Copyright: Win32 SDK Online Help


Legal Notice

Information in this document is subject to change without notice. Companies, names, and data used in examples herein are fictitious unless otherwise noted. No part of this document may be reproduced or transmitted in any form or by any means, electronic or mechanical, for any purpose, without the express written permission of Microsoft Corporation.

Portions of this document contain information pertaining to prerelease code that is not at the level of performance and compatibility of the final, generally available product offering. This information may be substantially modified prior to the first commercial shipment. Microsoft is not obligated to make this or any later version of the software product commercially available. APIs that constitute prerelease code are marked as "Preliminary Windows 95" or "Preliminary Windows NT" (as applicable). If your application is using any of these APIs, it must be marked as a BETA application. For further details and restrictions, see Sections 1 and 3 of the License Agreement.

Microsoft may have patents or pending patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in this document. The furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other intellectual property rights except as expressly provided in any written license agreement from Microsoft.

© 1985-1995 Microsoft Corporation. All rights reserved.

Microsoft, Microsoft Press, MS, MS-DOS, Visual Basic, Windows, Win32, and Win32s are registered trademarks; and Visual C++ and Windows NT are trademarks of Microsoft Corporation. OS/2 is a registered trademark licensed to Microsoft Corporation.

Adaptec is a registered trademark of Adaptec, Inc.

Macintosh and TrueType are registered trademarks of Apple Computer, Inc.

Asymetrix and ToolBook are registered trademarks of Asymetrix Corporation.

CompuServe is a registered trademark of CompuServe, Inc.

Sound Blaster and Sound Blaster Pro are trademarks of Creative Technology, Ltd.

Alpha AXP and DEC are trademarks of Digital Equipment Corporation.

Kodak is a registered trademark of Eastman Kodak Company.

PANOSE is a trademark of ElseWare Corporation.

Future Domain is a registered trademark of Future Domain Corporation.

Hewlett-Packard, HP, LaserJet, and PCL are registered trademarks of Hewlett-Packard Company.

AT, IBM, Micro Channel, OS/2, and XGA are registered trademarks, and PC/XT and RISC System/6000 are trademarks of International Business Machines Corporation.

Intel and Pentium are registered trademarks, and i386 and i486 are trademarks of Intel Corporation.

Video Seven is a trademark of Headland Technology, Inc.

Lotus is a registered trademark of Lotus Development Corporation.

MIPS is a registered trademark of MIPS Computer Systems, Inc.

Arial, Monotype, and Times New Roman are registered trademarks of The Monotype Corporation.

Motorola is a registered trademark of Motorola, Inc.

NCR is a registered trademark of NCR Corporation.

Nokia is a registered trademark of Nokia Corporation.

Novell and NetWare are registered trademarks of Novell, Inc.

Olivetti is a registered trademark of Ing. C. Olivetti.

PostScript is a registered trademark of Adobe Systems, Inc.

R4000 is a trademark of MIPS Computer Systems, Inc.

Roland is a registered trademark of Roland Corporation.

SCSI is a registered trademark of Security Control Systems, Inc.

Epson is a registered trademark of Seiko Epson Corporation, Inc.

Silicon Graphics is a registered trademark and OpenGL is a trademark of Silicon Graphics, Inc.

Stacker is a registered trademark of STAC Electronics.

Tandy is a registered trademark of Tandy Corporation.

Unicode is a registered trademark of Unicode, Incorporated.

UNIX is a registered trademark in the United States and other countries, licensed exclusively through X/Open Company, Ltd.

VAX is a trademark of Digital Equipment Corporation

Yamaha is a registered trademark of Yamaha Corporation of America.

Paintbrush is a trademark of Wordstar Atlanta Technology Center.


 Legal Information

Information in this online help system is subject to change without notice and does not represent a commitment on the part of Microsoft Corporation. The software and/or files described in this online help system are furnished under a license agreement or nondisclosure agreement. The software and/or files may be used or copied only in accordance with the terms of the agreement. The purchaser may make one copy of the software for backup purposes. No part of this online help system may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopying, recording, or information and retrieval systems, for any purpose other than the purchaser's personal use, without the written permission of Microsoft Corporation.

Microsoft may have patents or pending patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in this document. The furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other intellectual property rights except as expressly provided in any written license agreement from Microsoft.

Copyright © 1992-1995 Microsoft Corporation. All rights reserved.

Microsoft, MS, MS-DOS, Win32, Win32s, and Windows are registered trademarks, and Windows NT is a trademark of Microsoft Corporation.

Portions of this documentation are provided under license from Digital Equipment Corporation. Copyright © 1990, 1992 Digital Equipment Corporation. All rights reserved.

DEC, DECnet and PATHWORKS are trademarks of Digital Equipment Corporation.


Windows

A window in an application written for the Microsoft® Windows® operating system is a rectangular area of the screen where the application displays output and receives input from the user. A window shares the screen with other windows, including those from other applications. Only one window at a time can receive input from the user. The user can use the mouse, keyboard, or other input device to interact with this window and the application that owns it.


About Windows

Windows are the only means a Windows-based application has to interact with the user and accomplish tasks, so one of the first tasks of a Windows-based application is to create a window. This overview describes the elements of the Microsoft® Win32® application programming interface (API) that applications use to create and use windows; manage relationships between windows; and size, move, and display windows.


Desktop Window

When Windows starts, it automatically creates the desktop window. The desktop window is a system-defined window that paints the background of the screen and serves as the base for all windows displayed by all Win32-based applications.

The desktop window uses a bitmap stored in a bitmap file (with the .BMP filename extension) to paint the background of the screen. The pattern created by the bitmap is called the desktop wallpaper. By default, the desktop window uses the bitmap from a file specified in the registry as the desktop wallpaper.

A system configuration application, such as a Control Panel application, can change the desktop wallpaper by using the SystemParametersInfo function with the wAction parameter set to SPI_SETDESKWALLPAPER and the lpvParam parameter specifying a bitmap filename. SystemParametersInfo then loads the bitmap from the specified file, uses the bitmap to paint the background of the screen, and enters the new filename in the registry. For more information about bitmaps, see Bitmaps. For more information about the registry, see Registry.


Application Windows

Every Win32-based application creates at least one window, called the main window, that serves as the main window for the application. This window serves as the primary interface between the user and the application. Most applications also create many other windows, either directly or indirectly, to perform tasks related to the main window. Each window plays a part in displaying output and receiving input from the user.


Components of an Application Window

An application window can include a title bar, a menu bar, a System menu (also called the Control menu), a minimize box, a maximize box, a sizing border, a client area, a horizontal scroll bar, and a vertical scroll bar. An application's main window typically includes all of these components. The following illustration shows these components in a typical main window.

The title bar displays an application-defined icon and line of text; typically, the text specifies the name of the application or indicates the purpose of the window. An application specifies the icon and text when creating the window. The title bar also makes it possible for the user to move the window by using a mouse or other pointing device.

Most applications include a menu that lists the commands supported by the application. Items in the menu bar represent the main categories of commands. Choosing an item from the menu bar typically opens a pop-up menu whose items correspond to the tasks within a given category. By selecting a command, the user directs the application to carry out a task.

The System-menu box is a bitmap that, when clicked, displays the System menu. The System menu is a menu created and managed by Windows. It contains a standard set of menu items that, when chosen by the user, set a window's size or position, close the application, or open the Task List. For more information about menus and the System menu, see Menus (Windows NT).

The maximize and minimize boxes are bitmaps that, when clicked, affect a window's size and position. When the user clicks the maximize box, Windows enlarges the window to the size of the screen and positions the window, so it covers the entire screen. At the same time, Windows replaces the maximize box with the restore box. The restore box is a bitmap that, when clicked, restores the window to its previous size and position.

When the user clicks the minimize box, Windows reduces the window to the size of an icon, positions the window at the bottom of the screen, and displays the window's icon at the position of the window. An icon is a 32- by 32-pixel bitmap that represents a window. For more information about icons, see Icons.

The sizing border is an area around the perimeter of the window that enables the user to size the window by using a mouse or other pointing device.

The client area is the part of a window where the application displays output, such as text or graphics. For example, a desktop publishing application displays the current page of a document in the client area. The application must provide a function, called a window procedure, to process input to the window and display output in the client area. For more information about window procedures, see Window Procedures.

The horizontal and vertical scroll bars convert mouse or keyboard input into values that an application uses to shift the contents of the client area either horizontally or vertically. For example, a word-processing application that displays a lengthy document typically provides a vertical scroll bar to enable the user to page up and down through the document.

The title bar, menu bar, System menu, minimize and maximize boxes, sizing border, and scroll bars are referred to collectively as the window's nonclient area. Windows manages most aspects of the nonclient area; the application manages everything else about the window. In particular, the application manages the appearance and behavior of the client area.


Controls, Dialog Boxes, and Message Boxes

An application uses several types of windows in addition to its main window, including controls, dialog boxes, and message boxes.

A control is a window that an application uses to obtain a specific piece of information from the user, such as the name of a file to open or the desired point size of a text selection. Applications also use controls to obtain information needed to control a particular feature of an application. For example, a word-processing application typically provides a control to let the user turn wordwrapping on and off.

Controls are always used in conjunction with another window — typically, a dialog box. A dialog box is a window that contains one or more controls. An application uses a dialog box to prompt the user for input needed to complete a command. For example, an application that includes a command to open a file would display a dialog box that includes controls in which the user specifies a path and filename.

A message box is a window that displays a note, caution, or warning to the user. For example, a message box can inform the user of a problem the application has encountered while performing a task.

Dialog boxes and message boxes do not typically use the same set of window components as does a main window. Most have a title bar, a System menu, a border (nonsizing), and a client area, but they typically do not have a menu bar, minimize and maximize buttons, or scroll bars. For more information about dialog boxes and message boxes, see Dialog Boxes.


Window Creation

An application creates its main window by using the CreateWindow or CreateWindowEx function and providing information Windows requires to define the attributes of the window. CreateWindowEx has a parameter, dwExStyle, that CreateWindow does not have; otherwise, the functions are identical. In fact, CreateWindow simply calls CreateWindowEx, setting the dwExStyle parameter to zero. For this reason, the remainder of this topic refers only to CreateWindowEx.

The Win32 API provides additional functions — including DialogBox, CreateDialog, and MessageBox — for creating special-purpose windows such as dialog boxes and message boxes. For more information about these functions, see Dialog Boxes.


Window Attributes

An application must provide the following information when creating a window:

•	Window class

•	Window name

•	Window style

•	Parent or owner window

•	Size

•	Location

•	Position

•	Child-window identifier or menu handle

•	Instance handle

•	Creation data

These attributes are described in the following sections.

Window Class

Every window belongs to a window class. An application must register a window class before creating any windows of that class. The window class defines most aspects of a window's appearance and behavior. The chief component of a window class is the window procedure, a function that receives and processes all input and requests sent to the window. Windows provides the input and requests in the form of messages. For more information about window classes, window procedures, or messages, see Window Classes, Window Procedures, or Messages and Message Queues.

Window Name

A window can have a name. A window name (also called window text) is a text string that identifies a window for the user. A main window, dialog box, or message box typically displays its window name in its title bar, if present. For a control, the appearance of the window name depends on the control's class. A button, edit control, or static control displays its window name within the rectangle occupied by the control. A list box, combo box, or static control does not display its window name.

An application uses the SetWindowText function to change the window name after creating the window. It uses the GetWindowTextLength and GetWindowText functions to retrieve the current window-name text from a window.

Window Style

Every window has one or more window styles. A window style is a named constant that defines an aspect of the window's appearance and behavior that is not specified by the window's class. For example, the SCROLLBAR class creates a scroll bar control, but the SBS_HORZ and SBS_VERT styles determine whether a horizontal or vertical scroll bar control is created. A few window styles apply to all windows, but most apply to windows of specific window classes. Windows and, to some extent, the window procedure for the class, interpret the styles.

Parent or Owner Window

A window can have a parent window. A window that has a parent is called a child window. The parent window provides the coordinate system used for positioning a child window. Having a parent window affects aspects of a window's appearance; for example, a child window is clipped so that no part of the child window can appear outside the borders of its parent window. A window that has no parent, or whose parent is the desktop window, is called a top-level window. An application uses the EnumWindows function to obtain the handle of each of its top-level windows. EnumWindows passes the handle of each top-level window, in turn, to an application-defined callback function (a function called by Windows).

A window can own, or be owned by, another window. An owned window always appears in front of its owner window, is hidden when its owner window is minimized, and is destroyed when its owner window is destroyed.

Location, Size, and Position in the Z Order

Every window has a location, size, and position in the Z order. The location is the coordinates of the window's upper left corner, relative to the upper left corner of the screen or, in the case of a child window, the upper left corner of the parent's client area. A window's size is its width and height measured in pixels. A window's position in the Z order is the position of the window in a stack of overlapping windows.

Child-Window Identifier or Menu Handle

A child window can have a child-window identifier, a unique, application-defined value associated with the child window. Child-window identifiers are especially useful in applications that create multiple child windows. When creating a child window, an application specifies the identifier of the child window. After creating the window, the application can change the window's identifier by using the SetWindowLong function, or it can retrieve the identifier by using the GetWindowLong function.

Every window, except a child window, can have a menu. An application can include a menu by providing a menu handle either when registering the window's class or when creating the window.

Instance Handle

Every Win32-based application has an instance handle associated with it. Windows provides the instance handle to an application when the application starts. Because it can run multiple copies of the same application, Windows uses instance handles internally to distinguish one instance of an application from another. The application must specify the instance handle in many different windows, including those that create windows.

Creation Data

Every window can have application-defined creation data associated with it. When the window is first created, Windows passes a pointer to the data on to the window procedure of the window being created. The window procedure uses the data to initialize application-defined variables.


Main Window Creation

Every Win32-based application must have a WinMain function as its entry point. WinMain performs a number of tasks, including registering the window class for the main window and creating the main window. WinMain registers the main window class by calling the RegisterClass function, and it creates the main window by calling the CreateWindowEx function.

Portability Issue  The entry point need not be named WinMain.

Windows does not automatically display the main window after creating it; instead, an application must use the ShowWindow function to display the main window. After creating the main window, the application's WinMain function calls ShowWindow, passing it two parameters: the handle of the main window and a flag specifying whether the main window should be minimized or maximized when it is first displayed. Normally, the flag can be set to any of the constants beginning with the SW_ prefix that are defined in the Win32 header files. However, when ShowWindow is called to display the application's main window, the flag must be set to SW_SHOWDEFAULT. This flag tells Windows to display the window as directed by the program that launched the application.


Window-Creation Messages

When creating any window, Windows sends messages to the window procedure for the window. Windows sends the WM_NCCREATE message after creating the window's nonclient area and the WM_CREATE message after creating the client area. The window procedure receives both messages before Windows displays the window. Both messages include a pointer to a CREATESTRUCT structure that contains all the information specified in the CreateWindowEx function. Typically, the window procedure performs initialization tasks upon receiving these messages.

When creating a child window, Windows sends the WM_PARENTNOTIFY message to the parent window after sending the WM_NCCREATE and WM_CREATE messages. It also sends other messages while creating a window. The number and order of these messages depend on the window class and style and on the function used to create the window. These messages are described in other topics in this help file.


Multithread Applications

A Win32-based application can have multiple threads of execution, and each thread can create windows. An application can use the EnumThreadWindows function to enumerate the windows created by a particular thread. This function passes the handle of each thread window, in turn, to an application-defined callback function. The GetWindowThreadProcessId function returns the identifier of the thread that created a particular window.


Window Handles

After creating a window, the creation function returns a window handle that uniquely identifies the window. An application uses this handle in other functions to direct their actions to the window. A window handle has the HWND data type; an application must use this type when declaring a variable that holds a window handle.

The Win32 API includes several special constants that can replace a window handle in certain functions. These constants begin with the HWND_ prefix. For example, an application can use HWND_TOP or HWND_BOTTOM in the SetWindowPos function to move a window to the top or bottom of the Z order.

Although the NULL constant is not a window handle, an application can use it in some functions to specify that no window is affected. For example, specifying NULL for the CreateWindowEx function's hwndParent parameter creates a window that has no parent or owner. Some functions may return NULL instead of a handle, indicating that the given action applies to no window.

An application can use the FindWindow function to discover whether a window with the specified class name or window name exists in the system. If such a window exists, FindWindow returns the handle of the window. The IsWindow function determines whether a window handle identifies a valid, existing window.


Window Styles

The Win32 API provides general window styles and class-specific window styles. The general windows styles are constants that begin with the WS_ prefix; they can be combined to form different types of windows, including main windows, dialog boxes, and child windows. The class-specific window styles define the appearance and behavior of windows belonging to the predefined control classes such as edit controls and list boxes. This section describes the general window styles.

An application usually sets a window's styles when creating the window. It can also set the styles after creating the window by using the SetWindowLong function.


Overlapped Window

An overlapped window is a top-level window that has a title bar, border, and client area; it is meant to serve as an application's main window. It can also have a System menu, minimize and maximize boxes, and scroll bars. An overlapped window used as a main window typically includes all of these components.

By specifying the WS_OVERLAPPED or WS_OVERLAPPEDWINDOW style in the CreateWindowEx function, an application can create an overlapped window. If created with the WS_OVERLAPPED style, the window has a title bar and border. If created with the WS_OVERLAPPEDWINDOW style, the window has a title bar, sizing border, System menu, and minimize and maximize boxes.


Pop-up Window

A pop-up window is a special type of overlapped window used for dialog boxes, message boxes, and other temporary windows that appear outside an application's main window. Title bars are optional for pop-up windows; otherwise, pop-up windows are the same as overlapped windows of the WS_OVERLAPPED style.

An application creates a pop-up window by specifying the WS_POPUP style in CreateWindowEx. To include a title bar, the WS_CAPTION style must also be specified. An application can use the WS_POPUPWINDOW style to create a pop-up window that has a border and a System menu. The WS_CAPTION style must be combined with the WS_POPUPWINDOW style to make the System menu visible.


Child Window

A child window has the WS_CHILD style and is confined to the client area of its parent window. An application typically uses child windows to divide the client area of a parent window into functional areas. An application creates a child window by specifying the WS_CHILD style in the CreateWindowEx function.

A child window must have a parent window. The parent window can be an overlapped window, a pop-up window, or even another child window. An application specifies the parent window when calling CreateWindowEx. If the application specifies the WS_CHILD style in CreateWindowEx but does not specify a parent window, Windows does not create the window.

A child window has a client area but no other features, unless they are explicitly requested. An application can request a title bar, a System menu, minimize and maximize boxes, a border, and scroll bars for a child window, but a child window cannot have a menu. If the application specifies a menu handle, either when it registers the child's window class or creates the child window, the menu handle is ignored.

Positioning

Windows always positions the child window relative to the upper left corner of the parent window's client area. No part of a child window ever appears outside the borders of its parent window. If an application creates a child window that is larger than the parent window or positions a child window so that some or all of the child window extends beyond the borders of the parent, Windows clips the child window; that is, the portion outside the parent window's client area is not displayed. Actions that affect the parent window can also affect the child window, as follows.

Parent window	Child window
Destroyed	Destroyed before the parent window is destroyed.
Hidden	Hidden before the parent window is hidden. A child window is visible only when the parent window is visible.
Moved	Moved with the parent window's client area. The child window is responsible for painting its client area after the move.
Shown	Shown after the parent window is shown.
Clipping

Windows does not automatically clip a child window from the parent window's client area. This means the parent window draws over the child window if it carries out any drawing in the same location as the child window. Windows does, however, clip the child window from the parent window's client area if the parent window has the WS_CLIPCHILDREN style. If the child window is clipped, the parent window cannot draw over it.

A child window can overlap other child windows in the same client area. A child window that shares the same parent window as one or more other child windows is called a sibling window. Sibling windows can draw in each other's client area, unless one of the child windows has the WS_CLIPSIBLINGS style. If a child window does have this style, any portion of its sibling window that lies within the child window is clipped.

If a window has either the WS_CLIPCHILDREN or WS_CLIPSIBLINGS style, a slight loss in performance occurs. Each window takes up system resources, so an application should not use child windows indiscriminately. For best performance, an application that needs to logically divide its main window should do so in the window procedure of the main window rather than by using child windows.

Relationship to Parent Window

An application can change the parent window of an existing child window by calling the SetParent function. In this case, Windows removes the child window from the client area of the old parent window and moves it to the client area of the new parent window. If SetParent specifies a NULL handle, the desktop window becomes the new parent window. In this case, the child window is drawn on the desktop, outside the borders of any other window. The GetParent function retrieves the handle of a child window's parent window.

The parent window relinquishes a portion of its client area to a child window, and the child window receives all input from this area. The window class need not be the same for each of the child windows of the parent window. This means that an application can fill a parent window with child windows that look different and carry out different tasks. For example, a dialog box can contain many types of controls, each one a child window that accepts different types of data from the user.

A child window has only one parent window, but a parent can have any number of child windows. Each child window, in turn, can have child windows. In this chain of windows, each child window is called a descendant window of the original parent window. An application uses the IsChild function to discover whether a given window is a child window or a descendant window of a given parent window.

The EnumChildWindows function enumerates the child windows of a parent window. Then, EnumChildWindows passes the handle of each child window to an application-defined callback function. Descendant windows of the given parent window are also enumerated.

Messages

Windows passes a child window's input messages directly to the child window; the messages are not passed through the parent window. The only exception is if the child window has been disabled by the EnableWindow function. In this case, Windows passes any input messages that would have gone to the child window to the parent window instead. This permits the parent window to examine the input messages and enable the child window, if necessary.

A child window can have a unique integer identifier. Child window identifiers are important when working with control windows. An application directs a control's activity by sending it messages. The application uses the control's child window identifier to direct the messages to the control. In addition, a control sends notification messages to its parent window. A notification message includes the control's child window identifier, which the parent uses to identify which control sent the message. An application specifies the child-window identifier for other types of child windows by setting the hmenu parameter of the CreateWindowEx function to a value rather than a menu handle.


Window Border

The Win32 API provides the following border styles.

Style	Description
WS_BORDER	Creates a window with a thin-line border.
WS_DLGFRAME	Creates a window with a double border, a style typically used with dialog boxes. A window with this style cannot have a title bar.
WS_EX_DLGMODALFRAME	Creates a window with a double border. Unlike the WS_DLGFRAME style, an application can also specify the WS_CAPTION style to create a title bar for the window.
WS_EX_STATICEDGE	Creates a window with a three-dimensional border style intended to be used for items that do not accept user input.
WS_THICKFRAME	Creates a window with a sizing border.
A window with the WS_OVERLAPPED or WS_POPUPWINDOW style has the WS_BORDER style by default. One of the other border styles must be combined with the WS_OVERLAPPED or WS_POPUPWINDOW style to give an overlapped window a different border style.

If no border style is specified for a window with the WS_POPUP or WS_CHILD style, the system creates a borderless window. An application can use borderless child windows to divide the parent window's client area while keeping the divisions invisible to the user.


Nonclient-Area Components

The nonclient area of a window can include a title bar, System menu, minimize and maximize boxes, sizing border, and horizontal and vertical scroll bars. An application can create a window with one or more of these components by specifying the following styles in the CreateWindowEx function.

Style	Description
WS_CAPTION	Creates a window that has a title bar (includes the WS_BORDER style).
WS_HSCROLL	Creates a window that has a horizontal scroll bar.
WS_MAXIMIZEBOX	Creates a window that has a maximize box.
WS_MINIMIZEBOX	Creates a window that has a minimize box.
WS_SYSMENU	Creates a window that has a System-menu box in its title bar. The WS_CAPTION style must also be specified.
WS_VSCROLL	Creates a window that has a vertical scroll bar.


Initial State

The following styles determine whether a window is enabled or disabled, visible or invisible, and minimized or maximized.

Style	Description
WS_DISABLED	Creates a window that is initially disabled. A disabled window cannot receive input from the user.
WS_MAXIMIZE	Creates a window that is initially maximized.
WS_MINIMIZE	Creates a window that is initially minimized.
WS_VISIBLE	Creates a window that is initially visible.


Parent and Child Styles

The following styles affect the clipping relationship between a parent window and its child windows, and between a child window and its sibling windows.

Style	Description
WS_CLIPCHILDREN	Excludes the area occupied by child windows when drawing within the parent window. Use this style when creating the parent window.
WS_CLIPSIBLINGS	Clips child windows relative to each other; that is, when a particular child window receives a WM_PAINT message, the WS_CLIPSIBLINGS style clips all other overlapping child windows out of the region of the child window to be updated. If WS_CLIPSIBLINGS is not specified and child windows overlap, it is possible, when drawing within the client area of one child window, to draw within the client area of another neighboring child window.


Dialog Box Styles

A dialog box includes a built-in keyboard interface that processes the direction and TAB keys. The user can use these keys instead of the mouse to navigate among the controls in the dialog box. The following styles affect how the built-in keyboard interface processes the direction and TAB keys.

Style	Description
WS_GROUP	Specifies the first control of a group of controls. The user can change the keyboard focus from one control in the group to the next by using the direction keys. The next control with the WS_GROUP style ends the group and starts the next group.
WS_TABSTOP	Specifies a control that can receive the keyboard focus when the user presses the TAB key. Pressing the TAB key changes the keyboard focus to the next control of the WS_TABSTOP style.


Extended Styles

The following styles can be specified in the dwExStyle parameter of the CreateWindowEx function.

Style	Description
WS_EX_ACCEPTFILES	Specifies that a window created with this style accepts drag-drop files.
WS_EX_CONTEXTHELP	Includes a question mark in the title bar of the window. When the user clicks the question mark, the cursor changes to a question mark with a pointer. If the user then clicks a child window, the child receives a WM_HELP message. The child window should pass the message to the parent window procedure, which should call the WinHelp function using the HELP_WM_HELP command. The Help application displays a pop-up window that typically contains help for the child window.
WS_EX_CONTROLPARENT	Allows the user to navigate among the child windows of the window by using the TAB key.
WS_EX_DLGMODALFRAME	Creates a window with a double border. Unlike the WS_DLGFRAME style, an application can also specify the WS_CAPTION style to create a title bar for the window.
WS_EX_NOPARENTNOTIFY	Specifies that a child window created with this style will not send the WM_PARENTNOTIFY message to its parent window when either created or destroyed.
WS_EX_TOPMOST	Specifies that a window created with this style should be placed above all non-topmost windows and stay above them even when the window is deactivated.
WS_EX_TOOLWINDOW	Creates a tool window; that is, a window intended to be used as a floating toolbar. A tool window has a title bar that is shorter than a normal title bar, and the window title is drawn using a smaller font. A tool window does not appear in the task bar or in the window that appears when the user presses ALT+TAB.


Owned Windows

An overlapped or pop-up window can be owned by another overlapped or pop-up window. Being owned places several constraints on a window.

•	An owned window is always above its owner in the Z order.

•	Windows automatically destroys an owned window when its owner is destroyed.

•	An owned window is hidden when its owner is minimized.

Only an overlapped or pop-up window can be an owner window; a child window cannot be one. An application creates an owned window by specifying the owner's window handle as the hwndParent parameter of CreateWindowEx when it creates a window with the WS_OVERLAPPED or WS_POPUP style. The hwndParent parameter must identify an overlapped or pop-up window. If hwndParent identifies a child window, Windows assigns ownership to the top-level parent window of the child window. After creating an owned window, an application cannot transfer ownership of the window to another window.

Dialog boxes and message boxes are owned windows by default. An application specifies the owner window when calling a function that creates a dialog box or message box.

An application can use the GetWindow function with the GW_OWNER flag to retrieve the handle of a window's owner.


Disabled Windows

A window can be disabled. A disabled window receives no keyboard or mouse input, but it can receive messages from other windows, from other applications, and from Windows. An application typically disables a window to prevent the user from using the window. For example, an application may disable a push button in a dialog box to prevent the user from choosing it. An application can enable a disabled window at any time; enabling a window restores normal input.

By default, a window is enabled when created. An application can specify the WS_DISABLED style, however, to disable a new window. An application enables or disables an existing window by using the EnableWindow function. Windows sends a WM_ENABLE message to a window when its enabled state is about to change. An application can determine whether a window is enabled by using the IsWindowEnabled function.

When a child window is disabled, Windows passes the child's mouse input messages to the parent window. The parent uses the messages to determine whether to enable the child window. For more information about mouse input, see Mouse Input.

Only one window at a time can receive keyboard input; that window is said to have the keyboard focus. If an application uses the EnableWindow function to disable a keyboard-focus window, the window loses the keyboard focus in addition to being disabled. EnableWindow then sets the keyboard focus to NULL, meaning no window has the focus. If a child window, or other descendant window, has the keyboard focus, the descendant window loses the focus when the parent window is disabled. For more information about the keyboard focus, see Keyboard Input.


Foreground and Background Windows

Each process can have multiple threads of execution, and each thread can create windows. The thread that created the window with which the user is currently working is called the foreground thread, and the window is called the foreground window. All other threads are background threads, and the windows created by background threads are called background windows.

Each thread has a priority level that determines the amount of CPU time the thread receives. Although an application can set the priority level of its threads, normally the foreground thread has a slightly higher priority level than the background threads. Because it has a higher priority, the foreground thread receives more CPU time than the background threads. The foreground thread has a normal base priority of 9; a background thread has a normal base priority of 7.

The user sets the foreground window by clicking a window, or by using the ALT+TAB or ALT+ESC key combination. An application sets the foreground window by using the SetForegroundWindow function. If the new foreground window is a top-level window, Windows activates it; otherwise, it activates the associated top-level window. An application retrieves the handle of the foreground window by using the GetForegroundWindow function.


Show State

At any one given time, a window may be active or inactive; hidden or visible; and minimized, maximized, or restored. These qualities are referred to collectively as the window's show state.


Active Window

An active window is the top-level window of the application with which the user is currently working. To allow the user to easily identify the active window, Windows places it at the top of the Z order and changes the color of its title bar and border to the system-defined active window colors. Only a top-level window can be an active window. When the user is working with a child window, Windows activates the top-level parent window associated with the child window.

Only one top-level window in the system is active at a time. The user activates a top-level window by clicking it (or one of its child windows), or by using the ALT+ESC or ALT+TAB key combination. An application activates a top-level window by calling the SetActiveWindow function. A number of other functions can cause Windows to activate a different top-level window, including SetWindowPos, DeferWindowPos, SetWindowPlacement, and DestroyWindow. Although an application can activate a different top-level window at any time, to avoid confusing the user, it should do so only in response to a user action. An application uses the GetActiveWindow function to retrieve the handle of the active window.

When the activation changes from a top-level window of one application to the top-level window of another, Windows sends a WM_ACTIVATEAPP message to both applications, notifying them of the change. When the activation changes to a different top-level window in the same application, Windows sends both windows a WM_ACTIVATE message.


Visibility

A window can be either visible or hidden. Windows displays a visible window on the screen. It hides a hidden window by not drawing it. If a window is visible, the user can supply input to the window and view the window's output. If a window is hidden, it is effectively disabled. A hidden window can process messages from Windows or from other windows, but it cannot process input from the user or display output. An application sets a window's visibility state when creating the window. Later, the application can change the visibility state.

A window is visible when the WS_VISIBLE style is set for the window. By default, the CreateWindowEx function creates a hidden window unless the application specifies the WS_VISIBLE style. Typically, an application sets the WS_VISIBLE style after it has created a window to keep details of the creation process hidden from the user. For example, an application may keep a new window hidden while it customizes the window's appearance. If the WS_VISIBLE style is specified in CreateWindowEx, Windows sends the WM_SHOWWINDOW message to the window after creating the window, but before displaying it.

An application can determine whether a window is visible by using the IsWindowVisible function. An application can show (make visible) or hide a window by using the ShowWindow, SetWindowPos, DeferWindowPos, or SetWindowPlacement function. These functions show or hide a window by setting or removing the WS_VISIBLE style for the window. They also send the WM_SHOWWINDOW message to the window before showing or hiding it.

When an owner window is minimized, Windows automatically hides the associated owned windows. Similarly, when an owner window is restored, Windows automatically shows the associated owned windows. In both cases, Windows sends the WM_SHOWWINDOW message to the owned windows before hiding or showing them. Occasionally, an application may need to hide the owned windows without having to minimize or hide the owner. In this case, the application uses the ShowOwnedPopups function. This function sets or removes the WS_VISIBLE style for all owned windows and sends the WM_SHOWWINDOW message to the owned windows before hiding or showing them. Hiding an owner window has no effect on the visibility state of the owned windows.

When a parent window is visible, its associated child windows are also visible. Similarly, when the parent window is hidden, its child windows are also hidden. Minimizing the parent window has no effect on the visibility state of the child windows; that is, the child windows are minimized along with the parent, but the WS_VISIBLE style is not changed.

Even if a window has the WS_VISIBLE style, the user may not be able to see the window on the screen; other windows may completely overlap it or it may have been moved beyond the edge of the screen. Also, a visible child window is subject to the clipping rules established by its parent-child relationship. If the window's parent window is not visible, it will also not be visible. If the parent window moves beyond the edge of the screen, the child window also moves because a child window is drawn relative to the parent's upper left corner. For example, a user may move the parent window containing the child window far enough off the edge of the screen that the user may not be able to see the child window, even though the child window and its parent window both have the WS_VISIBLE style.


Minimized, Maximized, and Restored Windows

A maximized window is a window that has the WS_MAXIMIZE style. By default, Windows enlarges a maximized window so that it fills the screen or, in the case of a child window, the parent window's client area. Although a window's size can be set to the same size of a maximized window, a maximized window is slightly different. Windows automatically moves the window's title bar to the top of the screen or to the top of the parent window's client area. Also, Windows disables the window's sizing border and the window-positioning capability of the title bar (so that the user cannot move the window by dragging the title bar).

A minimized window is a window that has the WS_MINIMIZE style. By default, Windows reduces a minimized window to the size of an icon and moves the minimized window to the lower part of the screen or the lower part of the parent window's client area. The lower part of the screen or client area is sometimes called the icon area. Windows moves a minimized window into the first available position in the icon area, unless the application specifies another position. A restored window is a window that has been returned to its preminimized or premaximized size and position.

If an application specifies the WS_MAXIMIZE or WS_MINIMIZE style in the CreateWindowEx function, the window is initially maximized or minimized. After creating a window, an application can use the CloseWindow function to minimize the window. The ArrangeIconicWindows function arranges the application's minimized top-level windows along the bottom of the screen, or it arranges a parent window's minimized child windows along the bottom of the parent window.

The ShowWindow function can minimize, maximize, or restore a window. It can also set the window's visibility and activation states. The SetWindowPlacement function includes the same functionality as ShowWindow, but it can override the window's default minimized, maximized, and restored positions.

The IsZoomed and IsIconic functions determine whether a given window is maximized or minimized, respectively. The GetWindowPlacement function retrieves the minimized, maximized, and restored positions for the window, and also determines the window's show state.

When Windows receives a command to maximize or restore a minimized window, Windows sends the window a WM_QUERYOPEN message. If the window procedure returns FALSE, Windows ignores the Maximize or Restore command.

Windows automatically sets the size and position of a maximized window to the system-defined defaults for a maximized window. To override these defaults, an application can either call the SetWindowPlacement function or process the WM_GETMINMAXINFO message that is received by a window when Windows is about to maximize the window. WM_GETMINMAXINFO includes a pointer to a MINMAXINFO structure containing values Windows uses to set the maximized size and position. Replacing these values overrides the defaults.


Window Size and Position

A window's size and position are expressed as a bounding rectangle, given in coordinates relative to the screen or the parent window. The coordinates of a top-level window are relative to the upper left corner of the screen; the coordinates of a child window are relative to the upper left corner of the parent window. An application specifies a window's initial size and position when it creates the window, but it can change the window's size and position at any time. For more information about bounding rectangles, see Filled Shapes.


Size

A window's size (width and height) is given in pixels. A window can have zero width or height. If an application sets a window's width and height to zero, Windows sets the size to the default minimum window size. To discover the default minimum window size, an application uses the GetSystemMetrics function with the SM_CXMIN and SM_CYMIN flags.

An application may need to create a window with a client area of a particular size. The AdjustWindowRect and AdjustWindowRectEx functions calculate the required size of a window based on the desired size of the client area. The application can pass the resulting size values to the CreateWindowEx function.

An application can size a window so that it is extremely large; however, it should not size a window so that it is larger than the screen. Before setting a window's size, the application should check the width and height of the screen by using GetSystemMetrics with the SM_CXSCREEN and SM_CYSCREEN flags.


Position

A window's position is defined as the coordinates of its upper left corner. These coordinates, sometimes called window coordinates, are always relative to the upper left corner of the screen or, for a child window, the upper left corner of the parent window's client area. For example, a top-level window having the coordinates (10,10) is placed 10 pixels to the right of the upper left corner of the screen and 10 pixels down from it. A child window having the coordinates (10,10) is placed 10 pixels to the right of the upper left corner of its parent window's client area and 10 pixels down from it.

The WindowFromPoint function retrieves the handle of the window occupying a particular point on the screen. Similarly, the ChildWindowFromPoint and ChildWindowFromPointEx functions retrieve the handle of the child window occupying a particular point in the parent window's client area. Although ChildWindowFromPointEx can ignore invisible, disabled, and transparent child windows, ChildWindowFromPoint cannot.


Default Size and Position

An application can allow Windows to calculate the initial size or position of a top-level window by specifying CW_USEDEFAULT in CreateWindowEx. If the application sets the window's coordinates to CW_USEDEFAULT and has created no other top-level windows, Windows sets the new window's position relative to the upper left corner of the screen; otherwise, it sets the position relative to the position of the top-level window that the application created most recently. If the width and height parameters are set to CW_USEDEFAULT, Windows calculates the size of the new window. If the application has created other top-level windows, Windows bases the size of the new window on the size of the application's most recently created top-level window. Specifying CW_USEDEFAULT when creating a child or pop-up window causes Windows to set the window's size to the default minimum window size.


Tracking Size

Windows maintains a minimum and maximum tracking size for a window of the WS_THICKFRAME style; a window with this style has a sizing border. The minimum tracking size is the smallest window size the user can produce by dragging the window's sizing border. Similarly, the maximum tracking size is the largest window size the user can produce by dragging the sizing border.

A window's minimum and maximum tracking sizes are set to system-defined default values when Windows creates the window. An application can discover the defaults and override them by processing the WM_GETMINMAXINFO message. For more information about this message, see Size and Position Messages.


System Commands

An application that has a window with a System menu can change the size and position of that window by sending system commands. System commands are generated when the user chooses commands from the System menu. An application can emulate the user action by sending a WM_SYSCOMMAND message to the window. The following system commands affect the size and position of a window.

Command	Description
SC_CLOSE	Closes the window. This command sends a WM_CLOSE message to the window. The window carries out any steps needed to clean up and destroy itself.
SC_MAXIMIZE	Maximizes the window.
SC_MINIMIZE	Minimizes the window.
SC_RESTORE	Restores a minimized or maximized window to its previous size and position.
SC_SIZE	Starts a Size command. The user can change the size of the window by using the mouse or keyboard.


Z Order

The Z order of a window indicates the window's position in a stack of overlapping windows. This window stack is oriented along an imaginary axis, the z-axis, extending outward from the screen. The window at the top of the Z order overlaps all other windows. The window at the bottom of the Z order is overlapped by all other windows. An application sets a window's position in the Z order by placing it behind a given window, or at the top or bottom of the stack.

Windows maintains three separate Z orders — one for top-level windows, one for sibling windows, and one for topmost windows. A topmost window overlaps all other non-topmost windows, regardless of whether it is the active or foreground window. A topmost window has the WS_EX_TOPMOST style.

By default, Windows puts a window at the top of the Z order when creating the window. The user changes the Z order by activating a different window; Windows always positions the active window at the top of the Z order. An application uses the BringWindowToTop function to bring a window to the top of the Z order. It can rearrange the Z order by using SetWindowPos or DeferWindowPos.


Size and Position Functions

After creating a window, an application can set the window's size or position by calling one of several different functions, including SetWindowPlacement, MoveWindow, SetWindowPos, and DeferWindowPos. SetWindowPlacement sets a window's minimized position, maximized position, restored size and position, and show state. The MoveWindow and SetWindowPos functions are similar; both set the size or position of a single application window. The SetWindowPos function includes a set of flags that affect the window's show state; MoveWindow does not include these flags. Use the BeginDeferWindowPos, DeferWindowPos, and EndDeferWindowPos functions to simultaneously set the position of a number of windows, including the size, position, position in the Z order, and show state.

An application can retrieve the coordinates of a window's bounding rectangle by using the GetWindowRect function. GetWindowRect fills a RECT structure with the coordinates of the window's upper left and lower right corners. The coordinates are relative to the upper left corner of the screen, even for a child window. The ScreenToClient or MapWindowPoints function maps the screen coordinates of a child window's bounding rectangle to coordinates relative to the parent window's client area.

The GetClientRect function retrieves the coordinates of a window's client area. GetClientRect fills a RECT structure with the coordinates of the upper left and lower right corners of the client area, but the coordinates are relative to the client area itself. This means the coordinates of a client area's upper left corner are always (0,0), and the coordinates of the lower right corner are the width and height of the client area.


Size and Position Messages

Windows sends the WM_GETMINMAXINFO message to a window whose size or position is about to change. For example, the message is sent when the user chooses the Move or Size command from the System menu or clicks the sizing border or title bar; the message is also sent when an application calls SetWindowPos to move or size the window. WM_GETMINMAXINFO includes a pointer to a MINMAXINFO structure containing the default maximized size and position for the window, as well as the default minimum and maximum tracking sizes. An application can override the defaults by processing WM_GETMINMAXINFO and setting the appropriate members of MINMAXINFO. A window must have the WS_THICKFRAME or WS_CAPTION style to receive WM_GETMINMAXINFO. A window with the WS_THICKFRAME style receives this message during the window-creation process, as well as when it is being moved or sized.

Windows sends the WM_WINDOWPOSCHANGING message to a window whose size, position, position in the Z order, or show state is about to change. This message includes a pointer to a WINDOWPOS structure that specifies the window's new size, position, position in the Z order, and show state. By setting the members of WINDOWPOS, an application can affect the window's new size, position, and appearance.

After changing a window's size, position, position in the Z order, or show state, Windows sends the WM_WINDOWPOSCHANGED message to the window. This message includes a pointer to WINDOWPOS that informs the window of its new size, position, position in the Z order, and show state. Setting the members of the WINDOWPOS structure that is passed with WM_WINDOWPOSCHANGED has no effect on the window. A window that must process WM_SIZE and WM_MOVE messages must pass WM_WINDOWPOSCHANGED to the DefWindowProc function; otherwise, Windows does not send WM_SIZE and WM_MOVE messages to the window.

Windows sends the WM_NCCALCSIZE message to a window when the window is created or sized. Windows uses the message to calculate the size of a window's client area and the position of the client area relative to the upper left corner of the window. A window typically passes this message to the default window procedure; however, this message can be useful in applications that customize a window's nonclient area or preserve portions of the client area when the window is sized. For more information about window size, see Painting and Drawing.


Window Destruction

In general, an application must destroy all the windows it creates. It does this by using the DestroyWindow function. When a window is destroyed, the system hides the window, if it is visible, and then removes any internal data associated with the window. This invalidates the window handle, which can no longer be used by the application.

An application destroys many of the windows it creates soon after creating them. For example, an application usually destroys a dialog box window as soon as the application has sufficient input from the user to continue its task. An application eventually destroys the main window of the application (before terminating).

Before destroying a window, an application should save or remove any data associated with the window, and it should release any system resources allocated for the window. If the application does not release the resources, Windows will free any resources not freed by the application.

Destroying a window does not affect the window class from which the window is created. New windows can still be created using that class, and any existing windows of that class continue to operate. Destroying a window also destroys the window's descendant windows. The DestroyWindow function sends a WM_DESTROY message first to the window, then to its child windows and descendant window. In this way, all descendant windows of the window being destroyed are also destroyed.

A window with a System menu receives a WM_CLOSE message when the user chooses the Close command from the System menu. By processing this message, an application can prompt the user for confirmation before destroying the window. If the user confirms that the window should be destroyed, the application can call the DestroyWindow function to destroy the window.

If the window being destroyed is the active window, both the active and focus states are transferred to another window. The window that becomes the active window is the next window, as determined by the ALT+ESC key combination. The new active window then determines which window receives the keyboard focus.


Using Windows

•	Creating a main window.

•	Creating, enumerating, and sizing child windows.

•	Destroying a window.


Creating a Main Window

The first window an application creates is typically the main window. You create the main window by using the CreateWindowEx function, specifying the window class, window name, window styles, size, position, menu handle, instance handle, and creation data. A main window belongs to an application-defined window class, so you must register the window class and provide a window procedure for the class before creating the main window.

Most applications typically use the WS_OVERLAPPEDWINDOW style to create the main window. This style gives the window a title bar, a System menu, a sizing border, and minimize and maximize boxes. The CreateWindowEx function returns a handle that uniquely identifies the window.

The following example creates a main window belonging to an application-defined window class. The window name, "Main Window", will appear in the window's title bar. By combining the WS_VSCROLL and WS_HSCROLL styles with the WS_OVERLAPPEDWINDOW style, the application creates a main window with horizontal and vertical scroll bars in addition to the components provided by the WS_OVERLAPPEDWINDOW style. The four occurrences of the CW_USEDEFAULT constant set the initial size and position of the window to the system-defined default values. By specifying NULL instead of a menu handle, the window will have the menu defined for the window class.

HINSTANCE hinst;

HWND hwndMain;

.

. /* Register the window class for the main window. */

.

/* Create the main window. */

hwndMain = CreateWindowEx(

    0,                      /* no extended styles          */

    "MainWClass",           /* class name                  */

    "Main Window",          /* window name                 */

    WS_OVERLAPPEDWINDOW |   /* overlapped window           */

        WS_HSCROLL |        /* horizontal scroll bar       */

        WS_VSCROLL,         /* vertical scroll bar         */

    CW_USEDEFAULT,          /* default horizontal position */

    CW_USEDEFAULT,          /* default vertical position   */

    CW_USEDEFAULT,          /* default width               */

    CW_USEDEFAULT,          /* default height              */

    (HWND) NULL,            /* no parent or owner window   */

    (HMENU) NULL,           /* class menu used             */

    hinstance,              /* instance handle             */

    NULL);                  /* no window creation data     */

if (!hwndMain)

    return FALSE;

/*

 * Show the window using the flag specified by the program

 * that launched the application, and send the application

 * a WM_PAINT message.

 */

ShowWindow(hwndMain, SW_SHOWDEFAULT);

UpdateWindow(hwndMain);

.

. /* Start the message loop for the application. */

.

Notice that the preceding example calls the ShowWindow function after creating the main window. This is done because Windows does not automatically display the main window after creating it. By passing the SW_SHOWDEFAULT flag to ShowWindow, the application allows the program that launched the application to set the initial show state of the main window. The UpdateWindow function sends the window its first WM_PAINT message.


Creating, Enumerating, and Sizing Child Windows

You can divide a window's client area into different functional areas by using child windows. Creating a child window is like creating a main window — you use the CreateWindowEx function. To create a window of an application-defined window class, you must register the window class and provide a window procedure before creating the child window. You must give the child window the WS_CHILD style and specify a parent window for the child window when you create it.

The following example divides the client area of an application's main window into three functional areas by creating three child windows of equal size. Each child window is the same height as the main window's client area, but each is one-third its width. The main window creates the child windows in response to the WM_CREATE message, which the main window receives during its own window-creation process. Because each child window has the WS_BORDER style, each has a thin line border. Also, because the WS_VISIBLE style is not specified, each child window is initially hidden. Notice also that each child window is assigned a child-window identifier.

The main window sizes and positions the child windows in response to the WM_SIZE message, which the main window receives when its size changes. In response to WM_SIZE, the main window retrieves the dimensions of its client area by using the GetWindowRect function and then passes the dimensions to the EnumChildWindows function. EnumChildWindows passes the handle of each child window, in turn, to the application-defined EnumChildProc callback function. This function sizes and positions each child window by calling the MoveWindow function; the size and position are based on the dimensions of the main window's client area and the identifier of the child window. Afterward, EnumChildProc calls the ShowWindow function to make the window visible.

#define ID_FIRSTCHILD  100

#define ID_SECONDCHILD 101

#define ID_THIRDCHILD  102

LONG APIENTRY MainWndProc(hwnd, uMsg, wParam, lParam)

HWND hwnd;

UINT uMsg;

UINT wParam;

LONG lParam;

{

    RECT rcClient;

    int i;

    switch(uMsg) {

        case WM_CREATE: /* creating main window */

            /* Create three invisible child windows. */

            for (i = 0; i < 3; i++)

                CreateWindowEx(

                    0,

                    "ChildWClass",

                    (LPCTSTR) NULL,

                    WS_CHILD | WS_BORDER,

                    0,0,0,0,

                    hwnd,

                    (HMENU) (int) (ID_FIRSTCHILD + i),

                    hinst,

                    NULL);

            return 0;

        case WM_SIZE:   /* main window changed size */

            /*

             * Get the dimensions of the main window's client

             * area, and enumerate the child windows. Pass the

             * dimensions to the child windows during enumeration.

             */

            GetClientRect(hwnd, &rcClient);

            EnumChildWindows(hwnd, EnumChildProc,

                (LPARAM) &rcClient);

            return 0;

        .

        . /* Process other messages. */

        .

    }

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

}

BOOL CALLBACK EnumChildProc(hwndChild, lParam)

HWND hwndChild;

LPARAM lParam;

{

    LPRECT rcParent;

    int i, idChild;

    /*

     * Retrieve the child-window identifier. Use it to set the

     * position of the child window.

     */

    idChild = GetWindowLong(hwndChild, GWL_ID);

    if (idChild == ID_FIRSTCHILD)

        i = 0;

    else if (idChild == ID_SECONDCHILD)

        i = 1;

    else

        i = 2;

    /* Size and position the child window. */

    rcParent = (LPRECT) lParam;

    MoveWindow(hwndChild,

        (rcParent->right / 3) * i,

        0,

        rcParent->right / 3,

        rcParent->bottom,

        TRUE);

    /* Make sure the child window is visible. */

    ShowWindow(hwndChild, SW_SHOW);

    return TRUE;

}


Destroying a Window

You can use the DestroyWindow function to destroy a window. Typically, an application sends the WM_CLOSE message before destroying a window, giving the window the opportunity to prompt the user for confirmation before the window is destroyed. A window that includes a System menu automatically receives the WM_CLOSE message when the user chooses the Close command from the menu. If the user confirms that the window should be destroyed, the application calls DestroyWindow. Windows sends the WM_DESTROY message to the window after removing it from the screen. In response to WM_DESTROY, the window saves its data and frees any resources it allocated. A main window concludes its processing of WM_DESTROY by calling the PostQuitMessage function to quit the application.

The following example shows how to prompt for user confirmation before destroying a window. In response to WM_CLOSE, the example displays a dialog box that contains Yes, OK, and Cancel buttons. If the user clicks the Yes button, DestroyWindow is called; otherwise, the window is not destroyed. Because the window being destroyed is a main window, the example calls PostQuitMessage in response to WM_DESTROY.

case WM_CLOSE:

    /*

     * Create the message box. If the user clicks

     * the Yes button, destroy the main window.

     */

    if (MessageBox(hwnd, szConfirm, szAppName,

            MB_YESNOCANCEL) == IDYES)

        DestroyWindow(hwndMain);

    else

        return 0;

case WM_DESTROY:

    /*

     * Post the WM_QUIT message to

     * quit the application terminate.

     */

    PostQuitMessage(0);

    return 0;


Window Reference

The following functions and messages are associated with windows.


Window Functions

Following are the functions to create and manage windows.

AdjustWindowRect
AdjustWindowRectEx
AnyPopup
BeginDeferWindowPos
BringWindowToTop
ChildWindowFromPoint
CloseWindow
CreateWindow
CreateWindowEx
DeferWindowPos
DestroyWindow
EnableWindow
EndDeferWindowPos
EnumChildProc
EnumChildWindows
EnumThreadWindows
EnumThreadWndProc
EnumWindows
EnumWindowsProc
FindWindow
GetClientRect
GetDesktopWindow
GetForegroundWindow
GetLastActivePopup
GetNextWindow
GetParent
GetTopWindow
GetWindow
GetWindowPlacement
GetWindowRect
GetWindowText
GetWindowTextLength
GetWindowThreadProcessId
IsChild
IsWindow
IsWindowUnicode
IsWindowVisible
IsZoomed
MoveWindow
SetForegroundWindow
SetParent
SetWindowLong
SetWindowPlacement
SetWindowPos
SetWindowText
ShowOwnedPopups
ShowWindow
WindowFromPoint
WinMain

Obsolete or Deleted Functions

EnumTaskWindows
GetSysModalWindow
GetWindowTask
SetSysModalWindow


Window Messages

Following are the messages to create and manage windows.

WM_ACTIVATE
WM_ACTIVATEAPP
WM_CANCELMODE
WM_CHILDACTIVATE
WM_CLOSE
WM_COPYDATA
WM_CREATE
WM_DESTROY
WM_ENABLE
WM_ENDSESSION
WM_GETMINMAXINFO
WM_GETTEXT
WM_MOVE
WM_NCACTIVATE
WM_NCCALCSIZE
WM_NCCREATE
WM_NCDESTROY
WM_PARENTNOTIFY
WM_POWER
WM_QUERYENDSESSION
WM_QUERYOPEN
WM_QUIT
WM_SETTEXT
WM_SHOWWINDOW
WM_SIZE
WM_WINDOWPOSCHANGED
WM_WINDOWPOSCHANGING


Carets

A caret is a flashing line, block, or bitmap in the client area of a window. The caret typically indicates the place at which text or graphics will be inserted. The following illustration shows some common variations in the appearance of the caret.

Because only one window at a time can have the keyboard focus or be active, there is only one caret in the system. Generally, each window that accepts keyboard input must create the caret when it receives the keyboard focus and destroy the caret when it loses the keyboard focus. For more information on keyboard input, see Keyboard Input.

An application written for Microsoft® Windows® can create a caret, display or hide it, relocate the caret, and change its blink time.


About Carets

An application uses the CreateCaret function to specify the parameters for a caret. Windows forms a caret by inverting the pixel color within the rectangle specified by the caret's position, width, and height. The width and height are specified in logical units; therefore, the appearance of a caret is subject to the window's mapping mode.

After the caret is defined, an application uses the ShowCaret function to make the caret visible. When the caret appears, it automatically begins flashing. To display a solid caret, Windows inverts every pixel in the rectangle; to display a gray caret, Windows inverts every other pixel; to display a bitmap caret, Windows inverts only the white bits of the bitmap.

The elapsed time, in milliseconds, required to invert the caret is called the blink time. An application can determine the caret's blink time by using the GetCaretBlinkTime function. If it is necessary to define a specific blink time, use the SetCaretBlinkTime function to set the rate of the blink time to a specified number of milliseconds. The flash time is the elapsed time, in milliseconds, required to display, invert, and restore the caret's display. The flash time of a caret is twice as much as the blink time.

An application can determine the caret's position by using the GetCaretPos function. The position, in client coordinates, is copied to a POINT structure specified by a parameter in GetCaretPos. An application can move a caret in a window by using the SetCaretPos function. A window can move a caret only if it already owns the caret. SetCaretPos can move the caret whether it is visible or not.


Removing a Caret

An application can use the HideCaret function to remove the caret from the screen. This is useful when your application must redraw the screen while processing a message, but must keep the caret out of the way. When the application finishes drawing, it can display the caret again by using the ShowCaret function. Hiding the caret does not destroy its shape or invalidate the insertion point. Hiding the caret is cumulative; that is, if the application calls HideCaret five times, it must also call ShowCaret five times before the caret will reappear.

An application can remove the caret from the screen and destroy its shape by using the DestroyCaret function. DestroyCaret destroys the caret only if the window involved in the current task owns the caret.


Using Carets

•	Creating and displaying a caret

•	Hiding a caret

•	Destroying a caret

•	Adjusting the blink time

•	Processing keyboard input


Creating and Displaying a Caret

Upon receiving the keyboard focus, the window should create and display the caret. Use the CreateCaret function to create a caret in the given window. You can then call SetCaretPos to set the current position of the caret and ShowCaret to make the caret visible.

The system sends the WM_SETFOCUS message to the window receiving keyboard focus; therefore, an application should create and display the caret while processing this message.

HWND hwnd,   /* window handle                   */

int x;       /* horizontal coordinate of cursor */

int y;       /* vertical coordinate of cursor   */

int nWidth;      /* width of cursor             */

int nHeight;     /* height of cursor            */

char *lpszChar;  /* pointer to character        */

    case WM_SETFOCUS:

        /* Create a solid black caret. */

        CreateCaret(hwnd, (HBITMAP) NULL, nWidth, nHeight);

        /* Adjust the caret position, in client coordinates. */

        SetCaretPos(x, y);

        /* Display the caret. */

        ShowCaret(hwnd);

        break;

To create a caret based on a bitmap, you must specify a bitmap handle when using CreateCaret. You can use a graphics application to create the bitmap and a resource compiler to add the bitmap to your application's resources. Your application can then use the LoadBitmap function to load the bitmap handle. For example, you could replace the CreateCaret line in the preceding example with the following lines to create a bitmap caret.

/* Load the application-defined caret resource. */

hCaret = LoadBitmap(hinst, MAKEINTRESOURCE(120));

/* Create a bitmap caret. */

CreateCaret(hwnd, hCaret, 0, 0);

Alternatively, you can use the CreateBitmap or CreateDIBitmap function to retrieve the handle of the caret bitmap. For more information about bitmaps, see Bitmaps.

If your application specifies a bitmap handle, CreateCaret ignores the width and height parameters. The bitmap defines the size of the caret.


Hiding a Caret

Whenever your application redraws a screen while processing a message other than WM_PAINT, it must make the caret invisible by using the HideCaret function. When your application is finished drawing, redisplay the caret by using the ShowCaret function. If your application processes the WM_PAINT message, it is not necessary to hide and redisplay the caret, because this function does this automatically.

The following code sample shows how to have your application hide the caret while drawing a character on the screen and while processing the WM_CHAR message.

HWND hwnd,   /* window handle                   */

HDC hdc;     /* device context                  */

    case WM_CHAR:

        switch (wParam) {

            case 0x08:

             .

             . /* Process a backspace. */

             .

                break;

            case 0x09:

             .

             . /* Process a tab. */

             .

                break;

            case 0x0D:

             .

             . /* Process a carriage return. */

             .

                break;

            case 0x1B:

             .

             . /* Process an escape. */

             .

                break;

            case 0x0A:

             .

             . /* Process a linefeed. */

             .

                break;

            default:

                /* Process all other characters. */

                /* Hide the caret. */

                HideCaret(hwnd);

                /* Draw the character on the screen. */

                hdc = GetDC(hwnd);

                SelectObject(hdc,

                    GetStockObject(SYSTEM_FIXED_FONT));

                TextOut(hdc, x, y, lpszChar, 1);

                ReleaseDC(hwnd, hdc);

                /* Display the caret. */

                ShowCaret(hwnd);

        }

If your application calls the HideCaret function several times without calling ShowCaret, the caret will not be displayed until the application also calls ShowCaret the same number of times.


Destroying a Caret

When a window loses the keyboard focus, the system sends the WM_KILLFOCUS message to the window. Your application should destroy the caret while processing this message by using the DestroyCaret function. The following code shows how to destroy a caret in a window that no longer has the keyboard focus.

case WM_KILLFOCUS:

    /*

     * The window is losing the keyboard focus,

     * so destroy the caret.

     */

    DestroyCaret();

    break;


Adjusting the Blink Time

Because there is only one caret in the system, use caution when your application must adjust the rate of the blink time, so as not to disrupt subsequent windows that may receive the keyboard focus. If your application changes the blink time, it must restore the blink time to its original value upon losing the keyboard focus. The GetCaretBlinkTime function returns the current blink time, in milliseconds, and the SetCaretBlinkTime function sets the blink time to the specified number of milliseconds.

If you anticipate that your application will adjust the blink time, add the following line to the WM_SETFOCUS message processing.

uOldBlink = GetCaretBlinkTime();

Then, you can restore the blink time to its original rate by including the following line in the WM_KILLFOCUS message processing.

SetCaretBlinkTime(uOldBlink);


Processing Keyboard Input

The following example demonstrates how to use a caret in a simple text editor. The example updates the caret position as the user types printable characters and uses various keys to move through the client area.

#define TEXTMATRIX(x, y) \

    *(pTextMatrix + (y * nWindowCharsX) + x)

HINSTANCE hinst;      /* current instance                 */

HBITMAP hCaret;       /* caret bitmap                     */

HDC hdc;              /* device context                   */

PAINTSTRUCT ps;       /* client area paint info           */

static char *pTextMatrix = NULL; /* points to text matrix */

static int  nCharX,   /* width of char. in logical units  */

            nCharY,   /* height of char. in logical units */

            nWindowX, /* width of client area             */

            nWindowY, /* height of client area            */

            nWindowCharsX, /* width of client area        */

            nWindowCharsY, /* height of client area       */

            nCaretPosX,    /* x-position of caret         */

            nCaretPosY;    /* y-position of caret         */

static UINT uOldBlink;     /* previous blink rate         */

int x, y;    /* x and y coordinates to use in text matrix */

TEXTMETRIC tm;             /* font information            */

LONG APIENTRY MainWndProc(

    HWND hwnd,            /* window handle              */

    UINT message,         /* type of message            */

    UINT wParam,          /* additional information     */

    LONG lParam)          /* additional information     */

{

switch (message) {

    case WM_CREATE:

        /*

         * Select a fixed-width system font,

         * and get the text metrics of the font.

         */

        hdc = GetDC(hwnd);

        SelectObject(hdc,

            GetStockObject(SYSTEM_FIXED_FONT));

        GetTextMetrics(hdc, &tm);

        ReleaseDC(hwnd, hdc);

        /* Save the avg. width and height of characters. */

        nCharX = tm.tmAveCharWidth;

        nCharY = tm.tmHeight;

        return 0;

    case WM_SIZE:

        /*

         * Determine the width of the client area, in pixels

         * and in number of characters.

         */

        nWindowX = LOWORD(lParam);

        nWindowCharsX = max(1, nWindowX/nCharX);

        /*

         * Determine the height of the client area, in

         * pixels and in number of characters.

         */

        nWindowY = HIWORD(lParam);

        nWindowCharsY = max(1, nWindowY/nCharY);

        /* Clear the buffer that holds the text input. */

        if (pTextMatrix != NULL) {

            free(pTextMatrix);

        }

        /*

         * If there is enough memory, allocate space for the

         * text input buffer.

         */

        pTextMatrix = malloc(nWindowCharsX * nWindowCharsY);

        if (pTextMatrix == NULL) {

            ErrorHandler("Not enough memory.");

        }

        else {

            for (y = 0; y < nWindowCharsY; y++)

                for (x = 0; x < nWindowCharsX; x++)

                    TEXTMATRIX(x, y) = ' ';

        }

        /* Move the caret to the origin. */

        SetCaretPos(0, 0);

        return 0;

    case WM_KEYDOWN:

        switch (wParam) {

            case VK_HOME:       /* Home */

                nCaretPosX = 0;

                break;

            case VK_END:        /* End */

                nCaretPosX = nWindowCharsX - 1;

                break;

            case VK_PRIOR:      /* Page Up */

                nCaretPosY = 0;

                break;

            case VK_NEXT:       /* Page Down */

                nCaretPosY = nWindowCharsY -1;

                break;

            case VK_LEFT:       /* Left arrow */

                nCaretPosX = max(nCaretPosX - 1, 0);

                break;

            case VK_RIGHT:      /* Right arrow */

                nCaretPosX = min(nCaretPosX + 1,

                    nWindowCharsX - 1);

                break;

            case VK_UP:         /* Up arrow */

                nCaretPosY = max(nCaretPosY - 1, 0);

                break;

            case VK_DOWN:       /* Down arrow */

                nCaretPosY = min(nCaretPosY + 1,

                    nWindowCharsY - 1);

                break;

            case VK_DELETE:     /* Delete */

                /*

                 * Move all the characters that followed the

                 * deleted character (on the same line) one

                 * space back (to the left) in the matrix.

                 */

                for (x = nCaretPosX; x < nWindowCharsX; x++)

                    TEXTMATRIX(x, nCaretPosY) =

                        TEXTMATRIX(x + 1, nCaretPosY);

                /*

                 * Replace the last character on the

                 * line with a space.

                 */

                TEXTMATRIX(nWindowCharsX - 1,

                    nCaretPosY) = ' ';

                /*

                 * The application will draw outside the

                 * WM_PAINT message processing, so hide the

                 * caret.

                 */

                HideCaret(hwnd);

                /*

                 * Redraw the line, adjusted for the

                 * deleted character.

                 */

                hdc = GetDC(hwnd);

                SelectObject(hdc,

                    GetStockObject(SYSTEM_FIXED_FONT));

                TextOut(hdc, nCaretPosX * nCharX,

                    nCaretPosY * nCharY,

                    &TEXTMATRIX(nCaretPosX, nCaretPosY),

                    nWindowCharsX - nCaretPosX);

                ReleaseDC(hwnd, hdc);

                /* Display the caret. */

                ShowCaret(hwnd);

                break;

        }

        /*

         * Adjust the caret position based on the

         * virtual-key processing.

         */

        SetCaretPos(nCaretPosX * nCharX,

            nCaretPosY * nCharY);

        return 0;

    case WM_CHAR:

        switch (wParam) {

            case 0x08:          /* Backspace */

                /*

                 * Move the caret back one space, and then

                 * process this like the DEL key.

                 */

                if (nCaretPosX > 0) {

                    nCaretPosX--;

                    SendMessage(hwnd, WM_KEYDOWN,

                        VK_DELETE, 1L);

                }

                break;

            case 0x09:          /* Tab */

                /*

                 * Tab stops exist every four spaces, so add

                 * spaces until the user hits the next tab.

                 */

                do {

                    SendMessage(hwnd, WM_CHAR, ' ', 1L);

                } while (nCaretPosX % 4 != 0);

                break;

            case 0x0D:          /* Carriage return */

                /*

                 * Go to the beginning of the next line.

                 * The bottom line wraps around to the top.

                 */

                nCaretPosX = 0;

                if (++nCaretPosY == nWindowCharsY) {

                    nCaretPosY = 0;

                }

                break;

            case 0x1B:        /* Escape */

            case 0x0A:        /* Linefeed */

                /* No processing. */

                MessageBeep((UINT) -1);

                break;

            default:            /* all other characters */

                /* Add the character to the text buffer. */

                TEXTMATRIX(nCaretPosX, nCaretPosY) =

                    (char) wParam;

                /*

                 * The application will draw outside the

                 * WM_PAINT message processing, so hide the

                 * caret.

                 */

                HideCaret(hwnd);

                /* Draw the character on the screen. */

                hdc = GetDC(hwnd);

                SelectObject(hdc,

                    GetStockObject(SYSTEM_FIXED_FONT));

                TextOut(hdc, nCaretPosX * nCharX,

                    nCaretPosY * nCharY,

                    &TEXTMATRIX(nCaretPosX, nCaretPosY), 1);

                ReleaseDC(hwnd, hdc);

                /* Display the caret. */

                ShowCaret(hwnd);

                /*

                 * Prepare to wrap around if you reached the

                 * end of the line.

                 */

                if (++nCaretPosX == nWindowCharsX) {

                    nCaretPosX = 0;

                    if (++nCaretPosY == nWindowCharsY) {

                        nCaretPosY = 0;

                    }

                }

                break;

        }

        /*

         * Adjust the caret position based on the

         * character processing.

         */

        SetCaretPos(nCaretPosX * nCharX,

            nCaretPosY * nCharY);

        return 0;

    case WM_PAINT:

        /*

         * Draw all the characters in the buffer, line by

         * line.

         */

        hdc = BeginPaint(hwnd, &ps);

        SelectObject(hdc,

            GetStockObject(SYSTEM_FIXED_FONT));

        for (y = 0; y < nWindowCharsY; y++)

            TextOut(hdc, 0, y * nCharY, &TEXTMATRIX(0, y),

                nWindowCharsX);

        EndPaint(hwnd, &ps);

    case WM_SETFOCUS:

        /*

         * The window has the input focus. Load the

         * application-defined caret resource.

         */

        hCaret = LoadBitmap(hinst, MAKEINTRESOURCE(120));

        /* Create the caret. */

        CreateCaret(hwnd, hCaret, 0, 0);

        /* Adjust the caret position. */

        SetCaretPos(nCaretPosX * nCharX,

            nCaretPosY * nCharY);

        /* Display the caret. */

        ShowCaret(hwnd);

        break;

    case WM_KILLFOCUS:

        /*

         * The window is losing the input focus,

         * so destroy the caret.

         */

        DestroyCaret();

        break;

    default:                /* passes it on if unprocessed */

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

}                       /* ends switch (message)      */

    return NULL;

}                       /* ends main window procedure */


Caret Functions

The following functions are used with carets.

CreateCaret
DestroyCaret
GetCaretBlinkTime
GetCaretPos
HideCaret
SetCaretBlinkTime
SetCaretPos
ShowCaret


Clipboard

The clipboard is a set of functions and messages that enable applications designed for the Microsoft® Win32® application programming interface (API) to transfer data. Because all applications have access to the clipboard, data can be easily transferred between applications or within an application.

This overview does not describe how to copy and paste linked or embedded objects. For information on these subjects, see the OLE Programmer's Reference in the OLE volume.


About the Clipboard

A memory object on the clipboard can be in any data format, called a clipboard format. Each format is identified by an unsigned integer value. For standard (predefined) clipboard formats, this value is a constant defined by the Win32 API; for registered clipboard formats, it is the return value of the RegisterClipboardFormat function.

Except for registering clipboard formats, individual windows perform most clipboard operations. Typically, a window procedure transfers information to or from the clipboard in response to the WM_COMMAND message.

The clipboard is user-driven. A window should transfer data to or from the clipboard only in response to a command from the user. A window must not use the clipboard to transfer data without the user's knowledge.


Clipboard Formats

A window can place more than one object on the clipboard, each representing the same information in a different clipboard format. Users need not be aware of the clipboard formats used for an object on the clipboard.


Registered Clipboard Formats

Many applications work with data that cannot be translated into a standard clipboard format without loss of information. Such applications can register new clipboard formats by using the RegisterClipboardFormat function. A clipboard format that is used by an application, as opposed to a standard clipboard format, is called a registered clipboard format. For example, if a word-processing application copied formatted text to the clipboard using a standard text format, the formatting information would be lost. The solution would be to register a new clipboard format, such as rich-text format (RTF).

If more than one application registers a clipboard format with exactly the same name, the clipboard format is registered only once. Both calls to the RegisterClipboardFormat function return the same value. In this way, two different applications can share data by using a registered clipboard format.

For a list of standard clipboard formats, see the SetClipboardData function.


Private Clipboard Formats

An application can identify a private clipboard format by defining a value in the range CF_PRIVATEFIRST through CF_PRIVATELAST. An application can use a private clipboard format for an application-defined data format that does not need to be registered with the system.

Data handles associated with private clipboard formats are automatically freed by the system. Windows that use private clipboard formats can use the WM_DESTROYCLIPBOARD message to free any related resources that are no longer needed.

For more information about the WM_DESTROYCLIPBOARD message, see Clipboard Ownership.

An application can place data handles on the clipboard by defining a private format in the range CF_GDIOBJFIRST through CF_GDIOBJLAST. When using values in this range, the data handle is not a handle to a GDI object, but is a handle allocated by the GlobalAlloc function with the GMEM_DDESHARE and GMEM_MOVEABLE flags. When the clipboard is emptied the system automatically deletes the object using the GlobalFree function


Multiple Clipboard Formats

A window can place more than one clipboard object on the clipboard, each representing the same information in a different clipboard format. When placing information on the clipboard, the window should provide data in as many formats as possible.

Clipboard formats that contain the most information should be placed on the clipboard first, followed by less descriptive formats. A window pasting information from the clipboard typically retrieves a clipboard object in the first format it recognizes. Because clipboard formats are enumerated in the order they are placed on the clipboard, the first recognized format is also the most descriptive.

For example, suppose a user copies styled text from a word-processing document. The window containing the document might first place data on the clipboard in a registered format, such as RTF. Subsequently, the window would place data on the clipboard in a less descriptive format, such as text (CF_TEXT).

When the content of the clipboard is pasted into another window, the window retrieves data in the most descriptive format it recognizes. If the window recognizes RTF, the corresponding data is pasted into the document. Otherwise, the text data is pasted into the document and the formatting information is lost.


Synthesized Clipboard Formats

The system implicitly converts data between certain clipboard formats: if a window requests data in a format that is not on the clipboard, the system converts an available format to the requested format. The system can convert data between the text formats CF_UNICODETEXT, CF_TEXT, and CF_OEMTEXT; between the metafile formats CF_ENHMETAFILE and CF_METAFILEPICT; and between the bitmap formats CF_BITMAP and CF_DIB. The system can also convert CF_DIB to CF_PALETTE.

If the system provides a conversion between multiple formats, there is no advantage to placing multiple formats on the clipboard. When copying bitmaps, it is best to place only the CF_DIB format on the clipboard. This is because the colors in a device-dependent bitmap (CF_BITMAP) are relative to the system palette, which may change before the bitmap is pasted. If only the CF_DIB format is on the clipboard and a window requests the CF_BITMAP format, the system renders the device-dependent bitmap (DIB) using the current palette at that time.

If you place the CF_BITMAP format on the clipboard (and not CF_DIB), the system renders the CF_DIB clipboard format as soon as the clipboard is closed. This ensures that the correct palette is used to generate the DIB. Conversions between other clipboard formats occur upon demand.


Clipboard Operations

A window should use the clipboard when cutting, copying, or pasting data. A window places data on the clipboard for cut and copy operations and retrieves data from the clipboard for paste operations. The following sections describe these operations and related issues.

To place data on or retrieve data from the clipboard, a window must first open the clipboard by using the OpenClipboard function. Only one window can have the clipboard open at a time. When it has finished, the window must close the clipboard by calling the CloseClipboard function.


Cut and Copy Operations

To place information on the clipboard, a window first clears any previous clipboard content by using the EmptyClipboard function. This function sends the WM_DESTROYCLIPBOARD message to the previous clipboard owner, frees resources associated with data on the clipboard, and assigns clipboard ownership to the window that has the clipboard open.

After emptying the clipboard, a window places data on the clipboard in as many clipboard formats as possible. For each format, the window calls the SetClipboardData function, specifying the format identifier and a global memory handle. The memory handle can be NULL, indicating that the window renders the data on request. (For more information about the rendering of data, see Delayed Rendering.) A window should place data on the clipboard in order from the most descriptive clipboard format to the least descriptive.


Paste Operations

To retrieve paste information from the clipboard, a window first determines the clipboard format to retrieve. Typically, a window enumerates the available clipboard formats by using the EnumClipboardFormats function and uses the first format it recognizes. This method selects the best available format according to the priority set when the data was placed on the clipboard.

Alternatively, a window can use the GetPriorityClipboardFormat function. This function identifies the best available clipboard format according to a specified priority. A window that recognizes only one clipboard format can simply determine whether that format is available by using the IsClipboardFormatAvailable function.

After determining the clipboard format to use, a window calls the GetClipboardData function. This function returns the handle of a global memory object containing data in the specified format. A window can briefly lock the memory object in order to examine or copy the data. However, a window should not free the object or leave it locked for a long period of time.


Clipboard Ownership

The clipboard owner is the window associated with the information on the clipboard. A window becomes the clipboard owner when it places data on the clipboard — specifically, when it calls the EmptyClipboard function. The window remains the clipboard owner until it is closed or another window empties the clipboard.

When the clipboard is emptied, the clipboard owner receives a WM_DESTROYCLIPBOARD message. Following are some reasons why a window might process this message:

•	The window delayed rendering of one or more clipboard formats. In response to the WM_DESTROYCLIPBOARD message, the window might free resources it had allocated in order to render data on request. For more information about the rendering of data, see Delayed Rendering.

•	The window placed data on the clipboard in a private clipboard format. The data for private clipboard formats is not freed by the system when the clipboard is emptied. Therefore, the clipboard owner should free the data upon receiving the WM_DESTROYCLIPBOARD message. For more information about private clipboard formats, see Clipboard Formats.

•	The window placed data on the clipboard using the CF_OWNERDISPLAY clipboard format. In response to the WM_DESTROYCLIPBOARD message, the window might free resources it had used to display information in the clipboard viewer window. For more information about this alternative format, see Owner-Display Format.


Delayed Rendering

When placing a clipboard format on the clipboard, a window can delay rendering the data in that format until the data is needed. To do so, an application can specify NULL for the hData parameter of the SetClipboardData function. This is useful if the application supports several clipboard formats, some or all of which are time-consuming to render. By passing a NULL handle, a window renders complex clipboard formats only when and if they are needed.

If a window delays rendering a clipboard format, it must be prepared to render the format upon request for as long as it is the clipboard owner. The system sends the clipboard owner a WM_RENDERFORMAT message when a request is received for a specific format that has not been rendered. Upon receiving this message, the window should call the SetClipboardData function to place a global memory handle on the clipboard in the requested format.

If the clipboard owner is destroyed and has delayed rendering some or all clipboard formats, it receives the WM_RENDERALLFORMATS message. Upon receiving this message, the window should place valid memory handles on the clipboard for all clipboard formats that it provides. This ensures that these formats remain available after the clipboard owner is destroyed.

An application should not open the clipboard before calling SetClipboardData in response to the WM_RENDERFORMAT or WM_RENDERALLFORMATS message.

Any clipboard formats that are not rendered in response to the WM_RENDERALLFORMATS message cease to be available to other applications and are no longer enumerated by the clipboard functions.


Memory and the Clipboard

A memory object that is to be placed on the clipboard should be allocated by using the GlobalAlloc function with the GMEM_DDESHARE and GMEM_MOVEABLE flags.

Once a memory object is placed on the clipboard, ownership of that memory handle is transferred to the system. When the clipboard is emptied and the memory object has one of the following clipboard formats, the system frees the memory object by calling the indicated Win32 function:

Function called to free object	Clipboard format
DeleteMetaFile	CF_DSPENHMETAFILE
	CF_DSPMETAFILEPICT
	CF_ENHMETAFILE
	CF_METAFILEPICT
DeleteObject	CF_BITMAP
	CF_DSPBITMAP
	CF_PALETTE
GlobalFree	CF_DIB
	CF_DSPTEXT
	CF_OEMTEXT
	CF_TEXT
	CF_UNICODETEXT
When the clipboard is emptied of a memory object whose clipboard format is not shown in the preceding list, the application itself must free the memory object.


Clipboard Viewers

A clipboard viewer is a window that displays the current content of the clipboard. The clipboard viewer window is a convenience for the user and does not affect the data-transaction functions of the clipboard.

Typically, a clipboard viewer window can display at least the three most common formats: CF_TEXT, CF_BITMAP, and CF_METAFILEPICT. If a window does not make data available in any of these three formats, it should provide data in a display format or use the owner-display format.

A clipboard viewer chain is the linking together of two or more entities so that they are dependent upon one another for operation. This interdependency (chain) allows all running clipboard viewer applications to receive the messages sent to the current clipboard.


Clipboard Viewer Windows

A window adds itself to the clipboard viewer chain by calling the SetClipboardViewer function. The return value is the handle of the next window in the chain. Each clipboard viewer window must keep track of the next window in the clipboard viewer chain. When the content of the clipboard changes, the system sends a WM_DRAWCLIPBOARD message to the first window in the chain. After updating its display, each clipboard viewer window must pass this message on to the next window in the chain.

Before closing, a clipboard viewer window must remove itself from the clipboard viewer chain by calling the ChangeClipboardChain function. The system then sends a WM_CHANGECBCHAIN message to the first window in the chain.

For more information about processing the WM_DRAWCLIPBOARD and WM_CHANGECBCHAIN messages, see Creating a Clipboard Viewer Window.


Display Formats

A display format is a clipboard format used to display information in a clipboard viewer window. A clipboard owner that uses a private or registered clipboard format, and none of the most common standard formats, must provide data in a display format for viewing in a clipboard viewer window. The display formats are intended for viewing only and must not be pasted into a document.

The four display formats are: CF_DSPBITMAP, CF_DSPMETAFILEPICT, CF_DSPTEXT, and CF_DSPENHMETAFILE. These display formats are rendered in the same way as the standard formats, which are: CF_BITMAP, CF_TEXT, CF_METAFILEPICT, and CF_ENHMETAFILE.


Owner-Display Format

For a clipboard owner that does not use any of the common standard clipboard formats, an alternative to providing a display format is to use the owner-display (CF_OWNERDISPLAY) clipboard format.

By using the owner-display format, a clipboard owner can avoid the overhead of rendering data in an additional format by taking direct control over painting the clipboard viewer window. The clipboard viewer window sends messages to the clipboard owner whenever a portion of the window must be repainted or when the window is scrolled or resized.


Clipboard Commands

A user typically carries out clipboard operations by choosing commands from an application's Edit menu. Following is a brief description of the standard clipboard commands.

Command	Description
Cut	Places a copy of the current selection on the clipboard and deletes the selection from the document. The previous content of the clipboard is destroyed.
Copy	Places a copy of the current selection on the clipboard. The document remains unchanged. The previous content of the clipboard is destroyed.
Paste	Replaces the current selection with the content of the clipboard. The content of the clipboard is not changed.
Delete	Deletes the current selection from the document. The content of the clipboard is not changed. This command does not involve the clipboard, but it should appear with the clipboard commands on the Edit menu.


Using the Clipboard

•	Implementing the Cut, Copy, and Paste commands

•	Creating a clipboard viewer window


Implementing the Cut, Copy, and Paste Commands

This section describes how standard Cut, Copy, and Paste commands are implemented in an application. The example in this section uses these methods to place data on the clipboard using a registered clipboard format, the CF_OWNERDISPLAY format, and the CF_TEXT format. The registered format is used to represent rectangular or elliptical text windows, called labels.


Selecting Data

Before information can be copied to the clipboard, the user must select specific information to be copied or cut. An application should provide a means for the user to select information within a document and some kind of visual feedback to indicate selected data.


Creating an Edit Menu

An application should load an accelerator table containing the standard keyboard accelerators for the Edit menu commands. The TranslateAccelerator function must be added to the application's message loop for the accelerators to take effect. For more information about keyboard acceleratiors, see Keyboard Accelerators.


Processing the WM_INITMENUPOPUP Message

Not all clipboard commands are available to the user at any given time. An application should process the WM_INITMENUPOPUP message to enable the menu items for available commands and disable unavailable commands.

Following is the WM_INITMENUPOPUP case for an application named Label.

case WM_INITMENUPOPUP:
    InitMenu((HMENU) wParam);
    break;

The InitMenu function is defined as follows.

void PASCAL InitMenu(HMENU hmenu)

{

    int  cMenuItems = GetMenuItemCount(hmenu);

    int  nPos;

    UINT id;

    UINT fuFlags;

    PLABELBOX pbox = (hwndSelected == NULL) ? NULL :

        (PLABELBOX) GetWindowLong(hwndSelected, 0);

    for (nPos = 0; nPos < cMenuItems; nPos++) {

        id = GetMenuItemID(hmenu, nPos);

        switch (id) {

            case IDM_CUT:

            case IDM_COPY:

            case IDM_DELETE:

                if (pbox == NULL || !pbox->fSelected)

                    fuFlags = MF_BYCOMMAND | MF_GRAYED;

                else if (pbox->fEdit)

                    fuFlags = (id != IDM_DELETE && pbox->ichSel

                            == pbox->ichCaret) ?

                        MF_BYCOMMAND | MF_GRAYED :

                        MF_BYCOMMAND | MF_ENABLED;

                else

                    fuFlags = MF_BYCOMMAND | MF_ENABLED;

                EnableMenuItem(hmenu, id, fuFlags);

                break;

            case IDM_PASTE:

                if (pbox != NULL && pbox->fEdit)

                    EnableMenuItem(hmenu, id,

                        IsClipboardFormatAvailable(CF_TEXT) ?

                            MF_BYCOMMAND | MF_ENABLED :

                            MF_BYCOMMAND | MF_GRAYED

                    );

                else

                    EnableMenuItem(hmenu, id,

                        IsClipboardFormatAvailable(

                                uLabelFormat) ?

                            MF_BYCOMMAND | MF_ENABLED :

                            MF_BYCOMMAND | MF_GRAYED

                    );

        }

    }

}


Processing the WM_COMMAND Message

To process menu commands, add the WM_COMMAND case to your application's main window procedure. Following is the WM_COMMAND case for the Label application's window procedure.

case WM_COMMAND:

    switch (LOWORD(wParam)) {

        case IDM_CUT:

            if (EditCopy())

                EditDelete();

            break;

        case IDM_COPY:

            EditCopy();

            break;

        case IDM_PASTE:

            EditPaste();

            break;

        case IDM_DELETE:

            EditDelete();

            break;

        case IDM_EXIT:

            DestroyWindow(hwnd);

    }

    break;

To carry out the Copy and Cut commands, the window procedure calls the application-defined EditCopy function. For more information about the EditCopy function, see Copying Information to the Clipboard. To carry out the Paste command, the window procedure calls the application-defined EditPaste function. For more information about the EditPaste function, see Pasting Information from the Clipboard.


Copying Information to the Clipboard

In the Label application, the application-defined EditCopy function copies the current selection to the clipboard. This function does the following:

1.	Opens the clipboard by calling the OpenClipboard function.

2.	Empties the clipboard by calling the EmptyClipboard function.

3.	Calls the SetClipboardData function once for each clipboard format the application provides.

4.	Closes the clipboard by calling the CloseClipboard function.

Depending on the current selection, the EditCopy function either copies a range of text or copies an application-defined structure representing an entire label. The structure, called LABELBOX, is defined as follows.

#define BOX_ELLIPSE  0

#define BOX_RECT     1

#define CCH_MAXLABEL 80

#define CX_MARGIN    12

typedef struct tagLABELBOX {  /* box */

    RECT rcText;    /* coordinates of rectangle containing text  */

    BOOL fSelected; /* TRUE if the label is selected             */

    BOOL fEdit;     /* TRUE if text is selected                  */

    int nType;      /* rectangular or elliptical                 */

    int ichCaret;   /* caret position                            */

    int ichSel;     /* with ichCaret, delimits selection         */

    int nXCaret;    /* window position corresponding to ichCaret */

    int nXSel;      /* window position corresponding to ichSel   */

    int cchLabel;   /* length of text in atchLabel               */

    TCHAR atchLabel[CCH_MAXLABEL];

} LABELBOX, *PLABELBOX;

Following is the EditCopy function.

BOOL PASCAL EditCopy(VOID)

{

    PLABELBOX pbox;

    LPTSTR  lptstrCopy;

    HGLOBAL hglbCopy;

    int ich1, ich2, cch;

    if (hwndSelected == NULL)

        return FALSE;

    /* Open the clipboard, and empty it. */

    if (!OpenClipboard(hwndMain))

        return FALSE;

    EmptyClipboard();

    /* Get a pointer to the structure for the selected label. */

    pbox = (PLABELBOX) GetWindowLong(hwndSelected, 0);

    /* If text is selected, copy it using the CF_TEXT format. */

    if (pbox->fEdit) {

        if (pbox->ichSel == pbox->ichCaret) {   /* zero-length */

            CloseClipboard();                   /* selection   */

            return FALSE;

        }

        if (pbox->ichSel < pbox->ichCaret) {

            ich1 = pbox->ichSel;

            ich2 = pbox->ichCaret;

        }

        else {

            ich1 = pbox->ichCaret;

            ich2 = pbox->ichSel;

        }

        cch = ich2 - ich1;

        /* Allocate a global memory object for the text. */

        hglbCopy = GlobalAlloc(GMEM_DDESHARE,

            (cch + 1) * sizeof(TCHAR));

        if (hglbCopy == NULL) {

            CloseClipboard();

            return FALSE;

        }

        /* Lock the handle and copy the text to the buffer. */

        lptstrCopy = GlobalLock(hglbCopy);

        memcpy(lptstrCopy, &pbox->atchLabel[ich1],

            cch * sizeof(TCHAR));

        lptstrCopy[cch] = (TCHAR) 0;    /* null character */

        GlobalUnlock(hglbCopy);

        /* Place the handle on the clipboard. */

        SetClipboardData(CF_TEXT, hglbCopy);

    }

    /* If no text is selected, the label as a whole is copied. */

    else {

        /*

         * Save a copy of the selected label as a local memory

         * object. This copy is used to render data on request.

         * It is freed in response to the WM_DESTROYCLIPBOARD

         * message.

         */

        pboxLocalClip = (PLABELBOX) LocalAlloc(

            LMEM_FIXED,

            sizeof(LABELBOX)

        );

        if (pboxLocalClip == NULL) {

            CloseClipboard();

            return FALSE;

        }

        memcpy(pboxLocalClip, pbox, sizeof(LABELBOX));

        pboxLocalClip->fSelected = FALSE;

        pboxLocalClip->fEdit = FALSE;

        /*

         * Place a registered clipboard format, the owner-display

         * format, and the CF_TEXT format on the clipboard using

         * delayed rendering.

         */

        SetClipboardData(uLabelFormat, NULL);

        SetClipboardData(CF_OWNERDISPLAY, NULL);

        SetClipboardData(CF_TEXT, NULL);

    }

    /* Close the clipboard. */

    CloseClipboard();

    return TRUE;

}


Pasting Information from the Clipboard

In the Label application, the application-defined EditPaste function pastes the content of the clipboard. This function does the following:

1.	Opens the clipboard by calling the OpenClipboard function.

2.	Determines which of the available clipboard formats to retrieve.

3.	Retrieves the handle of the data in the selected format by calling the GetClipboardData function.

4.	Inserts a copy of the data into the document.

The handle returned by GetClipboardData is still owned by the clipboard, so an application must not free it or leave it locked.

5.	Closes the clipboard by calling the CloseClipboard function.

If a label is selected and contains an insertion point, the EditPaste function inserts the text from the clipboard at the insertion point. If there is no selection or if a label is selected, the function creates a new label, using the application-defined LABELBOX structure on the clipboard. The LABELBOX structure is placed on the clipboard by using a registered clipboard format.

Following is the EditPaste function.

VOID PASCAL EditPaste(VOID)

{

    PLABELBOX pbox;

    HGLOBAL   hglb;

    LPTSTR    lptstr;

    PLABELBOX pboxCopy;

    int cx, cy;

    HWND hwnd;

    pbox = hwndSelected == NULL ? NULL :

        (PLABELBOX) GetWindowLong(hwndSelected, 0);

    /*

     * If the application is in edit mode,

     * get the clipboard text.

     */

    if (pbox != NULL && pbox->fEdit) {

        if (!IsClipboardFormatAvailable(CF_TEXT))

            return;

        if (!OpenClipboard(hwndMain))

            return;

        hglb = GetClipboardData(CF_TEXT);

        if (hglb != NULL) {

            lptstr = GlobalLock(hglb);

            if (lptstr != NULL) {

                /*

                 * Call the application-defined ReplaceSelection

                 * function to insert the text and repaint the

                 * window.

                 */

                ReplaceSelection(hwndSelected, pbox, lptstr);

                GlobalUnlock(hglb);

            }

        }

        CloseClipboard();

        return;

    }

    /*

     * If the application is not in edit mode,

     * create a label window.

     */

    if (!IsClipboardFormatAvailable(uLabelFormat))

        return;

    if (!OpenClipboard(hwndMain))

        return;

    hglb = GetClipboardData(uLabelFormat);

    if (hglb != NULL) {

        pboxCopy = GlobalLock(hglb);

        if (pboxCopy != NULL) {

            cx = pboxCopy->rcText.right + CX_MARGIN;

            cy = pboxCopy->rcText.top * 2 + cyText;

            hwnd = CreateWindowEx(

                WS_EX_NOPARENTNOTIFY | WS_EX_TRANSPARENT,

                atchClassChild, NULL, WS_CHILD, 0, 0, cx, cy,

                hwndMain, NULL, hinst, NULL

            );

            if (hwnd != NULL) {

                pbox = (PLABELBOX) GetWindowLong(hwnd, 0);

                memcpy(pbox, pboxCopy, sizeof(LABELBOX));

                ShowWindow(hwnd, SW_SHOWNORMAL);

                SetFocus(hwnd);

            }

            GlobalUnlock(hglb);

        }

    }

    CloseClipboard();

}


Registering a Clipboard Format

To register a clipboard format, add a call to the RegisterClipboardFormat function to your application's instance initialization function, as follows.

/* Register a clipboard format. */

LoadString(hinstCurrent, IDS_FORMATNAME, atchTemp,

    sizeof(atchTemp));

uLabelFormat = RegisterClipboardFormat(atchTemp);

if (uLabelFormat == 0)

    return FALSE;


Processing the WM_RENDERFORMAT and WM_RENDERALLFORMATS Messages

If a window passes a NULL handle to the SetClipboardData function, it must process the WM_RENDERFORMAT and WM_RENDERALLFORMATS messages to render data upon request.

If the WM_RENDERFORMAT message delayed rendering a specific format and an application requested data in that format, the message is sent to the clipboard owner. If the WM_RENDERFORMAT message has delayed rendering one or more formats, the message is sent to the clipboard owner before it is destroyed.

To render a clipboard format, the window procedure must place a data handle on the clipboard by using the SetClipboardData function. It must not open the clipboard before calling SetClipboardData.

The Label application processes the WM_RENDERFORMAT and WM_RENDERALLFORMATS messages as follows.

case WM_RENDERFORMAT:

    RenderFormat((UINT) wParam);

    break;

case WM_RENDERALLFORMATS:

    RenderFormat(uLabelFormat);

    RenderFormat(CF_TEXT);

    break;

In both cases, the window procedure calls the application-defined RenderFormat function, defined as follows.

void PASCAL RenderFormat(UINT uFormat)

{

    HGLOBAL hglb;

    PLABELBOX pbox;

    LPTSTR  lptstr;

    int cch;

    if (pboxLocalClip == NULL)

        return;

    if (uFormat == CF_TEXT) {

        /* Allocate a buffer for the text. */

        cch = pboxLocalClip->cchLabel;

        hglb = GlobalAlloc(GMEM_DDESHARE,

            (cch + 1) * sizeof(TCHAR));

        if (hglb == NULL)

            return;

        /* Copy the text from pboxLocalClip. */

        lptstr = GlobalLock(hglb);

        memcpy(lptstr, pboxLocalClip->atchLabel,

            cch * sizeof(TCHAR));

        lptstr[cch] = (TCHAR) 0;

        GlobalUnlock(hglb);

        /* Place the handle on the clipboard. */

        SetClipboardData(CF_TEXT, hglb);

    }

    else if (uFormat == uLabelFormat) {

        hglb = GlobalAlloc(GMEM_DDESHARE, sizeof(LABELBOX));

        if (hglb == NULL)

            return;

        pbox = GlobalLock(hglb);

        memcpy(pbox, pboxLocalClip, sizeof(LABELBOX));

        GlobalUnlock(hglb);

        SetClipboardData(uLabelFormat, hglb);

    }

}


Processing the WM_DESTROYCLIPBOARD Message

A window can process the WM_DESTROYCLIPBOARD message in order to free any resources that it set aside to support delayed rendering. For example the Label application, when copying a label to the clipboard, allocates a local memory object. It then frees this object in response to the WM_DESTROYCLIPBOARD message, as follows.

case WM_DESTROYCLIPBOARD:

    if (pboxLocalClip != NULL) {

        LocalFree(pboxLocalClip);

        pboxLocalClip = NULL;

    }

    break;


Using the Owner-Display Clipboard Format

If a window places information on the clipboard by using the CF_OWNERDISPLAY clipboard format, it must do the following:

•	Process the WM_PAINTCLIPBOARD message. This message is sent to the clipboard owner when a portion of the clipboard viewer window must be repainted.

•	Process the WM_SIZECLIPBOARD message. This message is sent to the clipboard owner when the clipboard viewer window has been resized or its content has changed.

Typically, a window responds to this message by setting the scroll positions and ranges for the clipboard viewer window. In response to this message, the Label application also updates a SIZE structure for the clipboard viewer window.

•	Process the WM_HSCROLLCLIPBOARD and WM_VSCROLLCLIPBOARD messages. These messages are sent to the clipboard owner when a scroll bar event occurs in the clipboard viewer window.

•	Process the WM_ASKCBFORMATNAME message. The clipboard viewer window sends this message to an application to retrieve the name of the owner-display format.

The window procedure for the Label application processes these messages, as follows.

LRESULT CALLBACK MainWindowProc(hwnd, msg, wParam, lParam)

HWND hwnd;

UINT msg;

WPARAM wParam;

LPARAM lParam;

{

    static RECT rcViewer;

    RECT rc;

    LPRECT lprc;

    LPPAINTSTRUCT lpps;

    .

    .

    .

    switch (msg) {

        .

        .

        .

        case WM_PAINTCLIPBOARD:

            /* Determine the dimensions of the label. */

            SetRect(&rc, 0, 0,

                pboxLocalClip->rcText.right + CX_MARGIN,

                pboxLocalClip->rcText.top * 2 + cyText

            );

            /* Center the image in the clipboard viewer window. */

            if (rc.right < rcViewer.right) {

                rc.left = (rcViewer.right - rc.right) / 2;

                rc.right += rc.left;

            }

            if (rc.bottom < rcViewer.bottom) {

                rc.top = (rcViewer.bottom - rc.bottom) / 2;

                rc.bottom += rc.top;

            }

            /*

             * Paint the image, using the specified PAINTSTRUCT

             * structure, by calling the application-defined

             * PaintLabel function.

             */

            lpps = (LPPAINTSTRUCT) GlobalLock((HGLOBAL) lParam);

            PaintLabel(lpps, pboxLocalClip, &rc);

            GlobalUnlock((HGLOBAL) lParam);

            break;

        case WM_SIZECLIPBOARD:

            /*

             * Save the dimensions of the window in a static

             * RECT structure.

             */

            lprc = (LPRECT) GlobalLock((HGLOBAL) lParam);

            memcpy(&rcViewer, lprc, sizeof(RECT));

            GlobalUnlock((HGLOBAL) lParam);

            /*

             * Set the scroll ranges to zero (thus eliminating

             * the need to process the WM_HSCROLLCLIPBOARD and

             * WM_VSCROLLCLIPBOARD messages).

             */

            SetScrollRange((HWND) wParam, SB_HORZ, 0, 0, TRUE);

            SetScrollRange((HWND) wParam, SB_VERT, 0, 0, TRUE);

            break;

        case WM_ASKCBFORMATNAME:

            LoadString(hinst, IDS_OWNERDISPLAY,

                (LPSTR) lParam, wParam);

            break;

            .

            .

            .

        default:

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

    }

    return 0;

}


Creating a Clipboard Viewer Window

A clipboard viewer window displays the current content of the clipboard, and receives messages when the clipboard content changes. To create a clipboard viewer window, your application must do the following:

•	Add the window to the clipboard viewer chain.

•	Process the WM_CHANGECBCHAIN message.

•	Process the WM_DRAWCLIPBOARD message.

•	Remove the window from the clipboard viewer chain before it is destroyed.


Adding a Window to the Clipboard Viewer Chain

A window adds itself to the clipboard viewer chain by calling the SetClipboardViewer function. The return value is the handle of the next window in the chain. A window must keep track of this value — for example, by saving it in a static variable named hwndNextViewer.

The following example adds a window to the clipboard viewer chain in response to the WM_CREATE message.

case WM_CREATE:

    /* Add the window to the clipboard viewer chain. */

    hwndNextViewer = SetClipboardViewer(hwnd);

    break;


Processing the WM_CHANGECBCHAIN Message

A clipboard viewer window receives the WM_CHANGECBCHAIN message when another window is removing itself from the clipboard viewer chain. If the window being removed is the next window in the chain, the window receiving the message must unlink the next window from the chain. Otherwise, this message should be passed to the next window in the chain.

The following example shows the processing of the WM_CHANGECBCHAIN message.

case WM_CHANGECBCHAIN:

    /* If the next window is closing, repair the chain. */

    if ((HWND) wParam == hwndNextViewer)

        hwndNextViewer = (HWND) lParam;

    /* Otherwise, pass the message to the next link. */

    else if (hwndNextViewer != NULL)

        SendMessage(hwndNextViewer, uMsg, wParam, lParam);

    break;


Removing a Window from the Clipboard Viewer Chain

To remove itself from the clipboard viewer chain, a window calls the ChangeClipboardChain function. The following example removes a window from the clipboard viewer chain in response to the WM_DESTROY message.

case WM_DESTROY:

    ChangeClipboardChain(hwnd, hwndNextViewer);

    PostQuitMessage(0);

    break;


Processing the WM_DRAWCLIPBOARD Message

The WM_DRAWCLIPBOARD message notifies a clipboard viewer window that the content of the clipboard has changed. A window should do the following when processing the WM_DRAWCLIPBOARD message:

1.	Determine which of the available clipboard formats to display.

2.	Retrieve the clipboard data and display it in the window. Or if the clipboard format is CF_OWNERDISPLAY, send a WM_PAINTCLIPBOARD message to the clipboard owner.

3.	Send the message to the next window in the clipboard viewer chain.

For an example of processing the WM_DRAWCLIPBOARD message, see the example listing in Example of a Clipboard Viewer.


Example of a Clipboard Viewer

The following example shows a simple clipboard viewer application.

HINSTANCE hinst;

UINT uFormat = (UINT)(-1);

BOOL fAuto = TRUE;

LRESULT APIENTRY MainWndProc(hwnd, uMsg, wParam, lParam)

HWND hwnd;

UINT uMsg;

WPARAM wParam;

LPARAM lParam;

{

    static HWND hwndNextViewer;

    HDC hdc;

    HDC hdcMem;

    PAINTSTRUCT ps;

    LPPAINTSTRUCT lpps;

    RECT rc;

    LPRECT lprc;

    HGLOBAL hglb;

    LPSTR lpstr;

    HBITMAP hbm;

    HENHMETAFILE hemf;

    HWND hwndOwner;

    switch (uMsg) {

        case WM_PAINT:

            hdc = BeginPaint(hwnd, &ps);

            /* Branch depending on the clipboard format. */

            switch (uFormat) {

                case CF_OWNERDISPLAY:

                    hwndOwner = GetClipboardOwner();

                    hglb = GlobalAlloc(GMEM_DDESHARE,

                        sizeof(PAINTSTRUCT));

                    lpps = GlobalLock(hglb);

                    memcpy(lpps, &ps, sizeof(PAINTSTRUCT));

                    GlobalUnlock(hglb);

                    SendMessage(hwndOwner, WM_PAINTCLIPBOARD,

                        (WPARAM) hwnd, (LPARAM) hglb);

                    GlobalFree(hglb);

                    break;

                case CF_BITMAP:

                    hdcMem = CreateCompatibleDC(hdc);

                    if (hdcMem != NULL) {

                        if (OpenClipboard(hwnd)) {

                            hbm = (HBITMAP)

                                GetClipboardData(uFormat);

                            SelectObject(hdcMem, hbm);

                            GetClientRect(hwnd, &rc);

                            BitBlt(hdc, 0, 0, rc.right, rc.bottom,

                                hdcMem, 0, 0, SRCCOPY);

                            CloseClipboard();

                        }

                        DeleteDC(hdcMem);

                    }

                    break;

                case CF_TEXT:

                    if (OpenClipboard(hwnd)) {

                        hglb = GetClipboardData(uFormat);

                        lpstr = GlobalLock(hglb);

                        GetClientRect(hwnd, &rc);

                        DrawText(hdc, lpstr, -1, &rc, DT_LEFT);

                        GlobalUnlock(hglb);

                        CloseClipboard();

                    }

                    break;

                case CF_ENHMETAFILE:

                    if (OpenClipboard(hwnd)) {

                        hemf = GetClipboardData(uFormat);

                        GetClientRect(hwnd, &rc);

                        PlayEnhMetaFile(hdc, hemf, &rc);

                        CloseClipboard();

                    }

                    break;

                case 0:

                    GetClientRect(hwnd, &rc);

                    DrawText(hdc, "The clipboard is empty.", -1,

                        &rc, DT_CENTER | DT_SINGLELINE |

                        DT_VCENTER);

                    break;

                default:

                    GetClientRect(hwnd, &rc);

                    DrawText(hdc, "Unable to display format.", -1,

                        &rc, DT_CENTER | DT_SINGLELINE |

                        DT_VCENTER);

            }

            EndPaint(hwnd, &ps);

            break;

        case WM_SIZE:

            if (uFormat == CF_OWNERDISPLAY) {

                hwndOwner = GetClipboardOwner();

                hglb = GlobalAlloc(GMEM_DDESHARE, sizeof(RECT));

                lprc = GlobalLock(hglb);

                GetClientRect(hwnd, lprc);

                GlobalUnlock(hglb);

                SendMessage(hwndOwner, WM_SIZECLIPBOARD,

                    (WPARAM) hwnd, (LPARAM) hglb);

                GlobalFree(hglb);

            }

            break;

        case WM_CREATE:

            /* Add the window to the clipboard viewer chain. */

            hwndNextViewer = SetClipboardViewer(hwnd);

            break;

        case WM_CHANGECBCHAIN:

            /* If the next window is closing, repair the chain. */

            if ((HWND) wParam == hwndNextViewer)

                hwndNextViewer = (HWND) lParam;

            /* Otherwise, pass the message to the next link. */

            else if (hwndNextViewer != NULL)

                SendMessage(hwndNextViewer, uMsg, wParam, lParam);

            break;

        case WM_DESTROY:

            ChangeClipboardChain(hwnd, hwndNextViewer);

            PostQuitMessage(0);

            break;

        case WM_DRAWCLIPBOARD:  /* clipboard contents changed. */

            /*

             * Update the window by using Auto clipboard format.

             */

            SetAutoView(hwnd);

            /*

             * Pass the message to the next window in clipboard

             * viewer chain.

             */

            SendMessage(hwndNextViewer, uMsg, wParam, lParam);

            break;

        case WM_INITMENUPOPUP:

            if (!HIWORD(lParam))

                InitMenu(hwnd, (HMENU) wParam);

            break;

        case WM_COMMAND:

            switch (LOWORD(wParam)) {

                case IDM_EXIT:

                    DestroyWindow(hwnd);

                    break;

                case IDM_AUTO:

                    SetAutoView(hwnd);

                    break;

                default:

                    fAuto = FALSE;

                    uFormat = LOWORD(wParam);

                    InvalidateRect(hwnd, NULL, TRUE);

            }

            break;

        default:

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

    }

    return (LRESULT) NULL;

}

void PASCAL SetAutoView(HWND hwnd)

{

    static UINT auPriorityList[] = {

        CF_OWNERDISPLAY,

        CF_TEXT,

        CF_ENHMETAFILE,

        CF_BITMAP

    };

    uFormat = GetPriorityClipboardFormat(auPriorityList, 4);

    fAuto = TRUE;

    InvalidateRect(hwnd, NULL, TRUE);

    UpdateWindow(hwnd);

}

void PASCAL InitMenu(HWND hwnd, HMENU hmenu)

{

    UINT uFormat;

    char szFormatName[80];

    LPCSTR lpFormatName;

    UINT fuFlags;

    UINT idMenuItem;

    /*

     * If a menu is not the display menu, no initialization is necessary. */

     */

    if (GetMenuItemID(hmenu, 0) != IDM_AUTO)

        return;

    /* Delete all menu items except the first. */

    while (GetMenuItemCount(hmenu) > 1)

        DeleteMenu(hmenu, 1, MF_BYPOSITION);

    /* Check or uncheck the Auto menu item. */

    fuFlags = fAuto ? MF_BYCOMMAND | MF_CHECKED :

        MF_BYCOMMAND | MF_UNCHECKED;

    CheckMenuItem(hmenu, IDM_AUTO, fuFlags);

    /* If there are no clipboard formats, return. */

    if (CountClipboardFormats() == 0)

        return;

    /* Open the clipboard. */

    if (!OpenClipboard(hwnd))

        return;

    /* Add a separator and then a menu item for each format. */

    AppendMenu(hmenu, MF_SEPARATOR, 0, NULL);

    uFormat = EnumClipboardFormats(0);

    while (uFormat) {

        /*

         * Call an application-defined function to get the name

         * of the clipboard format.

         */

        lpFormatName = GetPredefinedClipboardFormatName(uFormat);

        /* For registered formats, get the registered name. */

        if (lpFormatName == NULL) {

            if (GetClipboardFormatName(uFormat, szFormatName,

                    sizeof(szFormatName)))

                lpFormatName = szFormatName;

            else

                lpFormatName = "(unknown)";

        }

        /*

         * Add a menu item for the format. For displayable

         * formats, use the format ID for the menu ID.

         */

        if (IsDisplayableFormat(uFormat)) {

            fuFlags = MF_STRING;

            idMenuItem = uFormat;

        }

        else {

            fuFlags = MF_STRING | MF_GRAYED;

            idMenuItem = 0;

        }

        AppendMenu(hmenu, fuFlags, idMenuItem, lpFormatName);

        uFormat = EnumClipboardFormats(uFormat);

    }

    CloseClipboard();

}

BOOL PASCAL IsDisplayableFormat(UINT uFormat)

{

    switch (uFormat) {

        case CF_OWNERDISPLAY:

        case CF_TEXT:

        case CF_ENHMETAFILE:

        case CF_BITMAP:

            return TRUE;

    }

    return FALSE;

}


Clipboard Reference

The following functions and messages are associated with the Clipboard.


Clipboard Functions

Following are the functions used with the Clipboard.

ChangeClipboardChain
CloseClipboard
CountClipboardFormats
EmptyClipboard
EnumClipboardFormats
GetClipboardData
GetClipboardFormatName
GetClipboardOwner
GetClipboardViewer
GetOpenClipboardWindow
GetPriorityClipboardFormat
IsClipboardFormatAvailable
OpenClipboard
RegisterClipboardFormat
SetClipboardData
SetClipboardViewer


Clipboard Messages

Following are the messages used with the clipboard.

WM_ASKCBFORMATNAME
WM_CHANGECBCHAIN
WM_COPY
WM_CUT
WM_DESTROYCLIPBOARD
WM_DRAWCLIPBOARD
WM_HSCROLLCLIPBOARD
WM_PAINTCLIPBOARD
WM_PASTE
WM_RENDERALLFORMATS
WM_RENDERFORMAT
WM_SIZECLIPBOARD
WM_VSCROLLCLIPBOARD


Chapter 1


Common Dialog Box Library

The following Windows 95 overview discusses the Common Dialog Box Library. Various common dialog boxes are described, and examples are included to help you use common dialog boxes in your Win32-based applications.


Common Dialog Box Library Platform Differences

The overviews for common dialog box libraries in Windows 95 and Windows NT are substantially different. To accommodate these differences, the Windows 95 overview is first presented in its entirety, followed by the Windows NT version.


About Common Dialog Boxes

Windows 95 Overview
For more information, see the Windows NT overview About Common Dialog Boxes.

Common dialog boxes are the standard file, print, color, font, and search dialog boxes used by applications based on the Microsoft Win32 application programming interface (API). Common dialog boxes provide a uniform user interface that lets users carry out common tasks, such as opening files and printing documents, without being forced to learn new techniques with each application.

You can create common dialog boxes for your own applications by using the common dialog box functions. These functions supply the dialog box procedures and templates for the common dialog boxes; you supply the initial values for the dialog boxes and the addresses of the variables and buffers that receive the input from the dialog boxes.


Common Dialog Box Basics

Common dialog boxes offer varying levels of control to the application. When you use a common dialog box in its simplest form, you fill a structure with initial values, call a function, and retrieve the user's input from the structure after the function returns. But you can also specify options that modify the appearance and behavior of a common dialog; create hook functions that let you monitor and filter messages sent to the dialog box procedure; use registered messages to receive or send information to the dialog box; and modify or replace the template that defines the number, type, and position of controls in the dialog box. The following sections describe the basics you need to work with common dialog boxes at all levels of control.


Dialog Box Types

Although you create all common dialog boxes in essentially the same way (by filling a structure with initial values and calling a dialog box function), you use different functions and structures to create the different common dialog box types. There are these common dialog boxes:

Color	Displays available colors and lets the user select basic colors or create a select custom colors. Use the ChooseColor function and CHOOSECOLOR structure.
Font	Displays lists of facenames, point sizes, and other font attributes that the user can select. Use the ChooseFont function and CHOOSEFONT structure.
Open	Displays the names of files, directories and drives, and lets the user select the combination of names that uniquely identifies the file to be opened. Use the GetOpenFileName function and OPENFILENAME structure.
Save As	Displays the names of files, directories and drives, and lets the user select or enter the combination of names that uniquely identifies the file to be saved. Use the GetSaveFileName function and OPENFILENAME structure.
Print	Displays and lets the user select print job options, such as the range of pages to print and the number of copies. Use the PrintDlg function. and PRINTDLG structure.
Page Setup	Displays and lets the user select page configuration options, such as paper orientation, size, source, and margins. Use the PageSetupDlg function and PAGESETUPDLG structure.
Find	Displays and lets the user select a search string and search options, such as the direction of the search. Use the FindText function and FINDREPLACE structure.
Replace	Displays and lets the user select search and replacement strings and replacement options, such as the direction of the search and the scope of the replacement. Use the ReplaceText function and FINDREPLACE structure.
Although a Print Setup dialog box is also available, it has been superseded by the Page Setup dialog box. Applications written for Win32 API version 4.0 or later should not use the Print Setup dialog box.

All common dialog boxes, except the Find and Replace dialog boxes, are modal. This means the function that you use the create the dialog box does not return until the user has closed the dialog box. The Find and Replace dialog boxes are modeless; the function returns before the dialog box closes. If you use the Find and Replace dialog boxes, you must also use the IsDialogMessage function in the main message loop of your application to ensure that these dialog boxes process dialog box keys, such as TAB and ESC, correctly.


Initialization Flags

You can modify the behavior and appearance of a common dialog box by using initialization flags. These are values that you set in the Flags member of the structure used to create the dialog box. You use the flags to specify which controls in a dialog box receive initial values, to disable selected controls, and to modify the range of values the user can set with the controls. You also use the flags to enable hook functions and custom templates for the dialog boxes.

For example, you set the CF_EFFECTS value in the Flags member of the CHOOSEFONT structure to direct the Font dialog box to display controls that let the user choose the color of the logical font as well as whether to use strike through and underline effects.

The initialization flag values are unique to each common dialog box and are described in detail with the corresponding structures.


Hook Functions and Custom Dialog Box Templates

Windows 95 Overview
For more information, see the Windows NT overview Hook Functions and Custom Dialog Box Templates.

All common dialog box functions use default dialog box procedures to process messages for the dialog box and its controls. You can customize the operation of a common dialog box by providing a hook function that monitors and responds to messages sent to the default dialog box procedure. You enable a hook procedure by setting an ENABLEHOOK value in the Flags member and the address of the hook function in an lpfnHook member of the structure for the dialog box. A hook function has this general form:

UINT APIENTRY MyHook(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (wParam) {
    case WM_*:
        // process the message
        return TRUE;
    default:
        return FALSE;
    }
}

The hook function receives messages and notifications before the dialog box procedure attempts to process them. (The exception is the WM_INITDIALOG message which the hook function receives after the dialog box procedure.) The hook function can process a message or let the dialog box procedure process it. If the hook function processes a message, it must return TRUE; otherwise, it must must return FALSE to direct the dialog procedure to process the message.

If the hook function processes the WM_CTLCOLORDLG message, it must return a valid brush handle for painting the background of the dialog box. In general, if it processes any WM_CTLCOLOR* message, it must return a valid brush handle for painting the background of the given control.

A hook function should never attempt to terminate the dialog box by calling the EndDialog function. Instead, the function must use the PostMessage function to post a WM_COMMAND message with the IDABORT value to the dialog box procedure. Posting IDABORT closes the dialog box and causes the dialog box function to return FALSE. If an application needs a specific error code, it must work out its own comunication mechanism with the hook function.

Although you can subclass controls in any of the common dialog boxes, you must do so from the hook function while processing the WM_INITDIALOG message. Because the common dialog box procedure may also subclass the controls, subclassing after the dialog box procedure ensures that your subclass hook procedure receives the control-specific messages before the subclass hook procedure set by the dialog box procedure.


Registered Messages and Message Strings

Common dialog boxes send registered messages to your window procedure or hook function to notify you of events and to request responses. A registered message is like any other window message except that the message identifier is not predefined. Before you can detect and process a registered message, you must retrieve the message identifier by passing the predefined message string to the RegisterWindowMessage function. There are these predefined message strings:

COLOROKSTRING	Approve or reject a color selection.
FILEOKSTRING	Approve or reject a filename.
FINDMSGSTRING	Find or replace a given string.
HELPMSGSTRING	Display help for a dialog box.
LBSELCHSTRING	Selection in a list box has changed.
SETRGBSTRING	Set the current color selection.
SHAREVISTRING	Opening a file causes a sharing violation.
The Find and Replace dialog boxes send their registered message, FINDMSGSTRING, to the window procedure of the window that owns the dialog box. Other common dialog boxes send their registered messages to hook functions. This means you must enable the hook function for these dialog boxes to receive the messages. One registered message, SETRGBSTRING, is intended to be sent to the common dialog box from the hook function.

In addition to registered messages, some common dialog boxes send and can accept other window messages. For example, the hook function for a Font dialog box can send the WM_CHOOSEFONT_GETLOGFONT message to retrieve the current logical font selections. These other messages and the registered messages are described in more detail in the sections later in this chapter that described the inidividual common dialog boxes.


Custom Templates

All common dialog box functions use default templates to define the number, type and position of controls in the dialog box. You can give users access to additional controls that are unique to your application by defining custom templates. For some dialog boxes, the custom template replaces the default template; for others, the custom template defines a "child" dialog box whose controls are combined with the controls specified by the default template.

Because a primary goal for common dialog boxes is to provide a consistent user interface for all applications, it is important that you customize a common dialog box only when it is absolutely necessary. If you do customize, always try to leave the original controls intact. In particular, avoid hiding a control or changing its function. If you add new controls, place them in empty space already in the dialog box or increase the size of the dialog box to make space.

You enable a custom template by setting a ENABLETEMPLATE or ENABLETEMPLATEHANDLE value in the Flags member in the corresponding structure for the dialog box. If the template is a resource in an application or dynamic link library, you must set the hInstance and lpTemplateName members of the structure. If the template is already in memory, the member you set depends on the given structure. In most cases, you must also enable a hook function for the dialog box to support and process input for the additional controls in your custom template.

When making a custom template, make sure the identifiers for the controls that you add are unique and do not conflict with existing controls. The default templates and identifier values are available in resource script (.DLG) and corresponding header (.H) files. Use these to determine the identifiers for the default controls.


Help Support

All common dialog boxes provide online help by default. The user can display help for individual controls by selecting the control and pressing the F1 key or by clicking the ? button in the title bar and subsequently clicking on a control.

If you customize a dialog box by adding new controls, you also need to extend help support for these controls by processing requests for help in the hook function. The hook function receives WM_HELP or WM_CONTEXTMENU messages when the user requests help by pressing the F1 key, using the ? button, or clicking the right mouse button. You should process these messages for the controls you have added, but let the default dialog box procedure process the messages for the original controls. For more information about how to process these messages, see the chapter describing the WinHelp function.

Although no longer recommended, you can supplement the default help by adding and supporting a Help button in the the dialog box. The Help button is useful for describing the general purpose of the dialog box as it applies to your application. You add a Help button to a dialog box by setting a SHOWHELP value in the Flags member of the structure for the dialog box. You support the Help button by processing the registered message associated with the HELPMSGSTRING message string. The common dialog box sends this message to the window procedure of the owner window whenever the user clicks the Help button.


Color Dialog Box

Windows 95 Overview
For more information, see the Windows NT overview Color Dialog Box.

The Color dialog box lets users select from a set of basic colors or create and select from a set of custom colors. You create and display a Color dialog box by initializing a CHOOSECOLOR structure and passing the structure to the ChooseColor function. The Color dialog box typically looks like this:

If the user chooses a color and clicks the OK button, ChooseColor returns TRUE and sets the rgbResult member of the CHOOSECOLOR structure to the RGB color value corresponding to the color selected by the user. The RGB color value specifies the intensities of the individual red, green, and blue colors that make up the selected color. The individual values range from 0 through 255. Use the RGB macro to create color values, and the GetRValue, GetBValue, and GetGValue macros to extract individual colors from a color value.

If the user cancels the Color dialog box or an error occurs, ChooseColor returns FALSE and the rgbResult member is not defined. You can determine the cause of an error by using the CommDlgExtendedError function to retrieve the extended error value.

The user can select from either the basic colors or custom colors. The basic colors, set by the Color dialog box, represent a reasonable selection of the colors available on the given device. Custom colors are reserved for colors that you choose or that the user creates. You must set the initial values for the 16 custom colors by setting the elements of the array pointed to by the lpCustColors member of the CHOOSECOLOR structure to the desired RGB color values.

You can modify the appearance and behavior of the Color dialog box by setting the Flags member of the CHOOSECOLOR structure to selected values. For example, you can direct the dialog box to display only solid colors by using the CC_SOLIDCOLOR value and you can direct the dialog box to propose an initial color selection (other than black) by setting the rgbResult member to the desired color value and using the CC_RGBINIT value.

The user can create custom colors by clicking the Define Custom Colors button in the dialog box. This displays an extension to the Color dialog box with which the user can pick a color, enter an RGB color value directly, or enter an RGB value indirectly by supplying hue, saturation, and luminousity (HSL) values. You can direct the Color dialog box to always display this extension by setting the Flags member to CC_FULLOPEN. You can prevent this extension from displaying by using the CC_PREVENTFULLOPEN value to disable the Define Custom Colors button. When the user creates a custom color, the dialog box also copies the new RGB color value to the corresponding element in the array pointed to by the lpCustColors member. To preserve new custom colors between calls to ChooseFont, it is recommended that you allocate static memory for the array.

You can enable a hook function for the dialog box by setting the CC_ENABLEHOOK value in the Flags member; the lpfnHook member must specify the address of the hook function. The dialog box sends the registered message defined by the COLOROKSTRING message string to the hook function whenever the user selects a color and click the OK button. The hook function returns a nonzero value to accept this color value; zero to reject it and keep the dialog box open. You can force the dialog box to select a given color by sending the registered message defined by the SETRGBSTRING message string from the hook function to the dialog box.

You can customize the Color dialog box by setting the CC_ENABLETEMPLATE or CC_ENABLETEMPLATEHANDLE value in the Flags member. Because the Color dialog box replaces the default template with the custom template, you should always start with the default template, specified in the COLOR.DLG file, when creating the custom template.


Font Dialog Box

Windows 95 Overview
For more information, see the Windows NT overview Font Dialog Box.

The Font dialog box lets the user choose attributes for a logical font, such as typeface name, style (bold, italic, or regular), point size, effect (underline or strikeout), text color, and script (or character set). You create and display a Font dialog box by initializing a CHOOSEFONT structure and passing the structure to the ChooseFont function. The Font dialog box typically looks like this:

If the user chooses font attributes and clicks the OK button, ChooseFont returns TRUE and sets the members of the LOGFONT structure pointed to by the lpLogFont member of the CHOOSEFONT structure. You can use the LOGFONT structure with the CreateFontIndirect function to create a logical font.

If the user cancels the Font dialog box or an error occurs, ChooseFont returns FALSE and the LOGFONT structure is not defined. You can determine the cause of an error by using the CommDlgExtendedError function to retrieve the extended error value.

When initializing the CHOOSEFONT structure, you must set the Flags member to CF_SCREENFONTS, CF_PRINTERFONTS, or CF_BOTH. To display the options for strikeout, underline, and color, you must use the CF_EFFECTS value.

To list device fonts for a printer, you must obtain a device context (DC) handle for the printer and use this handle in the hDC member of the CHOOSEFONT structure. To restrict the fonts the dialog box displays, you can use the CF_TTONLY, CF_FIXEDPITCHONLY, CF_NOVECTORFONTS, CF_NOVERTFONTS, CF_SCALABLEONLY, and CF_WYSIWYG values. You can also restrict the available styles, point sizes, and effects the dialog box displays for some fonts by using the CF_NOSIMULATIONS value. You can restrict the scripts represented by the displayed fonts by using the CF_SCRIPTSONLY and CF_SELECTSCRIPT values.

You can use the CF_INITTOLOGFONTSTRUCT value in Flags to initialize the controls in the dialog box with the values given in the LOGFONT structure. To initialize the text color, set the rgbColors member of CHOOSEFONT to a RGB color value. You can use the CF_USESTYLE to initialize the style control to the style name given in the buffer pointed to by the lpszStyle member. Use the CF_NOFACESEL, CF_NOSTYLESEL, CF_NOSIZESEL, and CF_NOSCRIPTSEL values to selectively prevent the dialog box from displaying initial values for the corresponding controls. This is useful when working with a selection of text that has more than one typeface, style, point size, or script value. These values will also be set in Flags when ChooseFont returns if the user did not select a corresponding value.

You can force the user to enter only valid typeface names, styles, and point sizes by using the CF_FORCEFONTEXIST value. You can further force the user to enter only point sizes in a given range by using the CF_LIMITSIZE value and setting the minimum and maximum point sizes in the nSizeMin and nSizeMax members.

You can enable the hook function for the Font dialog box by setting the CF_ENABLEHOOK value in Flags and setting the lpfnHook member to the address of the function. The dialog box procedure sends a WM_INITDIALOG message to the hook function with the lParam parameter set to the address of the CHOOSEFONT structure used to initialize the dialog box. The hook function can send the WM_CHOOSEFONT_GETLOGFONT message to the dialog box to retrieve the address of the LOGFONT structure that contains the current selections for the font. This is especially useful when processing processing the WM_COMMAND sent by the Apply button. (You can enable the Apply button by setting the Flags member to CF_APPLY.) The function can send the WM_CHOOSEFONT_SETLOGFONT to force the current selections to given values. The function can also send the WM_CHOOSEFONT_SETFLAGS message to set flags to the given value.

You can customize the Font dialog box by setting the CF_ENABLETEMPLATE or CF_ENABLETEMPLATEHANDLE value in the Flags member. Because the Font dialog box replaces the default template with the custom template, you should always start with the default template, specified in the FONT.DLG file, when creating the custom template.


Open and Save As Dialog Boxes

Windows 95 Overview
For more information, see the Windows NT overview Open and Save As Dialog Boxes.

The Open dialog box and the Save As dialog box let the user choose the location (drive and directory) and the name of a file or a set of files to open and save. The dialog boxes are nearly identical in appearance and behavior and you initialize them using the same OPENFILENAME structure. You create the Open dialog box by using the GetOpenFileName function and the Save As dialog box by using the GetSaveFileName function.

The appearance of the dialog boxes these functions create depend on the version of the Win32 API and whether you set the OFN_EXPLORER value in the Flags member of the OPENFILENAME structure. When running under version 4.0 or with OFN_EXPLORER, the dialog boxes provide user-interface features that are similar to the Windows Explorer. The Open dialog box looks like this:

The Save As dialog box looks like this:

Although the default title for a dialog box is either Open or Save As, you can change the title by setting the lpstrTitle member to the address of a new title. Also, you can hide the Open as read only option by using the OFN_HIDEREADONLY value. If this option is not hidden, the dialog box sets Flags to OFN_READONLY on return if the user checks this option.


Filenames and Directories

To retrieve a filename from the dialog box, you must set the lpstrFile member of the OPENFILENAME structure to the address of the buffer to receive the filename and set the nMaxFile member to the size of that buffer. Buffer sizes must be in bytes for the ANSI version of the structure and characters for the Unicode version. If the user chooses a filename and clicks the OK button, the dialog box copies the selected drive, directory, and filename to the given buffer. The function also sets the nFileOffset and nFileExtension members to the offsets, in bytes or characters, from the start of the buffer to the filename and to the filename extension, respectively. You can retrieve just the filename from the buffer pointed to by lpstrFile by using the GetFileTitle function. Alternately you can have the dialog box copy the filename to a buffer by setting the lpstrFileTitle member to the address of the buffer and the nMaxFileTitle member to size of the buffer.

If the user cancels the dialog box or an error occurs, the function returns FALSE. You can determine the cause of an error by using the CommDlgExtendedError function to retrieve the extended error value. If the buffer is too small to receive the full name, the CommDlgExtendedError function returns FNERR_BUFFERTOOSMALL and the first 2 bytes of the buffer pointed to by the lpstrFile member are set to an integer value specifying the size required to receive the full name.

The dialog box uses the current directory as the initial directory from which to display files and directories. You can set your own initial directory by setting the lpstrInitialDir member to the address of a string that specifies a directory. To prevent the dialog box from changing the current directory for the application, you can set the Flags member to OFN_NOCHANGEDIR. The user can still change directories to find a file, but the dialog box returns to the original directory when it closes.

You can direct the dialog box to add a default filename extension, if the user does not, by setting the lpstrDefExt member to the address of a string specifying an extension. Otherwise, the dialog box leaves filenames without extensions. If the user explicitly enters an extension or selects a file that already has an extension, the dialog box sets the Flags member to OFN_EXTENSIONDIFFERENT if that extension is different than that given by lpstrDefExt.

You can let the user select more than one file from a directory by using the OFN_ALLOWMULTISELECT value. If this case, the dialog box copies two or more consecutive, null-terminated strings to the buffer pointed to by lpstrFile. The first string specifies the selected drive and directory; all subsequent strings specify the names of files. The last string ends with an extra null character. The nFileExtension member is not used, and the nFileOffset member is the offset to the first filename.


Filters

You can restrict the number of files displayed by the dialog box by setting the lpstrFilter member to the address of a buffer that contains one or more filters. A filter consists of two null-terminated strings, a description and a pattern, one concatenated to the other. The dialog box displays the description to let the user pick which filter to use; it uses the pattern to pick out which files to display. The pattern can be a combination of valid filename characters and the asterisk (*). The asterisk is a wildcard that represents any combination of valid filename characters. The dialog box displays only those files that match the pattern. For example, if the pattern is "*.TXT", the dialog box displays only the files having the filename extension TXT. You can have multiple patterns for a given description, but must separate each pattern from the preceding with a semicolon (;).

You can supply multiple filters by concatenating them in the buffer. You must terminate the last filter with an extra null character. You can specify which filter the dialog box should initially use by setting the nFilterIndex member to the index of the filter. The first filter in the buffer has index 1, the second 2, and so on. If the user changes the filter while using the dialog box, the nFilterIndex member is set to the index of the selected filter on return.

You can create a custom filter by setting the lpstrCustomFilter	 member to the address of a buffer that contains a single filter and setting the nMaxCustFilter member to the size of the buffer, in characters or bytes. The dialog box always places the custom filter at the beginning of the list of filters and, on return, always updates the pattern part of the filter with the pattern from the filter selected by the user.


File and Directory Validation

The dialog box automatically checks filenames entered by the user to make sure the names contain valid characters. You can also direct the dialog to verify that the given file or drive and directory exist by using the OFN_FILEMUSTEXIST or OFN_PATHMUSTEXIST value, respectively. You can override the filename character validation by using the OFN_NOVALIDATE value.

The dialog box returns an error if opening the selected file would cause a sharing violation. You can direct the dialog box to send notification messages about sharing violations by using the OFN_SHAREAWARE value.

When using the Save As dialog box, you can direct the dialog box to prompt the user for permission to create a new file or overwrite an existing file by using the OFN_CREATEPROMPT and OFN_OVERWRITEPROMPT values. By default, the dialog box tests whether a new file can be created in the selected directory by creating a zero-length test file. You can prevent the creation of this test file by using the OFN_NOTESTFILECREATE value.

You can prevent the dialog box from return names of existing files that have the read-only attribute by using the OFN_NOREADONLYRETURN value. You can also prevent the dialog box from dereferencing link files by using the OFN_NODEREFERENCELINKS value. In this case, the dialog box returns the name of the link file rather than the name of the file referenced by the link file.


Hook Function

Windows 95 Overview
For more information, see the Windows NT overview The Hook Function.

You can enable a hook function for the dialog box by using the OFN_ENABLEHOOK value and setting the lpfnHook member to the address of the function. The hook function lets you monitor messages sent from the dialog box procedure. It also lets you support any controls you may add to the dialog box as described in the next section. When enabling the hook function, you should also set the OFN_EXPLORER value in the Flags member to make sure the dialog box displays the Windows Explorer-style user interface. This section only describes the hook function for dialog boxes created using OFN_EXPLORER.

The hook function receives a variety of messages while the dialog box is created and eventually destroyed. For example, the hook function receives a WM_INITDIALOG message with the lParam parameter set to the address of the OPENFILENAME structure used to initialize the dialog box. Most messages, however, are WM_NOTIFY notification messages indicating actions taken by the user in the dialog box. The lParam parameter for each WM_NOTIFY message is the address of a OFNOTIFY structure that defines the action. The code member in the header for the OFNOTIFY structure contains one of these notification values:

CDN_FILEOK	The user click the Open or Save button; the dialog box is about to close.
CDN_FOLDERCHANGE	A new folder has been opened in the Open or Save As dialog box.
CDN_HELP	The user clicked the Help button.
CDN_INITDONE	The system has finished initializing the dialog box, and the dialog box has finished processing the WM_INITDIALOG message. Also, the system has finished arranging controls in the common dialog box to make room for the controls of the child dialog box (if any).
CDN_SELCHANGE	The user has selected a new file or folder from the file list.
CDN_SHAREVIOLATION	The common dialog box encountered a sharing violation on the file about to be returned.
CDN_TYPECHANGE	The user selected a new file type from the "Files of type" combo box.
These messages are useful for modifying the behavior of the dialog box. For example, the hook function receives the CDN_FILEOK message when to user chooses a filename and clicks the OK button. The hook function can accept or reject the selected name by returning 0 or 1, respectively. Rejecting the filename forces the dialog box to remain open. To return a value from the hook function, you must set the message result value by using the SetWindowLong function and the DWL_MSGRESULT value.

Although the WM_NOTIFY messages supersede the registered messages previously used with the Open and Save As dialog boxes (such as the FILEOKSTRING, LBSELCHSTRING, SHAREVISTRING, and HELPMSGSTRING messages), the hook function also receives the superseded message after the WM_NOTIFY message if it does not use SetWindowLong to set the message result value or sets this value to zero.

You can send messages to the dialog box from the hook function to retrieve information about the status of the dialog box. The messages include:

CDM_GETFILEPATH	Retrieves the path and filename of the selected file.
CDM_GETFOLDERIDLIST	Retrieves the address of the item identifier list corresponding to the folder that the dialog box currently has open.
CDM_GETFOLDERPATH	Retrieves the path and name of the currently open folder or directory for the dialog box.
CDM_GETSPEC	Retrieves the filename (not including the path) of the currently selected file in the dialog box.
CDM_HIDECONTROL	Hides the given control.
CDM_SETCONTROLTEXT	Sets the text in the given control.
CDM_SETDEFEXT	Sets the default filename extension for the dialog box.


Customizing Dialog Boxes

You can customize the Open or Save As dialog box by using the OFN_ENABLETEMPLATE or OFN_ENABLETEMPLATEHANDLE value and setting the hInstance and lpTemplateName members to values that specify a custom dialog box template. Customizing a dialog box lets you add controls to the default Open or Save As dialog box, giving users options that are specific to your application. When customizing a dialog box, you must use the OFN_EXPLORER value to make sure the controls in your custom dialog box are added to (rather than replace) the controls in the default dialog box. This section only describes customizing dialog boxes that you have created using OFN_EXPLORER.

If you use the OFN_ENABLETEMPLATE value, the lpTemplateName member must point to the name or resource identifier of a dialog template resource in the module identified by hInstance. If you use the OFN_ENABLETEMPLATEHANDLE value, hInstance must be the handle of a block of memory containing the the dialog template. In both cases, you must also enable a hook function by using the OFN_ENABLEHOOK value. This hook function serves as the dialog box procedure for the custom dialog box as well as monitors notification messages sent from the default dialog box.

You can create your custom dialog box template as you do any other template, except that you must specify the WS_CHILD and WS_CLIPSIBLINGS styles and should specify the DS_3DLOOK and DS_CONTROL styles. The system requires that the custom dialog box be created as a child of the default Open or Save As dialog box. The WS_CLIPSIBLINGS style ensures that the custom dialog box does not paint over any of the controls in the default dialog box. The DS_3DLOOK style makes sure that the controls in the custom dialog box are consistent with the controls in the default dialog box. The DS_CONTROL style makes sure that the user can use the TAB and other navigation keys to move between all controls, default or custom, in the customized dialog box.

To make room for the new controls, the system expands the default dialog box by the width and height of the custom dialog box. By default, all controls from the custom dialog box are positioned below the controls in the default dialog box. However, you can override this default positioning by including a static text control in your custom dialog box template and assigning it the control identifier value of stc32. (This value is defined in the DLG.H header file.) In this case, the system uses the control as the point of reference for determining where to position the new controls. All new controls above and to the left of the stc32 control are positioned the same amount above and to the left of the controls in the default dialog box. New controls below and to the right of the stc32 control are positioned below and to the right of the default controls. In general, each new control is positioned such that it has the same position relative to the default controls as it had to the stc32 control. To make room for these new controls, the system adds space to the left, right, bottom, and top of the default dialog box as needed.

The system requires the hook function to process all messages intended for the custom dialog box and therefore sends the same window messages to the hook function as to any other dialog box procedure. For example, the hook function receives WM_COMMAND messages when the user clicks on button controls in the custom dialog box. The hook function is responsible for initializing these controls and retrieve values from the controls when the dialog box is closed. Note that when the hook function receives the WM_INITDIALOG message, the system has not yet moved the controls to their final positions.

The default dialog box procedure handles messages for all the controls in the default dialog box, but the hook function receives the WM_NOTIFY notification messages for user actions on these controls as described in the previous section.


Print Dialog Box

Windows 95 Overview
For more information, see the Windows NT overview Print Dialog Box.

The Print dialog box lets the user select options for a particular print job, such as such as the printer to use, the range of pages to print, and the number of copies. You create and display a Print dialog box by initializing a PRINTDLG structure and passing the structure to the PrintDlg function. The Print dialog box typically looks like this:

If the user chooses options and clicks the OK button, PrintDlg returns TRUE and sets the hDevMode and hDevNames members to global memory handles for the DEVMODE and DEVNAMES structures that specify the user's selections. You can use the information in these structures to create a device or information context for the selected printer. If the user cancels the Print dialog box or an error occurs, PrintDlg returns FALSE. You can determine the cause of an error by using the CommDlgExtendedError function to retrieve the extended error value.

When the PrintDlg function returns, you can determine which options the user selected by checking the Flags member. The PD_ALLPAGES, PD_SELECTION, or PD_PAGENUMS value is set to indicate whether the user wants to print all pages, selected pages, or pages in a range of page numbers. If PD_PAGENUMS is set, the nFromPage and nToPage members specify the page range. The PD_COLLATE value indicates that the user wants the pages to be collated when printed. The PD_PRINTTOFILE value indicates that the user selected the Print To File option. You can also set these values in the Flags member before calling PrintDlg to initially set the corresponding option. Use the PD_NOPAGENUMS and PD_NOSELECTION values to disable the corresponding options.

By default, the Print dialog box initially displays information about the current default printer. You can direct it to display information for another installed printer by initializing a DEVMODE or DEVNAMES structure and assigning the global memory handle for the structure to the hDevMode or hDevNames member. The device name you specify in the dmDeviceName member of the DEVMODE structure or in the wDriverOffset member of the DEVNAMES structure must identify a printer device that is also listed in the [Devices] section of the WIN.INI file. Otherwise, PrintDlg returns an error.

When the PrintDlg function successfully returns, the application must render the number of copies in nCopies, printing them collated or not collated depending on whether the PD_COLLATE flag is set. If the application does not support multiple copies or simulated collation, it should specify PD_USEDEVMODECOPIESANDCOLLATE to allow these options only if the printer driver supports them.

You can direct PrintDlg to automatically create a device or information context for the printer by using the PD_RETURNDC or PD_RETURNIC value. The function returns the handle of the context in the hDC member. If you use the PD_RETURNDC value, you can use the device context to generate output for the printer. If the user also selects the Print To File option, however, you should retrieve the address of the filename at the offset indicated by the wOutputOffset member of the DEVNAMES structure. You should specify the address of the filename in the lpszOutput member of the DOCINFO structure. The print subsystem will query the user for the filename. If you do not want the user to select Print To File option, set the Flags member to PD_HIDEPRINTTOFILE to hide the option or PD_DISABLEPRINTTOFILE to disable it.

You can retrieve information about the default printer without displaying the Print dialog box by using the PD_RETURNDEFAULT value. In this case, PrintDlg returns immediately after setting the hDevMode and hDevNames members to handles for structures containing the information.

You can prevent PrintDlg from displaying warnings on errors by using the PD_NOWARNING value. Otherwise, the function displays message boxes on errors such as no printers installed.

You can enable a hook function by using the PD_ENABLEPRINTHOOK value and setting the lpfnPrintHook member to the address of your hook function. You can customize the Print dialog box by using the PD_ENABLEPRINTTEMPLATE or PD_ENABLEPRINTTEMPLATEHANDLE value and specifying a custom dialog box template. PrintDlg uses the custom dialog box to replace the default dialog box. If you use PD_ENABLEPRINTTEMPLATE, you set the hInstance and lpPrintTemplateName members to specify the name and module instance for a dialog box template. If PD_ENABLEPRINTTEMPLATEHANDLE, set hPrintTemplate to the handle of a dialog box template in memory.

Although you can also create and display a Printer Setup dialog box using the PrintDlg function and the PD_PRINTSETUP value, the Printer Setup dialog box has been superseded by the Page Setup dialog box and should not be used. The PD_ENABLESETUPHOOK, PD_ENABLESETUPTEMPLATE, and PD_ENABLESETUPTEMPLATEHANDLE values apply only to the Page Setup dialog box.


Page Setup Dialog Box

Windows 95 Overview
For more information, see the Windows NT overview Page Setup Dialog Box.

The Page Setup dialog box lets the user to set the attributes of the printed page, such as the paper type (envelope, legal, letter, and so on), the paper source (manual feed, tractor feed, sheet feeder, and so on), the page orientation (portrait or landscape), and the width of the page margins. You create and display a Page Setup dialog box by initializing a PAGESETUPDLG structure and passing the structure to the PageSetupDlg function. The Page Setup dialog box typically looks like this:

If the user chooses options and clicks the OK button, PageSetupDlg returns TRUE after setting various members in the PAGESETUPDLG structure to specify the user's selections. You can use this information to prepare the output to be sent to the selected printer. If the user cancels the Page Setup dialog box or an error occurs, the function returns FALSE. You can determine the cause of an error by using the CommDlgExtendedError function to retrieve the extended error value.

When PageSetupDlg returns, the ptPaperSize and rtMargin members contain the values selected by the user. The hDevMode and hDevNames members contain to global memory handles for the DEVMODE and DEVNAMES structures that contain additional page information as well as information about the printer.

By default, the Page Setup dialog box displays information about the current default printer. You can direct the dialog box to display information about a specific printer by setting the members of a DEVMODE or DEVNAMES structure and assigning the global memory handles of the structures to the corresponding member in PAGESETUPDLG . If you specify the name of a printer that is not currently installed, the dialog box displays an error message. You can prevent the dialog box from displaying error messages by using the PSD_NOWARNING value. You can use the PSD_RETURNDEFAULT value to retrieve information about the default printer without displaying the Page Setup dialog box.

By default, measurements returned by the dialog box are in thousandths of inches if inches are the default measurement, or hundredths of millimeters if metric is the default measurement system. You can set the units of measurement for the margin widths in the dialog box by using the PSD_INHUNDREDTHSOFMILLIMETERS and PSD_INTHOUSANDTHSOFINCHES value. You can set the initial values for the margins by using the PSD_MARGINS value and the rtMargin member. The default initial values are one inch. You can set the minimum values that the user can enter for the margins by using the PSD_MINMARGINS values and the rtMinMargin member. The default minimum values are the minimum margins allowed by the printer.

You can prevent users from selecting given options by using the PSD_DISABLEMARGINS, PSD_DISABLEORIENTATION, PSD_DISABLEPAPER, and PSD_DISABLEPRINTER values to disable the corresponding controls.

You can enable a hook function for the dialog box by using the PSD_ENABLEPAGESETUPHOOK value and setting the lpfnPageSetupHook member to the address of your hook function. You can customize the Page Setup dialog box by using the PSD_ENABLEPAGESETUPTEMPLATE or PSD_ENABLEPAGESETUPTEMPLATEHANDLE value and specifying a custom dialog box template. PageSetupDlg uses the custom dialog box to replace the default dialog box. If you use PD_ENABLEPAGESETUPTEMPLATE, you set the hInstance and lpPageSetupTemplateName members to specify the name and module instance for a dialog box template. If PD_ENABLEPAGESETUPTEMPLATEHANDLE, set hPageSetupTemplate to the handle of a dialog box template in memory.

The Page Setup dialog box includes an image of a sample page that shows how the user's selections affect the appearance of the printed output. The image consists of a rectangle that represents the selected paper or envelope type, with a dotted-line rectangle representing the current margins and partial (greek-text) characters to show how text looks on the printed page. You can customize the appearance of the sample page by using the PSD_ENABLEPAGEPAINTHOOK value and setting the lpfnPagePaintHook member to the address of a hook function. The dialog box sends the following paint messages to the hook function whenever it needs a portion of the sample page redrawn:

WM_PSD_PAGESETUPDLG	Notifies the hook function to carry out initialization tasks.
WM_PSD_FULLPAGERECT	Specifies the bounding rectangle of the sample page.
WM_PSD_MINMARGINRECT	Specifies the minimum margin rectangle.
WM_PSD_MARGINRECT	Specifies the margin rectangle.
WM_PSD_GREEKTEXTRECT	Specifies the greek-text rectangle.
WM_PSD_ENVSTAMPRECT	Specifies the envelope-stamp rectangle (envelopes only).
WM_PSD_YAFULLPAGERECT	Specifies the bounding rectangle of the sample page.
The hook function receives these messages in the order in which they are listed. If the hook function processes a given message, it should draw the particular area within the sample page and return TRUE. Otherwise, it should return FALSE.

You can disable the display of the sample page by using the PSD_DISABLEPAGEPAINTING in the Flags member. Disabling the sample page prevents the WM_PSD_* message from being sent to your hook function. It also prevents the default dialog box procedure from painting the same page.


Find and Replace Dialog Boxes

Windows 95 Overview
For more information, see the Windows NT overview Find and Replace Dialog Boxes.

The Find dialog box and the Replace dialog box let users enter information that you can use to search for and possibly replace text in a document. The Find dialog box lets users enter a string to search for and specify search options. The Replace dialog box lets users enter both a search and replace string and specify search-and-replace options. You create and display a Find dialog box by initializing a FINDREPLACE structure and passing the structure to the FindText function. The Find dialog box typically looks like this:

You create and display a Replace dialog box by initializing a FINDREPLACE structure and passing the structure to the ReplaceText function. The Replace dialog box typically looks like this:

Unlike other common dialog boxes, the Find and the Replace dialog boxes are modeless. This means the user can switch between the dialog box and the window that created that dialog box. This is useful for letting the user search for a string, switch to the application window to work on the string, and switch back to the dialog box to search for another string without repeating the command needed to open the dialog box.

If the FindText or ReplaceText function successfully creates the dialog box, it returns the handle of the dialog box. You can use this handle to move and communicate with the dialog box. If the function cannot create the dialog box, it returns NULL. You can determine the cause of an error by using the CommDlgExtendedError function to retrieve the extended error value.

When the user clicks the Find Next, Replace, or Replace All button in a dialog box, the dialog box procedure sends a registered message to the window procedure of the owner window. To receive and process these messages, you must set the hwndOwner member of the FINDREPLACE structure to the handle of the window to receive the messages and you must register the FINDMSGSTRING message string to retrieve the value of the registered message.

Each registered message contains the address of the FINDREPLACE structure. Before sending the message, the dialog box sets the members of this structure with the latest user selections, including the string to search for, the replacement string (if any) and the search-and-replace options. You must check the Flags member to determine the action to carry out and the options selected.

You can determine whether the search for a string, replace a string, or replace all occurrences of a string by checking the Flags member for the the FR_FINDNEXT, FR_REPLACE, and FR_REPLACEALL value, respectively. When the user eventually closes the dialog box, the dialog box sets the FR_DIALOGTERM value in the Flags member of the FINDREPLACE structure in the last registered message sent to the owner window. After the owner window processes this message, the handle of the dialog box is no longer valid.

You can determine the search options by checking for the FR_DOWN, FR_MATCHCASE, and FR_WHOLEWORD values. If a value is not present, the opposite action is implied. For example, if FR_DOWN is present, the search should be carried out from the current location to the end of the document; but if not present, the search should be to the beginning of the document. You can disable the search options by using the FR_NOUPDOWN, FR_NOMATCHCASE, and FR_NOWHOLEWORD values. You can remove the options from the dialog box by using the FR_HIDEUPDOWN, FR_HIDEMATCHCASE, and FR_HIDEWHOLEWORD values.

You can enable a hook function for a Find dialog box or Replace dialog box by using the FR_ENABLEHOOK value and setting the lpfnHook member to the address of the hook function. If the hook function returns FALSE in response to the WM_INITDIALOG message, the function is responsible for calling the ShowWindow and UpdateWindow functions to display the dialog box any painting operations are complete. You can customize the dialog box by using the FR_ENABLETEMPLATE or FR_ENABLETEMPLATEHANDLE value. The custom dialog box replaces the default dialog box.


Using Common Dialog Boxes

Windows 95 Overview
For more information, see the Windows NT overview Using Common Dialog Boxes.

•	Choosing a color.

•	Choosing a font.

•	Opening a file.

•	Displaying the Print dialog box.

•	Setting up the printed page.

•	Finding text.


Choosing a Color

You can let the user choose a color, such as for a new solid brush, by displaying the Color dialog box. To display the dialog box, you initialize the lStructSize, hwndOwner, lpCustColors and Flags members in a CHOOSECOLOR structure and call the ChooseColor function as in the following example:

CHOOSECOLOR cc;          // common dialog box structure
COLORREF acrCustClr[16]; // array of custom colors
HWND hwnd;               // owner window
HBRUSH hbrush;           // brush handle

// Initialize CHOOSECOLOR

cc.lStructSize = sizeof(CHOOSECOLOR);
cc.hwndOwner = hwnd;
cc.lpCustColors = (LPDWORD) acrCustClr;
cc.Flags = CC_FULLOPEN;

if (ChooseColor(&cc)==TRUE)
    hbrush = CreateSolidBrush(cc.rgbResult);

In this example, the CC_FULLOPEN value in the Flags member directs the dialog box to display the Add Custom Colors extension to the dialog box with which the user can create new custom colors. Custom colors are copied back into the array pointed to by lpCustColors.

The ChooseColor function returns TRUE if the user selected a color. The RGB value of the selected is in the rgbResult member of the structure.


Choosing a Font

You can let the user choose the attributes of font, such as when creating a new logical font, by displaying the Font dialog box. To display the dialog box, you must initialize the members in a CHOOSEFONT structure and call the ChooseFont function as in the following example:

CHOOSEFONT cf;     // common dialog box structure
LOGFONT lf;        // logical font structure
HWND hwnd;         // owner window
HFONT hfont;       // new logical font handle

// Initialize CHOOSEFONT
cf.lStructSize = sizeof (CHOOSEFONT);
cf.hwndOwner = hwnd;
cf.lpLogFont = &lf;
cf.Flags = CF_SCREENFONTS | CF_EFFECTS;

if (ChooseFont(&cf)==TRUE)
    hfont = CreateFontIndirect(cf.lpLogFont);

In this example, the CF_SCREENFONTS defines the type of font to display information for and CF_EFFECTS causes the dialog box to display options to let the user select strikethrough, underlining, and color for the font. The function copies the font attributes to the lf variable, a LOGFONT structure.


Opening a File

You can let the user select the name of a file to open by displaying an Open dialog box. You initialize the lStructSize, hwndOwner, lpstrFile, and nMaxFile members of an OPENFILENAME structure and call the GetOpenFileName function as in the following example:

OPENFILENAME ofn;       // common dialog box structure
char szFile[260];       // buffer for filename
HWND hwnd;              // owner window
HANDLE hf;              // file handle

// Initialize OPENFILENAME
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = hwnd;
ofn.lpstrFile = szFile;
ofn.nMaxFile = sizeof(szFile);
ofn.lpstrFilter = "All\0*.*\0Text\0*.TXT\0";
ofn.nFilterIndex = 1;
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = NULL;
ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;

// Display the Open dialog box.

if (GetOpenFileName(&ofn)==TRUE)
    hf = CreateFile(ofn.lpstrFile, GENERIC_READ,
        0, (LPSECURITY_ATTRIBUTES) NULL,
        OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
        (HANDLE) NULL);

In this example, the lpstrFilter member receives the address of a filter that contains two patterns that the user can choose to view all files or just text files. The nFilterIndex member specifies that the first pattern is used when the dialog box is created. The OFN_EXPLORER value ensures that the Open dialog box displays a user-interface that is similar to the Windows Explorer. The OFN_PATHMUSTEXIST and OFN_FILEMUSTEXIST values direct the function to verify the the path and filename that the user enters exists before returning.


Displaying the Print Dialog Box

You can let the user choose options for printing a document by displaying a Print dialog box. To display the dialog box for the default printer, you initialize a PRINTDLG structure and call the PrintDlg function as in the following example:

PRINTDLG pd;
HWND hwnd;

pd.lStructSize = sizeof(PRINTDLG);
pd.hwndOwner   = hwnd;
pd.hDevMode    = NULL;      // don't forget to free or store hDevMode
pd.hDevNames   = NULL;     // don't forget to free or store hDevNames
pd.Flags       = PD_USEDEVMODECOPIESANDCOLLATE|PD_RETURNDC;
pd.nCopies   = 1;

if (PrintDlg(&pd)==TRUE) {

    // GDI calls to render output

    // Delete DC when done
    DeleteDC(pd.hDC);
}

In this example, the PD_RETURNDC value directs PrintDlg to return a device context handle for the selected printer. This handle is used to render output on the printer.


Setting Up the Printed Page

You can let the user select the attributes of the printed page, such as the paper type, paper source, page orientation, and page margins by displaying a Page Setup dialog box. To display the dialog box, you initialize a PAGESETUPDLG structure and call the PageSetupDlg function as in the following example:

PAGESETUPDLG psd;    // common dialog box structure
HWND hwnd;           // owner window

psd.lStructSize = sizeof(PAGESETUPDLG);
psd.hwndOwner   = hwnd;
psd.hDevMode    = NULL;    // don't  forget to free or store hDevMode
psd.hDevNames   = NULL;  // don't forget to free or store hDevNames
psd.Flags       = PSD_INTHOUSANDTHSOFINCHES | PSD_MARGINS;
psd.rtMargin.top = 1000;
psd.rtMargin.left = 1250;
psd.rtMargin.right = 1250;
psd.rtMargin.bottom = 1000;

if (PageSetupDlg(&psd)==TRUE) {
    // check paper size and margin values here
}

In this example, the PSD_MARGINS value directs the function to set the initial margin values as specified in the rtMargin member. In this case, the initial and returned margin values are expressed in thousandths of an inch. The initial paper size is the paper size specified in the device mode identified by the hDevMode member of the PAGESETUPDLG structure, or by the default printer's device mode if no printer was specified.

One of the ways an application can customize the Page Setup dialog box is to use a hook function to paint the sample page of the dialog box. You set the hook function by using the PSD_ENABLEPAGEPAINTHOOK value when creating the dialog box. The following example shows a sample hook function that draws the margin rectangle in the sample page area:

BOOL CALLBACK PaintHook(HWND hwndDlg, UINT uMsg, WPARAM wParam,

    LPARAM lParam)

{

    LPRECT lprc;

    COLORREF crMargRect;

    HDC hdc, hdcOld;

    switch (uMsg) {

        // Drawing the margin rectangle.

        case WM_PSD_MARGINRECT:

            hdc = (HDC) wParam;

            lprc = (LPRECT) lParam;

            // Get the system highlight color.

            crMargRect = GetSysColor(COLOR_HIGHLIGHT);

            // Create a dash-dot pen of the system highlight color and

            // select it into the DC of the sample page.

            hdcOld = SelectObject(hdc, CreatePen(PS_DASHDOT, .5,

                crMargRect));

            // Draw the margin rectangle.

            Rectangle(hdc, lprc->left, lprc->top, lprc->right,

                lprc->bottom);

            // Restore the previous pen to the DC.

            SelectObject(hdc, hdcOld);

            return TRUE;

        default:

            return FALSE;

    }

    return TRUE;

}


Finding Text

You can let the user enter a string and search options for a search by displaying a Find dialog box and monitoring messages sent by the dialog box. To display and manage the Find dialog box, you need to carry out three steps: register the FINDMSGSTRING message string, call the FindText function to create and display the dialog box, and check for the registered messages in the window procedure of the window that owns the dialog box.

To register the message string, you make the following call when initializing your application:

UINT uFindReplaceMsg;  // message id for FINDMSGSTRING

uFindReplaceMsg = RegisterWindowMessage();

To make sure the Find dialog box operates properly when eventually displayed, you must include a call to the IsDialogMessage function in your main message loop.

To display the Find dialog box, you initialize the FINDREPLACE structure and call the FindText function as in the following example:

FINDREPLACE fr;       // common dialog box structure
HWND hwnd;            // owner window
CHAR szFindWhat[80];  // buffer receiving string
HWND hdlg = NULL;     // handle of Find dialog box

fr.lStructSize = sizeof(FINDREPLACE);
fr.hwndOwner = hwnd;
fr.lpstrFindWhat = szFindWhat;
fr.wFindWhatLen = 80;
fr.Flags = 0;

hdlg = FindText(&fr);

Note that the FINDREPLACE structure and the buffer for the search string should be a global or static variable. You must set the hwndOwner member to specify the window that receives the registered messages. Once the dialog box is created, you can move or manipulate it by using the returned handle.

To monitor messages sent from the dialog box, you check for the registered message and process the values passed in the FINDREPLACE structure as in the following example:

LPFINDREPLACE lpfr;

if (msg == uFindReplaceMsg) {
    lpfr = (LPFINDREPLACE)lParam;
    if (lpfr->Flags & FR_FINDNEXT) {
        // search for string specified by lpfr->lpstrFindWhat
    } else if (lpfr->FR_DIALOGTERM) {
        // user has closed the dialog box
        hdlg = NULL;
    }
}

To fully process the message, you must check the Flags member for search options, indicated by values such as FR_DOWN, FR_WHOLEWORD, and FR_MATCHCASE.


Common Dialog Box Reference

The following functions, structures, and messages are associated with common dialog boxes in Windows 95.


Common Dialog Box Functions

Following are the functions used with common dialog boxes.

ChooseColor
ChooseFont
CommDlgExtendedError
FindText
GetFileTitle
GetOpenFileName
GetSaveFileName
PageSetupDlg
PrintDlg
ReplaceText


Common Dialog Box Structures

Following are the structures used with common dialog boxes.

OFNOTIFY
PAGESETUPDLG


Common Dialog Box Messages

Following are the messages used with common dialog boxes.

CDM_GETFILEPATH
CDM_GETFOLDERIDLIST
CDM_GETFOLDERPATH
CDM_GETSPEC
CDM_HIDECONTROL
CDM_SETCONTROLTEXT
CDM_SETDEFEXT
CDN_FILEOK
CDN_FOLDERCHANGE
CDN_HELP
CDN_INITDONE
CDN_SELCHANGE
CDN_SHAREVIOLATION
CDN_TYPECHANGE
COLOROKSTRING
FILEOKSTRING
FINDMSGSTRING
LBSELCHSTRING
SETRGBSTRING
SHAREVISTRING
WM_CHOOSEFONT_SETFLAGS
WM_CHOOSEFONT_SETLOGFONT
WM_PSD_ENVSTAMPRECT
WM_PSD_FULLPAGERECT
WM_PSD_GREEKTEXTRECT
WM_PSD_MARGINRECT
WM_PSD_MINMARGINRECT
WM_PSD_PAGESETUPDLG
WM_PSD_YAFULLPAGERECT


Common Dialog Box Library (Windows NT)

The following Windows NT overview discusses the Common Dialog Box Library. Various common dialog boxes are described, and examples are included to help you use common dialog boxes in your Win32-based applications.


About Common Dialog Boxes

Windows NT Overview
For more information, see the Windows 95 overview About Common Dialog Boxes.

Common dialog boxes make it easier to develop applications based on the Microsoft® Win32® application programming interface (API). A common dialog box is a dialog box that an application displays by calling a single function rather than by supplying a dialog box procedure and a resource file containing a dialog box template. The dynamic-link library COMDLG32.DLL provides a default procedure and a default template for each type of common dialog box. Each default dialog box procedure processes messages and notifications for a common dialog box and its controls. The default dialog box template defines the appearance of a common dialog box and its controls.

In addition to simplifying the development of Win32-based applications, common dialog boxes are helpful to users because they provide a standard set of controls for performing certain operations. Once Windows developers begin using common dialog boxes extensively in their applications, users will find that they can easily perform the same operations in all applications after mastering one.

This chapter describes the various common dialog boxes and includes examples to help you use common dialog boxes in your Win32-based applications.

Following are the types of common dialog boxes in the order in which they are presented in this chapter.

Name	Description
Color	Displays available colors as well as controls that allow the user to define custom colors.
Font	Displays lists of fonts and point sizes that correspond to available fonts. After the user selects a font, the dialog box displays sample text rendered with that font.
Open	Displays a list of filenames matching any specified extensions, directories, and drives. By selecting one of the listed filenames, the user indicates the file an application should open.
Save As	Displays a list of filenames matching any specified extensions, directories, and drives. By selecting one of the listed filenames, the user indicates the file an application should save.
Print	Displays information about the installed printer and its configuration. By altering and selecting controls in this dialog box, the user specifies how output should be printed and starts the printing process.
Page Setup	Displays the current page configuration and provides options for setting the paper orientation, size, source, and margins (when the printer driver supports these options).
Print Setup	This common dialog box has been superseded by the Page Setup dialog box. Win-32 applications should not use the Print Setup dialog box.
Find	Displays an edit control in which the user can type a string for an application to search. The user can specify which direction to search and can indicate whether the application should match the case of the specified string, and whether the string to match is an entire word.
Replace	Displays two edit controls in which the user can type strings. The first string identifies a word or value that the application should replace, and the second string identifies the replacement word or value.


Color Dialog Box

Windows NT Overview
For more information, see the Windows 95 overview Color Dialog Box.

The Color dialog box contains controls that enable a user to select and create colors.

Following is a Color dialog box.

The Basic Colors control displays up to 48 colors. The actual number of colors displayed is determined by the display driver. For example, a VGA driver displays 48 colors, and a monochrome display driver displays only 16. By using the Basic Colors control, the user can select a displayed color.

To display the Custom Colors control, the user clicks the Define Custom Colors button. The Custom Colors control displays custom colors. The user can select one of the 16 rectangles in this control and then create a new color by using one of the following methods:

•	Specifying red, green, and blue (RGB) values by using the Red, Green, and Blue edit controls, and then choosing the Add to Custom Colors button to display the new color in the selected rectangle.

•	Moving the cursor in the color spectrum control (the box at the upper right of the dialog box) to select hue and saturation values, moving the cursor in the luminosity control (the rectangle to the right of the spectrum control), and then choosing the Add to Custom Colors button to display the new color in the selected rectangle.

•	Specifying hue, saturation, and luminosity (HSL) values by using the Hue, Sat, and Lum edit controls, and then choosing the Add to Custom Colors button to display the new color in the selected rectangle.

The Color|Solid control displays the dithered and solid colors that correspond to the user's selection. (A dithered color is a color created by combining one or more pure or solid colors.) The Flags member of the CHOOSECOLOR structure contains a flag that, when specified, displays a Help button.

An application can display the Color dialog box in one of two ways: fully open or partially open. When the Color dialog box is displayed partially open, the user cannot change the custom colors.


Color Models Used by the Color Dialog Box

The Color dialog box uses two models for specifying colors: the RGB model and the HSL model. Regardless of the model used, internal storage is accomplished by use of the RGB model.

RGB Color Model

The RGB model is used to designate colors for displays and other devices that emit light. Valid red, green, and blue values are in the range 0 through 255, with 0 indicating minimum intensity and 255 indicating maximum intensity. The following illustration shows how the primary colors red, green, and blue can be combined to produce four additional colors. (For display devices, the color black results when the red, green, and blue values are set to 0; in display technology, black is the absence of all colors.)

Following are eight colors and their associated RGB values.

Color	RGB values
Red	255, 0, 0
Green	0, 255, 0
Blue	0, 0, 255
Cyan	0, 255, 255
Magenta	255, 0, 255
Yellow	255, 255, 0
White	255, 255, 255
Black	0, 0, 0
Windows stores internal colors as 32-bit RGB values. The high-order byte of the high-order word is reserved; the low-order byte of the high-order word specifies the intensity of the blue component; the high-order byte of the low-order word specifies the intensity of the green component; and the low-order byte of the low-order word specifies the intensity of the red component.

HSL Color Model

The Color dialog box provides controls for specifying HSL values. The following illustration shows the color spectrum control and the luminosity control that appear in the Color dialog box and shows the ranges of values the user can specify with these controls.

In the Color dialog box, the saturation and luminosity values must be in the range 0 through 240, and the hue value must be in the range 0 through 239.

Converting HSL Values to RGB Values

The dialog box procedure provided in COMDLG32.DLL for the Color dialog box contains code that converts HSL values to the corresponding RGB values. Following are several colors and their associated HSL and RGB values:

Color	HSL values	RGB values
Red	(0, 240, 120)	(255, 0, 0)
Yellow	(40, 240, 120)	(255, 255, 0)
Green	(80, 240, 120)	(0, 255, 0)
Cyan	(120, 240, 120)	(0, 255, 255)
Blue	(160, 240, 120)	(0, 0, 255)
Magenta	(200, 240, 120)	(255, 0, 255)
White	(0, 0, 240)	(255, 255, 255)
Black	(0, 0, 0)	(0, 0, 0)


Font Dialog Box

Windows NT Overview
For more information, see the Windows 95 overview Font Dialog Box.

The Font dialog box contains controls that allow a user to choose a font, a font style (such as bold, italic, or regular), a point size, an effect (such as underline or strikeout), or a text color. Following is a Font dialog box.


Open and Save As Dialog Boxes

Windows NT Overview
For more information, see the Windows 95 overview Open and Save As Dialog Boxes.

The Open dialog box and the Save As dialog box are similar in appearance. Each contains controls that enable a user to specify the location (drive and directory) and the name of a file or a set of files. In the case of the Open dialog box, the user selects the file or files to be opened. In the case of the Save As dialog box, however, the user selects the file or files to be saved. Following is an Open dialog box.


Print Dialog Box

Windows NT Overview
For more information, see the Windows 95 overview Print Dialog Box.

The Print dialog box contains controls that allow a user to configure a printer for a particular print job. The user can make selections, such as print quality, print range, and number of copies (if the printer supports multiple copies).

The Print dialog box differs from other common dialog boxes in that part of its dialog box procedure resides in COMDLG32.DLL and part in a printer driver. A printer driver is a program that configures a printer, converts graphics device interface (GDI) commands to low-level printer commands, and stores commands for a particular print job in a printer's queue.

A printer driver exports a function called ExtDeviceMode that displays a dialog box and its controls. Applications written for previous versions of Windows called the LoadLibrary function to load a device driver, and the GetProcAddress function to obtain the address of the ExtDeviceMode function. Win32-based applications no longer need to call LoadLibrary and GetProcAddress. Instead, an application calls a single function, PrintDlg, to display the Print dialog box and begin a print job. The code for PrintDlg resides in COMDLG32.DLL. The dialog box that appears when an application calls PrintDlg differs slightly from the dialog box that appears when the application calls directly into the device driver. The functionality is very similar in spite of the different appearance.


Page Setup Dialog Box

Windows NT Overview
For more information, see the Windows 95 overview Page Setup Dialog Box.

The Page Setup dialog box allows the user to set the attibutes of the printed page, including the paper type (envelope, legal, letter, and so on), the paper source (manual feed, tractor feed, sheet feeder, and so on), the page orientation (portrait or landscape), and the width of the page margins. The attributes presented in the dialog box vary depending on the capabilities of the printer.

The dialog box includes an image of a sample page that shows how the user's selections affect the appearance of the printed output. The image consists of a rectangle that represents the selected paper or envelope type. The system uses a dotted-line rectangle to represent the current margins, and fills the rectangle with greeking characters to show how text will look on a printed page.

The system uses a multiple-step process to draw the sample page. You can customize the appearance of the sample page by specifying a hook function that the system calls at each step in the drawing process. When the system calls the hook procedure, it sends a message that contains information that the hook procedure uses to draw in a particular area within the sample page.


Find and Replace Dialog Boxes

Windows NT Overview
For more information, see the Windows 95 overview Find and Replace Dialog Boxes.

The Find dialog box and the Replace dialog box are similar in appearance. You can use the Find dialog box to add string-search capabilities to an application and the Replace dialog box to add both string-search and string-substitution capabilities.

The Find and the Replace dialog boxes differ from other common dialog boxes in that they are modeless. This means the user can switch between the dialog box and the window that created that dialog box.


Using Common Dialog Boxes

Windows NT Overview
For more information, see the Windows 95 overview Using Common Dialog Boxes.

This section explains how to perform the following tasks:

•	Using the Color dialog box to display basic colors.

•	Using the Color dialog box to display custom colors.

•	Displaying the Font dialog box in an application.

•	Displaying the Open dialog box in an application.

•	Displaying the Save As dialog box in an application.

•	Monitoring List Box Controls in an Open or Save As dialog box.

•	Monitoring Filenames in an Open or Save As dialog box.

•	Displaying Explorer-Style Open and Save As Dialog Boxes.

•	Displaying a Print dialog box for the default printer.

•	Displaying the Find dialog box.

•	Displaying the Replace dialog box.

•	Processing Messages for a Find or Replace dialog box.

•	Customizing common dialog boxes.


Using the Color Dialog Box to Display Basic Colors

You can have your application display the Color dialog box so that a user can select one color from a list of basic screen colors. This section describes how you can provide code and structures in your application to make this possible.


Initializing the CHOOSECOLOR Structure to Display Basic Colors

Before displaying a Color dialog box, an application must initialize a CHOOSECOLOR structure. This structure should be global or be declared as a static variable. The members of this structure contain information about the following items:

•	The structure size

•	The window that owns the dialog box

•	Any customization of the common dialog box by the application

•	The hook function and custom dialog box template to use for a customized version of the Color dialog box

•	The RGB values for the selected basic color

If your application does not customize the dialog box and you want the user to be able to select a single color from the basic colors, initialize the CHOOSECOLOR structure in the following manner.

/* Color variables */

CHOOSECOLOR cc;     /* common dialog box structure */

COLORREF acrCustClr[16] = {

    RGB(255, 255, 255), RGB(239, 239, 239),

    RGB(223, 223, 223), RGB(207, 207, 207),

    RGB(191, 191, 191), RGB(175, 175, 175),

    RGB(159, 159, 159), RGB(143, 143, 143),

    RGB(127, 127, 127), RGB(111, 111, 111),

    RGB(95, 95, 95), RGB(79, 79, 79),

    RGB(63, 63, 63), RGB(47, 47, 47),

    RGB(31, 31, 31), RGB(15, 15, 15)

    }; /* array of gray colors */

/* Initialize the necessary members. */

cc.lStructSize = sizeof(CHOOSECOLOR);

cc.hwndOwner = hwnd;

cc.lpCustColors = (LPDWORD) acrCustClr;

cc.Flags = CC_PREVENTFULLOPEN;

/* Call the ChooseColor function. */

if (ChooseColor(&cc)){

.

.   /* Use cc.lpCustColors to select the requested color. */

.

}

In this example, the array pointed to by lpCustColors contains 16 doubleword RGB values that specify the color white, and the CC_PREVENTFULLOPEN flag is specified in the Flags member to disable the Define Custom Colors button and prevent the user from selecting a custom color.


Calling the ChooseColor Function to Display Basic Colors

After you initialize the structure, call the ChooseColor function. If the function succeeds and the user chooses the OK button to close the dialog box, the rgbResult member of the CHOOSECOLOR structure contains the RGB values for the basic color the user selected.


Using the Color Dialog Box to Display Custom Colors

You can have your application display the Color dialog box so that the user can create and select a custom color. This section describes how you can provide code and structures in your application to make this possible.


Initializing the CHOOSECOLOR Structure to Display Custom Colors

Before displaying a Color dialog box, an application must initialize a CHOOSECOLOR structure. This structure should be global or declared as a static variable. The members of this structure contain information about the following items:

•	The structure size

•	The window that owns the dialog box

•	Any customization of the common dialog box by the application

•	The hook function and custom dialog box template to use for a customized version of the Color dialog box

•	The RGB values for the custom color control

If your application does not customize the dialog box and you want the user to be able to create and select custom colors, initialize the CHOOSECOLOR structure in the following manner.

/* Color variables */

CHOOSECOLOR cc;     /* common dialog box structure */

COLORREF acrCustClr[16] = {

    RGB(255, 255, 255), RGB(239, 239, 239),

    RGB(223, 223, 223), RGB(207, 207, 207),

    RGB(191, 191, 191), RGB(175, 175, 175),

    RGB(159, 159, 159), RGB(143, 143, 143),

    RGB(127, 127, 127), RGB(111, 111, 111),

    RGB(95, 95, 95), RGB(79, 79, 79),

    RGB(63, 63, 63), RGB(47, 47, 47),

    RGB(31, 31, 31), RGB(15, 15, 15)

    }; /* array of gray colors */

/* Initialize the necessary members. */

cc.lStructSize = sizeof(CHOOSECOLOR);

cc.hwndOwner = hwnd;

cc.lpCustColors = (LPDWORD) acrCustClr;

cc.Flags = CC_FULLOPEN;

In the previous example, the array pointed to by the lpCustColors member contains sixteen 32-bit RGB values that specify 16 scales of gray, and the CC_FULLOPEN flag is specified in the Flags member to display the complete Color dialog box.


Calling the ChooseColor Function to Display Custom Colors

After you initialize the structure, you should call the ChooseColor function. If the function succeeds and the user chooses the OK button to close the dialog box, the lpCustColors member points to an array that contains the RGB values for the custom colors requested by the user.

You can give your application more control over custom colors by creating a new message identifier for the string defined by COLOROKSTRING . The application creates the new message identifier by calling RegisterWindowMessage and passing this value as the single parameter. After calling RegisterWindowMessage, the application receives a message immediately before the dialog box closes. The lParam parameter of this message contains a pointer to the CHOOSECOLOR structure. The application can use the lpCustColors member of this structure to check the current color. If the application returns a nonzero value when it processes this message, the dialog box does not close.

Similarly, you can have your application create a new message identifier for the string defined by the SETRGBSTRING value. The application's hook function can use the message identifier returned by calling RegisterWindowMessage with the SETRGBSTRING value to set a color in the dialog box. For example, the following line sets the color selection to blue.

SendMessage(hwndDlg, wSetRGBMsg, 0, (LPARAM) RGB(0, 0, 255));

In this example, the wSetRGBMsg argument is the message identifier returned by RegisterWindowMessage. The lParam parameter of the SendMessage function is set to the RGB values of the desired color. The wParam parameter is not used.

You can have your application specify any valid RGB values in the call to SendMessage. If the RGB values match one of the basic colors, the operating system selects the basic color and updates the spectrum and luminosity controls. If the RGB values do not match one of the basic colors, the system updates the spectrum and luminosity controls, but the basic color selection remains unchanged.

Note that if the Color dialog box is not fully open and the application sends RGB values that do not match one of the basic colors, the operating system does not update the dialog box. Updates are unnecessary because the spectrum and luminosity controls are not visible when the dialog box is only partially open.

For more information about processing registered window messages, see Displaying the Find Dialog Box.


Displaying the Font Dialog Box in An Application

The Font dialog box appears after you initialize the members in a CHOOSEFONT structure and call the ChooseFont function. This structure should be global or be declared as a static variable. The members of the CHOOSEFONT structure contain information about the following items:

•	Which attributes of the font initially appear in the dialog box.

•	Which attributes of the font the user has selected.

•	Which point size of the font the user has selected.

•	Whether the list of fonts corresponds to a printer, a screen, or both.

•	Whether the available fonts listed are TrueType only.

•	Whether the Effects box should appear in the dialog box.

•	Whether dialog box messages should be processed by an application-defined hook function.

•	Whether the point sizes of the selectable fonts should be limited to a specified range.

•	Whether the dialog box displays only what-you-see-is-what-you-get (WYSIWYG) fonts. (These fonts are resident on both the screen and the printer.)

•	Which color ChooseFont uses to render text in the Sample box the first time the application displays the dialog box.

•	Which color the user selected for text output.

To display the Font dialog box, include the following steps in your application:

1.	If the application requires printer fonts, obtain a device context (DC) handle for the printer and use this handle in the hDC member of the CHOOSEFONT structure. (If the Font dialog box displays only screen fonts, this member should be NULL.)

2.	Use appropriate flags in the Flags member of the CHOOSEFONT structure. They must include CF_SCREENFONTS, CF_PRINTERFONTS, or CF_BOTH.

3.	Set the rgbColors member of the CHOOSEFONT structure if the default color (black) is not appropriate.

4.	Set the nFontType member of the CHOOSEFONT structure by using the appropriate constant.

5.	Set the nSizeMin and nSizeMax members of the CHOOSEFONT structure if the CF_LIMITSIZE flag is specified in the Flags member.

6.	Call the ChooseFont function.

The following example initializes the CHOOSEFONT structure, calls ChooseFont, and uses the requested font to draw text on the display.

/* Font variables */

CHOOSEFONT cf;     /* common dialog box structure  */

LOGFONT lf;        /* logical font structure       */

HDC hdc;           /* display DC handle            */

HFONT hfont;       /* new logical font handle      */

HFONT hfontOld;    /* original logical font handle */

COLORREF crOld;    /* original text color          */

/* Initialize the necessary members. */

cf.lStructSize = sizeof (CHOOSEFONT);

cf.hwndOwner = hwnd;

cf.lpLogFont = &lf;

cf.Flags = CF_SCREENFONTS | CF_EFFECTS;

cf.rgbColors = RGB(0, 255, 255);

cf.nFontType = SCREEN_FONTTYPE;

/*

 * Display the dialog box, allow the user to

 * choose a font, and render the text in the

 * window with that selection.

 */

if (ChooseFont(&cf)){

    hdc = GetDC(hwnd);

    hfont = CreateFontIndirect(cf.lpLogFont);

    hfontOld = SelectObject(hdc, hfont);

    crOld = SetTextColor(hdc, cf.rgbColors);

    TextOut(hdc, 50, 150,

        "AaBbCcDdEeFfGgHh", 16);

    SetTextColor(hdc, crOld);

    SelectObject(hdc, hfontOld);

    DeleteObject(hfont);

    ReleaseDC(hwnd, hdc);

    }

An application can also use the WM_CHOOSEFONT_GETLOGFONT message to retrieve the current LOGFONT structure for the Font dialog box before the user closes the dialog box.


Displaying the Open Dialog Box in An Application

The Open dialog box appears after you initialize the members of an OPENFILENAME structure and call the GetOpenFileName function.

Before you call GetOpenFileName, structure members contain certain data, such as the name of the directory and the filter that appears in the dialog box. (A filter is a filename extension. The common dialog box code uses the extension to filter appropriate filenames from a directory.) After the call, structure members contain other data, such as the name of the selected file and the number of characters in that filename.

To display an Open dialog box, include the following steps in your application:

1.	Store the valid filters in a character array.

2.	Set the lpstrFilter member to point to this array.

3.	Set the nFilterIndex member to the value of the index that identifies the default filter.

4.	Set the lpstrFile member to point to an array that contains the initial filename and receives the selected filename.

5.	Set the nMaxFile member to the value that specifies the length of the filename array.

6.	Set the lpstrFileTitle member to point to a buffer that receives the title of the selected file.

7.	Set the nMaxFileTitle member to specify the length of the buffer.

8.	Set the lpstrInitialDir member to point to a string that specifies the initial directory. (If this member does not point to a valid string, it must be set to zero or point to a string set to NULL.)

9.	Set the lpstrTitle member to point to a string specifying the name that appears in the title bar of the dialog box. (If this pointer is NULL, the title is Open by default.)

10.	Initialize the lpstrDefExt member to point to the default extension. (This extension can be 0, 1, 2, or 3 characters long.)

11.	Call the GetOpenFileName function.

The following example initializes an OPENFILENAME structure, calls GetOpenFileName, and opens the file by using the lpstrFile member of the structure. The OPENFILENAME structure should be global or be declared as a static variable.

OPENFILENAME ofn;       /* common dialog box structure   */

char szDirName[MAX_PATH];    /* directory string              */

char szFile[260];       /* filename string               */

char szFileTitle[260];  /* file title string             */

char szFilter[260];     /* filter string                 */

char chReplace;         /* string separator for szFilter */

int i, cbString;        /* integer count variables       */

HANDLE hf;              /* file handle                   */

.

.

.

/*

 * Obtain the system directory name and

 * store it in szDirName.

 */

GetSystemDirectory(szDirName, sizeof(szDirName));

/* Place the terminating null character in the szFile. */

szFile[0] = '\0';

/* Load the filter string from the .RC file. */

cbString = LoadString(hinst, IDS_FILTERSTRING,

    szFilter, sizeof(szFilter));

/*

 * Add a terminating null character to the filter string.

 */

chReplace = szFilter[cbString - 1];

for (i = 0; szFilter[i] != '\0'; i++){

    if (szFilter[i] == chReplace)

        szFilter[i] = '\0';

}

/* Set the members of the OPENFILENAME structure. */

ofn.lStructSize = sizeof(OPENFILENAME);

ofn.hwndOwner = hwnd;

ofn.lpstrFilter = szFilter;

ofn.nFilterIndex = 1;

ofn.lpstrFile = szFile;

ofn.nMaxFile = sizeof(szFile);

ofn.lpstrFileTitle = szFileTitle;

ofn.nMaxFileTitle = sizeof(szFileTitle);

ofn.lpstrInitialDir = szDirName;

ofn.Flags = OFN_SHOWHELP | OFN_PATHMUSTEXIST |

    OFN_FILEMUSTEXIST;

/* Display the Open dialog box. */

if (GetOpenFileName(&ofn)) {

    /* Open the file. */

    hf = CreateFile(ofn.lpstrFile, GENERIC_READ,

        0, (LPSECURITY_ATTRIBUTES) NULL,

        OPEN_EXISTING,

        FILE_ATTRIBUTE_NORMAL,

        (HANDLE) NULL);

    .

    .   /* Perform the necessary file operations. */

    .

    /* Close the file. */

    CloseHandle(hf);

} /* end if */

The string referred to by the IDS_FILTERSTRING value in the preceding example is defined as follows in the resource-definition file.

STRINGTABLE

BEGIN

    IDS_FILTERSTRING "Bitmap File(*.BMP)|*.bmp|"

END

The vertical bars in this string are used as wildcards. After the LoadString function is used to retrieve the string, the wildcards are replaced with NULL. The wildcard can be any unique character and must be included as the last character in the string. Initializing strings in this manner guarantees that the parts of the string are contiguous in memory and that the string is terminated with two null characters.

An application that can open files over a network can create a new message identifier for the string defined by the SHAREVISTRING value. The application creates the new message identifier by calling RegisterWindowMessage and passing this value as the single parameter. After calling RegisterWindowMessage, the application is notified whenever a sharing violation occurs during a call to the OpenFile function. For more information about processing registered window messages, see Displaying the Find Dialog Box.


Displaying the Save As Dialog Box in An Application

The Save As dialog box appears after you initialize the members of an OPENFILENAME structure and call the GetSaveFileName function.

Before you call GetSaveFileName, structure members contain certain data, such as the name of the initial directory and a filter string. After the call, structure members contain other data, such as the name of the file to be saved and the number of characters in that filename.

The following example initializes an OPENFILENAME structure, calls GetSaveFileName, and saves the file. The OPENFILENAME structure should be global or be declared as a static variable.

OPENFILENAME ofn;       /* common dialog box structure   */

char szDirName[MAX_PATH];    /* directory string              */

char szFile[260];       /* filename string               */

char szFileTitle[260];  /* file title string             */

char szFilter[260];     /* filter string                 */

char chReplace;         /* string separator for szFilter */

int i, cbString;        /* integer count variables       */

HANDLE hf;              /* file handle                   */

/*

 * Obtain the system directory name and

 * store it in szDirName.

 */

GetSystemDirectory(szDirName, sizeof(szDirName));

/* Place the terminating null character in szFile. */

szFile[0] = '\0';

/* Load the filter string from the .RC file. */

cbString = LoadString(hinst, IDS_FILTERSTRING,

    szFilter, sizeof(szFilter));

/*

 * Add a terminating null character to the filter string.

 */

chReplace = szFilter[cbString - 1];

for (i = 0; szFilter[i] != '\0'; i++){

    if (szFilter[i] == chReplace)

        szFilter[i] = '\0';

}

/* Set the members of the OPENFILENAME structure. */

ofn.lStructSize = sizeof(OPENFILENAME);

ofn.hwndOwner = hwnd;

ofn.lpstrFilter = szFilter;

ofn.nFilterIndex = 1;

ofn.lpstrFile = szFile;

ofn.nMaxFile = sizeof(szFile);

ofn.lpstrFileTitle = szFileTitle;

ofn.nMaxFileTitle = sizeof(szFileTitle);

ofn.lpstrInitialDir = szDirName;

ofn.Flags = OFN_SHOWHELP | OFN_OVERWRITEPROMPT;

/* Display the Save As dialog box. */

if (GetSaveFileName(&ofn)) {

    .

    .   /* Perform the necessary file operations. */

    .

    /* Close the file. */

    CloseHandle(hf);

} /* end if */

The string referred to by the IDS_FILTERSTRING value in the preceding example is defined in the resource-definition file. It is used in exactly the same way as the IDS_FILTERSTRING value discussed in Displaying the Open Dialog Box in An Application.


Monitoring List Box Controls in an Open or Save As Dialog Box

An application can monitor list box selections to process and display data in custom controls. For example, an application can use a custom control to display the total length, in bytes, of all files selected in the File Name box. One method that the application can use to obtain this value is to recompute the total count of bytes each time the user selects a file or cancels the selection of a file. A faster method is for the application to use the LBSELCHSTRING message to identify a new selection and to add the corresponding file length to the value that appears in the custom control. (Note that, in this example, the custom control is a standard Windows control that is identified in a resource file template for one of the common dialog boxes.)

An application uses RegisterWindowMessage to register the selection change message. After registering the message, the application uses this function's return value to identify messages from the dialog box. The message is processed in the application-defined hook function for the common dialog box. The wParam parameter of each message identifies the list box in which the selection occurred. The low-order word of the lParam parameter identifies the list box item. The high-order word of the lParam parameter is one of the following values.

Value	Meaning
CD_LBSELCHANGE	The item identified by the low-order word of lParam was the item in a single-selection list box.
CD_LBSELSUB	The item identified by the low-order word of lParam is no longer selected in a multiple-selection list box.
CD_LBSELADD	The item identified by the low-order word of lParam was selected from a multiple-selection list box.
CD_LBSELNOITEMS	No items exist in a multiple-selection list box.
For an example that registers a common dialog box message, see Displaying the Find Dialog Box.


Monitoring Filenames in an Open or Save As Dialog Box

An application can alter the normal processing of an Open or Save As dialog box by monitoring the filename the user types and by performing other unique operations. For example, one application can prevent the user from closing the dialog box if the selected filename is prohibited. Another application, however, can enable the user to select multiple filenames.

To monitor filenames, register the FILEOKSTRING message. Do this by calling the RegisterWindowMessage function and passing the message name as its single parameter. After the message has been registered, the dialog box procedure in COMDLG32.DLL uses it to signal that the user has selected a filename and chosen the OK button and that the dialog box has checked the filename and is ready to return. The dialog box procedure signals these actions by sending the message to the application's hook function. After receiving the message, the hook function should return a value to the dialog box procedure that called it. If the hook function did not process the message, it should return 0; if the hook function processed the message and the dialog box should close, the hook function should return 0; and if the hook function processed the message but the dialog box should not close, the hook function should return 1. All other return values are reserved.


Displaying Explorer-Style Open and Save As Dialog Boxes

If you specify OFN_EXPLORER in the Flags member of the OPENFILENAME structure used to create the Open or Save As common dialog box, the system creates a dialog box that incorporates many of the user-interface features of the Windows Explorer. In addition, specifying OFN_EXPLORER allows you to customize the Open and Save As dialog boxes by adding a dialog template that includes the items that you want to add to the dialog box.

The OFN_EXPLORER value affects the way that the system interprets the hInstance, lpfnHook, and lpTemplateName members of the OPENFILENAME structure. If the Flags member includes OFN_ENABLETEMPLATE, the lpTemplateName member must point to the name of a dialog template resource in the module identified by hInstance. The dialog template must have the WS_CHILD style, and should also have the DS_3DLOOK style to ensure that the child dialog box incorporates the same user interface style as the common dialog box. The system uses the dialog template to create a child dialog box and positions it at the upper left corner of the standard file dialog box, growing the child dialog box if necessary to fit all controls for both dialog boxes.

If the child dialog box has a control with a identifier equal to stc32, the system attempts to place all of the standard dialog box controls within the stc32 control. If the stc32 control is too small to fit the standard controls, the system moves other controls in the child dialog box to the right of or below the stc32 control to make room — you don't need to know the exact dimensions of the common dialog box. If there is no stc32 control, the system positions all controls defined by the child dialog template below the standard controls. The system resizes the stc32 control to the size of the standard dialog box.

If the Flags member includes OFN_ENABLETEMPLATEHANDLE, the hInstance member is the memory handle of the dialog template. The system uses this template exactly as it uses the dialog template specified in lpTemplateName when Flags includes OFN_ENABLETEMPLATE, as described in the previous paragraphs.

The system communicates with the child dialog box by sending messages to the dialog procedure of the child dialog box. To specify the dialog box procedure, you must include OFN_ENABLEHOOK in the Flags member of the OPENFILENAME structure, and specify the address the procedure in the lpfnHook member.

When the system creates the dialog box, it sends WM_INITDIALOG message to the child dialog procedure specified in the lpfnHook member. The child dialog procedure receives the message before the system has moved any controls. The lParam parameter specifies the address of the OPENFILENAME structure that was passed to the GetOpenFileName or GetSaveFileName function.

The system also sends notification messages to the child dialog procedure to notify it of user and system activity affecting the child dialog box. The notification messages, sent using the WM_NOTIFY message, consist of the following:

Notification message	Description
CDN_FILEOK	The user click the Open or Save button; the common dialog box is about to close.
CDN_FOLDERCHANGE	A new folder has been opened in the Open or Save As dialog box.
CDN_HELP	The user clicked the Help button.
CDN_INITDONE	The system has finished initializating the dialog box, and the dialog box has finished processing the WM_INITDIALOG message. Also, the system has finished arranging controls in the common dialog box to make room for the controls of the child dialog box.
CDN_SELCHANGE	The user has selected a new file or folder from the file list.
CDN_SHAREVIOLATION	The common dialog box encountered a sharing violation on the file about to be returned.
CDN_TYPECHANGE	The user selected a new file type from the "Files of type" combo box.
If the child dialog procedure needs to return a value to the common dialog box, the procedure must use the SetWindowLong function to set the DWL_MSGRESULT value.

An application can send messages to an explorer-style Open or Save As dialog box to retrieve information about the status of the dialog box. The messages include:

Message	Description
CDM_GETFILEPATH	Retrieves the path and filename of the selected file.
CDM_GETFOLDERIDLIST	Retrieves the address of the item identifier list corresponding to the folder that the dialog box currently has open.
CDM_GETFOLDERPATH	Retrieves the path and name of the currently open folder or directory for the dialog box.
CDM_GETSPEC	Retrieves the filename (not including the path) of the currently selected file in the dialog box.


Displaying a Print Dialog Box for the Default Printer

To display a Print dialog box for the default printer, initialize a PRINTDLG structure and then call the PrintDlg function.

The members of the PRINTDLG structure can contain information about the following items:

•	The printer device context

•	The values that should appear in the dialog box controls

•	The hook function and custom dialog box template to use for a customized version of the Print dialog box or Print Setup dialog box

To display a Print dialog box for the currently installed printer, include the following steps in your application:

1.	Use the PD_RETURNDC flag in the Flags member of the PRINTDLG structure. This flag should be specified only if the application requires a device context (DC) handle.

2.	Initialize the lStructSize, hDevMode, and hDevNames members.

3.	Call the PrintDlg function and pass a pointer to the PRINTDLG structure just initialized.

Using the PD_RETURNDC flag causes PrintDlg to display the Print dialog box and return a handle identifying a printer device context in the hDC member of the PRINTDLG structure. The application passes the DC handle as the first parameter to the graphics device interface (GDI) functions that render output on the printer.


Displaying the Page Setup Dialog Box

The Page Setup dialog box allows the user to set the attibutes of the printed page, including the paper type, the paper source, the page orientation, and the width of the page margins. To display the Page Setup dialog box, initialize a PAGESETUPDLG structure and call the PageSetupDlg function.

One of the ways an application can customize the Page Setup dialog box is to use a hook function to paint the sample page of the dialog box. To use such a hook function, you must specify the PSD_ENABLEPAGEPAINTHOOK flag in the Flags member of the PAGESETUPDLG structure, and the name of your hook function in the lpfnPagePaintHook member.

After the dialog box is created, the system makes a sequence of calls to the hook function. Each call corresponds to a step in the drawing process, and includes a message that identifies the area of the sample page to be drawn, and the device context for the sample page. By processing these messages, the hook function can draw in one or more areas of the sample page. For a list of messages, see the description of the PAGESETUPDLG structure.

The following example creates a Page Setup dialog box and uses a hook function to draw the margin rectangle in the sample page area:

void DoPage(HWND hwnd, RECT rcMarg, RECT rcMinMarg, POINT ptPaperSize)

{

    PAGESETUPDLG psd = {0};

    psd.lStructSize = sizeof(PAGESETUPDLG);

    psd.hwndOwner   = hwnd;

    psd.hDevMode    = hDevMode;

    psd.hDevNames   = hDevNames;

    psd.Flags       = PSD_INTHOUSANDTHSOFINCHES | PSD_MARGINS |

        PSD_MINMARGINS | PSD_ENABLEPAGEPAINTHOOK;

    psd.ptPaperSize = ptPaperSize;

    psd.rtMargin = rcMarg;

    psd.rtMinMargin = rcMinMarg;

    psd.hInstance= g_hinst;

    psd.lCustData = 0;

    psd.lpfnPagePaintHook = PaintHook;

    PageSetupDlg(&psd);

}

BOOL CALLBACK PaintHook(HWND hwndDlg, UINT uMsg, WPARAM wParam,

    LPARAM lParam)

{

    LPRECT lprc;

    COLORREF crMargRect;

    HDC hdc, hdcOld;

    switch (uMsg) {

        // Drawing the margin rectangle.

        case WM_PSD_MARGINRECT:

            hdc = (HDC) wParam;

            lprc = (LPRECT) lParam;

            // Get the system highlight color.

            crMargRect = GetSysColor(COLOR_HIGHLIGHT);

            // Create a dash-dot pen of the system highlight color and

            // select it into the DC of the sample page.

            hdcOld = SelectObject(hdc, CreatePen(PS_DASHDOT, .5,

                crMargRect));

            // Draw the margin rectangle.

            Rectangle(hdc, lprc->left, lprc->top, lprc->right,

                lprc->bottom);

            // Restore the previous pen to the DC.

            SelectObject(hdc, hdcOld);

            return TRUE;

        default:

            return FALSE;

    }

    return TRUE;

}


Displaying the Find Dialog Box

The Find dialog box contains controls that allow a user to specify the following items:

•	Which string the application should find

•	Whether the string specifies a complete word or part of a word

•	Whether the application should match the case of the specified string

•	Which direction the application should search (preceding or following the current cursor location)

•	Whether the application should resume the search, searching for the next occurrence of the string

To display the Find dialog box, initialize a FINDREPLACE structure and call the FindText function. Members of the FINDREPLACE structure contain information about the following items:

•	Which window owns the dialog box

•	How the application should perform the search

•	Which character buffer should receive the string

To initialize the FINDREPLACE structure, perform the following tasks:

1.	Set the lStructSize member by using the sizeof operator.

2.	Set the hwndOwner member by using the handle that identifies the owner window of the dialog box.

3.	If you are customizing the Find dialog box, set the hInstance member to identify the instance of the module that contains your custom dialog box template.

4.	Set the Flags member to indicate the selection state of the dialog box options. (For example, specifying the FR_NOUPDOWN flag disables the Up and Down buttons, specifying the FR_NOWHOLEWORD flag disables the Match Whole Word Only check box, and specifying the FR_NOMATCHCASE flag disables the Match Case check box.)

5.	If you are supplying a custom dialog box template or hook function, specify additional flags in the Flags member.

6.	Set the lpstrFindWhat member to point to the buffer receiving the string to be found.

7.	Set the wFindWhatLen member to specify the size, in bytes, of the buffer pointed to by lpstrFindWhat.

8.	Set the lCustData member with any custom data your application may need to access.

9.	If your application customizes the Find dialog box, set the lpfnHook member to point to your hook function.

10.	If your application uses a custom dialog box template, set the lpTemplateName member to point to the string that identifies the template.

The following example initializes the FINDREPLACE structure and then calls FindText. This structure should be global or be declared as a static variable.

/* Find/Replace variables */

FINDREPLACE fr;        /* common dialog box structure     */

FINDREPLACE FAR* lpfr; /* pointer to dialog box structure */

CHAR szFindWhat[80];   /* buffer receiving string         */

HWND hdlg;             /* handle of dialog window         */

UINT uFindReplaceMsg;  /* returned by RegisterMessage()   */

/* Initialize the necessary members. */

fr.lStructSize = sizeof(FINDREPLACE);

fr.hwndOwner = hwnd;

fr.lpstrFindWhat = szFindWhat;

fr.wFindWhatLen = sizeof(szFindWhat);

/* Display the modeless Find dialog box. */

hdlg = FindText(&fr);


Displaying the Replace Dialog Box

The Replace dialog box is similar to the Find dialog box. However, the Replace dialog box has no Direction check box and has three additional controls that enable the user to specify the following:

•	Which string to replace

•	Whether the application should replace the occurrence of the string currently highlighted

•	Whether the application should replace all occurrences of the string

To display the Replace dialog box, initialize a FINDREPLACE structure and call the ReplaceText function.


Processing Messages for a Find or Replace Dialog Box

The Find and Replace dialog boxes differ from the other common dialog boxes in two respects: they are modeless and their respective dialog box procedures send messages to the application that calls the FindText or ReplaceText function. These messages contain data specified by the user in the dialog box controls, including which direction the application should search for a string, whether the application should match the case of the specified string, and whether the application should match the entire string.

To process messages from a Find or Replace dialog box, an application must register the dialog box's unique message, FINDMSGSTRING.

The application registers this message with the RegisterWindowMessage function. After the application registers the message, it uses the function's return value to identify messages from the Find or Replace dialog box. The following example registers the message with RegisterWindowMessage.

/* Register the FindReplace message. */

uFindReplaceMsg = RegisterWindowMessage(FINDMSGSTRING);

After the application registers this message, it can process messages for the Find or Replace dialog box by using the RegisterWindowMessage function's return value. The following example processes messages for the Find dialog box and then calls its own SearchFile function to locate the string of text. If the user is closing the dialog box (that is, if the Flags member of the FINDREPLACE structure is FR_DIALOGTERM), the handle is invalidated and the procedure returns zero.

if (message == uFindReplaceMsg){

    /*

     * Extract a pointer to the FINDREPLACE

     * structure from lParam.

     */

     lpfr = (FINDREPLACE FAR*) lParam;

    /*

     * If the system has set the FR_DIALOGTERM

     * flag, invalidate the handle identifying

     * the dialog box.

     */

     if (lpfr->Flags & FR_DIALOGTERM){

        hdlg = NULL;

        return 0;

        }

    /*

     * If the dialog box is still valid, call the

     * application-defined search routine (SearchFile) to

     * search for the requested string.

     */

     SearchFile((BOOL) (lpfr->Flags & FR_DOWN),

        (BOOL) (lpfr->Flags & FR_MATCHCASE));

     return 0;

     }


Customizing Common Dialog Boxes

A custom common dialog box is a common dialog box altered to suit a particular Windows-based application. The customization may be complex and include the hiding of original controls, the addition of new controls, or a change in the size of the original dialog box; or it may be simple, involving the alteration of a single existing control.

If you want to customize a common dialog box, you must provide a special hook function and, in most cases, a custom dialog box template. Customizations of this kind require a significant amount of additional code — displaying a customized common dialog box is not as simple as initializing the members of a structure and calling a single function.

Applications that subclass controls in any of the common dialog boxes must do so while processing the WM_INITDIALOG message in the application's hook function. This method allows the application to receive the control-specific messages first, because it subclasses the control after the common dialog box has installed its subclassing procedures. (The previous hook function should be called for all messages not handled by the application's subclass function, as is standard for subclassing.)

An application cannot subclass a control by defining a local class to override a specific control type. This is not possible because the data segment will not be initialized correctly when the class is called — the data segment will be the common dialog box's data segment, not the application's data segment.


Appropriate and Inappropriate Customizations

From the user's perspective, the chief benefit of the common dialog box is its consistent appearance and functionality from application to application. Therefore, it is important that you customize a common dialog box only when it is absolutely necessary for an application. Otherwise, the consistent appearance and simple coding interface are lost. Appropriate customizations leave intact as many of the original controls as possible. Increasing the size of the dialog box or adding new controls in available space already in the dialog box is an appropriate customization. Hiding original controls or otherwise changing the intended functionality of the original controls is a less appropriate customization.


Hook Functions and Custom Dialog Box Templates

Windows NT Overview
For more information, see the Windows 95 overview Hook Functions and Custom Dialog Box Templates.

Each common dialog box uses the dialog box procedure and dialog box template provided for it in COMDLG32.DLL. The dialog box procedure processes messages and notifications for the common dialog box and its controls. The dialog box template defines the appearance of the dialog box — its dimensions, its location, and the dimensions and locations of controls within it.

In addition to the procedure and template provided, a custom dialog box requires a hook function that you provide and, usually, a custom version of the dialog box template.


The Hook Function

Windows NT Overview
For more information, see the Windows 95 overview Hook Function.

The dialog box procedure provided in COMDLG32.DLL for a common dialog box calls the application's hook function if the application specifies the appropriate flag and pointer in the structure for that common dialog box. The structure for each common dialog box contains a Flags member that specifies whether the application defines a hook function and contains an lpfnHook member that points to the hook function, if one exists. If the application sets the Flags member to indicate that a hook function exists, it must also set the lpfnHook member. The following example sets the Flags and lpfnHook members of an OPENFILENAME structure to support an application's hook function.

#include <windows.h>

#include <commdlg.h>

#include <dlgs.h>

#include "generic.h"

OPENFILENAME ofn;       /* common dialog box structure    */

char szDirName[256];    /* directory string               */

char szFile[256];       /* filename string                */

char szFileTitle[256];  /* file title string              */

char szFilter[256];     /* filter string                  */

char chReplace;         /* string separator for szFilter  */

int i, cbString;        /* integer count variables        */

DWORD cBufLen;          /* dword count                    */

DWORD cTmp;             /* dword count                    */

HANDLE hf;              /* original file handle           */

HANDLE hfBackup;        /* backup file handle             */

char szBuffer[256];     /* character buffer               */

char szChar[256];       /* character buffer               */

char* pszBackupFile;    /* pointer to backup filename     */

BOOL fBackup;           /* TRUE if user checked "backup"  */

/* Obtain the system directory name. */

GetSystemDirectory((LPSTR)szDirName, sizeof(szDirName));

/* Place the terminating null character in the szFile. */

szFile[0] = '\0';

/* Load the filter string from the .RC file. */

cbString = LoadString(hinst, IDS_FILTERSTRING,

    szFilter, sizeof(szFilter));

/* Add a terminating null character to the string. */

chReplace = szFilter[cbString - 1];

for (i = 0; szFilter[i] != '\0'; i++) {

    if (szFilter[i] == chReplace)

        szFilter[i] = '\0';

}

/* Initialize the required OPENFILENAME members. */

ofn.lStructSize = sizeof(OPENFILENAME);

ofn.hwndOwner = hwnd;

ofn.hInstance = hinst;

ofn.lpstrFilter = szFilter;

ofn.nFilterIndex = 1;

ofn.lpstrFile = szFile;

ofn.nMaxFile = sizeof(szFile);

ofn.lpstrFileTitle = szFileTitle;

ofn.nMaxFileTitle = sizeof(szFileTitle);

ofn.lpstrInitialDir = szDirName;

ofn.Flags = OFN_SHOWHELP | OFN_PATHMUSTEXIST |

    OFN_FILEMUSTEXIST | OFN_ENABLEHOOK |

    OFN_ENABLETEMPLATE;

ofn.lpfnHook = FileOpenHookProc;

ofn.lpTemplateName = "FILEOPEN";

In the previous example, the address of the application-defined hook function is assigned to the lpfnHook member of the OPENFILENAME structure. The hook function processes any messages or notifications the custom dialog box requires. With the exception of one message (WM_INITDIALOG), the hook function receives messages and notifications before the dialog box procedure provided in COMDLG32.DLL receives them. In the case of WM_INITDIALOG, the hook function receives the message after the dialog box procedure. When the hook function finishes processing a message, it returns a value that indicates whether the dialog box procedure provided in COMDLG32.DLL should also process the message. If the dialog box procedure should process the message, the return value is FALSE. However, if the dialog box procedure should ignore the message, the return value is TRUE.

To process the message from the OK button after the dialog box procedure processes it, an application must post a message to itself when the OK message is received. When the application receives the message it has posted, the common dialog box procedure will have finished processing messages for the dialog box. This technique is particularly useful when working with the Find and Replace dialog boxes, because the Flags member of the FINDREPLACE structure does not reflect changes to the dialog box until after the messages have been processed by COMDLG32.DLL.

The following example shows a hook function for a custom Open dialog box.

UINT FAR PASCAL FileOpenHookProc(HWND hdlg, UINT msg, WPARAM wParam,

    LPARAM lParam)

{

    switch (msg) {

        /* WM_INITDIALOG is received after commdlg

        /* is processed.

         */

        case WM_INITDIALOG:

            return TRUE;

        case WM_COMMAND:

            /* Use IsDlgButtonChecked to set lCustData. */

            if (wParam == IDOK)

                /* Set the "backup file" flag. */

                fBackup = (DWORD) IsDlgButtonChecked(hdlg,

                    ID_CUSTCHX);

            return FALSE; /* Allow standard processing. */

            break;

        default:

            return FALSE;

    } /* end switch */

    return FALSE;

}

This hook function tests a custom check box when the user chooses the OK button. If the check box is selected, the hook function sets a global variable to a nonzero value; otherwise, it sets this variable to zero.

A hook function should never call the EndDialog function. Instead, if a hook function contains code that abnormally terminates a common dialog box, this code should pass the IDABORT value to the dialog box procedure by using the PostMessage function, as shown in the following example.

PostMessage(hDlg, WM_COMMAND, IDABORT, (LONG) FALSE);

When a hook function posts the IDABORT value, the common dialog box function returns the value contained in the low-order word of the lParam parameter. For example, if the hook function for GetOpenFileName calls the PostMessage function with (LONG) 100 as the last parameter, GetOpenFileName returns 100.

A hook function must be exported in an application's module-definition (.DEF) file, as shown in the following example.

NAME         Generic       ; application's module name

DESCRIPTION  'Sample Win32-based Application'

EXETYPE      WINDOWS       ; required for all Win32-based applications

STUB         'WINSTUB.EXE' ; Generates an error message if the

                           ; application is run without

                           ; Windows

CODE  PRELOAD MOVEABLE DISCARDABLE

DATA  PRELOAD MOVEABLE MULTIPLE

EXPORTS

        MainWndProc   @1   ; window processing function

        About         @2   ; "About" processing function

        FileOpenHookProc @3; common dialog box callback


Customizing a Dialog Box Template

The dialog box template provided in COMDLG32.DLL for each common dialog box contains the data the dialog box procedure uses to display that common dialog box. Most applications that customize a common dialog box also need to create a custom dialog box template to use instead of the dialog box template in COMDLG32.DLL. (A custom dialog box template is not required for all custom dialog boxes. A template would not be necessary, for instance, if an application changed a dialog box in a relatively minor way and only in an unusual situation.)

A developer should create a custom dialog box template by modifying the appropriate dialog box template in COMDLG32.DLL. Following are the template filenames and the names of their corresponding common dialog boxes.

Template filename	Corresponding dialog box
COLOR.DLG	Color
FILEOPEN.DLG	Open (single selection)
FILEOPEN.DLG	Open (multiple selection)
FINDTEXT.DLG	Find
FINDTEXT.DLG	Replace
FONT.DLG	Font
PRNSETUP.DLG	Print
PRNSETUP.DLG	Print Setup
Note  The custom dialog box templates listed above are defined in DLGS.H, except for COLOR.DLG, which is defined in COLORDLG.H.

The following example is from a custom dialog box template created for an Open dialog box.

FILEOPEN DIALOG LOADONCALL MOVEABLE DISCARDABLE

    36, 24, 264, 134

CAPTION "Open"

STYLE WS_CAPTION | WS_SYSMENU | WS_POPUP | DS_MODALFRAME

FONT 8, "Helv"

BEGIN

    LTEXT "File &Name:", stc3, 6, 6, 76, 10

    CONTROL "", edt1, "edit", ES_LEFT | ES_AUTOHSCROLL |

        WS_BORDER | WS_TABSTOP | WS_CHILD | ES_OEMCONVERT |

        ES_LOWERCASE, 6, 16, 90, 12

    CONTROL "", lst1, "listbox", LBS_SORT | LBS_NOTIFY |

        LBS_DISABLENOSCROLL | WS_VSCROLL | WS_BORDER |

        WS_TABSTOP | LBS_EXTENDEDSEL | LBS_HASSTRINGS |

        LBS_OWNERDRAWFIXED, 6, 32, 90, 68

    LTEXT "&Directories:", -1, 110,  6, 92, 9

    LTEXT "", stc1,            110, 16, 92, 9, SS_NOPREFIX

    CONTROL "", lst2, "listbox", LBS_SORT | LBS_HASSTRINGS |

        LBS_NOTIFY | LBS_DISABLENOSCROLL | WS_VSCROLL |

        WS_CHILD | WS_BORDER | WS_TABSTOP |

        LBS_OWNERDRAWFIXED, 110, 32, 92, 68

    LTEXT "List Files of &Type:", stc2, 6, 102, 90, 9

    CONTROL "", cmb1, "combobox", CBS_DROPDOWNLIST |

        CBS_AUTOHSCROLL | WS_BORDER | WS_VSCROLL |

        WS_TABSTOP | WS_CHILD, 6,  112,  90,  36

    LTEXT "Dri&ves:", stc4, 110, 102, 92, 9

    CONTROL "", cmb2, "combobox", CBS_SORT |

        CBS_HASSTRINGS | CBS_OWNERDRAWFIXED |

        CBS_DROPDOWNLIST | WS_CHILD |

        CBS_AUTOHSCROLL | WS_BORDER | WS_VSCROLL |

        WS_TABSTOP, 110, 112,  92, 68

    DEFPUSHBUTTON "OK",  IDOK,     208,  6, 50, 14, WS_GROUP

    PUSHBUTTON "Cancel", IDCANCEL, 208, 24, 50, 14, WS_GROUP

    PUSHBUTTON "&Help", pshHelp,     208,  46, 50, 14,

        WS_GROUP

    PUSHBUTTON "Net&work...", psh14, 208, 114, 50, 14,

        WS_GROUP

    AUTOCHECKBOX "&Read Only", chx1, 208,  68, 50, 12,

        WS_TABSTOP | WS_GROUP

    AUTOCHECKBOX "&Backup File", ID_CUSTCHX,

        208, 86, 50, 12, BS_AUTOCHECKBOX | WS_CHILD |

        WS_TABSTOP | WS_GROUP

END

The last entry supports the addition of a new Backup File check box immediately below the existing Read Only check box.

The custom template should be added to the application's resource file. You must use all of the unique control identifiers (that is, all identifiers whose values are other than −1) in the template, even if the dialog box does not use those controls. If you do not want to display all of the controls, you can specify coordinates for them outside the dialog box. You should also disable unwanted buttons and remove unnecessary tab stops.


Displaying the Custom Dialog Box

After your application creates the hook function and the dialog box template, it should set the members of the structure for the common dialog box being customized and call the appropriate function to display the custom dialog box.

The following example calls the GetOpenFileName function and creates a backup file if the user selects the Backup File check box in the custom Open dialog box.

/* Process the requested file. */

if (GetOpenFileName(&ofn)) {

    /*

     * If the user checked the Backup File Check box,

     * create a backup file.

     */

    if (fBackup) {

        /* Open the requested file. */

        hf = CreateFile(ofn.lpstrFile, GENERIC_READ,

             0, (LPSECURITY_ATTRIBUTES) NULL,

             OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,

             (HANDLE) NULL);

        /* Process the extension (if it exists). */

        if (ofn.nFileExtension) {

            for(i = 0; i < (int)ofn.nFileExtension;

                i++)

                szChar[i] = *ofn.lpstrFile++;

        } /* end if */

        else {

            i = 0;

            while (*ofn.lpstrFile != '\0')

                szChar[i++] = *ofn.lpstrFile++;

            szChar[i] = '.';

        } /* end else */

        /* Create the backup filename string. */

        pszBackupFile = lstrcat(szChar, "BAK");

        /* Create the backup file. */

        hfBackup = CreateFile(pszBackupFile, GENERIC_WRITE,

            0, (LPSECURITY_ATTRIBUTES) NULL,

            CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,

            (HANDLE) NULL);

        /*

         * Copy the contents of the original file

         * to the new file.

         */

        ReadFile(hf, szBuffer, 256, &cBufLen,

            NULL);

        while (cBufLen == 256) {

            WriteFile(hfBackup, szBuffer, 256, &cBufLen,

                NULL);

            ReadFile(hf, szBuffer, 256, &cBufLen, NULL);

        }

        WriteFile(hfBackup, szBuffer, cBufLen, &cTmp,

            NULL);

        /* Close the files. */

        CloseHandle(hfBackup);

        CloseHandle(hf);

    } /* end if */

} /* end if */


Supporting Help for Common Dialog Boxes

An application can display a Help button in any of the common dialog boxes by specifying the appropriate flag in the Flags member of the structure for a specific common dialog box. Following are the structures for the common dialog boxes and the Help flag that corresponds to each structure.

Structure	Flag
OPENFILENAME	OFN_SHOWHELP
CHOOSECOLOR	CC_SHOWHELP
FINDREPLACE	FR_SHOWHELP
CHOOSEFONT	CF_SHOWHELP
PRINTDLG	PD_SHOWHELP
If an application displays the Help button, it must process the user's request for help. The processing can be done either in one of the application's window procedures or in a hook function.

If the application processes the request for help in one of the application's window procedures, it must first create a new message identifier for the string defined by the HELPMSGSTRING value. The application creates the new message identifier by calling the RegisterWindowMessage function and passing this value as the single parameter. (For more information about processing registered window messages, see "Displaying the Find Dialog Box" earlier in this chapter.) In addition to creating a new message identifier, the application must use the hwndOwner member of the appropriate structure for the common dialog box, so this member contains the handle of the dialog box's owner window. After the message identifier is created and the hwndOwner member is specified, the dialog box procedure notifies the window procedure of the owner window whenever the user chooses the Help button.

The following example processes a user's request for help in the window procedure of its owner window. The if statement should be in the default section of the switch statement that processes messages.

MyHelpMsg = RegisterWindowMessage(HELPMSGSTRING);

.

.

.

if (message == MyHelpMsg)

    WinHelp(hWnd, "appfile.hlp", HELP_CONTEXT, ID_MY_CONTEXT);

If the application processes the request for help in a hook function, it should test for the following condition in the WM_COMMAND message.

wParam == pshHelp

When this condition is true, the hook function should call the WinHelp function, as shown in the preceding example. (To process the request for help in a hook function, you must include the DLGS.H header file in the source file that contains the hook-function code.)


Error Detection

Whenever a common dialog box function fails, an application can call the CommDlgExtendedError function to find out the cause of the failure. This function returns an error value that identifies the cause of the most recent error.

Six values are defined in the CDERR.H header file that identify the ranges of error values for categories of errors returned by CommDlgExtendedError. Following are these values in ascending order by value range.

Value	Meaning
CDERR_GENERALCODES	General error codes for common dialog boxes. These errors are in the range 0x0000 through 0x0FFF.
PDERR_PRINTERCODES	Error codes for the Print common dialog box. These errors are in the range 0x1000 through 0x1FFF.
CFERR_CHOOSEFONTCODES	Error codes for the Font common dialog box. These errors are in the range 0x2000 through 0x2FFF.
FNERR_FILENAMECODES	Error codes for the Open and Save As common dialog boxes. These errors are in the range 0x3000 through 0x3FFF.
FRERR_FINDREPLACECODES	Error codes for the Find and Replace common dialog boxes. These errors are in the range 0x4000 through 0x4FFF.
CCERR_CHOOSECOLORCODES	Error codes for the Color common dialog box. These errors are in the range 0x5000 through 0x5FFF.


Common Dialog Box Reference

The following functions, structures, and messages are associated with common dialog boxes in Windows NT.


Common Dialog Box Functions

Following are the functions used with common dialog boxes.

ChooseColor
ChooseFont
CommDlgExtendedError
FindText
GetFileTitle
GetOpenFileName
GetSaveFileName
PageSetupDlg
PrintDlg
ReplaceText


Common Dialog Box Structures

Following are the structures used with common dialog boxes.

OFNOTIFY
PAGESETUPDLG


Common Dialog Box Messages

Following are the messages used with common dialog boxes.

CDM_GETFILEPATH
CDM_GETFOLDERIDLIST
CDM_GETFOLDERPATH
CDM_GETSPEC
CDM_HIDECONTROL
CDM_SETCONTROLTEXT
CDM_SETDEFEXT
CDN_FILEOK
CDN_FOLDERCHANGE
CDN_HELP
CDN_INITDONE
CDN_SELCHANGE
CDN_SHAREVIOLATION
CDN_TYPECHANGE
COLOROKSTRING
FILEOKSTRING
FINDMSGSTRING
LBSELCHSTRING
SETRGBSTRING
SHAREVISTRING
WM_CHOOSEFONT_SETFLAGS
WM_CHOOSEFONT_SETLOGFONT
WM_PSD_ENVSTAMPRECT
WM_PSD_FULLPAGERECT
WM_PSD_GREEKTEXTRECT
WM_PSD_MARGINRECT
WM_PSD_MINMARGINRECT
WM_PSD_PAGESETUPDLG
WM_PSD_YAFULLPAGERECT


Cursors

A cursor is a small picture whose location on the screen is controlled by a pointing device, such as a mouse, pen, or trackball. (In the remainder of this section, the term mouse refers to any pointing device.) When the user moves the mouse, Microsoft® Windows® moves the cursor accordingly. Microsoft Win32® cursor functions enable applications to create, load, display, move, confine, and destroy cursors.


About Cursors

Windows provides a set of standard cursors that are available for any application to use at any time. The Windows header files contain identifiers for the standard cursors — the identifiers begin with the "IDC_" prefix.

Each standard cursor has a corresponding default image associated with it. The user or an application can replace the default image associated with any standard cursor at any time. An application replaces a default image by using the SetSystemCursor function.

An application can use the GetIconInfo function to retrieve the current image for a cursor, and can draw the cursor by using the DrawIconEx function. To draw the default image for a standard cursor, specify the DI_COMPAT flag in the call to DrawIconEx. If you do not specify the DI_COMPAT flag, DrawIconEx draws the standard cursor using the image that the user specified.

Custom cursors are designed for use in a specific application and can be any design the developer defines. The following illustration shows several custom cursors.

Cursors can be either monochrome or color, and either static or animated. The type of cursor used on a particular computer system depends on the system's display. Old displays such as VGA do not support color or animated cursors, but new displays (whose display drivers use the DIB engine) do support them.

Cursors and icons are similar and can be used interchangeably in many situations. The only difference between them is that an image specified as a cursor must be in the format that the display can support. For example, a cursor must be monochrome for a VGA display.


The Hot Spot

In the cursor, a pixel called the hot spot marks the exact screen location that is affected by a mouse event, such as clicking a mouse button. Typically, the hot spot is the focal point of the cursor. The system tracks and recognizes this point as the position of the cursor. For example, typical hot spots are the pixel at the tip of an arrow-shaped cursor and the pixel in the middle of a crosshair-shaped cursor.

When a mouse input event occurs, the Windows mouse driver translates the event into an appropriate mouse message that includes the coordinates of the hot spot. Windows sends the mouse message to the window that contains the hot spot or to the window that is capturing mouse input. For more information about mouse input, see Mouse Input.


The Mouse and the Cursor

If the system includes a mouse, Windows reflects the movement of the mouse by moving the cursor on the screen accordingly. As the cursor moves over different parts of windows or into different windows, Windows (or an application) changes the appearance of the cursor. For example, when the cursor crosses a window border, Windows changes the cursor into a two-headed arrow.

If the system does not have a mouse, Windows displays and moves the cursor only when the user chooses certain system commands, such as those used to size or move a window. To provide the user with a method of displaying and moving the cursor when a mouse isn't available, an application can use the cursor functions to simulate mouse movement. Given this simulation capability, the user can use the arrow keys to move the cursor.


Cursor Creation

Because standard cursors are predefined, it is not necessary to create them. To use a standard cursor, an application retrieves a cursor handle by using the LoadCursor or LoadImage function. A cursor handle is a unique value of the HCURSOR type that identifies a standard or custom cursor.

To create a custom cursor for an application, developers typically use a graphics application and include the cursor as a resource in the application's resource-definition file. At run time, an application calls LoadCursor to retrieve the cursor handle. Cursor resources contain data for several different display devices. LoadCursor automatically selects the most appropriate data for the current display device.

An application can also create a custom cursor at run time by using the CreateIconIndirect function, which creates a cursor based on the content of an ICONINFO structure. The GetIconInfo function fills this structure with hot spot coordinates and information concerning the associated bitmask and color.

Applications should implement custom cursors as resources and use LoadCursor or LoadImage rather than create the cursor at run time. Using cursor resources avoids device dependence, simplifies localization, and enables applications to share cursor designs.

The CreateIconFromResourceEx function enables an application to create icons and cursors based on resource data. CreateIconFromResourceEx creates a cursor based on binary resource data from other executable (.EXE) files or dynamic-link libraries (DLLs). It must be preceded by calls to the LookupIconIdFromDirectoryEx function, as well as several resource functions. LookupIconIdFromDirectoryEx identifies the most appropriate cursor data for the current display device. For more information about resource functions, see Resources.


Cursor Location and Appearance

If the system includes a mouse, Windows automatically displays a cursor and updates its position on the screen. Applications can obtain current screen coordinates of the cursor; applications move the cursor to any location on the screen by using the GetCursorPos and SetCursorPos functions, respectively.

Applications can also retrieve the handle of the current cursor by using the GetCursor function and can set the cursor by using the SetCursor function. After an application uses SetCursor, the appearance of the cursor does not change until the mouse moves, until the cursor is explicitly set to a different cursor, or until a system command is executed.

When the user moves the mouse, the system redraws the cursor at the new location as designated by the mouse. The system automatically redraws the cursor design associated with the window to which the cursor is pointing.

Applications can hide and redisplay the cursor, without changing the cursor design, by using the ShowCursor function. This function uses an internal counter to determine when to hide or display the cursor. An attempt to show the cursor increments the counter; an attempt to hide the cursor decrements the counter. The cursor is visible only if this counter is greater than or equal to zero.


The Window Class Cursor

When registering a window class, an application can assign it a default cursor, known as the class cursor. After the application registers the window class, each window of that class will have the specified class cursor.

To override the class cursor, an application can process the WM_SETCURSOR message. Applications can also replace a class cursor by using the SetClassLong function. This function changes the default window settings for all windows of a given class. For more information about window classes, see Window Classes.


Cursor Confinement

Applications can confine the cursor to a rectangular area on the screen by using the ClipCursor function. This can be useful when the user must respond to a certain event within the confined area of the rectangle. For example, an application might use ClipCursor to confine the cursor to a modal dialog box, preventing the user from interacting with other windows until the dialog box is closed.

The GetClipCursor function retrieves the screen coordinates of the rectangular area to which the cursor is temporarily confined. When it is necessary to confine the cursor, the application can also use this function to save the coordinates of the original area in which the cursor can move. Then, the application can restore the cursor to the original area when the new confinement is no longer necessary.


Cursor Destruction

When an application no longer needs a cursor it created by using the CreateIconIndirect function, it should destroy the cursor. The DestroyCursor function destroys the cursor handle and frees any memory that it used. Applications should use this function only on cursors that were created with CreateIconIndirect; it is not necessary to destroy other cursors.

The DestroyCursor function has no effect on a shared cursor; that is, a cursor that was loaded by using the LR_SHARED flag with the LoadImage function. A shared cursor is valid as long as the module from which it was loaded remains in memory.


Cursor Duplication

The CopyCursor function copies a cursor handle. This enables an application or DLL to retrieve the handle of a cursor owned by another module. Then, if the other module is freed, the application that copied the cursor will still be able to use the cursor design.

For information on how to add, remove, or replace cursor resources in executable files, see Resources.


Using Cursors

•	Creating a cursor

•	Displaying a cursor

•	Confining a cursor

•	Using cursor functions to create a mousetrap

•	Using the keyboard to move the cursor


Creating a Cursor

The following example creates two cursor handles: one for the standard hourglass cursor and one for a custom cursor included as a resource in the application's resource-definition file.

HINSTANCE hinst;            /* handle of current instance */

HCURSOR hCurs1, hCurs2;     /* cursor handles             */

/* Create a standard hourglass cursor. */

hCurs1 = LoadCursor(NULL, IDC_WAIT);

/* Create a custom cursor based on a resource. */

hCurs2 = LoadCursor(hinst, MAKEINTRESOURCE(240));

An application should implement custom cursors as resources. Rather than create the cursors at run time, use the LoadCursor or LoadImage function to avoid device dependence, to simplify localization, and to enable applications to share cursor designs.

The following example uses the CreateCursor function to create a custom cursor at run time. The example is included here to illustrate how the system interprets cursor bitmasks. Even though this example uses the CreateCursor function, you should use the CreateIconIndirect function instead because it is more efficient.

HINSTANCE hinst;            /* handle of current instance */

HCURSOR hCurs1, hCurs2;     /* cursor handles             */

HCURSOR hCurs3;             /* cursor handle              */

/* Yin cursor AND bitmask */

BYTE ANDmaskCursor[] = {

    0xFF, 0xFC, 0x3F, 0xFF,   /* line 1  */

    0xFF, 0xC0, 0x1F, 0xFF,   /* line 2  */

    0xFF, 0x00, 0x3F, 0xFF,   /* line 3  */

    0xFE, 0x00, 0xFF, 0xFF,   /* line 4  */

    0xF7, 0x01, 0xFF, 0xFF,   /* line 5  */

    0xF0, 0x03, 0xFF, 0xFF,   /* line 6  */

    0xF0, 0x03, 0xFF, 0xFF,   /* line 7  */

    0xE0, 0x07, 0xFF, 0xFF,   /* line 8  */

    0xC0, 0x07, 0xFF, 0xFF,   /* line 9  */

    0xC0, 0x0F, 0xFF, 0xFF,   /* line 10 */

    0x80, 0x0F, 0xFF, 0xFF,   /* line 11 */

    0x80, 0x0F, 0xFF, 0xFF,   /* line 12 */

    0x80, 0x07, 0xFF, 0xFF,   /* line 13 */

    0x00, 0x07, 0xFF, 0xFF,   /* line 14 */

    0x00, 0x03, 0xFF, 0xFF,   /* line 15 */

    0x00, 0x00, 0xFF, 0xFF,   /* line 16 */

    0x00, 0x00, 0x7F, 0xFF,   /* line 17 */

    0x00, 0x00, 0x1F, 0xFF,   /* line 18 */

    0x00, 0x00, 0x0F, 0xFF,   /* line 19 */

    0x80, 0x00, 0x0F, 0xFF,   /* line 20 */

    0x80, 0x00, 0x07, 0xFF,   /* line 21 */

    0x80, 0x00, 0x07, 0xFF,   /* line 22 */

    0xC0, 0x00, 0x07, 0xFF,   /* line 23 */

    0xC0, 0x00, 0x0F, 0xFF,   /* line 24 */

    0xE0, 0x00, 0x0F, 0xFF,   /* line 25 */

    0xF0, 0x00, 0x1F, 0xFF,   /* line 26 */

    0xF0, 0x00, 0x1F, 0xFF,   /* line 27 */

    0xF8, 0x00, 0x3F, 0xFF,   /* line 28 */

    0xFE, 0x00, 0x7F, 0xFF,   /* line 29 */

    0xFF, 0x00, 0xFF, 0xFF,   /* line 30 */

    0xFF, 0xC3, 0xFF, 0xFF,   /* line 31 */

    0xFF, 0xFF, 0xFF, 0xFF};  /* line 32 */

/* Yin cursor XOR bitmask */

BYTE XORmaskCursor[] = {

    0x00, 0x00, 0x00, 0x00,   /* line 1  */

    0x00, 0x03, 0xC0, 0x00,   /* line 2  */

    0x00, 0x3F, 0x00, 0x00,   /* line 3  */

    0x00, 0xFE, 0x00, 0x00,   /* line 4  */

    0x0E, 0xFC, 0x00, 0x00,   /* line 5  */

    0x07, 0xF8, 0x00, 0x00,   /* line 6  */

    0x07, 0xF8, 0x00, 0x00,   /* line 7  */

    0x0F, 0xF0, 0x00, 0x00,   /* line 8  */

    0x1F, 0xF0, 0x00, 0x00,   /* line 9  */

    0x1F, 0xE0, 0x00, 0x00,   /* line 10 */

    0x3F, 0xE0, 0x00, 0x00,   /* line 11 */

    0x3F, 0xE0, 0x00, 0x00,   /* line 12 */

    0x3F, 0xF0, 0x00, 0x00,   /* line 13 */

    0x7F, 0xF0, 0x00, 0x00,   /* line 14 */

    0x7F, 0xF8, 0x00, 0x00,   /* line 15 */

    0x7F, 0xFC, 0x00, 0x00,   /* line 16 */

    0x7F, 0xFF, 0x00, 0x00,   /* line 17 */

    0x7F, 0xFF, 0x80, 0x00,   /* line 18 */

    0x7F, 0xFF, 0xE0, 0x00,   /* line 19 */

    0x3F, 0xFF, 0xE0, 0x00,   /* line 20 */

    0x3F, 0xC7, 0xF0, 0x00,   /* line 21 */

    0x3F, 0x83, 0xF0, 0x00,   /* line 22 */

    0x1F, 0x83, 0xF0, 0x00,   /* line 23 */

    0x1F, 0x83, 0xE0, 0x00,   /* line 24 */

    0x0F, 0xC7, 0xE0, 0x00,   /* line 25 */

    0x07, 0xFF, 0xC0, 0x00,   /* line 26 */

    0x07, 0xFF, 0xC0, 0x00,   /* line 27 */

    0x01, 0xFF, 0x80, 0x00,   /* line 28 */

    0x00, 0xFF, 0x00, 0x00,   /* line 29 */

    0x00, 0x3C, 0x00, 0x00,   /* line 30 */

    0x00, 0x00, 0x00, 0x00,   /* line 31 */

    0x00, 0x00, 0x00, 0x00};  /* line 32 */

/* Create a custom cursor at run time. */

hCurs3 = CreateCursor(hinst,  /* app instance */

             19,     /* horiz pos of hot spot */

             2,      /* vert pos of hot spot  */

             32,     /* cursor width          */

             32,     /* cursor height         */

             ANDmaskCursor,    /* AND bitmask */

             XORmaskCursor);   /* XOR bitmask */

To create the cursor, CreateCursor applies the following truth table to the AND and XOR bitmasks.

AND bitmask	XOR bitmask	Display
0	0	Black
0	1	White
1	0	Screen
1	1	Reverse screen
For more information about bitmaps, see Bitmaps.

Before closing, your application must use the DestroyCursor function to destroy any cursors it created with CreateCursor. It is not necessary to destroy cursors created by other functions.


Displaying a Cursor

If the system includes a mouse, Windows automatically displays the class cursor (the cursor associated with the window to which the cursor is pointing). Your application can assign a class cursor while registering a window class. The following example illustrates this by assigning a cursor handle to the hCursor member of the WNDCLASS structure identified by the wc parameter.

WNDCLASS  wc;

/*

 * Fill the window class structure with parameters that

 * describe the main window.

 */

wc.style = NULL;                      /* class style(s)   */

wc.lpfnWndProc = (WNDPROC) MainWndProc; /* window proc.   */

wc.cbClsExtra = 0;           /* no per-class extra data   */

wc.cbWndExtra = 0;           /* no per-window extra data  */

wc.hInstance = hinstance;    /* app that owns the class   */

wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); /* class icon */

wc.hCursor = LoadCursor(hinstance, MAKEINTRESOURCE(230));

                                          /* class cursor */

wc.hbrBackground = GetStockObject(WHITE_BRUSH);

                                      /* class background */

wc.lpszMenuName =  "GenericMenu";           /* class menu */

wc.lpszClassName = "GenericWClass"          /* class name */

/* Register the window class. */

return RegisterClass(&wc);

When the window class is registered, the cursor identified by 230 in the application's resource-definition file will be the default cursor for all windows based on the class.

Your application can change the design of the cursor by using the SetCursor function and specifying a different cursor handle. However, when the cursor moves, Windows redraws the class cursor at the new location. To prevent the class cursor from being redrawn, your application must process the WM_SETCURSOR message. Each time the cursor moves and mouse input is not captured, Windows sends this message to the window in which the cursor is moving.

You can specify different cursors for different conditions while processing WM_SETCURSOR. For example, the following example shows how to display the hCurs3 cursor whenever the cursor moves over the icon of a minimized application.

case WM_SETCURSOR:

    /*

     * If the window is minimized, draw the hCurs3 cursor.

     * If the window is not minimized, draw the default

     * cursor (class cursor).

     */

    if (IsIconic(hwnd)) {

        SetCursor(hCurs3);

        break;

    }

When the window is not minimized, Windows displays the class cursor.

Your application can replace a class cursor by using the SetClassLong function. This function changes the default window settings for all windows of a given class. The following example replaces the existing class cursor with the hCurs2 cursor.

/* Change the cursor for hwnd's window class. */

SetClassLong(hwnd,    /* window handle */

    GCL_HCURSOR,      /* change cursor */

    (LONG) hCurs2);   /* new cursor    */

For more information about window classes and mouse input, see Window Classes and Mouse Input.


Confining a Cursor

The following example confines the cursor to the application's window and then restores the cursor to its previous window. The example uses the GetClipCursor function to record the area in which the cursor can move and the ClipCursor function to confine and restore the cursor.

RECT rcClip;           /* new ClipCursor area      */

RECT rcOldClip;        /* previous ClipCursor area */

/* Record the area in which the cursor can move. */

GetClipCursor(&rcOldClip);

/* Get the dimensions of the application's window. */

GetWindowRect(hwnd, &rcClip);

/* Confine the cursor to the application's window. */

ClipCursor(&rcClip);

    .

    .  /* Process input from the confined cursor. */

    .

/* Restore the cursor to its previous area. */

ClipCursor(&rcOldClip);

Because there is only one cursor at a time available in the system, an application that confines the cursor must restore the cursor before relinquishing control to another window.


Using Cursor Functions to Create a Mousetrap

The following example uses the SetCursorPos, GetCursorPos, CreateCursor, LoadCursor, and SetCursor functions to create a simple mousetrap. It also uses cursor and timer functions to monitor the cursor's position every 10 seconds. If the cursor position has not changed in the last 10 seconds and the application's main window is minimized, the application changes the cursor and moves it to the mousetrap icon.

An example for a similar mousetrap is included in Icons. It uses the LoadCursor and LoadIcon functions instead of the more device-dependent CreateCursor and CreateIcon functions.

HICON hIcon1;               /* icon handles             */

POINT ptOld;                /* previous cursor location */

HCURSOR hCurs1;             /* cursor handle            */

/*

 * The following cursor bitmasks are defined in a code

 * example that appears earlier in this topic.

 */

/* Yin cursor AND and XOR bitmasks */

BYTE ANDmaskCursor[] = ...

BYTE XORmaskCursor[] = ...

/* Yang icon AND bitmask */

BYTE ANDmaskIcon[] = {0xFF, 0xFF, 0xFF, 0xFF,  /* line 1  */

                      0xFF, 0xFF, 0xC3, 0xFF,  /* line 2  */

                      0xFF, 0xFF, 0x00, 0xFF,  /* line 3  */

                      0xFF, 0xFE, 0x00, 0x7F,  /* line 4  */

                      0xFF, 0xFC, 0x00, 0x1F,  /* line 5  */

                      0xFF, 0xF8, 0x00, 0x0F,  /* line 6  */

                      0xFF, 0xF8, 0x00, 0x0F,  /* line 7  */

                      0xFF, 0xF0, 0x00, 0x07,  /* line 8  */

                      0xFF, 0xF0, 0x00, 0x03,  /* line 9  */

                      0xFF, 0xE0, 0x00, 0x03,  /* line 10 */

                      0xFF, 0xE0, 0x00, 0x01,  /* line 11 */

                      0xFF, 0xE0, 0x00, 0x01,  /* line 12 */

                      0xFF, 0xF0, 0x00, 0x01,  /* line 13 */

                      0xFF, 0xF0, 0x00, 0x00,  /* line 14 */

                      0xFF, 0xF8, 0x00, 0x00,  /* line 15 */

                      0xFF, 0xFC, 0x00, 0x00,  /* line 16 */

                      0xFF, 0xFF, 0x00, 0x00,  /* line 17 */

                      0xFF, 0xFF, 0x80, 0x00,  /* line 18 */

                      0xFF, 0xFF, 0xE0, 0x00,  /* line 19 */

                      0xFF, 0xFF, 0xE0, 0x01,  /* line 20 */

                      0xFF, 0xFF, 0xF0, 0x01,  /* line 21 */

                      0xFF, 0xFF, 0xF0, 0x01,  /* line 22 */

                      0xFF, 0xFF, 0xF0, 0x03,  /* line 23 */

                      0xFF, 0xFF, 0xE0, 0x03,  /* line 24 */

                      0xFF, 0xFF, 0xE0, 0x07,  /* line 25 */

                      0xFF, 0xFF, 0xC0, 0x0F,  /* line 26 */

                      0xFF, 0xFF, 0xC0, 0x0F,  /* line 27 */

                      0xFF, 0xFF, 0x80, 0x1F,  /* line 28 */

                      0xFF, 0xFF, 0x00, 0x7F,  /* line 29 */

                      0xFF, 0xFC, 0x00, 0xFF,  /* line 30 */

                      0xFF, 0xF8, 0x03, 0xFF,  /* line 31 */

                      0xFF, 0xFC, 0x3F, 0xFF}; /* line 32 */

/* Yang icon XOR bitmask */

BYTE XORmaskIcon[] = {0x00, 0x00, 0x00, 0x00,  /* line 1  */

                      0x00, 0x00, 0x00, 0x00,  /* line 2  */

                      0x00, 0x00, 0x00, 0x00,  /* line 3  */

                      0x00, 0x00, 0x00, 0x00,  /* line 4  */

                      0x00, 0x00, 0x00, 0x00,  /* line 5  */

                      0x00, 0x00, 0x00, 0x00,  /* line 6  */

                      0x00, 0x00, 0x00, 0x00,  /* line 7  */

                      0x00, 0x00, 0x38, 0x00,  /* line 8  */

                      0x00, 0x00, 0x7C, 0x00,  /* line 9  */

                      0x00, 0x00, 0x7C, 0x00,  /* line 10 */

                      0x00, 0x00, 0x7C, 0x00,  /* line 11 */

                      0x00, 0x00, 0x38, 0x00,  /* line 12 */

                      0x00, 0x00, 0x00, 0x00,  /* line 13 */

                      0x00, 0x00, 0x00, 0x00,  /* line 14 */

                      0x00, 0x00, 0x00, 0x00,  /* line 15 */

                      0x00, 0x00, 0x00, 0x00,  /* line 16 */

                      0x00, 0x00, 0x00, 0x00,  /* line 17 */

                      0x00, 0x00, 0x00, 0x00,  /* line 18 */

                      0x00, 0x00, 0x00, 0x00,  /* line 19 */

                      0x00, 0x00, 0x00, 0x00,  /* line 20 */

                      0x00, 0x00, 0x00, 0x00,  /* line 21 */

                      0x00, 0x00, 0x00, 0x00,  /* line 22 */

                      0x00, 0x00, 0x00, 0x00,  /* line 23 */

                      0x00, 0x00, 0x00, 0x00,  /* line 24 */

                      0x00, 0x00, 0x00, 0x00,  /* line 25 */

                      0x00, 0x00, 0x00, 0x00,  /* line 26 */

                      0x00, 0x00, 0x00, 0x00,  /* line 27 */

                      0x00, 0x00, 0x00, 0x00,  /* line 28 */

                      0x00, 0x00, 0x00, 0x00,  /* line 29 */

                      0x00, 0x00, 0x00, 0x00,  /* line 30 */

                      0x00, 0x00, 0x00, 0x00,  /* line 31 */

                      0x00, 0x00, 0x00, 0x00}; /* line 32 */

hIcon1 = CreateIcon(hinstance, /* handle of app instance  */

             32,           /* icon width                  */

             32,           /* icon height                 */

             1,            /* number of XOR planes        */

             1,            /* number of bits per pixel    */

             ANDmaskIcon,  /* AND bitmask                 */

             XORmaskIcon); /* XOR bitmask                 */

hCurs1 = CreateCursor(hinstance, /* handle of app inst.   */

             19,         /* horiz. position of hot spot   */

             2,          /* vert. position of hot spot    */

             32,         /* cursor width                  */

             32,         /* cursor height                 */

             ANDmaskCursor,            /* AND bitmask     */

             XORmaskCursor);           /* XOR bitmask     */

.

. /* Fill in the window class structure. */

.

WNDCLASS  wc;

wc.hIcon = hIcon1;                        /* class icon   */

wc.hCursor = LoadCursor(NULL, IDC_ARROW); /* class cursor */

.

. /*

.  * Register the window class and perform

.  * other application initialization.

.  */

.

/* Set a timer for the mousetrap. */

GetCursorPos(&ptOld);

SetTimer(hwnd, IDT_CURSOR, 10000, (TIMERPROC) NULL);

LONG APIENTRY MainWndProc(

    HWND hwnd,          /* window handle          */

    UINT message,       /* type of message        */

    UINT wParam,        /* additional information */

    LONG lParam)        /* additional information */

{

    HDC hdc;              /* handle of device context */

    POINT pt;             /* current cursor location  */

    RECT rc;              /* iconized window location */

    switch (message) {

         .

         . /* Process other messages. */

         .

        case WM_TIMER:

            /*

             * If the window is minimized, compare the

             * current cursor position with the one 10

             * seconds before. If the cursor position has

             * not changed, move the cursor to the icon.

             */

            if (IsIconic(hwnd)) {

                GetCursorPos(&pt);

                if ((pt.x == ptOld.x) && (pt.y == ptOld.y)) {

                    GetWindowRect(hwnd, &rc);

                    SetCursorPos(rc.left + 20, rc.top + 4);

                    /*

                     * Note that the additional constants

                     * (20 and 4) are application-specific

                     * values to align the yin-shaped cursor

                     * and the yang-shaped icon.

                     */

                }

                else {

                    ptOld.x = pt.x;

                    ptOld.y = pt.y;

                }

            }

            return 0;

        case WM_SETCURSOR:

            /*

             * If the window is minimized, draw hCurs1.

             * If the window is not minimized, draw the

             * default * cursor (class cursor).

             */

            if (IsIconic(hwnd)) {

                SetCursor(hCurs1);

                break;

            }

        case WM_DESTROY:

            /* Destroy timer. */

            KillTimer(hwnd, IDT_CURSOR);

            PostQuitMessage(0);

            break;

                .

                . /* Process other messages. */

                .

    }             /* ends switch (message) */


Using the Keyboard to Move the Cursor

Because Windows does not require a mouse, an application should be able to simulate mouse actions with the keyboard. The following example shows how to achieve this, by using the GetCursorPos and SetCursorPos functions, and by processing input from the arrow keys.

HCURSOR hCurs1, hCurs2;    /* cursor handles          */

POINT pt;                  /* cursor location         */

RECT rc;                   /* client area coordinates */

static int repeat = 1;     /* repeat key counter      */

.

.   /* Other declarations and initialization. */

.

switch (message) {

.

. /* Process other messages. */

.

    case WM_KEYDOWN:

        if (wParam != VK_LEFT && wParam != VK_RIGHT &&

        wParam != VK_UP && wParam != VK_DOWN) {

            break;

        }

        GetCursorPos(&pt);

        /*

         *Convert screen coordinates to client

         * coordinates.

         */

        ScreenToClient(hwnd, &pt);

        switch (wParam) {

            /*

             * Move the cursor to reflect which

             * arrow keys are pressed.

             */

            case VK_LEFT:               /* left arrow */

                pt.x -= repeat;

                break;

            case VK_RIGHT:             /* right arrow */

                pt.x += repeat;

                break;

            case VK_UP:                   /* up arrow */

                pt.y -= repeat;

                break;

            case VK_DOWN:               /* down arrow */

                pt.y += repeat;

                break;

            default:

                return NULL;

        }

        repeat++;           /* increments repeat count */

        /* Keep the cursor in the client area. */

        GetClientRect(hwnd, &rc);

        if (pt.x >= rc.right) {

            pt.x = rc.right - 1;

        }

        else {

            if (pt.x < rc.left) {

                pt.x = rc.left;

            }

        }

        if (pt.y >= rc.bottom) {

            pt.y = rc.bottom - 1;

        }

        else {

            if (pt.y < rc.top) {

                pt.y = rc.top;

            }

        }

        /*

         * Convert client coordinates to screen

         *coordinates.

         */

        ClientToScreen(hwnd, &pt);

        SetCursorPos(pt.x, pt.y);

        break;

    case WM_KEYUP:

        repeat = 1;            /* clears repeat count */

        break;

        .

        .

        .

    }               /* ends switch (message) */


Cursor Reference

The following functions and messages are associated with cursors.


Cursor Functions

Following are the functions used with cursors.

ClipCursor
CopyCursor
CreateCursor
DestroyCursor
GetClipCursor
GetCursor
GetCursorPos
LoadCursor
LoadCursorFromFile
SetCursor
SetCursorPos
SetSystemCursor
ShowCursor


Cursor Messages

The following message is used with cursors.

WM_SETCURSOR


Extended Menus

A menu is one or more lists of application commands. Each command, which is represented by a text string or bitmap, is called a menu item. By using the mouse or the keyboard to choose a menu item, the user directs the application to perform the command associated with the menu item. When the user chooses a menu item, Microsoft® Windows® sends the application a command message that indicates which menu item the user chose.

This Windows 95 overview describes the extended menu functions and explains how to use them in a Win32-based application.


Menus and Extended Menus Platform Differences

The overviews for menus and extended menus in Windows 95 and Windows NT are substantially different. To accommodate these differences, the Windows 95 overview is first presented in its entirety, followed by the Windows NT version.


About Extended Menus

Windows 95 Overview
For more information, see the Windows NT overview About Menus.

This overview describes menus and explains how to use them in applications designed for the Microsoft Win32® application programming interface (API).

The extended menu functions described in this section supercede the menu functions described in Menus (Windows NT). However, the two sets of functions can be used interchangeably insofar as their capabilities overlap.


Menu Bars and Pop-up Menus

Windows 95 Overview
For more information, see the Windows NT overview Menu Bars and Pop-up Menus.

The menus in an application written for Windows are arranged hierarchically. A menu bar (sometimes called a top-level menu) resides at the uppermost level of the hierarchy; the lower levels consist of pop-up menus (also known as submenus).

The items in a menu bar represent the main categories of commands provided by an application. Selecting an item from the menu bar typically activates a pop-up menu whose items correspond to the commands in a given category. For example, a menu bar might contain a File menu item that, when the user selects it, activates a pop-up menu with such menu items as New, Open, Save, and so on.

Only an overlapped or pop-up window can contain a menu bar; a child window cannot contain one. If the window has a title bar, Windows positions the menu bar just below it. A menu bar is always visible. In contrast, a pop-up menu is not visible until the user selects a menu item that activates it. When the menu is displayed, it is attached to the title bar.

Every menu must have an owner window. Windows sends messages to a menu's owner window when the user selects the menu or chooses a command from the menu. These messages are described in Menu Messages.


Floating Pop-up Menus

Windows 95 Overview
For more information, see the Windows NT overview Floating Pop-up Menus.

Windows provides a special type of pop-up menu called a floating pop-up menu. A floating pop-up menu is not attached to the menu bar; it can appear anywhere on the screen. An application typically associates a floating pop-up menu with a portion of a window, such as the client area, or with a specific object, such as an icon. For this reason, floating pop-up menus are also called context menus.

A floating pop-up menu remains hidden until the user activates it, typically by clicking the right mouse button. The menu is usually displayed at the position of the caret or mouse cursor.


The System Menu

Windows 95 Overview
For more information, see the Windows NT overview The System Menu.

A System menu (also known as the Control menu) is a pop-up menu defined and managed almost exclusively by the operating system. It is represented by a small box containing a horizontal line that is displayed at the left end of the title bar. When the user clicks the box, Windows displays the System menu. Windows also displays the System menu when the user clicks the icon of a minimized application.

A System menu provides a standard set of menu items that the user can choose to change a window's size or position, close the application, or activate the Windows Task List. Items in a System menu can be added, deleted, and modified, but most applications just use the standard set of menu items. An overlapped, pop-up, or child window can have a System menu. It is uncommon for an overlapped or pop-up window not to include a System menu.

When the user chooses a command from a System menu, Windows sends a WM_SYSCOMMAND message to the menu's owner window. In most applications, the window procedure does not process messages from a System menu. Instead, it simply passes the messages to the DefWindowProc function for system-default processing of the message. If a command is added to a System menu, the window procedure must process the command.


Help Identifier

Associated with each menu bar and pop-up menu is a 32-bit help identifier. If the user presses the F1 key while the menu is active, this value is sent to the owner window as part of a WM_HELP message. For more information about help identifiers, see Help.


Menu Handles

Windows 95 Overview
For more information, see the Windows NT overview Menu Handles.

The system generates a unique handle for each menu. A menu handle is a value of the HMENU type. An application must specify a menu handle in many of the Windows menu functions. You receive the handle of a menu bar when you create the menu or load a menu resource. For more information about creating and loading menus, see Menu Creation.

To retrieve the handle of a menu that has been created or loaded, use the GetMenu or GetSubMenu function. GetMenu returns the handle of the menu bar assigned to the specified window. GetSubMenu returns the handle of the pop-up menu associated with a pop-up item (the GetMenuItemInfo function can also be used for this purpose.) The GetSystemMenu function retrieves the handle of a window's System menu.


Menu Items

Windows 95 Overview
For more information, see the Windows NT overview Menu Items.

Each menu contains one or more menu items. By choosing a menu item, a user can carry out a command or open a pop-up menu. The following sections introduce the various types of menu items and the ways in which an application can control a menu item's appearance and functionality.


Command Items and Pop-up Items

Choosing a menu item may either perform a command or open a pop-up menu. Menu items that perform commands are called command items; those that open pop-up menus are called pop-up items.

When the user chooses a command item, Windows sends a command message to the window that owns the menu. If the command item is on the System menu, Windows sends the WM_SYSCOMMAND message. Otherwise, it sends the WM_COMMAND message.

Associated with each pop-up item is the handle of a corresponding pop-up menu. When the user selects a pop-up item, Windows opens the pop-up menu. No command message is sent to the owner window. However, Windows sends a WM_INITMENUPOPUP message to the owner window before displaying the pop-up menu. You can get the handle of the pop-up menu associated with a pop-up item by using the GetSubMenu or GetMenuItemInfo function (the handle is NULL for command items).

A menu bar typically contains pop-up items, but it may also contain command items. A pop-up menu typically contains command items, but it may also contain pop-up items. By adding pop-up items to a pop-up menu, you can nest pop-up menus to an arbitrary depth. If you include a pop-up item in a pop-up menu, Windows automatically displays a small arrow to the right of the menu item text as a visual cue to the user that a pop-up menu has been nested.


Menu Item Identifier

Windows 95 Overview
For more information, see the Windows NT overview, Menu-Item Identifier.

Associated with each menu item is a 16-bit integer called an identifier. An application should assign a unique identifier to each menu item. When a command item is chosen, the item's identifier is sent to the owner window as part of a WM_COMMAND or WM_SYSCOMMAND message. You can also use an identifier to specify a menu item when you call many menu functions.

Pop-up items have identifiers just as command items do. However, Windows does not send a command message when a pop-up item is selected from a menu. Instead, Windows activates the pop-up menu associated with the menu item.

To retrieve the identifier of the menu item at a specified position, use the GetMenuItemID or GetMenuItemInfo function.


Menu Item Position

Windows 95 Overview
For more information, see the Windows NT overview, Menu-Item Position.

In addition to having a unique identifier, each menu item in a menu bar or pop-up menu has a unique position value. The leftmost item in a menu bar, or the topmost item in a pop-up menu, has position zero. The position value is incremented for subsequent menu items. Windows assigns a position value to all items in a menu, including separators. The following illustration shows the position values of items in a menu bar and a pop-up menu.

When calling a menu function that modifies or retrieves information about a specific menu item, you can specify the item using either its identifier or its position.


Default Menu Items

A pop-up menu may contain one default menu item. When the user opens a pop-up by double-clicking, Windows sends a command message to the menu's owner window and closes the menu as if the default item had been chosen. If there is no default command item, the pop-up menu remains open. To retrieve and set the default item for a pop-up menu, use the GetMenuDefaultItem and SetMenuDefaultItem functions.


Checked and Unchecked Menu Items

Windows 95 Overview
For more information, see the Windows NT overview Checked and Unchecked Menu Items.

A menu item can be either checked or unchecked. Windows displays a bitmap next to checked menu items to indicate their checked state. Windows does not display a bitmap next to unchecked items, unless an application-defined "unchecked" bitmap is specified. Only menu items in a pop-up menu can be checked; items in a menu bar cannot be checked.

Applications typically check or uncheck a menu item to indicate whether an option is in effect. For example, suppose an application has a toolbar that the user can show or hide using a Toolbar command. When the toolbar is hidden, the Toolbar menu item is unchecked. When the user chooses the command, the application checks the menu item and shows the toolbar. To retrieve and set the check state of a menu item, use the GetMenuItemInfo and SetMenuItemInfo functions.

Sometimes, a group of menu items corresponds to a set of mutually exclusive options. In this case, you can indicate the selected option by using a checked radio menu item (analogous to a radio button control). Checked radio items are displayed with a bullet bitmap instead of a check-mark bitmap. To check a menu item and make it a radio item, use the CheckMenuRadioItem function.

By default, Windows displays a check-mark or bullet bitmap next to checked menu items and no bitmap next to unchecked menu items. However, you can use the SetMenuItemBitmaps function to associate application-defined "checked" and "unchecked" bitmaps with a menu item. Windows then uses the specified bitmaps to indicate the menu item's checked or unchecked state.

Application-defined bitmaps associated with a menu item must be the same size as the default check-mark bitmap, the dimensions of which may vary depending on screen resolution. To retrieve the correct dimensions, use the GetMenuCheckMarkDimensions function. You can create multiple bitmap resources for different screen resolutions; create one bitmap resource and scale it, if necessary; or create a bitmap at run time and draw an image in it. The bitmaps may be either monochrome or color. However, because menu items are inverted when highlighted, the appearance of certain inverted color bitmaps may be undesirable.


Enabled, Disabled, and Grayed Menu Items

Windows 95 Overview
For more information, see the Windows NT overview Enabled, Disabled, and Grayed Menu Items.

A menu item can be enabled, disabled, or grayed. By default, a menu item is enabled. When the user chooses an enabled menu item, Windows sends a command message to the owner window or displays the corresponding pop-up menu, depending on whether the menu item is a command or a pop-up item.

When menu items are not available to the user, they should be disabled or grayed. Disabled and grayed menu items cannot be chosen. Typically, applications gray an unavailable menu item to provide a visual clue to the user that a command is not available; a disabled menu item does not provide this visual clue. A disabled item can serve as a heading for a group of related menu items. (For example, a disabled Save menu item can serve as a heading for a series of enabled command items, such as Save File, Save All, and Save As.) A grayed item can be used when an action is not appropriate. (For example, the Print command in the File menu can be grayed when the system does not have a printer installed.)

The EnableMenuItem function enables, disables, or grays a menu item. To determine whether a menu item is enabled, disabled, or grayed, use the GetMenuItemInfo function.


Highlighted Menu Items

Windows 95 Overview
For more information, see the Windows NT overview Highlighted Menu Items.

Windows automatically highlights menu items as the user selects them. However, highlighting can be explicitly added or removed from a menu item on the menu bar by using the HiliteMenuItem function. This function has no effect on menu items in pop-up menus. When HiliteMenuItem is used to highlight a menu item, though, the menu item only appears to be selected. If the user presses the ENTER key, the highlighted item is not chosen.


String, Bitmap, and Owner-Drawn Menu Items

An application can display a menu item using a string or a bitmap. In addition, an application can completely control the appearance of a menu item by using an owner-drawn item. The application is responsible for drawing owner-drawn items in any of their possible states (highlighted, checked, and so on).

For example, an application that has a Font menu might draw each menu item using the corresponding font (that is, the item for roman would be drawn using a roman font, the item for italic in an italic font, and so on).


Menu Item Separators and Line Breaks

Windows 95 Overview
For more information, see the Windows NT overview, Menu-Item Separators and Line Breaks.

Windows provides a special type of menu item, called a separator, that appears as a horizontal line. A separator can be used in a pop-up menu to divide a menu into groups of related items. A separator cannot be used in a menu bar, and the user cannot select a separator.

When a menu bar contains more items than will fit on one line, Windows automatically breaks the line into two or more lines. You can cause a line break to occur at a specific item on a menu bar by assigning the MFT_MENUBREAK type flag to the item. Windows places that item and all subsequent item on a new line.

When a pop-up menu contains more items than will fit in one column, Windows automatically breaks the menu into two or more columns. You can cause a column break to occur at a specific item in a pop-up menu by assigning the MFT_MENUBREAK type flag to the item. Windows places that item and all subsequent items in a new column. The MFT_MENUBARBREAK type flag has the same effect except that a vertical line appears between the new column and the old.


Keyboard Access to Menus

Windows 95 Overview
For more information, see the Windows NT overview Keyboard Access to Menus.

Windows provides a standard keyboard interface for menus. You can enhance this interface by providing mnemonics and accelerator keys for your menu items. The following sections describe the standard keyboard interface, mnemonics, and accelerator keys.


Standard Keyboard Interface

Windows 95 Overview
For more information, see the Windows NT overview Standard Keyboard Interface.

Windows is designed to work with or without a mouse or other pointing device. Because Windows provides a standard keyboard interface, the user can use the keyboard to select menu items. This keyboard interface does not need special code. An application receives a command message whether a menu item is selected through the keyboard or by using a mouse. The standard keyboard interface processes the following keystrokes.

Keystroke	Action
Alphabetic character	Selects the first menu item with the specified character as its mnemonic. If the selected item invokes a pop-up menu, the menu is displayed and the first item is highlighted. Otherwise, the menu item is chosen.
ALT	Toggles in and out of menu bar mode.
ALT+SPACEBAR	Displays the System menu.
ENTER	Activates a pop-up menu and selects the first menu item if an item has a pop-up menu associated with it. Otherwise, this keystroke chooses the item as if the user released the mouse button while the item was selected.
ESC	Exits menu mode.
LEFT ARROW	Works like the RIGHT ARROW key, except in the opposite direction. In pop-up menus, this keystroke backs up one column; when the currently selected item is in the far-left column, the previous pop-up menu is selected.
RIGHT ARROW	Cycles to the next top-level menu item. Top-level menu items include menu bar items and the System menu. If the selected item is in a pop-up menu, the next column in the pop-up menu is selected or the next top-level menu item is selected.
UP or DOWN ARROWS	Activates a pop-up menu when pressed in a top-level menu. When pressed in a pop-up menu, either keystroke selects the next or previous item.


Menu Mnemonics

Windows 95 Overview
For more information, see the Windows NT overview Menu Mnemonics.

The standard keyboard interface for menus can be enhanced by adding mnemonics to menu items. A mnemonic is an underlined letter in the text of a menu item. When a menu is active, the user can select a menu item by pressing the key that corresponds to the item's underlined letter. The menu bar is active when the user presses and releases the ALT key and the first item on the menu bar is highlighted. A pop-up menu is active when it is displayed.

A mnemonic keystroke for a menu item is created by preceding any character in the item's text string with an ampersand. For example, the text string "&Move" causes Windows to underline the letter "M".


Menu Keyboard Accelerators

Windows 95 Overview
For more information, see the Windows NT overview Menu Keyboard Accelerators.

In addition to having a mnemonic, a menu item can have a keyboard accelerator associated with it. A keyboard accelerator is different from a mnemonic, because the menu does not have to be active for the accelerator key to work. Also, a mnemonic is always associated with a menu item, while a keyboard accelerator is usually (but does not have to be) associated with a menu item.

Text that identifies the keyboard accelerator is added to the menu item text string. The accelerator text appears to the right of the menu item name, after a backslash and tab character (\t). For example, "&Close\tAlt+F4" represents a Close item with the ALT+F4 key combination as its keyboard accelerator and with the letter "C" as its mnemonic. For more information about accelerators, see Keyboard Accelerators.


Menu Creation

Windows 95 Overview
For more information, see the Windows NT overview Menu Creation.

You can create a menu using either a menu template or using menu creation functions. Menu templates are typically defined as resources. Menu template resources can be loaded explicitly or assigned as the default menu for a window class. You can also create menu template resources dynamically in memory.


Menu Template Resources

Windows 95 Overview
For more information, see the Windows NT overview, Menu-Template Resources.

Most applications create menus using menu template resources. A menu template defines a menu, including the items in the menu bar and all pop-up menus. For information about creating a menu template resource, see the documentation included with your development tools.

Once you have created a menu template resource and have added it to your application's executable (.EXE) file, you can use the LoadMenu function to load the resource into memory. This function returns the handle of the menu, which you can then assign to a window by using the SetMenu function.

Implementing menus as resources makes an application easier to localize for use in multiple countries. Only the resource-definition file needs to be translated for each language, not the application's source code.


Menu Template in Memory

Windows 95 Overview
For more information, see the Windows NT overview Menu Template in Memory.

A menu can be created from a menu template that is built in memory at run time. For example, an application that allows a user to customize its menu might create a menu template in memory based on the user's preferences. The application could then save the template in a file or in the registry for future use. To create a menu from a template in memory, use the LoadMenuIndirect function.

There are two types of menu templates. A standard menu template consists of a MENUITEMTEMPLATEHEADER structure followed by one or more MENUITEMTEMPLATE structures. In most cases, an extended menu template is used; it consists of a MENUEX_TEMPLATE_HEADER structure followed by one or more MENUEX_TEMPLATE_ITEM structures.


Menu Creation Functions

Windows 95 Overview
For more information, see the Windows NT overview, Menu-Creation Functions.

Using menu creation functions, you can create menus at run time or add menu items to existing menus. You can use the CreateMenu function to create an empty menu bar and the CreatePopupMenu function to create an empty pop-up menu. To add items to a menu, use the InsertMenuItem function.


Menu Display

Windows 95 Overview
For more information, see the Windows NT overview Menu Display.

After a menu has been loaded or created, it must be assigned to a window before Windows can display it. This assignment can be done by defining a class menu. For more information about class menus, see Class Menus. You can also assign a menu to a window by specifying the handle of the menu as the hmenu parameter of the CreateWindowEx function or by calling the SetMenu function.

To display a floating pop-up menu, use the TrackPopupMenu or TrackPopupMenuEx function. Floating pop-up menus, also called context menus, are typically displayed when the WM_CONTEXTMENU message is processed.


Class Menus

Windows 95 Overview
For more information, see the Windows NT overview Class Menus.

You can specify a default menu, called a class menu, when you register a window class. To do so, you assign the name of the menu template resource to the lpszMenuName member of the WNDCLASS structure used to register the class.

By default, every window is assigned the class menu for its window class so that you do not have to explicitly load the menu and assign it to each window. You can override the class menu by specifying a different menu handle in a call to the CreateWindowEx function. You can also change a window's menu after it is created by using the SetMenu function. For more information about window classes, see Window Classes.


Menu Destruction

Windows 95 Overview
For more information, see the Windows NT overview Menu Destruction.

If a menu is assigned to a window and that window is destroyed, Windows automatically destroys the menu, freeing the menu's handle and the memory occupied by the menu. Windows does not automatically destroy a menu that is not assigned to a window. An application must destroy the unassigned menu by calling the DestroyMenu function. Otherwise, the menu continues to exist in memory even after the application closes.


Menu Messages

Windows 95 Overview
For more information, see the Windows NT overview Menu Messages Overview.

Windows reports menu-related activity by sending messages to the window procedure of the window that owns the menu. Windows sends a series of messages when the user selects items on the menu bar or clicks the right mouse button to display a floating pop-up menu.

When the user activates an item on the menu bar, the owner window first receives a WM_SYSCOMMAND message. This message includes a flag that indicates whether the user activated the menu using the keyboard (SC_KEYMENU) or mouse (SC_MOUSEMENU). For more information about the keyboard interface for menus, see Keyboard Access to Menus.

Next, before displaying any pop-up menus, Windows sends the WM_INITMENU message to the window procedure so that an application can modify the menus before the user sees them. Windows sends the WM_INITMENU message only once per menu activation.

When the user selects a pop-up item, Windows sends the owner window the WM_INITMENUPOPUP message before displaying the pop-up menu. This message gives the application an opportunity to modify the pop-up menu before it is displayed.

Each time the user moves the highlighting from one item to another, Windows sends a WM_MENUSELECT message to the window procedure of the menu's owner window. This message identifies the currently selected menu item. Many applications provide an information area at the bottom of their main windows and use this message to display additional information about the selected menu item.

When the user chooses a command item from a menu, Windows sends a WM_COMMAND message to the window procedure. The low-order word of the WM_COMMAND message's wParam parameter contains the identifier of the chosen item. The window procedure should examine the identifier and process the message accordingly.

Not all menus are accessed through a window's menu bar. Many applications display floating pop-up menus when the user clicks the right mouse button at a specific location. Such applications should process the WM_CONTEXTMENU message and display a floating pop-up menu, if appropriate. If an application does not display a floating pop-up menu, it should pass the WM_CONTEXTMENU message to the DefWindowProc function for default processing.


Menu Modifications

Windows 95 Overview
For more information, see the Windows NT overview Menu Modifications.

A number of functions enable the developer to change a menu after it has been loaded or created. These changes may include adding or removing menu items and modifying existing menu items.

To add a menu item, use the InsertMenuItem function. You can use the SetMenuItemInfo function to change the attributes of an existing menu item. The lpmii parameter points to a MENUITEMINFO structure, which contains the new attributes and specifies which attributes to change. A menu item's attributes include its type, state, identifier, pop-up menu, bitmaps, item data, and text.

To retrieve information about a menu item, use the GetMenuItemInfo function. The lpmii parameter points to a MENUITEMINFO structure, which specifies the attributes to retrieve and receives their current values.

The DeleteMenu or RemoveMenu function is used to delete a menu item from a menu. If the item being deleted is a pop-up item, DeleteMenu deletes the associated pop-up menu, discarding the menu handle and freeing the memory used by the pop-up menu. RemoveMenu deletes a menu item, but if the item activates a pop-up menu, the function does not destroy the pop-up menu or its handle, allowing the menu to be reused.

After a menu bar has been modified, the DrawMenuBar function must be called to redraw the menu bar. Otherwise, the modifications will not appear until Windows redraws the owner window.


Superseded Functions

The following menu functions have been superseded. The new function should be used instead of the corresponding superseded function.

Superseded function	New function
AppendMenu	InsertMenuItem
ChangeMenu	SetMenuItemInfo
CheckMenuItem	SetMenuItemInfo
GetMenuState	GetMenuItemInfo
InsertMenu	InsertMenuItem
ModifyMenu	SetMenuItemInfo


Using Extended Menus

•	Using a menu template resource.

•	Creating a floating pop-up menu.

•	Using menu item bitmaps.

•	Creating owner-drawn menu items.

•	Using custom check mark bitmaps.


Using a Menu Template Resource

Windows 95 Overview
For more information, see the Windows NT overview, Using a Menu-Template Resource.

You typically include a menu in an application by creating a menu template resource and then loading the menu at run time. This section explains how to load a menu template resource and use it in your application. For information about creating a menu template resource, see the documentation included with your development tools.


Loading a Menu Template Resource

Windows 95 Overview
For more information, see the Windows NT overview, Loading a Menu-Template Resource.

You can load a menu template resource by calling the LoadMenu function, specifying the handle of the module that contains the resource and the menu template's identifier. LoadMenu returns a menu handle that you can use to assign the menu to a window. This window becomes the menu's owner window, receiving all the messages generated by the menu.

You can assign a menu to a window by using the SetMenu function or by specifying the menu's handle in the hmenu parameter of the CreateWindowEx function when creating a window. Another way that you can assign a menu to a window is to specify a menu template when you register a window class; the template identifies the menu as the class menu for the given window class. Whenever you create a window of the given class, Windows automatically assigns the given menu to the window.

You can create a class menu by including the identifier of the menu template resource as the lpszMenuName member of a WNDCLASS structure and then passing the address of the structure to the RegisterClass function.


Creating a Class Menu

Windows 95 Overview
For more information, see the Windows NT overview Creating a Class Menu.

The following example shows how to create a class menu for an application, create a window that uses the class menu, and process menu commands in the window procedure.

HINSTANCE hinst;

int APIENTRY WinMain(hinstance, hPrevInstance, lpCmdLine, nCmdShow)

HINSTANCE hinstance;

HINSTANCE hPrevInstance;

LPSTR lpCmdLine;

int nCmdShow;

{

    MSG msg;        // message

    WNDCLASS wc;    // windowclass data

    HWND hwnd;      // handle of main window

    // Create the window class for the main window. Specify

    // the identifier of the menu-template resource as the

    // lpszMenuName member of the WNDCLASS structure to create

    // the class menu.

    wc.style = 0;

    wc.lpfnWndProc = (WNDPROC) MainWndProc;

    wc.cbClsExtra = 0;

    wc.cbWndExtra = 0;

    wc.hInstance = hinstance;

    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);

    wc.hCursor = LoadCursor(NULL, IDC_ARROW);

    wc.hbrBackground = GetStockObject(WHITE_BRUSH);

    wc.lpszMenuName =  "MyMenuResource";

    wc.lpszClassName = "MainWClass";

    if (!RegisterClass(&wc))

        return FALSE;

    hinst = hinstance;

    // Create the main window. Set the hmenu parameter to NULL so

    // that Windows uses the class menu for the window.

    hwnd = CreateWindow("MainWClass", "Sample Application",

        WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,

        CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hinstance,

        NULL);

    if (hwnd == NULL)

        return FALSE;

    // Make the window visible and send a WM_PAINT message to the

    // window procedure.

    ShowWindow(hwnd, nCmdShow);

    UpdateWindow(hwnd);

    // Start the main message loop.

    while (GetMessage(&msg, NULL, 0, 0)) {

        TranslateMessage(&msg);

        DispatchMessage(&msg);

    }

    return msg.wParam;

        UNREFERENCED_PARAMETER(hPrevInstance);

}

LRESULT APIENTRY MainWndProc(hwnd, uMsg, wParam, lParam)

HWND hwnd;

UINT uMsg;

WPARAM wParam;

LPARAM lParam;

{

    switch (uMsg) {

        .

        . // Process other window messages.

        .

        case WM_COMMAND:

            // Test for the identifier of a command item.

            switch(LOWORD(wParam)) {

                case IDM_FI_OPEN:

                    DoFileOpen();   // application-defined

                    break;

                case IDM_FI_CLOSE:

                    DoFileClose();  // application-defined

                    break;

                .

                . // Process other menu commands.

                .

                default:

                    break;

            }

            return 0;

        .

        . // Process other window messages.

        .

        default:

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

    }

    return NULL;

}


Creating a Floating Pop-up Menu

Windows 95 Overview
For more information, see the Windows NT overview Creating a Floating Pop-up Menu.

To use a floating pop-up menu in an application, pass the handle of a pop-up menu to the TrackPopupMenu or TrackPopupMenuEx function. An application typically calls these functions in a window procedure when processing the WM_CONTEXTMENU message. For more information about this message, see Processing the WM_CONTEXTMENU Message.

In addition to the pop-up menu handle, TrackPopupMenu requires that you specify the handle of the owner window, the position of the floating pop-up menu (in screen coordinates), and the mouse button that the user can use to choose an item. TrackPopupMenuEx requires the same parameters as TrackPopupMenu, but TrackPopupMenuEx also enables you to specify a portion of the screen that the menu should not obscure.

You can specify the position of a menu by providing x- and y-coordinates along with the TPM_CENTERALIGN, TPM_LEFTALIGN, or TPM_RIGHTALIGN flag. The flag specifies the position of the menu relative to the x- and y-coordinates.

You should permit the user to choose an item from a pop-up menu by using the same mouse button used to display the menu. To do this, specify either TPM_LEFTBUTTON or TPM_RIGHTBUTTON flag to indicate which mouse button the user can use to choose a menu item.


Processing the WM_CONTEXTMENU Message

The WM_CONTEXTMENU message is generated when an application's window procedure passes the WM_RBUTTONUP or WM_NCRBUTTONUP message to the DefWindowProc function. The application can process this message to display a floating pop-up menu appropriate to a specific portion of its display. If the application does not display a menu, it should pass the message to DefWindowProc for default handling.

Following is an example of WM_CONTEXTMENU message processing as it might appear in an application's window procedure. The low-order and high-order words of the lParam parameter specify the screen coordinates of the mouse when the right mouse button is released. The application-defined OnContextMenu function returns TRUE if it displays a context menu or FALSE if it does not.

case WM_CONTEXTMENU:

    if (!OnContextMenu(hwnd, LOWORD(lParam), HIWORD(lParam)))

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

    break;

The following application-defined OnContextMenu function displays a floating pop-up menu if the specified mouse position is within the window's client area. A more sophisticated function might display one of several different menus depending on which portion of the client area is specified. To actually display the floating pop-up menu, this example calls an application-defined function called DisplayContextMenu. For a description of this function, see Displaying a Floating Pop-up Menu.

BOOL WINAPI OnContextMenu(HWND hwnd, int x, int y)

{

    RECT rc;                    // client area of window

    POINT pt = { x, y };        // location of mouse click

    // Get the bounding rectangle of the client area.

    GetClientRect(hwnd, &rc);

    // Convert the mouse position to client coordinates.

    ScreenToClient(hwnd, &pt);

    // If the position is in the client area, display a floating

    // pop-up menu.

    if (PtInRect(&rc, pt)) {

        ClientToScreen(hwnd, &pt);

        DisplayContextMenu(hwnd, pt);

        return TRUE;

    }

    // Return FALSE if no menu is displayed.

    return FALSE;

}


Displaying a Floating Pop-up Menu

The function shown in the following example displays a floating pop-up menu. This function might be called when an application's window procedure receives a WM_CONTEXTMENU message.

The application includes a menu resource identified by the string "PopupMenu". The top-level menu, or menu bar, simply contains a pop-up menu item. The application uses the TrackPopupMenu function to display the pop-up menu associated with this menu item. (The top-level menu itself is not displayed because TrackPopupMenu requires the handle of a pop-up menu.)

VOID APIENTRY DisplayContextMenu(HWND hwnd, POINT pt)

{

    HMENU hmenu;            // top-level menu

    HMENU hmenuTrackPopup;  // pop-up menu

    // Load the menu resource.

    if ((hmenu = LoadMenu(hinst, "PopupMenu")) == NULL)

        return;

    // TrackPopupMenu cannot display the top-level menu, so get

    // the handle of the first pop-up menu.

    hmenuTrackPopup = GetSubMenu(hmenu, 0);

    // Display the floating pop-up menu. Track the right mouse

    // button on the assumption that this function is called

    // during WM_CONTEXTMENU processing.

    TrackPopupMenu(hmenuTrackPopup,

            TPM_LEFTALIGN | TPM_RIGHTBUTTON,

            pt.x, pt.y, 0, hwnd, NULL);

    // Destroy the menu.

    DestroyMenu(hmenu);

}


Using Menu Item Bitmaps

Windows 95 Overview
For more information, see the Windows NT overview, Using Menu-Item Bitmaps.

Windows can use a bitmap instead of a text string to display a menu item. To use a bitmap, you must set the MF_BITMAP flag for the menu item and specify the handle of the bitmap that Windows should display for the menu item. This section describes how to set the MF_BITMAP flag and retrieve the handle of a bitmap.


Setting the MFT_BITMAP Type Flag

The MFT_BITMAP type flag tells Windows to use a bitmap rather than a text string to display a menu item. A menu item's MFT_BITMAP flag must be set at run time; it cannot be set in a menu-template resource.

You can use the SetMenuItemInfo or InsertMenuItem function to set the MFT_BITMAP type flag. To change a menu item from a text item to a bitmap item, use SetMenuItemInfo. To add a new bitmap item to a menu, use the InsertMenuItem function.


Creating the Bitmap

Windows 95 Overview
For more information, see the Windows NT overview Creating the Bitmap.

When you set the MFT_BITMAP type flag for a menu item, you must also specify the handle of the bitmap that Windows should display for the menu item. You can provide the bitmap as a bitmap resource or create the bitmap at run time. If you use a bitmap resource, you can use the LoadBitmap function to load the bitmap and obtain its handle.

To create the bitmap at run time, use graphics device interface (GDI) functions. GDI provides several ways to create a bitmap at run time, but developers typically use the following method:

1.	Use the CreateCompatibleDC function to create a device context compatible with the device context used by the application's main window.

2.	Use the CreateCompatibleBitmap function to create a bitmap compatible with the application's main window or use the CreateBitmap function to create a monochrome bitmap.

3.	Use the SelectObject function to select the bitmap into the compatible device context.

4.	Use GDI drawing functions, such as Ellipse and LineTo, to draw an image into the bitmap.

For more information about bitmaps, see Bitmaps.


Example of Menu Item Bitmaps

The example in this section creates two pop-up menus, each containing several bitmap menu items. For each pop-up menu, the application adds a corresponding pop-up item to the main window's menu bar.

The first pop-up menu contains menu items showing each of three chart types: pie, line, and bar. The bitmaps for these menu items are defined as resources and are loaded by using the LoadBitmap function. Associated with this menu is a "Chart" pop-up item on the menu bar.

The second pop-up menu contains menu items showing each of the five line styles used with the CreatePen function: PS_SOLID, PS_DASH, PS_DOT, PS_DASHDOT, and PS_DASHDOTDOT. The application creates the bitmaps for these menu items at run time using GDI drawing functions. Associated with this menu is a "Lines" pop-up item on the menu bar.

Defined in the application's window procedure are two static arrays of bitmap handles. One array contains the handles of the three bitmaps used for the Chart menu. The other contains the handles of the five bitmaps used for the Lines menu. When processing the WM_CREATE message, the window procedure loads the chart bitmaps, creates the line bitmaps, and then adds the corresponding menu items. When processing the WM_DESTROY message, the window procedure deletes all of the bitmaps.

Following are the relevant portions of the application's header file.

// Menu item identifiers

#define IDM_PIE         1

#define IDM_LINE        2

#define IDM_BAR         3

#define IDM_SOLID       4

#define IDM_DASH        5

#define IDM_DASHDOT     6

#define IDM_DASHDOTDOT  7

// Number of items on the Chart and Lines menus

#define C_LINES         5

#define C_CHARTS        3

// Bitmap resource identifiers

#define IDB_PIE         1

#define IDB_LINE        2

#define IDB_BAR         3

// Dimensions of the line bitmaps

#define CX_LINEBMP      40

#define CY_LINEBMP      10

Following are the relevant portions of the window procedure. The window procedure performs most of its initialization by calling the application-defined LoadChartBitmaps, CreateLineBitmaps, and AddBitmapMenu functions, described later in this section.

LRESULT CALLBACK MainWindowProc(

        HWND hwnd,

        UINT uMsg,

        WPARAM wParam,

        LPARAM lParam

        )

{

    static HBITMAP aHbmLines[C_LINES];

    static HBITMAP aHbmChart[C_CHARTS];

    int i;

    switch (uMsg) {

        case WM_CREATE:

             // Call application-defined functions to load the

             // bitmaps for the chart menu and create those for

             // the lines menu.

            LoadChartBitmaps(aHbmChart);

            CreateLineBitmaps(aHbmLines);

             // Call an application-defined function to create pop-up

             // menus containing the bitmap menu items. The function

             // also adds a pop-up item to the window's menu bar.

            AddBitmapMenu(

                    hwnd,      // menu bar's owner window

                    "&Chart",  // text of pop-up item on menu bar

                    IDM_PIE,   // ID of first item on pop-up menu

                    aHbmChart, // array of bitmap handles

                    C_CHARTS   // number of items on pop-up menu

                    );

            AddBitmapMenu(hwnd, "&Lines", IDM_SOLID,

                    aHbmLines, C_LINES);

            break;

        case WM_DESTROY:

            for (i = 0; i < C_LINES; i++)

                DeleteObject(aHbmLines[i]);

            for (i = 0; i < C_CHARTS; i++)

                DeleteObject(aHbmChart[i]);

            PostQuitMessage(0);

            break;

        .

        .  // Process additional messages here.

        .

        default:

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

    }

    return 0;

}

The application-defined LoadChartBitmaps function loads the bitmap resources for the chart menu by calling the LoadBitmap function, as follows.

VOID WINAPI LoadChartBitmaps(HBITMAP *paHbm)

{

    paHbm[0] = LoadBitmap(g_hinst, MAKEINTRESOURCE(IDB_PIE));

    paHbm[1] = LoadBitmap(g_hinst, MAKEINTRESOURCE(IDB_LINE));

    paHbm[2] = LoadBitmap(g_hinst, MAKEINTRESOURCE(IDB_BAR));

}

The application-defined CreateLineBitmaps function creates the bitmaps for the Lines menu by using GDI drawing functions. The function creates a memory DC with the same properties as the desktop window's DC. For each line style, the function creates a bitmap, selects it into the memory DC, and draws in it.

VOID WINAPI CreateLineBitmaps(HBITMAP *paHbm)

{

    HWND hwndDesktop = GetDesktopWindow();

    HDC hdcDesktop = GetDC(hwndDesktop);

    HDC hdcMem = CreateCompatibleDC(hdcDesktop);

    COLORREF clrMenu = GetSysColor(COLOR_MENU);

    HBRUSH hbrOld;

    HPEN hpenOld;

    HBITMAP hbmOld;

    int fnDrawMode;

    int i;

     // Create a brush using the menu background color,

     // and select it into the memory DC.

    hbrOld = SelectObject(hdcMem, CreateSolidBrush(clrMenu));

     // Create the bitmaps. Select each one into the memory

     // DC that was created and draw in it.

    for (i = 0; i < C_LINES; i++) {

        // Create the bitmap and select it into the DC.

        paHbm[i] = CreateCompatibleBitmap(hdcDesktop,

                CX_LINEBMP, CY_LINEBMP);

        hbmOld = SelectObject(hdcMem, paHbm[i]);

        // Fill the background using the brush.

        PatBlt(hdcMem, 0, 0, CX_LINEBMP, CY_LINEBMP, PATCOPY);

        // Create the pen and select it into the DC.

        hpenOld = SelectObject(hdcMem,

                CreatePen(PS_SOLID + i, 1, RGB(0, 0, 0)));

         // Draw the line. To preserve the background color where

         // the pen is white use the R2_MASKPEN drawing mode.

        fnDrawMode = SetROP2(hdcMem, R2_MASKPEN);

        MoveToEx(hdcMem, 0, CY_LINEBMP / 2, NULL);

        LineTo(hdcMem, CX_LINEBMP, CY_LINEBMP / 2);

        SetROP2(hdcMem, fnDrawMode);

        // Delete the pen, and select the old pen and bitmap.

        DeleteObject(SelectObject(hdcMem, hpenOld));

        SelectObject(hdcMem, hbmOld);

    }

    // Delete the brush and select the original brush.

    DeleteObject(SelectObject(hdcMem, hbrOld));

    // Delete the memory DC and release the desktop DC.

    DeleteDC(hdcMem);

    ReleaseDC(hwndDesktop, hdcDesktop);

}

The application-defined AddBitmapMenu function creates a pop-up menu and adds the specified number of bitmap menu items to it. Then it adds a corresponding pop-up item to the specified window's menu bar.

VOID WINAPI AddBitmapMenu(

        HWND hwnd,          // window that owned the menu bar

        LPSTR lpszText,     // text of pop-up item on menu bar

        UINT uID,           // ID of first bitmap menu item

        HBITMAP *paHbm,     // bitmaps for the menu items

        int cItems)         // number bitmap menu items

{

    HMENU hmenuBar = GetMenu(hwnd);

    HMENU hmenuPopup = CreatePopupMenu();

    MENUITEMINFO mii;

    int i;

    // Add the bitmap menu items to the pop-up menu.

    for (i = 0; i < cItems; i++) {

        mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_DATA;

        mii.fType = MFT_BITMAP;

        mii.wID = uID + i;

        mii.dwTypeData = (LPSTR) (paHbm[i]);

        InsertMenuItem(hmenuPopup, i, TRUE, &mii);

    }

    // Add a pop-up item to the menu bar.

    mii.fMask = MIIM_TYPE | MIIM_DATA | MIIM_SUBMENU;

    mii.fType = MFT_STRING;

    mii.hSubMenu = hmenuPopup;

    mii.dwTypeData = lpszText;

    InsertMenuItem(hmenuBar,

        GetMenuItemCount(hmenuBar), TRUE, &mii);

}


Creating Owner-Drawn Menu Items

If you need complete control over the appearance of a menu item, you can use an owner-drawn menu item in your application. This section describes the steps involved in creating and using an owner-drawn menu item.


Setting the MFT_OWNERDRAW Flag

You cannot define an owner-drawn menu item in your application's resource-definition file. Instead, you must create a new menu item or modify an existing one, so it has the MFT_OWNERDRAW type flag.

You can use the InsertMenuItem or SetMenuItemInfo function to specify an owner-drawn menu item. To place a new item on a menu, moving the other items down, use InsertMenuItem. To change the content of a menu, use SetMenuItemInfo.

When calling these two functions, you must specify the address of a MENUITEMINFO structure, giving the properties of the new menu item or the properties you want to change for an existing menu item. To make an item an owner-drawn item, specify the MIIM_TYPE value for the fMask member and the MFT_OWNERDRAW value for the fType member.

By setting the appropriate members of the MENUITEMINFO structure, you can associate an application-defined value, which is called item data, with each menu item. To do so, specify the MIIM_DATA value for the fMask member and the application-defined value for the dwItemData member.

You can use item data with any type of menu item, but it is particularly useful for owner-drawn items. For example, suppose a structure contains information used to draw a menu item. An application might use the item data for a menu item to store a pointer to the structure. The item data is sent to the menu's owner window with the WM_MEASUREITEM and WM_DRAWITEM messages. To retrieve the item data for a menu at any time, use the GetMenuItemInfo function.


Owner-Drawn Menus and the WM_MEASUREITEM Message

Before Windows displays an owner-drawn menu item for the first time, it sends the WM_MEASUREITEM message to the window procedure of the window that owns the item's menu. This message contains a pointer to a MEASUREITEMSTRUCT structure that identifies the item and contains the item data that an application may have assigned to it. The window procedure must fill the itemWidth and itemHeight members of the structure before returning from processing the message. Windows uses the information in these members when creating the bounding rectangle in which an application draws the menu item. It also uses the information to detect when the user chooses the item.


Owner-Drawn Menus and the WM_DRAWITEM Message

Whenever the item must be drawn (for example, when it is first displayed or when the user selects it), Windows sends the WM_DRAWITEM message to the window procedure of the menu's owner window. This message contains a pointer to a DRAWITEMSTRUCT structure, which contains information about the item, including the item data that an application may have assigned to it. In addition, DRAWITEMSTRUCT contains flags that indicate the state of the item (such as whether it is grayed or checked) as well as a bounding rectangle and a DC that the application uses to draw the item.

An application must do the following while processing the WM_DRAWITEM message:

1.	Determine the type of drawing that is necessary. To do so, check the itemAction member of the DRAWITEMSTRUCT structure.

2.	Draw the menu item appropriately, using the bounding rectangle and DC obtained from the DRAWITEMSTRUCT structure. The application must draw only within the bounding rectangle. For performance reasons, Windows does not clip portions of the image that are drawn outside the rectangle.

3.	Restore all GDI objects selected for the menu item's DC.

If the user selects the menu item, Windows sets the itemAction member of the DRAWITEMSTRUCT structure to the ODA_SELECT value and sets the ODS_SELECTED value in the itemState member. This is an application's cue to redraw the menu item to indicate that it is selected.


Example of Owner-Drawn Menu Items

The example in this section uses owner-drawn menu items in a pop-up menu. The menu items select specific font attributes, and the application displays each menu item using a font that has the corresponding attribute. For example, the Italic menu item is displayed in an italic font. The Character pop-up item on the menu bar opens the pop-up menu.

The menu bar and pop-up menu are defined initially by an extended menu-template resource. Because a menu template cannot specify owner-drawn items, the pop-up menu initially contains four text menu items with the following strings: "Regular," "Bold," "Italic," and "Underline." The application's window procedure changes these to owner-drawn items when it processes the WM_CREATE message. When it receives the WM_CREATE message, the window procedure calls the application-defined OnCreate function, which performs the following steps for each menu item:

1.	Allocates an application-defined MYITEM structure.

2.	Gets the text of the menu item and saves it in the application-defined MYITEM structure.

3.	Creates the font used to display the menu item and saves its handle in the application-defined MYITEM structure.

4.	Changes the menu item type to MFT_OWNERDRAW and saves a pointer to the application-defined MYITEM structure as item data.

Because a pointer to each application-defined MYITEM structure is saved as item data, it is passed to the window procedure in conjunction with the WM_MEASUREITEM and WM_DRAWITEM messages for the corresponding menu item. The pointer is contained in the itemData member of both the MEASUREITEMSTRUCT and DRAWITEMSTRUCT structures.

A WM_MEASUREITEM message is sent for each owner-drawn menu item the first time that it is displayed. The application processes this message by selecting the font for the menu item into a DC and then determining the space required to display the menu item text in that font. The font and menu item text are both specified by the menu item's MYITEM structure (the structure defined by the application). The application determines the size of the text by using the GetTextExtentPoint function.

The window procedure processes the WM_DRAWITEM message by displaying the menu item text in the appropriate font. The font and menu item text are both specified by the menu item's MYITEM structure. The application selects text and background colors appropriate to the menu item's state.

The window procedure processes the WM_DESTROY message to destroy fonts and free memory. The application deletes the font and frees the application-defined MYITEM structure for each menu item.

Following are the relevant portions of the application's header file.

// Menu item identifiers for the Character menu

#define IDM_CHARACTER 10

#define IDM_REGULAR   11

#define IDM_BOLD      12

#define IDM_ITALIC    13

#define IDM_UNDERLINE 14

// Structure associated with menu items

typedef struct tagMYITEM {

    HFONT hfont;

    int   cchItemText;

    char  szItemText[1];

} MYITEM;

#define CCH_MAXITEMTEXT 256

Following are the relevant portions of the application's window procedure and its associated functions.

LRESULT CALLBACK MainWindowProc(

        HWND hwnd,

        UINT uMsg,

        WPARAM wParam,

        LPARAM lParam

        )

{

    switch (uMsg) {

        case WM_CREATE:

            if (!OnCreate(hwnd))

                return -1;

            break;

        case WM_DESTROY:

            OnDestroy(hwnd);

            PostQuitMessage(0);

            break;

        case WM_MEASUREITEM:

            OnMeasureItem(hwnd, (LPMEASUREITEMSTRUCT) lParam);

            return TRUE;

        case WM_DRAWITEM:

            OnDrawItem(hwnd, (LPDRAWITEMSTRUCT) lParam);

            return TRUE;

        .

        . // Additional message processing goes here.

        .

        default:

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

    }

    return 0;

}

BOOL WINAPI OnCreate(HWND hwnd)

{

    HMENU hmenuBar = GetMenu(hwnd);

    HMENU hmenuPopup;

    MENUITEMINFO mii;

    UINT uID;

    MYITEM *pMyItem;

    // Get the handle of the pop-up menu.

    mii.fMask = MIIM_SUBMENU;     // information to get

    GetMenuItemInfo(hmenuBar, IDM_CHARACTER, FALSE, &mii);

    hmenuPopup = mii.hSubMenu;

    // Modify each menu item. Assume that the IDs IDM_REGULAR

    // through IDM_UNDERLINE are consecutive numbers.

    for (uID = IDM_REGULAR; uID <= IDM_UNDERLINE; uID++) {

         // Allocate an item structure, leaving space for a

         // string of up to CCH_MAXITEMTEXT characters.

        pMyItem = (MYITEM *) LocalAlloc(LMEM_FIXED,

                sizeof(MYITEM) + CCH_MAXITEMTEXT);

        // Save the item text in the item structure.

        mii.fMask = MIIM_TYPE;

        mii.dwTypeData = pMyItem->szItemText;

        mii.cch = CCH_MAXITEMTEXT;

        GetMenuItemInfo(hmenuPopup, uID, FALSE, &mii);

        pMyItem->cchItemText = mii.cch;

        // Reallocate the structure to the minimum required size.

        pMyItem = (MYITEM *) LocalReAlloc(pMyItem,

                sizeof(MYITEM) + mii.cch, LMEM_MOVEABLE);

        // Create the font used to draw the item.

        pMyItem->hfont = CreateMenuItemFont(uID);

        // Change the item to an owner-drawn item, and save

        // the address of the item structure as item data.

        mii.fMask = MIIM_TYPE | MIIM_DATA;

        mii.fType = MFT_OWNERDRAW;

        mii.dwItemData = (DWORD) pMyItem;

        SetMenuItemInfo(hmenuPopup, uID, FALSE, &mii);

    }

    return TRUE;

}

HFONT CreateMenuItemFont(UINT uID)

{

    LOGFONT lf;

    ZeroMemory(&lf, sizeof(lf));

    lf.lfHeight = 20;

    lstrcpy(lf.lfFaceName, "Times New Roman");

    switch (uID) {

        case IDM_BOLD:

            lf.lfWeight = FW_HEAVY;

            break;

        case IDM_ITALIC:

            lf.lfItalic = TRUE;

            break;

        case IDM_UNDERLINE:

            lf.lfUnderline = TRUE;

            break;

    }

    return CreateFontIndirect(&lf);

}

VOID WINAPI OnDestroy(HWND hwnd)

{

    HMENU hmenuBar = GetMenu(hwnd);

    HMENU hmenuPopup;

    MENUITEMINFO mii;

    UINT uID;

    MYITEM *pMyItem;

    // Get the handle of the pop-up menu.

    mii.fMask = MIIM_SUBMENU;     /* information to get */

    GetMenuItemInfo(hmenuBar, IDM_CHARACTER, FALSE, &mii);

    hmenuPopup = mii.hSubMenu;

    // Free resources associated with each menu item.

    for (uID = IDM_REGULAR; uID <= IDM_UNDERLINE; uID++) {

        // Get the item data.

        mii.fMask = MIIM_DATA;

        GetMenuItemInfo(hmenuPopup, uID, FALSE, &mii);

        pMyItem = (MYITEM *) mii.dwItemData;

        // Destroy the font and free the item structure.

        DeleteObject(pMyItem->hfont);

        LocalFree(pMyItem);

    }

}

VOID WINAPI OnMeasureItem(HWND hwnd, LPMEASUREITEMSTRUCT lpmis)

{

    MYITEM *pMyItem = (MYITEM *) lpmis->itemData;

    HDC hdc = GetDC(hwnd);

    HFONT hfntOld = SelectObject(hdc, pMyItem->hfont);

    SIZE size;

    GetTextExtentPoint(hdc, pMyItem->szItemText,

            pMyItem->cchItemText, &size);

    lpmis->itemWidth = size.cx;

    lpmis->itemHeight = size.cy;

    SelectObject(hdc, hfntOld);

    ReleaseDC(hwnd, hdc);

}

VOID WINAPI OnDrawItem(HWND hwnd, LPDRAWITEMSTRUCT lpdis)

{

    MYITEM *pMyItem = (MYITEM *) lpdis->itemData;

    COLORREF clrPrevText, clrPrevBkgnd;

    HFONT hfntPrev;

    int x, y;

    // Set the appropriate foreground and background colors.

    if (lpdis->itemState & ODS_SELECTED) {

        clrPrevText = SetTextColor(lpdis->hDC,

                GetSysColor(COLOR_HIGHLIGHTTEXT));

        clrPrevBkgnd = SetBkColor(lpdis->hDC,

                GetSysColor(COLOR_HIGHLIGHT));

    }

    else {

        clrPrevText = SetTextColor(lpdis->hDC,

                GetSysColor(COLOR_MENUTEXT));

        clrPrevBkgnd = SetBkColor(lpdis->hDC,

                GetSysColor(COLOR_MENU));

    }

    // Determine where to draw and leave space for a check mark.

    x = lpdis->rcItem.left;

    y = lpdis->rcItem.top;

    x += LOWORD(GetMenuCheckMarkDimensions());

    // Select the font and draw the text.

    hfntPrev = SelectObject(lpdis->hDC, pMyItem->hfont);

    ExtTextOut(lpdis->hDC, x, y, ETO_OPAQUE,

            &lpdis->rcItem, pMyItem->szItemText,

            pMyItem->cchItemText, NULL);

    // Restore the original font and colors.

    SelectObject(lpdis->hDC, hfntPrev);

    SetTextColor(lpdis->hDC, clrPrevText);

    SetBkColor(lpdis->hDC, clrPrevBkgnd);

}


Using Custom Check Mark Bitmaps

Windows 95 Overview
For more information, see the Windows NT overview Using Custom Check Mark Bitmaps.

Windows provides a default check mark bitmap for displaying next to a menu item that is checked. You can customize an individual menu item by providing a pair of bitmaps to replace the default check mark bitmap. Windows displays one bitmap when the item is checked and the other when it is unchecked. This section describes the steps involved in creating and using custom check mark bitmaps.


Creating Custom Check Mark Bitmaps

Windows 95 Overview
For more information, see the Windows NT overview Creating Custom Check Mark Bitmaps.

A custom check mark bitmap must be the same size as the default check mark bitmap. You can retrieve the default check mark size of the bitmap by calling the GetMenuCheckMarkDimensions function. The low-order word of this function's return value specifies the width; the high-order word specifies the height.

You can use bitmap resources to provide check mark bitmaps. However, because the required bitmap size varies depending on the display type, you may need to resize the bitmap at run time by using the StretchBlt function. Depending on the bitmap, the distortion caused by sizing could produce unacceptable results.

Instead of using a bitmap resource, you can create a bitmap at run time by using GDI functions. For the typical method, you follow these steps:

1.	Use the CreateCompatibleDC function to create a DC compatible with the DC used by the application's main window.

2.	Use the CreateCompatibleBitmap function to create a bitmap compatible with the application's main window, or use the CreateBitmap function to create a monochrome bitmap.

3.	Use the SelectObject function to select the bitmap into the compatible DC.

4.	Use GDI drawing functions, such as Ellipse and LineTo, to draw an image into the bitmap.


Associating Bitmaps with a Menu Item

Windows 95 Overview
For more information, see the Windows NT overview Associating Bitmaps with a Menu Item.

You associate a pair of check mark bitmaps with a menu item by passing the handles of the bitmaps to the SetMenuItemBitmaps function. The hbmUnchecked parameter identifies the unchecked bitmap, and the hbmChecked parameter identifies the checked bitmap. If you want to remove one or both check marks from a menu item, you can set the hbmUnchecked or hbmChecked parameter, or both, to NULL.


Setting the Check Mark Attribute

Windows 95 Overview Setting the Check Mark Attribute
For more information, see the Windows NT overview Setting the Check Mark Attribute.

The CheckMenuItem function sets a menu item's check mark attribute to either checked or unchecked. You can specify the MF_CHECKED value to set the check mark attribute to checked and the MF_UNCHECKED value to set it to unchecked. You can also set the check state of a menu item by using the SetMenuItemInfo function.

Sometimes a group of menu items represents a set of mutually exclusive options. By using the CheckMenuRadioItem function, you can check one menu item while simultaneously removing the check mark from all other menu items in the group.


Example of Using Custom Check Mark Bitmaps

The example in this section assigns custom check mark bitmaps to menu items in two pop-up menus. The menu items in the first pop-up menu specify character attributes: bold, italic, and underline. Each menu item can be either checked or unchecked. For these menu items, the example uses check mark bitmaps that resemble the checked and unchecked states of a check box control.

The menu items in the second pop-up menu specify paragraph alignment settings: left, centered, and right. Only one of these menu items is checked at any given time. For these menu items, the example uses check mark bitmaps that resemble the checked and unchecked states of a radio button control.

The window procedure processes the WM_CREATE message by calling the application-defined OnCreate function. The application-defined OnCreate function creates the four check mark bitmaps and then assigns them to their appropriate menu items by using the SetMenuItemBitmaps function.

To create each bitmap, the application-defined OnCreate function calls the application-defined CreateMenuBitmaps function, specifying a pointer to a bitmap-specific drawing function. The application-defined CreateMenuBitmaps function creates a monochrome bitmap of the required size, selects it into a memory DC, and erases the background. Then it calls the specified drawing function to fill in the foreground.

The four application-defined drawing functions are DrawCheck, DrawUncheck, DrawRadioCheck, and DrawRadioUncheck. They draw a rectangle with an X, an empty rectangle, an ellipse containing a smaller filled ellipse, and an empty ellipse, respectively.

The window procedure processes the WM_DESTROY message by deleting the check mark bitmaps. It retrieves each bitmap handle by using the GetMenuItemInfo function and then passes the handle to the DeleteObject function.

When the user chooses a menu item, a WM_COMMAND message is sent to the owner window. For menu items on the Character menu, the window procedure calls the application-defined CheckCharacterItem function. For items on the Paragraph menu, the window procedure calls the application-defined CheckParagraphItem function.

Each item on the Character menu can be checked and unchecked independently. Therefore, the application-defined CheckCharacterItem function simply toggles the specified menu item's check state. First, the function calls the GetMenuItemInfo function to get the current menu item state. Then it toggles the MFS_CHECKED state flag and sets the new state by calling the SetMenuItemInfo function.

Unlike character attributes, only one paragraph alignment can be selected at a time. Therefore, the application-defined CheckParagraphItem function checks the specified menu item and removes the check mark from all other items on the menu. To do so, it calls the CheckMenuRadioItem function.

Following are the relevant portions of the application's header file.

// Menu item identifiers for the Character menu

#define IDM_CHARACTER 10

#define IDM_BOLD      11

#define IDM_ITALIC    12

#define IDM_UNDERLINE 13

// Menu item identifiers for the Paragraph menu

#define IDM_PARAGRAPH 20

#define IDM_LEFT      21

#define IDM_CENTER    22

#define IDM_RIGHT     23

// Function-pointer type for drawing functions

typedef VOID (WINAPI * DRAWFUNC)(HDC hdc, SIZE size);

Following are the relevant portions of the application's window procedure and related functions.

LRESULT CALLBACK MainWindowProc(

        HWND hwnd,

        UINT uMsg,

        WPARAM wParam,

        LPARAM lParam

        )

{

    switch (uMsg) {

        case WM_CREATE:

            if (!OnCreate(hwnd))

                return -1;

            break;

        case WM_DESTROY:

            OnDestroy(hwnd);

            PostQuitMessage(0);

            break;

        case WM_COMMAND:

            switch (LOWORD(wParam)) {

                case IDM_BOLD:

                case IDM_ITALIC:

                case IDM_UNDERLINE:

                    CheckCharacterItem(hwnd, LOWORD(wParam));

                    break;

                case IDM_LEFT:

                case IDM_CENTER:

                case IDM_RIGHT:

                    CheckParagraphItem(hwnd, LOWORD(wParam));

                    break;

                .

                . // Process other commands here.

                .

            }

            break;

        .

        . // Process other messages here.

        .

        default:

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

    }

    return 0;

}

VOID WINAPI CheckCharacterItem(HWND hwnd, UINT uID)

{

    HMENU hmenuBar = GetMenu(hwnd);

    HMENU hmenuPopup;

    MENUITEMINFO mii;

    // Get the handle of the Character pop-up menu.

    mii.fMask = MIIM_SUBMENU;  // information to get

    GetMenuItemInfo(hmenuBar, IDM_CHARACTER, FALSE, &mii);

    hmenuPopup = mii.hSubMenu;

    // Get the state of the specified menu item.

    mii.fMask = MIIM_STATE;    // information to get

    GetMenuItemInfo(hmenuPopup, uID, FALSE, &mii);

    // Toggle the checked state.

    mii.fState ^= MFS_CHECKED;

    SetMenuItemInfo(hmenuPopup, uID, FALSE, &mii);

}

VOID WINAPI CheckParagraphItem(HWND hwnd, UINT uID)

{

    HMENU hmenuBar = GetMenu(hwnd);

    HMENU hmenuPopup;

    MENUITEMINFO mii;

    // Get the handle of the Paragraph pop-up menu.

    mii.fMask = MIIM_SUBMENU;  // information to get

    GetMenuItemInfo(hmenuBar, IDM_PARAGRAPH, FALSE, &mii);

    hmenuPopup = mii.hSubMenu;

    // Check the specified item and uncheck all the others.

    CheckMenuRadioItem(

            hmenuPopup,         // handle of pop-up menu

            IDM_LEFT,           // first item in range

            IDM_RIGHT,          // last item in range

            uID,                // item to check

            MF_BYCOMMAND        // IDs, not positions

            );

}

BOOL WINAPI OnCreate(HWND hwnd)

{

    HMENU hmenuBar = GetMenu(hwnd);

    HMENU hmenuPopup;

    MENUITEMINFO mii;

    UINT uID;

    HBITMAP hbmChecked;

    HBITMAP hbmUnchecked;

    // Get the handle of the Character pop-up menu.

    mii.fMask = MIIM_SUBMENU;     // information to get

    GetMenuItemInfo(hmenuBar, IDM_CHARACTER, FALSE, &mii);

    hmenuPopup = mii.hSubMenu;

    // Create the checked and unchecked bitmaps.

    hbmChecked = CreateMenuBitmap(DrawCheck);

    hbmUnchecked = CreateMenuBitmap(DrawUncheck);

    // Set the checkmark bitmaps for each menu item.

    for (uID = IDM_BOLD; uID <= IDM_UNDERLINE; uID++) {

        SetMenuItemBitmaps(hmenuPopup, uID, MF_BYCOMMAND,

                hbmUnchecked, hbmChecked);

    }

    // Get the handle of the Paragraph pop-up menu.

    mii.fMask = MIIM_SUBMENU;     // information to get

    GetMenuItemInfo(hmenuBar, IDM_PARAGRAPH, FALSE, &mii);

    hmenuPopup = mii.hSubMenu;

    // Create the checked and unchecked bitmaps.

    hbmChecked = CreateMenuBitmap(DrawRadioCheck);

    hbmUnchecked = CreateMenuBitmap(DrawRadioUncheck);

    // Set the checkmark bitmaps for each menu item.

    for (uID = IDM_LEFT; uID <= IDM_RIGHT; uID++) {

        SetMenuItemBitmaps(hmenuPopup, uID, MF_BYCOMMAND,

                hbmUnchecked, hbmChecked);

    }

    // Initially check the IDM_LEFT paragraph item.

    CheckMenuRadioItem(hmenuPopup, IDM_LEFT, IDM_RIGHT,

            IDM_LEFT, MF_BYCOMMAND);

    return TRUE;

}

HBITMAP WINAPI CreateMenuBitmap(DRAWFUNC lpfnDraw)

{

    // Create a DC compatible with the desktop window's DC.

    HWND hwndDesktop = GetDesktopWindow();

    HDC hdcDesktop = GetDC(hwndDesktop);

    HDC hdcMem = CreateCompatibleDC(hdcDesktop);

    // Determine the required bitmap size.

    DWORD dwExt = GetMenuCheckMarkDimensions();

    SIZE size = { LOWORD(dwExt), HIWORD(dwExt) };

    // Create a monochrome bitmap and select it.

    HBITMAP hbm = CreateBitmap(size.cx, size.cy, 1, 1, NULL);

    HBITMAP hbmOld = SelectObject(hdcMem, hbm);

    // Erase the background and call the drawing function.

    PatBlt(hdcMem, 0, 0, size.cx, size.cy, WHITENESS);

    (*lpfnDraw)(hdcMem, size);

    // Clean up.

    SelectObject(hdcMem, hbmOld);

    DeleteDC(hdcMem);

    ReleaseDC(hwndDesktop, hdcDesktop);

    return hbm;

}

VOID WINAPI DrawCheck(HDC hdc, SIZE size)

{

    HBRUSH hbrOld;

    hbrOld = SelectObject(hdc, GetStockObject(NULL_BRUSH));

    Rectangle(hdc, 0, 0, size.cx, size.cy);

    MoveToEx(hdc, 0, 0, NULL);

    LineTo(hdc, size.cx, size.cy);

    MoveToEx(hdc, 0, size.cy - 1, NULL);

    LineTo(hdc, size.cx - 1, 0);

    SelectObject(hdc, hbrOld);

}

VOID WINAPI DrawUncheck(HDC hdc, SIZE size)

{

    HBRUSH hbrOld;

    hbrOld = SelectObject(hdc, GetStockObject(NULL_BRUSH));

    Rectangle(hdc, 0, 0, size.cx, size.cy);

    SelectObject(hdc, hbrOld);

}

VOID WINAPI DrawRadioCheck(HDC hdc, SIZE size)

{

    HBRUSH hbrOld;

    hbrOld = SelectObject(hdc, GetStockObject(NULL_BRUSH));

    Ellipse(hdc, 0, 0, size.cx, size.cy);

    SelectObject(hdc, GetStockObject(BLACK_BRUSH));

    Ellipse(hdc, 2, 2, size.cx - 2, size.cy - 2);

    SelectObject(hdc, hbrOld);

}

VOID WINAPI DrawRadioUncheck(HDC hdc, SIZE size)

{

    HBRUSH hbrOld;

    hbrOld = SelectObject(hdc, GetStockObject(NULL_BRUSH));

    Ellipse(hdc, 0, 0, size.cx, size.cy);

    SelectObject(hdc, hbrOld);

}

VOID WINAPI OnDestroy(HWND hwnd)

{

    HMENU hmenuBar = GetMenu(hwnd);

    HMENU hmenuPopup;

    MENUITEMINFO mii;

    // Get the handle of the Character pop-up menu.

    mii.fMask = MIIM_SUBMENU;     // information to get

    GetMenuItemInfo(hmenuBar, IDM_CHARACTER, FALSE, &mii);

    hmenuPopup = mii.hSubMenu;

    // Get the check mark bitmaps and delete them.

    mii.fMask = MIIM_CHECKMARKS;

    GetMenuItemInfo(hmenuPopup, IDM_BOLD, FALSE, &mii);

    DeleteObject(mii.hbmpChecked);

    DeleteObject(mii.hbmpUnchecked);

    // Get the handle of the Paragraph pop-up menu.

    mii.fMask = MIIM_SUBMENU;     // information to get

    GetMenuItemInfo(hmenuBar, IDM_PARAGRAPH, FALSE, &mii);

    hmenuPopup = mii.hSubMenu;

    // Get the check mark bitmaps and delete them.

    mii.fMask = MIIM_CHECKMARKS;

    GetMenuItemInfo(hmenuPopup, IDM_LEFT, FALSE, &mii);

    DeleteObject(mii.hbmpChecked);

    DeleteObject(mii.hbmpUnchecked);

}


Extended Menu Reference

The functions, structures, and messages used with extended menus can be grouped as follows. Some of these application programming interface (API) elements are also used with menus.

Menu Handles

GetMenu
GetSubMenu
GetSystemMenu

Menu-Item Information

GetMenuItemID
GetMenuItemInfo
SetMenuItemInfo
MENUITEMINFO

Default Menu Items

GetMenuDefaultItem
SetMenuDefaultItem

Menu-Item States

CheckMenuRadioItem
EnableMenuItem
GetMenuCheckMarkDimensions
HiliteMenuItem
SetMenuItemBitmaps

Menu Templates

LoadMenu
LoadMenuIndirect
MENUITEMTEMPLATE
MENUITEMTEMPLATEHEADER
MENUEX_TEMPLATE_HEADER
MENUEX_TEMPLATE_ITEM

Menu Creation and Modification

CreateMenu
CreatePopupMenu
DeleteMenu
DestroyMenu
DrawMenuBar
InsertMenuItem
RemoveMenu

Menu Display

SetMenu
TrackPopupMenu
TrackPopupMenuEx
WM_CONTEXTMENU

Menu Messages

WM_COMMAND
WM_INITMENU
WM_INITMENUPOPUP
WM_MENUSELECT
WM_SYSCOMMAND


Extended Menu Functions

The following are the extended menu functions.

CheckMenuRadioItem
GetMenuDefaultItem
GetMenuItemInfo
GetMenuItemRect
InsertMenuItem
MenuItemFromPoint
SetMenuDefaultItem
SetMenuItemInfo
TrackPopupMenuEx


Extended Menu Structures

The following are the extended menu structures.

MENUEX_TEMPLATE_HEADER
MENUEX_TEMPLATE_ITEM
MENUITEMINFO
TPMPARAMS


Extended Menu Messages

The following are the extended menu messages.

WM_CONTEXTMENU


Menus (Windows NT)

A menu is one or more lists of application commands. Each command, which is represented by a text string or bitmap, is called a menu item. By using the mouse or the keyboard to choose a menu item, the user directs the application to perform the command associated with the menu item. When the user chooses a menu item, Microsoft® Windows® sends the application a command message that indicates which menu item the user chose.

This Windows NT overview describes menus and explains how to use them in a Win32-based application.


About Menus

Windows NT Overview
For more information, see the Windows 95 overview About Extended Menus.

A menu is one or more lists of application commands. Each command, which is represented by a text string or bitmap, is called a menu item. By using the mouse or the keyboard to choose a menu item, the user directs the application to perform the command associated with that menu item. When the user chooses a menu item, Microsoft® Windows® sends the application a command message that indicates which menu item the user chose.

Win32 also provides extended menu functions that give applications an improved way to create and control menus. The extended functions supersede the menu functions described in this topic and should be used in Win32-based applications whenever possible. For information about extended menu functions, see Extended Menus.


Menu Bars and Pop-up Menus

Windows NT Overview
For more information, see the Windows 95 overview Menu Bars and Pop-up Menus.

The menus in an application written for Microsoft Windows are arranged hierarchically. A menu bar (sometimes called a top-level menu) resides at the uppermost level of the hierarchy; the lower levels consist of pop-up menus (also known as submenus).

The items in a menu bar represent the main categories of commands provided by an application. Selecting an item from the menu bar typically activates a pop-up menu whose items correspond to the commands in a given category. For example, a menu bar might contain a File item that, when the user selects it, activates a pop-up menu with menu items such as New, Open, Save, and so on.

Only an overlapped or pop-up window can contain a menu bar; a child window cannot contain one. A menu bar is always visible. If the window has a title bar, Windows positions the menu bar just below it. By contrast, a pop-up menu is not visible until the user selects a menu item that activates it. When this menu is displayed, it is attached to the title bar.

Every menu must have an owner window. Windows sends messages to a menu's owner window when the user selects the menu or chooses a command from the menu. These messages are described in Menu Messages Overview.


Floating Pop-up Menus

Windows NT Overview
For more information, see the Windows 95 overview Floating Pop-up Menus.

Windows provides a special type of pop-up menu called a floating pop-up menu. A floating pop-up menu is not attached to the menu bar; it can appear anywhere on the screen. An application typically associates a floating pop-up menu with a portion of a window such as the client area or with a specific object such as an icon.

A floating pop-up menu remains hidden until the user selects it (for example, by clicking the appropriate screen location with the mouse.) A floating pop-up menu is typically displayed at the position of the caret or mouse cursor.


The System Menu

Windows NT Overview
For more information, see the Windows 95 overview The System Menu.

A System menu (also known as the Control menu) is a pop-up menu defined and managed almost exclusively by the system. It is represented by a small box containing a horizontal line that is displayed at the left end of the title bar. When the user clicks the box, Windows displays the System menu. Windows also displays the System menu when the user clicks the icon of a minimized application.

A System menu provides a standard set of menu items the user can choose to change a window's size or position, close the application, or activate the Windows Task List. Items in a System menu can be added, deleted, and modified, but most applications just use the standard set of menu items. An overlapped, pop-up, or child window can have a System menu. It is uncommon for an overlapped or pop-up window not to include a System menu.

When the user chooses a command from a System menu, Windows sends a WM_SYSCOMMAND message to the menu's owner window. In most applications, the window procedure does not process messages from a System menu. Instead, it simply passes the messages to the DefWindowProc function for system-default processing of the message. If a command is added to a System menu, the window procedure must process the command.


Menu Handles

Windows NT Overview
For more information, see the Windows 95 overview Menu Handles.

The system generates a unique handle for each menu. A menu handle is a value of the HMENU type. An application must specify a menu handle in many of the Windows menu functions. You receive the handle of a menu bar when you create the menu or loads a menu resource. For information about creating menus and loading menus, see Menu Creation.

The GetMenu or GetSubMenu function is used to retrieve the handle of a menu that has been created or loaded. GetMenu returns the handle of the menu bar assigned to the specified window. GetSubMenu returns the handle of a pop-up menu within the specified menu bar or pop-up menu. The GetSystemMenu function is used to retrieve the handle of a window's System menu.


Class Menus

Windows NT Overview
For more information, see the Windows 95 overview Class Menus.

When registering a window class, the developer can specify a default menu for that class. This default menu is known as the class menu. To specify a class menu, the developer must assign the name of the menu, as given in your application's resource-definition file, to the lpszMenuName member of the WNDCLASS structure used to register the window class. After the window class has been registered, each window of that class will have the specified class menu. The developer can override the class menu by specifying the handle of a different menu when creating a window of that class. For more information about window classes, see Window Classes.


Menu Items

Windows NT Overview
For more information, see the Windows 95 overview Menu Items.

There are two kinds of menu items in Win32 applications: command items and pop-up items. When the user chooses a command item, Windows sends a WM_COMMAND or WM_SYSCOMMAND message to the window procedure of the menu's owner window. A command item on a System menu generates a WM_SYSCOMMAND message; command items in other menus generate WM_COMMAND messages. When the user selects a pop-up item, Windows displays a pop-up menu but doesn't send a command message to the window procedure.

A menu bar typically contains pop-up items, but may also contain command items. A pop-up menu typically contains command items, but may also contain pop-up items. By adding pop-up items to a pop-up menu, you can nest pop-up menus to an arbitrary depth. If you include a pop-up item in a pop-up menu, Windows automatically displays a small arrow to the right of the menu item text as a visual cue to the user.


Menu-Item Identifier

Windows NT Overview
For more information, see the Windows 95 overview, Menu Item Identifier.

Associated with each menu item is a unique, application-defined integer, called an identifier. When the user chooses a command item, Windows sends the item's identifier to the owner window as part of a WM_COMMAND message. The window procedure examines the identifier to determine the source of the message, and processes the message accordingly. In addition, you can specify a menu item using its identifier when you call menu functions — for example, to enable or disable a menu item.

A menu identifier must be a value from 0 to 65,535, even though it is a 32-bit integer. This is because the WM_COMMAND message passes a menu identifier as the low-order word of its wParam parameter.

Beginning with the Win32 API, pop-up menu items have identifiers just as other menu items do. However, Windows does not send a WM_COMMAND message when a pop-up menu item is selected. Instead, Windows activates the pop-up menu associated with the pop-up menu item.


Checked and Unchecked Menu Items

Windows NT Overview
For more information, see the Windows 95 overview Checked and Unchecked Menu Items.

A menu item can be either checked or unchecked. When a menu item is checked, Windows uses a bitmap to display a check mark to the left of the menu item. When the menu item is unchecked, Windows does not display the check mark. Only menu items in a pop-up menu can be checked; menu items in a menu bar can not be checked.

An application typically uses check marks to indicate menu options that are in effect. For example, when the user selects paragraph formatting options from a menu in a word processing application, the application places check marks next to the selected options. The following illustration shows check marks next to the Left and Single Space options in a word processing application's Paragraph menu.

A check mark attribute controls whether a menu item is checked or not. A menu item's check mark attribute can be set by using the CheckMenuItem function. The GetMenuState function is used to determine whether a menu item is currently checked or unchecked.

Windows provides a default bitmap for displaying check marks. The developer, however, can substitute other bitmaps and direct Windows to use them instead of the default. Windows requires, however, that these check mark bitmaps have the same dimensions as the default check mark bitmap. The GetMenuCheckMarkDimensions function can be used to retrieve the default dimensions.

Two bitmaps can be associated with each menu item: one for when the menu item is checked and another for when it is unchecked. The SetMenuItemBitmaps function can be used to associate bitmaps with a menu item.

The developer can either provide check mark bitmaps as bitmap resources or create the bitmaps at run time by using graphic device interface (GDI) bitmap functions. A bitmap resource, however, isn't suitable for all video resolutions and aspect ratios, so the bitmap must be sized appropriately. The check mark bitmaps can be either monochrome or color. However, on a color screen the bitmap colors are inverted when the menu item is highlighted, and this result may be undesirable. For more information about bitmaps, see Bitmaps.


Enabled, Disabled, and Grayed Menu Items
Enabled, Disabled, and Graye Menu Items

Windows NT Overview
For more information, see the Windows 95 overview Enabled, Disabled, and Grayed Menu Items.

A menu item can be enabled, disabled, or grayed. By default, a menu item is enabled. When the user chooses an enabled menu item, Windows sends a command message to the corresponding window procedure or displays the corresponding pop-up menu, depending on whether the menu item is a command item or a pop-up item.

When menu items are not available to the user, they should be disabled or grayed. Disabled or grayed menu items do not generate a command message or display a pop-up menu when a user chooses them. Typically, applications gray an unavailable menu item to provide a visual clue to the user that a command is not available. A disabled menu item does not provide this visual clue. A disabled item can serve as a heading for group related menu items. (For example, a Save heading can be listed and then a series of commands such as Save File, Save All, and Save As). A grayed item can be used when an action is not appropriate. (For example, the Print command in the File menu can be grayed when the system does not have a printer installed.)

The EnableMenuItem function is used to enable, disable, or gray a menu item, and the GetMenuState function is used to determine whether a menu item is enabled, disabled, or grayed.


Menu-Item Separators and Line Breaks

Windows NT Overview
For more information, see the Windows 95 overview, Menu Item Separators and Line Breaks.

Windows provides a special type of menu item, called a separator, that consists of a horizontal line. A separator menu item can be used in a pop-up menu to divide a menu into groups of related items. A separator item cannot be used in a menu bar. The user cannot select a separator menu item, and a separator does not send command messages to the window procedure.

When a menu bar contains more items than will fit on one line, Windows automatically breaks it into two or more lines. You can force a line break at a specific item on a menu bar by assigning the MF_MENUBREAK flag to the item. Windows places that item and all remaining items on a new line.

The MF_MENUBREAK and MF_MENUBARBREAK flags are used to divide items in a pop-up menu into multiple columns. When MF_MENUBREAK flag is assigned to an item, Windows places it and all remaining items in a new column. The MF_MENUBARBREAK flag creates a similar effect, except Windows includes a vertical line in the menu to separate the new column from the old one.


Menu-Item Position

Windows NT Overview
For more information, see the Windows 95 overview, Menu-Item Position.

Windows assigns an integer position value to each item on a menu and uses the value to keep track of each item's position in the menu. Position values are zero-based; that is, the first item on a menu occupies position zero, the next position one, and so on. In a menu bar, the leftmost menu item is considered the first item, so it occupies position zero; in a pop-up menu, the uppermost menu item occupies position zero. Windows assigns position values to menu-item separators. The following illustration shows the position values of both items and separators in a menu bar and a pop-up menu.

A number of functions are used to add an item to a menu, delete an item from a menu, or modify an existing item on a menu. When one of these functions is called, the item to be modified is identified either by its position or by its identifier. Either the MF_BYPOSITION or MF_BYCOMMAND flag is also specified. For more information about modifying the contents of a menu, see Menu Modifications.


Highlighted Menu Items

Windows NT Overview
For more information, see the Windows 95 overview Highlighted Menu Items.

Windows automatically highlights menu items as the user selects them. Highlighting can, however, be explicitly added or removed from a menu item on the menu bar by calling the HiliteMenuItem function. This function has no effect on menu items in pop-up menus. When you use HiliteMenuItem to highlight a menu item, however, the menu item only appears to be selected; if the user presses the ENTER key, the highlighted item is not chosen.


Owner-drawn Menu Items

An application can completely control the appearance of a menu item by using an owner-drawn item. Owner-drawn items require an application to take total responsibility for drawing selected (highlighted), checked, and unchecked states. For example, if an application provided a font menu it could draw each menu item by using the corresponding font; the item for roman would be drawn with a roman font, the item for italic would be drawn in italic, and so on.

For information on how to create owner-drawn menu items, see Creating Owner-drawn Menu Items.


Help Item

The developer should provide a standard interface for the user, including a Help item on an application's menu bars. The item should read "Help," and it should be the rightmost item on the menu bar.


Keyboard Access to Menus

Windows NT Overview
For more information, see the Windows 95 overview Keyboard Access to Menus.

Windows provides a standard keyboard interface for menus. You can enhance this interface by including mnemonics and accelerator keys for your menu items. The following three sections describe the standard keyboard interface, mnemonics, and accelerator keys.


Standard Keyboard Interface

Windows NT Overview
For more information, see the Windows 95 overview Standard Keyboard Interface.

Windows is designed to work with or without a mouse or other pointing device. Because Windows provides a standard keyboard interface the user can use the keyboard to select menu items. Special code is not needed to support this keyboard interface. An application receives a command message whether a menu item is selected through the keyboard or by using a mouse. The standard keyboard interface processes the following keystrokes.

Keystroke	Action
ALT	Toggles in and out of menu bar mode.
ALT+SPACEBAR	Displays the System menu.
ESC	Exits menu mode.
RIGHT ARROW	Cycles to the next top-level menu item. This keystroke cycles between the application and System menus. If the selected item is in a pop-up menu, the next column in the pop-up menu is selected or the next top-level menu item is selected.
LEFT ARROW	Works like the RIGHT ARROW key, except in the opposite direction. In pop-up menus, this keystroke backs up one column; when the currently selected item is in the far-left column, the previous pop-up menu is selected.
UP or DOWN ARROWS	Activate a pop-up menu when pressed in a top-level menu. When pressed in a pop-up menu, either keystroke selects the next or previous item.
ENTER	Activates a pop-up menu and highlights the first item if an item has a pop-up menu associated with it; otherwise, this keystroke chooses the item as if the user released the mouse button while the item was selected.
Alphabetic character	Selects the first menu item with the specified character as its mnemonic. If the selected item onvokes a pop-up menu, the menu is displayed and the first item is highlighted; otherwise, the item is chosen.


Menu Mnemonics

Windows NT Overview
For more information, see the Windows 95 overview Menu Mnemonics.

The standard keyboard interface for menus can be enhanced by adding mnemonics to menu items. A mnemonic is a underlined letter in the text of a menu item. When a menu is active, the user can select a menu item by pressing the key that corresponds to the item's underlined letter. The menu bar is active when the user presses and releases the ALT key and the first item on the menu bar is highlighted. A pop-up menu is active when it is displayed.

A mnemonic keystroke for a menu item is created by preceding a character in the item's text string with an ampersand. For example, "&Move" causes Windows to underline the "M" character.


Menu Keyboard Accelerators

Windows NT Overview
For more information, see the Windows 95 overview Menu Keyboard Accelerators.

In addition to having a mnemonic, a menu item can have a keyboard accelerator associated with it. A keyboard accelerator is different from a mnemonic in that the menu need not be active for the accelerator key to work. Also, a mnemonic is always associated with a menu item, while a keyboard accelerator is usually associated with a menu item, but it does not have to be.

Text to identify the keyboard accelerator is added to the menu-item text string. The accelerator text appear to the right of the menu-item name after a backslash and tab character. For example, "&Close\tAlt+F4" represents a Close item with the ALT+F4 key combination as its keyboard accelerator and with C as its mnemonic. For more information on accelerators, see Keyboard Accelerators.


Menu Creation

Windows NT Overview
For more information, see the Windows 95 overview Menu Creation.

You can use the following methods to create a menu for use in an application:

•	Load a menu from a menu-template resource.

•	Build a menu from a menu template created at run time.

•	Use the menu creation functions to build a menu at run time.

The following sections describe how to use these three methods to create menus.


Menu-Template Resources

Windows NT Overview
For more information, see the Windows 95 overview, Menu Template Resources.

Most developers implement menus by creating a menu-template resource that is loaded at run time. A menu template defines a menu, including the items in the menu bar and all pop-up menus. For information about creating menu template resources, see your tools documentation.

Once you have created a menu-template resource and added it to your application's executable file, you can use the LoadMenu function to load the menu-template resource into memory. This function returns the handle of the menu, which you can then assign to a window by using the SetMenu function.

Implementing menus as resources makes an application easier to localize for use in multiple countries. Only the resource definition needs to be translated for each language, not the application's source code.


Menu Template in Memory

Windows NT Overview
For more information, see the Windows 95 overview Menu Template in Memory.

Instead of loading a menu-template resource, an application can create create a menu template in memory at run time. You create a menu from a template in memory by using the LoadMenuIndirect function. For descriptions of menu-template formats, see Using a Menu-Template Resource.


Menu-Creation Functions

Windows NT Overview
For more information, see the Windows 95 overview, Menu Creation Functions.

Another way to create a menu at run time is to use the CreateMenu and CreatePopupMenu functions to create empty menus. CreateMenu creates an empty menu bar; CreatePopupMenu creates an empty pop-up menu. Then menu items are added to the menus by using the AppendMenu or InsertMenu functions.


Menu Display

Windows NT Overview
For more information, see the Windows 95 overview Menu Display.

After a menu has been loaded or created, it must be assigned to a window before Windows can display it. This can be done by creating a class menu (see Class Menus), by specifying the handle of the menu as the hmenu parameter of the CreateWindowEx function, or by calling the SetMenu function.

The TrackPopupMenu function can be used to display a pop-up menu. To do so, the handle of a pop-up menu is passed to the function. The menu's owner window, the screen position where Windows should display the menu, and the mouse button the user must use to choose an item must also be specified.


Menu Destruction

Windows NT Overview
For more information, see the Windows 95 overview Menu Destruction.

If a menu is assigned to a window and that window is destroyed, Windows automatically destroys the menu, freeing the menu's handle and the memory occupied by the menu. Windows does not automatically destroy a menu that is not assigned to a window. An application must destroy the unassigned menu by calling the DestroyMenu function; otherwise, the menu continues to exist in memory even after the application closes.


Menu Messages Overview

Windows NT Overview
For more information, see the Windows 95 overview Menu Messages.

Windows reports menu-related activity by sending messages to the window procedure of the window that owns the menu. The first menu-related message the window procedure receives is WM_SYSCOMMAND. Windows sends this message when the user activates the menu by clicking the menu bar or by pressing a key that activates the menu (for more information, see Keyboard Access to Menus). The WM_SYSCOMMAND message includes a flag, either SC_KEYMENU or SC_MOUSEMENU, that indicates the hardware device used to activate the menu.

Next, Windows sends the WM_INITMENU message to the window procedure before Windows displays any pop-up menus, so an application can modify the menus before the user sees them. Windows sends the WM_INITMENU message only once per menu activation.

When the user selects a pop-up item, Windows sends the owner window the WM_INITMENUPOPUP message before displaying the pop-up menu. This message gives the application a second opportunity to modify the pop-up menu before it is displayed.

Each time the user moves the highlighting from one item to another, Windows sends a WM_MENUSELECT message to the window procedure of the menu's owner window. This message identifies the currently selected menu item. Many applications provide an information area at the bottom of their main windows and use this message to display additional information about the selected menu item.

Windows sends a WM_COMMAND message to the window procedure when the user chooses a command item from a menu. The low-order word of the WM_COMMAND message's wParam parameter contains the identifier of the chosen item. The window procedure should examine the identifier and process the message accordingly.


Menu Modifications

Windows NT Overview
For more information, see the Windows 95 overview Menu Modifications.

A number of functions can be used to modify a menu after it has been loaded or created. The AppendMenu and InsertMenu functions are used to add items to a menu. AppendMenu appends a menu item to the end of a menu; InsertMenu inserts a menu item at a specified position in a menu. Both functions permit the attributes of the menu item to be specified, including whether the menu item is enabled, checked, grayed, and so on.

The ModifyMenu function is used to change the appearance or attributes of an existing menu item. For example, the text string or bitmap of a menu item can be enabled, disabled, grayed, checked, or unchecked. ModifyMenu replaces the specified menu item with a new item.

The DeleteMenu or RemoveMenu functions are used to delete a menu item from a menu. If the item being deleted is a pop-up item, DeleteMenu deletes the associated pop-up menu, discarding the menu handle and freeing the memory used by the pop-up menu. The RemoveMenu function deletes a menu item, but if the item activates a pop-up menu, it does not destroy the pop-up menu or its handle, allowing the menu to be reused.

After a menu bar has been modified, the DrawMenuBar function must be called to redraw the menu bar. Otherwise, the modifications will not appear until Windows redraws the owner window.


Using Menus

•	Using a menu template resource.

•	Creating a floating pop-up menu.

•	Using menu item bitmaps.

•	Creating owner-drawn menu items.

•	Using custom check mark bitmaps.


Using a Menu-Template Resource

Windows NT Overview
For more information, see the Windows 95 overview, Using a Menu Template Resource.

You typically include a menu in an application by defining a menu template in the application's resource-definition file and then loading the menu at run time. Alternatively, you can create a menu template dynamically in memory. This section describes the format of a menu template, and explains how to load a menu-template resource. For information about defining a menu-template resource, see your tools documentation.


Extended Menu Template Format

The extended menu template format supports the new menu functionality available in the Win32 API. Like old menu template resources, extended menu template resources have the RC_MENU resource type. Windows distinguishes the two resource formats by the version number, which is the first member of the resource header.

Note  The structure definitions in this section are for explanation only. They are not defined in any standard header file.

An extended menu template consists of a header followed by one more more item definitions. The header has the following form:

typedef struct {

    WORD  wVersion;  // must be 1 for extended menu resources

    WORD  wOffset;   // offset of first item; typically 4

    DWORD dwHelpId;  // Help identifier for menu

} MENUEX_HDR;

Following is a description of each member:

wVersion

Specifies the template version number. This value must be 1 for extended menu templates.

wOffset

Specifies the offset of the first menu-item definition, relative to the end of this member. If the first menu-item definition immediately follows the dwHelpId member, this value should be 4.

dwHelpId

Specifies the Help identifier for the menu.

Following the header are one or more item definitions. Item definitions vary in size depending on the length of the menu text, and are packed on byte boundaries. Each item definition has the following form:

typedef struct {

    DWORD  dwType;      // menu-item type (MFT_* flags)

    DWORD  dwState;     // menu-item state (MFS_* flags)

    WORD   wId;         // application-defined menu-item identifier

    BYTE   bResInfo;    // resource info (MFR_* flags)

    char   szText[1];   // null-terminated menu text

    // dwHelpId - In pop-up menu items, a 32-bit Help identifier

    //     follows the variable-length szText member.

} MENUEX_ITEM;

Following is a description of each member:

dwType

Specifies the type of menu item. Can be a combination of the MFT_* flags defined in WINDOWS.H. For a list of menu-item types, see the description of the MENUITEMINFO structure.

dwState

Specifies the menu-item state. Can be a combination of the MFS_* flags defined in WINDOWS.H. For a list of menu-item states, see the description of the MENUITEMINFO structure.

wId

Specifies the menu-item identifier. This is an application-defined 16-bit value used to identify the menu item. Pop-up menu items can now have identifiers; previously, only command menu-items could have identifiers.

bResInfo

Specifies the type of menu-item definition. Can be zero or more of these values:

MFR_POPUP	The item definition is for a pop-up menu item.
MFR_END	The item is the last menu item in the menu or submenu.
szText

Specifies the menu-item text. This member is a null-terminated ANSI string. The size of the menu-item definition varies depending on the length of the string.

dwHelpId

Specifies the Help identifier for a submenu. This member follows the menu-item text for pop-up menu items. It is omitted for other menu items.

The following assembly-language example defines an extended menu template:

My_Menu_Template LABEL DWORD

        dw 0001h         ; template version number

        dw 0004h         ; Windows version number

        dd 0             ; Help id for main menu

        ; The following item definition specifies a pop-up menu

        ; item for a File submenu.

        dd MFT_STRING    ; type

        dd 0             ; state

        dw 1             ; identifier

        db MFR_POPUP     ; specifies a pop-up item

        db "&File", 0    ; text, including null character

        dd 0             ; Help id for the File submenu

        ; The following definition specifies an Exit command item,

        ; which appears in the File submenu. Because it is the last

        ; item in the submenu, the MFR_END flag is specified.

        dd MFT_STRING    ; type

        dd MFS_DEFAULT   ; state

        dw 2             ; identifier

        db MFR_END       ; last menu-item in submenu

        db "E&xit", 0    ; text, including null character

        ; The following definition specifies a Help command item.

        ; Because it is the last item in the menu, the MFR_END flag

        ; is specified.

        dd MFT_STRING    ; type

        dd 0             ; state

        dw 3             ; id

        db MFR_END       ; last menu-item in main menu

        db "&Help", 0    ; text, including null character


Old Menu Template Format

An old menu template defines a menu, but does not support the new menu functionality available in the Win32 API. An old menu template resource has the RT_MENU resource type. An old menu template consists of a MENUITEMTEMPLATEHEADER structure followed by one or more MENUITEMTEMPLATE structures.


Loading a Menu-Template Resource

Windows NT Overview
For more information, see the Windows 95 overview, Loading a Menu Template Resource.

You can load a menu-template resource by calling the LoadMenu function, specifying the handle of the module that contains the resource and the menu-template's identifier. LoadMenu returns a menu handle that you can use to assign the menu to a window. This window becomes the menu's owner window, receiving all the messages generated by the menu.

You can create a menu from a menu template that is already in memory by using the LoadMenuIndirect function. This is useful if your application generates menu templates dynamically.

Use the SetMenu function to assign a menu to a window, or specify the menu's handle in the hmenu parameter of the CreateWindowEx function when you create a window. Another way that you can assign a menu to a window is to specify a menu template when you register a window class. This identifies the menu as the class menu for the given window class. Whenever you create a window of the given class, Windows automatically assigns the given menu to the window.

You can create a class menu by including the identifier of the menu-template resource as the lpszMenuName member of a WNDCLASS structure and then passing the address of the structure to the RegisterClass function.


Creating a Class Menu

Windows NT Overview
For more information, see the Windows 95 overview Creating a Class Menu.

The following example shows how to create a class menu for an application, how to create a window that uses the class menu, and how to process menu commands in the window procedure.

HINSTANCE hinst;

int APIENTRY WinMain(hinstance, hPrevInstance, lpCmdLine, nCmdShow)

HINSTANCE hinstance;

HINSTANCE hPrevInstance;

LPSTR lpCmdLine;

int nCmdShow;

{

    MSG msg;        /* message               */

    WNDCLASS wc;    /* window-class data     */

    HWND hwnd;      /* handle of main window */

    /*

     * Create the window class for the main window. Specify

     * the identifier of the menu-template resource as the

     * lpszMenuName member of the WNDCLASS structure to create

     * the class menu.

     */

    wc.style = 0;

    wc.lpfnWndProc = (WNDPROC) MainWndProc;

    wc.cbClsExtra = 0;

    wc.cbWndExtra = 0;

    wc.hInstance = hinstance;

    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);

    wc.hCursor = LoadCursor(NULL, IDC_ARROW);

    wc.hbrBackground = GetStockObject(WHITE_BRUSH);

    wc.lpszMenuName =  "MyMenuResource";

    wc.lpszClassName = "MainWClass";

    if (!RegisterClass(&wc))

        return FALSE;

    hinst = hinstance;

    /*

     * Create the main window. Set the hmenu parameter to NULL so

     * that Windows uses the class menu for the window.

     */

    hwnd = CreateWindow("MainWClass", "Sample Application",

        WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,

        CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hinstance,

        NULL);

    if (hwnd == NULL)

        return FALSE;

    /*

     * Make the window visible and send a WM_PAINT message to the

     * window procedure.

     */

    ShowWindow(hwnd, nCmdShow);

    UpdateWindow(hwnd);

    /* Start the main message loop. */

    while (GetMessage(&msg, NULL, 0, 0)) {

        TranslateMessage(&msg);

        DispatchMessage(&msg);

    }

    return msg.wParam;

        UNREFERENCED_PARAMETER(hPrevInstance);

}

LRESULT APIENTRY MainWndProc(hwnd, uMsg, wParam, lParam)

HWND hwnd;

UINT uMsg;

WPARAM wParam;

LPARAM lParam;

{

    switch (uMsg) {

        .

        . /* Process other window messages. */

        .

        case WM_COMMAND:

            /* Test for the identifier of a command item. */

            switch(LOWORD(wParam)) {

                case IDM_FI_OPEN:

                    DoFileOpen();   /* application-defined */

                    break;

                case IDM_FI_CLOSE:

                    DoFileClose();  /* application-defined */

                    break;

                .

                . /* Process other menu commands. */

                .

                default:

                    break;

            }

            return 0;

        .

        . /* Process other window messages. */

        .

        default:

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

    }

    return NULL;

}


Creating a Floating Pop-up Menu

Windows NT Overview
For more information, see the Windows 95 overview Creating a Floating Pop-up Menu.

To use a floating pop-up menu in an application, pass the handle of a pop-up menu to the TrackPopupMenu function. An application typically calls TrackPopupMenu in a window procedure in response to a user-generated message, such as WM_LBUTTONDOWN or WM_KEYDOWN.

In addition to the pop-up menu handle, TrackPopupMenu requires that you specify the handle of the owner window, the position of the floating pop-up menu (in screen coordinates), and the mouse button the user can use to choose an item.

Specify the position by providing x- and y-coordinates along with the TPM_CENTERALIGN, TPM_LEFTALIGN, or TPM_RIGHTALIGN flag. The flag specifies the position of the menu relative to the x- and y-coordinates.

You should permit the user to choose an item from a pop-up menu by using the same mouse button used to display the menu. To do this, specify either TPM_LEFTBUTTON or TPM_RIGHTBUTTON flags to indicate which mouse button the user can use to select a menu item.


Creating a Floating Font-Attributes Menu

The example in this section contains portions of code from an application that creates and displays a floating pop-up menu that enables the user to set fonts and font attributes. The application displays the menu in the client area of its main window whenever the user clicks the left mouse button.

Here is the menu template for the pop-up menu that is provided in the application's resource-definition file.

PopupMenu MENU

BEGIN

  POPUP "Dummy Popup"

    BEGIN

      POPUP "Fonts"

        BEGIN

          MENUITEM "Courier",     IDM_FONT_COURIER

          MENUITEM "Times Roman", IDM_FONT_TMSRMN

          MENUITEM "Swiss",       IDM_FONT_SWISS

          MENUITEM "Helvetica",   IDM_FONT_HELV

          MENUITEM "Old English", IDM_FONT_OLDENG

        END

      POPUP "Sizes"

        BEGIN

          MENUITEM "7",  IDM_SIZE_7

          MENUITEM "8",  IDM_SIZE_8

          MENUITEM "9",  IDM_SIZE_9

          MENUITEM "10", IDM_SIZE_10

          MENUITEM "11", IDM_SIZE_11

          MENUITEM "12", IDM_SIZE_12

          MENUITEM "14", IDM_SIZE_14

        END

      POPUP "Styles"

        BEGIN

          MENUITEM "Bold",        IDM_STYLE_BOLD

          MENUITEM "Italic",      IDM_STYLE_ITALIC

          MENUITEM "Strike Out",  IDM_STYLE_SO

          MENUITEM "Superscript", IDM_STYLE_SUPER

          MENUITEM "Subscript",   IDM_STYLE_SUB

        END

    END

END

The following example gives the window procedure and supporting functions used to create and display the floating pop-up menu.

LRESULT APIENTRY MenuWndProc(hwnd, uMsg, wParam, lParam)

HWND hwnd;

UINT uMsg;

WPARAM wParam;

LPARAM lParam;

{

    RECT rc;    /* client area             */

    POINT pt;   /* location of mouse click */

    switch (uMsg) {

        case WM_LBUTTONDOWN:

            /* Get the bounding rectangle of the client area. */

            GetClientRect(hwnd, (LPRECT) &rc);

            /* Get the client coordinates for the mouse click. */

            pt.x = LOWORD(lParam);

            pt.y = HIWORD(lParam);

            /*

             * If the mouse click took place inside the client

             * area, execute the application-defined function

             * that displays the floating pop-up menu.

             */

            if (PtInRect((LPRECT) &rc, pt))

                HandlePopupMenu(hwnd, pt);

            break;

        .

        . /* Process other window messages. */

        .

        default:

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

    }

    return NULL;

}

VOID APIENTRY HandlePopupMenu(hwnd, pt)

HWND hwnd;

POINT pt;

{

    HMENU hmenu;            /* menu template         */

    HMENU hmenuTrackPopup;  /* floating pop-up menu  */

    /*

     * Load the menu template containing the pop-up menu from the

     * application's resources.

     */

    hmenu = LoadMenu(hinst, "PopupMenu");

    if (hmenu == NULL)

        return;

    /*

     * Get the first pop-up menu in the menu template. This is the

     * menu that TrackPopupMenu displays.

     */

    hmenuTrackPopup = GetSubMenu(hmenu, 0);

    /*

     * TrackPopup uses screen coordinates, so convert the

     * coordinates of the mouse click to screen coordinates.

     */

    ClientToScreen(hwnd, (LPPOINT) &pt);

    /* Draw and track the floating pop-up menu. */

    TrackPopupMenu(hmenuTrackPopup, TPM_LEFTALIGN | TPM_LEFTBUTTON,

        pt.x, pt.y, 0, hwnd, NULL);

    /* Destroy the menu.*/

    DestroyMenu(hmenu);

}


Using Menu-Item Bitmaps

Windows NT Overview
For more information, see the Windows 95 overview, Using Menu Item Bitmaps.

Windows can use a bitmap instead of a text string to display a menu item. To use a bitmap, you must set the MF_BITMAP flag for the menu item and specify the handle of the bitmap that Windows should display for the menu item. This section describes how to set the MF_BITMAP flag and retrieve the handle of a bitmap.


Setting the MF_BITMAP Flag

The MF_BITMAP flag tells Windows to use a bitmap rather than a text string to display a menu item. A menu item's MF_BITMAP flag must be set at run time; you cannot set it in the resource-definition file.

You can use the ModifyMenu, InsertMenu, or AppendMenu function to set the MF_BITMAP flag. To convert a menu item from a text string item to a bitmap item, use ModifyMenu. To add a new bitmap item to a menu, use the MF_BITMAP flag with the InsertMenu or AppendMenu function.


Creating the Bitmap

Windows NT Overview
For more information, see the Windows 95 overview Creating the Bitmap.

When you set the MF_BITMAP flag for a menu item, you must also specify the handle of the bitmap that Windows should display for the menu item. You can provide the bitmap as a bitmap resource or create the bitmap at run time.

To provide a bitmap resource, use a resource editor, such as ImageEdit, to create a bitmap resource, and then use a resource compiler to add the bitmap to your application's executable file. At run time, use the LoadBitmap function to load the bitmap and obtain its handle.

To create the bitmap at run time, use GDI functions. GDI provides several ways to create a bitmap at run time, but developers typically use the following method:

•	Use the CreateCompatibleDC function to create a device context compatible with the device context used by the application's main window.

•	Use the CreateCompatibleBitmap function to create a bitmap compatible with the application's main window.

•	Use the SelectObject function to select the bitmap into the compatible device context.

•	Use GDI drawing functions, such as Ellipse and LineTo, to draw an image into the bitmap.

•	Pass the handle of the bitmap to the ModifyMenu, InsertMenu, or AppendMenu function.

For more information about bitmaps, see Bitmaps.


Adding Lines and Graphs to a Menu

The following code sample shows how to create a menu that contains menu-item bitmaps. It creates two pop-up menus shown in the following illustration. The first is a Chart menu that contains three menu-item bitmaps: a pie chart, a line chart, and a bar chart. The example demonstrates how to load these bitmaps from the application's resource file, and then use the CreatePopupMenu and AppendMenu functions to create the menu and menu items.

The second pop-up menu is a Lines menu. It contains bitmaps showing the line styles provided by the predefined pen in Windows. The line-style bitmaps are created at run time by using GDI functions.

Here are the definitions of the bitmap resources in the application's resource-definition file.

PIE BITMAP pie.bmp

LINE BITMAP line.bmp

BAR BITMAP bar.bmp

Here are the relevant portions of the application's header file.

/* Menu-item identifiers */

#define IDM_SOLID       PS_SOLID

#define IDM_DASH        PS_DASH

#define IDM_DASHDOT     PS_DASHDOT

#define IDM_DASHDOTDOT  PS_DASHDOTDOT

#define IDM_PIE  1

#define IDM_LINE 2

#define IDM_BAR  3

/* Line-type flags */

#define SOLID       0

#define DOT         1

#define DASH        2

#define DASHDOT     3

#define DASHDOTDOT  4

/* Count of pens */

#define CPENS 5

/* Chart-type flags */

#define PIE  1

#define LINE 2

#define BAR  3

/* Function prototypes */

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

VOID MakeChartMenu(HWND);

VOID MakeLineMenu(HWND, HPEN, HBITMAP);

The following example shows how menus and menu-item bitmaps are created in an application.

LRESULT APIENTRY MainWndProc(hwnd, uMsg, wParam, lParam)

HWND hwnd;

UINT uMsg;

WPARAM wParam;

LPARAM lParam;

{

    static HPEN hpen[CPENS];

    static HBITMAP hbmp[CPENS];

    int i;

    switch (uMsg) {

        case WM_CREATE:

            /* Create the Chart and Line menus. */

            MakeChartMenu(hwnd);

            MakeLineMenu(hwnd, hpen, hbmp);

            return 0;

        .

        . /* Process other window messages. */

        .

        case WM_DESTROY:

            for (i = 0; i < CPENS; i++) {

                DeleteObject(hbmp[i]);

                DeleteObject(hpen[i]);

            }

            PostQuitMessage(0);

            break;

        default:

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

    }

    return NULL;

}

VOID MakeChartMenu(hwnd)

HWND hwnd;              /* handle of owner window      */

{

    HBITMAP hbmpPie;    /* handle of pie chart bitmap  */

    HBITMAP hbmpLine;   /* handle of line chart bitmap */

    HBITMAP hbmpBar;    /* handle of bar chart bitmap  */

    HMENU hmenuMain;    /* handle of main menu         */

    HMENU hmenuChart;   /* handle of chart pop-up menu */

    /*

     * Load the pie, line, and bar chart bitmaps from the

     * resource-definition file.

     */

    hbmpPie = LoadBitmap(hinst, MAKEINTRESOURCE(PIE));

    hbmpLine = LoadBitmap(hinst, MAKEINTRESOURCE(LINE));

    hbmpBar = LoadBitmap(hinst, MAKEINTRESOURCE(BAR));

    /*

     * Create the Chart pop-up menu and add it to the menu bar.

     * Append the Pie, Line, and Bar menu items to the Chart

     * pop-up menu.

     */

    hmenuMain = GetMenu(hwnd);

    hmenuChart = CreatePopupMenu();

    AppendMenu(hmenuMain, MF_STRING | MF_POPUP, (UINT) hmenuChart,

        "Chart");

    AppendMenu(hmenuChart, MF_BITMAP, IDM_PIE, (LPCTSTR) hbmpPie);

    AppendMenu(hmenuChart, MF_BITMAP, IDM_LINE,

        (LPCTSTR) hbmpLine);

    AppendMenu(hmenuChart, MF_BITMAP, IDM_BAR, (LPCTSTR) hbmpBar);

    return;

}

VOID MakeLineMenu(hwnd, phpen, phbmp)

HWND hwnd;

HPEN *phpen;

HBITMAP *phbmp;

{

    HMENU hmenuLines;       /* handle of Lines pop-up menu     */

    HMENU hmenu;            /* handle of main menu             */

    COLORREF crMenuClr;     /* menu-item background color      */

    HBRUSH hbrBackground;   /* handle of background brush      */

    HBRUSH hbrOld;          /* handle of previous brush        */

    LONG lCheckXY;          /* dimensions of check mark bitmap */

    WORD wLineX;            /* width of line bitmaps           */

    WORD wLineY;            /* height of line bitmaps          */

    HDC hdcMain;            /* handle of main window's DC      */

    HDC hdcLines;           /* handle of compatible DC         */

    HBITMAP hbmpOld;        /* handle of previous bitmap       */

    int i;                  /* loop counter                    */

    /* Create the Lines pop-up menu. Add it to the menu bar. */

    hmenu = GetMenu(hwnd);

    hmenuLines = CreatePopupMenu();

    AppendMenu(hmenu, MF_STRING | MF_POPUP,

        (UINT) hmenuLines, "&Lines");

    /* Create a brush for the menu-item background color. */

    crMenuClr = GetSysColor(COLOR_MENU);

    hbrBackground = CreateSolidBrush(crMenuClr);

    /*

     * Create a compatible device context for the line bitmaps,

     * and then select the background brush into it.

     */

    hdcMain = GetDC(hwnd);

    hdcLines = CreateCompatibleDC(hdcMain);

    hbrOld = SelectObject(hdcLines, hbrBackground);

    /*

     * Get the dimensions of the check mark bitmap. The width of

     * the line bitmaps will be five times the width of the

     * check mark bitmap.

     */

    lCheckXY = GetMenuCheckMarkDimensions();

    wLineX = LOWORD(lCheckXY) * (WORD) 5;

    wLineY = HIWORD(lCheckXY);

    /*

     * Create the bitmaps and select them, one at a time, into the

     * compatible device context. Initialize each bitmap by

     * filling it with the menu-item background color.

     */

    for (i = 0; i < CPENS; i++) {

        phbmp[i] = CreateCompatibleBitmap(hdcMain, wLineX, wLineY);

        if (i == 0)

            hbmpOld = SelectObject(hdcLines, phbmp[i]);

        else

            SelectObject(hdcLines, phbmp[i]);

        ExtFloodFill(hdcLines, 0, 0, crMenuClr, FLOODFILLBORDER);

    }

    /* Create the pens. */

    phpen[0] = CreatePen(PS_SOLID, 1, RGB(0, 0, 0));

    phpen[1] = CreatePen(PS_DOT, 1, RGB(0, 0, 0));

    phpen[2] = CreatePen(PS_DASH, 1, RGB(0, 0, 0));

    phpen[3] = CreatePen(PS_DASHDOT, 1, RGB(0, 0, 0));

    phpen[4] = CreatePen(PS_DASHDOTDOT, 1, RGB(0, 0, 0));

    /*

     * Select a pen and a bitmap into the compatible device

     * context, draw a line into the bitmap, and then append

     * the bitmap as an item in the Lines menu.

     */

    for (i = 0; i < CPENS; i++) {

        SelectObject(hdcLines, phbmp[i]);

        SelectObject(hdcLines, phpen[i]);

        MoveToEx(hdcLines, 0, wLineY / 2, NULL);

        LineTo(hdcLines, wLineX, wLineY / 2);

        AppendMenu(hmenuLines, MF_BITMAP, i + 1,

            (LPCTSTR) phbmp[i]);

    }

    /*

     * Release the main window's device context and destroy the

     * compatible device context. Also, destroy the background

     * brush.

     */

    ReleaseDC(hwnd, hdcMain);

    SelectObject(hdcLines, hbrOld);

    DeleteObject(hbrBackground);

    SelectObject(hdcLines, hbmpOld);

    DeleteDC(hdcLines);

    return;

}


Creating Owner-Drawn Menu Items

If you need complete control over the appearance of a menu item, you can use an owner-drawn menu item on your application. This section describes the steps involved in creating and using an owner-drawn menu item.


Setting the MF_OWNERDRAW Flag

You cannot define an owner-drawn menu item on your application's resource-definition file. Instead, you must create a new menu item or modify an existing one by using the MF_OWNERDRAW menu flag.

You can use the AppendMenu, InsertMenu, or ModifyMenu function to specify an owner-drawn menu item. Use AppendMenu to add a new item to the end of the given menu. Use InsertMenu to place a new item onto a menu, moving the other items down. Use ModifyMenu to change the contents of a menu.

When you call any of these three functions, you can pass a 32-bit value as the lpNewItem parameter. This value can represent any information that is meaningful to your application, and that will be available to your application when the item is to be displayed. For example, the value could contain a pointer to a structure; the structure, in turn, might contain a text string and the handle of a logical font that your application will use to draw the string.


Responding to the WM_MEASUREITEM Message

Before Windows displays an owner-drawn menu item for the first time, it sends the WM_MEASUREITEM message to the window procedure of the window that owns the item's menu. This message contains a pointer to a MEASUREITEMSTRUCT structure that identifies the item and contains an optional 32-bit value for the item. When the window procedure receives the WM_MEASUREITEM message, it must fill the itemWidth and itemHeight members of the structure before returning from processing the message. Windows uses the information in these members when creating the bounding rectangle in which your application draws the menu item. It also uses the information to detect when the user chooses the item.


Responding to the WM_DRAWITEM Message

Whenever the item must be drawn (for example, when it is first displayed or when the user chooses it as a command), Windows sends the WM_DRAWITEM message to the window procedure of the menu's owner window. This message contains a pointer to a DRAWITEMSTRUCT structure. Like the MEASUREITEMSTRUCT structure, DRAWITEMSTRUCT contains information about the item and its optional 32-bit data. In addition, DRAWITEMSTRUCT contains flags that indicate the state of the item (such as whether it is grayed or checked) as well as a bounding rectangle and a device context that the application uses to draw the item.

In response to the WM_DRAWITEM message, your application must perform the following actions before returning from processing the message:

1.	Determine the type of drawing that is necessary. To do so, check the itemAction member of the DRAWITEMSTRUCT structure.

2.	Draw the menu item appropriately, using the bounding rectangle and device context obtained from the DRAWITEMSTRUCT structure. Your application must draw only within the bounding rectangle. For performance reasons, Windows doesn't clip portions of the image that are drawn outside the rectangle.

3.	Restore all GDI objects selected for the menu item's device context.

If the menu item is selected, Windows sets the itemAction member of the DRAWITEMSTRUCT structure to ODA_SELECT and sets the ODS_SELECTED flag in the itemState member. This is an application's cue to redraw the menu item to indicate that it is selected.


Setting Fonts for Menu-Item Text Strings

This section contains an example from an application that uses owner-drawn menu items in a pop-up menu. The pop-up menu contains items that set the attributes of the current font, and the items are displayed using the appropriate font attribute.

Here is how the menu is defined in the resource-definition file. Note that the strings for the Regular, Bold, Italic, and Underline items are assigned at run time, so their strings are empty in the resource-definition file.

MainMenu MENU

BEGIN

    POPUP   "&Character"

    BEGIN

        MENUITEM    "",    IDM_REGULAR

        MENUITEM SEPARATOR

        MENUITEM    "",    IDM_BOLD

        MENUITEM    "",    IDM_ITALIC

        MENUITEM    "",    IDM_ULINE

    END

END

The application's window procedure processes the messages involved in using owner-drawn menu items. The application uses the WM_CREATE message to do the following:

•	Set the MF_OWNERDRAW flag for the menu items.

•	Set the text strings for the menu items.

•	Obtain handles of the fonts used to draw the items.

•	Obtain the text and background color values for selected menu items.

The text strings and font handles are stored in an array of application-defined MYITEM structures. The application-defined GetAFont function creates a font that corresponds to the given font attribute and returns the handle of the font. The handles are destroyed during the processing of the WM_DESTROY message.

During the processing of the WM_MEASUREITEM message, the example gets the width and height of a menu-item string and copies these values into the MEASUREITEMSTRUCT structure. Windows uses the width and height values to calculate the size of the pop-up menu.

During the processing of the WM_DRAWITEM message, the menu item's string is drawn with room left next to the string for the check mark bitmap. If the user selects the item, the selected text and background colors are used to draw the item.

LRESULT APIENTRY MainWndProc(hwnd, uMsg, wParam, lParam)

HWND hwnd;

UINT uMsg;

WPARAM wParam;

LPARAM lParam;

{

    typedef struct _MYITEM {

        HFONT hfont;

        LPSTR psz;

    } MYITEM;             /* structure for item font and string */

    MYITEM *pmyitem;      /* pointer to item's font and string       */

    static MYITEM myitem[CITEMS];   /* array of MYITEMS              */

    static HMENU hmenu;             /* handle of main menu           */

    static COLORREF crSelText;  /* text color of selected item       */

    static COLORREF crSelBkgnd; /* background color of selected item */

    COLORREF crText;            /* text color of unselected item     */

    COLORREF crBkgnd;           /* background color unselected item  */

    LPMEASUREITEMSTRUCT lpmis;  /* points to item of data            */

    LPDRAWITEMSTRUCT lpdis;     /* points to item drawing data       */

    HDC hdc;                    /* handle of screen DC               */

    SIZE size;                  /* menu-item text extents            */

    DWORD dwCheckXY;            /* check mark dimensions             */

    WORD wCheckX;               /* check mark width                  */

    int nTextX;                 /* width of menu item                */

    int nTextY;                 /* height of menu item               */

    int i;                      /* loop counter                      */

    HFONT hfontOld;             /* handle of old font                */

    BOOL fSelected = FALSE;     /* menu-item selection flag          */

    switch (uMsg) {

        case WM_CREATE:

            /*

             * Modify the Regular, Bold, Italic, and Underline

             * menu items to make them owner-drawn items. Associate

             * a MYITEM structure with each item to contain the

             * string and font handle for each item.

             */

            hmenu = GetMenu(hwnd);

            ModifyMenu(hmenu, IDM_REGULAR, MF_BYCOMMAND |

                MF_CHECKED | MF_OWNERDRAW, IDM_REGULAR,

                (LPTSTR) &myitem[REGULAR]);

            ModifyMenu(hmenu, IDM_BOLD, MF_BYCOMMAND |

                MF_OWNERDRAW, IDM_BOLD, (LPTSTR) &myitem[BOLD]);

            ModifyMenu(hmenu, IDM_ITALIC, MF_BYCOMMAND |

                MF_OWNERDRAW, IDM_ITALIC,

                (LPTSTR) &myitem[ITALIC]);

            ModifyMenu(hmenu, IDM_ULINE, MF_BYCOMMAND |

                MF_OWNERDRAW, IDM_ULINE, (LPTSTR) &myitem[ULINE]);

            /*

             * Retrieve each item's font handle and copy it into

             * the hfont member of each item's MYITEM structure.

             * Also, copy each item's string into the structures.

             */

            myitem[REGULAR].hfont = GetAFont(REGULAR);

            myitem[REGULAR].psz = "Regular";

            myitem[BOLD].hfont = GetAFont(BOLD);

            myitem[BOLD].psz = "Bold";

            myitem[ITALIC].hfont = GetAFont(ITALIC);

            myitem[ITALIC].psz = "Italic";

            myitem[ULINE].hfont = GetAFont(ULINE);

            myitem[ULINE].psz = "Underline";

            /*

             * Retrieve the text and background colors of the

             * selected menu text.

             */

            crSelText = GetSysColor(COLOR_HIGHLIGHTTEXT);

            crSelBkgnd = GetSysColor(COLOR_HIGHLIGHT);

            return 0;

        case WM_MEASUREITEM:

            /* Retrieve a device context for the main window. */

            hdc = GetDC(hwnd);

            /*

             * Retrieve pointers to the menu item's

             * MEASUREITEMSTRUCT structure and MYITEM structure.

             */

            lpmis = (LPMEASUREITEMSTRUCT) lParam;

            pmyitem = (MYITEM *) lpmis->itemData;

            /*

             * Select the font associated with the item into

             * the main window's device context.

             */

            hfontOld = SelectObject(hdc, pmyitem->hfont);

            /*

             * Retrieve the width and height of the item's string,

             * and then copy the width and height into the

             * MEASUREITEMSTRUCT structure's itemWidth and

             * itemHeight members.

             */

            GetTextExtentPoint32(hdc, pmyitem->psz,

                lstrlen(pmyitem->psz), &size);

            lpmis->itemWidth = size.cx;

            lpmis->itemHeight = size.cy;

            /*

             * Select the old font back into the device context,

             * and then release the device context.

             */

            SelectObject(hdc, hfontOld);

            ReleaseDC(hwnd, hdc);

            return TRUE;

            break;

        case WM_DRAWITEM:

            /*

             * Get pointers to the menu item's DRAWITEMSTRUCT

             * structure and MYITEM structure.

             */

            lpdis = (LPDRAWITEMSTRUCT) lParam;

            pmyitem = (MYITEM *) lpdis->itemData;

            /*

             * If the user has selected the item, use the selected

             * text and background colors to display the item.

             */

            if (lpdis->itemState & ODS_SELECTED) {

                crText = SetTextColor(lpdis->hDC, crSelText);

                crBkgnd = SetBkColor(lpdis->hDC, crSelBkgnd);

                fSelected = TRUE;

            }

            /*

             * Remember to leave space in the menu item for the

             * check mark bitmap. Retrieve the width of the bitmap

             * and add it to the width of the menu item.

             */

            dwCheckXY = GetMenuCheckMarkDimensions();

            wCheckX = LOWORD(dwCheckXY);

            nTextX = wCheckX + lpdis->rcItem.left;

            nTextY = lpdis->rcItem.top;

            /*

             * Select the font associated with the item into the

             * item's device context, and then draw the string.

             */

            hfontOld = SelectObject(lpdis->hDC, pmyitem->hfont);

            ExtTextOut(lpdis->hDC, nTextX, nTextY, ETO_OPAQUE,

                &lpdis->rcItem, pmyitem->psz,

                lstrlen(pmyitem->psz), NULL);

            /*

             * Select the previous font back into the device

             * context.

             */

            SelectObject(lpdis->hDC, hfontOld);

            /*

             * Return the text and background colors to their

             * normal state (not selected).

             */

            if (fSelected) {

                SetTextColor(lpdis->hDC, crText);

                SetBkColor(lpdis->hDC, crBkgnd);

            }

            return TRUE;

        .

        . /* Process other messages. */

        .

        case WM_DESTROY:

            /* Destroy the menu items' font handles. */

            for (i = 0; i < CITEMS; i++)

                DeleteObject(myitem[i].hfont);

            PostQuitMessage(0);

            break;

        default:

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

    }

    return NULL;

}

HFONT GetAFont(fnFont)

int fnFont;             /* font-attribute flag            */

{

    static LOGFONT lf;  /* structure for font information */

    /*

     * Get a handle to the ANSI fixed-pitch font, and copy

     * information about the font to a LOGFONT structure.

     */

    GetObject(GetStockObject(ANSI_FIXED_FONT), sizeof(LOGFONT),

        &lf);

    /* Set the font attributes, as appropriate. */

    if (fnFont == BOLD)

        lf.lfWeight = FW_BOLD;

    else

        lf.lfWeight = FW_NORMAL;

    lf.lfItalic = (fnFont == ITALIC);

    lf.lfItalic = (fnFont == ULINE);

    /* Create the font, and then return its handle. */

    return CreateFont(lf.lfHeight, lf.lfWidth,

        lf.lfEscapement, lf.lfOrientation, lf.lfWeight,

        lf.lfItalic, lf.lfUnderline, lf.lfStrikeOut, lf.lfCharSet,

        lf.lfOutPrecision, lf.lfClipPrecision, lf.lfQuality,

        lf.lfPitchAndFamily, lf.lfFaceName);

}


Using Custom Check Mark Bitmaps

Windows NT Overview
For more information, see the Windows 95 overview Using Custom Check Mark Bitmaps.

A Windows video device driver provides a default check mark bitmap that Windows displays next to a menu item that is checked. You can customize an individual menu item by providing a pair of bitmaps to replace the default check mark bitmap. Windows displays one bitmap when the item is checked and the other when it is unchecked. This section describes the steps involved in creating and using custom check mark bitmaps.


Creating Custom Check Mark Bitmaps

Windows NT Overview
For more information, see the Windows 95 overview Creating Custom Check Mark Bitmaps.

A custom check mark bitmap must be the same size as the default check mark bitmap. You can retrieve the default check mark bitmap's size by calling the GetMenuCheckMarkDimensions function. The low-order word of this function's return value specifies the width; the high-order word specifies the height.

Bitmap resources can be used to provide check mark bitmaps. However, a bitmap resource is not suitable for all screen resolutions and aspect ratios, so you'll need to use the StretchBlt function to size the bitmap, as appropriate. Depending on the bitmap being sized, the result of the sizing may not be acceptable, because stretching may distort the bitmap.

Instead of using a bitmap resource, GDI functions can be used to provide check mark bitmaps at run time. This involves the following steps, which an application typically performs during the WM_CREATE message:

1.	Create a device context in memory that is compatible with the screen.

2.	Create a bitmap that is compatible with the display.

3.	Select the bitmap into the device context.

4.	Draw or copy an image into the bitmap.

Call the CreateCompatibleDC function to create a device context that is compatible with the screen. The function's hdc parameter can specify either NULL or the return value from the GetDC function. CreateCompatibleDC returns the handle of the compatible device context.

Call the CreateCompatibleBitmap function to create an "empty" bitmap that is compatible with the screen. This function's nWidth and nHeight parameters set the size of the bitmap; they should specify the width and height information returned by the GetMenuCheckMarkDimensions function.

The CreateCompatibleBitmap function returns the handle of the bitmap. Pass this handle of the SelectObject function to select the bitmap into the compatible device context. Afterward, you can use the GDI drawing functions such as Rectangle and Ellipse to draw into the bitmap, or you can use functions such as BitBlt and StretchBlt to copy an image into the bitmap.

GDI provides several other ways to create bitmaps. For more information about bitmaps, see Bitmaps.


Associating Bitmaps with a Menu Item

Windows NT Overview
For more information, see the Windows 95 overview Associating Bitmaps with a Menu Item.

You associate a pair of check mark bitmaps with a menu item by passing the handles of the bitmaps to the SetMenuItemBitmaps function. The hbmUnchecked parameter identifies the unchecked bitmap; the hbmChecked parameter identifies the checked bitmap. If you want to remove one or both check marks from a menu item, you can set the hbmUnchecked or hbmChecked parameter, or both, to NULL.


Setting the Check Mark Attribute

Windows NT Overview
For more information, see the Windows 95 overview Setting the Check Mark Attribute.

The CheckMenuItem function sets a menu item's check mark attribute to either checked or unchecked. Specify the MF_CHECKED flag to set the check mark attribute to checked, or specify MF_UNCHECKED to set it to unchecked.


Simulating Check Boxes in a Menu

This section contains an example that shows how to simulate check boxes in a pop-up menu. The example contains a Character menu whose items allow the user to set the bold, italic, and underline attributes of the current font. When a font attribute is in effect, a check mark is displayed in the check box next to the corresponding menu item; otherwise, it is displayed in an empty check box next to the item.

The example in this section replaces the default check mark bitmap with two bitmaps: a bitmap with a checked box and the bitmap with an empty box. The checked check box bitmap is displayed next to the Bold, Italic, or Underline menu item when the item's check mark attribute is set to MF_CHECKED. The unchecked or empty check box bitmap is displayed when the check mark attribute is set to MF_UNCHECKED.

Windows provides a predefined bitmap that contains the images used for check boxes and radio buttons. The example in this section isolates the checked and empty check boxes, copies them to two separate bitmaps, and then uses them as the checked and unchecked bitmaps for items in the Character menu.

To retrieve the handle of the system-defined check box bitmap, the example in this section calls the LoadBitmap function, specifying NULL as the hinst parameter and OBM_CHECKBOXES as the lpBitmapName parameter. Because the images in the bitmap are all the same size, the example can isolate them by dividing the bitmap's width and height by the number of images in its rows and columns.

The following portion of a resource-definition file shows how the menu items in the Character menu are defined. Note that no font attributes are in effect initially, so the check mark attribute for the Regular item is set to checked and, by default, the check mark attribute of the remaining items is set to unchecked.

#include "men3.h"

MainMenu MENU

BEGIN

    POPUP   "&Character"

    BEGIN

        MENUITEM    "&Regular",     IDM_REGULAR, CHECKED

        MENUITEM SEPARATOR

        MENUITEM    "&Bold",        IDM_BOLD

        MENUITEM    "&Italic",      IDM_ITALIC

        MENUITEM    "&Underline",   IDM_ULINE

    END

END

Here is the relevant contents of the application's header file.

/* Menu-item identifiers */

#define IDM_REGULAR 0x1

#define IDM_BOLD    0x2

#define IDM_ITALIC  0x4

#define IDM_ULINE   0x8

/* Check mark flags */

#define CHECK   1

#define UNCHECK 2

/* Font-attribute mask */

#define ATTRIBMASK 0xe

/* Function prototypes */

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

HBITMAP GetMyCheckBitmaps(UINT);

BYTE CheckOrUncheckMenuItem(BYTE, HMENU);

The following example shows the portions of the window procedure that create the check mark bitmaps, set the check mark attribute of the Bold, Italic, and Underline menu items, and destroy check mark bitmaps.

LRESULT APIENTRY MainWndProc(hwndMain, uMsg, wParam, lParam)

HWND hwndMain;

UINT uMsg;

WPARAM wParam;

LPARAM lParam;

{

    static HBITMAP hbmpCheck;   /* handle of checked bitmap   */

    static HBITMAP hbmpUncheck; /* handle of unchecked bitmap */

    static HMENU hmenu;         /* handle of main menu        */

    BYTE fbFontAttrib;          /* font-attribute flags       */

    switch (uMsg) {

        case WM_CREATE:

            /*

             * Call the application-defined GetMyCheckBitmaps

             * function to get the predefined checked and

             * unchecked check box bitmaps.

             */

            hbmpCheck = GetMyCheckBitmaps(CHECK);

            hbmpUncheck = GetMyCheckBitmaps(UNCHECK);

            /*

             * Set the checked and unchecked bitmaps for the menu

             * items.

             */

            hmenu = GetMenu(hwndMain);

            SetMenuItemBitmaps(hmenu, IDM_BOLD, MF_BYCOMMAND,

                hbmpUncheck, hbmpCheck);

            SetMenuItemBitmaps(hmenu, IDM_ITALIC, MF_BYCOMMAND,

                hbmpUncheck, hbmpCheck);

            SetMenuItemBitmaps(hmenu, IDM_ULINE, MF_BYCOMMAND,

                hbmpUncheck, hbmpCheck);

            return 0;

        case WM_COMMAND:

            switch (LOWORD(wParam)) {

                /* Process the menu commands. */

                case IDM_REGULAR:

                case IDM_BOLD:

                case IDM_ITALIC:

                case IDM_ULINE:

                    /*

                     * CheckOrUncheckMenuItem is an application-

                     * defined function that sets the menu item

                     * check marks and returns the user-selected

                     * font attributes.

                     */

                    fbFontAttrib = CheckOrUncheckMenuItem(

                        (BYTE) LOWORD(wParam), hmenu);

                    .

                    . /* Set the font attributes. */

                    .

                    return 0;

                .

                . /* Process other command messages. */

                .

                default:

                    break;

            }

            break;

        .

        . /* Process other window messages. */

        .

        case WM_DESTROY:

            /* Destroy the checked and unchecked bitmaps. */

            DeleteObject(hbmpCheck);

            DeleteObject(hbmpUncheck);

            PostQuitMessage(0);

            break;

        default:

            return DefWindowProc(hwndMain, uMsg, wParam, lParam);

    }

    return NULL;

}

HBITMAP GetMyCheckBitmaps(fuCheck)

UINT fuCheck;               /* CHECK or UNCHECK flag            */

{

    COLORREF crBackground;  /* background color                 */

    HBRUSH hbrBackground;   /* background brush                 */

    HBRUSH hbrTargetOld;    /* original background brush        */

    HDC hdcSource;          /* source device context            */

    HDC hdcTarget;          /* target device context            */

    HBITMAP hbmpCheckboxes; /* handle of check box bitmap       */

    BITMAP bmCheckbox;      /* structure for bitmap data        */

    HBITMAP hbmpSourceOld;  /* handle of original source bitmap */

    HBITMAP hbmpTargetOld;  /* handle of original target bitmap */

    HBITMAP hbmpCheck;      /* handle of check mark bitmap      */

    RECT rc;                /* rectangle for check box bitmap   */

    DWORD dwCheckXY;        /* dimensions of check mark bitmap  */

    WORD wBitmapX;          /* width of check mark bitmap       */

    WORD wBitmapY;          /* height of check mark bitmap      */

    /*

     * Get the menu background color and create a solid brush

     * with that color.

     */

    crBackground = GetSysColor(COLOR_MENU);

    hbrBackground = CreateSolidBrush(crBackground);

    /*

     * Create memory device contexts for the source and

     * destination bitmaps.

     */

    hdcSource = CreateCompatibleDC((HDC) NULL);

    hdcTarget = CreateCompatibleDC(hdcSource);

    /*

     * Get the size of the Windows default check mark bitmap and

     * create a compatible bitmap of the same size.

     */

    dwCheckXY = GetMenuCheckMarkDimensions();

    wBitmapX = LOWORD(dwCheckXY);

    wBitmapY = LOWORD(dwCheckXY);

    hbmpCheck = CreateCompatibleBitmap(hdcSource, wBitmapX,

        wBitmapY);

    /*

     * Select the background brush and bitmap into the target DC.

     */

    hbrTargetOld = SelectObject(hdcTarget, hbrBackground);

    hbmpTargetOld = SelectObject(hdcTarget, hbmpCheck);

    /*

     * Use the selected brush to initialize the background color

     * of the bitmap in the target device context.

     */

    PatBlt(hdcTarget, 0, 0, wBitmapX, wBitmapY, PATCOPY);

    /*

     * Load the predefined check box bitmaps and select it

     * into the source DC.

     */

    hbmpCheckboxes = LoadBitmap((HINSTANCE) NULL,

        (LPTSTR) OBM_CHECKBOXES);

    hbmpSourceOld = SelectObject(hdcSource, hbmpCheckboxes);

    /*

     * Fill a BITMAP structure with information about the

     * check box bitmaps, and then find the upper-left corner of

     * the unchecked check box or the checked check box.

     */

    GetObject(hbmpCheckboxes, sizeof(BITMAP), &bmCheckbox);

    if (fuCheck == UNCHECK) {

        rc.left = 0;

        rc.right = (bmCheckbox.bmWidth / 4);

    }

    else {

        rc.left = (bmCheckbox.bmWidth / 4);

        rc.right = (bmCheckbox.bmWidth / 4) * 2;

    }

    rc.top = 0;

    rc.bottom = (bmCheckbox.bmHeight / 3);

    /*

     * Copy the appropriate bitmap into the target DC. If the

     * check box bitmap is larger than the default check mark

     * bitmap, use StretchBlt to make it fit; otherwise, just

     * copy it.

     */

    if (((rc.right - rc.left) > (int) wBitmapX) ||

            ((rc.bottom - rc.top) > (int) wBitmapY))

        StretchBlt(hdcTarget, 0, 0, wBitmapX, wBitmapY,

            hdcSource, rc.left, rc.top, rc.right - rc.left,

            rc.bottom - rc.top, SRCCOPY);

    else

        BitBlt(hdcTarget, 0, 0, rc.right - rc.left,

            rc.bottom - rc.top,

            hdcSource, rc.left, rc.top, SRCCOPY);

    /*

     * Select the old source and destination bitmaps into the

     * source and destination DCs, and then delete the DCs and

     * the background brush.

     */

    SelectObject(hdcSource, hbmpSourceOld);

    SelectObject(hdcTarget, hbrTargetOld);

    hbmpCheck = SelectObject(hdcTarget, hbmpTargetOld);

    DeleteObject(hbrBackground);

    DeleteObject(hdcSource);

    DeleteObject(hdcTarget);

    /* Return the handle of the new check mark bitmap. */

    return hbmpCheck;

}

BYTE CheckOrUncheckMenuItem(bMenuItemID, hmenu)

BYTE bMenuItemID;

HMENU hmenu;

{

    DWORD fdwMenu;

    static BYTE fbAttributes;

    switch (bMenuItemID) {

        case IDM_REGULAR:

            /*

             * Whenever the Regular menu item is selected, add a

             * check mark to it and then remove check marks from

             * any font-attribute menu items.

             */

            CheckMenuItem(hmenu, IDM_REGULAR, MF_BYCOMMAND |

                MF_CHECKED);

            if (fbAttributes & ATTRIBMASK) {

                CheckMenuItem(hmenu, IDM_BOLD, MF_BYCOMMAND |

                    MF_UNCHECKED);

                CheckMenuItem(hmenu, IDM_ITALIC, MF_BYCOMMAND |

                    MF_UNCHECKED);

                CheckMenuItem(hmenu, IDM_ULINE, MF_BYCOMMAND |

                    MF_UNCHECKED);

            }

            fbAttributes = IDM_REGULAR;

            return fbAttributes;

        case IDM_BOLD:

        case IDM_ITALIC:

        case IDM_ULINE:

            /*

             * Toggle the check mark for the selected menu item and

             * set the font attribute flags appropriately.

             */

            fdwMenu = GetMenuState(hmenu, (UINT) bMenuItemID,

                MF_BYCOMMAND);

            if (!(fdwMenu & MF_CHECKED)) {

                CheckMenuItem(hmenu, (UINT) bMenuItemID,

                    MF_BYCOMMAND | MF_CHECKED);

                fbAttributes |= bMenuItemID;

            } else {

                CheckMenuItem(hmenu, (UINT) bMenuItemID,

                    MF_BYCOMMAND | MF_UNCHECKED);

                fbAttributes ^= bMenuItemID;

            }

            /*

             * If any font attributes are currently selected,

             * remove the check mark from the Regular menu item;

             * if no attributes are selected, add a check mark

             * to the Regular menu item.

             */

            if (fbAttributes & ATTRIBMASK) {

                CheckMenuItem(hmenu, IDM_REGULAR,

                    MF_BYCOMMAND | MF_UNCHECKED);

                fbAttributes &= (BYTE) ~IDM_REGULAR;

            } else {

                CheckMenuItem(hmenu, IDM_REGULAR,

                    MF_BYCOMMAND | MF_CHECKED);

                fbAttributes = IDM_REGULAR;

            }

            return fbAttributes;

    }

}


Menu Reference

The following functions and messages are associated with menus.


Menu Functions

Following are the Windows functions used with menus.

AppendMenu
CheckMenuItem
CheckMenuRadioItem
CreateMenu
CreatePopupMenu
DeleteMenu
DestroyMenu
DrawMenuBar
EnableMenuItem
GetMenu
GetMenuCheckMarkDimensions
GetMenuDefaultItem
GetMenuItemCount
GetMenuItemID
GetMenuItemInfo
GetMenuItemRect
GetMenuState
GetMenuString
GetSubMenu
GetSystemMenu
HiliteMenuItem
InsertMenu
InsertMenuItem
IsMenu
LoadMenu
LoadMenuIndirect
MenuItemFromPoint
ModifyMenu
RemoveMenu
SetMenu
SetMenuDefaultItem
SetMenuItemBitmaps
SetMenuItemInfo
TrackPopupMenu
TrackPopupMenuEx

Obsolete or Deleted Functions

ChangeMenu


Menu Messages

Following are the Windows messages used with menus.

WM_CONTEXTMENU
WM_DRAWITEM
WM_ENTERMENULOOP
WM_EXITMENULOOP
WM_INITMENU
WM_INITMENUPOPUP
WM_MEASUREITEM
WM_MENUCHAR
WM_MENUSELECT
WM_SYSCOMMAND


Hooks

A hook is a point in the Microsoft® Windows® message-handling mechanism where an application can install a subroutine to monitor the message traffic in the system and process certain types of messages before they reach the target window procedure.

This overview describes Windows hooks and explains how to use them in a Windows-based application.


About Hooks

Hooks tend to slow down the system because they increase the amount of processing the system must perform for each message. You should install a hook only when necessary, and remove it as soon as possible.


Hook Chains

Windows contains many different types of hooks; each type provides access to a different aspect of the Windows message-handling mechanism. For example, an application can use the WH_MOUSE hook to monitor the message traffic for mouse messages.

Windows maintains a separate hook chain for each type of hook. A hook chain is a list of pointers to special, application-defined callback functions called hook procedures. When a message occurs that is associated with a particular type of hook, Windows passes the message to each hook procedure referenced in the hook chain, one after the other. The action a hook procedure can take depends on the type of hook involved. The hook procedures for some types of hooks can only monitor messages; others can modify messages or stop their progress though the chain, preventing them from reaching the next hook procedure or the destination window.


Hook Procedures

To take advantage of a particular type of hook, the developer provides a hook procedure and uses the SetWindowsHookEx function to install it into the chain associated with the hook. A hook procedure must have the following syntax:

LRESULT CALLBACK HookProc(nCode, wParam, lParam)
int nCode;
WPARAM wParam;
LPARAM lParam;

HookProc is a placeholder for an application-defined name. Because Windows must call the hook procedure, the actual name must be exported by listing it and, optionally, its ordinal value, in the EXPORTS statement of the application's module-definition file.

The nCode parameter is a hook code that the hook procedure uses to determine the action to perform. The value of the hook code depends on the type of the hook; each type has its own characteristic set of hook codes. The values of the wParam and lParam parameters depend on the hook code, but they typically contain information about a message that was sent or posted.

SetWindowsHookEx always installs a hook procedure at the beginning of a hook chain. When an event occurs that is monitored by a particular type of hook, Windows calls the procedure at the beginning of the hook chain associated with the hook. Each hook procedure in the chain determines whether to pass the event to the next procedure. A hook procedure passes an event to the next procedure by calling the CallNextHookEx function.

Note that the hook procedures for some types of hooks can only monitor messages. Windows passes messages to each hook procedure, regardless of whether a particular procedure calls CallNextHookEx.

A hook procedure can be global, monitoring messages for all threads in the system, or it can be thread specific, monitoring messages for only an individual thread. A global hook procedure can be called in the context of any application, so the procedure must be in a separate dynamic-link library (DLL) module. A thread specific hook procedure is called only in the context of the associated thread. If an application installs a hook procedure for one of its own threads, the hook procedure can be in either the same module as the rest of the application's code or in a DLL. If the application installs a hook procedure for a thread of a different application, the procedure must be in a DLL. For information about DLLs, see Dynamic-Link Libraries.

Note  You should use global hooks only for debugging purposes; otherwise, you should avoid them. Global hooks hurt system performance and cause conflicts with other applications that implement the same type of global hook.


Hook Types

Each type of hook enables an application to monitor a different aspect of the Windows message-handling mechanism. The following sections describe the types of hooks available in Windows.


WH_CALLWNDPROC and WH_CALLWNDPROCRET Hooks

The WH_CALLWNDPROC and WH_CALLWNDPROCRET hooks enable an application to monitor messages sent to window procedures by the SendMessage function. Windows calls a WH_CALLWNDPROC hook procedure before passing the message to the receiving window procedure, and calls the WH_CALLWNDPROCRET hook procedure after the window procedure has processed the message.

The WH_CALLWNDPROCRET hook passes the address of a CWPRETSTRUCT structure to the hook procedure. The structure contains the return value from the window procedure that processed the message, as well as the message parameters associated with the message. In previous versions of Windows, an application that needed the return value had to set a WH_CALLWNDPROC hook and subclass the window when the hook was called. However, subclassing does not work for messages set between processes.


WH_CBT Hook

Windows calls a WH_CBT hook procedure before activating, creating, destroying, minimizing, maximizing, moving, or sizing a window; before completing a system command; before removing a mouse or keyboard event from the system message queue; before setting the input focus; or before synchronizing with the system message queue. The value the hook procedure returns determines whether Windows allows or prevents one of these operations. The WH_CBT hook is intended primarily for Windows computer-based training (CBT) applications.


WH_DEBUG Hook

Windows calls a WH_DEBUG hook procedure before calling hook procedures associated with any other hook in the system. An application can use this hook to determine whether to allow the system to call hook procedures associated with other types of hooks.


WH_FOREGROUNDIDLE Hook

The WH_FOREGROUNDIDLE hook enables an application to peform low priority tasks during times when its foreground thread is idle. Windows calls a WH_FOREGROUNDIDLE hook procedure when the application's foreground thread is about to become idle.


WH_GETMESSAGE Hook

The WH_GETMESSAGE hook enables an application to monitor messages about to be returned by the GetMessage or PeekMessage function. An application uses the WH_GETMESSAGE hook to monitor mouse and keyboard input and other messages posted to a queue.


WH_JOURNALRECORD Hook

The WH_JOURNALRECORD hook enables an application to monitor and record input events. Typically, an application uses this hook to record a sequence of mouse and keyboard events it can play back later by using the WH_JOURNALPLAYBACK hook. The WH_JOURNALRECORD hook is a global hook — it cannot be used as a thread-specific hook.


WH_JOURNALPLAYBACK Hook

The WH_JOURNALPLAYBACK hook enables an application to insert messages into the system message queue. An application might use this hook to play back a series of mouse and keyboard events recorded earlier by using the WH_JOURNALRECORD hook. Regular mouse and keyboard input is disabled as long as a WH_JOURNALPLAYBACK hook is installed. A WH_JOURNALPLAYBACK hook is a global hook — it cannot be used as a thread-specific hook.

The WH_JOURNALPLAYBACK hook returns a time-out value. This value tells the system how many milliseconds to wait before processing the current message from the playback hook. This enables the hook to control the timing of the events it plays back.


WH_KEYBOARD Hook

The WH_KEYBOARD hook enables an application to monitor message traffic for WM_KEYDOWN and WM_KEYUP messages about to be returned by the GetMessage or PeekMessage function. An application uses the WH_KEYBOARD hook to monitor keyboard input posted to a message queue.


WH_MOUSE Hook

The WH_MOUSE hook enables an application to monitor mouse messages about to be returned by the GetMessage or PeekMessage function. An application uses the WH_MOUSE hook to monitor mouse input posted to a message queue.


WH_MSGFILTER and WH_SYSMSGFILTER Hooks

The WH_MSGFILTER and WH_SYSMSGFILTER hooks enable an application to monitor messages about to be processed by a menu, scroll bar, message box, or dialog box, and to detect when a different window is about to be activated as a result of the user's pressing the ALT+TAB or ALT+ESC key combination. The WH_MSGFILTER hook can monitor only messages passed to a menu, scroll bar, message box, or dialog box created by the application that installed the hook procedure. The WH_SYSMSGFILTER hook monitors such messages for all applications.

The WH_MSGFILTER and WH_SYSMSGFILTER hooks enable an application to perform message filtering during modal loops that is equivalent to the filtering done in the main message loop. For example, an application often examines a new message in the main loop between the time it retrieves the message from the queue and the time it dispatches the message, performing special processing as appropriate. However, during a modal loop, the system retrieves and dispatches messages without allowing an application the chance to filter the messages in its main message loop. If an application installs a WH_MSGFILTER or WH_SYSMSGFILTER hook procedure, the system calls the procedure during the modal loop. For more information about modal loops, see Windows.

An application can call the WH_MSGFILTER hook directly by calling the CallMsgFilter function. By using this function, the application can use the same code to filter messages during modal loops as it uses in the main message loop. To do so, the application encapsulates the filtering operations in a WH_MSGFILTER hook procedure and calls CallMsgFilter between the calls to the GetMessage and DispatchMessage functions.

while (GetMessage(&msg, (HWND) NULL, 0, 0)) {

    if (!CallMsgFilter(&qmsg, 0))

        DispatchMessage(&qmsg);

}

The last argument of CallMsgFilter is simply passed to the hook procedure; the application can enter any value. The hook procedure, by defining a constant such as MSGF_MAINLOOP, can use this value to determine where the procedure was called from.


WH_SHELL Hook

A Windows shell application can use the WH_SHELL hook to receive important notifications. Windows calls a WH_SHELL hook procedure when the shell application is about to be activated and when a top-level window is created or destroyed.


Using Hooks

•	Installing and Releasing Hook Procedures

•	Monitoring System Events


Installing and Releasing Hook Procedures

You can install a hook procedure by calling the SetWindowsHookEx function and specifying the type of hook calling the procedure, whether the procedure should be associated with all threads or with a particular thread, and a pointer to a procedure entry point.

You must place a global hook procedure in a DLL separate from the application installing the hook procedure. The installing application must have the handle of the DLL module before it can install the hook procedure. The LoadLibrary function, when given the name of the DLL, returns the handle of the DLL module. After you have the handle, you can call the GetProcAddress function to retrieve the address of the hook procedure. Finally, you use SetWindowsHookEx to install the hook procedure address in the appropriate hook chain. SetWindowsHookEx passes the module handle, a pointer to the hook-procedure entry point, and 0 for the thread identifier, indicating that the hook procedure should be associated with all threads in the system. This sequence is shown in the following example.

HOOKPROC hkprcSysMsg;

static HINSTANCE hinstDLL;

static HHOOK hhookSysMsg;

    .

    .

    .

hinstDLL = LoadLibrary((LPCTSTR) "c:\\windows\\sysmsg.dll");

hkprcSysMsg = (HOOKPROC)GetProcAddress(hinstDLL, "SysMessageProc");

hhookSysMsg = SetWindowsHookEx(WH_SYSMSGFILTER,

    hkprcSysMsg, hinstDLL, 0);

    .

    .

    .

You can release a thread-specific hook procedure (remove its address from the hook chain) by calling the UnhookWindowsHookEx function, specifying the handle of the hook procedure to release. Release a hook procedure as soon as your application no longer needs it.

You can release a global hook procedure by using UnhookWindowsHookEx, but this function does not free the DLL containing the hook procedure. This is because global hook procedures are called in the process context of every Windows-based application in the system, causing an implicit call to the LoadLibrary function for all of those processes. Because a call to the FreeLibrary function cannot be made for another process, there is then no way to free the DLL. Windows eventually frees the DLL after all processes explicitly linked to the DLL have either terminated or called FreeLibrary and all processes that called the hook procedure have resumed processing outside the DLL.

An alternative method for installing a global hook procedure is to provide an installation function in the DLL, along with the hook procedure. With this method, the installing application does not need the handle of the DLL module. By linking with the DLL, the application gains access to the installation function. The installation function can supply the DLL module handle and other details in the call to SetWindowsHookEx. The DLL can also contain a function that releases the global hook procedure; the application can call this hook-releasing function when terminating.


Monitoring System Events

The example in this section uses a variety of thread-specific hook procedures to monitor the system for events affecting a thread. It demonstrates how to process events for the following types of hook procedures:

WH_CALLWNDPROC
WH_CBT
WH_DEBUG
WH_GETMESSAGE
WH_KEYBOARD
WH_MOUSE
WH_MSGFILTER

In this example, the user can install and remove a hook procedure by using the menu. When a hook procedure is installed and an event that is monitored by the procedure occurs, the procedure writes information about the event to the client area of the application's main window.

#define NUMHOOKS 7

/* Global variables */

typedef struct _MYHOOKDATA {

    int nType;

    HOOKPROC hkprc;

    HHOOK hhook;

} MYHOOKDATA;

MYHOOKDATA myhookdata[NUMHOOKS];

LONG APIENTRY MainWndProc(hwndMain, uMsg, wParam, lParam)

HWND hwndMain;

UINT uMsg;

UINT wParam;

LONG lParam;

{

    static BOOL afHooks[NUMHOOKS];

    int index;

    static HMENU hmenu;

    switch (uMsg) {

        case WM_CREATE:

            /* Save the menu handle. */

            hmenu = GetMenu(hwndMain);

            /*

             * Initialize structures with hook data. The menu-item

             * identifiers are defined as 0 through 6 in the

             * header file. They can be used to identify array

             * elements both here and during the WM_COMMAND

             * message.

             */

            myhookdata[IDM_CALLWNDPROC].nType = WH_CALLWNDPROC;

            myhookdata[IDM_CALLWNDPROC].hkprc = CallWndProc;

            myhookdata[IDM_CBT].nType = WH_CBT;

            myhookdata[IDM_CBT].hkprc = CBTProc;

            myhookdata[IDM_DEBUG].nType = WH_DEBUG;

            myhookdata[IDM_DEBUG].hkprc = DebugProc;

            myhookdata[IDM_GETMESSAGE].nType = WH_GETMESSAGE;

            myhookdata[IDM_GETMESSAGE].hkprc = GetMsgProc;

            myhookdata[IDM_KEYBOARD].nType = WH_KEYBOARD;

            myhookdata[IDM_KEYBOARD].hkprc = KeyboardProc;

            myhookdata[IDM_MOUSE].nType = WH_MOUSE;

            myhookdata[IDM_MOUSE].hkprc = MouseProc;

            myhookdata[IDM_MSGFILTER].nType = WH_MSGFILTER;

            myhookdata[IDM_MSGFILTER].hkprc = MessageProc;

            /* Initialize all flags in the array to FALSE. */

            memset(afHooks, FALSE, sizeof(afHooks));

            return 0;

        case WM_COMMAND:

            switch (LOWORD(wParam)) {

                /*

                 * The user selected a hook command from the menu.

                 */

                case IDM_CALLWNDPROC:

                case IDM_CBT:

                case IDM_DEBUG:

                case IDM_GETMESSAGE:

                case IDM_KEYBOARD:

                case IDM_MOUSE:

                case IDM_MSGFILTER:

                    /*

                     * Use the menu-item identifier as an index

                     * into the array of structures with hook data.

                     */

                    index = LOWORD(wParam);

                    /*

                     * If the selected type of hook procedure isn't

                     * installed yet, install it and check the

                     * associated menu item.

                     */

                    if (!afHooks[index]) {

                        myhookdata[index].hhook = SetWindowsHookEx(

                            myhookdata[index].nType,

                            myhookdata[index].hkprc,

                            (HINSTANCE) NULL, GetCurrentThreadId());

                        CheckMenuItem(hmenu, index,

                            MF_BYCOMMAND | MF_CHECKED);

                        afHooks[index] = TRUE;

                    }

                    /*

                     * If the selected type of hook procedure is

                     * already installed, remove it and remove the

                     * check mark from the associated menu item.

                     */

                    else {

                        UnhookWindowsHookEx(myhookdata[index].hhook);

                        CheckMenuItem(hmenu, index,

                            MF_BYCOMMAND | MF_UNCHECKED);

                        afHooks[index] = FALSE;

                    }

                default:

                    return (DefWindowProc(hwndMain, uMsg, wParam,

                        lParam));

            }

            break;

            .

            . /* Process other messages. */

            .

        default:

            return DefWindowProc(hwndMain, uMsg, wParam, lParam);

    }

    return NULL;

}

/****************************************************************

  WH_CALLWNDPROC hook procedure

 ****************************************************************/

LRESULT CALLBACK CallWndProc(nCode, wParam, lParam)

int nCode;

WPARAM wParam;

LPARAM lParam;

{

    CHAR szCWPBuf[256];

    CHAR szMsg[16];

    HDC hdc;

    static int c = 0;

    int cch;

    if (nCode < 0)  /* do not process message */

        return CallNextHookEx(myhookdata[CALLWNDPROC].hhook, nCode,

                wParam, lParam);

    /*

     * Call an application-defined function that converts a message

     * constant to a string and copies it to a buffer.

     */

    LookUpTheMessage((PMSG) lParam, szMsg);

    hdc = GetDC(hwndMain);

    switch (nCode) {

        case HC_ACTION:

            cch = wsprintf(szCWPBuf,

               "CALLWNDPROC - tsk: %ld, msg: %s, %d times   ",

                wParam, szMsg, c++);

            TextOut(hdc, 2, 15, szCWPBuf, cch);

            break;

        default:

            break;

    }

    ReleaseDC(hwndMain, hdc);

    return CallNextHookEx(myhookdata[CALLWNDPROC].hhook, nCode,

        wParam, lParam);

}

/****************************************************************

  WH_GETMESSAGE hook procedure

 ****************************************************************/

LRESULT CALLBACK GetMsgProc(nCode, wParam, lParam)

int nCode;

WPARAM wParam;

LPARAM lParam;

{

    CHAR szMSGBuf[256];

    CHAR szRem[16];

    CHAR szMsg[16];

    HDC hdc;

    static int c = 0;

    int cch;

    if (nCode < 0) /* do not process message */

        return CallNextHookEx(myhookdata[GETMESSAGE].hhook, nCode,

            wParam, lParam);

    switch (nCode) {

        case HC_ACTION:

            switch (wParam) {

                case PM_REMOVE:

                    lstrcpy(szRem, "PM_REMOVE");

                    break;

                case PM_NOREMOVE:

                    lstrcpy(szRem, "PM_NOREMOVE");

                    break;

                default:

                    lstrcpy(szRem, "Unknown");

                    break;

            }

            /*

             * Call an application-defined function that converts a

             * message constant to a string and copies it to a

             * buffer.

             */

            LookUpTheMessage((PMSG) lParam, szMsg);

            hdc = GetDC(hwndMain);

            cch = wsprintf(szMSGBuf,

                "GETMESSAGE - wParam: %s, msg: %s, %d times   ",

                szRem, szMsg, c++);

            TextOut(hdc, 2, 35, szMSGBuf, cch);

            break;

        default:

            break;

    }

    ReleaseDC(hwndMain, hdc);

    return CallNextHookEx(myhookdata[GETMESSAGE].hhook, nCode,

        wParam, lParam);

}

/****************************************************************

  WH_DEBUG hook procedure

 ****************************************************************/

LRESULT CALLBACK DebugProc(nCode, wParam, lParam)

int nCode;

WPARAM wParam;

LPARAM lParam;

{

    CHAR szBuf[128];

    HDC hdc;

    static int c = 0;

    int cch;

    if (nCode < 0)  /* do not process message */

        return CallNextHookEx(myhookdata[DEBUG].hhook, nCode,

            wParam, lParam);

    hdc = GetDC(hwndMain);

    switch (nCode) {

        case HC_ACTION:

            cch = wsprintf(szBuf,

                "DEBUG - nCode: %d, tsk: %ld, %d times   ",

                nCode,wParam, c++);

            TextOut(hdc, 2, 55, szBuf, cch);

            break;

        default:

            break;

    }

    ReleaseDC(hwndMain, hdc);

    return CallNextHookEx(myhookdata[DEBUG].hhook, nCode, wParam,

        lParam);

}

/****************************************************************

  WH_CBT hook procedure

 ****************************************************************/

LRESULT CALLBACK CBTProc(nCode, wParam, lParam)

int nCode;

WPARAM wParam;

LPARAM lParam;

{

    CHAR szBuf[128];

    CHAR szCode[128];

    HDC hdc;

    static int c = 0;

    int cch;

    if (nCode < 0)  /* do not process message */

        return CallNextHookEx(myhookdata[CBT].hhook, nCode, wParam,

            lParam);

    hdc = GetDC(hwndMain);

    switch (nCode) {

        case HCBT_ACTIVATE:

            lstrcpy(szCode, "HCBT_ACTIVATE");

            break;

        case HCBT_CLICKSKIPPED:

            lstrcpy(szCode, "HCBT_CLICKSKIPPED");

            break;

        case HCBT_CREATEWND:

            lstrcpy(szCode, "HCBT_CREATEWND");

            break;

        case HCBT_DESTROYWND:

            lstrcpy(szCode, "HCBT_DESTROYWND");

            break;

        case HCBT_KEYSKIPPED:

            lstrcpy(szCode, "HCBT_KEYSKIPPED");

            break;

        case HCBT_MINMAX:

            lstrcpy(szCode, "HCBT_MINMAX");

            break;

        case HCBT_MOVESIZE:

            lstrcpy(szCode, "HCBT_MOVESIZE");

            break;

        case HCBT_QS:

            lstrcpy(szCode, "HCBT_QS");

            break;

        case HCBT_SETFOCUS:

            lstrcpy(szCode, "HCBT_SETFOCUS");

            break;

        case HCBT_SYSCOMMAND:

            lstrcpy(szCode, "HCBT_SYSCOMMAND");

            break;

        default:

            lstrcpy(szCode, "Unknown");

            break;

    }

    cch = wsprintf(szBuf, "CBT - nCode: %s, tsk: %ld, %d times   ",

        szCode, wParam, c++);

    TextOut(hdc, 2, 75, szBuf, cch);

    ReleaseDC(hwndMain, hdc);

    return CallNextHookEx(myhookdata[CBT].hhook, nCode, wParam,

        lParam);

}

/****************************************************************

  WH_MOUSE hook procedure

 ****************************************************************/

LRESULT CALLBACK MouseProc(nCode, wParam, lParam)

int nCode;

WPARAM wParam;

LPARAM lParam;

{

    CHAR szBuf[128];

    CHAR szMsg[16];

    HDC hdc;

    static int c = 0;

    int cch;

    if (nCode < 0)  /* do not process the message */

        return CallNextHookEx(myhookdata[MOUSE].hhook, nCode,

            wParam, lParam);

    /*

     * Call an application-defined function that converts a message

     * constant to a string and copies it to a buffer.

     */

    LookUpTheMessage((PMSG) lParam, szMsg);

    hdc = GetDC(hwndMain);

    cch = wsprintf(szBuf,

        "MOUSE - nCode: %d, msg: %s, x: %d, y: %d, %d times   ",

        nCode, szMsg, LOWORD(lParam), HIWORD(lParam), c++);

    TextOut(hdc, 2, 95, szBuf, cch);

    ReleaseDC(hwndMain, hdc);

    return CallNextHookEx(myhookdata[MOUSE].hhook, nCode, wParam,

        lParam);

}

/****************************************************************

  WH_KEYBOARD hook procedure

 ****************************************************************/

LRESULT CALLBACK KeyboardProc(nCode, wParam, lParam)

int nCode;

WPARAM wParam;

LPARAM lParam;

{

    CHAR szBuf[128];

    HDC hdc;

    static int c = 0;

    int cch;

    if (nCode < 0)  /* do not process message */

        return CallNextHookEx(myhookdata[KEYBOARD].hhook, nCode,

            wParam, lParam);

    hdc = GetDC(hwndMain);

    cch = wsprintf(szBuf, "KEYBOARD - nCode: %d, vk: %d, %d times ",

        nCode, wParam, c++);

    TextOut(hdc, 2, 115, szBuf, cch);

    ReleaseDC(hwndMain, hdc);

    return CallNextHookEx(myhookdata[KEYBOARD].hhook, nCode, wParam,

        lParam);

}

/****************************************************************

  WH_MSGFILTER hook procedure

 ****************************************************************/

LRESULT CALLBACK MessageProc(nCode, wParam, lParam)

int nCode;

WPARAM wParam;

LPARAM lParam;

{

    CHAR szBuf[128];

    CHAR szMsg[16];

    CHAR szCode[32];

    HDC hdc;

    static int c = 0;

    int cch;

    if (nCode < 0)  /* do not process message */

        return CallNextHookEx(myhookdata[MSGFILTER].hhook, nCode,

            wParam, lParam);

    switch (nCode) {

        case MSGF_DIALOGBOX:

            lstrcpy(szCode, "MSGF_DIALOGBOX");

            break;

        case MSGF_MENU:

            lstrcpy(szCode, "MSGF_MENU");

            break;

        case MSGF_SCROLLBAR:

            lstrcpy(szCode, "MSGF_SCROLLBAR");

            break;

        case MSGF_NEXTWINDOW:

            lstrcpy(szCode, "MSGF_NEXTWINDOW");

            break;

        default:

            wsprintf(szCode, "Unknown: %d", nCode);

            break;

    }

    /*

     * Call an application-defined function that converts a message

     * constant to a string and copies it to a buffer.

     */

    LookUpTheMessage((PMSG) lParam, szMsg);

    hdc = GetDC(hwndMain);

    cch = wsprintf(szBuf,

        "MSGFILTER  nCode: %s, msg: %s, %d times    ",

        szCode, szMsg, c++);

    TextOut(hdc, 2, 135, szBuf, cch);

    ReleaseDC(hwndMain, hdc);

    return CallNextHookEx(myhookdata[MSGFILTER].hhook, nCode,

        wParam, lParam);

}


Hook Reference

The following functions and messages are associated with hooks.


Hook Functions

Following are the functions used with hooks.

CallMsgFilter
CallNextHookEx
CallWndProc
CBTProc
DebugProc
GetMsgProc
JournalPlaybackProc
JournalRecordProc
KeyboardProc
MessageProc
MouseProc
SetWindowsHookEx
ShellProc
SysMsgProc
UnhookWindowsHookEx

Obsolete or Deleted Functions

DefHookProc
SetWindowsHook
UnhookWindowsHook


Hook Messages

Following are the messages used with hooks.

WM_QUEUESYNC


Icons

An icon is a picture that consists of a bitmapped image combined with a mask to create transparent areas in the picture. This overview describes creating, displaying, destroying, and duplicating icons.


About Icons

Windows uses icons throughout the user interface to represent objects such as files, printers, applications, and windows. The icon functions in the Microsoft® Win32® application programming interface (API) enable applications to create, load, display, arrange, and destroy icons.

The operating system provides a set of standard icons that are available for any application to use at any time. The Windows header files contain identifiers for the standard icons — the identifiers begin with the "IDI_" prefix.

Each standard icon has a corresponding default image associated with it. The user can replace the default image associated with any standard cursor at any time.

An application can retrieve the image for a cursor by using the GetIconInfo function, and can draw it by using the DrawIconEx function. To draw the default image for a cursor, specify the DI_COMPAT flag in the call to DrawIconEx. If you do not specify the DI_COMPAT flag, DrawIconEx draws the cursor using the image that the user specified.

Custom icons are designed for use in a particular application and can be any design the developer defines. Following are several custom icons.


The Iconic Hot Spot

One of the pixels in an icon is designated as the hot spot, which is the point the system tracks and recognizes as the position of the icon. An icon's hot spot is typically the pixel located at the center of the icon. If you use the CreateIconIndirect function to create an icon, you can specify any pixel to be the hot spot.


Icon Creation

Standard icons are predefined in Win32, so it is not necessary to create them. To use a standard icon, an application can obtain its handle by using the LoadImage function. An icon handle is a unique value of the HICON type that identifies a standard or custom icon.

To create a custom icon for an application, developers typically use a graphics application and include the icon as a resource in the application's resource-definition file. At run time, an application can call LoadIcon or LoadImage to retrieve the handle of the icon. An icon resource contains data for several different display devices. LoadIcon and LoadImage automatically select the most appropriate data for the current display device.

An application can also create a custom icon at run time by using the CreateIconIndirect function, which creates an icon based on the contents of an ICONINFO structure. The GetIconInfo function fills the structure with the hot spot coordinates and information about the bitmask bitmap and color bitmap for the icon.

Applications should implement custom icons as resources and should use LoadIcon or LoadImage, rather than create the icon at run time. Using icon resources avoids device dependence, simplifies localization, and enables applications to share icon shapes.

The CreateIconFromResourceEx function enables an application to browse through the system's resources and create icons and cursors based on resource data. CreateIconFromResourceEx creates an icon based on binary resource data from other executable files or dynamic-link libraries (DLLs). An application must precede this function with calls to the LookupIconIdFromDirectoryEx function and several of the resource functions. LookupIconIdFromDirectoryEx returns the identifier of the most appropriate icon data for the current display device. For more information about the resource functions, see Resources.


Icon Display

Once an application has loaded an icon, it can use the DrawIcon or DrawIconEx functions to draw the icon.

When registering a window class, an application can assign one or two icons to the class, depending on the operating system version. A class icon is a picture that the system uses to represent a window of a particular class. For more information about class icons, see Window Classes.


Icon Destruction

When an application no longer needs an icon it created by using the CreateIconIndirect (or CreateIcon) function, it should destroy the icon. The DestroyIcon function destroys the icon handle and frees any memory used by the icon. Applications should use this function only for icons created with CreateIconIndirect; it is not necessary to destroy other icons.


Icon Duplication

The CopyIcon function copies an icon handle. This enables an application or DLL to get its own handle for an icon owned by another module. Then, if the other module is freed, the application that copied the icon will still be able to use the icon.

The CopyImage function creates a new icon based on the specified source icon. The new icon can be larger or smaller than the source icon.

For information about adding, removing, or replacing icon resources in executable (.EXE) files, see Resources.


Using Icons

•	Creating an icon

•	Displaying an icon

•	Using icon functions to create a mousetrap

•	Sharing icon resources


Creating an Icon

To use an icon, your application must get the handle of the icon. The following example shows how to create two different icon handles: one for the standard exclamation icon and one for a custom icon included as a resource in the application's resource-definition file.

HICON hIcon1;   /* icon handle            */

HICON hIcon2;   /* icon handle            */

/* Create a standard question icon. */

hIcon1 = LoadIcon(NULL, IDI_QUESTION);

/* Create a custom icon based on a resource. */

hIcon2 = LoadIcon(hinst, MAKEINTRESOURCE(460));

/* Create a custom icon at run time. */

An application should implement custom icons as resources and should use the LoadIcon or LoadImage function, rather than create the icons at run time. This approach avoids device dependence, simplifies localization, and enables applications to share icon bitmaps. However, the following example uses CreateIcon to create a custom icon at run time, based on bitmap bitmasks; it is included to illustrate how the system interprets icon bitmap bitmasks.

HICON hIcon3;               /* icon handle        */

/* Yang icon AND bitmask */

BYTE ANDmaskIcon[] = {0xFF, 0xFF, 0xFF, 0xFF,   /* line 1 */

                      0xFF, 0xFF, 0xC3, 0xFF,   /* line 2 */

                      0xFF, 0xFF, 0x00, 0xFF,   /* line 3 */

                      0xFF, 0xFE, 0x00, 0x7F,   /* line 4 */

                      0xFF, 0xFC, 0x00, 0x1F,   /* line 5 */

                      0xFF, 0xF8, 0x00, 0x0F,   /* line 6 */

                      0xFF, 0xF8, 0x00, 0x0F,   /* line 7 */

                      0xFF, 0xF0, 0x00, 0x07,   /* line 8 */

                      0xFF, 0xF0, 0x00, 0x03,   /* line 9 */

                      0xFF, 0xE0, 0x00, 0x03,   /* line 10 */

                      0xFF, 0xE0, 0x00, 0x01,   /* line 11 */

                      0xFF, 0xE0, 0x00, 0x01,   /* line 12 */

                      0xFF, 0xF0, 0x00, 0x01,   /* line 13 */

                      0xFF, 0xF0, 0x00, 0x00,   /* line 14 */

                      0xFF, 0xF8, 0x00, 0x00,   /* line 15 */

                      0xFF, 0xFC, 0x00, 0x00,   /* line 16 */

                      0xFF, 0xFF, 0x00, 0x00,   /* line 17 */

                      0xFF, 0xFF, 0x80, 0x00,   /* line 18 */

                      0xFF, 0xFF, 0xE0, 0x00,   /* line 19 */

                      0xFF, 0xFF, 0xE0, 0x01,   /* line 20 */

                      0xFF, 0xFF, 0xF0, 0x01,   /* line 21 */

                      0xFF, 0xFF, 0xF0, 0x01,   /* line 22 */

                      0xFF, 0xFF, 0xF0, 0x03,   /* line 23 */

                      0xFF, 0xFF, 0xE0, 0x03,   /* line 24 */

                      0xFF, 0xFF, 0xE0, 0x07,   /* line 25 */

                      0xFF, 0xFF, 0xC0, 0x0F,   /* line 26 */

                      0xFF, 0xFF, 0xC0, 0x0F,   /* line 27 */

                      0xFF, 0xFF, 0x80, 0x1F,   /* line 28 */

                      0xFF, 0xFF, 0x00, 0x7F,   /* line 29 */

                      0xFF, 0xFC, 0x00, 0xFF,   /* line 30 */

                      0xFF, 0xF8, 0x03, 0xFF,   /* line 31 */

                      0xFF, 0xFC, 0x3F, 0xFF};  /* line 32 */

/* Yang icon XOR bitmask */

BYTE XORmaskIcon[] = {0x00, 0x00, 0x00, 0x00,   /* line 1 */

                      0x00, 0x00, 0x00, 0x00,   /* line 2 */

                      0x00, 0x00, 0x00, 0x00,   /* line 3 */

                      0x00, 0x00, 0x00, 0x00,   /* line 4 */

                      0x00, 0x00, 0x00, 0x00,   /* line 5 */

                      0x00, 0x00, 0x00, 0x00,   /* line 6 */

                      0x00, 0x00, 0x00, 0x00,   /* line 7 */

                      0x00, 0x00, 0x38, 0x00,   /* line 8 */

                      0x00, 0x00, 0x7C, 0x00,   /* line 9 */

                      0x00, 0x00, 0x7C, 0x00,   /* line 10 */

                      0x00, 0x00, 0x7C, 0x00,   /* line 11 */

                      0x00, 0x00, 0x38, 0x00,   /* line 12 */

                      0x00, 0x00, 0x00, 0x00,   /* line 13 */

                      0x00, 0x00, 0x00, 0x00,   /* line 14 */

                      0x00, 0x00, 0x00, 0x00,   /* line 15 */

                      0x00, 0x00, 0x00, 0x00,   /* line 16 */

                      0x00, 0x00, 0x00, 0x00,   /* line 17 */

                      0x00, 0x00, 0x00, 0x00,   /* line 18 */

                      0x00, 0x00, 0x00, 0x00,   /* line 19 */

                      0x00, 0x00, 0x00, 0x00,   /* line 20 */

                      0x00, 0x00, 0x00, 0x00,   /* line 21 */

                      0x00, 0x00, 0x00, 0x00,   /* line 22 */

                      0x00, 0x00, 0x00, 0x00,   /* line 23 */

                      0x00, 0x00, 0x00, 0x00,   /* line 24 */

                      0x00, 0x00, 0x00, 0x00,   /* line 25 */

                      0x00, 0x00, 0x00, 0x00,   /* line 26 */

                      0x00, 0x00, 0x00, 0x00,   /* line 27 */

                      0x00, 0x00, 0x00, 0x00,   /* line 28 */

                      0x00, 0x00, 0x00, 0x00,   /* line 29 */

                      0x00, 0x00, 0x00, 0x00,   /* line 30 */

                      0x00, 0x00, 0x00, 0x00,   /* line 31 */

                      0x00, 0x00, 0x00, 0x00};  /* line 32 */

hIcon3 = CreateIcon(hinst,    /* application instance     */

             32,              /* icon width               */

             32,              /* icon height              */

             1,               /* number of XOR planes     */

             1,               /* number of bits per pixel */

             ANDmaskIcon,     /* AND bitmask              */

             XORmaskIcon);    /* XOR bitmask              */

To create the icon, CreateIcon applies the following truth table to the AND and XOR bitmasks.

AND bitmask	XOR bitmask	Display
0	0	Black
0	1	White
1	0	Screen
1	1	Reverse screen
For information about full-color bitmaps, see Bitmaps and Colors.

Before closing, your application must use DestroyIcon to destroy any icon it created by using CreateIcon. It is not necessary to destroy icons created by other functions.


Displaying an Icon

Your application can load and create icons to display in the application's client area or child windows. The following example demonstrates how to draw an icon in the client area of the window whose display context (DC) is identified by the hdc parameter.

HICON hIcon1;   /* icon handle               */

HDC hdc;        /* handle of display context */

DrawIcon(hdc, 10, 20, hIcon1);

Windows automatically displays the class icon(s) for a window. Your application can assign class icons while registering a window class. Your application can replace a class icon by using the SetClassLong function. This function changes the default window settings for all windows of a given class. The following example replaces a class icon with the icon whose resource identifier is 480.

HINSTANCE hinst;            /* handle of current instance */

HWND hwnd;                  /* main window handle         */

/* Change the icon for hwnd's window class. */

SetClassLong(hwnd,         /* window handle */

    GCL_HICON,             /* changes icon  */

    (LONG) LoadIcon(hinst, MAKEINTRESOURCE(480))); /* new */

For more information about window classes, see Window Classes.


Using Icon Functions to Create a Mousetrap

The following example applies to operating system versions earlier than 4.0. It uses IsIconic, LoadIcon, and several cursor and timer functions to create a simple mousetrap. The example uses the cursor and timer functions to monitor the location of the cursor at 10-second intervals. If the cursor location has not changed in the last 10 seconds and the application's main window is minimized, the application changes the cursor shape and moves the cursor to the icon.

HICON hIcon1;              /* icon handle                */

POINT ptOld;               /* previous cursor location   */

HCURSOR hCurs1;            /* cursor handle              */

HINSTANCE hinstance;       /* handle of current instance */

hCurs1 = LoadCursor(hinstance, MAKEINTRESOURCE(220));

.

. /* Fill in the window class structure. */

.

WNDCLASS  wc;

wc.hIcon = LoadIcon(hinstance, MAKEINTRESOURCE(470));

wc.hCursor = LoadCursor(hinstance, MAKEINTRESOURCE(240));

.

. /*

.  * Register the window class and perform

.  * other application initialization.

.  */

.

/* Set a timer for the mousetrap. */

GetCursorPos(&ptOld);

SetTimer(hwnd, IDT_CURSOR, 10000, (TIMERPROC) NULL);

LONG APIENTRY MainWndProc(

    HWND hwnd,          /* window handle            */

    UINT message,       /* type of message          */

    UINT wParam,        /* additional information   */

    LONG lParam)        /* additional information   */

{

    HDC hdc;            /* device context handle    */

    POINT pt;           /* current cursor location  */

    RECT rc;            /* iconized window location */

    switch (message) {

         .

         . /* Process other messages here. */

         .

        case WM_TIMER:

            /*

             * If the window is minimized, compare the current

             * cursor position with the one from 10 seconds

             * earlier. If the cursor position has not changed,

             * move the cursor to the icon.

             */

            if (IsIconic(hwnd)) {

                GetCursorPos(&pt);

                if ((pt.x == ptOld.x) && (pt.y == ptOld.y)) {

                    GetWindowRect(hwnd, &rc);

                    SetCursorPos(rc.left, rc.top);

                }

                else {

                    ptOld.x = pt.x;

                    ptOld.y = pt.y;

                }

            }

            return 0;

        case WM_SETCURSOR:

            /*

             * If the window is minimized, draw hCurs1.

             * If the window is not minimized, draw the default

             * cursor (class cursor).

             */

            if (IsIconic(hwnd)) {

                SetCursor(hCurs1);

                break;

            }

        case WM_DESTROY:

            /* Destroy the timer. */

            KillTimer(hwnd, IDT_CURSOR);

            PostQuitMessage(0);

            break;

                .

                . /* Process other messages here. */

                .

    }             /* ends switch (message) */

An example for a similar mousetrap is included in Cursors. That example uses CreateIcon to create the class icon.


Sharing Icon Resources

The following code uses the functions CreateIconFromResourceEx, DrawIcon, and LookupIconIdFromDirectoryEx, and several of the resource functions, to create an icon handle based on icon data from another executable file. Then, it displays the icon in a window.

HICON hIcon1;       /* icon handle                */

HINSTANCE hExe;     /* handle to loaded .EXE file */

HRSRC hResource;    /* handle for FindResource    */

HRSRC hMem;         /* handle for LoadResource    */

BYTE *lpResource;   /* address of resource data   */

int nID;            /* ID of resource that best

                       fits current screen        */

HDC hdc;        /* handle of display context */

/* Load the file from which to copy the icon. */

hExe = LoadLibrary("myapp.exe");

/* Find the icon directory whose identifier is 440. */

hResource = FindResource(hExe,

    MAKEINTRESOURCE(440),

    RT_GROUP_ICON);

/* Load and lock the icon directory. */

hMem = LoadResource(hExe, hResource);

lpResource = LockResource(hMem);

/*

 * Get the identifier of the icon that is most appropriate

 * for the video display.

 */

nID = LookupIconIdFromDirectoryEx((PBYTE) lpResource, TRUE,

    CXICON, CYICON, LR_DEFAULTCOLOR);

/* Find the bits for the nID icon. */

hResource = FindResource(hExe,

    MAKEINTRESOURCE(nID),

    MAKEINTRESOURCE(RT_ICON));

/* Load and lock the icon. */

hMem = LoadResource(hExe, hResource);

lpResource = LockResource(hMem);

/* Create a handle to the icon. */

hIcon1 = CreateIconFromResourceEx((PBYTE) lpResource,

    SizeofResource(hExe, hResource), TRUE, 0x00030000,

    CXICON, CYICON, LR_DEFAULTCOLOR);

/* Draw the icon in the client area. */

DrawIcon(hdc, 10, 20, hIcon1);


Icon Reference

The following functions and messages are associated with icons.


Icon Functions

Following are the functions used with icons.

ArrangeIconicWindows
CopyIcon
CreateIcon
CreateIconFromResource
CreateIconIndirect
DestroyIcon
DrawIcon
DrawIconEx
GetIconInfo
IsIconic
LoadIcon
LookupIconIdFromDirectory
OpenIcon


Icon Messages

Following are the messages used with icons.

WM_ERASEBKGND
WM_ICONERASEBKGND
WM_PAINTICON


Keyboard Accelerators

In Microsoft® Windows®, a keyboard accelerator (or, simply, accelerator) is a keystroke or combination of keystrokes that generates a WM_COMMAND or WM_SYSCOMMAND message for an application.


About Keyboard Accelerators

Accelerators are closely related to menus — both provide the user with access to an application's command set. Typically, users rely on an application's menus to learn the command set and then switch over to using accelerators as they become more proficient with the application. Accelerators provide faster, more direct access to commands than menus do. At a minimum, an application should provide accelerators for the more commonly used commands. Although accelerators typically generate commands that exist as menu items, they can also generate commands that have no equivalent menu items.


Accelerator Tables

An accelerator table consists of an array of ACCEL structures, each defining an individual accelerator. Each ACCEL structure includes the following information:

•	The accelerator's keystroke combination.

•	The accelerator's identifier.

•	Various flags. This includes one that specifies whether Windows is to provide visual feedback by highlighting the corresponding menu item, if any, when the accelerator is used

To process accelerator keystrokes for a given thread, the developer must call the TranslateAccelerator function in the message loop associated with the thread's message queue. The TranslateAccelerator function monitors keyboard input to the message queue, checking for key combinations that match an entry in the accelerator table. When TranslateAccelerator finds a match, it translates the keyboard input (that is, the WM_KEYUP and WM_KEYDOWN messages) into a WM_COMMAND or WM_SYSCOMMAND message and then sends the message to the window procedure of the specified window. The following illustration shows how accelerators are processed.

The WM_COMMAND message includes the identifier of the accelerator that caused TranslateAccelerator to generate the message. The window procedure examines the identifier to determine the source of the message and then processes the message accordingly.

Accelerator tables exist at two different levels in Windows. Windows maintains a single, system-wide accelerator table that applies to all applications. An application cannot modify the system accelerator table. For a description of the accelerators provided by the system accelerator table, see Accelerator Keystroke Assignments.

Windows also maintains accelerator tables for each application. An application can define any number of accelerator tables for use with its own windows. A unique 32-bit handle (HACCEL) identifies each table. However, only one accelerator table can be active at a time for a given thread. The handle of the accelerator table passed to the TranslateAccelerator function determines which accelerator table is active for a thread. The active accelerator table can be changed at any time by passing a different accelerator-table handle to TranslateAccelerator.


Accelerator-Table Creation

Several steps are required to create an accelerator table for an application. First, a resource compiler is used to create accelerator-table resources and to add them to the application's executable file. At run time, the LoadAccelerators function is used to load the accelerator table into memory and retrieve the handle of the accelerator table. This handle is passed to the TranslateAccelerator function to activate the accelerator table.

An accelerator table can also be created for an application at run time by passing an array of ACCEL structures to the CreateAcceleratorTable function. This method supports user-defined accelerators in the application. Like the LoadAccelerators function, CreateAcceleratorTable returns an accelerator-table handle that can be passed to TranslateAccelerator to activate the accelerator table.

Windows automatically destroys accelerator tables loaded by LoadAccelerators. An accelerator table created by CreateAcceleratorTable must be destroyed before an application closes; otherwise, the table continues to exist in memory after the application has closed. An accelerator table is destroyed by calling the DestroyAcceleratorTable function.

An existing accelerator table can be copied and modified. The existing accelerator table is copied by using the CopyAcceleratorTable function. After the copy is modified, a handle of the new accelerator table is retrieved by calling CreateAcceleratorTable. Finally, the handle is passed to TranslateAccelerator to activate the new table.


Accelerator Keystroke Assignments

An ASCII character code or a virtual-key code can be used to define the accelerator. An ASCII character code makes the accelerator case sensitive. The ASCII "C" character can define the accelerator as ALT+c rather than ALT+C. Case-sensitive accelerators can, however, be confusing to use. For example, the ALT+C accelerator will be generated if the CAPS LOCK key is down or if the SHIFT key is down, but not if both are down.

Typically, accelerators don't need to be case sensitive, so most applications use virtual-key codes for accelerators rather than ASCII character codes. .

Avoid accelerators that conflict with an application's menu mnemonics, because the accelerator overrides the mnemonic, which can confuse the user. For more information about menu mnemonics, see Menus (Windows NT).

If an application defines an accelerator that is also defined in the system accelerator table, the application-defined accelerator overrides the system accelerator, but only within the context of the application. Avoid this practice, however, because it prevents the system accelerator from performing its standard role in the Windows user interface. The system-wide accelerators are described in the following list:

Accelerator	Description
ALT+ESC	Switches to the next application.
ALT+F4	Closes an application or a window.
ALT+HYPHEN	Opens the System menu for a document window.
ALT+PRINT SCREEN	Copies an image in the active window onto the clipboard.
ALT+SPACEBAR	Opens the System menu for an application window.
ALT+TAB	Switches to the next application.
CTRL+ESC	Switches to Windows Task List.
CTRL+F4	Closes the active group or document window.
F1	Starts Help if the application has Help.
PRINT SCREEN	Copies an image on the screen onto the clipboard.
SHIFT+ALT+TAB	Switches to the previous application. The user must press and hold down ALT+SHIFT while pressing TAB.


Accelerators and Menus

Using an accelerator is the same as choosing a menu item: Both actions cause Windows to send a WM_COMMAND or WM_SYSCOMMAND message to the corresponding window procedure. The WM_COMMAND message includes an identifier that the window procedure examines to determine the source of the message. If an accelerator generated the WM_COMMAND message, the identifier is that of the accelerator. Similarly, if a menu item generated the WM_COMMAND message, the identifier is that of the menu item. Because an accelerator provides a shortcut for choosing a command from a menu, an application usually assigns the same identifier to the accelerator and the corresponding menu item.

An application processes an accelerator WM_COMMAND message in exactly the same way as the corresponding menu item WM_COMMAND message. However, the WM_COMMAND message contains a flag that specifies whether the message originated from an accelerator or a menu item, in case accelerators must be processed differently from their corresponding menu items. The WM_SYSCOMMAND message does not contain this flag.

The identifier determines whether an accelerator generates a WM_COMMAND or WM_SYSCOMMAND message. If the identifier has the same value as a menu item in the System menu, the accelerator generates a WM_SYSCOMMAND message. Otherwise, the accelerator generates a WM_COMMAND message.

If an accelerator has the same identifier as a menu item and the menu item is grayed or disabled, the accelerator is disabled and does not generate a WM_COMMAND or WM_SYSCOMMAND message. Also, an accelerator does not generate a command message if the corresponding window is minimized.

When the user uses an accelerator that corresponds to a menu item, the window procedure receives the WM_INITMENU and WM_INITMENUPOPUP messages as though the user had selected the menu item. For information about how to process these messages, see Menus (Windows NT).

An accelerator that corresponds to a menu item should be included in the text of the menu item.


Using Keyboard Accelerators

•	Using an accelerator-table resource

•	Using an accelerator table created at run time


Using an Accelerator-Table Resource

The most common way to add accelerator support to a Windows-based application is to include an accelerator-table resource with the application's executable file and then load the resource at run time. The steps involved in using an accelerator-table resource are as follows:

•	Create an accelerator table in a resource-definition file. Compile it and add the resulting resource to your application's executable file.

•	Include a call to the LoadAccelerators function to load the accelerator-table resource and receive a handle of the accelerator table.

•	Add the TranslateAccelerator function to the message loop associated with the accelerator table.

•	Process the WM_COMMAND messages generated when the user uses the accelerator.


Creating the Accelerator-Table Resource

You create an accelerator-table resource by using the ACCELERATORS statement in your application's resource-definition file. You must assign a name or resource identifier to the accelerator table, preferably unlike that of any other resource. Windows uses this identifier to load the resource at run time.

Each accelerator you define requires a separate entry in the accelerator table. In each entry, you define the keystroke (either an ASCII character code or virtual-key code) that generates the accelerator and the accelerator's identifier. You must also specify whether the keystroke must be used in some combination with the ALT, SHIFT, or CTRL keys. For more information about virtual keys, see Keyboard Input.

An ASCII keystroke is specified either by enclosing the ASCII character in double quotation marks or by using the integer value of the character in combination with the ASCII flag. The following examples show how to define ASCII accelerators.

"A", ID_ACCEL1         ; SHIFT+A

65,  ID_ACCEL2, ASCII  ; SHIFT+A

A virtual-key code keystroke is specified differently depending on whether the keystroke is an alphanumeric key or a non-alphanumeric key. For an alphanumeric key, the key's letter or number, enclosed in double quotation marks, is combined with the VIRTKEY flag. For a non-alphanumeric key, the Windows virtual-key code for the specific key is combined with the VIRTKEY flag. The following examples show how to define virtual-key code accelerators.

"a",       ID_ACCEL3, VIRTKEY   ; A (caps-lock on) or a

VK_INSERT, ID_ACCEL4, VIRTKEY   ; INSERT key

The following example shows an accelerator-table resource that defines accelerators for file operations. The name of the resource is FileAccel.

FileAccel ACCELERATORS

BEGIN

    VK_F12, IDM_OPEN, CONTROL, VIRTKEY  ; CTRL+F12

    VK_F4,  IDM_CLOSE, ALT, VIRTKEY     ; ALT+F4

    VK_F12, IDM_SAVE, SHIFT, VIRTKEY    ; SHIFT+F12

    VK_F12, IDM_SAVEAS, VIRTKEY         ; F12

END

If you want the user to press the ALT, SHIFT, or CTRL keys in some combination with the accelerator keystroke, specify the ALT, SHIFT, and CONTROL flags in the accelerator's definition. Following are some examples.

"B",   ID_ACCEL5, ALT                   ; ALT_SHIFT+B

"I",   ID_ACCEL6, CONTROL, VIRTKEY      ; CTRL+I

VK_F5, ID_ACCEL7, CONTROL, ALT, VIRTKEY ; CTRL+ALT+F5

By default, when an accelerator key corresponds to a menu item, Windows highlights the menu item. You can use the NOINVERT flag to prevent highlighting for an individual accelerator. The following example shows how to use the NOINVERT flag.

VK_DELETE, ID_ACCEL8, VIRTKEY, SHIFT, NOINVERT  ; SHIFT+DELETE

To define accelerators that correspond to menu items in your application, include the accelerators in the text of the menu items. The following example shows how to include accelerators in menu-item text in a resource-definition file.

FilePopup MENU

BEGIN

    POPUP   "&File"

    BEGIN

        MENUITEM    "&New..",           IDM_NEW

        MENUITEM    "&Open\tCtrl+F12",  IDM_OPEN

        MENUITEM    "&Close\tAlt+F4"    IDM_CLOSE

        MENUITEM    "&Save\tShift+F12", IDM_SAVE

        MENUITEM    "Save &As...\tF12", IDM_SAVEAS

    END

END


Loading the Accelerator-Table Resource

An application loads an accelerator-table resource by calling the LoadAccelerators function and specifying the instance handle of the application whose executable file contains the resource and the name or identifier of the resource. LoadAccelerators loads the specified accelerator table into memory and returns the handle of the accelerator table.

An application can load an accelerator-table resource at any time. Usually, a single-threaded application loads its accelerator table before entering its main message loop. An application that uses multiple threads typically loads the accelerator-table resource for a thread before entering the message loop for the thread. An application or thread might also use multiple accelerator tables, each associated with a particular window in the application. Such an application would load the accelerator table for the window each time the user activated the window. For more information about threads, see Processes and Threads.


Calling the TranslateAccelerator Function

To process accelerators, an application's (or thread's) message loop must contain a call to the TranslateAccelerator function. TranslateAccelerator compares keystrokes to an accelerator table and, if it finds a match, translates the keystrokes into a WM_COMMAND (or WM_SYSCOMMAND) message. The function then sends the message to a window procedure. The parameters of the TranslateAccelerator function include the handle of the window that is to receive the WM_COMMAND messages, the handle of the accelerator table used to translate accelerators, and a pointer to an MSG structure containing a message from the queue. The following example shows how to call TranslateAccelerator from within a message loop.

while (GetMessage(&msg, (HWND) NULL, 0, 0)) {

    /* Check for accelerator keystrokes. */

    if (!TranslateAccelerator(

            hwndMain,      /* handle of receiving window    */

            haccel,        /* handle of active accel. table */

            &msg)) {       /* address of message data       */

        TranslateMessage(&msg);

        DispatchMessage(&msg);

    }

}


Processing WM_COMMAND Messages

When an accelerator is used, the window specified in the TranslateAccelerator function receives a WM_COMMAND or WM_SYSCOMMAND message. The low-order word of the wParam parameter contains the identifier of the accelerator. The window procedure examines the identifier to determine the source of the WM_COMMAND message and process the message accordingly.

Typically, if an accelerator corresponds to a menu item in the application, the accelerator and menu item are assigned the same identifier. If you need to know whether a given WM_COMMAND message was generated by an accelerator or by a menu item, you can examine the high-order word of the wParam parameter. If an accelerator generated the message, the high-order word is 1; if a menu item generated the message, the high-order word is 0.


Destroying the Accelerator-Table Resource

Windows automatically destroys accelerator-table resources loaded by the LoadAccelerators function, removing the resource from memory after the application closes.


Creating Accelerators for Font Attributes

The example in this section shows how to perform the following tasks:

•	Create an accelerator-table resource.

•	Load the accelerator table at run time.

•	Translate accelerators in a message loop.

•	Process WM_COMMAND messages generated by the accelerators.

These tasks are demonstrated in the context of an application that includes a Character menu and corresponding accelerators that allow the user to select attributes of the current font.

The following portion of a resource-definition file defines the Character menu and the associated accelerator table. Note that the menu items show the accelerator keystrokes and that each accelerator has the same identifier as its associated menu item.

#include <windows.h>

#include "acc.h"

MainMenu MENU

BEGIN

    POPUP   "&Character"

    BEGIN

        MENUITEM    "&Regular\tF5",         IDM_REGULAR

        MENUITEM    "&Bold\tCtrl+B",        IDM_BOLD

        MENUITEM    "&Italic\tCtrl+I",      IDM_ITALIC

        MENUITEM    "&Underline\tCtrl+U",   IDM_ULINE

    END

END

FontAccel ACCELERATORS

BEGIN

    VK_F5,  IDM_REGULAR,    VIRTKEY

    "B",    IDM_BOLD,       CONTROL, VIRTKEY

    "I",    IDM_ITALIC,     CONTROL, VIRTKEY

    "U",    IDM_ULINE,      CONTROL, VIRTKEY

END

The following sections from the application's source file show how to implement the accelerators.

HWND hwndMain;      /* handle of main window          */

HANDLE hinstAcc;    /* handle of application instance */

int WINAPI WinMain(hinst, hinstPrev, lpCmdLine, nCmdShow)

HINSTANCE hinst;

HINSTANCE hinstPrev;

LPSTR lpCmdLine;

int nCmdShow;

{

    MSG msg;            /* application messages              */

    HACCEL haccel;      /* handle of accelerator table       */

    .

    . /* Perform the initialization procedure. */

    .

    /* Create a main window for this application instance.  */

    hwndMain = CreateWindowEx(0L, "MainWindowClass",

        "Sample Application", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,

        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL,

        hinst, NULL );

    /* If a window cannot be created, return "failure." */

    if (!hwndMain)

        return FALSE;

    /* Make the window visible and update its client area. */

    ShowWindow(hwndMain, nCmdShow);

    UpdateWindow(hwndMain);

    /* Load the accelerator table. */

    haccel = LoadAccelerators(hinstAcc, "FontAccel");

    if (haccel == NULL)

        HandleAccelErr(ERR_LOADING);     /* application defined */

    /*

     * Get and dispatch messages until a WM_QUIT message is

     * received.

     */

    while (GetMessage(&msg, NULL, NULL, NULL)) {

        /* Check for accelerator keystrokes. */

        if (!TranslateAccelerator(

                hwndMain,      /* handle of receiving window    */

                haccel,        /* handle of active accel. table */

                &msg)) {       /* address of message data       */

            TranslateMessage(&msg);

            DispatchMessage(&msg);

        }

    }

    return msg.wParam;

}

LRESULT APIENTRY MainWndProc(hwndMain, uMsg, wParam, lParam)

HWND hwndMain;

UINT uMsg;

WPARAM wParam;

LPARAM lParam;

{

    BYTE fbFontAttrib;        /* array of font-attribute flags  */

    static HMENU hmenu;       /* handle of main menu            */

    switch (uMsg) {

        case WM_CREATE:

            /*

             * Add a check mark to the Regular menu item to

             * indicate that it is the default.

             */

            hmenu = GetMenu(hwndMain);

            CheckMenuItem(hmenu, IDM_REGULAR, MF_BYCOMMAND |

                MF_CHECKED);

            return 0;

        case WM_COMMAND:

            switch (LOWORD(wParam)) {

                /* Process the accelerator and menu commands. */

                case IDM_REGULAR:

                case IDM_BOLD:

                case IDM_ITALIC:

                case IDM_ULINE:

                    /*

                     * GetFontAttributes is an application-defined

                     * function that sets the menu-item check marks

                     * and returns the user-selected font attributes.

                     */

                    fbFontAttrib = GetFontAttributes(

                        (BYTE) LOWORD(wParam), hmenu);

                    /*

                     * SetFontAttributes is an application-defined

                     * function that creates a font with the

                     * user-specified attributes the font with

                     * the main window's device context.

                     */

                    SetFontAttributes(fbFontAttrib);

                    break;

                default:

                    break;

            }

            break;

            .

            . /* Process other messages. */

            .

        default:

            return DefWindowProc(hwndMain, uMsg, wParam, lParam);

    }

    return NULL;

}


Using an Accelerator Table Created at Run Time

The Win32 application programming interface (API) allows you to create accelerator tables at run time. The steps involved in creating and using an accelerator table at run time are as follows:

•	Define the accelerators by filling an array of ACCEL structures, and then create an accelerator table by passing the array to the CreateAcceleratorTable function.

•	Activate the accelerator table and process WM_COMMAND messages generated by the accelerators.

•	Destroy the accelerator table before the application closes.


Creating the Accelerator Table

The first step in creating an accelerator table at run time is filling an array of ACCEL structures. Each structure in the array defines an accelerator in the table. An accelerator's definition includes its flags, its key, and its identifier. The ACCEL structure has the following form.

typedef struct tagACCEL { // accl

    BYTE   fVirt;

    WORD   key;

    WORD   cmd;

} ACCEL;

You define an accelerator's keystroke by specifying an ASCII character code or a virtual-key code in the key member of the ACCEL structure. If you specify a virtual-key code, you must first include the FVIRTKEY flag in the fVirt member; otherwise, Windows interprets the code as an ASCII character code. You can include the FCONTROL, FALT, or FSHIFT flag, or all three, to combine the CTRL, ALT, or SHIFT key with the keystroke.

To create the accelerator table, pass the address of the array of ACCEL structures to the CreateAcceleratorTable function. CreateAcceleratorTable creates the accelerator table and returns the handle of the table.


Processing Accelerators

The process of loading and calling accelerators provided by an accelerator table created at run time is the same as processing those provided by an accelerator-table resource. For more information, see Loading the Accelerator-Table Resource through Processing WM_COMMAND Messages.


Destroying the Accelerator Table

Before an application closes, it must destroy accelerator tables created at run time. You can destroy an accelerator table and remove it from memory by passing the table's handle to the DestroyAcceleratorTable function.


Creating User-Editable Accelerators

This example shows how to construct a dialog box that allows the user to change the accelerator associated with a menu item. The dialog box consists of a combo box containing menu items, a combo box containing the names of keys, and check boxes for selecting the CTRL, ALT, and SHIFT keys. The following illustration shows the dialog box.

The following example shows how the dialog box is defined in the resource-definition file.

EdAccelBox DIALOG 5, 17, 193, 114

STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION

CAPTION "Edit Accelerators"

BEGIN

    COMBOBOX        IDD_MENUITEMS, 10, 22, 52, 53,

                        CBS_SIMPLE | CBS_SORT | WS_VSCROLL |

                        WS_TABSTOP

    CONTROL         "Control", IDD_CNTRL, "Button",

                        BS_AUTOCHECKBOX | WS_TABSTOP,

                        76, 35, 40, 10

    CONTROL         "Alt", IDD_ALT, "Button",

                        BS_AUTOCHECKBOX | WS_TABSTOP,

                        76, 48, 40, 10

    CONTROL         "Shift", IDD_SHIFT, "Button",

                        BS_AUTOCHECKBOX | WS_TABSTOP,

                        76, 61, 40, 10

    COMBOBOX        IDD_KEYSTROKES, 124, 22, 58, 58,

                        CBS_SIMPLE | CBS_SORT | WS_VSCROLL |

                        WS_TABSTOP

    PUSHBUTTON      "Ok", IDOK, 43, 92, 40, 14

    PUSHBUTTON      "Cancel", IDCANCEL, 103, 92, 40, 14

    LTEXT           "Select Item:", 101, 10, 12, 43, 8

    LTEXT           "Select Keystroke:", 102, 123, 12, 60, 8

END

The dialog box uses an array of application-defined VKEY structures, each containing a keystroke-text string and an accelerator-text string. When the dialog box is created, it parses the array and adds each keystroke-text string to the Select Keystroke combo box. When the user clicks the Ok button, the dialog box looks up the selected keystroke-text string and retrieves the corresponding accelerator-text string. The dialog box appends the accelerator-text string to the text of the menu item that the user selected. The following example shows the array of VKEY structures:

/* VKey Lookup Support */

#define MAXKEYS 26

typedef struct _VKEYS {

    char *pKeyName;

    char *pKeyString;

} VKEYS;

VKEYS vkeys[MAXKEYS] = {

    "BkSp",     "Back Space",

    "PgUp",     "Page Up",

    "PgDn",     "Page Down",

    "End",      "End",

    "Home",     "Home",

    "Lft",      "Left",

    "Up",       "Up",

    "Rgt",      "Right",

    "Dn",       "Down",

    "Ins",      "Insert",

    "Del",      "Delete",

    "Mult",     "Multiply",

    "Add",      "Add",

    "Sub",      "Subtract",

    "DecPt",    "Decimal Point",

    "Div",      "Divide",

    "F2",       "F2",

    "F3",       "F3",

    "F5",       "F5",

    "F6",       "F6",

    "F7",       "F7",

    "F8",       "F8",

    "F9",       "F9",

    "F11",      "F11",

    "F12",      "F12"

};

The dialog box's initialization procedure fills the Select Item and Select Keystroke combo boxes. After the user selects a menu item and associated accelerator, the dialog box examines the controls in the dialog box to get the user's selection, updates the text of the menu item, and then creates a new accelerator table that contains the user-defined new accelerator. The following example shows the dialog-box procedure.

/* Global variables */

HWND hwndMain;      /* handle of main window          */

HANDLE hinstAcc;    /* handle of application instance */

HACCEL haccel;      /* handle of accelerator table    */

.

.

.

/* Dialog-box procedure */

LRESULT CALLBACK EdAccelProc(hwndDlg, uMsg, wParam, lParam)

HWND hwndDlg;

UINT uMsg;

WPARAM wParam;

LPARAM lParam;

{

    int nCurSel;            /* index of list box item          */

    UINT idItem;            /* menu-item identifier            */

    UINT uItemPos;          /* menu-item position              */

    UINT i, j = 0;          /* loop counters                   */

    static UINT cItems;     /* count of items in menu          */

    char szTemp[32];        /* temporary buffer                */

    char szAccelText[32];   /* buffer for accelerator text     */

    char szKeyStroke[16];   /* buffer for keystroke text       */

    static char szItem[32]; /* buffer for menu-item text       */

    HWND hwndCtl;           /* handle of control window        */

    static HMENU hmenu;     /* handle of "Character" menu      */

    PCHAR pch, pch2;        /* pointers for string copying     */

    WORD wVKCode;           /* accelerator virtual-key code    */

    BYTE fAccelFlags;       /* fVirt flags for ACCEL structure */

    LPACCEL lpaccelNew;     /* address of new accel. table     */

    HACCEL haccelOld;       /* handle of old accel. table      */

    int cAccelerators;      /* number of accelerators in table */

    static BOOL fItemSelected = FALSE; /* item selection flag  */

    static BOOL fKeySelected = FALSE;  /* key selection flag   */

    switch (uMsg) {

        case WM_INITDIALOG:

            /* Get the handle of the menu-item combo box. */

            hwndCtl = GetDlgItem(hwndDlg, IDD_MENUITEMS);

            /*

             * The application's menu bar contains a "Character"

             * submenu whose items have accelerators associated

             * with them. Get the handle of the "Character"

             * submenu (its position within the main menu is 2),

             * and count the number of items it has.

             */

            hmenu = GetSubMenu(GetMenu(hwndMain), 2);

            cItems = GetMenuItemCount(hmenu);

            /*

             * Get the text of each item, strip out the '&' and

             * the accelerator text, and add the text to the

             * menu-item combo box.

             */

            for (i = 0; i < cItems; i++) {

                if (!(GetMenuString(hmenu, i, szTemp,

                        sizeof(szTemp), MF_BYPOSITION)))

                    continue;

                for (pch = szTemp, pch2 = szItem;

                       *pch != '\0'; ) {

                    if (*pch != '&') {

                        if (*pch == '\t') {

                            *pch = '\0';

                            *pch2 = '\0';

                        }

                        else

                            *pch2++ = *pch++;

                    }

                    else

                        pch++;

                }

                SendMessage(hwndCtl, CB_ADDSTRING, 0,

                    (LONG) (LPSTR) szItem);

            }

            /*

             * Now fill the keystroke combo box with the list of

             * keystrokes that will be allowed for accelerators.

             * The list of keystrokes is in the application-defined

             * structure called "vkeys".

             */

            hwndCtl = GetDlgItem(hwndDlg, IDD_KEYSTROKES);

            for (i = 0; i < MAXKEYS; i++)

                SendMessage(hwndCtl, CB_ADDSTRING, 0,

                    (LONG) (LPSTR) vkeys[i].pKeyString);

            return TRUE;

        case WM_COMMAND:

            switch (LOWORD(wParam)) {

                case IDD_MENUITEMS:

                    /*

                     * The user must select an item from the menu-

                     * item combo box. This flag is checked during

                     * IDOK processing to be sure a selection was made.

                     */

                    fItemSelected = TRUE;

                    return 0;

                case IDD_KEYSTROKES:

                    /*

                     * The user must select an item from the menu-

                     * item combo box. This flag is checked during

                     * IDOK processing to be sure a selection was made.

                     */

                    fKeySelected = TRUE;

                    return 0;

                case IDOK:

                    /*

                     * If the user has not selected a menu item

                     * and a keystroke, display a reminder in a

                     * message box.

                     */

                    if (!fItemSelected || !fKeySelected) {

                        MessageBox(hwndDlg,

                            "Item or key not selected.", NULL,

                            MB_OK);

                        return 0;

                    }

                    /*

                     * Determine whether the CTRL, ALT, and SHIFT

                     * keys are selected. Concatenate the

                     * appropriate strings to the accelerator-

                     * text buffer, and set the appropriate

                     * accelerator flags.

                     */

                    szAccelText[0] = '\0';

                    hwndCtl = GetDlgItem(hwndDlg, IDD_CNTRL);

                    if (SendMessage(hwndCtl, BM_GETCHECK, 0, 0)

                            == 1) {

                        lstrcat(szAccelText, "Ctl+");

                        fAccelFlags |= FCONTROL;

                    }

                    hwndCtl = GetDlgItem(hwndDlg, IDD_ALT);

                    if (SendMessage(hwndCtl, BM_GETCHECK, 0, 0)

                            == 1) {

                        lstrcat(szAccelText, "Alt+");

                        fAccelFlags |= FALT;

                    }

                    hwndCtl = GetDlgItem(hwndDlg, IDD_SHIFT);

                    if (SendMessage(hwndCtl, BM_GETCHECK, 0, 0)

                            == 1) {

                        lstrcat(szAccelText, "Shft+");

                        fAccelFlags |= FSHIFT;

                    }

                    /*

                     * Get the selected keystroke, and look up the

                     * accelerator text and the virtual-key code

                     * for the keystroke in the vkeys structure.

                     */

                    hwndCtl = GetDlgItem(hwndDlg, IDD_KEYSTROKES);

                    nCurSel = (int) SendMessage(hwndCtl,

                        CB_GETCURSEL, 0, 0);

                    SendMessage(hwndCtl, CB_GETLBTEXT,

                        nCurSel, (LONG) (LPSTR) szKeyStroke);

                    for (i = 0; i < MAXKEYS; i++) {

                        if(lstrcmp(vkeys[i].pKeyString,

                                szKeyStroke) == 0) {

                            lstrcpy(szKeyStroke,

                                vkeys[i].pKeyName);

                            break;

                        }

                    }

                    /*

                     * Concatenate the keystroke text to the

                     * "Ctl+","Alt+", or "Shft+" string.

                     */

                    lstrcat(szAccelText, szKeyStroke);

                    /*

                     * Determine the position in the menu of the

                     * selected menu item. Menu items in the

                     * "Character" menu have positions 0,2,3, and 4.

                     */

                    if (lstrcmp(szItem, "Regular") == 0)

                        uItemPos = 0;

                    else if (lstrcmp(szItem, "Bold") == 0)

                        uItemPos = 2;

                    else if (lstrcmp(szItem, "Italic") == 0)

                        uItemPos = 3;

                    else if (lstrcmp(szItem, "Underline") == 0)

                        uItemPos = 4;

                    /*

                     * Get the string that corresponds to the

                     * selected item.

                     */

                    GetMenuString(hmenu, uItemPos, szItem,

                        sizeof(szItem), MF_BYPOSITION);

                    /*

                     * Append the new accelerator text to the

                     * menu-item text.

                     */

                    for (pch = szItem; *pch != '\t'; pch++);

                    ++pch;

                    for (pch2 = szAccelText; *pch2 != '\0';

                            pch2++)

                        *pch++ = *pch2;

                    *pch = '\0';

                    /*

                     * Modify the menu item to reflect the new

                     * accelerator text.

                     */

                    idItem = GetMenuItemID(hmenu, uItemPos);

                    ModifyMenu(hmenu, idItem, MF_BYCOMMAND |

                        MF_STRING, idItem, szItem);

                    /* Reset the selection flags. */

                    fItemSelected = FALSE;

                    fKeySelected = FALSE;

                    /* Save the current accelerator table. */

                    haccelOld = haccel;

                    /*

                     * Count the number of entries in the current

                     * table, allocate a buffer for the table, and

                     * then copy the table into the buffer.

                     */

                    cAccelerators = CopyAcceleratorTable(

                        haccelOld, NULL, 0);

                    lpaccelNew = (LPACCEL) LocalAlloc(LPTR,

                        cAccelerators * sizeof(ACCEL));

                    if (lpaccelNew != NULL)

                        CopyAcceleratorTable(haccel, lpaccelNew,

                            cAccelerators);

                    /*

                     * Find the accelerator that the user modified

                     * and change its flags and virtual-key code

                     * as appropriate.

                     */

                    for (i = 0; (lpaccelNew[i].cmd ==

                                (WORD) idItem)

                            && (i < (UINT) cAccelerators); i++) {

                        lpaccelNew[i].fVirt = fAccelFlags;

                        lpaccelNew[i].key = wVKCode;

                    }

                    /*

                     * Create the new accelerator table, and

                     * destroy the old one.

                     */

                    DestroyAcceleratorTable(haccelOld);

                    haccel = CreateAcceleratorTable(lpaccelNew,

                        cAccelerators);

                    /* Destroy the dialog box. */

                    EndDialog(hwndDlg, TRUE);

                    return 0;

                case IDCANCEL:

                    EndDialog(hwndDlg, TRUE);

                    return TRUE;

                default:

                    break;

            }

        default:

            break;

    }

    return FALSE;

}


Keyboard Accelerator Reference

The following functions and messages are associated with keyboard accelerators.


Keyboard Accelerator Functions

Following are the functions used with accelerators.

CopyAcceleratorTable
CreateAcceleratorTable
DestroyAcceleratorTable
LoadAccelerators
TranslateAccelerator


Keyboard Accelerator Messages

Following are the messages used with accelerators.

WM_COMMAND
WM_INITMENU
WM_INITMENUPOPUP
WM_MENUCHAR
WM_MENUSELECT
WM_SYSCHAR
WM_SYSCOMMAND


Keyboard Input

This overview describes how Windows generates keyboard input and how an application receives and processes that input.


About Keyboard Input

All applications written for Microsoft® Windows® should accept user input from the keyboard as well as from the mouse. A Windows-based application receives keyboard input in the form of messages posted to its windows.


Keyboard Input Model

Windows provides device-independent keyboard support for applications by installing a keyboard device driver appropriate for the current keyboard. Windows provides language-independent keyboard support by using the language-specific keyboard layout currently selected by the user or the application. The keyboard device driver receives scan codes from the keyboard, which are sent to the keyboard layout where they are translated into messages and posted to the appropriate windows in your application.

Assigned to each key on a keyboard is a unique value called a scan code, a device-dependent identifier for the key on the keyboard. A keyboard generates two scan codes when the user types a key — one when the user presses the key and another when the user releases the key.

The keyboard device driver interprets a scan code and translates (maps) it to a virtual-key code, a device-independent value defined by Windows that identifies the purpose of a key. After translating a scan code, the keyboard layout creates a message that includes the scan code, the virtual-key code, and other information about the keystroke, and then places the message in the system message queue. Windows removes the message from the system message queue and posts it to the message queue of the appropriate thread. Eventually, the thread's message loop removes the message and passes it to the appropriate window procedure for processing. The following figure illustrates the keyboard input model for Windows.


Keyboard Focus and Activation

Windows posts keyboard messages to the message queue of the foreground thread that created the window with the keyboard focus. The keyboard focus is a temporary property of a window. Windows shares the keyboard among all windows on the display by shifting the keyboard focus, at the user's direction, from one window to another. The window that has the keyboard focus receives (from the message queue of the thread that created it) all keyboard messages until the focus changes to a different window.

A thread can call the GetFocus function to determine which of its windows (if any) currently has the keyboard focus. A thread can give the keyboard focus to one of its windows by calling the SetFocus function. When the keyboard focus changes from one window to another, the system sends a WM_KILLFOCUS message to the window that has lost the focus, and then sends a WM_SETFOCUS message to the window that has gained the focus.

The concept of keyboard focus is related to that of the active window. The active window is the top-level window the user is currently working with. The window with the keyboard focus is either the active window, or a child window of the active window. So the user can easily identify the active window, the system places it at the top of the Z order and makes its title bar (if it has one) and border highlighted.

The user can activate a top-level window by clicking it, selecting it using the ALT+TAB or ALT+ESC key combination, or selecting if from Task List. A thread can activate a top-level window by using the SetActiveWindow function. It can determine whether a top-level window it created is active by using the GetActiveWindow function.

When one window is deactivated and another activated, Windows sends the WM_ACTIVATE message first to the window being deactivated, then to the window being activated. The low-order word of the wParam parameter is zero if the window is being deactivated and nonzero if it is being activated. When the default window procedure receives the WM_ACTIVATE message, it sets the keyboard focus to the active window.


Keystroke Messages

Pressing a key results in a WM_KEYDOWN or WM_SYSKEYDOWN message being placed in the thread message queue associated with the window that has the keyboard focus. Releasing a key results in a WM_KEYUP or WM_SYSKEYUP message being placed in the queue.

Key-up and key-down messages typically occur in pairs, but if the user holds down a key long enough to start the keyboard's automatic repeat feature, the system generates a number of WM_KEYDOWN or WM_SYSKEYDOWN messages in a row. It then generates a single WM_KEYUP or WM_SYSKEYUP message when the user releases the key.


System and Nonsystem Keystrokes

Windows makes a distinction between system keystrokes and nonsystem keystrokes. System keystrokes produce system keystroke messages, WM_SYSKEYDOWN and WM_SYSKEYUP. Nonsystem keystrokes produce nonsystem keystroke messages, WM_KEYDOWN and WM_KEYUP.

If your window procedure must process a system keystroke message, make sure that after processing the message the procedure passes it to the DefWindowProc function. Otherwise, all system operations involving the ALT key will be disabled whenever the window has the keyboard focus. That is, the user won't be able to access the window's menus or System menu, or use the ALT+ESC or ALT+TAB key combination to activate a different window.

System keystroke messages are primarily for use by Windows rather than by an application. Windows uses them to provide its built-in keyboard interface to menus and to allow the user to control which window is active. System keystroke messages are generated when the user types a key in combination with the ALT key, or when the user types and no window has the keyboard focus (for example, when the active application is minimized). In this case, the messages are posted to the message queue associated with the active window.

Nonsystem keystroke messages are for use by application windows; the DefWindowProc function does nothing with them. A window procedure can discard any nonsystem keystroke messages that it does not need.


Virtual-Key Codes Described

The wParam parameter of a keystroke message contains the virtual-key code of the key that was pressed or released. A window procedure processes or ignores a keystroke message, depending on the value of the virtual-key code.

A typical window procedure processes only a small subset of the keystroke messages that it receives and ignores the rest. For example, a window procedure might process only WM_KEYDOWN keystroke messages, and only those that contain virtual-key codes for the cursor movement keys, shift keys (also called control keys), and function keys. A typical window procedure does not process keystroke messages from character keys. Instead, it uses the TranslateMessage function to convert the message into character messages. For more information about TranslateMessage and character messages, see Character Messages.


Keystroke Message Flags

The lParam parameter of a keystroke message contains additional information about the keystroke that generated the message. This information includes the repeat count, the scan code, the extended-key flag, the context code, the previous key-state flag, and the transition-state flag. The following illustration shows the locations of these flags and values in the lParam parameter:

An application can use the following values to manipulate the keystroke flags:

Value	Meaning
KF_ALTDOWN	Manipulates the ALT key flag, which indicated if the ALT key is pressed.
KF_DLGMODE	Manipulates the dialog mode flag, which indicates whether a dialog box is active.
KF_EXTENDED	Manipulates the extended key flag.
KF_MENUMODE	Manipulates the menu mode flag, which indicates whether a menu is active.
KF_REPEAT	Manipulates the repeat count.
KF_UP	Manipulates the transition state flag.
Repeat Count

You can check the repeat count to determine whether a keystroke message represents more than one keystroke. The system increments the count when the keyboard generates WM_KEYDOWN or WM_SYSKEYDOWN messages faster than an application can process them. This often occurs when the user holds down a key long enough to start the keyboard's automatic repeat feature. Instead of filling the system message queue with the resulting key-down messages, the system combines the messages into a single key down message and increments the repeat count. Releasing a key cannot start the automatic repeat feature, so the repeat count for WM_KEYUP and WM_SYSKEYUP messages is always set to 1.

Scan Code

The scan code is the value that the keyboard hardware generates when the user presses a key. It is a device-dependent value that identifies the key pressed, as opposed to the character represented by the key. An application typically ignores scan codes. Instead, it uses the device-independent virtual-key codes to interpret keystroke messages.

Extended-Key Flag

The extended-key flag indicates whether the keystroke message originated from one of the additional keys on the enhanced keyboard. The extended keys consist of the ALT and CTRL keys on the right-hand side of the keyboard; the INS, DEL, HOME, END, PAGE UP, PAGE DOWN and arrow keys in the clusters to the left of the numeric keypad; the NUM LOCK key; the BREAK (CTRL+PAUSE) key; the PRINT SCRN key; and the divide (/) and ENTER keys in the numeric keypad. The extended-key flag is set if the key is an extended key.

Context Code

The context code indicates whether the ALT key was down when the keystroke message was generated. The code is 1 if the ALT key was down and 0 if it was up.

Previous Key-State Flag

The previous key-state flag indicates whether the key that generated the keystroke message was previously up or down. It is 1 if the key was previously down and 0 if the key was previously up. You can use this flag to identify keystroke messages generated by the keyboard's automatic repeat feature. This flag is set to 1 for WM_KEYDOWN and WM_SYSKEYDOWN keystroke messages generated by the automatic repeat feature. It is always set to 0 for WM_KEYUP and WM_SYSKEYUP messages.

Transition-State Flag

The transition-state flag indicates whether pressing a key or releasing a key generated the keystroke message. This flag is always set to 0 for WM_KEYDOWN and WM_SYSKEYDOWN messages; it is always set to 1 for WM_KEYUP and WM_SYSKEYUP messages.


Character Messages

Keystroke messages provide a lot of information about keystrokes, but they don't provide character codes for character keystrokes. To retrieve character codes, an application must include the TranslateMessage function in its thread message loop. TranslateMessage passes a WM_KEYDOWN or WM_SYSKEYDOWN message to the keyboard layout. The layout examines the message's virtual-key code and, if it corresponds to a character key, provides the character code equivalent (taking into account the state of the SHIFT and CAPS LOCK keys). It then generates a character message that includes the character code and places the message at the top of the message queue. The next iteration of the message loop removes the character message from the queue and dispatches the message to the appropriate window procedure.


Nonsystem Character Messages

A window procedure can receive four different character messages, including WM_CHAR, WM_DEADCHAR, WM_SYSCHAR, and WM_SYSDEADCHAR. The TranslateMessage function generates a WM_CHAR or WM_DEADCHAR message when it processes a WM_KEYDOWN message. Similarly, it generates a WM_SYSCHAR or WM_SYSDEADCHAR message when it processes a WM_SYSKEYDOWN message.

An application that processes keyboard input typically ignores all but the WM_CHAR message, passing any other messages to the DefWindowProc function. Windows uses the WM_SYSCHAR and WM_SYSDEADCHAR messages to implement menu mnemonics.

The wParam parameter of all character messages contains the character code of the character key that was pressed. The value of the character code depends on the window class of the window receiving the message. If the Unicode™ version of the RegisterClass function was used to register the window class, the system provides Unicode characters to all windows of that class. Otherwise, the system provides ASCII character codes from the Windows character set. For more information about Unicode, see Unicode and Character Sets.

The contents of the lParam parameter of a character message are identical to the contents of the lParam parameter of the key-down message that was translated to produce the character message. For information about the contents of the lParam parameter, see Keystroke Message Flags.


Dead-Character Messages

Some non-English keyboards contain character keys that are not expected to produce characters by themselves. Instead, they are used to add a diacritic to the character produced by the subsequent keystroke. These keys are called dead keys. The circumflex key on a German keyboard is an example of a dead key. To enter the character consisting of an "o" with a circumflex, a German user would type the circumflex key followed by the "o" key. The window with the keyboard focus would receive the following sequence of messages:

WM_KEYDOWN
WM_DEADCHAR
WM_KEYUP
WM_KEYDOWN
WM_CHAR
WM_KEYUP

TranslateMessage generates the WM_DEADCHAR message when it processes the WM_KEYDOWN message from a dead key. Although the wParam parameter of the WM_DEADCHAR message contains the character code of the diacritic for the dead key, an application typically ignores the message. Instead, it processes the WM_CHAR message generated by the subsequent keystroke. The wParam parameter of the WM_CHAR message contains the character code of the letter with the diacritic. If the subsequent keystroke generates a character that cannot be combined with a diacritic, Windows generates two WM_CHAR messages. The wParam parameter of the first contains the character code of the diacritic; the wParam parameter of the second contains the character code of the subsequent character key.

The TranslateMessage function generates the WM_SYSDEADCHAR message when it processes the WM_SYSKEYDOWN message from a system dead key (a dead key that is pressed in combination with the ALT key). An application typically ignores the WM_SYSDEADCHAR message.


Key Status

While processing a keyboard message, an application may need to determine the status of another key besides the one that generated the current message. For example, a word-processing application that allows the user to press SHIFT+END to select a block of text must check the status of the SHIFT key whenever it receives a keystroke message from the END key. The application can use the GetKeyState function to determine the status of a virtual key at the time the current message was generated; it can use the GetAsyncKeyState function to retrieve the current status of a virtual key.

The keyboard layout maintains a list of names. The name of a key that produces a single character is the same as the character produced by the key. The name of a noncharacter key such as TAB and ENTER is stored as a character string. An application can retrieve the name of any key from the device driver by calling the GetKeyNameText function.


Keystroke and Character Translations

Windows includes several special purpose functions that translate scan codes, character codes, and virtual-key codes provided by various keystroke messages. These functions include MapVirtualKey, ToAscii, ToUnicode, and VkKeyScan.


Hot-Key Support

Windows provides a set of functions that applications can use to define hot keys. A hot key is a key combination that generates a WM_HOTKEY message, a message the system places at the top of a thread's message queue, bypassing any existing messages in the queue. Applications use hot keys to obtain high-priority keyboard input from the user. For example, by defining a hot key consisting of the CTRL+C key combination, an application can allow the user to cancel a lengthy operation.

To define a hot key, an application calls the RegisterHotKey function, specifying the combination of keys that generates the WM_HOTKEY message, the handle of the window to receive the message, and the identifier of the hot key. When the user presses the hot key, a WM_HOTKEY message is placed in the message queue of the thread that created the given window. The wParam parameter of the message contains the identifier of the hot key. The application can define multiple hot keys for a thread, but each hot key in the thread must have a unique identifier. Before the application terminates, it should use the UnregisterHotKey function to destroy the hot key.

Applications can use a hot key control to make it easy for the user to choose a hot key. Hot key controls are typically used to define a hot key that activates a window; they do not use the RegisterHotKey and UnregisterHotKey functions. Instead, an application that uses a hot key control typically sends the WM_SETHOTKEY message to set the hot key. Whenever the user presses the hot key, the system sends a WM_SYSCOMMAND message specifying SC_HOTKEY. For more information about hot key controls, see Hot-Key Controls.


Languages, Locales, and Keyboard Layouts

A language is a natural language, such as English, French, and Japanese. A sublanguange is a variant of a natural language that is spoken in a specific geographical region, such as the English sublanguages spoken in Great Britian and the United States. Win32-based applications use values, called locales, to uniquely identify languages and sublanguages. Applications typically use locales to set the language in which input and output is processed. Setting the locale for the keyboard, for example, affects the character values generated by the keyboard. Setting the locale for the display or printer affects the glyphs displayed or printed. Applications set the locale for a keyboard by loading and using keyboard layouts. They set the locale for a display or printer by selecting a font that supports the given locale.

A keyboard layout not only specifies the physical position of the keys on the keyboard but also determines the character values generated by pressing those keys. Each layout has an associated locale which identifies the current input language and determines which character values are generated by which keys and key combinations.

Every keyboard layout has a corresponding handle which identifies of the layout and language. The low word of the handle is a language identifier. The high word is a device handle, specifying the physical layout, or is zero, indicating a default physical layout. The user can associate any input language with a given physical layout. For example, an English-speaking user who very occasionally works in French can set the input language of the keyboard to French without changing the physical layout of the keyboard. This means the user can enter text in French using the familiar English layout.

Applications are generally not expected to manipulate input languages directly. Instead, the user sets up language and layout combinations, then switches among them. When the user clicks into text marked with a different language, the application calls the ActivateKeyboardLayout function to activate the user's default layout for that language. If the user edits text in a language which is not in the active list, the application can call the LoadKeyboardLayout function with the language to get a layout based on that language.

The ActivateKeyboardLayout function sets the input language for the current task. The hkl parameter can be either the handle of the keyboard layout or a zero-extended language identifier. Keyboard layout handles can be obtained from the LoadKeyboardLayout or GetKeyboardLayoutList function. The HKL_NEXT and HKL_PREV values can also be used to select the next or previous keyboard. For some operating systems, the KLF_UNLOADPREVIOUS value has no meaning and is ignored.

The GetKeyboardLayoutName function retrieves the name of the active keyboard layout for the calling thread. If an application creates the active layout using the LoadKeyboardLayout function, GetKeyboardLayoutName retrieves the same string used to create the layout. Otherwise, the string is the primary language identifier correspoding to the locale of the active layout. This means the function may not necessarily differentiate among different layouts with the same primary language, so cannot return specific information about the input language. The GetKeyboardLayout function, however, can be used to determine the input language.

The LoadKeyboardLayout function loads a keyboard layout and makes the layout available to the user. Applications can use the make the layout immediately active for the current thread by using the KLF_ACTIVATE value. An application can use the KLF_REORDER value to reorder the layouts without also specifying the KLF_ACTIVATE value. Applications should always use the KLF_SUBSTITUTE_OK value when loading keyboard layouts to ensure that the user's preference, if any, is selected. For some operating systems, the KLF_UNLOADPREVIOUS value is ignored.

For multilingual support, the LoadKeyboardLayout function provides the KLF_REPLACELANG and KLF_NOTELLSHELL flags. The KLF_REPLACELANG flag directs the function to replace an existing keyboard layout without changing associated the language. Attempting to replace an existing layout using the same language identifier but without specifying KLF_REPLACELANG is an error. The KLF_NOTELLSHELL flag prevents the function from notifying the shell when a keyboard layout is added or replaced. This is useful for applications that add multiple layouts in a consecutive series of calls. This flag should be used in all but the last call.

The UnloadKeyboardLayout function is restricted in that it cannot unload the system default input language. This ensures that the user always has one layout available for enter text using the same character set as used by the shell and file system.


Using Keyboard Input

A window receives keyboard input in the form of keystroke messages and character messages. The message loop associated with the window must include code to translate keystroke messages into the corresponding character messages. If the window displays keyboard input in its client area, it should create and display a caret to indicate the position where the next character will be entered. The following sections describe the code involved in receiving, processing, and displaying keyboard input.

•	Processing Keystroke Messages

•	Translating Character Messages

•	Processing Character Messages

•	Using the Caret

•	Displaying Keyboard Input


Processing Keystroke Messages

The window procedure of the window that has the keyboard focus receives keystroke messages when the user types at the keyboard. The keystroke messages are WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN, and WM_SYSKEYUP. A typical window procedure ignores all keystroke messages except WM_KEYDOWN. Windows posts the WM_KEYDOWN message when the user presses a key.

When the window procedure receives the WM_KEYDOWN message, it should examine the virtual-key code that accompanies the message to determine how to process the keystroke. The virtual-key code is in the message's wParam parameter. Typically, an application processes only keystrokes generated by noncharacter keys, including the function keys, the cursor movement keys, and the special-purpose keys such as INS, DEL, HOME and END.

The following example shows the window procedure framework that a typical application uses to receive and process keystroke messages.

        case WM_KEYDOWN:

            switch (wParam) {

                case VK_LEFT:

                    .

                    . /* Process the LEFT ARROW key. */

                    .

                    break;

                case VK_RIGHT:

                    .

                    . /* Process the RIGHT ARROW key. */

                    .

                    break;

                case VK_UP:

                    .

                    . /* Process the UP ARROW key. */

                    .

                    break;

                case VK_DOWN:

                    .

                    . /* Process the DOWN ARROW key. */

                    .

                    break;

                case VK_HOME:

                    .

                    . /* Process the HOME key. */

                    .

                    break;

                case VK_END:

                    .

                    . /* Process the END key. */

                    .

                    break;

                case VK_INSERT:

                    .

                    . /* Process the INS key. */

                    .

                    break;

                case VK_DELETE:

                    .

                    . /* Process the DEL key. */

                    .

                    break;

                case VK_F2:

                    .

                    . /* Process the F2 key. */

                    .

                    break;

                .

                . /* Process other noncharacter keystrokes. */

                .

                default:

                    break;

            }


Translating Character Messages

Any thread that receives character input from the user must include the TranslateMessage function in its message loop. This function examines the virtual-key code of a keystroke message and, if the code corresponds to a character, places a character message into the message queue. The character message is removed and dispatched on the next iteration of the message loop; the wParam parameter of the message contains the character code.

In general, a thread's message loop should use the TranslateMessage function to translate every message, not just virtual-key messages. Although TranslateMessage has no effect on other types of messages, it guarantees that keyboard input is translated correctly. The following example shows how to include the TranslateMessage function in a typical thread message loop.

while (GetMessage(&msg, (HWND) NULL, 0, 0)) {

    if (TranslateAccelerator(hwndMain, haccl, &msg) == 0) {

        TranslateMessage(&msg);

        DispatchMessage(&msg);

    }

}


Processing Character Messages

A window procedure receives a character message when the TranslateMessage function translates a virtual-key code corresponding to a character key. The character messages are WM_CHAR, WM_DEADCHAR, WM_SYSCHAR, and WM_SYSDEADCHAR. A typical window procedure ignores all character messages except WM_CHAR. The TranslateMessage function generates a WM_CHAR message when the user presses any of the following keys.

•	Any character key

•	BACKSPACE

•	ENTER (carriage return)

•	ESC

•	SHIFT+ENTER (linefeed)

•	TAB

When a window procedure receives the WM_CHAR message, it should examine the character code that accompanies the message to determine how to process the character. The character code is in the message's wParam parameter.

The following example shows the window procedure framework that a typical application uses to receive and process character messages.

        case WM_CHAR:

            switch (wParam) {

                case 0x08:

                    .

                    . /* Process a backspace. */

                    .

                    break;

                case 0x0A:

                    .

                    . /* Process a linefeed. */

                    .

                    break;

                case 0x1B:

                    .

                    . /* Process an escape. */

                    .

                    break;

                case 0x09:

                    .

                    . /* Process a tab. */

                    .

                    break;

                case 0x0D:

                    .

                    . /* Process a carriage return. */

                    .

                    break;

                default:

                    .

                    . /* Process displayable characters. */

                    .

                    break;

            }


Using the Caret

A window that receives keyboard input typically displays the characters the user types in the window's client area. A window should use a caret to indicate the position in the client area where the next character will appear. The window should also create and display the caret when it receives the keyboard focus, and hide and destroy the caret when it loses the focus. A window can perform these operations in the processing of the WM_SETFOCUS and WM_KILLFOCUS messages. For more information about carets, see Carets.


Displaying Keyboard Input

The example in this section shows how an application can receive characters from the keyboard, display them in the client area of a window, and update the position of the caret with each character typed. It also demonstrates how to move the caret in response to the LEFT ARROW, RIGHT ARROW, HOME and END keystrokes, and shows how to highlight selected text in response to the SHIFT+RIGHT ARROW key combination.

During processing of the WM_CREATE message, the window procedure shown in the example allocates a 64K buffer for storing keyboard input. It also retrieves the metrics of the currently loaded font, saving the height and average width of characters in the font. The height and width are used in processing the WM_SIZE message to calculate the line length and maximum number of lines, based on the size of the client area.

The window procedure creates and displays the caret when processing the WM_SETFOCUS message. It hides and deletes the caret when processing the WM_KILLFOCUS message.

When processing the WM_CHAR message, the window procedure displays characters, stores them in the input buffer, and updates the caret position. The window procedure also converts tab characters to four consecutive space characters. Backspace, linefeed, and escape characters generate a beep, but are not otherwise processed.

The window procedure performs the left, right, end, and home caret movements when processing the WM_KEYDOWN message. While processing the action of the RIGHT ARROW key, the window procedure checks the state of the SHIFT key and, if it is down, selects the character to the right of the caret as the caret is moved.

Note that the following code is written so that it can be compiled either as Unicode™ or as ANSI. If the source code defines Unicode, strings are handled as Unicode characters; otherwise, they are handled as ANSI characters.

#define BUFSIZE 65535

#define SHIFTED 0x8000

LONG APIENTRY MainWndProc(hwndMain, uMsg, wParam, lParam)

HWND hwndMain;

UINT uMsg;

UINT wParam;

LONG lParam;

{

    HDC hdc;                   /* handle of device context      */

    TEXTMETRIC tm;             /* structure for text metrics    */

    static DWORD dwCharX;      /* average width of characters   */

    static DWORD dwCharY;      /* height of characters          */

    static DWORD dwClientX;    /* width of client area          */

    static DWORD dwClientY;    /* height of client area         */

    static DWORD dwLineLen;    /* line length                   */

    static DWORD dwLines;      /* text lines in client area     */

    static int nCaretPosX = 0; /* horizontal position of caret  */

    static int nCaretPosY = 0; /* vertical position of caret    */

    static int nCharWidth = 0; /* width of a character          */

    static int cch = 0;        /* characters in buffer          */

    static int nCurChar = 0;   /* index of current character    */

    static PTCHAR pchInputBuf; /* address of input buffer       */

    int i, j;                  /* loop counters                 */

    int cCR = 0;               /* count of carriage returns     */

    int nCRIndex = 0;          /* index of last carriage return */

    int nVirtKey;              /* virtual-key code              */

    TCHAR szBuf[128];          /* temporary buffer              */

    TCHAR ch;                  /* current character             */

    PAINTSTRUCT ps;            /* required by BeginPaint        */

    RECT rc;                   /* output rectangle for DrawText */

    SIZE sz;                   /* string dimensions             */

    COLORREF crPrevText;       /* previous text color           */

    COLORREF crPrevBk;         /* previous background color     */

    switch (uMsg) {

        case WM_CREATE:

            /* Get the metrics of the current font. */

            hdc = GetDC(hwndMain);

            GetTextMetrics(hdc, &tm);

            ReleaseDC(hwndMain, hdc);

            /* Save the average character width and height. */

            dwCharX = tm.tmAveCharWidth;

            dwCharY = tm.tmHeight;

            /* Allocate a buffer to store keyboard input. */

            pchInputBuf = (LPTSTR) GlobalAlloc(GPTR,

                BUFSIZE * sizeof(TCHAR));

            return 0;

        case WM_SIZE:

            /* Save the new width and height of the client area. */

            dwClientX = LOWORD(lParam);

            dwClientY = HIWORD(lParam);

            /*

             * Calculate the maximum width of a line and the

             * maximum number of lines in the client area.

             */

            dwLineLen = dwClientX - dwCharX;

            dwLines = dwClientY / dwCharY;

            break;

        case WM_SETFOCUS:

            /*

             * Create, position, and display the caret when the

             * window receives the keyboard focus.

             */

            CreateCaret(hwndMain, (HBITMAP) 1, 0, dwCharY);

            SetCaretPos(nCaretPosX, nCaretPosY * dwCharY);

            ShowCaret(hwndMain);

            break;

        case WM_KILLFOCUS:

            /*

             * Hide and destroy the caret when the window loses the

             * keyboard focus.

             */

            HideCaret(hwndMain);

            DestroyCaret();

            break;

        case WM_CHAR:

            switch (wParam) {

                case 0x08:  /* backspace */

                case 0x0A:  /* linefeed */

                case 0x1B:  /* escape */

                    MessageBeep(0xFFFFFFFF);

                    return 0;

                case 0x09:  /* tab */

                    /* Convert tabs to four consecutive spaces. */

                    for (i = 0; i < 4; i++)

                        SendMessage(hwndMain, WM_CHAR, 0x20, 0);

                    return 0;

                case 0x0D:  /* carriage return */

                    /*

                     * Record the carriage return and position the

                     * caret at the beginning of the new line.

                     */

                    pchInputBuf[cch++] = 0x0D;

                    nCaretPosX = 0;

                    nCaretPosY += 1;

                    break;

                default:    /* displayable character */

                    ch = (TCHAR) wParam;

                    HideCaret(hwndMain);

                     /*

                      * Retrieve the character's width and output

                      * the character.

                      */

                    hdc = GetDC(hwndMain);

                    GetCharWidth32(hdc, (UINT) wParam, (UINT) wParam,

                        &nCharWidth);

                    TextOut(hdc, nCaretPosX, nCaretPosY * dwCharY,

                        &ch, 1);

                    ReleaseDC(hwndMain, hdc);

                    /* Store the character in the buffer. */

                    pchInputBuf[cch++] = ch;

                    /*

                     * Calculate the new horizontal position of the

                     * caret. If the position exceeds the maximum,

                     * insert a carriage return and move the caret

                     * to the beginning of the next line.

                     */

                    nCaretPosX += nCharWidth;

                    if ((DWORD) nCaretPosX > dwLineLen) {

                        nCaretPosX = 0;

                        pchInputBuf[cch++] = 0x0D;

                        ++nCaretPosY;

                    }

                    nCurChar = cch;

                    ShowCaret(hwndMain);

                    break;

            }

            SetCaretPos(nCaretPosX, nCaretPosY * dwCharY);

            break;

        case WM_KEYDOWN:

            switch (wParam) {

                case VK_LEFT:   /* LEFT ARROW */

                    /*

                     * The caret can move only to the beginning of

                     * the current line.

                     */

                    if (nCaretPosX > 0) {

                        HideCaret(hwndMain);

                        /*

                         * Retrieve the character to the left of

                         * the caret, calculate the character's

                         * width, then subtract the width from the

                         * current horizontal position of the caret

                         * to obtain the new position.

                         */

                        ch = pchInputBuf[--nCurChar];

                        hdc = GetDC(hwndMain);

                        GetCharWidth32(hdc, ch, ch, &nCharWidth);

                        ReleaseDC(hwndMain, hdc);

                        nCaretPosX = max(nCaretPosX - nCharWidth,

                            0);

                        ShowCaret(hwndMain);

                    }

                    break;

                case VK_RIGHT:  /* RIGHT ARROW */

                    /*

                     * Caret moves to the right or, when a carriage

                     * return is encountered, to the beginning of

                     * the next line.

                     */

                    if (nCurChar < cch) {

                        HideCaret(hwndMain);

                        /*

                         * Retrieve the character to the right of

                         * the caret. If it's a carriage return,

                         * position the caret at the beginning of

                         * the next line.

                         */

                        ch = pchInputBuf[nCurChar];

                        if (ch == 0x0D) {

                            nCaretPosX = 0;

                            nCaretPosY++;

                        }

                        /*

                         * If the character isn't a carriage

                         * return, check to see whether the SHIFT

                         * key is down. If it is, invert the text

                         * colors and output the character.

                         */

                        else {

                            hdc = GetDC(hwndMain);

                            nVirtKey = GetKeyState(VK_SHIFT);

                            if (nVirtKey & SHIFTED) {

                                crPrevText = SetTextColor(hdc,

                                    RGB(255, 255, 255));

                                crPrevBk = SetBkColor(hdc,

                                    RGB(0,0,0));

                                TextOut(hdc, nCaretPosX,

                                    nCaretPosY * dwCharY,

                                    &ch, 1);

                                SetTextColor(hdc, crPrevText);

                                SetBkColor(hdc, crPrevBk);

                            }

                            /*

                             * Get the width of the character and

                             * calculate the new horizontal

                             * position of the caret.

                             */

                            GetCharWidth32(hdc, ch, ch, &nCharWidth);

                            ReleaseDC(hwndMain, hdc);

                            nCaretPosX = nCaretPosX + nCharWidth;

                        }

                        nCurChar++;

                        ShowCaret(hwndMain);

                        break;

                    }

                    break;

                case VK_UP:     /* UP ARROW   */

                case VK_DOWN:   /* DOWN ARROW */

                    MessageBeep(0xFFFFFFFF);

                    return 0;

                case VK_HOME:   /* HOME */

                    /*

                     * Set the caret's position to the upper left

                     * corner of the client area.

                     */

                    nCaretPosX = nCaretPosY = 0;

                    nCurChar = 0;

                    break;

                case VK_END:    /* END */

                    /* Move the caret to the end of the text. */

                    for (i=0; i < cch; i++) {

                        /*

                         * Count the carriage returns and save the

                         * index of the last one.

                         */

                        if (pchInputBuf[i] == 0x0D) {

                            cCR++;

                            nCRIndex = i + 1;

                        }

                    }

                    nCaretPosY = cCR;

                    /*

                     * Copy all text between the last carriage

                     * return and the end of the keyboard input

                     * buffer to a temporary buffer.

                     */

                    for (i = nCRIndex, j = 0; i < cch; i++, j++)

                        szBuf[j] = pchInputBuf[i];

                    szBuf[j] = TEXT('\0');

                    /*

                     * Retrieve the text extent and use it

                     * to set the horizontal position of the

                     * caret.

                     */

                    hdc = GetDC(hwndMain);

                    GetTextExtentPoint32(hdc, szBuf, lstrlen(szBuf),

                        &sz);

                    nCaretPosX = sz.cx;

                    ReleaseDC(hwndMain, hdc);

                    nCurChar = cch;

                    break;

                default:

                    break;

            }

            SetCaretPos(nCaretPosX, nCaretPosY * dwCharY);

            break;

        case WM_PAINT:

            if (cch == 0)       /* nothing in input buffer */

                break;

            hdc = BeginPaint(hwndMain, &ps);

            HideCaret(hwndMain);

            /*

             * Set the clipping rectangle, and then draw the text

             * into it.

             */

            SetRect(&rc, 0, 0, dwLineLen, dwClientY);

            DrawText(hdc, pchInputBuf, -1, &rc, DT_LEFT);

            ShowCaret(hwndMain);

            EndPaint(hwndMain, &ps);

            break;

        .

        . /* Process other messages. */

        .

        case WM_DESTROY:

            PostQuitMessage(0);

            /* Free the input buffer. */

            GlobalFree((HGLOBAL) pchInputBuf);

            UnregisterHotKey(hwndMain, 0xAAAA);

            break;

        default:

            return DefWindowProc(hwndMain, uMsg, wParam, lParam);

    }

    return NULL;

}


Keyboard Input Reference

The following functions and messages are associated with keyboard input.


Keyboard Input Functions

Following are the functions used to receive and process keyboard input.

ActivateKeyboardLayout
EnableWindow
GetActiveWindow
GetAsyncKeyState
GetFocus
GetKeyboardLayoutName
GetKeyboardState
GetKeyNameText
GetKeyState
IsWindowEnabled
keybd_event
LoadKeyboardLayout
MapVirtualKey
OemKeyScan
RegisterHotKey
SetActiveWindow
SetFocus
SetKeyboardState
ToAscii
ToUnicode
UnloadKeyboardLayout
UnregisterHotKey
VkKeyScan

Obsolete or Deleted Functions

GetKBCodePage


Keyboard Input Messages

Following are the messages used to receive and process keyboard input.

WM_ACTIVATE
WM_CHAR
WM_DEADCHAR
WM_HOTKEY
WM_KEYDOWN
WM_KEYUP
WM_KILLFOCUS
WM_SETFOCUS
WM_SYSCHAR
WM_SYSDEADCHAR
WM_SYSKEYDOWN
WM_SYSKEYUP


Multiple Document Interface

The multiple document interface (MDI) is a specification that defines the standard user interface for applications written for Microsoft® Windows®.

Windows provides extensive support for MDI applications. This overview describes the structure of an MDI application and how to take advantage of the built-in MDI support found in the Microsoft® Win32® application program interface (API).


About the Multiple Document Interface

An MDI application enables the user to work with more than one document at the same time. Each document is displayed in a separate child window within the client area of the application's main window. Typical MDI applications include word-processing applications that allow the user to work with multiple text documents, and spreadsheet applications that allow the user to work with multiple charts and spreadsheets.


Frame, Client, and Child Windows

An MDI application has three kinds of windows: a frame window, a client window, as well as a number of child windows. The frame window is like the main window of the application: it has a sizing border, a title bar, a System menu (also known as the Control menu), a Minimize button, and a Maximize button. The application must register a window class for the frame window and provide a window procedure to support it.

An MDI application does not display output in the client area of the frame window. Instead, it displays the MDI client window. An MDI client window is a special type of child window belonging to the preregistered window class MDICLIENT. The client window is a child of the frame window; it serves as the background for child windows. It also provides support for creating and manipulating child windows. For example, an MDI application can create, activate, or maximize child windows by sending messages to the MDI client window.

When the user opens or creates a document, the client window creates a child window for the document. The client window is the parent window of all MDI child windows in a given application. Each child window has a sizing border, a title bar, a System menu, a Minimize button, and a Maximize button. Because a child window is clipped, it is confined to the client window and cannot appear outside it.

An MDI application can support more than one kind of document. For example, a typical spreadsheet application enables the user to work with both charts and spreadsheets. For each type of document that it supports, an MDI application must register a child window class and provide a window procedure to support the windows belonging to that class. For more information about window classes, see Window Classes." For more information about window procedures, see Window Procedures.

Following is a typical MDI application. It is named Multipad.


Child Window Creation

To create a child window, an MDI application either calls the CreateMDIWindow function or sends the WM_MDICREATE message to the MDI client window. A more efficient way to create an MDI child window is to call the CreateWindowEx function, specifying the WS_EX_MDICHILD extended style. A thread in an MDI application can use CreateMDIWindow or CreateWindowEx to create a child window in a different thread. The WM_MDICREATE message is used only in the context of the same thread.

To destroy a child window, an MDI application sends a WM_MDIDESTROY message to the MDI client window.


Child Window Activation

Any number of child windows can appear in the client window at any one time, but only one can be active. The active child window is positioned in front of all other child windows, and its border is highlighted.

The user can activate an inactive child window by clicking it. An MDI application activates a child window by sending a WM_MDIACTIVATE message to the MDI client window. As the client window processes this message, it sends a WM_MDIACTIVATE message to the window procedure of the child window to be activated and to the window procedure of the child window being deactivated.

Windows keeps track of each child window's position in the stack of overlapping windows. This stacking is known as the Z order. The user can activate the next child window in the Z order by choosing the Next command from the System menu in the active window. An application activates the next (or previous) child window in the Z order by sending a WM_MDINEXT message to the client window.

To retrieve the handle of the active child window, the MDI application sends a WM_MDIGETACTIVE message to the client window.


Multiple Document Menus

The frame window of an MDI application should include a menu bar with a Window menu item and its corresponding pop-up menu. The Window pop-up menu should include command items that arrange the child windows within the client window or that close all child windows. The Window menu of a typical MDI application might include the items in the following table.

Menu item	Purpose
Tile	Arranges child windows in a tile format so that each appears in its entirety in the client window.
Cascade	Arranges child windows in a cascade format. The child windows overlap one another, but the title bar of each is visible.
Arrange Icons	Arranges the icons of minimized child windows along the bottom of the client window.
Close All	Closes all child windows.
Whenever a child window is created, Windows automatically appends a new menu item to the Window menu. The text of the menu item is the same as the text on the menu bar of the new child window. By choosing the menu item, the user can activate the corresponding child window. When a child window is destroyed, Windows automatically removes the corresponding menu item from the Window menu.

Windows can add up to ten menu items to the Window menu. When the tenth child window is created, Windows adds the More Windows item to the Window menu. Choosing this item causes the Select Window dialog box to appear. The dialog box contains a list box with the titles of all MDI child windows currently available. The user can activate a child window by choosing its title from the list box.

If your MDI application supports several types of child windows, tailor the menu bar to reflect the operations associated with the active window. To do this, provide separate menu resources for each type of child window the application supports. When a new type of child window is activated, the application should send a WM_MDISETMENU message to the client window, passing to it the handle of the corresponding menu.

When no child window exists, the menu bar should contain only items used to create or open a document.

When the user is navigating through an MDI application's menus by using cursor keys, the keys behave differently than when the user is navigating through a typical application's menus. In an MDI application, control passes from the application's System menu to the System menu of the active child window, and then to the first item on the menu bar.


Accelerators

To receive and process accelerator keys for its child windows, an MDI application must include the TranslateMDISysAccel function in its message loop. The loop must call TranslateMDISysAccel before calling the TranslateAccelerator or DispatchMessage function.

Accelerator keys on the System menu for an MDI child window are different from those for a non-MDI child window. In an MDI child window, the ALT+ − (minus) key combination opens the System menu, the CTRL+F4 key combination closes the active child window, and the CTRL+F6 key combination activates the next child window.


Child Window Size and Arrangement

An MDI application controls the size and position of its child windows by sending messages to the MDI client window. To maximize the active child window, the application sends the WM_MDIMAXIMIZE message to the client window. When a child window is maximized, its client area completely fills the MDI client window. In addition, Windows automatically hides the child window's title bar, and adds the child window's System menu icon and Restore icon to the MDI application's menu bar. The application can restore the client window to its original (premaximized) size and position by sending the client window a WM_MDIRESTORE message.

An MDI application can arrange its child windows in either a cascade or tile format. When the child windows are cascaded, the windows appear in a stack. The window on the bottom of the stack occupies the upper left corner of the screen, and the remaining windows are offset vertically and horizontally so that the left border and title bar of each child window is visible. To arrange child windows in the cascade format, an MDI application sends the WM_MDICASCADE message. Typically, the application sends this message when the user chooses the Cascade command from the Window menu.

When the child windows are tiled, Windows displays each child window in its entirety — overlapping none of the windows. All of the windows are sized, as necessary, to fit within the client window. To arrange child windows in the tile format, an MDI application sends a WM_MDITILE message to the client window. Typically, the application sends this message when the user chooses the Tile command from the Window menu.

An MDI application should provide a different icon for each type of child window it supports. The application specifies an icon when registering the child window class. Windows automatically displays a child window's icon in the lower portion of the client window when the child window is minimized. An MDI application directs Windows to arrange child window icons by sending a WM_MDIICONARRANGE message to the client window. Typically, the application sends this message when the user chooses the Arrange Icons command from the Window menu.


Icon Title Windows

Because MDI child windows may be minimized, an MDI application must avoid manipulating icon title windows as if they were normal MDI child windows. Icon title windows appear when the application enumerates child windows of the MDI client window. Icon title windows differ from other child windows, however, in that they are owned by an MDI child window.

To determine whether a child window is an icon title window, use the GetWindow function with the GW_OWNER index. Nontitle windows return NULL. Note that this test is insufficient for top-level windows, because menus and dialog boxes are owned windows.


Child Window Data

Because the number of child windows varies depending on how many documents the user opens, an MDI application must be able to associate data (for example, the name of the current file) with each child window. There are two ways to do this:

•	Store child window data in the window structure.

•	Use window properties.


Data in the Window Structure

When an MDI application registers a window class, it may reserve extra space in the window structure for application data specific to this particular class of windows. To store and retrieve data in this extra space, the application uses the GetWindowWord, SetWindowWord, GetWindowLong, and SetWindowLong functions.

To maintain a large amount of data for a child window, an application can allocate memory for a data structure and then store the handle of the memory containing the structure in the extra space associated with the child window.


Multiple Document Window Properties

An MDI application can also store per-document data by using window properties. (Per-document data is data specific to the type of document contained in a particular child window.) Properties are different from extra space in the window structure in that you need not allocate extra space when registering the window class. A window can have any number of properties. Also, where offsets are used to access the extra space in window structures, properties are referred to by string names. For more information about window properties, see Window Properties.


Using the Multiple Document Interface

This section explains how to perform the following tasks:

•	Registering child and frame window classes.

•	Creating frame and child windows.

•	Writing the main message loop.

•	Writing the frame window procedure.

•	Writing the child window procedure.

•	Creating a child window.

To illustrate these tasks, this section includes examples from Multipad, a typical MDI application.


Registering Child and Frame Window Classes

A typical MDI application must register two window classes: one for its frame window and one for its child windows. If an application supports more than one type of document (for example, a spreadsheet and a chart), it must register a window class for each type.

The class structure for the frame window is similar to the class structure for the main window in non-MDI applications. The class structure for the MDI child windows differs slightly from the structure for child windows in non-MDI applications as follows:

•	The class structure should have an icon, because the user can minimize an MDI child window as if it were a normal application window.

•	The menu name should be NULL, because an MDI child window cannot have its own menu.

•	The class structure should reserve extra space in the window structure. With this space, the application can associate data, such as a filename, with a particular child window.

The following example shows how Multipad registers its frame and child window classes.

BOOL APIENTRY InitializeApplication()

{

    WNDCLASS wc;

    /* Register the frame window class. */

    wc.style         = 0;

    wc.lpfnWndProc   = (WNDPROC) MPFrameWndProc;

    wc.cbClsExtra    = 0;

    wc.cbWndExtra    = 0;

    wc.hInstance     = hInst;

    wc.hIcon         = LoadIcon(hInst, IDMULTIPAD);

    wc.hCursor       = LoadCursor((HANDLE) NULL, IDC_ARROW);

    wc.hbrBackground = (HBRUSH) (COLOR_APPWORKSPACE + 1);

    wc.lpszMenuName  = IDMULTIPAD;

    wc.lpszClassName = szFrame;

    if (!RegisterClass (&wc) )

        return FALSE;

    /* Register the MDI child window class. */

    wc.lpfnWndProc   = (WNDPROC) MPMDIChildWndProc;

    wc.hIcon         = LoadIcon(hInst, IDNOTE);

    wc.lpszMenuName  = (LPCTSTR) NULL;

    wc.cbWndExtra    = CBWNDEXTRA;

    wc.lpszClassName = szChild;

    if (!RegisterClass(&wc))

        return FALSE;

    return TRUE;

}


Creating Frame and Child Windows

After registering its window classes, an MDI application can create its windows. First, it creates its frame window by using the CreateWindow or CreateWindowEx function. After creating its frame window, the application creates its client window, again by using CreateWindow or CreateWindowEx. The application should specify MDICLIENT as the client window's class name; MDICLIENT is a preregistered window class defined by Windows. The lpvParam parameter of CreateWindow or CreateWindowEx should point to a CLIENTCREATESTRUCT structure. This structure contains the members described in the following table:

Member	Description
hWindowMenu	Identifies the Window menu used for controlling MDI child windows. As child windows are created, the application adds their titles to the Window menu as menu items. The user can then activate a child window by choosing its title from the Window menu.
idFirstChild	Specifies the identifier of the first MDI child window. The first MDI child window created is assigned this identifier. Additional windows are created with incremented window identifiers. When a child window is destroyed, Windows immediately reassigns the window identifiers to keep their range contiguous.
When a child window's title is added to the Window menu, Windows assigns an identifier to the child window. When the user chooses a child window's title, the frame window receives a WM_COMMAND message with the identifier in the wParam parameter. You should specify a value for the idFirstChild member that does not conflict with menu-item identifiers in the frame window's menu.

Multipad's frame window procedure creates the MDI client window while processing the WM_CREATE message. The following example shows how the client window is created.

case WM_CREATE:

    {

        CLIENTCREATESTRUCT ccs;

        /*

         * Retrieve the handle of the Window menu and assign the

         * first child window identifier.

         */

        ccs.hWindowMenu = GetSubMenu(GetMenu(hwnd), WINDOWMENU);

        ccs.idFirstChild = IDM_WINDOWCHILD;

        /* Create the MDI client window. */

        hwndMDIClient = CreateWindow( "MDICLIENT", (LPCTSTR) NULL,

            WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL,

            0, 0, 0, 0, hwnd, (HMENU) 0xCAC, hInst, (LPSTR) &ccs);

        ShowWindow(hwndMDIClient, SW_SHOW);

    }

    break;

Titles of child windows are added to the bottom of the Window menu. If the application adds strings to the Window menu by using the AppendMenu function, these strings can be overwritten by the titles of the child windows when the Window menu is repainted. (The Window menu is repainted whenever a child window is created or destroyed.) An MDI application that adds strings to its Window menu should use the InsertMenu function and verify that the titles of child windows have not overwritten these new strings.

Use the WS_CLIPCHILDREN style to create the MDI client window to prevent the window from painting over its child windows.


Writing the Main Message Loop

The main message loop of an MDI application is similar to that of a non-MDI application handling accelerator keys. The difference is that the MDI message loop calls the TranslateMDISysAccel function before checking for application-defined accelerator keys or before dispatching the message.

The following example shows the message loop of a typical MDI application.

while (GetMessage(&msg, (HWND) NULL, 0, 0)) {

    if (!TranslateMDISysAccel(hwndMDIClient, &msg) &&

            !TranslateAccelerator(hwndFrame, hAccel, &msg)){

        TranslateMessage(&msg);

        DispatchMessage(&msg);

    }

}

The TranslateMDISysAccel function translates WM_KEYDOWN messages into WM_SYSCOMMAND messages and sends them to the active MDI child window. If the message is not an MDI accelerator message, the function returns FALSE, in which case the application uses the TranslateAccelerator function to determine whether any of the application-defined accelerator keys were pressed. If not, the loop dispatches the message to the appropriate window procedure.


Writing the Frame Window Procedure

The window procedure for an MDI frame window is similar to that of a non-MDI application's main window. The difference is that a frame window procedure passes all messages it does not handle to the DefFrameProc function rather than to the DefWindowProc function. In addition, the frame window procedure must also pass some messages that it does handle, including those listed in the following table.

Message	Response
WM_COMMAND	Activates the MDI child window that the user chooses. This message is sent when the user chooses an MDI child window from the Window menu of the MDI frame window. The window identifier accompanying this message identifies the MDI child window to be activated.
WM_MENUCHAR	Opens the System menu of the active MDI child window when the user presses the ALT+ − (minus) key combination.
WM_SETFOCUS	Passes the keyboard focus to the MDI client window, which in turn passes it to the active MDI child window.
WM_SIZE	Resizes the MDI client window to fit in the new frame window's client area. If the frame window procedure sizes the MDI client window to a different size, it should not pass the message to the DefWindowProc function.
The frame window procedure in Multipad is called MPFrameWndProc. The handling of other messages by MPFrameWndProc is similar to that of non-MDI applications. WM_COMMAND messages in Multipad are handled by the locally defined CommandHandler function. For command messages Multipad does not handle, CommandHandler calls the DefFrameProc function. If Multipad doesn't use DefFrameProc by default, the user can't activate a child window from the Window menu, because the WM_COMMAND message sent by choosing the window's menu item (command) would be lost.


Writing the Child Window Procedure

Like the frame window procedure, an MDI child window procedure uses a special function for processing messages by default. All messages that the child window procedure does not handle must be passed to the DefMDIChildProc function rather than to the DefWindowProc function. In addition, some window-management messages must be passed to DefMDIChildProc, even if the application handles the message, in order for MDI to function correctly. Following are the messages the application must pass to DefMDIChildProc.

Message	Response
WM_CHILDACTIVATE	Performs activation processing when MDI child windows are sized, moved, or displayed. This message must be passed.
WM_GETMINMAXINFO	Calculates the size of a maximized MDI child window, based on the current size of the MDI client window.
WM_MENUCHAR	Passes the message to the MDI frame window.
WM_MOVE	Recalculates MDI client scroll bars, if they are present.
WM_SETFOCUS	Activates the child window, if it is not the active MDI child window.
WM_SIZE	Performs operations necessary for changing the size of a window, especially for maximizing or restoring an MDI child window. Failing to pass this message to the DefMDIChildProc function produces highly undesirable results.
WM_SYSCOMMAND	Handles System menu commands: SC_NEXTWINDOW, SC_PREVWINDOW, SC_MOVE, SC_SIZE, and SC_MAXIMIZE.


Creating a Child Window

To create an MDI child window, an application can either call the CreateMDIWindow function or send an WM_MDICREATE message to the MDI client window. (The application can use the CreateWindowEx function with the WS_EX_MDICHILD style to create MDI child windows.) A single-threaded MDI application can use either method to create a child window. A thread in a multithreaded MDI application must use the CreateMDIWindow or CreateWindowEx function to create a child window in a different thread.

The lParam parameter of a WM_MDICREATE message is a far pointer to an MDICREATESTRUCT structure. The structure includes four dimension members: x and y, which indicate the horizontal and vertical positions of the window, and cx and cy, which indicate the horizontal and vertical extents of the window. Any of these members may be assigned explicitly by the application, or they may be set to CW_USEDEFAULT, in which case Windows selects a position, size, or both, according to a cascading algorithm. In any case, all four members must be initialized. Multipad uses CW_USEDEFAULT for all dimensions.

The last member of the MDICREATESTRUCT structure is the style member, which may contain style bits for the window. To create an MDI child window that can have any combination of window styles, specify the MDIS_ALLCHILDSTYLES window style. When this style is not specified, an MDI child window has the WS_MINIMIZE, WS_MAXIMIZE, WS_HSCROLL, and WS_VSCROLL styles as default settings.

Multipad creates its MDI child windows by using its locally defined AddFile function (located in the source file MPFILE.C). The AddFile function sets the title of the child window by assigning the szTitle member of the window's MDICREATESTRUCT structure to either the name of the file being edited or to "Untitled." The szClass member is set to the name of the MDI child window class registered in Multipad's InitializeApplication function. The hOwner member is set to the application's instance handle.

The following example shows the AddFile function in Multipad.

HWND APIENTRY AddFile(pName)

CHAR * pName;

{

    HWND hwnd;

    CHAR sz[160];

    MDICREATESTRUCT mcs;

    if (!pName) {

        /*

         * If the pName parameter is NULL, load the "Untitled"

         * string from the STRINGTABLE resource and set the szTitle

         * member of MDICREATESTRUCT.

         */

        LoadString(hInst, IDS_UNTITLED, sz, sizeof(sz));

        mcs.szTitle = (LPCTSTR) sz;

    }

    else

        /*

         * Title the window with the full path and filename,

         * obtained by calling the OpenFile function with the

         * OF_PARSE flag, which is called before AddFile().

         */

        mcs.szTitle = of.szPathName;

    mcs.szClass = szChild;

    mcs.hOwner  = hInst;

    /* Use the default size for the child window. */

    mcs.x = mcs.cx = CW_USEDEFAULT;

    mcs.y = mcs.cy = CW_USEDEFAULT;

    /*

     * Give the child window the default style. The styleDefault

     * variable is defined in MULTIPAD.C.

     */

    mcs.style = styleDefault;

    /* Tell the MDI client window to create the child window. */

    hwnd = (HWND) SendMessage (hwndMDIClient, WM_MDICREATE, 0,

        (LONG) (LPMDICREATESTRUCT) &mcs);

    /*

     * If the file is found, read its contents into the child

     * window's client area.

     */

    if (pName) {

        if (!LoadFile(hwnd, pName)) {

            /* Cannot load the file; close the window. */

            SendMessage(hwndMDIClient, WM_MDIDESTROY,

                (DWORD) hwnd, 0L);

        }

    }

    return hwnd;

}

The pointer passed in the lParam parameter of the WM_MDICREATE message is passed to the CreateWindow function and appears as the first member in the CREATESTRUCT structure, passed in the WM_CREATE message. In Multipad, the child window initializes itself during WM_CREATE message processing by initializing document variables in its extra data and by creating the edit control's child window.


Multiple Document Interface Reference

The following functions and messages are used in MDI applications.


MDI Functions
Multiple Document Interface Functions

CreateMDIWindow
DefFrameProc
DefMDIChildProc
TranslateMDISysAccel


MDI Messages
Multiple Document Interface Messages

WM_MDIACTIVATE
WM_MDICASCADE
WM_MDICREATE
WM_MDIDESTROY
WM_MDIGETACTIVE
WM_MDIICONARRANGE
WM_MDIMAXIMIZE
WM_MDINEXT
WM_MDIREFRESHMENU
WM_MDIRESTORE
WM_MDISETMENU
WM_MDITILE


Messages and Message Queues

This overview describes messages and message queues and explains how to use them in your application.


About Messages and Message Queues

Unlike traditional applications, applications written for Microsoft® Windows® do not make explicit function calls (such as to getchar) to obtain input. Instead, they wait for Windows to pass input to them.

Windows passes all input for an application to the various windows in the application. Each window has a function, called a window procedure, that Windows calls whenever it has input for the window. The window procedure processes the input and returns control to Windows. For more information about window procedures, see Window Procedures.


Messages

Windows passes input to a window procedure in the form of messages. Messages are generated by Windows and by applications. Windows generates a message at each input event — for example, when the user types, moves the mouse, or clicks a control such as a scroll bar. Windows also generates messages in response to changes in the system brought about by an application, such as when an application changes the pool of system font resources or resizes one of its windows. An application can generate messages to direct its own windows to perform tasks or to communicate with windows in other applications.

Windows sends a message to a window procedure with a set of four parameters: a window handle, a message identifier, and two 32-bit values called message parameters. The window handle identifies the window for which the message is intended. Windows uses it to determine which window procedure to send the message to.

A message identifier is a named constant that identifies the purpose of a message. When a window procedure receives a message, it uses a message identifier to determine how to process the message. For example, the message identifier WM_PAINT tells the window procedure that the window's client area has changed and must be repainted.

Message parameters specify data or the location of data used by a window procedure when processing a message. The meaning and value of the message parameters depend on the message. A message parameter can contain an integer, packed bit flags, a pointer to a structure containing additional data, and so on. When a message does not use message parameters, it typically sets them to NULL. A window procedure must check the message identifier to determine how to interpret the message parameters.


Message Routing

Windows uses two methods to route messages to a window procedure: posting messages to a first-in, first-out queue called a message queue, a system-defined memory object that temporarily stores messages, and sending messages directly to a window procedure.

Messages posted to a message queue are called queued messages. They are primarily the result of user input entered through the mouse or keyboard, such as WM_MOUSEMOVE, WM_LBUTTONDOWN, WM_KEYDOWN, and WM_CHAR messages. Other queued messages include the timer, paint, and quit messages: WM_TIMER, WM_PAINT, and WM_QUIT. Most other messages, which are sent directly to a window procedure, are called nonqueued messages.


Queued Messages

Windows can display any number of windows at a time. To route mouse and keyboard input to the appropriate window, Windows uses message queues.

Windows maintains a single system message queue and any number of thread message queues, one for each GUI thread. To avoid the overhead of creating a message queue for non-GUI threads, all threads are created initially without a message queue. The system creates a thread's message queue only when the thread makes its first call to one of the Win32 USER or GDI functions.

Whenever the user moves the mouse, clicks the mouse buttons, or types on the keyboard, the device driver for the mouse or keyboard converts the input into messages and places them in the system message queue. Windows removes the messages, one at a time, from the system message queue, examines them to determine the destination window, and then posts them to the message queue of the thread that created the destination window. A thread's message queue receives all mouse and keyboard messages for the windows created by the thread. The thread removes messages from its queue and directs Windows to send them to the appropriate window procedure for processing. For more information about threads, see Processes and Threads.

With the exception of the WM_PAINT message, Windows always posts messages at the end of a message queue. This ensures that a window receives its input messages in the proper first-in, first-out sequence. The WM_PAINT message, however, is kept in the queue and is forwarded to the window procedure only when the queue contains no other messages. Multiple WM_PAINT messages for the same window are combined into a single WM_PAINT message, consolidating all invalid parts of the client area into a single area. Combining WM_PAINT messages reduces the number of times a window must redraw the contents of its client area.

The system posts a message to a thread's message queue by filling an MSG structure and then copying it to the message queue. Information in MSG includes: the handle of the window for which the message is intended, the message identifier, the two message parameters, the time the messate was posted, and the mouse cursor position. A thread can post a message to its own message queue or to the queue of another thread by using the PostMessage or PostThreadMessage function.

An application can remove a message from its queue by using the GetMessage function. To examine a message without removing it from its queue, an application can use the PeekMessage function. This function fills MSG with information about the message.

After removing a message from its queue, an application can use the DispatchMessage function to direct Windows to send the message to a window procedure for processing. DispatchMessage takes a pointer to MSG that was filled by a previous call to the GetMessage or PeekMessage function. DispatchMessage passes the window handle, the message identifier, and the two message parameters to the window procedure, but it does not pass the time the message was posted or mouse cursor position. An application can retrieve this information by calling the GetMessageTime and GetMessagePos functions while processing a message.


Nonqueued Messages

Nonqueued messages are sent immediately to the destination window procedure, bypassing the system message queue and thread message queue. Windows typically sends nonqueued messages to notify a window of events that affect it. For example, when the user activates a new application window, Windows sends the window a series of messages, including WM_ACTIVATE, WM_SETFOCUS, and WM_SETCURSOR. These messages notify the window that it has been activated, that keyboard input is being directed to the window, and that the mouse cursor has been moved within the borders of the window. Nonqueued messages can also result when an application calls certain Windows functions. For example, Windows sends the WM_WINDOWPOSCHANGED message after an application uses the SetWindowPos function to move a window.

An application can send a message by calling the SendMessage, SendNotifyMessage, or SendDlgItemMessage function. For more information about sending messages, see Sending a Message.


Message Handling

An application must remove and process messages posted to the message queues of its threads. A single-threaded application usually uses a message loop in its WinMain function to remove and send messages to the appropriate window procedures for processing. Applications with multiple threads can include a message loop in each thread that creates a window. The following sections describe how a message loop works and explain the role of a window procedure.


Message Loop

A simple message loop consists of one function call to each of these three functions: GetMessage, TranslateMessage, and DispatchMessage. The GetMessage function retrieves a message from the queue and copies it to an MSG structure. GetMessage returns TRUE unless it encounters the WM_QUIT message, in which case it returns FALSE and ends the loop. In a single-threaded application, ending the message loop is often the first step in closing the application. An application can end its own loop by using the PostQuitMessage function, typically in response to the WM_DESTROY message in the window procedure of the application's main window.

If you specify a window handle in GetMessage, only messages for the specified window are retrieved from the queue. GetMessage can also filter messages in the queue, retrieving only those messages that fall within a specified range. For more information about filtering messages, see Message Filtering.

A thread's message loop must include TranslateMessage, if the thread is to receive character input from the keyboard. Windows generates virtual-key messages (WM_KEYDOWN and WM_KEYUP) each time the user presses a key. A virtual-key message contains a virtual-key code that identifies which key was pressed, but not its character value. To retrieve this value, the message loop must contain TranslateMessage, which translates the virtual-key message into a character message (WM_CHAR) and places it back into the application message queue. The character message can then be removed upon a subsequent iteration of the message loop and dispatched to a window procedure.

The DispatchMessage function sends a message to the window procedure associated with the window handle specified in the MSG structure. If the window handle is HWND_TOPMOST, DispatchMessage sends the message to the window procedures of all top-level windows in the system. If the window handle is NULL, DispatchMessage does nothing with the message.

An application's main thread starts its message loop after initializing the application and creating at least one window. Once started, the message loop continues to retrieve messages from the thread's message queue and to dispatch them to the appropriate windows. The message loop ends when the GetMessage function removes the WM_QUIT message from the message queue.

Only one message loop is needed for a message queue, even if an application contains many windows. DispatchMessage always dispatches the message to the proper window; this is because each message in the queue is an MSG structure that contains the handle of the window to which the message belongs.

An application can modify its message loop in a variety of ways. For example, it can retrieve messages from the queue without dispatching them to a window. This is useful for applications that post messages not specifying a window. (These messages apply to the application rather than to a specific window because they have NULL window handles.) An application can also direct GetMessage to search for specific messages, leaving other messages in the queue. This is useful for applications that must temporarily bypass the usual first-in, first-out order of the message queue.

An application that uses accelerator keys must be able to translate keyboard messages into command messages. To do this, the application's message loop must include a call to the TranslateAccelerator function. For more information about accelerator keys, see Keyboard Accelerators.


Window Procedure

A window procedure is a function that receives and processes all messages sent to the window. Every window class has a window procedure, and every window created with that class uses that same window procedure to respond to messages.

The system sends a message to a window procedure by passing the message data as arguments to the procedure. The window procedure then performs an appropriate action for the message; it checks the message identifier and, while processing the message, uses the information specified by the message parameters.

A window procedure does not usually ignore a message. If it does not process a message, it must send the message back to the system for default processing. The window procedure does this by calling the DefWindowProc function, which performs a default action and returns a message result. The window procedure must then return this value as its own message result. Most window procedures process just a few types of messages and pass the others on to the system by calling DefWindowProc.

Because a window procedure is shared by all windows belonging to the same class, it can process messages for several different windows. To identify the specific window affected by the message, a window procedure can examine the window handle passed with a message. For more information about window procedures, see Window Procedures.


Posting and Sending Messages

Any application can post and send messages. Like the system, an application posts a message by copying it to a message queue and sends a message by passing the message data as arguments to a window procedure. To post and send messages, an application uses the PostMessage and SendMessage functions.

An application typically posts a message to notify a specific window to perform a task. PostMessage creates an MSG structure for the message and copies the message to the message queue. The application's message loop eventually retrieves the message and dispatches it to the appropriate window procedure.

An application typically sends a message to notify a window procedure to perform a task immediately. The SendMessage function sends the message to the window procedure corresponding to the given window. The function waits until the window procedure completes processing and then returns the message result. Parent and child windows often communicate by sending messages to each other. For example, a parent window that has an edit control as its child window can set the text of the control by sending a message to it. The control can notify the parent window of changes to the text that are carried out by the user by sending messages back to the parent.

Occasionally, an application may be required to send or post a message to all top-level windows in the system. For example, if the application changes the system time, it must notify all top-level windows about the change by sending a WM_TIMECHANGE message. An application can send or post a message to all top-level windows by calling the SendMessage or PostMessage function and specifying HWND_TOPMOST in the hwnd parameter.

An application can post a message without specifying a window. If the application supplies a NULL window handle when calling PostMessage, the message is posted to the queue associated with the current thread. Because no window handle is specified, the application must process the message in the message loop. This is one way to create a message that applies to the entire application, instead of to a specific window.

By using the InSendMessage function, a window procedure can determine whether it is processing a message sent by another thread. This capability is useful when message processing depends on the origin of the message.

A common programming error is to assume that the PostMessage function always posts a message. This is not true when the message queue is full. An application should check the return value of the PostMessage function to determine whether the message has been posted and, if it has not been, repost it.


Message Types

This section describes the two types of Windows messages: system defined and application defined.


System-Defined Messages

The system uses system-defined messages to control the operations of applications and to provide input and other information for applications to process. The system sends or posts a system-defined message when it communicates with an application. An application can also send or post system-defined messages. Applications usually use these messages to control the operation of control windows created by using preregistered window classes.

Each system message has a unique message identifier and a corresponding symbolic constant (defined in the Windows header files) that states the purpose of the message. For example, the WM_PAINT constant requests that a window paint its contents.

Symbolic constants specify the category to which system-defined messages belong. The prefix of the constant identifies the type of window that can interpret and process the message. Following are the prefixes and their related message categories.

Prefix	Message category
BM	Button control
CB	Combo box control
DM	Default push button control
EM	Edit control
LB	List box control
SBM	Scroll bar control
WM	General window
General window messages cover a wide range of information and requests, including messages for mouse and keyboard input, menu and dialog box input, window creation and management, and dynamic data exchange (DDE).


Application-Defined Messages

An application can create messages to use in its own windows or to communicate with windows in other processes. If an application creates its own messages, the window procedure that receives them must interpret the messages and provide appropriate processing.

Windows reserves message-identifier values in the range 0x0000 through 0x03FF (the value of WM_USER − 1) and 0x8000 through 0xBFFF for system-defined messages. Applications cannot use these values for private messages.

Values in the range 0x0400 (the value of WM_USER) through 0x7FFF are available for message identifiers defined by an application for its own use. Values in the range 0xC000 through 0xFFFF are available for message identifiers defined by an application for use in communicating with windows in other applications.

Windows returns a message identifier in the range 0xC000 through 0xFFFF when an application calls the RegisterWindowMessage function to register a message. The message identifier returned by this function is guaranteed to be unique throughout the system. If your application creates messages to communicate with windows in other applications, it should use RegisterWindowMessage to register the message. Use of this function prevents conflicts that can arise if other applications use the same message identifier for different purposes.


Message Filtering

An application can choose specific messages to retrieve from the message queue (while ignoring other messages) by using the GetMessage or PeekMessage function to specify a message filter. The filter is a range of message identifiers (specified by a first and last identifier), a window handle, or both. GetMessage and PeekMessage use a message filter to select which messages to retrieve from the queue. Message filtering is useful if an application must search the message queue for messages that have arrived later in the queue.

Any application that filters messages must ensure that a message satisfying the message filter can be posted. For example, if an application filters for a WM_CHAR message in a window that does not receive keyboard input, the GetMessage function does not return. This effectively "hangs" the application.

To filter for keyboard, mouse, and DDE messages, an application can use the WM_KEYFIRST and WM_KEYLAST, WM_MOUSEFIRST and WM_MOUSELAST messages, and WM_DDE_FIRST and WM_DDE_LAST constants.


Message Deadlocks

A thread that calls the SendMessage function to send a message to another thread cannot continue executing until the window procedure that receives the message returns. If the receiving thread yields control while processing the message, the sending thread cannot continue executing, because it is waiting for SendMessage to return. This situation is called a deadlock. The receiving thread need not yield control explicitly; calling any of the following functions can cause a thread to yield control.

DialogBox
DialogBoxIndirect
DialogBoxIndirectParam
DialogBoxParam
GetMessage
MessageBox
PeekMessage

A window procedure can determine whether a message it has received was sent by another thread by calling the InSendMessage function. Before calling any of the functions in the preceding list while processing a message, the window procedure should first call InSendMessage. If this function returns TRUE, the window procedure must call the ReplyMessage function before any function that causes the thread to yield control.


Using Messages and Message Queues

•	Creating a message loop

•	Examining a message queue

•	Posting a message

•	Sending a message


Creating a Message Loop

Windows automatically creates a message queue for each thread. If the thread creates one or more windows, a message loop must be provided; this message loop retrieves messages from the thread's message queue and dispatches them to the appropriate window procedures.

Because Windows directs messages to individual windows in an application, a thread must create at least one window before starting its message loop. Most Windows-based applications contain a single thread that creates windows. A typical application registers the window class for its main window, creates and shows the main window, and then starts its message loop — all in the WinMain function.

You create a message loop by using the GetMessage and DispatchMessage functions. If your application must obtain character input from the user, include the TranslateMessage function in the loop. TranslateMessage translates virtual-key messages into character messages. The following example shows the message loop in the WinMain function of a simple Windows-based application.

HINSTANCE hinst;

HWND hwndMain;

int APIENTRY WinMain(hInstance, hPrevInstance, lpszCmdLine,

    nCmdShow)

HINSTANCE hInstance;

HINSTANCE hPrevInstance;

LPSTR lpszCmdLine;

int nCmdShow;

{

    MSG msg;

    WNDCLASS wc;

    UNREFERENCED_PARAMETER(lpszCmdLine);

    /* Register the window class for the main window. */

    if (!hPrevInstance) {

        wc.style = 0;

        wc.lpfnWndProc = (WNDPROC) WndProc;

        wc.cbClsExtra = 0;

        wc.cbWndExtra = 0;

        wc.hInstance = hInstance;

        wc.hIcon = LoadIcon((HINSTANCE) NULL,

            IDI_APPLICATION);

        wc.hCursor = LoadCursor((HINSTANCE) NULL,

            IDC_ARROW);

        wc.hbrBackground = GetStockObject(WHITE_BRUSH);

        wc.lpszMenuName =  "MainMenu";

        wc.lpszClassName = "MainWndClass";

        if (!RegisterClass(&wc))

            return FALSE;

    }

    hinst = hInstance;  /* save instance handle */

    /* Create the main window. */

    hwndMain = CreateWindow("MainWndClass", "Sample",

        WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,

        CW_USEDEFAULT, CW_USEDEFAULT, (HWND) NULL,

        (HMENU) NULL, hinst, (LPVOID) NULL);

    /*

     * If the main window cannot be created, terminate

     * the application.

     */

    if (!hwndMain)

        return FALSE;

    /* Show the window and paint its contents. */

    ShowWindow(hwndMain, nCmdShow);

    UpdateWindow(hwndMain);

    /* Start the message loop. */

    while (GetMessage(&msg, (HWND) NULL, 0, 0)) {

        TranslateMessage(&msg);

        DispatchMessage(&msg);

    }

    /* Return the exit code to Windows. */

    return msg.wParam;

}

The GetMessage, TranslateMessage, and DispatchMessage functions take a pointer to an MSG structure as a parameter. If a message is available, GetMessage copies it to the MSG structure. If the message is a virtual-key message (such as WM_KEYDOWN or WM_SYSKEYDOWN), TranslateMessage generates a character message (WM_CHAR or WM_SYSCHAR) and places it in the message queue. DispatchMessage uses the members of the MSG structure as arguments for the window procedure; DispatchMessage does not return until the window procedure finishes processing the message.

If a thread supports accelerators, its message loop must include the TranslateAccelerator function. This function checks for key combinations that match an entry in the thread's accelerator table. When it finds a match, TranslateAccelerator translates the key combination into a WM_COMMAND message and dispatches it to the window procedure. For more information about accelerators, see Keyboard Accelerators.

If a thread uses a modeless dialog box, the message loop must include the IsDialogMessage function so that the dialog box can receive keyboard input. For more information about dialog boxes, see Dialog Boxes.

The following example shows a message loop for a thread that uses accelerators and displays a modeless dialog box. When TranslateAccelerator or IsDialogMessage returns TRUE (indicating that the message has been processed), TranslateMessage and DispatchMessage are not called. The reason for this is that TranslateAccelerator and IsDialogMessage perform all necessary translating and dispatching of messages.

HWND hwndMain;

HWND hwndDlgModeless = NULL;

MSG msg;

HACCEL haccel;

.

. /* Perform initialization and create a main window. */

.

while (GetMessage(&msg, (HWND) NULL, 0, 0)) {

    if (hwndDlgModeless == (HWND) NULL ||

            !IsDialogMessage(hwndDlgModeless, &msg) &&

            !TranslateAccelerator(hwndMain, haccel,

                &msg)) {

        TranslateMessage(&msg);

        DispatchMessage(&msg);

    }

}


Examining a Message Queue

Occasionally, an application needs to examine the contents of a thread's message queue from outside the thread's message loop. For example, if an application's window procedure performs a lengthy drawing operation, you may want the user to be able to interrupt the operation. Unless your application periodically examines the message queue during the operation for mouse and keyboard messages, it will not respond to user input until after the operation has completed. The reason for this is that the DispatchMessage function in the thread's message loop does not return until the window procedure finishes processing a message.

You can use the PeekMessage function to examine a message queue during a lengthy operation. PeekMessage is similar to the GetMessage function; both check a message queue for a message that matches the filter criteria and then copy the message to an MSG structure. The main difference between the two functions is that GetMessage does not return until a message matching the filter criteria is placed in the queue, whereas PeekMessage returns immediately regardless of whether a message is in the queue.

The following example shows how to use PeekMessage to examine a message queue for mouse clicks and keyboard input during a lengthy operation.

HWND hwnd;

BOOL fDone;

MSG msg;

/*

 * Begin the operation and continue until it is complete

 * or until the user clicks the mouse or presses a key.

 */

fDone = FALSE;

while (!fDone) {

    fDone = DoLengthyOperation(); /* application-defined */

    /*

     * Remove any messages that may be in the queue. If the

     * queue contains any mouse or keyboard

     * messages, end the operation.

     */

    while (PeekMessage(&msg, hwnd,  0, 0, PM_REMOVE)) {

        switch(msg.message) {

            case WM_LBUTTONDOWN:

            case WM_RBUTTONDOWN:

            case WM_KEYDOWN:

                .

                . /* Perform any required cleanup. */

                .

                fDone = TRUE;

        }

    }

}

Other functions, including GetQueueStatus and GetInputState, also allow you to examine the contents of a thread's message queue. GetQueueStatus returns an array of flags that indicates the types of messages in the queue; using it is the fastest way to discover whether the queue contains any messages. GetInputState returns TRUE if the queue contains mouse or keyboard messages. Both of these functions can be used to determine whether the queue contains messages that need to be processed.


Posting a Message

You can post a message to a message queue by using the PostMessage function. PostMessage places a message at the end of a thread's message queue and returns immediately, without waiting for the thread to process the message. The function's parameters include a window handle, a message identifier, and two message parameters. Windows copies these parameters to an MSG structure, fills the time and pt members of the structure, and places the structure in the message queue.

Windows uses the window handle passed with the PostMessage function to determine which thread message queue should receive the message. If the handle is HWND_TOPMOST, Windows posts the message to the thread message queues of all top-level windows.

You can use the PostThreadMessage function to post a message to a specific thread message queue. PostThreadMessage is similar to PostMessage, except the first parameter is a thread identifier rather than a window handle. You can retrieve the thread identifier by calling the GetCurrentThreadId function.

Use the PostQuitMessage function to exit a message loop. PostQuitMessage posts the WM_QUIT message to the currently executing thread. The thread's message loop terminates and returns control to Windows when it encounters the WM_QUIT message. An application usually calls PostQuitMessage in response to the WM_DESTROY message, as shown in the following example.

case WM_DESTROY:

    .

    . /* Perform cleanup tasks. */

    .

    PostQuitMessage(0);

    break;


Sending a Message

The SendMessage function is used to send a message directly to a window procedure. SendMessage calls a window procedure and waits for that procedure to process the message and return a result.

A message can be sent to any window in the system; all that is required is a window handle. Windows uses the handle to determine which window procedure should receive the message.

If a window procedure yields control when processing a message sent by another thread, a message deadlock may result. (For more information about message deadlocks, see Message Deadlocks.) Before processing a message that may have been sent from another thread, a window procedure should first call the InSendMessage function. If this function returns TRUE, the window procedure should call ReplyMessage before any function that causes the thread to yield control, as shown in the following example.

case WM_USER + 5:

    if (InSendMessage())

        ReplyMessage(TRUE);

    DialogBox(hInst, "MyDialogBox", hwndMain, (DLGPROC) MyDlgProc);

    break;

A number of messages can be sent to controls in a dialog box. These control messages set the appearance, behavior, and content of controls or retrieve information about controls. For example, the CB_ADDSTRING message can add a string to a combo box, and the BM_SETCHECK message can set the check state of a check box or radio button.

Use the SendDlgItemMessage function to send a message to a control, specifying the identifier of the control and the handle of the dialog box window that contains the control. The following example, taken from a dialog box procedure, copies a string from a combo box's edit control into its list box. The example uses SendDlgItemMessage to send a CB_ADDSTRING message to the combo box.

HWND hwndCombo;

int cTxtLen;

PSTR pszMem;

switch (uMsg) {

    case WM_COMMAND:

        switch (LOWORD(wParam)) {

            case IDD_ADDCBITEM:

                /*

                 * Get the handle of the combo box and the

                 * length of the string in the edit control

                 * of the combo box.

                 */

                hwndCombo = GetDlgItem(hwndDlg, IDD_COMBO);

                cTxtLen = GetWindowTextLength(hwndCombo);

                /*

                 * Allocate memory for the string and copy

                 * the string into the memory.

                 */

                pszMem = (PSTR) VirtualAlloc((LPVOID) NULL,

                    (DWORD) (cTxtLen + 1), MEM_COMMIT,

                    PAGE_READWRITE);

                GetWindowText(hwndCombo, pszMem,

                    cTxtLen + 1);

                /*

                 * Add the string to the list box of the

                 * combo box and remove the string from the

                 * edit control of the combo box.

                 */

                if (*pszMem != NULL) {

                    SendDlgItemMessage(hwndDlg, IDD_COMBO,

                        CB_ADDSTRING, 0,

                        (DWORD) ((LPSTR) pszMem));

                    SetWindowText(hwndCombo, (LPSTR) NULL);

                }

                /* Free the memory and return. */

                VirtualFree(pszMem, 0, MEM_RELEASE);

                return TRUE;

            .

            . /* Process other dialog box commands. */

            .

        }

    .

    . /* Process other dialog box messages. */

    .

}


Message and Message Queue Functions

Following are the functions used with messages and message queues.

BroadcastSystemMessage
DefWindowProc
DispatchMessage
GetInputState
GetMessage
GetMessageExtraInfo
GetMessagePos
GetMessageTime
GetQueueStatus
InSendMessage
PeekMessage
PostAppMessage
PostMessage
PostQuitMessage
PostThreadMessage
RegisterWindowMessage
ReplyMessage
SendAsyncProc
SendMessage
SendMessageCallback
SendMessageTimeout
SendNotifyMessage
SetMessageExtraInfo
TranslateMessage
WaitMessage

Obsolete or Deleted Functions

SetMessageQueue


Mouse Input

This overview describes how Windows generates mouse input and explains how an application receives and processes that input.


About Mouse Input

The mouse is an important, but optional, user-input device for applications written for Microsoft® Windows®. A well-written Windows-based application should include a mouse interface, but it should not depend on the mouse as the sole means of acquiring user input. The application should provide full keyboard support as well.

A Windows-based application receives mouse input in the form of messages that are sent or posted to its windows.


Mouse Cursor

When the user moves the mouse, the system moves a bitmap on the screen called the mouse cursor. The mouse cursor contains a single-pixel point called the hot spot, a point that the system tracks and recognizes as the position of the cursor. When a mouse event occurs, the window that contains the hot spot typically receives the mouse message resulting from the event. The window need not be active or have the keyboard focus to receive a mouse message.

The system maintains a variable that controls the mouse speed — that is, the distance the cursor moves when the user moves the mouse. You can use the SystemParametersInfo function with the SPI_GETMOUSE or SPI_SETMOUSE flag to retrieve or set the mouse speed. For more information about mouse cursors, see Cursors.


Mouse Capture

The system typically posts a mouse message to the window that contains the cursor hot spot at the time a mouse event occurs. An application can change this behavior by using the SetCapture function to route mouse messages to a specific window. The window receives all mouse messages until the application calls the ReleaseCapture function or specifies another capture window, or until the user clicks a window created by another thread.

Whenever the mouse capture changes, Windows sends a WM_CAPTURECHANGED message to the window that is losing the mouse capture. The lParam parameter of the message specifies the handle of the window that is gaining the mouse capture.

Only the foreground window can capture mouse input. When a background window attempts to capture mouse input, it receives messages only for mouse events that occur when the cursor hot spot is within the visible portion of the window.

Capturing mouse input is useful if a window must receive all mouse input, even when the cursor moves outside the window. For example, an application typically tracks the cursor position after a mouse "button down" event, following the cursor until a "button up" event occurs. If an application has not captured mouse input and the user releases the mouse button outside the window, the window does not receive the button up message.

A thread can use the GetCapture function to determine whether one of its windows has captured the mouse. If one of the thread's windows has captured the mouse, GetCapture retrieves the handle of the window.


Mouse Configuration

Although the mouse is an important input device for Windows-based applications, not every user necessarily has a mouse. An application can determine whether the system includes a mouse by passing the SM_MOUSEPRESENT value to the GetSystemMetrics function.

Windows supports a mouse having up to three buttons. On a three-button mouse, the buttons are designated as the left, middle, and right buttons. Windows messages and named constants related to the mouse buttons use the letters L, M, and R to identify the buttons. The button on a single-button mouse is considered to be the left button. Although Windows supports a mouse with multiple buttons, most applications use the left button primarily and use the others little, if at all.

An application can determine the number of buttons on the mouse by passing the SM_CMOUSEBUTTONS value to the GetSystemMetrics function. To configure the mouse for a left-handed user, the application can use the SwapMouseButton function to reverse the meaning of the left and right mouse buttons. Passing the SPI_SETMOUSEBUTTONSWAP value to the SystemParametersInfo function is another way to reverse the meaning of the buttons. Note, however, that the mouse is a shared resource, so reversing the meaning of the buttons affects all applications.


Mouse Messages

The mouse generates an input event whenever the user moves the mouse, or presses or releases a mouse button. Windows converts mouse input events into messages and posts them to the appropriate thread's message queue. When mouse messages are posted faster than a thread can process them, Windows discards all but the most recent mouse message.

A window receives a mouse message when a mouse event occurs while the cursor is within the borders of the window, or when the window has captured the mouse. Mouse messages are divided into two groups: client area messages and nonclient area messages. Typically, an application processes client area messages and ignores nonclient area messages.


Client Area Mouse Messages

A window receives a client area mouse message when a mouse event occurs within the window's client area. The system posts the WM_MOUSEMOVE message to the window when the user moves the cursor within the client area. It posts one of the following messages when the user presses or releases a mouse button while the cursor is within the client area.

Message	Meaning
WM_LBUTTONDBLCLK	The left mouse button was double-clicked.
WM_LBUTTONDOWN	The left mouse button was pressed.
WM_LBUTTONUP	The left mouse button was released.
WM_MBUTTONDBLCLK	The middle mouse button was double-clicked.
WM_MBUTTONDOWN	The middle mouse button was pressed.
WM_MBUTTONUP	The middle mouse button was released.
WM_RBUTTONDBLCLK	The right mouse button was double-clicked.
WM_RBUTTONDOWN	The right mouse button was pressed.
WM_RBUTTONUP	The right mouse button was released.
Message Parameters

The lParam parameter of a client area mouse message indicates the position of the cursor hot spot. The low-order word indicates the x-coordinate of the hot spot, and the high-order word indicates the y-coordinate. The coordinates are given in client coordinates. In the client coordinate system, all points on the screen are given relative to the coordinates (0,0) of the upper left corner of the client area.

The wParam parameter contains flags that indicate the status of the other mouse buttons and the CTRL and SHIFT keys at the time of the mouse event. You can check for these flags when mouse-message processing depends on the state of another mouse button or of the CTRL or SHIFT key. The lParam parameter can be a combination of the following values.

Value	Meaning
MK_CONTROL	The CTRL key is down.
MK_LBUTTON	The left mouse button is down.
MK_MBUTTON	The middle mouse button is down.
MK_RBUTTON	The right mouse button is down.
MK_SHIFT	The SHIFT key is down.
Double-Click Messages

The system generates a double-click message when the user clicks a mouse button twice in quick succession. When the user clicks a button, the system establishes a rectangle centered around the cursor hot spot. It also marks the time at which the click occurred. When the user clicks the same button a second time, the system determines whether the hot spot is still within the rectangle and calculates the time elapsed since the first click. If the hot spot is still within the rectangle and the elapsed time does not exceeded the double-click time-out value, the system generates a double-click message.

An application can get and set double-click time-out values by using the GetDoubleClickTime and SetDoubleClickTime functions, respectively. Alternatively, the application can set the double-click time-out value by using the SPI_SETDOUBLECLICKTIME flag with the SystemParametersInfo function. It can also set the size of the rectangle that Windows uses to detect double-clicks by passing the SPI_SETDOUBLECLKWIDTH and SPI_SETDOUBLECLKHEIGHT flags to SystemParametersInfo. Note, however, that setting the double-click time-out value and rectangle affects all applications.

An application-defined window does not, by default, receive double-click messages. Because of the system overhead involved in generating double-click messages, these messages are generated only for windows belonging to classes that have the CS_DBLCLKS class style. Your application must set this style when registering the window class. For more information about window classes, see Window Classes.

A double-click message is always the third message in a four-message series. The first two messages are the button down and button up messages generated by the first click. The second click generates the double-click message followed by another button up message. For example, double-clicking the left mouse button generates the following message sequence:

WM_LBUTTONDOWN
WM_LBUTTONUP
WM_LBUTTONDBLCLK
WM_LBUTTONUP

Because a window always receives a button down message before receiving a double-click message, an application typically uses a double-click message to extend a task it began during a button down message. For example, when the user clicks a color in the color palette of Windows Paintbrush™, Paintbrush displays the selected color next to the palette. When the user double-clicks a color, Paintbrush displays the color and opens the Edit Colors dialog box.


Nonclient Area Mouse Messages

A window receives a nonclient area mouse message when a mouse event occurs in any part of a window except the client area. A window's nonclient area consists of its border, menu bar, title bar, scroll bar, System menu (also called the Control menu), Minimize button, and Maximize button.

Windows generates nonclient area messages primarily for its own use. For example, Windows uses nonclient area messages to change the cursor to a two-headed arrow when the cursor hot spot moves into a window's border. A window must pass nonclient area mouse messages to the DefWindowProc function to take advantage of the built-in mouse interface found in Windows.

There is a corresponding nonclient area mouse message for each client area mouse message. The names of these messages are similar except that the named constants for the nonclient area messages include the letters "NC". For example, moving the cursor in the nonclient area generates a WM_NCMOUSEMOVE message, and pressing the left mouse button while the cursor is in the nonclient area generates a WM_NCLBUTTONDOWN message.

The lParam parameter of a nonclient area mouse message is a POINTS structure that contains the x- and y-coordinates of the cursor hot spot. Unlike coordinates of client area mouse messages, the coordinates are given in screen coordinates rather than client coordinates. In the screen coordinate system, all points on the screen are relative to the coordinates (0,0) of the upper left corner of the screen.

The wParam parameter contains a hit-test value, a value that indicates where in the nonclient area the mouse event occurred. The following section explains the purpose of hit-test values.


The WM_NCHITTEST Message

Whenever a mouse event occurs, the system sends a WM_NCHITTEST message to either the window that contains the cursor hot spot or the window that has captured the mouse. Windows uses this message to determine whether to send a client area or nonclient area mouse message. An application that must receive mouse movement and mouse button messages must pass the WM_NCHITTEST message to the DefWindowProc function.

The lParam parameter of the WM_NCHITTEST message contains the screen coordinates of the cursor hot spot. The DefWindowProc function examines the coordinates and returns a hit-test value that identifies the location of the hot spot. The hit-test value can be one of the following values.

Value	Location of hot spot
HTBORDER	In the border of a window that does not have a sizing border
HTBOTTOM	In the lower horizontal border of a window
HTBOTTOMLEFT	In the lower left corner of a window border
HTBOTTOMRIGHT	In the lower right corner of a window border
HTCAPTION	In a title bar
HTCLIENT	In a client area
HTCLOSE	In close button.
HTERROR	On the screen background or on a dividing line between windows (same as HTNOWHERE, except that the DefWindowProc function produces a system beep to indicate an error)
HTGROWBOX	In a size box (same as HTSIZE)
HTHELP	In Help button.
HTHSCROLL	In a horizontal scroll bar
HTLEFT	In the left border of a window
HTMENU	In a menu
HTMAXBUTTON	In Maximize button.
HTMINBUTTON	In Minimize button.
HTNOWHERE	On the screen background or on a dividing line between windows
HTREDUCE	In a Minimize button
HTRIGHT	In the right border of a window
HTSIZE	In a size box (same as HTGROWBOX)
HTSYSMENU	In a System menu or in a Close button in a child window
HTTOP	In the upper horizontal border of a window
HTTOPLEFT	In the upper left corner of a window border
HTTOPRIGHT	In the upper right corner of a window border
HTTRANSPARENT	In a window currently covered by another window
HTVSCROLL	In the vertical scroll bar
HTZOOM	In a Maximize button
If the cursor is in the client area of a window, DefWindowProc returns the HTCLIENT hit-test value to the window procedure. When the window procedure returns this code to the system, Windows converts the screen coordinates of the cursor hot spot to client coordinates, and then posts the appropriate client area mouse message.

The DefWindowProc function returns one of the other hit-test values when the cursor hot spot is in a window's nonclient area. When the window procedure returns one of these hit-test values, Windows posts a nonclient area mouse message, placing the hit-test value in the message's wParam parameter and the cursor coordinates in the lParam parameter.


Window Activation

When the user clicks an inactive top-level window or the child window of a inactive top-level window, Windows sends the WM_MOUSEACTIVATE message (among others) to the top-level or child window. Windows sends this message after posting the WM_NCHITTEST message to the window, but before posting the button down message. When WM_MOUSEACTIVATE is passed to the DefWindowProc function, Windows activates the top-level window and then posts the button down message to the top-level or child window.

By processing WM_MOUSEACTIVATE, a window can control whether the top-level window becomes the active window as a result of a mouse click, and whether the window that was clicked receives the subsequent button down message. It does so by returning one of the following values after processing WM_MOUSEACTIVATE.

Value	Meaning
MA_ACTIVATE	Activates the window and does not discard the mouse message.
MA_NOACTIVATE	Does not activate the window and does not discard the mouse message.
MA_ACTIVATEANDEAT	Activates the window and discards the mouse message.
MA_NOACTIVATEANDEAT	Does not activate the window but discards the mouse message.


Using Mouse Input

•	Tracking the mouse cursor

•	Drawing lines with the mouse

•	Processing a double-click message

•	Selecting a line of text


Tracking the Mouse Cursor

Windows-based applications often perform tasks that involve tracking the position of the mouse cursor. Most drawing applications, for example, track it during drawing operations, allowing the user to draw in a window's client area by dragging the mouse. Word-processing applications also track the cursor, enabling the user to select a word or block of text by clicking and dragging the mouse.

Tracking the cursor typically involves processing the WM_LBUTTONDOWN, WM_MOUSEMOVE, and WM_LBUTTONUP messages. A window determines when to begin tracking the cursor by checking the cursor position provided in the lParam parameter of the WM_LBUTTONDOWN message. For example, a word-processing application would begin tracking the cursor only if the WM_LBUTTONDOWN message occurred while the cursor was on a line of text, but not if it was past the end of the document.

A window tracks the position of the cursor by processing the stream of WM_MOUSEMOVE messages posted to the window as the mouse moves. Processing the WM_MOUSEMOVE message typically involves a repetitive painting or drawing operation in the client area. For example, a drawing application might redraw a line repeatedly as the mouse moves. A window uses the WM_LBUTTONUP message as a signal to stop tracking the cursor.


Drawing Lines with the Mouse

The example in this section demonstrates how to track the mouse cursor. It contains portions of a window procedure that enables the user to draw lines in a window's client area by dragging the mouse.

When the window procedure receives a WM_LBUTTONDOWN message, it captures the mouse and saves the coordinates of the cursor, using the coordinates as the starting point of the line. It also uses the ClipCursor function to confine the cursor to the client area during the line drawing operation.

During the first WM_MOUSEMOVE message, the window procedure draws a line from the starting point to the current position of the cursor. During subsequent WM_MOUSEMOVE messages, the window procedure erases the previous line by drawing over it with an inverted pen color. Then it draws a new line from the starting point to the new position of the cursor.

The WM_LBUTTONUP message signals the end of the drawing operation. The window procedure releases the mouse capture and frees the mouse from the client area.

LRESULT APIENTRY MainWndProc(hwndMain, uMsg, wParam, lParam)

HWND hwndMain;

UINT uMsg;

WPARAM wParam;

LPARAM lParam;

{

    HDC hdc;                       /* handle of device context  */

    RECT rcClient;                 /* client area rectangle     */

    POINT ptClientUL;              /* client upper left corner  */

    POINT ptClientLR;              /* client lower right corner */

    static POINTS ptsBegin;        /* beginning point           */

    static POINTS ptsEnd;          /* new endpoint              */

    static POINTS ptsPrevEnd;      /* previous endpoint         */

    static BOOL fPrevLine = FALSE; /* previous line flag        */

    switch (uMsg) {

        case WM_LBUTTONDOWN:

            /* Capture mouse input. */

            SetCapture(hwndMain);

            /*

             * Retrieve the screen coordinates of the client area,

             * and convert them into client coordinates.

            /*

            GetClientRect(hwndMain, &rcClient);

            ptClientUL.x = rcClient.left;

            ptClientUL.y = rcClient.top;

            /*

             * Add one to the right and bottom sides, because the

             * coordinates retrieved by GetClientRect do not

             * include the far left and lowermost pixels.

             */

            ptClientLR.x = rcClient.right + 1;

            ptClientLR.y = rcClient.bottom + 1;

            ClientToScreen(hwndMain, &ptClientUL);

            ClientToScreen(hwndMain, &ptClientLR);

            /*

             * Copy the client coordinates of the client area

             * to the rcClient structure. Confine the mouse cursor

             * to the client area by passing the rcClient structure

             * to the ClipCursor function.

             */

            SetRect(&rcClient, ptClientUL.x, ptClientUL.y,

                ptClientLR.x, ptClientLR.y);

            ClipCursor(&rcClient);

            /*

             * Convert the cursor coordinates into a POINTS

             * structure, which defines the beginning point of the

             * line drawn during a WM_MOUSEMOVE message.

             */

            ptsBegin = MAKEPOINTS(lParam);

            return 0;

        case WM_MOUSEMOVE:

            /*

             * When moving the mouse, the user must hold down

             * the left mouse button to draw lines.

             */

            if (wParam & MK_LBUTTON) {

                /*

                 * Retrieve a device context (DC) for the client

                 * area.

                 */

                hdc = GetDC(hwndMain);

                /*

                 * The following function ensures that pixels of

                 * the previously drawn line are set to white and

                 * those of the new line are set to black.

                 */

                SetROP2(hdc, R2_NOTXORPEN);

                /*

                 * If a line was drawn during an earlier

                 * WM_MOUSEMOVE message, draw over it. This erases

                 * the line by setting the color of its pixels to

                 * white.

                 */

                if (fPrevLine) {

                    MoveToEx(hdc, ptsBegin.x, ptsBegin.y,

                        (LPPOINT) NULL);

                    LineTo(hdc, ptsPrevEnd.x, ptsPrevEnd.y);

                }

                /*

                 * Convert the current cursor coordinates to a

                 * POINTS structure, and then draw a new line.

                 */

                ptsEnd = MAKEPOINTS(lParam);

                MoveToEx(hdc, ptsBegin.x, ptsBegin.y,

                    (LPPOINT) NULL);

                LineTo(hdc, ptsEnd.x, ptsEnd.y);

                /*

                 * Set the previous line flag, save the ending

                 * point of the new line, and then release the DC.

                 */

                fPrevLine = TRUE;

                ptsPrevEnd = ptsEnd;

                ReleaseDC(hwndMain, hdc);

            }

            break;

        case WM_LBUTTONUP:

            /*

             * The user has finished drawing the line. Reset the

             * previous line flag, release the mouse cursor, and

             * release the mouse capture.

             */

            fPrevLine = FALSE;

            ClipCursor(NULL);

            ReleaseCapture();

            return 0;

        case WM_DESTROY:

            PostQuitMessage(0);

            break;

        .

        . /* Process other messages. */

        .


Processing a Double-Click Message

To receive double-click messages, a window must belong to a window class that has the CS_DBLCLKS class style. You set this style when registering the window class, as shown in the following example.

BOOL InitApplication(hInstance)

HINSTANCE hInstance;

{

    WNDCLASS wc;

    wc.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;

    wc.lpfnWndProc = (WNDPROC) MainWndProc;

    wc.cbClsExtra = 0;

    wc.cbWndExtra = 0;

    wc.hInstance = hInstance;

    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);

    wc.hCursor = LoadCursor(NULL, IDC_IBEAM);

    wc.hbrBackground = GetStockObject(WHITE_BRUSH);

    wc.lpszMenuName = "MainMenu";

    wc.lpszClassName = "MainWClass";

    return RegisterClass(&wc);

}

A double-click message is always preceded by a button down message. For this reason, applications typically use a double-click message to extend a task that it began during a button down message.


Selecting a Line of Text

The example in this section is taken from a simple word-processing application. It includes code that enables the user to set the position of the caret by clicking anywhere on a line of text, and to select (highlight) a line of text by double-clicking anywhere on the line.

LRESULT APIENTRY MainWndProc(hwndMain, uMsg, wParam, lParam)

HWND hwndMain;

UINT uMsg;

WPARAM wParam;

LPARAM lParam;

{

    HDC hdc;                     /* handle of device context     */

    TEXTMETRIC tm;               /* font size data               */

    int i, j;                    /* loop counters                */

    int cCR = 0;                 /* count of carriage returns    */

    char ch;                     /* character from input buffer  */

    static int nBegLine;         /* beginning of selected line   */

    static int nCurrentLine = 0; /* currently selected line      */

    static int nLastLine = 0;    /* last text line               */

    static int nCaretPosX = 0;   /* x-coordinate of caret        */

    static int cch = 0;          /* number of characters entered */

    static int nCharWidth = 0;   /* exact width of a character   */

    static char szHilite[128];   /* text string to highlight     */

    static DWORD dwCharX;        /* average width of characters  */

    static DWORD dwLineHeight;   /* line height                  */

    static POINTS ptsCursor;     /* coordinates of mouse cursor  */

    static COLORREF crPrevText;  /* previous text color          */

    static COLORREF crPrevBk;    /* previous background color    */

    static PTCHAR pchInputBuf;   /* address of input buffer      */

    static BOOL fTextSelected = FALSE; /* text-selection flag    */

    switch (uMsg) {

        case WM_CREATE:

            /* Get the metrics of the current font. */

            hdc = GetDC(hwndMain);

            GetTextMetrics(hdc, &tm);

            ReleaseDC(hwndMain, hdc);

            /* Save the average character width and height. */

            dwCharX = tm.tmAveCharWidth;

            dwLineHeight = tm.tmHeight;

            /* Allocate a buffer to store keyboard input. */

            pchInputBuf = (LPSTR) GlobalAlloc(GPTR,

                BUFSIZE * sizeof(TCHAR));

            return 0;

        case WM_CHAR:

            switch (wParam) {

                case 0x08:  /* backspace */

                case 0x0A:  /* linefeed */

                case 0x1B:  /* escape */

                    MessageBeep(0xFFFFFFFF);

                    return 0;

                case 0x09:  /* tab */

                    /* Convert tabs to four consecutive spaces. */

                    for (i = 0; i < 4; i++)

                        SendMessage(hwndMain, WM_CHAR, 0x20, 0);

                    return 0;

                case 0x0D:  /* carriage return */

                    /*

                     * Record the carriage return, and position the

                     * caret at the beginning of the new line.

                     */

                    pchInputBuf[cch++] = 0x0D;

                    nCaretPosX = 0;

                    nCurrentLine += 1;

                    break;

                default:    /* displayable character */

                    ch = (char) wParam;

                    HideCaret(hwndMain);

                    /*

                     * Retrieve the character's width, and display the

                     * character.

                     */

                    hdc = GetDC(hwndMain);

                    GetCharWidth32(hdc, (UINT) wParam, (UINT) wParam,

                        &nCharWidth);

                    TextOut(hdc, nCaretPosX,

                        nCurrentLine * dwLineHeight, &ch, 1);

                    ReleaseDC(hwndMain, hdc);

                    /* Store the character in the buffer. */

                    pchInputBuf[cch++] = ch;

                    /*

                     * Calculate the new horizontal position of

                     * the caret. If the new position exceeds the

                     * maximum, insert a carriage return and

                     * reposition the caret at the beginning of

                     * the next line.

                     */

                    nCaretPosX += nCharWidth;

                    if ((DWORD) nCaretPosX > dwMaxCharX) {

                        nCaretPosX = 0;

                        pchInputBuf[cch++] = 0x0D;

                        ++nCurrentLine;

                    }

                    ShowCaret(hwndMain);

                    break;

            }

            SetCaretPos(nCaretPosX, nCurrentLine * dwLineHeight);

            nLastLine = max(nLastLine, nCurrentLine);

            break;

        .

        . /* Process other messages. */

        .

        case WM_LBUTTONDOWN:

            /*

             * If a line of text is currently highlighted, redraw

             * the text to remove the highlighting.

             */

            if (fTextSelected) {

                hdc = GetDC(hwndMain);

                SetTextColor(hdc, crPrevText);

                SetBkColor(hdc, crPrevBk);

                TextOut(hdc, 0, nCurrentLine * dwLineHeight,

                    szHilite, lstrlen(szHilite));

                ReleaseDC(hwndMain, hdc);

                ShowCaret(hwndMain);

                fTextSelected = FALSE;

            }

            /* Save the current mouse-cursor coordinates. */

            ptsCursor = MAKEPOINTS(lParam);

            /*

             * Determine which line the cursor is on, and save

             * the line number. Do not allow line numbers greater

             * than the number of the last line of text. The

             * line number is later multiplied by the average height

             * of the current font. The result is used to set the

             * y-coordinate of the caret.

             */

            nCurrentLine = min((int)(ptsCursor.y / dwLineHeight),

                nLastLine);

            /*

             * Parse the text input buffer to find the first

             * character in the selected line of text. Each

             * line ends with a carriage return, so it is possible

             * to count the carriage returns to find the selected

             * line.

             */

            cCR = 0;

            nBegLine = 0;

            if (nCurrentLine != 0) {

                for (i = 0; (i < cch) &&

                        (cCR < nCurrentLine); i++) {

                    if (pchInputBuf[i] == 0x0D)

                        ++cCR;

                }

                nBegLine = i;

            }

            /*

             * Starting at the beginning of the selected line,

             * measure  the width of each character, summing the

             * width with each character measured. Stop when the

             * sum is greater than the x-coordinate of the cursor.

             * The sum is used to set the x-coordinate of the caret.

             */

            hdc = GetDC(hwndMain);

            nCaretPosX = 0;

            for (i = nBegLine;

                    (pchInputBuf[i] != 0x0D) && (i < cch); i++) {

                ch = pchInputBuf[i];

                GetCharWidth32(hdc, (int) ch, (int) ch, &nCharWidth);

                if ((nCaretPosX + nCharWidth) > ptsCursor.x)

                    break;

                else

                    nCaretPosX += nCharWidth;

            }

            ReleaseDC(hwndMain, hdc);

            /* Set the caret to the user-selected position. */

            SetCaretPos(nCaretPosX, nCurrentLine * dwLineHeight);

            break;

        case WM_LBUTTONDBLCLK:

            /* Copy the selected line of text to a buffer. */

            for (i = nBegLine, j = 0; (pchInputBuf[i] != 0x0D) &&

                    (i < cch); i++)

                szHilite[j++] = pchInputBuf[i];

            szHilite[j] = '\0';

            /*

             * Hide the caret, invert the background and foreground

             * colors, and then redraw the selected line.

             */

            HideCaret(hwndMain);

            hdc = GetDC(hwndMain);

            crPrevText = SetTextColor(hdc, RGB(255, 255, 255));

            crPrevBk = SetBkColor(hdc, RGB(0, 0, 0));

            TextOut(hdc, 0, nCurrentLine * dwLineHeight, szHilite,

                lstrlen(szHilite));

            SetTextColor(hdc, crPrevText);

            SetBkColor(hdc, crPrevBk);

            ReleaseDC(hwndMain, hdc);

            fTextSelected = TRUE;

            break;

            .

            . /* Process other messages. */

            .

        default:

            return DefWindowProc(hwndMain, uMsg, wParam, lParam);

    }

    return NULL;

}


Mouse Input Reference

The following functions and messages are associated with mouse input.


Mouse Input Functions

Following are the functions used with mouse input.

DragDetect
GetCapture
GetDoubleClickTime
mouse_event
ReleaseCapture
SetCapture
SetDoubleClickTime
SwapMouseButton


Mouse Input Messages

Following are the messages used with mouse input.

WM_CAPTURECHANGED
WM_LBUTTONDBLCLK
WM_LBUTTONDOWN
WM_LBUTTONUP
WM_MBUTTONDBLCLK
WM_MBUTTONDOWN
WM_MBUTTONUP
WM_MOUSEACTIVATE
WM_MOUSEMOVE
WM_NCHITTEST
WM_NCLBUTTONDBLCLK
WM_NCLBUTTONDOWN
WM_NCLBUTTONUP
WM_NCMBUTTONDBLCLK
WM_NCMBUTTONDOWN
WM_NCMBUTTONUP
WM_NCMOUSEMOVE
WM_NCRBUTTONDBLCLK
WM_NCRBUTTONDOWN
WM_NCRBUTTONUP
WM_RBUTTONDBLCLK
WM_RBUTTONDOWN
WM_RBUTTONUP


Painting and Drawing

This overview describes how Windows manages output to the screen and explains what applications must do to draw in a window. In particular, this overview describes display device contexts (or, more simply, display DCs) and how to prepare and use them. The overview does not explain how to use graphics device interface (GDI) functions to generate output, nor does it explain how to print.


About Painting and Drawing

Nearly all applications use the screen to display the data they manipulate. An application paints images, draws figures, and writes text so that the user can view data as it is created, edited, and printed. Microsoft® Windows® provides a rich environment for painting and drawing, but, because Windows is a multitasking operating system, applications must cooperate with one another when accessing the screen.

To keep all applications functioning smoothly and cooperatively, Windows manages all output to the screen. Applications use windows as their primary output device rather than the screen itself. Windows supplies display DCs that uniquely correspond to the windows. Applications use display DCs to direct their output to the given windows. Drawing in a window (directing output to it) prevents an application from interfering with the output of other applications and allows applications to coexist with one another while still taking full advantage of the graphics capabilities of Windows.


When to Draw in a Window

An application draws in a window at a variety of times: when first creating a window, when changing the size of the window, when moving the window from behind another window, when minimizing or maximizing the window, when displaying data from an opened file, and when scrolling, changing, or selecting a portion of the displayed data.

Windows manages actions such as moving and sizing a window. If an action affects the content of the window, Windows marks the affected portion of the window as ready for updating and, at the next opportunity, sends a WM_PAINT message to the window procedure of the window. The message is a signal to the application to determine what must be updated and to carry out the necessary drawing.

Some actions are managed by the application, such as displaying open files and selecting displayed data. For these actions, an application can mark for updating the portion of the window affected by the action, causing a WM_PAINT message to be sent at the next opportunity. If an action requires immediate feedback, the application can draw while the action takes place, without waiting for WM_PAINT. For example, a typical application highlights the area the user selects rather than waiting for the next WM_PAINT message to update the area.

In all cases, an application can draw in a window as soon as it is created. To draw in the window, the application must first retrieve a handle of a display DC for the window. Ideally, an application carries out most of its drawing operations during the processing of WM_PAINT messages. In this case, the application retrieves a display DC by calling the BeginPaint function. If an application draws at any other time, such as from within WinMain or during processing of keyboard or mouse messages, it calls the GetDC or GetDCEx function to retrieve the display DC.


The WM_PAINT Message

Typically, an application draws in a window in response to a WM_PAINT message. Windows sends this message to a window procedure when changes to the window have altered the content of the client area. Windows sends the message only if there are no other messages in the application message queue.

Upon receiving a WM_PAINT message, an application can call BeginPaint to retrieve the display DC for the client area and use it in calls to GDI functions to carry out whatever drawing operations are necessary to update the client area. After completing the drawing operations, the application calls the EndPaint function to release the display DC.

Before BeginPaint returns the display DC, Windows prepares the DC for the given window. It first sets the clipping region for the DC to be equal to the intersection of the portion of the window that needs updating and the portion that is visible to the user. Only those portions of the window that have changed are redrawn. Attempts to draw outside this region are clipped and do not appear on the screen.

Windows can also send WM_NCPAINT and WM_ERASEBKGND messages to the window procedure before BeginPaint returns. These messages direct the application to draw the nonclient area and window background. The nonclient area is the part of a window that is outside of the client area. The area includes features such as the title bar, System menu (also known as the Control menu), and scroll bars. Most applications rely on the default window function, DefWindowProc, to draw this area and therefore pass the WM_NCPAINT message to this function. The window background is the color or pattern a window is filled with before other drawing operations begin. The background covers any images previously in the window or on the screen under the window. If a window belongs to a window class having a class background brush, the DefWindowProc function draws the window background automatically.

BeginPaint fills a PAINTSTRUCT structure with information such as the dimensions of the portion of the window to be updated and a flag indicating whether the window background has been drawn. The application can use this information to optimize drawing. For example, it can use the dimensions of the update region, specified by the rcPaint member, to limit drawing to only those portions of the window that need updating. If an application has very simple output, it can ignore the update region and draw in the entire window, relying on Windows to discard (clip) any unneeded output. Because the system clips drawing that extends outside the clipping region, only drawing that is in the update region is visible.

BeginPaint sets the update region of a window to NULL. This clears the region, preventing it from generating subsequent WM_PAINT messages. If an application processes a WM_PAINT message but does not call BeginPaint or otherwise clear the update region, the application continues to receive WM_PAINT messages as long as the region is not empty. In all cases, an application must clear the update region before returning from the WM_PAINT message.

After the application finishes drawing, it should call EndPaint. For most windows, EndPaint releases the display DC, making it available to other windows. EndPaint also shows the caret, if it was previously hidden by BeginPaint. BeginPaint hides the caret to prevent drawing operations from corrupting it.


The Update Region

The update region identifies the portion of a window that is out-of-date or invalid and in need of redrawing. Windows uses the update region to generate WM_PAINT messages for applications and to minimize the time applications spend bringing the contents of their windows up to date. Windows adds only the invalid portion of the window to the update region, requiring only that portion to be drawn.

When Windows determines that a window needs updating, it sets the dimensions of the update region to the invalid portion of the window. Setting the update region does not immediately cause the application to draw. Instead, the application continues retrieving messages from the application message queue until no messages remain. Windows then checks the update region, and if the region is not empty (non-NULL), it sends a WM_PAINT message to the window procedure.

An application can use the update region to generate its WM_PAINT messages. For example, an application that loads data from open files typically sets the update region while loading so that new data is drawn during processing of the next WM_PAINT message. In general, an application should not draw at the time its data changes, but route all drawing operations through the WM_PAINT message.


Invalidating and Validating the Update Region

An application invalidates a portion of a window and sets the update region by using the InvalidateRect or InvalidateRgn function. These functions add the specified rectangle or region (given in client coordinates) to the update region, combining the rectangle or region with anything Windows or the application may have previously added to the update region.

The InvalidateRect and InvalidateRgn functions do not generate WM_PAINT messages. Instead, Windows accumulates the changes made by these functions and its own changes while a window processes other messages in its message queue. By accumulating changes, a window processes all changes at once instead of updating bits and pieces one step at a time.

The ValidateRect and ValidateRgn functions validate a portion of the window by removing a specified rectangle or region from the update region. These functions are typically used when the window has updated a specific part of the screen in the update region before receiving the WM_PAINT message.


Retrieving the Update Region

The GetUpdateRect and GetUpdateRgn functions retrieve the current update region for the window. GetUpdateRect retrieves the smallest rectangle (in client coordinates) that encloses the entire update region. GetUpdateRgn retrieves the update region itself. These functions can be used to calculate the current size of the update region to determine where to carry out a drawing operation.

BeginPaint also retrieves the dimensions of the smallest rectangle enclosing the current update region, copying the dimensions to the rcPaint member in the PAINTSTRUCT structure. Because BeginPaint validates the update region, any call to GetUpdateRect and GetUpdateRgn immediately after a call to BeginPaint returns an empty update region.


Excluding the Update Region

The ExcludeUpdateRgn function excludes the update region from the clipping region for the display DC. This function is useful when drawing in a window other than when a WM_PAINT message is processing. It prevents drawing in the areas that will be updated during the next WM_PAINT message.


Synchronous and Asynchronous Drawing

Most drawing carried out during processing of the WM_PAINT message is asynchronous; that is, there is a delay between the time a portion of the window is invalidated and the time WM_PAINT is sent. During the delay, the application typically retrieves messages from the queue and carries out other tasks. The reason for the delay is that Windows generally treats drawing in a window as a low-priority operation and works as though user-input messages and messages that may affect the position or size of a window will be processed before WM_PAINT.

In some cases, it is necessary for an application to draw synchronously — that is, draw in the window immediately after invalidating a portion of the window. A typical application draws its main window immediately after creating the window to signal the user that the application has started successfully. Windows draws some control windows synchronously, such as buttons, because such windows serve as the focus for user input. Although any window with a simple drawing routine can be drawn synchronously, all such drawing should be done quickly and should not interfere with the application's ability to respond to user input.

The UpdateWindow and RedrawWindow functions allow for synchronous drawing. UpdateWindow sends a WM_PAINT message directly to the window if the update region is not empty. RedrawWindow also sends a WM_PAINT message, but gives the application greater control over how to draw the window, such as whether to draw the nonclient area and window background or whether to send the message regardless of whether the update region is empty. These functions send the WM_PAINT message directly to the window, regardless of the number of other messages in the application message queue.

Any window requiring time-consuming drawing operations should be drawn asynchronously to prevent pending messages from being blocked as the window is drawn. Also, any application that frequently invalidates small portions of a window should allow these invalid portions to consolidate into a single asynchronous WM_PAINT message, rather than a series of synchronous WM_PAINT messages.


Drawing Without the WM_PAINT Message

Although applications carry out most drawing operations while the WM_PAINT message is processing, it is sometimes more efficient for an application to draw directly in a window without relying on the WM_PAINT message. This can be useful when the user needs immediate feedback, such as when selecting text and dragging or sizing an object. In such cases, the application usually draws while processing keyboard or mouse messages.

To draw in a window without using a WM_PAINT message, the application uses the GetDC or GetDCEx function to retrieve a display DC for the window. With the display DC, the application can draw in the window and avoid intruding into other windows. When the application has finished drawing, it calls the ReleaseDC function to release the display DC for use by other applications.

When drawing without using a WM_PAINT message, the application usually does not invalidate the window. Instead, it draws in such a fashion that it can easily restore the window and remove the drawing. For example, when the user selects text or an object, the application typically draws the selection by inverting whatever is already in the window. The application can remove the selection and restore the original contents of the window by simply inverting again.

The application is responsible for carefully managing any changes it makes to the window. In particular, if an application draws a selection and an intervening WM_PAINT message occurs, the application must ensure that any drawing done during the message does not corrupt the selection. To avoid this, many applications remove the selection, carry out usual drawing operations, and then restore the selection when drawing is complete.


Window Coordinate System

The coordinate system for a window is based on the coordinate system of the display device. The basic unit of measure is the device unit (typically, the pixel). Points on the screen are described by x- and y-coordinate pairs. The x-coordinates increase to the right; y-coordinates increase from top to bottom. The origin (0,0) for the system depends on the type of coordinates being used.

Windows and applications specify the position of a window on the screen in screen coordinates. For screen coordinates, the origin is the upper left corner of the screen. The full position of a window is often described by a RECT structure containing the screen coordinates of two points that define the upper left and lower right corners of the window.

Windows and applications specify the position of points in a window by using client coordinates. The origin in this case is the upper left corner of the window or client area. Client coordinates ensure that an application can use consistent coordinate values while drawing in the window, regardless of the position of the window on the screen.

The dimensions of the client area are also described by a RECT structure that contains client coordinates for the area. In all cases, the upper left coordinate of the rectangle is included in the window or client area, while the lower right coordinate is excluded. Graphics operations in a window or client area are excluded from the right and lower edges of the enclosing rectangle.

Occasionally, applications may be required to map coordinates in one window to those of another window. An application can map coordinates by using the MapWindowPoints function. If one of the windows is the desktop window, the function effectively converts screen coordinates to client coordinates and vice versa; the desktop window is always specified in screen coordinates.


Window Regions

In addition to the update region, every window has a visible region that defines the window portion visible to the user. The system changes the visible region for the window whenever the window changes size or whenever another window is moved such that it obscures or exposes a portion of the window. Applications cannot change the visible region directly, but Windows automatically uses the visible region to create the clipping region for any display DC retrieved for the window.

The clipping region determines where the system permits drawing. When the application retrieves a display DC using the BeginPaint, GetDC, or GetDCEx function, the system sets the clipping region for the DC to the intersection of the visible region and the update region. Applications can change the clipping region by using functions such as SetWindowRgn, SelectClipPath and SelectClipRgn, to further limit drawing to a particular portion of the update area.

The WS_CLIPCHILDREN and WS_CLIPSIBLINGS styles further specify how Windows calculates the visible region for a window. If a window has one or both of these styles, the visible region excludes any child window or sibling windows (windows having the same parent window). Therefore, drawing that would otherwise intrude in these windows will always be clipped.


Window Background

The window background is the color or pattern used to fill the client area before a window begins drawing. The window background covers whatever was on the screen before the window was moved there, erasing existing images and preventing the application's new output from being mixed with unrelated information.

Windows paints the background for a window or gives the window the opportunity to do so by sending it a WM_ERASEBKGND message when the application calls BeginPaint. If an application does not process the message but passes it to DefWindowProc, Windows erases the background by filling it with the pattern in the background brush specified by the window's class. If the brush is not valid or the class has no background brush, Windows sets the fErase member in the PAINTSTRUCT structure BeginPaint returns, but carries out no other action. The application then has a second chance to draw the window background, if necessary.

If it processes WM_ERASEBKGND, the application should use the message's wParam parameter to draw the background. This parameter contains the handle of the display DC for the window. After drawing the background, the application should return a nonzero value. This ensures that BeginPaint does not erroneously set the fErase member of the PAINTSTRUCT structure to a nonzero value (indicating the background should be erased) when the application processes the subsequent WM_PAINT message.

An application can define a class background brush by assigning a brush handle or a system color value to the hbrBackground member of the WNDCLASS structure when registering the class with the RegisterClass function. The GetStockObject or CreateSolidBrush function can be used to create a brush handle. A system color value can be one of those defined for the SetSysColors function. (The value must be increased by one before it is assigned to the member.)

An application can process the WM_ERASEBKGND message even though a class background brush is defined. This is typical in applications that enable the user to change the window background color or pattern for a given window without affecting other windows in the class. In such cases, the application must not pass the message to DefWindowProc.

It is not necessary for an application to align brushes, because the system draws the brush using the window origin as the point of reference. Given this, the user can move the window without affecting the alignment of pattern brushes.


Minimized Windows

Windows reduces an application's main window (overlapping style) to a minimized window when the user chooses the Minimize command from the System menu or the application calls the ShowWindow function and specifies a value such as SW_MINIMIZE. Minimizing a window speeds up system performance by reducing the amount of work an application must do when updating its main window.

For a typical application, Windows draws an icon, called the class icon, when the window is minimized, labeling the icon with the name of the window. The class icon, a static image that represents the application, is specified by the application when it registers the window class. The application assigns the handle of the class icon to the hIcon member of WNDCLASS before calling RegisterClass. The application can use the LoadIcon function to retrieve the icon handle.

Before drawing the class icon, Windows sends a WM_ICONERASEBKGND message to the window procedure, enabling the application to prepare the background for drawing the icon by setting the best possible background colors for the icon. This is useful for applications that combine the icon with the current background colors. If the application processes the message, it should use the display DC provided with the message to draw the background (the wParam parameter contains the handle of the display DC). If the application does not process the WM_ICONERASEBKGND message, it should pass the message to DefWindowProc; the function fills the icon area with the current desktop color and pattern. After sending the WM_ICONERASEBKGND message, Windows sends the WM_PAINTICON message to the window procedure. The application should immediately forward this internal message to DefWindowProc.

Windows does not require that a window class have a class icon. If an application sets the hIcon member of WNDCLASS to NULL, a class icon is not defined. In this case, Windows sends the WM_ERASEBKGND message (instead of WM_ICONERASEBKGND) to a window of the class whenever the window must paint the icon background. Windows then sends a WM_PAINT message and the application draws an icon or another image representing the minimized window. In such cases, the application must determine when the window is minimized and draw accordingly. It can do so by calling the IsIconic function. If the function returns TRUE, the window is minimized. If an application has no class icon and fails to process WM_ERASEBKGND and WM_PAINT, the area that Windows reserves for the application's icon will contain whatever was previously on the screen.


Window Size

Windows changes the size of a window when the user chooses System menu commands, such as Size and Maximize, or when the application calls functions, such as the SetWindowPos function. When a window changes size, Windows assumes that the contents of the previously exposed portion of the window are not affected and need not be redrawn. Windows invalidates only the newly exposed portion of the window, which saves time when the eventual WM_PAINT message is processed by the application. In this case, WM_PAINT is not generated when the size of the window is reduced.

For some windows, any change to the size of the window invalidates the contents. For example, a clock application that adapts the face of the clock to fit neatly within its window must redraw the clock whenever the window changes size. To force Windows to invalidate the entire client area of the window when a vertical, horizontal, or both vertical and horizontal change is made, an application must specify the CS_VREDRAW or CS_HREDRAW style, or both, when registering the window class. Any window belonging to a window class having these styles is invalidated each time the user or the application changes the size of the window.


Nonclient Area

Windows sends a WM_NCPAINT message to the window whenever a part of the nonclient area of the window, such as the title bar, menu bar, or window frame, must be updated. Windows may also send other messages to direct a window to update a portion of its client area; for example, when a window becomes active or inactive, it sends the WM_NCACTIVATE message to update its title bar. In general, processing these messages for standard windows is not recommended, because the application must be able to draw all the required parts of the nonclient area for the window. For this reason, most applications pass these messages to DefWindowProc for default processing.

An application that creates custom nonclient areas for its windows must process these messages. When doing so, the application must use a window DC to carry out drawing in the window. The window DC enables the application to draw in all portions of the window, including the nonclient area. An application retrieves a window DC by using the GetWindowDC or GetDCEx function and, when drawing is complete, must release the window DC by using the ReleaseDC function.

Windows maintains an update region for the nonclient area. When an application receives a WM_NCPAINT message, the wParam parameter contains the handle of a region defining the dimensions of the update region. The application can use the handle to combine the update region with the clipping region for the window DC. Windows does not automatically combine the update region when retrieving the window DC unless the application uses GetDCEx and specifies both the region handle and the DCX_INTERSECTRGN flag. If the application does not combine the update region, only drawing operations that would otherwise extend outside the window are clipped. The application is not responsible for clearing the update region, regardless of whether it uses the region.

If an application processes the WM_NCACTIVATE message, after processing it must return TRUE to direct Windows to complete the change of active window. If the window is minimized when the application receives the WM_NCACTIVATE message, it should pass the message to DefWindowProc. In such cases, the default function redraws the label for the icon.


Child Windows

A child window is a window with the WS_CHILD or WS_CHILDWINDOW style. Like other window styles, child windows receive WM_PAINT messages to prompt updating. Each child window has an update region, which either Windows or the application can set to generate eventual WM_PAINT messages.

A child window's update and visible regions are affected by the child's parent window; this is not true for windows of other styles. Windows often sets the child window's update region when it sets the parent window's update region, causing the child window to receive WM_PAINT messages when the parent window receives them. Windows limits the location of the child window's visible region to within the client area of the parent window and clips any portion of the child window moved outside the parent window.

Windows sets the update region for a child window whenever part of the parent window's update region includes a portion of the child window. In such cases, Windows first sends a WM_PAINT message to the parent window and then sends a message to the child window, allowing the child to restore any portions of the window that the parent may have drawn over.

Windows does not set the parent's update region when the child's is set. An application cannot generate a WM_PAINT message for the parent window by invalidating the child window. Similarly, an application cannot generate a WM_PAINT message for the child by invalidating a portion of the parent's client area that lies entirely under the child window. In such cases, neither window receives a WM_PAINT message.

An application can prevent a child window's update region from being set when the parent window's is set by specifying the WS_CLIPCHILDREN style when creating the parent window. When this style is set, Windows excludes the child windows from the parent's visible region and therefore ignores any portion of the update region that may contain the child windows. When the application paints in the parent window, any drawing that would cover the child window is clipped, making a subsequent WM_PAINT message to the child window unnecessary.

The update and visible regions of a child window are also affected by the child window's siblings. Sibling windows are any windows that have a common parent window. If sibling windows overlap, then setting the update region for one affects the update region of another, causing WM_PAINT messages to be sent to both windows. Sibling windows receive WM_PAINT messages in the reverse order of their position in the Z order. Given this, the window highest in the Z order (on the top) receives its WM_PAINT message last, and vice versa.

Sibling windows are not automatically clipped. One sibling can draw over another overlapping sibling even if the window that is drawing has a lower position in the Z order. An application can prevent this by specifying the WS_CLIPSIBLINGS style when creating the windows. When this style is set, Windows excludes all portions of an overlapping sibling window from a window's visible region if the overlapping sibling window has a higher position in the Z order.

Note  The update and visible regions for windows that have the WS_POPUP or WS_POPUPWINDOW style are not affected by their parent windows.


About Display Device Contexts

A display DC is a device context, created by Windows, that an application uses to paint and draw a window. Windows prepares each display DC for output to a window, setting the drawing objects, colors, and modes for the window instead of for the display device. When the application supplies the display DC through calls to GDI functions, GDI uses the information in the context to generate output in the given window without intruding on other windows or other parts of the screen.

Windows provides five kinds of display DC: common, class, parent, private, and window. The common, class, and private DCs permit drawing in the client area of a given window. The parent and window DCs permit drawing anywhere in the window. Although the parent DC also permits drawing in the parent window, it is not intended to be used in this way.

Windows supplies a common, class, parent, or private DC to a window based on the type of display DC specified in that window's class style. Windows supplies a window DC only when the application explicitly requests one — for example, by calling the GetWindowDC or GetDCEx function. In all cases, an application can use the WindowFromDC function to determine which window a display DC currently represents.


Display Device Context Cache

Windows maintains a cache of display DCs that it uses for common, parent, and window DCs. Windows retrieves a DC from the cache whenever an application calls the GetDC or BeginPaint function; Windows returns the DC to the cache when the application subsequently calls the ReleaseDC or EndPaint function.

In Windows 3.x, the cache contains five display DCs, but only five DCs from the cache can be active at a time. To ensure that other applications have access to these DCs, an application must release a device context immediately after using it. Failure to do so eventually causes the application to fail.

There is no predetermined limit on the amount of DCs that a cache can hold; Windows creates a new display DC for the cache if none is available. Given this, a Win32-based application can have more than five active DCs from the cache at a time. However, the application must continue to release these DCs after use. Because new display DCs for the cache are allocated in the application's heap space, failing to release the DCs eventually consumes all available heap space. Windows indicates this failure by returning an error when it cannot allocate space for the new DC. Other functions unrelated to the cache may also return errors.

Portability  To minimize porting efforts, applications that use common DCs should be limited to no more than five and ensure that a common DC is released as soon as possible after it is used.


Display Device Context Defaults

Upon first creating a display DC, Windows assigns default values for the attributes (that is, drawing objects, colors, and modes) that comprise the DC. The following table shows the default values for the attributes of a display DC.

Attribute	Default value
Background color	Background color setting from Windows Control Panel (typically, white).
Background mode	OPAQUE.
Bitmap	None.
Brush	WHITE_BRUSH.
Brush origin	(0,0).
Clipping region	Entire window or client area with the update region clipped, as appropriate. Child and pop-up windows in the client area may also be clipped.
Palette	DEFAULT_PALETTE.
Current pen position	(0,0).
Device origin	Upper left corner of the window or the client area.
Drawing mode	R2_COPYPEN.
Font	SYSTEM_FONT (SYSTEM_FIXED_FONT for applications written to run with Windows versions 3.0 and earlier).
Intercharacter spacing	0.
Mapping mode	MM_TEXT.
Pen	BLACK_PEN.
Polygon-fill mode	ALTERNATE.
Stretch mode	BLACKONWHITE.
Text color	Text color setting from Control Panel (typically, black).
Viewport extent	(1,1).
Viewport origin	(0,0).
Window extent	(1,1).
Window origin	(0,0).
An application can modify the values of the display DC attributes by using selection and attribute functions, such as SelectObject, SetMapMode, and SetTextColor. For example, an application can modify the default units of measure in the coordinate system by using SetMapMode to change the mapping mode.

Changes to the attribute values of a common, parent, or window DC are not permanent. When an application releases these DCs, the current selections, such as mapping mode and clipping region, are lost as the context is returned to the cache. Changes to a class or private DC persist indefinitely. To restore them to their original defaults, an application must explicitly set each attribute.


Common Display Device Contexts

A common DC is used for drawing in the client area of the window. The Win32 API provides a common DC by default for any window whose window class does not explicitly specify a display DC style. Common DCs are typically used with windows that can be drawn without extensive changes to the DC attributes. Common DCs are convenient because they do not require additional memory or system resources, but they can be inconvenient if the application must set up many attributes before using them.

Windows retrieves all common DCs from the display DC cache. An application can retrieve a common DC immediately after the window is created. Because the common DC is from the cache, the application must always release the DC as soon as possible after drawing. After the common DC is released, it is no longer valid and the application must not attempt to draw with it. To draw again, the application must retrieve a new common DC, and continue to retrieve and release a common DC each time it draws in the window. If the application retrieves the DC handle by using the GetDC function, it must use the ReleaseDC function to release the handle. Similarly, for each BeginPaint function, the application must use a corresponding EndPaint function.

When the application retrieves the DC, Windows adjusts the origin so that it aligns with the upper left corner of the client area. It also sets the clipping region so that output to the DC is clipped to the client area. Any output that would otherwise appear outside the client area is clipped. If the application retrieves the common DC by using BeginPaint, Windows also includes the update region in the clipping region to further restrict the output.

When an application releases a common DC, Windows restores the default values for the attributes of the DC. An application that modifies attribute values must do so each time it retrieves a common DC. Releasing the DC releases any drawing objects the application may have selected into it, so the application need not release these objects before releasing the DC. In all cases, an application must never assume that the common DC retains nondefault selections after being released.


Private Display Device Contexts

A private DC enables an application to avoid retrieving and initializing a display DC each time the application must draw in a window. Private DCs are useful for windows that require many changes to the values of the attributes of the DC to prepare it for drawing. Private DCs reduce the time required to prepare the DC and therefore the time needed to carry out drawing in the window.

An application directs Windows to create a private DC for a window by specifying the CS_OWNDC style in the window class. Windows creates a unique private DC each time it creates a new window belonging to the class. Initially, the private DC has the same default values for attributes as a common DC, but the application can modify these at any time. Windows preserves changes to the DC for the life of the window or until the application makes additional changes.

An application can retrieve the handle of the private DC by using the GetDC function any time after the window is created. The application must retrieve the handle only once. Thereafter, it can keep and use the handle any number of times. Because a private DC is not part of the display DC cache, an application need never release the DC by using the ReleaseDC function.

Windows automatically adjusts the DC to reflect changes to the window, such as moving or sizing. This ensures that any overlapping windows are always properly clipped; that is, no action is required by the application to ensure clipping. However, Windows does not revise the DC to include the update region. Therefore, when processing a WM_PAINT message, the application must incorporate the update region either by calling BeginPaint or by retrieving the update region and intersecting it with the current clipping region. If the application does not call BeginPaint, it must explicitly validate the update region by using the ValidateRect or ValidateRgn function. If the application does not validate the update region, the window receives an endless series of WM_PAINT messages.

Because BeginPaint hides the caret if a window is showing it, an application that calls BeginPaint should also call the EndPaint function to restore the caret. EndPaint has no other effect on a private DC.

Although a private DC is convenient to use, it is expensive in terms of system resources, requiring 800 or more bytes to store. Private DCs are recommended when performance considerations outweigh storage costs.

Windows includes the private DC when sending the WM_ERASEBKGND message to the application. The current selections of the private DC, including mapping mode, are in effect when the application or Windows processes these messages. To avoid undesirable effects, Windows uses logical coordinates when erasing the background; for example, it uses the GetClipBox function to retrieve the logical coordinates of the area to erase and passes these coordinates to the FillRect function. Applications that process these messages can use similar techniques. Windows supplies a window DC with the WM_ICONERASEBKGND message regardless of whether the corresponding window has a private DC.

An application can use the GetDCEx function to force Windows to return a common DC for the window that has a private DC. This is useful for carrying out quick touch-ups to a window without changing the current values of the attributes of the private DC.


Class Display Device Contexts

By using a class DC, an application can use a single display DC for every window belonging to a given class. Class DCs are often used with control windows that are drawn using the same attribute values. Like private DCs, class DCs minimize the time required to prepare a DC for drawing.

Windows supplies a class DC for a window if it belongs to a window class having the CS_CLASSDC style. Windows creates the DC when creating the first window belonging to the class and then uses the same DC for all subsequently created windows in the class. Initially, the class DC has the same default values for attributes as a common DC, but the application can modify these at any time. Windows preserves all changes, except for the clipping region and device origin, until the last window in the class has been destroyed. A change made for one window applies to all windows in that class.

An application can retrieve the handle for the class DC by using the GetDC function any time after the first window has been created. The application can keep and use the handle without releasing it because the class DC is not part of the display DC cache. If the application creates another window in the same window class, the application must retrieve the class DC again. Retrieving the DC sets the correct device origin and clipping region for the new window. After the application retrieves the class DC for a new window in the class, the DC can no longer be used to draw in the original window without again retrieving it for that window. In general, each time it must draw in a window, an application must explicitly retrieve the class DC for the window.

Applications that use class DCs should always call BeginPaint when processing a WM_PAINT message. The function sets the correct device origin and clipping region for the window, and incorporates the update region. The application should also call EndPaint to restore the caret if BeginPaint hid it. EndPaint has no other effect on a class DC.

Windows passes the class DC when sending the WM_ERASEBKGND message to the application, permitting the current attribute values to affect any drawing carried out by the application or Windows when processing this message. Windows supplies a window DC with the WM_ICONERASEBKGND message regardless of whether the corresponding window has a class DC. As it could with a window having a private DC, an application can use GetDCEx to force Windows to return a common DC for the window that has a class DC.

Using class DCs is not recommended.


Window Display Device Contexts

A window DC enables an application to draw anywhere in a window, including the nonclient area. Window DCs are typically used by applications that process the WM_NCPAINT and WM_NCACTIVATE messages for windows with custom nonclient areas. Using a window DC is not recommended for any other purpose.

An application can retrieve a window DC by using the GetWindowDC or GetDCEx function with the DCX_WINDOW option specified. The function retrieves a window DC from the display DC cache. A window that uses a window DC must release it after drawing by using the ReleaseDC function as soon as possible. Window DCs are always from the cache; the CS_OWNDC and CS_CLASSDC class styles do not affect the DC.

When an application retrieves a window DC, Windows sets the device origin to the upper left corner of the window instead of the upper left corner of the client area. It also sets the clipping region to include the entire window, not just the client area. Windows sets the current attribute values of a window DC to the same default values as a common DC. An application can change the attribute values, but Windows does not preserve any changes when the DC is released.


Parent Display Device Contexts

A parent DC enables an application to minimize the time necessary to set up the clipping region for a window. An application typically uses parent DCs to speed up drawing for control windows without requiring a private or class DC. For example, Windows uses parent DCs for push button and edit controls. Parent DCs are intended for use with child windows only, never with top-level or pop-up windows.

Windows supplies a parent DC for any window belonging to a window class specifying the CS_PARENTDC style. An application can retrieve the parent DC by using GetDC immediately after the window is created. Windows always retrieves the parent DC from the display DC cache even if the parent uses a private or class DC, so the application must release the DC by using ReleaseDC as soon as possible after drawing. When processing a WM_PAINT message, the application must retrieve the parent DC by using BeginPaint and release it by using EndPaint.

When a parent DC is retrieved, Windows searches the cache for the display DC previously used by the parent window. In most cases, the parent window retrieves and releases a display DC before the child window attempts to retrieve one, so the parent DC is usually in the cache. If Windows finds the display DC, Windows uses it and its corresponding clipping region, which was previously calculated for the parent DC. The time saved is in skipping the calculation required to define the clipping region. If Windows does not find the parent DC, it retrieves a common DC for the window and calculates the clipping region for the window rather than for the parent window.

Windows sets the device origin for the parent DC to the upper left corner of the child window. Attribute values set by the parent window are not preserved for the child window; for example, the parent window cannot set the brush for its child windows. The only property preserved is the clipping region. The window must clip its own output to the limits of the window. Because the clipping region for the parent DC is identical to the parent window, the child window can potentially draw over the entire parent window, but the parent DC must not be used in this way.

Windows ignores the CS_PARENTDC style if the parent window uses a private or class DC, if the parent window clips its child windows, or if the child window clips its child windows or sibling windows. In these cases, Windows always retrieves a common DC for the window.


Window Update Lock

A window update lock is a temporary suspension of drawing in a window. Windows uses the lock to prevent other windows from drawing over the tracking rectangle whenever the user moves or sizes a window. Applications can use the lock to prevent drawing if they carry out similar moving or sizing operations with their own windows.

An application uses the LockWindowUpdate function to set or clear a window update lock, specifying the window to lock. The lock applies to the given window and all of its child windows. When the lock is set, the GetDC and BeginPaint functions return a display DC with a visible region that is empty. Given this, the application can continue to draw in the window, but all output is clipped. The lock persists until the application clears it by calling LockWindowUpdate, specifying NULL for the window. Although LockWindowUpdate forces a window's visible region to be empty, the function does not make the given window invisible and does not clear the WS_VISIBLE style bit.

After the lock is set, the application can use the GetDCEx function, with the DCX_LOCKWINDOWUPDATE value, to retrieve a display DC to draw over the locked window. This allows the application to draw a tracking rectangle when processing keyboard or mouse messages. Windows uses this method when the user moves and sizes windows. GetDCEx retrieves the display DC from the display DC cache, so the application must release the DC as soon as possible after drawing.

While a window update lock is set, the system creates an accumulated bounding rectangle for each locked window. When the lock is cleared, Windows uses this bounding rectangle to set the update region for the window and its child windows, forcing an eventual WM_PAINT message. If the accumulated bounding rectangle is empty (that is, if no drawing has occurred while the lock was set), the update region is not set.


Accumulated Bounding Rectangle

The accumulated bounding rectangle is the smallest rectangle enclosing the portion of a window or client area affected by recent drawing operations. An application can use this rectangle to conveniently determine the extent of changes caused by drawing operations. It is sometimes used in conjunction with LockWindowUpdate to determine which portion of the client area must be redrawn after the update lock is cleared.

An application uses the SetBoundsRect function (specifying DCB_ENABLE) to begin accumulating the bounding rectangle. Windows subsequently accumulates points for the bounding rectangle as the application uses the specified display DC. The application can retrieve the current bounding rectangle at any time by using the GetBoundsRect function. The application stops the accumulation by calling SetBoundsRect again, specifying the DCB_DISABLE value.


Using the WM_PAINT Message

You can use the WM_PAINT message to carry out the drawing necessary for displaying information. Because Windows sends WM_PAINT messages to your application when your window must be updated or when you explicitly request an update, you can consolidate the code for drawing in your application's window procedure. You can then use this code whenever your application must draw either new or existing information.

The following sections show a variety of ways to use the WM_PAINT message to draw in a window.

•	Drawing in the client area

•	Redrawing the entire client area

•	Redrawing in the update region

•	Invalidating the client area

•	Drawing a minimized window

•	Drawing a custom window background


Drawing in the Client Area

You use the BeginPaint and EndPaint functions to prepare for and complete the drawing in the client area. BeginPaint returns a handle of the display DC used for drawing in the client area; EndPaint ends the paint request and releases the DC.

In the following example, the window procedure writes the message "Hello, Windows!" in the client area. To make sure the string is visible when the window is first created, the WinMain function calls UpdateWindow immediately after creating and showing the window. This causes a WM_PAINT message to be sent immediately to the window procedure.

LRESULT APIENTRY WndProc(hwnd, message, wParam, lParam)

HWND hwnd;

UINT message;

WPARAM wParam;

LPARAM lParam;

{

    PAINTSTRUCT ps;

    HDC hdc;

    switch (message) {

        case WM_PAINT:

            hdc = BeginPaint(hwnd, &ps);

            TextOut(hdc, 0, 0, "Hello, Windows!", 15);

            EndPaint(hwnd, &ps);

            return 0L;

        .

        .

        .

    }

}

int APIENTRY WinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow)

HINSTANCE hInstance;         /* handle of current instance   */

HINSTANCE hPrevInstance;     /* handle of previous instance  */

LPSTR lpCmdLine;             /* address of command line      */

int nCmdShow;                /* show-window type (open/icon) */

{

    HWND hwnd;

    hwnd = CreateWindowEx( /* parameters */ );

    ShowWindow(hwnd, SW_SHOW);

    UpdateWindow(hwnd);

    .

    .

    .

    return msg.wParam;

}


Redrawing the Entire Client Area

You can have your application redraw the entire contents of the client area whenever the window changes size by setting the CS_HREDRAW and CS_VREDRAW styles for the window class. Applications that adjust the size of the drawing based on the size of the window use these styles to ensure that they start with a completely empty client area when drawing.

In the following example, the window procedure draws a five-pointed star that fits neatly in the client area. It uses a common DC and must set the mapping mode as well as window and viewport extents each time the WM_PAINT message is processed.

LRESULT APIENTRY WndProc(hwnd, message, wParam, lParam)

HWND hwnd;

UINT message;

WPARAM wParam;

LPARAM lParam;

{

    PAINTSTRUCT ps;

    HDC hdc;

    RECT rc;

    POINT aptStar[6] = {50,2, 2,98, 98,33, 2,33, 98,98, 50,2};

    .

    .

    .

        case WM_PAINT:

            hdc = BeginPaint(hwnd, &ps);

            GetClientRect(hwnd, &rc);

            SetMapMode(hdc, MM_ANISOTROPIC);

            SetWindowExtEx(hdc, 100, 100, NULL);

            SetViewportExtEx(hdc, rc.right, rc.bottom, NULL);

            Polyline(hdc, aptStar, 6);

            EndPaint(hwnd, &ps);

            return 0L;

        .

        .

        .

}

int APIENTRY WinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow)

HINSTANCE hInstance;         /* handle of current instance   */

HINSTANCE hPrevInstance;     /* handle of previous instance  */

LPSTR lpCmdLine;             /* address of command line      */

int nCmdShow;                /* show-window type (open/icon) */

{

    WNDCLASS wc;

    .

    .

    .

        wc.style = CS_HREDRAW | CS_VREDRAW;

        wc.lpfnWndProc = (WNDPROC) WndProc;

    .

    .

    .

        RegisterClass(&wc);

    .

    .

    .

    return msg.wParam;

}


Redrawing in the Update Region

You can limit the amount of drawing your application carries out when processing the WM_PAINT message by determining the size and location of the update region. Because Windows uses the update region when creating the clipping region for the window's display DC, you can indirectly determine the update region by examining the clipping region.

In the following example, the window procedure draws a triangle, a rectangle, a pentagon, and a hexagon, but only if all or a portion of each figure lies within the update region. The window procedure uses the RectVisible function and a 100-by-100 rectangle to determine whether a figure is within the clipping region (and therefore the update region) for the common DC retrieved by BeginPaint.

POINT aptTriangle[4]  = {50,2, 98,86,  2,86, 50,2},

      aptRectangle[5] = { 2,2, 98,2,  98,98,  2,98, 2,2},

      aptPentagon[6]  = {50,2, 98,35, 79,90, 21,90, 2,35, 50,2},

      aptHexagon[7]   = {50,2, 93,25, 93,75, 50,98, 7,75, 7,25, 50,2};

  .

  .

  .

        case WM_PAINT:

            hdc = BeginPaint(hwnd, &ps);

            SetRect(&rc, 0, 0, 100, 100);

            if (RectVisible(hdc, &rc))

                Polyline(hdc, aptTriangle, 4);

            SetViewportOrgEx(hdc, 100, 0, NULL);

            if (RectVisible(hdc, &rc))

                Polyline(hdc, aptRectangle, 5);

            SetViewportOrgEx(hdc, 0, 100, NULL);

            if (RectVisible(hdc, &rc))

                Polyline(hdc, aptPentagon, 6);

            SetViewportOrgEx(hdc, 100, 100, NULL);

            if (RectVisible(hdc, &rc))

                Polyline(hdc, aptHexagon, 7);

            EndPaint(hwnd, &ps);

            return 0L;

  .

  .

  .

The coordinates of each figure in this example lie within the same 100-by-100 rectangle. Before drawing a figure, the window procedure sets the viewport origin to a different part of the client area by using the SetViewportOrgEx function. This prevents figures from being drawn one on top of the other. Changing the viewport origin does not affect the clipping region, but does affect how the coordinates of the rectangle passed to RectVisible are interpreted. Changing the origin also allows you to use a single rectangle to check the update region rather than individual rectangles for each figure.


Invalidating the Client Area

Windows is not the only source of WM_PAINT messages. The InvalidateRect or InvalidateRgn function can indirectly generate WM_PAINT messages for your windows. These functions mark all or part of a client area as invalid (that must be redrawn).

In the following example, the window procedure invalidates the entire client area when processing WM_CHAR messages. This allows the user to change the figure by typing a number and view the results; these results are drawn as soon as there are no other messages in the application's message queue.

POINT aptPentagon[6] = {50,2, 98,35, 79,90, 21,90, 2,35, 50,2},

      aptHexagon[7]  = {50,2, 93,25, 93,75, 50,98, 7,75, 7,25, 50,2};

POINT *ppt = aptPentagon;

int cpt = 6;

  .

  .

  .

case WM_CHAR:

    switch (wParam) {

    case '5':

        ppt = aptPentagon;

        cpt = 6;

        break;

    case '6':

        ppt = aptHexagon;

        cpt = 7;

        break;

    }

    InvalidateRect(hwnd, NULL, TRUE);

    return 0L;

case WM_PAINT:

    hdc = BeginPaint(hwnd, &ps);

    GetClientRect(hwnd, &rc);

    SetMapMode(hdc, MM_ANISOTROPIC);

    SetWindowExtEx(hdc, 100, 100, NULL);

    SetViewportExtEx(hdc, rc.right, rc.bottom, NULL);

    Polyline(hdc, ppt, cpt);

    EndPaint(hwnd, &ps);

    return 0L;

In this example, the NULL argument used by InvalidateRect specifies the entire client area; the TRUE argument causes the background to be erased. If you do not want the application to wait until the application's message queue has no other messages, use the UpdateWindow function to force the WM_PAINT message to be sent immediately. If there is any invalid part of the client area, UpdateWindow sends the WM_PAINT message for the given window directly to the window procedure.


Drawing a Minimized Window

You can draw your own minimized windows rather than having Windows draw them for you. Most applications define a class icon when registering the window class for the window, and Windows draws the icon when the window is minimized. If you set the class icon to NULL, however, Windows sends a WM_PAINT message to your window procedure whenever the window is minimized, enabling the window procedure to draw in the minimized window.

In the following example, the window procedure draws a star in the minimized window. The procedure uses the IsIconic function to determine when the window is minimized. This ensures that the star is drawn only when the window is minimized.

POINT aptStar[6] = {50,2, 2,98, 98,33, 2,33, 98,98, 50,2};

  .

  .

  .

case WM_PAINT:

    hdc = BeginPaint(hwnd, &ps);

    /* Determine whether the window is minimized. */

    if (IsIconic(hwnd)) {

        GetClientRect(hwnd, &rc);

        SetMapMode(hdc, MM_ANISOTROPIC);

        SetWindowExtEx(hdc, 100, 100, NULL);

        SetViewportExtEx(hdc, rc.right, rc.bottom, NULL);

        Polyline(hdc, aptStar, 6);

    } else {

        TextOut(hdc, 0,0, "Hello, Windows!", 15);

    }

    EndPaint(hwnd, &ps);

    return 0L;

You set the class icon to NULL by setting the hIcon member of the WNDCLASS structure to NULL before calling the RegisterClass function for the window class.


Drawing a Custom Window Background

You can draw your own window background rather than having Windows draw it for you. Most applications specify a brush handle or system color value for the class background brush when registering the window class; Windows uses the brush or color to draw the background. If you set the class background brush to NULL, however, Windows sends a WM_ERASEBKGND message to your window procedure whenever the window background must be drawn, letting you draw a custom background.

In the following example, the window procedure draws a large checkerboard pattern that fits neatly in the window. The procedure fills the client area with a white brush and then draws thirteen 20-by-20 rectangles using a gray brush. The display DC to use when drawing the background is specified in the wParam parameter for the message.

HBRUSH hbrWhite, hbrGray;

  .

  .

  .

case WM_CREATE:

    hbrWhite = GetStockObject(WHITE_BRUSH);

    hbrGray  = GetStockObject(GRAY_BRUSH);

    return 0L;

case WM_ERASEBKGND:

    hdc = (HDC) wParam;

    GetClientRect(hwnd, &rc);

    SetMapMode(hdc, MM_ANISOTROPIC);

    SetWindowExtEx(hdc, 100, 100, NULL);

    SetViewportExtEx(hdc, rc.right, rc.bottom, NULL);

    FillRect(hdc, &rc, hbrWhite);

    for (i = 0; i < 13; i++) {

        x = (i * 40) % 100;

        y = ((i * 40) / 100) * 20;

        SetRect(&rc, x, y, x + 20, y + 20);

        FillRect(hdc, &rc, hbrGray);

    }

  return 1L;

If the application draws its own minimized window, Windows also sends the WM_ERASEBKGND message to the window procedure to draw the background for the minimized window. You can use the same technique used by WM_PAINT to determine whether the window is minimized — that is, call the IsIconic function and check for the return value TRUE.


Using the GetDC Function

You use the GetDC function to carry out drawing that must occur instantly rather than when a WM_PAINT message is processing. Such drawing is usually in response to an action by the user, such as making a selection or drawing with the mouse. In such cases, the user should receive instant feedback and must not be forced to stop selecting or drawing in order for the application to display the result. The following sections show how to use GetDC to draw in a window.


Drawing with the Mouse

You can permit the user to draw lines with the mouse by having your window procedure draw while processing the WM_MOUSEMOVE message. Windows sends the WM_MOUSEMOVE message to the window procedure whenever the user moves the cursor within the window. To draw lines, the window procedure can retrieve a display DC and draw a line in the window between the current and previous cursor positions.

In the following example, the window procedure prepares for drawing when the user presses and holds the left mouse button (sending the WM_LBUTTONDOWN message). As the user moves the cursor within the window, the window procedure receives a series of WM_MOUSEMOVE messages. For each message, the window procedure draws a line connecting the previous position and the current position. To draw the line, the procedure uses GetDC to retrieve a display DC; then, as soon as drawing is complete and before returning from the message, the procedure uses the ReleaseDC function to release the display DC. As soon as the user releases the mouse button, the window procedure clears the flag, and the drawing stops (which sends the WM_LBUTTONUP message).

BOOL fDraw = FALSE;

POINT ptPrevious;

  .

  .

  .

case WM_LBUTTONDOWN:

    fDraw = TRUE;

    ptPrevious.x = LOWORD(lParam);

    ptPrevious.y = HIWORD(lParam);

    return 0L;

case WM_LBUTTONUP:

    if (fDraw) {

        hdc = GetDC(hwnd);

        MoveToEx(hdc, ptPrevious.x, ptPrevious.y, NULL);

        LineTo(hdc, LOWORD(lParam), HIWORD(lParam));

        ReleaseDC(hwnd, hdc);

    }

    fDraw = FALSE;

    return 0L;

case WM_MOUSEMOVE:

    if (fDraw) {

        hdc = GetDC(hwnd);

        MoveToEx(hdc, ptPrevious.x, ptPrevious.y, NULL);

        LineTo(hdc, ptPrevious.x = LOWORD(lParam),

          ptPrevious.y = HIWORD(lParam));

        ReleaseDC(hwnd, hdc);

    }

  return 0L;

An application that enables drawing, as in this example, typically records either the points or lines so that the lines can be redrawn whenever the window is updated. Drawing applications often use a memory DC and an associated bitmap to store lines that were drawn by using a mouse.


Drawing at Timed Intervals

You can draw at timed intervals by creating a timer with the SetTimer function. By using a timer to send WM_TIMER messages to the window procedure at regular intervals, an application can carry out simple animation in the client area while other applications continue running.

In the following example, the application bounces a star from side to side in the client area. Each time the window procedure receives a WM_TIMER message, the procedure erases the star at the current position, calculates a new position, and draws the star within the new position. The procedure starts the timer by calling SetTimer while processing the WM_CREATE message.

RECT rcCurrent = {0,0,20,20};

POINT aptStar[6] = {10,1, 1,19, 19,6, 1,6, 19,19, 10,1};

int X = 2, Y = -1, idTimer = -1;

BOOL fVisible = FALSE;

HDC hdc;

LRESULT APIENTRY WndProc(hwnd, message, wParam, lParam)

HWND hwnd;

UINT message;

WPARAM wParam;

LPARAM lParam;

{

    PAINTSTRUCT ps;

    RECT rc;

    switch (message) {

        case WM_CREATE:

            /* Calculate the starting point. */

            GetClientRect(hwnd, &rc);

            OffsetRect(&rcCurrent, rc.right / 2, rc.bottom / 2);

            /* Initialize the private DC. */

            hdc = GetDC(hwnd);

            SetViewportOrgEx(hdc, rcCurrent.left,

                rcCurrent.top, NULL);

            SetROP2(hdc, R2_NOT);

            /* Start the timer. */

            SetTimer(hwnd, idTimer = 1, 10, NULL);

            return 0L;

        case WM_DESTROY:

            KillTimer(hwnd, 1);

            PostQuitMessage(0);

            return 0L;

        case WM_SIZE:

            switch (wParam) {

                case SIZE_MINIMIZED:

                    /* Stop the timer if the window is minimized. */

                    KillTimer(hwnd, 1);

                    idTimer = -1;

                    break;

                case SIZE_RESTORED:

                    /*

                     * Move the star back into the client area

                     * if necessary.

                     */

                    if (rcCurrent.right > (int) LOWORD(lParam))

                        rcCurrent.left =

                            (rcCurrent.right =

                                (int) LOWORD(lParam)) - 20;

                    if (rcCurrent.bottom > (int) HIWORD(lParam))

                        rcCurrent.top =

                            (rcCurrent.bottom =

                                (int) HIWORD(lParam)) - 20;

                    /* Fall through to the next case. */

                case SIZE_MAXIMIZED:

                    /* Start the timer if it had been stopped. */

                    if (idTimer == -1)

                        SetTimer(hwnd, idTimer = 1, 10, NULL);

                    break;

            }

            return 0L;

        case WM_TIMER:

            /* Hide the star if it is visible. */

            if (fVisible)

                Polyline(hdc, aptStar, 6);

            /* Bounce the star off a side if necessary. */

            GetClientRect(hwnd, &rc);

            if (rcCurrent.left + X < rc.left ||

                rcCurrent.right + X > rc.right)

                X = -X;

            if (rcCurrent.top + Y < rc.top ||

                rcCurrent.bottom + Y > rc.bottom)

                Y = -Y;

            /* Show the star in its new position. */

            OffsetRect(&rcCurrent, X, Y);

            SetViewportOrgEx(hdc, rcCurrent.left,

                rcCurrent.top, NULL);

            fVisible = Polyline(hdc, aptStar, 6);

            return 0L;

        case WM_ERASEBKGND:

            /* Erase the star. */

            fVisible = FALSE;

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

        case WM_PAINT:

            /*

             * Show the star if it is not visible. Use BeginPaint

             * to clear the update region.

             */

            BeginPaint(hwnd, &ps);

            if (!fVisible)

                fVisible = Polyline(hdc, aptStar, 6);

            EndPaint(hwnd, &ps);

            return 0L;

    }

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

}

This application uses a private DC to minimize the time required to prepare the DC for drawing. The window procedure retrieves and initializes the private DC when processing the WM_CREATE message, setting the binary raster operation mode to allow the star to be erased and drawn using the same call to the Polyline function. The window procedure also sets the viewport origin to allow the star to be drawn using the same set of points regardless of the star's position in the client area.

The application uses the WM_PAINT message to draw the star whenever the window must be updated. The window procedure draws the star only if it is not visible; that is, only if it has been erased by the WM_ERASEBKGND message. The window procedure intercepts the WM_ERASEBKGND message to set the fVisible variable, but passes the message to DefWindowProc so that Windows can draw the window background.

The application uses the WM_SIZE message to stop the timer when the window is minimized and to restart the timer when the minimized window is restored. The window procedure also uses the message to update the current position of the star if the size of the window has been reduced so that the star is no longer in the client area. The application keeps track of the star's current position by using the structure specified by rcCurrent, which defines the bounding rectangle for the star. Keeping all corners of the rectangle in the client area keeps the star in the area. The window procedure initially centers the star in the client area when processing the WM_CREATE message.


Painting and Drawing Reference

The following functions and messages are associated with painting and drawing.


Painting and Drawing Functions

Following are the functions used with painting and drawing.

BeginPaint
DrawAnimatedRects
DrawCaption
DrawEdge
DrawFocusRect
DrawFrameControl
DrawState
DrawStateProc
DrawTextEx
EndPaint
ExcludeUpdateRgn
GdiFlush
GdiGetBatchLimit
GdiSetBatchLimit
GetBkColor
GetBkMode
GetBoundsRect
GetROP2
GetUpdateRect
GetUpdateRgn
GetWindowDC
GrayString
InvalidateRect
InvalidateRgn
LockWindowUpdate
OutputProc
PaintDesktop
RedrawWindow
ResetDisplay
SetBkColor
SetBkMode
SetBoundsRect
SetRectRgn
SetROP2
UpdateWindow
ValidateRect
ValidateRgn
WindowFromDC


Painting and Drawing Messages

Following are the messages used with painting and drawing.

WM_DISPLAYCHANGE
WM_ERASEBKGND
WM_ICONERASEBKGND
WM_NCPAINT
WM_PAINT
WM_PAINTICON
WM_PRINT
WM_PRINTCLIENT
WM_SETREDRAW


Rectangles

Applications written for Microsoft® Windows® use rectangles to specify rectangular areas on the screen or in a window.


About Rectangles

In Windows applications, rectangles are used for the cursor clipping region, the invalid portion of the client area, an area for displaying formatted text, or the scroll area. Your applications can also use rectangles to fill, frame, or invert a portion of the client area with a given brush, and to retrieve the coordinates of a window or a window's client area.


Rectangle Coordinates

An application must use a RECT structure to define a rectangle. The structure specifies the coordinates of two points: the upper left and lower right corners of the rectangle. The sides of the rectangle extend from these two points and are parallel to the x- and y-axes.

The coordinate values for a rectangle are expressed as signed integers. The coordinate value of a rectangle's right side must be greater than that of its left side. Likewise, the coordinate value of the bottom must be greater than that of the top.

Because applications can use rectangles for many different purposes, the Windows rectangle functions do not use an explicit unit of measure. Instead, all rectangle coordinates and dimensions are given in signed, logical values. The mapping mode and the function in which the rectangle is used determine the units of measure. For more information about coordinates and mapping modes, see Coordinate Spaces and Transformations.


Rectangle Operations

The Microsoft® Win32® application programming interface (API) provides several functions for working with rectangles.

The SetRect function creates a rectangle, the CopyRect function makes a copy of a given rectangle, and the SetRectEmpty function creates an empty rectangle. An empty rectangle is any rectangle that has zero width, zero height, or both. The IsRectEmpty function determines whether a given rectangle is empty. The EqualRect function determines whether two rectangles are identical — that is, whether they have the same coordinates.

The InflateRect function increases or decreases the width or height of a rectangle, or both. It can add or remove width from both ends of the rectangle; it can add or remove height from both the top and bottom of the rectangle.

The OffsetRect function moves a rectangle by a given amount. It moves the rectangle by adding the given x-amount, y-amount, or x- and y-amounts to the corner coordinates.

The PtInRect function determines whether a given point lies within a given rectangle. The point is in the rectangle if it lies on the left or top side or is completely within the rectangle. The point is not in the rectangle if it lies on the right or bottom side.

The IntersectRect function creates a new rectangle that is the intersection of two existing rectangles, as shown in the following figure.

The UnionRect function creates a new rectangle that is the union of two existing rectangles, as shown in the following figure.

For information about functions that draw ellipses and polygons, see Filled Shapes.


Using Rectangles

The example in this section illustrates how to use the rectangle functions. It consists of the main window procedure from an application that enables the user to move and size a bitmap.

When the application starts, it draws a 32-pixel by 32-pixel bitmap in the upper left corner of the screen. The user can move the bitmap by dragging it. To size the bitmap, the user creates a target rectangle by dragging the mouse, then drags the bitmap and "drops" it on the target rectangle. The application responds by copying the bitmap into the target rectangle.

The window procedure that allows the user to move and size the bitmap is given in the following example.

LRESULT CALLBACK MainWndProc(hwnd, uMsg, wParam, lParam)

HWND hwnd;      /* handle of window         */

UINT uMsg;      /* message                  */

WPARAM wParam;  /* first message parameter  */

LPARAM lParam;  /* second message parameter */

{

    HDC hdc;                 /* device context (DC) for window   */

    RECT rcTmp;              /* temporary rectangle              */

    PAINTSTRUCT ps;          /* paint data for Begin/EndPaint    */

    POINT ptClientUL;        /* client area upper left corner    */

    POINT ptClientLR;        /* client area lower right corner   */

    static HDC hdcCompat;    /* DC for copying bitmap            */

    static POINT pt;         /* x and y coordinates of cursor    */

    static RECT rcBmp;       /* rectangle that encloses bitmap   */

    static RECT rcTarget;    /* rectangle to receive bitmap      */

    static RECT rcClient;    /* client-area rectangle            */

    static BOOL fDragRect;   /* TRUE if bitmap rect. is dragged  */

    static HBITMAP hbmp;     /* handle of bitmap to display      */

    static HBRUSH hbrBkgnd;  /* handle of background-color brush */

    static COLORREF crBkgnd; /* color of client-area background  */

    static HPEN hpenDot;     /* handle of dotted pen             */

    switch (uMsg) {

        case WM_CREATE:

            /* Load the bitmap resource. */

            hbmp = LoadBitmap(hinst, MAKEINTRESOURCE(1));

            /*

             * Create a device context (DC) to hold the bitmap.

             * The bitmap is copied from this DC to the window's DC

             * whenever it must be drawn.

             */

            hdc = GetDC(hwnd);

            hdcCompat = CreateCompatibleDC(hdc);

            SelectObject(hdcCompat, hbmp);

            /*

             * Create a brush of the same color as the background

             * of the client area. The brush is used later to erase

             * the old bitmap before copying the bitmap into the

             * target rectangle.

             */

            crBkgnd = GetBkColor(hdc);

            hbrBkgnd = CreateSolidBrush(crBkgnd);

            ReleaseDC(hwnd, hdc);

            /*

             * Create a dotted pen. The pen is used to draw the

             * bitmap rectangle as the user drags it.

             */

            hpenDot = CreatePen(PS_DOT, 1, RGB(0, 0, 0));

            /*

             * Set the initial rectangle for the bitmap. Note that

             * this application supports only a 32- by 32-pixel

             * bitmap. The rectangle is slightly larger than the

             * bitmap.

             */

            SetRect(&rcBmp, 1, 1, 34, 34);

            return 0;

        case WM_PAINT:

            /*

             * Draw the bitmap rectangle and copy the bitmap into

             * it. The 32-pixel by 32-pixel bitmap is centered

             * in the rectangle by adding 1 to the left and top

             * coordinates of the bitmap rectangle, and subtracting

             * 2 from the right and bottom coordinates.

             */

            BeginPaint(hwnd, &ps);

            Rectangle(ps.hdc, rcBmp.left, rcBmp.top,

                rcBmp.right, rcBmp.bottom);

            StretchBlt(ps.hdc, rcBmp.left + 1, rcBmp.top + 1,

                (rcBmp.right - rcBmp.left) - 2,

                (rcBmp.bottom - rcBmp.top) - 2, hdcCompat,

                0, 0, 32, 32, SRCCOPY);

            EndPaint(hwnd, &ps);

            break;

        case WM_MOVE:

        case WM_SIZE:

            /*

             * Convert the client coordinates of the client-area

             * rectangle to screen coordinates and save them in a

             * rectangle. The rectangle is passed to the ClipCursor

             * function during WM_LBUTTONDOWN processing.

             */

            GetClientRect(hwnd, &rcClient);

            ptClientUL.x = rcClient.left;

            ptClientUL.y = rcClient.top;

            ptClientLR.x = rcClient.right;

            ptClientLR.y = rcClient.bottom;

            ClientToScreen(hwnd, &ptClientUL);

            ClientToScreen(hwnd, &ptClientLR);

            SetRect(&rcClient, ptClientUL.x, ptClientUL.y,

                ptClientLR.x, ptClientLR.y);

            return 0;

        case WM_LBUTTONDOWN:

            /*

             * Restrict the mouse cursor to the client area. This

             * ensures that the window receives a matching

             * WM_LBUTTONUP message.

             */

            ClipCursor(&rcClient);

            /* Save the coordinates of the mouse cursor. */

            pt.x = (LONG) LOWORD(lParam);

            pt.y = (LONG) HIWORD(lParam);

            /*

             * If the user has clicked the bitmap rectangle, redraw

             * it using the dotted pen. Set the fDragRect flag to

             * indicate that the user is about to drag the

             * rectangle.

             */

            if (PtInRect(&rcBmp, pt)) {

                hdc = GetDC(hwnd);

                SelectObject(hdc, hpenDot);

                Rectangle(hdc, rcBmp.left, rcBmp.top, rcBmp.right,

                    rcBmp.bottom);

                fDragRect = TRUE;

                ReleaseDC(hwnd, hdc);

            }

            return 0;

        case WM_MOUSEMOVE:

            /*

             * Draw a target rectangle or drag the bitmap

             * rectangle, depending on the status of the fDragRect

             * flag.

             */

            if ((wParam && MK_LBUTTON)

                    && !fDragRect) {  /* draw a target rectangle */

                /*

                 * Set the mix mode so that the pen color is the

                 * inverse of the background color. The previous

                 * rectangle can then be erased by drawing

                 * another rectangle on top of it.

                 */

                hdc = GetDC(hwnd);

                SetROP2(hdc, R2_NOTXORPEN);

                /*

                 * If a previous target rectangle exists, erase

                 * it by drawing another rectangle on top of it.

                 */

                if (!IsRectEmpty(&rcTarget))

                    Rectangle(hdc, rcTarget.left, rcTarget.top,

                        rcTarget.right, rcTarget.bottom);

                /*

                 * Save the coordinates of the target rectangle.

                 * Avoid invalid rectangles by ensuring that the

                 * value of the left coordinate is greater than

                 * that of the right coordinate, and that the

                 * value of the bottom coordinate is greater than

                 * that of the top.

                 */

                if ((pt.x < (LONG) LOWORD(lParam)) &&

                        (pt.y > (LONG) HIWORD(lParam)))

                    SetRect(&rcTarget, pt.x, HIWORD(lParam),

                        LOWORD(lParam), pt.y);

                else if ((pt.x > (LONG) LOWORD(lParam)) &&

                        (pt.y > (LONG) HIWORD(lParam)))

                    SetRect(&rcTarget, LOWORD(lParam),

                        HIWORD(lParam), pt.x, pt.y);

                else if ((pt.x > (LONG) LOWORD(lParam)) &&

                        (pt.y < (LONG) HIWORD(lParam)))

                    SetRect(&rcTarget, LOWORD(lParam), pt.y,

                        pt.x, HIWORD(lParam));

                else

                    SetRect(&rcTarget, pt.x, pt.y, LOWORD(lParam),

                        HIWORD(lParam));

                /* Draw the new target rectangle. */

                Rectangle(hdc, rcTarget.left, rcTarget.top,

                    rcTarget.right, rcTarget.bottom);

                ReleaseDC(hwnd, hdc);

            }

            else if ((wParam && MK_LBUTTON)

                    && fDragRect) { /* drag the bitmap rectangle */

                /*

                 * Set the mix mode so that the pen color is the

                 * inverse of the background color.

                 */

                hdc = GetDC(hwnd);

                SetROP2(hdc, R2_NOTXORPEN);

                /*

                 * Select the dotted pen into the DC and erase

                 * the previous bitmap rectangle by drawing

                 * another rectangle on top of it.

                 */

                SelectObject(hdc, hpenDot);

                Rectangle(hdc, rcBmp.left, rcBmp.top,

                    rcBmp.right, rcBmp.bottom);

                /*

                 * Set the new coordinates of the bitmap

                 * rectangle, then redraw it.

                 */

                OffsetRect(&rcBmp, LOWORD(lParam) - pt.x,

                    HIWORD(lParam) - pt.y);

                Rectangle(hdc, rcBmp.left, rcBmp.top,

                    rcBmp.right, rcBmp.bottom);

                ReleaseDC(hwnd, hdc);

                /* Save the coordinates of the mouse cursor. */

                pt.x = (LONG) LOWORD(lParam);

                pt.y = (LONG) HIWORD(lParam);

            }

            return 0;

        case WM_LBUTTONUP:

            /*

             * If the bitmap rectangle and target rectangle

             * intersect, copy the bitmap into the target

             * rectangle. Otherwise, copy the bitmap into the

             * rectangle bitmap at its new location.

             */

            if (IntersectRect(&rcTmp, &rcBmp, &rcTarget)) {

                /*

                 * Erase the bitmap rectangle by filling it with

                 * the background color.

                 */

                hdc = GetDC(hwnd);

                FillRect(hdc, &rcBmp, hbrBkgnd);

                /*

                 * Redraw the target rectangle because the part

                 * that intersected with the bitmap rectangle was

                 * erased by the call to FillRect.

                 */

                Rectangle(hdc, rcTarget.left, rcTarget.top,

                    rcTarget.right, rcTarget.bottom);

                /* Copy the bitmap into the target rectangle. */

                StretchBlt(hdc, rcTarget.left + 1, rcTarget.top + 1,

                    (rcTarget.right - rcTarget.left) - 2,

                    (rcTarget.bottom - rcTarget.top) - 2, hdcCompat,

                    0, 0, 32, 32, SRCCOPY);

                /*

                 * Copy the target rectangle to the bitmap

                 * rectangle, set the coordinates of the target

                 * rectangle to 0, then reset the fDragRect flag.

                 */

                CopyRect(&rcBmp, &rcTarget);

                SetRectEmpty(&rcTarget);

                ReleaseDC(hwnd, hdc);

                fDragRect = FALSE;

            }

            else if (fDragRect) {

                /*

                 * Draw the bitmap rectangle, copy the bitmap into

                 * it, and reset the fDragRect flag.

                 */

                hdc = GetDC(hwnd);

                Rectangle(hdc, rcBmp.left, rcBmp.top,

                    rcBmp.right, rcBmp.bottom);

                StretchBlt(hdc, rcBmp.left + 1, rcBmp.top + 1,

                    (rcBmp.right - rcBmp.left) - 2,

                    (rcBmp.bottom - rcBmp.top) - 2, hdcCompat,

                    0, 0, 32, 32, SRCCOPY);

                ReleaseDC(hwnd, hdc);

                fDragRect = FALSE;

            }

            /* Release the mouse cursor. */

            ClipCursor((LPRECT) NULL);

            return 0;

        case WM_DESTROY:

            /*

             * Destroy the background brush, compatible bitmap,

             * and the bitmap.

             */

            DeleteObject(hbrBkgnd);

            DeleteDC(hdcCompat);

            DeleteObject(hbmp);

            PostQuitMessage(0);

            break;

        default:

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

    }

    return (LRESULT) NULL;

}


Rectangle Functions

Following are the functions used with rectangles.

CopyRect
EqualRect
InflateRect
IntersectRect
IsRectEmpty
OffsetRect
PtInRect
SetRect
SetRectEmpty
SubtractRect
UnionRect


Timers

A timer is an internal routine that repeatedly measures a specified interval, in milliseconds. Each time the interval (or time-out value) elapses, the system notifies the window associated with the timer. Because the accuracy of a timer depends on the system clock rate and how often the application retrieves messages from the message queue, the time-out value is only approximate.


About Timers

An application written for Microsoft® Windows® creates a timer by using the SetTimer function. If a window handle is given in this function, the application creates the timer for that window. Then, whenever the time-out value elapses, the system posts a WM_TIMER message to the window. If no window handle is given in SetTimer, the application that created the timer must monitor its message queue for WM_TIMER messages and dispatch them to the appropriate window.

A new timer starts timing as soon as it is created. An application can change a timer's time-out value by using SetTimer and can destroy a timer by using the KillTimer function. To use system resources efficiently, applications should destroy timers that are no longer necessary.

Each timer has a unique identifier. When creating a timer, an application can either specify an identifier or have the system create a unique value. The first parameter of a WM_TIMER message contains the identifier of the timer that posted the message.


Using Timers

•	Creating a timer

•	Destroying a timer

•	Using timer functions to create a mousetrap

•	Process the WM_TIMER message.

•	Use a TimerProc callback function.


Creating a Timer

The following example uses the SetTimer function to create two timers. The first timer is set for every 10 seconds, the second for every 5 minutes.

/* Set two timers. */

SetTimer(hwnd,             /* handle of main window */

    IDT_TIMER1,            /* timer identifier      */

    10000,                 /* 10-second interval    */

    (TIMERPROC) NULL);     /* no timer callback     */

SetTimer(hwnd,             /* handle of main window */

    IDT_TIMER2,            /* timer identifier      */

    300000,                /* 5-minute interval     */

    (TIMERPROC) NULL);     /* no timer callback     */

To process the WM_TIMER messages generated by these timers, add a WM_TIMER case statement to the window procedure for the hwnd parameter.

case WM_TIMER:

    switch (wParam) {

        case IDT_TIMER1:

            .

            . /* Process the 10-second timer. */

            .

             return 0;

        case IDT_TIMER2:

            .

            . /* Process the 5-minute timer. */

            .

            return 0;

    }

An application can also create a timer whose WM_TIMER messages are processed not by the main window procedure but by an application-defined callback function, as in the following code sample, which creates a timer and uses the callback function MyTimerProc to process the timer's WM_TIMER messages.

/* Set the timer. */

SetTimer(hwnd,                /* handle of main window */

    IDT_TIMER3,               /* timer identifier      */

    5000,                     /* 5-second interval     */

    (TIMERPROC) MyTimerProc); /* timer callback        */

The calling convention for MyTimerProc must be based on the Microsoft® Win32® callback function, TimerProc.

If your application creates a timer without specifying a window handle, your application must monitor the message queue for WM_TIMER messages and dispatch them to the appropriate window.

HWND hwndTimer;   /* handle of window for timer messages */

MSG msg;          /* message structure */

    while (GetMessage(&msg, /* message structure                */

            NULL,           /* handle of window receiving msg.  */

            NULL,           /* lowest message to examine        */

            NULL))          /* highest message to examine       */

        {

        /* Post WM_TIMER messages to the hwndTimer procedure.   */

        if (msg.message == WM_TIMER) {

            msg.hwnd = hwndTimer;

        }

        TranslateMessage(&msg); /* translates virtual-key codes */

        DispatchMessage(&msg);  /* dispatches message to window */

    }


Destroying a Timer

Applications should use the KillTimer function to destroy timers that are no longer necessary. The following example destroys the timers identified by the constants IDT_TIMER1, IDT_TIMER2, and IDT_TIMER3.

/* Destroy the timers. */

KillTimer(hwnd, IDT_TIMER1);

KillTimer(hwnd, IDT_TIMER2);

KillTimer(hwnd, IDT_TIMER3);


Using Timer Functions to Create a Mousetrap

Sometimes it is necessary to prevent more input while you have a cursor on the screen. One way to accomplish this is to create a special routine that traps mouse input until a specific event occurs. Many developers refer to this routine as "building a mousetrap."

The following example uses the SetTimer and KillTimer functions to create a simple mousetrap. SetTimer creates a timer that sends a WM_TIMER message every 10 seconds. Each time the application receives a WM_TIMER message, it records the cursor location. If the current location is the same as the previous location and the application's main window is minimized, the application moves the cursor to the icon. When the application closes, KillTimer stops the timer.

HICON hIcon1;               /* icon handle                       */

POINT ptOld;                /* previous cursor location          */

UINT uResult;               /* SetTimer's return value           */

HINSTANCE hinstance;        /* handle of current instance        */

.

. /* Perform application initialization here. */

.

wc.hIcon = LoadIcon(hinstance, MAKEINTRESOURCE(400));

wc.hCursor = LoadCursor(hinstance, MAKEINTRESOURCE(200));

/* Record the initial cursor position. */

GetCursorPos(&ptOld);

/* Set the timer for the mousetrap. */

uResult = SetTimer(hwnd,             /* handle of main window */

    IDT_MOUSETRAP,                   /* timer identifier      */

    10000,                           /* 10-second interval    */

    (TIMERPROC) NULL);               /* no timer callback     */

if (uResult == 0) {

    ErrorHandler("No timer is available.");

}

LONG APIENTRY MainWndProc(

HWND hwnd,          /* handle of main window  */

UINT message,       /* type of message        */

UINT wParam,        /* additional information */

LONG lParam)        /* additional information */

{

    HDC hdc;        /* handle of device context     */

    POINT pt;       /* current cursor location      */

    RECT rc;        /* location of minimized window */

    switch (message) {

        .

        .  /* Process other messages. */

        .

        case WM_TIMER:

            /*

             * If the window is minimized, compare the current

             * cursor position with the one from 10 seconds

             * earlier. If the cursor position has not changed,

             * move the cursor to the icon.

             */

            if (IsIconic(hwnd)) {

                GetCursorPos(&pt);

                if ((pt.x == ptOld.x) && (pt.y == ptOld.y)) {

                    GetWindowRect(hwnd, &rc);

                    SetCursorPos(rc.left, rc.top);

                }

                else {

                    ptOld.x = pt.x;

                    ptOld.y = pt.y;

                }

            }

            return 0;

        case WM_DESTROY:

            /* Destroy the timer. */

            KillTimer(hwnd, IDT_MOUSETRAP);

            PostQuitMessage(0);

            break;

        .

        .  /* Process other messages. */

        .

}

Although the following example also creates a mousetrap, it processes the WM_TIMER message through the application-defined callback function MyTimerProc, rather than through the application's message queue.

UINT uResult;               /* SetTimer's return value     */

HICON hIcon1;               /* icon handle                 */

POINT ptOld;                /* previous cursor location    */

HINSTANCE hinstance;        /* handle of current instance  */

.

. /* Perform application initialization here. */

.

wc.hIcon = LoadIcon(hinstance, MAKEINTRESOURCE(400));

wc.hCursor = LoadCursor(hinstance, MAKEINTRESOURCE(200));

/* Record the current cursor position. */

GetCursorPos(&ptOld);

/* Set the timer for the mousetrap. */

uResult = SetTimer(hwnd,      /* handle of main window */

    IDT_MOUSETRAP,            /* timer identifier      */

    10000,                    /* 10-second interval    */

    (TIMERPROC) MyTimerProc); /* timer callback        */

if (uResult == 0) {

    ErrorHandler("No timer is available.");

}

LONG APIENTRY MainWndProc(

HWND hwnd,          /* handle of main window  */

UINT message,       /* type of message        */

UINT wParam,        /* additional information */

LONG lParam)        /* additional information */

{

    HDC hdc;        /* handle of device context */

    switch (message) {

        .

        .    /* Process other messages. */

        .

        case WM_DESTROY:

            /* Destroy the timer. */

            KillTimer(hwnd, IDT_MOUSETRAP);

            PostQuitMessage(0);

            break;

        .

        .  /* Process other messages. */

        .

}

/*

 * MyTimerProc is an application-defined callback function that

 * processes WM_TIMER messages.

 */

VOID CALLBACK MyTimerProc(

    HWND hwnd,        /* handle of window for timer messages */

    UINT message,     /* WM_TIMER message                    */

    UINT idTimer,     /* timer identifier                    */

    DWORD dwTime)     /* current system time                 */

{

    RECT rc;

    POINT pt;

    /*

     * If the window is minimized, compare the current

     * cursor position with the one from 10 seconds earlier.

     * If the cursor position has not changed, move the

     * cursor to the icon.

     */

    if (IsIconic(hwnd)) {

        GetCursorPos(&pt);

        if ((pt.x == ptOld.x) && (pt.y == ptOld.y)) {

            GetWindowRect(hwnd, &rc);

            SetCursorPos(rc.left, rc.top);

        }

        else {

            ptOld.x = pt.x;

            ptOld.y = pt.y;

        }

    }

}


Timer Functions

The following functions are used with timers.

KillTimer
SetTimer
TimerProc


Window Classes

Every window is a member of a window class. A window class is a set of attributes that Microsoft® Windows® uses as a template to create a window in an application. This overview describes the types of window classes, how Windows locates them, and the elements that define the default behavior of windows that belong to them.


About Window Classes

Each window class has an associated window procedure shared by all windows of the same class. The window procedure processes messages for all windows of that class and therefore controls their behavior and appearance. For more information about window procedures, see Window Procedures.

An application must register a window class before it can create a window of that class. Registering a window class associates a window procedure, class styles, and other class attributes with a class name. When an application specifies a class name in the CreateWindow or CreateWindowEx function, the operating system creates a window with the window procedure, styles, and other attributes associated with that class name.


Types of Window Classes

There are three types of window classes: system global, application global, and application local. These types differ in scope and in when and how they are registered and destroyed.


System Global Classes

When Windows starts, it registers a set of system global classes for controls, including buttons, combo boxes, list boxes, scroll bars, edit controls, and static controls.

Any application can use a system global class at any time. Because Windows registers system global classes on behalf of all applications, an application cannot destroy any of these classes.


Application Global Classes

An application global class is a window class registered by a dynamic-link library (DLL) and available to all applications in the system. For example, you can register a window class that defines a custom control as an application global class so that all applications can create instances of the custom control.

In Windows, all window classes are process specific. An application can create a global class by creating the window class in a DLL and listing the name of the DLL in the registry under the appropriate keys.

Whenever a process starts, the system loads the specified DLL in the context of the newly started process before calling the main function in that process. The DLL must register the class during its initialization procedure and must specify the CS_GLOBALCLASS style. (For more information about class styles, see Class Styles.) After a class has been registered, any application can use it to create any number of windows belonging to that class.

Windows does not automatically destroy a class when the DLL that registered it is unloaded. For this reason, the Windows exit procedure of the DLL should call the UnregisterClass function to remove the class.


Application Local Classes

An application local class is any window class that an application registers for its exclusive use. Although an application can register any number of local classes, most applications register only one. This window class supports the window procedure of the application's main window.

Registering a local class is similar to registering an application global class, except that the CS_GLOBALCLASS style is not specified in the style member of the WNDCLASSEX structure.

Windows destroys a local class when the application that registered it closes. An application can also use the UnregisterClass function to remove a local class and free the storage associated with it.


How Windows Locates a Class

Windows maintains a list of WNDCLASSEX structures for each of the three types of window classes. When an application calls the CreateWindow or CreateWindowEx function to create a window with a specified class, Windows uses the following procedure to locate the class:

1.	Windows searches the list of application local classes for a class with the specified name. Note that several application instances can use the same name to register local classes. Windows uses instance handles to differentiate among local classes that have the same name.

2.	If the name is not in the application local class list, Windows searches the list of application global classes.

3.	If the name is not in the application global class list, Windows searches the list of system global classes.

All windows created by the application use this procedure, including windows created by Windows on the application's behalf, such as dialog boxes. It is possible to override system global classes without affecting other applications. That is, an application can register an application local class having the same name as a system global class. This replaces the system global class in the context of the application but does not prevent other applications from using the system global class.


Class Ownership

The owner of a class is the application or DLL that registered the class. Windows determines class ownership from the hInstance member of the WNDCLASSEX structure passed to the RegisterClassEx function when the class is registered. For Windows DLLs, the hInstance member must be the instance handle of the DLL. The class is destroyed when the owner closes or is unloaded. For this reason, the application must destroy all windows using the class before it closes or the DLL is unloaded.


Elements of a Window Class

The elements of a window class define the default behavior of windows belonging to the class. The application that registers a window class assigns elements to the class by setting appropriate members in a WNDCLASSEX structure and passing the structure to the RegisterClassEx function. The GetClassInfoEx and GetClassLong functions retrieve information about a given window class. The SetClassLong function changes elements of a local or global class that the application has already registered.

Although a complete window class consists of many elements, Windows requires only that an application supply a class name, the window-procedure address, and an instance handle. Use the other elements to define default attributes for windows of the class, such as the shape of the cursor and the content of the menu for the window. You must initialize any unused members of the WNDCLASSEX structure to zero or NULL. The window class elements are as follows.

Element	Purpose
Class name	Distinguishes the class from other registered classes.
Window-procedure address	Points to the function that processes all messages sent to windows in the class and defines the behavior of the window.
Instance handle	Identifies the application or DLL that registered the class.
Class cursor	Defines the mouse cursor that Windows displays for a window of the class.
Class icon	Defines the large icon.
Small class icon	Defines the small icon (Windows version 4.0 and higher).
Class background brush	Defines the color and pattern that fill the client area when the window is opened or painted.
Class menu	Specifies the default menu for windows that do not explicitly define a menu.
Class styles	Defines how to update the window after moving or resizing it, how to process double-clicks of the mouse, how to allocate space for the device context, and other aspects of the window.
Extra class memory	Specifies the amount of extra memory, in bytes, that Windows should reserve for the class. All windows in the class share the extra memory and can use it for any application-defined purpose. Windows initializes this memory to zero.
Extra window memory	Specifies the amount of extra memory, in bytes, that Windows should reserve for each window belonging to the class. The extra memory can be used for any application-defined purpose. Windows initializes this memory to zero.


Class Name

Every window class needs a class name to distinguish one class from another. Assign a class name by setting the lpszClassName member of the WNDCLASSEX structure to the address of a null-terminated string that specifies the name. Because window classes are process specific in Windows, window class names need to be unique only within the same process. Also, because class names occupy space in the system's private atom table, you should keep class name strings as short a possible.

The GetClassName function retrieves the name of the class to which a given window belongs.


Window-Procedure Address

Every class needs a window-procedure address to define the entry point of the window procedure used to process all messages for windows in the class. Windows passes messages to the procedure when it requires the window to carry out tasks, such as painting its client area or responding to input from the user. An application assigns a window procedure to a class by copying its address to the lpfnWndProc member of the WNDCLASSEX structure. For more information about window procedures, see Window Procedures.


Instance Handle

Every window class requires an instance handle to identify the application or DLL that registered the class. As a multitasking system, Windows lets several applications or DLLs run at the same time, so it requires instance handles to keep track of all of them. Windows assigns a handle to each copy of a running application or DLL.

Multiple instances of the same application or DLL all use the same code segment, but each has its own data segment. Windows uses an instance handle to identify the data segment that corresponds to a particular instance of an application or DLL.

Windows passes an instance handle to an application or DLL when the application starts. The application or DLL assigns this instance handle to the class by copying it to the hInstance member of the WNDCLASSEX structure.


Class Cursor

The class cursor defines the shape of the cursor when it is in the client area of a window in the class. Windows automatically sets the cursor to the given shape when the cursor enters the window's client area and ensures it keeps that shape while it remains in the client area. To assign a cursor shape to a window class, load a predefined cursor shape by using the LoadCursor function and then assign the returned cursor handle to the hCursor member of the WNDCLASSEX structure. Alternatively, provide a custom cursor resource and use the LoadCursor function to load it from the application's resources.

Windows does not require a class cursor. If an application sets the hCursor member of the WNDCLASSEX structure to NULL, a class cursor is not defined. Windows assumes the window sets the cursor shape each time the cursor moves into the window. A window can set the cursor shape by calling the SetCursor function whenever the window receives the WM_MOUSEMOVE message. For more information about cursors, see Cursors.


Class Icons

A class icon is a picture that the system uses to represent a window of a particular class. A class can have one or two icons, depending on the operating system version. You can use the GetVersionEx function to retrieve the version number.

Class Icons in Version 4.0 or Later

With version 4.0 or later, an application can have two class icons — one large and one small. The system displays a window's large class icon in the task-switch window that appears when the user presses ALT+TAB, and in the large icon views of the task bar and explorer. The small class icon appears in a window's title bar and in the small icon views of the task bar and explorer.

To assign a large and small icon to a window class, specify the handles of the icons in the hIcon and hIconSm members of the WNDCLASSEX structure. The icon dimensions must conform to required dimensions for large and small class icons. For a large class icon, you can determine the required dimensions by specifying the SM_CXICON and SM_CYICON values in a call to the GetSystemMetrics function. For a small class icon, specify the SM_CXSMICON and SM_CYSMICON values. For information about creating icons and loading icon resources, see Icons.

If an application sets the hIcon and hIconSm members of the WNDCLASSEX structure to NULL, the system uses the default application icon as the large and small class icons for the window class. If you specify a large class icon but not a small one, the system creates a small class icon based on the large one. However, if you specify a small class icon but not a large one, the system uses the default application icon as the large class icon and the specified icon as the small class icon.

You can override the large or small class icon for a particular window by using the WM_SETICON message. You can retrieve the current large or small class icon by using the WM_GETICON message.

Class Icons in Versions Earlier Than 4.0

In operating system versions earlier than 4.0, the class icon defines the icon used when a window of the given class is minimized. To assign an icon to a window class, specify an icon handle in the hIcon member of the WNDCLASS structure. If an application sets the hIcon member of WNDCLASS to NULL, a class icon is not defined. In this case, Windows sends the WM_ICONERASEBKGND message to a window of the class whenever it must paint the icon background. If the window does not process the WM_ICONERASEBKGND message, Windows draws an image of the contents of the window's client area when the window is minimized. For more information about drawing minimized windows, see Painting and Drawing.


Class Background Brush

A class background brush prepares the client area of a window for subsequent drawing by the application. Windows uses the brush to fill the client area with a solid color or pattern, thereby removing all previous images from that location whether they belonged to the window or not. Windows notifies a window that its background should be painted by sending the WM_ERASEBKGND message to the window. For more information about brushes, see Brushes.

To assign a background brush to a class, create a brush by using the appropriate GDI functions and assign the returned brush handle to the hbrBackground member of the WNDCLASSEX structure.

Instead of creating a brush, an application can set the hbrBackground member to one of the standard system color values. For a list of the standard system color values, see SetSysColors.

To use a standard system color, the application must increase the background-color value by one. For example, COLOR_BACKGROUND + 1 is the system background color. Alternatively, you can use the GetSysColorBrush function to retrieve the handle of a brush that corresponds to a standard system color, and then specify the handle in the hbrBackground member of the WNDCLASSEX structure.

Windows does not require that a window class have a class background brush. If this parameter is set to NULL, the window must paint its own background whenever it receives the WM_ERASEBKGND message.


Class Menu

A class menu defines the default menu to be used by the windows in the class if no explicit menu is given when the windows are created. A menu is a list of commands from which a user can choose actions for the application to carry out.

You can assign a menu to a class by setting the lpszMenuName member of the WNDCLASSEX structure to the address of a null-terminated string that specifies the resource name of the menu. The menu is assumed to be a resource in the given application. Windows automatically loads the menu when it is needed. Note that if the menu resource is identified by an integer and not by a name, the application can set the lpszMenuName member to that integer by applying the MAKEINTRESOURCE macro before assigning the value.

Windows does not require a class menu. If an application sets the lpszMenuName member of the WNDCLASSEX structure to NULL, Windows assumes the windows in the class have no menu bars. Even if no class menu is given, an application can still define a menu bar for a window when it creates the window.

Windows does not allow menu bars with child windows. If a menu is given for a class and a child window of that class is created, the menu is ignored. For more information about menus, see Menus (Windows NT).


Class Styles

The class styles define additional elements of the window class. Two or more styles can be combined by using the bitwise OR (|) operator. To assign a style to a window class, assign the style to the style member of the WNDCLASSEX structure. The class styles are as follows.

Style	Action
CS_BYTEALIGNCLIENT	Aligns the window's client area on a byte boundary (in the x direction) to enhance performance during drawing operations. This style affects the width of the window and its horizontal placement on the display.
CS_BYTEALIGNWINDOW	Aligns the window on a byte boundary (in the x direction) to enhance performance during operations that involve moving or sizing the window. This style affects the width of the window and its horizontal placement on the display.
CS_CLASSDC	Allocates one device context to be shared by all windows in the class. For more information about device contexts, see Class and Private Device Contexts and Device Contexts.
CS_DBLCLKS	Instructs Windows to send a double-click message to the window procedure when the user double-clicks the mouse while the cursor is within a window belonging to the class. For more information about double-clicks, see Mouse Input.
CS_GLOBALCLASS	Specifies that the window class is an application global class. For more information, see Application Global Classes.
CS_HREDRAW	Specifies that the entire window is to be redrawn if a movement or size adjustment changes the width of the client area.
CS_NOCLOSE	Disables the Close command on the System menu.
CS_OWNDC	Allocates a unique device context for each window in the class. For more information about device contexts, see Class and Private Device Contexts and Device Contexts.
CS_PARENTDC	Sets the clipping rectangle of the child window to that of the parent window so that the child can draw on the parent. A window with the CS_PARENTDC style bit receives a regular device context from the system's cache of device contexts. It does not give the child the parent's device context or device context settings. Specifying CS_PARENTDC enhances an application's performance. For more information about device contexts, see Class and Private Device Contexts and Device Contexts.
CS_SAVEBITS	Saves, as a bitmap, the portion of the screen image obscured by a window. Windows uses the saved bitmap to re-create the screen image when the window is removed. Windows displays the bitmap at its original location and does not send WM_PAINT messages to windows obscured by the window if other screen actions have not invalidated the stored image. Use this style for small windows that are displayed briefly and then removed before other screen activity takes place (for example, menus or dialog boxes). This style increases the time required to display the window, because the operating system must first allocate memory to store the bitmap.
CS_VREDRAW	Specifies that the entire window is to be redrawn if a movement or size adjustment changes the height of the client area.


Extra Class Memory

Windows maintains a WNDCLASSEX structure internally for each window class in the system. When an application registers a window class, it can direct Windows to allocate and append a number of additional bytes of memory to the end of the WNDCLASSEX structure. This memory is called extra class memory and is shared by all windows belonging to the class. Use the extra class memory to store any information pertaining to the class.

Because extra memory is allocated from the system's local heap, an application should use extra class memory sparingly. With operating system version 4.0 or later, the RegisterClassEx function fails if the amount of extra class memory requested is greater than 40 bytes. If an application requires more than 40 bytes, it should allocate its own memory and store a pointer to the memory in the extra class memory.

The SetClassWord and SetClassLong functions copy a value to the extra class memory. To retrieve a value from the extra class memory, use the GetClassWord and GetClassLong functions. The cbClsExtra member of the WNDCLASSEX structure specifies the amount of extra class memory to allocate. An application that doesn't use extra class memory must initialize the cbClsExtra member to zero.


Extra Window Memory

Windows maintains an internal data structure for each window. When registering a window class, an application can specify a number of additional bytes of memory, called extra window memory. When creating a window of the class, Windows allocates and appends the specified amount of extra window memory to the end of the window's structure. An application can use this memory to store window-specific data.

Because extra memory is allocated from the system's local heap, an application should use extra window memory sparingly. With operating system version 4.0 or later, the RegisterClassEx function fails if the amount of extra window memory requested is greater than 40 bytes. If an application requires more than 40 bytes, it should allocate its own memory and store a pointer to the memory in the extra window memory.

The SetWindowWord and SetWindowLong functions copy a value to the extra memory. The GetWindowWord and GetWindowLong functions retrieve a value from the extra memory. The cbWndExtra member of the WNDCLASSEX structure specifies the amount of extra window memory to allocate. An application that doesn't use the memory must initialize cbWndExtra to zero.


Class and Private Device Contexts

A device context is a special set of values that applications use for drawing in the client area of their windows. Windows requires a device context for each window on the display but allows some flexibility in how the operating system stores and treats that device context.

If no device-context style is explicitly given, Windows assumes each window uses a device context retrieved from a pool of contexts maintained by Windows. In such cases, each window must retrieve and initialize the device context before painting and free it after painting.

To avoid retrieving a device context each time it needs to paint inside a window, an application can specify the CS_OWNDC style for the window class. This class style directs Windows to create a private device context — that is, to allocate a unique device context for each window in the class. The application need only retrieve the context once and then use it for all subsequent painting. Although the CS_OWNDC style is convenient, use it carefully, because each device context uses a significant portion of system resources.

By specifying the CS_CLASSDC style, an application can create a class device context. A class device context is a rarely used feature that allows multiple windows created from the same window class within a process to use exactly the same device context for drawing.

An application can specify the CS_PARENTDC style to create child windows that inherit the device context of their parent window. This style allows a child window to draw in the client area of its parent.

An application can specify the CS_PARENTDC style to set the clipping rectangle of the child window to that of the parent window so the child can draw in the parent. A window with the CS_PARENTDC style receives a regular device context from the system's cache of device contexts. It does not give a child window's device context or device context settings to the parent window. Specifying CS_PARENTDC enhances an application's performance because Windows doesn't need to keep recalculating the visible region for each child window.

For more information about device contexts, see Device Contexts. For more information about painting, see Painting and Drawing.


Using Window Classes

In Windows, each application must register its own window classes. Your application can register an application local class at any time by using the RegisterClassEx function. You must define the window procedure in the application, fill the members of the WNDCLASSEX structure, and then pass a pointer to the structure to the RegisterClassEx function.

The following example shows how to register a local window class and use it to create your application's main window.

#include <windows.h>

/* Global variable */

HINSTANCE hinst;

/* Function prototypes */

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int);

InitApplication(HINSTANCE);

InitInstance(HINSTANCE, int);

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

/* Application entry point */

int WINAPI WinMain(hinstance, hPrevInstance, lpCmdLine, nCmdShow)

HINSTANCE hinstance;

HINSTANCE hPrevInstance;

LPSTR lpCmdLine;

int nCmdShow;

{

    MSG msg;

    if (!InitApplication(hinstance))

        return FALSE;

    if (!InitInstance(hinstance, nCmdShow))

        return FALSE;

    while (GetMessage(&msg, (HWND) NULL, 0, 0)) {

        TranslateMessage(&msg);

        DispatchMessage(&msg);

    }

    return msg.wParam;

        UNREFERENCED_PARAMETER(lpCmdLine);

}

BOOL InitApplication(hinstance)

HINSTANCE hinstance;

{

    WNDCLASSEX wcx;

    /*

     * Fill in the window class structure with parameters

     * that describe the main window.

     */

    wcx.cbSize = sizeof(wcx);          /* size of structure      */

    wcx.style = CS_HREDRAW |

        CS_VREDRAW;                    /* redraw if size changes */

    wcx.lpfnWndProc = MainWndProc;     /* points to window proc. */

    wcx.cbClsExtra = 0;                /* no extra class memory  */

    wcx.cbWndExtra = 0;                /* no extra window memory */

    wcx.hInstance = hinstance;         /* handle of instance     */

    wcx.hIcon = LoadIcon(NULL,

        IDI_APPLICATION);              /* predefined app. icon   */

    wcx.hCursor = LoadCursor(NULL,

        IDC_ARROW);                    /* predefined arrow       */

    wcx.hbrBackground = GetStockObject(

        WHITE_BRUSH);                  /* white background brush */

    wcx.lpszMenuName =  "MainMenu";    /* name of menu resource  */

    wcx.lpszClassName = "MainWClass";  /* name of window class   */

    wcx.hIconSm = LoadImage(hinstance, /* small class icon       */

        MAKEINTRESOURCE(5),

        GetSystemMetrics(SM_CXSMICON),

        GetSystemMetrics(SM_CYSMICON),

        LR_DEFAULTCOLOR);

    /* Register the window class. */

    return RegisterClassEx(&wcx);

}

BOOL InitInstance(hinstance, nCmdShow)

HINSTANCE hinstance;

int nCmdShow;

{

    HWND hwnd;

    /* Save the application-instance handle. */

    hinst = hinstance;

    /* Create the main window. */

    hwnd = CreateWindow(

        "MainWClass",        /* name of window class        */

        "Sample",            /* title-bar string            */

        WS_OVERLAPPEDWINDOW, /* top-level window            */

        CW_USEDEFAULT,       /* default horizontal position */

        CW_USEDEFAULT,       /* default vertical position   */

        CW_USEDEFAULT,       /* default width               */

        CW_USEDEFAULT,       /* default height              */

        (HWND) NULL,         /* no owner window             */

        (HMENU) NULL,        /* use class menu              */

        hinstance,           /* handle of app. instance     */

        (LPVOID) NULL);      /* no window-creation data     */

    if (!hwnd)

        return FALSE;

     /*

      * Show the window and send a WM_PAINT message to the window

      * procedure.

      */

    ShowWindow(hwnd, nCmdShow);

    UpdateWindow(hwnd);

    return TRUE;

}

Registering an application global class is similar to registering an application local class, with the following exceptions:

•	The style parameter of the WNDCLASSEX structure must specify the CS_GLOBALCLASS style.

•	The class can be registered by an application or a DLL. If registered by an application, the class is global only within the application. If the class is registered by a DLL and listed in the registry, the system loads the DLL for every application.

•	The application or DLL need not check for a previous instance of the application or DLL before registering the class.


Window Class Functions

Following are the functions used with window classes.

GetClassInfo
GetClassInfoEx
GetClassLong
GetClassName
GetClassWord
GetWindowLong
GetWindowWord
RegisterClass
RegisterClassEx
SetClassLong
SetClassWord
SetWindowLong
SetWindowWord
UnregisterClass


Window Procedures

In Microsoft® Windows®, every window has an associated window procedure — a function that processes all messages sent or posted to all windows of the class. All aspects of a window's appearance and behavior depend on the window procedure's response to these messages.


About Window Procedures

Each window is a member of a particular window class. The window class determines the default window procedure that an individual window uses to process its messages. All windows belonging to the same class use the same default window procedure. For example, the system defines a window procedure for the combo box class (COMBOBOX); all combo boxes then use that window procedure.

An application typically registers at least one new window class and an associated window procedure. After registering a class, the application can create many windows of that class, all of which use the same default window procedure. Because this means several sources could simultaneously call the same piece of code, the developer must be careful when modifying shared resources from a window procedure. For more information about window classes, see Window Classes.

Window procedures for dialog boxes (called dialog box procedures) have a similar structure and function as regular window procedures. All points referring to window procedures in this section also apply to dialog box procedures. For more information about dialog boxes, see Dialog Boxes.


Structure of a Window Procedure

A window procedure is a function that has four parameters and returns a 32-bit signed value. The parameters consist of a window handle, a UINT message identifier, and two message parameters declared with the WPARAM and LPARAM data types. The operating system defines a WPARAM value as a 32-bit unsigned integer and an LPARAM value as a 32-bit signed integer.

The window procedure parameters are described in the following table.

Parameter	Description
hwnd	Handle of the window receiving the message.
uMsg	Message identifier. The identifier corresponds to one of the predefined constants (for example, WM_CREATE) defined in the system header files or to an application-defined message identifier.
wParam, lParam	Message parameters. Their interpretation depends on the value of the uMsg parameter.
Message parameters often contain information in both their low-order and high-order words. The Microsoft® Win32® application programming interface (API) includes several macros an application can use to extract information from the message parameters. The LOWORD macro, for example, extracts the low-order word (bits 0 through 15) from a message parameter. Other macros include HIWORD, LOBYTE, and HIBYTE.

The return value of a window procedure is declared as an LRESULT data type, which is defined as a 32-bit signed value. The interpretation of the return value depends on the particular message. Consult the description of each message to determine the appropriate return value.

Because it is possible to call a window procedure recursively, it is important to minimize the number of local variables that it uses. When processing individual messages, an application should call functions outside the window procedure to avoid excessive use of local variables, possibly causing the stack to overflow during deep recursion.


Default Window Procedure

The default window procedure function DefWindowProc defines certain fundamental behavior shared by all windows. The default window procedure provides the minimal functionality for a window. An application-defined window procedure should pass any messages that it does not process to the DefWindowProc function for default processing.


Window Procedure Subclassing

When an application creates a window, the operating system allocates a block of memory for storing information specific to the window, including the address of the window procedure that processes messages for the window. When Windows needs to pass a message to the window, it searches the window-specific information for the address of the window procedure and passes the message to that procedure.

Subclassing is a technique that allows an application to intercept and process messages sent or posted to a particular window before the window has a chance to process them. By subclassing a window, an application can augment, modify, or monitor the behavior of the window. Although it is not recommended, an application can subclass any window, including those belonging to a system global class, such as an edit control or a list box. For example, an application could subclass an edit control to prevent the control from accepting certain characters. For an explanation of the risks involved, see the following section.

An application subclasses a window by replacing the address of the window's original window procedure with the address of a new window procedure, called the subclass procedure. Thereafter, the subclass procedure receives any messages sent or posted to the window.

The subclass procedure can take three actions upon receiving a message: it can pass the message to the original window procedure, modify the message and pass it to the original window procedure, or process the message and not pass it to the original window procedure. If the subclass procedure processes a message, it can do so before, after, or both before and after it passes the message to the original window procedure.

Windows provides two types of subclassing: instance and global. In instance subclassing, an application replaces the window procedure address of a single instance of a window. An application must use instance subclassing to subclass an existing window. In global subclassing, an application replaces the address of the window procedure in the WNDCLASS structure of a window class. All subsequent windows created with the class have the address of the subclass procedure, but existing windows of the class are not affected.


Instance Subclassing

An application subclasses an instance of a window by using the SetWindowLong function. The application passes the GWL_WNDPROC flag, the handle of the window to subclass, and the address of the subclass procedure to SetWindowLong. The subclass procedure can reside in either the application's module or a dynamic-link library (DLL). An application must list the name of the subclass procedure in the EXPORTS statement of the application's or DLL's module-definition (.DEF) file.

SetWindowLong returns the address of the window's original window procedure. The application must save the address, using it in subsequent calls to the CallWindowProc function, to pass intercepted messages to the original window procedure. The application must also have the original window procedure address to remove the subclass from the window. To remove the subclass, the application calls SetWindowLong again, passing the address of the original window procedure with the GWL_WNDPROC flag and the handle of the window.

An application can subclass any window in the system; however, when subclassing a window it does not own, the application must ensure that the subclass procedure does not destroy the original behavior of the window. Because the application does not control the window, it must not depend on information about the window that the owner might change in the future.

An application should not use the extra window bytes or the class bytes for a window without knowing exactly what the bytes mean and how the original window procedure uses them. Even so, the application should not use them unless it owns the window. If the application uses the extra window bytes of a window that another application owns and the owner changes some aspect of the extra bytes, the subclass procedure may fail. For this reason, an application should not subclass a window that belongs to a system global control class. Windows owns the system global classes, and aspects of the controls might change from one version of Windows to the next. If the application must subclass a window that belongs to a system global class, the developer may need to update the application when a new version of Windows is released.

Because instance subclassing occurs after a window is created, the application subclassing the window cannot add any extra bytes to the window. Applications that subclass a window should use the window's property list to store any data needed for an instance of the subclassed window. For more information about window properties, see Window Properties.

When an application subclasses a subclassed window, it must remove the subclasses in the reverse order they were performed. If the removal order is not reversed, an unrecoverable system error may occur.


Global Subclassing

To globally subclass a window class, the application must have a handle to a window of the class. The application also needs the handle to remove the subclass. To get the handle, an application typically creates a hidden window of the class to be subclassed. After obtaining the handle, the application calls the SetClassLong function, specifying the handle, the GCL_WNDPROC flag, and the address of the subclass procedure. SetClassLong returns the address of the original window procedure for the class.

The original window procedure address is used in global subclassing in the same way it is used in instance subclassing. The subclass procedure passes messages to the original window procedure by calling CallWindowProc. The application removes the subclass from the window class by calling SetClassLong again, specifying the address of the original window procedure, the GCL_WNDPROC flag, and the handle to a window of the class being subclassed. An application that globally subclasses a control class must remove the subclass when the application terminates; otherwise, an unrecoverable system error may occur.

Global subclassing has the same limitations as instance subclassing, plus some additional restrictions. An application should not use the extra bytes for either the class or the window instance without knowing exactly how the original window procedure uses them. If the application must associate data with a window, it should use window properties.

An application must not globally subclass a system global class. An unrecoverable system error may occur if more than one application globally subclasses a control class. If the application could benefit from globally subclassing a control class, use the technique called superclassing.


Window Procedure Superclassing

Superclassing is a technique that allows an application to create a new window class with the basic functionality of the existing class, plus enhancements provided by the application. A superclass is based on an existing window class called the base class. Frequently, the base class is a system global window class such as an edit control, but it can be any window class.

A superclass has its own window procedure, called the superclass procedure. The superclass procedure can take three actions upon receiving a message: It can pass the message to the original window procedure, modify the message and pass it to the original window procedure, or process the message and not pass it to the original window procedure. If the superclass procedure processes a message, it can do so before, after, or both before and after it passes the message to the original window procedure.

Unlike a subclass procedure, a superclass procedure can process window creation messages (WM_NCCREATE, WM_CREATE, and so on), but it must also pass them to the original base-class window procedure so that the base-class window procedure can perform its initialization procedure.

To superclass a window class, an application first calls the GetClassInfo function to retrieve information about the base class. GetClassInfo fills a WNDCLASS structure with the values from the WNDCLASS structure of the base class. Next, the application copies its own instance handle into the hInstance member of the WNDCLASS structure and copies the name of the superclass into the lpszClassName member. If the base class has a menu, the application must provide a new menu with the same menu identifiers and copy the menu name into the lpszMenuName member. If the superclass procedure processes the WM_COMMAND message and does not pass it to the window procedure of the base class, the menu need not have corresponding identifiers. GetClassInfo does not return the lpszMenuName, lpszClassName, or hInstance member of the WNDCLASS structure.

An application must also set the lpfnWndProc member of the WNDCLASS structure. The GetClassInfo function fills this member with the address of the original window procedure for the class. The application must save this address, to pass messages to the original window procedure, and then copy the address of the superclass procedure into the lpfnWndProc member. The application can, if necessary, modify any other members of the WNDCLASS structure. After it fills the WNDCLASS structure, the application registers the superclass by passing the address of the structure to the RegisterClass function. The superclass can then be used to create windows.

Because superclassing registers a new window class, an application can add to both the extra class bytes and the extra window bytes. The superclass must not use the original extra bytes for the base class or the window for the same reasons that an instance subclass or a global subclass should not use them. Also, if the application adds extra bytes for its use to either the class or the window instance, it must reference the extra bytes relative to the number of extra bytes used by the original base class. Because the number of bytes used by the base class may vary from one version of the base class to the next, the starting offset for the superclass's own extra bytes may also vary from one version of the base class to the next.


Using Window Procedures

•	Designing a window procedure

•	Associating a window procedure with a window class

•	Subclassing a window


Designing a Window Procedure

The following example shows the structure of a typical window procedure. The window procedure uses the message argument in a switch statement with individual messages handled by separate case statements. Notice that each case returns a specific value for each message. For messages that it does not process, the window procedure calls the DefWindowProc function.

LRESULT APIENTRY MainWndProc(hwnd, uMsg, wParam, lParam)

HWND hwnd;      // handle of window

UINT uMsg;      // message identifier

WPARAM wParam;  // first message parameter

LPARAM lParam;  // second message parameter

{

    switch (uMsg) {

        case WM_CREATE:

            // Initialize the window.

            return 0;

        case WM_PAINT:

            // Paint the window's client area.

            return 0;

        case WM_SIZE:

            // Set the size and position of the window.

            return 0;

        case WM_DESTROY:

            // Clean up window-specific data objects.

            return 0;

        .

        . // Process other messages.

        .

        default:

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

    }

    return 0;

}

The WM_NCCREATE messageis sent just after your window is created, but if an application responds to this message by returning FALSE, CreateWindowEx function fails. The WM_CREATE message is sent after your window is already created.

The WM_DESTROY message is sent when your window is about to be destroyed. The DestroyWindow function takes care of destroying any child windows of the window being destroyed. The WM_NCDESTROY message is sent just before a window is destroyed.

At the very least, a window procedure should process the WM_PAINT message to draw itself. Typically, it should handle mouse and keyboard messages as well. Consult the descriptions of individual messages to determine whether your window procedure should handle them.

Your application can call the DefWindowProc function as part of the processing of a message. In such a case, the application can modify the message parameters before passing the message to DefWindowProc, or it can continue with the default processing after performing its own operations.

A dialog box procedure receives a WM_INITDIALOG message instead of a WM_CREATE message and does not pass unprocessed messages to the DefDlgProc function. Otherwise, a dialog box procedure is exactly the same as a window procedure. For more information about dialog box procedures, see Dialog Boxes.


Associating a Window Procedure with a Window Class

You associate a window procedure with a window class when registering the class. You must fill a WNDCLASS structure with information about the class, and the lpfnWndProc member must specify the address of the window procedure. To register the class, pass the address of WNDCLASS structure to the RegisterClass function. Once the window class is registered, the window procedure is automatically associated with each new window created with that class.

The following example shows how to associate the window procedure in the previous example with a window class.

int APIENTRY WinMain(hinstance, hinstPrev, lpCmdLine, nCmdShow)

HINSTANCE hinstance;  // handle of current instance

HINSTANCE hinstPrev;  // handle of previous instance

LPSTR lpCmdLine;      // address of command-line string

int nCmdShow;         // show-window type

{

    WNDCLASS wc;

    // Register the main window class.

    wc.style = CS_HREDRAW | CS_VREDRAW;

    wc.lpfnWndProc = (WNDPROC) MainWndProc;

    wc.cbClsExtra = 0;

    wc.cbWndExtra = 0;

    wc.hInstance = hinstance;

    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);

    wc.hCursor = LoadCursor(NULL, IDC_ARROW);

    wc.hbrBackground = GetStockObject(WHITE_BRUSH);

    wc.lpszMenuName =  "MainMenu";

    wc.lpszClassName = "MainWindowClass";

    if (!RegisterClass(&wc))

       return FALSE;

    .

    . // Process other messages.

    .

}


Subclassing a Window

To subclass an instance of a window, call the SetWindowLong function and specify the handle of the window to subclass the GWL_WNDPROC flag and a pointer to the subclass procedure. SetWindowLong returns a pointer to the original window procedure; use this pointer to pass messages to the original procedure. The subclass window procedure must use the CallWindowProc function to call the original window procedure.

The following example shows how to subclass an instance of an edit control in a dialog box. The subclass window procedure enables the edit control to receive all keyboard input, including the ENTER and TAB keys, whenever the control has the input focus.

WNDPROC wpOrigEditProc;

LRESULT APIENTRY EditBoxProc(hwndDlg, uMsg, wParam, lParam)

HWND hwndDlg;

UINT uMsg;

WPARAM wParam;

LPARAM lParam;

{

    HWND hwndEdit;

    switch(uMsg) {

        case WM_INITDIALOG:

            // Retrieve the handle of the edit control.

            hwndEdit = GetDlgItem(hwndDlg, ID_EDIT);

            // Subclass the edit control.

            wpOrigEditProc = (WNDPROC) SetWindowLong(hwndEdit,

                GWL_WNDPROC, (LONG) EditSubclassProc);

            .

            . // Continue the initialization procedure.

            .

            return TRUE;

        case WM_DESTROY:

            // Remove the subclass from the edit control.

            SetWindowLong(hwndEdit, GWL_WNDPROC,

                (LONG) wpOrigEditProc);

            .

            . // Continue the cleanup procedure.

            .

            break;

    }

    return FALSE;

        UNREFERENCED_PARAMETER(lParam);

}

// Subclass procedure

LRESULT APIENTRY EditSubclassProc(hwnd, uMsg, wParam, lParam)

HWND hwnd;

UINT uMsg;

WPARAM wParam;

LPARAM lParam;

{

    if (uMsg == WM_GETDLGCODE)

        return DLGC_WANTALLKEYS;

    return CallWindowProc(wpOrigEditProc, hwnd, uMsg,

        wParam, lParam);

}


Window Procedure Functions

Following are the functions used with window procedures.

CallWindowProc
DefWindowProc
WindowProc


Window Properties

A window property is any data assigned to a window by the SetProp function. A window property is usually a handle of the window-specific data, but it may be any 32-bit value. Each window property is identified by a string name.


About Window Properties

Window properties are typically used to associate data with a subclassed window or a window in a multiple document interface (MDI) application. In either case, it is not convenient to use the extra bytes specified in the CreateWindow function or class structure for the following two reasons:

•	An application might not know how many extra bytes are available or how the space is being used. By using window properties, the application can associate data with a window without accessing the extra bytes.

•	An application must access the extra bytes by using offsets. Window properties, however, are accessed by their string identifiers, not by offsets.

For more information about subclassing, see Window Procedures. For more information about MDI windows, see Multiple Document Interface.

The Microsoft® Win32® application programming interface (API) provides several functions that enable applications to use window properties. The SetProp function assigns a window property and its string identifier to a window. The GetProp function retrieves the window property identified by a given string. The RemoveProp function destroys the association between a window and a window property but does not destroy the data itself. The EnumProps and EnumPropsEx functions enumerate all of a window's properties by using an application-defined callback function. EnumPropsEx includes an extra parameter for application-defined data used by the callback function.


Using Window Properties

•	Adding a window property

•	Retrieving a window property

•	Listing window properties for a given window

•	Deleting a window property


Adding a Window Property

The following example loads an icon and then a cursor and allocates memory for a buffer. The example then uses the SetProp function to assign the resulting icon, cursor, and memory handles as window properties for the window identified by the application-defined hwndSubclass variable. The properties are identified by the strings PROP_ICON, PROP_CURSOR, and PROP_BUFFER.

#define BUFFER 4096

HINSTANCE hinst;       /* handle of current instance    */

HWND hwndSubclass;     /* handle of a subclassed window */

HANDLE hIcon, hCursor;

HGLOBAL hMem;

char *lpMem;

TCHAR tchPath[] = "c:\\winnt\\samples\\winprop.c";

/* Load resources. */

hIcon = LoadIcon(hinst, MAKEINTRESOURCE(400));

hCursor = LoadCursor(hinst, MAKEINTRESOURCE(220));

/* Allocate and fill a memory buffer. */

hMem = GlobalAlloc(GPTR, BUFFER);

lpMem = GlobalLock(hMem);

lstrcpy(lpMem, tchPath);

GlobalUnlock(hMem);

/* Set the window properties for hwndSubclass. */

SetProp(hwndSubclass, "PROP_ICON", hIcon);

SetProp(hwndSubclass, "PROP_CURSOR", hCursor);

SetProp(hwndSubclass, "PROP_BUFFER", hMem);


Retrieving a Window Property

A window can create handles to its window property data and use the data for any purpose. The following example uses GetProp to obtain handles to the window properties identified by PROP_ICON, PROP_CURSOR, and PROP_BUFFER. The example then displays the contents of the newly obtained memory buffer, cursor, and icon in the window's client area.

#define PATHLENGTH 256

HWND hwndSubclass;     /* handle of a subclassed window */

HANDLE hIconProp, hCursProp;

HGLOBAL hMemProp;

char *lpFilename;

TCHAR tchBuffer[PATHLENGTH];

int nSize;

HDC hdc;

/* Get the window properties, then use the data. */

hIconProp = (HICON) GetProp(hwndSubclass, "PROP_ICON");

TextOut(hdc, 10, 40, "PROP_ICON", 9);

DrawIcon(hdc, 90, 40, hIconProp);

hCursProp = (HCURSOR) GetProp(hwndSubclass, "PROP_CURSOR");

TextOut(hdc, 10, 85, "PROP_CURSOR", 9);

DrawIcon(hdc, 110, 85, hCursProp);

hMemProp = (HGLOBAL) GetProp(hwndSubclass, "PROP_BUFFER");

lpFilename = GlobalLock(hMemProp);

nSize = sprintf(tchBuffer,

    "Path to file:  %s", lpFilename);

TextOut(hdc, 10, 10, tchBuffer, nSize);


Listing Window Properties for a Given Window

In the following example, the EnumPropsEx function lists the string identifiers of the window properties for the window identified by the application-defined hwndSubclass variable. This function relies on the application-defined callback function WinPropProc to display the strings in the window's client area.

EnumPropsEx(hwndSubclass, WinPropProc, NULL);

/*

 * WinPropProc is an application-defined callback function

 * that lists a window property.

 */

BOOL CALLBACK WinPropProc(

    HWND hwndSubclass,  /* handle of window with property */

    LPCSTR lpszString,  /* property string or atom        */

    HANDLE hData)       /* data handle                    */

{

    static int nProp = 1;    /* property counter          */

    TCHAR tchBuffer[BUFFER]; /* expanded-string buffer    */

    int nSize;               /* size of string in buffer  */

    HDC hdc;                 /* device-context handle     */

    hdc = GetDC(hwndSubclass);

    /* Display window property string in client area. */

    nSize = sprintf(tchBuffer, "WinProp %d:  %s", nProp++,

        lpszString);

    TextOut(hdc, 10, nProp * 20, tchBuffer, nSize);

    ReleaseDC(hwndSubclass, hdc);

    return TRUE;

}


Deleting a Window Property

When a window is destroyed, it must destroy any window properties it set. The following example uses the EnumPropsEx function and the application-defined callback function DelPropProc to destroy the properties associated with the window identified by the application-defined hwndSubclass variable. The callback function, which uses the RemoveProp function, is also shown.

case WM_DESTROY:

    EnumPropsEx(hwndSubclass, DelPropProc, NULL);

    PostQuitMessage(0);

    break;

    .

    .

    .

/*

 * DelPropProc is an application-defined callback function

 * that deletes a window property.

 */

BOOL CALLBACK DelPropProc(

    HWND hwndSubclass,  /* handle of window with property */

    LPCSTR lpszString,  /* property string or atom        */

    HANDLE hData)       /* data handle                    */

{

    RemoveProp(hwndSubclass, lpszString);

    return TRUE;

}


Window Property Functions

Following are the functions used with window properties.

EnumProps
EnumPropsEx
GetProp
PropEnumProc
PropEnumProcEx
RemoveProp
SetProp


Animation Controls

An animation control is a window that silently displays an Audio Video Interleaved (AVI) clip. An AVI clip is a series of bitmap frames like a movie. Although AVI clips can have sound, you cannot use such clips with animation controls. You can use only silent AVI clips.


About Animation Controls

Because the thread continues executing while the AVI clip is displayed, one common use for an animation control is to indicate system activity during a lengthy operation. For example, the Find dialog box of the Microsoft® Windows® Explorer displays a moving magnifying glass as the system searches for a file.

An animation control can display an AVI clip originating from either an uncompressed .AVI file or from an .AVI file that was compressed using run-length encoding (RLE). You can add the AVI clip to your application as an AVI resource, or the clip can accompany your application as a separate .AVI file.

The capabilities of an animation control are severely limited and are subject to change. If you need a control to provide multimedia playback and recording capabilities for your application, you can use the MCIWnd control. For more information about the MCIWnd control, see the multimedia documentation.


Animation Control Creation

An animation control belongs to the ANIMATE_CLASS window class. You create an animation control by using the CreateWindow function or the Animate_Create macro. The macro positions the animation control in the upper-left corner of the parent window and, if the ACS_CENTER style is not specified, sets the width and height of the control based on the dimensions of a frame in the AVI clip. If ACS_CENTER is specified, Animate_Create sets the width and height of the control to zero. You can use the SetWindowPos function to set the position and size of the control.

If you create an animation control within a dialog box or from a dialog box resource, the control is automatically destroyed when the user closes the dialog box. If you create an animation control within a window, you must explicitly destroy the control.


Animation Control Messages

An application sends messages to an animation control to open, play, stop, and close the corresponding AVI clip. Each message has one or more macros that you can use instead of sending the message explicitly.

After creating an animation control, an application sends the ACM_OPEN message to open an AVI clip and load it into memory. The message specifies either the path of an .AVI file or the name of an AVI resource. The system loads the AVI resource from the module that created the animation control.

If the animation control has the ACS_AUTOPLAY style, the control begins playing the AVI clip immediately after the .AVI file or AVI resource is opened. Otherwise, an application can use the ACM_PLAY message to start the AVI clip. An application can stop the clip at any time by sending the ACM_STOP message. The last frame played remains displayed when the control finishes playing the AVI clip or when ACM_STOP is sent.

An animation control can send two notification messages, ACN_START and ACN_STOP, to its parent window. Most applications do not handle either notification.

To close the .AVI file or AVI resource and remove it from memory, an application can use the Animate_Close macro, which sends ACM_OPEN with the filename or resource name set to NULL.


Default Message Processing

This section describes the window messages handled by the window procedure for the ANIMATE_CLASS window class.

Message	Processing performed
WM_CLOSE	Frees the .AVI file or AVI resource associated with the animation control.
WM_DESTROY	Frees the .AVI file or AVI resource, frees an internal data structure, and then calls the DefWindowProc function.
WM_ERASEBKGND	Erases the window background using the current background color for static controls.
WM_NCCREATE	Allocates and initializes an internal data structure and then calls DefWindowProc.
WM_NCHITTEST	Returns the HTTRANSPARENT hit test value.
WM_PAINT	Draws an AVI frame in the animation control.
WM_SIZE	Checks if the control has the ACS_CENTER style. If the control does not, it calls DefWindowProc. Otherwise, it centers the animation in the control, invalidates the control, and then calls DefWindowProc.


Using Animation Controls

•	Creating an animation control

•	Controlling the AVI clip


Creating an Animation Control

The following function creates an animation control in a dialog box. The animation control is positioned below the specified control, and the dimensions of the animation control are based on the dimensions of a frame in the AVI clip.

// CreateAnimationCtrl - creates an animation control, positions it

//     below the specified control in a dialog box, and opens the AVI

//     clip for the animation control.

// Returns the handle to the animation control.

// hwndDlg - handle to the dialog box

// nIDCtl - identifier of the control below which the animation control

//     is to be positioned

//

// Constants

//     IDC_ANIMATE - identifier of the animation control

//     CX_FRAME, CY_FRAME - width and height of the frames

//         in the AVI clip

HWND CreateAnimationCtrl(HWND hwndDlg, int nIDCtl)

{

    HWND hwndAnim = NULL;

    RECT rc;

    POINT pt;

    // Create the animation control.

    hwndAnim = Animate_Create(hwndDlg, IDC_ANIMATE,

        WS_BORDER | WS_CHILD, g_hinst);

    // Get the screen coordinates of the specified control button.

    GetWindowRect(GetDlgItem(hwndDlg, nIDCtl), &rc);

    // Convert the coordinates of the lower-left corner to

    // client coordinates.

    pt.x = rc.left;

    pt.y = rc.bottom;

    ScreenToClient(hwndDlg, &pt);

    // Position the animation control below the Stop button.

    SetWindowPos(hwndAnim, 0, pt.x, pt.y + 20,

        CX_FRAME, CY_FRAME,

        SWP_NOZORDER | SWP_DRAWFRAME);

    // Open the AVI clip, and show the animation control.

    Animate_Open(hwndAnim, "SEARCH");

    ShowWindow(hwndAnim, SW_SHOW);

    return hwndAnim;

}


Controlling the AVI Clip

The following function uses the predefined macros to control the display of the AVI clip in an animation control.

// DoAnimation - plays, stops, or closes an animation control's

//     AVI clip, depending on the value of an action flag.

// hwndAnim - handle to an animation control

// nAction - flag that determines whether to play, stop, or close

//     the AVI clip

void DoAnimation(HWND hwndAnim, int nAction)

{

    switch (nAction) {

        case PLAYIT:

            // Play the clip continuously starting with the

            // first frame.

            Animate_Play(hwndAnim, 0, -1, -1);

            break;

        case STOPIT:

            Animate_Stop(hwndAnim);

            break;

        case CLOSEIT:

            Animate_Close(hwndAnim);

            break;

        default:

            break;

    }

    return;

}


Animation Control Reference

The following function messages, macros, and notification messages are associated with animation controls.


Animation Control Messages and Macros

An application sends messages to control the playing of an AVI clip in an animation control. Each message has a corresponding macro, which you can use instead of sending the message explicitly. Some messages have related macros, which are a more specialized form of the corresponding macro.

ACM_OPEN
ACM_PLAY
ACM_STOP
Animate_Create


Animation Control Notification Messages

An animation control sends notifications, in the form of WM_COMMAND messages, to its parent window to notify it about events.

ACN_START
ACN_STOP


Animation Control Styles

The following window styles are used with animation controls.

ACS_AUTOPLAY	Starts playing the animation as soon as the animation clip is opened.
ACS_CENTER	Centers the animation in the animation control's window.
ACS_TRANSPARENT	Draws the animation using a transparent background rather than the background color specified in the animation clip.


Common Controls

Common controls are a set of windows that are supported by the common control library, which is a dynamic-link library (DLL) included with the Microsoft® Windows® operating system. Like other control windows, a common control is a child window that an application uses in conjunction with another window to perform input and output (I/O) tasks.


About Common Controls

Most common controls belong to a window class defined in the common control DLL. The window class and the corresponding window procedure define the properties, appearance, and behavior of the control. To ensure that the common control DLL is loaded, include the InitCommonControls function in your application. You create a common control by specifying the name of the window class when calling the CreateWindowEx function or by specifying the appropriate class name in a dialog box template.

For more detailed information about common controls, see the following topics.

•	Animation Controls

•	Drag List Boxes

•	Header Controls

•	Hot-Key Controls

•	Image Lists

•	List View Controls

•	Progress Bars

•	Property Sheets

•	Rich Edit Controls

•	Status Windows

•	Tab Controls

•	Toolbars

•	Tooltip Controls

•	Trackbars

•	Tree View Controls

•	Up-Down Controls


About Common Control Styles

Each type of common control has a set of control styles that you can use to vary the appearance and behavior of the control. The common control library also includes a set of control styles that apply to two or more types of common controls. The common control styles are described in the following topics.


About Common Control Messages

Because common controls are windows, an application can manipulate them by using messages, such as WM_GETFONT or WM_SETTEXT. In addition, the window class of each common control supports a set of control-specific messages that an application can use to manipulate the control. An application can use any of the message sending or posting functions to pass messages to the control. In addition, some common controls have a set of macros that an application can use instead of the sending or posting functions. The macros are typically easier to use than the functions.

When a change is made to the system color settings, Windows sends a WM_SYSCOLORCHANGE message to all top level windows. Your top level window must forward the WM_SYSCOLORCHANGE message to its common controls; otherwise, the controls will not be notified of the color change. This ensures that the colors used by your common controls are consistent with those used by other user interface objects. For example, a toolbar control uses the "3D Objects" color to draw its buttons. If the user changes the 3D Objects color but the WM_SYSCOLORCHANGE message is not forwarded to the toolbar, the toolbar buttons will remain in their original color while the color of other buttons in the system changes.


About Common Control Notification Messages

Common controls are child windows that send notification messages to the parent window when events, such as input from the user, occur in the control. The application relies on these notification messages to determine what action the user wants it to take. Except for trackbars, which use WM_HSCROLL message, common controls send notification messages as WM_NOTIFY messages. The lParam parameter of WM_NOTIFY is either the address of an NMHDR structure or the address of a larger structure that includes NMHDR as its first member. The structure contains the notification code and identifies the common control that sent the notification message. The meaning of the remaining structure members, if any, varies depending on the notification code.

Each type of common control has a corresponding set of notification codes. The common control library also provides notification codes that can be sent by more than one type of common control. Values for common notification values are described in the following topics.


Common Control Reference

The following functions, messages, notification messages, macros, and structures apply to all common controls.

Notification Processing

FORWARD_WM_NOTIFY
HANDLE_WM_NOTIFY
NMHDR

Mouse Click Notifications

NM_CLICK
NM_DBLCLK
NM_RCLICK
NM_RDBLCLK

Operation-Related Notifications

NM_OUTOFMEMORY

Focus Notifications

NM_KILLFOCUS
NM_RETURN
NM_SETFOCUS

Miscellaneous

GetEffectiveClientRect
INDEXTOSTATEIMAGEMASK
InitCommonControls
ShowHideMenuCtl


Common Control Functions

The following functions are used with common controls.

GetEffectiveClientRect
InitCommonControls
ShowHideMenuCtl


Common Control Message

Common controls send the following message to notify the parent window of events that affect the control.

WM_NOTIFY


Common Control Notification Messages

Common controls send notification messages to the parent window to inform it about events. The following notifications are used with common controls.

NM_CLICK
NM_DBLCLK
NM_KILLFOCUS
NM_OUTOFMEMORY
NM_RCLICK
NM_RDBLCLK
NM_RETURN
NM_SETFOCUS


Common Control Macros

The following macros are used with common controls.

FORWARD_WM_NOTIFY
HANDLE_WM_NOTIFY
INDEXTOSTATEIMAGEMASK


Common Control Structure

The following structure is used with common controls.

NMHDR


Common Control Constants

The following window classes and control styles are used with common controls.


Common Control Window Classes

The following window class names are provided by the common control library.

Class name	Description
ANIMATE_CLASS	Creates animation controls. These controls silently display an Audio Video Interleaved (AVI) clip.
HOTKEY_CLASS	Creates hot-key controls. These controls make it easy for the user to define hot keys.
PROGRESS_CLASS	Creates progress bars. These controls indicate the progress of a lengthy operation.
STATUSCLASSNAME	Creates status windows. These controls display status information in a horizontal window.
TOOLBARCLASSNAME	Creates toolbars. These controls contain buttons that carry out menu commands.
TOOLTIPS_CLASS	Creates tooltip controls. These controls display a small pop-up window containing a line of text that describes the purpose of a tool in an application.
TRACKBAR_CLASS	Creates trackbars. These controls let the user select from a range of values by moving a slider.
UPDOWN_CLASS	Creates up-down controls. These controls combine a pair of arrows with an edit control. Clicking the arrows increments or decrements the value in the edit control.
WC_HEADER	Creates header controls. These controls display headings at the top of columns of information and let the user sort the information by clicking the headings.
WC_LISTVIEW	Creates list-view controls. These controls display a collection of items, each consisting of an icon and a label, and provide several ways to arrange the items.
WC_TABCONTROL	Creates tab controls. These controls define multiple pages for the same area of a window or dialog box. Each page consists of a set of information or a group of controls that an application displays when the user selects the corresponding tab.
WC_TREEVIEW	Creates tree-view controls. These controls display a hierarchical list of items. Each item consists of a label and an optional bitmap.


Common Control Styles

Following are the common control styles. Except where noted, these styles apply to header controls, toolbar controls, and status windows.

Common control style	Description
CCS_ADJUSTABLE	Enables a toolbar's built-in customization features, which allow the user to drag a button to a new position or to remove a button by dragging it off the toolbar. In addition, the user can double-click the toolbar to display the Customize Toolbar dialog box, allowing the user to add, delete, and rearrange toolbar buttons.
CCS_BOTTOM	Causes the control to position itself at the bottom of the parent window's client area and sets the width to be the same as the parent window's width. Status windows have this style by default.
CCS_NODIVIDER	Prevents a two-pixel highlight from being drawn at the top of the control.
CCS_NOHILITE	Prevents a one-pixel highlight from being drawn at the top of the control.
CCS_NOMOVEY	Causes the control to resize and move itself horizontally, but not vertically, in response to a WM_SIZE message. If CCS_NORESIZE is used, this style does not apply. Header windows have this style by default.
CCS_NOPARENTALIGN	Prevents the control from automatically moving to the top or bottom of the parent window. Instead, the control keeps its position within the parent window despite changes to the size of the parent. If CCS_TOP or CCS_BOTTOM is also used, the height is adjusted to the default, but the position and width remain unchanged.
CCS_NORESIZE	Prevents the control from using the default width and height when setting its initial size or a new size. Instead, the control uses the width and height specified in the request for creation or sizing.
CCS_TOP	Causes the control to position itself at the top of the parent window's client area and sets the width to be the same as the parent window's width. Toolbars have this style by default.


Drag List Boxes

A drag list box is a special type of list box that enables the user to drag items from one position to another. An application can use a drag list box to display strings in a particular sequence and allow the user to change the sequence.


About Drag List Boxes

To create a drag list box, you first create a standard list box and then call the MakeDragList function. To convert a list box in a dialog box to a drag list box, you can call MakeDragList when the WM_INITDIALOG message is processed.

Drag list boxes have the same window styles and process the same messages as standard list boxes.


About Drag List Box Messages

A drag list box notifies its parent window of drag events by sending it a drag list message. The parent window must process the drag list message.

The drag list box registers the drag list message when the MakeDragList function is called. To get the message identifer (numeric value) of the drag list message, you must call the RegisterWindowMessage function, specifying the DRAGLISTMSGSTRING value.

The wParam parameter of the drag list message is the control identifier for the drag list box. The lParam parameter is the pointer to a DRAGLISTINFO structure, which contains the notification code for the drag event and other information. The return value of the message depends on the notification.


About Drag List Box Notification Messages

A drag list box sends its parent window notification messages in the form of drag list messages. The specific notification, which is identified by the uNotification member of the specified DRAGLISTINFO structure, can be DL_BEGINDRAG, DL_DRAGGING, DL_CANCELDRAG, or DL_DROPPED.

The DL_BEGINDRAG notification message is sent when the user clicks the left mouse button with the cursor on a list item. The parent window can return TRUE to begin the drag operation or FALSE to disallow dragging. In this way, the parent window can enable dragging for some list items and disable it for others. You can determine which list item is at the specified location by using the LBItemFromPt function.

If dragging is in effect, the DL_DRAGGING notification message is sent whenever the mouse is moved, or at regular intervals if the mouse is not being moved. The parent window should determine the list item under the cursor by using LBItemFromPt and then draw the insert icon by using the DrawInsert function. By specifying TRUE for the bAutoScroll parameter of LBItemFromPt, you can cause the list box to scroll by one line if the cursor is above or below its client area. The value you return for this notification specifies the type of mouse cursor that the drag list box should set.

The DL_CANCELDRAG notification message is sent if the user cancels a drag operation by clicking the right mouse button or pressing the ESC key. The DL_DROPPED notification message is sent if the user completes a drag operation by releasing the left mouse button, even if the cursor is not over a list item. The drag list box releases the mouse capture before sending either notification. The return value of these two notifications is ignored.


Drag List Box Reference

The following functions, notification messages, and structures are associated with drag list boxes.


Drag List Box Functions

The following functions are used with drag list boxes.

DrawInsert
LBItemFromPt
MakeDragList


Drag List Box Notification Messages

A drag list box sends notification messages to its parent window by using a registered window message, which is called a drag list message. There are the following drag list notification messages.

DL_BEGINDRAG
DL_CANCELDRAG
DL_DRAGGING
DL_DROPPED


Drag List Box Structure

The following structure is used with drag list boxes.

DRAGLISTINFO


Header Controls

A header control is a window that is usually positioned above columns of text or numbers. It contains a title for each column, and it can be divided into parts. The user can drag the dividers that separate the parts to set the width of each column. The following illustration shows a header control that has labeled columns giving detailed information about files in a directory.


About Header Controls

You can create a header control by using the CreateWindowEx function, specifying the WC_HEADER window class. This window class is registered when the common control dynamic-link library (DLL) is loaded. To ensure that this DLL is loaded, use the InitCommonControls function. After you create a header control, you can divide it into parts, set the text in each part, and control the appearance of the window by using header window messages.


About Header Control Styles

Header controls have a number of styles that determine the control's appearance and behavior. You set the initial styles when you create the header control. To retrieve and change the styles after creating the control, use the GetWindowLong and SetWindowLong functions.

A header control can be divided into two or more parts called header items. If a header control has the HDS_BUTTONS style, each item in the control looks and behaves like a push button. This style is useful if an application carries out a task when the user clicks an item in the header control. For example, an application could sort information in the columns differently depending on which item the user clicks.

The HDS_HORZ style creates a header control with a horizontal orientation.


Header Control Size and Position

Typically, you must set the size and position of a header control to fit within the boundaries of a particular rectangle, such as the client area of a window. By using the HDM_LAYOUT message, you can retrieve the appropriate size and position values from the header control.

When sending HDM_LAYOUT, you specify the address of an HD_LAYOUT structure that contains the coordinates of the rectangle that the header control is to occupy and provides a pointer to a WINDOWPOS structure. The control fills the WINDOWPOS structure with size and position values appropriate for positioning the control along the top of the specified rectangle. The height value is the sum of the heights of the control's horizontal borders and the average height of characters in the font currently selected into the control's device context.

If you want to use HDM_LAYOUT to set the initial size and position of a header control, you should set the initial visibility state of the control so that it is hidden. After sending HDM_LAYOUT to retrieve the size and position values, you can use the SetWindowPos function to set the new size, position, and visibility state.


Items

Each item in a header control can have a string, a bitmapped image, and an application-defined 32-bit value associated with it. The string and bitmap are displayed within the boundaries of the header item. If an item contains both a string and an image, the image is displayed above the string. If the string and image overlap, the string overwrites the overlapping portion of the image.

You add an item to a header control by sending the HDM_INSERTITEM message to the control. The message includes the address of an HD_ITEM structure, which defines the properties of the header item, including its string, bitmap, initial size, and application-defined value. The structure also specifies formatting flags that tell the control whether to center, left-align, or right-align the string or bitmap in the item's rectangle.

HDM_INSERTITEM returns the index of the newly added item. You can use the index in other messages to set properties or retrieve information about the item. You can delete an item by using the HDM_DELETEITEM message, specifying the index of the item to delete.

You can use the HDM_SETITEM message to set the properties of an existing header item and the HDM_GETITEM message to retrieve the current properties of an item. To retrieve a count of the items in a header control, use the HDM_GETITEMCOUNT message.

You can use the HBT_SPRING value to give a header item a "springy" quality. Although an item has a minimum width, it can grow wider if there is extra room in the owner window. A header control can have multiple springy items; the extra room in the owner window is distributed among the springy items.

To make an item springy, send the WM_SETTEXT message to the header control. In the wParam parameter, use the logical OR operator to combine the index of the header item with the HBT_SPRING value.


Owner-Drawn Header Controls

You can define individual items of a header control to be owner-drawn items. Using this technique gives you more control than you would otherwise have over the appearance of a header item.

You can use the HDM_INSERTITEM message to insert a new owner-drawn item into a header control or the HDM_SETITEM message to change an existing item to an owner-drawn item. Both messages include the address of an HD_ITEM structure, which should have the fmt member set to the HDF_OWNERDRAW value.

When a header control must draw an owner-drawn item, it sends the WM_DRAWITEM message to the parent window. The wParam parameter of the message is the child window identifier of the header control, and the lParam parameter is a pointer to a DRAWITEMSTRUCT structure. The parent window uses the information in the structure to draw the item. For an owner-drawn item in a header control, the DRAWITEMSTRUCT structure contains the following information.

Member	Description
CtlType	ODT_HEADER owner-drawn control type.
CtlID	Child-window identifier of the header control.
itemID	Index of the item to be drawn.
itemAction	ODA_DRAWENTIRE drawing-action flag.
itemState	ODS_SELECTED drawing-action flag if the cursor is on the item and the mouse button is down. Otherwise, this member is zero.
hwndItem	Handle of the header control.
hDC	Handle of the device context of the header control.
rcItem	Coordinates of the header item to be drawn. The coordinates are relative to the upper left corner of the header control.
itemData	Application-defined 32-bit value associated with the item.


About Header Control Notification Messages

A header control sends notification messages to its parent window when the user clicks or double-clicks an item, when the user drags an item divider, and when the attributes of an item change. The parent window receives the notifications in the form of WM_NOTIFY messages. The following notifications are used with header controls.

Notification	Description
HDN_BEGINTRACK	Signals the start of divider dragging.
HDN_DIVIDERDBLCLICK	Indicates that the user double-clicked a divider.
HDN_ENDTRACK	Signals the end of divider dragging.
HDN_ITEMCHANGED	Indicates a change in the attributes of an item.
HDN_ITEMCHANGING	Indicates that the attributes of an item are about to change.
HDN_ITEMCLICK	Indicates that the user clicked an item.
HDN_ITEMDBLCLICK	Indicates that the user double-clicked an item.
HDN_TRACK	Indicates that the user dragged a divider.


Default Header Control Message Processing

This section describes the window messages handled by the window procedure for the WC_HEADER window class.

Message	Processing performed
WM_CREATE	Initializes the header control.
WM_DESTROY	Frees resources allocated for the header control.
WM_ERASEBKGND	Erases the background of the header control using the current background color for the control.
WM_GETDLGCODE	Returns a combination of the DLGC_WANTTAB and DLGC_WANTARROWS values.
WM_GETFONT	Returns the handle of the current font, which is used by the header control to draw its text.
WM_LBUTTONDBLCLK	Captures mouse input. If the mouse cursor is on a divider, the control sends a HDN_BEGINTRACK notification message and begins tracking mouse movement. If the cursor is on a header item, the control redraws the item in the style that indicates the item is pressed.
WM_LBUTTONDOWN	Same as the WM_LBUTTONDBLCLK message.
WM_LBUTTONUP	Releases the mouse capture. If the control was tracking mouse movement, it sends the HDN_ENDTRACK notification message and redraws the header control. Otherwise, the control sends the HDN_ITEMCLICK notification message and redraws the header item that was clicked.
WM_MOUSEMOVE	If a divider is being dragged, the control sends the HDN_TRACK notification message and redraws itself. If the left mouse button is down and the cursor is on an item, the control redraws the item in the style that indicates the item is pressed.
WM_NCCREATE	Allocates and initializes an internal data structure.
WM_NCDESTROY	Frees resources allocated by the header control.
WM_PAINT	Paints the invalid region of the header control.
WM_SETCURSOR	Sets the cursor shape, depending on whether the cursor is on a divider or in a header item.
WM_SETFONT	Selects a new font handle into the device context for the header control.


Using Header Controls

•	Creating a header control

•	Adding an item to a header control


Creating a Header Control

The following example creates a header control and positions it along the top of the parent window's client area. The control is initially hidden. The example uses the HDM_LAYOUT message to determine the appropriate size and position of the control given the bounding rectangle of the parent window. Then the example sets the size and position of the control and makes it visible.

// DoCreateHeader - creates a header control that is positioned along

//     the top of the parent window's client area.

// Returns the handle of the header control.

// hwndParent - handle of the parent window

//

// Global variable

//    g_hinst - handle of the application instance

extern HINSTANCE g_hinst;

HWND DoCreateHeader(HWND hwndParent)

{

        HWND hwndHeader;

        RECT rcParent;

        HD_LAYOUT hdl;

        WINDOWPOS wp;

        // Ensure that the common control DLL is loaded, and then create

        // the header control.

        InitCommonControls();

        if ((hwndHeader = CreateWindowEx(0, WC_HEADER, (LPCTSTR) NULL,

                WS_CHILD | WS_BORDER | HDS_BUTTONS | HDS_HORZ,

                0, 0, 0, 0, hwndParent, (HMENU) ID_HEADER, g_hinst,

                (LPVOID) NULL)) == NULL)

            return (HWND) NULL;

        // Retrieve the bounding rectangle of the parent window's

        // client area, and then request size and position values

        // from the header control.

        GetClientRect(hwndParent, &rcParent);

        hdl.prc = &rcParent;

        hdl.pwpos = &wp;

        if (!SendMessage(hwndHeader, HDM_LAYOUT, 0, (LPARAM) &hdl))

            return (HWND) NULL;

        // Set the size, position, and visibility of the header control.

        SetWindowPos(hwndHeader, wp.hwndInsertAfter, wp.x, wp.y,

            wp.cx, wp.cy, wp.flags | SWP_SHOWWINDOW);

        return hwndHeader;

}


Adding an Item to a Header Control

The following example demonstrates how to use the HDM_INSERTITEM message and the HD_ITEM structure to add an item to a header control. The new item consists of a string that is left-justified within the item rectangle.

// DoInsertItem - inserts items into a header control.

// Returns the index of the newly added item.

// hwndHeader - handle of the header control

// iInsertAfter - index of the previous item

// nWidth - width of the new item

// lpsz - address of the item string

int DoInsertItem(HWND hwndHeader, int iInsertAfter,

    int nWidth, LPSTR lpsz)

{

    HD_ITEM hdi;

    int index;

    hdi.mask = HDI_TEXT | HDI_FORMAT | HDI_WIDTH;

    hdi.pszText = lpsz;

    hdi.cxy = nWidth;

    hdi.cchTextMax = lstrlen(hdi.pszText);

    hdi.fmt = HDF_LEFT | HDF_STRING;

    index = SendMessage(hwndHeader, HDM_INSERTITEM,

        (WPARAM) iInsertAfter, (LPARAM) &hdi);

    return index;

}


Header Control Reference

The following messages, notification messages, and structures are associated with header controls. These elements can be grouped as follows.

Size and Position

HDM_LAYOUT
HD_LAYOUT

Inserting and Deleting Items

HDM_DELETEITEM
HDM_INSERTITEM

Item Attributes

HDM_SETITEM
HDN_ITEMCHANGED
HDN_ITEMCHANGING
HDN_TRACK

Item Information

HDM_GETITEM
HDM_GETITEMCOUNT
HDN_ITEMCLICK
HDN_ITEMDBLCLICK
HD_ITEM
HD_NOTIFY

Divider Tracking

HDN_BEGINTRACK
HDN_DIVIDERDBLCLICK
HDN_ENDTRACK

Hit Testing

HD_HITTESTINFO
HDM_HITTEST


Header Control Messages

An application sends messages to add items and to control the appearance and behavior of a header control. Each message has a corresponding macro, which you can use instead of sending the message explicitly. There are the following header control messages.

HDM_DELETEITEM
HDM_GETITEM
HDM_GETITEMCOUNT
HDM_HITTEST
HDM_INSERTITEM


Header Control Notification Messages

A header control sends notification messages, in the form of WM_NOTIFY messages, to its parent window to notify it about events. The following notification messages are used with header controls.

HDN_BEGINTRACK
HDN_DIVIDERDBLCLICK
HDN_ENDTRACK
HDN_ITEMCHANGED
HDN_ITEMCHANGING
HDN_ITEMCLICK
HDN_ITEMDBLCLICK
HDN_TRACK


Header Control Structures

The following structures are used with header controls.

HD_HITTESTINFO
HD_ITEM
HD_LAYOUT
HD_NOTIFY


Header Control Styles

The following window styles are used with header controls.

HDS_BUTTONS	Header items behave like buttons.
HDS_HORZ	The header control is horizontal.


Hot-Key Controls

A hot-key control is a window that enables the user to enter a combination of keystrokes to be used as a hot key. A hot key is a key combination that the user can press to perform an action quickly. (For example, a user can create a hot key that activates a given window and brings it to the top of the Z order.) The hot-key control displays the user's choices and ensures that the user selects a valid key combination.


About Hot-Key Controls

When the user enters a key combination to be used as a hot key, the names of the keys appear in the hot-key control. A key combination can consist of a modifier key (such as CTRL, ALT, or SHIFT) and an accompanying key (such as a character key, an arrow key, a function key, and so on).

After the user has chosen a key combination, the application retrieves the key combination from the hot-key control and uses it to set up a hot key in the system. The information retrieved from the hot-key control includes a flag indicating the modifier key and the virtual-key code of the accompanying key.

The application can use the information provided by a hot-key control to set up a global hot key or a thread-specific hot key. A global hot key is associated with a particular window; it allows the user to activate the window from any part of the system. An application sets a global hot key by using the WM_SETHOTKEY message. Whenever the user uses a global hot key, the window specified in WM_SETHOTKEY receives a WM_SYSCOMMAND message that specifies the SC_HOTKEY value. This message activates the window that receives it. The hot key remains valid until the application that called WM_SETHOTKEY exits.

A thread-specific hot key generates a WM_HOTKEY message that is posted to the beginning of a particular thread so that it is removed by the next iteration of the message loop. An application sets a thread-specific hot key by using the RegisterHotKey function.


Hot-Key Control Creation

You create a hot-key control by using the CreateWindowEx function, specifying the HOTKEY_CLASS window class. When the function returns a handle to the hot-key control, an application typically sets some rules about invalid hot-key combinations and provides perhaps a default key combination. If an application does not set any rules, the user can choose any key or key combination as a hot key. Most applications, however, do not allow the user to use a common key (for example, the letter A) as a hot key.


About Hot-Key Control Messages

After creating a hot-key control, an application interacts with it by using three messages: HKM_SETRULES, HKM_SETHOTKEY, and HKM_GETHOTKEY.

An application can send the HKM_SETRULES message to specify a set of CTRL, ALT, and SHIFT key combinations that are considered invalid hot keys. If the application specifies an invalid key combination, it should also specify a default modifier combination to use when the user selects the invalid combination. When the user enters the invalid combination, the system performs a logical-OR operation on the invalid combination entered by the user and the default combination. The result is considered a valid combination; it is converted to a string and displayed in the control.

The HKM_SETHOTKEY message allows an application to set the hot key combination for a hot-key control. This message is also typically used when the hot-key control is created.

Applications use the HKM_GETHOTKEY message to retrieve the virtual-key code and modifier flags of the hot key chosen by the user of a hot-key control.


Default Hot-Key Message Processing

This section describes the window messages handled by the window procedure for the predefined HOTKEY_CLASS window class used with hot-key controls.

Message	Processing performed
WM_CHAR	Retrieves the virtual-key code.
WM_CREATE	Initializes the hot-key control, sets no hot-key rules, and uses the system font.
WM_ERASEBKGND	Hides the caret, calls the DefWindowProc function, and shows the caret again.
WM_GETDLGCODE	Returns a combination of the DLGC_WANTCHARS and DLGC_WANTARROWS values.
WM_GETFONT	Retrieves the font.
WM_KEYDOWN	Calls the DefWindowProc function if the key is ENTER, TAB, SPACE BAR, DEL, ESC, or BACKSPACE. If the key is SHIFT, CTRL, or ALT, it checks whether the combination is valid and, if it is, sets the hot key using the combination. Other keys are set as hot keys without their validity being checked first.
WM_KEYUP	Retrieves the virtual-key code.
WM_KILLFOCUS	Destroys the caret.
WM_LBUTTONDOWN	Sets the focus to the window.
WM_NCCREATE	Sets the WS_EX_CLIENTEDGE window style.
WM_PAINT	Paints the hot-key control.
WM_SETFOCUS	Creates and shows the caret.
WM_SETFONT	Sets the font.
WM_SYSCHAR	Retrieves the virtual-key code.
WM_SYSKEYDOWN	Calls the DefWindowProc function if the key is ENTER, TAB, SPACE BAR, DEL, ESC, or BACKSPACE. If the key is SHIFT, CTRL, or ALT, it checks whether the combination is valid and, if it is, sets the hot key using the combination. Other keys are set as hot keys without their validity being checked first.
WM_SYSKEYUP	Retrieves the virtual-key code.


Using Hot-Key Controls

•	Creating a hot-key control

•	Retrieving and setting a hot key


Creating a Hot-Key Control

The following function creates a hot-key control, uses the HKM_SETRULES and HKM_SETHOTKEY messages to initialize it, and returns a handle to the control. This hot-key control does not allow the user to choose a hot key that is a single unmodified key, nor does it permit the user to choose only SHIFT and a key. (These rules effectively prevent the user from choosing a hot key that might be accidentally entered while typing text.)

// InitializeHotkey - creates a hot-key control and sets rules

//    and default settings for it.

// Returns the handle of the hot-key control.

// hwndDlg - handle of the parent window (dialog box)

//

// Global variable

//     g_hinst - handle of the application instance

extern HINSTANCE g_hinst;

HWND WINAPI InitializeHotkey(HWND hwndDlg)

{

    // Ensure that the common control DLL is loaded.

    InitCommonControls();

    hwndHot = CreateWindowEx(

        0,                             // no extended styles

        HOTKEY_CLASS,                  // class name

        "",                            // no title (caption)

        WS_CHILD | WS_VISIBLE,         // style

        10, 10,                        // position

        200, 20,                       // size

        hwndDlg,                       // parent window

        NULL,                          // uses class menu

        g_hinst,                       // instance

        NULL                           // no WM_CREATE parameter

        );

    SetFocus(hwndHot);

    // Set rules for invalid key combinations. If the user

    // does not supply a modifier key, use ALT as a modifier.

    // If the user supplies SHIFT as a modifier key, use

    // SHIFT + ALT instead.

    SendMessage(hwndHot, HKM_SETRULES,

        (WPARAM) HKCOMB_NONE | HKCOMB_S, // invalid key combinations

        MAKELPARAM(HOTKEYF_ALT, 0));     // add ALT to invalid entries

    // Set CTRL + ALT + A as the default hot key for this window.

    // 0x41 is the virtual-key code for 'A'.

    SendMessage(hwndHot, HKM_SETHOTKEY,

        MAKEWORD(0x41, HOTKEYF_CONTROL | HOTKEYF_ALT), 0);

    return hwndHot;

}


Retrieving and Setting a Hot Key

After the user has chosen a hot key, an application should retrieve the hot key from the hot-key control by using the HKM_GETHOTKEY message. This message retrieves a 16-bit value that contains the virtual-key code and modifier keys describing the hot key.

The following function retrieves a key combination from a hot-key control and then uses the WM_SETHOTKEY message to set a global hot key. Note that you cannot set a global hot key for a window that has the WS_CHILD window style.

// ProcessHotkey - retrieves the hot key from the hot-key control and

//     sets it as the hot key for the application's main window.

// Returns TRUE if successful or FALSE otherwise.

// hwndHot - handle of the hot-key control

// hwndMain - handle of the main window

BOOL WINAPI ProcessHotkey(HWND hwndHot, HWND hwndMain)

{

    WORD wHotkey;

    UINT iSetResult;

    // Retrieve the hot key (virtual-key code and modifiers).

    wHotkey = SendMessage(hwndHot, HKM_GETHOTKEY, 0, 0);

    // Use the result as wParam for WM_SETHOTKEY.

    iSetResult = SendMessage(hwndMain, WM_SETHOTKEY, wHotkey, 0);

    switch (iSetResult) {

        case 2:            // WM_SETHOTKEY succeeded

            MessageBox(NULL, "Hot key previously assigned",

                "Okay", MB_OK);

            return TRUE;

        case 1:            // WM_SETHOTKEY succeeded

            return TRUE;

        case 0:

            MessageBox(NULL, "Invalid window for hot key",

                "Error", MB_OK);

            return FALSE;

        case -1:

            MessageBox(NULL, "Invalid hot key",

                "Error", MB_OK);

            return FALSE;

        default:

            MessageBox(NULL, "Unknown error", "Error", MB_OK);

            return FALSE;

    }

}


Hot-Key Control Messages

The following messages are associated with hot-key controls.

HKM_GETHOTKEY
HKM_SETHOTKEY
HKM_SETRULES


Image Lists

An image list is a collection of same-sized images, each of which can be referred to by its index. Image lists are used to efficiently manage large sets of icons or bitmaps. All images in an image list are contained in a single, wide bitmap in screen device format. An image list may also include a monochrome bitmap that contains masks used to draw images transparently (icon style).


About Image Lists

The Microsoft® Win32® application programming interface (API) provides image list functions, which enable you to draw images, create and destroy image lists, add and remove images, replace images, merge images, and drag images.

To use the image list functions, you must include the common control header file in your source code files and link with the common control export library. In addition, before calling any image list function, you must use the InitCommonControls function to ensure that the common control dynamic-link library (DLL) is loaded.


Types

There are two types of image lists: nonmasked and masked. A nonmasked image list consists of a color bitmap that contains one or more images. A masked image list consists of two bitmaps of equal size. The first is a color bitmap that contains the images, and the second is a monochrome bitmap that contains a series of masks — one for each image in the first bitmap.

When a nonmasked image is drawn, it is simply copied into the target device context; that is, it is drawn over the existing background color of the device context. When a masked image is drawn, the bits of the image are combined with the bits of the mask, typically producing transparent areas in the bitmap where the background color of the target device context shows through. There are several drawing styles that you can specify when drawing a masked image. For example, you can specify that the image be dithered to indicate a selected object. For more information about drawing images, see Drawing Images.


Image List Creation

You create an image list by calling the ImageList_Create function. The parameters include the type of image list to create, the dimensions of each image, and the number of images you intend to add to the list. For a nonmasked image list, the function creates a single bitmap large enough to hold the specified number of images of the given dimensions. Then it creates a screen-compatible device context and selects the bitmap into it. For a masked image list, the function creates two bitmaps and two screen-compatible device contexts. It selects the image bitmap into one device context and the mask bitmap into the other.

The initial size of an image list is determined by the size values you specify in ImageList_Create. If you attempt to add more images than you initially specified, the image list automatically grows to accommodate the additional images. In ImageList_Create, you specify the amount of images by which the image list can grow.

If ImageList_Create succeeds, it returns a handle of the HIMAGELIST type. You use this handle in other image list functions to access the image list and manage the images. You can add and remove images, copy images from one image list to another, and merge images from two different image lists. When you no longer need an image list, you can destroy it by specifying its handle in a call to the ImageList_Destroy function.


Adding and Removing Images

You can add bitmapped images, icons, or cursors to an image list. You add bitmapped images by specifying the handles of two bitmaps in a call to the ImageList_Add function. The first bitmap contains one or more images to add to the image bitmap, and the second bitmap contains the masks to add to the mask bitmap. For nonmasked image lists, the second bitmap handle is ignored; it can be set to NULL.

The ImageList_AddMasked function also adds bitmapped images to a masked image list. This function is similar to ImageList_Add, except that you do not specify a mask bitmap. Instead, you specify a color that the system combines with the image bitmap to automatically generate the masks. Each pixel of the specified color in the image bitmap is changed to black, and the corresponding bit in the mask is set to one. As a result, any pixel in the image that matches the specified color is transparent when the image is drawn.

The ImageList_AddIcon function adds an icon or cursor to an image list. If the image list is masked, ImageList_AddIcon adds the mask provided with the icon or cursor to the mask bitmap. If the image list is nonmasked, the mask for the icon or cursor is not used when drawing the image.

You can create an icon based on an image and mask in an image list by using the ImageList_GetIcon function. The function returns the handle of the new icon.

ImageList_Add, ImageList_AddMasked, and ImageList_AddIcon assign an index to each image as it is added to an image list. The indexes are zero-based; that is, the first image in the list has an index of zero, the next has an index of one, and so on. After adding a single image, the functions return the index of the image. When more than one image is added at a time, the functions return the index of the first image.

The ImageList_Remove function removes an image from an image list.


Replacing and Merging Images

The ImageList_Replace and ImageList_ReplaceIcon functions replace an image in an image list with a new image. ImageList_Replace replaces an image with a bitmapped image and mask, and ImageList_ReplaceIcon replaces an image with an icon or cursor.

The ImageList_Merge function merges two images, storing the new image in a new image list. The new image is created by drawing the second image transparently over the first. The mask for the new image is the result of performing a logical OR operation on the bits of the masks for the two existing images.


Drawing Images

To draw an image, you use the ImageList_Draw or ImageList_DrawEx function. You specify the handle of an image list, the index of the image to draw, the handle of the destination device context, a location within the device context, and one or more drawing styles.

When you specify the ILD_TRANSPARENT style, ImageList_Draw or ImageList_DrawEx uses a two-step process to draw a masked image. First, it performs a logical AND operation on the bits of the image and the bits of the mask. Then it performs a logical XOR operation on the results of the first operation and the background bits of the destination device context. This process creates transparent areas in the resulting image; that is, each white bit in the mask causes the corresponding bit in the resulting image to be transparent.

Before drawing a masked image on a solid color background, you should use the ImageList_SetBkColor function to set the background color of the image list to the same color as the destination. Setting the color eliminates the need to create transparent areas in the image and enables ImageList_Draw or ImageList_DrawEx to simply copy the image to the destination device context, resulting in a significant increase in performance. To draw the image, specify the ILD_NORMAL style in a call to ImageList_Draw or ImageList_DrawEx.

You can set the background color for a masked image list at any time so that it draws correctly on any solid background. Setting the background color to CLR_NONE causes images to be drawn transparently by default. To retrieve the background color of an image list, use the ImageList_GetBkColor function.

The ILD_BLEND25 and ILD_BLEND50 styles dither the image with the system highlight color. These styles are useful if you use a masked image to represent an object that the user can select. For example, you can use the ILD_BLEND50 style to draw the image when the user selects it.

A nonmasked image is copied to the destination device context using the SRCCOPY raster operation. The colors in the image appear the same regardless of the background color of the device context. The drawing styles specified in ImageList_Draw or ImageList_DrawEx also have no effect on the appearance of a nonmasked image.


Overlay Mask

Every image list includes a list of images to use as overlay masks. An overlay mask is an image drawn transparently over another image. Any image can be used as an overlay mask. You can specify up to four overlay masks per image list.

You add the index of an image to the list of overlay masks by using the ImageList_SetOverlayImage function, specifying the handle of the image list, the index of an image, and the index of an overlay mask. Note that the indices for the overlay masks are one-based rather than zero-based.

You draw an overlay mask over an image using a single call to the ImageList_Draw or ImageList_DrawEx function. The parameters include the index of the image to draw and the index of an overlay mask. You must use the INDEXTOOVERLAYMASK macro to specify the index of the overlay mask.


Dragging Images

The Win32 API includes functions for dragging an image on the screen. The dragging functions move an image smoothly, in color, and without any flashing of the cursor. Both masked and unmasked images can be dragged.

The ImageList_BeginDrag function begins a drag operation. The parameters include the handle of the image list, the index of the image to drag, and the location of the hot spot within the image. The hot spot is a single pixel that the dragging functions recognize as the exact screen location of the image. Typically, an application sets the hot spot so that it coincides with the hot spot of the mouse cursor. The ImageList_DragMove function moves the image to a new location.

The ImageList_DragEnter function sets the initial position of the drag image within a window and draws the image at the position. The parameters include the handle of the window in which to draw the image and the coordinates of the initial position within the window. The coordinates are relative to the window's upper-left corner, not the client area. The same is true for all of the image dragging functions that take coordinates as parameters. This means you must compensate for the widths of window elements, such as the border, title bar, and menu bar, when specifying the coordinates. If you specify a NULL window handle when calling ImageList_DragEnter, the dragging functions draw the image in the device context associated with the desktop window, and the coordinates are relative to the upper-left corner of the screen.

ImageList_DragEnter locks all other updates to the given window during the drag operation. If you need to do any drawing during a drag operation, such as highlighting the target of a drag and drop operation, you can temporarily hide the dragged image by using the ImageList_DragLeave function. Another method is to use the GetDCEx function with the DCX_LOCKWINDOWUPDATE value to retrieve a device context that allows you to draw. You must be careful, however, not to obliterate the dragged image.

The ImageList_SetDragCursorImage creates a new drag image by combining the given image (typically a mouse cursor image) with the current drag image. Because the dragging functions use the new image during a drag operation, you should use the ShowCursor function to hide the actual mouse cursor after calling ImageList_SetDragCursorImage. Otherwise, the system may appear to have two mouse cursors for the duration of the drag operation.

When an application calls ImageList_BeginDrag, the system creates an temporary, internal image list can copies the specified drag image to the internal list. You can retrieves the handle of the temporary drag image list by using the ImageList_GetDragImage function. The function also retrieves the current drag position, and the offset of the drag image relative to the drag position.


Image Information

The Win32 API includes a number of functions that retrieve information from an image list. The ImageList_GetImageInfo function fills an IMAGEINFO structure with information about a single image, including the handles of the image and mask bitmaps, the number of color planes and bits per pixel, and the bounding rectangle of the image within the image bitmap. You can use this information to directly manipulate the bitmaps for the image.

The ImageList_GetImageCount function retrieves the number of images in an image list.


Using Image Lists

•	Creating an image list.

•	Dragging an image.


Creating an Image List

To create an image list, use the ImageList_Create function, specifying the type of image list to create (unmasked or masked); the width and height, in pixels, of the images; the number of images you intend to add to the image list; and the amount of images by which the list can grow when it is resized to accommodate additional images. The common control DLL contains the executable code for the image list functions. You must ensure that the library is loaded by using the InitCommonControls function before making any calls to image list functions.

The following example creates a masked image list and uses the ImageList_AddIcon function to add two icons to the list.

// AddIconsToImageList - creates a masked image list and adds some

//     icons to it.

// Returns the handle of the new image list.

// hinst - handle of the application instance

//

// Global variables and constants

//     g_nBird and g_nTree - indexes of the images

//     CX_ICON and CY_ICON - width and height of the icon

//     NUM_ICONS - number of icons to add to the image list

extern int g_nBird, g_nTree;

#define CX_ICON  32

#define CY_ICON  32

#define NUM_ICONS 3

HIMAGELIST AddIconsToImageList(HINSTANCE hinst)

{

    HIMAGELIST himlIcons;  // handle of new image list

    HICON hicon;           // handle of icon

    // Ensure that the common control DLL is loaded.

    InitCommonControls();

    // Create a masked image list large enough to hold the icons.

    himlIcons = ImageList_Create(CX_ICON, CY_ICON, TRUE, NUM_ICONS, 0);

    // Load the icon resources, and add the icons to the image list.

    hicon = LoadIcon(hinst, MAKEINTRESOURCE(IDI_BIRD));

    g_nBird = ImageList_AddIcon(himlIcons, hicon);

    hicon = LoadIcon(hinst, MAKEINTRESOURCE(IDI_TREE));

    g_nTree = ImageList_AddIcon(himlIcons, hicon);

    return himlIcons;

}


Dragging an Image

Dragging an image involves calls to the ImageList_BeginDrag, ImageList_DragMove, and ImageList_EndDrag functions. ImageList_BeginDrag begins a drag operation by combining an image with the current mouse cursor, setting a hot spot in the image, and drawing the image in its initial position. The function also prevents the system from updating any other parts of the display. ImageList_DragMove drags the image to a new location. ImageList_EndDrag ends a drag operation, permitting the system to update any part of the display.

The remainder of this section provides an example using four functions that demonstrates how to drag an image. The first function shows how to draw an image in a window's client area, and subsequent functions show how to drag the image.


Drawing the Image

The following function draws an image and saves the client coordinates of the image's bounding rectangle. A subsequent function uses the bounding rectangle to determine whether the user has clicked the image.

// DrawTheImage - draws an image transparently and saves

//     the bounding rectangle of the drawn image

// Returns TRUE if successful or FALSE otherwise.

// hwnd - handle of the window in which to draw the image

// himl - handle of the image list that contains the image

// cx and cy - client coordinates for the upper-left corner of the image

//

// Global variables and constants

//     g_nImage - index of the image to draw

//     g_rcImage - bounding rectangle of the image

//     CX_IMAGE and CY_IMAGE - width and height of the image

extern int g_nImage;

extern RECT g_rcImage;

#define CX_IMAGE 32

#define CY_IMAGE 32

BOOL DrawTheImage(HWND hwnd, HIMAGELIST himl, int cx, int cy)

{

    HDC hdc;

    if ((hdc = GetDC(hwnd)) == NULL)

        return FALSE;

    if (!ImageList_Draw(himl, g_nImage, hdc, cx, cy, ILD_TRANSPARENT))

        return FALSE;

    ReleaseDC(hwnd, hdc);

    SetRect(&g_rcImage, cx, cy, CX_IMAGE + cx, CY_IMAGE + cy);

    return TRUE;

}


Beginning the Drag Operation

The following function is intended to be called in response to a mouse button-down message, such as WM_LBUTTONDOWN. The function determines whether the user has clicked within the bounding rectangle of the image. If the user has clicked, the function captures the mouse input, erases the image from the client area, and calculates the position for the hot spot within the image. The function sets the hot spot to coincide with the hot spot of the mouse cursor. Then the function begins the drag operation by calling ImageList_BeginDrag.

// StartDragging - begins dragging a bitmap.

// Returns TRUE if successful or FALSE otherwise.

// hwnd - handle of the window in which the bitmap is dragged

// ptCur - coordinates of the cursor

// himl - handle of the image list

//

// Global variables

//     g_rcImage - bounding rectangle of the image to drag

//     g_nImage - index of the image

//     g_ptHotSpot - location of the image's hot spot

//     g_cxBorder and g_cyBorder - width and height of border

//     g_cyCaption and g_cyMenu - height of title bar and menu bar

extern RECT g_rcImage;

extern int g_nImage;

extern POINT g_ptHotSpot;

BOOL StartDragging(HWND hwnd, POINT ptCur, HIMAGELIST himl)

{

    // Return if the cursor is not in the bounding rectangle of

    // the image.

    if (!PtInRect(&g_rcImage, ptCur))

        return FALSE;

    // Capture the mouse input.

    SetCapture(hwnd);

    // Erase the image from the client area.

    InvalidateRect(hwnd, &g_rcImage, TRUE);

    UpdateWindow(hwnd);

    // Calculate the location of the hot spot, and save it.

    g_ptHotSpot.x = ptCur.x - g_rcImage.left;

    g_ptHotSpot.y = ptCur.y - g_rcImage.top;

    // Begin the drag operation.

    if (!ImageList_BeginDrag(himl, g_nImage,

            g_ptHotSpot.x, g_ptHotSpot.y))

        return FALSE;

    // Set the initial location of the image, and make it visible.

    // Because the ImageList_DragEnter function expects coordinates to

    // be relative to the upper-left corner of the given window, the

    // width of the border, title bar, and menu bar need to be taken

    // into account.

    ImageList_DragEnter(hwnd, ptCur.x + g_cxBorder,

        ptCur.y + g_cyBorder + g_cyCaption + g_cyMenu);

    g_fDragging = TRUE;

    return TRUE;

}


Moving the Image

The following function, which drags the image to a new location, is intended to be called in response to the WM_MOUSEMOVE message.

// MoveTheImage - drags an image to the specified coordinates.

// Returns TRUE if successful or FALSE otherwise.

// ptCur - new coordinates for the image

BOOL MoveTheImage(POINT ptCur)

{

    if (!ImageList_DragMove(ptCur.x, ptCur.y))

        return FALSE;

    return TRUE;

}


Ending the Drag Operation

The following function ends the drag operation and draws the image in its final location. It also releases the mouse capture.

// StopDragging - ends a drag operation and draws the image

//     at its final location.

// Returns TRUE if successful or FALSE otherwise.

// hwnd - handle of the window in which the bitmap is dragged

// himl - handle of the image list

// ptCur - coordinates of the cursor

//

// Global variable

//     g_ptHotSpot - location of the image's hot spot

extern POINT g_ptHotSpot;

BOOL StopDragging(HWND hwnd, HIMAGELIST himl, POINT ptCur)

{

    ImageList_EndDrag();

    ImageList_DragLeave(hwnd)

    g_fDragging = FALSE;

    DrawTheImage(hwnd, himl, ptCur.x - g_ptHotSpot.x,

        ptCur.y - g_ptHotSpot.y);

    ReleaseCapture();

    return TRUE;

}


Image List Reference

The following functions, macros, and structures are associated with image lists. These elements can be grouped as follows.

Creating Image Lists

ImageList_Create
ImageList_Destroy
ImageList_LoadBitmap
ImageList_LoadImage

Adding and Removing Images

ImageList_Add
ImageList_AddIcon
ImageList_AddMasked
ImageList_Remove

Replacing and Merging Images

ImageList_Replace
ImageList_ReplaceIcon
ImageList_Merge

Drawing Images

ImageList_Draw
ImageList_DrawEx
ImageList_ExtractIcon
ImageList_GetBkColor
ImageList_GetIcon
ImageList_SetBkColor
INDEXTOOVERLAYMASK

Dragging Images

ImageList_BeginDrag
ImageList_DragEnter
ImageList_DragLeave
ImageList_DragMove
ImageList_DragShowNolock
ImageList_EndDrag
ImageList_GetDragImage
ImageList_SetDragCursorImage
ImageList_SetOverlayImage

Image Information

ImageList_GetIconSize
ImageList_GetImageCount
ImageList_GetImageInfo
ImageList_SetIconSize
IMAGEINFO

Storing Image Lists

ImageList_Read
ImageList_Write


Image List Functions

The following functions are used with image lists.

ImageList_Add
ImageList_AddMasked
ImageList_BeginDrag
ImageList_Create
ImageList_Destroy
ImageList_DragEnter
ImageList_DragLeave
ImageList_DragMove
ImageList_DragShowNolock
ImageList_Draw
ImageList_DrawEx
ImageList_EndDrag
ImageList_ExtractIcon
ImageList_GetBkColor
ImageList_GetDragImage
ImageList_GetIcon
ImageList_GetIconSize
ImageList_GetImageCount
ImageList_GetImageInfo
ImageList_LoadBitmap
ImageList_LoadImage
ImageList_Merge
ImageList_Read
ImageList_Remove
ImageList_Replace
ImageList_ReplaceIcon
ImageList_SetBkColor
ImageList_SetDragCursorImage
ImageList_SetIconSize
ImageList_SetOverlayImage
ImageList_Write


Image List Macro

The following macros are used with image lists.

ImageList_AddIcon
INDEXTOOVERLAYMASK


Image List Structure

The following structure is used with image lists.

IMAGEINFO


List View Controls

A list view control is a window that displays a collection of items, each item consisting of an icon and a label. List view controls provide several ways of arranging items and displaying individual items. For example, additional information about each item can be displayed in columns to the right of the icon and label.


About List View Controls

You can create a list view control by calling the CreateWindowEx function, specifying the WC_LISTVIEW window class. This window class is registered when the common controls dynamic-link library (DLL) is loaded. To ensure that this DLL is loaded, use the InitCommonControls function.

An application sends messages to a list view control to add, remove, arrange, and otherwise manipulate items. Each message has a macro that you can use instead of sending the message explicitly.

Like most common controls, a list view control sends notification messages to its parent window in the form of WM_NOTIFY messages. For more information about common controls, see Common Controls.


Views and Styles

List view controls can display their contents in four different views. The current view is specified by the control's window style. Additional window styles specify the alignment of items and control-specific functionality of the list view control. Information about the four views follows.

View	Description
Icon view	Specified by the LVS_ICON window style. Each item appears as a full-sized icon with a label below it. The user can drag the items to any location in the list view window.
Small icon view	Specified by the LVS_SMALLICON window style. Each item appears as a small icon with the label to the right of it. The user can drag the items to any location.
List view	Specified by the LVS_LIST window style. Each item appears as a small icon with a label to the right of it. Items are arranged in columns and cannot be dragged to any arbitrary location by the user.
Report view	Specified by the LVS_REPORT window style. Each item appears on its own line with information arranged in columns. The leftmost column contains the small icon and label, and subsequent columns contain subitems as specified by the application. Unless the LVS_NOCOLUMNHEADER window style is also specified, each column has a header.
You can change the view type after a list view control is created. To retrieve and change the window style, use the GetWindowLong and SetWindowLong functions. To determine the window styles that correspond to the current view, use the LVS_TYPEMASK value.

You can control the way items are arranged in icon or small icon view by specifying either the LVS_ALIGNTOP (default) or LVS_ALIGNLEFT window style. You can change the alignment after a list view control is created. To isolate the window styles that specify the alignment of items, use the LVS_ALIGNMASK value.

Additional window styles control other options — for example, whether a user can edit labels in place, whether more than one item can be selected at a time, and so on.


List View Image Lists

The icons for list view items are contained in image lists, which you create and assign to the list view control. One image list contains the full-sized icons used in icon view, and a separate image list contains smaller versions of the same icons for use in other views. You can also specify a third image list that contains state images, which are displayed next to an item's icon to indicate an application-defined state.

You assign an image list to a list view control by using the LVM_SETIMAGELIST message, specifying whether the image list contains full-sized icons, small icons, or state images. You can use the GetSystemMetrics function to determine appropriate dimensions for the full-sized and small icons and the ImageList_Create function to create the image lists. For more information about image lists, see Image Lists.

You can retrieve the handle of an image list currently assigned to a list view control by using the LVM_GETIMAGELIST message.

The full-sized and small icon image lists typically contain icons for each type of list view item. You do not need to create both of these image lists if only one is used — for example, if a list view control is never in icon view. If you create both image lists, they must contain the same images in the same order because a single value is used to identify a list view item's icon in both image lists.

The full-sized and small icon image lists can also contain overlay images, which are designed to be superimposed on item icons. A nonzero value in bits 8 through 11 of a list view item's state specifies the one-based index of an overlay image (zero indicates no overlay image). Because a 4-bit, one-based index is used, overlay images must be among the first 15 images in the image lists. For more information about list view item states, see Item States.

If a state image list is specified, a list view control reserves space to the left of each item's icon for a state image. An application can use state images, such as checked and cleared check boxes, to indicate application-defined item states. A nonzero value in bits 12 through 15 specifies the one-based index of a state image (zero indicates no state image). State images are typically not used in icon view.

By default, a list view control destroys the image lists assigned to it when it is destroyed. However, if a list view control has the LVS_SHAREIMAGELISTS window style, the application is responsible for destroying the image lists when they are no longer in use. You should specify this style if you assign the same image lists to multiple list view controls; otherwise, more than one control might try to destroy the same image list.


Items and Subitems

Each item in a list view control consists of an icon, a label, a current state, and an application-defined value. One or more subitems can also be associated with each item. A subitem is a string that, in report view, can be displayed in a column to the right of an item's icon and label. All items in a list view control have the same number of subitems. By using list view messages, you can add, modify, retrieve information about, and delete items. You can also find items with specific attributes.

The LV_ITEM structure defines a list view item or subitem. The iItem member is the zero-based index of the item. The iSubItem member is the one-based index of a subitem or zero if the structure contains information about an item. Additional members specify the item's text, icon, state, and item data. Item data is an application-defined value associated with a list view item.

To add an item to a list view control, use the LVM_INSERTITEM message, specifying the address of an LV_ITEM structure. Before adding multiple items, you can send the control an LVM_SETITEMCOUNT message, specifying the number of items the control will ultimately contain. This message enables the list view control to reallocate its internal data structures only once rather than every time you add an item. You can determine the number of items in a list view control by using the LVM_GETITEMCOUNT message.

To change the attributes of a list view item, use the LVM_SETITEM message, specifying the address of an LV_ITEM structure. The mask member of this structure specifies the item attributes you want to change. To change only the text of an item or subitem, use the LVM_SETITEMTEXT message.

To retrieve information about a list view item, use the LVM_GETITEM message, specifying the address of the LV_ITEM structure to fill in. The mask member of this structure specifies the item attributes to be retrieved. To retrieve only an item or subitem's text, use the LVM_GETITEMTEXT message.

To delete a list view item, use the LVM_DELETEITEM message. You can delete all items in a list view control by using the LVM_DELETEALLITEMS message.


Item States

An item's state is a value that specifies the item's availablility, indicates user actions, or otherwise reflects the item's status. A list view control changes some state bits, such as when the user selects an item. An application might change other state bits to disable or hide the item or to specify an overlay image or state image. For more information about overlay images and state images, see List View Image Lists.

An item's state is specified by the state member of the LV_ITEM structure. When you specify or change an item's state, the stateMask member specifies which state bits you want to change. You can change an item's state by using the LVM_SETITEMSTATE message. You can specify an item's state when you create it or when you change its attributes by using the LMV_SETITEM message. To determine an item's current state, use the LVM_GETITEMSTATE or LVM_GETITEM message.

To set an item's overlay image, the stateMask member of the LV_ITEM structure must include the LVIS_OVERLAYMASK value, and the state member must include the one-based index of the overlay image shifted left 8 bits by using the INDEXTOOVERLAYMASK macro. The index can be zero to specify no overlay image.

To set an item's state image, the stateMask member of the LV_ITEM structure must include the LVIS_STATEIMAGEMASK value, and the state member must include the one-based index of the state image shifted left 12 bits by using the INDEXTOSTATEIMAGEMASK macro. The index can be zero to specify no state image.


Callback Items and the Callback Mask

A callback item is a list view item for which the application — rather than the control — stores the text, icon, or both. Although a list view control can store these attributes for you, you may want to use callback items if your application already maintains some of this information. The callback mask specifies which item state bits are maintained by the application, and it applies to the whole control rather than to a specific item. The callback mask is zero by default, meaning that the list view control tracks all item states. If an application uses callback items or specifies a nonzero callback mask, it must be able to supply list view item attributes on demand.

A list view control requests any information that it needs to display an item by sending its owner window an LVN_GETDISPINFO notification message. The specified LV_DISPINFO structure identifies the item or subitem and indicates which attributes the application must supply. If item attributes or state bits that are maintained by the application change, the list view control sends its owner window an LVN_SETDISPINFO notification message. This notification enables the application to update its information.

If you change a callback item's attributes, you can use the LVM_UPDATE message to force the control to repaint the item. This message also arranges the list view control if it has the LVS_AUTOARRANGE style. You can use the LVM_REDRAWITEMS message to redraw a range of items by invaliding the corresponding portions of the list view control's client area.

You can define a callback item by specifying appropriate values for the pszText and iImage members of the LV_ITEM structure. If the application maintains the item's or subitem's text, you should specify the LPSTR_TEXTCALLBACK value for the pszText member. If the application keeps track of the icon for the item, you should specify the I_IMAGECALLBACK value for the iImage member.

To set the callback mask for a list view control, use the LVM_SETCALLBACKMASK message. A one bit in the callback mask means the application maintains the corresponding state bit for each list view item. To get the current callback mask, use the LVM_GETCALLBACKMASK message.

By effectively using callback items and the callback mask, you can ensure that each item attribute is maintained in only one place. Doing this can simplify your application, but the only space saved is the memory that would otherwise be required to store item labels and subitem text.


Columns

Columns control the way items and their subitems are displayed in report view. Each column has a title and width and is associated with a specific subitem (subitem zero is the item's icon and label). The attributes of a column are defined by an LV_COLUMN structure.

To add a column to a list view control, use the LVM_INSERTCOLUMN message. To delete a column, use the LVM_DELETECOLUMN message. You can retrieve and change the properties of an existing column by using the LVM_GETCOLUMN and LVM_SETCOLUMN messages.

To retrieve or change a column's width, use the LVM_GETCOLUMNWIDTH and LVM_SETCOLUMNWIDTH messages. You can determine the minimum column width necessary to display all of a string by using the LVM_GETSTRINGWIDTH message.

Unless the LVS_NOCOLUMNHEADER window style is specified, column headers appear in report view. The user can click a column header, causing an LVN_COLUMNCLICK notification message to be sent to the parent window. Typically, the parent window sorts the list view control by the specified column when this clicking occurs. The user can also drag the column guides between the headers to size the columns.


Arranging, Sorting, and Finding

You can use list view messages to arrange and sort items and to find items based on their attributes or positions. Arranging repositions items to align on a grid, but the indexes of the items do not change. Sorting changes the sequence of items (and their corresponding indexes) and then repositions them accordingly. You can arrange items only in icon and small icon views, but you can sort items in any view.

To arrange items, use the LVM_ARRANGE message. You can ensure that items are arranged at all times by specifying the LVS_AUTOARRANGE window style.

To sort items, use the LVM_SORTITEMS message. When you sort using this message, you specify an application-defined callback function that is called to compare the relative order of any two items. By supplying an appropriate comparison function, you can sort items by their label, by any subitem, or by any other property. Note that sorting items does not reorder the corresponding subitems. Thus, if any subitems are not callback items, you must regenerate the subitems after sorting.

You can ensure that a list view control is always sorted by specifying the LVS_SORTASCENDING or LVS_SORTDESCENDING window style. You cannot supply a comparison function when using these window styles. The list view sorts the items in ascending or descending order by label.

You can find a list view item with specific properties by using the LVM_FINDITEM message. You can find a list view item that is in a specified state and bears a specified geometrical relationship to a given item by using the LVM_GETNEXTITEM message. For example, you can retrieve the next selected item to the right of a specified item.


List View Item Position

Every list view item has a position and size, which you can retrieve and set using messages. You can also determine which item, if any, is at a specified position. The position of list view items is specified in view coordinates, which are client coordinates offset by the scroll position.

To retrieve and set an item's position, use the LVM_GETITEMPOSITION and LVM_SETITEMPOSITION messages. LVM_GETITEMPOSITION works for all views, but LVM_SETITEMPOSITION works only for icon and small icon views.

You can determine which item, if any, is at a particular location by using the LVM_HITTEST message.

To get the bounding rectangle for a list item or for only its icon or label, use the LVM_GETITEMRECT message.


Scroll Position

Unless the LVS_NOSCROLL window style is specified, a list view control can be scrolled to show more items than can fit in the client area of the control. You can get a list view control's scroll position and related information, scroll a list view control by a specified amount, or scroll a list view control such that a specified list item is visible.

In icon view or small icon view, the current scroll position is defined by the view origin. The view origin is the set of coordinates, relative to the visible area of the list view control, that correspond to the view coordinates (0, 0). To get the current view origin, use the LVM_GETORIGIN message. This message should be used only in icon or small icon view; it returns an error in list or report view.

In list or report view, the current scroll position is defined by the top index. The top index is the index of the first visible item in the list view control. To get the current top index, use the LVM_GETTOPINDEX message. This message returns a valid result only in list or report view; it returns zero in icon or small icon view.

You can use the LVM_GETVIEWRECT message to get the bounding rectangle of all items in a list view control, relative to the visible area of the control.

The LVM_GETCOUNTPERPAGE message returns the number of items that fit in one page of the list view control. This message returns a valid result only in list and report views; in icon and small icon views, it returns the total number of items.

To scroll a list view control by a specific amount, use the LVM_SCROLL message. Using the LVM_ENSUREVISIBLE message, you can scroll the list view control, if necessary, to ensure that a specified item is visible.


Label Editing

A list view control that has the LVS_EDITLABELS window style enables a user to edit item labels in place. The user begins editing by clicking the label of an item that has the focus. An application can begin editing automatically by using the LVM_EDITLABEL message. The list view control notifies the parent window when editing begins and when it is canceled or completed. When editing is completed, the parent window is responsible for updating the item's label, if appropriate.

When label editing begins, a list view control sends its parent window an LVN_BEGINLABELEDIT notification message. You can process this message to allow selective editing of specific labels; returning a nonzero value prevents label editing.

When label editing is canceled or completed, a list view control sends its parent window an LVN_ENDLABELEDIT notification message. The lParam parameter is the address of an LV_DISPINFO structure identifying the item and specifying the edited text. The parent window is responsible for updating the item's label, if appropriate, perhaps after validating the edited string. If editing is canceled, the iItem member is  − 1.

During label editing, you can get the handle of the edit control used for label editing by using the LVM_GETEDITCONTROL message. To limit the amount of text a user can enter, you can send the edit control an EM_LIMITTEXT message. You can even subclass the edit control to intercept and discard invalid characters. The edit control is created after the LVN_BEGINLABELEDIT notification message is sent.


List View Colors

An application can retrieve and set three colors for a list view control. To retrieve and set the text color, use the LVM_GETTEXTCOLOR and LVM_SETTEXTCOLOR messages. To retrieve and set the text background color, use the LVM_GETTEXTBKCOLOR and LVM_SETTEXTBKCOLOR messages. To retrieve and set the window background color, use the LVM_GETBKCOLOR and LVM_SETBKCOLOR messages.


List View Notification Messages

A list view control sends notification messages to its parent window in the form of WM_NOTIFY messages. The following notification messages are sent by a list view control.

Notification message	Description
LVN_BEGINDRAG	Signals the start of a drag and drop operation.
LVN_BEGINLABELEDIT	Signals the start of in-place label editing.
LVN_BEGINRDRAG	Signals the start of a drag and drop operation, using the right mouse button.
LVN_COLUMNCLICK	Indicates that the user clicked a column header in report view.
LVN_DELETEALLITEMS	Signals the deletion of all list view items.
LVN_DELETEITEM	Signals the deletion of a specific item.
LVN_ENDLABELEDIT	Signals the end of label editing.
LVN_GETDISPINFO	Requests information that the list view control requires to display an item.
LVN_INSERTITEM	Signals the insertion of a new list view item.
LVN_ITEMCHANGED	Indicates that an item has changed.
LVN_ITEMCHANGING	Indicates that an item is in the process of changing and enables the parent window to accept or deny the change.
LVN_KEYDOWN	Signals a keyboard event.
LVN_SETDISPINFO	Notifies a parent window that it must update the information it maintains for an item.


Default List View Message Processing

This section describes the window message processing performed by a list view control. Messages specific to list view controls are discussed elsewhere and are, therefore, not included here.

Message	Processing performed
WM_CHAR	Searches for a list view item that begins with the specified character and, if the item is found, selects and sets the focus to the item. Multiple characters received within a time-out interval are concatenated, and the list view control searches for an item that begins with the resulting string.
WM_COMMAND	Processes the EN_UPDATE and EN_KILLFOCUS notification messages and forwards all other edit control notifications to the parent window.
WM_CREATE	Performs additional initialization. If the LVS_SHAREIMAGELISTS window style is not specified, the list view control creates the icon and small icon image lists at this point.
WM_DESTROY	Frees resources.
WM_ERASEBKGND	Erases the window background using the current background color for the list view control. If the background color is the CLR_NONE value, the list view control forwards the message to the parent window.
WM_GETDLGCODE	Returns a combination of the DLGC_WANTTAB and DLGC_WANTARROWS values.
WM_GETFONT	Returns the handle of the current label font.
WM_HSCROLL	Scrolls the list view control horizontally.
WM_KEYDOWN	Processes the SPACEBAR, ENTER, and arrow keys and sends a LVN_KEYDOWN notification message to the parent window.
WM_KILLFOCUS	Repaints the focused list item, if any, and sends a NM_KILLFOCUS notification message to the parent window.
WM_LBUTTONDBLCLK	Sends the parent window an NM_DBLCLK notification message.
WM_LBUTTONDOWN	Processed in different ways depending on whether a click or drag operation is being initiated. To determine which operation is involved, the list view control enters a modal message loop until either the button is released or the mouse is moved. In the case of a click, the list view control may change which item has the focus and which items are selected, taking into account the cursor position, the state of the SHIFT and CTRL keys, and so on. Then the list view control sends its parent window an NM_CLICK notification message. If dragging begins over an item, the list view control selects and sets the focus to the item. Then it sends an LVN_BEGINDRAG notification message to the parent window. The parent window is responsible for actually carrying out the drag operation. If dragging begins over the window background, the list view control enters another modal message loop, enabling the user to form a rectangle by dragging the mouse. Items within the rectangle are selected.
WM_NCCREATE	Allocates and initializes an internal data structure and then calls the DefWindowProc function.
WM_NCDESTROY	Frees resources allocated by the list view control. Unless the LVS_SHAREIMAGELISTS style is used, this includes deleting the full-sized and small image lists.
WM_NOTIFY	Processes header control notification messages.
WM_PAINT	Displays any items in the update region. For callback items, the control first sends an LVN_GETDISPINFO notification message to the owner window to request display information.
WM_RBUTTONDOWN	Processed the same way as the WM_LBUTTONDOWN message, except that the control sends an NM_RCLICK notification message (instead of NM_CLICK) and an LVN_BEGINRDRAG notification message (instead of LVN_BEGINDRAG).
WM_SETFOCUS	Repaints the focused list item, if any, and sends an NM_SETFOCUS notification message to the parent window.
WM_SETFONT	Saves the specified font handle, forwards the message to the header window, if any, and repaints using the new font.
WM_SETREDRAW	Turns redrawing on or off.
WM_TIMER	Begins editing of an item label. If the user clicks the label of the focused item, the list view control sets a timer instead of entering edit mode immediately. The timer makes it possible for the list view control to not enter edit mode if the user double-clicks the label.
WM_VSCROLL	Scrolls the list view control vertically.
WM_WINDOWPOSCHANGED	Updates the window scroll bars. If the current view is icon or small icon view and the LVS_AUTOARRANGE style is specified, the list view control also arranges the list items.
WM_WININICHANGE	Processes changes to system metrics.


Using List View Controls

•	Creating a list view control

•	Initializing the image lists for a list view control

•	Adding columns to a list view control

•	Adding items to a list view control

•	Processing the WM_NOTIFY message

•	Changing list view styles


Creating a List View Control

To create a list view control, use the CreateWindowEx function, specifying the WC_LISTVIEW window class. The list view window class is registered in the application's address space when the common controls dynamic-link library (DLL) is loaded. To ensure that the DLL is loaded, use the InitCommonControls function.

The following example creates a list view control and then calls application-defined functions that add image lists, columns, and list view items. The window style specifies the list view control's initial view and other options. This example specifies report view, which enables the user to edit the labels of list view items.

// CreateListView - creates a list view control.

// Returns the handle of the new control if successful or NULL

//     otherwise.

// hwndParent - handle of the control's parent window

// pfData - file containing list view items

HWND WINAPI CreateListView(HWND hwndParent, FILE *pfData)

{

    HWND hwndLV;

    // Force the common controls DLL to be loaded.

    InitCommonControls();

    // Create the list view window.

    hwndLV = CreateWindow(WC_LISTVIEW, "",

        WS_CHILD | LVS_REPORT | LVS_EDITLABELS,

        0, 0, CW_USEDEFAULT, CW_USEDEFAULT,

        hwndParent, NULL, g_hinst, NULL);

    if (hwndLV == NULL)

        return NULL;

    // Call application-defined functions to initialize the

    // image lists, add columns, and add some items.

    if (!InitListViewImageLists(hwndLV) ||

            !InitListViewColumns(hwndLV) ||

            !InitListViewItems(hwndLV, pfData)) {

        DestroyWindow(hwndLV);

        return FALSE;

    }

    return hwndLV;              // return the control's handle

}


Initializing the Image Lists for a List View Control

A list view control can have up to three image lists associated with it: one for item icons in icon view, one for item icons in other views, and one for application-defined item states. The following example creates two image lists, adds an icon to each, and assigns them to a list view control by using the LVM_SETIMAGELIST message.

// InitListViewImageList - creates image lists for a list view.

// Returns TRUE if successful or FALSE otherwise.

// hwndLV - handle of the list view control

BOOL WINAPI InitListViewImageLists(HWND hwndLV)

{

    HICON hiconItem;        // icon for list view items

    HIMAGELIST himlLarge;   // image list for icon view

    HIMAGELIST himlSmall;   // image list for other views

    // Create the full-sized and small icon image lists.

    himlLarge = ImageList_Create(GetSystemMetrics(SM_CXICON),

        GetSystemMetrics(SM_CYICON), TRUE, 1, 1);

    himlSmall = ImageList_Create(GetSystemMetrics(SM_CXSMICON),

        GetSystemMetrics(SM_CYSMICON), TRUE, 1, 1);

    // Add an icon to each image list.

    hiconItem = LoadIcon(g_hinst, MAKEINTRESOURCE(IDI_ITEM));

    ImageList_AddIcon(himlLarge, hiconItem);

    ImageList_AddIcon(himlSmall, hiconItem);

    DeleteObject(hiconItem);

    // Assign the image lists to the list view control.

    ListView_SetImageList(hwndLV, himlLarge, LVSIL_NORMAL);

    ListView_SetImageList(hwndLV, himlSmall, LVSIL_SMALL);

    return TRUE;

}


Adding Columns to a List View Control

Columns appear only in report view, and they enable multiple pieces of information to be displayed for each list item. You can add columns to a list view control by using the LVM_INSERTCOLUMN message. Each item in a list view control can have, in addition to its item text, any number of strings called subitems. When you add a column to a list view control, you specify which subitem to display in the column.

Unless a list view control has the LVS_NOCOLUMNHEADER window style, each column has a header showing the column name. The user can click the header and can size the columns using the header.

The following example adds several columns to a list view control. The column headings are defined as string resources, which are consecutively numbered starting with IDS_FIRSTCOLUMN (defined in the application's header file). The number of columns is defined in the application's header file as C_COLUMNS.

// InitListViewColumns - adds columns to a list view control.

// Returns TRUE if successful or FALSE otherwise.

// hwndLV - handle of the list view control

BOOL WINAPI InitListViewColumns(HWND hwndLV)

{

    extern char g_achTemp[256];     // temporary buffer

    LV_COLUMN lvc;

    int iCol;

    // Initialize the LV_COLUMN structure.

    lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;

    lvc.fmt = LVCFMT_LEFT;

    lvc.cx = 100;

    lvc.pszText = g_achTemp;

    // Add the columns.

    for (iCol = 0; iCol < C_COLUMNS; iCol++) {

        lvc.iSubItem = iCol;

        LoadString(g_hinst, IDS_FIRSTCOLUMN + iCol,

                g_achTemp, sizeof(g_achTemp));

        if (ListView_InsertColumn(hwndLV, iCol, &lvc) == -1)

            return FALSE;

    }

    return TRUE;

}


Adding Items to a List View Control

An application can add items to a list view control by using the LVM_INSERTITEM message. The attributes of a list view item that are specified by an LV_ITEM structure include a state, a label, an icon, and item data. Associated with each item may be one or more subitems, which are strings that appear to the right of an item in report view.

The example in this section adds a list view item for each line in a text file. Semicolons are assumed to separate the item label and the subitem strings that follow it. The example saves each item's label and subitem strings in a structure, which is defined in the application's header file, as follows.

#define C_COLUMNS 6

typedef struct myitem_tag {

    LPSTR aCols[C_COLUMNS];

} MYITEM;

The application fills in an LV_ITEM structure and adds a list view item by using the LVM_INSERTITEM message. Because the application saves the item label in its own application-defined MYITEM structure, it specifies the LPSTR_TEXTCALLBACK value for the pszText member of the LV_ITEM structure. Specifying this value causes the control to send an LVN_GETDISPINFO notification message to its owner window whenever it needs to display the item. The address of the application-defined structure is saved as item data.

// InitListViewItems - adds items and subitems to a list view.

// Returns TRUE if successful or FALSE otherwise.

// hwndLV - handle of the list view control

// pfData - text file containing list view items with columns

//          separated by semicolons

BOOL WINAPI InitListViewItems(HWND hwndLV, FILE *pfData)

{

    extern char g_achTemp[256];         // temporary buffer

    PSTR pszStart;

    PSTR pszEnd;

    int iItem;

    int iSubItem;

    LV_ITEM lvi;

    // Initialize LV_ITEM members that are common to all items.

    lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_STATE;

    lvi.state = 0;

    lvi.stateMask = 0;

    lvi.pszText = LPSTR_TEXTCALLBACK;   // app. maintains text

    lvi.iImage = 0;                     // image list index

    // Read each line in the specified file.

    for (iItem = 0;

            fgets(g_achTemp, sizeof(g_achTemp), pfData);

            iItem++) {

        // Allocate an application-defined structure to store the

        // item label and the text of each subitem.

        MYITEM *pItem = LocalAlloc(LPTR, sizeof(MYITEM));

        // Copy the first string (the label).

        pszEnd = strchr(g_achTemp, ';');

        *pszEnd = '\0';

        pItem->aCols[0] = DupString(g_achTemp);

        // Copy subsequent strings (subitems).

        for (iSubItem = 1;

                iSubItem < C_COLUMNS && pszEnd != NULL;

                iSubItem++) {

            pszStart = pszEnd + 1;

            if ((pszEnd = strchr(pszStart, ';')) != NULL)

                *pszEnd = '\0';

            pItem->aCols[iSubItem] = DupString(pszStart);

        }

        // Initialize item-specific LV_ITEM members.

        lvi.iItem = iItem;

        lvi.iSubItem = 0;

        lvi.lParam = (LPARAM) pItem;    // item data

        // Add the item.

        ListView_InsertItem(hwndLV, &lvi);

        // There is no need to set the text of the subitems. They

        // default to LPSTR_TEXTCALLBACK.

    }

    return TRUE;

}

// DupString - allocates a copy of a string.

// lpsz - address of the null-terminated string to copy

LPSTR DupString(LPSTR lpsz)

{

    int cb = lstrlen(lpsz) + 1;

    LPSTR lpszNew = LocalAlloc(LMEM_FIXED, cb);

    if (lpszNew != NULL)

        CopyMemory(lpszNew, lpsz, cb);

    return lpszNew;

}


Processing the WM_NOTIFY Message

A list view control notifies its parent window of events by sending a WM_NOTIFY message. The wParam parameter is the identifier of the list view control, and the lParam parameter is the address of an NMHDR structure (or to a larger structure that has an NMHDR structure as its first member). The example in this section processes the LVN_GETDISPINFO, LVN_ENDLABELEDIT, and LVN_COLUMNCLICK notification messages.

A list view control sends the LVN_GETDISPINFO notification message to retrieve information about an item or subitem from the parent window. This notification is sent, for example, when an item with the LPSTR_TEXTCALLBACK value needs to be displayed.

A list view control sends the LVN_ENDLABELEDIT notification message when the user completes or cancels editing of an item's label. This notification is only sent if the list view control has the LVS_EDITLABELS window style. If editing is being canceled, the parent window typically does nothing. If editing is being completed, the parent window should set the item label to the new text, unless the item label is LPSTR_TEXTCALLBACK. In that case, the parent window should simply update the application-defined data it maintains for the list item.

If the user clicks a column header in report view, a list view control sends the LVN_COLUMNCLICK notification message. Typically, an application sorts a list view by the specified column when this clicking occurs. To sort, use the LVM_SORTITEMS message, specifying an application-defined comparison function.

The following example shows the portion of the application's window procedure that processes the WM_NOTIFY message.

case WM_NOTIFY:

    // Branch depending on the specific notification message.

    switch (((LPNMHDR) lParam)->code) {

        // Process LVN_GETDISPINFO to supply information about

        // callback items.

        case LVN_GETDISPINFO:

            Main_OnGetDispInfo((LV_DISPINFO *) lParam);

            break;

        // Process LVN_ENDLABELEDIT to change item labels after

        // in-place editing.

        case LVN_ENDLABELEDIT:

            return Main_OnEndLabelEdit(

                (LV_DISPINFO *) lParam

                );

        // Process LVN_COLUMNCLICK to sort items by column.

        case LVN_COLUMNCLICK:

            #define pnm ((NM_LISTVIEW *) lParam)

            ListView_SortItems(

                pnm->hdr.hwndFrom,

                ListViewCompareFunc,

                (LPARAM) (pnm->iSubItem)

                );

            #undef pnm

            break;

    }

    break;

The following example shows the application-defined functions that the window procedure uses to process list view notification messages.

// Main_OnGetDispInfo - processes the LVN_GETDISPINFO

//     notification message.

// pnmv - value of lParam (points to an LV_DISPINFO structure)

VOID WINAPI Main_OnGetDispInfo(LV_DISPINFO *pnmv)

{

    // Provide the item or subitem's text, if requested.

    if (pnmv->item.mask & LVIF_TEXT) {

        MYITEM *pItem = (MYITEM *) (pnmv->item.lParam);

        lstrcpy(pnmv->item.pszText,

                pItem->aCols[pnmv->item.iSubItem]);

    }

}

// Main_OnEndLabelEdit - processes the LVN_ENDLABELEDIT

//     notification message.

// Returns TRUE if the label is changed or FALSE otherwise.

// pnmv - value of lParam (points to an LV_DISPINFO structure)

BOOL Main_OnEndLabelEdit(LV_DISPINFO *pnmv)

{

    MYITEM *pItem;

    // The item is -1 if editing is being canceled.

    if (pnmv->item.iItem == -1)

        return FALSE;

    // Copy the new text to the application-defined structure,

    // a pointer to which is saved as item data.

    pItem = (MYITEM *) (pnmv->item.lParam);

    pItem->aCols[0] = (PSTR) LocalReAlloc(

        (HLOCAL) (pItem->aCols[0]),

        lstrlen(pnmv->item.pszText) + 1,

        LMEM_MOVEABLE

        );

    lstrcpy(pItem->aCols[0], pnmv->item.pszText);

    // No need to set the item text, because it is a callback item.

    return TRUE;

}

// ListViewCompareFunc - sorts the list view control. It is a

//     comparison function.

// Returns a negative value if the first item should precede the

//     second item, a positive value if the first item should

//     follow the second item, and zero if the items are equivalent.

// lParam1 and lParam2 - item data for the two items (in this

//     case, pointers to application-defined MYITEM structures)

// lParamSort - value specified by the LVM_SORTITEMS message

//     (in this case, the index of the column to sort)

int CALLBACK ListViewCompareFunc(

    LPARAM lParam1,

    LPARAM lParam2,

    LPARAM lParamSort)

{

    MYITEM *pItem1 = (MYITEM *) lParam1;

    MYITEM *pItem2 = (MYITEM *) lParam2;

    // Compare the specified column.

    int iCmp = lstrcmpi(pItem1->aCols[lParamSort],

        pItem2->aCols[lParamSort]);

    // Return the result if nonzero, or compare the

    // first column otherwise.

    return (iCmp != 0) ? iCmp :

        lstrcmpi(pItem1->aCols[0], pItem2->aCols[0]);

}


Changing List View Styles

An application can change the window style of a list view control after it is created by using the GetWindowLong and SetWindowLong functions. The following example changes the style bits that govern the view mode.

// SetView - sets a list view's window style to change the view.

// hwndLV - handle of the list view control

// dwView - value specifying a view style

VOID WINAPI SetView(HWND hwndLV, DWORD dwView)

{

    // Get the current window style.

    DWORD dwStyle = GetWindowLong(hwndLV, GWL_STYLE);

    // Only set the window style if the view bits have changed.

    if ((dwStyle & LVS_TYPEMASK) != dwView)

        SetWindowLong(hwndLV, GWL_STYLE,

            (dwStyle & ~LVS_TYPEMASK) | dwView);

}


List View Control Reference

The following messages, notification messages, and structures are associated with list view controls. These elements can be grouped, as follows.

Items and Subitems

LV_ITEM
LVM_DELETEALLITEMS
LVM_DELETEITEM
LVM_GETITEM
LVM_GETITEMCOUNT
LVM_GETITEMSPACING
LVM_GETITEMSTATE
LVM_GETITEMTEXT
LVM_GETSELECTEDCOUNT
LVM_INSERTITEM
LVM_SETITEM
LVM_SETITEMCOUNT
LVM_SETITEMSTATE
LVM_SETITEMTEXT

Callback Items

LV_DISPINFO
LVM_GETCALLBACKMASK
LVM_REDRAWITEMS
LVM_SETCALLBACKMASK
LVM_UPDATE
LVN_GETDISPINFO
LVN_SETDISPINFO

Columns

LV_COLUMN
LVM_DELETECOLUMN
LVM_GETCOLUMN
LVM_GETCOLUMNWIDTH
LVM_GETSTRINGWIDTH
LVM_INSERTCOLUMN
LVM_SETCOLUMN
LVM_SETCOLUMNWIDTH
LVN_COLUMNCLICK

Arranging, Sorting, and Finding

LV_FINDINFO
LVM_ARRANGE
LVM_FINDITEM
LVM_GETNEXTITEM
LVM_SORTITEMS

Item Positions and Scrolling

LV_HITTESTINFO
LVM_ENSUREVISIBLE
LVM_GETCOUNTPERPAGE
LVM_GETITEMPOSITION
LVM_GETITEMRECT
LVM_GETORIGIN
LVM_GETTOPINDEX
LVM_GETVIEWRECT
LVM_HITTEST
LVM_SCROLL
LVM_SETITEMPOSITION
LVM_SETITEMPOSITION32

Colors

LVM_GETBKCOLOR
LVM_GETTEXTBKCOLOR
LVM_GETTEXTCOLOR
LVM_SETBKCOLOR
LVM_SETTEXTBKCOLOR
LVM_SETTEXTCOLOR

Miscellaneous

LV_KEYDOWN
LVM_CREATEDRAGIMAGE
LVM_EDITLABEL
LVM_GETEDITCONTROL
LVM_GETIMAGELIST
LVM_SETIMAGELIST
LVN_BEGINDRAG
LVN_BEGINLABELEDIT
LVN_BEGINRDRAG
LVN_DELETEALLITEMS
LVN_DELETEITEM
LVN_ENDLABELEDIT
LVN_INSERTITEM
LVN_ITEMCHANGED
LVN_ITEMCHANGING
LVN_KEYDOWN
LVN_PEN
NM_LISTVIEW


List View Control Messages

An application sends messages to a list view control to alter its appearance, add or change items and columns, and so on. Each message has a corresponding macro, which you can use instead of sending the message explicitly.

LVM_ARRANGE
LVM_CREATEDRAGIMAGE
LVM_DELETEALLITEMS
LVM_DELETECOLUMN
LVM_DELETEITEM
LVM_EDITLABEL
LVM_ENSUREVISIBLE
LVM_FINDITEM
LVM_GETBKCOLOR
LVM_GETCALLBACKMASK
LVM_GETCOLUMN
LVM_GETCOLUMNWIDTH
LVM_GETCOUNTPERPAGE
LVM_GETEDITCONTROL
LVM_GETIMAGELIST
LVM_GETISEARCHSTRING
LVM_GETITEM
LVM_GETITEMCOUNT
LVM_GETITEMPOSITION
LVM_GETITEMRECT
LVM_GETITEMSPACING
LVM_GETITEMSTATE
LVM_GETITEMTEXT
LVM_GETNEXTITEM
LVM_GETORIGIN
LVM_GETSELECTEDCOUNT
LVM_GETSTRINGWIDTH
LVM_GETTEXTBKCOLOR
LVM_GETTEXTCOLOR
LVM_GETTOPINDEX
LVM_GETVIEWRECT
LVM_HITTEST
LVM_INSERTCOLUMN
LVM_INSERTITEM
LVM_REDRAWITEMS
LVM_SCROLL
LVM_SETBKCOLOR
LVM_SETCALLBACKMASK
LVM_SETCOLUMN
LVM_SETCOLUMNWIDTH
LVM_SETIMAGELIST
LVM_SETITEM
LVM_SETITEMCOUNT
LVM_SETITEMPOSITION
LVM_SETITEMPOSITION32
LVM_SETITEMSTATE
LVM_SETITEMTEXT
LVM_SETTEXTBKCOLOR
LVM_SETTEXTCOLOR
LVM_SORTITEMS
LVM_UPDATE


List View Control Notification Messages

A list view control sends notification messages to its owner window when events occur in the control.

LVN_BEGINDRAG
LVN_BEGINLABELEDIT
LVN_BEGINRDRAG
LVN_COLUMNCLICK
LVN_DELETEALLITEMS
LVN_DELETEITEM
LVN_ENDLABELEDIT
LVN_GETDISPINFO
LVN_INSERTITEM
LVN_ITEMCHANGED
LVN_ITEMCHANGING
LVN_KEYDOWN
LVN_PEN
LVN_SETDISPINFO


List View Control Structures

The following structures are used with list view controls.

LV_COLUMN
LV_DISPINFO
LV_FINDINFO
LV_HITTESTINFO
LV_ITEM
LV_KEYDOWN
NM_LISTVIEW


List View Control Constants

The following sections list window style flags and item state flags are used with list view controls.


List View Window Styles

The following window styles are specific to list view controls.

LVS_ALIGNLEFT	Specifies that items are left-aligned in icon and small icon view.
LVS_ALIGNTOP	Specifies that items are aligned with the top of the list view control in icon and small icon view.
LVS_AUTOARRANGE	Specifies that icons are automatically kept arranged in icon and small icon view.
LVS_BUTTON	Specifies that item icons look like buttons in icon view.
LVS_EDITLABELS	Allows item text to be edited in place. The parent window must process the LVN_ENDLABELEDIT notification message.
LVS_ICON	Specifies icon view.
LVS_LIST	Specifies list view.
LVS_NOCOLUMNHEADER	Specifies that a column header is not displayed in report view. By default, columns have headers in report view.
LVS_NOLABELWRAP	Displays item text on a single line in icon view. By default, item text may wrap in icon view.
LVS_NOSCROLL	Disables scrolling. All items must be within the client area.
LVS_NOSORTHEADER	Specifies that column headers do not work like buttons. This style is useful if clicking a column header in report view does not carry out an action, such as sorting.
LVS_OWNERDRAWFIXED	Enables the owner window to paint items in report view. The list view control sends a WM_DRAWITEM message to paint each item; it does not send separate messages for each subitem. The itemData member of the DRAWITEMSTRUCT structure contains the item data for the specified list view item.
LVS_REPORT	Specifies report view. When using the LVS_REPORT style with a List View control, the first column is always left-aligned. You can not use LVCFMT_RIGHT to change this alignment.
LVS_SHAREIMAGELISTS	Specifies that the control does not take ownership of the image lists assigned to it;  that is, it does not destroy the image lists when it is destroyed. This style enables the same image lists to be used with multiple list view controls.
LVS_SHOWSELALWAYS	Always show the selection,if any, even if the control does not have the focus.
LVS_SINGLESEL	Allows only one item at a time to be selected. By default, multiple items may be selected.
LVS_SMALLICON	Specifies small icon view.
LVS_SORTASCENDING	Sorts items based on item text in ascending order.
LVS_SORTDESCENDING	Sorts items based on item text in descending order.
You can use the LVS_TYPESTYLEMASK value to isolate the window styles that correspond to the current view: LVS_ICON, LVS_SMALLICON, LVS_LIST, and LVS_REPORT.

You can use the LVS_ALIGNMASK value to isolate the window styles that specify the alignment of items: LVS_ALIGNLEFT and LVS_ALIGNTOP.


List View Item States

An item's state determines its appearance and functionality. The state can be zero, or one or more of the following values.

LVIS_CUT	The item is marked for a cut and paste operation.
LVIS_DROPHILITED	The item is highlighted as a drag-and-drop target.
LVIS_FOCUSED	The item has the focus, so it is surrounded by a standard focus rectangle. Although more than one item may be selected, only one item can have the focus.
LVIS_SELECTED	The item is selected. The appearance of a selected item depends on whether it has the focus and on the system colors used for selection.
You can use the LVIS_OVERLAYMASK value to isolate the state bits that contain the one-based index of the overlay image. You can use the LVIS_STATEIMAGEMASK value to isolate the state bits that contain the one-based index of the state image.


Progress Bars

A progress bar is a window that an application can use to indicate the progress of a lengthy operation. It consists of a rectangle that is gradually filled, from left to right, with the system highlight color as an operation progresses. The following illustration shows a progress bar positioned along the bottom of a window.


About Progress Bars

You create a progress bar by using the CreateWindowEx function, specifying the PROGRESS_CLASS window class. This window class is registered when the common control dynamic-link library (DLL) is loaded. To ensure that this DLL is loaded, use the InitCommonControls function first.


Range and Current Position

A progress bar has a range and a current position. The range represents the entire duration of the operation, and the current position represents the progress that the application has made toward completing the operation. The window procedure uses the range and the current position to determine the percentage of the progress bar to fill with the highlight color and to determine the text, if any, to display within the progress bar. Because the range and current position values are expressed as unsigned integers, the highest possible range or current position value is 65,535.

The minimum value in the range can be from 0 to 65,535. Likewise, the maximum value can be from 0 to 65,535. If you do not set the range values, the system sets the minimum value to 0 and the maximum value to 100. You can adjust the range to convenient integers by using the PBM_SETRANGE message.

A progress bar provides several messages that you can use to set the current position. The PBM_SETPOS message sets the position to a given value. The PBM_DELTAPOS message advances the position by adding a specified value to the current position.

The PBM_SETSTEP message allows you to specify a step increment for a progress bar. Subsequently, whenever you send the PBM_STEPIT message to the progress bar, the current position advances by the specified increment. By default, the step increment is set to 10.


Default Progress Bar Message Processing

This section describes the window messages handled by the window procedure for the PROGRESS_CLASS window class.

Message	Processing performed
WM_CREATE	Allocates and initializes an initial structure.
WM_DESTROY	Frees all resources associated with the progress bar.
WM_ERASEBKGND	Draws the background and borders of the progress bar.
WM_GETFONT	Returns the handle of the font that the progress bar is currently using to draw text.
WM_PAINT	Draws the progress bar.
WM_SETFONT	Saves the handle of the new font and returns the handle of the previous font.


Using Progress Bars

The following example shows how to use a progress bar to indicate the progress of a lengthy file-parsing operation. The example creates a progress bar and positions it along the bottom of the parent window's client area. The height of the progress bar is based on the height of the arrow bitmap used in a scroll bar. The range is based on the size of the file divided by 2048, which is the size of each "chunk" of data read from the file. The example also sets an increment and advances the current position of the progress bar by the increment after parsing each chunk.

// ParseALargeFile - parses a large file and uses a progress bar to

//   indicate the progress of the parsing operation.

// Returns TRUE if successful or FALSE otherwise.

// hwndParent - parent window of the progress bar

// lpszFileName - name of the file to parse

//

// Global variable

//     g_hinst - instance handle

extern HINSTANCE g_hinst;

BOOL ParseALargeFile(HWND hwndParent, LPSTR lpszFileName)

{

    RECT rcClient;  // client area of parent window

    int cyVScroll;  // height of scroll bar arrow

    HWND hwndPB;    // handle of progress bar

    HANDLE hFile;   // handle of file

    DWORD cb;       // size of file and count of bytes read

    LPCH pch;       // address of data read from file

    LPCH pchTmp;    // temporary pointer

    // Ensure that the common control DLL is loaded and create a

    // progress bar along the bottom of the client area of the

    // parent window. Base the height of the progress bar on

    // the height of a scroll bar arrow.

    InitCommonControls();

    GetClientRect(hwndParent, &rcClient);

    cyVScroll = GetSystemMetrics(SM_CYVSCROLL);

    hwndPB = CreateWindowEx(0, PROGRESS_CLASS, (LPSTR) NULL,

        WS_CHILD | WS_VISIBLE, rcClient.left,

        rcClient.bottom - cyVScroll,

        rcClient.right, cyVScroll,

        hwndParent, (HMENU) 0, g_hinst, NULL);

    // Open the file for reading, and retrieve the size of the file.

    hFile = CreateFile(lpszFileName, GENERIC_READ, FILE_SHARE_READ,

        (LPSECURITY_ATTRIBUTES) NULL, OPEN_EXISTING,

        FILE_ATTRIBUTE_NORMAL, (HANDLE) NULL);

    if (hFile == (HANDLE) INVALID_HANDLE_VALUE)

        return FALSE;

    cb = GetFileSize(hFile, (LPDWORD) NULL);

    // Set the range and increment of the progress bar.

    SendMessage(hwndPB, PBM_SETRANGE, 0, MAKELPARAM(0, cb / 2048));

    SendMessage(hwndPB, PBM_SETSTEP, (WPARAM) 1, 0);

    // Parse the file.

    pch = (LPCH) LocalAlloc(LPTR, sizeof(char) * 2048);

    pchTmp = pch;

    do {

        ReadFile(hFile, pchTmp, sizeof(char) * 2048, &cb,

            (LPOVERLAPPED) NULL);

        .

        . // Include here any code that parses the file.

        .

        // Advance the current position of the progress bar

        // by the increment.

        SendMessage(hwndPB, PBM_STEPIT, 0, 0);

    } while (cb);

    CloseHandle((HANDLE) hFile);

    DestroyWindow(hwndPB);

    return TRUE;

}


Progress Bar Messages

The following messages are associated with progress bars.

PBM_DELTAPOS
PBM_SETPOS
PBM_SETRANGE
PBM_SETSTEP
PBM_STEPIT


Property Sheets

A property sheet is a window that allows the user to view and edit the properties of an item. For example, a spreadsheet application can use a property sheet to allow the user to set the font and border properties of a cell or to view and set the properties of a device, such as a disk drive, printer, or mouse.

This overview assumes that you have a thorough understanding of dialog box templates and dialog box procedures. If you do not, you should read Dialog Boxes before continuing with this overview.


About Property Sheets

A property sheet contains one or more overlapping child windows called pages, each containing control windows for setting a group of related properties. For example, a page can contain the controls for setting the font properties of an item, including the type style, point size, color, and so on. Each page has a tab that the user can select to bring the page to the foreground of the property sheet. The following illustration shows a property sheet for viewing and setting the properties of a floppy disk drive.


Property Sheet Dialog Boxes

A property sheet and the pages it contains are actually dialog boxes. The property sheet is a system-defined dialog box that manages the pages and provides a common container for them. The property sheet dialog box can be modal or modeless. It includes a frame, a title bar, and four buttons: OK, Cancel, Apply Now, and Help. (The Help button may be hidden as in the preceding illustration.) The dialog box procedures for the pages receive notification messages when the user selects the buttons.

Each page in a property sheet is an application-defined modeless dialog box that manages the control windows used to view and edit the properties of an item. You provide the dialog box template used to create each page as well as the dialog box procedure that manages the controls and sets the properties of the corresponding item.

A property sheet sends notification messages to the dialog box procedure for a page when the page is gaining or losing the activation and when the user chooses the OK, Cancel, Apply Now, or Help button. The notifications are sent in the form of WM_NOTIFY messages. The lParam parameter points to an NMHDR structure, which includes the window handle of the property sheet dialog box.

Some notification messages require a page to return either TRUE or FALSE in response to the WM_NOTIFY message. A page cannot simply return TRUE or FALSE; instead, it must use the SetWindowLong function to set the DWL_MSGRESULT value for the page dialog box to either TRUE or FALSE.


Pages

A property sheet must contain at least one page, but cannot contain more than the value of MAXPROPPAGES as defined in the Win32 header files. Each page has a zero-based index that the property sheet assigns according to the order in which the page is added to the property sheet. The indexes are used in messages that you send to the property sheet.

A property page can contain a nested dialog box. If it does, you must include the WS_EX_CONTROLPARENT style for the top-level dialog box and call the IsDialogMessage function with the handle of the parent dialog box. This ensures that the user can use mnemonics and the dialog box navigation keys to move the focus to controls in the nested dialog box.

Each page has a corresponding icon and label. The property sheet creates a tab for each page and displays the icon and label in the tab. All property sheet pages are expected to use a nonbold font. To ensure that the font is not bold, specify the DS_3DLOOK style in the dialog box template.

The dialog box procedure for a page must not call the EndDialog function. Doing so will destroy the entire property sheet, not just the page.


Property Sheet Creation

Before creating a property sheet, you must define one or more pages. This involves filling a PROPSHEETPAGE structure with information about the page — its icon, label, dialog box template, dialog box procedure, and so on — and then specifying the address of the structure in a call to the CreatePropertySheetPage function. The function returns a handle of the HPROPSHEETPAGE type that uniquely identifies the page.

To create a property sheet, you specify the address of a PROPSHEETHEADER structure in a call to the PropertySheet function. The structure defines the icon and title for the property sheet and also includes a pointer to an array of HPROPSHEETPAGE handles. When PropertySheet creates the property sheet, it includes the pages identified in the array. The order of the array determines the order of the pages in the property sheet.

Another way to create a property sheet is to specify an array of PROPSHEETPAGE structures instead of an array of HPROPSHEETPAGE handles. In this case, PropertySheet creates handles for the pages before adding them to the property sheet.

When a page is created, the dialog box procedure for the page receives a WM_INITDIALOG message. The message's lParam parameter points to the PROPSHEETPAGE structure used to create the page. The dialog box can save the information in the structure and use it later to modify the page.

PropertySheet automatically sets the size and initial position of a property sheet. The position is based on the position of the owner window, and the size is based on the largest page specified in the array of pages when the property sheet was created. If you want the pages to match the width of the four buttons at the bottom of the property sheet, set the width of the widest page to 190 dialog units.


Adding and Removing Pages

After creating a property sheet, an application can add a page by using the PSM_ADDPAGE message. Note that the size of the property sheet cannot change after it has been created, so the new page must be no larger than the largest page currently in the property sheet.

An application removes a page by using the PSM_REMOVEPAGE message. When you define a page, you can specify the address of a PropSheetPageProc callback function that the property sheet calls when it is creating or removing the page. Using PropSheetPageProc gives you an opportunity to perform initialization and cleanup operations for individual pages.

When a property sheet is destroyed, it automatically destroys all of the pages that have been added to it. The pages are destroyed in reverse order from that specified in the array used to create the pages. To destroy a page that was created by the CreatePropertySheetPage function but was not added to the property sheet, use the DestroyPropertySheetPage function.


Property Sheet Title and Page Labels

You specify the title of a property sheet in the PROPSHEETHEADER structure used to create the property sheet. If the dwFlags member includes the PSH_PROPTITLE value, the property sheet adds the "Properties for" prefix to the specified title string. An application can change the title after a property sheet is created by using the PSM_SETTITLE message.

By default, a property sheet uses the name string specified in the dialog box template as the label for a page. You can override the name string by including the PSP_USETITLE value in the dwFlags member of the PROPSHEETPAGE structure that defines the page. When PSP_USETITLE is specified, the pszTitle member must contain the address of the label string for the page.


Page Activation

A property sheet can have only one active page at a time. The page that has the activation is at the foreground of the overlapping stack of pages. The user activates a page by selecting its tab; an application activates a page by using the PSM_SETCURSEL message.

The property sheet sends the PSN_KILLACTIVE notification message to the page that is about to lose the activation. In response, the page should validate any changes that the user has made to the page. If the page requires additional user input before losing the activation, it should use the SetWindowLong function to set the DWL_MSGRESULT value of the page to TRUE. Also, the page should display a message box that describes the problem and provides the recommended action. The page should set DWL_MSGRESULT to FALSE when it is okay to lose the activation.

Before the page that is gaining the activation is visible, the property sheet sends the PSN_SETACTIVE notification message to the page. The page should respond by initializing its control windows.


Help Button

When a page is activated, the property sheet determines whether to enable or disable the Help button for the page by checking for the PSP_HASHELP style. If the page has this style, it supports the Help button. If the PSP_HASHELP style is not present, the button is disabled.

When the user chooses the Help button, the active page receives the PSN_HELP notification message. The page should respond by displaying help information, typically by calling the WinHelp function.


OK, Cancel, and Apply Now Buttons

The OK and Apply Now buttons are similar; both direct a property sheet's pages to validate and apply the property changes that the user has made. The only difference is that choosing the OK button causes the property sheet to be destroyed after the changes are applied, but choosing the Apply Now button does not.

When the user chooses the OK or Apply Now button, the property sheet sends the PSN_KILLACTIVE notification message to the active page, giving it an opportunity to validate the user's changes. If the page determines that the changes are valid, it should call the SetWindowLong function to set the DWL_MSGRESULT value for the page to FALSE. In this case, the property sheet sends the PSN_APPLY notification message to each page, directing them to apply the new properties to the corresponding item. If the page determines that the user's changes are not valid, it should set DWL_MSGRESULT to TRUE and display a dialog box informing the user of the problem. The page remains active until it sets DWL_MSGRESULT to FALSE in response to a PSN_KILLACTIVE message. An application can use the PSM_APPLY message to simulate the choice of the Apply Now button.

The Apply Now button is initially disabled when a page becomes active, indicating that there are not yet any property changes to apply. When the page receives user input through one of its controls indicating that the user has edited a property, the page should send the PSM_CHANGED message to the property sheet. The message causes the property sheet to enable the Apply Now button. If the user subsequently chooses the Apply Now or Cancel button, the page should reinitialize its controls and then send the PSM_UNCHANGED message to disable again the Apply Now button.

Sometimes the Apply Now button causes a page to make a change to a property sheet, and the change cannot be undone. When this happens, the page should send the PSM_CANCELTOCLOSE message to the property sheet. The message causes the property sheet to change the text of the OK button to "Close," indicating that the applied changes cannot be canceled.

Sometimes a page makes a change to the system configuration that requires Windows to be to restarted or the system rebooted before the change can take effect. After making such a change, a page should send either the PSM_RESTARTWINDOWS or PSM_REBOOTSYSTEM message to the property sheet. These messages cause the PropertySheet function to return the ID_PSRESTARTWINDOWS or ID_PSREBOOTSYSTEM value after the property sheet is destroyed.

The property sheet sends the the PSN_RESET notification message to all pages when the user chooses the Cancel button, indicating that the property sheet is about to be destroyed. A page should use the notification to perform cleanup operations.


Wizard Property Sheets

You can create a special type of property sheet called a wizard, which consists of a sequence of dialog boxes that guide the user through the steps of an operation, such as setting up a device or creating a birthday card. In a wizard property sheet, the pages do not have tabs, and only one page is visible at a time. Also, instead of having Ok and Apply Now buttons, a wizard property sheet has a Back button, a Next or Finish button, and a Cancel button. To tell the property sheet which buttons to enable, use the PSM_SETWIZBUTTONS message with the PSWIZB_BACK, PSWIZB_NEXT, and PSWIZB_FINISH values. You create and initialize a wizard property sheet just as you would a standard property sheet, except that you must include the PSH_WIZARD value in the dwFlags member of the PROPSHEETHEADER structure. The system ignores the pszCaption member; instead, it puts the label of the current page in the title bar of the property sheet. When the user switches from one page to the next, the system updates the title using the label of the current page.

You should use the following values to set the sizes of the elements in your wizard property sheet. Using these values ensures that your pages conform to the Window standards.

WIZ_BODYCX	Width of the body of a page in a wizard property sheet. The body does not include the bitmap area.
WIZ_BODYX	Horizontal coordinate of the upper left corner of the body of a page in a wizard property sheet. Use zero for the vertical coordinate of the body of a page.
WIZ_CXBMP	Width of the bitmap area in a page of a wizard property sheet. Use WIZ_CYDLG for the height of the bitmap area.
WIZ_CXDLG	Width of a page in a wizard property sheet.
WIZ_CYDLG	Height of a page in a wizard property sheet.
The dialog box procedure for a page in a wizard property sheet receives all of the same notification messages as a standard property sheet page. In addition, a wizard property sheet page receives three notification messages that a standard property sheet page does not receive: PSN_WIZBACK, PSN_WIZNEXT, and PSN_WIZFINISH. A wizard page receives these notifications when the user chooses the Back, Next, or Finish button.

When the user chooses the Back or Next button, the property sheet automatically advances to the previous or next page. An application can prevent the property sheet from advancing by setting the DWL_MSGRESULT value to −1 in response to the PSN_WIZBACK or PSN_WIZNEXT notification. To jump to a page other than the previous or next one, an application should set DWL_MSGRESULT to the identifier of the dialog box to be displayed.

The system automatically destroys the wizard property sheet when the user clicks the Finish button. An application can prevent the wizard from being destroyed by setting DWL_MSGRESULT to a nonzero value in response to the PSN_WIZFINISH notification message.


Property Sheet Extensions

A property sheet extension is a dynamic-link library (DLL) that adds one or more pages to a property sheet created by another module. The module that creates the property sheet includes an AddPropSheetPageProc callback function that the extension DLL calls to add a page. The function receives the handle of a page and an application-defined 32-bit value.

The extension DLL also contains a callback function called ExtensionPropSheetPageProc, which receives the address of AddPropSheetPageProc from the module that creates the property sheet. The extension DLL must export ExtensionPropSheetPageProc.

The Windows header files include two prototypes for defining property sheet callback functions. To define AddPropSheetPageProc, use the following prototype.

typedef BOOL (CALLBACK FAR * LPFNADDPROPSHEETPAGE)(HPROPSHEETPAGE,
    LPARAM);

To define ExtensionPropSheetPageProc, use the following prototype.

typedef BOOL (CALLBACK FAR * LPFNADDPROPSHEETPAGES)(LPVOID, LPFNADDPROPSHEETPAGE, LPARAM);


Using Property Sheets

•	Creating a property sheet

•	Processing notification messages


Creating a Property Sheet

The example in this section creates a property sheet that contains two pages — one for setting the font properties of a cell in a spreadsheet and another for setting the border properties of the cell. The example defines the pages by filling a pair of PROPSHEETPAGE structures and specifying the address in the PROPSHEETHEADER structure that is passed to the PropertySheet function. The dialog box templates, icons, and labels for the pages are loaded from the resources contained in the application's executable file. The icon for the property sheet is also loaded from the application's resources.

// DoPropertySheet - creates a property sheet that contains two pages.
// hwndOwner - handle of the owner window of the property sheet
//
// Global variables
//     g_hinst - instance handle
extern HINSTANCE g_hinst;

VOID DoPropertySheet(HWND hwndOwner)
{
    PROPSHEETPAGE psp[2];
    PROPSHEETHEADER psh;

    psp[0].dwSize = sizeof(PROPSHEETPAGE);
    psp[0].dwFlags = PSP_USEICONID | PSP_USETITLE;
    psp[0].hInstance = g_hinst;
    psp[0].pszTemplate = MAKEINTRESOURCE(DLG_FONT);
    psp[0].pszIcon = MAKEINTRESOURCE(IDI_FONT);
    psp[0].pfnDlgProc = FontDialogProc;
    psp[0].pszTitle = MAKEINTRESOURCE(IDS_FONT)
    psp[0].lParam = 0;
    psp[0].pfnCallback = NULL;

    psp[1].dwSize = sizeof(PROPSHEETPAGE);
    psp[1].dwFlags = PSP_USEICONID | PSP_USETITLE;
    psp[1].hInstance = g_hinst;
    psp[1].pszTemplate = MAKEINTRESOURCE(DLG_BORDER);
    psp[1].pszIcon = MAKEINTRESOURCE(IDI_BORDER);
    psp[1].pfnDlgProc = BorderDialogProc;
    psp[1].pszTitle = MAKEINTRESOURCE(IDS_BORDER);
    psp[1].lParam = 0;
    psp[1].pfnCallback = NULL;

    psh.dwSize = sizeof(PROPSHEETHEADER);
    psh.dwFlags = PSH_USEICONID | PSH_PROPSHEETPAGE;
    psh.hwndParent = hwndOwner;
    psh.hInstance = g_hinst;
    psh.pszIcon = MAKEINTRESOURCE(IDI_CELL_PROPERTIES);
    psh.pszCaption = (LPSTR) "Cell Properties";
    psh.nPages = sizeof(psp) / sizeof(PROPSHEETPAGE);
    psh.nStartPage = 0;
    psh.ppsp = (LPCPROPSHEETPAGE) &psp;
    psh.pfnCallback = NULL;

    PropertySheet(&psh);
    return;
}


Processing Notification Messages

A property sheet sends WM_NOTIFY messages to retrieve information from the pages and to notify the pages of user actions. The lParam parameter of the message is the address of an NMHDR structure, which contains the handle of the property sheet dialog box, the handle of the page dialog box, and a notification code. The page must respond to some notification messages by setting the DWL_MSGRESULT value of the page to either TRUE or FALSE.

The following example is a code fragment from the dialog box procedure for a page. It shows how to process the PSN_HELP notification message.

case WM_NOTIFY:
    switch (((NMHDR FAR *) lParam)->code) {

        case PSN_HELP:
             {
             char szBuf[FILE_LEN]; // buffer for name of help file

             // Display help for the font properties page.
             LoadString(g_hinst, IDS_HELPFILE, &szBuf, FILE_LEN)
             WinHelp(((NMHDR FAR *) lParam)->hwndFrom, &szBuf,
                 HELP_CONTEXT, IDH_FONT_PROPERTIES);
             break;
             }
        .
        . // Process other property sheet notifications here.
        .
    }


Property Sheet Reference

The following functions, messages, notification messages, and structures are associated with property sheets. These elements can be grouped as follows.

Property Sheet Creation

CreatePropertySheetPage
DestroyPropertySheetPage
PropertySheet
PROPSHEETHEADER
PROPSHEETPAGE
PropSheetPageProc
PropSheetProc
PSM_ADDPAGE
PSM_REMOVEPAGE

Property Sheet Extensions

AddPropSheetPageProc
ExtensionPropSheetPageProc

Page Activation

PSM_SETCURSEL
PSM_SETCURSELID
PSN_KILLACTIVE
PSN_SETACTIVE

Property Sheet Buttons

PSM_APPLY
PSM_CANCELTOCLOSE
PSM_CHANGED
PSM_PRESSBUTTON
PSM_REBOOTSYSTEM
PSM_RESTARTWINDOWS
PSM_UNCHANGED
PSN_APPLY
PSN_HELP
PSN_QUERYCANCEL
PSN_RESET

Wizard Property Sheets

PSM_SETFINISHTEXT
PSM_SETWIZBUTTONS
PSN_WIZBACK
PSN_WIZFINISH
PSN_WIZNEXT

Miscellaneous Messages

PSM_GETTABCONTROL
PSM_SETTITLE
PSM_QUERYSIBLINGS


Property Sheet Functions

The following functions are used with property sheets.

AddPropSheetPageProc
CreatePropertySheetPage
DestroyPropertySheetPage
ExtensionPropSheetPageProc
PropertySheet
PropSheetPageProc
PropSheetProc


Property Sheet Messages

An application sends messages to direct a property sheet to add and remove pages, enable and disable buttons, set the return value of the PropertySheet function, and so on. The following are the property sheet messages.

PSM_ADDPAGE
PSM_APPLY
PSM_CANCELTOCLOSE
PSM_CHANGED
PSM_GETCURRENTPAGEHWND
PSM_GETTABCONTROL
PSM_ISDIALOGMESSAGE
PSM_PRESSBUTTON
PSM_QUERYSIBLINGS
PSM_REBOOTSYSTEM
PSM_REMOVEPAGE
PSM_RESTARTWINDOWS
PSM_SETCURSEL
PSM_SETCURSELID
PSM_SETFINISHTEXT
PSM_SETTITLE
PSM_SETWIZBUTTONS
PSM_UNCHANGED


Property Sheet Notification Messages

A property sheet sends notification messages to the pages to notify them of events. The following are the property sheet notifications.

PSN_APPLY
PSN_HELP
PSN_KILLACTIVE
PSN_QUERYCANCEL
PSN_RESET
PSN_SETACTIVE
PSN_WIZBACK
PSN_WIZFINISH
PSN_WIZNEXT


Property Sheet Structures

The following structures are used with property sheets.

PROPSHEETHEADER
PROPSHEETPAGE


Rich Edit Controls

A rich edit control is a window in which the user can enter and edit text. The text can be assigned character and paragraph formatting, and can include embedded OLE objects. Rich edit controls provide a programming interface for formatting text. However, an application must implement any user interface components necessary to make formatting operations available to the user.


About Rich Edit Controls

Rich edit controls support almost all of the messages and notification messages used with multiline edit controls. Thus, applications that already use edit controls can be easily changed to use rich edit controls. Additional messages and notifications enable applications to access the functionality unique to rich edit controls. For information about edit controls, see Edit Controls.

An application can send messages to a rich edit control to perform such operations as formatting text, printing, and saving. An application can process notification messages to monitor events in a rich edit control. For example, an application can process notifications to filter keyboard and mouse input, to permit or deny changes to protected text, or to resize the control as needed to fit its content.

You create a rich edit control by using the CreateWindowEx function, specifying the "RichEdit" window class. Because the common control library registers this window class, you must call the LoadLibrary function to ensure that the RICHED32.DLL library is loaded before the rich edit control is created.

Rich edit controls support most of the window styles used with edit controls as well as additional styles. You should specify the ES_MULTILINE window style if you want to allow more than one line of text in the control.


Text Formatting

An application can send messages to a rich edit control to format characters and paragraphs and to retrieve formatting information. Paragraph formatting attributes include alignment, tabs, indents, and numbering. For characters, you can specify typeface, size, color, and effects such as bold, italic, and protected.

You can apply paragraph formatting by using the EM_SETPARAFORMAT message. To determine the current paragraph formatting for the selected text, use the EM_GETPARAFORMAT message. The PARAFORMAT structure is used with both messages to specify paragraph formatting attributes.

You can apply character formatting by using the EM_SETCHARFORMAT message. To determine the current character formatting for the selected text, you can use the EM_GETCHARFORMAT message. The CHARFORMAT structure is used with both messages to specify character attributes.

You can also use EM_SETCHARFORMAT and EM_GETCHARFORMAT messages to set and retrieve the default character formatting, which is the formatting applied to any subsequently inserted characters. For example, if an application sets the default character formatting to bold and the user then types a character, that character is bold.

The default character formatting is applied to newly inserted text only if the current selection is empty. Otherwise, the new text assumes the character formatting of the text it replaces. If the selection changes, the default character formatting changes to match the first character in the new selection.

The protected character effect is unique in that it does not change the appearance of text. If the user attempts to modify protected text, a rich edit control sends its parent window an EN_PROTECTED notification message, allowing the parent window to allow or prevent the change. To receive this notification message, you must enable it by using the EM_SETEVENTMASK message.

Foreground color is a character attribute, but background color is a property of the rich edit control. To set the background color, use the EM_SETBKGNDCOLOR message.


Current Selection in a Rich Edit Control

The user can select text in a rich edit control by using the mouse or the keyboard. The current selection is the range of selected characters, or the position of the insertion point if no characters are selected. An application can get information about the current selection, set the current selection, determine when the current selection changes, and show or hide the selection highlight.

To determine the current selection in a rich edit control, use the EM_EXGETSEL message. To set the current selection, use the EM_EXSETSEL message. The CHARRANGE structure is used with both messages and specifies a range of characters. To retrieve information about the contents of the current selection, you can use the EM_SELECTIONTYPE message.

An application can detect when the current selection changes by processing the EN_SELCHANGE notification message. The notification message specifies a SELCHANGE structure containing information about the new selection. A rich edit control sends this notification message only if you enable it by using the EM_SETEVENTMASK message.

By default, a rich edit control shows and hides the selection highlight when it gains and loses the focus. You can show or hide the selection highlight at any time by using the EM_HIDESELECTION message. For example, an application might provide a Search dialog box to find text in a rich edit control. The application might select matching text without closing the dialog box, in which case it must use the EM_HIDESELECTION message to highlight the selection.

As with edit controls, you can specify the ES_NOHIDESEL window style to prevent a rich edit control from hiding the selection highlight when it loses the focus. You can also use the EM_HIDESELECTION message to change the ES_NOHIDESEL window style after a rich edit control is created.

Instead of using the EM_EXGETSEL and EM_EXSETSEL messages, you retrieve and set the current selection by using the EM_GETSEL and EM_SETSEL edit control messages. The EM_GETSEL message packs two 16-bit character indexes into its 32-bit return value and, therefore, works only for selections that fall entirely within the first 64K. However, a rich edit control will never contain more than 32K of text, unless you extend this limit by using the EM_EXLIMITTEXT message. For selections that extend beyond the first 64K of text, the EM_GETSEL message returns  − 1.


Rich Edit Text Operations

An application can send messages to retrieve or find text in a rich edit control. You can retrieve either the selected text or a specified range of text.

To get the selected text in a rich edit control, use the EM_GETSELTEXT message. The text is copied to the specified character array. You must ensure that the array is large enough to hold the selected text plus a terminating null character.

To retrieve a specified range of text, use the EM_GETTEXTRANGE message. The TEXTRANGE structure used with this message specifies the text range to retrieve and points to a character array that receives the text. Here again, the application must ensure that the array is large enough for the specified text plus a terminating null character.

You can search for a string in a rich edit control by using the EM_FINDTEXT message. The FINDTEXT structure used with this message specifies the text range to search and the string to search for. You can also specify such options as whether the search is case-sensitive.


Word and Line Breaks

A rich edit control calls a function called a word break procedure to find breaks between words and to determine where it can break lines. The control uses this information when performing word wrap operations and when processing the CTRL+LEFT and CTRL+RIGHT key combinations. An application can send messages to a rich edit control to replace the default word break procedure, to retrieve word break information, and to determine what line a given character falls on.

Word break procedures for rich edit controls are similar to those for edit controls, but they have additional capabilities. Word break procedures for both kinds of controls can determine whether a character is a delimiter and can find the nearest word break before or after the specified position. A delimiter is a character that marks the end of a word, such as a space. In an edit control, word breaks occur only after delimiters.

Word break procedures for rich edit controls also group characters into character classes, each identified by a value in the range 0x00 through 0x0F. Word breaks occur either after delimiters or between characters of different classes. Thus, a word break procedure with different classes for alphanumeric and punctuation characters would find two word breaks in the string "WIN.COM".

A character's class can be combined with zero or more word break flags to form an eight-bit value. When performing word wrap operations, a rich edit control uses word break flags to determine where it can break lines. There are the following word break flags.

WBF_BREAKAFTER	Lines may be broken after the character.
WBF_BREAKLINE	The character is a delimiter. Delimiters mark the ends of words. Lines may be broken after delimiters.
WBF_ISWHITE	The character is a white space character. Trailing white space characters are not included in the length of a line when wrapping.
The WBF_BREAKAFTER value is used to allow wrapping after a character that does not mark the end of a word, such as a hyphen.

You can replace a rich edit control's default word break procedure with your own by using the EM_SETWORDBREAKPROC message. For more information about word break procedures, see the description of the EditWordBreakProc function.

Alternately, you can use the EM_SETWORDBREAKPROCEX message to replace the default extended word break procedure with an EditWordBreakProcEx function. This function provides additional information about the text, such as the character set. You can use the EM_GETWORDBREAKPROCEX message to retrieve the address of the current extended word break procedure.

You can use the EM_FINDWORDBREAK message to find word breaks or to determine a character's class and word break flags. In turn, the control calls its word break procedure to get the requested information.

To determine which line a given character falls on, you can use the EM_EXLINEFROMCHAR message.


Rich Edit Clipboard Operations

An application can paste the contents of the clipboard into a rich edit control using either the best available clipboard format or a specific clipboard format. You can also determine whether a rich edit control is capable of pasting a clipboard format.

As with an edit control, you can copy or cut the contents of the current selection by using the WM_COPY or WM_CUT message. Similarly, you can paste the contents of the clipboard into a rich edit control by using the WM_PASTE message. The control pastes the first available format that it recognizes, which presumably is the most descriptive format.

To paste a specific clipboard format, you can use the EM_PASTESPECIAL message. This message is useful for applications with a Paste Special command that enables the user to select the clipboard format. You can use the EM_CANPASTE message to determine whether a given format is recognized by the control.

You can also use the EM_CANPASTE message to determine whether any available clipboard format is recognized by a rich edit control. This message is useful when processing the WM_INITMENUPOPUP message. An application might enable or gray its Paste command depending on whether the control can paste any available format.

Rich edit controls register two clipboard formats: rich-text format and a format called RichEdit Text and Objects. An application can register these formats by using the RegisterClipboardFormat function, specifying the CF_RTF and CF_RETEXTOBJ values.


Streams

You can use streams to transfer data into or out of a rich edit control. A stream is defined by an EDITSTREAM structure, which specifies a buffer and an application-defined callback function.

To read data into a rich edit control (that is, stream the data in), use the EM_STREAMIN message. The control repeatedly calls the application's callback function, which transfers a portion of the data into the buffer each time.

To save the contents of a rich edit control (that is, stream the data out), you can use the EM_STREAMOUT message. The control repeatedly writes to the buffer and then calls the application's callback function. For each call, the callback function saves the contents of the buffer.


Printing

You can send messages to a rich edit control to render its output for a specified device, such as a printer. You can also specify the output device for which a rich edit control formats its text.

To format part of a rich edit control's contents for a specific device, you can use the EM_FORMATRANGE message. The FORMATRANGE structure used with this message specifies the range of text to format as well as the device context (DC) for the target device.

After formatting text for an output device, you can send the output to the device by using the EM_DISPLAYBAND message. By repeatedly using the EM_FORMATRANGE and EM_DISPLAYBAND messages, an application that prints the contents of a rich edit control can implement banding. (Banding is division of output into smaller parts for pringing purposes).

You can use the EM_SETTARGETDEVICE message to specify the target device for which a rich edit control formats its text. This message is useful for WYSIWYG  (what you see is what you get) formatting, in which an application positions text using the default printer's font metrics instead of the screen's.


Bottomless Rich Edit Controls

An application can resize a rich edit control as needed so that it is always the same size as its contents. A rich edit control supports this so-called "bottomless" functionality by sending its parent window an EN_REQUESTRESIZE notification message whenever the size of its contents changes.

When processing the EN_REQUESTRESIZE notification message, an application should resize the control to the dimensions in the specified REQRESIZE structure. An application might also move any information near the control to accommodate the control's change in height. To resize the control, you can use the SetWindowPos function.

You can force a bottomless rich edit control to send an EN_REQUESTRESIZE notification message by using the EM_REQUESTRESIZE message. This message can be useful when processing the WM_SIZE message.

To receive EN_REQUESTRESIZE notification messages, you must enable the notification by using the EM_SETEVENTMASK message.


Miscellaneous Notification Messages

A rich edit control's parent window can process notification messages to monitor events affecting the control. Rich edit controls support all of the notification messages used with edit controls as well as several additional ones. You can determine which notification messages a rich edit control sends its parent window by setting its event mask.

To set the event mask for a rich edit control, use the EM_SETEVENTMASK message. You can retrieve the current event mask for a rich edit control by using the EM_GETEVENTMASK message.

A rich edit control's parent window can filter all keyboard and mouse input to the control by processing the EN_MSGFILTER notification message. The parent window can prevent the keyboard or mouse message from being processed or can change the message by modifying the specified MSGFILTER structure.

An application can process the EN_PROTECTED notification message to detect when the users attempts to modify protected text. To mark a range of text as protected, you can set the protected character effect. For more information, see Text Formatting.

You can enable the user to drop files in a rich edit control by processing the EN_DROPFILES notification message. The specified ENDROPFILES structure contains information about the files being dropped.


Unsupported Edit Control Functionality

Rich edit controls support most but not all of the functionality of multiline edit controls. This section lists the edit control messages and window styles that are not supported by rich edit controls.

The following messages are processed by edit controls but not by rich edit controls.

Unsupported message	Comments
EM_FMTLINES	Not supported.
EM_GETHANDLE	Rich edit controls do not store text as a simple array of characters.
EM_GETMARGINS	Not supported.
EM_GETPASSWORDCHAR	The ES_PASSWORD style is not supported.
EM_SETHANDLE	Rich edit controls do not store text as a simple array of characters.
EM_SETMARGINS	Not supported.
EM_SETPASSWORDCHAR	The ES_PASSWORD style is not supported.
EM_SETRECTNP	Not supported.
EM_SETTABSTOPS	The EM_SETPARAFORMAT message is used instead.
WM_CTLCOLOR	The EM_SETBKGNDCOLOR message is used instead.
WM_GETFONT	The EM_GETCHARFORMAT message is used instead.
The following window styles are used with multiline edit controls but not with rich edit controls:

ES_LOWERCASE	ES_PASSWORD
ES_OEMCONVERT	ES_UPPERCASE


Rich Edit Control Reference

The messages, notification messages, and structures associated with rich edit controls are grouped as follows. Some of these application programming interface (API) elements are also used with edit controls.

Formatting

CHARFORMAT
EM_GETCHARFORMAT
EM_GETPARAFORMAT
EM_GETRECT
EM_SETBKGNDCOLOR
EM_SETCHARFORMAT
EM_SETEVENTMASK
EM_SETPARAFORMAT
EM_SETRECT
PARAFORMAT

Selection and Hit Testing

CHARRANGE
EM_CHARFROMPOS
EM_EXGETSEL
EM_EXSETSEL
EM_GETFIRSTVISIBLELINE
EM_GETSEL
EM_HIDESELECTION
EM_POSFROMCHAR
EM_SELECTIONTYPE
EM_SETSEL
EN_SELCHANGE
SELCHANGE

Text Operations

EM_EXLIMITTEXT
EM_FINDTEXT
EM_GETLIMITTEXT
EM_GETSELTEXT
EM_GETTEXTRANGE
EM_REPLACESEL
EM_SETLIMITTEXT
FINDTEXT
TEXTRANGE

Word and Line Breaks

EM_EXLINEFROMCHAR
EM_FINDWORDBREAK
EM_GETWORDBREAKPROC
EM_SETWORDBREAKPROC
EM_GETWORDBREAKPROCEX
EM_SETWORDBREAKPROCEX
EditWordBreakProcEx

Lines and Scrolling

EM_GETLINE
EM_GETLINECOUNT
EM_GETTHUMB
EM_LINEFROMCHAR
EM_LINEINDEX
EM_LINELENGTH
EM_LINESCROLL
EM_SCROLL
EM_SCROLLCARET

Editing Operations

EM_CANPASTE
EM_CANUNDO
EM_EMPTYUNDOBUFFER
EM_PASTESPECIAL
EM_UNDO

Streams

EDITSTREAM
EM_STREAMIN
EM_STREAMOUT

Printing

EM_DISPLAYBAND
EM_FORMATRANGE
EM_SETTARGETDEVICE
FORMATRANGE

Bottomless Rich Edit Controls

EM_REQUESTRESIZE
EN_REQUESTRESIZE
REQRESIZE

OLE Interfaces

IRichEditOle
IRichEditOleCallback

Miscellaneous

EM_GETEVENTMASK
EM_GETIMECOLOR
EM_GETIMEOPTIONS
EM_GETMODIFY
EM_GETOPTIONS
EM_GETPUNCTUATION
EM_GETWORDWRAPMODE
EM_SETEVENTMASK
EM_SETIMECOLOR
EM_SETIMEOPTIONS
EM_SETEVENTMASK
EM_SETMODIFY
EM_SETREADONLY
EM_SETOPTIONS
EM_SETPUNCTUATION
EM_SETWORDWRAPMODE
EN_CHANGE
EN_CORRECTTEXT
EN_DROPFILES
EN_ERRSPACE
EN_HSCROLL
EN_IMECHANGE
EN_KILLFOCUS
EN_MAXTEXT
EN_MSGFILTER
EN_OLEOPFAILED
EN_PROTECTED
EN_SAVECLIPBOARD
EN_SETFOCUS
EN_STOPNOUNDO
EN_UPDATE
EN_VSCROLL
IMC_GETCOMPOSITIONCOLOR
IMC_SETCOMPOSITIONCOLOR
WM_CONTEXTMENU
WM_CTLCOLOREDIT
COMPCOLOR
ENCORRECTTEXT
ENDROPFILES
ENOLEOPFAILED
ENPROTECTED
ENSAVECLIPBOARD
PUNCTUATION
MSGFILTER


Rich Edit Callback Functions

The following callback function is unique to rich edit controls:

EditWordBreakProcEx


Rich Edit Messages

The following messages are unique to rich edit controls.

EM_CANPASTE
EM_DISPLAYBAND
EM_EXGETSEL
EM_EXLIMITTEXT
EM_EXLINEFROMCHAR
EM_EXSETSEL
EM_FINDTEXT
EM_FINDTEXTEX
EM_FINDWORDBREAK
EM_FORMATRANGE
EM_GETCHARFORMAT
EM_GETEVENTMASK
EM_GETIMECOLOR
EM_GETIMEOPTIONS
EM_GETOLEINTERFACE
EM_GETOPTIONS
EM_GETPARAFORMAT
EM_GETPUNCTUATION
EM_GETSELTEXT
EM_GETTEXTRANGE
EM_GETWORDBREAKPROCEX
EM_GETWORDWRAPMODE
EM_HIDESELECTION
EM_PASTESPECIAL
EM_REQUESTRESIZE
EM_SELECTIONTYPE
EM_SETBKGNDCOLOR
EM_SETCHARFORMAT
EM_SETEVENTMASK
EM_SETIMECOLOR
EM_SETIMEOPTIONS
EM_SETOLEINTERFACE
EM_SETOPTIONS
EM_SETPARAFORMAT
EM_SETPUNCTUATION
EM_SETTARGETDEVICE
EM_SETWORDBREAKPROCEX
EM_SETWORDWRAPMODE
EM_STREAMIN
EM_STREAMOUT
IMC_GETCOMPOSITIONCOLOR
IMC_SETCOMPOSITIONCOLOR
WM_CONTEXTMENU


Rich Edit Notification Messages

Rich edit controls support most of the notification messages used with edit controls, plus the following notification messages. A rich edit control sends the following notification messages only if they have been enabled by using the EM_SETEVENTMASK message.

EN_CORRECTTEXT
EN_DROPFILES
EN_IMECHANGE
EN_MSGFILTER
EN_OLEOPFAILED
EN_PROTECTED
EN_REQUESTRESIZE
EN_SAVECLIPBOARD
EN_SELCHANGE
EN_STOPNOUNDO


Rich Edit Structures

The following structures are used with rich edit controls.

CHARFORMAT
CHARRANGE
COMPCOLOR
EDITSTREAM
ENDROPFILES
ENOLEOPFAILED
ENPROTECTED
ENSAVECLIPBOARD
FINDTEXT
FINDTEXTEX
FORMATRANGE
MSGFILTER
PARAFORMAT
PUNCTUATION
REOBJECT
REPASTESPECIAL
REQRESIZE
SELCHANGE
TEXTRANGE


Rich Edit OLE Interfaces

The rich edit control supports the client functionality defined by OLE. The control provides full support for most OLE client features. It does not support linking to its contents. The client is responsible for dialogs and error messages, managing storage for OLE objects, and document and application window level in-place activation support. The client can use the EM_GETOLEINTERFACE message to obtain an IRichEditOle interface from the rich edit control which allows it to manage objects. The client uses the EM_SETOLEINTERFACE message to register an IRichEditOleCallback interface that the control uses to obtain the required interfaces and storage.

The following OLE interfaces are used with rich text edit controls:

IRichEditOle
IRichEditOleCallback


Rich Edit Constants

The following sections describe constants used with rich edit controls.


Rich Edit Control Styles

The following window styles are unique to rich edit controls:

Style	Description
ES_DISABLENOSCROLL	Disables scrollbars instead of hiding them when they are not needed.
ES_EX_NOCALLOLEINIT	Prevents the control from calling the OleInitialize function when created. Useful only in dialog templates because CreateWindowEx does not accept this style.
ES_NOIME	Disables the input method editor (IME) operation. Available for Asian-languages only.
ES_SAVESEL	Preserves the selection when the control loses the focus. By default, the entire contents of the control are selected when it regains the focus.
ES_SELFIME	Directs the rich edit control to allow the application to handle all IME operations. Available for Asian-languages only.
ES_SUNKEN	Displays the control with a sunken border style so that the rich edit control appears recessed into its parent window. Applications developed for Windows 95 should use WS_EX_CLIENTEDGE instead of ES_SUNKEN.
ES_VERTICAL	Draws text and objects in a vertical direction. Available for Asian-languages only.
Rich edit controls also support the following edit control styles. To allow more than one line of text, you must specify the ES_MULTILINE style.

ES_AUTOHSCROLL	ES_NOHIDESEL
ES_AUTOVSCROLL	ES_READONLY
ES_CENTER	ES_RIGHT
ES_LEFT	ES_WANTRETURN
ES_MULTILINE
Rich edit controls do not support the following edit control styles:

ES_LOWERCASE	ES_PASSWORD
ES_OEMCONVERT	ES_UPPERCASE


Rich Edit Control Event Mask Flags

The event mask specifies which notification messages a rich edit control sends its parent window. The event mask can be zero or more of these values:

Value	Meaning
ENM_CHANGE	Sends EN_CHANGE notifications.
ENM_CORRECTTEXT	Sends EN_CORRECTTEXT notifications.
ENM_DROPFILES	Sends EN_DROPFILES notifications.
ENM_KEYEVENTS	Sends EN_MSGFILTER  notifications for keyboard events.
ENM_MOUSEEVENTS	Sends EN_MSGFILTER notifications for mouse events.
ENM_PROTECTED	Sends EN_PROTECTED notifications.
ENM_RESIZEREQUEST	Sends EN_REQUESTRESIZE notifications.
ENM_SCROLL	Sends EN_HSCROLL notifications.
ENM_SELCHANGE	Sends EN_SELCHANGE notifications.
ENM_UPDATE	Sends EN_UPDATE notifications.
The default event mask is ENM_NONE in which case no notification messages are sent to the parent window. You can retrieve and set the event mask for a rich edit control by using the ENM_GETEVENTMASK and ENM_SETEVENTMASK messages.


Status Windows

A status window is a horizontal window at the bottom of a parent window in which an application can display various kinds of status information. The status window can be divided into parts to display more than one type of information. The following illustration shows the status bar in the Microsoft® Windows® Paint application.


About Status Windows

You can create a status window by using the CreateStatusWindow function or by using the CreateWindowEx function and specifying the STATUSCLASSNAME window class. To ensure that the common control dynamic-link library (DLL) is loaded, use the InitCommonControls function first. After you create the status window, you can divide it into parts, set the text for each part, and control the appearance of the window by using status window messages.


Types and Styles

The default position of a status window is along the bottom of the parent window, but you can specify the CCS_TOP style to have it appear at the top of the parent window's client area.

You can specify the SBARS_SIZEGRIP style to include a sizing grip at the right end of the status window. A sizing grip is similar to a sizing border; it is a rectangular area that the user can click and drag to resize the parent window.

Note  You can combine the CCS_TOP and SBARS_SIZEGRIP styles. Doing so, however, is not recommended, because the resulting sizing grip is not functional even though the system draws it in the status window.


Size and Height

The window procedure for the status window automatically sets the initial size and position of the window, ignoring the values specified in the CreateWindowEx function. The width is the same as that of the parent window's client area. The height is based on the metrics of the font that is currently selected into the status window's device context and on the width of the window's borders.

The window procedure automatically adjusts the size of the status window whenever it receives a WM_SIZE message. Typically, when the size of the parent window changes, the parent sends a WM_SIZE message to the status window.

An application can set the minimum height of a status window's drawing area by sending the window an SB_SETMINHEIGHT message, specifying the minimum height, in pixels. The drawing area does not include the window's borders. A minimum height is useful for drawing in an owner-drawn status window. For more information about owner-drawn status windows, see Owner-Drawn Status Windows.

You retrieve the widths of the borders of a status window by sending the window an SB_GETBORDERS message. The message includes the pointer to a three element array that receives the widths.


Multiple-Part Status Windows

A status window can have many different parts, each displaying a different line of text. You divide a status window into parts by sending the window an SB_SETPARTS message, specifying the number of parts to create and the pointer to an integer array. The array contains one element for each part, and each element specifies the client coordinate of the right edge of a part.

A status window can have a maximum of 255 parts, although applications typically use far fewer than that. You retrieve a count of the parts in a status window, as well as the coordinate of the right edge of each part, by sending the window an SB_GETPARTS message.


Status Window Text Operations

You set the text of any part of a status window by sending the SB_SETTEXT message, specifying the zero-based index of a part, a pointer to the string to draw in the part, and the technique for drawing the string. The drawing technique determines whether the text has a border and, if it does, the style of the border. It also determines whether the parent window is responsible for drawing the text. For more information, see the following topic.

By default, text is left-aligned within the specified part of a status window. You can embed tab characters (\ t) in the text to center or right-align it. Text to the right of a single tab character is centered, and text to the right of a second tab character is right-aligned.

To retrieve text from a status window, use the SB_GETTEXTLENGTH and SB_GETTEXT messages.

If your application uses a status window that has only one part, you can use the WM_SETTEXT, WM_GETTEXT, and WM_GETTEXTLENGTH messages to perform text operations. These messages deal only with the part that has an index of zero, allowing you to treat the status window much like a static text control.

To display a line of status without creating a status window, use the DrawStatusText function. The function uses the same techniques to draw the status as the window procedure for the status window, but it does not automatically set the size and position of the status information. When calling the function, you must specify the size and position of the status information, as well as the device context of the window in which to draw it.


Owner-Drawn Status Windows

You can define individual parts of a status window to be owner-drawn parts. Using this technique gives you more control than you would otherwise have over the appearance of the window part. For example, you can display a bitmap rather than text in a part or draw text using a different font.

To define a window part as owner-drawn, send the SB_SETTEXT message to the status window, specifying the part and the SBT_OWNERDRAW drawing technique. When SBT_OWNERDRAW is specified, the lParam parameter is a 32-bit application-defined value that the application can use when drawing the part. For example, you can specify a font handle, a bitmap handle, a pointer to a string, and so on.

When a status window needs to draw an owner-drawn part, it sends the WM_DRAWITEM message to the parent window. The wParam parameter of the message is the child window identifier of the status window, and the lParam parameter is a pointer to a DRAWITEMSTRUCT structure. The parent window uses the information in the structure to draw the part. For an owner-drawn part of a status window, DRAWITEMSTRUCT contains the following information.

Member	Description
CtlType	Undefined; do not use.
CtlID	Child-window identifier of the status window.
itemID	Zero-based index of the part to be drawn.
itemAction	Undefined; do not use.
itemState	Undefined; do not use.
hwndItem	Handle to the status window.
hDC	Handle to the device context of the status window.
rcItem	Coordinates of the window part to be drawn. The coordinates are relative to the upper left corner of the status window.
itemData	Application-defined 32-bit value specified in the lParam parameter of the SB_SETTEXT message.


Simple Mode Status Windows

You put a status window into "simple mode" by sending it an SB_SIMPLE message. A simple mode status window displays only one part. When the text of the window is set, the window is invalidated, but it is not redrawn until the next WM_PAINT message. Waiting for the message reduces screen flicker by minimizing the number of times the window is redrawn. A simple mode status window is useful for displaying help text for menu items while the user is scrolling through a menu.

The string that a status window displays while in simple mode is maintained separately from the strings that it displays while not in simple mode. This means that you can put the window in simple mode, set its text, and switch back to nonsimple mode without the text being used in either mode.

When setting the text of a simple mode status window, you can specify any drawing technique except SBT_OWNERDRAW. A simple mode status window does not support owner drawing.


Default Status Window Message Processing

This section describes the window messages handled by the window procedure for the predefined STATUSCLASSNAME window class.

Message	Default processing
WM_CREATE	Initializes the status window.
WM_DESTROY	Frees resources allocated for the status window.
WM_GETFONT	Returns the handle to the current font with which the status window draws its text.
WM_GETTEXT	Copies the text from the first part of a status window to a buffer. It returns a 32-bit value that specifies the length, in characters, of the text and the technique used to draw the text.
WM_GETTEXTLENGTH	Returns a 32-bit value that specifies the length, in characters, of the text in the first part of a status window and the technique used to draw the text.
WM_NCHITTEST	Returns the HTBOTTOMRIGHT value if the mouse cursor is in the sizing grip, causing the system to display the sizing cursor. If the mouse cursor is not in the sizing grip, the status window passes this message to the DefWindowProc function.
WM_PAINT	Paints the invalid region of the status window.
WM_SETFONT	Selects the font handle into the device context for the status window.
WM_SETTEXT	Copies the specified text into the first part of a status window, using the default drawing operation (specified as zero). It returns TRUE if successful or FALSE otherwise.
WM_SIZE	Resizes the status window based on the current width of the parent window's client area and the height of the current font of the status window.


Using Status Windows

The following example creates a status window that has a sizing grip and divides the window into four equal parts based on the width of the parent window's client area.

// DoCreateStatusWindow - creates a status window and divides it into

//     the specified number of parts.

// Returns the handle to the status window.

// hwndParent - parent window for the status window

// nStatusID - child window identifier

// hinst - handle to the application instance

// nParts - number of parts into which to divide the status window

HWND DoCreateStatusWindow(HWND hwndParent, int nStatusID,

    HINSTANCE hinst, int nParts)

{

    HWND hwndStatus;

    RECT rcClient;

    HLOCAL hloc;

    LPINT lpParts;

    int i, nWidth;

    // Ensure that the common control DLL is loaded.

    InitCommonControls();

    // Create the status window.

    hwndStatus = CreateWindowEx(

        0,                       // no extended styles

        STATUSCLASSNAME,         // name of status window class

        (LPCTSTR) NULL,          // no text when first created

        SBARS_SIZEGRIP |         // includes a sizing grip

        WS_CHILD,                // creates a child window

        0, 0, 0, 0,              // ignores size and position

        hwndParent,              // handle to parent window

        (HMENU) nStatusID,       // child window identifier

        hinst,                   // handle to application instance

        NULL);                   // no window creation data

    // Get the coordinates of the parent window's client area.

    GetClientRect(hwndParent, &rcClient);

    // Allocate an array for holding the right edge coordinates.

    hloc = LocalAlloc(LHND, sizeof(int) * nParts);

    lpParts = LocalLock(hloc);

    // Calculate the right edge coordinate for each part, and

    // copy the coordinates to the array.

    nWidth = rcClient.right / nParts;

    for (i = 0; i < nParts; i++) {

        lpParts[i] = nWidth;

        nWidth += nWidth;

    }

    // Tell the status window to create the window parts.

    SendMessage(hwndStatus, SB_SETPARTS, (WPARAM) nParts,

        (LPARAM) lpParts);

    // Free the array, and return.

    LocalUnlock(hloc);

    LocalFree(hloc);

    return hwndStatus;

}


Status Window Reference

The following functions and messages are associated with status windows. These elements can be grouped as follows.

Creation

CreateStatusWindow

Size and Height

SB_GETRECT
SB_SETMINHEIGHT
SB_GETBORDERS

Text Operations

DrawStatusText
MenuHelp
SB_GETTEXT
SB_GETTEXTLENGTH
SB_SETTEXT

Multiple Part Status Windows

SB_GETPARTS
SB_SETPARTS

Simple Mode Status Windows

SB_SIMPLE


Status Window Functions

The following functions are used with status windows.

CreateStatusWindow
DrawStatusText
MenuHelp


Status Window Messages

The following messages are used with status windows.

SB_GETBORDERS
SB_GETPARTS
SB_GETRECT
SB_GETTEXT
SB_GETTEXTLENGTH
SB_SETMINHEIGHT
SB_SETPARTS
SB_SETTEXT
SB_SIMPLE


Tab Controls

A tab control is analogous to the dividers in a notebook or the labels in a file cabinet. By using a tab control, an application can define multiple pages for the same area of a window or dialog box. Each page consists of a set of information or a group of controls that the application displays when the user selects the corresponding tab. A special type of tab control displays tabs that look like buttons. Clicking a button should immediately perform a command instead of displaying a page.


About Tab Controls

You can create a tab control by calling the CreateWindowEx function, specifying the WC_TABCONTROL window class. This window class is registered when the common controls dynamic-link library (DLL) is loaded. To ensure that the DLL is loaded, use the InitCommonControls function.

You send messages to a tab control to add tabs and otherwise affect the control's appearance and behavior. Each message has a corresponding macro, which you can use instead of sending the message explicitly. You cannot, however, disable an individual tab in a tab control. However, you can disable a tab control in a property sheet by disabling the corresponding page.


About Tab Control Styles

You can apply specific characteristics to tab controls by specifying tab control styles (window styles specific to tab controls). For example, you can specify the alignment and general appearance of the tabs in a tab control.

You can cause the tabs to look like buttons by specifying the TCS_BUTTONS style. Tabs in this type of tab control should serve the same function as button controls; that is, clicking a tab should carry out a command instead of displaying a page. Because the display area in a button tab control is typically not used, no border is drawn around it.

You can cause a tab to receive the input focus when clicked by specifying the TCS_FOCUSONBUTTONDOWN style. This style is typically used only with the TCS_BUTTONS style. You can specify that a tab never receives the input focus by using the TCS_FOCUSNEVER style.

By default, a tab control displays only one row of tabs. If not all tabs can be shown at once, the tab control displays an up-down control so that the user can scroll additional tabs into view. For more information about up-down controls, see Up-Down Controls. You can cause a tab control to display multiple rows of tabs, if necessary, by specifying the TCS_MULTILINE style. In this way, all tabs can be displayed at once. The tabs are left-aligned within each row unless you specify the TCS_RIGHTJUSTIFY style. In this case, the width of each tab is increased so that each row of tabs fills the entire width of the tab control.

A tab control automatically sizes each tab to fit its icon, if any, and its label. To give all tabs the same width, you can specify the TCS_FIXEDWIDTH style. The control sizes all the tabs to fit the widest label, or you can assign a specific width and height by using the TCM_SETITEMSIZE message. Within each tab, the control centers the icon and label with the icon to the left of the label. You can force the icon to the left, leaving the label centered, by specifying the TCS_FORCEICONLEFT style. You can left-align both the icon and label by using the TCS_FORCELABELLEFT style. You cannot use the TCS_FIXEDWIDTH style with the TCS_RIGHTJUSTIFY style.

You can specify that the parent window draws the tabs in the control by using the TCS_OWNERDRAWFIXED style. For more information about owner-drawn tabs, see Owner-Drawn Tabs.

You can specify that a tab control create a tool tip control by using the TCS_TOOLTIPS style. For more information about using tool tip controls with a tab control, see Tooltip Controls.


Tabs and Tab Attributes

Each tab in a tab control consists of an icon, a label, and application-defined data. This information is specified by a TC_ITEM structure. You can add tabs to a tab control, get the number of tabs, retrieve and set the contents of a tab, and delete tabs. Tabs are identified by their zero-based index.

To add tabs to a tab control, use the TCM_INSERTITEM message, specifying the position of the item and the address of a TC_ITEM structure. You can retrieve and set the contents of an existing tab by using the TCM_GETITEM and TCM_SETITEM messages. For each tab, you can specify an icon, a label, or both. You can also specify application-defined data to associate with the tab.

You can retrieve the current number of tabs by using the TCM_GETITEMCOUNT message, delete a tab by using the TCM_DELETEITEM message, and delete all tabs in a tab control by using the TCM_DELETEALLITEMS message.

You can associate application-defined data with each tab. For example, you might save information about each page with its corresponding tab. By default, a tab control allocates four extra bytes per tab for application-defined data. You can change the number of extra bytes per tab by using the TCM_SETITEMEXTRA message. You can only use this message when the tab control is empty.

The application-defined data is specified by the lParam member of the TC_ITEM structure. If you use more than four bytes of application-defined data, you need to define your own structure and use it instead of TC_ITEM. You can retrieve and set application-defined data the same way you retrieve and set other information about a tab — by using the TCM_GETITEM and TCM_SETITEM messages.

The first member of your structure must be a TC_ITEMHEADER structure, and the remaining members must specify application-defined data. TC_ITEMHEADER is identical to TC_ITEM, except it does not have the lParam member. The difference between the size of your structure and the size of TC_ITEMHEADER should equal the number of extra bytes per tab.


Display Area

The display area of a tab control is the area in which an application displays the current page. Typically, an application creates a child window or dialog box, setting the window size and position to fit the display area. Given the window rectangle for a tab control, you can calculate the bounding rectangle of the display area by using the TCM_ADJUSTRECT message.

Sometimes the display area must be a particular size — for example, the size of a modeless child dialog box. Given the bounding rectangle for the display area, you can use TCM_ADJUSTRECT to calculate the corresponding window rectangle for the tab control.


Tab Selection

When the user selects a tab, a tab control sends its parent window notification messages in the form of WM_NOTIFY messages. The TCN_SELCHANGING notification message is sent before the selection changes, and the TCN_SELCHANGE notification message is sent after the selection changes.

You can process TCN_SELCHANGING to save the state of the outgoing page. You can return TRUE to prevent the selection from changing. For example, you might not want to switch away from a child dialog box in which a control has an invalid setting.

You must process TCN_SELCHANGE to display the incoming page in the display area. This might simply entail changing the information displayed in a child window. More often, each page consists of a child window or dialog box. In this case, an application might process this notification by destroying or hiding the outgoing child window or dialog box and by creating or showing the incoming child window or dialog box.

You can retrieve and set the current selection by using the TCM_GETCURSEL and TCM_SETCURSEL messages.


Tab Control Image Lists

Each tab can have an icon associated with it, which is specified by an index into the image list for the tab control. When a tab control is created, it has no image list associated with it. An application can create an image list by using the ImageList_Create function and then assign it to a tab control by using the TCM_SETIMAGELIST message.

You can add images to a tab control's image list just as you would to any other image list. However, an application should remove images by using the TCM_REMOVEIMAGE message instead of the ImageList_Remove function. This message ensures that each tab remains associated with the same image it had been.

Destroying a tab control does not destroy an image list that is associated with it. You must destroy the image list separately. This is useful if you want to assign the same image list to multiple tab controls.

To retrieve the handle of the image list currently associated with a tab control, you can use the TCM_GETIMAGELIST message.


Tab Size and Position

Each tab in a tab control has a size and position. You can set the size of tabs, retrieve the bounding rectangle of a tab, or determine which tab is at a specified position.

For fixed-width and owner-drawn tab controls, you can set the exact width and height of tabs by using the TCM_SETITEMSIZE message. In other tab controls, each tab's size is calculated based on the icon and label for the tab. The tab control includes space for a border and an additional margin. You can set the thickness of the margin by using the TCM_SETPADDING message.

You can determine the current bounding rectangle for a tab by using the TCM_GETITEMRECT message. You can determine which tab, if any, is at a specified location by using the TCM_HITTEST message.

In a tab control with the TCS_MULTILINE style, you can determine the current number of rows of tabs by using the TCM_GETROWCOUNT message.


Owner-Drawn Tabs

If a tab control has the TCS_OWNERDRAWFIXED style, the parent window must paint tabs by processing the WM_DRAWITEM message. The tab control sends this message whenever a tab needs to be painted. The lParam parameter specifies the address of a DRAWITEMSTRUCT structure, which contains the index of the tab, its bounding rectangle, and the device context (DC) in which to draw.

By default, the itemData member of DRAWITEMSTRUCT contains the value of the lParam member of the TC_ITEM structure. However, if you change the amount of application-defined data per tab, itemData contains a pointer to the data instead. You can change the amount of application-defined data per tab by using the TCM_SETITEMEXTRA message.

To specify the size of items in a tab control, the parent window must process the WM_MEASUREITEM message. Because all tabs in an owner-drawn tab control are the same size, this message is sent only once. There is no tab control style for owner-drawn tabs of varying size. You can also set the width and height of tabs by using the TCM_SETITEMSIZE message.


Tooltip Controls

You can use a tooltip control to provide a brief description of each tab in a tab control. A tab control that has the TCS_TOOLTIPS style creates a tooltip control when it is created, and when the tab control is destroyed, it destroys the tooltip control. You can also create a tooltip control and assign it to a tab control.

If you use a tooltip control with a tab control, the parent window must process the TTN_NEEDTEXT notification message to provide a description of each tab on request.

To use the same tooltip control with more than one tab control, create the tooltip control yourself and assign it to the tab control by using the TCM_SETTOOLTIPS message. You can get the handle of a tab control's current tooltip control by using the TCM_GETTOOLTIPS message. If you use this method, you should not use the TCS_TOOLTIPS style. For more information about tooltip controls, see Tooltip Controls.


Default Tab Control Message Processing

This section describes the message processing performed by a tab control. Messages specific to tab controls are discussed elsewhere and are, therefore, not included here.

Message	Processing performed
WM_CAPTURECHANGED	Does nothing if the tab control released the mouse capture itself. If another window captured the mouse and a button is held down, the command releases the button.
WM_CREATE	Allocates and initializes an internal data structure. The control creates a tool tip control if the TCS_TOOLTIPS style is specified.
WM_DESTROY	Frees resources allocated during WM_CREATE processing.
WM_GETDLGCODE	Returns a combination of the DLGC_WANTARROWS and DLGC_WANTCHARS values.
WM_GETFONT	Returns the handle of the font used for labels.
WM_KEYDOWN	Processes DIRECTION keys and changes the selection, if appropriate.
WM_KILLFOCUS	Invalidates the tab that has the focus, so it will be repainted to reflect an unfocused state.
WM_LBUTTONDOWN	Forwards the message to the tool tip control, if any, and changes the selection if the user is clicking a tab. If the user is clicking a button, the control redraws the button to give a sunken appearance and captures the mouse. If the user is clicking either a tab or button and the TCS_FOCUSONBUTTONDOWN style is specified, the control sets the focus to itself.
WM_LBUTTONUP	Releases the mouse if a button was pressed. If the cursor is over the button and is being held down, the control changes the selection accordingly and redraws the button.
WM_MOUSEMOVE	Forwards the message to the tool tip control, if any. If the TCS_BUTTONS style is specified and the mouse button is being held down after clicking, the control may also redraw the affected button to give it a raised or sunken appearance.
WM_NOTIFY	Forwards notification messages sent by the tool tip control.
WM_PAINT	Draws a border around the display area (unless the TCS_BUTTONS style is specified) and paints any tabs that intersect the invalid rectangle. For each tab, it draws the body of each tab (or sends a WM_DRAWITEM message to the parent window) and then draws a border around the tab.
WM_RBUTTONDOWN	Sends an NM_RCLICK notification message to the parent window.
WM_SETFOCUS	Invalidates the tab that has the focus so that it will be repainted to reflect a focused state.
WM_SETFONT	Sets the font used for labels.
WM_SETREDRAW	Sets the state of an internal flag that determines whether the control is repainted when items are inserted and deleted, when the font is changed, and so on.
WM_SIZE	Recalculates the positions of tabs and may invalidate part of the tab control to force repainting of some or all tabs.


Using Tab Controls

This section provides two examples that use tab controls. The first example uses a tab control to switch between multiple pages of text in an application's main window. The second example uses a tab control to switch between multiple pages of controls in a dialog box.

•	Creating a tab control

•	Creating a tabbed dialog box


Creating a Tab Control

The example in this section creates a tab control and displays it in the client area of the application's main window. The application displays a third window (a static control) in the display area of the tab control. The parent window positions and sizes the tab control and static control when it processes the WM_SIZE message.

There are seven tabs, one for each day of the week. When the user selects a tab, the application displays the name of the corresponding day in the static control. The following global variables are used in this example.

// Global variables

HINSTANCE g_hinst;    // handle of application instance

char g_achTemp[256];  // temporary buffer for strings

HWND g_hwndMain;      // main application window

HWND g_hwndTab;       // tab control

HWND g_hwndDisplay;   // handle of static control in

                      //   tab control's display area

The following function creates the tab control and adds a tab for each day of the week. The names of the days are defined as string resources, consecutively numbered starting with IDS_FIRSTDAY (defined in the application's header file). Both the parent window and the tab control must have the WS_CLIPSIBLINGS window style. The application's initialization function calls this function after creating the main window.

// DoCreateTabControl - creates a tab control, sized to fit the

//     specified parent window's client area, and adds some tabs.

// Returns the handle of the tab control.

// hwndParent - parent window (the application's main window)

HWND WINAPI DoCreateTabControl(HWND hwndParent)

{

    RECT rcClient;

    HWND hwndTab;

    TC_ITEM tie;

    int i;

    // Get the dimensions of the parent window's client area, and

    // create a tab control child window of that size.

    GetClientRect(hwndParent, &rcClient);

    InitCommonControls();

    hwndTab = CreateWindow(

        WC_TABCONTROL, "",

        WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE,

        0, 0, rcClient.right, rcClient.bottom,

        hwndParent, NULL, g_hinst, NULL

        );

    if (hwndTab == NULL)

        return NULL;

    // Add tabs for each day of the week.

    tie.mask = TCIF_TEXT | TCIF_IMAGE;

    tie.iImage = -1;

    tie.pszText = g_achTemp;

    for (i = 0; i < 7; i++) {

        LoadString(g_hinst, IDS_FIRSTDAY + i,

                g_achTemp, sizeof(g_achTemp));

        if (TabCtrl_InsertItem(hwndTab, i, &tie) == -1) {

            DestroyWindow(hwndTab);

            return NULL;

        }

    }

    return hwndTab;

}

The following function creates the static control that occupies the tab control's display area. The application's initialization function calls this function after creating the main window and the tab control.

// DoCreateDisplayWindow - creates a child window (a static

//     control) to occupy the tab control's display area.

// Returns the handle of the static control.

// hwndParent - parent window (the application's main window)

HWND WINAPI DoCreateDisplayWindow(HWND hwndParent)

{

    HWND hwndStatic = CreateWindow("STATIC", "",

        WS_CHILD | WS_VISIBLE | WS_BORDER,

        0, 0, CW_USEDEFAULT, CW_USEDEFAULT,

        hwndParent, NULL, g_hinst, NULL);

    return hwndStatic;

}

Following are the relevant portions of the application's window procedure. The application processes the WM_SIZE message to position and size the tab control and the static control. To determine the appropriate position and size for the static control, this example sends the tab control a TCM_ADJUSTRECT message (by using the TabCtrl_AdjustRect macro).

When a tab is selected, the tab control sends a WM_NOTIFY message, specifying the TCN_SELCHANGE notification message. The application processes this notification message by setting the text of the static control.

// MainWindowProc - processes the message for the main window class.

// The return value depends on the message.

// hwnd - handle of the window

// uMsg - identifier for the message

// wParam - message-specific parameter

// lParam - message-specific parameter

LRESULT CALLBACK MainWindowProc(

        HWND hwnd,

        UINT uMsg,

        WPARAM wParam,

        LPARAM lParam

        )

{

    switch (uMsg) {

        case WM_SIZE: {

                HDWP hdwp;

                RECT rc;

                // Calculate the display rectangle, assuming the

                // tab control is the size of the client area.

                SetRect(&rc, 0, 0,

                        LOWORD(lParam), HIWORD(lParam));

                TabCtrl_AdjustRect(g_hwndTab, FALSE, &rc);

                // Size the tab control to fit the client area.

                hdwp = BeginDeferWindowPos(2);

                DeferWindowPos(hdwp, g_hwndTab, NULL, 0, 0,

                    LOWORD(lParam), HIWORD(lParam),

                    SWP_NOMOVE | SWP_NOZORDER

                    );

                // Position and size the static control to fit the

                // tab control's display area, and make sure the

                // static control is in front of the tab control.

                DeferWindowPos(hdwp,

                    g_hwndDisplay, HWND_TOP, rc.left, rc.top,

                    rc.right - rc.left, rc.bottom - rc.top, 0

                    );

                EndDeferWindowPos(hdwp);

            }

            break;

        case WM_NOTIFY:

            switch (HIWORD(wParam)) {

                case 0:

                    .

                    .    // menu command processing

                    .

                case TCN_SELCHANGE: {

                        int iPage = TabCtrl_GetCurSel(g_hwndTab);

                        LoadString(g_hinst, IDS_FIRSTDAY + iPage,

                            g_achTemp, sizeof(g_achTemp));

                        SendMessage(g_hwndDisplay, WM_SETTEXT, 0

                            (LPARAM) g_achTemp);

                    }

                    break;

            }

            break;

            .

            .       // additional message processing

            .

        default:

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

    }

    return 0;

}


Creating a Tabbed Dialog Box

The example in this section creates a dialog box that uses tabs to provide multiple pages of controls. The main dialog box is a modal dialog box. Each page of controls is defined by a dialog box template that specifies the WS_CHILD style. When a tab is selected, the example creates a modeless dialog box for the incoming page and destroys the dialog box for the outgoing page.

Note  In many cases, you can implement multiple-page dialog boxes more easily by using property sheets. For more information about property sheets, see Property Sheets.

The template for the main dialog box simply defines two button controls. When processing the WM_INITDIALOG message, the dialog box procedure creates a tab control and loads the dialog template resources for each of the child dialog boxes.

The information is saved in an application-defined structure called DLGHDR. A pointer to this structure is associated with the dialog box window by using the SetWindowLong function. The structure is defined in the application's header file, as follows.

#define C_PAGES 3

typedef struct tag_dlghdr {

    HWND hwndTab;       // tab control

    HWND hwndDisplay;   // current child dialog box

    RECT rcDisplay;     // display rectangle for the tab control

    DLGTEMPLATE *apRes[C_PAGES];

} DLGHDR;

The following function processes the WM_INITDIALOG message for the main dialog box. The function allocates the DLGHDR structure, loads the dialog template resources for the child dialog boxes, and creates the tab control.

The size of each child dialog box is specified by the DLGTEMPLATE structure. The function examines the size of each dialog box and uses the macro for the TCM_ADJUSTRECT message to calculate an appropriate size for the tab control. Then it sizes the dialog box and positions the two buttons accordingly. This example sends TCM_ADJUSTRECT by using the TabCtrl_AdjustRect macro.

VOID WINAPI OnTabbedDialogInit(HWND hwndDlg)

{

    DLGHDR *pHdr = (DLGHDR *) LocalAlloc(LPTR, sizeof(DLGHDR));

    DWORD dwDlgBase = GetDialogBaseUnits();

    int cxMargin = LOWORD(dwDlgBase) / 4;

    int cyMargin = HIWORD(dwDlgBase) / 8;

    TC_ITEM tie;

    RECT rcTab;

    HWND hwndButton;

    RECT rcButton;

    int i;

    // Save a pointer to the DLGHDR structure.

    SetWindowLong(hwndDlg, GWL_USERDATA, (LONG) pHdr);

    // Create the tab control.

    pHdr->hwndTab = CreateWindow(

        WC_TABCONTROL, "",

        WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE,

        0, 0, 100, 100,

        hwndDlg, NULL, g_hinst, NULL

        );

    // Add a tab for each of the three child dialog boxes.

    tie.mask = TCIF_TEXT | TCIF_IMAGE;

    tie.iImage = -1;

    tie.pszText = "First";

    TabCtrl_InsertItem(pHdr->hwndTab, 0, &tie);

    tie.pszText = "Second";

    TabCtrl_InsertItem(pHdr->hwndTab, 1, &tie);

    tie.pszText = "Third";

    TabCtrl_InsertItem(pHdr->hwndTab, 2, &tie);

    // Lock the resources for the three child dialog boxes.

    pHdr->apRes[0] = DoLockDlgRes(MAKEINTRESOURCE(DLG_FIRST));

    pHdr->apRes[1] = DoLockDlgRes(MAKEINTRESOURCE(DLG_SECOND));

    pHdr->apRes[2] = DoLockDlgRes(MAKEINTRESOURCE(DLG_THIRD));

    // Determine the bounding rectangle for all child dialog boxes.

    SetRectEmpty(&rcTab);

    for (i = 0; i < C_PAGES; i++) {

        if (pHdr->apRes[i]->cx > rcTab.right)

            rcTab.right = pHdr->apRes[i]->cx;

        if (pHdr->apRes[i]->cy > rcTab.bottom)

            rcTab.bottom = pHdr->apRes[i]->cy;

    }

    rcTab.right = rcTab.right * LOWORD(dwDlgBase) / 4;

    rcTab.bottom = rcTab.bottom * HIWORD(dwDlgBase) / 8;

    // Calculate how large to make the tab control, so

    // the display area can accomodate all the child dialog boxes.

    TabCtrl_AdjustRect(pHdr->hwndTab, TRUE, &rcTab);

    OffsetRect(&rcTab, cxMargin - rcTab.left,

            cyMargin - rcTab.top);

    // Calculate the display rectangle.

    CopyRect(&pHdr->rcDisplay, &rcTab);

    TabCtrl_AdjustRect(pHdr->hwndTab, FALSE, &pHdr->rcDisplay);

    // Set the size and position of the tab control, buttons,

    // and dialog box.

    SetWindowPos(pHdr->hwndTab, NULL, rcTab.left, rcTab.top,

            rcTab.right - rcTab.left, rcTab.bottom - rcTab.top,

            SWP_NOZORDER);

    // Move the first button below the tab control.

    hwndButton = GetDlgItem(hwndDlg, BTN_CLOSE);

    SetWindowPos(hwndButton, NULL,

            rcTab.left, rcTab.bottom + cyMargin, 0, 0,

            SWP_NOSIZE | SWP_NOZORDER);

    // Determine the size of the button.

    GetWindowRect(hwndButton, &rcButton);

    rcButton.right -= rcButton.left;

    rcButton.bottom -= rcButton.top;

    // Move the second button to the right of the first.

    hwndButton = GetDlgItem(hwndDlg, BTN_TEST);

    SetWindowPos(hwndButton, NULL,

        rcTab.left + rcButton.right + cxMargin,

        rcTab.bottom + cyMargin, 0, 0,

        SWP_NOSIZE | SWP_NOZORDER);

    // Size the dialog box.

    SetWindowPos(hwndDlg, NULL, 0, 0,

        rcTab.right + cyMargin +

        2 * GetSystemMetrics(SM_CXDLGFRAME),

        rcTab.bottom + rcButton.bottom + 2 * cyMargin +

        2 * GetSystemMetrics(SM_CYDLGFRAME) +

        GetSystemMetrics(SM_CYCAPTION),

        SWP_NOMOVE | SWP_NOZORDER);

    // Simulate selection of the first item.

    OnSelChanged(hwndDlg);

}

// DoLockDlgRes - loads and locks a dialog template resource.

// Returns a pointer to the locked resource.

// lpszResName - name of the resource

DLGTEMPLATE * WINAPI DoLockDlgRes(LPCSTR lpszResName)

{

    HRSRC hrsrc = FindResource(NULL, lpszResName, RT_DIALOG);

    HGLOBAL hglb = LoadResource(g_hinst, hrsrc);

    return (DLGTEMPLATE *) LockResource(hglb);

}

The following function processes the TCN_SELCHANGE notification message for the main dialog box. The function destroys the dialog box for the outgoing page, if any. Then it uses the CreateDialogIndirect function to create a modeless dialog box for the incoming page.

// OnSelChanged - processes the TCN_SELCHANGE notification.

// hwndDlg - handle of the parent dialog box

VOID WINAPI OnSelChanged(HWND hwndDlg)

{

    DLGHDR *pHdr = (DLGHDR *) GetWindowLong(

        hwndDlg, GWL_USERDATA);

    int iSel = TabCtrl_GetCurSel(pHdr->hwndTab);

    // Destroy the current child dialog box, if any.

    if (pHdr->hwndDisplay != NULL)

        DestroyWindow(pHdr->hwndDisplay);

    // Create the new child dialog box.

    pHdr->hwndDisplay = CreateDialogIndirect(g_hinst,

        pHdr->apRes[iSel], hwndDlg, ChildDialogProc);

}

The following function processes the WM_INITDIALOG message for each of the child dialog boxes. You cannot specify the position of a dialog box created using the CreateDialogIndirect function. This function uses the SetWindowPos function to position the child dialog within the tab control's display area.

// OnChildDialogInit - Positions the child dialog box to fall

//     within the display area of the tab control.

VOID WINAPI OnChildDialogInit(HWND hwndDlg)

{

    HWND hwndParent = GetParent(hwndDlg);

    DLGHDR *pHdr = (DLGHDR *) GetWindowLong(

        hwndParent, GWL_USERDATA);

    SetWindowPos(hwndDlg, HWND_TOP,

        pHdr->rcDisplay.left, pHdr->rcDisplay.top,

        0, 0, SWP_NOSIZE);

}


Tab Control Reference

The messages, notification messages, and structures are associated with tab controls. These elements can be grouped as follows.

Tabs and Tab Attributes

TC_ITEM
TC_ITEMHEADER
TCM_DELETEALLITEMS
TCM_DELETEITEM
TCM_GETITEM
TCM_INSERTITEM
TCM_SETITEM
TCM_SETITEMEXTRA

Tab Selection

TCM_GETCURFOCUS
TCM_GETCURSEL
TCM_SETCURSEL
TCN_SELCHANGE
TCN_SELCHANGING

Tab Size and Position

TC_HITTESTINFO
TCM_ADJUSTRECT
TCM_GETITEMRECT
TCM_GETROWCOUNT
TCM_HITTEST
TCM_SETITEMSIZE
TCM_SETPADDING

Miscellaneous

TC_KEYDOWN
TCM_GETIMAGELIST
TCM_GETITEMCOUNT
TCM_GETTOOLTIPS
TCM_REMOVEIMAGE
TCM_SETIMAGELIST
TCM_SETTOOLTIPS
TCN_KEYDOWN


Tab Control Messages

An application sends messages to add tabs and otherwise control the appearance and behavior of a tab control. Each message has a corresponding macro, which you can use instead of sending the message explicitly.

TCM_ADJUSTRECT
TCM_DELETEALLITEMS
TCM_DELETEITEM
TCM_GETCURFOCUS
TCM_GETCURSEL
TCM_GETIMAGELIST
TCM_GETITEM
TCM_GETITEMCOUNT
TCM_GETITEMRECT
TCM_GETROWCOUNT
TCM_GETTOOLTIPS
TCM_HITTEST
TCM_INSERTITEM
TCM_REMOVEIMAGE
TCM_SETCURSEL
TCM_SETIMAGELIST
TCM_SETITEM
TCM_SETITEMEXTRA
TCM_SETITEMSIZE
TCM_SETPADDING
TCM_SETTOOLTIPS


Tab Control Notification Messages

The following notification messages are used with tab controls.

TCN_KEYDOWN
TCN_SELCHANGE
TCN_SELCHANGING


Tab Control Structures

The following structures are used with tab controls.

TC_HITTESTINFO
TC_ITEM
TC_ITEMHEADER
TC_KEYDOWN


Tab Control Styles

The following window styles are specific to tab controls.

TCS_BUTTONS	Specifies that tabs appear as buttons and no border is drawn around the display area.
TCS_FIXEDWIDTH	Specifies that all tabs are the same width. This style cannot be combined with the TCS_RIGHTJUSTIFY style.
TCS_FOCUSNEVER	Specifies that the tab control never receives the input focus.
TCS_FOCUSONBUTTONDOWN	Specifies that tabs receive the input focus when clicked.
TCS_FORCEICONLEFT	Aligns icons with the left edge of each fixed-width tab. This style can only be used with the TCS_FIXEDWIDTH style.
TCS_FORCELABELLEFT	Aligns labels with the left edge of each fixed-width tab; that is, it displays the label immediately to the right of the icon instead of centering it. This style can only be used with the TCS_FIXEDWIDTH style, and it implies the TCS_FORCEICONLEFT style.
TCS_MULTILINE	Displays multiple rows of tabs, if necessary, so all tabs are visible at once.
TCS_OWNERDRAWFIXED	Specifies that the parent window is responsible for drawing tabs.
TCS_RAGGEDRIGHT	Does not stretch each row of tabs to fill the entire width of the control. This style is the default.
TCS_RIGHTJUSTIFY	Increases the width of each tab, if necessary, so that each row of tabs fills the entire width of the tab control.  This window style is ignored unless the TCS_MULTILINE style is also specified.
TCS_SINGLELINE	Displays only one row of tabs. The user can scroll to see more tabs, if necessary. This style is the default.
TCS_TABS	Specifies that tabs appear as tabs and that a border is drawn around the display area. This style is the default.
TCS_TOOLTIPS	Specifies that the tab control has a tooltip control associated with it. For more information about tooltip controls, see Tooltip Controls.


Toolbars

A toolbar is a control window that contains one or more buttons. Each button sends a command message to the parent window when the user chooses it.


About Toolbars

Typically, the buttons in a toolbar correspond to items in the application's menu, providing an additional and more direct way for the user to access an application's commands. The following illustration shows a window that has a toolbar positioned below the menu bar.

A toolbar has built-in customization features, including a system-defined customization dialog box, that allow the user to insert, delete, or rearrange toolbar buttons. An application determines whether the customization features are available to the user and controls the extent to which the user may customize the toolbar.


Toolbar Creation

You can use the CreateToolbarEx function to create a toolbar and add an initial set of buttons to it. You can also use the CreateWindowEx function, specifying the TOOLBARCLASSNAME window class, but this second method creates a toolbar that initially contains no buttons. You add buttons to the toolbar by using the TB_ADDBUTTONS or TB_INSERTBUTTON message.

The TOOLBARCLASSNAME window class is registered when the common control dynamic-link library (DLL) is loaded. To ensure that this DLL is loaded, use the InitCommonControls function first.

A toolbar must be created as a child window with the WS_CHILD style. If you use CreateWindowEx to create a toolbar, you must specify the WS_CHILD window style. CreateToolbarEx includes the WS_CHILD style by default. You must specify the initial parent window when creating the toolbar, but you can change the parent window after creation by using the TB_SETPARENT message.


Toolbar Size and Position

The window procedure for a toolbar automatically sets the size and position of the toolbar window. The height is based on the height of the buttons in the toolbar. The width is the same as the width of the parent window's client area. The CCS_TOP and CCS_BOTTOM common control styles determine whether the toolbar is positioned along the top or bottom of the client area. By default, a toolbar has the CCS_TOP style.

The toolbar window procedure automatically adjusts the size of the toolbar whenever it receives a WM_SIZE or TB_AUTOSIZE message. An application should send either of these messages whenever the size of the parent window changes or after sending a message that requires the size of the toolbar to be adjusted — for example, the TB_SETBUTTONSIZE message.


Tooltip Style

There is only one class-specific style associated with toolbars: TBSTYLE_TOOLTIPS. When you specify this style, the toolbar creates and manages a tooltip control. A tooltip control is a small pop-up window that contains a line of text describing a toolbar button. The tooltip control is hidden and appears only when the user puts the cursor on a toolbar button, leaving it there for approximately one second. The tooltip control is displayed near the cursor.

When the toolbar receives a WM_MOUSEMOVE message, it sends a notification message to the tooltip control. The tooltip control sets a timer, and after approximately one second, checks if the cursor is still at the same location and is on a toolbar button. If it is, the tooltip control sends the TTN_NEEDTEXT notification message to the parent window to retrieve the descriptive text for the button. Then the tooltip control creates a pop-up window and displays the text in the window. The tooltip control destroys the pop-up window when the user clicks a mouse button or moves the cursor out of the toolbar.

An application that needs to send messages directly to the tooltip control can retrieve the handle of the tooltip by using the TB_GETTOOLTIPS message. An application can replace the tooltip control of a toolbar by using the TB_SETTOOLTIPS message. For more information about tooltip controls, see Tooltip Controls.


Toolbar Bitmaps

Each button in a toolbar can include a bitmapped image. A toolbar stores the information that it needs to draw the images in an internal list. When you call the CreateToolbarEx function, you specify a monochrome or color bitmap that contains the initial images, and the toolbar adds the information to the internal list of images. You can add additional images later by using the TB_ADDBITMAP message.

Each image has a zero-based index. The first image added to the internal list has an index of zero, the second image has an index of one, and so on. TB_ADDBITMAP adds images to the end of the list and returns the index of the first new image that it added. You use an image's index to associate the image with a button.

Windows assumes that all of a toolbar's bitmapped images are the same size. You specify the size when you create the toolbar by using CreateToolbarEx. If you use the CreateWindowEx function to create a toolbar, the size of the images is set to the default dimensions of 16 by 15 pixels. You can use the TB_SETBITMAPSIZE message to change the dimensions of the bitmapped images, but you must do so before adding any images to the internal list of images.


Toolbar Strings

Each button can display a string in addition to, or instead of, an image. A toolbar maintains an internal list that contains all of the strings available to toolbar buttons. You add strings to the internal list by using the TB_ADDSTRING message, specifying the address of the buffer containing the strings to add. Each string must be null-terminated, and the last string must be terminated with two null characters.

Each string has a zero-based index. The first string added to the internal list of strings has an index of zero, the second string has an index of one, and so on. TB_ADDSTRING adds strings to the end of the list and returns the index of the first new string. You use a string's index to associate the string with a button.


Toolbar Buttons

You add buttons to a toolbar by filling an array of TBBUTTON structures and specifying the address of the array either in the TB_ADDBUTTONS message or in a call to the CreateToolbarEx function. You can also use the TB_INSERTBUTTON message, which passes the address of a TBBUTTON structure to the toolbar. Each TBBUTTON structure defines the attributes of a button, including the indexes of its string and bitmap as well as its style, state, command identifier, and application-defined 32-bit value.

If you use the CreateWindowEx function to create a toolbar, you must send the TB_BUTTONSTRUCTSIZE message before adding any buttons. The message passes the size of the TBBUTTON structure to the toolbar.


Toolbar Button Styles

A button's style determines how the button appears and how it responds to user input. The TBSTYLE_BUTTON style creates a toolbar button that behaves like a standard push button. A button that has the TBSTYLE_CHECK style is similar to a standard push button, except it toggles between the pressed and nonpressed states each time the user clicks it.

You can create groups of toolbar buttons by using the TBSTYLE_GROUP or TBSTYLE_CHECKGROUP style, causing a button to stay pressed until the user chooses another button in the group. The TBSTYLE_SEP style creates a small gap between buttons. A button with this style does not receive user input.


Toolbar Button States

Each button in a toolbar has a current state. The toolbar updates a button's state to reflect user actions, such as clicking the button. The state indicates whether the button is currently pressed or not pressed, enabled or disabled, hidden or visible, and so on. Although an application sets a button's initial state when adding the button to the toolbar, it can change and retrieve the state by sending messages to the toolbar. For a list of toolbar button states, see Toolbar States.

An application can use the TB_GETSTATE and TB_SETSTATE messages to retrieve and set the state of a button. In addition, a toolbar includes the following messages that retrieve or set a particular state.

TB_CHECKBUTTON	TB_ISBUTTONCHECKED
TB_ENABLEBUTTON	TB_ISBUTTONENABLED
TB_HIDEBUTTON	TB_ISBUTTONHIDDEN
TB_INDETERMINATE	TB_ISBUTTONINDETERMINATE
TB_PRESSBUTTON	TB_ISBUTTONPRESSED


Command Identifier

Each button has a command identifier associated with it. When the user selects a button, the toolbar sends the parent window a WM_COMMAND message that includes the command identifier of the button. The parent window examines the command identifier and carries out the command associated with the button.


Button Size and Position

A toolbar keeps track of its buttons by assigning each button a position index. The index is zero based; that is, the leftmost button has an index of zero, the next button to the right has an index of one, and so on. An application must specify the index of a button when sending messages to retrieve information about the button or set the button's attributes.

A toolbar updates the position indexes as buttons are inserted and removed. An application can retrieve the current position index of a button by using the TB_COMMANDTOINDEX message. The message specifies the command identifier of a button, and the toolbar window uses the identifier to locate the button and return its position index.

All buttons in a toolbar are the same size. The CreateToolbarEx function requires you to set the initial size of the buttons when you create the toolbar. When you use the CreateWindowEx function to create a toolbar, the initial size is set to the default dimensions of 24 by 22 pixels. You can use the TB_SETBUTTONSIZE message to change the button size, but you must do so before adding any buttons to the toolbar. The TB_GETITEMRECT message retrieves the current dimensions of the buttons.

A toolbar automatically sets the width of its buttons when you add a string to the toolbar that is longer than any current toolbar string. The width is set to accommodate the longest string in the toolbar.


Customization

A toolbar has built in customization features that you can make available to the user by giving the toolbar the CCS_ADJUSTABLE common control style. The customization features allow the user to drag a button to a new position or to remove a button by dragging it off the toolbar. In addition, the user can double-click the toolbar to display the Customize Toolbar dialog box, which allows the user to add, delete, and rearrange toolbar buttons. An application can display the dialog box by using the TB_CUSTOMIZE message.

The toolbar sends notification messages (in the form of WM_NOTIFY messages) to the parent window at each step in the customization process. If the user holds the SHIFT key down and begins dragging a button, the toolbar automatically handles the drag operation. The toolbar sends the TBN_QUERYDELETE notification message to the parent window to determine whether the button may be deleted. The drag operation ends if the parent window returns FALSE. Otherwise, the toolbar captures mouse input and waits for the user to release the mouse button.

When the user releases the mouse button, the toolbar determines the location of the mouse cursor. If the cursor is outside the toolbar, the button is deleted. If the cursor is on another toolbar button, the toolbar sends the TBN_QUERYINSERT notification message to the parent window to determine if a button may be inserted to the left of the given button. The button is inserted if the parent window returns TRUE; otherwise, it is not. The toolbar sends the TBN_TOOLBARCHANGE notification message to signal the end of the drag operation.

If the user begins a drag operation without holding down the SHIFT key, the toolbar sends the TBN_BEGINDRAG notification message to the parent window. An application that implements its own button-dragging code can use this message as a signal to begin a drag operation. The toolbar sends the TBN_ENDDRAG notification message to signal the end of the drag operation.

A toolbar sends notification messages when the user customizes a toolbar by using the Customize Toolbar dialog box. The toolbar sends the TBN_BEGINADJUST notification message after the user double-clicks the toolbar, but before the dialog box is created. Next, the toolbar begins sending a series of TBN_QUERYINSERT notification messages to determine whether the toolbar allows buttons to be inserted. When the parent window returns TRUE, the toolbar stops sending TBN_QUERYINSERT notifications. If the parent window does not return TRUE for any button, the toolbar destroys the dialog box.

Next, the toolbar determines if any buttons may be deleted by sending one TBN_QUERYDELETE notification message for each button in the toolbar. The parent window returns TRUE to indicate that a button may be deleted; otherwise, it returns FALSE. The toolbar adds all toolbar buttons to the dialog box, but it grays those that may not be deleted.

Whenever the toolbar needs information about a button in the Customize Toolbar dialog box, it sends the TBN_GETBUTTONINFO notification message, specifying the index of the button for which it needs information and the address of a TBNOTIFY structure. The parent window must fill the structure with the relevant information.

The Customize Toolbar dialog box includes a Help button and a Reset button. When the user chooses the Help button, the toolbar sends the TBN_CUSTHELP notification message. The parent window should respond by displaying help information. The dialog box sends the TBN_RESET notification message when the user selects the Reset button. This message signals that the toolbar is about to reinitialize the dialog box.

An application can use the TB_SAVERESTORE message to save the current state of a toolbar in an initialization file or to restore the state based on information previously stored in an initialization file. The message saves the state information in the specified initialization file or in the WIN.INI file if no initialization file is specified. An application typically stores the state before the user begins customizing the toolbar in case the user later wants to restore the toolbar to its original state.


Default Message Handling

This section describes the window message processing performed by a toolbar. Because messages specific to toolbars are discussed elsewhere, they are not included here.

Message	Default processing
WM_CHARTOITEM	Forwards this message to the parent window.
WM_COMMAND	Forwards this message to the parent window.
WM_CREATE	Allocates internal memory and graphics objects. It also initializes internal variables and data structures.
WM_DESTROY	Frees all memory and graphics objects previously allocated for the toolbar.
WM_DRAWITEM	Forwards this message to the parent window.
WM_LBUTTONDBLCLK	Forwards this message to the DefWindowProc function and returns the result.
WM_LBUTTONDOWN	Forwards this message to the tooltip control. If a button was clicked, it sets the state of the button and redraws it. It begins a drag operation if the toolbar has the CCS_ADJUSTABLE style and the SHIFT key is down (or the ALT key, if the toolbar has the TBSTYLE_ALTDRAG style).
WM_LBUTTONUP	Forwards this message to the tooltip control. If a button was clicked, it sets the state of the button and redraws it. It also ends the drag operation, if one is underway, and redraws the toolbar.
WM_MEASUREITEM	Forwards this message to the parent window.
WM_MOUSEMOVE	Forwards this message to the tooltip control. If a button has the mouse capture and the cursor moves out of the button rectangle, it redraws the button. It checks whether the toolbar has lost the mouse capture and, if it has, ends the drag operation.
WM_NCACTIVATE, WM_NCPAINT	Redraws the borders of the toolbar if the toolbar does not have the CCS_NODIVIDER style. Otherwise, it forwards the message to the DefWindowProc function.
WM_NOTIFY	Forwards the TTN_NEEDTEXT notification message from the tooltip control to the parent of the toolbar.
WM_PAINT	Draws the toolbar.
WM_SIZE	Recalculates the size and position of the toolbar and redraws it.
WM_SYSCOLORCHANGE	Updates the colors of the buttons and toolbar to march the system colors.
WM_VKEYTOITEM	Forwards this message to the parent window.
WM_WININICHANGE	Reinitializes internal variables that depend on system metric values.


Using Toolbars

•	Creating a toolbar

•	Processing tooltip notification messages


Creating a Toolbar

The following example uses the CreateWindowEx function to create a toolbar that the user can customize and that has a tooltip control associated with it. The example uses the TB_ADDBITMAP and TB_ADDSTRING messages to add button images and buttons strings to the toolbar. The example also adds three buttons by using the TB_ADDBUTTONS message.

// CreateAToolBar - creates a toolbar and adds the initial set of

//     buttons to it.

// Returns the handle of the toolbar if successful or NULL otherwise.

// hwndParent - handle of the parent window

HWND CreateAToolBar(HWND hwndParent)

{

    HWND hwndTB;

    TBADDBITMAP tbab;

    TBBUTTON tbb[3];

    char szBuf[16];

    int iCut, iCopy, iPaste;

    // Ensure that the common control DLL is loaded.

    InitCommonControls();

    // Create a toolbar that the user can customize and that has a

    // tooltip associated with it.

    hwndTB = CreateWindowEx(0, TOOLBARCLASSNAME, (LPSTR) NULL,

        WS_CHILD | TBSTYLE_TOOLTIPS | CCS_ADJUSTABLE,

        0, 0, 0, 0, hwndParent, (HMENU) ID_TOOLBAR, g_hinst, NULL);

    // Send the TB_BUTTONSTRUCTSIZE message, which is required for

    // backward compatibility.

    SendMessage(hwndTB, TB_BUTTONSTRUCTSIZE,

        (WPARAM) sizeof(TBBUTTON), 0);

    // Add the bitmap containing button images to the toolbar.

    tbab.hInst = g_hinst;

    tbab.nID   = IDB_BUTTONS;

    SendMessage(hwndTB, TB_ADDBITMAP, (WPARAM) NUM_BUTTON_BITMAPS,

        (WPARAM) &tbab);

    // Add the button strings to the toolbar.

    LoadString(g_hinst, IDS_CUT, (LPSTR) &szBuf, MAX_LEN);

    iCut = SendMessage(hwndTB, TB_ADDSTRING, 0, (LPARAM) (LPSTR) szBuf);

    LoadString(g_hinst, IDS_COPY, (LPSTR) &szBuf, MAX_LEN);

    iCopy = SendMessage(hwndTB, TB_ADDSTRING, (WPARAM) 0,

        (LPARAM) (LPSTR) szBuf);

    LoadString(g_hinst, IDS_PASTE, (LPSTR) &szBuf, MAX_LEN);

    iPaste = SendMessage(hwndTB, TB_ADDSTRING, (WPARAM) 0,

        (LPARAM) (LPSTR) szBuf);

    // Fill the TBBUTTON array with button information, and add the

    // buttons to the toolbar.

    tbb[0].iBitmap = BMP_CUT;

    tbb[0].idCommand = IDM_CUT;

    tbb[0].fsState = TBSTATE_ENABLED;

    tbb[0].fsStyle = TBSTYLE_BUTTON;

    tbb[0].dwData = 0;

    tbb[0].iString = iCut;

    tbb[1].iBitmap = BMP_COPY;

    tbb[1].idCommand = IDM_COPY;

    tbb[1].fsState = TBSTATE_ENABLED;

    tbb[1].fsStyle = TBSTYLE_BUTTON;

    tbb[1].dwData = 0;

    tbb[1].iString = iCopy;

    tbb[2].iBitmap = BMP_PASTE;

    tbb[2].idCommand = IDM_PASTE;

    tbb[2].fsState = TBSTATE_ENABLED;

    tbb[2].fsStyle = TBSTYLE_BUTTON;

    tbb[2].dwData = 0;

    tbb[2].iString = iPaste;

    SendMessage(hwndTB, TB_ADDBUTTONS, (WPARAM) NUM_BUTTONS,

        (LPARAM) (LPTBBUTTON) &tbb);

    ShowWindow(hwndTB, SW_SHOW);

    return hwndTB;

}


Processing Tooltip Notification Messages

A toolbar that has the TBSTYLE_TOOLTIPS style creates a tooltip control, which an application can use to display help text for toolbar buttons. The parent window receives the TTN_NEEDTEXT notification message when the toolbar needs the help text for a button. The tooltip sends the notification in the form of a WM_NOTIFY message. The lParam parameter includes the address of a TOOLTIPTEXT structure that specifies the command identifier of the button for which help text is needed. An application can copy the help text to the structure, specify the address of a string containing the help text, or specify the instance handle and resource identifier of a string resource.

The following example demonstrates how to process the TTN_NEEDTEXT notification.

case WM_NOTIFY:

    switch (((LPNMHDR) lParam)->code) {

        case TTN_NEEDTEXT:

            {

            LPTOOLTIPTEXT lpttt;

            lpttt = (LPTOOLTIPTEXT) lParam;

            lpttt->hinst = g_hinst;

            // Specify the resource identifier of the descriptive

            // text for the given button.

            idButton = lpttt->hdr.idFrom;

            switch (idButton) {

                case IDM_CUT:

                    lpttt->lpszText = MAKEINTRESOURCE(IDS_TIPS_CUT);

                    break;

                case IDM_COPY:

                    lpttt->lpszText = MAKEINTRESOURCE(IDS_TIPS_COPY);

                    break;

                case IDM_PASTE:

                    lpttt->lpszText = MAKEINTRESOURCE(IDS_TIPS_PASTE);

                    break;

            }

            break;

            }

        .

        . // Process other notifications here.

        .

        default:

            break;

    }


Toolbar Reference

The functions, messages, notification messages, and structures are associated with toolbars. These elements can be grouped as follows.

Toolbar Creation

CreateToolbarEx
TB_BUTTONSTRUCTSIZE
TB_SETPARENT

Toolbar Size and Position

TB_AUTOSIZE
TB_SETBUTTONSIZE

Tooltip Style

TB_GETTOOLTIPS
TB_SETTOOLTIPS
TTN_NEEDTEXT

Toolbar Bitmaps

COLORMAP
CreateMappedBitmap
TB_ADDBITMAP
TB_CHANGEBITMAP
TB_GETBITMAP
TB_GETBITMAPFLAGS
TB_SETBITMAPSIZE
TBADDBITMAP

Toolbar Strings

TB_ADDSTRING
TB_GETBUTTONTEXT

Toolbar Buttons

TB_ADDBUTTONS
TB_BUTTONCOUNT
TB_COMMANDTOINDEX
TB_DELETEBUTTON
TB_GETBUTTON
TB_GETITEMRECT
TB_GETROWS
TB_INSERTBUTTON
TB_SETCMDID
TB_SETROWS
TBBUTTON
TBNOTIFY

Toolbar Button States

TB_CHECKBUTTON
TB_ENABLEBUTTON
TB_GETSTATE
TB_HIDEBUTTON
TB_INDETERMINATE
TB_ISBUTTONCHECKED
TB_ISBUTTONENABLED
TB_ISBUTTONHIDDEN
TB_ISBUTTONINDETERMINATE
TB_ISBUTTONPRESSED
TB_PRESSBUTTON
TB_SETSTATE

Toolbar Customization

TB_CUSTOMIZE
TB_SAVERESTORE
TBN_BEGINADJUST
TBN_BEGINDRAG
TBN_CUSTHELP
TBN_ENDADJUST
TBN_ENDDRAG
TBN_GETBUTTONINFO
TBN_QUERYDELETE
TBN_QUERYINSERT
TBN_RESET
TBN_TOOLBARCHANGE
TBSAVEPARAMS


Toolbar Functions

The following functions are used with toolbars.

CreateMappedBitmap
CreateToolbarEx


Toolbar Messages

The following messages are used with toolbars.

TB_ADDBITMAP
TB_ADDBUTTONS
TB_ADDSTRING
TB_AUTOSIZE
TB_BUTTONCOUNT
TB_BUTTONSTRUCTSIZE
TB_CHANGEBITMAP
TB_CHECKBUTTON
TB_COMMANDTOINDEX
TB_CUSTOMIZE
TB_DELETEBUTTON
TB_ENABLEBUTTON
TB_GETBITMAP
TB_GETBITMAPFLAGS
TB_GETBUTTON
TB_GETBUTTONTEXT
TB_GETITEMRECT
TB_GETROWS
TB_GETSTATE
TB_GETTOOLTIPS
TB_HIDEBUTTON
TB_INDETERMINATE
TB_INSERTBUTTON
TB_ISBUTTONCHECKED
TB_ISBUTTONENABLED
TB_ISBUTTONHIDDEN
TB_ISBUTTONINDETERMINATE
TB_ISBUTTONPRESSED
TB_PRESSBUTTON
TB_SAVERESTORE
TB_SETBITMAPSIZE
TB_SETBUTTONSIZE
TB_SETCMDID
TB_SETPARENT
TB_SETROWS
TB_SETSTATE
TB_SETTOOLTIPS


Toolbar Notification Messages

The parent window receives the following notification messages from a toolbar.

TBN_BEGINADJUST
TBN_BEGINDRAG
TBN_CUSTHELP
TBN_ENDADJUST
TBN_ENDDRAG
TBN_GETBUTTONINFO
TBN_QUERYDELETE
TBN_QUERYINSERT
TBN_RESET
TBN_TOOLBARCHANGE


Toolbar Structures

The following structures are used with toolbars.

COLORMAP
TBADDBITMAP
TBBUTTON
TBNOTIFY
TBSAVEPARAMS


Toolbar Constants

The following style flags and state flags are used with toolbars.


Toolbar Styles

A toolbar can have a combination of the following styles.

TBSTYLE_ALTDRAG	Allows the user to change the position of a toolbar button by dragging it while holding down the ALT key. If this style is not specified, the user must hold down the SHIFT key while dragging a button. Note that the CCS_ADJUSTABLE style must be specified to enable toolbar buttons to be dragged.
TBSTYLE_TOOLTIPS	Creates a tooltip control that an application can use to display descriptive text for the buttons in the toolbar.
TBSTYLE_WRAPABLE	Creates a toolbar that can have multiple lines of buttons. Toolbar buttons can "wrap" to the next line when the toolbar becomes too narrow to include all buttons on the same line. Wrapping occurs on separation and non-group boundaries.
A button in a toolbar can have a combination of the following styles.

TBSTYLE_BUTTON	Creates a standard push button.
TBSTYLE_CHECK	Creates a button that toggles between the pressed and not pressed states each time the user clicks it. The button has a different background color when it is in the pressed state.
TBSTYLE_CHECKGROUP	Creates a check button that stays pressed until another button in the group is pressed.
TBSTYLE_GROUP	Creates a button that stays pressed until another button in the group is pressed.
TBSTYLE_SEP	Creates a separator, providing a small gap between button groups. A button that has this style does not receive user input.


Toolbar States

A toolbar button can have a combination of the following states.

TBSTATE_CHECKED	The button has the TBSTYLE_CHECKED style and is being pressed.
TBSTATE_ENABLED	The button accepts user input. A button not having this state does not accept user input and is grayed.
TBSTATE_HIDDEN	The button is not visible and cannot receive user input.
TBSTATE_INDETERMINATE	The button is grayed.
TBSTATE_PRESSED	The button is being pressed.
TBSTATE_WRAP	A line break follows the button. The button must also have the TBSTATE_ENABLED state.


Tooltip Controls

A tooltip control is a small pop-up window that displays a single line of descriptive text giving the purpose of tools in an application. A tool is either a window, such as a child window or control, or an application-defined rectangular area within a window's client area.


About Tooltip Controls

A tooltip control is hidden most of the time, appearing only when the user puts the cursor on a tool and leaves it there for approximately one-half second. The tooltip control appears near the cursor and disappears when the user clicks a mouse button or moves the cursor off of the tool. A single tooltip control can support any number of tools. The following illustration shows a tooltip control associated with a button in a toolbar control.


Tooltip Creation

You create a tooltip control by using the CreateWindowEx function, specifying the TOOLTIPS_CLASS window class. The class is registered when the common control dynamic-link library (DLL) is loaded. To ensure that this DLL is loaded, include the InitCommonControls function in your application.

The window procedure for a tooltip control automatically sets the size, position, and visibility of the tooltip control. The height of the tooltip window is based on the height of the font currently selected into the device context for the tooltip control. The width varies based on the length of the string currently in the tooltip window.


Style and Activation

A tooltip control has two class-specific styles: TTS_ALWAYSTIP and TTS_NOPREFIX.

A tooltip control with the TTS_ALWAYSTIP style appears when the cursor is on a tool, regardless of whether the tooltip control's owner window is active or inactive. Without this style, the tooltip control appears when the tool's owner window is active, but not when it is inactive.

The TTS_NOPREFIX style prevents the system from stripping the ampersand (&) character from a string. If a tooltip control does not have the TTS_NOPREFIX style, the system automatically strips ampersand characters, allowing an application to use the same string as both a menu item and as text in a tooltip control.

A tooltip control itself can be either active or inactive. When it is active, the tooltip control appears when the cursor is on a tool. When it is inactive, the tooltip control does not appear, even if the cursor is on a tool. The TTM_ACTIVATE message activates and deactivates a tooltip control.

A tooltip control has the WS_POPUP and WS_EX_TOOLWINDOW window styles, regardless of whether you specify them when creating the control.


Types of Tools

A tooltip control can support any number of tools. To support a particular tool, you must register the tool with the tooltip control by sending the TTM_ADDTOOL message to the tooltip control. The message includes the address of a TOOLINFO structure, which provides information the tooltip control needs to display text for the tool. The cbSize member is required and must specify the size of the structure.

A tooltip control supports tools implemented as windows (such as child windows or control windows) and as rectangular areas within a window's client area. When you add a tool implemented as a rectangular area, the hwnd member of TOOLINFO must specify the handle of the window that contains the area, and the rect member must specify the client coordinates of the area's bounding rectangle. In addition, the uId member must specify the application-defined identifier for the tool.

When you add a tool implemented as a window, the uId member of TOOLINFO must contain the window handle of the tool. Also, the uFlags member must specify the TTF_IDISHWND value, which tells the tooltip control to interpret the uId member as a window handle.


Tool Text

When you add a tool to a tooltip control, the lpszText member of the TOOLINFO structure must specify the address of the string to display for the tool. You can change the text any time after adding the tool by using the TTM_UPDATETIPTEXT message.

If the high-order word of lpszText is zero, the low-order word must be the identifier of a string resource. When the tooltip control needs the text, the system loads the specified string resource from the application instance identified by the hinst member of TOOLINFO.

If you specify the LPSTR_TEXTCALLBACK value in the lpszText member, the tooltip control notifies the window specified in the hwnd member of TOOLINFO whenever the tooltip control needs to display text for the tool. The tooltip control sends the TTN_NEEDTEXT notification message to the window. The message includes the address of a TOOLTIPTEXT structure, which contains the window handle as well as the application-defined identifier for the tool. The window examines the structure to determine the tool for which text is needed, and it fills the appropriate structure members with information that the tooltip control needs to display the string.

Many applications create toolbars containing tools that correspond to menu commands. For such tools, it is convenient for the tooltip control to display the same text as the corresponding menu item. The system automatically strips the ampersand (&) accelerator characters from all strings passed to a tooltip control, unless the control has the TTS_NOPREFIX style.

To retrieve the text for a tool, use the TTM_GETTEXT message.


Relaying Mouse Messages to the Tooltip

A tooltip control needs to receive mouse messages to determine when to display the tooltip window. Because Windows sends mouse messages only to the window that contains the cursor, you must use the TTM_RELAYEVENT message to relay mouse messages to the tooltip control.

If a tool is implemented as a rectangular area in an application-defined window, the window procedure receives mouse messages and can relay them to the tooltip control. However, if a tool is implemented as a system-defined window, the mouse messages are sent to the window and are not readily available to the application. You must use a message hook to access and relay the mouse messages, or you must subclass the window.

When a tooltip control receives a relayed WM_MOUSEMOVE message, it determines whether the cursor is in the bounding rectangle of a tool. If the cursor is there, the tooltip control sets a timer. At the end of the time-out duration, the tooltip control checks the position of the cursor to see whether it has moved. If the cursor has not, the tooltip control retrieves the text for the tool, copies the text into the tooltip window, and shows the window. The tooltip control continues to show the window until it receives a relayed button-up or button-down message or until a relayed WM_MOUSEMOVE message indicates that the cursor has moved outside the bounding rectangle of the tool.

A tooltip control actually has three time-out durations associated with it. The initial duration is the length of time that the cursor must remain stationary within the bounding rectangle of a tool before the tooltip window is displayed. The reshow duration is the length of the delay before subsequent tooltip windows are displayed when the cursor moves from one tool to another. The autopopup duration is the length of time that the tooltip window remains displayed before it is hidden. That is, if the cursor remains stationary within the bounding rectangle after the tooltip window is displayed, the tooltip window is automatically hidden at the end of the autopopup duration. You can adjust all of the time-out durations by using the TTM_SETDELAYTIME message.

If an application includes a tool implemented as a rectangular area and the size or position of the control changes, it can use the TTM_NEWTOOLRECT message to report the change to the tooltip control. An application does not need to report size and position changes for a tool implemented as a window. Reporting that is not necessary because the tooltip control uses the window handle of a tool to determine if the cursor is on the tool, not the tool's bounding rectangle.

When it is about to be displayed, a tootip control sends the TTN_SHOW notification to the owner window. A tooltip control sends the TTN_POP notification when it is about to be hidden. Each notification is sent in the context of a WM_NOTIFY message.


Tooltip Hit Testing

The TTM_HITTEST message allows you to retrieve information that a tooltip control maintains about the tool occupying a particular point. The message includes a TTHITTESTINFO structure that contains a window handle, the coordinates of a point, and the address of a TOOLINFO structure. The tooltip control determines whether a tool occupies the point and, if it does, fills TOOLINFO with information about the tool.


Miscellaneous Messages

The TTM_GETCURRENTTOOL and TTM_GETTOOLINFO messages fill a TOOLINFO structure with information about a tool that has been registered with a tooltip control. The TTM_SETTOOLINFO message allows you to change the information that a tooltip control maintains for a particular tool. The TTM_DELTOOL message deletes a tool from a tooltip control.


Default Tooltip Control Message Processing

This section describes the window messages handled by the window procedure for the TOOLTIPS_CLASS window class.

Message	Default processing
WM_CREATE	Ensures that the tooltip control has the WS_EX_TOOLWINDOW and WS_POPUP window styles. It also allocates memory and initializes internal variables.
WM_DESTROY	Frees resources allocated for the tooltip control.
WM_GETFONT	Returns the handle of the font currently selected into the DC for the tooltip control.
WM_MOUSEMOVE	Hides the tooltip window.
WM_PAINT	Draws the tooltip window.
WM_SETFONT	Selects a new font handle into the DC for the tooltip control.
WM_TIMER	Hides the tooltip window if the tool has changed position or if the cursor has moved outside the tool. Otherwise, it shows the tooltip window.
WM_WININICHANGE	Resets internal variables that are based on system metrics.


Using Tooltip Controls

•	Creating a tooltip control

•	Using a tooltip control with a dialog box


Creating a Tooltip Control

The following example creates a tooltip control and adds several tools to it. The example creates a grid of rectangles in the client area of a window and then uses the TTM_ADDTOOL message to add each rectangle to the tooltip control. Note that the window procedure for the owner of the tooltip control must handle mouse messages and pass them on to the tooltip control by using the TTM_RELAYEVENT message.

// DoCreateTooltip - creates a tooltip control and adds some tools

//     to it.

// Returns the handle of the tooltip control if successful or NULL
//     otherwise.

// hwndOwner - handle of the owner window

//

// Global variable

//     g_hinst - handle of the application instance

extern HINSTANCE g_hinst;

HWND DoCreateTooltip(HWND hwndOwner)

{

    HWND hwndTT;    // handle of tooltip

    int row, col;   // rows and columns

    TOOLINFO ti;    // tool information

    int id = 0;     // offset to string identifiers

    static char *szTips[NUM_TIPS] =   // tip text

    {

    "Cut", "Copy", "Paste", "Undo", "Open", "Save"

    };

    // Ensure that the common control DLL is loaded, and create

    // a tooltip control.

    InitCommonControls();

    hwndTT = CreateWindow(TOOLTIPS_CLASS, (LPSTR) NULL, TTS_ALWAYSTIP,

        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,

        NULL, (HMENU) NULL, g_hinst, NULL);

    if (hwndTT == (HWND) NULL)

        return (HWND) NULL;

    // Divide the client area into a grid of rectangles, and add each

    // rectangle to the tooltip.

    for (row = 0; row < MAX_ROWS ; row++ )

        for (col = 0; col < MAX_COLS; col++) {

            ti.cbSize = sizeof(TOOLINFO);

            ti.uFlags = 0;

            ti.hwnd = hwndOwner;

            ti.hinst = g_hinst;

            ti.uId = (UINT) id;

            ti.lpszText = (LPSTR) szTips[id++];

            ti.rect.left = col * CX_COLUMN;

            ti.rect.top = row * CY_ROW;

            ti.rect.right = ti.rect.left + CX_COLUMN;

            ti.rect.bottom = ti.rect.top + CY_ROW;

            if (!SendMessage(hwndTT, TTM_ADDTOOL, 0,

                    (LPARAM) (LPTOOLINFO) &ti))

                return NULL;

        }

    return hwndTT;

}


Using a Tooltip Control with a Dialog Box

The following example includes a set of application-defined functions that implement a tooltip control for a dialog box. The DoCreateDialogTooltip function creates a tooltip control and uses the EnumChildWindows function to enumerate the controls in the dialog box. The enumeration procedure, EnumChildProc, registers each control with the tooltip control. The procedure specifies the dialog box as the parent window of each tooltip control and includes the LPSTR_TEXTCALLBACK value for each tooltip control. As a result, the dialog box receives a WM_NOTIFY message that contains the TTN_NEEDTEXT notification message whenever the tooltip control needs the text for a control. The dialog box procedure calls the OnWMNotify function to process the TTN_NEEDTEXT notifications. OnWMNotify provides the appropriate string based on the identifier of the tooltip control.

The tooltip control needs to receive mouse messages that the system sends to the control windows. To access the messages, the DoCreateDialogTooltip function installs a hook procedure of the WH_GETMESSAGE type. The hook procedure, GetMsgProc, monitors the message stream for mouse messages intended for one of the control windows and relays the messages to the tooltip control.

// DoCreateDialogTooltip - creates a tooltip control for a dialog box,

//     enumerates the child control windows, and installs a hook

//     procedure to monitor the message stream for mouse messages posted

//     to the control windows.

// Returns TRUE if successful or FALSE otherwise.

//

// Global variables

// g_hinst — handle of the application instance

// g_hwndTT — handle of the tooltip control

// g_hwndDlg — handle of the dialog box

// g_hhk — handle of the hook procedure

BOOL DoCreateDialogTooltip(void)

{

    // Ensure that the common control DLL is loaded, and create

    // a tooltip control.

    InitCommonControls();

    g_hwndTT = CreateWindowEx(0, TOOLTIPS_CLASS, (LPSTR) NULL,

        TTS_ALWAYSTIP, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,

        CW_USEDEFAULT, g_hwndDlg, (HMENU) NULL, g_hinst, NULL);

    if (g_hwndTT == NULL)

        return FALSE;

    // Enumerate the child windows to register them with the tooltip
    // control.

    if (!EnumChildWindows(g_hwndDlg, (WNDENUMPROC) EnumChildProc, 0))

        return FALSE;

    // Install a hook procedure to monitor the message stream for mouse

    // messages intended for the controls in the dialog box.

    g_hhk = SetWindowsHookEx(WH_GETMESSAGE, GetMsgProc,

        (HINSTANCE) NULL, GetCurrentThreadId());

    if (g_hhk == (HHOOK) NULL)

        return FALSE;

    return TRUE;

}

// EmumChildProc - registers control windows with a tooltip control by
//     using the TTM_ADDTOOL message to pass the address of a

//     TOOLINFO structure.

// Returns TRUE if successful or FALSE otherwise.

// hwndCtrl - handle of a control window

// lParam - application-defined value (not used)

BOOL EnumChildProc(HWND hwndCtrl, LPARAM lParam)

{

    TOOLINFO ti;

    char szClass[64];

    // Skip static controls.

    GetClassName(hwndCtrl, szClass, sizeof(szClass));

    if (lstrcmp(szClass, "STATIC") {

        ti.cbSize = sizeof(TOOLINFO);

        ti.uFlags = TTF_IDISHWND;

        ti.hwnd = g_hwndDlg;

        ti.uId = (UINT) hwndCtrl;

        ti.hinst = 0;

        ti.lpszText = LPSTR_TEXTCALLBACK;

        SendMessage(g_hwndTT, TTM_ADDTOOL, 0,

            (LPARAM) (LPTOOLINFO) &ti);

    }

    return TRUE;

}

// GetMsgProc - monitors the message stream for mouse messages intended

//     for a control window in the dialog box.

// Returns a message-dependent value.

// nCode - hook code

// wParam - message flag (not used)

// lParam - address of an MSG structure

LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)

{

    MSG *lpmsg;

    lpmsg = (MSG *) lParam;

    if (nCode < 0 || !(IsChild(g_hwndDlg, lpmsg->hwnd)))

        return (CallNextHookEx(g_hhk, nCode, wParam, lParam));

    switch (lpmsg->message) {

        case WM_MOUSEMOVE:

        case WM_LBUTTONDOWN:

        case WM_LBUTTONUP:

        case WM_RBUTTONDOWN:

        case WM_RBUTTONUP:

            if (g_hwndTT != NULL) {

                MSG msg;

                msg.lParam = lpmsg->lParam;

                msg.wParam = lpmsg->wParam;

                msg.message = lpmsg->message;

                msg.hwnd = hwnd;

                SendMessage(g_hwndTT, TTM_RELAYEVENT, 0,

                    (LPARAM) (LPMSG) &msg);

            }

            break;

        default:

            break;

    }

    return (CallNextHookEx(g_hhk, nCode, wParam, lParam));

}

// OnWMNotify - provides the tooltip control with the appropriate text

//     to display for a control window. This function is called by

//     the dialog box procedure in response to a WM_NOTIFY message.

// lParam - second message parameter of the WM_NOTIFY message

VOID OnWMNotify(LPARAM lParam)

{

    LPTOOLTIPTEXT lpttt;

    int idCtrl;

    if ((((LPNMHDR) lParam)->code) == TTN_NEEDTEXT) {

        idCtrl = GetDlgCtrlID((HWND) ((LPNMHDR) lParam)->idFrom);

        lpttt = (LPTOOLTIPTEXT) lParam;

        switch (idCtrl) {

            case ID_HORZSCROLL:

                lpttt->lpszText = "A horizontal scroll bar.";

                return;

            case ID_CHECK:

                lpttt->lpszText = "A check box.";

                return;

            case ID_EDIT:

                lpttt->lpszText = "An edit control.";

                return;

        }

    }

return;

}


Tooltip Control Reference

The following messages and structures are associated with tooltip controls. These elements can be grouped as follows.

Tooltip Activation

TTM_ACTIVATE

Adding and Deleting Tools

TOOLINFO
TTM_ADDTOOL
TTM_DELTOOL

Mouse Messages

TTM_NEWTOOLRECT
TTM_RELAYEVENT
TTM_SETDELAYTIME
TTN_POP
TTN_SHOW

Tool Text

TOOLTIPTEXT
TTM_GETTEXT
TTM_UPDATETIPTEXT
TTN_NEEDTEXT

Tooltip Hit Testing

TTHITTESTINFO
TTM_HITTEST
TTM_WINDOWFROMPOINT

Tool Information

TTM_ENUMTOOLS
TTM_GETCURRENTTOOL
TTM_GETTOOLCOUNT
TTM_GETTOOLINFO
TTM_SETTOOLINFO


Tooltip Control Messages

An application sends messages to activate and deactivate a tooltip control, add and delete tools, and so on.

TTM_ACTIVATE
TTM_ADDTOOL
TTM_DELTOOL
TTM_ENUMTOOLS
TTM_GETCURRENTTOOL
TTM_GETTEXT
TTM_GETTOOLCOUNT
TTM_GETTOOLINFO
TTM_HITTEST
TTM_NEWTOOLRECT
TTM_RELAYEVENT
TTM_SETDELAYTIME
TTM_SETTOOLINFO
TTM_UPDATETIPTEXT
TTM_WINDOWFROMPOINT


Tooltip Control Notification Messages

The following notification messages are used with tooltip controls.

TTN_NEEDTEXT
TTN_POP
TTN_SHOW


Tooltip Control Structures

The following structures are used with tooltip control messages.

TOOLINFO
TOOLTIPTEXT
TTHITTESTINFO


Trackbars

A trackbar is a window that contains a slider and optional tick marks. When the user moves the slider, using either the mouse or the direction keys, the trackbar sends notification messages to indicate the change. The following illustration shows a typical trackbar.


About Trackbars

Trackbars are useful when you want the user to select a discrete value or a set of consecutive values in a range. For example, you might use a trackbar to allow the user to set the repeat rate of the keyboard by moving the slider to a given tick mark.

The slider in a trackbar moves in increments that you specify when you create it. For example, if you specify that the trackbar should have a range of five, the slider can only occupy six positions: a position at the left side of the trackbar and one position for each increment in the range. Typically, each of these positions is identified by a tick mark.

You create a trackbar by using the CreateWindowEx function, specifying the TRACKBAR_CLASS window class. Once you have created a trackbar, you can use trackbar messages to change many of its properties. Changes that you can make include setting the minimum and maximum positions for the slider, drawing tick marks, setting a selection range, and repositioning the slider.


Trackbar Styles

Trackbars can have either a vertical or horizontal orientation. They can have tick marks on either side, both sides, or neither. They can also be used to specify a range of consecutive values. These properties are controlled by using trackbar styles, which you specify when you create the trackbar.

The TBS_HORZ and TBS_VERT styles determine the orientation of the trackbar. If you do not specify an orientation, the trackbar is oriented horizontally.

The TBS_AUTOTICKS style creates a trackbar that has a tick mark for each increment in its range of values. These tick marks are added automatically when an application sends the TBM_SETRANGE message. If you do not specify TBS_AUTOTICKS, you can use messages, such as TBM_SETTIC and TBM_SETTICFREQ, to specify the positions of the tick marks. To create a trackbar that does not display tick marks, you can use the TSM_NOTICKS style.

You can display tick marks on either or both sides of the trackbar. For horizontal trackbars, you can specify the TBS_BOTTOM or TBS_TOP style. For vertical trackbars, you can specify the TBS_RIGHT or TBS_LEFT style. (TBS_BOTTOM and TBS_RIGHT are the default settings.) For tick marks on both sides of the trackbar in any orientation, specify the TBS_BOTH style.

A trackbar can display a selection range only if you specify the TBS_ENABLESELRANGE style when you create it. When a trackbar has this style, the tick marks at the starting and ending positions of a selection range are displayed as triangles (instead of vertical dashes) and the selection range is highlighted. For example, selection ranges might be useful in a simple scheduling application. The user could select a range of tick marks corresponding to hours in a day to identify a scheduled meeting time.

By default, the length of a trackbar's slider varies as the selection range changes. If the trackbar has the TBS_FIXEDLENGTH style, the length of the slider remains the same even if the selection range changes. A trackbar that has the TBS_NOTHUMB style does not include a slider.


Messages to Trackbars

An application can send messages to the trackbar to retrieve information about the window and to change its characteristics.

To retrieve the position of the slider (that is, the value the user has chosen), use the TBM_GETPOS message. To set the position of the slider, use the TBM_SETPOS message.

The range of a trackbar is the set of contiguous values that the trackbar can represent. Most applications use the TBM_SETRANGE message to set the range of a trackbar when it is first created. Applications can dynamically alter the range after the trackbar has been created by using the TBM_SETRANGEMAX and TBM_SETRANGEMIN messages. An application that allows the range to be changed dynamically typically retrieves the final range settings when the user has finished working with the trackbar. To retrieve these settings, use the TBM_GETRANGEMAX and TBM_GETRANGEMIN messages.

An application can use the TBS_AUTOTICKS style to have a trackbar's tick marks displayed automatically. If an application needs to control the position or frequency of the tick marks, however, a number of messages can be used. To set the position of a tick mark, an application can use the TBM_SETTIC message. The TBM_SETTICFREQ message allows an application to set tick marks that appear at regular intervals in the trackbar's range. For example, the application can use this message to display only ten tick marks in a range of 1 through 100. To retrieve the index in the range corresponding to a tick mark, use the TBM_GETTIC message. The TBM_GETPTICS message retrieves an array of these indices. To retrieve the position of a tick mark, in client coordinates, use the TBM_GETTICPOS message. An application can retrieve the number of tick marks by using the TBM_GETNUMTICS message. The TBM_CLEARTICS message removes all of a trackbar's tick marks.

A trackbar's line size determines how far the slider moves when an application receives a TB_LINEDOWN or TB_LINEUP notification message. Similarly, the page size determines the response to the TB_PAGEDOWN and TB_PAGEUP notification messages. Applications can retrieve and set the line and page size values by using the TBM_GETLINESIZE, TBM_SETLINESIZE, TBM_GETPAGESIZE, and TBM_SETPAGESIZE messages.

An application can use messages to retrieve the dimensions of a trackbar. The TBM_GETTHUMBRECT message retrieves the bounding rectangle for the slider. The TBM_GETCHANNELRECT message retrieves the bounding rectangle for the trackbar's channel. (The channel is the area over which the slider moves and which contains the highlight when a range is selected.)

If a trackbar has the TBS_ENABLESELRANGE style, the user can select a range of contiguous values from it. A number of messages allow the selection range to be adjusted dynamically. The TBM_SETSEL message sets the starting and ending positions of a selection. To set just the starting position or just the ending position of a selection, use the TBM_SETSELSTART or TBM_SETSELEND message. When the user has finished setting a selection range, an application can retrieve the settings by using the TBM_GETSELSTART and TBM_GETSELEND messages. To clear a user's selection, use the TBM_CLEARSEL message.


Trackbar Notification Messages

A trackbar notifies its parent window of user actions by sending the parent WM_HSCROLL messages. The low-order word of the wParam parameter of WM_HSCROLL contains the notification code, and the high-order word specifies the position of the slider. The lParam parameter is the handle of the trackbar.

The system sends the TB_BOTTOM, TB_LINEDOWN, TB_LINEUP, and TB_TOP notification messages only when the user interacts with a trackbar by using the keyboard. The TB_THUMBPOSITION and TB_THUMBTRACK notification messages are only sent when the user is using the mouse. The TB_ENDTRACK, TB_PAGEDOWN, and TB_PAGEUP notification messages are sent in both cases. The following table lists the trackbar notification messages and the events (virtual-key codes or mouse events) that cause the notifications to be sent.

Notification message	Reason sent
TB_BOTTOM	VK_END
TB_ENDTRACK	WM_KEYUP (the user released a key that sent a relevant virtual-key code)
TB_LINEDOWN	VK_RIGHT or VK_DOWN
TB_LINEUP	VK_LEFT or VK_UP
TB_PAGEDOWN	VK_NEXT (the user clicked the channel below or to the right of the slider)
TB_PAGEUP	VK_PRIOR (the user clicked the channel above or to the left of the slider)
TB_THUMBPOSITION	WM_LBUTTONUP following a TB_THUMBTRACK notification message
TB_THUMBTRACK	Slider movement (the user dragged the slider)
TB_TOP	VK_HOME


Default Trackbar Message Processing

This section describes the window message processing performed by a trackbar.

Message	Processing performed
WM_CAPTURECHANGED	Kills the timer if one was set during WM_LBUTTONDOWN processing and sends the TB_THUMBPOSITION notification message, if necessary. It always sends the TB_ENDTRACK notification message.
WM_CREATE	Performs additional initialization. It sets the initial tick frequency to 1, the line size to 1, and the page size to  − 1.
WM_DESTROY	Frees resources.
WM_ENABLE	Repaints the trackbar window.
WM_ERASEBKGND	Erases the window background, using the current background color for the trackbar.
WM_GETDLGCODE	Returns the DLGC_WANTARROWS value.
WM_KEYDOWN	Processes the direction keys and sends the TB_TOP, TB_BOTTOM, TB_PAGEUP, TB_PAGEDOWN, TB_LINEUP, and TB_LINEDOWN notification messages, as appropriate.
WM_KEYUP	Sends the TB_ENDTRACK notification message if the key was one of the direction keys.
WM_KILLFOCUS	Repaints the trackbar window.
WM_LBUTTONDOWN	Sets the focus and the mouse capture to the trackbar. When necessary, it sets a timer that determines how quickly the slider moves toward the mouse cursor when the user holds down the mouse button in the window.
WM_LBUTTONUP	Releases the mouse capture and kills the timer if one was set during WM_LBUTTONDOWN processing. It sends the TB_THUMBPOSITION notification message, if necessary. It always sends the TB_ENDTRACK notification message.
WM_MOUSEMOVE	Moves the slider and sends the TB_THUMBTRACK notification message when tracking the mouse (see WM_TIMER).
WM_PAINT	Paints the trackbar.
WM_SETFOCUS	Repaints the trackbar window.
WM_SIZE	Sets the dimensions of the trackbar, removing the slider if there is not enough room to display it.
WM_TIMER	Retrieves the mouse position and updates the position of the slider. (It is received only when the user is dragging the slider.)
WM_WININICHANGE	Initializes slider dimensions.


Using Trackbars

•	Creating a trackbar

•	Processing trackbar notification messages


Creating a Trackbar

The following example shows how to create a trackbar with the TBS_AUTOTICKS and TBS_ENABLESELRANGE styles. When the trackbar is created, both its range and its selection range are initialized. The page size is also set at this time.

// CreateTrackbar - creates and initializes a trackbar.

//

// Global variable

//     g_hinst - instance handle

HWND WINAPI CreateTrackbar(

    HWND hwndDlg,  // handle of dialog box (parent window)

    UINT iMin,     // minimum value in trackbar range

    UINT iMax,     // maximum value in trackbar range

    UINT iSelMin,  // minimum value in trackbar selection

    UINT iSelMax)  // maximum value in trackbar selection

{

    InitCommonControls(); // loads common control's DLL

    hwndTrack = CreateWindowEx(

        0,                             // no extended styles

        TRACKBAR_CLASS,                // class name

        "Trackbar Control",            // title (caption)

        WS_CHILD | WS_VISIBLE |

        TBS_AUTOTICKS | TBS_ENABLESELRANGE,  // style

        10, 10,                        // position

        200, 30,                       // size

        hwndDlg,                       // parent window

        ID_TRACKBAR,             // control identifier

        g_hinst,                       // instance

        NULL                           // no WM_CREATE parameter

        );

    SendMessage(hwndTrack, TBM_SETRANGE,

        (WPARAM) TRUE,                   // redraw flag

        (LPARAM) MAKELONG(iMin, iMax));  // min. & max. positions

    SendMessage(hwndTrack, TBM_SETPAGESIZE,

        0, (LPARAM) 4);                  // new page size

    SendMessage(hwndTrack, TBM_SETSEL,

        (WPARAM) FALSE,                  // redraw flag

        (LPARAM) MAKELONG(iSelMin, iSelMax);

    SendMessage(hwndTrack, TBM_SETPOS,

        (WPARAM) TRUE,                   // redraw flag

        (LPARAM) iSelMin);

    SetFocus(hwndTrack);

    return hwndTrack;

}


Processing Trackbar Notification Messages

The following example is a function that is called whenever a WM_HSCROLL message is received by the dialog box containing the trackbar. The trackbar has the TBS_ENABLESELRANGE style. The position of the slider is compared against the selection range, and the slider is moved to the starting or ending position of the selection range, when necessary.

// TBNotifications - handles trackbar notifications received

//     in the wParam parameter of WM_HSCROLL. This function simply

//     ensures that the slider remains within the selection range.

VOID WINAPI TBNotifications(

    WPARAM wParam,  // wParam of WM_HSCROLL message

    HWND hwndTrack, // handle of trackbar window

    UINT iSelMin,   // minimum value of trackbar selection

    UINT iSelMax)   // maximum value of trackbar selection

{

    DWORD dwPos;    // current position of slider

    switch (LOWORD(wParam)) {

        case TB_ENDTRACK:

            dwPos = SendMessage(hwndTrack, TBM_GETPOS, 0, 0);

            if (dwPos > iSelMax)

                SendMessage(hwndTrack, TBM_SETPOS,

                    (WPARAM) TRUE,       // redraw flag

                    (LPARAM) iSelMax);

            else if (dwPos < iSelMin)

                SendMessage(hwndTrack, TBM_SETPOS,

                    (WPARAM) TRUE,       // redraw flag

                    (LPARAM) iSelMin);

            break;

        default:

            break;

        }

}


Trackbar Reference

The following messages are associated with trackbars.

Size and Position

TBM_GETCHANNELRECT
TBM_GETTHUMBLENGTH
TBM_GETTHUMBRECT
TBM_SETTHUMBLENGTH

Slider Position

TBM_GETPOS
TBM_SETPOS

Line and Page Size

TBM_GETLINESIZE
TBM_GETPAGESIZE
TBM_SETLINESIZE
TBM_SETPAGESIZE

Range

TBM_GETRANGEMAX
TBM_GETRANGEMIN
TBM_SETRANGE
TBM_SETRANGEMAX
TBM_SETRANGEMIN

Selection

TBM_CLEARSEL
TBM_GETSELEND
TBM_GETSELSTART
TBM_SETSEL
TBM_SETSELEND
TBM_SETSELSTART

Tick Marks

TBM_CLEARTICS
TBM_GETNUMTICS
TBM_GETPTICS
TBM_GETTIC
TBM_GETTICPOS
TBM_SETTIC
TBM_SETTICFREQ


Trackbar Messages

An application sends messages to the trackbar to retrieve information about the trackbar and to change its characteristics. The following are the trackbar messages.

TBM_CLEARSEL
TBM_CLEARTICS
TBM_GETCHANNELRECT
TBM_GETLINESIZE
TBM_GETNUMTICS
TBM_GETPAGESIZE
TBM_GETPOS
TBM_GETPTICS
TBM_GETRANGEMAX
TBM_GETRANGEMIN
TBM_GETSELEND
TBM_GETSELSTART
TBM_GETTHUMBLENGTH
TBM_GETTHUMBRECT
TBM_GETTIC
TBM_GETTICPOS
TBM_SETLINESIZE
TBM_SETPAGESIZE
TBM_SETPOS
TBM_SETRANGE
TBM_SETRANGEMAX
TBM_SETRANGEMIN
TBM_SETSEL
TBM_SETSELEND
TBM_SETSELSTART
TBM_SETTHUMBLENGTH
TBM_SETTIC
TBM_SETTICFREQ


Tree-View Controls

A tree-view control is a window that 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. Each item consists of a label and an optional bitmapped image, and each item can have a list of subitems associated with it. By clicking an item, the user can expand and collapse the associated list of subitems. The following illustration shows a tree-view control that displays a table of contents.


About Tree-View Controls

You create a tree-view control by using the CreateWindowEx function, specifying the WC_TREEVIEW window class. The class is registered when the common control dynamic-link library (DLL) is loaded. To ensure that this DLL is loaded, include the InitCommonControls function in your application.

After creating a tree-view control, you add, remove, arrange, or otherwise manipulate items by sending messages to it. Each message has one or more corresponding macros that you can use instead of sending the message explicitly. The macros are documented with the messages in the Reference section of this topic.


Tree-View Styles

Tree-view styles govern aspects of a tree-view control's appearance. You set the initial styles when you create the tree-view control. You can retrieve and change the styles after creating the tree-view control by using the GetWindowLong and SetWindowLong functions.

The TVS_HASLINES style enhances the graphic representation of a tree-view control's hierarchy by drawing lines that link child items to their corresponding parent item. This style does not link items at the root of the hierarchy. To do so, you need to combine the TVS_HASLINES and TVS_LINESATROOT styles.

The user can expand or collapse a parent item's list of child items by double-clicking the parent item. A tree-view control that has the TVS_HASBUTTONS style adds a button to the left side of each parent item. The user can click the button to expand or collapse the child items as an alternative to double-clicking the parent item. TVS_HASBUTTONS does not add buttons to items at the root of the hierarchy. To do so, you must combine TVS_HASLINES, TVS_LINESATROOT, and TVS_HASBUTTONS.

The TVS_EDITLABELS style makes it possible for the user to edit the labels of tree-view items. For more information about editing labels, see Tree-View Label Editing.

The TVS_SHOWSELALWAYS style causes a selected item to remain selected when the tree-view control loses focus.


Parent and Child Items

Any item in a tree-view control can have a list of subitems, which are called child items, associated with it. An item that has one or more child items is called a parent item. A child item is displayed below its parent item and is indented to indicate it is subordinate to the parent. An item that has no parent is at the top of the hierarchy and is called a root item.

You add an item to a tree-view control by sending the TVM_INSERTITEM message to the tree-view control. The message returns a handle of the HTREEITEM type, which uniquely identifies the item. When adding an item, you must specify the handle of the new item's parent item. If you specify NULL or the TVI_ROOT value instead of an parent item handle in the TV_INSERTSTRUCT structure, the item is added as a root item.

At any given time, the state of a parent item's list of child items can be either expanded or collapsed. When the state is expanded, the child items are displayed below the parent item. When it is collapsed, the child items are not displayed. The list automatically toggles between the expanded and collapsed states when the user double-clicks the parent item or, if the parent has the TVS_HASBUTTONS style, when the user clicks the button associated with the parent item. An application can expand or collapse the child items by using the TVM_EXPAND message.

A tree-view control sends the parent window a TVN_ITEMEXPANDING notification message when a parent item's list of child items is about to be expanded or collapsed. The notification gives an application the opportunity to prevent the change or to set any attributes of the parent item that depend on the state of the list of child items. After changing the state of the list, the tree-view control sends the parent window a TVN_ITEMEXPANDED notification message.

When a list of child items is expanded, it is indented relative to the parent item. You can set the amount of indentation by using the TVM_SETINDENT message or retrieve the current amount by using the TVM_GETINDENT message.

A tree-view control uses memory allocated from the heap of the process that creates the tree-view control. The maximum number of items in a tree view is based on the amount of memory available in the heap. Each item takes 64 bytes.


Item Labels

You typically specify the text of an item's label when adding the item to the tree-view control. The TVM_INSERTITEM message includes a TV_ITEM structure that defines the item's properties, including a string containing the text of the label.

A tree-view control allocates memory for storing each item; the text of the item labels takes up a significant portion of this memory. If your application maintains a copy of the strings in the tree-view control, you can decrease the memory requirements of the control by specifying the LPSTR_TEXTCALLBACK value in the pszText member of TV_ITEM instead of passing actual strings to the tree view. Using LPSTR_TEXTCALLBACK causes the tree-view control to retrieve the text of an item's label from the parent window whenever the item needs to be redrawn. To retrieve the text, the tree-view control sends a TVN_GETDISPINFO notification message, which includes the address of a TV_DISPINFO structure. The parent window must fill the appropriate members of the included structure.


Tree-View Label Editing

The user can directly edit the labels of items in a tree-view control that has the TVS_EDITLABELS style. The user begins editing by clicking the label of the item that has the focus. An application begins editing by using the TVM_EDITLABEL message. The tree-view control notifies the parent window when editing begins and when it is canceled or completed. When editing is completed, the parent window is responsible for updating the item's label, if appropriate.

When label editing begins, a tree-view control sends its parent window a TVN_BEGINLABELEDIT notification message. By processing this notification, an application can allow editing of some labels and prevent editing of others. Returning zero allows editing, and returning nonzero prevents it.

When label editing is canceled or completed, a tree-view control sends its parent window a TVN_ENDLABELEDIT notification message. The lParam parameter is the address of a TV_DISPINFO structure. The item member is a TV_ITEM structure that identifies the item and includes the edited text. The parent window is responsible for updating the item's label, if appropriate, perhaps after validating the edited string. The pszText member of TV_ITEM is zero if editing is canceled.

During label editing, typically in response to the TVN_BEGINLABELEDIT notification message, you can get the handle of the edit control used for label editing by using the TVM_GETEDITCONTROL message. You can send the edit control an EM_SETLIMITTEXT message to limit the amount of text a user can enter or subclass the edit control to intercept and discard invalid characters. Note, however, that the edit control is displayed only after TVN_BEGINLABELEDIT is sent.


Tree-View Item Position

An item's initial position is set when the item is added to the tree-view control by using the TVM_INSERTITEM message. The message includes a TV_INSERTSTRUCT structure that specifies the handle of the parent item and the handle of the item after which the new item is to be inserted. The second handle must identify either a child item of the given parent or one of these values: TVI_FIRST, TVI_LAST, or TVI_SORT.

When TVI_FIRST or TVI_LAST is specified, the tree-view control places the new item at the beginning or end of the given parent item's list of child items. When TVI_SORT is specified, the tree-view control inserts the new item into the list of child items in alphabetical order based on the text of the item labels.

You can put a parent item's list of child items into alphabetical order by using the TVM_SORTCHILDREN message. The message includes a parameter that specifies whether all levels of child items descending from the given parent item are also sorted in alphabetical order.

The TVM_SORTCHILDRENCB message allows you to sort child items based on criteria that you define. When you use this message, you specify an application-defined callback function that the tree-view control can call whenever the relative order of two child items needs to be decided. The callback function receives two 32-bit application-defined values for the items being compared and a third 32-bit value that you specify when sending TVM_SORTCHILDRENCB.


Tree-View Item States Overview

Each item in a tree-view control has a current state. For example, an item can be selected, disabled, expanded, and so on. For the most part, the tree-view control automatically sets an item's state to reflect user actions, such as selection of an item. However, you can also set an item's state by using the TVM_SETITEM message and retrieve the current state of an item by using the TVM_GETITEM message. For a complete list of item states, see Tree-View Control Constants.

An item's current state is specified by the state member of the TV_ITEM structure. A tree-view control might change an item's state to reflect a user action, such as selecting the item or setting the focus to the item. In addition, an application might change an item's state to disable or hide the item or to specify an overlay image or state image.

When you specify or change an item's state, the stateMask member of TV_ITEM specifies which state bits to set, and the state member contains the new values for those bits. To set an item's overlay image, stateMask must include the TVIS_OVERLAYMASK value, and state must include the one-based index of the overlay image shifted left eight bits by using the INDEXTOOVERLAYMASK macro. The index can be zero to specify no overlay image. The overlay image must have been added to the tree-view control's list of overlay images by a previous call to the ImageList_SetOverlayImage function. The function specifies the one-based index of the image to add; this is the index used with the INDEXTOOVERLAYMASK macro. A tree-view control can have up to four overlay images.

To set an item's state image, stateMask of TV_ITEM must include the TVIS_STATEIMAGEMASK value, and state must include the one-based index of the state image shifted left twelve bits by using the INDEXTOSTATEIMAGEMASK macro. The index can be zero to specify no state image. For more information about overlay and state images, see Tree-View Image Lists.


Item Selection

A tree-view control notifies the parent window when the selection changes from one item to another by sending the TVN_SELCHANGING and TVN_SELCHANGED notification messages. Both notifications include a value that specifies whether the change is the result of a mouse click or a keystroke. The notifications also include information about the item that is gaining the selection and the item that is losing the selection. You can use this information to set item attributes that depend on the selection state of the item. Returning TRUE in response to TVN_SELCHANGING prevents the selection from changing; returning FALSE allows the change.

An application can change the selection by sending the TVM_SELECTITEM message.


Item Information

Tree-view controls are used with a number of messages that retrieve information about items in the control. TVM_GETITEM retrieves the attributes of an item, including its current state, its selected and nonselected bitmapped images, a count of its child items, a pointer to its label string, and its application-defined 32-bit value.

The TVM_GETNEXTITEM message retrieves the tree-view item that bears the specified relationship to the current item. The message can retrieve an item's parent, the next or previous visible item, the first child item, and so on.

The TVM_GETITEMRECT message retrieves the bounding rectangle for a tree-view item. The TVM_GETCOUNT and TVM_GETVISIBLECOUNT messages retrieve a count of the items in a tree-view control and a count of the items that are currently visible in the tree-view control's window, respectively. You can ensure that a particular item is visible by using the TVM_ENSUREVISIBLE message.


Tree-View Image Lists

Each item in a tree-view control can have a pair of bitmapped images associated with it. The images appear on the left side of an item's label. One image is displayed when the item is selected, and the other is displayed when the item is not selected. For example, an item might display an open folder when it is selected and a closed folder when it is not selected.

To use item images, you must create an image list by using the ImageList_Create function, add the desired bitmaps to the list, and associate the list with the tree-view control by using the TVM_SETIMAGELIST message. By default, all items display the first image in the image list for both the selected and nonselected states. You can change the default behavior for a particular item by specifying the indexes of the selected and nonselected images when adding the item to the tree view using the TVM_INSERTITEM message. You can change the indexes after adding an item by using the TVM_SETITEM message.

A tree-view control's image lists can also contain overlay images, which are designed to be superimposed on item images. A nonzero value in bits 8 through 11 of a tree-view item's state specifies the one-based index of an overlay image (zero indicates no overlay image). Because a 4-bit, one-based index is used, overlay images must be among the first 15 images in the image lists. For more information about tree-view item states, see Tree-View Item States Overview.

If a state image list is specified, a tree-view control reserves space to the left of each item's icon for a state image. An application can use state images, such as checked and cleared check boxes, to indicate application-defined item states. A nonzero value in bits 12 through 15 specifies the one-based index of a state image (zero indicates no state image).

By specifying the I_IMAGECALLBACK value instead of the index of an image in the TV_ITEM structure, you can put off specifying the selected or nonselected image until the item is about to be redrawn. I_IMAGECALLBACK directs the tree view to query the parent window for the index by sending the TVN_GETDISPINFO notification message.

The TVM_GETIMAGELIST message retrieves the handle of a tree-view control's image list. This message is useful if you need to add more images to the list. For more information about image lists, see Image Lists.


Drag and Drop Operations

A tree-view control notifies the parent window when the user starts to drag an item. The parent window receives a TVN_BEGINDRAG notification message when the user begins dragging an item with the left mouse button and a TVN_BEGINRDRAG notification message when the user begins dragging with the right button. You can prevent a tree-view control from sending these notifications by giving the tree-view control the TVS_DISABLEDRAGDROP style.

You obtain an image to display during a drag operation by using the TVM_CREATEDRAGIMAGE message. The tree-view control creates a dragging bitmap based on the label of the item being dragged. Then the tree-view control creates an image list, adds the bitmap to it, and returns the handle of the image list.

You must provide the code that actually drags the item. This typically involves using the dragging capabilities of the image list functions and processing the WM_MOUSEMOVE and WM_LBUTTONUP (or WM_RBUTTONUP) messages sent to the parent window after the drag operation has begun. For more information about the image list functions, see Image Lists. For more information about dragging a tree-view item, see Dragging a Tree-View Item.

If items in a tree-view control are to be the targets of a drag and drop operation, you need to know when the mouse cursor is on a target item. You can find out by using the TVM_HITTEST message. You specify the address of a TV_HITTESTINFO structure that contains the current coordinates of the mouse cursor. When the SendMessage function returns, the structure contains a flag indicating the location of the mouse cursor relative to the tree-view control. If the cursor is over an item in the tree-view control, the structure contains the handle of the item as well.

You can indicate that an item is the target of a drag and drop operation by using the TVM_SETITEM message to set the state to the TVIS_DROPHILITED value. An item that has this state is drawn in the style used to indicate a drag and drop target.


About Tree-View Control Notification Messages

A tree-view control sends the following notification messages to its parent window in the form of WM_NOTIFY messages.

Notification	Description
TVN_BEGINDRAG	Signals the start of a drag and drop operation.
TVN_BEGINLABELEDIT	Signals the start of in-place label editing.
TVN_BEGINRDRAG	Signals the start of a drag and drop operation, using the right mouse button.
TVN_DELETEITEM	Signals the deletion of a specific item.
TVN_ENDLABELEDIT	Signals the end of label editing.
TVN_GETDISPINFO	Requests information that the tree-view control requires to display an item.
TVN_ITEMEXPANDED	Signals that a parent item's list of child items was expanded or collapsed.
TVN_ITEMEXPANDING	Signals that a parent item's list of child items is about to be expanded or collapsed.
TVN_KEYDOWN	Signals a keyboard event.
TVN_SELCHANGED	Signals that the selection has changed from one item to another.
TVN_SELCHANGING	Signals that the selection is about to be changed from one item to another.
TVN_SETDISPINFO	Notifies a parent window that it must update the information it maintains for an item.


Default Tree-View Controls Message Processing

This section describes the window message processing performed by a tree-view control. Because messages specific to tree-view controls are discussed elsewhere, they are not included here.

Message	Processing performed
WM_COMMAND	Processes the EN_UPDATE and EN_KILLFOCUS edit control notification  messages and forwards all other edit control notifications to the parent window. There is no return value.
WM_CREATE	Allocates memory and initializes internal data structures. It returns zero if successful or  − 1 otherwise.
WM_DESTROY	Frees all system resources associated with the control. It returns zero.
WM_ENABLE	Enables or disables the control.
WM_ERASEBKGND	Erases the window background using the current background color for the tree-view control. It returns TRUE.
WM_GETDLGCODE	Returns a combination of the DLGC_WANTARROWS and DLGC_WANTCHARS values.
WM_GETFONT	Returns the handle of the current label font.
WM_HSCROLL	Scrolls the tree-view control. It returns TRUE if scrolling occurs or FALSE otherwise.
WM_KEYDOWN	Sends the NM_RETURN notification message when the user presses the ENTER key. It moves the caret when the user presses the direction keys or the PAGE UP, PAGE DOWN, HOME, END, or BACKSPACE key. It scrolls the tree-view control when the user presses the CTRL key in combination with those keys. It sends the TVN_KEYDOWN notification message to the parent window. It returns TRUE if a key is processed or FALSE otherwise.
WM_KILLFOCUS	Repaints the focused item, if any, and sends an NM_KILLFOCUS notification message to the parent window.
WM_LBUTTONDBLCLK	Cancels label editing and, if an item was double-clicked, sends the NM_DBLCLK or NM_RDBLCLK notification message to the parent window. If the parent window returns TRUE, the tree-view control toggles the expanded state of the item, sending the parent window the TVN_ITEMEXPANDING and TVN_ITEMEXPANDED notification messages. There is no return value.
WM_LBUTTONDOWN	Toggles the expanded state if the user clicked the button associated with a parent item. If the user clicked an item label, the tree-view control selects and sets the focus to the item. If the user moves the mouse before releasing the mouse button, the tree-view control begins a drag and drop operation. There is no return value.
WM_PAINT	Paints the invalid region of the tree-view control. It returns zero.
WM_RBUTTONDOWN	Checks to see if an item was clicked and a drag operation was begun. If the operation has begun, it sends a TVN_BEGINRDRAG notification message to the parent window and highlights the drop target. Otherwise, it sends an NM_RCLICK notification message to the parent window. There is no return value.
WM_SETFOCUS	Repaints the focused item, if any, and sends an NM_SETFOCUS notification message to the parent window.
WM_SETFONT	Saves the specified font handle and repaints the tree-view control using the new font.
WM_SETREDRAW	Sets or clears the redraw flag. The tree-view control is redrawn after the redraw flag is set. It returns zero.
WM_SIZE	Recomputes internal variables that depend on the size of the tree-view control's client area. It returns TRUE.
WM_STYLECHANGED	Cancels label editing and redraws the tree-view control using the new styles. It returns zero.
WM_SYSCOLORCHANGE	Redraws the tree-view control using the new color if the redraw flag is set. There is no return value.
WM_TIMER	Begins editing an item label. If the user clicks the label of the focused item, the tree-view control sets a timer instead of entering edit mode immediately. The timer makes it possible for the tree view to avoid entering edit mode if the user double-clicks the label. It returns zero.
WM_VSCROLL	Scrolls the tree-view control. It returns TRUE if scrolling occurs or FALSE otherwise.


Using Tree-View Controls

•	Creating a tree-view control

•	Initializing the image list

•	Adding tree-view items

•	Dragging a tree-view item


Creating a Tree-View Control

To create a tree-view control, use the CreateWindowEx function, specifying the WC_TREEVIEW value for the window class. The tree-view window class is registered in the application's address space when the common control dynamic-link library (DLL) is loaded. To ensure that the DLL is loaded, use the InitCommonControls function.

The following example creates a tree-view control that is sized to fit the client area of the parent window. It also uses application-defined functions to associate an image list with the control and add items to the control.

// CreateATreeView - creates a tree-view control.

// Returns the handle of the new control if successful or NULL
//     otherwise.

// hwndParent - handle of the control's parent window

// lpszFileName - name of the file to parse for tree-view items

HWND CreateATreeView(HWND hwndParent, LPSTR lpszFileName)

{

    RECT rcClient;  // dimensions of client area

    HWND hwndTV;    // handle of tree-view control

    // Ensure that the common control DLL is loaded.

    InitCommonControls();

    // Get the dimensions of the parent window's client area, and create

    // the tree-view control.

    GetClientRect(hwndParent, &rcClient);

    hwndTV = CreateWindowEx(0, WC_TREEVIEW, "Tree View",

        WS_VISIBLE | WS_CHILD | WS_BORDER | TVS_HASLINES,

        0, 0, rcClient.right, rcClient.bottom,

        hwndParent, (HMENU) ID_TREEVIEW, g_hinst, NULL);

    // Initialize the image list, and add items to the control.

    // InitTreeViewImageLists and InitTreeViewItems are application-

    // defined functions.

    if (!InitTreeViewImageLists(hwndTV) ||

            !InitTreeViewItems(hwndTV, lpszFileName)) {

        DestroyWindow(hwndTV);

        return FALSE;

    }

    return hwndTV;

}


Initializing the Image List

Every item in a tree-view control can have two images associated with it. An item displays one image when it is selected and the other when it is not. To include images with tree-view items, you must use the image list functions to create an image list and add images to it. Then you must associate the image list with the tree-view control by using the TVM_SETIMAGELIST message.

The following example creates an image list, adds three bitmaps to the list, and associates the image list with a tree-view control.

// InitTreeViewImageLists - creates an image list, adds three bitmaps to //     it, and associates the image list with a tree-view control.

// Returns TRUE if successful or FALSE otherwise.

// hwndTV - handle of the tree-view control

//
// Global variables and constants

//     g_nOpen, g_nClosed, and g_nDocument - integer variables for

//         indexes of the images

//     CX_BITMAP and CY_BITMAP - width and height of an icon

//     NUM_BITMAPS - number of bitmaps to add to the image list

BOOL InitTreeViewImageLists(HWND hwndTV)

{

    HIMAGELIST himl;  // handle of image list

    HBITMAP hbmp;     // handle of bitmap

    // Create the image list.

    if ((himl = ImageList_Create(CX_BITMAP, CY_BITMAP,

            FALSE, NUM_BITMAPS, 0)) == NULL)

        return FALSE;

    // Add the open file, closed file, and document bitmaps.

    hbmp = LoadBitmap(g_hinst, MAKEINTRESOURCE(IDB_OPEN_FILE));

    g_nOpen = ImageList_Add(himl, hbmp, (HBITMAP) NULL);

    DeleteObject(hbmp);

    hbmp = LoadBitmap(g_hinst, MAKEINTRESOURCE(IDB_CLOSED_FILE));

    g_nClosed = ImageList_Add(himl, hbmp, (HBITMAP) NULL);

    DeleteObject(hbmp);

    hbmp = LoadBitmap(g_hinst, MAKEINTRESOURCE(IDB_DOCUMENT));

    g_nDocument = ImageList_Add(himl, hbmp, (HBITMAP) NULL);

    DeleteObject(hbmp);

    // Fail if not all of the images were added.

    if (ImageList_GetImageCount(himl) < 3)

        return FALSE;

    // Associate the image list with the tree-view control.

    TreeView_SetImageList(hwndTV, himl, TVSIL_NORMAL);

    return TRUE;

}


Adding Tree-View Items

You add an item to a tree-view control by sending the TVM_INSERTITEM message to the control. The message includes a pointer to a TV_INSERTSTRUCT structure, specifying the parent item, the item after which the new item is inserted, and a TV_ITEM structure that defines the attributes of the item. The attributes include the item's label, its selected and nonselected images, and a 32-bit application-defined value.

The example in this section creates a table of contents based on the information in a text file. The example includes two functions. The first function searches a file for headings. When it finds one, it extracts the text of the heading and the value that indicates the level of the heading and then passes them to the second function. Headings are assumed to be in the following form, .[heading].n, where heading is the text of the heading and n indicates the heading level. The example ignores heading levels greater than level four.

The second function adds an item to a tree-view control, using the heading text as the item's label and the heading level to determine the parent item for the new item. A level one heading is added to the root of the tree-view control, a level two heading is added as a child item of the previous level one item, and so on. The function assigns an image to an item based on whether it has any child items. If an item has child items, it gets an image representing a closed folder. Otherwise, it gets an image representing a document. An item uses the same image for both the selected and nonselected states.

// InitTreeViewItems - extracts headings from the specified file and

//     passes them to a function that adds them to a tree-view control.

// Returns TRUE if successful or FALSE otherwise.

// hwndTV - handle of the tree-view control

// lpszFileName - name of file with headings

BOOL InitTreeViewItems(HWND hwndTV, LPSTR lpszFileName)

{

    HANDLE hf;            // handle of file

    DWORD cbRead;         // number of bytes read

    char szItemText[128]; // label text of tree-view item

    int nLevel;           // heading level

    LPCH pch;             // pointer to data read from file

    LPCH pchTmp;          // temporary pointer

    DWORD i, j;           // counters

    // Open the file to parse.

    if ((hf = CreateFile(lpszFileName, GENERIC_READ,

            FILE_SHARE_READ, (LPSECURITY_ATTRIBUTES) NULL,

            OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,

            (HANDLE) NULL)) == (HANDLE) INVALID_HANDLE_VALUE)

        return FALSE;

    // Parse the file looking for headings.

    pch = (LPCH) LocalAlloc(LPTR, sizeof(char) * 2048);

    pchTmp = pch;

    do {

        // Read a chunk of the file.

        ReadFile(hf, pchTmp, sizeof(char) * 2048, &cbRead,

            (LPOVERLAPPED) NULL);

        // Parse the chunk looking for ".[".

        for (i = 0, j = 0; i < cbRead; i++) {

            if ((i + 2) > cbRead)    // break if end of chunk

                break;

             // Extract the heading text from between the brackets.

            if ((*pchTmp == '.') && (*(pchTmp+1) == '[')) {

                pchTmp = pchTmp + 2;

                i += 2;

                while (*pchTmp != ']' && ((i++) <= cbRead) )

                    szItemText[j++] = *pchTmp++;

                szItemText[j] = '\0';

                j = 0;

                nLevel = atoi(pchTmp + 2);

                // Add the item to the tree-view control.

                AddItemToTree(hwndTV, (LPSTR) &szItemText, nLevel);

            } else

                ++pchTmp;

        }

        pchTmp = pch;

    } while (cbRead != 0);

    CloseHandle((HANDLE) hf);

    return TRUE;

}

// AddItemToTree - adds items to a tree-view control.

// Returns the handle of the newly added item.

// hwndTV - handle of the tree-view control

// lpszItem - text of the item to add

// nLevel - level at which to add the item

HTREEITEM AddItemToTree(HWND hwndTV, LPSTR lpszItem, int nLevel)

{

    TV_ITEM tvi;

    TV_INSERTSTRUCT tvins;

    static HTREEITEM hPrev = (HTREEITEM) TVI_FIRST;

    static HTREEITEM hPrevRootItem = NULL;

    static HTREEITEM hPrevLev2Item = NULL;

    HTREEITEM hti;

    tvi.mask = TVIF_TEXT | TVIF_IMAGE

        | TVIF_SELECTEDIMAGE | TVIF_PARAM;

    // Set the text of the item.

    tvi.pszText = lpszItem;

    tvi.cchTextMax = lstrlen(lpszItem);

    // Assume the item is not a parent item, so give it a

    // document image.

    tvi.iImage = g_nDocument;

    tvi.iSelectedImage = g_nDocument;

    // Save the heading level in the item's application-defined

    // data area.

    tvi.lParam = (LPARAM) nLevel;

    tvins.item = tvi;

    tvins.hInsertAfter = hPrev;

    // Set the parent item based on the specified level.

    if (nLevel == 1)

        tvins.hParent = TVI_ROOT;

    else if (nLevel == 2)

        tvins.hParent = hPrevRootItem;

    else

        tvins.hParent = hPrevLev2Item;

    // Add the item to the tree-view control.

    hPrev = (HTREEITEM) SendMessage(hwndTV, TVM_INSERTITEM, 0,

         (LPARAM) (LPTV_INSERTSTRUCT) &tvins);

    // Save the handle of the item.

    if (nLevel == 1)

        hPrevRootItem = hPrev;

    else if (nLevel == 2)

        hPrevLev2Item = hPrev;

    // The new item is a child item. Give the parent item a

    // closed folder bitmap to indicate it now has child items.

    if (nLevel > 1) {

        hti = TreeView_GetParent(hwndTV, hPrev);

        tvi.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE;

        tvi.hItem = hti;

        tvi.iImage = g_nClosed;

        tvi.iSelectedImage = g_nClosed;

        TreeView_SetItem(hwndTV, &tvi);

    }

    return hPrev;

}


Dragging a Tree-View Item

Dragging a tree-view item typically involves processing the TVN_BEGINDRAG (or TVN_BEGINRDRAG) notification message, the WM_MOUSEMOVE message, and the WM_LBUTTONUP (or WM_RBUTTONUP) message. It also involves using the image list functions to draw the item as it is being dragged. For more information about image lists, see Image Lists.

The remainder of this section provides an example that demonstrates how to drag a tree-view item. The example consists of three functions. The first function begins the drag operation, the second drags the image, and the third ends the drag operation.


Beginning the Tree-View Drag Operation

A tree-view control sends the parent window a TVN_BEGINDRAG (or TVN_BEGINRDRAG) notification message whenever the user starts to drag an item. The parent window receives the notification in the form of a WM_NOTIFY message whose lParam parameter is the address of an NM_TREEVIEW structure. The members of this structure include the screen coordinates of the mouse cursor and a TV_ITEM structure that contains information about the item to be dragged.

The following example shows how to process the WM_NOTIFY message to obtain TVN_BEGINDRAG.

case WM_NOTIFY:

    switch (((LPNMHDR) lParam)->code) {

        case TVN_BEGINDRAG:

            Main_OnBeginDrag(hwndTV,    // application-defined function

                (NM_TREEVIEW *) lParam);

            break;

     .

     .  // Handle other notifications here.

     .

    }

    break;

Beginning the drag operation involves using the ImageList_BeginDrag function. The function's parameters include the handle of the image list containing the image to use during the drag operation and the index of the image. You can either provide your own image list and image, or you can have the tree-view control create them for you by using the TVM_CREATEDRAGIMAGE message.

Because the drag image replaces the mouse cursor for the duration of the drag operation, ImageList_BeginDrag requires you to specify a hot spot within the image. The coordinates of the hot spot are relative to the upper left corner of the image. ImageList_BeginDrag also requires you to specify the initial location of the drag image. An application typically sets the initial location so that the hot spot of the drag image corresponds to that of the mouse cursor at the time the user began the drag operation.

The following function demonstrates how to begin dragging a tree-view item. It uses the drag image provided by the tree-view control and obtains the bounding rectangle of the item to determine the appropriate point for the hot spot. (The dimensions of the bounding rectangle are the same as those of the image.) Note that the bounding rectangle does not account for the indentation of child items. For this reason, the function adds the amount of indentation to the x-coordinate of the hot spot.

The function captures mouse input, causing mouse messages to be sent to the parent window. The parent window needs the subsequent WM_MOUSEMOVE messages to determine where to drag the image and the WM_LBUTTONUP message to determine when to end the drag operation.

// Main_OnBeginDrag - begins dragging an item in a tree-view control.

// hwndTV - handle of the image list

// lpnmtv - address of information about the item being dragged

void Main_OnBeginDrag(HWND hwndTV, NM_TREEVIEW *lpnmtv)

{

    HIMAGELIST himl;    // handle of image list

    RECT rcItem;        // bounding rectangle of item

    DWORD dwLevel;      // heading level of item

    DWORD dwIndent;     // amount that child items are indented

    // Tell the tree-view control to create an image to use

    // for dragging.

    himl = TreeView_CreateDragImage(hwndTV, lpnmtv->itemNew.hItem);

    // Get the bounding rectangle of the item being dragged.

    TreeView_GetItemRect(hwndTV, lpnmtv->itemNew.hItem, &rcItem, TRUE);

    // Get the heading level and the amount that the child items are

    // indented.

    dwLevel = lpnmtv->itemNew.lParam;

    dwIndent = (DWORD) SendMessage(hwndTV, TVM_GETINDENT, 0, 0);

    // Start the drag operation.

    ImageList_BeginDrag(himl, hwndTV, 0,

        lpnmtv->ptDrag.x,

        lpnmtv->ptDrag.y,

        lpnmtv->ptDrag.x - ((dwLevel - 1) * dwIndent),

        lpnmtv->ptDrag.y - rcItem.top);

    // Hide the mouse cursor, and direct mouse input to the

    // parent window.

    ShowCursor(FALSE);

    SetCapture(GetParent(hwndTV));

    g_fDragging = TRUE;

    return;

}


Dragging the Tree-View Item

You drag a tree-view item by calling the ImageList_DragMove function when the parent window receives a WM_MOUSEMOVE message, as the following example shows. The example also performs hit testing during the drag operation to determine whether to highlight other items in the tree view as targets of a drag and drop operation.

// Main_OnMouseMove - drags an item in a tree-view control,

//     highlighting the item that is the target.

// hwndParent - handle of the parent window

// hwndTV - handle of the tree-view control

// xCur and yCur - x- and y-coordinates of the mouse cursor

void Main_OnMouseMove(HWND hwndParent, HWND hwndTV, LONG xCur, LONG yCur)

{

    HTREEITEM htiTarget;  // handle of target item

    TV_HITTESTINFO tvht;  // hit test information

    if (g_fDragging) {

        // Drag the item to the current position of the mouse cursor.

        ImageList_DragMove(xCur, yCur);

        // Find out if the cursor is on the item. If it is, highlight

        // the item as a drop target.

        tvht.pt.x = xCur;

        tvht.pt.y = yCur;

        if ((htiTarget = TreeView_HitTest(hwndTV, &tvht)) != NULL) {

            TreeView_SelectDropTarget(hwndTV, htiTarget);

        }

    }

    return;

}


Ending the Tree-View Drag Operation

The follow example ends a drag operation. The ImageList_EndDrag function is called when the parent window receives a WM_LBUTTONUP message.

// Main_OnLButtonUp - stops dragging a tree-view item, releases the

//     mouse capture, and shows the mouse cursor.

//
// Global variable

//     g_fDragging - indicates whether a drag operation is underway.

void Main_OnLButtonUp(void)

{

    if (g_fDragging) {

        ImageList_EndDrag();

        ReleaseCapture();

        ShowCursor(TRUE);

        g_fDragging = FALSE;

    }

    return;

}


Tree-View Control Reference

The following messages, macros, notification messages, and structures are associated with tree-view controls. These elements can be grouped as follows.

Item Labels

TV_ITEM
TVN_GETDISPINFO

Label Editing

TVM_EDITLABEL
TVM_ENDEDITLABELNOW
TVM_GETEDITCONTROL
TVN_BEGINLABELEDIT
TVN_ENDLABELEDIT

Item States

TVM_GETITEM
TVM_SELECTITEM
TVM_SETITEM
TVN_SELCHANGED
TVN_SELCHANGING

Tree-View Image Lists

TVM_GETIMAGELIST
TVM_SETIMAGELIST

Item Position

TV_INSERTSTRUCT
TVM_INSERTITEM
TVM_SORTCHILDREN
TVM_SORTCHILDRENCB

Parent and Child Items

TVM_EXPAND
TVM_GETINDENT
TVM_SETINDENT
TVN_ITEMEXPANDED
TVN_ITEMEXPANDING

Item Information

TV_DISPINFO
TVM_ENSUREVISIBLE
TVM_GETCOUNT
TVM_GETNEXTITEM
TVM_GETVISIBLECOUNT

Drag and Drop Operations

TV_HITTESTINFO
TVM_CREATEDRAGIMAGE
TVM_HITTEST
TVN_BEGINDRAG
TVN_BEGINRDRAG

Miscellaneous

NM_TREEVIEW
TV_KEYDOWN
TV_SORTCB
TVM_DELETEITEM
TVM_GETISEARCHSTRING
TVM_GETITEMRECT
TVN_DELETEITEM
TVN_KEYDOWN
TVN_SETDISPINFO


Tree-View Control Messages

An application sends messages to add items and to alter the appearance and behavior of a tree-view control. Each message has a corresponding macro, which you can use instead of sending the message explicitly. Some messages may have related macros, which are a more specialized form of a corresponding macro.

TVM_CREATEDRAGIMAGE
TVM_DELETEITEM
TVM_EDITLABEL
TVM_ENDEDITLABELNOW
TVM_ENSUREVISIBLE
TVM_EXPAND
TVM_GETCOUNT
TVM_GETEDITCONTROL
TVM_GETIMAGELIST
TVM_GETINDENT
TVM_GETISEARCHSTRING
TVM_GETITEM
TVM_GETITEMRECT
TVM_GETNEXTITEM
TVM_GETVISIBLECOUNT
TVM_HITTEST
TVM_INSERTITEM
TVM_SELECTITEM
TVM_SETIMAGELIST
TVM_SETINDENT
TVM_SETITEM
TVM_SORTCHILDREN
TVM_SORTCHILDRENCB


Tree-View Control Notification Messages

A tree-view control sends notifications messages to its parent window to notify it about events.

TVN_BEGINDRAG
TVN_BEGINLABELEDIT
TVN_BEGINRDRAG
TVN_DELETEITEM
TVN_ENDLABELEDIT
TVN_GETDISPINFO
TVN_ITEMEXPANDED
TVN_ITEMEXPANDING
TVN_KEYDOWN
TVN_SELCHANGED
TVN_SELCHANGING
TVN_SETDISPINFO


Tree-View Control Structures

The following structures are used with tree-view control messages.

NM_TREEVIEW
TV_DISPINFO
TV_HITTESTINFO
TV_INSERTSTRUCT
TV_ITEM
TV_KEYDOWN
TV_SORTCB


Tree-View Control Constants

The following window style flags and item state flags are used with tree-view controls.


Tree-View Window Styles

A tree view's window style can include one or more of the following values.

TVS_DISABLEDRAGDROP	Prevents the tree-view control from sending TVN_BEGINDRAG notification messages.
TVS_EDITLABELS	Allows the user to edit the labels of tree-view items.
TVS_HASBUTTONS	Displays plus (+) and minus (-) buttons next to parent items. The user clicks the buttons to expand or collapse a parent item's list of child items. To include buttons with items at the root of the tree view, TVS_LINESATROOT must also be specified.
TVS_HASLINES	Uses lines to show the hierarchy of items.
TVS_LINESATROOT	Uses lines to link items at the root of the tree-view control. This value is ignored if TVS_HASLINES is not also specified.
TVS_SHOWSELALWAYS	Causes a selected item to remain selected when the tree-view control loses focus.


Tree-View Item States

An item's state determines its appearance and functionality. It can be zero, or one or more of the following values.

TVIS_BOLD	The item is bold.
TVIS_CUT	The item is selected as part of a cut and paste operation.
TVIS_DROPHILITED	The item is selected as a drag and drop target.
TVIS_EXPANDED	The item's list of child items is currently expanded; that is, the child items are visible. This value applies only to parent items.
TVIS_EXPANDEDONCE	The item's list of child items has been expanded at least once. The TVN_ITEMEXPANDING and TVN_ITEMEXPANDED notification messages are not sent for parent items that have specified this value. This value applies only to parent items.
TVIS_FOCUSED	The item has the focus, so it is surrounded by a standard focus rectangle. Only one item can have the focus.
TVIS_OVERLAYMASK	The item's overlay image is included when the item is drawn. The index of the overlay image must be specified in the state member of the TV_ITEM structure by using the INDEXTOOVERLAYMASK macro. The overlay image must be added to the tree view's image list by using the ImageList_SetOverlayImage function. This value should not be combined with any other value.
TVIS_SELECTED	The item is selected. The appearance of a selected item depends on whether it has the focus and on whether the system colors are used for selection.
TVIS_STATEIMAGEMASK	The item's state image is included when the item is drawn. The index of the state image must be specified in the state member of the TV_ITEM structure by using theINDEXTOSTATEIMAGEMASK macro. This value should not be combined with any other value.
TVIS_USERMASK	Same as TVIS_STATEIMAGEMASK.


Up-Down Controls

An up-down control is 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 a companion control. The value associated with an up-down control is called its current position. An up-down control is most often used with a companion control, which is called a buddy window.


About Up-Down Controls

To the user, an up-down control and its buddy window often look like a single control. You can specify that an up-down control automatically position itself next to its buddy window and that it automatically set the caption of the buddy window to its current position. For example, you can use an up-down control with an edit control to prompt the user for numeric input. For more information about edit controls, see Edit Controls The following illustration shows an up-down control with an edit control as its buddy window, a combination that is sometimes referred to as a spinner control.

An up-down control without a buddy window functions as a sort of simplified scroll bar. For example, a tab control sometimes displays an up-down control to enable the user to scroll additional tabs into view. The following illustration shows an up-down control in the upper right corner of a tab control.

You can create an up-down control and specify its buddy window in several ways. The UPDOWN_CLASS value specifies an up-down control's window class. You can specify this window class in a dialog box template or in a call to the CreateWindowEx function. For more information about dialog box templates, see Dialog Boxes. Another way is to use the CreateUpDownControl function to create an up-down control and, at the same time, specify its buddy window, current position, and minimum and maximum positions.

The UPDOWN_CLASS window class is registered when the common controls dynamic-link library (DLL) is loaded. If you create an up-down control without using the CreateUpDownControl function, you must ensure that the DLL is loaded. You can do so by using the InitCommonControls function. For more information about common controls, see Common Controls.

CreateUpDownControl enables you to specify a buddy window. If you create an up-down control without using this function, you can assign a buddy window by specifying the UDS_AUTOBUDDY window style or by using the UDM_SETBUDDY message. If UDS_AUTOBUDDY is specified, the up-down control automatically selects the previous window in the Z order as its buddy window. This window might be the previous control in a dialog box template. You can use UDM_SETBUDDY to assign a specific buddy window to an up-down control. To determine an up-down control's current buddy window, use the UDM_GETBUDDY message. An up-down control and its buddy window must have the same parent window.

An up-down control notifies its parent window when its current position changes by sending it a UDN_DELTAPOS notification message and a WM_VSCROLL message.


About Up-Down Control Styles

Using window styles, you can control characteristics of an up-down control, such as how it positions itself relative to its buddy window, whether it sets the text of its buddy window, and whether it processes the UP ARROW and DOWN ARROW keys.

An up-down control with the UDS_ALIGNLEFT or UDS_ALIGNRIGHT style aligns with the left or right edge of its buddy window. The width of the buddy window is decreased to accommodate the width of the up-down control.

An up-down control with the UDS_SETBUDDYINT style sets the caption of its buddy window (using the WM_SETTEXT message) whenever the current position changes. The control inserts a thousands separator between every three digits of a decimal string unless the UDS_NOTHOUSANDS style is specified. If the buddy window is a list box, an up-down control sets its current selection instead of its caption.

You can specify the UDS_ARROWKEYS style to provide a keyboard interface for an up-down control. If this style is specified, the control processes the UP ARROW and DOWN ARROW keys. The control also subclasses the buddy window so that it can process these keys when the buddy window has the focus.

If you use an up-down control for horizontal scrolling, you can specify the UDS_HORZ style. This style causes the up-down control's arrows to point left and right instead of up and down.

By default, the current position does not change if the user attempts to increment it or decrement it beyond the maximum or minimum value. You can change this behavior by using the UDS_WRAP style, so the position "wraps" to the opposite extreme. For example, incrementing past the upper limit wraps the position back to the lower limit.


Position and Acceleration

After an up-down control is created, you can change the control's current position, minimum position, and maximum position by sending messages. You can also change the radix base used to display the current position in the buddy window and the rate at which the current position changes when the up or down arrow is clicked.

To retrieve the current position of an up-down control, use the UDM_GETPOS message. For an up-down control with a buddy window, the current position is the number in the buddy window's caption. Because the caption may have changed (for example, the user may have edited the text of an edit control), the up-down control retrieves the current caption and updates its current position accordingly.

The buddy window's caption may be either a decimal or hexadecimal string, depending on the radix base (that is, either base 10 or 16) of the up-down control. You can set the radix base by using the UDM_SETBASE message and retrieve the radix base by using the UDM_GETBASE message.

The UDM_SETPOS message sets the current position of a buddy window. Note that, unlike a scroll bar, an up-down control automatically changes its current position when the up and down arrows are clicked. An application, therefore, does not need to set the current position when processing the WM_VSCROLL message.

You can change the minimum and maximum positions of an up-down control by using the UDM_SETRANGE message. The maximum position may be less than the minimum, and in that case clicking the up arrow decreases the current position. To put it another way, up means moving towards the maximum position. To retrieve the minimum and maximum positions for an up-down control, use the UDM_GETRANGE message.

You can control the rate at which the position changes when the user holds down an arrow button by setting the up-down control's acceleration. The acceleration is defined by an array of UDACCEL structures. Each structure specifies a time interval and the number of units by which to increment or decrement at the end of that interval. To set the acceleration, use the UDM_SETACCEL message. To retrieve acceleration information, use the UDM_GETACCEL message.


Default Up-Down Controls Message Processing

This section describes the window message processing performed by an up-down control.

Message	Processing performed
WM_CREATE	Allocates and initializes a private data structure and saves its address as window data.
WM_DESTROY	Frees data allocated during WM_CREATE processing.
WM_ENABLE	Invalidates the window.
WM_KEYDOWN	Changes the current position in the case of an  UP ARROW or DOWN ARROW key.
WM_KEYUP	Ends changing the position.
WM_LBUTTONDOWN	Captures the mouse. If the buddy window is an edit control or list box, it sets the focus to the buddy window. If the mouse is over the up or down button, it begins changing the position and sets a timer.
WM_LBUTTONUP	Ends changing the position and releases the mouse capture if the up-down control has captured the mouse. If the buddy window is an edit control, it selects all the text in the edit control.
WM_PAINT	Paints the up-down control.
WM_TIMER	Changes the current position if the mouse is being held down over a button and a sufficient interval has elapsed.


Up-Down Control Reference

The following functions, messages, notification messages, and structures are associated with up-down controls. These elements can be grouped as follows.

Up-Down Control Creation

CreateUpDownControl
UDM_GETBUDDY
UDM_SETBUDDY

Current Position and Acceleration

UDACCEL
UDM_GETACCEL
UDM_GETBASE
UDM_GETPOS
UDM_GETRANGE
UDM_SETACCEL
UDM_SETBASE
UDM_SETPOS
UDM_SETRANGE

Notification Messages

UDN_DELTAPOS
WM_VSCROLL


Up-Down Control Functions

The following function is used with up-down controls.

CreateUpDownControl


Up-Down Control Messages

The following messages are used with up-down controls.

UDM_GETACCEL
UDM_GETBASE
UDM_GETBUDDY
UDM_GETPOS
UDM_GETRANGE
UDM_SETACCEL
UDM_SETBASE
UDM_SETBUDDY
UDM_SETPOS
UDM_SETRANGE


Up-Down Control Notification Messages

The following notification message is used with up-down controls.

UDN_DELTAPOS


Up-Down Control Structures

The following structure is used with up-down controls.

UDACCEL


Up-Down Control Styles

The following window styles are used with up-down controls.

UDS_ALIGNLEFT	Positions the up-down control next to the left edge of the buddy window. The buddy window is moved to the right and its width decreased to accommodate the width of the up-down control.
UDS_ALIGNRIGHT	Positions the up-down control next to the right edge of the buddy window. The width of the buddy window is decreased to accommodate the width of the up-down control.
UDS_ARROWKEYS	Causes the up-down control to increment and decrement the position when the UP ARROW and DOWN ARROW keys are pressed.
UDS_AUTOBUDDY	Automatically selects the previous window in the Z order as the up-down control's buddy window.
UDS_HORZ	Causes the up-down control's arrows to point left and right instead of up and down.
UDS_NOTHOUSANDS	Does not insert a thousands separator between every three decimal digits.
UDS_SETBUDDYINT	Causes the up-down control to set the text of the buddy window (using the WM_SETTEXT message) when the position changes. The text consists of the position formatted as a decimal or hexadecimal string.
UDS_WRAP	Causes the position to "wrap" if it is incremented or decremented beyond the ending or beginning of the range.


Buttons

Microsoft® Windows® provides dialog boxes and controls to support communication between an application and the user. A button is a control the user can turn on or off to provide input to an application.


About Buttons

There are several types of buttons and, within each type, one or more styles to distinguish among buttons of the same type. The user turns a button on or off by selecting it using the mouse or keyboard. Selecting a button typically changes its visual appearance and state (from checked to unchecked, for example). Windows, the button, and the application cooperate in changing the button's appearance and state. A button can send messages to its parent window, and a parent window can send messages to a button. Some buttons are painted by Windows, some by the application. Buttons can be used alone or in groups and can appear with or without application-defined text (a label). They belong to the BUTTON window class.

Although an application can use buttons in overlapped, pop-up, and child windows, they are designed for use in dialog boxes, where Windows standardizes their behavior. If an application uses buttons outside dialog boxes, it increases the risk that the application may behave in a nonstandard fashion. Applications typically either use buttons in dialog boxes or use window subclassing to create customized buttons.

For general information about controls, see Controls. For more information about dialog boxes, see Dialog Boxes. For more information about window subclassing, see Window Procedures.


Button Types and Styles

Windows provides five kinds of buttons: push buttons, check boxes, radio buttons, group boxes, and owner-drawn buttons. Each type has one or more styles.


Push Buttons

A push button is a rectangle containing application-defined text (label), an icon, or a bitmap that indicates what the button does when the user selects it. A push button can be one of two styles: standard or default, as defined by the constants BS_PUSHBUTTON and BS_DEFPUSHBUTTON. A standard push button is typically used to start an operation. It receives the keyboard focus when the user selects it. A default push button, on the other hand, is typically used to indicate the most common or default choice. It is a button that the user can select by simply pressing ENTER when a dialog box has the input focus.

When the user selects a push button (of either style), it receives the keyboard focus from Windows, which sends the button's parent window a WM_COMMAND message containing the BN_CLICKED notification code. In response, the dialog box typically closes and carries out the operation indicated by the button.


Check Boxes

A check box consists of a square box and application-defined text (label), an icon, or a bitmap that indicates a choice the user can make by selecting the button. Applications typically display check boxes in a group box to permit the user to choose from a set of related, but independent options. For example, an application might present a group of check boxes from which the user can select error conditions that produce warning beeps.

A check box can be one of four styles: standard, automatic, three-state, and automatic three-state, as defined by the constants BS_CHECKBOX, BS_AUTOCHECKBOX, BS_3STATE, and BS_AUTO3STATE, respectively. Each style can assume two check states: checked (an check mark inside the box) or unchecked (no check mark). In addition, a three-state check box can assume an indeterminate state (a grayed box inside the check box). Repeatedly selecting a standard or automatic check box toggles it from checked to unchecked and back again. Repeatedly selecting a three-state check box toggles it from checked to unchecked to indeterminate and back again.

When the user selects a check box (of any style), the check box receives the keyboard focus from Windows, which sends the check box's parent window a WM_COMMAND message containing the BN_CLICKED notification code. The parent window doesn't acknowledge this message if it comes from an automatic check box or automatic three-state check box, because Windows automatically sets the check state for those styles. But the parent window must acknowledge the message if it comes from a check box or three-state check box because the parent window, not Windows, is responsible for setting the check state for those styles. Regardless of the check box style, Windows automatically repaints the check box once its state is changed.


Radio Buttons

A radio button consists of a round button and application-defined text (a label), an icon, or a bitmap that indicates a choice the user can make by selecting the button. An application typically uses radio buttons in a group box to permit the user to choose from a set of related, but mutually exclusive options. For example, the application might present a group of radio buttons from which the user can select a format preference for text selected in the client area. The user could select a left-aligned, right-aligned, or centered format by selecting the corresponding radio button. Typically, the user can select only one option at a time from a set of radio buttons.

A radio button can be one of two styles: standard or automatic, as defined by the constants BS_RADIOBUTTON and BS_AUTORADIOBUTTON. Each style can assume two check states: checked (a dot in the button) or unchecked (no dot in the button). Repeatedly selecting a radio button (standard or automatic) toggles it from checked to unchecked and back again.

When the user selects either state, the radio button receives the keyboard focus from Windows, which sends the button's parent window a WM_COMMAND message containing the BN_CLICKED notification code. The parent window doesn't acknowledge this message if it comes from an automatic radio button because Windows automatically sets the check state for that style. But the parent window should acknowledge the message if it comes from a radio button because the parent window, not Windows, is responsible for setting the check state 1for that style. Regardless of the radio button style, Windows automatically repaints the button as its state changes.

When the user selects an automatic radio button, Windows automatically sets the  check state of all other radio buttons within the same group to unchecked. The same behavior is available for standard radio buttons by using the WS_GROUP style, as discussed in Dialog Boxes.


Owner-Drawn Buttons

Unlike radio buttons, an owner-drawn button is painted by the application, not by Windows, and has no predefined appearance or usage. Its purpose is to provide a button whose appearance and behavior are defined by the application alone. There is only one owner-drawn button style: BS_OWNERDRAW.

When the user selects an owner-drawn button, Windows sends the button's parent window a WM_COMMAND message containing the BN_CLICKED notification code, just as it does for a button that is not owner-drawn. The application must respond appropriately.


Group Boxes

A group box is a rectangle that surrounds a set of controls, such as check boxes or radio buttons, with application-defined text (label) in its upper left corner. The sole purpose of a group box is to organize controls related by a common purpose (usually indicated by the label). The group box has only one style, defined by the constant BS_GROUPBOX. Because a group box cannot be selected, it has no check state, focus state, or push state. An application cannot send messages to a group box.


Button Styles

Many developers create dialog boxes by using standalone tools, not requiring them to specify button styles. However, if an application creates a button by using the CreateWindow or CreateWindowEx function, the following table of constants can be used to define the button style.

Style	Meaning
BS_3STATE	Creates a button that is the same as a check box, except that the box can be grayed as well as checked or unchecked. Use the grayed state to show that the state of the check box is not determined.
BS_AUTO3STATE	Creates a button that is the same as a three-state check box, except that the box changes its state when the user selects it. The state cycles through checked, grayed, and unchecked.
BS_AUTOCHECKBOX	Creates a button that is the same as a check box, except that the check state automatically toggles between checked and unchecked each time the user selects the check box.
BS_AUTORADIOBUTTON	Creates a button that is the same as a radio button, except that when the user selects it, Windows automatically sets the button's check state to checked and automatically sets the check state for all other buttons in the same group to unchecked.
BS_CHECKBOX	Creates a small, empty check box with text. By default, the text is displayed to the right of the check box. To display the text to the left of the check box, combine this flag with the BS_LEFTTEXT style (or on Windows 95 only, with the equivalent BS_RIGHTBUTTON style).
BS_DEFPUSHBUTTON	Creates a push button that behaves like a BS_PUSHBUTTON style button, but also has a heavy black border. If the button is in a dialog box, the user can select the button by pressing the ENTER key, even when the button does not have the input focus. This style is useful for enabling the user to quickly select the most likely (default) option.
BS_GROUPBOX	Creates a rectangle in which other controls can be grouped. Any text associated with this style is displayed in the rectangle's upper left corner.
BS_LEFTTEXT	Places text on the left side of the radio button or check box when combined with a radio button or check box style. Same as the Windows 95 BS_RIGHTBUTTON style.
BS_OWNERDRAW	Creates an owner-drawn button. The owner window receives a WM_MEASUREITEM message when the button is created and a WM_DRAWITEM message when a visual aspect of the button has changed. Do not combine the BS_OWNERDRAW style with any other button styles.
BS_PUSHBUTTON	Creates a push button that posts a WM_COMMAND message to the owner window when the user selects the button.
BS_RADIOBUTTON	Creates a small circle with text. By default, the text is displayed to the right of the circle. To display the text to the left of the circle, combine this flag with the BS_LEFTTEXT style (or on Windows 95 only, with the equivalent BS_RIGHTBUTTON style). Use radio buttons for groups of related, but mutually exclusive choices.
BS_USERBUTTON	Obsolete, but provided for compatibility with 16-bit versions of Windows. Win32-based applications should use BS_OWNERDRAW instead.
BS_BITMAP	Windows 95 only: Specifies that the button displays a bitmap.
BS_BOTTOM	Windows 95 only: Places text at the bottom of the button rectangle.
BS_CENTER	Windows 95 only: Centers text horizontally in the button rectangle.
BS_ICON	Windows 95 only: Specifies that the button displays an icon.
BS_LEFT	Windows 95 only: Left-justifies the text in the button rectangle. However, if the button is a check box or radio button that does not have the BS_RIGHTBUTTON style, the text is left justified on the right side of the check box or radio button.
BS_MULTILINE	Windows 95 only: Wraps the button text to multiple lines if the text string is too long to fit on a single line in the button rectangle.
BS_NOTIFY	Windows 95 only: Enables a button to send BN_DBLCLK, BN_KILLFOCUS, and BN_SETFOCUS notification messages to its parent window. Note that buttons send the BN_CLICKED notification message regardless of whether it has this style.
BS_PUSHLIKE	Windows 95 only: Makes a button (such as a check box, three-state check box, or radio button) look and act like a push button. The button looks raised when it isn't pushed or checked, and sunken when it is pushed or checked.
BS_RIGHT	Windows 95 only: Right-justifies text in the button rectangle. However, if the button is a check box or radio button that does not have the BS_RIGHTBUTTON style, the text is right justified on the right side of the check box or radio button.
BS_RIGHTBUTTON	Windows 95 only: Positions a radio button's circle or a check box's square on the right side of the button rectangle. Same as the BS_LEFTTEXT style.
BS_TEXT	Windows 95 only: Specifies that the button displays text.
BS_TOP	Windows 95 only: Places text at the top of the button rectangle.
BS_VCENTER	Windows 95 only: Places text in the middle (vertically) of the button rectangle.


Button States

This section discusses how selecting a button changes its state and how the application should respond.


Button Selection

The user can select a button in three ways: by clicking it with the mouse, by tabbing to it and then pressing the ENTER key, or (if the button is part of a group defined by the WS_GROUP style) by tabbing to the selected button in the group and using the arrow keys to move within that group. The two tabbing methods are part of the predefined keyboard interface provided by Windows. For a complete description of this interface, see Dialog Boxes.

Selecting a button typically causes the following events:

•	Windows gives the button the keyboard focus.

•	The button sends its parent window a message to notify it of the selection.

•	The parent window (or Windows) sends the button a message to change its state.

•	The parent window (or Windows) repaints the button to reflect its new state.

The following topics discuss these events and button states in greater detail.


Elements of a Button State

A button's state can be characterized by its focus state, push state, and check state. The focus state applies to a check box, radio button, push button, or owner-drawn button. A button receives the keyboard focus when the user selects it and loses the focus when the user selects another control. Only one control can have the keyboard focus at a time.

When a button has the keyboard focus, the system typically highlights the text, icon, or bitmap of a button by surrounding it with a dotted line. In addition, a push button has a heavy dark border when it has the focus. Windows automatically changes the highlight for an automatic button, but the application must change the highlight for a nonautomatic button by sending messages.

The push state applies to a push button, check box, radio button, or three-state check box, but does not apply to other buttons. The push state of a button can be either pushed or not pushed. When a push button (or any button with the BS_PUSHLIKE style) is pushed, the button is drawn as a sunken button. When it is not pushed, it is drawn as a raised button. When a check box, radio button, or three-state check box is pushed, the background of the button is grayed. When it is not pushed, the background of the button is not grayed.

The check state applies to a check box, radio button, or three-state check box, but does not apply to other buttons. The state can be checked, unchecked, or (for three-state check boxes) indeterminate. A check box is checked when it contains a check mark, and is unchecked when it does not. A radio button is checked when it contains a black dot; and is unchecked when it does not. A three-state check box is checked when it contains a check mark, is unchecked when it does not, and is indeterminate when it contains a grayed box. Windows automatically changes the check state of an automatic button, but the application must change the check state of a nonautomatic button.


Changes to a Button State

When the user selects a button, it is generally necessary to change one or more of the button's state elements. Windows automatically changes the focus state for all button types, the push state for push buttons or buttons with the BS_PUSHLIKE style, and the check state for all automatic buttons. The application must make all other state changes, taking into account the button's type, style, and current state. The following list shows the state elements that must be changed for each button type:

•	A check box must change the check state.

•	A radio button must change the check state. It may also be necessary to change the check state of other radio buttons in the same group to ensure the mutually exclusive nature of radio buttons.

•	Because the state of an owner-drawn button is application dependent, what the application must change in the button can vary. No elements of a group box must be changed, because users cannot select group boxes.

An application can determine a button's state by sending it a BM_GETCHECK or BM_GETSTATE message; the application can set a button's state by sending it a BM_SETCHECK or BM_SETSTATE message.


Notification Messages from Buttons

When the user selects a button, its state changes, and the button sends notification messages to its parent window. For example, a push button control sends the BN_CLICKED notification message whenever the user chooses the button. In all cases, the low-order word of the wParam parameter contains the control identifier, the high-order word of wParam contains the notification code, and the lParam parameter contains the control window handle.

Portability Issue  The placement of notification message has moved from the lParam parameter to the wParam parameter. Windows 3.x − based applications that process notification messages must be modified in this respect when they are ported to Win32-based applications.

Both the message and the parent window's response depend on the type, style, and current state of the button. Following are the button notification messages an application should monitor and process.

Message	Description
BN_CLICKED	The user clicked a button.
BN_DBLCLK	The user double-clicked a button.
BN_DISABLE	A button is disabled.
BN_PUSHED	The user pushed a button.
BN_KILLFOCUS	The button lost the keyboard focus.
BN_PAINT	The button should be painted.
BN_SETFOCUS	The button gained the keyboard focus.
BN_UNPUSHED	The button is no longer pushed.
A button sends the BN_DISABLE, BN_PUSHED, BN_KILLFOCUS, BN_PAINT, BN_SETFOCUS, and BN_UNPUSHED notification messages only if it has the BS_NOTIFY style. It sends the BN_CLICKED and BN_DBLCLK notification messages regardless of the BS_NOTIFY style.

For automatic buttons, the operating system performs pushing, unpushing, and painting. In this case, the application typically processes only the BN_CLICKED and BN_DBLCLK notification messages. For buttons that are not automatic, the application typically responds to the notification message by sending a message to change the state of the button. For information about sending messages to buttons, Messages to Buttons.

When the user selects an owner-drawn button, the button sends its parent window a WM_DRAWITEM message containing the identifier of the control to be drawn and information about its dimensions and state. For more information about this message, see Using Owner-Drawn Buttons.


Messages to Buttons

A parent window can send messages to a button in an overlapped or child window by using the SendMessage function, or it can send messages to a button in a dialog box by using the SendDlgItemMessage, CheckDlgButton, CheckRadioButton, and IsDlgButtonChecked functions.

An application can use the BM_GETCHECK message to retrieve the check state of check box or radio button. An application can also use the BM_GETSTATE message to retrieve the button's current states (the check state, push state, and focus state). To get information about a specific state, use a bitmask on the returned state value.

The BM_SETCHECK message sets the check state of a check box or radio button; the message returns zero. The BM_SETSTATE message sets the push state of a button; this message also returns zero. The BM_SETSTYLE message changes the style of a button. It is designed for changing button styles within a type (for example, changing a check box to an automatic check box). It is not designed for changing between types (for example, changing a check box to a radio button). An application should not change a button from one type to another.

A button of the BS_BITMAP or BS_ICON style displays a bitmap or icon instead of text. The BM_SETIMAGE message associates the handle of a bitmap or icon with a button. The BM_GETIMAGE message retrieves the handle of the bitmap or icon associated with a button.

An application can also use the DM_GETDEFID message to retrieve the identifier of the default push button control in a dialog box. An application can use the DM_SETDEFID message to set the default push button for a dialog box.

Calling the CheckDlgButton or CheckRadioButton function is equivalent to sending a BM_SETCHECK message. Calling the IsDlgButtonChecked function is equivalent to sending a BM_GETCHECK message.


Button Color Messages

Windows provides default color values for buttons. The system sends a WM_CTLCOLORBTN message to a button's parent window before the button is drawn. This message contains a handle of the button's device context and a handle of the child window. The parent window can use these handles to change the button's text and background colors. The following table shows the default button-color values.

Value	Element colored
COLOR_BTNFACE	Button faces.
COLOR_BTNHIGHLIGHT	Highlight area (the top and left edges) of a button.
COLOR_BTNSHADOW	Shadow area (the bottom and right edges) of a button.
COLOR_BTNTEXT	Regular (nongrayed) text in buttons.
COLOR_GRAYTEXT	Disabled (gray) text in buttons. This color is set to 0 if the current display driver does not support a solid gray color.
COLOR_WINDOW	Window backgrounds.
COLOR_WINDOWFRAME	Window frames.
COLOR_WINDOWTEXT	Text in windows.
An application can retrieve the default values for these colors by calling the GetSysColor function, or set the values by calling the SetSysColors function. For more information about system colors, see System Information. For more information about how colors are used with controls, see Controls.

Portability Issue  The WM_CTLCOLOR message has been replaced by the set of control-color messages. When porting your Windows 3.x−based application to the Win32 API, you must modify any code that processes the WM_CTLCOLOR message.


Button Default Message Processing

The window procedure for the predefined button control window class carries out default processing for all messages that the button control procedure does not process. When the button control procedure returns FALSE for any message, the predefined window procedure checks the messages and performs the default actions listed in the following table.

Message	Default action
BM_CLICK	Sends the button a WM_LBUTTONDOWN and a WM_LBUTTONUP message, and sends the parent window a BN_CLICKED notification message.
BM_GETCHECK	Returns the check state of the button.
BM_GETIMAGE	Returns the handle of the bitmap or icon associated with the button or NULL if the button has no bitmap or icon.
BM_GETSTATE	Returns the current check state, push state, and focus state of the button.
BM_SETCHECK	Sets the check state for all styles of radio buttons and check boxes. If the wParam parameter is greater than zero for radio buttons, the button is given the WS_TABSTOP style.
BM_SETIMAGE	Associates the specified bitmap or icon handle with the button and returns the handle of the previous bitmap or icon.
BM_SETSTATE	Sets the push state of the button. For owner-drawn buttons, a WM_DRAWITEM message is sent to the parent window if the state of the button has changed.
BM_SETSTYLE	Sets the button style. If the low-order word of the lParam parameter is TRUE, the button is redrawn.
WM_CHAR	Checks a check box or automatic check box when the user presses the plus (+) or equal (=) keys. Unchecks a check box or automatic check box when the user presses the minus (−) key.
WM_ENABLE	Paints the button.
WM_ERASEBKGND	Erases the background for owner-drawn buttons. The backgrounds of other buttons are erased as part of the WM_PAINT and WM_ENABLE processing.
WM_GETDLGCODE	Returns values indicating the type of input processed by the default button procedure, as shown in the following table.
Button style	Returns
BS_AUTOCHECKBOX
	DLGC_WANTCHARS | DLGC_BUTTON
BS_AUTORADIOBUTTON
	DLGC_RADIOBUTTON
BS_CHECKBOX
	DLGC_WANTCHARS | DLGC_BUTTON
BS_DEFPUSHBUTTON
	DLGC_DEFPUSHBUTTON
BS_GROUPBOX
	DLGC_STATIC
BS_PUSHBUTTON
	DLGC_UNDEFPUSHBUTTON
BS_RADIOBUTTON
	DLGC_RADIOBUTTON
WM_GETFONT	Returns a handle of the current font.
WM_KEYDOWN	Pushes the button if the user presses the SPACEBAR.
WM_KEYUP	Releases the mouse capture for all cases except the TAB key.
WM_KILLFOCUS	Removes the focus rectangle from a button. For push buttons and default push buttons, the focus rectangle is invalidated. If the button has the mouse capture, the capture is released, the button is not clicked, and any push state is removed.
WM_LBUTTONDBLCLK	Sends a BN_DBLCLK notification message to the parent window for radio buttons and owner-drawn buttons. For other buttons, a double-click is processed as a WM_LBUTTONDOWN message.
WM_LBUTTONDOWN	Highlights the button if the position of the mouse cursor is within the button's client rectangle.
WM_LBUTTONUP	Releases the mouse capture if the button had the mouse capture.
WM_MOUSEMOVE	Performs the same action as WM_LBUTTONDOWN, if the button has the mouse capture. Otherwise, no action is performed.
WM_NCCREATE	Turns any BS_OWNERDRAW button into a BS_PUSHBUTTON button.
WM_NCHITTEST	Returns HTTRANSPARENT, if the button control is a group box.
WM_PAINT	Draws the button according to its style and current state.
WM_SETFOCUS	Draws a focus rectangle on the button getting the focus. For radio buttons and automatic radio buttons, the parent window is sent a BN_CLICKED notification message.
WM_SETFONT	Sets a new font and optionally updates the window.
WM_SETTEXT	Sets the text of the button. In the case of a group box, the message paints over the preexisting text before repainting the group box with the new text.
WM_SYSKEYUP	Releases the mouse capture for all cases except the TAB key.
The predefined window procedure passes all other messages to the DefWindowProc function for default processing.


Using Buttons

•	Creating a button outside a dialog box

•	Using buttons that are not owner-drawn

•	Using owner-drawn buttons


Creating a Button Outside a Dialog Box

The following example shows how to use the CreateWindow function to create a default push button.

hwndButton = CreateWindow(

    "BUTTON",   // predefined class

    "OK",       // button text

    WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,  // styles

    // Size and position values are given explicitly, because

    // the CW_USEDEFAULT constant gives zero values for buttons.

    10,         // starting x position

    10,         // starting y position

    100,        // button width

    100,        // button height

    hwnd,       // parent window

    NULL,       // No menu

    (HINSTANCE) GetWindowLong(hwnd, GWL_HINSTANCE),

    NULL);      // pointer not needed


Using Buttons that Are Not Owner-Drawn

The example in this section is the window procedure for a dialog box, as shown in the following illustration.

The check boxes and radio buttons in the Buttons dialog box are automatic. The check boxes are three-state. The Clear colors push button is a default push button. The check boxes, radio buttons, and push buttons are defined in the header file of the application, as follows.

#define IDB_BOX1        101             // first check box

#define IDB_BOX2        102             // second check box

#define IDB_BOX3        103             // third check box

#define IDB_REDBACK     104             // top radio button

#define IDB_BLUEBACK    105             // bottom radio button

#define IDB_CLEARBOXES  107             // top push button

#define IDB_CLEARBACK   108             // bottom push button

HBRUSH hbrRed, hbrBlue, hbrWhite;

BOOL fRedBack, fBlueBack, fClearColor;  // background-state flags

Note that it is not necessary to define IDOK, the identifier for the OK push button.

In the following window procedure, the WM_CTLCOLORDLG message notifies the application that the dialog box is about to be drawn. If the user presses the Clear colors button (signified by the fClearColor flag), the procedure uses the SendDlgItemMessage function to uncheck the check boxes and radio buttons. The BN_CLICKED notification message contains the identifiers of the buttons.

LRESULT APIENTRY ButtonProc(hDlg, message, wParam, lParam)

HWND hDlg;                // window handle of dialog box

UINT message;             // type of message

UINT wParam;              // message-specific information

LONG lParam;

{

    LRESULT lState;

    switch (message) {

        case WM_INITDIALOG:

            hbrRed = CreateSolidBrush(RGB(255, 0, 0));

            hbrBlue = CreateSolidBrush(RGB(0, 0, 255));

            hbrWhite = GetStockObject(WHITE_BRUSH);

            return TRUE;

        case WM_CTLCOLORDLG:

            if (fRedBack) {

                fRedBack = FALSE;

                return (LRESULT) hbrRed;

            }

            else if (fBlueBack) {

                fBlueBack = FALSE;

                return (LRESULT) hbrBlue;

            }

            else if (fClearColor) {

                fClearColor = FALSE;

                // Uncheck all check boxes and radio buttons.

                SendDlgItemMessage(hDlg,  // window handle

                    IDB_BOX1,             // button identifier

                    BM_SETCHECK,          // message

                    0,                    // check state unchecked)

                    0);                   // must be zero

                SendDlgItemMessage(hDlg, IDB_BOX2,

                    BM_SETCHECK, 0, 0);

                SendDlgItemMessage(hDlg, IDB_BOX3,

                    BM_SETCHECK, 0, 0);

                SendDlgItemMessage(hDlg, IDB_REDBACK,

                    BM_SETCHECK, 0, 0);

                SendDlgItemMessage(hDlg, IDB_BLUEBACK,

                    BM_SETCHECK, 0, 0);

            }

            return (LRESULT) hbrWhite;

        case WM_COMMAND:

                if (wParam == IDOK) {

                    EndDialog(hDlg, TRUE);

                    return TRUE;

                }

                if (HIWORD(wParam) == BN_CLICKED) {

                    switch (LOWORD(wParam)) {

                        case IDB_BOX1:

                            // Retrieve the state of the

                            // check box.

                            lState = SendDlgItemMessage(

                                hDlg, IDB_BOX1, BM_GETSTATE,

                                0, 0);

                             // The box-painting function is

                             // application defined.

                            BoxPainter(

                                hDlg,     // window handle

                                1,        // box to paint

                                lState);  // state of box

                            break;

                        case IDB_BOX2:

                            lState = SendDlgItemMessage(

                                hDlg, IDB_BOX2, BM_GETSTATE,

                                0, 0);

                            BoxPainter(hDlg, 2, lState);

                            break;

                        case IDB_BOX3:

                            lState = SendDlgItemMessage(

                                hDlg, IDB_BOX3, BM_GETSTATE,

                                0, 0);

                            BoxPainter(hDlg, 3, lState);

                            break;

                        case IDB_REDBACK:

                            fRedBack = TRUE;

                            InvalidateRect(hDlg, NULL,

                                TRUE);

                            break;

                        case IDB_BLUEBACK:

                            fBlueBack = TRUE;

                            InvalidateRect(hDlg, NULL,

                                TRUE);

                            break;

                        case IDB_CLEARBACK:

                            fClearColor = TRUE;

                            InvalidateRect(hDlg, NULL,

                                TRUE);

                            break;

                        case IDB_CLEARBOXES:

                            BoxPainter(hDlg, 4,

                                (LRESULT) 0);

                            break;

                    }

                }

        case WM_DESTROY:

            DeleteObject(hbrRed);

            DeleteObject(hbrBlue);

            // Do not delete hbrWhite, because it is a

            // stock object.

            break;

    }

    return FALSE;       // did not process a message

        UNREFERENCED_PARAMETER(lParam);

}


Using Owner-Drawn Buttons

The parent window of an owner-drawn button typically responds to at least three messages for the button: WM_INITDIALOG, WM_COMMAND, and WM_DRAWITEM. It is not necessary to process the WM_MEASUREITEM message for owner-drawn buttons.

When you must paint an owner-drawn button, Windows sends the parent window a WM_DRAWITEM message whose lParam points to a DRAWITEMSTRUCT structure. Use this structure with all owner-drawn controls to provide the application with the information it requires to paint the control. The itemAction and itemState members of the DRAWITEMSTRUCT structure define how to paint an owner-drawn button.

The following example shows how to process WM_INITDIALOG, WM_DRAWITEM, and WM_COMMAND messages for owner-drawn buttons. This example demonstrates how to draw one of two bitmaps for a control, depending on whether the control is selected. You would typically use the wParam parameter of the WM_DRAWITEM message to identify the control; in this example, only one control is assumed.

LRESULT APIENTRY OwnDrawProc(hDlg, message, wParam, lParam)

HWND hDlg;      // window handle of dialog box

UINT message;   // type of message

UINT wParam;    // message-specific information

LONG lParam;

{

    HDC hdcMem;

    LPDRAWITEMSTRUCT lpdis;

    switch (message) {

        case WM_INITDIALOG:

            // hinst, hbm1 and hbm2 are defined globally.

            hbm1 = LoadBitmap((HANDLE) hinst, "OwnBit1");

            hbm2 = LoadBitmap((HANDLE) hinst, "OwnBit2");

            return TRUE;

        case WM_DRAWITEM:

            lpdis = (LPDRAWITEMSTRUCT) lParam;

            hdcMem = CreateCompatibleDC(lpdis->hDC);

            if (lpdis->itemState & ODS_SELECTED)  // if selected

                SelectObject(hdcMem, hbm2);

            else

                SelectObject(hdcMem, hbm1);

            // Destination

            StretchBlt(

                lpdis->hDC,         // destination DC

                lpdis->rcItem.left, // x upper left

                lpdis->rcItem.top,  // y upper left

                // The next two lines specify the width and

                // height.

                lpdis->rcItem.right - lpdis->rcItem.left,

                lpdis->rcItem.bottom - lpdis->rcItem.top,

                hdcMem,    // source device context

                0, 0,      // x and y upper left

                32,        // source bitmap width

                32,        // source bitmap height

                SRCCOPY);  // raster operation

            DeleteDC(hdcMem);

            return TRUE;

        case WM_COMMAND:

            if (wParam == IDOK

                || wParam == IDCANCEL) {

                EndDialog(hDlg, TRUE);

                return TRUE;

            }

            if (HIWORD(wParam) == BN_CLICKED) {

                switch (LOWORD(wParam)) {

                    case IDB_OWNERDRAW:

                    .

                    . // application-defined processing

                    .

                    break;

                }

            }

            break;

        case WM_DESTROY:

            DeleteObject(hbm1);  // delete bitmaps

            DeleteObject(hbm2);

            break;

    }

    return FALSE;

        UNREFERENCED_PARAMETER(lParam);

}


Button Reference

The following functions and messages are associated with buttons.


Button Functions

Following are the functions used with buttons.

CheckDlgButton
CheckRadioButton
IsDlgButtonChecked


Button Messages

Following are the messages used with buttons.

BM_CLICK
BM_GETCHECK
BM_GETSTATE
BM_SETCHECK
BM_SETSTATE
BM_SETSTYLE
BN_CLICKED
BN_DISABLE
BN_HILITE
BN_PAINT
BN_UNHILITE
DM_GETDEFID
DM_SETDEFID
WM_CTLCOLORBTN
BN_DBLCLK
BN_DOUBLECLICKED
BN_KILLFOCUS
BN_SETFOCUS


Combo Boxes

A combo box is a unique type of control, defined by the COMBOBOX class, that combines much of the functionality of a list box and an edit control.

This overview describes the types and styles of combo box, the parts of a combo box, the use of an owner-drawn combo box, and how to subclass a combo box. Additional features of combo boxes are also discussed.


About Combo Boxes

The Microsoft® Win32® application programming interface (API) provides three types of combo box: simple combo boxes (CBS_SIMPLE), drop-down combo boxes (CBS_DROPDOWN), and drop-down list boxes (CBS_DROPDOWNLIST).

There are also a number of combo box styles that define specific properties. For example, two styles enable an application to create an owner-drawn combo box, making the application responsible for displaying information in the control.

A combo box consists of a list and a selection field. The list presents the options a user can select and the selection field displays the current selection. Except in drop-down list boxes, the selection field is an edit control and can be used to enter text not in the list.


Combo Box Types and Styles

Combo boxes can be characterized by type and style. Combo box types determine whether the combo box list is a drop-down list and whether the selection field is an edit control. A drop-down list appears only when the user opens it, so it uses less screen space than a list that is always visible. If the selection field is an edit control, the user can enter information not in the list; otherwise, the user can only select items in the list.

The following table shows the three combo box types and indicates whether each includes a drop-down list and an edit control:

Combo box type	Drop-down list	Edit control
Drop-down combo box	Yes	Yes
Drop-down list box	Yes	No
Simple combo box	No	Yes
Combo box styles define specific properties of a combo box. An application can combine styles; however some styles only apply to certain combo box types. The following table describes the combo box styles:

Style	Description
CBS_AUTOHSCROLL	Automatically scrolls the text in an edit control to the right when the user types a character at the end of the line. If this style is not set, only text that fits within the rectangular boundary is allowed.
CBS_DISABLENOSCROLL	Shows a disabled vertical scroll bar in the list box when the box does not contain enough items to scroll. Without this style, the scroll bar is hidden when the list box does not contain enough items.
CBS_DROPDOWN	Specifies a drop-down combo box.
CBS_DROPDOWNLIST	Specifies a drop-down list box.
CBS_HASSTRINGS	Specifies that an owner-drawn combo box contains items consisting of strings. The combo box maintains the memory and address for the strings so the application can use the CB_GETLBTEXT message to retrieve the text for a particular item.
CBS_LOWERCASE	Converts to lowercase all text in both the selection field and the list.
CBS_NOINTEGRALHEIGHT	Specifies that the size of the combo box is exactly the size specified by the application when it created the combo box. Normally, Windows sizes a combo box so that it does not display partial items.
CBS_OEMCONVERT	Converts text entered in the combo box edit control from the Windows character set to the OEM character set and then back to the Windows set. This ensures proper character conversion when the application calls the CharToOem function to convert a Windows string in the combo box to OEM characters. This style is most useful for combo boxes that contain filenames and applies only to combo boxes created with the CBS_SIMPLE or CBS_DROPDOWN style.
CBS_OWNERDRAWFIXED	Specifies that the owner of the list box is responsible for drawing its contents and that the items in the list box are all the same height. The owner window receives a WM_MEASUREITEM message when the combo box is created and a WM_DRAWITEM message when a visual aspect of the combo box has changed.
CBS_OWNERDRAWVARIABLE	Specifies that the owner of the list box is responsible for drawing its contents and that the items in the list box are variable in height. The owner window receives a WM_MEASUREITEM message for each item in the combo box when you create the combo box and a WM_DRAWITEM message when a visual aspect of the combo box has changed.
CBS_SIMPLE	Specifies a simple combo box.
CBS_SORT	Automatically sorts strings added to the list box.
CBS_UPPERCASE	Converts to uppercase all text in both the selection field and the list.


Combo Box List

A list is the portion of a combo box that displays the items a user can select. Typically, an application initializes the contents of the list when it creates a combo box. Any list item selected by the user is the current selection. In simple and drop-down combo boxes, the user can type in the selection field instead of selecting a list item. In these cases, there is no current selection. For more information, see Current Selection.


List Contents

When an application creates a combo box, it typically initializes the combo box by adding one or more items to the list. Later, an application may add or delete list items, reinitialize the list, or retrieve item information from it.

An application adds list items to a combo box by sending the CB_ADDSTRING message to it. The specified item is added to the end of the list or, in a sorted combo box, in its correct sorted position based on the item's string. In an unsorted combo box, an application can use the CB_INSERTSTRING message to insert an item at a specific position. Once added, a list item is identified by its position.

By using the CB_FINDSTRING or CB_FINDSTRINGEXACT message, an application can determine the position of a list item. CB_FINDSTRING finds an item whose string begins with the specified string. CB_FINDSTRINGEXACT finds an item whose string matches the string exactly. Neither message is case sensitive.

An application can remove a list item by using the CB_DELETESTRING message. If an application needs to reinitialize the combo box list, it can first clear its entire contents by using the CB_RESETCONTENT message. When adding multiple items to the list after a combo box has already been shown, an application can clear the redraw flag to prevent the combo box from being repainted after each item is added. For more information about redrawing, see the description of the WM_SETREDRAW message.

To retrieve the string associated with a list item, an application can use the CB_GETLBTEXT message. The item's string is copied to the buffer specified by the application. To ensure that the buffer is large enough to receive the string, the application can first use the CB_GETLBTEXTLEN message to determine the length of the string. To get the number of list items in a combo box, an application can use the CB_GETCOUNT message.


Current Selection

The current selection is a list item the user has selected; the selected text appears in the selection field of the combo box. However, in the case of a simple combo box or a drop down combo box, the current selection is only one form of possible user input in a combo box. The user can also type text in the selection field.

The current selection is identified by the zero-based index of the selected list item. An application can set and retrieve it at any time. The parent window or dialog box procedure receives notifications when user changes the current selection for a combo box. The parent window or dialog box is not notified when the application changes the selection.

When a combo box is created, there is no current selection. This is also true for a simple or drop-down combo box, if the user has edited the contents of the selection field. To set the current selection, an application sends the CB_SETCURSEL message to the combo box. An application can also use the CB_SELECTSTRING message to set the current selection to a list item whose string begins with a specified string. To determine the current selection, an application sends the CB_GETCURSEL message to the combo box. If there is no current selection, this message returns CB_ERR.

When the user changes the current selection in a combo box, the parent window or dialog-box procedure receives a WM_COMMAND message with the notification message CBN_SELCHANGE in the high-order word of the wParam parameter. As a result, the application can respond to this notification message and execute a specific process each time the user selects a list item. This notification message is not sent when the current selection is set using the CB_SETCURSEL message.

In a drop-down combo box or drop-down list box, an application wait for the use to close the list box before processing a change in the current selection. This can be useful when significant processing is required. For example, to update a directory list based on the selected drive, an application can process the CBN_CLOSEUP message instead of CBN_SELCHANGE to update a directory list after the user selects a drive.

An application could also process the notification messages CBN_SELENDOK and CBN_SELENDCANCEL. The system sends CBN_SELENDOK when the user selects a list item, or selects an item and then closes the list. This indicates the user has finished, and the selection should be processed. CBN_SELENDCANCEL is sent when the user selects an item, but then selects another control, presses the ESCAPE key while the drop-down list is open, or closes the dialog box. This indicates the user's selection should be ignored. In a simple combo box, CBN_SELENDOK is sent before every CBN_SELCHANGE message. If the WS_EX_NOPARENTNOTIFY window style is specified for the combo box, the system does not send CBN_SELENDOK and CBN_SELENDCANCEL messages.

In a simple combo box, the system sends the CBN_DBLCLK notification message when the user double-clicks a list item. In a drop-down combo box or drop-down list, a single click hides the list so it is not possible to double-click an item.


Drop-Down Lists

Certain notifications and messages apply only to combo boxes containing drop-down lists. When a drop-down list is open or closed, the parent window of a combo box receives a notification in the form of a WM_COMMAND message. If the list is being opened, the high-order word of wParam is CBN_DROPDOWN. If the list is being closed, it is CBN_CLOSEUP.

An application can open the list of a drop-down combo box or drop-down list box by using the CB_SHOWDROPDOWN message. It can determine whether the list is open by using the CB_GETDROPPEDSTATE message and can determine the coordinates of a drop-down list by using the CB_GETDROPPEDCONTROLRECT message. An application can also increase the width of a drop-down list by using the CB_SETDROPPEDWIDTH message.


Edit Control Selection Fields

The selection field is the portion of a combo box that displays the currently selected list item. In simple and drop-down combo boxes, the selection field is an edit control and can be used to enter text that is not in the list.

An application can retrieve or set the contents of the selection field and can determine or set the edit selection. The application can also limit the amount of text a user can type in the selection field. When the contents of the selection field change, Windows sends notification messages to the parent window or dialog box procedure.

To retrieve the content of the selection field, an application can send the WM_GETTEXT message to the combo box. To set the contents of the selection field of a simple or drop-down combo box, an application can send the WM_SETTEXT message to the combo box.

The edit selection is the range of selected text, if any, in the selection field of a simple or drop-down combo box. An application can determine the starting and ending character positions of the current selection by using the CB_GETEDITSEL message. It can also select characters in the edit selection by using the CB_SETEDITSEL message.

Initially, the amount of text that the user can type into the selection field is limited by the size of the selection field. However, if the combobox has the CBS_AUTOHSCROLL style, the text can continue beyond the size of the selection field. An application can use the CB_LIMITTEXT message to limit the amount of text a user can type into the selection field, regardless of whether the control has the CBS_AUTOHSCROLL style.

When the user edits the content of the selection field, the parent window or dialog box procedure receives notification messages. CBN_EDITUPDATE is sent first, indicating that the text in the selection field has been edited. After the altered text is displayed, Windows sends CBN_EDITCHANGE. When the selection field content changes as the result of a list item being selected, these messages are not sent.


Owner-Drawn Combo Boxes

An application can create an owner-drawn combo box to take responsibility for painting list items. The parent window or dialog box of an owner-drawn combo box (its owner) receives WM_DRAWITEM messages when a portion of the combo box needs to be painted. An owner-drawn combo box can list information other than, or in addition to, text strings. Owner-drawn combo boxes can be of any type. However, the edit control in a simple or drop-down combo box can only display text, while the owner paints the selection field in a drop-down list box.

The owner of an owner-drawn combo box must process the WM_DRAWITEM message. This message is sent whenever a portion of the combo box must be redrawn. The owner may need to process other messages, depending on the styles specified for the combo box.

An application can create an owner-drawn combo box by specifying the CBS_OWNERDRAWFIXED or CBS_OWNERDRAWVARIABLE style. If all list items in the combo box are the same height, such as strings or icons, an application can use the CBS_OWNERDRAWFIXED style. If list items are of varying height, bitmaps of different size, for example, an application can use the CBS_OWNERDRAWVARIABLE style.

The owner of an owner-drawn combo box can process a WM_MEASUREITEM message to specify the dimensions of list items in the combo box. If the application creates the combo box by using the CBS_OWNERDRAWFIXED style, Windows sends the WM_MEASUREITEM message only once. The dimensions specified by the owner are used for all list items. If the CBS_OWNERDRAWVARIABLE style is used, Windows sends a WM_MEASUREITEM message for each list item added to the combo box. The owner can determine or set the height of a list item at any time by using the CB_GETITEMHEIGHT and CB_SETITEMHEIGHT messages, respectively.

If the information displayed in an owner-drawn combo box includes text, an application can keep track of the text for each list item by specifying the CBS_HASSTRINGS style. Combo boxes with the CBS_SORT style are sorted based on this text. If a combo box is sorted and not of the CBS_HASSTRINGS style, the owner must process the WM_COMPAREITEM message.

In an owner-drawn combo box, the owner must keep track of list items containing information other than or in addition to text. One convenient way to do this is to save the handle of the information as item data. For more information about item data, see Data Associated with List Items. To free data objects associated with items in a combo box, the owner can process the WM_DELETEITEM message.

For an example of an owner-drawn combo box, see Creating an Owner-Drawn Combo Box.


Subclassed Combo Boxes

Subclassing is a procedure that allows an application to intercept and process messages sent or posted to a window. By using subclassing, an application can substitute its own processing for certain messages, while leaving most message processing to the class-defined window procedure.

When the operating system creates a window, it saves information about it in an internal data structure that includes the address of the window procedure. To subclass a window, an application calls the SetClassLong function to replace the address of that procedure with the instance address of an application-defined subclass procedure. Thereafter, all messages to the window are sent to the subclass procedure. This procedure then uses the CallWindowProc function to pass unprocessed messages to the original window procedure. For a description of the message processing performed by the COMBOBOX class window procedure, see Default Combo Box Behavior.

When the combo box is outside a dialog box, an application cannot process the TAB, ENTER, and ESCAPE keys unless it uses a subclass procedure. When a simple or drop-down combo box receives the input focus, it immediately sets the focus to its child edit control. Therefore, an application must subclass the edit control to intercept keyboard input for a simple or drop-down combo box. For an example of this, see Subclassing a Combo Box.

If a subclass procedure processes the WM_PAINT message, it must use the BeginPaint function to prepare for painting. Before calling the EndPaint function, it passes the device-context (DC) handle as the wParam parameter for the window procedure. If EndPaint is called first, the class window procedure does no painting because EndPaint validates the entire window.

A technique related to subclassing is superclassing. A superclass resembles any other class except that its window procedure does not call DefWindowProc to handle unprocessed messages. Instead, it passes unprocessed messages to the window procedure for the parent window class. Follow the guidelines in Window Procedures to avoid problems that can occur with subclassing and superclassing.


Special Combo Box Features

The Win32 API provides special-purpose messages and functions that enable an application to display a directory listing in a combo box, associate data with list items in a combo box, and change the keyboard interface for a drop-down combo box or drop-down list box.


Directory Lists

An application can add the names of files or subdirectories to a combo box by sending the CB_DIR message to it. The wParam parameter for the window procedure specifies the attributes of the files to add, and the lParam parameter points to the text string that defines the file specification.

Within a dialog box, an application can also use DlgDirListComboBox. If the specified filename includes a drive, path, or both, DlgDirListComboBox changes the current drive or directory and removes the drive and path from the filename string. To show the directory name, the function updates the specified static control, if any. It then resets the contents of the combo box, and sends the CB_DIR message to the combo box to add the specified filenames.

To remove the selected filename, directory name, or drive letter from a combo box that has been filled by using DlgDirListComboBox, an application can use the DlgDirSelectComboBoxEx function.

The DlgDirListComboBox and DlgDirSelectComboBoxEx functions and the CB_DIR message are similar to the DlgDirList and DlgDirSelectEx functions and the LB_DIR message used with list boxes.


Data Associated with List Items

An application can associate data with the list items in a combo box. The CB_SETITEMDATA message associates a DWORD value with a list item, and the CB_GETITEMDATA retrieves the value associated with a list item.

The example in Creating an Owner-Drawn Combo Box uses item data to associate a constant with each item in a drop-down list box. Such a unique value identifies each item independent of its sorted position.

Other applications might use item data to associate a handle or pointer with a list item. If so, an application can process a WM_DELETEITEM message to delete or free the specified object when the list item is deleted.


The Extended User Interface

Drop-down combo boxes and drop-down list boxes support an alternative keyboard interface called the extended user interface. By default, the F4 key opens or closes the list, and the DOWN ARROW changes the current selection. In a combo box with the extended user interface, however, the F4 key is disabled and pressing the DOWN ARROW key opens the drop-down list.

To select the user interface for a combo box, an application can send the CB_SETEXTENDEDUI message to the combo box. A TRUE value for the wParam parameter enables the extended user interface; a FALSE value sets the default user interface. To determine whether a combo box uses the extended user interface, an application can send the CB_GETEXTENDEDUI message to the combo box.


Combo Box Notifications

Messages from combo boxes are sent as notifications in the form of WM_COMMAND messages. The notification message is stored in the high word of the wParam parameter, and an application can process the following combo box notification messages.

Notification message	Description
CBN_CLOSEUP	Indicates the list in a drop-down combo box or drop-down list box is about to close.
CBN_DBLCLK	Indicates the user has double-clicked a list item in a simple combo box.
CBN_DROPDOWN	Indicates the list in a drop-down combo box or drop-down list box is about to open.
CBN_EDITCHANGE	Indicates the user has changed the text in the edit control of a simple or drop-down combo box. This notification message is sent after the altered text is displayed.
CBN_EDITUPDATE	Indicates the user has changed the text in the edit control of a simple or drop-down combo box. This notification message is sent before the altered text is displayed.
CBN_ERRSPACE	Indicates the combo box cannot allocate enough memory to carry out a request, such as adding a list item.
CBN_KILLFOCUS	Indicates the combo box is about to lose the input focus.
CBN_SELCHANGE	Indicates the current selection has changed.
CBN_SELENDCANCEL	Indicates that the selection made in the drop down list, while it was dropped down, should be ignored.
CBN_SELENDOK	Indicates that the selection made drop down list, while it was dropped down, should be accepted.
CBN_SETFOCUS	Indicates the combo box has received the input focus.


Default Combo Box Behavior

This section contains a table that describes the messages specifically handled by the predefined COMBOBOX class window procedure.

Message	Description
CB_ADDSTRING	Sends an LB_ADDSTRING message to the list window to add a list item.
CB_DELETESTRING	Sends an LB_DELETESTRING message to the list window to delete a list item.
CB_DIR	Adds the filenames matching the specified attributes and path to the list.
CB_FINDSTRING	Sends an LB_FINDSTRING message to the list window. This message returns the index of the first list item that begins with the specified text.
CB_FINDSTRINGEXACT	Sends an LB_FINDSTRING message to the list window. This message returns the index of the first list item exactly matching the specified text.
CB_GETCOUNT	Sends an LB_GETCOUNT message to the list window. It returns the number of list items.
CB_GETCURSEL	Sends an LB_GETCURSEL message to the list window. It returns the index of the currently selected item, if any.
CB_GETDROPPEDCONTROLRECT	Fills the specified rectangle structure with the screen coordinates of a drop-down list.
CB_GETDROPPEDSTATE	Returns TRUE if a drop-down list is open; otherwise, it returns FALSE.
CB_GETDROPPEDWIDTH	Returns the minimum allowable width, in pixels, of the drop down list.
CB_GETEDITSEL	Sends an EM_GETSEL message to the edit control, and it returns the starting and ending position of the current selection. In drop-down list boxes, the window procedure returns CB_ERR.
CB_GETEXTENDEDUI	Returns TRUE if the combo box is a drop-down combo box or drop-down list box and the extend user-interface flag is set; otherwise, it returns FALSE.
CB_GETHORIZONTALEXTENT	Sends an LB_GETHORIZONTALEXTENT message to the list window. It returns the scrollable width, in pixels, of the drop down list.
CB_GETITEMDATA	Sends an LB_GETITEMDATA message to the list window. It returns the 32-bit value associated with the specified list item.
CB_GETITEMHEIGHT	Sends an LB_GETITEMHEIGHT message to the list window. It returns the height, in pixels, of the specified owner-drawn list item.
CB_GETLBTEXT	Sends an LB_GETTEXT message to the list window. It copies the specified list text to the specified buffer.
CB_GETLBTEXTLEN	Sends an LB_GETTEXTLEN message to the list window. It returns the length, in bytes, of the specified list text.
CB_GETLOCALE	Sends an LB_GETLOCALE message to the list window. It returns the current locale for the list.
CB_GETTOPINDEX	Sends an LB_GETTOPINDEX message to the list window. It returns the index of the first visible item in the drop down list.
CB_INITSTORAGE	Sends an LB_INITSTORAGE message to the list window. It initializes space for the specified number of items and the specified number of bytes for item strings.
CB_INSERTSTRING	Sends an LB_INSERTSTRING message to the list window. It inserts a list item at the specified position.
CB_LIMITTEXT	Sends an EM_LIMITTEXT message to the edit control. It sets the maximum number of characters a user can enter in the edit control. In drop-down list boxes, the window procedure returns CB_ERR.
CB_RESETCONTENT	Sends an LB_RESETCONTENT message to the list window, and it removes the contents of the list.
CB_SELECTSTRING	Sends an LB_SELECTSTRING message to the list window. It selects the first list item, if any, that begins with the characters in the specified text.
CB_SETCURSEL	Sends an LB_SETCURSEL message to the list window, and it sets the current selection.
CB_SETDROPPEDWIDTH	Sets the minimum allowable width, in pixels, of the drop down list.
CB_SETEDITSEL	Sends an EM_SETSEL message to the edit control. It selects the specified range of text. In drop-down list boxes, the window procedure returns CB_ERR.
CB_SETEXTENDEDUI	Sets or clears the extended user-interface flag. This flag changes the keys that open and close the list in a drop-down combo box or drop-down list box. If the combo box is a simple combo box, the window procedure returns CB_ERR.
CB_SETHORIZONTALEXTENT	Sends an LB_SETHORIZONTALEXTENT message to the list window. It sets the scrollable width, in pixels, of the drop down list.
CB_SETITEMDATA	Sends an LB_SETITEMDATA message to the list window. It associates the specified 32-bit value with a list item.
CB_SETITEMHEIGHT	Sends an LB_SETITEMHEIGHT message to the list window. It sets the height of the specified owner-drawn list item or the selection field.
CB_SETLOCALE	Sends an LB_SETLOCALE message to the list window, and it sets the current locale for the list. The locale affects how the list is sorted if it has the CBS_SORT style and strings are added using CB_ADDSTRING.
CB_SETTOPINDEX	Sends an LB_SETTOPINDEX message to the list window. It scrolls the drop down list so the specified item is at the top of the visible range.
CB_SHOWDROPDOWN	Shows or hides the drop-down list. This message has no effect on simple combo boxes.
WM_CHAR	Processes character input. In drop-down list boxes, this message is passed to the list window, which moves the selection to the first item beginning with the specified character. In simple and drop-down combo boxes, this message is passed to the edit control.
WM_CLEAR	Deletes the edit selection. In simple and drop-down combo boxes, the edit control processes this message. In drop-down list boxes, the window procedure returns CB_ERR.
WM_COMMAND	Processes notification messages from the edit control and list window and sends corresponding combo box notification messages to the parent window.
	For edit control notifications, the window procedure may update the list window's current selection, caret index, and top index. For list notification messages, the window procedure may update the content of the selection field.
WM_COMPAREITEM	Passes the message to the parent window, enabling the application to specify the relative sort position of two owner-drawn list items. The combo box window receives this message from the list window.
WM_COPY	Copies the edit selection to the clipboard. In simple and drop-down combo boxes, the edit control processes this message. In drop-down list boxes, the window procedure returns CB_ERR.
WM_CREATE	Initializes the combo box.
WM_CUT	Deletes the edit selection and places it on the clipboard. In simple and drop-down combo boxes, the edit control processes this message. In drop-down list boxes, the window procedure returns CB_ERR.
WM_DELETEITEM	Passes the message to the parent window, notifying the application that a list item has been deleted. The combo box window receives this message from the list window.
WM_DRAWITEM	Passes the message on to the parent window enabling the application to paint the specified list item. The combo box window receives this message from the list window. The window procedure can also originate this message to have the application paint the selection field of a drop-down list box.
WM_ENABLE	Sets the state to enable or prohibit mouse and keyboard input.
WM_ERASEBKGND	Returns 1, indicating that the background is erased.
WM_GETDLGCODE	Returns a combination of the DLG_WANTCHARS and DLGC_WANTARROWS values.
WM_GETFONT	Returns the handle of the current font with which the combo box will draw its text.
WM_GETTEXT	Copies the contents of the selection field to the specified buffer. In simple and drop-down combo boxes, the edit control processes this message.
WM_GETTEXTLENGTH	Returns the length, in characters, of the text in the selection field. In simple and drop-down combo boxes, the edit control processes this message.
WM_KEYDOWN	Processes noncharacter keyboard input. In drop-down list boxes, this message is sent to the list window, which may show or hide itself, or change its current selection or caret index. In simple and drop-down combo boxes, this message is passed to the edit control. The edit control passes certain keys to the list window, such as the UP and DOWN ARROW keys and the F4 key.
WM_KILLFOCUS	Hides the highlight in the selection field and closes the drop-down list, if necessary. If the window receiving the input focus is part of the combo box (for example, the edit control), this message is ignored.
WM_LBUTTONDBLCLK	Same as WM_LBUTTONDOWN.
WM_LBUTTONDOWN	Sets the focus to the combo box and, for drop-down combo boxes and drop-down lists, can open or close the list. If it opens the list, the window procedure captures the mouse to enable selection by dragging and releasing the mouse button.
WM_LBUTTONUP	Releases the mouse capture if the mouse opened the list.
WM_MEASUREITEM	Posts the message to the parent window, enabling the application to modify the contents of the specified MEASUREITEMSTRUCT structure. The combo box window receives this message from the list window.
WM_MOUSEMOVE	Posts the message to the list window if the mouse has opened the list and the mouse button is still down. This enables a user to select an item by dragging the mouse pointer to a list item and then releasing the button.
WM_NCCREATE	Allocates an internal data structure used by the combo box window procedure.
WM_NCDESTROY	Frees resources allocated in response to the WM_NCCREATE message.
WM_PAINT	Paints the invalid region of the combo box. If wParam is not NULL, it is assumed to be a DC handle passed from a subclass function. The window procedure uses the specified DC instead of calling BeginPaint and EndPaint.
WM_PASTE	Replaces the edit selection with the contents of the clipboard. In simple and drop-down combo boxes, the edit control processes this message. In drop-down list boxes, the window procedure returns CB_ERR.
WM_SETFOCUS	Sets the focus to the edit control or, in drop-down list boxes, inverts the selection field and turns on the caret in the list window.
WM_SETFONT	Saves the specified font handle in an internal structure, adjusts the dimensions of the selection field and list, and invalidates the combo box window. Text in the selection field and the list is displayed in the saved font.
WM_SETREDRAW	Sets or clears the redraw flag. If the redraw flag is cleared, the combo box is not repainted until the flag is set again.
WM_SETTEXT	Sets the contents of the edit control. In simple and drop-down combo boxes, the edit control processes this message. In drop-down list boxes, the window procedure returns CB_ERR.
WM_SIZE	Resizes the child windows, if necessary.
WM_SYSKEYDOWN	Opens or closes the drop-down list depending on which arrow key the user pressed.
All other messages are passed to the DefWindowProc function for default processing.


Using Combo Boxes

•	Creating a simple combo box

•	Creating an owner-drawn combo box

•	Subclassing a combo box


Creating a Simple Combo Box

This section describes how to use a simple combo box in a dialog box. The example in Creating a Spell Dialog Box uses a simple combo box in a dialog box for a spelling checker. When it finds a misspelled word, the spelling checker suggests alternative spellings. The user can ignore the misspelling, change to one of the suggested spellings, or type a spelling not suggested. A simple combo box is well suited for receiving this kind of user input.


Creating the Simple Dialog Box

The dialog box template defines the window styles and control identifier for the combo box. In this example, the combo box uses the CBS_SIMPLE, CBS_SORT, WS_VSCROLL, and WS_TABSTOP styles.

The dialog box also contains three buttons: Change (IDOK), Ignore (IDSKIP), and Cancel (IDCANCEL). The IDOK and IDCANCEL constants are defined by the Win32 API. The IDSKIP constant is defined in the application's header file, as is the control identifier for the combo box, IDCOMBO.

For more information about dialog boxes, see Dialog Boxes.


Processing the WM_INITDIALOG and WM_DESTROY Messages in a Simple Dialog Box

When you use a combo box in a dialog box, you usually respond to the WM_INITDIALOG message by initializing the combo box. The code example in Creating a Spell Dialog Box calls the application-defined OpenDictionary function to load the dictionary. It then calls the application-defined SelectNextWord and InitSpellList functions to select the first misspelled word.

SelectNextWord selects the next word in the edit control and copies it to the specified buffer. InitSpellList determines whether the selected word is in the dictionary. If not, it places the word in the selection field of the combo box and adds suggested spellings to the list.

The dialog box procedure processes the WM_DESTROY message to free the resources allocated to the spelling dictionary.


Processing the WM_COMMAND Message in a Simple Dialog Box

When an event occurs in a dialog box control, the control sends a WM_COMMAND message to the dialog box procedure. The high-order word of the wParam parameter is a notification code, indicating the type of event that occurred. The low-order word of wParam is a constant identifying the control. The lParam parameter is the window handle for the control.

When processing the WM_COMMAND message, the spelling checker example examines the control identifier in the low-order word of wParam to determine the origin of the message. The constants IDCOMBO, IDOK, IDIGNORE, and IDCANCEL identify the combo box, the Change button, the Ignore button, and the Cancel button controls, respectively.

A combo box may send a WM_COMMAND message for a number of different reasons. To determine the type of event, the dialog box procedure examines the notification code in the high-order word of wParam. The example processes only the CBN_DBLCLK notification message, which is sent when the user double-clicks a list item. The dialog box procedure processes this notification message in the same way as a Change button click.

The buttons in this example send WM_COMMAND messages only when they are chosen by the user. When the user chooses the Change button, the dialog box procedure replaces the current selection in the application's edit control with the content of the selection field in the combo box. The selection field may contain either the selected list item or text the user has typed. The dialog box procedure then selects the next misspelled word in the same way it processes an Ignore button click.

When the user chooses the Ignore button, the dialog box procedure calls the application-defined SelectNextWord and InitSpellList functions to select the next misspelled word in the application's edit control. InitSpellList places the misspelled word in the selection field of the combo box and adds suggested spellings to the combo box list.

When the user chooses the Cancel button, the dialog box procedure calls the EndDialog function to close the dialog box.


Creating a Spell Dialog Box

Following are the dialog box procedure and supporting functions for the spelling checker dialog box.

HWND hwndMain;

HWND hwndEdit;

char achTemp[256];       /* temporary buffer            */

LPSTR lpstrDict;         /* buffer for dictionary file  */

LPSTR *paLpDict;         /* array of pointers to words  */

UINT  cWords;            /* number of words             */

/********************************************************

    FUNCTION:   SpellDlgProc

    PURPOSE:    Dialog procedure for Spell dialog box.

*********************************************************/

BOOL CALLBACK SpellDlgProc(hwndDlg, msg, wParam, lParam)

HWND hwndDlg;

UINT msg;

WPARAM wParam;

LPARAM lParam;

{

    switch (msg) {

        case WM_INITDIALOG:

            if (!OpenDictionary()) {

                EndDialog(hwndDlg, 0);

                break;

            }

            SendMessage(hwndEdit, EM_SETSEL, 0, 0);

            do

                if (!SelectNextWord(hwndEdit, achTemp)) {

                    GlobalFree((HGLOBAL) lpstrDict);

                    LocalFree((HLOCAL) paLpDict);

                    EndDialog(hwndDlg, 0);

                    break;

                }

            while (!InitSpellList(

                GetDlgItem(hwndDlg, IDCOMBO), achTemp));

            break;

        case WM_COMMAND:

            switch (LOWORD(wParam)) {

                case IDCOMBO:

                    if (HIWORD(wParam) != CBN_DBLCLK)

                        break;

                    /* For a double-click, process the OK case. */

                case IDOK:

                    SendDlgItemMessage(hwndDlg, IDCOMBO,

                        WM_GETTEXT, sizeof(achTemp),

                        (LPARAM) achTemp);

                    SendMessage(hwndEdit, EM_REPLACESEL, 0,

                        (LPARAM) achTemp);

                    /* Fall through to get the next word. */

                case IDIGNORE:

                    do

                        if (!SelectNextWord(hwndEdit, achTemp)) {

                            EndDialog(hwndDlg, 0);

                            break;

                        }

                    while (!InitSpellList(GetDlgItem(hwndDlg,

                        IDCOMBO), achTemp));

                    break;

                case IDCANCEL:

                    EndDialog(hwndDlg, 0);

            }

            break;

        case WM_DESTROY:

            GlobalFree((HGLOBAL) lpstrDict);

            LocalFree((HLOCAL) paLpDict);

            break;

        default:

            return FALSE;

    }

    return TRUE;

}

/********************************************************

    FUNCTION:   InitSpellList

    PURPOSE:    Initializes the selection field and list

                of suggestions for the specified word, if

                it is not in the dictionary.

    RETURNS:    If the list is initialized, the return

                value is TRUE. If an error occurs or the

                word is in the dictionary, the return

                value is FALSE.

*********************************************************/

BOOL PASCAL InitSpellList(HWND hwndCombo, LPSTR lpszWord)

{

    int min = 0;        /* beginning of search range */

    int max = cWords;   /* end of search range       */

    int n;              /* index of word             */

    int cmp;            /* result of comparison      */

    char ch;            /* first character in word   */

    ch = *lpszWord;

    CharLowerBuff(&ch, 1);

    /*

     * Perform a binary search for the word.

     *

     * The global array paLpDict contains pointers to words

     * in the global array lpstrDict. These two variables are

     * initialized by the OpenDictionary function.

     */

    n = max / 2;

    while (min < max) {

        cmp = lstrcmpi(lpszWord, paLpDict[n]);

        if (cmp == 0)

            return FALSE;       /* not misspelled */

        if (cmp < 0)

            max = n;

        else

            min = n + 1;

        n = (min + max) / 2;

    }

    /* List words beginning with the same letter as lpszWord. */

    SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);

    while (n > 0 && *paLpDict[n - 1] == ch)

        n--;

    while (*paLpDict[n] == ch)

        SendMessage(hwndCombo, CB_ADDSTRING,

            0, (LPARAM) paLpDict[n++]);

    /* Place the word in the selection field. */

    SendMessage(hwndCombo, WM_SETTEXT, 0, (LPARAM) lpszWord);

    return TRUE;

}


Creating an Owner-Drawn Combo Box

This section describes how to use an owner-drawn combo box. The example in Creating a Square Meal Dialog Box uses an owner-drawn drop-down list box to display the four food groups, each represented by a bitmap and a name. Selecting a food group causes the foods in that group to appear in a list.


Creating the Owner-Drawn Dialog Box

The dialog box template defines the window styles, buttons, and control identifiers for the combo box. The combo box in this example uses the CBS_DROPDOWNLIST, CBS_OWNERDRAWFIXED, CBS_SORT, CBS_HASSTRINGS, WS_VSCROLL, and WS_TABSTOP styles.

The dialog box also contains a list box (IDLIST) and two buttons: OK (IDOK) and Cancel (IDCANCEL). The IDOK and IDCANCEL constants are defined by the Win32 API. The constant IDLIST is defined in the application's header file, as is the control identifier, IDCOMBO.

For more information about dialog boxes, see Dialog Boxes.


Processing the WM_INITDIALOG and WM_DESTROY Messages in an Owner-Drawn Dialog Box

When you use a combo box in a dialog box, you usually respond to a WM_INITDIALOG message by initializing the combo box. The example in Creating a Square Meal Dialog Box loads the bitmaps used for the owner-drawn combo box, then calls the application-defined InitGroupList function to initialize the combo box. It also selects the first list item in the combo box, then calls the application-defined InitFoodList function to initialize the list box.

In the example, the owner-drawn combo box is a drop-down list box containing the names of each of the four food groups. InitGroupList adds the name of each food group, and calls the application-defined SetItemData function to associate a constant with each list item that identifies a corresponding food group.

The list box in the example contains the names of foods in the selected food group. InitFoodList resets the contents of the list box, then adds the names of the current food selection in the current food group drop-down list box.

The dialog box procedure processes the WM_DESTROY message to delete the bitmaps in the owner-drawn combo box.


Processing the WM_MEASUREITEM Message

An owner-drawn combo box sends the WM_MEASUREITEM message to its parent window or dialog box procedure so the application can set the dimensions of each list item. Because the example combo box has the CBS_OWNERDRAWFIXED style, the system sends the WM_MEASUREITEM message only once. Combo boxes with the CBS_OWNERDRAWVARIABLE style send a WM_MEASUREITEM message for each list item.

The lParam parameter points to a MEASUREITEMSTRUCT structure that identifies the control and list item. It also contains the default dimensions of the list item. The example in Creating a Square Meal Dialog Box modifies the itemHeight structure member to ensure that the list items are high enough to accommodate the food-group bitmaps.


Processing the WM_DRAWITEM Message

An owner-drawn combo box sends the WM_DRAWITEM message to its parent window or dialog box procedure each time the application must repaint a list item. The lParam parameter points to a DRAWITEMSTRUCT structure that identifies the control and list item. It also contains information needed to paint the item.

The example in Creating a Square Meal Dialog Box displays the list-item text and the bitmap associated with the food group. If the item has the focus, it also draws a focus rectangle. Before displaying the text, the example sets the foreground and background colors, based on the item selected. Because the combo box has the CBS_HASSTRINGS style, the combo box maintains the text for each list item that can be retrieved using the CB_GETLBTEXT message.

The bitmaps used for the list item depend on the food group. InitGroupList uses the CB_SETITEMDATA message to associate a constant with each list item, identifying the corresponding food group. The window procedure uses this value, contained in the itemData member of the DRAWITEMSTRUCT structure, to determine which bitmaps to display. The system uses two bitmaps for each food group symbol: a monochrome bitmap with the SRCAND raster operation to erase the irregular region behind the image, and a color bitmap with the SRCPAINT raster operation to paint the image.


Processing the WM_COMMAND Message in an Owner-Drawn Dialog Box

When an event occurs in a dialog box control, the control notifies the dialog box procedure by means of a WM_COMMAND message. The example in Creating a Square Meal Dialog Box processes notification messages from the combo box, the list box, and the OK button. The control identifier is in the low-order word of wParam, and the notification message is in the high-order word of wParam.

If the control identifier is IDCOMBO, an event has occurred in the combo box. In response, the dialog box procedure ignores all other combo box events except CBN_SELENDOK, which indicates that a selection was made, the drop down was closed up, and the changes made should be accepted. The dialog box procedure calls InitFoodList to reset the contents of the list box and to add the names of the current selection in the drop-down list box.

If the control identifier is IDLIST, an event has occurred in the list box. This causes the dialog box procedure to ignore all list box events except LBN_DBLCLK, which indicates that the user has double-clicked a list item. This event is processed in the same way as if an OK button has been chosen.

If the control identifier is IDOK, the user has chosen the OK button. In response, the dialog box procedure inserts the name of the selected food into the application's multiline edit control, then calls the EndDialog function to close the dialog box.

If the control identifier is IDCANCEL, the user has clicked the Cancel button. In response, the dialog box procedure calls EndDialog to close the dialog box.


Creating a Square Meal Dialog Box

Following are the dialog box procedure and supporting functions for the Square Meal dialog box.

HWND hwndMain;

HWND hwndEdit;

char achTemp[256];       /* temporary buffer            */

HBITMAP hbmBread;

HBITMAP hbmDairy;

HBITMAP hbmFruit;

HBITMAP hbmMeat;

HBITMAP hbmBreadMask;

HBITMAP hbmDairyMask;

HBITMAP hbmFruitMask;

HBITMAP hbmMeatMask;

/********************************************************

    FUNCTION:   FoodDlgProc

    PURPOSE:    Dialog procedure for Food dialog box.

*********************************************************/

BOOL CALLBACK FoodDlgProc(hwndDlg, msg, wParam, lParam)

HWND hwndDlg;

UINT msg;

WPARAM wParam;

LPARAM lParam;

{

    LPMEASUREITEMSTRUCT lpmis;

    LPDRAWITEMSTRUCT lpdis;

    HBITMAP hbmIcon;

    HBITMAP hbmMask;

    COLORREF clrBackground;

    COLORREF clrForeground;

    TEXTMETRIC tm;

    HDC hdc;

    HWND hwnd;

    int x;

    int y;

    switch (msg) {

        case WM_INITDIALOG:

            /*

             * Call an application-defined function to load

             * bitmap resources.

             */

            if (!LoadIconBitmaps()) {

                EndDialog(hwndDlg, -1);

                break;

            }

            /* Initialize the drop-down list box. */

            if (!InitGroupList(hwndDlg)) {

                DeleteIconBitmaps();

                EndDialog(hwndDlg, -1);

                break;

            }

            /* Select the first food group. */

            SendDlgItemMessage(hwndDlg, IDCOMBO, CB_SETCURSEL,

                0, 0);

            /* List the foods and select the first food. */

            InitFoodList(hwndDlg);

            SendDlgItemMessage(hwndDlg, IDLIST, LB_SETCURSEL,

                0, 0);

            break;

        case WM_MEASUREITEM:

            lpmis = (LPMEASUREITEMSTRUCT) lParam;

            if (lpmis->itemHeight < CY_BITMAP + 2)

                lpmis->itemHeight = CY_BITMAP + 2;

            break;

        case WM_DRAWITEM:

            lpdis = (LPDRAWITEMSTRUCT) lParam;

            if (lpdis->itemID == -1)            /* empty item */

                break;

            /* Determine the bitmaps used to draw the icon. */

            switch (lpdis->itemData) {

                case ID_BREAD:

                    hbmIcon = hbmBread;

                    hbmMask = hbmBreadMask;

                    break;

                case ID_DAIRY:

                    hbmIcon = hbmDairy;

                    hbmMask = hbmDairyMask;

                    break;

                case ID_FRUIT:

                    hbmIcon = hbmFruit;

                    hbmMask = hbmFruitMask;

                    break;

                default:                /* meat */

                    hbmIcon = hbmMeat;

                    hbmMask = hbmMeatMask;

                    break;

            }

            /*

             * The colors depend on whether the item is

             * selected.

             */

            clrForeground = SetTextColor(lpdis->hDC,

                GetSysColor(lpdis->itemState & ODS_SELECTED ?

                COLOR_HIGHLIGHTTEXT : COLOR_WINDOWTEXT));

            clrBackground = SetBkColor(lpdis->hDC,

                GetSysColor(lpdis->itemState & ODS_SELECTED ?

                COLOR_HIGHLIGHT : COLOR_WINDOW));

            /* Calculate the vertical and horizontal position. */

            GetTextMetrics(lpdis->hDC, &tm);

            y = (lpdis->rcItem.bottom + lpdis->rcItem.top -

                tm.tmHeight) / 2;

            x = LOWORD(GetDialogBaseUnits()) / 4;

            /* Get and display the text for the list item. */

            SendMessage(lpdis->hwndItem, CB_GETLBTEXT,

                lpdis->itemID, (LPARAM) (LPCSTR) achTemp);

            ExtTextOut(lpdis->hDC, CX_BITMAP + 2 * x, y,

                ETO_CLIPPED | ETO_OPAQUE, &lpdis->rcItem,

                achTemp, lstrlen(achTemp), NULL);

            /* Restore the previous colors. */

            SetTextColor(lpdis->hDC, clrForeground);

            SetBkColor(lpdis->hDC, clrBackground);

            /* Show the icon. */

            hdc = CreateCompatibleDC(lpdis->hDC);

            if (hdc == NULL)

                break;

            SelectObject(hdc, hbmMask);

            BitBlt(lpdis->hDC, x, lpdis->rcItem.top + 1,

                CX_BITMAP, CY_BITMAP, hdc, 0, 0, SRCAND);

            SelectObject(hdc, hbmIcon);

            BitBlt(lpdis->hDC, x, lpdis->rcItem.top + 1,

                CX_BITMAP, CY_BITMAP, hdc, 0, 0, SRCPAINT);

            DeleteDC(hdc);

            /* If the item has the focus, draw focus rectangle. */

            if (lpdis->itemState & ODS_FOCUS)

                DrawFocusRect(lpdis->hDC, &lpdis->rcItem);

            break;

        case WM_COMMAND:

            switch (LOWORD(wParam)) {

                case IDCOMBO:

                    if (HIWORD(wParam) == CBN_SELENDOK) {

                        InitFoodList(hwndDlg);

                        SendDlgItemMessage(hwndDlg, IDLIST,

                            LB_SETCURSEL, 0, 0);

                    }

                    break;

                case IDLIST:

                    if (HIWORD(wParam) != LBN_DBLCLK)

                        break;

                    /* For a double-click, process the OK case. */

                case IDOK:

                    /* Get the text for the selected list item. */

                    hwnd = GetDlgItem(hwndDlg, IDLIST);

                    SendMessage(hwnd, LB_GETTEXT,

                        SendMessage(hwnd, LB_GETCURSEL, 0, 0),

                        (LPARAM) achTemp);

                    /* Insert the text into the edit window. */

                    SendMessage(hwndEdit, EM_REPLACESEL, 0,

                        (LPARAM) achTemp);

                    EndDialog(hwndDlg, 0);

                    break;

                case IDCANCEL:

                    hwnd = GetDlgItem(hwndDlg, IDCOMBO);

                    if (SendMessage(hwnd, CB_GETDROPPEDSTATE,

                            0, 0))

                        SendMessage(hwnd, CB_SHOWDROPDOWN,

                            FALSE, 0);

                    else

                        EndDialog(hwndDlg, 0);

            }

            break;

        case WM_DESTROY:

            /*

             * Call the application-defined function to free

             * bitmap resources.

             */

            DeleteIconBitmaps();

            break;

        default:

            return FALSE;

    }

    return TRUE;

}

/********************************************************

    FUNCTION:   InitGroupList

    PURPOSE:    Initializes the "food groups" drop-down

                list box.

    COMMENTS:   The ID of the food group associated with

                each list item is saved as item data.

*********************************************************/

BOOL PASCAL InitGroupList(HWND hwndDlg)

{

    HWND hwndCombo = GetDlgItem(hwndDlg, IDCOMBO);

    DWORD dwIndex;

    /* Add an item for each food group. */

    LoadString(hinst, ID_BREAD, achTemp, sizeof(achTemp));

    dwIndex = SendMessage(hwndCombo, CB_ADDSTRING, 0,

        (LPARAM) (LPCSTR) achTemp);

    SendMessage(hwndCombo, CB_SETITEMDATA, dwIndex, ID_BREAD);

    LoadString(hinst, ID_DAIRY, achTemp, sizeof(achTemp));

    dwIndex = SendMessage(hwndCombo, CB_ADDSTRING, 0,

        (LPARAM) (LPCSTR) achTemp);

    SendMessage(hwndCombo, CB_SETITEMDATA, dwIndex, ID_DAIRY);

    LoadString(hinst, ID_FRUIT, achTemp, sizeof(achTemp));

    dwIndex = SendMessage(hwndCombo, CB_ADDSTRING, 0,

        (LPARAM) (LPCSTR) achTemp);

    SendMessage(hwndCombo, CB_SETITEMDATA, dwIndex, ID_FRUIT);

    LoadString(hinst, ID_MEAT, achTemp, sizeof(achTemp));

    dwIndex = SendMessage(hwndCombo, CB_ADDSTRING, 0,

        (LPARAM) (LPCSTR) achTemp);

    SendMessage(hwndCombo, CB_SETITEMDATA, dwIndex, ID_MEAT);

    return TRUE;

}

/********************************************************

    FUNCTION:   InitFoodList

    PURPOSE:    Clears the contents of the food list, and

                adds the names of foods for the current

                food group.

*********************************************************/

void PASCAL InitFoodList(HWND hwndDlg)

{

    HWND hwndCombo = GetDlgItem(hwndDlg, IDCOMBO);

    HWND hwndList = GetDlgItem(hwndDlg, IDLIST);

    UINT idFoodGroup;

    LPSTR lpsz;

    LPSTR lpszEnd;

    /* Determine the current food group. */

    idFoodGroup = SendMessage(

        hwndCombo,

        CB_GETITEMDATA,

        SendMessage(hwndCombo, CB_GETCURSEL, 0, 0),

        0

    );

    /* Clear the list contents. */

    SendMessage(hwndList, LB_RESETCONTENT, 0, 0);

    .

    .   /* Add food names for the current food group. */

    .

}


Subclassing a Combo Box

This section demonstrates how to subclass combo boxes so your application can use them outside a dialog box. The example in Creating a Combo-box Toolbar shows the window procedure for a toolbar window containing two combo boxes. By subclassing the edit controls within the combo boxes, the toolbar window intercepts TAB, ENTER, and ESC keys that would otherwise be ignored.

The following illustration shows the toolbar window.


Processing the WM_CREATE Message

The example in Creating a Combo-box Toolbar processes the WM_CREATE message to create two combo box controls as child windows. It then subclasses the edit controls (selection fields) in each combo box because they receive the character input for simple and drop-down combo box. The application gets the handle of each edit control by using the ChildWindowFromPoint function.

To subclass the edit controls, the application calls the SetWindowLong function, replacing the address of the class window procedure with the address of the application-defined SubClassProc function. The address of the original window procedure is saved in the global variable lpfnEditWndProc.

SubClassProc intercepts TAB, ESC, and ENTER keys and notifies the toolbar window by sending application-defined messages (WM_TAB, WM_ESC, and WM_ENTER). SubClassProc uses the CallWindowProc function to pass most messages to the original window procedure, lpfnEditWndProc.


Processing the WM_SETFOCUS Message

When the toolbar window receives the input focus, it immediately sets the focus to the first combo box in the toolbar. To do so, the example in Creating a Combo-box Toolbar calls the SetFocus function in response to the WM_SETFOCUS message.


Processing the Application-Defined Messages

In the example in Creating a Combo-box Toolbar, SubClassProc sends application-defined messages to the toolbar window when the user presses the TAB, ESC, or ENTER key in a combo box. The WM_TAB message is sent for the TAB key, the WM_ESC message for the ESC key, and the WM_ENTER message for the ENTER key.

The example processes the WM_TAB message by setting the focus to the next combo box in the toolbar. It processes the WM_ESC message by setting the focus to the main application window.

In response to the WM_ENTER message, the example ensures that the current selection for the combo box is valid and then sets the focus to the main application window. If the combo box contains no current selection, the example uses the CB_FINDSTRINGEXACT message to search for a list item that matches the contents of the selection field. If there is a match, the example sets the current selection; otherwise, it adds a new list item.


Creating a Combo-box Toolbar

Following are the window procedure for the toolbar and the subclass procedure for the two combo boxes.

#define WM_TAB (WM_USER)

#define WM_ESC (WM_USER + 1)

#define WM_ENTER (WM_USER + 2)

HWND hwndMain;

HWND hwndEdit;

WNDPROC lpfnEditWndProc; /* original window procedure for */

                         /*   the combo box edit windows  */

int cyToolbar;           /* toolbar window height        */

/********************************************************

    FUNCTION:   ToolbarWindowProc

    PURPOSE:    Window procedure for the toolbar window

*********************************************************/

LRESULT CALLBACK ToolbarWindowProc(hwnd, msg, wParam, lParam)

HWND hwnd;

UINT msg;

WPARAM wParam;

LPARAM lParam;

{

    static HWND   hwndEdit1;

    static HWND   hwndEdit2;

    static HWND   hwndCombo1;

    static HWND   hwndCombo2;

    .

    .

    .

    POINT       pt;

    DWORD       dwBaseUnits;

    HWND        hwndCombo;

    DWORD       dwIndex;

    switch (msg) {

        case WM_CREATE:

            /* Create two combo box child windows. */

            dwBaseUnits = GetDialogBaseUnits();

            hwndCombo1 = CreateWindow("COMBOBOX", "",

                CBS_DROPDOWN | WS_CHILD | WS_VISIBLE,

                (6 * LOWORD(dwBaseUnits)) / 4,

                (2 * HIWORD(dwBaseUnits)) / 8,

                (100 * LOWORD(dwBaseUnits)) / 4,

                (50 * HIWORD(dwBaseUnits)) / 8,

                hwnd, NULL, hinst, NULL);

            hwndCombo2 = CreateWindow("COMBOBOX", "",

                CBS_DROPDOWN | WS_CHILD | WS_VISIBLE,

                (112 * LOWORD(dwBaseUnits)) / 4,

                (2 * HIWORD(dwBaseUnits)) / 8,

                (100 * LOWORD(dwBaseUnits)) / 4,

                (50 * HIWORD(dwBaseUnits)) / 8,

                hwnd, NULL, hinst, NULL);

            /* Get the edit window handle for each combo box. */

            pt.x = 1;

            pt.y = 1;

            hwndEdit1 = ChildWindowFromPoint(hwndCombo1, pt);

            hwndEdit2 = ChildWindowFromPoint(hwndCombo2, pt);

            /*

             * Change the window procedure for both edit windows

             * to the subclass procedure.

             */

            lpfnEditWndProc = (WNDPROC) SetWindowLong(hwndEdit1,

                GWL_WNDPROC, (DWORD) SubClassProc);

            SetWindowLong(hwndEdit2, GWL_WNDPROC,

                (DWORD) SubClassProc);

            break;

        case WM_SETFOCUS:

            SetFocus(hwndCombo1);

            break;

        case WM_TAB:

            if (GetFocus() == hwndEdit1)

                SetFocus(hwndCombo2);

            else

                SetFocus(hwndCombo1);

            break;

        case WM_ESC:

            hwndCombo = GetFocus() == hwndEdit1 ?

                hwndCombo1 : hwndCombo2;

            /* Clear the current selection. */

            SendMessage(hwndCombo, CB_SETCURSEL,

                (WPARAM) (-1), 0);

            /* Set the focus to the main window. */

            SetFocus(hwndMain);

            break;

        case WM_ENTER:

            hwndCombo = GetFocus() == hwndEdit1 ?

                hwndCombo1 : hwndCombo2;

            SetFocus(hwndMain);

            /* If there is no current selection, set one. */

            if (SendMessage(hwndCombo, CB_GETCURSEL, 0, 0)

                    == CB_ERR) {

                if (SendMessage(hwndCombo, WM_GETTEXT,

                        sizeof(achTemp), (LPARAM) achTemp) == 0)

                    break;      /* empty selection field */

                dwIndex = SendMessage(hwndCombo,

                    CB_FINDSTRINGEXACT, (WPARAM) (-1),

                    (LPARAM) achTemp);

                /* Add the string, if necessary, and select it. */

                if (dwIndex == CB_ERR)

                    dwIndex = SendMessage(hwndCombo, CB_ADDSTRING,

                        0, (LPARAM) achTemp);

                if (dwIndex != CB_ERR)

                    SendMessage(hwndCombo, CB_SETCURSEL,

                        dwIndex, 0);

            }

            break;

            .

            .   /* Process additional messages. */

            .

        default:

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

    }

    return 0;

}

/********************************************************

    FUNCTION:   SubClassProc

    PURPOSE:    Process TAB and ESCAPE keys, and pass all

                other messages to the class window

                procedure.

*********************************************************/

LRESULT CALLBACK SubClassProc(hwnd, msg, wParam, lParam)

HWND hwnd;

UINT msg;

WPARAM wParam;

LPARAM lParam;

{

    switch (msg) {

        case WM_KEYDOWN:

            switch (wParam) {

                case VK_TAB:

                    SendMessage(hwndToolbar, WM_TAB, 0, 0);

                    return 0;

                case VK_ESCAPE:

                    SendMessage(hwndToolbar, WM_ESC, 0, 0);

                    return 0;

                case VK_RETURN:

                    SendMessage(hwndToolbar, WM_ENTER, 0, 0);

                    return 0;

            }

            break;

        case WM_KEYUP:

        case WM_CHAR:

            switch (wParam) {

                case VK_TAB:

                case VK_ESCAPE:

                case VK_RETURN:

                    return 0;

            }

    }

    /*

     * Call the original window procedure for default

     * processing.

     */

    return CallWindowProc(lpfnEditWndProc, hwnd,

        msg, wParam, lParam);

}


Combo Box Reference

The following functions and messages are associated with combo boxes.


Combo Box Functions

Following are the functions used with combo boxes.

DlgDirListComboBox
DlgDirSelect
DlgDirSelectComboBox
DlgDirSelectComboBoxEx


Combo Box Messages

Following are the messages used with combo boxes.

CB_ADDSTRING
CB_DELETESTRING
CB_DIR
CB_FINDSTRING
CB_FINDSTRINGEXACT
CB_GETCOUNT
CB_GETCURSEL
CB_GETDROPPEDCONTROLRECT
CB_GETEDITSEL
CB_GETEXTENDEDUI
CB_GETITEMDATA
CB_GETITEMHEIGHT
CB_GETLBTEXT
CB_GETLBTEXTLEN
CB_GETLOCALE
CB_INSERTSTRING
CB_LIMITTEXT
CB_RESETCONTENT
CB_SELECTSTRING
CB_SETCURSEL
CB_SETEDITSEL
CB_SETEXTENDEDUI
CB_SETITEMDATA
CB_SETITEMHEIGHT
CB_SETLOCALE
CB_SHOWDROPDOWN
CBN_CLOSEUP
CBN_DBLCLK
CBN_DROPDOWN
CBN_EDITCHANGE
CBN_EDITUPDATE
CBN_ERRSPACE
CBN_KILLFOCUS
CBN_SELCHANGE
CBN_SELENDCANCEL
CBN_SELENDOK
CBN_SETFOCUS
WM_COMPAREITEM
WM_DRAWITEM
WM_MEASUREITEM


Controls

In Microsoft® Windows®, a control is a child window an application uses in conjunction with another window to perform simple input and output (I/O) tasks. Controls are most often used within dialog boxes, but they can also be used in other windows. Controls within dialog boxes provide the user with the means to type text, choose options, and direct a dialog box to complete its action. Controls in other windows provide a variety of services, such as letting the user choose commands, view status, and view and edit text.


About Controls

Controls, like other windows, each belong to a window class, either predefined or application defined. The window class and the corresponding window procedure define the properties of the control, its appearance, behavior, and purpose. An application can create controls individually by specifying the name of the window class when calling the CreateWindowEx function. An application can also direct Windows to create controls for a dialog box by specifying the controls in the dialog box template.

Controls are child windows. When Windows creates controls for a dialog box, each control is the child of the dialog box. When an application creates a control, the control is the child of a window identified by the application. This relationship is important because a control sends messages, called notification messages, to its parent window when events, such as input from the user, occur in the control. The application relies on these notification messages to determine what action the user wants the application to take.

Because controls are windows, an application can manipulate them by using the window-management functions, such as the ShowWindow and EnableWindow functions. If the window class for a control supports control messages, an application can also manipulate a control of that class by using the SendMessage function to send these messages to the control. The purpose and function of each control message is specific to the window class and is defined by the control's window procedure.


Predefined Controls

Windows provides several predefined window classes for controls. Controls belonging to these window classes are called predefined controls. An application creates a predefined control of a particular type by specifying the appropriate window class name in either the CreateWindowEx function or the dialog box template. Following are the predefined window classes.

Name	Description
BUTTON	Creates button controls. These controls typically notify the parent window when the user chooses the control.
COMBOBOX	Creates combo boxes. These controls are a combination of list boxes and edit controls, letting the user choose and edit items.
EDIT	Creates edit controls. These controls let the user view and edit text.
LISTBOX	Creates list boxes. These controls display a list from which the user can select one or more items.
SCROLLBAR	Creates scroll bar controls. These controls let the user choose the direction and distance to scroll information in a related window.
STATIC	Creates static controls. These controls often act as labels for other controls.
Each predefined window class has a corresponding set of control styles that enable an application to vary the appearance and behavior of the controls it creates. For example, the BUTTON class supports styles to create push buttons, radio buttons, check boxes, and group boxes. An application specifies the style when creating the control.

Each predefined window class has a corresponding set of notification and control messages. Applications rely on the notification messages to determine when the user has provided input to the controls. For example, a push button sends a BN_CLICKED message to the parent window when the user clicks the button. Applications use the control messages to retrieve information from the controls and to manipulate the appearance and behavior of the controls. For example, an application can send a BM_GETCHECK message to a check box to determine whether it currently contains a check mark.

Most applications make extensive use of predefined controls in dialog boxes and other windows. Because predefined controls offer many capabilities, a full discussion of each is beyond the scope of this topic.


Custom Controls

Applications can create custom controls to perform tasks not supported by predefined controls. Windows provides the following ways to create custom controls:

•	Use owner-drawn buttons, list boxes, and combo boxes.

•	Subclass an existing control-window class.

•	Register and implement from scratch an application-defined window class.

Buttons, list boxes, and combo boxes have owner-drawn styles available that direct the control to send a message to the parent window whenever the control must be drawn. This feature permits an application to alter the appearance of a control. For buttons, the owner-drawn style affects how the system draws the entire control. For list boxes and combo boxes, the parent window draws the items within the control, and the control draws its own outline. For example, an application can customize a list box so that it displays a small bitmap next to each item in the list.

An application can designate list boxes, combo boxes, and buttons as owner-drawn controls by creating them with the appropriate style. When a control has the owner-drawn style, Windows handles the user's interaction with the control as usual, performing such tasks as detecting when a user has chosen a button and notifying the button's owner of the event. However, because the control is owner drawn, the parent window of the control is responsible for the visual appearance of the control. For more information about owner-drawn controls, see the individual topics for buttons, list boxes, and combo boxes.

Subclassing an existing control is another way to create a custom control. The subclass procedure can alter selected behaviors of the control by processing those messages that affect the selected behaviors. All other messages pass to the original window procedure for the control. For example, an application can display a small bitmap next to the text in a read-only, single-line edit control by subclassing the control and processing the WM_PAINT message. For more information about subclassing, see Window Classes.

Although an application may subclass a predefined control, it relies on the window procedure of the control to provide all other aspects of the control's behavior. For more information about a control's behavior, see the individual topics for the predefined controls.

An application can create custom controls by registering an application-defined window class and specifying the name of the window class in the CreateWindowEx function or in the dialog box template. The process for registering an application-defined window class for a custom control is the same as for registering a class for an ordinary window. Each class must have a unique name, a corresponding window procedure, and other information.

At a minimum, the window procedure draws the control. If an application uses the control to let the user type information, the window procedure also processes input messages from the keyboard and mouse and sends notification messages to the parent window. In addition, if the control supports control messages, the window procedure processes messages sent to it by the parent window or other windows. For example, controls often process the WM_GETDLGCODE message sent by dialog boxes to direct a dialog box to process keyboard input in a given way.


Control Notification Messages

A control should send a notification message to its parent window to notify the parent about user input or changes to the control. The notification message is a WM_COMMAND message that includes a control identifier and a notification code identifying the nature of the event. A control identifier is a unique number the application uses to identify the control sending the message. The application sets the identifier for a control when it creates the control. The application specifies the identifier either in the hMenu parameter of the CreateWindowEx function or in the id member of the dialog box template (the DLGITEMTEMPATE structure).

Because the control does not set the control identifier, the control must retrieve the identifier before it can send notification messages. A control must use the GetDlgCtrlID function to retrieve its own control identifier. Although the control identifier is specified as the menu handle when the control is created, the GetMenu function cannot be used to retrieve the identifier. Alternatively, a control can retrieve the identifier from the hMenu member in the CREATESTRUCT structure while processing the WM_CREATE message.


Control Messages

A parent window or other windows send control messages to direct a control to perform specific tasks. The window procedure processes these messages and carries out the requested action.

Control messages can be predefined or application defined. Windows has several predefined messages, such as WM_GETTEXT and WM_GETDLGCODE, that it sends to controls. These messages typically correspond to window-management functions that carry out actions on windows. In general, the window procedure for an application-defined control should process any predefined control message in the following table if the message affects the operation of the control.

Message	Recommendation
WM_GETDLGCODE	Process if the control uses the ENTER, ESC, TAB, or arrow keys. The IsDialogMessage function sends this message to controls in a dialog box to determine whether to process the keys or pass them to the control.
WM_GETFONT	Process if the WM_SETFONT message is also processed.
WM_GETTEXT	Process if the control text is not the same as the title specified by the CreateWindowEx function.
WM_GETTEXTLENGTH	Process if the control text is not the same as the title specified by the CreateWindowEx function.
WM_KILLFOCUS	Process if the control displays a caret, a focus rectangle, or another item to indicate that it has the input focus.
WM_SETFOCUS	Process if the control displays a caret, a focus rectangle, or another item to indicate that it has the input focus.
WM_SETTEXT	Process if the control text is not the same as the title specified by the CreateWindowEx function.
WM_SETFONT	Process if the control displays text. Windows sends this message when creating a dialog box that has the DS_SETFONT style.
Application-defined control messages are specific to the given control and must be explicitly sent to the control by using a SendMessage or SendDlgItemMessage function. The numeric value for each message must be unique and must not conflict with the values of other window messages. To ensure that application-defined message values do not conflict, an application should create each value by adding a unique number to the WM_USER value.


Control Messages

Following are the messages used with controls.

WM_GETFONT
WM_SETFONT
WM_SETTEXT


Dialog Boxes

In Microsoft® Windows®, a dialog box is a temporary window an application creates to retrieve user input. An application typically uses dialog boxes to prompt the user for additional information for commands. A dialog box usually contains one or more controls (child windows) with which the user enters text, chooses options, or directs the action of the command.


About Dialog Boxes

Windows provides many functions, messages, and predefined controls to help create and manage dialog boxes, thus making it easier to develop the user interface for an application. This overview describes the dialog box functions and messages and explains how to use them to create and use dialog boxes.

Windows also provides many predefined, or "common," dialog boxes that support commands, such as File Open and File Print. Applications that use these commands should use the common dialog boxes to prompt for the same user input, regardless of the type of application carrying out the commands. For more information about using common dialog boxes in your applications, see Common Dialog Box Library.


When to Use a Dialog Box

Most applications use dialog boxes to prompt for additional information for commands that require user input. Using a dialog box is the only recommended way for an application to retrieve the input. For example, the File Open command requires the name of a file to open, so an application should use a dialog box to prompt the user for the name. In such cases, the application creates the dialog box when the user chooses the command and destroys the dialog box immediately after the user supplies the information.

Many applications also use dialog boxes to display information or options while the user works in another window. For example, word processing applications often use a dialog box with a text-search command. While the application searches for the text, the dialog box remains on the screen. The user can then return to the dialog box and search for the same word again; or the user can change the entry in the dialog box and search for a new word. Applications that use dialog boxes in this way typically create one when the user chooses a command and continue to display it for as long as the application runs or until the user explicitly closes the dialog box.

To support the different ways applications use dialog boxes, Windows provides two types of dialog box: modal and modeless. A modal dialog box requires the user to supply information or cancel the dialog box before allowing the application to continue. Applications use modal dialog boxes in conjunction with commands that require additional information before they can proceed. A modeless dialog box allows the user to supply information and return to the previous task without closing the dialog box. Modal dialog boxes are simpler to manage than modeless dialog boxes because they are created, perform their task, and are destroyed by calling a single function.

To create either a modal or modeless dialog box, an application must supply a dialog box template to describe the dialog box style and content; the application must also supply a dialog box procedure to carry out tasks. The dialog box template is a binary description of the dialog box and the controls it contains. The developer can create this template as a resource to be loaded from the application's executable file, or created in memory while the application runs. The dialog box procedure is an application-defined callback function that Windows calls when it has input for the dialog box or tasks for the dialog box to carry out. Although a dialog box procedure is similar to a window procedure, it does not have the same responsibilities.

An application typically creates a dialog box by using either the DialogBox or CreateDialog function. DialogBox creates a modal dialog box; CreateDialog creates a modeless dialog box. These two functions load a dialog box template from the application's executable file and create a pop-up window that matches the template's specifications. There are other functions that create a dialog box by using templates in memory and pass additional information to the dialog box procedure as the dialog box is created.

Dialog boxes usually belong to a predefined, exclusive window class. Windows uses this window class and its corresponding window procedure for both modal and modeless dialog boxes. When the function is called, it creates the window for the dialog box, as well as the windows for the controls in the dialog box, then sends selected messages to the dialog box procedure. While the dialog box is visible, the predefined window procedure manages all messages, processing some messages and passing others to the dialog box procedure so that the procedure can carry out tasks. Applications do not have direct access to the predefined window class or window procedure, but they can use the dialog box template and dialog box procedure to modify the style and behavior of a dialog box.


Owner Window

Most dialog boxes have an owner window (or more simply, an owner). When creating the dialog box, the application sets the owner by specifying the owner's window handle. Windows uses the owner to determine the position of the dialog box in the Z order so that the dialog box is always positioned above its owner. Also, Windows can send messages to the window procedure of the owner, notifying it of events in the dialog box.

Windows automatically hides or destroys the dialog box whenever its owner is hidden or destroyed. This means the dialog box procedure requires no special processing to detect changes to the state of the owner window.

Because the typical dialog box is used in conjunction with a command in a menu, the owner window is usually the window containing the menu. Although it is possible to create a dialog box that has no owner, it is not recommended. For example, when a modal dialog box has no owner, Windows does not disable any of the application's other windows and allows the user to continue to carry out work in the other windows, defeating the purpose of the modal dialog box.

When a modeless dialog box has no owner, Windows neither hides nor destroys the dialog box when other windows in the application are hidden or destroyed. Although this does not defeat the purpose of the modeless dialog box, it requires that the application carry out special processing to ensure the dialog box is hidden and destroyed at appropriate times.


Message Boxes

A message box is a special dialog box that an application can use to display messages and prompt for simple input. A message box typically contains a text message and one or more buttons. An application creates the message box by using the MessageBox or MessageBoxEx function, specifying the text and the number and types of buttons to display. The MessageBoxEx function also allows you to specify the language to use for the text of any predefined push buttons in the message box.

Although the message box is a dialog box, Windows takes complete control of the creation and management of the message box. This means the application does not provide a dialog box template and dialog box procedure. Windows creates its own template based on the text and buttons specified for the message box and supplies its own dialog box procedure.

A message box is a modal dialog box and Windows creates it by using the same internal functions that DialogBox uses. If the application specifies an owner window when calling MessageBox or MessageBoxEx, Windows disables the owner. An application can also direct Windows to disable all top-level windows belonging to the current task by specifying the MB_TASKMODAL value when creating the dialog box.

Windows can send messages to the owner, such as WM_CANCELMODE and WM_ENABLE, just as it does when creating a modal dialog box. The owner window should carry out any actions requested by these messages.


Modal Dialog Boxes

A modal dialog box should be a pop-up window having a System menu, a title bar, and a thick border; that is, the dialog box template should specify the WS_POPUP, WS_SYSMENU, WS_CAPTION, and DS_MODALFRAME styles. Although an application can designate the WS_VISIBLE style, Windows always displays a modal dialog box regardless of whether the dialog box template specifies the WS_VISIBLE style. An application must not create a modal dialog box having the WS_CHILD style. A modal dialog box with this style disables itself, preventing any subsequent input from reaching the application.

An application creates a modal dialog box by using either the DialogBox or DialogBoxIndirect function. DialogBox requires the name or identifier of a resource containing a dialog box template; DialogBoxIndirect requires the handle of a memory object containing a dialog box template. The DialogBoxParam and DialogBoxIndirectParam functions also create modal dialog boxes; they are identical to the previously mentioned functions but pass a specified parameter to the dialog box procedure when the dialog box is created.

When creating the modal dialog box, Windows makes it the active window. The dialog box remains active until the dialog box procedure calls the EndDialog function or Windows activates a window in another application. Neither the user nor the application can make the owner window active until the modal dialog box is destroyed.

When the owner window is not already disabled, Windows automatically disables the window and any child windows belonging to it when it creates the modal dialog box. The owner window remains disabled until the dialog box is destroyed. Although a dialog box procedure could potentially enable the owner window at any time, enabling the owner defeats the purpose of the modal dialog box and is not recommended. When the dialog box procedure is destroyed, Windows enables the owner window again, but only if the modal dialog box caused the owner to be disabled.

As Windows creates the modal dialog box, it sends the WM_CANCELMODE message to the window (if any) currently capturing mouse input. An application that receives this message should release the mouse capture so that the user can move the mouse in the modal dialog box. Because Windows disables the owner window, all mouse input is lost if the owner fails to release the mouse upon receiving this message.

To process messages for the modal dialog box, Windows starts its own message loop, taking temporary control of the message queue for the entire application. When Windows retrieves a message that is not explicitly for the dialog box, it dispatches the message to the appropriate window. If it retrieves a WM_QUIT message, it posts the message back to the application message queue so that the application's main message loop can eventually retrieve the message.

Windows sends the WM_ENTERIDLE message to the owner window whenever the application message queue is empty. The application can use this message to carry out a background task while the dialog box remains on the screen. When an application uses the message in this way, the application must frequently yield control (for example, by using the PeekMessage function) so that the modal dialog box can receive any user input. To prevent the modal dialog box from sending the WM_ENTERIDLE messages, the application can specify the DS_NOIDLEMSG style when creating the dialog box.

An application destroys a modal dialog box by using the EndDialog function. In most cases, the dialog box procedure calls EndDialog when the user chooses the Close command from the dialog box's System menu or chooses the OK or Cancel button in the dialog box. The dialog box can return a value through the DialogBox function (or other creation functions) by specifying a value when calling the EndDialog function. Windows returns this value after destroying the dialog box. Most applications use this return value to determine whether the dialog box completed its task successfully or was canceled by the user. Windows does not return control from the function that creates the dialog box until the dialog box procedure has called the EndDialog function.


Modeless Dialog Boxes

A modeless dialog box should be a pop-up window having a System menu, a title bar, and a thin border; that is, the dialog box template should specify the WS_POPUP, WS_CAPTION, WS_BORDER, and WS_SYSMENU styles. Windows does not automatically display the dialog box unless the template specifies the WS_VISIBLE style.

An application creates a modeless dialog box by using the CreateDialog or CreateDialogIndirect function. CreateDialog requires the name or identifier of a resource containing a dialog box template; CreateDialogIndirect requires the handle of a memory object containing a dialog box template. Two other functions, CreateDialogParam and CreateDialogIndirectParam, also create modeless dialog boxes; they pass a specified parameter to the dialog box procedure when the dialog box is created.

CreateDialog and other creation functions return a window handle for the dialog box. The application and the dialog box procedure can use this handle to manage the dialog box. For example, if WS_VISIBLE is not specified in the dialog box template, the application can display the dialog box by passing the window handle to the ShowWindow function.

A modeless dialog box neither disables the owner window nor sends messages to it. When creating the dialog box, Windows makes it the active window, but the user or the application can change the active window at any time. If the dialog box does become inactive, it remains above the owner window in the Z order, even if the owner window is active.

The application is responsible for retrieving and dispatching input messages to the dialog box. Most applications use the main message loop for this. To permit the user to move to and select controls by using the keyboard, however, the application must call the IsDialogMessage function. For more information about this function, see Dialog Box Keyboard Interface.

A modeless dialog box cannot return a value to the application as a modal dialog box does, but the dialog box procedure can send information to the owner window by using the SendMessage function.

An application must destroy all modeless dialog boxes before terminating. It can destroy a modeless dialog box by using the DestroyWindow function. In most cases, the dialog box procedure calls DestroyWindow in response to user input, such as choosing the Cancel button. If the user never closes the dialog box in this way, the application must call DestroyWindow.

DestroyWindow invalidates the window handle for the dialog box, so any subsequent calls to functions that use the handle return error values. To prevent errors, the dialog box procedure should notify the owner that the dialog box has been destroyed. Many applications maintain a global variable containing the handle for the dialog box. When the dialog box procedure destroys the dialog box, it also sets the global variable to NULL, indicating that the dialog box is no longer valid.

The dialog box procedure must not call the EndDialog function to destroy a modeless dialog box.


Dialog Box Template

A dialog box template is binary data that describes the dialog box, defining its height, width, style, and the controls it contains. To create a dialog box, Windows either loads a dialog box template from the resources in the application's executable file or uses the template passed to it in global memory by the application. In either case, the application must supply a template when creating a dialog box.

A developer creates template resources by using a resource compiler or a dialog box editor. A resource compiler converts a text description into a binary resource, and a dialog box editor saves an interactively constructed dialog box as a binary resource.

Note  An explanation of how to create template resources and add them to the application's executable file is beyond the scope of this book. For more information about creating template resources and adding them to an executable file, see the documentation provided with your application development tools.

Applications that create dialog boxes without using template resources must create templates in memory and pass the templates to either the DialogBoxIndirect or CreateDialogIndirect function. An application creates a memory template by allocating a global memory object and filling it with a DLGTEMPLATE structure and one or more DLGITEMTEMPLATE structures. A memory template is identical in form and content to a template resource. Many applications that use memory templates first load a template resource into memory by using the LoadResource function, then modify the loaded resource to create a new memory template.

The following sections describe the styles, measurements, and other values used in a dialog box template.


Dialog Box Template Styles

Every dialog box template specifies a combination of style values that define the appearance and features of the dialog box. The style values can be window styles, such as WS_POPUP and WS_SYSMENU, and dialog box styles, such as DS_MODALFRAME. The number and type of styles for a template depends on the type and purpose of the dialog box.

Windows passes all window styles given in the template to the CreateWindowEx function when creating the dialog box. Windows may pass one or more extended styles depending on the given dialog box styles. For example, when the template specifies DS_MODALFRAME, Windows uses WS_EX_DLGMODALFRAME when creating the dialog box. When the template specifies DS_SYSMODAL, Windows uses WS_EX_TOPMOST. All other dialog box styles affect how Windows manages the dialog box.

Most dialog boxes are pop-up windows that have a System menu and a title bar. Therefore, the typical template specifies the WS_POPUP, WS_SYSMENU, and WS_CAPTION styles. The template also specifies a border style: WS_BORDER for modeless dialog boxes, and DS_MODALFRAME for modal dialog boxes. A template may specify a window type other than pop-up (such as WS_OVERLAPPED) if it creates a customized window instead of a dialog box.

Windows always displays a modal dialog box regardless of whether the WS_VISIBLE style is given. When the template for a modeless dialog box specifies the WS_VISIBLE style, Windows automatically displays the dialog box when it is created. Otherwise, the application is responsible for displaying the dialog box by using the ShowWindow function.

The template can specify the DS_SETFOREGROUND style to force Windows to bring the dialog box to the foreground. This is especially useful for modal dialog boxes that require immediate attention from the user regardless of whether the owner window is the foreground window.

Using the DS_ABSALIGN style, Windows interprets dialog box measurements as screen coordinates; using the DS_SETFONT style, Windows uses a given font, instead of the system font, to draw text in the dialog box client area and in the controls in the dialog box; the DS_NOIDLEMSG style prevents a modal dialog box from sending WM_ENTERIDLE messages to the owner window. These styles are described in more detail in later topics.

The DS_LOCALEDIT style does not apply to Win32-based applications.

Dialog boxes with the DS_SYSMODAL style receive the WS_EX_TOPMOST window style but no other special properties or styles; this means the user still has access to other windows on the desktop even though a DS_SYSMODAL dialog box may be displayed.


Dialog Box Measurements

Every dialog box template contains measurements that specify the position, width, and height of the dialog box and the controls it contains. These measurements are device independent, so an application can use a single template to create the same dialog box for all types of display devices. This ensures that a dialog box will have the same proportions and appearance on all screens despite differing resolutions and aspect ratios between screens.

Dialog box measurements are given in dialog base units. One horizontal unit is equal to one-fourth of the average character width for the system font. One vertical unit is equal to one-eighth of the average character height for the system font. An application can retrieve the number of pixels per base unit for the current display by using the GetDialogBaseUnits function. An application can convert measurements from dialog base units to pixels by using the MapDialogRect function.

The template must specify the initial coordinates of the upper left corner of the dialog box. Usually the coordinates are relative to the upper left corner of the owner window's client area. When the template specifies the DS_ABSALIGN style or the dialog box has no owner, the position is relative to the upper left corner of the screen. Windows sets this initial position when creating the dialog box, but permits an application to adjust the position before displaying the dialog box. For example, an application can retrieve the dimensions of the owner window, calculate a new position that centers the dialog box in the owner window, and then set the position by using the SetWindowPos function.

The template should specify a dialog box width and height that does not exceed the width and height of the screen and ensures that all controls and are within the client area of the dialog box. Although Windows permits a dialog box to be any size, creating one that is too small or too large can prevent the user from providing input, defeating the purpose of the dialog box. Many applications use more than one dialog box when there are a large number of controls. In such cases, the initial dialog box usually contains one or more buttons that the user can choose to display the next dialog box.


Dialog Box Controls

The template specifies the position, width, height, style, identifier, and window class for each control in the dialog box. Windows creates each control by passing this data to the CreateWindowEx function. Controls are created in the order they are given in the template. The template should specify the appropriate number, type, and order of controls to ensure that the user can enter the input needed to complete the command associated with the dialog box.

For each control, the template specifies style values that define the appearance and operation of the control. Every control is a child window and therefore must have the WS_CHILD style. To ensure that the control is visible when the dialog box is displayed, each control must also have the WS_VISIBLE style. Other commonly used window styles are WS_BORDER for controls that have optional borders, WS_DISABLED for controls that should be disabled when the dialog box is initially created, and WS_TABSTOP and WS_GROUP for controls that can be accessed using the keyboard. The WS_TABSTOP and WS_GROUP styles are used in conjunction with the dialog keyboard interface described later in this topic.

The template may also specify control styles specific to the control's window class. For example, a template that specifies a button control must give a button control style such as BS_PUSHBUTTON or BS_CHECKBOX. Windows passes the control styles to the control window procedure through the WM_CREATE message, allowing the procedure to adapt the appearance and operation of the control.

Windows converts the position coordinates and the width and height measurements from dialog base units to pixels, before passing these to CreateWindowEx. When Windows creates a control, it specifies the dialog box as the parent window. This means Windows always interprets the position coordinates of the control as client coordinates, relative to the upper left corner of the dialog box's client area.

The template specifies the window class for each control. A typical dialog box contains controls belonging to the predefined control window classes, such as the button and edit control window classes. In this case, the template specifies window classes by supplying the corresponding predefined atom values for the classes. When a dialog box contains a control belonging a custom control window class, the template gives the name of that registered window class or the atom value currently associated with the name.

Each control in a dialog box must have a unique identifier to distinguish it from other controls. Controls send information to the dialog box procedure through WM_COMMAND messages, so the control identifiers are essential for the procedure to determine which control sent a given message. The only exception to this rule are control identifiers for static controls. Static controls do not require unique identifiers because they send no WM_COMMAND messages.

To permit the user to close the dialog box, the template should specify at least one push button and give it the control identifier IDCANCEL. To permit the user to choose between completing or canceling the command associated with the dialog box, the template should specify two push buttons, labeled OK and Cancel, with control identifiers of IDOK and IDCANCEL, respectively.

A template also specifies optional text and creation data for a control. The text typically provides labels for button controls or specifies the initial content of a static text control. The creation data is one or more bytes of data that Windows passes to the control window procedure when creating the control. Creation data is useful for controls that require more information about their initial content or style than is given by other data. For example, an application can use creation data to set the initial setting and range for a scroll bar control.


System Menu

Windows gives a dialog box a System menu when the template specifies the WS_SYSMENU style. To prevent inappropriate command input, Windows automatically disables all commands in the menu except the Move and Close commands. The user can use the Move command to move the dialog box. When the user chooses the Close command, Windows sends a WM_COMMAND message to the dialog box procedure with the wParam parameter set to IDCANCEL. This is identical to the message sent by the Cancel button when the user chooses it. The recommended action for this message is to close the dialog box and cancel the requested command or task.

Although other menus in dialog boxes are not recommended, a dialog box template can specify a menu by supplying the identifier or the name of a menu resource. In this case, Windows loads the resource and creates the menu for the dialog box. Applications typically use menu identifiers or names in templates when using the templates to create custom windows rather than dialog boxes.


Dialog Box Fonts

Windows draws all text in dialog box using the system font by default. An application can direct Windows to use another font by setting the DS_SETFONT style for the dialog box and specifying a point size and typeface name. Although a dialog box template can specify a font, Windows always uses the system font for the title and menus of the dialog box; the DS_SETFONT style does not change this.

When the DS_SETFONT style is specified, the system sends a WM_SETFONT message to the dialog box procedure and to each control as it creates the control. The dialog box procedure is responsible for saving the font handle passed with the WM_SETFONT message and selecting the handle into the display device context whenever it writes text to the window. Predefined controls do this by default.

When the DS_SETFONT style is given, Windows uses the average character width of the font to calculate the position and dimensions of the dialog box. Otherwise, it uses the average character width of the system font.


Templates in Memory

A template in memory consists of a DLGTEMPLATE structure and related data followed by one or more DLGITEMTEMPLATE structures and related data. There is one DLGITEMTEMPLATE structure for each control in the dialog box.

The DLGTEMPLATE structure specifies the position, width, height, style, and number of controls in the dialog box. Additional data following the structure specifies the optional menu, class, title, and font for the dialog box. The DLGTEMPLATE structure has the following form:

typedef struct { // dltt

    DWORD style;

    DWORD dwExtendedStyle;

    WORD  cdit;

    WORD  x;

    WORD  y;

    WORD  cx;

    WORD  cy;

} DLGTEMPLATE;

The style member specifies the window and dialog box styles for the dialog box. Windows does not use the dwExtendedStyle member when creating a dialog box. An application that uses templates to create other types of windows can use this member to specify extended window styles for the other windows. The x and y members specify the dialog box position; cx and cy specify the width and height. The cdit member specifies the number of controls in the dialog box and is the same as the number of DLGITEMTEMPLATE structures in the template.

The DLGTEMPLATE structure is immediately followed by a 16-bit value that specifies whether the dialog box has a menu. When the value is 0x0000, the dialog box has no menu. When the value is 0xFFFF, the subsequent 16-bit value specifies the identifier of the menu resource that describes the dialog box's menu. When the initial value is neither 0x0000 nor 0xFFFF, Windows assumes it is the start of a null-terminated string specifying the name of the menu resource that describes the dialog box's menu.

The first 16-bit value following the menu identifier or name specifies the window class to which the dialog box belongs. When the value is 0x0000, Windows uses the predefined dialog box class for the dialog box. When the value is 0xFFFF, the subsequent 16-bit value is an atom value identifying a registered window class. When the initial value is neither 0x0000 nor 0xFFFF, Windows assumes it is the start of a null-terminated string identifying a registered window class.

The dialog box title immediately follows the class atom or name. The title is a null-terminated string. When the string is empty, Windows leaves the title bar for the dialog box blank. When the dialog box does not have the WS_CAPTION style, Windows sets the title to the given string but does not display it.

When the dialog box has the DS_SETFONT style, the dialog box title is immediately followed by a 16-bit value specifying the point size and by a null-terminated string specifying the typeface for the font. Windows uses this data to create a font for use when writing text in the dialog box client area and in each control. When the dialog box does not have the DS_SETFONT style, the 16-bit value and string are not part of the template.

Each DLGITEMTEMPLATE structure in the template contains data specifying the position, width, height, style, and identifier of the control. Additional information follows each structure, specifying the window class to which the control belongs, the initial text for the control, and any other creation data needed to create the control. A DLGITEMTEMPLATE structure has the following form:

typedef struct { // dlit

    DWORD style;

    DWORD dwExtendedStyle;

    WORD  x;

    WORD  y;

    WORD  cx;

    WORD  cy;

    WORD  id;

} DLGITEMTEMPLATE;

The style member specifies the control style. This member is a combination of window-style flags, such as BS_PUSHBUTTON and WS_VISIBLE. Windows does not use the dwExtendedStyle member to create controls for dialog boxes. Applications that use templates to create other types of windows can use this member to specify extended window styles for those controls. The x and y members specify the coordinates of the upper left corner of the control; cx and cy specify the width and height of the control. The id member is the control identifier.

The control's window class is specified by an atom or name immediately following the DLGITEMTEMPLATE structure. When the first 16-bit value after the structure is 0xFFFF, the subsequent 16-bit value is an atom value identifying a registered window class. Otherwise, the first value is the start of a null-terminated string specifying the name of a registered window class.

The control text starts on the first 16-bit boundary after the class atom or name. This text is either two 16-bit values specifying a resource identifier or a null- terminated string specifying the initial text for the control. If this member is a resource identifier, the first 16-bit value is 0xFFFF and the second is the identifier. Resource identifiers are usually given for controls, such as static icon controls, that load and display icons or other resources rather than displaying text.

Any additional creation data required by the control follows the control text. Windows passes this data to the control as the creation parameters when it calls the CreateWindowEx function.


Dialog Box Procedure

A dialog box procedure is similar to a window procedure in that Windows sends messages to the procedure when it has information to give or tasks to carry out. Unlike a window procedure, a dialog box procedure never calls the DefWindowProc function. Instead, it returns the Boolean value TRUE if it processes a message or FALSE if it does not.

Every dialog box procedure has the following form:

BOOL APIENTRY DlgProc(hwndDlg, message, wParam, lParam)

HWND hwndDlg;

UINT message;

WPARAM wParam;

LPARAM lParam;

{

    switch (message) {

        // Place message cases here.

        default:

            return FALSE;

    }

}

The procedure parameters serve the same purpose as in a window procedure, with the hwndDlg parameter receiving the window handle of the dialog box.

Most dialog box procedures process the WM_INITDIALOG message and the WM_COMMAND messages sent by the controls, but process few if any other messages. If a dialog box procedure does not process a message, it must return FALSE to direct Windows to process the messages internally. The only exception to this rule is the WM_INITDIALOG message. The dialog box procedure must return TRUE to direct Windows to further process the WM_INITDIALOG message. In any case, the procedure must not call DefWindowProc.


The WM_INITDIALOG Message

Windows does not send a WM_CREATE message to the dialog box procedure. Instead, it sends a WM_INITDIALOG message when it creates the dialog box and all its controls but before it displays the dialog box. The procedure should carry out any initialization required to ensure that the dialog box displays the current settings associated with the command or task. For example, when a dialog box contains a control to show the current drive and directory, the procedure must determine the current drive and directory and set the control to that value.

The procedure can initialize controls by using functions such as SetDlgItemText and CheckDlgButton. Because controls are windows, the procedure can also manipulate them by using window-management functions such as EnableWindow and SetFocus. The procedure can retrieve the window handle for a control by using the GetDlgItem function.

The dialog box procedure can change the contents, state, and position of any control as needed. For example, in a dialog box that contains a list box of filenames and an Open button, the procedure can disable the Open button until the user selects a file from the list. In this example, the dialog box template specifies the WS_DISABLED style for the Open button and Windows automatically disables the button when creating it. When the dialog box procedure receives a notification message from the list box indicating that the user has selected a file, the procedure calls the EnableWindow function to enable the Open button.

If the application creates the dialog box by using one of the functions DialogBoxParam, DialogBoxIndirectParam, CreateDialogParam, or CreateDialogIndirectParam, the lParam parameter for the WM_INITDIALOG message contains the extra parameter passed to the function. Applications typically use this extra parameter to pass the address of additional initialization information to the dialog box procedure, but the dialog box procedure must determine the meaning of the parameter. If the application uses another function to create the dialog box, Windows sets the lParam parameter to NULL.

Before returning from the WM_INITDIALOG message, the procedure should determine whether it should set the input focus to a given control. If the dialog box procedure returns TRUE, Windows automatically sets the input focus to the control whose window handle is in the wParam parameter. If the control receiving the default focus is not appropriate, it can set the focus to the appropriate control by using the SetFocus function. If the procedure sets the input focus, it must return FALSE to prevent Windows from setting the default focus. The control receiving the default input focus is always the first control given in the template that is visible, not disabled, and has the WS_TABSTOP style. If no such control exists, Windows sets the default input focus to the first control in the template.


The WM_COMMAND Message

A control can send a WM_COMMAND message to the dialog box procedure when the user carries out an action in the control. These messages, called notification messages, inform the procedure of user input and permit it to carry out appropriate responses.

All predefined controls, except static controls, send notification messages for selected user actions. For example, a push button sends the BN_CLICKED notification message whenever the user chooses the button. In all cases, the low-order word of the wParam parameter contains the control identifier, the high-order word of wParam contains the notification code, and the lParam parameter contains the control window handle.

The dialog box procedure should monitor and process notification messages. In particular, the procedure must process messages having the IDOK or IDCANCEL identifiers; these messages represent a request by the user to close the dialog box. The procedure should close the dialog box by using the EndDialog function for modal dialog boxes and the DestroyWindow function for modeless dialog boxes.

Windows also sends WM_COMMAND messages to the dialog box procedure if the dialog box has a menu, such as the System menu, and the user chooses a command. In particular, Windows sends a WM_COMMAND message with the wParam parameter set to IDCANCEL whenever the user chooses the Close command in the dialog box's System menu. The message is nearly identical to the notification message sent by the Cancel button and should be processed in exactly the same way.


The WM_PARENTNOTIFY Message

A control sends a WM_PARENTNOTIFY message whenever the user presses a mouse button while pointing to the control. Some applications interpret this message as a signal to carry out an action related to the control, such as displaying a line of text describing the purpose of the control.

Windows also sends WM_PARENTNOTIFY messages when it creates and destroys a window, but not for controls created from a dialog box template. Windows prevents these messages by specifying the WS_EX_NOPARENTNOTIFY style when creating the controls. An application cannot override this default behavior unless it creates its own controls for the dialog box.


Control-Color Messages

Controls and Windows can send control-color messages when they want the dialog box procedure to paint the background of a control or other window by using a specific brush and colors. This can be useful when applications override the default colors used in dialog boxes and their controls. Following are the control-color messages, which have replaced the WM_CTLCOLOR message.

WM_CTLCOLORBTN
WM_CTLCOLORDLG
WM_CTLCOLOREDIT
WM_CTLCOLORLISTBOX
WM_CTLCOLORSCROLLBAR
WM_CTLCOLORSTATIC

A control sends a control-color message to the dialog box procedure just before it paints its own background. The message allows the procedure to specify which brush to use and to set the background and foreground colors. The procedure specifies a brush by returning the brush handle. To set the background and foreground colors, the procedure uses the SetBkColor and SetTextColor functions with the control's display device context. The control-color message passes a handle of the display device context to the procedure in the message's wParam parameter.

Windows sends a WM_CTLCOLORDLG message to the dialog box procedure if the procedure does not process the WM_ERASEBKGND message. The predefined dialog box class does not have a class background brush, so this message lets the procedure define its own background without having to include the code to carry out the work.

In any case, when a dialog box procedure does not process a control-color message, Windows uses a brush with the default window color to paint the background for all controls and windows except scroll bars. An application can retrieve the default window color by passing the COLOR_WINDOW value to the GetSysColor function. While the background is painted, the foreground color for the display device context is set to the default text color (COLOR_WINDOWTEXT). For scroll bars, Windows uses a brush having the default scroll bar color (COLOR_SCROLLBAR). In this case, the background and foreground colors for the display device context are set to white and black, respectively.


Dialog Box Default Message Processing

The window procedure for the predefined dialog box class carries out default processing for all messages that the dialog box procedure does not process. When the dialog box procedure returns FALSE for any message, the predefined window procedure checks the messages and carries out the following default actions:

Message	Default action
DM_GETDEFID	Returns the control identifier of the default push button if it exists. Otherwise, returns zero.
DM_SETDEFID	Sets the control specified by the control identifier in the wParam parameter to the default push button.
WM_ACTIVATE	Restores the input focus to the control identified by the previously saved handle if the dialog box is activated. Otherwise, the procedure saves the handle of the control having the input focus.
WM_CHARTOITEM	Returns zero.
WM_CLOSE	Posts the BN_CLICKED notification message to the dialog box, specifying IDCANCEL as the control identifier. If the dialog box has an IDCANCEL control identifier and the control is currently disabled, the procedure sounds a warning and does not post the message.
WM_COMPAREITEM	Returns zero.
WM_ERASEBKGND	Fills the dialog box client area by using either the brush returned from the WM_CTLCOLORDLG message or with the default window color.
WM_GETFONT	Returns the handle of the application-defined dialog box font.
WM_INITDIALOG	Returns zero.
WM_LBUTTONDOWN	Sends a CB_SHOWDROPDOWN message to the combo box having the input focus, directing the control to hide its drop-down list box. The procedure calls DefWindowProc to complete the default action.
WM_NCDESTROY	Releases global memory allocated for edit controls in the dialog box (applies to dialog boxes in Windows-based applications that specify the DS_LOCALEDIT style) and frees any application-defined font (applies to dialog boxes that specify the DS_SETFONT style). The procedure calls the DefWindowProc function to complete the default action.
WM_NCLBUTTONDOWN	Sends a CB_SHOWDROPDOWN message to the combo box having the input focus, directing the control to hide its drop-down list box. The procedure calls DefWindowProc to complete the default action.
WM_NEXTDLGCTL	Sets the input focus to the next or previous control in the dialog box, to the control identified by the handle in the wParam parameter, or to the first control in the dialog box that is visible, not disabled, and has the WS_TABSTOP style. The procedure ignores this message if the current window with the input focus is not a control.
WM_SETFOCUS	Sets the input focus to the control identified by a previously saved control window handle. If no such handle exists, the procedure sets the input focus to the first control in the dialog box template that is visible, not disabled, and has the WS_TABSTOP style. If no such control exists, the procedure sets the input focus to the first control in the template.
WM_SHOWWINDOW	Saves the handle of the control having the input focus if the dialog box is being hidden, then calls DefWindowProc to complete the default action.
WM_SYSCOMMAND	Saves the handle of the control having the input focus if the dialog box is being minimized, then calls DefWindowProc to complete the default action.
WM_VKEYTOITEM	Returns zero.
The predefined window procedure passes all other messages to DefWindowProc for default processing.


Dialog Box Keyboard Interface

Windows provides a special keyboard interface for dialog boxes that carries out special processing for several keys. The interface generates messages that correspond to certain buttons in the dialog box or changes the input focus from one control to another. Following are the keys used in this interface and their respective actions.

Key	Action
ALT+mnemonic	Moves the input focus to the first control (having the WS_TABSTOP style) after the static control containing the given mnemonic.
DOWN	Moves the input focus to the next control in the group.
ENTER	Sends a WM_COMMAND message to the dialog box procedure. The wParam parameter is set to IDOK or control identifier of the default push button.
ESC	Sends a WM_COMMAND message to the dialog box procedure. The wParam parameter is set to IDCANCEL.
LEFT	Moves the input focus to the previous control in the group.
mnemonic	Moves the input focus to the first control (having the WS_TABSTOP style) after the static control containing the given mnemonic.
RIGHT	Moves the input focus to the next control in the group.
SHIFT+TAB	Moves the input focus to the previous control that has the WS_TABSTOP style.
TAB	Moves the input focus to the next control that has the WS_TABSTOP style.
UP	Moves the input focus to the previous control in the group.
The Win32 API automatically provides the keyboard interface for all modal dialog boxes. It does not provide the interface for modeless dialog boxes unless the application calls the IsDialogMessage function to filter messages in its main message loop. This means that the application must pass the message to IsDialogMessage immediately after retrieving the message from the message queue. The function processes the messages if it is for the dialog box and returns a nonzero value to indicate that the message has been processed and must not be passed to the TranslateMessage or DispatchMessage function.

Because the dialog box keyboard interface uses direction keys to move between controls in a dialog box, an application cannot use these keys to scroll the contents of any modal dialog box or any modeless dialog box for which IsDialogMessage is called. When a dialog box has scroll bars, the application must provide an alternate keyboard interface for the scroll bars. Note that the mouse interface for scrolling is available when the system includes a mouse.


The WS_TABSTOP Style

The TAB key and SHIFT+TAB keys have no effect when the controls in the dialog box do not have the WS_TABSTOP style. Windows looks for this style as it searches for the next control in the dialog box to receive the input focus.

When the user presses TAB or SHIFT+TAB, Windows first determines whether the control having the input focus processes these keys. It sends the control a WM_GETDLGCODE message, and if the control returns DLGC_WANTTAB, Windows passes the keys to the control. Otherwise, Windows uses the GetNextDlgTabItem function to locate the next control that is visible, not disabled, and that has the WS_TABSTOP style. The search starts with the control currently having the input focus and proceeds in the order in which the controls were created — that is, the order in which they are defined in the dialog box template. When the system locates a control having the required characteristics, Windows moves the input focus to it.

An application can also use GetNextDlgTabItem to locate controls having the WS_TABSTOP style. The function retrieves the window handle of the next or previous control having the WS_TABSTOP style without moving the input focus.


The WS_GROUP Style

By default, Windows moves the input focus to the next or previous control whenever the user presses a direction key. As long as the current control with the input focus does not process these keys and the next or previous control is not a static control, Windows continues to move the input focus through all controls in the dialog box as the user continues to press the direction keys.

An application can use the WS_GROUP style to modify this default behavior. The style marks the beginning of a group of controls. If a control in the group has the input focus when the user begins pressing direction keys, the focus remains in the group. In general, the first control in a group must have the WS_GROUP style and all other controls in the group must not have this style. All controls in the group must be contiguous — that is, they must have been created consecutively with no intervening controls.

When the user presses a direction key, Windows first determines whether the current control having the input focus processes the direction keys. Windows sends a WM_GETDLGCODE message to the control and if the control returns the DLGC_WANTARROWS value, passes the key to the control. Otherwise, Windows uses the GetNextDlgGroupItem function to determine the next control in the group.

GetNextDlgGroupItem searches controls in the order (or reverse order) they were created. If the user presses the RIGHT or DOWN key, GetNextDlgGroupItem returns the next control if that control does not have WS_GROUP style. Otherwise, the function reverses the order of the search and returns the first control that has the WS_GROUP style. If the user presses the LEFT or UP key, the function returns the previous control unless the current control already has the WS_GROUP style. If the current control has this style, the function reverses the order of the search, locates the first control having the WS_GROUP style, and returns the control that immediately precedes the located control.

Once Windows has the next or previous control, it sends a WM_GETDLGCODE message to the control to determine the control type. Windows then moves the input focus to control if it is not a static control. If the control is an automatic radio button, Windows sends a BM_CLICK message to it. An application can also use GetNextDlgGroupItem to locate controls in a group.

Generally, the first control in the group combines the WS_GROUP and WS_TABSTOP styles so that the user can move from group to group by using the TAB key. If the group contains radio buttons, the application should apply the WS_TABSTOP style only to the first control in the group. Windows automatically moves the style when the user moves between controls in the group. This ensures that the input focus will always be on the most recently selected control when the user moves to the group using the TAB key.


Mnemonics

A mnemonic is a selected letter or digit in the label of a button or in the text of a static control. Windows moves the input focus to the control associated with the mnemonic whenever the user either presses the key that corresponds to the mnemonic or presses this key and the ALT key in combination. Mnemonics provide a quick way for the user to move to a given control by using the keyboard.

An application creates a mnemonic for a control by inserting the ampersand (&) immediately before the selected letter or digit in the label or text for the control. In most cases, the null-terminated string provided with the control in the dialog box template contains the ampersand. However, an application can create a mnemonic at any time by replacing a control's existing label or text by using the SetDlgItemText function. Only one mnemonic can be given for each control. Although it is recommended, mnemonics in a dialog box need not be unique.

When the user presses a letter or digit key, Windows first determines whether the current control having the input focus processes the key. Windows sends a WM_GETDLGCODE message to the control, and if the control returns the DLGC_WANTALLKEYS or DLG_WANTMESSAGE value, Windows passes the key to the control. Otherwise, it searches for a control whose mnemonic matches the given letter or digit. It continues to search until it locates a control or has examined all controls. During the search, it skips any static controls that have the SS_NOPREFIX style.

If Windows locates a static control and the control is not disabled, Windows moves the input focus to the first control after the static control that is visible, not disabled, and that has the WS_TABSTOP style. If Windows locates some other control that has a matching mnemonic, it moves the input focus to that control. If the control is a default push button, Windows sends a BN_CLICKED notification message to the dialog box procedure. If the control is another style of button and there is no other control in the dialog box having the same mnemonic, Windows sends the BM_CLICK message to the control.


Dialog Box Settings

The dialog box settings are the current selections and values for the controls in the dialog box. The dialog box procedure is responsible for initializing the controls to these settings when creating the dialog box. It is also responsible for retrieving the current settings from the controls before destroying the dialog box. The methods used to initialize and retrieve settings depend on the type of control.


Radio Buttons and Check Boxes

Dialog boxes use radio buttons and check boxes to let the user choose from a list of options. Radio buttons let the user choose from mutually exclusive options; check boxes let the user pick a combination of options.

The dialog box procedure can set the initial state of a check box by using the CheckDlgButton function, which sets or clears the check box. For radio buttons in a group of mutually exclusive radio buttons, the dialog box procedure can use the CheckRadioButton function to set the appropriate radio button and automatically clear any other radio button.

Before a dialog box terminates, the dialog box procedure can check the state of each radio button and check box by using the IsDlgButtonChecked function, which returns the current state of the button. A dialog box typically saves this information to initialize the buttons the next time it creates the dialog box.


Dialog Box Edit Controls

Many dialog boxes have edit controls that let the user supply text as input. Most dialog box procedures initialize an edit control when the dialog box first starts. For example, the dialog box procedure may place a proposed filename in the control that the user can then select, modify, or replace. The dialog box procedure can set the text in an edit control by using the SetDlgItemText function, which copies text from a given buffer to the edit control. When the edit control receives the input focus, it automatically selects the complete text for editing.

Because edit controls do not automatically return their text to the dialog box, the dialog box procedure must retrieve the text before it terminates. It can retrieve the text by using the GetDlgItemText function, which copies the edit control text to a buffer. The dialog box procedure typically saves this text to initialize the edit control later or passes it on to the parent window for processing.

Some dialog boxes use edit controls that let the user enter numbers. The dialog box procedure can retrieve a number from an edit control by using the GetDlgItemInt function, which retrieves the text from the edit control and converts the text to a decimal value. The user types the number in decimal digits. It can be either signed or unsigned. The dialog box procedure can display an integer by using the SetDlgItemInt function. SetDlgItemInt converts a signed or unsigned integer to a string of decimal digits.


List Boxes, Combo Boxes, and Directory Listings

Some dialog boxes display lists of names from which the user can select one or more names. To display a list of filenames, for example, a dialog box typically uses a list box and the DlgDirList and DlgDirSelect functions. The DlgDirList function automatically fills a list box with the filenames in the current directory. The DlgDirSelect function retrieves the selected filename from the list box. Together, these two functions provide a convenient way for a dialog box to display a directory listing so the user can select a file without having to type its name and location.

A dialog box can also use a combo box to display a list of filenames. The DlgDirListComboBox function automatically fills a list box portion of the combo box with the filenames in the current directory. The DlgDirSelectComboBox function retrieves a selected filename from the list box portion.


Dialog Box Control Messages

Many controls recognize predefined messages that, when received by controls, cause them to carry out some action. For example, the BM_SETCHECK message sets the check in a check box and the EM_GETSEL message retrieves the portion of the control's text that is currently selected. The control messages give a dialog procedure greater and more flexible access to the controls than the standard functions, so they are often used when the dialog box requires complex interactions with the user.

A dialog box procedure can send a message to a control by supplying the control identifier and using the SendDlgItemMessage function, which is identical to the SendMessage function, except that it uses a control identifier instead of a window handle to identify the control that is to receive the message. A given message may require that the dialog procedure send parameters with the message, and the message may have corresponding return values. The operation and requirements of each control message depends on the purpose of the message and the control that processes it.

For more information about the control messages, see Controls.


Custom Dialog Boxes

An application can create custom dialog boxes by using an application-defined window class for the dialog boxes instead of using the predefined dialog box class. Applications typically use this method when a dialog box is their main window, but it is also useful for creating modal and modeless dialog boxes for applications that have standard overlapping windows.

The application-defined window class allows the application to define a window procedure for the dialog box and process messages before sending them to the dialog box procedure. It also lets the application define a class icon, a class background brush, and a class menu for the dialog box. The application must register the window class before attempting to create a dialog box and must provide the dialog box template with the atom value or name of the window class.

Many applications create a new dialog box class by first retrieving the class information for the predefined dialog box class, and passing it to the GetClassInfo function, which fills a WNDCLASS structure with the information. The application modifies individual members of the structure, such as the class name, brush, and icon, then registers the new class by using the RegisterClass function. If an application fills the WNDCLASS structure on its own, it must set the cbWndExtra member to the DLGWINDOWEXTRA, which is the number of extra bytes Windows requires for each dialog box. If an application also uses extra bytes for each dialog box, they must be beyond the extra bytes required by Windows.

The window procedure for the custom dialog box has the same parameters and requirements as any other window procedure. Unlike other window procedures, however, the window procedure for this dialog box should call the DefDlgProc function instead of the DefWindowProc function for any messages it does not process. DefDlgProc carries out the same default message processing as the window procedure for the predefined dialog box, which includes calling the dialog box procedure.

An application can also create custom dialog boxes by subclassing the window procedure of the predefined dialog box. The SetWindowLong function lets an application set the address of the window procedure for a given window. The application may also attempt to subclass by using the SetClassLong function, but doing so affects all dialog boxes in the system, not just those belonging to the application.

Applications that create custom dialog boxes sometimes provide an alternate keyboard interface for the dialog boxes. For modeless dialog boxes, this may mean the application does not call the IsDialogMessage function and instead processes all keyboard input in the custom window procedure. In such cases, the application can use the WM_NEXTDLGCTL message to minimize the code needed to move the input focus from one control to another. This message, when passed to DefDlgProc, moves the input focus to a specified control and updates the appearance of the controls, such as moving the default push button border or setting an automatic radio button.


Using Dialog Boxes

You use dialog boxes to display information and prompt for input from the user. Your application loads and initializes the dialog box, processes user input, and destroys the dialog box when the user finishes the task. The process for handling dialog boxes varies, depending on whether the dialog box is modal or modeless. A modal dialog box requires the user to close the dialog box before activating another window in the application. However, the user can activate windows in different applications. A modeless dialog box does not require an immediate response from the user. It is similar to a main window containing controls. The following sections discuss how to use both types of dialog boxes.

•	Displaying a message box

•	Creating a modal dialog box

•	Creating a modeless dialog box

•	Initializing a dialog box

•	Creating a template in memory


Displaying a Message Box

The simplest form of modal dialog box is the message box. Most applications use message boxes to warn the user of errors and to prompt for directions on how to proceed after an error has occurred. You create a message box by using the MessageBox or MessageBoxEx function, specifying the message and the number and type of buttons to display. Windows creates a modal dialog box, providing its own dialog box template and procedure. After the user closes the message box, MessageBox or MessageBoxEx returns a value identifying the button chosen by the user to close the message box.

In the following example, the application displays a message box if the fError variable is TRUE. The message box displays the message describing the error. The MB_OKCANCEL style directs MessageBox to provide two buttons with which the user can choose how to proceed:

if (fError) {

    if (MessageBox(hwndDlg, SZNOTFOUND, SZDELETEITEM,

        MB_OKCANCEL)==IDOK)

        .

        . // Prompt for a new item name and repeat the command.

        .

    else

        .

        . // Cancel the command.

        .

}

In this example, SZNOTFOUND and SZDELETEITEM are application-defined, null-terminated strings that represent the message text and the title for the message box.


Creating a Modal Dialog Box

You create a modal dialog box by using the DialogBox function. You must specify the identifier or name of a dialog box template resource and the address of the dialog box procedure. The DialogBox function loads the template, displays the dialog box, and processes all user input until the user closes the dialog box.

In the following example, the application displays a modal dialog box when the user chooses a Delete Item command from an application menu. The dialog box contains an edit control (in which the user enters the name of an item) and OK and Cancel buttons. The control identifiers for these controls are ID_ITEMNAME, IDOK, and IDCANCEL, respectively.

The first part of the example consists of the statements that create the modal dialog box. These statements, in the window procedure for the application's main window, create the dialog box when the system receives a WM_COMMAND message having the IDM_DELETEITEM command identifier. The second part of the example is the dialog box procedure, which retrieves the contents of the edit control and closes the dialog box upon receiving a WM_COMMAND message.

The following statements create the modal dialog box. The dialog box template is a resource in the application's executable file and has the resource identifier DLG_DELETEITEM:

        case WM_COMMAND:

            switch (LOWORD(wParam)) {

                case IDM_DELETEITEM:

                    if (DialogBox(hinst,

                         MAKEINTRESOURCE(DLG_DELETEITEM),

                         hwnd, (DLGPROC)DeleteItemProc)==IDOK)

                        .

                        . // Complete the command; szItemName

                        . // contains the name of the item to

                        . // delete.

                        .

                     else

                        .

                        . // Cancel the command.

                        .

                break;

            }

            return 0L;

In this example, the application identifies its main window as the owner window for the dialog box. When Windows initially displays the dialog box, its position is relative to the upper left corner of the owner window's client area. The application uses the return value from DialogBox to determine whether to proceed with the command or cancel it. The following statements define the dialog box procedure.

char szItemName[80]; // receives name of item to delete.

BOOL CALLBACK DeleteItemProc(hwndDlg, message, wParam, lParam)

HWND hwndDlg;

UINT message;

WPARAM wParam;

LPARAM lParam;

{

    switch (message) {

        case WM_COMMAND:

            switch (LOWORD(wParam)) {

                case IDOK:

                    if (!GetDlgItemText(hwndDlg, ID_ITEMNAME,

                             szItemName, 80))

                         *szItemName=0;

                    // Fall through.

                case IDCANCEL:

                    EndDialog(hwndDlg, wParam);

                    return TRUE;

            }

    }

    return FALSE;

}

In this example, the procedure uses GetDlgItemText to retrieve the current text from the edit control identified by ID_ITEMNAME. The procedure then calls the EndDialog function to set the dialog box's return value to either IDOK or IDCANCEL, depending on the message received, and to begin the process of closing the dialog box. The IDOK and IDCANCEL identifiers correspond to the OK and Cancel buttons. After the procedure calls EndDialog, Windows sends additional messages to the procedure to destroy the dialog box and returns the dialog box's return value back to the function that created the dialog box.


Creating a Modeless Dialog Box

You create a modeless dialog box by using the CreateDialog function, specifying the identifier or name of a dialog box template resource and the address of the dialog box procedure. CreateDialog loads the template, creates the dialog box, and optionally displays it. Your application is responsible for retrieving and dispatching user input messages to the dialog box procedure.

In the following example, the application displays a modeless dialog box — if it is not already displayed — when the user chooses a Go To command from an application menu. The dialog box contains an edit control, a check box, and OK and Cancel buttons. The dialog box template is a resource in the application's executable file and has the resource identifier DLG_GOTO. The user enters a line number in the edit control and checks the check box to specify that the line number is relative to the current line. The control identifiers are ID_LINE, ID_ABSREL, IDOK, and IDCANCEL.

The statements in the first part of the example create the modeless dialog box. These statements, in the window procedure for the application's main window, create the dialog box when the window procedure receives a WM_COMMAND message having the IDM_GOTO command identifier, but only if the global variable hwndGoto does not already contain a valid handle. The second part of the example is the application's main message loop. The loop includes the IsDialogMessage function to ensure that the user can use the dialog box keyboard interface in this modeless dialog box. The third part of the example is the dialog box procedure. The procedure retrieves the contents of the edit control and check box when the user chooses the OK button. The procedure destroys the dialog box when the user chooses the Cancel button.

HWND hwndGoto = NULL;  // window handle of dialog box

    .

    .

    .

    case WM_COMMAND:

        switch (LOWORD(wParam)) {

            case IDM_GOTO:

                if (!IsWindow(hwndGoto)) {

                    hwndGoto = CreateDialog(hinst,

                         MAKEINTRESOURCE(DLG_GOTO),

                         hwnd, (DLGPROC) GoToProc);

                    ShowWindow(hwndGoto, SW_SHOW);

                }

                break;

        }

        return 0L;

In the preceding statements, CreateDialog is called only if hwndGoto does not contain a valid window handle. This ensures that the application does not display two dialog boxes at the same time. To support this method of checking, the dialog procedure must set hwndGoto to NULL when it destroys the dialog box.

The message loop for an application consists of the following statements:

while (GetMessage(&msg, NULL, NULL, NULL)) {

    if (!IsWindow(hwndGoto) || !IsDialogMessage(hwndGoto, &msg)) {

        TranslateMessage(&msg);

        DispatchMessage(&msg);

    }

}

The loop checks the validity of the window handle for the dialog box and only calls the IsDialogMessage function if the handle is valid. IsDialogMessage only processes the message if it belongs to the dialog box. Otherwise, it returns FALSE and the loop dispatches the message to the appropriate window.

The following statements define the dialog box procedure:

int iLine;             // receives line number

BOOL fRelative;        // receives check box status

    .

    .

    .

BOOL CALLBACK GoToProc(hwndDlg, message, wParam, lParam)

HWND hwndDlg;

UINT message;

WPARAM wParam;

LPARAM lParam;

{

    BOOL fError;

    switch (message) {

        case WM_INITDIALOG:

            CheckDlgButton(hwndDlg, ID_ABSREL, fRelative);

            return TRUE;

        case WM_COMMAND:

            switch (LOWORD(wParam)) {

                case IDOK:

                    fRelative = IsDlgButtonChecked(hwndDlg,

                        ID_ABSREL);

                    iLine = GetDlgItemInt(hwndDlg, ID_LINE,

                        &fError, fRelative);

                    if (fError) {

                        MessageBox(hwndDlg, SZINVALIDNUMBER,

                            SZGOTOERR, MB_OK);

                        SendDlgItemMessage(hwndDlg, ID_LINE,

                            EM_SETSEL, 0, -1L);

                    } else

                        .

                        . // Notify the owner window to carry

                        . // out the command.

                        .

                    return TRUE;

                case IDCANCEL:

                    DestroyWindow(hwndDlg);

                    hwndGoto = NULL;

                    return TRUE;

            }

    }

    return FALSE;

}

In the preceding statements, the procedure processes the WM_INITDIALOG and WM_COMMAND messages. During WM_INITDIALOG processing, the procedure initializes the check box by passing the current value of the global variable fRelative to CheckDlgButton. The procedure then returns TRUE to direct Windows to set the default input focus.

During WM_COMMAND processing, the procedure closes the dialog box only if the user chooses the Cancel button — that is, the button having the IDCANCEL identifier. The procedure must call DestroyWindow to close a modeless dialog box. Notice that the procedure also sets the hwndGoto variable to NULL to ensure that other statements that depend on this variable operate correctly.

If the user chooses the OK button, the procedure retrieves the current state of the check box and assigns it to the fRelative variable. It then uses the variable to retrieve the line number from the edit control. GetDlgItemInt translates the text in the edit control into an integer. The value of fRelative determines whether the function interprets the number as a signed or unsigned value. If the edit control text is not a valid number, GetDlgItemInt sets the value of the fError variable to nonzero. The procedure checks this value to determine whether to display an error message or carry out the command. In the event of an error, the dialog box procedure sends a message to the edit control, directing it to select the text in the control so that the user can easily replace it. If GetDlgItemInt does not return an error, the procedure can either carry out the requested command itself or send a message to the owner window, directing it to carry out the command.


Initializing a Dialog Box

You initialize the dialog box and its contents while processing the WM_INITDIALOG message. The most common task is to initialize the controls to reflect the current dialog box settings. Another common task is to center a dialog box on the screen or within its owner window. A useful task for some dialog boxes is to set the input focus to a given control rather than accept the default input focus.

In the following example, the dialog box procedure centers the dialog box and sets the input focus while processing the WM_INITDIALOG message. To center the dialog box, the procedure retrieves the window rectangles for the dialog box and the owner window and calculates a new position for the dialog box. To set the input focus, the procedure checks the wParam parameter to determine the identifier of the default input focus:

HWND hwndOwner;

RECT rc, rcDlg, rcOwner;

    case WM_INITDIALOG:

        // Get the owner window and dialog box rectangles.

        if ((hwndOwner = GetParent(hwndDlg)) == NULL)

            hwndOwner = GetDesktopWindow();

        GetWindowRect(hwndOwner, &rcOwner);

        GetWindowRect(hwndDlg, &rcDlg);

        CopyRect(&rc, &rcOwner);

         // Offset the owner and dialog box rectangles so that

         // right and bottom values represent the width and

         // height, and then offset the owner again to discard

         // space taken up by the dialog box.

        OffsetRect(&rcDlg, -rcDlg.left, -rcDlg.top);

        OffsetRect(&rc, -rc.left, -rc.top);

        OffsetRect(&rc, -rcDlg.right, -rcDlg.bottom);

         // The new position is the sum of half the remaining

         // space and the owner's original position.

        SetWindowPos(hwndDlg,

            HWND_TOP,

            rcOwner.left + (rc.right / 2),

            rcOwner.top + (rc.bottom / 2),

            0, 0,          // ignores size arguments

            SWP_NOSIZE);

        if (GetDlgCtrlID((HWND) wParam) != ID_ITEMNAME) {

            SetFocus(GetDlgItem(hwndDlg, ID_ITEMNAME));

            return FALSE;

        }

        return TRUE;

In the preceding statements, the procedure uses the GetParent function to retrieve the owner window handle for a dialog box. The function returns the owner window handle for dialog boxes, and the parent window handle for child windows. Because an application can create a dialog box that has no owner, the procedure checks the returned handle and uses the GetDesktopWindow function to retrieve the desktop window handle, if necessary. After calculating the new position, the procedure uses the SetWindowPos function to move the dialog box, specifying the HWND_TOP value to ensure that the dialog box remains on top of the owner window.

Before setting the input focus, the procedure checks the control identifier of the default input focus. Windows passes the window handle of the default input focus in the wParam parameter. The GetDlgCtrlID function returns the identifier for the control identified by the window handle. If the identifier does not match the correct identifier, the procedure uses the SetFocus function to set the input focus. The GetDlgItem function is required to retrieve the window handle of the desired control.


Creating a Template in Memory

Applications sometimes adapt or modify the content of dialog boxes depending on the current state of the data being processed. In such cases, it is not practical to provide all possible dialog box templates as resources in the application's executable file. But creating templates in memory gives the application more flexibility to adapt to any circumstances.

In the following example, the application creates a template in memory for a modal dialog box that contains a message and OK and Help buttons:

LRESULT DisplayMyMessage(HINSTANCE hinst, HWND hwndOwner,

    LPSTR lpszMessage)

{

    HGLOBAL hgbl;

    LPDLGTEMPLATE lpdt;

    LPDLGITEMTEMPLATE lpdit;

    LPWORD lpw;

    LPWSTR lpwsz;

    LRESULT ret;

    hgbl = GlobalAlloc(GMEM_ZEROINIT, 1024);

    if (!hgbl)

        return -1;

    lpdt = (LPDLGTEMPLATE)GlobalLock(hgbl);

    // Define a dialog box.

    lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU

        | DS_MODALFRAME | WS_CAPTION;

    lpdt->cdit = 3;  // number of controls

    lpdt->cdit = 1;

    lpdt->x  = 10;  lpdt->y  = 10;

    lpdt->cx = 100; lpdt->cy = 100;

    lpw = (LPWORD) (lpdt + 1);

    *lpw++ = 0;   // no menu

    *lpw++ = 0;   // predefined dialog box class (by default)

    lpwsz = (LPWSTR) lpw;

    lstrcpyW(lpwsz, L"My Message");  // dialog title (Unicode)

    lpw = (LPWORD) (lpwsz + lstrlenW(lpwsz) + 1);

    // Define an OK button.

    lpdit = (LPDLGITEMTEMPLATE) lpw;

    lpdit->x  = 10; lpdit->y  = 10;

    lpdit->cx = 40; lpdit->cy = 20;

    lpdit->id = IDOK;  // OK button identifier

    lpdit->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON;

    lpw = (LPWORD) (lpdit + 1);

    *lpw++ = 0xFFFF;

    *lpw++ = 0x0080;    // button class

    lpwsz = (LPWSTR) lpw;

    lstrcpyW(lpwsz, L"OK");  // button label (Unicode)

    lpw = (LPWORD) (lpwsz + lstrlenW(lpwsz) + 1);

    *lpw++ = 0;              // no creation data

    // Define a Help button.

    lpdit = (LPDLGITEMTEMPLATE) lpw;

    lpdit->x  = 55; lpdit->y  = 10;

    lpdit->cx = 40; lpdit->cy = 20;

    lpdit->id = ID_HELP;    // Help button identifier

    lpdit->style = WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON;

    lpw = (LPWORD) (lpdit + 1);

    *lpw++ = 0xFFFF;

    *lpw++ = 0x0080;                 // button class atom

    lpwsz = (LPWSTR) lpw;

    lstrcpyW(lpwsz, L"Help");        // button label (Unicode)

    lpw = (LPWORD) (lpwsz + lstrlenW(lpwsz) + 1);

    *lpw++ = 0;                      // no creation data

    // Define a static text control.

    lpdit = (LPDLGITEMTEMPLATE) lpw;

    lpdit->x  = 55; lpdit->y  = 10;

    lpdit->cx = 40; lpdit->cy = 20;

    lpdit->id = ID_TEXT;  // text identifier

    lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;

    lpw = (LPWORD) (lpdit + 1);

    *lpw++ = 0xFFFF;

    *lpw++ = 0x0082;                         // static class

    for (lpwsz = (LPWSTR) lpw;

         *lpwsz++ = (WCHAR) *lpszMessage++;  // message

         );

    lpw = (LPWORD) lpwsz;

    *lpw++ = 0;                              // no creation data

    GlobalUnlock(hgbl);

    ret = DialogBoxIndirect(hinst, (LPDLGTEMPLATE) hgbl,

        hwndOwner, (DLGPROC) DialogProc);

    GlobalFree(hgbl);

    return ret;

}


Dialog Box Reference

The following functions, structures, and messages are associated with dialog boxes.


Dialog Box Functions

Following are the functions used to create and manage dialog boxes and controls within dialog boxes.

CreateDialog
CreateDialogIndirect
CreateDialogIndirectParam
CreateDialogParam
DefDlgProc
DialogBox
DialogBoxIndirect
DialogBoxIndirectParam
DialogBoxParam
DialogProc
EndDialog
GetDialogBaseUnits
GetDlgCtrlID
GetDlgItem
GetDlgItemInt
GetDlgItemText
GetNextDlgGroupItem
GetNextDlgTabItem
IsDialogMessage
MapDialogRect
MessageBox
MessageBoxEx
SendDlgItemMessage
SetDlgItemInt
SetDlgItemText
MessageBoxIndirect


Dialog Box Structures

Following are the structures used to create and manage dialog boxes and controls within dialog boxes.

DLGITEMTEMPLATE
DLGTEMPLATE
MSGBOXPARAMS


Dialog Box Messages

Following are the messages used to create and manage dialog boxes and controls within dialog boxes.

WM_CTLCOLORMSGBOX
WM_ENTERIDLE
WM_GETDLGCODE
WM_INITDIALOG
WM_NEXTDLGCTL


Edit Controls

Microsoft® Windows® provides dialog boxes and controls to support communication between the application and the user. An edit control is a rectangular control window typically used in a dialog box to permit the user to enter and edit text from the keyboard.


About Edit Controls

An edit control is selected and receives the input focus when a user clicks the mouse inside it or presses the TAB key. After it is selected, the edit control displays its text (if any) and a flashing caret that indicates the insertion point. The user can then enter text, move the insertion point, or select text to be moved or deleted by using the keyboard or the mouse. An edit control can send notification messages to its parent window in the form of WM_COMMAND messages. For more information about messages from an edit control, see Edit Control Notification Messages. A parent window can send messages to an edit control in a dialog box by calling the SendDlgItemMessage function. Each of the messages sent to edit controls are discussed in this overview.

Windows provides both single line edit controls (sometime called SLEs) and multiline edit controls (sometimes called MLEs). Edit controls belong to the EDIT window class.

A combo box is a control that combines much of the functionality of an edit control and a list box. In a combo box, the edit control displays the current selection and the list box presents options a user can select. For more information about combo boxes, see Combo Boxes.

Many developers use the dialog boxes provided in the common dialog box library (COMDLG32.DLL) to perform tasks that otherwise might require customized edit controls. For information about common dialog boxes, see Common Dialog Box Library.


Edit Control Styles

Windows provides several edit control styles. An individual edit control can have several styles at the same time. Most developers use standalone tools to develop dialog boxes and so may not need to specify edit control styles explicitly. If an application creates an edit control using the CreateWindow or CreateWindowEx function, however, it must specify these edit control styles.

Every edit control specifies a combination of style values that define the appearance and features of the edit control. The style values can establish the appearance of a single-line or multiline edit control, align the text in the control, and determine how, and even if, text appears in the edit control. The number and type of styles the application uses depend on the type and purpose of the edit control.

There are two line styles for edit controls. The default is a single-line edit control that doesn't require an associated style. An application can create a multiline edit control by using the ES_MULTILINE style.

There are three styles that cause Windows to align the text in an edit control. The ES_LEFT, ES_CENTER, and ES_RIGHT styles determine whether text is aligned on the left, center, or right, respectively. These styles apply only to multiline edit controls.

An application can use a style to determine how Windows displays text that a user enters into an edit control. The ES_LOWERCASE style converts the text into lowercase characters; the ES_UPPERCASE style converts the text into uppercase characters. Some applications may need to convert the text in a Windows string (such as a filename) into a specific character set. The ES_OEMCONVERT style ensures the proper conversion of characters in these instances. For more information about character sets, see Consoles and Character-Mode Support.

When the amount of text to be displayed exceeds the size of the edit control, an application can use two styles to scroll the text through the edit control. The ES_AUTOHSCROLL style automatically scrolls text horizontally in single-line and multiline edit controls. When the application has a multiline edit control, it can also use the ES_AUTOVSCROLL style to automatically scroll text vertically, if necessary.

Other available styles define different aspects of an edit control. The ES_NUMBER style (available in version 4.0 or later) restricts input to the edit control to digits only. The ES_NOHIDESEL style specifies that the selected text is not hidden when the edit control loses the keyboard focus. The ES_READONLY style makes the edit control read-only. The ES_PASSWORD style displays all characters in the edit control as asterisks. (An application can define a different character to display by using the EM_SETPASSWORDCHAR message, as described later in this topic.) In multiline edit controls, an application can specify the ES_WANTRETURN style to request that Windows insert a carriage return when the user presses the ENTER key in the edit control.

By default, an edit control has no border. To give it one, an application can use the WS_BORDER window style.


The Text Buffer

Windows stores edit control text in a buffer and copies it to the control, as necessary. This section discusses the tools Windows provides to allocate and initialize the buffer and to change its characteristics.


Allocating a Text Buffer

When Windows creates an edit control, it automatically creates a text buffer, sets its initial size, and increases the size as necessary. The size can be up to a predefined limit of approximately 32 kilobytes for single-line edit controls. Because this limit can change, it is called a soft limit. An application can set a hard limit to the buffer size by sending an EM_SETLIMITTEXT message to the edit control. If the buffer exceeds either limit, Windows sends the application an EN_ERRSPACE message. An application can retrieve the current text limit by sending an EM_GETLIMITTEXT message.

Windows typically creates an edit control buffer in a dialog box, using memory outside the application's data segment. An application can suppress this default allocation behavior and create the buffer from its local heap by using the DS_LOCALEDIT style when creating the edit control. An application that uses the DS_LOCALEDIT style is responsible for all buffer allocations. To make the initial allocation, an application can call the LocalAlloc function and pass the returned buffer handle to the edit control by sending it an EM_SETHANDLE message. To make subsequent allocations (in response to an EN_ERRSPACE message, for example), an application should save the current buffer content (if necessary) and obtain a new buffer as follows:

1.	Retrieve the handle of the memory currently allocated for the text in a multiline edit control by sending the control an EM_GETHANDLE message.

2.	Free the buffer by calling the LocalFree function.

3.	Obtain a new buffer (and buffer handle) by calling LocalAlloc.

4.	Give the buffer handle to Windows by sending the control an EM_SETHANDLE message.

The EM_SETHANDLE and EM_GETHANDLE messages apply only to multiline edit controls.

An application that uses the default allocation behavior (that is, does not use the DS_LOCALEDIT style) must not send EM_SETHANDLE and EM_GETHANDLE messages to the edit control.

Sending an EM_SETHANDLE message has several side effects: it clears the undo flag (making the EM_CANUNDO message return zero), it clears the modify flag (making the EM_GETMODIFY message return zero), and it redraws the edit control window.


Initializing a Text Buffer

An application can initialize or reinitialize an edit control's text buffer by calling the SetDlgItemText function. An application can retrieve the content of a text buffer by calling the GetDlgItemText function.


Making a Text Buffer Read-Only

For each edit control, Windows maintains a read-only flag that indicates whether the control's text is read-write (the default) or read-only. An application can set the read-write or read-only flag for the text by sending the control an EM_SETREADONLY message. To determine whether an edit control is read-only, an application can call the GetWindowLong function using the GWL_STYLE constant. The EM_SETREADONLY message applies to both single-line and multiline edit controls.


Changing the Formatting Rectangle

The visibility of an edit control's text is governed by the dimensions of its window rectangle and its formatting rectangle. The window rectangle is the client area of the window containing the edit control. The formatting rectangle is a construct maintained by Windows for formatting the text displayed in the window rectangle. When an edit control is first displayed, the two rectangles are identical on the screen. An application can make the formatting rectangle larger than the window rectangle (thereby limiting the visibility of the edit control's text) or smaller than the window rectangle (thereby creating extra white space around the text).

An application can set the coordinates of an edit control's formatting rectangle by sending it an EM_SETRECT message. The EM_SETRECT message also automatically redraws the edit control's text. To establish the coordinates of the formatting rectangle without redrawing the control's text, an application can send the control an EM_SETRECTNP message. To retrieve the coordinates of the formatting rectangle, an application can send the control an EM_GETRECT message. These messages apply to multiline edit controls only.


Text Operations

Windows automatically processes all user-initiated text operations and notifies the application when the operations are completed. This section discusses user-initiated text operations and the application's response.


Character Sets

Windows (except version 4.0) supports two character sets: Unicode™, a two-byte character set, and ANSI, a one-byte character set that is a strict subset of Unicode. In ANSI, n characters equals n bytes, but in Unicode, n characters equals 2n bytes. For more information about Unicode and character sets, see Unicode and Character Sets.


Fonts

An application can change the font that an edit control uses by sending the WM_SETFONT message. Most applications do this while processing the WM_INITDIALOG message. Changing the font does not change the size of the edit control; applications that send the WM_SETFONT message may have to retrieve the font metrics for the text and recalculate the size of the edit control. For more information about fonts and font metrics, see Fonts and Text.


Selecting an Edit Control

The user can select an edit control by clicking it with the mouse or by tabbing to it. The "tabbing" method is part of a predefined keyboard interface that Windows provides. For a complete description of this interface, see Dialog Boxes.) When the user selects an edit control, Windows gives the control the keyboard focus and highlights its text by using reverse video.


Selecting Text

After selecting an edit control, the user can select text in the control by using the mouse or the keyboard. An application can retrieve the starting and ending character positions of the current selection in an edit control by sending the control an EM_GETSEL message. The return value for the ending position is one greater than the last character in the selection (that is, the position of the first character following the last selected character).

An application can also select text in an edit control by sending the control an EM_SETSEL message with the starting and ending character indices for the selection. For example, the application can use EM_SETSEL with EM_REPLACESEL to delete text from an edit control.

These three messages apply to both single-line and multiline edit controls.


Replacing Text

An application can replace selected text in an edit control by sending the control an EM_REPLACESEL message with a pointer to the replacement text. If there is no current selection, EM_REPLACESEL inserts the replacement text at the insertion point. The application may receive an EN_ERRSPACE notification message if the replacement text exceeds the available memory. This message applies to both single-line and multiline edit controls.

An application can use EM_REPLACESEL to replace part of an edit control's text or the SetDlgItemText function to replace all of it.


Cut, Copy, Paste, and Clear Operations

Windows provides four messages for moving text between an edit control and the clipboard. The WM_COPY message copies the current selection (if any) from an edit control to the clipboard without deleting it from the edit control. The WM_CUT message deletes the current selection, if any, in the edit control and copies the deleted text to the clipboard. The WM_CLEAR message deletes the current selection (if any) from an edit control, but does not copy it to the clipboard (unless the user pressed the SHIFT key). The WM_PASTE message copies text from the clipboard into an edit control at the insertion point. These four messages apply to both single-line and multiline edit controls.

With version 4.0 or later, an edit control includes a built in context menu that makes it easy for the user to move text between the edit control and the clipboard. The context menu appears when the user clicks the control using the right mouse button. The menu items in the context menu include Undo, Cut, Copy, Paste, Delete, and Select All.


Modifying Text

The user can select, delete, or move text in an edit control. Windows maintains an internal flag for each edit control indicating whether the content of the control has been modified. Windows clears this flag when it creates the control and sets the flag whenever the text in the control is modified. An application can retrieve the modification flag by sending the control an EM_GETMODIFY message and set or clear the modification flag by sending the control an EM_SETMODIFY message. These messages apply to both single-line and multiline edit controls.


Limiting User-Entered Text

The default limit to the amount of text a user can enter in an edit control is 32 kilobytes. An application can change the amount of text the user can enter by sending the control an EM_SETLIMITTEXT message. This message sets a hard limit to the number of bytes the user can enter into an edit control, but affects neither text that is already in the control when the message was sent nor text copied to the control by the SetDlgItemText function or the WM_SETTEXT message. For example, suppose that the application uses the SetDlgItemText function to place 500 bytes in an edit control, and the user also enters 500 bytes (1000 bytes total). If the application then sends an EM_SETLIMITTEXT message limiting user-entered text to 300 bytes, the 1000 bytes already in the edit control remain there, and the user cannot add any more text. On the other hand, if the application sends an EM_SETLIMITTEXT message limiting user-entered text to 1300 bytes, the 1000 bytes remain, but the user can add 300 more bytes.

When the user reaches the character limit of an edit control, Windows sends the application a WM_COMMAND message containing an EN_MAXTEXT notification message. This notification message does not mean that memory has been exhausted, but that the limit for user-entered text has been reached; the user cannot enter any more text. To change this limit, an application must send the control a new EM_SETLIMITTEXT message with a higher limit.

As an example of the use of EM_SETLIMITTEXT and EN_MAXTEXT, suppose that the application must limit the user to no more than four characters in an edit control. The application would use EM_SETLIMITTEXT to specify a four-character limit. If the user tried to enter a fifth character, Windows would send an EN_MAXTEXT notification message to the application.


Character and Line Operations

The Microsoft® Win32® application programming interface (API) provides several messages that return information about the characters and lines in an edit control. Most of the messages return an index, usually a zero-based number, to refer to a character or line. Given this, a single-line edit control containing n characters, the line index is zero and the characters are indexed from zero to n − 1. In a multiline edit control containing m lines and n characters, the lines are indexed from zero to m − 1, and the characters are indexed from zero to n − 1. Note that character indexing ignores linebreaks.

An application can determine the number of characters in an edit control by sending the WM_GETTEXTLENGTH message to the edit control. This message returns the length, in characters (not including the terminating null character), of the text in a single-line or multiline edit control. The EM_LINELENGTH message returns the length, in characters, of a line specified by the character index of a character in the line. The returned length does not include any selected characters. An application can use these messages in a single-line or multiline edit control.

The EM_GETFIRSTVISIBLELINE message returns the zero-based index of the uppermost visible line in a multiline edit control, or the zero-based index of the first visible character in a single-line edit control. An application can copy a line from an edit control to a buffer by sending the EM_GETLINE message to the edit control. The line is specified by its line index and the first word of the receiving buffer contains the maximum number of bytes to be copied to the buffer. The return value is the number of bytes copied. This message can also be used in a single-line or multiline edit control.

There are unique messages available to return the information about a line in a multiline edit control. The EM_GETLINECOUNT message returns the number of lines in an edit control. An application can determine the index of a character in a specific line by using the EM_LINEFROMCHAR and EM_LINEINDEX messages. The EM_LINEFROMCHAR message returns the index of the line containing a specified character index. This message is the reverse of the EM_LINEINDEX message, which returns the index of the first character in a specified line.


Scrolling Text in an Edit Control

An application can implement scrolling in an edit control by using the automatic scrolling styles discussed in Edit Control Styles or by explicitly adding scroll bars to the control. To add a horizontal scroll bar, use the style WS_HSCROLL; to add a vertical scroll bar, use the style WS_VSCROLL. An edit control with scroll bars processes its own scroll bar messages. For detailed information about adding scroll bars to edit controls, see Scroll Bars.

Windows provides three messages that an application can send to an edit control with scroll bars. The EM_LINESCROLL message can scroll a multiline edit control both vertically and horizontally. The lParam parameter specifies the number of lines to scroll vertically starting from the current line and the wParam parameter specifies the number of characters to scroll horizontally, starting from the current character. The edit control doesn't acknowledge horizontal scrolling messages if it has the ES_CENTER or ES_RIGHT style. This message applies to multiline edit controls only.

The EM_SCROLL message scrolls a multiline edit control vertically, which is the same effect as sending a WM_VSCROLL message. The wParam parameter specifies the scrolling action. The EM_SCROLL message applies to multiline edit controls only.

The EM_SCROLLCARET message scrolls the caret into view in an edit control. This was done in previous versions of Windows by specifying wParam = FALSE in an EM_SETSEL message. A Win32-based application should use the EM_SCROLLCARET message for the task.


Tab Stops and Margins

An application can set tab stops in a multiline edit control by using the EM_SETTABSTOPS message. (The default for a tab stop is eight characters.) When an application adds text to the edit control, tab characters in the text automatically generate space up to the next tab stop. The EM_SETTABSTOPS message does not automatically cause Windows to redraw the text. To do that, an application can call the InvalidateRect function. The EM_SETTABSTOPS message applies to multiline edit controls only.

An application can set width of the left and right margins for an edit control by using the EM_SETMARGINS message. After sending this message, Windows redraws the edit control to reflect the new margin settings. An application can retrieve the width of the left or right margin by sending the EM_GETMARGINS message. By default, the edit control margins are set to be just wide enough to accommodate the largest character horizontal overhang (negative ABC widths) for the font currently in use in the edit control.


Password Characters

An application can use a password character in an edit control to conceal user input. When a password character is set, it is displayed in place of each character the user types. When a password character is removed, the control displays the characters the user types. If the application creates an edit control using the style ES_PASSWORD, the default password character is an asterisk (*). An application can use the EM_SETPASSWORDCHAR message to remove or define a different password character and the EM_GETPASSWORDCHAR message to retrieve the current password character. These messages apply to single-line edit controls only.


Using Integers

Windows provides two integer-conversion functions for edit controls designed to contain numbers only. The SetDlgItemInt function creates the string representation of a specified integer (signed or unsigned) and sends the string to an edit control. SetDlgItemInt returns no value. The GetDlgItemInt function creates an integer (signed or unsigned) from its string representation in an edit control. GetDlgItemInt returns the integer (or an error value).


Undoing Text Operations

Every edit control maintains an undo flag that indicates whether an application can reverse (undo) the most recent operation on the edit control (to undo a text deletion, for example). The edit control sets the undo flag to indicate that the operation can be undone and resets it to indicate that the operation cannot be undone. An application can determine the setting of the undo flag by sending the control an EM_CANUNDO message.

An application can undo the most recent operation by sending the control an EM_UNDO message. An operation can be undone provided no other edit control operation occurs first. For example, the user can delete text, replace the text (undo the deletion), and then delete the text again (undo the replacement). The EM_UNDO message applies to both single-line and multiline edit controls and always works for single-line edit controls.

An application can reset an edit control's undo flag by sending the control an EM_EMPTYUNDOBUFFER message. Windows automatically resets the undo flag whenever an edit control receives an EM_SETHANDLE or WM_SETTEXT message. The SetDlgItemText function sends a WM_SETTEXT message.


Wordwrap Functions

An application can use wordwrap functions with multiline edit controls to locate the word or word fragment that should be wrapped to the next line. Using the default wordwrap function provided by Windows, lines always end at the spaces between words. An application can specify its own wordwrap function by supplying a EditWordBreakProc wordwrap function and sending an edit control an EM_SETWORDBREAKPROC message. An application can retrieve the address of the current wordwrap function by sending the control an EM_GETWORDBREAKPROC message.

An application may direct a multiline edit control to add or remove a soft linebreak character (two carriage returns and a linefeed) automatically at the end of wrapped text lines. An application can turn this feature on or off by sending the edit control an EM_FMTLINES message. This message applies only to multiline edit controls and does not affect a line that ends with a hard linebreak (one carriage return and a linefeed entered by the user).


Retrieving Points and Characters

An application can determine which character is closest to the specified point in an edit control by sending the EM_CHARFROMPOS message. The message returns the character index and line index of the character nearest the point. Similarly, an application can determine the client coordinates of the specified character in an edit control by sending the EM_POSFROMCHAR message. The application specifies the index of a character and the message returns the x and y coordinates of the upper left corner of the character.


Edit Control Notification Messages

The user makes editing requests by using the keyboard and mouse. Windows sends each request to the edit control's parent window in the form of a WM_COMMAND message. The message includes the edit control identifier in the low-order word of the wParam parameter, the handle of the edit control in the lParam parameter, and an edit control notification message corresponding to the user's action in the high-order word of the wParam parameter.

Portability issue  In Microsoft® Windows NT™, the placement of the notification code in a notification message has moved from the lParam parameter to the wParam parameter. Windows 3.x applications that process notification messages must modify this code when porting to Windows NT.

An application should examine each notification message and respond appropriately. The following table lists each edit control notification message and the action that generates it.

Notification message	User action
EN_CHANGE	The user has modified text in an edit control. Windows updates the display before sending this message (unlike EN_UPDATE).
EN_ERRSPACE	The edit control cannot allocate enough memory to meet a specific request.
EN_HSCROLL	The user has clicked the edit control's horizontal scroll bar. Windows sends this message before updating the screen.
EN_KILLFOCUS	The user has selected another control.
EN_MAXTEXT	While inserting text, the user has exceeded the specified number of characters for the edit control. Insertion has been truncated. This message is also sent either when an edit control does not have the ES_AUTOHSCROLL style and the number of characters to be inserted exceeds the width of the edit control or when an edit control does not have the ES_AUTOVSCROLL style and the total number of lines to be inserted exceeds the height of the edit control.
EN_SETFOCUS	The user has selected this edit control.
EN_UPDATE	The user has altered the text in the edit control and Windows is about to display the new text. Windows sends this message after formatting the text, but before displaying it, so that the application can resize the edit control window.
EN_VSCROLL	The user has clicked the edit control's vertical scroll bar. Windows sends this message before updating the screen.
In addition, the system sends a WM_CTLCOLOREDIT message to an edit control's parent window before the edit control is drawn. This message contains a handle of the edit control's display context (DC) and a handle of the child window. The parent window can use these handles to change the edit control's text and background colors.


Edit Control Default Message Processing

The window procedure for the predefined edit control window class carries out default processing for all messages that the edit control procedure does not process. When the edit control procedure returns FALSE for any message, the predefined window procedure checks the messages and carries out the following default actions.

Message	Default action
EM_CANUNDO	Returns TRUE if the edit control operation can be undone.
EM_CHARFROMPOS	Returns the character index and line index of the character nearest the specified point.
EM_EMPTYUNDOBUFFER	Empties the undo buffer and sets the undo flag retrieved by the EM_CANUNDO message to FALSE. Windows automatically clears the undo flag whenever the edit control receives a WM_SETTEXT or EM_SETHANDLE message.
EM_FMTLINES	Adds or removes soft linebreak characters (two carriage returns and a linefeed) to the ends of wrapped lines in a multiline edit control. It is not processed by single-line edit controls.
EM_GETFIRSTVISIBLELINE	Returns the zero-based index of the first visible character in a single-line edit control or the zero-based index of the uppermost visible line in a multiline edit control.
EM_GETHANDLE	Returns a handle identifying the buffer containing the multiline edit control's text. It is not processed by single-line edit controls.
EM_GETLIMITTEXT	Returns the current text limit, in characters.
EM_GETLINE	Copies characters in a single-line edit control to a buffer and returns the number of characters copied. In a multiline edit control, retrieves a line of text from the control and returns the number of characters copied.
EM_GETLINECOUNT	Returns the number of lines in the edit control.
EM_GETMARGINS	Returns the widths of the left and right margins.
EM_GETMODIFY	Returns a flag indicating whether the content of an edit control has been modified.
EM_GETPASSWORDCHAR	Returns the character that edit controls use in conjunction with the ES_PASSWORD style.
EM_GETRECT	Returns the coordinates of the formatting rectangle in an edit control.
EM_GETSEL	Returns the starting and ending character positions of the current selection in the edit control.
EM_GETTHUMB	Returns the position of the scroll box.
EM_GETWORDBREAKPROC	Returns the address of the current wordwrap function in an edit control.
EM_LINEFROMCHAR	Returns the zero-based number of the line in a multiline edit control that contains a specified character index This message is the reverse of the EM_LINEINDEX message. It is not processed by single-line edit controls.
EM_LINEINDEX	Returns the character of a line in a multiline edit control. This message is the reverse of the EM_LINEFROMCHAR message. It is not processed by single-line edit controls.
EM_LINELENGTH	Returns the length, in characters, of a single-line edit control. In a multiline edit control, returns the length, in characters, of a specified line.
EM_LINESCROLL	Scrolls the text vertically in a single-line edit control or horizontally in a multiline edit control (when the control has the ES_LEFT style). The lParam parameter specifies the number of lines to scroll vertically, starting from the current line. The wParam parameter specifies the number of characters to scroll horizontally, starting from the current character.
EM_POSFROMCHAR	Returns the client coordinates of the specified character.
EM_REPLACESEL	Replaces the current selection with the text in an application-supplied buffer, sends the parent window EN_UPDATE and EN_CHANGE messages, and updates the undo buffer.
EM_SCROLL	Scrolls the text vertically in a multiline edit control. This message is equivalent to sending a WM_VSCROLL message to the edit control. It is not processed by single-line edit controls.
EM_SCROLLCARET	Scrolls the caret into view in an edit control. In earlier versions of Windows this was done via EM_SETSEL using particular parameters. A Win32-based application should use EM_SCROLLCARET.
EM_SETFONT	Unsupported.
EM_SETHANDLE	Sets a handle to the memory used as a text buffer, empties the undo buffer, resets the scroll positions to zero, and redraws the window.
EM_SETLIMITTEXT	Sets the maximum number of characters the user may enter in the edit control. For single-line edit controls, this value is either 0x7FFFFFFE (0x7FFE for version 4.0) or the value of the wParam parameter, whichever is smaller. For multiline edit controls, this value is either 0xFFFFFFFF (0xFFFF for version 4.0) or the value of the wParam parameter, whichever is smaller.
EM_SETMARGINS	Sets the widths of the left and right margins, and redraws the edit control to reflect the new margins.
EM_SETMODIFY	Sets or clears the modification flag to indicate whether the edit control has been modified.
EM_SETPASSWORDCHAR	Defines the character that edit controls use in conjunction with the ES_PASSWORD style.
EM_SETREADONLY	Sets or removes the read-only style (ES_READONLY) in an edit control.
EM_SETRECT	Sets the formatting rectangle for the multiline edit control and redraws the window. It is not processed by single-line edit controls.
EM_SETRECTNP	Sets the formatting rectangle for the multiline edit control but does not redraw the window. It is not processed by single-line edit controls.
EM_SETSEL	Selects a range of characters in the edit control by setting the starting and ending positions to be selected.
EM_SETTABSTOPS	Sets tab-stop positions in the multiline edit control. It is not processed by single-line edit controls.
EM_SETWORDBREAKPROC	Replaces the default wordwrap function with an application-defined wordwrap function.
EM_UNDO	Removes any text that was just inserted or inserts any deleted characters and sets the selection to the inserted text. If necessary, sends the EN_UPDATE and EN_CHANGE notification messages to the parent window.
WM_CHAR	Writes a character to the single-line edit control and sends the EN_UPDATE and EN_CHANGE notification messages to the parent window. Writes a character to the multiline edit control. Handles the accelerator keys for standard functions, such as CTRL+C for copying and CTRL+V for pasting. In multiline edit controls, also processes TAB, and CTRL+TAB keystrokes to move among the controls in a dialog box and to insert tabs into multiline edit controls. Uses the MessageBeep function for illegal characters.
WM_CLEAR	Clears the current selection, if any, in an edit control. If there is no current selection, deletes the character to the right of the caret. If the user presses the SHIFT key, this cuts the selection to the clipboard, or deletes the character to the left of the caret when there is no selection. If the user presses the CTRL key, this deletes the selection, or deletes to the end of the line when there is no selection.
WM_COPY	Copies text to the clipboard unless the style is ES_PASSWORD, in which case the message returns zero.
WM_CREATE	Creates the edit control and notifies the parent window with TRUE for success or −1 for failure.
WM_CUT	Cuts the selection to the clipboard, or deletes the character to the left of the cursor if there is no selection.
WM_ENABLE	Causes the rectangle to be redrawn in gray for single-line edit controls. Returns the enabled state for single-line and multiline edit controls.
WM_ERASEBKGND	Fills the multiline edit control window with the current color of the edit control.
WM_GETDLGCODE	Returns the following values: DLGC_WANTCHARS, DLGC_HASSETSEL, and DLGC_WANTARROWS. In multiline edit controls, it also returns DLGC_WANTALLKEYS. If the user presses ALT+BACKSPACE, it also returns DLGC_WANTMESSAGE.
WM_GETFONT	Returns the handle of the font being used by the control, or NULL if the control uses the system font.
WM_GETTEXT	Copies the specified number of characters to a buffer and returns the number of characters copied.
WM_GETTEXTLENGTH	Returns the length, in characters, of the text in an edit control. The length does not include the null- terminating character.
WM_HSCROLL	Scrolls the text in a multiline edit control horizontally and handles scroll box movement.
WM_KEYDOWN	Performs standard processing of the virtual-key codes.
WM_KILLFOCUS	Removes the keyboard focus of an edit control window, destroys the caret, hides the current selection, and notifies the parent window that the edit control has lost the focus.
WM_LBUTTONDBLCLK	Clears the current selection and selects the word under the cursor. If the SHIFT key is down, extends the selection to the word under the cursor.
WM_LBUTTONDOWN	Changes the current insertion point. If the SHIFT key is down, it extends the selection to the position of the cursor. In multiline edit controls, also sets the timer to automatically scroll when the user holds down the mouse button outside the multiline edit control window.
WM_LBUTTONUP	Releases the mouse capture and sets the text insertion point in the single-line edit control. In a multiline edit control, it also kills the timer set in the WM_LBUTTONDOWN message.
WM_MOUSEMOVE	Changes the current selection in the single-line edit control, if the mouse button is down. In a multiline edit controls, also sets the timer to automatically scroll if the user holds down the mouse button outside the multiline edit control window.
WM_NCCREATE	Points to the CREATESTRUCT structure for the window. This message is sent to the WM_CREATE message when a window is first created.
WM_NCDESTROY	Frees all memory associated with the edit control window, including the text buffer, undo buffer, tab-stop buffer, and highlight brush.
WM_PAINT	Erases the background, fills the window with the current color of the edit control window, draws the border (if any), sets the font and draws any text, and shows the text-insertion caret.
WM_PASTE	Pastes text from the clipboard into the edit control window at the caret position.
WM_SETFOCUS	Sets the keyboard focus of an edit control window (shows the current selection, if it was hidden, and creates the caret).
WM_SETFONT	Sets the font and optionally redraws the edit control.
WM_SETTEXT	Copies text to the single-line edit control, notifies the parent window when there is insufficient memory, empties the undo buffer, and sends the EN_UPDATE and EN_CHANGE notification messages to the parent window. In multiline edit controls, also rewraps the lines (if necessary) and sets the scroll positions.
WM_SIZE	Changes the size of the edit control window and ensures that the minimum size accommodates the height and width of a character.
WM_SYSCHAR	Returns TRUE if the user presses ALT+BACKSPACE; otherwise, it takes no action.
WM_SYSKEYDOWN	Undoes the last action if the user presses ALT+BACKSPACE; otherwise, it takes no action.
WM_TIMER	Scrolls the text in the edit control window if the user holds down the mouse button outside the multiline edit control window.
WM_UNDO	Removes any text that was just inserted or inserts any deleted characters and sets the selection to the inserted text. If necessary, sends the EN_UPDATE and EN_CHANGE notification messages to the parent window.
WM_VSCROLL	Scrolls a multiline edit control vertically and handles scroll box movement. It is not processed by single-line edit controls.
The predefined edit control window procedure passes all other messages to the DefWindowProc function for default processing.


Using Edit Controls

Edit controls are typically used in dialog boxes, but you can use them in the client area of a standard window as well. Single-line edit controls are useful for retrieving a single string from the user. Multiline edit controls make it easy for your application to implement most of the features of a simple word processor.

•	Simple word processing with an edit control

•	Using single-line edit controls


Simple Word Processing with an Edit Control

The following example implements much of the functionality of a simple word processor by filling the client area of a window with a multiline edit control. The system automatically performs wordwrap operations for this edit control and also handles the processing for the vertical scroll bar (created by specifying ES_AUTOVSCROLL in the call to the CreateWindow function). The WM_COMMAND message processes menu items; they allow the user to undo the previous action, cut or copy selections to the clipboard, paste text from the clipboard, and delete the current selection.

LONG APIENTRY MainWndProc(

HWND hwnd,                /* window handle                   */

UINT message,             /* type of message                 */

UINT wParam,              /* additional information          */

LONG lParam)              /* additional information          */

{

    static HWND hwndEdit;

    CHAR lpszTrouble[] = "When in the Course of human Events "

                         "it becomes necessary for one People "

                         "to dissolve the Political Bands which "

                         "have connected them with another, and "

                         "to assume among the Powers of the "

                         "Earth, the separate and equal Station "

                         "to which the Laws of Nature and of "

                         "Nature's God entitle them, a decent "

                         "Respect to the Opinions of Mankind "

                         "requires that they should declare the "

                         "causes which impel them to the "

                         "Separation. ";

    switch (message) {

        case WM_CREATE:

            hwndEdit = CreateWindow(

                "EDIT",     /* predefined class                  */

                NULL,       /* no window title                   */

                WS_CHILD | WS_VISIBLE | WS_VSCROLL |

                    ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL,

                0, 0, 0, 0, /* set size in WM_SIZE message       */

                hwnd,       /* parent window                     */

                (HMENU) ID_EDITCHILD, /* edit control ID         */

                (HINSTANCE) GetWindowLong(hwnd, GWL_HINSTANCE),

                NULL);                /* pointer not needed      */

             /* Add text to the window. */

             SendMessage(hwndEdit, WM_SETTEXT, 0,

                (LPARAM) lpszTrouble);

            return 0;

        case WM_COMMAND:

            switch (wParam) {

                case IDM_EDUNDO:

                    /*

                     * Send WM_UNDO only if there is something

                     * to be undone.

                     */

                    if (SendMessage(hwndEdit, EM_CANUNDO, 0, 0))

                        SendMessage(hwndEdit, WM_UNDO, 0, 0);

                    else

                        MessageBox(hwndEdit,

                            "Nothing to undo.",

                            "Undo notification", MB_OK);

                    break;

                case IDM_EDCUT:

                    SendMessage(hwndEdit, WM_CUT, 0, 0);

                    break;

                case IDM_EDCOPY:

                    SendMessage(hwndEdit, WM_COPY, 0, 0);

                    break;

                case IDM_EDPASTE:

                    SendMessage(hwndEdit, WM_PASTE, 0, 0);

                    break;

                case IDM_EDDEL:

                    SendMessage(hwndEdit, WM_CLEAR, 0, 0);

                    break;

                case IDM_PASSWORD:

                    DialogBox(hinst, /* current instance         */

                        "PassBox",   /* resource to use          */

                         hwnd,       /* parent handle            */

                         (DLGPROC) PassProc);

                    break;

                case IDM_WRAP:

                    SendMessage(hwndEdit,

                        EM_SETWORDBREAKPROC,

                        (WPARAM) 0,

                        (LPARAM) (EDITWORDBREAKPROC) WordBreakProc);

                    SendMessage(hwndEdit,

                        EM_FMTLINES,

                        (WPARAM) TRUE,

                        (LPARAM) 0);

                    SendMessage(hwndEdit,

                        EM_SETSEL,

                        0, -1); /* select all text */

                    SendMessage(hwndEdit, WM_CUT, 0, 0);

                    SendMessage(hwndEdit, WM_PASTE, 0, 0);

                    break;

                case IDM_ABOUT:

                    DialogBox(hinst, /* current instance         */

                        "AboutBox",  /* resource to use          */

                         hwnd,       /* parent handle            */

                         (DLGPROC) About);

                    break;

                default:

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

            }

            break;

        case WM_SETFOCUS:

            SetFocus(hwndEdit);

            return 0;

        case WM_SIZE:

            /*

             * Make the edit control the size of the window's

             * client area.

             */

            MoveWindow(hwndEdit,

                0, 0,           /* starting x- and y-coordinates */

                LOWORD(lParam), /* width of client area          */

                HIWORD(lParam), /* height of client area         */

                TRUE);          /* repaint window                */

            return 0;

        case WM_DESTROY:

            PostQuitMessage(0);

            return 0;

        default:

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

    }

    return NULL;

}


Using Single-Line Edit Controls

The example in this section demonstrates how to use a window procedure to produce a dialog box that prompts the user to enter a password.

The single-line edit control in the Password dialog box has the ES_PASSWORD style. By default, edit controls with this style display an asterisk for each character the user types. This example, however, uses the EM_SETPASSWORDCHAR message to change the default character from an asterisk to a plus sign (+).

This window procedure changes the default push button from Cancel to OK as soon as the user enters text in the edit control. If the user presses the OK button, the window procedure uses the EM_LINELENGTH and EM_GETLINE messages to retrieve the text.

LRESULT CALLBACK PassProc(hDlg, message, wParam, lParam)

HWND hDlg;                /* window handle of the dialog box */

UINT message;             /* type of message                 */

UINT wParam;              /* message-specific information    */

LONG lParam;

{

    CHAR lpszPassword[16];

    WORD cchPassword;

    switch (message) {

        case WM_INITDIALOG:

            /* Set password character to a plus sign (+) */

            SendDlgItemMessage(hDlg,

                IDE_PASSWORDEDIT,

                EM_SETPASSWORDCHAR,

                (WPARAM) '+',

                (LPARAM) 0);

            /* Set the default push button to "Cancel." */

            SendMessage(hDlg,

                DM_SETDEFID,

                (WPARAM) IDCANCEL,

                (LPARAM) 0);

            return TRUE;

        case WM_COMMAND:

            /*

             * Set the default push button to "OK" when the user

             * enters text.

             */

            if(HIWORD (wParam) == EN_CHANGE &&

                    LOWORD(wParam) == IDE_PASSWORDEDIT)

                SendMessage(hDlg,

                    DM_SETDEFID,

                    (WPARAM) IDOK,

                    (LPARAM) 0);

            switch(wParam) {

                case IDOK:

                    /* Get number of characters. */

                    cchPassword = (WORD) SendDlgItemMessage(hDlg,

                        IDE_PASSWORDEDIT,

                        EM_LINELENGTH,

                        (WPARAM) 0,

                        (LPARAM) 0);

                    if (cchPassword >= 16) {

                        MessageBox(hDlg,

                            "Too many characters.",

                            "Error",

                            MB_OK);

                        EndDialog(hDlg, TRUE);

                        return FALSE;

                    }

                    else if (cchPassword == 0) {

                        MessageBox(hDlg,

                            "No characters entered.",

                            "Error",

                            MB_OK);

                        EndDialog(hDlg, TRUE);

                        return FALSE;

                    }

                    /*

                     * Put the number of characters into first word

                     * of buffer.

                     */

                    *((LPWORD)lpszPassword) = cchPassword;

                    /* Get the characters. */

                    SendDlgItemMessage(hDlg,

                        IDE_PASSWORDEDIT,

                        EM_GETLINE,

                        (WPARAM) 0,       /* line 0 */

                        (LPARAM) lpszPassword);

                    /* Null-terminate the string. */

                    lpszPassword[cchPassword] = 0;

                    MessageBox(hDlg,

                        lpszPassword,

                        "Did it work?",

                        MB_OK);

                    /* Call a local password-parsing function. */

                    ParsePassword(lpszPassword);

                    EndDialog(hDlg, TRUE);

                    return TRUE;

                case IDCANCEL:

                    EndDialog(hDlg, TRUE);

                    return TRUE;

            }

            return 0;

    }

    return FALSE;

        UNREFERENCED_PARAMETER(lParam);

}


Edit Control Reference

The following functions and messages are associated with edit controls.


Edit Control Functions

Following are the functions used with edit controls.

EditWordBreakProc


Edit Control Messages

Following are the messages used with edit controls.

EM_CANUNDO
EM_CHARFROMPOS
EM_EMPTYUNDOBUFFER
EM_FMTLINES
EM_GETFIRSTVISIBLELINE
EM_GETHANDLE
EM_GETLIMITTEXT
EM_GETLINE
EM_GETLINECOUNT
EM_GETMARGINS
EM_GETMODIFY
EM_GETPASSWORDCHAR
EM_GETRECT
EM_GETSEL
EM_GETWORDBREAKPROC
EM_LINEFROMCHAR
EM_LINEINDEX
EM_LINELENGTH
EM_LINESCROLL
EM_POSFROMCHAR
EM_REPLACESEL
EM_SCROLL
EM_SCROLLCARET
EM_SETHANDLE
EM_SETLIMITTEXT
EM_SETMARGINS
EM_SETMODIFY
EM_SETPASSWORDCHAR
EM_SETREADONLY
EM_SETRECT
EM_SETRECTNP
EM_SETSEL
EM_SETTABSTOPS
EM_SETWORDBREAKPROC
EM_UNDO
EN_CHANGE
EN_ERRSPACE
EN_HSCROLL
EN_KILLFOCUS
EN_MAXTEXT
EN_SETFOCUS
EN_UPDATE
EN_VSCROLL
WM_COMMAND
WM_COPY
WM_CTLCOLOREDIT
WM_CUT
WM_PASTE
WM_UNDO


List Boxes

The Microsoft® Win32® application programming interface (API) provides dialog boxes and controls to support communication between an application and the user. A list box is a control window that contains a list of items from which the user can choose.


About List Boxes

List box items can be represented by text strings, bitmaps, or both. If the list box is not large enough to display all the list box items at once, the list box can provide a scroll bar. The user maneuvers through the list box items, scrolling the list when necessary, and selects or removes the selection from items. Selecting a list box item changes its visual appearance, usually by changing the text and background colors to the colors specified by the operating system metrics for selected items. When the user selects an item or removes the selection from an item, Windows sends a notification message to the parent window of the list box.

A dialog box procedure is responsible for initializing and monitoring its child windows, including any list boxes. The dialog box procedure communicates with the list box by sending messages to it and by processing the notification messages sent by the list box. For more information about dialog boxes, see Dialog Boxes.

For general information about controls, see Controls.


List Box Styles

The Win32 API provides two general styles of list box: single-selection (the default style) and multiple-selection. In a single-selection list box, the user can select only one item at a time. In a multiple-selection list box, the user can select more than one item at a time; an application must specify either the LBS_MULTIPLESEL or the LBS_EXTENDEDSEL style for a multiple-selection list box.

The Win32 API provides many other list box and window styles that control the appearance and operation of a list box. These styles indicate whether list box items are sorted, arranged in multiple columns, drawn by the application, and so on. The dimensions and styles of a list box are typically defined in a dialog box template included in an application's resources. For information about how to create a dialog box template and include it in an application, see the documentation provided with your development tools.

To create a list box by using the CreateWindow or CreateWindowEx function, use the LISTBOX class, appropriate window style constants, and the following style constants to define the list box.

List box style	Description
LBS_DISABLENOSCROLL	Shows a disabled vertical scroll bar for the list box when the box does not contain enough items to scroll. If you do not specify this style, the scroll bar is hidden when the list box does not contain enough items.
LBS_EXTENDEDSEL	Allows multiple items to be selected by using the SHIFT key and the mouse or special key combinations.
LBS_HASSTRINGS	Specifies that a list box contains items consisting of strings. The list box maintains the memory and addresses for the strings so that the application can use the LB_GETTEXT message to retrieve the text for a particular item. By default, all list boxes except owner-drawn list boxes have this style. You can create an owner-drawn list box either with or without this style.
LBS_MULTICOLUMN	Specifies a multicolumn list box that is scrolled horizontally. The LB_SETCOLUMNWIDTH message sets the width of the columns.
LBS_MULTIPLESEL	Turns string selection on or off each time the user clicks or double-clicks a string in the list box. The user can select any number of strings.
LBS_NODATA	Obsolete.
LBS_NOINTEGRALHEIGHT	Specifies that the size of the list box is exactly the size specified by the application when it created the list box. Normally, Windows sizes a list box so that the list box does not display partial items.
LBS_NOREDRAW	Specifies that the list box's appearance is not updated when changes are made. You can change this style by sending a WM_SETREDRAW message at any time.
LBS_NOSEL	Specifies that the list box contains items that can be viewed but not selected.
LBS_NOTIFY	Notifies the parent window with an input message whenever the user clicks or double-clicks a string in the list box.
LBS_OWNERDRAWFIXED	Specifies that the owner of the list box is responsible for drawing its contents and that the items in the list box are the same height. The owner window receives a WM_MEASUREITEM message when the list box is created and a WM_DRAWITEM message when a visual aspect of the list box has changed.
LBS_OWNERDRAWVARIABLE	Specifies that the owner of the list box is responsible for drawing its contents and that the items in the list box are variable in height. The owner window receives a WM_MEASUREITEM message for each item in the combo box when the combo box is created and a WM_DRAWITEM message when a visual aspect of the combo box has changed.
LBS_SORT	Sorts strings in the list box alphabetically.
LBS_STANDARD	Sorts strings in the list box alphabetically. The parent window receives an input message whenever the user clicks or double-clicks a string. The list box has borders on all sides.
LBS_USETABSTOPS	Enables a list box to recognize and expand tab characters when drawing its strings. The default tab positions are 32 dialog box units. A dialog box unit is a horizontal or vertical distance. One horizontal dialog box unit is equal to 0.25 of the current dialog box base-width unit. Windows calculates these units based on the height and width of the current system font. The GetDialogBaseUnits function returns the current dialog box base units in pixels.
LBS_WANTKEYBOARDINPUT	Specifies that the owner of the list box receives WM_VKEYTOITEM messages whenever the user presses a key and the list box has the input focus. This enables an application to perform special processing on the keyboard input.


List Box Functions Overview

The Win32 API provides two functions specific to list boxes. The DlgDirList function fills a list box with the files and directories in a specified path. The DlgDirSelectEx function retrieves the current selection in a list box initialized by DlgDirList. These functions make it possible for the user to select a file from a list box without typing the location and name of the file.


Notification Messages from List Boxes

When an event occurs in a list box, the list box sends a notification message to the dialog box procedure of the owner window. List box notification messages are sent when a user selects, double-clicks, or cancels a list box item; when the list box receives or loses the keyboard focus; and when the system cannot allocate enough memory for a list box request. A notification message is sent as a WM_COMMAND message in which the low-order word of the wParam parameter contains the list box identifier, the high-order word of wParam contains the notification message, and the lParam parameter contains the control window handle.

Portability Issue  The placement of notification message has moved from the lParam parameter to the wParam parameter. Windows 3.x−based applications that process notification messages must be modified in this respect when they are ported to Win32-based applications.

A dialog box procedure is not required to process these messages; the default window procedure processes them.

An application should monitor and process the following list box notification messages.

Notification message	Description
LBN_DBLCLK	The user double-clicks an item in the list box.
LBN_ERRSPACE	The list box cannot allocate enough memory to fulfill a request.
LBN_KILLFOCUS	The list box loses the keyboard focus.
LBN_SELCANCEL	The user cancels the selection of an item in the list box.
LBN_SELCHANGE	The selection in a list box is about to change.
LBN_SETFOCUS	The list box receives the keyboard focus.


Messages to List Boxes

A dialog box procedure can send messages to a list box to add, delete, examine, and change list box items. For example, a dialog box procedure could send an LB_ADDSTRING message to a list box to add an item, and an LB_GETSEL message to determine whether the item is selected. Other messages set and retrieve information about the size, appearance, and behavior of the list box. For example, the LB_SETHORIZONTALEXTENT message sets the scrollable width of a list box. A dialog box procedure can send any message to a list box by using the SendMessage or SendDlgItemMessage function.

A list box item is often referenced by its index, an integer that represents the item's position in the list box. The index of the first item in a list box is 0, the index of the second item is 1, and so on.

The following table describes how the predefined list box procedure responds to list box messages.

Message	Response
LB_ADDFILE	Inserts a file into a directory list box filled by the DlgDirList function and retrieves the list box index of the inserted item.
LB_ADDSTRING	Adds a string to a list box and returns its index.
LB_DELETESTRING	Removes a string from a list box and returns the number of strings remaining in the list.
LB_DIR	Adds a list of filenames to a list box and returns the index of the last filename added.
LB_FINDSTRING	Returns the index of the first string in the list box that matches a given prefix.
LB_FINDSTRINGEXACT	Returns the index of the string that is equivalent to or prefixed by a given prefix.
LB_GETANCHORINDEX	Returns the index of the item that the mouse last selected.
LB_GETCARETINDEX	Returns the index of the item that has the focus rectangle.
LB_GETCOUNT	Returns the number of items in the list box.
LB_GETCURSEL	Returns the index of the currently selected item.
LB_GETHORIZONTALEXTENT	Returns the scrollable width, in pixels, of a list box.
LB_GETITEMDATA	Returns the 32-bit value associated with the given item.
LB_GETITEMHEIGHT	Returns the height, in pixels, of an item in a list box.
LB_GETITEMRECT	Retrieves the client coordinates of the given list box item.
LB_GETLOCALE	Retrieves the locale of the list box. The high-order word contains the country code and the low-order word contains the language identifier.
LB_GETSEL	Returns the selection state of a list box item.
LB_GETSELCOUNT	Returns the number of selected items in a multiple-selection list box.
LB_GETSELITEMS	Creates an array of the indexes of all selected items in a multiple-selection list box and returns the total number of selected items.
LB_GETTEXT	Retrieves the string associated with a given item and the length of the string.
LB_GETTEXTLEN	Returns the length, in characters, of the string associated with a given item.
LB_GETTOPINDEX	Returns the index of the first visible item in a list box.
LB_INITSTORAGE	Allocates memory for the specified number of items and their associated strings.
LB_INSERTSTRING	Inserts a string at a given index in a list box.
LB_ITEMFROMPOINT	Retrieves the zero-based index of the item nearest the specified point in a list box.
LB_RESETCONTENT	Removes all items from a list box.
LB_SELECTSTRING	Selects the first string it finds that matches a given prefix.
LB_SELITEMRANGE	Selects a given range of items in a list box.
LB_SELITEMRANGEEX	Selects a given range of items if the index of the first item in the range is less than the index of the last item in the range. Cancels the selection in the range if the index of the first item is greater than the last.
LB_SETANCHORINDEX	Sets the item that the mouse last selected to a given item.
LB_SETCARETINDEX	Sets the focus rectangle to a given list box item.
LB_SETCOLUMNWIDTH	Sets the width, in pixels, of all columns in a list box.
LB_SETCOUNT	Sets the number of items in a list box.
LB_SETCURSEL	Selects a given list box item.
LB_SETHORIZONTALEXTENT	Sets the scrollable width, in pixels, of a list box.
LB_SETITEMDATA	Associates a 32-bit value with a list box item.
LB_SETITEMHEIGHT	Sets the height, in pixels, of an item or items in a list box.
LB_SETLOCALE	Sets the locale of a list box and returns the previous locale identifier.
LB_SETSEL	Selects an item in a multiple-selection list box.
LB_SETTABSTOPS	Sets the tab stops to those specified in a given array.
LB_SETTOPINDEX	Scrolls the list box so the specified item is at the top of the visible range.


Default Window-Message Processing

The window procedure for the predefined list box window class carries out default processing for all messages that the list box does not process. When the list box procedure returns FALSE for a message, the predefined window procedure checks the message and performs default actions, as shown in the following table.

Message	Default action
WM_CHAR	Moves the selection to the first item that begins with the character the user typed. If the list box has the LBS_OWNERDRAW style, no action occurs. Multiple characters typed within a short interval are treated as a group, and the first item that begins with that series of characters is selected.
WM_CREATE	Creates an empty list box.
WM_DESTROY	Destroys the list box and frees any resources it uses.
WM_DROPFILES	Passes the message to the dialog box procedure or parent window process.
WM_ENABLE	If the control is visible, invalidates the rectangle so the strings can be painted gray.
WM_ERASEBKGND	Erases the background of a list box. If the list box has the LBS_OWNERDRAW style, the background is not erased.
WM_GETDLGCODE	Returns DLGC_WANTARROWS | DLGC_WANTCHARS, indicating the default list box procedure processes the arrow keys and WM_CHAR messages.
WM_GETFONT	Returns a handle of the current font for the list box.
WM_HSCROLL	Scrolls the list box horizontally.
WM_KEYDOWN	Processes virtual keys for scrolling. The virtual key is the index of the item to move the caret to. The selection is not changed.
WM_KILLFOCUS	Turns the caret off and destroys it. Sends an LBN_KILLFOCUS notification message to the owner of the list box.
WM_LBUTTONDBLCLK	Tracks the mouse in the list box client area. This enables the user to cancel a selection if the mouse button is released outside the list box client area.
WM_LBUTTONDOWN	Tracks the mouse in the list box client area. This enables the user to cancel a selection if the mouse button is released outside the list box client area.
WM_LBUTTONUP	Tracks the mouse in the list box client area. This enables the user to cancel a selection if the mouse button is released outside the list box client area.
WM_MOUSEMOVE	Tracks the mouse in the list box client area. This enables the user to cancel a selection if the mouse button is released outside the list box client area.
WM_PAINT	Performs a subclassed paint operation by using the list box handle of the device context (DC).
WM_SETFOCUS	Turns the caret on and sends an LBN_SETFOCUS notification message to the owner of the list box.
WM_SETFONT	Sets a new font for the list box.
WM_SETREDRAW	Sets or clears the redraw flag based on the value of wParam.
WM_SIZE	Resizes the list box to an integral number of items.
WM_VSCROLL	Scrolls the list box vertically.
The predefined list box procedure passes all other messages to DefWindowProc for default processing.


Using List Boxes

•	Creating a simple list box

•	Creating a directory listing in a single-selection list box

•	Creating a multiple-selection list box

•	Creating an owner-drawn list box


Creating a Simple List Box

The following example demonstrates how a dialog box procedure creates a simple list box and fills it with the names of people on a softball team. When a name in the list is selected, additional information about the player is displayed in the dialog box. The following illustration shows the dialog box.

The list box has the LBS_STANDARD style, a combination of LBS_SORT, LBS_NOTIFY, WS_VSCROLL, and WS_BORDER. The code initializes the dialog box while processing the WM_INITDIALOG message. For each name that appears in the list box, the code sends an LB_ADDSTRING message to the list box. By processing the LBN_SELCHANGE notification message, the code also keeps track of when the selection changes.

#define BUFFER MAX_PATH

#define NAMELENGTH 15

#define POSITIONLENGTH 20

#define TEAMSIZE 15

typedef struct {

    TCHAR tchName[NAMELENGTH];

    TCHAR tchPosition[POSITIONLENGTH];

    int nGamesPlayed;

    int nInningsPlayed;

    double xBattingAverage;

    TCHAR tchFoodName[NAMELENGTH];

} Player;

Player Roster[] = {

        {"Pete", "shortstop", 26, 90, .608, "Rutabaga"},

        {"Suzanna", "catcher", 16, 53, .286, "Toast"},

        {"Jack", "pitcher", 27, 110, .542, "Animal Crackers"},

        {"Karen", "second base", 26, 140, .238, "Pez"},

        {"Dave", "first base", 28, 138, .508, "Suds"},

        {"Wendy", "third base", 25, 154, .493, "Ham"},

        {"Matt", "shortstop", 24, 112, .579, "Oats"},

        {"Jenny", "right field", 22, 101, .509, "Mashed Potatoes"},

        {"Seth", "left-center field", 20, 76, .407, "Otter Pop"},

        {"Kathie", "left field", 26, 127, .353, "Baba Ganouj"},

        {"Colin", "pitcher", 26, 96, .456, "Lefse"},

        {"Penny", "right field", 24, 112, .393, "Zotz"},

        {"Art", "left-center field", 17, 56, .375, "Cannelloni"},

        {"Cindy", "second base", 13, 58, .207, "Tequila"},

        {"David", "center field", 18, 101, .612, "Bok Choy"}

    };

/*

 * FUNCTION: DlgTeamProc(HWND, unsigned, UINT, LONG)

 *

 * PURPOSE:  Dialog box for "BFG Softball Statistics"

 */

BOOL APIENTRY DlgTeamProc(

    HWND hDlg,            /* window handle of dialog box   */

    UINT message,         /* type of message               */

    UINT wParam,          /* message-specific information  */

    LONG lParam)          /* message-specific information  */

{

    TCHAR tchBuffer[BUFFER];

    int nItem;

    int i;

    HWND hwndList;

    switch (message) {

        case WM_INITDIALOG:

        {

            	hwndList = GetDlgItem(hDlg, IDL_SOFTBALL);

            /* Initialize the list box (fill it with player names). */

            for (i = 0; i < TEAMSIZE; i++) {

                SendMessage(hwndList, LB_ADDSTRING, 0,

                    (LPARAM) Roster[i].tchName);

                SendMessage(hwndList, LB_SETITEMDATA, i, (LPARAM) i);

            }

            SetFocus(hwndList);

            return FALSE;

        }

        case WM_COMMAND:

            switch (LOWORD(wParam)) {

                case IDL_SOFTBALL:

                    switch (HIWORD(wParam)) {

                        case LBN_SELCHANGE:

                            /* Show the selected player's statistics. */

                            hwndList = GetDlgItem(hDlg, IDL_SOFTBALL);

                            nItem = SendMessage(hwndList, LB_GETCURSEL,

                                0, 0);

                            i = SendMessage(hwndList, LB_GETITEMDATA,

                                nItem, 0);

                            SetDlgItemText(hDlg, IDS_POS,

                                Roster[i].tchPosition);

                            SetDlgItemText(hDlg, IDS_GAME,

                                _itoa(Roster[i].nGamesPlayed,

                                tchBuffer, 10));

                            SetDlgItemText(hDlg, IDS_INN,

                                _itoa(Roster[i].nInningsPlayed,

                                tchBuffer, 10));

                            SetDlgItemText(hDlg, IDS_BA,

                                _gcvt(Roster[i].xBattingAverage,

                                3, tchBuffer));

                            SetDlgItemText(hDlg, IDS_FOOD,

                                Roster[i].tchFoodName);

                            return TRUE;

                    }

                    break;

                case IDOK:

                case IDCANCEL:

                  /* Destroy the dialog box. */

                  EndDialog(hDlg, TRUE);

                  return TRUE;

                default:

                  return FALSE;

            }

        default:

            return FALSE;

    }

}


Creating a Directory Listing in a Single-Selection List Box

The following example demonstrates how to display the content of the current directory in a list box and enable the user to delete one file at a time.

In addition to the standard list box styles, this list box has the LBS_MULTICOLUMN and LBS_HSCROLL styles. The code initializes the list box by using the DlgDirList function to fill the list box with the names of all the files in the current directory. When the user chooses the Delete button, the DlgDirSelectEx function retrieves the name of the selected file. The code deletes the file by using the DeleteFile function and updates the directory list box by sending the LB_DELETESTRING message.

#define BUFFER MAX_PATH

/*

 * FUNCTION: DlgDelFileProc(HWND, unsigned, UINT, LONG)

 *

 * PURPOSE:  "Delete File" dialog box

 */

BOOL APIENTRY DlgDelFileProc(

    HWND hDlg,            /* window handle of dialog box     */

    UINT message,         /* type of message                 */

    UINT wParam,          /* message-specific information    */

    LONG lParam)

{

    DWORD cchCurDir;

    LPTSTR lpszCurDir;

    LPTSTR lpszFileToDelete;

    int nItem;

    int nTotal;

    TCHAR tchBuffer[BUFFER];

    BOOL fResult;

    switch (message) {

        case WM_INITDIALOG:

            /*

             * Initialize the list box by filling it with files from

             * the current directory.

             */

            lpszCurDir = tchBuffer;

            GetCurrentDirectory(cchCurDir, lpszCurDir);

            DlgDirList(hDlg, lpszCurDir, IDL_FILES, IDS_PATHTOFILL, 0);

            SetFocus(GetDlgItem(hDlg, IDL_FILES));

            return FALSE;

        case WM_COMMAND:

            switch (LOWORD(wParam)) {

                case IDOK:

                    /*

                     * When the user presses the DEL (IDOK) button,

                     * delete the selected file.

                     */

                    lpszFileToDelete = tchBuffer;

                    DlgDirSelectEx(hDlg, lpszFileToDelete, MAX_PATH,

                        IDL_FILES);

                    fResult = DeleteFile(lpszFileToDelete);

                    if (!fResult) {

                        MessageBox(hDlg, "Could not delete file.",

                            NULL, MB_OK);

                    }

                    else {

                        nItem = SendMessage(GetDlgItem(hDlg, IDL_FILES),

                            LB_GETCURSEL, 0, 0);

                        nTotal = SendMessage(GetDlgItem(hDlg,

                            IDL_FILES), LB_DELETESTRING, nItem, 0);

                        /* Update the list box. */

                        if (nTotal > nItem) {

                            SendMessage(GetDlgItem(hDlg, IDL_FILES),

                                LB_SETCURSEL, nItem, 0);

                        }

                        else {

                            SendMessage(GetDlgItem(hDlg, IDL_FILES),

                                LB_SETCURSEL, nTotal, 0);

                        }

                    }

                    return TRUE;

                case IDCANCEL:

                    /* Destroy the dialog box. */

                    EndDialog(hDlg, TRUE);

                    return TRUE;

                default:

                    return FALSE;

            }

        default:

            return FALSE;

    }

}


Creating a Multiple-Selection List Box

The following example displays and initializes the dialog box used in the preceding example. However, this code uses the LBS_MULTIPLESEL style to enable the user to select more than one file at a time. When the user chooses the Delete button, the example sends the LB_GETSELCOUNT message (to retrieve the number of files selected) and the LB_GETSELITEMS message (to retrieve an array of selected list box items). After deleting a file, the code removes the corresponding item from the list box by sending the LB_DELETESTRING message.

#define BUFFER MAX_PATH

#define BIGBUFF 8192

/*

 * FUNCTION: DlgDelFilesProc(HWND, unsigned, UINT, LONG)

 *

 * PURPOSE:  "Delete files" dialog box

 */

BOOL APIENTRY DlgDelFilesProc(

    HWND hDlg,            /* window handle of dialog box  */

    UINT message,         /* type of message              */

    UINT wParam,          /* message-specific information */

    LONG lParam)

{

    DWORD cchCurDir;

    LPTSTR lpszCurDir;

    LPTSTR lpszFileToDelete;

    int nSelItems;

    int nSelItemsInBuffer;

    TCHAR tchBuffer[BUFFER];

    TCHAR tchMsgBuff[BUFFER];

    int nBuffer[BIGBUFF];

    int i;

    BOOL fResult;

    HWND hListBox;

    switch (message) {

        case WM_INITDIALOG:

            /*

             * Initialize the list box by filling it with files from

             * the current directory.

             */

            lpszCurDir = tchBuffer;

            GetCurrentDirectory(cchCurDir, lpszCurDir);

            DlgDirList(hDlg, lpszCurDir, IDL_FILES, IDS_PATHTOFILL, 0);

            SetFocus(GetDlgItem(hDlg, IDL_FILES));

            return FALSE;

        case WM_COMMAND:

            switch (LOWORD(wParam)) {

                case IDOK:

                    /*

                     * When the user presses the Delete (IDOK)

                     * button, delete all the selected files.

                     */

                    lpszFileToDelete = tchBuffer;

                    hListBox = GetDlgItem(hDlg, IDL_FILES);

                    nSelItems = SendMessage(hListBox,

                            LB_GETSELCOUNT, 0, 0);

                    nSelItemsInBuffer = SendMessage(hListBox,

                            LB_GETSELITEMS, 512, (LPARAM) nBuffer);

                    if (nSelItems > nSelItemsInBuffer) {

                        MessageBox(hDlg, "Too many items selected.",

                                NULL, MB_OK);

                    }

                    else {

                        /*

                         * Go through the list backwards because after

                         * deleting an item the indices change for every

                         * subsequent item. By going backward, the

                         * indice are never invalidated.

                         */

                        for (i = nSelItemsInBuffer - 1; i >= 0; i--) {

                            SendMessage(hListBox, LB_GETTEXT,

                                        nBuffer[i],

                                        (LPARAM) lpszFileToDelete);

                            fResult = DeleteFile(lpszFileToDelete);

                            if (!fResult) {

                                sprintf(tchMsgBuff,

                                        "Could not delete file: %s "

                                        "GetLastError = %u",

                                        (LPARAM) lpszFileToDelete);

                                /* Call app-defined error handler. */

                                ErrorHandler(tchMsgBuff);

                            }

                            else {

                                SendMessage(hListBox, LB_DELETESTRING,

                                        nBuffer[i], 0);

                            }

                        }

                        SendMessage(hListBox, LB_SETCARETINDEX, 0, 0);

                    }

                    return TRUE;

                case IDCANCEL:

                    /* Destroy the dialog box. */

                    EndDialog(hDlg, TRUE);

                    return TRUE;

                default:

                    return FALSE;

            }

        default:

                return FALSE;

    }

}


Creating an Owner-Drawn List Box

The following example shows how to draw a list box that contains five owner-drawn items: four drawing implements and a fork. Each list item appears as a bitmap followed by the name of the object. A button prompts the user to select one item that is not like the others. Choosing the button with the fork selected displays a "You're right!" message and closes the dialog box. Choosing the button with any other list item selected displays a "Try again!" message.

The list box has the LBS_OWNERDRAW and LBS_HASSTRINGS styles, in addition to the standard list box styles. The code initializes the list box by sending the LB_ADDSTRING message to set the text, and then sends the LB_SETITEMDATA message to associate a bitmap with each list box item. The code also sets the height of each list box item by processing the WM_MEASUREITEM message and draws the text and bitmap for each item by processing the WM_DRAWITEM message.

#define XBITMAP 80

#define YBITMAP 20

#define BUFFER MAX_PATH

HBITMAP hbmpPencil, hbmpCrayon, hbmpMarker, hbmpPen, hbmpFork;

HBITMAP hbmpPicture, hbmpOld;

void AddItem(HWND hwnd, LPSTR lpstr, HBITMAP hbmp)

{

    int nItem;

    nItem = SendMessage(hwndList, LB_ADDSTRING, 0, lpstr);

    SendMessage(hwndList, LB_SETITEMDATA, nItem, hbmp);

}

DWORD APIENTRY DlgDrawProc(

        HWND hDlg,            /* window handle of dialog box     */

        UINT message,         /* type of message                 */

        UINT wParam,          /* message-specific information    */

        LONG lParam)

{

    int nItem;

    TCHAR tchBuffer[BUFFER];

    HBITMAP hbmp;

    HWND hListBox;

    TEXTMETRIC tm;

    int y;

    HDC hdcMem;

    LPMEASUREITEMSTRUCT lpmis;

    LPDRAWITEMSTRUCT lpdis;

    RECT rcBitmap;

    switch (message) {

        case WM_INITDIALOG:

            /* Load bitmaps. */

            hbmpPencil = LoadBitmap(hinst, MAKEINTRESOURCE(700));

            hbmpCrayon = LoadBitmap(hinst, MAKEINTRESOURCE(701));

            hbmpMarker = LoadBitmap(hinst, MAKEINTRESOURCE(702));

            hbmpPen = LoadBitmap(hinst, MAKEINTRESOURCE(703));

            hbmpFork = LoadBitmap(hinst, MAKEINTRESOURCE(704));

            /* Retrieve list box handle. */

            hListBox = GetDlgItem(hDlg, IDL_STUFF);

            /*

             * Initialize the list box text and associate a bitmap

             * with each list box item.

             */

            AddItem(hListBox, "pencil", hbmpPencil);

            AddItem(hListBox, "crayon", hbmpCrayon);

            AddItem(hListBox, "marker", hbmpMarker);

            AddItem(hListBox, "pen",    hbmpPen);

            AddItem(hListBox, "fork",   hbmpFork);

            SetFocus(hListBox);

            SendMessage(hListBox, LB_SETCURSEL, 0, 0);

            return TRUE;

        case WM_MEASUREITEM:

            lpmis = (LPMEASUREITEMSTRUCT) lParam;

            /* Set the height of the list box items. */

            lpmis->itemHeight = 20;

            return TRUE;

        case WM_DRAWITEM:

            lpdis = (LPDRAWITEMSTRUCT) lParam;

            /* If there are no list box items, skip this message. */

            if (lpdis->itemID == -1) {

                break;

            }

            /*

             * Draw the bitmap and text for the list box item. Draw a

             * rectangle around the bitmap if it is selected.

             */

            switch (lpdis->itemAction) {

                case ODA_SELECT:

                case ODA_DRAWENTIRE:

                    /* Display the bitmap associated with the item. */

                    hbmpPicture = (HBITMAP) SendMessage(lpdis->hwndItem,

                        LB_GETITEMDATA, lpdis->itemID, (LPARAM) 0);

                    hdcMem = CreateCompatibleDC(lpdis->hDC);

                    hbmpOld = SelectObject(hdcMem, hbmpPicture);

                    BitBlt(lpdis->hDC,

                        lpdis->rcItem.left, lpdis->rcItem.top,

                        lpdis->rcItem.right - lpdis->rcItem.left,

                        lpdis->rcItem.bottom - lpdis->rcItem.top,

                        hdcMem, 0, 0, SRCCOPY);

                    /* Display the text associated with the item. */

                    SendMessage(lpdis->hwndItem, LB_GETTEXT,

                        lpdis->itemID, (LPARAM) tchBuffer);

                    GetTextMetrics(lpdis->hDC, &tm);

                    y = (lpdis->rcItem.bottom + lpdis->rcItem.top -

                        tm.tmHeight) / 2;

                    TextOut(lpdis->hDC,

                        XBITMAP + 6,

                        y,

                        tchBuffer,

                        strlen(tchBuffer));

                    SelectObject(hdcMem, hbmpOld);

                    DeleteDC(hdcMem);

                    /* Is the item selected? */

                    if (lpdis->itemState & ODS_SELECTED) {

                        /*

                         * Set RECT coordinates to surround only the

                         * bitmap.

                         */

                        rcBitmap.left = lpdis->rcItem.left;

                        rcBitmap.top = lpdis->rcItem.top;

                        rcBitmap.right = lpdis->rcItem.left + XBITMAP;

                        rcBitmap.bottom = lpdis->rcItem.top + YBITMAP;

                        /*

                         * Draw a rectangle around bitmap to indicate

                         * the selection.

                         */

                        DrawFocusRect(lpdis->hDC, &rcBitmap);

                    }

                    break;

                case ODA_FOCUS:

                    /*

                     * Do not process focus changes. The focus caret

                     * (outline rectangle) indicates the selection.

                     * The Which one? (IDOK) button indicates the final

                     * selection.

                     */

                    break;

            }

            return TRUE;

        case WM_COMMAND:

            switch (LOWORD(wParam)) {

                case IDOK:

                    /* Get the selected item's text. */

                    nItem = SendMessage(GetDlgItem(hDlg, IDL_STUFF),

                        LB_GETCURSEL, 0, (LPARAM) 0);

                        hbmp = SendMessage(GetDlgItem(hDlg, IDL_STUFF),

                            LB_GETITEMDATA, nItem, 0);

                    /*

                     * If the item is not the correct answer, tell the

                     * user to try again.

                     *

                     * If the item is the correct answer, congratulate

                     * the user and destroy the dialog box.

                     */

                    if (hbmp != hbmpFork) {

                        MessageBox(hDlg, "Try again!", "Oops.", MB_OK);

                        return FALSE;

                    }

                    else {

                        MessageBox(hDlg, "You're right!",

                            "Congratulations.", MB_OK);

                      /* Fall through. */

                    }

                case IDCANCEL:

                    /* Destroy the dialog box. */

                    EndDialog(hDlg, TRUE);

                    return TRUE;

                default:

                    return FALSE;

            }

        case WM_DESTROY:

            /* Free any resources used by the bitmaps. */

            DeleteObject(hbmpPencil);

            DeleteObject(hbmpCrayon);

            DeleteObject(hbmpMarker);

            DeleteObject(hbmpPen);

            DeleteObject(hbmpFork);

            return TRUE;

        default:

            return FALSE;

    }

    return FALSE;

}


List Box Reference

The following functions and messages are associated with list boxes.


List Box Functions

Following are the functions used with list boxes.

DlgDirList
DlgDirSelectEx


List Box Messages

Following are the messages used with list boxes.

LB_ADDFILE
LB_ADDSTRING
LB_DELETESTRING
LB_DIR
LB_FINDSTRING
LB_FINDSTRINGEXACT
LB_GETANCHORINDEX
LB_GETCARETINDEX
LB_GETCOUNT
LB_GETCURSEL
LB_GETHORIZONTALEXTENT
LB_GETITEMDATA
LB_GETITEMHEIGHT
LB_GETITEMRECT
LB_GETLOCALE
LB_GETSEL
LB_GETSELCOUNT
LB_GETSELITEMS
LB_GETTEXT
LB_GETTEXTLEN
LB_GETTOPINDEX
LB_INSERTSTRING
LB_RESETCONTENT
LB_SELECTSTRING
LB_SELITEMRANGE
LB_SELITEMRANGEEX
LB_SETANCHORINDEX
LB_SETCARETINDEX
LB_SETCOLUMNWIDTH
LB_SETCOUNT
LB_SETCURSEL
LB_SETHORIZONTALEXTENT
LB_SETITEMDATA
LB_SETITEMHEIGHT
LB_SETLOCALE
LB_SETSEL
LB_SETTABSTOPS
LB_SETTOPINDEX
LBN_DBLCLK
LBN_ERRSPACE
LBN_KILLFOCUS
LBN_SELCANCEL
LBN_SELCHANGE
LBN_SETFOCUS
WM_CHARTOITEM
WM_DELETEITEM
WM_VKEYTOITEM


Scroll Bars

A window in an application written for Microsoft® Windows® can display a data object, such as a document or a bitmap, that is larger than the window's client area. When provided with a scroll bar, the user can scroll a data object in the client area to bring into view the portions of the object that extend beyond the borders of the window.


About Scroll Bars

Scroll bars should be included in any window for which the content of the client area extends beyond the window's borders. A scroll bar's orientation determines the direction in which scrolling occurs when the user operates the scroll bar. A horizontal scroll bar enables the user to scroll the content of a window to the left or right. A vertical scroll bar enables the user to scroll the content up or down.


Parts of a Scroll Bar

A scroll bar consists of a shaded shaft with an arrow button at each end and a scroll box (sometimes called a thumb) between the arrow buttons. A scroll bar represents the overall length or width of a data object in a window's client area; the scroll box represents the portion of the object that is visible in the client area. The position of the scroll box changes whenever the user scrolls a data object to display a different portion of it. In version 4.0 or later, Windows also adjusts the size of a scroll bar's scroll box so that it indicates what portion of the entire data object is currently visible in the window. If most of the object is visible, the scroll box occupies most of the scroll bar's shaft. Similarly, if only a small portion of the object is visible, the scroll box occupies a small part of the shaft.

The user scrolls the content of a window by clicking one of the arrow buttons, by clicking the area in the shaded shaft, or by dragging the scroll box. When the user clicks an arrow button, the application scrolls the content by one unit (typically a single line or column). When the user clicks the shaded areas, the application scrolls the content by one window. The amount of scrolling that occurs when the user drags the scroll box depends on the distance the user drags the scroll box and on the scrolling range of the scroll bar. For more information about the scrolling range, see Scroll Box Position and Scrolling Range.


Standard Scroll Bars and Scroll Bar Controls

A scroll bar is included in a window either as a standard scroll bar or as a scroll bar control. A standard scroll bar is located in the nonclient area of a window. It is created with the window and displayed when the window is displayed. The sole purpose of a standard scroll bar is to enable the user to generate scrolling requests for viewing the entire content of the client area. You can include a standard scroll bar in a window by specifying WS_HSCROLL, WS_VSCROLL, or both styles when you create the window. The WS_HSCROLL style creates a horizontal scroll bar positioned at the bottom of the client area. The WS_VSCROLL style creates a vertical scroll bar positioned at the right of the client area. The SM_CXHSCROLL and SM_CYHSCROLL system metric values define the width and height of a standard horizontal scroll bar. The SM_CXVSCROLL and SM_CYVSCROLL values define the width and height of a standard vertical scroll bar.

A scroll bar control is a control window that belongs to the SCROLLBAR window class. A scroll bar control appears and functions like a standard scroll bar, but it is a separate window. As a separate window, a scroll bar control receives direct input focus, indicated by a flashing caret displayed in the scroll box. Unlike a standard scroll bar, a scroll bar control also has a built-in keyboard interface that enables the user to direct scrolling. You can use as many scroll bar controls as needed in a single window. When you create a scroll bar control, you must specify the scroll bar's size and position. However, if a scroll bar control's window can be resized, adjustments to the scroll bar's size must be made whenever the size of the window changes.

The advantage of using a standard scroll bar is that Windows creates the scroll bar and automatically sets its size and position. However, standard scroll bars are sometimes too restrictive. For example, suppose that you want to divide a client area into quadrants and use a separate set of scroll bars to control the content of each quadrant. You cannot use standard scroll bars because you can only create one set of scroll bars for a particular window. Use scroll bar controls instead, because you can add as many of them to a window as you want.

Applications can provide scroll bar controls for purposes other than scrolling the content of a window. For example, a screen saver application might provide a scroll bar for setting the speed at which graphics are moved about on the screen.

A scroll bar control can have a number of styles that serves to control the orientation and position of the scroll bar. You specify the styles that you want when you call the CreateWindowEx function to create a scroll bar control. Some of the styles create a scroll bar control that uses a default width or height. However, you must always specify the x- and y-coordinates and the other dimensions of the scroll bar. Following are the scroll bar control styles.

Style	Meaning
SBS_BOTTOMALIGN
	Aligns the bottom edge of the scroll bar with the bottom edge of the rectangle defined by the CreateWindowEx parameters x, y, nWidth, and nHeight. The scroll bar has the default height for system scroll bars. Use this style with the SBS_HORZ style.
SBS_HORZ
	Designates a horizontal scroll bar. If neither the SBS_BOTTOMALIGN nor SBS_TOPALIGN style is specified, the scroll bar has the height, width, and position specified by the parameters of CreateWindowEx.
SBS_LEFTALIGN
	Aligns the left edge of the scroll bar with the left edge of the rectangle defined by the parameters of CreateWindowEx. The scroll bar has the default width for system scroll bars. Use this style with the SBS_VERT style.
SBS_RIGHTALIGN
	Aligns the right edge of the scroll bar with the right edge of the rectangle defined by the parameters of CreateWindowEx. The scroll bar has the default width for system scroll bars. Use this style with the SBS_VERT style.
SBS_SIZEBOX
	Designates a size box. If you specify neither the SBS_SIZEBOXBOTTOMRIGHTALIGN nor the SBS_SIZEBOXTOPLEFTALIGN style, the size box has the height, width, and position specified by the parameters of CreateWindowEx.
SBS_SIZEBOXBOTTOMRIGHTALIGN
	Aligns the lower right corner of the size box with the lower right corner of the rectangle specified by the parameters of CreateWindowEx. The size box has the default size for system size boxes. Use this style with the SBS_SIZEBOX style.
SBS_SIZEBOXTOPLEFTALIGN
	Aligns the upper left corner of the size box with the upper left corner of the rectangle specified by the parameters of CreateWindowEx. The size box has the default size for system size boxes. Use this style with the SBS_SIZEBOX style.
SBS_SIZEGRIP
	Same as SBS_SIZEBOX, but with a raised edge (version 4.0 or later).
SBS_TOPALIGN
	Aligns the top edge of the scroll bar with the top edge of the rectangle defined by the parameters of CreateWindowEx. The scroll bar has the default height for system scroll bars. Use this style with the SBS_HORZ style.
SBS_VERT
	Designates a vertical scroll bar. If you specify neither the SBS_RIGHTALIGN nor the SBS_LEFTALIGN style, the scroll bar has the height, width, and position specified by the parameters of CreateWindowEx.


Scroll Box Position and Scrolling Range

The position of the scroll box is represented as an integer; it is relative to the left or upper end of the scroll bar, depending on whether the scroll bar is horizontal or vertical. The position must be within the minimum and maximum values of the scrolling range. For example, in a scroll bar with a range of 0 through 100, position 50 is in the middle, with the remaining positions distributed equally along the scroll bar. The initial range depends on the scroll bar. Standard scroll bars have an initial range of 0 through 100; scroll bar controls have an empty range (both minimum and maximum values are zero), unless you supply an explicit range when the control is created. You can change the range at any time. With operating system version 4.0 or later, you can use the SetScrollInfo function to set the range values, and the GetScrollInfo function to retrieve the current range values. In versions earlier than 4.0, you can use the SetScrollRange and GetScrollRange functions.

An application typically adjusts the scroll range to convenient integers, making it easy to translate the scroll box position into a value corresponding to the data object to be scrolled. For example, if an application must display 260 lines of a text file in a window that can show only 16 lines at a time, the vertical scroll bar range can be set to 1 through 244. If the scroll box is at position 1, the first line will be at the top of the window. If the scroll box is at position 244, the last line (line 260) will be at the bottom of the window. If an application attempts to specify a position value that is less than the minimum or more than the maximum, the minimum or maximum scrolling range value is used instead.

In version 4.0 or later, an application can set a page size for a scroll bar. The page size represents the number of data units that can fit in the client area of the owner window given its current size. For example, if the client area can hold 16 lines of text, an application would set the page size to 16. Windows uses the page size, along with the scrolling range and length of the scroll shaft, to set the size of the scroll box. Whenever a window containing a scroll bar is resized, an application should call the SetScrollInfo function to set the page size. An application can retrieve the current page size by calling the sending GetScrollInfo function.

To establish a useful relationship between the scroll bar range and the data object, an application must adjust the range whenever the size of the data object changes.

As the user moves the scroll box in a scroll bar, the scroll bar reports the scroll box position as an integer in the scrolling range. If the position is the minimum value, the scroll box is at the top of a vertical scroll bar or at the left end of a horizontal scroll bar. If the position is the maximum value, the scroll box is at the bottom of a vertical scroll bar or at right end of a horizontal scroll bar.

In version 4.0 or later, the maximum value that a scroll bar can report (that is, the maximum scrolling position) depends on the page size. If the scroll bar has a page size greater than one, the maximum scrolling position is less than the maximum range value. You can use the following formula to calculate the maximum scrolling position:

MaxScrollPos = MaxRangeValue - (PageSize - 1)

An application must move the scroll box in a scroll bar. Although the user makes a request for scrolling in a scroll bar, the scroll bar does not automatically update the scroll box position. Instead, it passes the request to the parent window, which must scroll the data and update the scroll box position. In version 4.0 or later, an application uses the SetScrollInfo function to update the scroll box position; otherwise, it uses the SetScrollPos function. Because it controls the scroll box movement, the application can move the scroll box in increments that work best for the data being scrolled.


Scroll Bar Visibility

The system hides and disables a standard scroll bar when equal minimum and maximum values are specified. With version 4.0 or later, the system also hides and disables a standard scroll bar if you specify a page size that includes the entire scroll range of the scroll bar. This is the way to temporarily hide a scroll bar when it is not needed for the content of the client area. There is no need to make scrolling requests through the scroll bar when it is hidden. The system enables the scroll bar and shows it again when you set the minimum and maximum values to unequal values or, in version 4.0 or later, when the page size that does not include the entire scroll range. The ShowScrollBar function can also be used to hide or show a scroll bar. It does not affect the scroll bar's range, page size, or scroll box position.

The EnableScrollBar function can be used to disable one or both arrows of a scroll bar. An application displays disabled arrows in gray and does not respond to user input.


Scroll Bar Requests

The user makes scrolling requests by clicking various parts of a scroll bar. Windows sends the request to the given window in the form of a WM_HSCROLL or WM_VSCROLL message. A horizontal scroll bar sends the WM_HSCROLL message; a vertical scroll bar sends the WM_VSCROLL message. Each message includes a notification code that corresponds to the user's action, to the handle of the scroll bar (scroll bar controls only), and, in some cases, to the position of the scroll box.

The following figure shows the notification messages that the user generates when clicking various parts of a scroll bar.

The scroll bar notification codes specify the action the user takes. An application examines the codes that accompany the WM_HSCROLL and WM_VSCROLL messages and then performs the appropriate scrolling operation. In the following table of notification messages, the user's action is specified for each message, followed by the application's response. In each case, a unit is defined by the application as appropriate for the given data. For example, the typical unit for scrolling text vertically is a line of text.

Notification  message	Action	Response
SB_LINEUP	The user clicks the top scroll arrow.	Decrements the scroll box position; scrolls toward the top of the data by one unit.
SB_LINEDOWN	The user clicks the bottom scroll arrow.	Increments the scroll box position; scrolls toward the bottom of the data by one unit.
SB_LINELEFT	The user clicks the left scroll arrow.	Decrements the scroll box position; scrolls toward the left end of the data by one unit.
SB_LINERIGHT	The user clicks the right scroll arrow.	Increments the scroll box position; scrolls toward the right end of the data by one unit.
SB_PAGEUP	The user clicks the scroll bar shaft above the scroll box.	Decrements the scroll box position by the number of data units in the window; scrolls toward the top of the data by the same number of units.
SB_PAGEDOWN	The user clicks the scroll bar shaft below the scroll box.	Increments the scroll box position by the number of data units in the window; scrolls toward the bottom of the data by the same number of units.
SB_PAGELEFT	The user clicks the scroll bar shaft to the left of the scroll box.	Decrements the scroll box position by the number of data units in the window; scrolls toward the left end of the data by the same number of units.
SB_PAGERIGHT	The user clicks the scroll bar shaft to the right of the scroll box.	Increments the scroll box position by the number of data units in the window; scrolls toward the right end of the data by the same number of units.
SB_THUMBPOSITION	The user releases the scroll box after dragging it.	Sets the scroll box to the position given in the message; scrolls the data by the same number of units the scroll box has moved.
SB_THUMBTRACK	The user drags the scroll box.	Sets the scroll box to the position given in the message and scrolls the data by the same number of units the scroll box has moved for applications that draw data quickly. Applications that cannot draw data quickly must wait for the SB_THUMBPOSITION message before moving the scroll box and scrolling the data.
SB_ENDSCROLL	The user releases the mouse after holding it on an arrow or in the scroll bar shaft.	No response is needed.
A scroll bar generates the SB_THUMBPOSITION and SB_THUMBTRACK notification messages when the user clicks and drags the scroll box. An application should be programmed to process either the SB_THUMBTRACK or the SB_THUMBPOSITION notification message.

The SB_THUMBPOSITION notification message occurs when the user releases the mouse button after clicking the scroll box. An application that processes this message performs the scrolling operation after the user has dragged the scroll box to the desired position and released the mouse button.

SB_THUMBTRACK notification messages occur as the user drags the scroll box. If an application processes SB_THUMBTRACK messages, it can scroll the content of a window as the user drags the scroll box. However, a scroll bar can generate many SB_THUMBTRACK notification messages in a short period, so an application should process these messages only if it can quickly repaint the content of the window.


Keyboard Interface for a Scroll Bar

A scroll bar control provides a built-in keyboard interface that enables the user to issue scrolling requests by using the keyboard; a standard scroll bar does not. When a scroll bar control has the keyboard focus, it sends WM_HSCROLL and WM_VSCROLL messages to its parent window when the user presses the arrow keys. The notification message is sent with each message corresponding to the arrow key the user has pressed. Following are the arrow keys and their corresponding notification messages.

Arrow key	Notification message
DOWN	SB_LINEDOWN or SB_LINERIGHT
END	SB_BOTTOM
HOME	SB_TOP
LEFT	SB_LINEUP or SB_LINELEFT
PGDN	SB_PAGEDOWN or SB_PAGERIGHT
PGUP	SB_PAGEUP or SB_PAGELEFT
RIGHT	SB_LINEDOWN or SB_LINERIGHT
UP	SB_LINEUP or SB_LINELEFT
Note that the keyboard interface of a scroll bar control sends the SB_TOP and SB_BOTTOM notification messages. The SB_TOP message indicates that the user has reached the top value of the scrolling range. An application scrolls the window content downward so that the top of the data object is visible. The SB_BOTTOM message indicates that the user has reached the bottom value of the scrolling range. If an application processes the SB_BOTTOM message, it scrolls the window content upward so that the bottom of the data object is visible.

If you want a keyboard interface for a standard scroll bar, you can create one yourself by processing the WM_KEYDOWN message in your window procedure and then performing the appropriate scrolling action based on the virtual-key code that accompanies the message. For information about how to create a keyboard interface for a scroll bar, see Creating a Keyboard Interface for a Standard Scroll Bar.


Scrolling the Client Area

The simplest way to scroll the content of a client area is to erase and then redraw it. This is the method an application is likely to use with SB_PAGEUP, SB_PAGEDOWN, and SB_TOP notification messages, which typically require completely new content.

For some notification messages, such as SB_LINEUP and SB_LINEDOWN, not all the content need be erased, because some remains visible after scrolling occurs. The ScrollWindowEx function preserves a portion of the client area's content, move the preserved portion a specified amount, and then prepares the rest of the client area for painting new information. ScrollWindowEx uses the BitBlt function to move a specific part of the data object to a new location within the client area. Any uncovered part of the client area (anything not preserved) is invalidated, erased, and painted when the next WM_PAINT message occurs.

The ScrollWindowEx function can be used to exclude a portion of the client area from the scrolling operation. This keeps items with fixed positions, such as child windows, from moving within the client area. It automatically invalidates the portion of the client area that is to receive the new information, so the application does not have to compute its own clipping regions. For more information on clipping, see Clipping.

Usually an application scrolls the content of a window in the direction opposite that indicated by the scroll bar. For example, when the user clicks the shaft in the area below the scroll box, an application scrolls the object in the window upward to reveal a portion of the object that is below the visible portion.


Scroll Bar Colors and Metrics

The system-defined color value, COLOR_SCROLLBAR, controls the color within a scroll bar's shaft. Use the GetSysColor function to determine the color of the shaft and the SetSysColors function to set the color of the shaft. Note, however, that this change of color affects all scroll bars in the system.

You can get the dimensions of the bitmaps that Windows uses in standard scroll bars by calling the GetSystemMetrics function. Following are the system metric values associated with scroll bars.

System metric	Description
SM_CXHSCROLL	Width of arrow bitmap on horizontal scroll bar
SM_CXHTHUMB	Width of scroll box on horizontal scroll bar. In version 4.0 or later, this value retrieves the width a scroll bar that has a page size of zero.
SM_CXVSCROLL	Width of arrow bitmap on vertical scroll bar
SM_CYHSCROLL	Height of arrow bitmap on horizontal scroll bar
SM_CYVSCROLL	Height of arrow bitmap on vertical scroll bar
SM_CYVTHUMB	Height of scroll box on vertical scroll bar. In version 4.0 or later, this value retrieves the height of a scroll bar that has a page size of zero.


Using Scroll Bars

•	Creating scroll bars

•	Scrolling text

•	Scrolling a bitmap

•	Creating a keyboard interface for a standard scroll bar

Note  The examples in this section set the scroll range, scroll position, and page size by using SetScrollInfo function, which is available only with version 4.0 and later. For operating system versions earlier than 4.0, use the SetScrollRange and SetScrollPos functions.


Creating Scroll Bars

When creating an overlapped, pop-up, or child window, you can add standard scroll bars by using the CreateWindowEx function and specifying WS_HSCROLL, WS_VSCROLL, or both styles. Doing this adds a horizontal or vertical scroll bar, or both, to the window. The following example creates a window with standard horizontal and vertical scroll bars.

hwnd = CreateWindowEx(

    0L,                          /* no extended styles        */

    "MyAppClass",                /* window class              */

    "Scroll Bar Application",    /* text for window title bar */

    WS_OVERLAPPEDWINDOW |        /* window styles             */

        WS_HSCROLL |

        WS_VSCROLL,

    CW_USEDEFAULT,             /* default horizontal position */

    CW_USEDEFAULT,             /* default vertical position   */

    CW_USEDEFAULT,             /* default width               */

    CW_USEDEFAULT,             /* default height              */

    (HWND) NULL,         /* no parent for overlapped windows  */

    (HMENU) NULL,        /* window class menu                 */

    hinst,               /* instance owning this window       */

    (LPVOID) NULL        /* pointer not needed                */

);

To process scroll bar messages for these scroll bars, you must include appropriate code in the main window procedure.

When using the CreateWindowEx function to create a window, you can add a scroll bar control by specifying the SCROLLBAR window class. This creates a horizontal or vertical scroll bar, depending on whether SBS_HORZ or SBS_VERT is specified as the window style. The scroll bar size and its position relative to its parent window can also be specified. The following example creates a horizontal scroll bar control and positions it in the upper right corner of the window.

hwndScroll = CreateWindowEx(

    0L,                          /* no extended styles        */

    "SCROLLBAR",                 /* scroll bar control class  */

    (LPSTR) NULL,                /* text for window title bar */

    WS_CHILD | SBS_HORZ,         /* scroll bar styles         */

    0,                           /* horizontal position       */

    0,                           /* vertical position         */

    200,                         /* width of the scroll bar   */

    CW_USEDEFAULT,               /* default height            */

    hwnd,                   /* handle of main window          */

    (HMENU) NULL,           /* no menu for a scroll bar       */

    hinst,                  /* instance owning this window    */

    (LPVOID) NULL           /* pointer not needed             */

);


Scrolling Text

This section describes the changes you can make to an application's main window procedure to enable a user to scroll text. The example in Example of Scrolling Text creates and displays an array of text strings and processes WM_HSCROLL and WM_VSCROLL messages generated by the scroll bars so that the user can scroll text both vertically and horizontally.


Scrolling Text with the WM_CREATE Message

Scrolling units are typically set while processing the WM_CREATE message. It is convenient to base the scrolling units on the dimensions of the font associated with the window's display context (DC). To retrieve the font dimensions for a specific DC, use the GetTextMetrics function.

In the example in Example of Scrolling Text, one vertical scrolling unit is equivalent to the height of a character cell, plus external leading. One horizontal scrolling unit is equivalent to the average width of a character cell. The horizontal scrolling positions, therefore, do not correspond to actual characters, unless the screen font is fixed-width.


Scrolling Text with the WM_SIZE Message

When processing the WM_SIZE message, it is convenient to adjust the scrolling range and scrolling position to reflect the dimensions of the client area as well as the number of lines of text that will be displayed.

The SetScrollInfo function sets the minimum and maximum position values, the page size, and the scrolling position for a scroll bar. For versions earlier than 4.0, use the SetScrollRange function to set the minimum and maximum position values, and the SetScrollPos function to adjust the scroll box to reflect the scrolling position.


Scrolling Text with the WM_HSCROLL and WM_VSCROLL Messages

The scroll bar sends WM_HSCROLL and WM_VSCROLL messages to the window procedure whenever the user clicks the scroll bar or drags the scroll box. The low-order words of WM_VSCROLL and WM_HSCROLL each contain a notification message that indicates the direction and magnitude of the scrolling action.

When the WM_HSCROLL and WM_VSCROLL messages are processed, the scroll bar notification message is examined and the scrolling increment is calculated. After the increment is applied to the current scrolling position, the window is scrolled to the new position by using the ScrollWindowEx function, and the position of the scroll box is adjusted by using the SetScrollInfo function. For operating system versions earlier than 4.0, use the SetScrollPos function to adjust the scroll box position.

After a window is scrolled, part of its client area is made invalid. To ensure that the invalid region is updated, the UpdateWindow function is used to generate a WM_PAINT message.


Scrolling Text with the WM_PAINT Message

When processing the WM_PAINT message, it is convenient to draw the lines of text that you want to appear in the invalid portion of the window. The example in the following section uses the current scrolling position and the dimensions of the invalid region to determine the range of lines within the invalid region to display them.


Example of Scrolling Text

The following example shows how to have your application scroll text in response to input from the horizontal and vertical scroll bars.

HDC hdc;

PAINTSTRUCT ps;

TEXTMETRIC tm;

SCROLLINFO si;

/* These variables are required to display text. */

static int xClient;     /* width of client area                  */

static int yClient;     /* height of client area                 */

static int xClientMax;  /* maximum width of client area          */

static int xChar;       /* horizontal scrolling unit             */

static int yChar;       /* vertical scrolling unit               */

static int xUpper;      /* average width of uppercase letters    */

static int xPos;        /* current horizontal scrolling position */

static int yPos;        /* current vertical scrolling position   */

static int xMax;        /* maximum horiz. scrolling position     */

static int yMax;        /* maximum vert. scrolling position      */

int xInc;               /* horizontal scrolling increment        */

int yInc;               /* vertical scrolling increment          */

int i;                  /* loop counter                          */

int x, y;               /* horiz. and vert. printing coords      */

int FirstLine;          /* first line in the invalidated area    */

int LastLine;           /* last line in the invalidated area     */

/* Create an array of lines to display. */

#define LINES 27

static char *abc[] = { "anteater", "bear", "cougar", "dingo",

  "elephant", "frog", "gazelle", "hyena", "iguana", "jackal",

  "kangaroo", "llama", "moose", "newt", "octopus", "penguin",

  "quail", "rat", "squid", "tortoise", "urus", "vole",

  "walrus", "xylophone", "yak", "zebra",

  "This line contains many words, but no character. Go figure." };

switch (uMsg) {

    case WM_CREATE :

        /* Get the handle of the client area's device context. */

        hdc = GetDC (hwnd);

        /* Extract font dimensions from the text metrics. */

        GetTextMetrics (hdc, &tm);

        xChar = tm.tmAveCharWidth;

        xUpper = (tm.tmPitchAndFamily & 1 ? 3 : 2) * xChar/2;

        yChar = tm.tmHeight + tm.tmExternalLeading;

        /* Free the device context. */

        ReleaseDC (hwnd, hdc);

        /*

         * Set an arbitrary maximum width for client area.

         * (xClientMax is the sum of the widths of 48 average

         * lowercase letters and 12 uppercase letters.)

         */

        xClientMax = 48 * xChar + 12 * xUpper;

        return 0;

    case WM_SIZE:

        /* Retrieve the dimensions of the client area. */

        yClient = HIWORD (lParam);

        xClient = LOWORD (lParam);

        /*

         * Determine the maximum vertical scrolling position.

         * The two is added for extra space below the lines

         * of text.

         */

        yMax = max (0, LINES + 2 - yClient/yChar);

        /*

         * Make sure the current vertical scrolling position

         * does not exceed the maximum.

         */

        yPos = min (yPos, yMax);

        /*

         * Adjust the vertical scrolling range and scroll box

         * position to reflect the new yMax and yPos values.

         */

        si.cbSize = sizeof(si);

        si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS;

        si.nMin   = 0;

        si.nMax   = yMax;

        si.nPage  = yClient / yChar;

        si.nPos   = yPos;

        SetScrollInfo(hwnd, SB_VERT, &si, TRUE);

        /*

         * Determine the maximum horizontal scrolling position.

         * The two is added for extra space to the right of the

         * lines of text.

         */

        xMax = max (0, 2 + (xClientMax - xClient)/xChar);

        /*

         * Make sure the current horizontal scrolling position

         * does not exceed the maximum.

         */

        xPos = min (xPos, xMax);

        /*

         * Adjust the horizontal scrolling range and scroll box

         * position to reflect the new xMax and xPos values.

         */

        si.cbSize = sizeof(si);

        si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS;

        si.nMin   = 0;

        si.nMax   = xMax;

        si.nPage  = xClient / xChar;

        si.nPos   = xPos;

        SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);

        return 0;

    case WM_PAINT:

        /* Prepare the window for painting. */

        hdc = BeginPaint(hwnd, &ps);

        /*

         * Use the current vertical scrolling position and

         * coordinates of the invalid rectangle to determine

         * the range of new lines that should be drawn in the

         * client area.

         */

        FirstLine = max (0, yPos + ps.rcPaint.top/yChar - 1);

        LastLine = min (LINES, yPos + ps.rcPaint.bottom/yChar);

        /* Display these lines. */

        for (i = FirstLine;i < LastLine;i++) {

            x = xChar * (1 - xPos);

            y = yChar * (1 - yPos + i);

            TextOut (hdc, x, y, abc[i], lstrlen(abc[i]));

            }

        /* Indicate that painting is finished. */

        EndPaint(hwnd, &ps);

        break;

    case WM_HSCROLL:

        switch(LOWORD (wParam)) {

            /* User clicked shaft left of the scroll box. */

            case SB_PAGEUP:

                 xInc = -8;

                 break;

            /* User clicked shaft right of the scroll box. */

            case SB_PAGEDOWN:

                 xInc = 8;

                 break;

            /* User clicked the left arrow. */

            case SB_LINEUP:

                 xInc = -1;

                 break;

            /* User clicked the right arrow. */

            case SB_LINEDOWN:

                 xInc = 1;

                 break;

            /* User dragged the scroll box. */

            case SB_THUMBTRACK:

                 xInc = HIWORD(wParam) - xPos;

                 break;

            default:

                 xInc = 0;

        }

        /*

         * If applying the horizontal scrolling increment does not

         * take the scrolling position out of the scrolling range,

         * increment the scrolling position, adjust the position

         * of the scroll box, and update the window.

         */

        if (xInc = max (-xPos, min (xInc, xMax - xPos))) {

            xPos += xInc;

            ScrollWindowEx (hwnd, -xChar * xInc, 0,

                (CONST RECT *) NULL, (CONST RECT *) NULL,

                (HRGN) NULL, (LPRECT) NULL, SW_INVALIDATE);

            si.cbSize = sizeof(si);

            si.fMask  = SIF_POS;

            si.nPos   = xPos;

            SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);

            UpdateWindow (hwnd);

        }

        return 0;

    case WM_VSCROLL:

            switch(LOWORD (wParam)) {

            /* User clicked the shaft above the scroll box. */

            case SB_PAGEUP:

                 yInc = min(-1, -yClient / yChar);

                 break;

            /* User clicked the shaft below the scroll box. */

            case SB_PAGEDOWN:

                 yInc = max(1, yClient / yChar);

                 break;

            /* User clicked the top arrow. */

            case SB_LINEUP:

                 yInc = -1;

                 break;

            /* User clicked the bottom arrow. */

            case SB_LINEDOWN:

                 yInc = 1;

                 break;

            /* User dragged the scroll box. */

            case SB_THUMBTRACK:

                 yInc = HIWORD(wParam) - yPos;

                 break;

            default:

                 yInc = 0;

        }

        /*

         * If applying the vertical scrolling increment does not

         * take the scrolling position out of the scrolling range,

         * increment the scrolling position, adjust the position

         * of the scroll box, and update the window. UpdateWindow

         * sends the WM_PAINT message.

         */

        if (yInc = max(-yPos, min(yInc, yMax - yPos))) {

            yPos += yInc;

            ScrollWindow(hwnd, 0, -yChar * yInc,

                (CONST RECT *) NULL, (CONST RECT *) NULL,

                (HRGN) NULL, (LPRECT) NULL, SW_INVALIDATE);

            si.cbSize = sizeof(si);

            si.fMask  = SIF_POS;

            si.nPos   = YPos;

            SetScrollInfo(hwnd, SB_VERT, &si, TRUE);

            UpdateWindow (hwnd);

        }

        return 0;


Scrolling a Bitmap

This section describes changes you can make to an application's main window procedure to enable the user to scroll a bitmap. The example in Example of Scrolling a Bitmap includes a menu item that copies the screen content to a bitmap and displays the bitmap in the client area.

The example also processes the WM_HSCROLL and WM_VSCROLL messages generated by the scroll bars so that the user may scroll the bitmap horizontally and vertically. Unlike the example for scrolled text, the bitmap example employs the BitBlt function to draw the invalid portion of the client area.


Scrolling a Bitmap with the WM_CREATE Message

When the WM_CREATE message is processed, the variables required for scrolling are initialized. Use the CreateCompatibleDC function to create a compatible device context (DC), the CreateBitmap function to create a bitmap, and the SelectObject function to select the bitmap for the DC. Note that a compatible DC is also known as a memory DC.

The device-specific information about the display device is retrieved. If a compatible DC is created for the screen, as in the example, use the GetDeviceCaps function to get this information. The information includes the number of adjacent color bits per pixel, the number of color planes, and the height and width of the DC.


Scrolling a Bitmap with the WM_SIZE Message

Processing of the WM_SIZE message requires adjusting the scrolling range and position, so it reflects the dimensions of the client area and the bitmap that will be displayed.

The SetScrollInfo function sets the minimum and maximum position values, the page size, and the scrolling position for a scroll bar. For operating system versions earlier than 4.0, use the SetScrollPos function to adjust the scroll box position.


Scrolling a Bitmap with the WM_HSCROLL and WM_VSCROLL Messages

When the WM_HSCROLL and WM_VSCROLL messages are processed, the scroll bar notification message is examined and the scrolling position is set to a new value that reflects the scrolling action of the user. If the scrolling position is within the scrolling range, the window is scrolled to the new position by using the ScrollWindow function. The position of the scroll box is then adjusted by using the SetScrollInfo function. In versions earlier than 4.0, use the SetScrollPos function.

After a window is scrolled, part of its client area is made invalid. To ensure that the invalid region is updated, use the UpdateWindow function to generate a WM_PAINT message. When processing the WM_PAINT message, an application must repaint the invalid region at the bottom of the client area. When scrolling or resizing the client area, the example uses the BitBlt function to copy the appropriate portion of the bitmap to the invalid portion of the client area.


Example of Scrolling a Bitmap

The following example enables the user to capture the screen content into a bitmap and scroll the bitmap in the client area.

HDC hdc;

PAINTSTRUCT ps;

SCROLLINFO si;

/* These variables are required by BitBlt.                      */

static HDC hdcWin;           /* window DC                       */

static HDC hdcScreen;        /* DC for entire screen            */

static HDC hdcScreenCompat;  /* memory DC for screen            */

static HBITMAP hbmpCompat;   /* bitmap handle for old DC        */

static BITMAP bmp;           /* bitmap data structure           */

static BOOL fBlt;            /* TRUE if BitBlt occurred         */

static BOOL fScroll;         /* TRUE if scrolling occurred      */

static BOOL fSize;           /* TRUE if fBlt & WM_SIZE          */

/* These variables are required for horizontal scrolling.       */

static int xMinScroll;       /* minimum horizontal scroll value */

static int xCurrentScroll;   /* current horizontal scroll value */

static int xMaxScroll;       /* maximum horizontal scroll value */

/* These variables are required for vertical scrolling.         */

static int yMinScroll;       /* minimum vertical scroll value   */

static int yCurrentScroll;   /* current vertical scroll value   */

static int yMaxScroll;       /* maximum vertical scroll value   */

switch (uMsg) {

    case WM_CREATE:

        /*

         * Create a normal DC and a memory DC for the entire

         * screen. The normal DC provides a snapshot of the

         * screen contents. The memory DC keeps a copy of this

         * snapshot in the associated bitmap.

         */

        hdcScreen = CreateDC("DISPLAY", (LPCSTR) NULL,

            (LPCSTR) NULL, (CONST DEVMODE *) NULL);

        hdcScreenCompat = CreateCompatibleDC(hdcScreen);

        /*

         * Retrieve the metrics for the bitmap associated with the

         * regular device context.

         */

        bmp.bmBitsPixel =

            (BYTE) GetDeviceCaps(hdcScreen, BITSPIXEL);

        bmp.bmPlanes = (BYTE) GetDeviceCaps(hdcScreen, PLANES);

        bmp.bmWidth = GetDeviceCaps(hdcScreen, HORZRES);

        bmp.bmHeight = GetDeviceCaps(hdcScreen, VERTRES);

        /* The width must be byte-aligned. */

        bmp.bmWidthBytes = ((bmp.bmWidth + 15) &~15)/8;

        /* Create a bitmap for the compatible DC. */

        hbmpCompat = CreateBitmap(bmp.bmWidth, bmp.bmHeight,

            bmp.bmPlanes, bmp.bmBitsPixel, (CONST VOID *) NULL);

        /* Select the bitmap for the compatible DC. */

        SelectObject(hdcScreenCompat, hbmpCompat);

        /* Initialize the flags. */

        fBlt = FALSE;

        fScroll = FALSE;

        fSize = FALSE;

        /* Initialize the horizontal scrolling variables. */

        xMinScroll = 0;

        xCurrentScroll = 0;

        xMaxScroll = 0;

        /* Initialize the vertical scrolling variables. */

        yMinScroll = 0;

        yCurrentScroll = 0;

        yMaxScroll = 0;

        break;

    case WM_SIZE: {

        int xNewSize;

        int yNewSize;

        xNewSize = LOWORD(lParam);

        yNewSize = HIWORD(lParam);

        if (fBlt)

            fSize = TRUE;

        /*

         * The horizontal scrolling range is defined by

         * (bitmap_width) - (client_width). The current horizontal

         * scroll value remains within the horizontal scrolling range.

         */

        xMaxScroll = max(bmp.bmWidth-xNewSize, 0);

        xCurrentScroll = min(xCurrentScroll, xMaxScroll);

        si.cbSize = sizeof(si);

        si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS;

        si.nMin   = xMinScroll;

        si.nMax   = xMaxScroll;

        si.nPage  = xNewSize;

        si.nPos   = xCurrentScroll;

        SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);

        /*

         * The vertical scrolling range is defined by

         * (bitmap_height) - (client_height). The current vertical

         * scroll value remains within the vertical scrolling range.

         */

        yMaxScroll = max(bmp.bmHeight - yNewSize, 0);

        yCurrentScroll = min(yCurrentScroll, yMaxScroll);

        si.cbSize = sizeof(si);

        si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS;

        si.nMin   = yMinScroll;

        si.nMax   = yMaxScroll;

        si.nPage  = yNewSize;

        si.nPos   = yCurrentScroll;

        SetScrollInfo(hwnd, SB_VERT, &si, TRUE);

    }

        break;

    case WM_PAINT: {

        PRECT prect;

        hdc = BeginPaint(hwnd, &ps);

        /*

         * If the window has been resized and the user has

         * captured the screen, use the following call to

         * BitBlt to paint the window's client area.

         */

        if (fSize) {

            BitBlt(ps.hdc,

                0, 0,

                bmp.bmWidth, bmp.bmHeight,

                hdcScreenCompat,

                xCurrentScroll, yCurrentScroll,

                SRCCOPY);

            fSize = FALSE;

        }

        /*

         * If scrolling has occurred, use the following call to

         * BitBlt to paint the invalid rectangle.

         *

         * The coordinates of this rectangle are specified in the

         * RECT structure to which prect points.

         *

         * Note that it is necessary to increment the seventh

         * argument (prect->left) by xCurrentScroll and the

         * eighth argument (prect->top) by yCurrentScroll in

         * order to map the correct pixels from the source bitmap.

         */

        if (fScroll) {

            prect = &ps.rcPaint;

            BitBlt(ps.hdc,

                prect->left, prect->top,

                (prect->right - prect->left),

                (prect->bottom - prect->top),

                hdcScreenCompat,

                prect->left + xCurrentScroll,

                prect->top + yCurrentScroll,

                SRCCOPY);

            fScroll = FALSE;

        }

        EndPaint(hwnd, &ps);

    }

        break;

    case WM_HSCROLL: {

        int xDelta;     /* xDelta = new_pos - current_pos */

        int xNewPos;    /* new position */

        int yDelta = 0;

        switch (LOWORD(wParam)) {

            /* User clicked the shaft left of the scroll box. */

            case SB_PAGEUP:

                xNewPos = xCurrentScroll - 50;

                break;

            /* User clicked the shaft right of the scroll box. */

            case SB_PAGEDOWN:

                xNewPos = xCurrentScroll + 50;

                break;

            /* User clicked the left arrow. */

            case SB_LINEUP:

                xNewPos = xCurrentScroll - 5;

                break;

            /* User clicked the right arrow. */

            case SB_LINEDOWN:

                xNewPos = xCurrentScroll + 5;

                break;

            /* User dragged the scroll box. */

            case SB_THUMBPOSITION:

                xNewPos = HIWORD(wParam);

                break;

            default:

                xNewPos = xCurrentScroll;

        }

        /* New position must be between 0 and the screen width. */

        xNewPos = max(0, xNewPos);

        xNewPos = min(xMaxScroll, xNewPos);

        /* If the current position does not change, do not scroll.*/

        if (xNewPos == xCurrentScroll)

            break;

        /* Set the scroll flag to TRUE. */

        fScroll = TRUE;

        /* Determine the amount scrolled (in pixels). */

        xDelta = xNewPos - xCurrentScroll;

        /* Reset the current scroll position. */

        xCurrentScroll = xNewPos;

        /*

         * Scroll the window. (The system repaints most of the

         * client area when ScrollWindowEx is called; however, it is

         * necessary to call UpdateWindow in order to repaint the

         * rectangle of pixels that were invalidated.)

         */

        ScrollWindowEx(hwnd, -xDelta, -yDelta, (CONST RECT *) NULL,

            (CONST RECT *) NULL, (HRGN) NULL, (LPRECT) NULL,

            SW_INVALIDATE);

        UpdateWindow(hwnd);

        /* Reset the scroll bar. */

        si.cbSize = sizeof(si);

        si.fMask  = SIF_POS;

        si.nPos   = xCurrentScroll;

        SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);

    }

        break;

    case WM_VSCROLL: {

        int xDelta = 0;

        int yDelta;     /* yDelta = new_pos - current_pos */

        int yNewPos;    /* new position */

        switch (LOWORD(wParam)) {

            /* User clicked the shaft above the scroll box. */

            case SB_PAGEUP:

                yNewPos = yCurrentScroll - 50;

                break;

            /* User clicked the shaft below the scroll box. */

            case SB_PAGEDOWN:

                yNewPos = yCurrentScroll + 50;

                break;

            /* User clicked the top arrow. */

            case SB_LINEUP:

                yNewPos = yCurrentScroll - 5;

                break;

            /* User clicked the bottom arrow. */

            case SB_LINEDOWN:

                yNewPos = yCurrentScroll + 5;

                break;

            /* User dragged the scroll box. */

            case SB_THUMBPOSITION:

                yNewPos = HIWORD(wParam);

                break;

            default:

                yNewPos = yCurrentScroll;

        }

        /* New position must be between 0 and the screen height. */

        yNewPos = max(0, yNewPos);

        yNewPos = min(yMaxScroll, yNewPos);

        /* If the current position does not change, do not scroll.*/

        if (yNewPos == yCurrentScroll)

            break;

        /* Set the scroll flag to TRUE. */

        fScroll = TRUE;

        /* Determine the amount scrolled (in pixels). */

        yDelta = yNewPos - yCurrentScroll;

        /* Reset the current scroll position. */

        yCurrentScroll = yNewPos;

        /*

         * Scroll the window. (The system repaints most of the

         * client area when ScrollWindowEx is called; however, it is

         * necessary to call UpdateWindow in order to repaint the

         * rectangle of pixels that were invalidated.)

         */

        ScrollWindowEx(hwnd, -xDelta, -yDelta, (CONST RECT *) NULL,

            (CONST RECT *) NULL, (HRGN) NULL, (LPRECT) NULL,

            SW_INVALIDATE);

        UpdateWindow(hwnd);

        /* Reset the scroll bar. */

        si.cbSize = sizeof(si);

        si.fMask  = SIF_POS;

        si.nPos   = yCurrentScroll;

        SetScrollInfo(hwnd, SB_VERT, &si, TRUE);

    }

        break;

    case WM_COMMAND:        /* uMsg: command from app. menu */

        switch(wParam) {

            case IDM_STC:

                /*

                 * Copy the contents of the current screen

                 * into the compatible DC.

                 */

                BitBlt(hdcScreenCompat, 0, 0, bmp.bmWidth,

                    bmp.bmHeight, hdcScreen, 0, 0, SRCCOPY);

                /*

                 * Copy the compatible DC to the client area.

                 */

                hdcWin = GetDC(hwnd);

                BitBlt(hdcWin, 0, 0, bmp.bmWidth, bmp.bmHeight,

                    hdcScreenCompat, 0, 0, SRCCOPY);

                ReleaseDC(hwnd, hdcWin);

                fBlt = TRUE;

                break;

            default:

                return (DefWindowProc(hwnd, uMsg,

                    wParam, lParam));

        }

        break;


Creating a Keyboard Interface for a Standard Scroll Bar

Although a scroll bar control provides a built-in keyboard interface, a standard scroll bar does not. To implement a keyboard interface for a standard scroll bar, a window procedure must process the WM_KEYDOWN message and examine the virtual-key code specified by the wParam parameter. If the virtual-key code corresponds to an arrow key, the window procedure sends itself a WM_HSCROLL or WM_VSCROLL message with the low-order word of the wParam parameter set to the appropriate scroll bar notification message. For example, when the user presses the UP arrow key, the window procedure receives a WM_KEYDOWN message with wParam equal to VK_UP. In response, the window procedure sends itself a WM_VSCROLL message with the low-order word of wParam set to the SB_LINEUP notification message.

The following example shows how to include a keyboard interface for a standard scroll bar.

WORD wScrollNotify = 0xFFFF;

.

.

.

case WM_KEYDOWN:

    switch (wParam) {

        case VK_UP:

            wScrollNotify = SB_LINEUP;

            break;

        case VK_PRIOR:

            wScrollNotify = SB_PAGEUP;

            break;

        case VK_NEXT:

            wScrollNotify = SB_PAGEDOWN;

            break;

        case VK_DOWN:

            wScrollNotify = SB_LINEDOWN;

            break;

        case VK_HOME:

            wScrollNotify = SB_TOP;

            break;

        case VK_END:

            wScrollNotify = SB_BOTTOM;

            break;

    }

    if (wScrollNotify != -1)

        SendMessage(hwnd, WM_VSCROLL,

            MAKELONG(wScrollNotify, 0), 0L);

    break;

.

.

.


Scroll Bar Reference

The following functions and messages are associated with scroll bars.


Scroll Bar Functions

Following are the functions used with scroll bars.

EnableScrollBar
GetScrollPos
GetScrollRange
ScrollDC
ScrollWindow
ScrollWindowEx
SetScrollPos
SetScrollRange
ShowScrollBar


Scroll Bar Messages

Following are the messages used with scroll bars.

SBM_ENABLE_ARROWS
SBM_GETPOS
SBM_GETRANGE
SBM_SETPOS
SBM_SETRANGE
SBM_SETRANGEREDRAW
WM_CTLCOLORSCROLLBAR
WM_HSCROLL
WM_VSCROLL


Static Controls

The Microsoft® Windows® operating system provides dialog boxes and controls to support communication between an application and the user. A static control is a control that enables an application to provide the user with certain types of text and graphics that typically require no response.


About Static Controls

Applications often use static controls to label other controls or to separate a group of controls. Although static controls are child windows, they cannot be selected. Therefore, they cannot receive the keyboard focus and cannot have a keyboard interface. A static control that has the SS_NOTIFY style receives mouse input, notifying the parent window when the user clicks or double clicks the control. Static controls belong to the STATIC window class.

Although static controls can be used in overlapped, pop-up, and child windows, they are designed for use in dialog boxes, where Windows standardizes their behavior. By using static controls outside dialog boxes, a developer increases the risk that the application might behave in a nonstandard fashion. Typically, a developer either uses static controls in dialog boxes or uses the SS_OWNERDRAW style to create customized static controls.

For more information about dialog boxes, see Dialog Boxes. For more information about window classes, see Window Classes. For more information about window subclassing, see Window Procedures.


Static Control Types and Styles

The Microsoft® Win32® application programming interface (API) provides four types of static controls: simple graphics, text, images, and owner-drawn. Each type has one or more styles.


Simple Graphics

A simple graphics static control displays a frame or a filled rectangle. A frame can be drawn in a number of styles, included black, gray, or white. In addition, a frame and can drawn with an etched style to give it a three-dimensional appearance. The frame styles include SS_BLACKFRAME, SS_GRAYFRAME, SS_WHITEFRAME, SS_ETCHEDHORZ, SS_ETCHEDVERT, and SS_ETCHEDFRAME.

A rectangle can be filled with color in one of three styles: black, gray, or white. These styles are defined by the constants SS_BLACKRECT, SS_GRAYRECT, and SS_WHITERECT.


Text

A text static control displays text in a rectangle in one of five styles: left-aligned without wordwrap, left aligned with wordwrap, centered, right-aligned, or "simple." These styles are defined by the constants SS_LEFTNOWORDWRAP, SS_LEFT, SS_CENTER, SS_RIGHT, and SS_SIMPLE, respectively. Windows rearranges the text in these controls in predefined ways, except for "simple" text, which is not rearranged.

An application can change the text in a text static control at any time by using the SetWindowText function or the WM_SETTEXT message.

The system displays as much text as it can in the static control and clips whatever does not fit. To calculate an appropriate size for the control, retrieve the font metrics for the text. For more information about fonts and font metrics, see Fonts and Text.


Images

An image static control can display bitmaps, icons (including animated icons), or enhanced metafiles. The type of graphic that a particular static control displays depends on the control's style: SS_BITMAP, SS_ICON, or SS_ENHMETAFILE. An application specifies the style when it creates the control and also specifies the handle of the bitmap, icon, or metafile for the control to display. After the control is created, an application can associate a different graphic with the control by sending it an STM_SETIMAGE message, specifying the handle of the new graphic object. An application can retrieve the handle of the graphic object currently associated with a static control by sending it an STM_GETIMAGE message. An application sends messages to a static control by using the SendDlgItemMessage function.


Owner-Drawn

By using the SS_OWNERDRAW style, an application can take responsibility for painting a static control. The parent window of an owner-drawn static control (its owner) receives a WM_DRAWITEM message whenever the static control needs to be painted. The message includes the address of a DRAWITEMSTRUCT structure that contains information that the owner window uses when drawing the control.


Static Control Styles

Many developers create dialog boxes by using standalone tools and so may not need to specify static control styles. However, if a developer uses the CreateWindow or CreateWindowEx function to create a static control for an application, the developer must use the following constants to define the style.

Style	Description
SS_BITMAP	Specifies a bitmap is to be displayed in the static control. The given text is the name of a bitmap (not a filename) defined elsewhere in the resource file. The style ignores the nWidth and nHeight parameters; the control automatically sizes itself to accommodate the bitmap.
SS_BLACKFRAME	Specifies a box with a frame drawn in the same color as the window frames. This color is black in the default Windows color scheme.
SS_BLACKRECT	Specifies a rectangle filled with the current window frame color. This color is black in the default Windows color scheme.
SS_CENTER	Specifies a simple rectangle and centers the given text in the rectangle. The text is formatted before it is displayed. Words that extend past the end of a line are automatically wrapped to the beginning of the next centered line.
SS_CENTERIMAGE	Specifies that, if the bitmap or icon is smaller than the client area of the static control, the rest of the client area is filled with the color of the pixel in the top left corner of the bitmap or icon. If the static control contains a single line of text, the text is centered vertically in the client area of the control.
SS_ENHMETAFILE	Specifies an enhanced metafile is to be displayed in the static control. The given text is the name of a metafile. An enhanced metafile static control has a fixed size; the metafile is scaled to fit the static control's client area.
SS_ETCHEDFRAME	Draws the frame of the static control using the EDGE_ETCHED edge style. For more information, see the DrawEdge function.
SS_ETCHEDHORZ	Draws the top and bottom edges of the static control using the EDGE_ETCHED edge style. For more information, see the DrawEdge function.
SS_ETCHEDVERT	Draws the left and right edges of the static control using the EDGE_ETCHED edge style. For more information, see the DrawEdge function.
SS_GRAYFRAME	Specifies a box with a frame drawn with the same color as the screen background (desktop). This color is gray in the default Windows color scheme.
SS_GRAYRECT	Specifies a rectangle filled with the current screen background color. This color is gray in the default Windows color scheme.
SS_ICON	Specifies an icon is to be displayed in the dialog box. The given text is the name of an icon (not a filename) defined elsewhere in the resource file. The icon can be an animated cursor. The style ignores the nWidth and nHeight parameters; the control automatically sizes itself to accommodate the icon.
SS_LEFT	Specifies a simple rectangle and left-aligns the given text in the rectangle. The text is formatted before it is displayed. Words that extend past the end of a line are automatically wrapped to the beginning of the next left-aligned line.
SS_LEFTNOWORDWRAP	Specifies a simple rectangle and left-aligns the given text in the rectangle. Tabs are expanded, but words are not wrapped. Text that extends past the end of a line is clipped.
SS_NOPREFIX	Prevents interpretation of any ampersand (&) characters in the control's text as accelerator prefix characters. These are displayed with the ampersand removed and the next character in the string underlined. This static control style may be included with any of the defined static controls. An application can combine SS_NOPREFIX with other styles by using the bitwise OR (|) operator. This can be useful when filenames or other strings that may contain an ampersand (&) must be displayed in a static control in a dialog box.
SS_NOTIFY	Sends the parent window STN_CLICKED, STN_DBLCLK, STN_DISABLE, and STN_ENABLE notification messages when the user clicks or double-clicks the control.
SS_OWNERDRAW	Specifies that the owner of the static control is responsible for drawing the control. The owner window receives a WM_DRAWITEM message whenever the control needs to be drawn.
SS_REALSIZEIMAGE	Prevents a static icon or bitmap control (that is, static controls that have the SS_ICON or SS_BITMAP style) from being resized as it is loaded or drawn. If the icon or bitmap is larger than the destination area, the image is clipped.
SS_RIGHT	Specifies a simple rectangle and right-aligns the given text in the rectangle. The text is formatted before it is displayed. Words that extend past the end of a line are automatically wrapped to the beginning of the next right-aligned line.
SS_RIGHTJUST	Specifies that the lower right corner of a static control with the SS_BITMAP or SS_ICON style is to remain fixed when the control is resized. Only the top and left sides are adjusted to accommodate a new bitmap or icon.
SS_SIMPLE	Specifies a simple rectangle and displays a single line of left-aligned text in the rectangle. The text line cannot be shortened or altered in any way. The control's parent window or dialog box must not process the WM_CTLCOLORSTATIC message.
SS_SUNKEN	Draws a half-sunken border around a static control.
SS_WHITEFRAME	Specifies a box with a frame drawn with the same color as the window background. This color is white in the default Windows color scheme.
SS_WHITERECT	Specifies a rectangle filled with the current window background color. This color is white in the default Windows color scheme.


Static Control Default Message Processing

The window procedure for the predefined static control window class performs default processing for all messages that the static control procedure does not process. When the static control returns FALSE for any message, the predefined window procedure checks the messages and carries out the default action described in the following table. In the table, a text static control is a static control with the style SS_LEFTNOWORDWRAP, SS_LEFT, SS_CENTER, SS_RIGHT, or SS_SIMPLE.

Message	Default action
WM_CREATE	Loads the graphic object and sizes the window to the object's size, for graphic static controls. Takes no action for other static controls.
WM_DESTROY	Frees and destroys any graphic object, for graphic static  controls. Takes no action for other static controls.
WM_ENABLE	Repaints visible static controls.
WM_ERASEBKGND	Returns TRUE, indicating the control erases the background.
WM_GETDLGCODE	Returns DLGC_STATIC.
WM_GETFONT	Returns the handle of the font for text static controls.
WM_GETTEXTLENGTH	Returns the length, in characters, of the text for a text static control.
WM_LBUTTONDBLCLK	Sends the parent window an STN_DBLCLK notification message if the control style is SS_NOTIFY.
WM_LBUTTONDOWN	Sends the parent window an STN_CLICKED notification message if the control style is SS_NOTIFY.
WM_NCLBUTTONDBLCLK	Sends the parent window an STN_DBLCLK notification message if the control style is SS_NOTIFY.
WM_NCLBUTTONDOWN	Sends the parent window an STN_CLICKED notification message if the control style is SS_NOTIFY.
WM_NCHITTEST	Returns HTCLIENT if the control style is SS_NOTIFY; otherwise, returns HTTRANSPARENT.
WM_PAINT	Repaints the control.
WM_SETFONT	Sets the font and repaints for text static controls.
WM_SETTEXT	Sets the text and repaints for text static controls.
The predefined window procedure passes all other messages to DefWindowProc for default processing.


Using Static Controls

The following example uses a timer and the STM_SETIMAGE message to animate an icon in a dialog box. The icon handles and the icon identifier (IDI_ICON) are defined in a global header file.

LRESULT APIENTRY StaticProc(hDlg, message, wParam, lParam)

HWND hDlg;      /* window handle of dialog box           */

UINT message;   /* type of message                       */

UINT wParam;    /* message-specific information          */

LONG lParam;

{

    UINT idTimer = 1;

    static UINT i;

    static HICON aIcons[11];

    switch (message) {

        case WM_INITDIALOG:             /* initialize dialog box */

            i = 0;

            /* Load icons("hinst" is defined globally). */

            hiconOne    = LoadIcon(hinst, "OneIco");

            aIcons[i]   = hiconOne;

            hiconTwo    = LoadIcon(hinst, "TwoIco");

            aIcons[++i] = hiconTwo;

                .

                . /* Continue with the remaining icons. */

                .

            i = 0;

             /*

              * Use STM_SETIMAGE to associate an icon with the

              * IDI_ICON identifier.

              */

            SendDlgItemMessage(hDlg,  /* dialog box window handle */

               IDI_ICON,              /* icon identifier          */

               STM_SETIMAGE,          /* message to send          */

               (WPARAM) IMAGE_ICON,   /* image type               */

               (LPARAM) aIcons[i++]); /* icon handle              */

            /* Set a timer for 50-millisecond intervals. */

            SetTimer(hDlg, idTimer, 50, (TIMERPROC) NULL);

            return TRUE;

        case WM_TIMER:

             /*

              * Use STM_SETIMAGE to associate a new icon with

              * the IDI_ICON identifier whenever a WM_TIMER

              * message is received.

              */

            SendDlgItemMessage(hDlg,  /* dialog box window handle */

               IDI_ICON,              /* icon identifier          */

               STM_SETIMAGE,          /* message to send          */

               (WPARAM) IMAGE_ICON,   /* image type               */

               (LPARAM) aIcons[i++]); /* new icon handle          */

            if (i == 10)

                i = 0;

            break;

        case WM_COMMAND:

            if (wParam == IDOK

                || wParam == IDCANCEL) {

                EndDialog(hDlg, TRUE);

                return TRUE;

            }

            return 0;

        case WM_DESTROY: /* clean up  */

            KillTimer(hDlg, idTimer);

            DeleteObject(hiconOne);

            DeleteObject(hiconTwo);

                .

                . /* Continue with the remaining icons. */

                .

            return 0;

    }

    return FALSE;

        UNREFERENCED_PARAMETER(lParam);

}


Static Control Messages

Following are the messages used with static controls. (STM_GETICON and STM_SETICON are used only with icons.)

STM_GETICON
STM_SETICON
WM_CTLCOLORSTATIC


Control Panel Applications

Control Panel applications are special-purpose dynamic-link libraries (DLLs) that let users configure the environment of Microsoft® Windows®.

This overview describes Control Panel applications and explains the functions and messages that these applications use and process to complete their work.


About Control Panel Applications

Even though Windows provides a number of standard Control Panel applications, you can create additional applications to let users examine and modify the settings and operational modes of specific hardware and software.


Application Responsibilities and Operation

The primary responsibility of any Control Panel application is to display a dialog box and to carry out any tasks specified by the user. Despite this responsibility, Control Panel applications do not provide menus or other direct means for users to access their dialog boxes. Instead, these applications operate under the control of another application and display their dialog boxes only when requested by the controlling application.

Control Panel applications are usually controlled by a Windows system utility specifically designed to give users access to these applications. However, any application can load and manage Control Panel applications, as long as the controlling application sends messages and processes return values in the way that the Control Panel applications expect.

Most Control Panel applications display and manage a single dialog box, giving the user control of the settings and operational modes of a single system component. However, any given Control Panel application can provide any number of dialog boxes to control any number of system components. (These individual dialog boxes are sometimes called applets.) To distinguish between dialog boxes, a Control Panel application typically supplies the controlling application with a unique icon for each dialog box. The controlling application displays these icons and the user can choose a dialog box by choosing the corresponding icon.


Application Entry-Point Function

Every Control Panel application must export the standard entry-point function, CPlApplet. This function receives requests, in the form of Control Panel (CPL) messages, and carries out the requested work, such as initializing the application, displaying and managing the dialog box(es), and closing the application.

When the controlling application first loads the Control Panel application, it retrieves the address of the CPlApplet function and subsequently uses the address to call the function and pass it messages. The controlling application may send the following messages:

Message	Description
CPL_DBLCLK	Sent to notify CPlApplet that the user has chosen the icon associated with a given dialog box. CPlApplet should display the corresponding dialog box and carry out any user-specified tasks.
CPL_EXIT	Sent after the last CPL_STOP message and immediately before the controlling application uses the FreeLibrary function to free the DLL containing the Control Panel application. CPlApplet should free any remaining memory and prepare to close.
CPL_GETCOUNT	Sent after the CPL_INIT message to prompt CPlApplet to return a number indicating how many dialog boxes it supports.
CPL_INIT	Sent immediately after the DLL containing the Control Panel application is loaded, to prompt CPlApplet to perform initialization procedures, including memory allocation.
CPL_INQUIRE	Sent after the CPL_GETCOUNT message, to prompt CPlApplet to provide information about a given dialog box. This message has been superseded by the CPL_NEWINQUIRE message.
CPL_NEWINQUIRE	Sent after the CPL_GETCOUNT message, to prompt CPlApplet to provide information about a given dialog box . The second parameter (lParam2) is a pointer to a NEWCPLINFO structure.
CPL_SELECT	Sent to notify CPlApplet that the user has selected the icon. associated with a given dialog box.
CPL_STOP	Sent once for each dialog box before the controlling application closes. CPlApplet should free any memory associated with the given dialog box.


Message Processing

CPlApplet processes all messages sent to a Control Panel application by a controlling application. The function expects to be sent messages in a given order. The controlling application expects the messages to be processed in a given way.

CPlApplet receives the CPL_INIT message when the controlling application first loads the Control Panel application. The function should carry out any initialization, such as allocating memory, and return nonzero. If CPlApplet cannot complete the initialization, it must return zero, directing the controlling application to terminate communication and release the DLL.

CPlApplet receives the CPL_GETCOUNT message only if the CPL_INIT message succeeded. The function must then return the number of dialog boxes supported by the Control Panel application.

CPlApplet receives one CPL_NEWINQUIRE message for each dialog box supported by the Control Panel application. Each message includes the address of a NEWCPLINFO structure and a unique identifier that the controlling application uses to identify the given dialog box. The function must set the dwSize member in the NEWCPLINFO structure to the size of the structure, set the hIcon member to the handle of the icon that represents the dialog box, and set the szName and szInfo members to the addresses of the short name and description of the dialog box. If the function also sets the dwHelpContext and szHelpFile members, the controlling application will provide context-sensitive Help for the dialog box. The lData member can be used for application-defined data.

Note  The CPL_NEWINQUIRE message and NEWCPLINFO structure supersede the CPL_INQUIRE message and CPLINFO structure, respectively.

CPlApplet receives a CPL_SELECT message as a notification that the user has selected the icon representing the dialog box. The function may receive this message any number of times. The message includes the dialog box identifier previously supplied by the controlling application and the lData value previously supplied by CPlApplet. Typically, Control Panel applications do not respond to the CPL_SELECT message.

CPlApplet receives a CPL_DBLCLK message as a notification that the user has chosen the icon representing the dialog box. The function may receive this message any number of times. The message includes the dialog box identifier and the lData value. The function should display the corresponding dialog box and process subsequent user input.

Before the controlling application terminates, CPlApplet receives the CPL_STOP message once for each dialog box supported by the Control Panel application. The message includes the identifier for the dialog box and the lData value. The function should free any memory that it allocated for the given dialog box.

After the last CPL_STOP message, CPlApplet receives a CPL_EXIT message. The function should free all remaining allocated memory and unregister any private window classes that it may have registered. Immediately after the function returns from this message, the controlling application releases the Control Panel application by calling the FreeLibrary function.


Application Setup

Every Control Panel application is a dynamic-link library. To make sure the DLL containing your Control Panel application can be located and automatically loaded by the Windows system utility, the DLL file must have the .CPL filename extension and must be set up in one of the following ways:

•	Copied to the directory that contains the Windows system utility.

•	Copied to the Windows SYSTEM directory.

•	Registered under the the MMCPL key of the HKEY_CURRENT_USER key in the registry.

You should register the DLL in the registry if the DLL exports functions other than CPlApplet and provides functionality beyond the scope of a Control Panel application. For more information about the registry, seeRegistry.


Creating Control Panel Applications

Although a Control Panel application may support more than one dialog box, it processes all requests through the single CPlApplet function. In the following example, the Control Panel application supports three dialog boxes that let the user set preferences for a component stereo system attached to the computer. The example uses an application-defined StereoApplets array that contains three structures, each corresponding to one of the dialog boxes. Each structure contains all the information required by the CPL_NEWINQUIRE message, as well as the dialog box template and dialog box procedure required by the CPL_DBLCLK message. The code demonstrates how to fill the structures in the StereoApplets array.

#define NUM_APPLETS 3

typedef struct tagApplets

{

    int icon;         // icon resource identifier

    int namestring;   // name-string resource identifier

    int descstring;   // description-string resource identifier

    int dlgtemplate;  // dialog box template resource identifier

    DLGPROC dlgfn;    // dialog box procedure

} APPLETS;

APPLETS StereoApplets[NUM_APPLETS] =

{

    AMP_ICON, AMP_NAME, AMP_DESC, AMP_DLG, AmpDlgProc,

    TUNER_ICON, TUNER_NAME, TUNER_DESC, TUNER_DLG, TunerDlgProc,

    TAPE_ICON, TAPE_NAME, TAPE_DESC, TAPE_DLG, TapeDlgProc,

};

LONG CALLBACK CPlApplet(hwndCPL, uMsg, lParam1, lParam2)

HWND hwndCPL;      // handle of Control Panel window

UINT uMsg;         // message

LPARAM lParam1;    // first message parameter

LPARAM lParam2;    // second message parameter

{

    int i;

    LPNEWCPLINFO lpNewCPlInfo;

    i = (int) lParam1;

    switch (uMsg) {

        case CPL_INIT:      // first message, sent once

            hinst = GetModuleHandle("ecp.cpl");

            return TRUE;

        case CPL_GETCOUNT:  // second message, sent once

            return NUM_APPLETS;

            break;

        case CPL_NEWINQUIRE: // third message, sent once per app

            lpNewCPlInfo = (LPNEWCPLINFO) lParam2;

            lpNewCPlInfo->dwSize = (DWORD) sizeof(NEWCPLINFO);

            lpNewCPlInfo->dwFlags = 0;

            lpNewCPlInfo->dwHelpContext = 0;

            lpNewCPlInfo->lData = 0;

            lpNewCPlInfo->hIcon = LoadIcon(hinst,

                (LPCTSTR) MAKEINTRESOURCE(StereoApplets[i].icon));

            lpNewCPlInfo->szHelpFile[0] = '\0';

            LoadString(hinst, StereoApplets[i].namestring,

                lpNewCPlInfo->szName, 32);

            LoadString(hinst, StereoApplets[i].descstring,

                lpNewCPlInfo->szInfo, 64);

            break;

        case CPL_SELECT:    // applet icon selected

            break;

        case CPL_DBLCLK:    // applet icon double-clicked

            MessageBeep(MB_ICONEXCLAMATION);

            DialogBox(hinst,

                MAKEINTRESOURCE(StereoApplets[i].dlgtemplate),

                hwndCPL, StereoApplets[i].dlgfn);

            break;

        case CPL_STOP:      // sent once per app. before CPL_EXIT

            break;

        case CPL_EXIT:    // sent once before FreeLibrary is called

            break;

        default:

            break;

    }

    return 0;

}


Control Panel Reference

The following functions and messages are associated with the Control Panel.


Control Panel Functions

Following is the function used with the Control Panel.

CPlApplet


Control Panel Messages

Following are the messages used with the Control Panel.

CPL_DBLCLK
CPL_EXIT
CPL_GETCOUNT
CPL_INIT
CPL_INQUIRE
CPL_NEWINQUIRE
CPL_SELECT
CPL_STOP
WM_CPL_LAUNCH
WM_CPL_LAUNCHED


File Installation Library

The Microsoft® Win32® application programming interface (API) includes a file installation library that makes it easier for applications to install files properly and enables setup programs to analyze files currently installed.


About File Installation

The functions included in the file installation library determine where a file should be installed, identify conflicts with currently installed files, and perform the installation process. These functions enable installation programs to avoid the following problems:

•	Installing older versions of components over newer versions

•	Changing the language in a mixed-language system without notification

•	Installing multiple copies of a library in different directories

•	Copying files to network directories shared by multiple users

The file installation library also includes functions that enable applications to query a version resource for file information and present the information in a clear format. This information includes the file's purpose, author, version number, and so on.

Version information can be added to any Microsoft® Windows® file that can have Windows resources, such as a dynamic-link library (DLL), an executable file, or a font file. To add the information, a developer must create a version resource and add the resource to the file by using a resource compiler and specifying VS_FILE_INFO as the resource type.


Creating an Installation Program

An installation program typically has the following goals:

•	To place files in the correct location.

•	To notify the user if the installation program is replacing an existing file with a version that is significantly different — for example, replacing a German-language file with an English-language file, or replacing a newer file with an older file.

When writing the installation program, the developer must have the following information for each file on the installation disk(s):

•	The name and location of the file (referred to as the source file).

•	The name of the equivalent file on the user's hard disk (referred to as the destination file). This name is usually the same as the filename on the installation disk.

•	The sharing status of the file — that is, whether the file is private to the application being installed or could be shared by multiple applications.

For each file on the installation disk(s), the installation program must, at a minimum, call the VerFindFile and VerInstallFile functions. These functions are described briefly in the following paragraphs.

The installation program can use VerFindFile with the destination-file name to determine where the file should be copied on the disk. This function can also be used to specify whether the file is private to the application or can be shared. If a problem occurs in finding the file, VerFindFile returns an error value. For example, if Windows is using the destination file, VerFindFile returns VFF_FILEINUSE. The installation program must notify the user of the problem and respond to the user's decision to continue or to end the installation.

VerInstallFile copies the source file to a temporary file in the directory specified by VerFindFile. If necessary, VerInstallFile expands the file by using the functions in the data decompression library.

VerInstallFile compares the version information of the temporary file to that of the destination file. If the two differ, VerInstallFile returns one or more error values. For example, it returns VIF_SRCOLD if the temporary file is older than the destination file and VIF_DIFFLANG if the files have different language identifiers or code-page values. The installation program must notify the user of the problem and respond to the user's decision to continue or to end the installation.

Some VerInstallFile errors are recoverable. That is, the installation program can call VerInstallFile again, specifying the VIFF_FORCEINSTALL option, to install the file regardless of the version conflict. If VerInstallFile returns VIF_TEMPFILE and the user chooses not to force the installation, the installation program should delete the temporary file.

VerInstallFile could encounter a nonrecoverable error when attempting to force installation, even though the error did not exist previously. For example, the file could be locked by another user before the installation program attempted to force installation. If an installation program attempts to force installation after a non-recoverable error, VerInstallFile fails. The installation program must contain routines to recover from this type of error.

The recommended solution is to display for all errors a common dialog box with the buttons Install, Skip, and Install All. (Another solution is a dialog box with the buttons Yes, Yes to All, Skip, and Cancel.) The Install All button should prevent the installation program from prompting the user about similar errors by including the VIFF_FORCEINSTALL option in all subsequent uses of VerInstallFile. For nonrecoverable errors, the Install and Install All buttons should be disabled.

To display a useful error message to the user, the installation program usually must retrieve information from the version resources of the conflicting files. The file installation library provides four functions the installation program can use for this purpose: GetFileVersionInfoSize, GetFileVersionInfo, VerQueryValue, and VerLanguageName. GetFileVersionInfoSize returns the size of the version information. GetFileVersionInfo uses information retrieved by GetFileVersionInfoSize to retrieve a structure that contains the version information. VerQueryValue retrieves a specific member from that structure.

For example, if VerInstallFile returns the VIF_DIFFTYPE error, the installation program should use the GetFileVersionInfoSize, GetFileVersionInfo, and VerQueryValue functions on the temporary and destination files to obtain the general type of each file. If the languages of the files conflict, the installation program should also use VerLanguageName to translate the binary language identifier into a text representation of the language. (For example, 0x040C translates to the string "French.")

If VerInstallFile returns a file error, such as VIF_ACCESSVIOLATION, the installation program should use the GetLastError function to retrieve the most recent error value. The program should translate this value into an informative message to display to the user. The program must not yield control between the calls to VerInstallFile and GetLastError.


File Installation Library Functions

Following are the functions used for file installation.

GetFileVersionInfo
GetFileVersionInfoSize
VerFindFile
VerInstallFile
VerLanguageName
VerQueryValue

Obsolete or Deleted Functions

GetFileResource
GetFileResourceSize


File Manager Extensions

In Microsoft® Windows®, a File Manager extension is a dynamic-link library (DLL) that adds a menu and buttons to File Manager. A File Manager extension can also display (in the status bar) Help text for the buttons. This guide describes how to create and install extensions for File Manager.


About File Manager Extensions

File Manager maintains a list of extensions in an initialization file and loads the extensions when starting. An extension DLL contains an entry point that processes menu commands and notification messages sent by File Manager. Up to five extension DLLs can be installed at any one time.


Creating a File Manager Extension

A File Manager extension must reside in a DLL that includes a standard entry point, the FMExtensionProc callback function. The extension must include the WFEXT.H header file that defines File Manager messages and structures. File Manager communicates with the extension DLL by sending the following messages to the DLL's FMExtensionProc function.

Message	Meaning
1−99	User has selected an item from the extension-supplied menu. The value is the identifier of the selected menu item.
FMEVENT_HELPSTRING	User is selecting an extension menu or toolbar command item. File Manager wants the extension to supply a helpstring.
FMEVENT_HELPMENUITEM	User has pressed F1 while selecting an extension menu or toolbar command item. File Manager wants the extension to call WinHelp appropriately for the command item.
FMEVENT_INITMENU	User has selected the extension's menu. The extension should initialize items in the menu.
FMEVENT_LOAD	File Manager is loading the extension DLL and prompts the DLL for information about the menu that the DLL supplies.
FMEVENT_SELCHANGE	Selection in the File Manager directory window or Search Results window has changed.
FMEVENT_TOOLBARLOAD	File Manager is creating the toolbar and prompts the extension DLL for information about any buttons the DLL adds to the toolbar.
FMEVENT_UNLOAD	File Manager is unloading the extension DLL.
FMEVENT_USER_REFRESH	User has chosen the Refresh command from the Window menu. The extension should update items in the menu, if necessary.


Creating the Entry-Point Function

File Manager communicates with an extension DLL through the FMExtensionProc callback function. Make sure to export this function by listing it in the EXPORTS statement of your extension's module-definition (.DEF) file. The FMExtensionProc function handles the messages listed in the preceding section by performing the tasks listed in the following table.

Task	Action
Initializing the extension (FMEVENT_LOAD)	Provides File Manager with the name and handle of the menu and saves the menu-item delta value.
Initializing the menu (FMEVENT_INITMENU)	Initializes all top-level menu items and the items in any submenus.
Initializing the toolbar (FMEVENT_TOOLBARLOAD)	Provides File Manager with information about the buttons to add to the toolbar, including the command identifier, Help string identifier, styles, and bitmap identifier.
Processing menu selections	Carries out commands that the user chooses from the extension's menu.
Processing file selections (FMEVENT_SELCHANGE)	Queries File Manager for information about the file that the user has selected from the directory window or Search Results window.
Updating items in the menu (FMEVENT_USER_REFRESH)	Modifies the menu as appropriate when the user chooses File Manager's Refresh command from the Window menu.
Providing menu item help strings (FMEVENT_HELPSTRING)	Provides File Manager with a help string for a specified command in a specified menu. File Manager displays this string in the area at the bottom left of the window.
Passing menu item help requests on to WinHelp (FMEVENT_HELPMENUITEM)	Provides WinHelp with the window passed by File Manager and menu item information,
Quitting the extension DLL (FMEVENT_UNLOAD)	Frees any memory allocated and prepares to exit.
The FMExtensionProc function is defined as follows.

LONG WINAPI FMExtensionProc(hwnd, wMsg, lParam)

HWND hwnd;

WORD wMsg;

LONG lParam;

The hwnd parameter identifies the File Manager window. An extension should use this window handle to specify the parent window for any dialog box or message box it must display. It should also use this handle to send query messages to File Manager. The uMsg parameter contains one of the File Manager messages listed previously. The lParam parameter contains a message-specific value. The return value from the FMExtensionProc function depends on the value of the uMsg parameter.

The menu added to File Manager may be a hierarchical (cascaded) menu and may contain grayed, disabled, or checked menu items in addition to command items. Menu items should be text only; owner-drawn menus and bitmap menus are not supported. Changing the bitmap for check marks is not supported.

Whenever File Manager calls the FMExtensionProc function, it waits to refresh its directory windows (for changes in the file system) until after the function returns. This allows the extension to perform large numbers of file operations without excessive repainting on the part of File Manager. It is not necessary for the extension to send the FM_REFRESH_WINDOWS message to notify File Manager to repaint its directory windows.


Loading the Extension

File Manager first sends the FMEVENT_LOAD message to the FMExtensionProc function. The lParam parameter accompanying the FMEVENT_LOAD message points to an FMS_LOAD structure that File Manager uses to obtain information about the extension-supplied menu, including the menu name and menu handle.

File Manager also uses the FMS_LOAD structure to pass the menu-item delta value to the extension. To avoid conflicts with its own menu-item identifiers, File Manager renumbers the menu-item identifiers in an extension-supplied menu by adding the delta value to each identifier. An extension DLL that must modify its menu after File Manager has loaded it must use the delta value. For example, to delete a menu item, the extension DLL finds the sum of the delta value and the menu-item identifier and passes it as the idItem parameter to the DeleteMenu function.

If an extension returns FALSE in response to this message, File Manager calls the FreeLibrary function and ends any communication with the extension DLL. This is the only place where an extension can notify File Manager of initialization problems and thus prevent the extension from being loaded.


Adding Custom Buttons

A File Manager extension can add custom buttons to the File Manager toolbar by returning button information in response to the FMEVENT_TOOLBARLOAD message. File Manager sends this message to the FMExtensionProc function of the extension only if the extension successfully installed a custom menu during the processing of the FMEVENT_LOAD message. Use custom buttons as accelerator keys for menu commands specified in the custom menu.

When FMExtensionProc receives the FMEVENT_TOOLBARLOAD message, the lParam parameter points to an FMS_TOOLBARLOAD structure. The File Manager extension must copy information about the custom buttons to the structure, including the number of buttons and a specifier for the bitmap containing the button images (either the identifier for a bitmap resource or a handle to a memory bitmap). The extension must also include the address of an array of EXT_BUTTON structures, each of which must contain a command identifier for the corresponding button. If the button is an accelerator for a menu command, the button identifier and corresponding menu-command identifier must be equal.

The bitmap containing the button images must be a bitmap resource or a memory bitmap. The extension must copy either the resource identifier or the memory bitmap's handle to the FMS_TOOLBARLOAD structure; and, in the case of a bitmap resource, the resource must be in the extension's executable file.

The bitmap must contain one image for each specified button. The bitmap height is always 15 pixels; the width is always a multiple of 16 pixels because each button image must be 16 pixels wide. Button images are concatenated from left to right. For example, the image of the first button specified in the array of EXT_BUTTON structures must be the leftmost image in the bitmap.

An extension can provide a line of Help text for a button by specifying the identifier of a string resource in the idsHelp member of the EXT_BUTTON structure. When the user selects the button, File Manager retrieves the string resource and displays it on the toolbar.


Processing Menu Selections

The menu resource that you define for your extension's menu must use menu-item identifiers in the range 1 through 99. When the user selects an item, the extension receives a command notification that is the identifier of the selected item as defined in the resource-definition file (which has the .RC filename extension). The command notification is not the sum of the delta value and the identifier. An extension DLL's FMExtensionProc function carries out commands by processing command notifications.


Initializing the Extension Menu

Whenever the user selects the extension's main menu item from File Manager's menu bar, File Manager sends the FMEVENT_INITMENU message to the extension DLL. An extension can use this message to initialize its menu items. For example, an extension can add check marks, disable items, or gray items during this message.

When the user selects submenus within the extension's menu, File Manager does not send the FMEVENT_INITMENU message. An extension DLL must initialize all items at the same time, including those in submenus.


Updating the Extension Menu

When the user chooses the Refresh command from the Window menu, File Manager sends an FMEVENT_USER_REFRESH message to an extension DLL. The extension can use this opportunity to update its menu items.


Processing File Selections

When the user selects a filename in the directory window or in the Search Results window, File Manager sends the FMEVENT_SELCHANGE message to an extension DLL. The extension can use this opportunity to send a query message to File Manager to obtain more information about the user's selection.

Because the user can change the selection often, the extension should return promptly after processing the FMEVENT_SELCHANGE message to avoid slowing the user's selection process.


Quitting the Extension Dynamic-Link Library

When File Manager quits, it sends the FMEVENT_UNLOAD message to each extension DLL and then calls the FreeLibrary function to free the DLLs. Each DLL should free any memory that it has allocated.


Installing Extensions

File Manager installs extensions that have settings in the [AddOns] section of the WINFILE.INI initialization file. Each setting contains an entry and a value. An entry consists of a string that represents the name of an extension. The value assigned to the entry consists of a string that specifies the path to the extension DLL. An application can use the WritePrivateProfileString function to add a setting to WINFILE.INI. The following example shows a setting in WINFILE.INI.

[AddOns]

MyExtension=C:\NT\SYSTEM\MYEXT.DLL

File Manager does not display an error message if it cannot find an extension DLL, so an extension DLL can be deleted in order to uninstall it. Even so, an application that installs an extension DLL should provide an uninstall option to remove the extension's setting from the WINFILE.INI file.


Extension Messages

An extension can send the following window messages to retrieve relevant information from File Manager. File Manager is guaranteed to respond correctly only to messages sent from the FMExtensionProc function.

Message	Description
FM_GETDRIVEINFO	File Manager returns drive information from the active window. An extension provides a pointer to an FMS_GETDRIVEINFO structure; File Manager fills the structure with drive information.
FM_GETFILESEL	File Manager returns information about a selected file from the active File Manager window (either the directory window or the Search Results window). An extension provides a pointer to an FMS_GETFILESEL structure; File Manager fills the structure with file information.
FM_GETFILESELLFN	Same as the FM_GETFILESEL message except that the selected file may have a long filename.
FM_GETFOCUS	File Manager returns a value that identifies the type of window with input focus.
FM_GETSELCOUNT	File Manager returns the count of selected files in the directory and Search Results windows.
FM_GETSELCOUNTLFN	Same as the FM_GETSELCOUNT message except that the count includes files with long filenames.
FM_REFRESH_WINDOWS	File Manager repaints either its active window or all of its windows. This message is similar to File Manager's Refresh command on the Window menu.
FM_RELOAD_EXTENSIONS	File Manager reloads all extensions. First, File Manager unloads all extensions, sending an FMEVENT_UNLOAD message to each extension. Then, it reloads the extensions, sending an FMEVENT_LOAD message to each extension. The FM_RELOAD_EXTENSIONS message allows an extension to uninstall itself by removing its setting from the WINFILE.INI file; this action causes File Manager to reload the remaining extensions. Other applications and programs (for example, installation programs) can also post this message by calling the PostMessage function.


Processing Commands and Messages from File Manager

The following code shows the FMExtensionProc function for a sample extension DLL. It demonstrates how an extension processes the menu commands and notification messages sent by File Manager.

HINSTANCE hinst;

HMENU hmenu;

WORD wMenuDelta;

BOOL fMultiple = FALSE;

BOOL fLFN = FALSE;

LONG WINAPI FMExtensionProc(hwnd, wMsg, lParam)

HWND hwnd;

WORD wMsg;

LONG lParam;

{

    CHAR szBuf[200];

    INT count;

    switch (wMsg) {

    case FMEVENT_LOAD:

       #define lpload  ((LPFMS_LOAD) lParam)

       /* Save the menu-item delta value. */

       wMenuDelta = lpload->wMenuDelta;

       /* Fill the FMS_LOAD structure. */

       lpload->dwSize = sizeof(FMS_LOAD);

       lstrcpy(lpload->szMenuName, "&Extension");

       /* Return the handle of the menu. */

       hinst = GetModuleHandle("ext.dll");

       lpload->hMenu = GetSubMenu(LoadMenu(hinst,

       MAKEINTRESOURCE(MYMENU)), 0);

       return (LONG)TRUE;

   case FMEVENT_UNLOAD:

       /* Perform any cleanup procedures here. */

       break;

   case FMEVENT_INITMENU:

       /* Copy the menu handle. */

       hmenu = (HMENU) lParam;

       /*

             * Add check marks to menu items as appropriate.

             * Add menu-item delta values to menu-item

             * identifiers to specify the menu items to check.

        */

       CheckMenuItem(hmenu,

               wMenuDelta + IDM_MULTIPLE,

               fMultiple ? MF_BYCOMMAND | MF_CHECKED :

                       MF_BYCOMMAND | MF_UNCHECKED);

       CheckMenuItem(hmenu,

               wMenuDelta + IDM_LFN,

               fLFN ? MF_BYCOMMAND | MF_CHECKED :

                       MF_BYCOMMAND | MF_UNCHECKED);

       break;

   case FMEVENT_TOOLBARLOAD:

   {

       static EXT_BUTTON extbtn[] = {

          {1, 0, 0},

       };

            /* Fill the FMS_TOOLBARLOAD structure. */

       #define lptbld ((LPFMS_TOOLBARLOAD) lParam)

       lptbld->dwSize = sizeof(FMS_TOOLBARLOAD);

       lptbld->lpButtons = (LPEXT_BUTTON) &extbtn;

       lptbld->cButtons = 1;

       lptbld->cBitmaps = 1;

       lptbld->idBitmap = ID_BUTTONBITMAP;

       return (LONG)TRUE;

   }

   case FMEVENT_USER_REFRESH:

            MessageBox(hwnd, "User refresh event",

                "Hey!", MB_OK);

       break;

   case FMEVENT_SELCHANGE:

       break;

        /*

         * The following messages are generated when the user

         * chooses items from the extension menu.

         */

   case FMEVENT_HELPSTRING:

       #define lphs ((LPFMS_HELPSTRING)lParam)

       if (lphs->idCommand == -1)

          lstrcpy(lphs->szHelp, "Help for extension menu");

       else

          wsprintf(lphs->szHelp, "Help for item %d", lphs->idCommand);

       break;

   case FMEVENT_HELPMENUITEM:

       wsprintf(szBuf, "Help for %d", lParam);

       MessageBox(hwnd, szBuf, "WinHelp call", MB_OK);

       /*

        * Use: WinHelp(hwnd, "ExtHelp.hlp", HELP_CONTEXT, lParam);

        */

       break;

   case IDM_GETFOCUS:

       wsprintf(szBuf, "Focus %d",

               (INT) SendMessage(hwnd, FM_GETFOCUS, 0, 0));

       MessageBox(hwnd, szBuf, "Focus", MB_OK);

       break;

   case IDM_GETCOUNT:

       count = (INT) SendMessage(hwnd,

                fLFN ? FM_GETSELCOUNTLFN : FM_GETSELCOUNT,

                0, 0);

       wsprintf(szBuf, "%d files selected", count);

       MessageBox(hwnd, szBuf, "Selection Count", MB_OK);

       break;

   case IDM_GETFILE:

   {

       FMS_GETFILESEL file;

       count = (INT) SendMessage(hwnd,

               fLFN ? FM_GETSELCOUNTLFN : FM_GETSELCOUNT,

               FMFOCUS_DIR,

               0);

       while (count >= 1) {

                /*

                 * Selection indices are zero-based (0 is

                 * first).

                 */

      count--;

      SendMessage(hwnd, FM_GETFILESEL, count,

          (LONG) (LPFMS_GETFILESEL) &file);

      wsprintf(szBuf, "file %s\nSize %ld",

          (LPSTR) file.szName, file.dwSize);

                MessageBox(hwnd, szBuf, "File Information",

                    MB_OK);

      if (!fMultiple)

         break;

       }

       break;

   }

   case IDM_GETDRIVE:

   {

       FMS_GETDRIVEINFO drive;

       SendMessage(hwnd, FM_GETDRIVEINFO, 0,

       (LONG) (LPFMS_GETDRIVEINFO)&drive);

       wsprintf(szBuf,

                "%s\nFree %ld\nTotal %ld\nVolume %s\nShare %s",

       (LPSTR) drive.szPath, drive.dwFreeSpace,

       drive.dwTotalSpace, (LPSTR) drive.szVolume,

       (LPSTR) drive.szShare);

       MessageBox(hwnd, szBuf, "Drive Info", MB_OK);

       break;

   }

   case IDM_LFN:

       MessageBox(hwnd, "IDM_LFN", "Hi", MB_OK);

       fLFN = !fLFN;

       break;

   case IDM_MULTIPLE:

       MessageBox(hwnd, "IDM_MULTIPLE", "Hi", MB_OK);

       fMultiple = !fMultiple;

       break;

   case IDM_REFRESH:

   case IDM_REFRESHALL:

       SendMessage(hwnd, FM_REFRESH_WINDOWS,

       wMsg == IDM_REFRESHALL, 0);

       break;

   case IDM_RELOAD:

       PostMessage(hwnd, FM_RELOAD_EXTENSIONS, 0, 0);

       break;

    }

    return 0L;

}


Adding the Undelete Command

File Manager supports a hook for adding an Undelete command to the File menu (below the Delete command). If an "undelete" dynamic-link library is specified in the WINFILE.INI file, File Manager adds the Undelete command to the File menu when starting. When the user chooses the Undelete command, File Manager calls the DLL.

The [settings] section of the WINFILE.INI file should include a reference to the undelete DLL, as follows.

[settings]

UNDELETE.DLL=C:\MYDIR\OTHER.DLL

An undelete DLL must include a standard entry point, the UndeleteFile function. This function must be exported by specifying the name of the function in the EXPORTS statement of the DLL's module-definition (.DEF) file.

The UndeleteFile function is defined as follows:

DWORD APIENTRY UndeleteFile(hwndParent, lpszDir)

HWND hwndParent;

LPSTR lpszDir;

The hwndParent parameter identifies the parent window for any dialog boxes the DLL creates. The lpszDir parameter specifies the initial directory to be used (for example, C:\TEMP).


File Manager Extension Functions

Following are the functions used with File Manager extensions.

FMExtensionProc
UndeleteFile


Screen Saver Library

The Microsoft® Win32® application programming interface (API) supports special applications called screen savers that start when the mouse and keyboard have been idle for a period of time. Screen savers exist for two main reasons:

•	To avoid phosphor burn caused by static images on a screen

•	To conceal sensitive information left on a screen


About Screen Savers

The Desktop application in Windows Control Panel lets users select from a list of screen savers, specify how much time should elapse before the screen saver is started, configure screen savers, and preview screen savers. Screen savers are loaded automatically when Windows starts or when a user activates the screen saver feature by using Control Panel.

Once a screen saver is chosen, Windows monitors keystrokes and mouse movements, starting the screen saver after a period of inactivity. However, Windows does not start the screen saver if any of the following conditions exist:

•	The active application is not a Windows-based application.

•	A computer-based training (CBT) window is present.

•	The active application receives the WM_SYSCOMMAND message with wParam set to the SC_SCREENSAVE value, but does not pass the message to the DefWindowProc function.

Screen savers contain specific exported functions, resource definitions, and variable declarations. The static-link library SCRNSAVE.LIB contains the main function and other startup code required for a screen saver. When a screen saver starts, the startup code in SCRNSAVE.LIB creates a full-screen window. The window class for this window is declared as follows.

WNDCLASS cls;

cls.hCursor        = NULL;

cls.hIcon          = LoadIcon(hInst, MAKEINTATOM(ID_APP));

cls.lpszMenuName   = NULL;

cls.lpszClassName  = "WindowsScreenSaverClass";

cls.hbrBackground  = GetStockObject(BLACK_BRUSH);

cls.hInstance      = hInst;

cls.style          = CS_VREDRAW | CS_HREDRAW |

                     CS_SAVEBITS | CS_DBLCLKS;

cls.lpfnWndProc    = (WNDPROC) ScreenSaverProc;

cls.cbWndExtra     = 0;

cls.cbClsExtra     = 0;

To create a screen saver, most developers create a source-code module containing three required functions and link them with SCRNSAVE.LIB. A screen saver module is responsible only for configuring itself and for providing visual effects.

One of the three required functions in a screen saver module is ScreenSaverProc. This function processes specific messages and passes any unprocessed messages back to SCRNSAVE.LIB. Following are some of the typical messages processed by ScreenSaverProc.

Message	Meaning
WM_CREATE	Retrieve any initialization data from the file REGEDIT.INI. Set a window timer for the screen saver window. Perform any other required initialization.
WM_ERASEBKGND	Erase the screen saver window and prepare for subsequent drawing operations.
WM_TIMER	Perform drawing operations.
WM_DESTROY	Destroy the timer(s) created when the application processed the WM_CREATE message. Perform any additional required cleanup.
ScreenSaverProc passes unprocessed messages to SCRNSAVE.LIB by calling the DefScreenSaverProc function. The following table describes how this function processes various messages.

Message	Action
WM_SETCURSOR	Sets the cursor to the null cursor, removing it from the screen.
WM_PAINT	Paints the screen background.
WM_LBUTTONDOWN	Terminates the screen saver.
WM_MBUTTONDOWN	Terminates the screen saver.
WM_RBUTTONDOWN	Terminates the screen saver.
WM_KEYDOWN	Terminates the screen saver.
WM_MOUSEMOVE	Terminates the screen saver.
WM_ACTIVATE	If wParam is FALSE, terminates the screen saver.
The second required function in a screen saver module is ScreenSaverConfigureDialog. This function displays a dialog box that enables the user to configure the screen saver. (Thus, an application must provide a corresponding dialog box template.) Windows displays the configuration dialog box when the user chooses the Setup button in the Screen Saver box in the Desktop application in Control Panel. The data entered by the user with the configuration dialog box is stored in the REGEDIT.INI file.

The third required function in a screen saver module is RegisterDialogClasses. This function must be called by all screen saver applications. However, applications that do not require special windows or custom controls in the configuration dialog box can simply return TRUE. Applications requiring custom controls or special windows should use this function to register the corresponding window classes.

In addition to creating a module that supports the three functions just described, a screen saver should supply an icon. This icon is visible only when the screen saver is run as a standalone application. (To be run by Control Panel, a screen saver must have the .SCR filename extension; to be run as a standalone application, it must have the .EXE filename extension.) The icon must be identified in the screen saver's resource file by the constant ID_APP, which is defined in the header file SCRNSAVE.H.

One final requirement is a screen saver description string. The resource file for a screen saver must contain a descriptive string that Control Panel displays as the screen saver name. The description string must be the first string in the resource file's string table (identified with the ordinal value 1).


Using the Screen Saver Functions

•	Creating a screen saver

•	Installing new screen savers

•	Adding help


Creating a Screen Saver

This section contains example code taken from a screen saver application. At intervals ranging from 1 through 10 seconds, this application repaints the screen with one of four colors: white, light gray, dark gray, and black. The application paints the screen each time it receives a WM_TIMER message. The user can adjust the interval at which this message is sent by displaying the application's configuration dialog box and adjusting a single horizontal scroll bar.


Supporting the Configuration Dialog Box

Most screen savers provide a configuration dialog box to let the user specify customization data such as unique colors, drawing speeds, line thicknesses, fonts, and so on. To support the configuration dialog box, the application must provide a dialog box template and must also support the ScreenSaverConfigureDialog function. Following is the dialog box template for the sample application.

DLG_SCRNSAVECONFIGURE DIALOG 6, 18, 160, 63
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION |
    WS_SYSMENU
CAPTION "Sample Screen-Saver Setup"
FONT 8, "MS Sans Serif"
BEGIN
    GROUPBOX      "Redraw Speed", 101, 0, 6, 98, 40
    SCROLLBAR     ID_SPEED, 5, 31, 89, 10
    LTEXT         "Fast", 103, 6, 21, 20, 8
    LTEXT         "Slow", 104, 75, 21, 20, 8
    PUSHBUTTON    "OK", ID_OK, 117, 10, 40, 14
    PUSHBUTTON    "Cancel", ID_CANCEL, 117, 32, 40, 14
END

You must define the constant used to identify the dialog box template by using the decimal value 2003, as in the following example.

#define  DLG_SCRNSAVECONFIGURE 2003

The following example shows the ScreenSaverConfigureDialog function found in the sample application.

#define MINVEL  1               /* minimum redraw-speed value    */

#define MAXVEL  10              /* maximum redraw-speed value    */

#define DEFVEL  5               /* default redraw-speed value    */

LONG    lSpeed = DEFVEL;        /* redraw-speed variable         */

extern HINSTANCE hMainInstance; /* screen saver instance handle  */

CHAR   szAppName[80];           /* .INI section name             */

CHAR   szTemp[20];              /* temporary array of characters */

CHAR   szRedrawSpeed[] = "Redraw Speed";   /* .INI speed entry   */

BOOL WINAPI ScreenSaverConfigureDialog(hDlg, message, wParam, lParam)

HWND  hDlg;

UINT  message;

DWORD wParam;

LONG  lParam;

{

    static HWND hSpeed; /* handle of speed scroll bar */

    static HWND hOK;    /* handle of OK push button */

    switch(message)

    {

        case WM_INITDIALOG:

            /* Retrieve the application name from the .RC file. */

            LoadString(hMainInstance, idsAppName, szAppName, 40);

            /* Retrieve the .INI (or registry) filename. */

            LoadString(hMainInstance, idsIniFile, szIniFile,

                MAXFILELEN);

            /* Retrieve any redraw-speed data from the registry. */

            lSpeed = GetPrivateProfileInt(szAppName, szRedrawSpeed,

                DEFVEL, szIniFile);

            /*

             * If the initialization file does not contain an entry

             * for this screen saver, use the default value.

             */

            if(lSpeed > MAXVEL || lSpeed < MINVEL)

                lSpeed = DEFVEL;

            /* Initialize the redraw-speed scroll bar control. */

            hSpeed = GetDlgItem(hDlg, ID_SPEED);

            SetScrollRange(hSpeed, SB_CTL, MINVEL, MAXVEL, FALSE);

            SetScrollPos(hSpeed, SB_CTL, lSpeed, TRUE);

            /* Retrieve a handle of the OK push button control. */

            hOK = GetDlgItem(hDlg, ID_OK);

            return TRUE;

        case WM_HSCROLL:

            /*

             * Process scroll bar input, adjusting the lSpeed

             * value as appropriate.

             */

            switch (LOWORD(wParam))

                {

                    case SB_PAGEUP:

                        --lSpeed;

                    break;

                    case SB_LINEUP:

                        --lSpeed;

                    break;

                    case SB_PAGEDOWN:

                        ++lSpeed;

                    break;

                    case SB_LINEDOWN:

                        ++lSpeed;

                    break;

                    case SB_THUMBPOSITION:

                        lSpeed = HIWORD(wParam);

                    break;

                    case SB_BOTTOM:

                        lSpeed = MINVEL;

                    break;

                    case SB_TOP:

                        lSpeed = MAXVEL;

                    break;

                    case SB_THUMBTRACK:

                    case SB_ENDSCROLL:

                        return TRUE;

                    break;

                }

                if ((int) lSpeed <= MINVEL)

                    lSpeed = MINVEL;

                if ((int) lSpeed >= MAXVEL)

                    lSpeed = MAXVEL;

                SetScrollPos((HWND) lParam, SB_CTL, lSpeed, TRUE);

            break;

        case WM_COMMAND:

            switch(LOWORD(wParam))

            {

                case ID_OK:

                   /*

                    * Write the current redraw-speed variable to

                    * the .INI file.

                    */

                    wsprintf(szTemp, "%ld", lSpeed);

                    WritePrivateProfileString(szAppName, szRedrawSpeed,

                        szTemp, szIniFile);

                case ID_CANCEL:

                    EndDialog(hDlg, LOWORD(wParam) == ID_OK);

                return TRUE;

            }

    }

    return FALSE;

}

In addition to providing the dialog box template and supporting the ScreenSaverConfigureDialog function, an application must also support the RegisterDialogClasses function. This function registers any nonstandard window classes required by the screen saver. Because the sample application used only standard window classes in its dialog box procedure, this function simply returns TRUE, as in the following example.

BOOL WINAPI RegisterDialogClasses(hInst)

HANDLE  hInst;

{

    return TRUE;

}


Supporting the Screen Saver Window Procedure

Each screen saver must support a window procedure named ScreenSaverProc. Like most window procedures, ScreenSaverProc processes a set of specific messages and passes any unprocessed messages to a default procedure. However, instead of passing them to the DefWindowProc function, ScreenSaverProc passes unprocessed messages to the DefScreenSaverProc function. Another difference between ScreenSaverProc and a normal window procedure is that the handle passed to ScreenSaverProc identifies the entire desktop rather than a client window. The following example shows the ScreenSaverProc window procedure for the sample screen saver.

LONG WINAPI ScreenSaverProc(hwnd, message, wParam, lParam)

HWND  hwnd;

UINT  message;

DWORD wParam;

LONG  lParam;

{

static HDC          hdc;    /* device-context handle */

static RECT         rc;     /* RECT structure */

static UINT         uTimer; /* timer identifier */

    switch(message)

    {

        case WM_CREATE:

            /* Retrieve the application name from the .RC file. */

            LoadString(hMainInstance, idsAppName, szAppName, 40);

            /* Retrieve the .INI (or registry) filename. */

            LoadString(hMainInstance, idsIniFile, szIniFile,

                MAXFILELEN);

            /* Retrieve any redraw-speed data from the registry. */

            lSpeed = GetPrivateProfileInt(szAppName, szRedrawSpeed,

                DEFVEL, szIniFile);

           /*

            * Set a timer for the screen saver window using the

            * redraw-rate stored in REGEDIT.INI.

            */

            uTimer = SetTimer(hwnd, 1, lSpeed * 1000, NULL);

            break;

        case WM_ERASEBKGND:

           /*

            * The WM_ERASEBKGND message is issued before the

            * WM_TIMER message, allowing the screen saver to

            * paint the background as appropriate.

            */

            hdc = GetDC(hwnd);

            GetClientRect (hwnd, &rc);

            FillRect (hdc, &rc, GetStockObject(BLACK_BRUSH));

            ReleaseDC(hwnd,hdc);

            break;

        case WM_TIMER:

           /*

            * The WM_TIMER message is issued at (lSpeed * 1000)

            * intervals, where lSpeed == .001 seconds. This

            * code repaints the entire desktop with a white,

            * light gray, dark gray, or black brush each

            * time a WM_TIMER message is issued.

            */

            hdc = GetDC(hwnd);

            GetClientRect(hwnd, &rc);

            if (i++ <= 4)

                FillRect(hdc, &rc, GetStockObject(i));

            else

                (i = 0);

            ReleaseDC(hwnd,hdc);

            break;

        case WM_DESTROY:

           /*

            * When the WM_DESTROY message is issued, the screen saver

            * must destroy any of the timers that were set at WM_CREATE

            * time.

            */

            if (uTimer)

                KillTimer(hwnd, uTimer);

            break;

    }

   /*

    * DefScreenSaverProc processes any messages

    * ignored by ScreenSaverProc.

    */

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

}


Creating a Module-Definition File

The ScreenSaverProc and ScreenSaverConfigureDialog functions must be exported in the application's module-definition file; RegisterDialogClasses should not be exported, however. The following example shows the module-definition file for the sample application.

NAME    SSTEST.SCR

DESCRIPTION 'SCRNSAVE : Test'

STUB    'WINSTUB.EXE'

EXETYPE WINDOWS

CODE    MOVEABLE

DATA    MOVEABLE MULTIPLE

HEAPSIZE  1024

STACKSIZE 4096

EXPORTS

        ScreenSaverProc

        ScreenSaverConfigureDialog


Installing New Screen Savers

When compiling the list of available screen savers, Control Panel searches the Windows startup directory for files with the .SCR extension. Because screen savers are standard Windows executable files with .EXE extensions, you must rename them so they have .SCR extensions and copy them to the correct directory.


Adding Help

The configuration dialog box for a screen saver typically includes a Help button. Screen saver applications can check for the Help button identifier and call the WinHelp function in the same way Help is provided in other Windows-based applications.


Screen Saver Functions

Following are the functions used with screen savers.

DefScreenSaverProc
RegisterDialogClasses
ScreenSaverConfigureDialog
ScreenSaverProc


Shell Dynamic Data Exchange Interface

This overview describes the dynamic data exchange (DDE) interface of Program Manager (PROGMAN.EXE). Program Manager is a shell — that is, an application that enables users to group, start, and otherwise control other applications for the Microsoft® Windows® operating system.


About Program Manager Initialization

Program Manager starts automatically when the user starts Windows and runs as long as Windows is in use. When it starts, Program Manager displays one or more windows within its main window. Each window contains icons that correspond to logically related Windows-based applications. For example, the Accessories window contains icons for Windows Write, Paintbrush, Notepad, and other accessory applications.

Program Manager stores initialization and configuration information in the registry. This information is stored under the Settings, Groups, and Restrictions keys in the following section of the registry:

HKEY_CURRENT_USER\Software\Microsoft\WindowsNT\
        CurrentVersion\Program Manager

Additional information is stored in the Program Groups key in the following section of the registry:

HKEY_LOCAL_MACHINE\SOFTWARE


Settings Key

The Settings key contains information that Program Manager uses to configure its environment. The following entries appear in the Settings key.

Entry	Description
MinOnRun	Specifies whether to minimize Program Manager when an application is started.
AutoArrange	Specifies whether Program Manager should automatically arrange icons within groups.
SaveSettings	Specifies whether to save the position of the Program Manager window when Program Manager terminates.
DISPLAY.DRV	Specifies the filename of the display driver in use when Program Manager last terminated. When Program Manager starts, it compares this value to the filename of the display driver currently in use. If the names are different, Program Manager re-extracts the application icons.
Window	Specifies the location and dimensions of the Program Manager window.
Order	Specifies the order that the groups listed in the Groups key appear in the Program Manager window.
Startup	Specifies the name of the startup group. Program Manager automatically starts the applications in the startup group whenever it starts.


Groups Key

The windows that appear in the Program Manager window correspond to group files. From the user's perspective, a group file is a collection of icons that represent logically related applications, but from the programmer's perspective, a group file is actually a collection of data. This data includes the color information for the icons (AND and XOR masks), an offset to the resource header of each icon, the ideal resolution for displaying each icon, the name of the executable (.EXE) file that contains the application, and so on.

There are two types of groups: common and personal. A common group is shared among multiple users through network connections; a personal group is not shared. Program Manager stores information about personal groups under the Groups key. It stores information about common groups under the HKEY_LOCAL_MACHINE\SOFTWARE key.

The Groups key of the registry identifies the names of the group files that Program Manager displays as unique windows or icons. The groups must be numbered, but they need not be listed in any particular order. Program Manager never changes the number of an existing group.


Restrictions Key

The Restrictions key controls whether certain features of Program Manager are enabled or disabled. The following entries can appear in the Restrictions key.

Entry	Description
NoRun	Specifies whether to disable the Run command on the File menu. If this entry is set to 1, the Run command is disabled. If this entry is set to 0, the Run command is enabled. The default is 0 if no value is specified.
NoClose	Specifies whether to prevent the user from closing Program Manager through the File menu, the System menu, the ALT+F4 key combination, or the Task List. If this entry is set to 1, closing is prevented. If this entry is set to 0, closing is allowed. The default is 0 if no value is specified.
EditLevel	Controls the extent to which the user can modify read-write groups. (Shared read-only groups cannot be modified.) This entry can be set to one of the following values.
Value	Action
0	Allows any modifications to the group. This is the default value.
1	Prevents the user from creating, deleting, or renaming groups.
2	Prevents the user from creating, deleting, or renaming groups and from creating or deleting items in a group.
3	Prevents the user from creating, deleting, or renaming groups; from creating or deleting items in a group; and from changing command lines for items in a group.
4	Prevents the user from changing any property of an item in a group; from creating, deleting, or renaming groups; from creating or deleting items in a group; and from changing command lines for items in a group.
NoFileMenu	Specifies whether to disable the File menu and all of its commands. If this entry is set to 1, the File menu is disabled. If this entry is set to 0, the menu is enabled. The default setting is 0 if no value is specified.
NoSaveSettings	Specifies whether to disable the Save Settings on Exit command on the Options menu. If this entry is set to 1, the Save Settings on Exit command is disabled. If this entry is set to 0, the command is enabled. The default setting is 0 if no value is specified.
Setting the value of NoRun to 1 and the value of EditLevel to 3 prevents a user from using Program Manager to run any applications not already in a program group.


Command-String Interface

Program Manager has a DDE command-string interface that allows other applications to create, display, delete, and reload groups; add items to groups; replace items in groups; delete items from groups; and close Program Manager. The following commands perform these actions:

AddItem	ExitProgman
CreateGroup	Reload
DeleteGroup	ReplaceItem
DeleteItem	ShowGroup
For example, the setup program for an application can use these commands to instruct Program Manager to install the application's icon in a group.

Multiple commands can be concatenated; each command must be contained in square brackets, and parameters must be contained in parentheses and separated by commas. Quotation marks must delimit arguments that contain spaces, brackets, or parentheses. For example, the following set of commands adds WINAPP.EXE to the Windows Applications group:

[CreateGroup("Windows Applications")]

[ShowGroup("My Group",1)]

[AddItem(winapp.exe,Win App,winapp.exe,2)]

To use these commands, an application must first initiate a DDE conversation with Program Manager. The application and topic names for the conversation are both PROGMAN. Then the application sends the WM_DDE_EXECUTE message, specifying the appropriate command and its parameters.

Note  The user can configure Windows to use a shell other than Program Manager as the default. Therefore, do not design an application that assumes Program Manager will be available for a DDE conversation.

The following sections describe Program Manager DDE command strings in detail. In the syntax blocks in the following sections, brackets enclose optional parameters.


CreateGroup

The syntax for the CreateGroup command has this form:

CreateGroup(GroupName[,CommonGroupFlag])

The CreateGroup command instructs Program Manager to create a new group or activate the window of an existing group.

Following are the parameters for this command:

GroupName

Identifies the group to be created or activated. This parameter is a string. If a group already exists with the name specified by GroupName, CreateGroup activates the group window.

CommonGroupFlag

Specifies whether the new group is a common group or a personal group. If this parameter is 1, a common group is created; if it is 0, a personal group is created. To create a common group, the user currently logged on must have administrative privileges. If this parameter is 1 but the user does not have administrative privileges, the command fails. The default value of this parameter is 1 (common group) if no value is specified and if the user has administrative privileges. The default value is 0 (personal group) if no value is specified and the user does not have administrative privileges.

  Note  If the second parameter of the CreateGroup command specifies the path of the group file (as was required in Windows version 3.1), the parameter is ignored.


ShowGroup

The syntax for the ShowGroup command has this form:

ShowGroup(GroupName,ShowCommand[,CommonGroupFlag])

The ShowGroup command instructs Program Manager to minimize, maximize, or restore the window of an existing group.

Following are the parameters for this command:

GroupName

Identifies the group window to be minimized, maximized, or restored.

ShowCommand

Specifies the action Program Manager is to perform on the group window. This parameter is an integer. It must have one of the following values.

Value	Action
1	Activates and displays the group window. If the window is minimized or maximized, Windows restores it to its original size and position.
2	Activates the group window and displays it as an icon.
3	Activates the group window and displays it as a maximized window.
4	Displays the group window in its most recent size and position. The window that is currently active remains active.
5	Activates the group window and displays it in its current size and position.
6	Minimizes the group window.
7	Displays the group window as an icon. The currently active window remains active.
8	Displays the group window in its current state. The currently active window remains active.
CommonGroupFlag

Specifies whether the group is a common group or a personal group. If this parameter is 1, the group being minimized, maximized, or restored is a common group; if it is 0, the group is a personal group. This parameter defaults to 1 (common group) if no value is specified. To minimize, maximize, or restore a common group, the user currently logged on must have administrative privileges. If this parameter is 1 but the user does not have administrative privileges, the command fails.


DeleteGroup

The syntax for the DeleteGroup command has this form:

DeleteGroup(GroupName[,CommonGroupFlag])

The DeleteGroup command instructs Program Manager to delete an existing group.

Following are the parameters for this command:

GroupName

Identifies the group to be deleted.

CommonGroupFlag

Specifies whether the group is a common group or a personal group. If this parameter is 1, the group being deleted is a common group; if it is 0, the group is a personal group. This parameter defaults to 1 (common group) if no value is specified. To delete a common group, the user currently logged on must have administrative privileges. If this parameter is 1 but the user does not have administrative privileges, the command fails.

  Note  If the second parameter of the DeleteGroup command specifies the path of the group file (as was required in Windows version 3.1), the parameter is ignored.


Reload

The syntax for the Reload command has this form:

Reload(GroupName[,CommonGroupFlag])

The ReloadGroup command instructs Program Manager to remove and reload an existing group. An application that modifies group files can use this command to cause Program Manager to update the groups when it has finished making modifications.

Following are the parameters for this command:

GroupName

Identifies the group to be removed and reloaded. If no value is specified for the GroupName parameter, Program Manager unloads all groups and reloads the groups specified in the Groups key of the registry. The Settings and Restrictions keys are not reread.

CommonGroupFlag

Specifies whether the group is a common group or a personal group. If this parameter is 1, the group being reloaded is a common group; if it is 0, the group is a personal group. This parameter defaults to 1 (common group) if no value is specified. To reload a common group, the user currently logged on must have administrative privileges. If this parameter is 1 but the user does not have administrative privileges, the command fails.


AddItem

The syntax for the AddItem command has this form:

AddItem(CmdLine[,
    Name[,IconPath[,IconIndex[,xPos,yPos[,DefDir[,
    HotKey[,fMinimize[fSeparateMemSpace] ] ] ] ] ] ])

The AddItem command instructs Program Manager to add an icon to an existing group. There is a limit of 50 items per group.

Following are the parameters for this command:

CmdLine

Specifies the full command line required to run the application. This parameter is a string. At a minimum, this string is the name of the executable file for the application. It can also include the full path of the application and any parameters required by the application.

Name

Specifies the title that is displayed below the icon in the group window.

IconPath

Identifies the filename for the icon to be displayed in the group window. This parameter is a string. This file can be either a Windows-based executable file or an icon file. If no value is specified for the IconPath parameter, Program Manager uses the first icon in the file specified by the CmdLine parameter if that file is an executable file. If CmdLine specifies an associated file, Program Manager uses the first icon of the associated executable file. The association is taken from the registry. (For more information about the registry, see Registry.) If CmdLine specifies neither an executable file nor an associated executable file, Program Manager uses a default icon.

IconIndex

Specifies the index of the icon in the file identified by the IconPath parameter. The IconIndex parameter is an integer. PROGMAN.EXE contains five built-in icons that can be used for programs not written for Windows.

xPos

Specifies the horizontal position of the icon in the group window. This parameter is an integer. Both the xPos and yPos parameters must be used to specify the position of the icon. If the position is not specified, Program Manager places the icon in the next available space.

yPos

Specifies the vertical position of the icon in the group window. This parameter is an integer. Both the xPos and yPos parameters must be used to specify the position of the icon. If the position is not specified, Program Manager places the icon in the next available space.

DefDir

Specifies the name of the default (or working) directory. This parameter is a string.

HotKey

Identifies a hot (or shortcut) key that is specified by the user.

fMinimize

Specifies whether an application window is to be minimized when first displayed.

fSeparateMemSpace

Specifies whether a 16-bit application runs in a separate memory space.


ReplaceItem

The syntax for the ReplaceItem command has this form:

ReplaceItem(ItemName)

The ReplaceItem command instructs Program Manager to delete an item and record the position of the deleted item. Program Manager adds a new item (specified by the next AddItem command) at this recorded position.

Following is the parameter for this command:

ItemName

Specifies the item to be deleted. Its position is recorded by Program Manager.


DeleteItem

The syntax for the DeleteItem command has this form:

DeleteItem(ItemName)

The DeleteItem command instructs Program Manager to delete an item from the currently active group.

Following is the parameter for this command:

ItemName

Specifies the item to be deleted from the currently active group.


ExitProgman

The syntax for the ExitProgman command has this form:

ExitProgman(bSaveGroups)

If Program Manager was started by another application, the ExitProgman command instructs Program Manager to terminate and, optionally, save its group information.

Following is the parameter for this command:

bSaveGroups

Specifies a Boolean value that, if it is nonzero, causes Program Manager to save its group information before closing. If bSaveGroups is zero, Program Manager does not save its group information.


Requesting Group Information

Program Manager can provide information about its groups to an application. Applications can request this information from Program Manager by using the PROGMAN topic.

An application can obtain a list of Program Manager groups by issuing a request for the Group item. Program Manager provides the list in CF_TEXT format. The list consists of group-name strings separated by carriage returns.

An application can use a group name as an item name to request information about the group. Program Manager provides this information in CF_TEXT format. The fields of group information are separated by commas. The first line of the information contains the group name (in quotation marks), the path of the group file, and the number of items in the group. Each subsequent line contains information about an item in the group, including the command line (in quotation marks), the default directory, the icon path, the position in the group, the icon index, the shortcut key (in numeric form), and the minimize flag.


Shell Library

A shell is an application that enables users to group, start, and otherwise control other applications. This overview describes features of the shell for the Microsoft® Windows® operating system.


About the Shell Library

The following features are supported by the dynamic-link library SHELL.DLL:

•	The drag-drop feature

•	Associations (used) to find and start applications

•	Extraction of icons from executable files

The header file for the functions that support these features is SHELLAPI.H. The library is SHELL32.LIB.


Using the Shell Features

•	Using the drag-drop feature

•	Using associations to find and start applications

•	Extracting icons from executable files


Using the Drag-Drop Feature

When an application implements the drag-drop feature, a user can select one or more files in File Manager, drag them to an open application, and drop them there. The application in which the files were dropped receives a message it can use to retrieve the filenames and the coordinates of the point at which the files were dropped.

An application that can accept dropped files from File Manager calls the DragAcceptFiles function for one or more of its windows. When the user releases the mouse button to drop a file or files in the window specified in the call to DragAcceptFiles, File Manager sends the application a WM_DROPFILES message. (File Manager does not send the WM_DROPFILES message to an application unless the application calls DragAcceptFiles.) WM_DROPFILES contains a handle of a structure the application can query to retrieve the name of the dropped file and the coordinates of the cursor when the file was dropped. The application can use the DragQueryFile function to retrieve a count of the files that were dropped and their names. The DragQueryPoint function returns the window coordinates of the cursor when the user released the mouse button.

To free the memory allocated by the system for the WM_DROPFILES message, an application calls the DragFinish function when it is finished.

For example, an application can call the DragAcceptFiles function when it starts and call a drag-drop function when it receives a WM_DROPFILES message, as shown in the following example.

case WM_CREATE:

    DragAcceptFiles(hwnd, TRUE);

    break;

case WM_DROPFILES:

    DragFunc(hwnd, wParam); /* application-defined function */

    break;

case WM_DESTROY:

    DragAcceptFiles(hwnd, FALSE);

    break;

The following example uses the DragQueryPoint function to determine where to begin to write text. The first call to the DragQueryFile function determines the number of dropped files. The loop writes the name of each file, beginning at the point returned by DragQueryPoint.

POINT pt;

WORD cFiles, a;

char lpszFile[80];

DragQueryPoint((HANDLE) wParam, &pt);

cFiles = DragQueryFile((HANDLE) wParam, 0xFFFF, (LPSTR) NULL, 0);

for(a = 0; a < cFiles; pt.y += 20, a++) {

    DragQueryFile((HANDLE) wParam, a, lpszFile, sizeof(lpszFile));

    TextOut(hdc, pt.x, pt.y, lpszFile, lstrlen(lpszFile));

}

DragFinish((HANDLE) wParam);


Using Associations to Find and Start Applications

File Manager includes an Associate dialog box that makes it possible for users to associate a filename extension with a specific application. File Manager stores these associations in the registry (under HKEY_CURRENT_USER\Software\Description\Microsoft\Windows\CurrentVersion\Extensions). If a file has a filename extension that is associated with an application, that application starts automatically whenever a user double-clicks that file in File Manager.

Using the FindExecutable and ShellExecute functions, applications can take advantage of such associations to find and start applications or open and print files.

An application can use the FindExecutable function to retrieve the name and handle of the executable file that is associated with a specified filename. The ShellExecute function either opens or prints a specified file, depending on the value of its lpOperation parameter. To open a document file, the function relies on the association of the filename extension.

Windows 95: You can use ShellExecute to open or explore a Windows 95 folder. To open a folder, use either of the following calls:

ShellExecute(handle, NULL, "path_to_folder", NULL, NULL, SW_SHOWNORMAL);

or

ShellExecute(handle, "open", "path_to_folder", NULL, NULL, SW_SHOWNORMAL);

To explore a folder, use the following call:

ShellExecute(handle, "explore", "path_to_folder", NULL, NULL, SW_SHOWNORMAL);

If the lpOperation parameter is NULL, the function opens the file specified by its lpFile parameter. If lpOperation is "open" or "explore", the function will force a open window or explorer.


Extracting Icons from Executable Files

An application can use the ExtractIcon function to retrieve the handle of an icon from a specified executable file, dynamic-link library, or icon file. The following example uses the DragQueryPoint function to retrieve the coordinates of the point where a file was dropped, the DragQueryFile function to retrieve the filename of a dropped file, and the ExtractIcon function to retrieve the handle of the first icon in the file, if any.

POINT pt;

WORD cFiles;

HDC hdc;

char lpszFile[80];

HANDLE hCurrentInst, hicon;

DragQueryPoint((HANDLE) wParam, &pt);

cFiles = DragQueryFile((HANDLE) wParam, 0xFFFF, NULL, NULL);

if(cFiles > 1) {

    TextOut(hdc, pt.x, pt.y,

        "Please drop only one icon file.", 31);

    return FALSE;

}

else {

    DragQueryFile((HANDLE) wParam, 0, lpszFile, sizeof(lpszFile));

    hCurrentInst = (HINSTANCE) GetWindowLong(hwnd, GWL_HINSTANCE);

    hicon = ExtractIcon(hCurrentInst, lpszFile, 0);

    if (hicon == NULL)

        TextOut(hdc, pt.x, pt.y, "No icons found.", 15);

    else if (hicon == (HICON) 1)

        TextOut(hdc, pt.x, pt.y,

            "File must be .EXE, .ICO, or .DLL.", 33);

    else

        DrawIcon(hdc, pt.x, pt.y, hicon);

}

DragFinish((HANDLE) wParam);


Shell Library Reference

The following functions, interfaces, messages, and structures are associated with shell features.


Shell Library Functions

The following functions are used to implement shell features.

DragAcceptFiles
DragFinish
DragQueryFile
DragQueryPoint
ExtractAssociatedIcon
ExtractIcon
FindExecutable
ShellAbout
ShellExecute
ShellExecuteEx


Shell Library Interfaces

The following interfaces are used to implement shell features.

IContextMenu
ICopyHook
IExtractIcon
IShellPropSheetExt
IShellExtInit
IShellLink
IShellFolder
IEnumIDList


Shell Library Messages

The following message is used to implement shell features.

WM_DROPFILES


Shell Library Structures

The following structure is used to implement shell features.

SHELLEXECUTEINFO


About Windows 95 Shell Extensions

Applications can extend the shell of the Microsoft Windows 95 operating system in a number of ways. A shell extension enhances the shell by providing additional ways to manipulate file objects, by simplifying the task of browsing through the file system and networks, or by giving the user easier access to tools that manipulate objects in the file system. For example, a shell extension can assign an icon to each file or add commands to the context menu and file menu for a file.

Windows 95 supports the following types of shell extensions:

•	Context menu handlers: These add items to the context menu for a particular file object. (The context menu is displayed when the user clicks a file object with the alternate mouse button.)

•	Drag-and-drop handlers: These are context menu handlers that the system calls when the user drops an object after dragging it to a new position.

•	Icon handlers: These typically add instance-specific icons for file objects. They can also be used to add icons for all files belonging to the same class.

•	Property-sheet handlers: These add pages to the property sheet dialog box that the shell displays for a file object. The pages are specific to a class of files or a particular file object.

•	Copy-hook handlers: These are called when a folder object is about to be copied, moved, deleted, or renamed. The handler can either allow or prevent the operation.

The design of a shell extension is based on the Component Object Model in Object Linking and Embedding (OLE). The shell accesses an object through interfaces. An application implements the interfaces in a shell extension dynamic-link library (DLL), which is similar to an In-Process Server DLL in OLE.

For more information, see "Extending the Windows 95 Shell" in the Windows 95 Guide to Programming.


Windows 95 Shell Extensions on Windows NT

Applications that employ Windows 95 shell-extension handlers (icon handlers, property-page handlers, context-menu handlers, copy hooks, drag-and-drop handlers, and other such DLL-based shell extension classes) can run on the next release of Windows NT with the new shell. To do so, you must take one additional step while registering during setup. This topic describes how to install such applications on Windows NT.

Because shell extensions handlers run in a system process, namely the shell process, Windows NT administrators require control over which shell handlers are allowed to run. When the new shell is available on Windows NT, administrators will have control over which shell handlers can run in much the same way they can now control which device drivers can run.

For the Windows NT shell to recognize and run a shell-extension handler, the handler's CLSID must be listed in the Registry Editor under a new registry key (as well as being registered in the typical way as specified for Windows 95). This registry key contains a list of the handlers that are approved for the shell to run. By default, this key's access control permissions allow only someone with administrator privileges to modify the list.

The CLSID for the extension must be registered at the following location:

HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved

To register the extension, a "named value" should be added to the "Approved" key. The name of the value must be the string form of the CLSID as obtained from the StringFromCLSID() function, which is used elsewhere in the registry. The value itself should be the ProgID. The ProgID is stored here simply to make inspection of the registry easier, as it is easier to decipher than a CLSID. The Windows NT shell does not look at this value, however, only at the presence or absence of the CLSID.

Your setup application may or may not be able to write to this key, depending on the privileges of the person installing the application. The setup application should attempt to open the key described above, requesting the KEY_SET_VALUE permission. If it succeeds, the new CLSID can be added to fully register the corresponding shell extension. If the request fails with a security violation, then the person installing the application does not have permission to register new shell extensions. In this case, the setup application might warn the user that some application features will not be available unless an administrator turns them on (by installing the application, or by writing the registry keys directly). Or, if the shell extension is crucial to the application's functioning, the setup application might cause the installation to fail completely, notifying the user that the program must be installed by an administrator.

When setting up on Windows 95, it is not necessary to write the CLSID to this key, although writing it is harmless. Note, however, that the key may not exist in a Windows 95 installation, so that if your setup application does attempt to open the key, it may fail.

The following sample code details this process. Full error handling has been omitted.

#include <windows.h>

#include <string.h>

void main(void)

{

     //

     // First, attempt to open the registry key where approved extensions are

     // listed. Note the extra slashes within the second parameter (the

     // registry path string).

     //

     long err;

     HKEY hkApproved;

     err = RegOpenKeyEx(

               HKEY_LOCAL_MACHINE,

"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved",

               0,

               KEY_SET_VALUE,

               &hkApproved);

     if (err == ERROR_ACCESS_DENIED)

     {

          //

          // The user does not have permissions to add a new value to this key. In this

          // case, a reasonable action would be to warn the user that some

          // application features will not be available unless an administrator

          // installs the application. If the shell extension is central to the

          // functioning of the application, tell the user that the install

          // can only be performed by an administrator, and stop the install.

          //

     }

     else if (err == ERROR_FILE_NOT_FOUND)

     {

          //

          // The key does not exist. This should only happen if setup is running

          // on Windows 95 instead of Windows NT, or if you are installing on an older

          // version of either operating system that does not have the Windows 95-style UI.

          //

     }

     else if (err != ERROR_SUCCESS)

     {

          //

          // some other problem...

          //

     }

     else

     {

          //

          // The open of the key succeeded. Now register the new shell extension

          // under this key. This requires having the ProgID and string form of the

          // CLSID handy.

          //

          //

          // Assume that lpstrProgID contains our ProgID string.

          //

            LPSTR lpstrProgID = "My Bogus Class";

          //

          // Assume that clsidExtension contains the CLSID struct. The code below

          // creates a string form this CLSID. If  a string version of

          // the CLSID is already handy, skip this code.

          //

          CLSID clsidExtension = {0x11111111, 0x1111, 0x1111, 0x11, 0x11,

                                  0x11, 0x11, 0x11, 0x11, 0x11, 0x11};

          HRESULT hr;

          LPOLESTR lpolestrCLSID;

          CHAR rgchCLSID[40];

          CoInitialize(NULL);

          hr = StringFromCLSID(clsidExtension, &lpolestrCLSID);

          //

          // StringFromCLSID returns a Unicode string, so convert to ANSI for

          // calling the registry. Note that on Windows NT you can call the Unicode

          // version of the registry API instead.

          //

          WideCharToMultiByte(CP_ACP,     0, lpolestrCLSID, -1, rgchCLSID, 40,

                                    NULL, NULL);

          CoTaskMemFree(lpolestrCLSID);

          CoUninitialize();

          //

          // Now add the new value to the registry.

          // Note that each new shell extension CLSID must be registered here.

          //

          err = RegSetValueEx(

                    hkApproved,

                    rgchCLSID,

                    0,

                    REG_SZ,

                    (const BYTE *)lpstrProgID,

                    strlen(lpstrProgID));

          //

          // Finally, close the key.

          //

          err = RegCloseKey(hkApproved);

     }

}


Bitmaps

A bitmap is a powerful graphics object used to create, manipulate (scale, scroll, rotate, and paint), and store images as files on a disk.


About Bitmaps

A bitmap is one of seven objects that can be selected into a device context. The other six objects are the pen, brush, font, region, logical palette, and path. (For more information about device contexts and related objects, see Device Contexts.)

In the Microsoft® Win32® application programming interface (API), Control Panel applications are examples of applications that use bitmaps. When a user selects wallpaper for the desktop, the user actually selects a bitmap, which Windows uses to paint the desktop background.

Windows creates this pattern by repeatedly drawing a 32- by 32-pixel pattern on the desktop. This pattern is stored as a bitmap in the file REDBRICK.BMP.

From the user's point of view, a bitmap is a rectangle of pixels that form a visual image. However, from the developer's perspective, a bitmap is a collection of structures that specify or contain the following elements:

•	A header that describes the resolution of the device on which the rectangle of pixels was created, the dimensions of the rectangle, the size of the array of bits, and so on.

•	A logical palette.

•	An array of bits that defines the relationship between pixels in the bitmapped image and entries in the logical palette.

The following illustration shows the developer's perspective of the bitmap found in the file REDBRICK.BMP. It shows a palette array, a 32- by 32-pixel rectangle, and the index array that maps colors from the palette to pixels in the rectangle.

In the preceding example, the rectangle of pixels was created on a VGA display device using a palette of 16 colors. A 16-color palette requires 4-bit indices; therefore, the array that maps palette colors to pixel colors is composed of 4-bit indices as well. (For more information about logical color-palettes, see Colors.)

Note that in the above bitmap, Windows maps indices to pixels beginning with the bottom scan line of the rectangular region and ending with the top scan line. (A scan line is a single row of adjacent pixels on a video display.) For example, the first row of the array (row 0) corresponds to the bottom row of pixels, scan line 31. This is because the above bitmap is a "bottom-up" device-independent bitmap (DIB), a common type of bitmap. In "top-down" DIBs and in device-dependent bitmaps (DDBs), Windows maps indices to pixels beginning with the top scan line.


Bitmap Types

There are two types of bitmaps: device-dependent (DDBs) and device-independent (DIBs). DDBs were common in early (pre-3.0) versions of Windows. In fact, they were the only bitmaps available to developers. However, as display technology improved and as the variety of display devices increased among Windows users, certain inherent problems surfaced. For example, there was no method of storing (or retrieving) the resolution of the display type on which a bitmap was created, so a drawing application could not quickly determine whether a bitmap was suitable for the type of video display device on which the application was running. To solve this problem, Microsoft created DIBs.


Device-Independent Bitmaps

A DIB contains the following color and dimension information:

•	The color format of the device on which the rectangular image was created.

•	The resolution of the device on which the rectangular image was created.

•	The palette for the device on which the image was created.

•	An array of bits that maps red, green, blue (RGB) triplets to pixels in the rectangular image.

•	A data-compression identifier that indicates the data compression scheme (if any) used to reduce the size of the array of bits.

This information is stored in a BITMAPINFO structure consisting of a BITMAPINFOHEADER structure followed by two or more RGBQUAD structures. The BITMAPINFOHEADER specifies the dimensions of the pixel rectangle, describes the device's color technology, and identifies the compression schemes used to reduce the bitmap's size. The RGBQUAD structures identify the colors that appear in the pixel rectangle.

There are two varieties of DIB: "bottom-up" DIBs, in which the origin lies at the lower left corner, and "top-down" DIBs, in which the origin lies at the upper left corner. If the height of a DIB, as indicated by the biHeight member of the BITMAPINFOHEADER structure, is a positive value, it is a bottom-up DIB; if the height is a negative value, it is a top-down DIB. Top-down DIBs cannot be compressed.

The color format is specified in terms of a count of color planes and color bits. The count of color planes is always 1; the count of color bits is 1 for monochrome bitmaps, 4 for VGA bitmaps, and 8, 16, 24, or 32 for bitmaps on other color devices. An application retrieves the number of color bits a particular display (or printer) uses by calling the GetDeviceCaps function, specifying BITSPIXEL as the second argument.

The resolution of a display device is specified in pixels per meter. An application can retrieve the horizontal resolution for a video display, or printer, by following a three-step process:

1.	Call the GetDeviceCaps function, specifying HORZRES as the second argument.

2.	Call GetDeviceCaps a second time, specifying HORZSIZE as the second argument.

3.	Divide the first return value by the second return value.

The application can retrieve the vertical resolution by using the same three-step process with different parameters: VERTRES in place of HORZRES, and VERTSIZE in place of HORZSIZE.

The palette is represented by an array of RGBQUAD structures that specify the red, green, and blue intensity components for each color in a display device's color palette. Each color index in the palette array maps to a specific pixel in the rectangular region associated with the bitmap. The size of this array, in bits, is equivalent to the width of the rectangle, in pixels, multiplied by the height of the rectangle, in pixels, multiplied by the count of color bits for the device. An application can retrieve the size of the device's palette by calling the GetDeviceCaps function, specifying the NUMCOLORS constant as the second argument.

The Win32 API supports the compression of the palette array for 8-bit-per-pixel and 4-bit-per-pixel bottom-up DIBs. These arrays can be compressed by using the run-length encoding (RLE) scheme. The RLE scheme uses 2-byte values, the first byte specifying the number of consecutive pixels that use a color index and the second byte specifying the index. For more information about bitmap compression, see the description of the BITMAPINFOHEADER structure.

An application can create a DIB from a DDB by initializing the required structures and calling the GetDIBits function. To determine whether a device supports this function, call the GetDeviceCaps function, specifying RC_DI_BITMAP as the RASTERCAPS flag.

An application can use a DIB to set pixels on the display device by calling the SetDIBitsToDevice or the StretchDIBits function. To determine whether a device supports the SetDIBitsToDevice function, call the GetDeviceCaps function, specifying RC_DIBTODEV as the RASTERCAPS flag. Specify RC_STRETCHDIB as the RASTERCAPS flag to determine if the device supports StretchDIBits.

An application that simply needs to display a preexisting DIB can use the SetDIBitsToDevice function. For example, a spreadsheet application can open existing charts and display them in a window by using the SetDIBitsToDevice function. To repeatedly redraw a bitmap in a window, however, the application should use the BitBlt function. For example, a multimedia application that combines animated graphics with sound would benefit from calling the BitBlt function because it executes faster than SetDIBitsToDevice.


Device-Dependent Bitmaps

Device-dependent bitmaps are supported only for compatibility with applications written for Windows versions earlier than 3.0. A developer writing a new application, or porting an application written for a previous version of Windows to the Win32 platform, should use DIBs.

DDBs are described by using a single structure, the BITMAP structure. The members of this structure specify the width and height of a rectangular region, in pixels; the width of the array that maps entries from the device palette to pixels; and the device's color format, in terms of color planes and bits per pixel. An application can retrieve the color format of a device by calling the GetDeviceCaps function and specifying the appropriate constants.

There are two types of DDBs: discardable and nondiscardable. A discardable DDB is a bitmap that Windows discards if the bitmap is not selected into a DC and if system memory is low. The CreateDiscardableBitmap function creates discardable bitmaps. The CreateBitmap, CreateCompatibleBitmap, and CreateBitmapIndirect functions create nondiscardable bitmaps.

An application can create a DDB from a DIB by initializing the required structures and calling the CreateDIBitmap function. Specifying CBM_INIT in the call to CreateDIBitmap is equivalent to calling the CreateCompatibleBitmap function to create a DDB in the format of the device and then calling the SetDIBits function to translate the DIB bits to the DDB. To determine whether a device supports the SetDIBits function, call the GetDeviceCaps function, specifying RC_DI_BITMAP as the RASTERCAPS flag.


Bitmaps, Device Contexts, and Drawing Surfaces

A device context (DC) is a data structure defining the graphics objects, their associated attributes, and the graphics modes affecting output on a device. An application creates a DC by calling the CreateDC function; it retrieves a window manager device context by calling the GetDC function.


The Drawing Surface

Before returning a handle that identifies that DC, the window manager selects a drawing surface into the DC. If the application called the CreateDC function to create a device context for a VGA display, the dimensions of this drawing surface are 640 by 480 pixels. If the application called the GetDC function, the dimensions reflect the size of the client area.

When an application passes the handle returned by CreateDC or GetDC to one of the graphics device interface (GDI) drawing functions, the requested output appears on the drawing surface selected into the device context.


Compatible Device Contexts

To enable applications to place output in memory rather than sending it to an actual device, the Win32 API provides a special device context for bitmap operations called a compatible device context. A compatible DC enables Windows to treat a portion of memory as a virtual device. It is an array of bits in memory that an application can use temporarily to store the color data for bitmaps created on a normal drawing surface.

An application creates a compatible DC by calling the CreateCompatibleDC function and receives a handle that identifies a normal device context. Windows creates a temporary one-bit placeholder for the array. Before performing drawing operations using the compatible DC handle, the application must increase the size of this array. To do this, the application can call the CreateBitmap, CreateBitmapIndirect, or CreateCompatibleBitmap function to create a bitmap of the appropriate dimensions and then call the SelectObject function to select the bitmap into the DC. After the bitmap is selected into the compatible DC, Windows replaces the single-bit array with an array large enough to store color information for the specified rectangle of pixels.

When an application passes the handle returned by CreateCompatibleDC to one of the GDI drawing functions, the requested output does not appear on a device's drawing surface. Instead, Windows stores the color information for the resultant line, curve, text or region in the array of bits. The application can copy the image stored in memory back onto a drawing surface by calling the BitBlt function, identifying the compatible DC as the source device context and a window or screen DC as the target device context.

When displaying a DIB or a DDB created from a DIB on a palette device, you can improve the speed at which the image is drawn by arranging the logical palette to match the layout of the system palette. To do this, call GetDeviceCaps with the NUMRESERVED value to get the number of reserved colors in the system. Then call GetSystemPaletteEntries and fill in the first and last NUMRESERVED/2 entries of the logical palette with the corresponding system colors. For example, if NUMRESERVED is 20, you would fill in the first and last 10 entries of the logical palette with the system colors. Then fill in the remaining 256 − NUMRESERVED colors of the logical palette (in our example, the remaining 236 colors) with colors from the DIB and set the PC_NOCOLLAPSE flag on each of these colors. For more information about color and palettes, see Colors.


Bitmap Rotation

Windows provides a function to copy a bitmap into a parallelogram; this function, PlgBlt, performs a bit-block transfer from a rectangle in a source device context into a parallelogram in a destination device context. In order to rotate the bitmap, an application must provide the coordinates, in world units, to be used for the corners of the parallelogram. (For more information about rotation and world units, see Coordinate Spaces and Transformations.)


Bitmap Scaling

The Win32 API also provides a function to scale a bitmap; this function, StretchBlt, performs a bit-block transfer from a rectangle in a source device context into a rectangle in a destination device context. However, unlike the BitBlt function, which duplicates the source rectangle dimensions in the destination rectangle, StretchBlt allows an application to specify the dimensions of both the source and the destination rectangles. When the destination bitmap is smaller than the source bitmap, Windows combines rows or columns of color data (or both) in the bitmap before rendering the corresponding image on the display device. Windows combines the color data according to the specified stretch mode, which the application defines by calling the SetStretchBltMode function. When the destination bitmap is larger than the source bitmap, Windows scales or magnifies each pixel in the resultant image accordingly.


Bitmaps as Brushes

The Win32 API provides a number of functions that use the brush currently selected into a device context to perform bitmap operations. For example, the PatBlt function replicates the brush in a rectangular region within a window, and the FloodFill function replicates the brush inside an area in a window bounded by the specified color (unlike PatBlt, FloodFill does fill nonrectangular shapes).

The PatBlt function name (an abbreviation for pattern block transfer) implies that the function simply replicates the brush (or pattern) until it fills a specified rectangle. However, the function is actually much more powerful. Before replicating the brush, it combines the color data for the pattern with the color data for the existing pixels on the video display by using a raster operation (ROP). An ROP is a bitwise operation that is applied to the bits of color data for the replicated brush and the bits of color data for the target rectangle on the display device. There are 256 ROPs in the Win32 API; however, the PatBlt function recognizes only those that require a pattern and a destination (not those that require a source). The following table identifies the five most common ROPs.

ROP	Description
PATCOPY	Copies the pattern to the destination bitmap.
PATINVERT	Combines the destination bitmap with the pattern by using the Boolean OR operator.
DSTINVERT	Inverts the destination bitmap.
BLACKNESS	Turns all output to binary zeroes.
WHITENESS	Turns all output to binary ones.
The FloodFill function replicates the brush within a region bounded by a specified color. However, unlike the PatBlt function, FloodFill does not combine the color data for the brush with the color data for the pixels on the display; it simply sets the color of all pixels within the enclosed region on the display to the color of the brush that is currently selected into the device context.


Bitmap Storage

Bitmaps should be saved in a file that uses the established Windows format and assigned a name with the three-character .BMP extension. The established Windows format consists of a BITMAPFILEHEADER structure followed by a BITMAPINFOHEADER structure. An array of RGBQUAD structures (also called a color table) follows the BITMAPINFOHEADER structure. The color table is followed by a second array of indexes into the color table (the actual bitmap data).

The Windows format is shown in the following illustration.

The members of the BITMAPFILEHEADER structure identify the file; specify the size of the file, in bytes; and specify the offset from the first byte in the header to the first byte of bitmap data. The members of the BITMAPINFOHEADER structure specify the bitmap's width and height, in pixels; the color format (count of color planes and color bits per pixel) of the display device on which the bitmap was created; whether the bitmap data was compressed before storage and the type of compression used; the number of bytes of bitmap data; the resolution of the display device on which the bitmap was created; and the number of colors represented in the data. The RGBQUAD structures specify the RGB intensity values for each of the colors in the device's palette. The color-index array maps indices values from the RGBQUAD array to pixels in a rectangular region on the display.

The following hexadecimal output shows the contents of the file REDBRICK.BMP.

0000    42 4d 76 02 00 00 00 00  00 00 76 00 00 00 28 00

0010    00 00 20 00 00 00 20 00  00 00 01 00 04 00 00 00

0020    00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00

0030    00 00 00 00 00 00 00 00  00 00 00 00 80 00 00 80

0040    00 00 00 80 80 00 80 00  00 00 80 00 80 00 80 80

0050    00 00 80 80 80 00 c0 c0  c0 00 00 00 ff 00 00 ff

0060    00 00 00 ff ff 00 ff 00  00 00 ff 00 ff 00 ff ff

0070    00 00 ff ff ff 00 00 00  00 00 00 00 00 00 00 00

0080    00 00 00 00 00 00 00 00  00 00 00 00 00 00 09 00

0090    00 00 00 00 00 00 11 11  01 19 11 01 10 10 09 09

00a0    01 09 11 11 01 90 11 01  19 09 09 91 11 10 09 11

00b0    09 11 19 10 90 11 19 01  19 19 10 10 11 10 09 01

00c0    91 10 91 09 10 10 90 99  11 11 11 11 19 00 09 01

00d0    91 01 01 19 00 99 11 10  11 91 99 11 09 90 09 91

00e0    01 11 11 11 91 10 09 19  01 00 11 90 91 10 09 01

00f0    11 99 10 01 11 11 91 11  11 19 10 11 99 10 09 10

0100    01 11 11 11 19 10 11 09  09 10 19 10 10 10 09 01

0110    11 19 00 01 10 19 10 11  11 01 99 01 11 90 09 19

0120    11 91 11 91 01 11 19 10  99 00 01 19 09 10 09 19

0130    10 91 11 01 11 11 91 01  91 19 11 00 99 90 09 01

0140    01 99 19 01 91 10 19 91  91 09 11 99 11 10 09 91

0150    11 10 11 91 99 10 90 11  01 11 11 19 11 90 09 11

0160    00 19 10 11 01 11 99 99  99 99 99 99 99 99 09 99

0170    99 99 99 99 99 99 00 00  00 00 00 00 00 00 00 00

0180    00 00 00 00 00 00 90 00  00 00 00 00 00 00 00 00

0190    00 00 00 00 00 00 99 11  11 11 19 10 19 19 11 09

01a0    10 90 91 90 91 00 91 19  19 09 01 10 09 01 11 11

01b0    91 11 11 11 10 00 91 11  01 19 10 11 10 01 01 11

01c0    90 11 11 11 91 00 99 09  19 10 11 90 09 90 91 01

01d0    19 09 91 11 01 00 90 10  19 11 00 11 11 00 10 11

01e0    01 10 11 19 11 00 90 19  10 91 01 90 19 99 00 11

01f0    91 01 11 01 91 00 99 09  09 01 10 11 91 01 10 91

0200    99 11 10 90 91 00 91 11  00 10 11 01 10 19 19 09

0210    10 00 99 01 01 00 91 01  19 91 19 91 11 09 10 11

0220    00 91 00 10 90 00 99 01  11 10 09 10 10 19 09 01

0230    91 90 11 09 11 00 90 99  11 11 11 90 19 01 19 01

0240    91 01 01 19 09 00 91 10  11 91 99 09 09 90 11 91

0250    01 19 11 11 91 00 91 19  01 00 11 00 91 10 11 01

0260    11 11 10 01 11 00 99 99  99 99 99 99 99 99 99 99

0270    99 99 99 99 99 90

The following table shows the data bytes associated with the structures in a bitmap file.

Structure	Corresponding bytes
BITMAPFILEHEADER	0x00 − 0x0D
BITMAPINFOHEADER	0x0E − 0x31
RGBQUAD array	0x32 − 0x75
Color-index array	0x76 − 0x275


Using Bitmaps

•	Capturing an image

•	Scaling an image

•	Storing an image


Capturing an Image

You can use a bitmap to capture an image, and you can store the captured image in memory, display it at a different location in your application's window, or display it in another window.

In some cases, you may want your application to capture images and store them only temporarily. For example, when you scale or "zoom" a picture created in a drawing application, the application must temporarily save the normal view of the image and display the zoomed view. Later, when the user selects the normal view, the application must replace the zoomed image with a copy of the normal view that it temporarily saved.

To store an image temporarily, your application must call CreateCompatibleDC to create a DC that is compatible with the current window DC. After you create a compatible DC, you create a bitmap with the appropriate dimensions by calling the CreateCompatibleBitmap function and then select it into this device context by calling the SelectObject function.

After the compatible device context is created and the appropriate bitmap has been selected into it, you can capture the image. The Win32 API provides the BitBlt function to capture images. This function performs a bit block transfer — that is, it copies data from a source bitmap into a destination bitmap. Because it copies data from bitmaps, you'd expect that two arguments to this function would be bitmap handles; however, this is not the case. Instead, BitBlt receives handles that identify two device contexts and copies the bitmap data from a bitmap selected into the source DC into a bitmap selected into the target DC. In this case, the target DC is the compatible DC, so when BitBlt completes the transfer, the image has been stored in memory. To redisplay the image, call BitBlt a second time, specifying the compatible DC as the source DC and a window (or printer) DC as the target DC.

The following example code, from an application that captures an image of the entire desktop, creates a compatible device context and a bitmap with the appropriate dimensions, selects the bitmap into the compatible DC, and then copies the image using the BitBlt function.

/*

 * Create a normal DC and a memory DC for the entire screen. The

 * normal DC provides a "snapshot" of the screen contents. The

 * memory DC keeps a copy of this "snapshot" in the associated

 * bitmap.

 */

hdcScreen = CreateDC("DISPLAY", NULL, NULL, NULL);

hdcCompatible = CreateCompatibleDC(hdcScreen);

/* Create a compatible bitmap for hdcScreen. */

hbmScreen = CreateCompatibleBitmap(hdcScreen,

                     GetDeviceCaps(hdcScreen, HORZRES),

                     GetDeviceCaps(hdcScreen, VERTRES));

if (hbmScreen == 0)

    errhandler("hbmScreen", hwnd);

/* Select the bitmaps into the compatible DC. */

if (!SelectObject(hdcCompatible, hbmScreen))

    errhandler("Compatible Bitmap Selection", hwnd);

        /* Hide the application window. */

        ShowWindow(hwnd, SW_HIDE);

        /*

         * Copy color data for the entire display into a

         * bitmap that is selected into a compatible DC.

         */

        if (!BitBlt(hdcCompatible,

               0,0,

               bmp.bmWidth, bmp.bmHeight,

               hdcScreen,

               0,0,

               SRCCOPY))

        errhandler("Screen to Compat Blt Failed", hwnd);

        /* Redraw the application window. */

        ShowWindow(hwnd, SW_SHOW);


Scaling an Image

Some applications scale images — that is, they display zoomed or reduced views of an image. For example, a drawing application may provide a zoom feature that enables the user to view and edit a drawing on a pixel-by-pixel basis.

Applications scale images by calling the StretchBlt function. Like the BitBlt function, StretchBlt copies bitmap data from a bitmap in a source DC into a bitmap in a target DC. However, unlike the BitBlt function, StretchBlt scales the image based on the specified dimensions of the source and target rectangles. If the source rectangle is larger than the target rectangle, the resultant image will appear to have shrunk; if the source rectangle is smaller than the target rectangle, the resultant image will appear to have expanded.

If the target rectangle is smaller than the source rectangle, StretchBlt removes color data from the image according to a specified stretch mode as shown in the following table.

Stretch Mode	Method
BLACKONWHITE	Performs a logical AND operation on the color data for the eliminated pixels and the color data for the remaining pixels.
WHITEONBLACK	Performs a logical OR operation on the color data for the eliminated pixels and the color data for the remaining pixels.
COLORONCOLOR	Eliminates the color data of the deleted pixels completely.
HALFTONE	Approximates the original (source) color data in the destination.
You set the stretch mode by calling the SetStretchBltMode function.

The following example code is taken from an application that displays an image either at its original size or a twice the original size. (This application uses the default stretch mode.)

    hdcScaled = CreateCompatibleDC(hdcScreen);

    hbmScaled = CreateCompatibleBitmap(hdcScreen,

                    GetDeviceCaps(hdcScreen, HORZRES) * 2,

                    GetDeviceCaps(hdcScreen, VERTRES) * 2);

    if (hbmScaled == 0)

        errhandler("hbmScaled", hwnd);

    /* Select the bitmaps into the compatible DC. */

    if (!SelectObject(hdcScaled, hbmScaled))

        errhandler("Scaled Bitmap Selection", hwnd);

case WM_COMMAND:     /* message: command from application menu */

    switch(wParam) {

        case IDM_SCALEX1:

            if (fBlt){

                 fScaled = FALSE;

                 hdcWin = GetDC(hwnd);

                 BitBlt(hdcWin,

                    0,0,

                    bmp.bmWidth, bmp.bmHeight,

                    hdcCompatible,

                    0,0,

                    SRCCOPY);

                 ReleaseDC(hwnd, hdcWin);

            }

            break;

        case IDM_SCALEX2:

            if (fBlt){

                 fScaled = TRUE;

                 StretchBlt(hdcScaled,

                     0, 0,

                     bmp.bmWidth * 2, bmp.bmHeight * 2,

                     hdcCompatible,

                     0, 0,

                     bmp.bmWidth, bmp.bmHeight,

                     SRCCOPY);

                 hdcWin = GetDC(hwnd);

                 BitBlt(hdcWin,

                    0,0,

                    bmp.bmWidth, bmp.bmHeight,

                    hdcScaled,

                    0,0,

                    SRCCOPY);

                 ReleaseDC(hwnd, hdcWin);

            }

            break;


Storing an Image

Many applications store images permanently as files. For example, drawing applications store pictures, spreadsheet applications store charts, CAD applications store drawings, and so on.

If you are writing an application that will store a bitmapped image in a file, you should use the Windows file format described in Bitmap Storage. In order to store a bitmap in this format, you must initialize a BITMAPINFO structure (consisting of a BITMAPFILEHEADER structure and an array of RGBQUAD structures), as well as an array of palette indices.

The following example code defines a function that allocates memory for and initializes members within a BITMAPINFOHEADER structure.

PBITMAPINFO CreateBitmapInfoStruct(HWND hwnd, HBITMAP hBmp) {

    BITMAP bmp;

    PBITMAPINFO pbmi;

    WORD    cClrBits;

    /* Retrieve the bitmap's color format, width, and height. */

    if (!GetObject(hBmp, sizeof(BITMAP), (LPSTR)&bmp))

        errhandler("GetObject", hwnd);

    /* Convert the color format to a count of bits. */

    cClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel);

    if (cClrBits == 1)

        cClrBits = 1;

    else if (cClrBits <= 4)

        cClrBits = 4;

    else if (cClrBits <= 8)

        cClrBits = 8;

    else if (cClrBits <= 16)

        cClrBits = 16;

    else if (cClrBits <= 24)

        cClrBits = 24;

    else

        cClrBits = 32;

    /*

     * Allocate memory for the BITMAPINFO structure. (This structure

     * contains a BITMAPINFOHEADER structure and an array of RGBQUAD data

     * structures.)

     */

    if (cClrBits != 24)

         pbmi = (PBITMAPINFO) LocalAlloc(LPTR,

                    sizeof(BITMAPINFOHEADER) +

                    sizeof(RGBQUAD) * (2^cClrBits));

    /*

     * There is no RGBQUAD array for the 24-bit-per-pixel format.

     */

    else

         pbmi = (PBITMAPINFO) LocalAlloc(LPTR,

                    sizeof(BITMAPINFOHEADER));

    /* Initialize the fields in the BITMAPINFO structure. */

    pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);

    pbmi->bmiHeader.biWidth = bmp.bmWidth;

    pbmi->bmiHeader.biHeight = bmp.bmHeight;

    pbmi->bmiHeader.biPlanes = bmp.bmPlanes;

    pbmi->bmiHeader.biBitCount = bmp.bmBitsPixel;

    if (cClrBits < 24)

        pbmi->bmiHeader.biClrUsed = 2^cClrBits;

    /* If the bitmap is not compressed, set the BI_RGB flag. */

    pbmi->bmiHeader.biCompression = BI_RGB;

    /*

     * Compute the number of bytes in the array of color

     * indices and store the result in biSizeImage.

     */

    pbmi->bmiHeader.biSizeImage = (pbmi->bmiHeader.biWidth + 7) /8

                                  * pbmi->bmiHeader.biHeight

                                  * cClrBits;

    /*

     * Set biClrImportant to 0, indicating that all of the

     * device colors are important.

     */

    pbmi->bmiHeader.biClrImportant = 0;

    return pbmi;

}

The following example code defines a function that initializes the remaining structures, retrieves the array of palette indices, opens the file, copies the data, and closes the file.

void CreateBMPFile(HWND hwnd, LPTSTR pszFile, PBITMAPINFO pbi,

                  HBITMAP hBMP, HDC hDC)

 {

    HANDLE hf;                  /* file handle */

    BITMAPFILEHEADER hdr;       /* bitmap file-header */

    PBITMAPINFOHEADER pbih;     /* bitmap info-header */

    LPBYTE lpBits;              /* memory pointer */

    DWORD dwTotal;              /* total count of bytes */

    DWORD cb;                   /* incremental count of bytes */

    BYTE *hp;                   /* byte pointer */

    DWORD dwTmp;

    pbih = (PBITMAPINFOHEADER) pbi;

    lpBits = (LPBYTE) GlobalAlloc(GMEM_FIXED, pbih->biSizeImage);
    if (!lpBits)

         errhandler("GlobalAlloc", hwnd);

    /*

     * Retrieve the color table (RGBQUAD array) and the bits

     * (array of palette indices) from the DIB.

     */

    if (!GetDIBits(hDC, hBMP, 0, (WORD) pbih->biHeight,

                   lpBits, pbi, DIB_RGB_COLORS))

        errhandler("GetDIBits", hwnd);

    /* Create the .BMP file. */

    hf = CreateFile(pszFile,

                   GENERIC_READ | GENERIC_WRITE,

                   (DWORD) 0,

                   (LPSECURITY_ATTRIBUTES) NULL,

                   CREATE_ALWAYS,

                   FILE_ATTRIBUTE_NORMAL,

                   (HANDLE) NULL);

    if (hf == INVALID_HANDLE_VALUE)

        errhandler("CreateFile", hwnd);

    hdr.bfType = 0x4d42;        /* 0x42 = "B" 0x4d = "M" */

    /* Compute the size of the entire file. */

    hdr.bfSize = (DWORD) (sizeof(BITMAPFILEHEADER) +

                 pbih->biSize + pbih->biClrUsed

                 * sizeof(RGBQUAD) + pbih->biSizeImage);

    hdr.bfReserved1 = 0;

    hdr.bfReserved2 = 0;

    /* Compute the offset to the array of color indices. */

    hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) +

                    pbih->biSize + pbih->biClrUsed

                    * sizeof (RGBQUAD);

    /* Copy the BITMAPFILEHEADER into the .BMP file. */

    if (!WriteFile(hf, (LPVOID) &hdr, sizeof(BITMAPFILEHEADER),

       (LPDWORD) &dwTmp, (LPOVERLAPPED) NULL))

       errhandler("WriteFile", hwnd);

    /* Copy the BITMAPINFOHEADER and RGBQUAD array into the file. */

    if (!WriteFile(hf, (LPVOID) pbih, sizeof(BITMAPINFOHEADER)

                  + pbih->biClrUsed * sizeof (RGBQUAD),

                  (LPDWORD) &dwTmp, (LPOVERLAPPED) NULL))

       errhandler("WriteFile", hwnd);

    /* Copy the array of color indices into the .BMP file. */

    dwTotal = cb = pbih->biSizeImage;

    hp = lpBits;

    while (cb > MAXWRITE)  {

            if (!WriteFile(hf, (LPSTR) hp, (int) MAXWRITE,

                          (LPDWORD) &dwTmp, (LPOVERLAPPED) NULL))

                errhandler("WriteFile", hwnd);

            cb-= MAXWRITE;

            hp += MAXWRITE;

    }

    if (!WriteFile(hf, (LPSTR) hp, (int) cb,

         (LPDWORD) &dwTmp, (LPOVERLAPPED) NULL))

           errhandler("WriteFile", hwnd);

    /* Close the .BMP file. */

    if (!CloseHandle(hf))

           errhandler("CloseHandle", hwnd);

    /* Free memory. */

    GlobalFree((HGLOBAL)lpBits);
}


Bitmap Functions

Following are the functions used with bitmaps.

BitBlt
CreateBitmap
CreateBitmapIndirect
CreateCompatibleBitmap
CreateDIBitmap
CreateDIBSection
CreateDiscardableBitmap
ExtFloodFill
FloodFill
GetBitmapBits
GetBitmapDimensionEx
GetDIBColorTable
GetDIBits
GetPixel
GetStretchBltMode
LoadBitmap
MaskBlt
PatBlt
PlgBlt
SetBitmapBits
SetBitmapDimensionEx
SetDIBColorTable
SetDIBits
SetDIBitsToDevice
SetPixel
SetPixelV
SetStretchBltMode
StretchBlt
StretchDIBits

Obsolete or Deleted Functions

GetBitmapDimension
SetBitmapDimension


Brushes

A brush is a graphics tool that a Microsoft® Win32®-based application uses to paint the interior of polygons, ellipses, and paths. Drawing applications use brushes to paint shapes; word processing applications use brushes to paint rules; computer-aided design (CAD) applications use brushes to paint the interiors of cross-section views; and spreadsheet applications use brushes to paint the sections of pie charts and the bars in bar graphs.


About Brushes

There are two types of brushes: logical and physical. A logical brush is a description of the ideal bitmap that an application would use to paint shapes. A physical brush is the actual bitmap that a device driver creates based on an application's logical-brush definition. For more information about bitmaps, see Bitmaps.

When an application calls one of the functions that create a brush, it retrieves a handle that identifies a logical brush. When the application passes this handle to the SelectObject function, the device driver for the corresponding display or printer creates the physical brush.


Brush Origin

When an application calls a drawing function to paint a shape, Windows positions a brush at the start of the paint operation and maps a pixel in the brush bitmap to the window origin of the client area. (The window origin is the upper-left corner of the  window's client area.) The coordinates of the pixel that Windows maps are called the brush origin. The default brush origin is located in the upper-left corner of the brush bitmap, at the coordinates (0,0). Windows then copies the brush across the client area, forming a pattern that is as tall as the bitmap. The copy operation continues, row by row, until the entire client area is filled. However, the brush pattern is visible only within the boundaries of the specified shape.

There are instances when the default brush origin should not be used. For example, it may be necessary for an application to use the same brush to paint the backgrounds of its parent and child windows and blend a child window's background with that of the parent window. To do this, the application should reset the brush origin by calling the SetBrushOrgEx function and shifting the origin the required number of pixels. (An application can retrieve the current brush origin by calling the GetBrushOrgEx function.)

The following illustration shows a five-pointed star filled by using an application-defined brush. The illustration shows a zoomed image of the brush, as well as the location to which it was mapped at the beginning of the paint operation.


Logical Brush Types

There are four types of logical brushes (solid, stock, hatch, and pattern) as shown in the following illustration.

The stock and hatch types each have several predefined brushes, as described in Hatch Brush.


Solid Brush

A solid brush is a logical brush that contains 64 pixels of the same color. An application can create a solid logical brush by calling the CreateSolidBrush function, specifying the color of the brush required. After creating the solid brush, the application can select it into its device context and use it to paint filled shapes.


Stock Brush

There are seven predefined logical stock brushes maintained by the graphics device interface (GDI). There are also 21 predefined logical stock brushes maintained by the window management interface (USER).

The following rectangles were painted by using the seven predefined stock brushes.

An application can retrieve a handle identifying one of the seven stock brushes by calling the GetStockObject function, specifying the brush type.

The 21 stock brushes maintained by the window management interface correspond to the colors of window elements such as menus, scroll bars, and buttons. An application can obtain a handle identifying one of these brushes by calling the GetSysColorBrush function and specifying a system-color value. An application can retrieve the color corresponding to a particular window element by calling the GetSysColor function. An application can set the color corresponding to a window element by calling the SetSysColors function.


Hatch Brush

There are six predefined logical hatch brushes maintained by GDI. The following rectangles were painted by using the six predefined hatch brushes.

An application can create a hatch brush by calling the CreateHatchBrush function, specifying one of the six hatch styles.


Pattern Brush

A pattern (or custom) brush is created from an application-defined bitmap or device-independent bitmap (DIB). The following rectangles were painted by using different pattern brushes.

To create a logical pattern brush, an application must first create a bitmap. After creating the bitmap, the application can create the logical pattern brush by calling the CreatePatternBrush or CreateDIBPatternBrushPt function, supplying a handle that identifies the bitmap (or DIB). The brushes that appear in the preceding illustration were created from monochrome bitmaps. For a description of bitmaps, DIBs, and the functions that create them, see Bitmaps.


Using Brushes

You can use a brush to paint the interior of virtually any shape by using a GDI function. This includes the interiors of rectangles, ellipses, polygons, and paths. Depending on the requirements of your application, you can use a solid brush of a specified color, a stock brush, a hatch brush, or a pattern brush.

This section contains code samples that demonstrate the creation of a custom brush dialog box. The dialog box contains a grid that represents the bitmap Windows uses as a brush. A user can use this grid to create a pattern-brush bitmap and then view the custom pattern by clicking the Test Pattern button.

The following illustration shows a pattern created by using the Custom Brush dialog box.

To display a dialog box, you must first create a dialog box template. The following dialog box template defines the Custom Brush dialog box.

CustBrush DIALOG 6, 18, 160, 118

STYLE WS_DLGFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION

CAPTION "Custom Brush"

FONT 8, "MS Sans Serif"

BEGIN

    CONTROL         "", IDD_GRID, "Static", SS_BLACKFRAME |

                    WS_CHILD, 3, 2, 83, 79

    CONTROL         "", IDD_RECT, "Static", SS_BLACKFRAME |

                    WS_CHILD, 96, 11, 57, 28

    PUSHBUTTON      "Test Pattern", IDD_PAINTRECT, 96, 47, 57, 14

    PUSHBUTTON      "OK", IDD_OK, 29, 98, 40, 14

    PUSHBUTTON      "Cancel", IDD_CANCEL, 92, 98, 40, 14

END

The Custom Brush dialog box contains five controls: a bitmap-grid window, a pattern-viewing window, and three push buttons, labeled Test Pattern, OK and Cancel. The Test Pattern push button enables the user to view the pattern. The dialog box template specifies the overall dimensions of the dialog box window, assigns a value to each control, specifies the location of each control, and so forth. (For more information about creating dialog box templates, see Dialog Boxes.)

The control values in the dialog box template are constants that have been defined as follows in the application's header file.

#define IDD_GRID  120

#define IDD_RECT  121

#define IDD_PAINTRECT 122

#define IDD_OK  123

#define IDD_CANCEL 124

After you create a dialog box template and include it in the application's resource-definition file, you must write a dialog procedure. This procedure processes messages that Windows sends to the dialog box. The following excerpt from an application's source code shows the dialog box procedure for the Custom Brush dialog box and the two application-defined functions it calls.

int APIENTRY BrushDlgProc(HWND hdlg, WORD message, LONG wParam,

                         LONG lParam)

{

    static HWND hwndGrid;       /* grid-window control     */

    static HWND hwndBrush;      /* pattern-brush control   */

    static RECT rctGrid;        /* grid-window rectangle   */

    static RECT rctBrush;       /* pattern-brush rectangle */

    static UINT bBrushBits[8];  /* bitmap bits             */

    static RECT rect[64];       /* grid-cell array         */

    static HBITMAP hbm;         /* bitmap handle           */

    HBRUSH hbrush;              /* current brush           */

    HBRUSH hbrushOld;           /* default brush           */

    HRGN hrgnCell;              /* test-region handle      */

    HDC hdc;                    /* DC handle               */

    int x, y, deltaX, deltaY;   /* drawing coordinates     */

    POINTS ptlHit;              /* mouse coordinates       */

    int i;                      /* count variable          */

    switch (message)

        {

        case WM_INITDIALOG:

            /*

             * Retrieve a window handle for the grid-window and

             * pattern-brush controls

             */

            hwndGrid = GetDlgItem(hdlg, IDD_GRID);

            hwndBrush = GetDlgItem(hdlg, IDD_RECT);

            /* Initialize the array of bits that defines the

             * custom brush pattern with the value 1 to produce a

             * solid white brush).

             */

            for (i=0; i<8; i++)

                bBrushBits[i] = 0xFF;

            /*

             * Retrieve dimensions for the grid-window and pattern-brush

             * controls.

             */

            GetClientRect(hwndGrid, &rctGrid);

            GetClientRect(hwndBrush, &rctBrush);

            /* Determine the width and height of a single cell. */

            deltaX = (rctGrid.right - rctGrid.left)/8;

            deltaY = (rctGrid.bottom - rctGrid.top)/8;

            /* Initialize the array of cell rectangles. */

            for (y=rctGrid.top, i=0; y < rctGrid.bottom; y += deltaY){

                for (x=rctGrid.left; x < (rctGrid.right - 8) && i < 64;

                        x += deltaX, i++) {

                    rect[i].left = x; rect[i].top = y;

                    rect[i].right = x + deltaX;

                    rect[i].bottom = y + deltaY;

                }

            }

            return FALSE;

        case WM_PAINT:

            /* Draw the grid. */

            hdc = GetDC(hwndGrid);

            for (i=rctGrid.left; i<rctGrid.right;

                 i+=(rctGrid.right - rctGrid.left)/8){

                 MoveToEx(hdc, i, rctGrid.top, NULL);

                 LineTo(hdc, i, rctGrid.bottom);

            }

            for (i=rctGrid.top; i<rctGrid.bottom;

                 i+=(rctGrid.bottom - rctGrid.top)/8){

                 MoveToEx(hdc, rctGrid.left, i, NULL);

                 LineTo(hdc, rctGrid.right, i);

            }

            ReleaseDC(hwndGrid, hdc);

            return FALSE;

        case WM_LBUTTONDOWN:

            /* Store the mouse coordinates in a POINT structure. */

            ptlHit = MAKEPOINTS((POINTS FAR *)lParam);

            /*

             * Create a rectangular region with dimensions and

             * coordinates that correspond to those of the grid

             * window.

             */

            hrgnCell = CreateRectRgn(rctGrid.left, rctGrid.top,

                        rctGrid.right, rctGrid.bottom);

            /* Retrieve a window DC for the grid window. */

            hdc = GetDC(hwndGrid);

            /* Select the region into the DC. */

            SelectObject(hdc, hrgnCell);

            /* Test for a button click in the grid-window rectangle. */

            if (PtInRegion(hrgnCell, ptlHit.x, ptlHit.y)){

                /*

                 * A button click occurred in the grid-window rectangle;

                 * isolate the cell in which it occurred.

                 */

                for(i=0; i<64; i++){

                    DeleteObject(hrgnCell);

                    hrgnCell = CreateRectRgn(rect[i].left, rect[i].top,

                               rect[i].right, rect[i].bottom);

                    if (PtInRegion(hrgnCell, ptlHit.x, ptlHit.y)){

                         InvertRgn(hdc, hrgnCell);

                         /* Set the appropriate brush bits. */

                         if (i % 8 == 0)

                            bBrushBits[i/8] = bBrushBits[i/8] ^ 0x80;

                         else if (i % 8 == 1)

                            bBrushBits[i/8] = bBrushBits[i/8] ^ 0x40;

                         else if (i % 8 == 2)

                            bBrushBits[i/8] = bBrushBits[i/8] ^ 0x20;

                         else if (i % 8 == 3)

                            bBrushBits[i/8] = bBrushBits[i/8] ^ 0x10;

                         else if (i % 8 == 4)

                            bBrushBits[i/8] = bBrushBits[i/8] ^ 0x08;

                         else if (i % 8 == 5)

                            bBrushBits[i/8] = bBrushBits[i/8] ^ 0x04;

                         else if (i % 8 == 6)

                            bBrushBits[i/8] = bBrushBits[i/8] ^ 0x02;

                         else if (i % 8 == 7)

                            bBrushBits[i/8] = bBrushBits[i/8] ^ 0x01;

                      /* Exit the "for" loop after the bit is set. */

                         break;

                    } /* end if */

                } /* end for */

            } /* end if */

            /* Release the DC for the control. */

            ReleaseDC(hwndGrid, hdc);

            return TRUE;

        case WM_COMMAND:

            switch (wParam){

               case IDD_PAINTRECT:

                    hdc = GetDC(hwndBrush);

                    /* Create a monochrome bitmap. */

                    hbm = CreateBitmap(8, 8, 1, 1,

                          (LPBYTE)bBrushBits);

                    /* Select the custom brush into the DC.      */

                    hbrush = CreatePatternBrush(hbm);

                    hbrushOld = SelectObject(hdc, hbrush);

                    /* Use the custom brush to fill the rectangle. */

                    Rectangle(hdc, rctBrush.left, rctBrush.top,

                              rctBrush.right, rctBrush.bottom);

                    /* Clean up memory. */

                    SelectObject(hdc, hbrushOld);

                    DeleteObject(hbrush);

                    DeleteObject(hbm);

                    ReleaseDC(hwndBrush, hdc);

                  return TRUE;

                case IDD_OK:

                case IDD_CANCEL:

                    EndDialog(hdlg, TRUE);

                    return TRUE;

            } /* end switch */

            break;

        default:

            return FALSE;

        }

}

int GetStrLngth(LPTSTR cArray)

{

    int i = 0;

    while (cArray[i++] != 0);

    return i-1;

}

DWORD RetrieveWidth(LPTSTR cArray, int iLength)

{

    int i, iTmp;

    double dVal, dCount;

    dVal = 0.0;

    dCount = (double)(iLength-1);

    for (i=0; i<iLength; i++){

        iTmp = cArray[i] - 0x30;

        dVal = dVal + (((double)iTmp) * pow(10.0, dCount--));

    }

    return (DWORD)dVal;

}

The dialog box procedure for the Custom Brush dialog box processes four messages, as described in the following table.

Message	Action
WM_INITDIALOG	Retrieves a window handle and dimensions for the grid-window and pattern-brush controls, computes the dimensions of a single cell in the grid-window control, and initializes an array of grid-cell coordinates.
WM_PAINT	Draws the grid pattern in the grid-window control.
WM_LBUTTONDOWN	Determines whether the cursor is within the grid-window control when the user presses the left mouse button. If so, the dialog box procedure inverts the appropriate grid cell and records the state of that cell in an array of bits that is used to create the bitmap for the custom brush.
WM_COMMAND	Processes input for the three push button controls. If the user presses the Test Pattern button, the dialog box procedure paints the Test Pattern control with the new custom brush pattern. If the user presses the OK or Cancel button, the dialog box procedure performs actions accordingly.
For more information about messages and message processing, see Messages and Message Queues.

After you write the dialog box procedure, export it in the module-definition file, include the function definition for the procedure in the application's header file, and then call the dialog box procedure at the appropriate point in the application.

The following excerpt from the module-definition file shows how the dialog box procedure for the Custom Brush is exported.

; Export all functions that are called by a Windows routine.

EXPORTS

        MainWndProc   @1   ; name of window processing function

        BrushDlgProc  @2   ; name of custom-brush processing function

The following excerpt from the application's header file shows the function definition for the dialog box procedure and the two functions it calls.

int APIENTRY BrushDlgProc(HWND hdlg, WORD message, LONG wParam,

             LONG lParam);

int GetStrLngth(LPTSTR cArray);

DWORD RetrieveWidth(LPTSTR cArray, int iLength);

Finally, the following code shows how the dialog box procedure is called from the application's source-code file. In this example, the dialog box procedure is called when the user chooses an option from the application's menu.

switch (message) {

    case WM_CREATE:

        break;

    case WM_COMMAND:           /* message: command from application menu */

        switch(wParam) {

            case IDM_CUSTOMBRUSH:

                    DialogBox((HANDLE)GetModuleHandle(NULL),

                    (LPTSTR)"CustBrush", hWnd,

                    (DLGPROC)BrushDlgProc);

                break;


Brush Functions

Following are the functions that can be used with brushes.

CreateBrushIndirect
CreateDIBPatternBrush
CreateDIBPatternBrushPt
CreateHatchBrush
CreatePatternBrush
CreateSolidBrush
GetBrushOrgEx
GetSysColorBrush
SetBrushOrgEx

Obsolete or Deleted Functions

FixBrushOrgEx


Clipping

Clipping is the process of limiting output to a region or path within the client area of an application's window.


About Clipping

Clipping is used by Microsoft® Win32®-based applications in a variety of ways. Word processing and spreadsheet applications clip keyboard input to keep it from appearing in the margins of a page or spreadsheet. Computer-aided design (CAD) and drawing applications clip graphics output to keep it from overwriting the edges of a drawing or picture.

A clipping region is a region with edges that are either straight lines or curves. A clip path is a region with edges that are straight lines, Bézier curves, or combinations of both. For more information about regions, see Regions. For more information about paths, see Paths.


Clipping Regions

A clipping region is one of the graphic objects that an application can select into a device context (DC). It is typically rectangular. Some device contexts provide a predefined or default clipping region while others do not. For example, if you obtain a device context handle from the BeginPaint function, the DC contains a predefined rectangular clipping region that corresponds to the invalid rectangle that requires repainting. However, if you obtain a device context handle by calling the CreateDC or GetDC function, the DC does not contain a default clipping region. For more information about device contexts returned by the BeginPaint function, see Painting and Drawing. For more information about device contexts returned by the CreateDC and GetDC functions, see Device Contexts.

Applications can perform a variety of operations on clipping regions. Some of these operations require a handle identifying the region and some do not. For example, an application can perform the following operations directly on a device context's clipping region:

•	Determine whether graphics output appears within the region's borders by passing coordinates of the corresponding line, arc, bitmap, text, or filled shape to the PtVisible function.

•	Determine whether part of the client area intersects a region by calling the RectVisible function.

•	Move the existing region by a specified offset by calling the OffsetClipRgn function.

•	Exclude a rectangular part of the client area from the current clipping region by calling the ExcludeClipRect function.

•	Combine a rectangular part of the client area with the current clipping region by calling the IntersectClipRect function.

After obtaining a handle identifying the clipping region, an application can perform any operation that is common with regions; for example:

•	Combining a copy of the current clipping region with a second region by calling the CombineRgn function.

•	Compare a copy of the current clipping region to a second region by calling the EqualRgn function.

•	Determine whether a point lies within the interior of a copy of the current clipping region by calling the PtInRegion function.


Clip Paths

Like a clipping region, a clip path is another graphics object that an application can select into a device context. Unlike a clipping region, a clip path is always created by an application and it is used for clipping to one or more irregular shapes. For example, an application can use the lines and curves that form the outlines of characters in a string of text to define a clip path.

To create a clip path, it's first necessary to create a path that describes the required irregular shape. Paths are created by calling the appropriate graphics device interface (GDI) drawing functions after calling the BeginPath function and before calling the EndPath function. This collection of functions is called a path bracket. For more information about paths and path brackets, see Paths.

After the path is created, it can be converted to a clip path by calling the SelectClipPath function, identifying a device context, and specifying a usage mode. The usage mode determines how Windows combines the new clip path with the device context's original clipping region. The following table describes the usage modes.

Mode	Description
RGN_AND	The clip path includes the intersection (overlapping areas) of the device context's clipping region and the current path.
RGN_COPY	The clip path is the current path.
RGN_DIFF	The clip path includes the device context's clipping region with any intersecting parts of the current path excluded.
RGN_OR	The clip path includes the union (combined areas) of the device context's clipping region and the current path.
RGN_XOR	The clip path includes the union of the device context's clipping region and the current path but excludes the intersection.


Using Clipping

This section contains example code that shows how to generate a clip path consisting of a character string. The example creates a logical font and uses it to draw a string within a clip path, then fills the path by drawing horizontal and vertical lines.

/*

 * DoClipPat - Draws a clip path using the specified string

 * Return value - TRUE if successful; FALSE otherwise

 * lplf - address of a LOGFONT structure that defines the font to

 *        use to draw the clip path

 * lpsz - address of a string to use for the clip path

 */

BOOL DoClipPath(LPLOGFONT lplf, LPSTR lpsz)

{

    LOGFONT lf;         /* logical font structure                    */

    HFONT hfont;        /* new logical font handle                   */

    HFONT hfontOld;     /* original logical font handle              */

    HDC hdc;            /* display DC handle                         */

    int nXStart, nYStart; /* drawing coordinates                     */

    RECT rc;            /* rectangle structure for painting window   */

    SIZE sz;            /* size structure that receives text extents */

    int nStrLen;        /* length of the string                      */

    int i;              /* loop counter                              */

    /* Retrieve a cached DC for the window. */

    hdc = GetDC(hwnd);

    /* Erase the current window contents. */

    GetClientRect(hwnd, &rc);

    FillRect(hdc, &rc, GetStockObject(WHITE_BRUSH));

    /*

     * Use the specified font to create a logical font and select it

     * into the DC.

     */

    hfont = CreateFontIndirect(lplf);

    if (hfont == NULL)

        return FALSE;

    hfontOld = SelectObject(hdc, hfont);

    /* Create a clip path. */

    nStrLen = lstrlen(lpsz);

    BeginPath(hdc);

        TextOut(hdc, nXStart, nYStart, lpsz, nStrLen);

    EndPath(hdc);

    SelectClipPath(hdc, RGN_DIFF);

    /*

     * Retrieve the dimensions of the rectangle surrounding

     * the text.

     */

    GetTextExtentPoint32(hdc, lpsz, nStrLen, &sz);

    /* Draw horizontal lines through the clip path. */

    for (i = nYStart + 1; i < (nYStart + sz.cy); i += 3) {

       MoveToEx(hdc, nXStart, i, (LPPOINT) NULL);

       LineTo(hdc, (nXStart + sz.cx), i);

    }

    /* Draw vertical lines through the clip path. */

    for (i = nXStart + 1; i < (nXStart + sz.cx); i += 3){

       MoveToEx(hdc, i, nYStart, (LPPOINT) NULL);

       LineTo(hdc, i, (nYStart + sz.cy));

    }

    /* Select the original font into the DC and release the DC. */

    SelectObject(hdc, hfontOld);

    DeleteObject(hfont);

    ReleaseDC(hwnd, hdc);

    return TRUE;

}

For an example that demonstrates how an application creates a rectangular clipping region, see Regions.


Clipping Functions

Following are the functions that can be used with clipping.

ExcludeClipRect
ExtSelectClipRgn
GetClipBox
GetClipRgn
GetMetaRgn
IntersectClipRect
OffsetClipRgn
PtVisible
RectVisible
SelectClipPath
SelectClipRgn
SetMetaRgn


Colors

Color is an important element in the pictures and images generated by Windows-based applications. This overview describes how Windows-based applications can manage and use colors with pens, brushes, text, or bitmaps.


About Colors

Color can be used to communicate ideas, show relationships between items, and improve the appeal and quality of output. Windows enables applications to discover the color capabilities of given devices and to choose from the available colors those that best suit their needs.

Although not described in this overview, image color matching is an important feature of color management that helps ensure that color images look the same whether displayed on screen or printed on paper. For more information, see Image Color Matching.


Color Basics

The color capabilities of devices, such as displays and printers, can range from monochrome to thousands of colors. Because an application may need to generate output for devices throughout this range, it should be prepared be prepared to handle varying color capabilities.

An application can discover the number of colors available for a given device by using the GetDeviceCaps function to retrieve the NUMCOLORS value. This value specifies the count of colors available for use by the application. Usually, this count corresponds to a physical property of the output device, such as the number of inks in the printer or the number of distinct color signals the display adapter can transmit to the monitor.

Although the NUMCOLORS value specifies the count of colors, it does not identify what the available colors are. An application can discover what colors are available by enumerating all pens having the PS_SOLID type. Because the device driver that supports a given device usually has a full range of solid pens and because Windows requires that solid pens have only colors that the device can generate, enumerating these pens is often equivalent to enumerating the colors. An application can enumerate the pens by using the EnumObjects function.


Color Values

By default, Windows defines color as a combination of three primary colors — red, green, and blue. Windows identifies a color by giving it a color value (sometimes called an RGB triplet), which consists of three 8-bit values specifying the intensities of its color components. Black has the minimum intensity for red, green, and blue, so the color value for black is (0, 0, 0). White has the maximum intensity for red, green, and blue, so its color value is (255, 255, 255).

Note  If image color matching is enabled, the definition of color and the meaning of a color value depends on the type of color space that is currently set for the device context.

Windows and applications use parameters and variables having the COLORREF type to pass and store color values. For example, the EnumObjects function identifies the color of each pen by setting the lopnColor member in a LOGPEN structure to a color value. Applications can extract the individual values of the red, green, and blue components from a color value by using the GetRValue, GetGValue, and GetBValue macros, respectively. Applications can create a color value from individual component values by using the RGB macro. When creating or examining a logical palette, an application uses the RGBQUAD structure to define color values and to examine individual component values.


Color Approximations and Dithering

Although an application can use color without regard to the color capabilities of the device, the resulting output may not be as informative and pleasing as output for which color is carefully chosen. Few, if any, devices guarantee an exact match for every possible color value; therefore, if an application requests a color that the device cannot generate, Windows approximates that color by using a color that the device can generate. For example, if an application attempts to create a red pen for a black and white printer, it will receive a black pen instead — Windows uses black as the approximation for red.

An application can discover whether Windows will approximate a given color by using the GetNearestColor function. The function takes a color value and returns the color value of the closest matching color the device can generate. The method Windows uses to determine this approximation depends on the device driver and its color capabilities. In most cases, the approximated color's overall intensity is closest to that of the requested color.

When an application creates a pen or sets the color for text, Windows always approximates a color if no exact match exists. When an application creates a solid brush, Windows may attempt to simulate the requested color by dithering. Dithering simulates a color by alternating two or more colors in a pattern. For example, different shades of pink can be simulated by alternating different combinations of red and white. Depending on the colors and the pattern, dithering can produce reasonable simulations. It is most useful for monochrome devices, because it expands the number of available "colors" well beyond simple black and white.

The method used to create dithered colors depends on the device driver. Most device drivers use a standard dithering algorithm, which generates a pattern based on the intensity values of the requested red, green, and blue colors. In general, any requested color that cannot be generated by the device is subject to simulation, but an application is not notified when Windows simulates a color. Furthermore, an application cannot modify or change the dithering algorithm of the device driver. An application, however, can bypass the algorithm by creating and using pattern brushes. In this way, the application creates its own dithered colors by combining solid colors in the bitmap that it uses to create the brush.


Color in Bitmaps

Windows handles colors in bitmaps differently than colors in pens, brushes, and text. Compatible bitmaps, created by using the CreateBitmap or CreateCompatibleBitmap function, are device specific and retain color information in a device-dependent format. No color values are used, and the colors are not subject to approximations and dithering.

Device-independent bitmaps (DIBs) retain color information either as color values or color palette indices. If color values are used, the colors are subject to approximation, but not dithering. Color palette indices can only be used with devices that support color palettes. Although Windows does not approximate or dither colors identified by indices, the resulting color may be different than that intended, because the indices yield valid results only in the context of the color palette that was current at the time the bitmap was created. If the palette changes, so do the colors in the bitmap.


Color Mixing

Color mixing lets an application create new colors by combining the pen or brush color with colors in the existing image. The application can choose either to draw the pen or brush color as is (effectively drawing over any existing image) or to mix the color with the colors already present.

The foreground mix mode, sometimes called the binary raster operation, determines how these colors are mixed. An application can merge colors, preserving all components of both colors; mask colors, removing or moderating components that are not common; or exclusively mask colors, removing or moderating components that are common. There are several variations on these basic mixing operations.

Color mixing is subject to color approximation. If the result of color mixing is a color that the device cannot generate, Windows approximates the result, using a color it can generate. If an application mixes dithered colors, the individual colors used to create the dithered color are mixed, and the results are subject to color approximation.

An application sets the foreground mix mode by using the SetROP2 function and retrieves the current mode by using the GetROP2 function.

Although there is a background mix mode, that mode does not control the mixing of colors. Instead, it specifies whether a background color is used when drawing styled lines, hatched brushes, and text.


Color Palettes

A color palette is an array that contains color values identifying the colors that can currently be displayed or drawn on the output device. Color palettes are used by devices that are capable of generating many colors but that can only display or draw a subset of these at any given time. For such devices, Windows maintains a system palette to track and manage the current colors of the device. Applications do not have direct access to the system palette. Instead, Windows associates a default palette with each device context. Applications can use the colors in the default palette or define their own colors by creating logical palettes and associating them with individual device contexts.

An application can determine whether a device supports color palettes by checking for the RC_PALETTE bit in the RASTERCAPS value returned by the GetDeviceCaps function.


Default Palette

The default palette is an array of color values identifying the colors that can be used with a device context by default. Windows associates the default palette with a context whenever an application creates a context for a device that supports color palettes. The default palette ensures that colors are available for use by an application without any further action.

The default palette typically has 20 entries (colors), but the exact number of entries may vary from device to device. This number is equal to the NUMCOLORS value returned by the GetDeviceCaps function. An application can retrieve the color values for colors in the default palette by enumerating solid pens, the same technique used to discover the colors available on nonpalette devices. The colors in the default palette depend on the device. Display devices, for example, often use the 16 standard colors of the VGA display and 4 other colors defined by Windows. Printer devices may use other default colors.

When using the default palette, applications use color values to specify pen and text colors. If the requested color is not in the palette, Windows approximates the color by using the closest color in the palette. If an application requests a solid brush color that is not in the palette, Windows simulates the color by dithering with colors that are in the palette.

To avoid approximations and dithering, applications can also specify pen, brush, and text colors by using color palette indices rather than color values. A color palette index is an integer value that identifies a specific palette entry. Applications can use color palette indices in place of color values but must use the PALETTEINDEX macro to create the indices.

Color palette indices are only useful for devices that support color palettes. To avoid this device dependence, applications that use the same code to draw to both palette and nonpalette devices should use palette-relative color values to specify pen, brush, and text colors. These values are identical to color values except when creating solid brushes. (On palette devices, a solid brush color specified by a palette-relative color value is subject to color approximation instead of dithering.) Applications must use the PALETTERGB macro to create palette-relative color values.

Windows does not allow an application to change the entries in the default palette. To use colors other than those in the default palette, an application must create its own logical palette and select the palette into the device context.


Logical Palette

A logical palette is a color palette that an application creates and associates with a given device context. Logical palettes let applications define and use colors that meet their specific needs. Applications can create any number of logical palettes, using them for separate device contexts or switching between them for a single device context. The maximum number of palettes that an application can create depends on the resources of the system.

An application creates a logical palette by using the CreatePalette function. The application fills a LOGPALETTE structure, which specifies the number of entries and the color values for each entry, and then the application passes the structure to CreatePalette. The function returns a palette handle that the application uses in all subsequent operations to identify the palette. To use colors in the logical palette, the application selects the palette into a device context by using the SelectPalette function and then realizes the palette by using the RealizePalette function. The colors in the palette are available as soon as the logical palette is realized.

An application should limit the size of its logical palettes to just enough entries to represent the colors needed. Applications cannot create logical palettes larger than the maximum palette size, a device-dependent value. Applications can obtain the maximum size by using the GetDeviceCaps function to retrieve the SIZEPALETTE value.

Although an application can specify any color value for a given entry in a logical palette, not all colors can be generated by the given device. Windows does not provide a way to discover which colors are supported, but the application can discover the total number of these colors by retrieving the color resolution of the device. The color resolution, specified in color bits per pixel, is equal to the COLORRES value returned by the GetDeviceCaps function. A device that has a color resolution of 18 has 262,144 possible colors. If an application requests a color that is not supported, Windows chooses an appropriate approximation.

Once a logical palette is created, an application can change colors in the palette by using the SetPaletteEntries function. If the logical palette has been selected and realized, changing the palette does not immediately affect the colors being displayed. The application must use the UnrealizeObject and RealizePalette functions to update the colors. In some cases, the application may need to deselect, unrealize, select, and realize the logical palette to ensure that the colors are updated exactly as requested. If an application selects a logical palette into more than one device context, changes to the logical palette affect all device contexts for which it is selected.

An application can change the number of entries in a logical palette by using the ResizePalette function. If the application reduces the size, the remaining entries are unchanged. If the application extends the size, Windows sets the color for each new entry to black (0, 0, 0) and the flag to zero.

An application can retrieve the color and flag values for entries in a given logical palette by using the GetPaletteEntries function. An application can retrieve the index for the entry in a given logical palette that most closely matches a specified color value by using the GetNearestPaletteIndex function.

When an application no longer needs a logical palette, it can delete it by using the DeleteObject function. The application must make sure the logical palette is no longer selected into a device context before deleting the palette.


Palette Animation

Palette animation is a technique to simulate motion by rapidly changing the colors of selected entries in a color palette. An application can carry out palette animation by creating a logical palette that contains "reserved" entries and then using the AnimatePalette function to change colors in those reserved entries.

An application creates a reserved entry in a logical palette by setting the peFlags member of the PALETTEENTRY structure to the PC_RESERVED flag. Once this logical palette is selected and realized, the application can call the AnimatePalette function to change one or more reserved entries. If the given palette is associated with the active window, Windows updates the colors on the screen immediately.


System Palette

Windows maintains a system palette for each device that uses palettes. The system palette contains the color values for all colors that can currently be displayed or drawn by the device. Other than viewing the contents of the system palette, applications cannot access the system palette directly. Instead, Windows has complete control of the system palette and permits access only through the use of logical palettes.

An application can view the contents of the system palette by using the GetSystemPaletteEntries function. This function retrieves the contents of one or more entries, up to the total number of entries in the system palette. The total is always equal to the number returned for the SIZEPALETTE value by the GetDeviceCaps function and is the same as the maximum size for any given logical palette.

Although applications cannot change colors in the system palette directly, they may cause changes when realizing logical palettes. To realize a palette, Windows examines each requested color and attempts to find an entry in the system palette that contains an exact match. If Windows finds a matching color, it maps the logical palette index to the corresponding system palette index. If Windows does not find an exact match, it copies the requested color to an unused system palette entry before mapping the indices. If all system palette entries are in use, Windows maps the logical palette index to the system palette entry whose color most closely matches the requested color. Once this mapping is set, applications cannot override it. For example, applications cannot use system palette indices to specify colors; only logical palette indices are permitted.

Applications can modify the way indices are mapped by setting the peFlags member of the PALETTEENTRY structure to selected values when creating the logical palette. For example, the PC_NOCOLLAPSE flag directs Windows to immediately copy the requested color to an unused system palette entry regardless of whether a system palette entry already contains that color. Also, the PC_EXPLICIT flag directs Windows to map the logical palette index to an explicitly given system palette index. (The application gives the system palette index in the low-order word of the PALETTEENTRY structure.)

Palettes can be realized as either a background palette or a foreground palette by specifying TRUE or FALSE respectively for the bForceBackground parameter in the SelectPalette function. There can be only one foreground palette in the system at a time. If the window is the currently active window or a descendent of the currently active window, it can realize a foreground palette. Otherwise the palette is realized as a background palette regardless of the value of the bForceBackground parameter. The critical property of a foreground palette is that, when realized, it can overwrite all entries (except for the static entries) in the system palette. Windows accomplishes this by marking all of the entries that are not static in the system palette as unused before the realization of a foreground palette, thereby eliminating all of the used entries. No preprocessing occurs on the system palette for a background palette realization. The foreground palette sets all of the possible nonstatic colors. Background palettes can set only what remains open and are prioritized in a first-come, first-serve manner. Typically, applications use background palettes for child windows which realize their own individual palettes. This helps minimize the number of changes that occur to the system palette.

An unused system palette entry is any entry that is not reserved and does not contain a static color. Reserved entries are explicitly marked with the PC_RESERVED value. These entries are created when an application realizes a logical palette for palette animation. Static color entries are created by Windows and correspond to the colors in the default palette. The GetDeviceCaps function can be used to retrieve the NUMRESERVED value, which specifies the number of system palette entries reserved for static colors.

Because the system palette has a limited number of entries, selecting and realizing a logical palette for a given device may affect the colors associated with other logical palettes for the same device. These color changes are especially dramatic when they occur on the display. An application can make sure that reasonable colors are used for its currently selected logical palette by resetting the palette before each use. An application resets the palette by calling the UnrealizeObject and RealizePalette functions. Using these functions causes Windows to remap the colors in the logical palette to reasonable colors in the system palette.


System Palette and Static Colors

Ordinarily, the system palette entries that Windows reserves for static colors cannot be changed. An application can override this default behavior by using the SetSystemPaletteUse function to reduce the number of static color entries and, thereby, increase the number of unused system palette entries. However, because changing the static colors can have an immediate and dramatic effect on all windows on the display, an application should not call SetSystemPaletteUse, unless it has a maximized window and the input focus.

When an application calls SetSystemPaletteUse with the SYSPAL_NOSTATIC value, Windows frees all but two of the reserved entries, allowing those entries to receive new color values when the application subsequently realizes its logical palette. The remaining two static color entries remain reserved and are set to white and black. An application can restore the reserved entries by calling SetSystemPaletteUse with the SYSPAL_STATIC value. It can discover the current system palette usage by using the GetSystemPaletteUse function.

Furthermore, after setting the system palette usage to SYSPAL_NOSTATIC, the application must immediately realize its logical palette, call the GetSysColor function to save the current system color settings, call the SetSysColors function to set the system colors to reasonable values using black and white, and finally send the WM_SYSCOLORCHANGE message to other top-level windows to allow them to be redrawn with the new system colors. When setting system colors using black and white, the application should make sure adjacent or overlapping items, such as window frames and borders, are set to black and white, respectively.

Before the application loses the input focus, closes its window, or terminates, it must immediately call SetSystemPaletteUse with the SYSPAL_STATIC value, realize its logical palette, restore the system colors to their previous values, and send the WM_SYSCOLORCHANGE message. Windows sends a WM_PAINT message to any window that is affected by a system color change. Applications that have brushes using the existing system colors should delete those brushes and recreate them using the new system colors.


Palette Messages

Changes to the system palette for the display device can have dramatic and sometimes undesirable effects on the colors used in windows on the desktop. To minimize the impact of these changes, Windows provides a set of messages that help applications manage their logical palettes while ensuring that colors in the active window are as close as possible to the colors intended.

Windows sends a WM_QUERYNEWPALETTE message to a top-level or overlapped window just before activating the window. This message gives an application the opportunity to select and realize its logical palette so that it receives the best possible mapping of colors for its logical palette. When the application receives the message, it should use the SelectPalette, UnrealizeObject, and RealizePalette functions to select and realize the logical palette. Doing so directs Windows to update colors in the system palette so that its colors match as many colors in the logical palette as possible.

When an application causes changes to the system palette as a result of realizing its logical palette, Windows sends a WM_PALETTECHANGED message to all top-level and overlapped windows. This message gives applications the opportunity to update the colors in the client areas of their windows, replacing colors that have changed with colors that more closely match the intended colors. An application that receives the WM_PALETTECHANGED message should use UnrealizeObject and RealizePalette to reset the logical palettes associated with all inactive windows and then update the colors in the client area for each inactive window by using the UpdateColors function. This technique does not guarantee the greatest number of exact color matches; however, it does ensure that colors in the logical palette are mapped to reasonable colors in the system palette.

Note  To avoid creating an infinite loop, an application should never realize the palette for the window whose handle matches the handle passed in the wParam parameter of the WM_PALETTECHANGED message.

The UpdateColors function typically updates a client area of an inactive window faster than redrawing the area. However, because UpdateColors performs color translation based on the color of each pixel before the system palette changed, each call to this function results in the loss of some color accuracy. This means UpdateColors cannot be used to update colors when the window becomes active. In such cases, the application should redraw the client area.

Windows may send the WM_QUERYNEWPALETTE message when changes to the logical palette are made. Also, Windows may send the WM_PALETTEISCHANGING message to all top-level and overlapped windows when the system palette is about to change.


Halftone Palette and Color Adjustment

Halftone palettes are intended to be used whenever the stretching mode of a device context is set to HALFTONE. An application creates a halftone palette by using the CreateHalftonePalette function. The application must select and realize this palette into the device context before calling the StretchBlt or StretchDIBits function.

Windows automatically adjusts the input color of source bitmaps whenever applications call the StretchBlt and StretchDIBits functions and the stretching mode of a device context is set to HALFTONE. These color adjustments affect certain attributes of the image, such as contrast and brightness. An application can set the color adjustment values by using the SetColorAdjustment function. The application can retrieve the color adjustment values for the specified device context by using the GetColorAdjustment function.


Using Color

•	Enumerating colors

•	Creating colored pens and brushes


Enumerating Colors

You can determine how many colors a device supports and what those colors are by retrieving the count of colors for the device and enumerating the colors of the solid pens. To retrieve the number of colors, use the GetDeviceCaps function with the NUMCOLORS value. To enumerate solid pens, use the EnumObjects function and a corresponding callback function that receives information about each pen.

// GetTheColors - returns the count and color values of solid colors
// Returns the address of array containing colors
// hdc - handle of device context

COLORREF *GetTheColors(HDC hdc)
{
    int cColors;
    COLORREF *aColors;

    // Get the number of colors.
    cColors = GetDeviceCaps(hdcCurrent, NUMCOLORS);

    // Allocate space for the array.
    aColors = (COLORREF *)LocalAlloc(LPTR, sizeof(COLORREF) *
        (cColors+1));

    // Save the count of colors in first element.
    aColors[0] = (LONG)cColors;

    // Enumerate all pens and save solid colors in the array.
    EnumObjects(hdc, OBJ_PEN, (GOBJENUMPROC)MyEnumProc, (LONG)aColors);

    // Refresh the count of colors.
    aColors[0] = (LONG)cColors;

    return aColors;
}

int MyEnumProc(LPVOID lp, LPBYTE lpb)
{
    LPLOGPEN lopn;
    COLORREF *aColors;
    int iColor;

    lopn = (LPLOGPEN)lp;
    aColors = (COLORREF *)lpb;

    if (lopn->lopnStyle==PS_SOLID) {
        // Check for too many colors.
        if ((iColor = (int)aColors[0]) <= 0)
             return 0;
        aColors[iColor] = lopn->lopnColor;
        aColors[0]--;
    }
    return 1;
}


Creating Colored Pens and Brushes

Although you can specify any color for a pen when creating it, Windows uses only colors that are available on the device. This means Windows uses the closest matching color when it realizes the pen for drawing. When creating brushes, Windows generates a dithered color if you specify a color that the device does not support. In either case, you can use the RGB macro to specify a color when creating a pen or brush.

// DrawARectangle - draws a red rectangle with a green border
// No return value.
// hdc - handle of the device context

void DrawARectangle(HDC hdc)

{
    HPEN hpen, hpenOld;
    HBRUSH hbrush, hbrushOld;

    // Create a green pen.
    hpen = CreatePen(PS_SOLID, 10, RGB(0, 255, 0));
    // Create a red brush.
    hbrush = CreateSolidBrush(RGB(255, 0, 0));

    // Select the new pen and brush, and then draw.
    hpenOld = SelectObject(hdc, hpen);
    hbrushOld = SelectObject(hdc, hbrush);
    Rectangle(hdc, 100,100, 200,200);

    // Do not forget to clean up.
    SelectObject(hdc, hpenOld);
    DeleteObject(hpen);
    SelectObject(hdc, hbrushOld);
    DeleteObject(hbrush);
}


Color Reference

The following functions and messages are associated with color.


Color Functions

Following are the functions used with color.

AnimatePalette
CreateHalftonePalette
CreatePalette
GetColorAdjustment
GetNearestColor
GetNearestPaletteIndex
GetPaletteEntries
GetSystemPaletteEntries
GetSystemPaletteUse
RealizePalette
ResizePalette
SelectPalette
SetColorAdjustment
SetPaletteEntries
SetSystemPaletteUse
UnrealizeObject
UpdateColors


Color Messages

Following are the messages used with color.

WM_PALETTECHANGED
WM_PALETTEISCHANGING
WM_QUERYNEWPALETTE
WM_SYSCOLORCHANGE


Coordinate Spaces and Transformations

Applications written for the Microsoft® Windows® operating system use coordinate spaces and transformations to scale, rotate, translate, shear, and reflect graphics output. A coordinate space is a planar space based on the Cartesian coordinate system. This system requires two axes that are perpendicular and equal in length. There are four coordinate spaces in Windows: world, page, device, and physical device (client area, or desktop, or page of printer paper). A transformation is an algorithm that alters ("transforms") the size, orientation, and shape of objects.


About Coordinate Spaces and Transformations

Coordinate spaces and transformations are used, for example, by desktop publishing applications to "zoom" parts of a page or to display adjacent pages in a window; computer-aided design (CAD) applications use them to rotate objects, scale drawings, or to create perspective views; and spreadsheet applications use them to move and size graphs.

The following illustrations show successive views of an object created in a drawing application. The first illustration shows the object as it appears in the original drawing; the five remaining illustrations show the effects of applying various transformations.

Original View

Scaled View

Translated View

Rotated View

Sheared View

Reflection


Transformation of Coordinate Spaces

A coordinate space is a planar space based on the Cartesian coordinate system. This system provides a means of specifying the location of each point on a plane. It requires two axes that are perpendicular and equal in length. The following illustration shows a coordinate space.

The Microsoft® ( ) Win32® application programming interface (API) uses four coordinate spaces: world, page, device, and physical device. Applications use world space to rotate, shear, or reflect graphics output. World space measures 2^32 units high by 2^32 units wide. Page space (referred to as logical space in earlier versions of Windows) also measures 2^32 units high by 2^32 units wide. Device space measures 2^27 units high by 2^27 units wide. Page space works with device space to provide applications with device-independent units, such as millimeters and inches. The Win32 API refers to both world space and page space as logical space. The final coordinate space, physical device, usually refers to the client area of the application's window; however, it can also include the entire desktop, a complete window (including the frame, title bar, and menu bar), or a page of printer or plotter paper. Physical device dimensions vary according to the dimensions set by the display, printer, or plotter technology.

To depict output on a physical device, Windows copies (or maps) a rectangular region from one coordinate space into the next coordinate space until finally the output appears in its entirety on the physical device. Mapping begins in the application's world space if the application has called the SetWorldTransform function; otherwise, mapping occurs in page space. As Windows copies each point within the rectangular region from one space into another, it applies an algorithm called a transformation. A transformation alters (or transforms) the size, orientation, and shape of objects that are copied from one coordinate space into another. Although a transformation affects an object as a whole, it is applied to each point, or to each line, in the object.

The following illustration shows a typical transformation performed by using the SetWorldTransform function.


World-Space to Page-Space Transformations

World-space to page-space transformations are new to Windows. They support translation and scaling that were available in previous versions of Windows. In addition, they support rotation, shear, and reflection capabilities. The following sections describe these transformations, illustrate their effects, and provide the algorithms used to achieve them.


Translation

Some applications translate (or shift) objects drawn in the client area. If your application features this capability, use the SetWorldTransform function to set the appropriate world-space to page-space transformation. This function receives a pointer to an XFORM structure containing the appropriate values. The eDx and eDy members of XFORM specify the horizontal and vertical translation components, respectively.

When translation occurs, each point in an object is shifted vertically, horizontally, or both, by a specified amount. The following illustration shows a 20- by 20-unit rectangle that was translated to the right by 10 units when copied from world coordinate space to page coordinate space.

In the preceding illustration, the x-coordinate of each point in the rectangle is 10 units greater than the original x-coordinate.

Horizontal translation can be represented by the following algorithm.

x' = x + Dx

Where x' is the new x-coordinate, x is the original x-coordinate, and Dx is the horizontal distance moved.

Vertical translation can be represented by the following algorithm.

y' = y + Dy

Where y' is the new y-coordinate, y is the original y-coordinate, and Dy is the vertical distance moved.

The horizontal and vertical translation transformations can be combined into a single operation by using a 3-by-3 matrix.

                      |1   0   0|

|x' y' 1| = |x y 1| * |0   1   0|

                      |Dx  Dy  1|

(The rules of matrix multiplication state that the number of rows in one matrix must equal the number of columns in the other. The integer 1 in the matrix |x y 1| is a placeholder that was added to meet this requirement.)

The 3-by-3 matrix that produced the illustrated translation transformation contains the following values.

|1  0  0|

|0  1  0|

|10 0  1|


Scaling

Most CAD and drawing applications provide features that scale output created by the user. If your application features scaling (or zoom) capabilities, use the SetWorldTransform function to set the appropriate world-space to page-space transformation. This function receives a pointer to an XFORM structure containing the appropriate values. The eM11 and eM22 members of XFORM specify the horizontal and vertical scaling components, respectively.

When scaling occurs, the vertical and horizontal lines (or vectors), that constitute an object, are stretched or compressed with respect to the x- or y-axis. The following illustration shows a 20- by 20-unit rectangle scaled vertically to twice its original height when copied from world coordinate space to page coordinate space.

In the preceding illustration, the vertical lines that define the original rectangle's side measure 20 units, while the vertical lines that define the scaled rectangle's sides measure 40 units.

Vertical scaling can be represented by the following algorithm.

y' = y * Dy

Where y' is the new length, y is the original length, and Dy is the vertical scaling factor.

Horizontal scaling can be represented by the following algorithm.

x' = x * Dx

Where x' is the new length, x is the original length, and Dx is the horizontal scaling factor.

The vertical and horizontal scaling transformations can be combined into a single operation by using a 2-by-2 matrix.

|x' y'|  =  |Dx   0|  *  |x y|

            |0   Dy|

The 2-by-2 matrix that produced the scaling transformation contains the following values.

|1    0|

|0    2|


Rotation

Many CAD applications provide features that rotate objects drawn in the client area. If your application features rotation capabilities, use the SetWorldTransform function to set the appropriate world-space to page-space transformation. This function receives a pointer to an XFORM structure containing the appropriate values. The eM11, eM12, eM21, and eM22 members of XFORM specify, respectively, the cosine, sine, negative sine, and cosine of the angle of rotation.

When rotation occurs, the points that constitute an object are rotated with respect to the coordinate-space origin. The following illustration shows a 20- by 20-unit rectangle rotated 30 degrees when copied from world coordinate space to page coordinate space.

In the preceding illustration, each point in the rectangle was rotated 30 degrees with respect to the coordinate-space origin.

The following algorithm computes the new x-coordinate (x') for a point (x,y) that is rotated by angle A with respect to the coordinate-space origin.

x' = (x * cos A) - (y * sin A)

The following algorithm computes the y-coordinate (y') for a point (x,y) that is rotated by the angle A with respect to the origin.

y' = (x * sin A) + (y * cos A)

The two rotation transformations can be combined in a 2-by-2 matrix as follows.

|x' y'| == |x y| * | cos A   sin A|

                   |-sin A   cos A|

The 2-by-2 matrix that produced the rotation contains the following values.

| .8660    .5000|

|-.5000    .8660|

Rotation Algorithm Derivation

Rotation algorithms are based on trigonometry's addition theorem stating that the trigonometric function of a sum of two angles (A1 and A2) can be expressed in terms of the trigonometric functions of the two angles.

sin(A1 + A2) = (sin A1 * cos A2) + (cos A1 * sin A2)

cos(A1 + A2) = (cos A1 * cos A2) - (sin A1 * sin A2)

The following illustration shows a point p rotated counterclockwise to a new position p'. In addition, it shows two triangles formed by a line drawn from the coordinate-space origin to each point and a line drawn from each point through the x-axis.

Using trigonometry, the x-coordinate of point p can be obtained by multiplying the length of the hypotenuse h by the cosine of A1.

x = h * cos A1

The y-coordinate of point p can be obtained by multiplying the length of the hypotenuse h by the sine of A1.

y = h * sin A1

Likewise, the x-coordinate of point p' can be obtained by multiplying the length of the hypotenuse h by the cosine of (A1 + A2).

x' = h * cos (A1 + A2)

Finally, the y-coordinate of point p' can be obtained by multiplying the length of the hypotenuse h by the sine of (A1 + A2).

y' = h * sin (A1 + A2)

Using the addition theorem, the preceding algorithms become the following.

x' = (h * cos A1 * cos A2) - (h * sin A1 * sin A2)

y' = (h * cos A1 * sin A2) + (h * sin A1 * cos A2)

The rotation algorithms for a given point rotated by angle A2 can be obtained by substituting x for each occurrence of (h * cos A1) and substituting y for each occurrence of (h * sin A1).

x' = (x * cos A2) - (y * sin A2)

y' = (x * sin A2) + (y * cos A2)


Shear

Some applications provide features that shear objects drawn in the client area. If your application features shear capabilities, use the SetWorldTransform function to set appropriate values in the world-space to page-space transformation. This function receives a pointer to an XFORM structure containing the appropriate values. The eM12 and eM21 members of XFORM specify the horizontal and vertical proportionality constants, respectively.

There are two components of the shear transformation. The first alters the vertical lines in an object; the second alters the horizontal lines. The following illustration shows a 20- by 20-unit rectangle sheared horizontally when copied from world space to page space.

A horizontal shear can be represented by the following algorithm:

x' = x + (Sx * y)

where x is the original x-coordinate, Sx is the proportionality constant, and x' is the result of the shear transformation.

A vertical shear can be represented by the following algorithm:

y' = y + (Sy * x)

where y is the original y-coordinate, Sy is the proportionality constant, and y' is the result of the shear transformation.

The horizontal-shear and vertical-shear transformations can be combined into a single operation using a 2-by-2 matrix.

|x' y'| == |x y| * |  1   Sx|

                   | Sy    1|

The 2-by-2 matrix that produced the shear contains the following values.

|1    1|

|0    1|


Reflection

Some applications provide features that reflect (or mirror) objects drawn in the client area. If your application features reflection capabilities, use the SetWorldTransform function to set the appropriate values in the world-space to page-space transformation. This function receives a pointer to an XFORM structure containing the appropriate values. The eM11 and eM22 members of XFORM specify the horizontal and vertical reflection components, respectively.

The reflection transformation creates a "mirror" image of an object with respect to either the x- or y-axis. In short, reflection is just negative scaling. To produce a horizontal reflection, x-coordinates are multiplied by −1. To produce a vertical reflection, y-coordinates are multiplied by  − 1.

Horizontal reflection can be represented by the following algorithm:

x' = −x

where x is the x-coordinate and x' is the result of the reflection.

The 2-by-2 matrix that produced horizontal reflection contains the following values:

|-1    0|

|0     1|

Vertical reflection can be represented by the following algorithm:

y' = -y

where y is the y-coordinate and y' is the result of the reflection.

The 2-by-2 matrix that produced vertical reflection contains the following values:

|1    0|

|0   -1|

The horizontal-reflection and vertical-reflection operations can be combined into a single operation by using the following 2-by-2 matrix:

|-1    0|

|0    -1|


Combined World-to-Page Space Transformations

You can combine the five world-to-page transformations into a single 3-by-3 matrix. The CombineTransform function can be used to combine two world-space to page-space transformations. You can use the combined transformations to alter output associated with a particular device context (DC) by calling the SetWorldTransform function and supplying the elements for this matrix. When an application calls SetWorldTransform, it stores the elements of the 3-by-3 matrix in an XFORM structure. The members of this structure correspond to the first two columns of a 3-by-3 matrix; the last column of the matrix is not required because its values are constant.

You can retrieve the elements of the current world transformation matrix by calling the GetWorldTransform function and supplying a pointer to an XFORM structure.


Page-Space to Device-Space Transformations

The page-space to device-space transformation was part of the original Windows interface. This transformation determines the mapping mode for all graphics output associated with a particular DC. A mapping mode is a scaling transformation that specifies the size of the units used for drawing operations. The mapping mode may also perform translation. In some cases, the mapping mode alters the orientation of the x- and y-axes in device space. The mapping modes are described in the following table.

Mapping mode	Description
MM_ANISOTROPIC	Each unit in page space is mapped to an application-specified unit in device space. The axis may or may not be equally scaled (for example, a circle drawn in world space may appear to be an ellipse when depicted on a given device). The orientation of the axis is also specified by the application.
MM_HIENGLISH	Each unit in page space is mapped to 0.001 inch in device space. Increasing values of x occur as you move to the right; increasing values of y occur as you move up.
MM_HIMETRIC	Each unit in page space is mapped to 0.01 millimeter in device space. Increasing values of x occur as you move to the right; increasing values of y occur as you move up.
MM_ISOTROPIC	Each unit in page space is mapped to an application-defined unit in device space. The axes are always equally scaled. The orientation of the axes may be specified by the application.
MM_LOENGLISH	Each unit in page space is mapped to 0.01 inch in device space. Increasing values of x occur as you move to the right; increasing values of y occur as you move up.
MM_LOMETRIC	Each unit in page space is mapped to 0.1 millimeter in device space. Increasing values of x occur as you move to the right; increasing values of y occur as you move up.
MM_TEXT	Each unit in page space is mapped to one pixel; that is, no scaling is performed at all. When no translation is in effect (this is the default), page space in the MM_TEXT mapping mode is equivalent to physical device space. Increasing values of x occur as you move to the right; increasing values of y occur as you move down.
MM_TWIPS	Each unit in page space is mapped to one twentieth of a printer's point (1/1440 inch). Increasing values of x occur as you move to the right; increasing values of y occur as you move up.
You set a mapping mode by calling the SetMapMode function. You retrieve the current mapping mode for a DC by calling the GetMapMode function.

The page-space to device-space transformations consist of values calculated from the points given by the window and viewport. The window and viewport each consist of a pair of points, with one point specifying an origin and the other a width and height (called the extents). The window points are in logical coordinates; the viewport in device coordinates (pixels). Windows combines the origins and extents from both the window and viewport to create the transformation. This means that the window and viewport each specify half of the factors needed to define the transformation used to map points in page space to device space. The effect of a transformation calculated in this way is that Windows maps the window origin to the viewport origin and the window extents to the viewport extents, as shown in the following illustration.

The window and viewport extents establish a ratio or scaling factor used in the page-space to device-space transformations. For the six predefined mapping modes (MM_HIENGLISH, MM_LOENGLISH, MM_HIMETRIC, MM_LOMETRIC, MM_TEXT, and MM_TWIPS), the extents are set by Windows when you call SetMapMode. They cannot be changed. The other two mapping modes (MM_ISOTROPIC and MM_ANISOTROPIC) require that you specify the extents. This is done by calling SetMapMode to set the appropriate mode and then calling the SetWindowExtEx and SetViewportExtEx functions to specify the extents. In the MM_ISOTROPIC mapping mode, it is important to call SetWindowExtEx before calling SetViewportExtEx.

The window and viewport origins establish the translation used in the page-space to device-space transformations. You set the window and viewport origins by using the SetWindowOrgEx and SetViewportOrgEx functions. The origins are independent of the extents, and an application can set them regardless of the current mapping mode. Changing a mapping mode does not affect the currently set origins (although it can affect the extents). Origins are specified in absolute units that the current mapping mode does not affect. You can also alter the origins by using the OffsetWindowOrgEx and OffsetViewportOrgEx functions.

The following formula shows the math involved in converting a point from page space to device space.

Dx = ((Lx - WOx) * VEx / WEx) + VOx

The following variables are involved.

Dx	 x value in device units

Lx	 x value in logical units (also known as page space units)

WOx	 window x origin

VOx	 viewport x origin

WEx	 window x-extent

VEx	 viewport x-extent

The same equation with y replacing x transforms the y component of a point.

The formula first offsets the point from its coordinate origin. This value, no longer biased by the origin, is then scaled into the destination coordinate system by the ratio of the extents. Finally, the scaled value is offset by the destination origin to its final mapping.

The LPtoDP and DPtoLP functions may be used to convert from logical points to device points and from device points to logical points, respectively.


Predefined Mapping Modes

Of the six predefined mapping modes, one is device dependent (MM_TEXT) while the remaining five (MM_HIENGLISH, MM_LOENGLISH, MM_HIMETRIC, MM_LOMETRIC, and MM_TWIPS) are device independent.

The default mapping mode is MM_TEXT. One logical unit equals one pixel. Positive x is to the right, and positive y is down. This mode maps directly to the device's coordinate system. The logical-to-physical mapping involves only an offset in x and y that is defined by the application-controlled window and viewport origins. The viewport and window extents are all set to 1, creating a one-to-one mapping.

If your application displays geometric shapes (circles, squares, polygons, and so on), you may want to choose one of the device-independent mapping modes. For example, if you are writing code to provide charting capabilities for a spreadsheet application and want to guarantee that the diameter of each pie chart is 2 inches, you can choose the MM_LOENGLISH mapping mode and call the appropriate functions to draw and fill the chart. By specifying MM_LOENGLISH, you guarantee that the diameter of the chart is consistent on any display or printer. If you were to choose MM_TEXT instead of MM_LOENGLISH, a chart that appears circular on a VGA display would appear elliptical on an EGA display and would appear very small on a 300 dpi (dots per inch) laser printer.


Application-Defined Mapping Modes

The two application-defined mapping modes (MM_ISOTROPIC and MM_ANISOTROPIC) are provided for application-specific mapping modes. The MM_ISOTROPIC mode guarantees that logical units in the x-direction and in the y-direction are equal, while the MM_ANISOTROPIC mode allows the units to differ. A CAD or drawing application can benefit from the MM_ISOTROPIC mapping mode but may need to specify logical units that correspond to the increments on an engineer's scale (1/64 inch). These units would be difficult to obtain with the predefined mapping modes (MM_HIENGLISH or MM_HIMETRIC); however, they can easily be obtained by selecting the MM_ISOTROPIC (or MM_ANISOTROPIC) mode. The following example shows how to set logical units to 1/64 inch:

SetMapMode(hDC, MM_ISOTROPIC);

SetWindowExtEx(hDC, 64, 64, NULL);

SetViewportExtEx(hDC, GetDeviceCaps(hDC, LOGPIXELSX),

                      GetDeviceCaps(hDC, LOGPIXELSY), NULL);


Device-Space to Physical-Device Transformation

The device-space to physical-device transformation is unique in several respects. For example, it is limited to translation and is controlled by the window manager component of Windows. The sole purpose of this transformation is to ensure that the origin of device space is mapped to the proper point on the physical device. There are no functions to set this transformation, nor are there any functions to retrieve related data.


Default Transformations

Whenever an application creates a DC and immediately begins calling GDI drawing or output functions, it takes advantage of the default page-space to device-space, and device-space to client-area transformations. A world-to-page space transformation cannot happen until the application first calls the SetGraphicsMode function to set the mode to GM_ADVANCED and then calls the SetWorldTransform function.

Use of MM_TEXT (the default page-space to device-space transformation) results in a one-to-one mapping; that is, a given point in page space maps to the same point in device space. As previously mentioned, this transformation is not specified by a matrix. Instead, it is obtained by dividing the width of the viewport by the width of the window and the height of the viewport by the height of the window. In the default case, the viewport dimensions are 1-pixel by 1-pixel and the window dimensions are 1-page unit by 1-page unit.

The device-space to physical-device (client area, desktop, or printer paper) transformation always results in a one-to-one mapping; that is, one unit in device space is always equivalent to one unit in the client area, on the desktop, or on a page. The sole purpose of this transformation is translation; it ensures that output appears correctly in an application's window no matter where that window is moved on the desktop.

The one unique aspect of MM_TEXT is the orientation of the y-axis in page space. In MM_TEXT, the positive y-axis extends downward and the negative y-axis extends upward.


Using Coordinate Spaces and Transformations

This section contains an example that demonstrates the following tasks:

•	Drawing graphics with predefined units.

•	Centering graphics in the application's client area.

•	Scaling graphics output to half its original size.

•	Translating graphics output 3/4 of an inch to the right.

•	Rotating graphics 30 degrees.

•	Shearing graphics output along the x-axis.

•	Reflecting graphics output about an imaginary horizontal axis drawn through its midpoint.

The following example was used to create the illustrations that appear earlier in this topic.

void TransformAndDraw(int iTransform, HWND hWnd)

{

HDC hDC;

XFORM xForm;

RECT rect;

/* Retrieve a DC handle for the application's window. */

hDC = GetDC(hWnd);

/*

 * Set the mapping mode to LOENGLISH. This moves the

 * client area origin from the upper left corner of the

 * window to the lower left corner (this also reorients

 * the y-axis so that drawing operations occur in a true

 * Cartesian space). It guarantees portability so that

 * the object drawn retains its dimensions on any

 * display running Windows.

 */

SetMapMode(hDC, MM_LOENGLISH);

/*

 * Set the appropriate world transformation (based on the

 * user's menu selection).

 */

switch (iTransform) {

        case SCALE:        /* Scale to 1/2 of the original size. */

            xForm.eM11 = (FLOAT) 0.5;

            xForm.eM12 = (FLOAT) 0.0;

            xForm.eM21 = (FLOAT) 0.0;

            xForm.eM22 = (FLOAT) 0.5;

            xForm.eDx  = (FLOAT) 0.0;

            xForm.eDy  = (FLOAT) 0.0;

            SetWorldTransform(hDC, &xForm);

            break;

        case TRANSLATE:   /* Translate right by 3/4 inch. */

            xForm.eM11 = (FLOAT) 1.0;

            xForm.eM12 = (FLOAT) 0.0;

            xForm.eM21 = (FLOAT) 0.0;

            xForm.eM22 = (FLOAT) 1.0;

            xForm.eDx  = (FLOAT) 75.0;

            xForm.eDy  = (FLOAT) 0.0;

            SetWorldTransform(hDC, &xForm);

            break;

        case ROTATE:      /* Rotate 30 degrees counterclockwise. */

            xForm.eM11 = (FLOAT) 0.8660;

            xForm.eM12 = (FLOAT) 0.5000;

            xForm.eM21 = (FLOAT) -0.5000;

            xForm.eM22 = (FLOAT) 0.8660;

            xForm.eDx  = (FLOAT) 0.0;

            xForm.eDy  = (FLOAT) 0.0;

            SetWorldTransform(hDC, &xForm);

            break;

        case SHEAR:       /* Shear along the x-axis with a    */

                          /* proportionality constant of 1.0. */

            xForm.eM11 = (FLOAT) 1.0;

            xForm.eM12 = (FLOAT) 1.0;

            xForm.eM21 = (FLOAT) 0.0;

            xForm.eM22 = (FLOAT) 1.0;

            xForm.eDx  = (FLOAT) 0.0;

            xForm.eDy  = (FLOAT) 0.0;

            SetWorldTransform(hDC, &xForm);

            break;

        case REFLECT:     /* Reflect about a horizontal axis. */

            xForm.eM11 = (FLOAT) 1.0;

            xForm.eM12 = (FLOAT) 0.0;

            xForm.eM21 = (FLOAT) 0.0;

            xForm.eM22 = (FLOAT) -1.0;

            xForm.eDx  = (FLOAT) 0.0;

            xForm.eDy  = (FLOAT) 0.0;

            SetWorldTransform(hDC, &xForm);

            break;

        case NORMAL:      /* Set the unity transformation. */

            xForm.eM11 = (FLOAT) 1.0;

            xForm.eM12 = (FLOAT) 0.0;

            xForm.eM21 = (FLOAT) 0.0;

            xForm.eM22 = (FLOAT) 1.0;

            xForm.eDx  = (FLOAT) 0.0;

            xForm.eDy  = (FLOAT) 0.0;

            SetWorldTransform(hDC, &xForm);

            break;

    }

/* Find the midpoint of the client area. */

GetClientRect(hWnd, (LPRECT) &rect);

DPtoLP(hDC, (LPPOINT) &rect, 2);

/* Select a hollow brush. */

SelectObject(hDC, GetStockObject(HOLLOW_BRUSH));

/* Draw the exterior circle. */

Ellipse(hDC, (rect.right / 2 - 100), (rect.bottom / 2 + 100),

    (rect.right / 2 + 100), (rect.bottom / 2 - 100));

/* Draw the interior circle. */

Ellipse(hDC, (rect.right / 2 -94), (rect.bottom / 2 + 94),

    (rect.right / 2 + 94), (rect.bottom / 2 - 94));

/* Draw the key. */

Rectangle(hDC, (rect.right / 2 - 13), (rect.bottom / 2 + 113),

    (rect.right / 2 + 13), (rect.bottom / 2 + 50));

Rectangle(hDC, (rect.right / 2 - 13), (rect.bottom / 2 + 96),

    (rect.right / 2 + 13), (rect.bottom / 2 + 50));

/* Draw the horizontal lines. */

MoveToEx(hDC, (rect.right / 2 - 150), (rect.bottom / 2 + 0), NULL);

LineTo(hDC, (rect.right / 2 - 16), (rect.bottom / 2 + 0));

MoveToEx(hDC, (rect.right / 2 - 13), (rect.bottom / 2 + 0), NULL);

LineTo(hDC, (rect.right / 2 + 13), (rect.bottom / 2 + 0));

MoveToEx(hDC, (rect.right / 2 + 16), (rect.bottom / 2 + 0), NULL);

LineTo(hDC, (rect.right / 2 + 150), (rect.bottom / 2 + 0));

/* Draw the vertical lines. */

MoveToEx(hDC, (rect.right / 2 + 0), (rect.bottom / 2 - 150), NULL);

LineTo(hDC, (rect.right / 2 + 0), (rect.bottom / 2 - 16));

MoveToEx(hDC, (rect.right / 2 + 0), (rect.bottom / 2 - 13), NULL);

LineTo(hDC, (rect.right / 2 + 0), (rect.bottom / 2 + 13));

MoveToEx(hDC, (rect.right / 2 + 0), (rect.bottom / 2 + 16), NULL);

LineTo(hDC, (rect.right / 2 + 0), (rect.bottom / 2 + 150));

ReleaseDC(hWnd, hDC);

}


Coordinate Space and Transformation Functions

Following are the functions used with coordinate spaces and transformations.

ClientToScreen
CombineTransform
DPtoLP
GetCurrentPositionEx
GetGraphicsMode
GetMapMode
GetViewportExtEx
GetViewportOrgEx
GetWindowExtEx
GetWindowOrgEx
GetWorldTransform
LPtoDP
MapWindowPoints
ModifyWorldTransform
OffsetViewportOrgEx
OffsetWindowOrgEx
ScaleViewportExtEx
ScaleWindowExtEx
ScreenToClient
SetGraphicsMode
SetMapMode
SetViewportExtEx
SetViewportOrgEx
SetWindowExtEx
SetWindowOrgEx
SetWorldTransform


Device Contexts

A device context is a structure that defines a set of graphic objects and their associated attributes, and the graphic modes that affect output. The graphic objects include a pen for line drawing, a brush for painting and filling, a bitmap for copying or scrolling parts of the screen, a palette for defining the set of available colors, a region for clipping and other operations, and a path for painting and drawing operations.


About Device Contexts

One of the chief features of the Microsoft® Win32® application programming interface (API) is device independence. Win32-based applications can draw and print output on a variety of devices. The software that supports this device independence is contained in two dynamic-link libraries. The first, GDI.DLL, is referred to as the graphics device interface (GDI); the second is referred to as a device driver. The name of the second depends on the device where the application draws output. For example, if the application draws output in the client area of its window on a VGA display, this library is VGA.DLL; if the application prints output on an Epson® FX-80 printer, this library is EPSON9.DLL.

An application must inform GDI to load a particular device driver and, once the driver is loaded, to prepare the device for drawing operations (such as selecting a line color and width, a brush pattern and color, a font typeface, a clipping region, and so on). These tasks are accomplished by creating and maintaining a device context. A device context is a structure that defines a set of graphic objects and their associated attributes, and the graphic modes that affect output. The graphic objects include a pen for line drawing, a brush for painting and filling, a bitmap for copying or scrolling parts of the screen, a palette for defining the set of available colors, a region for clipping and other operations, and a path for painting and drawing operations. Unlike most of the Win32 structures, an application never has direct access to the device context; instead, it operates on the structure indirectly by calling various functions.


Graphic Objects

The pen, brush, bitmap, palette, region, and path associated with a device context are referred to as the device context's graphic objects. Following are the attributes associated with each of these objects.

Graphic object	Associated attributes
Bitmap	Size, in bytes; dimensions, in pixels; color-format; compression scheme; and so on
Brush	Style, color, pattern, and origin
Palette	Colors and size (or number of colors)
Font	Typeface name, width, height, weight, character set, and so on
Path	Shape
Pen	Style, width, and color
Region	Location and dimensions
When an application creates a device context, Windows automatically stores a set of default objects in it. (There is no default bitmap or path.) An application can examine the attributes of the default objects by calling the GetCurrentObject and GetObject functions. The application can change these defaults by creating a new object and selecting it into the device context. An object is selected into a device context by calling the SelectObject function.


Graphic Modes

Windows supports five graphic modes that allow an application to specify how colors are mixed, where output appears, how the output is scaled, and so on. These modes, which are stored in a device context, are described in the following table.

Mode	Description
Background mode	Defines how background colors are mixed with existing window or screen colors for bitmap and text operations.
Drawing mode	Defines how foreground colors are mixed with existing window or screen colors for pen, brush, bitmap, and text operations.
Mapping mode	Defines how graphics output is mapped from logical (or world) space onto the window, screen, or printer paper.
Polygon-fill mode	Defines how the brush pattern is used to fill the interior of complex regions.
Stretching mode	Defines how bitmap colors are mixed with existing window or screen colors when the bitmap is compressed (or scaled down).
As it does with graphic objects, Windows initializes a device context with default graphic modes. An application can retrieve and examine these default modes by calling the following functions.

Graphic mode	Function
Background mode	GetBkMode
Drawing mode	GetROP2
Mapping mode	GetMapMode
Polygon-fill mode	GetPolyFillMode
Stretching mode	GetStretchBltMode
An application can change the default modes by calling one of the following functions.

Graphic mode	Function
Background mode	SetBkMode
Drawing mode	SetROP2
Mapping mode	SetMapMode
Polygon-fill mode	SetPolyFillMode
Stretching mode	SetStretchBltMode


Device Context Types

The Win32 API provides four types of device contexts: display, printer, memory (or compatible), and information. Each type serves a specific purpose, as described in the following table.

Device context	Purpose
Display	Supports drawing operations on a video display.
Printer	Supports drawing operations on a printer or plotter.
Memory	Supports drawing operations on a bitmap.
Information	Supports the retrieval of device data.


Display Device Contexts

Windows provides three types of device contexts for video displays: class, common and private. Class and private device contexts are used in applications that perform numerous drawing operations such as computer-aided design (CAD) applications, desktop-publishing applications, drawing and painting applications, and so on. Common device contexts are used in applications that perform infrequent drawing operations.

An application obtains a display device context by calling either the BeginPaint or GetDC function and identifying the window in which the corresponding output will appear. (The type of device context Windows returns is dependent on how the application registered its window class.) Typically, an application obtains a display device context only when it must draw in the client area. When the application is finished drawing, it must release the device context by calling the EndPaint or ReleaseDC function.

Class Device Contexts

Class device contexts are supported strictly for compatibility with previous versions of Windows. When writing a Win32-based application, avoid using the class device context. Use a private device context instead.

Common Device Contexts

Common device contexts are display device contexts maintained in a special cache by the window-management component of the Win32 API. An application obtains a handle identifying one of the available common device contexts by calling the GetDC, GetDCEx, or BeginPaint function. Before returning this device context handle, Windows initializes a common device context with default objects, attributes, and modes. Any drawing operations performed by the application use these defaults unless one of the GDI functions is called to select a new object, change the attributes of an existing object, or select a new mode.

Because only a limited number of common device contexts exist in the window manager's heap, an application should release these device contexts after it has finished drawing. An application releases a common device context by calling the ReleaseDC or EndPaint function. When the application releases a common device context, any changes to the default data are lost.

Private Device Contexts

Private device contexts are display device contexts that, unlike common device contexts, retain any changes to the default data — even after an application calls the ReleaseDC or EndPaint function. Private device contexts are not part of the window manager's cache and therefore need not be released after use. The window manager automatically removes a private device context after the last window of that class has been destroyed.

An application creates a private device context by first specifying the CS_OWNDC window-class style when it initializes the style member of the WNDCLASS structure and calls the RegisterClass function. (For more information about window classes, see Window Classes.) After creating a window with the CS_OWNDC style, an application can call the GetDC, GetDCEx, or BeginPaint function once to obtain a handle identifying a private device context. The application can continue using this handle (and the associated device context) until it deletes the window created with this class. Any changes to graphic objects and their attributes, or graphic modes are retained by Windows until the window is deleted.


Printer Device Contexts

Windows provides a single type of printer device context that can be used when printing on a dot-matrix printer, ink-jet printer, laser printer, or plotter. An application creates a printer device context by calling the CreateDC function and supplying the appropriate arguments (the name of the printer driver, the name of the printer, the file or device name for the physical output medium, and other initialization data). When an application has finished printing, it deletes the printer device context by calling the DeleteDC function. An application must delete (rather than release) a printer device context; the ReleaseDC function fails when an application attempts to use it to release a printer device context.


Memory Device Contexts

Windows supports a memory device context that stores bitmapped images for a particular device. An application creates a memory device context by calling the CreateCompatibleDC function and supplying a handle that identifies a device context for a particular device. When Windows processes this call, it creates a bitmap having a color format compatible with the original device. Because the bitmap is compatible with the given device, a memory device context is also sometimes referred to as a compatible device context.

The original bitmap in a memory device context is simply a placeholder. Its dimensions are one pixel by one pixel. Before an application can begin drawing, it must select a bitmap with the appropriate width and height into the device context by calling the SelectObject function. Once the new bitmap is selected into the memory device context, an application can begin using the device context to store images. For more information about bitmaps and bitmap operations, see Bitmaps.


Information Device Contexts

Windows supports an information device context used to retrieve default device data. For example, an application can call the CreateIC function to create an information device context for a particular model of printer and then call the GetCurrentObject and GetObject functions to retrieve the default pen or brush attributes. Because Windows can retrieve device information without creating the structures normally associated with the other types of device contexts, an information device context involves far less overhead and is created significantly faster than any of the other types. After an application finishes retrieving data by using an information device context, it must call the DeleteDC function.


Device Context Operations

An application can perform the following operations on a device context:

•	Enumerate existing graphic objects.

•	Select new graphic objects.

•	Delete existing graphic objects.

•	Save the current graphic objects, their attributes, and the graphic modes.

•	Restore previously saved graphic objects, their attributes, and the graphic modes.

In addition, an application can use a device context to determine how graphics output is translated, cancel lengthy drawing operations (begun by a thread in a multithreaded application), or reset a printer to a particular state.


Operations on Graphic Objects

Once an application creates a display or printer device context, it can begin drawing on the associated device or, in the case of the memory device context, it can begin drawing on the bitmap stored in memory. However, before drawing begins and sometimes while drawing is in progress, it is often necessary to replace the default objects with new objects.

An application can examine a default object's attributes by calling the GetCurrentObject and GetObject functions. The GetCurrentObject function returns a handle identifying the current pen, brush, palette, bitmap, or font, and the GetObject function initializes a structure containing that object's attributes.

Some printers provide resident pens, brushes, and fonts that can be used to improve drawing speed in an application. Two functions can be used to enumerate these objects: EnumObjects and EnumFontFamilies. If the application must enumerate resident pens or brushes, it can call the EnumObjects function to examine the corresponding attributes. If the application must enumerate resident fonts, it can call the EnumFontFamilies function (which can also enumerate GDI fonts).

Once an application determines that a default object needs replacing, it creates a new object by calling one of the following creation functions.

Graphic object	Function
Bitmap	CreateBitmap, CreateBitmapIndirect, CreateCompatibleBitmap, CreateDiscardableBitmap, CreateDIBitmap
Brush	CreateBrushIndirect, CreateDIBPatternBrush, CreateDIBPatternBrushPt, CreateHatchBrush, CreatePatternBrush, CreateSolidBrush
Color Palette	CreatePalette
Font	CreateFont, CreateFontIndirect
Pen	CreatePen, CreatePenIndirect, ExtCreatePen
Region	CreateEllipticRgn, CreateEllipticRgnIndirect, CreatePolygonRgn, CreatePolyPolygonRgn, CreateRectRgn, CreateRectRgnIndirect, CreateRoundRectRgn
Each of these functions returns a handle identifying a new object. After an application retrieves a handle, it must call the SelectObject function to replace the default object. However, the application should save the handle identifying the default object and use this handle to replace the new object when it is no longer needed. When the application finishes drawing with the new object, it must restore the default object by calling the SelectObject function and delete the new object by calling the DeleteObject function. Failing to delete objects causes serious performance problems.


Cancellation of Drawing Operations

When complex drawing applications perform lengthy graphics operations, they consume valuable system resources. By taking advantage of Win32 multitasking features, an application can use threads and the CancelDC function to manage these operations. For example, if the graphics operation performed by thread A is consuming needed resources, thread B can call the CancelDC function to halt that operation.


Retrieving Device Data

Windows supports two functions, GetDeviceCaps and DeviceCapabilities, that applications can use to retrieve device data using a device context. GetDeviceCaps retrieves general device data for the following devices:

•	Raster displays

•	Dot-matrix printers

•	Ink-jet printers

•	Laser printers

•	Vector plotters

•	Raster cameras

The data includes the supported capabilities of the device, including device resolution (for video displays), color format (for video displays and color printers), number of graphic objects, raster capabilities, curve drawing, line drawing, polygon drawing, and text drawing. An application retrieves this data by supplying a handle identifying the appropriate device context as well as an index specifying the type of data the function is to retrieve.

The DeviceCapabilities function retrieves data specific to printers, including the number of available paper bins, the duplex capabilities of the printer, the resolutions supported by the printer, the maximum and minimum supported paper size, and so on. An application retrieves this data by supplying strings specifying a printer device and port, as well as an index specifying the type of data that the function is to retrieve.


Saving, Restoring, and Resetting a Device Context

The Win32 API supports three functions that an application can use to save, restore, and reset a device context: SaveDC, RestoreDC, and ResetDC. The SaveDC function records on a special GDI stack the current device context's graphic objects and their attributes, and graphic modes. A drawing application can call this function before a user begins drawing and save the application's original state — providing a "clean slate" for the user. To return to this original state, the application calls the RestoreDC function.

ResetDC is provided to reset printer device context data. An application calls this function to reset the paper orientation, paper size, output scaling factor, number of copies to be printed, paper source (or bin), duplex mode, and so on. Typically, an application calls this function after a user has changed one of the printer options and Windows has issued a WM_DEVMODECHANGE message.


Using the Device Context Functions

•	Obtaining a private display device context

•	Creating a printer device context

•	Retrieving the capabilities of a printer

•	Retrieving graphic-object attributes and selecting new graphic objects


Obtaining a Private Display Device Context

An application performing numerous drawing operations in the client area of its window must use a private display device context. To create this type of device context, the application must specify the CS_OWNDC constant for the style member of the WNDCLASS structure when registering the window class. After registering the window class, the application obtains a handle identifying a private display device context by calling the GetDC function.

The following example shows how to create a private display device context.

#include <windows.h>    /* required for all Windows apps */

#include <stdio.h>

#include <string.h>     /* strtok                        */

#include "dc.h"         /* specific to this program      */

/* Function prototypes */

BOOL InitApplication(HINSTANCE);

long FAR PASCAL MainWndProc(HWND, UINT, UINT, LONG);

/* Global variables */

HINSTANCE hinst;       /* handle of current instance     */

HDC hdc;               /* display device context handle  */

    .

    .

    .

BOOL InitApplication(HINSTANCE hinstance)

{

    WNDCLASS  wc;

    /*

     * Fill in the window class structure with parameters

     * describing the main window.

     */

    wc.style = CS_OWNDC;         /* Private-DC constant */

    wc.lpfnWndProc = (WNDPROC) MainWndProc;

    wc.cbClsExtra = 0;

    wc.cbWndExtra = 0;

    wc.hInstance = hinstance;

    wc.hIcon = LoadIcon((HINSTANCE) NULL,

        MAKEINTRESOURCE(IDI_APPLICATION));

    wc.hCursor = LoadCursor((HINSTANCE) NULL,

        MAKEINTRESOURCE(IDC_ARROW));

    wc.hbrBackground = GetStockObject(WHITE_BRUSH);

    wc.lpszMenuName =  "GenericMenu";

    wc.lpszClassName = "GenericWClass";

    /* Register the window class and return the

     * resultant code.

     */

    return RegisterClass(&wc);

}

LRESULT APIENTRY MainWndProc(

        HWND hwnd,           /* window handle          */

        UINT message,        /* type of message        */

        WPARAM wParam,       /* additional information */

        LPARAM lParam)       /* additional information */

{

PAINTSTRUCT ps;              /* paint structure        */

    /* Retrieve a handle identifying the private DC.   */

    hdc = GetDC(hwnd);

    switch (message) {

        case WM_PAINT:

              BeginPaint(hwnd, &ps);

        .

        . /* Draw and paint using private DC. */

        .


Creating a Printer Device Context

An application can create a printer device context in one of two ways:

•	Calling the PrintDlg function to display a common dialog box that allows the user to specify printer options, then creating a printer device context by using those options.

•	Creating a printer device context by using the default printer data from the WIN.INI file.

This section contains code demonstrating the latter method.

To use the default printer, retrieve and parse the appropriate string from the WIN.INI file. This string is retrieved by calling the GetProfileString function and specifying the appropriate section and entry names. In the case of the default printer, this data is stored in the [windows] section and identified by the entry named device. The seventh line in the following excerpt from a WIN.INI file shows an entry for a Kodak® Diconix™ printer.

[windows]

    load=

    run=

    Beep=yes

    Spooler=yes

    NullPort=None

    device=Diconix,winspool,LPT1:

    CoolSwitch=1

    BorderWidth=3

    KeyboardSpeed=31

    InitialKeyboardIndicators=2

    CursorBlinkRate=530

    DoubleClickSpeed=686

    Programs=com exe bat pif cmd

    Documents=

    DeviceNotSelectedTimeout=15

    TransmissionRetryTimeout=45

    swapdisk=

    NetWarn=1

    fPromptOnVerbose=FALSE

    fPromptOnWarning=FALSE

    fPromptOnError=TRUE

    fPrintVerbose=FALSE

    fPrintFileLine=FALSE

    shell=

    ScreenSaveTimeOut=300

    ScreenSaveActive=0

    DebugOptions=2048

The following example shows how a printer device context was created by using the data from WIN.INI.

HDC hdcPrint;               /* printer DC handle        */

char szDevString[120];      /* array for WIN.INI data   */

char *szPrinter, *szDriver; /* printer and driver names */

char *szPort;               /* port name                */

    /*

     * Retrieve the printer, printer-driver, and

     * output-port names from WIN.INI.

     */

    GetProfileString("windows", "device", ",,,",

        szDevString, 120);

    /*

     * Parse the string of names, setting ptrs

     * as required. If the string contains the

     * required names, use them to create a

     * device context.

     */

    if ((szPrinter = strtok(szDevString,

               (const char *) ","))

            && (szDriver = strtok ((char *) NULL,

               (const char *) ", "))

            && (szPort = strtok ((char *) NULL,

               (const char *) ", ")))

        hdcPrint = CreateDC(szDriver, szPrinter,

            szPort, NULL);

    /*

     * Print a test page that contains the string

     * "PRINTER TEST" in the upper left corner.

     */

    Escape(hdcPrint, STARTDOC, 8, "Test-Doc", NULL);

    TextOut(hdcPrint, 50, 50, "PRINTER TEST", 12);

    Escape(hdcPrint, NEWFRAME, 0, NULL, NULL);

    Escape(hdcPrint, ENDDOC, 0, NULL, NULL);

    /* Delete the printer DC. */

    DeleteDC(hdcPrint);


Retrieving the Capabilities of a Printer

Not every output device supports the entire set of Win32 graphics functions. For example, because of hardware limitations, most vector plotters do not support bit-block transfers. An application can determine whether a device supports a particular Win32 graphics function by calling the GetDeviceCaps function, specifying the appropriate index, and examining the return value.

The following example shows how an application tests a printer to determine whether it supports bit-block transfers.

/*

 * Examine the raster capabilities of the device

 * identified by hdcPrint to verify that it supports

 * the BitBlt function.

 */

if ((GetDeviceCaps(hdcPrint, RASTERCAPS)

       & RC_BITBLT) == 0) {

   DeleteDC(hdcPrint);

   break;

}

else

/* Print the bitmap using the printer DC. */


Retrieving Graphic-Object Attributes and Selecting New Graphic Objects

An application can retrieve the attributes for a pen, brush, palette, font, or bitmap by calling the GetCurrentObject and GetObject functions. The GetCurrentObject function returns a handle identifying the object currently selected into the device context; the GetObject function returns a structure that describes the object's attributes.

The following example shows how an application can retrieve the current brush attributes and use the retrieved data to determine whether it is necessary to select a new brush.

HDC hdc;                     /* display DC handle       */

HBRUSH hbrushNew, hbrushOld; /* brush handles           */

HBRUSH hbrush;               /* brush handle            */

LOGBRUSH lb;                 /* logical-brush structure */

    /*

     * Retrieve a handle identifying the current brush.

     */

    hbrush = GetCurrentObject(hdc, OBJ_BRUSH);

    /*

     * Retrieve a LOGBRUSH structure that contains the

     * current brush attributes.

     */

    GetObject(hbrush, sizeof(LOGBRUSH), &lb);

    /*

     * If the current brush is not a solid-black brush,

     * replace it with the solid-black stock brush.

     */

    if ((lb.lbStyle != BS_SOLID)

           || (lb.lbColor != 0x000000)) {

        hbrushNew = GetStockObject(BLACK_BRUSH);

        hbrushOld = SelectObject(hdc, hbrushNew);

    }

    /* Perform painting operations with the white brush. */

    /*

     * After completing the last painting operation

     * with the new brush, the application should

     * select the original brush back into the

     * device context and delete the new brush.

     * In this example, hbrushNew contains a handle

     * to a stock object. It is not necessary (but it

     * is not harmful) to call DeleteObject on a stock

     * object. If hbrushNew contained a handle to a brush

     * created by a function such as CreateBrushIndirect,

     * it would be necessary to call DeleteObject.

     */

    SelectObject(hdc, hbrushOld);

    DeleteObject(hbrushNew);

Note that the application saved the original brush handle when calling the SelectObject function the first time. This handle is saved so that the original brush can be selected back into the device context after the last painting operation has been completed with the new brush. After the original brush is selected back into the device context, the new brush is deleted, freeing memory in the GDI heap.


Device Context Reference

The following functions and messages are associated with device contexts.


Device Context Functions

Following are the functions used with device contexts.

CancelDC
ChangeDisplaySettings
CreateCompatibleDC
CreateDC
CreateIC
DeleteDC
DeleteObject
DeviceCapabilities
DrawEscape
EnumDisplaySettings
EnumObjects
EnumObjectsProc
GetCurrentObject
GetDC
GetDCEx
GetDCOrgEx
GetDeviceCaps
GetGraphicsMode
GetObject
GetObjectType
GetStockObject
ReleaseDC
ResetDC
RestoreDC
SaveDC
SelectObject


Device Context Messages

Following is the message used with device contexts.

WM_DEVMODECHANGE


Enhanced Metafile Records

An enhanced metafile is an array of variable-length structures called enhanced metafile records. This overview contains definitions for enhanced metafile records.


About Enhanced Metafile Records

The first records in a metafile specify general information, such as the resolution of the device on which the picture was created, the dimensions of the picture, and so on. The remaining records, which constitute the bulk of the metafile, identify the graphics device interface (GDI) functions used to create the picture.


Enhanced Metafile Record Structure

At the beginning of every enhanced metafile record is an EMR structure, which contains two members. The first member, iType, identifies the record type — that is, the GDI function whose parameters are contained in the record. Because the structures are variable in length, the other member, nSize, contains the size of the record. Immediately following the nSize member are the remaining parameters, if any, of the GDI function.


Playing Back Enhanced Metafiles

Applications can play back enhanced metafiles using the PlayEnhMetaFile or EnumEnhMetaFile function. If using PlayEnhMetaFile to draw the picture, you pass a handle to the enhanced metafile without being concerned with the format of the enhanced metafile records. However, it is sometimes desirable to enumerate the records in the enhanced metafile to search for a particular GDI function and modify the parameters of the function in some manner. To do this, you can use EnumEnhMetaFile and provide a callback function of the type ENHMFENUMPROC to process the enhanced metafile records. To modify the parameters for an enhanced metafile record, you must know the format of the parameters within the record.


Enhanced Metafile Reference

The following structures are used with enhanced metafile records. Note that the first structure, EMR, is used as the first member of the remaining structures.

EMR
EMRANGLEARC
EMRARC, EMRARCTO, EMRCHORD, EMRPIE
EMRBITBLT
EMRCREATEBRUSHINDIRECT
EMRCREATECOLORSPACE
EMRCREATEDIBPATTERNBRUSHPT
EMRCREATEMONOBRUSH
EMRCREATEPALETTE
EMRCREATEPEN
EMRELLIPSE, EMRRECTANGLE
EMREOF
EMREXCLUDECLIPRECT, EMRINTERSECTCLIPRECT
EMREXTCREATEFONTINDIRECTW
EMREXTCREATEPEN
EMREXTFLOODFILL
EMREXTSELECTCLIPRGN
EMREXTTEXTOUTA, EMREXTTEXTOUTW
EMRFILLRGN
EMRFRAMERGN
EMRGDICOMMENT
EMRINVERTRGN, EMRPAINTRGN
EMRLINETO, EMRMOVETOEX
EMRMASKBLT
EMRMODIFYWORLDTRANSFORM
EMROFFSETCLIPRGN
EMRPLGBLT
EMRPOLYDRAW
EMRPOLYDRAW16
EMRPOLYPOLYLINE, EMRPOLYPOLYGON
EMRPOLYPOLYLINE16, EMRPOLYPOLYGON16
EMRPOLYTEXTOUTA, EMRPOLYTEXTOUTW
EMRRESIZEPALETTE
EMRRESTOREDC
EMRROUNDRECT
EMRSELECTOBJECT, EMRDELETEOBJECT
EMRSELECTPALETTE
EMRSETARCDIRECTION
EMRSETCOLORADJUSTMENT
EMRSETDIBITSTODEVICE
EMRSETMAPPERFLAGS
EMRSETBKCOLOR, EMRSETTEXTCOLOR
EMRSETMITERLIMIT
EMRSETPALETTEENTRIES
EMRSETPIXELV
EMRSETWORLDTRANSFORM
EMRSTRETCHDIBITS
EMRSTRETCHBLT
EMRTEXT
EMRFILLPATH, EMRSTROKEANDFILLPATH, EMRSTROKEPATH
EMRPOLYLINE, EMRPOLYBEZIER, EMRPOLYGON, EMRPOLYBEZIERTO, EMRPOLYLINETO
EMRPOLYLINE16, EMRPOLYBEZIER16, EMRPOLYGON16, EMRPOLYBEZIERTO16, EMRPOLYLINETO16
EMRSCALEVIEWPORTEXTEX, EMRSCALEWINDOWEXTEX
EMRSELECTCOLORSPACE, EMRDELETECOLORSPACE
EMRSETVIEWPORTORGEX, EMRSETWINDOWORGEX, EMRSETBRUSHORGEX
EMRSETVIEWPORTEXTEX, EMRSETWINDOWEXTEX


Enhanced Metafile Records with No Parameters

typedef struct tagABORTPATH

{

    EMR emr;

} EMRABORTPATH,      *PEMRABORTPATH,
  EMRBEGINPATH,      *PEMRBEGINPATH,
  EMRENDPATH,        *PEMRENDPATH,
  EMRCLOSEFIGURE,    *PEMRCLOSEFIGURE,
  EMRFLATTENPATH,    *PEMRFLATTENPATH,
  EMRWIDENPATH,      *PEMRWIDENPATH,
  EMRSETMETARGN,     *PEMRSETMETARGN,
  EMRSAVEDC,         *PEMRSAVEDC,
  EMRREALIZEPALETTE, *PEMRREALIZEPALETTE;

Contains data for the AbortPath, BeginPath, EndPath, CloseFigure, FlattenPath, WidenPath, SetMetaRgn, SaveDC, and RealizePalette enhanced metafile records.


Enhanced Metafile Records with One Parameter

typedef struct tagEMRSELECTCLIPPATH
{
    EMR   emr;

    DWORD iMode;

} EMRSELECTCLIPPATH,    *PEMRSELECTCLIPPATH,
  EMRSETBKMODE,         *PEMRSETBKMODE,
  EMRSETMAPMODE,        *PEMRSETMAPMODE,
  EMRSETPOLYFILLMODE,   *PEMRSETPOLYFILLMODE,
  EMRSETROP2,           *PEMRSETROP2,
  EMRSETSTRETCHBLTMODE, *PEMRSETSTRETCHBLTMODE,
  EMRSETTEXTALIGN,      *PEMRSETTEXTALIGN,
  EMRENABLEICM,         *PEMRENABLEICM

Contains parameters for the SelectClipPath, SetBkMode, SetPolyFillMode, SetROP2, SetStretchBltMode, SetTextAlign, and EnableICM enhanced metafile records.

Members

emr

Base structure for all record types.

iMode

Value and meaning that varies depending on the function contained in the enhanced metafile record. For a description of this member, see the documentation of the functions contained in this record .

See Also

SelectClipPath, SetBkMode, SetPolyFillMode, SetROP2, SetStretchBltMode, SetTextAlign


Filled Shapes

Filled shapes are geometric shapes that are outlined by using the current pen and filled by using the current brush. There are five filled shapes: ellipse, chord, pie, polygon, and rectangle.


About Filled Shapes

An application written for Microsoft® Windows® uses filled shapes in a variety of ways. Spreadsheet applications, for example, use filled shapes to construct charts and graphs, and drawing and painting applications use filled shapes to allow the user to draw figures and illustrations.


About Ellipses

An ellipse is a closed curve defined by two fixed points (f1 and f2) such that the sum of the distances (d1 + d2) from any point on the curve to the two fixed points is constant. The following illustration shows an ellipse drawn by using the Ellipse function.

When calling Ellipse, an application supplies the coordinates of the upper left and lower right corners of the ellipse's bounding rectangle. A bounding rectangle is the smallest rectangle completely surrounding the ellipse. When Windows draws the ellipse, it excludes the right and lower sides if no world transformations are set. Therefore, for any rectangle measuring x units wide by y units high, the associated ellipse measures x−1 units wide by y−1 units high. If the application sets a world transformation by calling the SetWorldTransform or ModifyWorldTransform function, Windows includes the right and lower sides.


About Chords

A chord is a region bounded by the intersection of an ellipse and a line segment called a secant. The following illustration shows a chord drawn by using the Chord function.

When calling Chord, an application supplies the coordinates of the upper left and lower right corners of the ellipse's bounding rectangle, as well as the coordinates of two points defining two radials. A radial is a line drawn from the center of an ellipse's bounding rectangle to a point on the ellipse.

When Windows draws the curved part of the chord, it does so by using the current arc direction for the specified device context. The default arc direction is counterclockwise. You can have your application reset the arc direction by calling the SetArcDirection function.


About Pies

A pie is a region bounded by the intersection of an ellipse curve and two radials. The following illustration shows a pie drawn by using the Pie function.

When calling Pie, an application supplies the coordinates of the upper left and lower right corners of the ellipse's bounding rectangle, as well as the coordinates of two points defining two radials.

When Windows draws the curved part of the pie, it uses the current arc direction for the given device context. The default arc direction is counterclockwise. An application can reset the arc direction by calling the SetArcDirection function.


About Polygons

A polygon is a filled shape with straight sides. The sides of a polygon are drawn by using the current pen. When Windows fills a polygon, it uses the current brush and the current polygon fill mode. The two fill modes — alternate (the default) and winding — determine whether regions within a complex polygon are filled or left unpainted. An application can select either mode by calling the SetPolyFillMode function. For more information about polygon fill modes, see Regions.

The following illustration shows a polygon drawn by using Polygon.

In addition to drawing a single polygon by using Polygon, an application can draw multiple polygons by using the PolyPolygon function.


Drawing Rectangles

A rectangle is a four-sided polygon whose opposing sides are parallel and equal in length. Although an application can draw a rectangle by calling the Polygon function, supplying the coordinates of each corner, Windows provides a simpler method, use of the Rectangle function. This function requires only the coordinates for the upper left and the lower right corners. When an application calls the Rectangle function, Windows draws the rectangle, excluding the right and lower sides if no world transformation is set for the given device context.

If a world transformation has been set by using the SetWorldTransform or ModifyWorldTransform function, Windows includes the right and lower edges.

In addition to drawing a normal rectangle, the Microsoft® Win32® application programming interface (API) provides a function that applications can use to draw rectangles with rounded corners. This function, RoundRect, requires that the application supply the coordinates of the lower left and upper right corners, as well as the width and height of the ellipse used to round each corner.

The Win32 API also provides three functions that applications can use to manipulate rectangles, described as follows.

Function	Description
FillRect	Repaints the interior of a rectangle.
FrameRect	Redraws the sides of a rectangle.
InvertRect	Inverts the colors that appear within the interior of a rectangle.


Using Filled Shapes

This section illustrates how to use filled shape functions. The example uses the main window procedure from an application that enables the user to draw ellipses, rectangles, and rectangles with rounded corners.

The user draws a filled shape by selecting a particular shape from the menu, positioning the cursor at the upper left corner of the shape (or the shape's bounding rectangle in the case of an ellipse), and then dragging the mouse until the desired dimensions are obtained.

The following illustration shows three filled shapes drawn using the sample code in this section.

To enable the user to draw filled shapes, include the following code in your application.

LRESULT APIENTRY MainWndProc(hwnd, uMsg, wParam, lParam)

HWND hwnd;      /* handle of window         */

UINT uMsg;      /* message                  */

WPARAM wParam;  /* first message parameter  */

LPARAM lParam;  /* second message parameter */

{

    HDC hdc;         /* handle of device context (DC)   */

    PAINTSTRUCT ps;  /* paint data for Begin/EndPaint   */

    POINT ptClientUL; /* client area upper left corner  */

    POINT ptClientLR; /* client area lower right corner */

    static HDC hdcCompat;/* handle of DC for bitmap     */

    static POINT pt;     /* x- and y-coordinates of cursor    */

    static RECT rcTarget; /* rect to receive filled shape     */

    static RECT rcClient; /* client area rectangle            */

    static BOOL fSizeEllipse; /* TRUE if ellipse is sized     */

    static BOOL fDrawEllipse;   /* TRUE if ellipse is drawn   */

    static BOOL fDrawRectangle; /* TRUE if rectangle is drawn */

    static BOOL fSizeRectangle; /* TRUE if rectangle is sized */

    static BOOL fSizeRoundRect; /* TRUE if rounded rect is sized */

    static BOOL fDrawRoundRect; /* TRUE if rounded rect is drawn */

    static int nEllipseWidth;   /* width for round corners       */

    static int nEllipseHeight;  /* height for round corners      */

    switch (uMsg) {

        case WM_COMMAND:

            switch (wParam) {

                /*

                 * Set the appropriate flag to indicate which

                 * filled shape the user is drawing.

                 */

                case IDM_ELLIPSE:

                    fSizeEllipse = TRUE;

                break;

                case IDM_RECTANGLE:

                    fSizeRectangle = TRUE;

                break;

                case IDM_ROUNDRECT:

                    fSizeRoundRect = TRUE;

                break;

                default:

                    return DefWindowProc(hwnd, uMsg, wParam,

                         lParam);

            }

            break;

        case WM_CREATE:

            nEllipseWidth = 20;

            nEllipseHeight = 20;

            return 0;

        case WM_PAINT:

            BeginPaint(hwnd, &ps);

            /*

             * Because the default brush is white, select

             * a different brush into the device context

             * to demonstrate the painting of filled shapes.

             */

            SelectObject(ps.hdc, GetStockObject(GRAY_BRUSH));

            /*

             * If one of the filled shape "draw" flags is TRUE,

             * draw the corresponding shape.

             */

            if (fDrawEllipse) { /* draws ellipse */

                Ellipse(ps.hdc, rcTarget.left, rcTarget.top,

                    rcTarget.right, rcTarget.bottom);

                    fDrawEllipse = FALSE;

                    rcTarget.left = rcTarget.right = 0;

                    rcTarget.top = rcTarget.bottom = 0;

                    }

            if (fDrawRectangle) { /* Draws rectangle */

                Rectangle(ps.hdc, rcTarget.left, rcTarget.top,

                    rcTarget.right, rcTarget.bottom);

                    fDrawRectangle = FALSE;

                    rcTarget.left = rcTarget.right = 0;

                    rcTarget.top = rcTarget.bottom = 0;

                    }

            if (fDrawRoundRect) { /* Draws rounded rectangle */

                RoundRect(ps.hdc, rcTarget.left, rcTarget.top,

                    rcTarget.right, rcTarget.bottom,

                    nEllipseWidth, nEllipseHeight);

                    fDrawRectangle = FALSE;

                    rcTarget.left = rcTarget.right = 0;

                    rcTarget.top = rcTarget.bottom = 0;

                    }

            EndPaint(hwnd, &ps);

            break;

        case WM_SIZE:

            /*

             * Convert the client coordinates of the client area

             * rectangle to screen coordinates and save them in a

             * rectangle. The rectangle is passed to the ClipCursor

             * function during WM_LBUTTONDOWN processing.

             */

            GetClientRect(hwnd, &rcClient);

            ptClientUL.x = rcClient.left;

            ptClientUL.y = rcClient.top;

            ptClientLR.x = rcClient.right;

            ptClientLR.y = rcClient.bottom;

            ClientToScreen(hwnd, &ptClientUL);

            ClientToScreen(hwnd, &ptClientLR);

            SetRect(&rcClient, ptClientUL.x, ptClientUL.y,

                ptClientLR.x, ptClientLR.y);

            return 0;

        case WM_LBUTTONDOWN:

            /*

             * Restrict the cursor to the client area.

             * This ensures that the window receives a matching

             * WM_LBUTTONUP message.

             */

            ClipCursor(&rcClient);

            /* Save the coordinates of the cursor. */

            pt.x = (LONG) LOWORD(lParam);

            pt.y = (LONG) HIWORD(lParam);

            /*

             * If the user chooses one of the filled shapes,

             * set the appropriate flag to indicate that the

             * shape is being sized.

             */

             if (fDrawEllipse)

                fSizeEllipse = TRUE;

            return 0;

        case WM_MOUSEMOVE:

            /*

             * If one of the "size" flags is set, draw

             * the target rectangle as the user drags

             * the mouse.

             */

            if ((wParam && MK_LBUTTON)

                    && (fSizeEllipse || fSizeRectangle

                    || fSizeRoundRect)) {  /* draws target rect. */

                /*

                 * Set the mixing mode so that the pen color is the

                 * inverse of the background color. The previous

                 * rectangle can then be erased by drawing

                 * another rectangle on top of it.

                 */

                hdc = GetDC(hwnd);

                SetROP2(hdc, R2_NOTXORPEN);

                /*

                 * If a previous target rectangle exists, erase

                 * it by drawing another rectangle on top.

                 */

                 if (!IsRectEmpty(&rcTarget))

                     Rectangle(hdc, rcTarget.left, rcTarget.top,

                         rcTarget.right, rcTarget.bottom);

                /*

                 * Save the coordinates of the target rectangle.

                 * Avoid invalid rectangles by ensuring that the

                 * value of the left coordinate is greater than

                 * that of the right, and that the value of the

                 * bottom coordinate is greater than that of

                 * the top.

                 */

                if ((pt.x < (LONG) LOWORD(lParam)) &&

                        (pt.y > (LONG) HIWORD(lParam)))

                    SetRect(&rcTarget, pt.x, HIWORD(lParam),

                        LOWORD(lParam), pt.y);

                else if ((pt.x > (LONG) LOWORD(lParam)) &&

                        (pt.y > (LONG) HIWORD(lParam)))

                    SetRect(&rcTarget, LOWORD(lParam),

                        HIWORD(lParam), pt.x, pt.y);

                else if ((pt.x > (LONG) LOWORD(lParam)) &&

                        (pt.y < (LONG) HIWORD(lParam)))

                    SetRect(&rcTarget, LOWORD(lParam), pt.y,

                        pt.x, HIWORD(lParam));

                else

                    SetRect(&rcTarget, pt.x, pt.y, LOWORD(lParam),

                        HIWORD(lParam));

                /* Draw the new target rectangle. */

                Rectangle(hdc, rcTarget.left, rcTarget.top,

                    rcTarget.right, rcTarget.bottom);

                ReleaseDC(hwnd, hdc);

            }

            return 0;

        case WM_LBUTTONUP:

            /*

             * If one of the "size" flags is TRUE, reset

             * it to FALSE, and then set the corresponding

             * "draw" flag.

             * Invalidate the appropriate rectangle and issue

             * a WM_PAINT message.

             */

             if (fSizeEllipse) {

                 fSizeEllipse = FALSE;

                 fDrawEllipse = TRUE;

                }

             if (fSizeRectangle) {

                 fSizeRectangle = FALSE;

                 fDrawRectangle = TRUE;

                }

             if (fSizeRoundRect) {

                 fSizeRoundRect = FALSE;

                 fDrawRoundRect = TRUE;

                }

             if (fDrawEllipse || fDrawRectangle || fDrawRoundRect)

               {

                 InvalidateRect(hwnd, &rcTarget, TRUE);

                 UpdateWindow(hwnd);

                }

            /* Release the cursor. */

            ClipCursor((LPRECT) NULL);

            return 0;

        case WM_DESTROY:

            /*

             * Destroy the background brush, compatible bitmap,

             * and bitmap.

             */

            DeleteDC(hdcCompat);

            PostQuitMessage(0);

            break;

        default:

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

    }

    return (LRESULT) NULL;

}


Filled Shape Functions

The following functions are used with filled shapes.

Chord
Ellipse
FillRect
FrameRect
InvertRect
Pie
Polygon
PolyPolygon
Rectangle
RoundRect


Fonts and Text

Fonts are used to draw text on video displays and other output devices. The Microsoft® Windows® operating system provides a set of functions that developers can use to install, select, and query different fonts.


About Fonts

To a person trained in the mechanics of manuscript composition or familiar with standard typography, some of the typographic terms used in Windows may be unusual. Most of the differences between standard typography and Windows reflect changes in technology. The original typographic terms were based on hot-metal composition, whereas the terms used in Windows, which appear as member names for the font and text output structures, reflect a new technology based on laser-printer output and composition performed on a personal computer using desktop publishing software.


Fonts Overview

In Windows, a font is a collection of characters and symbols that share a common design. The three major elements of this design are referred to as typeface, style, and size.

Typeface

The term typeface refers to specific characteristics of characters and symbols in the font, such as the width of the thick and thin strokes that compose the characters and the presence or absence of serifs. A serif is the short cross line at the ends of an unconnected stroke. A font or typeface without serifs is usually called a sans-serif font.

Style

The term style refers to the weight and slant of a font. Font weights can range from thin to black. The following list identifies possible weights for Windows fonts (beginning with the lightest and ending with the heaviest).

Thin
Extralight
Light
Normal
Medium
Semibold
Bold
Extrabold
Heavy

Three terms categorize the slant of a Windows font: roman, oblique, and italic.

The characters in a roman font are upright. The characters in an oblique font are artificially slanted. The slant is achieved by performing a shear transformation on the characters from a roman font. The characters in an italic font are truly slanted and appear as they were designed. For more information on shearing, see Coordinate Spaces and Transformations.

Size

In Windows, the size of a font is an imprecise value. It can generally be determined by measuring the distance from the bottom of a lowercase "g" to the top of an adjacent uppercase "M," as shown in the following illustration.

A font's size is specified in units called points. A point is .013837 of an inch. Following the point system devised by Pierre Simon Fournier, it is common practice to approximate a point as 1/72 inch.


Font Families

Windows organizes fonts by family; a family is a set of fonts having common stroke width and serif characteristics. Windows categorizes families with five family names. A sixth name ("Dontcare") allows an application to use the default font. The following table describes the font-family names.

Font-family name	Description
Decorative	Specifies a novelty font. An example is Old English.
Dontcare	Specifies a generic family name. This name is used when information about a font does not exist or does not matter.
Modern	Specifies a monospace font with or without serifs. Monospace fonts are usually modern; examples include Pica, Elite, and Courier New®.
Roman	Specifies a proportional font with serifs. An example is Times New Roman.
Script	Specifies a font that is designed to look like handwriting; examples include Script and Cursive.
Swiss	Specifies a proportional font without serifs. An example is Arial.
These family names correspond to constants found in the WINGDI.H file: FF_DECORATIVE, FF_DONTCARE, FF_MODERN, FF_ROMAN, FF_SCRIPT, and FF_SWISS. An application uses these constants when it creates a font, selects a font, or retrieves information about a font.

Fonts within a family are distinguished by size (10 point, 24 point, etc.) and style (regular, italic, etc.).


Raster, Vector, and TrueType® Fonts

Windows-based applications can use three different kinds of font technologies to display and print text: raster, vector, and TrueType. The differences between these fonts reflect the way that the glyph for each character or symbol is stored in the respective font-resource file. In raster fonts, a glyph is a bitmap that Windows uses to draw a single character or symbol in the font. In vector fonts, a glyph is a collection of line endpoints that define the line segments Windows uses to draw a character or symbol in the font. In TrueType fonts, a glyph is a collection of line and curve commands as well as a collection of hints. Windows uses the line and curve commands to define the outline of the bitmap for a character or symbol in the TrueType font. Windows uses the hints to adjust the length of the lines and shapes of the curves used to draw the character or symbol. These hints and the respective adjustments are based on the amount of scaling used to reduce or increase the size of the bitmap.

Because the bitmaps for each glyph in a raster font are designed for a specific resolution of device, raster fonts are generally considered to be device dependent. Vector fonts, on the other hand, are not device dependent, because each glyph is stored as a collection of scalable lines. However, vector fonts are generally drawn more slowly than raster or TrueType fonts. TrueType fonts provide both relatively fast drawing speed and true device independence. By using the hints associated with a glyph, a developer can scale the characters from a TrueType font up or down and still maintain their original shape.

As previously mentioned, the glyphs for a font are stored in a font-resource file. A font-resource file is actually a Windows library that contains only data — there is no code. For raster and vector fonts, this data is divided into two parts: a header describing the font's metrics and the glyph data. A font-resource file for a raster or vector font is identified by the .FON filename extension. For TrueType fonts, there are two files for each font: the first file contains a relatively short header and the second contains the actual font data. The first file is identified by a .FOT extension and the second is identified by a .TTF extension.


Character Sets Used by Fonts

All fonts use a character set. A character set contains punctuation marks, numerals, uppercase and lowercase letters, and all other printable characters. Each element of a character set is identified by a number.

Most character sets used in Windows are supersets of the U.S. ASCII character set, which defines characters for the 96 numeric values from 32 through 127. There are five major groups of character sets:

•	Windows

•	Unicode™

•	OEM (original equipment manufacturer)

•	Symbol

•	Vendor-specific

Windows Character Set

The Windows character set is the most commonly used character set in Windows programming. It is essentially equivalent to the ANSI character set. The blank character is the first character in the Windows character set. It has a hexadecimal value of 0x20 (decimal 32). The last character in the Windows character set has a hexadecimal value of 0xFF (decimal 255).

Many fonts specify a default character. Whenever a request is made for a character that is not in the font, Windows provides this default character. Many fonts using the Windows character set specify the period (.) as the default character. TrueType fonts typically use an open box as the default character.

Fonts use a break character called a quad to separate words and justify text. Most fonts using the Windows character set specify that the blank character will serve as the break character.

Windows version 3.1 added 24 characters to the Windows code page, as shown in the following table.

Character	Name	Windows character code
‚	base line single quote	130
ƒ	florin	131
„	base line double quote	132
…	ellipsis	133
†	dagger	134
‡	double dagger	135
ˆ	circumflex	136
‰	permille	137
Š	S Hacek	138
‹	left single guillemet	139
Œ	OE ligature	140
'	left single quote	145
'	right single quote	146
"	left double quote	147
"	right double quote	148
•	bullet	149
−	en dash	150
—	em dash	151
˜	tilde	152
™	trademark ligature	153
š	s Hacek	154
›	right single guillemet	155
œ	oe ligature	156
Ÿ	Y Dieresis	159
It should be noted that the characters for left and right single quote were first added to the character set for the release of Windows version 3.0.

Unicode™ Character Set

The Windows ANSI character uses 8 bits to represent each character; therefore, the maximum number of characters that can be expressed using 8 bits is 256 (2^8). This is usually sufficient for Western languages, including the diacritical marks used in French, German, Spanish, and other languages. However, Eastern languages employ thousands of separate characters, which cannot be encoded by using a single-byte coding scheme. With the proliferation of computer commerce, double-byte coding schemes were developed so that characters could be represented in 8-bit, 16-bit, 24-bit, or 32-bit sequences. This requires complicated passing algorithms; even so, using different code sets could yield entirely different results on two different computers.

To address the problem of multiple coding schemes, the Unicode standard for data representation was developed. A 16-bit character coding scheme, Unicode can represent 65,536 (2^16) characters, which is enough to include all languages in computer commerce today, as well as punctuation marks, mathematical symbols, and room for future expansion. Unicode establishes a unique code for every character to ensure that character translation is always accurate.

OEM Character Set

The OEM character set is typically used in full-screen MS-DOS® sessions for screen display. Characters 32 through 127 are usually the same in the OEM, U.S. ASCII, and Windows character sets. The other characters in the OEM character set (0 through 31 and 128 through 255) correspond to the characters that can be displayed in a full-screen MS-DOS session. These characters are generally different from the Windows characters.

Symbol Character Set

The Symbol character set contains special characters typically used to represent mathematical and scientific formulas.

Vendor-Specific Character Sets

Many printers and other output devices provide fonts based on character sets that differ from the Windows and OEM sets — for example, the Extended Binary Coded Decimal Interchange Code (EBCDIC) character set. To use one of these character sets, the printer driver translates from the Windows character set to the vendor-specific character set.


Font Installation and Deletion

A font must already be resident on a given device or installed in the Windows font table in order for an application to draw text using glyphs from that font. The Windows font table is an internal array that identifies all nondevice fonts that are available to a Windows-based application. An application can retrieve the names of fonts currently installed on a device and stored in the internal font table by calling the EnumFontFamilies or ChooseFont function.

An application can install a font by calling the font-installation function AddFontResource. The AddFontResource function loads a font that is stored in a font-resource file.

In the case of TrueType fonts, an additional step is sometimes necessary before the font can be installed in the font table. Some font manufacturers ship only the TrueType font-data files (identified by the .TTF extension). Before Windows can load these fonts, it requires a corresponding header file (identified by the .FOT extension). To create this header file, an application must call the CreateScalableFontResource function and pass the name of the font-data file as the third parameter. When this header file is created, an application can install the font by calling the AddFontResource function and passing the name of the new header file.

When an application finishes using an installed font, it must remove that font by calling the RemoveFontResource function.

Whenever an application calls the functions that add and delete font resources, it should also call the SendMessage function and send a WM_FONTCHANGE message to all top-level windows in the system. This message notifies other applications that the internal font table has been altered by an application that added or removed a font.


Font Creation and Selection

Previous versions of Windows required that the application developer provide source code and a dialog box template to support an interface that displayed the available fonts from which the user could choose. The new Font common dialog box simplifies the creation and selection process. By initializing the CHOOSEFONT structure and calling the ChooseFont function, an application can support the same font-selection interface that previously required many lines of code. (For more information about the Font common dialog box, see Common Dialog Box Library.)

Selection by the User

Most font creation and selection operations involve the user. For example, word processing applications let the user select unique fonts for headings, footnotes, and body text. After the user selects a font by using the Font dialog box and presses the OK button, the ChooseFont function initializes the members of a LOGFONT structure with the attributes of the requested font. To use this font for text-output operations, an application must first create a logical font and then select that font into its device context. A logical font is an application-supplied description of an ideal font. A developer can create a logical font by calling the CreateFont or the CreateFontIndirect functions. In this case, the application would call CreateFontIndirect and supply a pointer to the LOGFONT structure initialized by ChooseFont. In general, it is more efficient to call CreateFontIndirect because CreateFont requires several parameters while CreateFontIndirect requires only one — a pointer to LOGFONT.

Before an application can actually begin drawing text with a logical font, it must find the closest match from the fonts stored internally on the device and the fonts whose resources have been loaded into the operating system. The fonts stored on the device or in the operating system are called physical fonts. The process of finding the physical font that most closely matches a specified logical font is called font mapping. This process occurs when an application calls the SelectObject function and supplies a handle identifying a logical font. Font mapping is performed by using an internal algorithm that compares the attributes of the requested logical font against the attributes of available physical fonts. When the font mapper algorithm completes its search and determines the closest possible match, the SelectObject function returns and the application can begin drawing text with the new font.

The SetMapperFlags function specifies whether or not the font mapper algorithm searches only for physical fonts with aspect ratios that match the physical device. The aspect ratio for a device is the ratio formed by the width and the height of a pixel on that device.


Special Font Selection Considerations

Although most font selection operations involve the user, there are some instances where this is not true. For example, a developer may want to use a unique font in an application to draw text in a control window. To select an appropriate font, the application must be able to determine what fonts are available, create a logical font that describes one of these available fonts, and then select that font into the appropriate device context.

An application can enumerate the available fonts by using the EnumFontFamilies function. This can be useful when an application must determine which fonts are available from a given family.

Once an application has enumerated the available fonts and located an appropriate match, it should use the values returned by the font enumeration function to initialize the members of a LOGFONT structure. Then it can call the CreateFontIndirect function, passing to it a pointer to the initialized LOGFONT structure. If the CreateFontIndirect function is successful, the application can then select the logical font by calling the SelectObject function.

When initializing the members of the LOGFONT structure, be sure to specify a specific character set in the lfCharSet member. This member is important in the font mapping process and the results will be inconsistent if this member is not initialized correctly. If you specify a typeface name in the lfFaceName member of the LOGFONT structure, make sure that the lfCharSet value matches the character set of the typeface specified in lfFaceName. For example, if you want to select a font such as "MS Mincho", lfCharSet must be set to the predefined value SHIFTJIS_CHARSET.


Embedded Fonts

Embedding a font is the technique of bundling a document and the fonts it contains into a file for transmission to another computer. Embedding a font guarantees that a font specified in a transmitted file will be present on the computer receiving the file. Not all fonts can be moved from computer to computer, however, since most fonts are licensed to only one computer at a time. In Windows, only TrueType fonts can be embedded.

Applications should embed a font in a document only when requested by a user. An application cannot be distributed along with documents that contain embedded fonts, nor can an application itself contain an embedded font. Whenever an application distributes a font, in any format, the proprietary rights of the owner of the font must be acknowledged.

It may be a violation of a font vendor's proprietary rights or user license agreement to embed any fonts where embedding is not permitted or to fail to observe the following guidelines on embedding fonts. A font's license may give only read-write permission for a font to be installed and used on the destination computer. Or the license may give read-only permission. Read-only permission allows a document to be viewed and printed (but not modified) by the destination computer; documents with read-only embedded fonts are themselves read-only. Read-only embedded fonts may not be unbundled from the document and installed on the destination computer.

An application can determine the license status by calling the GetOutlineTextMetrics function and examining the otmfsType member of the OUTLINETEXTMETRIC structure. If bit 1 of otmfsType is set, embedding is not permitted for the font. If bit 1 is clear, the font can be embedded. If bit 2 is set, the embedding is read-only.

To embed a font, an application can use the GetFontData function to read the font file. Setting the dwTable and dwOffset parameters of GetFontData to 0L and the cbData parameter to −1L ensures that the application reads the entire font file from the beginning.

After an application retrieves the font data, it can store the data with the document by using any applicable format. Most applications build a font directory in the document, listing the embedded fonts and whether the embedding is read-write or read-only. An application can use the otmpStyleName and otmFamilyName members of the OUTLINETEXTMETRIC structure to identify the font.

If the read-only bit is set for the embedded font, applications must encrypt the font data before storing it with the document. The encryption method need not be complicated; for example, using the XOR operator to combine the font data with an application-defined constant is adequate and fast.


About Text Output

Text output is the most common type of graphic output found within the client area of Windows-based applications. It is used by Windows-based applications in different ways. Word processing and desktop publishing applications create documents with formatted text; spreadsheet applications use text, numbers, and symbols to specify formulas, label columns, and list values; database applications create records and display queries with text, and CAD applications use text to label objects and display dimensions.

The Win32® application programming interface (API) provides a complete set of functions to format and draw text in an application's client area and on a page of printer paper. These functions can be divided into two categories: those that format the text (or prepare it for output) and those that actually draw the text. The formatting functions align text, set the intercharacter spacing, set the text and text-background colors, and justify text. The drawing functions draw individual characters (or symbols) or entire strings of text.


Formatting Text

The formatting functions can be divided into three categories: those that retrieve or set the text-formatting attributes for a device context, those that retrieve character widths, and those that retrieve string widths and heights.


Text-Formatting Attributes

An application can use six functions to set the text-formatting attributes for a device context: SetBkColor, SetBkMode, SetTextAlign, SetTextCharacterExtra, SetTextColor, and SetTextJustification. These functions affect the text alignment, the intercharacter spacing, the text justification, and text and background colors. In addition, six other functions can be used to retrieve the current text formatting attributes for any device context: GetBkColor, GetBkMode, GetTextAlign, GetTextCharacterExtra, GetTextColor, and GetTextExtentPoint32.

Text Alignment

Applications can use the SetTextAlign function to specify how Windows should position the characters in a string of text when they call one of the drawing functions. This function can be used to position headings, page numbers, callouts, and so on. Windows positions a string of text by aligning a reference point on an imaginary rectangle that surrounds the string, with the current cursor position or with a point passed as an argument to one of the text drawing functions. The SetTextAlign function lets the application specify the location of this reference point. The list below identifies the possible reference point locations.

Location	Description
left/bottom	The reference point is located at the bottom left corner of the rectangle.
left/base line	The reference point is located at the intersection of the character-cell base line and the left edge of the rectangle.
left/top	The reference point is located at the top left corner of the rectangle.
center/bottom	The reference point is located at the center of the bottom of the rectangle.
center/base line	The reference point is located at the intersection of the character-cell base line and the center of the rectangle.
center/top	The reference point is located at the center of the top of the rectangle.
right/bottom	The reference point is located at the bottom right corner of the rectangle.
right/base line	The reference point is located at the intersection of the character-cell base line and the right edge of the rectangle.
right/top	The reference point is located at the top right corner of the rectangle.
The following illustration shows a string of text drawn by calling the TextOut function. Before drawing the text, the SetTextAlign function was called to relocate the reference point at each one of the nine possible locations.

The default text alignment for a device context is the upper left corner of the imaginary rectangle that surrounds the text. An application can retrieve the current text-alignment setting for any device context by calling the GetTextAlign function.

Intercharacter Spacing

Applications can use the SetTextCharacterExtra function to alter the intercharacter spacing for all text output operations in a given device context. The following illustration shows a string of text drawn twice by calling the TextOut function. Before drawing the text the second time, the SetTextCharacterExtra function was called to increment the intercharacter spacing.

The default intercharacter spacing value for any device context is zero. An application can retrieve the current intercharacter spacing value for a device context by calling the GetTextCharacterExtra function.

Text Justification

Applications can use the GetTextExtentPoint32 and SetTextJustification functions to justify a line of text. Text justification is a common operation in any desktop publishing and in most word processing applications. The GetTextExtentPoint32 function computes the width and height of a string of text. After the width is computed, the application can call the SetTextJustification function to distribute extra spacing between each of the words in a line of text. The following illustration shows a paragraph of text printed twice: in the first paragraph, the text was not justified; in the second paragraph, the text was justified by calling the GetTextExtentPoint32 and SetTextJustification functions.

Text and Background Color

Applications can use the SetTextColor function to set the color of text drawn in the client-area of their windows, as well as the color of text drawn on a color printer. An application can use the SetBkColor function to set the color that appears behind each character and the SetBkMode function to specify how Windows should blend the selected background color with the current color or colors on the video display.

The default text color for a display device context is black; the default background color is white; and the default background mode is OPAQUE. An application can retrieve the current text color for a device context by calling the GetTextColor function. An application can retrieve the current background color for a device context by calling the GetBkColor function and the current background mode by calling the GetBkMode function.


Character Widths

Applications need to retrieve character-width data when they perform such tasks as fitting strings of text to page or column widths. There are four functions that an application can use to retrieve character-width data. Two of these functions retrieve the character-advance width and two of these functions retrieve actual character-width data.

An application can use the GetCharWidth32 and GetCharWidthFloat functions to retrieve the advance width for individual characters or symbols in a string of text. The advance width is the distance that the cursor on a video display or the print-head on a printer must advance before printing the next character in a string of text. The GetCharWidth32 function returns the advance width as an integer value. If greater precision is required, an application can use the GetCharWidthFloat function to retrieve fractional advance-width values.

An application can retrieve actual character-width data by using the GetCharABCWidths and GetCharABCWidthsFloat functions. To retrieve character widths for characters in a string of text that will be printed using a TrueType font, an application can call the GetCharABCWidths function; however, for any other font, the application should call the GetCharABCWidthsFloat function. (For more information about TrueType fonts, see Raster, Vector, and TrueType® Fonts). The following illustration shows the three components of the ABC width:

The "A" spacing is the width to add to the current position before placing the character. The "B" spacing is the width of the character itself. The "C" spacing is the white space to the right of the character. The total advance width is determined by calculating the sum of A+B+C. The character cell is an imaginary rectangle that surrounds each character or symbol in a Windows font. Because characters can overhang or underhang the character cell, either or both of the A and C increments can be a negative number.


String Widths and Heights

In addition to retrieving character-width data for individual characters, applications also need to compute the width and height of entire strings. Two functions retrieve string-width and height measurements: GetTextExtentPoint32, and GetTabbedTextExtent. If the string does not contain tab characters, an application can use the GetTextExtentPoint32 function to retrieve the width and height of a specified string. If the string contains tab characters, an application should call the GetTabbedTextExtent function.

Windows also supports a special function, called GetTextExtentExPoint, that applications can use for word-wrapping operations. This function returns the number of characters from a specified string that fit within a given space.

Font Ascenders and Descenders

Some applications determine the line spacing between text lines of different sizes by using a font's maximum ascender and descender. An application can retrieve these values by calling the GetTextMetrics function and then checking the tmAscent and tmDescent members of the TEXTMETRIC.

The maximum ascent and descent are different from the typographic ascent and descent. In TrueType fonts, the typographic ascent and descent are typically the top of the "f" glyph and bottom of the "g" glyph. An application can retrieve the typographic ascender and descender for a TrueType font by calling the GetOutlineTextMetrics function and checking the values in the otmMacAscent and otmMacDescent members of the OUTLINETEXTMETRIC structure. It is important to note that TrueType font metrics do not correspond exactly to the metrics for Windows raster fonts, because TrueType font metrics have been designed by Apple Computer, Inc. for consistency across a variety of display and output devices.

The following figure shows the difference between the vertical text metric values returned in the NEWTEXTMETRIC and OUTLINETEXTMETRIC structures. (The names beginning with otm are members of the OUTLINETEXTMETRIC structure.)

Font Dimensions

An application can retrieve the physical dimensions of a TrueType font by calling the GetOutlineTextMetrics function. An application can retrieve the physical dimensions of any other font by calling the GetTextMetrics function. To determine the dimensions of an output device, an application can call the GetDeviceCaps function. GetDeviceCaps returns both physical and logical dimensions.

A logical inch is a measure Windows uses to present legible fonts on the screen and is approximately 30 to 40 percent larger than a physical inch. The use of logical inches precludes an exact match between the output of the screen and printer. Developers should be aware that the text on a screen is not simply a scaled version of the text that will appear on the page, particularly if graphics are incorporated into the text.


Drawing Text

After an application selects the appropriate font, sets the required text-formatting options, and computes the necessary character width and height values for a string of text, it can begin drawing characters and symbols by calling any of the four text-output functions. Two of these functions, DrawText and TabbedTextOut, are part of Window Manager and found in the library USER.DLL; the remaining two functions are part of GDI and found in the library GDI.DLL. When an application calls one of these functions, the operating system passes the call to the graphics engine, which in turn passes the call to the appropriate device driver. At the device driver level, all of these calls are supported by one or more calls to the driver's own ExtTextOut or TextOut function. An application will achieve the fastest execution by calling the ExtTextOut function, which is quickly converted into an ExtTextOut call for the device. However, there are instances when an application should call one of the other three functions; for example, to draw multiple lines of text within the borders of a specified rectangular region, it is more efficient to call the DrawText function. To create a multicolumn table with justified columns of text, it is more efficient to call the TabbedTextOut function.


Using the Font and Text-Output Functions

This section describes how you can use the font and text-output functions to draw normal text, draw text from different fonts on the same line, rotate lines of text, display the font-selection common dialog-box, enumerate fonts, and so on.

•	Using a stock font to draw text

•	Creating a logical font

•	Enumerating the installed fonts

•	Checking the text capabilities of a device

•	Setting the text alignment

•	Drawing text from different fonts on the same line

•	Rotating lines of text

•	Retrieving character outlines

•	Using portable truetype metrics

•	Using PANOSE numbers

•	Creating customized fonts


Using a Stock Font to Draw Text

Windows provides six stock fonts. A stock font is a logical font that an application can obtain by calling the GetStockObject function and passing a value that identifies the requested font. The following list contains the six values that you can specify to obtain a stock font.

Value	Meaning
ANSI_FIXED_FONT	Specifies a monospace font based on the Windows character set. A Courier font is typically used.
ANSI_VAR_FONT	Specifies a proportional font based on the Windows character set. MS Sans Serif is typically used.
DEVICE_DEFAULT_FONT	Specifies the preferred font for the given device. This is typically the System font for display devices; however, for some dot-matrix printers this is a font that is resident on the device. (Printing with this font is usually faster than printing with a downloaded, bitmapped font).
OEM_FIXED_FONT	Specifies a monospace font based on an OEM character set. For IBM® computers and compatibles, the OEM font is based on the IBM PC character set.
SYSTEM_FONT	Specifies the System font. This is a proportional font based on the Windows character set, and is used by the operating system to display window titles, menu names, and text in dialog boxes. The System font is always available. Other fonts are available only if they have been installed.
SYSTEM_FIXED_FONT	Specifies a monospace font compatible with the System font in Windows versions earlier than 3.0.
The following example retrieves a handle of the Windows variable stock font, selects it into a device context, and then writes a string using that font:

HFONT hfnt, hOldFont;

    hfnt = GetStockObject(ANSI_VAR_FONT);

    if (hOldFont = SelectObject(hdc, hfnt)) {

        TextOut(hdc, 10, 50, "Sample ANSI_VAR_FONT text.", 26);

        SelectObject(hdc, hOldFont);

    }

If other stock fonts are not available, GetStockObject returns a handle to the System font (SYSTEM_FONT). You should use stock fonts only if the mapping mode for your application's device context is MM_TEXT.


Creating a Logical Font

You can use the Font common dialog box to display available fonts. The ChooseFont dialog box is displayed after an application initializes the members of a CHOOSEFONT structure and calls the ChooseFont function. After the user chooses one of the available fonts and presses the OK button, the ChooseFont function initializes a LOGFONT structure with the relevant data. Your application can then call the CreateFontIndirect function and create a logical font based on the user's request. The following example demonstrates how this is done.

HFONT FAR PASCAL MyCreateFont( void )

{

CHOOSEFONT cf;

LOGFONT lf;

HFONT hfont;

    /* Initialize members of the CHOOSEFONT structure. */

    cf.lStructSize = sizeof(CHOOSEFONT);

    cf.hwndOwner = (HWND)NULL;

    cf.hDC = (HDC)NULL;

    cf.lpLogFont = &lf;

    cf.iPointSize = 0;

    cf.Flags = CF_SCREENFONTS;

    cf.rgbColors = RGB(0,0,0);

    cf.lCustData = 0L;

    cf.lpfnHook = (LPCFHOOKPROC)NULL;

    cf.lpTemplateName = (LPSTR)NULL;

    cf.hInstance = (HINSTANCE) NULL;

    cf.lpszStyle = (LPSTR)NULL;

    cf.nFontType = SCREEN_FONTTYPE;

    cf.nSizeMin = 0;

    cf.nSizeMax = 0;

    /* Display the CHOOSEFONT common-dialog box. */

    ChooseFont(&cf);

    /* Create a logical font based on the user's   */

    /* selection and return a handle identifying   */

    /* that font.                                  */

    hfont = CreateFontIndirect(cf.lpLogFont);

    return (hfont);

}


Enumerating the Installed Fonts

In some instances, an application must be able to enumerate the available fonts and select the one most appropriate for a particular operation. An application can enumerate the available fonts by calling the EnumFonts or EnumFontFamilies function. These functions send information about the available fonts to a callback function that the application supplies. The callback function receives information in LOGFONT and NEWTEXTMETRIC structures. (The NEWTEXTMETRIC structure contains information about a TrueType font. When the callback function receives information about a non-TrueType font, the information is contained in a TEXTMETRIC structure.) By using this information, an application can limit the user's choices to only those fonts that are available.

The EnumFontFamilies function is similar to the EnumFonts function but includes some extra functionality. EnumFontFamilies allows an application to take advantage of styles available with TrueType fonts. New and upgraded applications should use EnumFontFamilies instead of EnumFonts.

In previous versions of Windows, the only style attributes were weight and italic; any other styles were specified in the family name for the font. For example, when an application used the EnumFonts function to query the available Courier fonts, EnumFonts might return information for Courier, Courier Bold, Courier Bold Italic, and Courier Italic. It would not return information about any other Courier fonts that might be installed, because any other Courier fonts would typically have a different family name.

TrueType fonts are organized around a typeface name (for example, Courier New) and style names (for example, italic, bold, and extra-bold). The EnumFontFamilies function enumerates all the styles associated with a given family name, not simply the bold and italic attributes. For example, when the system includes a TrueType font called Courier New Extra-Bold, EnumFontFamilies lists it with the other Courier New fonts. The capabilities of EnumFontFamilies are helpful for fonts with many or unusual styles and for fonts that cross international borders.

If an application does not supply a typeface name, the EnumFonts and EnumFontFamilies functions supply information about one font in each available family. To enumerate all the fonts in a device context, the application can specify NULL for the typeface name, compile a list of the available typefaces, and then enumerate each font in each typeface.

The following example uses the EnumFontFamilies function to retrieve the number of available raster, vector, and TrueType font families.

    UINT uAlignPrev;

    int aFontCount[] = { 0, 0, 0 };

    char szCount[8];

    EnumFontFamilies(hdc, (LPCTSTR) NULL,

        (FONTENUMPROC) EnumFamCallBack, (LPARAM) aFontCount);

    uAlignPrev = SetTextAlign(hdc, TA_UPDATECP);

    MoveToEx(hdc, 10, 50, (LPPOINT)NULL);

    TextOut(hdc, 0, 0, "Number of raster fonts: ", 24);

    itoa(aFontCount[0], szCount, 10);

    TextOut(hdc, 0, 0, szCount, strlen(szCount));

    MoveToEx(hdc, 10, 75, (LPPOINT)NULL);

    TextOut(hdc, 0, 0, "Number of vector fonts: ", 24);

    itoa(aFontCount[1], szCount, 10);

    TextOut(hdc, 0, 0, szCount, strlen(szCount));

    MoveToEx(hdc, 10, 100, (LPPOINT)NULL);

    TextOut(hdc, 0, 0, "Number of TrueType fonts: ", 26);

    itoa(aFontCount[2], szCount, 10);

    TextOut(hdc, 0, 0, szCount, strlen(szCount));

    SetTextAlign(hdc, uAlignPrev);

        .

        .

        .

BOOL FAR PASCAL EnumFamCallBack(lplf, lpntm, FontType, aFontCount)

LPLOGFONT lplf;

LPNEWTEXTMETRIC lpntm;

DWORD FontType;

LPVOID aFontCount;

{

    int far * aiFontCount = (int far *) aFontCount;

    /*

     * Record the number of raster, TrueType, and vector

     * fonts in the font-count array.

     */

    if (FontType & RASTER_FONTTYPE)

        aiFontCount[0]++;

    else if (FontType & TRUETYPE_FONTTYPE)

        aiFontCount[2]++;

    else

        aiFontCount[1]++;

    if (aiFontCount[0] || aiFontCount[1] || aiFontCount[2])

        return TRUE;

    else

        return FALSE;

    UNREFERENCED_PARAMETER( lplf );

    UNREFERENCED_PARAMETER( lpntm );

}

This example uses two masks, RASTER_FONTTYPE and TRUETYPE_FONTTYPE, to determine the type of font being enumerated. If the RASTER_FONTTYPE bit is set, the font is a raster font. If the TRUETYPE_FONTTYPE bit is set, the font is a TrueType font. If neither bit is set, the font is a vector font. A third mask, DEVICE_FONTTYPE, is set when a device (for example, a laser printer) supports downloading TrueType fonts; it is zero if the device is a display adapter, dot-matrix printer, or other raster device. An application can also use the DEVICE_FONTTYPE mask to distinguish GDI-supplied raster fonts from device-supplied fonts. Windows can simulate bold, italic, underline, and strikeout attributes for GDI-supplied raster fonts, but not for device-supplied fonts.

An application can also check bits 1 and 2 in the tmPitchAndFamily member of the NEWTEXTMETRIC structure to identify a TrueType font. If bit 1 is 0 and bit 2 is 1, the font is a TrueType font.

Vector fonts are categorized as OEM_CHARSET instead of ANSI_CHARSET. Some applications identify vector fonts by using this information, checking the tmCharSet member of the NEWTEXTMETRIC structure. This categorization usually prevents the font mapper from choosing vector fonts unless they are specifically requested. (Most applications no longer use vector fonts because their strokes are single lines and they take longer to draw than TrueType fonts, which offer many of the same scaling and rotation features that required vector fonts in earlier versions of Windows.)


Checking the Text Capabilities of a Device

You can use the EnumFonts and EnumFontFamilies functions to enumerate the fonts that are available in a printer-compatible memory device context. You can also use the GetDeviceCaps function to retrieve information about the text capabilities of a device. By calling the GetDeviceCaps function with the NUMFONTS index, you can determine the minimum number of fonts supported by a printer. (An individual printer may support more fonts than specified in the return value from GetDeviceCaps with the NUMFONTS index.) By using the TEXTCAPS index, you can identify many of the text capabilities of the specified device.


Setting the Text Alignment

You can query and set the text alignment for a device context by using the GetTextAlign and SetTextAlign functions. The text-alignment settings determine how text is positioned relative to a given location. Text can be aligned to the right or left of the position or centered over it; it can also be aligned above or below the point.

The following example shows a method for determining which horizontal alignment flag is set:

switch ((TA_LEFT | TA_RIGHT | TA_CENTER) & GetTextAlign(hdc))

{

case TA_LEFT:

   .

   .

   .

case TA_RIGHT:

   .

   .

   .

case TA_CENTER:

   .

   .

   .

}

You can also use the SetTextAlign function to update the current position when a text-output function is called. For instance, the following example uses the SetTextAlign function to update the current position when the TextOut function is called. In this example, the cArial parameter is an integer that specifies the number of Arial fonts.

UINT uAlignPrev;

char szCount[8];

uAlignPrev = SetTextAlign(hdc, TA_UPDATECP);

MoveToEx(hdc, 10, 50, (LPPOINT) NULL);

TextOut(hdc, 0, 0, "Number of Arial fonts: ", 23);

itoa(cArial, szCount, 10);

TextOut(hdc, 0, 0, (LPSTR) szCount, strlen(szCount));

SetTextAlign(hdc, uAlignPrev);


Drawing Text From Different Fonts on the Same Line

Different type styles within a font family can have different widths. For example, bold and italic styles of a family are always wider than the roman style for a given point size. When you display or print several type styles on a single line, you must keep track of the width of the line to avoid having characters displayed or printed on top of one another.

You can use two functions to retrieve the width (or extent) of text in the current font. The GetTabbedTextExtent function computes the width and height of a character string. If the string contains one or more tab characters, the width of the string is based upon a specified array of tab-stop positions. The GetTextExtentPoint32 function computes the width and height of a line of text.

When necessary, Windows synthesizes a font by changing the character bitmaps. To synthesize a character in a bold font, Windows draws the character twice: once at the starting point, and again one pixel to the right of the starting point. To synthesize a character in an italic font, Windows draws two rows of pixels at the bottom of the character cell, moves the starting point one pixel to the right, draws the next two rows, and continues until the character has been drawn. By shifting pixels, each character appears to be sheared to the right. The amount of shear is a function of the height of the character.

One way to write a line of text that contains multiple fonts is to use the GetTextExtentPoint32 function after each call to TextOut and add the length to a current position. The following example writes the line "This is a sample string." using bold characters for "This is a", switches to italic characters for "sample", then returns to bold characters for "string." After printing all the strings, it restores the system default characters.

int XIncrement;

int YStart;

TEXTMETRIC tm;

HFONT hfntDefault, hfntItalic, hfntBold;

SIZE sz;

LPSTR lpszString1 = "This is a ";

LPSTR lpszString2 = "sample ";

LPSTR lpszString3 = "string.";

/* Create a bold and an italic logical font. */

hfntItalic = MyCreateFont();

hfntBold = MyCreateFont();

/* Select the bold font and draw the first string         */

/* beginning at the specified point (XIncrement, YStart). */

XIncrement = 10;

YStart = 50;

hfntDefault = SelectObject(hdc, hfntBold);

TextOut(hdc, XIncrement, YStart, lpszString1,

        lstrlen(lpszString1));

/*

 * Compute the length of the first string and add

 * this value to the x-increment that is used for the

 * text-output operation.

 */

GetTextExtentPoint32(hdc, lpszString1,

                   lstrlen(lpszString1), &sz);

XIncrement += sz.cx;

/*

 * Retrieve the overhang value from the TEXTMETRIC

 * structure and subtract it from the x-increment.

 * (This is only necessary for non-TrueType raster

 * fonts.)

 */

GetTextMetrics(hdc, &tm);

XIncrement -= tm.tmOverhang;

/*

 * Select an italic font and draw the second string

 * beginning at the point (XIncrement, YStart).

 */

hfntBold = SelectObject(hdc, hfntItalic);

GetTextMetrics(hdc, &tm);

XIncrement -= tm.tmOverhang;

TextOut(hdc, XIncrement, YStart, lpszString2,

        lstrlen(lpszString2));

/*

 * Compute the length of the second string and add

 * this value to the x-increment that is used for the

 * text-output operation.

 */

GetTextExtentPoint32(hdc, lpszString2, lstrlen(lpszString2), &sz);

XIncrement += sz.cx;

/*

 * Reselect the bold font and draw the third string

 * beginning at the point (XIncrement, YStart).

 */

SelectObject(hdc, hfntBold);

TextOut(hdc, XIncrement - tm.tmOverhang, YStart, lpszString3,

            lstrlen(lpszString3));

/* Reselect the original font. */

SelectObject(hdc, hfntDefault);

/* Delete the bold and italic fonts. */

DeleteObject(hfntItalic);

DeleteObject(hfntBold);

In this example, the GetTextExtentPoint32 function initializes the members of a SIZE structure with the length and height of the specified string. The GetTextMetrics function retrieves the overhang for the current font. Because the overhang is zero if the font is a TrueType font, the overhang value does not change the string placement. For raster fonts, however, it is important to use the overhang value.

The overhang is subtracted from the bold string once, to bring subsequent characters closer to the end of the string if the font is a raster font. Because overhang affects both the beginning and end of the italic string in a raster font, the glyphs start at the right of the specified location and end at the left of the endpoint of the last character cell. (The GetTextExtentPoint32 function retrieves the extent of the character cells, not the extent of the glyphs.) To account for the overhang in the raster italic string, the example subtracts the overhang before placing the string and subtracts it again before placing subsequent characters.

The SetTextJustification function adds extra space to the break characters in a line of text. You can use the GetTextExtentPoint function to determine the extent of a string, then subtract that extent from the total amount of space the line should occupy, and use the SetTextJustification function to distribute the extra space among the break characters in the string. The SetTextCharacterExtra function adds extra space to every character cell in the selected font, including the break character. (You can use the GetTextCharacterExtra function to determine the current amount of extra space being added to the character cells; the default setting is zero.)

You can place characters with greater precision by using the GetCharWidth32 or GetCharABCWidths function to retrieve the widths of individual characters in a font. The GetCharABCWidths function is more accurate than the GetCharWidth32 function, but only when it is used with TrueType fonts; when you use GetCharABCWidths with non-TrueType fonts, it retrieves the same information as GetCharWidth32.

ABC spacing also allows an application to perform very accurate text alignment. For example, when the application right aligns a raster roman font without using ABC spacing, the advance width is calculated as the character width. This means the white space to the right of the glyph in the bitmap is aligned, not the glyph itself. By using ABC widths, applications have more flexibility in the placement and removal of white space when aligning text, because they have information that allows them to finely control intercharacter spacing.


Rotating Lines of Text

You can rotate TrueType fonts at any angle. This is useful for labeling charts and other illustrations. The following example rotates a string in 10-degree increments around the center of the client area by changing the value of the lfEscapement and lfOrientation members of the LOGFONT structure used to create the font.

RECT rc;

int angle;

HFONT hfnt, hfntPrev;

LPSTR lpszRotate = "String to be rotated.";

/* Allocate memory for a LOGFONT structure. */

PLOGFONT plf = (PLOGFONT) LocalAlloc(LPTR, sizeof(LOGFONT));

/* Specify a font typeface name and weight. */

lstrcpy(plf->lfFaceName, "Arial");

plf->lfWeight = FW_NORMAL;

/* Retrieve the client-rectangle dimensions. */

GetClientRect(hwnd, &rc);

/*

 * Set the background mode to transparent for the

 * text-output operation.

 */

SetBkMode(hdc, TRANSPARENT);

/*

 * Draw the string 36 times, rotating 10 degrees

 * counter-clockwise each time.

 */

for (angle = 0; angle < 3600; angle += 100) {

    plf->lfEscapement = angle;

    hfnt = CreateFontIndirect(plf);

    hfntPrev = SelectObject(hdc, hfnt);

    TextOut(hdc, rc.right / 2, rc.bottom / 2,

        lpszRotate, lstrlen(lpszRotate));

    SelectObject(hdc, hfntPrev);

    DeleteObject(hfnt);

}

/* Reset the background mode to its default. */

SetBkMode(hdc, OPAQUE);

/* Free the memory allocated for the LOGFONT structure. */

LocalFree((LOCALHANDLE) plf);


Retrieving Character Outlines

You can use the GetGlyphOutline function to retrieve the outline of a glyph from a TrueType font. The glyph outline returned by the GetGlyphOutline function is for a grid-fitted glyph. (A grid-fitted glyph has been modified so that its bitmap image conforms as closely as possible to the original design of the glyph.) If your application requires an unmodified glyph outline, request the glyph outline for a character in a font whose size is equal to the font's em units. (To create a font with this size, set the lfHeight member of the LOGFONT structure to the negative of the value of the ntmSizeEM member of the NEWTEXTMETRIC structure.)

GetGlyphOutline returns the outline as a bitmap or as a series of polylines and splines. When an application retrieves a glyph outline as a series of polylines and splines, the information is returned in a TTPOLYGONHEADER structure followed by as many TTPOLYCURVE structures as required to describe the glyph. All points are returned as POINTFX structures and represent absolute positions, not relative moves. The starting point given by the pfxStart member of the TTPOLYGONHEADER structure is the point where the outline for a contour begins. The TTPOLYCURVE structures that follow can be either polyline records or spline records.

To render a TrueType character outline in Windows, you must use both the polyline and the spline records. Windows can render both polylines and splines easily. Each polyline and spline record contains as many sequential points as possible, to minimize the number of records returned.

The starting point given in the TTPOLYGONHEADER structure is always on the outline of the glyph. The specified point serves as both the starting and ending points for the contour.


Polyline Records

Polyline records are a series of points; lines drawn between the points describe the outline of the character. A polyline record begins with the last point in the previous record (or, for the first record in the contour, the starting point). Each point in the record is on the glyph outline and can be connected simply by using straight lines.


Spline Records

Spline records represent the quadratic curves (that is, quadratic b-splines) used by TrueType. A spline record begins with the last point in the previous record (or for the first record in the contour, with the starting point). For the first spline record, the starting point and the last point in the record are on the glyph outline. For all other spline records, only the last point is on the glyph outline. All other points in the spline records are off the glyph outline and must be rendered as the control points of b-splines.

The last spline or polyline record in a contour always ends with the contour's starting point. This arrangement ensures that every contour is closed.

Because b-splines require three points (one point off the glyph outline between two points that are on the outline), you must perform some calculations when a spline record contains more than one off-curve point.

For example, if a spline record contains three points (A, B, and C) and it is not the first record, points A and B are off the glyph outline. To interpret point A, use the current position (which is always on the glyph outline) and the point on the glyph outline between points A and B. To find the midpoint (M) between A and B, you can perform the following calculation.

M = A + (B − A)/2

The midpoint between consecutive off-outline points in a spline record is a point on the glyph outline, according to the definition of the spline format used in TrueType fonts.

If the current position is designated by P, the two quadratic splines defined by this spline record are (P, A, M) and (M, B, C).


Using Portable TrueType Metrics

Applications that use the TrueType text metrics can achieve a high degree of printer and document portability; even applications that must maintain compatibility with earlier versions of Windows can use the TrueType metrics.

Design widths overcome most of the problems of device-dependent text introduced by physical devices. Design widths are a kind of logical width. Independent of any rasterization problems or scaling transformations, each glyph has a logical width and height. Composed to a logical page, each character in a string has a place that is independent of the physical device widths. Although a logical width implies that widths can be scaled linearly at all point sizes, this is not necessarily true for either nonportable or most TrueType fonts. At smaller point sizes, some glyphs are made wider relative to their height for better readability.

The characters in TrueType core fonts are designed against a 2048 by 2048 grid. The design width is the width of a character in these grid units. (TrueType supports any integer grid size up to 16,384 by 16,384; grid sizes that are integer powers of 2 scale faster than other grid sizes.)

The font outline is designed in notional units. The em square is the notional grid against which the font outline is fitted. (You can use the otmEMSquare member of OUTLINETEXTMETRIC and the ntmSizeEM member of NEWTEXTMETRIC to retrieve the size of the em square in notional units.) When a font is created that has a point size (in device units) equal to the size of its em square, the ABC widths for this font are the desired design widths. For example, assume the size of an em square is 1000 and the ABC widths of a character in the font are 150, 400, and 150. A character in this font that is 10 device units high would have ABC widths of 1.5, 4, and 1.5, respectively. Since the MM_TEXT mapping mode is most commonly used with fonts (and MM_TEXT is equivalent to device units), this is a simple calculation.

Because of the high resolution of TrueType design widths, applications that use them must take into account the large numeric values that can be created.


Device vs. Design Units

An application can retrieve font metrics for a physical font only after the font has been selected into a device context. When a font is selected into a device context, it is scaled for the device. The font metrics specific to the device are known as device units.

Portable metrics in fonts are known as design units. To apply to a given device, design units must be converted to device units. Use the following formula to convert design units to device units.

DeviceUnits = (DesignUnits/unitsPerEm) * (PointSize/72) * DeviceResolution

The variables in this formula have the following meanings.

Variable	Description
DeviceUnits	Specifies the DesignUnits font metric converted to device units. This value is in the same units as the value given for DeviceResolution.
DesignUnits	Specifies the font metric to be converted to device units. This value can be any font metric, including the width of a character or the ascender value for an entire font.
unitsPerEm	Specifies the em square size for the font.
PointSize	Specifies size of the font, in points. (One point equals 1/72 of an inch.)
DeviceResolution	Specifies number of device units (pixels) per inch. Typical values might be 300 for a laser printer or 96 for a VGA screen.
This formula should not be used to convert device units back to design units. Device units are always rounded to the nearest pixel. The propagated round-off error can become very large, especially when an application is working with screen sizes.

To request design units, create a logical font whose height is specified as −unitsPerEm. Applications can retrieve the value for unitsPerEm by calling the EnumFontFamilies function and checking the ntmSizeEM member of the NEWTEXTMETRIC structure.


Metrics for Portable Documents

The following table specifies the most important font metrics for applications that require portable documents and the functions that allow an application to retrieve them.

Function	Metric	Use
EnumFontFamilies	ntmSizeEM	Retrieval of design metrics; conversion to device metrics
GetCharABCWidths	ABCWidths	Accurate placement of characters at the start and end of margins, picture boundaries, and other text breaks
GetCharWidth32	AdvanceWidths	Placement of characters on a line
GetOutlineTextMetrics	otmfsType	Font-embedding bits
	otmsCharSlopeRise	Y-component for slope of cursor for italic fonts
	otmsCharSlopeRun	X-component for slope of cursor for italic fonts
	otmAscent	Line spacing
	otmDescent	Line spacing
	otmLineGap	Line spacing
	otmpFamilyName	Font identification
	otmpStyleName	Font identification
	otmpFullName	Font identification (typically, family and style name)
The otmsCharSlopeRise, otmsCharSlopeRun, otmAscent, otmDescent, and otmLineGap members of the OUTLINETEXTMETRIC structure are scaled or transformed to correspond to the current device mode and physical height (as given in the tmHeight member of the NEWTEXTMETRIC structure).

Font identification is important in those instances when an application must select the same font — for example, when a document is reopened or moved to a different operating system. The font mapper always selects the correct font when an application requests a font by full name. The family and style names provide input to the standard font dialog box, which ensures that the selection bars are properly placed.

The otmsCharSlopeRise and otmsCharSlopeRun values are used to produce a close approximation of the main italic angle of the font. For typical roman fonts, otmsCharSlopeRise is 1 and otmsCharSlopeRun is 0. For italic fonts, the values attempt to approximate the sine and cosine of the main italic angle of the font (in counterclockwise degrees past vertical); note that the italic angle for upright fonts is 0. Because these values are not expressed in design units, they should not be converted into device units.

The character placement and line spacing metrics enable an application to compute device-independent line breaks that are portable across screens, printers, typesetters, and even platforms.

Device-independent page layout requires the following seven basic steps:

1.	Normalize all design metrics to a common ultra-high resolution (UHR) value (for example, 65,536 DPI); this prevents round-off errors.

2.	Compute line breaks based on UHR metrics and physical page width; this yields a starting point and an ending point of a line within the text stream.

3.	Compute the device page width in device units (for example, pixels).

4.	Fit each line of text into the device page width, using the line breaks computed in step 2.

5.	Compute page breaks by using UHR metrics and the physical page length; this yields the number of lines per page.

6.	Compute the line heights in device units.

7.	Fit the lines of text onto the page, using the lines per page from step 5 and the line heights from step 6.

If all applications adopt these techniques, developers can virtually guarantee that documents moved from one application to another will retain their original appearance and format.


Using PANOSE Numbers

TrueType font files include PANOSE numbers, which applications can use to choose a font that closely matches their specifications. The PANOSE system classifies faces by 10 different attributes. For more information about these attributes, see the PANOSE structure. A PANOSE structure is part of the OUTLINETEXTMETRIC structure (whose values are filled in by calling the GetOutlineTextMetrics function).

The PANOSE attributes are rated individually on a scale. The resulting values are concatenated to produce a number. Given this number for a font and a mathematical metric to measure distances in the PANOSE space, an application can determine the nearest neighbors.


Creating Customized Fonts

Windows keeps a font table containing all the fonts that applications can use. Windows chooses a font from this table when an application calls the CreateFont or CreateFontIndirect function. There can be up to 253 entries in the table.

A font resource is a group of individual fonts representing characters in a given character set that have various combinations of heights, widths, and pitches. You can load font resources and add the fonts in each resource to the operating system font table by using the AddFontResource function. To remove a font resource from the font table, you can use the RemoveFontResource function.

After you add a font resource to the font table, you can use the individual fonts in the resource. In other words, the CreateFont function takes the fonts into account when it tries to match a physical font to the specified logical font. (Fonts in the table are never directly accessible to an application. They are available only through the CreateFontIndirect and CreateFont functions, which return the handles of the fonts, not their memory addresses.)

Whenever your application adds or removes a font resource, it should inform all other applications of the change by sending a WM_FONTCHANGE message to them. Use the following call to the SendMessage function to send the message to all windows.

SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0);

You can use the GetProfileString function to search the [Fonts] section of the WIN.INI file for the list of fonts that the user has used Control Panel to install.


Creating Font Resources

A font resource file is an empty Windows dynamic-link library; it contains no code or data, but it does contain resources. You can create font resources by creating font files and adding them as resources to a font resource file. To create a font resource file, follow these steps:

1.	Create the font files.

2.	Create a resource-definition file for the font.

3.	Create a dummy code module.

4.	Create a module-definition file that describes the fonts and the devices that use the fonts.

5.	Compile and link the source files.

You can add a font file to an empty library, along with such resources as icons, cursors, and menus, by using resource compiler.

Note  A complete explanation of how to create a font resource file is beyond the scope of this book. For more information on this topic, see the documentation provided with your application development tools.


Installing and Using an Embedded Font

You must separate an embedded font from the containing document and install it in the user's operating system before Windows can use it. Although the exact procedure for separating the font from the document depends on the method used to embed it, your application should always perform these steps:

1.	Resolve name conflicts before installing the font.

2.	Write the font data to a file, decoding read-only fonts as necessary.

3.	Use the CreateScalableFontResource function to create a font resource file for the unembedded font.

In Windows, only a TrueType font can be embedded.

Your application should avoid installing a font with the same name as a font that is already on the system. To determine whether there are duplicate style names, an application can compare the information returned by EnumFontFamilies against the family name and style name stored with the embedded font.

Read-Write Permission

Embedded fonts that have read-write permission (and that therefore can be permanently installed on the user's system) should be written to a file that has the .TTF filename extension.

Most applications put the files for embedded fonts that have read-write permission into either the SYSTEM subdirectory of the user's Windows directory or into the application's working directory. Files for read-only embedded fonts are typically put into a temporary directory.

Before installing an embedded font, you must use the CreateScalableFontResource function to create a font resource file. Because Windows cannot directly interpret the native TrueType font file format, it requires a file that mimics the standard .FON file (called a .FOT file) to make internal bookkeeping and enumeration easier. The CreateScalableFontResource function produces a .FOT file that points to the TrueType font file. Once this .FOT file is produced, Windows applications can use TrueType fonts transparently by using the AddFontResource and RemoveFontResource functions. You can also use the CreateScalableFontResource function to install special fonts for logos, icons, and other graphics. Font resource files for read-only fonts should use a different extension (for example, .FOR) and should be hidden from other applications in the system by specifying 1 for the first parameter of CreateScalableFontResource.

Your application should offer users the option of permanently installing embedded fonts that have read-write permission. To permanently install a font, applications should concatenate the typeface and style names and then use the WriteProfileString function to insert this string along with the .FOT file name in the [Fonts] section of the WIN.INI file. A typical font entry in the [Fonts] section looks like the following example.

Times New Roman Bold (TrueType)=TIMESBD.FOT

Read-Only Permission

Embedded fonts with read-only permission should not use the .TTF extension and should avoid the .FOT and .FON extensions. A typical filename extension for read-only embedded fonts is .TTR. Files for read-only embedded fonts must be removed from the operating system and from both physical and logical memory as soon as the containing document is closed, so their names do not need to be meaningful except to the application.

If a document contains one or more read-only embedded fonts, the user must not be permitted to edit the document. If the user is allowed to edit the document in any way, your application must first strip away and delete the read-only embedded fonts. As mentioned earlier, read-only embedded fonts must be removed from the operating system and memory immediately when the document in which they are bundled is closed.

To delete read-only embedded fonts, your application should follow these steps:

1.	Call the RemoveFontResource function for each font to be deleted.

2.	Delete the font resource file for each font.

3.	Delete each TrueType font file for each font.

When an application creates a file for a read-only embedded font and specifies 1 for the first parameter of the CreateScalableFontResource function, the EnumFonts and EnumFontFamilies functions will not enumerate this font. Hiding read-only embedded fonts in this manner makes it unlikely that another application can use them, even though Windows resources are theoretically available to all processes in Windows. The RemoveFontResource function does not delete a font currently in use. If your application uses a read-only embedded font installed by another application, it can be difficult for the installing application to delete the font. In this case, your application should delete the resource file and the TrueType font file when the user closes the document containing the read-only fonts.

It is very important that applications delete the TrueType font file for read-only embedded fonts. If the delete operation fails when the user closes the document, the application should periodically attempt to delete the file as the application runs, when it closes, and the next time it starts.

In some cases, an application is unable to delete a TrueType font file for a read-only embedded font because of external events (such as a system failure). There is no legal liability for events that are out of the control of the application.


Font and Text Functions

Following are the functions used with fonts.

AddFontResource
CreateFont
CreateFontIndirect
CreateScalableFontResource
DrawText
DrawTextEx
EnumFontFamilies
EnumFontFamProc
EnumFonts
EnumFontsProc
ExtTextOut
GetAspectRatioFilterEx
GetCharABCWidths
GetCharABCWidthsFloat
GetCharacterPlacement
GetCharWidth
GetCharWidth32
GetCharWidthFloat
GetFontData
GetGlyphOutline
GetKerningPairs
GetOutlineTextMetrics
GetRasterizerCaps
GetTabbedTextExtent
GetTextAlign
GetTextCharacterExtra
GetTextColor
GetTextExtentExPoint
GetTextExtentPoint
GetTextExtentPoint32
GetTextFace
GetTextMetrics
PolyTextOut
RemoveFontResource
SetMapperFlags
SetTextAlign
SetTextCharacterExtra
SetTextColor
SetTextJustification
TabbedTextOut
TextOut

Obsolete or Deleted Functions

GetAspectRatioFilter
GetTextExtent


Lines and Curves

Lines and curves are used to draw graphics output on raster devices. As discussed in this overview, a line is a set of highlighted pixels on a raster display (or a set of dots on a printed page) identified by two points: a starting point and an ending point. A regular curve is a set of highlighted pixels on a raster display (or dots on a printed page) that defines the perimeter (or part of the perimeter) of a conic section. An irregular curve is a set of pixels that defines a curve that does not fit the perimeter of a conic section.


About Lines and Curves

All types of applications written for Microsoft® Windows® use lines and curves to draw graphics output on raster devices. Computer-aided design (CAD) and drawing applications use lines and curves to outline objects, specify the centers of objects, the dimensions of objects, and so on. Spreadsheet applications use lines and curves to draw grids, charts, and graphs. Word processing applications use lines to create rules and borders on a page of text.


Lines

A line is a set of highlighted pixels on a raster display (or a set of dots on a printed page) identified by two points: a starting point and an ending point. In Windows, the pixel located at the starting point is always included in the line, and the pixel located at the ending point is always excluded. (This kind of line is sometimes called inclusive-exclusive.)

When an application calls one of the Windows line-drawing functions, graphics device interface (GDI), or in some cases a device driver, determines which pixels should be highlighted. GDI is a dynamic-link library (DLL) that processes graphics function calls from a Windows-based application and passes those calls to a device driver. A device driver is a DLL that receives input from GDI, converts the input to device commands, and passes those commands to the appropriate device. GDI uses a digital differential analyzer (DDA) to determine the set of pixels that define a line. A DDA determines the set of pixels by examining each point on the line and identifying those pixels on the display surface (or dots on a printed page) that correspond to the points. The following illustration shows a line, its starting point, its ending point, and the pixels highlighted by using a simple DDA.

The simplest and most common DDA is the Bresenham, or incremental, DDA. A modified version of this algorithm draws lines in Windows versions 3.x. The incremental DDA is noted for its simplicity, but it is also noted for its inaccuracy. Because it rounds off to the nearest integer value, it sometimes fails to represent the original line requested by the application. The Microsoft® Win32® DDA used by GDI does not round off to the nearest integer. As a result, this new DDA produces output that is sometimes much closer in appearance to the original line requested by the application.

Note  If an application requires line output that cannot be achieved with the new DDA, it can draw its own lines by calling the LineDDA function and supplying a private DDA. However, the LineDDA function draws lines much slower than the Windows line-drawing functions. Do not use this function within an application if speed is a primary concern.

An application can use the new DDA to draw single lines and multiple, connected line segments. An application can draw a single line by calling the LineTo function. This function draws a line from the current position up to, but not including, a specified ending point. An application can draw a series of connected line segments by calling the Polyline function, supplying an array of points that specify the ending point of each line segment. An application can draw multiple, disjointed series of connected line segments by calling the PolyPolyline function, supplying the required ending points.

The following illustration shows line output created by calling the LineTo, Polyline, and PolyPolyline functions.


Curves

A regular curve is a set of highlighted pixels on a raster display (or dots on a printed page) that define the perimeter (or part of the perimeter) of a conic section. An irregular curve is a set of pixels that define a curve that does not fit the perimeter of a conic section. In Windows, the ending point is excluded from a curve just as it is excluded from a line.

When an application calls one of the Windows curve-drawing functions, GDI breaks the curve into a number of extremely small, discrete line segments. After determining the endpoints (starting point and ending point) for each of these line segments, GDI determines which pixels (or dots) define each line by applying its DDA.

An application can draw an ellipse or part of an ellipse by calling the Arc function. This function draws the curve within the perimeter of an invisible rectangle called a bounding rectangle. The size of the ellipse is specified by two invisible radials extending from the center of the rectangle to the sides of the rectangle. The following illustration shows an arc (part of an ellipse) drawn by using the Arc function.

When calling the Arc function, an application specifies the coordinates of the bounding rectangle and radials. The preceding illustration shows the rectangle and radials with dashed lines while the actual arc was drawn using a solid line.

When drawing the arc of another object, the application can call the SetArcDirection and GetArcDirection functions to control the direction (clockwise or counterclockwise) in which the object is drawn. The default direction for drawing arcs and other objects is counterclockwise.

In addition to drawing ellipses or parts of ellipses, Windows-based applications can draw irregular curves called Bézier curves. A Bézier curve is an irregular curve whose curvature is defined by four control points (p1, p2, p3, and p4). The control points p1 and p4 define the starting and ending points of the curve, and the control points p2 and p3 define the shape of the curve by marking points where the curve reverses orientation.

An application can draw irregular curves by calling the PolyBezier function, supplying the appropriate control points.


Combined Lines and Curves

In addition to drawing lines or curves, Windows-based applications can draw combinations of line and curve output by calling a single function. For example, an application can draw the outline of a pie chart by calling the AngleArc function.

The AngleArc function draws an arc along a circle's perimeter and draws a line connecting the starting point of the arc to the circle's center. In addition to using the AngleArc function, a Windows-based application can also combine line and irregular curve output by using the PolyDraw function.


Line and Curve Attributes

A device context (DC) contains attributes that affect line and curve output. The line and curve attributes include the current position, brush style, brush color, pen style, pen color, transformation, and so on.

The default current position for any DC is located at the point (0,0) in logical (or world) space. You can set these coordinates to a new position by calling the MoveToEx function and passing a new set of coordinates.

Note  Windows provides two sets of line- and curve-drawing functions. The first set retains the current position in a DC, and the second set alters the position. You can identify the functions that alter the current position by examining the function name. If the function name ends with the preposition "To", the function sets the current position to the ending point of the last line drawn (LineTo, ArcTo, PolylineTo, or PolyBezierTo). If the function name does not end with this preposition, it leaves the current position intact (Arc, Polyline, or PolyBezier).

The default brush is a solid white brush. An application can create a new brush by calling the CreateBrushIndirect function. After creating a brush, the application can select it into its DC by calling the SelectObject function. Windows provides a complete set of functions to create, select, and alter the brush in an application's DC. For more information about these functions and about brushes in general, see Brushes.

The default pen is a cosmetic, solid black pen that is one pixel wide. An application can create a pen by using the ExtCreatePen function. After creating a pen, your application can select it into its DC by calling the SelectObject function. Windows provides a complete set of functions to create, select, and alter the pen in an application's DC. For more information about these functions and about pens in general, see Pens.

The default transformation is the unity transformation (specified by the identity matrix). An application can specify a new transformation by calling the SetWorldTransform function. Windows provides a complete set of functions to transform lines and curves by altering their width, location, and general appearance. For more information about these functions, see Coordinate Spaces and Transformations.


Using Lines and Curves

You can use the line and curve functions to draw virtually any shape or object in the client area of an application window. This section illustrates how these functions can be used to draw markers or a pie chart.

•	Drawing markers

•	Drawing a pie chart


Drawing Markers

You can use the line functions to draw markers. A marker is a symbol centered over a point. Drawing applications use markers to designate starting points, ending points, and control points. Spreadsheet applications use markers to designate points of interest on a chart or graph.

In the following code sample, the application-defined Marker function creates a marker by using the MoveToEx and LineTo functions. These functions draw two intersecting lines, 20 pixels in length, centered over the cursor coordinates.

void Marker(LONG x, LONG y, HWND hwnd)

{

    HDC hdc;

    hdc = GetDC(hwnd);

        MoveToEx(hdc, (int) x - 10, (int) y, (LPPOINT) NULL);

        LineTo(hdc, (int) x + 10, (int) y);

        MoveToEx(hdc, (int) x, (int) y - 10, (LPPOINT) NULL);

        LineTo(hdc, (int) x, (int) y + 10);

    ReleaseDC(hwnd, hdc);

}

Windows stores the coordinates of the cursor in the lParam parameter of the WM_LBUTTONDOWN message when the user presses the left mouse button. The following code demonstrates how an application gets these coordinates, determines whether they lie within its client area, and passes them to the Marker function to draw the marker.

/* Line- and arc-drawing variables */

static BOOL bCollectPoints;

static POINT ptMouseDown[32];

static int index;

POINTS ptTmp;

RECT rc;

    case WM_LBUTTONDOWN:

        if (bCollectPoints && index < 32){

            /* Create the region from the client area. */

            GetClientRect(hwnd, &rc);

            hrgn = CreateRectRgn(rc.left, rc.top,

                rc.right, rc.bottom);

            ptTmp = MAKEPOINTS((POINTS FAR *) lParam);

            ptMouseDown[index].x = (LONG) ptTmp.x;

            ptMouseDown[index].y = (LONG) ptTmp.y;

            /* Test for a hit in the client rectangle. */

            if (PtInRegion(hrgn, ptMouseDown[index].x,

                    ptMouseDown[index].y)) {

                /* If a hit occurs, record the mouse coords. */

                Marker(ptMouseDown[index].x, ptMouseDown[index].y,

                    hwnd);

                index++;

            }

        }

        break;


Drawing a Pie Chart

You can use the line and curve functions to draw a pie chart. The primary function used to draw pie charts is the AngleArc function, which requires you to supply the coordinates of the center of the pie, the radius of the pie, a start angle, and a sweep angle. Following is a dialog box that the user can use to enter these values.

The dialog box template found in the application's resource script (.RC) file specifies characteristics of the preceding dialog box (its height, the controls it contains, and its style), as follows.

AngleArc DIALOG 6, 18, 160, 100

STYLE WS_DLGFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION

CAPTION "Pie Chart"

FONT 8, "MS Sans Serif"

BEGIN

    EDITTEXT   IDD_X, 18, 22, 25, 12, ES_AUTOHSCROLL

    LTEXT      "X", 102, 4, 24, 9, 8

    EDITTEXT   IDD_Y, 18, 39, 25, 12, ES_AUTOHSCROLL

    LTEXT      "Y", 104, 5, 42, 12, 8

    LTEXT      "Center", 105, 19, 11, 23, 8

    EDITTEXT   IDD_RADIUS, 103, 9, 32, 12, ES_AUTOHSCROLL

    EDITTEXT   IDD_STARTANGLE, 103, 31, 32, 12, ES_AUTOHSCROLL

    EDITTEXT   IDD_SWEEPANGLE, 103, 53, 32, 12, ES_AUTOHSCROLL

    LTEXT      "Radius", 109, 73, 11, 25, 8

    LTEXT      "Start Angle", 110, 59, 33, 42, 8

    LTEXT      "Sweep Angle", 111, 55, 55, 43, 8

    PUSHBUTTON "OK", IDD_OK, 9, 82, 40, 14

    PUSHBUTTON "Cancel", IDD_CANCEL, 110, 82, 40, 14

END

The dialog box procedure, found in the application's source file, retrieves data (center coordinates, arc radius, and start and sweep angles) by following these steps:

1.	The application-defined ClearBits function initializes the array that receives the user-input to zero.

2.	The application-defined GetStrLngth function retrieves the length of the string entered by the user.

3.	The application-defined RetrieveInput function retrieves the value entered by the user.

The following sample code shows the dialog box procedure.

BOOL CALLBACK ArcDlgProc(HWND hdlg, UINT uMsg, WPARAM wParam,

                       LPARAM lParam)

{

    CHAR chInput[4];    /* receives control-window input  */

    int cch;            /* array-size and count variable  */

    switch (uMsg) {

        case WM_INITDIALOG:

            return FALSE;

        case WM_COMMAND:

            switch (wParam){

                /*

                 * If the user pressed the OK button, retrieve the

                 * data that was entered in the various AngleArc

                 * controls.

                 */

                case IDD_OK:

                    /*

                     * Retrieve the x-coordinate of the arc's

                     * center.

                     */

                    ClearBits(chInput, sizeof(chInput));

                    GetDlgItemText(hdlg, IDD_X, chInput,

                        sizeof(chInput));

                    cch = GetStrLngth(chInput);

                    nX = (int)RetrieveInput(chInput, cch);

                    /*

                     * Retrieve the y-coordinate of the arc's

                     * center.

                     */

                    ClearBits(chInput, sizeof(chInput));

                    GetDlgItemText(hdlg, IDD_Y, chInput,

                        sizeof(chInput));

                    cch = GetStrLngth(chInput);

                    nY = (int)RetrieveInput(chInput, cch);

                    /* Retrieve the radius of the arc. */

                    ClearBits(chInput, sizeof(chInput));

                    GetDlgItemText(hdlg, IDD_RADIUS, chInput,

                        sizeof(chInput));

                    cch = GetStrLngth(chInput);

                    dwRadius = (DWORD) RetrieveInput(chInput, cch);

                    /* Retrieve the start angle. */

                    ClearBits(chInput, sizeof(chInput));

                    GetDlgItemText(hdlg, IDD_STARTANGLE, chInput,

                        sizeof(chInput));

                    cch = GetStrLngth(chInput);

                    xStartAngle = (float) RetrieveInput(chInput,

                                    cch);

                    /* Retrieve the sweep angle. */

                    ClearBits(chInput, sizeof(chInput));

                    GetDlgItemText(hdlg, IDD_SWEEPANGLE, chInput,

                        sizeof(chInput));

                    cch = GetStrLngth(chInput);

                    xSweepAngle = (float) RetrieveInput(chInput,

                                     cch);

                    EndDialog(hdlg, FALSE);

                    return TRUE;

                /*

                 * If user presses the CANCEL button, close the

                 * dialog box.

                 */

                case IDD_CANCEL:

                    EndDialog(hdlg, FALSE);

                    return TRUE;

            } /* end switch (wParam) */

            break;

        default:

            return FALSE;

    } /* end switch (message) */

    UNREFERENCED_PARAMETER(lParam);

}

void ClearBits(LPTSTR cArray, int iLength)

{

    int i;

    for (i = 0; i < iLength; i++)

        cArray[i] = 0;

}

int GetStrLngth(LPTSTR cArray)

{

    int i = 0;

    while (cArray[i++] != 0);

        return i - 1;

}

DWORD RetrieveInput(LPTSTR cArray, int iLength)

{

    int i, iTmp;

    double dVal, dCount;

    dVal = 0.0;

    dCount = (double) (iLength - 1);

    /* Convert ASCII input to a floating-point value. */

    for (i = 0; i < iLength; i++) {

        iTmp = cArray[i] - 0x30;

        dVal = dVal + (((double)iTmp) * pow(10.0, dCount--));

    }

    return (DWORD) dVal;

}

To draw each section of the pie chart, pass the values entered by the user to the AngleArc function. To fill the pie chart using the current brush, embed the call to AngleArc in a path bracket. The following code sample shows the defined path bracket and the call to AngleArc.

int nX;

int nY;

DWORD dwRadius;

float xStartAngle;

float xSweepAngle;

                case (IDM_ANGLEARC):

                   DialogBox((HINSTANCE) GetModuleHandle (NULL),

                             (LPTSTR) "AngleArc",

                             hwnd, (DLGPROC) ArcDlgProc);

                    hdc = GetDC(hwnd);

                        BeginPath(hdc);

                            SelectObject(hdc,

                                GetStockObject(GRAY_BRUSH));

                            MoveToEx(hdc, nX, nY, (LPPOINT) NULL);

                            AngleArc(hdc, nX, nY, dwRadius,

                                xStartAngle, xSweepAngle);

                            LineTo(hdc, nX, nY);

                        EndPath(hdc);

                    StrokeAndFillPath(hdc);

                    ReleaseDC(hwnd, hdc);

                    break;


Line and Curve Functions

Following are the functions used with lines and curves.

AngleArc
Arc
ArcTo
GetArcDirection
LineDDA
LineDDAProc
LineTo
MoveToEx
PolyBezier
PolyBezierTo
PolyDraw
Polyline
PolylineTo
PolyPolyline
SetArcDirection


Metafiles

Applications written for the Microsoft® Windows® operating system use two graphics tools to store pictures: metafiles and bitmaps. For information about bitmaps, see Bitmaps. This overview describes metafiles.


About Metafiles

A metafile is a collection of structures that store a picture in a device-independent format. Device independence is the one feature that sets metafiles apart from bitmaps: unlike a bitmap, a metafile guarantees device independence. For example, when an application creates a picture measuring 2 by 2 inches on a VGA display and stores that picture in a metafile, the picture maintains its original dimensions when printed on a 300 dpi laser printer or copied over a network and displayed in another application that is running on an 8514/A video display. There is a drawback to metafiles, however; they are generally drawn more slowly than bitmaps. Therefore, if an application requires fast drawing and device independence is not an issue, it should use bitmaps instead of metafiles.

Internally, a metafile is an array of variable-length structures called metafile records. The first records in the metafile specify general information such as the resolution of the device on which the picture was created, the dimensions of the picture, and so on. The remaining records, which constitute the bulk of any metafile, correspond to the graphics device interface (GDI) functions required to draw the picture. These records are stored in the metafile after a special metafile device context (DC) is created. This DC is then used for all drawing operations required to create the picture. When Windows processes a GDI function associated with a metafile DC, it converts the function into the appropriate data and stores this data in a record appended to the metafile.

After a picture is complete and the last record is stored in the metafile, the metafile can be passed to another application by means of the clipboard, embedded within another file, stored on disk, or played repeatedly. A metafile is played when its records are converted to device commands and processed by the appropriate device.

There are two types of metafiles: enhanced and Windows. An enhanced metafile is used in applications written using the Microsoft® Win32® application programming interface (API). The enhanced format consists of a header, a table of handles to GDI objects, a private palette, and an array of metafile records. Enhanced metafiles provide true device independence. (You can think of the picture stored in an enhanced metafile as a "snapshot" of the video display taken at a particular moment. This "snapshot" maintains its dimensions no matter where it appears: on a printer, a plotter, or the desktop, or in the client area of any Win32-based application.)

A Windows metafile is used for applications written using the Windows version 3.x API. The Windows format consists of a header and an array of metafile records. Windows-format metafiles are limited in their capabilities and should rarely be used — the Windows-metafile API is supported to maintain backward compatibility with applications that were written to run with Windows version 3.x.


Enhanced-Format Metafiles

A developer can use enhanced metafiles to store a picture created by using the Win32 GDI functions (including new path and transformation functions). Because the enhanced metafile format is standardized for the Win32 API, pictures that are stored in this format can be copied from one Win32 application to another; and, because the pictures are truly device independent, they are guaranteed to maintain their shape and proportion on any output device.


Enhanced Metafiles

An enhanced metafile is an array of records. A metafile record is a variable-length ENHMETARECORD structure. This structure identifies the record type, specifies the record length, and contains additional data that is dependent on the record type.

The first record in an enhanced metafile is always the enhanced-metafile header. The header specifies the following information.

•	Size of the metafile, in bytes

•	Dimensions of the picture frame, in device units

•	Dimensions of the picture frame, in .01-millimeter units

•	Number of records in the metafile

•	Offset to an optional text description

•	Size of the optional palette

•	Resolution of the original device, in pixels

•	Resolution of the original device, in millimeters

An optional text description can follow the header record. The text description describes the picture and the author's name. The optional palette specifies the colors used to create the enhanced metafile. The remaining records identify the GDI functions used to create the picture. The following hexadecimal output corresponds to a record generated for a call to the SetMapMode function.

00000011 0000000C 00000004

The value 0x00000011 specifies the record type (corresponds to the EMR_SETMAPMODE constant defined in the file WINGDI.H). The value 0x0000000C specifies the length of the record, in bytes. The value 0x00000004 identifies the mapping mode (corresponds to the MM_LOENGLISH constant defined in the file WINGDI.H).


Enhanced Metafile Operations

A developer creates an enhanced metafile by using the CreateEnhMetaFile function and supplying the appropriate arguments. The Win32 API uses these arguments to maintain picture dimensions, to determine whether the metafile should be stored on a disk or in memory, and so on.

To maintain picture dimensions across output devices, the Win32 API requires the resolution of the reference device. This reference device is the device on which the picture first appeared, and the reference DC is the DC associated with the reference device. When calling the CreateEnhMetaFile function, the application must supply a handle that identifies this DC. The application can get this handle by calling the GetDC or CreateDC function or specify NULL as the handle to use the current display device for the reference device.

Most applications store pictures permanently and therefore create an enhanced metafile that is stored on a disk; however, there are some instances when this is not necessary. For example, a word-processing application that provides chart-drawing capabilities could store a user-defined chart in memory as an enhanced metafile and then copy the enhanced metafile bits from memory into the user's document file. An application that requires a metafile that is stored permanently on a disk must supply the filename when it calls the CreateEnhMetaFile function. If the developer does not supply a filename, Windows automatically treats the metafile as a temporary file and stores it in memory.

The developer can add an optional text description to a metafile containing information about the picture and the author. An application can display these strings in the File Open dialog box to provide the user with information about metafile content that will help in selecting the appropriate file. If an application includes the text description, the application must supply a pointer to the string when it calls the CreateEnhMetaFile function.

When the CreateEnhMetaFile function is successful, it returns a handle that identifies a special metafile DC. A metafile DC is unique in that it is associated with a file rather than with an output device. When Windows processes a GDI function that received a handle to a metafile DC, it converts the GDI function into an enhanced-metafile record and appends the record to the end of the enhanced metafile.

After a picture is complete and the last record is appended to the enhanced metafile, the application can close the file by calling the CloseEnhMetaFile function. This function closes and deletes the special metafile DC and returns a handle identifying the enhanced metafile. The application can use this handle to accomplish the following tasks.

•	Display the picture stored in the enhanced metafile.

•	Create copies of the enhanced metafile.

•	Enumerate, edit, or copy the individual records in the enhanced metafile.

•	Retrieve the optional description that is stored in the enhanced metafile.

•	Retrieve a copy of the enhanced-metafile header.

•	Retrieve a binary version of the enhanced metafile.

•	Enumerate the colors in the optional palette.

•	Convert an enhanced-format metafile into a Windows-format metafile.

Some applications create temporary backup (or duplicate) copies of a file before enabling the user to alter the original. An application can create a backup copy of an enhanced metafile by calling the CopyEnhMetaFile function, supplying a handle that identifies the enhanced metafile, and supplying a pointer to the name of the new file.

Most drawing, illustration, and computer-aided design (CAD) applications require a means of editing a picture stored in an enhanced metafile. Although editing an enhanced metafile is a complex task, a developer can use the EnumEnhMetaFile function in combination with other Win32 functions to provide this capability in your application. The EnumEnhMetaFile function and its associated callback function enable the application to process individual records in an enhanced metafile.

Some applications display the text description of an enhanced metafile with the corresponding filename in the File Open dialog box. An application can determine whether this string exists in an enhanced metafile by retrieving the metafile header and examining one of its members. The GetEnhMetaFileHeader function can retrieve the metafile header. If the string exists, the application retrieves it by calling the GetEnhMetaFileDescription function.

Some applications retrieve the contents of a metafile by calling the GetEnhMetaFileBits function; however, before retrieving the contents, the application must specify the size of the file. To get the size, the application can use the GetEnhMetaFileHeader function and examine the appropriate member.

To achieve consistent colors when a picture is displayed on various output devices, an application can call the CreatePalette function and store a logical palette in an enhanced metafile. Other applications that display the picture stored in the enhanced metafile retrieve this palette and call the RealizePalette function before displaying the picture. To determine whether a palette is stored in an enhanced metafile, an application can retrieve the metafile header and examine the appropriate member. If a palette exists, the application can call the GetEnhMetaFilePaletteEntries function to retrieve the logical palette.


Windows-Format Metafiles

The Win32 API supports the Windows metafile format to maintain compatibility with applications written for Windows version 3.x. Following are the limitations of this format.

•	A Windows-format metafile is application and device dependent. Changes in the application's mapping modes or the device resolution affect the appearance of metafiles created in this format.

•	A Windows-format metafile does not contain a comprehensive header that describes the original picture dimensions, the resolution of the device on which the picture was created, an optional text description, or an optional palette.

•	A Windows-format metafile does not support the new curve, path, and transformation functions.

•	Some Windows-format metafile records cannot be scaled.

•	The metafile DC associated with a Windows-format metafile cannot be queried (that is, an application cannot retrieve device-resolution data, font metrics, and so on).

To convert a Windows-format metafile to an enhanced-format metafile, an application can call the GetMetaFileBitsEx function to retrieve the data from the Windows-format metafile and then call the SetWinMetaFileBits function to convert this data into an enhanced-format metafile.

A developer writing a Win32-based application should avoid using the Windows-format functions and use the enhanced-format functions instead.


Using Metafiles

•	Creating an enhanced metafile

•	Displaying a picture and storing it in an enhanced metafile

•	Opening an enhanced metafile and displaying its contents

•	Editing an enhanced metafile


Creating an Enhanced Metafile

This section contains an example that demonstrates the creation of an enhanced metafile that is stored on a disk, using a filename specified by the user.

The example uses a DC for the application window as the reference DC. (Windows stores the resolution data for this device in the enhanced-metafile's header.) The application retrieves a handle identifying this DC by calling the GetDC function.

The example uses the dimensions of the application's client area to define the dimensions of the picture frame. Using the rectangle dimensions returned by the GetClientRect function, the application converts the device units to .01-millimeter units and passes the converted values to the CreateEnhMetaFile function.

The example displays a Save As common dialog box that enables the user to specify the filename of the new enhanced metafile. The system appends the three-character .EMF extension to this filename and passes the name to the CreateEnhMetaFile function.

The example also embeds a text description of the picture in the enhanced-metafile header. This description is specified as a resource in the string table of the application's resource file. However, in a working application, this string would be retrieved from a custom control in a common dialog box or from a separate dialog box displayed solely for this purpose.

/* Obtain a handle to a reference DC. */

hdcRef = GetDC(hWnd);

/*

 * Determine the picture frame dimensions.

 * iWidthMM is the display width in millimeters.

 * iHeightMM is the display height in millimeters.

 * iWidthPels is the display width in pixels.

 * iHeightPels is the display height in pixels

 */

iWidthMM = GetDeviceCaps(hdcRef, HORZSIZE);

iHeightMM = GetDeviceCaps(hdcRef, VERTSIZE);

iWidthPels = GetDeviceCaps(hdcRef, HORZRES);

iHeightPels = GetDeviceCaps(hdcRef, VERTRES);

/*

 * Retrieve the coordinates of the client

 * rectangle, in pixels.

 */

GetClientRect(hWnd, &rect);

/*

 * Convert client coordinates to .01-mm units.

 * Use iWidthMM, iWidthPels, iHeightMM, and

 * iHeightPels to determine the number of

 * .01-millimeter units per pixel in the x-

 *  and y-directions.

 */

rect.left = (rect.left * iWidthMM * 100)/iWidthPels;

rect.top = (rect.top * iHeightMM * 100)/iHeightPels;

rect.right = (rect.right * iiWidthMM * 100)/iWidthPels;

rect.bottom = (rect.bottom * iHeightMM * 100)/iHeightPels;

/* Load the filename filter from the string table. */

LoadString(hInst, IDS_FILTERSTRING,

     (LPSTR)szFilter, sizeof(szFilter));

/*

 * Replace the '%' separators that are embedded

 * between the strings in the string-table entry

 * with '\0'.

 */

for (i=0; szFilter[i]!='\0'; i++)

    if (szFilter[i] == '%')

            szFilter[i] = '\0';

/* Load the dialog title string from the table. */

LoadString(hInst, IDS_TITLESTRING,

     (LPSTR)szTitle, sizeof(szTitle));

/* Initialize the OPENFILENAME members. */

szFile[0] = '\0';

Ofn.lStructSize = sizeof(OPENFILENAME);

Ofn.hwndOwner = hWnd;

Ofn.lpstrFilter = szFilter;

Ofn.lpstrFile= szFile;

Ofn.nMaxFile = sizeof(szFile);

Ofn.lpstrFileTitle = szFileTitle;

Ofn.nMaxFileTitle = sizeof(szFileTitle);

Ofn.lpstrInitialDir = (LPSTR)NULL;

Ofn.Flags = OFN_SHOWHELP | OFN_OVERWRITEPROMPT;

Ofn.lpstrTitle = szTitle;

/*

 * Display the Filename common dialog box. The

 * filename specified by the user is passed

 * to the CreateEnhMetaFile function and used to

 * store the metafile on disk.

 */

GetSaveFileName(&Ofn);

/* Load the description from the string table. */

LoadString(hInst, IDS_DESCRIPTIONSTRING,

     (LPSTR)szDescription, sizeof(szDescription));

/*

 * Replace the '%' string separators that are

 * embedded between strings in the string-table

 * entry with '\0'.

 */

for (i=0; szDescription[i]!='\0'; i++)

    if (szDescription[i] == '%')

            szDescription[i] = '\0';

/* Create the metafile DC. */

hdcMeta = CreateEnhMetaFile(hdcRef,

          (LPTSTR) Ofn.lpstrFile,

          &rect, (LPSTR)szDescription);

if (!hdcMeta)

    errhandler("CreateEnhMetaFile", hWnd);

/* Release the reference DC. */

ReleaseDC(hWnd, hdcRef);


Displaying a Picture and Storing It in an Enhanced Metafile

This section contains an example demonstrating the creation of a picture and the process of storing the corresponding records in a metafile. The example draws a picture to the display or stores it in a metafile. If a display DC handle is given, it draws a picture to the screen using various GDI functions. If an enhanced metafile DC is given, it stores the same picture in the enhanced metafile.

void DrawOrStore(HWND hwnd, HDC hdcMeta, HDC hdcDisplay)

{

RECT rect;

HDC hDC;

int fnMapModeOld;

HBRUSH hbrOld;

/* Draw it to the display DC or store it in the metafile DC. */

if (hdcMeta)

    hDC = hdcMeta;

else

    hDC = hdcDisplay;

/* Set the mapping mode in the DC. */

fnMapModeOld = SetMapMode(hDC, MM_LOENGLISH);

/* Find the midpoint of the client area. */

GetClientRect(hwnd, (LPRECT)&rect);

DPtoLP(hDC, (LPPOINT)&rect, 2);

/* Select a gray brush. */

hbrOld = SelectObject(hDC, GetStockObject(GRAY_BRUSH));

/* Draw a circle with a one inch raduis. */

Ellipse(hDC, (rect.right/2 - 100), (rect.bottom/2 + 100),

       (rect.right/2 + 100), (rect.bottom/2 - 100));

/* Perform additional drawing here. */

/* Set the device context back to its original state. */

SetMapMode(hDC, fnMapModeOld);

SelectObject(hDC, hbrOld);

}


Opening an Enhanced Metafile and Displaying Its Contents

This section contains an example demonstrating how an application opens an enhanced metafile stored on disk and displays the associated picture in the client area.

The example uses the Open common dialog box to enable the user to select an enhanced metafile from a list of existing files. It then passes the name of the selected file to the GetEnhMetaFile function, which returns a handle identifying the file. This handle is passed to the PlayEnhMetaFile function in order to display the picture.

LoadString(hInst, IDS_FILTERSTRING,

     (LPSTR)szFilter, sizeof(szFilter));

/*

 * Replace occurrences of '%' string separator

 * with '\0'.

 */

for (i=0; szFilter[i]!='\0'; i++)

    if (szFilter[i] == '%')

            szFilter[i] = '\0';

LoadString(hInst, IDS_DEFEXTSTRING,

     (LPSTR)szDefExt, sizeof(szFilter));

/*

 * Use the OpenFilename common dialog box

 * to obtain the desired filename.

 */

 szFile[0] = '\0';

 Ofn.lStructSize = sizeof(OPENFILENAME);

 Ofn.hwndOwner = hWnd;

 Ofn.lpstrFilter = szFilter;

 Ofn.lpstrCustomFilter = (LPSTR)NULL;

 Ofn.nMaxCustFilter = 0L;

 Ofn.nFilterIndex = 1L;

 Ofn.lpstrFile = szFile;

 Ofn.nMaxFile = sizeof(szFile);

 Ofn.lpstrFileTitle = szFileTitle;

 Ofn.nMaxFileTitle = sizeof(szFileTitle);

 Ofn.lpstrInitialDir = (LPSTR) NULL;

 Ofn.lpstrTitle = (LPSTR)NULL;

 Ofn.Flags = OFN_SHOWHELP | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;

 Ofn.nFileOffset = 0;

 Ofn.nFileExtension = 0;

 Ofn.lpstrDefExt = szDefExt;

 GetOpenFileName(&Ofn);

/* Open the metafile. */

hemf = GetEnhMetaFile(Ofn.lpstrFile);

/* Retrieve a handle to a window DC. */

hDC = GetDC(hWnd);

/* Retrieve the client rectangle dimensions. */

GetClientRect(hWnd, &rct);

/* Draw the picture. */

PlayEnhMetaFile(hDC, hemf, &rct);

/* Release the metafile handle. */

DeleteEnhMetaFile(hemf);

/* Release the window DC. */

ReleaseDC(hWnd, hDC);


Editing an Enhanced Metafile

To edit a picture stored in an enhanced metafile, an application must perform the following tasks.

1.	Use hit-testing to capture the cursor coordinates and retrieve the position of the object (line, arc, rectangle, ellipse, polygon, or irregular shape) that the user wants to alter.

2.	Convert these coordinates to logical (or world) units.

3.	Call the EnumEnhMetaFile function and examine each metafile record.

4.	Determine whether a given record corresponds to a GDI drawing function.

5.	If it does, determine whether the coordinates stored in the record correspond to the line, arc, ellipse, or other graphics element that intersects the coordinates specified by the user.

6.	Upon finding the record that corresponds to the output that the user wants to alter, erase the object on the screen that corresponds to the original record.

7.	Delete the corresponding record from the metafile, saving a pointer to its location.

8.	Permit the user to redraw or replace the object.

9.	Convert the GDI functions used to draw the new object into one or more enhanced-metafile records.

10.	Store these records in the enhanced metafile.


Metafile Functions

Following are the functions used with enhanced format metafiles.

CloseEnhMetaFile
CopyEnhMetaFile
CreateEnhMetaFile
DeleteEnhMetaFile
EnhMetaFileProc
EnumEnhMetaFile
GdiComment
GetEnhMetaFile
GetEnhMetaFileBits
GetEnhMetaFileDescription
GetEnhMetaFileHeader
GetEnhMetaFilePaletteEntries
GetWinMetaFileBits
PlayEnhMetaFile
PlayEnhMetaFileRecord
SetEnhMetaFileBits
SetWinMetaFileBits

The following functions are provided for compatibility with Windows-format metafiles:

CloseMetaFile
CopyMetaFile
CreateMetaFile
DeleteMetaFile
EnumMetaFile
EnumMetaFileProc
GetMetaFile
GetMetaFileBitsEx
PlayMetaFile
PlayMetaFileRecord
SetMetaFileBitsEx


Paths

A path is one or more figures (or shapes) that are filled, outlined, or both filled and outlined. Applications written for Microsoft® Windows® use paths in many ways. Paths are used in drawing and painting applications. Computer-aided design (CAD) applications use paths to create unique clipping regions, to draw outlines of irregular shapes, and to fill the interiors of irregular shapes. An irregular shape is a shape composed of Bézier curves and straight lines. (A regular shape is an ellipse, a circle, a rectangle, or a polygon.)


About Paths

A path is one of the objects associated with a device context (DC). However, unlike the default objects (the pen, the brush, and the font) that are part of any new DC, there is no default path. For more information about DCs, see Device Contexts.

To create a path and select it into a DC, it is first necessary to define the points that describe it. This is done by calling the BeginPath function, specifying the appropriate drawing functions, and then by calling the EndPath function. This combination of functions (BeginPath, drawing functions, and EndPath) constitute a path bracket. The following functions can be used in a path bracket.

AngleArc	LineTo	Polyline
Arc	MoveToEx	PolylineTo
ArcTo	Pie	PolyPolygon
Chord	PolyBezier	PolyPolyline
CloseFigure	PolyBezierTo	Rectangle
Ellipse	PolyDraw	RoundRect
ExtTextOut	Polygon	TextOut
When an application calls EndPath, Windows selects the associated path into the specified DC. (If another path had previously been selected into the DC, Windows deletes that path without saving it.) After Windows selects the path into the DC, an application can operate on the path in one of the following ways:

•	Draw the outline of the path (using the current pen).

•	Paint the interior of the path (using the current brush).

•	Draw the outline and fill the interior of the path.

•	Modify the path (converting curves to line segments).

•	Convert the path into a clip path.

•	Convert the path into a region.

•	Flatten the path by converting each curve in the path into a series of line segments.

•	Retrieve the coordinates of the lines and curves that compose a path.


Outlined and Filled Paths

An application can draw the outline of a path by calling the StrokePath function, it can fill the interior of a path by calling the FillPath function, and it can both outline and fill the path by calling the StrokeAndFillPath function.

Whenever an application fills a path, Windows uses the DC's current fill mode. An application can retrieve this mode by calling the GetPolyFillMode function, and it can set a new fill mode by calling the SetPolyFillMode function. For a description of the two fill modes, see Regions.

The following illustration shows the cross-section of an object created by a computer-aided design (CAD) application using paths that were both outlined and filled.


Transformations of Paths

Paths are defined using logical units and current transformations. (If the SetWorldTransform function has been called, the logical units are world units; otherwise, the logical units are page units.) An application can use world transformations to scale, rotate, shear, translate, and reflect the lines and Bézier curves that define a path.

Note  A world transformation within a path bracket only affects those lines and curves drawn after the transformation was set. It will have no affect on those lines and curves that were drawn before it was set. For a description of the world transformation, see Coordinate Spaces and Transformations.

An application can also use SetWorldTransform to outline the shape of the pen used to outline a path if the pen is a geometric pen. For a description of geometric pens, see Pens.


Clip Paths and Graphic Effects

An application can use clipping and paths to create special graphic effects. The following illustration shows a string of text drawn with a large Arial font.

The next illustration shows the result of selecting the text as a clip path and drawing radial lines for a circle whose center is located above and left of the string.

Note  Before graphics device interface (GDI) adds text created with a bitmapped font to a path, it converts the font to an outline or vector font.

An application creates a clip path by generating a path bracket and then calling the SelectClipPath function. After a clip path is selected into a DC, output only appears within the borders of the path.

In addition to creating special graphics effects, clip paths are also useful in applications that save images as enhanced metafiles. By using a clip path, an application is able to ensure device independence because the units used to specify a path are logical units (as opposed to device units that are used to specify a region).


Conversion of Paths to Regions

An application can convert a path into a region by calling the PathToRegion function. Like SelectClipPath, PathToRegion is useful in the creation of special graphics effects. For example, there are no functions that allow an application to offset a path; however, there is a function that enables an application to offset a region (OffsetRgn). Using PathToRegion, an application can create the effect of animating a complex shape by creating a path that defines the shape, converting the path into a region (by calling PathToRegion), and then repeatedly painting, moving, and erasing the region (by calling functions in a sequence, such as FillRgn, OffsetRgn, and FillRgn).


Curved Paths

An application can flatten the curves in a path by calling the FlattenPath function. This function is especially useful for applications that fit text onto the contour of a path which contains curves. To fit the text, the application must perform the following steps:

1.	Create the path where the text appears.

2.	Call the FlattenPath function to convert the curves in a path into line segments.

3.	Call the GetPath function to retrieve those line segments.

4.	Calculate the length of each line and the width of each character in the string.

5.	Use line-width and character-width data to position each character along the curve.


Using Paths

This section contains a code sample that enables the user to select a font of a particular point size (by using the Choose Font dialog box), select a clip path (by using text drawn with this font), and then view the result of clipping to the text.

This code sample was used to create the illustration that appears in Clip Paths.

CHOOSEFONT cf;          /* common dialog box font structure */

LOGFONT lf;             /* logical font structure */

HFONT hfont;            /* new logical font handle */

HFONT hfontOld;         /* original logical font handle */

HDC hdc;                /* display DC handle */

int nXStart, nYStart;   /* drawing coordinates */

RECT rc;                /* rect structure for painting window */

SIZE sz;                /* structure that receives text extents */

double aflSin[90];      /* sine of 0-90 degrees */

double aflCos[90];      /* cosine of 0-90 degrees */

double flRadius,a;      /* radius of circle */

int iMode;              /* clipping mode */

HRGN hrgn;              /* clip region handle */

LRESULT APIENTRY MainWndProc(

    HWND hwnd,                /* window handle                   */

    UINT message,             /* type of message                 */

    WPARAM wParam,            /* additional information          */

    LPARAM lParam)            /* additional information          */

{

    PAINTSTRUCT ps;

    switch (message) {

        case WM_PAINT:

            hdc = BeginPaint(hwnd, &ps);

            EndPaint(hwnd, &ps);

            break;

        case WM_COMMAND:     /* command from app's menu */

            switch (wParam) {

                case IDM_VANISH:  /* erases client area */

                    hdc = GetDC(hwnd);

                    GetClientRect(hwnd, &rc);

                    FillRect(hdc, &rc, GetStockObject(WHITE_BRUSH));

                    ReleaseDC(hwnd, hdc);

                    break;

                case IDM_AND: /* sets clip mode to RGN_AND */

                    iMode = RGN_AND;

                    break;

                case IDM_COPY: /* sets clip mode to RGN_COPY */

                    iMode = RGN_COPY;

                    break;

                case IDM_DIFF: /* sets clip mode to RGN_DIFF */

                    iMode = RGN_DIFF;

                    break;

                case IDM_OR: /* sets clip mode to RGN_OR */

                    iMode = RGN_OR;

                    break;

                case IDM_XOR: /* sets clip mode to RGN_XOR */

                    iMode = RGN_XOR;

                    break;

                case IDM_CLIP_PATH:

                    /* Retrieve a cached DC for the window. */

                    hdc = GetDC(hwnd);

                    /*

                     * Use the font requested by the user in the

                     * Choose Font dialog box to create a logical font,

                     * then select that font into the device context.

                     */

                    hfont = CreateFontIndirect(cf.lpLogFont);

                    hfontOld = SelectObject(hdc, hfont);

                    /*

                     * Retrieve the dimensions of the rectangle

                     * that surrounds the text.

                     */

                     GetTextExtentPoint32(hdc, "Clip Path", 9, &sz);

                    /*

                     * Set a clipping region using the rect that

                     * surrounds the text.

                     */

                     hrgn = CreateRectRgn(nXStart, nYStart,

                         nXStart + sz.cx,

                         nYStart + sz.cy);

                     SelectClipRgn(hdc, hrgn);

                    /*

                     * Create a clip path using text drawn with

                     * the user's requested font.

                     */

                    BeginPath(hdc);

                        TextOut(hdc, nXStart, nYStart, "Clip Path", 9);

                    EndPath(hdc);

                    SelectClipPath(hdc, iMode);

                    /* Compute the sine of 0, 1, ... 90 degrees. */

                    for (i = 0; i < 90; i++) {

                        aflSin[i] = sin( (((double)i) / 180.0)

                                    * 3.14159);

                        }

                    /* Compute the cosine of 0, 1,... 90 degrees. */

                    for (i = 0; i < 90; i++) {

                        aflCos[i] = cos( (((double)i) / 180.0)

                                    * 3.14159);

                        }

                    /* Set the radius value. */

                    flRadius = (double)(2 * sz.cx);

                    /*

                     * Draw the 90 rays extending from the

                     * radius to the edge of the circle.

                     */

                    for (i = 0; i < 90; i++) {

                        MoveToEx(hdc, nXStart, nYStart,

                           (LPPOINT) NULL);

                        LineTo(hdc, nXStart + ((int) (flRadius

                            * aflCos[i])),

                               nYStart + ((int) (flRadius

                            * aflSin[i])));

                        }

                    /* Reselect the original font into the DC. */

                     SelectObject(hdc, hfontOld);

                    /* Delete the user's font. */

                     DeleteObject(hfont);

                    /* Release the DC. */

                    ReleaseDC(hwnd, hdc);

                    break;

                case IDM_FONT:

                    /* Initialize necessary members. */

                    cf.lStructSize = sizeof (CHOOSEFONT);

                    cf.hwndOwner = hwnd;

                    cf.lpLogFont = &lf;

                    cf.Flags = CF_SCREENFONTS | CF_EFFECTS;

                    cf.rgbColors = RGB(0, 255, 255);

                    cf.nFontType = SCREEN_FONTTYPE;

                    /*

                     * Display the Font dialog box, allow the user

                     * to choose a font, and render text in the

                     * window with that selection.

                     */

                    if (ChooseFont(&cf)) {

                        hdc = GetDC(hwnd);

                        hfont = CreateFontIndirect(cf.lpLogFont);

                        hfontOld = SelectObject(hdc, hfont);

                        crOld = SetTextColor(hdc, cf.rgbColors);

                        TextOut(hdc, nXStart, nYStart,

                            "Clip Path", 9);

                        SetTextColor(hdc, crOld);

                        SelectObject(hdc, hfontOld);

                        DeleteObject(hfont);

                        ReleaseDC(hwnd, hdc);

                    }

                    break;

                default:

                    return DefWindowProc(hwnd, message, wParam,

                         lParam);

            }

            break;

        case WM_DESTROY:    /* window is being destroyed    */

            PostQuitMessage(0);

            break;

        default:                 /* if unprocessed...      */

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

    }

    return 0;

}


Path Functions

Use the following functions to create, alter, or draw paths.

AbortPath
BeginPath
CloseFigure
EndPath
FillPath
FlattenPath
GetMiterLimit
GetPath
PathToRegion
SetMiterLimit
StrokeAndFillPath
StrokePath
WidenPath


Pens

A pen is a graphics tool that an application for Microsoft® Windows® uses to draw lines and curves. Drawing applications use pens to draw freehand lines, straight lines, and curves. Computer-aided design (CAD) applications use pens to draw visible lines, hidden lines, section lines, center lines, and so on. Word processing and desktop publishing applications use pens to draw borders and rules. Spreadsheet applications use pens to designate trends in graphs and to outline bar graphs and pie charts.


About Pens

There are two types of pen: cosmetic and geometric. A cosmetic pen is used with applications requiring lines of fixed width and lines that are quickly drawn. A CAD application, for example, uses a cosmetic pen to generate hidden, section, center, and dimension lines that are between .015 and .022 inches wide — regardless of the scale factor. A geometric pen is used with applications requiring scalable lines, lines with unique end or join styles, and lines that are wider than a single pixel. A spreadsheet application, for example, uses a geometric pen to define each of the bars in a bar graph as a wide line.


Cosmetic Pens

The dimensions of a cosmetic pen are specified in device units. Therefore, lines drawn with a cosmetic pen always have a fixed width. Lines drawn with a cosmetic pen are generally drawn three to ten times faster than lines drawn with a geometric pen. Cosmetic pens have three attributes: width, style, and color. For more information about these attributes, see Pen Attributes.

To create a cosmetic pen, an application uses the CreatePen, CreatePenIndirect, or ExtCreatePen function. To retrieve one of the three stock cosmetic pens managed by window manager, the application uses the GetStockObject function.

After a pen is created (or a handle identifying one of the stock pens is obtained), the pen is selected into the application's device context (DC) by calling the SelectObject function. From this point on, the application uses this pen for any line-drawing operations in its client area.


Geometric Pens

The dimensions of a geometric pen are specified in logical units. Therefore, lines drawn with a geometric pen can be scaled — that is, they may appear wider or narrower, depending on the current world transformation. For more information about the world transformation, see Coordinate Spaces and Transformations.

In addition to the three attributes shared with cosmetic pens (width, style, and color), geometric pens possess the following four attributes: pattern, optional hatch, end style, and join style. For more information about these attributes, see Pen Attributes.

To create a geometric pen, an application uses the ExtCreatePen function. As with cosmetic pens, the SelectObject function selects a geometric pen into the application's DC.


Pen Attributes

There are seven pen attributes that define the type of pen and its characteristics: width, style, color, pattern, hatch, end style, and join style. Both cosmetic and geometric pens have the width, style, and color attributes. Only geometric pens have the pattern, hatch, end style, and join style attributes. The pattern and optional hatch attribute are usually associated with a brush, but can also be used with geometric pens.


Width

The width attribute specifies a cosmetic pen width in device units. When used with a geometric pen, however, it specifies the pen's width in logical units. For more information about device units, see Coordinate Spaces and Transformations.

Currently, Windows limits the width of cosmetic pens to a single pixel; however, future versions may remove this limitation.


Style

The style attribute specifies the line pattern that appears when a particular cosmetic or geometric pen is used. There are eight predefined pen styles. The following illustration shows the seven of these styles that are defined by Windows.

The inside-frame style is identical to the solid style for cosmetic pens. However, it operates differently when used with a geometric pen. If the geometric pen is wider than a single pixel and a drawing function uses the pen to draw a border around a filled object, Windows draws the border inside the object's frame. By using the inside-frame style, an application can ensure that an object appears entirely within the specified dimensions, regardless of the geometric pen width.

In addition to the seven styles defined by Windows, there is an eighth style that is user (or application) defined. A user-defined style generates lines with a customized series of dashes and dots.

Use the CreatePen, CreatePenIndirect, or ExtCreatePen function to create a pen that has the Windows-defined styles. Use the ExtCreatePen function to create a pen that has a user-defined style.


Color

The color attribute specifies the pen's color. An application can create a cosmetic pen with a unique color by storing the red, green, blue (RGB) triplet that specifies the desired color in a COLORREF structure and passing this structure's address to the CreatePen, CreatePenIndirect, or ExtCreatePen function. (The stock pens are limited to black, white, and invisible.) For more information about RGB triplets and color, see Colors.


Pattern

The pattern attribute specifies the pattern of a geometric pen.

The following illustration shows lines drawn with different geometric pens. Each pen was created using a different pattern attribute.

The first line in the previous illustration is drawn using one of the six available hatch patterns; for more information about hatch patterns, see Hatch. The next line is drawn using the hollow pattern, identical to the null pattern. The third line is drawn using a custom pattern created from an 8- by 8-pixel bitmap. (For more information about bitmaps and their creation, see Bitmaps.) The last line is drawn using a solid pattern. Creating a brush and passing its handle to the ExtCreatePen function creates a pattern.


Hatch

The hatch attribute specifies the hatch type of a geometric pen with the hatch pattern attribute. There are six patterns available. The following illustration shows lines drawn using different hatch patterns.


End Cap

The end cap attribute specifies the shape of a geometric pen: round, square, or flat. The following illustration shows parallel lines drawn using each type of end cap.

The round and square end caps extend past the starting and ending points of a line drawn with a geometric pen; the flat end cap does not.


Join

The join attribute specifies how the ends of two geometric lines are joined: beveled, mitered, or round. The following illustration shows pairs of connected lines drawn using each type of join.


Using Pens

This section contains sample code that demonstrates the appearance of lines drawn using various pen styles and attributes.

LRESULT CALLBACK MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam,

                             LPARAM lParam)

{

    PAINTSTRUCT ps;

    LOGBRUSH lb;

    RECT rc;

    HDC hdc;

    int i;

    HPEN hPen, hPenOld;

    DWORD dwPenStyle[] = {

                           PS_DASH,

                           PS_DASHDOT,

                           PS_DOT,

                           PS_INSIDEFRAME,

                           PS_NULL,

                           PS_SOLID

                        };

    UINT uHatch[] = {

                      HS_BDIAGONAL,

                      HS_CROSS,

                      HS_DIAGCROSS,

                      HS_FDIAGONAL,

                      HS_HORIZONTAL,

                      HS_VERTICAL

                     };

    switch (uMsg)

    {

        case WM_PAINT:

        {

            GetClientRect(hWnd, &rc);

            rc.left += 10;

            rc.top += 10;

            rc.bottom -= 10;

            /* Initialize the pen's "brush." */

            lb.lbStyle = BS_SOLID;

            lb.lbColor = RGB(255,0,0);

            lb.lbHatch = 0;

            hdc = BeginPaint(hWnd, &ps);

            for (i = 0; i < 6; i++)

            {

                hPen = ExtCreatePen(PS_COSMETIC | dwPenStyle[i],

                                    1, &lb, 0, NULL);

                hPenOld = SelectObject(hdc, hPen);

                MoveToEx(hdc, rc.left + (i * 20), rc.top, NULL);

                LineTo(hdc, rc.left + (i * 20), rc.bottom);

                SelectObject(hdc, hPenOld);

                DeleteObject(hPen);

            }

            rc.left += 150;

            for (i = 0; i < 6; i++)

            {

                lb.lbStyle = BS_HATCHED;

                lb.lbColor = RGB(0,0,255);

                lb.lbHatch = uHatch[i];

                hPen = ExtCreatePen(PS_GEOMETRIC,

                                    5, &lb, 0, NULL);

                hPenOld = SelectObject(hdc, hPen);

                MoveToEx(hdc, rc.left + (i * 20), rc.top, NULL);

                LineTo(hdc, rc.left + (i * 20), rc.bottom);

                SelectObject(hdc, hPenOld);

                DeleteObject(hPen);

            }

            EndPaint(hWnd, &ps);

        }

        break;

        case WM_DESTROY:

            DeleteObject(hPen);

            PostQuitMessage(0);

            break;

        default:

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

    }

    return FALSE;

}


Pen Functions

Following are the functions that support the pen interface.

CreatePen
CreatePenIndirect
ExtCreatePen


Printing and Print Spooler

Microsoft® Windows® provides a complete set of functions that allow applications to print on a variety of devices: laser printers, vector plotters, raster printers, and fax machines.


About Printing

One of the chief features of Windows printing functions is their support of device independence; instead of issuing device-specific commands to draw output on a particular printer or plotter, an application calls high-level functions from graphics device interface (GDI). For example, to print a bitmapped image, an application can call the BitBlt function, supplying the coordinates for the bitmap as well as handles identifying the source and destination device contexts (DCs). The call to BitBlt is then converted to raw device commands by a printer device driver. A device driver is a Windows dynamic-link library (DLL) that supports the Windows device driver interface (DDI). A device driver generates raw device commands when it processes calls to DDI functions made by the graphics engine. The commands are processed by the printer when it prints the image. The syntax, number, and type of these commands vary from device to device.


Default Printing Interface

In addition to GDI and the device driver, the default printing interface consists of several other components that process output before it arrives at the printer. These components are the print spooler, the print processor, the graphics engine, and the monitor.


Print Spooler

The primary component of the printing interface is the print spooler. The print spooler is a Windows executable file that manages the printing process. Management of printing involves retrieving the location of the correct printer driver, loading that driver, converting high-level function calls to journal records, storing those journal records on disk as a print job, and so on.

The spooler is loaded at startup and continues to run until the operating system is shut down. Windows Print Manager provides a graphical interface that the user or system administrator can use to access and configure the spooler; however, if Print Manager is disabled or shut down, the spooler continues to run.

Applications that print create a printer DC. When an application creates a printer DC, the spooler performs necessary tasks such as determining the location of the required printer driver and then loading the appropriate printer driver. It also determines the data type used to record the print job. The supported data types include journal records, ASCII text, and PostScript®. A print job is a document stored internally (by using one of the supported data types) that may contain one or more pages of output. It may consist of multiple forms; for example, a job may consist of one envelope and three pages of A4 paper. A print job is defined (or bracketed) by the StartDoc and EndDoc functions.

The default data type for a print job is the journal record. A journal record is a compact structure used to store text output commands, raster graphics commands, and so on. When an application calls StartDoc, the spooler creates a journal file and a data file and begins storing journal records in the journal file. Each time the application calls one of the GDI drawing functions, one or more new journal records are created and stored in the journal file. The journal and data files are created in an operating system directory. The spooler uses the journal file to store journal records and uses the data file to record the type of form, the data type for the print job, the target printer, and so on. These files are deleted by the spooler when the job has successfully printed.


Print Processor

The spooler monitors the current print jobs and the target printer to determine an appropriate time to print a job. Once the spooler determines that a job should be printed, it calls the print processor. The print processor is a Windows DLL that reads and converts journal records into DDI calls.


Graphics Engine

The graphics engine is a Windows DLL that converts print processor output into calls to device driver functions. The device driver, in turn, processes these calls and converts them into raw device commands that the device can process.


Monitor

Once a device driver has converted an entire journal file into raw device commands, the file of converted commands is passed back to the spooler. The spooler sends these low-level commands to a monitor. A monitor is a Windows DLL that passes the raw device commands over the network, through a parallel port, or through a serial port to the device.


Printer Device Contexts Overview

Just as an application requires a display DC before it can begin drawing in the client area of a window, it needs a special printer DC before it can begin sending output to a printer. A printer DC is similar to a display DC in that it is an internal data structure that defines a set of graphic objects and their associated attributes and specifies the graphic modes that affect output. The graphic objects include a pen (for line drawing), a brush (for painting and filling), and a font (for text output).

Unlike a display DC, printer DCs are not owned by the window management component, and they cannot be obtained by calling the GetDC function. Instead, an application must call the CreateDC or PrintDlg function. When an application calls CreateDC, it must supply a driver and port name. This data is stored in one of the operating system initialization (.INI) files. It can be retrieved by calling the EnumPrinters function.

When an application calls PrintDlg and specifies the PD_RETURNDC value in the Flags member of the PRINTDLG structure, Windows automatically returns a handle identifying the user's selected printer DC. For an example that demonstrates this task, see Using a Print Dialog Box and Retrieving a Printer Device Context.


Printer Escapes

Windows version 3.x supported as many as 64 special functions called printer escapes that applications used to access special device features. An application called these functions by specifying one of 64 predefined values as the second parameter to the Escape function. For example, one of these applications printing on a PostScript printer could draw a PostScript graphic object called a path by calling the Escape function and supplying the BEGIN_PATH and END_PATH values. Most of these escapes are obsolete in the Microsoft® Win32® application programming interface (API) but are provided to simplify the porting of 16-bit Windows-based applications. The Win32 version of GDI supports a complete set of path functions that applications can use instead of the escapes to draw paths on any device. For a list of the Win32 functions that replace some of the escapes, see the Escape function.

Of the 64 original printer escapes, only the QUERYESCSUPPORT and the PASSTHROUGH escapes can be used by Win32-based applications:

Applications written for Windows 3.x can also use QUERYESCSUPPORT and PASSTHROUGH as well as the following 10 escapes. Note that the following escapes are only supported for backwards compatibility with Windows 3.x-based applications. The Escape function may fail if a Win32-based application uses any of these.

•	ABORTDOC

•	ENDDOC

•	GETPHYSPAGESIZE

•	GETPRINTINGOFFSET

•	GETSCALINGFACTOR

•	NEWFRAME

•	NEXTBAND

•	SETABORTPROC

•	SETCOPYCOUNT

•	STARTDOC

In addition to supporting Escape, the Win32 API provides a new extended escape function called ExtEscape. This function allows applications to access capabilities of a particular device not directly available through GDI.


WYSIWYG Display and Output

Most applications attempt to support WYSIWYG (what you see is what you get) output. This means that text drawn with a 10-point Helvetica bold font in the application window should have a similar appearance when it is printed. Obtaining true WYSIWYG output is virtually impossible and even undesirable in most cases. This is due, in part, to the differences in video and printer technologies; a pixel on a screen is generally larger than a dot on a common laser printer. Viewing distances are different as well; a computer user typically sits about two feet away from the screen, but a reader's eyes are usually one foot or less from the printed page.

To compensate for legibility differences between screens and the printed page, Windows supports a unit called the logical inch that is always specified in pixels. For a video display, the logical inch is always greater than the physical inch to compensate for the longer viewing distance and the (generally) coarser resolution. For printers, the logical inch is always equal to the physical inch.

To obtain a WYSIWYG effect when drawing text, an application can use the CreateFont function to specify the typeface name and point size of an ideal (or logical) font and then call the SelectObject function to identify the display or printer DC. When the application calls SelectObject, Windows selects a physical font that is the closest possible match to the specified logical font. When Windows selects the display font, it chooses a physical font that is larger than the actual point size. From the user's perspective, however, it appears to be very close to the correct height. When Windows selects the font for the printer, it chooses a physical font that is actually the requested point size. For more information about fonts and text output, see Fonts and Text.

To obtain a WYSIWYG effect when drawing bitmapped graphics, an application can retrieve the width and height, in logical inches, of the screen and the printed page. Using these values, the application can create horizontal and vertical scaling factors to maintain the proportion of bitmapped images when they are drawn on a printer. For an example that demonstrates this process, see WYSIWYG Display and Output. For more information about bitmaps and bitmap output, see Bitmaps.


Using the Printing Functions

This section contains examples that demonstrate how to print text and graphics. The code was taken from an application that allows a user to open and display a 16-color bitmapped image that is stored as a .BMP file.

In addition to displaying the bitmapped image, the application allows the user to configure the printer and then print the image and a string of text specifying the location of the file that contained the image. The application prints the text at the top of the page and the image in the center of the page.

•	Opening and displaying a .BMP file

•	Using a print dialog box and retrieving a printer device context

•	Preparing to print

•	Printing a document


Opening and Displaying a .BMP File

In the sample application, a user is able to open a .BMP file that contains a bitmapped image and display that image in the client area of the application's window. The user selects the file to be opened when the application displays the Open dialog box. (For more information about the Open dialog box, see Common Dialog Box Library.)

After the user selects a file and closes the dialog box, the file and path names are stored in members of the OPENFILENAME structure. The application uses this data to open the appropriate file and retrieve the bitmap header and data. The following code sample can be used to retrieve this data.

 /* Retrieve a handle identifying the file. */

 hfbm = CreateFile(ofn.lpstrFile, GENERIC_READ,

        FILE_SHARE_READ, (LPSECURITY_ATTRIBUTES) NULL,

        OPEN_EXISTING, FILE_ATTRIBUTE_READONLY,

        (HANDLE) NULL);

 /* Retrieve the BITMAPFILEHEADER structure. */

 ReadFile(hfbm, &bmfh, sizeof(BITMAPFILEHEADER),

     &dwRead, (LPOVERLAPPED)NULL);

 /* Retrieve the BITMAPFILEHEADER structure. */

 ReadFile(hfbm, &bmih, sizeof(BITMAPINFOHEADER),

     &dwRead, (LPOVERLAPPED)NULL);

 /* Allocate memory for the BITMAPINFO structure. */

 hmem1 = GlobalAlloc(GHND,

     sizeof(BITMAPINFOHEADER) +

     ((1<<bmih.biBitCount) * sizeof(RGBQUAD)));

 lpbmi = GlobalLock(hmem1);

 /*

  * Load BITMAPINFOHEADER into the BITMAPINFO

  * structure.

  */

 lpbmi->bmiHeader.biSize = bmih.biSize;

 lpbmi->bmiHeader.biWidth = bmih.biWidth;

 lpbmi->bmiHeader.biHeight = bmih.biHeight;

 lpbmi->bmiHeader.biPlanes = bmih.biPlanes;

 lpbmi->bmiHeader.biBitCount = bmih.biBitCount;

 lpbmi->bmiHeader.biCompression = bmih.biCompression;

 lpbmi->bmiHeader.biSizeImage = bmih.biSizeImage;

 lpbmi->bmiHeader.biXPelsPerMeter = bmih.biXPelsPerMeter;

 lpbmi->bmiHeader.biYPelsPerMeter = bmih.biYPelsPerMeter;

 lpbmi->bmiHeader.biClrUsed = bmih.biClrUsed;

 lpbmi->bmiHeader.biClrImportant = bmih.biClrImportant;

 /*

  * Retrieve the color table.

  * 1 << bmih.biBitCount == 2 ^ bmih.biBitCount

  */

 ReadFile(hfbm, lpbmi->bmiColors,

     ((1<<bmih.biBitCount) * sizeof(RGBQUAD)),

     &dwRead, (LPOVERLAPPED) NULL);

 /*

  * Allocate memory for the required number of

  * bytes.

  */

 hmem2 = GlobalAlloc(GHND,

     (bmfh.bfSize - bmfh.bfOffBits));

 lpvBits = GlobalLock(hmem2);

 /* Retrieve the bitmap data. */

 ReadFile(hfbm, lpvBits,

     (bmfh.bfSize - bmfh.bfOffBits),

     &dwRead, (LPOVERLAPPED) NULL);

 /*

  * Create a bitmap from the data stored in the

  * .BMP file.

  */

 hbm = CreateDIBitmap(hdc, &bmih,

     CBM_INIT, lpvBits,

     lpbmi, DIB_RGB_COLORS);

/*

 * Unlock the global memory objects and

 * close the .BMP file.

 */

 GlobalUnlock(hmem1);

 GlobalUnlock(hmem2);

 CloseHandle(hfbm);

 /* Set the fDisplayBitmap flag. */

 if (hbm)

     fDisplayBitmap = TRUE;

 else

     TextOut(hdc, 100, 100, "LoadBitmap Failed", 17);

 /* Paint the window (and draw the bitmap). */

 GetClientRect(hwnd, &rect);

 InvalidateRect(hwnd, &rect, TRUE);

 UpdateWindow(hwnd);

Once the bitmap data is retrieved, the bitmapped image can be drawn in the application's client area. The following code sample is used to draw the bitmap.

case WM_PAINT:

    BeginPaint(hwnd, &ps);

        if (fDisplayBitmap) {

            hdcMem = CreateCompatibleDC(ps.hdc);

            SelectObject(hdcMem, hbm);

            GetObject(hbm, sizeof(BITMAP), (LPSTR) &bm);

            BitBlt(ps.hdc, 0, 0, bm.bmWidth, bm.bmHeight,

                hdcMem, 0, 0, SRCCOPY);

            DeleteDC(hdcMem);

        }

    EndPaint(hwnd, &ps);

    break;


Using a Print Dialog Box and Retrieving a Printer Device Context

The first step in printing involves setting up the printer and obtaining a printer DC. In the sample application, the File menu contains two options, Print and Print Setup. By selecting either option, the user can configure the printer. When the user selects the Print Setup option, the Print Setup dialog box is displayed and the user can select a printer, a page orientation, a paper size, and so on. When the user selects the Print option, the Print dialog box is displayed and the user can select a range of pages, a print quality, a number of copies, and so on. The user can also display the Print Setup dialog box by clicking the Setup push button.

The Print and Print Setup dialog boxes are both displayed by initializing the members of a PRINTDLG structure and calling the PrintDlg function. (For more information about displaying the Print Setup dialog box, see Common Dialog Box Library). In addition to retrieving user-specified data, PrintDlg can be used to obtain a printer DC by specifying the PD_RETURNDC value in the Flags member of the PRINTDLG structure. The following code sample shows how to intialize the members of the structure and to display the Print dialog box.

/* Initialize the PRINTDLG members. */

pd.lStructSize = sizeof(PRINTDLG);

pd.hDevMode = (HANDLE) NULL;

pd.hDevNames = (HANDLE) NULL;

pd.Flags = PD_RETURNDC;

pd.hwndOwner = hwnd;

pd.hDC = (HDC) NULL;

pd.nFromPage = 1;

pd.nToPage = 1;

pd.nMinPage = 0;

pd.nMaxPage = 0;

pd.nCopies = 1;

pd.hInstance = (HANDLE) NULL;

pd.lCustData = 0L;

pd.lpfnPrintHook = (LPPRINTHOOKPROC) NULL;

pd.lpfnSetupHook = (LPSETUPHOOKPROC) NULL;

pd.lpPrintTemplateName = (LPSTR) NULL;

pd.lpSetupTemplateName = (LPSTR)  NULL;

pd.hPrintTemplate = (HANDLE) NULL;

pd.hSetupTemplate = (HANDLE) NULL;

/* Display the PRINT dialog box. */

PrintDlg(&pd);


Preparing to Print

The following code sample determines whether the selected printer is capable of printing bitmaps by calling the GetDeviceCaps function, supplying the RASTERCAPS value. By examining this function's return value, the application can determine whether it should print a document or inform the user that the device does not support raster output.

/*

 * Examine the raster capabilities of the device

 * identified by pd.hDC to verify that it supports

 * the BitBlt function.

 */

if (!(GetDeviceCaps(pd.hDC, RASTERCAPS)

    & RC_BITBLT)) {

    DeleteDC(pd.hDC);

    MessageBox(hwnd,

        "Printer cannot display bitmaps.",

        "Device Error",

        MB_OK);

    break;

}

After the sample application determines that the selected printer is capable of printing bitmaps, it follows these steps:

1.	Sets a Boolean flag that the application's abort procedure can examine to determine whether to allow printing to continue.

2.	Registers the application's AbortProc function, which is used to cancel a print job.

3.	Displays a modeless Cancel dialog box.

4.	Disables the application's window while the dialog box is displayed.

The steps are illustrated in the following code sample.

/*

 * Set the flag used by the AbortPrintJob

 * dialog procedure.

 */

 bPrint = TRUE;

/*

 * Register the application's AbortProc

 * function with GDI.

 */

 SetAbortProc(pd.hDC, AbortProc);

/* Display the modeless Cancel dialog box. */

 hdlgCancel = CreateDialog(hinst, (LPTSTR) "AbortDlg",

    hwnd, (DLGPROC) AbortPrintJob);

/* Disable the application's window. */

 EnableWindow(hwnd, FALSE);

Once the application registers AbortProc with Windows, GDI calls the function repeatedly during the printing process to determine whether to cancel a job. In the current version of the Win32 API, GDI calls this function approximately every two seconds until the entire job has been spooled.

If the user chooses to cancel the job, GDI notifies the spooler that it should delete the corresponding journal file from the print queue and reset the printer to its default state.


Abort Procedure

Any application written for Windows that supports printing should provide an abort procedure and a modeless dialog box that allow a user to cancel a print job. The abort procedure for the sample application contains a message loop that retrieves messages for the modeless dialog box.

BOOL CALLBACK AbortProc(HDC hdc, int nCode)

{

    MSG msg;

    /*

     * Retrieve and remove messages from the thread's message

     * queue.

     */

    while (PeekMessage((LPMSG) &msg, (HWND) NULL,

            0, 0, PM_REMOVE)) {

        /* Process any messages for the Cancel dialog box. */

        if (!IsDialogMessage(hdlgCancel, (LPMSG) &msg)) {

            TranslateMessage((LPMSG) &msg);

            DispatchMessage((LPMSG) &msg);

         }

    }

    /*

     * Return the global bPrint flag (which is set to FALSE

     * if the user presses the Cancel button).

     */

     return bPrint;

}

For Win16-based applications, this procedure must be exported in the application's module-definition (.DEF) file.


Cancel Dialog Box

The Cancel dialog box typically contains a single push button that allows the user to cancel a print job. The following template for the Cancel dialog box was taken from the sample application's resource (.RES) file.

AbortDlg DIALOG LOADONCALL MOVEABLE DISCARDABLE 33, 32, 160, 70

CAPTION "Sample Printing App"

STYLE WS_BORDER | WS_CAPTION | WS_DLGFRAME | WS_VISIBLE |

      WS_POPUP | WS_SYSMENU

BEGIN

    CONTROL "Now Printing: ", IDD_TEXT, "static",

        SS_CENTER | WS_CHILD, 0, 10, 160, 8

    CONTROL "", IDD_FILE, "static",

        SS_CENTER | WS_CHILD, 0, 25, 160, 8

    CONTROL "Cancel", IDD_CANCEL, "button",

        BS_DEFPUSHBUTTON | WS_TABSTOP | WS_CHILD,

        60, 45, 45, 15

END

The code sample that follows shows the dialog box procedure for the application.

LRESULT CALLBACK AbortPrintJob(

        HWND hwndDlg,     /* window handle of dialog box     */

        UINT message,     /* type of message                 */

        WPARAM wParam,    /* message-specific information    */

        LPARAM lParam)    /* message-specific information    */

{

    switch (message) {

        case WM_INITDIALOG:  /* message: initialize dialog box  */

            /* Initialize the static text control. */

            SetDlgItemText(hwndDlg, IDD_FILE, ofn.lpstrFile);

            return TRUE;

        case WM_COMMAND:     /* message: received a command */

            /* User pressed "Cancel" button--stop print job. */

            MessageBox(hwndDlg, "Incoming", "WM_COMMAND", MB_OK);

            bPrint = FALSE;

            return TRUE;

        default:

            return FALSE;     /* didn't process a message   */

    }

        UNREFERENCED_PARAMETER(lParam);

        UNREFERENCED_PARAMETER(wParam);

        UNREFERENCED_PARAMETER(message);

}


Printing a Document

Once the application initializes the necessary variables, registers its AbortProc function, and displays its modeless Cancel dialog box, it can start the print job by calling the StartDoc function.

After the application begins a print job, it can define individual pages in the document by calling the StartPage and EndPage functions and embedding the appropriate calls to GDI drawing functions within this bracket. After the application has defined the last page, it can close the document and end the print job by calling the EndDoc function.

The following example shows the code required to print a string of text and a bitmapped image. The string of text, centered at the top of the page, identifies the path and filename for the file that contains the bitmapped image. The bitmapped image, centered vertically and horizontally on the page, is drawn so that the same proportions used to draw the image in the application's window are maintained.

                /*

                 * Initialize the members of a DOCINFO

                 * structure.

                 */

                 di.cbSize = sizeof(DOCINFO);

                 di.lpszDocName = "Bitmap Printing Test";

                 di.lpszOutput = (LPTSTR) NULL;

                 di.lpszDataType = (LPTSTR) NULL;

                 di.fwType = 0;

                /*

                 * Begin a print job by calling the StartDoc

                 * function.

                 */

                 nError = StartDoc(pd.hDC, &di);

                 if (nError == SP_ERROR) {

                     errhandler("StartDoc", hwnd);

                     goto Error;

                    }

                /*

                 * Inform the driver that the application is

                 * about to begin sending data.

                 */

                 nError = StartPage(pd.hDC);

                 if (nError <= 0) {

                     errhandler("StartPage", hwnd);

                     goto Error;

                    }

                /*

                 * Retrieve the number of pixels-per-logical-inch

                 * in the horizontal and vertical directions

                 * for the display upon which the bitmap

                 * was created.

                 */

                 fLogPelsX1 = (float) GetDeviceCaps(pd.hDC, LOGPIXELSX);

                 fLogPelsY1 = (float) GetDeviceCaps(pd.hDC, LOGPIXELSY);

                /*

                 * Retrieve the number of pixels-per-logical-inch

                 * in the horizontal and vertical directions

                 * for the printer upon which the bitmap

                 * will be printed.

                 */

                 fLogPelsX2 = (float) GetDeviceCaps(pd.hDC,

                     LOGPIXELSX);

                 fLogPelsY2 = (float) GetDeviceCaps(pd.hDC,

                     LOGPIXELSY);

                /*

                 * Determine the scaling factors required to

                 * print the bitmap and retain its original

                 * proportions.

                 */

                 if (fLogPelsX1 > fLogPelsX2)

                    fScaleX = (fLogPelsX1 / fLogPelsX2);

                 else

                    fScaleX = (fLogPelsX2 / fLogPelsX1);

                 if (fLogPelsY1 > fLogPelsY2)

                    fScaleY = (fLogPelsY1 / fLogPelsY2);

                 else

                    fScaleY = (fLogPelsY2 / fLogPelsY1);

                /*

                 * Compute the coordinate of the upper left

                 * corner of the centered bitmap.

                 */

                 cWidthPels = GetDeviceCaps(pd.hDC, HORZRES);

                 xLeft = ((cWidthPels / 2) -

                            ((int) (((float) bmih.biWidth)

                             * fScaleX)) / 2);

                 cHeightPels = GetDeviceCaps(pd.hDC, VERTRES);

                 yTop = ((cHeightPels / 2) -

                            ((int) (((float) bmih.biHeight)

                             * fScaleY)) / 2);

                /*

                 * Create a memory DC that is compatible with

                 * the printer and select the bitmap (which

                 * the user requested) into this DC.

                 */

                 hdcMem = CreateCompatibleDC(pd.hDC);

                 if (!SelectObject(hdcMem, hbm))

                    errhandler("SelectObject Failed", hwnd);

                /*

                 * Use the StretchBlt function to scale the

                 * bitmap and maintain its original proportions

                 * (that is, if the bitmap was square when it

                 * appeared in the application's client area,

                 * it should also appear square on the page).

                 */

                 if (!StretchBlt(pd.hDC, xLeft, yTop,

                         (int) ((float) bmih.biWidth * fScaleX),

                         (int) ((float) bmih.biHeight * fScaleY),

                         hdcMem, 0, 0,

                         bmih.biWidth, bmih.biHeight,

                         SRCCOPY))

                     errhandler("StretchBlt Failed", hwnd);

                /* Delete the memory DC. */

                 DeleteDC(hdcMem);

                /*

                 * Retrieve the width of the string that

                 * specifies the full path and filename for the

                 * file that contains the bitmap.

                 */

                 GetTextExtentPoint32(pd.hDC, ofn.lpstrFile,

                     ofn.nFileExtension + 3,

                     &szMetric);

                /*

                 * Compute the starting point for the

                 * text-output operation. The string will

                 * be centered horizontally and positioned

                 * three-lines down from the top of the page.

                 */

                 xLeft = ((cWidthPels / 2) - (szMetric.cx / 2));

                 yTop = (szMetric.cy * 3);

                /*

                 * Print the path and filename for the bitmap,

                 * centered at the top of the page.

                 */

                 TextOut(pd.hDC, xLeft, yTop, ofn.lpstrFile,

                     ofn.nFileExtension + 3);

                /*

                 * Determine whether the user has pressed

                 * the Cancel button in the AbortPrintJob

                 * dialog box; if the button has been pressed,

                 * call the AbortDoc function. Otherwise, inform

                 * the spooler that the page is complete.

                 */

                 nError = EndPage(pd.hDC);

                 if (nError <= 0) {

                    errhandler("EndPage", hwnd);

                    goto Error;

                 }

                /* Inform the driver that document has ended. */

                 nError = EndDoc(pd.hDC);

                 if (nError <= 0)

                    errhandler("EndDoc", hwnd);

Error:

                /* Enable the application's window. */

                EnableWindow(hwnd, TRUE);

                /* Remove the AbortPrintJob dialog box. */

                DestroyWindow(hdlgCancel);

                /* Delete the printer DC. */

                DeleteDC(pd.hDC);

Because the pixels on a screen typically have different dimensions than the dots on a printer, it is necessary to scale bitmapped images to obtain a WYSIWYG effect. This is done by obtaining horizontal and vertical scaling factors and then applying those factors to the width and height values passed to the StretchBlt function. In the sample application, the scaling factors were obtained by retrieving the horizontal and vertical logical-pixel count for the two devices. Once the scaling factors were obtained, they were used to adjust the bitmap width and height.

To center the bitmap on the page, the application first computed the width and height of the scaled bitmap. (The bitmap was scaled to maintain the original proportions of the image.) These values were divided by two and then subtracted from half of the width and height of the page. The result defines the coordinates of the upper left corner of the bitmap.

To center the text at the top of the page, the application called the GetTextExtentPoint32 function to retrieve the width and height of the string specifying the path names and filenames. Once these values were obtained, the application used the height to position the string three lines down the page and the width to position the string horizontally centered on the page.

The following illustration shows a representation of the page that appeared when the application printed the bitmapped image in the WINLOGO.BMP file. This illustration also depicts the variables used to position the text and to position and scale the bitmap.


Printing and Print Spooler Reference

The following functions, structures, and messages are associated with printing and the print spooler.


Printing and Print Spooler Functions

Following are the functions used to print.

AbortDoc
DeviceCapabilities
EndDoc
EndPage
Escape
ExtEscape
SetAbortProc
StartDoc
StartPage

Following are the functions used to access the print spooler.

AbortPrinter
AbortProc
AddForm
AddJob
AddMonitor
AddPort
AddPrinter
AddPrinterConnection
AddPrinterDriver
AddPrintProcessor
AddPrintProvidor
AdvancedDocumentProperties
ClosePrinter
ConfigurePort
ConnectToPrinterDlg
DeleteForm
DeleteMonitor
DeletePort
DeletePrinter
DeletePrinterConnection
DeletePrinterDriver
DeletePrintProcessor
DeletePrintProvidor
DocumentProperties
EndDocPrinter
EndPagePrinter
EnumForms
EnumJobs
EnumMonitors
EnumPorts
EnumPrinterDrivers
EnumPrinters
EnumPrintProcessorDataTypes
EnumPrintProcessors
FindClosePrinterChangeNotification
FindFirstPrinterChangeNotification
FindNextPrinterChangeNotification
FreePrinterNotifyInfo
GetForm
GetJob
GetPrinter
GetPrinterData
GetPrinterDriver
GetPrinterDriverDirectory
GetPrintProcessorDirectory
OpenPrinter
PrinterMessageBox
PrinterProperties
ReadPrinter
ResetPrinter
ScheduleJob
SetForm
SetJob
SetPrinter
SetPrinterData
StartDocPrinter
StartPagePrinter
WaitForPrinterChange
WritePrinter


Printing and Print Spooler Structures

The following structures are used with the print spooler:

DATATYPES_INFO_1
PRINTER_NOTIFY_OPTIONS
PRINTER_NOTIFY_OPTIONS_TYPE
PRINTER_NOTIFY_INFO
PRINTER_NOTIFY_INFO_DATA


Printing and Print Spooler Messages

Following is the message used with the print spooler.

WM_SPOOLERSTATUS


Regions

In Microsoft® Windows®, a region is a rectangle, polygon, or ellipse (or a combination of two or more of these shapes) that can be filled, painted, inverted, framed, and used to perform hit testing (testing for the cursor location).


About Regions

Following are three types of regions that have been filled and framed.


Region Creation and Selection

An application creates a region by calling a function associated with a specific shape. The following table shows the function(s) associated with each of the standard shapes.

Shape	Function
Rectangular region	CreateRectRgn, CreateRectRgnIndirect
Rectangular region with rounded corners	CreateRoundRectRgn
Elliptical region	CreateEllipticRgn, CreateEllipticRgnIndirect
Polygonal region	CreatePolygonRgn, CreatePolyPolygonRgn
Each region creation function returns a handle that identifies the new region. An application can use this handle to select the region into a device context by calling the SelectObject function and supplying this handle as the second argument. After a region is selected into a device context, the application can perform various operations on it.


Region Operations

Applications can combine regions, compare them, paint or invert their interiors, draw a frame around them, retrieve their dimensions, and test whether the cursor lies within their boundaries.


Combining

An application combines two regions by calling the CombineRgn function. Using this function, an application can combine the intersecting parts of two regions, all but the intersecting parts of two regions, the two original regions in their entirety, and so on. Following are five values that define the region combinations.

Value	Meaning
RGN_AND	The intersecting parts of two original regions define a new region.
RGN_COPY	A copy of the first (of the two original regions) defines a new region.
RGN_DIFF	The part of the first region that does not intersect the second defines a new region.
RGN_OR	The two original regions define a new region.
RGN_XOR	Those parts of the two original regions that do not overlap define a new region.
The following illustration shows the five possible combinations of a square and a circular region resulting from a call to CombineRgn.


Comparing

An application compares two regions to determine whether or not they are identical by calling the EqualRgn function. EqualRgn considers two regions identical if they are equal in size and shape.


Filling

An application fills the interior of a region by calling the FillRgn function and supplying a handle that identifies a specific brush. When an application calls FillRgn, Windows fills the region with the brush by using the current fill mode for the specified device context. There are two fill modes: alternate and winding. The application can set the fill mode for a device context by calling the SetPolyFillMode function. The application can retrieve the current fill mode for a device context by calling the GetPolyFillMode function.

The following illustration shows two identical regions: one filled using alternate mode and the other filled using winding mode.

Alternate Mode

To determine which pixels Windows highlights when alternate mode is specified, perform the following test:

1.	Select a pixel within the region's interior.

2.	Draw an imaginary ray, in the positive x-direction, from that pixel towards infinity.

3.	Each time the ray intersects a boundary line, increment a count value.

Windows highlights the pixel if the count value is an odd number.

Winding Mode

To determine which pixels Windows highlights when winding mode is specified, perform the following test:

1.	Determine the direction in which each boundary line is drawn.

2.	Select a pixel within the region's interior.

3.	Draw an imaginary ray, in the positive x-direction, from the pixel toward infinity.

4.	Each time the ray intersects a boundary line with a positive y-component, increment a count value. Each time the ray intersects a boundary line with a negative y-component, decrement the count value.

Windows highlights the pixel if the count value is nonzero.


Painting

An application fills the interior of a region by using the brush currently selected into a device context by the PaintRgn function. This function uses the current polygon fill modes (alternate and winding).


Inverting

An application inverts the colors that appear within a region by calling the InvertRgn function. On monochrome displays, InvertRgn makes white pixels black and black pixels white. On color screens, this inversion is dependent on the type of technology used to generate the colors for the screen.


Framing

An application draws a border around a region by calling the FrameRgn function and specifying the border width and brush pattern that Windows uses when drawing the frame.


Retrieving a Bounding Rectangle

An application retrieves the dimensions of a region's bounding rectangle by calling the GetRgnBox function. If the region is rectangular, GetRgnBox returns the dimensions of the region. If the region is elliptical, the function returns the dimensions of the smallest rectangle that can be drawn around the ellipse. The long sides of the rectangle are the same length as the ellipse's major axis, and the short sides of the rectangle are the same length as the ellipse's minor axis. If the region is polygonal, GetRgnBox returns the dimensions of the smallest rectangle that can be drawn around the entire polygon.


Moving

An application moves a region by calling the OffsetRgn function. The given offsets along the x-axis and y-axis determine the number of logical units to move left or right and up or down.


Hit Testing

An application performs hit testing on regions to determine the coordinates of the current cursor position. Then it passes these coordinates — as well as a handle identifying the region — to the PtInRegion function. The cursor coordinates can be retrieved by processing the various mouse messages, such as WM_LBUTTONDOWN, WM_LBUTTONUP, WM_RBUTTONDOWN, and WM_RBUTTONUP. The return value for PtInRegion indicates whether the cursor position is within the given region.


Using Regions

•	Using regions to clip output

•	Using regions to perform hit testing


Using Regions to Clip Output

This section contains a single example that demonstrates how you can use regions to enable the user to define how a part of client area output can appear. Regions used for this purpose are called clipping regions.

The example for this section is taken from a Windows-based application that enables a user to capture the entire desktop as a bitmap and then isolate and save a part of this image as a .BMP file.

By selecting the Define Clip Region option from the application's menu, the user is able to select a clipping region by clicking the left mouse button and dragging the mouse. As the user drags the mouse, the application draws a rectangle that corresponds to the new clipping region.

By selecting the Clip option, the user is able to redraw the isolated part of the image within the boundaries of the specified rectangle.


Defining the Clipping Region

When the user selects the Define Clip Region option, Windows issues a WM_COMMAND message. The wParam parameter of this message contains an application-defined constant, IDM_DEFINE, that indicates that the user selected this option from the menu. The application processes this input by setting a Boolean flag, fDefineRegion, as shown in the following code sample.

case WM_COMMAND:

    switch (wParam) {

case IDM_DEFINE:

    fDefineRegion = TRUE;

break;

After selecting the Define Clipping Region option, the user can begin drawing the rectangle by clicking and dragging the mouse while the cursor is in the application's client area.

When the user presses the left button, Windows issues a WM_LBUTTONDOWN message. The lParam parameter of this message contains the cursor coordinates, which correspond to the upper left corner of a rectangle used to define the clipping region. The application processes the WM_LBUTTONDOWN message, as follows.

/* These variables are required for clipping. */

static POINT ptUpperLeft;

static POINT ptLowerRight;

static POINT aptRect[5];

static POINT ptTmp;

static POINTS ptsTmp;

static BOOL fDefineRegion;

static BOOL fRegionExists;

static HRGN hrgn;

static RECT rctTmp;

int i;

switch (message) {

case WM_LBUTTONDOWN:

    if (fDefineRegion) {

        /* Retrieve the new upper left corner. */

        ptsTmp = MAKEPOINTS(lParam);

        ptUpperLeft.x = (LONG) ptsTmp.x;

        ptUpperLeft.y = (LONG) ptsTmp.y;

    }

    if (fRegionExists) {

        /* Erase the previous rectangle. */

        hdc = GetDC(hwnd);

        SetROP2(hdc, R2_NOTXORPEN);

        if (!Polyline(hdc, (CONST POINT *) aptRect, 5))

            errhandler("Polyline Failed", hwnd);

        ReleaseDC(hwnd, hdc);

        /* Clear the rectangle coordinates. */

        for (i = 0; i < 4; i++) {

               aptRect[i].x = 0;

               aptRect[i].y = 0;

        }

        /* Clear the temporary point structure. */

        ptTmp.x = 0;

        ptTmp.y = 0;

        /* Clear the lower right coordinates. */

        ptLowerRight.x = 0;

        ptLowerRight.y = 0;

        /* Reset the flag. */

        fRegionExists = FALSE;

        fDefineRegion = TRUE;

        /* Retrieve the new upper left corner. */

        ptsTmp = MAKEPOINTS(lParam);

        ptUpperLeft.x = (LONG) ptsTmp.x;

        ptUpperLeft.y = (LONG) ptsTmp.y;

    }

break;

As the user drags the mouse, Windows issues WM_MOUSEMOVE messages and stores the new cursor coordinates in the lParam parameter. Each time the application receives a new WM_MOUSEMOVE message, it erases the previous rectangle (if one exists) and draws the new rectangle by calling the Polyline function, passing it the coordinates of the four corners of the rectangle. The application performs the following tasks.

/* These variables are required for clipping. */

static POINT ptUpperLeft;

static POINT ptLowerRight;

static POINT aptRect[5];

static POINT ptTmp;

static POINTS ptsTmp;

static BOOL fDefineRegion;

static BOOL fRegionExists;

static HRGN hrgn;

static RECT rctTmp;

int i;

switch (message) {

case WM_MOUSEMOVE:

    if (wParam & MK_LBUTTON && fDefineRegion) {

        /* Get a window DC. */

        hdc = GetDC(hwnd);

        if (!SetROP2(hdc, R2_NOTXORPEN))

            errhandler("SetROP2 Failed", hwnd);

        /*

         * If previous mouse movement occurred, store the original

         * lower right corner coordinates in a temporary structure.

         */

        if (ptLowerRight.x) {

            ptTmp.x = ptLowerRight.x;

            ptTmp.y = ptLowerRight.y;

        }

        /*

         * Get the new coordinates of the clipping region's lower

         * right corner.

         */

        ptsTmp = MAKEPOINTS(lParam);

        ptLowerRight.x = (LONG) ptsTmp.x;

        ptLowerRight.y = (LONG) ptsTmp.y;

        /*

         * If previous mouse movement occurred, erase the original

         * rectangle.

         */

        if (ptTmp.x) {

            aptRect[0].x = ptUpperLeft.x;

            aptRect[0].y = ptUpperLeft.y;

            aptRect[1].x = ptTmp.x;

            aptRect[1].y = ptUpperLeft.y;

            aptRect[2].x = ptTmp.x;

            aptRect[2].y = ptTmp.y;

            aptRect[3].x = ptUpperLeft.x;

            aptRect[3].y = ptTmp.y;

            aptRect[4].x = aptRect[0].x;

            aptRect[4].y = aptRect[0].y;

            if (!Polyline(hdc, (CONST POINT *) aptRect, 5))

                errhandler("Polyline Failed", hwnd);

        }

        aptRect[0].x = ptUpperLeft.x;

        aptRect[0].y = ptUpperLeft.y;

        aptRect[1].x = ptLowerRight.x;

        aptRect[1].y = ptUpperLeft.y;

        aptRect[2].x = ptLowerRight.x;

        aptRect[2].y = ptLowerRight.y;

        aptRect[3].x = ptUpperLeft.x;

        aptRect[3].y = ptLowerRight.y;

        aptRect[4].x = aptRect[0].x;

        aptRect[4].y = aptRect[0].y;

        if (!Polyline(hdc, (CONST POINT *) aptRect, 5))

             errhandler("Polyline Failed", hwnd);

        ReleaseDC(hwnd, hdc);

    }

    break;


Clipping Output

After the user chooses the Clip option from the menu, the application uses the coordinates of the rectangle the user created to define a clipping region. After defining the clipping region and selecting it into the application's device context, the application redraws the bitmapped image. The application performs these tasks, as follows.

/* These variables are required for clipping. */

static POINT ptUpperLeft;

static POINT ptLowerRight;

static POINT aptRect[5];

static POINT ptTmp;

static POINTS ptsTmp;

static BOOL fDefineRegion;

static BOOL fRegionExists;

static HRGN hrgn;

static RECT rctTmp;

int i;

case WM_COMMAND:

    switch (wParam) {

case IDM_CLIP:

    hdc = GetDC(hwnd);

    /*

     * Retrieve the application's client rectangle and paint

     * with the default (white) brush.

     */

    GetClientRect(hwnd, &rctTmp);

    FillRect(hdc, &rctTmp, GetStockObject(WHITE_BRUSH));

    /* Use the rect coordinates to define a clipping region. */

    hrgn = CreateRectRgn(aptRect[0].x, aptRect[0].y,

        aptRect[2].x, aptRect[2].y);

    SelectClipRgn(hdc, hrgn);

    /* Transfer (draw) the bitmap into the clipped rectangle. */

    BitBlt(hdc,

       0, 0,

       bmp.bmWidth, bmp.bmHeight,

       hdcCompatible,

       0, 0,

       SRCCOPY);

    ReleaseDC(hwnd, hdc);

break;


Using Regions to Perform Hit Testing

The example in Brushes uses regions to simulate a "zoomed" view of an 8- by 8-pixel monochrome bitmap. By clicking on the pixels in this bitmap, the user creates a custom brush suitable for drawing operations. The example shows how to use the PtInRegion function to perform hit testing and the InvertRgn function to invert the colors in a region.


Region Functions

Following are the functions used with regions.

CombineRgn
CreateEllipticRgn
CreateEllipticRgnIndirect
CreatePolygonRgn
CreatePolyPolygonRgn
CreateRectRgn
CreateRectRgnIndirect
CreateRoundRectRgn
EqualRgn
ExtCreateRegion
FillRgn
FrameRgn
GetPolyFillMode
GetRegionData
GetRgnBox
InvertRgn
OffsetRgn
PaintRgn
PtInRegion
RectInRegion
SetPolyFillMode


Accessibility

The Microsoft® Win32® API provides a set of accessibility features that make it easier for persons with disabilities to use computers. This overview describes the provided accessibility features and the Win32 functions and structures for controlling these features.


About Accessibility

There are two categories of accessibility features:

•	Accessibility parameters. These are system parameters that can be set by the user. Applications can check the state of an accessibility parameter to determine whether the user wants special behavior that can be provided in an application-specific manner. For example, the ShowSounds parameter indicates that an application that typically uses sound to convey important information should also provide the information visually.

•	Built-in accessibility features. These features are built into the system or provided as an extension to the system. They affect how the user provides keyboard and mouse input to the computer. When enabled, their functionality is available regardless of which applications are running. An example is a keyboard filter that makes it easier for users with movement impairments to type key combinations such as CTRL+ALT+DEL.


Accessibility Parameters

The system maintains a set of accessibility parameters that indicate whether the user has special needs or preferences. The user controls the state of these parameters, typically using a Control Panel application. Control Panel applications or other programs that allow the user to customize the Windows environment can use the SystemParametersInfo function to set the accessibility parameters.

Applications should use the GetSystemMetrics function to determine the state of the accessibility parameters. When an accessibility parameter is set to TRUE, the application should modify its user interface, if necessary, to accomodate the user's preferences.

Win32 supports the following accessibility parameter:

Parameter	Description
ShowSounds	Indicates that an application that typically uses sound to convey important information should provide the information visually.


Built-in Accessibility Features

The built-in accessibility features are extensions to the operating system. These features affect the behavior of the system regardless of which applications are running.

Win32 supports the following built-in accessibility features:

Feature	Description
AccessTimeout	Enables a user to specify a timeout interval after which system-wide accessibility features are automatically disabled. The AccessTimeout feature is intended for computers that are shared by several users with different preferences. Each individual can use hot keys or the Control Panel to enable preferred features. After a user leaves, the features he or she enabled will be automatically disabled by the timeout. The accessibility features affected by the timeout are FilterKeys, MouseKeys, StickyKeys, and ToggleKeys. The ACCESSTIMEOUT structure defines the parameters for this feature.
FilterKeys	Enables control of keyboard properties, such as the amount of time before a keystroke is accepted as input and the amount of time before a keystroke begins to repeat. The FilterKeys feature also provides sound feedback when a key is pressed and when it is accepted as input. The FILTERKEYS structure defines the parameters for this feature.
MouseKeys	Enables the user to control the mouse pointer using the numeric keypad. The MOUSEKEYS structure defines the parameters for this feature.
SoundSentry	Displays a visual signal when a sound is generated by a Windows-based application or an MS-DOS application running in a window. The SOUNDSENTRY structure defines the parameters for this feature.
StickyKeys	Enables the user to type key combinations, such as CTRL+ALT+DEL, in sequence rather than at the same time. The STICKYKEYS structure defines the parameters for this feature.
ToggleKeys	Provides sound feedback when the user turns on or off the CAPS LOCK, NUM LOCK, or SCROLL LOCK keys. The TOGGLEKEYS structure defines the parameters for this feature.
The SystemParametersInfo function provides the programming interface to the built-in accessibility features. This function is useful in Control Panel applications or other programs that allow the user to customize the Windows environment. The SystemParametersInfo function can perform the following tasks:

•	Query the system to determine the availability and current state of a specified built-in accessibility feature

•	Enable a feature and specify parameters that control its behavior

•	Disable a feature

•	Enable a hot key that allows the user to enable or disable a feature

For each of the built-in features, Win32 defines a structure that applications use with SystemParametersInfo to query or set the parameters of the feature.

An application can use SystemParametersInfo to enable or disable a feature directly. For some of the features, SystemParametersInfo can enable a hot key or key combination so the user can toggle the state of a feature. There are no hot keys for the SoundSentry feature. The following accessibility features have hot keys:

Feature	Description
FilterKeys	Hold down the LEFT SHIFT key for eight seconds to toggle the FilterKeys feature on or off. Holding down the LEFT SHIFT key for 12 seconds enables FilterKeys using the most conservative values for FILTERKEYS.iBounceMSec. Holding down the LEFT SHIFT key for 16 seconds enables FilterKeys using the most conservative values for FILTERKEYS.iWaitMSec.
MouseKeys	LEFT ALT+LEFT SHIFT+NUM LOCK
StickyKeys	Press the SHIFT key 5 times
ToggleKeys	Hold down the NUM LOCK key for 5 seconds


Using Accessibility

•	Checking the state of an accessibility parameter.

•	Enabling a built-in accessibility feature.


Checking the State of an Accessibility Parameter

The following code fragment uses the GetSystemMetrics function to check the ShowSounds parameter. If GetSystemMetrics returns TRUE, the application should present all important information in visual form.

BOOL fShowSounds;

fShowSounds = GetSystemMetrics(SM_SHOWSOUNDS);


Enabling a Built-in Accessibility Feature

The following code fragment uses the SystemParametersInfo function to enable the FilterKeys feature:

FILTERKEYS fk;

BOOL bSuccess;

// fill in members of the FILTERKEYS structure

fk.cbSize = sizeof(FILTERKEYS);

fk.dwFlags = (FKF_FILTERKEYSON | FKF_HOTKEYACTIVE |

                       FKF_AVAILABLE | FKF_HOTKEYSOUND | FKF_CLICKON);

fk.iWaitMSec = 1000;

fk.iDelayMSec = 1000;

fk.iRepeatMSec = 500;

fk.iBounceMSec = 0;

// call SystemParametersInfo with SPI_SETFILTERKEYS code

bSuccess = SystemParametersInfo(SPI_SETFILTERKEYS, 0, (LPVOID) &fk, 0);


Accessibility Reference

The following structures and messages are associated with accessibility features.


Accessibility Functions

Use the following functions to implement accessibility features:

GetSystemMetrics
SystemParametersInfo


Accessibility Structures

Use the following structures to implement accessibility features:

ACCESSTIMEOUT
FILTERKEYS
HIGHCONTRAST
MOUSEKEYS
SERIALKEYS
SOUNDSENTRY
STICKYKEYS
TOGGLEKEYS


Atoms

In Microsoft® Windows®, an atom table is a system-defined table that stores strings and corresponding identifiers. An application places a string in an atom table and receives a 16-bit integer, called an atom, that can be used to access the string. A string that has been placed in an atom table is called an atom name.


About Atom Tables

Dynamic data exchange (DDE) applications use an atom table to share item-name and topic-name strings with other applications. Rather than passing actual strings, a DDE application passes atoms to its partner application. The partner uses the atoms to obtain the strings from the atom table.


Global Atom Table

The Windows global atom table, which can contain up to 37 entries, is available to all applications. When an application places a string in the global atom table, the system generates an atom that is unique throughout the system. Any application that has the atom can obtain the string it identifies by querying the global atom table.

An application that defines a private clipboard-data format or DDE-data format for sharing data with other applications should place the format name in the global atom table. This technique prevents conflicts with the names of formats defined by the system or by other applications, and makes the identifiers (atoms) for the messages or formats available to the other applications.


Local Atom Tables

An application can use a local atom table to efficiently manage a large number of strings used only within the application. These strings, and the associated atoms, are available only to the application that created the table.

An application requiring the same string in a number of structures can reduce memory usage by using a local atom table. Rather than copying the string into each structure, the application can place the string in the atom table and include the resulting atom in the structures. In this way, a string appears only once in memory but can be used many times in the application.

Applications can also use local atom tables to save time when searching for a particular string. To perform a search, an application need only place the search string in the atom table and compare the resulting atom with the atoms in the relevant structures. Comparing atoms is typically faster than comparing strings.

By default, a local atom table can contain up to 37 entries. However, the size of a local atom table, unlike the size of a global atom table, can be changed. An application uses the InitAtomTable function to accomplish this task. If the application calls InitAtomTable, however, it must do so before calling any other atom-management functions.


Atom Types

Applications can use two types of atoms: string and integer. The following sections describe these types.


String Atoms

Applications pass null-terminated strings to atom tables and receive string atoms (16-bit integers) in return. String atoms have the following properties:

•	The values of string atoms are in the range 0xC000 through 0xFFFF.

•	Case is not significant in searches for an atom name in an atom table. Also, the entire string must match in a search operation; no substring matching is performed.

•	The string associated with a string atom can be no more than 255 bytes in size. This limitation applies to all atom functions.

•	A reference count is associated with each atom name. The count is incremented each time the atom name is added to the table and decremented each time the atom name is deleted from it. This prevents different users of the same string atom from destroying each other's atom names. When the reference count for an atom name equals zero, the system removes the atom and the atom name from the table.


Integer Atoms

Integer atoms differ from string atoms in the following ways:

•	The values of integer atoms are in the range 0x0001 through 0xBFFF. The values of integer atoms and string atoms do not overlap, so both types of atoms can be used in the same block of code.

•	The string representation of an integer atom is #dddd, where the values represented by dddd are decimal digits. Leading zeros are ignored.

•	There is no reference count or storage overhead associated with an integer atom.

Several Windows functions accept either string or integer atoms as parameters. When passing an integer atom to these functions, an application must use the MAKEINTATOM macro to create the atom.


Atom Creation and Usage Count

An application creates a local atom by calling the AddAtom function; it creates a global atom by calling the GlobalAddAtom function. Both functions require a pointer to a string. The system searches the appropriate atom table for the string and returns the corresponding atom to the application. In the case of a string atom, if the string already resides in the atom table, the system increments the reference count for the string during this process.

Repeated calls to add the same atom name return the same atom. If the atom name does not exist in the table when AddAtom is called, the atom name is added to the table and a new atom is returned. If it is a string atom, its reference count is also set to one.

An application should call the DeleteAtom function when it no longer needs to use a local atom; it should call the GlobalDeleteAtom function when it no longer needs a global atom. In the case of a string atom, either of these functions reduces the reference count of the corresponding atom by one. When the reference count reaches zero, the system deletes the atom name from the table.

The atom name of a string atom remains in the global atom table as long as its reference count is greater than zero, even after the application that placed it in the table terminates. A local atom table is destroyed when the associated application terminates, regardless of the reference counts of the atoms in the table.


Atom-Table Queries

An application can determine whether a particular string is already in an atom table by using the FindAtom or GlobalFindAtom function. These functions search an atom table for the specified string and, if the string is there, return the corresponding atom.

An application can use the GetAtomName or GlobalGetAtomName function to retrieve an atom-name string from an atom table, provided the application has the atom corresponding to the string sought. Both functions copy the atom-name string of the specified atom to a buffer and return the length of the string that was copied. GetAtomName retrieves an atom-name string from a local atom table, and GlobalGetAtomName retrieves an atom-name string from the global atom table.


Atom String Formats

The AddAtom, GlobalAddAtom, FindAtom, and GlobalFindAtom functions take a pointer to a null-terminated string. An application can specify this pointer in one of the following ways.

Format	Description
#dddd	An integer specified as a decimal string. Used to create or find an integer atom.
string atom name	A string atom name. Used to add a string atom name to an atom table and receive an atom in return.


Using Atoms

The most typical use for atoms is in DDE applications. In the DDE protocol, applications use global atoms to identify the applications exchanging data, the nature of the data being exchanged, and the actual data items being exchanged. For more information about DDE and for examples that show how to use atoms, see Dynamic Data Exchange.


Atom Functions

Following are the functions associated with atoms.

AddAtom
DeleteAtom
FindAtom
GetAtomName
GlobalAddAtom
GlobalDeleteAtom
GlobalFindAtom
GlobalGetAtomName
InitAtomTable

Obsolete or Deleted Functions

GetAtomHandle


Communications

A communications resource is a physical or logical device that provides a single bidirectional, asynchronous data stream. Serial ports, parallel ports, fax machines, and modems are examples of communications resources. For each communications resource, there is a service provider, consisting of a library or driver, that enables applications to access the resource.


About Communications

The file input and output (I/O) functions (CreateFile, CloseHandle, ReadFile, ReadFileEx, WriteFile, and WriteFileEx) provide the basic interface for opening and closing a communications resource handle and for performing read and write operations. The Microsoft® Win32® application programming interface (API) also includes a set of communications functions that provide access to communications resources. This overview describes the use of file I/O and communications functions, which enable applications to perform the following tasks:

•	Open a handle to a specified communications resource.

•	Set and query the configuration of a serial communications resource.

•	Read from or write to a serial communications resource.

•	Monitor a specified set of events that might occur for a given serial communications resource.

•	Send a control command to the device driver associated with a specified communications resource, causing the driver to execute an extended function.


Communications Resource Handles

A process uses the CreateFile function to open a handle to a communications resource. For example, specifying COM1 opens a handle to a serial port, and LPT1 opens a handle to a parallel port. If the specified resource is currently being used by another process, CreateFile fails. Any thread of the process can use the handle returned by CreateFile to identify the resource in any of the functions that access the resource.

When using CreateFile to open a handle directly to a device, an application must use the special characters " \\ .\" to identify the device. For example, to open a handle to drive A, specify " \\ .\a:" for the lpszName parameter of CreateFile. The calling process can use the handle in the DeviceIoControl function to send control codes to the device.

When the process calls CreateFile to open a communications resource, it specifies the following attributes:

•	What type of read-write access exists for the specified resource.

•	Whether the handle can be inherited by child processes.

•	Whether the handle can be used in overlapped (asynchronous) I/O operations. (For a description of overlapped operations, see Synchronization.)

When the process uses CreateFile to open a communications resource, it must specify certain values for the following parameters:

•	The fdwShareMode parameter must be zero, opening the resource for exclusive access.

•	The fdwCreate parameter must specify the OPEN_EXISTING flag.

•	The hTemplateFile parameter must be NULL.


Modification of Communications Resource Settings

When the CreateFile function opens a handle to a serial communications resource, the system initializes and configures the resource according to the values set up the last time the resource was opened. Preserving the previous settings enables the user to retain the settings specified through an MS-DOS® mode command when the device is reopened. The values inherited from the previous open operation include the configuration settings of the device control block (a DCB structure) and the time-out values used in I/O operations. If the device has never been opened, it is configured with the system defaults.

To determine the initial configuration of a serial communications resource, a process calls the GetCommState function, which fills in a serial port DCB structure with the current configuration settings. To modify this configuration, a process specifies a DCB structure in a call to the SetCommState function.

Members of the DCB structure specify the configuration settings such as the baud rate, the number of data bits per byte, and the number of stop bits per byte. Other DCB members specify special characters and enable parity checking and flow control. When a process needs to modify only a few of these configuration settings, it should first call GetCommState to fill in a DCB structure with the current configuration. Then the process can adjust the important values in the DCB structure and reconfigure the device by calling SetCommState and specifying the modified DCB structure. This procedure ensures that the unmodified members of the DCB structure contain appropriate values. For example, a common error is to configure a device with a DCB structure in which the structure's XonChar member is equal to the XoffChar member. Some members of the DCB structure are different from those in previous versions of Microsoft Windows®. In particular, the flags for controlling RTS (request-to-send) and DTR (data-terminal-ready) flow control have changed.

The BuildCommDCB function provides another way to modify a DCB structure. BuildCommDCB uses a string with the same form as the command-line arguments of the mode command to specify the baud rate, parity scheme, number of stop bits, and number of data bits. The remaining members of DCB are not changed by this function, except that the appropriate members are set to disable XON/XOFF and hardware flow control. BuildCommDCB only modifies a DCB structure; it does not reconfigure the device.

A process can reconfigure a communications resource by using the GetCommProperties function to get information from a device driver about the configuration settings that it supports. The process can use this information to avoid specifying a configuration that is not supported.

The SetCommState function reconfigures the communications resource, but it does not affect the internal output and input buffers of the specified driver. The buffers are not flushed, and pending read and write operations are not terminated prematurely.

A process reinitializes a communications resource by using the SetupComm function, which performs the following tasks:

•	Terminates pending read and write operations, even if they have not been completed.

•	Discards unread characters and frees the internal output and input buffers of the driver associated with the specified resource.

•	Reallocates the internal output and input buffers.

A process is not required to call SetupComm. If it does not, the resource's driver initializes the device with the default settings the first time that the communications resource handle is used.


Communications Resource Configuration

The COMMCONFIG structure defines the configuration of a communications resource, serial or otherwise. The format of the structure varies depending on the type of communications resource (the provider subtype). The first few structure members are common to all communications resources; additional members are defined for specific provider subtypes. Specific service providers may extend the COMMCONFIG structure as well.

An application can get and set the configuration of a communications resource by using the GetCommConfig and SetCommConfig functions. When opened, a communications resource is initialized using the default configuration for its provider subtype. To get and set the default configuration for a provider subtype, use the GetDefaultCommConfig and SetDefaultCommConfig functions.

To prompt the user for configuration information, use the CommConfigDialog function. This function displays a dialog box defined by the service provider and fills in a COMMCONFIG structure based on user input.


Modem Configuration

Modem configuration functions enable you to configure a modem before making a connection. An application can set modem options and determine the features of a modem without using commands specific to any modem device. Following are the general features an application may set before making a call:

•	Primary mode of operation (synchronous, asynchronous, and whether error control is enabled).

•	V.42 error control (defined by CCITT recommendation V.42), including specific parameters. CCITT stands for the International Telegraph and Telephone Consultative Committee.

•	V.42bis (defined by CCITT recommendation V.42bis) and MNP5 data compression.

•	Time-out options, including call setup, inactivity, and buffered data delivery.

Before setting a modem's configuration, an application should determine the capabilities of the modem device by using the GetCommProperties function. This function fills in a COMMPROP structure. This structure contains both a general portion, which applies to all communications devices, and a portion that is specific to each provider subtype. For modem devices, the provider-specific portion of the COMMPROP structure is a MODEMDEVCAPS structure.

An application can get and set the current configuration of a modem by using the GetCommConfig and SetCommConfig functions, both of which use a COMMCONFIG structure. This structure contains both a general portion, which applies to all communications devices, and a portion that is specific to each provider subtype. For modem devices, the provider-specific portion of the COMMCONFIG structure is a MODEMSETTINGS structure.

After configuring a modem, an application can use the telephony application programming interface (TAPI) to actually establish a connection.

The modem configuration functions do not provide for long-term management and maintenance of a modem. Modem service providers should supply modem configuration dialog boxes for this purpose.


Read and Write Operations

The Win32 API supports both synchronous and asynchronous (overlapped) file I/O operations on serial communications resources. Overlapped operations enable the calling thread to perform other tasks while the operation executes in the background. A thread uses the ReadFile or ReadFileEx function to read from a communications resource, and the WriteFile or WriteFileEx function to write to a communications resource. ReadFile and WriteFile can be performed synchronously or asynchronously. ReadFileEx and WriteFileEx can only be performed asynchronously.

The behavior of these read and write functions is affected by whether the function is executed as an overlapped operation, whether the time-out parameters are associated with the handle, and whether flow control parameters are associated with the handle.

A thread can also write to a communications resource by using the TransmitCommChar function, which transmits a specified character ahead of any pending data in the output buffer. This function is useful for transmitting a high priority signal character to the receiving system. Transmission of the high priority character is still subject to flow control and write time-outs, and the operation is performed synchronously.

A thread can use the PurgeComm function to discard all characters in a device's output or input buffer. PurgeComm can also terminate pending read or write operations, even if the operations have not been completed. If a thread uses PurgeComm to flush an output buffer, the deleted characters are not transmitted. To empty the output buffer while ensuring that the contents are transmitted, a thread can call the FlushFileBuffers function (a synchronous operation). Note, however, that FlushFileBuffers is subject to flow control but not to write time-outs, and it will not return until all pending write operations have been transmitted.


Overlapped Operations

Overlapped operations enable a thread to execute a time-consuming I/O operation in the background, leaving the thread free to perform other tasks. To enable overlapped I/O operations on a communications resource, the thread must specify the FILE_FLAG_OVERLAPPED flag in the CreateFile function when the handle is opened. To execute the ReadFile or WriteFile function as an overlapped operation, the calling thread must specify a pointer to an OVERLAPPED structure.The OVERLAPPED structure must contain a handle to a manual-reset (not an auto-reset) event object. The system sets the state of the event object to not-signaled when a call to the I/O function returns before the operation has been completed. The system sets the state of the event object to signaled when the operation has been completed. The thread uses a wait function to check the current state of the event object or to wait for its state to be signaled.

The ReadFileEx and WriteFileEx functions can be performed only as overlapped operations. The calling thread specifies a pointer to the FileIOCompletionRoutine function, which is executed when the overlapped operation is completed. The completion routine is executed only if the calling thread performs an alertable operation.

For more information about event objects, wait functions, alertable waits, and completion routines, see Synchronization.


Time-Outs

A handle to a communications resource has an associated set of time-out parameters that affect the behavior of read and write operations. Time-outs can cause a ReadFile, ReadFileEx, WriteFile, or WriteFileEx operation to conclude when a time-out interval elapses, even though the specified number of characters have not been read or written. It is not treated as an error when a time-out occurs during a read or write operation (that is, the read or write function's return value indicates success). The count of bytes actually read or written is reported by ReadFile or WriteFile (or by the GetOverlappedResult or FileIOCompletionRoutine function, if the I/O was performed as an overlapped operation).

When an application opens a communications resource, the operating system sets the resource's time-out values to the values in effect when the resource was last used. If the communications resource has never been opened, the operating system sets the time-out values to some default value. In either case, an application should always determine the current time-out values after opening the resource, and then explicitly set them to meet its requirements. To determine the current time-out values of a communications resource, use the GetCommTimeouts function. To change the time-out values, use the SetCommTimeouts function.

Two types of time-outs are enabled by the time-out parameters. An interval time-out occurs when the time between the receipt of any two characters exceeds a specified number of milliseconds. Timing starts when the first character is received and is restarted when each new character is received. A total time-out occurs when the total amount of time consumed by a read operation exceeds a calculated number of milliseconds. Timing starts immediately when the I/O operation begins. Write operations support only total time-outs. Read operations support both interval and total time-outs, which can be used separately or combined.

The time, in milliseconds, of the total time-out period for a read or write operation is calculated by using the multiplier and constant values from the COMMTIMEOUTS structure specified in the GetCommTimeouts or SetCommTimeouts function. The following formula is used:

Timeout = (MULTIPLIER * number_of_bytes) + CONSTANT

Using both a multiplier and a constant enables the total time-out period to vary, depending on the amount of data being requested. An application can use only the constant by setting the multiplier to zero, or use only the multiplier by setting the constant to zero. If both the constant and multiplier are zero, total time-out is not used.

If all read time-out parameters are zero, read time-outs are not used, and a read operation is not complete until the requested number of bytes have been read or an error occurs. Similarly, if all write time-out parameters are zero, a write operation is not completed until the requested number of bytes have been written or an error occurs.

If the read interval time-out parameter is the MAXDWORD value and both read total time-out parameters are zero, a read operation is completed immediately after reading whatever characters are available in the input buffer, even if it is empty. This is the same as the ReadComm function in previous versions of Windows.

Interval timing forces a read operation to return when there is a lull in reception. A process using interval time-outs can set a fairly short interval parameter, so it can respond quickly to small, isolated bursts of one or a few characters, yet it can still collect large buffers of characters with a single call when data is received in a steady stream.

Time-outs for a write operation can be useful when transmission is blocked by some kind of flow control or when the SetCommBreak function has been called to suspend character transmission.

The following table summarizes the behavior of read operations based on the values specified for total and interval time-outs.

Total	Interval	Behavior
0	0	Returns when the buffer is completely filled. Time-outs are not used.
T	0	Returns when the buffer is completely filled or when T milliseconds have elapsed since the beginning of the operation.
0	Y	Returns when the buffer is completely filled or when Y milliseconds have elapsed between the receipt of any two characters. Timing does not begin until the first character is received.
T	Y	Returns when the buffer is completely filled or when either type of time-out occurs.
Note, however, that timing is relative to the system controlling the physical device. For a remote device such as a modem, the timing is relative to the server system to which the modem is attached. Any network propagation delay is not factored in. For example, a client application might specify a total time-out that computes to be 500 milliseconds. When 500 milliseconds have elapsed at the server, a time-out error is returned to the client. If there is a 50 milliseconds network propagation delay, the client will not be notified of the time-out until approximately 50 milliseconds after the time-out actually occurred.

The time-out parameters affect the behavior of overlapped read and write operations on a communications device. With overlapped I/O, the ReadFile, WriteFile, ReadFileEx, or WriteFileEx function can return before the operation has been completed. The time-out parameters can determine when the operation has been completed.


Communications Errors

There are other circumstances where a read or write operation can be completed with fewer than the requested number of characters, even though a time-out has not occurred. Following are some examples:

•	Some drivers support the use of special characters, which complete a read operation immediately with only the characters that have been read up to the point when they are received.

•	The PurgeComm function can be called to prematurely terminate pending read or write operations. This function can also delete the contents of the output or input buffers, or both.

•	If a communications error occurs during a read or write operation, all I/O operations on the communications resource are terminated. Break conditions, parity errors, or framing errors are examples of such errors. When an error occurs, the process must call the ClearCommError function to clear the error flag before it can begin additional I/O operations. ClearCommError reports the specific error that occurred and the current status of the device.


Communications Events

A process can monitor a set of events that occur in a communications resource. For example, an application can use event monitoring to determine when the CTS (clear-to-send) and DSR (data-set-ready) signals change state.

A process can monitor events on a given communications resource by using the SetCommMask function to create an event mask. To determine the current event mask for a communications resource, a process can use the GetCommMask function. The following values specify events that can be monitored.

Value	Meaning
EV_BREAK	A break was detected on input.
EV_CTS	The CTS (clear-to-send) signal changed state.
EV_DSR	The DSR (data-set-ready) signal changed state.
EV_ERR	A line-status error occurred. Line-status errors are CE_FRAME, CE_OVERRUN, and CE_RXPARITY.
EV_RING	A ring indicator was detected.
EV_RLSD	The RLSD (receive-line-signal-detect) signal changed state.
EV_RXCHAR	A character was received and placed in the input buffer.
EV_RXFLAG	The event character was received and placed in the input buffer. The event character is specified in the device's DCB structure, which is applied to a serial port by using the SetCommState function.
EV_TXEMPTY	The last character in the output buffer was sent.
After a set of events is specified, a process uses the WaitCommEvent function to wait for one of the events to occur. WaitCommEvent can be used synchronously or as an overlapped operation. For additional information about executing a function as an overlapped operation, see Synchronization.

When one of the events specified in the event mask occurs, the process completes the wait operation and sets an event mask variable to indicate the type of event detected. If the SetCommMask is called for a communications resource while a wait is pending for that resource, WaitCommEvent returns an error.

The WaitCommEvent function detects events that have occurred since the last call to SetCommMask or WaitCommEvent. For example, if you specify the EV_RXCHAR event as a wait-satisfying event, a call to WaitCommEvent will be satisfied if there are characters in the driver's input buffer that have arrived since the last call to WaitCommEvent or SetCommMask. Thus, given the following pseudo-code,

while (we_care) {

WaitCommEvent

T1:	// Read bytes

// process them

T2:	}

... any characters received between T1 and T2 will satisfy the next call to WaitCommEvent.

When monitoring an event that occurs when a signal (CTS, DSR, and so on) changes state, WaitCommEvent reports the change, but not the current state. To query the current state of the CTS (clear-to-send), DSR (data-set-ready), RLSD (receive-line-signal-detect), and ring indicator signals, a process can use the GetCommModemStatus function.


Extended Functions

Some communications functions can be called for a device by using the EscapeCommFunction function. This function sends a code to direct the device to execute an extended function. For example, an application can suspend character transmission with the SETBREAK code and resume transmission with the CLRBREAK code. These particular operations can also be started by calling the SetCommBreak and ClearCommBreak functions. EscapeCommFunction can also be used to implement manual modem control. For example, the CLRDTR and SETDTR codes can be used to implement manual DTR (data-terminal-ready) flow control. Note, however, that an error occurs if a process uses EscapeCommFunction to manipulate the DTR line when the device has been configured to enable DTR handshaking, or the RTS (request-to-send) line if RTS handshaking is enabled.

The DeviceIoControl function enables a process to send an extended function code directly to a specified device driver, causing the device to perform a given operation. DeviceIoControl gives a device associated with a communications resource capabilities not supported by the standard serial communications functions. It enables an application to configure a device using parameters unique to that device as well as to call any device-specific functions.


Using the Communications Functions

•	Configuring a communications resource

•	Monitoring communications events


Configuring a Communications Resource

The following example opens a handle to COM1 and fills in a DCB structure with the current configuration. The DCB structure is then modified and used to reconfigure the device.

DCB dcb;
HANDLE hCom;
DWORD dwError;
BOOL fSuccess;

hCom = CreateFile("COM1",
    GENERIC_READ | GENERIC_WRITE,
    0,    /* comm devices must be opened w/exclusive-access */
    NULL, /* no security attrs */
    OPEN_EXISTING, /* comm devices must use OPEN_EXISTING */
    0,    /* not overlapped I/O */
    NULL  /* hTemplate must be NULL for comm devices */
    );

if (hCom == INVALID_HANDLE_VALUE) {
    dwError = GetLastError();

    /* handle error */
}

/*
 * Omit the call to SetupComm to use the default queue sizes.
 * Get the current configuration.
 */

fSuccess = GetCommState(hCom, &dcb);

if (!fSuccess) {
    /* Handle the error. *
}

/* Fill in the DCB: baud=9600, 8 data bits, no parity, 1 stop bit. */

dcb.BaudRate = 9600;
dcb.ByteSize = 8;
dcb.Parity = NOPARITY;
dcb.StopBits = ONESTOPBIT;

fSuccess = SetCommState(hCom, &dcb);

if (!fSuccess) {
    /* Handle the error. *
}


Monitoring Communications Events

The following example code opens the serial port for overlapped I/O, creates an event mask to monitor CTS and DSR signals, and then waits for an event to occur. The WaitCommEvent function should be executed as an overlapped operation so the other threads of the process cannot perform I/O operations during the wait.

HANDLE hCom;
OVERLAPPED o;
BOOL fSuccess;
DWORD dwEvtMask;

hCom = CreateFile("COM1",
    GENERIC_READ | GENERIC_WRITE,
    0, /* exclusive access */
    NULL, /* no security attrs */
    OPEN_EXISTING,
    FILE_FLAG_OVERLAPPED,
    NULL
    );

if (hCom == INVALID_HANDLE_VALUE) {
    /* Deal with the error. */
}

/* Set the event mask. */

fSuccess = SetCommMask(hCom, EV_CTS | EV_DSR);

if (!fSuccess) {
    /* deal with error */
}

/* Create an event object for use in WaitCommEvent. */

o.hEvent = CreateEvent(NULL, /* no security attributes */
    FALSE, /* auto reset event */
    FALSE, /* not signaled */
    NULL /* no name */
    );

assert(o.hEvent);

if (WaitCommEvent(hCom, &dwEvtMask, &o)) {
    if (dwEvtMask & EV_DSR) {
        /*
         * . . .
         */
    }

    if (dwEvtMask & EV_CTS) {
        /*
         * . . .
         */
    }
}


Communication Functions

Following are the functions used with communications devices.

BuildCommDCB
BuildCommDCBAndTimeouts
ClearCommBreak
ClearCommError
CommConfigDialog
DeviceIoControl
EscapeCommFunction
GetCommConfig
GetCommMask
GetCommModemStatus
GetCommProperties
GetCommState
GetCommTimeouts
PurgeComm
SetCommBreak
SetCommConfig
SetCommMask
SetCommState
SetCommTimeouts
SetupComm
TransmitCommChar
WaitCommEvent


Consoles and Character-Mode Support

The Microsoft® Win32® application programming interface (API) provides consoles that manage input and output (I/O) for character-mode applications (applications that do not provide their own graphical user interface).

This overview describes Win32 support for character-mode applications.


About Character-Mode Support

Consoles provide high-level support for simple character-mode applications that interact with the user by using functions that read from standard input and write to standard output or standard error. Consoles also provide sophisticated low-level support that gives direct access to a console's screen buffer and that enables applications to receive extended input information (such as mouse input).


Consoles

A console is an interface that provides I/O to character-mode applications. This processor-independent mechanism makes it easy to port existing character-mode applications or to create new character-mode tools and applications.

A console consists of an input buffer and one or more screen buffers. The input buffer contains a queue of input records, each of which contains information about an input event. The input queue always includes key-press and key-release events. It can also include mouse events (pointer movements and button presses and releases) and events during which user actions affect the size of the active screen buffer. A screen buffer is a two-dimensional array of character and color data for output in a console window.

The Win32 API functions enable different levels of access to a console. The high-level console I/O functions enable an application to read from standard input to retrieve keyboard input stored in a console's input buffer. The functions also enable an application to write to standard output or standard error to display text in the console's screen buffer. The high-level functions also support redirection of standard handles and control of console modes for different I/O functionality. The low-level console I/O functions enable applications to receive detailed input about keyboard and mouse events, as well as events involving user interactions with the console window. The low-level functions also enable greater control of output to the screen.


Creation of a Console

Microsoft Windows® creates a new console when it starts a console process, a character-mode process whose entry point is the main function. For example, Windows creates a new console when it starts the command processor. When the command processor starts a new console process, the user can specify whether the system creates a new console for the new process or whether it inherits the command processor's console. A process can create a console by using one of the following methods:

•	A graphical user interface (GUI) or console process that is not currently attached to a console can use the AllocConsole function to create a new console.

•	A GUI or console process can use the CreateProcess function to create a new console process and specify a flag to tell the system to create a new console.

Typically, a process uses AllocConsole to create a console when an error occurs requiring interaction with the user. For example, a GUI process can create a console when an error occurs that prevents it from using its normal graphical interface, or a console process that does not normally interact with the user can create a console when an error makes it necessary. The process that calls AllocConsole must not be attached to an existing console. GUI processes are not attached to any console when they are created. A console process is not attached to a console if the DETACHED_PROCESS flag was specified in a call to CreateProcess when the process was created. A process can use the FreeConsole function to detach itself from an inherited console or from a console created by AllocConsole.

A process can also create a console by specifying the CREATE_NEW_CONSOLE flag in a call to CreateProcess. This method creates a new console that is accessible to the child process but not to the parent process. Separate consoles enable both parent and child processes to interact with the user without conflict. If this flag is not specified when a console process is created, both processes are attached to the same console, and there is no guarantee that the correct process will receive the input intended for it. Applications can prevent confusion by creating child processes that do not inherit handles of the input buffer, or by enabling only one child process at a time to inherit an input buffer handle while preventing the parent process from reading console input until the child has finished.

Creating a new console results in a new console window, as well as separate I/O screen buffers. The process associated with the new console uses the GetStdHandle function to get the handles of the new console's input and screen buffers. These handles enable the process to access the console.

When a process uses CreateProcess, it can specify a STARTUPINFO structure, whose members control the characteristics of the first new console (if any) created for the child process. The STARTUPINFO structure specified in the call to CreateProcess affects a console created if the CREATE_NEW_CONSOLE flag is specified. It also affects a console created if the child process subsequently uses AllocConsole. The following console characteristics can be specified:

•	The size, in character cells, and the location, in screen pixel coordinates, of the new console window

•	The size, in character cells, of the new console's screen buffer

•	The text and background color attributes of the new console's screen buffer

•	The name appearing in the title bar of the new console's window

The system uses default values if the STARTUPINFO values are not specified. A child process can use the GetStartupInfo function to determine the values in its STARTUPINFO structure.

A process cannot change the location of its console window on the screen, but the following console functions are available to set or retrieve the other properties specified in the STARTUPINFO structure.

Function	Description
GetConsoleScreenBufferInfo	Retrieves the window size, screen buffer size, and color attributes.
SetConsoleWindowInfo	Changes the size of the console window.
SetConsoleScreenBufferSize	Changes the size of the screen buffer.
SetConsoleTextAttribute	Sets the color attributes.
SetConsoleTitle	Sets the console window title.
GetConsoleTitle	Retrieves the console window title.


Closing a Console

A process can use the FreeConsole function to detach itself from its console. If other processes share the console, the console is not destroyed, but the process that called FreeConsole cannot refer to it. After calling FreeConsole, the process can use AllocConsole to create a new console.

A console is closed when the last process attached to it terminates or calls FreeConsole.


Console Handles

A console process uses handles to access the input and screen buffers of its console. A process can use the GetStdHandle, CreateFile, or CreateConsoleScreenBuffer function to open one of these handles.

The GetStdHandle function provides a mechanism for retrieving the standard input (STDIN), standard output (STDOUT), and standard error (STDERR) handles associated with a process. During console creation, the system creates these handles. Initially, STDIN is a handle of the console's input buffer, and STDOUT and STDERR are handles of the console's active screen buffer. However, the SetStdHandle function can redirect the standard handles by changing the handle associated with STDIN, STDOUT, or STDERR. Because the parent's standard handles are inherited by any child process, subsequent calls to GetStdHandle return the redirected handle. A handle returned by GetStdHandle may, therefore,  refer to something other than console I/O. For example, before creating a child process, a parent process can use SetStdHandle to set a pipe handle to be the STDIN handle that is inherited by the child process. When the child process calls GetStdHandle, it gets the pipe handle. This means that the parent process can control the standard handles of the child process. The handles returned by GetStdHandle have GENERIC_READ | GENERIC_WRITE access unless SetStdHandle has been used to set the standard handle to have lesser access.

The value of the handles returned by GetStdHandle will not be 0, 1, and 2, so the standard predefined stream constants in the STDIO.H header file (STDIN, STDOUT, and STDERR) cannot be used in functions that require a console handle.

The CreateFile function enables a process to get a handle of its console's input buffer and active screen buffer, even if STDIN and STDOUT have been redirected. To open a handle of a console's input buffer, specify the CONIN$ value in a call to CreateFile. Specify the CONOUT$ value in a call to CreateFile to open a handle of a console's active screen buffer. CreateFile enables you to specify the read-write access of the handle that it returns.

The CreateConsoleScreenBuffer function creates a new screen buffer and returns a handle, which can be used in any function that accepts a handle of console output. The new screen buffer is not active until its handle is specified in a call to the SetConsoleActiveScreenBuffer function. Note that changing the active screen buffer does not affect the handle returned by GetStdHandle. Similarly, using SetStdHandle to change the STDOUT handle does not affect the active screen buffer.

Console handles returned by CreateFile and CreateConsoleScreenBuffer can be used in any of the console functions that require a handle of a console's input buffer or of a console screen buffer. Handles returned by GetStdHandle can be used by the console functions if they have not been redirected to refer to something other than console I/O. If a standard handle has been redirected to refer to a file or a pipe, however, the handle can only be used by the ReadFile and WriteFile functions.

A process can use the DuplicateHandle function to create a duplicate console handle that has different access or inheritability from the original handle. Note, however, that a process can create a duplicate console handle only for its own use. This differs from other handle types (such as file, pipe, or mutex objects), for which DuplicateHandle can create a duplicate that is valid for a different process.

To close a console handle, a process can use the CloseHandle function.


Console Input Buffer

Each console has an input buffer that contains a queue of input event records. When a console's window has the keyboard focus, a console formats each input event (such as a single keystroke, a movement of the mouse, or a mouse-button click) as an input record that it places in the console's input buffer.

Applications can access a console's input buffer indirectly by using the high-level console I/O functions, or directly by using the low-level console I/O functions. The high-level input functions filter and process the data in the input buffer, returning only a stream of input characters. The low-level input functions enable applications to read input records directly from a console's input buffer, or to place input records into the input buffer.

An input record is a structure containing information about the type of event that occurred (keyboard, mouse, window resizing, focus, or menu event) as well as specific details about the event. The EventType member in an INPUT_RECORD structure indicates which type of event is contained in the record.

Focus and menu events are placed in a console's input buffer for internal use by the system and should be ignored by applications.

Keyboard Events

Keyboard events are generated when any key is pressed or released; this includes control keys. However, the ALT key has special meaning to Windows when pressed and released without being combined with another character, and it is not passed through to the application. Also, the CTRL+C key combination is not passed through if the input handle is in processed mode.

If the input event is a keystroke, the Event member in INPUT_RECORD is a KEY_EVENT_RECORD structure containing the following information:

•	A Boolean value indicating whether the key was pressed or released.

•	A repeat count that can be greater than one when a key is held down.

•	The virtual-key code, identifying the given key in a device-independent manner.

•	The virtual-scan code, indicating the device-dependent value generated by the keyboard hardware.

•	The translated Unicode™ or ANSI character.

•	A flag variable indicating the state of the control keys (the ALT, CTRL, SHIFT, NUM LOCK, SCROLL LOCK, and CAPS LOCK keys) and indicating whether an enhanced key was pressed. Enhanced keys for the IBM® 101-key and 102-key keyboards are the INS, DEL, HOME, END, PAGE UP, PAGE DOWN, and arrow keys in the clusters to the left of the numeric keypad and the divide (/) and ENTER keys in the numeric keypad.

Mouse Events

Mouse events are generated whenever the user moves the mouse or presses or releases one of the mouse buttons. Mouse events are placed in the input buffer only if the following conditions are met:

•	The console input mode is set to ENABLE_MOUSE_INPUT (the default mode).

•	The console window has the keyboard focus.

•	The mouse pointer is within the borders of the console's window.

If the input event is a mouse event, the Event member in INPUT_RECORD is a MOUSE_EVENT_RECORD structure containing the following information:

•	The coordinates of the mouse pointer in terms of the character-cell row and column in the screen buffer's coordinate system.

•	A flag variable indicating the state of the mouse buttons.

•	A flag variable indicating the state of the control keys (ALT, CTRL, SHIFT, NUM LOCK, SCROLL LOCK, and CAPS LOCK) and indicating whether an enhanced key was pressed. Enhanced keys for the IBM 101-key and 102-key keyboards are the INS, DEL, HOME, END, PAGE UP, PAGE DOWN, and arrow keys in the clusters to the left of the numeric keypad and the divide (/) and ENTER keys in the numeric keypad.

•	A flag variable indicating whether the event was a normal button-press or button-release event, a mouse movement event, or the second click of a double-click event.

Note that the mouse position coordinates are in terms of the screen buffer, not the console window. The screen buffer may have been scrolled with respect to the window, so the upper left corner of the window is not necessarily the (0,0) coordinate of the screen buffer. To determine the coordinates of the mouse relative to the coordinate system of the window, subtract the window origin coordinates from the mouse position coordinates. Use the GetConsoleScreenBufferInfo function to determine the window origin coordinates.

The dwButtonState member of the MOUSE_EVENT_RECORD structure has a bit corresponding to each mouse button. The bit is 1 if the button is down and 0 if the button is up. A button-release event is detected by a 0 value for the dwEventFlags member of MOUSE_EVENT_RECORD and a change in a button's bit from 1 to 0. The GetNumberOfConsoleMouseButtons function retrieves the number of buttons on the mouse.

Buffer-Resizing Events

A console window's menu enables the user to change the size of the active screen buffer; this change generates a buffer-resizing event. Buffer-resizing events are placed in the input buffer if the console's input mode is set to ENABLE_WINDOW_INPUT (that is, the default mode is disabled).

If the input event is a buffer-resizing event, the Event member of INPUT_RECORD is a WINDOW_BUFFER_SIZE_RECORD structure containing the new size of the screen buffer, expressed in character-cell columns and rows.

If the user reduces the size of the screen buffer, any data in the discarded portion of the buffer is lost.

Changes to the screen buffer size as a result of application calls to the SetConsoleScreenBufferSize function are not generated as buffer-resizing events.


Console Screen Buffers

A screen buffer is a two-dimensional array of character and color data for output in a console window. A console can have multiple screen buffers. The active screen buffer is the one that is displayed on the screen.

The system creates a screen buffer whenever it creates a new console. A process can use the CreateConsoleScreenBuffer function to create additional screen buffers for its console. A new screen buffer is not active until its handle is specified in a call to the SetConsoleActiveScreenBuffer function. However, screen buffers can be accessed for reading and writing whether they are active or inactive.

Each screen buffer has its own two-dimensional array of character information records. The data for each character is stored in a CHAR_INFO structure that specifies the Unicode or ANSI character and the foreground and background colors in which that character is displayed.

A number of properties associated with a screen buffer can be set independently for each screen buffer. This means that changing the active screen buffer can have a dramatic effect on the appearance of the console window. The properties associated with a screen buffer include:

•	Screen buffer size, in character rows and columns.

•	Text attributes (foreground and background colors for displaying text to be written by the WriteFile or WriteConsole function).

•	Window size and location (the rectangular region of the screen buffer that is displayed in the console window).

•	Cursor position, appearance, and visibility.

•	Output modes (ENABLE_PROCESSED_OUTPUT and ENABLE_WRAP_AT_EOL_OUTPUT). For more information about console output modes, see High-Level Console Modes.

When a screen buffer is created, it contains blanks. Its cursor is visible and positioned at the buffer's origin (0,0), and the window is positioned with its upper left corner at the buffer's origin. The size of the screen buffer, the window size, the text attributes, and the appearance of the cursor are determined by the user or by the system defaults. To retrieve the current values of the various properties associated with the screen buffer, use the GetConsoleScreenBufferInfo, GetConsoleCursorInfo, and GetConsoleMode functions.

Applications that change any of the screen buffer properties should either create their own screen buffer or save the state of the inherited screen buffer during startup and restore it at exit.


Window and Screen Buffer Size

The size of a screen buffer is expressed in terms of a coordinate grid based on character cells. The width is the number of character cells in each row, and the height is the number of rows. Associated with each screen buffer is a window that determines the size and location of the rectangular portion of the screen buffer displayed in the console window. A screen buffer's window is defined by specifying the character-cell coordinates of the upper left and lower right cells of the window's rectangle.

A screen buffer can be any size, limited only by available memory. The dimensions of a screen buffer's window cannot exceed the corresponding dimensions of either the screen buffer or the maximum window that can fit on the screen based on the current font size (controlled exclusively by the user).

The GetConsoleScreenBufferInfo function returns the following information about a screen buffer and its window:

•	The current size of the screen buffer

•	The current location of the window

•	The maximum size of the window given the current screen buffer size, the current font size, and the screen size

The GetLargestConsoleWindowSize function returns the maximum size of a console's window based on the current font and screen sizes. This size differs from the maximum window size returned by GetConsoleScreenBufferInfo in that the screen buffer size is ignored.

To change a screen buffer's size, use the SetConsoleScreenBufferSize function. This function fails if either dimension of the specified size is less than the corresponding dimension of the console's window.

To change the size or location of a screen buffer's window, use the SetConsoleWindowInfo function. This function fails if the specified window-corner coordinates exceed the limits of the screen buffer or the screen. Changing the window size of the active screen buffer changes the size of the console window displayed on the screen.

A process can change its console's input mode to enable window input so that the process is able to receive input when the user changes the screen buffer size. If an application enables window input, it can use GetConsoleScreenBufferInfo to retrieve window and screen buffer size at startup. This information can then be used to determine the way data is displayed in the window. If the user changes the screen buffer size, the application can respond by changing the way data is displayed. For example, an application can adjust the way text wraps at the end of the line if the number of characters per row changes. If an application does not enable window input, it must either use the inherited window and screen buffer sizes, or set them to the desired size during startup and restore the inherited sizes at exit. For additional information about window input mode, see Low-Level Console Modes.


Scrolling the Screen Buffer

The console window displays a portion of the active screen buffer. Each screen buffer maintains its own current window rectangle that specifies the coordinates of the upper left and lower right character cells to be displayed in the console window. To determine the current window rectangle of a screen buffer, use GetConsoleScreenBufferInfo. When a screen buffer is created, the upper left corner of its window is at the upper left corner of the screen buffer at (0,0).

The window rectangle can change to display different parts of the screen buffer. The window rectangle of a screen buffer can change in the following situations:

•	When SetConsoleWindowInfo is called to specify a new window rectangle, it scrolls the view of the screen buffer by changing the position of the window rectangle without changing the size of the window. For examples of scrolling the window's contents, see Scrolling a Screen Buffer's Window.

•	When using the WriteFile function to write to a screen buffer with wrap at end-of-line (EOL) output mode enabled, the window rectangle shifts automatically, so the cursor is always displayed.

•	When the SetConsoleCursorPosition function specifies a new cursor position that is outside the boundaries of the current window rectangle, the window rectangle shifts automatically to display the cursor.

•	When the user changes the size of the console window or uses the window's scroll bars, the window rectangle of the active screen buffer can change. This change is not reported as a window resizing event in the input buffer.

In each of these situations, the window rectangle shifts to display a different part of the screen buffer, but the contents of the screen buffer remain in the same position. The following situations can cause the screen buffer's contents to shift:

•	When the ScrollConsoleScreenBuffer function is called, a rectangular block is copied from one part of a screen buffer to another.

•	When using WriteFile to write to a screen buffer with wrap at EOL output mode enabled, the screen buffer's contents scroll automatically when the end of the screen buffer is encountered. This scrolling discards the top row of the screen buffer.

ScrollConsoleScreenBuffer specifies the screen buffer rectangle that is moved and the new upper left coordinates to which the rectangle is copied. This function can scroll a portion or the entire contents of the screen buffer.

The illustration shows a ScrollConsoleScreenBuffer operation that scrolls the entire contents of the screen buffer up by several rows. The contents of the top rows are discarded, and the bottom rows are filled with a specified character and color.

The effects of ScrollConsoleScreenBuffer can be limited by specifying an optional clipping rectangle so that the contents of the screen buffer outside the clipping rectangle are unchanged. The effect of clipping is to create a subwindow (the clipping rectangle) whose contents are scrolled without affecting the rest of the screen buffer. For an example that uses ScrollConsoleScreenBuffer, see Scrolling a Screen Buffer's Contents.

Cursor Appearance and Position

A screen buffer's cursor can be visible or hidden. When it is visible, its appearance can vary, ranging from from completely filling a character cell to appearing as a horizontal line at the bottom of the cell. To retrieve information about the appearance and visibility of the cursor, use the GetConsoleCursorInfo function. This function reports whether the cursor is visible and describes the appearance of the cursor as the percentage of a character cell that it fills. To set the appearance and visibility of the cursor, use the SetConsoleCursorInfo function.

Characters written by the high-level console I/O functions are written at the current cursor location, advancing the cursor to the next location. To determine the current cursor position in the coordinate system of a screen buffer, use GetConsoleScreenBufferInfo. You can use SetConsoleCursorPosition to set the cursor position and, thereby, control the placement of text that is written or echoed by the high-level I/O functions. If you move the cursor, text at the new cursor location is overwritten.

The position, appearance, and visibility of the cursor are set independently for each screen buffer.

Screen Buffer Color Attributes

Each screen buffer character cell stores the color attributes for the colors used in drawing the text and background of that cell. An application can set the color data for each character cell individually, storing the data in the Attributes member of the CHAR_INFO structure for each cell.

The current text attributes of each screen buffer determine the foreground (text) and background colors of characters subsequently written or echoed by the high-level functions. An application can use GetConsoleScreenBufferInfo to determine the current text attributes of a screen buffer and the SetConsoleTextAttribute function to set the text attributes. Changing a screen buffer's text attributes does not affect the display of characters previously written. These text attributes do not affect characters written by the low-level console I/O functions (such as the WriteConsoleOutput or WriteConsoleOutputCharacter function) which either explicitly specify the attributes for each cell that is written or leave the attributes unchanged at the written positions.

The following attribute constants are defined in the WINCON.H header file:

•	FOREGROUND_BLUE

•	FOREGROUND_GREEN

•	FOREGROUND_RED

•	FOREGROUND_INTENSITY

•	BACKGROUND_BLUE

•	BACKGROUND_GREEN

•	BACKGROUND_RED

•	BACKGROUND_INTENSITY

The foreground attributes specify the text color, and the background attributes specify the color used to fill the cell's background. An application can combine the constants to achieve different colors. For example, the following combination results in bright cyan text on a blue background.

FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY | BACKGROUND_BLUE

If no background constant is specified, the background is black, and if no foreground constant is specified, the text is black. For example, the following combination produces black text on a white background.

BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED


Input and Output Methods

The Win32 API provides two very different approaches to console I/O, the choice of which depends on how much flexibility and control an application needs. The high-level approach enables simple character stream I/O, but it limits access to a console's input and screen buffers. The low-level approach requires that developers write more code and choose among a greater range of functions, but it also gives an application more flexibility.

An application can use the file I/O functions, ReadFile and WriteFile, and the console functions, ReadConsole and WriteConsole, for high-level I/O that provides indirect access to a console's input and screen buffers. The high-level input functions filter and process the data in a console's input buffer to return input as a stream of characters, discarding mouse and buffer-resizing input. Similarly, the high-level output functions write a stream of characters that are displayed at the current cursor location in a screen buffer. An application controls the way these functions work by setting a console's I/O modes.

The low-level I/O functions provide direct access to a console's input and screen buffers, enabling an application to access mouse and buffer-resizing input events and extended information for keyboard events. Low-level output functions enable an application to read from or write to a specified number of consecutive character cells in a screen buffer, or to read or write to rectangular blocks of character cells at a specified location in a screen buffer. A console's input modes affect low-level input by enabling the application to determine whether mouse and buffer-resizing events are placed in the input buffer. A console's output modes have no effect on low-level output.

The high-level and low-level I/O methods are not mutually exclusive, and an application can use any combination of these functions. Typically, however, an application uses one approach or the other exclusively.

The sections that follow describe in detail the console modes and the high-level and low-level I/O functions.


Console Modes

Associated with each console input buffer are a set of input modes that affects input operations. Similarly, each console screen buffer has a set of output modes that affects output operations. The input modes can be divided into two groups: those that affect the high-level input functions and those that affect the low-level input functions. The output modes only affect applications that use the high-level output functions.

The GetConsoleMode function reports the current input mode of a console's input buffer or the current output mode of a screen buffer. The SetConsoleMode function sets the current mode of either a console input buffer or a screen buffer. If a console has multiple screen buffers, the output modes of each can be different. An application can change I/O modes at any time. For more information about the console modes that affect high-level and low-level I/O operations, see High-Level Console Modes and Low-Level Console Modes.


High-Level Console I/O

The high-level I/O functions provide a simple way to read a stream of characters from console input or to write a stream of characters to console output. A high-level read operation gets input characters from a console's input buffer and stores them in a specified buffer. A high-level write operation takes characters from a specified buffer and writes them to a screen buffer at the current cursor location, advancing the cursor as each character is written.

High-level I/O gives you a choice between the ReadFile and WriteFile functions and the ReadConsole and WriteConsole functions. They are identical, except for two important differences. The console functions support the use of either Unicode characters or the ANSI character set; the file I/O functions do not support Unicode. Also, the file I/O functions can be used to access files, pipes, and serial communications devices; the console functions can only be used with console handles. This distinction is important if an application relies on standard handles that may have been redirected.

When using either set of high-level functions, an application can control the text and background colors used to display characters subsequently written to a screen buffer. An application can also use the console modes that affect high-level console I/O to enable or disable the following properties:

•	Echoing of keyboard input to the active screen buffer

•	Line input, in which a read operation does not return until the ENTER key is pressed

•	Automatic processing of keyboard input to handle carriage returns, CTRL+C, and other input details

•	Automatic processing of output to handle line wrapping, carriage returns, backspaces, and other output details


High-Level Console Modes

The behavior of the high-level console functions is affected by the console input and output modes. All of the following console input modes are enabled for a console's input buffer when a console is created:

•	Line input mode

•	Processed input mode

•	Echo input mode

Both of the following console output modes are enabled for a console screen buffer when it is created:

•	Processed output mode

•	Wrapping at EOL output mode

All three input modes, along with processed output mode, are designed to work together. It is best to either enable or disable all of these modes as a group. When all are enabled, the application is said to be in "cooked" mode, which means that most of the processing is handled for the application. When all are disabled, the application is in "raw" mode, which means that input is unfiltered and any processing is left to the application.

An application can use the GetConsoleMode function to determine the current mode of a console's input buffer or screen buffer. You can enable or disable any of these modes by using the following values in the SetConsoleMode function. Note that setting the output mode of one screen buffer does not affect the output mode of other screen buffers.

Mode	Description
ENABLE_PROCESSED_INPUT
	Used with a console input handle to cause the system to process any system editing or control key input rather than returning it as input in the read operation's buffer. If line input is also enabled, backspaces and carriage returns are handled correctly. A backspace causes the cursor to move back one space without affecting the character at the cursor position. A carriage return is converted to carriage return − linefeed character combination. If echo input mode is enabled and the output should reflect system editing, processed output must be enabled for the active screen buffer. If processed input is enabled, the CTRL+C key combination is passed on to the appropriate handler regardless of whether line input is enabled. For more information about control handlers, see Console Control Handlers.
ENABLE_LINE_INPUT
	Used with a console input handle to cause the ReadFile and ReadConsole functions to return when the ENTER key is pressed. If line input mode is disabled, the functions return when one or more characters are available in the input buffer.
ENABLE_ECHO_INPUT
	Used with a console input handle to cause keyboard input read by the ReadFile or ReadConsole function to be echoed to the active screen buffer. Characters are echoed only if the process that calls ReadFile or ReadConsole has an open handle of the active screen buffer. Echo mode cannot be enabled unless line input is also enabled. The output mode of the active screen buffer affects the way echoed input is displayed.
ENABLE_PROCESSED_OUTPUT
	Used with a console screen buffer handle to cause the system to perform the appropriate action for ANSI control characters that are written to a screen buffer. The backspace, tab, bell, carriage return, and linefeed characters are processed. A tab character moves the cursor to the next tab stop, which occurs every eight characters. A bell character sounds a short tone.
ENABLE_WRAP_AT_EOL_OUTPUT
	Used with a console screen buffer handle to cause the current output position (cursor position) to move to the first column in the next row (line) when the end of the current row is reached. If the bottom of the window region is reached, the window origin is moved down one row. This movement has the effect of scrolling the contents of the window up one row. If the bottom of the screen buffer is reached, the contents of the screen buffer are scrolled up one row, and the top row of the screen buffer is discarded. If this mode is disabled, the last character in the row is overwritten with any subsequent characters.


High-Level Console Input and Output Functions

The ReadFile and WriteFile functions, or the ReadConsole and WriteConsole functions, enable an application to read console input and write console output as a stream of characters. ReadConsole and WriteConsole behave exactly like ReadFile and WriteFile except that they can be used either as wide-character functions (in which text arguments must use Unicode) or as ANSI functions (in which text arguments must use characters from the Windows 3.x character set). Applications that need to maintain a single set of sources to support either Unicode or the ANSI character set should use ReadConsole and WriteConsole.

ReadConsole and WriteConsole can only be used with console handles; ReadFile and WriteFile can be used with other handles (such as files or pipes). ReadConsole and WriteConsole fail if used with a standard handle that has been redirected and is no longer a console handle.

To get keyboard input, a process can use ReadFile or ReadConsole with a handle of the console's input buffer, or it can use ReadFile to read input from a file or a pipe if STDIN has been redirected. These functions only return keyboard events that can be translated into ANSI characters (or Unicode characters in the case of ReadConsole). The input that can be returned includes control key combinations. The functions do not return keyboard events involving the function keys or arrow keys. Input events generated by mouse, window, focus, or menu input are discarded.

If line input mode is enabled (the default mode), ReadFile and ReadConsole do not return to the calling application until the ENTER key is pressed. If line input mode is disabled, the functions do not return until at least one character is available. In either mode, all available characters are read until either no more keys are available or the specified number of characters has been read. Unread characters are buffered until the next read operation. The functions report the total number of characters actually read. If echo input mode is enabled, characters read by these functions are written to the active screen buffer at the current cursor position.

A process can use WriteFile or WriteConsole to write to either an active or inactive screen buffer, or it can use WriteFile to write to a file or a pipe if STDOUT has been redirected. Processed output mode and wrap at EOL output mode control the way characters are written or echoed to a screen buffer.

Characters written by WriteFile or WriteConsole, or echoed by ReadFile or ReadConsole, are inserted in a screen buffer at the current cursor position. As each character is written, the cursor position advances to the next character cell; however, the behavior at the end of a row depends on the screen buffer's wrap at EOL output mode. An application can use the GetConsoleScreenBufferInfo function to determine the current cursor position and the SetConsoleCursorPosition function to set the cursor position.

For an example that uses the high-level console I/O functions, see Using the High-Level Input and Output Functions.


Low-Level Console I/O

The low-level console I/O functions expand an application's control over console I/O by enabling direct access to a console's input and screen buffers. These functions enable an application to perform the following tasks:

•	Receive input about mouse and buffer-resizing events

•	Receive extended information about keyboard input events

•	Write input records to the input buffer

•	Read input records without removing them from the input buffer

•	Determine the number of pending events in the input buffer

•	Flush the input buffer

•	Read and write strings of Unicode or ANSI characters at a specified location in a screen buffer

•	Read and write strings of text and background color attributes at a specified screen buffer location

•	Read and write rectangular blocks of character and color data at a specified screen buffer location

•	Write a single Unicode or ANSI character, or a text and background color attribute combination, to a specified number of consecutive cells beginning at a specified screen buffer location


Low-Level Console Modes

The types of input events reported in a console's input buffer depend on the console's mouse and window input modes. The console's processed input mode determines how the system handles the CTRL+C key combination. To set or retrieve the state of a console's input modes, an application can specify a console input buffer handle in a call to the SetConsoleMode or GetConsoleMode function. The following modes are used with console input handles.

Mode	Description
ENABLE_MOUSE_INPUT
	Controls whether mouse events are reported in the input buffer. By default, mouse input is enabled and window input is disabled. Changing either of these modes affects only input that occurs after the mode is set; pending mouse or window events in the input buffer are not flushed. The mouse pointer is displayed regardless of the mouse mode.
ENABLE_WINDOW_INPUT
	Controls whether buffer-resizing events are reported in the input buffer. By default, mouse input is enabled and window input is disabled. Changing either of these modes affects only input that occurs after the mode is set; pending mouse or window events in the input buffer are not flushed. The mouse pointer is displayed regardless of the mouse mode.
ENABLE_PROCESSED_INPUT
	Controls the processing of input for applications using the high-level console I/O functions. However, if processed input mode is enabled, the CTRL+C key combination is not reported in the console's input buffer. Instead, it is passed on to the appropriate control handler function. For more information about control handlers, see Console Control Handlers.
The output modes of a screen buffer do not affect the behavior of the low-level output functions.


Low-Level Console Input Functions

A console's input buffer contains input records that can include information about keyboard, mouse, buffer-resizing, focus, and menu events. The low-level functions provide direct access to the input buffer, unlike the high-level functions that filter and process the input buffer's data, discarding all but keyboard input.

The Win32 API provides five low-level functions for accessing a console's input buffer:

•	ReadConsoleInput

•	PeekConsoleInput

•	GetNumberOfConsoleInputEvents

•	WriteConsoleInput

•	FlushConsoleInputBuffer

The ReadConsoleInput, PeekConsoleInput, and WriteConsoleInput functions use the INPUT_RECORD structure to read from or write to an input buffer.

Following are descriptions of the low-level console input functions.

Function	Description
ReadConsoleInput	Reads and removes input records from an input buffer. The function does not return until at least one record is available to be read. Then all available records are transferred to the buffer of the calling process until either no more records are available or the specified number of records has been read. Unread records remain in the input buffer for the next read operation. The function reports the total number of records that have been read. For an example that uses ReadConsoleInput, see Reading Input Buffer Events.
PeekConsoleInput	Reads without removing the pending input records in an input buffer. All available records up to the specified number are copied into the buffer of the calling process. If no records are available, the function returns immediately. The function reports the total number of records that have been read.
GetNumberOfConsoleInputEvents	Determines the number of unread input records in an input buffer.
WriteConsoleInput	Places input records into the input buffer behind any pending records in the buffer. The input buffer grows dynamically, if necessary, to hold as many records as are written. To use this function, the specified input buffer handle must have GENERIC_WRITE access.
FlushConsoleInputBuffer	Discards all unread events in the input buffer. To use this function, the specified input buffer handle must have GENERIC_WRITE access.
A thread of an application's process can perform a wait operation to wait for input to be available in an input buffer. To initiate a wait operation, specify a handle of the input buffer in a call to any of the wait functions (WaitForSingleObject, WaitForMultipleObjects, WaitForSingleObjectEx, or WaitForMultipleObjectsEx). These functions can return when the state of one or more objects is signaled. The state of a console input handle becomes signaled when there are unread records in its input buffer. The state is reset to nonsignaled when the input buffer becomes empty. If there is no input available, the calling thread enters an efficient wait state, consuming very little processor time while waiting for the conditions of the wait operation to be satisfied.


Low-Level Console Output Functions

The low-level console output functions provide direct access to the character cells of a screen buffer. One set of functions reads from or writes to consecutive cells beginning at any location in the screen buffer. Another set of functions reads from or writes to rectangular blocks of cells.

The following functions read from or write to a specified number of consecutive character cells in a screen buffer, beginning with a specified cell.

Function	Description
ReadConsoleOutputCharacter
	Copies a string of Unicode or ANSI characters from a screen buffer.
WriteConsoleOutputCharacter
	Writes a string of Unicode or ANSI characters to a screen buffer.
ReadConsoleOutputAttribute
	Copies a string of text and background color attributes from a screen buffer.
WriteConsoleOutputAttribute
	Writes a string of text and background color attributes to a screen buffer.
FillConsoleOutputCharacter
	Writes a single Unicode or ANSI character to a specified number of consecutive cells in a screen buffer.
FillConsoleOutputAttribute
	Writes a text and background color attribute combination to a specified number of consecutive cells in a screen buffer.
For all of these functions, when the last cell of a row is encountered, reading or writing wraps around to the first cell of the next row. When the end of the last row of the screen buffer is encountered, the write functions discard all unwritten characters or attributes, and the read functions report the number of characters or attributes actually written..

The following functions read from or write to rectangular blocks of character cells at a specified location in a screen buffer.

Function	Description
ReadConsoleOutput
	Copies character and color data from a specified block of screen buffer cells into a given block in a destination buffer.
WriteConsoleOutput
	Writes character and color data to a specified block of screen buffer cells from a given block in a source buffer.
These functions treat screen buffers and source or destination buffers as two-dimensional arrays of CHAR_INFO structures (containing character and color attribute data for each cell). The functions specify the width and height, in character cells, of the source or destination buffer, and the pointer to the buffer is treated as a pointer to the origin cell (0,0) of the two-dimensional array. The functions use a SMALL_RECT structure to specify which rectangle to access in the screen buffer, and the coordinates of the upper left cell in the source or destination buffer determine the location of the corresponding rectangle in that buffer.

These functions automatically clip the specified screen buffer rectangle to fit within the boundaries of the screen buffer. For example, if the rectangle specifies lower right coordinates that are (column 100, row 50) and the screen buffer is only 80 columns wide, the coordinates are clipped so that they are (column 79, row 50). Similarly, this adjusted rectangle is again clipped to fit within the boundaries of the source or destination buffer. The screen buffer coordinates of the actual rectangle that was read from or written to are specified. For an example that uses these functions, see Reading and Writing Blocks of Characters and Attributes.

The illustration shows a ReadConsoleOutput operation where clipping occurs when the block is read from the screen buffer, and again when the block is copied into the destination buffer. The function reports the actual screen buffer rectangle that it copied from.


Console Code Pages

A code page is a mapping of 256 character codes to individual characters. Different code pages include different special characters, typically customized for a language or a group of languages.

Associated with each console are two code pages: one for input and one for output. A console uses its input code page to translate keyboard input into the corresponding character value. It uses its output code page to translate the character values written by the various output functions into the images displayed in the console window. An application can use the SetConsoleCP and GetConsoleCP functions to set and retrieve a console's input code pages and the SetConsoleOutputCP and GetConsoleOutputCP functions to set and retrieve its output code pages.

The identifiers of the code pages available on the local computer are stored in the registry under the following key.

%HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Nls\\CodePage%

For information about using the registry functions to determine the available code pages, see Registry.

For more information about code pages, see String Manipulation.


Console Control Handlers

Each console process has its own list of control handler functions that are called by the system when the process receives a CTRL+C, CTRL+BREAK, or CTRL+CLOSE signal. Initially, the list of control handlers for each process contains only a default handler function that calls the ExitProcess function. A console process can add or remove additional handler functions by calling the SetConsoleCtrlHandler function. This function does not affect the lists of control handlers for other processes. When a console process receives any of the control signals, it calls the handler functions on a last-registered, first-called basis until one of the handlers returns TRUE. If none of the handlers returns TRUE, the default handler is called.

The following typedef declaration illustrates the format of a control handler function.

typedef BOOL (*PHANDLER_ROUTINE)(DWORD dwCtrlType);

The function's dwCtrlType parameter identifies which control signal was received, and the return value indicates whether the signal was handled.

For an example of a control handler function, see Registering a Control Handler Function.


CTRL+C and CTRL+BREAK Signals

The CTRL+C and CTRL+BREAK key combinations receive special handling by console processes. By default, when a console window has the keyboard focus, CTRL+C or CTRL+BREAK is treated as a signal (SIGINT or SIGBREAK) and not as keyboard input. By default, these signals are passed to all console processes that are attached to the console, causing the system to call the control handler function or functions associated with these processes. Detached processes (GUI processes or console processes started with the DETACHED_PROCESS or CREATE_NEW_CONSOLE flag) are not affected.

CTRL+BREAK is always treated as a signal, but an application can change the default CTRL+C behavior in two ways that prevent the handler functions from being called:

•	The SetConsoleMode function can disable the ENABLE_PROCESSED_INPUT input mode for a console's input buffer, so CTRL+C is reported as keyboard input rather than as a signal.

•	When SetConsoleCtrlHandler is called with NULL and TRUE values for its parameters, the calling process ignores CTRL+C signals. Normal CTRL+C processing is restored by calling SetConsoleCtrlHandler with NULL and FALSE values. This attribute of ignoring or not ignoring CTRL+C signals is inherited by child processes, but it can be enabled or disabled by any process without affecting existing processes.


CTRL+CLOSE Signal

The system generates a CTRL+CLOSE signal when the user closes a console. All processes attached to the console receive the signal, giving each process an opportunity to clean up before termination. When a process receives this signal, the handler function can take one of the following actions after performing any cleanup operations:

•	Call ExitProcess to terminate the process.

•	Return FALSE. If none of the registered handler functions returns TRUE, the default handler terminates the process.

•	Return TRUE. In this case, no other handler functions are called, and a pop-up dialog box asks the user whether to terminate the process. If the user chooses not to terminate the process, the system does not close the console until the process finally terminates.


Console Process Groups

When a process uses the CreateProcess function to create a new console process, it can specify the CREATE_NEW_PROCESS_GROUP flag to make the new process the root process of a console process group. The process group includes all processes that are descendants of the root process.

A process can use the GenerateConsoleCtrlEvent function to send a CTRL+C or CTRL+BREAK signal to all processes in a console process group. The signal is only received by those processes in the group that are attached to the same console as the process that called GenerateConsoleCtrlEvent.


Using the Console

•	Using the high-level input and output functions

•	Writing characters or colors to consecutive cells

•	Reading and writing blocks of characters and attributes

•	Reading input buffer events

•	Scrolling a screen buffer's window

•	Scrolling a screen buffer's contents

•	Registering a control handler function

•	Console application issues


Using the High-Level Input and Output Functions

The following example uses the high-level console I/O functions for console I/O. For more information about the high-level console I/O functions, see High-Level Console I/O.

The example assumes that the default I/O modes are in effect initially for the first calls to the ReadFile and WriteFile functions. Then the input mode is changed to turn off line input mode and echo input mode for the second calls to ReadFile and WriteFile. The SetConsoleTextAttribute function is used to set the colors in which subsequently written text will be displayed. Before exiting, the program restores the original console input mode and color attributes.

The example's NewLine function is used when line input mode is disabled. It handles carriage returns by moving the cursor position to the first cell of the next row. If the cursor is already in the last row of the screen buffer, the contents of the screen buffer are scrolled up one line. For an example that illustrates the use of the ScrollConsoleScreenBuffer function to scroll a screen buffer, see Scrolling a Screen Buffer's Contents.

#include <windows.h>

VOID NewLine(VOID);

VOID ScrollScreenBuffer(HANDLE, INT);

HANDLE hStdout, hStdin;

CONSOLE_SCREEN_BUFFER_INFO csbiInfo;

VOID main(void) {

LPSTR lpszPrompt1 = "Type something and press Enter:\n";

LPSTR lpszPrompt2 = "Type any key: ";

CHAR chBuffer[256];

DWORD cRead, cWritten, fdwMode, fdwOldMode;

WORD wOldColorAttrs;

/* Get handles to STDIN and STDOUT. */

hStdin = GetStdHandle(STD_INPUT_HANDLE);

hStdout = GetStdHandle(STD_OUTPUT_HANDLE);

if (hStdin == INVALID_HANDLE_VALUE ||

        hStdout == INVALID_HANDLE_VALUE)

    MyErrorExit("GetStdHandle");

/* Save the current text colors. */

if (! GetConsoleScreenBufferInfo(hStdout, &csbiInfo))

    MyErrorExit("GetConsoleScreenBufferInfo");

wOldColorAttrs = csbiInfo.wAttributes;

/* Set the text attr. to draw red text on black background. */

if (! SetConsoleTextAttribute(hStdout, FOREGROUND_RED))

        MyErrorExit("SetConsoleTextAttribute");

/*

 * Write to STDOUT and read from STDIN by using the default

 * modes. Input is echoed automatically, and ReadFile

 * does not return until a carriage return is typed.

 *

 * The default input modes are line, processed, and echo.

 * The default output modes are processed and wrap at EOL.

 */

while (1) {

    if (! WriteFile(

            hStdout,              /* output handle  */

            lpszPrompt1,          /* prompt string  */

            lstrlen(lpszPrompt1), /* string length  */

            &cWritten,            /* bytes written  */

            NULL) )               /* not overlapped */

        break;

    if (! ReadFile(

            hStdin,    /* input handle        */

            chBuffer,  /* buffer to read into */

            255,       /* size of buffer      */

            &cRead,    /* actual bytes read   */

            NULL) )    /* not overlapped      */

        break;

    if (chBuffer[0] == 'q') break;

}

/* Turn off the line input mode, and echo the input mode. */

if (! GetConsoleMode(hStdin, &fdwOldMode))

    MyErrorExit("GetConsoleMode");

fdwMode = fdwOldMode &

          ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT);

if (! SetConsoleMode(hStdin, fdwMode))

    MyErrorExit("SetConsoleMode");

/* Prompt for input. */

if (! WriteFile(

        hStdout,              /* output handle  */

        lpszPrompt2,          /* prompt string  */

        lstrlen(lpszPrompt2), /* string length  */

        &cWritten,            /* bytes written  */

        NULL) )               /* not overlapped */

    MyErrorExit("WriteFile");

/*

 * Without line and echo input modes, ReadFile returns

 * when any input is available. Carriage returns must

 * be handled, and WriteFile is used to echo input.

 */

while (1) {

    if (! ReadFile(hStdin, chBuffer, 1, &cRead, NULL))

        break;

    if (chBuffer[0] == '\r')

        NewLine();

    else

        if (! WriteFile(hStdout, chBuffer, cRead,

                        &cWritten, NULL))

            break;

    if (chBuffer[0] == 'q') break;

}

/* Restore the original console mode. */

if (! SetConsoleMode(hStdin, fdwOldMode))

    MyErrorExit("SetConsoleMode");

/* Restore the original text colors. */

if (! SetConsoleTextAttribute(hStdout, wOldColorAttrs))

    MyErrorExit("SetConsoleTextAttribute");

}

/*

 * The NewLine function handles carriage returns when the processed

 * input mode is disabled. It gets the current cursor position

 * and resets it to the first cell of the next row.

 */

VOID NewLine(VOID) {

if (! GetConsoleScreenBufferInfo(hStdout, &csbiInfo))

    MyErrorExit("GetConsoleScreenBufferInfo");

csbiInfo.dwCursorPosition.X = 0;

/*

 * If it is the last line in the screen buffer, scroll

 * the buffer up.

 */

if ((csbiInfo.dwSize.Y-1) == csbiInfo.dwCursorPosition.Y) {

    ScrollScreenBuffer(hStdout, 1);

}

/* Otherwise, advance the cursor to the next line. */

else

    csbiInfo.dwCursorPosition.Y += 1;

if (! SetConsoleCursorPosition(hStdout,

              csbiInfo.dwCursorPosition))

    MyErrorExit("SetConsoleCursorPosition");

}


Writing Characters or Colors to Consecutive Cells

Characters or color attributes can be written to specified character cells in a screen buffer. The following example uses the WriteConsoleOutputCharacter function to write a string of characters beginning at the upper left corner of a screen buffer. Then the example uses the WriteConsoleOutputAttribute function to write a string of color attributes to the first 51 cells of the same row. The coord parameter for both functions specifies the character cell in the screen buffer at which writing begins. The location in the console window where these characters or colors appear depends on the current window rectangle of the screen buffer. For additional information about the relationship between a screen buffer and its windows, see Window and Screen Buffer Size and Scrolling the Screen Buffer.

    HANDLE hOutput;

    LPTSTR lpszString = "Character String";

    DWORD cWritten;

    BOOL fSuccess;

    COORD coord;

    WORD wColors[3], wColor;

    CHAR chFillChar;

/* Write a string of characters to a screen buffer. */

    coord.X = 0;            /* start at first cell */

    coord.Y = 0;            /*   of first row      */

    fSuccess = WriteConsoleOutputCharacter(

        hOutput,              /* screen buffer handle     */

        lpszString,           /* pointer to source string */

        lstrlen(lpszString),  /* length of string         */

        coord,                /* first cell to write to   */

        &cWritten);           /* actual number written to */

    if (! fSuccess)

        MyErrorExit("WriteConsoleOutputCharacter");

/* Write a string of colors to a screen buffer. */

    wColors[0] = BACKGROUND_RED;

    wColors[1] = BACKGROUND_RED |     /* white background */

                 BACKGROUND_GREEN |

                 BACKGROUND_BLUE;

    wColors[2] = BACKGROUND_BLUE;

    for (;fSuccess && coord.X < 50; coord.X += 3)

        fSuccess = WriteConsoleOutputAttribute(

            hOutput,          /* screen buffer handle     */

            wColors,          /* pointer to source string */

            3,                /* length of string         */

            coord,            /* first cell to write to   */

            &cWritten);       /* actual number written to */

    if (! fSuccess)

        MyErrorExit("WriteConsoleOutputAttribute");

The same character or color attribute can be written to a specified number of consecutive screen buffer cells beginning at a specified location. The following example uses the FillConsoleOutputCharacter function to clear a 80-by-50-character screen buffer, and then it uses the FillConsoleOutputAttribute function to set the color attributes of the same cells.

/* Fill an 80-by-50-character screen buffer with the space character. */

    coord.X = 0;            /* start at first cell */

    coord.Y = 0;            /*   of first row      */

    chFillChar = ' ';

    fSuccess = FillConsoleOutputCharacter(

        hStdout,          /* screen buffer handle     */

        chFillChar,       /* fill with spaces         */

        80*50,            /* number of cells to fill  */

        coord,            /* first cell to write to   */

        &cWritten);       /* actual number written to */

    if (! fSuccess)

        MyErrorExit("FillConsoleOutputCharacter");

/* Set 80-by-50-character screen buffer colors to white text on red. */

    wColor = BACKGROUND_RED |

             FOREGROUND_RED |

             FOREGROUND_GREEN |

             FOREGROUND_BLUE;

    fSuccess = FillConsoleOutputAttribute(

        hStdout,          /* screen buffer handle     */

        wColor,           /* color to fill with       */

        80*50,            /* number of cells to fill  */

        coord,            /* first cell to write to   */

        &cWritten);       /* actual number written to */

    if (! fSuccess)

        MyErrorExit("FillConsoleOutputAttribute");


Reading and Writing Blocks of Characters and Attributes

The ReadConsoleOutput function copies a rectangular block of character and color attribute data from a console screen buffer into a destination buffer. The function treats the destination buffer as a two-dimensional array of CHAR_INFO structures. Similarly, the WriteConsoleOutput function copies a rectangular block of character and color attribute data from a source buffer to a console screen buffer. For more information about reading from or writing to rectangular blocks of screen buffer cells, see Input and Output Methods.

The following example uses the CreateConsoleScreenBuffer function to create a new screen buffer. After the SetConsoleActiveScreenBuffer function makes this the active screen buffer, a block of characters and color attributes is copied from the top two rows of the SDTOUT screen buffer into a temporary buffer. The data is then copied from the temporary buffer into the new active screen buffer. When the application is finished using the new screen buffer, it calls SetConsoleActiveScreenBuffer to restore the original STDOUT screen buffer.

#include <windows.h>

VOID main(void) {

    HANDLE hStdout, hNewScreenBuffer;

    SMALL_RECT srctReadRect;

    SMALL_RECT srctWriteRect;

    CHAR_INFO chiBuffer[160]; // [2][80];

    COORD coordBufSize;

    COORD coordBufCoord;

    BOOL fSuccess;

    /*

     * Get a handle of the STDOUT screen buffer to copy from and

     * create a new screen buffer to copy to.

     */

    hStdout = GetStdHandle(STD_OUTPUT_HANDLE);

    hNewScreenBuffer = CreateConsoleScreenBuffer(

       GENERIC_READ |           /* read-write access      */

       GENERIC_WRITE,

       0,                       /* not shared             */

       NULL,                    /* no security attributes */

       CONSOLE_TEXTMODE_BUFFER, /* must be TEXTMODE       */

       NULL);                   /* reserved; must be NULL */

    if (hStdout == INVALID_HANDLE_VALUE ||

            hNewScreenBuffer == INVALID_HANDLE_VALUE)

        MyErrorExit("CreateConsoleScreenBuffer");

    /* Make the new screen buffer the active screen buffer. */

    if (! SetConsoleActiveScreenBuffer(hNewScreenBuffer) )

        MyErrorExit("SetConsoleActiveScreenBuffer");

    /* Set the source rectangle. */

    srctReadRect.Top = 0;    /* top left: row 0, col 0  */

    srctReadRect.Left = 0;

    srctReadRect.Bottom = 1; /* bot. right: row 1, col 79 */

    srctReadRect.Right = 79;

    /* The temporary buffer size is 2 rows x 80 columns. */

    coordBufSize.Y = 2;

    coordBufSize.X = 80;

    /*

     * The top left destination cell of the temporary buffer is

     * row 0, col 0.

     */

    coordBufCoord.X = 0;

    coordBufCoord.Y = 0;

    /* Copy the block from the screen buffer to the temp. buffer. */

    fSuccess = ReadConsoleOutput(

       hStdout,        /* screen buffer to read from       */

       chiBuffer,      /* buffer to copy into              */

       coordBufSize,   /* col-row size of chiBuffer        */

       coordBufCoord,  /* top left dest. cell in chiBuffer */

       &srctReadRect); /* screen buffer source rectangle   */

    if (! fSuccess)

        MyErrorExit("ReadConsoleOutput");

    /* Set the destination rectangle. */

    srctWriteRect.Top = 10;    /* top lt: row 10, col 0 */

    srctWriteRect.Left = 0;

    srctWriteRect.Bottom = 11; /* bot. rt: row 11, col 79 */

    srctWriteRect.Right = 79;

    /* Copy from the temporary buffer to the new screen buffer. */

    fSuccess = WriteConsoleOutput(

        hNewScreenBuffer, /* screen buffer to write to    */

        chiBuffer,        /* buffer to copy from          */

        coordBufSize,     /* col-row size of chiBuffer    */

        coordBufCoord, /* top left src cell in chiBuffer  */

        &srctWriteRect); /* dest. screen buffer rectangle */

    if (! fSuccess)

        MyErrorExit("WriteConsoleOutput");

    Sleep(10000);

    /* Restore the original active screen buffer. */

    if (! SetConsoleActiveScreenBuffer(hStdout))

        MyErrorExit("SetConsoleActiveScreenBuffer");

}


Reading Input Buffer Events

The ReadConsoleInput function can be used to directly access a console's input buffer. When a console is created, mouse input is enabled and window input is disabled. To ensure that the process receives all types of events, this example uses the SetConsoleMode function to enable window and mouse input. Then it goes into a loop that reads and handles console input events.

VOID MouseEventProc(MOUSE_EVENT_RECORD);

VOID ResizeEventProc(WINDOW_BUFFER_SIZE_RECORD);

VOID KeyEventProc(KEY_EVENT_RECORD);

VOID GetInputEvents(VOID);

DWORD main(VOID) {

    HANDLE hStdin;

    DWORD cNumRead, fdwMode, fdwSaveOldMode, i;

    INPUT_RECORD irInBuf[128];

    /* Get the standard input handle. */

    hStdin = GetStdHandle(STD_INPUT_HANDLE);

    if (hStdin == INVALID_HANDLE_VALUE)

        MyErrorExit("GetStdHandle");

    /* Save the current input mode, to be restored on exit. */

    if (! GetConsoleMode(hStdin, &fdwSaveOldMode) )

        MyErrorExit("GetConsoleMode");

    /* Enable the window and mouse input events. */

    fdwMode = ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT;

    if (! SetConsoleMode(hStdin, fdwMode) )

        MyErrorExit("SetConsoleMode");

    /* Loop to read and handle the input events. */

    while (1) {

        /* Wait for the events. */

        if (! ReadConsoleInput(

                hStdin,      /* input buffer handle    */

                irInBuf,     /* buffer to read into    */

                128,         /* size of read buffer    */

                &cNumRead) ) /* number of records read */

            MyErrorExit("ReadConsoleInput");

        /* Dispatch the events to the appropriate handler. */

        for (i = 0; i < cNumRead; i++)

            switch(irInBuf[i].EventType) {

                case KEY_EVENT: /* keyboard input */

                    KeyEventProc(irInBuf[i].Event.KeyEvent);

                    break;

                case MOUSE_EVENT: /* mouse input */

                    MouseEventProc(irInBuf[i].Event.MouseEvent);

                    break;

                case WINDOW_BUFFER_SIZE_EVENT: /* scrn buf. resizing */

                    ResizeEventProc(

                        irInBuf[i].Event.WindowBufferSizeEvent);

                    break;

                case FOCUS_EVENT:  /* disregard focus events */

                case MENU_EVENT:   /* disregard menu events  */

                    break;

                default:

                    MyErrorExit("unknown event type");

                    break;

            }

    }

    return 0;

}


Scrolling a Screen Buffer's Window

The SetConsoleWindowInfo function can be used to scroll the contents of a screen buffer in the console window. This function can also change the window size. The function can either specify the new upper left and lower right corners of the screen buffer's window as absolute screen buffer coordinates or specify the changes from the current window coordinates. The function fails if the specified window coordinates are outside the boundaries of the screen buffer.

The following example scrolls the view of the screen buffer up one row by modifying the absolute window coordinates returned by the GetConsoleScreenBufferInfo function.

HANDLE hStdout;

CONSOLE_SCREEN_BUFFER_INFO csbiInfo;

SMALL_RECT srctWindow;

hStdout = GetStdHandle(STD_OUTPUT_HANDLE);

/* Get the current screen buffer size and window position. */

if (! GetConsoleScreenBufferInfo(hStdout, &csbiInfo))

    MyErrorExit("GetConsoleScreenBufferInfo");

/* Set srctWindow to the current window size and location. */

srctWindow = csbiInfo.srWindow;

/* If window is not at the screen buffer top, move it up one line. */

if ( srctWindow.Top > 0 ) {

    srctWindow.Top -= 1;      /* move top up by one row    */

    srctWindow.Bottom -= 1;   /* move bottom up by one row */

    if (! SetConsoleWindowInfo(

               hStdout,      /* screen buffer handle       */

               TRUE,         /* absolute coordinates       */

               &srctWindow)) /* specifies new location     */

        MyErrorExit("SetConsoleWindowInfo");

}

The same scrolling can be done by specifying changes in the window coordinates.

/* Get the current screen buffer window position. */

if (! GetConsoleScreenBufferInfo(hStdout, &csbiInfo))

    MyErrorExit("GetConsoleScreenBufferInfo");

/*If window is not at the screen buffer top, move it up one line. */

if (csbiInfo.srWindow.Top > 0) {

    srctWindow.Top = -1;      /* move top up by one row    */

    srctWindow.Bottom = -1;   /* move bottom up by one row */

    srctWindow.Left = 0;      /* no change                 */

    srctWindow.Right = 0;     /* no change                 */

    if (! SetConsoleWindowInfo(

               hStdout,      /* screen buffer handle   */

               FALSE,        /* deltas, not absolute   */

               &srctWindow)) /* specifies new location */

        MyErrorExit("SetConsoleWindowInfo");

}


Scrolling a Screen Buffer's Contents

The ScrollConsoleScreenBuffer function moves a block of character cells from one part of a screen buffer to another part of the same screen buffer. The function specifies the upper left and lower right cells of the source rectangle to be moved and the destination coordinates of the new location for the upper left cell. The character and color data in the source cells is moved to the new location, and any cells left empty by the move are filled in with a specified character and color. If a clipping rectangle is specified, the cells outside of it are left unchanged.

ScrollConsoleScreenBuffer can be used to delete a line by specifying coordinates of the first cell in the line as the destination coordinates and specifying a scrolling rectangle that includes all the rows below the line.

The following example shows the use of a clipping rectangle to scroll only the bottom 15 rows of the screen buffer. The rows in the specified rectangle are scrolled up one line at a time, and the top row of the block is discarded. The contents of the screen buffer outside the clipping rectangle are left unchanged.

HANDLE hStdout;

BOOL fSuccess;

CONSOLE_SCREEN_BUFFER_INFO csbiInfo;

SMALL_RECT srctScrollRect, srctClipRect;

CHAR_INFO chiFill;

COORD coordDest;

hStdout = GetStdHandle(STD_OUTPUT_HANDLE);

if (hStdout == INVALID_HANDLE_VALUE)

    MyErrorExit("GetStdHandle");

/* Get the screen buffer size. */

fSuccess = GetConsoleScreenBufferInfo(hStdout, &csbiInfo);

if (! fSuccess)

    MyErrorExit("GetConsoleScreenBufferInfo");

/*

 * The scrolling rectangle is the bottom 15 rows of the

 * screen buffer.

 */

srctScrollRect.Top = csbiInfo.dwSize.Y - 16;

srctScrollRect.Bottom = csbiInfo.dwSize.Y - 1;

srctScrollRect.Left = 0;

srctScrollRect.Right = csbiInfo.dwSize.X - 1;

/* The destination for the scroll rectangle is one row up. */

coordDest.X = 0;

coordDest.Y = csbiInfo.dwSize.Y - 17;

/*

 * The clipping rectangle is the same as the scrolling rectangle.

 * The destination row is left unchanged.

 */

srctClipRect = srctScrollRect;

/* Fill the bottom row with green blanks. */

chiFill.Attributes = BACKGROUND_GREEN | FOREGROUND_RED;

chiFill.Char.AsciiChar = ' ';

/* Scroll up one line. */

fSuccess = ScrollConsoleScreenBuffer(

    hStdout,         /* screen buffer handle     */

    &srctScrollRect, /* scrolling rectangle      */

    &srctClipRect,   /* clipping rectangle       */

    coordDest,       /* top left destination cell*/

    &chiFill);       /* fill character and color */


Registering a Control Handler Function

This section shows an example of the SetConsoleCtrlHandler function that is used to install a control handler.

When a CTRL+C signal is received, the control handler returns TRUE, indicating that it has handled the signal. Doing this prevents other control handlers from being called.

When a CTRL_CLOSE_EVENT signal is received, the control handler returns TRUE, causing the system to display a dialog box that gives the user the choice of terminating the process and closing the console or allowing the process to continue execution. If the user chooses not to terminate the process, the system closes the console when the process finally terminates.

When a CTRL+BREAK, CTRL_LOGOFF_EVENT, or CTRL_SHUTDOWN_EVENT signal is received, the control handler returns FALSE. Doing this causes the signal to be passed to the next control handler function. If no other control handlers have been registered or none of the registered handlers returns TRUE, the default handler will be used, resulting in the process being terminated.

BOOL CtrlHandler(DWORD fdwCtrlType) {

    switch (fdwCtrlType) {

        /* Handle the CTRL+C signal. */

        case CTRL_C_EVENT:

            Beep(1000, 1000);

            return TRUE;

        /* CTRL+CLOSE: confirm that the user wants to exit. */

        case CTRL_CLOSE_EVENT:

            return TRUE;

        /* Pass other signals to the next handler. */

        case CTRL_BREAK_EVENT:

        case CTRL_LOGOFF_EVENT:

        case CTRL_SHUTDOWN_EVENT:

        default:

            return FALSE;

    }

}

VOID main(void) {

BOOL fSuccess;

fSuccess = SetConsoleCtrlHandler(

    (PHANDLER_ROUTINE) CtrlHandler,  /* handler function */

    TRUE);                           /* add to list      */

if (! fSuccess)

    MyErrorExit("Could not set control handler");


Console Application Issues

The 8-bit console functions use the OEM code page. All other functions use the ANSI code page by default. This means that strings returned by the console functions may not be processed correctly by the other functions and vice versa. For example, if FindFirstFileA returns a string that contains certain extended ANSI characters, WriteConsoleA will not display the string properly.

The best long-term solution for a console application is to use Unicode. Barring that solution, a console application should use the SetFileApisToOEM function. That function changes relevant Win32 file functions so that they produce OEM character set strings rather than ANSI character set strings.

Following are the Win32 file functions:

_lopen	GetDriveType	LoadLibrary
CopyFile	GetFileAttributes	LoadLibraryEx
CreateDirectory	GetFullPathName	MoveFile
CreateFile	GetModuleFileName	MoveFileEx
CreateProcess	GetModuleHandle	OpenFile
DeleteFile	GetSystemDirectory	RemoveDirectory
FindFirstFile	GetTempFileName	SearchPath
FindNextFile	GetTempPath	SetCurrentDirectory
GetCurrentDirectory	GetVolumeInformation	SetFileAttributes
GetDiskFreeSpace	GetWindowsDirectory
When dealing with command lines, a console application should obtain the command line in Unicode form and convert it to OEM form, using the relevant  character-to-OEM functions. Note, also, that argv uses the ANSI character set.


Console Reference

The following functions and structures are associated with accessing a console.


Console Functions

Following are the functions used to access a console.

AllocConsole
CreateConsoleScreenBuffer
FillConsoleOutputAttribute
FillConsoleOutputCharacter
FlushConsoleInputBuffer
FreeConsole
GenerateConsoleCtrlEvent
GetConsoleCP
GetConsoleCursorInfo
GetConsoleMode
GetConsoleOutputCP
GetConsoleScreenBufferInfo
GetConsoleTitle
GetLargestConsoleWindowSize
GetNumberOfConsoleInputEvents
GetNumberOfConsoleMouseButtons
GetStdHandle
HandlerRoutine
PeekConsoleInput
ReadConsole
ReadConsoleInput
ReadConsoleOutput
ReadConsoleOutputAttribute
ReadConsoleOutputCharacter
ScrollConsoleScreenBuffer
SetConsoleActiveScreenBuffer
SetConsoleCP
SetConsoleCtrlHandler
SetConsoleCursorInfo
SetConsoleCursorPosition
SetConsoleMode
SetConsoleOutputCP
SetConsoleScreenBufferSize
SetConsoleTextAttribute
SetConsoleTitle
SetConsoleWindowInfo
SetStdHandle
WriteConsole
WriteConsoleInput
WriteConsoleOutput
WriteConsoleOutputAttribute
WriteConsoleOutputCharacter


Console Structures

Following are the structures used to access a console.

CHAR_INFO
CONSOLE_CURSOR_INFO
CONSOLE_SCREEN_BUFFER_INFO
FOCUS_EVENT_RECORD
INPUT_RECORD
MENU_EVENT_RECORD
WINDOW_BUFFER_SIZE_RECORD


Data Decompression Library

This overview describes important concepts relating to data compression and describes the decompression functions in LZEXPAND.DLL.


About the Data Decompression Library

The Microsoft® Windows® operating system includes a dynamic-link library (DLL) named LZEXPAND.DLL. Typically, an application calls functions in LZEXPAND.DLL to decompress data previously compressed by using the Microsoft File Compression Utility (COMPRESS.EXE).


Data Compression

Data compression is an operation that reduces the size of a file by minimizing redundant data. In a file that contains text, redundant data can be frequently occurring characters, such as the space character, or common vowels, such as the letters e and a; it can also be frequently occurring character strings. Data compression creates a compressed version of a file by minimizing this redundant data.

Each type of data-compression algorithm minimizes redundant data in a unique manner. For example, the Huffman encoding algorithm assigns a code to characters in a file based on how frequently those characters occur. Another compression algorithm, called run-length encoding, generates a two-part value for repeated characters: the first part specifies the number of times the character is repeated, and the second part identifies the character. Another compression algorithm, known as the Lempel-Ziv algorithm, converts variable-length strings into fixed-length codes that consume less space than the original strings.

To compress large applications or data files, you can run COMPRESS.EXE from the command line. COMPRESS.EXE uses the Lempel-Ziv compression algorithm.


Data Decompression

Applications can call the functions in LZEXPAND.DLL to decompress files compressed by using COMPRESS.EXE. The functions can also process uncompressed files without attempting to decompress them. To use these functions, applications must include the LZEXPAND.H header file.

The following table describes each function found in LZEXPAND.DLL.

Function	Purpose
CopyLZFile	This function is obsolete. It is provided to simplify porting of 16-bit Windows-based applications. Win32-based applications should use the LZCopy function.
GetExpandedName	Retrieves the original name of a compressed file, if the /r option was used during compression of the file.
LZClose	Closes a file that was opened when the application called the LZOpenFile function.
LZCopy	Copies a source file to a destination file. If the source file is compressed, this function creates a decompressed destination file. If the source file is not compressed, this function duplicates the original file. This function is intended for single-file copy operations.
LZDone	This function is obsolete and should not be used in Win32-based applications. It is provided to simplify porting of 16-bit Windows-based applications.
LZInit	Creates structures used for decompressing files.
LZOpenFile	Opens a file and returns a handle that identifies it.
LZRead	Reads a specified number of bytes from a file. If the file is compressed, this function decompresses the bytes before copying them to the destination buffer.
LZSeek	Positions the file pointer within the decompressed image of a compressed file. The application calls this function to position the pointer before calling the LZRead function.
LZStart	This function is obsolete and should not be used in Win32-based applications. It is provided to simplify porting of 16-bit Windows-based applications.


Using the Data Decompression Library

Functions in LZEXPAND.DLL can be used to decompress single or multiple files. They can also be used to decompress compressed files a portion at a time.

•	Decompressing a single file

•	Decompressing multiple files

•	Reading bytes from compressed files


Decompressing a Single File

An application can decompress a single compressed file by performing the following tasks.

1.	Open the source file by calling the LZOpenFile function.

2.	Open the destination file by calling LZOpenFile.

3.	Copy the source file to the destination file by calling the LZCopy function and passing the handles returned by LZOpenFile.

4.	Close the files by calling the LZClose function.


Decompressing Multiple Files

An application can decompress multiple files by performing the following tasks.

1.	Open the source files by calling the LZOpenFile function.

2.	Open the destination files by calling LZOpenFile.

3.	Copy the source files to the destination files by calling the LZCopy function.

4.	Close the files by calling the LZClose function.


Reading Bytes from Compressed Files

In addition to decompressing a complete file in a single operation, an application can decompress a compressed file a portion at a time by using the LZSeek and LZRead functions. These functions are particularly useful when it is necessary to extract parts of large files. For example, a font manufacturer may have compressed files containing font metrics in addition to character data. To use the information in these files, an application would need to decompress the file; however, most applications would use only part of the file at any particular time. To get information about font metrics, the application would extract data from the header. To get information from the text, the application would reposition the file pointer by calling LZSeek and extract character data by calling LZRead.


Data Decompression Library Functions

Following are the functions used to decompress files.

GetExpandedName
LZClose
LZCopy
LZInit
LZOpenFile
LZRead
LZSeek

Obsolete or Deleted Functions

CopyLZFile
LZDone
LZStart


Debugging

A debugger is an application that enables a developer to observe and correct programming errors.

The first section of this overview describes the debugging-specific features of certain standard Windows functions — specifically, process, thread, and exception-handling functions.

The second section of this overview describes the Windows debugging functions. These functions enable an application to wait for debugging events, cause breakpoint exceptions, transfer execution control to the debugger, and so on.


About Debugging Support

Microsoft® Windows® supports several functions that can be used to create a basic, event-driven debugger. "Event-driven" means that the debugger is notified every time certain events occur in the process being debugged. Notification enables the debugger to take appropriate action in response to the events.


Support from Process, Thread, and Exception Functions

Some functions essential to debugging are actually part of the process, thread, or exception-handling architectures. This section describes how to start a process that is going to be debugged and how to examine and manipulate the context and execution of a thread. It also describes how a debugger should handle exceptions.


Process Functions

The CreateProcess function enables a debugger to start a process and debug it. The fdwCreate parameter of CreateProcess is used to specify the type of debugging operation. If the DEBUG_PROCESS flag is specified for the parameter, a debugger debugs the new process and all of the process's descendants, provided that the descendants are created without the DEBUG_PROCESS flag.

If the DEBUG_PROCESS and DEBUG_ONLY_THIS_PROCESS flags are specified for fdwCreate, a debugger debugs the new process but none of its descendants.

One debugger can debug another by creating a process with the DEBUG_PROCESS flag. The new process (the debugger being debugged) must then create a process with the DEBUG_PROCESS flag.

The OpenProcess function enables a debugger to obtain the identifier of an existing process. (The DebugActiveProcess function uses this identifier to attach the debugger to the process.) Typically, debuggers open a process with the PROCESS_VM_READ and PROCESS_VM_WRITE flags. Using these flags enables the debugger to read from and write to the virtual memory of the process by using the ReadProcessMemory and WriteProcessMemory functions. For more information about processes, see Processes and Threads.


Thread Functions

The CreateThread function creates a new thread for a process. Debuggers typically need to examine or change the contents of a thread's registers. To accomplish this, a debugger must obtain a handle of the thread by using the DuplicateHandle function and specifying the appropriate access to the thread (THREAD_GET_CONTEXT, THREAD_SET_CONTEXT, or both).

A process with appropriate access to a thread can examine the thread's registers by using the GetThreadContext function and set the contents of the thread's registers by using the SetThreadContext function.

A process can also obtain THREAD_SUSPEND_RESUME access to a thread. This type of access enables a debugger to control a thread's execution with the SuspendThread and ResumeThread functions. For more information about threads, see Processes and Threads.


Exception Handling for Debugging

When an exception occurs in a process that is being debugged, the kernel notifies the debugger by passing the exception to it. This is known as first-chance notification. The kernel then suspends all threads in the process being debugged.

If the debugger does not handle the exception, the kernel attempts to locate an appropriate exception handler. If the kernel cannot locate an appropriate one, the kernel again notifies the debugger that an exception has occurred. This is known as last-chance notification. If the debugger does not handle the exception after the last-chance notification, the kernel terminates the process being debugged.

For more information about exception handling, see Structured Exception Handling.


Debugging Functions

Although most of the Windows debugging functions are used to create a debugger, several functions are designed for use in the process being debugged.

To start a process and debug it, a debugger must use CreateProcess, as described in the previous section.

To debug a process that is already executing, the debugger should use DebugActiveProcess with the process identifier retrieved by OpenProcess. DebugActiveProcess attaches the debugger to the active process. In this case, only the active process can be debugged; its descendants cannot. The debugger must have appropriate access to the executing process to use DebugActiveProcess. For more information about access rights, see Security.

After the debugger has either created or attached itself to the process it intends to debug, the kernel notifies the debugger of all debugging events that occur in the process, and, if specified, in the process's descendants. For more information about debugging events, see Debugging Events.

The debugger uses the WaitForDebugEvent function at the beginning of its main loop. This function blocks the debugger until a debugging event occurs. When the debugging event occurs, the kernel suspends all threads in the process being debugged and notifies the debugger of the event. The debugger can interact with the user, or manipulate the state of the process being debugged, by using the FlushInstructionCache, GetThreadContext, GetThreadSelectorEntry, ReadProcessMemory, SetThreadContext, and WriteProcessMemory functions.

GetThreadSelectorEntry returns the descriptor table entry for a specified selector and thread. Debuggers use the descriptor table entry to convert a segment-relative address to a linear virtual address. The ReadProcessMemory and WriteProcessMemory functions require linear virtual addresses.

Debuggers frequently read the memory of the process being debugged and write the memory that contains instructions to the instruction cache. After the instructions are written, the debugger calls FlushInstructionCache to execute the cached instructions.

The debugger uses the ContinueDebugEvent function at the end of its main loop. This function allows the process being debugged to continue executing.


Communicating with the Debugger

The OutputDebugString function sends a string from the process being debugged to the debugger by generating an OUTPUT_DEBUG_STRING_EVENT debugging event.

The DebugBreak function causes a breakpoint exception in the current process. A breakpoint is a location in a program where execution is stopped to allow the developer to examine the program's code, variables, and register values and, as necessary, to make changes, continue execution, or terminate execution.

The FatalExit function terminates the current process and gives execution control to the debugger, but unlike DebugBreak, it does not generate an exception. This function should only be used as a last resort, because it does not always free the process's memory or close its files.


Debugging Events

A debugging event is an incident in the process being debugged that causes the kernel to notify the debugger. Debugging events include creating a process, creating a thread, loading a dynamic-link library (DLL), unloading a DLL, sending an output string, and generating an exception.

If a debugging event occurs while a debugger is waiting for one, the kernel fills the DEBUG_EVENT structure specified by WaitForDebugEvent with information describing the event.

When the kernel notifies the debugger of a debugging event, it also suspends all threads in the affected process. The threads do not resume execution until the debugger continues the debugging event by using ContinueDebugEvent. The following debugging events may occur while a process is being debugged.

Debugging event	Description
CREATE_PROCESS_DEBUG_EVENT
	Generated whenever a new process is created in a process being debugged or whenever the debugger begins debugging an already active process. The kernel generates this debugging event before the process begins to execute in user mode and before the kernel generates any other debugging events for the new process.
	The DEBUG_EVENT structure contains a CREATE_PROCESS_DEBUG_INFO structure. This structure includes a handle of the new process, a handle of the process's image file, a handle of the process's initial thread, and other information that describes the new process.
	The handle of the process has PROCESS_VM_READ and PROCESS_VM_WRITE access. If a debugger has these types of access to a thread, it can read and write to the process's memory by using the ReadProcessMemory and WriteProcessMemory functions.
	The handle of the process's image file has GENERIC_READ access and is opened for read-sharing.
	The handle of the process's initial thread has THREAD_GET_CONTEXT, THREAD_SET_CONTEXT, and THREAD_SUSPEND_RESUME access to the thread. If a debugger has these types of access to a thread, it can read from and write to the thread's registers by using the GetThreadContext and SetThreadContext functions and can suspend and resume the thread by using the SuspendThread and ResumeThread functions.
CREATE_THREAD_DEBUG_EVENT
	Generated whenever a new thread is created in a process being debugged or whenever the debugger begins debugging an already active process. This debugging event is generated before the new thread begins to execute in user mode.
	The DEBUG_EVENT structure contains a CREATE_THREAD_DEBUG_INFO structure. This structure includes a handle of the new thread and the thread's starting address. The handle has THREAD_GET_CONTEXT, THREAD_SET_CONTEXT, and THREAD_SUSPEND_RESUME access to the thread. If a debugger has these types of access to a thread, it can read from and write to the thread's registers by using the GetThreadContext and SetThreadContext functions and can suspend and resume the thread by using the SuspendThread and ResumeThread functions.
EXCEPTION_DEBUG_EVENT
	Generated whenever an exception occurs in the process being debugged. Possible exceptions include attempting to access inaccessible memory, executing breakpoint instructions, attempting to divide by zero, or any other exception noted in Structured Exception Handling.
	The DEBUG_EVENT structure contains an EXCEPTION_DEBUG_INFO structure. This structure describes the exception that caused the debugging event.
	Besides the standard exception conditions, an additional exception code can occur during console process debugging. The kernel generates a DBG_CONTROL_C exception code when CTRL+C is input to a console process that handles CTRL+C signals and is being debugged. This exception code is not meant to be handled by applications. An application should never use an exception handler to deal with it. It is raised only for the benefit of the debugger and is only used when a debugger is attached to the console process.
	If a process is not being debugged or if the debugger passes on the DBG_CONTROL_C exception unhandled (through the gn command), the application's list of handler functions is searched, as documented for the SetConsoleCtrlHandler function.
	If the debugger handles the DBG_CONTROL_C exception (through the gh command), an application will not notice the CTRL+C except in code like this.
	while ((inputChar = getchar()) != EOF) ... while (gets(inputString)) ...
	Thus, the debugger cannot be used to stop the read wait in such code from terminating.
EXIT_PROCESS_DEBUG_EVENT
	Generated whenever the last thread in a process being debugged exits. This debugging event occurs immediately after the kernel unloads the process's DLLs and updates the process's exit code.
	The DEBUG_EVENT structure contains an EXIT_PROCESS_DEBUG_INFO structure that specifies the exit code.
	The debugger deallocates any internal structures associated with the process on receipt of this debugging event. The kernel closes the debugger's handle of the exiting process and all of the process's threads.
EXIT_THREAD_DEBUG_EVENT
	Generated whenever a thread that is part of a process being debugged exits. The kernel generates this debugging event immediately after it updates the thread's exit code.
	The DEBUG_EVENT structure contains an EXIT_THREAD_DEBUG_INFO structure that specifies the exit code.
	The debugger deallocates any internal structures associated with the thread on receipt of this debugging event. The system closes the debugger's handle of the exiting thread.
	This debugging event does not occur if the exiting thread is the last thread of a process. In this case, the EXIT_PROCESS_DEBUG_EVENT debugging event occurs instead.
LOAD_DLL_DEBUG_EVENT
	Generated whenever a process being debugged loads a DLL. This debugging event occurs when the system loader resolves links to a DLL or when the debugged process uses the LoadLibrary function. This debugging event only occurs the first time the kernel attaches a DLL to the virtual address space of a process.
	The DEBUG_EVENT structure contains a LOAD_DLL_DEBUG_INFO structure. This structure includes a handle of the newly loaded DLL, the base address of the DLL, and other information that describes the DLL.
	Typically, a debugger loads a symbol table associated with the DLL on receipt of this debugging event.
OUTPUT_DEBUG_STRING_EVENT
	Generated when a process being debugged uses the OutputDebugString function.
	The DEBUG_EVENT structure contains an OUTPUT_DEBUG_STRING_INFO structure. This structure specifies the address, length, and format of the debugging string.
UNLOAD_DLL_DEBUG_EVENT
	Generated whenever a process being debugged unloads a DLL by using the FreeLibrary function. This debugging event only occurs the last time a DLL is unloaded from a process's address space (that is, when the DLL's usage count is zero).
	The DEBUG_EVENT structure contains an UNLOAD_DLL_DEBUG_INFO structure. This structure specifies the base address of the DLL in the address space of the process that unloads the DLL.
	Typically, a debugger unloads a symbol table associated with the DLL upon receiving this debugging event.
	When a process exits, the kernel automatically unloads the process's DLLs, but does not generate an UNLOAD_DLL_DEBUG_EVENT debugging event.


Using Debugging Support

The following example uses the WaitForDebugEvent and ContinueDebugEvent functions to illustrate how a simple debugger might be organized.

DEBUG_EVENT DebugEv;                   /* debugging event info.  */

DWORD dwContinueStatus = DBG_CONTINUE; /* exception continuation */

for(;;) {

 /*

  * Wait for a debugging event to occur. The second parameter

  * indicates that the function does not return until

  * a debugging event occurs.

  */

WaitForDebugEvent(&DebugEv, INFINITE);

  /* Process the debugging event code. */

  switch (DebugEv.dwDebugEventCode) {

    case EXCEPTION_DEBUG_EVENT:

      /*

       * Process the exception code. When handling

       * exceptions, remember to set the continuation

       * status parameter (dwContinueStatus). This value

       * is used by the ContinueDebugEvent function.

       */

      switch (DebugEv.u.Exception.ExceptionRecord.ExceptionCode) {

          case EXCEPTION_ACCESS_VIOLATION:

                 /*

                  * First chance: Pass this on to the kernel.

                  * Last chance: Display an appropriate error.

                  */

          case EXCEPTION_BREAKPOINT:

                 /*

                  * First chance: Display the current

                  * instruction and register values.

                  */

          case EXCEPTION_DATATYPE_MISALIGNMENT:

                 /*

                  * First chance: Pass this on to the kernel.

                  * Last chance: Display an appropriate error.

                  */

          case EXCEPTION_SINGLE_STEP:

                 /*

                  * First chance: Update the display of the

                  * current instruction and register values.

                  */

          case DBG_CONTROL_C:

                 /*

                  * First chance: Pass this on to the kernel.

                  * Last chance: Display an appropriate error.

                  */

          /* Handle other exceptions. */

      }

    case CREATE_THREAD_DEBUG_EVENT:

           /*

            * As needed, examine or change the thread's registers

            * with the GetThreadContext and SetThreadContext functions;

            * and suspend and resume thread execution with the

            * SuspendThread and ResumeThread functions.

            */

    case CREATE_PROCESS_DEBUG_EVENT:

           /*

            * As needed, examine or change the registers of the

            * process's initial thread with the GetThreadContext and

            * SetThreadContext functions; read from and write to the

            * process's virtual memory with the ReadProcessMemory and

            * WriteProcessMemory functions; and suspend and resume

            * thread execution with the SuspendThread and ResumeThread

            * functions.

            */

    case EXIT_THREAD_DEBUG_EVENT:

           /* Display the thread's exit code. */

    case EXIT_PROCESS_DEBUG_EVENT:

           /* Display the process's exit code. */

    case LOAD_DLL_DEBUG_EVENT:

           /*

            * Read the debugging information included

            * in the newly loaded DLL.

            */

    case UNLOAD_DLL_DEBUG_EVENT:

           /*

            * Display a message that the DLL has

            * been unloaded.

            */

    case OUTPUT_DEBUG_STRING_EVENT:

           /* Display the output debugging string. */

  }

/* Resume executing the thread that reported the debugging event. */

ContinueDebugEvent(DebugEv.dwProcessId,

    DebugEv.dwThreadId, dwContinueStatus);

}


Debugging Functions

Following are the functions that support debugging:

ContinueDebugEvent
DebugActiveProcess
DebugBreak
FatalAppExit
FatalExit
FlushInstructionCache
GetThreadContext
GetThreadSelectorEntry
OutputDebugString
ReadProcessMemory
SetDebugErrorLevel
SetThreadContext
WaitForDebugEvent
WriteProcessMemory


Device Input and Output

Applications use a device input and output control to communicate with a device driver. This overview discusses device handles, which identify the device being accessed, and device control codes, which specify the action the driver is to perform.


About Device Input and Output

The DeviceIoControl function provides a device input and output control (IOCTL) interface through which an application can communicate directly with a device driver. The DeviceIoControl function is a general-purpose interface that can send control codes to a variety of devices.


Device Handles

A DeviceIoControl call specifies a handle of a device driver to identify the device being accessed. You can use the CreateFile function to get a device driver handle.

The CreateFile call must specify either the name of a device or the name of the driver associated with a device. To specify a device name, the lpszname parameter of CreateFile specifies a string with the format

\\.\DeviceName

The types of devices that you can open and the method that you must use to specify them in the CreateFile function depend on the Win32 platform on which your application is running.

On Windows NT, DeviceIoControl can open a handle of a specific device. For example, to open a handle to the logical drive A:, specify "\\\\.\\a:". Alternatively, you can use the names "\\\\.\\PhysicalDrive0", "\\\\.\\PhysicalDrive1", and so on, to open handles to the physical drives on a system.

For Win32-based applications running on Windows 95, DeviceIoControl must specify a handle of a virtual device driver. For example, to open a handle to the system VxD, specify "\\\\.\\vwin32".

The CreateFile call should specify the FILE_SHARE_READ and FILE_SHARE_WRITE access flags when opening a handle to a device driver. However, when opening a communications resource, such as a serial port, CreateFile must specify exclusive access. Other CreateFile parameters are used as follows when opening a device handle:

•	The fdwCreate parameter must specify the OPEN_EXISTING flag.

•	The hTemplateFile parameter must be NULL.

•	The fdwAttrsAndFlags parameter can specify FILE_FLAG_OVERLAPPED to indicate that the returned handle can be used in overlapped (asynchronous) I/O operations.


Device Control Codes

An application can use the DeviceIoControl function to send a control code to a device driver. The control code specifies the action that the driver is to perform. For example, a control code can ask a device driver to return information about the corresponding device, or direct the driver to carry out an action on the device, such as formatting a disk.

A number of standard control codes are defined in the Win32 header files. For a list of standard control codes, see  DeviceIoControl . In addition, device drivers can define their own device-specific control codes. The types of control codes you can specify depend on the device being accessed and the Win32 platform on which your application is running.

Applications running on Windows NT can use the standard control codes or device-specific control codes to perform direct input and output operations on a floppy disk drive, hard disk drive, tape drive, or CD-ROM drive.

Win32-based applications running on Windows 95 cannot use the standard control codes in the Win32 header files. These applications are restricted to using the control codes supported by the virtual device driver being accessed. For example, the system VxD, VWIN32.VXD, supports the input and output control (IOCTL) functions originally provided by MS-DOS Interrupt 21h.

The control code specified in a DeviceIoControl call determines the values that must be specified for the other DeviceIoControl parameters. For example, a Windows NT application can specify the IOCTL_DISK_FORMAT_TRACKS control code. In this case, the lpvInBuffer parameter must point to a filled-in FORMAT_PARAMETERS structure, and the cbInBuffer parameter must specify the size of the structure.


Using Device Input and Output Control

•	Calling DeviceIoControl on Windows NT

•	Calling DeviceIoControl on Windows 95


Calling DeviceIoControl on Windows NT

On Windows NT, an application can use the DeviceIoControl function to perform direct input and output operations on, or retrieve information about, a floppy disk drive, hard disk drive, tape drive, or CD-ROM drive. The following example demonstrates how to retrieve information about the first physical drive in the system. It uses the CreateFile function to obtain the device handle of the first physical drive, and then uses the DeviceIoControl function with the IOCTL_DISK_GET_DRIVE_GEOMETRY control code to fill a DISK_GEOMETRY structure with information about the drive.

BOOL GetDriveGeometry(DISK_GEOMETRY *pdg)

{

    HANDLE hDevice;

    BOOL fResult;

    DWORD cb;

    hDevice = CreateFile("\\\\.\\PhysicalDrive0",

        0, FILE_SHARE_READ | FILE_SHARE_WRITE,

        NULL, OPEN_EXISTING, 0, NULL);

    if (hDevice == NULL)

        return FALSE;

    fResult = DeviceIoControl(hDevice,

        IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0,

        pdg, sizeof(*pdg), &cb, (LPOVERLAPPED) NULL);

    if (!fResult)

        return FALSE;

    CloseHandle(hDevice);

}

This example succeeds only when it runs on Windows NT, for two reasons:

•	The standard device input/output control codes are available only on Windows NT, and

•	On Windows 95, an application must specify a virtual device driver in the CreateFile function — not a specific device.


Calling DeviceIoControl on Windows 95

A Win32-based application running on Windows 95 can use the DeviceIoControl function to send control codes directly to a virtual device driver (VxD). Any VxD can support any number of control codes, or none at all.

The system VxD, VWIN32.VXD, supports the input and output control (IOCTL) functions originally provided by MS-DOS Interrupt 21h. The following example shows how to call Get Media ID (Interrupt 21h Function 440Dh Minor Code 66h) from a Win32-based application:

"\\\\.\\VxDName"

In Windows 95,

#define VWIN32_DIOC_DOS_IOCTL 1

typedef struct _DEVIOCTL_REGISTERS {

    DWORD reg_EBX;

    DWORD reg_EDX;

    DWORD reg_ECX;

    DWORD reg_EAX;

    DWORD reg_EDI;

    DWORD reg_ESI;

    DWORD reg_Flags;

} DEVIOCTL_REGISTERS, *PDEVIOCTL_REGISTERS;

typedef struct _MID {

    WORD  midInfoLevel;

    DWORD midSerialNum;

    BYTE  midVolLabel[11];

    BYTE  midFileSysType[8];

} MID, *PMID;

BOOL GetMediaID(PMID pmid, UINT nDrive)

{

    DEVIOCTL_REGISTERS reg;

    reg.reg_EAX = 0x440D;       /* IOCTL for block devices */

    reg.reg_EBX = nDrive;       /* zero-based drive ID     */

    reg.reg_ECX = 0x0866;       /* Get Media ID command    */

    reg.reg_EDX = (DWORD) pmid; /* receives media ID info  */

    if (!DoIOCTL(&reg))

        return FALSE;

    if (reg.reg_Flags & 0x8000) /* error if carry flag set */

        return FALSE;

    return TRUE;

}

BOOL DoIOCTL(PDEVIOCTL_REGISTERS preg)

{

    HANDLE hDevice;

    BOOL fResult;

    DWORD cb;

    preg->reg_Flags = 0x8000; /* assume error (carry flag set) */

    hDevice = CreateFile("\\\\.\\vwin32",

        GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,

        (LPSECURITY_ATTRIBUTES) NULL, OPEN_EXISTING,

        FILE_ATTRIBUTE_NORMAL, (HANDLE) NULL);

    if (hDevice == (HANDLE) INVALID_HANDLE_VALUE)

        return FALSE;

    else {

        fResult = DeviceIoControl(hDevice, VWIN32_DIOC_DOS_IOCTL,

            preg, sizeof(*preg), preg, sizeof(*preg), &cb, 0);

        if (!fResult)

            return FALSE;

    }

    CloseHandle(hDevice);

    return TRUE;

}


Device Input and Output Reference

The following functions, operations, and structures are associated with device input and output.


Device Input and Output Functions

Use the following function to implement device input and output:

DeviceIoControl


Device Input and Output Operations

Use the following operations to implement device input and output:

FSCTL_DISMOUNT_VOLUME
FSCTL_LOCK_VOLUME
FSCTL_UNLOCK_VOLUME
IOCTL_DISK_CHECK_VERIFY
IOCTL_DISK_EJECT_MEDIA
IOCTL_DISK_FORMAT_TRACKS
IOCTL_DISK_GET_DRIVE_GEOMETRY
IOCTL_DISK_GET_DRIVE_LAYOUT
IOCTL_DISK_GET_MEDIA_TYPES
IOCTL_DISK_GET_PARTITION_INFO
IOCTL_DISK_LOAD_MEDIA
IOCTL_DISK_MEDIA_REMOVAL
IOCTL_DISK_PERFORMANCE
IOCTL_DISK_REASSIGN_BLOCKS
IOCTL_DISK_SET_DRIVE_LAYOUT
IOCTL_DISK_SET_PARTITION_INFO
IOCTL_DISK_VERIFY
IOCTL_SERIAL_LSRMST_INSERT


Device Input and Output Structures

Use these structures in device input and output operations:

FORMAT_PARAMETERS
DISK_GEOMETRY
DRIVE_LAYOUT_INFORMATION
PARTITION_INFORMATION
PREVENT_MEDIA_REMOVAL
DISK_PERFORMANCE
REASSIGN_BLOCKS
SET_PARTITION_INFORMATION
VERIFY_INFORMATION


Dynamic Data Exchange

This overview provides guidelines for implementing dynamic data exchange for applications that cannot use the Dynamic Data Exchange Management Library (DDEML). For more information about the DDEML, see Dynamic Data Exchange Management Library.


About Dynamic Data Exchange

The Microsoft® Win32® application programming interface (API) provides several methods for transferring data between applications. One method is to use the Win32 dynamic data exchange (DDE) protocol. The DDE protocol is a set of messages and guidelines. It sends messages between applications that share data and uses shared memory to exchange data between applications. Applications can use the DDE protocol for one-time data transfers and for continuous exchanges in which applications send updates to one another as new data becomes available.

The Win32 API also includes the Dynamic Data Exchange Management Library (DDEML). The DDEML is a dynamic-link library (DLL) that applications running with Windows can use to share data. The DDEML provides an application programming interface (API) that simplifies the task of adding DDE capability to a Win32-based application. Instead of sending, posting, and processing DDE messages directly, an application uses the DDEML functions to manage DDE conversations. (A DDE conversation is the interaction between client and server applications.)

The DDEML also provides a facility for managing the strings and data that DDE applications share. Instead of using atoms and pointers to shared memory objects, DDE applications create and exchange string handles, which identify strings, and data handles, which identify memory objects. The DDEML also makes it possible for a server application to register the service names it supports. The names are broadcast to other applications in the system, which can use the names to connect to the server. Moreover, the DDEML ensures compatibility among DDE applications by forcing them to implement the DDE protocol in a consistent manner.

Existing applications that use the message-based DDE protocol are fully compatible with those that use the DDEML. That is, an application that uses message-based DDE can establish conversations and perform transactions with applications that use the DDEML. Because of the many advantages of the DDEML, new applications should use it rather than the DDE messages. To use the API elements of the DDEML, you must include the DDEML header file in your source files, link with the DDEML library, and ensure that the DDEML dynamic-link library is in the system's search path.


Dynamic Data Exchange Protocol

Because the Win32 API has a message-based architecture, passing messages is the most appropriate method for automatically transferring information between applications. However, Win32 messages contain only two parameters (wParam and lParam) for passing data. As a result, these parameters must refer indirectly to other pieces of data when more than a few words of information pass between applications. The DDE protocol defines exactly how applications should use the wParam and lParam parameters to pass larger pieces of data by means of global atoms and shared memory handles. The DDE protocol has specific rules for allocating and deleting global atoms and shared memory objects.

A global atom is a reference to a character string. In the DDE protocol, atoms identify the applications exchanging data, the nature of the data being exchanged, and the data items themselves. For more information about atoms, see Atoms. A shared memory handle is a handle to a memory object allocated by GlobalAlloc, using the GMEM_DDESHARE flag. In the DDE protocol, shared memory objects store data items passed between applications, protocol options, and remote command execution strings.


Uses for Windows Dynamic Data Exchange

DDE is most appropriate for data exchanges that do not require ongoing user interaction. Usually, an application provides a method for the user to establish the link between the applications exchanging data. Once that link is established, however, the applications exchange data without further user involvement.

DDE can be used to implement a broad range of application features — for example:

•	Linking to real-time data, such as to stock market updates, scientific instruments, or process control.

•	Creating compound documents, such as a word processing document that includes a chart produced by a graphics application. Using DDE, the chart will change when the source data is changed, while the rest of the document remains the same.

•	Performing data queries between applications, such as a spreadsheet querying a database for accounts past due.


Dynamic Data Exchange from the User's Point of View

The following example illustrates illustrates how two DDE applications can cooperate, as seen from the user's point of view.

A spreadsheet user wants to use Microsoft® Excel to track the price of a particular stock on the New York Stock Exchange. The user has a Win32-based application called Quote that in turn has access to NYSE data. The DDE conversation between Microsoft Excel and Quote takes place as follows:

•	The user initiates the conversation by supplying the name of the application (Quote) that will supply the data and the particular topic of interest (NYSE). The resulting DDE conversation is used to request quotes on specific stocks.

•	Microsoft Excel broadcasts the application and topic names to all DDE applications currently running in the system. Quote responds, establishing a conversation with Microsoft Excel about the NYSE topic.

•	The user can then create a spreadsheet formula in a cell that requests that the spreadsheet be automatically updated whenever a particular stock quotation changes. For example, the user could request an automatic update whenever a change occurs in the selling price of ZAXX stock by specifying the following Microsoft Excel formula:

='Quote'|'NYSE'!ZAXX

•	The user can terminate the automatic updating of the ZAXX stock quotation at any time. Other data links that were established separately (such as for quotations for other stocks) still will remain active under the same NYSE conversation.

•	The user can also terminate the entire conversation between Microsoft Excel and Quote on the NYSE topic, so that no specific data links on that topic can be established without initiating a new conversation.


Dynamic Data Exchange Concepts

The following sections explain the important concepts and terminology that are key to understanding dynamic data exchange.


Client, Server, and Conversation

Two applications participating in dynamic data exchange are said to be engaged in a DDE conversation. The application that initiates the conversation is the DDE client application; the application that responds to the client is the DDE server application. An application can engage in several conversations at the same time, acting as the client in some and as the server in others.

A DDE conversation takes place between two windows, one for each of the participating applications. A window may be the main window of the application; a window associated with a specific document, as in a multiple document interface (MDI) application; or a hidden (invisible) window whose only purpose is to process DDE messages.

Since a DDE conversation is identified by the pair of handles to the windows engaged in the conversation, no window should be engaged in more than one conversation with another window. Either the client application or the server application must provide a different window for each of its conversations with a particular server or client application.

An application can ensure a pair of client and server windows is never involved in more than one conversation by creating a hidden window for each conversation. The sole purpose of this window is to process DDE messages.


Application, Topic, and Item Names

The DDE protocol identifies the units of data passed between the client and server with a three-level hierarchy of application, topic, and item names.

Each DDE conversation is uniquely defined by the application name and topic. At the beginning of a DDE conversation, the client and server determine the application name and topic. The application name is usually the name of the server application. For example, when Microsoft Excel acts as the server in a conversation, the application name is Excel.

The DDE topic is a general classification of data within which multiple data items may be "discussed" (exchanged) during the conversation. For applications that operate on file-based documents, the topic is usually a filename. For other applications, the topic is an application-specific name.

Because the client and server window handles together identify a DDE conversation, the application name and topic that define a conversation cannot be changed during the course of the conversation.

A DDE data item is information related to the conversation topic exchanged between the applications. Values for the data item can be passed from the server to the client, or from the client to the server. Data can be passed with any of the standard clipboard formats or with a registered clipboard format. A special, registered format named Link identifies an item in a DDE conversation. For more information about clipboard formats, see Clipboard.


The System Topic

Applications should support the system topic at all times. This topic provides a context for information that may be of general interest to another application.

Data-item values must be rendered in the CF_TEXT clipboard format. Individual elements of item values for a system topic must be delimited by tab characters. The following table suggests some items for the system topic.

Item	Description
Formats	Tab-delimited list of clipboard formats the application can render. Typically, CF_ formats are listed with the "CF_" portion of the names removed (for example, CF_TEXT is listed as "TEXT").
Help	Text that briefly explains how to use the DDE server.
ReturnMessage	Supporting detail for the most recently used WM_DDE_ACK message. This item is useful when more than eight bits of application-specific return data are required.
Status	Indication of the current status of the application. When a server receives a WM_DDE_REQUEST message for this system-topic item, it should respond by posting a WM_DDE_DATA message with a string containing either Busy or Ready, as appropriate.
SysItems	List of system-topic items the application supports.
TopicItemList	Similar to the SysItems item, except that TopicItemList should be supported for each topic other than the system topic. This allows browsing of the items supported under any topic. If the items cannot be enumerated, this item should contain only "TopicItemList".
Topics	List of topics the application supports at the current time; this list can vary from moment to moment.


Permanent Data Links

Once a DDE conversation has begun, the client can establish one or more permanent data links with the server. A data link is a communications mechanism by which the server notifies the client whenever the value of a given data item changes. The data link is permanent in the sense that this notification process continues until the data link or the DDE conversation itself is terminated.

There are two kinds of permanent DDE data links: warm and hot. In a warm data link, the server notifies the client that the value of the data item has changed, but the server does not send the data value to the client until the client requests it. In a hot data link, the server immediately sends the changed data value to the client.

Applications that support warm or hot data links typically provide a Copy or Paste Link command in their Edit menu to enable the user to establish links between applications. For more information, see Initiating a Data Link.


Atoms and Shared Memory Objects

Certain arguments of DDE messages are global atoms or shared memory objects. Applications using these arguments must follow explicit rules about when to allocate and delete them. In all cases, the message sender must delete any atom or shared memory object that the intended receiver will not receive because of an error condition, such as failure of the PostMessage function.

DDE uses shared memory objects for three purposes:

•	To carry a data-item value to be exchanged. This is an item referenced by the hData parameter in the WM_DDE_DATA and WM_DDE_POKE messages.

•	To carry options in a message. This is an item referenced by the hOptions parameter in a WM_DDE_ADVISE message.

•	To carry a command execution string. This is an item referenced by the hCommands parameter in the WM_DDE_EXECUTE message and its corresponding WM_DDE_ACK message.

An application that receives a DDE shared memory object must treat it as read only. The application must not use the object as a mutual read-write area for the free exchange of data.

As it does with a DDE atom, an application should free a shared memory object to manage memory effectively. The application should also lock and unlock memory objects.


Dynamic Data Exchange Messages Overview

Because DDE is a message-based protocol, it employs no special Win32 functions or libraries. All DDE transactions are conducted by passing certain defined DDE messages between the client and server windows.

There are nine DDE messages; the symbolic constants for these messages are defined in the DDE header file. Certain structures for the various DDE messages are also defined in this header file.

The following table summarizes the nine DDE messages.

Message	Description
WM_DDE_ACK	Acknowledges receiving or not receiving a message.
WM_DDE_ADVISE	Requests the server application to supply an update or notification for a data item whenever it changes. This establishes a permanent data link.
WM_DDE_DATA	Sends a data-item value to the client application.
WM_DDE_EXECUTE	Sends a string to the server application, which is expected to process the string as a series of commands.
WM_DDE_INITIATE	Initiates a conversation between the client and server applications.
WM_DDE_POKE	Sends a data-item value to the server application.
WM_DDE_REQUEST	Requests the server application to provide the value of a data item.
WM_DDE_TERMINATE	Terminates a conversation.
WM_DDE_UNADVISE	Terminates a permanent data link.
An application calls SendMessage to issue the WM_DDE_INITIATE message or a WM_DDE_ACK message sent in response to WM_DDE_INITIATE. All other messages are sent by PostMessage. The first parameter of these calls is the handle of the receiving window; the second parameter contains the message to be sent; the third parameter identifies the sending window; and the fourth parameter contains the message-specific arguments.


Dynamic Data Exchange Message Flow

A typical DDE conversation consists of the following events:

1.	The client application initiates the conversation, and the server application responds.

2.	The applications exchange data by any or all of the following methods:

•	The server application sends data to the client at the client's request.

•	The client application sends unsolicited data to the server application.

•	The client application requests the server application to notify the client whenever a data item changes (warm data link).

•	The client application requests the server application to send data whenever the data changes (hot data link).

•	The server application carries out a command at the client's request.

3.	Either the client or server application terminates the conversation.

An application window that processes requests from a client or server must process them strictly in the order they are received.

A client can establish conversations with more than one server; a server can have conversations with more than one client. When handling messages from more than one source, a client or server must process the messages of a given conversation synchronously, but need not process all messages synchronously. In other words, it can shift from one conversation to another as needed.

If an application is unable to process an incoming request because it is waiting for a DDE response, it must prevent deadlock by posting a WM_DDE_ACK message with the fBusy member of the DDEACK structure set to 1. An application can also send a busy WM_DDE_ACK message if, for any reason, it cannot process an incoming request within a reasonable amount of time.

An application should be able to handle the failure of a client or server to respond to a message within a certain time. Since the time-out interval may vary depending on the nature of the application and the configuration of the user's system (including whether it is connected to a network), the application should provide a way for the user to specify the interval.


Parameter-Packing Functions

The lParam parameter of many DDE messages contains two pieces of data. For example, the lParam of the WM_DDE_DATA message contains a data handle and an atom. In previous versions of Windows, an application could use the MAKELONG macro to prepare an lParam parameter, and the LOWORD and HIWORD macros to remove the low-order and high-order values from lParam. Because a Win32 data handle is a 32-bit value, a Win32-based application must use the PackDDElParam function to pack the handle and atom into an lParam parameter, and the UnpackDDElParam function to remove the values. DDE applications must use PackDDElParam and UnpackDDElParam for all messages posted during a DDE conversation.

The Win32 API also includes the ReuseDDElParam and FreeDDElParam functions. ReuseDDElParam allows a DDE application to reuse a packed lParam parameter, helping reduce the number of memory reallocations the application must perform during a conversation. An application can use FreeDDElParam to free the memory associated with a data handle received during a DDE conversation.


Using Dynamic Data Exchange

•	Initiating a DDE conversation

•	Transferring a single data item

•	Establishing a permanent data link

•	Carrying out commands in a server application

•	Terminating a DDE conversation


Initiating a Conversation

To initiate a DDE conversation, the client sends a WM_DDE_INITIATE message. Usually, the client broadcasts this message by calling SendMessage, with −1 as the first parameter. If the application already has the window handle of the server application, it can send the message directly to that window. The client prepares atoms for the application name and topic name by calling GlobalAddAtom. The client can request conversations with any potential server application and for any potential topic by supplying NULL (wildcard) atoms for the application and topic.

The following example illustrates how the client initiates a conversation, where both the application and topic are specified.

/* Global variable */

static BOOL fInInitiate = FALSE;

    char *szApplication;

    char *szTopic;

    atomApplication = *szApplication == 0 ?

        NULL : GlobalAddAtom((LPSTR) szApplication);

    atomTopic = *szTopic == 0 ?

        NULL : GlobalAddAtom((LPSTR) szTopic);

    fInInitiate = TRUE;

    SendMessage((HWND) -1,        /* broadcasts message          */

        WM_DDE_INITIATE,          /* initiates conversation      */

        (WPARAM) hwndClientDDE,   /* handle of client DDE window */

        MAKELONG(atomApplication, /* application-name atom       */

            atomTopic));          /* topic-name atom             */

    fInInitiate = FALSE;

    if (atomApplication != NULL)

        GlobalDeleteAtom(atomApplication);

    if (atomTopic != NULL)

        GlobalDeleteAtom(atomTopic);

Note that if your application uses NULL atoms, you need not use the GlobalAddAtom and GlobalDeleteAtom functions. In this example, the client application creates two global atoms containing the name of the server and the name of the topic, respectively.

The client application sends a WM_DDE_INITIATE message with these two atoms in the lParam parameter of the message. In the call to the SendMessage function, the special window handle −1 directs Windows to send this message to all other active applications. SendMessage does not return to the client application until all applications that receive the message have, in turn, returned control to Windows. This means that all WM_DDE_ACK messages sent in reply by the server applications are guaranteed to have been processed by the client by the time the SendMessage call has returned.

After SendMessage returns, the client application deletes the global atoms.

Server applications respond according to the logic illustrated in the following diagram.

To acknowledge one or more topics, the server must create atoms for each conversation (requiring duplicate application-name atoms if there are multiple topics) and send a WM_DDE_ACK message for each conversation, as illustrated in the following example.

if ((atomApplication = GlobalAddAtom("Server")) != 0) {

    if ((atomTopic = GlobalAddAtom(szTopic)) != 0) {

        SendMessage(hwndClientDDE,

            WM_DDE_ACK,

            (WPARAM) hwndServerDDE,

            MAKELONG(atomApplication, atomTopic));

        GlobalDeleteAtom(atomApplication);

    }

    GlobalDeleteAtom(atomTopic);

}

if ((atomApplication == 0) || (atomTopic == 0)) {

     .

     . /* error handling */

     .

}

When a server responds with a WM_DDE_ACK message, the client application should save the handle of the server window. The client receiving the handle as the wParam parameter of the WM_DDE_ACK message then sends all subsequent DDE messages to the server window this handle identifies.

If your client application uses a NULL atom for the application name or topic name, expect the application to receive acknowledgments from more than one server application. Multiple acknowledgements can also come from multiple instances of a DDE server, even if your client application does not use NULL atoms. A server should always use a unique window for each conversation. The window procedure in the client application can use the handle of the server window (provided as the lParam parameter of WM_DDE_INITIATE) to track multiple conversations. This allows a single client window to process several conversations without needing to terminate and reconnect with a new client window for each conversation.


Transferring a Single Item

Once a DDE conversation has been established, the client can either retrieve the value of a data item from the server by issuing the WM_DDE_REQUEST message, or submit a data-item value to the server by issuing WM_DDE_POKE.


Retrieving an Item from the Server

To retrieve an item from the server, the client sends the server a WM_DDE_REQUEST message specifying the item and format to retrieve, as shown in the following example.

if ((atomItem = GlobalAddAtom(szItemName)) != 0) {

    if (!PostMessage(hwndServerDDE,

            WM_DDE_REQUEST,

            (WPARAM) hwndClientDDE,

            PackDDElParam(WM_DDE_REQUEST, CF_TEXT, atomItem)))

        GlobalDeleteAtom(atomItem);

}

if (atomItem == 0) {

     .

     . /* error handling */

     .

}

In this example, the client specifies the clipboard format CF_TEXT as the preferred format for the requested data item.

The receiver (server) of the WM_DDE_REQUEST message typically must delete the item atom, but if the PostMessage call fails, the client must delete the atom.

If the server has access to the requested item and can render it in the requested format, the server copies the item value as a shared memory object and sends the client a WM_DDE_DATA message, as illustrated in the following example.

/*

 * Allocate the size of the DDE data header, plus the data: a

 * string,<CR><LF><NULL>. The byte for the string's terminating

 * null character is counted by DDEDATA.Value[1].

 */

if (!(hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE,

        (LONG) sizeof(DDEDATA) + lstrlen(szItemValue) + 2)))

    return;

if (!(lpData = (DDEDATA FAR*) GlobalLock(hData)))  {

    GlobalFree(hData);

    return;

}

   .

   .

   .

lpData->cfFormat = CF_TEXT;

lstrcpy((LPSTR) lpData->Value, (LPSTR) szItemValue);

/* Each line of CF_TEXT data is terminated by CR/LF. */

lstrcat((LPSTR) lpData->Value, (LPSTR) "\r\n");

GlobalUnlock(hData);

if ((atomItem = GlobalAddAtom((LPSTR) szItemName)) != 0) {

    lParam = PackDDElParam(WM_DDE_ACK, (UINT) hData, atomItem);

    if (!PostMessage(hwndClientDDE,

            WM_DDE_DATA,

            (WPARAM) hwndServerDDE,

            lParam)) {

        GlobalFree(hData);

        GlobalDeleteAtom(atomItem);

        FreeDDElParam(WM_DDE_ACK, lParam);

    }

}

if (atomItem == 0) {

     .

     . /* error handling */

     .

}

In this example, the server application allocates a memory object to contain the data item. The memory is allocated with the GMEM_DDESHARE option, so that the server and client applications can share the memory. After allocating the memory object, the server application locks the object so it can obtain the object's address. The data object is initialized as a DDEDATA structure.

The server application then sets the cfFormat member of the structure to CF_TEXT to inform the client application that the data is in text format. The client responds by copying the value of the requested data into the Value member of the DDEDATA structure. After the server has filled the data object, the server unlocks the data and creates a global atom containing the name of the data item.

Finally, the server issues the WM_DDE_DATA message by calling PostMessage. The handle of the data object and the atom containing the item name are packed into the lParam parameter of the message by the PackDDElParam function.

If PostMessage fails, the server must use the FreeDDElParam function to free the packed lParam parameter. The server must also free the packed lParam parameter for the WM_DDE_REQUEST message it received.

If the server cannot satisfy the request, it sends a negative WM_DDE_ACK message to the client, as shown in the following example.

/* negative acknowledgment */

PostMessage(hwndClientDDE,

    WM_DDE_ACK,

    (WPARAM) hwndServerDDE,

    PackDDElParam(WM_DDE_ACK, 0, atomItem));

Upon receiving a WM_DDE_DATA message, the client processes the data-item value as appropriate. Then, if the fAckReq member pointed to in the WM_DDE_DATA message is 1, the client must send the server a positive WM_DDE_ACK message, as shown in the following example.

UnpackDDElParam(WM_DDE_DATA, lParam, (PUINT) &hData,

    (PUINT) &atomItem);

if (!(lpDDEData = (DDEDATA FAR*) GlobalLock(hData))

        || (lpDDEData->cfFormat != CF_TEXT)) {

    PostMessage(hwndServerDDE,

        WM_DDE_ACK,

        (WPARAM) hwndClientDDE,

        PackDDElParam(WM_DDE_ACK, 0, atomItem)); /* negative ACK */

}

/* Copy data from lpDDEData here.*/

if (lpDDEData->fAckReq) {

    PostMessage(hwndServerDDE,

        WM_DDE_ACK,

        (WPARAM) hwndClientDDE,

        PackDDElParam(WM_DDE_ACK, 0x8000,

            atomItem)); /* positive ACK */

}

bRelease = lpDDEData->fRelease;

GlobalUnlock(hData);

if (bRelease)

    GlobalFree(hData);

In this example, the client examines the format of the data. If the format is not CF_TEXT (or if the client cannot lock the memory for the data), the client sends a negative WM_DDE_ACK message to indicate that it cannot process the data. If the client cannot lock a data handle because the handle contains the fAckReq member, the client should not send a negative WM_DDE_ACK message. Instead, the client should terminate the conversation.

If a client sends a negative acknowledgement in response to a WM_DDE_DATA message, the server is responsible for freeing the memory (but not the lParam parameter) referenced by the WM_DDE_DATA message associated with the negative acknowledgement.

If it can process the data, the client examines the fAckReq member of the DDEDATA structure to determine whether the server requested that it be informed that the client received and processed the data successfully. If the server did request this information, the client sends the server a positive WM_DDE_ACK message.

Because unlocking data invalidates the pointer to the data, the client saves the value of the fRelease member before unlocking the data object. After saving the value, the client then examines it to determine whether the server application requested the client to free the memory containing the data; the client acts accordingly.

Upon receiving a negative WM_DDE_ACK message, the client can ask for the same item value again, specifying a different clipboard format. Typically, a client will first ask for the most complex format it can support, then step down if necessary through progressively simpler formats until it finds one the server can provide.

If the server supports the Formats item of the system topic, the client can determine once what clipboard formats the server supports, instead of determining them each time the client requests an item. For more information about the system topic, see The System Topic.


Submitting an Item to the Server

The client may send an item value to the server by using the WM_DDE_POKE message. The client renders the item to be sent and sends the WM_DDE_POKE message, as illustrated in the following example.

if (!(hPokeData = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE,

        (LONG) sizeof(DDEPOKE) + lstrlen(szValue) + 2)))

    return;

if (!(lpPokeData = (DDEPOKE FAR*) GlobalLock(hPokeData))) {

    GlobalFree(hPokeData);

    return;

}

lpPokeData->fRelease = TRUE;

lpPokeData->cfFormat = CF_TEXT;

lstrcpy((LPSTR) lpPokeData->Value, (LPSTR) szValue);

/* Each line of CF_TEXT data is terminated by CR/LF. */

lstrcat((LPSTR) lpPokeData->Value, (LPSTR) "\r\n");

GlobalUnlock(hPokeData);

if ((atomItem = GlobalAddAtom((LPSTR) szItem)) != 0) {

       .

       .

       .

        if (!PostMessage(hwndServerDDE,

                WM_DDE_POKE,

                (WPARAM) hwndClientDDE,

                PackDDElParam(WM_DDE_POKE, (UINT) hPokeData,

                    atomItem))) {

           GlobalDeleteAtom(atomItem);

           GlobalFree(hPokeData);

        }

}

if (atomItem == 0) {

     .

     . /* error handling */

     .

}

Note that sending data by using a WM_DDE_POKE message is essentially the same as sending it by using WM_DDE_DATA, except that WM_DDE_POKE is sent from the client to the server.

If the server is able to accept the data-item value in the format rendered by the client, the server processes the item value as appropriate and sends the client a positive WM_DDE_ACK message. If it is unable to process the item value, because of its format or for other reasons, the server sends the client a negative WM_DDE_ACK message.

UnpackDDElParam(WM_DDE_POKE, lParam, (PUINT) &hPokeData,

    (PUINT) &atomItem);

GlobalGetAtomName(atomItem, szItemName, ITEM_NAME_MAX_SIZE);

if (!(lpPokeData = (DDEPOKE FAR*) GlobalLock(hPokeData))

        || lpPokeData->cfFormat != CF_TEXT

        || !IsItemSupportedByServer(szItemName)) {

    PostMessage(hwndClientDDE,

        WM_DDE_ACK,

        (WPARAM) hwndServerDDE,

        PackDDElParam(WM_DDE_ACK, 0, atomItem)); /* negative ACK */

}

lstrcpy(szItemValue, lpPokeData->Value); /* copies value */

bRelease = lpPokeData->fRelease;

GlobalUnlock(hPokeData);

if (bRelease) {

    GlobalFree(hPokeData);

}

PostMessage(hwndClientDDE,

    WM_DDE_ACK,

    (WPARAM) hwndServerDDE,

    PackDDElParam(WM_DDE_ACK,

         0x8000, atomItem));    /* positive ACK */

In this example, the server calls GlobalGetAtomName to retrieve the name of the item the client sent. The server then determines whether it supports the item and whether the item is rendered in the correct format (that is, CF_TEXT). If the item is not supported and not rendered in the correct format, or if the server cannot lock the memory for the data, the server sends a negative acknowledgment back to the client application. Note that in this case, sending a negative acknowledgement is correct because WM_DDE_POKE messages are always assumed to have the fAckReq member set. The server should ignore the member.

If a server sends a negative acknowledgement in response to a WM_DDE_POKE message, the client is responsible for freeing the memory (but not the lParam parameter) referenced by the WM_DDE_POKE message associated with the negative acknowledgement.


Establishing a Permanent Data Link

A client application can use DDE to establish a link to an item in a server application. After such a link is established, the server sends periodic updates of the linked item to the client, typically, whenever the value of the item changes. Thus, a permanent data stream is established between the two applications; this data stream remains in place until it is explicitly disconnected.


Initiating a Data Link

The client initiates a data link by posting a WM_DDE_ADVISE message, as shown in the following example.

if (!(hOptions = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE,

        sizeof(DDEADVISE))))

    return;

if (!(lpOptions = (DDEADVISE FAR*) GlobalLock(hOptions))) {

    GlobalFree(hOptions);

    return;

}

lpOptions->cfFormat = CF_TEXT;

lpOptions->fAckReq = TRUE;

lpOptions->fDeferUpd = FALSE;

GlobalUnlock(hOptions);

if ((atomItem = GlobalAddAtom(szItemName)) != 0) {

    if (!(PostMessage(hwndServerDDE,

            WM_DDE_ADVISE,

            (WPARAM) hwndClientDDE,

            PackDDElParam(WM_DDE_ADVISE, (UINT) hOptions,

                atomItem)))) {

        GlobalDeleteAtom(atomItem);

        GlobalFree(hOptions);

        FreeDDElParam(WM_DDE_ADVISE, lParam);

    }

}

if (atomItem == 0) {

    .

    . /* error handling */

    .

}

In this example, the client application sets the fDeferUpd flag of the WM_DDE_ADVISE message to FALSE. This directs the server application to send the data to the client whenever the data changes.

If the server is unable to service the WM_DDE_ADVISE request, it sends the client a negative WM_DDE_ACK message. But if the server has access to the item and can render it in the requested format, the server notes the new link (recalling the flags specified in the hOptions parameter) and sends the client a positive WM_DDE_ACK message. From then on, until the client issues a matching WM_DDE_UNADVISE message, the server sends the new data to the client every time the value of the item changes in the server.

The WM_DDE_ADVISE message establishes the format of the data to be exchanged during the link. If the client attempts to establish another link with the same item but is using a different data format, the server can choose to reject the second data format or attempt to support it. If a warm link has been established for any data item, the server can support only one data format at a time. This is because the WM_DDE_DATA message for a warm link has a NULL data handle, which otherwise contains the format information. Thus, a server must reject all warm links for an item already linked, and must reject all links for an item that has warm links. Another interpretation may be that the server changes the format and the hot or warm state of a link when a second link is requested for the same data item.

In general, client applications should not attempt to establish more than one link at a time for a data item.


Initiating a Data Link with the Paste Link Command

Applications that support hot or warm data links typically support a registered clipboard format named Link. When associated with the application's Copy and Paste Link commands, this clipboard format enables the user to establish DDE conversations between applications simply by copying a data item in the server application and pasting it into the client application.

A server application supports the Link clipboard format by placing in the clipboard a string containing the application, topic, and item names when the user chooses the Copy command from the Edit menu. Following is the standard Link format:

application\0topic\0item\0\0

A single null character separates the names, and two null characters terminate the entire string.

Both the client and server applications must register the Link clipboard format, as shown:

cfLink = RegisterClipboardFormat("Link");

A client application supports the Link clipboard format by means of a Paste Link command on its Edit menu. When the user chooses this command, the client application parses the application, topic, and item names from the Link-format clipboard data. Using these names, the client application initiates a conversation for the application and topic, if such a conversation does not already exist. The client application then sends a WM_DDE_ADVISE message to the server application, specifying the item name contained in the Link-format clipboard data.

Following is an example of a client application's response when the user chooses the Paste Link command.

void DoPasteLink(hwndClientDDE)

HWND hwndClientDDE;

{

    HANDLE hData;

    LPSTR lpData;

    HWND hwndServerDDE;

    CHAR szApplication[APP_MAX_SIZE + 1];

    CHAR szTopic[TOPIC_MAX_SIZE + 1];

    CHAR szItem[ITEM_MAX_SIZE + 1];

    int nBufLen;

    if (OpenClipboard(hwndClientDDE)) {

        if (!(hData = GetClipboardData(cfLink)) ||

                !(lpData = GlobalLock(hData))) {

            CloseClipboard();

            return;

        }

        /* Parse the clipboard data. */

        if ((nBufLen = lstrlen(lpData)) >= APP_MAX_SIZE) {

            CloseClipboard();

            GlobalUnlock(hData);

            return;

        }

        lstrcpy(szApplication, lpData);

        lpData += (nBufLen + 1); /* skips over null */

        if ((nBufLen = lstrlen(lpData)) >= TOPIC_MAX_SIZE) {

            CloseClipboard();

            GlobalUnlock(hData);

            return;

        }

        lstrcpy(szTopic, lpData);

        lpData += (nBufLen + 1); /* skips over null */

        if ((nBufLen = lstrlen(lpData)) >= ITEM_MAX_SIZE) {

            CloseClipboard();

            GlobalUnlock(hData);

            return;

        }

        lstrcpy(szItem, lpData);

        GlobalUnlock(hData);

        CloseClipboard();

        if (hwndServerDDE =

                FindServerGivenAppTopic(szApplication, szTopic)) {

            /* App/topic conversation is already started. */

            if (DoesAdviseAlreadyExist(hwndServerDDE, szItem))

                MessageBox(hwndMain,

                    "Advisory already established",

                    "Client", MB_ICONEXCLAMATION | MB_OK);

            else

                SendAdvise(hwndClientDDE, hwndServerDDE, szItem);

        }

        else {

            /* Client must initiate a new conversation first. */

            SendInitiate(szApplication, szTopic);

            if (hwndServerDDE =

                    FindServerGivenAppTopic(szApplication,

                        szTopic))

                SendAdvise(hwndClientDDE, hwndServerDDE, szItem);

        }

    }

    return;

}

In this example, the client application opens the clipboard and determines whether it contains data in the Link format (that is, cfLink) it had previously registered. If not, or if it cannot lock the data in the clipboard, the client returns.

After the client application retrieves a pointer to the clipboard data, it parses the data to extract the application, topic, and item names.

The client application determines whether a conversation on the topic already exists between it and the server application. If a conversation does exist, the client checks whether a link already exists for the data item. If such a link exists, the client displays a message box to the user; otherwise, it calls its own SendAdvise function to send a WM_DDE_ADVISE message to the server for the item.

If a conversation on the topic does not already exist between the client and the server, the client first calls its own SendInitiate function to broadcast the WM_DDE_INITIATE message to request a conversation and, second, calls its own FindServerGivenAppTopic function to establish the conversation with the window that responds on behalf of the server application. After the conversation has begun, the client application calls SendAdvise to request the link.


Notifying the Client that Data Has Changed

When the client establishes a link by using the WM_DDE_ADVISE message, with the fDeferUpd member not set (that is, equal to zero) in the DDEDATA structure, the client has requested the server send the data item each time the item's value changes. In such cases, the server renders the new value of the data item in the previously specified format and sends the client a WM_DDE_DATA message, as shown in the following example.

/*

 * Allocate the size of a DDE data header, plus data (a string),

 * plus a <CR><LF><NULL>

 */

if (!(hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE,

        sizeof(DDEDATA) + lstrlen(szItemValue) + 3)))

    return;

if (!(lpData = (DDEDATA FAR*) GlobalLock(hData))) {

    GlobalFree(hData);

    return;

}

lpData->fAckReq = bAckRequest;  /* as specified in original     */

                                /* WM_DDE_ADVISE message        */

lpData->cfFormat = CF_TEXT;

lstrcpy(lpData->Value, szItemValue); /* copies value to be sent */

lstrcat(lpData->Value, "\r\n"); /* CR/LF for CF_TEXT format     */

GlobalUnlock(hData);

if ((atomItem = GlobalAddAtom(szItemName)) != 0) {

    if (!PostMessage(hwndClientDDE,

            WM_DDE_DATA,

            (WPARAM) hwndServerDDE,

            PackDDElParam(WM_DDE_DATA, (UINT) hData, atomItem))) {

        GlobalFree(hData);

        GlobalDeleteAtom(atomItem);

        FreeDDElParam(WM_DDE_DATA, lParam);

    }

}

if (atomItem == 0) {

     .

     . /* error handling */

     .

}

In this example, the client processes the item value as appropriate. If the fAckReq flag for the item is set, the client sends the server a positive WM_DDE_ACK message.

When the client establishes the link, with the fDeferUpd member set (that is, equal to 1), the client has requested that only a notification, not the data itself, be sent each time the data changes. In such cases, when the item value changes, the server does not render the value but simply sends the client a WM_DDE_DATA message with a null data handle, as illustrated in the following example.

if (bDeferUpd) {     /* checking whether the flag was originally */

                     /* set in the WM_DDE_ADVISE message         */

    if ((atomItem = GlobalAddAtom(szItemName)) != 0) {

        if (!PostMessage(hwndClientDDE,

                WM_DDE_DATA,

                (WPARAM) hwndServerDDE,

                PackDDElParam(WM_DDE_DATA, 0,

                    atomItem))) {                   /* NULL data */

            GlobalDeleteAtom(atomItem);

            FreeDDElParam(WM_DDE_DATA, lParam);

        }

    }

}

if (atomItem == 0) {

     .

     . /* error handling */

     .

}

As necessary, the client can request the latest value of the data item by issuing a normal WM_DDE_REQUEST message, or it can simply ignore the notice from the server that the data has changed. In either case, if fAckReq is equal to 1, the client is expected to send a positive WM_DDE_ACK message to the server.


Terminating a Data Link

If the client requests that a specific data link be terminated, the client sends the server a WM_DDE_UNADVISE message, as shown in the following example.

if ((atomItem = GlobalAddAtom(szItemName)) != 0) {

    if (!PostMessage(hwndServerDDE,

            WM_DDE_UNADVISE,

            (WPARAM) hwndClientDDE,

            PackDDElParam(WM_DDE_UNADVISE, 0, atomItem))) {

        GlobalDeleteAtom(atomItem);

        FreeDDElParam(WM_DDE_UNADVISE, lParam);

    }

}

if (atomItem == 0) {

     .

     . /* error handling */

     .

}

The server checks whether the client currently has a link to the specific item in this conversation. If a link exists, the server sends the client a positive WM_DDE_ACK message; the server is then no longer required to send updates about the item. If no link exists, the server sends the client a negative WM_DDE_ACK message.

The WM_DDE_UNADVISE message specifies a data format. A format of zero informs the server to stop all links for the specified item, even if several hot links are established and each uses a different format.

To terminate all links for a conversation, the client application sends the server a WM_DDE_UNADVISE message with a null item atom. The server determines whether the conversation has at least one link currently established. If a link exists, the server sends the client a positive WM_DDE_ACK message; the server then no longer has to send any updates in the conversation. If no link exists, the server sends the client a negative WM_DDE_ACK message.


Carrying Out Commands in a Server Application

A Win32-based application can use the WM_DDE_EXECUTE message to cause a certain command or series of commands to be carried out in another application. To do this, the client sends the server a WM_DDE_EXECUTE message containing a handle to a command string, as shown in the following example.

if (!(hCommand = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE,

        sizeof(szCommandString) + 1)))

    return;

if (!(lpCommand = GlobalLock(hCommand))) {

    GlobalFree(hCommand);

    return;

}

lstrcpy(lpCommand, szCommandString);

GlobalUnlock(hCommand);

if (!PostMessage(hwndServerDDE,

        WM_DDE_EXECUTE,

        (WPARAM) hwndClientDDE,

        PackDDElParam(WM_DDE_EXECUTE, 0, (UINT) hCommand))) {

    GlobalFree(hCommand);

    FreeDDElParam(WM_DDE_EXECUTE, lParam);

}

In this example, the server attempts to carry out the specified command string. If it succeeds, the server sends the client a positive WM_DDE_ACK message; otherwise, it sends a negative WM_DDE_ACK message. This WM_DDE_ACK message reuses the hCommand handle passed in the original WM_DDE_EXECUTE message.

If the client's command execution string requests that the server terminate, the server should respond by sending a positive WM_DDE_ACK message and then post a WM_DDE_TERMINATE message before terminating. All other commands sent with a WM_DDE_EXECUTE message should be executed synchronously; that is, the server should send a WM_DDE_ACK message only after successfully completing the command.


Terminating a Conversation

Either the client or the server can issue a WM_DDE_TERMINATE message to terminate a conversation at any time. Similarly, both the client and server applications should be prepared to receive this message at any time. An application must terminate all of its conversations before shutting down.

In the following example, the application terminating the conversation posts a WM_DDE_TERMINATE message.

PostMessage(hwndServerDDE, WM_DDE_TERMINATE,

    PackDDElParam(WM_DDE_TERMINATE, (UINT) hwndClientDDE, 0), 0);

This informs the other application that the sending application will send no further messages and the recipient can close its window. The recipient is expected in all cases to respond promptly by sending a WM_DDE_TERMINATE message. The recipient must not send a negative, busy, or positive WM_DDE_ACK message.

After an application has sent the WM_DDE_TERMINATE message to the partner in a DDE conversation, it must not respond to messages from that partner, since the partner might have destroyed the window to which the response would be sent.

If an application receives a DDE message other than WM_DDE_TERMINATE after it has posted WM_DDE_TERMINATE, it should free all objects associated with the received messages except the data handles for WM_DDE_DATA or WM_DDE_POKE messages that do not have the fRelease member set.

When an application is about to terminate, it should end all active DDE conversations before completing processing of the WM_DESTROY message. However, if an application does not end its active DDE conversations, the system will terminate any DDE conversations associated with a window when the window is destroyed. The following example shows how a server application terminates all DDE conversations.

void TerminateConversations(hwndServerDDE)

HWND hwndServerDDE;

{

    HWND hwndClientDDE;

    /* Terminate each active conversation. */

    while (hwndClientDDE = GetNextLink(hwndClientDDE)) {

        SendTerminate(hwndServerDDE, hwndClientDDE);

    }

    return;

}

BOOL AtLeastOneLinkActive(VOID)

{

    return TRUE;

}

HWND GetNextLink(hwndDummy)

    HWND hwndDummy;

{

    return (HWND) 1;

}

VOID SendTerminate(HWND hwndServerDDE, HWND hwndClientDDE)

{

    return;

}


Dynamic Data Exchange Reference

The following functions and messages are associated with dynamic data exchange.


Dynamic Data Exchange Functions

Following are the functions used with DDE.

DdeSetQualityOfService
FreeDDElParam
ImpersonateDdeClientWindow
PackDDElParam
ReuseDDElParam
UnpackDDElParam


Dynamic Data Exchange Messages

Following are the messages used with DDE.

WM_DDE_ACK
WM_DDE_ADVISE
WM_DDE_DATA
WM_DDE_EXECUTE
WM_DDE_INITIATE
WM_DDE_POKE
WM_DDE_REQUEST
WM_DDE_TERMINATE
WM_DDE_UNADVISE


Dynamic Data Exchange Management Library

In Microsoft® Windows®, dynamic data exchange (DDE) is a form of interprocess communications that uses shared memory to exchange data between applications. Applications can use DDE for one-time data transfers and for ongoing exchanges and updating of data.


About the DDEML

DDE differs from the clipboard data-transfer mechanism that is also part of the Windows operating system. One difference is that the clipboard is almost always used as a one-time response to a specific action by the user — such as choosing the Paste command from a menu. Although DDE may also be initiated by a user, it typically continues without the user's further involvement.

The dynamic data exchange management library (DDEML) provides an application programming interface (API) that simplifies the task of adding DDE capability to a Windows application. Instead of sending, posting, and processing DDE messages directly, an application uses the functions provided by the DDEML to manage DDE conversations. A DDE conversation is the interaction between client and server applications. The DDEML also provides a means for managing the strings and data shared among DDE applications. Instead of using atoms and pointers to shared memory objects, DDE applications create and exchange string handles, which identify strings, and data handles, which identify DDE objects. The DDEML provides a function (DdeNameService) that enables a server application to register the service names it supports. The service names are then broadcast to other applications in the system, which use the names to connect to the server. The DDEML also ensures compatibility among DDE applications by requiring them to implement the DDE protocol in a consistent manner.

Existing applications using the message-based DDE protocol are fully compatible with those that use the DDEML; that is, an application using message-based DDE can establish conversations and perform transactions with applications using the DDEML. Instead of using DDE messages in your new application, take advantage of the DDEML and the many improvements it offers.

To use the API elements of the DDEML, you must include the DDEML.H header file in your source files, link with the USER32.LIB file, and ensure that the DDEML.DLL file resides in the system's path.


Basic Concepts

The concepts in this section are key to understanding DDE and the DDEML.


Client and Server Interaction

DDE always occurs between a client application and a server application. The DDE client application initiates the exchange by establishing a conversation with the server to send transactions to the server. A transaction is a request for data or services. The DDE server application responds to transactions by providing data or services to the client. For example, a graphics application might contain a bar graph representing a corporation's quarterly profits, but the data for the bar graph might be contained in a spreadsheet application. To obtain the latest profit figures, the graphics application (the client) could establish a conversation with the spreadsheet application (the server). The graphics application could then send a transaction to the spreadsheet application, requesting the latest profit figures.

A server can have many clients at the same time, and a client can request data from multiple servers. An application can also be both a client and a server. Either the client or the server can terminate the conversation at any time.


Transactions and the DDE Callback Function

The DDEML notifies an application about DDE activity that affects the application by sending transactions to the application's DDE callback function. A DDE transaction is similar to a message — it is a named constant accompanied by other parameters that contain additional information about the transaction.

The DDEML passes a transaction to an application-defined DDE callback function that carries out an action appropriate to the type of transaction. For example, when a client application attempts to establish a conversation with a server application, the client calls the DdeConnect function. This function causes the DDEML to send an XTYP_CONNECT transaction to the server's DDE callback function. The callback function can allow the conversation by returning TRUE to the DDEML, or it can deny the conversation by returning FALSE. For a detailed discussion of transactions, see Transaction Management.


Service Names, Topic Names, and Item Names

A DDE server uses a three-level hierarchy — service name (called "application name" in previous DDE documentation), topic name, and item name — to uniquely identify a unit of data the server can exchange during a conversation.

A service name is a string a server application responds to when a client attempts to establish a conversation with the server. A client must specify this service name to establish a conversation with the server. Although a server can respond to many service names, most servers respond to only one name.

A topic name is a string that identifies a logical data context. For servers that operate on file-based documents, topic names are typically filenames; for other servers, they are other application-specific strings. A client must specify a topic name along with a server's service name when it attempts to establish a conversation with a server.

An item name is a string that identifies a unit of data a server can pass to a client during a transaction. For example, an item name might identify an integer, a string, several paragraphs of text, or a bitmap.

The service, topic, and item names enable the client to establish a conversation with a server and to receive data from the server.


System Topic

The System topic provides a context for information of general interest to any DDE client. It is recommended that server applications support the System topic at all times. The System topic is defined in the DDEML.H header file as SZDDESYS_TOPIC.

To determine which servers are present and the kinds of information they can provide, a client application can request a conversation on the System topic upon starting, setting the device name to NULL. Such wildcard conversations are costly in terms of system performance, so they should be kept to a minimum. For more information about initiating DDE conversations, see Conversation Management.

A server must support the following item names within the System topic and any other item names that are useful to a client.

Item	Description
SZDDE_ITEM_ITEMLIST	A list of the items supported under a non-System topic. (This list may vary from moment to moment and from topic to topic.)
SZDDESYS_ITEM_FORMATS	A tab-delimited list of strings representing all clipboard formats potentially supported by the service application. Strings that represent predefined clipboard formats are equivalent to the CF_ values with the "CF_" prefix removed. For example, the CF_TEXT format is represented by the string "TEXT". These strings must be uppercase to further identify them as predefined formats. The list of formats must appear in the order of most rich in content to least rich in content.
	For more information about clipboard formats and rendering data, see Clipboard.
SZDDESYS_ITEM_HELP	User-readable information of general interest. This item must contain, at a minimum, information on how to use the server application's DDE features. This information may include, but is not limited to, how to specify items within topics, what execute strings the server can perform, what poke transactions are allowed, and how to find help on other System topic items.
SZDDESYS_ITEM_RTNMSG	Supporting detail for the most recently used WM_DDE_ACK message. This item is useful when more than 8 bits of application-specific return data are required.
SZDDESYS_ITEM_STATUS	An indication of the current status of the server. Typically, this item supports only the CF_TEXT format and contains the Ready or Busy string.
SZDDESYS_ITEM_SYSITEMS	A list of the items supported under the System topic by this server.
SZDDESYS_ITEM_TOPICS	A list of the topics supported by the server at the current time. (This list may vary from moment to moment.)
These item names are values defined in the DDEML.H header file. To obtain string handles for these strings, an application must use the DDEML string-management functions, just as it would for any other string in a DDEML application. For more information about managing strings, see String Management.


DDEML and Threads

The DDEInitialize function registers an application with the DDEML, creating a DDEML instance. A DDEML instance is thread-based, associated with the thread that called DDEInitialize.

All DDEML function calls for objects belonging to a DDEML instance must be made from the same thread that called DDEInitialize to create the instance. If you call a DDEML function from a different thread, the function will fail. You cannot access a DDEML conversation from a thread other than the one that allocated the conversation.


Initialization

Before calling any other DDEML function, an application must call the DdeInitialize function. DdeInitialize obtains an instance identifier for the application, registers the application's DDE callback function with the DDEML, and specifies the transaction filter flags for the callback function.

Each instance of an application or a dynamic-link library (DLL) must pass its instance identifier as the idInst parameter to any other DDEML function that requires it. The purpose of multiple DDEML instances is to support DLLs that must use the DDEML at the same time an application is using it. An application must not use more than one instance of the DDEML.

Transaction filters optimize system performance by preventing the DDEML from passing unwanted transactions to the application's DDE callback function. An application sets the transaction filters when it calls DdeInitialize. An application must specify a transaction filter flag for each type of transaction that it does not process in its callback function. An application can change its transaction filters with a subsequent call to DdeInitialize. For a complete list of transaction filter flags, see the description of DdeInitialize in the Microsoft Win32 Programmer's Reference, Volume 3. For more information about transactions, see Transaction Management.

The following example shows how to initialize an application to use the DDEML.

DWORD idInst = 0;

HINSTANCE hinst;

.

.

.

DdeInitialize(&idInst,         /* receives instance identifier */

    (PFNCALLBACK) DdeCallback, /* address of callback function */

    CBF_FAIL_EXECUTES |        /* filter XTYPE_EXECUTE         */

    CBF_SKIP_ALLNOTIFICATIONS, /* filter notifications         */

    0);

.

.

.

An application must call the DdeUninitialize function when it is no longer going to use the DDEML. This function terminates any conversations currently open for the application and frees the DDEML resources the system allocated for the application.


Callback Function

An application that uses the DDEML must provide a callback function that processes the DDE events affecting the application. The DDEML notifies an application of such events by sending transactions to the application's DDE callback function. The transactions a callback function receives depend on which callback filter flags the application specified in DdeInitialize and whether the application is a client, a server, or both. The following example shows the general structure of a callback function for a typical client application.

HDDEDATA CALLBACK DdeCallback(uType, uFmt, hconv, hsz1,

    hsz2, hdata, dwData1, dwData2)

UINT uType;       /* transaction type                 */

UINT uFmt;        /* clipboard data format            */

HCONV hconv;      /* handle of conversation           */

HSZ hsz1;         /* handle of string                 */

HSZ hsz2;         /* handle of string                 */

HDDEDATA hdata;   /* handle of global memory object   */

DWORD dwData1;    /* transaction-specific data        */

DWORD dwData2;    /* transaction-specific data        */

{

    switch (uType) {

        case XTYP_REGISTER:

        case XTYP_UNREGISTER:

            .

            .

            .

            return (HDDEDATA) NULL;

        case XTYP_ADVDATA:

            .

            .

            .

            return (HDDEDATA) DDE_FACK;

        case XTYP_XACT_COMPLETE:

            .

            .

            .

            return (HDDEDATA) NULL;

        case XTYP_DISCONNECT:

            .

            .

            .

            return (HDDEDATA) NULL;

        default:

            return (HDDEDATA) NULL;

    }

}

The uType parameter specifies the transaction type sent to the callback function by the DDEML. The values of the remaining parameters depend on the transaction type. The transaction types and the events that generate them are described in the following topics. For detailed information about each transaction type, see Transaction Management.


String Management

To carry out a DDE task, many DDEML functions require access to strings. For example, a client must specify a service name and a topic name when it calls the DdeConnect function to request a conversation with a server. An application specifies a string by passing a string handle (HSZ) rather than a pointer in a DDEML function. A string handle is a doubleword value, assigned by the system, that identifies a string.

An application can obtain a string handle for a particular string by calling the DdeCreateStringHandle function. This function registers the string with the system and returns a string handle to the application. The application can pass the handle to DDEML functions that must access the string. The following example obtains string handles for the System topic string and the service name string.

HSZ hszServName;

HSZ hszSysTopic;

.

.

.

hszServName = DdeCreateStringHandle(

    idInst,         /* instance identifier    */

    "MyServer",     /* string to register     */

    CP_WINANSI);    /* Windows ANSI code page */

hszSysTopic = DdeCreateStringHandle(

    idInst,         /* instance identifier    */

    SZDDESYS_TOPIC, /* System topic           */

    CP_WINANSI);    /* Windows ANSI code page */

.

.

.

The idInst parameter in the preceding example specifies the instance identifier obtained by the DdeInitialize function.

An application's DDE callback function receives one or more string handles during most DDE transactions. For example, a server receives two string handles during the XTYP_REQUEST transaction: one identifies a string specifying a topic name, and the other identifies a string specifying an item name. An application can obtain the length of the string that corresponds to a string handle and copy the string to an application-defined buffer by calling the DdeQueryString function, as shown in the following example.

DWORD idInst;

DWORD cb;

HSZ hszServ;

PSTR pszServName;

.

.

.

cb = DdeQueryString(idInst, hszServ, (LPSTR) NULL, 0,

    CP_WINANSI) + 1;

pszServName = (PSTR) LocalAlloc(LPTR, (UINT) cb);

DdeQueryString(idInst, hszServ, pszServName, cb, CP_WINANSI);

.

.

.

An instance-specific string handle cannot be mapped from string handle to string and back to string handle. For instance, although DdeQueryString creates a string from a string handle and then DdeCreateStringHandle creates a string handle from that string, the two handles are not the same, as shown in the following example.

DWORD idInst;

DWORD cb;

HSZ hszInst, hszNew;

PSZ pszInst;

.

.

.

DdeQueryString(idInst, hszInst, pszInst, cb, CP_WINANSI);

hszNew = DdeCreateStringHandle(idInst, pszInst, CP_WINANSI);

/* hszNew != hszInst ! */

.

.

.

A string handle passed to an application's DDE callback function becomes invalid when the callback function returns. An application can save a string handle for use after the callback function returns by using the DdeKeepStringHandle function.

When an application calls DdeCreateStringHandle, the system enters the specified string into a string table and generates a handle that it uses to access the string. The system also maintains a usage count for each string in the string table.

When an application calls DdeCreateStringHandle and specifies a string that already exists in the table, the system increments the usage count rather than adding another occurrence of the string. (An application can also increment the usage count by using DdeKeepStringHandle.) When an application calls the DdeFreeStringHandle function, the system decrements the usage count.

A string is removed from the table when its usage count equals zero. Because more than one application can obtain the handle of a particular string, an application must not free a string handle more times than it has created or retained the handle. Otherwise, the application can cause the string to be removed from the table, denying other applications access to the string.

The DDEML string-management functions are based on the Windows atom manager and are subject to the same size restrictions as are atoms.


Name Service

The DDEML makes it possible for a server application to register the service names that it supports and to prevent the DDEML from sending XTYP_CONNECT transactions for unsupported service names to the server's DDE callback function. The remaining topics in this section describe the name service.


Service Name Registration

By registering its service names with the DDEML, a server informs other DDE applications in the system that a new server is available. A server registers a service name by calling the DdeNameService function and specifying a string handle that identifies the name. In response, the DDEML sends an XTYP_REGISTER transaction to the callback function of each DDEML application in the system (except those that specified the CBF_SKIP_REGISTRATIONS filter flag in the DdeInitialize function). The XTYP_REGISTER transaction passes two string handles to a callback function: the first identifies the string specifying the base service name, and the second identifies the string specifying the instance-specific service. A client typically uses the base service name in a list of available servers, so the user can select a server from the list. The client uses the instance-specific service name to establish a conversation with a specific instance of a server application, if more than one instance is running.

A server can use DdeNameService to unregister a service name. This function causes the DDEML to send XTYP_UNREGISTER transactions to the other DDE applications in the system, informing them that they can no longer use the name to establish conversations.

A server must call DdeNameService to register its service names soon after calling DdeInitialize. A server must unregister its service names by using DdeNameService just before calling the DdeUninitialize function.


Service Name Filter

In addition to registering service names, DdeNameService enables a server to turn its service name filter on or off. When a server turns off its service name filter, the DDEML sends the XTYP_CONNECT transaction to the server's DDE callback function whenever any client calls the DdeConnect function, regardless of the service name specified in the function. When a server turns on its service name filter, the DDEML sends the XTYP_CONNECT transaction to the server only when DdeConnect specifies a service name the server has specified in a call to DdeNameService.

By default, the service name filter is on when an application calls DdeInitialize. This default prevents the DDEML from sending the XTYP_CONNECT transaction to a server before the server has created the string handles it needs. A server can turn off its service name filter by specifying the DNS_FILTEROFF flag in a call to DdeNameService. The DNS_FILTERON flag turns on the filter.


Conversation Management

A conversation between a client and a server is always established at the request of the client. When a conversation is established, each partner receives a handle that identifies the conversation. The partners use this handle in other DDEML functions to send transactions and manage the conversation. A client can request a conversation with a single server, or it can request multiple conversations with one or more servers.

The remaining topics in this section describe how an application establishes new conversations and gets information about existing conversations.


Single Conversations

A client application requests a single conversation with a server by calling the DdeConnect function and specifying string handles that identify the strings containing the service name of the server application and the topic name for the conversation. The DDEML responds by sending the XTYP_CONNECT transaction to the DDE callback function of each server application that either has registered a service name that matches the one specified in DdeConnect or has turned service name filtering off by calling DdeNameService. A server can also filter XTYP_CONNECT transactions by specifying the CBF_FAIL_CONNECTIONS filter flag in the DdeInitialize function. During the XTYP_CONNECT transaction, the DDEML passes the service name and the topic name to the server. The server must examine the names and return TRUE if it supports the service name and topic name pair or FALSE if it does not.

If no server responds positively to the client's request to connect, the client receives NULL from DdeConnect and no conversation is established. If a server returns TRUE, a conversation is established and the client receives a conversation handle — a doubleword value that identifies the conversation. The client uses the handle in subsequent DDEML calls to obtain data from the server. The server receives the XTYP_CONNECT_CONFIRM transaction (unless the server specified the CBF_SKIP_CONNECT_CONFIRMS filter flag). This transaction passes the conversation handle to the server.

The following example requests a conversation on the System topic with a server that recognizes the service name MyServer. The hszServName and hszSysTopic parameters are previously created string handles.

HCONV hConv;         /* conversation handle            */

HWND hwndParent;     /* parent window handle           */

HSZ hszServName;     /* service name string handle     */

HSZ hszSysTopic;     /* System topic string handle     */

.

.

hConv = DdeConnect(

    idInst,               /* instance identifier        */

    hszServName,          /* service name string handle */

    hszSysTopic,          /* System topic string handle */

    (PCONVCONTEXT) NULL); /* use default context        */

if (hConv == NULL) {

    MessageBox(hwndParent, "MyServer is unavailable.",

        (LPSTR) NULL, MB_OK);

    return FALSE;

}

.

.

.

In the preceding example, DdeConnect causes the DDE callback function of the MyServer application to receive an XTYP_CONNECT transaction.

In the following example, the server responds to the XTYP_CONNECT transaction by comparing the topic name string handle the DDEML passed to the server with each element in the array of topic name string handles the server supports. If the server finds a match, it establishes the conversation.

#define CTOPICS 5

HSZ hsz1;                  /* string handle passed by DDEML  */

HSZ ahszTopics[CTOPICS];   /* array of supported topics      */

int i;                     /* loop counter                   */

.

. /* Use a switch statement to examine transaction types. */

.

case XTYP_CONNECT:

    for (i = 0; i < CTOPICS; i++) {

        if (hsz1 == ahszTopics[i])

            return TRUE;   /* establish a conversation       */

    }

    return FALSE; /* topic not supported; deny conversation  */

.

. /* Process other transaction types. */

.

If the server returns TRUE in response to the XTYP_CONNECT transaction, the DDEML sends an XTYP_CONNECT_CONFIRM transaction to the server's DDE callback function. The server can obtain the handle for the conversation by processing this transaction.

A client can establish a wildcard conversation by specifying NULL for the service name string handle, the topic name string handle, or both in a call to DdeConnect. If at least one of the string handles is NULL, the DDEML sends the XTYP_WILDCONNECT transaction to the callback functions of all DDE applications (except those that filter the XTYP_WILDCONNECT transaction). Each server application should respond by returning a data handle that identifies a null-terminated array of HSZPAIR structures. If the server application has not called DdeNameService to register its service names and if filtering is on, the server does not receive XTYP_WILDCONNECT transactions. For more information about data handles, see Data Management.

The array must contain one structure for each service name and topic name pair that matches the pair specified by the client. The DDEML selects one of the pairs to establish a conversation and returns to the client a handle that identifies the conversation. The DDEML sends the XTYP_CONNECT_CONFIRM transaction to the server (unless the server filters this transaction). The following example shows a typical server response to the XTYP_WILDCONNECT transaction.

#define CTOPICS 2

UINT uType;

HSZPAIR ahszp[(CTOPICS + 1)];

HSZ ahszTopicList[CTOPICS];

HSZ hszServ, hszTopic;

WORD i, j;

if (uType == XTYP_WILDCONNECT) {

     /*

      * Scan the topic list and create an array of HSZPAIR

      * structures.

      */

    j = 0;

    for (i = 0; i < CTOPICS; i++) {

        if (hszTopic == (HSZ) NULL ||

                hszTopic == ahszTopicList[i]) {

            ahszp[j].hszSvc = hszServ;

            ahszp[j++].hszTopic = ahszTopicList[i];

        }

    }

    /*

     * End the list with an HSZPAIR structure that contains NULL

     * string handles as its members.

     */

    ahszp[j].hszSvc = NULL;

    ahszp[j++].hszTopic = NULL;

    /*

     * Return a handle to a global memory object containing the

     * HSZPAIR structures.

     */

    return DdeCreateDataHandle(

        idInst,          /* instance identifier     */

        (LPBYTE) &ahszp, /* points to HSZPAIR array */

        sizeof(HSZ) * j, /* length of the array     */

        0,               /* start at the beginning  */

        (HSZ) NULL,      /* no item name string     */

        0,               /* return the same format  */

        0);              /* let the system own it   */

}

Either the client or the server can terminate a conversation at any time by calling the DdeDisconnect function. This function causes the callback function of the partner in the conversation to receive the XTYP_DISCONNECT transaction (unless the partner specified the CBF_SKIP_DISCONNECTS filter flag). Typically, an application responds to the XTYP_DISCONNECT transaction by using the DdeQueryConvInfo function to obtain information about the conversation that terminated. After the callback function returns from processing the XTYP_DISCONNECT transaction, the conversation handle is no longer valid.

A client application that receives an XTYP_DISCONNECT transaction in its DDE callback function can attempt to reestablish the conversation by calling the DdeReconnect function. The client must call DdeReconnect from within its DDE callback function.


Multiple Conversations

A client application can use the DdeConnectList function to determine whether any servers of interest are available in the system. A client specifies a service name and topic name when it calls DdeConnectList, causing the DDEML to broadcast the XTYP_WILDCONNECT transaction to the DDE callback functions of all servers that match the service name (except those that filter the transaction). A server's callback function should return a data handle that identifies a null-terminated array of HSZPAIR structures. The array should contain one structure for each service name and topic name pair that matches the pair specified by the client. The DDEML establishes a conversation for each HSZPAIR structure filled by the server and returns a conversation list handle to the client. The server receives the conversation handle by way of the XTYP_CONNECT_CONFIRM transaction (unless the server filters this transaction).

A client can specify NULL for the service name, topic name, or both when it calls DdeConnectList. If the service name is NULL, all servers in the system that support the specified topic name respond. A conversation is established with each responding server, including multiple instances of the same server. If the topic name is NULL, a conversation is established on each topic recognized by each server that matches the service name.

A client can use the DdeQueryNextServer and DdeQueryConvInfo functions to identify the servers that respond to DdeConnectList. DdeQueryNextServer returns the next conversation handle in a conversation list, and DdeQueryConvInfo fills a CONVINFO structure with information about the conversation. The client can keep the conversation handles that it needs and discard the rest from the conversation list.

The following example uses DdeConnectList to establish conversations with all servers that support the System topic and then uses the DdeQueryNextServer and DdeQueryConvInfo functions to obtain the servers' service name string handles and store them in a buffer.

HCONVLIST hconvList; /* conversation list       */

DWORD idInst;        /* instance identifier     */

HSZ hszSystem;       /* System topic            */

HCONV hconv = NULL;  /* conversation handle     */

CONVINFO ci;         /* holds conversation data */

UINT cConv = 0;      /* count of conv. handles  */

HSZ *pHsz, *aHsz;    /* point to string handles */

/* Connect to all servers that support the System topic. */

hconvList = DdeConnectList(idInst, NULL, hszSystem, NULL, NULL);

/* Count the number of handles in the conversation list. */

while ((hconv = DdeQueryNextServer(hconvList, hconv)) != NULL)

    cConv++;

/* Allocate a buffer for the string handles. */

hconv = NULL;

aHsz = (HSZ *) LocalAlloc(LMEM_FIXED, cConv * sizeof(HSZ));

/* Copy the string handles to the buffer. */

pHsz = aHsz;

while ((hconv = DdeQueryNextServer(hconvList, hconv)) != NULL) {

    DdeQueryConvInfo(hconv, QID_SYNC, (PCONVINFO) &ci);

    DdeKeepStringHandle(idInst, ci.hszSvcPartner);

    *pHsz++ = ci.hszSvcPartner;

}

.

. /* Use the handles; converse with the servers. */

.

/* Free the memory and terminate the conversations. */

LocalFree((HANDLE) aHsz);

DdeDisconnectList(hconvList);

An application can terminate an individual conversation in a conversation list by calling the DdeDisconnect function. An application can terminate all conversations in a conversation list by calling the DdeDisconnectList function. Both functions cause the DDEML to send XTYP_DISCONNECT transactions to each partner's DDE callback function. DdeDisconnectList sends an XTYP_DISCONNECT transaction for each conversation handle in the list.

A client can retrieve a list of the conversation handles in a conversation list by passing an existing conversation list handle to DdeConnectList. The enumeration process removes the handles of terminated conversations from the list, and nonduplicate conversations that fit the specified service name and topic name are added.

If DdeConnectList specifies an existing conversation list handle, the function creates a new conversation list that contains the handles of any new conversations and the handles from the existing list.

If duplicate conversations exist, DdeConnectList attempts to prevent duplicate conversation handles in the conversation list. A duplicate conversation is a second conversation with the same server on the same service name and topic name. Two such conversations would have different handles, yet they would identify the same conversation.


Data Management

Because DDE uses memory objects to pass data from one application to another, the DDEML provides a set of functions that DDE applications can use to create and manage DDE objects.

All transactions that involve the exchange of data require the application supplying the data to create a local buffer containing the data and then to call the DdeCreateDataHandle function. This function allocates a DDE object, copies the data from the buffer to the object, and returns a data handle. A data handle is a doubleword value that the DDEML uses to provide access to data in the DDE object. To share the data in a DDE object, an application passes the data handle to the DDEML, and the DDEML passes the handle to the DDE callback function of the application that is receiving the data transaction.

The following example shows how to create a DDE object and obtain a handle of the object. During the XTYP_ADVREQ transaction, the callback function converts the current time to an ASCII string, copies the string to a local buffer, and then creates a DDE object that contains the string. The callback function returns the handle of the DDE object (HDDEDATA) to the DDEML, which passes the handle to the client application.

typedef struct tagTIME

  {

    INT     hour;   /* 0 - 11 hours for analog clock */

    INT     hour12; /* 12-hour format */

    INT     hour24; /* 24-hour format */

    INT     minute;

    INT     second;

    INT     ampm;   /* 0 - AM , 1 - PM */

  } TIME;

HDDEDATA EXPENTRY DdeCallback(uType, uFmt, hconv, hsz1, hsz2,

    hdata, dwData1, dwData2)

UINT uType;

UINT uFmt;

HCONV hconv;

HSZ hsz1;

HSZ hsz2;

HDDEDATA hdata;

DWORD dwData1;

DWORD dwData2;

{

    CHAR szBuf[32];

    switch (uType) {

    case XTYP_ADVREQ:

        if ((hsz1 == hszTime && hsz2 == hszNow) &&

                (uFmt == CF_TEXT)) {

            /* Copy the formatted string to a buffer. */

            itoa(tmTime.hour, szBuf, 10);

            lstrcat(szBuf, ":");

            if (tmTime.minute < 10)

                lstrcat(szBuf, "0");

            itoa(tmTime.minute, &szBuf[lstrlen(szBuf)], 10);

            lstrcat(szBuf, ":");

            if (tmTime.second < 10)

                strcat(szBuf, "0");

            itoa(tmTime.second, &szBuf[lstrlen(szBuf)], 10);

            szBuf[lstrlen(szBuf)] = '\0';

            /* Create a global object and return its data handle. */

            return (DdeCreateDataHandle(

                idInst,

                (LPBYTE) szBuf,     /* instance identifier   */

                lstrlen(szBuf) + 1, /* source buffer length  */

                0,                  /* offset from beginning */

                hszNow,             /* item name string      */

                CF_TEXT,            /* clipboard format      */

                0));                /* no creation flags     */

        } else

            return (HDDEDATA) NULL;

    .

    . /* Process other transactions. */

    .

    }

}

The receiving application obtains a pointer to the DDE object by passing the data handle to the DdeAccessData function. The pointer returned by DdeAccessData provides read-only access. The application should use the pointer to review the data and then call the DdeUnaccessData function to invalidate the pointer. The application can copy the data to a local buffer by using the DdeGetData function.

The following example obtains a pointer to the DDE object identified by the hData parameter, copies the contents to a local buffer, and then invalidates the pointer.

HDDEDATA hdata;

LPBYTE lpszAdviseData;

DWORD cbDataLen;

DWORD i;

char szData[32];

.

.

.

case XTYP_ADVDATA:

    lpszAdviseData = DdeAccessData(hdata, &cbDataLen);

    for (i = 0; i < cbDataLen; i++)

        szData[i] = *lpszAdviseData++;

    DdeUnaccessData(hdata);

    return (HDDEDATA) TRUE;

.

.

.

Usually, when an application that created a data handle passes that handle to the DDEML, the handle becomes invalid in the creating application. This situation is not a problem if the application must share data with only a single application. If an application must share the same data with multiple applications, however, the creating application should specify the HDATA_APPOWNED flag in DdeCreateDataHandle. Doing so gives ownership of the DDE object to the creating application and prevents the DDEML from invalidating the data handle. The application can then pass the data handle any number of times after calling DdeCreateDataHandle only once.

If an application specifies the HDATA_APPOWNED flag in the afCmd parameter of DdeCreateDataHandle, it must call the DdeFreeDataHandle function to free the memory handle, regardless of whether it passed the handle to the DDEML. Before it terminates, an application must call DdeFreeDataHandle to free any data handle that it created but did not pass to the DDEML.

An application that has not yet passed the handle of a DDE object to the DDEML can add data to the object or overwrite data in the object by using the DdeAddData function. Typically, an application uses DdeAddData to fill an uninitialized DDE object. After an application passes a data handle to the DDEML, the DDE object identified by the handle cannot be changed; it can only be freed.


Transaction Management

After establishing a conversation with a server, a client can send transactions to obtain data and services from the server. The remaining topics in this section describe the types of transactions that clients can use to interact with a server.


Request Transaction

A client application can use the XTYP_REQUEST transaction to request a data item from a server application. The client calls the DdeClientTransaction function, specifying XTYP_REQUEST as the transaction type and specifying the data item the application needs.

The DDEML passes the XTYP_REQUEST transaction to the server, specifying the topic name, item name, and data format requested by the client. If the server supports the requested topic, item, and format, the server should return a data handle that identifies the current value of the item. The DDEML passes this handle to the client as the return value from DdeClientTransaction. The server should return NULL if it does not support the topic, item, or format requested.

DdeClientTransaction uses the lpdwResult parameter to return a transaction-status flag to the client. If the server does not process the XTYP_REQUEST transaction, DdeClientTransaction returns NULL, and lpdwResult points to the DDE_FNOTPROCESSED or DDE_FBUSY flag. If the DDE_FNOTPROCESSED flag is returned, the client cannot determine why the server did not process the transaction.

If a server does not support the XTYP_REQUEST transaction, it should specify the CBF_FAIL_REQUESTS filter flag in the DdeInitialize function. This flag prevents the DDEML from sending the transaction to the server.


Poke Transaction

A client can send unsolicited data to a server by using DdeClientTransaction to send an XTYP_POKE transaction to a server's callback function.

The client application first creates a buffer that contains the data to send to the server and then passes a pointer to the buffer as a parameter to DdeClientTransaction. Alternatively, the client can use the DdeCreateDataHandle function to obtain a data handle that identifies the data and then pass the handle to DdeClientTransaction. In either case, the client also specifies the topic name, item name, and data format when it calls DdeClientTransaction.

The DDEML passes the XTYP_POKE transaction to the server, specifying the topic name, item name, and data format that the client requested. To accept the data item and format, the server should return DDE_FACK. To reject the data, the server should return DDE_FNOTPROCESSED. If the server is too busy to accept the data, the server should return DDE_FBUSY.

When DdeClientTransaction returns, the client can use the lpdwResult parameter to access the transaction-status flag. If the flag is DDE_FBUSY, the client should send the transaction again later.

If a server does not support the XTYP_POKE transaction, it should specify the CBF_FAIL_POKES filter flag in DdeInitialize. This flag prevents the DDEML from sending this transaction to the server.


Advise Transaction

A client application can use the DDEML to establish one or more links to items in a server application. When such a link has been established, the server sends periodic updates about the linked item to the client (typically, whenever the value of the item associated with the server application changes). Linking establishes an advise loop between the two applications that remains in place until the client ends it.

There are two kinds of advise loops: "hot" and "warm." In a hot advise loop, the server immediately sends a data handle that identifies the changed value. In a warm advise loop, the server notifies the client that the value of the item has changed but does not send the data handle until the client requests it.

A client can request a hot advise loop with a server by specifying the XTYP_ADVSTART transaction type in a call to DdeClientTransaction. To request a warm advise loop, the client must combine the XTYPF_NODATA flag with the XTYP_ADVSTART transaction type. In either event, the DDEML passes the XTYP_ADVSTART transaction to the server's DDE callback function. The server's DDE callback function should examine the parameters that accompany the XTYP_ADVSTART transaction (including the requested format, topic name, and item name) and then return TRUE to allow the advise loop or FALSE to deny it.

After an advise loop has been established, the server application should call the DdePostAdvise function whenever the value of the item associated with the requested item name changes. This call results in an XTYP_ADVREQ transaction being sent to the server's own DDE callback function. The server's DDE callback function should return a data handle that identifies the new value of the data item. The DDEML then notifies the client that the specified item has changed by sending the XTYP_ADVDATA transaction to the client's DDE callback function.

If the client requested a hot advise loop, the DDEML passes the data handle for the changed item to the client during the XTYP_ADVDATA transaction. Otherwise, the client can send an XTYP_REQUEST transaction to obtain the data handle.

It is possible for a server to send updates faster than a client can process the new data. The speed of updates can be a problem for a client that must perform lengthy processing operations on the data. In this case, the client should specify the XTYPF_ACKREQ flag when it requests an advise loop. This flag causes the server to wait for the client to acknowledge that it has received and processed a data item before the server sends the next data item. Advise loops that are established with the XTYPF_ACKREQ flag are more robust with fast servers but may occasionally miss updates. Advise loops established without the XTYPF_ACKREQ flag are guaranteed not to miss updates as long as the client keeps up with the server.

A client can end an advise loop by specifying the XTYP_ADVSTOP transaction type in a call to DdeClientTransaction.

If a server does not support advise loops, it should specify the CBF_FAIL_ADVISES filter flag in the DdeInitialize function. This flag prevents the DDEML from sending the XTYP_ADVSTART and XTYP_ADVSTOP transactions to the server.


Execute Transaction

A client can use the XTYP_EXECUTE transaction to cause a server to execute a command or a series of commands.

To execute a server command, the client first creates a buffer that contains a command string for the server to execute and then passes either a pointer to the buffer or a data handle identifying the buffer when it calls DdeClientTransaction. Other required parameters include the conversation handle, the item name string handle, the format specification, and the XTYP_EXECUTE transaction type. An application that creates a data handle for passing execute data must specify NULL for the hszItem parameter of the DdeCreateDataHandle function and zero for the uFmt parameter.

The DDEML passes the XTYP_EXECUTE transaction to the server's DDE callback function and specifies the format name, conversation handle, topic name, and data handle identifying the command string. If the server supports the command, it should use the DdeAccessData function to obtain a pointer to the command string, execute the command, and then return DDE_FACK. If the server does not support the command or cannot complete the transaction, it should return DDE_FNOTPROCESSED. The server should return DDE_FBUSY if it is too busy to complete the transaction.

In general, a server's callback function should process the XTYP_EXECUTE transaction before returning with the following exceptions:

1.	When the command passed with the XTYP_EXECUTE transaction requests the server to terminate, the server should not terminate until its callback function returns from processing XTYP_EXECUTE.

2.	If the server must perform an operation, such as processing a dialog box or a DDE transaction that might cause DDEML recursion problems, the server should return the CBR_BLOCK return code to block the execute transaction, perform the operation, and then resume processing the execute transaction.

When DdeClientTransaction returns, the client can use the lpdwResult parameter to access the transaction status flag. If the flag is DDE_FBUSY, the client should send the transaction again later.

If a server does not support the XTYP_EXECUTE transaction, it should specify the CBF_FAIL_EXECUTES filter flag in the DdeInitialize function. Doing so prevents the DDEML from sending the transaction to the server.


Synchronous and Asynchronous Transactions

A client can send either synchronous or asynchronous transactions. In a synchronous transaction, the client specifies a time-out value that indicates the maximum amount of time it will wait for the server to process the transaction. DdeClientTransaction does not return until the server processes the transaction, the transaction fails, or the time-out value expires. The client specifies the time-out value when it calls DdeClientTransaction.

During a synchronous transaction, the client enters a modal loop while waiting for the transaction to be processed. The client can still process user input but cannot send another synchronous transaction until DdeClientTransaction returns.

A client sends an asynchronous transaction by specifying the TIMEOUT_ASYNC flag in DdeClientTransaction. The function returns after the transaction has begun, passing a transaction identifier to the client. When the server finishes processing the asynchronous transaction, the DDEML sends an XTYP_XACT_COMPLETE transaction to the client. One of the parameters that the DDEML passes to the client during the XTYP_XACT_COMPLETE transaction is the transaction identifier. By comparing this transaction identifier with the identifier returned by DdeClientTransaction, the client identifies which asynchronous transaction the server has finished processing.

A client can use the DdeSetUserHandle function as an aid in processing an asynchronous transaction. This function makes it possible for a client to associate an application-defined doubleword value with a conversation handle and a transaction identifier. The client can use the DdeQueryConvInfo function during the XTYP_XACT_COMPLETE transaction to obtain the application-defined doubleword value. Because of this function, an application need not maintain a list of active transaction identifiers.

When a client successfully completes a request for data using a synchronous transaction, the DDEML has no way to tell when the client has finished using the data received. The client application must pass the data handle received to the DdeFreeDataHandle function, notifying the DDEML that the handle will no longer be used. Data handles returned by synchronous transactions are effectively owned by the client.

If a server does not process an asynchronous transaction in a timely manner, the client can abandon the transaction by calling the DdeAbandonTransaction function. The DDEML releases all resources associated with the transaction and discards the results of the transaction when the server finishes processing it. A time-out during a synchronous transaction effectively cancels the transaction.

The asynchronous transaction method is provided for applications that must send a high volume of DDE transactions while simultaneously performing a substantial amount of processing, such as performing calculations. The asynchronous method is also useful in applications that must stop processing DDE transactions temporarily so they can complete other tasks without interruption. In most other situations, an application should use the synchronous method.

Synchronous transactions are simpler to maintain and are faster than asynchronous transactions. However, only one synchronous transaction can be performed at a time, whereas many asynchronous transactions can be performed simultaneously. With synchronous transactions, a slow server can cause a client to remain idle while it is waiting for a response. Also, synchronous transactions cause the client to enter a modal loop that could bypass message filtering in the application's own message loop.

If the client has installed a hook procedure to filter messages (that is, specified the WH_MSGFILTER hook type in a call to the SetWindowsHookEx function), a synchronous transaction will not cause the system to bypass the hook procedure. When an input event occurs while the client is waiting for a synchronous transaction to end, the hook procedure receives an MSGF_DDEMGR hook code. The main danger of using a synchronous transaction modal loop is that a modal loop created by a dialog box can interfere with its operation. Asynchronous transactions should always be used when the DDEML is being used by a dynamic-link library (DLL).


Transaction Control

An application can suspend transactions to its DDE callback function — either those transactions associated with a specific conversation handle or all transactions regardless of the conversation handle. This capability is useful when an application receives a transaction that requires lengthy processing. In such a case, the application can return the CBR_BLOCK return code to suspend future transactions associated with the transaction's conversation handle, so that the application is free to process other conversations.

When processing has been completed, the application calls the DdeEnableCallback function to resume transactions associated with the suspended conversation. Calling DdeEnableCallback causes the DDEML to resend the transaction that resulted in the application suspending the conversation. Therefore, the application should store the result of the transaction in such a way that it can obtain and return the result without reprocessing the transaction.

An application can suspend all transactions associated with a specific conversation handle by specifying the handle and the EC_DISABLE flag in a call to DdeEnableCallback. By specifying a NULL handle, an application can suspend all transactions for all conversations.

When a conversation has been suspended, the DDEML saves transactions for the conversation in a transaction queue. When the application reenables the conversation, the DDEML removes the saved transactions from the queue and passes each transaction to the appropriate callback function. The capacity of the transaction queue is large, but an application should reenable a suspended conversation as soon as possible to avoid losing transactions.

An application can resume usual transaction processing by specifying the EC_ENABLEALL flag in DdeEnableCallback. For a more controlled resumption of transaction processing, the application can specify the EC_ENABLEONE flag. This flag removes one transaction from the transaction queue and passes it to the appropriate callback function; after that transaction has been processed, any conversations are again disabled.

If the EC_ENABLEONE flag and a conversation handle are specified in the call to DdeEnableCallback, only that conversation is blocked after the transaction has been processed. If a NULL conversation handle is specified, all conversations are blocked after a transaction has been processed in any conversation.


Transaction Classes

The DDEML has four classes of transactions. Each class is identified by a constant that begins with the XCLASS_ prefix. The classes are defined in the DDEML header file. The class value is combined with the transaction-type value and is passed to the DDE callback function of the receiving application.

A transaction's class determines the return value that a callback function is expected to return if it processes the transaction. The following return values and transaction types are associated with each of the four transaction classes.

Class	Return value	Transaction
XCLASS_BOOL	TRUE or FALSE	XTYP_ADVSTART XTYP_CONNECT
XCLASS_DATA	A data handle, the CBR_BLOCK return code, or NULL	XTYP_ADVREQ XTYP_REQUEST XTYP_WILDCONNECT
XCLASS_FLAGS	A transaction flag: DDE_FACK, DDE_FBUSY, or DDE_FNOTPROCESSED	XTYP_ADVDATA XTYP_EXECUTE XTYP_POKE
XCLASS_NOTIFICATION	None	XTYP_ADVSTOP XTYP_CONNECT_ CONFIRM  XTYP_DISCONNECT XTYP_ERROR XTYP_REGISTER XTYP_UNREGISTER XTYP_XACT_ COMPLETE


Transaction Types

Each DDE transaction type has a receiver and an associated activity that causes the DDEML to generate each type.

Transaction type	Receiver	Cause
XTYP_ADVDATA	Client	A server responded to an XTYP_ADVREQ transaction by returning a data handle.
XTYP_ADVREQ	Server	A server called the DdePostAdvise function, indicating that the value of a data item in an advise loop had changed.
XTYP_ADVSTART	Server	A client specified the XTYP_ADVSTART transaction type in a call to the DdeClientTransaction function.
XTYP_ADVSTOP	Server	A client specified the XTYP_ADVSTOP transaction type in a call to DdeClientTransaction.
XTYP_CONNECT	Server	A client called the DdeConnect function and specified a service name and topic name supported by the server.
XTYP_CONNECT_CONFIRM	Server	The server returned TRUE in response to an XTYP_CONNECT or XTYP_WILDCONNECT transaction.
XTYP_DISCONNECT	Client/Server	A partner in a conversation called the DdeDisconnect function, causing both partners to receive this transaction.
XTYP_ERROR	Client/Server	A critical error has occurred. The DDEML may not have sufficient resources to continue.
XTYP_EXECUTE	Server	A client specified the XTYP_EXECUTE transaction type in a call to DdeClientTransaction.
XTYP_MONITOR	DDE monitoring application	A DDE event occurred in the system. For more information about DDE monitoring applications, see Monitoring Applications.
XTYP_POKE	Server	A client specified the XTYP_POKE transaction type in a call to DdeClientTransaction.
XTYP_REGISTER	Client/Server	A server application used the DdeNameService function to register a service name.
XTYP_REQUEST	Server	A client specified the XTYP_REQUEST transaction type in a call to DdeClientTransaction.
XTYP_UNREGISTER	Client/Server	A server application used DdeNameService to unregister a service name.
XTYP_WILDCONNECT	Server	A client called the DdeConnect or DdeConnectList function, specifying NULL for the service name, the topic name, or both.
XTYP_XACT_COMPLETE	Client	An asynchronous transaction, sent when the client specified the TIMEOUT_ASYNC flag in a call to DdeClientTransaction, has concluded.


Error Detection for DDEML Functions

Whenever a DDEML function fails, an application can call the DdeGetLastError function to determine the cause of the failure. DdeGetLastError returns an error value that specifies the cause of the most recent error.


Monitoring Applications

The application programming interface (API) elements of the DDEML can be used to create an application that monitors DDE activity in the system. Like any DDEML application, a DDE monitoring application contains a DDE callback function. The DDEML notifies a monitoring application's DDE callback function whenever a DDE event occurs, passing information about the event to the callback function. The application typically displays the information in a window or writes it to a file.

To receive notifications from the DDEML, an application must have registered as a DDE monitor by specifying the APPCLASS_MONITOR flag in a call to the DdeInitialize function. In this same call, the application can specify one or more monitor flags to indicate the types of events for which the DDEML is to notify the application's callback function. The following monitor flags can be specified by an application:

Flag	Description
MF_CALLBACKS	Notifies the callback function whenever a transaction is sent to any DDE callback function in the system.
MF_CONV	Notifies the callback function whenever a conversation is established or terminated.
MF_ERRORS	Notifies the callback function whenever a DDEML error occurs.
MF_HSZ_INFO	Notifies the callback function whenever a DDEML application creates, frees, or increments the usage count of a string handle or whenever a string handle is freed as a result of a call to the DdeUninitialize function.
MF_LINKS	Notifies the callback function whenever an advise loop is started or ended.
MF_POSTMSGS	Notifies the callback function whenever the system or an application posts a DDE message.
MF_SENDMSGS	Notifies the callback function whenever the system or an application sends a DDE message.
The following example shows how to register a DDE monitoring application so that its DDE callback function receives notifications of all DDE events.

DWORD idInst;

PFNCALLBACK lpDdeProc;

hInst = hInstance;

if (DdeInitialize(

        (LPDWORD) &idInst,  /* instance identifier              */

        DDECallback,        /* points to callback function      */

        APPCLASS_MONITOR |  /* this is a monitoring application */

        MF_CALLBACKS     |  /* monitor callback functions       */

        MF_CONV          |  /* monitor conversation data        */

        MF_ERRORS        |  /* monitor DDEML errors             */

        MF_HSZ_INFO      |  /* monitor data handle activity     */

        MF_LINKS         |  /* monitor advise loops             */

        MF_POSTMSGS      |  /* monitor posted DDE messages      */

        MF_SENDMSGS,        /* monitor sent DDE messages        */

        0))                 /* reserved                         */

    return FALSE;

The DDEML informs a monitoring application of a DDE event by sending an XTYP_MONITOR transaction to the application's DDE callback function. During this transaction, the DDEML passes a monitor flag that specifies the type of DDE event that has occurred and a handle of a DDE object that contains detailed information about the event. The DDEML provides a set of structures that the application can use to extract the information from the DDE object. There is a corresponding structure for each type of DDE event.

Structure	Description
MONCBSTRUCT	Contains information about a transaction.
MONCONVSTRUCT	Contains information about a conversation.
MONERRSTRUCT	Contains information about the latest DDE error.
MONLINKSTRUCT	Contains information about an advise loop.
MONHSZSTRUCT	Contains information about a string handle.
MONMSGSTRUCT	Contains information about a DDE message that was sent or posted.
The following example shows the DDE callback function of a DDE monitoring application that formats information about each string handle event and then displays the information in a window. The function uses the MONHSZSTRUCT structure to extract the information from the DDE object.

HDDEDATA CALLBACK DDECallback(uType, uFmt, hconv, hsz1, hsz2,

    hdata, dwData1, dwData2)

UINT uType;

UINT uFmt;

HCONV hconv;

HSZ hsz1;

HSZ hsz2;

HDDEDATA hdata;

DWORD dwData1;

DWORD dwData2;

{

    LPVOID lpData;

    CHAR *szAction;

    CHAR szBuf[256];

    DWORD cb;

    switch (uType) {

        case XTYP_MONITOR:

            /* Obtain a pointer to the global memory object. */

            if (lpData = DdeAccessData(hdata, &cb)) {

                /* Examine the monitor flag. */

                switch (dwData2) {

                    case MF_HSZ_INFO:

#define PHSZS ((MONHSZSTRUCT FAR *)lpData)

                        /*

                         * The global memory object contains

                         * string handle data. Use the MONHSZSTRUCT

                         * structure to access the data.

                         */

                        switch (PHSZS->fsAction) {

                            /*

                             * Examine the action flags to

                             * determine the action performed on

                             * the handle.

                             */

                            case MH_CREATE:

                                szAction = "Created";

                                break;

                            case MH_KEEP:

                                szAction = "Incremented";

                                break;

                            case MH_DELETE:

                                szAction = "Deleted";

                                break;

                            case MH_CLEANUP:

                                szAction = "Cleaned up";

                                break;

                            default:

                                DdeUnaccessData(hdata);

                                return (HDDEDATA) 0;

                        }

                        /* Write formatted output to a buffer. */

                        wsprintf(szBuf,

                            "Handle %s, Task: %x, Hsz: %lx(%s)",

                            (LPSTR) szAction, PHSZS->hTask,

                            PHSZS->hsz, (LPSTR) PHSZS->str);

                        .

                        . /* Display text or write to a file. */

                        .

                        break;

#undef PHSZS

                    .

                    . /* Process other MF_* flags. */

                    .

                    default:

                        break;

                }

            }

            /* Free the global memory object. */

            DdeUnaccessData(hdata);

            break;

        default:

            break;

    }

    return (HDDEDATA) 0;

}


Dynamic Data Exchange Management Functions

Following are the functions used to manage dynamic data exchange.

DdeAbandonTransaction
DdeAccessData
DdeAddData
DdeCallback
DdeClientTransaction
DdeCmpStringHandles
DdeConnect
DdeConnectList
DdeCreateDataHandle
DdeCreateStringHandle
DdeDisconnect
DdeDisconnectList
DdeEnableCallback
DdeFreeDataHandle
DdeFreeStringHandle
DdeGetData
DdeGetLastError
DdeInitialize
DdeKeepStringHandle
DdeNameService
DdePostAdvise
DdeQueryConvInfo
DdeQueryNextServer
DdeQueryString
DdeReconnect
DdeSetUserHandle
DdeUnaccessData
DdeUninitialize


Dynamic-Link Libraries

In Microsoft® Windows®, dynamic linking provides a way for a process to call a function that is not part of its executable code. The executable code for the function is located in a dynamic-link library (DLL), containing one or more functions that are compiled, linked, and stored separately from the processes using them. The Microsoft® Win32® application programming interface (API) is implemented as a set of dynamic-link libraries, so any process using the Win32 API uses dynamic linking.


About Dynamic-Link Libraries

Dynamic linking allows an executable module (either a .DLL or .EXE file) to include only the information needed at run time to locate the executable code for a DLL function. This type of linking differs from the more familiar static linking, which requires a copy of a library function's executable code in the executable module of each application using it.

There are two methods for calling a function in a DLL:

•	Load-time dynamic linking occurs when an application's code makes an explicit call to a DLL function. This type of linking requires that the executable module of the application be built by linking with the DLL's import library, which supplies the information needed to locate the DLL function when the application starts. For more information, see Load-Time Dynamic Linking.

•	Run-time dynamic linking occurs when a program uses the LoadLibrary and GetProcAddress functions to get the starting address of a DLL function. This type of linking eliminates the need to link with an import library. For more information, see Using Run-Time Dynamic Linking.

A DLL attaches to a process when the process starts or when one of its threads calls the LoadLibrary function. When a DLL attaches to a process, the operating system maps the DLL module into the address space of the process, making the DLL's executable code available to the process. When a DLL detaches from a process at process termination or as a result of a call to the FreeLibrary function, the DLL module is unmapped from the address space of the process.

Like any other function, a DLL function is executed in the context of the thread (and the thread's process) that calls it. Therefore, the following conditions apply:

•	The threads of the process that called the DLL can use handles opened by a DLL function. Similarly, handles opened by any thread of the calling process can be used in the DLL function.

•	The DLL uses the user stack of the calling thread and the address space of the calling process.

•	Memory allocated by the DLL is in the address space of the calling process.

•	The threads of the process that called the DLL can read from or write to the globally declared variables in the DLL.


Advantages of Dynamic Linking

Dynamic linking has the following advantages:

•	Many processes can use a single DLL simultaneously, sharing a single copy of the DLL in memory. Doing this saves memory space and reduces swapping.

•	When the functions in a DLL change, the applications that use them do not need to be recompiled or relinked as long as the functions' arguments and return values do not change. In contrast, statically linked object code requires that the application be relinked when the functions change.

•	A DLL can provide after-market support. For example, a display driver DLL can be modified to support a display that was not available when the application was shipped.

•	Programs written in different programming languages can call the same DLL function as long as the programs follow the function's calling convention. The programs and the DLL function must be compatible in the following ways: the order the function expects its arguments to be pushed onto the stack, whether the function or the application is responsible for cleaning up the stack, and whether any arguments are passed in registers.

A potential disadvantage to using DLLs is that the application is not self-contained; it depends on the existence of a separate DLL module. A process using load-time dynamic linking is terminated by the operating system if the DLL is not found at process startup. A process using run-time dynamic linking is not terminated in this situation, but capabilities provided by the DLL are not available to the program.


Dynamic-Link Library Creation

To create a DLL, first create one or more source code (.C) files and a module-definition (.DEF) file. The .C file contains the exported functions for the DLL. The .DEF file lists these functions and defines other attributes of the DLL.

The compiler uses the .C file to create an object code (.OBJ) file. The library manager creates an export (.EXP) file and an import library (.LIB) file from the .DEF file.

Finally, the linker uses the .OBJ, .EXP, and .LIB files to build the executable files for the DLL. The .OBJ and .EXP files provide information the linker needs to build the .DLL file. The .LIB file contains information the linker needs to resolve external references to DLL functions, so that a program can locate the specified DLL at run time. The .LIB file enables the linker to build an executable module (.EXE or .DLL) that calls a function in the DLL. For more information about .DEF files, see Module-Definition File.

Note that the information in this section is based on using Win32 software development tools. For more detailed information about creating DLLs, see the documentation included with your development tools.


Dynamic-Link Library Entry-Point Function

A DllEntryPoint function is an optional DLL function that the operating system calls to perform user-defined operations. DllEntryPoint is not a typical function; it is a reference to a function specified in the linker command line. A DLL is not required to have an entry-point function, but it can be useful for initializing and cleaning up processes and threads. The name of a DLL's entry-point function is specified by the -entry switch of the linker. For example, the following command line specifies LibMain as the entry-point function of MYDLL.DLL.

link -entry:LibMain -out:mydll.dll mydll.exp mydll.obj $(mylibs)

If an entry-point function is specified, the operating system causes it to be called whenever any of the following events occurs:

•	The DLL attaches to a process. For processes using load-time dynamic linking, attachment occurs during initialization. For processes using run-time linking, the DLL attaches and the entry-point function is called before LoadLibrary returns.

•	The DLL detaches from a process. Detachment occurs when the process terminates or when the DLL is unloaded by a call to the FreeLibrary function. If the process terminates as a result of the TerminateProcess or TerminateThread function, the system does not call the entry-point function.

•	The DLL attaches to a thread. Attachment occurs whenever a new thread is created in a process to which a DLL is attached.

•	The DLL detaches from a thread. Detachment occurs whenever a thread of an attached process terminates, except as a result of the TerminateThread or TerminateProcess function. When a DLL detaches from a process, the entry-point function is called only once for the entire process rather than once for each existing thread of the process.

The system causes the entry-point function to be called, but it is called in the context of a process or thread attaching to or detaching from the DLL. This allows a DLL to use its entry-point function for allocating memory in the address space of the process or to open handles accessible to the process. When it is called to attach a new thread, the entry-point function can allocate memory for thread local storage (TLS) that is private to the new thread. For more information about thread local storage, see Processes and Threads.

When a DLL's entry-point function is called for process attachment, it returns TRUE to indicate success. For processes using load-time linking, a return value of FALSE causes the process initialization to fail and the process terminates. For processes using run-time linking, a return value of FALSE causes the LoadLibrary function to return NULL, indicating failure. The return value of the entry-point function is disregarded when it is called for any other reasons, such as process detaching, thread attaching, or thread detaching.


Module-Definition File

A module-definition (.DEF) file is a text file containing one or more module statements that describe various attributes of a DLL. The descriptions and examples in this section are based on the keywords and syntax used by the Win32 software development tools. For complete information about module-definition files, see the documentation included with your development tools.

A DLL requires a .DEF file to create an import library (.LIB) file and an export (.EXP) file. The linker uses the import library to build any executable module that uses the DLL and uses the export file to build the .DLL file.

A DLL's module-definition file must include a LIBRARY statement and an EXPORTS statement. The LIBRARY statement identifies the module-definition file as belonging to a DLL, and it must be the first statement in the file. The name specified in the LIBRARY statement identifies the library in the DLL's import library. The EXPORTS statement lists the names and, optionally, the ordinal values of the functions exported by the DLL. When ordinal values are specified, they must be in the range 1 through N, where N is the number of functions exported by the DLL.

The following .DEF file for a DLL exports three functions and associates an ordinal value with each function.

LIBRARY mydll

EXPORTS

    Func_A @1

    Func_B @2

    Func_C @3

The .DEF file can contain additional statements, specifying other attributes of a DLL. For example, the SECTIONS statements can change the default scope of global and static variables. The following SECTIONS statement makes the DLL's initialized data shared, but its uninitialized variables are not shared.

SECTIONS

    .data READ WRITE SHARED    ; share initialized variables


Load-Time Dynamic Linking

Load-time dynamic linking occurs when an application's code explicitly calls a DLL function. When the source code is compiled or assembled, the DLL function call generates an external function reference in the object code. To resolve this external reference, the application must be linked with the import library for the DLL.

Finding an external function in an import library informs the linker that the code for that function is in a DLL. To resolve external references to DLLs, the linker simply adds information to the executable file that tells the system where to find the DLL code when the process starts up.

When the system starts a program that contains dynamically linked references, it uses the information in the program's executable file to locate the required DLLs. The system first searches the set of pre-installed DLLs, such as the performance library (KERNEL32.DLL) and the security library (USER32.DLL). The system then searches for the DLLs in the following sequence:

1.	The directory where the executable module for the current process is located.

2.	The current directory.

3.	The windows system directory. The GetSystemDirectory function retrieves the path of this directory.

4.	The windows directory. The GetWindowsDirectory function retrieves the path of this directory.

5.	The directories listed in the PATH environment variable.

Note that the LIBPATH environment variable is not used.

If it cannot locate a specified DLL, the system terminates the process and displays a dialog box that reports the error. Otherwise, the system maps the DLL modules into the process's address space.

If any of the DLLs has a DllEntryPoint function, the operating system calls the function. DllEntryPoint specifies a code that indicates the DLL is attaching to the process. If the entry-point function does not return TRUE, the system terminates the process and reports the error. For more information about the entry-point function, see Dynamic-Link Library Entry-Point Function.

Finally, the system modifies the executable code of the process to provide starting addresses for the DLL functions.

Like the rest of a program's code, DLL code is mapped into the address space of the process when the process starts up and is loaded into memory only when needed. As a result, the PRELOAD and LOADONCALL code attributes used by .DEF files to control loading in previous versions of Windows no longer have meaning.


Run-Time Dynamic Linking

Run-time dynamic linking occurs when the process calls the LoadLibrary function to specify the name of a DLL and the GetProcAddress function to get the starting address of any function in the DLL. Run-time dynamic linking eliminates the need to link the process with an import library. Since the process does not explicitly call the DLL's functions, it does not generate external references to them.

If the call to LoadLibrary specifies a DLL module already mapped into the address space of the calling process, the function simply returns a handle of the DLL and increments the module's reference count. Otherwise, LoadLibrary attempts to locate the DLL using the same search sequence used for load-time dynamic linking (see Load-Time Dynamic Linking). If the search succeeds, the system maps the DLL module into the address space of the process. If the DLL has a DllEntryPoint function, the operating system calls the function in the context of the thread that called LoadLibrary. The entry-point function is not called if the DLL is already attached to the process due to a previous call to LoadLibrary with no corresponding call to the FreeLibrary function.

If the system cannot find the DLL or if the entry-point function returns FALSE, LoadLibrary returns NULL. If LoadLibrary succeeds, it returns a handle of the DLL module. The process can use this handle to identify the DLL in a call to the GetProcAddress or FreeLibrary function.

The GetModuleHandle function also returns a handle used in GetProcAddress or FreeLibrary. GetModuleHandle succeeds only if the DLL module is already mapped into the address space of the process by load-time linking or by a previous call to LoadLibrary. Unlike LoadLibrary, GetModuleHandle does not increment the module's reference count. The GetModuleFileName function retrieves the full path of the module associated with a handle returned by GetModuleHandle or LoadLibrary.

The process can use GetProcAddress to get the starting handle returned by LoadLibrary or the address of a function in the DLL using a DLL module handle returned by either LoadLibrary or GetModuleHandle. The function is specified by using its name or ordinal value as listed in the EXPORTS statement of the DLL's .DEF file.

When the DLL module is no longer needed, the process can call the FreeLibrary function. This function decrements the module's reference count and unmaps it from the address space of the process if the reference count is zero.

Run-time dynamic linking enables the process to continue executing even if a DLL is not available. The process can then use an alternate method to accomplish its objective. For example, if a process is unable to locate one DLL, it can try to use another, or it can notify the user of an error. If the user can provide the full path of the missing DLL, the process can use this information to load the library even though it is not in the normal search path. This situation contrasts with load-time linking in which the operating system simply terminates the process if it cannot find the DLL.

It is not necessary for the developer to know the names of either the DLLs or the functions within a DLL. The process can get this information from a configuration file or from the user.

Run-time dynamic linking can cause problems if the DLL is using the DllEntryPoint function to perform initialization for each thread of a process, because threads existing when LoadLibrary is called will not be initialized. For an example showing how to deal with this problem, see Using Thread Local Storage in a Dynamic-Link Library.


Dynamic-Link Library Data

Windows supports the use of the following DLL data:

•	Global and static variables in a DLL module private to each process that uses the DLL.

•	Global and static variables shared by all processes simultaneously using a DLL.

•	Dynamically allocated memory private to each process that uses a DLL.

•	Dynamically allocated memory shared by multiple processes.

•	Static storage private to each thread of a multithreaded process.

The default scope of a DLL's variables is the same as that of any statically linked code. Global variables in a DLL source code file are global to each process using the DLL. Static variables create permanent storage for each process, limiting their scope to the block in which they are declared. As a result, each process has its own instance of a DLL's global and static variables by default.

Win32 development tools enable a DLL's .DEF file to override the default scope of global and static variables. For more information, see Module-Definition File and the documentation included with your development tools.

When a DLL allocates memory using any of the allocation functions (GlobalAlloc, LocalAlloc, HeapAlloc, VirtualAlloc, malloc, and other C run-time allocation functions), the memory is allocated in the address space of the calling process and is accessible only to the threads of that process. A DLL's .DEF file cannot be used to change the scope of dynamically allocated memory.

A DLL can use file mapping to allocate memory that can be shared among processes. For a general discussion of using file mapping to create named shared memory, see File Mapping. For an example that uses the DllEntryPoint function to set up shared memory using file mapping, see Using Shared Memory in a Dynamic-Link Library.

The thread local storage functions enable a DLL to allocate an index for storing and retrieving a different value for each thread of a multithreaded process. For example, a spreadsheet application can create a new instance of the same thread each time the user opens a new spreadsheet. A DLL providing the functions for various spreadsheet operations can use thread local storage to save information about the current state of each spreadsheet (row, column, and so on). For a general discussion of thread local storage, see Processes and Threads. For an example that uses the DllEntryPoint function to set up thread local storage, see Using Thread Local Storage in a Dynamic-Link Library.


Using Dynamic-Link Libraries

•	Creating a simple dynamic-link library

•	Using load-time dynamic linking

•	Using run-time dynamic linking

•	Using shared memory in a dynamic-link library

•	Using thread local storage in a dynamic-link library


Creating a Simple Dynamic-Link Library

DLLs make common functions available to a number of processes or threads at once. The following file, MYPUTS.C, contains a simple string printing function. This DLL does not use a DllEntryPoint function because it has no initialization or cleanup functions to perform.

#include <windows.h>

/*

 * A function that writes a null-terminated string to the

 * console output.

 */

VOID myPuts(LPTSTR lpszMsg) {

    DWORD cchWritten;

    HANDLE hStdout;

    /* Get a handle to the console output. */

    hStdout = GetStdHandle(STD_OUTPUT_HANDLE);

    /* Write a null-terminated string to the console output. */

    while (*lpszMsg)

        WriteFile(hStdout, lpszMsg++, 1, &cchWritten, NULL);

}

The module-definition file for this DLL is MYPUTS.DEF, and it contains the following information.

LIBRARY myputs

EXPORTS

     myPuts

The name specified in the LIBRARY statement identifies the DLL in the DLL's import library. Load-time dynamic linking enables the system to use this name for locating the DLL. If run-time dynamic linking is being used, the LoadLibrary function does not use this name to locate the DLL. The EXPORTS statement indicates that other .EXE or .DLL modules can call the myPuts function.

The source code in MYPUTS.C is compiled to produce an object module (MYPUTS.OBJ). The library manager uses the module-definition file (MYPUTS.DEF) to create the import library (MYPUTS.LIB) and the export file (MYPUTS.EXP). The linker uses MYPUTS.EXP and MYPUTS.OBJ to produce the executable DLL module (MYPUTS.DLL). MYPUTS.LIB is not used in creating MYPUTS.DLL, but the linker uses it to create any executable module (.EXE or .DLL) that calls the myPuts function.

Following are some typical command lines used to compile and link a DLL. For more information about compiling and linking dynamic-link libraries and programs that use them, see the documentation included with your development tools.

cvars=-DWIN32 -D_MT -DSTRICT

# Compile myputs.c to create myputs.obj.

myputs.obj: myputs.c

    $(cc)  $(cflags) $(cvars) myputs.c

# Create the DLL's import library.

# Also create the myputs.exp export file.

myputs.lib: myputs.def

    $(lib) -machine:i386 \

    -def:myputs.def     \

    -out:myputs.lib

# Link myputs.obj and myputs.exp to create myputs.dll.

# myputs.lib is not used here but is included as a

# dependency to force creation of myputs.exp.

myputs.dll: myputs.obj myputs.lib

    $(link)          \

    -out:myputs.dll  \

    myputs.exp myputs.obj $(conlibs)

# If the DLL has a DllEntryPoint function, substitute a line

# like this to specify the name of the entry-point function.

#    $(link) -entry:LibMain    \


Using Load-Time Dynamic Linking

Once you have created a DLL, you can use it in an application. The following file, LOADTIME.C, is the source code for a simple console process that uses the myPuts function from MYPUTS.DLL.

/*

 *   File:  loadtime.c

 *   A simple program that uses myPuts() from myputs.dll

 */

#include <windows.h>

VOID myPuts(LPTSTR);   /* a function from a DLL */

VOID main(VOID) {

    myPuts("message printed using the DLL function\n");

}

Because LOADTIME.C calls the DLL function explicitly, the executable module for the application must be linked with the import library (MYPUTS.LIB). Following are some typical command lines used for compiling and linking a program that uses a DLL.

# Compile loadtime.c to create loadtime.obj.

loadtime.obj: loadtime.c

    $(cc)  $(cflags) $(cvars) loadtime.c

# Link loadtime.obj and myputs.lib to create loadtime.exe.

loadtime.exe: loadtime.obj myputs.lib

    $(link) $(conflags) \

    -out:loadtime.exe loadtime.obj myputs.lib $(conlibs)


Using Run-Time Dynamic Linking

You can use the same DLL in both load-time and run-time dynamic linking. If the system can find the specified DLL module, the following source code produces the same output as the load-time example in the previous section. The program uses the LoadLibrary function to get a handle of MYPUTS.DLL. If LoadLibrary succeeds, the program uses the returned handle in the GetProcAddress function to get the starting address of the DLL's myPuts function. After calling the DLL function, the program calls the FreeLibrary function to detach the DLL from the process.

The following example illustrates an important difference between run-time and load-time dynamic linking. If the MYPUTS.DLL file is not available, the application using load-time dynamic linking simply terminates. The run-time dynamic linking example, however, can respond to the error.

/*

 *   File:  runtime.c

 *   A simple program that uses LoadLibrary and

 *   GetProcAddress to access myPuts() from the myputs DLL.

 */

#include <stdio.h>

#include <windows.h>

typedef VOID (*MYPROC)(LPTSTR);

VOID main(VOID) {

    HINSTANCE hinstLib;

    MYPROC ProcAdd;

    BOOL fFreeResult, fRunTimeLinkSuccess = FALSE;

    /* Get a handle to the DLL module. */

    hinstLib = LoadLibrary("myputs");

    /* If the handle is valid, try to get the function address. */

    if (hinstLib != NULL) {

        ProcAdd = (MYPROC) GetProcAddress(hinstLib, "myPuts");

        /* If the function address is valid, call the function. */

        if (fRunTimeLinkSuccess = (ProcAdd != NULL))

            (ProcAdd) ("message via DLL function\n");

        /* Free the DLL module. */

        fFreeResult = FreeLibrary(hinstLib);

  }

    /* If unable to call the DLL function, use an alternative. */

    if (! fRunTimeLinkSuccess)

        printf("message via alternative method\n");

}

Because the program uses run-time dynamic linking, it is not necessary to link with the DLL's import library when creating the program's executable module. The following lines are typical of the command lines used to compile and link a program using run-time linking.

# Compile runtime.c to create runtime.obj.

runtime.obj: runtime.c

    $(cc)  $(cflags) $(cvars) runtime.c

# Link runtime.obj to create loadtime.exe.

runtime.exe: runtime.obj

    $(link) $(conflags) \

    -out:runtime.exe runtime.obj $(conlibs)


Using Shared Memory in a Dynamic-Link Library

This section shows the use of a DLL's entry-point function to set up memory that can be shared by multiple processes. In this DLL, the name of the entry-point function is LibMain. The module-definition file for this DLL is MYPUTS.DEF, and it contains the following information.

LIBRARY myputs

EXPORTS

     myPuts

The example uses file mapping to map a block of named shared memory into the address space of each process to which the DLL is attached. The entry-point function calls the CreateFileMapping function to create a file-mapping object whenever the DLL attaches to a new process. This function can be used to either create or open a named file-mapping object. The first process to which the DLL attaches creates the file-mapping object. Subsequent processes open a handle of the existing object. The GetLastError function triggers initialization of the shared memory because it returns NO_ERROR to the first process and ERROR_ALREADY_EXISTS to subsequent processes.

The MapViewOfFile function maps the file-mapping object into the address space of each process, returning a pointer to the memory. Note that the shared memory can be mapped to a different address in each process. For this reason, each process has its own instance of lpvMem, which is declared as a global variable so that it is available to the DLL's functions. The example assumes that the DLL's global data is not shared, so each attaching process has its own instance of lpvMem. By default, DLL data is not shared, but the default can be modified by the DLL's module-definition (.DEF) file (see Module-Definition File).

Any shared DLL memory persists only as long as the DLL is attached to a process. In this example, the shared memory is released when the last handle of the file-mapping object is closed. To create persistent shared memory, a DLL can create a detached process (see Processes and Threads) when the DLL attaches to the first process. If this detached process uses the DLL and does not terminate, it has a handle of the file-mapping object that prevents the shared memory from being released.

/*

 *   File:  dllshmem.c

 *

 *   A DLL entry-point function sets up shared memory using

 *   named file mapping.

 */

#include <windows.h>

#include <memory.h>

#define SHMEMSIZE 4096

static LPVOID lpvMem = NULL; /* address of shared memory */

/*

 * LibMain() is the DllEntryPoint function for this DLL.

 */

BOOL LibMain(HINSTANCE hinstDLL,   /* DLL module handle  */

        DWORD fdwReason,      /* reason called           */

        LPVOID lpvReserved) { /* reserved                */

    HANDLE hMapObject = NULL;   /* handle to file mapping */

    BOOL fInit, fIgnore;

    switch (fdwReason) {

        /*

         * The DLL is attaching to a process due to process

         * initialization or a call to LoadLibrary.

         */

          case DLL_PROCESS_ATTACH:

            /* Create a named file mapping object */

            hMapObject = CreateFileMapping(

                (HANDLE) 0xFFFFFFFF, /* use paging file    */

                NULL,                /* no security attr.  */

                PAGE_READWRITE,      /* read/write access  */

                0,                   /* size: high 32-bits */

                SHMEMSIZE,           /* size: low 32-bits  */

                "dllmemfilemap");    /* name of map object */

            if (hMapObject == NULL)

                return FALSE;

            /* The first process to attach initializes memory. */

            fInit = (GetLastError() != ERROR_ALREADY_EXISTS);

            /* Get a pointer to the file-mapped shared memory. */

            lpvMem = MapViewOfFile(

                hMapObject,     /* object to map view of    */

                FILE_MAP_WRITE, /* read/write access        */

                0,              /* high offset:   map from  */

                0,              /* low offset:    beginning */

                0);             /* default: map entire file */

            if (lpvMem == NULL)

                return FALSE;

            /* Initialize memory if this is the first process. */

            if (fInit)

                memset(lpvMem, '\0', SHMEMSIZE);

            break;

        /* The attached process creates a new thread. */

        case DLL_THREAD_ATTACH:

            break;

        /* The thread of the attached process terminates. */

        case DLL_THREAD_DETACH:

            break;

        /*

         * The DLL is detaching from a process due to

         * process termination or a call to FreeLibrary.

         */

        case DLL_PROCESS_DETACH:

            /* Unmap shared memory from the process's address space. */

            fIgnore = UnmapViewOfFile(lpvMem);

            /* Close the process's handle to the file-mapping object. */

            fIgnore = CloseHandle(hMapObject);

            break;

        default:

          break;

  }

    return TRUE;

    UNREFERENCED_PARAMETER(hinstDLL);

    UNREFERENCED_PARAMETER(lpvReserved);

}

/*

 * SetSharedMem sets the contents of shared memory.

 */

VOID SetSharedMem(LPTSTR lpszBuf) {

    LPTSTR lpszTmp;

    /* Get the address of the shared memory block. */

    lpszTmp = (LPTSTR) lpvMem;

    /* Copy the null-terminated string into shared memory. */

    while (*lpszBuf)

        *lpszTmp++ = *lpszBuf++;

    *lpszTmp = '\0';

}

/*

 * GetSharedMem gets the contents of shared memory.

 */

VOID GetSharedMem(LPTSTR lpszBuf, DWORD cchSize) {

    LPTSTR lpszTmp;

    /* Get the address of the shared memory block. */

    lpszTmp = (LPTSTR) lpvMem;

    /* Copy from shared memory into the caller's buffer. */

    while (*lpszTmp && --cchSize)

        *lpszBuf++ = *lpszTmp++;

    *lpszBuf = '\0';

}


Using Thread Local Storage in a Dynamic-Link Library

This section shows the use of a DLL's entry-point function to set up a thread local storage (TLS) index to provide private storage for each thread of a multithreaded process.

The entry-point function uses the TlsAlloc function to allocate a TLS index whenever the DLL attaches to a process. Each thread of the process can then use this index to store a pointer to its own block of memory.

When the entry-point function is called with the DLL_PROCESS_ATTACH value, it peforms the following actions:

1.	Uses the TlsAlloc function to allocate a TLS index.

2.	Allocates a block of memory to be used exclusively by the initial thread of the process.

3.	Uses the TLS index in a call to the TlsSetValue function to store a pointer to the allocated memory.

Each time the process creates a new thread, the entry-point function is called with the DLL_THREAD_ATTACH value. The entry-point function then allocates a block of memory for the new thread and stores a pointer to it by using the TLS index. Each thread can use the TLS index in a call to TlsGetValue to retrieve the pointer to its own block of memory.

When a thread terminates, the entry-point function is called with the DLL_THREAD_DETACH value and the memory for that thread is freed. When a process terminates, the entry-point function is called with the DLL_PROCESS_DETACH value and the TLS index is freed.

The TLS index is stored in a global variable, making it available to all of the DLL's functions. The following example assumes that the DLL's global data is not shared, because the TLS index is not necessarily the same for each process to which the DLL is attached.

static DWORD dwTlsIndex; /* address of shared memory */

/*

 * LibMain() is the DllEntryPoint function for this DLL.

 */

BOOL LibMain(HINSTANCE hinstDLL,   /* DLL module handle  */

        DWORD fdwReason,     /* reason called      */

        LPVOID lpvReserved) {/* reserved           */

    LPVOID lpvData;

    BOOL fIgnore;

    switch (fdwReason) {

        /*

         * The DLL is attaching to a process due to process

         * initialization or a call to LoadLibrary.

         */

        case DLL_PROCESS_ATTACH:

              /* Allocate a TLS index. */

              if ((dwTlsIndex = TlsAlloc()) == 0xFFFFFFFF)

                  return FALSE;

            /* No break: Initialize the index for first thread. */

        /* The attached process creates a new thread. */

        case DLL_THREAD_ATTACH:

            /* Initialize the TLS index for this thread. */

            lpvData = (LPVOID) LocalAlloc(LPTR, 256);

            if (lpvData != NULL)

                fIgnore = TlsSetValue(dwTlsIndex, lpvData);

            break;

        /* The thread of the attached process terminates. */

        case DLL_THREAD_DETACH:

            /* Release the allocated memory for this thread. */

            lpvData = TlsGetValue(dwTlsIndex);

            if (lpvData != NULL)

                LocalFree((HLOCAL) lpvData);

            break;

        /*

         * The DLL is detaching from a process due to

         * process termination or call to FreeLibrary.

         */

        case DLL_PROCESS_DETACH:

            /* Release the allocated memory for this thread. */

            lpvData = TlsGetValue(dwTlsIndex);

            if (lpvData != NULL)

                LocalFree((HLOCAL) lpvData);

            /* Release the TLS index. */

            TlsFree(dwTlsIndex);

            break;

        default:

            break;

    }

    return TRUE;

    UNREFERENCED_PARAMETER(hinstDLL);

    UNREFERENCED_PARAMETER(lpvReserved);

}

When a process uses load-time linking with this DLL, the entry-point function is sufficient to manage the thread local storage. Problems can occur with a process that uses run-time linking because the TLS memory is not allocated for threads that exist before the LoadLibrary function is called to attach the process. The following example solves this problem by checking the value returned by the TlsGetValue function and allocating memory if the value indicates that the TLS slot for this thread is not set.

LPVOID lpvData;

/* Retrieve a data pointer for the current thread. */

lpvData = TlsGetValue(dwTlsIndex);

/* If NULL, allocate memory for this thread. */

if (lpvData == NULL) {

    lpvData = (LPVOID) LocalAlloc(LPTR, 256);

    if (lpvData != NULL)

        TlsSetValue(dwTlsIndex, lpvData);

}


Dynamic-Link Library Functions

Following are the functions used in dynamic linking.

DisableThreadLibraryCalls
DllEntryPoint
FreeLibrary
FreeLibraryAndExitThread
GetModuleFileName
GetModuleHandle
GetProcAddress
LoadLibrary
LoadLibraryEx
LoadModule

Obsolete or Deleted Functions

FreeModule
FreeProcInstance
GetCodeHandle
GetInstanceData
GetModuleUsage
MakeProcInstance


Errors

Well-written applications include code that allows them to recover gracefully from unexpected errors. When an error occurs, the application may need to request user intervention, or it may be able to recover without help. In extreme cases, the application may log the user off or shut down the system.


About Errors

Microsoft® Windows® includes a special error-handling mechanism for exceptions, such as divide-by-zero errors. For more information about exception handling, see Structured Exception Handling.


Notifying the User

To notify the user that some kind of error has occurred, many applications simply produce a sound by using the Beep or MessageBeep function or flash the window by using the FlashWindow function. An application can also use these functions to call attention to an error and then display a message box or an error message containing details about the error.


Logging Off or Shutting Down

An application can use the ExitWindows function to log the current user off. The ExitWindowsEx function can also perform the following tasks:

•	Shut down the system.

•	Shut down the system and restart it.

•	Log off and force all running applications to terminate.

Logging off stops all processes associated with the security context of the process that called the exit function, logs the user off the system, and displays the Logon dialog box.

Shutting down brings the system to a condition in which it is safe to turn off the computer. All file-system buffers are flushed to the disk, and a message box is displayed informing the user that the computer can be turned off. If the reboot option is specified, the computer restarts.

The calling process must have the SE_SHUTDOWN_NAME privilege to shut down or to shut down and restart. For an example that enables this privilege and shuts down the system, see Shutting Down.


Last-Error Code

When an error occurs, most functions in the Microsoft® Win32® application programming interface (API) return an error code, usually FALSE, NULL, 0xFFFFFFFF, or −1. Most functions in the Win32 API also set an internal error code called the last-error code. When a function succeeds, the last-error code is not reset. The error code is maintained separately for each running thread; an error in one thread does not overwrite the last-error code in another thread. An application can retrieve the last-error code by using the GetLastError function; the error code may tell more about what actually occurred to make the function fail.

The SetLastError function sets the error code for the current thread. The SetLastErrorEx function also allows the caller to set an error type indicating the severity of the error. These functions are intended primarily for dynamic-link libraries (DLLs), so they can emulate the behavior of the Win32 API.

The Win32 API defines a set of error codes that can be set as last-error codes or be returned by these functions..

Error codes are 32-bit values (bit 31 is the most significant bit). Bit 29 is reserved for application-defined error codes; no Win32 API error code has this bit set. Developers who define an error code for an application should set this bit to indicate that the error code has been defined by an application and to ensure that the error code does not conflict with any system-defined error codes.


Error Message Boxes

Some errors, such as a drive-not-ready error (when the door of the floppy disk drive is open), cause Windows to display a message box informing the user that an error has occurred. Applications that handle these errors without user intervention can use the SetErrorMode function to suppress error message boxes.


Using Errors

•	Notifying the user of errors - example

•	Logging off

•	Shutting down

•	Retrieving the last-error code


Notifying the User of Errors - Example

The following example flashes a window and plays the system exclamation sound.

FlashWindow(hwnd, TRUE); /* invert the title bar   */

Sleep(500);              /* wait a bit             */

FlashWindow(hwnd, TRUE); /* invert again           */

/* Play the system exclamation sound. */

MessageBeep(MB_ICONEXCLAMATION);


Logging Off

The ExitWindows function logs the current user off. All applications must agree to terminate before the user logs off. If any application returns FALSE when it processes the WM_QUERYENDSESSION message, the user is not logged off. If your application handles the WM_QUERYENDSESSION message, you can allow the user to cancel the log-off operation, even if another application or Windows originated the end-session request.

The following example logs off the current user, unless the user selects the No button in the message box displayed when the application receives the WM_QUERYENDSESSION message.

            ExitWindows(0, 0); /* log the current user off    */

case WM_QUERYENDSESSION:  /* in application's MainWndProc */

{

    int i  = MessageBox(NULL, "Shutdown?",

       "Received WM_QUERYENDSESSION", MB_YESNO);

    /*

     * Return TRUE to allow shutdown, FALSE to stop.

     */

    return i == IDYES;

    break;

}


Shutting Down

The ExitWindowsEx function can be used to shut down the system. Shutting down flushes file buffers to disk and brings the system to a condition in which it is safe to turn off the computer. The calling process must have the SE_SHUTDOWN_NAME privilege to shut down the system.

The following example enables the SE_SHUTDOWN_NAME privilege and then shuts down the system.

HANDLE hToken;

TOKEN_PRIVILEGES tkp;

/* Get a token for this process. */

if (!OpenProcessToken(GetCurrentProcess(),

        TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))

    error("OpenProcessToken");

/* Get the LUID for the shutdown privilege. */

LookupPrivilegeValue(NULL, TEXT("SE_SHUTDOWN_NAME"),

        &tkp.Privileges[0].Luid);

tkp.PrivilegeCount = 1;  /* one privilege to set    */

tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

/* Get the shutdown privilege for this process. */

AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,

        (PTOKEN_PRIVILEGES)NULL, 0);

/* Cannot test the return value of AdjustTokenPrivileges. */

if (GetLastError() != ERROR_SUCCESS)

    error("AdjustTokenPrivileges");

/* Shut down the system and force all applications to close. */

if (!ExitWindowsEx(EWX_SHUTDOWN | EWX_FORCE, 0))

    error("ExitWindowsEx");

For more information about setting security privileges, see Security.


Retrieving the Last-Error Code

When a function in the Win32 API fails, it sets the last-error code. If your application needs more details about an error, it can retrieve the last-error code.

The following example shows an error-handling function used by the other examples in this topic.

void error(LPSTR lpszFunction)

{

    CHAR szBuf[80];

    DWORD dw = GetLastError();

    sprintf(szBuf, "%s failed: GetLastError returned %u\n",

        lpszFunction, dw);

    MessageBox(NULL, szBuf, "ERROR", MB_OK);

    ExitProcess(dw);

}


Error Functions

Following are the functions used with errors.

Beep
ExitWindows
ExitWindowsEx
FlashWindow
GetLastError
MessageBeep
SetErrorMode
SetLastError
SetLastErrorEx


Event Logging

When an error occurs in an application written for Microsoft® Windows®, the system administrator or support personnel must determine what caused the error, attempt to recover any lost data, and prevent the error from recurring. If applications record important events such as low-memory conditions or excessive disk retries, the record of this information, called an event log, can be used to help determine what conditions may have caused the error and the context in which the error occurred. (Event logging can also be applied to the Windows operating system and to system services.) By periodically viewing the event log, the system administrator may be able to identify problems before they cause serious damage.

Many applications record errors and events in various proprietary error logs. These proprietary logs have different formats, apply different user interfaces for their display, and cannot be merged to provide a complete report. But all of these logs store similar information and present the logged data in similar ways.

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


Event Logging Model

Event logs store records of significant events on behalf of the Windows operating system and the applications that run with Windows. Generally, applications should log only information that could be useful in diagnosing a hardware or software problem.

Events are classified as information, warnings, and errors. All event classifications have well-defined common data and can optionally include event-specific data. For example, information can assert that a service has started. Warnings are used for recoverable problems such as low disk-space conditions. Errors are used for nonrecoverable conditions that might cause an application to fail. In addition to logging event classifications, the security service logs successes and failures in audits.


Logging Guidelines

Because logging functions are general purpose, developers must decide what information is appropriate to log. It is important to note that logging consumes resources: disk space and logging time. The event log is not intended to be used as a trace facility.

You should log information about events that can be used to diagnose problems after they have occurred. Logging low-memory conditions, for example, can provide information about a problem that the system administrator can solve by adding more memory to the computer.

Following are more examples in which event logging is helpful:

•	A disk driver encounters a bad sector on the disk. It may be able to read from or write to the sector after some retries, but the sector will probably go bad eventually. The disk driver should log a warning if it can proceed; otherwise, it should log an error.

•	A file system finds a bad sector and fixes it. A large number of events of this type might indicate that the disk is about to fail. The file system logs a warning event.

•	A device driver encounters a hardware problem, such as a disk controller time-out, a power failure in a parallel port, or a data error from a network or serial card. Logging information about these events can help in diagnosing hardware problems. The device driver logs the hardware problem.

•	An Application encounters resource problems. An application or a device driver may get into a low-memory situation (caused by a code bug, for example) that degrades performance. Logging an event when memory allocation fails might later provide a clue about what went wrong. The application logs the resource problem.

•	A server application (a database or a communications server, for example) records events such as a user logging on, opening a database, or starting a file transfer. The server can also log important information as it runs, such as the number of resources the application is using, errors it encounters (cannot access file, host process disconnected, and so on), a corruption in the database (not able to find a leaf node down a certain path in a tree), or whether a file transfer was successful or not. All of this information can be valuable to a support person (or to the developer of the application). The application records such events and logs them as information events.


Logging Performance and Size

Typically, how much disk space does an event log require? What is the overhead for an application that makes a call to log an event? The answers to these questions depend on how much information the application chooses to log. This is why it is important to log only essential information and to place event logging calls in an error path in the application, rather than place them in the main path, where the performance hit would be more severe.


Event Logging Management Information

Event logging management information is stored in the Services key of the configuration database and can be modified by a system administrator.

The structure of the configuration information is as follows:

HKEY_LOCAL_MACHINE

  SYSTEM

    CurrentControlSet

      Services

        EventLog

          Application

          Security

          System

The EventLog key contains several subkeys, called logfiles. The default logfiles are Application, Security, and System. Each logfile subkey can contain subkeys, called sources. You cannot use a source name that has been used as a logfile name, and source names should not be hierarchical. (The backslash character [\] cannot be used in a registry key.) Each source entry contains information specific to the source of the event, as shown in the following table.

Value	Description
EventMessageFile	Specifies the path for the event identifier message file. This value has the type REG_EXPAND_SZ.
CategoryMessageFile	Specifies the path for the category message file. The event category and event identifier message strings can be in the same file. This value has the type REG_EXPAND_SZ.
ParameterMessageFile	Specifies the path for the event source's parameter message file. This file contains language-independent strings that are to be inserted into the event description strings. You can use the same message file for parameter, category, and event identifier message strings. This value has the type REG_EXPAND_SZ.
CategoryCount	Specifies the number of categories supported. This value has the type REG_DWORD.
TypesSupported	Specifies a bitmask of supported types. This value has the type REG_DWORD.
When an application uses the RegisterEventSource or OpenEventLog function to get a handle of an event log, the event logging service searches for the specified source name in the registry. For example, the Application logfile might have configured sources of Microsoft® SQL Server™ and Microsoft® Excel. If an application uses RegisterEventSource or OpenEventLog with a source name of Application, SQL, or Excel, the event logging service returns a handle to the Application logfile.

An application can use the Application event log without adding a new source key to the registry. If the application calls RegisterEventSource, passing a source name that cannot be found in the registry, the event logging service uses the Application logfile by default. However, because there is not a message or category string file, the event viewer will not be able to map the event identifier or category to a replacement string. For this reason, the recommended procedure is to add a unique source name for the application to the registry. This allows you to specify message files for the event identifier and category in your events. Applications and services should add their source names to the Application logfile. Device drivers should add their source name to the System logfile.

An event viewer application uses the OpenEventLog function to open the event log for an event source. The event viewer can then use the ReadEventLog function to read event records from the log. ReadEventLog returns a buffer containing an EVENTLOGRECORD structure and additional information that describes a logged event. The EventID member of the EVENTLOGRECORD is the identifier of a description string in the source's event message file. The event viewer uses the LoadLibrary function to load the file indicated by the source's EventMessageFile registry value. The viewer then uses the FormatMessage function to retrieve the description string from the loaded module.

The description string may contain insertion string placeholders, such as %n, where %1 indicates the first insertion string, and so on. In this case, the buffer returned by ReadEventLog contains the insertion strings. The NumStrings member of the EVENTLOGRECORD indicates the number of insertion strings. The StringOffset member of the EVENTLOGRECORD indicates the location of the first insertion string in the buffer.

An insertion string may also contain placeholders of the form %%n, where n is the identifier of a string in the source's parameter message file. In this case, the event viewer uses LoadLibrary and FormatMessage to retrieve the insertion string from the file indicated by the source's ParameterMessageFile registry value.

For more information about using the registry, see Registry. For more information about creating and using message files, see your message compiler documentation.


Event Logging Operations

In the following table are the five operations that can be performed on the event logs.

Operation	Function
Backup	BackupEventLog
Clear	ClearEventLog
Query	GetOldestEventLogRecord, GetNumberOfEventLogRecords
Read	ReadEventLog
Write	ReportEvent
The OpenEventLog, OpenBackupEventLog, RegisterEventSource, DeregisterEventSource, and CloseEventLog functions also open and close event log handles; this provides an object-oriented model for the function set, as well as some performance gain when performing multiple operations on the logs.

The OpenEventLog and ReportEvent functions take an optional server name as a parameter so that the operations can be performed on the remote server. OpenEventLog should be used for reading or performing some administrative operation (backup, clear, query) on the log, and RegisterEventSource should be used for writing to logs.


Event Log Entry

This guide describes the parameters supplied for logged events.


Source

Source is the name of the software that logs the event. For many applications, Source may be simply the application name, or it may reflect a subcomponent of a larger application.


Event Identifier

Event identifiers are looked up within a message file to locate a description string that can be presented to the user. Support personnel also use event identifiers; if a user can identify the source and the event identifier, support personnel will know exactly which event has occurred. Event identifiers are unique to a particular source.


Type

Windows NT™ defines five types of event logging. Each event must be of a single type, because types cannot be combined.

Event type	Description
Information	Information events are used to note infrequent but significant successful operations. For example, when Microsoft SQL Server successfully loads, it may be appropriate to log a "SQL Server has started" information event. Note that while this is appropriate for major server services, it is generally inappropriate for a desktop application (Microsoft Excel, for example) to log an event each time it is started. Information events should not be used as a trace facility.
Warning	Warning events are used to indicate problems that are not significant, but that may foretell of future errors or other problems. Resource consumption is a good candidate for a Warning event. For example, a warning could be logged if disk space is low. Errors that are recovered without loss of function or data can be classified as warnings.
Error	Error events are used to indicate significant problems that have occurred and that the user should know about. Errors usually indicate a loss of functionality or data. For example, if a service cannot be loaded as the system boots, an Error event can be logged.
Success Audit	Success Audit events are security events that occur when an audited access attempt is successful. For example, a successful logon attempt is a Success Audit event.
Failure Audit	Failure Audit events are security events that occur when an audited access attempt fails. For example, a failed attempt to open a file is a Failure Audit event.


Category

Categories are used to help organize events so that they can be filtered in the Event Viewer. Each Source can define its own numbered Categories and the text strings to which they are mapped. The Categories must be numbered consecutively beginning with the number 1. With Event Viewer, it is possible to filter by Source and within Source, by Category. The security system uses several categories: Logon/Logoff, File System Access, Privileged Actions, Change in Security Policy. Categories for other parts of the system are developed over time as it becomes clear which events are being logged. An application can define its own categories.


Strings

Strings are optional language-independent (nonlocalized) strings used to fill in values for placeholders in description strings. Because the strings are not localized, it is critical that this field be used only to store language-independent strings such as numeric values or string tokens (filenames, user names, and so on). String length must not exceed 32 kilobytes − 1 characters.

It is not acceptable to use several strings to "paste" together a larger description or to use nontoken strings. The insertion string should be treated as data, not text. For example, the following example is not recommended:

Str1$ = successfully

Description = "User was %1 added to database."

Using these two strings to form the string, "User was successfully added to database." (the alternative being Str1$ = "not") is not acceptable for three reasons:

1.	The strings "successfully" and "not" should be localized.

2.	Even if the insertion strings are obtained from language-dependent message files, this is done when the event is logged, not when it is viewed. When the event is viewed, the language may be wrong.

3.	Such substitutions of adverbs and adjectives will not work in many other languages. The preceding example should use two separate events.

The following example shows an appropriate use of strings:

Str1$ = "c:\testapp.c".

Description = "Access denied. Attempted to open the file %1"


Description

Each event is associated with a description located in a message file that is registered by the Source. The description should help the user understand what went wrong and suggest what actions to take. Focus the description toward users solving their own problems, not toward support people or developers. Make the description clear and concise and avoid culture-specific phrases. If your event includes private data in the Data field, include at the end of the description an explanation about what the Data field contains. For example, the network software often notes: "(The SMB is the event data)." As a convention, use parentheses around such remarks, as indicated in this example. Several applications can share the same message file, and the message file can contain descriptions for both the event identifier and the event category.

The description strings are indexed by event identifier, enabling Event Viewer to display event-specific text for any event based on the event identifier. All descriptions are localized and language dependent. Description strings can optionally contain placeholders for insertion strings. Each placeholder is represented by a percent sign and an index number for the string to substitute. For example, the placeholder %1 is replaced by the first insertion string, %5 is replaced by the fifth insertion string, and so on.


Data

Each event can have event-specific data associated with it. Event Viewer has no information of any of the events, and only displays extra data in a combined hexadecimal and text dump format. Use event-specific data sparingly, including it only if you are sure it will be useful to a support technician or a developer. You might include, for example, data containing a structure filled with information that could help a technician debug an application failure.

Examples of event-specific data are found in many network events; network control blocks (NCBs) are included as event-specific data. In all cases, the last part of the description string should include a note about what information is available as event-specific data. Third-party applications can use the Data field to store information the application can process independently of Event Viewer. For example, you could write your own viewer specific to your events, or write a program that scans the logfiles and makes reports, including information from the event-specific data.


The EVENTLOGRECORD Structure

The ReadEventLog function uses the EVENTLOGRECORD structure to format event log information. This structure contains information relating to the content of the event record. The actual event record information follows this structure in the buffer returned by the ReadEventLog function.


Special Cases

Each call to an event logging function is considered to be an atomic operation. For reading the event log, only whole event records are returned. For logging events, each event record is guaranteed to be written as a complete record in the log. The following list describes how the event logging service handles special conditions:

•	Multiple calls written to the same log. The event logging service serializes the operations; the event logs are written sequentially in the logfile.

•	A call to read and a call to write are made at the same time. What happens depends on where the current read operation is being carried out in the file. If the read position is at the end of the file, either the read operation fails with an "end-of-file" status (if the write operation has not been done), or it returns the new record that the write operation has just written to the log.

•	Clearing the log before reading. The read operation returns an "end-of-file" status after the file is cleared.

•	Clearing the log before writing. The clear operation truncates the logfile; the write operation then writes the new record at the beginning of the log.


Using Event Logging

•	Adding a source to the registry.

•	Reporting an event.

•	Querying the event log.

•	Reading the event log.

You can use the Windows Registration Database Editor (REGEDIT.EXE) to view the event log registry keys, and you can use Event Viewer to view the event logs.


Adding a Source to the Registry

You can use the default Application event log without adding your source name to the registry. However, Event Viewer will not be able to map your event identifier codes to message strings unless you register your source and provide a message-file name.

You can add a new source name to the registry by opening a new registry subkey under the Application key and adding registry values to the new subkey. The following code sample opens a new source name called SamplApp and adds to the new subkey a message-file name and a bitmask of supported types.

HKEY hk;

DWORD dwData;

UCHAR szBuf[80];

/*

 * Add your source name as a subkey under the Application

 * key in the EventLog service portion of the registry.

 */

if (RegCreateKey(HKEY_LOCAL_MACHINE,

"SYSTEM\\CurrentControlSet\\Services\

\\EventLog\\Application\\SamplApp",

            &hk))

    ErrorExit("could not create registry key");

/* Set the Event ID message-file name. */

strcpy(szBuf, "%SystemRoot%\\System\\SamplApp.dll");

/* Add the Event ID message-file name to the subkey. */

if (RegSetValueEx(hk,             /* subkey handle         */

        "EventMessageFile",       /* value name            */

        0,                        /* must be zero          */

        REG_EXPAND_SZ,            /* value type            */

        (LPBYTE) szBuf,           /* address of value data */

        strlen(szBuf) + 1))       /* length of value data  */

    ErrorExit("could not set event message file");

/* Set the supported types flags. */

dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE |

    EVENTLOG_INFORMATION_TYPE;

if (RegSetValueEx(hk,      /* subkey handle                */

        "TypesSupported",  /* value name                   */

        0,                 /* must be zero                 */

        REG_DWORD,         /* value type                   */

        (LPBYTE) &dwData,  /* address of value data        */

        sizeof(DWORD)))    /* length of value data         */

    ErrorExit("could not set supported types");

RegCloseKey(hk);


Reporting an Event

After you have added a source name to the registry, use the RegisterEventSource function to get a handle of the Application event log, as in the following example, which gets the handle and then adds an event to the logs.

LPSTR aszMsg[] = {

    "SamplApp",

    };

HANDLE h;

h = RegisterEventSource(NULL, /* uses local computer         */

    "SamplApp");              /* source name                 */

if (h == NULL)

    ErrorExit("could not register event source");

if (!ReportEvent(h,           /* event log handle            */

        EVENTLOG_ERROR_TYPE,  /* event type                  */

        0,                    /* category zero               */

        0x1003,               /* event identifier            */

        NULL,                 /* no user security identifier */

        1,                    /* one substitution string     */

        0,                    /* no data                     */

        (LPTSTR *) aszMsg,    /* address of string array     */

        NULL))                /* address of data             */

    ErrorExit("could not report event");

DeregisterEventSource(h);


Querying the Event Log

The following code sample displays the number of event records currently in the Application event log and the System event log.

/* Open the System log. */

h = OpenEventLog(NULL,  /* uses local computer   */

    "System");          /* source name          */

if (h == NULL)

    ErrorExit("could not open System event log");

/* Get the number of records in the System event log. */

if (!GetNumberOfEventLogRecords(h, &cRecords))

    ErrorExit

       ("could not get number of records");

printf("There are %d records in the System event log.\n", cRecords);

CloseEventLog(h);

/* Open the Application log. */

h = OpenEventLog(NULL,  /* uses local computer  */

    "Application");     /* source name          */

if (h == NULL)

    ErrorExit("could not open Application event log");

/* Get the number of records in the Application event log. */

if (!GetNumberOfEventLogRecords(h, &cRecords))

    ErrorExit("could not get number of records");

printf("There are %d records in the Application event log.\n",

    cRecords);

CloseEventLog(h);


Reading the Event Log

The following code sample reads all the records in the Application logfile and displays the event identifier, event type, and source name for each event log entry.

EVENTLOGRECORD *pevlr;

BYTE bBuffer[BUFFER_SIZE];

DWORD dwRead, dwNeeded, cRecords, dwThisRecord = 0;

    /* Open the Application event log. */

    h = OpenEventLog(NULL,  /* uses local computer      */

        "Application");     /* source name              */

    if (h == NULL)

        ErrorExit("could not open Application event log");

    pevlr = (EVENTLOGRECORD *) &bBuffer;

    /*

     * Opening the event log positions the file pointer

     * for this handle at the beginning of the log.

     *

     * Read records sequentially until there

     * are no more.

     */

    while (ReadEventLog(h,                /* event log handle */

                EVENTLOG_FORWARDS_READ |  /* reads forward    */

                EVENTLOG_SEQUENTIAL_READ, /* sequential read  */

                0,            /* ignored for sequential reads */

                pevlr,        /* address of buffer            */

                BUFFER_SIZE,  /* size of buffer               */

                &dwRead,      /* count of bytes read          */

                &dwNeeded)) { /* bytes in next record         */

        while (dwRead > 0) {

            /*

             * Print the event ID, type, and source name.

             * The source name is just past the end of the

             * formal structure.

             */

            printf("%02d  Event ID: 0x%08X ",

                dwThisRecord++, pevlr->EventID);

            printf("EventType: %d Source: %s\n",

                pevlr->EventType, (LPSTR) ((LPBYTE) pevlr +

                sizeof(EVENTLOGRECORD)));

            dwRead -= pevlr->Length;

            pevlr = (EVENTLOGRECORD *)

                ((LPBYTE) pevlr + pevlr->Length);

        }

        pevlr = (EVENTLOGRECORD *) &bBuffer;

    }

    CloseEventLog(h);


Event Logging Functions

The following functions are used with event logging.

BackupEventLog
ClearEventLog
CloseEventLog
DeregisterEventSource
GetNumberOfEventLogRecords
GetOldestEventLogRecord
NotifyChangeEventLog
OpenBackupEventLog
OpenEventLog
ReadEventLog
RegisterEventSource
ReportEvent


Files

A file is the basic unit of storage that enables a computer to distinguish one set of information from another.


About Files

In Microsoft® Windows®, files are stored on storage media, such as disks or tapes, and can be organized into groups called directories. The Windows file input and output (I/O) functions enable applications to create, open, modify, and delete files and directories. They also enable applications to obtain system information, such as what disk drives are present.


System Organization

A volume is a storage device, such as a fixed disk or floppy disk, formatted to store directories and files. Each volume has a root directory. Directories and files on the volume are organized in a tree structure that starts at the root directory. Each directory entry identifies the name, attributes, location, and size of the file or subdirectory.

A large volume can be divided into more than one logical volume, also called a partition. To the user and to the operating system, each partition appears to be a separate volume.

A file system is operating system software that manages the low-level organization of files on a volume. Windows supports the following file systems:

•	File allocation table (FAT)

•	High-performance file system (HPFS)

•	New Technology file system (NTFS)

The type of file system defines the filename conventions on a volume and may also provide specific file system features, such as security, recoverability, and high I/O performance. Each volume can use a different file system.

For more information on the FAT, HPFS, and NTFS file systems, see File Systems.


Accessing Files

The first time a file function accesses a volume and whenever a volume is placed in a floppy-disk drive, Windows examines the volume to determine the appropriate file system. Thereafter, Windows manages all I/O to that volume through the device driver supporting the file system. If an error occurs, the driver returns it to Windows, which then passes it back to the application.

The Windows file functions enable applications to access files regardless of the underlying file system. However, capabilities may vary depending on the file system and/or operating system in use. For example, the CreateFile function includes a security parameter that provides no security benefits for an application written for Windows running with current versions of MS-DOS.

The Windows file functions that create, open, and delete files and directories identify them by their names. These functions store or search for the file or directory in the current directory on the current disk drive, unless the name explicitly specifies a path to a different directory, disk drive, or both.


Filename Conventions

Although each file system can have specific rules about the formation of individual components in a directory or filename, all file systems follow the same general conventions for combining components. For example, the FAT file system requires file and directory names to have the 8.3-character filename format, the HPFS file system allows names to be up to 254 characters, and the NTFS file system allows names to be up to 255 characters. All three file systems use the backslash (\) character to separate directory names and the filename when forming a path.

General rules for applications creating names for directories and files or processing names supplied by the user include the following:

•	Use any character in the current code page for a name, but do not use a path separator, a character in the range 0 through 31, or any character explicitly disallowed by the file system. A name can contain characters in the extended character set (128−255).

•	Use the backslash (\), the forward slash (/), or both to separate components in a path. No other character is acceptable as a path separator.

•	Use a period (.) as a directory component in a path to represent the current directory.

•	Use two consecutive periods (..) as a directory component in a path to represent the parent of the current directory.

•	Use a period (.) to separate components in a directory name or filename.

•	Do not use the following characters in directory names or filenames, because they are reserved for Windows:

< > : " / \ |

•	Do not use reserved words, such as aux, con, and prn, as filenames or directory names.

•	Process a path as a null-terminated string. The maximum length for a path is given by MAX_PATH.

The wide (Unicode) versions of the CreateDirectory, FindFirstFile, GetFileAttributes, and SetFileAttributes functions permit paths that exceed the MAX_PATH length if the path has the "\\?\" or "\\?\UNC\" prefix. These prefixes direct the functions to turn off path parsing. Use the "\\?\" prefix with paths for local storage devices and the "\\?\UNC\" prefix with paths having the Universal Naming Convention format.

•	Do not assume case sensitivity. Consider names such as OSCAR, Oscar, and oscar to be the same.

By following the rules listed in this section, an application can create valid names for files and directories regardless of the file system in use.

Long Filenames on Windows NT FAT Partitions

You can create or open long filenames on Windows NT FAT partitions.

The operating system stores the long filenames on disk in Unicode. This means that the original long file name is always preserved, even if it contains extended characters, and regardless of the code page that is active during a disk read or write operation.

The legal character set for these long filenames is the NTFS legal character set, less one character: the colon (':') that NTFS uses for opening alternate file streams. This means that you can freely copy files between NTFS and FAT partitions without losing any file name information.

The operating system stores the long filenames on disk masquerading as extra volume label directory entries. These entries are not available from the DOS dir command, but they are available from the Windows NT dir command. When you create a long filename on a Windows NT FAT partition, the operating system creates a corresponding short 8.3 form of the name, just as it does on an NTFS partition.


File Operations

This section describes the file I/O operations and operating system information provided by the file functions in the Microsoft® Win32® application programming interface (API).


Creating and Opening Files with the CreateFile Function

The CreateFile function can create a new file or open an existing file. When an application uses this function, it must specify whether it will read from the file, write to the file, or both. The application must also specify what action to take whether or not the file exists. For example, an application can specify that CreateFile always be used to create the file. As a result, the function creates the file if it does not exist and overwrites the file if it does exist.

CreateFile also enables an application to specify whether it wants to share the file for reading, writing, both, or neither. A file that is not shared cannot be opened more than once by the first application nor by another application until the first application has closed.

Windows assigns a unique identifier, called a file handle, to each file that is opened or created. An application can use the file handle in functions that read from, write to, and describe the file. It is valid until the file is closed. When an application starts, it inherits all open file handles from the process that started it, if the handles are inheritable. For more information about processes, see Processes and Threads.

For information about the standard input, standard output, and standard error file handles, see Consoles and Character-Mode Support.

An application should check the return value of CreateFile before attempting to use the handle to access the file. If an error occurs, the application can use the GetLastError function to get extended error information.


Closing and Deleting Files

To use operating system resources efficiently, an application should close files when they are no longer needed by using the CloseHandle function. If a file is open when an application terminates, Windows closes it automatically.

The DeleteFile function can be used to delete a file. The file must, however, be closed before any attempt to delete it.


Copying and Moving Files

Before a file can be copied, it must be closed or opened only for reading. No thread can have the file opened for writing. To copy an existing file to a new one, use the CopyFile function. Applications can specify whether CopyFile fails if the new file already exists.

A file must also be closed before an application can move it. The MoveFile function copies an existing file to a new location and deletes the original. Applications frequently use this function to rename files.


Reading from and Writing to a File

Every open file has a file pointer that specifies the next byte to be read or the location to receive the next byte written. When a file is opened for the first time, Windows places the file pointer at the beginning of the file. As each byte is read or written, Windows advances the file pointer. An application can also move the file pointer by using the SetFilePointer function.

An application reads from and writes to a file by using the ReadFile and WriteFile functions. These functions require a handle of a file to be opened for reading and writing, respectively. ReadFile and WriteFile read and write a specified number of bytes at the location indicated by the file pointer. The data is read and written exactly as given; the functions do not format the data.

When the file pointer reaches the end of a file and the application attempts to read from the file, no error occurs, but no bytes are read. Therefore, reading zero bytes without an error means the program has reached the end of the file.

An application can truncate or extend a file by using the SetEndOfFile function. This function sets the end of file to the current position of the file pointer. A WriteFile of zero bytes does nothing.

When an application writes to a file, Windows usually collects the data being written in an internal buffer and writes the data to the disk on a regular basis.

An application can force the operating system to write the contents of the buffer to the disk by using the FlushFileBuffers function. Alternatively, an application can specify that write operations are to bypass the internal buffer and write directly to the disk by setting a flag when the file is created or opened by using the CreateFile function.

If there is data in the internal buffer when the file is closed, Windows does not automatically write the contents of the buffer to the disk before closing the file. If the application does not force the operating system to write the buffer to disk before closing the file, the caching algorithm determines when the buffer is written.

Locking and Unlocking Files

Although Windows allows more than one application to open a file and write to it, applications must not write over each other's work. An application can prevent this problem by temporarily locking a region in a file. The LockFile function locks a specified range of bytes in a file. The range may extend beyond the current end of the file. Locking part of a file prevents all other processes from reading or writing anywhere in the specified area. Attempts to read from or write to a region locked by another process always fail. The application unlocks the region by using the UnlockFile function. An application should unlock all locked areas before closing a file.

Synchronizing Input and Output

Asynchronous input and output is a type of I/O that allows some I/O functions to return immediately, even though an I/O request is still pending. Asynchronous I/O enables an application to continue with other processing and wait for the I/O to be completed at a later time. Asynchronous I/O is also called overlapped I/O.

The ReadFile and WriteFile functions enable an application to specify an OVERLAPPED structure that indicates where to position the file pointer before the read or write operation. The handle of the file being read from or written to must have been opened with the FILE_FLAG_OVERLAPPED flag. The OVERLAPPED structure can also contain an event handle on which the WaitForSingleObject or WaitForMultipleObjects function can wait.

An application can also wait on the file handle to synchronize the completion of an I/O operation, but doing so requires extreme caution. Each time an I/O operation is started, the operating system sets the file handle to the nonsignaled state. Each time an I/O operation is completed, the operating system sets the file handle to the signaled state. Therefore, if an application starts two I/O operations and waits on the file handle, there is no way to determine which operation is finished when the handle is set to the signaled state. If an application must perform multiple asynchronous I/O operations on a single file, it should wait on the event handle in the OVERLAPPED structure for each I/O operation, rather than on the file handle.

The ReadFileEx and WriteFileEx functions enable an application to specify a routine to execute when the asynchronous I/O request is completed.

For more information about synchronization, see Synchronization.


Searching for Files

An application can search the current directory for all filenames that match a given pattern by using the FindFirstFile, FindNextFile, and FindClose functions. The pattern must be a valid filename and can include wildcard characters.

FindFirstFile creates a handle that FindNextFile uses to search for other files with the same pattern. Both functions also return information about the file that was found in a WIN32_FIND_DATA structure. This information includes the filename, size, attributes, and time. The FindClose function destroys the handle created by FindFirstFile.

An application can search for a single file on a specific path by using the SearchPath function.


Creating Temporary Files

Applications can create temporary filenames with the GetTempFileName function. The GetTempPath function retrieves the path to the directory where temporary files are to be created.


Getting Information About Files

Nine characteristics called attributes may be associated with a file. The attributes can be one or more of the following values.

Value	Meaning
FILE_ATTRIBUTE_ARCHIVE	The file is an archive file. Applications use this value to mark files for backup or removal.
FILE_ATTRIBUTE_DIRECTORY	The file is a directory.
FILE_ATTRIBUTE_HIDDEN	The file is hidden. It is not included in an ordinary directory listing.
FILE_ATTRIBUTE_NORMAL	The file has no other attributes. This value is valid only if used alone.
FILE_ATTRIBUTE_READONLY	The file is read-only. Applications can read from the file but cannot write to it or delete it.
FILE_ATTRIBUTE_SYSTEM	The file is part of the operating system or is used exclusively by it.
FILE_ATTRIBUTE_TEMPORARY	The file is being used for temporary storage. Applications can write to the file only if absolutely necessary. Most of the file's data remains in memory without being flushed to the media, because the file will soon be deleted.
FILE_ATTRIBUTE_ATOMIC_WRITE	Reserved; do not use.
FILE_ATTRIBUTE_XACTION_WRITE	Reserved; do not use.
An application can retrieve and set a file's attributes by using the GetFileAttributes and SetFileAttributes functions. Applications cannot, however, use SetFileAttributes to set the directory attribute.

The GetFileType function returns the type of a file: disk, character (such as a console), pipe, or unknown. The GetFileSize function returns the size of a file. Applications can retrieve the full path of a file by using the GetFullPathName function.

Applications can retrieve and set the date and time a file was created, last modified, or last accessed by using the GetFileTime and SetFileTime functions. For more information about file times, see Time.


Directory Operations

When an application creates a new file, the operating system adds it to the specified directory. Each directory can have any number of files, up to the physical limit of the disk. An application can create new directories and delete existing directories by using the CreateDirectory and RemoveDirectory functions. An application cannot delete a directory unless it is empty.

The directory at the end of the active path is called the current directory; it is the directory in which the active application started, unless explicitly changed. An application can determine which directory is current by using the GetCurrentDirectory function. An application can change the current directory by using the SetCurrentDirectory function.

On the Windows NT platform, you can obtain a handle to a directory by calling the CreateFile function with the FILE_FLAG_BACKUP_SEMANTICS flag set. You can pass a directory handle to some functions in place of a file handle.

An application can monitor the contents of a directory and its subdirectories by using the FindFirstChangeNotification, FindNextChangeNotification, and FindCloseChangeNotification functions. Waiting for a change notification is similar to having a read operation pending against a directory and, if necessary, its subdirectories. When something changes within the directory being watched, the read operation is completed. For example, an application can use these functions to update a directory listing whenever a filename within the monitored directory changes.

An application can specify a set of conditions that trigger a change notification by using the FindFirstChangeNotification function. The conditions include changes to filenames, directory names, attributes, file size, time of last write, and security. This function also returns a handle that can be waited on by using the WaitForSingleObject or WaitForMultipleObjects function. If the wait condition is satisfied, FindNextChangeNotification can be used to provide a notification handle to wait on subsequent changes.

The FindCloseChangeNotification function closes the notification handle.


Getting System Information

Windows provides several functions that applications can use to obtain information about the file system, operating system, and hardware.

The GetVolumeInformation function retrieves information about the file system on a given volume. This information includes the volume name, volume serial number, file system name, file system flags, maximum length of a filename, and so on.

The GetSystemDirectory and GetWindowsDirectory functions retrieve the paths to the Windows system directory and the Windows directory, respectively.

The GetDiskFreeSpace function retrieves organizational information about a disk, including the number of bytes per sector, the number of sectors per cluster, the number of free clusters, and the total number of clusters.

The GetDriveType function indicates whether the disk referenced by the specified disk drive is a removable, fixed, CD-ROM, RAM, or network drive.

The GetLogicalDrives function identifies the drives currently present on the operating system. The GetLogicalDriveStrings function retrieves a null-terminated string for each drive present on the operating system. Use these strings whenever a root directory is required.


File Compression

Windows NT release 3.51 supports file compression on an individual file basis for volumes that use the NTFS file system.


Compression Attribute

On volumes that use the NTFS file system, each file and directory has a compression attribute. Other file systems may also implement a compression attribute for individual files and directories.

You can determine whether a file system supports a compression attribute for files and directories by calling the GetVolumeInformation function and examining the FS_FILE_COMPRESSION bit flag.

If a file's compression attribute is set, all of the data in the file is compressed. If the attribute is clear, none of the data in the file is compressed. There is no partially compressed state. The compression attribute is a simple Boolean indicator of compression state.

A directory's compression attribute provides a default compression attribute for newly created files and subdirectories. When you call CreateFile or CreateDirectory to create a new file or directory, the new file or directory inherits the compression attribute of its parent directory.


Compression State

Each file and directory on a volume that supports compression for individual files and directories has a compression state. Windows NT release 3.51 provides such support for volumes that use the NTFS file system.

Whereas the compression attribute of a file or directory indicates simply whether the file or directory is compressed or not compressed, the compression state also specifies the format of any compressed data.

Compression state is encoded as a 16-bit value. A compression state value of zero indicates that a file is not compressed. A value of one indicates that a file is compressed, using the default compression format for its parent directory. Any other value indicates that a file is compressed, using the compression format encoded by the compression state value.

For directories, the compression state provides a default compression state for newly created files and subdirectories. In other words, new files and directories inherit the compression state of their parent directory.


Determining Compression Attribute and State

Use the GetFileAttributes function to determine the compression attribute of a file or directory.

Use the FSCTL_GET_COMPRESSION DeviceIoControl operation to determine the compression state of a file or directory.


Setting Compression Attribute and State

On volumes whose file system supports the compression of files or directories, such as NTFS volumes under Windows NT release 3.51, new files and subdirectories inherit the compression attribute and compression state of their parent directory.

Use the FSCTL_SET_COMPRESSION DeviceIoControl operation to set the compression state of a file or directory. This operation also sets the compression attribute of the file or directory.

Setting the compression state of a file to a nonzero value compresses the file, using the compression format encoded by the compression state value. Setting a file's compression state to zero decompresses the file. These are synchronous operations. The file is compressed or decompressed immediately when you set its compression state.

Setting a directory's compression state does not cause any immediate compression or decompression. Instead, setting a directory's compression state sets a default compression state that will be given to all newly created files and subdirectories.


Obtaining the Size of a Compressed File

Use the GetCompressedFileSize function to obtain the compressed size of a file. If the file is compressed, its compressed size will be less than its uncompressed size. Use the GetFileSize).function to determine the uncompressed size of a file.


Using Files

The Windows file functions enable applications to access files regardless of the underlying file system. However, their functionality may vary depending on the operating system in use. If you have questions about a specific function, consult the reference information for that function.

For functions that manipulate files, the filenames may be relative to the current directory. A filename is relative to the current directory if it does not begin with a disk designator or directory name separator, such as a backslash (\). If the filename begins with a disk designator, it is a fully qualified path.

The examples in this section illustrate how to perform the following tasks:

•	Creating and opening files

•	Reading, writing, and locking files

•	Creating and using a temporary file

•	Searching for files and changing file attributes

•	Monitoring changes in a directory or directory tree

•	Testing for the end of the file

•	Retrieving a file pointer


Creating and Opening Files

You can use the CreateFile function to create a new file or open an existing file. You must specify the filename, preferred access, share mode, creation instructions, and attributes.

The following example returns a handle of the current console input buffer.

HANDLE hReadWriteInput;

hReadWriteInput = CreateFile("CONIN$",

    GENERIC_READ | GENERIC_WRITE,

    FILE_SHARE_READ | FILE_SHARE_WRITE, /* share with cmd.      */

    NULL,

    OPEN_EXISTING,              /* open already created console */

    0,                          /* normal file open             */

    NULL

    );

For more information about consoles, see Consoles and Character-Mode Support.

In the following example, CreateFile opens an existing file for reading.

HANDLE hFile;

hFile = CreateFile("MYFILE.TXT",           /* open MYFILE.TXT    */

                GENERIC_READ,              /* open for reading   */

                FILE_SHARE_READ,           /* share for reading  */

                (LPSECURITY_ATTRIBUTES) NULL, /* no security     */

                OPEN_EXISTING,             /* existing file only */

                FILE_ATTRIBUTE_NORMAL,     /* normal file        */

                (HANDLE) NULL);            /* no attr. template  */

if (hFile == INVALID_HANDLE_VALUE) {

        ErrorHandler("Could not open file.");   /* process error */

}

In this example, CreateFile succeeds only if a file named MYFILE.TXT already exists in the current directory. An application should check the return value of CreateFile before attempting to use the handle to access the file. If an error occurs, the application should use the GetLastError function to get extended error information and respond accordingly.

A file must be closed before it can be deleted. The following lines close and delete the MYFILE.TXT file.

CloseHandle(hFile);

DeleteFile("MYFILE.TXT");

In the following example, CreateFile creates a new file and opens it for writing.

HANDLE hFile;

hFile = CreateFile("MYFILE.TXT",           /* create MYFILE.TXT  */

             GENERIC_WRITE,                /* open for writing   */

             0,                            /* do not share       */

             (LPSECURITY_ATTRIBUTES) NULL, /* no security        */

             CREATE_ALWAYS,                /* overwrite existing */

             FILE_ATTRIBUTE_NORMAL |       /* normal file        */

             FILE_FLAG_OVERLAPPED,         /* asynchronous I/O   */

             (HANDLE) NULL);               /* no attr. template  */

if (hFile == INVALID_HANDLE_VALUE) {

    ErrorHandler("Could not open file.");  /* process error      */

}

In addition to the standard attributes (read only, hidden, system, and so on), you can also specify security attributes by including a pointer to a SECURITY_ATTRIBUTES structure as the fourth parameter. However, the underlying operating system must support security for these attributes for them to have any effect. For more information about security, see Security.


Reading, Writing, and Locking Files

The ReadFile function requires a file handle that is open for reading, or reading and writing. ReadFile copies a specified number of bytes, up to the end of the file, to a specified buffer. It returns the actual number of bytes read in a variable specified by its fourth parameter.

The WriteFile function requires a file handle that is open for writing, or writing and reading. WriteFile copies a specified number of bytes, up to the end of the buffer, to a specified file. It returns the actual number of bytes written in a variable specified by its fourth parameter.

The following example illustrates a possible flow for using callback completion asynchronous I/O.

Completion Routine:

VOID IoCompletionRoutine(DWORD dwErrorCode,

        DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped)

{

    /* If an I/O error occurred, display the error and then exit. */

    if (dwErrorCode) {

        printf("FATAL I/O Error %ld I/O Context %lx.%lx\n",

            dwErrorCode, lpOverlapped, lpOverlapped->hEvent);

        ExitProcess(dwErrorCode);

    }

    LocalFree(lpOverlapped);

}

Main Thread:

VOID IoWorkerThread(VOID)

{

    HANDLE HandleVector[2];

    DWORD CompletionStatus;

    PIOREQUEST IoRequestPacket;

    LPOVERLAPPED Overlapped;

    BOOL IoOperationStatus;

    HandleVector[0] = IoWorkerListLock;

    HandleVector[1] = IoWorkerListSemaphore;

    for(;;) {

        /* Do an alertable wait on the handle vector. Both objects */

        /* being signaled at the same time means that there is an  */

        /* I/O request in the queue and the caller has exclusive   */

        /* access to the queue.                                    */

        CompletionStatus = WaitForMultipleObjectsEx(2, HandleVector,

                TRUE, INFINITE, TRUE);

        /* If the wait failed, error out. */

        if (CompletionStatus == 0xFFFFFFFF) {

            printf("FATAL WAIT ERROR %ld\n", GetLastError());

            ExitProcess(1);

        }

        /* If an I/O completion occurred, wait for another         */

        /* I/O request or I/O completion.                          */

        if (CompletionStatus != WAIT_IO_COMPLETION) {

        /* The wait was satisfied. Ownership of the I/O            */

        /* request queue is exclusive, and there is something in   */

        /* the queue. To insert something in the queue, the        */

        /* inserter gets the list lock (mutex), inserts an entry,  */

        /* signals the list semaphore, and finally releases the    */

        /* list lock.                                              */

            IoRequestPacket = RemoveHeadList(&IoRequestList);

            ReleaseMutex(IoWorkerListLock);

            /* Allocate an overlapped structure. */

            Overlapped = LocalAlloc(LMEM_ZEROINIT,

                    sizeof(OVERLAPPED));

            if (!Overlapped) {

                printf("FATAL allocation error\n");

                ExitProcess(1);

            }

            Overlapped->Offset = IoRequestPacket->Offset;

            Overlapped->OffsetHigh = IoRequestPacket->OffsetHigh;

            Overlapped->hEvent =

                    IoRequestPacket->dwAdditionalIoContext;

            if (IoRequestPacket->bRead) {

                IoOperationStatus =

                            ReadFileEx(IoRequestPacket->hFile,

                    IoRequestPacket->lpBuffer,

                    IoRequestPacket->dwTransferCount,

                    Overlapped, IoCompletionRoutine);

            }

            else {

                IoOperationStatus =

                    WriteFileEx(IoRequestPacket->hFile,

                        IoRequestPacket->lpBuffer,

                        IoRequestPacket->dwTransferCount,

                        Overlapped,

                        IoCompletionRoutine);

            }

            /* Test to see if the I/O was queued successfully. */

            if (!IoOperationStatus) {

                printf("FATAL I/O Error %ld I/O Context %lx.%lx\n",

                    GetLastError(), Overlapped, Overlapped->hEvent);

                ExitProcess(1);

            }

            /* The I/O queued successfully. Go back into the */

            /* alertable wait for I/O completion or for      */

            /* more I/O requests.                            */

        }

    }

}

The SetFilePointer function moves the file pointer a specified number of bytes, relative to the beginning or end of the file, or the file pointer's current position. If a positive number of bytes is specified, SetFilePointer moves the file pointer toward the beginning of the file; a negative value moves the pointer toward the end of the file.

The following example appends one file to the end of another file. The application opens two files by using CreateFile: ONE.TXT is opened for reading, and TWO.TXT is opened for writing. Then the application appends the contents of ONE.TXT to the end of TWO.TXT by reading and writing 4K blocks by using ReadFile and WriteFile. Before writing to the second file, the application sets the second file's pointer to the end of the file by using SetFilePointer and locks the area to be written by using LockFile. This prevents another process from accessing the area while the write is in progress. After each write operation, UnlockFile unlocks the locked area.

HANDLE hFile;

HANDLE hAppend;

DWORD  dwBytesRead, dwBytesWritten, dwPos;

char   buff[4096];

/* Open the existing file. */

hFile = CreateFile("ONE.TXT",     /* open ONE.TXT       */

    GENERIC_READ,                 /* open for reading   */

    0,                            /* do not share       */

    (LPSECURITY_ATTRIBUTES) NULL, /* no security        */

    OPEN_EXISTING,                /* existing file only */

    FILE_ATTRIBUTE_NORMAL,        /* normal file        */

    (HANDLE) NULL);               /* no attr. template  */

if (hFile == INVALID_HANDLE_VALUE) {

    ErrorHandler("Could not open ONE.");  /* process error */

}

/*

 * Open the existing file, or if the file does not exist,

 * create a new file.

 */

hAppend = CreateFile("TWO.TXT",   /* open TWO.TXT       */

    GENERIC_WRITE,                /* open for writing   */

    0,                            /* do not share       */

    (LPSECURITY_ATTRIBUTES) NULL, /* no security        */

    OPEN_ALWAYS,                  /* open or create     */

    FILE_ATTRIBUTE_NORMAL,        /* normal file        */

    (HANDLE) NULL);               /* no attr. template  */

if (hAppend == INVALID_HANDLE_VALUE) {

    ErrorHandler("Could not open TWO.");    /* process error */

}

/*

 * Append the first file to the end of the second file.

 * Lock the second file to prevent another process from

 * accessing it while writing to it. Unlock the

 * file when writing is finished.

 */

do {

  if (ReadFile(hFile, (LPSTR) buff, 4096, &dwBytesRead, NULL)) {

      dwPos = SetFilePointer(hAppend, 0, (LPLONG) NULL, FILE_END);

      LockFile(hAppend, dwPos, 0, dwPos + dwBytesRead, 0);

      WriteFile(hAppend, (LPSTR) buff, dwBytesRead,

          &dwBytesWritten, NULL);

      UnlockFile(hAppend, dwPos, 0, dwPos + dwBytesRead, 0);

  }

} while (dwBytesRead == 4096);

/* Close both files. */

CloseHandle(hFile);

CloseHandle(hAppend);


Creating and Using a Temporary File

The following example copies one file to another. The second file is an uppercase version of the first file.

The application opens the ORIGINAL.TXT file by using CreateFile. The application then obtains a temporary filename with the GetTempFileName function and uses CreateFile to create the temporary file. The application reads 4K blocks into a buffer, converts the buffer contents to uppercase, and writes the converted buffer to the temporary file. When all of ORIGINAL.TXT has been written to the temporary file, the application closes both files and renames the temporary file to ALLCAPS.TXT by using the MoveFile function.

HANDLE hFile;

HANDLE hTempFile;

DWORD  dwBytesRead, dwBytesWritten, dwPos;

char szTempName[MAX_PATH];

char buffer[4096];

/* Open the existing file. */

hFile = CreateFile("ORIGINAL.TXT",        /* filename   */

    GENERIC_READ,                 /* open for reading   */

    0,                            /* do not share       */

    (LPSECURITY_ATTRIBUTES) NULL, /* no security        */

    OPEN_EXISTING,                /* existing file only */

    FILE_ATTRIBUTE_NORMAL,        /* normal file        */

    (HANDLE) NULL);               /* no attr. template  */

if (hFile == INVALID_HANDLE_VALUE) {

    ErrorHandler("Could not open file."); /* process err. on fail*/

}

/* Create a temporary file. */

GetTempFileName("\\TEMP", /* dir. for temp. files            */

    "NEW",                /* temp. filename prefix           */

    0,                    /* create unique name w/ sys. time */

    (LPTSTR) szTempName); /* buffer for name                 */

hTempFile = CreateFile((LPTSTR) szTempName,  /* filename     */

    GENERIC_READ | GENERIC_WRITE, /* open for read-write     */

    0,                            /* do not share            */

    (LPSECURITY_ATTRIBUTES) NULL, /* no security             */

    CREATE_ALWAYS,                /* overwrite existing      */

    FILE_ATTRIBUTE_NORMAL,        /* normal file             */

    (HANDLE) NULL);               /* no attr. template       */

if (hTempFile == INVALID_HANDLE_VALUE) {

    ErrorHandler("Could not create temporary file.");

}

/*

 * Read 4K blocks to the buffer.

 * Change all characters in the buffer to uppercase.

 * Write the buffer to the temporary file.

 */

do {

    if (ReadFile(hFile, (LPSTR) buffer, 4096,

        &dwBytesRead, NULL)) {

        CharUpperBuff((LPTSTR) buffer, dwBytesRead);

        WriteFile(hTempFile, (LPSTR) buffer, dwBytesRead,

            &dwBytesWritten, NULL);

    }

} while (dwBytesRead == 4096);

/* Close both files. */

CloseHandle(hFile);

CloseHandle(hTempFile);

/* Move the temporary file to the new text file. */

if (!MoveFile(szTempName, "ALLCAPS.TXT")) {

    ErrorHandler("Could not move temp. file.");

}


Searching for Files and Changing File Attributes

The following example copies all text files in the current directory to a new directory of read-only files named \TEXTRO. Files in the new directory are changed to read only, if necessary.

The application uses the GetCurrentDirectory function to retrieve the current directory path. This function is also used to return to the current directory after changing to the \TEXTRO directory.

The application then creates the \TEXTRO directory by using the CreateDirectory function.

The application searches the current directory for all .TXT files by using the FindFirstFile and FindNextFile functions. Each .TXT file is copied to the \TEXTRO directory. After a file is copied, the GetFileAttributes function determines whether the file is read only. If the file is not read only, the application changes directories to \TEXTRO and converts the copied file to read only by using the SetFileAttributes function.

After all .TXT files in the current directory have been copied, the application closes the search handle by using the FindClose function.

WIN32_FIND_DATA FileData;

HANDLE hSearch;

DWORD dwAttrs;

char szDirPath[] = "c:\\TEXTRO\\";

char szNewPath[MAX_PATH];

char szHome[MAX_PATH];

BOOL fFinished = FALSE;

/* Create a new directory. */

if (!CreateDirectory(szDirPath, NULL)) {

    ErrorHandler("Couldn't create new directory.");

}

/* Start searching for .TXT files in the current directory. */

hSearch = FindFirstFile("*.txt", &FileData);

if (hSearch == INVALID_HANDLE_VALUE) {

    ErrorHandler("No .TXT files found.");

}

/*

 * Copy each .TXT file to the new directory

 * and change it to read only, if not already.

 */

while (!fFinished) {

    lstrcpy(szNewPath, szDirPath);

    lstrcat(szNewPath, FileData.cFileName);

    if (CopyFile(FileData.cFileName, szNewPath, FALSE)) {

        dwAttrs = GetFileAttributes(FileData.cFileName);

        if (!(dwAttrs & FILE_ATTRIBUTE_READONLY)) {

                SetFileAttributes(szNewPath,

                    dwAttrs | FILE_ATTRIBUTE_READONLY);

            }

    }

    else {

        ErrorHandler("Couldn't copy file.");

    }

    if (!FindNextFile(hSearch, &FileData))

        if (GetLastError() == ERROR_NO_MORE_FILES) {

            MessageBox(hwnd, "No more .TXT files.",

                "Search completed.", MB_OK);

            fFinished = TRUE;

        }

        else {

            ErrorHandler("Couldn't find next file.");

        }

}

/* Close the search handle. */

if (!FindClose(hSearch)) {

    ErrorHandler("Couldn't close search handle.");

}


Monitoring Changes in a Directory or Directory Tree

The following example monitors the directory tree starting at C:\ for directory name changes. It also monitors the C:\WINDOWS directory for filename changes.

The example uses the FindFirstChangeNotification function to create two notification handles and the WaitForMultipleObjects function to wait on the handles. Whenever a directory is created or deleted in the tree starting at C:\ , the example updates the entire directory tree. Whenever a file is created or deleted in the C:\WINDOWS directory, the example refreshes the WINDOWS directory. The FindNextChangeNotification function restarts the change notification each time the example processes a change.

DWORD dwWaitStatus;

HANDLE dwChangeHandles[2];

/*

 * Watch the C:\WINDOWS directory for file creation and

 * deletion.

 */

dwChangeHandles[0] = FindFirstChangeNotification(

    "C:\\WINDOWS",                 /* directory to watch       */

    FALSE,                         /* do not watch the subtree */

    FILE_NOTIFY_CHANGE_FILE_NAME); /* watch filename changes   */

if (dwChangeHandles[0] == INVALID_HANDLE_VALUE)

    ExitProcess(GetLastError());

/*

 * Watch the C:\ subtree for directory creation and

 * deletion.

 */

dwChangeHandles[1] = FindFirstChangeNotification(

    "C:\\",                        /* directory to watch      */

    TRUE,                          /* watch the subtree       */

    FILE_NOTIFY_CHANGE_DIR_NAME);  /* watch dir. name changes */

if (dwChangeHandles[1] == INVALID_HANDLE_VALUE)

    ExitProcess(GetLastError());

/*

 * Change notification is set. Now wait on both notification

 * handles and refresh accordingly.

 */

while (TRUE) {

  /* Wait for notification. */

  dwWaitStatus = WaitForMultipleObjects(2, dwChangeHandles,

      FALSE, INFINITE);

  switch (dwWaitStatus) {

    case WAIT_OBJECT_0:

      /*

       * A file was created or deleted in C:\WINDOWS.

       * Refresh this directory and restart the

       * change notification. RefreshDirectory is an

       * application-defined function.

       */

      RefreshDirectory("C:\\WINDOWS")

      if (FindNextChangeNotification(dwChangeHandles[0]) == FALSE)

          ExitProcess(GetLastError());

      break;

    case WAIT_OBJECT_0 + 1:

      /*

       * A directory was created or deleted in C:\.

       * Refresh the directory tree and restart the

       * change notification. RefreshTree is an

       * application-defined function.

       */

      RefreshTree("C:\\");

      if (FindNextChangeNotification(dwChangeHandles[1]) == FALSE)

          ExitProcess(GetLastError());

      break;

       default:

            ExitProcess(GetLastError());

  }

}


Testing for the End of the File

The ReadFile function checks for the end-of-file condition (eof) differently for synchronous and asynchronous read operations. When a synchronous read operation reaches the end of a file, ReadFile returns TRUE and sets the variable pointed to by lpNumberOfBytesRead to zero. An asynchronous read operation can encounter the end of a file during the initiating call to ReadFile or during subsequent asynchronous operation.

The test for end-of-file during a synchronous read operation is simple, as shown in the following example:

// attempt a synchronous read operation
bResult = ReadFile(hFile, &inBuffer, nBytesToRead, &nBytesRead, NULL);
// check for eof
if (bResult &&  nBytesRead == 0, ) {
    // we're at the end of the file
}

The test for end-of-file during an asynchronous read operation is more difficult. There are three end-of-file indicators for asynchronous read operations:

•	ReadFile returns FALSE and GetLastError returns ERROR_HANDLE_EOF.

•	ReadFile returns FALSE and GetLastError returns ERROR_IO_PENDING.

•	GetOverLappedResult returns FALSE and GetLastError returns ERROR_HANDLE_EOF.

The following example shows how to test for an end-of-file during an asynchronous read operation:

// attempt to initiate an asynchronous read operation
bResult = ReadFile(hFile, &inBuffer, nBytesToRead, &nBytesRead, NULL);
// if there was a problem ...
if (!bResult) {
    switch (dwError = GetLastError()) {
    case ERROR_HANDLE_EOF: {
    // we're at the end of the file
    }
    case ERROR_IO_PENDING: {
    // we're at the end of the file
    }
    // other error cases
    }
}
    .
    .
    .
// check on an asynchronous read operation
bResult = GetOverlappedResult(hFile, &gOverlapped, &nBytesRead,
    &gOverlapped) ;
// if there was a problem ...
if (!bResult) {
    switch (dwError = GetLastError()) {
    case ERROR_HANDLE_EOF: {
    // we're at the end of the file
    }
    // other error cases
    }
}


Retrieving a File Pointer

The following example retrieves the current position of the file pointer in the file specified by the hFile value.

HANDLE hFile;

DWORD dwCurrentFilePosition;

dwCurrentFilePosition = SetFilePointer(

    hFile, /* must have GENERIC_READ and/or GENERIC_WRITE    */

    0,     /* do not move pointer                            */

    NULL,  /* hFile is not large enough to need this pointer */

    FILE_CURRENT);  /* provides offset from current position */


File Functions

Following are the functions used with files.

_hread
_hwrite
_lclose
_lcreat
_llseek
_lopen
_lread
_lwrite
AreFileApisANSI
CopyFile
CreateDirectory
CreateDirectoryEx
CreateFile
CreateIoCompletionPort
DefineDosDevice
DeleteFile
FileIOCompletionRoutine
FindClose
FindCloseChangeNotification
FindFirstChangeNotification
FindFirstFile
FindNextChangeNotification
FindNextFile
FlushFileBuffers
GetBinaryType
GetCurrentDirectory
GetDiskFreeSpace
GetDriveType
GetFileAttributes
GetFileInformationByHandle
GetFileSize
GetFileType
GetFullPathName
GetLogicalDrives
GetLogicalDriveStrings
GetQueuedCompletionStatus
GetShortPathName
GetTempDrive
GetTempFileName
GetTempPath
GetVolumeInformation
LockFile
LockFileEx
MoveFile
MoveFileEx
OpenFile
QueryDosDevice
ReadFile
ReadFileEx
RemoveDirectory
SearchPath
SetCurrentDirectory
SetEndOfFile
SetFileApisToANSI
SetFileApisToOEM
SetFileAttributes
SetFilePointer
SetHandleCount
SetVolumeLabel
UnlockFile
UnlockFileEx
WriteFile
WriteFileEx


File Mapping

This Windows 95 overview discusses the file-mapping functions in the Microsoft® Win32® application programming interface (API). These functions allow a process to create file-mapping objects and file views to easily access and share data.


File Mapping Platform Differences

The overviews for file mapping in Windows 95 and Windows NT are substantially different. To accommodate these differences, the Windows 95 overview is first presented in its entirety, followed by the Windows NT version.


About File Mapping

Windows 95 Overview
For more information, see the Windows NT overview About File Mapping.

File mapping is the association of a file's contents to a portion of a process's virtual address space. The operating system creates a file-mapping object to maintain this association. A file view is the portion of virtual address space that is used to access the file's contents. Processes read and write to the file view using pointers just as they would with dynamically allocated memory. Also, the VirtualProtect function operates on file views just like any other virtual memory.

Windows reads data from the file into the file view and writes it back out to the file as needed. In effect, file mapping is a way to tell the system to back a specified part of a process's virtual address space with a specified file or with the system pagefile.

Mapping a file allows a process to access files on disk in the same way as dynamically allocated memory or to share memory between two or more processes. The file-mapping functions in the Microsoft® Win32® application programming interface (API) allow a process to create file-mapping objects and file views to easily access and share data.


Accessing Files Using the CreateFile Function

The first step in mapping a file is to open the file by calling the CreateFile function. The file should be opened with exclusive access to ensure that other processes cannot write to the portion of the file that is mapped. An easy way to obtain exclusive access is to specify zero in the fdwShareMode parameter of CreateFile.

The CreateFileMapping function uses the handle returned by CreateFile to create a file-mapping object. CreateFileMapping enables you to specify an object name, the number of bytes to be mapped from the file, and the read-write access to the mapped memory. CreateFileMapping fails if the access flags conflict with those specified when the file was opened by using CreateFile. For example, to read and write to the file, specify the GENERIC_READ and GENERIC_WRITE values in the fdwAccess parameter of CreateFile and specify the PAGE_READWRITE value in the fdwProtect parameter of CreateFileMapping.

A file mapping can map a file as large as the file system allows. The dwMaximumSizeHigh and dwMaximumSizeLow parameters of CreateFileMapping allow you to specify the number of bytes to be mapped from the file. The size of the file mapping is independent of the size of the file being mapped.

However, if the mapping is larger than the file, the system grows the file before CreateFileMapping returns. If the file mapping is smaller than the file, only the specified number of bytes from the file is mapped.

When you do not want the size of the file to change (for example, when mapping read-only files), call CreateFileMapping and specify zero for both dwMaximumSizeHigh and dwMaximumSizeLow. Doing this creates a file-mapping object exactly the same size as the file. Otherwise, you must calculate or estimate the size of the finished file because file-mapping objects are static in size; once created they cannot grow or shrink.

To actually map the data from the file to memory, you must create a view of the file. The MapViewOfFile and MapViewOfFileEx functions use the file-mapping object handle returned by CreateFileMapping to create a view (or a copy) of the file or a portion of the file in the process's virtual address space. These functions fail if the access flags conflict with those specified when the file-mapping object was created by CreateFileMapping. MapViewOfFileEx works exactly like MapViewOfFile except that it allows a process to specify the base address of the view of the file in the process's virtual address space.

MapViewOfFile returns a pointer to the file view. An application uses this pointer to read and write data to the file mapping in the same way as it would access dynamic memory. By dereferencing a pointer in the range of addresses specified in MapViewOfFile, an application can read and write data to the file. The actual reading and writing to the file on disk is handled by the system. Data is not actually transferred at the time the file-mapping object is written to. Instead, much of the file input and output (I/O) is cached to improve general system performance. Applications may override this behavior by calling the FlushViewOfFile function to force the system to perform disk transactions immediately.

An application may create multiple file views from the same file-mapping object. A file view can be a different size than the file-mapping object from which it is derived, but it must fit within the file-mapping object. The offset specified by the dwOffsetHigh and dwOffsetLow parameters of MapViewOfFile must be a multiple of the allocation granularity of the system. To obtain the system's memory allocation granularity, use the GetSystemInfo function, which fills in the members of a SYSTEM_INFO structure.

When done with the file-mapping object, the process should destroy all file views in its address space by using the UnmapViewOfFile function for each file view. This function invalidates the pointer to the process's virtual address space. If any of the pages of the file view have changed since the view was mapped, the system writes the changed pages of the file "lazily" to disk. To commit the data to disk immediately, call FlushViewOfFile before unmapping the view.

Both the file-mapping object and the file must be closed by calling CloseHandle to first close the file-mapping object and then the file.

After closing a file-mapping object and unmapping all views, if necessary, a process can adjust the size of the file by using the SetFilePointer and SetEndOfFile functions. For example, if the mapping is larger than the desired size of the file, a process can set the file pointer to the desired size of the file.


Sharing Files and Memory

File mapping can be used to share a file or memory between two or more processes. To do so, all of the processes must use the same file-mapping object to create identical views of the file or memory. Each process's view resides in the process's own virtual address space. If one process updates its view, the other process sees the update immediately.

To share a file the first process creates or opens a file by using CreateFile. Next, it creates a file-mapping object by using CreateFileMapping and specifying a name for the file-mapping object. To share memory that is not associated with a file, a process must use the CreateFileMapping function and specify (HANDLE)0xFFFFFFFF instead of an existing file handle. The corresponding file-mapping object accesses memory backed by the system paging file. You must specify a size greater than zero when you specify (HANDLE)0xFFFFFFFF in a call to CreateFileMapping.

The easiest way for other processes to obtain a handle of the file-mapping object created by the first process is to use the OpenFileMapping function and specify the object's name. If the file-mapping object does not have a name, the process must obtain a handle to it through inheritance or duplication. For more information on inheritance and duplication, see Processes and Threads, and Handles and Objects.

Processes that share files or memory must create file views by using the MapViewOfFile or MapViewOfFileEx function just as they would when accessing a file. They must coordinate their access using semaphores, mutexes, events, or some other mutual exclusion technique. For more information on synchronization, see Synchronization.

A shared file-mapping object will not be destroyed until all processes that use it close their handles to it by using CloseHandle and call UnMapViewOfFile on all file views.


Coherence

Coherence guarantees that the data accessible in a file view is an identical copy of the file's contents on disk. Although the CreateFileMapping function works with remote files, it does not keep them coherent. For example, if two computers both map a file as writable, and both change the same page, each computer will see only its own write operations to the page. When the data gets updated on the disk, it is not merged.


Using File Mapping

Windows 95 Overview
For more information, see the Windows NT overview Using File Mapping.

The code samples in this guide illustrate how two processes might access an existing file as named shared memory.

As discussed earlier, the processes must synchronize their access to the memory. For more information on synchronization, see Synchronization.

In the following code, the first process calls CreateFileMapping function to create a file-mapping object. When a corresponding file view is created, the process has read-write access to the memory.

hMapFile = CreateFileMapping(hFile,    // current file handle

    NULL,                              // default security

    PAGE_READWRITE,                    // read-write access

    0,                                 // max. object size

    0,                                 // size of hFile

    "MyFileMappingObject");            // name of map. object

if (hMapFile == NULL) {

    ErrorHandler("Could not create file-mapping object.");

}

The following code uses the file-mapping object handle returned by CreateFileMapping to create a view of the file in the process's address space.

lpMapAddress = MapViewOfFile(hMapFile, // handle to map. object

    FILE_MAP_ALL_ACCESS,               // read-write access

    0,                                 // max. object size

    0,                                 // size of hFile

    0);                                // map entire file

if (lpMapAddress == NULL) {

    ErrorHandler("Could not map view of file.");

}

The MapViewOfFile function returns a pointer to the file view. The process can use the pointer to access the memory for whatever it needs to do.

In the next example, a second process uses the OpenFileMapping function to share the same memory. As in the original process, the MapViewOfFile function returns a pointer to the file view.

hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, // r-w access

    FALSE,                             // do not inherit

    "MyFileMappingObject");            // name of mapping obj.

if (hMapFile == NULL) {

    ErrorHandler("Could not open file-mapping object.");

}

lpMapAddress = MapViewOfFile(hMapFile, // handle to map. obj.

    FILE_MAP_ALL_ACCESS,               // read-write access

    0,                                 // max. object size

    0,                                 // size of hFile

    0);                                // map entire file

if (lpMapAddress == NULL) {

    ErrorHandler("Could not map view of file.");

}

Note that MapViewOfFile may return different addresses in different processes. To specify the location of the file view within a process's address space, use the MapViewOfFileEx function rather than MapViewOfFile.

The following example uses the UnmapViewOfFile function to invalidate the pointer to the mapped memory. This destroys the file view in the process's address space. If any pages of the file view have changed since the file view was mapped, UnmapViewOfFile also copies the changed pages to the file on disk.

if (!UnmapViewOfFile(lpMapAddress)) {

    ErrorHandler("Could not unmap view of file.");

}

When a process is finished using a file mapping and has umapped all views, it must close the file mapping object's handle by calling CloseHandle.

CloseHande(hMapFile);

The FlushViewOfFile function copies the specified number of bytes of the file view to the physical file but does not destroy the file view:

if (!FlushViewOfFile(lpMapAddress, dwBytesToFlush)) {

    ErrorHandler("Could not flush memory to disk.");

}


File Mapping Functions

The following functions are used with file mapping.

CreateFileMapping
FlushViewOfFile
MapViewOfFile
MapViewOfFileEx
OpenFileMapping
UnmapViewOfFile


File Mapping (Windows NT)

This Windows NT™ overview discusses the file-mapping functions in the Microsoft® Win32® application programming interface (API). These functions allow a process to create file-mapping objects and file views to easily access and share data.


About File Mapping

Windows NT Overview
For more information, see the Windows 95 overview About File Mapping.

File mapping is the copying of a file's contents to a process's virtual address space. The copy of the file's contents is called the file view, and the internal structure the operating system uses to maintain the copy is called the file-mapping object.

Another process can create an identical file view in its own virtual address space by using the first process's file-mapping object to create the view. This enables the processes to share data. Any process that has the name or a handle of a file-mapping object can create a file view.

Microsoft® Windows NT™ file-mapping functions create file-mapping objects and file views necessary for this method of data sharing.


Sharing a File

If two (or more) processes need to share a file, one process should open the file for exclusive access by using the CreateFile function. The CreateFileMapping function uses the handle returned by CreateFile to create a file-mapping object. Processes that have the name or a handle of the file-mapping object can share the file's data. The file handle should remain open until the processes are no longer sharing the file; this prevents nonsharing processes from reading from or writing to the file.

CreateFileMapping enables you to specify an object name, the number of bytes to be mapped from the file, and the read-and-write access to the mapped memory. CreateFileMapping fails if the access flags conflict with those specified when the file was opened by using CreateFile. CreateFileMapping returns a handle of the file-mapping object. This handle is used to create a "view of the file," or "file view," in the process's virtual address space. A file view is a copy of the entire file or a portion of the file, depending on the number of bytes requested.

The process that created the file-mapping object uses the MapViewOfFile function with the file-mapping object handle to create a file view, or copy of the file, in the process's virtual address space. MapViewOfFile returns a pointer to the file view. This function fails if the access flags conflict with those specified when the mapping object was created with CreateFileMapping.

To share the data in the file view, another process must create an identical file view in its own virtual address space. To do this, the process must first obtain a handle of the same file-mapping object and then create its own file view by using MapViewOfFile. The easiest way to obtain a handle of the file-mapping object is to use the OpenFileMapping function and specify the object's name. If the file-mapping object does not have a name, the process must obtain a handle of it through inheritance or duplication. For more information on inheritance and duplication, see Processes and Threads and Handles and Objects.

MapViewOfFile returns a pointer to the file view. To ensure that multiple processes are sharing the same data through their own pointers, all views of a file must be derived from the same file-mapping object. If this is the case, the file views are said to be coherent, or identical. Typically, file views are not coherent if they are derived from different file-mapping objects, even if the mapping objects refer to the same file.

Because the file view is basically a block of memory and not a file, processes read from and write to the file view by using pointers just as though the block were dynamically allocated. You do not need to use the ReadProcessMemory and WriteProcessMemory functions.

If one or more of the processes has write access to the shared data, processes must synchronize their access to the shared data by using a semaphore. This ensures that the file views remain coherent in all processes. For more information on synchronization, see Synchronization.

Some applications require that a file be mapped to the same address in multiple processes. To place the file view at a specific location within the process's address space, you should use the MapViewOfFileEx function and specify the desired address. If there is not enough space at the specified address, the function fails.

Although CreateFileMapping works with remote files, it does not keep them coherent. For example, if two machines both map a file as writable, and both change the same page, each machine will only see its own writes to the page. When the data gets updated on the disk, it is not merged.


Sharing a Memory Block

If two (or more) processes need to share a memory block not associated with a file, one process must use the CreateFileMapping function and specify (HANDLE)0xFFFFFFFF instead of an existing file handle. The corresponding file-mapping object accesses memory from the operating-system paging file. Processes sharing the operating-system paging file must create file views by using the MapViewOfFile or MapViewOfFileEx function just as when sharing a named file.


Closing a File View

When a process has finished using the shared memory, it should destroy the file view in its address space by using the UnmapViewOfFile function. This invalidates the pointer to the shared memory. If any of the pages of the file view changed since the view was mapped, this function copies the changed pages to the physical file.

To copy a specified number of bytes from the file view to the physical file, you should use the FlushViewOfFile function. FlushViewOfFile does not destroy the file view.

For information on other ways to share data among applications, see Dynamic Data Exchange Management Library.


Using File Mapping

Windows NT Overview
For more information, see the Windows 95 overview Using File Mapping.

The code samples in this guide illustrate how two processes might access an existing file as named shared memory.

If one or both processes write to the shared memory, the processes must use a semaphore to synchronize their access to the memory. For more information on synchronization, see Synchronization.

In the following code, the CreateFileMapping function creates a file-mapping object. When a corresponding file view is created, the process has read-and-write access to the memory.

hMapFile = CreateFileMapping(hFile,    /* current file handle */

    (LPSECURITY_ATTRIBUTES) NULL,      /* no security         */

    PAGE_READWRITE,                    /* read-write access   */

    0,                                 /* max. object size is */

    0,                                 /*   size of hFile     */

    "MyFileMappingObject");            /* name of map. object */

if (hMapFile == NULL) {

    ErrorHandler("Could not create file-mapping object.");

}

The following code uses the file-mapping object handle returned by CreateFileMapping to create a view of the file in the process's address space.

lpMapAddress = MapViewOfFile(hMapFile, /* handle to map. object */

    FILE_MAP_ALL_ACCESS,               /* read-write access     */

    0,                                 /* max. object size is   */

    0,                                 /*   size of hFile       */

    0);                                /* map entire file       */

if (lpMapAddress == NULL) {

    ErrorHandler("Could not map view of file.");

}

The MapViewOfFile function returns a pointer to the file view. The process can use the pointer to access the memory for whatever it needs to do.

In the next example, a second process uses the OpenFileMapping function to share the same memory. As in the original process, the MapViewOfFile function returns a pointer to the file view.

hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, /* r-w access  */

    FALSE,                             /* do not inherit       */

    "MyFileMappingObject");            /* name of mapping obj. */

if (hMapFile == NULL) {

    ErrorHandler("Could not open file-mapping object.");

}

lpMapAddress = MapViewOfFile(hMapFile, /* hndl. to map. obj.   */

    FILE_MAP_ALL_ACCESS,               /* read-write access   */

    0,                                 /* max. object size is */

    0,                                 /*   size of hFile     */

    0);                                /* map entire file     */

if (lpMapAddress == NULL) {

    ErrorHandler("Could not map view of file.");

}

Note that MapViewOfFile returns different addresses in different processes. To specify the location of the file view within a process's address space, use the MapViewOfFileEx function, rather than MapViewOfFile.

The following example uses the UnmapViewOfFile function to invalidate the pointer to the mapped memory. This destroys the file view in the process's address space. If any pages of the file view changed since the view was mapped, UnmapViewOfFile also copies the changed pages to the physical file.

if (!UnmapViewOfFile(lpMapAddress)) {

    ErrorHandler("Could not unmap view of file.");

}

The FlushViewOfFile function copies the specified number of bytes of the file view to the physical file but does not destroy the file view:

if (!FlushViewOfFile(lpMapAddress, dwBytesToFlush)) {

    ErrorHandler("Could not flush memory to disk.");

}


File Mapping Functions

The following functions are used with file mapping.

CreateFileMapping
FlushViewOfFile
MapViewOfFile
MapViewOfFileEx
OpenFileMapping
UnmapViewOfFile


File Systems

Applications based on the Microsoft® Win32® application programming interface (API) rely on file systems to store and retrieve information on mass storage devices. File systems provide the underlying support that applications need to create and access files and directories on the individual volumes associated with the devices.


About File Systems

Depending on the configuration of a computer, a Win32-based application may have access to volumes managed by any of the following file systems:

•	New Technology file system (NTFS)

•	File allocation table (FAT) file system

•	Protected-mode FAT file system

•	High-performance file system (HPFS)

For example, applications that connect to network drives may encounter file systems that range from FAT to NTFS. Because different volumes may be managed by different file systems, it is important to understand the differences between file systems and to prepare applications to work effectively with all available file systems. The following sections describe these differences and present guidelines for handling them within applications.


Guidelines

Each file system consists of one or more drivers and supporting dynamic-link libraries that define the data formats and features of the file system. These determine the conventions used for filenames, the level of security and recoverability available, and the general performance of input and output (I/O) operations. Before you access files and directories on a given volume, you should determine the capabilities of the file system by using the GetVolumeInformation function. The function returns values, such as the maximum length of filenames, that you can use to adapt your application to work effectively with the file system.

In general, you should always avoid using static buffers for filenames and paths. Instead, use the values returned by GetVolumeInformation to allocate buffers as you need them. If you must use static buffers, reserve 256 characters for filenames and 260 characters for paths. These are the maximums currently recommended for Win32-based applications.


The New Technology File System

The New Technology file system (NTFS) organizes data on fixed disks. This file system supports object-oriented applications by treating all files as objects with user- and system-defined attributes. NTFS provides all the capabilities of the FAT and HPFS file systems without many of their limitations. Accessing files under NTFS is often faster than accessing similar files under the FAT or HPFS file systems.

NTFS is a fully recoverable file system. It is designed to restore consistency to a disk after a CPU failure, system crash, or I/O error. NTFS allows the operating system to recover without your having to use disk-checking utilities. However, NTFS provides these utilities in case recovery fails or corruption occurs outside the control of the file system. NTFS also includes features not present in HPFS or FAT, such as security, Unicode filenames, automatic creation of MS-DOS® aliases, multiple data streams, and unique functionality specific to the POSIX subsystem. For more information about security, see Security.

NTFS follows the filename conventions described in the HPFS section, but it also supports Unicode filenames.

NTFS cannot manipulate a file's extended attributes if the file was created on HPFS.


The File Allocation Table File System

The FAT file system organizes data on fixed disks and floppy disks. The distinguishing feature of the FAT file system is its filename convention. The filename convention consists of a filename (up to eight characters), a separating period (.), and a filename extension (up to three characters).

The main advantage of FAT volumes is that they are accessible by MS-DOS, Microsoft® Windows®, and OS/2 systems. FAT is also the only file system currently supported on floppy disks and other removable media.

Valid FAT filenames have the following form:

[[drive:]][[directory\]]filename[[.extension]]

The drive parameter must name an existing drive and can be any letter from A through Z. The drive letter must be followed by a colon (:).

The directory parameter specifies the directory that contains the file's directory entry. This value must be followed by a backslash (\) to separate it from the filename. If the specified directory is not in the current directory, directory must include the names of all directories in the file's path, separated by backslashes. The root directory is specified by using a backslash at the beginning of the name. For example, if the directory ABCD is in the directory SAMPLE and SAMPLE is in the root directory, the correct directory specification is \SAMPLE\ABCD. A directory name consists of any combination of up to eight letters, digits, or the following special characters:

$ % ' − _ @ { } ~ ` ! # ( )

A directory name can also have an extension that is any combination of up to three letters, digits, or special characters, preceded by a period (.).

The filename and extension parameters specify the file. Filename can be any combination of up to eight letters, digits, or the special characters previously listed; extension can be any combination of up to three letters, digits, or special characters, all preceded by a period. Filename can also include embedded (preceded and followed by one or more letters, digits, or special characters just noted) spaces. For example, the string "disk 1" is a legal value for filename.

FAT volumes do not distinguish between uppercase and lowercase letters.


The Protected-Mode FAT File System

The protected-mode FAT file system organizes data on fixed and floppy disks. Protected-mode FAT is compatible with the FAT file system, using file allocation tables and directory entries to store information about the contents of a disk. Protected-mode FAT also supports long filenames, storing these names and other information such as the date and time the file was last accessed in the FAT structures.

Protected-mode FAT allows filenames of up to 255 characters, including the terminating null character. This is similar to the New Technology file system (NTFS) which allows filenames of up to 256 characters.

Protected-mode FAT allows paths of up to 260 characters, including the terminating null character.


The High-Performance File System

HPFS organizes data on fixed disks. Filenames under HPFS can be any practical length (up to 254 characters) and can contain characters that are not valid for the FAT file system, such as spaces and periods. In many cases, accessing files under HPFS is faster than accessing similar files under the FAT file system.

Blank spaces can be used anywhere in an HPFS filename or directory name, but blank spaces and periods at the end of a filename are ignored. There is no requirement that HPFS filenames have extensions; however, many applications still create and use them.

The following special characters can also be used in HPFS filenames:

, + = [ ] ; _

An HPFS filename can be all uppercase, all lowercase, or mixed case. The case is preserved for directory listings but is ignored in file searches and all other system operations. Therefore, in a given directory, there cannot be more than one file with the same name when the only difference is case.


Handles and Objects

An object is an internal structure that represents a system resource, such as a file, a thread, or a graphic image. An application cannot directly access the internal structure of an object or the system resource that an object represents. Instead, an application must obtain an object handle and use this handle to examine or modify the system resource (or both). In the Microsoft® Win32® application programming interface (API), handles are usually implemented as indirect pointers, but this is not always the case.


About Handles and Objects

Windows uses objects and handles to regulate access to system resources for two main reasons. First, the use of objects ensures that developers are not writing code specifically to low-level, internal structures. This enables Microsoft to add or change functionality of the operating system, as long as the original calling conventions are maintained. When subsequent versions of the operating system are released, applications will gain this new functionality with little or no additional development.

Second, the use of objects enables developers to take advantage of Win32 security. Each object has its own access-control list (ACL) that specifies the types of actions processes can perform on the object. The operating system examines an object's ACL each time an application attempts to create a handle to the object. For more information about security, see Security.

For most objects, the Win32 API provides functions that create the object, create an object handle, close the object handle, and destroy the object. These tasks may be combined or unnecessary, depending on the type of object and the situation. For example, an application could create an event object. Other applications could open the event and each would have a unique handle to the same event object. In this scenario, as the applications finish using the object, each closes its handle. When there are no open handles to the event object, the operating system removes the object from memory.

In contrast, an application could obtain the existing window-object handle. In this instance, when the window object is no longer needed, the application must remove the object from memory, which invalidates the window handle.

When a process terminates, the system automatically closes handles and deletes objects created by the process. However, when a thread terminates, the system usually does not close handles or delete objects. The only exceptions are window, hook, window position, and dynamic data exchange (DDE) conversation objects that are deleted when the creating thread terminates.

Handles and objects consume memory. Therefore, to preserve system performance, an application should close handles and delete objects as soon as they are no longer needed. Applications that do not do this can slow the operating system, due to excessive use of the paging file.

Windows provides three categories of objects: user, graphics device interface (GDI), and kernel, as shown in the following tables. The system uses user objects to support window management, GDI objects to support graphics, and kernel objects to support memory management, process execution, and interprocess communications (IPC). For information about creating and using a specific object, refer to the associated overview.

Windows User Objects

User object	Overview
Accelerator table	Keyboard Accelerators
Caret	Carets
Cursor	Cursors
Dynamic data exchange conversation	Dynamic Data Exchange Management Library
Desktop	Security
Hook	Hooks
Icon	Icons
Menu	Menus (Windows NT)
Window	Windows
Window position	Windows
Window station	Windows
Windows GDI Objects

GDI object	Overview
Bitmap	Bitmaps
Brush	Brushes
Font	Fonts and Text
Palette	Colors
Pen	Pens
Extended pen	Pens
Region	Regions
Device context	Device Contexts
Memory device context	Device Contexts
Metafile	Metafiles
Metafile device context	Metafiles
Enhanced metafile	Metafiles
Enhanced-metafile device context	Metafiles
Windows Kernel Objects

Kernel object	Overview
Process	Processes and Threads
Thread	Processes and Threads
File	Files
File mapping	File Mapping
Event	Synchronization
Semaphore	Synchronization
Mutex	Synchronization
Pipe (named and anonymous)	Pipes
Mailslot	Mailslots
Communications device	Communications
Heap	Memory Management
Module	Dynamic-Link Libraries
Update resource	Resources
Find file	Files
Event log	Event Logging
Change notification	Files
Token	Security
Service object	Printing and Print Spooler
LZ file	Data Decompression Library


Handle Limitations

Some objects, such as user and GDI objects, support only one handle at a time. The system provides the handle when an application creates the object and invalidates the handle when the application destroys the object. Other objects, such as some kernel objects, support multiple handles to a single object. The operating system automatically removes the object from memory after the last handle to the object is closed.

The total number of open handles in the operating system is limited only by the amount of memory available to the operating system. However, a single process may have no more than 16,384 open GDI object handles. The per-process limit on kernel handles is 2^30. There is no per-process limit on user handles, but there is a systemwide limit of 65,536.


User and Graphics Device Interface Objects

User and GDI objects support only one handle per object. Processes cannot inherit or duplicate handles to user or GDI objects.

Handles to user objects are public to all processes. That is, any process can use the user object handle, provided that the process has access to the object as defined by user security. For more information about security, see Security.

Handles to GDI objects are private to a process. That is, only the process that created the GDI object can use the object handle.

In the following illustration, an application creates a window object. The CreateWindow function creates the window object and returns an object handle.

After the window object has been created, the application can use the window handle to display or change the window. The handle remains valid until the window object is destroyed.

In the next illustration, the application destroys the window object. The DestroyWindow function removes the window object from memory, which invalidates the window handle.

The following table lists the Windows user objects and each object's creator and destructor functions. The creator functions either create the object and an object handle or simply return the existing object handle. The destructor functions remove the object from memory, which invalidates the object handle.

Note that the window station and desktop objects are created and maintained by the system; applications cannot delete these objects.

User Objects

Object	Creator function	Destructor function
Accelerator table	CreateAcceleratorTable	DestroyAcceleratorTable
Cursor	CreateCursor, LoadCursor, GetCursor, SetCursor	DestroyCursor
DDE conversation	DdeConnect, DdeConnectList, DdeQueryNextServer, DdeReconnect	DdeDisconnect, DdeDisconnectList
Desktop	GetThreadDesktop	−
Hook	SetWindowsHook, SetWindowsHookEx	UnhookWindowsHook, UnhookWindowsHookEx
Menu	CreateMenu, CreatePopupMenu, GetMenu, GetSubMenu, GetSystemMenu, LoadMenu, LoadMenuIndirect	DestroyMenu
Window	CreateWindow, CreateWindowEx, CreateDialogParam, CreateDialogIndirectParam, CreateMDIWindow, FindWindow, GetWindow, GetClipboardOwner, GetDesktopWindow, GetDlgItem, GetForegroundWindow, GetLastActivePopup, GetOpenClipboardWindow, GetTopWindow, WindowFromDC, WindowFromPoint, and others	DestroyWindow
Window position	BeginDeferWindowPos	EndDeferWindowPos
Window station	GetProcessWindowStation	−
The following table lists the Windows GDI objects and each object's creator and destructor functions. The creator functions either create the object and an object handle or simply return the existing object handle. The destructor functions remove the object from memory, which invalidates the object handle.

GDI Objects

Object	Creator function	Destructor function
Bitmap	CreateBitmap, CreateBitmapIndirect, CreateCompatibleBitmap, CreateDIBitmap, CreateDIBSection, CreateDiscardableBitmap	DeleteObject
Brush	CreateBrushIndirect, CreateDIBPatternBrush, CreateDIBPatternBrushPt, CreateHatchBrush, CreatePatternBrush, CreateSolidBrush	DeleteObject
Font	CreateFont, CreateFontIndirect	DeleteObject
Palette	CreatePalette	DeleteObject
Pen	CreatePen, CreatePenIndirect	DeleteObject
Extended pen	ExtCreatePen	DeleteObject
Region	CombineRgn, CreateEllipticRgn, CreateEllipticRgnIndirect, CreatePolygonRgn, CreatePolyPolygonRgn, CreateRectRgn, CreateRectRgnIndirect, CreateRoundRectRgn, ExtCreateRegion, PathToRegion	DeleteObject
Device context (DC)	CreateDC, GetDC	DeleteDC, ReleaseDC
Memory DC	CreateCompatibleDC	DeleteDC
Metafile	CloseMetaFile, CopyMetaFile, GetMetaFile, SetMetaFileBitsEx	DeleteMetaFile
Metafile DC	CreateMetafile	CloseMetaFile
Enhanced metafile	CloseEnhMetaFile, CopyEnhMetaFile, GetEnhMetaFile, SetEnhMetaFileBits	DeleteEnhMetaFile
Enhanced-metafile DC	CreateEnhMetaFile	CloseEnhMetaFile


Kernel Objects

Kernel object handles are process specific. That is, a process must either create a kernel object or open an existing object to obtain an object handle. Any process can create a new handle to an existing kernel object (even one created by another process), provided that the process knows the name of the object and has access to the object as defined by user security. For more information about security, see Security.

Processes can inherit or duplicate handles to the following types of kernel objects:

•	Processes

•	Threads

•	Files (including file-mapping objects)

•	Events

•	Semaphores

•	Mutexes

•	Pipes (named and anonymous)

•	Mailslots

•	Communications devices

All other kernel objects are private to the process that created them; object handles cannot be duplicated or inherited.

A child process inherits an open handle from its parent process if inheritance was specified when the original handle was created and if the child process was created with the "inherit handles" flag set. An inherited handle is valid only in the context of the child process.

The DuplicateHandle function duplicates a handle into the current process or into another process. If an application duplicates one of its handles into another process, the duplicated handle is valid only in the context of the other process.

A duplicated or inherited handle is a unique value, but it refers to the same object as the original handle.

Kernel object handles include access rights that indicate the actions the application wants to perform on the object. An application specifies access rights when it creates an object or obtains an existing object handle. Each type of kernel object supports its own set of access rights. For example, event handles can have "set" or "wait" access (or both), file handles can have "read" or "write" access (or both), and so on. For more information about access rights, see Security, and topics that describe individual objects.

In the following illustration, an application creates an event object. The CreateEvent function creates the event object and returns an object handle.

After the event object has been created, the application can use the event handle to set or wait on the event. The handle remains valid until the application closes the handle or terminates.

Most kernel objects support multiple handles to a single object. For example, the application in the preceding illustration could obtain additional event object handles by using the OpenEvent function, as shown in the following illustration.

This method enables an application to have handles with different access rights. For example, Handle 1 might have "set" and "wait" access to the event, and Handle 2 might have only "wait" access.

If another process knows the event name and has security access to the object, it can create its own event object handle by using OpenEvent, as shown in the following illustration.

The original application could also duplicate one of its handles into the same process or into another process by using the DuplicateHandle function, as shown in the following illustration.

The following illustration shows how a child process inherits a handle created by its parent process.

A child process of an application automatically inherits handles created by its parent process if inheritance was specified when the handles were created and if the child process was created with the "inherit handles" flag set. Note that in the preceding illustration, Handle 2 is not equivalent to Handle 1 but does refer to the same event object.

For more information about inheritance, see Processes and Threads and Files

An object remains in memory as long as at least one object handle exists. In the following illustration, the applications use the CloseHandle function to close their event object handles. When there are no event handles, the system removes the object from memory, as shown in the following illustration.

Occasionally, an object remains in memory after all object handles have been closed. For example, a thread could create an event object and wait on the event handle. While the thread is waiting, another thread could close the same event object handle. The event object remains in memory, without any event object handles, until the event object is set to the signaled state and the wait operation is completed. At this time, the system removes the object from memory.

Windows manages file objects somewhat differently from other kernel objects. File objects contain the file pointer — the pointer to the next byte to be read or written in a file. Whenever an application creates a new file handle, the system creates a new file object. Therefore, more than one file object can refer to a single file on disk, as shown in the next illustration.

Only through duplication or inheritance can more than one file handle refer to the same file object, as shown in the following illustration.

The following table lists each of the Windows kernel objects and each object's creator and destructor functions. The creator functions either create the object and an object handle or create a new existing object handle. The destructor functions close the object handle. When an application closes the last handle to a kernel object, the system removes the object from memory.

Kernel Objects

Object	Creator function	Destructor function
Process	CreateProcess, OpenProcess, GetCurrentProcess	CloseHandle, TerminateProcess
Thread	CreateThread, CreateRemoteThread, GetCurrentThread	CloseHandle, TerminateThread
File	CreateFile	CloseHandle, DeleteFile
File mapping	CreateFileMapping, OpenFileMapping	CloseHandle
Event	CreateEvent, OpenEvent	CloseHandle
Semaphore	CreateSemaphore, OpenSemaphore	CloseHandle
Mutex	CreateMutex, OpenMutex	CloseHandle
Pipe	CreatePipe	CloseHandle
Named pipe	CreateNamedPipe	CloseHandle, DisconnectNamedPipe
Mailslot	CreateMailslot	CloseHandle
Communications device	GetStdHandle	CloseHandle
Heap	HeapCreate	HeapDestroy
Module	LoadLibrary, GetModuleHandle	FreeLibrary
Update resource	BeginUpdateResource	EndUpdateResource
Find file	FindFirstFile	FindClose
Event log	OpenEventLog, RegisterEventSource, OpenBackupEventLog	CloseEventLog
Change notification	FindFirstChangeNotification	FindCloseChangeNotification


Handles and Objects Functions

CloseHandle
DuplicateHandle
GetHandleInformation
SetHandleInformation


,


Help

Online help can come in a variety of forms, from detailed conceptual information to quick definitions. This overview discusses elements of the Win32 application programming interface (API) that support online help.


About Help

An important element of a user-friendly application is readily available online help. Microsoft® Windows® provides functions and messages that when used in conjunction with the Windows Help application make it easy to implement online help in your application. This overview discusses elements of the Win32 application programming interface (API) that support online help. It describes how to use these elements to give users a means to request help and explains how to use the Windows Help application to display help.


Help Requests

Most Windows-based applications provide online help information in a variety of forms, ranging from conceptual help that explains the purpose of an application's features to pop-up help that provides quick definitions of individual elements in the application's user interface. You use Win32 functions and messages to give users a variety of ways to request access to this information. The following sections describe these help requests.


Help Menu

Most applications provide user access to help information by including a Help menu in the main window. When the user selects an item from a Help menu, the corresponding window procedure receives a WM_COMMAND message that identifies the selected item. The application responds by displaying the appropriate help information, such as a list of help topics, an index, or an introduction to the application.


Help from the Keyboard

Windows provides user access to help information from the keyboard by notifying the application whenever the user presses the F1 key. The system sends WM_HELP to the window that has the keyboard focus when the user presses the F1 key. If the window is child window (for example, a control in a dialog box), the DefWindowProc function passes the message to the parent window. If a menu is active when F1 is pressed, the system sends the message to the window associated with the menu. The application responds by displaying help information associated with the window, control, or menu that has the focus or is active. For example, if the user selects a control in a dialog box and presses F1, the application displays help information for that control.

The lParam parameter of WM_HELP is a pointer to a HELPINFO structure that contains detailed information about the item for which help is requested. You use this information to determine the help topic to display. The HELPINFO structure also includes the coordinates of the mouse cursor at the time the user pressed the F1 key. You can use this information to provide help based on the location of the mouse cursor.


Help from the Mouse

Windows provides user access to help information from the mouse by notifying the application whenever the user clicks the right mouse button or clicks a window, control, or menu after clicking the Question (?) button. The application responds by displaying help information associated with the given window, control, or menu.

The system sends a WM_CONTEXTMENU message when the user clicks the right mouse button. The window that was clicked receives the message. If the window is a child window, such as a control, the DefWindowProc function passes the message to the parent window. The WM_CONTEXTMENU message specifies the coordinates of the mouse cursor. The x-coordinate is in the low-order word of the lParam parameter, and the y-coordinate is in the high-order word. If the user clicked a control, the wParam parameter is the handle of the control that received the button click.

The system sends a WM_HELP message when the user clicks an item in a window after clicking the Question (?) button that appears in the title bar of the window. You can add a Question button to a title bar by specifying the WS_EX_CONTEXTHELP style in the CreateWindowEx function when creating the window. The lParam parameter of WM_HELP is a pointer to a HELPINFO structure that contains detailed information about the item for which help is requested, including the coordinates of the mouse cursor at the time the user clicked the mouse button.

The Question button is recommended for use in dialog boxes only. In the past, applications have provided user access to help information about a dialog box by providing a Help button in the dialog box. This method is no longer recommended. Use the Question button instead.


Help Display and Windows Help

Once an application receives a request for help, it should display the appropriate help information. Because the Windows Help application supports a variety of ways to display help and a user interface that is consistent with that used by Windows to display its own help information, it is recommended that applications use Windows Help rather than other ways to display help. To direct Windows Help to display help information, an application uses the WinHelp function, specifying details such as the information to display and the form of the window in which to display it. The following sections explain how to use WinHelp to display help information.


Help Files

To view help information, you must specify a help file when calling the WinHelp function. The help file must have the Windows Help (.HLP) file format and have one or more topics. Each topic is a distinct unit of information, such as a conceptual description, a set of instructions, a picture, a glossary definition, and so on. Topics must be uniquely identified so that Windows Help can locate the topic whenever it is requested. Internally, Windows Help uses topic identifiers to locate topics, but applications most often use context identifiers (unique integer values) to specify topics to display. The help file author must explicitly map context identifiers to topic identifiers in the [MAP] section of the project file used to build the help file.

When you specify a help file but you do not specify a path, WinHelp looks for the help file in the Help directory or in a directory specified by the PATH environment variable. In addition, WinHelp can find a help file whose name is listed in the following registry location:

HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\Help

To take advantage of the registry, you must create a value name that has the same name as your help file. The value assigned to that name must be the directory where the help file resides.

If WinHelp cannot find the given help file, it displays a dialog box that allows the user to specify the location of the help file. Because WinHelp saves the location information in the registry, WinHelp does not ask again for the location of the same help file.

For more information about how to author and build a help file, see the documentation provided with your development tools.


Starting Windows Help

The following example uses the WinHelp function to start the Windows Help application and open the Windows NT Help file to its Contents topic.

HWND hwnd;     // main window handle

BOOL bResult   // for checking boolean function result

bResult = WinHelp(hWnd, "WINNT.HLP", HELP_CONTENTS, 0L);

This next example opens the Windows NT user Help file, searches the file for the topic associated with a keyword string, and then displays the topic.

HWND hwnd;     // main window handle

BOOL bResult   // for checking boolean function result

bResult = WinHelp(hWnd, "WINNT.HLP", HELP_KEY,

                  (DWORD) "finding topics");


Help Topics Dialog Box

You can display the Help Topics dialog box by calling the WinHelp function with the HELP_FINDER command. The Help Topics dialog box lets the user select topics to display by viewing the titles of the topics, the keywords associated with the topics, or the words and phrases found in the topics. Applications typically display the Help Topics dialog box when the user chooses a command, such as Help Topics, from the Help menu. An application may also display this dialog box if the user presses the F1 key when no specific window, control, or menu in the application has the focus or is active.

In the past, applications have used the HELP_CONTENTS and HELP_INDEX commands with the WinHelp function to display the Contents topic and the keyword index of the help file. These commands are no longer recommended. Use the HELP_FINDER command instead.


Information Topics

You can display a specific topic by calling the WinHelp function with the HELP_CONTEXT command and specifying the context identifier for the topic. Applications typically use the HELP_CONTEXT command in response to user requests for topics containing conceptual information or procedural help rather than information about a specific control or menu. In such cases, the user may continue to browse the help file looking for related information before returning to the application.

The HELP_CONTEXT command invokes a regular instance of Windows Help, enabling the user to access other topics in the help file. It typically displays the main help window, which includes a title bar, system menu, minimize and maximize buttons, main menu, optional navigation bar, sizing border, and a client area. The text of the selected topic appears in the client area, and the user can navigate through the help file by using hot links or navigation buttons in the main window. The regular instance of Windows Help can also be used to display help in one or more secondary windows instead of the main window.


Pop-up Topics

You can display a pop-up topic that contains information for a specific control or menu by calling the WinHelp function with the HELP_WM_HELP or HELP_CONTEXTMENU command. These commands display a topic in a pop-up window near the corresponding control or menu. To let the user return immediately to work in the application, the pop-up window is destroyed as soon as the user presses a key or clicks the left mouse button.

You use the HELP_WM_HELP command when processing WM_HELP messages for control windows. Because most controls pass the WM_HELP message to the DefWindowProc function, the corresponding dialog box procedure (or parent window procedure) processes this message. Rather than give a specific context identifier, the dialog box procedure must pass an array of control and context identifier pairs to WinHelp along with the control handle specified in the hItemHandle member of HELPINFO structure passed with the WM_HELP message. The function determines the identifier of the control for which the WM_HELP message was generated and uses the matching context identifier to display the appropriate topic.

You use the HELP_CONTEXTMENU command when processing WM_CONTEXTMENU messages. Because most controls pass the WM_CONTEXTMENU message to the DefWindowProc function, the corresponding dialog box procedure (or parent window procedure) processes this message. Again, the procedure specify an array of control and context identifier pairs and the handle in wParam when calling WinHelp so that the function can pick the appropriate context identifier from the array and display the appropriate topic. Unlike the HELP_WM_HELP command, HELP_CONTEXTMENU first displays a What's This? command in a menu. If the user chooses the command, WinHelp displays the topic. Otherwise, the request is canceled.

You can also display pop-up topics by using the HELP_CONTEXTPOPUP command and specifying a context identifier of the topic. This command is similar to the HELP_CONTEXT command but invokes the pop-up instance of Windows Help used by HELP_WM_HELP and HELP_CONTEXTMENU. Applications can use this command in response to WM_HELP messages to display help for menus and for windows that are not controls in a dialog box. To use this command most effectively, the application should assign context identifiers to these menus and windows.

You can assign a context identifier to any window or menu in the application. When the user's help requests generates a WM_HELP message, the system includes the context identifier in the HELPINFO structure that it passes to the parent window along with the WM_HELP message. The parent window can then pass the context identifier to WinHelp to display the requested help topic.

You use the SetWindowContextHelpId function to assign a context identifier to a window or control and the SetMenuContextHelpId function to assign a context identifier to a menu. You can retrieve the context identifier for a window or menu by using the GetWindowContextHelpId or GetMenuContextHelpId function.


Keyword Searches

You can enable the user to find and view topics by assigning keywords to topics in the help file. A keyword is simply a string that is associated with one or more topics. Windows Help collects all keywords in a help file, places them in a table, and displays them in the Index list of the Help Topics dialog box. When the user selects a keyword, Windows Help displays the associated help topic or displays a list of topics from which the user can choose if there is more than one topic associated with the keyword.

In an application, you can use the HELP_KEY, HELP_PARTIALKEY, or HELP_MULTIKEY command with WinHelp to search for and display help topics based on whole or partial keywords. You specify the command, the keyword string, the help file, and the handle of the owner window. In all cases, if a single match is found, WinHelp displays the corresponding topic. If more than one match is found, the function displays the Topics Found dialog, letting the user choose which topic to view. If no match is found, WinHelp either displays the Index list (for HELP_KEY and HELP_PARTIALKEY) or displays an error message (for HELP_MULTIKEY).

You can search for multiple keywords in a single call to WinHelp by separating each keyword from the preceeding one with a semicolon (;). (Searching for multiple keywords is not supported for help files created for version 3.x.) You can also search for a keywords across multiple help files if the help file that you specify has a contents (.CNT) file that contains :Index or :Link commands. With the HELP_KEY command, WinHelp searches for keywords in all files specified by these commands. With the HELP_MULTIKEY and HELP_PARTIALKEY commands, the function searches all files except those specified by :Link commands.

By default, Windows Help recognizes only the keyword table identified by the K footnote character in the help source file. You can direct Windows Help to create additional keyword tables by specifying a footnote character other than K with the keyword definitions in the Windows Help file. (The footnote character A, however, is reserved.) You must define any additional keyword tables by using MULTIKEY statements in the [OPTIONS] section of the project file when building the help file.

An application can use the HELP_SETINDEX command with the WinHelp function to direct Windows Help to display a keyword table other than K in its Index list. To direct Windows Help to search for a keyword in an alternate keyword table, an application can use the HELP_MULTIKEY command. You specify the keyword and keyword table in a MULTIKEYHELP structure, which you pass to WinHelp.

When WinHelp displays a topic, it displays it in the window specified by the > footnote for the topic, or in the window specified by the :Base command in the contents file, or in the main window. If the main window is already open to a different help file when you call WinHelp, the function hides main window while searching. In this case, canceling both the Topics Found and Help Topics dialogs, close the main window.


Secondary Help Windows

The main window of the Windows Help application is called the primary window. Windows Help can also display help topics in a secondary window. Unlike the main help window, a secondary window does not contain a menu bar. You can include a navigation bar in a secondary window, and you can add buttons to the bar. You can also choose to have Windows Help automatically adjust the height of secondary window to accommodate the topic.

You must define secondary windows in the [WINDOWS] section of your help project file, providing the name and, optionally, initial size and position of each window. You can direct the Windows Help application to display a topic in a secondary window by appending an angle bracket (>) and the name you have defined for the secondary window to the name of the help file and then passing the resulting string to the WinHelp function.

An application can change the size and position of a primary or secondary window by specifying the address of a HELPWININFO structure and the HELP_SETWINPOS command in a call to WinHelp. HELPWININFO specifies the name of the window and its new size and position. The primary help window is the "main" window.


Training Card Help

Using training card help, an application can display a sequence of instructions to guide the user through the steps of a task. A training card typically consists of text that explains a particular step and authorable buttons associated with TCard macros that allow the user to tell the application what to do next. Training cards may only be displayed in secondary windows and must not contain hot links to other topics in the help file.

An application initiates the training card instance of Windows Help by calling the WinHelp function and specifying the HELP_TCARD command in combination with another command such as HELP_CONTEXT. Subsequently, when the user clicks an authorable button in the training card, clicks a hot spot assigned to the TCard macro, or closes the training card, Windows Help notifies the application by sending it a WM_TCARD message. The wParam parameter identifies the button or user action, and the lParam parameter contains additional data, the meaning of which depends on the value of wParam.


Canceling Help

Windows Help requires an application to explicitly cancel Help so that it can free any resources it used to keep track of the application and its help files. The application can do this at any time by calling the WinHelp function and specifying the HELP_QUIT command. Note that this is not true for the pop-up instance of Windows Help. An application should not try to close the pop-up instance.

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

To close the training card instance of Windows Help, you must specify both the HELP_TCARD and HELP_QUIT commands when calling the WinHelp function. An application does not need to cancel the training card instance of Windows Help if the user cancels it first. Windows Help notifies an application when the user cancels the training card instance by sending the WM_TCARD message with the wParam parameter set to IDCLOSE.


Using Help

This section shows how to provide context-sensitive help for a dialog box and how to set the appearance of a secondary help window.

•	Providing Help in a dialog box

•	Setting the appearance of a secondary help window


Providing Help in a Dialog Box

To provide context-sensitive help in a dialog box, you must create an array consisting of pairs of doubleword values. The first value in each pair is the identifier of a control in the dialog box, and the second is the context identifier of the help topic for the control. The array should contain one pair of identifiers for each control in the dialog box.

The dialog box procedure must process the WM_HELP and WM_CONTEXTMENU messages. The dialog box procedure receives WM_HELP when the user presses the F1 key and WM_CONTEXTMENU when the user clicks the right mouse button.

The lParam parameter of WM_HELP is a pointer to a HELPINFO structure. The hItemHandle member of this structure identifies the control for which the user has requested help. You must pass the handle to the WinHelp function along with the HELP_WM_HELP command, the name of your help file, and a pointer to the array of identifiers. The WinHelp function searches the array for the control identifier of the specified control and then retrieves the corresponding help context identifier. Next, the function passes the help context identifier to Windows Help, which finds the corresponding topic and displays it in a pop-up window. If the control has an identifier of  − 1, the system searches for the next control that is a tab stop and uses its identifier to find the help context identifier. For this reason, it is important that you place static text before controls in a resource file.

Processing WM_CONTEXTMENU is similar to processing WM_HELP when calling the WinHelp function, with these two exceptions:

•	You pass the wParam parameter from WM_CONTEXTMENU, which is the handle of the control that sent the message.

•	You specify the HELP_CONTEXTMENU command instead of HELP_WM_HELP.

The HELP_CONTEXTMENU command causes Windows Help to display a menu before it displays the help topic. The menu is system defined. It allows the user to display help for the control or to display the Help Topics dialog box.

The following example shows how to implement context-sensitive help in a dialog box.

LRESULT CALLBACK EditDlgProc(HWND hwndDlg, UINT uMsg, WPARAM 	wParam,

    LPARAM lParam)

{

// Create an array of control identifiers and context identifiers.

static DWORD aIds[] = {

    ID_SAVE,   IDH_SAVE,

    ID_DELETE, IDH_DELETE,

    ID_COPY,   IDH_COPY,

    ID_PASTE,  IDH_PASTE,

    0,0

};

switch (uMsg) {

    case WM_HELP:

        WinHelp(((LPHELPINFO) lParam)->hItemHandle, "helpfile.hlp",

            HELP_WM_HELP, (DWORD) (LPSTR) aIds);

        break;

    case WM_CONTEXTMENU:

        WinHelp((HWND) wParam, "helpfile.hlp", HELP_CONTEXTMENU,

            (DWORD) (LPVOID) aIds);

        break;

    .

    . // process other messages here

    .

    }

return FALSE;

}


Setting the Appearance of a Secondary Help Window

An application can set the size, position, and show state of a secondary help window by passing the HELP_SETWINPOS command and the address of a HELPWININFO structure to the WinHelp function. The members of HELPWININFO specify the name of the window to change and the window's new size, position, and show state.

The following example sets the appearance of a secondary window named "wnd_menu". The name must be defined in the [WINDOWS] section of the help project file.

BOOL DoWindowSize(VOID)

{

    HANDLE hhwi;

    LPHELPWININFO lphwi;

    WORD wSize;

    char *szWndName = "wnd_menu";

    wSize = sizeof(HELPWININFO) + lstrlen(szWndName);

    hhwi = GlobalAlloc(GHND, wSize);

    lphwi = (LPHELPWININFO) GlobalLock(hhwi);

    lphwi->wStructSize = wSize;

    lphwi->x    = 256;      // horizontal position

    lphwi->y    = 256;      // vertical position

    lphwi->dx   = 767;      // width

    lphwi->dy   = 512;      // height

    lphwi->wMax = SW_SHOW;  // show the window

    lstrcpy(lphwi->rgchMember, szWndName);  // secondary window

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

    GlobalUnlock(hhwi);

    GlobalFree(hhwi);

return;

}


Help Reference

The following sections list the messages and functions associated with Help controls.


Help Functions

The following functions are used with online Help.

GetMenuContextHelpId
GetWindowContextHelpId
SetMenuContextHelpId
SetWindowContextHelpId
WinHelp


Help Messages

The following messages are used with online Help.

WM_HELP
WM_TCARD


Image Color Matching

Image color matching provides accurate and consistent reproductions of color images on all output devices. This overview describes image color matching and explains how to use the related functions. For general information about colors and how to specify colors when drawing, see Colors.


About Image Color Matching

Despite differences in imaging technologies and color capabilities between devices, image color matching ensures that a color image will look the same or as close as possible to the same when output to screen, paper, film, and other media. Applications typically use image color matching to let users create color images on the screen that can then be reproduced exactly on a printer or on other screens.


Logical Colors, Gamuts, and Gamut Matching

By default, Windows disables image color matching to ensure that existing applications continue to draw color images as originally intended. You can enable image color matching for a device context by using the SetICMMode function. You must enable image color matching for each device context you intend to use for output.

Once you enable image color matching, you can create a color space and select it into the device contexts of the devices you wish to use. The color space defines the set of logical colors that you may use to draw. For each device, the system or the device driver transforms the logical colors to device (or physical) colors in a way that ensures consistency across devices.

To use a color from the color space, you specify a logical color value. The format of the value depends on the color space type. In some color spaces, this is similar to RGB (red, green, blue) color value described in previous Windows documentation, but the red, green, and blue components of logical color values are defined in terms of independent colormetric measure rather than arbitrary color units imposed by a device driver. In other cases, you may use color values that actually contain CMYK (cyan, magenta, yellow, black) values.

Not all devices support all colors. You can determine which colors are supported by a given device by checking its gamut, the set of colors it can produce. Different devices have different gamuts. For example, the screen can display cyans that no printer can produce; likewise, there are some reds on a page that never appear on a display.

An important element of image color matching is gamut matching, the process of finding color matches in the gamuts of different devices. This can range from the simple (such as truncating to the surface of the printer gamut), to the sophisticated (such as moving all colors a bit to maintain contrasts). Matching is not simply the process of ensuring that each pixel is faithfully reproduced with a given color. Instead, image color matching works within the capabilities of the given output device to produce an image in which the colors have the same relation to one another as they do when produced on other devices.

You can determine whether given colors are within the gamut of a device by using the CheckColorsInGamut function. This is useful for determining whether the screen has a larger gamut than the current printer. In such cases, you can notify the user of which screen colors won't print. You can preview the colors of a print job on the screen by using the ColorMatchToTarget function. The function first uses the current color space and gamut-matching method of a given device context, such as for a printer, to convert the colors in an image. It then converts the converted image to display on the preview device.

Image color matching applies to any drawing operation in which colors are given as color values. It affects colors that you specify directly, such as when setting the color of individual pixels using the SetPixel function, or indirectly, when you set the colors in pens, brushes, fonts and other graphics objects. Image color matching does not apply to device-dependent bitmaps, such as those created by the CreateBitmap and CreateCompatibleBitmap functions.


Color Spaces

Image color matching uses color spaces to define the set of colors available for a device. To each device context, the system assigns a default color space whose attributes, such as color space type, gamut-matching method and color endpoints, fully define how the system transforms color values for the device. You can create your own color spaces and replace the default color space for a device context by using the CreateColorSpace and SetColorSpace functions. These functions let you explicitly set the format of the color values you use in your application and how the device interprets those values and generates colors.

To create a color space, you set the members of a LOGCOLORSPACE structure and pass the structure to the CreateColorSpace function. You can either set the members to the values you want or specify the filename of a color profile that contains the characterization of the device. For more information, see Color Profiles.

Every color space must have a color space type and a gamut matching method. Gamut matching specifies whether colors in a given image are transformed into an exact match or are modified to make best use of the gamut of the given device, and is described in Gamut Matching Method.

The color space types can be device RGB (red, green, blue), device CMYK (cyan, magenta, yellow, black), or calibrated RGB. Device RGB, the default color space for device contexts, consists of the arbitrary set of colors for the specified output device. Logical color values in this space are given as three 8-bit color values (in a 32-bit value) and are sent to the device driver without transformation. Device CMYK is similar to device RGB except that logical color values are given as four 8-bit values. You use this color space for devices, typically printers, that use CMYK color values. For example, you might use it to carry out color separation and pass color values directly to a CMYK printer.

Calibrated RGB consists of colors in the set defined by three color endpoints. The color endpoints are given as three 32-bit values and are interpreted as defined by the 1931 CIE (Commission Internationale de L'Eclairage) XYZ standard.

After you have created a color space, you can select it into a device context by using the SetColorSpace function. You can delete a color space if you no longer need it by using the DeleteColorSpace function.

You can retrieve the color space for a specified device context by using the GetColorSpace function. This is useful if you want to get the logical definition or color profile file associated with the color space. You can use the GetLogColorSpace function to copy this information to a LOGCOLORSPACE structure.


Gamut Matching Method

The gamut matching method determines how colors on a given device are "matched" with colors on another device. The type of matching needed depends on the image. There are some images for which users rarely want image color matching. For example, users like saturated, undithered colors in bar charts and highlights used in presentations — the device colors are far superior to dithered patterns of primary colors.

Gamut-matching methods include the following:

•	Business graphics

Preserves saturation (prevents dithering) if the requested color is not available. Useful for business charts and many computer-generated presentations.

•	Colormetric

Produces exact colormetric matches. Dithers primary colors if necessary. Colormetric matching is important when named colors are wanted.

•	Photographic

Produces the best perceptual match between devices. Takes advantage of the entire gamut of the device to maximize the number of distinct colors presented. This is best for photographic images.

You set the gamut-matching method for a device context by setting the lcsIntent member in the LOGCOLORSPACE structure when creating the color space. The matching choices for the display and printer are global settings; they apply to all applications at all times.

In some cases, a user may want to use different matching methods in the same document. For example, the user may want to use the colormetric method to draw the company logo but the business graphics method for bar charts. You can mix gamut-matching methods on the same page of output by creating appropriate color spaces and using SetColorSpace to switch between the spaces as needed.


Color Profiles

A color profile is a file that contains information that defines the color capabilities of a device. A color profile for a display monitor, for example, defines the chromaticities of the phosphors for that monitor; one for a printer defines the chromaticities of the inks on a given type of paper. The system uses this information when mapping logical colors to the physical colors available on the device.

Color profiles exist for display monitors, printers, and scanners. By default, the system uses the color profile that best matches a given device, based on information in the profile and provided by the device driver. If a color profile is not present for a given device, the system uses a default profile for that device.

In some cases, it may be important to let the user choose the color profile to use for a given device. This can occur when the device configuration has changed in a way that the system cannot detect. You can enumerate all color profiles for a device by using the EnumICMProfiles function. This identifies each color profile by passing its filename to an EnumICMProfilesProc callback function that you supply. You can set the color profile for the device by using the SetICMProfile function. You can determine the current color profile for the device by using the GetICMProfile function.

A color profile is available only if it is listed in the registry. You can install or remove color profiles in the registry by using the UpdateICMRegKey function. You can also use this function to query for printer profiles that match specified device settings, or to associate a color profile with a given color-matching DLL and output device.


Device-Independent Bitmaps and Enhanced Metafiles

To provide for image color matching, color characterization is included in device-independent bitmaps (DIBs) and enhanced metafiles. In DIBs, the color characterization is placed in the DIB header. In enhanced metafiles, the characterization is in metafile records. Color characterization is not available for compatible bitmaps and standard (16-bit) metafiles.

You set the color characterization for a DIB by setting the appropriate members in the BITMAPV4HEADER structure for the DIB. This structure is identical to the BITMAPINFOHEADER structure except that it includes members that define the color space type, color endpoints, and other related values. Some operating systems support the device CMYK color space type in DIBs but only for 32-bit DIBs. In such cases, the output device must also accept this format. If a DIB does not contain color characterization information, the system uses a default characterization.

You set color characterization for an enhanced metafile by using the CreateColorSpace and SetColorSpace functions when recording the metafile. The system records information about the color spaces and carries out color matching with the intended output device when the metafile is played. The system also records the SetICMMode and DeleteColorSpace functions, but no other image color matching functions can be used with enhanced metafiles. If you specify a color profile in the LOGCOLORSPACE structure when recording an enhanced metafile, the system records the filename of the color profile but not the content of the profile. This is similar to the way fonts are handled in enhanced metafiles.


Gamma Correction

Some display adapters support downloadable gamma correction tables. These tables let you control the colors generated by the digital-to-analog converter (DAC) by mapping specific RGB values to DAC values. You can set the gamma ramp for any 24-bit display adapters that provide hardware gamma correction by using the SetDeviceGammaRamp function. The hardware gamma ramp is a global property that affects all running applications and is not changed on a per-device context basis. You can retrieve the current gamma ramp by using the GetDeviceGammaRamp function.


Image Color Matching Reference

This section provides a listing of the image color matching functions and structures.


Image Color Matching Functions

This following are the image color matching functions.

CheckColorsInGamut
ColorMatchToTarget
CreateColorSpace
DeleteColorSpace
EnumICMProfiles
EnumICMProfilesProc
GetColorSpace
GetDeviceGammaRamp
GetICMProfile
GetLogColorSpace
SetColorSpace
SetDeviceGammaRamp
SetICMMode
SetICMProfile
UpdateICMRegKey


Image Color Matching Macros

This following are the image color matching macros.

CMYK
GetCValue
GetKValue
GetMValue
GetYValue


Image Color Matching Structures

The following structures are used with the image color matching functions.

BITMAPV4HEADER
CIEXYZ
CIEXYZTRIPLE
LOGCOLORSPACE


Interprocess Communications

The Microsoft® Win32® application programming interface (API) provides a rich set of mechanisms for facilitating communications and data sharing between applications. Collectively, the activities enabled by these mechanisms are called interprocess communications (IPC). In addition to facilitating the division of labor among several specialized processes, some forms of IPC can distribute the computational load among cooperating computers on a network.


About Interprocess Communications

As computer users become more sophisticated, they demand more power from the applications they use. To meet this demand, developers add more features to their applications, and the applications become larger. These large applications can eventually become unmanageable, both from a development standpoint and from a user-interface point of view. Therefore, developers now tend to produce highly focused applications that do a good job on a limited number of features and then to enable those applications to communicate and share data with other specialized applications. No longer can any one application meet all user expectations; the age of cooperating and communicating applications has arrived.

Typically, cooperating and communicating applications can be categorized as clients or servers. A client is an application or a process that requests a service from some other process. A server is an application or a process that responds to a client request. Many applications act as both a client and a server, depending on the situation. For example, a word processing application might act as a client in requesting a summary table of manufacturing costs from a spreadsheet application acting as a server. The spreadsheet application, in turn, might act as a client in requesting the latest inventory levels from an automated inventory control application.


Development Considerations

If a developer decides that an application would benefit from IPC, the developer must consider some of the following questions before deciding which of the available IPC methods to use.

•	Should the application be able to communicate with other applications running on other computers on a network, or is it sufficient for the application to communicate only with applications on the local computer? In other words, does the application need to be networkable? Some IPC methods work either on the local computer or over a network; others work only on the local computer.

•	Should the application be able to communicate with applications running on other computers that may be running under different operating systems (that is, MS-DOS®, Microsoft® Windows® Version 3.x, UNIX®)? In other words, must the application be interoperable?

•	Should the user of the application have to choose the other application(s) with which the application communicates, or can the application implicitly find its cooperating partners?

•	Should the application communicate with many different applications in a general way, such as allowing cut and paste operations with any other application, or should its communications requirements be limited to a restricted set of interactions with specific other applications? Applications that communicate in a general way are called loosely coupled; applications that have a more strictly defined interaction are called tightly coupled.

•	Is performance a critical aspect of the application? All IPC mechanisms include some amount of communications overhead.

•	Should the application be a Windows-based application, or will character-mode functionalities be sufficient? Some IPC mechanisms discussed in this topic do not work in character-mode−only applications. The clipboard, dynamic data exchange (DDE), and object linking and embedding (OLE) all require that the application have at least one window.

The answers to these questions determine whether an application can benefit by using one or more of the IPC mechanisms available in the Win32 API. This topic discusses the strengths and weaknesses of each of the Win32 IPC mechanisms.


File Mapping and IPC

File mapping enables a process to treat the content of a file as if it were a block of memory in the process's address space. Therefore, instead of using file input and output (I/O) operations, the process can use simple pointer operations to examine and modify the contents of the file.

The Win32 API enables two or more processes to access the same file-mapping object. Each process receives a pointer to memory in its own address space. With this pointer, the process can read or modify the contents of the file.

There are three ways an application can share a file-mapping object created in one process with another process:

•	Inheritance. The first process creates the file-mapping object and then allows the handle of the object to be inherited by a child process.

•	Named file mapping. The first process creates the file-mapping object with a well-known name (which can be different from the filename). The second process opens the file-mapping object by specifying the well-known name. Alternatively, the first process can create a file-mapping object with a unique name and communicate that name to the second process through some other IPC mechanism (named pipe, mailslot, and so on).

•	Handle duplication. The first process creates the file-mapping object and then passes the handle of the object to the second process. The second process then duplicates the handle to gain access to the shared memory. The original process can communicate the file-mapping handle to the second process through one of the other IPC mechanisms described in this topic (named pipe, mailslot, and so on). For more information about duplicating handles, see Synchronization.

When two or more processes have read-write access to a shared memory block, they must use some sort of synchronization object, such as a semaphore, to prevent data corruption in a multitasking environment.

File mapping is quite efficient and also provides operating-system−supported security attributes that can help prevent unauthorized data corruption. File mapping can be used only between processes on a local computer; it cannot be used over a network. An application can, however, create a file-mapping object to a file on a remotely mounted volume. For example, if a remote server is mounted as the F drive, an application can create a file-mapping object to a file on that volume. However, a process running on a remote server cannot share a file-mapping object with a process running on a local computer.

Key Point  File mapping is an efficient way for two or more processes on the same computer to share data, but the developer must provide synchronization between the processes. For more information, see File Mapping, and Synchronization.


Shared Memory and IPC

The Win32 API uses a special case of file mapping to provide shared memory access between processes. If you specify the system swapping file when creating a file-mapping object, the file-mapping object is treated as a shared memory block. Other processes can access the same block of memory by opening the same file-mapping object, as described in File Mapping.

Because shared memory is implemented with file mapping, it supports security access attributes and can operate only between processes running on the same computer.

Key Point  Shared memory in the Win32 API is implemented by using file mapping. All characteristics of file mapping apply to shared memory. For more information, see File Mapping.


Anonymous Pipes and IPC

An anonymous (or unnamed) pipe enables related processes to transfer information back and forth as if they were reading from and writing to a file. Typically, anonymous pipes are used for redirecting the standard input and output (I/O) of a child process so that it can exchange data with its parent process.

To use an anonymous pipe, the parent process typically creates the pipe and then allows its read and write handles to be inherited by a child process. The parent process writes data to the pipe; the child process can read the data from the other end of the pipe. Likewise, the child process can write data to the pipe and the parent process can read the data from its end of the pipe. A parent process can also create two or more child processes that inherit the read and write handles to an anonymous pipe. Those child processes can use that pipe to communicate between each other directly, without going through the parent process.

Anonymous pipes cannot be used over a network, nor can they be used between unrelated processes. For information about a pipe mechanism that can be used with unrelated processes and over a network, see Named Pipes.

Key Point  Anonymous pipes provide an efficient way to redirect standard I/O to child processes on the same computer. For more information, see Pipes.


Named Pipes and IPC

Like anonymous pipes, named pipes are used to transfer data back and forth between processes. Unlike anonymous pipes, however, named pipes can operate between unrelated processes and across a network between computers. Typically, a server process creates a named pipe with a well-known name. Client processes that can get the name of the pipe can open the other end of the pipe, subject to access restrictions specified by the pipe's creator. After they are connected, the server and client can exchange data by performing read and write operations on the pipe. Alternatively, the pipe creator can create a pipe and let a child process inherit the handle to the pipe, or it can create a pipe with a unique name and communicate that name to the client through some other IPC mechanism (such as a mailslot maintained by the client).

Key Point  Named pipes provide a relatively simple programming interface that makes transferring data across a network no more difficult than transferring data between two processes on the same computer. For more information, see Pipes.


IPC Mailslots

Mailslots provide a one-way interprocess communications capability. Any process can create a mailslot and become a mailslot server. Other processes, called mailslot clients, can gain access to the mailslot by its name and send messages to the mailslot server process. A process can be both a mailslot server and a mailslot client, so two-way IPC is possible with multiple mailslots.

Incoming messages are always appended to the mailslot. The mailslot saves the messages until the creating process has a chance to read them.

Mailslots are similar to named pipes, but with a somewhat simplified programming interface and the added ability to broadcast messages to all computers in a specified network domain. A mailslot client can send a message to a mailslot on its local computer, to a mailslot on another computer, or to all mailslots with the same name on all computers in a specified network domain. Messages broadcast to a domain can be no longer than 400 bytes; messages sent to a single mailslot are limited only by the maximum message size specified by the creator of the mailslot (which can be unlimited).

Key Point  Mailslots offer an easy way for applications to send and receive short messages. They also provide the ability to broadcast messages across all computers in a network domain. For more information, see Mailslots.


Using the Clipboard for IPC

The clipboard provides a mechanism for the well-established cut-copy-paste model for simple data sharing between Win32-based applications. It enables an application to read or write data in many different standard and application-defined formats. It also works between applications on the same computer or on different computers on a network.

The clipboard acts as a central depository for data sharing among applications. When a user performs a cut or copy operation in an application, the application puts the selected data on the clipboard in one or more formats. Any other application can then retrieve the data from the clipboard, choosing from the available formats. The clipboard is a very loosely coupled exchange medium, wherein the two applications need only agree on the data format.

Key Point  All Win32-based applications should support the clipboard for those data formats that they understand. For example, a text editor or word processor should at least be able to produce and accept clipboard data in pure text format. For more information, see Clipboard.


Dynamic Data Exchange and IPC

Dynamic data exchange (DDE) is a protocol for interprocess communications that enables applications to exchange data in a variety of formats. Applications can use DDE for one-time data exchanges or for ongoing exchanges in which the applications update one another as new data becomes available.

The data formats used by DDE are the same as those used for the Windows clipboard IPC mechanism. DDE can be thought of as an extension of the clipboard mechanism. The clipboard is almost always used for a one-time response to a user command, such as choosing the Paste command from a menu. DDE is also usually initiated by a user command, but it often continues to function without further user interaction.

Three types of data exchange are possible with DDE:

•	Cold link. The exchange is a one-time data transfer, like the clipboard.

•	Warm link. A server notifies the client when data changes, and the client must then request new data.

•	Hot link. A server sends data updates to the client when data changes.

DDE exchanges can occur between applications running on the same computer or on different computers on a network.

Key Point  Most major Windows-based applications support DDE. Like the clipboard, DDE support enables an application to exchange data in a variety of standard formats with other Windows-based applications that support DDE. A developer can also define custom DDE data formats for special-purpose IPC between applications with more tightly coupled communications requirements. For more information, see Dynamic Data Exchange and Dynamic Data Exchange Management Library.


Object Linking and Embedding

Object linking and embedding (OLE) applications manage compound documents — that is, documents made up of data from a variety of different applications. OLE provides services that make it easy for applications to call on other applications for data editing. For example, an OLE-aware word processor could embed a graph from a spreadsheet. The user could start the spreadsheet automatically from within the word processor by choosing the embedded chart for editing. The OLE libraries would take care of starting the spreadsheet and presenting the graph for editing. When the user quit the spreadsheet, the graph would be updated in the original word processor document. Contrast this with a DDE link involving a spreadsheet graph in a word processor document. With DDE, the user would have to explicitly start the spreadsheet and open the graph document in order to make changes. With OLE, the spreadsheet appears to be an extension of the word processor.

Like an application using DDE, an OLE-aware application can communicate with a wide variety of other Windows-based applications. Because the OLE protocol includes all necessary context information, the application will be able to hold OLE conversations with all other OLE-aware applications — even those that have yet to be written.

Key Point  OLE supports compound documents and enables an application to include embedded or linked data that, when chosen, automatically starts another application for data editing. This enables the application to be extended by any other OLE-aware application.


Dynamic-Link Libraries and IPC

It is possible to build a Win32-based dynamic-link library (DLL) so that its global data is shared with all processes that call the DLL. Therefore, cooperating processes can call the DLL to examine and modify global data owned by the DLL. For example, process A calls a DLL function with data that the DLL stores in its global data space. Process B calls another DLL function that retrieves that data. Because of the multitasking nature of the Win32 API, the DLL would have to use a semaphore or another synchronization object to control access to the shared memory.

Although shared global data can be used in a DLL, Win32 file mapping is recommended for shared memory. File mapping is more efficient and provides the additional benefit of access protection. (For example, a client can be limited to read-only access to a file-mapping object.)

Key Point  Although a developer can use shared global data segments in a DLL to allow two or more applications to share data, it is preferable to use Win32 file-mapping functions to create shared memory. For more information, see Dynamic-Link Libraries.


Remote Procedure Call

The Win32 API provides remote procedure calls (RPC) to enable applications to call functions remotely. With RPC, communication with other processes becomes as easy as calling a function. RPC operates between processes on a single computer or on different computers on a network. One way to think of RPC is as a DLL that works on a network.

The RPC provided by the Win32 API is compliant with the Open Software Foundation (OSF) Distributed Computing Environment (DCE). This means that RPC applications written by using the Win32 API are able to communicate with other RPC applications running with other operating systems that support DCE. RPC automatically supports data conversion to account for different hardware architectures and for byte-ordering between dissimilar environments.

The Win32 software development kit includes RPC libraries that support MS-DOS−hosted RPC clients. With this facility, a Windows NT server, for example, can provide service to many MS-DOS clients through RPC.

RPC clients and servers are tightly coupled but still maintain high performance. Windows makes extensive use of RPC to facilitate a client-server relationship between different parts of the operating system.

Key Point  RPC provides IPC with a function interface, with support for automatic data conversion and for communications with other operating systems. Using RPC, a developer can create high-performance, tightly coupled distributed applications. For more information, see the Microsoft RPC Components.


The Netbios Function and IPC

The Win32 API provides the Netbios function to process low-level network control functions. This capability is provided primarily for applications written using the IBM NetBIOS system that must be ported to Windows. It is highly recommended that a developer writing a new application use the other IPC mechanisms described in this topic rather than the low-level Netbios function. The IPC mechanisms provided in the Win32 API encapsulate and hide an enormous amount of raw NetBIOS functionality that the developer would otherwise have to implement.

Consider, for example, the following list of NetBIOS actions that would be necessary to emulate a Win32-based mailslot:

On the server end

•	Add the name to the local table.

•	Listen for the session connection.

•	Read the data upon connection.

•	Append the data to the message queue.

•	Close the session.

•	Listen for another session connection.

•	Allow the queued messages to be retrieved.

On the client side

•	Open the session.

•	Write the data.

•	Close the session.

Key Point  The Netbios function is provided only for porting an existing application written using the IBM NetBIOS system or for those applications that need specialized access to low-level network functionality. For most applications, it is better to use the higher-level IPC mechanisms available in the Win32 API. For more information, see Networks.


Summary

It is likely that an application will support IPC by using several of the mechanisms described in this topic. For example, all Win32-based applications should provide at least minimal support for the clipboard. In addition, DDE and OLE may offer the application an opportunity to communicate in a loosely coupled way with a wide variety of applications that support these protocols. The great strength of these loosely coupled mechanisms is that a developer can enable an application to share data with other applications without knowing anything about the applications themselves. By supporting the protocols for the clipboard, DDE, and OLE, the developer is assured of a growing number of applications with which the application can share data. As new applications are written that support these protocols, the developer's application will be ready to communicate with them.

As an application becomes more sophisticated, a developer may find it advantageous to break up the application into tightly coupled cooperating processes that use shared memory, pipes, or RPC to communicate. These tightly coupled mechanisms can provide high-performance extensions to the application. But when adding these more specialized IPC methods, the developer should not abandon the more loosely coupled IPC methods that allow the application to share data in a general way with most other Win32-based applications.


Large Integer Operations

This overview describes Microsoft Win32 support for operations on large (64-bit) integers.


About Large Integer Operations

Applications can multiply signed or unsigned 32-bit integers, generating 64-bit results, by using the Int32x32To64 and UInt32x32To64 functions. Applications can shift bits in 64-bit values to the left or right by using the Int64ShllMod32, Int64ShraMod32, and Int64ShrlMod32 functions. These functions provide logical and arithmetic shifting.

Applications can also multiply and divide 32-bit values in a single operation by using the MulDiv function. Although the result of the operation is a 32-bit value, the function stores the intermediate result as a 64-bit value, so that information is not lost when large 32-bit values are multiplied and divided.


Large Integer Operations Functions

Following are the functions used with large integer operations.

Int32x32To64
Int64ShllMod32
Int64ShraMod32
Int64ShrlMod32
MulDiv
UInt32x32To64


Mailslots

A mailslot is a mechanism for one-way interprocess communications (IPC). An application written for Microsoft® Windows® can store messages in a mailslot. The owner of the mailslot can retrieve messages that are stored there. These messages are typically sent over a network to either a specified computer or to all computers in a specified domain. A domain is a group of workstations and servers that share a group name.


About Mailslots

A mailslot is a pseudofile; it resides in memory, and standard Windows file functions write to it. Unlike disk files, however, mailslots are temporary. When every handle of a mailslot is closed, the mailslot and all the data it contains are deleted. The data in a mailslot message can be in any form.

A mailslot server is a process that creates and owns a mailslot. When the server creates a mailslot, it receives a mailslot handle. This handle must be used when a process reads messages from the mailslot. Only the process that creates a mailslot (or has obtained the handle by some other mechanism, such as inheritance) can read from the mailslot. A mailslot exists until all server handles to it have been closed or all server processes have exited. All mailslots are local to the process that creates them; a process cannot create a remote mailslot.

A mailslot client is a process that writes a message to a mailslot. Any process that has the name of a mailslot can put a message there. New messages follow preexisting messages in the mailslot.

Mailslots can broadcast messages within a domain. If several processes in a domain each create a mailslot using the same name, every message that is addressed to that mailslot and sent to the domain is received by the participating processes. Because one process can control both a server mailslot handle and the client handle retrieved when the mailslot is opened for a write operation, applications can easily implement a simple message-passing facility within a domain.

Some developers choose to use named pipes instead of mailslots for interprocess communications. Named pipes are a simple way for two processes to exchange messages. Mailslots, on the other hand, are a simple way for a process to broadcast messages to many other processes. For more information about named pipes, see Pipes.

Another issue in the choice between mailslots and named pipes is that mailslots use datagrams, and named pipes do not. A datagram is a small packet of information that the network sends along the wire. Like a radio or television broadcast, a datagram offers no confirmation of receipt; there is no  way to guarantee that a datagram has been received. Just as mountains, large buildings, or interfering signals might cause a radio or television signal to get lost, there are things the sender has no knowledge of that can prevent a datagram from reaching a particular destination. Named pipes are more like simple one-to-one telephone calls: you can talk only to one party, but you know that the conversation is occurring. So, if an application requires guaranteed reception, it  should use a named pipe; but named pipes cannot broadcast. Mailslots do not guarantee reception, but they can broadcast.


Mailslot Names

When a process creates a mailslot, the mailslot name must have the following form.

\\.\mailslot\[path]name

A mailslot name requires the following elements: two backslashes to begin the name, a period, a backslash following the period, the word mailslot, and a trailing backslash. Case, however, is not important. A mailslot name can be preceded by a path consisting of the names of one or more pseudodirectories, separated by backslashes. For example, if a user expects messages on the subject of taxes from Bob, Pete, and Sue, the user's mailslot application might allow the user to create individual mailslots for each sender.

\\.\mailslot\taxes\bobs_comments

\\.\mailslot\taxes\petes_comments

\\.\mailslot\taxes\sues_comments

To put a message into a mailslot, a process opens a mailslot whose name is in one of several forms. To write to a mailslot on the local computer, a process can use a mailslot name using the same form required for creating a mailslot. This situation, however, is relatively uncommon. More frequently, a process uses the following form to write to a mailslot on a specific remote computer.

\\computername\mailslot\[path]name

The following form allows a process to put a message into every mailslot in the specified domain that has the given name.

\\domainname\mailslot\[path]name

To put a message into every mailslot with a given name in the system's primary domain, a process uses the following form.

\\*\mailslot\[path]name


Mailslots and Microsoft LAN Manager 2.x

Windows uses mailslots similar to those developed for Microsoft LAN Manager version 2.0. An application that uses LAN Manager 2.x mailslots can interact easily with mailslots created by Windows. There are significant differences, however, between Windows-based mailslots and LAN Manager mailslots:

•	Windows-based mailslots all have the same class — there are no "first class" and "second class" mailslots.

•	All Windows-based mailslot messages have equal priority and are always appended to the mailslot buffer. When a Windows-based mailslot message is written to a mailslot on a computer that requires message priority, the system sets the priority to the lowest value (0).

•	Write operations to Windows-based mailslots on local computers return an error value if an error occurs. Write operations to remote Windows-based mailslots do not return an error value when they fail. (Because there is no built-in limit to the size of the mailslot buffer failure is unlikely.)

•	Write operations to Windows-based mailslots fail immediately if the message cannot be appended to the mailslot buffer (if the buffer is too small, for example). Immediate failure makes write time-outs irrelevant; contrary to LAN Manager mailslots, there are no write time-outs for Windows-based mailslots.

•	A process that creates a Windows-based mailslot can specify that the mailslot handle be inherited by its child processes. (Mailslot handles in LAN Manager cannot be inherited.)

A process writes messages to a Windows-based mailslot by using standard file input and output functions. The following table shows LAN Manager mailslot functions and their corresponding Windows functions.

LAN Manager functions	Windows functions
DosDeleteMailslot	CloseHandle
DosMailslotInfo	GetMailslotInfo
DosMakeMailslot	CreateMailslot
DosReadMailslot	ReadFile
DosWriteMailslot	WriteFile


Server and Client Functions

Clients and servers when working with mailslots should use only the functions discussed in this section. Other Windows functions should not be used, even if they accept file handles or filenames as arguments.


Mailslot Server Functions

Mailslot servers have exclusive use of three functions, as shown in the following table.

Function	Description
CreateMailslot	Creates a mailslot and returns a mailslot handle.
GetMailslotInfo	Retrieves the maximum message size, the mailslot size, the size of the next message in the mailslot, the number of messages in the mailslot, and the amount of time a read operation can wait for a message.
SetMailslotInfo	Changes the read time-out for a mailslot.
The following functions are also used by mailslot servers.

Function	Description
DuplicateHandle	Duplicates the mailslot handle.
ReadFile	Retrieves messages from a mailslot.
GetFileTime	Retrieves the date and time a mailslot was created.
SetFileTime	Sets the date and time a mailslot was created.


Client Functions

A client process uses the following functions when interacting with a mailslot.

Function	Description
CloseHandle	Closes a mailslot handle for a client process.
CreateFile	Creates a mailslot handle for a client process.
DuplicateHandle	Duplicates a mailslot handle.
WriteFile	Writes data to a mailslot.


Using Mailslots

•	Creating a mailslot

•	Writing to a mailslot

•	Reading from a mailslot


Creating a Mailslot

Mailslots are supported by three specialized functions: CreateMailslot, GetMailslotInfo, and SetMailslotInfo. These functions are used by the mailslot server.

The following code sample uses the CreateMailslot function to retrieve the handle of a mailslot named sample_mailslot.

BOOL FAR PASCAL Makeslot(HWND hwnd, HDC hdc)

{

    LPSTR lpszSlotName = "\\\\.\\mailslot\\sample_mailslot";

    /* The mailslot handle "hSlot1" is declared globally. */

    hSlot1 = CreateMailslot(lpszSlotName,

        0,                         /* no maximum message size         */

        MAILSLOT_WAIT_FOREVER,     /* no time-out for read operations */

        (LPSECURITY_ATTRIBUTES) NULL); /* no security attributes      */

    if (hSlot1 == INVALID_HANDLE_VALUE) {

        ErrorHandler(hwnd, "CreateMailslot"); /* local error handler */

        return FALSE;

    }

    TextOut(hdc, 10, 10, "CreateMailslot successful.", 26);

    return TRUE;

}

To create a mailslot that can be inherited by child processes, an application should change the SECURITY_ATTRIBUTES structure passed as the last parameter of CreateMailslot. To do this, the application sets the bInheritHandle member of this structure to TRUE (the default setting is FALSE).


Writing to a Mailslot

Writing to a mailslot is similar to writing to a standard disk file. The following code uses the CreateFile, WriteFile, and CloseHandle functions to put a short message in a mailslot. The message is broadcast to every computer in the primary domain of the system.

LPSTR lpszMessage = "Message for sample_mailslot in primary domain.";

BOOL fResult;

HANDLE hFile;

DWORD cbWritten;

hFile = CreateFile("\\\\*\\mailslot\\sample_mailslot",

    GENERIC_WRITE,

    FILE_SHARE_READ, /* required to write to a mailslot */

    (LPSECURITY_ATTRIBUTES) NULL,

    OPEN_EXISTING,

    FILE_ATTRIBUTE_NORMAL,

    (HANDLE) NULL);

if (hFile == INVALID_HANDLE_VALUE) {

    ErrorHandler(hwnd, "Primary domain"); /* local error handler */

    return FALSE;

}

fResult = WriteFile(hFile,

    lpszMessage,

    (DWORD) lstrlen(lpszMessage) + 1, /* include terminat. null char. */

    &cbWritten,

    (LPOVERLAPPED) NULL);

if (!fResult) {

    ErrorHandler(hwnd, "WriteFile");

    return FALSE;

}

TextOut(hdc, 10, 10, "WriteFile successful.", 21);

fResult = CloseHandle(hFile);

if (!fResult) {

    ErrorHandler(hwnd, "CloseHandle");

    return FALSE;

}

TextOut(hdc, 10, 30, "CloseHandle successful.", 23);

return TRUE;

Messages broadcast to a domain must be no longer than 400 bytes. Messages that are not broadcast should be smaller than 64 kilobytes. There is no limit to the number of messages that can be sent to a mailslot.


Reading from a Mailslot

The process that creates a mailslot can read messages from it by using the mailslot handle in a call to the ReadFile function. The code in the following example calls the GetMailslotInfo function to determine whether there are messages in the mailslot. If messages are waiting, each is displayed in a message box along with the number of messages remaining to be read.

BOOL FAR PASCAL Readslot(HWND hwnd, HDC hdc)

{

    DWORD cbMessage, cMessage, cbRead;

    BOOL fResult;

    LPSTR lpszBuffer;

    CHAR achID[80];

        DWORD cAllMessages;

    cbMessage = cMessage = cbRead = 0;

    /* Mailslot handle "hSlot1" is declared globally. */

    fResult = GetMailslotInfo(hSlot1, /* mailslot handle         */

        (LPDWORD) NULL,               /* no maximum message size */

        &cbMessage,                   /* size of next message    */

        &cMessage,                    /* number of messages      */

        (LPDWORD) NULL);              /* no read time-out        */

    if (!fResult) {

        ErrorHandler(hwnd, "GetMailslotInfo");

        return FALSE;

    }

    if (cbMessage == MAILSLOT_NO_MESSAGE) {

        TextOut(hdc, 10, 10, "No waiting messages.", 20);

        return TRUE;

    }

    cAllMessages = cMessage;

    while (cMessage != 0) {              /* retrieves each message  */

        /* Create a message-number string. */

        wsprintf((LPSTR) achID,

            "\nMessage #%d of %d\n", cAllMessages - cMessage + 1,

            cAllMessages);

        /* Allocate memory for the message. */

        lpszBuffer = (LPSTR) GlobalAlloc(GPTR,

            lstrlen((LPSTR) achID) + cbMessage);

        lpszBuffer[0] = '\0';

        fResult = ReadFile(hSlot1,

            lpszBuffer,

            cbMessage,

            &cbRead,

            (LPOVERLAPPED) NULL);

        if (!fResult) {

            ErrorHandler(hwnd, "ReadFile");

            GlobalFree((HGLOBAL) lpszBuffer);

            return FALSE;

        }

        /* Concatenate the message and the message-number string. */

        lstrcat(lpszBuffer, (LPSTR) achID);

        /* Display the message. */

        MessageBox(hwnd,

            lpszBuffer,

            "Contents of Mailslot",

            MB_OK);

        GlobalFree((HGLOBAL) lpszBuffer);

        fResult = GetMailslotInfo(hSlot1, /* mailslot handle         */

            (LPDWORD) NULL,               /* no maximum message size */

            &cbMessage,                   /* size of next message    */

            &cMessage,                    /* number of messages      */

            (LPDWORD) NULL);              /* no read time-out        */

        if (!fResult) {

            ErrorHandler(hwnd, "GetMailslotInfo");

            return FALSE;

        }

    }

    return TRUE;

}

A mailslot exists until the CloseHandle function is called for all open server handles or until all server processes that own a mailslot handle exit. In both cases, any unread messages are deleted from the mailslot, all client handles to the mailslot are closed, and the mailslot itself is deleted from memory.


Mailslot Functions

The following functions can be used with mailslots.

CreateMailslot
GetMailslotInfo
SetMailslotInfo


Memory Management

This overview describes Win32 memory management. It also explains how to allocate and use memory.


About Memory Management

In the Microsoft® Win32® application programming interface (API), each process has its own 32-bit virtual address space that enables addressing up to 4 gigabytes (GB) of memory. The 2 GB in low memory (0x00 to 0x7FFFFFFF) are available to the user, and the 2 GB in high memory (0x80000000 to 0xFFFFFFFF) are reserved for the kernel. The virtual addresses used by a process do not represent the actual physical location of an object in memory. Instead, for each process the kernel maintains a page map, an internal data structure used to translate virtual addresses into corresponding physical addresses.


Virtual Address Space and Physical Storage

The virtual address space of each process is much larger than the total physical memory, random-access memory (RAM), available to all processes. To increase the size of physical storage, the kernel uses the disk for additional storage. The total amount of storage available to all executing processes is the sum of the physical memory, RAM, and the free space on disk available to the paging file, a disk file used to increase the amount of physical storage. Physical storage and the virtual (logical) address space of each process are organized into pages, units of memory, whose size depends on the host computer. For example, on x86 computers the host page size is 4 kilobytes (K).

To maximize its flexibility in managing memory, the kernel can move pages of physical memory to and from a paging file on disk. When a page is moved in physical memory, the kernel updates the page maps of the affected processes. When the kernel needs space in physical memory, it moves the least recently used pages of physical memory to the paging file. Manipulation of physical memory by the kernel is completely transparent to applications, which operate only in their virtual address spaces.

The pages of a process's virtual address space can be in one of the following states.

State	Description
Free	A free page is not currently accessible, but it is available to be committed or reserved.
Reserved	A reserved page is a block of the process's virtual address space that has been set aside for future use. The process cannot access a reserved page, and there is no physical storage associated with it. A reserved page reserves a range of virtual addresses that cannot be used subsequently by other allocation operations (that is, by functions such as malloc, LocalAlloc, and so on). A process can use the VirtualAlloc function to reserve pages of its address space and later to commit the reserved pages. It can use the VirtualFree function to release them.
Committed	A committed page is one for which physical storage (in memory or on disk) has been allocated. It can be protected to allow either no access or read-only access, or it can have read and write access. A process can use the VirtualAlloc function to allocate committed pages. The GlobalAlloc and LocalAlloc functions allocate committed pages with read-write access. A committed page allocated by VirtualAlloc can be decommitted by the VirtualFree function, which releases the page's storage and changes the state of the page to reserved.


Global and Local Functions

A process can use the GlobalAlloc and LocalAlloc functions to allocate memory. In the linear 32-bit environment of the Win32 API, the local heap and the global heap are not distinguished. As a result, there is no difference between the memory objects allocated by these functions.

Memory objects allocated by GlobalAlloc and LocalAlloc are in private, committed pages with read-write access. Private memory cannot be accessed by other processes. Memory allocated by using GlobalAlloc with the GMEM_DDESHARE flag is not actually shared globally as it is in Windows version 3. x. However, this flag is available for compatibility purposes and can be used by some applications to enhance the performance of dynamic data exchange (DDE) operations. Applications requiring shared memory for other purposes must use file-mapping objects. Multiple processes can map a view of the same file-mapping object to provide named shared memory. For more information about file mapping, see File Mapping and Shared Memory.

By using GlobalAlloc and LocalAlloc, you can allocate a block of memory of any size that can be represented by 32 bits. You are limited only by the available physical memory, including storage in the paging file on disk. These functions, along with the other global and local functions that manipulate global and local memory objects, are included in the Win32 API for compatibility with 16-bit versions of Windows. However, the change from a 16-bit segmented memory model to a 32-bit virtual memory model has made some of the functions and their options unnecessary or meaningless. For example, there are no longer near and far pointers, because both local and global allocations return 32-bit virtual addresses.

Both GlobalAlloc and LocalAlloc can allocate fixed or movable memory objects. Movable objects can also be marked as discardable. In earlier versions of Windows, movable memory objects were important for memory management. They enabled the system to compact the heap when necessary to make space available for other memory allocations. By using virtual memory, the system is able to manage memory by moving pages of physical memory without affecting the virtual addresses of the processes using the pages. When the system moves a page of physical memory, it simply maps the process's virtual page to the new location of the physical page. Movable memory is still useful for allocating discardable memory. When the system needs additional physical storage, it can use a "least recently used" algorithm to free discardable memory that is not locked. Discardable memory should be used for data that is needed infrequently and can be regenerated easily.

When allocating a fixed memory object, GlobalAlloc and LocalAlloc return a 32-bit pointer that the calling process can immediately use to access the memory. For movable memory, the return value is a handle. To get a pointer to a movable memory object, the calling process uses the GlobalLock and LocalLock functions. These functions lock the memory so that it cannot be moved or discarded. The internal data structures for each memory object include a lock count that is initially zero. For movable memory objects, GlobalLock and LocalLock increment the count by one, and the GlobalUnlock and LocalUnlock functions decrement the count by one. Locked memory is not moved or discarded, unless the memory object is reallocated by using the GlobalReAlloc or LocalReAlloc function. The memory block of a locked memory object remains locked in memory until its lock count is decreased to zero, at which time it can be moved or discarded.

The actual size of the memory allocated by GlobalAlloc or LocalAlloc can be larger than the requested size. To determine the actual number of bytes allocated, use the GlobalSize or LocalSize function. If the amount allocated is greater than the amount requested, the process can use the entire amount.

The GlobalReAlloc and LocalReAlloc functions change the size, in bytes, or the attributes of a memory object allocated by GlobalAlloc and LocalAlloc. The size can increase or decrease.

The GlobalFree and LocalFree functions release memory allocated by GlobalAlloc, LocalAlloc, GlobalReAlloc, or LocalReAlloc.

Other global and local functions include the GlobalDiscard, LocalDiscard, GlobalFlags, LocalFlags, GlobalHandle, and LocalHandle functions. To discard a specified discardable memory object without invalidating the handle, use GlobalDiscard or LocalDiscard. The handle can be used later by GlobalReAlloc or LocalReAlloc to allocate a new block of memory associated with the same handle. To return information about a specified memory object, use GlobalFlags or LocalFlags. The information includes the object's lock count and indicates whether the object is discardable or has already been discarded. To return the handle of the memory object associated with a specified pointer, use GlobalHandle or LocalHandle.


Standard C Library Functions

Win32 processes can safely use the standard C library functions (malloc, free, and so on) to manipulate memory. When used with previous versions of Windows, these functions had potential problems that no longer apply to applications using the Win32 API. For example, malloc allocates a fixed pointer that does not take advantage of movable memory. Memory management is no longer a problem because the system is free to manage memory by moving pages of physical memory without affecting the virtual addresses. Similarly, the distinction between near and far pointers is no longer relevant. So, unless you want to allocate discardable memory, it is now reasonable to use the standard C library functions for memory management.


Virtual Memory Functions

The Win32 API provides a set of virtual memory functions that enable a process to manipulate or determine the status of pages in its virtual address space. Many applications are able to satisfy their memory needs by using the standard allocation functions (GlobalAlloc, LocalAlloc, malloc, and so on). However, virtual memory functions provide some capabilities not available to the standard allocation functions. They can perform the following operations:

•	Reserve a range of a process's virtual address space. Reserving address space does not allocate any physical storage, but it prevents other allocation operations from using the specified range. It does not affect the virtual address spaces of other processes. Reserving pages prevents needless consumption of physical storage, while enabling a process to reserve a range of its address space into which a dynamic data structure can grow. The process can allocate physical storage for this space, as needed.

•	Commit a range of reserved pages in a process's virtual address space so that physical storage (either in RAM or on disk) is accessible only to the allocating process.

•	Specify read-write, read-only, or no access for a range of committed pages. This differs from the standard allocation functions that always allocate pages with read-write access.

•	Free a range of reserved pages, making the range of virtual addresses available for subsequent allocation operations by the calling process.

•	Decommit a range of committed pages, releasing their physical storage and making it available for subsequent allocation by any process.

•	Lock one or more pages of committed memory into physical memory (RAM) so that the system cannot swap the pages out to the paging file.

•	Obtain information about a range of pages in the virtual address space of the calling process or a specified process.

•	Change the access protection for a specified range of committed pages in the virtual address space of the calling process or a specified process.

The virtual memory functions manipulate pages of memory. The functions use the size of a page on the current computer to round off specified sizes and addresses.

To determine the size of a page on the current computer, use the GetSystemInfo function.

The VirtualAlloc function performs one of the following operations:

•	Reserves one or more free pages.

•	Commits one or more reserved pages.

•	Reserves and commits one or more free pages.

You can specify the starting address of the pages to be reserved or committed, or you can allow the system to determine the address. The function rounds the specified address to the appropriate page boundary. Reserved pages are not accessible, but committed pages can be allocated with the PAGE_READWRITE, PAGE_READONLY, or PAGE_NOACCESS flag. When pages are committed, storage is allocated in the paging file, but each page is initialized and loaded into physical memory only at the first attempt to read from or write to that page. You can use normal pointer references to access memory committed by the VirtualAlloc function.

The VirtualFree function performs one of the following operations:

•	Decommits one or more committed pages, changing the state of the pages to reserved. Decommitting pages releases the physical storage associated with the pages, making it available to be allocated by any process. Any block of committed pages can be decommitted.

•	Releases a block of one or more reserved pages, changing the state of the pages to free. Releasing a block of pages makes the range of reserved addresses available to be allocated by the process. Reserved pages can be released only by freeing the entire block that was initially reserved by VirtualAlloc.

•	Decommits and releases a block of one or more committed pages simultaneously, changing the state of the pages to free. The specified block must include the entire block initially reserved by VirtualAlloc, and all of the pages must be currently committed.

The VirtualLock function enables a process to lock one or more pages of committed memory into physical memory (RAM), preventing the system from swapping the pages out to the paging file. It can be used to ensure that critical data is accessible without disk access. Locking pages into memory is dangerous because it restricts the system's ability to manage memory. Excessive use of VirtualLock can degrade system performance by causing executable code to be swapped out to the paging file. The VirtualUnlock function unlocks memory locked by VirtualLock.

The VirtualQuery and VirtualQueryEx functions return information about a region of consecutive pages beginning at a specified address in the address space of a process. VirtualQuery returns information about memory in the calling process. VirtualQueryEx returns information about memory in a specified process and is used to support debuggers that need information about a process being debugged. The region of pages is bounded by the specified address rounded down to the nearest page boundary. It extends through all subsequent pages with the following attributes in common:

•	The state of all pages is the same: either committed, reserved, or free.

•	If the initial page is not free, all pages in the region are part of the same initial allocation of pages that were reserved by a call to VirtualAlloc.

•	The access protection of all pages is the same (that is, the PAGE_READONLY, PAGE_READWRITE, or PAGE_NOACCESS flag).

The VirtualProtect function enables a process to modify the access protection of any committed page in the address space of a process. For example, a process can allocate read-write pages to store sensitive data, and then it can change the access to read only or no access to protect against accidental overwriting. VirtualProtect is typically used with pages allocated by VirtualAlloc, but it also works with pages committed by any of the other allocation functions. However, VirtualProtect changes the protection of entire pages, and pointers returned by the other functions are not necessarily aligned on page boundaries. The VirtualProtectEx function is similar to VirtualProtect, except it changes the protection of memory in a specified process. Changing the protection is useful to debuggers in accessing the memory of a process being debugged.


Heap Functions

The heap functions enable a process to create a private heap, a block of one or more pages in the address space of the calling process. The process can then use a separate set of functions to manage the memory in that heap. There is no difference between memory allocated from a private heap and that allocated by using the standard allocation functions (GlobalAlloc, LocalAlloc, malloc, and so on).

The HeapCreate function creates a private heap object from which the calling process can allocate memory blocks by using the HeapAlloc function. HeapCreate specifies both an initial size and a maximum size for the heap. The initial size determines the number of committed, read-write pages initially allocated for the heap. The maximum size determines the total number of reserved pages. These pages create a contiguous block in the virtual address space of a process into which the heap can grow. Additional pages are automatically committed from this reserved space if requests by HeapAlloc exceed the current size of committed pages, assuming that the physical storage for it is available. Once the pages are committed, they are not decommitted until the process is terminated or until the heap is destroyed by calling the HeapDestroy function.

The memory of a private heap object is accessible only to the process that created it. If a dynamic-link library (DLL) creates a private heap, it does so in the address space of the process that called the DLL. It is accessible only to that process.

The HeapAlloc function allocates a specified number of bytes from a private heap and returns a pointer to the allocated block. The pointer identifies the block for the HeapFree function to release or for the HeapSize function to determine the size.

Memory allocated by HeapAlloc is not movable. Because the system cannot compact a private heap, the heap can become fragmented.

A possible use for the heap functions is to create a private heap when a process starts up, specifying an initial size sufficient to satisfy the memory requirements of the process. If the call to the HeapCreate function fails, the process can terminate or notify the user of the memory shortage; if it succeeds, however, the process is assured of having the memory it needs.


Shared Memory

In the Win32 API, shared memory is implemented by file mapping. All memory allocated by the other allocation methods (the GlobalAlloc, LocalAlloc, HeapAlloc, or VirtualAlloc function) is accessible only to the calling process. Memory allocated by a DLL, however, is in the address space of the process that called the DLL and is not accessible to other processes using the same DLL.

Named file mapping provides an easy way to create a block of shared memory. A process can specify a name when it uses the CreateFileMapping function to create a file-mapping object. Other processes can specify the same name to either the CreateFileMapping or OpenFileMapping function to obtain a handle of the mapping object. The names of event objects, semaphore objects, mutex objects, and file-mapping objects share the same name space. If a specified name matches the name of an existing object of a different type, an error occurs. When creating named objects, try to use unique names and check the function return values for duplicate name errors.

Each process specifies its handle of the file-mapping object in the MapViewOfFile function to map a view of the file into its own address space. The views of all processes for a single file-mapping object are mapped into the same sharable pages of physical storage. However, the virtual addresses of the mapped views can vary from one process to another, unless the MapViewOfFileEx function is used to map the view at a specified address. Although sharable, the pages of physical storage used for a mapped file view are not global; they are not accessible to processes that have not mapped a view of the file.

A file-mapping object is associated with a disk file that the system uses when the mapped view is swapped out of physical memory and onto the disk. This disk swap file can be the system's paging file, or it can be some other file that was specified when the file-mapping object was created. In that case, the memory is initialized along with the contents of the file. Mapping a specified file in the file system is useful for processes that need to share the data in an existing file or that want to use the file to save data generated by the sharing processes. If you map a specified file, you should open it for exclusive access and keep the handle open until you are finished with the shared memory. Keeping it open will prevent other processes from opening another handle on the file to use ReadFile or WriteFile or from creating additional mapping objects for the same file, any of which actions can lead to unpredictable results.

Any pages committed by mapping a view of a file are released when the last process with a view of the mapping object either terminates or unmaps its view by calling the UnmapViewOfFile function. At this time, the specified file (if any) associated with the mapping object is updated. A specified file can also be forced to update by calling the FlushViewOfFile function.

For more information about file mapping, see File Mapping. For an example of shared memory in a DLL, see Dynamic-Link Libraries.

If multiple processes have write access to shared memory, access to the memory should be synchronized. For more information about interprocess synchronization, see Synchronization.


Access Validation

The Win32 API provides a set of functions that a process can use to verify whether it has a specified type of access to a given memory address or range of addresses. The following access validation functions are available.

Function	Description
IsBadCodePtr	Determines whether the calling process has read access to the memory at the specified address.
IsBadReadPtr	Determines whether the calling process has read access to the memory at a specified range of addresses.
IsBadStringPtr	Determines whether the calling process has read access to the memory pointed to by a null-terminated string pointer. The function validates access for a specified number of characters or until it encounters the string's terminating null character.
IsBadWritePtr	Determines whether the calling process has write access to the memory at a specified range of addresses.
The IsBadHugeReadPtr and IsBadHugeWritePtr functions are also available for compatibility with earlier versions of Windows that distinguished between normal memory allocations and huge allocations occupying multiple segments. In the Win32 API, these functions are equivalent to IsBadReadPtr and IsBadWritePtr.

In a preemptive multitasking environment, it is possible for some other thread to change the process's access to the memory being tested. Even when an access validation function indicates that the process has the desired access to the specified memory, you should use structured exception handling when attempting to access the memory. Use of structured exception handling enables the system to notify the process if an access violation exception occurs, giving the process an opportunity to handle the exception. For more information about structured exception handling, see Structured Exception Handling.


Guard Pages

An application establishes a guard page by setting a memory page's PAGE_GUARD page protection modifier flag. This flag can be specified, along with other page protection flags, in the functions VirtualAlloc, VirtualProtect, and VirtualProtectEx. The PAGE_GUARD flag can be used with any other page protection flag, except for the NO_ACCESS flag.

If a program attempts to access an address within a guard page, the operating system raises a STATUS_GUARD_PAGE (0x80000001) exception. The operating system also clears the PAGE_GUARD flag, removing the memory page's guard page status. The system will not stop the next attempt to access the memory page with a STATUS_GUARD_PAGE exception.

If a guard page exception occurs during a system service, the service fails and typically returns some failure status indicator. Since the system also removes the relevant memory page's guard page status, the next invocation of the same system service won't fail due to a STATUS_GUARD_PAGE exception (unless, of course, someone reestablishes the guard page).

A guard page thus provides a one-shot alarm for memory page access. This can be useful for an application that needs to monitor the growth of large dynamic data structures. For example, there are operating systems that use guard pages to implement automatic stack checking.

The following short program illustrates the one-shot behavior of guard page protection, and how it can cause a system service to fail:

#include <windows.h>

#include <stdio.h>

#include <stdlib.h>

int main()

{

// local variables

LPVOID lpvAddr;

DWORD cbSize;

BOOL vLock;

LPVOID commit;

// amount of memory we'll allocate

cbSize = 512;

// try to allocate some memory

lpvAddr = VirtualAlloc(NULL,cbSize,MEM_RESERVE,PAGE_NOACCESS);

// if we failed ...

if(lpvAddr == NULL)

fprintf(stdout,"VirtualAlloc failed on RESERVE with %ld\n",

GetLastError());

// try to commit the allocated memory

commit = VirtualAlloc(NULL,cbSize,MEM_COMMIT,PAGE_READONLY|PAGE_GUARD);

// if we failed ...

if(commit == NULL)

fprintf(stderr,"VirtualAlloc failed on COMMIT with %ld\n",

GetLastError());

else  // we succeeded

fprintf(stderr,"Committed %lu bytes at address %lp\n",

cbSize,commit);

// try to lock the committed memory

vLock = VirtualLock(commit,cbSize);

// if we failed ...

if(!vLock)

fprintf(stderr,"Cannot lock at %lp, error = %lu\n",

commit,GetLastError());

else  // we succeeded

       fprintf(stderr,"Lock Achieved at %lp\n",commit);

// try to lock the committed memory again

vLock = VirtualLock(commit,cbSize);

// if we failed ...

if(!vLock)

fprintf(stderr,"Cannot get 2nd lock at %lp, error = %lu\n",

commit,GetLastError());

else  // we succeeded

fprintf(stderr,"2nd Lock Achieved at %lp\n",commit);

} // endof function

The output of this program looks like this:

Committed 512 bytes at address 003F0000

Cannot lock at 003F0000, error = 0x80000001

2nd Lock Achieved at 003F0000

Note that the first attempt to lock the memory block fails, raising a STATUS_GUARD_PAGE exception. The second attempt succeeds, because the memory block's guard page protection has been toggled off by the first attempt.


Using the Virtual Memory Functions

This section explains how to use the virtual memory functions for dynamic allocation.

The following example illustrates the use of the VirtualAlloc and VirtualFree functions in reserving and committing memory as needed for a dynamic array. First, VirtualAlloc is called to reserve a block of pages with NULL specified as the base address parameter, forcing the kernel to determine the location of the block. Later, VirtualAlloc is called whenever it is necessary to commit a page from this reserved region, and the base address of the next page to be committed is specified.

The example uses try-except structured exception-handling syntax to commit pages from the reserved region. Whenever a page fault exception occurs during the execution of the try block, the filter function in the expression preceding the except block is executed. If the filter function can allocate another page, execution continues in the try block at the point where the exception occurred. Otherwise, the exception handler in the except block is executed. For more information about structured exception handling, see Structured Exception Handling.

As an alternative to dynamic allocation, the process can simply commit the entire region instead of only reserving it. However, committing the region consumes physical storage that might not be needed, making it unavailable for use by other processes.

The example uses VirtualFree to free the reserved and committed pages when it is finished with them. The function is called twice: first to decommit the committed pages and again to release the entire region of reserved pages.

#define PAGELIMIT 80

#define PAGESIZE 0x1000

INT PageFaultExceptionFilter(DWORD);

VOID MyErrorExit(LPTSTR);

LPTSTR lpNxtPage;

DWORD dwPages = 0;

VOID UseDynamicVirtualAlloc(VOID) {

  LPVOID lpvBase;

  LPTSTR lpPtr;

  BOOL bSuccess;

  DWORD i;

  /* Reserve pages in the process's virtual address space. */

  lpvBase = VirtualAlloc(

         NULL,               /* system selects address   */

         PAGELIMIT*PAGESIZE, /* size of allocation       */

         MEM_RESERVE,        /* allocates reserved pages */

         PAGE_NOACCESS);     /* protection = no access   */

  if (lpvBase == NULL )

      MyErrorExit("VirtualAlloc reserve");

  lpPtr = lpNxtPage = (LPTSTR) lpvBase;

  /*

   * Use try-except structured exception handling when

   * accessing the pages. If a page fault occurs, the

   * exception filter is executed to commit another page

   * from the reserved block of pages.

   */

  for (i=0; i < PAGELIMIT*PAGESIZE; i++) {

      try {

          /* Write to memory. */

          lpPtr[i] = 'a';

      }

      /*

       * If there is a page fault, commit another page

       * and try again.

       */

      except ( PageFaultExceptionFilter(

                   GetExceptionCode() ) ) {

          /*

           * This is executed only if the filter function is

           * unsuccessful in committing the next page.

           */

          ExitProcess( GetLastError() );

      }

  }

  /* Release the block of pages when you are finished using them. */

  /* First, decommit the committed pages. */

  bSuccess = VirtualFree(

            lpvBase,          /* base address of block    */

            dwPages*PAGESIZE, /* bytes of committed pages */

            MEM_DECOMMIT);    /* decommit the pages       */

  /* Release the entire block. */

  if (bSuccess)

      bSuccess = VirtualFree(

            lpvBase,        /* base address of block     */

            0,              /* releases the entire block */

            MEM_RELEASE);   /* releases the pages        */

}

INT PageFaultExceptionFilter(DWORD dwCode) {

LPVOID lpvResult;

  /* If the exception is not a page fault, exit. */

  if (dwCode != EXCEPTION_ACCESS_VIOLATION) {

      printf("exception code = %d\n", dwCode);

      return EXCEPTION_EXECUTE_HANDLER;

  }

  printf("page fault\n");

  /* If the reserved pages are used up, exit. */

  if (dwPages >= PAGELIMIT) {

      printf("out of pages\n");

      return EXCEPTION_EXECUTE_HANDLER;

  }

  /* Otherwise, commit another page. */

  lpvResult = VirtualAlloc(

      (LPVOID) lpNxtPage, /* next page to commit  */

      PAGESIZE,           /* page size, in bytes  */

      MEM_COMMIT,         /* alloc committed page */

      PAGE_READWRITE);    /* read-write access    */

  if (lpvResult == NULL ) {

      printf("VirtualAlloc failed\n");

      return EXCEPTION_EXECUTE_HANDLER;

  }

  /*

   * Increment the page count, and advance lpNxtPage

   * to the next page.

   */

  dwPages++;

  lpNxtPage += PAGESIZE;

  /* Continue execution where the page fault occurred. */

  return EXCEPTION_CONTINUE_EXECUTION;

}


Memory Management Functions

Following are the Win32 functions used in memory management.

CopyMemory
FillMemory
GetProcessHeap
GetProcessHeaps
GlobalAlloc
GlobalDiscard
GlobalFlags
GlobalFree
GlobalHandle
GlobalLock
GlobalMemoryStatus
GlobalReAlloc
GlobalSize
GlobalUnlock
HeapAlloc
HeapCompact
HeapCreate
HeapDestroy
HeapFree
HeapLock
HeapReAlloc
HeapSize
HeapUnlock
HeapValidate
IsBadCodePtr
IsBadHugeReadPtr
IsBadHugeWritePtr
IsBadReadPtr
IsBadStringPtr
IsBadWritePtr
LocalAlloc
LocalDiscard
LocalFlags
LocalFree
LocalHandle
LocalLock
LocalReAlloc
LocalSize
LocalUnlock
MoveMemory
VirtualAlloc
VirtualFree
VirtualLock
VirtualProtect
VirtualProtectEx
VirtualQuery
VirtualQueryEx
VirtualUnlock
ZeroMemory

Obsolete or Deleted Functions

ChangeSelector
DefineHandleTable
FreeSelector
GetCodeInfo
GetFreeSpace
GlobalCompact
GlobalDosAlloc
GlobalDosFree
GlobalFix
GlobalLRUNewest
GlobalLRUOldest
GlobalNotify
GlobalPageLock
GlobalPageUnlock
GlobalUnfix
GlobalUnWire
GlobalWire
LimitEmsPages
LocalCompact
LocalInit
LocalShrink
LockSegment
SetSwapAreaSize
SwitchStackBack
SwitchStackTo
UnlockSegment


Performance Monitoring

Performance monitoring refers to the procedure for determining the system resources that an application consumes, such as processor time and memory.


About Performance Monitoring

An application developer can use the Microsoft® Win32® performance monitoring functions to determine whether an application uses system resources efficiently and to fine-tune its performance. These functions are especially helpful in evaluating the effects of changes as developers migrate Microsoft® Windows® version 3.x applications to Win32.


Counters and Elapsed Times

A counter is a general term used in programming to refer to an incrementing variable. Some systems include a high-resolution performance counter that provides high-resolution elapsed times. The elapsed time can be used to fine-tune sections of source code. Win32 provides two functions that enable application developers to obtain the value of a counter.

If a high-resolution performance counter exists on the system, the QueryPerformanceFrequency function can be used to express the frequency, in counts per second. The value of the count is processor dependent. On some processors, for example, the count might be the cycle rate of the processor clock.

The QueryPerformanceCounter function retrieves the current value of the high-resolution performance counter (if one exists on the system). By calling this function at the beginning and end of a section of code, an application essentially uses the counter as a stopwatch.

For example, QueryPerformanceFrequency might indicate that the frequency of the high-resolution performance counter on the system is 50,000 counts per second. If the application calls QueryPerformanceCounter immediately before and immediately after the section of code to be timed, the counter values might be 1500 counts and 3500 counts, respectively. These values would indicate that .04 seconds (2000 counts) elapsed while the code executed.


Registry Database

Windows includes several tools that monitor the system. To present data in a different format, to use data inside another application, or to create a performance monitor, an application must retrieve information through the registry. For more information about the registry, see Registry.


Getting Performance Data

An application can obtain system-performance information by using the RegQueryValueEx registry function with the HKEY_PERFORMANCE_DATA key. The application can use the RegOpenKey function to open the HKEY_PERFORMANCE_DATA handle, but it should use RegCloseKey to close the handle when it has finished running. This allows monitored software to be to be removed or installed, which cannot happen while they are being monitored. Network transports and drivers are examples of monitored software you may wish to remove.

Performance data is not stored in the registry. Using the RegQueryValueEx function with the HKEY_PERFORMANCE_DATA key causes the system to collect the data from the appropriate system object managers.

If an application is accessing a remote system, it must use the RegConnectRegistry function with the name of the remote system and the HKEY_PERFORMANCE_DATA key. RegConnectRegistry retrieves a key that the application can use with RegQueryValueEx to retrieve performance data from the remote system.

The basic layout of the data retrieved by RegQueryValueEx is a PERF_DATA_BLOCK structure followed by one PERF_OBJECT_TYPE structure and accompanying data for each type of object being monitored. The system being observed defines objects that can be monitored. Typical object types include processors, disks, and memory.

The PERF_DATA_BLOCK structure describes the system and the performance data. This structure contains the size of the data, the number of objects being monitored, the frequency and value of the high-resolution performance counter, an offset to the system name, and so on.

The PERF_OBJECT_TYPE structure describes the performance data for one type of object. This structure contains the size of the structure and the object-specific data that follows the structure, the number of counters defined for the object type, the number of instances of this object type, the level of informational details provided, the code page, indices to the object name and Explain title in the title database, and so on.

Following each PERF_OBJECT_TYPE structure, there is a list of PERF_COUNTER_DEFINITION structures, one for each counter defined for the object. The PERF_COUNTER_DEFINITION structure specifies the type and size of the counter, the offset to the counter, the detail level, the counter name, and Explain title in the registry, and so on.

An instance is a unique copy of a particular object type. The number of instances of a particular object type determines what follows the list of counter definitions. Not all object types have instances. A memory object, for example, has no instances because the system has only one memory. If the object type does not have instances, the counter definitions are followed by a single PERF_COUNTER_BLOCK structure and data for each counter. PERF_COUNTER_BLOCK contains the total length of the structure, in bytes, and the counter data that follows it.

If the object type has one or more instances, the list of counter definitions is followed by a PERF_INSTANCE_DEFINITION structure and a PERF_COUNTER_BLOCK structure for each instance. The PERF_INSTANCE_DEFINITION structure includes the name, identifier, and name of the parent of the instance. For example, the thread object type has instances; each thread in the system is an instance.

The number of object types, instances, and counters may vary from one call to the RegQueryValueEx function to another. Therefore, the number and size of structures included in the performance data as well as the size of the data that follows each structure may also vary. To ensure that it is receiving the appropriate information, an application must use the offsets included in the performance structures to navigate through the performance data. Every offset is relative to the beginning of the structure containing it.


Getting Descriptive Text

The names of the objects and counters, as well as the text that explains their meaning, can be obtained by calling the RegQueryValueEx function with hkey set to HKEY_PERFORMANCE_DATA and lpszValueName set to "Counter <langid>" or "Explain <langid>", where <langid> is a language identifier string. A language identifier string is the ASCII representation of a 3-digit hexadecimal language identifier. For example, the code for English is "009"; calling RegQueryValueEx with "Counter 009" will obtain the object names in English.

The 'Counter' and 'Explain' data are stored as MULTI_SZ strings. This type of data consists of a list of Unicode strings, each terminated with UNICODE_NULL. The last string is followed by an additional UNICODE_NULL.

The strings are listed in pairs. The first item is the Unicode string of the index contained in PERF_OBJECT_TYPE.ObjectNameTitleIndex or PERF_COUNTER_DEFINITION.CounterNameTitleIndex. The second item is the actual name of the index. Following is a fragment of the paired data:

2     System

4     Memory

6     % Processor Time

10    Read Operations/sec

12    Write Operations/sec

To retrieve a name or the Explain text for an item, an application should perform the following steps:

1.	If the system is remote, call the RegConnectRegistry function to establish a connection to the remote machine's registry.

2.	Call the RegQueryValueEx function, specifying either 'Counter <langid>' or 'Explain <langid>' as the name of the value to query. This provides MULTI_SZ data containing either the names of all the objects and counters, or Help information for all the objects and counters. Note that these query strings are case-sensitive.

If the call to RegQueryValueEx is successful, the return value is ERROR_SUCCESS, and the names are returned in the buffer pointed to by the function's lpbData parameter.

If the input buffer size is 0, the RegQueryValueEx return value is the buffer size needed to store the names.

If the input buffer size is too small, the RegQueryValueEx return value is ERROR_MORE_DATA.

If the specified language code is not installed in the system, the RegQueryValueEx return value is ERROR_FILE_NOT_FOUND.

Refer to RegQueryValueEx for further details on its operation.

3.	Convert the appropriate index (PERF_OBJECT_TYPE.ObjectNameTitleIndex, PERF_OBJECT_TYPE.ObjectHelpTitleIndex, PERF_COUNTER_DEFINITION.CounterNameTitleIndex, or PERF_COUNTER_DEFINITION.CounterHelpTitleIndex) into Unicode or ASCII, depending on whether the application is Unicode or ASCII.

4.	Search the MULTI_SZ data for the appropriate index.

5.	Retrieve the string following the matching index as the object's name or descriptive information.

See Displaying Object, Counter, and Instance Names and Displaying Counter Title Indices for sample code illustrating these tasks.


Getting Selected Data

When using the RegQueryValueEx function, an application must use the lpcbData parameter to specify a byte count of the amount of data to retrieve. Estimating this amount is difficult because the number of object types and their instances is determined by the system configuration and system activity. The amount may vary from one request to another. If the function does not pass enough space, the return value will be ERROR_MORE_DATA. Therefore, an application should include a retry loop in which it passes increasing amounts of buffer space until it no longer gets this error. The successful buffer size should be the starting point for subsequent calls to RegQueryValueEx.

In some cases, the application may not need to retrieve all the performance data provided by the system. Retrieving all of that data may be costly in terms of processor or memory requirements. The lpszValueName parameter of RegQueryValueEx indicates the amount of information to retrieve. This parameter can be in one of the following formats. The strings are case-sensitive. If a string includes more than one word, the words must be separated by a space.

String	Description
Global	The function returns all data for counters on the local computer except those included in the Costly category, described later in this table.
nnn xx yyy	Each of these strings is a Unicode string representing the decimal value for PERF_OBJECT_TYPE.ObjectNameTitleIndex. The function returns data only about the specified object types on the local computer.
	Note that more object types may be returned than are requested. This situation occurs if other object types are needed to support the requested data; for example, processes are needed to identify threads, so processes will also be returned even if only threads are requested.
Foreign ssss	The string ssss is the name of a foreign computer — that is, one that does not support the registry calls for returning data remotely. The function returns all data for counters on the foreign computer if your system is capable of collecting data from a foreign computer. This approach can be tried if RegConnectRegistry fails to connect to a foreign computer.
Foreign ssss nnn xx yyy	This format combines Foreign ssss and nnn xx yyy, discussed previously. The function returns all data for the specified counters on the foreign computer if the system is capable of collecting data from a foreign computer. An application can try this approach if RegConnectRegistry fails to connect to a foreign computer, but all of the available data is not wanted.
Costly	The function returns data for object types whose data is expensive to collect in terms of processor time or memory usage. A secondary thread may be started if an application needs to respond to the user during data collection.


Using Performance Monitoring

This section includes examples of code that display objects, counters, and Explain text for a system.

•	Displaying object, counter, and instance names

•	Displaying counter title indices


Displaying Object, Counter, and Instance Names

The example in this section shows how an application can display object, counter, and instance names.

#define UNICODE 1

#define _UNICODE 1

//

//  "C" Include files

//

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <malloc.h>

//

//  Windows Include files

//

#include <windows.h>

#include <winperf.h>

#include <tchar.h>

//

//  Local constants

//

#define RESERVED        0L       // reserved argument in fn. calls

#define INITIAL_SIZE    40960L   // initial perf data buff size

#define EXTEND_SIZE     4096L    // extend size of perf data buff

#define LINE_LENGTH     80       // display line length

#define WRAP_POINT       LINE_LENGTH-12   // wrap point for explain text

#define OBJECT_TEXT_INDENT  4    // indent of object explain text

//

//  Command line option values

//

#define COMMAND_ERROR      0

#define COMMAND_HELP       1

#define COMMAND_COUNTER    2

#define COMMAND_NOT_FOUND  3

//

//

//  Text string Constant definitions

//

const LPTSTR NamesKey = TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib");

const LPTSTR DefaultLangId = TEXT("009");

const LPTSTR Counters = TEXT("Counter ");

const LPTSTR Help = TEXT("Explain ");

const LPTSTR LastHelp = TEXT("Last Help");

const LPTSTR LastCounter = TEXT("Last Counter");

const LPTSTR Slash = TEXT("\\");

const LPTSTR Global = TEXT("Global");

//

//  Global Buffers

//

TCHAR   cValueName[LINE_LENGTH];  // used to store counter value string

CHAR    cExeName[LINE_LENGTH*2];  // used in processing command line

CHAR    cCtrName[LINE_LENGTH];    // used in processing command line

BOOL

StringToInt (

    IN  LPTSTR  InStr,

    OUT PDWORD  pdwOutInt

)

/*++

StringToInt

    Returns the decimal interpretation of the string in the InStr

    argument. Works for either Unicode or ANSI strings.

Arguments:

    InStr

        string to translate

    pdwOutInt

        base 10 version of the number in the InStr argument

Return Value:

    TRUE if conversion was successful

    FALSE if not

--*/

{

    // check for NULL pointers passed to function

    if ((!InStr) || (!pdwOutInt)) {

        SetLastError (ERROR_BAD_ARGUMENTS);

        return FALSE;

    }

    if ( (_stscanf (InStr, TEXT(" %d"), pdwOutInt)) == 1) {

        return TRUE;

    } else {

        return FALSE;

    }

} // StringToInt

VOID

DisplayCommandHelp (

)

/*++

DisplayCommandHelp

    displays usage of command line arguments

Arguments

    NONE

Return Value

    NONE

--*/

{

    printf ("\n\nPERFEX:");

    printf ("\n    Sample program to demonstrate Win32 Performance API");

    printf ("\n\nUsage:");

    printf ("\n\n     perfex [-? | counter]");

    printf ("\n\n          -?  Displays a list of all counter objects in the system");

    printf ("\n     counter  is the name of a counter object");

    printf ("\n                  and displays the performance counters for that object");

    printf ("\n");

} // DisplayCommandHelp

VOID

DisplayNotFound (

)

/*++

DisplayNotFound

    displays not found & usage of command line arguments

Arguments

    NONE

Return Value

    NONE

--*/

{

    printf ("\n*** Counter object not found in the system***\n");

    DisplayCommandHelp();        // display command line usage

} // DisplayNotFound

LPTSTR

*BuildNameTable(

    HKEY    hKeyRegistry,   // handle to registry db with counter names

    LPTSTR  lpszLangId,     // unicode value of Language subkey

    PDWORD  pdwLastItem     // size of array in elements

)

/*++

BuildNameTable

    Caches the counter names and explain text to accelerate name lookups

    for display.

Arguments:

    hKeyRegistry

        Handle to an open registry (this can be local or remote.) and

        is the value returned by RegConnectRegistry or a default key.

    lpszLangId

            The unicode id of the language to look up. (default is 009)

    pdwLastItem

            The last array element

Return Value:

    pointer to an allocated table.

    (the caller must free it when finished!)

    the table is an array of pointers to zero terminated TEXT strings.

    A NULL pointer is returned if an error occured. (error value is

    available using the GetLastError function).

    The structure of the buffer returned is:

        Array of pointers to zero terminated strings consisting of

            pdwLastItem elements

        MULTI_SZ string containing counter id's and names returned from

            registry for the specified language

        MULTI_SZ string containing explain text id's

            and explain text strings

            as returned by the registry for the specified language

    The structures listed above are contiguous so that they may be freed

    by a single "free" call when finished with them, however only the

    array elements are intended to be used.

--*/

{

    LPTSTR  *lpReturnValue;     // returned pointer to buffer

    LPTSTR  *lpCounterId;       //

    LPTSTR  lpCounterNames;  // pointer to Names buffer returned by reg.

    LPTSTR  lpHelpText ;     // pointet to exlpain buffer returned by reg.

    LPTSTR  lpThisName;         // working pointer

    BOOL    bStatus;            // return status from TRUE/FALSE fn. calls

    LONG    lWin32Status;       // return status from fn. calls

    DWORD   dwHelpItems;        // number of explain text items

    DWORD   dwCounterItems;     // number of counter text items

    DWORD   dwValueType;        // value type of buffer returned by reg.

    DWORD   dwArraySize;        // size of pointer array in bytes

    DWORD   dwBufferSize;       // size of total buffer in bytes

    DWORD   dwCounterSize;      // size of counter text buffer in bytes

    DWORD   dwHelpSize;         // size of help text buffer in bytes

    DWORD   dwThisCounter;      // working counter

    DWORD   dwLastId;           // largest ID value used by explain/counter text

    HKEY    hKeyValue;          // handle to Perflib entry in registry

    TCHAR   CounterNameBuffer[LINE_LENGTH]; // buffer conatining Counter query

    TCHAR   HelpNameBuffer[LINE_LENGTH]; // buffer conatining Help query

    BOOL    bClosePerformanceKey; // flag for closing HKEY_PERFORMANCE_DATA key

    //initialize data

    lpReturnValue = NULL;

    hKeyValue = NULL;

    bClosePerformanceKey = FALSE;

    // check for null arguments and insert defaults if necessary

    if (!lpszLangId) {

        lpszLangId = DefaultLangId;

    }

    // open handle to Perflib key in registry to get number of items

    // used in order to compute array and buffer sizes

    lWin32Status = RegOpenKeyEx (

        hKeyRegistry,

        NamesKey,

        RESERVED,

        KEY_READ,

        &hKeyValue);

    // on error, free buffers, close keys and return NULL pointer

    if (lWin32Status != ERROR_SUCCESS) {

        goto BNT_BAILOUT;

    }

    // query registry to get number of Explain text items

    dwBufferSize = sizeof (dwHelpItems);

    lWin32Status = RegQueryValueEx (

        hKeyValue,

        LastHelp,

        RESERVED,

        &dwValueType,

        (LPBYTE)&dwHelpItems,

        &dwBufferSize);

    if ((lWin32Status != ERROR_SUCCESS) || (dwValueType != REG_DWORD)) {

        goto BNT_BAILOUT;

    }

    // query registry to get number of counter and object name items

    dwBufferSize = sizeof (dwCounterItems);

    lWin32Status = RegQueryValueEx (

        hKeyValue,

        LastCounter,

        RESERVED,

        &dwValueType,

        (LPBYTE)&dwCounterItems,

        &dwBufferSize);

    if ((lWin32Status != ERROR_SUCCESS) || (dwValueType != REG_DWORD)) {

        goto BNT_BAILOUT;

    }

    // use the greater of Help items or Counter Items to size array

    if (dwHelpItems >= dwCounterItems) {

        dwLastId = dwHelpItems;

    } else {

        dwLastId = dwCounterItems;

    }

    // array size is # of elements (+ 1, since names are "1" based)

    // times the size of a pointer

    dwArraySize = (dwLastId + 1) * sizeof(LPTSTR);

    // build the Query strings for the specified language ID

    lstrcpy (CounterNameBuffer, Counters);

    lstrcat (CounterNameBuffer, lpszLangId);

    lstrcpy (HelpNameBuffer, Help);

    lstrcat (HelpNameBuffer, lpszLangId);

    // get size of counter names

    dwBufferSize = 0;

    lWin32Status = RegQueryValueEx (

        HKEY_PERFORMANCE_DATA,

        CounterNameBuffer,

        RESERVED,

        &dwValueType,

        NULL,

        &dwBufferSize);

    if (lWin32Status != ERROR_SUCCESS) goto BNT_BAILOUT;

    bClosePerformanceKey = TRUE;

    dwCounterSize = dwBufferSize;

    // get size of help text

    dwBufferSize = 0;

    lWin32Status = RegQueryValueEx (

        HKEY_PERFORMANCE_DATA,

        HelpNameBuffer,

        RESERVED,

        &dwValueType,

        NULL,

        &dwBufferSize);

    if (lWin32Status != ERROR_SUCCESS) goto BNT_BAILOUT;

    dwHelpSize = dwBufferSize;

    // allocate buffer with room for pointer array, counter name

    // strings and help name strings

    lpReturnValue = malloc (dwArraySize + dwCounterSize + dwHelpSize);

    if (!lpReturnValue) {

        lWin32Status = ERROR_OUTOFMEMORY;

        goto BNT_BAILOUT;

    }

    // initialize pointers into buffer

    lpCounterId = lpReturnValue;

    lpCounterNames = (LPTSTR)((LPBYTE)lpCounterId + dwArraySize);

    lpHelpText = (LPTSTR)((LPBYTE)lpCounterNames + dwCounterSize);

    // initialize the pointers to NULL

    for (dwBufferSize = 0; dwBufferSize <= dwLastId; dwBufferSize++) {

        lpCounterId[dwBufferSize] = NULL;

    }

    // read counter names into buffer. Counter names will be stored as

    // a MULTI_SZ string in the format of "###" "Name"

    dwBufferSize = dwCounterSize;

    lWin32Status = RegQueryValueEx (

        HKEY_PERFORMANCE_DATA,

        CounterNameBuffer,

        RESERVED,

        &dwValueType,

        (LPVOID)lpCounterNames,

        &dwBufferSize);

    if (lWin32Status != ERROR_SUCCESS) goto BNT_BAILOUT;

    // read explain text into buffer. Counter names will be stored as

    // a MULTI_SZ string in the format of "###" "Text..."

    dwBufferSize = dwHelpSize;

    lWin32Status = RegQueryValueEx (

        HKEY_PERFORMANCE_DATA,

        HelpNameBuffer,

        RESERVED,

        &dwValueType,

        (LPVOID)lpHelpText,

        &dwBufferSize);

    if (lWin32Status != ERROR_SUCCESS) goto BNT_BAILOUT;

    // load counter array items, by locating each text string

    // in the returned buffer and loading the

    // address of it in the corresponding pointer array element.

    for (lpThisName = lpCounterNames;

         *lpThisName;

         lpThisName += (lstrlen(lpThisName)+1) ) {

        // first string should be an integer

        //       (in decimal digit characters)

        // so translate to an integer for use in array

        //       element identification

        bStatus = StringToInt (lpThisName, &dwThisCounter);

        if (!bStatus) {

            // error is in GetLastError

            goto BNT_BAILOUT;  // bad entry

        }

        // point to corresponding counter name which follows the id number

        // string.

        lpThisName += (lstrlen(lpThisName)+1);

        // and load array element with pointer to string

        lpCounterId[dwThisCounter] = lpThisName;

    }

    // repeat the above for the explain text strings

    for (lpThisName = lpHelpText;

         *lpThisName;

         lpThisName += (lstrlen(lpThisName)+1) ) {

        // first string should be an integer (in decimal unicode digits)

        bStatus = StringToInt (lpThisName, &dwThisCounter);

        if (!bStatus) {

            // error is in GetLastError

            goto BNT_BAILOUT;  // bad entry

        }

        // point to corresponding counter name

        lpThisName += (lstrlen(lpThisName)+1);

        // and load array element;

        lpCounterId[dwThisCounter] = lpThisName;

    }

    // if the last item arugment was used,

    // then load the last ID value in it

    if (pdwLastItem) *pdwLastItem = dwLastId;

    // close the registry keys

    RegCloseKey (hKeyValue);

    RegCloseKey (HKEY_PERFORMANCE_DATA);

    // exit returning the pointer to the buffer

    return lpReturnValue;

BNT_BAILOUT:

    if (lWin32Status != ERROR_SUCCESS) {

        // if lWin32Status has error, then set last error value to it,

        // otherwise assume that last error already has value in it

        SetLastError (lWin32Status);

    }

    if (lpReturnValue) {

        free ((LPVOID)lpReturnValue);

    }

    if (bClosePerformanceKey == TRUE) RegCloseKey (HKEY_PERFORMANCE_DATA);

    if (hKeyValue) RegCloseKey (hKeyValue);

    return NULL;

} // BuildNameTable

DWORD

GetSystemPerfData (

    IN HKEY hKeySystem,

    IN LPTSTR   pValue,

    IN PPERF_DATA_BLOCK *pPerfData

)

/*++

GetSystemPerfData

    Allocates data buffer as required and queries performance data

    specified in pValue from registry.

Arguments

    hKeySystem

        Handle to performance data in registry

    pValue

        Value string to return from registry

    pPerfData

        address of pointer to allocated perf data block that is

        filled in by call to RegQueryValue.

Return Value

    ERROR_SUCCESS if data returned

    WIN 32 ERROR if error encountered

--*/

{  // GetSystemPerfData

    LONG     lError ;   // Win 32 Error returned by fn. calls

    DWORD    Size;      // size of data buffer passed to fn. call

    DWORD    Type;      // type of data buffer returned by fn. call

    // allocate initial buffer if one is not passed into this routine

    if (*pPerfData == NULL) {

        *pPerfData = malloc (INITIAL_SIZE);

        if (*pPerfData == NULL) {

            return ERROR_OUTOFMEMORY;

        }

    }

    while (TRUE) {

        Size = _msize (*pPerfData); // query the size of the data buffer

        lError = RegQueryValueEx (  // get performance data from reg.

            hKeySystem,

            pValue,

            RESERVED,

            &Type,

            (LPBYTE)*pPerfData,

            &Size) ;

        // check for success and valid perf data block signature

        if ((!lError) &&

            (Size > 0) &&

            (*pPerfData)->Signature[0] == (WCHAR)'P' &&

            (*pPerfData)->Signature[1] == (WCHAR)'E' &&

            (*pPerfData)->Signature[2] == (WCHAR)'R' &&

            (*pPerfData)->Signature[3] == (WCHAR)'F' ) {

            return (ERROR_SUCCESS) ;

        }

        // if buffer is not big enough, reallocate and try again

        if (lError == ERROR_MORE_DATA) {

            *pPerfData = realloc (

                *pPerfData,

                _msize (*pPerfData) +

                EXTEND_SIZE) ;

            if (!*pPerfData) {

                return (lError) ;

            }

        } else {

            return (lError) ;

        }

    }

}  // GetSystemPerfData

/*++

Pointer Functions

    These functions are used to walk down the various structures

    in the perf data block returned by the call to RegQueryValueEx

--*/

PPERF_OBJECT_TYPE

FirstObject (

    PPERF_DATA_BLOCK pPerfData

)

{

    return ((PPERF_OBJECT_TYPE) ((PBYTE) pPerfData + pPerfData->HeaderLength)) ;

}

PPERF_OBJECT_TYPE

NextObject (

    PPERF_OBJECT_TYPE pObject

)

{  // NextObject

    return ((PPERF_OBJECT_TYPE) ((PBYTE) pObject + pObject->TotalByteLength)) ;

}  // NextObject

PERF_COUNTER_DEFINITION *

FirstCounter(

    PERF_OBJECT_TYPE *pObjectDef

)

{

    return (PERF_COUNTER_DEFINITION *)

               ((PCHAR) pObjectDef + pObjectDef->HeaderLength);

}

PERF_COUNTER_DEFINITION *

NextCounter(

    PERF_COUNTER_DEFINITION *pCounterDef

)

{

    return (PERF_COUNTER_DEFINITION *)

               ((PCHAR) pCounterDef + pCounterDef->ByteLength);

}

PERF_INSTANCE_DEFINITION *

FirstInstance (

    PERF_OBJECT_TYPE    *pObject

)

{

    return (PERF_INSTANCE_DEFINITION *)

        ((PBYTE) pObject + pObject->DefinitionLength);

}

PERF_INSTANCE_DEFINITION *

NextInstance (

    PERF_INSTANCE_DEFINITION *pInstance

)

{

    // next instance is after

    //    this instance + this instances counter data

    PERF_COUNTER_BLOCK  *pCtrBlk;

    pCtrBlk = (PERF_COUNTER_BLOCK *)

        ((PBYTE)pInstance + pInstance->ByteLength);

    return (PERF_INSTANCE_DEFINITION *)

        ((PBYTE)pInstance + pInstance->ByteLength + pCtrBlk->ByteLength);

}

LONG

PrintExplainText(

    DWORD   Indent,

    LPTSTR  szTextString

)

/*++

PrintExplainText

    Prints Long strings in a wrapped format for display on screen

Arguments

    Indent

        number of characters to indent text from left margin

    szTextString

        string to print on stdout

ReturnValue

    number of lines of text printed

--*/

{

    LPTSTR  szThisChar;

    BOOL    bNewLine;

    DWORD   dwThisPos;

    DWORD   dwLinesUsed;

    szThisChar = szTextString;

    dwLinesUsed = 0;

    // check arguments

    if (!szTextString) {

        return dwLinesUsed;

    }

    if (Indent > WRAP_POINT) {

        return dwLinesUsed; // can't do this

    }

    bNewLine = TRUE;

    // print text

    while (*szThisChar) {

        if (bNewLine){

            for (dwThisPos = 0; dwThisPos < Indent; dwThisPos++) {

                printf (" ");

            }

            bNewLine = FALSE;

        }

        if ((*szThisChar == ' ') && (dwThisPos >= WRAP_POINT)) {

            printf ("\n");

            bNewLine = TRUE;

            // go to next printable character

            while (*szThisChar <= ' ') {

                szThisChar++;

            }

            dwLinesUsed++;

        } else {

            printf ("%c", *szThisChar);

            szThisChar++;

        }

        dwThisPos++;

    }

    printf ("\n");

    bNewLine = TRUE;

    dwLinesUsed++;

    return dwLinesUsed;

} // PrintExplainText

DWORD

ProcessCommandLine (

    IN LPTSTR  lpCmdLine,

    IN LPTSTR  *lppCounterNames,

    IN DWORD   dwLastCounter,

    OUT LPTSTR  *lpValueString

)

/*++

ProcesCommandLine

    Reads arguments in command line and determines

    what program should do.

    Command line syntax is:

        PERFEX [ ? | Object]

    if "?" is in command line, then list of counter objects is displayed

    if a text string (other than "?") then string is translated to a

    counter object id and the counters for that object are displayed

Arguments

    lpCmdLine

        null terminated string that contains command line arguments

    lppCounterNames

        pointer to array of counter names (used for lookup)

    dwLastCounter

        number of elements in CounterNames array

    lpValueString

        value string to send to ReqQueryValue in order to return counter

        data for specified counter

ReturnValue

    TRUE    if valid data is returned

    FALSE   if unable to process command line

            (command syntax help should be displayed).

--*/

{

    LPTSTR  lpLocalString;

    DWORD   dwReturnValue;

    DWORD   dwElem;

    TCHAR   LocalBuffer[100];

    INT     BufferSize;

    INT     Index;

    dwReturnValue = COMMAND_ERROR;  // assume error until

                                    // proven otherwise

    lpLocalString = lpCmdLine;

    // move pointer past exe name

    while ((*lpLocalString > TEXT(' ')) && (*lpLocalString)) lpLocalString++;

    // move pointer to next non-space char;

    while ((*lpLocalString <= TEXT(' ')) && (*lpLocalString)) lpLocalString++;

    if (*lpLocalString) {

        // check for "HELP" command line argument

        if (*lpLocalString == TEXT('-')) {

            if (*++lpLocalString == TEXT('?')) {

                *lpValueString = Global;

                dwReturnValue = COMMAND_HELP;

            }

        } else { // first arg is not preceded by a '-'

                 // so compare to counters

            // see if command line matches a counter name

            // duplicate the LocalString

            BufferSize = sizeof(LocalBuffer) / sizeof(TCHAR) - 1;

            for (Index=0; Index < BufferSize; Index++) {

               if (*lpLocalString == TEXT('\0') ||

                  *lpLocalString == TEXT(' ')){

                  LocalBuffer[Index] = TEXT('\0');

                  break;

               } else {

                  LocalBuffer[Index] = *lpLocalString++;

               }

            }

            LocalBuffer[BufferSize] = TEXT('\0');

            dwReturnValue = COMMAND_NOT_FOUND;

            for (dwElem = 0; dwElem <= dwLastCounter; dwElem++) {

                // compare counter name to command line

                if (lppCounterNames[dwElem]) {

                    if ((lstrcmpi(lppCounterNames[dwElem], LocalBuffer))

                          == 0) {

                        // match found

                        // make element Number a string and exit

                        _stprintf ((LPTSTR)&cValueName[0], TEXT("%d"), dwElem);

                        *lpValueString = (LPTSTR)&cValueName[0];

                        dwReturnValue = COMMAND_COUNTER;

                        break;  // out of for loop

                    } // endif command line matches string

                } // endif lppCounterNames[dwElem] not equal NULL

            } // end for loop that searches table

        } // if not "-?"

    } else {

        dwReturnValue = COMMAND_ERROR;

    }

    return dwReturnValue;

} // ProcessCommandLine

VOID

DisplayObjectNames (

    PPERF_DATA_BLOCK    pPerf,

    LPTSTR              *pNames

)

/*++

DisplayObjectNames

    Scans the perf data and prints the name of each object found in the

    list

Arguments

    pPerf

        pointer to the perf data block returned by the call to

        RegQueryValueEx

    pNames

        pointer to the name table containing the array of counter names

        and explain text pointers.

Return Value

    NONE

--*/

{

    DWORD       dwThisObject;   // count of objects

    PPERF_OBJECT_TYPE pThisObject;    // pointer to object structure

    printf ("\nThe available performance counter objects are:");

    // loop from first object in buffer returned and display the

    // number of objects in the buffer

    for (dwThisObject = 0, pThisObject = FirstObject (pPerf);

        dwThisObject < pPerf->NumObjectTypes;

        dwThisObject++, pThisObject = NextObject(pThisObject)) {

        printf ("\n\"%ws\"\n",

            pNames[pThisObject->ObjectNameTitleIndex]);

        PrintExplainText (OBJECT_TEXT_INDENT,

            pNames[pThisObject->ObjectHelpTitleIndex]);

    }

} // DisplayObjectNames

VOID

DisplayCounterData (

    PPERF_DATA_BLOCK    pPerf,

    LPTSTR              *pNames

)

/*++

DisplayCounterData

    Scans the perf data and prints the name of counter and

    instance found in the list

Arguments

    pPerf

        pointer to the perf data block returned by the call to

        RegQueryValueEx

    pNames

        pointer to the name table containing the array of counter names

        and explain text pointers.

Return Value

    NONE

--*/

{

    DWORD               dwThisObject;   // count of objects

    PPERF_OBJECT_TYPE   pThisObject;    // pointer to object structure

    DWORD               dwThisCounter;  // count of counters

    PPERF_COUNTER_DEFINITION    pThisCounter;

    LONG               lThisInstance;

    PPERF_INSTANCE_DEFINITION   pThisInstance;

    // for each object in buffer, display each counter and instance

    for (dwThisObject = 0, pThisObject = FirstObject (pPerf);

        dwThisObject < pPerf->NumObjectTypes;

        dwThisObject++, pThisObject = NextObject(pThisObject)) {

        printf ("\n\nThe object \"%ws\", ",

            pNames[pThisObject->ObjectNameTitleIndex]);

        // if there are instnances, then loop through all instances

        // of this object

        if (pThisObject->NumInstances != PERF_NO_INSTANCES) {

            printf (" which has the following instances:");

            for (lThisInstance = 0,

                 pThisInstance = FirstInstance(pThisObject);

                lThisInstance < pThisObject->NumInstances;

                lThisInstance++,

                pThisInstance = NextInstance(pThisInstance)) {

                printf ("\n\t\"%ws\"",

                    (LPWSTR)((PBYTE)pThisInstance

                     + pThisInstance->NameOffset));

            }

            printf ("\n");

        } else {

            printf (" which has only one occurance,");

        }

        // now display all counters described in this object

        printf ("\nand has the following counters:");

        for (dwThisCounter = 0,

             pThisCounter = FirstCounter (pThisObject);

            dwThisCounter < pThisObject->NumCounters;

            dwThisCounter++, pThisCounter = NextCounter(pThisCounter)) {

            printf ("\n    \"%ws\"",

                    pNames[pThisCounter->CounterNameTitleIndex]);

        }

    }

} // DisplayCounterData

int

_CRTAPI1 main(

    int argc,

    char *argv[]

)

/*++

main

    entry point to perfex

    This program illustrates how to:

        get performance counter names and explain text from the registry

        obtain counter object value strings for use

        in querying perf. data

        walk the performance data structures returned by the registry

    This program does not show how to:

        format or process the counter data returned

            the counter data returned by the registry depends on the

            counter type. This data must be processed and formatted by

            the application program.

Arguments

    argc

        # of command line arguments present

    argv

        array of pointers to command line strings

    (note that these are obtained from the GetCommandLine function in

    order to work with both Unicode and ANSI strings.)

ReturnValue

    0 (ERROR_SUCCESS) if command was processed

    Non-Zero if command error was detected.

--*/

{

    LPTSTR  *lpCounterText; // array of counter name strings

    LPTSTR  lpCommandLine;  // pointer to command line string

    LPTSTR  lpValueString;  // value string to pass to registry for data

    DWORD   dwLastElement;  // number of elements in lpCounterText

    PPERF_DATA_BLOCK  pDataBlock; // pointer to perfdata block

    DWORD   dwStatus;       // return status of fn. calls

    DWORD   dwAction;       // display mode indicated by command line

    // query counter names from registry and load into table

    lpCounterText = BuildNameTable (

        HKEY_LOCAL_MACHINE,

        DefaultLangId,

        &dwLastElement);

    if (!lpCounterText) {

        printf ("ERROR: Unable to read counter names from registry.");

        return (TRUE);

    }

    lpCommandLine = GetCommandLine(); // get command line

    // read command line to determine what to do

    dwAction = ProcessCommandLine (lpCommandLine,

        lpCounterText,

        dwLastElement,

        &lpValueString);

    if (dwAction == COMMAND_ERROR) { // if unable to read command line

        DisplayCommandHelp();        // display command line usage

        free (lpCounterText);        // free buffer and return error

        return (TRUE);

    } else if (dwAction == COMMAND_NOT_FOUND) {

        DisplayNotFound();           // display not found

                                     // & command line usage

        free (lpCounterText);        // free buffer and return error

        return (TRUE);

    } else {

        // of command requires processing, then get perf data from reg.

        pDataBlock = NULL;

        dwStatus = GetSystemPerfData (

            HKEY_PERFORMANCE_DATA,

            lpValueString,

            &pDataBlock);

        if (dwStatus != ERROR_SUCCESS) {

            printf ("\nERROR: Unable to obtain data for that counter");

            free (lpCounterText);

            return (dwStatus);

        } else {

            // if data was returned, then display in format requested by

            // command line

            if (dwAction == COMMAND_HELP) {

                // display object names returned from registry

                DisplayObjectNames (pDataBlock, lpCounterText);

            } else {

                // display counter data for specified object

                DisplayCounterData (pDataBlock, lpCounterText);

            }

        }

        free (lpCounterText);

        return (ERROR_SUCCESS); // success

    }

}


Displaying Counter Title Indices

This section includes example code that displays counter title indices and their names.

#define UNICODE 1

#define _UNICODE 1

#include <stdio.h>

#include <stdlib.h>

#include <assert.h>

#include <windows.h>

#include <string.h>

#include <memory.h>

#include <process.h>

#include <tchar.h>

#define SZ_DUMMY 10

int GetRegDataBound(HKEY hkey)

{

    TCHAR chDummy[SZ_DUMMY];

    DWORD cSubKeys;

    DWORD cbMaxSubkey;

    DWORD cbMaxClass;

    DWORD cValues;

    DWORD cbMaxValueName;

    DWORD cbMaxValueData;

    DWORD cbSecurityDescriptor;

    FILETIME ftLastWriteTime;

    DWORD lErr;

    DWORD cbClassSize = SZ_DUMMY;

    lErr = RegQueryInfoKey(hkey, chDummy, &cbClassSize,

        NULL, &cSubKeys, &cbMaxSubkey, &cbMaxClass,

        &cValues, &cbMaxValueName, &cbMaxValueData,

        &cbSecurityDescriptor, &ftLastWriteTime);

    if (lErr == ERROR_SUCCESS)

        return cbMaxValueData;

    else

        return -1;

}

int

_CRTAPI1 main(

)

{

    HKEY hKeyData;

    LONG lErr;

    LPTSTR lptstr;

    int   iSize;

    DWORD dwType;

    DWORD dwSize;

    int   iIndex;

    lErr = RegOpenKeyEx(HKEY_LOCAL_MACHINE,

TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Perflib\\009"),

        0, KEY_ALL_ACCESS, &hKeyData);

    assert(lErr == ERROR_SUCCESS);

    iSize = GetRegDataBound(hKeyData);

    if (iSize == -1)

        exit(-1);

    iSize++;

    lptstr = malloc(iSize * sizeof(TCHAR));

    dwSize = iSize;

    lErr = RegQueryValueEx(hKeyData, TEXT("Counters"), 0, &dwType,

        (LPBYTE) lptstr, &dwSize);

    assert(lErr == ERROR_SUCCESS);

    while (*lptstr) {

        _stscanf (lptstr, TEXT(" %d"), &iIndex);

//        iIndex = atoi(lptstr);

        lptstr += lstrlen(lptstr) + 1;

        printf("#define CNTR_%.3d\t \"%ws\"\n", iIndex, lptstr);

        lptstr += lstrlen(lptstr) + 1;

    }

    lErr = RegCloseKey(hKeyData);

    assert(lErr == ERROR_SUCCESS);

    return 0;

}


Performance Monitoring Functions

Following are the functions used for performance monitoring.

RegConnectRegistry
RegQueryValueEx
QueryPerformanceCounter
QueryPerformanceFrequency

Obsolete or Deleted Functions

ProfClear
ProfFinish
ProfFlush
ProfInsChk
ProfSampRate
ProfSetup
ProfStart
ProfStop


Pipes

A pipe is a communication conduit with two ends: a process with a handle to one end can communicate with a process having a handle to the other end. This overview describes how to create, manage, and use pipes.


About Pipes

Pipes can be one-way — where one end is read-only and the other end is write-only, or they can be two-way — where both ends of the pipe can read or write. The Microsoft® Win32® application programming interface (API) provides both anonymous (unnamed) pipes and named pipes.


Anonymous Pipes

An anonymous pipe is an unnamed, one-way pipe that transfers data between a parent process and a child process or between two child processes of the same parent process. Although it is possible to use anonymous pipes for communication between unrelated processes, it is easier to use named pipes for that purpose (for more information, see Named Pipes). Anonymous pipes are always local; they cannot be used for communication over a network.

The CreatePipe function creates an anonymous pipe and returns two handles, one to the read end and one to the write end of the pipe. The read handle has only read access to the pipe, and the write handle has only write access to the pipe. To communicate through the pipe, a handle to one of the ends must be passed to another process. Usually, this is done through inheritance; that is, a child process inherits a handle from its parent process. The inheritability of these handles is controlled by the creating process in the following ways:

•	The CreatePipe function specifies a SECURITY_ATTRIBUTES structure. If the bInheritHandle member of this structure is TRUE, the handles can be inherited.

•	The DuplicateHandle function can change the inheritability of a pipe handle. This function enables a process to create a noninheritable duplicate of an inheritable pipe handle or to create an inheritable duplicate of a noninheritable pipe handle.

•	The CreateProcess function enables a parent process to specify whether the new child process will inherit all or none of the parent's inheritable handles.

When a child process inherits a handle, the system enables the process to access the pipe referred to by that handle. However, the parent process must communicate the handle value to the child process. Typically, this is done by using the SetStdHandle and GetStdHandle functions, which set and retrieve the standard handles (standard input, standard output, or standard error) of a process. The parent process can specify a pipe handle in a call to SetStdHandle before the child process is created. The current standard handles of the parent process are inherited by the child process. So, when the child process starts up, it can use the GetStdHandle function to retrieve the handle value. The parent process can change its own standard handles without affecting the standard handles of its existing child processes.

To read from the pipe, a process uses the read handle in a call to the ReadFile function. Unless an error occurs, ReadFile does not return until the specified number of bytes has been read or until all handles to the write end of the pipe have been closed.

To write to the pipe, a process uses the write handle in a call to the WriteFile function. WriteFile does not return until the specified number of bytes has been written or an error occurs. If the pipe's buffer is full and bytes remain to be written, WriteFile does not return until some other process or thread reads from the pipe, making more buffer space available. CreatePipe enables the creating process to specify a buffer size for the pipe, or it can use the default buffer size.

Asynchronous (overlapped) read and write operations are not supported for anonymous pipes. This means that the ReadFileEx and WriteFileEx functions cannot be used with anonymous pipes. The lpOverLapped parameter of the ReadFile and WriteFile functions is ignored when used with an anonymous pipe.

An anonymous pipe exists until all handles to both read and write ends of the pipe are closed by the CloseHandle function.


Named Pipes

A named pipe is a one-way or two-way pipe for communicating between a server process and one or more client processes. A server process specifies a name when it calls the CreateNamedPipe function to create one or more instances of a named pipe. All instances of a named pipe share the same pipe name, but each instance has its own buffers and handles and provides a separate conduit for client-server communication. When a client process specifies a pipe name in the CreateFile or CallNamedPipe function, it connects to an instance of the pipe. The use of instances enables multiple client processes to use the same named pipe simultaneously.

Subject to security checks, any client process can access a named pipe, making it easy to communicate between related or unrelated processes. Named pipes can be used locally to communicate between processes on the same machine or across a network to connect processes on different machines.

In the Win32 API, the difference between client and server processes is greatly diminished, because any process can act as both a server and a client, making peer-to-peer communication possible. As used here, server refers to a process that uses CreateNamedPipe to create a named pipe, and client refers to a process that uses CreateFile or CallNamedPipe to connect to an instance of a named pipe.


Pipe Names

Each named pipe must have a unique name that distinguishes it from other named pipes. Use the following form when specifying the name of a pipe in the CreateNamedPipe, CreateFile, WaitNamedPipe, or CallNamedPipe function.

\\servername\pipe\pipename

The server process cannot create a pipe on a computer, so CreateNamedPipe must use a period to indicate the local computer as shown in this example.

\\.\pipe\pipename

Client processes using CreateFile, WaitNamedPipe, or CallNamedPipe can use a period to specify a local pipe, but they must specify the name of a server to open a pipe on a remote computer.

The pipename part of the name can include any character, including numbers and special characters. The entire pipe name string can be up to 256 characters long. Pipe names are not case-sensitive.


Named Pipe Modes

A number of modes associated with a named pipe or with a handle to a named pipe affect the use and behavior of the pipe. Some of these modes can be set differently for each handle to a pipe, while others must be the same for all handles to a pipe.

The server process specifies the following modes when it calls the CreateNamedPipe function. The type and access modes must be the same for all instances of a pipe.

Mode	Meaning
Type	PIPE_TYPE_BYTE or PIPE_TYPE_MESSAGE. The type mode determines whether data is written to a named pipe as a stream of messages or as a stream of bytes. If no type is specified in CreateNamedPipe, the default is PIPE_TYPE_BYTE. A handle to a byte pipe must be in byte-read mode. A handle to a message pipe can be in either byte-read or message-read mode. For more information about pipe types, see Named Pipe Type and Read Mode.
Access	PIPE_ACCESS_INBOUND, PIPE_ACCESS_OUTBOUND, or PIPE_ACCESS_DUPLEX. This mode is equivalent to specifying the read or write access of the server's handles to the pipe, where inbound is equivalent to GENERIC_READ access, outbound is equivalent to GENERIC_WRITE access, and duplex is equivalent to GENERIC_READ | GENERIC_WRITE access. Client processes using the CreateFile function to connect to a named pipe must specify an access compatible with the access specified by the server. For example, a client must specify GENERIC_READ access for an outbound pipe.
The remaining pipe modes can differ for each pipe handle. This means that the client and server ends of the same pipe instance can use different modes. CreateNamedPipe sets all of these modes for the pipe handles of a server. CreateFile supports setting the overlapped and write-through modes for the pipe handles of a client. Both client and server processes use the SetNamedPipeHandleState function to set the read and wait modes of a pipe handle.

Mode	Meaning
Read	PIPE_READMODE_BYTE or PIPE_READMODE_MESSAGE. In byte-read mode, data is read from a named pipe as a stream of bytes. In message-read mode, data is read from a named pipe as a stream of messages. Only byte-read mode is allowed for byte-type pipes. Either byte-read or message-read mode is allowed for message-type pipes. The default is byte-type mode, if no read mode is specified in CreateNamedPipe. For more information about read modes, see Named Pipe Type and Read Mode.
Wait	PIPE_WAIT or PIPE_NOWAIT. In blocking-wait mode, the ReadFile, WriteFile, and ConnectNamedPipe functions wait indefinitely  in some situations   for a process on the other end of the pipe to perform an action. In nonblocking-wait mode, the functions return if they cannot finish their operations immediately. For more information about wait modes, see Blocking and Nonblocking Pipe Operations.
Overlapped	FILE_FLAG_OVERLAPPED. In overlapped mode, functions performing read, write, and connect operations that take a significant time to be completed can return immediately. This enables the thread to perform other operations while a time-consuming operation executes in the background. For more information about overlapped mode, see Synchronous and Overlapped Input and Output.
Write-through	FILE_FLAG_WRITE_THROUGH. In write-through mode, the functions that write to a named pipe do not return until the data written is transmitted across the network and into the pipe's buffer on the remote computer. This mode affects only write operations on byte-type pipes and, then, only when the client and server processes are on different computers. If write-through mode is not enabled, a write function returns successfully, even if the data is not transmitted. For more information about write-through modes, see Write-through to Remote Clients.
The initial read mode for a pipe handle is specified when a server process calls CreateNamedPipe. If PIPE_READMODE_BYTE is specified or if no read mode is specified, the pipe handle is created in byte-read mode. If both PIPE_READMODE_MESSAGE and PIPE_TYPE_MESSAGE are specified, the handle is created in message-read mode. For a client process, a pipe handle returned by CreateFile is always in byte-read mode initially. Both client and server processes can use the SetNamedPipeHandleState function to change the read mode of a pipe handle. For a message-type pipe, the read mode can be different for server and client handles to the same pipe instance.


Named Pipe Operations

The first time the server calls CreateNamedPipe, the function specifies the maximum number of instances of the pipe that can exist simultaneously. Limited by this maximum, the server can call CreateNamedPipe repeatedly to create additional instances of the pipe. If the function succeeds, each call returns a handle to the server end of a named pipe instance.

As soon as a pipe instance is created, a client process can connect to it by calling the CreateFile or CallNamedPipe function. If a pipe instance is available, CreateFile returns a handle to the client end of the pipe instance. If no instances of the pipe are available, a client process can use the WaitNamedPipe function to wait for one to become available.

A client process can also use CallNamedPipe to combine into a single operation the functions that connect to a pipe instance (waiting for one to be available, if necessary), write a message, read a message, and close its pipe handle. CallNamedPipe can be used only by a client process and only with a message-type pipe.

A server process specifies a handle to a pipe instance in a call to the ConnectNamedPipe function to determine when a client process is connected to it. If the pipe handle is in blocking mode, the ConnectNamedPipe operation does not return until a client is connected.

Client and server processes can call one of several functions — in addition to CallNamedPipe — to read from and write to a named pipe. The behavior of these functions depends on the type of pipe and the modes in effect for the specified pipe handle, as follows:

•	The ReadFile and WriteFile functions can be used with either byte-type or message-type pipes.

•	The ReadFileEx and WriteFileEx functions can be used with either byte-type or message-type pipes if the pipe handle was opened for overlapped operations.

•	The PeekNamedPipe function can be used to read without removing the contents of either a byte-type pipe or a message-type pipe. PeekNamedPipe can also return additional information about the pipe instance.

•	The TransactNamedPipe function can be used with message-type pipes if the pipe handle of the calling process is set to message-read mode. The function writes a request message and reads a reply message in a single operation, enhancing network performance.

For a pipe handle in byte-read mode, a read operation is completed successfully when all available bytes in the pipe are read or when the specified number of bytes is read.

For a pipe handle in message-read mode, a ReadFile or ReadFileEx operation is completed successfully only when the entire message is read. If the specified number of bytes to read is less than the size of the next message, the function reads as much of the message as possible before returning FALSE (with the GetLastError function returning ERROR_MORE_DATA). However, the remainder of the message can be read by making additional calls to ReadFile, ReadFileEx, or PeekNamedPipe. Note that PeekNamedPipe returns TRUE after reading a complete or partial message, and it reports the number of bytes remaining in a partially read message.

For a message-type pipe with multiple unread messages, a read operation using a message-read pipe handle returns after reading one message. An operation using a byte-read handle does not distinguish between the messages — it reads all available bytes up to the specified number.

When a client and server finish using a pipe instance, the server calls the DisconnectNamedPipe function to close the connection to the client process. This function makes the client's handle invalid (if it has not already been closed). Any unread data in the pipe is discarded. To ensure that all bytes or messages written to the pipe are read by the client, the server first calls the FlushFileBuffers function, which does not return until the client has read all data from the pipe. After the client is disconnected, the server calls the CloseHandle function to close its handle to the pipe instance. Alternatively, the server can use ConnectNamedPipe to enable a new client to connect to this instance of the pipe.

A process can retrieve information about a named pipe by calling the GetNamedPipeInfo function, which returns the type of the pipe, the size of the input and output buffers, and the maximum number of pipe instances that can be created. The GetNamedPipeHandleState function reports on the read and wait modes of a pipe handle, the current number of pipe instances, and additional relevant information for pipes that communicate over a network. The SetNamedPipeHandleState function sets the read mode and wait modes of a pipe handle. For client processes communicating with a remote server, the function also controls the maximum number of bytes to collect or the maximum time to wait before transmitting a message (assuming the client's handle was not opened with write-through mode enabled).


Named Pipe Server Process

The simplest server process can use the CreateNamedPipe function to create a single instance of a pipe, connect to a single client, communicate with the client, disconnect the pipe, close the pipe handle, and terminate. Typically, however, a server process must communicate with multiple client processes. A server process can use a single pipe instance by connecting to and disconnecting from each client in sequence, but performance would be poor. To handle multiple clients simultaneously, the server process must create multiple pipe instances.

The Win32 API supports three basic strategies for servicing multiple pipe instances. The server process can perform the following tasks:

•	Create multiple threads (and/or processes) with a separate thread for each instance of the pipe. For an example of a multithreaded server process, see Multithreaded Server.

•	Overlap operations by specifying an OVERLAPPED structure in the ReadFile, WriteFile, and ConnectNamedPipe functions. For an example of a server process that uses overlapped operations, see Server Using Overlapped Input and Output.

•	Overlap operations by using the ReadFileEx and WriteFileEx functions, which specify a completion routine to be executed when the operation is complete. For an example of a server process that uses completion routines, see Server Using Completion Routines.

The multithreaded server strategy is easy to write, because the thread for each instance handles communications for only a single client. The system allocates processor time to each thread as needed. But each thread uses system resources, which is a potential disadvantage for a server that handles a large number of clients. Other complications occur if the actions of one client necessitate communications with other clients (as for a network game program, where a move by one player must be communicated to the other players).

With a single-threaded server, it is easier to coordinate operations that affect multiple clients, and it is easier to protect shared resources (for example, a database file) from simultaneous access by multiple clients. The challenge of a single-threaded server is that it requires coordination of overlapped operations in order to allocate processor time for handling the simultaneous needs of the clients.


Named Pipe Type and Read Mode

The type of a pipe determines how data is written to a named pipe, and the read mode determines how data is read from a named pipe. Data can be transmitted through a named pipe as either a stream of bytes or as a stream of messages. When using the CreateNamedPipe function to create an instance of a named pipe, the server process specifies the pipe's type, the type it must specify for all instances.

A byte-type pipe is created if PIPE_TYPE_BYTE is specified or, by default, if no type is specified. This means that data is written to the pipe as a stream of bytes, and the system does not differentiate between the bytes written in different write operations. A handle to a byte-type pipe can be in byte-read mode only.

A message-type pipe is created if PIPE_TYPE_MESSAGE is specified. This means that the system treats each write operation to the pipe as a message unit. A handle to a message-type pipe can be in either byte-read or message-read mode.


Blocking and Nonblocking Pipe Operations

The wait mode (blocking or nonblocking) of a pipe handle determines whether the ReadFile, WriteFile, and ConnectNamedPipe functions return immediately in situations that would otherwise require an indefinite wait. By default, all named pipe handles returned by the CreateNamedPipe or CreateFile function are created with blocking-wait mode enabled. Nonblocking-wait mode can be enabled for a server's pipe handle by specifying PIPE_NOWAIT in CreateNamedPipe. Both server and client processes can change a pipe handle's wait mode by specifying either PIPE_WAIT or PIPE_NOWAIT in a call to the SetNamedPipeHandleState function.

Note that nonblocking-wait mode is supported for compatibility with Microsoft® LAN Manager version 2.0, and it should not be used to achieve overlapped input and output (I/O) with named pipes. Overlapped I/O should be used instead because it enables time-consuming ReadFile, WriteFile, and ConnectNamedPipe operations to execute in the background after the function returns. For more information about overlapped I/O, see Synchronous and Overlapped Input and Output.

A ReadFile operation is affected by the wait mode of a pipe handle when the pipe is empty. With a blocking-wait handle, the operation is not completed successfully until data is available from a thread writing to the other end of the pipe. Using a nonblocking-wait handle, the function returns FALSE immediately, and the GetLastError function returns ERROR_NO_DATA.

A WriteFile operation is affected by a pipe handle's wait mode when there is insufficient space in the pipe's buffer to hold all the data. With a blocking-wait handle, the write operation cannot succeed until sufficient space is created in the buffer by a thread reading from the other end of the pipe. With a nonblocking-wait handle, the write operation returns TRUE immediately, without writing any bytes (for a message-type pipe) or after writing as many bytes as the buffer holds (for a byte-type pipe).

A ConnectNamedPipe operation is affected by the wait mode of a pipe handle when there is no client connected or waiting to connect to the pipe instance. With a blocking-wait handle, the connect operation does not succeed until a client process connects to the pipe instance by calling either the CreateFile or CallNamedPipe function. With a nonblocking-wait handle, the connect operation returns FALSE immediately, and the GetLastError function returns ERROR_PIPE_LISTENING.

The wait mode of a pipe handle does not affect read or write operations when using the TransactNamedPipe or CallNamedPipe function.


Synchronous and Overlapped Input and Output

The Win32 API supports both synchronous and asynchronous (overlapped) operations on named pipes. The ReadFile, WriteFile, TransactNamedPipe, and ConnectNamedPipe functions can run either synchronously or asynchronously. The ReadFileEx and WriteFileEx functions can run only asynchronously. When functions run synchronously, they do not return until the operation is finished. This means that the execution of the calling thread can be blocked for an indefinite period while it waits for a time-consuming operation to finish. When functions run asynchronously, they return immediately even before their operations are finished. This enables a time-consuming operation to be executed in the background while the calling thread is free to perform other tasks. In the Win32 API, asynchronous execution is known as overlapped I/O.

Overlapped operations make it possible for one pipe to read and write data simultaneously and for a single thread to perform simultaneous I/O operations on multiple pipe handles. This enables a single-threaded server process to handle communications with multiple client processes efficiently. For examples that illustrate overlapped operations by a server process, see Server Using Overlapped Input and Output and Server Using Completion Routines.

For a server process to use synchronous operations to communicate with more than one client, it must create a separate thread for each client process so that one or more threads can run while other threads are waiting. For an example of a multithreaded server process that uses synchronous operations, see Multithreaded Server.

Overlapped operations on a named pipe are enabled by specifying the FILE_FLAG_OVERLAPPED flag when the handle is created (by the CreateNamedPipe function for a server process or the CreateFile function for a client process). If this flag is not specified, overlapped mode is disabled. The overlapped mode of a pipe handle cannot be changed after the pipe handle has been created. The overlapped mode can be different for server and client handles to the same pipe instance.

The ReadFile, WriteFile, TransactNamedPipe, and ConnectNamedPipe functions can be performed asynchronously only if overlapped mode is enabled for the specified pipe handle and a valid pointer to an OVERLAPPED structure is specified. If the OVERLAPPED pointer is NULL, the system attempts to make the operation look synchronous. Depending on the number of pending operations, this attempt may or may not be successful. Therefore, it is strongly recommended that if you create a handle with FILE_FLAG_OVERLAPPED and want asynchronous behavior, you should always specify a valid OVERLAPPED structure or use the functions intended for asynchronous operations such as ReadFileEx and WriteFileEx.

When ReadFile, WriteFile, TransactNamedPipe, and ConnectNamedPipe are performed asynchronously, one of the following outcomes occurs:

•	If the operation is complete when the function returns, the return value indicates the success or failure of the operation. If an error occurs, the return value is FALSE and the GetLastError function returns something other than ERROR_IO_PENDING.

•	If the operation has not finished when the function returns, the return value is FALSE and GetLastError returns ERROR_IO_PENDING. In this case, the calling thread must wait until the operation has finished. The calling thread must then call the GetOverlappedResult function to determine the results.

The hEvent member of the specified OVERLAPPED structure must contain a handle to a manual-reset — not an auto-reset — event object. This is a synchronization object created by the CreateEvent function. The thread that initiates the overlapped operation uses the event object to determine when the operation is finished. For more information about event objects, see Synchronization.

An event object is either in a signaled or nonsignaled state. If an overlapped function returns before its operation has finished, the system sets the state of the event object to nonsignaled. When the operation is finished, the system sets the state to signaled. The thread can detect the object's state by specifying a handle to the event object in a call to one of the wait functions: WaitForSingleObject, WaitForMultipleObjects, WaitForSingleObjectEx, or WaitForMultipleObjectsEx. These functions do not return until the state of a specified object is signaled or until a time-out interval has elapsed. For the wait functions that wait for multiple objects, the function's return value indicates which of the objects is signaled. Doing this enables a server process to use a loop that performs the following steps:

1.	Specifies multiple event objects in a call to WaitForMultipleObjects or WaitForMultipleObjectsEx, and then waits for one of the objects to be in a signaled state.

2.	Uses the wait function's return value to determine which overlapped operation is finished.

3.	Performs the tasks necessary to clean up the completed operation and initiate the next operation for that pipe handle. This may involve starting another overlapped operation for the same pipe handle.

If the hEvent member of the OVERLAPPED structure is a NULL pointer instead of a handle to an event object, the calling thread can use the pipe handle to determine when an overlapped operation has finished. In this case, the system sets the state of the pipe handle to signaled or nonsignaled, as described previously for the state of an event object. It is strongly recommended that you always use an event object when performing overlapped operations rather than relying on the pipe handle. In particular, you should not use the pipe handle for this purpose when performing simultaneous operations on the same handle because there is no way of knowing which operation's completion caused the pipe handle to be signaled. The only safe technique for performing simultaneous operations on the same pipe handle is to use a separate OVERLAPPED structure with its own event object for each operation.

The ReadFileEx and WriteFileEx functions provide another form of overlapped I/O. Unlike the overlapped ReadFile and WriteFile functions, which use an event object to signal completion, the extended functions specify a completion routine. A completion routine is a function that is queued for execution when the read or write operation is finished. The completion routine is not executed until the thread that called ReadFileEx and WriteFileEx enters an alertable wait by calling one of the extended wait functions: WaitForSingleObjectEx, WaitForMultipleObjectsEx, or SleepEx. These functions are like the normal wait functions in that they return when a specified object is in the signaled state or when a time-out interval has elapsed. However, these functions can also perform an alertable wait that occurs when their fAlertable parameter is set to TRUE. In an alertable wait, the functions also return when a ReadFileEx or WriteFileEx completion routine is queued for execution. A server process can use the extended functions to perform a sequence of read and write operations for each client that connects to it. Each read or write operation in the sequence specifies a completion routine, and each completion routine initiates the next step in the sequence.


Write-through to Remote Clients

The write-through mode of a named pipe handle affects the behavior of byte-type pipes when data is transmitted across a network. To enable write-through mode for a named pipe handle, a process specifies the FILE_FLAG_WRITE_THROUGH flag in the CreateNamedPipe function for a server process or in the CreateFile function for a client process. If this flag is not specified, write-through mode is disabled. The write-through mode of a pipe handle cannot be changed after the pipe handle has been created. The write-through mode can be different for server and client handles to the same pipe instance.

If write-through mode is not enabled, the system enhances the efficiency of network operations by buffering data until a minimum number of bytes have accumulated or until a maximum time period has elapsed. Buffering enables multiple write operations to be combined into a single network transmission. This means that a write operation can be successfully completed after the data is in the outbound buffer but before it is transmitted across the network.

A client process can use the SetNamedPipeHandleState function to control the number of bytes and the time-out period before transmission for a pipe on which write-through mode is disabled.

If write-through mode is enabled, the transmission across the network is not delayed and the write operation is not completed until the data is in the pipe buffer on the remote machine. Write-through mode is useful for applications that require synchronization for every write operation.

The system always performs write operations on message-type pipes as if write-through mode were enabled.


Pipe Security

A server process uses the ImpersonateNamedPipeClient function to assume the security token of the client process connected to the specified pipe instance. This function can be useful in determining whether to grant the request of a client process. For example, a named pipe server can provide access to a database or file system to which the server process has privileged access. When a client process makes a request from the server, the client typically has some lesser level of security access. By assuming the security token of the client, the server can attempt to access the protected database. The system then grants or denies the server's access, based on the security level of the client. When the server is finished, it uses the RevertToSelf function to restore its original security token.


Using Pipes

Pipes are useful in applications that must pass a continuous stream of data between processes.

•	Anonymous pipes overview

•	Multithreaded server

•	Server using overlapped input and output

•	Server using completion routines

•	Named pipe client process

•	Transactions on named pipes


Anonymous Pipes Overview

A typical use of an anonymous pipe is to create a channel for communication between a parent process and its child process by redirecting the standard input or standard output handles of the child process. To redirect the standard output handle of a child process, the parent process performs the following steps:

1.	Calls the GetStdHandle function to get the current standard output handle, which it saves for later use.

2.	Calls the CreatePipe function to create an anonymous pipe. This function returns handles to the read and write ends of the pipe.

3.	Calls the SetStdHandle function to set its standard output to be the write handle of the pipe.

4.	Calls the CreateProcess function to create the child process. The child process inherits the inheritable handles of the parent process. It also inherits the values of the standard handles of its parent process, which it can retrieve using the GetStdHandle function.

5.	Calls the CloseHandle function to close the parent's handle to the write end of the pipe. After the child process inherits this handle, the parent process no longer needs its copy of the handle.

6.	Calls the ReadFile function to read from the pipe. This operation enables the parent process to read the data written to standard output by the child process.

The child process uses the GetStdHandle function to get its standard output handle, which is actually a handle to the write end of the pipe. The child process then uses the WriteFile function to write its output to the pipe.

Data is written to an anonymous pipe as a stream of bytes. This means that a process reading from a pipe cannot distinguish between the bytes written in separate write operations, unless both reading and writing processes use some protocol that lets the reading process know how many bytes to read. Typically, there is no protocol, so the reading process reads from the pipe until all write handles to the pipe are closed, which causes the ReadFile function to return FALSE. When a child process's standard output is redirected, the child process calls CloseHandle or terminates (which automatically closes the handle). Note that it is important for the parent process to close its handle to the write end of the pipe before trying to read from the pipe. Otherwise, its ReadFile operation cannot return FALSE because there is still an open handle to the write end of the pipe.

The procedure for redirecting standard input is similar to that for redirecting standard output, except that the pipe's read handle is used for the child's standard input. In this case, the parent process must ensure that the child process does not inherit the pipe's write handle. Otherwise, the ReadFile operation of the child process cannot return FALSE because the child process has an open handle to the write end of the pipe.

The parent process typically creates the read and write handles to the pipe so that they can be inherited by a child process. It does this by using CreatePipe, specifying a SECURITY_ATTRIBUTES structure with the bInheritHandle member set to TRUE. When a child's standard input is redirected, the child process should not inherit the pipe's write handle. The parent process prevents inheritance by using the DuplicateHandle function to create a noninheritable duplicate of the handle and then using CloseHandle to close the inheritable handle.

For an example program that uses anonymous pipes to redirect the standard handles of a child process, see Processes and Threads.


Multithreaded Server

This example of a multithreaded server process has a main thread that loops continuously, creating a pipe instance and waiting for a client process to connect. When a client process connects, the server process creates a thread to service that client and the loop starts over. It is possible for a client process to connect successfully to the pipe instance in the interval between calls to the CreateNamedPipe and ConnectNamedPipe functions. If this happens, ConnectNamedPipe returns FALSE, and GetLastError returns ERROR_PIPE_CONNECTED.

The thread created to service each pipe instance reads requests from the pipe and writes replies to the pipe until the client process closes its handle. When this happens, the thread flushes the pipe, disconnects, closes its pipe handle, and terminates.

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <windows.h>

VOID InstanceThread(LPVOID);

VOID GetAnswerToRequest(LPTSTR, LPTSTR, LPDWORD);

int xx = 0;

DWORD main(VOID) {

  BOOL fConnected;

  DWORD dwThreadId;

  HANDLE hPipe, hThread;

  LPTSTR lpszPipename = "\\\\.\\pipe\\mynamedpipe";

  /*

   * The main loop creates an instance of the named pipe and

   * then waits for a client to connect to it. When the client

   * connects, a thread is created to handle communications

   * with that client, and the loop is repeated.

   */

  for (;;) {

      hPipe = CreateNamedPipe(

          lpszPipename,             /* pipe name          */

          PIPE_ACCESS_DUPLEX,       /* read/write access  */

          PIPE_TYPE_MESSAGE |       /* message type pipe  */

          PIPE_READMODE_MESSAGE |   /* message-read mode  */

          PIPE_WAIT,                /* blocking mode      */

          PIPE_UNLIMITED_INSTANCES, /* max. instances     */

          BUFSIZE,                  /* output buffer size */

          BUFSIZE,                  /* input buffer size  */

          PIPE_TIMEOUT,             /* client time-out    */

          NULL);                    /* no security attr.  */

      if (hPipe == INVALID_HANDLE_VALUE)

          MyErrExit("CreatePipe");

      /*

       * Wait for the client to connect; if it succeeds,

       * the function returns TRUE. If the function returns FALSE,

       * GetLastError returns ERROR_PIPE_CONNECTED.

       */

      fConnected = ConnectNamedPipe(hPipe, NULL) ?

                   TRUE :

                   (GetLastError() == ERROR_PIPE_CONNECTED);

      if (fConnected) {

          /* Create a thread for this client. */

          hThread = CreateThread(

              NULL,           /* no security attr.    */

              0,              /* default stack size   */

              (LPTHREAD_START_ROUTINE) InstanceThread,

              (LPVOID) hPipe, /* thread parameter     */

              0,              /* not suspended        */

              &dwThreadId);   /* returns thread ID    */

          if (hThread == INVALID_HANDLE_VALUE)

              MyErrExit("CreateThread");

      } else

         /* The client could not connect, so close the pipe. */

         CloseHandle(hPipe);

  }

  return 1;

}

VOID InstanceThread(LPVOID lpvParam) {

  CHAR chRequest[BUFSIZE];

  CHAR chReply[BUFSIZE];

  DWORD cbBytesRead, cbReplyBytes, cbWritten;

  BOOL fSuccess;

  HANDLE hPipe;

  /* The thread's parameter is a handle to a pipe instance. */

  hPipe = (HANDLE) lpvParam;

  while (1) {

      /* Read client requests from the pipe. */

      fSuccess = ReadFile(

          hPipe,        /* handle to pipe         */

          chRequest,    /* buffer to receive data */

          BUFSIZE,      /* size of buffer         */

          &cbBytesRead, /* number of bytes read   */

          NULL);        /* not overlapped I/O     */

      if (! fSuccess || cbBytesRead == 0)

          break;

      GetAnswerToRequest(chRequest, chReply, &cbReplyBytes);

      /* Write the reply to the pipe. */

      fSuccess = WriteFile(

         hPipe,        /* handle to pipe           */

         chReply,      /* buffer to write from     */

         cbReplyBytes, /* number of bytes to write */

         &cbWritten,   /* number of bytes written  */

         NULL);        /* not overlapped I/O       */

      if (! fSuccess || cbReplyBytes != cbWritten) break;

  }

  /*

   * Flush the pipe to allow the client to read the pipe's contents

   * before disconnecting. Then disconnect the pipe, and close the

   * handle to this pipe instance.

   */

  FlushFileBuffers(hPipe);

  DisconnectNamedPipe(hPipe);

  CloseHandle(hPipe);

}


Server Using Overlapped Input and Output

This example is a single-threaded server process that uses overlapped operations to service simultaneous connections to multiple client processes. The server process creates a fixed number of pipe instances, each of which can be connected to a separate client process. When a client process has finished using its pipe instance, the server disconnects from the client and reuses the pipe instance to connect to a new client.

Associated with each pipe instance is an OVERLAPPED structure containing an event object. This structure is specified as a parameter in each ReadFile, WriteFile, and ConnectNamedPipe operation on the pipe instance. Although the example shows simultaneous operations on different pipe instances, it avoids simultaneous operations on a single pipe instance. Because the same event object is used for read, write, and connect operations for each instance, there is no way to know which operation's completion caused the event to be set to the signaled state for simultaneous operations using the same pipe instance.

The event handles for each pipe instance are also stored in an array used by the WaitForMultipleObjects function. This function waits for one of the events to be signaled, and its return value is the array index of the event that satisfied the wait. The example uses this index to retrieve a structure containing information for the pipe instance. The server uses the fPendingIO member of the structure to keep track of whether the most recent I/O operation on the instance was pending, necessitating a call to the GetOverlappedResult function. It uses the dwState member of the structure to determine the next operation that must be performed for the instance.

Overlapped ReadFile, WriteFile, and ConnectNamedPipe operations may have finished when the function returns, or they may still be pending when the function returns. If the operation is pending, the event object in the specified OVERLAPPED structure is set to the nonsignaled state before the function returns. When the pending operation has finished, the system sets the state of the event object to signaled. The state of the event object is not changed if the operation finishes before the function returns.

Because the example uses manual reset event objects, the state of the event objects is not changed to nonsignaled by the WaitForMultipleObjects function. This is important, because the example relies on the event objects remaining in the signaled state except when there is a pending operation.

If the operation is already finished when ReadFile, WriteFile, or ConnectNamedPipe returns, the function's return value indicates the result. For read and write operations, the number of bytes transferred is also returned. If the operation is still pending, the ReadFile, WriteFile, or ConnectNamedPipe function returns FALSE and the GetLastError function returns ERROR_IO_PENDING. In this case, the results are retrieved using the GetOverlappedResult function after the operation has finished. GetOverlappedResult returns only the results of operations that were pending, and does not report the results of operations that were completed before the overlapped ReadFile, WriteFile, or ConnectNamedPipe function returned.

Before disconnecting from a client, the multithreaded server example in the previous section used FlushFileBuffers to ensure that the client had read everything written to the pipe. This would defeat the purpose of overlapped I/O, because the flush operation would block the execution of the server thread while it waits for the client to empty the pipe. Consequently, it is necessary to wait for a signal from the client that it has finished before disconnecting. In this example, the signal is the error generated by trying to read from the pipe after the client process closes its handle.

#include <windows.h>

#define CONNECTING_STATE 0

#define READING_STATE 1

#define WRITING_STATE 2

#define INSTANCES 4

typedef struct {

  OVERLAPPED oOverlap;

  HANDLE hPipeInst;

  CHAR chBuf[BUFSIZE];

  DWORD cbToWrite;

  DWORD dwState;

  BOOL fPendingIO;

} PIPEINST, *LPPIPEINST;

VOID DisconnectAndReconnect(DWORD);

BOOL ConnectToNewClient(HANDLE, LPOVERLAPPED);

VOID GetDataToWriteToClient(LPPIPEINST);

PIPEINST Pipe[INSTANCES];

HANDLE hEvents[INSTANCES];

DWORD main(VOID) {

  DWORD i, dwWait, cbBytes, dwErr;

  BOOL fSuccess;

  LPTSTR lpszPipename = "\\\\.\\pipe\\mynamedpipe";

  /*

   * The initial loop creates several instances of a named pipe

   * along with an event object for each instance.  An

   * overlapped ConnectNamedPipe operation is started for

   * each instance.

   */

  for (i = 0; i < INSTANCES; i++) {

      /* Create an event object for this instance. */

      hEvents[i] = CreateEvent(

          NULL,    /* no security attr.        */

          TRUE,    /* manual-reset event       */

          TRUE,    /* initial state = signaled */

          NULL);   /* unnamed event object     */

      if (hEvents[i] == NULL)

          MyErrExit("CreateEvent");

      Pipe[i].oOverlap.hEvent = hEvents[i];

      Pipe[i].hPipeInst = CreateNamedPipe(

          lpszPipename,            /* pipe name           */

          PIPE_ACCESS_DUPLEX |     /* read/write access   */

          FILE_FLAG_OVERLAPPED,    /* overlapped mode     */

          PIPE_TYPE_MESSAGE |      /* message-type pipe   */

          PIPE_READMODE_MESSAGE |  /* message-read mode   */

          PIPE_WAIT,               /* blocking mode       */

          INSTANCES,               /* number of instances */

          BUFSIZE,                 /* output buffer size  */

          BUFSIZE,                 /* input buffer size   */

          PIPE_TIMEOUT,            /* client time-out     */

          NULL);                   /* no security attr.   */

      if (Pipe[i].hPipeInst == INVALID_HANDLE_VALUE)

          MyErrExit("CreatePipe");

      /* Call the subroutine to connect to the new client. */

      Pipe[i].fPendingIO = ConnectToNewClient(

          Pipe[i].hPipeInst,

          &Pipe[i].oOverlap);

      Pipe[i].dwState = Pipe[i].fPendingIO ?

          CONNECTING_STATE : /* still connecting   */

          READING_STATE;     /* ready to read      */

  }

  while (1) {

      /*

       * Wait for the event object to be signaled, indicating

       * completion of an overlapped read, write, or

       * connect operation.

       */

      dwWait = WaitForMultipleObjects(

         INSTANCES,    /* number of event objects */

         hEvents,      /* array of event objects  */

         FALSE,        /* does not wait for all   */

         INFINITE);    /* waits indefinitely      */

      /* dwWait shows which pipe completed the operation.  */

      i = dwWait - WAIT_OBJECT_0; /* determines which pipe */

      if (i < 0 || i > (INSTANCES - 1))

          MyErrExit("index out of range");

      /* Get the result if the operation was pending. */

      if (Pipe[i].fPendingIO) {

          fSuccess = GetOverlappedResult(

               Pipe[i].hPipeInst, /* handle to pipe       */

               &Pipe[i].oOverlap, /* OVERLAPPED structure */

               &cbBytes,          /* bytes transferred    */

               FALSE);            /* do not wait          */

          switch (Pipe[i].dwState) {

              /* Pending connect operation */

              case CONNECTING_STATE:

                  if (! fSuccess)

                      MyErrExit("ConnectNamedPipe");

                  Pipe[i].dwState = READING_STATE;

                  break;

              /* Pending read operation */

              case READING_STATE:

                  if (! fSuccess || cbBytes == 0) {

                      DisconnectAndReconnect(i);

                      continue;

                  }

                  Pipe[i].dwState = WRITING_STATE;

                  break;

              /* Pending write operation */

              case WRITING_STATE:

                  if (! fSuccess ||

                          cbBytes != Pipe[i].cbToWrite) {

                      DisconnectAndReconnect(i);

                      continue;

                  }

                  Pipe[i].dwState = READING_STATE;

                  break;

              default:

                  MyErrExit("invalid pipe state");

          }

      }

      /* The pipe state determines which operation to do next. */

      switch (Pipe[i].dwState) {

          /*

           * READING_STATE:

           * The pipe instance is connected to the client

           * and is ready to read a request from the client.

           */

          case READING_STATE:

                  fSuccess = ReadFile(

                  Pipe[i].hPipeInst,

                  Pipe[i].chBuf,

                  BUFSIZE,

                  &cbBytes,

                  &Pipe[i].oOverlap);

              /* The read operation completed successfully. */

              if (fSuccess && cbBytes != 0) {

                  Pipe[i].fPendingIO = FALSE;

                  Pipe[i].dwState = WRITING_STATE;

                  continue;

              }

              /* The read operation is still pending */

              dwErr = GetLastError();

              if (! fSuccess &&

                    (dwErr == ERROR_IO_PENDING)) {

                Pipe[i].fPendingIO = TRUE;

                continue;

              }

              /* An error occurred; disconnect from the client. */

              DisconnectAndReconnect(i);

              break;

          /*

           * WRITING_STATE:

           * The request was successfully read from the client.

           * Get the reply data and write it to the client.

           */

          case WRITING_STATE:

              GetDataToWriteToClient(&Pipe[i]);

              fSuccess = WriteFile(

                  Pipe[i].hPipeInst,

                  Pipe[i].chBuf,

                  Pipe[i].cbToWrite,

                  &cbBytes,

                  &Pipe[i].oOverlap);

              /* The write operation completed successfully. */

              if (fSuccess &&

                      cbBytes == Pipe[i].cbToWrite) {

                  Pipe[i].fPendingIO = FALSE;

                  Pipe[i].dwState = READING_STATE;

                  continue;

              }

              /* The write operation is still pending. */

              dwErr = GetLastError();

              if (! fSuccess &&

                      (dwErr == ERROR_IO_PENDING)) {

                  Pipe[i].fPendingIO = TRUE;

                  continue;

              }

              /* An error occurred; disconnect from the client. */

              DisconnectAndReconnect(i);

              break;

          default:

              MyErrExit("invalid pipe state");

      }

  }

  return 0;

}

/*

 * DisconnectAndReconnect(DWORD)

 * This function is called when an error occurs or when the client

 * closes its handle to the pipe. Disconnect from this client, and then

 * call ConnectNamedPipe to wait for another client to connect.

 */

VOID DisconnectAndReconnect(DWORD i) {

  /* Disconnect the pipe instance. */

  if (! DisconnectNamedPipe(Pipe[i].hPipeInst) )

      MyErrExit("DisconnectNamedPipe");

  /* Call a subroutine to connect to the new client. */

  Pipe[i].fPendingIO = ConnectToNewClient(

      Pipe[i].hPipeInst,

      &Pipe[i].oOverlap);

  Pipe[i].dwState = Pipe[i].fPendingIO ?

      CONNECTING_STATE : /* still connecting   */

      READING_STATE;     /* ready to read      */

}

/*

 * ConnectToNewClient(HANDLE, LPOVERLAPPED)

 * This function is called to start an overlapped connect operation. It

 * returns TRUE if an operation is pending or FALSE if the connection

 * has been completed.

 */

BOOL ConnectToNewClient(HANDLE hPipe, LPOVERLAPPED lpo) {

  BOOL fConnected, fPendingIO = FALSE;

  /* Start an overlapped connection for this pipe instance. */

  fConnected = ConnectNamedPipe(hPipe, lpo);

  /* Overlapped ConnectNamedPipe should return FALSE. */

  if (fConnected)

      MyErrExit("ConnectNamedPipe");

  switch (GetLastError()) {

      /* The overlapped connection in progress. */

      case ERROR_IO_PENDING:

          fPendingIO = TRUE;

          break;

      /* Client is already connected, so signal an event. */

      case ERROR_PIPE_CONNECTED:

          if (SetEvent(lpo->hEvent))

              break;

      /* If an error occurs during the connect operation... */

      default:

          MyErrExit("ConnectNamedPipe");

  }

  return fPendingIO;

}


Server Using Completion Routines

The ReadFileEx and WriteFileEx functions provide another form of overlapped I/O. Unlike the overlapped ReadFile and WriteFile functions, which use an event object to signal completion, the extended functions specify a completion routine. A completion routine is a function that is queued for execution when the read or write operation is done. The completion routine is not executed until the thread that called ReadFileEx and WriteFileEx enters an alertable wait by calling one of the extended wait functions: WaitForSingleObjectEx, WaitForMultipleObjectsEx, or SleepEx. These functions are like the other wait functions in that they return when a specified object is in the signaled state or when a time-out interval has elapsed. However, these functions can also perform an alertable wait, which occurs when their fAlertable parameter is set to TRUE. In an alertable wait, the functions also return when a ReadFileEx or WriteFileEx completion routine is queued for execution. A server process can use the extended functions to perform a sequence of read and write operations for each client that connects to it. Each read or write operation in the sequence specifies a completion routine, and each completion routine initiates the next step in the sequence.

Like the previous example, this example is a single-threaded server process that creates a message-type pipe and uses overlapped operations. The server process differs in that it uses the extended functions ReadFileEx and WriteFileEx to perform overlapped I/O. Unlike the overlapped ReadFile and WriteFile functions, which signal an event object upon completion, the extended functions specify a completion routine, which is queued for execution when the operation is finished. The server process uses the WaitForSingleObjectEx function, which performs an alertable wait that returns when a completion routine is ready to execute. The wait function also returns when an event object is signaled, which in this example indicates that the overlapped ConnectNamedPipe operation has finished (a new client has connected).

Initially, the server process creates a single instance of the pipe and starts an overlapped ConnectNamedPipe operation. When a client connects, the server allocates a structure to provide storage for that pipe instance and then calls the ReadFileEx function to launch a sequence of I/O operations to handle communications with the client. Each operation specifies a completion routine that performs the next operation in the sequence. The sequence terminates when the client is disconnected and the pipe instance closed. After starting the sequence of operations for the new client, the server creates another pipe instance and waits for the next client to connect.

The parameters of the ReadFileEx and WriteFileEx functions specify a completion routine and a pointer to an OVERLAPPED structure. This pointer is later passed to the completion routine in its lpOverLap parameter. Because the OVERLAPPED structure points to the first member in the structure allocated for each pipe instance, the completion routine can use its lpOverLap parameter to access the structure for the pipe instance.

To avoid duplication, the listing for the ConnectToNewClient subroutine is not shown; it is identical to the one used by the overlapped server process in the previous section.

#include <windows.h>

typedef struct {

  OVERLAPPED oOverlap;

  HANDLE hPipeInst;

  CHAR chBuf[BUFSIZE];

  DWORD cbToWrite;

} PIPEINST, *LPPIPEINST;

BOOL CreateAndConnectInstance();

BOOL ConnectToNewClient(HANDLE, LPOVERLAPPED);

VOID GetDataToWriteToClient(LPPIPEINST);

VOID DisconnectAndClose(LPPIPEINST);

VOID CompletedWriteRoutine(DWORD, DWORD, LPOVERLAPPED);

VOID CompletedReadRoutine(DWORD, DWORD, LPOVERLAPPED);

HANDLE hPipe;

DWORD main(VOID) {

  HANDLE hConnectEvent;

  OVERLAPPED oConnect;

  LPPIPEINST lpPipeInst;

  DWORD dwWait, cbBytes;

  BOOL fSuccess, fPendingIO;

  /* Create one event object for the connect operation. */

  hConnectEvent = CreateEvent(

      NULL,    /* no security attr.         */

      TRUE,    /* manual reset event        */

      TRUE,    /* initial state = signaled  */

      NULL);   /* unnamed event object      */

  if (hConnectEvent == NULL)

      MyErrExit("CreateEvent");

  oConnect.hEvent = hConnectEvent;

  /*

   * Call a subroutine to create one instance, and wait for

   * the client to connect.

   */

  fPendingIO = CreateAndConnectInstance(&oConnect);

  while (1) {

   /*

    * Wait for a client to connect, or for a read or write

    * operation to be completed, which causes a completion

    * routine to be queued for execution.

    */

      dwWait = WaitForSingleObjectEx(

          hConnectEvent,  /* event object to wait for */

          INFINITE,       /* waits indefinitely       */

          TRUE);          /* alertable wait enabled   */

      switch (dwWait) {

        /* The wait is satisfied by a completed connect operation. */

          case 0:

              /* If an operation is pending, get the result of the

               * connect operation.

               */

              if (fPendingIO) {

                  fSuccess = GetOverlappedResult(

                      hPipe,     /* pipe handle          */

                      &oConnect, /* OVERLAPPED structure */

                      &cbBytes,  /* bytes transferred    */

                      FALSE);    /* does not wait        */

                  if (! fSuccess)

                      MyErrExit("ConnectNamedPipe");

              }

              /* Allocate storage for this instance. */

              lpPipeInst = (LPPIPEINST) GlobalAlloc(

                  GPTR, sizeof(PIPEINST));

              if (lpPipeInst == NULL)

                  MyErrExit("GlobalAlloc lpPipeInst");

              lpPipeInst->hPipeInst = hPipe;

              /*

               * Start the read operation for this client.

               * Note that this same routine is later used as a

               * completion routine after a write operation.

               */

              lpPipeInst->cbToWrite = 0;

              CompletedWriteRoutine(0, 0,

                  (LPOVERLAPPED) lpPipeInst);

              /* Create new pipe instance for the next client. */

              fPendingIO = CreateAndConnectInstance(

                  &oConnect);

              break;

        /*

         * The wait is satisfied by a completed read or write

         * operation. This allows the system to execute the

         * completion routine.

         */

          case WAIT_IO_COMPLETION:

              break;

        /* An error occurred in the wait function. */

          default:

              MyErrExit("WaitForSingleObjectEx");

      }

  }

  return 0;

}

/*

 * CompletedWriteRoutine(DWORD, DWORD, LPOVERLAPPED)

 * This routine is called as an I/O completion routine after writing to

 * the pipe, or when a new client has connected to a pipe instance. It

 * starts another read operation.

 */

VOID CompletedWriteRoutine(DWORD dwErr, DWORD cbWritten,

    LPOVERLAPPED lpOverLap) {

  LPPIPEINST lpPipeInst;

  BOOL fRead = FALSE;

  /* lpOverlap points to storage for this instance. */

  lpPipeInst = (LPPIPEINST) lpOverLap;

  /*

   * The write operation has finished, so read the next request (if

   * there is no error).

   */

  if ((dwErr == 0) && (cbWritten == lpPipeInst->cbToWrite))

      fRead = ReadFileEx(

          lpPipeInst->hPipeInst,

          lpPipeInst->chBuf,

          BUFSIZE,

          (LPOVERLAPPED) lpPipeInst,

          (LPOVERLAPPED_COMPLETION_ROUTINE) CompletedReadRoutine);

  /* Disconnect if an error occurred. */

  if (! fRead)

      DisconnectAndClose(lpPipeInst);

}

/*

 * CompletedReadRoutine(DWORD, DWORD, LPOVERLAPPED)

 * This routine is called as an I/O completion routine after reading a

 * request from the client. It gets data and writes it to the pipe.

 */

VOID CompletedReadRoutine(DWORD dwErr, DWORD cbBytesRead,

    LPOVERLAPPED lpOverLap) {

  LPPIPEINST lpPipeInst;

  BOOL fWrite = FALSE;

  /* lpOverlap points to storage for this instance. */

  lpPipeInst = (LPPIPEINST) lpOverLap;

  /*

   * The read operation has finished, so write a response (if no

   * error occurred).

   */

  if ((dwErr == 0) && (cbBytesRead != 0)) {

      GetDataToWriteToClient(lpPipeInst);

      fWrite = WriteFileEx(

          lpPipeInst->hPipeInst,

          lpPipeInst->chBuf,

          lpPipeInst->cbToWrite,

          (LPOVERLAPPED) lpPipeInst,

          (LPOVERLAPPED_COMPLETION_ROUTINE) CompletedWriteRoutine);

  }

  /* Disconnect if an error occurred. */

  if (! fWrite)

      DisconnectAndClose(lpPipeInst);

}

/*

 * DisconnectAndClose(LPPIPEINST)

 * This routine is called when an error occurs or when the client closes

 * its handle to the pipe.

 */

VOID DisconnectAndClose(LPPIPEINST lpPipeInst)

{

  /* Disconnect the pipe instance. */

  if (! DisconnectNamedPipe(lpPipeInst->hPipeInst) )

      MyErrExit("DisconnectNamedPipe");

  /* Close the handle to the pipe instance. */

  CloseHandle(lpPipeInst->hPipeInst);

  /* Release the storage for the pipe instance. */

  if (lpPipeInst != NULL)

      GlobalFree(lpPipeInst);

}

/*

 * CreateAndConnectInstance(LPOVERLAPPED)

 * This function creates a pipe instance and connects to the new client.

 * It returns TRUE if the connect operation is pending and FALSE if

 * the connection has been completed.

 */

BOOL CreateAndConnectInstance(LPOVERLAPPED lpoOverlap) {

  LPTSTR lpszPipename = "\\\\.\\pipe\\mynamedpipe";

  hPipe = CreateNamedPipe(

      lpszPipename,             /* pipe name           */

      PIPE_ACCESS_DUPLEX |      /* read/write access   */

      FILE_FLAG_OVERLAPPED,     /* overlapped mode     */

      PIPE_TYPE_MESSAGE |       /* message-type pipe   */

      PIPE_READMODE_MESSAGE |   /* message read mode   */

      PIPE_WAIT,                /* blocking mode       */

      PIPE_UNLIMITED_INSTANCES, /* unlimited instances */

      BUFSIZE,                  /* output buffer size  */

      BUFSIZE,                  /* input buffer size   */

      PIPE_TIMEOUT,             /* client time-out     */

      NULL);                    /* no security attr.   */

  if (hPipe == INVALID_HANDLE_VALUE)

      MyErrExit("CreatePipe");

  /* Call a subroutine to connect to the new client. */

  return ConnectToNewClient(hPipe, lpoOverlap);

}


Named Pipe Client Process

A client process uses the CreateFile function to open a handle to a named pipe. If the pipe exists but all of its instances are busy, CreateFile returns FALSE and the GetLastError function returns ERROR_PIPE_BUSY. When this happens, the client process uses the WaitNamedPipe function to wait for an instance of the pipe to be available.

CreateFile fails if the access specified is incompatible with the access specified (duplex, outbound, or inbound) when the server created the pipe. For a duplex pipe (read/write), the client can specify read, write, or read/write access; for an outbound pipe (server write only), the client must specify read only; and for an inbound pipe (server read only), the client must specify write only.

The handle returned by CreateFile defaults to byte-read mode, blocking-wait mode, overlapped mode disabled, and write-through mode disabled. The client process can use CreateFile to enable overlapped mode by specifying FILE_FLAG_OVERLAPPED or to enable write-through mode by specifying FILE_FLAG_WRITE_THROUGH. The client can use the SetNamedPipeHandleState function to enable nonblocking mode by specifying PIPE_WAIT or to enable message-read mode by specifying PIPE_READMODE_MESSAGE.

The following example shows a client process that opens a named pipe, sets the pipe handle to message-read mode, uses WriteFile to send a request to the server, and uses ReadFile to read the server's reply. This client process can be used with any of the message-type servers shown in the previous sections. With a byte-type server, however, this client process fails when it calls SetNamedPipeHandleState to change to message-read mode. Because the client is reading from the pipe in message-read mode, it is possible for the ReadFile operation to return FALSE after reading a partial message. This happens when the message is larger than the read buffer. In this situation, GetLastError returns ERROR_MORE_DATA, and the remainder of the message is read by additional calls to ReadFile.

#include <windows.h>

 DWORD main(int argc, char *argv[]) {

  HANDLE hPipe;

  LPVOID lpvMessage;

  CHAR chBuf[512];

  BOOL fSuccess;

  DWORD cbRead, cbWritten, dwMode;

  LPTSTR lpszPipename = "\\\\.\\pipe\\mynamedpipe";

  /* Try to open a named pipe; wait for it, if necessary. */

  while (1) {

      hPipe = CreateFile(

          lpszPipename,   /* pipe name           */

          GENERIC_READ |  /* read/write access   */

          GENERIC_WRITE,

          0,              /* no sharing          */

          NULL,           /* no security attr.   */

          OPEN_EXISTING,  /* opens existing pipe */

          0,              /* default attributes  */

          NULL);          /* no template file    */

      /* Break if the pipe handle is valid. */

      if (hPipe != INVALID_HANDLE_VALUE)

          break;

      /* Exit if an error other than ERROR_PIPE_BUSY occurs. */

      if (GetLastError() != ERROR_PIPE_BUSY)

          MyErrExit("Could not open pipe");

      /* All pipe instances are busy, so wait for 20 seconds. */

      if (! WaitNamedPipe(lpszPipename, 20000) )

          MyErrExit("Could not open pipe");

  }

  /* The pipe connected; change to message-read mode. */

  dwMode = PIPE_READMODE_MESSAGE;

  fSuccess = SetNamedPipeHandleState(

      hPipe,    /* pipe handle          */

      &dwMode,  /* new pipe mode        */

      NULL,     /* don't set max. bytes */

      NULL);    /* don't set max. time  */

  if (! fSuccess)

      MyErrExit("SetNamedPipeHandleState");

  /* Send a message to the pipe server. */

  lpvMessage = (argc > 1) ? argv[1] : "default message";

  fSuccess = WriteFile(

      hPipe,                  /* pipe handle     */

      lpvMessage,             /* message         */

      strlen(lpvMessage) + 1, /* message length  */

      &cbWritten,             /* bytes written   */

      NULL);                  /* not overlapped  */

  if (! fSuccess)

      MyErrExit("WriteFile");

  do {

      /* Read from the pipe. */

      fSuccess = ReadFile(

          hPipe,    /* pipe handle              */

          chBuf,    /* buffer to receive reply  */

          512,      /* size of buffer           */

          &cbRead,  /* number of bytes read     */

          NULL);    /* not overlapped           */

      if (! fSuccess && GetLastError() != ERROR_MORE_DATA)

          break;

      /* Reply from the pipe is written to STDOUT. */

      if (! WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),

              chBuf, cbRead, &cbWritten, NULL))

          break;

  } while (! fSuccess); /* repeat loop if ERROR_MORE_DATA */

  CloseHandle(hPipe);

  return 0;

}


Transactions on Named Pipes

A named pipe transaction is a client-server communication that combines a write operation and a read operation into a single network operation. A transaction can be used only on a duplex, message-type pipe. Transactions improve the performance of network communications between a client and a remote server. Processes can use the TransactNamedPipe and CallNamedPipe functions to perform named pipe transactions.

TransactNamedPipe is typically used by a client process to write a request message to the named pipe server and read the server's response message. The client process must specify GENERIC_READ | GENERIC_WRITE access when it opens its pipe handle by calling the CreateFile function. Then, the client process sets the pipe handle to message-read mode by calling the SetNamedPipeHandleState function. If the read buffer specified in the call to TransactNamedPipe is not large enough to hold the entire message written by the server, the function returns FALSE and GetLastError returns ERROR_MORE_DATA. The client can read the remainder of the message by calling either the ReadFile, ReadFileEx, or PeekNamedPipe function.

TransactNamedPipe is typically called by client processes, but can also be used by a server process.

The following example shows a client process using TransactNamedPipe. The example assumes that the client process has used CreateFile to connect to the pipe and SetNamedPipeHandleState to set the pipe handle's read mode, as shown in the client process example in the preceding section.

fSuccess = TransactNamedPipe(

    hPipe,               /* pipe handle             */

    lpszWrite,           /* message to server       */

    strlen(lpszWrite)+1, /* message length          */

    chReadBuf,           /* buffer to receive reply */

    512,                 /* size of read buffer     */

    &cbRead,             /* number of bytes read    */

    NULL);               /* not overlapped          */

/*

 * Exit if an error occurs, unless the error indicates there is more

 * data in the message.

 */

if (! fSuccess && (GetLastError() != ERROR_MORE_DATA))

    MyErrExit("TransactNamedPipe");

while(1) {

    /* Data from the pipe is written to STDOUT. */

    if (! WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),

            chReadBuf, cbRead, &cbWritten, NULL) )

        break;

    /* Break if TransactNamedPipe or ReadFile is successful. */

    if (fSuccess)

        break;

    /* Read from the pipe if there is more data in the message.*/

    fSuccess = ReadFile(

        hPipe,      /* pipe handle              */

        chReadBuf,  /* buffer to receive reply  */

        512,        /* size of buffer           */

        &cbRead,    /* number of bytes read     */

        NULL);      /* not overlapped           */

    /* Exit if an error other than ERROR_MORE_DATA occurs. */

    if (! fSuccess && (GetLastError() != ERROR_MORE_DATA))

        break;

}

A client process uses CallNamedPipe to combine the CreateFile, WaitNamedPipe (if necessary), TransactNamedPipe, and CloseHandle operations into a single function. Because the pipe handle is closed before the function returns, any additional bytes in the message are lost if the message is larger than the speciffied size of the read buffer. The following example shows the use of CallNamedPipe.

/* Combines connect, wait, write, read, and close operations. */

fSuccess = CallNamedPipe(

    lpszPipename,        /* pipe name               */

    lpszWrite,           /* message to server       */

    strlen(lpszWrite)+1, /* message length          */

    chReadBuf,           /* buffer to receive reply */

    512,                 /* size of read buffer     */

    &cbRead,             /* number of bytes read    */

    20000);              /* waits for 20 seconds    */

if (fSuccess || GetLastError() == ERROR_MORE_DATA) {

    /* Data from the pipe is written to STDOUT. */

    WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),

        chReadBuf, cbRead, &cbWritten, NULL);

    /*

     * The pipe is closed, so no more bytes can be read from the

     * message.

     */

    if (! fSuccess)

        printf("\n...extra data in message was lost\n");

}


Pipe Functions

Following are the functions used with pipes.

CallNamedPipe
ConnectNamedPipe
CreateNamedPipe
CreatePipe
DisconnectNamedPipe
GetNamedPipeHandleState
GetNamedPipeInfo
PeekNamedPipe
SetNamedPipeHandleState
TransactNamedPipe
WaitNamedPipe


Power Management

This overview describes the power management functions and messages, and explains how to use them in applications and installable drivers.


About Power Management

The Windows operating system uses power management to reduce the power consumption of a computer and the attached devices. Windows works in conjunction with the computer and its devices to monitor system operation and shut down devices or the computer itself when idle. To help applications and installable drivers take advantage of power management and to ensure that no data is lost when a device or the computer is shut down, Windows provides functions and messages that reveal the system power status and notify of power management events.


About System Power Status

System power status indicates the source of power for a computer, that is, whether it uses a system battery or AC power. For computers that use batteries, the status also indicates how much battery life remains and whether the battery is currently charging.

You can retrieve the system power status by using the GetSystemPowerStatus function. This copies information about the power supply and battery status to a SYSTEM_POWER_STATUS structure. This structure identifies whether the system has a battery, and if it does, whether the battery is being used and the percentage of charge remaining.

Applications and installable drivers typically use the system power status to make decisions about whether to continue operation. For example, an application that is beginning a lengthy operation may check the status to determine whether enough battery power exists to complete the operation.

If power is low, an application can request user intervention or request that the system to shut itself down. You can suspend the operation of the system by using the SetSystemPowerState function. This generates a power management event that, if approved by all applications and drivers in the system, shuts the system down until the user restores power. Even if a computer uses AC power, an application that determines that the system is idle and can request that the system shut itself down to save power.


Power Management Events

A power management event is a change in either the system power status or the operational mode of a device or the computer. Because these events can affect the operation of applications and installable drivers and can lead to loss of data, Windows notifies all applications and installable drivers by broadcasting a WM_POWERBROADCAST message for each event.

A system power status event occurs when there is a change in the power supply or in the system battery status. For example, the system broadcasts a message whenever the user switches from battery to AC power or vice versa. The system also broadcasts a message when remaining battery power slips below 10%.

An operational mode event occurs when there is a change in power consumption, such as the system shutting itself down or the user turning the system back on. Some changes in operational mode can cause loss of data if applications and drivers do not prepare for them. Therefore, the system broadcasts messages about these changes before they actually occur. For example, if the system determines that it is idle, it broadcasts a message notifying applications and drivers that it is about to suspend operation and shut itself down to save power. The applications and drivers can prepare for this suspension by closing files and saving data that may otherwise be lost when power is shut off.

The system has three ways to shut itself down. It can suspend operation, place operation on standby, or carry out critical suspension. An application can also shut the system down by using the SetSystemPowerState function to suspend operation.

When system operation is suspended, power to all devices is lost. The WM_POWERBROADCAST messages, sent immediately before suspension, allow device drivers to save the state of the device. For many devices (but not all), saving the state means the driver can restore the state when power is eventually restored, allowing the device to continue operation as if power was never lost.

When the system goes into standby, power to devices may be reduced but no state is lost and interrupts continue to be processed. For example, a hard disk drive on standby may stop spinning but state information is preserved and the drive responds to requests for access. Standby operation is transparent to applications because the corresponding WM_POWERBROADCAST messages are never sent to them. Instead only device drivers receive and process these messages.

When the system carries out a critical suspension, battery power is too low to let the computer continue to run. Unlike for suspended and standby operations, the system does not notify applications and drivers before carrying out a critical suspension. This means data may be lost.

When system operation is restored after having been suspended or placed on standby, the system notifies all applications and drivers. It also identifies how the system was previously shut down so that the application or driver can take appropriate steps to restore its data and continue its own operation.


Power Messages

The system sends power messages to all applications and installable drivers whenever a power management event occurs or whenever an application calls the SetSystemPowerState function to suspend operation. The system sends these messages through the WM_POWERBROADCAST message, setting the wParam parameter to the message type. For example, the message type, PBT_APMPOWERSTATUSCHANGE, indicates a system power status change message.

The system sends a PBT_APMQUERYSUSPEND or PBT_APMQUERYSTANDBY message to request permission to suspend system operation or place it on stanmdby. The system expects each application and driver to determine whether the requested event should occur and to return TRUE or FALSE indicating this decision. Any application or driver can deny the request and prevent it from occurring.

The system sends a PBT_APMSUSPEND or PBT_APMSTANDBY message immediately before suspending operation or placing it on standby. This gives applications and drivers one last chance to prepare for the event before it occurs. In many cases, the system sends these messages without requesting permission to do so. This happens, for example, if an application forces suspension with the SetSystemPowerState function.

The standby messages (PBT_APMQUERYSTANDBY, PBT_APMQUERYSTANDBYFAILED, PBT_APMRESUMESTANDBY, and PBT_APMSTANDBY) are not set to applications. these are intended to be sent to low-level drivers and system components.

The system sends the PBT_APMQUERYSUSPENDFAILED or PBT_APMQUERYSTANDBYFAILED message whenever a requested event is denied. These messages are intended to notify applications and drivers to continue operation as usual.

The system sends the PBT_APMRESUMESUSPEND, PBT_APMRESUMESTANDBY, or PBT_APMRESUMECRITICAL message when system operation has been restored.

Note  The WM_POWER message, previously available to applications and drivers for use with power management, is maintained for backward compatibility. All current applications and installable drivers should use and process the WM_POWERBROADCAST message instead.


Power Management Reference

This section describes the power management functions, messages, and structures.


Power Management Functions

This section describes the power management functions.

GetSystemPowerStatus
SetSystemPowerState


Power Management Messages

This section descibes the power management messages.

PBT_APMPOWERSTATUSCHANGE
PBT_APMQUERYSTANDBY
PBT_APMQUERYSTANDBYFAILED
PBT_APMQUERYSUSPEND
PBT_APMQUERYSUSPENDFAILED
PBT_APMRESUMECRITICAL
PBT_APMRESUMESTANDBY
PBT_APMRESUMESUSPEND
PBT_APMSTANDBY
PBT_APMSUSPEND
WM_POWERBROADCAST


Power Management Structure

This section describes the power management structure.

SYSTEM_POWER_STATUS


Processes and Threads

A process is an executing application that consists of a private virtual address space, code, data, and other operating system resources, such as files, pipes, and synchronization objects that are visible to the process. A process also contains one or more threads that run in the context of the process. A thread is the basic entity to which the operating system allocates CPU time. A thread can execute any part of the application's code, including a part currently being executed by another thread. All threads of a process share the virtual address space, global variables, and operating system resources of the process.

This overview describes processes and threads, and explains how to create and use them.


About Processes and Threads

An application written for Microsoft® Windows® can consist of more than one process, and a process can consist of more than one thread. The Microsoft® Win32® application program interface (API) supports multitasking, which creates the effect of simultaneous execution of multiple processes and threads.


Multitasking

A process is a program that is loaded into memory and prepared for execution. Each process has a private virtual address space. A process consists of the code, data, and other system resources — such as files, pipes, and synchronization objects — that are accessible to the threads of the process. Each process is started with a single thread, but additional independently executing threads can be created.

A thread can execute any part of the program's code, including a part executed by another thread. Threads are the basic entity to which the operating system allocates CPU time. Each thread maintains a set of structures for saving its context while waiting to be scheduled for processing time. The context includes the thread's set of machine registers, the kernel stack, a thread environment block, and a user stack in the address space of the thread's process. All threads of a process share the virtual address space and can access the global variables and system resources of the process.

A multitasking operating system divides the available CPU time among the threads that need it. In Windows, the Win32 API is designed for preemptive multitasking; this means that the system allocates small slices of CPU time among the competing threads. The currently executing thread is suspended when its time slice elapses, allowing another thread to run. When the system switches from one thread to another, it saves the context of the suspended thread and restores the saved context of the next thread in the queue.

Because each time slice is small (approximately 20 milliseconds), it appears that multiple threads are executing at the same time. This is actually the case on multiprocessor systems, where the executable threads are distributed among the available processors. On a single processor system, however, using multiple threads does not result in more instructions being executed. In fact, the system can slow down if it is forced to keep track of too many threads.

To the user, the advantage of multitasking is the ability to have several applications open and working at the same time. For example, a user can edit a file with one application while another application is printing or recalculating a spreadsheet.

To the application developer, the advantage of multitasking is the ability to create applications that use more than one process and to create processes that use more than one thread of execution. For example, you can have one thread that handles interactions with the user (keyboard and mouse input), while other threads with lower priority perform the other work of the process. The higher priority of the input thread makes the program responsive to the user, while the other threads ensure that the processor can be used efficiently during the slices of time between keystrokes.


When to Use Multitasking

Any thread of any process can use the CreateThread and CreateProcess functions to create additional threads or processes. An application might use multiple processes for functions that require a private address space and private resources, to protect them from the activities of other threads. Functions that are to be distributed as separate executable modules but that can be integrated to form a single application, can benefit from the multiprocess approach.

It is useful for a process to have multiple threads in situations where the application has several tasks to run concurrently. For example, an application that opens more than one window can have a separate thread perform the work of the application in each window. Multiple threads can be a convenient way to structure a program that performs several similar or identical tasks. For example, a named pipe server can create a thread to handle communications with each client process that attaches to the pipe. Other examples of using multiple threads are processes that do the following:

•	Handle input for multiple windows.

•	Manage input from several communications devices.

•	Need to distinguish among tasks of varying priority. For example, a high-priority thread handles time-critical tasks, and a low-priority thread performs other tasks.

It is typically more efficient for an application to implement multitasking by distributing tasks among the threads of a single process, rather than by creating multiple processes, for the following reasons:

•	The system can create and execute threads more quickly than it can create processes, primarily because the code for threads has already been mapped into the address space of the process, while the code for a new process must be loaded.

•	All threads of a process share the same address space and can access the process's global variables, which can simplify communications between threads.

•	All threads of a process can use open handles to resources such as files and pipes.

For both multiple threads and multiple processes, there are costs and dangers to be considered. The system consumes memory for the structures required by both processes and threads. Keeping track of a large number of threads consumes CPU time. With multiple threads accessing the same resources, you must synchronize the threads to avoid conflicts. This is true for system resources (such as communications ports or disk drives), handles to resources shared by multiple processes (such as file or pipe handles), or the resources of a single process (such as global variables accessed by multiple threads). Failure to synchronize multiple threads properly (in the same or in different processes) can lead to program problems such as deadlock and race conditions. The Win32 API provides a set of synchronization objects and functions you can use to coordinate multiple threads. For more information about synchronization, see Synchronizing Execution of Multiple Threads and Synchronization.

The Win32 API also provides alternative ways to execute multiple tasks that, in some cases, make multithreaded processes unnecessary. The most significant of these are overlapped I/O and the ability to wait for multiple events.

Overlapped I/O enables a single thread to initiate multiple time consuming I/O requests that can run concurrently. This asynchronous I/O can be performed on files, pipes, serial communications devices, or tape devices. For more information about files, see Files. For more information about pipes, see Pipes. For more information about serial communication devices, see Communications. For more information about tape devices, see Tape Backup.

Waiting for multiple events enables a single thread to block its execution while waiting for any one of several events to occur. This is much more efficient than using multiple threads, each waiting for a single event, or using a single thread that consumes CPU time by continually checking for an event of interest. For more information about waiting for multiple events, see Synchronization.


Scheduling

The system scheduler controls multitasking by determining which of the competing threads receives the next slice of the processor's time. Each time slice consists of a fixed number of clock ticks. The Windows scheduler is preemptive, gaining control whenever a clock interrupt occurs and decrementing the count of clock ticks remaining in the time slice of the currently executing thread. If the count goes to zero, the scheduler determines which thread runs next. The scheduler maintains a queue of executable threads at each priority level. When the highest priority is shared by more than one executable thread, the next time slice goes to the thread at the head of the priority queue. The thread that just finished executing is placed at the end of the queue of threads with its priority. Threads that are suspended or blocked (for example, waiting for a semaphore object or waiting for input) are not executable, so until they become unblocked, the scheduler does not allocate any processor time to them, regardless of their priority. When the scheduler awards the next time slice to a different thread, the context of the currently executing thread is saved, and the machine state is set according to the context of the next executable thread.


Scheduling Priorities

The scheduling priority of each thread is determined by the following criteria:

•	The priority class of its process (high, normal, or idle)

•	The priority level of the thread within the priority class of its process (lowest, below normal, normal, above normal, highest)

•	The dynamic priority boost, if any, the system applies to the thread's base priority

By default, the priority class of a process is set to normal. The CreateProcess function allows a parent process to specify the priority class of its child processes. Use SetPriorityClass to change the priority class of a process and GetPriorityClass to determine the current priority class of a process.

There are five priority levels within each priority class. The levels range from lowest (−2) to highest (2). All threads are started with normal (0) priority. The SetThreadPriority function enables you to change the priority level of a thread to any of the five levels. Use the GetThreadPriority function to determine the current priority level of a thread.

The base priority of each thread is the thread's priority level within the priority class of its process. The scheduler uses this base priority to determine a thread's dynamic priority, which it uses to make scheduling decisions. A thread's dynamic priority is never less than its base priority. The scheduler raises and lowers the dynamic priority of a thread to enhance its responsiveness when significant things happen to the thread. For example, whenever a window receives input (such as timer messages, mouse move messages, keyboard input), the scheduler boosts the priorities of all threads within the process that owns the window. In some cases, the dynamic priority of a waiting thread is raised when a wait is satisfied. For example, a wait associated with disk or keyboard I/O results in a dynamic boost when the input occurs.

After raising a thread's dynamic priority, the scheduler reduces that priority by one level each time the thread completes a time slice, until the thread drops back to its base priority.

In addition to these dynamic priority boosts, the scheduler raises the priority class of the process associated with the foreground window, so it is greater than or equal to the priority class of any background processes. The process's priority class returns to its original setting when it is no longer in the foreground. A user can always make a given window lose the foreground priority boost by clicking on another window or by using the ALT+TAB or CTRL+ESC key combination.

The priority classes are intended to be used as follows.

Priority	Meaning
HIGH_PRIORITY_CLASS	Indicates a process that performs time-critical tasks that must be executed immediately for it to run correctly. The threads of a high-priority class process preempt the threads of normal or idle priority class processes. An example is Windows Task List, which must respond quickly when called by the user, regardless of the load on the operating system. Use extreme care when using the high-priority class, because a high-priority class CPU-bound application can use nearly all available cycles.
IDLE_PRIORITY_CLASS	Indicates a process whose threads run only when the system is idle and are preempted by the threads of any process running in a higher priority class. An example is a screen saver. The idle priority class is inherited by child processes.
NORMAL_PRIORITY_CLASS	Indicates a normal process with no special scheduling needs.
REALTIME_PRIORITY_CLASS	Indicates a process that has the highest possible priority. The threads of a real-time priority class process preempt the threads of all other processes, including operating system processes performing important tasks. For example, a real-time process that executes for more than a very brief interval can cause disk caches not to flush or cause the mouse to be unresponsive.
Use the high-priority class with extreme care. If a thread runs at the highest priority level for extended periods, other threads in the system will be starved for CPU time. If several threads are set at high priority at the same time, the effect of the high priority is neutralized. The high-priority class should be reserved for threads that must respond to time critical events. If your application has a task that requires the high-priority class while most of its functions are normal priority, use SetPriorityClass to raise the priority class temporarily; then reduce it once the time-critical task has been completed. Another strategy is to create a high-priority process that is blocked most of the time, awakening only when the critical task is needed. The important point is that a thread should be high priority and executable only for a brief period, when it has time-critical work to perform.

Having selected a priority class for a multithreaded process, use SetThreadPriority to adjust the relative priority of its threads. A typical strategy is to use a higher priority level for the process's input thread, to ensure responsiveness to the user. Other threads, particularly those that are CPU intensive, can be set to a lower relative priority, to ensure that they can be preempted when necessary. However, if you have a higher priority thread waiting for a lower priority thread to complete some task, be sure to block the execution of the waiting thread (using a wait function, critical section, or the Sleep function) rather than having it iterate in a loop. Otherwise, the process will deadlock, because the lower priority thread will never get scheduled.


Creating Threads

The CreateThread function creates a new thread for a process. The creating thread must specify the starting address of the code that the new thread is to execute. Typically, the starting address is the name of a function defined in the program's code. A process can have multiple threads simultaneously executing the same function. The function called by the thread takes a single 32-bit parameter and returns a doubleword result.

The following example illustrates the creation of a new thread that executes the locally defined ThreadFunc function.

DWORD ThreadFunc(LPDWORD lpdwParam) {

    printf("ThreadFunc:  thread parameter=%d\n", *lpdwParam);

    return 0;

}

DWORD main(VOID) {

    DWORD dwThreadId, dwThrdParam = 1;

    HANDLE hThread;

    hThread = CreateThread(

        NULL,                        /* no security attributes        */

        0,                           /* use default stack size        */

        (LPTHREAD_START_ROUTINE) ThreadFunc, /* thread function       */

        &dwThrdParam,                /* argument to thread function   */

        0,                           /* use default creation flags    */

        &dwThreadId);                /* returns the thread identifier */

    /* Check the return value for success. */

    if (hThread == NULL)

        ErrorExit("CreateThread error\n");

For simplicity, this example passes a pointer to dwThrdParam as an argument to the thread function. This could be a pointer to any type of data or structure, or it could be omitted altogether by passing a NULL pointer and deleting the references to the parameter in ThreadFunc. It is risky to pass the address of the local variable if the creating thread exits before the new thread, because the pointer becomes invalid. Instead, either pass dynamically allocated parameters or make the creating thread wait for the new thread to terminate. Data can also be passed from the creating thread to the new thread using global variables. With global variables, it is usually necessary to synchronize access by multiple threads. For more information about synchronizing, see Synchronizing Execution of Multiple Threads.

Using the thread function's argument to pass data to the new thread is particularly useful in processes where the main thread might create multiple threads to execute the same code. In this case, it is inconvenient to use global variables. For example, a process that enables the user to open several files at the same time can create a new thread for each file, with each of the threads executing the same thread function. The creating thread can pass as an argument the unique information (such as the filename) required by each instance of the thread function.

The creating thread can use the arguments to CreateThread to specify the following:

•	The security attributes for the handle of the new thread. These security attributes include an inheritance flag that determines whether the handle can be inherited by child processes. The security attributes also include a security descriptor, which the system uses to perform access checks on all subsequent uses of the thread's handle before access is granted. For more information about security attributes, see Security.

•	The initial stack size of the new thread. The thread's stack is allocated automatically in the memory space of the process; it can grow as needed and it is freed when the thread terminates.

•	A creation flag that enables you to create the thread in a suspended state. When suspended, the thread does not run until the ResumeThread function is called.

The handle returned by CreateThread has full-access rights to the new thread. Subject to security checks, the handle can be used in any of the Win32 API functions that accepts a handle to a thread object. The handle can be duplicated by DuplicateHandle, which enables you to create a thread handle with a subset of the access rights.

A thread can also be created with the CreateRemoteThread function. This is used by debugger processes to create a thread that runs in the address space of another process.


Suspending Thread Execution

A thread can suspend and resume the execution of another thread using the SuspendThread and ResumeThread functions. While a thread is suspended, it is not scheduled for time on the processor.

SuspendThread is not particularly useful for synchronization because it does not control the point in the code at which the thread's execution is suspended. However, you might want to suspend a thread in a situation where you are confirming a user's input that would terminate the work of the thread. If confirmed, the thread is terminated; otherwise, it resumes.

If a thread is created in a suspended state, it does not begin to run until ResumeThread is called with a handle to the suspended thread. This can be useful for initializing the thread's state before it begins to run. See Using a Multithreaded Multiple Document Interface Application for an example that uses this method to modify the thread's priority before it can run. Suspending a thread at creation can be useful for one-time synchronization, because ResumeThread ensures that the suspended thread will resume running at the starting point of its code.

A thread can temporarily suspend its own execution for a specified interval by calling the Sleep or SleepEx functions. This is useful particularly in cases where the thread responds to user interaction, as it can delay execution long enough to enable the users to observe the results of their actions. During the sleep interval, the thread is not scheduled for time on the processor.


Synchronizing Execution of Multiple Threads

To avoid conflicts, it is necessary to synchronize access by multiple threads to shared resources. Synchronization is also necessary to ensure that interdependent code is executed in the proper sequence.

The Win32 API provides a number of objects whose handles can be used to synchronize multiple threads. These objects include:

•	Synchronization objects: mutex, semaphore, and event handles

•	File handles

•	Named pipe handles

•	Console input buffer handles

•	Communication device handles

•	Process handles

•	Thread handles

The state of each of these objects is either signaled or not signaled. When a handle to any of these objects is specified by a call to one of the wait functions — WaitForSingleObject, WaitForMultipleObjects, WaitForSingleObjectEx, or WaitForMultipleObjectsEx — the execution of the calling thread is blocked until the state of the specified object is signaled. As with a suspended thread, a waiting thread consumes very little processor time.

Some of these objects are useful in blocking a thread until some event occurs. For example, a console input buffer handle is signaled when there is unread input, such as a keystroke or mouse button press. Process and thread handles are signaled when the process or thread terminates. This allows a process, for example, to create a child process and then block its own execution until the new process has terminated.

Other objects are useful in protecting shared resources from simultaneous access. For example, multiple threads can each have a handle to a mutex object. Before accessing a shared resource, the threads must call one of the wait functions to wait for the state of the mutex to be signaled. When the mutex becomes signaled, only one waiting thread is released to access the resource. The state of the mutex is immediately reset to not signaled so any other waiting threads remain blocked. When the thread is finished with the resource, it must set the state of the mutex to signaled to free other threads to access the resource.

For the threads of a single process, critical-section objects provide another (and slightly more efficient) means of synchronization. A critical section is used like a mutex to enable only one thread at a time to use the protected resource. A thread uses the EnterCriticalSection function to request ownership of a critical section. If it is already owned by another thread, the requesting thread is blocked. After it receives ownership, the thread is free to use the protected resource. The execution of the other threads of the process is not affected unless they attempt to enter the same critical section.

The WaitForInputIdle function makes a thread wait until a specified process is initialized and waiting for user input with no input pending. This can be useful for synchronizing parent and child processes, because CreateProcess returns without waiting for the child process to complete its initialization.

For more about critical sections and synchronization, see Synchronization.


Thread Local Storage

All threads of a process share the virtual address space and the global variables of that process. Sometimes it is desirable to have static storage that is local to each thread. Of course, the local variables of a thread function are local to each thread that runs the function. But when a thread invokes another function, the static or global variables used by that function store the same value for all threads. With thread local storage (TLS), one thread allocates an index that can be used by any thread of the process to store and retrieve a different value for each thread.

The following is a typical TLS scenario:

1.	The TlsAlloc function is used during process or dynamic-link library (DLL) initialization to allocate a TLS index.

2.	Each thread that needs to use the TLS index allocates dynamic storage, then uses the TlsSetValue function to associate the index with a pointer to the dynamic storage.

3.	When a thread needs to access its storage, it specifies the TLS index in a call to the TlsGetValue function to retrieve the pointer.

4.	Each thread frees the dynamic storage that it has associated with a TLS index when it is no longer needed. When all threads have finished using a TLS index, the TlsFree function frees the index.

The constant TLS_MINIMUM_AVAILABLE defines the minimum number of TLS indexes available in each process. This minimum is guaranteed to be at least 64 for all systems.

TLS can be useful with DLLs. The DllEntryPoint function performs the initial TLS operations in the context of the process or thread the DLL is attaching to or detaching from. When the DLL attaches to a new process, the entry-point function calls TlsAlloc to allocate a TLS index for that process. When the DLL attaches to a new thread of that process, the entry-point function allocates dynamic memory for that thread and uses TlsSetValue to save private data to the index. The DLL stores the TLS index in a global variable that is private to each attached process. The functions of the DLL can use the TLS index in a call to TlsGetValue to access the private data for the calling thread.

For an example illustrating the use of thread local storage, see Using Thread Local Storage.


Terminating a Thread

A thread runs until one of the following events occurs:

•	It calls the ExitThread function.

•	The thread function returns. This results in an implicit call to the ExitProcess function for a primary thread, or to the ExitThread function for other threads.

•	ExitProcess is invoked explicitly or implicitly by any thread of the process.

•	The TerminateThread function is called with a handle to the thread.

•	The TerminateProcess function is called with a handle to the thread's process.

When a thread terminates, the state of the thread object changes to signaled, releasing any other threads that had been waiting for the thread to terminate. Then its termination status changes from STILL_ACTIVE to the exit value of the thread.

If a thread is terminated by ExitThread, the entry-point function of all attached DLLs is invoked with a value indicating that the thread is detaching from the DLL. If a thread is terminated by ExitProcess, the DLL entry-point functions are invoked once, to indicate that the process is detaching. DLLs are not notified when a thread is terminated by TerminateThread or TerminateProcess. For more information about DLLs, see Dynamic-Link Libraries.

The GetExitCodeThread function returns the termination status of a thread. While a thread is executing, its termination status is STILL_ACTIVE. When a thread terminates, its termination status is the exit value of the thread, which is the value specified in the call to ExitThread, ExitProcess, or TerminateThread, or the value returned by the thread function.


Multiple Threads and Graphics Device Interface Objects

To enhance performance, access to graphics device interface (GDI) objects (such as palettes, device contexts (DC), regions, and the like) is not serialized. This creates a potential danger for processes that have multiple threads sharing these objects. For example, if one thread deletes a GDI object while another thread is using it, the results are unpredictable. This danger can be avoided simply by not sharing GDI objects. If sharing is unavoidable (or desirable), the application must provide its own mechanisms for synchronizing access. For more information about synchronizing access, see Synchronizing Execution of Multiple Threads.


Creating Processes

The CreateProcess function creates a new process, which runs independently of the creating process. The function provides two methods for identifying the program to be executed. The most common method is to specify the image file's path and filename. If the lpszImageName parameter is NULL, the program is identified in the lpszCommandLine parameter.

If CreateProcess succeeds, it returns a PROCESS_INFORMATION structure containing handles and identification numbers for the new process and its primary thread. The thread and process handles are created with full access rights, although access can be restricted if a security descriptor is specified.


Inheritance

A child process can inherit a number of properties and resources from its parent process. You can also prevent a child process from inheriting anything from its parent process. The following can be inherited:

•	Any inheritable open handle returned by the CreateFile function. This includes handles to files, console input buffers, console screen buffers, named pipes, serial communication devices, and mailslots.

•	Inheritable open handles to process, thread, mutex, event, semaphore, named pipe, anonymous pipe, and file mapping objects.

•	Environment variables.

•	The current directory.

•	The console of parent process, unless the process is detached or a new console is created. A child console process also inherits the parent's standard handles, as well as access to the input buffer and the active screen buffer. For more about console processes, see Consoles and Character-Mode Support.

The fInheritHandles parameter of CreateProcess determines whether the inheritable handles of the parent process are inherited by the child process. The inheritability of the handles is specified in the functions used to create, open, or duplicate the handles. This allows a child process to inherit some of its parent's handles, while not inheriting others. For each of these object types there is a creation function (such as CreateProcess or CreateFile) that takes a security attributes argument via a flag determines whether the handle can be inherited. If the security attributes argument is NULL, the handle is not inherited.

Some of these objects have an open function (such as OpenMutex or OpenEvent) with an inherit flag parameter that determines inheritability.

Any of these handles can be duplicated using the DuplicateHandle function by which you can specify whether the handle can be inherited. This can be useful if a process has an inheritable open handle that you do not want to be inherited by the child process. In this case, use DuplicateHandle to open a noninheritable duplicate of the handle, then use the CloseHandle function to close the inheritable handle. DuplicateHandle can also open an inheritable duplicate of a noninheritable handle.

An inherited handle has the same value and access privileges as the parent process's handle. To use a handle, the child process must retrieve the handle and know the object to which it refers. For most handles, the parent process must communicate this information to the child process. This can be done using the command line or any of the other methods for interprocess communication (such as pipes or shared memory).

An inherited handle refers to the same object as the parent process's handle does. When one process changes the state of the object, the change affects both processes. With file handles, for example, if one process uses a handle to read from a file, the current file position is moved for all processes using the same handle.

A child process inherits the environment variables and current directory of its parent process by default. However, CreateProcess enables the parent process to specify a different current directory or block of environment variables. For more information about environment variables, see Environment Variables

The child process does not inherit the following:

•	Priority class.

•	Memory handles.

•	Pseudohandles, as in the handles returned by the GetCurrentProcess or GetCurrentThread function. These handles are valid only for the calling process. For more information about these functions, see Process and Thread Handles and Identifiers.

•	DLL module handles returned by the LoadLibrary function.

•	GDI or USER handles, such as HBITMAP or HMENU. Refer to WINDEF.H for a complete list of these handles.


Environment Variables

Every process has an environment block that contains a set of environment variables and their values. The command processor for Microsoft® Windows NT™ (called CMD.EXE) provides the set command to display its environment block or to create new environment variables. Programs started by the command processor inherit the command processor's environment variables.

By default, a child process inherits the environment variables of its parent process. However, you can specify a different environment for the child process by creating a new environment block and passing a pointer to it as a parameter to the CreateProcess function.

The GetEnvironmentStrings function returns a pointer to the environment block of the calling process. This should be treated as a read-only block; do not modify it directly. Instead, use the SetEnvironmentVariable function to change an environment variable. The GetEnvironmentVariable function determines whether a specified variable is defined in the environment of the calling process, and, if so, what its value is. For more information about environments, see the examples in Changing Environment Variables.


Setting Window Properties Using STARTUPINFO

A parent process can specify properties associated with the main window of its child process. A pointer to a STARTUPINFO structure is passed as a parameter to the CreateProcess function. The members of this structure can be used to specify more than a dozen different characteristics of the child's main window. The dwFlags member contains a bit field that determines whether the other members of the structure are used. This allows the creating process to specify values for any subset of the window properties. Default values are used for the properties not specified by dwFlags. The dwFlags member can also force a feedback cursor to be displayed during the initialization of the new process. A process can use the GetStartupInfo function to retrieve the STARTUPINFO structure specified when it was created.

For GUI processes, the STARTUPINFO structure specifies the default values to be used the first time the new process calls the CreateWindow and ShowWindow functions to create and display an overlapped window. The following default values can be specified:

•	The width and height, in pixels, of the window created by CreateWindow.

•	The location in screen coordinates of the window created by CreateWindow.

•	The nCmdShow parameter of ShowWindow.

For console processes, use the STARTUPINFO specifications only when a new console is created either by CreateProcess with CREATE_NEW_CONSOLE specified, or by the AllocConsole function. For more about console processes, see Consoles and Character-Mode Support. STARTUPINFO can specify the following console window properties:

•	The size, in character cells, and the location in screen coordinates of the new console window.

•	The size, in character cells, of the new console's screen buffer.

•	The text and background color attributes of the new console's screen buffer.

•	The title of the new console's window.


Terminating a Process

A process terminates when one of the following occurs:

•	Any thread of the process calls the ExitProcess function.

•	The primary thread of the process returns. This results in an implicit call to ExitProcess.

•	The last thread of the process terminates.

•	The TerminateProcess function is called with a handle to the process.

When a process terminates, the following events occur:

•	Open handles to files or other resources are closed automatically. Note that the objects referenced by these handles exist until all open handles are closed. This means that an object remains valid after a process closes, if another process has a handle to it.

•	The state of the process object becomes signaled, satisfying any threads that are waiting for the process to terminate. For more about synchronization, see Synchronizing Execution of Multiple Threads.

•	The termination status of the process changes from STILL_ACTIVE to the exit value of the process.

Child processes are not automatically terminated when a parent process terminates.

ExitProcess is the preferred way to terminate a process, because it notifies all attached DLLs of the termination, and it ensures that all threads of the process are terminated. If a process is terminated by ExitProcess, the entry-point function of all attached DLLs is invoked with a value indicating that the process is detaching from the DLL. DLLs are not notified when a process is terminated by TerminateProcess. For more information about DLLs, see Dynamic-Link Libraries.

When a process is terminated by ExitProcess or TerminateProcess, all threads of the process are terminated immediately with no chance to run additional code (except for the DLL process detach code if ExitProcess is called). This means that the process does not execute code in termination handler blocks such as the finally block of the try-finally termination handler supported by Microsoft compilers. For more information about handlers, see Structured Exception Handling.

The primary thread of a process differs from the other threads of a process in that ExitProcess (rather than the ExitThread function) is invoked implicitly when a primary thread returns. Alternatively, the primary thread can avoid terminating other threads by explicitly calling ExitThread before it exits. In this case, one of the remaining threads explicitly calls ExitProcess, to ensure that all threads of the process are terminated. For example, it is possible for an attached DLL to create a thread that does not terminates unless ExitProcess is invoked.

ExitProcess can be invoked implicitly by the system. For most unhandled exceptions, the system's default action is to call ExitProcess. For console processes, ExitProcess is called by the default handler function that can be invoked when a CTRL+C or CTRL+BREAK signal is received. For more about console application, see Consoles and Character-Mode Support. Note that this default handling of console interrupt signals can terminate parent and child processes, because all processes attached to a console receive the signal. An interrupt signal received by a console window is propagated only to attached console processes. Detached processes and processes that have created new console windows are not affected. GUI processes are not affected by CTRL+C or CTRL+BREAK signals.

The GetExitCodeProcess function returns the termination status of a process. While a process is running, its termination status is STILL_ACTIVE. When a process terminates, its termination status is the exit value of the process, which is the value specified in the call to ExitProcess or TerminateProcess, or the value returned by the main or WinMain function of the process. If a process is terminated in some other way (for example, by a fatal, unhandled exception or a CTRL+C signal) the process's termination value is the exception value that caused the termination. The process's exit value is also used as the exit value of all of the threads that had not previously terminated.


Process and Thread Handles and Identifiers

When a new thread is created by the CreateThread or CreateRemoteThread function, a handle of the thread is returned. Similarly, when a new process is created by the CreateProcess function, handles of the new process and its primary thread are returned. These handles are created with full access rights, and — subject to security access checking — can be used in any of the functions that accepts a thread or process handle. These handles can be inherited by child processes, depending on the inheritance flag specified when they are created. The handles are valid until closed, even after the process or thread they represent is terminated.

The OpenProcess function opens a handle to a process specified by its process identifier. OpenProcess enables you to specify the handle's access rights and inheritability.

A process can use the GetCurrentProcess function to retrieve a pseudohandle of its own process object; a thread can use the GetCurrentThread function to retrieve a pseudohandle to its own thread object. These pseudohandles are valid only for the calling process; they cannot be inherited or duplicated for use by other processes.

The functions that create a process or thread also return an identifier that uniquely identifies the process or thread throughout the system. A process can use the GetCurrentProcessId function to get its own process identifier. Similarly, a thread can use the GetCurrentThreadId function to get its own thread identifier. The identifiers are valid from the time the thread or process is created until the thread or process terminates.


Using Processes and Threads

•	Using a multithreaded multiple document interface application

•	Creating a child process with redirected input and output

•	Changing environment variables

•	Using thread local storage


Using a Multithreaded Multiple Document Interface Application

The following example shows how to use multiple threads in a multiple document interface (MDI) process. The process has a single main window, but can have any number of child windows. The primary thread of the process performs initialization and also handles messages to all windows through the application-defined MainWndProc and ChildWndProc functions.

Each time a child window is created, a new thread is also created. In this example, the new thread only checks continually to see if it is time to terminate. In a real application, the new thread could be used to draw the contents of the window or to carry out the functions associated with the window.

The ThreadFunc function is specified in the CreateThread function as the code for the new thread to execute. The handle of the child window associated with the thread is passed as a parameter to ThreadFunc. The child window's handle is also a parameter to ChildWndProc when a message is dispatched to the child window. A handle is necessary for any communication between a child window and its corresponding thread. Both ThreadFunc and ChildWndProc use the window handle in the SetWindowLong function to access the 32-bit value that is reserved for application use in each window structure. In this example, the 32-bit value is a termination flag. When ChildWndProc gets the WM_CLOSE message, it sets the flag; ThreadFunc checks the flag each time through its loop.

This example shows how to use normal priority for the primary thread and below-normal priority for the other threads. Because the primary thread passes all messages for both the main window and the child windows, its higher relative priority ensures responsiveness to user input. (Even when the child threads are left at normal priority, the scheduler automatically boosts the priority of the input thread when necessary.)

When the user terminates the process by closing the main window, a global Boolean parameter is set to terminate the child threads. At this point, the primary thread waits for each child thread to terminate before proceeding. This is necessary only if you want the threads to clean up, save changes to a file, or detach from DLLs before closing. Without waiting, the primary thread terminates the process by returning before the lower priority threads were able to run any additional code.

#include <windows.h>

#include <stdio.h>

#include <stdlib.h>

#define MM_NEWWIN       8001

typedef struct _PTHREADLIST {

  HANDLE hThread;

  LPVOID lpvNext;

} THREADLIST, *PTHREADLIST;

/* Globals */

HANDLE hModule;            /* handle to .EXE file for this process */

HWND   hwndMain = NULL;    /* handle to main window                */

BOOL fKillAll = FALSE;     /* sets TRUE to terminate all threads   */

PTHREADLIST pHead = NULL;  /* head of linked list of thread info.  */

/* Forward declarations */

BOOL InitializeApp(VOID);

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

LRESULT CALLBACK ChildWndProc(HWND, UINT, WPARAM, LPARAM);

DWORD ThreadFunc(HWND);

VOID AddThreadToList(HANDLE);

VOID ErrorExit(LPSTR);

/* Primary thread:  Initialize the application and dispatch messages. */

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst,

        LPSTR lpszCmdLn, int nShowCmd) {

    MSG msg;

    hModule = GetModuleHandle(NULL);

    if (! InitializeApp())

        ErrorExit("InitializeApp failure!");

    while (GetMessage(&msg, NULL, 0, 0)) {

      TranslateMessage(&msg);

      DispatchMessage(&msg);

    }

    return 1;

    UNREFERENCED_PARAMETER(hInst);

    UNREFERENCED_PARAMETER(hPrevInst);

    UNREFERENCED_PARAMETER(lpszCmdLn);

    UNREFERENCED_PARAMETER(nShowCmd);

}

/* Register window classes and create the main window. */

BOOL InitializeApp(VOID) {

    HMENU hmenuMain, hmenuPopup;

    WNDCLASS wc;

    /* Register a window class for the main window. */

    wc.style            = CS_OWNDC;

    wc.lpfnWndProc      = MainWndProc;

    wc.cbClsExtra       = 0;

    wc.cbWndExtra       = 0;

    wc.hInstance        = hModule;

    wc.hIcon            = LoadIcon(NULL,IDI_APPLICATION);

    wc.hCursor          = LoadCursor(NULL, IDC_ARROW);

    wc.hbrBackground    = (HBRUSH)(COLOR_BACKGROUND+1);

    wc.lpszMenuName     = NULL;

    wc.lpszClassName    = "MainWindowClass";

    if (! RegisterClass(&wc))

        return FALSE;

    /* Register a window class for child windows. */

    wc.lpfnWndProc      = ChildWndProc;

    wc.lpszClassName    = "ThreadWindowClass";

    if (! RegisterClass(&wc))

        return FALSE;

    /* Create a menu for the main window. */

    hmenuMain = CreateMenu();

    hmenuPopup = CreateMenu();

    if (! AppendMenu(hmenuPopup, MF_STRING, MM_NEWWIN, "&New Window"))

        return FALSE;

    if (! AppendMenu(hmenuMain, MF_POPUP, (UINT) hmenuPopup, "&Threads"))

        return FALSE;

    /* Create the main window. */

    hwndMain = CreateWindow("MainWindowClass", "Primary Window",

        WS_OVERLAPPED | WS_CAPTION | WS_BORDER | WS_THICKFRAME |

        WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_CLIPCHILDREN |

        WS_VISIBLE | WS_SYSMENU, CW_USEDEFAULT, CW_USEDEFAULT,

        CW_USEDEFAULT, CW_USEDEFAULT, NULL, hmenuMain, hModule,

        NULL);

    if (hwndMain == NULL)

        return FALSE;

    /* Set the initial focus. */

    SetFocus(hwndMain);

    return TRUE;

}

/* Main window procedure: Handle messages for the main window. */

LRESULT CALLBACK MainWndProc(HWND hwnd, UINT uiMessage,

        WPARAM wParam, LPARAM lParam) {

    static HWND hwndClient;

    static DWORD dwCount = 1;

    CLIENTCREATESTRUCT ccsClientCreate;

    HWND hwndChildWnd;

    DWORD IDThread;

    PTHREADLIST pNode;

    switch (uiMessage) {

       /* Create a client window to receive child window messages. */

       case WM_CREATE:

           ccsClientCreate.hWindowMenu = NULL;

           ccsClientCreate.idFirstChild = 1;

           hwndClient = CreateWindow("MDICLIENT", NULL,

               WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE, 0, 0, 0, 0,

               hwnd, NULL, hModule, (LPVOID)&ccsClientCreate);

           return 0L;

       /*

        * Close the main window.  First set fKillAll to TRUE to

        * terminate all threads.  Then wait for the threads to exit

        * before passing a close message to a default handler.  If you

        * don't wait for threads to terminate, process terminates

        * with no chance for thread cleanup.

        */

       case WM_CLOSE:

           fKillAll = TRUE;

           pNode = pHead;

           while (pNode) {

               DWORD dwRes;

               SetThreadPriority(pNode->hThread,

                   THREAD_PRIORITY_HIGHEST);

               dwRes = WaitForSingleObject(pNode->hThread,

                   INFINITE);

               pNode = (PTHREADLIST) pNode->lpvNext;

           }

           return DefFrameProc(hwnd, hwndClient, uiMessage,

               wParam, lParam);

       /* Terminate the process. */

       case WM_DESTROY:

           PostQuitMessage(0);

           return 0L;

       /* Handle the menu commands. */

       case WM_COMMAND:

           switch (LOWORD(wParam)) {

           /* Create a child window and start a thread for it. */

             case MM_NEWWIN: {

               HANDLE hThrd;

               MDICREATESTRUCT mdicCreate;

               TCHAR tchTitleBarText[32];

               LONG lPrev;

               sprintf(tchTitleBarText, "Thread Window %d", dwCount);

               mdicCreate.szClass = "ThreadWindowClass";

               mdicCreate.szTitle = tchTitleBarText;

               mdicCreate.hOwner  = hModule;

               mdicCreate.x = mdicCreate.y =

               mdicCreate.cx = mdicCreate.cy = CW_USEDEFAULT;

               mdicCreate.style = mdicCreate.lParam = 0L;

               /*

                * Send a "create child window" message to the

                * client window.

                */

               hwndChildWnd = (HWND) SendMessage(hwndClient,

                   WM_MDICREATE, 0L, (LONG)&mdicCreate);

               if (hwndChildWnd == NULL)

                   ErrorExit("Failed in Creating Thread Window!");

               /*

                * Window structure used to pass a quit message to

                * the thread.

                */

               lPrev = SetWindowLong(hwndChildWnd, GWL_USERDATA, 0);

               /* Create suspended, alter priority before resuming. */

               hThrd = CreateThread(NULL,  /* no security attributes */

                         0,                /* use default stack size */

                         (LPTHREAD_START_ROUTINE) ThreadFunc,

                         (LPVOID)hwndChildWnd, /* param to thrd func */

                         CREATE_SUSPENDED, /* creation flag          */

                         &IDThread);       /* returns thread id      */

               if (hThrd == NULL)

                   ErrorExit("CreateThread Failed!");

               AddThreadToList(hThrd);

               dwCount++;

               /*

                * Set the priority lower than the primary (input)

                * thread, so that the process is responsive to user

                * input.  Then resume the thread.

                */

               if (! SetThreadPriority(hThrd,

                       THREAD_PRIORITY_BELOW_NORMAL))

                   ErrorExit("SetThreadPriority failed!");

               if ((ResumeThread(hThrd)) == -1)

                   ErrorExit("ResumeThread failed!");

               return 0L;

             }

             default:

               return DefFrameProc(hwnd, hwndClient, uiMessage,

                              wParam, lParam);

           }

       default:

           return DefFrameProc(hwnd, hwndClient, uiMessage,

                          wParam, lParam);

    }

}

/* Handle messages for the child windows. */

LRESULT CALLBACK ChildWndProc(HWND hwnd, UINT uiMessage, WPARAM wParam,

 LPARAM lParam) {

    LONG lPrevLong;

    switch (uiMessage) {

        /* Use a window structure to pass "close" message to thread. */

        case WM_CLOSE:

            lPrevLong = SetWindowLong(hwnd, GWL_USERDATA, 1);

            return DefMDIChildProc(hwnd, uiMessage, wParam, lParam);

        case WM_DESTROY:

            return 0L;

        default:

            return DefMDIChildProc(hwnd, uiMessage, wParam, lParam);

    }

}

/*

 * Each child window has a thread that can be used to perform tasks

 * associated with that window--for example, drawing its contents.

 */

DWORD ThreadFunc(HWND hwnd) {

    LONG lKillMe = 0L;

    while (TRUE) {

        lKillMe = GetWindowLong(hwnd, GWL_USERDATA);

        if (fKillAll || lKillMe) break;

        /* Perform tasks. */

    }

        /* Perform actions needed before thread termination. */

    return 0;

}

VOID AddThreadToList(HANDLE hThread) {

    PTHREADLIST pNode;

    pNode = (PTHREADLIST) LocalAlloc(LPTR, sizeof(PTHREADLIST));

    if (pNode == NULL)

        ErrorExit("malloc Failed!");

    pNode->hThread = hThread;

    pNode->lpvNext = (LPVOID) pHead;

    pHead = pNode;

}

VOID ErrorExit(LPSTR lpszMessage) {

    MessageBox(hwndMain, lpszMessage, "Error", MB_OK);

    ExitProcess(0);

}


Creating a Child Process with Redirected Input and Output

The following example shows the creation of a child process by a console process and illustrates a technique for using anonymous pipes to redirect the child process's standard input and output. If you have a program that can read its input from the standard input (STDIN) or write its results to the standard output (STDOUT), redirected I/O enables you to execute the program as a child process while controlling its input and receiving its output.

The example shows how to use a SECURITY_ATTRIBUTES structure to create handles that can be inherited by the child process. The structure is used in the CreatePipe function to create inheritable handles to the read and write ends of two pipes. The read end of one pipe serves as standard input for the child process, and the write end of the other pipe is the child's standard output. These pipe handles are specified in the SetStdHandle function, which makes them the standard handles inherited by the child process. After the child process is created, SetStdHandle is used again to restore the original standard handles for the parent process.

The parent process uses the other ends of the pipes to write to the child's input and read the child's output. The handles to these ends of the pipe are also inheritable. However, the handle must not be inherited. Before creating the child process, the parent process must use DuplicateHandle to create a noninheritable duplicate of the application-defined hChildStdinWr global variable. It then uses CloseHandle to close the inheritable handle. This leaves the parent process with a pipe handle it can use, but which the child process does not inherit. For more information about pipes, see Pipes.

The following is the parent process.

#include <stdio.h>

#include <windows.h>

#define BUFSIZE 4096

HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup,

    hChildStdoutRd, hChildStdoutWr,

    hInputFile, hSaveStdin, hSaveStdout;

BOOL CreateChildProcess(VOID);

VOID WriteToPipe(VOID);

VOID ReadFromPipe(VOID);

VOID ErrorExit(LPTSTR);

VOID ErrMsg(LPTSTR, BOOL);

DWORD main(int argc, char *argv[]) {

    SECURITY_ATTRIBUTES saAttr;

    BOOL fSuccess;

    /* Set the bInheritHandle flag so pipe handles are inherited. */

    saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);

    saAttr.bInheritHandle = TRUE;

    saAttr.lpSecurityDescriptor = NULL;

    /*

     * The steps for redirecting child's STDOUT:

     *     1.  Save current STDOUT, to be restored later.

     *     2.  Create anonymous pipe to be STDOUT for child.

     *     3.  Set STDOUT of parent to be write handle of pipe, so

     *         it is inherited by child.

     */

    /* Save the handle to the current STDOUT. */

    hSaveStdout = GetStdHandle(STD_OUTPUT_HANDLE);

    /* Create a pipe for the child's STDOUT. */

    if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0))

        ErrorExit("Stdout pipe creation failed\n");

    /* Set a write handle to the pipe to be STDOUT. */

    if (! SetStdHandle(STD_OUTPUT_HANDLE, hChildStdoutWr))

        ErrorExit("Redirecting STDOUT failed");

    /*

     * The steps for redirecting child's STDIN:

     *     1.  Save current STDIN, to be restored later.

     *     2.  Create anonymous pipe to be STDIN for child.

     *     3.  Set STDIN of parent to be read handle of pipe, so

     *         it is inherited by child.

     *     4.  Create a noninheritable duplicate of write handle,

     *         and close the inheritable write handle.

     */

    /* Save the handle to the current STDIN. */

    hSaveStdin = GetStdHandle(STD_INPUT_HANDLE);

    /* Create a pipe for the child's STDIN. */

    if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0))

        ErrorExit("Stdin pipe creation failed\n");

    /* Set a read handle to the pipe to be STDIN. */

    if (! SetStdHandle(STD_INPUT_HANDLE, hChildStdinRd))

        ErrorExit("Redirecting Stdin failed");

    /* Duplicate the write handle to the pipe so it is not inherited. */

    fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,

        GetCurrentProcess(), &hChildStdinWrDup, 0,

        FALSE,       /* not inherited */

        DUPLICATE_SAME_ACCESS);

    if (! fSuccess)

        ErrorExit("DuplicateHandle failed");

    CloseHandle(hChildStdinWr);

    /* Now create the child process. */

    if (! CreateChildProcess())

        ErrorExit("Create process failed");

    /* After process creation, restore the saved STDIN and STDOUT. */

    if (! SetStdHandle(STD_INPUT_HANDLE, hSaveStdin))

        ErrorExit("Re-redirecting Stdin failed\n");

    if (! SetStdHandle(STD_OUTPUT_HANDLE, hSaveStdout))

        ErrorExit("Re-redirecting Stdout failed\n");

    /* Get a handle to the parent's input file. */

    if (argc > 1)

        hInputFile = CreateFile(argv[1], GENERIC_READ, 0, NULL,

            OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);

    else

        hInputFile = hSaveStdin;

    if (hInputFile == INVALID_HANDLE_VALUE)

        ErrorExit("no input file\n");

    /* Write to pipe that is the standard input for a child process. */

    WriteToPipe();

    /* Read from pipe that is the standard output for child process. */

    ReadFromPipe();

    return 0;

}

BOOL CreateChildProcess() {

    PROCESS_INFORMATION piProcInfo;

    STARTUPINFO siStartInfo;

    /* Set up members of STARTUPINFO structure. */

    siStartInfo.cb = sizeof(STARTUPINFO);

    siStartInfo.lpReserved = NULL;

    siStartInfo.lpReserved2 = NULL;

    siStartInfo.cbReserved2 = 0;

    siStartInfo.lpDesktop = NULL;

    siStartInfo.dwFlags = 0;

    /* Create the child process. */

    return CreateProcess(NULL,

        "child",       /* command line                       */

        NULL,          /* process security attributes        */

        NULL,          /* primary thread security attributes */

        TRUE,          /* handles are inherited              */

        0,             /* creation flags                     */

        NULL,          /* use parent's environment           */

        NULL,          /* use parent's current directory     */

        &siStartInfo,  /* STARTUPINFO pointer                */

        &piProcInfo);  /* receives PROCESS_INFORMATION       */

VOID WriteToPipe(VOID) {

    DWORD dwRead, dwWritten;

    CHAR chBuf[BUFSIZE];

    /* Read from a file and write its contents to a pipe. */

    for (;;) {

        if (! ReadFile(hInputFile, chBuf, BUFSIZE, &dwRead, NULL) ||

            dwRead == 0) break;

        if (! WriteFile(hChildStdinWrDup, chBuf, dwRead,

            &dwWritten, NULL)) break;

    }

    /* Close the pipe handle so the child stops reading. */

    if (! CloseHandle(hChildStdinWrDup))

        ErrorExit("Close pipe failed\n");

}

VOID ReadFromPipe(VOID) {

    DWORD dwRead, dwWritten;

    CHAR chBuf[BUFSIZE];

    HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);

    /*

     * Close the write end of the pipe before reading from the

     * read end of the pipe.

     */

    if (! CloseHandle(hChildStdoutWr))

        ErrorExit("Closing handle failed");

    /* Read output from child, and write it to parent's STDOUT. */

    for (;;) {

        if (! ReadFile(hChildStdoutRd, chBuf, BUFSIZE, &dwRead, NULL) ||

            dwRead == 0) break;

        if (! WriteFile(hSaveStdout, chBuf, dwRead, &dwWritten, NULL))

            break;

    }

}

VOID ErrorExit (LPTSTR lpszMessage) {

    fprintf(stderr, "%s\n", lpszMessage);

    ExitProcess(0);

}

Here's the child process:

#include <windows.h>

#define BUFSIZE 4096

VOID main(VOID) {

    CHAR chBuf[BUFSIZE];

    DWORD dwRead, dwWritten;

    HANDLE hStdin, hStdout;

    BOOL fSuccess;

    hStdout = GetStdHandle(STD_OUTPUT_HANDLE);

    hStdin = GetStdHandle(STD_INPUT_HANDLE);

    if ((hStdout == INVALID_HANDLE_VALUE) ||

        (hStdin == INVALID_HANDLE_VALUE))

        ExitProcess(1);

    for (;;) {

      /* Read from standard input. */

      fSuccess = ReadFile(hStdin, chBuf, BUFSIZE, &dwRead, NULL);

      if (! fSuccess || dwRead == 0)

          break;

      /* Write to standard output. */

      fSuccess = WriteFile(hStdout, chBuf, dwRead, &dwWritten, NULL);

      if (! fSuccess)

          break;

    }

}


Changing Environment Variables

The environment block consists of a null-terminated block of null-terminated strings (that is, two null bytes at the end of the block), where each string is in the form:

name=value

Because the equal sign is a separator, it must not be used in the name of an environment variable. The following example creates a new environment block to pass to a child process.

TCHAR tchNewEnv[BUFSIZE];

LPTSTR lpszCurrentVariable;

BOOL fSuccess;

/* Copy name=value environment variable pairs into environment block. */

lpszCurrentVariable = tchNewEnv;

if (lstrcpy(lpszCurrentVariable, "OperatingSystem=Windows") == NULL)

    ErrorExit("lstrcpy failed");

lpszCurrentVariable += lstrlen(lpszCurrentVariable) + 1;

if (lstrcpy(lpszCurrentVariable, "API=Win32") == NULL)

    ErrorExit("lstrcpy failed");

/* Terminate the block with a NULL byte. */

lpszCurrentVariable += lstrlen(lpszCurrentVariable) + 1;

*lpszCurrentVariable = '\0';

/* Create the child process, specifying a new environment block. */

fSuccess = CreateProcess(NULL, "childenv", NULL, NULL, TRUE, 0,

    (LPVOID) tchNewEnv,     /* new environment block */

    NULL, &siStartInfo, &piProcInfo);

if (! fSuccess)

    ErrorExit("CreateProcess failed");

If you want the child process to inherit most of the parent's environment with only a few changes, save the current values, make changes for the child to inherit, and then restore the saved values for example.

LPTSTR lpszOldValue;

TCHAR tchBuf[BUFSIZE];

BOOL fSuccess;

/*

 * lpszOldValue gets current value of "varname", or NULL if "varname"

 * environment variable does not exist. Set "varname" to new value,

 * create child process, then use SetEnvironmentVariable to restore

 * original value of "varname". If lpszOldValue is NULL, the "varname"

 * variable will be deleted.

 */

lpszOldValue = ((GetEnvironmentVariable("varname",

    tchBuf, BUFSIZE) > 0) ? tchBuf : NULL);

/* Set a value for the child to inherit. */

if (! SetEnvironmentVariable("varname", "newvalue"))

    ErrorExit("SetEnvironmentVariable failed");

/* Create a child process. */

fSuccess = CreateProcess(NULL, "childenv", NULL, NULL, TRUE, 0,

    NULL,     /* inherit parent's environment */

    NULL, &siStartInfo, &piProcInfo);

if (! fSuccess)

    ErrorExit("CreateProcess failed");

/* Restore the parent's environment. */

if (! SetEnvironmentVariable("varname", lpszOldValue))

    ErrorExit("SetEnvironmentVariable failed");

The following example, taken from a console process, prints the contents of the process's environment block.

LPTSTR lpszVariable;

LPVOID lpvEnv;

/* Get a pointer to the environment block. */

lpvEnv = GetEnvironmentStrings();

/*

 * Variable strings are separated by NULL byte, and the block is

 * terminated by a NULL byte.

 */

for (lpszVariable = (LPTSTR) lpvEnv; *lpszVariable; lpszVariable++) {

    while (*lpszVariable)

        putchar(*lpszVariable++);

    putchar('\n');

}


Using Thread Local Storage

Thread local storage (TLS) enables multiple threads of the same process to use an index allocated by the TlsAlloc function to store and retrieve a value that is local to the thread. In this example, an index is allocated when the process starts. When each thread starts, it allocates a block of dynamic memory and stores a pointer to this memory by using the TLS index. The TLS index is used by the locally defined CommonFunc function to access the data local to the calling thread. Before each thread terminates, it releases its dynamic memory.

#include <stdio.h>

#include <windows.h>

#define THREADCOUNT 4

DWORD dwTlsIndex;

VOID ErrorExit(LPTSTR);

VOID CommonFunc(VOID) {

  LPVOID lpvData;

    /* Retrieve a data pointer for the current thread. */

    lpvData = TlsGetValue(dwTlsIndex);

    if ((lpvData == 0) && (GetLastError() != 0))

        ErrorExit("TlsGetValue error");

    /*

     *    Use the data stored for the current thread.

     */

    printf("common: thread %d: lpvData=%lx\n",

        GetCurrentThreadId(), lpvData);

    Sleep(5000);

}

DWORD ThreadFunc(VOID) {

    LPVOID lpvData;

    /* Initialize the TLS index for this thread. */

    lpvData = (LPVOID) LocalAlloc(LPTR, 256);

    if (! TlsSetValue(dwTlsIndex, lpvData))

        ErrorExit("TlsSetValue error");

    printf("thread %d: lpvData=%lx\n", GetCurrentThreadId(), lpvData);

    CommonFunc();

    /* Release the dynamic memory before the thread returns. */

    lpvData = TlsGetValue(dwTlsIndex);

    if (lpvData != 0)

        LocalFree((HLOCAL) lpvData);

    return 0;

}

DWORD main(VOID) {

    DWORD IDThread;

    HANDLE hThread[THREADCOUNT];

    int i;

    /* Allocate a TLS index. */

    if ((dwTlsIndex = TlsAlloc()) == 0xFFFFFFFF)

        ErrorExit("TlsAlloc failed");

    /* Create multiple threads. */

    for (i = 0; i < THREADCOUNT; i++) {

        hThread[i] = CreateThread(NULL,/* no security attributes    */

            0,                       /* use default stack size      */

            (LPTHREAD_START_ROUTINE) ThreadFunc, /* thread function */

            NULL,                    /* no thread function argument */

            0,                       /* use default creation flags  */

            &IDThread);              /* returns thread identifier   */

        /* Check the return value for success. */

        if (hThread[i] == NULL)

            ErrorExit("CreateThread error\n");

    }

    for (i = 0; i < THREADCOUNT; i++)

        WaitForSingleObject(hThread[i], INFINITE);

    return 0;

}

VOID ErrorExit (LPTSTR lpszMessage) {

    fprintf(stderr, "%s\n", lpszMessage);

    ExitProcess(0);

}


Process and Thread Functions

Following are the functions used with processes and threads.

AttachThreadInput
CommandLineToArgvW
CreateProcess
CreateRemoteThread
CreateThread
ExitProcess
ExitThread
FreeEnvironmentStrings
GetCommandLine
GetCurrentProcess
GetCurrentProcessId
GetCurrentThread
GetCurrentThreadId
GetEnvironmentStrings
GetEnvironmentVariable
GetExitCodeProcess
GetExitCodeThread
GetPriorityClass
GetProcessAffinityMask
GetProcessShutdownParameters
GetProcessTimes
GetProcessVersion
GetProcessWorkingSetSize
GetStartupInfo
GetThreadPriority
GetThreadTimes
OpenProcess
ResumeThread
SetEnvironmentVariable
SetPriorityClass
SetProcessShutdownParameters
SetThreadAffinityMask
SetThreadPriority
Sleep
SleepEx
SetProcessWorkingSetSize
SuspendThread
TerminateProcess
TerminateThread
TlsAlloc
TlsFree
TlsGetValue
TlsSetValue
WaitForInputIdle
WinExec

Obsolete or Deleted Functions

Yield


Registry

The registry is a system-defined database that applications and Microsoft® Windows® system components use to store and retrieve configuration data.


About the Registry

The registry stores data in binary files. To manipulate registry data, an application must use the registry functions. This overview describes the registry and the functions that applications use to access and manipulate the data stored there. The data stored in the registry varies according to the Windows platform that is used. This overview contains a description of registry entries that can exist on any platform.


Structure of the Registry

The registry stores data in a hierarchically structured tree. Each node in the tree is called a key. Each key can contain both subkeys and data entries called values. Sometimes, the presence of a key is all the data that an application requires; other times, an application opens a key and uses the values associated with the key. A key can have any number of values, and the values can be in any form.

Each key has a name consisting of one or more printable ANSI characters — that is, characters ranging from values 32 through 127. Key names cannot include a space, a backslash (\), or a wildcard character (* or ?). Key names beginning with a period (.) are reserved. The name of each subkey is unique with respect to the key that is immediately above it in the hierarchy. Key names are not localized into other languages, although values may be.


Registry Storage Space

Although there are few technical limits to the type and size of data an application can store in the registry, certain practical guidelines exist to promote system efficiency. An application should store configuration and initialization data in the registry, but other kinds of data should be stored elsewhere.

Generally, data consisting of more than one or two kilobytes (K) should be stored as a file and referred to by using a key in the registry rather than being stored as a value. Instead of duplicating large pieces of data in the registry, an application should save the data as a file and refer to the file. Executable binary code should never be stored in the registry.

A value entry uses much less registry space than a key. To save space, an application should group similar data together as a structure and store the structure as a value rather than storing each of the structure members as a separate key. (Storing the data in binary form allows an application to store data in one value that would otherwise be made up of several incompatible types.)


Predefined Keys

An application must open a key before it can add data to the registry. To open a key, an application must supply the handle of another key in the registry that is already open. The system defines standard handles that are always open. An application can use these predefined handles as entry points to the registry.

The system provides two predefined keys at the root of the registry: HKEY_LOCAL_MACHINE and HKEY_USERS. In addition, the system defines two subkeys: HKEY_CLASSES_ROOT (a subkey of HKEY_LOCAL_MACHINE) and HKEY_CURRENT_USER (a subkey of HKEY_USERS). These registry handles are valid for all Win32 implementations of the registry, although the use of the handles may vary from platform to platform.

Predefined keys help an application navigate in the registry and make it possible to develop tools that allow a system administrator to manipulate categories of data. Applications that add data to the registry should always work within the framework of predefined keys, so administrative tools can find and use the new data.

These predefined keys are used as entry points to the registry.

Entry point	Use
HKEY_CLASSES_ROOT	Registry entries subordinate to this key define types (or classes) of documents and the properties associated with those types. Data stored under this key is used by Windows shell applications and by object linking and embedding (OLE) applications.
HKEY_CURRENT_USER	Registry entries subordinate to this key define the preferences of the current user. These preferences include the settings of environment variables, data about program groups, colors, printers, network connections, and application preferences.
HKEY_LOCAL_MACHINE	Registry entries subordinate to this key define the physical state of the computer, including data about the bus type, system memory, and installed hardware and software.
HKEY_USERS	Registry entries subordinate to this key define the default user configuration for new users on the local computer and the user configuration for the current user.
The use of HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, and HKEY_USERS varies depending on the implementation of the registry. In addition, other predefined handles have been defined for specific Windows platforms.


Categories of Data

Before putting data into the registry, an application should divide the data into two categories: computer-specific data and user-specific data. By making this distinction, an application can support multiple users, and yet locate user-specific data over a network and use that data in different locations, allowing location-independent user profile data. (A user profile is a set of configuration data saved for every user.)

When the application is installed, it should record the computer-specific data under the HKEY_LOCAL_MACHINE key. In particular, it should create keys for the company name, product name, and version number, as shown in the following example:

HKEY_LOCAL_MACHINE\Software\MyCompany\MyProduct\1.0

If the application supports OLE, it should record that data under HKEY_LOCAL_MACHINE\Software\Classes.

An application should record user-specific data under the HKEY_CURRENT_USER key, as shown in the following example:

HKEY_CURRENT_USER\Software\MyCompany\MyProduct\1.0\...


Opening, Creating, and Closing Keys

Before an application can add data to the registry, it must create or open a key. To create or open a key, an application always refers to the key as a subkey of a currently open key. The four predefined keys (HKEY_LOCAL_MACHINE, HKEY_CLASSES_ROOT, HKEY_USERS, and HKEY_CURRENT_USER) are always open. An application uses the RegOpenKey or RegOpenKeyEx function to open a key and the RegCreateKey or RegCreateKeyEx function to create a key.

An application can use the RegCloseKey function to close a key and write the data it contains into the registry. RegCloseKey does not necessarily write the data to the registry before returning; it can take as much as several seconds for the cache to be flushed to the hard disk. If an application must explicitly write registry data to the hard disk, it can use the RegFlushKey function. RegFlushKey, however, uses many system resources and should be called only when absolutely necessary.


Writing and Deleting Registry Data

An application can use either the RegSetValue or RegSetValueEx function to associate a value and its data with a key. RegSetValue works only with strings (values having the REG_SZ type). RegSetValueEx, however, can write values with any type of data. Either of these functions can create a key and its value at the same time.

To delete a value from a key, an application can use the RegDeleteValue function. To delete a key, it can use the RegDeleteKey function. A deleted key is not removed until the last handle to it has been closed. Subkeys and values cannot be created under a deleted key.

To change a key's security information, an application can use the RegSetKeySecurity function.


Retrieving Data from the Registry

To retrieve data from the registry, an application typically enumerates the subkeys of a key until it finds a particular one and then retrieves data from the value or values associated with it. An application can call either the RegEnumKey or RegEnumKeyEx function to enumerate the subkeys of a given key. RegEnumKeyEx returns a subkey and its class, but RegEnumKey returns only the subkey, not the class.

To retrieve detailed data about a particular subkey, an application can call the RegQueryInfoKey function. The RegGetKeySecurity function retrieves a copy of the security descriptor protecting a key.

An application can use the RegEnumValue function to enumerate the values for a given key, and the RegQueryValue or RegQueryValueEx function to retrieve a particular value for a key. An application typically calls RegEnumValue to determine the value names and then RegQueryValueEx to retrieve the data for the names.

RegQueryValue and RegQueryValueEx differ in how they treat unexpanded references to environment variables. If an unnamed value contains an unexpanded environment variable (for example, %PATH%), RegQueryValue expands the variable into the storage buffer provided as one of its parameters. RegQueryValueEx, however, does not expand these references. (Applications can also use the ExpandEnvironmentStrings function to expand environment variables.)


Registry Files

Applications can save part of the registry in a file and then load the contents of the file back into the registry. A registry file is useful when a large amount of data is being manipulated, when many entries are being made in the registry, or when the data is transitory and must be loaded and then unloaded again. Applications that back up and restore parts of the registry are likely to use registry files.

To save a key and its subkeys and values to a registry file, an application can call the RegSaveKey function. To write the registry file back to the registry, an application can use the RegLoadKey, RegReplaceKey, or RegRestoreKey function.

RegLoadKey loads registry data from a specified file into a specified subkey under HKEY_USERS or HKEY_LOCAL_MACHINE on the calling application's computer or on a remote computer. The function creates the specified subkey if it does not already exist. After calling this function, an application can use the RegUnLoadKey function to restore the registry to its previous state.

RegReplaceKey replaces a key and all its subkeys and values in the registry with the data contained in a specified file. The new data takes effect the next time the system is started.

RegRestoreKey loads registry data from a specified file into a specified key on the calling application's computer or on a remote computer. This function replaces the subkeys and values below the specified key with the subkeys and values that follow the top-level key in the file.


Using the Registry

The following example demonstrates the use of the RegQueryInfoKey, RegEnumKey, and RegEnumValue functions. The hKey parameter passed to each function is the handle of an open key. This key must be opened before the function call and closed afterward.

// QueryKey - enumerates the subkeys of a given key and the associated

//     values and then copies the information about the keys and values

//     into a pair of edit controls and list boxes.

// hDlg - dialog box that contains the edit controls and list boxes

// hKey - key whose subkeys and values are to be enumerated

VOID QueryKey(HWND hDlg, HANDLE hKey)

{

    CHAR     achKey[MAX_PATH];

    CHAR     achClass[MAX_PATH] = "";  /* buffer for class name   */

    DWORD    cchClassName = MAX_PATH;  /* length of class string  */

    DWORD    cSubKeys;                 /* number of subkeys       */

    DWORD    cbMaxSubKey;              /* longest subkey size     */

    DWORD    cchMaxClass;              /* longest class string    */

    DWORD    cValues;              /* number of values for key    */

    DWORD    cchMaxValue;          /* longest value name          */

    DWORD    cbMaxValueData;       /* longest value data          */

    DWORD    cbSecurityDescriptor; /* size of security descriptor */

    FILETIME ftLastWriteTime;      /* last write time             */

    DWORD i, j;

    DWORD retCode, retValue;

    CHAR  achValue[MAX_VALUE_NAME];

    DWORD cchValue = MAX_VALUE_NAME;

    CHAR  achBuff[80];

    // Get the class name and the value count.

    RegQueryInfoKey(hKey,        /* key handle                    */

        achClass,                /* buffer for class name         */

        &cchClassName,           /* length of class string        */

        NULL,                    /* reserved                      */

        &cSubKeys,               /* number of subkeys             */

        &cbMaxSubKey,            /* longest subkey size           */

        &cchMaxClass,            /* longest class string          */

        &cValues,                /* number of values for this key */

        &cchMaxValue,            /* longest value name            */

        &cbMaxValueData,         /* longest value data            */

        &cbSecurityDescriptor,   /* security descriptor           */

        &ftLastWriteTime);       /* last write time               */

    SetDlgItemText(hDlg, IDE_CLASS, achClass);

    SetDlgItemInt(hDlg, IDE_CVALUES, cValues, FALSE);

    SendMessage(GetDlgItem(hDlg, IDL_LISTBOX),

        LB_ADDSTRING, 0, (LONG) "..");

    // Enumerate the child keys, looping until RegEnumKey fails. Then

    // get the name of each child key and copy it into the list box.

    SetCursor(LoadCursor(NULL, IDC_WAIT));

    for (i = 0, retCode = ERROR_SUCCESS;

            retCode == ERROR_SUCCESS; i++) {

        retCode = RegEnumKey(hKey, i, achKey, MAX_PATH);

        if (retCode == (DWORD)ERROR_SUCCESS)

            SendMessage(GetDlgItem(hDlg, IDL_LISTBOX),

                LB_ADDSTRING, 0, (LONG) achKey);

    }

    SetCursor(LoadCursor (NULL, IDC_ARROW));

    // Enumerate the key values.

    SetCursor(LoadCursor(NULL, IDC_WAIT));

    if (cValues)

        for (j = 0, retValue = ERROR_SUCCESS;

                j < cValues; j++) {

            cchValue = MAX_VALUE_NAME;

            achValue[0] = '\0';

            retValue = RegEnumValue(hKey, j, achValue,

                &cchValue,

                NULL,

                NULL,    /* &dwType, */

                NULL,    /* &bData,  */

                NULL);   /* &bcData  */

            if (retValue != (DWORD) ERROR_SUCCESS &&

                    retValue != ERROR_INSUFFICIENT_BUFFER) {

                wsprintf (achBuff,

                    "Line:%d 0 based index = %d, retValue = %d, "

                     "ValueLen = %d",

                     __LINE__, j, retValue, cchValue);

                MessageBox (hDlg, achBuff, "Debug", MB_OK);

            }

            achBuff[0] = '\0';

            // Add each value to a list box.

            if (!lstrlen(achValue))

                lstrcpy(achValue, "<NO NAME>");

            wsprintf(achBuff, "%d) %s ", j, achValue);

            SendMessage(GetDlgItem(hDlg,IDL_LISTBOX2),

                LB_ADDSTRING, 0, (LONG) achBuff);

        }

    SetCursor(LoadCursor(NULL, IDC_ARROW));

}


Registry Functions

Following are the functions used with the registry:

RegCloseKey
RegConnectRegistry
RegCreateKey
RegCreateKeyEx
RegDeleteKey
RegDeleteValue
RegEnumKey
RegEnumKeyEx
RegEnumValue
RegFlushKey
RegGetKeySecurity
RegLoadKey
RegNotifyChangeKeyValue
RegOpenKey
RegOpenKeyEx
RegQueryInfoKey
RegQueryValue
RegQueryValueEx
RegReplaceKey
RegRestoreKey
RegSaveKey
RegSetKeySecurity
RegSetValue
RegSetValueEx
RegUnLoadKey


Remote Access Service

Remote Access Service (RAS) lets users at remote locations work as if connected directly to a computer network, accessing one or more RAS servers.


About Remote Access Service

Win32 RAS support enables a RAS client application to start a RAS connection operation, get information about existing RAS connections, and end a RAS connection.

Microsoft® Win32® application programming interface (API) does not currently provide support for applications to administer the Remote Access Server.

This overview discusses the following topics:

•	Types of RAS connection operations

•	Phonebook files and the information needed to establish a connection

•	Connection states during a connection operation

•	Notification handlers for tracking the progress of a connection operation

•	Paused states during a connection operation that enable the RAS client to collect additional information from the user

•	Support for connection operations that require a callback from the remote server

•	Ending a RAS connection


RAS Connection Operations

A RAS client application uses the RasDial function to establish a connection to a RAS server. The RasDial function starts the connection operation, which is then carried out by the Remote Access Connection Manager.

The Remote Access Connection Manager is a service that handles the details of establishing the connection to the remote server. This service also provides the client with status information during the connection operation. The Remote Access Connection Manager starts automatically when an application loads the RASAPI32.DLL.

The RasDial call specifies the following information when it starts a connection operation:

•	The connection information that the Remote Access Connection Manager needs to establish the connection.

•	An optional notification handler that receives progress notifications during the connection operation. If the RasDial call specifies a notification handler, the call is asynchronous; otherwise, it is synchronous.

•	An optional RASDIALEXTENSIONS structure to enable or disable extensions to the RasDial operation. The extensions permit a RAS client to directly enable some modem settings, to control whether RAS uses the prefixes and suffixes in a phonebook entry, and to support paused states during the connection operation.


Synchronous Operations

When RasDial is invoked as a synchronous operation, the function does not return until the connection has been established or an error occurs. Synchronous mode provides a simple way for a RAS client to establish a connection. The client can simply call RasDial, wait for the function to return, and then call the RasGetConnectStatus function to determine whether the connection operation was successful. Once the connection has been established, the client application can terminate without breaking the connection. If an error occurs, the client application must shut down the connection operation before terminating.

The disadvantage of synchronous mode is that the client does not receive progress notifications as the connection operation proceeds. As a workaround for this lack of progress notifications, a synchronous mode client can use a separate thread that calls RasGetConnectStatus to poll for and display the current state. However, for RAS clients that want to receive progress information, the preferred technique is to invoke RasDial asynchronously.


Asynchronous Operations

When RasDial is invoked as an asynchronous operation, the function returns immediately. In asynchronous mode, the RasDial call must specify a notification handler that the Remote Access Connection Manager uses to inform the client whenever the connection operation changes states or an error occurs.

The notification handler can be a window to receive messages, or a RasDialFunc or RasDialFunc1 callback function. The Remote Access Connection Manager makes its asynchronous notifications in the context of the thread that made the RasDial call. For this reason, the calling thread must not terminate until the connection operation has been successfully established or an error occurs. As in synchronous mode, the client application can safely terminate once the connection has been established, and it must shut down the connection operation if an error occurs.


Phonebook Files and Connection Information

A RasDial call must specify the information that the Remote Access Connection Manager needs to establish the connection. Typically, the RasDial call provides the connection information by specifying a phonebook entry in a phonebook file. The connection information in a phonebook entry includes phone numbers, bps rates, user authentication information, and other connection information.

A RAS client uses the parameters of the RasDial function to specify a phonebook file and an entry in that file. The lpszPhonebookPath parameter can specify the name of a phonebook file, or it can be NULL to indicate that the default phonebook file should be used. The lpRasDialParams parameter points to a RASDIALPARAMS structure that specifies the name of the phonebook entry to use.

To display a list of phonebook entries from which the user can select a connection, a RAS client can call the RasEnumEntries function to enumerate the entries in a phonebook file.

To make a connection without using a phonebook entry, the RasDial call can specify an empty string for the szEntryName member of the RASDIALPARAMS structure. The RASDIALPARAMS.szPhoneNumber member must contain the number to call. In this case, the Remote Access Connection Manager uses the first available modem port and default values for all other settings.


Phonebook Files

Phonebook files provide a standard way to collect and specify the information that the Remote Access Connection Manager needs to establish a remote connection. A phonebook file is a text file that associates entry names with information such as phone numbers, COM ports, and modem settings. Each phonebook entry contains the information needed to establish a RAS connection.

The Win32 API does not currently provide support for creating a phonebook file.

Windows 95: Dial-up networking stores phonebook entries in the registry rather than in a phonebook file. A user or administrator can use the Dial-Up Networking folder to create and edit phonebook entries. You can use the RasCreatePhonebookEntry and RasEditPhonebookEntry functions to create or edit a phonebook entry. These functions display a dialog box in which the user can specify information about the phonebook entry. You can use the RasGetEntryDialParams and RasSetEntryDialParams functions to set or retrieve the connection parameters for a phonebook entry.

Windows NT:  The functions for creating and editing a phonebook entry are not supported. Microsoft's remote access application, RASPHONE.EXE, creates a default phonebook file called RASPHONE.PBK, and can also create personal phonebook files. A user or administrator can use RASPHONE.EXE to create and edit entries in a phonebook file. Using RASPHONE.EXE is currently the only safe way to create a phonebook file or to create or edit a phonebook entry.


User Authentication Information

The Remote Access Connection Manager service on the client computer sends a user name and password to the RAS server on the remote computer. Before it will establish a connection, the remote server uses this information to authenticate the user. By default, the Remote Access Connection Manager sends the user name and password of the currently logged-on user. The RAS client can use the RASDIALPARAMS structure specified in the RasDial call to specify a different user name and password.

If the remote server cannot authenticate the user with the specified information, it can allow the connection operation to enter a paused state to enable the RAS client to collect different authentication data from the user.


Other Connection Information

The members of the RASDIALPARAMS structure can also specify the following connection information:

•	A phone number to override the number in the phonebook entry.

•	A callback phone number that the remote server can call back to establish the connection.

•	The name of the remote network domain on which the authentication is to occur.

For the callback number and the domain, the RASDIALPARAMS members can either indicate that RAS should use the information in the phonebook entry, or it can provide information that overrides the phonebook data.

A RAS client can use the lpRasDialExtensions parameter of the RasDial function to control whether RAS uses a phone number prefix or suffix specified in a phonebook entry.


Connection States

During the process of connecting to a remote server, the Remote Access Connection Manager and the RAS server on the remote computer perform several steps to establish the connection. Each of these steps is identified by a connection state. The RASCONNSTATE enumeration is a set of values that correspond to these connection states. The connection states can be divided into the following three groups:

Running states	The running states are the parts of the connection operation that RAS handles automatically, such as connecting to the necessary devices, authenticating the user, and waiting for a callback from the remote server. Unless an error occurs, the RAS client need take no action other than to pass the notification on to the user.
Paused states	The paused states occur when the remote server pauses the connection operation to get additional input from the user. During a paused state, the user can type a callback number, a different user name and password if the user authentication fails, or a new password if the old one has expired.
Terminal states	The terminal states occur when the connection has been successfully established, the connection operation has failed, or the connection has been broken by a RasHangUp call.
There are several mechanisms that a RAS client can use to determine the current state of a connection operation. When a RAS client executes the RasDial function asynchronously, the Remote Access Connection Manager sends progress notifications to the client's notification handler whenever the connection state changes. In addition, the client can use the RasGetConnectStatus function to get the current state of any RAS connection operation.


Notification Handlers

An asynchronous RasDial call must specify a notification handler. During an asynchronous connection operation, the Remote Access Connection Manager uses the notification handler to inform the RAS client whenever the connection state changes or an error occurs.

The actions performed by a notification handler can be divided into the following categories:

•	Handling errors.

•	Providing feedback to the user as the connection operation proceeds through the various connection states. See Informational Notifications.

•	Handling paused states.

•	Signaling the RAS client application when the connection operation has been completed. See Completion Notifications.

There are three types of notification handlers, each of which receives the same basic information: the current connection state and an error code that is nonzero only if an error has occurred.

RasDialFunc	A callback function prototype that receives only the current connection state and error code information.
RasDialFunc1	A callback function prototype that receives the HRASCONN connection handle and extended error information in addition to the basic information. The connection handle parameter makes RasDialFunc1 useful for client applications that support multiple simultaneous connection operations. This allows the client to specify the same callback function for all operations, and enables the callback function to determine which connection is changing states.
Window handle	A window handle to which RAS sends WM_RASDIALEVENT messages containing the current connection state and error code information. Use this method if your source code must be compatible with 16-bit Windows, because 16-bit Windows does not support either of the callback functions.
The Remote Access Connection Manager suspends the connection operation until the notification handler returns. For this reason, the handler should return as soon as possible unless an error has occurred.

The RasDial function should not be called from within a notification handler. The other remote access functions (RasGetConnectStatus, RasEnumEntries, RasEnumConnections, RasGetErrorString, and RasHangUp) can be called from within a handler.


Handling RAS Errors

When an error occurs, the Remote Access Connection Manager invokes the client's notification handler. The notification indicates the connection state when the error occurred, and a code that identifies the error. In these cases, the notification handler should call RasHangUp to end the RAS connection.

The RAS client can use the RasGetErrorString function to get a display string describing the error.


Informational Notifications

For the connection states known as running states, no action is required of the notification handler unless an error occurs. Running states occur during the parts of the connection operation that RAS handles automatically, such as connecting to the necessary devices, authenticating the user, and waiting for a callback from the remote server. The notification is simply a progress report to the client.

The client can choose to pass these informational notifications on to the user. In some running states, the client may want to display additional information. For example, a notification handler that receives a RASCS_ConnectDevice notification can call the RasGetConnectStatus function to get the name and type of the device being connected to. Another example is when the client receives a RASCS_Projected notification. This occurs when the RAS projection phase of the connection operation has been completed. The client can call the RasGetProjectionInfo function to get additional information about the projection. The client can use this information to notify the user as to which network protocols can be used by this connection.

You should avoid writing code that depends on the order or occurrence of particular informational states, because this may vary between platforms.


Completion Notifications

The Remote Access Connection Manager continues progress notifications until the connection operation has been completed. This occurs in the following situations:

•	The connection is established. The handler receives a RASCS_Connected notification. The RAS client application can exit without breaking the connection.

•	An error occurs. The handler receives a notification indicating the error and the connection state when the error occurred.

•	The connection operation is interrupted by a RasHangUp call.


Paused States

During a connection operation, there can be times when the remote server cannot proceed without additional information from the local user. Beginning with Microsoft® Windows NT™ version 3.5, the RasDial function supports paused states. A paused state allows the Remote Access Connection Manager to suspend a connection operation so the RAS client application can collect information from the user.

Paused states are useful in the following situations:

•	When the user needs to provide a callback number.

•	When the user authentication fails, the user can type in a different user name and password.

•	When the user's password has expired, the user can provide a new password.

By default, paused state support is disabled. RAS clients that want to support paused states must set the RDEOPTS_PausedStates flag in the RASDIALEXTENSIONS structure passed as a parameter to RasDial.

When a paused state occurs, the Remote Access Connection Manager invokes the client's notification handler. If paused state support is disabled, the notification message indicates an error, and the connection operation fails. If it is enabled, the Connection Manager pauses the connection operation to wait for the RAS client's response. The RAS client can resume the connection operation by a second RasDial call, or terminate it by calling the RasHangUp function.

After getting the user's input, the RAS client restarts the connection operation by calling RasDial again. This second RasDial call must specify the following information:

•	The connection handle that was returned by the original RasDial call.

•	The same notification handler as the original RasDial call.

•	The user's input in the appropriate members of the RASDIALPARAMS structure. Other members of the RASDIALPARAMS structure should have the same information as specified in the original RasDial call.

The second RasDial call cannot be made from within the notification handler.


Callback Connections

RAS supports connections in which the remote server hangs up and then calls back to the client to establish the connection.

For each user that can connect to a RAS server, the server stores a callback attribute that controls how the connection is made. The default attribute is No Callback, which means that the user can connect to the RAS server without a callback. Alternatively, the administrator of the RAS server can assign to a user either the Preset or Set By Caller callback attribute.


Preset

For a user assigned the Preset restriction, the administrator specifies a phone number that the RAS server must call back to establish a connection. The user cannot specify a different number, and the connection cannot be made without a callback.

A Preset callback operation is handled automatically by the Remote Access Connection Manager and the remote server. The RAS client application does not need to do anything other than provide feedback to the user when the notification handler is called during the various states of the callback operation.


Set by Caller

A user assigned the Set By Caller privilege can choose to connect either with or without a callback. The RasDial call uses the szCallBackNumber member of the RASDIALPARAMS structure to indicate the choice.

The szCallBackNumber member can simply specify the callback number; or, to establish the connection without a callback, szCallBackNumber can point to an empty string, "". In either of these cases, the Remote Access Connection Manager handles the connection operation automatically. As with a Preset callback operation, the RAS client does not need to perform any action other than to provide feedback to the user.

If the RasDial call enables paused states, szCallBackNumber can point to an asterisk string, "*", to indicate that the connection operation should enter a paused state to allow the user to type in the callback number. In this case, the connection operation for a Set By Caller user enters a paused state after the remote server has authenticated the user. During the paused state, the RAS client gets the callback number input from the user. The client then resumes the connection operation by making a second RasDial call in which szCallBackNumber specifies the number supplied by the user.

Note that if paused states are not enabled there is a different meaning when szCallBackNumber points to an asterisk string, "*". In this case, the asterisk indicates that the callback number is stored in the phonebook file specified by the RasDial call.


Disconnecting

When a RAS client application starts a connection operation, the RasDial call receives an HRASCONN connection handle to identify the connection. If the returned handle is not NULL, the client must eventually call the RasHangUp function to end the connection. If an error occurs during the connection operation, the client must call RasHangUp even though the connection was never established.

The application that calls RasHangUp should not exit immediately, because the Remote Access Connection Manager needs time to properly terminate the connection. Instead, the application should wait until the RasGetConnectStatus function returns ERROR_INVALID_HANDLE, indicating that the connection has been deleted.

A RAS client application might need to end a connection even though it does not have the handle returned by RasDial. For example, the application that called RasDial might have exited once the connection was successfully established. In this case, the disconnecting application can use the RasEnumConnections function to get all the current connections. For each connection, RasEnumConnections returns a RASCONN structure containing the HRASCONN connection handle and the phonebook entry name or phone number specified when the connection operation was started. This information can be used to display a list of connections from which the user can select the connection to end.


Using Remote Access Service

The following topic explains how to use Remote Access Service features in an application.

•	Linking to the remote access DLL


Linking to the Remote Access DLL

If an application links statically to the RASAPI32 DLL, the application will fail to load if Remote Access Service is not installed. A RAS application can load when RAS is not installed by using LoadLibrary to load the DLL, and GetProcAddress to obtain pointers to the RAS functions.

The Win32 RAS functions are in RASAPI32.DLL. The import library for these functions is RASAPI32.LIB. To use the RAS functions, your programs must include the following files:

File	Description
RAS.H	Contains the RAS function prototypes, constants, and structure definitions.
RASERROR.H	Contains the RAS error codes.


Remote Access Service Reference

The following functions, strucures, messages, and enumeration types are associated with remote access service.


Remote Access Service Functions

Use these functions to implement Remote Access Service functionality:

RasCreatePhonebookEntry
RasDial
RasDialFunc
RasDialFunc1
RasEditPhonebookEntry
RasEnumConnections
RasEnumEntries
RasGetConnectStatus
RasGetEntryDialParams
RasGetErrorString
RasGetProjectionInfo
RasHangUp
RasSetEntryDialParams


Remote Access Service Structures

Use these structures to implement Remote Access Service functionality:

RASAMB
RASCONN
RASCONNSTATUS
RASDIALEXTENSIONS
RASDIALPARAMS
RASENTRYNAME
RASPPPIP
RASPPPIPX
RASPPPNBF


Remote Access Service Messages

Use this message to implement Remote Access Service functionality:

WM_RASDIALEVENT


Remote Access Service Enumeration Types

Use these enumeration types to implement Remote Access Service functionality:

RASCONNSTATE
RASPROJECTION


Resources

A resource is binary data that a resource compiler or developer adds to an application's executable file. A resource can be either standard or defined. The data in a standard resource describes an icon, cursor, menu, dialog box, bitmap, enhanced metafile, font, accelerator table, message-table entry, string-table entry, or version. An application-defined resource, also called a custom resource, contains any data required by a specific application.


About Resources

This overview describes the functions that enable applications to find a resource in a module; load a resource into memory; add, delete or replace a resource in an executable file; and generate a list of the resources contained in a module. For specific information about the organization of resource data within executable files, refer to the resource formats documentation.

For information about how to create standard resources, refer to the following table.

Resource	Topic
Accelerator table	Keyboard Accelerators
Bitmap	Bitmaps
Cursor	Cursors
Dialog box	Dialog Boxes
Enhanced metafile	Metafiles
Font	Fonts and Text
Icon	Icons
Menu	Menus (Windows NT)
Message-table entry	Your message-compiler documentation
String-table entry	String Manipulation
Version information	File Installation Library
For information about how to include resource data in a Microsoft® Windows® executable file, refer to the documentation for your resource compiler.


Finding and Loading Resources

Before using a resource, an application must load it into memory. The FindResource and FindResourceEx functions find a resource in a module and return a handle to the binary resource data. FindResource locates a resource by type and name. FindResourceEx locates the resource by type, name, and language. Information about FindResource in this topic also applies to FindResourceEx.

The LoadResource function uses the resource handle returned by FindResource to load the resource into memory. After an application loads a resource by using LoadResource, Windows automatically unloads and reloads the resource as memory conditions and application execution require. Thus, an application need not explicitly unload a resource it no longer needs.

An application can use FindResource and LoadResource to find and load any type of resource, but these functions should be used only if the application must access the binary resource data for subsequent function calls. To use a resource immediately, an application should use one of the following resource-specific functions to find and load resources in one call.

Function	Action
FormatMessage	Loads and formats a message-table entry.
LoadAccelerators	Loads an accelerator table.
LoadBitmap	Loads a bitmap resource.
LoadCursor	Loads a cursor resource.
LoadIcon	Loads an icon resource.
LoadImage	Loads an icon, cursor, bitmap, or enhanced metafile  resource.
LoadMenu	Loads a menu resource.
LoadString	Loads a string-table entry.
Before terminating, an application should release the memory occupied by accelerator tables, bitmaps, cursors, icons, and menus by using one of the functions in the following table.

Resource	Release function
Accelerator table	DestroyAcceleratorTable
Bitmap	DeleteObject
Cursor	DestroyCursor
Icon	DestroyIcon
Menu	DestroyMenu
When the application terminates, Windows automatically releases the memory occupied by the other types of resources.


Adding, Deleting, and Replacing Resources

Applications must frequently add, delete, or replace resources in executable files. Two methods can be used to accomplish these tasks. The first is to edit the resource-definition file, recompile the resources, and add the recompiled resources to the application's executable file. The second method is to copy the resource data directly into the application's executable file.

For example, to localize an English-language application for use in Norway, it may be necessary to replace the English dialog box with one using Norwegian. A developer creates an appropriate dialog box by using a dialog box editor or by writing a template in the resource-definition file. The developer then recompiles the resources and adds the new resources to the application's executable file.

If an appropriate dialog box exists in binary form, however, the developer can copy the data directly to the executable file being localized by using three Windows functions. The BeginUpdateResource function creates an update handle for the executable file whose resources are to be changed. The UpdateResource function uses this handle to add, delete, or replace a resource in the executable file. The EndUpdateResource function closes the handle.

After an update handle to an executable file is created by BeginUpdateResource, an application can use UpdateResource repeatedly to make changes to the resource data. Each call to UpdateResource contributes to an internal list of additions, deletions, and replacements but does not actually write the data to the executable file. Immediately before closing the update handle, EndUpdateResource writes the accumulated changes to the executable file.

Sometimes, an application must copy resources or find resource sizes. The LoadLibrary function provides a module handle to an executable file whose resources are to be copied, and the LockResource function provides a pointer to the resource data in the specified module. The SizeofResource function returns the size, in bytes, of a specified resource.


Enumerating Resources

Three Windows functions enable an application to obtain lists of resource types, names, and languages in a specified module. The EnumResourceTypes function provides a list of resource types found in the module, the EnumResourceNames function provides the name of each resource within a given type, and the EnumResourceLanguages function provides the language of each resource of a given name and type. These functions and their associated callback functions enable applications to create a list of all resources in a module. This process is described in Creating a Resource List.


Using Resources

•	Updating resources

•	Creating a resource list


Updating Resources

The following example copies a dialog box resource from one executable file, HAND.EXE, to another, FOOT.EXE, by following these steps:

1.	The LoadLibrary function loads the executable file HAND.EXE.

2.	The FindResource and LoadResource functions locate and load the dialog box resource named If from the file.

3.	The LockResource function returns a pointer to the dialog box resource data.

4.	The BeginUpdateResource function opens an update handle FOOT.EXE.

5.	The UpdateResource function copies the dialog box resource from HAND.EXE to FOOT.EXE.

6.	The EndUpdateResource function completes the update.

The following code implements these steps.

HRSRC hResLoad;     // handle to loaded resource

HANDLE hExe;        // handle to existing .EXE file

HRSRC hRes;         // handle/ptr. to res. info. in hExe

HANDLE hUpdateRes;  // update resource handle

char *lpResLock;    // pointer to resource data

BOOL result;

// Load the .EXE file that contains the dialog box you want to copy.

hExe = LoadLibrary("hand.exe");

if (hExe == NULL) {

    ErrorHandler("Could not load exe.");

}

// Locate the dialog box resource in the .EXE file.

hRes = FindResource(hExe, "AboutBox", RT_DIALOG);

if (hRes == NULL) {

    ErrorHandler("Could not locate dialog box.");

}

// Load the dialog box into global memory.

hResLoad = LoadResource(hExe, hRes);

if (hResLoad == NULL) {

    ErrorHandler("Could not load dialog box.");

}

// Lock the dialog box into global memory.

lpResLock = LockResource(hRes);

if (lpResLock == NULL) {

    ErrorHandler("Could not lock dialog box.");

}

// Open the file to which you want to add the dialog box resource.

hUpdateRes = BeginUpdateResource("foot.exe", FALSE);

if (hUpdateRes == NULL) {

    ErrorHandler("Could not open file for writing.");

}

// Add the dialog box resource to the update list.

result = UpdateResource(hUpdateRes,       // update resource handle

             RT_DIALOG,                   // change dialog box resource

             "AboutBox",                  // dialog box name

             MAKELANGID(LANG_NEUTRAL,

                 SUBLANG_NEUTRAL),        // neutral language ID

             lpResLock,                   // ptr to resource info

             SizeofResource(hExe, hRes)); // size of resource info.

if (result == FALSE) {

    ErrorHandler("Could not add resource.");

}

// Write changes to FOOT.EXE and then close it.

if (!EndUpdateResource(hUpdateRes, FALSE)) {

    ErrorHandler("Could not write changes to file.");

}

// Clean up.

if (!FreeLibrary(hExe)) {

    ErrorHandler("Could not free executable.");

}


Creating a Resource List

The following example creates a list of every resource in the HAND.EXE file. The list is written to the RESINFO.TXT file.

The code demonstrates how to load the executable file, create a file in which to write resource information, and call the EnumResourceTypes function to send each resource type found in the module to the application-defined callback function EnumTypesFunc. See EnumResTypeProc for information on callback functions of this type. This callback function uses the EnumResourceNames function to pass the name of every resource within the specified type to another application-defined callback function, EnumNamesFunc. See EnumResNameProc for information on callback functions of this type. EnumNamesFunc uses the EnumResourceLanguages function to pass the language of every resource of the specified type and name to a third callback function, EnumLangsFunc. See EnumResLangProc for information on callback functions of this type. EnumLangsFunc writes information about the resource of the specified type, name, and language to the RESINFO.TXT file.

char szBuffer[80]; // print buffer for EnumResourceTypes

DWORD cbWritten;   // number of bytes written to res. info. file

int cbString;      // length of string in sprintf

// Declare callback functions.

BOOL EnumTypesFunc(

    HANDLE hModule,

    LPTSTR lpType,

    LONG lParam);

BOOL EnumNamesFunc(

    HANDLE hModule,

    LPCTSTR lpType,

    LPTSTR lpName,

    LONG lParam);

BOOL EnumLangsFunc(

    HANDLE hModule,

    LPCTSTR lpType,

    LPCTSTR lpName,

    WORD wLang,

    LONG lParam);

// Load the .EXE whose resources you want to list.

hExe = LoadLibrary("hand.exe");

if (hExe == NULL) {

    ErrorHandler("Could not load .EXE.");

}

// Create a file to contain the resource info.

hFile = CreateFile("resinfo.txt",      // name of file

    GENERIC_READ | GENERIC_WRITE,      // access mode

    0,                                 // share mode

    (LPSECURITY_ATTRIBUTES) NULL,      // no security

    CREATE_ALWAYS,                     // create flags

    FILE_ATTRIBUTE_NORMAL,             // file attributes

    (HANDLE) NULL);                    // no template

if (hFile == INVALID_HANDLE_VALUE) {

    ErrorHandler("Could not open file.");

}

// Find all of the loaded file's resources.

cbString = sprintf(szBuffer,

    "The file contains the following resources:\n\n");

WriteFile(hFile,           // file to hold resource info.

    szBuffer,              // what to write to the file

    (DWORD) cbString,      // number of bytes in szBuffer

    &cbWritten,            // number of bytes written

    NULL);                 // no overlapped I/O

EnumResourceTypes(hExe,              // module handle

    (ENUMRESTYPEPROC)EnumTypesFunc,  // callback function

    0);                              // extra parameter

// Unload the executable file whose resources were

// enumerated and close the file created to contain

// the resource information.

FreeLibrary(hExe);

CloseHandle(hFile);

//    FUNCTION: EnumTypesFunc(HANDLE, LPSTR, LONG)

//

//    PURPOSE:  Resource type callback

BOOL EnumTypesFunc(

    HANDLE hModule,   // module handle

    LPTSTR lpType,    // address of resource type

    LONG lParam)      // extra parameter, could be

                      // used for error checking

{

    int cbString;

    // Write the resource type to a resource information file.

    // The type may be a string or an unsigned decimal

    // integer, so test before printing.

    if ((ULONG)lpType & 0xFFFF0000) {

        cbString = sprintf(szBuffer, "Type: %s\n", lpType);

    }

    else {

        cbString = sprintf(szBuffer, "Type: %u\n", (USHORT)lpType);

    }

    WriteFile(hFile, szBuffer, (DWORD) cbString,

        &cbWritten, NULL);

    // Find the names of all resources of type lpType.

    EnumResourceNames(hModule,

        lpType,

        (ENUMRESNAMEPROC)EnumNamesFunc,

        0);

    return TRUE;

}

//    FUNCTION: EnumNamesFunc(HANDLE, LPSTR, LPSTR, LONG)

//

//    PURPOSE:  Resource name callback

BOOL EnumNamesFunc(

    HANDLE hModule,   // module handle

    LPCTSTR lpType,   // address of resource type

    LPTSTR lpName,    // address of resource name

    LONG lParam)      // extra parameter, could be

                      // used for error checking

{

    int cbString;

     // Write the resource name to a resource information file.

     // The name may be a string or an unsigned decimal

     // integer, so test before printing.

    if ((ULONG)lpName & 0xFFFF0000) {

        cbString = sprintf(szBuffer, "\tName: %s\n", lpName);

    }

    else {

        cbString = sprintf(szBuffer, "\tName: %u\n",

            (USHORT)lpName);

    }

    WriteFile(hFile, szBuffer, (DWORD) cbString,

        &cbWritten, NULL);

     // Find the languages of all resources of type

     // lpType and name lpName.

    EnumResourceLanguages(hModule,

        lpType,

        lpName,

        (ENUMRESLANGPROC)EnumLangsFunc,

        0);

    return TRUE;

}

//    FUNCTION: EnumLangsFunc(HANDLE, LPSTR, LPSTR, WORD, LONG)

//

//    PURPOSE:  Resource language callback

BOOL EnumLangsFunc(

    HANDLE hModule,  // module handle

    LPCTSTR lpType,  // address of resource type

    LPCTSTR lpName,  // address of resource name

    WORD wLang,      // resource language

    LONG lParam)     // extra parameter, could be

                        used for error checking

{

    HANDLE hResInfo;

    char szBuffer[80];

    int cbString = 0;

    hResInfo = FindResourceEx(hModule, lpType, lpName, wLang);

    // Write the resource language to the resource information file.

    cbString = sprintf(szBuffer, "\t\tLanguage: %u\n",

        (USHORT)wLang);

    WriteFile(hFile, szBuffer, (DWORD) cbString,

        &cbWritten, NULL);

    // Write the resource handle and size to buffer.

    cbString = sprintf(szBuffer,

        "\t\thResInfo == %lx,  Size == %lu\n\n",

        hResInfo,

        SizeofResource(hModule, hResInfo));

    WriteFile(hFile, szBuffer, (DWORD) cbString,

        &cbWritten, NULL);

    return TRUE;

}


Resource Functions

Following are the functions used with resources.

BeginUpdateResource
CopyImage
EndUpdateResource
EnumResLangProc
EnumResNameProc
EnumResourceLanguages
EnumResourceNames
EnumResourceTypes
EnumResTypeProc
FindResource
FindResourceEx
LoadImage
LoadResource
LockResource
SizeofResource
UpdateResource

Obsolete or Deleted Functions

FreeResource
SetResourceHandler
UnlockResource


Security

The security provisions of Microsoft® Windows NT™ are available to Windows-based applications automatically. Every application running on the system is subject to the security imposed by the particular configuration of the local implementation of Windows NT.


About Security

The security functions in the Microsoft Win32® application programming interface (API) allow an application to selectively grant and deny access to an object. An application can specify many different kinds of access for particular users and groups of users. The operating system grants or denies access to an object based on a comparison of the security provisions stored with an object with the access rights specified in a token associated with the process or thread requesting the access. These security functions allow an application to query and manipulate the security features of both an object and a process or thread.

The impact of Windows security on most Windows functions is minimal, and a Windows-based application not requiring security functionality usually does not need to incorporate any special code. However, a developer can use the security features of Windows NT to provide a number of services in a Windows-based application. Generally, any application that manipulates a system-wide resource such as the system time, must use the security system to gain access to that resource. A security-aware application might allow the user to query the security attributes of a file, provide specialized feedback when access to a secure file is denied, or customize the security attributes of a file or group of files so that only a subset of other users on a network has access to the information.

Windows NT is designed to support C2-level security as defined by the US Department of Defense. Some of the most important requirements of C2-level security are shown in the following list.

•	It must be possible to control access to a resource. This access control must include or exclude individual users or named groups of users.

•	Memory must be protected so its contents cannot be read after it is freed by a process.

•	Users must identify themselves in a unique manner when they log on. All auditable actions must identify the user performing the action.

•	System administrators must be able to audit security-related events. Access to this audit data must be limited to authorized administrators.

•	The system must protect itself from external interference or tampering, such as modification of the running system or of system files stored on disk.


Security Model

All named objects in Windows NT, and some unnamed objects, can be secured. The security attributes of each securable object in Windows are described by a security descriptor, that contains information about the owner of the object and by an access-control list (ACL), identifying the users and groups allowed or denied access to the object. An ACL contains an entry for each user, global group, or local group (alias) being allowed or denied access to the object. Each of these entries is an access-control entry (ACE).

At logon, a user is assigned an access token containing identifiers that represent the user and any groups to which the user belongs. Every process run on behalf of this user will have a copy of this particular access token. When a process attempts to use an object, the system compares the security attributes listed in the access token with the ACEs in the object's ACL. The system compares the access token with each ACE until access is either granted or denied or until there are no more ACEs to check. Conceivably, several ACEs could apply to a token. And, if this occurs, the access rightsaccess rights granted by each ACE accumulate. For example, if one ACE grants read access to a group in an access token and another ACE grants write access to the user, who is also a member of the group, the user will have both read and write access to the object when the access check is complete.

The following illustration shows the relationship between these blocks of security information:

Typically, the application protecting an object is a server in that it defines the users and groups with access to the object. The application interacts with clients when they attempt to gain access to the object. Users and groups are identified by security identifiers (SIDs). An SID is a structure of variable length that uniquely identifies a user or group. SIDs are stored in a security database that an application can query by calling Win32 functions. With one exception, an SID is used to identify a user or group is never reassigned to another user or group. For a given account, the only SID that will not be the same from logon to logon is the logon-identifier SID. In the model represented by the preceding illustration, SIDs would be used to identify the following:

•	The owner and group in the security descriptor

•	The recipient of the access being granted by each ACE

•	The user and groups in the access token

Security descriptors, SIDs, and ACLs are treated by applications as opaque structures and are intended to be manipulated only by using Win32 functions. This helps ensure that these structures remain syntactically accurate and prevents future enhancements to the security system from breaking existing code.

Pointers to doubleword values or structures must be aligned on doubleword boundaries. However, the exception is strings, for which alignment is not critical. All Win32 memory-allocation functions return handles of doubleword-aligned memory objects.


Access Tokens

When a user logs on, the system verifies the user's password by comparing it with information stored in a security database. If the password is authenticated, the system produces an access token and attaches it to the user's process. This access token identifies the user in all subsequent interactions with securable objects and contains the following information about a process:

•	The user's SID

•	Group SIDs

•	Privileges

•	An owner SID

•	The SID for the primary group

•	The default discretionary access-control list (ACL)

•	The source of the access token

•	Whether the token is a primary or impersonation token

•	Current impersonation levels

•	Other statistics

Every process must have an access token, but even a thread can have one assigned to it. When a thread has an access token, it supersedes the token of the process that owns the thread. This allows individual threads of a server process to impersonate clients by associating a client's access token with the thread. The only exception to this is any action requiring the SE_TCB_NAME privilege. This privilege is always checked against the process token, even if the current thread has an impersonation token.

For more information about privileges, see Privileges. For more information about security identifiers (SIDs), see Security Identifiers (SIDs). For more information about discretionary ACLs, see Access-control Lists (ACLs). For more information about the components of an access token, see the following token structures and enumerated types.

Structure or type	Specifies
TOKEN_CONTROL	Information useful in identifying an access token.
TOKEN_DEFAULT_DACL	The default discretionary ACL for an access token.
TOKEN_GROUPS	Specifies the SIDs of the access token's groups and whether any privileges are enabled.
TOKEN_INFORMATION_CLASS	Information being set in or retrieved from an access token.
TOKEN_OWNER	The SID of an access token's owner.
TOKEN_PRIMARY_GROUP	The SID of the access token's primary group.
TOKEN_PRIVILEGES	The privileges associated with an access token and whether the privileges are enabled.
TOKEN_SOURCE	The source of an access token.
TOKEN_STATISTICS	Statistics associated with an access token.
TOKEN_TYPE	Whether an access token is being used as an impersonation token.
TOKEN_USER	The SID of an access token's user.
Following are the functions an application can use to manipulate access tokens.

Function	Description
AdjustTokenGroups	Changes the group information in an access token.
AdjustTokenPrivileges	Changes the privileges in an access token.
GetTokenInformation	Retrieves information about a token.
OpenProcessToken	Retrieves the handle of the access token for a process.
OpenThreadToken	Retrieves the handle of the access token for a thread.
SetTokenInformation	Changes a token's owner, primary group, or default discretionary ACL.


Security Descriptors

A security descriptor contains the security information associated with an object. This information can include an owner, a primary group, a discretionary access-control list, and a system access-control list. This information is stored in the form of security identifiers (SIDs) and access-control lists (ACLs). For more information about access-control lists, see Access-control Lists (ACLs).

There are five groups of Win32 functions that manipulate security descriptors, corresponding to five different kinds of objects:

•	Files

•	User Objects (also called window-management objects)

•	Kernel objects

•	Registry objects

•	Private objects

To manipulate security descriptors for files and directories, an application can use the GetFileSecurity and SetFileSecurity functions. These functions identify files and directories by using character strings, instead of using the handles required by other security functions.

Kernel objects and user objects are manipulated by two pairs of functions: GetKernelObjectSecurity and SetKernelObjectSecurity, and GetUserObjectSecurity and SetUserObjectSecurity. Kernel and user objects are separated in this way because it is possible for a file handle and a window handle to have the same value. An application can use these functions to ensure that the correct object referenced.

An application can use the RegGetKeySecurity and RegSetKeySecurity functions to retrieve and set security descriptors for keys in the registry.

The functions that manipulate private objects allow an application, usually a server, to associate a security descriptor with its own object type. The functions provide the ability to retrieve default information from an access token, support inheritance, and manipulate specific parts of the security descriptor. These functions are CreatePrivateObjectSecurity, GetPrivateObjectSecurity, SetPrivateObjectSecurity, and DestroyPrivateObjectSecurity.

The Win32 functions in the following table enable an application to query a security descriptor or set specific information in it.

Function	Description
GetSecurityDescriptorControl	Retrieves revision and control information.
GetSecurityDescriptorDacl	Retrieves the discretionary ACL.
GetSecurityDescriptorGroup	Retrieves primary group information.
GetSecurityDescriptorLength	Returns the length of a security descriptor.
GetSecurityDescriptorOwner	Retrieves the owner of a security descriptor.
GetSecurityDescriptorSacl	Retrieves the system ACL.
SetSecurityDescriptorDacl	Sets discretionary ACL information.
SetSecurityDescriptorGroup	Sets primary group information.
SetSecurityDescriptorOwner	Sets the owner of the security descriptor.
SetSecurityDescriptorSacl	Sets system ACL information.
To check the revision level and structural integrity of a security descriptor, an application can call the IsValidSecurityDescriptor function.

A security descriptor can be in either an absolute or self-relative format. In absolute format, a security descriptor contains pointers to its information, not the information itself. This format is useful when default settings for the owner, group, and discretionary ACL are available, because an application can simply call the InitializeSecurityDescriptor function to initialize a SECURITY_DESCRIPTOR structure and then point to preexisting components, such as SIDs and ACLs.

A security descriptor in self-relative format contains information in a contiguous block of memory. In this format, a SECURITY_DESCRIPTOR structure always starts the information, but the other components of the security descriptor can follow the structure in any order. Instead of using memory addresses, the security descriptor's components are identified by offsets from the beginning of the descriptor. This format is useful when a security descriptor must be stored on disk, transmitted by means of a communications protocol, or copied in memory.

All security descriptors provided by the operating system as the result of calls to Win32 API functions are in self-relative format. Security descriptors passed back to the operating system can be in either form, depending on the situation.

A server that copies secured objects to various media can use the MakeSelfRelativeSD function to create a self-relative security descriptor from an absolute security descriptor. The MakeAbsoluteSD function can create an absolute security descriptor from a self-relative security descriptor.


Access-control Lists (ACLs)

Part of the security descriptor for each securable object is a list specifying users and groups, and the access to the object each is granted or denied. This list is an access-control list (ACL). An ACL consists of two parts. The first is a header in the form of an ACL structure. This structure contains information pertaining to the entire ACL, such as its revision level and size. The second part is an ordered list of access-control entries (ACEs). Each ACE identifies a user, group, or local group, and the access each of them is allowed.

There are two types of ACLs: discretionary and system.

A discretionary ACL is controlled by the owner of an object and specifies the access particular users or groups can have to an object. For example, the owner of a file can use a discretionary ACL to control who can and cannot have access to the file.

When an object's discretionary ACL contains no access-control entries, no access rights have been explicitly granted. Therefore, access to the object is implicitly denied. However, when an object has no discretionary ACL, no protection is assigned to the object and any access request is granted. For information about setting no ACL for an object, see Allowing Access.

An object may also have system-level security information associated with it, in the form of a system ACL. System ACLs are controlled by system administrators. A system ACL can enable the system administrator to audit any attempts to gain access to an object. In future releases, a system ACL will also be able to raise an alarm when an unauthorized user attempts to gain access to an object.

An application can use Win32 functions to retrieve, initialize, query, and modify ACLs.

Function	Description
GetAclInformation	Retrieves revision or size information about an ACL.
GetSecurityDescriptorDacl	Retrieves a discretionary ACL from a specified security descriptor.
GetSecurityDescriptorSacl	Retrieves a system ACL from a specified security descriptor.
InitializeAcl	Initializes an ACL by creating an empty ACL structure.
IsValidAcl	Determines whether an ACL's revision level and structure are valid.
SetAclInformation	Changes the revision information in an ACL.
SetSecurityDescriptorDacl	Puts a discretionary ACL into a specified security descriptor, superseding any preexisting discretionary ACL.
SetSecurityDescriptorSacl	Puts a system access-control list into a specified security descriptor, superseding any preexisting system ACL.
To change a security descriptor's ACL, an application generally initializes a new ACL, adds ACEs to it, then uses either the SetSecurityDescriptorDacl or SetSecurityDescriptorSacl function to add the new ACL to the security descriptor. GetSecurityDescriptorDacl and GetSecurityDescriptorSacl retrieve a pointer to a preexisting ACL in a security descriptor so an application can copy information from the previous ACL as it creates a new one.


Access-control Entries (ACEs)

Each of the entries in an access-control list (ACL) is an access-control entry (ACE). Each ACE consists of three parts:

•	A header in the form of an ACE_HEADER structure structure

•	An access mask for the specified ACE type

•	A security identifier (SID)

The ACE_HEADER structure gives information such as the type of the ACE and its size. The access mask is a 32-bit value that specifies the rights being granted, denied, or monitored. The security identifier is in the form of an SID structure and it specifies the user or group to which the ACE applies.

Discretionary ACLs have two types of ACE defined in the AceType member of the ACE_HEADER structure. They are shown in the following table.

Type	Description
ACCESS_ALLOWED_ACE_TYPE	This ACE grants the specified rights to the user or group identified by the security identifier. It is defined by an ACCESS_ALLOWED_ACE structure.
ACCESS_DENIED_ACE_TYPE	This ACE denies the specified rights to the user or group identified by the security identifier. It is defined by an ACCESS_DENIED_ACE structure.
Only one type of ACE, SYSTEM-AUDIT-ACE-TYPE, is currently supported for system ACLs. It specifies what types of access cause system-level audits. This ACE is defined by a SYSTEM_AUDIT_ACE structure.

The SYSTEM_ALARM_ACE_TYPE is not supported in the current version of Windows NT.

Security auditing is used to keep a log of security-significant events, such as which users access a secured file. The SYSTEM_AUDIT_ACE_TYPE ACE is used to generate security audit messages and causes them to be entered into a system audit log for later processing. An administrator can view this log by using Event Viewer (EVENTVWR.EXE) and can manipulate the log by using the event-logging functions.

The order of ACEs in an ACL is important. An access token is checked against the ACEs in an ACL until it either accumulates the access rights it needs, it is explicitly denied access in an access-denied ACE, or it reaches the end of the ACL and is implicitly denied access. If a user is a member of several groups represented by ACEs in the ACL, the rights granted to each group apply to the user. For example, a user may request read and write access to an object protected by an ACE that grants one group read access only. Another ACE may provide protection that grants write access. If the user belongs to both groups, the request will succeed. An ACL typically denies access to specific users or groups of users and allows access to more general categories of users. Although the ACEs in an ACL can be in any order, the security menu items in File Manager and Registry Editor (REGEDT32.EXE) only work with ACLs in which access-denied ACEs precede access-allowed ACEs.

To change a security descriptor's ACL, an application usually initializes a new ACL, adds ACEs to it, and then adds the ACL to the security descriptor. The AddAccessAllowedAce and AddAccessDeniedAce functions add an ACE at the end of a discretionary ACL. The AddAuditAccessAce function adds an ACE at the end of a system ACL. The AddAce function allows an application to specify the position of a new ACE in an ACL, and the DeleteAce function allows an application to remove an ACE from a specified position in one. The GetAce and FindFirstFreeAce functions are especially useful when copying information from a preexisting ACL to a new one.


Access Masks and Access Rights

An access right defines a particular set of abilities that can be granted or denied to a process when it attempts to use an object. For example, if an application attempts to create a subkey in the registry but does not have the KEY_CREATE_SUB_KEY access right, the system does not carry out the operation. An application usually requests a set of access rights when it opens an object, and in the case of registry keys, it makes that request when it calls the RegOpenKeyEx function.

An access mask is the component of an access-control entry (ACE) that contains the specific rights, standard rights, and generic rights defining the access a user or group has to an object. Access masks are also used to request access rights when an object is opened. For example, an application that needs to set values, create subkeys, and query values in the registry can open a key using an access mask that combines the KEY_WRITE and KEY_QUERY_VALUE access rights.

An access mask is a single 32-bit value. The first 16 bits are the specific rights and apply only to the object type associated with the access mask. Bits 16 through 23 are the standard rights applying to all objects. Bits 28 through 31 are the generic rights mapped to specific and standard rights when access to an object is requested.

Generic access rights are broad types of access whose exact implementation is determined by the application defining an object. These rights are used when protecting an object. For example, an application that defines a voice-annotation object might define specific access rights by using VOICE_PLAY and VOICE_EDIT for playing and editing the object. It might set up a GENERIC_MAPPING structure in which GENERIC_EXECUTE maps to VOICE_PLAY and GENERIC_WRITE maps to both VOICE_PLAY and VOICE_EDIT.

The following are the generic rights that have been defined.

Constant	Meaning
GENERIC_ALL	Read, write, and execute access
GENERIC_EXECUTE	Execute access
GENERIC_READ	Read access
GENERIC_WRITE	Write access
If an application receives GENERIC_WRITE access to a file, for example, it has specific rights allowing it to write and append data to the file, write file attributes, and write extended attributes. In addition, the application has the STANDARD_RIGHTS_WRITE and SYNCHRONIZE standard access rights.

The following constants are masks for the standard access rights.

Constant	Meaning
DELETE	Delete access.
READ_CONTROL	Read access to the security descriptor not including the system ACL.
STANDARD_RIGHTS_ALL	Combines DELETE, READ_CONTROL, WRITE_DAC, WRITE_OWNER, and SYNCHRONIZE access.
STANDARD_RIGHTS_EXECUTE	Currently defined to equal READ_CONTROL.
STANDARD_RIGHTS_READ	Currently defined to equal READ_CONTROL.
STANDARD_RIGHTS_REQUIRED	Combines DELETE, READ_CONTROL, WRITE_DAC, and WRITE_OWNER access.
STANDARD_RIGHTS_WRITE	Currently defined to equal READ_CONTROL.
SYNCHRONIZE	Synchronize access. Allows a thread to wait for the object. This access type is not supported by all object types.
WRITE_DAC	Write access to the discretionary ACL.
WRITE_OWNER	Write access to the owner.
The SPECIFIC_RIGHTS_ALL constant denotes all of the specific rights, even those not be defined for an object.

The system validates each requested access against the process's access token, so requests for broad access can require a great deal of validation time. Therefore, it is generally better for applications to avoid requesting the broadest possible access to an object except when such access is actually required. Certain rights are commonly used in an ACL to deny access to an object, but they are rarely used in requests to open an object. In particular, requesting any of the access rights in the following list has a negative impact on system performance:

EVENT_ALL_ACCESS	SECTION_ALL_ACCESS
FILE_MAP_ALL_ACCESS	SEMAPHORE_ALL_ACCESS
GENERIC_ALL	SERVICE_ALL_ACCESS
KEY_ALL_ACCESS	SPECIFIC_RIGHTS_ALL
MUTEX_ALL_ACCESS	STANDARD_RIGHTS_ALL
PROCESS_ALL_ACCESS	THREAD_ALL_ACCESS
SC_MANAGER_ALL_ACCESS	TOKEN_ALL_ACCESS
The MAXIMUM_ALLOWED constant specifies that an object is to be opened by using all the access rights that are valid for the given user. An additional access type, ACCESS_SYSTEM_SECURITY, is needed to manipulate an object's system ACL. Neither MAXIMUM_ALLOWED nor ACCESS_SYSTEM_SECURITY can be used in an DACL. However, you can use ACCESS_SYSTEM_SECURITY in a SACL to audit use of that bit in an access attempt.

The MapGenericMask function maps a series of generic rights specified in a GENERIC_MAPPING structure to specific and standard rights in an access mask. An application can use the GENERIC_MAPPING structure to specify the access rights for an object when it is created. When a client process requests access to the object, the server can use MapGenericMask to translate the client's requested access into the standard and specific rights for that object.

To discover whether a client process has the proper access rights to an object, a server can call the AccessCheck or AccessCheckAndAuditAlarm function. The AreAllAccessesGranted and AreAnyAccessesGranted functions compare a requested access mask with a granted access mask.


Security Identifiers (SIDs)

A security identifier (SID) is a unique value of variable length used to identify a user or group. The SID assigned to a user when he or she logs on becomes part of the access token that accompanies any process begun by that user. Except for the logon SID, an SID is always unique. When it has been used to identify a user or group, it cannot be used again, at any time, to identify another user or group.

SIDs identify several separate elements. These include the owner and group in security descriptors, the recipient of the access being granted by access-control entries (ACEs), and the user, as well as groups of which the user is a member in access tokens.

An SID also contains the following information.

•	A 48-bit identifier authority value

•	A revision level

•	A variable number of subauthority values (relative identifiers)

The identifier authority value actually contains two values and is the most important piece of information in an SID. It contains a value identifying the agency that issued the SID, usually representing a Microsoft® Server™ domain, and a 32-bit relative identifier (RID) value, to uniquely identify the user or group in that agency. Joining these values ensures that no two SIDs will be the same, even if two different SID-issuing authorities issue the same RID. Each SID-issuing authority issues a given RID only once.

A standardized shorthand notation for SIDs makes it simpler to visualize their components:

S-R-I-S-S...

In the notation shown above, S identifies the series of digits as an SID, R is the revision level, I is the identifier-authority value, and S is the subauthority value. An SID could be written in this notation as follows:

S-1−4138−86

In this example, the SID has a revision level of 1, an identifier-authority value of 4138, and one subauthority value of 86.

An application is never required to manipulate an SID directly. The following Win32 functions provide all the functionality required to work with SIDs.

Function	Description
AllocateAndInitializeSid	Allocates and initializes an SID with the specified number of subauthorities.
CopySid	Copies a source SID to a buffer.
EqualPrefixSid	Tests two SID prefix values for equality. An SID prefix is the entire SID except for the last subauthority value.
EqualSid	Tests two SIDs for equality. They must match exactly to be considered equal.
FreeSid	Frees an SID previously allocated by using the AllocateAndInitializeSid function.
GetLengthSid	Retrieves the length of an SID.
GetSidIdentifierAuthority	Retrieves a pointer to an SID's identifier authority.
GetSidLengthRequired	Retrieves the size of the buffer required to store an SID with a specified number of subauthorities.
GetSidSubAuthority	Retrieves a pointer to a specified subauthority in an SID.
GetSidSubAuthorityCount	Retrieves the number of subauthorities in an SID.
InitializeSid	Initializes an SID structure.
IsValidSid	Tests the validity of an SID by verifying that the revision number is within a known range and that the number of subauthorities is less than the maximum.
LookupAccountName	Retrieves the SID corresponding to a specified account name. Use the GetUserName function to retrieve the user name for the current thread.
LookupAccountSid	Retrieves the account name corresponding to a specified SID.
Some identifier authorities are predefined, as shown in the following table.

Identifier authority	SID Value
SECURITY_NULL_SID_AUTHORITY	0
SECURITY_WORLD_SID_AUTHORITY	1
SECURITY_LOCAL_SID_AUTHORITY	2
SECURITY_CREATOR_SID_AUTHORITY	3
SECURITY_NT_AUTHORITY	5
The following RID values are also defined.

Relative identifier authority	Value	Superior authority
SECURITY_NULL_RID	0	S-1−0
SECURITY_WORLD_RID	0	S-1−1
SECURITY_LOCAL_RID	0	S-1−2
SECURITY_CREATOR_OWNER_RID	0	S-1−3
SECURITY_CREATOR_GROUP_RID	1	S-1−3
An application can combine an identifier authority and one of these RID values to create an SID that is meaningful on all installations. For example, S-1−1−0 (SECURITY_WORLD_SID_AUTHORITY and SECURITY_WORLD_RID) always identifies the special group representing all users. These security identifiers are universal well-known SIDs. A universal well-known SID is meaningful on all secure systems using this security model, including systems not running Windows NT. The AllocateAndInitializeSid function provides a simple method of combining an identifier authority and an RID.

The following are some universal well-known SIDs.

Universal well-known SID	Value	Identifies
Null SID	(S-1−0−0)	A group with no members. This is often used when an SID value is not known.
World	(S-1−1−0)	A group that includes all users.
Local	(S-1−2−0)	Users who log on to terminals locally (physically) connected to the system.
Creator Owner ID	(S-1−3−0)	A security identifier to be replaced by the security identifier of the user who created a new object. This SID is used in inheritable ACLs.
Creator Group ID	(S-1−3−1)	Identifies a security identifier to be replaced by the primary-group SID of the user who created a new object. Use this SID in inheritable ACLs.
Another predefined identifier authority is SECURITY_NT_AUTHORITY (S-1−5). This identifier authority produces SIDs that are not universal but are meaningful only on Windows NT installations. An application can use the following RID values with SECURITY_NT_AUTHORITY to create well-known SIDs.

Constant	Identifies
SECURITY_DIALUP_RID (S-1−5−1)
	Users who log on to terminals using a dialup modem. This is a group identifier.
SECURITY_NETWORK_RID (S-1−5−2)
	Users who log on across a network. This is a group identifier.
SECURITY_BATCH_RID (S-1−5−3)
	Users who log on using a batch queue facility. This is a group identifier.
SECURITY_INTERACTIVE_RID (S-1−5−4)
	Users who log on for interactive operation. This is a group identifier.
SECURITY_LOGON_IDS_RID (S-1−5−5-X-Y)
	A logon session. This is used to ensure that only processes in a given logon session can gain access to the window-station objects for that session. The X and Y values for these SIDs are different for each logon session. The value SECURITY_LOGON_IDS_RID_COUNT is the number of RIDs in this identifier (5-X-Y).
SECURITY_SERVICE_RID (S-1−5−6)
	An account authorized to perform security services.
SECURITY_LOCAL_SYSTEM_RID (S-1−5−0x12)
	The user account used by the operating system.
SECURITY_BUILTIN_DOMAIN_RID (S-1−5−0x20)
	The built-in system domain.
The following RIDs are relative to each domain.

RID	Identifies
DOMAIN_USER_RID_ADMIN	The administrative user account in a domain.
DOMAIN_USER_RID_GUEST	The guest-user account in a domain. This account can be logged onto automatically by users who do not have an account.
DOMAIN_GROUP_RID_ADMINS	The domain administrator's group. This account exists only on systems running Microsoft® LAN Manager for Windows NT™, not Windows NT systems.
DOMAIN_GROUP_RID_USERS	A group containing all user accounts in a domain. All users are automatically added to this group.
An alias is a local group and is similar to a global group, but it can contain members from other domains. Its members can be users or other groups. Some domain-relative RIDs, such as the following, can be used to form well-known SIDs used as local groups.

RID	Identifies
DOMAIN_ALIAS_RID_ADMINS	A local group used for administration of the domain.
DOMAIN_ALIAS_RID_USERS	A local group representing all users in the domain.
DOMAIN_ALIAS_RID_GUESTS	A local group representing guests of the domain.
DOMAIN_ALIAS_RID_POWER_USERS	A local group used to represent a user or set of users that expect to treat a system as if it were their personal computer rather than a multiuser workstation.
DOMAIN_ALIAS_RID_ACCOUNT_OPS	A local group existing only on systems running Microsoft LAN Manager for Windows NT. This local group permits control over non-administrator accounts.
DOMAIN_ALIAS_RID_SYSTEM_OPS	A local group existing only on systems running Microsoft LAN Manager for Windows NT. This local group performs system administrative functions, not including security functions. It establishes network shares, controls printers, unlocks workstations, and performs other operations.
DOMAIN_ALIAS_RID_PRINT_OPS	A local group existing only on systems running Microsoft LAN Manager for Windows NT. This local group controls printers and print queues.
DOMAIN_ALIAS_RID_BACKUP_OPS	A local group used for controlling assignment of file backup-and-restore privileges.
DOMAIN_ALIAS_RID_REPLICATOR	A local group responsible for copying security databases from the primary domain controller to the backup domain controllers.


Privileges

A privilege is used to control access to an object or service more strictly than is normal with discretionary access control. A system manager uses privileges to control which users are able to manipulate system resources. An application uses privileges when it changes a system resource, such as when it changes the system time or shuts down the system.

A privilege is a locally unique identifier (LUID) identified by a character string. This 64-bit value is guaranteed to be unique on the operating system that generated it until the system is restarted. For example, SE_SYSTEMTIME_NAME is a string identifying an LUID. A privilege has three representations, as shown below.

•	A string name, meaningful across systems, called a global program name (for example, SE_SYSTEMTIME_NAME).

•	A readable name that can be displayed to the user when necessary. For example, "Change the system time."

•	A local representation that differs from computer to computer.

Privileges provide access to services rarely needed by most users. An account usually has privileges that are disabled, and they must be enabled to be used. For example, to set the time on the local computer, an application has to set the SE_PRIVILEGE_ENABLED attribute for the SE_SYSTEMTIME_NAME privilege. For security reasons, disable an enabled privilege when it is no longer needed.

The following privileges are defined by Windows NT.

Privilege	Description
SE_ASSIGNPRIMARYTOKEN_NAME	Required to assign the primary token of a process.
SE_AUDIT_NAME	Required to generate audit-log entries. Give this privilege to secure servers.
SE_BACKUP_NAME	Required to perform backup operations.
SE_CHANGE_NOTIFY_NAME	Required to receive notifications of changes to files or directories. This privilege also causes the system to skip all traversal access checks. It is enabled by default for all users.
SE_CREATE_PAGEFILE_NAME	Required to create a paging file.
SE_CREATE_PERMANENT_NAME	Required to create a permanent object.
SE_CREATE_TOKEN_NAME	Required to create a primary token.
SE_DEBUG_NAME	Required to debug a process.
SE_INC_BASE_PRIORITY_NAME	Required to increase the base priority of a process.
SE_INCREASE_QUOTA_NAME	Required to increase the quota assigned to a process.
SE_LOAD_DRIVER_NAME	Required to load or unload a device driver.
SE_LOCK_MEMORY_NAME	Required to lock physical pages in memory.
SE_PROF_SINGLE_PROCESS_NAME	Required to gather profiling information for a single process.
SE_REMOTE_SHUTDOWN_NAME	Required to shut down a system using a network request.
SE_RESTORE_NAME	Required to perform restore operations.
SE_SECURITY_NAME	Required to perform a number of security-related functions, such as controlling and viewing audit messages. This privilege identifies its holder as a security operator.
SE_SHUTDOWN_NAME	Required to shut down a local system.
SE_SYSTEM_ENVIRONMENT_NAME	Required to modify the non-volatile RAM of systems that use this type of memory to store configuration information.
SE_SYSTEM_PROFILE_NAME	Required to gather profiling information for the entire system.
SE_SYSTEMTIME_NAME	Required to modify the system time.
SE_TAKE_OWNERSHIP_NAME	Required to take ownership of an object without being granted discretionary access. This privilege allows the owner value to be set only to those values that the holder may legitimately assign as the owner of an object.
SE_TCB_NAME	This privilege identifies its holder as part of the trusted computer base. Some trusted protected subsystems are granted this privilege.
SE_UNSOLICITED_INPUT_NAME	Required to read unsolicited input from a terminal device.
The following functions are provided for working with privileges.

Function	Description
LookupPrivilegeValue	Allows an application to retrieve the LUID corresponding to a privilege on the local system. This is the local representation of that privilege and an application can set it in the TOKEN_PRIVILEGES and LUID_AND_ATTRIBUTES structures.
LookupPrivilegeDisplayName	Retrieves a displayable privilege name. For example, "Force shutdown from a remote system."
LookupPrivilegeName	Retrieves a programmatic privilege name.
PrivilegeCheck	Determines whether a client application has the privileges required to gain access to an object, such as, SE_REMOTE_SHUTDOWN_NAME.


Impersonation

Impersonation is the ability of a process to take on the security attributes of another process. Typically, a server thread impersonates a client thread to act on behalf of that client to access objects or validate access to its own objects. For example, when a client in a DDE conversation requests information from a DDE server, the server can impersonate the client so the system can verify that the client is allowed access to the information.

Currently, there are three impersonation levels:

Impersonation Level	Meaning
SecurityAnonymous	Indicates the client does not want the server to obtain identification information about the client.
SecurityIdentification	Allows the server to obtain information about the client, such as security identifiers and privileges, without being able to impersonate the client. This is useful for servers who export their own objects, such as tables and views exported by a database product. Using the retrieved client security information, the server is able to make access-validation decisions for itself even though it is unable to use other services as the client.
SecurityImpersonation	Allows the server to impersonate the client's security context on its local system. The server cannot impersonate the client on remote systems.
A fourth level, SecurityDelegation, is not supported in this release of Windows NT.

A DDE server application can impersonate a client by calling the DdeImpersonateClient function. When it has finished the task requiring the impersonation, the DDE server application can revert to its own security information by calling the RevertToSelf function. Similarly, a named-pipe server can use the ImpersonateNamedPipeClient and RevertToSelf functions. The DuplicateToken function creates an impersonation token that duplicates an existing token.

The ImpersonateSelf function enables a thread to generate a copy of its own access token. This is useful when an application needs to change the security attributes of a single thread. For example, sometimes only one thread of a process requires a special privilege.


Security in New Objects

When an application creates an object, any values explicitly provided in a security descriptor are assigned to the object. If a security descriptor is not explicitly provided, the system searches for security information in different places, depending on the information required.

This guide describes the algorithms for security attribute assignments to newly created objects.


Assignment of Owner

To assign an owner to a new object when a security descriptor is not provided, the system checks the creator's access token for a default value. If no default value is found, the creator's user identifier (from the access token) is assigned as the object's owner. Even when an owner is provided in a security descriptor, the system checks these values in the access token to make sure the specified owner can be assigned ownership of the object.


Assignment of Group

To assign a primary group to a new object when a security descriptor is not provided, the system uses the primary group in the creator's access token.


Assignment of Discretionary ACL

To assign a discretionary access-control list (ACL) to a new object when a security descriptor is not provided, the system checks the parent's discretionary ACL for inheritable access-control entries (ACEs) and creates an ACL from any it finds. If there are no inheritable ACEs, the system checks the creator's security descriptor for a default discretionary ACL. If none is found in the security descriptor, the system looks in the creator's access token. If none of these sources provides a discretionary ACL, the object is created without one, and universal unconditional access to the object is granted.


Assignment of System ACL

To assign a system ACL to a new object when a security descriptor is not provided, the system checks the parent's system ACL for inheritable ACEs and creates an ACL from any it finds. If there are no inheritable ACEs, the system checks the creator's security descriptor for a default system ACL. When a system ACL is provided explicitly or by default in a security descriptor, the creator of the object must have the SE_SECURITY_NAME privilege, although this privilege is not required if the system ACL is acquired by inheritance. If none of these sources provides a system ACL, the object is created without one.


Security Attributes Inheritance

The security attributes of an object can be passed from process to process through the mechanism of handle inheritance. In addition, individual ACEs can be inherited in an ACL by new objects.


Handle Inheritance

If a new process inherits a handle, it also inherits the security attributes associated with that handle. A pointer to a SECURITY_ATTRIBUTES structure is used as a parameter in most Win32 kernel and window-management functions that return object handles. The bInheritHandle member of this structure specifies whether the returned handle is inherited when a new process is created. The security attributes of the inherited handle are identical to those of the original handle.


ACE Inheritance

Each ACE in an ACL begins with an ACE_HEADER structure structure specifying how that ACE is inherited. Among other things, the flags in an ACE_HEADER structure specify whether the ACE is inherited by container objects (directories or registry keys) or by non-container objects, such as files.

ACE Inheritance in Container Objects

This section outlines the rules governing the inheritance of ACEs by container objects.

If the CONTAINER_INHERIT_ACE flag is set in the ACE_HEADER structure of the parent ACE, a copy of the ACE is added to the end of the inherited ACL and the following actions are performed on the inherited ACE:

•	All inheritance flags in the inherited ACE are cleared.

•	If the ACE contains an access mask and any generic access flags are set, the generic rights are mapped to the standard and specific rights for the child object type.

If neither the CONTAINER_INHERIT_ACE flag nor the NO_PROPAGATE_INHERIT_ACE flag is set, the OBJECT_INHERIT_ACE and INHERIT_ONLY_ACE flags are set. If both the CONTAINER_INHERIT_ACE and the NO_PROPAGATE_INHERIT_ACE are set, the ACE is added to the end of the inherited ACL.

If neither the NO_PROPAGATE_INHERIT_ACE nor the CONTAINER_INHERIT_ACE flag is set in the ACE_HEADER structure of the parent ACE, a copy of the ACE is added to the end of the inherited ACL and its INHERIT_ONLY_ACE flag is set.

Otherwise, the ACE is not inherited.

ACE Inheritance in Non-container Objects

The following rules govern the inheritance of ACEs in objects other than containers.

If the OBJECT_INHERIT_ACE flag is set in the ACE_HEADER structure of the parent ACE, the ACE is copied to the end of the inherited ACL and:

•	The INHERIT_ONLY_ACE flag in the inherited ACE is cleared.

•	The NO_PROPAGATE_INHERIT_ACE, OBJECT_INHERIT_ACE, and CONTAINER_INHERIT_ACE flags in the inherited ACE are cleared.

•	If the ACE contains an access mask and, if any generic access flags are set, the generic rights are mapped to the standard and specific rights for the child object type.

Otherwise, the ACE is not inherited.


Duplicating Handles

Among cooperating processes, any one process is only as restricted as the least restricted process. For example, a process can call the DuplicateHandle function to duplicate an object handle belonging to a second (source) process into a third (target) process. If the access rights requested for the target process are greater than the rights held by the source process, the system checks the requested access rights against the security context of the process calling DuplicateHandle. If the calling process has the required access rights, the handle is duplicated, and the target process has greater access to the object than the source process.


Audit Generation

C2-level security requirements specify that system administrators must be able to audit security-related events and that access to this audit data must be limited to authorized administrators. The Win32 API provides functions enabling an administrator to monitor security-related events.

The system access-control list (ACL) contains audit access-control entries (ACEs) for an object. An application can use the GetSecurityDescriptorSacl and SetSecurityDescriptorSacl functions to retrieve an existing system ACL or to set a new one. The AddAuditAccessAce function adds an ACE to a system ACL that causes the system to record specified access attempts in a security log. This security log can be read by using the Microsoft Windows Event Viewer (EVENTVWR.EXE), and can be manipulated by using the event-logging functions discussed in Event Logging. For more information about system ACLs, see Access-control Lists (ACLs).

An application can use the ObjectPrivilegeAuditAlarm function to generate audit and alarm messages whenever a process attempts to complete a privileged operation. The PrivilegedServiceAuditAlarm generates audit and alarm messages whenever a process attempts to perform a privileged system-service operation.

The ObjectCloseAuditAlarm generates audit messages when an object is deleted. The ObjectOpenAuditAlarm function generates audit messages when a process attempts to open or gain access to an object.


Securable Objects

The kernel and window-management systems contain securable objects. This term refers to an object that has a security descriptor.

All named objects are securable. Some unnamed objects, such as unnamed process and thread objects, have security descriptors also.

You can use Win32 functions to query and set the security attributes of securable objects. The following are types of securable objects and the functions an application can use to manipulate their security attributes.

Object type	Functions
Files and directories	GetFileSecurity, SetFileSecurity
Mailslots	GetFileSecurity, SetFileSecurity
Pipes	GetFileSecurity, SetFileSecurity
Kernel objects (processes, threads, access tokens, and file-mapping objects)	SetKernelObjectSecurity, GetKernelObjectSecurity
Window-management objects (window stations and desktops)	GetUserObjectSecurity, SetUserObjectSecurity
Registry objects	RegGetKeySecurity, RegSetKeySecurity
Service objects	QueryServiceObjectSecurity, SetServiceObjectSecurity
Synchronization objects	SetKernelObjectSecurity, GetKernelObjectSecurity
Private objects (objects private to the creating application)	CreatePrivateObjectSecurity, DestroyPrivateObjectSecurity, GetPrivateObjectSecurity, SetPrivateObjectSecurity


File and Directory Objects

File and directory objects can be secured only when the New Technology file system (NTFS) is in use.

The access rights for files and directories must be manipulated by using the generic access rights.

For file objects, the handle returned by the CreateFile function has SYNCHRONIZE access and the right to read file attributes, in addition to the access rights specified in the call (GENERIC_READ, GENERIC_WRITE, or both).

GENERIC_READ access for file objects combines STANDARD_RIGHTS_READ and SYNCHRONIZE with rights that allow the process to read data from the file, read file attributes, and read extended attributes.

GENERIC_WRITE access for file objects combines STANDARD_RIGHTS_WRITE and SYNCHRONIZE with rights that allow the process to write data to the file, append data to it, write file attributes, and write extended attributes.

An application cannot use an access-denied ACE to deny only GENERIC_READ or GENERIC_WRITE access to a file. If an application denies GENERIC_WRITE access to a file, SYNCHRONIZE access is implicitly denied. When the CreateFile function is used in an attempt to open the file for read access, the function requests SYNCHRONIZE access and the operation fails. Instead of denying read or write access to a file, an application can explicitly allow the permitted access rights.

For directory objects, the handle returned by the CreateDirectory function has SYNCHRONIZE access and the right to list the contents of the directory.

For more information about files and directories, see Files.


Mailslot Objects

The handle returned by the CreateMailslot function has GENERIC_READ, SYNCHRONIZE, and WRITE_DAC access to the mailslot object.

GENERIC_READ access for a mailslot combines STANDARD_RIGHTS_READ with rights allowing the process to read data from the mailslot, read mailslot attributes, and read extended attributes.

For more information about mailslots, see Mailslots.


Pipe Objects

The security attributes of named pipes differ slightly from those of anonymous pipes.


Access Rights to Named Pipes

The handle returned by the CreateNamedPipe function always has SYNCHRONIZE access. It also has GENERIC_READ, GENERIC_WRITE, or both, depending on the open mode of the pipe. The following are the access rights for each open mode.

Open mode	Access rights
PIPE_ACCESS_DUPLEX	GENERIC_READ, GENERIC_WRITE, and SYNCHRONIZE
PIPE_ACCESS_INBOUND	GENERIC_READ and SYNCHRONIZE
PIPE_ACCESS_OUTBOUND	GENERIC_WRITE  and SYNCHRONIZE
GENERIC_READ access for a named pipe combines STANDARD_RIGHTS_READ access with rights that allow the process to read data from the named pipe and to read named-pipe attributes.

GENERIC_WRITE access for a named pipe combines STANDARD_RIGHTS_WRITE with rights that allow the process to write data to the named pipe and to write named-pipe attributes.


CreatePipe Function and Anonymous Pipes

The handles returned by the CreatePipe function have GENERIC_READ, GENERIC_WRITE, and SYNCHRONIZE access to the anonymous pipe, in addition to the right to write the attributes of the pipe. GENERIC_READ and GENERIC_WRITE access map to the same access rights as for named pipes.

For more information about pipes, see Pipes.


Special Access Kernel Objects

The following are the kernel objects for which the system defines special access rights:

•	Processes

•	Threads

•	Access tokens

•	File mapping


Process Objects

The valid access rights for process objects are STANDARD_RIGHTS_REQUIRED and the rights given in the following table.

Value	Meaning
PROCESS_ALL_ACCESS	Specifies all possible access rights for a process object.
PROCESS_CREATE_PROCESS	Required to create a process.
PROCESS_CREATE_THREAD	Required to create a thread.
PROCESS_DUP_HANDLE	Required to duplicate a handle.
PROCESS_QUERY_INFORMATION	Required to retrieve certain information about a process, such as its priority class.
PROCESS_SET_INFORMATION	Required to set certain information about a process, such as its priority class.
PROCESS_TERMINATE	Required to terminate a process.
PROCESS_VM_OPERATION	Required to perform an operation on the address space of a process.
PROCESS_VM_READ	Required to read memory in a process.
PROCESS_VM_WRITE	Required to write to memory in a process.
SYNCHRONIZE	Required to wait for the process to terminate.
The handle returned by the CreateProcess function has PROCESS_ALL_ACCESS access to the process object.

For more information about processes, see Processes and Threads.


Thread Objects

The valid access rights for thread objects are STANDARD_RIGHTS_REQUIRED and the rights given in the following table.

Value	Meaning
SYNCHRONIZE	Required to wait for the thread to exit.
THREAD_ALL_ACCESS	Specifies all possible access rights for a thread object. A thread created with THREAD_ALL_ACCESS access is created with its execution suspended.
THREAD_DIRECT_IMPERSONATION	Required for a server thread that impersonates a client.
THREAD_GET_CONTEXT	Required to read the context of a thread using GetThreadContext.
THREAD_IMPERSONATE	Required to use a thread's security information directly without calling it by using a communication mechanism that provides impersonation services.
THREAD_QUERY_INFORMATION	Required to read certain information from the thread object.
THREAD_SET_CONTEXT	Required to write the context of a thread.
THREAD_SET_INFORMATION	Required to set certain information in the thread object.
THREAD_SET_THREAD_TOKEN	Required to set the impersonation token for a thread.
THREAD_SUSPEND_RESUME	Required to suspend or resume a thread.
THREAD_TERMINATE	Required to terminate a thread.
The handle returned by the CreateThread function has THREAD_ALL_ACCESS access to the thread object.

For more information about threads, see Processes and Threads.


Access-token Objects

A process or thread cannot wait on an access-token object because the access-token object type does not support the SYNCHRONIZE standard access type.

The access rights defined for access-token objects are STANDARD_RIGHTS_REQUIRED and the rights given in the following table.

Value	Meaning
TOKEN_ADJUST_DEFAULT	Required to adjust default information, such as the owner, primary group, and default ACL in an access token.
TOKEN_ADJUST_GROUPS	Required to adjust the groups in an access token.
TOKEN_ADJUST_PRIVILEGES	Required to adjust the privileges in an access token.
TOKEN_ASSIGN_PRIMARY	Required to attach a primary token to a process. The SE_CREATE_TOKEN_NAME privilege is also required to accomplish this task.
TOKEN_DUPLICATE	Required to duplicate an access token.
TOKEN_EXECUTE	Combines STANDARD_RIGHTS_EXECUTE and TOKEN_IMPERSONATE.
TOKEN_IMPERSONATE	Required to attach an impersonation access token to a process.
TOKEN_QUERY	Required to query an access token.
TOKEN_QUERY_SOURCE	Required to query the source of an access token.
TOKEN_READ	Combines STANDARD_RIGHTS_READ and TOKEN_QUERY.
TOKEN_WRITE	Combines STANDARD_RIGHTS_WRITE, TOKEN_ADJUST_PRIVILEGES, TOKEN_ADJUST_GROUPS, and TOKEN_ADJUST_DEFAULT.
The TOKEN_ALL_ACCESS access right combines all possible access rights for a token.

The access rights for tokens are typically specified in calls to the OpenProcessToken and OpenThreadToken functions.


File Mapping Objects

A process or thread cannot wait on an access-token object because the access-token object type does not support the SYNCHRONIZE standard access type.

The access rights defined for file mapping objects are STANDARD_RIGHTS_REQUIRED and the rights given in the following table.

Value	Meaning
FILE_MAP_READ	Read access to the file-mapping object is requested. This allows a readable view of the file to be mapped.
FILE_MAP_WRITE	Write access to the file mapping object is requested. This allows a writable view of the file to be mapped. If the file mapping access rights do not include PAGE_READWRITE, this access type does not allow writing the mapped file.
SECTION_EXTEND_SIZE	Required to extend the size of a file mapping object.
SECTION_MAP_EXECUTE	Required to complete an operation in a file mapping object.
SECTION_MAP_READ	Equivalent to FILE_MAP_READ.
SECTION_MAP_WRITE	Equivalent to FILE_MAP_WRITE.
SECTION_QUERY	Required to query a file mapping object.
If the call to the CreateFileMapping function specifies the PAGE_READWRITE protection flag, the handle to the file mapping object has SECTION_QUERY | SECTION_MAP_READ | SECTION_MAP_WRITE access. If the call to CreateFileMapping specifies PAGE_READONLY, the handle of the file mapping object has SECTION_QUERY | SECTION_MAP_READ access.

The FILE_MAP_ALL_ACCESS access right specifies all possible access rights for the file mapping object. The SECTION_ALL_ACCESS access right is equivalent to it.

For more information about file-mapping objects, see File Mapping.


Window-management Objects

The following are the securable window-management objects.

Securable Object	Description
Window station	An object that contains a clipboard, a set of global atoms, and a group of desktop objects. The interactive window station assigned to the logon session of the interactive user also contains the display device, keyboard, and mouse. Window stations provide the first level of security for a work station and are the source of inheritable security for desktop objects.
Desktop	An object that has a display surface and contains windows, menus, and hooks. A desktop object is a subobject of a window-station object, from which it inherits security.


Window-station Objects
Window Station Objects

The following are the window station access rights and their meanings.

Constant	Description
WINSTA_ACCESSCLIPBOARD	Required to use the clipboard.
WINSTA_ACCESSGLOBALATOMS	Required to manipulate global atoms.
WINSTA_CREATEDESKTOP	Required to create new desktop objects on the window station.
WINSTA_ENUMDESKTOPS	Required to enumerate existing desktop objects.
WINSTA_ENUMERATE	Required for the window station to be enumerated.
WINSTA_EXITWINDOWS	Required to successfully call the ExitWindows or ExitWindowsEx function. Window stations can be shared by users and this access type can prevent other users of a window station from logging off the window station owner.
WINSTA_READATTRIBUTES	Required to read the attributes of a window station object. This attribute includes color settings and other global window station properties.
WINSTA_READSCREEN	Required to access screen contents.
WINSTA_WRITEATTRIBUTES	Required to modify the attributes of a window station object. The attributes include color settings and other global window-station properties.
The following are the generic mappings for the interactive window-station object, which is the window station assigned to the logon session of the interactive user.

Value	Maps to
GENERIC_READ	STANDARD_RIGHTS_READ, WINSTA_ENUMDESKTOPS, WINSTA_ENUMERATE, WINSTA_READATTRIBUTES, and WINSTA_READSCREEN
GENERIC_WRITE	STANDARD_RIGHTS_WRITE, WINSTA_ACCESSCLIPBOARD, WINSTA_CREATEDESKTOP, and WINSTA_WRITEATTRIBUTES
GENERIC_EXECUTE	STANDARD_RIGHTS_EXECUTE, WINSTA_ACCESSGLOBALATOMS, and WINSTA_EXITWINDOWS
GENERIC_ALL	STANDARD_RIGHTS_REQUIRED, WINSTA_ACCESSCLIPBOARD, WINSTA_ACCESSGLOBALATOMS, WINSTA_CREATEDESKTOP, WINSTA_ENUMDESKTOPS, WINSTA_ENUMERATE, WINSTA_EXITWINDOWS, WINSTA_READATTRIBUTES, WINSTA_READSCREEN, and WINSTA_WRITEATTRIBUTES
The following are the generic mappings for a noninteractive window-station object. The system assigns noninteractive window stations to all logon sessions other than that of the interactive user.

Value	Maps to
GENERIC_READ	STANDARD_RIGHTS_READ, WINSTA_ENUMDESKTOPS, WINSTA_ENUMERATE, and WINSTA_READATTRIBUTES
GENERIC_WRITE	STANDARD_RIGHTS_WRITE, WINSTA_ACCESSCLIPBOARD, and WINSTA_CREATEDESKTOP
GENERIC_EXECUTE	STANDARD_RIGHTS_EXECUTE, WINSTA_ACCESSGLOBALATOMS, and WINSTA_EXITWINDOWS
GENERIC_ALL	STANDARD_RIGHTS_REQUIRED, WINSTA_ACCESSCLIPBOARD, WINSTA_ACCESSGLOBALATOMS, WINSTA_CREATEDESKTOP, WINSTA_ENUMDESKTOPS, WINSTA_ENUMERATE, WINSTA_EXITWINDOWS, and WINSTA_READATTRIBUTES
An application can call the GetProcessWindowStation function to retrieve a handle of its assigned window station. The security attributes of the window station can be retrieved and set by using this handle in calls to the GetUserObjectSecurity and SetUserObjectSecurity functions. An application can use the GetUserObjectInformation and SetUserObjectInformation functions to get and set information about a window-station object. For more information on window-station objects, see Window Stations and Desktops.


Desktop Objects

A new desktop inherits its security descriptor from its parent window station.

The following are the desktop access rights and their meanings.

Constant	Description
DESKTOP_CREATEMENU	Required to create a menu on the the desktop.
DESKTOP_CREATEWINDOW	Required to create a window on the desktop.
DESKTOP_ENUMERATE	Required for the desktop to be enumerated.
DESKTOP_HOOKCONTROL	Required to establish any of the window hooks.
DESKTOP_JOURNALPLAYBACK	Required to perform journal playback on a desktop.
DESKTOP_JOURNALRECORD	Required to perform journal recording on a desktop.
DESKTOP_READOBJECTS	Required to read objects on the desktop.
DESKTOP_SWITCHDESKTOP	Required to activate the desktop using the SwitchDesktop function.
DESKTOP_WRITEOBJECTS	Required to write objects on the desktop.
The following are the generic mappings for a desktop object contained in the interactive window station of the user's logon session.

Value	Maps to
GENERIC_READ	DESKTOP_ENUMERATE, DESKTOP_READOBJECTS, and STANDARD_RIGHTS_READ
GENERIC_WRITE	DESKTOP_CREATEMENU, DESKTOP_CREATEWINDOW, DESKTOP_HOOKCONTROL, DESKTOP_JOURNALPLAYBACK, DESKTOP_JOURNALRECORD, DESKTOP_WRITEOBJECTS, and STANDARD_RIGHTS_WRITE
GENERIC_EXECUTE	DESKTOP_SWITCHDESKTOP and STANDARD_RIGHTS_EXECUTE
GENERIC_ALL	DESKTOP_CREATEMENU, DESKTOP_CREATEWINDOW, DESKTOP_ENUMERATE, DESKTOP_HOOKCONTROL, DESKTOP_JOURNALPLAYBACK, DESKTOP_JOURNALRECORD, DESKTOP_READOBJECTS, DESKTOP_SWITCHDESKTOP, DESKTOP_WRITEOBJECTS, and STANDARD_RIGHTS_REQUIRED
An application can call the GetThreadDesktop function to retrieve a handle of the desktop for a given thread. The desktop's security attributes can be retrieved and set by using this handle in calls to GetUserObjectSecurity and SetUserObjectSecurity. An application can use the GetUserObjectInformation and SetUserObjectInformation functions to get and set information about a desktop object. For more information on desktop objects, see Window Stations and Desktops.


Registry Key Objects

The following are the registry-key access rights and their meanings.

Value	Meaning
KEY_ALL_ACCESS	Combines the STANDARD_RIGHTS_REQUIRED, KEY_QUERY_VALUE, KEY_SET_VALUE, KEY_CREATE_SUB_KEY, KEY_ENUMERATE_SUB_KEYS, KEY_NOTIFY, and KEY_CREATE_LINK values.
KEY_CREATE_LINK	Required to create a link to a registry-key object.
KEY_CREATE_SUB_KEY	Required to create a subkey of a registry-key object.
KEY_ENUMERATE_SUB_KEYS	Required to enumerate the subkeys of a registry-key object.
KEY_EXECUTE	Equivalent to KEY_READ.
KEY_NOTIFY	Required to request change notifications for a registry key or for subkeys of a registry key.
KEY_QUERY_VALUE	Required to query a value of a registry-key object.
KEY_READ	Combines the STANDARD_RIGHTS_READ, KEY_QUERY_VALUE, KEY_ENUMERATE_SUB_KEYS, and KEY_NOTIFY values.
KEY_SET_VALUE	Required to create or set a value of a registry-key object.
KEY_WRITE	Combines the STANDARD_RIGHTS_WRITE, KEY_SET_VALUE, and KEY_CREATE_SUB_KEY values.
For more information about registry objects, see Registry.


Service Objects

The access rights and generic mappings for service-control manager objects and service objects are given in the reference materials for the OpenService and OpenSCManager functions. For information about service objects, see Services.


Synchronization Objects

There are three kinds of securable synchronization objects: semaphores, events, and mutexes. The fourth type of synchronization object is critical sections. Because they are per-process objects and not kernel objects, they are not securable.


Semaphore Objects

The valid access rights for semaphore objects are STANDARD_RIGHTS_REQUIRED and the rights given in the following table.

Value	Meaning
SEMAPHORE_ALL_ACCESS	Specifies all possible access rights for a semaphore object.
SEMAPHORE_MODIFY_STATE	Specifies modify state (release) access.
SYNCHRONIZE	Specifies synchronization (wait) access.
The handle returned by the CreateSemaphore function has SEMAPHORE_ALL_ACCESS access to the semaphore object.


Event Objects

The valid access rights for event objects are STANDARD_RIGHTS_REQUIRED and the rights given in the following table.

Value	Meaning
EVENT_ALL_ACCESS	Specifies all possible access rights for an event object.
EVENT_MODIFY_STATE	Specifies modify state (release) access.
SYNCHRONIZE	Specifies synchronization (wait or release) access.
The handle returned by the CreateEvent function has EVENT_ALL_ACCESS access to the semaphore object.


Mutex Objects

The valid access rights for mutex objects are STANDARD_RIGHTS_REQUIRED and the rights given in the following table.

Value	Meaning
MUTEX_ALL_ACCESS	Specifies all possible access rights for a mutex object.
MUTEX_MODIFY_STATE	Specifies modify state (release) access.
SYNCHRONIZE	Specifies synchronization (wait or release) access.
The handle returned by the CreateMutex function has MUTEX_ALL_ACCESS access to the mutex object.


Using Security

The following topics demonstrate some practical applications of the Win32 API security functions and structures. As noted in File and Directory Objects, file objects can be secured only when the NTFS file system is in use.

•	Denying all access

•	Allowing access

•	Setting privileges

•	Security editor

•	Designing a protected server


Denying All Access

The following example demonstrates adding an empty discretionary access-control list (ACL) to a file's security descriptor. An empty ACL implicitly denies all access to the file.

PSECURITY_DESCRIPTOR pSD;

PACL pACL;

DWORD cbACL = 1024;

/* Initialize a security descriptor. */

pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR,

    SECURITY_DESCRIPTOR_MIN_LENGTH);   /* defined in WINNT.H */

if (pSD == NULL) {

    ErrorHandler("LocalAlloc");

    return FALSE;

}

if (!InitializeSecurityDescriptor(pSD,

        SECURITY_DESCRIPTOR_REVISION)) { /* defined in WINNT.H */

    ErrorHandler("InitializeSecurityDescriptor");

    goto Cleanup;

}

/* Initialize a DACL. */

pACL = (PACL) LocalAlloc(LPTR, cbACL);

if (pACL == NULL) {

    ErrorHandler("LocalAlloc");

    goto Cleanup;

}

if (!InitializeAcl(pACL, cbACL, ACL_REVISION2)) {

    ErrorHandler("InitializeAcl");

    goto Cleanup;

}

/* Add an empty ACL to the SD to deny access. */

if (!SetSecurityDescriptorDacl(pSD,

        TRUE,     /* fDaclPresent flag  */

        pACL,

        FALSE)) { /* not a default DACL */

    ErrorHandler("SetSecurityDescriptorDacl");

    goto Cleanup;

}

/* Use the new SD as the file's security info. */

if (!SetFileSecurity(lpszTestFile,

        DACL_SECURITY_INFORMATION,

        pSD)) {

    ErrorHandler("SetFileSecurity");

    goto Cleanup;

}

Cleanup:

    if(pSD != NULL)

        LocalFree((HLOCAL) pSD);

    if(pACL != NULL)

        LocalFree((HLOCAL) pACL);


Allowing Access

The following example demonstrates adding a NULL discretionary ACL to a file's security descriptor. A NULL ACL implicitly allows all access to the file.

Note: It is fine to write code like this that builds security descriptors from scratch. It is, however, a good practice for people who write code that builds or manipulates security descriptors to first write code that explores the default security descriptors that Windows NT places on objects. For example, if Windows NT by default includes in a DACL an ACE granting the Local Logon SID certain access, it's good to know that, so that a decision not to grant any access to the Local Logon SID would be a conscious decision.

PSECURITY_DESCRIPTOR pSD;

/* Initialize a security descriptor. */

pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR,

    SECURITY_DESCRIPTOR_MIN_LENGTH);   /* defined in WINNT.H */

if (pSD == NULL) {

    ErrorHandler("LocalAlloc");

    return FALSE;

}

if (!InitializeSecurityDescriptor(pSD,

        SECURITY_DESCRIPTOR_REVISION)) { /* defined in WINNT.H */

    ErrorHandler("InitializeSecurityDescriptor");

    goto Cleanup;

}

/* Add a NULL disc. ACL to the security descriptor. */

if (!SetSecurityDescriptorDacl(pSD,

        TRUE,     /* specifying a disc. ACL  */

        (PACL) NULL,

        FALSE)) { /* not a default disc. ACL */

    ErrorHandler("SetSecurityDescriptorDacl");

    goto Cleanup;

}

/* Add the security descriptor to the file. */

if (!SetFileSecurity(lpszTestFile,

        DACL_SECURITY_INFORMATION,

        pSD)) {

    ErrorHandler("SetFileSecurity");

    goto Cleanup;

}

Cleanup:

    if(pSD != NULL)

        LocalFree((HLOCAL) pSD);

Rather than allowing all access by using a NULL ACL, applications generally allow access to an object by adding access-control entries (ACEs) to an ACL. The following example demonstrates finding a security identifier (SID) for a particular account and adding an access-allowed ACE for that account.

    PSECURITY_DESCRIPTOR pSD;

    PACL pACLNew;

    DWORD cbACL = 1024;

    PSID pSID;

    DWORD cbSID = 1024;

    LPSTR lpszAccount = "UserABC";

    LPSTR lpszDomain;

    DWORD cchDomainName = 80;

    PSID_NAME_USE psnuType;

    /* Initialize a new security descriptor. */

    pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR,

        SECURITY_DESCRIPTOR_MIN_LENGTH);  /* defined in WINNT.H  */

    if (pSD == NULL) {

        ErrorHandler("LocalAlloc");

        return FALSE;

    }

    if (!InitializeSecurityDescriptor(pSD,

            SECURITY_DESCRIPTOR_REVISION)) {

        ErrorHandler("InitializeSecurityDescriptor");

        goto Cleanup;

    }

    /* Initialize a new ACL.                 */

    pACLNew = (PACL) LocalAlloc(LPTR, cbACL);

    if (pACLNew == NULL) {

        ErrorHandler("LocalAlloc");

        goto Cleanup;

    }

    if (!InitializeAcl(pACLNew, cbACL, ACL_REVISION2)) {

        ErrorHandler("InitializeAcl");

        goto Cleanup;

    }

    /* Retrieve the SID for UserABC.         */

    pSID = (PSID) LocalAlloc(LPTR, cbSID);

    psnuType = (PSID_NAME_USE) LocalAlloc(LPTR, 1024);

    lpszDomain = (LPSTR) LocalAlloc(LPTR, cchDomainName);

    if (pSID == NULL || psnuType == NULL ||

        lpszDomain == NULL) {

        ErrorHandler("LocalAlloc");

        goto Cleanup;

    }

    if (!LookupAccountName((LPSTR) NULL, /* local name */

            lpszAccount,

            pSID,

            &cbSID,

            lpszDomain,

            &cchDomainName,

            psnuType)) {

        ErrorHandler("LookupAccountName");

        goto Cleanup;

    }

    if (!IsValidSid(pSID))

        TextOut(hdc, 10, yIncrement += 18,

            "SID is not valid.", 17);

    else

        TextOut(hdc, 10, yIncrement += 18,

            "SID is valid.", 13);

    /* Allow read but not write access to the file. */

    if (!AddAccessAllowedAce(pACLNew,

            ACL_REVISION2,

            GENERIC_READ,

            pSID)) {

        ErrorHandler("AddAccessAllowedAce");

        goto Cleanup;

    }

    /* Add a new ACL to the security descriptor.          */

    if (!SetSecurityDescriptorDacl(pSD,

            TRUE,              /* fDaclPresent flag  */

            pACLNew,

            FALSE)) {          /* not a default disc. ACL */

        ErrorHandler("SetSecurityDescriptorDacl");

        goto Cleanup;

    }

    /* Apply the new security descriptor to the file. */

    if (!SetFileSecurity("d:\\ntfs_sample_file",

            DACL_SECURITY_INFORMATION,

            pSD)) {

        ErrorHandler("SetFileSecurity");

        goto Cleanup;

    }

    TextOut(hdc, 10, yIncrement += 18,

        "Successfully added access-allowed ACE to file's DACL.", 53);

    Cleanup:

        FreeSid(pSID);

        if(pSD != NULL)

            LocalFree((HLOCAL) pSD);

        if(pACLNew != NULL)

            LocalFree((HLOCAL) pACLNew);

        if(psnuType != NULL)

            LocalFree((HLOCAL) psnuType);

        if(lpszDomain != NULL)

            LocalFree((HLOCAL) lpszDomain);


Setting Privileges

The following example removes the discretionary ACL from a file. If necessary, ownership of the file is given to the Administrator account. If required, the SE_TAKE_OWNERSHIP_NAME privilege is enabled for the account.

LPSTR lpszOwnFile = "d:\\ntfs_sample_file";

PSID pSIDAliasAdmins = NULL;

static SID_IDENTIFIER_AUTHORITY

    siaNTAuthority = SECURITY_NT_AUTHORITY;

BOOL FAR PASCAL TakeOwnership()

{

    SECURITY_DESCRIPTOR sd;

    /*

     * Initialize a security descriptor and assign it a NULL

     * discretionary ACL to allow unrestricted access.

     * Assign the security descriptor to a file.

     */

    if (!InitializeSecurityDescriptor(&sd,

            SECURITY_DESCRIPTOR_REVISION)) {

        ErrorHandler("InitializeSecurityDescriptor");

        return FALSE;

    }

    if (!SetSecurityDescriptorDacl(&sd,

            TRUE,

            (PACL) NULL,

            FALSE)) {

        ErrorHandler("SetSecurityDescriptorDacl");

        return FALSE;

    }

    if (SetFileSecurity(lpszOwnFile,

            DACL_SECURITY_INFORMATION,

            &sd))

        return TRUE;

    else

        ErrorHandler("SetFileSecurity1");

    /*

     * If the preceding call to SetFileSecurity fails, create

     * an Administrator SID and use it to set the owner of

     * the security descriptor.

     */

    if (!AllocateAndInitializeSid(&siaNTAuthority,

            2,                     /* subauthority count  */

                                   /* first subauthority */

            SECURITY_BUILTIN_DOMAIN_RID,

                                   /* second subauthority */

            DOMAIN_ALIAS_RID_ADMINS,

            0, 0, 0, 0, 0, 0,

            &pSIDAliasAdmins)) {

        ErrorHandler("AllocateAndInitializeSid");

        return FALSE;

    }

    if (!SetSecurityDescriptorOwner(&sd,

            pSIDAliasAdmins,

            FALSE)) {

        ErrorHandler("SetSecurityDescriptorOwner");

        FreeSid(pSIDAliasAdmins);

        return FALSE;

    }

    /*

     * If the following call to SetFileSecurity fails,

     * enable SE_TAKE_OWNERSHIP_NAME in the access token for

     * the current process and try again.

     */

    if (!SetFileSecurity(lpszOwnFile,

            OWNER_SECURITY_INFORMATION,

            &sd)) {

        ErrorHandler("SetFileSecurity2");

        if (!AssertTakeOwnership(TRUE)) {   /* local */

            MessageBox(NULL, "Must be logged on as Administrator",

                "AssertTakeOwnership", MB_OK);

            FreeSid(pSIDAliasAdmins);

            return FALSE;

        }

        if (!SetFileSecurity(lpszOwnFile,

                OWNER_SECURITY_INFORMATION,

                &sd)) {

            MessageBox(NULL, "Must be logged on as Administrator",

                "SetFileSecurity", MB_OK);

            FreeSid(pSIDAliasAdmins);

            return FALSE;

        }

    }

    /*

     * The Administrator is now the owner of the file.

     * Try again to assign a NULL ACL.

     */

    if (SetFileSecurity(lpszOwnFile,

            DACL_SECURITY_INFORMATION,

            &sd)) {

        MessageBox(NULL, "Added NULL DACL; protection removed",

            "SetFileSecurity", MB_OK);

        AssertTakeOwnership(FALSE);

        return TRUE;

    }

    else {

        AssertTakeOwnership(FALSE);

        ErrorHandler("SetFileSecurity3");

        return FALSE;

    }

}

BOOL FAR PASCAL AssertTakeOwnership(BOOL fEnable)

{

    HANDLE hToken;

    LUID TakeOwnershipValue;

    TOKEN_PRIVILEGES tkp;

    /* Retrieve a handle of the access token.           */

    if (!OpenProcessToken(GetCurrentProcess(),

            TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,

            &hToken)) {

        ErrorHandler("OpenProcessToken");

        return FALSE;

    }

    /*

     * Enable the SE_TAKE_OWNERSHIP_NAME privilege or

     * disable all privileges, depending on the fEnable

     * flag.

     */

    if(fEnable) {

        if (!LookupPrivilegeValue((LPSTR) NULL,

                SE_TAKE_OWNERSHIP_NAME,

                &TakeOwnershipValue)) {

            ErrorHandler("LookupPrivilegeValue");

            return FALSE;

        }

        tkp.PrivilegeCount = 1;

        tkp.Privileges[0].Luid = TakeOwnershipValue;

        tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

        AdjustTokenPrivileges(hToken,

            FALSE,

            &tkp,

            sizeof(TOKEN_PRIVILEGES),

            (PTOKEN_PRIVILEGES) NULL,

            (PDWORD) NULL);

        /*

         * The return value of AdjustTokenPrivileges cannot

         * be tested.

         */

        if (GetLastError() != ERROR_SUCCESS) {

            ErrorHandler("AdjustTokenPrivileges");

            return FALSE;

        }

    }

    else {

        AdjustTokenPrivileges(hToken,

            TRUE,               /* disable all privileges */

            (PTOKEN_PRIVILEGES) NULL,

            (DWORD) 0,

            (PTOKEN_PRIVILEGES) NULL,

            (PDWORD) NULL);

        /*

         * The return value of AdjustTokenPrivileges cannot

         * be tested.

         */

        if (GetLastError() != ERROR_SUCCESS) {

            ErrorHandler("AdjustTokenPrivileges");

            return FALSE;

        }

    }

    return TRUE;

}


Security Editor

Both File Manager and the Microsoft Windows NT Registry Editor (REGEDT32.EXE) include a security editor that allows a user with the appropriate privileges and access rights to change the security attributes of files and registry keys. This security editor imposes guidelines on the form of the security information. Applications that modify the security of files, directories, or registry keys can follow these guidelines so the security editor will function correctly after the modifications.

The security editor accepts discretionary ACLs having either zero or more ACCESS_DENIED_ACE access-control entries (ACEs) or zero or more ACCESS_ALLOWED_ACE ACEs. The two ACE types cannot be mixed in a discretionary ACL. Neither does the security editor accept ACCESS_DENIED_ACE ACEs that deny only partial access. For example, it would reject an ACE that denies only read access to a file.

The security editor also imposes a requirement on inheritance flags. These flags are ignored for noncontainer objects, such as files, but are important for container objects, such as directories and registry keys. For container objects that support permissions on objects in the container, make sure that each security identifier (SID) has an ACE inherited by objects and an ACE inherited by containers. Accordingly, the discretionary ACL should contain ACEs in which the AceFlags member of the ACE_HEADER structure structure contains the OBJECT_INHERIT_ACE and CONTAINER_INHERIT_ACE flags. Sometimes these flags can be combined in a single ACE. For example, a discretionary ACL that grants read access to a directory can contain a CONTAINER_INHERIT_ACE ACE that grants GENERIC_READ access to the user or group as well as an ACE with the OBJECT_INHERIT_ACE and INHERIT_ONLY_ACE flags that also grants GENERIC_READ access. In this case, the required flags could be combined into an ACE that grants GENERIC_READ access and combines the CONTAINER_INHERIT_ACE and OBJECT_INHERIT_ACE flags.

The same rules for inheritance flags apply to system ACLs. The security editor does not support the SYSTEM_ALARM_ACE type and will not edit a system ACL containing one. As noted earlier, this ACE type is not supported by the current version of Windows NT.


Designing a Protected Server

The designer of a server application that assigns security to private object types must make many decisions about the design of the security interface, such as those in the following list:

•	Define object.

•	Determine the types of objects and the access types required, including whether to support SYNCHRONIZE.

•	Determine whether an object is a container or noncontainer, as well as the appropriate inheritance flags. For more information about container objects, see Networks.

•	Define appropriate access types and generic mappings.

•	Determine impersonation characteristics.

•	Develop security descriptor for the initial object and for new objects assembled from the parent's security descriptor and the client's access token.

•	Consider string- versus handle-based object-manipulation functions.

•	Resolve potential conflicts in access rights. For example, decide what is to be done if an administrator and a user both have delete access to an object.

For example, the designer of a protected print server might choose to define a server object, a printer object, and a document object. The three access rights in the following table are likely to be required:

Access right	Description
Administrate	Allows the holder to add objects to and delete them from another object. This right applies to the server, the printers, and the documents.
Enumerate	Allows the holder to list a container object's contents. This right applies to the server and to the printers.
Use	Allow the holder to add items to a print queue. This right applies to the printers.


Security Functions

Following are the functions used to control security.

AccessCheck
AccessCheckAndAuditAlarm
AddAccessAllowedAce
AddAccessDeniedAce
AddAce
AddAuditAccessAce
AdjustTokenGroups
AdjustTokenPrivileges
AllocateAndInitializeSid
AllocateLocallyUniqueId
AreAllAccessesGranted
AreAnyAccessesGranted
CopySid
CreatePrivateObjectSecurity
DdeImpersonateClient
DeleteAce
DestroyPrivateObjectSecurity
DuplicateToken
EqualPrefixSid
EqualSid
FindFirstFreeAce
FreeSid
GetAce
GetAclInformation
GetFileSecurity
GetKernelObjectSecurity
GetLengthSid
GetPrivateObjectSecurity
GetProcessWindowStation
GetSecurityDescriptorControl
GetSecurityDescriptorDacl
GetSecurityDescriptorGroup
GetSecurityDescriptorLength
GetSecurityDescriptorOwner
GetSecurityDescriptorSacl
GetSidIdentifierAuthority
GetSidLengthRequired
GetSidSubAuthority
GetSidSubAuthorityCount
GetTokenInformation
GetUserObjectSecurity
ImpersonateNamedPipeClient
ImpersonateSelf
InitializeAcl
InitializeSecurityDescriptor
InitializeSid
IsValidAcl
IsValidSecurityDescriptor
IsValidSid
LookupAccountName
LookupAccountSid
LookupPrivilegeDisplayName
LookupPrivilegeName
LookupPrivilegeValue
MakeAbsoluteSD
MakeSelfRelativeSD
MapGenericMask
ObjectCloseAuditAlarm
ObjectOpenAuditAlarm
ObjectPrivilegeAuditAlarm
OpenProcessToken
OpenThreadToken
PrivilegeCheck
PrivilegedServiceAuditAlarm
RevertToSelf
SetAclInformation
SetFileSecurity
SetKernelObjectSecurity
SetPrivateObjectSecurity
SetSecurityDescriptorDacl
SetSecurityDescriptorGroup
SetSecurityDescriptorOwner
SetSecurityDescriptorSacl
SetThreadToken
SetTokenInformation
SetUserObjectSecurity


Services

In the Microsoft® Win32® application programming interface (API), a service is an executable object that is installed in a registry database maintained by the service control manager.


About Services

The services database includes information that determines whether each installed service is started on demand or is started automatically when the system starts. The database can also contain logon and security information for a service so that a service can run even though no user is logged on. It also enables system administrators to customize security requirements for each service and thereby control access to the service. No more than one instance of a service can be running at a time.

Services can be divided into these two groups: Win32 services that conform to the interface rules of the service control manager, and driver services that conform to the device driver protocols for Microsoft Windows NT™.


Service Control Manager

A service control manager provides a unified and secure means of controlling services. Each machine that is running Windows NT has a service control manager process started by the system at system startup. The service control manager is a remote procedure call (RPC) server. The functions in the Win32 API that access a service control manager are provided through an RPC server so that service configuration and service control processes can manipulate services on remote machines.

The Win32 API includes a set of functions that provide a programmer's interface for the following tasks performed by the service control manager:

•	Using the registry to maintain a database of installed service objects.

•	Starting services either when the system is starting up or upon demand.

•	Maintaining status information on running services.

•	Transmitting control requests to running services.

Three types of programs use these functions:

Type	Description
Win32 service process
	A process that provides executable code for one or more services. Win32 services use functions that connect to the service control manager and send status information to it. Driver services do not use these functions.
Service configuration program
	A program that queries or modifies a service control manager database. Service configuration programs use functions that open a database, install or delete services in a database, and query or modify the configuration and security parameters of installed services. The functions are used to manipulate Win32 services and driver services.
Service control program
	A program that starts a service and controls a running service. Service control programs use functions that send requests to the service control manager, which starts the requested service or sends the control request to the specified service.


Database of Installed Services

The service control manager maintains a ServicesActive database in the registry. This is the currently active database that was used to start the system. The following is the registry path to this database.

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services

In this directory, there is a ServiceName key for each installed Win32 service or driver service. The ServiceName key is the name of the service specified by the CreateService function when the service was installed.

The database includes the following information about each installed service:

•	The type of service. For Win32 services, the service type indicates whether the service executes in its own process or shares a process with other Win32 services. For driver services, it indicates whether the service is a kernel driver or a file system driver.

•	The start type of the service. The start type indicates whether the service is started automatically at system startup or whether the service control manager starts it when requested by a service control process. The start type can also indicate whether the service is disabled, in which case it cannot be started.

•	A fully qualified path of the service's executable file. The filename extension is .EXE for Win32 services and .SYS for driver services.

•	Optional information used by the service control manager to determine the proper order for starting services. This information can include a list of services that must be running before the service can start, the name of a load ordering group that the service is part of, and a tag identifier that indicates the start order of the service in its load ordering group.

•	For Win32 services, an optional logon account name in which the service process runs and an optional password for this account. If no account is specified, the service runs in the LocalSystem account.

•	For driver services, an optional driver object name (for example, \FileSystem\Rdr or \Driver\Xns), used by the I/O system to load the device driver. If no name is specified, the I/O system creates a default name based on the service name.


Win32 Service Processes

A Win32 service process contains executable code for one or more services. To conform to the interface requirements of the service control manager, it must include:

•	A main function that immediately calls the StartServiceCtrlDispatcher function to connect the main thread of the process to the service control manager.

•	An entry point function, ServiceMain, for each service that can run in the process.

•	A control handler function, Handler, for each service that can run in the process.

For simplicity, the discussions in this section use the term service to mean Win32 service. The information in this section does not apply to driver services.


Main Function

When the service control manager starts a service process, it waits for the process to call the StartServiceCtrlDispatcher function. If a service does not share a process with other services (SERVICE_WIN32_OWN_PROCESS services), the main thread of a service process should make this call immediately, leaving all initialization tasks to be performed by the ServiceMain function after the service starts. For services where multiple services share a process (SERVICE_WIN32_SHARE_PROCESS services) and where some common process-wide initialization needs to be done before any ServiceMain function is called, the main thread can do the work before calling StartServiceCtrlDispatcher, as long as it takes less than 30 seconds. Otherwise, another thread must be created to do the process-wide initialization, while the main thread calls StartServiceCtrlDispatcher. Any service specific initialization should still be done by the individual ServiceMain functions.

If StartServiceCtrlDispatcher succeeds, it connects the calling thread to the service control manager and does not return until all running services in the process have terminated. The service control manager uses this connection to send control and service start requests to the main thread of the service process. The main thread acts as a dispatcher by calling the appropriate Handler function to handle control requests or by creating a new thread to execute the appropriate ServiceMain function when a new service is started.

The StartServiceCtrlDispatcher function specifies a dispatch table containing an entry for each service that can run in the calling process. Each entry specifies the ServiceMain function for that service. For SERVICE_WIN32_SHARE_PROCESS services, each entry must contain the name of a service. This name is the service name that was specified by the CreateService function when the service was installed. For SERVICE_WIN32_OWN_PROCESS services, the service name in the table entry is ignored.


ServiceMain Function

The ServiceMain function is the entry point for a service. When a service control program calls the StartService function and the service process for this service is not yet running, the service control manager starts the process and sends a start request to the dispatcher in the service's main thread. The dispatcher creates a new thread to execute the ServiceMain function for the service.

A ServiceMain function should perform the following tasks:

1.	Call the RegisterServiceCtrlHandler function immediately to register a Handler function to handle control requests for the service. The return value of RegisterServiceCtrlHandler is a SERVICE_STATUS_HANDLE type that identifies the service in calls to the SetServiceStatus function. A service calls SetServiceStatus to inform the service control manager of its status.

2.	Perform initialization. If the execution time of the initialization code is expected to be very short (less than one second), initialization can be performed directly in ServiceMain.

If the initialization time is expected to be longer than one second, call SetServiceStatus, specifying SERVICE_START_PENDING as the current service state. As initialization continues, the service should make additional calls to SetServiceStatus to report progress. Sending multiple SetServiceStatus calls is useful for both service debugging and product support.

The following members of the SERVICE_STATUS structure passed in SetServiceStatus calls should change as the initialization progresses:

Member	Value
dwCurrentState	Set this value to SERVICE_START_PENDING during initialization. Set it to SERVICE_RUNNING when initialization is complete.
dwControlsAccepted	You can disable control codes during initialization and enable them when initialization is complete.
dwCheckPoint	Increment this value each time SetServiceStatus.  is called. That informs the service control manager of the progress of a lengthy initialization.
dwWaitHint	This value is an estimate of how long it will take to complete the next initialization step. It should reflect a worst-case estimate of the amount of time, in milliseconds, that will elapse before the next pending call to SetServiceStatus. If this interval elapses and dwCheckPoint has not been incremented, the service control manager or service control program can assume that an error has occurred.
3.	When initialization is complete, call SetServiceStatus to specify the current state as SERVICE_RUNNING. The ServiceMain function can then go on to perform the service tasks, or, if there are no pending tasks, it can return. Any change in the state of the service warrants a call to SetServiceStatus to report new status information. If the service stops due to an error, the service should use the dwServiceSpecificExitCode and dwWin32ExitCode members of the SERVICE_STATUS structure to identify the error.


The Control Handler Function

Each Win32 service has a control handler function, the Handler function, that is invoked by the main thread's dispatcher when the service process receives a control request. Control requests are generated by application programs that call the ControlService function. To register a Handler function, the service's ServiceMain function calls RegisterServiceCtrlHandler.

Whenever a service's Handler function is invoked, the service must call the SetServiceStatus function to report its status to the service control manager. This call must be done regardless of whether the status changed.

There is a set of standard control codes that the ControlService function can specify. All services must accept and process the SERVICE_CONTROL_INTERROGATE control code. Any of the other standard control codes can be enabled or disabled by calling SetServiceStatus. Services can also handle additional user-defined control codes, which must be in the range 128 to 255.

The standard control codes are listed below:

Control	Meaning
SERVICE_CONTROL_STOP
	Requests the service to stop.
SERVICE_CONTROL_PAUSE
	Requests the service to pause.
SERVICE_CONTROL_CONTINUE
	Requests the paused service to resume.
SERVICE_CONTROL_INTERROGATE
	Requests the service to immediately update its current status information to the service control manager.
SERVICE_CONTROL_SHUTDOWN
	Requests the service to perform cleanup tasks, because the system is shutting down. Due to the extremely limited time available for shutdown, this control code should be used only by services that must perform a specific cleanup operation that takes a minimal amount of time before the system shuts down. The Event Log and Server services are examples of services that handle SERVICE_CONTROL_SHUTDOWN. The Event Log service needs to clear a dirty bit in the files that it maintains. The Server service needs to shutdown to prevent future network connections to a system that is shut down.
	To respond quickly to the SERVICE_CONTROL_SHUTDOWN code, the service may send a SERVICE_STOP_PENDING message and allow another thread to complete the shutdown operation. Service shutdown is complete when the SERVICE_STOPPED message is sent. The system gives the service control manager a limited amount of time (about 20 seconds) to complete service shutdown, after which time system shutdown proceeds regardless of whether service shutdown is complete. .


Service Configuration Programs

Service configuration programs are used by programmers or system administrators to query or modify a service control manager database. These databases are maintained in the registry, so they can also be accessed by using the registry functions or a registry editor. It is, however, safer to use the service control manager's configuration functions, which ensure that the service is installed and configured properly.

Service control manager databases and services are implemented as objects that should only be accessed through the service control manager's configuration functions. A database of installed services is represented by an SCManager object, and an installed service is represented by a service object. An SCManager object is a container object that holds service objects.

The handle type of both SCManager objects and service objects is SC_HANDLE. The OpenSCManager function returns a handle to an SCManager object on a specified machine. The CreateService and OpenService functions return a handle to a service object installed in a specified SCManager object. The CloseServiceHandle function closes SC_HANDLE to either an SCManager object or a service object.

The functions that return SC_HANDLE can request different types of access to the SCManager or service object. The requested access is granted or denied depending on the access token of the calling process and the security descriptor associated with the SCManager or service object.

A configuration program uses the CreateService function to install a new service in an service control manager database. This function specifies the name of the service and provides the service's configuration information that is stored in the database. For a description of the information stored in the database for each service, see Database of Installed Services.The DeleteService function removes an installed service from its database.

The following functions are available to determine the current configuration of a service control manager database:

Function	Description
QueryServiceConfig
	Fills in a buffer with a QUERY_SERVICE_CONFIG structure, containing the current configuration information for a specified service object.
QueryServiceObjectSecurity
	Fills in a buffer with the SECURITY_DESCRIPTOR structure of a specified SCManager or service object.
EnumDependentServices
	Fills in a buffer with an array of ENUM_SERVICE_STATUS structures, containing the name and current status of all services that are dependent on a specified service object.
EnumServicesStatus
	Fills in a buffer with an array of ENUM_SERVICE_STATUS structures, containing the name and current status of all services in a specified SCManager object.
To modify the configuration information for a service object, a configuration program uses the ChangeServiceConfig function. To modify the security descriptor for either an SCManager object or a service object, a configuration program uses the SetServiceObjectSecurity function.

Before using either of these functions to reconfigure a service object, a program should use the LockServiceDatabase function. This function tries to acquire a lock on the specified service control manager database and, if successful, prevents the service control manager from starting a service while the database is being reconfigured. A lock should also be acquired before using the registry functions to reconfigure a service object. Note, however, that failure to acquire a lock does not prevent a configuration program from successfully reconfiguring a service object. The only effect of a lock is to prevent the service control manager from starting a service in the locked database. To release the lock on the database when the reconfiguration is complete, use the UnlockServiceDatabase function. To determine whether the database is locked, use the QueryServiceLockStatus function.


Service Control Programs

A service control program performs the following actions:

•	Starts a Win32 service or a driver service, if the service's start type is SERVICE_DEMAND_START.

•	Sends control requests to a running service.

•	Queries the current status of a running service.

The program must have an open handle to any service object that it wants to start or control. To do this, it must perform these steps:

1.	Use the OpenSCManager function to open a handle to a service control manager database on a specified machine.

2.	Use the OpenService or CreateService function to open a handle to the desired service object.


Service Startup

To start a service, use the StartService function. For Win32 services, the calling process can use the parameters of this function to specify an array of arguments that are passed to the ServiceMain function of the service. This function fails if the service control manager database is locked. If this occurs, the service control program can wait a few seconds and call StartService again. It can check the current lock status of the database by calling the QueryServiceLockStatus function.

When starting a driver service, StartService returns after the device driver has completed its initialization.

When starting a Win32 service, StartService returns after the ServiceMain function thread for the new service has been created. During its initialization, a service specifies a SERVICE_STATUS structure in calls to the SetServiceStatus function to report its progress to the service control manager. The service control program can retrieve this status information by calling the QueryServiceStatus function. During initialization, the dwCurrentState member of the SERVICE_STATUS structure should be SERVICE_START_PENDING. The service should increment the dwCheckPoint member at regular intervals during initialization. The dwWaitHint member is a time interval, in milliseconds, that indicates how long the service control program should wait before calling QueryServiceStatus again. When the initialization is complete, the service changes the dwCurrentState member to SERVICE_RUNNING.


Service Control Requests

To send control requests to a running service, use the ControlService function. This function specifies a control value that is passed to the Handler function of the specified service. This control value can be a user-defined code, or it can be one of the standard codes that enable the calling program to perform the following actions:

•	Stops or pauses a service.

•	Resumes a paused service.

•	Gets updated status information from a service.

Each service specifies the control values that it will accept and process. To determine which of the standard control values are accepted by a service, use the QueryServiceStatus function or specify the SERVICE_CONTROL_INTERROGATE control value in a call to the ControlService function. The dwControlsAccepted member of the SERVICE_STATUS structure returned by these functions indicates whether the service can be stopped and whether it can be paused and resumed. All services accept the SERVICE_CONTROL_INTERROGATE control value, which requests the service to immediately report its current status.

Note, however, that the QueryServiceStatus function reports the service control manager's most recent status for a specified service, but does not get an updated status from the service itself. Using the SERVICE_CONTROL_INTERROGATE control value in a call to ControlService ensures that the status information returned is current.


Service Security

When a process uses the OpenSCManager function to open a handle to a service control manager database, the system performs a security check before granting the requested access. All processes are permitted SC_MANAGER_CONNECT, SC_MANAGER_ENUMERATE_SERVICE, and SC_MANAGER_QUERY_LOCK_STATUS access to all service control manager databases. This access enables any process to open a service control manager database handle that it can use for the OpenService, EnumServicesStatus, and QueryServiceLockStatus functions. Only processes with Administrator privileges are able to open a database handle that can be used by the CreateService and LockServiceDatabase functions.

Security for service objects is provided by an access check performed when a process uses the OpenService function. The access permitted to different users depends on the SECURITY_DESCRIPTOR structure associated with the service object. The service control manager creates a service object's security descriptor when the service is installed by the CreateService function. You can use the QueryServiceObjectSecurity and SetServiceObjectSecurity functions to query and set the security descriptor of a service object. The default security descriptor of a service object permits the following access:

•	All users have SERVICE_QUERY_CONFIG, SERVICE_QUERY_STATUS, SERVICE_ENUMERATE_DEPENDENTS, SERVICE_INTERROGATE, and SERVICE_USER_DEFINED_CONTROL access.

•	Local users have SERVICE_START access in addition to those listed above.

•	LocalSystem users and PowerUsers have SERVICE_START, SERVICE_PAUSE_CONTINUE, and SERVICE_STOP access in addition to those listed above.

•	Administrators have SERVICE_ALL_ACCESS access.


Win32 Service User Accounts

Each Win32 service runs in a user account. The user name and password of an account are specified by the CreateService function at the time the service is installed. The user name and password can be changed by using the ChangeServiceConfig function. You can use the QueryServiceConfig function to get the user name (but not the password) of a service object.

When starting a service process, the service control manager logs on to the account associated with the service. If the log on is successful, the system produces an access token and attaches it to the new service process. This token identifies the service process in all subsequent interactions with securable objects (objects that have a security descriptor associated with them). For example, if the service tries to open a handle to a pipe, the system compares the service's access token to the pipe's security descriptor before granting access.

A SERVICE_WIN32_OWN_PROCESS service that runs in a process by itself can have an account from either the built-in (local), primary, or trusted domain. A SERVICE_WIN32_SHARE_PROCESS service that can share a process with multiple services must be installed to run in the LocalSystem account. This restriction exists because different services in the same process must run under the same security context.

The service control manager does not try to maintain the passwords of service user accounts. If a password is expired, the logon fails and the service fails to start. The system administrator who assigns accounts to services can create accounts with passwords that never expire. The administrator can also manage accounts with passwords that expire by using a service configuration program to periodically change the passwords.

If a service needs to recognize another service before sharing its information, the second service can either use the same account as the first service, or it can run in an account belonging to an alias that is recognized by the first service. Services that need to run in a distributed manner across the network should run in domain-wide accounts.


Interactive Services

An interactive service is a Win32 service that allows the user's desktop to interact with the service. Interactive services run in the LocalSystem account. Services are configured to be interactive when the dwServiceType parameter in a CreateService call is set to include the SERVICE_INTERACTIVE_PROCESS bit flag. SERVICE_INTERACTIVE_PROCESS may be used only with the SERVICE_WIN32_OWN_PROCESS or SERVICE_WIN32_SHARE_PROCESS flags. This bit flag affects only the service process when it is created (that is, when the first service in the process is started).

The following key in the registry contains a value called NoInteractiveServices that controls the effect of the SERVICE_INTERACTIVE_PROCESS flag:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Windows

The NoInteractiveServices value defaults to 0, which means that services marked with the SERVICE_INTERACTIVE_PROCESS flag will be allowed to be interactive. When the NoInteractiveServices value is set to nonzero, any service started thereafter, regardless of whether it has been configured with SERVICE_INTERACTIVE_PROCESS, will not be allowed to run interactively. Setting NoInteractiveServices to nonzero completely guarantees a secure system.


Using Services

•	Writing a Win32 service process's main function

•	Writing a ServiceMain function

•	Writing a control handler function

•	Opening an SCManager database

•	Installing a service

•	Deleting a service

•	Changing a service configuration

•	Querying a service's configuration

•	Starting a service

•	Sending control requests to a service


Writing a Win32 Service Process's main Function

The main function of a Win32 service process calls the StartServiceCtrlDispatcher function to connect to the service control manager and start the control dispatcher thread. The dispatcher thread loops, waiting for incoming control requests for the services specified in the dispatch table. This thread does not return unless there is an error or all of the services in the process have terminated. When all services in a process have terminated, the service control manager sends a control request to the dispatcher thread telling it to shut down. The thread can then return from the StartServiceCtrlDispatcher call and the process can terminate.

The example provided in this section demonstrates a service process that supports only one service. Service processes with a single service call StartServiceCtrlDispatcher immediately because its entry-point function, ServiceMain, can perform all necessary initialization.

If your service process supports multiple services, the implementation of the main function may differ slightly. The names of the additional services are added to the dispatch table so they can be monitored by the dispatcher thread. Some multiple service processes may need to perform process-wide initialization tasks before starting any of the services with the StartServiceCtrlDispatcher call. If this is the case and the initialization is brief (less than 30 seconds), the main thread can take care of it before calling StartServiceCtrlDispatcher. If this initialization typically lasts longer than 30 seconds, one of the following strategies can be used:

•	Call CreateThread to create a thread to perform the process-wide initialization.

•	Use a global flag that each service checks during its initialization so that the first service to start up performs the tasks that are process-wide.

The following example calls a local function, SvcDebugOut, to print informational messages and errors to the debugger, and a Win32 function, GetLastError, to retrieve a detailed error code when RegisterServiceCtrlHandler fails. SvcDebugOut takes two parameters: a single string that can contain one formatted output character and a numeric value to be used as the formatted character.

/* Globals */

SERVICE_STATUS          MyServiceStatus;

SERVICE_STATUS_HANDLE   MyServiceStatusHandle;

/* Function Prototypes */

VOID  MyServiceStart (DWORD   argc, LPTSTR  *argv);

VOID  MyServiceCtrlHandler (IN  DWORD opcode);

DWORD MyServiceInitialization(DWORD argc, LPTSTR  *argv,
        DWORD  *specificError);

VOID _CRTAPI1 main(void)

{

    SERVICE_TABLE_ENTRY   DispatchTable[] = {

        { TEXT("MyService"),    MyServiceStart      },

        { NULL,                 NULL                }

    };

    if (!StartServiceCtrlDispatcher( DispatchTable)) {

        SvcDebugOut(" [MY_SERVICE] StartServiceCtrlDispatcher error =
                    %d\n", GetLastError());

    }

}

VOID SvcDebugOut(LPSTR String, DWORD Status)

{

    CHAR  Buffer[1024];

    if (strlen(String) < 1000)  {

        sprintf(Buffer, String, Status);

        OutputDebugStringA(Buffer);

    }

}


Writing a ServiceMain Function

The MyServiceStart function in the following example is the service's entry point. When the control dispatcher is told to start a service, it creates a thread that will begin executing at this point. MyServiceStart has access to command-line arguments in the same manner as does the typical main function. The first parameter contains the number of arguments being passed to the service. There will always be at least one argument. The second parameter is a pointer to an array of string pointers. The first item in the array always points to the service name.

MyServiceStart first fills in the SERVICE_STATUS structure including the control codes that it will accept. Note that although this service accepts PAUSE_CONTINUE, it does nothing significant when told to pause. PAUSE_CONTINUE was included for illustration purposes only; if pausing does not add value to your service, do not support it. The dwCheckPoint, dwWaitHint, and the exit code fields are all initialized to zero.

MyServiceStart then calls the RegisterServiceCtrlHandler function to register MyService as the service's Handler function and begin initialization. The following sample initialization function, MyServiceInitialization, is included for illustration purposes; it does not perform any initialization tasks such as creating additional threads. If your service's initialization performs tasks that are expected to take longer than one second, your code must call SetServiceStatus periodically to send out wait hints and check points indicating that progress is being made.

When initialization has completed successfully, a call to SetServiceStatus with a status of SERVICE_RUNNING is made and the service can continue with its work. If an error has occurred in initialization, MyServiceStart reports SERVICE_STOPPED with the SetServiceStatus call and returns.

Since this sample service does not do anything, MyServiceStart simply returns control to the caller. However, a real service should use this thread to do whatever work it was designed to do. The ServiceMain function for a service that does not need a thread to do its work, such as a service that processes only RPC requests, should return control to the caller. It is important to return, rather than call the ExitThread function, because returning allows for cleanup of the memory allocated for the arguments.

To output debugging information, MyServiceStart calls SvcDebugOut. The source code for SvcDebugOut is listed in Writing a Win32 Service Process's main Function.

void MyServiceStart (DWORD   argc, LPTSTR  *argv)

{

    DWORD   status;

    DWORD   specificError;

    MyServiceStatus.dwServiceType        = SERVICE_WIN32;

    MyServiceStatus.dwCurrentState       = SERVICE_START_PENDING;

    MyServiceStatus.dwControlsAccepted   = SERVICE_ACCEPT_STOP |

        SERVICE_ACCEPT_PAUSE_CONTINUE;

    MyServiceStatus.dwWin32ExitCode      = 0;

    MyServiceStatus.dwServiceSpecificExitCode = 0;

    MyServiceStatus.dwCheckPoint         = 0;

    MyServiceStatus.dwWaitHint           = 0;

    MyServiceStatusHandle = RegisterServiceCtrlHandler(

                            TEXT("MyService"),

                            MyServiceCtrlHandler);

    if (MyServiceStatusHandle == (SERVICE_STATUS_HANDLE)0) {

        SvcDebugOut(" [MY_SERVICE] RegisterServiceCtrlHandler
                    failed %d\n", GetLastError());

        return;

    }

    // Initialization code goes here.

    status = MyServiceInitialization(argc,argv, &specificError);

    // Handle error condition

    if (status != NO_ERROR) {

        MyServiceStatus.dwCurrentState       = SERVICE_STOPPED;

        MyServiceStatus.dwCheckPoint         = 0;

        MyServiceStatus.dwWaitHint           = 0;

        MyServiceStatus.dwWin32ExitCode      = status;

        MyServiceStatus.dwServiceSpecificExitCode = specificError;

        SetServiceStatus (MyServiceStatusHandle, &MyServiceStatus);

        return;

    }

    // Initialization complete - report running status

    MyServiceStatus.dwCurrentState       = SERVICE_RUNNING;

    MyServiceStatus.dwCheckPoint         = 0;

    MyServiceStatus.dwWaitHint           = 0;

    if (!SetServiceStatus (MyServiceStatusHandle, &MyServiceStatus)) {

        status = GetLastError();

        SvcDebugOut(" [MY_SERVICE] SetServiceStatus error
            %ld\n",status);

    }

    // This is where the service does its work.     //

    SvcDebugOut(" [MY_SERVICE] Returning the Main Thread \n",0);

    return;

}

/* stub initialization function */

DWORD MyServiceInitialization(DWORD   argc, LPTSTR  *argv,
        DWORD *specificError)

{

    argv;

    argc;

    specificError;

    return(0);

}


Writing a Control Handler Function

The MyServiceCtrlHandler function in the following example is the service's Handler function. When this function is called by the dispatcher thread, it handles the control code passed in the parameter Opcode and then calls the SetServiceStatus function to update the service's status. Every time a Handler function receives a control code, it is appropriate to return status with a call to SetServiceStatus regardless of whether the service operates on the control.

The Handler function executes in the context of the dispatcher thread. Therefore, this function should not perform time-consuming operations. If an operation such as a stop request is going to take a long time, the Handler function should send the SERVICE_STOP_PENDING message in a call to SetServiceStatus and then signal the other service thread(s), if necessary, that a stop operation is in progress. Then the function should return so that the dispatcher can service more requests. One of the other service threads becomes responsible for sending further wait hints and the final SERVICE_STOPPED message.

Note that when the pause control is received, MyServiceCtrlHandler simply sets the dwCurrentState field in the SERVICE_STATUS structure to SERVICE_PAUSED. Likewise, when the continue control is received, the state is set to SERVICE_RUNNING. Note that MyServiceCtrlHandler is not presented as an accurate example of how to handle the pause and continue controls. Since MyServiceCtrlHandler is a template for a Handler function, code for the pause and continue controls is included for completeness. A real service that supports either the pause or continue control should handle these controls in whatever way makes sense for that service. Many services support neither the pause or continue control. If the service indicates that it does not support pause or continue with the dwControlsAccepted parameter, then the service control manager will not send pause or continue controls to the service's Handler function.

When handling the stop request for a service that will take a long time, the current thread should create another thread or ask an existing one to handle the stop process. The current thread should simply call SetServiceStatus with the SERVICE_STOP_PENDING message and return to the caller.

To output debugging information, MyServiceCtrlHandler calls SvcDebugOut. The source code SvcDebugOut is listed in Writing a Win32 Service Process's main Function.

VOID MyServiceCtrlHandler ( IN  DWORD   Opcode)

{

    DWORD   status;

    switch(Opcode) {

    case SERVICE_CONTROL_PAUSE:

        /* Do whatever it takes to pause here.

        MyServiceStatus.dwCurrentState = SERVICE_PAUSED;

        break;

    case SERVICE_CONTROL_CONTINUE:

        /* Do whatever it takes to continue here.

        MyServiceStatus.dwCurrentState = SERVICE_RUNNING;

        break;

    case SERVICE_CONTROL_STOP:

        /* Do whatever it takes to stop here.

        MyServiceStatus.dwWin32ExitCode = 0;

        MyServiceStatus.dwCurrentState  = SERVICE_STOPPED;

        MyServiceStatus.dwCheckPoint    = 0;

        MyServiceStatus.dwWaitHint      = 0;

        if (!SetServiceStatus (MyServiceStatusHandle, &MyServiceStatus))
        {

            status = GetLastError();

            SvcDebugOut(" [MY_SERVICE] SetServiceStatus error
                %ld\n",status);

        }

        SvcDebugOut(" [MY_SERVICE] Leaving MyService \n",0);

        return;

    case SERVICE_CONTROL_INTERROGATE:

        /* fall through to send current status

        break;

    default:

        SvcDebugOut(" [MY_SERVICE] Unrecognized opcode %ld\n", Opcode);

    }

    /* Send current status.

    if (!SetServiceStatus (MyServiceStatusHandle,  &MyServiceStatus)) {

        status = GetLastError();

        SvcDebugOut(" [MY_SERVICE] SetServiceStatus error
            %ld\n",status);

    }

    return;

}


Opening an SCManager Database

The examples in the following sections require an open handle to an SCManager database object. Different operations on a service control manager database require different levels of access, and you should only request the minimum access required. If SC_MANAGER_ALL_ACCESS is requested, the OpenSCManager function fails if the calling process does not have administrator privileges. The following example shows how to request full access to the ServicesActive database on the local machine.

/* Open a handle to the SC Manager database. */

schSCManager = OpenSCManager(

     NULL,                   /* local machine           */

     NULL,                   /* ServicesActive database */

     SC_MANAGER_ALL_ACCESS); /* full access rights      */

if (schSCManager == NULL)

    MyErrorExit("OpenSCManager");


Installing a Service

A service configuration program uses the CreateService function to install a service in a service control manager database. The application-defined schSCManager handle must have SC_MANAGER_CREATE_SERVICE access to the SCManager object. The following example shows how to install a service.

VOID CreateSampleService() {

LPCTSTR lpszBinaryPathName =

          TEXT("%SystemRoot%\\system\\testserv.exe");

  schService = CreateService(

       schSCManager,              /* SCManager database      */

       TEXT("Sample_Srv"),        /* name of service         */

        lpszDisplayName,          /* service name to display */

       SERVICE_ALL_ACCESS,        /* desired access          */

       SERVICE_WIN32_OWN_PROCESS, /* service type            */

       SERVICE_DEMAND_START,      /* start type              */

       SERVICE_ERROR_NORMAL,      /* error control type      */

       lpszBinaryPathName,        /* service's binary        */

       NULL,                      /* no load ordering group  */

       NULL,                      /* no tag identifier       */

       NULL,                      /* no dependencies         */

       NULL,                      /* LocalSystem account     */

       NULL);                     /* no password             */

  if (schService == NULL)

      MyErrorExit("CreateService");

  else

      printf("CreateService SUCCESS\n");

  CloseServiceHandle(schService);

}


Deleting a Service

In the following example, a service configuration program uses the OpenService function to get a handle with DELETE access to an installed service object. The program then uses the service object handle in the DeleteService function to remove the service from the service control manager database.

VOID DeleteSampleService() {

  schService = OpenService(

       schSCManager,       /* SCManager database      */

       TEXT("Sample_Srv"), /* name of service         */

       DELETE);            /* only need DELETE access */

  if (schService == NULL)

      MyErrorExit("OpenService");

  if (! DeleteService(schService) )

      MyErrorExit("DeleteService");

  else

      printf("DeleteService SUCCESS\n");

  CloseServiceHandle(schService);

}


Changing a Service Configuration

In the following example, a service configuration program uses the ChangeServiceConfig function to change the configuration parameters of an installed service. The program first tries to lock the database, to prevent the service control manager from starting a service while it is being reconfigured. If it successfully locks the database, the program opens a handle to the service object, modifies its configuration, unlocks the database, and then closes the service  object handle. If the program does not successfully in lock the database, it uses the QueryServiceLockStatus function to retrieve information about the lock.

VOID ReconfigureSampleService(BOOL fDisable) {

SC_LOCK sclLock;

LPQUERY_SERVICE_LOCK_STATUS lpqslsBuf;

DWORD dwBytesNeeded, dwStartType;

  /* Need to acquire database lock before reconfiguring. */

  sclLock = LockServiceDatabase(schSCManager);

  /* If the database cannot be locked, report the details. */

  if (sclLock == NULL) {

      /* Exit if the database is not locked by another process. */

      if (GetLastError() != ERROR_SERVICE_DATABASE_LOCKED)

          MyErrorExit("LockServiceDatabase");

      /* Allocate a buffer to get details about the lock. */

      lpqslsBuf = (LPQUERY_SERVICE_LOCK_STATUS) LocalAlloc(

          LPTR, sizeof(QUERY_SERVICE_LOCK_STATUS)+256);

      if (lpqslsBuf == NULL)

          MyErrorExit("LocalAlloc");

      /* Get and print the lock status information. */

      if (! QueryServiceLockStatus(

          schSCManager,

          lpqslsBuf,

          sizeof(QUERY_SERVICE_LOCK_STATUS)+256,

          &dwBytesNeeded) )

          MyErrorExit("QueryServiceLockStatus");

      if (lpqslsBuf->fIsLocked)

          printf("Locked by: %s, duration: %d seconds\n",

              lpqslsBuf->lpLockOwner,

              lpqslsBuf->dwLockDuration);

      else

          printf("No longer locked\n");

      LocalFree(lpqslsBuf);

      MyErrorExit("Could not lock database");

  }

  /* The database is locked, so it is safe to make changes. */

  /* Open a handle to the service. */

  schService = OpenService(

       schSCManager,           /* SCManager database */

       TEXT("Sample_Srv"),     /* name of service    */

       SERVICE_CHANGE_CONFIG); /* need CHANGE access */

  if (schService == NULL)

      MyErrorExit("OpenService");

  dwStartType = (fDisable) ? SERVICE_DISABLED :

                             SERVICE_DEMAND_START;

  if (! ChangeServiceConfig(

       schService,        /* handle of service            */

       SERVICE_NO_CHANGE, /* service type: no change      */

       dwStartType,       /* *change* service start type  */

       SERVICE_NO_CHANGE, /* error control: no change     */

       NULL,              /* binary path: no change       */

       NULL,              /* load order group: no change  */

       NULL,              /* tag ID: no change            */

       NULL,              /* dependencies: no change      */

       NULL,              /* account name: no change      */

       NULL) )            /* password: no change          */

      MyErrorExit("ChangeServiceConfig");

  else

      printf("ChangeServiceConfig SUCCESS\n");

  /* Release the database lock. */

  UnlockServiceDatabase(sclLock);

  /* Close the handle to the service. */

  CloseServiceHandle(schService);

}


Querying a Service's Configuration

In the following example, a service configuration program uses the OpenService function to get a handle with SERVICE_QUERY_CONFIG access to an installed service object. Then the program uses the service object handle in the QueryServiceConfig function to retrieve the current configuration of the service.

VOID GetSampleServiceConfig() {

LPQUERY_SERVICE_CONFIG lpqscBuf;

DWORD dwBytesNeeded;

  /* Open a handle to the service. */

  schService = OpenService(

       schSCManager,           /* SCManager database  */

       TEXT("Sample_Srv"),     /* name of service     */

       SERVICE_QUERY_CONFIG);  /* need QUERY access   */

  if (schService == NULL)

      MyErrorExit("OpenService");

  /* Allocate a buffer for the information configuration. */

  lpqscBuf = (LPQUERY_SERVICE_CONFIG) LocalAlloc(

                                       LPTR, 4096);

  if (lpqscBuf == NULL)

      MyErrorExit("LocalAlloc");

  /* Get and print the information configuration. */

  if (! QueryServiceConfig(

      schService,

      lpqscBuf,

      4096,

      &dwBytesNeeded) )

      MyErrorExit("QueryServiceConfig");

  printf("\nSample_Srv configuration: \n");

  printf("  Type: 0x%x\n", lpqscBuf->dwServiceType);

  printf("  Start Type: 0x%x\n", lpqscBuf->dwStartType);

  printf("  Err Control: 0x%x\n", lpqscBuf->dwErrorControl);

  printf("  Binary path: %s\n", lpqscBuf->lpBinaryPathName);

  if (lpqscBuf->lpLoadOrderGroup != NULL)

      printf("  Load order group: %s\n",

                 lpqscBuf->lpLoadOrderGroup);

  if (lpqscBuf->dwTagId != 0)

      printf("  Tag ID: %d\n", lpqscBuf->dwTagId);

  if (lpqscBuf->lpDependencies != NULL)

      printf("  Dependencies: %s\n", lpqscBuf->lpDependencies);

  if (lpqscBuf->lpServiceStartName != NULL)

      printf("  Start Name: %s\n",

                 lpqscBuf->lpServiceStartName);

  LocalFree(lpqscBuf);

}


Starting a Service

To start a service, the following example opens a handle to an installed database and then specifies the handle in a call to the StartService function. StartService can be used to start either a Win32 service or a driver service, but this example assumes that a Win32 service is being started. After starting the service, the program uses the members of the SERVICE_STATUS structure returned by the QueryServiceStatus function to track the progress of the Win32 service.

VOID StartSampleService() {

SERVICE_STATUS ssStatus;

DWORD dwOldCheckPoint;

  schService = OpenService(

       schSCManager,          /* S. C. Manager database */

       TEXT("Sample_Srv"),    /* name of service        */

       SERVICE_ALL_ACCESS);

     //  SERVICE_START |        /* need START access  */

     //  SERVICE_QUERY_CONFIG); /* and QUERY access   */

  if (schService == NULL)

      MyErrorExit("OpenService");

  if (! StartService(schService, /* handle of service   */

            0,                   /* number of arguments */

            NULL) )              /* no arguments        */

      MyErrorExit("StartService");

  else

      printf("Service start pending\n");

  /* Check the status until the service is running. */

  if (! QueryServiceStatus(

      schService,   /* handle of service       */

      &ssStatus) )  /* address of status info  */

      MyErrorExit("QueryServiceStatus");

  while (ssStatus.dwCurrentState != SERVICE_RUNNING) {

      /* Save the current checkpoint. */

      dwOldCheckPoint = ssStatus.dwCheckPoint;

      /* Wait for the specified interval. */

      Sleep(ssStatus.dwWaitHint);

      /* Check the status again. */

      if (! QueryServiceStatus(

              schService,   /* handle of service       */

              &ssStatus) )  /* address of status info  */

          break;

      /* Break if the checkpoint has not been incremented. */

      if (dwOldCheckPoint >= ssStatus.dwCheckPoint)

          break;

  }

  if (ssStatus.dwCurrentState == SERVICE_RUNNING)

      printf("StartService SUCCESS\n");

  else {

      printf("\nService not started: \n");

      printf("  Current State: %d\n",

                   ssStatus.dwCurrentState);

      printf("  Exit Code: %d\n", ssStatus.dwWin32ExitCode);

      printf("  Service Specific Exit Code: %d\n",

                   ssStatus.dwServiceSpecificExitCode);

      printf("  Check Point: %d\n", ssStatus.dwCheckPoint);

      printf("  Wait Hint: %d\n", ssStatus.dwWaitHint);

  }

  CloseServiceHandle(schService);

}


Sending Control Requests to a Service

The following example uses the ControlService function to send a control value to a running service. Different control values require different levels of access to the service object. For example, a service object handle must have SERVICE_STOP access to send the SERVICE_CONTROL_STOP code. When ControlService returns, a SERVICE_STATUS structure contains the latest status information for the service.

VOID ControlSampleService(DWORD fdwControl) {

SERVICE_STATUS ssStatus;

DWORD fdwAccess;

  /* The required service object access depends on the control. */

  switch (fdwControl) {

      case SERVICE_CONTROL_STOP:

          fdwAccess = SERVICE_STOP;

          break;

      case SERVICE_CONTROL_PAUSE:

      case SERVICE_CONTROL_CONTINUE:

          fdwAccess = SERVICE_PAUSE_CONTINUE;

          break;

      case SERVICE_CONTROL_INTERROGATE:

          fdwAccess = SERVICE_INTERROGATE;

          break;

      default:

          fdwAccess = SERVICE_INTERROGATE;

  }

  /* Open a handle to the service. */

  schService = OpenService(

       schSCManager,        /* SCManager database */

       TEXT("Sample_Srv"),  /* name of service    */

       fdwAccess);          /* specify access     */

  if (schService == NULL)

      MyErrorExit("OpenService");

  /* Send a control value to the service. */

  if (! ControlService(

      schService,   /* handle of service       */

      fdwControl,   /* control value to send    */

      &ssStatus) )  /* address of status info  */

      MyErrorExit("ControlService");

  /* Print the service status. */

  printf("\nStatus of Sample_Srv: \n");

  printf("  Service Type: 0x%x\n", ssStatus.dwServiceType);

  printf("  Current State: 0x%x\n", ssStatus.dwCurrentState);

  printf("  Controls Accepted: 0x%x\n",

               ssStatus.dwControlsAccepted);

  printf("  Exit Code: %d\n", ssStatus.dwWin32ExitCode);

  printf("  Service Specific Exit Code: %d\n",

               ssStatus.dwServiceSpecificExitCode);

  printf("  Check Point: %d\n", ssStatus.dwCheckPoint);

  printf("  Wait Hint: %d\n", ssStatus.dwWaitHint);

  return;

}


Service Functions

Following are the Win32 functions used by services and by programs that control or configure services:

ChangeServiceConfig
CloseServiceHandle
ControlService
CreateService
DeleteService
EnumDependentServices
EnumServicesStatus
GetServiceDisplayName
GetServiceKeyName
Handler
LockServiceDatabase
NotifyBootConfigStatus
OpenSCManager
OpenService
QueryServiceConfig
QueryServiceLockStatus
QueryServiceObjectSecurity
QueryServiceStatus
RegisterServiceCtrlHandler
ServiceMain
SetServiceBits
SetServiceObjectSecurity
SetServiceStatus
StartService
StartServiceCtrlDispatcher
UnlockServiceDatabase


String Manipulation

The overview describes the string manipulation functions and explains how to use them in your Win32-based applications.


About String Manipulation

The string manipulation functions give applications developed for the Win32 application programming interface (API) the means to copy, compare, sort, format, and convert character strings as well as the means to determine the character type of each character in a string. All the string manipulation functions support the single-byte, double-byte, and Unicode character sets if these character sets are supported by the operating system on which the application is run.


String Manipulation in Windows

Many Windows functions duplicate or enhance familiar string-manipulation functions from the standard C library. Many of the enhancements enable Windows functions to work with Unicode or extended character sets. For example, the Windows functions in the following table are identical to standard C functions except that the Windows functions are enhanced for use with Unicode.

Windows function	Standard C function
lstrcat	strcat
lstrcmp	strcmp
lstrcmpi	strcmpi
lstrcpy	strcpy
lstrlen	strlen
The strlen standard C function, for example, always returns the number of bytes in a string, but the lstrlen function returns the number of characters, regardless of whether the characters are 1 or 2 bytes wide.

The following Windows functions differ from standard C functions such as tolower and toupper in that they operate on any character in a character set. By using the CharLower function, for example, a Windows-based application can convert an uppercase U with an umlaut (Ü) to lowercase (ü). For more information about character sets, see Single-byte Character Sets.

Function	Description
CharLower	Converts a character or string to lowercase.
CharLowerBuff	Converts a character string to lowercase.
CharNext	Moves to the next character in a string.
CharPrev	Moves to the preceding character in a string.
CharUpper	Converts a character or string to uppercase.
CharUpperBuff	Converts a string to uppercase.
The following Windows functions make determinations about a character based on the semantics of the language selected by the user. These functions are Unicode enabled.

Function	Description
IsCharAlpha	Determines whether a character is alphabetic.
IsCharAlphaNumeric	Determines whether a character is alphanumeric.
IsCharLower	Determines whether a character is lowercase.
IsCharUpper	Determines whether a character is uppercase.
The wsprintf and wvsprintf functions are extensions to the standard C functions sprintf and vsprintf. The Windows versions support format specifications unique to Unicode.


String Resources

An application that maintains character strings in resources can be translated into new languages with minimum effort. Instead of searching for strings in the source modules, a developer can simply translate the strings in the resource file and relink the application. In addition, using string resources simplifies creation of Unicode and non-Unicode versions of the application from the same source files.

The LoadString function loads a string resource from an application's executable file. The FormatMessage function loads a string resource and interprets formatting options that may be embedded in the string.

Windows 32-bit resources in binary form are stored in Unicode format. When loading resources, applications can use the Unicode version of the resource functions (LoadStringW, for example) to obtain resources as Unicode data.


Obsolete Functions

The AnsiLower function is obsolete. Win32-based applications should use the CharLower function.

The AnsiLowerBuff function is obsolete. Win32-based applications should use the CharLowerBuff function.

The AnsiNext function is obsolete. Win32-based applications should use the CharNext function.

The AnsiPrev function is obsolete. Win32-based applications should use the CharPrev function.

The AnsiUpper function is obsolete. Win32-based applications should use the CharUpper function.

The AnsiUpperBuff function is obsolete. Win32-based applications should use the CharUpperBuff function.

OemToAnsi
OemToAnsiBuff


String Manipulation Reference

This section provides detailed reference information for the string manipulation functions, structures, and messages.


String Manipulation Functions

Following are the functions used with string manipulation.

CharLower
CharLowerBuff
CharNext
CharPrev
CharToOem
CharToOemBuff
CharUpper
CharUpperBuff
CompareString
ConvertDefaultLocale
EnumCalendarInfo
EnumCalendarInfoProc
EnumCodePagesProc
EnumDateFormats
EnumDateFormatsProc
EnumLocalesProc
EnumSystemCodePages
EnumSystemLocales
EnumTimeFormats
EnumTimeFormatsProc
FoldString
FormatMessage
GetACP
GetCPInfo
GetCurrencyFormat
GetDateFormat
GetNumberFormat
GetLocaleInfo
GetOEMCP
GetStringTypeA
GetStringTypeEx
GetStringTypeW
GetSystemDefaultLangID
GetSystemDefaultLCID
GetThreadLocale
GetTimeFormat
GetUserDefaultLangID
GetUserDefaultLCID
IsCharAlpha
IsCharAlphaNumeric
IsCharLower
IsCharUpper
IsDBCSLeadByte
IsTextUnicode
IsValidCodePage
IsValidLocale
LCMapString
LoadString
lstrcat
lstrcmp
lstrcmpi
lstrcpy
lstrcpyn
lstrlen
MultiByteToWideChar
OemToChar
OemToCharBuff
SetLocaleInfo
SetThreadLocale
WideCharToMultiByte
wsprintf
wvsprintf


String Manipulation Constants

This section describes the constants used with the string manipulation functions.


Character Type Information Values

The character-type bits are divided into several levels. The information for one level can be retrieved by a single call to this function. Each level is limited to 16 bits of information so that the other mapping routines limited to 16 bits of representation per character can return character-type information.

The character types supported by this function include the following.

Ctype 1: These types support ANSI C and POSIX (LC_CTYPE) character-typing functions. A combination of these values is returned in the array pointed to by the lpCharType parameter when the fdwInfoType parameter is set to CT_CTYPE1.

Name	Value	Meaning
C1_UPPER	0x0001	Uppercase
C1_LOWER	0x0002	Lowercase
C1_DIGIT	0x0004	Decimal digits
C1_SPACE	0x0008	Space characters
C1_PUNCT	0x0010	Punctuation
C1_CNTRL	0x0020	Control characters
C1_BLANK	0x0040	Blank characters
C1_XDIGIT	0x0080	Hexadecimal digits
C1_ALPHA	0x0100	Any letter
The following character types are either constant or computable from basic types and do not need to be supported by this function.

Type	Description
Alphanumeric	Alphabetic characters and digits
Printable	Graphic characters and blank
Ctype 2: These types support proper layout of Unicode™ text. The direction attributes are assigned so that the bidirectional layout algorithm standardized by Unicode produces accurate results. These types are mutually exclusive. For more information about the use of these attributes, see The Unicode Standard: Worldwide Character Encoding, Volumes 1 and 2, Addison Wesley Publishing Company: 1991, 1992, ISBN 0201567881.

Name	Value	Meaning
Strong:
C2_LEFTTORIGHT	0x1	Left to right
C2_RIGHTTOLEFT	0x2	Right to left
Weak:
C2_EUROPENUMBER	0x3	European number, European digit
C2_EUROPESEPARATOR	0x4	European numeric separator
C2_EUROPETERMINATOR	0x5	European numeric terminator
C2_ARABICNUMBER	0x6	Arabic number
C2_COMMONSEPARATOR	0x7	Common numeric separator
Neutral:
C2_BLOCKSEPARATOR	0x8	Block separator
C2_SEGMENTSEPARATOR	0x9	Segment separator
C2_WHITESPACE	0xA	White space
C2_OTHERNEUTRAL	0xB	Other neutrals
Not applicable:
C2_NOTAPPLICABLE	0x0	No implicit directionality (for example, control codes)
Ctype 3: These types are intended to be placeholders for extensions to the POSIX types required for general text processing or for the standard C library functions. These types are supported in the current version of Microsoft® Windows NT™. A combination of these values is returned when fdwInfoType is set to CT_CTYPE3.

Name	Value	Meaning
C3_NONSPACING	0x1	Nonspacing mark
C3_DIACRITIC	0x2	Diacritic nonspacing mark
C3_VOWELMARK	0x4	Vowel nonspacing mark
C3_SYMBOL	0x8	Symbol
C3_KATAKANA	0x10	Katakana character
C3_HIRAGANA	0x20	Hiragana character
C3_HALFWIDTH	0x40	Half Width character
C3_FULLWIDTH	0x80	Full Width character
C3_IDEOGRAPH	0x100	Ideographic character
C3_KASHIDA	0x200	Arabic Kashida character
C3_ALPHA	0x8000	All linguistic characters (alphabetic, syllabary and ideographic)
Not applicable:
C3_NOTAPPLICABLE	0x0	Not applicable


Format Specifications

%[-][#][0][width][.precision]type

Format specifications always begin with a percent sign (%). Each field is a single character or a number signifying a particular format option. The simplest format specification contains only the percent sign and a type character (for example, %s). The optional fields control other aspects of the formatting.

%

Required. Marks the beginning of the format specification. If the percent sign is followed by a character that has no meaning as a format field, the character is not formatted (for example, %% produces a single percent-sign character).

−

Optional. Pads the output with blanks or zeros to the right to fill the field width, justifying output to the left. If this field is omitted, the output is padded to the left, justifying it to the right.

#

Optional. Prefix hexadecimal values with 0x (lowercase) or 0X (uppercase).

0

Optional. Pad the output value with zeros to fill the field width. If this field is omitted, the output value is padded with blank spaces.

width

Optional. Copy the specified minimum number of characters to the output buffer. The width field is a nonnegative integer. The width specification never causes a value to be truncated; if the number of characters in the output value is greater than the specified width, or if the width field is not present, all characters of the value are printed, subject to the precision specification.

.precision

Optional. For numbers, copy the specified minimum number of digits to the output buffer. If the number of digits in the argument is less than the specified precision, the output value is padded on the left with zeros. The value is not truncated when the number of digits exceeds the specified precision. If the specified precision is 0 or omitted entirely, or if the period (.) appears without a number following it, the precision is set to 1.

For strings, copy the specified maximum number of characters to the output buffer.

type

Required. Determines whether the associated argument is interpreted as a character, a string, or a number. Can be one of these character sequences:

c	A single character. The functions ignore character arguments with a numeric value of zero. This sequence is interpreted as type WCHAR when the calling application uses the #define UNICODE compile flag and as type CHAR otherwise.
C	A single character. This sequence is interpreted as type CHAR when the calling application uses the #define UNICODE compile flag and as type WCHAR otherwise.
d	A signed decimal integer argument. This sequence is equivalent to the i sequence.
hc, hC	A single character. The functions ignore character arguments with a numeric value of zero. This sequence is always interpreted as type CHAR, even when the calling application uses the #define UNICODE compile flag.
hs, hS	A string. This sequence is always interpreted as type LPSTR, even when the calling application uses the #define UNICODE compile flag.
i	A signed decimal integer. This sequence is equivalent to the d sequence.
lc, lC	A single character. The functions ignore character arguments with a numeric value of zero. This sequence is always interpreted as type WCHAR, even when the calling application does not use the #define UNICODE compile flag.
ld	A long signed decimal integer. This sequence is equivalent to the li sequence.
li	A long signed decimal integer. This sequence is equivalent to the ld sequence.
ls, lS	A string. This sequence is always interpreted as type LPWSTR, even when the calling application does not use the #define UNICODE compile flag. This sequence is equivalent to the ws sequence.
lu	A long unsigned integer.
lx, lX	A long unsigned hexadecimal integer in lowercase or uppercase.
s	A string. This sequence is interpreted as type LPWSTR when the calling application uses the #define UNICODE compile flag and as type LPSTR otherwise.
S	A string. This sequence is interpreted as type LPSTR when the calling application uses the #define UNICODE compile flag and as type LPWSTR otherwise.
u	An unsigned integer argument.
x, X	An unsigned hexadecimal integer in lowercase or uppercase.


Structured Exception Handling

An exception is an event that occurs during the execution of a program, and that requires the execution of software outside the normal flow of control. Hardware exceptions can result from the execution of certain instruction sequences, such as division by zero or an attempt to access an invalid memory address. A software routine can also initiate an exception explicitly.

The Microsoft® Win32® application programming interface (API) supports structured exception handling, a mechanism for handling hardware- and software-generated exceptions.


About Structured Exception Handling

Structured exception handling gives developers complete control over the handling of exceptions, provides support for debuggers, and is usable across all programming languages and machines.

The Win32 API also supports termination handling, which enables developers to ensure that whenever a guarded body of code is executed, a specified block of termination code is also executed. The termination code is executed regardless of how the flow of control leaves the guarded body. For example, a termination handler can guarantee that clean-up tasks are performed even if an exception or some other error occurs while the guarded body of code is being executed.

Structured exception and termination handling is an integral part of the Win32 API; it enables a robust implementation of the system software. Developers can use these mechanisms to create consistently robust and reliable applications.

Structured exception handling is made available to developers primarily through compiler support. For example, the Microsoft compilers provided with the Win32 software development kit support the try keyword that identifies a guarded body of code, and the except and finally keywords that identify an exception handler and a termination handler, respectively. Although this topic uses examples from the support available in Microsoft compilers, other compiler vendors can provide this support as well.


Exception Handling

Exceptions can be initiated by hardware or software, and can occur in kernel-mode as well as user-mode code. Win32-based structured exception handling provides a single mechanism for the handling of kernel-mode and user-mode exceptions, both hardware- and software-generated.

The execution of certain instruction sequences can result in exceptions that are initiated by hardware. For example, an access violation is generated by the hardware when a process attempts to read from or write to a virtual address to which it does not have the appropriate access.

Events that require exception handling may also occur during execution of a software routine (for example, when an invalid parameter value is specified). When this happens, a thread can initiate an exception explicitly by calling the RaiseException function. This function enables the calling thread to specify information that describes the exception.


Exception Dispatching

When a hardware or software exception occurs, the processor stops execution at the point at which the exception occurred and transfers control to the system. First, the system saves both the machine state of the current thread and information that describes the exception. The system then attempts to find an exception handler to handle the exception.

The machine state of the thread in which the exception occurred is saved in a CONTEXT structure. This information (called the context record) enables the system to continue execution at the point of the exception if the exception is successfully handled. The description of the exception (called the exception record) is saved in an EXCEPTION_RECORD structure. Because it stores the machine-dependent information of the context record separately from the machine-independent information of the exception record, the exception-handling mechanism is portable to different platforms. The information in both the context and exception records is available by means of the GetExceptionInformation function, and can be made available to any exception handlers that are executed as a result of the exception. The exception record includes the following information.

•	An exception code that identifies the type of exception.

•	Flags indicating whether the exception is continuable. Any attempt to continue execution after a noncontinuable exception generates another exception.

•	A pointer to another exception record. This facilitates creation of a linked list of exceptions if nested exceptions occur.

•	The address at which the exception occurred.

•	An array of 32-bit arguments that provide additional information about the exception.

When an exception occurs in user-mode code, the system goes through the following search for an exception handler:

1.	The system first attempts to notify the process's debugger, if any.

2.	If the process is not being debugged, or if the associated debugger does not handle the exception, the system attempts to locate a frame-based exception handler by searching the stack frames of the thread in which the exception occurred. The system searches the current stack frame first, then proceeds backward through preceding stack frames.

3.	If no frame-based handler can be found, or no frame-based handler handles the exception, the system makes a second attempt to notify the process's debugger.

4.	If the process is not being debugged, or if the associated debugger does not handle the exception, the system provides default handling based on the exception type. For most exceptions, the default action is to call the ExitProcess function.

When an exception occurs in kernel-mode code, the system searches the stack frames of the kernel stack in an attempt to locate an exception handler. If a handler cannot be located or no handler handles the exception, the system is shut down as if the ExitWindows function had been called.


Debugger Support

The system's handling of user-mode exceptions provides support for sophisticated debuggers. If the process in which an exception occurs is being debugged, the system generates a debug event. If the debugger is using the WaitForDebugEvent function, the debug event causes that function to return with a pointer to a DEBUG_EVENT structure. This structure contains the process and thread identifiers that the debugger can use to access the thread's context record. The structure also contains an EXCEPTION_DEBUG_INFO structure that includes a copy of the exception record.

The system's search for an exception handler includes two attempts to notify a process's debugger. The first notification attempt provides the debugger with an opportunity to handle breakpoint or single-step exceptions. The user can then issue debugger commands to manipulate the process's environment before any exception handlers are executed. The second attempt to notify the debugger occurs only if the system is unable to find a frame-based exception handler that handles the exception.

At each notification attempt, the debugger uses the ContinueDebugEvent function to return control to the system. Before returning control, the debugger can handle the exception and modify the thread state as appropriate, or it can choose not to handle the exception. Using ContinueDebugEvent, the debugger can indicate that it has handled the exception, in which case the machine state is restored and thread execution is continued at the point at which the exception occurred. The debugger can also indicate that it did not handle the exception, which causes the system to continue its search for an exception handler.


Frame-based Exception Handling

A frame-based exception handler is a mechanism by which a developer deals with the possibility that an exception may occur in a certain sequence of code. A frame-based exception handler consists of the following elements.

•	A guarded body of code

•	A filter expression

•	An exception-handler block

Frame-based exception handlers are declared in language-specific syntax. For example, in the Microsoft® C Optimizing Compiler, they are implemented by the try-except statement. For more information about the Microsoft C exception-handling syntax, see Syntax.

The guarded body of code is a set of one or more statements for which the filter expression and the exception-handler block provide exception-handling protection. The guarded body can be a block of code, a set of nested blocks, or an entire procedure or function. In Microsoft C, a guarded body is enclosed by braces ({}) following the try keyword.

The filter expression of a frame-based exception handler is an expression that is evaluated by the system when an exception occurs within the guarded body. This evaluation results in one of the following actions by the system.

•	The system stops its search for an exception handler, restores the machine state, and continues thread execution at the point at which the exception occurred.

•	The system continues its search for an exception handler.

•	The system transfers control to the exception handler, and thread execution continues sequentially in the stack frame in which the exception handler is found. If the handler is not in the stack frame in which the exception occurred, the system unwinds the stack, leaving the current stack frame and any other stack frames until it is back to the exception handler's stack frame. Before an exception handler is executed, termination handlers are executed for any guarded bodies of code that terminated as a result of the transfer of control to the exception handler. For more information about termination handlers, refer to Termination Handling.

The filter expression can be a simple expression, or it can invoke a filter function that attempts to handle the exception. You can call the GetExceptionCode and GetExceptionInformation functions from within a filter expression to get information about the exception being filtered. GetExceptionCode returns a code that identifies the type of exception, and GetExceptionInformation returns a pointer to an EXCEPTION_POINTERS structure that contains pointers to CONTEXT and EXCEPTION_RECORD structures.

These functions cannot be called from within a filter function, but their return values can be passed as parameters to a filter function. GetExceptionCode can be used within the exception-handler block, but GetExceptionInformation cannot because the information it points to is typically on the stack and is destroyed when control is transferred to an exception handler. However, an application can copy the information to safe storage to make it available to the exception handler.

The advantage of a filter function is that it can handle an exception and return a value that causes the system to continue execution from the point at which the exception occurred. With an exception-handler block, in contrast, execution continues sequentially from the exception handler rather than from the point of the exception.

Handling an exception may be as simple as noting an error and setting a flag that will be examined later, printing a warning or error message, or taking some other limited action. If execution can be continued, it may also be necessary to change the machine state by modifying the context record. For an example of a filter function that handles a page fault exception, see Memory Management.

The UnhandledExceptionFilter function can be used as a filter function in a filter expression. It returns EXCEPTION_EXECUTE_HANDLER unless the process is being debugged, in which case it returns EXCEPTION_CONTINUE_SEARCH.


Termination Handling

A termination handler is a mechanism by which a developer ensures that a specific block of code is executed whenever flow of control leaves a particular guarded body of code. A termination handler consists of the following elements.

•	A guarded body of code

•	A block of termination code to be executed when the flow of control leaves the guarded body

Termination handlers are declared in language-specific syntax. In Microsoft C, they are implemented by the try-finally statement. For more information about the Microsoft C exception-handling syntax, see Syntax.

The guarded body of code can be a block of code, a set of nested blocks, or an entire procedure or function. Whenever the guarded body is executed, the block of termination code will be executed. The only exception to this is when the thread terminates during execution of the guarded body (for example, if the ExitThread or ExitProcess function is called from within the guarded body).

The termination block is executed when the flow of control leaves the guarded body, regardless of whether the guarded body terminated normally or abnormally. The guarded body is considered to have terminated normally when the last statement in the block is executed and control proceeds sequentially into the termination block. Abnormal termination occurs when the flow of control leaves the guarded body due to an exception, or due to a control statement such as return, goto, break, or continue. The AbnormalTermination function can be called from within the termination block to determine whether the guarded body terminated normally.


Syntax

This section describes the syntax and usage of structured exception handling as implemented in Microsoft C. The following keywords are interpreted by the Microsoft C compiler as part of the structured exception-handling mechanism.

Keyword	Description
try	Begins a guarded body of code. Used with the except keyword to construct an exception handler, or with the finally keyword to construct a termination handler.
except	Begins a block of code that is executed only when an exception occurs within its associated try block.
finally	Begins a block of code that is executed whenever the flow of control leaves its associated try block.
The compiler also interprets the GetExceptionCode, GetExceptionInformation, and AbnormalTermination functions as keywords, and their use outside the appropriate exception-handling syntax generates a compiler error. Following are brief descriptions of these functions.

Function	Description
GetExceptionCode	Returns a code that identifies the type of exception. This function can be called only from within the filter expression or exception-handler block of a try-except exception handler.
GetExceptionInformation	Returns a pointer to an EXCEPTION_POINTERS structure containing pointers to the context record and the exception record. This function can be called only from within the filter expression of a try-except exception handler.
AbnormalTermination	Indicates whether the flow of control left the associated try block sequentially after executing the last statement in the block. This function can be called only from within the finally block of a try-finally termination handler.


Exception-Handler Syntax

The try and except keywords are used to construct a frame-based exception handler. The following example shows the structure of a try-except exception handler.

try {

    // guarded body of code

}

except (filter-expression) {

    // exception-handler block

}

Note that the try block and the exception-handler block require braces ({}). Using a goto statement to jump into the body of a try block or into an exception-handler block is not permitted. This rule applies to both try-except and try-finally statements.

The try block contains the guarded body of code that the exception handler protects. A function can have any number of try-except statements, and these exception-handling statements can be nested within the same function or in different functions. If an exception occurs within the try block, the system takes control and begins the search for an exception handler. For a detailed description of this search, see Exception Handling.

The exception handler receives only exceptions that occur within a single thread. This means that if a try block contains a call to the CreateProcess or CreateThread function, exceptions that occur within the new process or thread are not dispatched to this handler.

The system evaluates the filter expression of each exception handler guarding the code in which the exception occurred until either the exception is handled or there are no more handlers. A filter expression must be evaluated as one of the three following values.

Value	Meaning
EXCEPTION_EXECUTE_HANDLER
	The system transfers control to the exception handler, and execution continues in the stack frame in which the handler is found.
EXCEPTION_CONTINUE_SEARCH
	The system continues to search for a handler.
EXCEPTION_CONTINUE_EXECUTION
	The system stops its search for a handler and returns control to the point at which the exception occurred. If the exception is noncontinuable, this results in a EXCEPTION_NONCONTINUABLE_EXCEPTION exception.
The filter expression is evaluated in the context of the function in which the try-except statement is located, even though the exception may have occurred in a different function. This means that the filter expression can access the function's local variables. Similarly, the exception-handler block can access the local variables of the function in which it is located.

For more information about filter expressions and filter functions, see Frame-based Exception Handling.


Termination-Handler Syntax

The try and finally keywords are used to construct a termination handler. The following example shows the structure of a try-finally termination handler.

try {

    // guarded body of code

}

finally {

    // finally block

}

As with the try-except statement, both the try block and the finally block require braces ({}), and using a goto statement to jump into either block is not permitted.

The try block contains the guarded body of code that is protected by the termination handler. A function can have any number of try-finally statements, and these termination handling structures can be nested within the same function or in different functions.

The finally block is executed whenever the flow of control leaves the try block. However, the finally block is not executed if either the ExitProcess or ExitThread function is called from within the try block.

If execution of the try block terminates because of an exception that invokes the exception-handling block of a frame-based exception handler, the finally block is executed before the exception-handling block is executed. Similarly, a call to the standard C longjmp function from the try block causes execution of the finally block before execution resumes at the target of the longjmp operation. If try block execution terminates due to a normal control statement (return, break, continue, or goto), the finally block is executed.

The AbnormalTermination function can be used within the finally block to determine whether the try block terminated sequentially — that is, whether it reached the closing brace (}). Leaving the try block because of a call to longjmp, a jump to an exception handler, or a return, break, continue, or goto statement, is considered an abnormal termination. Note that failure to terminate sequentially causes the system to search backward through all stack frames to determine whether any termination handlers must be called. This can result in performance degradation due to the execution of hundreds of instructions.

Execution of the finally block can terminate by any of the following means.

•	Execution of the last statement in the block and continuation to the next instruction

•	Use of a normal control statement (return, break, continue, or goto)

•	Use of longjmp or a jump to an exception handler

The finally block is executed in the context of the function in which the try-finally statement is located. This means that the finally block can access that function's local variables.


Using Structured Exception Handling

•	Using an Exception Handler

•	Using a Termination Handler


Using an Exception Handler

The following example shows a version of the standard C strcpy function that can handle an invalid pointer and return NULL if one is encountered.

Note that this exception handler is intended to handle an access-violation exception, but is inappropriate if some other type of exception occurs. Therefore, the filter expression in the example uses the GetExceptionCode function to check the exception type before executing the handler. This enables the system to continue its search for an appropriate handler if some other type of exception occurs.

Note also that there is no problem with using a return statement in the try block of a try-except statement. This differs from the use of return in the try block of a try-finally statement, which causes an abnormal termination of the try block.

LPTSTR SafeStrcpy(LPTSTR lpszString1, LPTSTR lpszString2) {

    try {

        return strcpy(string1, string2);

    }

    except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?

                EXCEPTION_EXECUTE_HANDLER :

                EXCEPTION_CONTINUE_SEARCH ) {

        return NULL;

    }

}

The following example shows the interaction of nested try-finally and try-except statements. The RaiseException function causes an exception in the guarded body of a try-finally termination handler that is inside the guarded body of a try-except exception handler. The exception causes the system to evaluate the FilterFunction function, whose return value in turn causes the exception handler to be invoked. However, before the exception-handler block is executed, the finally block of the termination handler is executed because the flow of control has left the try block of the termination handler.

DWORD FilterFunction() {

    printf("1 ");                     // printed first

    return EXCEPTION_EXECUTE_HANDLER;

}

VOID main(VOID) {

    try {

        try {

            RaiseException(1,         // exception code

                0,                    // continuable exception

                0, NULL);             // no arguments

        }

        finally {

            printf("2 ")              // this is printed second

        }

    }

    except ( FilterFunction() ) {

        printf("3\n");                // this is printed last

    }

}


Using a Termination Handler

The following example shows how a try-finally statement is used to ensure that resources are released when execution of a guarded body of code terminates. In this case, a thread uses the EnterCriticalSection function to wait for ownership of a critical section object. When the thread is finished executing the code that is protected by the critical section, it must call the LeaveCriticalSection function to make the critical section object available to other threads. Using a try-finally statement guarantees that this will happen.

For more information about critical section objects, see Synchronization.

LPTSTR lpBuffer = NULL;

CRITICAL_SECTION csCriticalSection;

try {

     // EnterCriticalSection synchronizes code

     // with other threads.

    EnterCriticalSection(&CriticalSection);

    // Perform a task that may cause an exception.

    lpBuffer = (LPTSTR) LocalAlloc(LPTR, 10);

    strcpy(lpBuffer,"Hello");  // possible access violation

    printf("%s\n",lpBuffer);

    LocalFree(lpBuffer);

}

 // LeaveCriticalSection is called even if

 // an exception occurred.

finally {

    LeaveCriticalSection(&CriticalSection);

}


Structured Exception Handling Functions

Following are the functions used in structured exception handling.

AbnormalTermination
GetExceptionCode
GetExceptionInformation
RaiseException
SetUnhandledExceptionFilter
UnhandledExceptionFilter

Obsolete or Deleted Functions

Catch
Throw


Synchronization

The Microsoft® Win32® application programming interface (API) provides a variety of ways to coordinate multiple threads of execution.


About Synchronization

The functions described in this overview provide synchronization mechanisms, such as wait functions and synchronization objects, and overlapped input and output (I/O) operations. The synchronization mechanisms also include critical section objects and interlocked variable access


Wait Functions

The Win32 API provides a set of wait functions that enable a thread to block its own execution. These functions do not return until a set of conditions specified by the wait function's parameters have been satisfied. These parameters include a time-out interval and handles of one or more synchronization objects. For more information about synchronization objects, see Synchronization Objects Overview.

When a wait function is called, it checks the state of the specified synchronization object (or objects) and any other conditions that could cause it to return. If this initial state does not satisfy the specified conditions and the time-out interval has not elapsed, the calling thread enters an efficient wait state, consuming very little processor time while waiting for the conditions to be satisfied. The time-out interval can be set to INFINITE to cause an indefinite wait.

The WaitForSingleObject and WaitForSingleObjectEx functions require a handle of one synchronization object. These functions return when the state of the object is signaled, or when the time-out interval elapses. (The state of a synchronization object is either signaled or nonsignaled.)

The WaitForMultipleObjects, WaitForMultipleObjectsEx, and MsgWaitForMultipleObjects functions enable the calling thread to specify an array containing one or more synchronization object handles. These functions can be set to return when the state of any one of the specified objects is signaled, in which case the return value indicates the array index of the object that caused the function to return. Alternatively, the functions can be set to return only when the state of all objects is signaled at the same time, in which case the return value simply indicates that the specified conditions were satisfied.

When waiting for all objects to be signaled, these multiple-object functions do not modify the state of the specified objects until all objects are signaled simultaneously. For example, a mutex can be signaled, but the calling thread does not get ownership of it until the other objects are also signaled. In the meantime, some other thread may get ownership of the mutex, thereby delaying satisfaction of all specified conditions.

The WaitForSingleObjectEx and WaitForMultipleObjectsEx functions differ from the other wait functions in that they can optionally perform an alertable wait. In an alertable wait, the function can return when the specified conditions are satisfied, but it can also return if the system queues a completion routine for execution by the waiting thread. For more information about alertable waits and I/O completion routines, see Synchronization and Overlapped Input and Output.

The MsgWaitForMultipleObjects function is identical to WaitForMultipleObjects, except that it can also return when a specified type of input is available in the calling thread's input queue. For example, a thread could use MsgWaitForMultipleObjects to block its execution until either the state of a specified object is signaled, or there is mouse input available in the thread's input queue. When input is available, the thread can use the GetMessage or PeekMessage function to retrieve it.

Before returning, a wait function modifies the state of some types of synchronization objects. Modification occurs only for the object or objects whose signaled state caused the function to return. A wait function can modify the state of synchronization objects as follows:

•	The count of a semaphore object decreases by one, with the semaphore's state changing to nonsignaled if its count is zero.

•	The state of mutex, auto-reset event, and change notification objects changes to nonsignaled.

•	The state of manual-reset event, process, thread, and console input objects is not affected by a wait function.


Synchronization Objects Overview

A synchronization object is an object whose handle can be specified in one of the wait functions to coordinate the execution of multiple threads. The state of a synchronization object is either signaled, which can allow the wait function to return, or nonsignaled, which can prevent the function from returning. More than one process can have a handle of the same synchronization object, making interprocess synchronization possible.

The Win32 API provides the following three object types intended exclusively for synchronization.

Type	Description
Event	Notifies one or more waiting threads that an event has occurred.
Mutex	Can be owned by only one thread at a time, enabling threads to coordinate mutually exclusive access to a shared resource.
Semaphore	Maintains a count between zero and some maximum value, limiting the number of threads that are simultaneously accessing a shared resource.
Though available for other uses, the following objects can also be used for synchronization.

Object	Description
Change notification	Created by the FindFirstChangeNotification function, its state is signaled when a specified type of change occurs within a specified directory or directory tree. For more information, see Files.
Console input	Created when a console is created, when a handle to console input is returned by the CreateFile function when CONIN$ is specified, or by the GetStdHandle function. Its state is signaled when there is unread input in the console's input buffer, and nonsignaled when the input buffer is empty. For more information about consoles, see Consoles and Character-Mode Support.
Process	Created when a new process is created by calling the CreateProcess function, its state is nonsignaled while the process is running, and signaled when the process terminates. For more information about processes, see Processes and Threads.
Thread	Created when a new thread is created by calling the CreateProcess, CreateThread, or CreateRemoteThread function, its state is nonsignaled while the thread is running, and signaled when the thread terminates. For more information about threads, see Processes and Threads.
In some circumstances, you can also use a file, named pipe, or communications device as a synchronization object; however, their use for this purpose is discouraged. For additional information about I/O operations on files, named pipes, or communications, see Synchronization and Overlapped Input and Output.


Mutex Objects Overview

A mutex object is a synchronization object whose state is signaled when it is not owned by any thread, and nonsignaled when it is owned. Only one thread at a time can own a mutex, whose name comes from the fact that it is useful in coordinating mutually exclusive access to a shared resource. For example, to prevent two threads from writing to shared memory at the same time, each thread waits for ownership of a mutex before executing the code that accesses the memory. After writing to the shared memory, the thread releases the mutex.

A thread uses the CreateMutex function to create a mutex object. The creating thread can request immediate ownership of the mutex and can also specify a name for the mutex object. Threads in other processes can open a handle of an existing mutex object by specifying its name in a call to the OpenMutex function. For additional information about names for mutex, event, and semaphore objects, see Interprocess Synchronization.

Any thread with a handle of a mutex object can use one of the wait functions to request ownership of the mutex. If the mutex is owned by another thread, the wait function blocks the execution of the requesting thread until the owning thread releases the mutex using the ReleaseMutex function. The return value of the wait function indicates whether the function returned for some reason other than the state of the mutex being signaled.

Once a thread owns a mutex, it can specify the same mutex in repeated wait-function calls without blocking its execution. This prevents a thread from deadlocking itself while waiting for a mutex that it already owns. To release its ownership under such circumstances, the thread must call ReleaseMutex once for each time that the mutex satisfied the conditions of a wait function.

If a thread terminates without releasing its ownership of a mutex object, the mutex is considered to be abandoned. A waiting thread can acquire ownership of an abandoned mutex, but the wait function's return value indicates that the mutex is abandoned. It is best to assume that an abandoned mutex indicates that an error has occurred and that any shared resource being protected by the mutex is in an undefined state. If the thread proceeds normally, as though the mutex had not been abandoned, the mutex's abandoned flag is cleared when the thread releases its ownership. This restores normal mutex behavior if the mutex is subsequently specified in a wait function.


Semaphore Objects Overview

A semaphore object is a synchronization object that maintains a count between zero and a specified maximum value. A semaphore's state is signaled when its count is greater than zero, and nonsignaled when its count is zero.

The semaphore object is useful in controlling a shared resource that can support a limited number of users. It acts like a gate that counts the threads as they enter and exit a controlled area and limits the number of threads sharing the resource to a specified maximum number. For example, an application might want to place a limit on the number of windows that it creates. It uses a semaphore with a maximum count equal to the window limit, decrementing the count whenever a window is created and incrementing it whenever a window is closed. The application specifies the semaphore object in a wait function before each window is created. When the count is zero — indicating that the window limit has been reached — the wait function blocks execution of the window-creation code.

A thread uses the CreateSemaphore function to create a semaphore object. The creating thread specifies the initial count and the maximum count of the object. The initial count must be neither less than zero nor greater than the maximum count. The creating thread can also specify a name for the semaphore object. Threads in other processes can open a handle of an existing semaphore object by specifying its name in a call to the OpenSemaphore function. For additional information about names for mutex, event, and semaphore objects, see Interprocess Synchronization.

Each time that a wait function returns because of a semaphore's signaled state, the count of the semaphore is decreased by one. The ReleaseSemaphore function increases a semaphore's count by a specified amount. The count can never be less than zero or greater than the maximum count.

The initial count of a semaphore is typically set to the maximum value. The count is then decremented from that level as the protected resource is consumed. Alternatively, a semaphore can be created with an initial count of zero to block access to the protected resource while the application is being initialized. After initialization, you would use ReleaseSemaphore to increment the count to the maximum.

Threads do not acquire ownership of semaphore objects as they do with mutex objects. A thread that owns a mutex can wait repeatedly for the same mutex object without its execution becoming blocked. A thread that waits repeatedly for the same semaphore object, however, decrements the semaphore's count each time a wait is satisfied; its execution is blocked when the count gets to zero. Similarly, only the thread that owns a mutex can successfully call the ReleaseMutex function, though any thread can use ReleaseSemaphore to increase the count of a semaphore object, even if the thread never used a wait function to decrement the count.

A thread can decrement a semaphore's count more than once by repeatedly specifying the same semaphore object in calls to any of the wait functions. However, calling the WaitForMultipleObjects function with an array that contains multiple handles of the same semaphore does not perform multiple decrements.


Event Objects Overview

An event object is a synchronization object whose state can be explicitly set to signaled by use of the SetEvent or PulseEvent function. Following are the two types of event object.

Object	Description
Manual-reset event	An event object whose state remains signaled until it is explicitly reset to nonsignaled by the ResetEvent function. While it is signaled, any number of waiting threads, or threads that subsequently specify the same event object in one of the wait functions, can be released.
Auto-reset event	An event object whose state remains signaled until a single waiting thread is released, at which time the system automatically sets the state to nonsignaled. If no threads are waiting, the event object's state remains signaled.
The event object is useful in signaling a thread that a particular event has occurred. For example, in overlapped input and output, the system sets a specified event object to the signaled state when the overlapped operation has been completed. A single thread can specify different event objects in several simultaneous overlapped operations, then use the WaitForMultipleObjects function to wait for the state of any one of the event objects to be signaled.

A thread uses the CreateEvent function to create an event object. The creating thread specifies the initial state of the object and whether it is a manual-reset or auto-reset event object. The creating thread can also specify a name for the event object. Threads in other processes can open a handle of an existing event object by specifying its name in a call to the OpenEvent function. For additional information about names for mutex, event, and semaphore objects, see Interprocess Synchronization.

A thread can use the PulseEvent function to set an event object's state to signaled and then reset it to nonsignaled after releasing the appropriate number of waiting threads. For a manual-reset event object, all waiting threads that can be released immediately are released. For an auto-reset event object, the function releases only a single waiting thread, even if multiple threads are waiting. If no threads are waiting, or if no thread can be released immediately, PulseEvent simply sets the event object's state to nonsignaled and returns.


Interprocess Synchronization

Multiple processes can have handles of the same mutex, semaphore, or event object, so these objects can be used to accomplish interprocess synchronization. The process that creates an object can use the handle returned by the creation function (CreateEvent, CreateMutex, or CreateSemaphore). Other processes can open a handle of the object by using its name, or through inheritance or duplication.


Object Names

Named objects provide an easy way for processes to share object handles. The name specified by the creating process is limited to MAX_PATH characters, and can include any character except the backslash path-separator character (\). Once a process has created a named event, mutex, or semaphore object, other processes can use the name to call the appropriate function (OpenEvent, OpenMutex, or OpenSemaphore) to open a handle of the object. Name comparison is case sensitive. The names of event, semaphore, mutex, and file-mapping objects share the same name space, so an error occurs if a specified name matches the name of an existing object of a different type. When creating named objects, therefore, use unique names and be sure to check function return values for duplicate-name errors.

If the name specified in a call to the CreateMutex function matches the name of an existing mutex object, the function returns a handle of the existing object. In this case, the call to CreateMutex is equivalent to a call to the OpenMutex function. (The CreateEvent and CreateSemaphore functions work the same way with existing named event and semaphore objects, respectively.) Having multiple processes use CreateMutex for the same mutex is therefore equivalent to having one process that calls CreateMutex while the other processes call OpenMutex, except that it eliminates the need to ensure that the creating process is started first. When using this technique for mutex objects, however, none of the calling processes should request immediate ownership of the mutex. If multiple processes do request immediate ownership, it can be difficult to predict which process actually gets the initial ownership.


Object Inheritance

A child process created by the CreateProcess function can inherit a handle of a mutex, event, or semaphore if the SECURITY_ATTRIBUTES structure — specified when the object was created — enabled inheritance. The handle inherited by the child process has the same access to the object as the parent's handle. The inherited handle appears in the handle table of the child process, but for the child process to be able to use the handle, the parent process must communicate the handle's value to the child process. The parent can do this by specifying the value as a command-line argument when it calls the CreateProcess function. The child process can then use the GetCommandLine function to retrieve the command-line string and convert the handle argument into a usable handle. For more information about object inheritance, see Processes and Threads.


Object Duplication

The DuplicateHandle function creates a duplicate handle that can be used by another specified process. This method of sharing object handles is more complex than using named objects or inheritance. It requires communication between the creating process and the process into which the handle is duplicated. The necessary information (the handle value and process identifier) can be communicated by any of the interprocess communication methods (for example, named pipe, shared file, shared memory). For more information about object duplication, see Processes and Threads.


Synchronization and Overlapped Input and Output

The Win32 API supports both synchronous and asynchronous (or overlapped) I/O operations on files, named pipes, and serial communications devices. The WriteFile, ReadFile, DeviceIoControl, WaitCommEvent, ConnectNamedPipe, and TransactNamedPipe functions can be performed either synchronously or asynchronously. The ReadFileEx and WriteFileEx functions can be performed asynchronously only.

When a function is executed synchronously, it does not return until the operation has been completed. This means that the execution of the calling thread can be blocked for an indefinite period while it waits for a time-consuming operation to finish. Functions called for overlapped operation can return immediately, even though the operation has not been completed. This enables a time-consuming I/O operation to be executed in the background while the calling thread is free to perform other tasks. For example, a single thread can perform simultaneous I/O operations on different handles, or even simultaneous read and write operations on the same handle. To synchronize its execution with the completion of the overlapped operation, the calling thread uses the GetOverlappedResult function or one of the wait functions to determine when the operation has been completed.

Overlapped operations require a file, named pipe, or communications device that was created with the FILE_FLAG_OVERLAPPED flag. To call a function as an overlapped operation, the calling thread must specify a pointer to an OVERLAPPED structure. If this pointer is NULL, the operation is performed synchronously, even though the handle was created with FILE_FLAG_OVERLAPPED enabled. The OVERLAPPED structure must contain a handle to a manual-reset — not an auto-reset — event object. The system sets the state of the event object to nonsignaled when a call to the I/O function returns before the operation has been completed. The system sets the state of the event object to signaled when the operation has been completed.

When a function is called as an overlapped operation, the operation may have been completed before the function returns. When this happens, the results are handled as if the operation had been performed synchronously. If the operation has not yet been completed, however, the function's return value is FALSE, and the GetLastError function returns ERROR_IO_PENDING.

A thread can manage overlapped operations by either of two methods. It can use the GetOverlappedResult function to wait for the overlapped operation to be completed. Alternatively, it can specify a handle of the OVERLAPPED structure's manual-reset event object in one of the wait functions and then call GetOverlappedResult after the wait function returns. GetOverlappedResult returns the results of the completed overlapped operation, and for functions in which such information is appropriate, it reports the actual number of bytes that were transferred.

When performing multiple simultaneous overlapped operations, the calling thread must specify a separate OVERLAPPED structure with its own manual-reset event object for each operation. The thread can then specify handles of the different event objects in the handle-array parameter of the WaitForMultipleObjects function (or one of the other multiple-object wait functions) to wait for any one of the overlapped operations to be completed. The return value of the multiple-object wait function indicates which event object was signaled, so the thread can determine which operation was completed.

If no event object is specified in the OVERLAPPED structure, the system signals the state of the file, named pipe, or communications device when the overlapped operation has been completed. Thus, you can specify these handles as synchronization objects in a wait function, though their use for this purpose can be difficult to manage. When performing simultaneous overlapped operations on the same file, named pipe, or communications device, there is no way to know which operation caused the object's state to be signaled. It is safer to use a separate event object for each overlapped operation.

For examples that illustrate the use of overlapped operations, completion routines, and the GetOverlappedResult function, see Pipes.


Critical Section Objects

Critical section objects provide synchronization similar to that provided by mutex objects, except that critical section objects can be used only by the threads of a single process. Event, mutex, and semaphore objects can also be used in a single-process application, but critical section objects provide a slightly faster, more efficient mechanism for mutual-exclusion synchronization. Like a mutex object, a critical section object can be owned by only one thread at a time, which makes it useful for protecting a shared resource from simultaneous access. For example, a process could use a critical section object to prevent more than one thread at a time from modifying a global data structure.

The process is responsible for allocating the memory used by a critical section object. Typically, this is done by simply declaring a variable of type CRITICAL_SECTION. Before the threads of the process can use it, the critical section object must be initialized by using the InitializeCriticalSection function.

A thread uses the EnterCriticalSection function to request ownership and the LeaveCriticalSection function to release its ownership. If the critical section object is currently owned by another thread, EnterCriticalSection waits indefinitely for ownership. This differs from the use of a mutex object for mutual exclusion, where the wait functions accept a specified time-out interval.

Once a thread owns a critical section object, it can make additional calls to EnterCriticalSection without blocking its execution. This prevents a thread from deadlocking itself while waiting for a critical section object that it already owns. To release its ownership, the thread must call LeaveCriticalSection once for each time that it entered the critical section.

Any thread of the process can use the DeleteCriticalSection function to release the system resources that were allocated when the critical section object was initialized. After this function has been called, the critical section object can no longer be used for synchronization.

When a critical section object is owned, the only other threads affected are those that are waiting for ownership in a call to EnterCriticalSection. Threads that are not waiting are free to continue their normal execution.


Interlocked Variable Access

The InterlockedIncrement and InterlockedDecrement functions provide a simple mechanism for synchronizing access to a specified 32-bit variable that is shared by multiple threads in the same or in different processes. These functions combine the operations of incrementing or decrementing the variable and checking the resulting value. This is useful in a multitasking operating system, in which the system can interrupt one thread's execution to grant a slice of processor time to another thread. Without such synchronization, one thread could increment a variable but be interrupted by the system before it can check the resulting value of the variable. A second thread could then increment the same variable. When the first thread receives its next timeslice, it will check the value of the variable, which has now been incremented not once but twice. The interlocked variable-access functions protect against this kind of error.

The threads of different processes can use this mechanism if the variable is in shared memory.


Using Synchronization

•	Using named objects

•	Waiting for multiple objects

•	Using mutex objects

•	Using semaphore objects

•	Using event objects

•	Using critical section objects


Using Named Objects

This example illustrates the use of an object name to let two processes open handles of the same mutex object.

The first process uses the CreateMutex function to create the mutex object. Note that the function succeeds even if there is an existing object with the same name.

/* One process creates the mutex object. */

HANDLE hMutex;

DWORD dwErr;

hMutex = CreateMutex(

    NULL,                  /* no security descriptor */

    FALSE,                 /* mutex not owned        */

    "NameOfMutexObject");  /* object name            */

if (hMutex == NULL)

    printf("CreateMutex error: %d\n", GetLastError() );

else

    if ( GetLastError() == ERROR_ALREADY_EXISTS )

        printf("CreateMutex opened existing mutex\n");

    else

        printf("CreateMutex created new mutex\n");

The second process uses the OpenMutex function to open a handle of the existing mutex. This function fails if a mutex object with the specified name does not exist. The access parameter requests full access to the mutex object, which is necessary for the handle to be used in any of the wait functions.

/* Another process opens a handle of the existing mutex. */

HANDLE hMutex;

hMutex = OpenMutex(

    MUTEX_ALL_ACCESS,      /* request full access    */

    FALSE,                 /* handle not inheritable */

    "NameOfMutexObject");  /* object name            */

if (hMutex == NULL)

    printf("OpenMutex error: %d\n", GetLastError() );

The following example uses the CreateSemaphore function to illustrate a named-object creation operation that fails if the object already exists.

HANDLE CreateNewSemaphore(LPSECURITY_ATTRIBUTES lpsa,

    LONG cInitial, LONG cMax, LPTSTR lpszName) {

HANDLE hSem;

/* Create or open a named semaphore. */

hSem = CreateSemaphore(

    lpsa,         /* security attributes */

    cInitial,     /* initial count       */

    cMax,         /* maximum count       */

    lpszName);    /* semaphore name      */

/* Close handle, and return NULL if existing semaphore opened. */

if (hSem != NULL &&

        GetLastError() == ERROR_ALREADY_EXISTS) {

    CloseHandle(hSem);

    return NULL;

}

/* If new semaphore was created, return the handle. */

return hSem;

}


Waiting for Multiple Objects

This example uses the CreateEvent function to create two event objects. It then uses the WaitForMultipleObjects function to wait for one of them to be signaled.

HANDLE hEvents[2];

DWORD i, dwEvent;

/* Create two event objects. */

for (i = 0; i < 2; i++) {

    hEvents[i] = CreateEvent(

        NULL,   /* no security attributes        */

        FALSE,  /* auto-reset event object       */

        FALSE,  /* initial state is nonsignaled  */

        NULL);  /* unnamed object                */

    if (hEvents[i] == NULL) {

        printf("CreateEvent error: %d\n", GetLastError() );

        ExitProcess(0);

    }

}

/*

 * The creating thread waits for other threads or processes

 * to signal the event objects.

 */

dwEvent = WaitForMultipleObjects(

    2,           /* number of objects in array */

    hEvents,     /* array of objects           */

    FALSE,       /* wait for any               */

    INFINITE);   /* indefinite wait            */

/* Return value indicates which event is signaled. */

switch (dwEvent) {

    /* hEvent[0] was signaled. */

    case WAIT_OBJECT_0 + 0:

        /* Perform tasks required by this event. */

        break;

    /* hEvent[1] was signaled. */

    case WAIT_OBJECT_0 + 1:

        /* Perform tasks required by this event. */

        break;

    /* Return value is invalid. */

    default:

        printf("Wait error: %d\n", GetLastError());

        ExitProcess(0);

}


Using Mutex Objects

You can use a mutex object to protect a shared resource from simultaneous access by multiple threads or processes. Each thread must wait for ownership of the mutex before it can execute the code that accesses the shared resource. For example, if several threads share access to a database, the threads can use a mutex object to permit only one thread at a time to write to the database.

In the following example, a process uses the CreateMutex function to create a named mutex object or open a handle of an existing mutex object.

HANDLE hMutex;

/* Create a mutex with no initial owner. */

hMutex = CreateMutex(

    NULL,                       /* no security attributes */

    FALSE,                      /* initially not owned      */

    "MutexToProtectDatabase");  /* name of mutex          */

if (hMutex == NULL) {

    /* check for error */

}

When a thread of this process writes to the database, as in the next example, it first requests ownership of the mutex. If it gets ownership, the thread writes to the database and then releases its ownership.

The example uses the try-finally structured exception-handling syntax to ensure that the thread properly releases the mutex. The finally block of code is executed no matter how the try block terminates (unless the try block includes a call to the TerminateThread function). This prevents the mutex from being abandoned inadvertently.

BOOL FunctionToWriteToDatabase(HANDLE hMutex) {

DWORD dwWaitResult;

/* Request ownership of mutex. */

dwWaitResult = WaitForSingleObject(

        hMutex,   /* handle of mutex           */

        5000L);   /* five-second time-out interval */

switch (dwWaitResult) {

    /* The thread got mutex ownership. */

    case WAIT_OBJECT_0:

        try {

            .

            . /* Write to the database. */

            .

        }

        finally {

            /* Release ownership of the mutex object. */

            if (! ReleaseMutex(hMutex)) {

                /* Deal with error. */

            }

            break;

        }

    /* Cannot get mutex ownership due to time-out. */

    case WAIT_TIMEOUT:

        return FALSE;

    /* Got ownership of the abandoned mutex object. */

    case WAIT_ABANDONED:

        return FALSE;

}

return TRUE;

}


Using Semaphore Objects

In the following example, a process uses a semaphore object to limit the number of windows it creates. First, it uses the CreateSemaphore function to create the semaphore and to specify initial and maximum counts.

HANDLE hSemaphore;

LONG cMax = 10;

LONG cPreviousCount;

/* Create a semaphore with initial and max. counts of 10. */

hSemaphore = CreateSemaphore(

    NULL,   /* no security attributes */

    cMax,   /* initial count          */

    cMax,   /* maximum count          */

    NULL);  /* unnamed semaphore      */

if (hSemaphore == NULL) {

    /* Check for error. */

}

Before any thread of the process creates a new window, it uses the WaitForSingleObject function to determine whether the semaphore's current count permits the creation of additional windows. The wait function's time-out parameter is set to zero, so the function returns immediately if the semaphore is nonsignaled.

DWORD dwWaitResult;

/* Try to enter the semaphore gate. */

dwWaitResult = WaitForSingleObject(

        hSemaphore,   /* handle of semaphore          */

        0L);          /* zero-second time-out interval */

switch (dwWaitResult) {

    /* The semaphore object was signaled. */

    case WAIT_OBJECT_0:

        .

        . /* OK to open another window. */

        .

        break;

    /* Semaphore was nonsignaled, so a time-out occurred. */

    case WAIT_TIMEOUT:

        .

        . /* Cannot open another window. */

        .

        break;

}

When a thread closes a window, it uses the ReleaseSemaphore function to increment the semaphore's count.

/* Increment the count of the semaphore. */

if (! ReleaseSemaphore(

        hSemaphore,  /* handle of semaphore              */

        1,           /* increase count by one            */

        NULL) ) {    /* not interested in previous count */

    /* Deal with the error. */

}


Using Event Objects

The Win32 API uses event objects in a number of situations to notify a waiting thread of the occurrence of an event. For example, overlapped I/O operations on files, named pipes, and communications devices use an event object to signal their completion. For more information about the use of event objects in overlapped I/O operations, see Synchronization and Overlapped Input and Output.

In the following example, an application uses event objects to prevent several threads from reading from a shared memory buffer while a master thread is writing to that buffer. First, the master thread uses the CreateEvent function to create a manual-reset event object. The master thread sets the event object to nonsignaled when it is writing to the buffer and then resets the object to signaled when it has finished writing. Then it creates several reader threads and an auto-reset event object for each thread. Each reader thread sets its event object to signaled when it is not reading from the buffer.

#define NUMTHREADS 4

HANDLE hGlobalWriteEvent;

void CreateEventsAndThreads(void) {

HANDLE hReadEvents[NUMTHREADS], hThread;

DWORD i, IDThread;

/*

 * Create a manual-reset event object. The master thread sets

 * this to nonsignaled when it writes to the shared buffer.

 */

hGlobalWriteEvent = CreateEvent(

    NULL,        /* no security attributes    */

    TRUE,        /* manual-reset event        */

    TRUE,        /* initial state is signaled */

    "WriteEvent" /* object name               */

    );

if (hGlobalWriteEvent == NULL) {

    /* error exit */

}

/*

 * Create multiple threads and an auto-reset event object

 * for each thread. Each thread sets its event object to

 * signaled when it is not reading from the shared buffer.

 */

for(i = 1; i <= NUMTHREADS; i++) {

    /* Create the auto-reset event. */

    hReadEvents[i] = CreateEvent(

        NULL,     /* no security attributes    */

        FALSE,    /* auto-reset event          */

        TRUE,     /* initial state is signaled */

        NULL);    /* object not named          */

    if (hReadEvents[i] == NULL) {

        /* error exit */

    }

    hThread = CreateThread(NULL, 0,

            (LPTHREAD_START_ROUTINE) ThreadFunction,

            &hReadEvents[i], /* pass event handle  */

            0, &IDThread);

    if (hThread == NULL) {

        /* error exit */

    }

}

}

Before the master thread writes to the shared buffer, it uses the ResetEvent function to set the state of hGlobalWriteEvent (an application-defined global variable) to nonsignaled. This blocks the reader threads from starting a read operation. The master then uses the WaitForMultipleObjects function to wait for all reader threads to finish any current read operations. When WaitForMultipleObjects returns, the master thread can safely write to the buffer. After it has finished, it sets hGlobalWriteEvent and all the reader-thread events to signaled, enabling the reader threads to resume their read operations.

VOID WriteToBuffer(VOID) {

DWORD dwWaitResult, i;

/* Reset hGlobalWriteEvent to nonsignaled, to block readers. */

if (! ResetEvent(hGlobalWriteEvent) ) {

        /* error exit */

}

/* Wait for all reading threads to finish reading. */

dwWaitResult = WaitForMultipleObjects(

        NUMTHREADS,   /* number of handles in array   */

        hReadEvents,  /* array of read-event handles  */

        TRUE,         /* wait until all are signaled  */

        INFINITE);    /* indefinite wait              */

switch (dwWaitResult) {

    /* All read-event objects were signaled. */

    case WAIT_OBJECT_0:

        .

        . /* Write to the shared buffer. */

        .

        break;

    /* An error occurred. */

    default:

        printf("Wait error: %d\n", GetLastError());

        ExitProcess(0);

}

/* Set hGlobalWriteEvent to signaled. */

if (! SetEvent(hGlobalWriteEvent) ) {

        /* error exit */

}

/* Set all read events to signaled. */

for(i = 1; i <= NUMTHREADS; i++)

    if (! SetEvent(hReadEvents[i]) ) {

            /* error exit */

    }

}

Before starting a read operation, each reader thread uses WaitForMultipleObjects to wait for the application-defined global variable hGlobalWriteEvent and its own read event to be signaled. When WaitForMultipleObjects returns, the reader thread's auto-reset event has been reset to nonsignaled. This blocks the master thread from writing to the buffer until the reader thread uses the SetEvent function to set the event's state back to signaled.

VOID ThreadFunction(LPVOID lpParam) {

DWORD dwWaitResult, i;

HANDLE hEvents[2];

hEvents[0] = (HANDLE) *lpParam;  /* thread's read event */

hEvents[1] = hGlobalWriteEvent;

dwWaitResult = WaitForMultipleObjects(

        2,            /* number of handles in array   */

        hEvents,      /* array of event handles       */

        TRUE,         /* wait till all are signaled   */

        INFINITE);    /* indefinite wait              */

switch (dwWaitResult) {

    /* Both event objects were signaled. */

    case WAIT_OBJECT_0:

        .

        . /* Read from the shared buffer. */

        .

        break;

    /* An error occurred. */

    default:

        printf("Wait error: %d\n", GetLastError());

        ExitThread(0);

}

/* Set the read event to signaled. */

if (! SetEvent(hEvents[0]) ) {

        /* error exit */

}

}


Using Critical Section Objects

The following example shows how a thread initializes, enters, and leaves a critical section. As with the mutex example (see Using Mutex Objects), this example uses the try-finally structured exception-handling syntax to ensure that the thread calls the LeaveCriticalSection function to release its ownership of the critical section object.

CRITICAL_SECTION GlobalCriticalSection;

/* Initialize the critical section. */

InitializeCriticalSection(&GlobalCriticalSection);

/* Request ownership of the critical section. */

try {

    EnterCriticalSection(&GlobalCriticalSection);

        .

        . /* Access the shared resource. */

        .

}

finally {

    /* Release ownership of the critical section. */

    LeaveCriticalSection(&GlobalCriticalSection);

}


Synchronization Functions

Following are the functions used in synchronization.

CreateEvent
CreateMutex
CreateSemaphore
DeleteCriticalSection
EnterCriticalSection
GetOverlappedResult
InitializeCriticalSection
InterlockedDecrement
InterlockedExchange
InterlockedIncrement
LeaveCriticalSection
MsgWaitForMultipleObjects
OpenEvent
OpenMutex
OpenSemaphore
PulseEvent
ReleaseMutex
ReleaseSemaphore
ResetEvent
SetEvent
WaitForMultipleObjects
WaitForMultipleObjectsEx
WaitForSingleObject
WaitForSingleObjectEx


System Information

The Microsoft® Win32® application programming interface (API) includes functions that describe the current system configuration.


About System Information

The functions described in this overview retrieve a variety of data, such as the computer name, user name, settings of environment variables, processor type, system colors, and so on. The Win32 API also includes functions that can change the system configuration, shut down the system, and start the Microsoft® Windows™ Help application.


System Configuration

Several of the functions in the Win32 API are specifically intended to describe or change the system configuration. At startup, for example, a computer is assigned the name listed in the registry. An application can retrieve this name by using the GetComputerName function and can change the name by using the SetComputerName function. SetComputerName changes the registry, not the current computer name. As a result, the new name is not assigned until the computer is restarted. For more information about the registry, see Registry.

The GetUserName function retrieves the name of the user currently logged onto the system. The user name is either the logon name or the user's full name, if the latter is included in the registry.

The GetSystemInfo function retrieves processor and memory information, such as the page size, original equipment manufacturer (OEM) identifier, number and type of processors, application address range, and so on. The GetVersion function retrieves the major and minor revision numbers of the installed version of Microsoft Windows. The GetKeyboardType function retrieves such information as the type of keyboard and the number of function keys on the current keyboard.

The SystemParametersInfo function retrieves or sets various system attributes, such as double-click time, screen saver time-out, window border width, and desktop pattern. When an application uses SystemParametersInfo to set a parameter, the change takes place immediately. This function also enables applications to update the user profile, so changes to the system will be preserved when the system is restarted.

The GetThreadDesktop function retrieves a handle of the desktop for a given thread. This handle can be used in calls to functions that retrieve and set security attributes.

The Windows directory is the directory that contains Windows-based applications, initialization files, and Help files. The GetWindowsDirectory function retrieves the path to this directory. Applications that create files should do so in the Windows directory. This is the only directory guaranteed to be private to a user running a shared version of Windows.

The system directory is the directory that contains Windows libraries, drivers, and font files. The GetSystemDirectory function retrieves the path to this directory.

An environment variable is a symbolic variable that represents some element of the system, such as a path, a filename, or other literal data. For example, the environment variable PATH represents the directories in which to search for executable files. When a user logs on, the system initializes environment variables based on the environment section of the registry. The ExpandEnvironmentStrings function retrieves the values of specified environment variables.

System metrics are the dimensions of various Windows display elements. (Display elements are the parts of a window and the Windows display that appear on the system display screen.) Typical system metrics include the window border width, icon height, and so on. System metrics also describe other aspects of the system, such as whether a mouse is installed, double-byte characters are supported, or a debugging version of Windows is installed. The GetSystemMetrics function retrieves a specified system metric.

Applications can also retrieve and set the color of window elements such as menus, scroll bars, and buttons by using the GetSysColor and SetSysColors functions, respectively.


System Shutdown

The Win32 API also provides a way for an application to shut down a local or remote computer. This is particularly useful for system administrators who update system software on remote computers. The InitiateSystemShutdown function starts a timer and displays a dialog box that prompts the user to log off. While the dialog box is displayed, the AbortSystemShutdown function can stop the timer and prevent the computer from shutting down. However, if the timer expires, the computer is shut down. InitiateSystemShutdown can also restart the computer following shutdown.


Using System Information

•	Getting system configuration information

•	Getting hardware information

•	Changing the colors of window elements

•	Shutting down the system


Getting System Configuration Information

The following example uses the GetComputerName, GetUserName, GetSystemDirectory, GetWindowsDirectory, and ExpandEnvironmentStrings functions to get information that describes the system configuration. This example displays the information in a window's client area.

LPTSTR lpszSystemInfo;    /* ptr. to system info. string */

DWORD cchBuff = 256;     /* size of comp. or user name   */

TCHAR tchBuffer2[BUFFER];   /* buffer for concat'd. str. */

DWORD dwResult;               /* function return value */

SYSTEM_INFO siSysInfo;     /* struct. for hardware info. */

int aTabs[1] = {260};    /* tab stop for TabbedTextOut */

TCHAR tchBuffer[BUFFER]; /* buffer for expanded string */

int nSize;                           /* size of string */

lpszSystemInfo = tchBuffer2;

/* Get and display the name of the computer. */

GetComputerName(lpszSystemInfo, &cchBuff);

nSize = sprintf(tchBuffer, "Computer name:  %s",

    lpszSystemInfo);

TextOut(hdc, 15, 20, tchBuffer, nSize);

/* Get and display the user name. */

GetUserName(lpszSystemInfo, &cchBuff);

nSize = sprintf(tchBuffer, "User name:  %s",

    lpszSystemInfo);

TextOut(hdc, 15, 40, tchBuffer, nSize);

/* Get and display the system directory. */

nSize = GetSystemDirectory(lpszSystemInfo, MAX_PATH);

nSize = sprintf(tchBuffer, "System directory:  %s",

    lpszSystemInfo);

TextOut(hdc, 15, 60, tchBuffer, nSize);

/* Get and display the Windows directory. */

nSize = GetWindowsDirectory(lpszSystemInfo, MAX_PATH);

nSize = sprintf(tchBuffer, "Windows directory:  %s",

    lpszSystemInfo);

TextOut(hdc, 15, 80, tchBuffer, nSize);

/* Display the "environment variables" header. */

nSize = sprintf(tchBuffer,

    "Environment variables (partial list):");

TextOut(hdc, 15, 105, tchBuffer, nSize);

/* Expand the OS and NTVERSION environment variables. */

dwResult = ExpandEnvironmentStrings(

               "OS=%OS%     NTVERSION=%NTVERSION%",

               lpszSystemInfo,

               BUFFER);

TextOut(hdc, 25, 120, (LPCTSTR) lpszSystemInfo,

    dwResult - 1);

/* Expand the PATH environment variable. */

dwResult = ExpandEnvironmentStrings(

               "PATH=%PATH%",

               lpszSystemInfo,

               BUFFER);

TextOut(hdc, 25, 135, (LPCTSTR) lpszSystemInfo,

    dwResult - 1);

/* Expand the LIBPATH environment variable. */

dwResult = ExpandEnvironmentStrings(

               "LIBPATH=%LIBPATH%",

               lpszSystemInfo,

               BUFFER);

TextOut(hdc, 25, 150, (LPCTSTR) lpszSystemInfo,

    dwResult - 1);

/* Expand the TMP environment variable. */

dwResult = ExpandEnvironmentStrings(

               "TMP=%TMP%",

               lpszSystemInfo,

               BUFFER);

TextOut(hdc, 25, 165, (LPCTSTR) lpszSystemInfo,

    dwResult - 1);

The next example uses the GetVersion function to obtain the current version of Windows and then displays the version number in a message box.

DWORD dwResult;               /* function return value */

TCHAR tchBuffer[BUFFER]; /* buffer for expanded string */

int nSize;                           /* size of string */

dwResult = GetVersion();

nSize = sprintf(tchBuffer, "Windows version %d.%d\n",

    LOBYTE(LOWORD(dwResult)),

    HIBYTE(LOWORD(dwResult)));

MessageBox(NULL, tchBuffer, "GetVersion", MB_ICONINFORMATION);


Getting Hardware Information

The following example uses the GetSystemInfo function to obtain hardware information such as the OEM identifier, processor type, page size, and so on. The example displays the information in a window's client area.

SYSTEM_INFO siSysInfo;     /* struct. for hardware info. */

int aTabs[1] = {260};    /* tab stop for TabbedTextOut */

TCHAR tchBuffer[BUFFER]; /* buffer for expanded string */

int nSize;                           /* size of string */

/* Display the "hardware information" header. */

nSize = sprintf(tchBuffer,

    "Hardware information:");

TextOut(hdc, 15, 20, tchBuffer, nSize);

/* Copy the hardware information to the SYSTEM_INFO structure. */

GetSystemInfo(&siSysInfo);

/* Display the contents of the SYSTEM_INFO structure. */

nSize = sprintf(tchBuffer,

    "OEM ID: %u\tNumber of Processors: %u",

    siSysInfo.dwOemId,

    siSysInfo.dwNumberOfProcessors);

TabbedTextOut(hdc, 25, 40, tchBuffer,

    nSize, 1, aTabs, 25);

nSize = sprintf(tchBuffer,

    "Page size: %u\tProcessor Type: %u",

    siSysInfo.dwPageSize,

    siSysInfo.dwProcessorType);

TabbedTextOut(hdc, 25, 60, tchBuffer,

    nSize, 1, aTabs, 25);

nSize = sprintf(tchBuffer,

    "Minimum app address: %lx\tMaximum app address: %lx",

    siSysInfo.lpMinimumApplicationAddress,

    siSysInfo.lpMaximumApplicationAddress);

TabbedTextOut(hdc, 25, 80, tchBuffer,

    nSize, 1, aTabs, 25);

nSize = sprintf(tchBuffer,

    "Active processor mask: %u",

    siSysInfo.dwActiveProcessorMask);

TextOut(hdc, 25, 100, tchBuffer, nSize);

The following example uses the GetSystemMetrics function to determine whether a mouse is installed and whether the mouse buttons are swapped. The example also uses the SystemParametersInfo function to retrieve the mouse threshold and speed. It displays the information in a message box.

TCHAR tchBuffer[BUFFER]; /* buffer for expanded string */

int nSize;                           /* size of string */

BOOL fResult;                  /* system shutdown flag */

int aMouseInfo[3];             /* array for mouse info. */

/* Is there a mouse? */

fResult = GetSystemMetrics(SM_MOUSEPRESENT);

if (fResult == 0) {

    /* Indicate if there is no mouse. */

    nSize = sprintf(tchBuffer, "No mouse installed.");

} else {

    /*

     * If there is a mouse, determine whether

     * its buttons are swapped.

     */

    fResult = GetSystemMetrics(SM_SWAPBUTTON);

    if (fResult == 0) {

        nSize = sprintf(tchBuffer, "Buttons not swapped.\r");

    } else {

        nSize = sprintf(tchBuffer, "Buttons swapped.\r");

    }

    /* Get the mouse speed and the threshold values. */

    SystemParametersInfo(SPI_GETMOUSE, /* get mouse info.   */

        NULL,                          /* not used          */

        &aMouseInfo,                   /* holds mouse info. */

        NULL);                         /* not used          */

    nSize += sprintf(tchBuffer + nSize,

        "Speed: %d\r", aMouseInfo[2]);

    sprintf(tchBuffer + nSize,

        "Threshold (x,y): %d,%d",

        aMouseInfo[0], aMouseInfo[1]);

}

/* Display the mouse information. */

MessageBox(NULL, tchBuffer, "Mouse information",

    MB_ICONINFORMATION);

This next example uses SystemParametersInfo to double the mouse speed and update the MouseSpeed value in the WIN.INI file.

TCHAR tchBuffer[BUFFER]; /* buffer for expanded string */

int nSize;                           /* size of string */

int aMouseInfo[3];             /* array for mouse info. */

/* Get the current mouse speed. */

SystemParametersInfo(SPI_GETMOUSE, /* get mouse info.   */

    NULL,                          /* not used          */

    &aMouseInfo,                   /* holds mouse info. */

    NULL);                         /* not used          */

/* Double it. */

aMouseInfo[2] = 2 * aMouseInfo[2];

/* Change the mouse speed to the new value and update WIN.INI. */

SystemParametersInfo(SPI_SETMOUSE, /* set mouse info.    */

    NULL,                          /* not used           */

    aMouseInfo,                    /* mouse info. to set */

    SPIF_UPDATEINIFILE);           /* update win.ini     */


Changing the Colors of Window Elements

The following example uses the SetSysColors function to change the color of active window borders to dark purple, of active title bars to dark cyan, and of the window background to light gray.

                          /* window elements to change */

int aiElements[3] = {COLOR_ACTIVEBORDER,

                     COLOR_ACTIVECAPTION,

                     COLOR_WINDOW};

DWORD aColors[3];               /* array of RGB values */

/* Define the new colors. */

aColors[0] = RGB(0x80, 0x00, 0x80);  /* dark purple */

aColors[1] = RGB(0x00, 0x80, 0x80);  /* dark cyan   */

aColors[2] = RGB(0xC0, 0xC0, 0xC0);  /* light gray  */

/*

 * Set the window elements in aiElements to the colors

 * specified in aColors.

 */

SetSysColors(3, aiElements, aColors);

The next example uses the GetSysColor function to retrieve the color of the window background and displays the red, green, blue (RGB) value, in hexadecimal notation, in a message box.

DWORD dwResult;               /* function return value */

TCHAR tchBuffer[BUFFER]; /* buffer for expanded string */

int nSize;                           /* size of string */

/* Get the color of the window background. */

dwResult = GetSysColor(COLOR_WINDOW);

nSize = sprintf(tchBuffer,

    "Window color: {%x, %x, %x}",

    GetRValue(dwResult),

    GetGValue(dwResult),

    GetBValue(dwResult));

MessageBox(NULL, tchBuffer, "GetSysColor", MB_ICONINFORMATION);


Shutting Down the System

The following example uses the InitiateSystemShutdown function to begin the system shutdown process on the local computer. Note that the application must first enable the SE_SHUTDOWN_NAME privilege to shut down the computer the user is logged onto.

HANDLE hToken;              /* handle to process token */

TOKEN_PRIVILEGES tkp;        /* ptr. to token structure */

BOOL fResult;                  /* system shutdown flag */

/*

 * Get the current process token handle

 * so we can get shutdown privilege.

 */

if (!OpenProcessToken(GetCurrentProcess(),

        TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))

    ErrorHandler("OpenProcessToken failed.");

/* Get the LUID for shutdown privilege. */

LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME,

        &tkp.Privileges[0].Luid);

tkp.PrivilegeCount = 1;  /* one privilege to set    */

tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

/* Get shutdown privilege for this process. */

AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,

    (PTOKEN_PRIVILEGES) NULL, 0);

/* Cannot test the return value of AdjustTokenPrivileges. */

if (GetLastError() != ERROR_SUCCESS)

    ErrorHandler("AdjustTokenPrivileges enable failed.");

/* Display the shutdown dialog box and start the time-out countdown. */

fResult = InitiateSystemShutdown(

    NULL,            /* shut down local computer */

    "Click on the main window and press \

     the Escape key to cancel shutdown.",

                                 /* msg. to user */

    20,                       /* time-out period */

    FALSE,         /* prompt user to close apps. */

    TRUE);             /* reboot after shutdown  */

if (!fResult) {

    ErrorHandler("InitiateSystemShutdown failed.");

}

/* Disable shutdown privilege. */

tkp.Privileges[0].Attributes = 0;

AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,

        (PTOKEN_PRIVILEGES) NULL, 0);

if (GetLastError() != ERROR_SUCCESS)

    ErrorHandler("AdjustTokenPrivileges disable failed.");

If the AbortSystemShutdown function is executed in the time-out period specified by InitiateSystemShutdown, the system does not shut down. The following example enables the user to prevent the system from shutting down by clicking on the application's main window and pressing the ESC key. As noted earlier, your application must enable the SE_SHUTDOWN_NAME privilege to stop the system shutdown.

HANDLE hToken;              /* handle to process token */

TOKEN_PRIVILEGES tkp;        /* ptr. to token structure */

BOOL fResult;                  /* system shutdown flag */

case WM_KEYDOWN:

    /* Process only the Escape key. */

    if (wParam != VK_ESCAPE) {

        break;

    }

    /*

     * Get the current process token handle

     * so we can get shutdown privilege.

     */

    if (!OpenProcessToken(GetCurrentProcess(),

            TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))

        ErrorHandler("OpenProcessToken failed.");

    /* Get the LUID for shutdown privilege. */

    LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME,

            &tkp.Privileges[0].Luid);

    tkp.PrivilegeCount = 1;  /* one privilege to set    */

    tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

    /* Get shutdown privilege for this process. */

    AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,

        (PTOKEN_PRIVILEGES)NULL, 0);

    /* Cannot test the return value of AdjustTokenPrivileges. */

    if (GetLastError() != ERROR_SUCCESS)

        ErrorHandler("AdjustTokenPrivileges enable failed.");

    /* Prevent the system from shutting down. */

    fResult = AbortSystemShutdown(NULL);

    if (!fResult) {

        ErrorHandler("AbortSystemShutdown failed.");

    }

    /* Disable shutdown privilege. */

    tkp.Privileges[0].Attributes = 0;

    AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,

        (PTOKEN_PRIVILEGES) NULL, 0);

    if (GetLastError() != ERROR_SUCCESS)

        ErrorHandler("AdjustTokenPrivileges disable failed.");

    break;


System Information Functions

Following are the functions used to retrieve or set system information, shut down the system, or start Windows Help.

AbortSystemShutdown
ExpandEnvironmentStrings
GetComputerName
GetKeyboardType
GetSysColor
GetSystemDirectory
GetSystemInfo
GetSystemMetrics
GetThreadDesktop
GetUserName
GetVersion
GetVersionEx
GetWindowsDirectory
InitiateSystemShutdown
SetComputerName
SetSysColors
SystemParametersInfo
WinHelp

Obsolete or Deleted Functions

DOS3Call
GetCurrentPDB
GetCurrentTask
GetDOSEnvironment
GetWinFlags
IsTask


System Messages

System messages provide the way to uniformly notify all applications and other components in the system of changes that may affect their operation and access to resources. Applications and other components use and process system messages to take advantage of new resources when they become available and to prevent loss of data when existing resources become unavailable.


About System Messages

The Windows operating system provides two predefined classes of system messages: device messages and power messages. Device messages notify applications and installable drivers of device change events; power messages notify these of power management events. Applications and other components can also define and use their own system messages to provide for notification of other types of events.

This overview describes system messages, system-message broadcasts, and the specific class of system messages called device messages. For more information about power messages, see Power Management.


System Messages and System-Message Broadcasts

Each system message consists of a message identifier and two 32-bit parameters, wParam and lParam. The message identifier is a unique value that specifies the message purpose. The parameters provide additional information that is message-specific, but the wParam parameter is often a notification value that further specifies the message purpose.

A system-message broadcast is simply the sending of a system message to components in the system. You broadcast a system message by using the BroadcastSystemMessage function and specifying the recipients of the message. Rather than specify individual recipients, you must specify one or more types of recipients. These types are applications, installable drivers, Windows-based network drivers, and system-level device drivers. BroadcastSystemMessage sends messages to all members of each type you specify.

Most applications do not broadcast system messages. Instead, they process system messages sent by other components. The operating system typically broadcasts system messages in response to changes that usually take place within system-level device drivers. The device driver or related component generates the system message and broadcasts it to applications and other components to notify them of the change. For example, the subsystem responsible for disk drives generates and broadcasts a system message whenever the device driver for the floppy disk drive detects a change of media such as when the user inserts a disk in the drive.

Applications receive system messages through the window procedure of their top-level windows. System messages are not sent to child windows. The action an application takes in response to a system message depends on the message. Some system messages, called query messages, require the application to respond by returning either TRUE or FALSE to indicate whether the system should continue to broadcast the message to other recipients.


Custom System Messages

You can create your own system messages and use them to coordinate activities between applications and other components in the system. This is especially useful if you have created your own installable drivers or system-level device drivers. Your custom system messages can carry information to and from your driver and the applications that use the driver.

You broadcast custom system messages using the BroadcastSystemMessage function.(System-level device drivers use a related, system-level function.) The function sends the messages to these recipients in this order: system-level device drivers, Windows-based network drivers, installable drivers, and applications. This means that system-level device drivers, if chosen as recipients, always get the first opportunity to respond to a system message. Within a given recipient type, no driver is guaranteed to receive a given message before any other driver. This means a system message intended for a specific driver must have an globally-unique message identifier so that no other driver unintentionally processes it.

Query messages are a useful way to poll recipients for permission to carry out a given action. You can generate your own a query messages by setting the BSF_QUERY value in the dwFlags parameter when calling BroadcastSystemMessage. Each recipient of the query message must return TRUE for the function to send the message to the next recipient. If any recipient returns FALSE, the broadcast ends immediately and the function returns 0.

You can create installable drivers that broadcast and process system messages. An installable driver is a dynamic-link library (DLL) that exports a DriverProc function. The driver receives system messages through its DriverProc function and can broadcast messages using BroadcastSystemMessage. Installable drivers are typically used to support multimedia devices, such as sound boards, but can be used for other devices and purposes too.

Windows-based network drivers are dynamic-link libraries that provide the underlying support for applications that use the Windows network functions to connect to and browse network resources. System-level device drivers are operating-system-specific executable components that provide direct access to and management of the hardware devices of the computer. The details regarding how these components process system messages is beyond the scope of this book.


Device Messages and Device Change Events

Device messages are system messages that notify applications and other components of device change events. These events occur whenever the system detects a change to the system hardware such as when the user docks or undocks a laptop computer, or inserts or removes a device such as a PCMCIA card. Change events can occur while the system is running or when the system resumes operation after temporarily being suspended.

To help ensure that applications and installable drivers do not lose data when devices become unavailable, the operating system monitors the hardware configuration and sends device message to the applications and installable drivers to notify them of the changes and to give them the opportunity to prepare for the changes before they occur.

For each event, the system broadcasts a WM_DEVICECHANGE message to all applications and installable drivers. In this message, the wParam parameter identifies the event type and the lParam parameter is usually the address of event-specific data.

The event-specific data identifies the device and provides additional detail about the event. The format of this data depends on the device type, but the first few bytes always has the same format as the DEV_BROADCAST_HDR structure. This means you can always check the dbch_devicetype member in the data to determine the device type.

The system sends a DBT_DEVICEARRIVAL message (that is, a WM_DEVICECHANGE message with wParam set to DBT_DEVICEARRIVAL) whenever a device has been inserted and is available for use. Applications typically check the device type and begin using the device immediately if appropriate.

The system sends a DBT_DEVICEQUERYREMOVE to request permission to remove a device. If an application determines that it needs the device, it can deny this request and cancel the removal by returning FALSE. To determine whether it needs the device, an application can display a dialog box to prompt the user for instructions. If the application does not need the device, it must return TRUE. The system immediately sends a DBT_DEVICEQUERYREMOVEFAILED message if any application or driver canceled a previous request to remove a device.

The system sends a DBT_DEVICEREMOVEPENDING message as a last warning before a device is removed. At this point, the application cannot cancel the removal, so if it is using the device it must prepare for its removal to prevent loss of data. This is especially important when a network connection is being removed. The application must determine whether any of its open files or pipes are on that connection. It can do this by comparing the network resource identifier in the event-specific data of the message with the resource identifiers previously obtained for the files and pipes. The system sends a DBT_DEVICEREMOVECOMPLETE when a device has been removed and is no longer available.

The system sends DBT_DEVICETYPESPECIFIC message whenever a device-specific event occurs. It sends a DBT_CONFIGCHANGED message if current configuration has changed, such as when the operational parameters of a device have been changed by the user.


Using System Messages

•	Processing a Request to Remove a Device


Processing a Request to Remove a Device

An application receives a DBT_DEVICEQUERYREMOVE message when a component in the system has decided to remove a given device. When the application receives this message, it should determine whether it is using the given device and either cancel or prepare for the removal. In the following example, the application processes the message by checking the type of device that is to be removed.

PDEV_BROADCAST_HDR pdbch;
PDEV_BROADCAST_VOLUME pdbcv;

case WM_DEVICECHANGE:
    pdbch = (PDEV_BROADCAST_HDR) lParam;
    switch (pdbch->dbch_devicetype) {
    case DBT_DEVTYP_VOLUME:
        pdbcv = (PDEV_BROADCAST_VOLUME) pdbch;
        if (pdbcv->dbcv_flags == DBTF_MEDIA)
            // pdbcv->dbcv_unitmask identifies which logical drive
        }
        return TRUE;
    default:
        return TRUE;
    }


System Message Reference

This section describes the functions, messages, and structures that support system messages.


System Message Functions

This section describes the functions that support system messages.

BroadcastSystemMessage


System Messages Reference

This section describes the device messages.

DBT_CONFIGCHANGED
DBT_DEVICEARRIVAL
DBT_DEVICEQUERYREMOVE
DBT_DEVICEQUERYREMOVEFAILED
DBT_DEVICEREMOVECOMPLETE
DBT_DEVICEREMOVEPENDING
DBT_DEVICETYPESPECIFIC
WM_DEVICECHANGE


System Message Structures

This section describes the structures associated with device messages.

_DEV_BROADCAST_USERDEFINED
DEV_BROADCAST_HDR
DEV_BROADCAST_OEM
DEV_BROADCAST_PORT
DEV_BROADCAST_VOLUME


Tape Backup

The tape functions provided in the Microsoft® Win32® application programming interface (API) enable backup applications to read from and write to a tape, initialize a tape, and retrieve tape or tape drive information.


About Tape Backup

In Microsoft® Windows™, a tape volume consists of a recording medium and its physical carrier. The entire length of tape in a volume is not available for recording data. Short sections at the beginning and the end of the tape are reserved for attaching the tape to the hubs in the carrier. The first position on the tape where data can be recorded is the called the beginning-of-medium marker, and the last position is called the end-of-medium marker.

Every tape volume has one or more partitions. A partition is a portion of the volume, containing its own beginning and ending points, that does not overlap with any other portion of the volume. Each partition has three predefined positions. The first position in a partition where you can record data is called the beginning-of-partition marker, and the last is called end-of-partition marker. The early-warning position is located immediately before the end-of-partition marker. The early-warning position notifies tape applications to transfer buffered data to the tape before reaching the end-of-partition marker.

The area between a partition's beginning and ending points is typically divided into sections by filemarks or setmarks. Filemarks and setmarks are special recorded elements that do not contain user data; they simply divide the partition into smaller areas to provide an address scheme. Filemarks and setmarks serve similar purposes, but setmarks provide faster positioning on high-capacity tape drives.

Typically, tape devices support filemarks and setmarks. Support of both enables tape data to be formatted such that setmarks separate data from different disk volumes and filemarks separate data from individual files on a disk volume.

Another recorded element that denotes locations on the tape is an erase gap, an area of erased tape or a pattern that the device does not recognize as a mark or as user data.

There are three types of filemarks. A short filemark contains a short erase gap that cannot be overwritten unless the write operation is performed from the beginning of the partition or from an earlier long filemark. A long filemark contains a long erase gap that enables an application to position the tape at the beginning of the filemark and to overwrite the filemark and the erase gap. A normal filemark does not contain an erase gap. Tape devices that use filemarks support either short and long filemarks or normal filemarks, but not all three.

The area on a partition between setmarks or filemarks is available for recording data. A unit of data written to or read from a tape is referred to as a block.


Tape Initialization

An application must use the CreateFile function to create a handle of a tape device. This handle is used in subsequent operations on the tape in the device.

Before an application writes to a tape, the tape must be formatted according to the needs of the application and the capabilities of the tape drive being used. The CreateTapePartition function reformats a tape, creating on it a given number of partitions of a specified size.

The PrepareTape function prepares a tape to be accessed or removed. This function can load, unload, lock, or unlock a tape. This function can also tension the tape by moving the tape to the end of the tape and back to the beginning.

To retrieve and set information about a tape and tape drive, an application uses the GetTapeParameters, SetTapeParameters, and GetTapeStatus functions.

GetTapeParameters retrieves information that describes a tape or a tape drive. The tape information includes the tape's type, density, and block size; the number of partitions on the tape; the amount of tape remaining; and so on. The tape drive information includes the drive's default block size, the maximum partition count, and the features that are supported.

SetTapeParameters either sets the tape block size or sets the tape drive flags that indicate whether the drive supports hardware error correction, data compression, data padding, or any combination of the three.

GetTapeStatus indicates whether the tape drive is ready to process tape commands.


Tape Input and Output

The Win32 API provides several functions that applications can use to perform input and output (I/O) on a tape drive. Tape I/O is similar to I/O performed on a communications device.

When performing tape I/O, some tape drives store tape firmware information in the first few blocks on a tape, typically using some portion of the first 100 blocks. Applications should not use those blocks. More specific information on this subject is available from individual tape system manufacturers. In general, an application that skips the first 100 blocks on a tape will avoid tape drive idiosyncracies.

The GetTapePosition and SetTapePosition functions retrieve and move the current tape position. The WriteTapemark function writes a specified number of setmarks, filemarks, short filemarks, and long filemarks. The EraseTape function erases all or part of a tape.

The ReadFile and WriteFile functions read and write file data from and to the tape. The data is read and written in complete blocks. If the tape's block size is 512 bytes, all read and write operations must use buffers that are simple integer multiples of that block size: 512, 1024, 1536, 2048, and so on. Most, if not all, drives only allow a write operation after the tape is rewound or after a read operation produces an end-of-data error message.

If ReadFile encounters a filemark, the data up to the filemark is read and the function fails. (The GetLastError function returns an error code indicating the type of filemark that was encountered.) To continue reading beyond the filemark, an application must move the tape past the filemark and call ReadFile again.

ReadFile and WriteFile read and write only the data stream. The BackupRead and BackupWrite functions read and write all the streams associated with a file. These include data, extended attributes, security, and alternative data streams. The security and alternate data streams are relevant only on the new technology file system (NTFS) partition.

The BackupSeek function seeks forward in a file initially accessed by BackupRead or BackupWrite. This function enables an application to skip information that causes access errors.

If an application needs to access only the file data, it should use ReadFile and WriteFile. These functions can also read alternative data streams if the streams were created by using the CreateFile function.

A tape-backup application must use BackupRead and BackupWrite to copy all information pertaining to a file. However, these functions do not read or write file characteristics such as attributes, file creation time, and so on. Applications must use the file input and output functions, such as GetFileAttributes and SetFileAttributes, to retrieve and set those values.


Using Tape Backup

•	Creating a backup application

•	Backing up and restoring Posix file links


Creating a Backup Application

To perform any input or output on a tape, a backup application must first obtain a handle of the tape device. The following code sample shows how to use the CreateFile function to open a tape device.

HANDLE hTape;   /* handle to tape device */

hTape = CreateFile(

    "\\\\.\\TAPE0",     /* name of tape device to open */

    GENERIC_READ | GENERIC_WRITE, /* read-write access */

    0,                    /* not used                  */

    0,                    /* not used                  */

    OPEN_EXISTING,        /* required for tape devices */

    0,                    /* not used                  */

    NULL);                /* not used                  */

To back up a directory tree to a tape, an application must use the FindFirstFile and FindNextFile functions to traverse the directory tree. Each time a file is found, the application should get the file's attributes by using the GetFileAttributes function. If there are hard links, the application should determine the number of links and save the file's unique identifier in a table for future comparisons. The first time a file is found, the application should use CreateFile to open the file and the BackupRead function to begin the backup. Then it can use the WriteFile function repeatedly to transfer all the information in the buffer filled by BackupRead to the tape. The second time a file is found (checked against the table of file identifiers when there are hard links), the application can simply write the general file information to the tape, followed by a stream whose identifier is BACKUP_LINK.

When restoring files from tape to disk, an application must use the CreateFile, BackupWrite, and ReadFile functions. For each file on the tape, the application should use CreateFile to create a new file on disk and BackupWrite to begin restoring the file. Then it should use ReadFile repeatedly until all the information for the file has been read from the tape into the buffer filled by BackupWrite. If one of the streams in the BackupWrite buffer has a BACKUP_LINK stream identifier, the application must establish a hard link. If the data needed to establish the link does not exist, BackupWrite fails. The application can use a preexisting catalog to locate and restore the original data, or it can notify the user that the file data to be restored is in a different location.


Backing Up and Restoring Posix File Links

A backup application can use the BackupWrite function to recreate Posix file links.

The BackupRead function does not return Posix file link data. A backup application must maintain the link information itself. The following pseudocode presents algorithms for backing up and restoring Posix file link data along with other file information.

PseudoCode Algorithm for Backing Up Posix File Links

1.  Initialize and empty a list of known links.

2.  While there are more files to back up

3.     Read the disk and get the next file.

4.     Open the file for read.

5.     Call GetFileInformationByHandle() to get the

          NumberOfLinks and the FileIndex.

6.     If the NumberOfLinks is greater than 1

7.        Search the list of know links looking for

             the same FileIndex.

8.           If a match is NOT found

9.              add the full path of the file and the

                   FileIndex to the list.

10.             Call BackupRead() to copy all data to

                   your backup media.

10.          Else

11.             Mark the data as a LINK on your backup media

11.             store the full path from the list

                   to your backup media.

12.          Endif

13.    Else

14.       Call BackupRead() to copy all data to your

             backup media.

15.    Endif

16. EndWhile

PseudoCode Algorithm for Restoring Posix File Links

1.  While there are more files to restore

2.     If the file is a LINK

3.        use the full path which was saved as data

             to open the file.

4.        Initialize a WIN32_STREAM_ID structure with

             dwStreamId equal to BACKUP_LINK.

5.        Initialize the dwStreamAttributes to 0.

6.        Initialize the dwStreamNameSize to 0.

7.        Initialize a buffer containing the full path

             of the file you are restoring in UNICODE.

8.        Initialize the dwStreamSizeHigh to 0.

9.        Initialize the dwStreamSizeLow to the size

             in bytes of the buffer     containing the full path.

10.       Call BackupWrite() with the WIN32_STREAM_ID

11.       Call BackupWrite() with the buffer containing

             the full path.

13.          Else

14.       Call BackupWrite() with the data stored on

             your backup media.

15.    Endif

16. EndWhile


Tape Backup Functions

Following are the functions used for tape backup.

BackupRead
BackupSeek
BackupWrite
CreateTapePartition
EraseTape
GetTapeParameters
GetTapePosition
GetTapeStatus
PrepareTape
SetTapeParameters
SetTapePosition
WriteTapemark


Time

The Microsoft® Win32® application programming interface (API) provides a variety of date and time functions, structures, and messages to retrieve and set the date and time for the system, files, and the local time zone.


About Time

This overview describes various functions, structures, and messages and explains how to use them to examine and modify dates and times.

For information about related topics, see the following overviews:

•	Files

•	File Systems


System Time

System time is the current date and time of day. Windows keeps system time so that your applications have ready access to accurate time. When Windows first starts, it sets the system time to a value based on the real-time clock of the computer and thereafter regularly updates the time.

Windows bases system time on coordinated universal time (UTC). UTC-based time is loosely defined as the current date and time of day in Greenwich, England. You can retrieve the system time by using the GetSystemTime function. GetSystemTime copies the time to a SYSTEMTIME structure that contains individual members for month, day, year, weekday, hour, minute, second, and milliseconds.

Because system time is UTC-based, the time copied to the SYSTEMTIME structure may not be the same as the local time—the date and time of day for your time zone. You can retrieve the local time by using the GetLocalTime function. GetLocalTime converts the system time to a local time based on the current time-zone settings and copies the result to a SYSTEMTIME structure.

The current time-zone settings control how Windows converts between UTC and local time. You can retrieve the current time-zone settings by using the GetTimeZoneInformation function. The function copies the setting to a TIME_ZONE_INFORMATION structure and returns a value indicating whether local time is currently in standard or daylight-savings time. You can set the time-zone settings by using the SetTimeZoneInformation function.

You can set the system time by using the SetSystemTime or SetLocalTime function. SetSystemTime assumes you have specified a UTC-based time; SetLocalTime assumes local time and converts to UTC before setting the system time. If you change the system time, you should send the WM_TIMECHANGE message to all top-level windows by using the SendMessage function.


Windows Time

Windows time is the number of milliseconds elapsed since Windows started running. To ensure that applications designed for earlier versions of Windows continue to run successfully, the GetTickCount and GetCurrentTime functions return the current Windows time. However, if your application requires the current date and time of day, you should use the GetSystemTime or GetLocalTime function whenever possible.

Because GetTickCount and GetCurrentTime are identical in operation, you should use GetTickCount to retrieve Windows time.You typically use GetTickCount to compare the current Windows time with the time returned by the GetMessageTime function. GetMessageTime returns the Windows time when the given message was created.

Windows time is stored as a 32-bit value, which means Windows can record no more than 2^32 millisecond intervals before the 32-bit value overflows to zero. This is approximately 49.7 days. If you use Windows time, check for the overflow condition when comparing times.


File Times

A file time represents the specific date and time at which a given file was created, last accessed, or last written to. Windows records file times whenever applications create, access, and write to files. Windows records the times using a 64-bit value specifying the number of 100-nanosecond intervals that have elapsed since 12:00 A.M. January 1, 1601 (UTC). Writing to a file changes the last write time; writing to or reading from the file (including running an executable file) changes the last access time.

Note  Not all file systems can record creation and last access time. In particular, the file allocation table (FAT) file system records only last-write times.

You can retrieve the file times for a given file by using the GetFileTime function. GetFileTime copies the creation, last access, and last write times to individual FILETIME structures. Each structure consists of two 32-bit values that combine to form the single 64-bit value. You can also retrieve the file times by using the FindFirstFile and FindNextFile functions. These functions copy the times to FILETIME structures in a WIN32_FIND_DATA structure.

You can set the file times for a file by using the SetFileTime function. This function lets you modify creation, last access, and last write times without changing the content of the file. You can compare the times of different files by using the CompareFileTime function. The function compares two file times and returns a value indicating which time is greater or returns zero if the times are equal.

To make a file time more meaningful to a user, you can extract the month, day, year, and time of day from a file time by using the FileTimeToSystemTime function. FileTimeToSystemTime converts the file time and copies the individual values for date and time of day to a SYSTEMTIME structure.

Windows records all file times in UTC-based times, but you can convert a file time to the local time for your time zone by using the FileTimeToLocalFileTime function. Before displaying a file time to a user, applications typically convert the file time to local time, then extract the month, day, year and time of day using FileTimeToSystemTime.

If you plan to modify file times for given files, you can convert a date and time of day to a file time by using the SystemTimeToFileTime function. If the original date and time of day are given in the local time for your time zone, you can convert the resulting file time to UTC by using the LocalFileTimeToFileTime function. Always make sure the file times you set using SetFileTime are valid UTC-based times.


MS-DOS Date and Time

MS-DOS date and MS-DOS time are packed 16-bit values that specify the month, day, year, and time of day an MS-DOS file was last written to. MS-DOS records the date and time whenever an MS-DOS application creates or writes to a file. MS-DOS applications retrieve this date and time using MS-DOS functions. When you use the GetFileTime function to retrieve the file times for files that were created by MS-DOS, GetFileTime automatically converts MS-DOS dates and times to UTC-based times.

If you encounter an MS-DOS date and time that has not been converted, you can convert it to a UTC-based time by using the DosDateTimeToFileTime function. This function copies the converted date and time to a FILETIME structure. You can convert the value back to an MS-DOS date and time by using the FileTimeToDosDateTime function.


Using Time

•	Retrieving the last-write time

•	Changing a file time to the current time

•	Setting the system time


Retrieving the Last-Write Time

The following example retrieves the last-write time for a file, converts it to local time based on the current time-zone settings, and creates a date and time string that can be shown to the user.

// GetLastWriteTime - retrieves the last-write time and converts the
//                      time to a string
// Return value - TRUE if successful, FALSE otherwise
// hFile      - must be a valid file handle
// lpszString - address of buffer to receive string

BOOL GetLastWriteTime(HANDLE hFile, LPSTR lpszString)
{
    FILETIME ftCreate, ftAccess, ftWrite, ftLocal;
    SYSTEMTIME stCreate;

    // Retrieve the file times for the file.
    if (!GetFileTime(hFile, &ftCreate, &ftAccess, &ftWrite))
        return FALSE;

    // Convert the last-write time to local time.
    if (!FileTimeToLocalFileTime(&ftWrite, &ftLocal))
        return FALSE;

    // Convert the local file time from UTC to system time.
    FileTimeToSystemTime(&ftLocal, &stCreate);

    // Build a string showing the date and time.
    wsprintf(lpszString, "%02d/%02d/%d  %02d:%02d",
        stCreate.wDay, stCreate.wMonth, stCreate.wYear,
        stCreate.wHour, stCreate.wMinute);

    return TRUE;
}


Changing a File Time to the Current Time

The following example sets the last-write time for a file to the current system time.

// SetFileToCurrentTime - sets last write time to current system time
// Return value - TRUE if successful, FALSE otherwise
// hFile  - must be a valid file handle

BOOL SetFileToCurrentTime(HANDLE hFile)
{
    FILETIME ft;
    SYSTEMTIME st;
    BOOL f;

    GetSystemTime(&st);              // gets current time
    SystemTimeToFileTime(&st, &ft);  // converts to file time format
    f = SetFileTime(hf,              // sets last-write time for file
        (LPFILETIME) NULL, (LPFILETIME) NULL, &ft);

    return f;
}


Setting the System Time

The following example sets the system time.

// SetNewTime - sets system time
// Return value - TRUE if successful, FALSE otherwise
// hour     - new hour (0-23)
// minutes  - new minutes (0-59)

BOOL SetNewTime(WORD hour, WORD minutes)
{
    SYSTEMTIME st;
    char *pc;

    GetSystemTime(&st);       // gets current time
    st.wHour = hour;          // adjusts hours
    st.wMinute = minutes;     // and minutes
    if (!SetSystemTime(&st))  // sets system time
        return FALSE;
    return TRUE;
}


Date and Time Functions
Time Functions

Following are the functions used with time formats.

CompareFileTime
DosDateTimeToFileTime
FileTimeToDosDateTime
FileTimeToLocalFileTime
FileTimeToSystemTime
GetCurrentTime
GetFileTime
GetLocalTime
GetSystemTime
GetSystemTimeAdjustment
GetSystemTimeAsFileTime
GetTickCount
GetTimeZoneInformation
LocalFileTimeToFileTime
SetFileTime
SetLocalTime
SetSystemTime
SetSystemTimeAdjustment
SetTimeZoneInformation
SystemTimeToFileTime
SystemTimeToTZSpecificLocalTime


Window Stations and Desktops

This overview describes the new window station and desktop functionality, and is primarily intended for developers of Win32 services. Developers of typical applications that will be run by the logged-on user do not need to be concerned about window stations and desktops.

Beginning with Microsoft® Windows NT™ version 3.5, the Win32® API provides new window station and desktop functionality that enables Win32 services to call USER32 and GDI32 functions regardless of the logon account in which the service is running. This new functionality enables Win32 services to make these calls while maintaining the security of applications running in the account of the logged-on interactive user.

For more information on how Win32 services use the window station and desktop support, see Interactive Services.


Window Stations

A window station is a secure object that contains a clipboard, a set of global atoms and a group of desktop objects. The interactive window station assigned to the logon session of the interactive user also contains the keyboard, mouse, and display device. The interactive window station is visible to the user and can receive input from the user. All other window stations are noninteractive, which means that they cannot be made visible to the user, and cannot receive user input.

Applications can use the following functions for manipulating window station objects:

Function	Description
CloseWindowStation	Closes a specified window station.
CreateWindowStation	Creates a new window station.
EnumWindowStations	Enumerates the window stations in the system by repeatedly calling an application-defined EnumWindowStationProc callback function.
GetProcessWindowStation	Returns a handle of the window station assigned to the calling process.
GetUserObjectInformation	Gets information about a window station or desktop object.
GetUserObjectSecurity	Gets security information for a window station or desktop object.
OpenWindowStation	Opens a handle of an existing window station.
SetProcessWindowStation	Assigns a specified window station to the calling process.
SetUserObjectInformation	Sets information about a window station or desktop object.
SetUserObjectSecurity	Sets security information for a window station or desktop object.


Desktops

A desktop is a secure object contained within a window station. A desktop has a logical display surface and contains windows, menus, and hooks. A window station can have multiple desktops. Only the desktops of the interactive window station can be visible and receive user input. On the interactive window station, only one desktop at a time is active. This active desktop, also known as the input desktop, is the one that is currently visible to the user and that receives user input. Applications can use the OpenInputDesktop function to get a handle of the input desktop. Applications that have the necessary access can use the SwitchDesktop function to specify a different input desktop.

Invisible, noninteractive window stations enable Win32 services that do not have access to the interactive window station to start GUI applications. Applications running in a noninteractive window station cannot receive input or be visible. For example, the schedule service could use this support to start a GUI backup application on a remote computer on which the interactive window station was not accessible. For more information, see Interactive Services.

Applications can use the following functions for manipulating desktop objects:

Function	Description
CloseDesktop	Closes a specified desktop.
CreateDesktop	Creates a new desktop on a specified window station.
EnumDesktops	Enumerates the desktops on a specified window station by repeatedly calling an application-defined EnumDesktopProc callback function.
EnumDesktopWindows	Enumerates the windows on a specified desktop by repeatedly calling an application-defined EnumWindowsProc callback function.
GetThreadDesktop	Returns a handle of the desktop assigned to the calling thread.
GetUserObjectInformation	Gets information about a window station or desktop object.
GetUserObjectSecurity	Gets security information for a window station or desktop object.
OpenDesktop	Opens a handle of an existing desktop.
SetThreadDesktop	Assigns a specified desktop to the calling thread.
SetUserObjectInformation	Sets information about a window station or desktop object.
SetUserObjectSecurity	Sets security information for a window station or desktop object.


Window Station and Desktop Creation

The system automatically creates the interactive window station. When an interactive user logs on, the system associates the interactive window station with the user's logon session. The system also creates the default input desktop for the interactive window station.

When a noninteractive process such as a Win32 service attempts to connect to Win32 and no window station exists for the process' logon session, Win32 attempts to create a window station and desktop for the session. The name of the created window station is based on the logon session identifier, and the desktop is named "Default." The discretionary access control lists (DACLs) for the window station and desktop grant the following accesses to the service's user account:

Window Station: WINSTA_READATTRIBUTES | WINSTA_ACCESSCLIPBOARD | WINSTA_CREATEDESKTOP | WINSTA_ACCESSGLOBALATOMS | WINSTA_EXITWINDOWS | STANDARD_RIGHTS_REQUIRED

Desktop: DESKTOP_READOBJECTS | DESKTOP_WRITEOBJECTS | DESKTOP_CREATEWINDOW | DESKTOP_CREATEMENU | DESKTOP_HOOKCONTROL | DESKTOP_ENUMERATE | STANDARD_RIGHTS_REQUIRED

A process can use the CreateWindowStation function to create a new window station, and the CreateDesktop function to create a new desktop.


Process Connection to a Window Station

A process automatically establishes a connection to a window station and desktop when it first calls a USER32 or GDI32 function (other than the window station or desktop functions) that must go to the Win32 server. The Win32 server determines the window station to which a process connects according to the following rules:

1.	If the process has called the SetProcessWindowStation function, it connects to the window station specified in that call.

2.	If the process did not call SetProcessWindowStation, it connects to the window station inherited from the parent process.

3.	If the process did not call SetProcessWindowStation and did not inherit a window station, the Win32 server attempts to open for MAXIMUM_ACCESS and connect to a window station as follows:

a.	If a window station name was specified in the lpDesktop member of the STARTUPINFO structure that was passed to the CreateProcess function when the process was created, the process connects to the specified window station.

b.	Otherwise, if the process is running in the logon session of the interactive user, the process connects to the interactive window station.

c.	If the process is running in a noninteractive logon session, the window station name is formed based on the logon session identifier and an attempt is made to open that window station. If the open operation fails because this window station does not exist, Win32 tries to create the window station and a default desktop.


Thread Connection to a Desktop

After a process connects to a window station, the Win32 server assigns a desktop to the thread making the connection to Win32. The desktop assigned during this connection process cannot be closed by calling the CloseDesktop function. The Win32 server determines the desktop to assign to the thread according to the following rules:

1.	If the thread has called the SetThreadDesktop function, it connects to the specified desktop.

2.	If the thread did not call SetThreadDesktop, it connects to the desktop inherited from the parent process.

3.	If the thread did not call SetThreadDesktop and did not inherit a desktop, the Win32 server attempts to open for MAXIMUM_ACCESS and connect to a desktop as follows:

a.	If a desktop name was specified in the lpDesktop member of the STARTUPINFO structure that was passed to the CreateProcess function when the process was created, the thread connects to the specified desktop.

b.	Otherwise, the thread connects to the default desktop of the window station to which the process connected.

The desktop assigned during this connection process cannot be closed by calling the CloseDesktop function.


Inherited Handles

When a process is connecting to a window station or desktop, the Win32 server searches the process's handle table for inherited handles. The Win32 server uses the first window station and desktop handles that it finds. If you want a child process to connect to a particular inherited window station or desktop, you must ensure that the only the desired handles are marked inheritable. If a child process inherits multiple window station or multiple desktop handles, the results of the window station and desktop connection are undefined.

Handles to a window station and desktop that the Win32 server opens while connecting a process to a window station or desktop are not inheritable.


Logoff Events

A logoff event occurs when a process calls the ExitWindows or ExitWindowsEx function. The logoff event is identified by the window station of the process calling ExitWindowsEx.

When a logoff event occurs, the system notifies all processes in the system as follows:

•	All windows of processes in the logon session being logged off receive the WM_QUERYENDSESSION and WM_ENDSESSION messages. All windows on the desktops of the window station being logged off receive these messages, even if the windows belong to processes running in another logon session.

•	Every process in the system receives the CTRL_LOGOFF_EVENT control signal. This signal does not indicate which session is being logged off. The system sends this signal after sending the window messages. For more information on control signals, see the SetConsoleCtrlHandler function.

If the process that called ExitWindowsEx is running in the logon session of the interactive user, all processes in the logon session are terminated. If the process calling ExitWindowsEx is in some other logon session, only the notifications are made; no processes are terminated.


Using Window Stations and Desktops

•	Creating an interactive process

•	Interacting with the user by a win32 service

•	Handling logoff events


Creating an Interactive Process

The following code fragment shows how a Win32 service process could use the STARTUPINFO structure in a CreateProcess call to create a process that has access to the user's interactive window station and default desktop. A noninteractive Win32 service could use this technique to interact with the logged on user. The new process could then use a named pipe or some other means of interprocess communication to communicate with the Win32 service.

To create an interactive process as shown in this example, a Win32 service must be logged in to the LocalSystem account.

#include <windows.h>

STARTUPINFO si;

PROCESS_INFORMATION ProcessInformation;

si.cb = sizeof(STARTUPINFO);

si.lpReserved = NULL;

si.lpTitle = NULL;

si.lpDesktop = "WinSta0\\Default";

si.dwX = si.dwY = si.dwXSize = si.dwYSize = 0L;

si.dwFlags = 0;;

si.wShowWindow = SW_SHOW;

si.lpReserved2 = NULL;

si.cbReserved2 = 0;

if (CreateProcess(NULL, lpszCmdLine, NULL, NULL, FALSE,

                   0, NULL, NULL, &si, &ProcessInformation)) {

    CloseHandle(ProcessInformation.hProcess);

    CloseHandle(ProcessInformation.hThread);

}


Interacting with the User by a Win32 Service

For a noninteractive Win32 service to interact with the user, it must open the user's window station ("WinSta0") and desktop ("Default"). By default, only the logged-on user and Win 32 services running in the LocalSystem account are granted access to the user's window station and desktop. This means that services running in other accounts must either impersonate the user when opening the interactive window station and desktop, or have access granted to those accounts by the user.

For compatibility with future versions of Windows NT that may support multiple users and/or multiple desktops per user, the user's window station and desktop names should not be hard-coded. Client applications should pass the names of their window station and desktop to the service as part of the request to the service.

This code sample displays a message on the user's desktop in response to an RPC request from one of the user's applications. Note that a global variable dwGuiThreadId in this example is also used in the logoff handling example. If the thread that displays the message box terminates after it is done with the message box, it is not necessary to save and restore the thread's desktop. It is necessary to restore the process's window station.

DWORD dwGuiThreadId = 0;

int

UserMessageBox(

    RPC_BINDING_HANDLE h,

    LPSTR lpszWindowStation,

    LPSTR lpszDesktop,

    LPSTR lpszText,

    LPSTR lpszTitle,

    UINT fuStyle)

{

    DWORD dwThreadId;

    HWINSTA hwinstaSave;

    HDESK hdeskSave;

    HWINSTA hwinstaUser;

    HDESK hdeskUser;

    int result;

    /*

     * Ensure connection to service window station and desktop, and

     * save their handles.

     */

    GetDesktopWindow();

    hwinstaSave = GetProcessWindowStation();

    dwThreadId = GetCurrentThreadId();

    hdeskSave = GetThreadDesktop(dwThreadId);

    /*

     * Impersonate the client and connect to the User's

     * window station and desktop.

     */

    RpcImpersonateClient(h);

    hwinstaUser = OpenWindowStation(lpszWindowStation, FALSE, MAXIMUM_ALLOWED);

    if (hwinstaUser == NULL) {

        RpcRevertToSelf();

        return 0;

    }

    SetProcessWindowStation(hwinstaUser);

    hdeskUser = OpenDesktop(lpszDesktop, 0, FALSE, MAXIMUM_ALLOWED);

    RpcRevertToSelf();

    if (hdeskUser == NULL) {

        SetProcessWindowStation(hwinstaSave);

        CloseWindowStation(hwinstaUser);

        return 0;

    }

    SetThreadDesktop(hdeskUser);

    /*

     * Display message box.

     */

    dwGuiThreadId = dwThreadId;

    result = MessageBox(NULL, lpszText, lpszTitle, fuStyle);

    dwGuiThreadId = 0;

    /*

     * Restore window station and desktop.

     */

    SetThreadDesktop(hdeskSave);

    SetProcessWindowStation(hwinstaSave);

    CloseDesktop(hdeskUser);

    CloseWindowStation(hwinstaUser);

    return result;

}


Handling Logoff Events

Win32 services that interact with the user should be prepared to handle logoff events. When a logoff event occurs, the Win32 service must close all handles to the user's window station and desktop.

This sample demonstrates how the message box in the interaction example code should be dismissed at logoff. The ConsoleCtrlHandler function in this example is a HandlerRoutine that was specified by a call to the SetConsoleCtrlHandler function.

BOOL CALLBACK EnumProc(

    HWND hwnd,

    LPARAM lParam)

{

    /*

     * Send a WM_CLOSE to destroy the window, because DestroyWindow does

     * not work across threads.

     */

    SendMessage(hwnd, WM_CLOSE, 0, 0);

    return TRUE;

}

BOOL ConsoleCtrlHandler(

    DWORD dwCtrlType)

{

    if (dwCtrlType == CTRL_LOGOFF_EVENT && dwGuiThreadId != 0) {

        SetThreadDesktop(GetThreadDesktop(dwGuiThreadId));

        EnumThreadWindows(dwGuiThreadId, EnumProc, 0);

    }

    return FALSE;

}


Window Station and Desktop Reference

The following functions and structures are associated with window station and desktop features.


Window Station and Desktop Functions

Use the following functions to implement window station and desktop features:

CloseDesktop
CloseWindowStation
CreateDesktop
CreateWindowStation
EnumDesktops
EnumDesktopWindows
EnumWindowStations
GetProcessWindowStation
GetThreadDesktop
GetUserObjectInformation
GetUserObjectSecurity
OpenDesktop
OpenInputDesktop
OpenWindowStation
SetProcessWindowStation
SetThreadDesktop
SetUserObjectInformation
SetUserObjectSecurity
SwitchDesktop


Window Station and Desktop Structures

Use the following structure to manipulate window station and desktop objects:

USEROBJECTFLAGS


End User Defined Characters

End-user-defined characters (EUDC) are customized characters that users install for viewing and printing documents.

This overview discusses the TrueType fonts that support end-user-defined characters and describes the functions used to access and manage these characters in Win32-based applications.


About End User Defined Characters

End-user-defined characters give users a way to form names and other words using characters that are not available in standard screen and printer fonts.

End-user-defined characters are available only in Asian-language versions of the Microsoft Windows operating system.


Character Sets and Fonts

An end-user-defined character is always associated with a double-byte character set (DBCS) and a TrueType font. Applications identify the specified character by using the character's assigned DBCS character value, and the operating system uses this value to locate shape and style information in a corresponding TrueType font. The shape and style information specifies how the character is drawn on the screen or printed page.

The DBCS character values that can be assigned depend on the specified character set. Each set has at least one range of reserved values for use as end-user-defined characters. The system or applications explicitly define these ranges by setting appropriate values under the EUDCCodeRange key in the registry. In the registry, each character set is identified by a unique code-page number.

To create an end-user-defined character, the user chooses a character value that is within the specified range and adds the shape and style information to the TrueType font in the entry that corresponds to that character value. Users create the shape and style information using an EUDC editor or by purchasing end-user-defined font packages from font vendors. Any DBCS TrueType font can contain end-user-defined characters. The font is called a "separate" EUDC font if it contains only end-user-defined characters. The font is an "integrated" EUDC font if it contains standard characters as well as end-user-defined characters.

Separate EUDC fonts are said to be either "typeface-aware" or "typeface-unaware." A typeface-unaware font is designed to be a general purpose font that can be used with fonts of different typeface styles and of different implementations, such as GDI raster, WIFE, device, and TrueType fonts. A typeface-aware font is designed for use with a specific TrueType font.

The system default EUDC font is a typeface-unaware font that the system automatically associates with all DBCS fonts except those TrueType fonts that have explicitly associated typeface-aware fonts. Applications set the system default EUDC font by setting the value of the SystemDefaultEUDCFont name under the EUDC key in the registry. Similarly, applications can associate typeface-aware fonts with corresponding TrueType fonts by specifying a typeface name and associated font file under the EUDC key. Separate EUDC fonts cannot be associated with integrated EUDC fonts.

The system "hides" the system default EUDC and typeface-aware fonts. This means applications cannot enumerate or otherwise examine these fonts using GDI functions. Applications, such as EUDC editors and Control Panel, must use the registry entries to add, modify, and delete EUDC fonts.

End-user-defined characters can also be used in Unicode-enabled applications. The reserved ranges for each character set are mapped to corresponding values in the Unicode private use area (values 0xE000 and higher). There are mappings for both Japanese and Chinese character sets. For a list of these mappings, see Japanese EUDC Ranges and Chinese EUDC Ranges.


Writing, Mapping, and Sorting Characters

Applications write end-user-defined characters to the screen or printer the same way as writing other characters, by using output functions such as TextOut and ExtTextOut. These functions automatically retrieve character information from EUDC fonts if EUDC is enabled. When writing end-user-defined characters, the action of the text output function depends on the currently selected font. If the selected font is an integrated EUDC font, the function retrieves character information from that font. If the selected font is a DBCS TrueType font that has an associated typeface-aware EUDC font, the function retrieves information from the specified typeface-aware font. If the selected font does not have an associated typeface-aware font, the function retrieves information from the system default EUDC font. If the character is not in the system default EUDC font or there is no system default EUDC font, the function writes the default character defined by the selected font.

Applications can map end-user-defined characters to and from Unicode by using the MultiByteToWideChar and WideCharToMultiByte functions. The MultiByteToWideChar function maps an end-user-defined character to a character position in the Unicode private use area. The WideCharToMultiByte function maps a character in the private use area to its multibyte character counterpart, if such a mapping exists. The code page specified in this function must contain an EUDC code range for the mapping to occur. If it does not, the function returns the default character for any characters in the Unicode private use area.

Both MultiByteToWideChar and WideCharToMultiByte preserve the "round trip" mapping of end-user-defined characters from a code page to Unicode and back to the original code page. But these functions do not necessarily preserve mapping to other code pages. For example, if a character from code page 932 is mapped to Unicode, then mapped from Unicode to another code page with an EUDC range, it is likely that the original character will be mapped to a different end-user-defined character in the destination code page. Similarly, mapping a Unicode string to a code page that has an EUDC range may have unintended results. If the Unicode string contains a private-use code point, that code point may be mapped to an end-user-defined character whether or not the code point actually represents such a character.

Applications can compare strings that contain end-user-defined characters by using the CompareStringA function. The function maps the characters to the Unicode end user zone before comparing character values. Applications can create a sort key for the string by using the LCMapStringA function and the LCMAP_SORTKEY value. This function maps characters to Unicode first. All characters in the private use area are sorted after all other Unicode characters. Within the area, characters are sorted in numerical order. If an application attempts to retrieve CTYPE ifnormation for an end-user-defined character by using the GetStringTypeA function, the function returns NULL for each character.


End User Defined Character Reference

This section provides reference information on:

•	Registry entries.

•	End user defined character constants.


Registry Entries

The following registry information shows the appropriate entries for use with end user defined characters.


EUDCCodeRange

EUDCCodeRange
    CodePage=FromTo[,FromTo]

The EUDCCodeRange registry entry contains entries that define end-user-defined characters (EUDC) code ranges for the various code pages (character sets).

EUDCCodeRange Key

The EUDCCodeRange key has the following location in the registry:

HKEY_LOCAL_MACHINE\ 	System\CurrentControlSet\Control\NLS\CodePage\EUDCCodeRange

The key contains one or more values specifying the range of character values within a codepage that are available for end-user-defined characters. Under this key, a value name is one of these code-page values:

Value	Meaning
932	Japan
936	Simplified Chinese
949	Unified Hangeul Code (Hangeul TongHabHyung Code)
950	Traditional Chinese
1361	Johab
The value associated with each name is a string consisting of one or more pairs of 4-digit hexadecimal numbers, with the numbers in each pair separated by a hyphen (-) and each pair separated from any preceding pair by a comma (,). The following example illustrates this format:

HKEY_LOCAL_MACHINE\

System\CurrentControlSet\Control\NLS\CodePage\EUDCCodeRange

923=F040-F9FC

950=FA40-FEFE, 8E40-A0FE, 8140-8DFE, C6A1-C8FE

CodePage

A user-defined value name that identifies the code page. It must be the letters "CP" followed by 5 decimal digits specifying the code page.

FromTo

A string value consisting of a pair of 4-digit hexadecimal values separated by a hyphen (-). Multiple FromTo values may be specified, but each must be separated from the previous by a comma (,).

The following examples show possible EUDC ranges for code pages 923 and 950:

CP00923=F040-F9FC
CP00950=FA40-FEFE,8E40-A0FE,8140-8DFE,C6A1-C8FE


EUDC

EUDC
    SystemDefaultEUDCFont=TrueTypeEUDCFontFileName
    TrueTypeFontTypeface=TrueTypeEUDCFontFileName

EUDC Key

The EUDC registry key has the following location in the registry:

HKEY_CURRENT_USER\EUDC

The EUDC key contains one or more subkeys with each subkey containing values defining the fonts associated with end-user-defined characters for a given code page. Under the EUDC, a subkey name can be one of these code-page numbers:

Value	Meaning
932	Japan
936	Simplified Chinese
949	Unified Hangeul Code (Hangeul TongHabHyung Code)
950	Traditional Chinese
1361	Johab
One value under the subkey has the name SystemDefaultEUDCFont. Other values, if any, have names that identify a typeface. The values associated with these names are strings specifying the name of TrueType font file containing the given font. The following example shows the EUDC key for code page 932:

HKEY_CURRENT_USER\EUDC\932

SystemDefaultEUDCFont=EUDC.TTF

MS Mincho=MINEUDC.TTF

MS Gothic=GTEUDC.TTF

SystemDefaultEUDCFont

Predefined value name used to set the system default font. The corresponding value must be a string that identifies a typeface-unaware EUDC font. There is no system default EUDC font unless this entry is explicitly specified.

TrueTypeFontTypeface

A user-defined value name that identifies the typeface name associated with a TrueType font. The corresponding value must be a string that identifies a typeface-aware EUDC font.

TrueTypeEUDCFontFileName

A string value consisting of the filename of a "separate" EUDC font file.

The following example sets the system default EUDC font to be EUDC.TTF and associates the typeface-aware fonts, MINEUDC.TTF and GOTEUDC.TTF, with the typeface names "MS Mincho" and "MS Gothic":

SystemDefaultEUDCFont=EUDC.TTF
MS Mincho=MINEUDC.TTF
MS Gothic=GOTEUDC.TTF


End User Defined Character Constants

The following constants are used with end user defined characters in the following Far Eastern languages.


Japanese EUDC Ranges

The following table shows the mapping between the Japanese Microsoft Standard Character Set (ShiftJIS) and Unicode.

Shift JIS	Unicode
F040	U+E000
F041	U+E001
F042	U+E002
:	:
F9FA	U+E755
F9FB	U+E756
F9FC	U+E757


Chinese EUDC Ranges

The following table shows the mapping between the Chinese character sets (BIG-5 and GB 2312-80) and Unicode.

BIG-5	Unicode
FA40 - FEFE	U+E000 - U+E310
8E40 - A0FE	U+E311 - U+EEB7
8140 - 8DFE	U+EEB8 - U+F6B0
C6A1 - C8FE	U+F6B1 - U+F8FF
GB 2312-80	Unicode
F8A1 - FEFE	U+E000 - U+E29F
AAA1 - AFFE	U+E2A0 - U+E4DF


Korean EUDC Ranges

The following table shows the mapping from Korean EUDC characters (Unified Hangeul Code) and Unicode.

Unified Hangeul	Unicode
C9A1 - C9FE	U+E000 - U+E05D
FEA1 - FEFE	U+E05E - U+E0BB


Input Method Editor

The input method editor (IME), available in Asian versions of the Microsoft Windows operating system, helps minimize the effort needed by users to enter text containing characters from Unicode and double-byte character sets.

This overview describes the IME and explains how to use the input method manager functions to create and manage IME windows.


About Input Method Editor

The input method editor relieves users of the need to remember all possible character values. Instead, the IME monitors the user's keystrokes, anticipates the characters the user may want, and presents a list of candidate characters from which to choose.

By default, the IME provides an IME window through which users enter keystrokes and view and select candidates. Applications developed for the Win32 application programming interface (API) can use the input method manager (IMM) functions and messages to create and manage their own IME windows, providing a custom interface while using the conversion capabilities of the IME.


Status, Composition, and Candidates Windows

The status, composition, and candidates windows form the user interface for the IME. The status window indicates that the IME is open and provides the user the means to set the conversion modes. The composition window appears when the user enters text and, depending on the conversion mode, either displays the text as entered or displays converted text. The candidates window appears in conjunction with the composition window. It contains a list of "candidates" (alternative characters) for the selected character or characters in the composition window. The user can scroll through the candidates list and select the desired character(s), then return to the composition window. The user can compose the desired text in this way until the composition string is finalized and the window is closed. The IME sends the composed characters to the application in the form of WM_IME_CHAR or WM_IME_COMPOSITION/GCS_RESULT messages. If the application does not process these messages, the DefWindowProc function translates them into one or more WM_CHAR messages.

By default, the system automatically creates and manages status, composition, and candidates windows for all windows that require text input. For many applications, this default processing is sufficient. These applications rely entirely on the system for IME support and are said to be IME-unaware because they are unaware of the many tasks the system carries out to manage the IME windows.

An IME-aware application, on the other hand, participates in the creation and management of IME windows. Such applications control the operation, position, and appearance of the default windows by sending messages to and by intercepting and processing messages intended for these windows. In some cases, applications create their own IME windows and provide complete processing for their custom status, composition and candidates windows.


IME Window Class

The "IME" window class is a predefined system global class that defines the appearance and behavior of the standard IME windows. The class is similar to common control classes in that you create a window of this class by using the CreateWindowEx function. Like static controls, an IME window does not respond to user input by itself. Instead, it notifies the IME of user input actions and processes control messages sent to it by the IME or applications to carry out a response to the user action.

IME-aware applications sometimes create their own IME windows using the IME class. This allows the application to take advantage of the default processing of the IME window while having control of the positioning of the window.


IME Messages

The system sends IME window messages to the window procedure of the application when certain event occur that affect the IME windows. For example, the system sends the WM_IME_SETCONTEXT message to the application when a window is activated. IME-unaware application pass these messages to the DefWindowProc function which sends them to the corresponding default IME window. IME-aware applications either process these messages or forward them the their own IME windows.

You can direct an IME window to carry out an action, such as change the position of composition window, by using the WM_IME_CONTROL message. The IME notifies the application about changes to the composition string by using the WM_IME_COMPOSITION message and about general changes to the status of the IME windows by sending the WM_IME_NOTIFY message.


Input Context

An input context is an internal structure, maintained by the IME, that contains information about the status of the IME and is used by IME windows. By default, the system creates and assigns an input context to each thread. Within the thread, this default input context is a shared resource and is associated with each newly created window.

To retrieve or set information in the IME, an application must first retrieve a handle to the input context associated with a given window. You retrieve the handle by using the ImmGetContext function. You can use the retrieved handle in subsequent calls to the input method manager functions to retrieve and set IME values, such as the composition window style, the composition style, and the status window position. Once you have finished using the context, you must release it using the ImmReleaseContext function.

Because the default input context is a shared resource, any changes you make to it apply to all windows in the thread. However, you can override this default behavior by creating and associating your own input context to one or more window of the thread. The changes you make to your own input context apply only to the windows with which it is associated.

You can create an input context by using the ImmCreateContext function. You assign the context to a window by using the ImmAssociateContext function. This function returns the handle of the previously associated input context. If you have not associated an input context with the window before, the returned handle is for the default input context. You should save this handle and later reassociate with the window if you no longer want to use your own input context.

Once an input context is associated with a window, the system automatically selects that context when the window is activated and receives the input focus. The style and other information in the input context affects subsequent keyboard input for that window, determining whether and how the IME operates.

You must destroy any input context you create before terminating your application. You destroy an input context by using the ImmDestroyContext function. Before destroying it, you must remove the input context from any association it has with windows in the thread by using the ImmAssociateContext function.


Composition String

The composition string is the current text in the composition window. This is the text that the IME converts to final characters. Each composition string consists of one or more clauses, where a clause is the smallest combination of characters that the IME can convert to a final character. You can get and set the composition string and get and set the composition string by using the ImmGetCompositionString and ImmSetCompositionString functions.

As the user enters text in the composition window, the IME tracks the status of the composition string. This status includes attribute information, clause information, typing information, and cursor position. You can retrieve the composition status by using the ImmGetCompositionString function.

In the attribute information array, all characters of one clause must have the same attribute. The attribute information is an array of 8-bit values that specifies the status of characters in the composition string. There is one value for each byte in the string, including one byte each for the lead and second bytes of any double-byte characters in the string. For each value in the array, bits 0 through 3 can be one combination of these values:

ATTR_INPUT
	Character being entered by the user. It is yet to be converted by the IME.
ATTR_INPUT_ERROR
	Character is the error character and cannot be converted by the IME.
ATTR_TARGET_CONVERTED
	Character converted by the IME. The user has selected this character and the IME has converted it.
ATTR_CONVERTED
	A converted character. The IME has already converted this character.
ATTR_TARGET_NOTCONVERTED
	Character being converted. The user has selected this character but the IME has not yet converted it.
All other values are reserved. In Japanese, any unconverted character having the ATTR_INPUT attribute is a Hiragana, Katakana, or alphanumeric character. In Korean, this character is a Hangeul character that is not converted by IME yet. In Traditional and Simplified Chinese, each IME may limit its character in some range.

You can retrieve the composition status by using the ImmGetCompositionString function.

The clause information is an array of 32-bit values that specify the positions of the clauses in the composition string. There is one value for each clause and a final value that specifies the length of the full string. Each value in the array specifies the offset, in bytes, from the beginning of the string to the clause. The first value is always 0 because the first clause always starts at the beginning of the string. For example, if a string has two clauses, the clause information has three values: the first value is 0, the second value is the offset of the second clause, and the third value is the length of the string.

The typing information a null-terminated character string representing the characters entered at the keyboard.

The cursor position is a value indicating the position of the cursor relative to the characters in the composition string. The value is the offset, in bytes, from the beginning of the string. If this value is 0, the cursor is immediately before the first character in the string. If the value is equal to the length of the string, the cursor is immediately after the last character. If -1, the cursor is not present.

You can set the composition string or elements of the composition status by using the ImmSetCompositionString function. To ensure that the composition window updates it appearance based on these changes, the function allows for generating a notification message to be sent to the window. Applications that set a combination of composition status elements typically set the fNotify parameter to FALSE for all but the last call to this function so that only one notification message is generated for the composition window.


Candidate Lists

A candidate list is a CANDIDATELIST structure consisting of an array of strings that specify the characters or character strings that the user may choose from. You can retrieve the candidate lists by using the ImmGetCandidateListCount and ImmGetCandidateList functions.


Hot Keys

Hot keys give the user a way to quickly change the input mode of the IME or to switch to another IME. Although applications cannot add hot keys to the system, they can initiate the same action as a hot key by using the ImmSimulateHotKey function.


Using Input Method Editor

•	Processing the WM_IME_COMPOSITION message


Processing the WM_IME_COMPOSITION Message

Applications that process the WM_IME_COMPOSITION message test the bits in lParam parameter and call the ImmGetCompositionString function to retrieve the indicated string or data. The following example checks for the result string, allocates sufficient memory for the string, and retrieves the result string from the IME:

HIMC hIMC;
HWND hWnd;
DWORD dwSize;
HGLOBAL hstr;
LPSTR lpstr;

case WM_IME_COMPOSITION:
    if (lParam & GCS_RESULTSTR) {
        hIMC = ImmGetContext(hWnd);

        If (!hIMC)
            MyError(ERROR_NULLCONTEXT);

        // Get the size of the result string.
        dwSize = ImmGetCompositionString(hIMC, GCS_RESULTSTR, NULL, 0);

        // increase buffer size for NULL terminator,
        //   maybe it is in UNICODE
        dwSize += sizeof(WCHAR);

        hstr = GlobalAlloc(GHND,dwSize);
        if (hstr == NULL)
             MyError(ERROR_GLOBALALLOC);

        lpstr = GlobalLock(hstr);
        if (lpstr == NULL)
             MyError(ERROR_GLOBALLOCK);

        // Get the result strings that is generated by IME into lpstr.
        ImmGetCompositionString(hIMC, GCS_RESULTSTR, lpstr, dwSize);
        ImmReleaseContext(hWnd, hIMC);

        // add this string into text buffer of application

        GlobalUnlock(hstr);
        GlobalFree(hstr);
    }


Input Method EditorReference

This section contains an alphabetical list of the input method editor functions, messages, and structures.


Input Method Editor Functions

This section describes the input method editor functions.

EnumRegisterWordProc
ImmAssociateContext
ImmConfigureIME
ImmCreateContext
ImmDestroyContext
ImmEnumRegisterWord
ImmEscape
ImmGetCandidateList
ImmGetCandidateListCount
ImmGetCandidateWindow
ImmGetCompositionFont
ImmGetCompositionString
ImmGetCompositionWindow
ImmGetContext
ImmGetConversionList
ImmGetConversionStatus
ImmGetDefaultIMEWnd
ImmGetDescription
ImmGetGuideLine
ImmGetIMEFileName
ImmGetOpenStatus
ImmGetProperty
ImmGetRegisterWordStyle
ImmGetStatusWindowPos
ImmGetVirtualKey
ImmInstallIME
ImmIsIME
ImmIsUIMessage
ImmNotifyIME
ImmRegisterWord
ImmReleaseContext
ImmSetCandidateWindow
ImmSetCompositionFont
ImmSetCompositionString
ImmSetCompositionWindow
ImmSetConversionStatus
ImmSetOpenStatus
ImmSetStatusWindowPos
ImmSimulateHotKey
ImmUnregisterWord


Input Method Editor Messages

This section describes the input method editor messages.

IMC_GETCANDIDATEPOS
IMC_GETCOMPOSITIONFONT
IMC_GETCOMPOSITIONWINDOW
IMC_GETCONVERSIONMODE
IMC_GETOPENSTATUS
IMC_GETSENTENCEMODE
IMC_GETSTATUSWINDOWPOS
IMC_SETCANDIDATEPOS
IMC_SETCOMPOSITIONFONT
IMC_SETCOMPOSITIONWINDOW
IMC_SETCONVERSIONMODE
IMC_SETOPENSTATUS
IMC_SETSENTENCEMODE
IMC_SETSTATUSWINDOWPOS
IMN_CHANGECANDIDATE
IMN_CLOSECANDIDATE
IMN_CLOSESTATUSWINDOW
IMN_GUIDELINE
IMN_OPENCANDIDATE
IMN_OPENSTATUSWINDOW
IMN_SETCANDIDATEPOS
IMN_SETCOMPOSITIONFONT
IMN_SETCOMPOSITIONWINDOW
IMN_SETCONVERSIONMODE
IMN_SETOPENSTATUS
IMN_SETSENTENCEMODE
IMN_SETSTATUSWINDOWPOS
WM_IME_CHAR
WM_IME_COMPOSITION
WM_IME_COMPOSITIONFULL
WM_IME_CONTROL
WM_IME_ENDCOMPOSITION
WM_IME_NOTIFY
WM_IME_SELECT
WM_IME_SETCONTEXT
WM_IME_STARTCOMPOSITION


Input Method Editor Structures

This section describes the structures used with input method editor functions and messages.

CANDIDATEFORM
CANDIDATELIST
COMPOSITIONFORM
STYLEBUF


Input Method Editor Constants

This section describes the constants used by the input method editor functions and messages.


IME Conversion Mode Values

Bit	Meaning
IME_CMODE_CHARCODE	Set to 1 if character code input mode; 0 if not.
IME_CMODE_EUDC	Set to 1 if EUDC conversion mode; 0 if not.
IME_CMODE_FULLSHAPE	Set to 1 if full shape mode; 0 if half shape mode.
IME_CMODE_HANJACONVERT	Set to 1 if HANJA convert mode; 0 if not.
IME_CMODE_KATAKANA	Set to 1 if KATAKANA mode; 0 if HIRAGANA mode.
IME_CMODE_NATIVE	Set to 1 if NATIVE mode; 0 if ALPHANUMERIC mode.
IME_CMODE_NOCONVERSION	Set to 1 to prevent processing of conversions by IME; 0 if not.
IME_CMODE_ROMAN	Set to 1 if ROMAN input mode; 0 if not.
IME_CMODE_SOFTKBD	Set to 1 if Soft Keyboard mode; 0 if not.
All other bits are reserved.


IME Composition String Values

Value	Description
GCR_ERRORSTR	Retrieves or updates the error string.
GCR_INFORMATIONSTR	Retrieves or updates the information string.
GCS_COMPATTR	Retrieves or updates the attribute of the composition string.
GCS_COMPCLAUSE	Retrieves or updates clause information of the composition string.
GCS_COMPREADATTR	Retrieves or updates the attributes of the reading string of the current composition.
GCS_COMPREADCLAUSE	Retrieves or updates the clause information of the reading string of the composition string.
GCS_COMPREADSTR	Retrieves or updates the reading string of the current composition.
GCS_COMPSTR	Retrieves or updates the current composition string.
GCS_CURSORPOS	Retrieves or updates the cursor position in composition string.
GCS_DELTASTART	Retrieves or updates the starting position of any changes in composition string.
GCS_RESULTCLAUSE	Retrieves or updates clause information of the result string.
GCS_RESULTREADCLAUSE	Retrieves or updates clause information of the reading string.
GCS_RESULTREADSTR	Retrieves or updates the reading string.
GCS_RESULTSTR	Retrieves or updates the string of the composition result.
GCS_TYPINGINFO	Retrieves or updates the typing information of reading string. In contrast to reading information, this shows raw key strokes that the end user types.


IME Hot Key Identifiers

IME_CHOTKEY_IME_NONIME_TOGGLE	(Simplified Chinese) Toggles between IME and non-IME operation.
IME_CHOTKEY_SHAPE_TOGGLE	(Simplified Chinese) Toggles the shape conversion mode of IME.
IME_CHOTKEY_SYMBOL_TOGGLE	(Simplified Chinese) Toggles the symbol conversion mode of IME. Symbol mode indicates that the user can input Chinese punctuation and symbols by mapping to the punctuation and symbols on the keyboard.
IME_JHOTKEY_CLOSE_OPEN	(Japanese) Alternately opens and closes the IME.
IME_KHOTKEY_ENGLISH	(Korean) Switches to English.
IME_KHOTKEY_SHAPE_TOGGLE	(Korean) Toggles the shape conversion mode of IME.
IME_KHOTKEY_HANJACONVERT	(Korean) Switches to Hanja converision.
IME_THOTKEY_IME_NONIME_TOGGLE	(Traditional Chinese) Toggles between IME and non-IME operation.
IME_THOTKEY_SHAPE_TOGGLE	(Traditional Chinese) Toggles the shape conversion mode of IME.
IME_THOTKEY_SYMBOL_TOGGLE	(Traditional Chinese) Toggles the symbol conversion mode of IME.


IME Sentence Mode Values

Constant	Definition
IME_SMODE_AUTOMATIC	The IME carries out conversion processing in automatic mode.
IME_SMODE_NONE	No information for sentence.
IME_SMODE_PHRASEPREDICT	The IME uses phrase information to predict the next character.
IME_SMODE_PLURALCLAUSE	The IME uses plural clause information to carry out conversion processing.
IME_SMODE_SINGLECONVERT	The IME carries out conversion processing in single character mode.
Bits 16 through 31 are reserved for IME use.


IME Escapes

Escape	Description
IME_ESC_GET_EUDC_DICTIONARY	Retrieves the path of the EUDC dictionary file. On input, the lpData parameter must be the pointer to the buffer to receive the path. This buffer must be no less than 80 characters in length. On return, the buffer contains the null-terminated string specifying the full path. For use by the Chinese EUDC editor; do not use in other applications.
IME_ESC_HANJA_MODE	Converts from Hangeul to Hanja. On input, lpData must be the pointer to the buffer that contains the Hangeul character to convert; on output, it receives the converted Hanja as a null-terminated string. For use by the Korean editor; do not use in other applications.
IME_ESC_IME_NAME	Retrieves the name of the IME. On input, the lpData parameter must be the pointer to the buffer to receive the name. This buffer must be no less than 64 characters in length. On return, the buffer contains the null-terminated string specifying the IME name. For use by the Chinese EUDC editor; do not use in other applications.
IME_ESC_MAX_KEY	Returns the maximum number of key stokes for an EUDC character. For use by the Chinese EUDC editor; do not use in other applications.
IME_ESC_QUERY_SUPPORT	Checks for implementation. Returns zero if the escape is not implemented.
IME_ESC_SEQUENCE_TO_INTERNAL	Returns the character code that matches the given sequence code. On input, the lpData parameter is the pointer to a 32-bit variable that contains the sequence code. For use by the Chinese EUDC editor; do not use in other applications. Normally, the Chinese IME will encode its reading character codes into sequence 1 to n.
IME_ESC_SET_EUDC_DICTIONARY	Sets the EUDC dictionary file. On input, the lpData parameter is the pointer to a null-terminated string specifying the full path. For use by the Chinese EUDC editor; do not use in other applications.
The system reserves the escapes in the range IME_ESC_RESERVED_FIRST to IME_ESC_RESERVED_LAST for its own use.

The system reserves the escapes in the range IME_ESC_PRIVATE_FIRST to IME_ESC_PRIVATE_LAST for private use by IMEs.


National Language Support

National language support functions help applications developed for the Win32 application programming interface (API) adapt to the differing language- and location-specific needs of users around the world.

This overview describes the national language support functions and explains how to use them in your Win32-based applications.


About National Language Support

The national language support functions let applications set the locale for the user, identifying the language in which the user carries out work, and retrieve strings, representing times, dates and other information, that are correctly formatted for the given language and location of the world.

National language support also includes support for keyboard layouts and language-specific fonts. For more information about these topics, see Keyboard Input and Fonts and Text.


Locales

A locale is a collection of language-related, user preference information represented as a list of values. Each system has at least one installed locale and usually has many locales from which the user may choose. Each locale has a unique locale identifier (LCID), a 32-bit value that consists in part of a language identifier. The language identifier is a standard international numeric abbreviation for a country or geographical region.

The system assigns a locale to each thread. Initially, the system assigns the system default locale to the thread. This default locale is set by the user when the system is installed or through the International applet of the Control Panel. If a thread is run in a process belonging to a user, the system assigns the user default locale to the thread. An application can override either default by using the the SetThreadLocale function to explicitly set the locale for a thread.

There are two predefined locale identifiers: LOCALE_SYSTEM_DEFAULT, which identifies the system default locale, and LOCALE_USER_DEFAULT, which identifies the locale of the current user. An application can retrieve the current locale identifiers by using the GetSystemDefaultLCID and GetUserDefaultLCID functions. Similarly, an application can retrieve the current language identifiers by using the GetSystemDefaultLangID and GetUserDefaultLangID functions.

An application can retrieve specific information about any available language or locale. This can be important for handling language- and locale-specific strings. An application can retrieve information about a locale by using the GetLocaleInfo function. Each element of locale information has a unique LCTYPE value that identifies a specific information type. Applications use these values to retrieve the information they need.

All LCTYPE values are mutually-exclusive, so only one type of information can be retrieved at a time. An exception is the LOCALE_NOUSEROVERRIDE which can be used to bypasses user overrides and retrieve the system default values for the requested locale.

Locale information is always stored and manipulated as a null-terminated string. No binary data is allowed; any numeric values must be specified as text. Each type of information has a particular format. Also, several of types are linked together, such that changing one changes the value of the other as well.

Although a given locale identifier may be supported, it is not available for use by an application unless it is also installed.


Time and Date

You can retrieve strings for any given time or date in a format that is appropriate for the current locale by using the GetTimeFormat and GetDateFormat functions.

For GetTimeFormat, the time values in the SYSTEMTIME structure pointed to by lpTime must be valid. The function checks each of the time values to determine that it is within the appropriate range of values. If any of the time values are outside the correct range, the function fails, and sets the last-error to ERROR_INVALID_PARAMETER.

The function ignores the date portions of the SYSTEMTIME structure pointed to by lpTime: wYear, wMonth, wDayOfWeek, and wDay.

If a time marker exists and the TIME_NOTIMEMARKER flag is not set, the function localizes the time marker based on the specified locale identifier. Examples of time markers are "AM" and "PM" for US English, "de." and "du." for Mexican Spanish.

If TIME_NOMINUTESORSECONDS or TIME_NOSECONDS is specified, the function removes the separator(s) preceding the minutes and/or seconds element(s).

If TIME_NOTIMEMARKER is specified, the function removes the separator(s) preceding and following the time marker.

If TIME_FORCE24HOURFORMAT is specified, the function displays any existing time marker, unless the TIME_NOTIMEMARKER flag is also set.

The function does not include milliseconds as part of the formatted time string.

To use the LOCALE_NOUSEROVERRIDE flag, lpFormat must be NULL.

No errors are returned for a bad format string. The function simply forms the best time string that it can. If more than two hour, minute, second, or time marker format pictures are passed in, then the function defaults to two. For example, the only time marker pictures that are valid are L"t" and L"tt" (the 'L' indicates a Unicode (16-bit characters) string). If L"ttt" is passed in, the function assumes L"tt".

For GetDateFormat, the date values in the SYSTEMTIME structure pointed to by lpDate must be valid. The function checks each of the date values: year, month, day, and day of week. If the day of the week is incorrect, the function uses the correct value, and returns no error. If any of the other date values are outside the correct range, the function fails, and sets the last-error to ERROR_INVALID_PARAMETER.

The day name, abbreviated day name, month name, and abbreviated month name are all localized based on the given locale identifier. The function ignores the time portions of the SYSTEMTIME structure pointed to by lpDate: wHour, wMinute, wSecond, and wMilliseconds.

The flag DATE_USE_ALT_CALENDAR will always use the format defined as the default format for that alternate calendar, rather than using any user overrides.  The user overrides will only be used in the event that there is no default format for the alternate calendar specified.

The DATE_SHORTDATE and DATE_LONGDATE flag options are mutually exclusive. If neither one is specified and lpFormat is NULL, then DATE_SHORTDATE is the default.

If the lpFormat parameter is not NULL, the dwFlags parameter must be zero. None of the flags make sense when the format string is specified.

No errors are returned for a bad format string. The function simply forms the best date string that it can. For example, the only year pictures that are valid are L"yyyy" and L"yy" (the 'L' indicates a Unicode (16-bit characters) string). If L"y" is passed in, the function  assumes L"yy". If L"yyy" is passed in, the function assumes L"yyyy". If more than 4 date (L"dddd") or 4 month (L"MMMM") pictures are passed in, then the function defaults to L"dddd" or L"MMMM".

Any text that should remain in its exact form in the date string should be enclosed within single quotes in the date format picture. The single quote may also be used as an escape character to allow the single quote itself to be displayed in the date string. However, the escape sequence must be enclosed within two single quotes.  For example, to display the date as "May '93", the format string would be:  L"MMMM ''''yy " The first and last single quotes are the enclosing quotes.  The second and third single quotes are the escape sequence to allow the single quote to be displayed before the century.


Date and Calendar

Most locales use the standard Gregorian calendar and a set number of date formats. These "default choices" for date formats are available for display by using the EnumDateFormats function. There are other locales which require special considerations when creating a complete list of format choices. Some of these require text strings to be inserted within the date format string, others require a completely different method of computation of the values. These special requirements are addressed by the addition of new LCTYPE and CALTYPE values.

Each locale identifier has a default calendar type associated with it. A locale identifier can also have an alternate calendar type, which can be set using the LOCALE_IOPTIONALCALENDAR type for this locale.


Localization and the Shell Font

Windows NT is available in localized editions of many different languages, but the U.S. English edition can also be used to run applications written in other languages. This is true even when the base character sets are different, such as when applications are written in the Central and Eastern European languages, or in Greek. These applications require a user interface (UI) with dialog boxes, icons, and applets that provide information in the application's language, which may be different than the language being used in the current Windows NT UI.

To enable the U.S. English Windows NT user interface, as well as characters outside the Windows character set for the US and Western Europe (code page 1252), to display correctly within applications and in system edit controls, Windows NT uses intelligent font switching based on the currently selected locale. This allows currently shipping localized applications to run on the U.S. English version of Windows NT without modifying the application in any way.

An example of the problem being addressed here is that the U.S. English Windows NT shell font is MS Sans Serif but the shell font for Greek Windows 3.1 is MS Sans Serif Greek. These character sets cannot be directly mapped to each other so simply replacing the MS Sans Serif font with the MS Sans Serif Greek font when the locale is set to Greek does not allow existing applications with this kind of difference to run adequately or to display Greek characters in system menus, dialogs and edit controls. To resolve this problem at run time, Microsoft has defined a new font face name, MS Shell Dlg. It is mapped by an entry in the registry to the appropriate shell font for the currently active locale.


MS Shell Dlg

MS Shell Dlg is a mapping mechanism that enables U.S. English Windows NT to support non-code page 1252 locales. It is not a font but only a face name for a nonexistent font. It can be specified in either the Windows NT Setup file during the installation process or when customizing a local system by double-clicking on the Control Panel's International icon. When you double-click on the icon, select the appropriate Country and Language in the International dialog box, and then reboot the system, the appropriate change occurs in the Registry under the following key:

HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\Current Version\FontSubstitutes

An added benefit of this new means of font mapping in the registry is that you can change the font for the entire shell by simply changing one .inf file entry. For example, Far East localization is much easier because you can change the .inf file entry, instead of changing every instance of MS Sans Serif in every .rc and .dlg file, and the change is complete without rebuilding any binaries.

Windows NT applications can also take advantage of this feature. It is very helpful when your application contains multiple language resources that cross character-set boundaries. It is also useful when you have an English application in which supporting multiple languages and character sets is important.


Windows 95 and MS Shell Dlg

Windows 95 does not support the concept of switching Windows character sets so the role of MS Shell Dlg is more limited. It does, however, facilitate localization in that Windows 95 is equipped with a static entry to replace the standard system font. For example, the system font, MS San Serif, is easily replaced with MS San Serif Greek or another language. This also ensures compatibility with the applets provided with Windows NT.


When MS Shell Dlg Should Not Be Used

At this time, MS Shell Dlg is not intended for use when you are working with a static, non-English UI application that you want to run when the user has chosen a locale with a different Windows base character set. This is because the application's UI language may not be supported with the font that is substituted for MS Shell Dlg. For example, if you are using a German localized version of Windows NT and want to install a non-Unicode, Greek application, you can use the Control Panel's International applet to change the locale to Greek. This will reset MS Shell Dlg to be a Greek font but this font does not contain all of the glyphs necessary to display German. Therefore, any non-ASCII characters in your German UI will not be displayed properly. To support this scenario, you would have to set MS Shell Dlg to a font that contains both the Western European and the Greek glyphs.


National Language Support Reference

This section provides detailed reference information for the national language support functions, structures, and messages. The information is separated into the following functional groups.


National Language Support Functions

This section describes the national language support functions. Many national language support functions generate extended error information on errors. Use the GetLastError function to get this information.

SetLocaleInfo


National Language Support Macros

This section describes the macros used with the national language support functions.

LANGIDFROMLCID
MAKELANGID
MAKELCID


National Language Support Constants

This section describes the constants used with the national language support functions.


Locale Information

LOCALE_ILANGUAGE

Language identifier indicating the language. The maximum number of characters allowed for this string is 5.

LOCALE_SLANGUAGE

Full localized name of the language.

LOCALE_SENGLANGUAGE

Full English name of the language from the International Organization for Standardization (ISO) Standard 639. This is always restricted to characters mappable into the ASCII 127-character subset.

LOCALE_SABBREVLANGNAME

Abbreviated name of the language, created by taking the 2-letter language abbreviation from the ISO Standard 639 and adding a third letter, as appropriate, to indicate the sublanguage.

LOCALE_SNATIVELANGNAME

Native name of the language.

LOCALE_ICOUNTRY

Country code, based on international phone codes, also referred to as IBM country codes. The maximum number of characters allowed for this string is 6.

LOCALE_SCOUNTRY

Full localized name of the country.

LOCALE_SENGCOUNTRY

Full English name of the country. This is always restricted to characters mappable into the ASCII 127-character subset.

LOCALE_SABBREVCTRYNAME

Abbreviated name of the country from the ISO Standard 3166.

LOCALE_SNATIVECTRYNAME

Native name of the country.

LOCALE_IDEFAULTLANGUAGE

Language identifier for the principal language spoken in this locale. This is provided so that partially specified locales can be completed with default values. The maximum number of characters allowed for this string is 5.

LOCALE_IDEFAULTCOUNTRY

Country code for the principal country in this locale. This is provided so that partially specified locales can be completed with default values. The maximum number of characters allowed for this string is 6.

LOCALE_IDEFAULTANSICODEPAGE

American National Standards Institute (ANSI) code page associated with this locale. The maximum number of characters allowed for this string is 6.

LOCALE_IDEFAULTOEMCODEPAGE

Original equipment manufacturer (OEM) code page associated with the locale. The maximum number of characters allowed for this string is 6.

LOCALE_IDEFAULTCODEPAGE

Original equipment manufacturer (OEM) code page associated with the country. The maximum number of characters allowed for this string is 6.

LOCALE_SLIST

Character(s) used to separate list items. For example, a comma is used in many locales.

LOCALE_IMEASURE

System of measurement. This value is 0 if the metric system (Systéme International d'Unités, or S.I.) is used and 1 if the U.S. system is used. The maximum number of characters allowed for this string is 2.

LOCALE_SDECIMAL

Character(s) used as the decimal separator.

LOCALE_STHOUSAND

Character(s) used to separate groups of digits to the left of the decimal.

LOCALE_SGROUPING

Sizes for each group of digits to the left of the decimal. An explicit size is needed for each group; sizes are separated by semicolons. If the last value is zero, the preceding value is repeated. To group thousands, specify 3;0, for example.

LOCALE_IDIGITS

Number of fractional digits. The maximum number of characters allowed for this string is 3.

LOCALE_ILZERO

Specifier for leading zeros in decimal fields. The maximum number of characters allowed for this string is 2. The specifier can be one of the following values:

0	No leading zeros
1	Leading zeros
LOCALE_INEGNUMBER

Negative number mode. The mode can be one of these values:

0	(1.1)
1	-1.1
2	- 1.1
3	1.1-
4	1.1 -
LOCALE_SNATIVEDIGITS

Native equivalents to ASCII 0 through 9.

LOCALE_SCURRENCY

String used as the local monetary symbol.

LOCALE_SINTLSYMBOL

Three characters of the international monetary symbol specified in ISO 4217, "Codes for the Representation of Currencies and Funds," followed by the character separating this string from the amount.

LOCALE_SMONDECIMALSEP

Character(s) used as the monetary decimal separator.

LOCALE_SMONTHOUSANDSEP

Character(s) used as the monetary separator between groups of digits to the left of the decimal.

LOCALE_SMONGROUPING

Sizes for each group of monetary digits to the left of the decimal. An explicit size is needed for each group; sizes are separated by semicolons. If the last value is zero, the preceding value is repeated. To group thousands, specify 3;0, for example.

LOCALE_ICURRDIGITS

Number of fractional digits for the local monetary format. The maximum number of characters allowed for this string is 3.

LOCALE_IINTLCURRDIGITS

Number of fractional digits for the international monetary format. The maximum number of characters allowed for this string is 3.

LOCALE_ICURRENCY

Positive currency mode. The maximum number of characters allowed for this string is 2. The mode can be one of the following values:

0	Prefix, no separation
1	Suffix, no separation
2	Prefix, 1-char. separation
3	Suffix, 1-char. separation
LOCALE_INEGCURR

Negative currency mode. The maximum number of characters allowed for this string is 3. The mode can be one of the following values:

0	($1.1)
1	−$1.1
2	$−1.1
3	$1.1−
4	(1.1$)
5	−1.1$
6	1.1−$
7	1.1$−
8	−1.1 $ (space before $)
9	−$ 1.1 (space after $)
10	1.1 $− (space before $)
11	$ 1.1− (space after $)
12	$ −1.1 (space after $)
13	1.1− $ (space before $)
14	($ 1.1) (space after $)
15	(1.1 $) (space before $)
LOCALE_SDATE

Character(s) for the date separator.

LOCALE_STIME

Character(s) for the time separator.

LOCALE_STIMEFORMAT

Time formatting strings for this locale. The string can consist of a combination of the hour, minute, and second format pictures defined in in the Hour, Minute, and Second Format Pictures table in National Language Support Constants.

LOCALE_SSHORTDATE

Short date formatting string for this locale. The string can consist of a combination of day, month, and year format pictures defined in in Day, Month, Year, and Era Format Pictures table in National Language Support Constants.

LOCALE_SLONGDATE

Long date formatting string for this locale. The string can consist of a combination of day, month, and year format pictures defined in in the Day, Month, Year, and Era Format Pictures table in National Language Support Constantsand any string of characters enclosed in single quotes. Characters in single quotes remain as given.

LOCALE_IDATE

Short date format-ordering specifier. The maximum number of characters allowed for this string is 2. The specifier can be one of the following values:

0	Month-Day-Year
1	Day-Month-Year
2	Year-Month-Day
LOCALE_ILDATE

Long date format-ordering specifier. The maximum number of characters allowed for this string is 2. The specifier can be one of the following values:

0	Month-Day-Year
1	Day-Month-Year
2	Year-Month-Day
LOCALE_ITIME

Time format specifier. The maximum number of characters allowed for this string is 2. The specifier can be one of the following values:

0	AM / PM 12-hour format
1	24-hour format
LOCALE_ICENTURY

Specifier for full 4-digit century. The maximum number of characters allowed for this string is 2. The specifier can be one of the following values:

0	Abbreviated 2-digit century
1	Full 4-digit century
LOCALE_ITLZERO

Specifier for leading zeros in time fields. The maximum number of characters allowed for this string is 2. The specifier can be one of the following values:

0	No leading zeros for hours
1	Leading zeros for hours
LOCALE_IDAYLZERO

Specifier for leading zeros in day fields. The maximum number of characters allowed for this string is 2. The specifier can be one of the following values:

0	No leading zeros for days
1	Leading zeros for days
LOCALE_IMONLZERO

Specifier for leading zeros in month fields. The maximum number of characters allowed for this string is 2. The specifier can be one of the following values:

0	No leading zeros for months
1	Leading zeros for months
LOCALE_S1159

String for the AM designator.

LOCALE_S2359

String for the PM designator.

LOCALE_ICALENDARTYPE

Current calendar type. This type can be one of these values:

1	Gregorian (as in United States)
2	Gregorian (English strings always)
3	Era: Year of the Emperor (Japan)
4	Era: Year of the Republic of China
5	Tangun Era (Korea)
LOCALE_IOPTIONALCALENDAR

Additional calendar types. This can be a zero-separated list of one or more of these calendars type values:

0	No additional types valid
1	Gregorian (as in United States)
2	Gregorian (English strings always)
3	Era: Year of the Emperor (Japan)
4	Era: Year of the Republic of China
5	Tangun Era (Korea)
LOCALE_IFIRSTDAYOFWEEK

Specifier for the first day in a week. The specifier can be one of these values:

0	LOCALE_SDAYNAME1
1	LOCALE_SDAYNAME2
2	LOCALE_SDAYNAME3
3	LOCALE_SDAYNAME4
4	LOCALE_SDAYNAME5
5	LOCALE_SDAYNAME6
6	LOCALE_SDAYNAME7
LOCALE_IFIRSTWEEKOFYEAR

Specifier for the first week of the year. The specifier can be one of these values:

0	Week containing 1/1 is the first week of that year.
1	First full week following 1/1 is the first week of that year.
2	First week containing at least 4 days is the first week of that year.
LOCALE_SDAYNAME1

Native long name for Monday.

LOCALE_SDAYNAME2

Native long name for Tuesday.

LOCALE_SDAYNAME3

Native long name for Wednesday.

LOCALE_SDAYNAME4

Native long name for Thursday.

LOCALE_SDAYNAME5

Native long name for Friday.

LOCALE_SDAYNAME6

Native long name for Saturday.

LOCALE_SDAYNAME7

Native long name for Sunday.

LOCALE_SABBREVDAYNAME1

Native abbreviated name for Monday.

LOCALE_SABBREVDAYNAME2

Native abbreviated name for Tuesday.

LOCALE_SABBREVDAYNAME3

Native abbreviated name for Wednesday.

LOCALE_SABBREVDAYNAME4

Native abbreviated name for Thursday.

LOCALE_SABBREVDAYNAME5

Native abbreviated name for Friday.

LOCALE_SABBREVDAYNAME6

Native abbreviated name for Saturday.

LOCALE_SABBREVDAYNAME7

Native abbreviated name for Sunday.

LOCALE_SMONTHNAME1

Native long name for January.

LOCALE_SMONTHNAME2

Native long name for February.

LOCALE_SMONTHNAME3

Native long name for March.

LOCALE_SMONTHNAME4

Native long name for April.

LOCALE_SMONTHNAME5

Native long name for May.

LOCALE_SMONTHNAME6

Native long name for June.

LOCALE_SMONTHNAME7

Native long name for July.

LOCALE_SMONTHNAME8

Native long name for August.

LOCALE_SMONTHNAME9

Native long name for September.

LOCALE_SMONTHNAME10

Native long name for October.

LOCALE_SMONTHNAME11

Native long name for November.

LOCALE_SMONTHNAME12

Native long name for December.

LOCALE_SMONTHNAME13

Native name for 13th month, if exists.

LOCALE_SABBREVMONTHNAME1

Native abbreviated name for January.

LOCALE_SABBREVMONTHNAME2

Native abbreviated name for February.

LOCALE_SABBREVMONTHNAME3

Native abbreviated name for March.

LOCALE_SABBREVMONTHNAME4

Native abbreviated name for April.

LOCALE_SABBREVMONTHNAME5

Native abbreviated name for May.

LOCALE_SABBREVMONTHNAME6

Native abbreviated name for June.

LOCALE_SABBREVMONTHNAME7

Native abbreviated name for July.

LOCALE_SABBREVMONTHNAME8

Native abbreviated name for August.

LOCALE_SABBREVMONTHNAME9

Native abbreviated name for September.

LOCALE_SABBREVMONTHNAME10

Native abbreviated name for October.

LOCALE_SABBREVMONTHNAME11

Native abbreviated name for November.

LOCALE_SABBREVMONTHNAME12

Native abbreviated name for December.

LOCALE_SABBREVMONTHNAME13

Native abbreviated name for 13th month, if exists.

LOCALE_SPOSITIVESIGN

String value for the positive sign.

LOCALE_SNEGATIVESIGN

String value for the negative sign.

LOCALE_IPOSSIGNPOSN

Formatting index for positive values. The maximum number of characters allowed for this string is 2. The index can be one of the following values:

0	Parentheses surround the amount and the monetary symbol.
1	The sign string precedes the amount and the monetary symbol.
2	The sign string succeeds the amount and the monetary symbol.
3	The sign string immediately precedes the monetary symbol.
4	The sign string immediately succeeds the monetary symbol.
LOCALE_INEGSIGNPOSN

Formatting index for negative values. This index uses the same values as LOCALE_IPOSSIGNPOSN. The maximum number of characters allowed for this string is 2.

LOCALE_IPOSSYMPRECEDES

Position of monetary symbol in a positive monetary value. This value is 1 if the monetary symbol precedes the positive amount, 0 if it follows it. The maximum number of characters allowed for this string is 2.

LOCALE_IPOSSEPBYSPACE

Separation of monetary symbol in a positive monetary value. This value is 1 if the monetary symbol is separated by a space from a positive amount, 0 if it is not. The maximum number of characters allowed for this string is 2.

LOCALE_INEGSYMPRECEDES

Position of monetary symbol in a negative monetary value. This value is 1 if the monetary symbol precedes the negative amount, 0 if it follows it. The maximum number of characters allowed for this string is 2.

LOCALE_INEGSEPBYSPACE

Separation of monetary symbol in a negative monetary value. This value is 1 if the monetary symbol is separated by a space from the negative amount, 0 if it is not. The maximum number of characters allowed for this string is 2.

LOCALE_NOUSEROVERRIDE

Can be combined with other LOCALE values to bypass any user override and return the system default value for the given locale information.

Many of the locale types listed above are closely related, such that changing one affects the value of others. The following shows the relationships between these types.

LOCALE_ICURRENCY

LOCALE_IPOSSEPBYSPACE, LOCALE_IPOSSYMPRECEDES

LOCALE_INEGCURR

LOCALE_INEGSEPBYSPACE, LOCALE_INEGSYMPRECEDES, LOCALE_INEGSIGNPOSN, LOCALE_IPOSSIGNPOSN

LOCALE_SSHORTDATE

LOCALE_SDATE, LOCALE_IDATE

LOCALE_SLONGDATE

LOCALE_ILDATE

LOCALE_STIMEFORMAT

LOCALE_STIME, LOCALE_ITIME, LOCALE_ITLZERO


Day, Month, Year, and Era Format Pictures

The format picture for a date string consists of a combination of null-terminated strings.

Day
d	Day of the month as digits without leading zeros for single digit days.
dd	Day of the month as digits with leading zeros for single digit days
ddd	Day of the week as a 3-letter abbreviation as given by a LOCALE_SABBREVDAYNAME value.
dddd	Day of the week as given by a LOCALE_SDAYNAME value.
Month
M	Month as digits without leading zeros for single digit months.
MM	Month as digits with leading zeros for single digit months
MMM	Month as a three letter abbreviation as given by a LOCALE_SABBREVMONTHNAME value.
MMMM	Month as given by a LOCALE_SMONTHNAME value.
Year
y	Year represented only be the last digit.
yy	Year represented only be the last two digits.
yyyy	Year represented by the full 4 digits.
Period/Era
gg	Period/era string as given by the CAL_SERASTRING value.
The "gg" format picture in a date string is ignored if there is no associated era string.


Hour, Minute, and Second Format Pictures

The format picture for a time string consists of a combination of one string from each of these format types:

Hours
h	Hours without leading zeros for single digit hours (12 hour clock)
hh	Hours with leading zeros for single digit hours (12 hour clock)
H	Hours without leading zeros for single digit hours (24 hour clock)
HH	Hours with leading zeros for single digit hours (24 hour clock)
Minutes
m	Minutes without leading zeros for single digit minutes
mm	Minutes with leading zeros for single digit minutes
Seconds
s	Seconds without leading zeros for single digit seconds
ss	Seconds with leading zeros for single digit seconds
Time Marker
t	One character time marker string
tt	Multi-character time marker string


Primary Language Identifiers

0x00	Neutral
0x36	Afrikaans
0x1c	Albanian
0x01	Arabic
0x2d	Basque
0x02	Bulgarian
0x23	Byelorussian
0x03	Catalan
0x04	Chinese
0x05	Czech
0x06	Danish
0x13	Dutch
0x09	English
0x25	Estonian
0x29	Farsi
0x0b	Finnish
0x0c	French
0x07	German
0x08	Greek
0x0d	Hebrew
0x0e	Hungarian
0x0f	Icelandic
0x21	Indonesian
0x10	Italian
0x11	Japanese
0x2c	Kampuchean
0x12	Korean
0x2b	Laotian
0x26	Latvian
0x27	Lithuanian
0x2f	Macedonian
0x28	Maori
0x14	Norwegian
0x15	Polish
0x16	Portuguese
0x17	Rhaeto Roman
0x18	Romanian
0x19	Russian
0x1a	Serbo Croatian
0x1b	Slovak
0x24	Slovenian
0x2e	Sorbian
0x0a	Spanish
0x30	Sutu
0x1d	Swedish
0x1e	Thai
0x31	Tsonga
0x32	Tswana
0x1f	Turkish
0x22	Ukrainian
0x20	Urdu
0x33	Venda
0x2a	Vietnamese
0x34	Xhosa
0x35	Zulu


Secondary Language Identifiers

0x00	Neutral
0x01	Default
0x02	System Default
0x01	Arabic (Saudi Arabia)
0x02	Arabic (Iraq)
0x03	Arabic (Egypt)
0x04	Arabic (Libya)
0x05	Arabic (Algeria)
0x06	Arabic (Morocco)
0x07	Arabic (Tunisia)
0x08	Arabic (Oman)
0x09	Arabic (Yemen)
0x10	Arabic (Syria)
0x11	Arabic (Jordan)
0x12	Arabic (Lebanon)
0x13	Arabic (Kuwait)
0x14	Arabic (U.A.E.)
0x15	Arabic (Bahrain)
0x16	Arabic (Qatar)
0x01	Chinese (Taiwan)
0x02	Chinese (PRC)
0x03	Chinese (Hong Kong)
0x04	Chinese (Singapore)
0x01	Dutch
0x02	Dutch (Belgian)
0x01	English (US)
0x02	English (UK)
0x03	English (Australian)
0x04	English (Canadian)
0x05	English (New Zealand)
0x06	English (Ireland)
0x01	French
0x02	French (Belgian)
0x03	French (Canadian)
0x04	French (Swiss)
0x05	French (Luxembourg)
0x01	German
0x02	German (Swiss)
0x03	German (Austrian)
0x04	German (Luxembourg)
0x05	German (Liechtenstein)
0x04	Hebrew (Israel)
0x01	Italian
0x02	Italian (Swiss)
0x01	Norwegian (Bokmal)
0x02	Norwegian (Nynorsk)
0x01	Portuguese (Brazilian)
0x02	Portuguese
0x01	Serbo Croatian (Latin)
0x02	Serbo Croatian (Cyrillic)
0x01	Spanish (Traditional Sort)
0x02	Spanish (Mexican)
0x03	Spanish (Modern Sort)


Language Identifiers

Identifier	Locale
0x0436	Afrikaans
0x041C	Albania
0x1401	Algeria
0x0409	American
0x0C09	Australian
0x0C07	Austrian
0x3C01	Bahrain
0x042D	Basque
0x080C	Belgian
0x0813	Belgian (Flemish)
0x0809	British
0x0402	Bulgaria
0x0423	Byelorussia
0x1009	Canadian
0x0403	Catalan
0x041A	Croatian
0x0405	Czech
0x0406	Danish
0x0413	Dutch (Standard)
0x0C01	Egypt
0x0425	Estonia
0x0429	Farsi
0x040B	Finnish
0x040C	French (Standard)
0x0C0C	French Canadian
0x0407	German (Standard)
0x042E	Germany
0x0408	Greek
0x0C04	Hong Kong
0x040E	Hungarian
0x040F	Icelandic
0x0421	Indonesia
0x0801	Iraq
0x1809	Ireland
0x040D	Israel
0x0410	Italian (Standard)
0x0411	Japan
0x2C01	Jordan
0x0412	Korea
0x3401	Kuwait
0x0426	Latvia
0x3001	Lebanon
0x1001	Libya
0x1407	Liechtenstein
0x0427	Lithuania
0x140C	Luxembourg (French)
0x1007	Luxembourg (German)
0x042f	Macedonia
0x080A	Mexican
0x0818	Moldavia
0x0819	Moldavia
0x1801	Morocco
0x1409	New Zealand
0x0414	Norwegian (Bokmal)
0x0814	Norwegian (Nynorsk)
0x2001	Oman
0x0415	Polish
0x0416	Portuguese (Brazilian)
0x0816	Portuguese (Standard)
0x0804	PRC
0x4001	Qatar
0x0417	Rhaeto-Romanic
0x0418	Romania
0x0419	Russian
0x0401	Saudi Arabia
0x081A	Serbian
0x1004	Singapore
0x041B	Slovak
0x0424	Slovenia
0x0C0A	Spanish (Modern Sort)
0x040A	Spanish (Traditional Sort)
0x0430	Sutu
0x041D	Swedish
0x100C	Swiss (French)
0x0807	Swiss (German)
0x0810	Swiss (Italian)
0x2801	Syria
0x0404	Taiwan
0x041E	Thailand
0x0431	Tsonga
0x0432	Tswana
0x1C01	Tunisia
0x041f	Turkish
0x3801	U.A.E.
0x0422	Ukraine
0x0420	Urdu
0x0433	Venda
0x0435	Xhosa
0x2401	Yemen
0x0436	Zulu


Calendar Type Information

CAL_ICALINTVALUE

An integer value indicating the calendar type of the alternate calendar.

CAL_IYEAROFFSETRANGE

One or more null-terminated strings that specify the year offsets for each of the era ranges. The last string has an extra terminating null character.

CAL_SABBREVDAYNAME1

Abbreviated native name of the first day of the week.

CAL_SABBREVDAYNAME2

Abbreviated native name of the second day of the week.

CAL_SABBREVDAYNAME3

Abbreviated native name of the third day of the week.

CAL_SABBREVDAYNAME4

Abbreviated native name of the fourth day of the week.

CAL_SABBREVDAYNAME5

Abbreviated native name of the fifth day of the week.

CAL_SABBREVDAYNAME6

Abbreviated native name of the sixth day of the week.

CAL_SABBREVDAYNAME7

Abbreviated native name of the seventh day of the week.

CAL_SABBREVMONTHNAME1

Abbreviated native name of the first month of the year.

CAL_SABBREVMONTHNAME2

Abbreviated native name of the second month of the year.

CAL_SABBREVMONTHNAME3

Abbreviated native name of the third month of the year.

CAL_SABBREVMONTHNAME4

Abbreviated native name of the fourth month of the year.

CAL_SABBREVMONTHNAME5

Abbreviated native name of the fifth month of the year.

CAL_SABBREVMONTHNAME6

Abbreviated native name of the sixth month of the year.

CAL_SABBREVMONTHNAME7

Abbreviated native name of the seventh month of the year.

CAL_SABBREVMONTHNAME8

Abbreviated native name of the eighth month of the year.

CAL_SABBREVMONTHNAME9

Abbreviated native name of the ninth month of the year.

CAL_SABBREVMONTHNAME10

Abbreviated native name of the tenth month of the year.

CAL_SABBREVMONTHNAME11

Abbreviated native name of the eleventh month of the year.

CAL_SABBREVMONTHNAME12

Abbreviated native name of the twelfth month of the year.

CAL_SABBREVMONTHNAME13

Abbreviated native name of the thirteenth month of the year, if it exists.

CAL_SCALNAME

The native name of the alternate calendar.

CAL_SDAYNAME1

Native name of the first day of the week.

CAL_SDAYNAME2

Native name of the second day of the week.

CAL_SDAYNAME3

Native name of the third day of the week.

CAL_SDAYNAME4

Native name of the fourth day of the week.

CAL_SDAYNAME5

Native name of the fifth day of the week.

CAL_SDAYNAME6

Native name of the sixth day of the week.

CAL_SDAYNAME7

Native name of the seventh day of the week.

CAL_SERASTRING

One or more null-terminated strings that specify each of the Unicode codepoints specifying the era associated with the given CAL_IYEAROFFSETRANGE. The last string has an extra terminating null character. See example below.

CAL_SLONGDATE

Long date formats for this calendar type.

CAL_SMONTHNAME1

Native name of the first month of the year.

CAL_SMONTHNAME2

Native name of the second month of the year.

CAL_SMONTHNAME3

Native name of the fifth month of the year.

CAL_SMONTHNAME4

Native name of the fourth month of the year.

CAL_SMONTHNAME5

Native name of the fifth month of the year.

CAL_SMONTHNAME6

Native name of the sixth month of the year.

CAL_SMONTHNAME7

Native name of the seventh month of the year.

CAL_SMONTHNAME8

Native name of the eighth month of the year.

CAL_SMONTHNAME9

Native name of the ninth month of the year.

CAL_SMONTHNAME10

Native name of the tenth month of the year.

CAL_SMONTHNAME11

Native name of the eleventh month of the year.

CAL_SMONTHNAME12

Native name of the twelfth month of the year.

CAL_SMONTHNAME13

Native name of the thirteenth month of the year, if it exists.

CAL_SSHORTDATE

Short date formats for this calendar type.

If the native name for the day of the week or for a month is an empty string, that name is identical to the name given in the corresponding locale information and therefore is not duplicated here.

The CAL_IYEAROFFSETRANGE and CAL_SERASTRING values vary in format depending on the type of optional calendar. The following example shows the values for these types (for each supported alternate calendar type) along with the formula for how to use the CAL_IYEAROFFSETRANGE value to compute the correct year given the Gregorian current year value Y:

CAL_ICALINTVALUE = "1"
CAL_IYEAROFFSETRANGE = ""
CAL_SERASTRING = ""

CAL_ICALINTVALUE = "2"
CAL_IYEAROFFSETRANGE = ""
CAL_SERASTRING = ""

CAL_ICALINTVALUE = "3"
CAL_IYEAROFFSETRANGE = "1989\01926\01912\01868\0"
CAL_SERASTRING = "Ux337B\0Ux337C\0Ux337D\0Ux337E\0"
if (Y>=1989) { Y = (Y-1989)+1; }
if (Y>=1926 && Y<1989) { Y = (Y-1926)+1; }
if (Y>=1912 && Y<1926) { Y = (Y-1912)+1; }
if (Y>=1868 && Y<1912) { Y = (Y-1868)+1; }
if (Y<1868) { Y = Y; }

CAL_ICALINTVALUE = "4"
CAL_IYEAROFFSETRANGE = "1912\0"
CAL_SERASTRING = "Ux4E2D\0Ux83EF\0Ux6C11\0Ux570B\0"
if (Y>=1912) { Y = (Y-1912)+1; }
if (Y<1912) { Y = Y; }

CAL_ICALINTVALUE = "5"
CAL_IYEAROFFSETRANGE = "2333\0"
CAL_SERASTRING = ""
Y = Y+2333;


Language Code and Scripts

Language/Locale	Code	Script
Greek	ELL	Other
Russian	RUS	Cyrillic
Turkish	TRK	Latin 2
Polish	PLK	Latin 2
Czech	CSY	Latin 2
Slovak	SKY	Latin 2
Hungarian	HUN	Latin 2
Danish	DAN	Latin 1
Dutch (Standard)	NLD	Latin 1
Belgian (Flemish)	NLB	Latin 1
English (American)	ENU	Latin 1
English (British)	ENG	Latin 1
English (Australian)	ENA	Latin 1
English (Canadian)	ENC	Latin 1
English (New Zealand)	ENZ	Latin 1
English (Ireland)	ENI	Latin 1
Finnish	FIN	Latin 1
French (Standard)	FRA	Latin 1
French (Belgian)	FRB	Latin 1
French (Canadian)	FRC	Latin 1
French (Swiss)	FRS	Latin 1
German (Standard)	DEU	Latin 1
German (Swiss)	DES	Latin 1
German (Austrian)	DEA	Latin 1
Icelandic	ISL	Latin 1
Italian (Standard)	ITA	Latin 1
Italian (Swiss)	ITS	Latin 1
Norwegian (Bokmal)	NOR	Latin 1
Norwegian (Nynorsk)	NON	Latin 1
Portuguese (Brazilian)	PTB	Latin 1
Portuguese (Standard)	PTG	Latin 1
Swedish	SVE	Latin 1
Spanish (Standard/Traditional)	ESP	Latin 1
Spanish (Mexican)	ESM	Latin 1
Spanish (Modern)	ESN	Latin 1


Unicode and Character Sets

Unicode and traditional character sets give the Microsoft Windows operating system the means to support the many different written languages of the international marketplace. Unicode is a worldwide character-encoding standard that uses 16-bit character values to represent all the characters used in modern computing, including technical symbols and special characters used in publishing. Traditional character sets are previous character-encoding standards, such as the Windows ANSI character set, that use 8-bit character values or combinations of 8-bit values to represent the characters used in a specific language or geographical region.

This overview describes the character set functions and explains how to use them in your Win32-based applications.


About Unicode and Character Sets

Because the world's character-based data has been developed using both Unicode and traditional characters sets, the Win32 application programming interface (API) provides character set functions that help Win32-based applications convert the character-based data from its original character set to Unicode or another traditional character set. Because not all operating systems support Unicode, these character set functions also help Win32-based applications create character-based data that may be transferred to and used on any operating system.

For details about Unicode beyond the scope of this overview, see The Unicode™ Standard: Worldwide Character Encoding, Version 1.0, Volumes 1 and 2, Addison-Wesley Publishing Company: 1991, 1992, ISBN 0201567881.


Unicode and Character Set Reference

This section provides detailed reference information for the character set functions, structures, and messages. The information is separated into the following functional groups.


Character Sets

A character set is a mapping of characters to their identifying numeric values. Most of the character sets commonly used in computers are single-byte character sets in which each character is identified by a value one byte wide. The large number of characters in Asian languages led to the development of multibyte character sets, in particular the double-byte character set (DBCS). Microsoft® Windows NT™ incorporates a new global standard for character encoding: Unicode.


Single-byte Character Sets

A single-byte character set is a mapping of 256 individual characters to their identifying numeric values. The character codes 0x20 through 0x7E represent standardized displayable characters, but the characters represented by the remaining codes vary among character sets. The ASCII character set covers the range 0x00 through 0x7F.

In Windows, the ANSI character set is used in window manager and graphics device interface (GDI), but the MS-DOS file allocation table (FAT) file system uses a character set called the original equipment manufacturer (OEM) character set. Variations on the character sets, called code pages, include different special characters, typically customized for a language or group of languages. The OEM code page generally used in the United States is code page 437.

Applications that use the Microsoft® Win32® application programming interface (API) can use Unicode to avoid the inconsistencies of varied code pages and as an aid in developing easily localized applications.

An application can use the GetACP function to retrieve the ANSI code-page identifier for the system or use the GetOEMCP function to retrieve the OEM code-page identifier.

The OemToChar and OemToCharBuff functions allow an application to convert a character or string from the OEM code page to either the ANSI code page or Unicode. To convert in the other direction, you can use either the CharToOem or CharToOemBuff function. In addition, an application can use the MultiByteToWideChar and WideCharToMultiByte functions to map single-byte character set (SBCS) strings to Unicode and Unicode strings to SBCS strings.

The GetCPInfo function fills a CPINFO structure with information that includes the size, in bytes, of the largest character in the code page and the default character used when a character code is entered that has no corresponding entry in the code page.


Double-byte Character Sets

The double-byte character set (DBCS) is called an expanded 8-bit character set because its smallest unit is a byte. It can be thought of as the ANSI character set for some Asian versions of Windows (particularly the Japanese version). Win32 functions for the Japanese version of Windows accept DBCS strings for the ANSI versions of the functions. However, unlike the handling of Unicode, DBCS character handling requires detailed changes in the character-processing algorithms throughout an application's source code.

An application can use the IsDBCSLeadByte function to determine whether a given character is the first byte in a 2-byte character; this helps identify double-byte character sets. In addition, an application can use the MultiByteToWideChar and WideCharToMultiByte functions to map DBCS strings to Unicode and Unicode strings to DBCS strings.


Unicode

Unicode is a worldwide character-encoding standard. Windows uses it exclusively at the system level for character and string manipulation. Unicode simplifies localization of software and improves multilingual text processing. By implementing it in an application, a developer can enable the application with universal data exchange capabilities for global marketing, using a single binary file for every possible character code.

Unicode defines semantics for each character, standardizes script behavior, provides a standard algorithm for bidirectional text, and defines cross-mappings to other standards. Among the scripts supported by Unicode are Latin, Greek, Han, Hiragana, and Katakana. Supported languages include, but are not limited to, German, French, English, Greek, Chinese, and Japanese.

Unicode can represent all the world's characters in modern computer use, including technical symbols and special characters used in publishing. Because each Unicode character is 16 bits wide, it is possible to have separate values for up to 65,536 characters. Unicode-enabled functions are often referred to as "wide-character" functions.

Win32 functions support applications that use either Unicode or the regular ANSI character set. Mixed use in the same application is also possible. Adding Unicode support to an application is easy, and a developer can even maintain a single set of sources from which to compile an application that supports either Unicode or the Windows ANSI character set.

Win32 functions support Unicode by assigning its strings a specific data type and providing a separate set of entry points and messages to support this new data type. A series of macros and naming conventions make transparent migration to Unicode, or even compiling both non-Unicode and Unicode versions of an application from the same set of sources, a straightforward matter.

Implementing Unicode as a separate data type also enables the compiler's type checking to ensure that only Unicode parameters are used with functions expecting Unicode strings.


Unicode in Windows

Win32 API elements that use characters are generally implemented in one of three formats:

•	A generic version that can be compiled for either ANSI or Unicode

•	An ANSI version

•	A Unicode version

This guide dicsusses Unicode data types and how they are used in functions and messages; the use of resources, filenames, and command-line arguments; and methods of translating between different types of strings.


Data Types

Most string operations for Unicode can be written by using the same logic used for handling the Windows ANSI character set, except that the basic unit of operation is a 16-bit character instead of an 8-bit byte. The header files provide a number of type definitions that make it easy to create sources that can be compiled for Unicode or for the ANSI character set.

The following example shows the method used in the Win32 header files to define three sets of data types: a set of generic type definitions that can compile for either ANSI or Unicode, and two sets of specific type definitions. The first set of specific type definitions is for use with the existing Windows (ANSI) character set, and the other is for use with Unicode (or wide) characters.

/* Generic types */

#ifdef UNICODE

 typedef wchar_t TCHAR;

#else

 typedef unsigned char TCHAR;

#endif

typedef TCHAR * LPTSTR, *LPTCH;

/* 8-bit character specific */

typedef unsigned char CHAR;

typedef CHAR *LPSTR, *LPCH;

/* Unicode specific (wide characters) */

typedef unsigned wchar_t WCHAR;

typedef WCHAR *LPWSTR, *LPWCH;

The letter T preceding a type definition designates a generic type that can be compiled for either ANSI or Unicode. The letter W preceding a type definition designates a wide-character (Unicode) type. For the actual implementation of this method, see the WINNT.H header file.

An application using generic data types can be compiled for Unicode simply by defining UNICODE before the include statements for the header files. To compile the code for ANSI, omit the UNICODE definition.

Developers are encouraged to use the generic data types, but the specific types exist for applications that require mixed-type control.


Function Prototypes

Function prototypes are also provided in generic, ANSI, and Unicode varieties, as shown below. The generic function prototype consists of the standard function name implemented as a macro. The preprocessor expands each macro into one of the specific function prototypes, depending on whether UNICODE is defined. The letters A (ANSI) and W (wide) are added at the end of the function names in the specific function prototypes. In this example, the generic prototype uses the generic type LPTSTR for the text parameter, but the A and W prototypes use the LPCSTR and LPCWSTR character types, respectively.

SetWindowText(HWND hwnd, LPTSTR lpText);

SetWindowTextA(HWND hwnd, LPCSTR lpText);

SetWindowTextW(HWND hwnd, LPCWSTR lpText);

An application can use the generic function and make Unicode dependent on whether the UNICODE option is used to compile the code, or it can make mixed calls by using the explicit function names ending with A and W.

This three-prototype approach applies to all functions with text arguments. Always use a generic function prototype with the generic string and character types. All function names that end with an uppercase W take wide-character arguments.

Some functions exist only in wide-character versions and can be used only with the appropriate data type.

The reference material for each Unicode-enabled function is labeled with a Unicode icon. If the function exists as a macro that the preprocessor must expand into an ANSI or Unicode form, only the macro form is documented.

Note  Whenever a function has a length parameter for a character string, the length should be given as a count of characters (TCHAR units) in the string. However, functions that require or return pointers to untyped memory blocks, such as the GlobalAlloc function, are exceptions.


Message Translation

Although applications generally use the same window class, messages between windows of different classes are transparently translated by the system.

Even though a window function is implemented to receive messages in Unicode or ANSI format, the window procedure can still send messages or call functions of either type.

The following messages have text arguments and are subject to automatic text translation. (For information about automatic translation, see Subclassing and Automatic Message Translation.)

CB_ADDSTRING	WM_ASKCBFORMATNAME
CB_DIR	WM_CHAR
CB_FINDSTRING	WM_CHARTOITEM
CB_GETLBTEXT	WM_CREATE
CB_INSERTSTRING	WM_DEADCHAR
CB_SELECTSTRING	WM_DEVMODECHANGE
	WM_GETTEXT
EM_GETLINE	WM_MDICREATE
EM_REPLACESEL	WM_MENUCHAR
EM_SETPASSWORDCHAR	WM_NCCREATE
	WM_SETTEXT
LB_ADDFILE	WM_SYSCHAR
LB_ADDSTRING	WM_SYSDEADCHAR
LB_DIR	WM_WININICHANGE
LB_FINDSTRING
LB_GETTEXT
LB_INSERTSTRING
LB_SELECTSTRING


String Functions

All of the string functions listed in this section exist in ANSI and Unicode implementations to support ANSI and Unicode arguments. There are, however, subtle differences among some of them.

The following string functions do not require special comment; their ANSI and Unicode implementations work identically.

CharNext
CharPrev
lstrcat
lstrcpy
lstrlen

The value returned by the lstrlen function is always the number of characters, regardless of whether the ANSI or Unicode form is used.

The following string functions are sensitive to the locale of the current thread (as derived from the locale the user selects in Control Panel). The lstrcmp and lstrcmpi functions do not perform byte comparisons like their ANSI C namesakes; they compare strings according to the rules of the selected locale.

CharLower
CharLowerBuff
CharUpper
CharUpperBuff
lstrcmp
lstrcmpi

The following functions convert between the OEM character set and either ANSI or Unicode, depending on which version is used.

CharToOem
CharToOemBuff
OemToChar
OemToCharBuff

The print function wsprintf supports Unicode by providing the following new and changed data types in its format specifications. These format specifications affect the way the wsprintf function interprets the corresponding passed-in parameter.

Format specification	ANSI version	Unicode version
c	CHAR	WCHAR
C	WCHAR	CHAR
hc, hC	CHAR	CHAR
hs, hS	LPSTR	LPSTR
lc, lC	WCHAR	WCHAR
ls, lS	LPWSTR	LPWSTR
s	LPSTR	LPWSTR
S	LPWSTR	LPSTR
The data type for the output text always depends on the version of the function. Where the data type of the passed-in parameter and of the output text do not agree, wsprintf will perform a conversion from Unicode to ANSI, or vice versa, as required.

For the Unicode version of wsprintf, the format string is Unicode, as is the output text.


Standard C Functions

The standard C libraries contain wide-character versions of the ANSI string functions that begin with the letters str. The wide-character versions of the functions start with the letters wcs (or sometimes _wcs). The Unicode data type is compatible with the wide-character data type wchar_t in ANSI C; this allows access to the wide-character string functions.

Generic functions exist for all standard C string functions. They start with the letters _tcs and are listed in the TCHAR.H header file. These functions use the generic data types TCHAR and TCHAR*

An application must add the following lines to its program in order to use the generic functions and compile for Unicode:

     #define _UNICODE

     #include <tchar.h>

     #include <wchar.h>

Note that both the TCHAR.H and WCHAR.H are required, and that the leading underscore on the _UNICODE variable is also required.

The wcstombs and mbstowcs functions can convert from the character set supported by the standard C library to Unicode and back, with some limitations. For more information about translating strings to and from Unicode, see Translation Between String Types.

The printf function defined in TCHAR.H supports the same format specifications as wsprintf; for details, see String Functions. Similarly, TCHAR.H contains a wprintf function, in which the format string itself is a Unicode string.


Filenames

In Windows, the ANSI character set is used in window manager and GDI; the MS-DOS FAT file system uses the OEM character set. Windows applications that create MS-DOS files have sometimes had to use the CharToOem and OemToChar functions to translate between these character sets. However, the New Technology file system (NTFS) file system is capable of storing filenames in Unicode; no translation is necessary with NTFS.

With Unicode implementations of the file-system functions, it is not necessary to perform translations to and from ANSI and OEM character sets. Instead, a developer can use a single source file to compile non-Unicode versions of an application by providing macros for functions that are not invoked when compiling for Unicode, such as CharToOem and OemToChar.

The special filename characters in MS-DOS are unchanged in Unicode filenames:

"\," "/," ".," "?," "*."

These special characters are in the ASCII range of characters (0x00 through 0x7F) and their Unicode equivalents are simply the same values in a 2-byte form: 0x0000 through 0x007F.


Translation Between String Types

The following Win32 functions translate character strings from one string type to another.

Function	Description
FoldString	Translates one character string to another.
LCMapString	Maps a character string by locale.
ToUnicode	Translates a virtual-key code into a Unicode character.
MultiByteToWideChar	Maps a multibyte string into a wide-character string.
WideCharToMultiByte	Maps a wide-character string into a multibyte string.
The WideCharToMultiByte and MultiByteToWideChar functions are particularly useful for applications that support several string types. ANSI C also defines the conversion functions wcstombs and mbstowcs, but they can only convert to and from the character set supported by the standard C library.


Command-line Arguments

An application can use the GetCommandLine function to retrieve Unicode command-line arguments by calling it as a Unicode function.


Using Strings and Unicode

•	Using generic data types

•	Registering window classes

•	Subclassing and automatic message translation

•	Using special characters in Unicode

•	Using functions that have no Unicode equivalents


Using Generic Data Types

If you use generic data types in your code, it can be compiled for Unicode simply by defining UNICODE before the include statements for the header files. To compile the code for ANSI, omit the UNICODE definition.

To convert code that processes strings so it can be compiled for either ANSI or Unicode, follow these steps.

1.	Change all character and string types used for text to TCHAR, LPTSTR, or LPTCH.

2.	Be sure that pointers to nontext data buffers or binary byte arrays are coded with the LPBYTE type and not mistakenly with the LPTSTR or LPTCH type. Declare pointers of indeterminate type explicitly as void pointers by using LPVOID, as appropriate.

3.	Make pointer arithmetic type-independent. Using units of TCHAR size yields variables that are two bytes if UNICODE is defined, and one byte if UNICODE is not defined. Using pointer arithmetic always returns the number of elements pointed to by the pointer, whether the elements are one or two bytes in size. The following expression always returns the number of elements, regardless of whether UNICODE is defined:

cCount = lpEnd - lpStart;

The following expression determines the number of bytes used:

cByteCount = (lpEnd - lpStart) * sizeof(TCHAR);

There is no need to change a statement like the following one, because the pointer increment points to the next character element.

chNext = *++lpText;

4.	Replace literal strings and manifest character constants with macros. Change expressions like the following one.

    while(*lpFileName++ != '\\') {

/* .

/* .

/* .

    }

Use the TEXT macro as follows in this expression.

    while(*lpFileName++ != TEXT('\\')) {

        ./*

        ./*

        ./*

    }

Precede a literal string in the Unicode form of a function by the letter L. The TEXT macro causes strings to be evaluated as L"string" when UNICODE is defined, and to "string" otherwise. The following call to the Unicode version of lstrlen demonstrates the use of the L identifier.

cch == lstrlenW(L"hello world");

For easier management, move literal strings into resources, especially if they contain characters outside the ASCII range (that is, 0x00 through 0x7F).

5.	Call only the Unicode versions of the standard C library string functions, as listed in Standard C Functions.

6.	Change any code that relies on 255 as the largest value for a character.

When you compile code that you have changed as outlined above, the compiler creates the same binary file as it did before you made the changes. When you compile the code using the UNICODE option, however, it is compiled as a Unicode application.


Registering Window Classes

A window class is supported by a window procedure. You can register a window class by using either the RegisterClassA or RegisterClassW function. If you register the window class by using RegisterClassA, the application tells the system that the windows of the created class expect messages with text or character parameters to use the ANSI character set; if you register it by using RegisterClassW, the application requests that the system pass text parameters of messages as Unicode. The IsWindowUnicode function enables applications to query the nature of each window.

The following example shows how to register an ANSI window class and a Unicode window class and how to write the window procedures for both cases. For the purposes of this example, all functions and structures are shown with the specific A or W data types. Using the techniques explained in Using Generic Data Types, you could alternatively write this example by using generic data types, so that it could be compiled as either ANSI or Unicode, depending on whether UNICODE is defined.

/* Register an ANSI window class. */

WNDCLASSA AnsiWndCls;

AnsiWndCls.style         = CS_DBLCLKS | CS_PARENTDC;

AnsiWndCls.lpfnWndProc   = (WNDPROC)AnsiWndProc;

AnsiWndCls.cbClsExtra    = 0;

AnsiWndCls.cbWndExtra    = 0;

AnsiWndCls.hInstance     = hmodUser;

AnsiWndCls.hIcon         = NULL;

AnsiWndCls.hCursor       = LoadCursor(NULL, (LPTSTR)IDC_IBEAM);

AnsiWndCls.hbrBackground = NULL;

AnsiWndCls.lpszMenuName  = NULL;

AnsiWndCls.lpszClassName = "TestAnsi";

RegisterClassA(&AnsiWndCls);

/* Register a Unicode window class. */

WNDCLASSW UnicodeWndCls;

UnicodeWndCls.style         = CS_DBLCLKS | CS_PARENTDC;

UnicodeWndCls.lpfnWndProc   = (WNDPROC)UniWndProc;

UnicodeWndCls.cbClsExtra    = 0;

UnicodeWndCls.cbWndExtra    = 0;

UnicodeWndCls.hInstance     = hmodUser;

UnicodeWndCls.hIcon         = NULL;

UnicodeWndCls.hCursor       = LoadCursor(NULL,(LPTSTR)IDC_IBEAM);

UnicodeWndCls.hbrBackground = NULL;

UnicodeWndCls.lpszMenuName  = NULL;

UnicodeWndCls.lpszClassName = L"TestUnicode";

RegisterClassW(&UnicodeWndCls);

The following example shows the difference between handling the WM_CHAR message in an ANSI window procedure and a Unicode window procedure.

/* ANSI Window Procedure */

LONG AnsiWndProc(HWND hwnd, UINT message,

                 WPARAM wParam, LPARAM lParam)

{

    /* Dispatch the messages that can be received. */

    switch (message) {

        case WM_CHAR:

            /*

             * wParam - the value of the key

             * lParam - (not used in this example)

             */

            if (lstrcmpA("Q", (LPCSTR) wParam)) {

                 /*.

                 /*.

                 /*.

            }

            else {

                 ./*

                 /*.

                 /*.

            }

            break;

        ./*

        ./* process other messages */

        ./*

    }

}

/* Unicode Window Procedure */

LONG UniWndProc(HWND hwnd, UINT message,

    WPARAM wParam, LPARAM lParam)

{

    /* Dispatch the messages that can be received. */

    switch (message) {

        case WM_CHAR:

            /*

             * wParam - the value of the key

             * lParam - (not used in this example)

             */

            if (lstrcmpW(L"Q", (LPCWSTR) wParam)) {

                 /*.

                 /*.

                 /*.

            }

            else {

                 /*.

                 /* .

                 /* .

            }

            break;

        /* .

        /* process other messages */

        /* .

    }

}

All text in messages received by AnsiWndProc will be composed of ANSI characters, and all text in messages received by UniWndProc will be composed of Unicode characters.


Subclassing and Automatic Message Translation

Subclassing is a technique that allows an application to intercept and process messages sent or posted to a particular window before the window has a chance to process them. The system automatically translates messages into ANSI or Unicode form, depending on the form of the function that subclassed the window procedure.

The following call to the SetWindowLongA function subclasses the current window procedure associated with the window identified by the hwnd parameter. The new window procedure, NewWndProc, will receive messages with text in ANSI format.

OldWndProc = (WNDPROC) SetWindowLongA(hwnd,

    GWL_WNDPROC, (LONG)NewWndProc);

When NewWndProc has finished processing a message, it uses the CallWindowProc function as follows to pass the message to OldWndProc.

CallWindowProc(OldWndProc, hwnd, uMessage, wParam, lParam);

If OldWndProc was created with a class style of UNICODE, messages will be translated from the ANSI form received by NewWndProc into Unicode.

Similarly, a call to the SetWindowLongW function would subclass the current window procedure with a window procedure that expects Unicode text messages. Message translation, if necessary, is performed during the processing of the CallWindowProc function.

For more information about subclassing, see Window Procedures.


Using Special Characters in Unicode

There are a few special characters and characters with unusual meanings in Unicode text strings. To avoid unexpected problems with these characters, use the rules provided in the following topics.

•	Null-terminated strings

•	Byte-order mark

•	Escape sequences and control characters

•	Line and paragraph separators

•	ASCII control codes 0x000D and 0x000A

•	Nonspacing characters and diacritics


Null-terminated Strings

Always cast zero to TCHAR when using null-terminated strings. The code 0x0000 is the Unicode string terminator for null-terminated strings. A single null byte is not sufficient for this code, because many Unicode characters contain null bytes as either the high or the low byte. An example is the letter A, for which the character code is 0x0041.


Byte-order Mark

Always prefix a Unicode plain text file with a byte-order mark. Because Unicode plain text is a sequence of 16-bit codes, it is sensitive to the byte ordering used when the text was written.

A byte-order mark is not a control character that selects the byte order of the text; it simply informs an application receiving the file that the file is byte ordered.

Ideally, all Unicode text would follow only one set of byte-ordering rules. This is not possible, however, because microprocessors differ in the position of the least significant byte: Intel® and MIPS® processors have the least significant byte first; Motorola processors (and byte-reversed Unicode files) have it last. With only a single set of byte-ordering rules, users of one type of microprocessor would be forced to swap the byte order every time a plain text file is read from or written to, even if the file is never transferred to another system based on a different microprocessor.

The preferred place to specify byte order is in a file header, but text files do not have headers. Therefore, Unicode has defined a character (0xFEFF) and a noncharacter (0xFFFE) as byte-order marks. They are mirror byte-images of each other.

Since the sequence 0xFEFF is exceedingly rare at the outset of regular non-Unicode text files, it can serve as an implicit marker or signature to identify the file as a Unicode file. Applications written to read both Unicode and non-Unicode text files should use the presence of this sequence as a near-certain indicator that the file is a Unicode file. (Compare this technique to using the MS-DOS EOF marker to terminate text files.)

When an application finds 0xFEFF at the beginning of a text file, it typically processes the file as though it were a Unicode file, although it may also perform further heuristic checks to verify that this is true. Such a check could be as simple as a test of whether the variation in the low-order bytes is much higher than the variation in the high-order bytes. For example, if ASCII text is converted to Unicode text, every second byte is zero. Also, checking both for the linefeed and carriage-return characters (0x000A and 0x000D) and for even or odd file size can provide a strong indicator of the nature of the file.

When an application finds 0xFFFE at the beginning of a text file, it interprets it to mean the file is a byte-reversed Unicode file. The application can either swap the order of the bytes or alert the user that an error has occurred.

The Unicode byte-order mark character is not found in any code page, so it disappears if data is converted to ANSI. Unlike other Unicode characters, it is not replaced by a default character when it is converted. If a byte-order mark is found in the middle of a file, it is not interpreted as a Unicode character and has no effect on text output.

The Unicode value 0xFFFF is illegal in plain text files and cannot be passed between Windows functions. The value 0xFFFF is reserved for an application's private use.


Escape Sequences and Control Characters

Translate escape sequences character by character into Unicode. When an ASCII plain text file is converted to Unicode, there is a chance that it will subsequently be converted back to ASCII. Converting escape sequences into Unicode on a character-by-character basis, rather than as a single 2-byte characters makes it possible to perform the reverse conversion without recognizing and parsing the escape sequences as such. For example, ESC+A should become 0x001B (ESC), 0x0041 (A), rather than 0x411B.

The first 32 sixteen-bit characters in Unicode are intended for the 32 control characters. This approach supports the existing use of control characters for formatting purposes — that is, Unicode applications can treat these control characters in exactly the same way as they treat their ASCII equivalents.


Line and Paragraph Separators

Use the line-separator character (0x2028) and the paragraph-separator character (0x2029) to divide plain text. A new line is begun after each line separator. A new paragraph is begun after each paragraph separator.

Because these are separator codes, it is not necessary to start the first line or paragraph in the file with them, or to end the last line or paragraph with them. (Doing so would indicate that there is an empty line or paragraph in that location.)

The line separator can be used to indicate an unconditional end of line. However, line separators do not correspond to the carriage-return and linefeed characters, or to the carriage-return−linefeed character combination; they must be processed separately from carriage return and linefeed characters.

The paragraph separator can be inserted between paragraphs of text. This allows plain text files to be created that can be formatted with different line widths on different systems. The receiving system can ignore any line breaks and break paragraphs only at the paragraph separators.


ASCII Control Codes 0x000D and 0x000A

The Unicode standard does not prescribe a specific meaning for the control codes 0x000D (carriage return) and 0x000A (linefeed). There is no requirement that these codes be used in combination, and if used individually, either code may represent either itself only or both codes together. It is entirely up to the application to determine what these codes represent. (Applications have always had to interpret these control codes in ASCII; the Unicode policy is not a change in their use.)


Nonspacing Characters and Diacritics

When breaking lines or otherwise separating text, be sure to keep nonspacing characters with their base characters. Many scripts contain characters that visually combine with other characters on output — for example, the diacritical marks (or "floating accents"). In Unicode, nonspacing characters follow their base character.


Using Functions That Have No Unicode Equivalents

Windows functions that have not been exported in a Unicode version have typically been replaced by more powerful or extended functions that do support Unicode. If you are porting code that calls the OpenFile function, for example, you can support Unicode by using the CreateFile or CreateFileEx function instead.

If a function has no Unicode equivalent, you can map characters to and from 8-bit character sets before and after the function call. For example, the number-formatting functions atoi and itoa use only the digits 0 through 9. Normally, mapping Unicode to 8-bit characters could cause loss of data, but you can avoid this by making your code type independent and conditionalizing the expressions. For example, the following statements are type dependent and should be changed to support Unicode.

    char str[4];

    num = atoi(str);

These statements could be rewritten as follows to make them type independent.

    TCHAR tstr[4];

    CHAR strTmp[SIZE];

    #ifdef UNICODE

    wcstombs(strTmp, (const wchar_t *) tstr, sizeof(strTmp));

    num = atoi(strTmp);

    #else

    num = atoi(tstr);

    #endif

In this example, the wcstombs function is the standard C function that translates Unicode to ASCII. The example relies on the fact that the digits 0 through 9 can always be translated from Unicode to ASCII, even if some of the surrounding text cannot. The atoi function stops at any character that is not a digit. You can use the LCMapString function if you need to process text that includes the native digits provided for some of the scripts in Unicode.


Unicode and Character Set Functions

This section describes the character set functions. On errors, some of these functions set an extended error value. Use the GetLastError function to retrieve this value.

IsDBCSLeadByteEx
TranslateCharsetInfo
WideCharToMultiByte


Obsolete Unicode Functions

The AnsiToOem function is obsolete. Use the CharToOem function.

The AnsiToOemBuff function is obsolete. Use the CharToOemBuff function.

The OemToAnsi function is obsolete. Use the OemToChar function.

The OemToAnsiBuff function is obsolete. Use the OemToCharBuff function.


Unicode and Character Set Structures

This section describes the structures used by the character set functions.

CHARSETINFO
FONTSIGNATURE
LOCALESIGNATURE


Unicode and Character Set Constants

This section describes the constants used with the character set functions.


ANSI Code Page Identifiers
ANSI Code-Page Identifiers

Identifier	Meaning
874	Thai
932	Japan
936	Chinese (PRC, Singapore)
949	Korean
950	Chinese (Taiwan, Hong Kong)
1200	Unicode (BMP of ISO 10646)
1250	Windows 3.1 Eastern European
1251	Windows 3.1 Cyrillic
1252	Windows 3.1 Latin 1 (US, Western Europe)
1253	Windows 3.1 Greek
1254	Windows 3.1 Turkish
1255	Hebrew
1256	Arabic
1257	Baltic


OEM Code Page Identifiers
OEM Code-Page Identifiers

Identifier	Meaning
437	MS-DOS United States
708	Arabic (ASMO 708)
709	Arabic (ASMO 449+, BCON V4)
710	Arabic (Transparent Arabic)
720	Arabic (Transparent ASMO)
737	Greek (formerly 437G)
775	Baltic
850	MS-DOS Multilingual (Latin I)
852	MS-DOS Slavic (Latin II)
855	IBM Cyrillic (primarily Russian)
857	IBM Turkish
860	MS-DOS Portuguese
861	MS-DOS Icelandic
862	Hebrew
863	MS-DOS Canadian-French
864	Arabic
865	MS-DOS Nordic
866	MS-DOS Russian (former USSR)
869	IBM Modern Greek
874	Thai
932	Japan
936	Chinese (PRC, Singapore)
949	Korean
950	Chinese (Taiwan, Hong Kong)
1361	Korean (Johab)


Code Page Identifiers
Code-Page Identifiers

Identifier	Meaning
037	EBCDIC
437	MS-DOS  United States
500	EBCDIC "500V1"
708	Arabic (ASMO 708)
709	Arabic (ASMO 449+, BCON V4)
710	Arabic (Transparent Arabic)
720	Arabic (Transparent ASMO)
737	Greek (formerly 437G)
775	Baltic
850	MS-DOS  Multilingual (Latin I)
852	MS-DOS  Slavic (Latin II)
855	IBM Cyrillic (primarily Russian)
857	IBM Turkish
860	MS-DOS  Portuguese
861	MS-DOS Icelandic
862	Hebrew
863	MS-DOS Canadian-French
864	Arabic
865	MS-DOS Nordic
866	MS-DOS Russian
869	IBM Modern Greek
874	Thai
875	EBCDIC
932	Japan
936	Chinese (PRC, Singapore)
949	Korean
950	Chinese (Taiwan, Hong Kong)
1026	EBCDIC
1200	Unicode (BMP of ISO 10646)
1250	Windows 3.1 Eastern European
1251	Windows 3.1 Cyrillic
1252	Windows 3.1 US (ANSI)
1253	Windows 3.1 Greek
1254	Windows 3.1 Turkish
1255	Hebrew
1256	Arabic
1257	Baltic
1361	Korean (Johab)
10000	Macintosh Roman
10001	Macintosh Japanese
10006	Macintosh Greek I
10007	Macintosh Cyrillic
10029	Macintosh Latin 2
10079	Macintosh Icelandic
10081	Macintosh Turkish


Codepage Bitfields
Code-Page Bitfields

Bit	Code page	Description
ANSI
0	1252	Latin 1
1	1250	Latin 2: Eastern Europe
2	1251	Cyrillic
3	1253	Greek
4	1254	Turkish
5	1255	Hebrew
6	1256	Arabic
7	1257	Baltic
8 - 16		Reserved for ANSI
ANSI and OEM
17	874	Thai
18	932	JIS/Japan
19	936	Chinese: Simplified chars--PRC and Singapore
20	949	Korean Unified Hangeul Code (Hangeul TongHabHyung Code)
21	950	Chinese: Traditional chars--Taiwan and Hong Kong
22 - 29		Reserved for alternate ANSI and OEM
30 - 31		Reserved by system.
OEM
32 - 47		Reserved for OEM
48	869	IBM Greek
49	866	MS-DOS Russian
50	865	MS-DOS Nordic
51	864	Arabic
52	863	MS-DOS Canadian French
53	862	Hebrew
54	861	MS-DOS Icelandic
55	860	MS-DOS Portuguese
56	857	IBM Turkish
57	855	IBM Cyrillic; primarily Russian
58	852	Latin 2
59	775	Baltic
60	737	Greek; former 437 G
61	708	Arabic; ASMO 708
62	850	WE/Latin 1
63	437	US


Networks

An application written for Microsoft® Windows® can use the network functions in the Microsoft® Win32® application programming interface (API) to implement networking capabilities without making allowances for a particular network provider or physical network implementation.


About Networks

Win32 network functions are network independent. Applications can use these functions to add and cancel network connections and to retrieve information about the current configuration of the network. In addition, the Win32 API implements a version of the NetBIOS network interface for applications that require it.

In addition to using the network functions, processes can also use the Win32 API implementations of mailslots and named pipes to communicate with one another. For more information about these subjects, see Mailslots and Pipes.

The following figure shows the structure of a typical network.

In the preceding figure, the hierarchy for Microsoft Advanced Server resources is given in detail as Network provider #1. Network resources from other providers have different hierarchical systems. An application does not need information about the hierarchy before it begins to work with a network. It can proceed from the network root (that is, the topmost container resource) and retrieve information about the network's resources as the information is required.

Network resources that contain other resources are called containers. Container resources are in boxes in the preceding figure.

Resources that do not contain other resources are objects. Sharepoint #1 and Sharepoint #2 in the figure are objects. A sharepoint is an object that is accessible across the network, such as a printer or a shared directory.


Network-Independent Functions

Windows version 3.1 included the following network-independent network functions:

WNetAddConnection
WNetCancelConnection
WNetGetConnection

The Win32 API supports these functions and has added the following network and network enumeration functions:

WNetAddConnection2	WNetEnumResource
WNetCancelConnection2	WNetGetLastError
WNetCloseEnum	WNetGetUser
WNetConnectionDialog	WNetOpenEnum
WNetDisconnectDialog
Many of these functions use a NETRESOURCE structure, which is also part of the Win32 API. WNetAddConnection and WNetCancelConnection are supported for compatibility with earlier versions of Windows. However, new applications typically use WNetAddConnection2 and WNetCancelConnection2 instead.

An application can use the network functions to browse, add, or cancel network connections anywhere in the hierarchy. By starting at the network root, the resources from all network providers can be enumerated.

A persistent connection is a network connection that Windows automatically restores when the user logs on. Using WNetAddConnection2 and WNetCancelConnection2, an application can control whether a network connection is persistent from one session to the next.


The Netbios Function

The Netbios function is provided primarily for applications that were written for the NetBIOS interface and need to be ported to Windows. Applications not requiring compatibility with NetBIOS can usually use other interfaces, such as mailslots and named pipes, to accomplish tasks similar to those supported by Netbios.

Netbios in the Win32 API takes one parameter: a pointer to a structure describing a network control block (NCB). The NCB structure contains information about the network environment and a pointer to a buffer that is used for messages or for further data about the network.


Windows NetBios Enhancements

The Win32 implementation of the Netbios function includes the following enhancements that are not part of the NetBIOS 3.0 specification:

•	POST routines can be called from the C programming language by means of the ncb_post member of the NCB structure.

•	Each asynchronous network control block can supply an event (in the ncb_event member of the NCB structure) set to the signaled state when the NCB completes.

•	An application can enumerate all available LAN adapters by using the NCBENUM command in the ncb_command member of the NCB structure.


Differences Between Windows and NetBIOS

In addition to the enhancements listed in the preceding section, the following differences exist between the Win32 implementation of the Netbios function and the NetBIOS 3.0 specification:

•	The system does not monitor the number of outstanding NCB commands specified when the NCBRESET command is issued. The memory quota limits for Windows are used to limit the total resources an application can use.

•	Asynchronous commands on invalid sessions are rejected when they are submitted.

•	The numbers of the network names (the ncb_num member of the NCB structure) are assigned on a per-process basis.

•	Requests for the status of the local adapter retrieve only the names that were added by the process making the request.

•	The value 1 for the ncb_lana_num member of the NCB structure is not exclusive when the NCBRESET command is issued. All MS-DOS and 16-bit Windows-based applications also share access to name number 1.


Using Networks

The Windows network functions enable your application to query and control network connections directly or to give direct control of the network connections to the user. To use these functions, you must link to the multiple-provider router library (MPR.LIB). This section discusses how to use the network functions in your application.

•	Using the connections dialog box

•	Enumerating network resources

•	Adding a network connection

•	Retrieving the connection name

•	Retrieving the user name

•	Canceling a network connection

•	Retrieving network errors


Using the Connections Dialog Box

The WNetConnectionDialog function creates a dialog box that allows the user to browse and connect to network resources. Conversely, the WNetDisconnectDialog function creates a dialog box that allows the user to disconnect from them.

The following example shows how to use the WNetConnectionDialog function to create a dialog box that displays disk resources.

DWORD dwResult;

dwResult = WNetConnectionDialog(hwnd,

    RESOURCETYPE_DISK);

if(dwResult != NO_ERROR) {

    /*

     * An application-defined error handler is demonstrated in the

     * section titled "Retrieving Network Errors."

     */

    NetErrorHandler(hwnd, dwResult, (LPSTR)"WNetConnectionDialog");

    return FALSE;

}


Enumerating Network Resources

To enumerate a network container resource, your application should pass the address of a NETRESOURCE structure to the WNetOpenEnum function. WNetOpenEnum creates a handle to the resource described by the NETRESOURCE structure. The application then passes this handle to the WNetEnumResource function, which returns information about the resource in the form of an array of NETRESOURCE structures. When the handle is no longer needed, the application can close it by calling the WNetCloseEnum function.

Your application can continue enumerating any container resource described in the array of NETRESOURCE structures retrieved by WNetEnumResource. If the dwUsage member of the NETRESOURCE structure is RESOURCEUSAGE_CONTAINER, the application can pass the address of that structure to WNetOpenEnum to open the container and continue the enumeration. If dwUsage is RESOURCEUSAGE_CONNECTABLE, the application can pass the structure's address to the WNetAddConnection2 function.

The following example illustrates an application-defined function (EnumerateFunc) that enumerates all the resources on a network. When calling this function, specify NULL for the pointer to the NETRESOURCE structure. When WNetOpenEnum receives the NULL pointer, it retrieves a handle to the root of the network. Whenever a NETRESOURCE structure retrieved by WNetEnumResource is RESOURCEUSAGE_CONTAINER, the EnumerateFunc function calls itself and uses a pointer to that structure in its call to WNetOpenEnum.

BOOL FAR PASCAL EnumerateFunc(hwnd, hdc, lpnr)

HWND hwnd;

HDC hdc;

LPNETRESOURCE lpnr;

{

    DWORD dwResult, dwResultEnum;

    HANDLE hEnum;

    DWORD cbBuffer = 16384; /* 16K is reasonable size                 */

    DWORD cEntries = 0xFFFFFFFF; /* enumerate all possible entries    */

    LPNETRESOURCE lpnrLocal;     /* pointer to enumerated structures  */

    DWORD i;

    dwResult = WNetOpenEnum(RESOURCE_GLOBALNET,

        RESOURCETYPE_ANY,

        0,                 /* enumerate all resources                 */

        lpnr,              /* NULL first time this function is called */

        &hEnum);           /* handle to resource                      */

    if (dwResult != NO_ERROR) {

        /*

         * An application-defined error handler is demonstrated in the

         * section titled "Retrieving Network Errors."

         */

        NetErrorHandler(hwnd, dwResult, (LPSTR)"WNetOpenEnum");

        return FALSE;

    }

    do {

        /* Allocate memory for NETRESOURCE structures. */

        lpnrLocal = (LPNETRESOURCE) GlobalAlloc(GPTR, cbBuffer);

        dwResultEnum = WNetEnumResource(hEnum, /* resource handle     */

            &cEntries,               /* defined locally as 0xFFFFFFFF */

            lpnrLocal,               /* LPNETRESOURCE                 */

            &cbBuffer);              /* buffer size                   */

        if (dwResultEnum == NO_ERROR) {

            for(i = 0; i < cEntries; i++) {

                /*

                 * Following is an application-defined function for

                 * displaying contents of NETRESOURCE structures.

                 */

                DisplayStruct(hdc, &lpnrLocal[i]);

                /*

                 * If this NETRESOURCE is a container, call the function

                 * recursively.

                 */

                if(RESOURCEUSAGE_CONTAINER ==

                        (lpnrLocal[i].dwUsage & RESOURCEUSAGE_CONTAINER))

                    if(!EnumerateFunc(hwnd, hdc, &lpnrLocal[i]))

                        TextOut(hdc, 10, 10,

                            "EnumerateFunc returned FALSE.", 29);

            }

        }

        else if (dwResultEnum != ERROR_NO_MORE_ITEMS) {

            NetErrorHandler(hwnd, dwResultEnum, (LPSTR)"WNetEnumResource");

            break;

        }

    }

    while(dwResultEnum != ERROR_NO_MORE_ITEMS);

    GlobalFree((HGLOBAL) lpnrLocal);

    dwResult = WNetCloseEnum(hEnum);

    if(dwResult != NO_ERROR) {

        NetErrorHandler(hwnd, dwResult, (LPSTR)"WNetCloseEnum");

        return FALSE;

    }

    return TRUE;

}


Adding a Network Connection

To make a connection to a network resource described by a NETRESOURCE structure, an application can call the WNetAddConnection2 function, as shown in the following example.

DWORD dwResult;

NETRESOURCE nr;

dwResult = WNetAddConnection2(&nr, /* NETRESOURCE from enumeration */

    (LPSTR) NULL,             /* no password                       */

    (LPSTR) NULL,             /* logged-in user                    */

    CONNECT_UPDATE_PROFILE);  /* update profile with connect info  */

if (dwResult == ERROR_ALREADY_ASSIGNED) {

    TextOut(hdc, 10, 10, "Already connected to specified resource.", 40);

    return FALSE;

}

else if (dwResult == ERROR_DEVICE_ALREADY_REMEMBERED) {

    TextOut(hdc, 10, 10,

        "Attempted reassignment of remembered device.", 44);

    return FALSE;

}

else if(dwResult != NO_ERROR) {

    /*

     * An application-defined error handler is demonstrated in the

     * section titled "Retrieving Network Errors."

     */

    NetErrorHandler(hwnd, dwResult, (LPSTR)"WNetAddConnection2");

    return FALSE;

}

TextOut(hdc, 10, 10, "Connected to specified resource.", 32);

return TRUE;

The WNetAddConnection function is supported for compatibility with earlier versions of Windows. For new applications, use WNetAddConnection2.


Retrieving the Connection Name

To retrieve the name of the network resource associated with a local device, an application can use the WNetGetConnection function, as shown in the following example.

CHAR szDeviceName[80];

DWORD dwResult, cchBuff = sizeof(szDeviceName);

dwResult = WNetGetConnection("z:",

    (LPSTR) szDeviceName,

    &cchBuff);

switch (dwResult) {

    case NO_ERROR:

        TextOut(hdc, 10, 10, (LPSTR) szDeviceName,

            lstrlen((LPSTR) szDeviceName));

        break;

    case ERROR_NOT_CONNECTED:

        TextOut(hdc, 10, 10, "Device z: not connected.", 24);

    case ERROR_CONNECTION_UNAVAIL:

        /* A connection is remembered but not connected. */

        TextOut(hdc, 10, 10, "Connection unavailable.", 23);

    default:

        /*

         * An application-defined error handler is demonstrated in the

         * section titled "Retrieving Network Errors."

         */

        NetErrorHandler(hwnd, dwResult, (LPSTR)"WNetGetConnection");

        return FALSE;

}


Retrieving the User Name

To retrieve the name of the user associated either with a local device connected to a network resource or with the name of a network, an application can call the WNetGetUser function. The following example uses the device name to retrieve the name of the user.

CHAR szUserName[80];

DWORD dwResult, cchBuff = 80;

dwResult = WNetGetUser("z:",

    (LPSTR) szUserName,

    &cchBuff);

if(dwResult == NO_ERROR)

    TextOut(hdc, 10, 10,

        (LPSTR) szUserName,

        lstrlen((LPSTR) szUserName));

else {

    /*

     * An application-defined error handler is demonstrated in the

     * section titled "Retrieving Network Errors."

     */

    NetErrorHandler(hwnd, dwResult, (LPSTR)"WNetGetUser");

    return FALSE;

}


Canceling a Network Connection

To cancel a connection to a network resource, an application can call the WNetCancelConnection2 function, as shown in the following example.

DWORD dwResult;

dwResult = WNetCancelConnection2("z:",

    CONNECT_UPDATE_PROFILE, /* remove connection from profile */

    FALSE);               /* fail if open files or jobs       */

if (dwResult == ERROR_NOT_CONNECTED) {

    TextOut(hdc, 10, 10, "Drive z: not connected.", 23);

    return FALSE;

}

else if(dwResult != NO_ERROR) {

    /*

     * An application-defined error handler is demonstrated in the

     * section titled "Retrieving Network Errors."

     */

    NetErrorHandler(hwnd, dwResult, (LPSTR)"WNetCancelConnection2");

    return FALSE;

}

TextOut(hdc, 10, 10, "Connection closed for z:.", 25);

The WNetCancelConnection function is supported for compatibility with earlier versions of Windows. For new applications, use WNetCancelConnection2.


Retrieving Network Errors

When one of the Windows network functions returns WN_EXTENDED_ERROR, an application can call the WNetGetLastError function to get more information about the error that occurred. This information is usually specific to the network provider.

The following example illustrates an application-defined error-handling function (NetErrorHandler) that takes three arguments: a window handle, the error code returned by one of the Windows network functions, and the name of the function that produced the error. If the error code is WN_EXTENDED_ERROR, NetErrorHandler calls WNetGetLastError to get extended error information.

BOOL WINAPI NetErrorHandler(hwnd, dwErrorCode, lpszFunction)

HWND  hwnd;

DWORD dwErrorCode;

LPSTR lpszFunction;

{

    DWORD dwWNetResult, dwLastError;

    CHAR szError[256];

    CHAR szCaption[256];

    CHAR szDescription[256];

    CHAR szProvider[256];

    /* The following code performs standard error-handling. */

    if (dwErrorCode != ERROR_EXTENDED_ERROR) {

        wsprintf((LPSTR) szError, "%s failed; \nResult is %ld",

            lpszFunction, dwErrorCode);

        wsprintf((LPSTR) szCaption, "%s error", lpszFunction);

        MessageBox(hwnd, (LPSTR) szError, (LPSTR) szCaption, MB_OK);

        return TRUE;

    }

    /*

     * The following code performs error-handling when the

     * ERROR_EXTENDED_ERROR return value indicates that WNetGetLastError

     * can retrieve additional information.

     */

    else {

        dwWNetResult = WNetGetLastError(&dwLastError,

            (LPSTR) szDescription,  /* buffer for error description  */

            sizeof(szDescription),

            (LPSTR) szProvider,     /* buffer for provider name      */

            sizeof(szProvider));

        if(dwWNetResult != NO_ERROR) {

            wsprintf((LPSTR) szError,

                "WNetGetLastError failed; error %ld", dwWNetResult);

            MessageBox(hwnd, (LPSTR) szError,

                "WNetGetLastError", MB_OK);

            return FALSE;

        }

        wsprintf((LPSTR) szError,

            "%s failed with code %ld;\n%s",

            (LPSTR) szProvider, dwLastError, (LPSTR) szDescription);

        wsprintf((LPSTR) szCaption, "%s error", lpszFunction);

        MessageBox(hwnd, (LPSTR) szError, (LPSTR) szCaption, MB_OK);

        return TRUE;

    }

}


Network Functions

Following are the functions used with networks.

Netbios
WNetAddConnection
WNetAddConnection2
WNetAddConnection3
WNetCancelConnection
WNetCancelConnection2
WNetCloseEnum
WNetConnectionDialog
WNetDisconnectDialog
WNetEnumResource
WNetGetConnection
WNetGetLastError
WNetGetUniversalName
WNetGetUser
WNetOpenEnum


 LAN Manager Functions

Overview of Windows Networking Functions

For OS/2®-based servers the Microsoft® LAN Manager functions provided much of the functionality required for a network operating system; this functionality was missing from the local operating system. The Microsoft® Windows NT™ operating system will provide this missing functionality in the base. However, in order to make the migration of existing 16-bit applications as easy as possible, it is necessary to still define 32-bit equivalents of some of the LAN Manager functions.

The Windows networking functions specified in this online help are designed to provide some of the API functionality that was available in LAN Manager 2.x. They are not the base Windows NT networking functions. Windows NT takes some of the functionality that was previously supplied by the networking software, and moves this into the base functions (such as error and audit logging, printing). Windows NT also provides a network-independent set of network functions (the WNet functions) that allow network functions to work across different network vendors' products. If a base function or WNet function exists that could be used by your application, you should convert from the Windows networking function to the public Windows NT equivalent. There are at least three reasons to make the change now:

1.	The WNet functions are network independent, while the Windows networking functions only work on LAN Manager networks.

2.	Some of the Windows networking functions specified in this document may not be supported in future releases of Windows NT if they have been superseded by base functions or WNet functions. (Of course Microsoft does not plan to remove specific Windows networking functions unless equivalent or better functionality is available from other functions.)

3.	The Windows networking functions may not be supported on some other future Microsoft platforms, since they are not part of the Microsoft® Win32® application programming interface (API).

In this documentation, equivalent Win32 functions will be listed that could be used in place of the Windows networking function. If at all possible, this is the function that your application should use.

This documentation assumes that you are familiar with the existing set of 16-bit LAN Manager functions. The 32-bit widening of the API data structures is specified here, but the description of the functionality for each field is not covered unless the functionality has changed from that specified in the LAN Manager 2.x Programmer's Reference.


 API Buffers

The RPC run times will allocate the buffers required to remote the APIs. This is a requirement for both efficiency and interoperability. Using the RPC run times to allocate the API transmission buffers results in the two significant differences between a LAN Manager 2.x API and windows networking function.

•	For a set type function (data to the server) the function caller specifies a buffer containing the information structure relevant to the function level but does not specify the buffer length.

•	For a get type function (data returned from the server) the caller does not pre-allocate a buffer for the return information. The caller passes a LPBYTE * to the function on input. On successful return the buffer pointer will contain a pointer to a buffer containing the return information. When the caller has finished processing the returned information NetApiBufferFree must be called. This simplifies the calling code, because the caller does not need to guess at the size of the buffer required and will not need to resize and reissue the function as was the case with the LAN Manager 2.x functions.


 API Data Alignment

All data structures specified for the Windows networking functions will be 32-bit word aligned. The base size for an API structure element will be a DWORD.


 Enumeration Buffer Lengths

Enumeration functions will take an advisory maximum data length parameter, prefmaxlen, which allows a control on the number of bytes returned from an enumeration call. The prefered length is specified in units of 8-bit bytes. The actual function may return more than the prefered maximum length.

A Windows networking function enumeration call will not return partial entries.


 Parameter Error Reporting

Add and SetInfo functions will return an index for a parameter in error. The caller may pass a NULL pointer for the parm_err parameter indicating that the field should not be set by the function. For remoted functions to downlevel servers this field will be returned as PARM_ERROR_UNKNOWN by the RpcXlate conversion layer.


 Parmnum for SetInfo

To reduce the number of RPC interfaces we need for each SetInfo function, there will be no Parmnum parameter for the 32-bit SetInfo functions. Instead, the fields that can be set in the information structures will be set using additional infolevels. Although this will increase the number of information levels for a specified function, it will be easier to program to them. In an attempt to keep the mapping to and from downlevel calls simple, the new information levels will be easily mapped to the old parmnum values. By subtracting a specific number like PARMNUM_BASE_INFOLEVEL (whose value will be 1000).


 Parmnum for GetInfo

There will be no addition of a parmnum field for the GetInfo function.


 Embedded Strings

Windows networking function info structures will not contain embedded strings. This improves the alignability of the info structures and allows for OEM flexibility in the core functions. This does not change the feel of the LAN Manager 2.x functions that support string pointers. Code porting merely requires a pointer assignment rather than a string copy.

Any API information field that is returned in an enumeration call that can be subsequently used as a key for a GetInfo call is guaranteed to be present in the enumeration buffer. If the variable length information string that would specify the key field value will not fit then the entire fixed length structure for the entry is not returned. Other variable-length fields will be returned as a NULL pointer for the case where the string will not fit as with LAN Manager 2.x.


 Enumeration Resume Handles

Enumeration resume handles will be identifiers for the actual resume key contained in the instance data for the function. This is required for security, interoperabilty and to simplify the caller code for the function.

If a NULL is passed for the pointer to the resume handle, then no handle is stored and the ennumeration search cannot be continued. This is useful in cases where the application does not want to enumerate all the items.

If an error is returned from an enumeration call, the resume handle must be treated as invalid and not used for any subsequent enumeration calls. For example, the enumeration should be restarted from the beginning.


 User-Specific Information

The LAN Manager 2.x functions assumed that there would only be one user per computer. Therefore, some functions have that assumption built in, such as the NetSession functions. Since this assumption is not valid on Windows NT, the functions have had to be modified to take a user name as an additional parameter in order to be able to uniquely identify the information being queried or set.


 Enumeration Functions

The enumeration functions all return the number of entries read, the total entries that could have been returned if the buffer was big enough, a buffer with the entries, and a return code. The following table details what an application can expect for the various parameters (M is less than N):

Condition	entriesread	totalentries	buffer	returncode
No entries	0	0	NULL	SUCCESS
>= 1 entry	N	N	NOT NULL	SUCCESS
>= 1 entry	M	N	NOT NULL ERROR_MORE_DATA
Failure	?	?	?	Error Code
The caller must first examine the returned status before proceeding to examine any of the other parameters for data.

Note that "totalentries" is the total number of entries that would have been returned if the return buffer was big enough. For example, the total number of entries that were available for entries, using the current resume handle, if any, when the function was called. The one exception to this occurs in the NetUserEnum function when receiving data from a downlevel (OS/2 LANMAN) computer. In this case, the total entries always reflects the total number of entries in the database, no matter where it is in the resume sequence.


 SetInfo Functions

All the SetInfo functions take a structure that contains the new information to be set. If any of the pointer fields in the structure are NULL pointers, then the corresponding field is not changed by the call. This is consistent with LAN Manager 2.x functionality.

In addition, the information levels that allow GUEST access to query information do not allow callers with GUEST access to set the fields. For example, a caller with GUEST that calls the SetInfo function will probably get an error back from the SetInfo call.


 Windows Networking Functions

Function Status

Windows networking functions will use the LAN Manager 2.x error reporting convention. For example, a successful function call returns 0, a nonzero return code indicates an error in the range of the LAN Manager 2.x API/OS2 errors.

An extended error range will be added for Windows NT specific errors.

Since the Windows networking functions will use RPC, the API error definition will also be extended to include RPC error codes.


 RPC Buffer Allocation Errors

Since the RPC run time will allocate memory for send and receive buffers, the function should expect to see RPC allocation errors. In the event of an RPC allocation error, a resumable API handle is invalidated. This is a requirement since resumable functions are not rewindable.


 Obsolete Information Fields

Many of the information fields in the core information structures will be obsolete in the Windows NT service implementation. These fields will remain in the information structure for compatibility with 16-bit versions of Windows and will be returned with an intelligent default on Windows NT systems.


 NLS Support

There are only Unicode versions of the Windows networking functions. If you use these functions, you MUST define Unicode in your source file before including any of the LM include files.


 Windows Networking Function Definitions

The Windows networking functions are 'stdcall' calling convention functions that return a DWORD API status:

#define NET_API_STATUS DWORD

#define NET_API_FUNCTION __stdcall


 Buffer Manipulation Functions

For remotable functions that return information to the caller, the RPC run time will allocate the buffer containing the return information. When the caller has finished processing the returned information, NetApiBufferFree must be called. Additional buffer manipulation functions are also supported.

The buffer manipulation functions are:

NetApiBufferAllocate

NetApiBufferFree

NetApiBufferReallocate

NetApiBufferSize


 Service Functions

Note  A complete set of service functions are provided in the Win32 API. These should be used in place of the NetService functions, unless you have a requirement to control services on a downlevel server. For more details, see Services.

Service functions control services. A service is an application that an administrator can control using the Service Controller interfaces.

Services allow administrators to control applications on the network and maintain the integrity of users' data. On a typical network, applications are shared by many users. If an administrator terminates an application running on a server, a user who has not finished working with that application can lose important data. When an application is implemented as a service, the service controller checks the status before changing the state of the service. Windows NT Networking provides several standard services, such as the Workstation, Server, and Messenger services.

A service can be started using the service functions. At startup time, the service defines whether it can be stopped, paused, and continued.

NetServiceControl controls the operations of network services, and it can provide time hints to controlling applications. NetServiceEnum retrieves information about all started services. NetServiceGetInfo retrieves information about a particular started service. NetServiceInstall starts a network service. NetServiceStatus sets status and code information for a network service.

The service functions provide service information at three levels:

typedef struct _SERVICE_INFO_0 {
LPWSTR	svci0_name;	/* service name */
} SERVICE_INFO_0, *PSERVICE_INFO_0, *LPSERVICE_INFO_0;

typedef struct _SERVICE_INFO_1 {
LPWSTR	svci1_name;
DWORD	svci1_status;
DWORD	svci1_code;
DWORD	svci1_pid;
} SERVICE_INFO_1, *PSERVICE_INFO_1, *LPSERVICE_INFO_1;

typedef struct _SERVICE_INFO_2 {
LPWSTR	svci2_name;
DWORD	svci2_status;
DWORD	svci2_code;
DWORD	svci2_pid;
LPWSTR	svci2_text;

DWORD	svci2_specific_error;
} SERVICE_INFO_2, *PSERVICE_INFO_2, *LPSERVICE_INFO_2;

The service functions are:

NetServiceControl

NetServiceEnum

NetServiceGetInfo

NetServiceInstall


 Server Functions

Server functions perform administrative tasks on a local or remote server. Any user or application with admin group membership on a local or remote server can perform administrative tasks on that server to control its operation, user access, and resource sharing. The low-level parameters that affect a server's operation can be examined and modified by calling NetServerGetInfo and NetServerSetInfo.

The LAN Manager 2.x server API included several fields that logically belong to other LAN Manager services and core Windows NT components. For this reason the server information levels available in LAN Manager 2.x are no longer available in Windows networking functions. The server specific information is available in 3 levels starting at base level 100.


 Server System Information

Level 100 available with guest access:

typedef struct _SERVER_INFO_100 {
DWORD	sv100_platform_id;
LPWSTR	sv100_name;
} SERVER_INFO_100, *PSERVER_INFO_100, *LPSERVER_INFO_100;

Level 101 available with User access:

typedef struct _SERVER_INFO_101 {
DWORD	sv101_platform_id;
LPWSTR	sv101_name;
DWORD	sv101_version_major;
DWORD	sv101_version_minor;
DWORD	sv101_type;
LPWSTR	sv101_comment;
} SERVER_INFO_101, *PSERVER_INFO_101, *LPSERVER_INFO_101;

Level 102 available with Admin access:

typedef struct SERVER_INFO_102 {
DWORD	sv102_platform_id;
LPWSTR	sv102_name;
DWORD	sv102_version_major;
DWORD	sv102_version_minor;
DWORD	sv102_type;
LPWSTR	sv102_comment;
DWORD	sv102_users;
DWORD	sv102_disc;
BOOL	sv102_hidden;
DWORD	sv102_announce;
DWORD	sv102_anndelta;
LPWSTR	sv102_userpath;
} SERVER_INFO_102, *PSERVER_INFO_102, *LPSERVER_INFO_102;

Level 400-499 OS/2 Server information.

Level 402 available with Admin access:

typedef struct _SERVER_INFO_402 {
DWORD	sv402_ulist_mtime;
DWORD	sv402_glist_mtime;
DWORD	sv402_alist_mtime;
LPWSTR	sv402_alerts;
DWORD	sv402_security;
DWORD	sv402_numadmin;
DWORD	sv402_lanmask;
LPWSTR	sv402_guestacct;
DWORD	sv402_chdevs;
DWORD	sv402_chdevq;
DWORD	sv402_chdevjobs;
DWORD	sv402_connections;
DWORD	sv402_shares;
DWORD	sv402_openfiles;
DWORD	sv402_sessopens;
DWORD	sv402_sessvcs;
DWORD	sv402_sessreqs;
DWORD	sv402_opensearch;
DWORD	sv402_activelocks;
DWORD	sv402_numreqbuf;
DWORD	sv402_sizreqbuf;
DWORD	sv402_numbigbuf;
DWORD	sv402_numfiletasks;
DWORD	sv402_alertsched;
DWORD	sv402_erroralert;
DWORD	sv402_logonalert;
DWORD	sv402_accessalert;
DWORD	sv402_diskalert;
DWORD	sv402_netioalert;
DWORD	sv402_maxauditsz;
LPWSTR	sv402_srvheuristics;
} SERVER_INFO_402, *PSERVER_INFO_402, *LPSERVER_INFO_402;

Level 403 available with Admin access:

typedef struct _SERVER_INFO_403 {
DWORD	sv403_ulist_mtime;
DWORD	sv403_glist_mtime;
DWORD	sv403_alist_mtime;
LPWSTR	sv403_alerts;
DWORD	sv403_security;
DWORD	sv403_numadmin;
DWORD	sv403_lanmask;
LPWSTR	sv403_guestacct;
DWORD	sv403_chdevs;
DWORD	sv403_chdevq;
DWORD	sv403_chdevjobs;
DWORD	sv403_connections;
DWORD	sv403_shares;
DWORD	sv403_openfiles;
DWORD	sv403_sessopens;
DWORD	sv403_sessvcs;
DWORD	sv403_sessreqs;
DWORD	sv403_opensearch;
DWORD	sv403_activelocks;
DWORD	sv403_numreqbuf;
DWORD	sv403_sizreqbuf;
DWORD	sv403_numbigbuf;
DWORD	sv403_numfiletasks;
DWORD	sv403_alertsched;
DWORD	sv403_erroralert;
DWORD	sv403_logonalert;
DWORD	sv403_accessalert;
DWORD	sv403_diskalert;
DWORD	sv403_netioalert;
DWORD	sv403_maxauditsz;
LPWSTR	sv403_srvheuristics;
DWORD	sv403_auditedevents;
DWORD	sv403_autoprofile;
LPWSTR	sv403_autopath;
} SERVER_INFO_403, *PSERVER_INFO_403, *LPSERVER_INFO_403;

Level 500-599 Windows NT Server information.

Level 502 available with Admin access:

typedef struct _SERVER_INFO_502 {
DWORD	sv502_sessopens;
DWORD	sv502_sessvcs;
DWORD	sv502_opensearch;
DWORD	sv502_sizreqbuf;
DWORD	sv502_initworkitems;
DWORD	sv502_maxworkitems;
DWORD	sv502_rawworkitems;
DWORD	sv502_irpstacksize;
DWORD	sv502_maxrawbuflen;
DWORD	sv502_sessusers;
DWORD	sv502_sessconns;
DWORD	sv502_maxpagedmemoryusage;
DWORD	sv502_maxnonpagedmemoryusage;
BOOL	sv502_enablesoftcompat;
BOOL	sv502_enableforcedlogoff;
BOOL	sv502_timesource;
BOOL	sv502_acceptdownlevelapis;
BOOL	sv502_lmannounce;
} SERVER_INFO_502, *PSERVER_INFO_502, *LPSERVER_INFO_502;

Level 503 available with Admin access:

typedef struct _SERVER_INFO_503 {
DWORD	sv503_sessopens;
DWORD	sv503_sessvcs;
DWORD	sv503_opensearch;
DWORD	sv503_sizreqbuf;
DWORD	sv503_initworkitems;
DWORD	sv503_maxworkitems;
DWORD	sv503_rawworkitems;
DWORD	sv503_irpstacksize;
DWORD	sv503_maxrawbuflen;
DWORD	sv503_sessusers;
DWORD	sv503_sessconns;
DWORD	sv503_maxpagedmemoryusage;
DWORD	sv503_maxnonpagedmemoryusage;
BOOL	sv503_enablesoftcompat;
BOOL	sv503_enableforcedlogoff;
BOOL	sv503_timesource;
BOOL	sv503_acceptdownlevelapis;
BOOL	sv503_lmannounce;
LPTSTR	sv503_domain;
DWORD	sv503_maxcopyreadlen;
DWORD	sv503_maxcopywritelen;
DWORD	sv503_minkeepsearch;
DWORD	sv503_maxkeepsearch;
DWORD	sv503_minkeepcomplsearch;
DWORD	sv503_maxkeepcomplsearch;
DWORD	sv503_threadcountadd;
DWORD	sv503_numblockthreads;
DWORD	sv503_scavtimeout;
DWORD	sv503_minrcvqueue;
DWORD	sv503_minfreeworkitems;
DWORD	sv503_xactmemsize;
DWORD	sv503_threadpriority;
DWORD	sv503_maxmpxct;
DWORD	sv503_oplockbreakwait;
DWORD	sv503_oplockbreakresponsewait;
BOOL	sv503_enableoplocks;
BOOL	sv503_enableoplockforceclose;
BOOL	sv503_enablefcbopens;
BOOL	sv503_enableraw;
BOOL	sv503_enabledpc;
BOOL	sv503_enablemdlio;
BOOL	sv503_enablefastio;
} SERVER_INFO_503, *PSERVER_INFO_503, *LPSERVER_INFO_503;

The following information levels are only valid for NetServerSetInfo and replace the older way of passing in a Parmnum to set a specific field.

The following are supported on downlevel systems (for example, LAN Manager 2.x) as well:

typedef struct _SERVER_INFO_1005 {
DWORD	sv1005_comment;
} SERVER_INFO_1005, *PSERVER_INFO_1005, *LPSERVER_INFO_1005;

typedef struct _SERVER_INFO_1107 {
DWORD	sv1107_users;
} SERVER_INFO_1107, *PSERVER_INFO_1107, *LPSERVER_INFO_1107;

typedef struct _SERVER_INFO_1010 {
DWORD	sv1010_disc;
} SERVER_INFO_1010, *PSERVER_INFO_1010, *LPSERVER_INFO_1010;

typedef struct _SERVER_INFO_1016 {
BOOL	sv1016_hidden;
} SERVER_INFO_1016, *PSERVER_INFO_1016, *LPSERVER_INFO_1016;

typedef struct _SERVER_INFO_1017 {
DWORD	sv1017_announce;
} SERVER_INFO_1017, *PSERVER_INFO_1017, *LPSERVER_INFO_1017;

typedef struct _SERVER_INFO_1018 {
DWORD	sv1018_anndelta;
} SERVER_INFO_1018, *PSERVER_INFO_1018, *LPSERVER_INFO_1018;

typedef struct _SERVER_INFO_1037 {
DWORD	sv1037_alertsched;
} SERVER_INFO_1037, *PSERVER_INFO_1037, *LPSERVER_INFO_1037;

typedef struct _SERVER_INFO_1038 {
DWORD	sv1038_erroralert;
} SERVER_INFO_1038, *PSERVER_INFO_1038, *LPSERVER_INFO_1038;

typedef struct _SERVER_INFO_1039 {
DWORD	sv1039_logonalert;
} SERVER_INFO_1039, *PSERVER_INFO_1039, *LPSERVER_INFO_1039;

typedef struct _SERVER_INFO_1040 {
DWORD	sv1040_accessalert;
} SERVER_INFO_1040, *PSERVER_INFO_1040, *LPSERVER_INFO_1040;

typedef struct _SERVER_INFO_1041 {
DWORD	sv1041_diskalert;
} SERVER_INFO_1041, *PSERVER_INFO_1041, *LPSERVER_INFO_1041;

typedef struct _SERVER_INFO_1042 {
DWORD	sv1042_netioalert;
} SERVER_INFO_1042, *PSERVER_INFO_1042, *LPSERVER_INFO_1042;

typedef struct _SERVER_INFO_1043 {
DWORD	sv1043_maxauditsz;
} SERVER_INFO_1043, *PSERVER_INFO_1043, *LPSERVER_INFO_1043;

The following do not do anything on downlevel systems (for example, LAN Manager 2.x) since they cannot be modified on the fly on those systems:

typedef struct _SERVER_INFO_1009 {
DWORD	sv1009_users;
} SERVER_INFO_1009, *PSERVER_INFO_1009, *LPSERVER_INFO_1009;

typedef struct _SERVER_INFO_1021 {
LPWSTR	sv1021_userpath;
} SERVER_INFO_1021, *PSERVER_INFO_1021, *LPSERVER_INFO_1021;

typedef struct _SERVER_INFO_1022 {
DWORD	sv1022_chdevs;
} SERVER_INFO_1022, *PSERVER_INFO_1022, *LPSERVER_INFO_1022;

typedef struct _SERVER_INFO_1028 {
DWORD	sv1028_sessopens;
} SERVER_INFO_1028, *PSERVER_INFO_1028, *LPSERVER_INFO_1028;

typedef struct _SERVER_INFO_1029 {
DWORD	sv1029_opensearch;
} SERVER_INFO_1029, *PSERVER_INFO_1029, *LPSERVER_INFO_1029;

The following are not supported on downlevel systems (for example, LAN Manager 2.x) since these are Windows NT − only fields:

typedef struct _SERVER_INFO_1001 {
DWORD	sv1001_maxworkitems;
} SERVER_INFO_1001, *PSERVER_INFO_1001, *LPSERVER_INFO_1001;

typedef struct _SERVER_INFO_1002 {
DWORD	sv1002_maxrawbuflen;
} SERVER_INFO_1002, *PSERVER_INFO_1002, *LPSERVER_INFO_1002;

typedef struct _SERVER_INFO_1003 {
DWORD	sv1003_sessusers;
} SERVER_INFO_1003, *PSERVER_INFO_1003, *LPSERVER_INFO_1003;

typedef struct _SERVER_INFO_1004 {
DWORD	sv1004_sesscons;
} SERVER_INFO_1004, *PSERVER_INFO_1004, *LPSERVER_INFO_1004;

typedef struct _SERVER_INFO_1006 {
DWORD	sv1006_enablesoftcompat;
} SERVER_INFO_1006, *PSERVER_INFO_1006, *LPSERVER_INFO_1006;

For NetServerSetInfo, parmnum values refer to the fields in the _SERVER_INFO structures as follows. These values are used when indicating an error in a specific parameter via parm_err.

parmnum value	Field in server_info struct
SV_NAME_PARMNUM	sv_name
SV_VERSION_MAJOR_PARMNUM	sv_version_major
SV_VERSION_MINOR_PARMNUM	sv_version_minor
SV_TYPE_PARMNUM	sv_type
SV_COMMENT_PARMNUM	sv_comment
SV_USERS_PARMNUM	sv_users
SV_DISC_PARMNUM	sv_disc
SV_HIDDEN_PARMNUM	sv_hidden
SV_ANNOUNCE_PARMNUM	sv_announce
SV_ANNDELTA_PARMNUM	sv_anndelta
SV_USERPATH_PARMNUM	sv_userpath
SV_ULIST_MTIME_PARMNUM	sv_ulist_mtime
SV_GLIST_MTIME_PARMNUM	sv_glist_mtime
SV_ALIST_MTIME_PARMNUM	sv_alist_mtime
SV_ALERTS_PARMNUM	sv_alerts
SV_SECURITY_PARMNUM	sv_security
SV_NUMADMIN_PARMNUM	sv_numadmin
SV_LANMASK_PARMNUM	sv_lanmask
SV_GUESTACC_PARMNUM	sv_guestacc
SV_CHDEVS_PARMNUM	sv_chdevs
SV_CHDEVQ_PARMNUM	sv_chdevq
SV_CHDEVJOBS_PARMNUM	sv_chdevjobs
SV_CONNECTIONS_PARMNUM	sv_connections
SV_SHARES_PARMNUM	sv_shares
SV_OPENFILES_PARMNUM	sv_openfiles
SV_SESSOPENS_PARMNUM	sv_sessopens
SV_SESSVCS_PARMNUM	sv_sessvcs
SV_SESSREQS_PARMNUM	sv_sessreqs
SV_OPENSEARCH_PARMNUM	sv_opensearch
SV_ACTIVELOCKS_PARMNUM	sv_activelocks
SV_NUMREQBUF_PARMNUM	sv_numreqbuf
SV_SIZREQBUF_PARMNUM	sv_sizreqbuf
SV_NUMBIGBUF_PARMNUM	sv_numbigbuf
SV_NUMFILETASKS_PARMNUM	sv_numfiletasks
SV_ALERTSCHED_PARMNUM	sv_alertsched
SV_ERRORALERT_PARMNUM	sv_erroralert
SV_LOGONALERT_PARMNUM	sv_logonalert
SV_ACCESSALERT_PARMNUM	sv_accessalert
SV_DISKALERT_PARMNUM	sv_diskalert
SV_NETIOALERT_PARMNUM	sv_netioalert
SV_MAXAUDITSZ_PARMNUM	sv_maxauditsz
SV_SRVHEURISTICS_PARMNUM	sv_srvheuristics
SV_AUDITEDEVENTS_PARMNUM	sv_auditedevents
SV_AUTOPROFILE_PARMNUM	sv_autoprofile
SV_MAXWORKITEMS_PARMNUM	sv_maxworkitems
SV_RAWWORKITEMS_PARMNUM	sv_rawworkitems
SV_IRPSTACKSIZE_PARMNUM	sv_irpstacksize
SV_SESSUSERS_PARMNUM	sv_sessusers
SV_SESSCONNS_PARMNUM	sv_sessconns
SV_MAXNONPAGEDMEMORYUSAGE_PARMNUM	sv_maxnonpagedmemoryusage
SV_MAXPAGEDMEMORYUSAGE_PARMNUM	sv_maxpagedmmeoryusage
SV_ENABLEOFTCOMPAT_PARMNUM	sv_enablesoftcompat
The server functions are:

NetServerGetInfo

NetServerSetInfo.


 Workstation and Workstation User Functions

Workstation functions perform administrative tasks on a local or remote workstation. Any user or application with admin group membership on a local or remote server can perform administrative tasks on that workstation to control its operation, user access, and resource sharing. The low-level parameters that affect a workstation's operation can be examined and modified by calling NetWkstaGetInfo and NetWkstaSetInfo.

The workstation API data structures are restructured from those of LAN Man 2.x to allow the information to be grouped by type and security accesses. The LAN Manager 2.x workstation information format is discontinued due to the following problems:

•	The base level (0 and 1) were not grouped by accessibility such that a non superset level (level 10) was required to allow guest access to the information.

•	Platform specific implementation information was included in the base levels such that every platform had to return all information including a default for non-relevant fields. This grew the size of the information structures unneccessarily, making the function cumbersome to use.

The workstation functions allow access to two discrete groups of workstation information:

•	System information.

•	Platform specific information (Windows NT, OS/2, MS-DOS, and so on)

The Workstation User functions allow access to user-specific information. The user-specific information is separated from the workstation information because there can be more than one user on a workstation.

Within each group the fields are categorized by security access such that the guest accessible fields are a subset of the user accessible fields that are a subset of the admin accessible fields.

The system information structure contains a platform base number that identifies the levels and format of the platform specific information structures.

The workstation function information structures are:

System Information −

Level 100 available with guest access −

typedef struct _WKSTA_INFO_100 {
DWORD	wki100_platform_id;
LPWSTR	wki100_computername;
LPWSTR	wki100_langroup;
DWORD	wki100_ver_major;
DWORD	wki100_ver_minor;
} WKSTA_INFO_100, *PWKSTA_INFO_100, *LPWKSTA_INFO_100;

Level 101 available with User access:

typedef struct _WKSTA_INFO_101 {
DWORD	wki101_platform_id;
LPWSTR	wki101_computername;
LPWSTR	wki101_langroup;
DWORD	wki101_ver_major;
DWORD	wki101_ver_minor;
LPWSTR	wki101_lanroot;
} WKSTA_INFO_101, *PWKSTA_INFO_101, *LPWKSTA_INFO_101;

Level 102 available with Admin access:

typedef struct _WKSTA_INFO_102 {
DWORD	wki102_platform_id;
LPWSTR	wki102_computername;
LPWSTR	wki102_langroup;
DWORD	wki102_ver_major;
DWORD	wki102_ver_minor;
LPWSTR	wki102_lanroot;
DWORD	wki102_logged_on_users;
} WKSTA_INFO_102, *PWKSTA_INFO_102, *LPWKSTA_INFO_102;

Platform Specific Information

Level 300-399 MS-DOS Workstation information.

Level 300 available with guest access:

Level 302 available with Admin access:

typedef struct _WKSTA_INFO_302 {
DWORD	wki302_char_wait;
DWORD	wki302_collection_time;
DWORD	wki302_maximum_collection_count;
DWORD	wki302_keep_conn;
DWORD	wki302_keep_search;
DWORD	wki302_max_cmds;
DWORD	wki302_num_work_buf;
DWORD	wki302_siz_work_buf;
DWORD	wki302_max_wrk_cache;
DWORD	wki302_sess_timeout;
DWORD	wki302_siz_error;
DWORD	wki302_num_alerts;
DWORD	wki302_num_services;
DWORD	wki302_errlog_sz;
DWORD	wki302_print_buf_time;
DWORD	wki302_num_char_buf;
DWORD	wki302_siz_char_buf;
LPWSTR	wki302_wrk_heuristics;
DWORD	wki302_mailslots;
DWORD	wki302_num_dgram_buf;
} WKSTA_INFO_302, *PWKSTA_INFO_302, *LPWKSTA_INFO_302;

Level 400-499 OS/2 Workstation information.

Level 402 available with Admin access:

typedef struct _WKSTA_INFO_402 {
DWORD	wki402_char_wait;
DWORD	wki402_collection_time;
DWORD	wki402_maximum_collection_count;
DWORD	wki402_keep_conn;
DWORD	wki402_keep_search;
DWORD	wki402_max_cmds;
DWORD	wki402_num_work_buf;
DWORD	wki402_siz_work_buf;
DWORD	wki402_max_wrk_cache;
DWORD	wki402_sess_timeout;
DWORD	wki402_siz_error;
DWORD	wki402_num_alerts;
DWORD	wki402_num_services;
DWORD	wki402_errlog_sz;
DWORD	wki402_print_buf_time;
DWORD	wki402_num_char_buf;
DWORD	wki402_siz_char_buf;
LPWSTR	wki402_wrk_heuristics;
DWORD	wki402_mailslots;
DWORD	wki402_num_dgram_buf;
DWORD	wki402_max_threads;
} WKSTA_INFO_402, *PWKSTA_INFO_402, *LPWKSTA_INFO_402;

Level 500-599 Windows NT Workstation information.

Level 502 available with Admin access:

typedef struct _WKSTA_INFO_502 {
DWORD	wki502_char_wait;
DWORD	wki502_collection_time;
DWORD	wki502_maximum_collection_count;
DWORD	wki502_keep_conn;
DWORD	wki502_max_cmds;
DWORD	wki502_sess_timeout;
DWORD	wki502_siz_char_buf;
DWORD	wki502_max_threads;
DWORD	wki502_lock_quota;
DWORD	wki502_lock_increment;
DWORD	wki502_lock_maximum;
DWORD	wki502_pipe_increment;
DWORD	wki502_pipe_maximum;
DWORD	wki502_cache_file_timeout;
DWORD	wki502_dormant_file_limit;
DWORD	wki502_read_ahead_throughput;
DWORD	wki502_num_mailslot_buffers;
DWORD	wki502_num_srv_announce_buffers;
DWORD	wki502_dgreceiver_threads;
BOOL	wki502_use_opportunistic_locking;
BOOL	wki502_use_unlock_behind;
BOOL	wki502_use_close_behind;
BOOL	wki502_buf_named_pipes;
BOOL	wki502_use_lock_read_unlock;
BOOL	wki502_utilize_nt_caching;
BOOL	wki502_use_raw_read;
BOOL	wki502_use_raw_write;
BOOL	wki502_use_write_raw_data;
BOOL	wki502_use_encryption;
BOOL	wki502_buf_files_deny_write;
BOOL	wki502_buf_read_only_files;
BOOL	wki502_force_core_create_mode;
BOOL	wki502_use_512_byte_max_transfer;
} WKSTA_INFO_502, *PWKSTA_INFO_502, *LPWKSTA_INFO_502;

This format of workstation information allows for a more logical future extension. When new information is to be added to any set of guest,user and admin information a new set of levels is created to include the current infromation plus the new information.

The following information levels are only valid for NetWkstaSetInfo and replace the older way of passing in a Parmnum to set a specific field.

The following are supported on downlevel systems (for example, LAN Manager 2.x) as well:

typedef struct _WKSTA_INFO_1010 {
DWORD	wki1010_char_wait;
} WKSTA_INFO_1010, *PWKSTA_INFO_1010, *LPWKSTA_INFO_1010;

typedef struct _WKSTA_INFO_1011 {
DWORD	wki1011_collection_time;
} WKSTA_INFO_1011, *PWKSTA_INFO_1011, *LPWKSTA_INFO_1011;

typedef struct _WKSTA_INFO_1012 {
DWORD	wki1012_maximum_collection_count;
} WKSTA_INFO_1012, *PWKSTA_INFO_1012, *LPWKSTA_INFO_1012;

typedef struct _WKSTA_INFO_1027 {
DWORD	wki1027_errlog_sz;
} WKSTA_INFO_1027, *PWKSTA_INFO_1027, *LPWKSTA_INFO_1027;

typedef struct _WKSTA_INFO_1028 {
DWORD	wki1028_print_buf_time;
} WKSTA_INFO_1028, *PWKSTA_INFO_1028, *LPWKSTA_INFO_1028;

typedef struct _WKSTA_INFO_1032 {
DWORD	wki1032_wrk_heuristics;
} WKSTA_INFO_1032, *PWKSTA_INFO_1032, *LPWKSTA_INFO_1032;

typedef struct _WKSTA_INFO_1035 {
LPWSTR	wki1035_oth_domains;
} WKSTA_INFO_1035, *PWKSTA_INFO_1035, *LPWKSTA_INFO_1035;

The following do nothing on downlevel systems (for example, LAN Manager 2.x) since these fields cannot be set on them:

typedef struct _WKSTA_INFO_1013 {
DWORD	wki1013_keep_conn;
} WKSTA_INFO_1013, *PWKSTA_INFO_1013, *LPWKSTA_INFO_1013;

typedef struct _WKSTA_INFO_1018 {
DWORD	wki1018_sess_timeout;
} WKSTA_INFO_1018, *PWKSTA_INFO_1018, *LPWKSTA_INFO_1018;

typedef struct _WKSTA_INFO_1023 {
DWORD	wki1023_siz_char_buf;
} WKSTA_INFO_1023, *PWKSTA_INFO_1023, *LPWKSTA_INFO_1023;

typedef struct _WKSTA_INFO_1033 {
DWORD	wki1033_max_threads;
} WKSTA_INFO_1033, *PWKSTA_INFO_1033, *LPWKSTA_INFO_1033;

The following are not supported on downlevel systems (for example, LAN Manager 2.x):

typedef struct _WKSTA_INFO_1041 {
DWORD	wki1041_lock_quota;
} WKSTA_INFO_1041, *PWKSTA_INFO_1041, *LPWKSTA_INFO_1041;

typedef struct _WKSTA_INFO_1042 {
DWORD	wki1042_lock_increment;
} WKSTA_INFO_1042, *PWKSTA_INFO_1042, *LPWKSTA_INFO_1042;

typedef struct _WKSTA_INFO_1043 {
DWORD	wki1043_lock_maximum;
} WKSTA_INFO_1043, *PWKSTA_INFO_1043, *LPWKSTA_INFO_1043;

typedef struct _WKSTA_INFO_1044 {
DWORD	wki1044_pipe_increment;
} WKSTA_INFO_1044, *PWKSTA_INFO_1044, *LPWKSTA_INFO_1044;

typedef struct _WKSTA_INFO_1045 {
DWORD	wki1045_pipe_maximum;
} WKSTA_INFO_1045, *PWKSTA_INFO_1045, *LPWKSTA_INFO_1045;

typedef struct _WKSTA_INFO_1046 {
DWORD	wki1046_dormant_file_limit;
} WKSTA_INFO_1046, *PWKSTA_INFO_1046, *LPWKSTA_INFO_1046;

typedef struct _WKSTA_INFO_1047 {
DWORD	wki1047_cache_file_timeout;
} WKSTA_INFO_1047, *PWKSTA_INFO_1047, *LPWKSTA_INFO_1047;

typedef struct _WKSTA_INFO_1048 {
BOOL	wki1048_use_opportunity_locking;
} WKSTA_INFO_1048, *PWKSTA_INFO_1048, *LPWKSTA_INFO_1048;

typedef struct _WKSTA_INFO_1049 {
BOOL	wki1049_use_unlock_behind;
} WKSTA_INFO_1049, *PWKSTA_INFO_1049, *LPWKSTA_INFO_1049;

typedef struct _WKSTA_INFO_1050 {
BOOL	wki1050_use_close_behind;
} WKSTA_INFO_1050, *PWKSTA_INFO_1050, *LPWKSTA_INFO_1050;

typedef struct _WKSTA_INFO_1051 {
BOOL	wki1051_buf_named_pipes;
} WKSTA_INFO_1051, *PWKSTA_INFO_1051, *LPWKSTA_INFO_1051;

typedef struct _WKSTA_INFO_1052 {
BOOL	wki1052_use_lock_read_unlock;
} WKSTA_INFO_1052, *PWKSTA_INFO_1052, *LPWKSTA_INFO_1052;

typedef struct _WKSTA_INFO_1053 {
BOOL	wki1053_utilize_nt_caching;
} WKSTA_INFO_1053, *PWKSTA_INFO_1053, *LPWKSTA_INFO_1053;

typedef struct _WKSTA_INFO_1054 {
BOOL	wki1054_use_raw_read;
} WKSTA_INFO_1054, *PWKSTA_INFO_1054, *LPWKSTA_INFO_1054;

typedef struct _WKSTA_INFO_1055 {
BOOL	wki1055_use_raw_write;
} WKSTA_INFO_1055, *PWKSTA_INFO_1055, *LPWKSTA_INFO_1055;

typedef struct _WKSTA_INFO_1056 {
BOOL	wki1056_use_write_raw_data;
} WKSTA_INFO_1056, *PWKSTA_INFO_1056, *LPWKSTA_INFO_1056;

typedef struct _WKSTA_INFO_1057 {
BOOL	wki1057_use_encryption;
} WKSTA_INFO_1057, *PWKSTA_INFO_1057, *LPWKSTA_INFO_1057;

typedef struct _WKSTA_INFO_1058 {
BOOL	wki1058_buf_files_deny_write;
} WKSTA_INFO_1058, *PWKSTA_INFO_1058, *LPWKSTA_INFO_1058;

typedef struct _WKSTA_INFO_1059 {
BOOL	wki1059_buf_read_only_files;
} WKSTA_INFO_1059, *PWKSTA_INFO_1059, *LPWKSTA_INFO_1059;

typedef struct _WKSTA_INFO_1060 {
BOOL	wki1060_force_core_create_mode;
} WKSTA_INFO_1060, *PWKSTA_INFO_1060, *LPWKSTA_INFO_1060;

typedef struct _WKSTA_INFO_1061 {
BOOL	wki1061_use_512_byte_max_transfer;
} WKSTA_INFO_1061, *PWKSTA_INFO_1061, *LPWKSTA_INFO_1061;

typedef struct _WKSTA_INFO_1062 {
DWORD	wki1062_read_ahead_throughput;
} WKSTA_INFO_1062, *PWKSTA_INFO_1062, *LPWKSTA_INFO_1062;

The Workstation User function information structures are:

Level 0 and 1 available with User access:

typedef struct _WKSTA_USER_INFO_0 {
LPWSTR	wkui0_username;
} WKSTA_USER_INFO_0, *PWKSTA_USER_INFO_0, *LPWKSTA_USER_INFO_0;

typedef struct _WKSTA_USER_INFO_1 {
LPWSTR	wkui1_username;
LPWSTR	wkui1_logon_domain;
LPWSTR	wkui1_logon_server;

LPWSTR	wkui1_oth_domains;
} WKSTA_USER_INFO_1, *PWKSTA_USER_INFO_1, *LPWKSTA_USER_INFO_1;

typedef struct _WKSTA_USER_INFO_1101 {
LPTSTR	wkui1101_oth_domains;
} WKSTA_USER_INFO_1101, *PWKSTA_USER_INFO_1101,
 *LPWKSTA_USER_INFO_1101;

For NetWkstaSetInfo, parmnum values refer to the fields in the workstation info structure as follows. These values are used when indicating an error in a specific parameter via parm_err.

parmnum value	Field in wksta_info struct
WKSTA_PLATFORM_ID_PARMNUM	wki_platform_id
WKSTA_COMPUTERNAME_PARMNUM	wki_computername
WKSTA_LANGROUP_PARMNUM	wki_langroup
WKSTA_OTH_DOMAINS_PARMNUM	wki_oth_domains
WKSTA_VER_MAJOR_PARMNUM	wki_ver_major
WKSTA_VER_MINOR_PARMNUM	wki_ver_minor
WKSTA_LOGGED_ON_USERS_PARMNUM	wki_logged_on_users
WKSTA_LANROOT_PARMNUM	wki_lanroot
WKSTA_LOGON_DOMAIN_PARMNUM	wki_logon_domain
WKSTA_LOGON_SERVER_PARMNUM	wki_logon_server
WKSTA_CHARWAIT_PARMNUM	wki_char_wait
WKSTA_CHARTIME_PARMNUM	wki_collection_time
WKSTA_CHARCOUNT_PARMNUM	wki_maximum_collection_count
WKSTA_KEEPCONN_PARMNUM	wki_keep_conn
WKSTA_KEEPSEARCH_PARMNUM	wki_keep_search
WKSTA_MAXCMDS_PARMNUM	wki_max_cmds
WKSTA_NUMWORKBUF_PARMNUM	wki_num_work_buf
WKSTA_MAXWRKCACHE_PARMNUM	wki_max_wrk_cache
WKSTA_SESSTIMEOUT_PARMNUM	wki_sess_timeout
WKSTA_SIZERROR_PARMNUM	wki_siz_error
WKSTA_NUMALERTS_PRAMNUM	wki_num_alerts
WKSTA_NUMSERVICES_PARMNUM	wki_num_services
WKSTA_ERRLOGSZ_PARMNUM	wki_errlog_sz
WKSTA_PRINTBUFTIME_PARMNUM	wki_print_buf_time
WKSTA_NUMCHARBUF_PARMNUM	wki_num_char_buf
WKSTA_SIZCHARBUF_PARMNUM	wki_siz_char_buf
WKSTA_WRKHEURISTICS_PARMNUM	wki_wrk_heuristics
WKSTA_MAILSLOTS_PRAMNUM	wki_mailslots
WKSTA_MAXTHREADS_PARMNUM	wki_max_threads
WKSTA_SIZWORKBUF_PARMNUM	wki_siz_work_buf
WKSTA_DORMANTTIMEOUT_PARMNUM	wki_dormant_timeout
WKSTA_LOCKQUOTA_PARMNUM	wki_lock_quota
WKSTA_LOCKINCREMENT_PARMNUM	wki_lock_increment
WKSTA_LOCKMAXIMUM_PARMNUM	wki_lock_maximum
WKSTA_PIPEINCREMENT_PRAMNUM	wki_pipe_increment
WKSTA_PIPEMAXIMUM_PARMNUM	wki_pipe_maximum
WKSTA_RAWREADTHRESHOLD_PARMNUM	wki_raw_read_threshold
WKSTA_USEOPLOCKING_PARMNUM	wki_use_opportunistic_locking
WKSTA_USEOPBATCH_PARMNUM	wki_use_op_batch
WKSTA_USEUNLOCKBEHIND_PARMNUM	wki_use_unlock_behind
WKSTA_USECLOSEBEHIND_PARMNUM	wki_use_close_behind
WKSTA_BUFNAMEDPIPES_PARMNUM	wksta_buf_named_pipes
WKSTA_USELOCKANDREADANDUNLOCK _PARMNUM	wki_use_lock_and_read_and _unlock
WKSTA_UTILIZENTCACHING_PARMNUM	wki_utilize_nt_caching
WKSTA_USERAWREAD_PARMNUM	wki_use_raw_read
WKSTA_USEWRITERAWWITHDATA_PARMNUM	wki_use_write_raw_with_data
WKSTA_USEENCRYPTION_PARMNUM	wki_use_encryption
WKSTA_BUFFILESWITHDENYWRITE _PARMNUM	wki_buf_files_with_deny_write
WKSTA_BUFREADONLYFILES_PRAMNUM	wki_buf_read_only_files
WKSTA_FORCECORECREATEMODE_PARMNUM	wki_force_core_create_mode
WKSTA_USE512BYTESMAXTRANSFER _PARMNUM	wki_use_512_bytes_max_transfer
The workstation functions are:

NetWkstaGetInfo

NetWkstaSetInfo

The Workstation User functions are:

NetWkstaUserEnum

NetWkstaUserGetInfo

NetWkstaUserSetInfo


 Use Functions

Note  The WNetAddConnection2 and WNetCancelConnection2 functions should be used instead of the NetUse functions.

Use functions examine or control connections (uses) between workstations and servers. Connections are distinguished from sessions: a session is established the first time a workstation makes a connection to a shared resource on the server; all further connections between the workstation and the server are part of this same session until the session ends. Two types of connections can be made: device-name connections (which can only be explicit) and universal-naming convention (UNC) connections (which can be explicit or implicit).

Connections are made on a per-user basis. A connection made by a user is deleted when that user logs off. For this reason the NetUse functions are local only, since a connection set up by a remote user would not be accessible to any other users, even the user that was interactively logged onto that computer.

NetUseAdd creates a device-name connection or an explicit UNC connection. Implicit UNC connections are made by the function responsible for the connection.

NetUseAdd establishes an explicit connection between the local computer and a resource shared on a server by redirecting a local device name to the share name of a remote server resource (\\servername\sharename). Once a device-name connection is made, users or applications can use the remote resource by specifying the local device name. To establish an implicit UNC connection, an application passes the share name of a resource to any function that accepts UNC paths. The function accepts the UNC name and makes a connection to the specified share name. All further requests on this connection require the full share name.

NetUseDel ends a connection to a shared resource. NetUseEnum enumerates all current connections between the local computer and resources on remote servers. NetUseGetInfo returns information about a connection to a shared resource.

The use functions are available at three information levels.

typedef struct _USE_INFO_0 {
LPWSTR	ui0_local;
LPWSTR	ui0_remote;
} USE_INFO_0, *PUSE_INFO_0, *LPUSE_INFO_0;

typedef struct _USE_INFO_1 {
LPWSTR	ui1_local;
LPWSTR	ui1_remote;
LPWSTR	ui1_password;
DWORD	ui1_status;
DWORD	ui1_asg_type;
DWORD	ui1_refcount;
DWORD	ui1_usecount;
} USE_INFO_1, *PUSE_INFO_1, *LPUSE_INFO_1;

Information level 2 is not available if the function is remoted to a downlevel system — ERROR_NOT_SUPPORTED will be returned in that case.

typedef struct _USE_INFO_2 {
LPWSTR	ui2_local;
LPWSTR	ui2_remote;
LPWSTR	ui2_password;
DWORD	ui2_status;
DWORD	ui2_asg_type;
DWORD	ui2_refcount;
DWORD	ui2_usecount;
LPWSTR	ui2_username;

LPWSTR	ui2_domainname;
} USE_INFO_2, *PUSE_INFO_2, *LPUSE_INFO_2;

The use functions are:

NetUseAdd

NetUseDel

NetUseEnum

NetUseGetInfo


 Share Functions

Share functions control shared resources. A shared resource is a local resource on a server (for example, a disk directory, print device, or named pipe) that can be accessed by users and applications on the network.

NetShareAdd allows a user or application to share a resource of a specific type using the specified share name. NetShareAdd requires the share name and local device name to share the resource. A user or application must have an account on the server to access the resource.

You may also specify a Security Descriptor to be associated with a share, which specifies which users will be allowed to access files through this share, and with what type of access.

LAN Manager defines three types of special share names for interprocess communication (IPC) and remote administration of the server:

•	IPC$, reserved for interprocess communication.

•	ADMIN$, reserved for remote administration.

•	A$, B$, C$ (and other local disk names followed by a dollar sign), assigned to local disk devices.

Share functions are available at four information levels.

typedef struct _SHARE_INFO_0 {
LPWSTR	shi0_netname;
} SHARE_INFO_0, *PSHARE_INFO_0, *LPSHARE_INFO_0;

typedef struct _SHARE_INFO_1 {
LPWSTR	shi1_netname;
DWORD	shi1_type;
LPWSTR	shi1_remark;
} SHARE_INFO_1, *PSHARE_INFO_1, *LPSHARE_INFO_1;

typedef struct _SHARE_INFO_2 {
LPWSTR	shi2_netname;
DWORD	shi2_type;
LPWSTR	shi2_remark;
DWORD	shi2_permissions;
DWORD	shi2_max_uses;
DWORD	shi2_current_uses;
LPWSTR	shi2_path;
LPWSTR	shi2_passwd;
} SHARE_INFO_2, *PSHARE_INFO_2, *LPSHARE_INFO_2;

typedef struct _SHARE_INFO_502 {
LPTSTR	shi502_netname;
DWORD	shi502_type;
LPTSTR	shi502_remark;
DWORD	shi502_permissions;
DWORD	shi502_max_uses;
DWORD	shi502_current_uses;
LPTSTR	shi502_path;
LPTSTR	shi502_passwd;
DWORD	shi502_reserved;
PSECURITY_DESCRIPTOR	shi502_security_descriptor;
} SHARE_INFO_502, *PSHARE_INFO_502, *LPSHARE_INFO_502;

The following information levels are valid only for NetShareSetInfo and replace the older way of passing in a Parmnum to set a specific field.

The following are supported on downlevel systems (for example, LAN Manager 2.x) as well:

typedef struct _SHARE_INFO_1004 {
LPWSTR	shi1004_remark;
} SHARE_INFO_1004, *PSHARE_INFO_1004, *LPSHARE_INFO_1004;

typedef struct _SHARE_INFO_1006 {
DWORD	shi1006_max_uses;
} SHARE_INFO_1006, *PSHARE_INFO_1006, *LPSHARE_INFO_1006;

The following is only supported on Windows NT.

typedef struct _SHARE_INFO_1501 {
DWORD	shi1501_reserved;
PSECURITY_DESCRIPTOR	shi1501_security_descriptor;
} SHARE_INFO_1501, *PSHARE_INFO_1501, *LPSHARE_INFO_1501;

For NetShareSetInfo, parmnum values refer to the fields in the share_info structure as follows. These values are used when indicating an error in a specific parameter via parm_err.

parmnum value	Field in share_info struct
SHARE_NETNAME_PARMNUM	shi_netname
SHARE_TYPE_PARMNUM	shi_type
SHARE_REMARK_PARMNUM	shi_remark
SHARE_PERMISSIONS_PARMNUM	shi_permissions
SHARE_MAX_USES_PARMNUM	shi_max_uses
SHARE_CURRENT_USES_PARMNUM	shi_current_uses
SHARE_PATH_PARMNUM	shi_path
SHARE_PASSWD_PARMNUM	shi_passwd
SHARE_FILE_SD_PARMNUM	shi_security_descriptor
The share functions are:

NetShareAdd

NetShareCheck

NetShareDel

NetShareEnum

NetShareGetInfo

NetShareSetInfo


 Session Functions

Session functions control network sessions established between workstations and servers. They require that the Server service be started on the specified server. A session is a link between a workstation and a server. It is established the first time a workstation makes a connection with a shared resource on the server. Until the session ends, all further connections between the workstation and the server are part of this same session. To end a session, an application on the server end of a connection calls NetSessionDel. This deletes all current connections between the workstation and the server. NetSessionEnum returns information about all sessions established for a server. NetSessionGetInfo returns information about a particular session.

Per-user information is managed by the NetSession functions through the use of the username parameter. Since there can be multiple users per session, this parameter is necessary in order to access the user-specific information for the session.

Session functions are available at four information levels.

typedef struct _SESSION_INFO_0 {
LPWSTR	sesi0_cname;
} SESSION_INFO_0, *PSESSION_INFO_0, *LPSESSION_INFO_0;

typedef struct _SESSION_INFO_1 {
LPWSTR	sesi1_cname;
LPWSTR	sesi1_username;
DWORD	sesi1_num_opens;
DWORD	sesi1_time;
DWORD	sesi1_idle_time;
DWORD	sesi1__flags;
} SESSION_INFO_1, *PSESSION_INFO_1, *LPSESSION_INFO_1;

typedef struct _SESSION_INFO_2 {
LPWSTR	sesi2_cname;
LPWSTR	sesi2_username;
DWORD	sesi2_num_opens;
DWORD	sesi2_time;
DWORD	sesi2_idle_time;
DWORD	sesi2_flags;
LPWSTR	sesi2_cltype_name;
} SESSION_INFO_2, *PSESSION_INFO_2, *LPSESSION_INFO_2;

typedef struct _SESSION_INFO_10 {
LPWSTR	sesi10_cname;
LPWSTR	sesi10_username;
DWORD	sesi10_time;
DWORD	sesi10_idle_time;
} SESSION_INFO_10, *PSESSION_INFO_10, *LPSESSION_INFO_10;

sesi_username cannot be NULL. sesi1_flags and sesi2_flags can take the following bits:

SESS_GUEST	0x00000001
SESS_NONENCRYPTION	0x00000002

The session functions are:

NetSessionDel

NetSessionEnum

NetSessionGetInfo


 File Functions

File functions provide a way to monitor and close the file, device, and pipe resources open on a server. NetFileClose forces a server resource closed. This function can be used when a system error prevents normal closure. NetFileEnum returns information about resources open on a server. A file can be opened one or more times by one or more applications. Each file opening is uniquely identified. NetFileEnum returns an entry for each file opening. NetFileGetInfo returns information about one particular opening of a resource.

File functions are available at information levels 2 and 3 only. Levels 0 and 1 are not supported.

typedef struct _FILE_INFO_2 {
DWORD	fi2_id;
} FILE_INFO_2, *PFILE_INFO_2, *LPFILE_INFO_2;

typedef struct _FILE_INFO_3 {
DWORD	fi3_id;
DWORD	fi3_permissions;
DWORD	fi3_num_locks;
LPWSTR	fi3_pathname;
LPWSTR	fi3_username;
} FILE_INFO_3, *PFILE_INFO_3, *LPFILE_INFO_3;

The file functions are:

NetFileClose

NetFileEnum

NetFileGetInfo


 Message Functions

Message functions send and receive messages and manipulate message aliases. A message is a buffer of text data sent to a user or application on the network. To receive a message, a user or application must register a message alias in a computer's table of message names. This can be done by using NetMessageNameAdd. A message name table contains a list of registered message aliases (users and applications) permitted to receive messages.

The aliases registered in the message name table are case insensitive. NetMessageNameDel deletes a specific message alias from the message name table. NetMessageNameEnum lists all the aliases stored in the message name table. NetMessageNameGetInfo retrieves information about a particular message alias in the message name table.

To send a message, an application calls NetMessageBufferSend. Applications can also send broadcast messages to all users in a domain or to all computers on a network using NetMessageBufferSend.

Message functions are available at two information levels.

MSG_INFO_1 exists only for compatability. The Windows NT messenger will not forward names or allow names to be forwarded to it.

typedef struct _MSG_INFO_0 {
LPWSTR	msgi0_name;
} MSG_INFO_0, *PMSG_INFO_0, *LPMSG_INFO_0;

typedef struct _MSG_INFO_1 {
LPWSTR	msgi1_name;
DWORD	msgi1_forward_flag;
LPWSTR	msgi1_forward;
} MSG_INFO_1, *PMSG_INFO_1, *LPMSG_INFO_1;

The message functions are:

NetMessageBufferSend

NetMessageNameAdd

NetMessageNameDel

NetMessageNameEnum

NetMessageNameGetInfo


 Remote Utility Function

The remote utility function enables applications to access the time-of-day information on a remote server.

NetRemoteTOD returns time-of-day information from a remote server.


 Security Account Functions

User Functions

User functions control a user's account in the security database. Each user or application that accesses resources must have an account in the security database. The Windows NT Security system (SAM) uses this user account to verify that the user or application has permission to use a resource. When a user or an application requests access to a resource, the security system checks for an appropriate user account or group account to permit the access.

NetUserEnum can be used to list all user accounts in a domain. An application can verify the groups to which a user belongs by calling NetUserGetGroups, which returns a list of global group names. The NetUserGetLocalGroups function does the same for local groups. When a user account is no longer needed, use NetUserDel to delete the account from the server. Once the account is removed, the user can no longer access the server, except by using the guest account. Because the user's password is confidential, it is not returned by NetUserEnum or NetUserGetInfo. The password is initially assigned when NetUserAdd is called. NetUserSetInfo sets the password and other elements of a user account.

User account information is available at five levels:

typedef struct _USER_INFO_0 {
LPWSTR	usri0_name;
} USER_INFO_0, *PUSER_INFO_0, *LPUSER_INFO_0;

typedef struct _USER_INFO_1 {
LPWSTR	usri1_name;
LPWSTR	usri1_password;
DWORD	usri1_password_age;
DWORD	usri1_priv;
LPWSTR	usri1_home_dir;
LPWSTR	usri1_comment;
DWORD	usri1_flags;
LPWSTR	usri1_script_path;
} USER_INFO_1, *PUSER_INFO_1, *LPUSER_INFO_1;

typedef struct _USER_INFO_2 {
LPWSTR	usri2_name;
LPWSTR	usri2_password;
DWORD	usri2_password_age;
DWORD	usri2_priv;
LPWSTR	usri2_home_dir;
LPWSTR	usri2_comment;
DWORD	usri2_flags;
LPWSTR	usri2_script_path;
DWORD	usri2_auth_flags;
LPWSTR	usri2_full_name;
LPWSTR	usri2_usr_comment;
LPWSTR	usri2_parms;
LPWSTR	usri2_workstations;
DWORD	usri2_last_logon;
DWORD	usri2_last_logoff;
DWORD	usri2_acct_expires;
DWORD	usri2_max_storage;
DWORD	usri2_units_per_week;
LPBYTE	usri2_logon_hours;
DWORD	usri2_bad_pw_count;
DWORD	usri2_num_logons;
LPWSTR	usri2_logon_server;
DWORD	usri2_country_code;
DWORD	usri2_code_page;
} USER_INFO_2, *PUSER_INFO_2, *LPUSER_INFO_2;

typedef struct _USER_INFO_3 {
LPWSTR	usri3_name;
LPWSTR	usri3_password;
DWORD	usri3_password_age;
DWORD	usri3_priv;
LPWSTR	usri3_home_dir;
LPWSTR	usri3_comment;
DWORD	usri3_flags;
LPWSTR	usri3_script_path;
DWORD	usri3_auth_flags;
LPWSTR	usri3_full_name;
LPWSTR	usri3_usr_comment;
LPWSTR	usri3_parms;
LPWSTR	usri3_workstations;
DWORD	usri3_last_logon;
DWORD	usri3_last_logoff;
DWORD	usri3_acct_expires;
DWORD	usri3_max_storage;
DWORD	usri3_units_per_week;
PBYTE	usri3_logon_hours;
DWORD	usri3_bad_pw_count;
DWORD	usri3_num_logons;
LPWSTR	usri3_logon_server;
DWORD	usri3_country_code;
DWORD	usri3_code_page;
DWORD	usri3_user_id;
DWORD	usri3_primary_group_id;
LPWSTR	usri3_profile;
LPWSTR	usri3_home_dir_drive;
DWORD	usri3_password_expired;
}USER_INFO_3, *PUSER_INFO_3, *LPUSER_INFO_3;

typedef struct _USER_INFO_10 {
LPWSTR	usri10_name;
LPWSTR	usri10_comment;
LPWSTR	usri10_usr_comment;
LPWSTR	usri10_full_name;
} USER_INFO_10, *PUSER_INFO_10, *LPUSER_INFO_10;

typedef struct _USER_INFO_11 {
LPWSTR	usri11_name;
LPWSTR	usri11_comment;
LPWSTR	usri11_usr_comment;
LPWSTR	usri11_full_name;
DWORD	usri11_priv;
DWORD	usri11_auth_flags;
DWORD	usri11_password_age;
LPWSTR	usri11_home_dir;
LPWSTR	usri11_parms;
DWORD	usri11_last_logon;
DWORD	usri11_last_logoff;
DWORD	usri11_bad_pw_count;
DWORD	usri11_num_logons;
LPWSTR	usri11_logon_server;
DWORD	usri11_country_code;
LPWSTR	usri11_workstations;
DWORD	usri11_max_storage;
DWORD	usri11_units_per_week;
LPBYTE	usri11_logon_hours;
DWORD	usri11_code_page;
} USER_INFO_11, *PUSER_INFO_11, *LPUSER_INFO_11;

typedef struct _USER_INFO_20 {
LPWSTR	usri20_name;
LPWSTR	usri20_full_name;
LPWSTR	usri20_comment;
DWORD	usri20_flags;
DWORD	usri20_user_id;
}USER_INFO_20, *PUSER_INFO_20, *LPUSER_INFO_20;

The following information levels are valid only for NetUserSetInfo and replace the older way of passing in a Parmnum to set a specific field.

The following are supported on downlevel systems (for example, LAN Manager 2.x) as well:

typedef struct _USER_INFO_1003 {
LPWSTR	usri1003_password;
} USER_INFO_1003, *PUSER_INFO_1003, *LPUSER_INFO_1003;

typedef struct _USER_INFO_1005 {
DWORD	usri1005_priv;
} USER_INFO_1005, *PUSER_INFO_1005, *LPUSER_INFO_1005;

typedef struct _USER_INFO_1006 {
LPWSTR	usri1006_home_dir;
} USER_INFO_1006, *PUSER_INFO_1006, *LPUSER_INFO_1006;

typedef struct _USER_INFO_1007 {
LPWSTR	usri1007_comment;
} USER_INFO_1007, *PUSER_INFO_1007, *LPUSER_INFO_1007;

typedef struct _USER_INFO_1008 {
DWORD	usri1008_flags;
} USER_INFO_1008, *PUSER_INFO_1008, *LPUSER_INFO_1008;

typedef struct _USER_INFO_1009 {
LPWSTR	usri1009_script_path;
} USER_INFO_1009, *PUSER_INFO_1009, *LPUSER_INFO_1009;

typedef struct _USER_INFO_1010 {
DWORD	usri1010_auth_flags;
} USER_INFO_1010, *PUSER_INFO_1010, *LPUSER_INFO_1010;

typedef struct _USER_INFO_1011 {
LPWSTR	usri1011_full_name;
} USER_INFO_1011, *PUSER_INFO_1011, *LPUSER_INFO_1011;

typedef struct _USER_INFO_1012 {
LPWSTR	usri1012_usr_comment;
} USER_INFO_1012, *PUSER_INFO_1012, *LPUSER_INFO_1012;

typedef struct _USER_INFO_1013 {
LPWSTR	usri1013_parms;
} USER_INFO_1013, *PUSER_INFO_1013, *LPUSER_INFO_1013;

typedef struct _USER_INFO_1014 {
LPWSTR	usri1014_workstations;
} USER_INFO_1014, *PUSER_INFO_1014, *LPUSER_INFO_1014;

typedef struct _USER_INFO_1017 {
DWORD	usri1017_acct_expires;
} USER_INFO_1017, *PUSER_INFO_1017, *LPUSER_INFO_1017;

typedef struct _USER_INFO_1018 {
DWORD	usri1018_max_storage;
} USER_INFO_1018, *PUSER_INFO_1018, *LPUSER_INFO_1018;

typedef struct _USER_INFO_1020 {

DWORD	usri1020_units_per_week;
LPBYTE	usri1020_logon_hours;
} USER_INFO_1020, *PUSER_INFO_1020, *LPUSER_INFO_1020;

typedef struct _USER_INFO_1023 {
LPWSTR	usri1023_logon_server;
} USER_INFO_1023, *PUSER_INFO_1023, *LPUSER_INFO_1023;

typedef struct _USER_INFO_1024 {
DWORD	usri1024_country_code;
} USER_INFO_1024, *PUSER_INFO_1024, *LPUSER_INFO_1024;

typedef struct _USER_INFO_1025 {
DWORD	usri1025_code_page;
} USER_INFO_1025, *PUSER_INFO_1025, *LPUSER_INFO_1025;

typedef struct _USER_INFO_1051 {

DWORD	usri1051_primary_group_id;

} USER_INFO_1051, *PUSER_INFO_1051, *LPUSER_INFO_1051;

typedef struct _USER_INFO_1052 {

LPWSTR	usri1052_profile;

} USER_INFO_1052, *PUSER_INFO_1052, *LPUSER_INFO_1052;

typedef struct _USER_INFO_1053 {

LPWSTR	usri1053_home_dir_drive;

} USER_INFO_1053, *PUSER_INFO_1053, *LPUSER_INFO_1053;

For NetUserSetInfo, parmnum values refer to the fields in the user_info structure as follows. These values are used when indicating an error in a specific parameter via parm_err.

parmnum value	Field in user_info struct
USER_NAME_PARMNUM	usri_name
USER_PASSWORD_PARMNUM	usri_password
USER_PASSWORD_AGE_PARMNUM	usri_password_age
USER_PRIV_PARMNUM	usri_priv
USER_HOME_DIR_PARMNUM	usri_home_dir
USER_COMMENT_PARMNUM	usri_comment
USER_FLAGS_PARMNUM	usri_flags
USER_SCRIPT_PATH_PARMNUM	usri_script_path
USER_AUTH_FLAGS_PARMNUM	usri_auth_flags
USER_FULL_NAME_PARMNUM	usri_full_name
USER_USR_COMMENT_PARMNUM	usri_usr_comment
USER_PARMS_PARMNUM	usri_parms
USER_WORKSTATIONS_PARMNUM	usri_workstations
USER_LAST_LOGON_PARMNUM	usri_last_logon
USER_LAST_LOGOFF_PARMNUM	usri_last_logoff
USER_ACCT_EXPIRES_PARMNUM	usri_acct_expires
USER_MAX_STORAGE_PARMNUM	usri_max_storage
USER_UNITS_PER_WEEK_PARMNUM	usri_units_per_week
USER_LOGON_HOURS_PARMNUM	usri_logon_hours
USER_PAD_PW_COUNT_PARMNUM	usri_bad_pw_count
USER_NUM_LOGONS_PARMNUM	usri_num_logons
USER_LOGON_SERVER_PARMNUM	usri_logon_server
USER_COUNTRY_CODE_PARMNUM	usri_country_code
USER_CODE_PAGE_PARMNUM	usri_code_page
USER_PRIMARY_GROUP_PARMNUM	usri_primary_group_id
USER_PROFILE	usri_profile
USER_HOME_DIR_DRIVE_PARMNUM	usri_home_dir_drive
The user functions are:

NetUserAdd

NetUserDel

NetUserEnum

NetUserGetGroups

NetUserGetInfo

NetUserGetLocalGroups

NetUserSetGroups

NetUserSetInfo


 User Modal Functions

The user modal functions control the system-wide parameters that affect the Windows NT Security system behavior.

User modal information is available at three levels:

typedef struct _USER_MODALS_INFO_0 {
DWORD	usrmod0_min_passwd_len;
DWORD	usrmod0_max_passwd_age;
DWORD	usrmod0_min_passwd_age;
DWORD	usrmod0_force_logoff;
DWORD	usrmod0_password_hist_len;
} USER_MODALS_INFO_0, *PUSER_MODALS_INFO_0, LPUSER_MODALS_INFO_0;

typedef struct _USER_MODALS_INFO_1 {
DWORD	usrmod1_role;
LPWSTR	usrmod1_primary;
} USER_MODALS_INFO_1, *PUSER_MODALS_INFO_1, *LPUSER_MODALS_INFO_1;

typedef struct _USER_MODALS_INFO_2 {
LPWSTR	usrmod2_domain_name;
PSID	usrmod2_domain_id;
}USER_MODALS_INFO_2, *PUSER_MODALS_INFO_2, *LPUSER_MODALS_INFO_2;

The following information levels are valid only for NetUserModalsSet and replace the older way of passing in a Parmnum to set a specific field.

The following are supported on downlevel systems (for example, LAN Manager 2.x) as well. Note that the mapping from the old parmnum to the information level does not apply to the role and primary fields.

typedef struct _USER_MODALS_INFO_1001 {
DWORD	usrmod1001_min_passwd_len;
} USER_MODALS_INFO_1001, *PUSER_MODALS_INFO_1001, *LPUSER_MODALS_INFO_1001;

typedef struct _USER_MODALS_INFO_1002 {
DWORD	usrmod1002_max_passwd_age;
} USER_MODALS_INFO_1002, *PUSER_MODALS_INFO_1002, *LPUSER_MODALS_INFO_1002;

typedef struct _USER_MODALS_INFO_1003 {
DWORD	usrmod1003_min_passwd_age;
} USER_MODALS_INFO_1003, *PUSER_MODALS_INFO_1003, *LPUSER_MODALS_INFO_1003;

typedef struct _USER_MODALS_INFO_1004 {
DWORD	usrmod1004_force_logoff;
} USER_MODALS_INFO_1004, *PUSER_MODALS_INFO_1004, *LPUSER_MODALS_INFO_1004;

typedef struct _USER_MODALS_INFO_1005 {
DWORD	usrmod1005_password_hist_len;
} USER_MODALS_INFO_1005, *PUSER_MODALS_INFO_1005, *LPUSER_MODALS_INFO_1005;

typedef struct _USER_MODALS_INFO_1006 {
DWORD	usrmod1006_role;
} USER_MODALS_INFO_1006, *PUSER_MODALS_INFO_1006, *LPUSER_MODALS_INFO_1006;

typedef struct _USER_MODALS_INFO_1007 {
LPWSTR	usrmod1007_primary;
} USER_MODALS_INFO_1007, *PUSER_MODALS_INFO_1007, *LPUSER_MODALS_INFO_1007;

For NetUserModalsSet, parmnum values refer to the fields in the modals_info structure as follows. These values are used when indicating an error in a specific parameter via parm_err.

parmnum value	Field in modals_info struct
MODALS_MIN_PASSWD_LEN_PARMNUM	usrmod_min_passwd_len
MODALS_MAX_PASSWD_AGE_PARMNUM	usrmod_max_passwd_age
MODALS_MIN_PASSWD_AGE_PARMNUM	usrmod_min_passwd_age
MODALS_FORCE_LOGOFF_PARMNUM	usrmod_force_logoff
MODALS_PASSWD_HIST_LIST_PARMNUM	usrmod_passwd_hist_list
MODALS_ROLE_PARMNUM	usrmod_role
MODALS_PRIMARY_PARMNUM	usrmod_primary
MODALS_DOMAIN_NAME_PARMNUM	usrmod_domain_name
MODALS_DOMAIN_ID_PARMNUM	usrmod_domain_id
The user modal functions are:

NetUserModalsGet

NetUserModalsSet


 Global Group functions

The global group functions control global groups of users in a way that can be used across domains. A global group is a set of users who share common permissions in the security database. Group functions create or delete global groups, and review or adjust the membership of the global groups. The global group has a group name that specifies the user names of global group members.

To create a global group, an application calls NetGroupAdd, supplying a group name. Initially, the global group has no members. To assign members to the global group, call NetGroupSetUsers. To add a user to an existing global group, call NetGroupAddUser. To set general information about the global group, call NetGroupSetInfo.

NetGroupDelUser deletes a specified user name from a global group, and NetGroupDel disbands a global group. NetGroupDel works whether or not the global group has any members.

Three group functions retrieve information about the global groups on a server: NetGroupEnum produces a list of all global groups; NetGroupGetUsers lists all members of a specified global group; and NetGroupGetInfo returns general information about the global group.Each user account automatically belongs to one of the special global groups Domain Users or None, according to the user's Security Requirements. Membership of these global groups is indirectly controlled by the NetUserAdd, NetUserDel, and NetUserSetInfo functions. Group functions control groups of users.

Group account information is available at two levels:

typedef struct _GROUP_INFO_0 {
LPWSTR	grpi0_name;
} GROUP_INFO_0, *PGROUP_INFO_0, *LPGROUP_INFO_0;

typedef struct _GROUP_INFO_1 {
LPWSTR	grpi1_name;
LPWSTR	grpi1_comment;
} GROUP_INFO_1, *PGROUP_INFO_1, *LPGROUP_INFO_1;

typedef struct _GROUP_INFO_2 {
LPWSTR	grpi2_name;
LPWSTR	grpi2_comment;
DWORD	grpi2_group_id;
DWORD	grpi2_attributes;
}GROUP_INFO_2, *PGROUP_INFO_2;

The groups to which a user belongs may be obtained at one information level.

typedef struct _GROUP_USERS_INFO_0 {
LPWSTR	grui0_name;
} GROUP_USERS_INFO_0, *PGROUP_USERS_INFO_0, *LPGROUP_USERS_INFO_0;

typedef struct _GROUP_USERS_INFO_1 {
LPWSTR	grui1_name;
DWORD	grui1_attributes;
} GROUP_USERS_INFO_1, *PGROUP_USERS_INFO_1, *LPGROUP_USERS_INFO_1;

The following information levels are valid only for NetGroupSetInfo and replace the older way of passing in a Parmnum to set a specific field.

The following are supported on downlevel systems (for example, LAN Manager 2.x) as well:

typedef struct _GROUPINFO_1002 {
LPWSTR	grpi1002_comment;
} GROUP_USERS_INFO_1002, *PGROUP_USERS_INFO_1002, *LPGROUP_USERS_INFO_1002;

typedef struct _GROUP_INFO_1005 {
DWORD	grpi1005_attributes;
} GROUP_INFO_1005, *PGROUP_INFO_1005, *LPGROUP_INFO_1005;

For NetGroupSetInfo, parmnum values refer to the fields in the group_info structure as follows. These values are used when indicating an error in a specific parameter via parm_err.

parmnum value	Field in group_info struct
GROUP_NAME_PARMNUM	grpi_name
GROUP_COMMENT_PARMNUM	grpi_comment
GROUP_ATTRIBUTES_PARMNUM	grpi_attributes
The group functions are:

NetGroupAdd

NetGroupAddUser

NetGroupDel

NetGroupDelUser

NetGroupEnum

NetGroupGetInfo

NetGroupGetUsers

NetGroupSetInfo

NetGroupSetUsers


 Local Group Functions

A local group is a set of users who share common permissions in the security database. A local group can have members that are either users or global groups (global groups can contain only users). The local group functions control members of local groups in a way that can be used only by the systems within a "cluster". A "cluster" is the individual workstation if the system is a Windows NT system, but it contains all the Windows NT Servers of a domain if the system is a Windows NT Server. Thus, a local group defined on a workstation can be used only on that workstation, but a local group defined on a Windows NT Server can be used by any other Windows NT Server within the same domain. The local Group functions create or delete local groups, and review or adjust the memberships of local groups.

A member can be added to a local group by specifying the security identifier (SID) of the member. The Win32 LookupAccountName function can be used to translate a member account name to a SID.

To create a local group, an application calls NetLocalGroupAdd, supplying a local group name. Initially, the local group has no members. To assign members to the local group, call NetLocalGroupSetMembers. To add a member to an existing local group, call NetLocalGroupAddMember. To set general information about the local group, call NetLocalGroupSetInfo.

NetLocalGroupDelMember deletes a specified member from a local group, and NetLocalGroupDel disbands a local group, deleting all existing members of the local group first.

Three local group functions retrieve information about the local groups on a server: NetLocalGroupEnum produces a list of all local groups; NetLocalGroupGetMembers lists all members of a specified local group; and NetLocalGroupGetInfo returns general information about the local group.

Group account information is available at three levels:

typedef struct _LOCALGROUP_INFO_0 {
LPWSTR	lgrpi0_name;
} LOCALGROUP_INFO_0, *PLOCALGROUP_INFO_0, LPLOCALGROUP_INFO_0;

typedef struct _LOCALGROUP_INFO_1 {
LPWSTR	lgrpi1_name;
LPWSTR	lgrpi1_comment;
} LOCALGROUP_INFO_1, *PLOCALGROUP_INFO_1, LPLOCALGROUP_INFO_1;

typedef struct _LOCALGROUP_INFO_1002 {
LPWSTR	lgrpi1002_comment;
} LOCALGROUP_INFO_1002, *PLOCALGROUP_INFO_1002, LPLOCALGROUP_INFO_1002;

The local group to which a member belongs may be obtained at two information level.

typedef struct _LOCALGROUP_MEMBERS_INFO_0 {
PSID	lgrmi0_sid;
} LOCALGROUP_MEMBERS_INFO_0, *PLOCALGROUP_MEMBERS_INFO_0, *LPLOCALGROUP_MEMBERS_INFO_0;

typedef struct _LOCALGROUP_MEMBERS_INFO_0 {
PSID	lgrmi0_sid;
} LOCALGROUP_MEMBERS_INFO_0, *PLOCALGROUP_MEMBERS_INFO_0, *LPLOCALGROUP_MEMBERS_INFO_0;

typedef struct _LOCALGROUP_MEMBERS_INFO_1 {
PSID	lgrmi1_sid;
SID_NAME_USE	lgrmi1_sidusage;
LPWSTR	lgrmi1_name;
} LOCALGROUP_MEMBERS_INFO_1, *PLOCALGROUP_MEMBERS_INFO_1, *LPLOCALGROUP_MEMBERS_INFO_1;

typedef struct _LOCALGROUP_USERS_INFO_0 {
LPWSTR	lgrui0_name;
} LOCALGROUP_USERS_INFO_0, *PLOCALGROUP_USERS_INFO_0, *LPLOCALGROUP_USERS_INFO_0;

For NetLocalGroupSetInfo, parmnum values refer to the fields in the group_info structure as follows. These values are used when indicating an error in a specific parameter via parm_err.

parmnum value	Field in group_info struct
LOCALGROUP_NAME_PARMNUM	lgrpi_name
LOCALGROUP_COMMENT_PARMNUM	lgrpi_comment
The local group functions are:

NetLocalGroupAdd

NetLocalGroupAddMember

NetLocalGroupDel

NetLocalGroupDelMember

NetLocalGroupEnum

NetLocalGroupGetInfo

NetLocalGroupGetMembers

NetLocalGroupSetInfo

NetLocalGroupSetMembers


 Access Functions

Note  A full set of access setting functions exist in Win32. These should be used in place of the NetAccess functions. The NetAccess functions work only when remoted to a downlevel system.

Access permissions functions examine or modify user or group access permissions for specified resources. An access control list (ACL) contains the name of a resource, an audit attribute field, and a list of access control entries. An access control entry (ACE) is a user name or group name and its corresponding access permissions.

The audit attribute field defines what type of events will be audited for that resource. It is possible to audit various types of events, depending on whether the resource is a file or a directory. It is possible to audit events such as opening, writing, and deleting a file; creating or deleting a directory; and changing the ACL of the resource.

NetAccessAdd creates an ACL for a resource and sets user name or group name access permissions. NetAccessDel deletes the ACL for a resource. NetAccessGetInfo returns the ACL for a particular resource. NetAccessEnum returns information about all ACLs.

Only users or applications with admin group membership or special permission for the resource can define or examine access permissions. Users have special permissions for a resource when they are granted ACCESS_PERM permission for that resource; this is also known as P permission.

NetAccessCheck verifies whether a user has permission to perform a specified operation on a particular resource. If access permission is needed, you can use NetAccessSetInfo to change the ACL. NetAccessGetUserPerms returns a specified user's or group's permission for a specified resource.

Access permission information is available at two levels:

typedef struct _ACCESS_INFO_0 {
LPWSTR	acc0_resource_name;
} ACCESS_INFO_0, *PACCESS_INFO_0, *LPACCESS_INFO_0;

typedef struct _ACCESS_INFO_1 {
LPWSTR	acc1_resource_name;
DWORD	acc1_attr;
DWORD	acc1_count;
} ACCESS_INFO_1, *PACCESS_INFO_1, *LPACCESS_INFO_1;

Access list information is available at one levels:

typedef struct _ACCESS_LIST {
LPWSTR	acl_ugname;
DWORD	acl_access;
} ACCESS_LIST, *PACCESS_LIST, *LPACCESS_LIST;

The following information levels are valid only for NetAccessSetInfo and replace the older way of passing in a Parmnum to set a specific field.

The following are supported on downlevel systems (for example, LAN Manager 2.x) as well:

typedef struct _ACCESS_INFO_1002 {
DWORD	acc1002_attr;
} ACCESS_INFO_1002, *PACCESS_INFO_1002, *LPACCESS_INFO_1002;

For NetAccessSetInfo, parmnum values refer to the fields in the access_info structure as follows. These values are used when indicating an error in a specific parameter via parm_err.

parmnum value	Field in access_info struct
ACCESS_RESOURCE_NAME_PARMNUM	acc_resource_name
ACCESS_ATTR_PARMNUM	acc_attr
ACCESS_COUNT_PARMNUM	acc_count
ACCESS_ACCESS_LIST_PARMNUM	array following acc1_count
The following are defined for the bits in the acc1_attr field of _ACCESS_INFO_1:

Value	Constant
ACCESS_AUDIT	0x001
ACCESS_SUCCESS_OPEN	0x010
ACCESS_SUCCESS_WRITE	0x020
ACCESS_SUCCESS_DELETE	0x040
ACCESS_SUCCESS_ACL	0x080
ACCESS_SUCCESS_MASK	0x0F0
ACCESS_FAIL_OPEN	0x100
ACCESS_FAIL_WRITE	0x200
ACCESS_FAIL_DELETE	0x400
ACCESS_FAIL_ACL	0x800
ACCESS_FAIL_MASK	0xF00
ACCESS_FAIL_SHIFT	0x004
The access permission functions are:

NetAccessAdd

NetAccessCheck

NetAccessDel

NetAccessEnum

NetAccessGetInfo

NetAccessGetUserPerms

NetAccessSetInfo


 Domain Functions

Domain functions retrieve information about a domain. They require that the workstation service be started.

The domain functions are:

NetGetDCName

NetServerTransportAdd

NetServerTransportDel

NetServerTransportEnum

NetWkstaTransportAdd

NetWkstaTransportDel

NetWkstaTransportEnum


 Transport Functions

Transport functions handle binding and unbinding of transports to and from the server and redirector, and also enumerate the transports used by a component. The server transport functions deal with transports managed by the server, and the workstation transport functions deal with transports managed by the redirector.

NetServerTransportAdd allows the user to bind the transport to the server. NetServerTransportDel allows the user to unbind the server from the transport. NetServerTransportEnum enumerates the transports that are managed by the server.

The NetWkstaTransportAdd/Del/Enum functions perform equivalent operations for the workstation.

Server transport functions are available at one information level.

typedef struct _SERVER_TRANSPORT_INFO_0 {
DWORD	svti0_number_of_vcs;
LPWSTR	svti0_transport_name;
LPBYTE	svti0_transport_address;
DWORD	svti0_transportaddresslength;
LPWSTR	svti0_networkaddress;
} SERVER_TRANSPORT_INFO_0, *PSERVER_TRANSPORT_INFO_0, *LPSERVER_TRANSPORT_INFO_0;

Workstation transport functions are available at one information level.

typedef struct _WKSTA_TRANSPORT_INFO_0 {
DWORD	wkti0_quality_of_service;
DWORD	wkti0_number_of_vcs;
LPWSTR	wkti0_transport_name;
LPWSTR	wkti0_transport_address;
} WKSTA_TRANSPORT_INFO_0, *PWKSTA_TRANSPORT_INFO_0, *LPWKSTA_TRANSPORT_INFO_0;

The transport functions are:

NetServerTransportAdd

NetServerTransportDel

NetServerTransportEnum


 Alert Functions

Alert functions notify network service programs and applications of network events. An event is a particular instance of a process or state of hardware as defined by an application. The alert functions allow applications to indicate when predefined events occur.

NetAlertRaise is used to indicate that an event has occurred.

The fixed-length header contains the standard alert data structure. The STD_ALERT data structure has the following format:

typedef struct _STD_ALERT {
DWORD	alrt_timestamp;
WCHAR	alrt_eventname[EVLEN+1];
WCHAR	alrt_servicename[SNLEN+1];
} STD_ALERT, *PSTD_ALERT, *LPSTD_ALERT;

The ADMIN_OTHER_INFO data structure has the following format:

typedef struct _ADMIN_OTHER_INFO {
DWORD	alrtad_errcode;
DWORD	alrtad_numstrings;
} ADMIN_OTHER_INFO, *PADMIN_OTHER_INFO, *LPADMIN_OTHER_INFO;

/* Followed by consecutive Unicode strings; the count
is in the alrtad_numstrings element. */
WCHAR	mergestrings[];

The ERRLOG_OTHER_INFO data structure has the following format:

typedef struct _ERRLOG_OTHER_INFO {
DWORD	alrter_errcode;
DWORD	alrter_offset;
} ERRLOG_OTHER_INFO, *PERRLOG_OTHER_INFO, *LPERRLOG_OTHER_INFO;

The PRINT_OTHER_INFO data structure has the following format:

typedef struct _PRINT_OTHER_INFO {
DWORD	alrtpr_jobid;
DWORD	alrtpr_status;
DWORD	alrtpr_submitted;
DWORD	alrtpr_size;
} PRINT_OTHER_INFO, *PPRINT_OTHER_INFO, *LPPRINT_OTHER_INFO;
/* Followed by consecutive Unicode strings. */
WCHAR	computername[];
WCHAR	username[];
WCHAR	queuename[];
WCHAR	destname[];
WCHAR	status_string[];

The USER_OTHER_INFO data structure has the following format:

typedef struct _USER_OTHER_INFO {
DWORD	alrtus_errcode;
DWORD	alrtus_numstrings;
} USER_OTHER_INFO, *PUSER_OTHER_INFO, *LPUSER_OTHER_INFO;
/*
 * Followed by a number of consecutive Unicode strings;
 * the count is in the alrtus_numstrings element. */
 */
WCHAR	mergestrings[];

/* Further followed by two more consecutive Unicode strings. */
WCHAR	username[];
WCHAR	computername[];

The alert functions are:

NetAlertRaise

NetAlertRaiseEx


 Error Logging Functions

Note  Use the error logging functions only for remoting to downlevel. For Windows NT use the Event Logging functions.

Windows NT uses an integrated Event Logging mechanism for reporting both errors and audits. The NetError and NetAudit functions are provided to access downlevel LAN Manager logs. They will report ERROR_NOT_SUPPORTED if called to an Windows NT system.

The error log is a file that stores error messages (in binary format). It contains information about LAN Manager software internal errors, MS OS/2 and MS-DOS internal errors, and network service errors.

NetErrorLogRead reads entries from the error log; and NetErrorLogClear clears the error log and, optionally, saves the entries in a backup file.

NetErrorLogRead uses the ERROR_LOG data structure to read entries from and write entries to the error log. An entry consists of a fixed-length data structure. The data structure can be followed by Unicode strings (el_text) that describe the error message, and a block of raw data (el_data) related to the cause of the error. Because of the variable lengths and structures of the el_data and el_text portions of the entry, only the fixed-length data structure is defined in the ERROR_LOG data structure.

The error log entry has the following format:

typedef struct _ERROR_LOG {
DWORD	el_len;
DWORD	el_reserved;
DWORD	el_time;
DWORD	el_error;
LPWSTR	el_name
LPWSTR	el_text;

LPBYTE	el_data;

DWORD	el_data_size;
DWORD	el_nstrings;
} ERROR_LOG, *PERROR_LOG, *LPERROR_LOG;

/*
 * Variable-length raw data specific to the error. el_len will be preceded by pad bytes

 * as required for proper alignment. There may also be pad bytes after the end of the

 * fixed length structure, before el_data. Use the pointer in the fixed length structure

 * to reference this data.
 */
BYTE	el_data[];	/* Raw data	 */
DWORD	el_len2;

The error log handle is defined as follows:

typedef struct _HLOG {
DWORD	time;
DWORD	last_flags;
DWORD	offset;
DWORD	rec_offset;
} HLOG, *PHLOG, *LPHLOG;

The error log functions are:

NetErrorLogClear

NetErrorLogRead


 Configuration Functions

Note  The configuration functions are only for downlevel support. Use the registry functions to retrieve configuration information on Windows NT.

Configuration functions retrieve network configuration information.

Configuration functions are available at one information level.

typedef struct _CONFIG_INFO_0 {
LPWSTR	cfgi0_key;
LPWSTR	cfgi0_data;
} CONFIG_INFO_0, *PCONFIG_INFO_0, *LPCONFIG_INFO_0;

The configuration functions are:

NetConfigGet

NetConfigGetAll

NetConfigSet


 Statistics Functions

LAN Manager accumulates a set of operating statistics for workstations and servers from the time that the Workstation or Server service is started. NetStatisticsGet is called to get those statistics. The statistics function, NetStatisticsGet, retrieves the operating statistics for workstations and servers. Since Windows NT and downlevel workstations collect a different set of statistics, the caller must know whether the server is Windows NT or downlevel (which can be discovered using the NetServerGetInfo function) and interpret the returned buffer accordingly.

NetStatisticsGet returns a STAT_WORKSTATION_0 data structure when workstation statistics are requested; it returns a STAT_SERVER_0 data structure when server statistics are requested.

The downlevel STAT_WORKSTATION_0 data structure has the following format:

typedef struct _STAT_WORKSTATION_0 {
DWORD	stw0_start;
DWORD	stw0_numNCB_r;
DWORD	stw0_numNCB_s;
DWORD	stw0_numNCB_a;
DWORD	stw0_fiNCB_r;
DWORD	stw0_fiNCB_s;
DWORD	stw0_fiNCB_a;
DWORD	stw0_fcNCB_r;
DWORD	stw0_fcNCB_s;
DWORD	stw0_fcNCB_a;
DWORD	stw0_sesstart;
DWORD	stw0_sessfailcon;
DWORD	stw0_sessbroke;
DWORD	stw0_uses;
DWORD	stw0_usefail;
DWORD	stw0_autorec;
DWORD	stw0_bytessent_r_hi;
DWORD	stw0_bytessent_r_lo;
DWORD	stw0_bytesrcvd_r_hi;
DWORD	stw0_bytesrcvd_r_lo;
DWORD	stw0_bytessent_s_hi;
DWORD	stw0_bytessent_s_lo;
DWORD	stw0_bytesrcvd_s_hi;
DWORD	stw0_bytesrcvd_s_lo;
DWORD	stw0_bytessent_a_hi;
DWORD	stw0_bytessent_a_lo;
DWORD	stw0_bytesrcvd_a_hi;
DWORD	stw0_bytesrcvd_a_lo;
DWORD	stw0_reqbufneed;
DWORD	stw0_bigbufneed;
} STAT_WORKSTATION_0, *PSTAT_WORKSTATION_0, *LPSTAT_WORKSTATION_0;

The Windows NT STAT_WORKSTATION_0 data structure has the following format:

typedef struct _STAT_WORKSTATION_0 {
LARGE_INTEGER	StatisticsStartTime;
LARGE_INTEGER	BytesReceived;
LARGE_INTEGER	SmbsReceived;
LARGE_INTEGER	PagingReadBytesRequested;
LARGE_INTEGER	NonPagingReadBytesRequested;
LARGE_INTEGER	CacheReadBytesRequested;
LARGE_INTEGER	NetworkReadBytesRequested;
LARGE_INTEGER	BytesTransmitted;
LARGE_INTEGER	SmbsTransmitted;
LARGE_INTEGER	PagingWriteBytesRequested;
LARGE_INTEGER	NonPagingWriteBytesRequested;
LARGE_INTEGER	CacheWriteBytesRequested;
LARGE_INTEGER	NetworkWriteBytesRequested;
DWORD	InitiallyFailedOperations;
DWORD	FailedCompletionOperations;
DWORD	ReadOperations;
DWORD	RandomReadOperations;
DWORD	ReadSmbs;
DWORD	LargeReadSmbs;
DWORD	SmallReadSmbs;
DWORD	WriteOperations;
DWORD	RandomWriteOperations;
DWORD	WriteSmbs;
DWORD	LargeWriteSmbs;
DWORD	SmallWriteSmbs;
DWORD	RawReadsDenied;
DWORD	RawWritesDenied;
DWORD	NetworkErrors;
// Connection	/Session counts
DWORD	Sessions;
DWORD	FailedSessions;
DWORD	Reconnects;
DWORD	CoreConnects;
DWORD	Lanman20Connects;
DWORD	Lanman21Connects;
DWORD	LanmanNtConnects;
DWORD	ServerDisconnects;
DWORD	HungSessions;
DWORD	UseCount;
DWORD	FailedUseCount;
//
// Queue Leng	ths (updates protected by RdrMpxTableSpinLock NOT
// RdrStatisticsSpinlock)
//
DWORD	CurrentCommands;
} STAT_WORKSTATION_0, *PSTAT_WORKSTATION_0, *LPSTAT_WORKSTATION_0;

The STAT_SERVER_0 data structure has the following format:

typedef struct _STAT_SERVER_0 {
DWORD	sts0_start;
DWORD	sts0_fopens;
DWORD	sts0_devopens;
DWORD	sts0_jobsqueued;
DWORD	sts0_sopens;
DWORD	sts	0_stimedout;
DWORD	sts0_serrorout;
DWORD	sts0_pwerrors;
DWORD	sts0_permerrors;
DWORD	sts0_syserrors;
DWORD	sts0_bytessent_low;
DWORD	sts0_bytessent_high;
DWORD	sts0_bytesrcvd_low;
DWORD	sts0_bytesrcvd_high;
DWORD	sts0_avresponse;
DWORD	sts0_reqbufneed;
DWORD	sts0_bigbufneed;
} STAT_SERVER_0, *PSTAT_SERVER_0, *LPSTAT_SERVER_0;

The statistics function is:

NetStatisticsGet


 Auditing Functions

Note  The auditing functions are for downlevel only. Windows NT automatically records audits on failed accesses when AccessCheckAndAudit is used. To read audits, use the ReadEventLog function.

Windows NT uses an integrated event logging mechanism for reporting both errors and audits. The NetError and NetAudit functions are provided to access downlevel LAN Manager logs. They will report ERROR_NOT_SUPPORTED if called to an Windows NT system.

Auditing functions control the audit log. Auditing functions monitor operations on the specified server. If auditing is enabled, each monitored operation generates an audit entry. For example, when a user establishes a connection to the server, a single audit entry is generated.

Audit entries are stored in a binary file called an audit trail or audit log. All Auditing functions perform their operations on this file. LAN Manager defines many types of audit entries.

NetAuditRead reads the audit log. NetAuditClear clears the audit log.

Data Structures

All audit entries include a fixed-length header used in conjunction with variable-length data specific to the entry type. Because of the variable lengths and structures of the ae_data element of the audit entry (it is possible for ae_data to be zero bytes), only the fixed header is defined in the audit_entry data structure.

The variable-length portion of the audit entry can contain an offset to a variable-length Unicode string. The offset values are DWORDs. To determine the value of the pointer to this string, add the offset value to the address of the ae_data data structure.

The following example illustrates this procedure. Assume that pAE points to a buffer that contains a complete audit entry and that the ae_type element of the audit_entry data structure contains the value AE_CONNSTOP, which specifies the predefined AE_CONNSTOP data structure. To point the variable pszComputerName to the Unicode string that contains the name of the client whose connection was stopped, an application would perform the following algorithm:

PAUDIT_ENTRY	pAE;	/* Fixed part of audit entry */
LPAE_CONNSTOP	pAEvar;	/* Variable-length structure */
LPWSTR	pszComputerName;	/* Pointer to var-length string*/

/* Calculate the offset to the variable-length structure. */
pAEvar = (_LPAE_CONNSTOP) (((LPBYTE) pAE) + pAE->ae_data_offset);

/* Calculate the offset to the computername. */
pszComputerName = ((LPBYTE) pAEvar) + pAEvar->ae_cp_compname;

Fixed-Length Header

The audit_entry data structure has the following format:

typedef struct _AUDIT_ENTRY {
DWORD	ae_len;
DWORD	ae_reserved;
DWORD	ae_time;
DWORD	ae_type;
DWORD	ae_data_offset;	/* Offset from beginning
   address of audit_entry */

DWORD	ae_data_size;
} AUDIT_ENTRY, *PAUDIT_ENTRY, *LPAUDIT_ENTRY;

/* Variable-length data specific to type of audit entry. There may be
   pad bytes after 	ae_data_size for alignment purposes.

*/
BYTE	ae_data[];

/* Terminating length indicator. Preceded by pad bytes for proper alignment.*/
DWORD	ae_len2;

where

ae_len and ae_len2

Specify the length of the audit entry. Both have the same value. The ae_len element is included at the beginning and at the end of the audit entry to enable both backward and forward scanning of the log.

ae_reserved

Reserved.

ae_time

Specifies when the audit entry was generated. The value is stored as the number of seconds elapsed since 00:00:00, January 1, 1970.

ae_type

Specifies the type of audit entry. Type values from 0x0000 through 0x07FF are reserved. OEMs and other applications programmers can reserve values from 0x0800 through 0xFFFF.

ae_data_offset

Specifies the byte offset from the beginning of the audit entry to the beginning of the variable-length portion (ae_data) of the audit entry.

ae_data

Specifies the variable-length portion of the audit entry; it differs depending on the type of entry specified by ae_type. The information begins at ae_data_offset bytes from the top of the audit entry. For information about the structure of each entry type defined by LAN Manager, see Variable-Length Data.


 Variable-Length Data

The following data structures are specific to the audit entry type The structures follow the audit_entry header, but they are not necessarily contiguous.

The _AE_SRVSTATUS data structure is associated with an audit entry of type AE_SRVSTATUS.

typedef struct _AE_SRVSTATUS {
DWORD	ae_sv_status;
}AE_SRVSTATUS , * PAE_SRVSTATUS ;

The _AE_SESSLOGON data structure is associated with an audit entry of type AE_SESSLOGON.

typedef struct _AE_SESSLOGON {
DWORD	ae_so_compname;
DWORD	ae_so_username;
DWORD	ae_so_privilege;
}AE_SESSLOGON , * PAE_SESSLOGON ;

The _AE_SESSLOGOFF data structure is associated with an audit entry of type AE_SESSLOGOFF.

typedef struct AE_SESSLOGOFF {
DWORD	ae_sf_compname;
DWORD	ae_sf_username;
DWORD	ae_sf_reason;
}AE_SESSLOGOFF , * PAE_SESSLOGOFF;

The _AE_SESSPWERR data structure is associated with an audit entry of type AE_SESSPWERR.

typedef struct _AE_SESSPWERR {
DWORD	ae_sp_compname;
DWORD	ae_sp_username;
}AE_SESSPWERR , * PAE_SESSPWERR ;

The _AE_CONNSTART data structure is associated with an audit entry of type AE_CONNSTART.

typedef struct _AE_CONNSTART {
DWORD	ae_ct_compname;
DWORD	ae_ct_username;
DWORD	ae_ct_netname;
DWORD	ae_ct_connid;
}AE_CONNSTART , * PAE_CONNSTART ;

The _AE_CONNSTOP data structure is associated with an audit entry of type AE_CONNSTOP.

typedef struct _AE_CONNSTOP {
DWORD	ae_cp_compname;
DWORD	ae_cp_username;
DWORD	ae_cp_netname;
DWORD	ae_cp_connid;
DWORD	ae_cp_reason;
}AE_CONNSTOP , * PAE_CONNSTOP ;

The _AE_CONNREJ data structure is associated with an audit entry of type AE_CONNREJ.

typedef struct _AE_CONNREJ {
DWORD	ae_cr_compname;
DWORD	ae_cr_username;
DWORD	ae_cr_netname;
DWORD	ae_cr_reason;
}AE_CONNREJ , * PAE_CONNREJ ;

The _AE_RESACCESS data structure is associated with an audit entry of type AE_RESACCESS.

typedef struct _AE_RESACCESS {
DWORD	ae_ra_compname;
DWORD	ae_ra_username;
DWORD	ae_ra_resname;
DWORD	ae_ra_operation;
DWORD	ae_ra_returncode;
DWORD	ae_ra_restype;
DWORD	ae_ra_fileid;
}AE_RESACCESS , * PAE_RESACCESS ;

The _AD_RESACCESSREJ data structure is associated with an audit entry of type AE_RESACCESSREJ.

typedef struct _AE_RESACCESSREJ {
DWORD	ae_rr_compname;
DWORD	ae_rr_username;
DWORD	ae_rr_resname;
DWORD	ae_rr_operation;
}AE_RESACCESSREJ , * PAE_RESACCESSREJ ;

The _AD_CLOSEFILE data structure is associated with an audit entry of type AE_CLOSEFILE.

typedef struct _AE_CLOSEFILE {
DWORD	ae_cf_compname;
DWORD	ae_cf_username;
DWORD	ae_cf_resname;
DWORD	ae_cf_fileid;
DWORD	ae_cf_duration
DWORD	ae_cf_reason;
}AE_CLOSEFILE , * PAE_CLOSEFILE ;

The _AE_SERVICESTAT data structure is associated with an audit entry of type AE_SERVICESTAT.

typedef struct _AE_SERVICESTAT {
DWORD	ae_ss_compname;
DWORD	ae_ss_username;
DWORD	ae_ss_svcname;
DWORD	ae_ss_status;
DWORD	ae_ss_code;
DWORD	ae_ss_text;
DWORD	ae_ss_returnval;
}AE_SERVICESTAT , * PAE_SERVICESTAT ;

The _AE_ACLMOD data structure is associated with audit entries of type AE_ACLMOD and AE_ACLMODFAIL.

struct _AE_ACLMOD {
DWORD	ae_am_compname;
DWORD	ae_am_username;
DWORD	ae_am_resname;
DWORD	ae_am_action;
DWORD	ae_am_datalen;
}AE_ACLMOD, * PAE_ACLMOD;

The _AE_UASMOD data structure is associated with an audit entry of type AE_UASMOD.

typedef struct _AE_UASMOD {
DWORD	ae_um_compname;
DWORD	ae_um_username;
DWORD	ae_um_resname;
DWORD	ae_um_rectype;
DWORD	ae_um_action;
DWORD	ae_um_datalen;
}AE_UASMOD , * PAE_UASMOD ;

The _AE_NETLOGON data structure is associated with an audit entry of type AE_NETLOGON.

typedef struct _AE_NETLOGON {
DWORD	ae_no_compname;
DWORD	ae_no_username;
DWORD	ae_no_privilege;
DWORD	ae_no_authflags;
}AE_NETLOGON , * PAE_NETLOGON ;

The _AE_NETLOGOFF data structure is associated with an audit entry of type AE_NETLOGOFF.

typedef struct _AE_NETLOGOFF {
DWORD	ae_nf_compname;
DWORD	ae_nf_username;
DWORD	ae_nf_reserved1;
DWORD	ae_nf_reserved2;
}AE_NETLOGOFF , * PAE_NETLOGOFF ;

The _AE_ACCLIM data structure is associated with an audit entry of type AE_ACCLIMITEXCD.

typedef struct _AE_ACCLIM {
DWORD	ae_al_compname;
DWORD	ae_al_username;
DWORD	ae_al_resname;
DWORD	ae_al_limit;
}AE_ACCLIM , * PAE_ACCLIM ;

The _AE_LOCKOUT data structure is associated with an audit entry of type AE_LOCKOUT.

typedef struct AE_LOCKOUT {
DWORD	ae_lk_compname;
DWORD	ae_lk_username;
DWORD	ae_lk_action;
DWORD	ae_lk_bad_pw_count;
}AE_LOCKOUT , PAE_LOCKOUT ;

The _AE_GENERIC data structure is associated with an audit entry of type AE_GENERIC.

typedef struct _AE_GENERIC {
DWORD	ae_ge_msgfile;
DWORD	ae_ge_msgnum;
DWORD	ae_ge_params;
DWORD	ae_ge_param1;
DWORD	ae_ge_param2;
DWORD	ae_ge_param3;
DWORD	ae_ge_param4;
DWORD	ae_ge_param5;
DWORD	ae_ge_param6;
DWORD	ae_ge_param7;
DWORD	ae_ge_param8;
DWORD	ae_ge_param9;
}AE_GENERIC , * PAE_GENERIC ;

The audit log handle is defined as follows:

typedef struct _HLOG {
DWORD	time;
DWORD	last_flags;
DWORD	offset;
DWORD	rec_offset;
} HLOG, *PHLOG, *LPHLOG;

The auditing functions are:

NetAuditClear

NetAuditRead


 Replicator Functions

The Windows NT replicator functions control how the Windows NT Replicator service updates selective directories from an export server to one or more clients. In addition to providing compatible LAN Manager 2.x functionality in a well-defined manner, this new set of LAN Manager functions allow for specific API (operation) security checking.

The change from the file system based control on LAN Manager 2.x to replicator function control on Windows NT has the following implications:

•	Applications can no longer delete a directory in the import path of a client to stop receiving updates from its master.

•	Applications can no longer use the REPL.INI file in each replicated directory on a master to control the method of replication.

•	Applications can no longer lock or unlock a directory on a master from being replicated by creating or deleting the USERLOCK.* file(s).

•	Applications can no longer lock or unlock a directory on a client from receiving updates from its master by creating or deleting the USERLOCK.* file(s).

•	Applications that depend on the LAN Manager 2.x behavior of ignoring locks for file integrity trees will need to be modified. (Windows NT policy differs from LAN Manager 2.x policy; under Windows NT the locks are always respected.)

Each of the intended operations listed preceding can be specified to the Windows NT replicator service through an appropriate function.

Any user or application that belongs to the admin or server operator group on a local or remote export server can modify the parameters that control the replication master.

There are three categories of replicator functions:

•	Replicator configuration functions

•	Replicator export directory functions

•	Replicator import directory functions


 Replicator Configuration Functions

The configuration parameters of the replicator service can be examined using NetReplGetInfo. They can be modified using NetReplSetInfo.

The replicator service configuration parameters are:

role

Role of the Replicator service, which is either REPL_ROLE_IMPORT (client), REPL_ROLE_EXPORT (master), or REPL_ROLE_BOTH. On a Windows NT Server, any of these values are allowed. Under Windows NT systems, only REPL_ROLE_IMPORT is allowed.

exportpath

Fully qualified path to the master tree in which directories are created and replicated from. This path must include the drive letter.

exportlist

List of computer and domain names to send update announcements to. If this list is not provided, then update announcements will be sent to the server's domain. The list entries are separated by semicolons; computer names in the list must not have leading backslashes.

importpath

Fully qualified path to the client tree in which directories are created to receive the replicas of the master. This path must include the drive letter.

importlist

List of computers and domain names to receive updates from. If this list is not provided, then update announcements are received from the server's domain. The list entries are separated by semicolons; computer names in the list must not have leading backslashes.

logonusername

User account name belonging to the replicator group with which the client logs on to read files from its master(s). This field is ignored by the Windows NT replicator, but is provided for possible future use.

interval

Time in minutes within which the master checks for changes in all the replicated directories. This field may be ignored by the Windows NT replicator, but is provided for possible future use.

pulse

Time in number of intervals within which the master notifies its clients of the current replica version when no updates are necessary. This field may be ignored by the Windows NT replicator, but is provided for possible future use.

guardtime

Time in minutes that a REPL_INTEGRITY_TREE level integrity directory must be stable before a client is allowed to update from it. (See the explanation of integrity in Replicator Export Directory Functions). The default guard time is 2 minutes.

random

A value in seconds sent by a master to its clients so that the clients can use the 0 random range to generate a random time to wait on before updating from the master.

The configuration parameters (except importpath and exportpath) values can all be dynamically set.

These functions can be called whether the replicator service is running or not. If the replicator service is already running, any modification (except to importpath and exportpath) to the replication configuration takes effect immediately, and is persistent after the replicator service has been stopped. If the replicator service is not started, the parameters are stored as persistent information and will take effect when the replicator service starts up. The service must be stopped to set the importpath and exportpath values.

The replicator configuration information structures are:

typedef struct _REPL_INFO_0 {
DWORD	rp0_role;
LPWSTR	rp0_exportpath;
LPWSTR	rp0_exportlist;
LPWSTR	rp0_importpath;
LPWSTR	rp0_importlist;
LPWSTR	rp0_logonusername;
DWORD	rp0_interval;
DWORD	rp0_pulse;
DWORD	rp0_guardtime;
DWORD	rp0_random;
} REPL_INFO_0, *PREPL_INFO_0, *LPREPL_INFO_0;

typedef struct _REPL_INFO_1000 {
DWORD	rp1000_interval;
} REPL_INFO_1000, *PREPL_INFO_1000, *LPREPL_INFO_1000;

typedef struct _REPL_INFO_1001 {
DWORD	rp1001_pulse;
} REPL_INFO_1001, *PREPL_INFO_1001, *LPREPL_INFO_1001;

typedef struct _REPL_INFO_1002 {
DWORD	rp1002_guardtime;
} REPL_INFO_1002, *PREPL_INFO_1002, *LPREPL_INFO_1002;

typedef struct _REPL_INFO_1003 {
DWORD	rp1003_random;
} REPL_INFO_1003, *PREPL_INFO_1003, *LPREPL_INFO_1003;


 Replicator Export Directory Functions

The replicator export directory functions control top-level directories under the export path on the master. A user can create a new directory under the export path and the Replicator service will automatically replicate that directory. Or, a directory under the export path can be registered using NetReplExportDirAdd. When adding a directory to be replicated using these functions, the replication controls (integrity and extent) are specified via the NetReplExportDirAdd function. If the directory is created in the file system and no replicator functions are called, then the directory is treated as having file integrity and tree extent.

Integrity determines when a master updates a client. When integrity is REPL_INTEGRITY_FILE, the client gets a replica of a file within the directory when it is not in use (being changed or replicated). When integrity is set to REPL_INTEGRITY_TREE, every file and directory within the replicated directory must be stable for the amount of time specified by the guardtime parameter before the client is updated. Extent determines whether the entire tree within the directory is replicated (REPL_EXTENT_TREE) or only the files in the first-level directory is replicated (REPL_EXTENT_FILE).

The replication controls of each replicated directory can be examined using NetReplExportDirGetInfo, and dynamically modified using NetReplExportDirSetInfo. These control fields used to be specified in the REPL.INI file within each replicated directory on LAN Manager 2.x, and they were not dynamically settable. On Windows NT, the REPL.INI file is not used and will be ignored in the replication process.

NetReplExportDirEnum returns a list of directories that are currently replicated. NetReplExportDirDel deregisters a directory so that it is no longer replicated.

The lock status information is returned in two fields: lockcount and locktime. Lockcount indicates the number of outstanding locks on a directory. Locktime is the time (in seconds since 1970, GMT) when the directory was first locked, or is 0 if the directory is not locked at the present time.

NetReplExportDirLock locks a directory so that it is not replicated, by incrementing a lock reference count for the directory. A lock on a directory can be unlocked using NetReplExportDirUnlock. The replication does not resume unless all outstanding locks on that directory are released, and the lock reference count is returned to 0. (The locktime field is automatically set to 0 when lockcount is 0.)

The replicator export directory functions can be called whether the Replicator service is running or not. If the Replicator service is running as a master, any modification to the directory controls takes effect immediately, and is persistent after the Replicator service has been stopped. If the Replicator service is not started, the controls for the directory is stored as persistent information and will take effect when the Replicator service starts up.

The replicator export directory functions are available at the following information levels:

typedef struct _REPL_EDIR_INFO_0 {
LPWSTR	rped0_dirname;
} REPL_EDIR_INFO_0, *PREPL_EDIR_INFO_0, *LPREPL_EDIR_INFO_0;

typedef struct _REPL_EDIR_INFO_1 {
LPWSTR	rped1_dirname;
DWORD	rped1_integrity;
DWORD	rped1_extent;
} REPL_EDIR_INFO_1, *PREPL_EDIR_INFO_1, *LPREPL_EDIR_INFO_1;

typedef struct _REPL_EDIR_INFO_2 {
LPWSTR	rped2_dirname;
DWORD	rped2_integrity;
DWORD	rped2_extent;
DWORD	rped2_lockcount;
DWORD	rped2_locktime;
} REPL_EDIR_INFO_2, *PREPL_EDIR_INFO_2, *LPREPL_EDIR_INFO_2;

typedef struct _REPL_EDIR_INFO_1000 {
DWORD	rped1000_integrity;
} REPL_EDIR_INFO_1000, *PREPL_EDIR_INFO_1000, *LPREPL_EDIR_INFO_1000;

typedef struct _REPL_EDIR_INFO_1001 {
DWORD	rped1001_extent;
} REPL_EDIR_INFO_1001, *PREPL_EDIR_INFO_1001, *LPREPL_EDIR_INFO_1001;

The replicator export directory functions are:

NetReplExportDirAdd

NetReplExportDirDel

NetReplExportDirEnum

NetReplExportDirGetInfo

NetReplExportDirSetInfo

NetReplExportDirLock

NetReplExportDirUnlock


 Replicator Import Directory Functions

The replicator import directory functions designate the top-level directories under the import path to receive updates on. They also return status information about a replicated directory on the client. On LAN Manager 2.x, a user must create a directory under the import path and the Replicator service automatically replicates to it. On Windows NT, import directories are automatically added if they are exported by an export server from which importer is importing. Another way to register a directory in advance of it being exported, is to use the NetReplImportDirAdd functions. This function does not create the directory itself. This is useful if you wish to modify some of the properties of the import directory (for example, to lock it) prior to it first beginning to import this directory.

NetReplImportDirDel deregisters a directory. This is used to clean up a directory that is no longer being exported. It will not stop replication if there is an active exporter, since it will be re-registered the next time the exporter tells the importer what directories it is exporting. If you wish to prevent importing of an actively exported directory, use the NetReplImportDirLock function.

NetReplImportDirEnum lists all the directories that are replicated to a client, and NetReplImportDirGetInfo returns the status of a specified directory.

The status information of a directory consists of the replication state, the UNC computer name of the master (mastername), and the time (in seconds since 1970, GMT) when the directory was last updated (last_update_time). If the state is REPL_STATE_OK, the directory currently has a master, and is receiving regular update notices from it. If the state is REPL_STATE_NO_MASTER, the directory is not supported by any master, and it is normally empty. If the state is REPL_STATE_NO_SYNC, the directory has a master, but the master has not sent any update notices within the interval time period. This may be due to a communication failure, the master crashing, the directory being locked, files in the client directory being opened at update time, or an unstable REPL_INTEGRITY_TREE integrity directory on the master. If the client Replicator service is not started the state is REPL_STATE_NEVER_REPLICATED, mastername is a NULL string, and last_update_time is 0.NetReplImportDirLock locks a directory so that it does not receive updates, by incrementing a lock reference count for the directory. A lock on a directory can be unlocked using NetReplImportDirUnlock. The directory is not updated unless all outstanding locks on that directory are released, and the lock reference count is returned to 0.

The lock status information is returned in two fields: lockcount and locktime. Lockcount indicates the number of outstanding locks on a directory. Locktime is the time (in seconds since 1970, GMT) when the directory was first locked. (locktime is set to 0 whenever lockcount goes to 0.)

The replicator import directory functions can be called whether the Replicator service is running or not. If the Replicator service is running as a client, directory adds or deletes take effect immediately, and is persistent after the Replicator service has been stopped. If the Replicator service is not started, any added directory will receive updates when the Replicator service starts up (if there exists a master that exports the directory).

The replicator import directory function are available at the following information levels:

typedef struct _REPL_IDIR_INFO_0 {
LPWSTR	rpid0_dirname;
} REPL_IDIR_INFO_0, *PREPL_IDIR_INFO_0, *LPREPL_IDIR_INFO_0;

typedef struct _REPL_IDIR_INFO_1 {
LPWSTR	rpid1_dirname;
DWORD	rpid1_state;
LPWSTR	rpid1_mastername;
DWORD	rpid1_last_update_time;
DWORD	rpid1_lockcount;
DWORD	rpid1_locktime;
} REPL_IDIR_INFO_1, *PREPL_IDIR_INFO_1, *LPREPL_IDIR_INFO_1;

The replicator import directory functions are:

NetReplImportDirAdd

NetReplImportDirDel

NetReplImportDirEnum

NetReplImportDirGetInfo

NetReplImportDirLock


 Schedule Service Functions

Schedule service functions are used to submit and manage jobs to be executed at a given computer at a given time or times in future. Jobs can be commands and programs. Jobs can be managed at remote and local computers provided schedule service is running at a given computer.

Schedule service functions were designed to support old AT command functionality, but they extend this functionality so that new AT command may submit and manage jobs at remote as well as local computers. Schedule service functions are also known as "Job" and "AT command" functions.

Schedule service functions are job submittal (NetScheduleJobAdd), job cancellation (NetScheduleJobDel), job enumeration (NetScheduleJobEnum) and retrieving information about a particular job (NetScheduleJobGetInfo). In order for these functions to succeed, a caller must have administrator's privilege at a computer where Schedule service is running.

Data Structures

AT_INFO data structure is used by NetScheduleJobAdd( ) to specify a job to be added, and by NetScheduleJobGetInfo( ) to return information about an already submitted job. AT_ENUM data structure is used by NetScheduleJobEnum( ) to enumerate and return information about an entire queue of already submitted jobs.

typedef struct _AT_INFO {
DWORD	JobTime;
DWORD	DaysOfMonth;
UCHAR	DaysOfWeek;
UCHAR	Flags;
LPWSTR	Command;
} AT_INFO, *PAT_INFO, *LPAT_INFO;

typedef struct _AT_ENUM {
DWORD	JobId;
DWORD	JobTime;
DWORD	DaysOfMonth;
UCHAR	DaysOfWeek;
UCHAR	Flags;
LPWSTR	Command;
} AT_ENUM, *PAT_ENUM, *LPAT_ENUM;

JobId

Job identifier of an already submitted job.

JobTime

Time of day when a job is scheduled to run. Time is a local time at a computer where Schedule service is running. Time is measured from midnight and is expressed in milliseconds.

DaysOfMonth

Bitmask for days of month when a job is scheduled to run. The bitmask is NULL if a job was scheduled to run only once at the first occurrence of JobTime. For each bit that is set in the bitmask a job will run at JobTime on a corresponding day of the month. Bit 0 corresponds to first day of the month, etc.

DaysOfWeek

Bitmask for days of week when this job is scheduled to run. The bitmask is NULL if a job was scheduled to run only once at the first occurrence of JobTime. For each bit that is set in the bitmask a job will run at JobTime on a corresponding day of the week. Bit 0 corresponds to Monday (first day of the week), etc.

Flags

Bitmask describing job properties. For job submission (NetScheduleJobAdd) possible values are:

JOB_RUN_PERIODICALLY

If this flag bit is set then job runs on every day where corresponding bits in DaysOfMonth or DaysOfWeek are set. If this flag bit is clear then job runs only once for each bit that was set in DaysOfMonth and/or DaysOfWeek at the time of job submission.

JOB_ADD_CURRENT_DATE

When this flag bit is set then job will also execute at the first occurrence of JobTime at the computer where job is submitted to. In other words, setting this flag bit is equivalent to setting the corresponding day bit in DaysOfMonth bitmask.

For job information retrieval (NetScheduleJobEnum and NetScheduleJobGetInfo) possible values are:

JOB_RUN_PERIODICALLY

This flag bit is equal to the original value of this flag bit when a job was submitted.

JOB_EXEC_ERROR

This flag bit is set whenever Schedule service failed to execute successfully this job the last time this job was supposed to run.

JOB_RUNS_TODAY

This flag bit is set if JobId is larger than the current time of day at the computer where this job is queued at.

Command

Points to a Unicode string that contains the name of command, batch program or binary file to execute.

The schedule service functions are:

NetScheduleJobAdd

NetScheduleJobDel

NetScheduleJobEnum

NetScheduleJobGetInfo


Lanman Functions Not Supported in Windows NT
 LAN Manager Functions Not Supported in Windows NT

The following section lists the 16-bit LAN Manager functions that are no longer supported in the Win32 API. In general, the rule we have followed is to not support anything that was marked as obsolete in LAN Manager 2.x. In addition, there are some functions that no longer make sense in Windows NT, and those have been removed as well. Another set of functions has been folded into the Windows NT base or Win32 API.


 Functions with No 32-bit Net Equivalents

•	NetAlertStop, NetAlertStart

•	NetAuditWrite

•	NetBiosClose, NetBiosEnum, NetBiosGetInfo, NetBiosOpen, NetBiosSubmit

•	NetCharDev and NetCharDevQ

•	NetErrorLogWrite

•	NetLogonEnum

•	NetHandleGetInfo levels 2 and 3

•	NetMessageFileSend, NetMessageLogFileGet, NetMessageLogFileSet, NetMessageNameFwd, NetMessageNameUnFwd

•	NetRemoteCopy, NetRemoteExec, NetRemoteMove

•	NetServerAdminCommand

•	NetWkstaSetUID


 Functions That Only Have Support for Remoting to Downlevel

•	NetAccess functions

•	NetAudit functions

•	NetConfig functions

•	NetError functions


Requests from 16-Bit LANMan Clients
 Requests from 16-bit LAN Manager Clients

Windows NT provides support for most remote functions called from downlevel clients. However, the following calls are not supported when remoted from a downlevel client to a Windows NT server. In some of the following, there is a more current "2" version of the function that is supported (such as NetServerEnum).

•	NetFileEnum

•	NetFileGetInfo

•	NetFileClose

•	NetServerAdminCommand

•	NetAuditOpen

•	NetAuditClear

•	NetErrorLogOpen

•	NetErrorLogClear

•	NetMessageNameFwd

•	NetMessageNameUnFwd

•	NetMessageFileSend

•	NetMessageLogFileSet

•	NetMessageLogFileGet

•	NetUserAdd

•	NetUserSetInfo

•	NetWkstaSetUID

•	NetUseEnum

•	NetUseAdd

•	NetUseDel

•	NetUseGetInfo

•	NetProfileSave

•	NetProfileLoad

•	NetStatisticsGet

•	NetStatisticsClear

•	NetNetBiosEnum

•	NetNetBiosGetInfo

•	NetServerEnum

•	NetConfigGet2

•	NetConfigGetAll2

•	NetHandleGetInfo

•	NetHandleSetInfo

•	NetAuditRead

•	NetUserValidate2

•	NetAccessCheck

•	NetAlertRaise

•	NetAlertStart

•	NetAlertStop

•	NetAuditWrite

•	NetServiceStatus

•	DosPrintDriverEnum

•	DosPrintQProcessorEnum

•	DosPrintPortEnum

•	DosPrintDest

•	NetConfigSet


Calling 16-bit LANMan Servers
 Calling 16-bit LAN Manager Servers

When an RPC-based function fails to connect to the appropriate interface, the client-side stub may attempt to initiate a down-level function request to the server selected. For most of the Windows networking functions specified in this document, and any API where the functionality and data formats are changed only for 32-bit usage, the conversion is straightforward. For components that offer new functionality the caller of the function should generally be aware of the destination type. When the new function offers a superset of the functionality of the down-level station the same function is used for both destinations, but the new function fields must have either a reserved value of an associated field to inform the conversion layer the field may be ignored if going downlevel. This is required so that a function caller is not misled as to the action performed when the function was called.


Network Dynamic Data Exchange
Network DDE

The Micrsoft® Win32® application programming interface (API) provides network dynamic data exchange (network DDE) services.


About Network DDE

Dynamic data exchange lets a process establish data conversations with other processes executing on the same computer. Network DDE lets a process establish data conversations with other processes executing on other computers over a network.


Network DDE Reference

The following functions and structures are associated with network dynamic data exchange.


Network DDE Functions

Use these functions to implement network DDE functionality:

NDdeGetErrorString
NDdeGetShareSecurity
NDdeGetTrustedShare
NDdeIsValidAppTopicList
NDdeIsValidShareName
NDdeSetShareSecurity
NDdeSetTrustedShare
NDdeShareAdd
NDdeShareDel
NDdeShareEnum
NDdeShareGetInfo
NDdeShareSetInfo
NDdeTrustedShareEnum


Network DDE Structures

Use this structure to implement network DDE functionality:

NDDESHAREINFO


 Windows Sockets


 Introduction to Windows Sockets


 What is Windows Sockets?

The Windows Sockets documentation defines a network programming interface for Microsoft® Windows® based on the "socket" paradigm popularized in the Berkeley Software Distribution (BSD) from the University of California at Berkeley. It encompasses both familiar Berkeley socket style routines and a set of Windows-specific extensions designed to allow the programmer to take advantage of the message-driven nature of Windows.

The Windows Sockets documentation is intended to provide a single application programming interface (API) to which application developers can program and multiple network software vendors can conform. Furthermore, in the context of a particular version of Microsoft Windows, it defines a binary interface (ABI) such that an application written using the Windows Sockets API can work with a conformant protocol implementation from any network software vendor. This specification thus defines the library calls and associated semantics to which an application developer can program and which a network software vendor can implement.

Network software that conforms to this Windows Sockets specification will be considered "Windows Sockets compliant." Suppliers of interfaces that are Windows Sockets compliant shall be referred to as "Windows Sockets Suppliers." To be Windows Sockets compliant, a vendor must implement 100% of this Windows Sockets specification.

Applications capable of operating with any Windows Sockets-compliant protocol implementation will be considered to have a "Windows Sockets Interface" and will be referred to as "Windows Sockets Applications."

This version of the Windows Sockets specification defines and documents the use of the API in conjunction with the Internet Protocol Suite (IPS, generally referred to as TCP/IP). Specifically, all Windows Sockets implementations support both stream (TCP) and datagram (UDP) sockets.

While the use of this API with alternative protocol stacks is not precluded (and is expected to be the subject of future revisions of the specification), such usage is beyond the scope of this version of the specification.


 Berkeley Sockets

The Windows Sockets Specification has been built on the Berkeley Sockets programming model, which is the de facto standard for TCP/IP networking. It is intended to provide a high degree of familiarity for programmers who are used to programming with sockets in UNIX and other environments, and to simplify the task of porting existing sockets-based source code. The Windows Sockets API is consistent with release 4.3 of the Berkeley Software Distribution (4.3BSD).

Portions of the Windows Sockets specification are derived from material that is Copyright © 1982-1986 by the Regents of the University of California. All rights are reserved. The Berkeley Software License Agreement specifies the terms and conditions for redistribution.


 Microsoft Windows and Windows-Specific Extensions

This API is intended to be usable within all implementations and versions of Microsoft Windows from Microsoft Windows version 3.0 onwards. It thus provides for Windows Sockets implementations and Windows Sockets applications in both 16- and 32-bit operating environments.

Windows Sockets makes provisions for multithreaded Windows processes. A process contains one or more threads of execution. In the Windows 3.1 non-multithreaded world, a task corresponds to a process with a single thread. All references to threads in this document refer to actual "threads" in multithreaded Windows environments. In non-multithreaded environments (such as Windows 3.0), use of the term "thread" refers to a Windows process.

The Microsoft Windows extensions included in Windows Sockets are provided to allow application developers to create software that conforms to the Windows programming model. It is expected that this will facilitate the creation of robust and high-performance applications, and will improve the cooperative multitasking of applications within nonpreemptive versions of Windows. With the exception of WSAStartup and WSACleanup, their use is not mandatory.


 The Status of This Specification

Windows Sockets is an independent specification that was created for the benefit of application developers and network vendors and, indirectly, computer users. Discussion of this documentation and suggested improvements continue and are welcomed. Such discussion occurs mainly via the Internet news group alt.winsock.


 Programming with Sockets


 Windows Sockets Stack Installation Checking

To detect the presence of one (or many) Windows Sockets implementations on a system, an application that has been linked with the Windows Sockets Import Library may simply call the WSAStartup function. A more sophisticated application can examine the $PATH environment variable and search for instances of Windows Sockets implementations (WINSOCK.DLL). For each instance, it can issue a LoadLibrary call and use the WSAStartup function to discover implementation-specific data.

This version of the Windows Sockets specification does not attempt to address explicitly the issue of multiple concurrent Windows Sockets implementations. Nothing in the specification should be interpreted as restricting multiple Windows Sockets DLLs from being present and used concurrently by one or more Windows Sockets applications.

For further details of where to obtain Windows Sockets components, see Windows Sockets Components.


 Sockets

The material in this guide is derived from the document "An Advanced 4.3BSD Interprocess Communication Tutorial," by Samuel J. Leffler, Robert S. Fabry, William N. Joy, Phil Lapsley, Steve Miller, and Chris Torek.


 Socket Basic Concepts

The basic building block for communication is the socket. A socket is an endpoint of communication to which a name can be bound. Each socket in use has a type and an associated process. Sockets exist within communication domains. A communication domain is an abstraction introduced to bundle common properties of threads communicating through sockets. Sockets typically exchange data only with sockets in the same domain (it may be possible to cross domain boundaries, but only if some translation process is performed). The Windows Sockets facilities support a single communication domain: the Internet domain, which is used by processes that communicate using the Internet Protocol Suite. (Future versions of this specification may include additional domains.)

Sockets are typed according to the communication properties visible to a user. Applications are presumed to communicate only between sockets of the same type, although there is nothing that prevents communication between sockets of different types should the underlying communication protocols support this.

Two types of sockets are currently available to a user. A stream socket provides for the bidirectional, reliable, sequenced, and unduplicated flow of data without record boundaries.

A datagram socket supports bidirectional flow of data that is not promised to be sequenced, reliable, or unduplicated. That is, a process receiving messages on a datagram socket may find messages duplicated, and possibly, in an order different from the order in which it was sent. An important characteristic of a datagram socket is that record boundaries in data are preserved. Datagram sockets closely model the facilities found in many contemporary packet-switched networks such as Ethernet.


 Client-Server Model

The paradigm most commonly used in constructing distributed applications is the client-server model. In this scheme, client applications request services from a server application. This implies an asymmetry in establishing communication between the client and server.

The client and server require a well-known set of conventions before service may be rendered (and accepted). These conventions constitute a protocol that must be implemented at both ends of a connection. Depending on the situation, the protocol may be symmetric or asymmetric. In a symmetric protocol, either side may play the master or slave roles. In an asymmetric protocol, one side is immutably recognized as the master, with the other as the slave. An example of a symmetric protocol is the TELNET protocol used in the Internet for remote terminal emulation. An example of an asymmetric protocol is the Internet file transfer protocol, FTP. No matter whether the specific protocol used in obtaining a service is symmetric or asymmetric, when accessing a service there is a "client process" and a "server process."

A server application typically listens at a well-known address for service requests. That is, the server process remains dormant until a connection is requested by a client's connection to the server's address. At such a time, the server process "wakes up" and services the client, performing whatever appropriate actions the client requests of it. While connection-based services are the norm, some services are based on the use of datagram sockets.


 Out-of-Band Data

Note  The following discussion of out-of-band data, also referred to as TCP Urgent data, follows the model used in the Berkeley software distribution. Users and implementors should be aware of the fact that there are at present two conflicting interpretations of RFC 793 (in which the concept is introduced), and that the implementation of out-of-band data in the Berkeley Software Distribution does not conform to the Host Requirements laid down in RFC 1122. To minimize interoperability problems, application developers are advised not to use out-of-band data unless this is required in order to interoperate with an existing service. Windows Sockets suppliers are urged to document the out-of-band semantics (BSD or RFC 1122) that their product implements. It is beyond the scope of this specification to mandate a particular set of semantics for out-of-band data handling.

The stream socket abstraction includes the notion of "out of band" data. Out-of-band data is a logically independent transmission channel associated with each pair of connected stream sockets. Out-of-band data is delivered to the user independently of normal data. The abstraction defines that the out-of-band data facilities must support the reliable delivery of at least one out-of-band message at a time. This message may contain at least one byte of data, and at least one message may be pending delivery to the user at any one time. For communications protocols that support only in-band signaling (that is, the urgent data is delivered in sequence with the normal data), the system typically extracts the data from the normal data stream and stores it separately. This allows users to choose between receiving the urgent data in order and receiving it out of sequence without having to buffer all the intervening data. It is possible to "peek" at out-of-band data.

An application may prefer to process out-of-band data "in-line," as part of the normal data stream. This is achieved by setting the socket option SO_OOBINLINE (see setsockopt). In this case, the application may wish to determine whether any of the unread data is "urgent" (the term usually applied to in-line out-of-band data). To facilitate this, the Windows Sockets implementation will maintain a logical "mark" in the data stream to indicate the point at which the out-of-band data was sent. An application can use the SIOCATMARK ioctlsocket command to determine whether there is any unread data preceding the mark. For example, the application might use this to resynchronize with its peer by ensuring that all data up to the mark in the data stream is discarded when appropriate.

The WSAAsyncSelect function is particularly well suited to handling notification of the presence of out-of-band data.


 Broadcasting

By using a datagram socket, it is possible to send broadcast packets on many networks supported by the system. The network itself must support broadcast: the system provides no simulation of broadcast in software. Broadcast messages can place a high load on a network, since they force every host on the network to service them. Consequently, the ability to send broadcast packets has been limited to sockets that are explicitly marked as allowing broadcasting. Broadcast is typically used for one of two reasons: it is needed to find a resource on a local network without prior knowledge of its address, or important functions such as routing require that information be sent to all accessible neighbors.

The destination address of the message to be broadcast depends on the network(s) on which the message is to be broadcast. The Internet domain supports a shorthand notation for broadcast on the local network, the address INADDR_BROADCAST. Received broadcast messages contain the sender's address and port, because datagram sockets must be bound before use.

Some types of network support the notion of different types of broadcast. For example, the IEEE 802.5 token ring architecture supports the use of link-level broadcast indicators, which control whether broadcasts are forwarded by bridges. The Windows Sockets specification does not provide any mechanism whereby an application can determine the type of underlying network, nor any way to control the semantics of broadcasting.


 Byte Ordering

The Intel byte ordering is like that of the DEC VAX™, and therefore differs from the Internet and 68000-type processor byte ordering. Thus, care must be taken to ensure correct orientation.

Any reference to IP addresses or port numbers passed to or from a Windows Sockets function must be in network order. This includes the IP address and port fields of a struct sockaddr_in (but not the sin_family field).

Consider an application that typically contacts a server on the TCP port corresponding to the "time" service, but provides a mechanism for the user to specify that an alternative port is to be used. The port number returned by getservbyname is already in network order, which is the format required when constructing an address, so no translation is required. However, if the user elects to use a different port, entered as an integer, the application must convert this from host order to network order (using the htons function) before using it to construct an address. Conversely, if the application is to display the number of the port within an address (returned using, for example, getpeername), the port number must be converted from network order to host order (using ntohs) before it can be displayed.

Since the Intel and Internet byte orders are different, the conversions described preceding are unavoidable. Application writers are cautioned that they should use the standard conversion functions provided as part of the Windows Sockets API rather than writing their own conversion code, since future implementations of Windows Sockets are likely to run on systems for which the host order is identical to the network byte order. Only applications that use the standard conversion functions are likely to be portable.


 Socket Options

The socket options supported by Windows Sockets are listed in setsockopt and getsockopt. A Windows Sockets implementation must recognize all of these options, and (for getsockopt) return plausible values for each. The default value for each option is shown in the following table.

Value	Type	Meaning	Default	Note
SO_ACCEPTCONN	BOOL	Socket is in listen mode.	FALSE unless a listen has been performed
SO_BROADCAST	BOOL	Socket is configured for the transmission of broadcast messages.	FALSE
SO_DEBUG	BOOL	Debugging is enabled.	FALSE	(i)
SO_DONTLINGER	BOOL	If true, the SO_LINGER option is disabled.	TRUE
SO_DONTROUTE	BOOL	Routing is disabled.	FALSE	(i)
SO_ERROR	int	Retrieve error status and clear.	0
SO_KEEPALIVE	BOOL	Keepalive messages are being sent.	FALSE
SO_LINGER	struct linger FAR *	Returns the current linger options.	l_onoff is 0
SO_OOBINLINE	BOOL	Out-of-band data is being received in the normal data stream.	FALSE
SO_RCVBUF	int	Buffer size for recv operations.	Implementation dependent	(i)
SO_REUSEADDR	BOOL	The address to which this socket is bound can be used by others.	FALSE
SO_SNDBUF	int	Buffer size for send operations.	Implementation dependent	(i)
SO_TYPE	int	The type of the socket (for example, SOCK_STREAM).	As created using socket
TCP_NODELAY	BOOL	Disables the Nagle algorithm for send coalescing.	Implementation dependent
Notes:

(i)  An implementation may silently ignore this option on setsockopt and return a constant value for getsockopt, or it may accept a value for setsockopt and return the corresponding value in getsockopt without using the value in any way.


 Database Files

The getXbyY and WSAAsyncGetXByY classes of routines are provided for retrieving network-specific information. (This specification uses the function name getXbyY to represent the set of routines gethostbyaddr, gethostbyname, and so on. Similarly WSAAsyncGetXByY represents WSAAsyncGetHostByAddr, and so on.) The getXbyY routines were originally designed (in the first Berkeley UNIX releases) as mechanisms for looking up information in text databases. Although the information may be retrieved by the Windows Sockets implementation in different ways, a Windows Sockets application requests such information in a consistent manner through either the getXbyY or the WSAAsyncGetXByY class of routines.


 Deviation from Berkeley Sockets

There are a few limited instances in which the Windows Sockets API has had to divert from strict adherence to the Berkeley conventions, usually because of difficulties of implementation in a Windows environment.


 Socket Data Type and Error Values

A new data type, SOCKET, has been defined. The definition of this type was necessary for future enhancements to the Windows Sockets specification, such as being able to use sockets as file handles in Windows NT. Definition of this type also facilitates porting applications to a Win32 environment, because the type will automatically be promoted from 16 to 32 bits.

In UNIX, all handles, including socket handles, are small, non-negative integers, and some applications make assumptions that this will be true. Windows Sockets handles have no restrictions, other than that the value INVALID_SOCKET is not a valid socket. Socket handles may take any value in the range 0 to INVALID_SOCKET − 1.

Because the SOCKET type is unsigned, compiling existing source code from, for example, a UNIX environment may lead to compiler warnings about signed/unsigned data type mismatches.

This means, for example, that checking for errors when the socket and accept routines return should not be done by comparing the return value with  − 1, or seeing if the value is negative (both approaches are common and legal in BSD). Instead, an application should use the manifest constant INVALID_SOCKET as defined in WINSOCK.H. For example:

TYPICAL BSD STYLE:

s = socket(...);

if (s == -1)    /* or s < 0 */

    {...}

PREFERRED STYLE:

s = socket(...);

if (s == INVALID_SOCKET)

    {...}


select and FD_*
 select and FD_XXX

Because a SOCKET is no longer represented by the UNIX-style "small non-negative integer," the implementation of the select function was changed in the Windows Sockets API. Each set of sockets is still represented by the fd_set type, but instead of being stored as a bitmask the set is implemented as an array of SOCKETs. To avoid potential problems, applications must adhere to the use of the FD_XXX macros to set, initialize, clear, and check the fd_set structures.


 Error Codes - errno, h_errno & WSAGetLastError

Error codes set by the Windows Sockets implementation are not made available via the errno variable. Additionally, for the getXbyY class of functions, error codes are NOT made available via the h_errno variable. Instead, error codes are accessed by using the WSAGetLastError . This function is provided in Windows Sockets as a precursor (and eventually an alias) for the Win32 function GetLastError. This is intended to provide a reliable way for a thread in a multithreaded process to obtain per-thread error information.

For compatibility with BSD, an application may choose to include a line of the form:

#define errno WSAGetLastError

This will allow networking code that was written to use the global errno to work correctly in a single-threaded environment. There are, obviously, some drawbacks. If a source file includes code that inspects errno for both socket and nonsocket functions, this mechanism cannot be used. Furthermore, it is not possible for an application to assign a new value to errno. (In Windows Sockets the function WSASetLastError can be used for this purpose.)

TYPICAL BSD STYLE:

r = recv(...);

if (r == -1

 && errno == EWOULDBLOCK)

    {...}

PREFERRED STYLE:

r = recv(...);

if (r == -1 /* (but see below) */

 && WSAGetLastError == EWOULDBLOCK)

    {...}

Although error constants consistent with 4.3 Berkeley Sockets are provided for compatibility purposes, applications should, where possible, use the "WSA" error code definitions. For example, a more accurate version of the preceding source code fragment is:

r = recv(...);

if (r == -1 /* (but see below) */

 && WSAGetLastError == WSAEWOULDBLOCK)

    {...}


 Pointers

All pointers used by applications with Windows Sockets should be FAR. To facilitate this, data type definitions such as LPHOSTENT are provided.


 Renamed Functions

In two cases it was necessary to rename functions that are used in Berkeley Sockets to avoid clashes with other functions.

close & closesocket

In Berkeley Sockets, sockets are represented by standard file descriptors, and so the close function can be used to close sockets as well as regular files. While nothing in Windows Sockets prevents an implementation from using regular file handles to identify sockets, nothing requires it either. Socket descriptors are not presumed to correspond to regular file handles, and file operations such as read, write, and close cannot be assumed to work correctly when applied to sockets. Sockets must be closed by using the closesocket function. Using the close function to close a socket is incorrect and the effects of doing so are undefined by this specification.

ioctl & ioctlsocket

Various C-language run-time systems use the ioctl function for purposes unrelated to Windows Sockets. For this reason we have defined the function ioctlsocket, which is used to handle socket functions that in the Berkeley Software Distribution are performed using ioctl and fcntl.


Blocking routines & EINPROGRESS
 Blocking Routines and EINPROGRESS

Although blocking operations on sockets are supported under Windows Sockets, their use is strongly discouraged. Programmers who are constrained to use blocking mode — for example, as part of an existing application that is to be ported — should be aware of the semantics of blocking operations in Windows Sockets. For more details, see Blocking/Nonblocking and Data Volatility.


 Maximum Number of Sockets Supported

The maximum number of sockets supported by a particular Windows Sockets supplier is implementation specific. An application should make no assumptions about the availability of a certain number of sockets. This topic is addressed further in WSAStartup. However, the number of sockets supported by a particular implementation is independent of the issue of the maximum number of sockets an application can actually make use of.

The maximum number of sockets a Windows Sockets application can make use of is determined at compile time by the manifest constant FD_SETSIZE. This value is used in constructing the fd_set structures used in select. The default value in WINSOCK.H is 64. If an application is designed to be capable of working with more than 64 sockets, the implementor should define the manifest FD_SETSIZE in every source file before including WINSOCK.H. One way of doing this is to include the definition within the compiler options in the makefile, for example adding -DFD_SETSIZE=128 as an option to the compiler command line for Microsoft C. It must be emphasized that defining FD_SETSIZE as a particular value has no effect on the actual number of sockets provided by a Windows Sockets implementation.


 Include Files

For ease of portability of existing Berkeley sockets based source code, a number of standard Berkeley include files are supported. However, these Berkeley header files merely include the WINSOCK.H include file, and it is therefore sufficient (and recommended) that Windows Sockets application source files should simply include WINSOCK.H.


 Return Values on Function Failure

The manifest constant SOCKET_ERROR is provided for checking function failure. Although use of this constant is not mandatory, it is recommended. The following example illustrates the use of the SOCKET_ERROR constant:

TYPICAL BSD STYLE:

r = recv(...);

if (r == -1     /* or r < 0 */

 && errno == EWOULDBLOCK)

    {...}

PREFERRED STYLE:

r = recv(...);

if (r == SOCKET_ERROR && WSAGetLastError == WSAEWOULDBLOCK)

    {...}


 Raw Sockets

The Windows Sockets specification does not mandate that a Windows Sockets DLL support raw sockets, that is, sockets opened with SOCK_RAW. However, a Windows Sockets DLL is allowed and encouraged to supply raw socket support. A Windows Sockets-compliant application that needs to use raw sockets should attempt to open the socket with the socket call, and if it fails either attempt to use another socket type or indicate the failure to the user.


 Windows Sockets in Multithreaded Versions of Windows

The Windows Sockets interface is designed to work for both single-threaded versions of Windows (such as Windows 3.1) and preemptive multithreaded versions of Windows (such as Windows NT). In a multithreaded environment the sockets interface is basically the same, but the author of a multithreaded application must be aware that it is the responsibility of the application, not the Windows Sockets implementation, to synchronize access to a socket between threads. This is the same rule that applies to other forms of I/O such as file I/O. Failure to synchronize calls on a socket leads to unpredictable results; for example if there are two simultaneous calls to send, there is no guarantee as to the order in which the data will be sent.

Closing a socket in one thread that has an outstanding blocking call on the same socket in another thread will cause the blocking call to fail with WSAEINTR, just as if the operation were canceled. This also applies if there is a select call outstanding and the application closes one of the sockets being selected.

There is no default blocking hook installed in preemptive multithreaded versions of Windows. This is because the computer will not be blocked if a single application is waiting for an operation to complete and hence not calling PeekMessage or GetMessage, which cause the application to yield in nonpreemptive Windows. However, for backwards compatibility, the WSASetBlockingHook call is implemented in multithreaded versions of Windows, and applications whose behavior depends on the default blocking hook can install their own blocking hook that duplicates the default hook's semantics.


 Socket Functions

In each routine it is indicated that the header file WINSOCK.H must be included. The Berkeley-compatible header files that are supported are provided for compatibility purposes only, and each of them will simply include WINSOCK.H. The Windows header file WINDOWS.H is also needed, but WINSOCK.H will include it if necessary.

The Windows Sockets specification includes the following Berkeley-style socket functions:

accept*	An incoming connection is acknowledged and associated with an immediately created socket. The original socket is returned to the listening state.
bind	Assign a local name to an unnamed socket.
closesocket*	Remove a socket from the per-process object reference table. Only blocks if SO_LINGER is set.
connect*	Initiate a connection on the specified socket.
getpeername	Retrieve the name of the peer connected to the specified socket.
getsockname	Retrieve the current name for the specified socket
getsockopt	Retrieve options associated with the specified socket.
htonl	Convert a 32-bit quantity from host byte order to network byte order.
htons	Convert a 16-bit quantity from host byte order to network byte order.
inet_addr	Converts a character string representing a number in the Internet standard "." notation to an Internet address value.
inet_ntoa	Converts an Internet address value to an ASCII string in "." notation (for example, "a.b.c.d").
ioctlsocket	Provide control for sockets.
listen	Listen for incoming connections on a specified socket.
ntohl	Convert a 32-bit quantity from network byte order to host byte order.
ntohs	Convert a 16-bit quantity from network byte order to host byte order.
recv*	Receive data from a connected socket.
recvfrom*	Receive data from either a connected or unconnected socket.
select*	Perform synchronous I/O multiplexing.
send*	Send data to a connected socket.
sendto*	Send data to either a connected or unconnected socket.
setsockopt	Store options associated with the specified socket.
shutdown	Shut down part of a full-duplex connection.
socket	Create an endpoint for communication and return a socket.
* The function can block if acting on a blocking socket.


 Blocking/Nonblocking and Data Volatility

One major issue in porting applications from a Berkeley sockets environment to a Windows environment involves "blocking"; that is, invoking a function that does not return until the associated operation is completed. The problem arises if the operation takes an arbitrarily long time to complete: an obvious example is a recv that may block until data has been received from the peer system. The default behavior within the Berkeley sockets model is for a socket to operate in a blocking mode unless the programmer explicitly requests that operations be treated as nonblocking.

Note  It is strongly recommended that programmers use the nonblocking (asynchronous) operations if at all possible, because they work significantly better within the nonpreemptive Windows environment. Use blocking operations only if absolutely necessary, and carefully read and understand this topic if you must use blocking operations.

Even on a blocking socket, some operations (for example, bind, getsockopt, getpeername) can be completed immediately. For such operations there is no difference between blocking and nonblocking operation. Other operations (for example, recv) may be completed immediately or may take an arbitrary time to complete, depending on various transport conditions. When applied to a blocking socket, these operations are referred to as blocking operations. All functions that can block are listed with an asterisk in the tables in Socket Functions and Socket Database Functions.

Within a Windows Sockets implementation, a blocking operation that cannot be completed immediately is handled as follows. The DLL initiates the operation, and then enters a loop in which it dispatches any Windows messages (yielding the processor to another thread if necessary) and then checks for the completion of the Windows Sockets function. If the function has completed, or if WSACancelBlockingCall has been invoked, the blocking function completes with an appropriate result. Refer to WSASetBlockingHook for a complete description of this mechanism, including pseudocode for the various functions.

If a Windows message is received for a process for which a blocking operation is in progress, there is a risk that the application will attempt to issue another Windows Sockets call. Because of the difficulty of managing this condition safely, the Windows Sockets specification does not support such application behavior. Two functions are provided to assist you in this situation. WSAIsBlocking may be called to determine whether or not a blocking Windows Sockets call is in progress. WSACancelBlockingCall may be called to cancel an in-progress blocking call, if any. Any other Windows Sockets function that is called in this situation will fail with the error WSAEINPROGRESS. It should be emphasized that this restriction applies to both blocking and nonblocking operations.

Although this mechanism is sufficient for simple applications, it cannot support the complex message-dispatching requirements of more advanced applications (for example, those using the MDI model). For such applications, Windows Sockets includes the function WSASetBlockingHook, which allows the programmer to define a special function that will be called instead of the default message dispatch function previously described.

The Windows Sockets DLL calls the blocking hook only if all of the following are true: the function is one that is defined as being able to block, the specified socket is a blocking socket, and the request cannot be completed immediately. (A socket is set to blocking by default, but the IOCTL FIONBIO and WSAAsyncSelect both set a socket to nonblocking mode.) If an application uses only nonblocking sockets and uses the WSAAsyncSelect and/or the WSAAsyncGetXByY routines instead of select and the getXbyY routines, then the blocking hook will never be called and the application does not need to handle reentrancy.

If an application invokes an asynchronous or nonblocking operation that takes a pointer to a memory object (for example, a buffer, or a global variable) as an argument, the application must ensure that the object is available to the Windows Sockets implementation throughout the operation. The application must not invoke any Windows function that might affect the mapping or addressability of the memory involved. In a multithreaded system, the application is also responsible for coordinating access to the object using appropriate synchronization mechanisms. A Windows Sockets implementation cannot, and will not, address these issues. The possible consequences of failing to observe these rules are beyond the scope of this specification.


 Socket Database Functions

The Windows Sockets specification defines the following database functions. As noted earlier, a Windows Sockets supplier may choose to implement these in a manner that does not depend on local database files. The pointer returned by certain database functions such as gethostbyname points to a structure allocated by the Windows Sockets library. The data pointed to is volatile and is good only until the next Windows Sockets function call from that thread. Additionally, the application must never attempt to modify this structure or to free any of its components. Only one copy of this structure is allocated for a thread, and so the application should copy any information it needs before issuing any other Windows Sockets function calls.

gethostbyaddr*	Retrieves the name(s) and address corresponding to a network address.
gethostbyname*	Retrieves the name(s) and address corresponding to a host name.
gethostname	Retrieves the name of the local host.
getprotobyname*	Retrieves the protocol name and number corresponding to a protocol name.
getprotobynumber*	Retrieves the protocol name and number corresponding to a protocol number.
getservbyname*	Retrieves the service name and port corresponding to a service name.
getservbyport*	Retrieves the service name and port corresponding to a port.
* The function can block under some circumstances.


 Microsoft Windows-Specific Extension Functions

Windows Sockets provides a number of extensions to the standard set of Berkeley Sockets functions. Principally, these extended functions allow message-based, asynchronous access to network events. While use of this extended function set is not mandatory for socket-based programming (with the exception of WSAStartup and WSACleanup), it is recommended for conformance with the Microsoft Windows programming paradigm.

The following functions provide asynchronous versions of the standard Berkeley getXbyY functions. For example, the WSAAsyncGetHostByName function provides an asynchronous message-based implementation of the standard Berkeley gethostbyname function.

WSAAsyncGetHostByAddr

WSAAsyncGetHostByName

WSAAsyncGetProtoByName

WSAAsyncGetProtoByNumber

WSAAsyncGetServByName

WSAAsyncGetServByPort

WSAAsyncSelect	Performs asynchronous version of select.
WSACancelAsyncRequest	Cancels an outstanding instance of a WSAAsyncGetXByY function.
WSACancelBlockingCall	Cancels an outstanding "blocking" function call.
WSACleanup	Signs off from the underlying Windows Sockets DLL.
WSAGetLastError	Obtains details of last Windows Sockets function error.
WSAIsBlocking	Determines if the underlying Windows Sockets DLL is already blocking an existing call for this thread.
WSASetBlockingHook	"Hooks" the blocking method used by the underlying Windows Sockets implementation.
WSASetLastError	Sets the error to be returned by a subsequent call to WSAGetLastError.
WSAStartup	Initializes the underlying Windows Sockets DLL.
WSAUnhookBlockingHook	Restores the original blocking function.


 Asynchronous Select Mechanism

The WSAAsyncSelect function allows an application to register an interest in one or many network events. This function is provided to supersede the need to do polled network I/O. Any situation in which select or nonblocking I/O routines (such as send and recv) are either already used or are being considered is usually a candidate for the WSAAsyncSelect function. When declaring interest in such condition(s), you supply a window handle to be used for notification. The corresponding window then receives message-based notification of the conditions in which you declared an interest.

WSAAsyncSelect allows interest to be declared in the following conditions for a particular socket:

•	Socket readiness for reading

•	Socket readiness for writing

•	Out-of-band data ready for reading

•	Socket readiness for accepting incoming connection

•	Completion of nonblocking connect operation

•	Connection closure


 Asynchronous Support Routines

The asynchronous "database" functions allow applications to request information in an asynchronous manner. Some network implementations or configurations perform network-based operations to resolve such requests. The WSAAsyncGetXByY functions allow application developers to request services that would otherwise block the operation of the whole Windows environment if the standard Berkeley function were used. The WSACancelAsyncRequest function allows an application to cancel any outstanding asynchronous request.


 Hooking Blocking Methods

As noted in Blocking/Nonblocking and Data Volatility, Windows Sockets implements blocking operations in such a way that Windows message processing can continue, which may result in the application that issued the call receiving a Windows message. In certain situations, an application may need to influence or change the way in which this pseudo-blocking process is implemented. The WSASetBlockingHook function provides the ability to substitute a named function that the Windows Sockets implementation is to use when relinquishing the processor during a "blocking" operation.


 Error Handling

For compatibility with thread-based environments, details of function errors are obtained through the WSAGetLastError function. Although the accepted Berkeley-style mechanism for obtaining socket-based network errors is by using errno, this mechanism cannot guarantee the integrity of an error ID in a multithreaded environment. WSAGetLastError allows you to retrieve an error code on a per-thread basis.

WSAGetLastError returns error codes that avoid conflict with standard Microsoft C error codes. Certain error codes returned by certain Windows Sockets routines fall into the standard range of error codes as defined by Microsoft C. If you are NOT using an application development environment that defines error codes consistent with Microsoft C, you should use the Windows Sockets error codes prefixed by "WSA" to ensure accurate error code detection.

Note that this specification defines a recommended set of error codes, and lists the possible errors that may be returned as a result of each function. It may be the case in some implementations that other Windows Sockets error codes will be returned in addition to those listed, and applications should be prepared to handle errors other than those enumerated under each function description. However, a Windows Sockets implementation must not return any value that is not enumerated in the table of legal Windows Sockets errors given in Error Codes.


Accessing a Windows Sockets DLL from an Intermediate DLL
 Accessing a Windows Sockets DLL from an Intermediate DLL (16-bit Applications)

A Windows Sockets DLL can be accessed both directly from an application and through an "intermediate" DLL. An example of such an intermediate DLL would be a virtual network API layer that supports generalized network functionality for applications and uses Windows Sockets. Such a DLL could be used by several applications simultaneously, and the DLL must take special precautions with respect to the WSAStartup and WSACleanup calls to ensure that these routines are called in the context of each task that will make Windows Sockets calls. This is because the Windows Sockets DLL will need a call to WSAStartup for each task in order to set up task-specific data structures, and a call to WSACleanup to free any resources allocated for the task.

There are (at least) two ways to accomplish this. The simplest method is for the intermediate DLL to have calls similar to WSAStartup and WSACleanup that applications call as appropriate. The DLL would then call WSAStartup or WSACleanup from within these routines. Another mechanism is for the intermediate DLL to build a table of task handles, which are obtained from the GetCurrentTask Windows function, and at each entry point into the intermediate DLL check whether WSAStartup has been called for the current task, then call WSAStartup if necessary.

If a DLL makes a blocking call and does not install its own blocking hook, then the DLL author must be aware that control may be returned to the application either by an application-installed blocking hook or by the default blocking hook. Thus, it is possible that the application will cancel the DLL's blocking operation via WSACancelBlockingCall. If this occurs, the DLL's blocking operation will fail with the error code WSAEINTR, and the DLL must return control to the calling task as quickly as possible, because the user has likely pressed a Cancel or Close button and the task has requested control of the CPU. It is recommended that DLLs that make blocking calls install their own blocking hooks with WSASetBlockingHook to prevent unforeseen interactions between the application and the DLL.

Note that this is not necessary for DLLs in Windows NT because of its different process and DLL structure. Under Windows NT, the intermediate DLL could simply call WSAStartup in its DLL initialization routine, which is called whenever a new process which uses the DLL starts.


 Internal Use of Messages by Windows Sockets Implementations

To implement Windows Sockets purely as a DLL, it may be necessary for the DLL to post messages internally for communication and timing. This is perfectly legal; however, a Windows Sockets DLL must not post messages to a window handle opened by a client application except for those messages requested by the application. A Windows Sockets DLL that needs to use messages for its own purposes must open a hidden window and post any necessary messages to the handle for that window.


 Private API Interfaces

The WINSOCK.DEF file in DLL Ordinal Numbers lists the ordinals defined for the Windows Sockets functions. In addition to the ordinal values listed, all ordinals 999 and below are reserved for future Windows Sockets use. It may be convenient for a Windows Sockets implementation to export additional, private interfaces from the Windows Sockets DLL. This is perfectly acceptable, as long as the ordinals for these exports are above 1000. Note that any application that uses a particular Windows Sockets DLL's private functions will most likely not work on any other vendor's Windows Sockets implementation. Only the functions defined in this document are guaranteed to be present in every Windows Sockets implementation.

If an application uses private interfaces of a particular vendor's Windows Sockets DLL, it is recommended that the DLL not be statically linked with the application but rather dynamically loaded with the Windows routines LoadLibrary and GetProcAddress. This allows the application to give an informative error message if it is run on a system with a Windows Sockets DLL that does not support the same set of extended functionality.


 Error Codes and Header Files

The following topics list the error codes and header files.

Error Codes

Header Files


 Error Codes

The following is a list of possible error codes returned by the WSAGetLastError function, along with their explanations. The error numbers are consistently set across all Windows Sockets-compliant implementations.

Windows Sockets code	Berkeley equivalent	Error	Interpretation
WSAEINTR	EINTR	10004	As in standard C
WSAEBADF	EBADF	10009	As in standard C
WSAEACCES	EACCES	10013	As in standard C
WSAEDISCON	None	10101	The message terminated gracefully. Used only for message-oriented protocols.
WSAEFAULT	EFAULT	10014	As in standard C
WSAEINVAL	EINVAL	10022	As in standard C
WSAEMFILE	EMFILE	10024	As in standard C
WSAEWOULDBLOCK	EWOULDBLOCK	10035	As in BSD
WSAEINPROGRESS	EINPROGRESS	10036	This error is returned if anyWindows Sockets function is called while a blocking function is in progress.
WSAEALREADY	EALREADY	10037	As in BSD
WSAENOTSOCK	ENOTSOCK	10038	As in BSD
WSAEDESTADDRREQ	EDESTADDRREQ	10039	As in BSD
WSAEMSGSIZE	EMSGSIZE	10040	As in BSD
WSAEPROTOTYPE	EPROTOTYPE	10041	As in BSD
WSAENOPROTOOPT	ENOPROTOOPT	10042	As in BSD
WSAEPROTONOSUPPORT	EPROTONOSUPPORT	10043	As in BSD
WSAESOCKTNOSUPPORT	ESOCKTNOSUPPORT	10044	As in BSD
WSAEOPNOTSUPP	EOPNOTSUPP	10045	As in BSD
WSAEPFNOSUPPORT	EPFNOSUPPORT	10046	As in BSD
WSAEAFNOSUPPORT	EAFNOSUPPORT	10047	As in BSD
WSAEADDRINUSE	EADDRINUSE	10048	As in BSD
WSAEADDRNOTAVAIL	EADDRNOTAVAIL	10049	As in BSD
WSAENETDOWN	ENETDOWN	10050	As in BSD. This error may be reported at any time if the Windows Sockets implementation detects an underlying failure.
WSAENETUNREACH	ENETUNREACH	10051	As in BSD
WSAENETRESET	ENETRESET	10052	As in BSD
WSAECONNABORTED	ECONNABORTED	10053	As in BSD
WSAECONNRESET	ECONNRESET	10054	As in BSD
WSAENOBUFS	ENOBUFS	10055	As in BSD
WSAEISCONN	EISCONN	10056	As in BSD
WSAENOTCONN	ENOTCONN	10057	As in BSD
WSAESHUTDOWN	ESHUTDOWN	10058	As in BSD
WSAETOOMANYREFS	ETOOMANYREFS	10059	As in BSD
WSAETIMEDOUT	ETIMEDOUT	10060	As in BSD
WSAECONNREFUSED	ECONNREFUSED	10061	As in BSD
WSAELOOP	ELOOP	10062	As in BSD
WSAENAMETOOLONG	ENAMETOOLONG	10063	As in BSD
WSAEHOSTDOWN	EHOSTDOWN	10064	As in BSD
WSAEHOSTUNREACH	EHOSTUNREACH	10065	As in BSD
WSASYSNOTREADY	None	10091	Returned by WSAStartup, indicating that the network subsystem is unusable.
WSAVERNOTSUPPORTED	None	10092	Returned by WSAStartup, indicating that the Windows Sockets DLL cannot support this app.
WSANOTINITIALISED	None	10093	Returned by any function except WSAStartup, indicating that a successful WSAStartup, has not yet been performed.
WSAHOST_NOT_FOUND	HOST_NOT_FOUND	11001	As in BSD
WSATRY_AGAIN	TRY_AGAIN	11002	As in BSD
WSANO_RECOVERY	NO_RECOVERY	11003	As in BSD
WSANO_DATA	NO_DATA	11004	As in BSD
The first set of definitions is present to resolve contentions between standard C error codes, which may be defined inconsistently between various C compilers.

The second set of definitions provides Windows Sockets versions of regular Berkeley Sockets error codes.

The third set of definitions consists of extended Windows Sockets-specific error codes.

The fourth set of errors are returned by Windows Sockets getXbyY and WSAAsyncGetXByY functions, and correspond to the errors that in Berkeley software would be returned in the h_errno variable. They correspond to various failures that may be returned by the Domain Name Service. If the Windows Sockets implementation does not use the DNS, it will use the most appropriate code. In general, a Windows Sockets application should interpret WSAHOST_NOT_FOUND and WSANO_DATA as indicating that the key (name, address, and so on) was not found, while WSATRY_AGAIN and WSANO_RECOVERY suggest that the name service itself is nonoperational.

The error numbers are derived from the WINSOCK.H header file and are based on the fact that Windows Sockets error numbers are computed by adding 10000 to the "normal" Berkeley error number.

Note that this table does not include all of the error codes defined in WINSOCK.H. This is because it includes only errors that might reasonably be returned by a Windows Sockets implementation. WINSOCK.H, on the other hand, includes a full set of BSD definitions to ensure compatibility with ported software.


 Header Files


 Berkeley Header Files

A Windows Sockets supplier who provides a development kit to support the development of Windows Sockets applications must supply a set of vestigial header files with names that match a number of the header files in the Berkeley software distribution. These files are provided for source code compatibility only, and each consists of three lines:

#ifndef _WINSOCKAPI_

#include <winsock.h>

#endif

The header files provided for compatibility are:

NETDB.H
ARPA/INET.H
SYS/TIME.H
SYS/SOCKET.H
NETINET/IN.H

The file WINSOCK.H contains all of the type and structure definitions, constants, macros, and function prototypes used by the Windows Sockets specification. You may choose to ignore the compatibility headers and include WINSOCK.H in each source file.


Windows Sockets Header File - winsock.h
 Windows Sockets Header File — WINSOCK.H

The WINSOCK.H header file includes a number of types and definitions from the standard Windows header file WINDOWS.H. The WINDOWS.H file in the Windows 3.0 SDK (Software Developer's Kit) lacks a #include guard, so if you need to include WINDOWS.H as well as WINSOCK.H, you should define the symbol _INC_WINDOWS before #including WINSOCK.H, as follows:

#include <windows.h>

#define _INC_WINDOWS

#include <winsock.h>

Users of the SDK for Windows 3.1 and later need not do this.

A Windows Sockets DLL vendor must not make any modifications to this header file that could impact binary compatibility of Windows Sockets applications. The constant values, function parameters, return codes, and the like must remain consistent across all Windows Sockets DLL vendors.

/* WINSOCK.H--definitions to be used with the WINSOCK.DLL

 *

 * This header file corresponds to version 1.1 of the Windows Sockets specification.

 *

 * This file includes parts which are Copyright (c) 1982-1986 Regents

 * of the University of California. All rights reserved. The

 * Berkeley Software License Agreement specifies the terms and

 * conditions for redistribution.

 */

#ifndef _WINSOCKAPI_

#define _WINSOCKAPI_

/*

 * Pull in WINDOWS.H if necessary

 */

#ifndef _INC_WINDOWS

#include <windows.h>

#endif /* _INC_WINDOWS */

/*

 * Basic system type definitions, taken from the BSD file sys/types.h.

 */

typedef unsigned char u_char;

typedef unsigned short u_short;

typedef unsigned int u_int;

typedef unsigned long u_long;

/*

 * The new type to be used in all

 * instances which refer to sockets.

 */

typedef u_int  SOCKET;

/*

 * Select uses arrays of SOCKETs. These macros manipulate such

 * arrays. FD_SETSIZE may be defined by the user before including

 * this file, but the default here should be >= 64.

 *

 * CAVEAT IMPLEMENTOR and USER: THESE MACROS AND TYPES MUST BE

 * INCLUDED IN WINSOCK.H EXACTLY AS SHOWN HERE.

 */

#ifndef FD_SETSIZE

#define FD_SETSIZE 64

#endif /* FD_SETSIZE */

typedef struct fd_set {

 u_short fd_count;  /* how many are SET? */

 SOCKET fd_array[FD_SETSIZE]; /* an array of SOCKETs */

} fd_set;

extern int PASCAL FAR __WSAFDIsSet(SOCKET, fd_set FAR *);

#define FD_CLR(fd, set) do { \

 u_int __i; \

 for (__i = 0; __i < ((fd_set FAR *)(set))->fd_count ; __i++) { \

 if (((fd_set FAR *)(set))->fd_array[__i] == fd) { \

  while (__i < ((fd_set FAR *)(set))->fd_count-1) { \

  ((fd_set FAR *)(set))->fd_array[__i] = \

   ((fd_set FAR *)(set))->fd_array[__i+1]; \

  __i++; \

  } \

  ((fd_set FAR *)(set))->fd_count--; \

  break; \

 } \

 } \

} while(0)

#define FD_SET(fd, set) do { \

 if (((fd_set FAR *)(set))->fd_count < FD_SETSIZE) \

 ((fd_set FAR *)(set))->fd_array[((fd_set FAR *)(set))->fd_count++]=fd;\

} while(0)

#define FD_ZERO(set) (((fd_set FAR *)(set))->fd_count=0)

#define FD_ISSET(fd, set) __WSAFDIsSet((SOCKET)fd, (fd_set FAR *)set)

/*

 * Structure used in select call, taken from the BSD file sys/time.h.

 */

struct timeval {

 long tv_sec;  /* seconds */

 long tv_usec; /* and microseconds */

};

/*

 * Operations on timevals.

 *

 * NB: timercmp does not work for >= or <=.

 */

#define timerisset(tvp)  ((tvp)->tv_sec || (tvp)->tv_usec)

#define timercmp(tvp, uvp, cmp) \

 ((tvp)->tv_sec cmp (uvp)->tv_sec || \

  (tvp)->tv_sec == (uvp)->tv_sec && (tvp)->tv_usec cmp (uvp)->tv_usec)

#define timerclear(tvp)  (tvp)->tv_sec = (tvp)->tv_usec = 0

/*

 * Commands for ioctlsocket, taken from the BSD file fcntl.h.

 *

 *

 * Ioctl's have the command encoded in the lower word,

 * and the size of any in or out parameters in the upper

 * word. The high 2 bits of the upper word are used

 * to encode the in/out status of the parameter; for now

 * we restrict parameters to at most 128 bytes.

 */

#define IOCPARM_MASK 0x7f  /* parameters must be < 128 bytes */

#define IOC_VOID 0x20000000 /* no parameters */

#define IOC_OUT  0x40000000 /* copy out parameters */

#define IOC_IN  0x80000000 /* copy in parameters */

#define IOC_INOUT (IOC_IN|IOC_OUT)

     /* 0x20000000 distinguishes new &

      old ioctl's */

#define _IO(x,y) (IOC_VOID|(x<<8)|y)

#define _IOR(x,y,t) (IOC_OUT|(((long)sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y)

#define _IOW(x,y,t) (IOC_IN|(((long)sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y)

#define FIONREAD _IOR('f', 127, u_long) /* get # bytes to read */

#define FIONBIO _IOW('f', 126, u_long) /* set/clear non-blocking i/o */

#define FIOASYNC _IOW('f', 125, u_long) /* set/clear async i/o */

/* Socket I/O Controls */

#define SIOCSHIWAT _IOW('s', 0, u_long) /* set high watermark */

#define SIOCGHIWAT _IOR('s', 1, u_long) /* get high watermark */

#define SIOCSLOWAT _IOW('s', 2, u_long) /* set low watermark  */

#define SIOCGLOWAT _IOR('s', 3, u_long) /* get low watermark  */

#define SIOCATMARK _IOR('s', 7, u_long) /* at oob mark?       */

/*

 * Structures returned by network database library, taken from the

 * BSD file netdb.h. All addresses are supplied in host order, and

 * returned in network order (suitable for use in system calls).

 */

struct hostent {

 char FAR * h_name;            /* official name of host        */

 char FAR * FAR * h_aliases;   /* alias list                   */

 short h_addrtype;             /* host address type            */

 short h_length;               /* length of address            */

 char FAR * FAR * h_addr_list; /* list of addresses            */

#define h_addr h_addr_list[0]  /* address, for backward compat */

};

/*

 * It is assumed here that a network number

 * fits in 32 bits.

 */

struct netent {

 char FAR * n_name;  /* official name of net */

 char FAR * FAR * n_aliases; /* alias list */

 short n_addrtype;  /* net address type */

 u_long n_net;   /* network # */

};

struct servent {

 char FAR * s_name;  /* official service name */

 char FAR * FAR * s_aliases; /* alias list */

 short s_port;   /* port # */

 char FAR * s_proto;  /* protocol to use */

};

struct protoent {

 char FAR * p_name;  /* official protocol name */

 char FAR * FAR * p_aliases; /* alias list */

 short p_proto;  /* protocol # */

};

/*

 * Constants and structures defined by the Internet system,

 * Per RFC 790, September 1981, taken from the BSD file netinet/in.h.

 */

/*

 * Protocols

 */

#define IPPROTO_IP  0  /* dummy for IP */

#define IPPROTO_ICMP  1  /* control message protocol */

#define IPPROTO_GGP  2  /* gateway^2 (deprecated) */

#define IPPROTO_TCP  6  /* tcp */

#define IPPROTO_PUP  12  /* pup */

#define IPPROTO_UDP  17  /* user datagram protocol */

#define IPPROTO_IDP  22  /* xns idp */

#define IPPROTO_ND  77  /* UNOFFICIAL net disk proto */

#define IPPROTO_RAW  255  /* raw IP packet */

#define IPPROTO_MAX  256

/*

 * Port/socket numbers: network standard functions

 */

#define IPPORT_ECHO  7

#define IPPORT_DISCARD  9

#define IPPORT_SYSTAT  11

#define IPPORT_DAYTIME  13

#define IPPORT_NETSTAT  15

#define IPPORT_FTP  21

#define IPPORT_TELNET  23

#define IPPORT_SMTP  25

#define IPPORT_TIMESERVER 37

#define IPPORT_NAMESERVER 42

#define IPPORT_WHOIS  43

#define IPPORT_MTP  57

/*

 * Port/socket numbers: host specific functions

 */

#define IPPORT_TFTP  69

#define IPPORT_RJE  77

#define IPPORT_FINGER  79

#define IPPORT_TTYLINK  87

#define IPPORT_SUPDUP  95

/*

 * UNIX TCP sockets

 */

#define IPPORT_EXECSERVER 512

#define IPPORT_LOGINSERVER 513

#define IPPORT_CMDSERVER 514

#define IPPORT_EFSSERVER 520

/*

 * UNIX UDP sockets

 */

#define IPPORT_BIFFUDP  512

#define IPPORT_WHOSERVER 513

#define IPPORT_ROUTESERVER 520

     /* 520+1 also used */

/*

 * Ports < IPPORT_RESERVED are reserved for

 * privileged processes (e.g. root).

 */

#define IPPORT_RESERVED  1024

/*

 * Link numbers

 */

#define IMPLINK_IP  155

#define IMPLINK_LOWEXPER 156

#define IMPLINK_HIGHEXPER 158

/*

 * Internet address (old style... should be updated)

 */

struct in_addr {

 union {

  struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;

  struct { u_short s_w1,s_w2; } S_un_w;

  u_long S_addr;

 } S_un;

#define s_addr S_un.S_addr

    /* can be used for most tcp & ip code */

#define s_host S_un.S_un_b.s_b2

    /* host on imp */

#define s_net S_un.S_un_b.s_b1

    /* network */

#define s_imp S_un.S_un_w.s_w2

    /* imp */

#define s_impno S_un.S_un_b.s_b4

    /* imp # */

#define s_lh S_un.S_un_b.s_b3

    /* logical host */

};

/*

 * Definitions of bits in internet address integers.

 * On subnets, the decomposition of addresses to host and net parts

 * is done according to subnet mask, not the masks here.

 */

#define IN_CLASSA(i)  (((long)(i) & 0x80000000) == 0)

#define IN_CLASSA_NET  0xff000000

#define IN_CLASSA_NSHIFT 24

#define IN_CLASSA_HOST  0x00ffffff

#define IN_CLASSA_MAX  128

#define IN_CLASSB(i)  (((long)(i) & 0xc0000000) == 0x80000000)

#define IN_CLASSB_NET  0xffff0000

#define IN_CLASSB_NSHIFT 16

#define IN_CLASSB_HOST  0x0000ffff

#define IN_CLASSB_MAX  65536

#define IN_CLASSC(i)  (((long)(i) & 0xc0000000) == 0xc0000000)

#define IN_CLASSC_NET  0xffffff00

#define IN_CLASSC_NSHIFT 8

#define IN_CLASSC_HOST  0x000000ff

#define INADDR_ANY  (u_long)0x00000000

#define INADDR_LOOPBACK  0x7f000001

#define INADDR_BROADCAST (u_long)0xffffffff

#define INADDR_NONE  0xffffffff

/*

 * Socket address, internet style.

 */

struct sockaddr_in {

 short sin_family;

 u_short sin_port;

 struct in_addr sin_addr;

 char sin_zero[8];

};

#define WSADESCRIPTION_LEN 256

#define WSASYS_STATUS_LEN 128

typedef struct WSAData {

 WORD   wVersion;

 WORD   wHighVersion;

 char   szDescription[WSADESCRIPTION_LEN+1];

 char   szSystemStatus[WSASYS_STATUS_LEN+1];

 unsigned short  iMaxSockets;

 unsigned short  iMaxUdpDg;

 char FAR *  lpVendorInfo;

} WSADATA;

typedef WSADATA FAR *LPWSADATA;

/*

 * Options for use with [gs]etsockopt at the IP level.

 */

#define IP_OPTIONS 1  /* set/get IP per-packet options */

/*

 * Definitions related to sockets: types, address families, options,

 * taken from the BSD file sys/socket.h.

 */

/*

 * This is used instead of -1, since the

 * SOCKET type is unsigned.

 */

#define INVALID_SOCKET (SOCKET)(~0)

#define SOCKET_ERROR  (-1)

/*

 * Types

 */

#define SOCK_STREAM 1  /* stream socket */

#define SOCK_DGRAM 2  /* datagram socket */

#define SOCK_RAW 3  /* raw-protocol interface */

#define SOCK_RDM 4  /* reliably-delivered message */

#define SOCK_SEQPACKET 5  /* sequenced packet stream */

/*

 * Option flags per-socket.

 */

#define SO_DEBUG 0x0001  /* turn on debugging info recording */

#define SO_ACCEPTCONN 0x0002  /* socket has had listen */

#define SO_REUSEADDR 0x0004  /* allow local address reuse */

#define SO_KEEPALIVE 0x0008  /* keep connections alive */

#define SO_DONTROUTE 0x0010  /* just use interface addresses */

#define SO_BROADCAST 0x0020  /* permit sending of broadcast msgs */

#define SO_USELOOPBACK 0x0040  /* bypass hardware when possible */

#define SO_LINGER 0x0080  /* linger on close if data present */

#define SO_OOBINLINE 0x0100  /* leave received OOB data in line */

#define SO_DONTLINGER (u_int)(~SO_LINGER)

/*

 * Additional options.

 */

#define SO_SNDBUF 0x1001  /* send buffer size */

#define SO_RCVBUF 0x1002  /* receive buffer size */

#define SO_SNDLOWAT 0x1003  /* send low-water mark */

#define SO_RCVLOWAT 0x1004  /* receive low-water mark */

#define SO_SNDTIMEO 0x1005  /* send timeout */

#define SO_RCVTIMEO 0x1006  /* receive timeout */

#define SO_ERROR 0x1007  /* get error status and clear */

#define SO_TYPE  0x1008  /* get socket type */

/*

 * TCP options.

 */

#define TCP_NODELAY 0x0001

/*

 * Address families.

 */

#define AF_UNSPEC 0  /* unspecified */

#define AF_UNIX  1  /* local to host (pipes, portals) */

#define AF_INET  2  /* internetwork: UDP, TCP, etc. */

#define AF_IMPLINK 3  /* arpanet imp addresses */

#define AF_PUP  4  /* pup protocols: e.g. BSP */

#define AF_CHAOS 5  /* mit CHAOS protocols */

#define AF_NS  6  /* XEROX NS protocols */

#define AF_ISO  7  /* ISO protocols */

#define AF_OSI  AF_ISO  /* OSI is ISO */

#define AF_ECMA  8  /* european computer manufacturers */

#define AF_DATAKIT 9  /* datakit protocols */

#define AF_CCITT 10  /* CCITT protocols, X.25 etc */

#define AF_SNA  11  /* IBM SNA */

#define AF_DECnet 12  /* DECnet */

#define AF_DLI  13  /* Direct data link interface */

#define AF_LAT  14  /* LAT */

#define AF_HYLINK 15  /* NSC Hyperchannel */

#define AF_APPLETALK 16  /* AppleTalk */

#define AF_NETBIOS 17  /* NetBios-style addresses */

#define AF_MAX  18

/*

 * Structure used by kernel to store most

 * addresses.

 */

struct sockaddr {

 u_short sa_family;  /* address family */

 char sa_data[14];  /* up to 14 bytes of direct address */

};

/*

 * Structure used by kernel to pass protocol

 * information in raw sockets.

 */

struct sockproto {

 u_short sp_family;  /* address family */

 u_short sp_protocol;  /* protocol */

};

/*

 * Protocol families, same as address families for now.

 */

#define PF_UNSPEC AF_UNSPEC

#define PF_UNIX  AF_UNIX

#define PF_INET  AF_INET

#define PF_IMPLINK AF_IMPLINK

#define PF_PUP  AF_PUP

#define PF_CHAOS AF_CHAOS

#define PF_NS  AF_NS

#define PF_ISO  AF_ISO

#define PF_OSI  AF_OSI

#define PF_ECMA  AF_ECMA

#define PF_DATAKIT AF_DATAKIT

#define PF_CCITT AF_CCITT

#define PF_SNA  AF_SNA

#define PF_DECnet AF_DECnet

#define PF_DLI  AF_DLI

#define PF_LAT  AF_LAT

#define PF_HYLINK AF_HYLINK

#define PF_APPLETALK AF_APPLETALK

#define PF_MAX  AF_MAX

/*

 * Structure used for manipulating linger option.

 */

struct linger {

 u_short l_onoff;  /* option on/off */

 u_short l_linger;  /* linger time */

};

/*

 * Level number for (get/set)sockopt to apply to socket itself.

 */

#define SOL_SOCKET 0xffff  /* options for socket level */

/*

 * Maximum queue length specifiable by listen.

 */

#define SOMAXCONN 5

#define MSG_OOB  0x1  /* process out-of-band data */

#define MSG_PEEK 0x2  /* peek at incoming message */

#define MSG_DONTROUTE 0x4  /* send without using routing tables */

#define MSG_MAXIOVLEN 16

/*

 * Define constant based on rfc883, used by gethostbyxxxx calls.

 */

#define MAXGETHOSTSTRUCT 1024

/*

 * Define flags to be used with the WSAAsyncSelect call.

 */

#define FD_READ  0x01

#define FD_WRITE 0x02

#define FD_OOB  0x04

#define FD_ACCEPT 0x08

#define FD_CONNECT 0x10

#define FD_CLOSE 0x20

/*

 * All Windows Sockets error constants are biased by WSABASEERR from

 * the "normal"

 */

#define WSABASEERR  10000

/*

 * Windows Sockets definitions of regular Microsoft C error constants

 */

#define WSAEINTR  (WSABASEERR+4)

#define WSAEBADF  (WSABASEERR+9)

#define WSAEACCES  (WSABASEERR+13)

#define WSAEFAULT  (WSABASEERR+14)

#define WSAEINVAL  (WSABASEERR+22)

#define WSAEMFILE  (WSABASEERR+24)

/*

 * Windows Sockets definitions of regular Berkeley error constants

 */

#define WSAEWOULDBLOCK  (WSABASEERR+35)

#define WSAEINPROGRESS  (WSABASEERR+36)

#define WSAEALREADY  (WSABASEERR+37)

#define WSAENOTSOCK  (WSABASEERR+38)

#define WSAEDESTADDRREQ  (WSABASEERR+39)

#define WSAEMSGSIZE  (WSABASEERR+40)

#define WSAEPROTOTYPE  (WSABASEERR+41)

#define WSAENOPROTOOPT  (WSABASEERR+42)

#define WSAEPROTONOSUPPORT (WSABASEERR+43)

#define WSAESOCKTNOSUPPORT (WSABASEERR+44)

#define WSAEOPNOTSUPP  (WSABASEERR+45)

#define WSAEPFNOSUPPORT  (WSABASEERR+46)

#define WSAEAFNOSUPPORT  (WSABASEERR+47)

#define WSAEADDRINUSE  (WSABASEERR+48)

#define WSAEADDRNOTAVAIL (WSABASEERR+49)

#define WSAENETDOWN  (WSABASEERR+50)

#define WSAENETUNREACH  (WSABASEERR+51)

#define WSAENETRESET  (WSABASEERR+52)

#define WSAECONNABORTED  (WSABASEERR+53)

#define WSAECONNRESET  (WSABASEERR+54)

#define WSAENOBUFS  (WSABASEERR+55)

#define WSAEISCONN  (WSABASEERR+56)

#define WSAENOTCONN  (WSABASEERR+57)

#define WSAESHUTDOWN  (WSABASEERR+58)

#define WSAETOOMANYREFS  (WSABASEERR+59)

#define WSAETIMEDOUT  (WSABASEERR+60)

#define WSAECONNREFUSED  (WSABASEERR+61)

#define WSAELOOP  (WSABASEERR+62)

#define WSAENAMETOOLONG  (WSABASEERR+63)

#define WSAEHOSTDOWN  (WSABASEERR+64)

#define WSAEHOSTUNREACH  (WSABASEERR+65)

#define WSAENOTEMPTY  (WSABASEERR+66)

#define WSAEPROCLIM  (WSABASEERR+67)

#define WSAEUSERS  (WSABASEERR+68)

#define WSAEDQUOT  (WSABASEERR+69)

#define WSAESTALE  (WSABASEERR+70)

#define WSAEREMOTE  (WSABASEERR+71)

/*

 * Extended Windows Sockets error constant definitions

 */

#define WSASYSNOTREADY  (WSABASEERR+91)

#define WSAVERNOTSUPPORTED (WSABASEERR+92)

#define WSANOTINITIALISED (WSABASEERR+93)

/*

 * Error return codes from gethostbyname and gethostbyaddr

 * (when using the resolver). Note that these errors are

 * retrieved via WSAGetLastError and must therefore follow

 * the rules for avoiding clashes with error numbers from

 * specific implementations or language run-time systems.

 * For this reason the codes are based at WSABASEERR+1001.

 * Note also that [WSA]NO_ADDRESS is defined only for

 * compatibility purposes.

 */

#define h_errno  WSAGetLastError

/* Authoritative Answer: Host not found */

#define WSAHOST_NOT_FOUND (WSABASEERR+1001)

#define HOST_NOT_FOUND  WSAHOST_NOT_FOUND

/* Non-Authoritative: Host not found, or SERVERFAIL */

#define WSATRY_AGAIN  (WSABASEERR+1002)

#define TRY_AGAIN  WSATRY_AGAIN

/* Non recoverable errors, FORMERR, REFUSED, NOTIMP */

#define WSANO_RECOVERY  (WSABASEERR+1003)

#define NO_RECOVERY  WSANO_RECOVERY

/* Valid name, no data record of requested type */

#define WSANO_DATA  (WSABASEERR+1004)

#define NO_DATA   WSANO_DATA

/* no address, look for MX record */

#define WSANO_ADDRESS  WSANO_DATA

#define NO_ADDRESS  WSANO_ADDRESS

/*

 * Windows Sockets errors redefined as regular Berkeley error constants

 */

#define EWOULDBLOCK  WSAEWOULDBLOCK

#define EINPROGRESS  WSAEINPROGRESS

#define EALREADY  WSAEALREADY

#define ENOTSOCK  WSAENOTSOCK

#define EDESTADDRREQ  WSAEDESTADDRREQ

#define EMSGSIZE  WSAEMSGSIZE

#define EPROTOTYPE  WSAEPROTOTYPE

#define ENOPROTOOPT  WSAENOPROTOOPT

#define EPROTONOSUPPORT  WSAEPROTONOSUPPORT

#define ESOCKTNOSUPPORT  WSAESOCKTNOSUPPORT

#define EOPNOTSUPP  WSAEOPNOTSUPP

#define EPFNOSUPPORT  WSAEPFNOSUPPORT

#define EAFNOSUPPORT  WSAEAFNOSUPPORT

#define EADDRINUSE  WSAEADDRINUSE

#define EADDRNOTAVAIL  WSAEADDRNOTAVAIL

#define ENETDOWN  WSAENETDOWN

#define ENETUNREACH  WSAENETUNREACH

#define ENETRESET  WSAENETRESET

#define ECONNABORTED  WSAECONNABORTED

#define ECONNRESET  WSAECONNRESET

#define ENOBUFS   WSAENOBUFS

#define EISCONN   WSAEISCONN

#define ENOTCONN  WSAENOTCONN

#define ESHUTDOWN  WSAESHUTDOWN

#define ETOOMANYREFS  WSAETOOMANYREFS

#define ETIMEDOUT  WSAETIMEDOUT

#define ECONNREFUSED  WSAECONNREFUSED

#define ELOOP   WSAELOOP

#define ENAMETOOLONG  WSAENAMETOOLONG

#define EHOSTDOWN  WSAEHOSTDOWN

#define EHOSTUNREACH  WSAEHOSTUNREACH

#define ENOTEMPTY  WSAENOTEMPTY

#define EPROCLIM  WSAEPROCLIM

#define EUSERS   WSAEUSERS

#define EDQUOT   WSAEDQUOT

#define ESTALE   WSAESTALE

#define EREMOTE   WSAEREMOTE

/* Socket function prototypes */

#ifdef __cplusplus

extern "C" {

#endif

SOCKET PASCAL FAR accept (SOCKET s, struct sockaddr FAR *addr,

    int FAR *addrlen);

int PASCAL FAR bind (SOCKET s, const struct sockaddr FAR *addr, int namelen);

int PASCAL FAR closesocket (SOCKET s);

int PASCAL FAR connect (SOCKET s, const struct sockaddr FAR *name, int namelen);

int PASCAL FAR ioctlsocket (SOCKET s, long cmd, u_long FAR *argp);

int PASCAL FAR getpeername (SOCKET s, struct sockaddr FAR *name,

    int FAR * namelen);

int PASCAL FAR getsockname (SOCKET s, struct sockaddr FAR *name,

    int FAR * namelen);

int PASCAL FAR getsockopt (SOCKET s, int level, int optname,

    char FAR * optval, int FAR *optlen);

u_long PASCAL FAR htonl (u_long hostlong);

u_short PASCAL FAR htons (u_short hostshort);

unsigned long PASCAL FAR inet_addr (const char FAR * cp);

char FAR * PASCAL FAR inet_ntoa (struct in_addr in);

int PASCAL FAR listen (SOCKET s, int backlog);

u_long PASCAL FAR ntohl (u_long netlong);

u_short PASCAL FAR ntohs (u_short netshort);

int PASCAL FAR recv (SOCKET s, char FAR * buf, int len, int flags);

int PASCAL FAR recvfrom (SOCKET s, char FAR * buf, int len, int flags,

    struct sockaddr FAR *from, int FAR * fromlen);

int PASCAL FAR select (int nfds, fd_set FAR *readfds, fd_set FAR *writefds,

   fd_set FAR *exceptfds, const struct timeval FAR *timeout);

int PASCAL FAR send (SOCKET s, const char FAR * buf, int len, int flags);

int PASCAL FAR sendto (SOCKET s, const char FAR * buf, int len, int flags,

   const struct sockaddr FAR *to, int tolen);

int PASCAL FAR setsockopt (SOCKET s, int level, int optname,

    const char FAR * optval, int optlen);

int PASCAL FAR shutdown (SOCKET s, int how);

SOCKET PASCAL FAR socket (int af, int type, int protocol);

/* Database function prototypes */

struct hostent FAR * PASCAL FAR gethostbyaddr(const char FAR * addr,

      int len, int type);

struct hostent FAR * PASCAL FAR gethostbyname(const char FAR * name);

int PASCAL FAR gethostname (char FAR * name, int namelen);

struct servent FAR * PASCAL FAR getservbyport(int port, const char FAR * proto);

struct servent FAR * PASCAL FAR getservbyname(const char FAR * name,

      const char FAR * proto);

struct protoent FAR * PASCAL FAR getprotobynumber(int proto);

struct protoent FAR * PASCAL FAR getprotobyname(const char FAR * name);

/* Microsoft Windows Extension function prototypes */

int PASCAL FAR WSAStartup(WORD wVersionRequired, LPWSADATA lpWSAData);

int PASCAL FAR WSACleanup(void);

void PASCAL FAR WSASetLastError(int iError);

int PASCAL FAR WSAGetLastError(void);

BOOL PASCAL FAR WSAIsBlocking(void);

int PASCAL FAR WSAUnhookBlockingHook(void);

FARPROC PASCAL FAR WSASetBlockingHook(FARPROC lpBlockFunc);

int PASCAL FAR WSACancelBlockingCall(void);

HANDLE PASCAL FAR WSAAsyncGetServByName(HWND hWnd, u_int wMsg,

     const char FAR * name,

     const char FAR * proto,

     char FAR * buf, int buflen);

HANDLE PASCAL FAR WSAAsyncGetServByPort(HWND hWnd, u_int wMsg, int port,

     const char FAR * proto, char FAR * buf,

     int buflen);

HANDLE PASCAL FAR WSAAsyncGetProtoByName(HWND hWnd, u_int wMsg,

      const char FAR * name, char FAR * buf,

      int buflen);

HANDLE PASCAL FAR WSAAsyncGetProtoByNumber(HWND hWnd, u_int wMsg,

      int number, char FAR * buf,

      int buflen);

HANDLE PASCAL FAR WSAAsyncGetHostByName(HWND hWnd, u_int wMsg,

     const char FAR * name, char FAR * buf,

     int buflen);

HANDLE PASCAL FAR WSAAsyncGetHostByAddr(HWND hWnd, u_int wMsg,

     const char FAR * addr, int len, int type,

     const char FAR * buf, int buflen);

int PASCAL FAR WSACancelAsyncRequest(HANDLE hAsyncTaskHandle);

int PASCAL FAR WSAAsyncSelect(SOCKET s, HWND hWnd, u_int wMsg,

    long lEvent);

#ifdef __cplusplus

}

#endif

/* Microsoft Windows Extended data types */

typedef struct sockaddr SOCKADDR;

typedef struct sockaddr *PSOCKADDR;

typedef struct sockaddr FAR *LPSOCKADDR;

typedef struct sockaddr_in SOCKADDR_IN;

typedef struct sockaddr_in *PSOCKADDR_IN;

typedef struct sockaddr_in FAR *LPSOCKADDR_IN;

typedef struct linger LINGER;

typedef struct linger *PLINGER;

typedef struct linger FAR *LPLINGER;

typedef struct in_addr IN_ADDR;

typedef struct in_addr *PIN_ADDR;

typedef struct in_addr FAR *LPIN_ADDR;

typedef struct fd_set FD_SET;

typedef struct fd_set *PFD_SET;

typedef struct fd_set FAR *LPFD_SET;

typedef struct hostent HOSTENT;

typedef struct hostent *PHOSTENT;

typedef struct hostent FAR *LPHOSTENT;

typedef struct servent SERVENT;

typedef struct servent *PSERVENT;

typedef struct servent FAR *LPSERVENT;

typedef struct protoent PROTOENT;

typedef struct protoent *PPROTOENT;

typedef struct protoent FAR *LPPROTOENT;

typedef struct timeval TIMEVAL;

typedef struct timeval *PTIMEVAL;

typedef struct timeval FAR *LPTIMEVAL;

/*

 * Windows message parameter composition and decomposition

 * macros.

 *

 * WSAMAKEASYNCREPLY is intended for use by the Windows Sockets implementation

 * when constructing the response to a WSAAsyncGetXByY routine.

 */

#define WSAMAKEASYNCREPLY(buflen,error) MAKELONG(buflen,error)

/*

 * WSAMAKESELECTREPLY is intended for use by the Windows Sockets implementation

 * when constructing the response to WSAAsyncSelect.

 */

#define WSAMAKESELECTREPLY(event,error) MAKELONG(event,error)

/*

 * WSAGETASYNCBUFLEN is intended for use by the Windows Sockets application

 * to extract the buffer length from the lParam in the response

 * to a WSAGetXByY.

 */

#define WSAGETASYNCBUFLEN(lParam)  LOWORD(lParam)

/*

 * WSAGETASYNCERROR is intended for use by the Windows Sockets application

 * to extract the error code from the lParam in the response

 * to a WSAGetXByY.

 */

#define WSAGETASYNCERROR(lParam)  HIWORD(lParam)

/*

 * WSAGETSELECTEVENT is intended for use by the Windows Sockets application

 * to extract the event code from the lParam in the response

 * to a WSAAsyncSelect.

 */

#define WSAGETSELECTEVENT(lParam)  LOWORD(lParam)

/*

 * WSAGETSELECTERROR is intended for use by the Windows Sockets application

 * to extract the error code from the lParam in the response

 * to a WSAAsyncSelect.

 */

#define WSAGETSELECTERROR(lParam)  HIWORD(lParam)

#endif /* _WINSOCKAPI_ */


 Notes for Windows Sockets Suppliers


 Introduction to Notes for Windows Sockets Suppliers

A WINSOCK.DLL or WINSOCK32.DLL must implement ALL the functionality described in the Windows Sockets documentation.

Windows Sockets version 1.1 implementations must support both TCP and UDP type sockets. An implementation may support raw sockets (of type SOCK_RAW), but their use is deprecated.

Certain functions documented in this Help file have special notes for Windows Sockets implementors. A Windows Sockets implementation shoul conform to the function as documented. The special notes are provided for assistance and clarification.


 Windows Sockets Components


 Development Components

The Windows Sockets development components for use by Windows Sockets application developers will be provided by each Windows Sockets supplier. These Windows Sockets development components are:

Component	Description
Windows Sockets Documentation	This document
WINSOCK.LIB file	Windows Sockets API Import Library
WINSOCK.H file	Windows Sockets Header File
NETDB.H file	Berkeley Compatible Header File
ARPA/INET.H file	Berkeley Compatible Header File
SYS/TIME.H file	Berkeley Compatible Header File
SYS/SOCKET.H file	Berkeley Compatible Header File
NETINET/IN.H file	Berkeley Compatible Header File
Run-Time Components

The run-time component provided by each Windows Sockets supplier is:

Component	Description
WINSOCK.DLL	The Windows Sockets API implementation DLL


 Multithreadedness and Blocking Routines

Data areas returned by, for example, the functions in the getXbyY family (gethostbyaddr, and so on) MUST be on a per-thread basis.

Note that an application must be prevented from making multiple nested Windows Sockets function calls. Only one outstanding function call will be allowed for a particular task. Any Windows Sockets call performed when an existing blocking call is already outstanding will fail with an error code of WSAEINPROGRESS. There are two exceptions to this restriction: WSACancelBlockingCall and WSAIsBlocking may be called at any time. Windows Sockets suppliers should note that although preliminary drafts of this specification indicated that the restriction only applied to blocking function calls, and that it would be permissible to make nonblocking calls while a blocking call was in progress, this is no longer true.

Regarding the implementation of blocking routines, the solution in Windows Sockets is to simulate the blocking mechanism by having each routine call PeekMessage as it waits for the completion of its operation. In anticipation of this, the function WSASetBlockingHook is provided to allow you to define a special routine to be called instead of the default PeekMessage loop.


 Database Files Implementation

The database routines in the getXbyY family (gethostbyaddr, and so on.) were originally designed (in the first Berkeley UNIX releases) as mechanisms for looking up information in text databases. A Windows Sockets supplier may choose to employ local files OR a name service to provide some or all of this information. If local files exist, the format of the files must be identical to that used in BSD UNIX, allowing for the differences in text file formats.


 FD_ISSET

It is necessary to implement the FD_ISSET Berkeley macro using a supporting function: __WSAFDIsSet. It is the responsibility of a Windows Sockets implementation to make this available as part of the Windows Sockets API. Unlike the other functions exported by a Windows Sockets DLL, however, this function is not intended to be invoked directly by Windows Sockets applications: It should be used only to support the FD_ISSET macro. The source code for this function is:

int FAR

__WSAFDIsSet(SOCKET fd, fd_set FAR *set)

{

    int i = set->fd_count;

    while (i--)

        if (set->fd_array[i] == fd)

            return 1;

    return 0;

}


 Error Codes Returned by WSAGetLastError

To avoid conflict between various compiler environments, Windows Sockets implementations MUST return the error codes listed in the API specification, using the manifest constants beginning with "WSA". The Berkeley-compatible error code definitions are provided solely for compatibility purposes for applications being ported from other platforms.


 DLL Ordinal Numbers

The WINSOCK.DEF file for use by every Windows Sockets implementation is as follows. Ordinal values starting at 1000 are reserved for Windows Sockets implementors to use for exporting private interfaces to their DLLs. A Windows Sockets implementation must not use any ordinals 999 and below except for those functions listed following. An application that is to work with any Windows Sockets DLL must use only those routines listed follwoing; using a private export makes an application dependent on a particular Windows Sockets implementation.

;

;  File: winsock.def

; System: MS-Windows 3.x

; Summary: Module definition file for Windows Sockets DLL.

;

LIBRARY  WINSOCK  ; Application's module name

DESCRIPTION 'BSD Socket API for Windows'

EXETYPE  WINDOWS  ; required for all windows applications

STUB  'WINSTUB.EXE' ; generates error message if application

    ; is run without Windows

;CODE can be FIXED in memory because of potential upcalls

CODE  PRELOAD  FIXED

;DATA must be SINGLE and at a FIXED location since this is a DLL

DATA  PRELOAD  FIXED  SINGLE

HEAPSIZE 1024

STACKSIZE 16384

; All functions that will be called by any Windows routine

; must be exported. Any additional exports beyond those defined

; here must have ordinal numbers 1000 or above.

EXPORTS

 accept    @1

 bind    @2

 closesocket   @3

 connect   @4

 getpeername   @5

 getsockname   @6

 getsockopt   @7

 htonl    @8

 htons    @9

 inet_addr   @10

 inet_ntoa   @11

 ioctlsocket   @12

 listen    @13

 ntohl    @14

 ntohs    @15

 recv    @16

 recvfrom   @17

 select    @18

 send    @19

 sendto    @20

 setsockopt   @21

 shutdown   @22

 socket    @23

 gethostbyaddr   @51

 gethostbyname   @52

 getprotobyname   @53

 getprotobynumber  @54

 getservbyname   @55

 getservbyport   @56

 gethostname   @57

 WSAAsyncSelect   @101

 WSAAsyncGetHostByAddr  @102

 WSAAsyncGetHostByName  @103

 WSAAsyncGetProtoByNumber @104

 WSAAsyncGetProtoByName  @105

 WSAAsyncGetServByPort  @106

 WSAAsyncGetServByName  @107

 WSACancelAsyncRequest  @108

 WSASetBlockingHook  @109

 WSAUnhookBlockingHook  @110

 WSAGetLastError  @111

 WSASetLastError  @112

 WSACancelBlockingCall  @113

 WSAIsBlocking   @114

 WSAStartup   @115

 WSACleanup   @116

 __WSAFDIsSet   @151

 WEP    @500 RESIDENTNAME

;eof


 Validation Suite

The Windows Sockets API Tester (WSAT) to ensure Windows Sockets compatibility between Windows Sockets DLL implementations is currently in beta test. This beta version includes functionality testing of the Windows Sockets interface and is supported by a comprehensive scripting language. The final version of WSAT will be available in Spring 1993. If you wish to receive the tester or more information on the beta, send email to wsat@microsoft.com.


 For Further Reference

This documentation is intended to cover the Windows Sockets interface to TCP/IP in detail. Many details of TCP/IP and Windows, however, are intentionally omitted in the interest of brevity, and this specification often assumes background knowledge of these topics. For more information, the following references may be helpful:

Braden, R.[1989], RFC 1122, Requirements for Internet Hosts — Communication Layers, Internet Engineering Task Force.

Comer, D. [1991], Internetworking with TCP/IP Volume I: Principles, Protocols, and Architecture, Prentice Hall, Englewood Cliffs, New Jersey.

Comer, D. and Stevens, D. [1991], Internetworking with TCP/IP Volume II: Design, Implementation, and Internals, Prentice Hall, Englewood Cliffs, New Jersey.

Comer, D. and Stevens, D. [1991], Internetworking with TCP/IP Volume III: Client-Server Programming and Applications, Prentice Hall, Englewood Cliffs, New Jersey.

Leffler, S. et al., An Advanced 4.3BSD Interprocess Communication Tutorial.

Petzold, C. [1992], Programming Windows 3.1, Microsoft Press, Redmond, Washington.

Stevens, W.R. [1990], Unix Network Programming, Prentice Hall, Englewood Cliffs, New Jersey.


 Background Information


 Legal Status of Windows Sockets

The copyright for the Windows Sockets specification is owned by the specification authors listed on the title page. Permission is granted to redistribute this specification in any form, provided that the contents of the specification are not modified. Windows Sockets implementors are encouraged to include this specification with their product documentation.

The Windows Sockets logo on the title page of this document is meant for use on both Windows Sockets implementations and for applications that use the Windows Sockets interface. Use of the logo is encouraged on packaging, documentation, collateral, and advertising. The logo is available on microdyne.com in pub/winsock as WINSOCK.BMP. The suggested color for the logo's title bar is blue, the electrical socket grey, and the text and outline black.

UNIX is a trademark of Unix System Laboratories, Inc.

VAX is a trademark of Digital Equipment Corporation.

Windows is a trademark of Microsoft Corporation

68000 is a trademark of Motorola, Inc.

NT and Windows/NT are trademarks of Microsoft Corporation.


 Windows Sockets for Windows NT

Microsoft® Windows NT™ fully supports the Windows Sockets functions as defined in the Win32 SDK (Software Development Kit). However, Windows NT has some additional features available through its Windows Sockets interface that are not described in the Windows Sockets specification. This document describes the extended features of the Windows Sockets interface in Windows NT, a superset of the Windows Sockets functionality.

Some of the features described in this document were not implemented in the initial release of Windows NT but are available in Windows NT version 3.5. The most notable new features are the SO_SNDTIMEO, SO_RCVTIMEO, and SO_OPENTYPE socket options and support for NetBIOS providers.


 Support for 32-bit Applications

Included with the Windows NT release disks is the WINSOCK.DLL file, which provides the functions necessary for 16-bit applications to use Windows Sockets through 16-bit subsystem of Windows NT. Win32-based applications use a different DLL, WSOCK32.DLL, which exports routines that take exclusively 32-bit arguments.

The 32-bit versions of the Windows Sockets functions take all the same parameters, with the notable exception that all int and SOCKET parameters are widened from 16 bits to 32 bits. This widening is of no concern if you are writing applications to be portable between 16-bit and 32-bit environments, since the compiler performs the necessary steps automatically.


 Windows NT Socket Handles

From a developer's standpoint, perhaps the most notable aspect of the Windows Sockets support in Windows NT is that the handles returned from the socket and accept functions are native Windows NT system handles that have been opened, by default, as "asynchronous" or "overlapped" handles. This allows an application to use the handles as arguments to system routines in addition to the Windows Sockets routines and also to share the handles between threads and processes.


 Sharing Sockets Between Threads

Because a handle value is global to all threads in a process, a handle can be accessed in any thread, even threads that did not open the handle. For example, one thread can call the socket function, which returns a socket handle. A different thread in the same process can make other Windows Sockets calls with the returned socket handle. No special action is required to enable the second thread to use the handle; it just needs to obtain the handle value.

It is also possible for multiple threads to access a single socket simultaneously, but an application that does this must synchronize important actions. For example, if one thread performs a bind operation on a socket at the same time another thread is performing a getsockname operation, then because of the preemptive scheduling of Windows NT there are no guarantees that the getsockname operation will execute before the bind operation. It could happen that getsockname returns WSAEINVAL because the socket is not yet bound.

Another important example of simultaneous access in multiple threads to a single socket is data transfer. An application can have one thread calling send on a socket and another thread calling recv with no adverse effects whatsoever. However, if multiple threads call send on a socket, there are no guarantees as to the order of data delivery. The only guarantee is that the data in each send operation will be sent as a contiguous chunk — there is no possibility of intermixing data from different send calls. The analagous situation exists for multiple simultaneous recv calls — there is no guarantee as to which will finish first, but the data returned to any given recv operation is contiguous.

Making multiple simultaneous calls from different threads will not in any way damage the internal state of the socket maintained by Windows Sockets. Windows Sockets internally synchronizes the socket state whenever it changes in any way. Therefore, you need not worry about synchronizing calls for the sake of preserving the internal state of Windows Sockets.


 Sharing Sockets Between Processes

Handles in Windows NT can also be shared between processes. However, since each process has its own handle table, it is more work to share handles between processes than between threads. There are two mechanisms for sharing handles between processes: inheritance and duplication.

In inheritance, a process (called the "parent process") creates another process (called the "child process") using the Win32 function CreateProcess with the fInheritHandles parameter set to TRUE. This causes the system to map into the child's process table all the inheritable handles of the parent process. Note that while not all Win32 handles are inheritable (inheritance requires opening a handle in a special manner), all socket handles are inheritable.

Once you create the child process, it must be given the values of the handles it needs to access. When it has the handle values, it can pass the handles to Windows Sockets or other functions.

In duplication, a process can pass a handle to another existing process with the Win32 function DuplicateHandle. This function allows one process to map a handle into the process table of another process, although the specific handle value may be different in the receiving process.

When sharing sockets between processes, the same synchronization issues exist as when sharing sockets between threads. In addition, you must be aware of two other special properties of sharing sockets between processes.

First, since both processes have a view of the socket handle, both processes must call closesocket before the system closes the socket. The process that first calls closesocket only takes the socket out of its internal handle table. The first closesocket call does not affect the second process's access to the socket in any way. The second closesocket does the actual cleanup of the socket, including initiating the protocol-level virtual circuit termination if the socket is connected. If the socket sharing is really a "hand-off" from one process to another, it is best to close the socket in the first process immediately after the CreateProcess or DuplicateHandle call.

Second, some socket options, such as SO_LINGER, are kept on a per-process basis. Therefore, after a socket handle has been passed to a second process, changes in socket options by one process may not be reflected in the other process. For this reason it is advisable to set up any socket options that both processes will need before sharing the socket handle.

Many Unix® services that use sockets make use of child process creation and inheritance to handle multiple simultaneous clients. This is typically done by a "master" process creating a socket, calling listen on the socket, and using accept to accept incoming connections. Then this process creates a "slave" process that actually services the client while the master immediately closes the accepted socket. This is useful in Unix, where multiple threads are generally not available, and this algorithm will work in Windows NT. However, processes use more memory than threads. Context switches between processes use about twice the CPU instructions used in context switches between threads within a single process. In addition, threads can share information much more easily than processes, so it is usually easier in the long run to use threads rather than processes. For all these reasons, it is strongly recommended that you write a service that handles multiple clients simultaneously so that it uses one thread per client rather than one process per client. It is even better to use multiple clients per thread. This technique is discussed in Accessing Sockets Through the Win32 I/O Functions.


 Using Sockets as Standard I/O Handles

A special case of sharing sockets between processes is using sockets as standard input, output, or errors for a child process created with CreateProcess. This is useful for causing a process to unwittingly read input from a socket and to write output to a socket. Such a child process may "know" absolutely nothing about sockets or even networks; it just reads from its standard input and writes to its standard output.

There are two key steps in making this possible. First, a socket must be opened for "synchronous" access (that is, not overlapped) with the SO_OPENTYPE socket option described following. Second, the socket must be connected with either the connect or accept Windows Sockets function calls. After these steps, making a socket handle accessible as a standard I/O handle is just like doing so for other handles: Specify the handle value in the hStdInput, hStdOutput, and/or hStdError fields of the STARTUPINFO structure passed to CreateProcess Win32 function. The created process will read from and write to the socket without ever knowing it is a socket.


 Accessing Sockets Through the Win32 I/O Functions

Since Windows NT socket handles are system socket handles, it is possible to use Windows NT socket handles as parameters to several of the Win32 functions. The most useful Win32 functions for sockets are the ReadFile and WriteFile functions since these allow an application to perform aynchronous I/O on a handle by means of the lpOverlapped parameter. In overlapped I/O, the request is started with the initial call but the call does not block waiting for the request to be completed. For example, if an application makes an overlapped ReadFile call when no data exists to be read on a socket, the calling thread will regain control immediately rather than waiting for data to arrive on the socket. The application will be notified when the request has been completed via the lpOverlapped parameter.

Overlapped I/O differs from the socket concept of nonblocking I/O in that overlapped I/O actually performs the I/O eventually if it cannot be completed immediately. In nonblocking I/O, if the I/O cannot be performed immediately, then it fails with the error code WSAEWOULDBLOCK and the application must reissue the request at a later point.

Overlapped I/O is especially useful in a service that handles multiple sockets. A single thread can be used to perform I/O on all of the sockets without the overhead of the select call. Also, the use of overlapped I/O allows an application to mix different types of I/O in a single thread; for example, I/O on named pipes and I/O on sockets.

Because Windows NT socket handles are, by default, opened as overlapped handles, an application must specify the lpOverlapped parameter on calls to ReadFile and WriteFile. However, an application can also use the SO_OPENTYPE socket option to open sockets that are not overlapped.


 Accessing Sockets Through the C Run-time Libraries

The C run-time libraries (CRTs) provide useful functionality for input and output formatting through routines such as fprintf, fscanf, and so on. It may also be useful to access socket handles through these routines in existing code that uses C run-time calls such as _read and _write.

The C run-time libraries take two different inputs to identify a file: a CRT handle (different from a system handle such as a socket) and a file pointer. The low-level I/O routines, such as _read, take CRT handles, while the more sophisticated formatting routines, such as fprintf, take file pointers.

To access sockets through the C run-time routines, an application must perform several steps:

1.	Use the SO_OPENTYPE socket option described following so that any opened socket handles are synchronous.

2.	Open a connected socket by calling either socket and connect or by calling accept. It is legal to use datagram sockets, although their inherent unreliability may make them unsuitable for C run-time access in many applications.

3.	Obtain a CRT socket handle with the _open_osf_handle C run-time API. If the application intends to use only the low-level C run-time calls, the handle returned by this call is sufficient and the application is ready to make C run-time calls.

4.	If the application wants to use the higher-level C run-time calls that do data formatting, the application must obtain a file pointer (FILE *) by using the _fdopen C run-time call.


 Socket Options Specific to Windows NT

Windows NT supplies several socket options beyond those included in the Windows Sockets specification. Because these options are not currently part of the formal Windows Sockets specification, an application that uses these options is not compatible with Windows Sockets. However, for applications written exclusively for Windows NT, these options can be very useful.


 SO_SNDTIMEO and SO_RCVTIMEO

These two options set up timeouts for the send, sendto, recv, and recvfrom functions. You can obtain the same functionality by calling select with a timeout just before the I/O call, but these options offer a significant improvement in performance by avoiding a kernel transition and the other overhead of the select call. For any code whose performance is very critical, applications should use these timeout options rather than select.

You can set these options on any type of socket in any state. The default value for these options is zero, which refers to an infinite timeout. Any other setting is the timeout, in milliseconds. It is legal to set the timeout to any value, but values less than 500 milliseconds (half a second) are interpreted to be 500 milliseconds.

To set a send timeout, use

int timeout = TIMEOUT_VALUE;

int err;

SOCKET s;

s = socket( ... );

err = setsockopt(

        s,

        SOL_SOCKET,

        SO_SNDTIMEO,

        (char *)&timeout,

        sizeof(timeout));

if (err != NO_ERROR) {

    /* failed for some reason... */

}

where TIMEOUT_VALUE is the needed timeout in milliseconds. To set a receive timeout, substitute SO_RCVTIMEO for SO_SNDTIMEO in the preceding example.

After setting one of these options to a nonzero value, I/O through the Windows Sockets calls fails with the error WSAETIMEDOUT if the request cannot be satisfied within the specified timeout. If a request times out, an application has no guarantees as to how much data was actually sent or received in the I/O call.


 SO_OPENTYPE

By default, all socket handles are opened as overlapped handles so that asynchronous I/O can be performed on them. However, in many situations it is preferable to have nonoverlapped (synchronous) socket handles. For example, only nonoverlapped handles can be used with the C run-time libraries or used as standard I/O handles for a process. The SO_OPENTYPE socket option allows an application to open nonoverlapped socket handles.

The SO_OPENTYPE option must be set on a per-thread basis since it affects how each thread opens sockets, and it must be set before a socket handle is opened in order to affect the socket. The default value for this option is zero, which opens sockets as overlapped handles. Other possible values for this option are SO_SYNCHRONOUS_ALERT and SO_SYNCHRONOUS_NONALERT. SO_SYNCHRONOUS_ALERT allows operations performed on the socket handle to be alerted by an APC routine (software interrupt), while SO_SYNCHRONOUS_NONALERT blocks APCs from being delivered to threads waiting on requests on socket handles. Typically, it does not matter which of these options is chosen: either makes socket handles nonoverlapped.

Use the following to open a nonoverlapped socket handle:

SOCKET s;

int optionValue = SO_SYNCHRONOUS_NONALERT;

int err;

err = setsockopt(

        INVALID_SOCKET,

        SOL_SOCKET,

        SO_OPENTYPE,

        (char *)&optionValue,

        sizeof(optionValue));

if (err != NO_ERROR) {

    /* failed for some reason... */

}

s = socket( ... );

Note that the socket handle passed to setsockopt is ignored for this option.

The SO_OPENTYPE socket option affects both the socket and accept Windows Sockets calls. The setting of SO_OPENTYPE is preserved throughout the lifetime of the thread in which it is set, so it is not necessary to set its value before each socket opens. However, it is necessary to set this option for every thread that opens sockets if the nondefault behavior is desired. Also, if different layers of an application open sockets and have different expectations of the type of handles opened, it is advisable to use getsockopt before the setsockopt call to obtain the original setting of SO_OPENTYPE, then reset SO_OPENTYPE to the original value after opening the socket. For example,

SOCKET s;

int originalValue;

int optionValue = SO_SYNCHRONOUS_ALERT;

int err;

int optionLength = sizeof(originalValue);

/* Get the original setting of SO_OPENTYPE. */

err = getsockopt(

        INVALID_SOCKET,

        SOL_SOCKET,

        SO_OPENTYPE,

        (char *)&originalValue,

        optionLength);

if (err != NO_ERROR) {

    /* failed for some reason... */

}

/* Set SO_OPENTYPE so that we get a synchronous socket handle. */

err = setsockopt(

        INVALID_SOCKET,

        SOL_SOCKET,

        SO_OPENTYPE,

        (char *)&optionValue,

        sizeof(optionValue));

if (err != NO_ERROR) {

    /* failed for some reason... */

}

s = socket( ... );

/* Reset the SO_OPENTYPE setting to its original value. */

err = setsockopt(

        INVALID_SOCKET,

        SOL_SOCKET,

        SO_OPENTYPE,

        (char *)&optionValue,

        sizeof(optionValue));

if (err != NO_ERROR) {

    /* failed for some reason... */

}

This technique is especially useful in DLLs that use synchronous sockets.

There are some Windows Sockets features that you cannot use with synchronous sockets. The WSAAsyncSelect call cannot be used with synchronous sockets and will fail with the error WSAEINVAL. It is also not possible to set the SO_SNDTIMEO and SO_RCVTIMEO socket options on synchronous sockets; setsockopt with these options on synchronous sockets fails with WSAEINVAL as well.


 Multiple Protocol Support

In addition to TCP/IP, Windows NT supports several additional transport protocols through its Windows Sockets interface. Although these protocols are not explicitly addressed in the Windows Sockets specification, the interface to Windows Sockets over different transport protocols is quite feasible. This is because the fundamental job of a transport protocol is data transfer, along with the fact that Windows Sockets provides a rich interface for low-level data transfer in applications. Having a common, well-known interface allows applications to be ported quickly between different transport protocols, and there are several successful examples of this.

Because of the architecture of the Windows Sockets component of Windows NT, all supported transport protocols are accessed through the same DLL, WSOCK32.DLL. In fact, a single application can simultaneously use sockets of different transport protocols.

An application uses the parameters to the socket function to specify the protocol it will use. For example, a TCP socket is opened with

s_tcp = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );

while an SPX socket is opened with

s_spx = socket( AF_IPX, SOCK_SEQPACKET, NSPROTO_SPX );

After opening a socket for a specific protocol, all actions performed on the socket go through the specified protocol. In the preceding example, if the application did a listen on the s_tcp socket but not on the s_spx socket, it would receive incoming connects through TCP but not receive incoming connects through SPX.


 Protocol Characteristics

It is important to understand the different characteristics of transport protocols when designing an application that uses them. While all transport protocols share the same fundamental purpose of bidirectional data transfer, many details of the data transfer differ. The following sections list key characteristics of transport protocols that apply to Windows Sockets applications.


 Addressing

The most obvious difference between different transport protocols is the way each uses transport addresses, called "socket addresses" in Windows Sockets terms. Virtually all transport protocols expose different address formats to applications, the one exception being NetBIOS protocols, which all use the same address format.

A number of Windows Sockets functions take socket addresses as input or output parameters, including bind, accept, sendto, recvfrom, getsockname, and getpeername. For all these functions a socket address is really two arguments: a pointer to the socket address structure itself and a length integer that gives the number of bytes in the socket address. For many transport protocols the length of a socket address is always the same, but socket address lengths can differ between transport protocols. For example, a TCP/IP socket address has 16 bytes and an IPX/SPX socket address has 14 bytes.

The format of socket address structures used by a transport protocol is specified in the af, or "address family" argument to the socket function. All TCP/IP sockets (including both TCP and UDP sockets) are opened with the AF_INET address family, while IPX/SPX sockets are opened with AF_IPX. Other transport protocols use different address family values as defined in the header file WINSOCK.H.

An application must fill in a socket address when binding to a local address or connecting to a remote address, and also to interpret the socket addresss returned from the accept, sendto, recvfrom, getpeername, and getsockname functions.


 Connection-Oriented vs. Connectionless Transport

In a connection-oriented transport protocol, applications are required to establish a virtual circuit (sometimes abbreviated to "VC") before data transfer can take place. Virtual circuit establishment is assymetrical. One side, the server, must indicate to the transport protocol that it can receive incoming connections via the listen function. The other side, the client, initiates the circuit with the connect function, and the server can obtain a socket for the circuit with the accept function. Once the circuit is established, data transfer takes place with the send and recv functions. Protocol-level activity results from this circuit establishment, and more protocol activity tears down the circuit when the sockets are closed. TCP and SPX are examples of connection-oriented transport protocols.

In a connectionless transport protocol, circuit establishment is not required for data transfer. An application need only open and bind a socket, after which it can use the sendto and recvfrom functions to send and receive data. Of course, in order to specify the remote address for sending data or the address from which received data was sent, you must specify a socket address to these routines. UDP and IPX are examples of connectionless transport protocols.

It is possible to use the connect function on sockets opened for connectionless protocols. This is merely an application convenience, allowing the application to use the send and recv functions, and this does not result in any protocol activity. If a socket is connected in this manner, it will receive only packets sent from the connected address; other packets destined for the socket are silently discarded.


 Reliable vs. Unreliable Data Delivery

Most physical networks are inherently unreliable. They can drop data, corrupt it, deliver it out of order, and deliver multiple copies of it. Some transport protocols hide this unreliability from applications by using protocol-level mechanisms to ensure that data is delivered in the correct order, without loss, corruption, or duplication. Other transport protocols do not make these guarantees; they simply make a best effort to get the data to its intended recipient, but physical network failures can lead to data integrity problems.

Because they require fewer system resources and less processing, unreliable protocols often provide better performance, especially for applications that send small amounts of data in a request-response (transaction) format. However, applications that use connectionless protocols must guarantee reliability, which makes applications more complicated. Reliable protocols are usually simpler for the application at the expense of a higher cost in system resources and performance.

Typically, connection-oriented protocols are reliable, while connectionless protocols are unreliable. While this is true of all the transport protocols supported by Windows NT, there are exceptions.


 Terminating a Virtual Circuit

For a connection-oriented transport protocol, there are two ways to terminate a virtual circuit: orderly and abortive. In an orderly release, both sides get a chance to indicate that they have sent all the data they intend to send, and only when both sides have finished is the actual circuit terminated. For such a release, one side can use the shutdown function to indicate that it has finished sending, while the other side continues sending. In an abortive termination of a virtual circuit, one side decides that it is time to terminate the circuit and unilaterally ends the connection. If the other side attempts to use the connected socket, the request fails.

By default, closesocket also attempts an orderly release of the connection. However, under several circumstances, such as pending unreceived, outstanding send calls, and more, a closesocket will result in an abortive close.

All transport protocols support the concept of an abortive release, but not all protocols support orderly release. If an application attempts an orderly release on a transport protocol that does not support orderly release, the connection is terminated abortively. TCP supports orderly release, while SPX supports only abortive release.


 Message-Oriented vs. Stream-Oriented

Connection-oriented transport protocols can be either message-oriented or stream-oriented. In a message-oriented transport protocol, each block of data is sent and received as a single block. An individual message is never broken down when received, although a transport protocol can be forced to break down a message if it is larger than the physical network's maximum transmission unit (MTU). However, this is transparent to the application.

In a stream-oriented transport protocol, data is sent and received as a continuous stream, without any message boundaries. The transport protocol is free to coalesce data from discrete send calls and deliver it to a single recv call, as well as to break down the data buffer given to a single send call and deliver it to several recv calls. An application cannot control how these breakdowns occur, and gets no notification of how data was sent. If an application needs to communicate in discrete messages, it must frame them, for example, by preceding message data with the length of the message until the specified length arrives.

Some message-oriented protocols support stream semantics in addition to message semantics. If an application opens a socket with SOCK_STREAM on such a transport protocol, then the transport ignores all message boundaries when transmitting and receiving data. It simply delivers data as it becomes available, regardless of whether the data is a complete message. This feature is handy for maximizing application portability. Note, however, that stream-oriented transport protocols cannot implement message-oriented semantics due to lack of information.


 Expedited Data

Some connection-oriented transport protocols support expedited data, also referred to as "urgent data" or "out-of-band data." Data sent with the MSG_OOB flag in the send function is sent as expedited data, and the transport protocol makes every effort to deliver the data as quickly as possible. Often the data is delivered out of order so that it can get to the other application as quickly as possible. For maximum portability, avoid expedited data since it is not supported by all transport protocols.


 Connect and Disconnect Data

A few transport protocols support connect and disconnect data, in which a small amount of data is sent by each side when a virtual circuit is established or terminated. This data can be anything, but is often negotiation information about the version of software connecting, and so on. Again, for protocol portability, avoid this feature since it is not universally supported.


 Broadcasts

Most connectionless transport protocols support broadcasts in the same fashion, in which any bound socket can send a broadcast if the SO_BROADCAST option is set, and broadcasts sent to the appropriate local endpoint are received without any additional work on the part of the application. NetBIOS transport protocols, however, handle broadcasts somewhat differently. In order to receive broadcasts, an application must bind to the NetBIOS broadcast address, which is an asterisk ("*") followed by 15 blank spaces (ASCII character 0x20). This means two things: A socket must be specially bound to receive broadcasts, and applications cannot depend on receiving broadcasts intended only for a specific application, since all NetBIOS broadcasts are delivered to this address. In other protocols such as UDP/IP and IPX, broadcasts are delivered to a socket only if the broadcast was sent to the same port to which the socket was bound.


 Extended Support for Message-Oriented Protocols

The Berkeley Software Distribution (BSD) sockets interface was originally designed to support primarily TCP/IP, and the Windows Sockets interface is based on BSD sockets. This interface is not sufficiently rich for message-oriented transport protocols, however, so Windows NT includes some minor extensions of the interface so that applications can fully exploit message-oriented transport protocols.


 MSG_PARTIAL Flag

Under some circumstances, applications may not have available in a single, contiguous data buffer all the data that make up a single message to be sent. The message can be very large, for example, or can be composed of discrete parts in an application's virtual address space. To allow an application to send this message without having to allocate a buffer and copy all the data into the buffer, Windows NT allows the application to specify the MSG_PARTIAL bit in the flags parameter of the send function. This bit tells the transport protocol that the data in the send operation is just part of a larger message, and that the protocol should take whatever action is necessary to deliver the data as a partial message.


 WSARecvEx Function

By default, for message-oriented transport protocols the Windows Sockets recv function receives a single message in each call to the API. This works fine for most cases, but there are two situations in which this is insufficient: when the application's data buffer is smaller than the message, and when the message is large and arrives in several pieces.

When the buffer is smaller than the data, as much of the message as will fit is copied into the user's buffer and recv returns with the error code WSAEMSGSIZE. A subsequent call to recv will get the next part of the message. Applications written for message-oriented transport protocols should be coded for this possibility if message sizing is not guaranteed by the application's data transfer protocol. If an application gets this error code, then the entire data buffer is filled with data.

It is more complicated when a very large message arrives a little at a time. For example, if an application sends a 1-megabyte message, the transport protocol must break up the message in order to send it over the physical network. It is theoretically possible for the transport protocol on the receiving side to buffer all the data in the message, but this would be quite expensive in terms of resources.

It would be better to allow a recv call to complete with only a partial message and some indication to the application that the data is only a partial message. However, the Windows Sockets recv function has only one output parameter: the number of bytes received. Therefore, Windows NT supplies the WSARecvEx function, which is identical to the recv function except that the flags parameter is an in-out parameter:

int

PASCAL

FAR

WSARecvEx (

        SOCKET s,

        char FAR * buf,

        int len,

        int *flags

        );

On return from WSARecvEx, if a partial message was received, the MSG_PARTIAL bit is set in the flags parameter. If a complete message was received, MSG_PARTIAL is not set in flags. For a stream-oriented transport protocol, MSG_PARTIAL is never set on return from WSARecvEx; for stream transport protocols, this function behaves identically to the Windows Sockets recv function.


 WSAEDISCON Error Code

After a virtual circuit is gracefully terminated on a stream-oriented transport protocol and all data has been received, the recv and WSARecvEx functions return zero to indicate that there will never be any more data to read on the connection. However, most message-oriented transport procotols support the concept of a zero-length message. Applications therefore need a mechanism to distinguish a zero-length message and graceful circuit termination.

The Windows Sockets interface in Windows NT uses the WSAEDISCON error code to solve this problem. When the circuit is gracefully terminated, this error code is returned to the application, and a return value of zero is used to indicate a message of length zero.

Following is an example of client-side code that establishes an SPX connection, and receives and processes messages until the connection is terminated.

SOCKET s;

SOCKADDR_IPX sockaddrIpx;

INT err;

INT bytesReceived;

INT flags;

/* open the SPX socket handle */

s = socket( AF_IPX, SOCK_SEQPACKET, NSPROTO_SPX );

/* initialize the sockaddr for the remote machine */

sockaddrIpx.sa_family = AF_IPX;

sockaddrIpx.sa_netnum = 0;

sockaddrIpx.sa_nodenum = 123;  /* substitute real nodenum here */

sockaddrIpx.sa_socket = 1; /*substitute real socket number here */

/* connect the socket */

err = connect(

        s,

        (PSOCKADDR)&sockaddrIpx,

        sizeof(sockaddrIpx) );

if ( err != 0 ) {

    /* indicate connection failure */

}

/* receive data until the connection terminates */

while ( TRUE ) {

    /* use WSARecvEx to receive data */

    flags = 0;

    bytesReceived = WSARecvEx( s, buffer, buflen, &flags );

    /* check for error or graceful termination */

    if ( bytesReceived < 0 ) {

        if ( WSAGetLastError( ) == WSAEDISCON ) {

            /* graceful termination */

            break;

        }

        /* some other error, indicate to user */

        break;

    }

    /* check for partial message */

    if ( (flags & MSG_PARTIAL) != 0 ) {

        /* a partial message; handle specially */

    }

    /* check for 0-length message */

    if ( bytesReceived == 0 ) {

        /* 0-length message, process */

    } else {

        /* message contained data */

    }

}

/* circuit terminated or error, close socket */

closesocket( s );


 Windows NT Support for Connect and Disconnect Data

Some transport protocols, such as DECNet and OSI TP4, support the concept of connect and disconnect data. This is additional data, not in the normal data stream, that is sent on the wire along with connect or disconnect requests and is typically used for things like application-level version negotiation. The TDI interface provides support for connect and disconnect data through the TDI_CONNECTION_INFORMATION structure, which has fields for UserDataLength, UserData, OptionsLength, and Options and is passed on TDI connect, accept, and disconnect requests.

The sockets interface, however, does not provide input parameters for connect data on the connect function or for disconnect data on the shutdown and closesocket functions. However, it is relatively natural to use the setsockopt function to specify connect and disconnect data to send, and to use the getsockopt function to retrieve connect and disconnect data sent by the remote side. To support this, the following socket options are included with the Windows NT version of the Windows Sockets header file (WINSOCK.H):

/*

 * Options for connect and disconnect data and options. Used only by

 * non-TCP/IP transports such as DECNet, OSI TP4, etc.

 */

#define SO_CONNDATA     0x7000

#define SO_CONNOPT      0x7001

#define SO_DISCDATA     0x7002

#define SO_DISCOPT      0x7003

#define SO_CONNDATALEN  0x7004

#define SO_CONNOPTLEN   0x7005

#define SO_DISCDATALEN  0x7006

#define SO_DISCOPTLEN   0x7007

How an application uses these options in conjunction with getsockopt and setsockopt depends on the type of application, server or client, and how it will use connect data. Each case is explained following.

Connect and disconnect options are semantically the same as connect and disconnect data, from the standpoint of the Windows Sockets interface. The "options" are really just a buffer of data that is passed to the transport protocol prior to the connect or disconnect, and a buffer that is retrieved following a connect or disconnect. Therefore, an application uses connect or disconnect options in much the same manner it uses connect or disconnect data. The only difference is the option names used on the getsockopt and setsockopt calls; for example, use SO_CONNOPT in place of SO_CONNDATA.


 Client Applications and Connect Data

A Windows Sockets client application written for a transport protocol that supports connect data should call setsockopt with SOL_SOCKET as the level, SO_CONNDATA as the option name, and a buffer in the option value field that contains the connect data it intends to send. This call must be made before calling the connect function. The specified connect data is then sent on the connect request.

Two steps are required to retrieve response connect data. First, before the connect call, the application must inform the Windows Sockets DLL how much space to reserve for the response connect data. This is done by calling setsockopt with option level SOL_SOCKET, option name SO_CONNDATALEN, and having the option value parameter point to an integer that contains the maximum number of connect data bytes expected. The Windows Sockets DLL will set aside a buffer of this size to contain connect data sent by the server application.

After the connect has completed successfully, the application can call getsockopt with an option level of SOL_SOCKET, an option name of SO_CONNDATA, and a buffer in the option value parameter large enough to hold the response connect data. The Windows Sockets DLL then copies the response connect data into the caller's buffer.

Note that the Windows Sockets DLL keeps the response connect data buffer valid for the lifetime of the socket. Therefore, an application can retrieve the response connect data for the socket at any time after the socket is connected and before it is closed.


 Server Applications and Connect Data

A server application's use of connect data implicitly differs in two important ways from a client application's use. First, a server application receives the client's connect data before it sends its own. Second, because the socket's interface does not support the concept of delayed accept, a server application is limited to sending the same response connect data to all clients.

A server application that is to receive connect data should use setsockopt with the SO_CONNDATALEN option to force the Windows Sockets DLL to reserve buffer space into which to receive connect data for incoming connect requests. The specified amount of connect data buffer space is used for all incoming connects, but each connect gets a separate buffer. After a new connected socket is accepted with accept the application calls getsockopt with the SO_CONNDATA option and a buffer large enough to hold expected response data. The Windows Sockets DLL fills in this buffer with the connect data sent by the client.

To send connect data, a server application calls setsockopt with the SO_CONNDATA option and a buffer of data before incoming connections are accepted (typically before listen). Thereafter, any client that connects to the server will receive the specified connect data. The connect data sent by a server can be changed at any time with another setsockopt call, which discards the previous data and replaces it with new connect data.


 Disconnect Data

Client and server applications send and receive disconnect data in a manner similar to the way a client application sends and receives connect data. To send disconnect data the application calls setsockopt with the SO_DISCDATA option and a buffer of disconnect data to send. The data will then be sent either when the application calls shutdown to disconnect the send side of the socket or when the application calls closesocket on the socket.

To receive disconnect data, an application must call setsockopt with the SO_DISCDATALEN option before a remote closes the connection. This option specifies the amount of disconnect data the application expects to receive.

After the remote has disconnected, the SO_DISCDATA option on getsockopt retrieves the disconnect data sent by the remote. The application passes in a buffer large enough to hold all the disconnect data, and the Windows Sockets DLL copies the received disconnect data into the buffer.


 Additional Items

The following topics provide details on additional items in Windows Sockets.

•	Blocking Sockets Calls

•	WSAGetLastError vs. GetLastError

•	Closing Sockets: Graceful vs. Abortive

•	Notes on Performance

•	Windows NT Extensions to WINSOCK.H


 Blocking Sockets Calls

The Windows Sockets specification defines a "blocking hook" mechanism, accessed through the WSASetBlockingHook, WSAUnhookBlockingHook, WSAIsBlocking, and WSACancelBlockingCall functions. The blocking hook works by polling for Windows messages while a Windows Sockets function call is blocking on network activity and calling back into the application when a message arrives. This mechanism allows a measure of multitasking to occur within the nonpreemptive Windows environment. In fact, an application that makes blocking calls gets a "default blocking hook" installed, which can result in reentrance to the application if the application makes any calls that must block.The blocking hook is useful for promoting multitasking, but Windows NT, being a fully preemptive, multitasking operating system, doesn't need any help from applications to do multitasking. Additionally, programming Windows applications that use the blocking is complex, requiring special attention to reentrance issues. Therefore, 32-bit applications for Windows NT do not get a default blocking hook installed. If a thread makes a blocking call, the thread simply blocks, and the system schedules other threads as appropriate, waking up the blocked thread when the I/O completes.

If a 32-bit application really does require the blocking hook semantics, such an application can use WSASetBlockingHook to install any blocking hook on a per-thread basis. This blocking hook will operate exactly as specified in the Windows Sockets specification. Note that the fact that the blocking hook is per-thread means two things for multithreaded applications: If they need blocking hooks, they must install a blocking hook for every thread that makes blocking Windows Sockets calls; and they can install a different blocking hook in different threads of their process, allowing different blocking hook behavior in different threads.

If a 16-bit application is ported to Win32 and depends on the behavior of the default blocking hook, the application can install as a blocking hook code that performs the same actions as the default blocking hook:

BOOL

DefaultBlockingHook (

    VOID

    )

{

    MSG msg;

    BOOLEAN retrievedMessage;

    //

    // Get the next message, if any.

    //

    retrievedMessage = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);

    //

    // Process the message if we got one.

    //

    if (retrievedMessage) {

        TranslateMessage((CONST MSG *)&msg);

        DispatchMessage((CONST MSG *)&msg);

    }

    //

    // If we got a message, indicate that we want to be called again.

    //

    return retrievedMessage;

} // DefaultBlockingHook

Note that 16-bit Windows Sockets applications running in the 16-bit subsystem of Windows NT do get the default blocking hook semantics as described in the Windows Sockets specification, so there is no need to modify 16-bit applications to take advantage of the blocking hook behavior.


 WSAGetLastError vs. GetLastError

Windows Sockets applications use the WSAGetLastError function to retrieve specific error information on failed function calls. For 32-bit applications under Windows NT, the WSAGetLastError function is just a call through to theWin32 GetLastError call, which provides identical functionality. Therefore, if an application makes a Windows Sockets call that fails, then a Win32 function call that also fails, the result of WSAGetLastError will give the error code for the Win32 function failure. In addition, some C run-time calls, specifically printf, reset the thread's last error to zero, so a call to WSAGetLastError after one of these function calls can return the value zero rather than the actual failure code. It is strongly recommended that applications be written to call WSAGetLastError (or GetLastError) immediately after a failed Windows Sockets call is detected without any intervening function calls.

Note also that WSASetLastError is just a call through to SetLastError, so calling WSASetLastError will reset the error obtained by GetLastError.


 Closing Sockets: Graceful vs. Abortive

For transport protocols that support graceful close, Windows NT has been carefully designed to perform graceful closes when appropriate, and to perform abortive close operations when appropriate. By default, closing a connected socket with closesocket results in a graceful close of the virtual circuit. In addition, using shutdown on the send side of a socket initiates a graceful close. If an application is to force an abortive close, it should set the SO_LINGER option on the socket to have a timeout of zero.

Windows NT uses an abortive close to indicate to the remote end that a connection was terminated in an ungraceful manner. There are several causes for this:

•	Closing a socket when there is unreceived data buffered on the socket.

•	Exiting a process without calling closesocket on all connected sockets.

•	Data arrives after the graceful close has been initiated.

•	The SO_LINGER option is nonzero, but some data remains unsent after the timeout expires.

To ensure a graceful close on a virtual circuit, an application must receive all data on the socket and manually call closesocket on the socket. To do this properly, some application protocols require the shutdown function to initiate graceful close in conjunction with recv or WSARecvEx to ensure that all data sent by the remote is received locally.


 Notes on Performance

Application performance can be tuned so that data can be transferred as quickly as possible with minimal burden on the system CPU. There are several general guidelines that can help you tune your code. Many of these simple guidelines will seem obvious, but it is surprising how often they are overlooked.

First, send and receive data in chunks as large as possible, up to approximately 64 kilobytes. There is a certain amount of unavoidable overhead in each send or recv call, and sending and receiving large chunks of data spreads the overhead over fewer calls.

Second, do as little in performance paths as possible. Do not include any extraneous calls, either Windows Sockets or Win32. If you need to send a lot of data, do it in a tight loop without any calls other than send. If you must specify a timeout on the send, do not use the select function, which has the inherent overhead of a kernel transition. Instead, set the SO_SNDTIMEO option on the socket and use send only. If you're handling several sockets in your application, use threads so that you can avoid calls to select (but be careful not to use too many threads — threads cost memory and introduce context switching overhead).

It is possible to achieve very high data transfer rates with the Windows Sockets interface in Windows NT. With TCP/IP on a 10-megabit-per-second ethernet, we have seen rates of more than a megabyte per second, which is close to the theoretical maximum for the medium, and the system CPUs were not fully saturated. This demonstrates that in a carefully coded and tuned application it is possible to achieve excellent performance through Windows Sockets.


 Windows NT Extensions to WINSOCK.H

To support some of the features unique to Windows NT described in this document, the WINSOCK.H header file that is included with the Win32 SDK contains some additional information, as shown:

/*

 * Options for connect and disconnect data and options. Used only by

 * non-TCP/IP transports such as DECNet, OSI TP4, etc.

 */

#define SO_CONNDATA     0x7000

#define SO_CONNOPT      0x7001

#define SO_DISCDATA     0x7002

#define SO_DISCOPT      0x7003

#define SO_CONNDATALEN  0x7004

#define SO_CONNOPTLEN   0x7005

#define SO_DISCDATALEN  0x7006

#define SO_DISCOPTLEN   0x7007

/*

 * Option for opening sockets for synchronous access.

 */

#define SO_OPENTYPE     0x7008

#define SO_SYNCHRONOUS_ALERT    0x10

#define SO_SYNCHRONOUS_NONALERT 0x20

#define WSAEDISCON              (WSABASEERR+101)

int PASCAL FAR WSARecvEx (SOCKET s, char FAR * buf, int len, int *flags);


 Windows Sockets Service Registration and Name Resolution

The service registration and resolution functionality helps you write client server applications. Using this functionality, a service can register its existence with a name space (registration), and a client can find a service within a name space (resolution).


 Service Registration and Resolution Definitions

The following functions and structures let you implement service registration and resolution functionality.


 Service Registration and Resolution Functions

Use these functions to implement service registration and resolution functionality:

EnumProtocols
GetAddressByName
GetNameByType
GetService
GetTypeByName
SetService


 Service Registration and Resolution Structures

Use these structures to implement service registration and resolution functionality:

BLOB
CSADDR_INFO
NS_SERVICE_INFO
PROTOCOL_INFO
SERVICE_ADDRESS
SERVICE_ADDRESSES
SERVICE_INFO
SERVICE_TYPE_INFO_ABS
SERVICE_TYPE_VALUE_ABS


Introduction to Audio

Microsoft® Windows® provides several different types and levels of audio services. You should become familiar with these types and levels so you can choose the services appropriate for your application. This overview assumes you have a basic knowledge of digital audio and Musical Instrument Digital Interface (MIDI).


About Audio Services

This overview covers the following topics:

•	Types of audio services

•	Levels of audio services

•	Windows audio architecture

•	Audio file formats

•	Further reading


Types of Audio Services

Different types of audio services require different formats for the audio information and different technologies to reproduce audio. Windows offers the following types of audio services:

•	Waveform audio services provide playback and recording support for digital audio hardware. Waveform audio is useful for reproducing nonmusical audio material such as sound effects and voice-over narration. Waveform audio has moderate storage-space and data-transfer rate requirements — as low as 11 kilobytes per second of audio.

•	MIDI audio services provide support for MIDI-file and MIDI-event playback (through internal or external synthesizers) and MIDI-event recording. MIDI audio is useful with music-related applications such as music composition and MIDI sequencer programs. Because they require less storage space and a lower data-transfer rate than waveform audio, you may want to use MIDI audio services to provide introductory and background music in your applications.

•	Compact disc (CD) audio services provide support for playback of Red Book audio information on CDs by means of the CD-ROM drive on multimedia computers. CD audio offers the highest quality reproduction of musical material but has the highest storage-space requirements — 176 kilobytes per second of audio. You cannot read from the CD-ROM drive while playing CD audio.


Levels of Audio Services

The different levels of audio services let you choose services appropriate to the requirements of your application and to your programming ability. Windows offers two levels of audio services:

•	High-level audio services allow you to play and record audio files by using as little as one function call. Compared with low-level audio services, high-level services are easier to use and require less programming. High-level services also meet the audio requirements of most applications.

•	Low-level audio services allow you to communicate directly with audio device drivers to manage playback and recording. Low-level audio services require more programming than high-level services but give you more control over audio playback and recording.

The easiest way to play and record audio is to use high-level audio services. If the high-level audio services do not meet the audio needs of your application, you can use low-level audio services to write your own routines to manage audio playback and recording.


Windows Audio Architecture

Windows provides audio services through high-level audio functions, Media Control Interface (MCI) device drivers, low-level audio functions, the MIDI Mapper, and low-level audio device drivers. The following illustration shows the relationship between an application and the elements of Windows that provide audio support.


High-Level Audio Support

MCI functions, along with MCI device drivers, provide high-level audio support for MIDI, waveform, and CD audio devices. MCI drivers can play disk-resident (hard disk and CD-ROM) audio files in the background while an application runs in the foreground. In addition to MCI, Windows provides high-level audio support with three special-purpose functions that play waveform sounds: MessageBeep, PlaySound, and sndPlaySound. You can also use these functions to play waveform sounds associated with system alerts and sounds identified by entries in the registry.

High-level audio functions should meet the audio requirements of most applications. For information about using MCI and the MessageBeep, PlaySound, and sndPlaySound functions, see High-Level Audio.


Low-Level Audio Support

Low-level audio functions provide a device-independent interface to audio hardware in multimedia computers. These functions supply low-level audio services by letting applications communicate directly with the audio device drivers. MCI drivers and the MessageBeep, PlaySound, and sndPlaySound functions use these low-level functions to provide high-level audio services.

Low-level audio functions are provided for applications — such as audio tools programs — that have special-purpose audio requirements. For example, a MIDI sequencer application would use low-level audio functions to record and play MIDI data. For information about using low-level audio services, see Low-Level Audio.


The MIDI Mapper

The MIDI Mapper provides standard patch services for device-independent playback of MIDI files. Standard patch services ensure that different MIDI synthesizers use the same instrument sounds to reproduce the music in a MIDI file.

The MIDI Mapper translates and redirects messages sent to it by low-level MIDI output functions. Because the high-level MIDI services use low-level MIDI output functions, the MIDI Mapper can be used with high-level as well as low-level MIDI services. For information about the architecture of the MIDI Mapper and how to use the MIDI Mapper with high-level audio services, see High-Level Audio. For information about using the MIDI Mapper with low-level audio services, see Low-Level Audio. MIDI files must follow certain authoring guidelines to use the standard patch services provided by the MIDI Mapper. For details about these authoring guidelines, see High-Level Audio.


Audio File Formats

Windows supports a tagged file structure called the Resource Interchange File Format (RIFF). There are two RIFF file formats currently defined for audio files.

RIFF type	Filename extension	Description
RMID	.RMI	MIDI audio file
WAVE	.WAV	Waveform audio file
The WAVE file format supports a number of digital audio data formats. All multimedia computers support pulse code modulated (PCM) formats of 8-bit monaural data at sample rates of 11.025 kilohertz (kHz) and 22.05 kHz.

In addition to Resource Interchange File Format MIDI (RMID) files, the MCI MIDI sequencer plays standard MIDI files in the format defined by the International MIDI Association in the "Standard MIDI Files 1.0" specification. For information about how to obtain this specification, see Further Reading. RMID files are standard MIDI files with a RIFF header.


Using RIFF Files

The multimedia file input and output (I/O) services include functions for working with RIFF files. For information about using these functions, see Multimedia File Input/Output.


Further Reading

For more information on digital audio, digital-signal processing, and computer music, see the following books:

Boom, Michael. Music Through MIDI. Redmond: Microsoft Press, 1987.

Chamberlin, Hal. Musical Applications of Microprocessors. Hasbrouk Heights: Hayden Book Company, Inc., 1985.

Pohlmann, Ken. Principles of Digital Audio. Indianapolis: Howard W. Sams & Co., 1985.

Roads, Curtis, and John Strawn. Foundations of Computer Music. Cambridge: The MIT Press, 1985.

Strawn, John F. Digital Audio Engineering, An Anthology. Los Altos: William Kaufmann, Inc., 1985.

Strawn, John F. Digital Audio Signal Processing, An Anthology. Los Altos: William Kaufmann, Inc., 1985.

For information about MIDI and standard MIDI files, see the following MIDI specifications:

MIDI 1.0 Detailed Specification

Standard MIDI Files 1.0 Specification

These specifications are available from the International MIDI Association at the following address:

International MIDI Association
5316 West 57th Street
Los Angeles, CA 90056


High-Level Audio

This overview explains how to use the high-level audio services of Microsoft® Windows® to add sound to applications. For an overview of the audio services, see Introduction to Audio.

This overview covers the following topics:

•	Playing waveform sounds

•	Playing and Recording Audio Using the Media Control Interface

•	Opening waveform and MIDI sequencer devices

•	Authoring MIDI files

The topics in this overview assume you have a basic knowledge of digital audio and MIDI. For additional information on these subjects, see Further Reading.


Function Prefixes

High-level audio function names begin with the following prefixes:

Prefix	Function group
snd	System-alert sound functions
mci	MCI functions


Playing Waveform Sounds

One basic way to use sound is to associate a sound with a user action or with a warning or alert message. These sounds tend to be short in duration and are often played repeatedly. Windows provides three functions to play waveform sounds.

Function	Description
MessageBeep	Plays the sound that corresponds to a given system-alert level.
PlaySound	Plays the sound that corresponds to the given filename or registry entry.
sndPlaySound	Plays the sound that corresponds to the given filename or registry entry.
These functions provide methods of playing the following waveform sounds:

•	WAVE files stored on a hard disk or CD-ROM

•	In-memory WAVE resources

•	WAVE files specified by entries in the registry

•	WAVE files associated with system-alert levels


Restrictions in Playing Waveform Sounds

There are some restrictions to using the MessageBeep, PlaySound, and sndPlaySound function to play waveform sounds:

•	The entire sound must fit in available physical memory.

•	The sound must be in a data format playable by one of the installed waveform audio device drivers.

Use MessageBeep, PlaySound, and sndPlaySound to play WAVE files that are relatively small in size — up to about 100 kilobytes. For larger sound files, use the MCI services. For information about using MCI, see Playing and Recording Audio Using the Media Control Interface.


Using the PlaySound and sndPlaySound Functions

The PlaySound and sndPlaySound functions can be used to perform the following tasks:

•	Playing WAVE files

•	Looping High-Level Audio Sounds

•	Playing High-Level Audio WAVE Resources

•	Playing High-Level Audio Sounds Specified in the Registry

Although the examples shown in these topics use the sndPlaySound function, most of the sample code works with the PlaySound function as well.


Playing WAVE Files

The following statement plays the C:\SOUNDS\BELLS.WAV file.

sndPlaySound("C:\\SOUNDS\\BELLS.WAV", SND_SYNC);

If the specified file does not exist or does not fit into the available physical memory, sndPlaySound plays the default system sound specified by the SystemDefault entry in the [sounds] section of the registry. If there is no SystemDefault entry, sndPlaySound fails without producing any sound. If you don't want the default system sound to play, specify the SND_NODEFAULT flags in the following example.

sndPlaySound("C:\\SOUNDS\\BELLS.WAV", SND_SYNC | SND_NODEFAULT);


Looping High-Level Audio Sounds

If you specify the SND_LOOP and SND_ASYNC flags for the wFlags parameter of the sndPlaySound function, as in the following example, the sound continues to play repeatedly.

sndPlaySound("C:\\SOUNDS\\BELLS.WAV", SND_LOOP | SND_ASYNC);

If you want to "loop" a sound, you must play it asynchronously. You cannot use the SND_SYNC flag with the SND_LOOP flag. A looped sound continues to play until sndPlaySound is called to play another sound. To stop playing a looped or asynchronous sound without playing another sound, use the following statement.

sndPlaySound(NULL, 0);


Playing High-Level Audio WAVE Resources

You can also build WAVE files into an application as resources and use the sndPlaySound function to play these sounds by specifying the SND_MEMORY flag. The SND_MEMORY flag indicates that the lpszSoundName parameter is a pointer to an in-memory image of the WAVE file. To include a WAVE file as a resource in an application, add the following entry to the application's resource script (.RC) file.

soundName WAVE c:\sounds\bells.wav

The name soundName is a placeholder for a name that you supply to refer to this WAVE resource. WAVE resources are loaded and accessed just like other application-defined Windows resources. The function in the following example plays a specified WAVE resource.

/* Plays a specified WAVE resource. */

BOOL PlayResource(LPSTR lpName)

{

    BOOL bRtn;

    LPSTR lpRes;

    HANDLE hResInfo, hRes;

    /* Find the WAVE resource. */

    hResInfo = FindResource(hInst, lpName, "WAVE");

    if (hResInfo == NULL)

        return FALSE;

    /* Load the WAVE resource. */

    hRes = LoadResource(hInst, hResInfo);

    if (hRes == NULL)

        return FALSE;

    /* Lock the WAVE resource and play it. */

    lpRes = LockResource(hRes);

    if (lpRes != NULL) {

        bRtn = sndPlaySound(lpRes, SND_MEMORY | SND_SYNC |

            SND_NODEFAULT);

        UnlockResource(hRes);

    }

    else

        bRtn = 0;

    /* Free the WAVE resource and return success or failure. */

    FreeResource(hRes);

    return bRtn;

}

To play a WAVE resource by using this function, pass to the function a pointer to a string containing the name of the resource, as shown in the following example.

PlayResource("soundName");


Playing High-Level Audio Sounds Specified in the Registry

The sndPlaySound function also plays waveform sounds referred to by a key-name in the [sounds] section of the registry. This enables users to assign their own sounds to system alerts and warnings, or to user actions such as mouse-button click. For example, the [sounds] section of the registry might look like the following.

[sounds]

SystemDefault=C:\SOUNDS\BUMMER.WAV, Says BUMMER

SystemAsterisk=C:\SOUNDS\WHALES.WAV, Whale sounds

SystemExclamation=C:\SOUNDS\LASER.WAV, Laser gun sounds

SystemHand=C:\SOUNDS\OHOH.WAV, Says OH-OH

SystemQuestion=C:\SOUNDS\JIBERISH.WAV, Person mumbling

SystemStart=C:\SOUNDS\CHORD.WAV, Plays a chord

MouseClick=C:\SOUNDS\CLICK.WAV, Recording of a clicking sound

To play a sound identified by a registry entry, call sndPlaySound with the lpszSoundName parameter pointing to a string that contains the name of the entry that identifies the sound. For example, to play the sound associated with the MouseClick entry in the [sounds] section of the registry and wait for the sound to finish before returning, use the following statement.

sndPlaySound("MouseClick", SND_SYNC);

If the specified registry entry or the waveform file it identifies does not exist, or if the sound does not fit into the available physical memory, sndPlaySound plays the default system sound specified by the SystemDefault entry. If there is no SystemDefault entry, sndPlaySound fails without producing any sound. If you don't want the default system sound to play, specify the SND_NODEFAULT flag, as in the following example.

sndPlaySound("MouseClick", SND_SYNC | SND_NODEFAULT);

Note  The sndPlaySound function always searches the [sounds] section of the registry for a keyname matching the lpszSoundName parameter before attempting to load a file with this name.

The [sounds] section of the registry includes an optional string following the waveform filename for descriptive text about the sound in the file. This descriptive text is displayed in the Sound option of the Control Panel.


Playing System-Alert Sounds

The MessageBeep function uses the waveform audio hardware to produce a variety of user-selectable sounds.

When you call MessageBeep, it searches the [sounds] section of the registry for the WAVE file that corresponds to the specified alert level. Following are the registry entries for system-alert sounds.

Registry Entry	Description
SystemDefault	Identifies the sound produced when the MessageBeep function is called with the wAlert  parameter set to an invalid alert level or when the requested alert sound can't be found. This is called the default system sound.
SystemAsterisk	Identifies the sound produced when MessageBeep is called with wAlert set to MB_ICONASTERISK.
SystemExclamation	Identifies the sound produced when MessageBeep is called with wAlert set to MB_ICONEXCLAMATION.
SystemHand	Identifies the sound produced when MessageBeep is called with wAlert set to MB_ICONHAND.
SystemQuestion	Identifies the sound produced when MessageBeep is called with wAlert set to MB_ICONQUESTION.
If MessageBeep is called with wAlert set to zero, it plays the default system sound. If wAlert is set to −1, MessageBeep uses the computer speaker to produce a standard beep sound. If MessageBeep can't play the requested sound, it plays the default system sound. If it can't play the default system sound, then it produces a beep sound using the computer speaker.

The Sound option of the Control Panel enables users to set these registry entries to customize their environment for system-alert sounds. It also enables users to disable these alert sounds.


Playing and Recording Audio Using the Media Control Interface

The Media Control Interface (MCI) provides a high-level interface for controlling both internal and external media devices. It provides support for playing wave- form, MIDI, and compact disc audio and for recording waveform audio. MCI is the easiest way for multimedia applications to play and record audio.

MCI uses device drivers to interpret and execute high-level MCI commands. MCI device drivers can stream digital audio and MIDI data directly from a storage device to the appropriate device driver, allowing applications to play files too large to fit in available physical memory. This data streaming takes place in the background while an application is running. The application is responsible only for setting up MCI and telling it to start playing or recording.

MCI provides two types of interface: command-message and command-string. This section explains how to use the command-message interface for waveform, MIDI, and compact disc audio devices. For an introduction to MCI and for information about the command-string interface, see Media Control Interface.


MCI Audio Data Types

The MMSYSTEM.H header file defines data types and function prototypes for MCI. You must include this header file in any source-code module that uses MCI functions.

Following are the data types for structures used with extended MCI commands related to audio.

Type	Description
MCI_SEQ_SET_PARMS	Specifies a structure for the MCI_SET command message for MIDI sequencer devices.
MCI_WAVE_DELETE_PARMS	Specifies a structure for the MCI_DELETE command message for waveform audio devices.
MCI_WAVE_OPEN_PARMS	Specifies a structure for the MCI_OPEN command message for waveform audio devices.
MCI_WAVE_SET_PARMS	Specifies a structure for the MCI_SET command message for waveform audio devices.


MCI Audio Commands

MCI provides a standard set of commands applying to all types of media devices. Some of these commands can be extended to accommodate unique features of a particular type of device.

Following are the MCI command messages that perform common audio playback and recording tasks.

MCI command message	Audio task
MCI_OPEN	Open an audio device.
MCI_CLOSE	Close an audio device.
MCI_PLAY	Play all or part of audio selection; resume playback from pause.
MCI_STOP	Stop playback.
MCI_PAUSE	Pause playback.
MCI_SEEK	Change current location.
MCI_CUE	Cue a device so playback or recording begins with minimum delay.
MCI_RECORD	Begin recording on a waveform audio device.
MCI_SAVE	Save a recorded waveform audio file.
MCI_INFO	Query device information such as the product name and the name of the device element currently associated with the device (returns information in string format).
MCI_GETDEVCAPS	Query device capabilities such as the device name and number of inputs and outputs (if the device can record).
MCI_STATUS	Query device status such as current playback position, media length, media format, time format, record level, CD audio track, and MIDI sequencer tempo.
MCI_SET	Set device parameters such as time format, waveform data format, and MIDI sequencer tempo.


Opening MCI Audio Devices

MCI requires that audio devices be opened before they can be accessed. Use the MCI_OPEN command message along with the MCI_OPEN_PARMS structure to open an audio device and obtain an MCI device identifier. Subsequent commands use this device identifier to identify the device to receive the command.

The MCI device identifier is returned in the wDeviceID member. Always check the return value of the mciSendCommand function after sending an MCI_OPEN command message before using this device identifier. A nonzero return value indicates that there was an error in opening the device and that the returned device identifier is not valid.

For waveform audio devices, you can use an extended structure, MCI_WAVE_OPEN_PARMS. This structure has a dwBufferSeconds member to specify the number of seconds of buffering used by the MCI waveform device driver. If you use this member, you must specify the MCI_WAVE_OPEN_BUFFER flag for the dwParam1 parameter of mciSendCommand to validate the member.

If you do not want to specify the number of seconds of buffering for the driver to use, you can use the MCI_WAVE_OPEN_PARMS structure when you open waveform audio devices.

When you open a simple device, such as a compact disc audio device, you must specify the device name. When you open a compound device, such as a waveform or MIDI sequencer device, the device name is optional. Use the lpstrDeviceType member of the MCI_OPEN_PARMS structure to specify the device name. MCI lets you use a string or a constant for this member. Following are the strings and constants for MCI audio devices.

Device	String	Constant
Compact disc	cdaudio	MCI_DEVTYPE_CD_AUDIO
Waveform	waveaudio	MCI_DEVTYPE_WAVEFORM_AUDIO
MIDI sequencer	sequencer	MCI_DEVTYPE_SEQUENCER
A string is the default format for specifying device names. If you use a constant to specify the device name, you must specify the MCI_OPEN_TYPE_ID flag in addition to the MCI_OPEN_TYPE flag.


Opening Waveform and MIDI Sequencer Devices

Waveform and MIDI sequencer devices are compound devices. Compound devices require an associated device element — a WAVE or MIDI file. There are three ways to open compound devices:

•	Specify only the device name.

•	Specify only the device element and let MCI select the device associated with the file extension of the device element.

•	Specify both the device name and the device element.

Specify only the device name when opening a device to query its capabilities with the MCI_GETDEVCAPS command message and when you plan to use the device to play more than one device element.

If you don't specify a device name when you open a compound device, MCI chooses an appropriate device type by comparing the file extension of the device element with entries in the [mci extensions] section of the registry. The following example uses this technique to open a MIDI sequencer device to play a MIDI file named CHOPIN.RMI.

UINT wDeviceID;

MCI_OPEN_PARMS mciOpenParms;

.ifdef REF

    .

    .

    .

.endif

/* Open the device by specifying only the device element. */

mciOpenParms.lpstrElementName = "CHOPIN.RMI";

if (mciSendCommand(0,                           /* device ID */

        MCI_OPEN,                               /* command   */

        MCI_OPEN_ELEMENT,                       /* flags     */

        (DWORD) (LPVOID) &mciOpenParms))  /* parameter block */

    /* Error, unable to open device. */

    return FALSE;

else

    /* Device opened successfully. Get the device ID. */

    wDeviceID = mciOpenParms.wDeviceID;

Instead of letting MCI choose the device, you can specify the device name when you open the device. The following example uses this technique to open a waveform audio device to play the BELLS.WAV file. This example uses a string to specify the device name. For an example using a constant to specify the device name, see Opening Compact Disc Devices.

UINT wDeviceID;

MCI_OPEN_PARMS mciOpenParms;

.ifdef REF

    .

    .

    .

.endif

/*

 * Open the device by specifying both the device

 * element and the device name.

 */

mciOpenParms.lpstrDeviceType = "waveaudio";

mciOpenParms.lpstrElementName = "C:\\SOUNDS\\BELLS.WAV";

if (mciSendCommand(0,                           /* device ID */

        MCI_OPEN,                               /* command   */

        MCI_OPEN_ELEMENT | MCI_OPEN_TYPE,       /* flags     */

        (DWORD) (LPVOID) &mciOpenParms))  /* parameter block */

    /* Error, unable to open device. */

    return FALSE;

else

    /* Device opened successfully. Get the device ID. */

    wDeviceID = mciOpenParms.wDeviceID;


Using the MIDI Mapper With the MCI Sequencer

The MIDI Mapper is the default output device for the MCI MIDI sequencer. It provides standard patch services for device-independent playback of MIDI files. Applications that use the MCI sequencer to play MIDI files should use the MIDI Mapper. For details about the MIDI Mapper, see The MIDI Mapper. For information about authoring device-independent MIDI files, see Authoring MIDI Files.

When you open the MCI MIDI sequencer, MCI attempts to select the MIDI Mapper as the output device. If the MIDI Mapper is unavailable because it is already in use, MCI selects another MIDI output device.

Note  The MIDI Mapper currently supports only one client at a time in the current versions of Microsoft Windows NT.

After opening the sequencer, you should check to see if the MIDI Mapper was available and was selected as the output device. The following example uses the MCI_STATUS command message to verify that the MIDI Mapper is the output device for the MCI sequencer.

UINT wDeviceID;

DWORD dwReturn;

MCI_STATUS_PARMS mciStatusParms;

.ifdef REF

    .

    .

    .

.endif

/* Make sure the opened device is the MIDI Mapper. */

mciStatusParms.dwItem = MCI_SEQ_STATUS_PORT;

if (dwReturn = mciSendCommand(wDeviceID, MCI_STATUS,

        MCI_STATUS_ITEM, (DWORD)(LPVOID) &mciStatusParms)) {

    /* Error sending MCI_STATUS command. */

}

if (LOWORD(mciStatusParms.dwReturn) == MIDI_MAPPER) {

    /* The MIDI Mapper is the output device. */

}

else {

    /* The MIDI Mapper is not the output device. */

}

MCI also provides a command message that explicitly selects the MIDI Mapper as the output device for the sequencer. The following example uses the MCI_SET command message to select the MIDI Mapper as the output device for the MCI sequencer.

UINT wDeviceID;

DWORD dwReturn;

MCI_SEQ_SET_PARMS mciSeqSetParms;

.ifdef REF

    .

    .

    .

.endif

/* Set the MIDI Mapper as the output port for the open device. */

mciSeqSetParms.dwPort = MIDI_MAPPER;

if (dwReturn = mciSendCommand(wDeviceID, MCI_SET, MCI_SEQ_SET_PORT,

                              (DWORD)(LPVOID) &mciSeqSetParms)) {

    /* Error, unable to set Mapper as output port. */

}

Before querying the sequencer or setting an output port, you must successfully open the sequencer. Both of the previous examples assume that the wDeviceID parameter contains a valid device identifier for the sequencer.


Opening Compact Disc Devices

Because a compact disc audio device is a simple device, you need only specify the device name when opening it by using either a string or a constant device identifier. The following example opens a compact disc device by using a constant device identifier to specify the device name.

UINT wDeviceID;

MCI_OPEN_PARMS mciOpenParms;

.ifdef REF

    .

    .

    .

.endif

/* Open the device by specifying a constant device ID. */

mciOpenParms.lpstrDeviceType = (LPCSTR) MCI_DEVTYPE_CD_AUDIO;

if (mciSendCommand(0,                           /* device ID */

        MCI_OPEN,                               /* command   */

        MCI_OPEN_TYPE | MCI_OPEN_TYPE_ID,       /* flags     */

        (DWORD) (LPVOID) &mciOpenParms))  /* parameter block */

    /* Error, unable to open device. */

    return FALSE;

else

    /* Device opened successfully. Get the device ID. */

    wDeviceID = mciOpenParms.wDeviceID;


Handling High-Level Audio MCI Errors

Always check the return value of the mciSendCommand function. If it indicates an error, you can use the mciGetErrorString function to get a textual description of the error. You can also interpret the error code yourself; MMSYSTEM.H defines constants for MCI error return codes.

Note  To interpret an error return value from mciSendCommand yourself, mask the high-order word; the low-order word contains the error code. However, if you pass the error return value to the mciGetErrorString function, you must pass the entire doubleword value.

The following example function takes the MCI error code specified by dwError, passes it to mciGetErrorString, and displays the resulting textual error description by using the MessageBox function.

/*

 * Uses mciGetErrorString to get a

 * text description of an MCI error.

 * Displays the error description by using MessageBox.

 */

void showError(DWORD dwError)

{

    char szErrorBuf[MAXERRORLENGTH];

    MessageBeep(MB_ICONEXCLAMATION);

    if(mciGetErrorString(dwError, (LPSTR) szErrorBuf,

            MAXERRORLENGTH))

        MessageBox(hMainWnd, szErrorBuf,

                "MCI Error", MB_ICONEXCLAMATION);

    else

        MessageBox(hMainWnd, "Unknown Error", "MCI Error",

                MB_ICONEXCLAMATION);

}


Starting Playback

Once you successfully open an MCI audio device, you can use the MCI_PLAY command message along with the MCI_PLAY_PARMS structure to begin playback. MMSYSTEM.H defines MCI_PLAY_PARMS as follows.

typedef struct {

        DWORD   dwCallback; /* callback for MCI_NOTIFY flag */

        DWORD   dwFrom;     /* playback begin position */

        DWORD   dwTo;       /* playback end position */

} MCI_PLAY_PARMS;

Playback begins at the current position in the device element. When a device element is opened, the current position is set to the beginning of the medium. After a device element is played, the current position is at the end of the medium. You can use the MCI_SEEK command message to change the current position. For more information about MCI_SEEK, see Changing the Current Position.

You can also set beginning and ending positions for playback by specifying the MCI_FROM and MCI_TO flags with the MCI_PLAY command message. If you specify one of these flags, you must fill in the corresponding dwFrom or dwTo member in the MCI_PLAY_PARMS structure with the desired beginning or ending time. If you are using a time format other than the default time format, you must set the time format before specifying a beginning or ending time with MCI_PLAY.


Example: Playing a WAVE File

The following example function opens a waveform device and plays the WAVE file specified by the lpszWAVEFileName parameter.

/*

 * Plays a given WAVE file by using MCI_OPEN, MCI_PLAY.

 * Returns when playback

 * begins. Returns 0L on success;

 * otherwise returns an MCI error code.

 */

DWORD playWAVEFile(HWND hWndNotify, LPSTR lpszWAVEFileName)

{

    UINT wDeviceID;

    DWORD dwReturn;

    MCI_OPEN_PARMS mciOpenParms;

    MCI_PLAY_PARMS mciPlayParms;

    /*

     * Open the device by specifying the

     * device name and device element.

     * MCI will choose a device capable

     * of playing the given file.

     */

    mciOpenParms.lpstrDeviceType = "waveaudio";

    mciOpenParms.lpstrElementName = lpszWAVEFileName;

    if (dwReturn = mciSendCommand(0, MCI_OPEN,

            MCI_OPEN_TYPE | MCI_OPEN_ELEMENT,

            (DWORD)(LPVOID) &mciOpenParms)) {

        /*

         * Failed to open device;

         * don't close it, just return error.

         */

        return dwReturn;

    }

    /* Device opened successfully. Get the device ID. */

    wDeviceID = mciOpenParms.wDeviceID;

    /*

     * Begin playback. The window-procedure function

     * for the parent window is notified with an

     * MM_MCINOTIFY message when playback is

     * complete. The window procedure then

     * closes the device.

     */

    mciPlayParms.dwCallback = (DWORD) hWndNotify;

    if (dwReturn = mciSendCommand(wDeviceID, MCI_PLAY,

            MCI_NOTIFY, (DWORD)(LPVOID) &mciPlayParms)) {

        mciSendCommand(wDeviceID, MCI_CLOSE, 0, NULL);

        return dwReturn;

    }

    return 0;

}


Example: Playing a MIDI File

The following example function opens a MIDI sequencer device, verifies that the MIDI Mapper was selected as the output port, plays the MIDI file specified by the lpszMIDIFileName parameter, and closes the device after playback is complete.

/*

 * Plays a given MIDI file using MCI_OPEN, MCI_PLAY.

 * Returns as soon as playback begins. The window

 * procedure function for the given window is notified

 * when playback is complete. Returns 0L on success;

 * otherwise returns an MCI error code.

 */

DWORD playMIDIFile(HWND hWndNotify, LPSTR lpszMIDIFileName)

{

    UINT wDeviceID;

    DWORD dwReturn;

    MCI_OPEN_PARMS mciOpenParms;

    MCI_PLAY_PARMS mciPlayParms;

    MCI_STATUS_PARMS mciStatusParms;

    /*

     * Open the device by specifying the

     * device name and device element.

     * MCI will attempt to choose the

     * MIDI Mapper as the output port.

     */

    mciOpenParms.lpstrDeviceType = "sequencer";

    mciOpenParms.lpstrElementName = lpszMIDIFileName;

    if (dwReturn = mciSendCommand(NULL, MCI_OPEN,

            MCI_OPEN_TYPE | MCI_OPEN_ELEMENT,

            (DWORD)(LPVOID) &mciOpenParms)) {

        /*

         * Failed to open device;

         * don't close it, just return error.

         */

        return dwReturn;

    }

    /* Device opened successfully. Get the device ID. */

    wDeviceID = mciOpenParms.wDeviceID;

    /* See if the output port is the MIDI Mapper. */

    mciStatusParms.dwItem = MCI_SEQ_STATUS_PORT;

    if (dwReturn = mciSendCommand(wDeviceID, MCI_STATUS,

            MCI_STATUS_ITEM,

            (DWORD)(LPVOID) &mciStatusParms)) {

        mciSendCommand(wDeviceID, MCI_CLOSE, 0, NULL);

        return dwReturn;

    }

    /*

     * The output port is not the MIDI Mapper.

     * Ask if user wants to continue.

     */

    if (LOWORD(mciStatusParms.dwReturn) != MIDI_MAPPER) {

        if (MessageBox(hMainWnd,

                "The MIDI Mapper is not available. Continue?",

                "", MB_YESNO) == IDNO) {

            /*

             * User does not want to continue. Not an error;

             * just close the device and return.

             */

            mciSendCommand(wDeviceID, MCI_CLOSE, 0, NULL);

            return 0;

        }

    }

    /*

     * Begin playback. The window procedure function

     * for the parent window is notified with an

     * MM_MCINOTIFY message when playback is complete.

     * The window procedure then closes the device.

     */

    mciPlayParms.dwCallback = (DWORD) hWndNotify;

    if (dwReturn = mciSendCommand(wDeviceID, MCI_PLAY,

            MCI_NOTIFY, (DWORD)(LPVOID) &mciPlayParms)) {

        mciSendCommand(wDeviceID, MCI_CLOSE, 0, NULL);

        return dwReturn;

    }

    return 0;

}


Example: Playing a Compact Disc Track

The following example function opens a compact disc device, plays the track specified by the wTrack parameter, and closes the device after playback is complete.

/*

 * Plays a given compact disc track using

 * MCI_OPEN, MCI_PLAY. Returns as

 * soon as playback begins. The window procedure

 * function for the given window will be notified

 * when playback is complete. Returns 0L on

 * success; otherwise, it returns an MCI error code.

 */

DWORD playCDTrack(HWND hWndNotify, BYTE bTrack)

{

    UINT wDeviceID;

    DWORD dwReturn;

    MCI_OPEN_PARMS mciOpenParms;

    MCI_SET_PARMS mciSetParms;

    MCI_PLAY_PARMS mciPlayParms;

    /*

     * Open the compact disc device by specifying

     * the device name.

     */

    mciOpenParms.lpstrDeviceType = "cdaudio";

    if (dwReturn = mciSendCommand(NULL, MCI_OPEN,

            MCI_OPEN_TYPE, (DWORD)(LPVOID) &mciOpenParms)) {

        /*

         * Failed to open device;

         * don't close it, just return error.

         */

        return dwReturn;

    }

    /* Device opened successfully, get the device ID. */

    wDeviceID = mciOpenParms.wDeviceID;

    /* Set the time format to track/minute/second/frame. */

    mciSetParms.dwTimeFormat = MCI_FORMAT_TMSF;

    if (dwReturn = mciSendCommand(wDeviceID, MCI_SET,

            MCI_SET_TIME_FORMAT, (DWORD)(LPVOID) &mciSetParms)) {

        mciSendCommand(wDeviceID, MCI_CLOSE, 0, NULL);

        return dwReturn;

    }

    /*

     * Begin playback from the given track and play

     * until the beginning of the next track. The window

     * procedure function for the parent window will be

     * notified with an MM_MCINOTIFY message when playback

     * is complete. Unless the play command fails, the

     * window procedure closes the device.

     */

    mciPlayParms.dwFrom = MCI_MAKE_TMSF(bTrack, 0, 0, 0);

    mciPlayParms.dwTo = MCI_MAKE_TMSF(bTrack + 1, 0, 0, 0);

    mciPlayParms.dwCallback = (DWORD) hWndNotify;

    if (dwReturn = mciSendCommand(wDeviceID, MCI_PLAY,

            MCI_FROM | MCI_TO | MCI_NOTIFY,

            (DWORD)(LPVOID) &mciPlayParms)) {

        mciSendCommand(wDeviceID, MCI_CLOSE, 0, NULL);

        return dwReturn;

    }

    return 0;

}

To specify a track-relative position with a compact disc device, you must use the track/minute/second/frame time format. For details, see Setting the Time Format.


Changing the Current Position

To change the current position in a device element, use the MCI_SEEK command message along with the MCI_TO flag and the MCI_SEEK_PARMS structure. MMSYSTEM.H defines MCI_SEEK_PARMS as follows.

typedef struct {

        DWORD   dwCallback; /* callback for MCI_NOTIFY flag */

        DWORD   dwTo;       /* seek position */

} MCI_SEEK_PARMS;

If you use the dwTo member to specify a seek position with MCI_SEEK, you should query the time format and set it, if necessary.

In addition to specifying a position with the dwTo member, you can specify the MCI_SEEK_TO_START or MCI_SEEK_TO_END flags for the dwParam1 parameter of the mciSendCommand function to find the starting and ending positions of the device element. If you use one of these flags, don't specify the MCI_TO flag.


Setting the Time Format

Use the MCI_SET command message along with the MCI_SET_PARMS structure to set the time format for an open device. Set the dwTimeFormat member to one of the following constants.

Constant	Time format
MCI_FORMAT_BYTES	Bytes (in pulse code modulated [PCM] format files)
MCI_FORMAT_MILLISECONDS	Milliseconds
MCI_FORMAT_MSF	Minute/second/frame
MCI_FORMAT_SAMPLES	Samples
MCI_FORMAT_SMPTE_24	SMPTE, 24 frame
MCI_FORMAT_SMPTE_25	SMPTE, 25 frame
MCI_FORMAT_SMPTE_30	SMPTE, 30 frame
MCI_FORMAT_SMPTE_30DROP	SMPTE, 30 frame drop
MCI_FORMAT_TMSF	Track/minute/second/frame
MCI_SEQ_FORMAT_SONGPTR	MIDI song pointer
The following example sets the time format to milliseconds on the device specified by wDeviceID:

UINT wDeviceID;

MCI_SET_PARMS mciSetParms;

.ifdef REF

    .

    .

    .

.endif

/* Set time format to milliseconds. */

mciSetParms.dwTimeFormat = MCI_FORMAT_MILLISECONDS;

if (mciSendCommand(wDeviceID, MCI_SET, MCI_SET_TIME_FORMAT,

                   (DWORD) &mciSetParms))

    /* Error, unable to set time format. */

    return FALSE;

else

    /* Time format set successfully. */

    return TRUE;


Using the Minute/Second/Frame Time Format

In the minute/second/frame time format specified with the MCI_FORMAT_MSF constant, the time is relative to the beginning of the medium. The time is packed into a double as follows.

Word	Byte	Contents
High-order word	High-order byte	Unused
	Low-order byte	Frames
Low-order word	High-order byte	Seconds
	Low-order byte	Minutes
The MMSYSTEM.H header file defines the following macros to get and set elements of a minute/second/frame packed doubleword.

Macro	Description
MCI_MSF_MINUTE	Gets minute value in a minute/second/frame doubleword.
MCI_MSF_SECOND	Gets second value in a minute/second/frame doubleword.
MCI_MSF_FRAME	Gets frame value in a minute/second/frame doubleword.
MCI_MAKE_MSF	Sets minute, second, and frame values in a minute/second/frame doubleword.
Note  The first few seconds of audio compact discs contain table-of-contents data. To play from the beginning of a disc using the minute/second/frame time format, use the MCI_STATUS command message to get the position of the first track and play from that position.


Using the Track/Minute/Second/Frame Time Format

In the track/minute/second/frame time format specified with the MCI_FORMAT_TMSF constant, the time is relative to the beginning of the specified track. The time is packed into a doubleword, as follows.

Word	Byte	Contents
High-order word	High-order byte	Frames
	Low-order byte	Seconds
Low-order word	High-order byte	Minutes
	Low-order byte	Track
The MMSYSTEM.H header file defines the following macros to get and set elements of a track/minute/second/frame packed doubleword.

Macro	Description
MCI_TMSF_TRACK	Gets track value in a track/minute/second/frame doubleword.
MCI_TMSF_MINUTE	Gets minute value in a track/minute/second/frame doubleword.
MCI_TMSF_SECOND	Gets second value in a track/minute/second/frame doubleword.
MCI_TMSF_FRAME	Gets frame value in a track/minute/second/frame doubleword.
MCI_MAKE_TMSF	Sets track, minute, second, and frame values in a track/minute/second/frame doubleword.


Using the SMPTE Time Formats

Society of Motion Picture and Television Engineers (SMPTE) time formats are based on standard time formats developed for the motion picture and television industries. For SMPTE time formats, the time is packed into a doubleword, as shown in the following table follows.

Word	Byte	Contents
High-order word	High-order byte	Frames
	Low-order byte	Seconds
Low-order word	High-order byte	Minutes
	Low-order byte	Hours


Closing MCI Audio Devices

After you finish using an MCI device, you must use the MCI_CLOSE command messages to close the device. If you are playing a compound device, such as a waveform or MIDI device, and want to play a different device element using the same device, close the device and reopen it using the new device element.

Note  If you're playing multiple device elements with the same device, you'll get better performance if you open the device by explicitly specifying its name, then open, play, and close the individual device elements separately. Don't close the device until you have finished playing all of the device elements. Otherwise, the driver is reloaded each time you open the device.


Getting Information About Devices and Media

Use the MCI_STATUS command message along with the MCI_STATUS_PARMS structure to get information about the status of an open device and its associated device element.

Before using the MCI_STATUS command message, you must identify the status item to query for by putting a constant in the dwItem member of the structure. Select a topic below to view the constants and their corresponding status items for the different audio device types.

All Audio Devices
Waveform Devices
Compact Disc Devices
MIDI Sequencer Devices


All Audio Devices

Constant	Status item
MCI_STATUS_LENGTH	Length of the medium
MCI_STATUS_POSITION	Current position
MCI_STATUS_MODE	Current mode
MCI_STATUS_TIME_FORMAT	Time format
MCI_STATUS_READY	Ready state


Waveform Devices

Constant	Status item
MCI_WAVE_STATUS_BLOCKALIGN	Block alignment
MCI_WAVE_STATUS_FORMATTAG	Format tag
MCI_WAVE_STATUS_CHANNELS	Number of channels
MCI_WAVE_STATUS_SAMPLESPERSEC	Sample rate
MCI_WAVE_STATUS_AVGBYTESPERSEC	Average bytes per second
MCI_WAVE_STATUS_BITSPERSAMPLE	Bits per sample (in PCM format files)
MCI_WAVE_STATUS_LEVEL	Record level


Compact Disc Devices

Constant	Status item
MCI_STATUS_NUMBER_OF_TRACKS	Number of tracks
MCI_STATUS_MEDIA_PRESENT	Media present
MCI_STATUS_CURRENT_TRACK	Current track


MIDI Sequencer Devices

Constant	Status item
MCI_SEQ_STATUS_TEMPO	Tempo
MCI_SEQ_STATUS_PORT	Port
MCI_SEQ_STATUS_OFFSET	SMPTE offset
MCI_SEQ_STATUS_DIVTYPE	Division type of file


Getting Track-Relative Information for Compact Disc Devices

For compact disc devices, you can get the starting position and length of a track by specifying the MCI_TRACK flag and setting the dwTrack member of the MCI_STATUS_PARMS structure to the desired track number. To get the starting position of a track, set the dwItem member to MCI_STATUS_POSITION. To get the length of a track, set dwItem to MCI_STATUS_LENGTH. The following function gets the number of tracks on the disc and the starting position of each track. It then uses the MessageBox function to report the starting positions of the tracks.

/*

 * Uses the MCI_STATUS command to get and

 * display the starting times for the tracks

 * on a compact disc. Returns 0L on success;

 * otherwise, it returns an MCI error code.

 */

DWORD getCDTrackStartTimes(void)

{

    UINT wDeviceID;

    int i, iNumTracks;

    DWORD dwReturn;

    DWORD *pMem;

    char szTempString[64];

    char szTimeString[512] = "\0"; /* enough for 20 tracks */

    MCI_OPEN_PARMS mciOpenParms;

    MCI_SET_PARMS mciSetParms;

    MCI_STATUS_PARMS mciStatusParms;

    /* Open the compact disc device by specifying the device name.

     */

    mciOpenParms.lpstrDeviceType = "cdaudio";

    if (dwReturn = mciSendCommand(NULL, MCI_OPEN,

            MCI_OPEN_TYPE,

            (DWORD)(LPVOID) &mciOpenParms)) {

        /*

         * Failed to open device.

         * Don't have to close it; just return error.

         */

        return dwReturn;

    }

    /* Device opened successfully. Get the device ID. */

    wDeviceID = mciOpenParms.wDeviceID;

    /* Set the time format to minute/second/frame format. */

    mciSetParms.dwTimeFormat = MCI_FORMAT_MSF;

    if (dwReturn = mciSendCommand(wDeviceID, MCI_SET,

            MCI_SET_TIME_FORMAT,

            (DWORD)(LPVOID) &mciSetParms)) {

        mciSendCommand(wDeviceID, MCI_CLOSE, 0, NULL);

        return dwReturn;

    }

    /* Get the number of tracks; limit to number

     * we can display (20).

     */

    mciStatusParms.dwItem = MCI_STATUS_NUMBER_OF_TRACKS;

    if (dwReturn = mciSendCommand(wDeviceID, MCI_STATUS,

            MCI_STATUS_ITEM,

            (DWORD)(LPVOID) &mciStatusParms)) {

        mciSendCommand(wDeviceID, MCI_CLOSE, 0, NULL);

        return dwReturn;

    }

    iNumTracks = mciStatusParms.dwReturn;

    iNumTracks = min(iNumTracks, 20);

    /* Allocate memory to hold starting positions. */

    pMem = (DWORD *)LocalAlloc(LPTR, iNumTracks * sizeof(DWORD));

    if (pMem == NULL) {

        mciSendCommand(wDeviceID, MCI_CLOSE, 0, NULL);

        return 0xFFFFFFFF;

    }

    /*

     * For each track, get and save the starting position and

     * build a string containing starting positions.

     */

    for(i = 1; i <= iNumTracks; i++) {

        mciStatusParms.dwItem = MCI_STATUS_POSITION;

        mciStatusParms.dwTrack = i;

        if (dwReturn = mciSendCommand(wDeviceID, MCI_STATUS,

                MCI_STATUS_ITEM | MCI_TRACK,

                (DWORD)(LPVOID) &mciStatusParms)) {

            mciSendCommand(wDeviceID, MCI_CLOSE, 0, NULL);

            return dwReturn;

        }

        pMem[i-1] = mciStatusParms.dwReturn;

        wsprintf(szTempString, "Track %2d - %02d:%02d:%02d\n",

                 i, MCI_MSF_MINUTE(pMem[i-1]),

                 MCI_MSF_SECOND(pMem[i-1]),

                 MCI_MSF_FRAME(pMem[i-1]));

        lstrcat(szTimeString, szTempString);

    }

    /* Use MessageBox to display starting times. */

    MessageBox(hMainWnd, szTimeString, "Track Starting Position",

               MB_ICONINFORMATION);

    /* Free memory and close the device. */

    LocalFree((HANDLE) pMem);

    if (dwReturn = mciSendCommand(wDeviceID,

            MCI_CLOSE, 0, NULL)) {

            return dwReturn;

    }

    return 0;

}


Recording With Waveform Audio Devices

MCI supports recording with waveform audio devices. You can insert or overwrite recorded information in an existing file or record into a new file. To open an existing file for recording, open a waveform device and device element as you would open them for playback. To record into a new file, open the device but specify a zero-length filename for the device element.

When MCI creates a new file for recording, the waveform data format is set to a default format specified by the device driver. To use a format other than the default format, you can use the MCI_SET command message to change the format.

To begin recording, use the MCI_RECORD command message along with the MCI_RECORD_PARMS structure.

If you record to an existing file, you can use the MCI_TO and MCI_FROM flags to specify beginning and ending points for recording. For example, if you record to an existing file 20 seconds long, and you begin recording at 5 seconds and end recording at 10 seconds, you will have a recording 25 seconds long. It will contain 5 seconds of the original recording followed by the 5 seconds of new recording, and will end with the remaining 15 seconds of the original recording.

If you don't specify an ending position, recording continues until you send an MCI_STOP command message, or until the driver runs out of free disk space. If you record to a new file, you can omit the MCI_FROM flag or set it to 0 to start recording at the beginning of a new file. You can specify an ending position to terminate recording when recording to a new file.

If you record in overwrite mode to an existing file, you can use the MCI_TO and MCI_FROM flags to specify beginning and ending points of the waveform section that is to be overwritten. For example, if you record to an existing file 20 seconds long, and you begin recording at 5 seconds and end recording at 10 seconds, you still have a recording 20 seconds long. However, the section beginning at 5 seconds and ending at 10 seconds has been replaced.


Saving a Recorded File

When recording is complete, use the MCI_SAVE command message along with the MCI_SAVE_PARMS structure to save the recording before closing the device.

If you close the device without saving, the recorded data is lost.


Checking Input Levels on PCM Devices

To get the level of the input signal before recording on a pulse code modulated (PCM) waveform input device, use the MCI_STATUS command message. Specify the MCI_STATUS_ITEM flag and set the dwItem member in the MCI_STATUS_PARMS structure to MCI_WAVE_STATUS_LEVEL. The average input signal level is returned in the dwReturn member of the MCI_STATUS_PARMS structure. The left-channel value is in the high-order word, and the right- or mono-channel value is in the low-order word.

The input level is represented as an unsigned value. For 8-bit samples, this value is in the range 0 through 127 (0x7F). For 16-bit samples, it is in the range 0 through 32,767 (0x7FFF).


Example of Recording With a Waveform Audio Device

The following example function opens a waveform audio device with a new file, records for the specified time, plays the recording, and prompts the user to specify whether the recording should be saved as a file.

/*

 * Uses the MCI_OPEN, MCI_RECORD, MCI_SAVE commands to record and

 * save a waveform audio file. Returns 0L on success; otherwise,

 * returns an MCI error code.

 */

DWORD recordWAVEFile(DWORD dwMilliSeconds)

{

    UINT wDeviceID;

    DWORD dwReturn;

    MCI_OPEN_PARMS mciOpenParms;

    MCI_RECORD_PARMS mciRecordParms;

    MCI_SAVE_PARMS mciSaveParms;

    MCI_PLAY_PARMS mciPlayParms;

    /*

     * Open a waveform device with a new file for recording.

     */

    mciOpenParms.lpstrDeviceType = "waveaudio";

    mciOpenParms.lpstrElementName = "";

    if (dwReturn = mciSendCommand(0, MCI_OPEN,

            MCI_OPEN_ELEMENT | MCI_OPEN_TYPE,

            (DWORD)(LPVOID) &mciOpenParms)) {

        /*

         * Failed to open device. Don't close it; just return

         * error.

         */

        return dwReturn;

    }

    /* Device opened successfully. Get the device ID. */

    wDeviceID = mciOpenParms.wDeviceID;

    /*

     * Begin recording and record for the specified number

     * of milliseconds. Wait for recording to complete before

     * continuing. Assume the default time format for the

     * waveform device (milliseconds).

     */

    mciRecordParms.dwTo = dwMilliSeconds;

    if (dwReturn = mciSendCommand(wDeviceID, MCI_RECORD,

            MCI_TO | MCI_WAIT, (DWORD)(LPVOID) &mciRecordParms)) {

        mciSendCommand(wDeviceID, MCI_CLOSE, 0, NULL);

        return dwReturn;

    }

    /* Play the recording and query user to save the file. */

    mciPlayParms.dwFrom = 0;

    if (dwReturn = mciSendCommand(wDeviceID, MCI_PLAY,

            MCI_FROM | MCI_WAIT,

            (DWORD)(LPVOID) &mciPlayParms)) {

        mciSendCommand(wDeviceID, MCI_CLOSE, 0, NULL);

        return dwReturn;

    }

    if (MessageBox(hMainWnd, "Do you want to save this recording?",

            "", MB_YESNO) == IDNO) {

        mciSendCommand(wDeviceID, MCI_CLOSE, 0, NULL);

        return 0;

    }

    /*

     * Save the recording to a file named TEMPFILE.WAV. Wait for

     * the operation to finish before continuing.

     */

    mciSaveParms.lpfilename = "tempfile.wav";

    if (dwReturn = mciSendCommand(wDeviceID, MCI_SAVE,

            MCI_SAVE_FILE | MCI_WAIT,

            (DWORD)(LPVOID) &mciSaveParms)) {

        mciSendCommand(wDeviceID, MCI_CLOSE, 0, NULL);

        return dwReturn;

    }

    return 0;

}


Using the MCI MIDI Sequencer with High-Level Audio

The MCI MIDI sequencer plays standard MIDI files and Resource Interchange File Format (RIFF) MIDI files (RMID files). Standard MIDI files conform to the "Standard MIDI Files 1.0" specification. For information about this specification, see Introduction to Audio. Because RMID files are standard MIDI files with a RIFF header, information about standard MIDI files also applies to RMID files.

There are currently three variations of standard MIDI files. The MCI sequencer plays only two of these: format 0 and format 1 MIDI files.

Note  When the MCI MIDI sequencer encounters a MIDI file not marked as being authored for Windows, it displays a dialog box informing the user. MIDI files authored for Windows should be marked with the MARKMIDI utility program. For additional information about MARKMIDI, see Using the MARKMIDI Utility.

•	Querying for sequence division types

•	Querying and Setting the MIDI Tempo

•	Changing sequencer synchronization


Querying for Sequence Division Types

The division type of a MIDI sequence refers to the technique used to represent the time between MIDI events in the sequence. Use the MCI_STATUS command message and set the dwItem member of the MCI_STATUS_PARMS structure to MCI_SEQ_STATUS_DIVTYPE to determine the division type of a sequence.

If the MCI_STATUS command message succeeds, the dwReturn member of the MCI_STATUS_PARMS structure contains one of the following values to indicate the division type.

Value	Division type
MCI_SEQ_DIV_PPQN	PPQN (parts per quarter-note)
MCI_SEQ_DIV_SMPTE_24	SMPTE, 24 frames per second (fps)
MCI_SEQ_DIV_SMPTE_25	SMPTE, 25 fps
MCI_SEQ_DIV_SMPTE_30	SMPTE, 30 fps
MCI_SEQ_DIV_SMPTE_30DROP	SMPTE, 30 fps drop frame
You must know the division type of a sequence to change or query its tempo. You can't change the division type of a sequence by using the MCI sequencer.


Querying and Setting the MIDI Tempo

Use the MCI_STATUS command message and set the dwItem member of the MCI_STATUS_PARMS structure to MCI_SEQ_STATUS_TEMPO to get the tempo of a sequence. If the MCI_STATUS command message succeeds, the dwReturn member of the MCI_STATUS_PARMS structure contains the current tempo.

To change tempo, use the MCI_SET command message with the MCI_SEQ_SET_PARMS structure. Specify the MCI_SEQ_SET_TEMPO flag and set the value of the dwTempo member of the structure to the desired tempo.

The way tempo is represented depends on the division type of the sequence. If the division type is PPQN, the tempo is represented in beats per minute. If the division type is one of the SMPTE division types, the tempo is represented in frames per second. For information about determining the division type of a sequence, Querying for Sequence Division Types.


Changing Sequencer Synchronization

To change the synchronization mode of a sequencer device, use the MCI_SET command message with the MCI_SEQ_SET_MASTER and MCI_SEQ_SET_SLAVE flags. Two members in the MCI_SEQ_SET_PARMS structure, dwMaster and dwSlave, are used to specify the master and slave synchronization modes.

The master synchronization mode controls synchronization information sent by the sequencer to an output port. The slave synchronization mode controls where the sequencer gets its timing information to play a MIDI file. Following are the constants for the dwMaster member and their corresponding master synchronization modes.

Constant	Synchronization mode
MCI_SEQ_MIDI	MIDI Synchronization. Send timing information to output port using MIDI timing clock messages.
MCI_SEQ_SMPTE	SMPTE Synchronization. Send timing information to output port using MIDI quarter-frame messages.
MCI_SEQ_NONE	No Synchronization. Send no timing information.
Following are the constants for the dwSlave member and their corresponding slave synchronization modes.

Constant	Synchronization mode
MCI_SEQ_FILE	File Synchronization. Get timing information from MIDI file.
MCI_SEQ_MIDI	MIDI Synchronization. Get timing information from input port using MIDI timing clock messages.
MCI_SEQ_SMPTE	SMPTE Synchronization. Get timing information from input port using MIDI quarter-frame messages.
MCI_SEQ_NONE	No Synchronization. Get timing information from MCI commands only and ignore timing information (such as tempo changes) that are in the MIDI file.
Note  Currently, for master synchronization, the MCI MIDI sequencer supports only the No Synchronization mode (MCI_SEQ_NONE). For slave synchronization, it supports only the File Synchronization mode (MCI_SEQ_FILE) and the No Synchronization mode (MCI_SEQ_NONE).


The MIDI Mapper

The MIDI Mapper's standard patch services provide device-independent MIDI file playback for applications. You don't need to understand exactly how the MIDI Mapper works to use these services. The MIDI Mapper can be used with the MCI MIDI sequencer or with low-level MIDI output services.

To learn more about the MIDI Mapper or about authoring standard MIDI files for Windows, press the browse button (>>) to view more topics about how the MIDI Mapper works. For specific information about how to use the MIDI Mapper, see Using the MCI MIDI Sequencer or Low-Level Audio.


MIDI Notational Conventions

Unless stated otherwise, all references to MIDI channel numbers use the logical channel numbers 1 through 16. These logical channel numbers correspond to the physical channel numbers 0 through 15 that are actually part of the MIDI message. All references to MIDI program-change and key values use the physical values 0 through 127. All numbers are decimal unless preceded by 0x prefix, in which case they are hexadecimal.

In the discussion of the MIDI Mapper, the term source refers to the input side of the MIDI Mapper. The term destination refers to the output side of the MIDI Mapper. For example, a source channel is the MIDI channel of a message sent to the MIDI Mapper, and a destination channel is the MIDI channel of a message sent from the MIDI Mapper to an output device.


The MIDI Mapper and Windows

The MIDI Mapper is part of the system software. The following illustration shows how the MIDI Mapper relates to other elements of the audio services.

From the viewpoint of an application, the MIDI Mapper looks like another MIDI output device. The MIDI Mapper receives messages sent to it by the low-level MIDI output functions midiOutShortMsg and midiOutLongMsg. The MIDI Mapper modifies these messages and redirects them to a MIDI output device according to the current MIDI setup map. The current MIDI setup map is selected by the user by means of the MIDI Control Panel option. Only the user can select the current setup map; applications cannot change the current setup map.


The MIDI Mapper Architecture

The MIDI Mapper uses a MIDI setup map to determine how to translate and redirect messages it receives. A MIDI setup map consists of the following types of maps.

•	Channel map

•	Patch map

•	Key map

The following illustration shows the roles of channel, patch, and key maps in a MIDI setup map.


The Channel Map

The channel map affects all MIDI channel messages. MIDI channel messages include note-on, note-off, polyphonic-key-aftertouch, control-change, program- change, channel-aftertouch, and pitch-bend-change messages. The MIDI Mapper uses a single channel map with an entry for each of the 16 MIDI channels. Each channel-map entry specifies the following:

•	A destination channel for the MIDI message

•	A destination output device for the MIDI message

•	An optional patch map specifying other possible modifications for the MIDI message

The destination channel is set to one of the 16 MIDI channels. MIDI messages are modified to reflect each new channel assignment. For example, if the destination channel entry for MIDI channel 4 is set to 6, all MIDI messages sent to channel 4 will be mapped to channel 6, as shown in the following illustration.

In this example, the MIDI status byte 0x93 is mapped to 0x95. The low-order of a MIDI status byte specify the channel number. Source channels are set to either active or inactive. Messages sent to inactive source channels are ignored, so an inactive channel is in effect muted or turned off.

The destination output device is set to one of the available MIDI output devices. A MIDI output device can be an internal synthesizer or a physical MIDI output port.

MIDI system messages are MIDI messages (with status bytes) from 0xF0 to 0xFF. There is no channel associated with MIDI system messages, so they can't be mapped. MIDI system messages are sent to all MIDI output devices listed in a channel map.


Patch Maps

Each channel map entry can have an associated patch map. Patch maps affect MIDI program-change and volume-controller messages. Program-change messages tell a synthesizer to change the instrument sound (patch) for a specified channel. Volume-controller messages set the volume for a channel.

A patch map has a translation table with an entry for each of the 128 program-change values. Each patch map specifies the following:

•	A destination program-change value

•	A volume scalar

•	An optional key map

When program-change messages are received by the MIDI Mapper, the destination program-change value is substituted for the program-change value in the message. For example, if the destination program-change value for program-change 16 is 18, the MIDI Mapper modifies the MIDI program-change message as shown in the following illustration.


The Volume Scalar

The purpose of the volume scalar is to allow adjustments between the relative output levels of different patches on a synthesizer. For example, if the bass patch on a synthesizer is too loud compared with its piano patch, you can change the setup map to scale the bass volume down or the piano volume up.

The volume scalar specifies a percentage value for changing all MIDI main-volume controller messages that follow an associated program-change message. For example, if the volume scalar value is 50%, the MIDI Mapper modifies MIDI main-volume controller messages as shown in the following illustration:


Key Maps

Each entry in the patch-map translation table can have an associated key map. Key maps affect note-on, note-off, and polyphonic-key-aftertouch messages. A key map has a translation table with an entry for each of the 128 MIDI key values. For example, if the entry for key value 60 is 72, the MIDI Mapper modifies MIDI note-on messages as shown in the following illustration.

Key maps are useful with synthesizers that have key-based percussion instruments with a particular percussion sound assigned to each key. Key maps are usually assigned to the first patch in the patch maps on the percussion channels (10 and 16).


Summary of Maps and MIDI Messages

Following are the status bytes for MIDI messages and the map types that affect each message.

MIDI status	Description	Map types
0x80−0x8F	Note-off	Channel maps, key maps
0x90−0x9F	Note-on	Channel maps, key maps
0xA0−0xAF	Polyphonic-key-aftertouch	Channel maps, key maps
0xB0−0xBF	Control-change	Channel maps, patch maps
0xC0−0xCF	Program-change	Channel maps, patch maps
0xD0−0xDF	Channel-aftertouch	Channel maps
0xE0−0xEF	Pitch-bend-change	Channel maps
0xF0−0xFF	System	Not mapped
•	The high-order four bits represent the status value. The low-order four bits represent the channel information.

•	Patch maps affect only controller 7 (main volume).

•	System messages are sent to all devices listed in a channel map.


Authoring MIDI Files

The "MIDI 1.0 Detailed Specification" does not define any standard patch assignments for synthesizers. Therefore, when you create a MIDI file, it won't be reproduced correctly unless it is played back on the same MIDI synthesizer setup used to create it. For example, if you create a piano concerto for your Yamaha® DX7 and try to play it back on a Roland® LAPC-1, it may be played with a flute instead of a piano.

To enable MIDI files to be a viable format for representing music in multimedia computing, Windows provides MIDI authoring guidelines. These guidelines include a list of standard patch assignments and standard key assignments for percussion instruments. Using the MIDI Mapper, MIDI files authored in accordance with these guidelines can be played on any multimedia computer with internal or external MIDI synthesizers.


About Base-Level and Extended Synthesizers

Although it is difficult to clearly quantify distinctions between synthesizers, it is important to have some guidelines so you can create MIDI files that will play on all multimedia computers. The terms used to distinguish synthesizers for the purpose of authoring MIDI files are base-level synthesizer and extended synthesizer.

The distinctions between base-level and extended synthesizers are made solely on the number of instruments and notes the synthesizer can play, not on the quality or the cost of the synthesizer. Following are the minimum capabilities of base-level and extended synthesizers.

Synthesizer	Melodic instruments		Percussive instruments
	Number	Polyphony	Number	Polyphony
Base-level	3 instruments	6 notes	3 instruments	3 notes
Extended	9 instruments	16 notes	8 instruments	16 notes
Polyphony is the number of notes the synthesizer can play simultaneously. The polyphony expressed above applies to each group of instruments — melodic and percussive. For example, a base-level synthesizer is capable of playing six notes distributed among three melodic instruments and three notes distributed among three percussive instruments. Each melodic instrument is on a different MIDI channel; the percussive instruments are key-based — all on a single MIDI channel.

All multimedia computers provide at least a base-level synthesizer. Users can enhance their computer by adding internal or external synthesizers, which can be either base-level or extended synthesizers. When adding a synthesizer, the user must configure the MIDI Mapper to use the new device. If the MIDI Mapper is not configured, the instrument sounds will be incorrect when MIDI files are played, unless the application has the ability to send output directly to an internal synthesizer or output port. The MIDI Control Panel option allows a user to configure the MIDI Mapper as needed.


Authoring Guidelines for MIDI Files

Follow these guidelines to author device-independent MIDI files for Windows:

•	Author for both base-level and extended synthesizer setups.

•	Use MIDI channels 13 through 16 for base-level synthesizer data (reserve channel 16 for key-based percussion instruments).

•	Use MIDI channels 1 through 10 for extended synthesizer data (reserve channel 10 for key-based percussion instruments).

•	Prioritize MIDI data by putting crucial data in the lower-numbered channels.

•	Limit the polyphony of nonpercussive channels to a total of 6 notes for base-level data and 16 notes for extended data.

•	Limit the polyphony of percussive channels to a total of 3 notes for base-level data and 16 notes for extended data.

•	Use the standard MIDI patch assignments and key assignments.

•	Always send a program-change message to a channel to select a patch before sending other messages to that channel. For the two percussion channels (10 and 16), select program number 0.

•	Always follow a MIDI program-change message with a MIDI main-volume controller message (controller number 7) to set the relative volume of the patch.

•	Use a value of 80 (0x50) for the main-volume controller for normal listening levels. For quieter or louder levels, you can use lower or higher values.

•	Use only the following MIDI messages: note-on with velocity, note-off, program change, pitch bend, main volume (controller 7), and damper pedal (controller 64). Internal synthesizers are required to respond to these messages and most MIDI musical instruments respond to them as well.

•	Use the MARKMIDI utility program to mark MIDI files authored for Windows.

The following illustration summarizes the use of the 16 MIDI channels in a standard MIDI file authored for Windows.


Prioritizing MIDI Data

Synthesizers don't always fall cleanly into the base-level and extended designations defined earlier. It's up to the user to determine how to use synthesizers that are capable of more than the base-level requirements but do not fully meet the extended requirements. For this reason, it's important to prioritize the melodic data by putting the most critical data in lower-numbered channels. For example, a user may have a synthesizer capable of playing six melodic instruments with 12-note polyphony. The user can use this device as an extended synthesizer by setting up the MIDI Mapper to play only the first six melodic channels and ignore any information on channels 7, 8, and 9.


Standard MIDI Patch Assignments

The standard MIDI patch assignments for authoring MIDI files for use with Windows are based on the MIDI Manufacturers Association (MMA) General MIDI Mode specification. Following are the standard MIDI patch assignments.

Piano	Chromatic Percussion	Organ
0 Acoustic grand piano	8 Celesta	16 Hammond organ
1 Bright acoustic piano	9 Glockenspiel	17 Percussive organ
2 Electric grand piano	10 Music box	18 Rock organ
3 Honky-tonk piano	11 Vibraphone	19 Church organ
4 Rhodes piano	12 Marimba	20 Reed organ
5 Chorused piano	13 Xylophone	21 Accordion
6 Harpsichord	14 Tubular bells	22 Harmonica
7 Clavinet	15 Dulcimer	23 Tango accordion
Guitar	Bass	Strings
24 Acoustic guitar (nylon)	32 Acoustic bass	40 Violin
25 Acoustic guitar (steel)	33 Electric bass (finger)	41 Viola
26 Electric guitar (jazz)	34 Electric bass (pick)	42 Cello
27 Electric guitar (clean)	35 Fretless bass	43 Contrabass
28 Electric guitar (muted)	36 Slap bass 1	44 Tremolo strings
29 Overdriven guitar	37 Slap bass 2	45 Pizzicato strings
30 Distortion guitar	38 Synth bass 1	46 Orchestral harp
31 Guitar harmonics	39 Synth bass 2	47 Timpani
Ensemble	Brass	Reed
48 String ensemble 1	56 Trumpet	64 Soprano sax
49 String ensemble 2	57 Trombone	65 Alto sax
50 Synth. strings 1	58 Tuba	66 Tenor sax
51 Synth. strings 2	59 Muted trumpet	67 Baritone sax
52 Choir Aahs	60 French horn	68 Oboe
53 Voice Oohs	61 Brass section	69 English horn
54 Synth voice	62 Synth. brass 1	70 Bassoon
55 Orchestra hit	63 Synth. brass 2	71 Clarinet
Pipe	Synth Lead	Synth Pad
72 Piccolo	80 Lead 1 (square)	88 Pad 1 (new age)
73 Flute	81 Lead 2 (sawtooth)	89 Pad 2 (warm)
74 Recorder	82 Lead 3 (calliope lead)	90 Pad 3 (polysynth)
75 Pan flute	83 Lead 4 (chiff lead)	91 Pad 4 (choir)
76 Bottle blow	84 Lead 5 (charang)	92 Pad 5 (bowed)
77 Shakuhachi	85 Lead 6 (voice)	93 Pad 6 (metallic)
78 Whistle	86 Lead 7 (fifths)	94 Pad 7 (halo)
79 Ocarina	87 Lead 8 (brass + lead)	95 Pad 8 (sweep)
Sound Effects
120 Guitar fret noise
121 Breath noise
122 Seashore
123 Bird tweet
124 Telephone ring
125 Helicopter
126 Applause
127 Gunshot


Standard MIDI Key Assignments

The standard MIDI key assignments for percussion instruments are based on the MMA General MIDI Mode specification. The following illustration shows the standard key assignments for MIDI files authored for Windows.


Using the MARKMIDI Utility

The MARKMIDI utility program marks MIDI files as following the authoring guidelines for Windows MIDI files. The program does not verify that the file is authored correctly; it only marks the file by adding a sequencer-specific meta-event to the first track chunk. MARKMIDI has the following command syntax.

MARKMIDI src-filename dest-filename

If the MCI MIDI sequencer is used to play a MIDI file not marked by MARKMIDI, it displays a dialog box informing the user that the file is not authored for Windows.

Note  Do not use MARKMIDI to mark MIDI files unless the files were authored according to the guidelines presented in this guide. If your application uses MIDI files not authored to these guidelines, the application must instruct users to install or create the proper maps by using the MIDI Mapper Control Panel application. For example, if your application uses MIDI files following the General MIDI channel recommendations, your users should create or install a General MIDI map for their synthesizers.


High-Level Audio Functions

Following are the functions used with high-level audio services.

mciGetCreatorTask
mciGetDeviceID
mciGetErrorString
mciGetYieldProc
mciSendCommand
mciSendString
mciSetYieldProc
PlaySound
sndPlaySound


Low-Level Audio

This overview explains how to use the low-level audio services of Microsoft® Windows® to manage playback and recording of waveform and Musical Instrument Digital Interface (MIDI) audio.

For an overview of Windows audio services, see Introduction to Audio. For a discussion of high-level audio services, see High-Level Audio.

This overview covers the following topics:

•	Using low-level audio services

•	Playing waveform audio

•	Recording waveform audio

•	Playing MIDI audio

•	Recording MIDI audio

•	Using auxiliary audio devices

•	Using audio clipboard formats

You should have a basic knowledge of digital audio and MIDI before reading this overview. If you need additional information on these subjects, see Introduction to Audio.


Function Prefixes

Low-level audio function names begin with the following prefixes.

Prefix	Description
aux	Auxiliary audio functions
midi	MIDI audio functions
wave	Waveform audio functions


Using Low-Level Audio Services

Low-level audio services control different types of audio devices, including waveform, MIDI, and auxiliary audio devices. Many of the concepts for using low-level services apply to more than one type of device. The following topics present general information on using low-level audio services:

•	Querying audio devices

•	Opening and closing device drivers

•	Allocating and preparing audio data blocks

•	Managing audio data blocks

•	Using the MMTIME structure

•	Handling errors with audio functions

Subsequent topics in this overview discuss the use of specific types of audio devices.


Querying Audio Devices

Before playing or recording audio, you must determine the capabilities of the audio hardware present in the system. Audio capability can vary from one multimedia computer to the next; applications should not make assumptions about the audio hardware present in a given system.


Getting the Number of Devices

The Win32 application programming interface (API) provides the following functions to determine how many devices of a certain type are available in a given system.

Function	Description
auxGetNumDevs	Retrieves the number of auxiliary audio devices present in the system.
midiInGetNumDevs	Retrieves the number of MIDI input devices present in the system.
midiOutGetNumDevs	Retrieves the number of MIDI output devices present in the system.
waveInGetNumDevs	Retrieves the number of waveform input devices present in the system.
waveOutGetNumDevs	Retrieves the number of waveform output devices present in the system.
Audio devices are identified by a device identifier. The device identifier is determined implicitly from the number of devices present in a given system. Device identifiers range from zero to one less than the number of devices present. For example, if there are two MIDI output devices in a system, valid device identifiers are 0 and 1.


Getting the Capabilities of a Device

After you determine how many devices of a certain type are present in a system, you can inquire about the capabilities of each device. The Win32 API provides the following functions to determine the capabilities of audio devices.

Function	Description
auxGetDevCaps	Retrieves the capabilities of a given auxiliary audio device.
midiInGetDevCaps	Retrieves the capabilities of a given MIDI input device.
midiOutGetDevCaps	Retrieves the capabilities of a given MIDI output device.
waveInGetDevCaps	Retrieves the capabilities of a given waveform input device.
waveOutGetDevCaps	Retrieves the capabilities of a given waveform output device.
Each of these functions takes a pointer to a structure that it fills with information on the capabilities of a specified device. Following are the structures that correspond to each of the device-inquiry functions.

Function	Structure
auxGetDevCaps	AUXCAPS
midiInGetDevCaps	MIDIINCAPS
midiOutGetDevCaps	MIDIOUTCAPS
waveInGetDevCaps	WAVEINCAPS
waveOutGetDevCaps	WAVEOUTCAPS


Opening and Closing Low-Level Audio Device Drivers

After getting the capabilities of an audio device, you must open the device before you can use it. Audio devices aren't guaranteed to be shareable, so a particular device might not be available when you request it. If this happens, you should notify the user and allow the user to try to open the device again. When you open an audio device, be sure to close it as soon as you finish using it.

The Win32 API provides the following functions to open and close different types of audio devices.

Function	Description
midiInOpen	Opens a specified MIDI input device for recording.
midiInClose	Closes a specified MIDI input device.
midiOutOpen	Opens a MIDI output device for playback.
midiOutClose	Closes a specified MIDI output device.
waveInOpen	Opens a waveform input device for recording.
waveInClose	Closes a specified waveform input device.
waveOutOpen	Opens a waveform output device for playback.
waveOutClose	Closes a specified waveform output device.
These functions are discussed in detail later in this section.


About Device Handles

Each function that opens an audio device takes as parameters a device identifier, a pointer to a memory location, and some parameters unique to each type of device. The memory location is filled with a device handle. Use this device handle of identify the open audio device when calling other audio functions.

The distinction between audio-device identifiers and audio-device handles is subtle, but very important. Don't confuse the two in your application. Following are the differences between device identifiers and device handles.

•	Device identifiers are determined implicitly from the number of devices present in a system, which is obtained by using the device-numbering functions (auxGetNumDevs, midiInGetNumDevs, and so on).

•	Device handles are returned when device drivers are opened by using the device-opening functions (midiInOpen, midiOutOpen, and so on)

•	The only functions that take device identifiers as parameters are the device-capabilities functions (waveOutGetDevCaps, midiInGetDevCaps, and so on), the device-opening functions, and volume functions (waveOutGetVolume, waveOutSetVolume, and so on). All other functions take device handles.

There are no functions for opening and closing auxiliary audio devices. Auxiliary audio devices don't need to be opened and closed like MIDI and waveform devices because there is no continuous data transfer associated with them. All auxiliary audio functions take device identifiers to identify devices.


Allocating and Preparing Audio Data Blocks

Some low-level audio functions require applications to allocate data blocks to pass to the device drivers for playback or recording purposes. Each of these functions uses a structure (or header) to describe its data block. The following table identifies these functions and their associated header structures. (The MMSYSTEM.H file defines the data structures for these headers.)

Function	Header structure	Purpose
waveOutWrite	WAVEHDR	Waveform playback
waveInAddBuffer	WAVEHDR	Waveform recording
midiOutLongMsg	MIDIHDR	MIDI system-exclusive playback
midiInAddBuffer	MIDIHDR	MIDI system-exclusive recording
Before you use one of the functions listed above to pass a data block to a device driver, you must allocate memory for the data block according to the guidelines discussed in the following topics.


Allocating Memory for Audio Data Blocks

Before preparing a data block, you must allocate memory for the data block and the header structure that describes the data block.

To allocate memory, use the GlobalAlloc function with the GMEM_MOVEABLE flag to get a handle of the memory object. Then pass this handle of the GlobalLock function to get a pointer to the memory object.

To free a data block, use GlobalUnlock and GlobalFree.


Preparing Audio Data Blocks

Before you pass an audio data block to a device driver, you must prepare the data block by passing it to a header-preparation function. When the device driver is finished with the data block and returns it, you must clean up this preparation by passing the data block to a header clean-up function before any allocated memory can be freed.

Windows provides the following functions for preparing and cleaning up audio data blocks.

Function	Description
midiInPrepareHeader	Prepares a MIDI-input data block.
midiInUnprepareHeader	Cleans up the preparation on a MIDI-input data block.
midiOutPrepareHeader	Prepares a MIDI-output data block.
midiOutUnprepareHeader	Cleans up the preparation on a MIDI-output data block.
waveInPrepareHeader	Prepares a waveform-input data block.
waveInUnprepareHeader	Cleans up the preparation on a waveform-input data block.
waveOutPrepareHeader	Prepares a waveform-output data block.
waveOutUnprepareHeader	Cleans up the preparation on a waveform-output data block.


Managing Audio Data Blocks

Unless the audio data is small enough to be contained in a single data block, applications must continually supply the device driver with data blocks until playback or recording is complete. This is true for waveform input and output, and for MIDI system-exclusive input messages. Regular MIDI channel messages don't require data blocks for input or output.

Even if a single data block is used, applications must be able to determine when a device driver is finished with the data block so the application can free the memory associated with the data block and header structure. There are three ways to determine when a device driver is finished with a data block:

•	Specify a window to receive a message sent by the driver when it is finished with a data block.

•	Specify a callback function to receive a message sent by the driver when it is finished with a data block.

•	Poll a bit in the dwFlags member of the WAVEHDR or MIDIHDR data structure sent with each data block.

If an application doesn't get a data block to the device driver when needed, there can be an audible gap in playback or a loss of incoming recorded information. Use a double-buffering scheme to stay at least one data block ahead of the device driver.

Note  To get time-stamped MIDI input data, you must use a callback function.


Using a Window to Process Driver Messages

The easiest type of callback function to use to process driver messages is a window callback. To use a window callback, specify the CALLBACK_WINDOW flag in the dwFlags parameter and a window handle as the dwCallback parameter of the device-opening function. Driver messages will be sent to the window-procedure function for the window identified by the handle in dwCallback.

Messages sent to the window function are specific to the audio device type used. For details on these messages, see the topics later in this section on using window messages for each specific audio device type.


Using a Callback Function to Process Low-Level Audio Driver Messages

You can also write your own low-level callback function to process messages sent by the device driver. To use a low-level callback function, specify the CALLBACK_FUNCTION flag in the dwFlags parameter and the address of the callback in the dwCallback parameter of the device-opening function.

Messages sent to a callback function are similar to messages sent to a window, except that they have two doubleword parameters instead of one unsigned-integer and one doubleword parameter. For details on these messages, see the sections later in this section about using low-level callbacks for each specific audio device type.

Callback functions for the low-level audio services are often called from another thread running asynchronously from the application's thread. It is therefore important to use critical sections to protect data shared between the callback routine and the rest of the application. For more information about critical sections, see Synchronization.

There are several differences between callback functions for the low-level audio services under Windows NT and under Windows 3.1:

•	Under Windows 3.1, a low-level audio callback function is called at interrupt time. The call to a low-level audio callback function occurs on a separate thread under Windows NT.

•	Under Windows 3.1, a low-level audio callback function has to be in a dynamic-link library. Under Windows NT, there is no such restriction.

•	Under Windows 3.1, a low-level audio callback function must be exported in a .DEF file. Under Windows NT, that is not necessary.

If source code must be compatible with Windows 3.1, it should follow the Windows 3.1 rules as noted briefly above and specified more fully in the Windows 3.1 documentation.

One other item should be noted carefully. There is a limited set of APIs that a Windows 3.1 low-level audio callback function may call. In Win32, that strict limitation has been removed. However, it is strongly recommended that a Windows NT low-level audio callback function restrain its calls to a similar set of APIs. Here is the Windows NT recommended list:

EnterCriticalSection	ReleaseSemaphore
LeaveCriticalSection	SetEvent
midiOutLongMsg	timeGetSystemTime
midiOutShortMsg	timeGetTime
OutputDebugString	timeKillEvent
PostMessage	timeSetEvent
PostThreadMessage
If an application's low-level audio callback function does stray from this list, it should be careful not to call APIs that take a long time to complete.

In particular, calling wave and midi APIs may result in a deadlock.

If a Win32 low-level audio callback shares data with other code, a Critical Section  or similar mutual exclusion mechanism should be used to protect the integrity of the data.

Use one of the following techniques to pass instance data from an application to a low-level callback function residing in a dynamic link library:

•	Pass the instance data using the dwInstance parameter of the function that opens the device driver.

•	Pass the instance data using the dwUser member of the WAVEHDR and MIDIHDR structures that identify an audio data block being sent to a device driver.

If you need more than 32 bits of instance data, pass a pointer to a structure containing the additional information.


Managing Low-Level Audio Data Blocks by Polling

In addition to using a callback function, you can poll the dwFlags member of a WAVEHDR or MIDIHDR structure to determine when an audio device is finished with a data block. There are times when it's better to poll dwFlags rather than wait for a window to receive messages from the drivers. For example, immediately after you call the waveOutReset function to release pending data blocks, you can poll to be sure that the data blocks are indeed done before proceeding to call the waveOutUnprepareHeader function and free the memory for the data block.

MMSYSTEM.H defines two flags for testing the dwFlags member: WHDR_DONE for a WAVEHDR structure, and MHDR_DONE for a MIDIHDR structure.


Using the MMTIME Structure

Windows uses a structure called MMTIME to represent time. Low-level audio functions that use MMTIME include waveInGetPosition and waveOutGetPosition. The timeGetSystemTime function also uses MMTIME to represent system time.


Setting the Time Format

MMTIME can represent time in one or more different formats including milliseconds, samples, Society of Motion Picture and Television Engineers (SMPTE), and MIDI song-pointer formats. The wType member specifies the format used to represent time. Before calling a function that uses the MMTIME structure, you must set the wType member to indicate your requested time format. Be sure to check wType after the call to see if the requested time format is supported. If the requested time format is not supported, the time is specified in an alternate time format selected by the device driver and the wType member is changed to indicate the selected time format. MMSYSTEM.H defines the following flags for the wType member of the MMTIME structure.

Flag	Description
TIME_MS	Milliseconds
TIME_SAMPLES	Number of waveform audio samples
TIME_BYTES	Number of waveform audio bytes
TIME_SMPTE	SMPTE time
TIME_MIDI	MIDI song-position pointer
For details on using MMTIME with the waveOutGetPosition function, seeGetting the Current Playback Position.


Getting the System Time

Use the timeGetSystemTime or timeGetTime function to get the system time. System time is defined as the time (in milliseconds) since Windows was started. For more information on timeGetSystemTime and timeGetTime, see Multimedia Timer and Joystick Services.


Handling Errors with Low-Level Audio Functions

Low-level audio functions return a nonzero error code. A set of functions convert these error codes into a textual description of the error. The application must still look at the error value itself to determine how to proceed, but textual descriptions of errors can be used in dialog boxes describing errors to users.

The following functions can be used to get textual descriptions of low-level audio errors.

Function	Description
midiInGetErrorText	Retrieves a textual description of a specified MIDI input error.
midiOutGetErrorText	Retrieves a textual description of a specified MIDI output error.
waveInGetErrorText	Retrieves a textual description of a specified waveform input error.
waveOutGetErrorText	Retrieves a textual description of a specified waveform output error.
The only low-level audio functions that don't return error codes are the device-numbering functions (auxGetNumDevs, midiInGetNumDevs, and so on). These functions return a value of zero if no devices are present in a system, or if any errors are encountered by the function.


Playing Waveform Audio

If your application plays waveform audio, you can use the Media Control Interface (MCI) to control waveform output devices. If the MCI waveform playback services don't meet the needs of your application, you can manage waveform playback by using the low-level waveform services.


Waveform Output Data Types

The MMSYSTEM.H header file defines data types and function prototypes for all of the audio functions. You must include this header file in any source-code module that uses these functions. MMSYSTEM.H defines the following data types for the waveform output functions.

Type	Description
HKL	Handle to a keyboard layout.
HWAVEOUT	Handle to an audio  waveform output device.
WAVEOUTCAPS	Structure used to inquire about the capabilities of a particular waveform output device.
WAVEFORMAT	Structure that specifies the data formats supported by a particular waveform output device. This structure is also used for waveform input devices.
WAVEHDR	Structure that is a header for a block of waveform output data. This structure is also used for waveform input devices.


Querying Waveform Output Devices

Before playing a waveform, call the waveOutGetDevCaps function to determine the waveform output capabilities of the playback device as described earlier in this section. This function takes a pointer to a WAVEOUTCAPS structure, which it fills with information about the capabilities of a given device. This information includes the manufacturer and product identifiers, a product name for the device, and the version number of the device driver.

In addition, the WAVEOUTCAPS structure provides information on the standard waveform formats and features supported by the device driver.


Determining Standard Format Support

The dwFormats member of the WAVEOUTCAPS structure specifies the standard waveform formats supported by a device. The MMSYSTEM.H header file defines the following standard waveform format identifiers for the dwFormats member.

Format identifier	Waveform format
WAVE_FORMAT_1M08	8-bit mono at 11.025 kHz
WAVE_FORMAT_1S08	8-bit stereo at 11.025 kHz
WAVE_FORMAT_1M16	16-bit mono at 11.025 kHz
WAVE_FORMAT_1S16	16-bit stereo at 11.025 kHz
WAVE_FORMAT_2M08	8-bit mono at 22.05 kHz
WAVE_FORMAT_2S08	8-bit stereo at 22.05 kHz
WAVE_FORMAT_2M16	16-bit mono at 22.05 kHz
WAVE_FORMAT_2S16	16-bit stereo at 22.05 kHz
WAVE_FORMAT_4M08	8-bit mono at 44.1 kHz
WAVE_FORMAT_4S08	8-bit stereo at 44.1 kHz
WAVE_FORMAT_4M16	16-bit mono at 44.1 kHz
WAVE_FORMAT_4S16	16-bit stereo at 44.1 kHz
The value of the dwFormats member is the result of a logical OR operation on the flags listed above.

This information on standard-format support also applies to the WAVEINCAPS structure used with waveform input devices. For information about the WAVEINCAPS structure, see Querying Waveform Input Devices.

To determine whether a specific format is supported by a device, use the waveOutOpen function with the WAVE_FORMAT_QUERY flag as shown in the next section.


Determining Low-Level Audio Nonstandard Format Support

Waveform devices can support nonstandard formats not listed in the preceding table. To see whether a particular format (standard or nonstandard) is supported by a device, you can call the waveOutOpen function with the WAVE_FORMAT_QUERY flag. The WAVE_FORMAT_QUERY flag tells waveOutOpen to check whether the requested format is supported. The wave device is not actually opened. The requested format is specified by the structure pointed to by the lpFormat parameter passed to waveOutOpen. For information about setting up this structure, see Specifying Waveform Data Formats. The following example uses this technique to determine whether a given waveform device supports a given format.

/*

 * Determines whether the given waveform output device supports

 * a given wave-form format. Returns 0 if the format is supported,

 * WAVEERR_BADFORMAT if the format is not supported, and one of

 * the MMSYSERR_ error codes if there are other errors in opening

 * the given waveform device.

 */

UINT IsFormatSupported(LPPCMWAVEFORMAT lpPCMWaveFormat,

    UINT wDeviceID)

{

    return (waveOutOpen(

            NULL,                           // NULL for query

            wDeviceID,                      // device identifier

            (LPWAVEFORMAT)lpPCMWaveFormat,  // requested format

            NULL,                           // no callback

            NULL,                           // no instance data

            WAVE_FORMAT_QUERY));            // query only

}

This technique to determine nonstandard format support also applies to waveform input devices. The only difference is that the waveInOpen function is used in place of waveOutOpen to query for format support.

Note  To determine whether a particular waveform-data format is supported by any of the waveform devices in a system, use the technique illustrated in the previous example, but specify the WAVE_MAPPER constant for the wDeviceID parameter. For more information about using the WAVE_MAPPER constant, see Selecting a Waveform Output Device.


Determining Capabilities of Waveform Output Devices

Waveform output devices vary in the capabilities they support. The dwSupport member of the WAVEOUTCAPS structure indicates whether a given device supports capabilities such as volume and pitch changes. MMSYSTEM.H defines the following flags for the dwSupport member.

Flag	Description
WAVECAPS_PITCH	Pitch-change support
WAVECAPS_PLAYBACKRATE	Playback-rate-change support
WAVECAPS_VOLUME	Volume-control support
WAVECAPS_LRVOLUME	Individual volume-control support for both left and right channels
The dwSupport member is a logical OR of the flags listed in the preceding table.

For more information about playback volume levels, see Changing Waveform Playback Volume. For more information about pitch and playback rates, see Changing Pitch and Playback Rate.


Opening Waveform Output Devices

Use the waveOutOpen function to open a waveform output device for playback. This function opens the device associated with the specified device identifier and returns a handle of the open device by writing the handle of a specified memory location.


Selecting a Waveform Output Device

Some multimedia computers have multiple waveform output devices. Unless you know you want to open a specific waveform output device in a system, you should use the WAVE_MAPPER constant for the device identifier when you open a device. The waveOutOpen function chooses the device in the system best capable of playing the given data format.


Specifying Waveform Data Formats

When you call the waveOutOpen function to open a device driver for playback or determine whether the driver supports a particular data format, use the lpFormat parameter to specify a pointer to a structure containing the requested waveform data format.

The WAVEFORMAT structure specifies format information common to all types of waveform data formats. Currently the only format supported is pulse code modulated (PCM), but in the future other types such as adaptive differential pulse code modualtion (ADPCM) may be supported.

In addition to the general information in the WAVEFORMAT structure, specific information is needed to describe a PCM waveform data format completely. For PCM waveform data, the PCMWAVEFORMAT structure includes a WAVEFORMAT structure along with an additional member containing PCM-specific information.


Using the PCMWAVEFORMAT Structure

For PCM audio data, use the PCMWAVEFORMAT structure to specify the data format. The following example shows how to set up a PCMWAVEFORMAT structure for 11.025 kilohertz (kHz) 8-bit mono and for 44.1 kHz 16-bit stereo. After setting up PCMWAVEFORMAT, the example calls the IsFormatSupported function to verify that the PCM waveform output device supports the format. The source code for IsFormatSupported is given in an example in "Determining Nonstandard Format Support."

UINT wReturn;

PCMWAVEFORMAT pcmWaveFormat;

/* Set up PCMWAVEFORMAT for 11 kHz 8-bit mono. */

pcmWaveFormat.wf.wFormatTag = WAVE_FORMAT_PCM;

pcmWaveFormat.wf.nChannels = 1;

pcmWaveFormat.wf.nSamplesPerSec = 11025L;

pcmWaveFormat.wf.nAvgBytesPerSec = 11025L;

pcmWaveFormat.wf.nBlockAlign = 1;

pcmWaveFormat.wBitsPerSample = 8;

/* See if format is supported by any device in system. */

wReturn = IsFormatSupported(&pcmWaveFormat, WAVE_MAPPER);

/* Report results. */

if (wReturn == 0)

     MessageBox(hMainWnd, "11 kHz 8-bit mono is supported.",

       "", MB_ICONINFORMATION);

else if (wReturn == WAVERR_BADFORMAT)

     MessageBox(hMainWnd, "11 kHz 8-bit mono NOT supported.",

       "", MB_ICONINFORMATION);

else

     MessageBox(hMainWnd, "Error opening waveform device.",

       "Error", MB_ICONEXCLAMATION);

/* Set up PCMWAVEFORMAT for 44.1 kHz 16-bit stereo. */

pcmWaveFormat.wf.wFormatTag = WAVE_FORMAT_PCM;

pcmWaveFormat.wf.nChannels = 2;

pcmWaveFormat.wf.nSamplesPerSec = 44100L;

pcmWaveFormat.wf.nAvgBytesPerSec = 176400L;

pcmWaveFormat.wf.nBlockAlign = 4;

pcmWaveFormat.wBitsPerSample = 32;

/* See if format is supported by any device in the system. */

wReturn = IsFormatSupported(&pcmWaveFormat, WAVE_MAPPER);

/* Report results. */

if (wReturn == 0)

    MessageBox(hMainWnd, "44.1 kHz 16-bit stereo is supported.",

      "", MB_ICONINFORMATION);

else if (wReturn == WAVERR_BADFORMAT)

    MessageBox(hMainWnd, "44.1 kHz 16-bit stereo NOT supported.",

      "", MB_ICONINFORMATION);

else

    MessageBox(hMainWnd, "Error opening waveform device.",

      "Error", MB_ICONEXCLAMATION);


Getting Format Information from a WAVE File

The easiest way to get waveform-format information from a WAVE file is by using the multimedia file input and output (I/O) services. To do this, use the mmioDescend function to locate the "fmt" chunk containing the format information and the mmioRead function to read the format chunk directly into the proper format structure. (Chunks are the basic building blocks of RIFF files.) The following example illustrates this technique. For more information about multimedia file I/O, see Multimedia File Input/Output.

void GetFormatInfo(void)

{

    HMMIO       hmmio;

    MMCKINFO    mmckinfoParent;

    MMCKINFO    mmckinfoSubchunk;

    DWORD       dwFmtSize;

    HANDLE      hFormat;

    WAVEFORMAT  *pFormat;

.ifdef REF

        .

        .

        .

.endif

    /* Open the given file for reading using buffered I/O. */

.ifdef REF

        ...

.endif

    /*

     * Locate a "RIFF" chunk with a "WAVE" form type

     * to make sure it's a WAVE file.

     */

.ifdef REF

        ...

.endif

    /*

     * Now, find the format chunk (form type "fmt "). It should be

     * a subchunk of the "RIFF" parent chunk.

     */

    mmckinfoSubchunk.ckid = mmioFOURCC('f', 'm', 't', ' ');

    if (mmioDescend(hmmio, &mmckinfoSubchunk, &mmckinfoParent,

            MMIO_FINDCHUNK)) {

        MessageBox(hwndApp, "WAVE file is corrupted.",

            NULL, MB_OK | MB_ICONEXCLAMATION);

        mmioClose(hmmio, 0);

        return;

    }

    /*

     * Get the size of the format chunk;

     * allocate and lock memory for it.

     */

    dwFmtSize = mmckinfoSubchunk.cksize;

    hFormat = LocalAlloc(LMEM_MOVEABLE, dwFmtSize);

    if (hFormat == NULL) {

        MessageBox(hwndApp, "Out of memory.",

            NULL, MB_OK | MB_ICONEXCLAMATION);

        mmioClose(hmmio, 0);

        return;

    }

    pFormat = (WAVEFORMAT *) LocalLock(hFormat);

    if (pFormat == NULL) {

        MessageBox(hwndApp, "Failed to lock memory for format chunk.",

            NULL, MB_OK | MB_ICONEXCLAMATION);

        LocalFree(hFormat);

        mmioClose(hmmio, 0);

        return;

    }

    /* Read the format chunk. */

    if (mmioRead(hmmio, (LPSTR)pFormat,

                dwFmtSize) != (LRESULT)dwFmtSize) {

        MessageBox(hwndApp, "Failed to read format chunk.",

            NULL, MB_OK | MB_ICONEXCLAMATION);

        LocalUnlock(hFormat);

        LocalFree(hFormat);

        mmioClose(hmmio, 0);

        return;

    }

    /* Make sure it's a PCM file. */

    if (pFormat->wFormatTag != WAVE_FORMAT_PCM) {

        LocalUnlock(hFormat);

        LocalFree(hFormat);

        mmioClose(hmmio, 0);

        MessageBox(hwndApp, "The file is not a PCM file.",

            NULL, MB_OK | MB_ICONEXCLAMATION);

        return;

    }

    /*

     * Make sure the system has a waveform output

     * device capable of playing this format.

     */

    if (waveOutOpen(&hWaveOut, WAVE_MAPPER, (LPWAVEFORMAT)pFormat,

                NULL, 0L, WAVE_FORMAT_QUERY)) {

        LocalUnlock(hFormat);

        LocalFree(hFormat);

        mmioClose(hmmio, 0);

        MessageBox(hwndApp,

            "The waveform device can't play this format.",

            NULL, MB_OK | MB_ICONEXCLAMATION);

        return;

    }

.ifdef REF

    .

    .

    .

.endif

}


Writing Waveform Data

After successfully opening a waveform output device driver, you can begin waveform playback.

The waveOutWrite function writes a data block to a waveform output device. Use the WAVEHDR structure to specify the waveform data block you are sending. This structure contains a pointer to a locked data block, the length of the data block, and assorted flags.

After you send a data block to an output device by using waveOutWrite, you must wait until the device driver is finished with the data block before freeing it. If you are sending multiple data blocks, you must monitor the system for the completion of each data block so that you know when to send additional blocks. For details about different techniques for monitoring data block completion, see Managing Audio Data Blocks.


Example of Writing Waveform Data

The following example illustrates the steps required to allocate and set up a WAVEHDR data structure and write a block of data to a waveform output device.

/*

 * Global variables. Must be visible to window-procedure function

 *  so it can unlock and free the data block after it has been played.

 */

HANDLE hData  = NULL; // handle of waveform data memory

HPSTR  lpData = NULL; // pointer to waveform data memory

void WriteWaveData(void)

{

    HWAVEOUT    hWaveOut;

    HGLOBAL     hWaveHdr;

    LPWAVEHDR   lpWaveHdr;

    HMMIO       hmmio;

    UINT        wResult;

    HANDLE      hFormat;

    WAVEFORMAT  *pFormat;

    DWORD       dwDataSize;

.ifdef REF

        .

        .

        .

.endif

    /* Open a waveform device for output using window callback. */

    if (waveOutOpen((LPHWAVEOUT)&hWaveOut, WAVE_MAPPER,

                    (LPWAVEFORMAT)pFormat,

                    (LONG)hwndApp, 0L, CALLBACK_WINDOW)) {

        MessageBox(hwndApp,

                   "Failed to open waveform output device.",

                   NULL, MB_OK | MB_ICONEXCLAMATION);

        LocalUnlock(hFormat);

        LocalFree(hFormat);

        mmioClose(hmmio, 0);

        return;

    }

    /*

     * Allocate and lock memory for the waveform data. The memory

     * for waveform data must be globally allocated with

     * GMEM_MOVEABLE and GMEM_SHARE flags.

     */

    hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, dwDataSize );

    if (!hData)

    {

        MessageBox(hwndApp, "Out of memory.",

                   NULL, MB_OK | MB_ICONEXCLAMATION);

        mmioClose(hmmio, 0);

        return;

    }

    if ((lpData = GlobalLock(hData)) == NULL) {

        MessageBox(hwndApp, "Failed to lock memory for data chunk.",

                   NULL, MB_OK | MB_ICONEXCLAMATION);

        GlobalFree(hData);

        mmioClose(hmmio, 0);

        return;

    }

    /* Read the waveform data subchunk. */

    if(mmioRead(hmmio, (HPSTR) lpData, dwDataSize) != (LRESULT)dwDataSize) {

        MessageBox(hwndApp, "Failed to read data chunk.",

                   NULL, MB_OK | MB_ICONEXCLAMATION);

        GlobalUnlock(hData);

        GlobalFree(hData);

        mmioClose(hmmio, 0);

        return;

    }

    /*

     * Allocate and lock memory for the header. This memory must

     * also be globally allocated with GMEM_MOVEABLE and

     * GMEM_SHARE flags.

     */

    hWaveHdr = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE,

        (DWORD) sizeof(WAVEHDR));

    if (hWaveHdr == NULL) {

        GlobalUnlock(hData);

        GlobalFree(hData);

        MessageBox(hwndApp, "Not enough memory for header.",

            NULL, MB_OK | MB_ICONEXCLAMATION);

        return;

    }

    lpWaveHdr = (LPWAVEHDR) GlobalLock(hWaveHdr);

    if (lpWaveHdr == NULL) {

        GlobalUnlock(hData);

        GlobalFree(hData);

        MessageBox(hwndApp,

            "Failed to lock memory for header.",

            NULL, MB_OK | MB_ICONEXCLAMATION);

        return;

    }

    /* After allocation, set up and prepare header. */

    lpWaveHdr->lpData = lpData;

    lpWaveHdr->dwBufferLength = dwDataSize;

    lpWaveHdr->dwFlags = 0L;

    lpWaveHdr->dwLoops = 0L;

    waveOutPrepareHeader(hWaveOut, lpWaveHdr, sizeof(WAVEHDR));

    /*

     * Now the data block can be sent to the output device. The

     * waveOutWrite function returns immediately and waveform

     * data is sent to the output device in the background.

     */

    wResult = waveOutWrite(hWaveOut, lpWaveHdr, sizeof(WAVEHDR));

    if (wResult != 0) {

        waveOutUnprepareHeader(hWaveOut, lpWaveHdr,

                               sizeof(WAVEHDR));

        GlobalUnlock( hData);

        GlobalFree(hData);

        MessageBox(hwndApp, "Failed to write block to device",

                   NULL, MB_OK | MB_ICONEXCLAMATION);

        return;

    }

.ifdef REF

    .

    .

    .

.endif

}


PCM Waveform Data Format

The lpData member in the WAVEHDR structure points to the waveform data samples. For 8-bit PCM data, each sample is represented by a single unsigned data byte. For 16-bit PCM data, each sample is represented by a 16-bit signed value. The following table summarizes the maximum, minimum, and midpoint values for PCM waveform data.

Data format	Maximum value	Minimum value	Midpoint value
8-bit PCM	255 (0xFF)	0	128 (0x80)
16-bit PCM	32767 (0x7FFF)	-32768 (0x8000)	0
The order of the data bytes varies between 8-bit and 16-bit, and between mono and stereo formats. The following tables show data packing for the first four words of different PCM waveform data formats.

Data packing for 8-bit mono PCM:

Sample 1	Sample 2	Sample 3	Sample 4
Channel 0	Channel 0	Channel 0	Channel 0
Data packing for 8-bit stereo PCM:

Sample 1		Sample 2
Channel 0 (left)	Channel 1 (right)	Channel 0 (left)	"Channel 1 (right)"
Low-order byte	High-order byte	Low-order byte	High-order byte
Data packing for 16-bit mono PCM:

Sample 1		Sample 2
Channel 0 low byte	Channel 0 high byte	Channel 0 low byte	Channel 0 high byte
Data packing for 16-bit stereo PCM:

Sample 1
Channel 0 (left) byte	Channel 0 (left) byte	Channel 1 (right) byte	Channel 1 (right) byte


Waveform Looping

Waveform looping is controlled by the dwLoops and dwFlags members in the WAVEHDR structures passed to the device with waveOutWrite. Use the WHDR_BEGINLOOP and WHDR_ENDLOOP flags in the dwFlags member to specify the beginning and ending data blocks for looping.

To loop on a single block, specify both flags for the same block. To specify the number of loops, use the dwLoops member in the WAVEHDR structure for the first block in the loop.

You can stop waveform looping with the waveOutBreakLoop function. The blocks making up the loop are played to the end before the loop is stopped.


Using Window Messages to Manage Waveform Playback

The following messages can be sent to a window-procedure function for managing waveform playback.

Message	Description
MM_WOM_CLOSE	Sent when the device is closed using waveOutClose.
MM_WOM_DONE	Sent when the device driver is finished with a data block sent using waveOutWrite.
MM_WOM_OPEN	Sent when the device is opened using waveOutOpen.
A wParam and lParam parameter is associated with each of these messages. The wParam parameter always specifies a handle of the open waveform device. For the MM_WOM_DONE message, lParam specifies a pointer to a WAVEHDR structure identifying the completed data block. The lParam parameter is unused for the MM_WOM_CLOSE and MM_WOM_OPEN messages.

The most useful message is MM_WOM_DONE. When this message signals that playback of a data block is complete, you can clean up and free the data block. Unless you need to allocate memory or initialize variables, you probably don't need to process the MM_WOM_OPEN and MM_WOM_CLOSE messages.

The following example shows how to process the MM_WOM_DONE message. The example assumes the application does not play multiple data blocks, so it can close the output device after playing a single data block.

/* WndProc--Main window-procedure function. */

LRESULT WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)

{

    switch (msg) {

.ifdef REF

        .

        .

        .

.endif

        case MM_WOM_DONE:

        /* A data block has been played and can now be freed. */

            waveOutUnprepareHeader((HWAVEOUT) wParam,

                (LPWAVEHDR) lParam, sizeof(WAVEHDR) );

            GlobalUnlock(hData);

            GlobalFree(hData);

            waveOutClose((HWAVEOUT) wParam);

            break;

    }

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

}


Using a Low-Level Callback Function to Manage Waveform Playback

The syntax of the low-level callback function for waveform output devices is as follows:

void CALLBACK waveOutCallback(hWaveOut, wMsg,
     dwInstance, dwParam1, dwParam2)

The following messages can be sent in the wMsg parameter of waveform output callback functions.

Message	Description
WOM_CLOSE	Sent when the device is closed using the waveOutClose function.
WOM_DONE	Sent when the device driver is finished with a data block sent using the waveOutWrite function.
WOM_OPEN	Sent when the device is opened using the waveOutOpen function.
These messages are similar to the messages sent to window-procedure functions, the parameters are different. A handle of the open waveform device is passed as a parameter to the callback function, along with the doubleword of instance data that was passed using waveOutOpen.

The callback function has two message-specific parameters: dwParam1 and dwParam2. For the WOM_DONE message, dwParam1 specifies a pointer to a WAVEHDR structure identifying the completed data block and dwParam2 is not used. For the WOM_OPEN and WOM_CLOSE messages, neither of the parameters is used.

After the driver is finished with a data block, you can clean up and free the data block, as described in "Allocating and Preparing Audio Data Blocks." Because of the suggested restrictions on low-level audio callback functions, it is better to not do this from within the callback. See Using a Callback Function to Process Driver Messages for details about suggested restrictions on using callback functions.


Getting the Current Playback Position

While a waveform is playing, you can monitor the current playback position within the waveform. The Win32 API provides the waveOutGetPosition function for this purpose.

This function takes three parameters: a handle of a waveform output device, a pointer to an MMTIME structure, and an unsigned integer specifying the size of the MMTIME structure.

For waveform devices, the preferred time format in which to represent the current position is samples. Thus the current position of a waveform device is specified as the number of samples for one channel from the beginning of the waveform.

To query the current position of a waveform device, set the wType member of the MMTIME structure to TIME_SAMPLES and pass the structure to waveOutGetPosition.


Stopping, Pausing, and Restarting Playback

You can stop or pause playback while a waveform is playing. Once playback has been paused, you can restart it. The Win32 API provides the following functions for controlling waveform playback.

Function	Description
waveOutPause	Pauses playback on a waveform output device.
waveOutReset	Stops playback on a waveform output device and marks all pending data blocks as done.
waveOutRestart	Resumes playback on a paused waveform output device.
Use the waveOutPause function to pause a waveform device that is currently playing. To resume playback on a paused device, use the waveOutRestart function. These functions take a single parameter: the waveform output device handle returned by the waveOutOpen function. Pausing a waveform device may not be instantaneous — the driver can finish playing the current block before pausing playback.

Typically, as soon as the first waveform data block is sent by using the waveOutWrite function, the waveform device begins playing. If you don't want the waveform to start playing immediately, call waveOutPause before calling waveOutWrite. When you want to begin playing the waveform, call waveOutRestart.

To stop a waveform from playing, use the waveOutReset function. This function differs from waveOutPause in that it also marks all pending data blocks as being done. You can not use waveOutRestart to restart a device that has been stopped by using waveOutReset. You must use waveOutWrite to send the first data block to resume playback on the device.


Closing Waveform Output Devices

After waveform playback is complete, call the waveOutClose function to close the waveform device. If waveOutClose is called while a waveform is playing, the close operation fails and the function returns an error code indicating that the device was not closed. If you don't want to wait for playback to end before closing the device, call the waveOutReset function before closing. This stops playback and allows the device to be closed. Be sure to clean up the preparation on all data blocks before closing the waveform output device.


Changing Waveform Playback Volume

Windows provides the following functions to query and set the volume level of waveform output devices.

Function	Description
waveOutGetVolume	Gets the volume level of the specified waveform device.
waveOutSetVolume	Sets the volume level of the specified waveform device.
Not all waveform devices support volume changes. Some devices support individual volume control on both the left and right channels. For information about how to determine the volume-control capabilities of waveform devices, see Determining Capabilities of Waveform Output Devices.

Note  Unless your application is designed to be a master volume-control application providing the user with volume control for all audio devices in a system, be sure that your application opens an audio device before changing its volume. Also, be sure your application queries the volume level before changing it and restores the volume level to its previous level as soon as possible.

Volume is specified in a doubleword value of which the high-order 16 bits specify the relative volume of the right channel, and the low-order 16 bits specify the relative volume of the left (or mono) channel.

For devices that don't support left- and right-channel volume control, the low-order 16 bits specify the volume level, and the high-order 16 bits are ignored. Volume-level values range from 0x0 (silence) to 0xFFFF (maximum volume) and are interpreted logarithmically. The perceived volume increase is the same when increasing the volume level from 0x5000 to 0x6000 as it is from 0x4000 to 0x5000.

The waveOutGetVolume function returns the volume as a doubleword value at an address specified by a pointer parameter.


Changing Pitch and Playback Rate

Some waveform output devices can vary the pitch and the playback rate of waveform data. Not all waveform devices support pitch and playback-rate changes. For information about how to determine if a particular waveform device supports pitch and playback-rate changes, see Determining Capabilities of Waveform Output Devices.

Following are the differences between changing pitch and playback rate:

•	Changing the playback rate is performed by the device driver and does not require specialized hardware. The sample rate is not changed, but the driver interpolates by skipping or synthesizing samples. For example, if the playback rate is changed by a factor of two, the driver skips every other sample.

•	Changing the pitch requires specialized hardware. The playback rate and sample rate are not changed.

Windows provides the following functions to query and set waveform pitch and playback rates.

Function	Description
waveOutGetPitch	Gets the pitch for the specified waveform output device.
waveOutGetPlaybackRate	Gets the playback rate for the specified waveform output device.
waveOutSetPitch	Sets the pitch for the specified waveform output device.
waveOutSetPlaybackRate	Sets the playback rate for the specified waveform output device.
The pitch and playback rates are changed by a factor specified with a fixed-point number packed into a doubleword value. The high-order 16 bits specify the integer part, and the low-order 16 bits specify the fractional part of the number. For example, the value 1.5 is represented as 0x00018000L. The value 0.75 is represented as 0x0000C000L. A value of 1.0 (0x00010000) means the pitch or playback rate is unchanged.


Recording Low-Level Waveform Audio

If the MCI waveform-recording services don't meet the needs of your application, you can handle waveform recording using the low-level waveform services.


Waveform Input Data Types

The MMSYSTEM.H header file defines data types and function prototypes for all of the audio functions. You must include this header file in any source-code module that uses these functions. MMSYSTEM.H defines the following data types for waveform-input functions.

Type	Description
HWAVEIN	Handle of an open waveform input device.
WAVEINCAPS	Data structure used to inquire about the capabilities of a particular waveform input device.
WAVEFORMAT	Structure that specifies the data formats supported by a particular waveform input device. This structure is also used for waveform output devices.
WAVEHDR	Structure that is a header for a block of waveform input data. This structure is also used for waveform output devices.


Querying Waveform Input Devices

Before recording a waveform, you should call the waveInGetDevCaps function to determine the waveform input capabilities of the system. This function takes a pointer to a WAVEINCAPS structure that it fills with information about the capabilities of a given device. This information includes the manufacturer and product identifiers, a product name for the device, and the version number of the device driver. In addition, the WAVEINCAPS structure provides information about the standard waveform formats that the device supports.


Opening Waveform Input Devices

Use the waveInOpen function to open a waveform input device for recording. This function opens the device associated with the specified device identifier and returns a handle of the open device by writing the handle of a specified memory location.


Selecting a Waveform Input Device

Some multimedia computers will have multiple waveform input devices. Unless you know you want to open a specific waveform input device in a system, you should use the WAVE_MAPPER constant for the device identifier when you open a device. The waveOutOpen function will choose the device in the system best able to record in the given data format.


Managing Waveform Recording

Once you open a waveform input device, you can begin recording waveform data. Waveform data is recorded into application-supplied buffers specified by a WAVEHDR structure. This is the same structure used for waveform playback described in Writing Waveform Data. Memory for the WAVEHDR structure and its accompanying data buffer must be allocated and prepared, as shown in Allocating and Preparing Audio Data Blocks.

Windows provides the following functions to manage waveform recording:

Function	Description
waveInAddBuffer	Sends a buffer to the device driver so it can be filled with recorded waveform data.
waveInReset	Stops waveform recording and marks all pending buffers as done.
waveInStart	Starts waveform recording.
waveInStop	Stops waveform recording.
Use the waveInAddBuffer function to send data buffers to the device driver. As the buffers are filled with recorded waveform data, the application is notified with either a window message or with a callback message, depending on the flag specified when the device was opened.

Use the waveInStart function to begin recording. Before beginning to record, send at least one buffer to the driver or incoming data may be lost. To stop waveform recording, use the waveInStop function.

Before closing the device by using the waveOutClose function, call the waveOutReset function to mark any pending data blocks as being done.


Using Window Messages to Manage Waveform Recording

The following messages can be sent to a window-procedure function for managing waveform recording.

Message	Description
MM_WIM_CLOSE	Sent when the device is closed using the waveInClose function.
MM_WIM_DATA	Sent when the device driver is finished with a data buffer sent using the waveInAddBuffer function.
MM_WIM_OPEN	Sent when the device is opened using the waveInOpen function.
There is a wParam and lParam parameter associated with each of these messages. The wParam parameter always specifies a handle of the open waveform device. The lParam parameter is unused for the MM_WIM_CLOSE and MM_WIM_OPEN messages.

For the MM_WIM_DATA message, lParam specifies a pointer to a WAVEHDR structure that identifies the data buffer. This data buffer may not be completely filled with waveform data, because recording can stop before the buffer is filled. Use the dwBytesRecorded member of the WAVEHDR structure to determine the amount of valid data present in the buffer.

The most useful message is MM_WIM_DATA. Unless you need to allocate memory or initialize variables, you probably don't need to use the MM_WIM_OPEN and MM_WIM_CLOSE messages. When the device driver is finished with a data block, you can clean up and free the data block as described in Allocating and Preparing Audio Data Blocks.


Using a Low-Level Callback Function to Manage Waveform Recording

The syntax of the low-level callback function for waveform input devices is as follows.

void CALLBACK waveInCallback(hWaveIn, wMsg,
    dwInstance, dwParam1, dwParam2)

The following messages can be sent in the wMsg parameter of waveform input callback functions.

Message	Description
WIM_CLOSE	Sent when the device is closed using the waveInClose function.
WIM_OPEN	Sent when the device is opened using the waveInOpen function.
These messages resemble messages sent to window-procedure functions, but their parameters are different. A handle of an open waveform device is passed as a parameter to the callback function, along with the doubleword value of instance data that was passed using waveInOpen.

The callback function has two message-specific parameters: dwParam1 and dwParam2. For the WIM_CLOSE and WIM_OPEN messages, these parameters are not used. For the WIM_DONE message, dwParam1 specifies a pointer to a WAVEHDR structure identifying the completed data block and dwParam2 is not used.

After the driver is finished with a data block, you can clean up and free the data block. Because of the suggested restrictions of low-level audio callback functions, it is better not to do this within the callback function. It is better to set events or semaphores and do this outside the callback function. For details about the suggested restrictions on using callback functions, see Using a Callback Function to Process Driver Messages.


Playing MIDI Audio

To play MIDI files, use the MCI sequencer. If the MCI sequencer services don't meet the needs of your application, you can manage MIDI playback using the low-level MIDI services.


Low-Level Audio MIDI Output Data Types

The MMSYSTEM.H header file defines data types and function prototypes for all low-level audio functions. You must include this header file in any source module that uses these functions. MMSYSTEM.H defines the following data types for low-level MIDI output function:

Type	Description
HMIDIOUT	Handle of a MIDI output device.
MIDIHDR	Structure is a header for a block of MIDI system-exclusive data. This structure is used for input as well as output.
MIDIOUTCAPS	Structure used to inquire about the capabilities of a particular MIDI output device.


Querying Low-Level MIDI Output Devices

Before playing MIDI audio, you should call the midiOutGetDevCaps function to determine the capabilities of the MIDI output hardware present in the system. This function takes a pointer to a MIDIOUTCAPS structure that it fills with information about the capabilities of a given device. This information includes the manufacturer and product identifiers, a product name for the device, and the version number of the device driver. In addition, the MIDIOUTCAPS structure provides information on the device technology, the number of voices and notes supported, the MIDI channels that the device responds to, and features supported by the driver.


Determining the Technology of the Device

MIDI output devices can be either internal synthesizers or external MIDI output ports. The wTechnology member specifies the technology of the device. MMSYSTEM.H defines the following flags to identify device technology.

Flag	Description
MOD_MIDIPORT	The device is an external MIDI output port.
MOD_SQSYNTH	Device is an internal square-wave synthesizer.
MOD_FMSYNTH	Device is an internal FM synthesizer.
MOD_SYNTH	Device is an internal synthesizer (generic).
MOD_MAPPER	Device is the MIDI Mapper.


Determining Capabilities of Internal Synthesizers

If the device is an internal synthesizer, additional device information is available in the wVoices, wNotes, and wChannelMask members of the MIDIOUTCAPS structure. If the device is an external output port, these members are unused.

The wVoices member specifies the number of voices the device supports. Each voice can have a different sound or timbre. Voices are differentiated by MIDI channel. For example, a four-voice synthesizer uses four MIDI channels. The wNotes member specifies the polyphony of the device — the maximum number of notes that can be played simultaneously. The wChannelMask member is a bit representation of the MIDI channels that the device responds to. For example, if the device responds to the first eight MIDI channels, wChannelMask is 0x00FF.

The dwSupport member of the MIDIOUTCAPS structure indicates whether the device driver supports volume changes and patch caching. MMSYSTEM.H defines the following flags for the dwSupport member.

Flag	Description
MIDICAPS_VOLUME	Indicates the driver supports volume control.
MIDICAPS_LRVOLUME	Indicates the driver supports individual volume control for the left and right channels.
MIDICAPS_CACHE	Indicates the driver supports patch caching.
Volume changes are only supported by internal synthesizer devices. External MIDI output ports don't support volume changes. For information about changing volume, see Changing Internal MIDI Synthesizer Volume.


Opening Low-Level Audio MIDI Output Devices

Use the midiOutOpen function to open a MIDI output device for playback. This function opens the device associated with the specified device identifier and returns a handle of the open device by writing the handle of a specified memory location.


Sending MIDI Messages

Once you open a MIDI output device, you can begin sending it MIDI messages by using the following functions.

Function	Description
midiOutLongMsg	Sends a buffer of MIDI data to the specified MIDI output device. Use this function to send multiple MIDI events, including system-exclusive messages, to a MIDI device.
midiOutShortMsg	Sends a MIDI message to a specified MIDI output device. This function can use running status by omitting the status byte.
midiOutReset	Turns off all notes on all channels for a specified MIDI output device. Any pending system-exclusive buffers are marked as done and returned to the application.
Use midiOutShortMsg to send any MIDI message (except for system-exclusive messages). This function takes an HMIDIOUT parameter specifying the MIDI output device to which to send the message, and a doubleword value for the MIDI message. The message is packed into the doubleword value as follows.

Word	Byte	Contents
High-order word	High-order byte	Not used
	Low-order byte	MIDI data 2 (optional)
Low-order word	High-order Byte	MIDI data 1 (optional)
	Low-order byte	MIDI status
The two MIDI data bytes are optional, depending on the MIDI status byte. The following example uses midiOutShortMsg to send a given MIDI event to a given MIDI output device.

/* Sends a given MIDI event to the given output device */

UINT sendMIDIEvent(hMidiOut, bStatus, bData1, bData2)

HMIDIOUT hMidiOut;      // handle of the output device

BYTE bStatus;           // MIDI status byte

BYTE bData1;            // first MIDI data byte

BYTE bData2;            // second MIDI data byte

{

    union {

        DWORD dwData;

        BYTE bData[4];

    } u;

    /* Construct the MIDI message */

    u.bData[0] = bStatus;

    u.bData[1] = bData1;

    u.bData[2] = bData2;

    u.bData[3] = 0;

    /* Send the message */

    return midiOutShortMsg(hMidiOut, u.dwData);

}

Note  MIDI output drivers are not required to verify data before sending it to an output port. It is up to applications to ensure that only valid data is sent using the midiOutShortMsg function.


Sending Buffered Messages

MIDI system-exclusive messages are the only MIDI messages that will not fit into a single doubleword value. System exclusive messages can be any length. Windows provides the midiOutLongMsg function for sending one or more messages, including system-exclusive messages, to MIDI output devices.

Use the MIDIHDR structure to specify MIDI system-exclusive data blocks. This structure contains a pointer to a locked data block, the data-block length, and assorted flags.

Memory for the MIDIHDR structure and the data block pointed to by lpData must be allocated and prepared, as shown in "Allocating and Preparing Audio Data Blocks."

After you send a system-exclusive data block using midiOutLongMsg, you must wait until the device driver is finished with the data block before freeing it. If you are sending multiple data blocks, you must monitor the completion of each data block so you know when to send additional blocks. (If your application uses a callback function or callback window, it will receive the MOM_DONE message when the driver finishes with the data block.) For information on different techniques for monitoring data-block completion, see Managing Audio Data Blocks.

Note  Any MIDI status byte other than a system-real-time message will terminate a system-exclusive message. If you are using multiple data blocks to send a single system-exclusive message, do not send any MIDI messages other than system-real-time messages between data blocks.


Using Window Messages to Manage Buffered Playback

The following messages can be sent to a window-procedure function for managing MIDI system-exclusive playback.

Message	Description
MM_MOM_CLOSE	Sent when the device is closed using the midiOutClose function.
MM_MOM_DONE	Sent when the device driver is finished with a data block sent using the midiOutLongMsg function.
MM_MOM_OPEN	Sent when the device is opened using the midiOutOpen function.
A wParam and lParam parameter is associated with each of these messages. The wParam parameter always specifies a handle of the open MIDI device. For the MM_MOM_DONE message, lParam specifies a pointer to a MIDIHDR structure identifying the completed data block. The lParam parameter is unused for the MM_MOM_CLOSE and MM_MOM_OPEN messages.

The most useful message is the MM_MOM_DONE message. Unless you need to allocate memory or initialize variables, you probably don't need to process the MM_MOM_OPEN and MM_MOM_CLOSE messages. When playback of a data block is completed, you can clean up and free the data block as described in Allocating and Preparing Audio Data Blocks.


Using a Callback to Manage Buffered Playback

This syntax of the low-level callback function for MIDI output devices is as follows.

void CALLBACK midiOutCallback(hMidiOut, wMsg,
    dwInstance, dwParam1, dwParam2)

The following messages can be sent to the wMsg parameter of MIDI output callback functions.

Message	Description
MOM_CLOSE	Sent when the device is closed using the midiOutClose function.
MOM_DONE	Sent when the device driver is finished with a data block sent using the midiOutLongMsg function.
MOM_OPEN	Sent when the device is opened using the midiOutOpen function.
These messages are similar to those sent to window-procedure functions, but the parameters are different. A handle of the open MIDI device is passed as a parameter to the callback function along with the doubleword value of instance data passed using midiOutOpen.

The callback function has two message-specific parameters: dwParam1 and dwParam2. For the MOM_OPEN and MOM_CLOSE messages, these parameters are not used. For the MOM_DONE message, dwParam1 specifies a pointer to a MIDIHDR structure identifying the completed data block and dwParam2 is not used.

After the driver is finished with a data block, you can clean up and free the data block. Because of the suggested restrictions on low-level audio callback functions, it is better not to do this from within the callback function. For details about the suggested restrictions on using callback functions, see Using a Callback Function to Process Driver Messages.


Sending MIDI Messages Using Running-Status

The MIDI 1.0 Specification allows the use of running-status when a message has the same status byte as the previous message. When running status is used, the status byte of subsequent messages can be omitted. You can send MIDI messages using running status by using the midiOutShortMsg function by packing the message into a doubleword value as follows.

Word	Byte	Contents
High-order word	High-order byte	Not used
	Low-order byte	Not used
Low-order word	High-order Byte	MIDI data 2 (optional)
	Low-order byte	MIDI data 1


Resetting Low-Level Audio MIDI Output

The midiOutReset function will turn off all notes, and mark any pending system-exclusive buffers as done and return them to the application. It may be useful in an application that uses MIDI output to provide the user with the ability to reset MIDI output.

Note  Terminating a system-exclusive message without sending an EOX (end-of-exclusive) byte may cause problems for the receiving device. The midiOutReset function does not send an EOX byte when it terminates a system-exclusive message; applications are responsible for doing this.


Changing Low-Level Audio Internal MIDI Synthesizer Volume

Windows provides the following functions to query and set the volume level of internal MIDI synthesizer devices.

Function	Description
midiOutGetVolume	Gets the volume level of the specified internal MIDI synthesizer device.
midiOutSetVolume	Sets the volume level of the specified internal MIDI synthesizer device.
Not all MIDI output devices support volume changes. Some devices can support individual volume changes on both the left and the right channels. For information about how to determine whether a particular device supports volume change, see Determining Capabilities of Waveform Output Devices.

Note  Unless your application is designed to be a master volume-control application providing the user with volume control for all audio devices in a system, be sure your application opens an audio device before changing its volume. Also be sure your application queries the volume level before changing it and restore the volume level to its previous level as soon as possible.

Volume is specified in a doubleword value; the high-order 16 bits specify the relative volume of the right channel, and the low-order 16 bits specify the relative volume of the left channel.

For devices that don't support individual volume changes on both the left and right channels, the low-order 16 bits specify the volume level, and the high-order 16 bits are ignored. Values for the volume level range from 0x0 (silence) to 0xFFFF (maximum volume) and are interpreted logarithmically. The perceived volume increase is the same from volume level 0x5000 to 0x6000 as it is from 0x4000 to 0x5000.

When querying volume levels using midiOutGetVolume, the volume is returned in a doubleword location specified by a pointer parameter.


Preloading Low-Level Audio Patches With Internal MIDI Synthesizers

Some internal MIDI synthesizer devices can't keep all of their patches loaded simultaneously. These devices must preload their patch data.

Windows provides the following functions to request that a synthesizer preload and cache specified patches.

Function	Description
midiOutCachePatches	Requests that an internal MIDI synthesizer device preload and cache specified melodic patches.
midiOutCacheDrumPatches	Requests that an internal MIDI synthesizer device preload and cache specified key-based percussion patches.
The midiOutCachePatches function takes a pointer to a PATCHARRAY to indicate the patches to be cached.

Each element in the array corresponds to a patch with each of the 16 bits representing one of the 16 MIDI channels. Bits are set for each of the channels that use that particular patch. For example, if patch number 0 is used by physical MIDI channels 0 and 8, set element 0 of the array to 0x0101.

The midiOutCacheDrumPatches function takes a pointer to a KEYARRAY to indicate the key-based percussion patches to be cached.

Each element in the array corresponds to a key-based percussion patch with each of the 16 bits representing one of the 16 MIDI channels. Bits are set for each of the channels that use that particular patch. For example, if the percussion patch for key number 60 is used by physical MIDI channels 9 and 15, set element 60 of the array to 0x8200.


Using the MIDI Mapper with Low-Level MIDI Functions

The MIDI Mapper provides standard patch services for device-independent playback of MIDI files. Applications that use MIDI files for audio should use the MIDI Mapper. For information about the MIDI Mapper and about authoring device-independent MIDI files, see High-Level Audio.

To use the MIDI Mapper, open it by using the midiOutOpen function with the wDeviceID parameter set to the constant MIDIMAPPER. You can then send MIDI messages to the MIDI Mapper by using the midiOutShortMsg or midiOutLongMsg function.


Recording Low-Level MIDI Audio

To record MIDI audio data, you must use low-level MIDI input functions. MCI does not currently provide a device handler for recording MIDI audio.


Low-Level Audio MIDI Input Data Types

The MMSYSTEM.H header file defines data types and function prototypes for all of the low-level audio functions. MMSYSTEM.H defines the following data types for low-level MIDI input functions.

Type	Description
HMIDIIN	A handle of a MIDI input device.
MIDIHDR	A structure that is a header for a block of MIDI system-exclusive data. This structure is used for input as well as output.
MIDIINCAPS	A structure used to inquire about the capabilities of a MIDI input device.


Querying MIDI Input Devices for Low-Level Audio

Before recording MIDI audio, you should call the midiInGetDevCaps function to determine the capabilities of the MIDI input hardware present in the system. This function takes a pointer to a MIDIINCAPS structure that it fills with information about the capabilities of a given device. This information includes the manufacturer and product identifiers, a product name for the device, and the version number of the device driver.


Opening Low-Level MIDI Input Devices

Use the midiInOpen function to open a MIDI input device for recording. This function opens the device associated with the specified device identifier and returns a handle of the open device by writing the handle of a specified memory location.


Managing MIDI Recording of Low-Level Audio

Once you open a MIDI input device, you can begin recording MIDI data. Win32 provides the following functions for managing MIDI recording.

Function	Description
midiInAddBuffer	Sends a buffer to the device driver so it can be filled with recorded MIDI data.
midiInReset	Stops MIDI recording and marks all pending buffers as done.
midiInStart	Starts MIDI recording and resets the time stamp to zero.
midiInStop	Stops MIDI recording.
Use the midiInAddBuffer function to send data buffers to the device driver for recording system-exclusive messages. Before you use midiInAddBuffer, you must allocate and prepare memory for the MIDIHDR data structure and the data block pointed to by the lpData member. For information about allocating and preparing this memory, see Allocating and Preparing Audio Data Blocks.

Use the midiInStart function to begin recording. To record system-exclusive messages, send at least one buffer to the driver with midiInAddBuffer before starting to record. As the buffers are filled with recorded data, the application is notified by one of the techniques discussed in "Managing Audio Data Blocks."

To stop recording, use the midiInStop function. Before closing the device by using the midiInClose function, call midiInReset to mark any pending data blocks as being done. Before freeing the memory used by a data block, call the midiInUnprepareHeader function to clean up the preparation performed previously.

You must use either a window-procedure function or a low-level callback function to receive MIDI data. If you want time-stamped data, you must use a low-level callback function.

To record system-exclusive messages, you must supply the device driver with data buffers. These buffers are specified by a MIDIHDR structure. This is the same structure used for MIDI buffered playback as described in "Sending Buffered Messages." Memory for the MIDIHDR structure and its accompanying data buffer must be allocated and prepared as shown in Allocating and Preparing Audio Data Blocks.


Using Window Messages to Manage MIDI Recording

The following messages can be sent to a window-procedure function for managing MIDI recording.

Message	Description
MM_MIM_CLOSE	Sent when the device is closed using the midiInClose function.
MM_MIM_DATA	Sent when a complete MIDI message is received (this message is used for all MIDI messages except system-exclusive messages).
MM_MIM_ERROR	Sent when an invalid MIDI message is received (this message is used for all MIDI messages except system-exclusive messages).
MM_MIM_LONGDATA	Sent when either a complete MIDI system-exclusive message is received, or when a data buffer sent using the midiInAddBuffer function is filled with system-exclusive data.
MM_MIM_LONGERROR	Sent when an invalid MIDI system-exclusive message is received.
MM_MIM_OPEN	Sent when the device is opened using the midiInOpen function.
A wParam and an lParam parameter are associated with each of these messages. The wParam parameter always specifies a handle of the open MIDI device. The lParam parameter is unused for the MM_MIM_CLOSE and MM_MIM_OPEN messages.

For the MM_MIM_DATA message, lParam specifies the received MIDI data. This data is packed into a doubleword value as follows.

Word	Byte	Contents
High-order word	High-order byte
	Low-order byte	MIDI data 2 (optional)
Low-order word	High-order Byte	MIDI data 1 (optional)
	Low-order byte	MIDI status
For the MM_MIM_LONGDATA message, lParam specifies a pointer to a MIDIHDR structure that identifies the data buffer for system-exclusive messages. The data buffer might not be completely filled — you usually don't know the size of the system-exclusive messages before recording them, so you must allocate a buffer large enough for the largest expected message. Use the dwBytesRecorded member of the MIDIHDR structure to determine the amount of valid data present in the buffer.


Using a Low-Level Callback Function to Manage MIDI Recording

This syntax of the low-level callback function for MIDI input devices is as follows:

void CALLBACK midiInCallback(hMidiIn, wMsg,
    dwInstance, dwParam1, dwParam2)

The following messages can be sent in the wMsg parameter of MIDI input callback functions.

Message	Description
MIM_CLOSE	Sent when the device is closed using the midiInClose function.
MIM_DATA	Sent when a complete MIDI message is received (this message is used for all MIDI messages except system-exclusive messages).
MIM_ERROR	Sent when an invalid MIDI message is received (this message is used for all MIDI messages except system-exclusive messages).
MIM_LONGERROR	Sent when an invalid MIDI system-exclusive message is received.
MIM_LONGDATA	Sent when either a complete MIDI system-exclusive message is received, or when a data buffer is filled with system-exclusive data.
MIM_OPEN	Sent when the device is opened using the midiInOpen function.
These messages are similar to those sent to window-procedure functions, but the parameters are different. A handle of the open MIDI device is passed as a parameter to the callback, along with the doubleword value of instance data that was passed using the midiInOpen value.

The callback has two message-specific parameters: dwParam1 and dwParam2. For the MIM_OPEN and MIM_CLOSE messages, these parameters are unused.

For the MIM_DATA message, dwParam1 specifies the received MIDI data and dwParam2 specifies a time stamp for the data. The data is packed into a doubleword value, as shown in the previous section on using window messages.

For the MIM_LONGDATA message, dwParam1 specifies a pointer to a MIDIHDR structure that identifies the data buffer for system-exclusive messages. As with the MIM_DATA message, dwParam2 specifies a time stamp for the data. The data buffer may not be completely filled. Use the dwBytesRecorded member of the MIDIHDR structure to determine the amount of valid data present in the buffer.

After the device driver is finished with a data block, you can clean up and free the data block. Because of the suggested restrictions on low-level audio callback functions, it is better not to do this from within the callback function. It is better to set events or semaphores and do this outside of the callback function. See Using a Callback Function to Process Driver Messages for details about the suggested restrictions on using callback functions.


Receiving Time-Stamped MIDI Messages

Because of the delay between when the device driver receives a MIDI message and the time the application receives the message, MIDI input device drivers time-stamp the MIDI message with the time the message was received. MIDI time stamps are defined as the time the first byte of the message was received and are specified in milliseconds. The midiInStart function resets the time stamps for a device to zero.

As stated earlier, to receive time stamps with MIDI input, you must use a low-level callback function. The dwParam2 parameter of the callback function specifies the time stamp for data associated with the MIM_DATA and MIM_LONGDATA messages.


Receiving Running-Status Messages

The MIDI 1.0 specification allows the use of running-status when a message has the same status byte as the previous message. When running status is used, the status byte of subsequent messages can be omitted. All MIDI input device drivers are required to expand messages using running status to complete messages — you always receive complete MIDI messages from a MIDI input device driver.


Auxiliary Audio Devices

Auxiliary audio devices are audio devices whose output is mixed with the MIDI and waveform output devices in a multimedia computer. An example of an auxiliary audio device is the compact disc audio output from a CD-ROM drive.

Control for auxiliary audio devices is provided by a software-controlled audio mixer. The mixer can reside on the motherboard of a multimedia computer, or it can be on an add-in sound card. The following illustration shows the conceptual audio-signal routing in a multimedia computer.

In this multimedia computer, there are two auxiliary audio devices: the CD-ROM and the external audio input. The external audio input is an input jack that allows the user to connect other audio devices.


Querying Low-Level Auxiliary Audio Devices

Not all multimedia systems have auxiliary audio support. You can use the auxGetNumDevs function to determine the number of controllable auxiliary devices present in a system.

To get information on a particular auxiliary audio device, use the auxGetDevCaps function. This function takes a pointer to an AUXCAPS structure that it fills with information about the capabilities of a given device.


Determining Auxiliary Audio Device Types

The MMSYSTEM.H header file defines the following flags for the wTechnology member of the AUXCAPS structure to determine the device type of an auxiliary audio device.

Flag	Description
AUXCAPS_CDAUDIO	The device is an internal CD-ROM drive.
AUXCAPS_AUXIN	The device is an auxiliary audio input jack.


Determining Capabilities of Auxiliary Audio Devices

The dwSupport member of the AUXCAPS structure indicates whether the device driver supports volume changes. The MMSYSTEM.H header file defines the following flags for the dwSupport member.

Flag	Description
AUXCAPS_VOLUME	Volume-control support
AUXCAPS_LRVOLUME	Individual volume-control support for both the left and right channels


Changing Auxiliary Audio-Device Volume

Windows provides the following functions to query and set the volume for auxiliary audio devices.

Function	Description
auxGetVolume	Gets the volume level of the specified auxiliary audio device.
auxSetVolume	Sets the volume level of the specified auxiliary audio device.
Not all auxiliary audio devices support volume changes. Some devices can support individual volume changes on both the left and the right channels. For information about how to determine whether a particular device supports volume changes, see Determining Capabilities of Waveform Output Devices.

Note  Unless your application is designed to be a master volume-control application providing the user with volume control for all audio devices in a system, you should open an audio device before changing its volume. Also be sure your application queries the volume level before changing it and restores the volume level to its previous level as soon as possible.

The volume level is specified (as it was in the waveform and MIDI volume-control functions) in a doubleword value with the high-order 16 bits specifying the relative volume of the right channel and the low-order 16 bits specifying the relative volume of the left channel. For devices that don't support individual volume control on both the left and right channels, the low-order 16 bits specify the volume level, and the high-order 16 bits are ignored.

Values for the volume level range from 0x0 (silence) to 0xFFFF (maximum volume) and are interpreted logarithmically. This means the perceived volume increase is the same from volume level 0x5000 to 0x6000 as it is from 0x4000 to 0x5000.

When querying volume levels with the auxGetVolume function, the volume is returned in a doubleword location specified by a pointer parameter.


Audio Clipboard Formats

In addition to the standard and nonstandard waveform formats previously presented in this section, there are two Clipboard formats that can be used to represent audio data: CF_WAVE and CF_RIFF. Use the CF_WAVE format to represent data in one of the standard formats, such as 11 kHz or 22 kHz PCM. Use the CF_RIFF format to represent more complex data formats that cannot be represented as standard wave files.


Low-Level Audio Functions

Following are the functions used with low-level audio services.

auxGetDevCaps
auxGetNumDevs
auxGetVolume
auxOutMessage
auxSetVolume
midiInAddBuffer
midiInClose
midiInGetDevCaps
midiInGetErrorText
midiInGetID
midiInGetNumDevs
midiInMessage
midiInOpen
midiInPrepareHeader
midiInReset
midiInStart
midiInStop
midiInUnprepareHeader
midiOutCacheDrumPatches
midiOutCachePatches
midiOutClose
midiOutGetDevCaps
midiOutGetErrorText
midiOutGetID
midiOutGetNumDevs
midiOutGetVolume
midiOutLongMsg
midiOutMessage
midiOutOpen
midiOutPrepareHeader
midiOutReset
midiOutSetVolume
midiOutShortMsg
midiOutUnprepareHeader
MidiProc
waveInAddBuffer
waveInClose
waveInGetDevCaps
waveInGetErrorText
waveInGetID
waveInGetNumDevs
waveInGetPosition
waveInMessage
waveInOpen
waveInPrepareHeader
waveInReset
waveInStart
waveInStop
waveInUnprepareHeader
waveOutBreakLoop
waveOutClose
waveOutGetDevCaps
waveOutGetErrorText
waveOutGetID
waveOutGetNumDevs
waveOutGetPitch
waveOutGetPlaybackRate
waveOutGetPosition
waveOutGetVolume
waveOutMessage
waveOutOpen
waveOutPause
waveOutPrepareHeader
waveOutReset
waveOutRestart
waveOutSetPitch
waveOutSetPlaybackRate
waveOutSetVolume
waveOutUnprepareHeader
waveOutWrite
WaveProc


Media Control Interface

The Media Control Interface (MCI) provides applications written for Microsoft® Windows® with device-independent capabilities for controlling media devices such as audio hardware, videodisc players, and animation players. This overview presents an introduction to MCI and shows how to begin using it in Windows-based applications.


About the Media Control Interface

MCI provides a device-independent, extensible interface for controlling virtually any type of media device. Because of the high level of device independence provided by MCI, you are encouraged to use MCI rather than low-level functions to access the multimedia capabilities of Windows.

Click on a topic below to view it:

•	The Architecture of MCI

•	The MCI Command Set

•	MCI Programming Interfaces

•	The Command-Message interface

•	The Command-String Interface (an introduction)

For more information about using MCI to control different types of audio devices, see High-Level Audio.


The Architecture of MCI

To provide extensibility, MCI is designed around an architecture that uses special MCI device drivers to interpret and execute MCI commands.

MCI device drivers can control media hardware directly or through the low-level multimedia functions provided by Windows. Most commonly used devices, such as waveform audio and Musical Instrument Digital Interface (MIDI) devices, are controlled through the low-level multimedia functions.


The MCI Programming Interfaces

MCI provides two programming interfaces: command string and command message.


The Command-String Interface

The command-string interface allows you to use English-language commands to communicate with MCI devices. For example, the following command string plays a WAVE file named TIMPANI.WAV.

play timpani.wav

The command-string interface is designed for use with high-level programming and authoring environments such as Microsoft® Visual Basic® and Asymetrix® ToolBook®. Use the command-string interface for applications that provide a text-based interface to let users control MCI devices.


The Command-Message Interface

The command-message interface uses a message-passing paradigm to communicate with MCI devices. The following example performs the same operation as the command-string example in The Command-String Interface.

WORD wDeviceID;

MCI_PLAY_PARMS mciPlayParms;

mciSendCommand(wDeviceID,            /* device identifier */

    MCI_PLAY,                        /* command message   */

    0,                               /* flags             */

    (DWORD) (LPVOID) &mciPlayParms); /* structure         */

The command-message interface is designed to be used by applications requiring a C-language interface to control multimedia devices. Use the command-message interface for applications that directly control multimedia devices.


The MCI Command Set

The MCI command set provides a generic core set of commands to control different types of media devices. For example, MCI uses the same command to begin playback of a waveform audio file, a videodisc track, and an animation sequence. Some devices have unique capabilities, such as the capability of an animation player to use a frame-based time format. For such devices, MCI provides extended commands that are unique to a particular type of device.

The commands in the command-string interface provide a good overview of the MCI command set. Each of these commands is represented by a similar command message in the command-message interface. For example, the close command string is the equivalent of the MCI_CLOSE command message.

Following are some commonly used commands.

Command	Description
capability	Requests information about the capabilities of a device.
close	Closes a device after it has been used.
info	Requests information about a device (for example, a description of the hardware associated with the device).
open	Opens and initializes a device.
pause	Pauses playing or recording on a device.
play	Begins playing on a device.
record	Begins recording on a device.
resume	Resumes playing or recording on a paused device.
seek	Changes the current position in the media.
set	Changes control settings, such as the time format the device is using.
status	Requests information about the status of a device (for example, whether the device is playing or paused).
stop	Stops playing or recording on a device.


About MCI Devices

MCI device drivers can be classified as either simple devices or compound devices. Simple devices do not require a data file for playback. Videodisc players and compact disc (CD) audio players are examples of simple devices. Compound devices require a data file for playback. MIDI sequencers and waveform audio players are examples of compound devices. The data file associated with a compound device is known as a device element. Examples of device elements are MIDI files and WAVE files.


Standard MCI Device Types

A device type identifies a class of MCI devices that responds to a common set of commands. Following are the currently defined device types.

Device type	Description
animation	Animation device
cdaudio	CD audio player
dat	Digital audio tape player
digitalvideo	Digital video in a window (not based on graphics device interface)
other	Undefined MCI device
overlay	Overlay device (analog video in a window)
scanner	Image scanner
sequencer	MIDI sequencer
videodisc	Videodisc player
waveaudio	Audio device that plays digitized waveform files


MCI Device Names

For any given device type, there might be several MCI drivers that share the command set but operate on different data formats. For example, for animation devices there are several MCI drivers that use the same command set but use different file formats. To uniquely identify an MCI driver, MCI uses device names.

Device names are identified in the [mci32] section of the registry. This section identifies all MCI device drivers to Windows. The following is part of a typical [mci] section.

[mci32]

WaveAudio=mciwave.dll

Sequencer=mciseq.dll

AVIVideo=mciavi.dll

CDAudio=mcicda.dll

The key name (on the left side of the equal sign) is the device name. The value corresponding to the key name (on the right side of the equal sign) identifies the filename of the MCI driver. The device name is often the same as the device type for the driver, as is the case for the WaveAudio, Sequencer, and CDAudio devices in the preceding example. The AVIVideo device is a digital video device, but it uses a unique device name.

If an MCI driver is installed using a device name that already exists in the [mci32] section, Windows appends an integer to the device name of the new driver, creating a unique device name. In the preceding example, a driver installed using the cdaudio device name would be assigned device name cdaudio1. A subsequent cdaudio device would be assigned device name cdaudio2.


Opening MCI Devices

Before using an MCI device, you must initialize it by opening it. Opening a device loads its driver into memory (if it isn't already loaded) and establishes a device identifier to identify the device in subsequent commands. (The device identifier is not used in the command-string interface.) There are several ways to specify the device you want to open:

•	With simple devices, you can open the device by specifying the device name.

•	With compound devices, you can open the device by specifying the device name, the device element, or both.

For example, the following command string opens a CD audio device (a simple device) by specifying the device name.

open cdaudio

The next command string opens a waveform audio device (a compound device) by specifying the device name and a device element.

open bells.wav type waveaudio

You can also open a compound device by specifying only the device element, as shown in the following example.

open bells.wav

If you specify only a device element when opening a compound device, MCI uses the filename extension of the device element filename to determine which device to open. The registry contains an [mci extensions] section that associates filename extensions and corresponding MCI device types. The following is part of an [mci extensions] section.

[mci extensions]

Wav=WaveAudio

Mid=Sequencer

rmi=Sequencer

avi=avivideo


Using the Command-Message Interface

Applications that require a C-language interface to MCI should use the command-message interface. The following topics provide background and detailed information about using this interface.

About Command Messages
Summary of MCI Command Messages
Sending MCI Command Messages
Opening an MCI Device
Closing an MCI Device
Using the Wait and Notify Flags
Using MCI_SYSINFO to Obtain MCI System Information
About the Command-String Interface
Sending MCI Command Strings
Additional Information About Command Strings


About Command Messages

MCI command messages consist of the following three elements:

•	A constant message value

•	A structure (parameter block) specifying additional parameters for the command

•	A set of flags specifying options for the command and validating members in the structure

Commands are sent by using the mciSendCommand function, which has parameters for the message, flags, and a pointer to the structure. For more information about the mciSendCommand function, see Sending MCI Command Messages.


Command-Message Example

For an example of an MCI command message, consider MCI_PLAY. The MMSYSTEM.H header file defines the MCI_PLAY command message, the MCI_NOTIFY, MCI_WAIT, MCI_FROM, and MCI_TO flags, and the MCI_PLAY_PARMS structure. The MCI_PLAY_PARMS structure has the following form.

typedef struct {

    DWORD   dwCallback;

    DWORD   dwFrom;

    DWORD   dwTo;

} MCI_PLAY_PARMS;

The MCI_WAIT and MCI_NOTIFY flags are option flags. MCI_WAIT tells the driver to wait until the command is complete before returning control to the application. MCI_NOTIFY tells the driver to notify the application when the command is complete. For more information on using these flags, see Using the Wait and Notify Flags.

The MCI_FROM and MCI_TO flags validate the dwFrom and dwTo members in the MCI_PLAY_PARMS structure. These members specify beginning and ending positions for the play operation. Both flags are optional. If either flag is specified, the driver takes the value from the corresponding member in the structure as a beginning or ending position; otherwise, the members are ignored.

Note  Members in a structure are ignored unless corresponding flags are specified to validate the members.


Items in Query Commands

Two command messages that query devices for information, MCI_GETDEVCAPS and MCI_STATUS, extend the command-message paradigm by adding a dwItem member to the structure and defining item constants for the member. Item constants specify which item of information is being requested. For example, MMSYSTEM.H defines the MCI_STATUS_PARMS structure for the MCI_STATUS command message as follows.

typedef struct {

    DWORD   dwCallback;

    DWORD   dwReturn;

    DWORD   dwItem;

    DWORD   dwTrack;

} MCI_STATUS_PARMS;

If you use the MCI_STATUS_ITEM flag to validate the dwItem member, make sure that dwItem contains a constant defined by MMSYSTEM.H to indicate the exact status information requested. The MCI_STATUS command message uses the following constants for dwItem:

MCI_STATUS_CURRENT_TRACK
MCI_STATUS_LENGTH
MCI_STATUS_MEDIA_PRESENT
MCI_STATUS_MODE
MCI_STATUS_NUMBER_OF_TRACKS
MCI_STATUS_POSITION
MCI_STATUS_READY
MCI_STATUS_TIME_FORMAT


Summary of MCI Command Messages

MCI defines four classifications of command messages. The command messages and options in the following two classifications are defined as the minimum command set for any MCI driver:

•	System command messages are handled directly by MCI rather than by the driver.

•	Required command messages are handled by the driver. All drivers should support the required command messages and options.

Regardless of the specific driver you use, you should be able to assume that the command messages and options in the two preceding groups are available.

The command messages in the following two classifications are not supported by all drivers:

•	Basic (or optional) command messages are used by some devices. If a device supports a basic command message, it must support a defined set of options for the command message.

•	Extended command messages are specific to certain device types or drivers. They include new command messages (for example, the MCI_PUT and MCI_WHERE command messages for the animation device type) and extensions to existing command messages (for example, the MCI_ANIM_GETDEVCAPS_CAN_STRETCH option added to the MCI_STATUS command message for the animation device type).

If you need to use a basic or extended command message or option, you should query the device driver before trying to use the command message or option (that is, unless you are certain that the MCI driver you have used during development is the same one that will be available on the delivery system). The following tables summarize the specific command messages in each category.

MCI directly processes the following system command messages, rather than passing them to MCI device drivers.

Command	Description
MCI_BREAK	Sets a break key for an MCI device.
MCI_SYSINFO	Returns information about MCI devices.
Required command messages must be supported by all MCI device drivers. The following table lists the required command messages.

Command	Description
MCI_CLOSE	Closes the device.
MCI_GETDEVCAPS	Obtains the capabilities of a device.
MCI_INFO	Obtains textual information from a device.
MCI_OPEN	Initializes the device.
MCI_STATUS	Obtains status information from the device.
Following are the basic command messages. The use of these command messages by a device is optional.

Command	Description
MCI_LOAD	Loads data from a file.
MCI_PAUSE	Stops playing.
MCI_PLAY	Starts transmitting output data.
MCI_RECORD	Starts recording data.
MCI_RESUME	Resumes playing or recording on a paused device.
MCI_SAVE	Saves data to a file.
MCI_SEEK	Seeks forward or backward.
MCI_SET	Sets the operating state of the device.
MCI_STATUS	Obtains status information about the device. (Supplements the required MCI_STATUS command message with options for devices using linear media with identifiable positions.)
MCI_STOP	Stops playing or recording.
Some MCI devices have additional command messages or add options to existing command messages. Although some extended command messages apply only to a specific device driver, most of them apply to all drivers of a particular device type. For example, the sequencer command set extends the MCI_SET command message to add time formats that are needed by MIDI sequencers.

Unless you are certain that the specific MCI driver you use during development will be available on the delivery system, do not assume that the device supports the extended command messages or options. You can use the MCI_GETDEVCAPS command message to determine whether a specific feature is supported. Applications should be ready to handle an MCIERR_UNSUPPORTED_FUNCTION return value.

The following extended command messages are available with certain device types.

Command Message	Device types	Description
MCI_CUE	waveaudio	Prepares for playing or recording.
MCI_DELETE	waveaudio	Deletes a data segment from the media element.
MCI_ESCAPE	videodisc	Sends custom information to a device.
MCI_FREEZE	overlay	Disables video acquisition to the frame buffer.
MCI_PUT	animation overlay	Defines the source, destination, and frame windows.
MCI_REALIZE	animation	Tells the device to select and realize its palette into a display context of the displayed window.
MCI_SPIN	videodisc	Starts the disc spinning or stops the disc from spinning.
MCI_STEP	animation, videodisc	Steps the play one or more frames forward or reverse.
MCI_UNFREEZE	overlay	Enables the frame buffer to acquire video data.
MCI_UPDATE	animation	Repaints the current frame into the display context.
MCI_WHERE	animation, overlay	Obtains the rectangle specifying the source, destination, or frame area.
MCI_WINDOW	animation, overlay	Controls display window options such as caption text.


Sending MCI Command Messages

Windows provides the following functions to send command messages to devices and to query devices for error information.

Function	Description
mciSendCommand	Sends a command message to an MCI device.
mciGetErrorString	Returns the error string corresponding to an error number.


The MCI Device Identifier

MCI returns a device identifier when you open a device by using the MCI_OPEN command message. Use this identifier to identify the opened device when sending subsequent commands.

MMSYSTEM.H defines a special constant, MCI_ALL_DEVICE_ID, to indicate that a command message is to be sent to all of the MCI devices that an application has opened. You can use MCI_ALL_DEVICE_ID with any command message that does not return information. For instance, the following example closes all of the MCI devices that have been opened by an application.

DWORD dwReturn;

/*

 * Closes all MCI devices opened by this application.

 * Waits until devices are closed before returning.

 */

if (dwReturn = mciSendCommand(MCI_ALL_DEVICE_ID, MCI_CLOSE,

        MCI_WAIT, NULL))

    /* Error, unable to close all devices. */

    return FALSE;

Note  Although using the MCI_ALL_DEVICE_ID identifier is a convenient way to broadcast a command to all your devices, don't rely on it to synchronize devices; the timing between messages can vary.


Opening an MCI Device

Before using a device, you must initialize it by using the MCI_OPEN command message. The variations of this command message make it one of the most complex of all MCI commands.


The MCI_OPEN_PARMS Structure

Like all MCI command messages, MCI_OPEN has an associated structure. The default structure for MCI_OPEN is the MCI_OPEN_PARMS structure. Certain devices, such as waveaudio, animation, and overlay devices, have extended structures to accommodate additional optional parameters. Unless you need to use these additional parameters, you can use the MCI_OPEN_PARMS structure with any MCI device.

MCI uses the wDeviceID member of this structure to return the device identifier to the application. You should check the return value of the mciSendCommand function before using the device identifier, to be sure that it is valid. A nonzero return value indicates that an error occurred during the opening of the device process.

Note  You can also determine the device identifier by specifying the device name in a call to the mciGetDeviceID function.

Other members used in opening a device correspond to the following flags for the command message.

Flag	Meaning
MCI_OPEN_ALIAS	The lpstrAlias member of the structure contains a pointer to a device alias.
MCI_OPEN_ELEMENT	The lpstrElementName member of the structure contains a pointer to the element name.
MCI_OPEN_SHAREABLE	The device or element was opened as shareable.
MCI_OPEN_TYPE	The lpstrDeviceType member of the structure contains a pointer to the device-type identifier.
MCI_OPEN_TYPE_ID	The lpstrDeviceType member of the structure contains an integer device-type identifier.


Opening Simple Devices

To open a simple device such as a CD audio or videodisc device, use the lpstrDeviceType member in the MCI_OPEN_PARMS structure to identify the device to open. There are three ways to identify devices:

•	Specify a pointer to a null-terminated string containing the device name.

•	Specify a device-type constant.

•	Specify the actual name of the device driver.

Regardless of which method you use to identify the device, you must specify the MCI_OPEN_TYPE flag to validate the lpstrDeviceType member. For instance, the following example opens a CD audio device by specifying the device name.

UINT wDeviceID;

DWORD dwReturn;

MCI_OPEN_PARMS mciOpenParms;

/* Open a compact disc device by specifying the device name. */

mciOpenParms.lpstrDeviceType = "cdaudio";

if (dwReturn = mciSendCommand(0, MCI_OPEN, MCI_OPEN_TYPE,

        (DWORD)(LPVOID) &mciOpenParms))

    /* Error, unable to open device. */

    return FALSE;

/* Device opened successfully. Get the device ID. */

wDeviceID = mciOpenParms.wDeviceID;

You can also open a device by specifying a device-type constant. To be opened by means of a device-type constant, device drivers must be installed in the [mci] section of the registry by using the following device types.

Device type	Device-type constant
animation	MCI_DEVTYPE_ANIMATION
cdaudio	MCI_DEVTYPE_CD_AUDIO
dat	MCI_DEVTYPE_DAT
digitalvideo	MCI_DEVTYPE_DIGITAL_VIDEO
other	MCI_DEVTYPE_OTHER
overlay	MCI_DEVTYPE_OVERLAY
scanner	MCI_DEVTYPE_SCANNER
sequencer	MCI_DEVTYPE_SEQUENCER
videodisc	MCI_DEVTYPE_VIDEODISC
waveaudio	MCI_DEVTYPE_WAVEFORM_AUDIO
If you open a device by specifying a device-type constant, you must specify the MCI_OPEN_TYPE_ID flag in addition to the MCI_OPEN_TYPE flag. The following example opens a CD audio device by specifying a device-type constant.

UINT wDeviceID;

DWORD dwReturn;

MCI_OPEN_PARMS mciOpenParms;

/*

* Open a compact disc device by

* specifying a device-type constant.

*/

mciOpenParms.lpstrDeviceType = (LPCSTR) MCI_DEVTYPE_CD_AUDIO;

if (dwReturn = mciSendCommand(0, MCI_OPEN,

        MCI_OPEN_TYPE | MCI_OPEN_TYPE_ID,

        (DWORD)(LPVOID) &mciOpenParms))

    /* Error, unable to open device. */

    return FALSE;

/* Device opened successfully. Get the device ID. */

wDeviceID = mciOpenParms.wDeviceID;

When you open a device by specifying a device-type constant, MCI uses the high-order word of the lpstrDeviceType member to distinguish between multiple occurrences of the device type in the registry.

For example, if the registry lists entries for waveaudio1 and waveaudio2, the following statement sets the lpstrDeviceType member to specify the device identified by waveaudio2.

LPSTR lpstrDeviceType;

lpstrDeviceType = (LPSTR)MAKELONG(MCI_DEVTYPE_WAVEFORM_AUDIO, 2);

Similarly, to specify the device identified by waveaudio1, set the high-order word of lpstrDeviceType to 0 or 1. (Setting the high-order word to 0 tells MCI to use an unnumbered device or the lowest-numbered device.)

You can also open a device by specifying the filename of the device driver in the lpstrDeviceType member of the MCI_OPEN_PARMS structure. You don't need to specify the complete path or the filename extension — MCI assumes that drivers are located in the Windows system directory and have a filename extension of .DRV.

Note  Opening MCI devices by specifying the filename of the device driver may be useful during development and testing. However, this technique is not recommended for applications because it makes them device dependent. Applications that open MCI devices by filename may not work in all systems.


Opening Compound Devices

There are three ways to open a compound device:

•	Specify only the device (by using the device name, a device-type constant, or the filename of the device driver).

•	Specify both the device and the device element.

•	Specify only the device element.

The first method — specifying only the device — is useful for determining the capabilities of a device by using the MCI_GETDEVCAPS command message. To actually control a media device, you must specify a device element when you open the device.

To specify a device element, fill the lpstrElementName member of the MCI_OPEN_PARMS structure with a pointer to a null-terminated string containing the filename of the device element. You must also validate the lpstrElementName member by specifying the MCI_OPEN_ELEMENT flag in the dwFlags parameter of the mciSendCommand function.

You can specify the device in the same manner used for simple devices: by device name, by device-type constant, or by the filename of the driver. The following example opens the waveaudio device with a WAVE file named TIMPANI.WAV.

UINT wDeviceID;

DWORD dwReturn;

MCI_OPEN_PARMS mciOpenParms;

/*

 * Open a waveaudio device by specifying

 * the device name and device element.

 */

mciOpenParms.lpstrDeviceType = "waveaudio";

mciOpenParms.lpstrElementName = "timpani.wav";

if (dwReturn = mciSendCommand(0, MCI_OPEN,

        MCI_OPEN_TYPE | MCI_OPEN_ELEMENT,

        (DWORD)(LPVOID) &mciOpenParms))

    /* Error, unable to open device. */

    return FALSE;

/* Device opened successfully. Get the device ID. */

wDeviceID = mciOpenParms.wDeviceID;

You can also open a device by specifying just a device element. MCI uses the filename extension of the given device element along with the [mci extensions] section of the registry to select the device to open. For more information about opening devices by specifying only a device element, see Opening MCI Devices.


Closing an MCI Device

The MCI_CLOSE command message releases access to a device or device element. MCI frees a device when all processes using a device have closed it. To help MCI manage devices, applications should explicitly close each device or device element when they are finished using it.

Note  It is very important that applications close all opened MCI devices before terminating. You can close all devices with a single command message by specifying the MCI_ALL_DEVICE_ID constant as the device identifier.


Using the Wait and Notify Flags

Typically, MCI returns control to the application immediately, even if it takes several seconds to complete the action initiated by a command. For example, after a CD audio device receives a seek command, control returns to the application before the seek operation is complete. You can use the following two flags to request that MCI wait until a command is complete before returning control to the application, or that MCI notify the application when the command is complete.

Flag	Description
MCI_NOTIFY	Directs the device to return control immediately and post the MM_MCINOTIFY message when the requested action is complete.
MCI_WAIT	Directs the device to wait until the requested action is complete before returning control to the application.


Using the Notify Flag

The MCI_NOTIFY flag directs MCI to post the MM_MCINOTIFY message when the device completes an action. The application specifies the handle of the destination window for the message in the dwCallBack member of the structure sent with the command message. Every structure associated with a command message contains this member.

Note  MCI can have only one pending notification message for each device.

When MCI posts the MM_MCINOTIFY message, it sets the low-order word of the lParam parameter of the window procedure to the identifier of the device initiating the callback. The wParam parameter of the window procedure contains one of the following constants specifying the notification status of the callback.

Flag	Meaning
MCI_NOTIFY_SUCCESSFUL	The conditions required for initiating the callback are satisfied and the command finished without interruption.
MCI_NOTIFY_SUPERSEDED	MCI had a notification pending and received another notify request. MCI resets the callback conditions to correspond to the notify request of the new command.
MCI_NOTIFY_ABORTED	The application sent a new command that prevented the callback conditions set by a previous command from being satisfied. If an application interrupts a command that requested notification, MCI does not inform the window procedure of the notify command being aborted.
MCI_NOTIFY_FAILURE	A device error occurred while a device was executing the command. For example, MCI posts this message when a hardware error occurs during a play command.


Using the Wait Flag and Break Command Message

Specifying the MCI_WAIT flag with a command message causes MCI to wait until the command has finished before returning control to the application. Using the wait flag with commands that take a long time essentially disables a system from receiving any user input until the command is complete.

MCI supports a break key to interrupt the wait operation and return control to the application. The break key does not interrupt the command, but by returning control to the application, it allows the application to monitor user input.

By default, MCI defines the break key as CTRL+BREAK. Applications can redefine this key by using the MCI_BREAK command message. MCI_BREAK uses the MCI_BREAK_PARMS structure.

The following flags validate members in the MCI_BREAK_PARMS structure:

Flag	Description
MCI_BREAK_HWND	Validates the hwndBreak member, which specifies the window that must have the focus to enable break detection.
MCI_BREAK_KEY	Validates the nVirtKey member, which specifies the virtual-key code to be used for the break key.
MCI_BREAK_OFF	Disables any existing break key.


Using MCI_SYSINFO to Obtain MCI System Information

The MCI_SYSINFO command message obtains system information about MCI devices. MCI handles this message without relaying it to any MCI device. MCI returns the system information in the MCI_SYSINFO_PARMS structure.

The MCI_SYSINFO command message has the following flags.

Flag	Meaning
MCI_SYSINFO_QUANTITY	MCI returns the number of devices of a given type listed in the [mci] section of the registry. When this flag is used with the MCI_SYSINFO_OPEN flag, the number of open devices is returned.
MCI_SYSINFO_NAME	MCI returns the name of a device that satisfies the query. When this flag is used with the MCI_SYSINFO_OPEN flag, only the names of open devices are returned.
MCI_SYSINFO_OPEN	MCI returns the number or names of open devices.
MCI_SYSINFO_INSTALLNAME	MCI returns the name listed in the registry entry used to install the device.
You use the MCI_SYSINFO_QUANTITY flag to determine the number of devices for a particular type listed in the [mci] section of the registry. For this flag, set the wDeviceType member of the structure to the device type. When requesting the number of devices, set the wDeviceID parameter to NULL. MCI returns the number of devices as a doubleword in the lpstrReturn member of the structure. If you combine the MCI_SYSINFO_QUANTITY flag with the MCI_SYSINFO_OPEN flag, MCI returns the number of devices of that type opened by the process.

Once you have the number of devices, you can enumerate the names of the devices by using the MCI_SYSINFO_NAME flag. To get information by using this flag, you must create a buffer for the return name. In the structure, specify a pointer to the buffer, the size of the buffer, the index number corresponding to the device (1 is the first device), and the device type. This information is entered in the lpstrReturn, dwRetSize, dwNumber, and wDeviceType members. MCI returns the device name in the buffer. When requesting the name of a particular device, set the wDeviceID parameter to NULL. To restrict the names to open devices, use the MCI_SYSINFO_OPEN flag with MCI_SYSINFO_NAME.

To retrieve information on all devices in the system, you can assign the MCI_ALL_DEVICE_ID constant to the wDeviceID parameter. When you use this identifier, MCI ignores the contents of the wDeviceType member and returns information on all MCI devices listed in the registry. When you use the MCI_SYSINFO_OPEN flag with the MCI_ALL_DEVICE_ID identifier, MCI returns information about the devices opened by the task.

You can retrieve the installation name of an open device by using the MCI_SYSINFO_INSTALLNAME flag. To get the installation name, you must create a buffer for the return name. In the structure, specify a pointer to the buffer and the size of the buffer in the lpstrReturn and dwRetSize members. MCI places the device that corresponds to the wDeviceID parameter name in the buffer.


About the Command-String Interface

This section presents an introduction to the MCI command-string interface. MCI provides the following functions for working with command strings.

Function	Description
mciSendString	Sends a command string to an MCI device driver. This function also has parameters for callback functions and return strings.
mciGetErrorString	Returns the error string corresponding to an error number.


Sending MCI Command Strings

Use the mciSendString function to send command strings to a device. The following statement passes the "play to 500" command string to a waveaudio device driver.

DWORD dwErrorCode;

dwErrorCode = mciSendString("play waveaudio to 500", NULL, 0, 0L);

If the mciSendString function succeeds, it returns zero. If the function fails, it returns an error code. To get extended error information, use the mciGetErrorString function.


Additional Information About Command Strings

The MCITEST application contains examples of using the mciSendString and mciGetErrorString functions. You can use this application to experiment with MCI devices and command strings.


Multimedia File Input/Output

Most multimedia applications require file input/output (I/O) — the ability to create, read, and write disk files. The multimedia file I/O services provided by the Microsoft® Win32® application programming interface (API) offer buffered and unbuffered file I/O and support for standard Resource Interchange File Format (RIFF) files. The services are extensible with custom I/O procedures.


About the Multimedia File Input/Output Services

Most applications need only the basic file I/O services and the RIFF file I/O services. Applications sensitive to file I/O performance, such as applications that stream data from a CD-ROM in real time, can optimize performance by using services to directly access the file I/O buffer. Applications that access custom storage systems can provide their own I/O procedure that reads and writes elements of the storage system. A storage system is a method of physically storing data in a file, such as a file-archival system or a database storage system.

This section covers the following topics:

•	Using basic file I/O services

•	Performing buffered file I/O

•	Working with RIFF files

•	Directly accessing a file I/O buffer

•	Using memory files

•	Writing a custom I/O procedure

The multimedia file I/O services provide support for the following file I/O operations:

•	Basic unbuffered and buffered file I/O

•	RIFF file I/O

•	Direct access to the file I/O buffer

•	Memory files

•	Custom storage system I/O using application-supplied I/O procedures


Comparison With Other File I/O

You might ask why you need another set of file I/O services, when you already have the services of the C run-time and Win32 API libraries. The multimedia file I/O services offer the following advantages over other file I/O services:

•	They are a part of the system software, so they don't increase the size of your application, like linking to the C run-time libraries

•	They provide more functionality than the Win32 services, such as support for buffered I/O, RIFF files, memory files, and custom storage systems

In addition, the multimedia file I/O services are optimized for performance-intensive applications.


Function Prefixes

All multimedia file I/O function names begin with the mmio prefix. Similarly, all multimedia file I/O message names begin with the MMIOM_ prefix.


Data Types

The MMSYSTEM.H header file defines data types and function prototypes for all multimedia file I/O functions. You must include this header file in any source-code module that uses these functions. MMSYSTEM.H depends on declarations made in WINDOWS.H, so you must first include the WINDOWS.H header file. MMSYSTEM.H defines the following data types for the multimedia file I/O functions.

Type	Description
FOURCC	A four-character code identifying an element of a RIFF file.
HMMIO	A handle of an open file.
MMCKINFO	A structure containing information about a chunk in a RIFF file.
MMIOINFO	A structure used to maintain the current state of a file accessed using the multimedia file I/O services.
MMIOPROC	A custom multimedia file I/O procedure.


Performing Basic File Input/Output

Using the basic I/O services is similar to using the C run-time file I/O services. Files must be opened before they can be read or written. After reading or writing, the file must be closed. You can change the current read/write location by seeking to a specified position in an open file. The following table lists the basic file I/O functions.

Function	Description
mmioClose	Closes an open file.
mmioOpen	Opens a file for reading or writing or both and returns a handle of the open file.
mmioRead	Reads a specified number of bytes from an open file.
mmioSeek	Changes the current position for reading or writing in an open file.
mmioWrite	Writes a specified number of bytes to an open file.
These file I/O functions provide the core of the multimedia file I/O services — you can use them for buffered and unbuffered I/O, as well as for I/O to RIFF files, memory files, and custom storage systems.


Opening a Multimedia File

Before doing any I/O operations to a file, you must first open the file by using the mmioOpen function. The mmioOpen function returns a file handle that you use to identify the open file when calling other file I/O functions.

Note  Do not use HMMIO file handles with Windows or C run-time file I/O functions.

There are options you can use with the mmioOpen function for operations beyond basic file I/O. By specifying an MMIOINFO structure with the lpmmioinfo parameter you can open memory files, specify a custom I/O procedure, or supply a buffer for buffered I/O. These topics are discussed later in this section. First, this section discusses the most basic use of mmioOpen — opening files for basic unbuffered file I/O.

To open a file for basic I/O operations, set the lpmmioinfo parameter of mmioOpen to NULL. For example, the following example opens a file named C:\SAMPLES\SAMPLE1.TXT for reading, and checks the return value for errors.

HMMIO hFile;

.ifdef REF

    .

    .

    .

.endif

if ((hFile = mmioOpen("C:\\SAMPLES\\SAMPLE1.TXT",

        NULL, MMIO_READ)) != NULL) /* File opened successfully */

    return TRUE;

else

        /* File cannot be opened. */

    return FALSE;


Options for Opening a File

When you open a file, you must specify whether you are opening the file for reading, writing, or both reading and writing. In addition, you can specify other options, such as to create or delete a new file. Use the dwFlags parameter of mmioOpen to specify options for opening a file.

Following are the basic options for opening a file using mmioOpen:

Flag	Description
MMIO_READ	Opens a file for reading only.
MMIO_WRITE	Opens a file for writing only.
MMIO_READWRITE	Opens a file for reading and writing.
MMIO_CREATE	Creates a new file (if the file already exists, it truncates it to zero length).
MMIO_DELETE	Deletes a file.
MMIO_ALLOCBUF	Opens a file for buffered I/O.
The MMIO_READ, MMIO_WRITE, and MMIO_READWRITE flags are read/write privilege flags. These flags are mutually exclusive — specify only one when opening a file. If you don't specify one of these flags, mmioOpen opens the file for reading only.

The MMIO_CREATE and MMIO_DELETE flags are also mutually exclusive. You can specify one of the read/write privilege flags with the MMIO_CREATE flag. You can't specify any additional flags with the MMIO_DELETE flag.

For information on using the MMIO_ALLOCBUF flag, see Performing Buffered File Input/Output.

In addition to the basic options for opening a file, there are sharing options you can use for opening files so they can be opened and accessed by more than one process. Following are the sharing options for opening a file using mmioOpen.

Flag	Description
MMIO_COMPAT	Opens a file in compatibility mode.
MMIO_EXCLUSIVE	Opens a file in exclusive mode.
MMIO_DENYWRITE	Opens a file and denies other processes write access to the file.
MMIO_DENYREAD	Opens a file and denies other processes read access to the file.
MMIO_DENYNONE	Opens a file without denying other processes read or write access to the file.


Creating and Deleting Files

To create a new file, specify the MMIO_CREATE option with the mmioOpen function. For example, the following example creates a new file and opens it for both reading and writing.

HMMIO hFile;

.ifdef REF

    .

    .

    .

.endif

hFile = mmioOpen("NEWFILE.TXT",

                  NULL, MMIO_CREATE | MMIO_READWRITE);

if (hFile != NULL)

        /* File created successfully. */

    return TRUE;

else

        /* File could not be created. */

    return FALSE;

Note  If the file you are creating already exists, it will be truncated to zero length.

To delete a file, specify the MMIO_DELETE flag with the mmioOpen function. Once you delete a file, it can't be recovered. If the file deletion is the result of a request from a user, always query the user to be sure the user wants to delete the specified file before you actually delete it.


Reading and Writing a File

To read and write to open files, use the mmioRead and mmioWrite functions. Each of these functions takes an HMMIO file handle, a pointer to a buffer, and a parameter specifying the number of bytes to read or write.

For an example using mmioRead to read from a file, see Example of RIFF File I/O.


Seeking to a New Position in a Multimedia File

The current position or file pointer in a file is the location where the next read or write operation will occur. To change the current position in an open file, use the mmioSeek function.

The return value is the new position, specified in bytes from the beginning of the file. If an error occurs, the return value is −1. If you seek to an invalid location in a file, such as past the end of the file, mmioSeek may not return an error, but subsequent I/O operations can fail.


Performing Buffered File Input/Output

Most of the overhead in file I/O involves accessing the media (the physical device). If you are reading or writing many small blocks of information, the media device can spend a lot of time seeking the physical location on the media for each read or write operation. In this case, better performance is achieved by using buffered file I/O. With buffered I/O, the file I/O manager maintains an intermediate buffer larger than the blocks of information you are reading or writing. It only accesses the media when the buffer must be filled from or written to the disk.


Deciding When to Use Buffered File I/O

It's difficult to provide exact metrics telling you when you need to use buffered I/O. It depends on how many read and write operations you perform on a file, and on the size of these read and write operations. A general guideline is to use buffered I/O if you are doing many small I/O operations (less than 2 kilobytes each). But this rule isn't absolute — it's best to understand exactly how your program uses file I/O and experiment to optimize file I/O for your program's requirements.


Opening a File for Buffered File I/O

The multimedia file I/O manager provides several ways to set up and use buffered file I/O. The main distinction between these different approaches is whether the file I/O manager or the application allocates the buffer — either the file I/O manager or the application can allocate the I/O buffer. Unless you want to access the I/O buffer directly or open a memory file, let the file I/O manager allocate the buffer. For more information about accessing an I/O buffer directly and using memory files, see Directly Accessing a File Input/Output Buffer and Performing File Input/Output on Memory Files.

A buffer allocated by the file I/O manager is called an internal buffer. To open a file for buffered I/O using an internal buffer, specify the MMIO_ALLOCBUF flag with the mmioOpen function when you open the file. Once a file is opened for buffered I/O, the buffer is essentially transparent to the application. You can read, write, and seek the same way as with unbuffered I/O.


I/O Buffer Control Functions

The multimedia file I/O services also include some functions that give you more control over the file I/O buffer. Using the following functions, you can force the contents of an I/O buffer to be written to disk, enable buffered I/O on a file opened for unbuffered I/O, change the size of an I/O buffer, and supply your own I/O buffer.

Function	Description
mmioFlush	Writes the contents of the I/O buffer to disk.
mmioSetBuffer	Changes the size of the I/O buffer, and allows applications to supply their own buffer.


Flushing an I/O Buffer

Flushing an I/O buffer means writing the contents of the buffer to disk. You don't have to call the mmioFlush function to flush an I/O buffer — the buffer is automatically flushed when you close a file using the mmioClose function. If you don't close a file immediately after writing to it, you flush the buffer to ensure the information is written to disk.

Note  If you run out of disk space, mmioFlush may fail, even if the preceding mmioWrite calls were successful. Similarly, mmioClose may fail when it is flushing its I/O buffer.


Changing the Size of the Internal I/O Buffer

The default size of the internal I/O buffer is 8K. If this size is not adequate, you can use the mmioSetBuffer function to change the size of the buffer. You can also use mmioSetBuffer to enable buffering on a file opened for unbuffered I/O.

The following example opens a file named SAMPLE.TXT for unbuffered I/O, and then enables buffered I/O with an internal 16K buffer.

HMMIO hFile;

.ifdef REF

    .

    .

    .

.endif

if ((hFile = mmioOpen("SAMPLE.TXT", NULL, MMIO_READ)) != NULL) {

    /* File opened successfully; request an I/O buffer */

    if (mmioSetBuffer(hFile, NULL, 16384L, 0))

            /* Buffer cannot be allocated. */

        return FALSE;

    else

            /* Buffer allocated successfully. */

        return TRUE;

}

else

        /* File cannot be opened. */

    return FALSE;


Supplying Your Own I/O Buffer

You can also use mmioSetBuffer to supply your own buffer for use as a memory file. For details on using memory files, see Performing File Input/Output on Memory Files.


Working With RIFF Files

The preferred format for multimedia files is the Resource Interchange File Format (RIFF). The RIFF format is a tagged-file structure.

The multimedia file I/O services provide the following functions to support file I/O to RIFF files.

Function	Description
mmioAscend	Ascends out of a RIFF file chunk to the next chunk in the file.
mmioCreateChunk	Creates a new chunk in a RIFF file.
mmioDescend	Descends into a RIFF file chunk beginning at the current file position, or searches for a specified chunk.
mmioFOURCC	Converts four individual characters into a four-character code.
mmioStringToFOURCC	Converts a null-terminated string into a four-character code.
These functions work with the basic buffered and unbuffered file I/O services — you can open, read, and write RIFF files the same as other file types.


About RIFF Files

The basic building block of a RIFF file is called a chunk. Each chunk consists of the following fields:

•	A four-character code specifying the chunk identifier

•	A doubleword specifying the size of the data field in the chunk

•	A data field

The only chunks allowed to contain other chunks (subchunks) are those with a chunk identifier of "RIFF" or "LIST". The first chunk in a RIFF file must be a "RIFF" chunk. All other chunks in the file are subchunks of the "RIFF" chunk.


"RIFF" Chunks

"RIFF" chunks include an additional field in the first four bytes of the data field. This additional field provides the form type of the field. The form type is a four-character code identifying the format of the data stored in the file. For example, Microsoft waveform audio files (WAVE files) have a form type of "WAVE". The following illustration shows a "RIFF" chunk containing two subchunks.


"LIST" Chunks

"LIST" chunks also include an additional field in the first four bytes of the data field. This additional field contains the list type of the field. The list type is a four-character code identifying the contents of the list. For example, a "LIST" chunk with a list type of "INFO" can contain "ICOP" and "ICRD" chunks providing copyright and creation date information. The following illustration shows a "RIFF" chunk containing a "LIST" chunk and one other subchunk (the "LIST" chunk contains two subchunks).


Generating Four-Character Codes

A four-character code is a 32-bit quantity representing a sequence of one to four ASCII alphanumeric characters, padded on the right with blank characters. The data type for a four-character code is FOURCC. Use the mmioFOURCC function to convert four characters to a four-character code, as shown in the following example, which generates a four-character code for "WAVE":

FOURCC fourccID;

.ifdef REF

    .

    .

    .

.endif

fourccID = mmioFOURCC('W', 'A', 'V', 'E');

To convert a null-terminated string into a four-character code, use the mmioStringToFOURCC function, as shown in the following example, which also generates a four-character code for "WAVE":

FOURCC fourccID;

.ifdef REF

    .

    .

    .

.endif

fourccID = mmioStringToFOURCC("WAVE", 0);

The second parameter in mmioStringToFOURCC specifies options for converting the string to a four-character code. If you specify the MMIO_TOUPPER flag, mmioStringToFOURCC converts all alphabetic characters in the string to uppercase. This is useful when you need to specify a four-character code to identify a custom I/O procedure (four-character codes identifying file-extension names must be all uppercase).


Creating RIFF Chunks

To create a new chunk, use the mmioCreateChunk function to write a chunk header at the current position in an open file.

The following example creates a new chunk with a chunk ID of "RIFF" and a form type of "RDIB".

HMMIO    hmmio;

MMCKINFO mmckinfo;

.ifdef REF

    .

    .

    .

.endif

mmckinfo.fccType = mmioFOURCC('R', 'D', 'I', 'B');

mmioCreateChunk(hmmio, &mmckinfo, MMIO_CREATERIFF);

If you're creating a "RIFF" or "LIST" chunk, you must specify the form type in the fccType field of the MMCKINFO structure. In the previous example, the form type is "RDIB".

If you know the size of the data field in a new chunk, you can set the cksize member in the MMCKINFO structure when you create the chunk. This value will be written to the data size field in the new chunk. If this value is not correct when you call the mmioAscend function to mark the end of the chunk, it will be rewritten automatically to reflect the correct size of the data field.

After you create a new chunk using mmioCreateChunk, the file position is set to the data field of the chunk (8 bytes from the beginning of the chunk). If the chunk is a "RIFF" or "LIST" chunk, the file position is set to the location following the form type or list type (12 bytes from the beginning of the chunk).


Navigating RIFF Files

RIFF files consist of nested chunks of data. Multimedia file I/O services include two functions you can use to navigate between chunks in a RIFF file: mmioAscend and mmioDescend. You might think of these functions as high-level seek functions. When you descend into a chunk, the file position is set to the data field of the chunk (8 bytes from the beginning of the chunk). For "RIFF" and "LIST" chunks, the file position is set to the location following the form type or list type (12 bytes from the beginning of the chunk). When you ascend out of a chunk, the file position is set to the location following the end of the chunk.


Descending Into a Chunk

The mmioDescend function descends into a chunk or searches for a chunk, beginning at the current file position.

The mmioDescend function fills an MMCKINFO structure with information on the chunk. This information includes the chunk identifier, the size of the data field, and the form type, or list type if the chunk is a "RIFF" or "LIST" chunk.


Searching for a Chunk

To search for a chunk in an open RIFF file, specify the MMIO_FINDCHUNK flag in the wFlags parameter of mmioDescend. Set the ckid member of the MMCKINFO structure referenced by lpck to the four-character code of the chunk you want to search for.

If you are searching for a "RIFF" or "LIST" chunk, you don't need to set the ckid member of the MMCKINFO structure — mmioDescend sets this member for you. Set the fccType member to the four-character code of the form type or list type of the chunk.

The following example searches for a "RIFF" chunk with a form type of "WAVE" to verify that the file that has just been opened is a WAVE waveform audio file.

HMMIO    hmmio;

MMCKINFO mmckinfoParent;

MMCKINFO mmckinfoSubchunk;

.ifdef REF

    .

    .

    .

.endif

/*

 * Locate a "RIFF" chunk with a "WAVE" form type

 * to make sure the file is a WAVE file.

 */

mmckinfoParent.fccType = mmioFOURCC('W', 'A', 'V', 'E');

if (mmioDescend(hmmio, (LPMMCKINFO) &mmckinfoParent,

                NULL, MMIO_FINDRIFF))

        /* The file is not a WAVE file. */

    return FALSE;

else

        /* The file is a WAVE file. */

    return TRUE;

If the chunk you are searching for is a subchunk enclosed by a parent chunk (as are all chunks other than "RIFF" chunks), you should identify the parent chunk with the lpckParent parameter. In this case, mmioDescend will only search within the specified parent chunk.

The following example searches for the "fmt " chunk in the "RIFF" chunk descended into by the previous example.

/*

 * Find the format chunk (form type "fmt "); it should be

 * a subchunk of the "RIFF" parent chunk.

 */

mmckinfoSubchunk.ckid = mmioFOURCC('f', 'm', 't', ' ');

if (mmioDescend(hmmio, &mmckinfoSubchunk, &mmckinfoParent,

        MMIO_FINDCHUNK)) {

        /* Error, cannot find the "fmt " chunk. */

    return FALSE;

}

else {

        /* "fmt " chunk found. */

    return TRUE;

}

If you do not specify a parent chunk, the current file position should be at the beginning of a chunk before you call mmioDescend to search for a chunk. If you do specify a parent chunk, the current file position can be anywhere in the parent chunk.

If the search for a subchunk fails, the current file position is undefined. You can use the mmioSeek function and the dwDataOffset field of the MMCKINFO structure for the enclosing parent chunk to seek back to the beginning of the parent chunk, as in the following example:

mmioSeek(hmmio, mmckinfoParent.dwDataOffset + 4, SEEK_SET);

Since the dwDataOffset member specifies the offset to the beginning of the data portion of the chunk, you must seek four bytes past dwDataOffset to set the file position to be after the form type.


Ascending Out of a Chunk

After you descend into a chunk and read the data in the chunk, you can move the file position to the beginning of the next chunk by ascending out of the chunk by using the mmioAscend function.

For example, the following statement ascends out of the "fmt " subchunk descended into by the previous example, illustrating searching for a subchunk:

/* Ascend out of the "fmt " subchunk.

 */

mmioAscend(hmmio, &mmckinfoSubchunk, 0);


Example of RIFF File I/O

The following example shows how to open a RIFF file for buffered I/O, as well as how to descend, ascend, and read RIFF chunks.

/* ReversePlay--Plays a WAVE waveform audio file backwards. */

void ReversePlay(void)

{

    char        szFileName[128];           /* filename of file to open */

    HMMIO       hmmio;                    /* file handle for open file */

    MMCKINFO    mmckinfoParent;  /* parent chunk information structure */

    MMCKINFO    mmckinfoSubchunk; /* subchunk information structure    */

    DWORD       dwFmtSize;        /* size of "fmt" chunk               */

    DWORD       dwDataSize;       /* size of "data" chunk              */

    WAVEFORMAT  *pFormat;         /* pointer to memory for "fmt" chunk */

.ifdef REF

    ...

.endif

    /* Get the filename from the edit control. */

.ifdef REF

     ...

.endif

    /*

     * Open the given file for reading with buffered I/O

     * using the default internal buffer.

     */

    hmmio = mmioOpen(szFileName, NULL, MMIO_READ | MMIO_ALLOCBUF);

    if(hmmio == NULL){

        Error("Failed to open file.");

        return;

    }

    /*

     * Locate a "RIFF" chunk with a "WAVE" form type

     * to make sure the file is a WAVE file.

     */

    mmckinfoParent.fccType = mmioFOURCC('W', 'A', 'V', 'E');

    if (mmioDescend(hmmio, (LPMMCKINFO) &mmckinfoParent, NULL,

                    MMIO_FINDRIFF)) {

        Error("This is not a WAVE file.");

        mmioClose(hmmio, 0);

        return;

    }

    /*

     * Find the "fmt " chunk (form type "fmt "); it must be

     * a subchunk of the "RIFF" parent chunk.

     */

    mmckinfoSubchunk.ckid = mmioFOURCC('f', 'm', 't', ' ');

    if (mmioDescend(hmmio, &mmckinfoSubchunk, &mmckinfoParent,

                    MMIO_FINDCHUNK)) {

        Error("WAVE file has no \"fmt\" chunk");

        mmioClose(hmmio, 0);

        return;

    }

    /*

     * Get the size of the "fmt " chunk--allocate and lock memory for it.

     */

    dwFmtSize = mmckinfoSubchunk.cksize;

.ifdef REF

    ...

.endif

    /* Read the "fmt " chunk. */

    if (mmioRead(hmmio, (HPSTR) pFormat, dwFmtSize) != (LRESULT)dwFmtSize){

        Error("Failed to read format chunk.");

.ifdef REF

        ...

.endif

        mmioClose(hmmio, 0);

        return;

    }

    /* Ascend out of the "fmt " subchunk. */

    mmioAscend(hmmio, &mmckinfoSubchunk, 0);

    /*

     * Find the data subchunk. The current file position

     * should be at the beginning of the data chunk.

     */

    mmckinfoSubchunk.ckid = mmioFOURCC('d', 'a', 't', 'a');

    if (mmioDescend(hmmio, &mmckinfoSubchunk, &mmckinfoParent,

                    MMIO_FINDCHUNK)) {

        Error("WAVE file has no data chunk.");

.ifdef REF

        ...

.endif

        mmioClose(hmmio, 0);

        return;

    }

    /* Get the size of the data subchunk. */

    dwDataSize = mmckinfoSubchunk.cksize;

    if (dwDataSize == 0L) {

        Error("The data chunk contains no data.");

.ifdef REF

        ...

.endif

        mmioClose(hmmio, 0);

        return;

    }

    /* Open a waveform output device. */

.ifdef REF

    ...

.endif

    /* Allocate and lock memory for the waveform data. */

.ifdef REF

    ...

.endif

    /* Read the waveform data subchunk. */

    if(mmioRead(hmmio, (HPSTR) lpData,

            dwDataSize) != (LRESULT)dwDataSize) {

        Error("Failed to read data chunk.");

.ifdef REF

        ...

.endif

        mmioClose(hmmio, 0);

        return;

    }

    /* Close the file. */

    mmioClose(hmmio, 0);

    /* Reverse the sound and play it. */

.ifdef REF

    ...

.endif

}


Directly Accessing a File Input/Output Buffer

Applications that are performance sensitive, such as applications that must stream data in real time from a CD-ROM, can optimize file I/O performance by accessing the file I/O buffer directly. Exercise care if you choose to do this — by accessing the file I/O buffer directly, you bypass some of the safeguards and error checking provided by the file I/O manager.

The multimedia file I/O services provide the following functions to support direct I/O buffer access.

Function	Description
mmioAdvance	Fills and/or flushes the I/O buffer of a file set up for direct I/O buffer access.
mmioGetInfo	Retrieves information on the file I/O buffer of a file opened for buffered I/O.
mmioSetInfo	Changes information on the file I/O buffer of a file opened for buffered I/O.
To access a file I/O buffer directly, open the file for buffered I/O as described in "Performing Buffered File I/O." You can use the internal file I/O buffer or supply your own buffer by using the mmioSetBuffer function.


Getting Information on the File I/O Buffer

Use the mmioGetInfo function to get information on a file I/O buffer, such as the buffer size and address.


Reading and Writing the File I/O Buffer

There are three members in the MMIOINFO structure used for reading and writing the file I/O buffer: pchNext, pchEndRead, and pchEndWrite. The pchNext field points to the next location in the buffer to read or write. You must increment pchNext as you read and write the buffer. The pchEndRead field identifies the last valid character you can read from the buffer. Likewise, pchEndWrite identifies the last location in the buffer you can write. To be precise, both pchEndRead and pchEndWrite point to the memory location following the last valid data in the buffer.


Advancing the File I/O Buffer

When you reach the end of the file I/O buffer, you must advance the buffer to fill it from the disk (if you are reading), and flush it to the disk (if you are writing). Use the mmioAdvance function to advance a file I/O buffer.

The mmioAdvance function advances the buffer by (pchNext − cchBuffer) bytes. All data in the buffer before pchNext is assumed to have been read already, while all data from pchNext to pchEndRead will be considered unread. So, when mmioAdvance is called, all data before pchNext will be overwritten. The buffer must not be treated as an array and pchNext must be incremented until pchNext equals pchEndRead.

The following illustrations show how the file I/O buffer is advanced as a file is read or written.


Using the mmioAdvance Function

To fill a file I/O buffer from disk, call mmioAdvance with the MMIO_READ flag. If there is not enough data remaining in the file to fill the buffer, the pchEndRead member in the MMIOINFO structure points to the location following the last valid byte in the buffer.

To flush a buffer to disk, first set the MMIO_DIRTY flag in the dwFlags member of the MMIOINFO structure. Then call mmioAdvance with the MMIO_WRITE flag.


Example of Accessing a File I/O Buffer

The following example is based on the ReversePlay example function discussed earlier in this section. In this example, direct-buffer access is used to read waveform data from a file.

HMMIO    hmmio;

MMIOINFO mmioinfo;

DWORD    dwDataSize;

DWORD    dwCount;

HPSTR    hptr;

.ifdef REF

    .

    .

    .

.endif

/* Get information on the file I/O buffer. */

if (mmioGetInfo(hmmio, &mmioinfo, 0)) {

    Error("Failed to get I/O buffer info");

    mmioClose(hmmio, 0);

    return FALSE;

}

/*

 * Read the entire file by directly reading the file I/O buffer.

 * When the end of the I/O buffer is reached, advance the buffer.

 */

for (dwCount = dwDataSize, hptr = lpData; dwCount > 0; dwCount--) {

    /* Check to see if the I/O buffer must be advanced. */

    if (mmioinfo.pchNext == mmioinfo.pchEndRead) {

        if(mmioAdvance(hmmio, &mmioinfo, MMIO_READ)) {

            Error("Failed to advance buffer.");

            mmioClose(hmmio, 0);

            return FALSE;

        }

    }

    /* Get a character from the buffer. */

    *hptr++ = *mmioinfo.pchNext++;

}

/* End direct buffer access and close the file. */

mmioSetInfo(hmmio, &mmioinfo, 0);

mmioClose(hmmio, 0);


Ending Direct Access of a File I/O Buffer

When you finish accessing a file I/O buffer, pass the MMIOINFO structure filled by the mmioGetInfo function to the mmioSetInfo function to stop direct-buffer access. If you wrote to the buffer, set the MMIO_DIRTY flag in the dwFlags member of the MMIOINFO structure before calling mmioSetInfo. Otherwise, the buffer will not be flushed to disk.


Performing File Input/Output on Memory Files

The multimedia file I/O services let you to treat a block of memory as a file. This can be useful if you already have a file image in memory. Memory files let you reduce the number of special-case conditions in your code because, for I/O purposes, you can treat file memory images as if they were disk-based files. You can also use memory files with the Clipboard.


Opening Memory Files

Like I/O buffers, memory files can use memory allocated by the application or by the file I/O manager. In addition, memory files can be either expandable or non-expandable. When the file I/O manager reaches the end of an expandable memory file, it expands the memory file by a predefined increment.

To open a memory file, use mmioOpen with the szFileName parameter set to NULL and the MMIO_READWRITE flag set in the dwOpenFlags parameter. Set the lpmmioinfo parameter to point to an MMIOINFO structure as follows:

•	Set the pIOProc member to NULL.

•	Set the fccIOProc member to FOURCC_MEM.

•	Set the pchBuffer member to point to the memory block. To request that the file I/O manager allocate the memory block, set pchBuffer to NULL.

•	Set the cchBuffer member to the initial size of the memory block.

•	Set the adwInfo[0] member to the minimum expansion size of the memory block. For a non-expandable memory file, set adwInfo[0] to NULL.

•	Set all other members to zero.


Allocating Memory for Memory Files

There are no restrictions on allocating memory for use as a non-expandable memory file. You can use static memory or stack memory, or you can use locally allocated or globally allocated memory. For expandable memory files, you must use memory allocated using the GlobalAlloc function and locked using the GlobalLock function.


Using Custom Input/Output Procedures

Multimedia file I/O services use I/O procedures to handle the physical input and output associated with reading and writing to different types of storage systems, such as file-archival systems and database-storage systems. There are predefined I/O procedures for standard Microsoft® Windows® files and for memory files. In the future, there will be a predefined I/O procedure for accessing elements of compound files. Compound files consist of a number of individual files, called file elements, bound together in one physical file.

You can supply a custom I/O procedure for accessing a unique storage system such as a database or file archive. This I/O procedure is private to your application.

The multimedia file I/O services provide the following functions to support custom I/O procedures:

Function	Description
mmioInstallIOProc	Installs, removes, or locates an I/O procedure.
mmioSendMessage	Sends a custom message to the I/O procedure associated with a file.
•	Opening a file using a custom I/O procedure

•	Writing an I/O procedure

•	Installing an I/O procedure


Opening a File Using a Custom I/O Procedure

Before learning about how to write an I/O procedure, it's helpful to understand how to use one. To open a file using a custom I/O procedure, use the mmioOpen function as you would to open any other file. Use a plus sign (+) in the filename to separate the name of the physical file from the name of the element of the file you want to open. For example, the following statement opens a file element named "element" from a file named FILENAME.ARC:

mmioOpen("filename.arc+element", NULL, MMIO_READ);

When the file I/O manager encounters a plus sign in a filename, it looks at the preceding filename extension to determine which I/O procedure to associate with the file. In the previous example, the file I/O manager will attempt to use the I/O procedure associated with the .ARC filename extension. If no I/O procedure is installed, the mmioOpen function returns an error.


Writing an I/O Procedure

An I/O procedure is a message-processing function supplied by an application. An I/O procedure function has the following syntax:

LRESULT IOProc(lpmmioinfo, wMsg, lParam1, lParam2)

The lpmmioinfo parameter specifies a pointer to an MMIOINFO structure associated with the file being accessed.

The wMsg parameter is of type UINT and specifies the message being sent by the file I/O manager to the I/O procedure.

The lParam1 parameter is of type LPARAM and specifies 32 bits of message-specific information.

The lParam2 parameter is of type LPARAM and specifies 32 bits of message-specific information.

The return value is message-specific. If the I/O procedure does not recognize a message, it should return zero.


I/O Procedure Messages

I/O procedures must respond to the MMIOM_CLOSE, MMIOM_OPEN, MMIOM_READ, MMIOM_WRITE, MMIOM_SEEK, and MMIOM_WRITEFLUSH messages. Each of these messages has two parameters.

You can also create custom messages and send them to your I/O procedure using the mmioSendMessage function. If you define your own messages, be sure they are defined at or above the MMIOM_USER message. For example, the following example defines a message named MMIOM_MYMESSAGE:

#define   MMIOM_MYMESSAGE         MMIOM_USER + 0


Using the MMIOINFO Structure

In addition to processing messages, an I/O procedure must maintain the lDiskOffset member in the MMIOINFO structure referenced by the lpmmioinfo parameter. The lDiskOffset member must always contain the file offset to the location that the next MMIOM_READ or MMIOM_WRITE message will access. The offset is specified in bytes and is relative to the beginning of the file. The I/O procedure can use the adwInfo[] member to maintain any required state information. The I/O procedure should not modify any other members in the MMIOINFO structure.


Installing an I/O Procedure

Use mmioInstallIOProc to install, remove, or locate an I/O procedure.

For example, to install an I/O procedure associated with the filename extension ARC, use the following statement:

mmioInstallIOProc (mmioFOURCC('A', 'R', 'C', ' '),

                   (LPMMIOPROC)lpmmioproc, MMIO_INSTALLPROC);

Note  Be sure to remove any I/O procedures you've installed before closing your application.


Installing an I/O Procedure Using MmioOpen

When you install an I/O procedure by using the mmioInstallIOProc function, the procedure remains installed until you remove it. The I/O procedure will be used for any file you open if the file has the appropriate filename extension. You can also temporarily install an I/O procedure by using the mmioOpen function. In this case, the I/O procedure is only used with a file opened by mmioOpen and is removed when the file is closed by using the mmioClose function.

To specify an I/O procedure when you open a file using mmioOpen, use the lpmmioinfo parameter to reference an MMIOINFO structure as follows:

•	Set the fccIOProc member to NULL.

•	Set the pIOProc member to the procedure-instance address of the I/O procedure.

•	Set all other members to zero (unless you are opening a memory file, or directly reading or writing to the file I/O buffer).


File Input/Output Functions

Following are the functions used with file input/output.

mmioAdvance
mmioAscend
mmioClose
mmioCreateChunk
mmioDescend
mmioFlush
mmioFOURCC
mmioGetInfo
mmioInstallIOProc
mmioOpen
MMIOProc
mmioRead
mmioRename
mmioSeek
mmioSendMessage
mmioSetBuffer
mmioSetInfo
mmioStringToFOURCC
mmioWrite
mmsystemGetVersion


Introduction to Multimedia Services

Microsoft® Windows® provides developers with high-level and low-level services for developing multimedia applications that use the extended capabilities of a multimedia personal computer.


About Windows Multimedia Services

Windows provides the following multimedia services:

•	A Media Control Interface (MCI) for controlling media devices.

•	Extensible string-based and message-based interfaces for communicating with MCI device drivers.

•	MCI device drivers for playing and recording waveform audio, playing Musical Instrument Digital Interface (MIDI) files, and playing compact disc audio from a CD-ROM drive.

•	Low-level application programming interface (API) support for multimedia-related services.

•	Low-level support for playing and recording audio with waveform and MIDI audio devices.

•	Low-level support for precision timer services.

•	Multimedia file input and output (I/O) services that provide buffered and unbuffered file I/O and support for standard Resource Interchange File Format (RIFF) files. The services are extensible by means of custom I/O procedures.

•	A MIDI Mapper supporting standard MIDI patch services. This allows MIDI files to be authored independently of users' MIDI synthesizer setups.

•	Control Panel options that let users change display drivers, set up a screen saver, install multimedia device drivers, assign waveform sounds to system alerts, and configure the MIDI Mapper.

This overview covers the following topics:

•	The software architecture of the multimedia services

•	The design philosophy and implementation of the multimedia services

•	Basic information about developing applications that use the multimedia services


Architecture of Windows Multimedia Services

Although the multimedia services are provided by a number of files, the overall architecture can be viewed as consisting of just three software modules:

•	The WINMM library, which provides the MCI services and low-level multimedia support functions

•	Multimedia device drivers, which provide communication between the low-level WINMM functions and multimedia devices, such as waveform, MIDI, and timer hardware

•	Drivers for MCI, which provide high-level control of media devices


Windows Multimedia Design Philosophy

The architecture of the multimedia services is designed around the concepts of extensibility and device independence. Extensibility allows the software architecture to accommodate advances in technology easily, without changes to the architecture itself. Device independence makes it easy to develop multimedia applications that will run on a wide range of hardware providing different levels of multimedia support. Three design elements of the system software provide extensibility and device independence:

•	A translation layer (WINMM) that isolates applications from device drivers and centralizes device-independent code

•	Run-time linking that allows the translation layer to link to the drivers it needs

•	A well-defined and consistent driver interface that minimizes special-case code and makes the installation and upgrade process easier


Building a Multimedia Application

Before writing a multimedia application, you should be familiar with programming in the Windows environment.

When using the multimedia services, you must include the MMSYSTEM.H header file in all source-code files that call multimedia functions. This header file depends on declarations made in the WINDOWS.H header file, so you must first include WINDOWS.H. The MMSYSTEM.H header file provides function prototypes as well as definitions of multimedia data types and constants.

In addition to linking the normal Windows libraries, you must also link to the WINMM.LIB import library when linking an application that uses multimedia functions.


Multimedia Timer and Joystick Services

This overview shows you how to add joystick input capabilities to your application and how to control event timing.


About Multimedia Timers

The joystick services can receive control signals from up to two joysticks. Timer services provide improved timer resolution and accuracy. Intel®-based systems have an accuracy of up to 16 milliseconds and MIPS®-based systems have an accuracy of up to 10 milliseconds.

The functions and data structures associated with the joystick and timer-interrupt services are defined in MMSYSTEM.H and WINMM.LIB.


Timer Services

The multimedia timer services provided with the Microsoft® Win32® application programming interface (API) let applications schedule timed periodic or one-time asynchronous events. Unlike the timer services that post WM_TIMER messages to a message queue, the multimedia timer services call a callback function.


Timer Data Types

The MMSYSTEM.H header file defines data types and function prototypes for timer functions. You must include this header file in any source-code module that uses timer services. MMSYSTEM.H defines the following new data types.

Type	Description
MMTIME	A structure for representing time in one of several formats.
TIMECAPS	A structure for querying timer capabilities.


Using Timer Services

Timer services let an application request and receive timer messages at application-specified intervals. Real-time multimedia applications can use the following functions to control the pace of data and synchronized presentations.

Function	Description
timeBeginPeriod	Establishes the minimum timer resolution an application will use.
timeEndPeriod	Clears a minimum timer resolution previously set using timeBeginPeriod.
timeGetDevCaps	Returns information about the capabilities of the timer services.
timeGetTime	Returns the system time in milliseconds.
timeGetSystemTime	Fills an MMTIME structure with the system time in milliseconds.
timeSetEvent	Creates a timer event that executes a specific action at a specific time or at periodic intervals.
timeKillEvent	Cancels a timer event previously created using timeSetEvent.


Getting the System Time

An application can get the current system time using the timeGetTime or timeGetSystemTime function. The system time is the count of milliseconds since the Microsoft® Windows® operating system was started. The timeGetTime function returns the system time, and the timeGetSystemTime function fills an MMTIME structure with the system time.


Determining Maximum and Minimum Event Periods

You can use the timeGetDevCaps function to determine the minimum and maximum timer-event periods provided by the timer services. These values vary across computers and can vary depending on the mode in which Windows is running.


Establishing Minimum Timer Resolution

Before starting timer events, your application must establish the minimum timer resolution that it intends to use. It must clear this value after finishing with the timer-event services.

Use the timeBeginPeriod and timeEndPeriod functions to set and clear the minimum timer-event resolution for your application. You must match a call to timeBeginPeriod with a corresponding call to timeEndPeriod, specifying the same minimum resolution in both calls. An application can make multiple timeBeginPeriod calls, as long as each call is matched with a call to timeEndPeriod.


Starting Timer Events

To initialize and start timer events, use the timeSetEvent function. This function returns a timer identifier that can be used to stop or identify timer events.

The timeSetEvent function returns a timer identifier if successful or NULL if unsuccessful. Interrupt timers are a scarce resource, and periodic timers with resolution less than 100 milliseconds consume a significant portion of CPU time. For periodic timers, you must pair calls to timeSetEvent with calls to timeKillEvent. For more information, see Canceling a Timer Event.

The lpFunction parameter contains the address of the function to be called when the timer event takes place.

Since the callback function is accessed at interrupt time, it must adhere to strict programming guidelines. Timer-callback functions follow the same programming guidelines as callback functions for the low-level audio services. For information about writing low-level audio callback functions, see Low-Level Audio. For more information about timer callback functions, see TimeProc.


Canceling a Multimedia Timer Event

You can cancel an active timer event at any time. Be sure to cancel any outstanding timers before freeing the module containing the callback function. To cancel a timer event, use the timeKillEvent function.


Using Timer Callbacks

This topic describes how an application can use the timer services. First, the application calls the timeGetDevCaps function to determine the minimum and maximum resolution supported by the timer services. Before setting up any timer events, the application uses the timeBeginPeriod function to establish the minimum timer resolution it will use, as shown in the following example:

#define TARGET_RESOLUTION 1  /* Try for 1-millisecond accuracy. */

TIMECAPS tc;

UINT     wTimerRes;

if(timeGetDevCaps(&tc, sizeof(TIMECAPS)) != TIMERR_NOERROR) {

    /* Error; application can't continue. */

}

wTimerRes = min(max(tc.wPeriodMin, TARGET_RESOLUTION),

    tc.wPeriodMax);

timeBeginPeriod(wTimerRes);

To start the timer event, the application specifies the amount of time before the callback occurs, the required resolution, the address of the callback function, and user data to supply with the callback. The application can use a function like the following to start a one-time timer event.

UINT SetTimerCallback(NPSEQ npSeq,           /* Sequencer data */

                      UINT msInterval)       /* Event interval */

{

    npSeq->wTimerID = timeSetEvent(

         msInterval,           /* Delay                        */

         wTimerRes,            /* Resolution (global variable) */

         (LPTIMECALLBACK) OneShotTimer, /* Callback function   */

         (DWORD) npSeq,               /* User data             */

         TIME_ONESHOT);               /* Event type (one-time) */

    if (npSeq->wTimerID != 0)

        return TIMERR_NOCANDO;

    else

        return TIMERR_NOERROR;

}

The following callback function is used for the one-shot timer.

void PASCAL OneShotTimer(UINT wTimerID, UINT msg,

    DWORD dwUser, DWORD dw1, DWORD dw2)

{

    NPSEQ npSeq;            /* Pointer to sequencer data   */

    npSeq = (NPSEQ) dwUser;

    npSeq->wTimerID = 0;    /* Invalidate unused timer id  */

    TimerIntRoutine(npSeq); /* Handle interrupt-time tasks */

    UNREFERENCED_PARAMETER(dw1);

    UNREFERENCED_PARAMETER(dw2);

    UNREFERENCED_PARAMETER(msg);

    UNREFERENCED_PARAMETER(wTimerID);

}

Before freeing the dynamic-link library (DLL) that contains the callback function, the application cancels any outstanding timers. To cancel one timer event, it can call the following function.

void DestroyTimer(NPSEQ npSeq)

{

    if (npSeq->wTimerID) {      /* If timer event is pending */

        timeKillEvent(npSeq->wTimerID);  /* Cancel the event */

        npSeq->wTimerID = 0;

    }

}

Finally, to cancel the minimum timer resolution it established, the application calls timeEndPeriod as follows.

timeEndPeriod(wTimerRes);


Joystick Services

The joystick is an input device that provides position information. It is an additional supported input device, not a replacement for the mouse. All absolute-position devices, including touch screens, digitizing tablets, and light pens, can use the joystick services to provide position and button information to applications.

The joystick services are loaded when Windows is started. The joystick services can monitor two joysticks, each with two- or three-axis movement, and up to four buttons. Applications access the joystick services through the set of functions described in this section.

Note  The driver for the IBM® Game Adapter supports two 2-axis joysticks or one 3-axis joystick.


Joystick Data Types

The MMSYSTEM.H header file defines new data types and function prototypes for joystick functions. MMSYSTEM.H defines the following new data types.

Type	Description
JOYCAPS	A structure that contains joystick capability information.
JOYINFO	A structure that contains joystick position and button information.


Using Joystick Services

Joystick services include functions to query each joystick for its capabilities, to poll each joystick for position and button information, and to receive messages in response to joystick events. Your application can use the following joystick functions to accept input from one or two joysticks.

Function	Description
joyGetNumDevs	Returns the number of joysticks supported by the joystick services.
joyGetDevCaps	Returns joystick capabilities.
joyGetPos	Returns joystick position and button information.
joySetCapture	Causes joystick input to be sent to a specified window at regular intervals or when the joystick state changes.
joyReleaseCapture	Releases the joystick captured using joySetCapture.
joyGetThreshold	Returns the movement threshold of a joystick.
joySetThreshold	Sets the movement threshold of a joystick.


Determining Joystick Capabilities

The various joysticks in use today can support two or three axes and a variety of button configurations. Also, joysticks support different ranges of motion and polling frequencies. Joystick drivers can support either one or two joysticks. Two functions allow you to determine the capabilities of the joystick services and joystick devices installed on a system.


Getting the Joystick Driver Capabilities

You can use the joyGetNumDevs function to determine the number of joystick devices supported by the joystick services. This function returns the number of joysticks, or zero if there is no joystick support. The value returned is not necessarily the number of joysticks attached to the system. To determine whether a joysticf supportek is attached, call the joyGetPos function for the device. The function returns JOYERR_UNPLUGGED if the specified device is disconnected.

The following example determines whether the joystick services are available and then determines if a joystick is attached to one of the ports:

JOYINFO joyinfo;

UINT wNumDevs, wDeviceID;

BOOL bDev1Attached, bDev2Attached;

    if((wNumDevs = joyGetNumDevs()) == 0)

        return ERR_NODRIVER;

    bDev1Attached =

            joyGetPos(JOYSTICKID1,&joyinfo) != JOYERR_UNPLUGGED;

    bDev2Attached =

            wNumDevs == 2 &&

            joyGetPos(JOYSTICKID2,&joyinfo) != JOYERR_UNPLUGGED;

    /* Decide which joystick to use */

    if(bDev1Attached || bDev2Attached)

        wDeviceID = bDev1Attached ? JOYSTICKID1 : JOYSTICKID2;

    else

        return ERR_NODEVICE;


Getting the Joystick Capabilities

You can use the joyGetDevCaps function to obtain the specific capabilities of each joystick attached to a given system. This function fills a JOYCAPS structure with the range of each axis on the joystick, the number of buttons, and the maximum and minimum polling frequency.


Methods for Checking Joystick Status

An application can receive information from the joystick in one of two ways:

•	By processing joystick messages from a captured joystick

•	By polling the joystick directly

The message-processing method can be simpler to use; your application is sent messages that indicate the position of the stick and the state of the buttons (pressed or released).


Capturing Joystick Messages to a Window Function

You can capture joystick input to a window function; your application then receives joystick messages at specified intervals or when the user manipulates the joystick. The messages are described in the following topic.

Only one application can capture joystick messages from a given joystick. Capturing joystick messages does not, however, prevent your application (or other applications) from polling the joystick using joyGetPos. If joyGetPos is called while joystick input is captured, joystick events occurring close to the time of the joyGetPos call may not be accurately reported to the capture window.

The joySetCapture function captures joystick input to a window function you specify. To release the joystick, call the joyReleaseCapture function.

To capture messages from two joysticks attached to the system, you must call joySetCapture twice, once for each joystick. Your window then receives separate messages for each device.

You cannot capture an unplugged joystick. The joySetCapture function returns zero if successful; it returns JOYERR_UNPLUGGED if the specified device is unplugged.

Note  The joystick services set up a Windows timer event with each call to joySetCapture.

Set the period parameter for joySetCapture to a value that falls within the minimum and maximum resolution range for the joystick. To determine the minimum and maximum resolution of the joystick, call the joyGetDevCaps function, which fills the wPeriodMin and wPeriodMax members in the JOYCAPS structure.

If the specified period value is outside the range of valid resolution values for the joystick, the joystick services use the minimum or maximum resolution value, whichever is closer to the specified period.


Processing Multimedia Timer Joystick Messages

The following joystick messages can be sent to a window function. Numerals 1 and 2 in these messages correspond to the joystick initiating the message. MM_JOY1 messages are sent to the window function if your application requests input from the first joystick, and MM_JOY2 messages are sent if your application requests input from the second joystick. All messages report nonexistent buttons as released.

Messages	Description
MM_JOY1MOVE, MM_JOY2MOVE	Report a change in the x-axis and/or y-axis position of the joystick. The wParam parameter contains a combination of JOY_BUTTON bit flags specifying which buttons were pressed. The low-order word of lParam contains the x-position of the joystick, and the high-order word contains the y-position.
MM_JOY1ZMOVE, MM_JOY2ZMOVE	Report a change in the z-axis position of a 3-axis joystick. The wParam parameter contains a combination of JOY_BUTTON bit flags specifying which buttons were pressed. The low-order word of lParam contains the x-position of the joystick, and the high-order word contains the y-position.
MM_JOY1BUTTONUP, MM_JOY2BUTTONUP, MM_JOY1BUTTONDOWN, MM_JOY2BUTTONDOWN	Report that a joystick button has been pressed or released. The wParam parameter contains one JOY_BUTTONCHG bit flag specifying which button changed state and a combination of JOY_BUTTON bit flags specifying the current button states. The low-order word of lParam contains the x-position of the joystick, and the high-order word contains the y-position.
The joystick services use the following bit flags, passed in the wParam parameter of the window function, to report the state of the joystick buttons.

Flag	Description
JOY_BUTTON1	Set when button 1 is pressed.
JOY_BUTTON1CHG	Set when button 1 has changed state.
JOY_BUTTON2	Set when button 2 is pressed.
JOY_BUTTON2CHG	Set when button 2 has changed state.
JOY_BUTTON3	Set when button 3 is pressed.
JOY_BUTTON3CHG	Set when button 3 has changed state.
JOY_BUTTON4	Set when button 4 is pressed.
JOY_BUTTON4CHG	Set when button 4 has changed state.
The MM_JOY*MOVE messages use the JOY_BUTTON flags to report the state (pressed or released) of all buttons on the specified joystick.

The MM_JOY*BUTTONUP and MM_JOY*BUTTONDOWN messages use the JOY_BUTTON flags to report the state (pressed or released) of all buttons on the specified joystick. Also, they use JOY_BUTTONCHG flags to indicate which button changed state, thereby generating the message.

For example, if the user presses and holds buttons 1 and 2 and then moves the stick, a window function may receive the following messages.

Message	wParam Flags
MM_JOY1BUTTONDOWN	JOY_BUTTON1 | JOY_BUTTON1CHG
MM_JOY1BUTTONDOWN	JOY_BUTTON1 | JOY_BUTTON2 | JOY_BUTTON2CHG
MM_JOY1MOVE	JOY_BUTTON1 | JOY_BUTTON2
A window function may receive the following messages when the user presses and releases button 3 without moving the stick.

Message	wParam Flags
MM_JOY1BUTTONDOWN	JOY_BUTTON3 | JOY_BUTTON3CHG
MM_JOY1BUTTONUP	JOY_BUTTON3CHG


Releasing the Joystick

When your application no longer needs to receive periodic joystick messages, it should release the joystick by using the joyReleaseCapture function. If your application does not release the joystick before ending, the joystick is released shortly after the capture window is destroyed.


Setting the Movement Threshold

You can change the movement threshold of the joystick by calling the joySetThreshold function. The movement threshold is the number of device units that the stick must be moved before an MM_JOY*MOVE message is sent to the window that has captured the device.


Polling the Joystick

You can poll the joystick for position and button information. For example, an application may poll the joystick to get baseline position values; the Joystick Control Panel application uses this technique when calibrating the joystick. The joyGetPos function allows you to poll the joystick for position and button information.

Note  Calling joyGetPos while joystick input is captured can prevent the joystick services from accurately reporting joystick events to the capture window.


Using Joystick Messages

The remainder of this topic presents examples from a simple joystick game that performs the useful function of shooting holes in the desktop: it gets position and button-state information from the joystick services and, when a user presses the joystick buttons, plays waveform resources and paints bullet holes on the screen.

Most of the joystick-control code is in the main window function. In the following WM_CREATE case of the message handler, the application captures input from joystick 1.

case WM_CREATE:

    if(joySetCapture(hWnd, JOYSTICKID1,  NULL, FALSE)) {

        MessageBeep(MB_ICONEXCLAMATION);

        MessageBox(hWnd, "Couldn't capture the joystick.", NULL,

                        MB_OK | MB_ICONEXCLAMATION);

        PostMessage(hWnd,WM_CLOSE,0,0L);

    }

    break;

In response to the MM_JOY1MOVE messages, the application changes the position of the cursor and, if either button is pressed, draws a hole in the desktop.

case MM_JOY1MOVE :

    if((UINT) wParam & (JOY_BUTTON1 | JOY_BUTTON2))

        DrawFire(hWnd);

    DrawSight(lParam);  /* Calculate new cursor position */

    break;

In response to the MM_JOY1BUTTONDOWN messages, the application uses sndPlaySound to play a waveform audio file.

case MM_JOY1BUTTONDOWN :

    if((UINT) wParam & JOY_BUTTON1) {

        sndPlaySound(lpButton1,

                     SND_LOOP | SND_ASYNC | SND_MEMORY);

        DrawFire(hWnd);

    }

    else if(wParam & JOY_BUTTON2) {

        sndPlaySound(lpButton2,

                     SND_ASYNC | SND_MEMORY |  SND_LOOP);

        DrawFire(hWnd);

    }

    break;

By specifying the SND_LOOP and SND_ASYNC flags with sndPlaySound, the JOYTOY application repeats the waveform playback until the button is released.

When a button is released, the window function receives a MM_JOY1BUTTONUP message, and handles it with the following statement.

case MM_JOY1BUTTONUP:

    sndPlaySound(NULL, 0);

    break;

This sequence stops the waveform-audio playback.


Multimedia Timer and Joystick Functions

Following are the functions used with joystick services.

joyGetDevCaps
joyGetNumDevs
joyGetPos
joyGetThreshold
joyReleaseCapture
joySetCapture
joySetThreshold

Following are the functions used with timer services.

timeBeginPeriod
timeEndPeriod
timeGetDevCaps
timeGetSystemTime
timeGetTime
timeKillEvent
TimeProc
timeSetEvent


_hread
_hread  QuickInfo  Overview  Group

The _hread function reads data from the specified file. This function is provided for compatibility with 16-bit versions of Windows. Win32-based applications should use the ReadFile function.

long _hread(

HFILE  hFile,	// handle of file
LPVOID  lpBuffer,	// address of buffer for read data
long  lBytes	// length, in bytes, of data buffer
);
Parameters

hFile

Identifies the specified file.

lpBuffer

Points to a buffer that contains the data read from the file.

lBytes

Specifies the number of bytes to be read from the file.

Return Value

The return value indicates the number of bytes actually read from the file. If the number of bytes read is less than lBytes, the function has reached the end of file (EOF) before reading the specified number of bytes.

If the function fails, the return value is HFILE_ERROR. To get extended error information, call GetLastError.

See Also

_hwrite, ReadFile


_hwrite
_hwrite  QuickInfo  Overview  Group

The _hwrite function writes data to the specified file. This function is provided for compatibility with 16-bit versions of Windows. Win32-based applications should use the WriteFile function.

long _hwrite(

HFILE  hFile,	// handle of file
LPCSTR  lpBuffer,	// address of buffer for data to be written
long  lBytes	// number of bytes to write
);
Parameters

hFile

Identifies the specified file.

lpBuffer

Points to a buffer that contains the data to be written to the file.

lBytes

Specifies the number of bytes to be written to the file.

Return Value

If the function succeeds, the return value indicates the number of bytes actually written to the file.

If the function fails, the return value is HFILE_ERROR. To get extended error information, call GetLastError.

See Also

_hread, WriteFile


_lclose
_lclose  QuickInfo  Overview  Group

The _lclose function closes the specified file so that it is no longer available for reading or writing. This function is provided for compatibility with 16-bit versions of Windows. Win32-based applications should use the CloseHandle function.

HFILE _lclose(

HFILE  hFile	// handle of file to close
);
Parameters

hFile

Identifies the file to be closed. This handle is returned by the function that created or last opened the file.

Return Value

If the function succeeds, the return value is zero.

If the function fails, the return value is HFILE_ERROR. To get extended error information, call GetLastError.

See Also

CloseHandle, CreateFile, _lopen


_lcreat
_lcreat  QuickInfo  Overview  Group

The _lcreat function creates or opens a specified file. This function is provided for compatibility with 16-bit versions of Windows. Win32-based applications should use the CreateFile function.

HFILE _lcreat(

LPCSTR  lpPathName,	// address of name of file to open
int  iAttribute	// file attribute
);
Parameters

lpPathName

Points to a null-terminated string that names the file to be opened. The string must consist of characters from the Windows ANSI character set.

iAttribute

Specifies the file attributes. This parameter must be one of the following values:

Value	Meaning
0	Normal (can be read from or written to without restriction).
1	Read only (cannot be opened for write)
2	Hidden (not found by directory search)
4	System (not found by directory search)
Return Value

If the function succeeds, the return value is a file handle.

If the function fails, the return value is HFILE_ERROR. To get extended error information, call GetLastError.

Remarks

If the file does not exist, _lcreat creates a new file and opens it for writing. If the file exists, _lcreat truncates the file size to zero and opens it for reading and writing. When the function opens the file, the pointer is set to the beginning of the file.

The _lcreat function should be used carefully. It can open any file, even one already opened by another function.

See Also

CreateFile, _lopen


_llseek
_llseek  QuickInfo  Overview  Group

The _llseek function repositions the file pointer in a previously opened file. This function is provided for compatibility with 16-bit versions of Windows. Win32-based applications should use the SetFilePointer function.

LONG _llseek(

HFILE  hFile,	// handle of file
LONG  lOffset,	// number of bytes to move
int  iOrigin	// position to move from
);
Parameters

hFile

Identifies the file.

lOffset

Specifies the number of bytes the file pointer is to be moved.

iOrigin

Specifies the starting position and direction of the file pointer. This parameter must be one of the following values:

Value	Meaning
FILE_BEGIN	Moves the file pointer lOffset bytes from the beginning of the file.
FILE_CURRENT	Moves the file pointer lOffset bytes from its current position.
FILE_END	Moves the file pointer lOffset bytes from the end of the file.
Return Value

If the function succeeds, the return value specifies the new offset of the pointer, in bytes, from the beginning of the file.

If the function fails, the return value is HFILE_ERROR. To get extended error information, call GetLastError.

Remarks

When a file is initially opened, the file pointer is set to the beginning of the file. The _llseek function moves the pointer an arbitrary amount without reading data, which facilitates random access to the file's contents.

See Also

_lopen, SetFilePointer


_lopen
_lopen  QuickInfo  Overview  Group

The _lopen function opens an existing file and sets the file pointer to the beginning of the file. This function is provided for compatibility with 16-bit versions of Windows. Win32-based applications should use the CreateFile function.

HFILE _lopen(

LPCSTR  lpPathName,	// address of name of file to open
int  iReadWrite	// file access mode
);
Parameters

lpPathName

Points to a null-terminated string that names the file to open. The string must consist of characters from the Windows ANSI character set.

iReadWrite

Specifies the modes in which to open the file. This parameter consists of one access mode and an optional share mode. The access mode must be one of the following values:

Value	Meaning
OF_READ	Opens the file for reading only.
OF_READWRITE	Opens the file for reading and writing.
OF_WRITE	Opens the file for writing only.
The share mode can be one of the following values:

Value	Meaning
OF_SHARE_COMPAT	Opens the file in compatibility mode, enabling any process on a given computer to open the file any number of times. If the file has been opened by using any of the other share modes, _lopen fails.
OF_SHARE_DENY_NONE	Opens the file without denying other processes read or write access to the file. If the file has been opened in compatibility mode by any other process, _lopen fails.
OF_SHARE_DENY_READ	Opens the file and denies other processes read access to the file. If the file has been opened in compatibility mode or for read access by any other process, _lopen fails.
OF_SHARE_DENY_WRITE	Opens the file and denies other processes write access to the file. If the file has been opened in compatibility mode or for write access by any other process, _lopen fails.
OF_SHARE_EXCLUSIVE	Opens the file in exclusive mode, denying other processes both read and write access to the file. If the file has been opened in any other mode for read or write access, even by the current process, _lopen fails.
Return Value

If the function succeeds, the return value is a file handle.

If the function fails, the return value is HFILE_ERROR. To get extended error information, call GetLastError.

See Also

CreateFile


_lread
_lread  QuickInfo  Overview  Group

The _lread function reads data from the specified file. This function is provided for compatibility with 16-bit versions of Windows. Win32-based applications should use the ReadFile function.

UINT _lread(

HFILE  hFile,	// handle of file
LPVOID  lpBuffer,	// address of buffer for read data
UINT  uBytes	// length, in bytes, of data buffer
);
Parameters

hFile

Identifies the specified file.

lpBuffer

Points to a buffer that contains the data read from the file.

uBytes

Specifies the number of bytes to be read from the file.

Return Value

The return value indicates the number of bytes actually read from the file. If the number of bytes read is less than uBytes, the function has reached the end of file (EOF) before reading the specified number of bytes.

If the function fails, the return value is HFILE_ERROR. To get extended error information, call GetLastError.

See Also

_lwrite, ReadFile


_lwrite
_lwrite  QuickInfo  Overview  Group

The _lwrite function writes data to the specified file. This function is provided for compatibility with 16-bit versions of Windows. Win32-based applications should use the WriteFile function.

UINT _lwrite(

HFILE  hFile,	// handle of file
LPCSTR  lpBuffer,	// address of buffer for data to be written
UINT  uBytes	// number of bytes to write
);
Parameters

hFile

Identifies the specified file.

lpBuffer

Points to a buffer that contains the data to write to the file.

uBytes

Specifies the number of bytes to be written to the file.

Return Value

If the function succeeds, the return value indicates the number of bytes actually written to the file.

If the function fails, the return value is HFILE_ERROR. To get extended error information, call GetLastError.

See Also

_lread, WriteFile


AbnormalTermination
AbnormalTermination  QuickInfo  Overview  Group

The AbnormalTermination function indicates whether the try block of a try-finally statement terminated normally. The function can be called only from within the finally block of a try-finally statement.

BOOL AbnormalTermination(VOID)

Parameters

This function has no parameters.

Return Value

If the try block of the try-finally statement terminated abnormally, the return value is TRUE; otherwise, it is FALSE.

Remarks

The try block terminates normally only if execution leaves the block sequentially after executing the last statement in the block. Statements (such as return, goto, continue, or break) that cause execution to leave the try block result in abnormal termination of the block. This is the case even if such a statement is the last statement in the try block.

Abnormal termination of a try block causes the system to search backward through all stack frames to determine whether any termination handlers must be called. This can result in the execution of hundreds of instructions, so it is important to avoid abnormal termination of a try block due to a return, goto, continue, or break statement. Note that these statements do not generate an exception, even though the termination is abnormal.


AbortDoc
AbortDoc  QuickInfo  Overview  Group

The AbortDoc function stops the current print job and erases everything drawn since the last call to the StartDoc function. This function replaces the ABORTDOC printer escape.

int AbortDoc(

HDC  hdc	// handle of device context
);
Parameters

hdc

Identifies the device context for the print job.

Return Value

If the function succeeds, the return value is greater than zero.

If the function fails, the return value is SP_ERROR. To get extended error information, call GetLastError.

Remarks

Applications should call the AbortDoc function to stop a print job if an error occurs, or to stop a print job after the user cancels that job. To end a successful print job, an application should call the EndDoc function.

If Windows Print Manager was used to start the print job, calling the AbortDoc function erases the entire spool job, so that the printer receives nothing. If Print Manager was not used to start the print job, the data may already have been sent to the printer. In this case, the printer driver resets the printer (when possible) and ends the print job.

See Also

EndDoc, SetAbortProc, StartDoc


AbortPath
AbortPath  QuickInfo  Overview  Group

The AbortPath function closes and discards any paths in the specified device context.

BOOL AbortPath(

HDC  hdc	// handle of device context
);
Parameters

hdc

Identifies the device context from which a path will be discarded.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

If there is an open path bracket in the given device context, the path bracket is closed and the path is discarded. If there is a closed path in the device context, the path is discarded.

See Also

BeginPath, EndPath


AbortPrinter
AbortPrinter  QuickInfo  Overview  Group

The AbortPrinter function deletes a printer's spool file if the printer is configured for spooling.

BOOL AbortPrinter(

HANDLE  hPrinter	// handle of printer object
);
Parameters

hPrinter

Identifies the printer from which the spool file is deleted.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

If the printer is not configured for spooling, AbortPrinter has no effect.

The printer handle identified by the hPrinter parameter is returned by the OpenPrinter function.

See Also

OpenPrinter


AbortProc
AbortProc  QuickInfo  Overview  Group

The AbortProc function is an application-defined callback function that is called when a print job is to be canceled during spooling.

BOOL CALLBACK AbortProc(

HDC  hdc,	// handle of device context
int  iError	// error value
);
Parameters

hdc

Identifies the device context for the print job.

iError

Specifies whether an error has occurred. This parameter is zero if no error has occurred; it is SP_OUTOFDISK if Windows Print Manager is currently out of disk space and more disk space will become available if the application waits.

Return Value

The callback function should return TRUE to continue the print job or FALSE to cancel the print job.

Remarks

An application installs this callback function by calling the SetAbortProc function. AbortProc is a placeholder for the application-defined function name.

If the iError parameter is SP_OUTOFDISK, the application need not cancel the print job. If it does not cancel the job, it must yield to Print Manager by calling the PeekMessage or GetMessage function.

See Also

GetMessage, PeekMessage, SetAbortProc


AbortSystemShutdown
AbortSystemShutdown  QuickInfo  Overview  Group

The AbortSystemShutdown function stops a system shutdown started by using the InitiateSystemShutdown function.

BOOL AbortSystemShutdown(

LPTSTR  lpMachineName	// address of name of computer to stop shutting down
);
Parameters

lpMachineName

Points to the null-terminated string that specifies the network name of the computer where the shutdown is to be stopped. If lpMachineName is NULL or points to an empty string, the function stops the shutdown on the local computer.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The InitiateSystemShutdown function displays a dialog box that notifies the user that the system is shutting down. During the InitiateSystemShutdown time-out period, the AbortSystemShutdown function can prevent the system from shutting down.

To stop the local computer from shutting down, the calling process must have the SE_SHUTDOWN_NAME privilege. To stop a remote computer from shutting down, the calling process must have the SE_REMOTE_SHUTDOWN_NAME privilege on the remote computer. By default, users can enable the SE_SHUTDOWN_NAME privilege on the computer they are logged onto, and administrators can enable the SE_REMOTE_SHUTDOWN_NAME privilege on remote computers.

Failures of this function are typically due to an invalid computer name, an inaccessible computer, or insufficient privilege.

See Also

InitiateSystemShutdown


accept
accept  QuickInfo

The Windows Sockets accept function accepts a connection on a socket.

SOCKET accept (

SOCKET  s,
struct sockaddr FAR  * addr,
int FAR  * addrlen
);
Parameters

s

A descriptor identifying a socket that is in listen mode.

addr

An optional pointer to a buffer which receives the address of the connecting entity, as known to the communications layer. The exact format of the addr argument is determined by the address family established when the socket was created.

addrlen

An optional pointer to an integer which contains the length of the address addr.

Return Value

If no error occurs, accept returns a value of type SOCKET, which is a descriptor for the accepted packet. Otherwise, a value of INVALID_SOCKET is returned, and a specific error code may be retrieved by calling WSAGetLastError.

The integer referred to by addrlen initially contains the amount of space pointed to by addr. On return it will contain the actual length, in bytes, of the address returned.

Error Codes

WSANOTINITIALISED	A successful WSAStartup must occur before using this function.
WSAENETDOWN	The Windows Sockets implementation has detected that the network subsystem has failed.
WSAEFAULT	The addrlen argument is too small (less than the size of a sockets address structure).
WSAEINTR	The (blocking) call was canceled using WSACancelBlockingCall.
WSAEINPROGRESS	A blocking Windows Sockets call is in progress.
WSAEINVAL	The listen function was not invoked before accept.
WSAEMFILE	The queue is empty upon entry to accept and there are no descriptors available.
WSAENOBUFS	No buffer space is available.
WSAENOTSOCK	The descriptor is not a socket.
WSAEOPNOTSUPP	The referenced socket is not a type that supports connection-oriented service.
WSAEWOULDBLOCK	The socket is marked as nonblocking and no connections are present to be accepted.
Remarks

This function extracts the first connection on the queue of pending connections on s, creates a new socket with the same properties as s and returns a handle to the new socket. If no pending connections are present on the queue, and the socket is not marked as nonblocking, accept blocks the caller until a connection is present. If the socket is marked nonblocking and no pending connections are present on the queue, accept returns an error as described following. The accepted socket may not be used to accept more connections. The original socket remains open.

The argument addr is a result parameter that is filled in with the address of the connecting entity, as known to the communications layer. The exact format of the addr parameter is determined by the address family in which the communication is occurring. The addrlen is a value-result parameter; it should initially contain the amount of space pointed to by addr; on return it will contain the actual length (in bytes) of the address returned. This call is used with connection-based socket types such as SOCK_STREAM. If addr and/or addrlen are equal to NULL, then no information about the remote address of the accepted socket is returned.

See Also

bind, connect, listen, select, socket, WSAAsyncSelect, WSACancelBlockingCall, WSAStartup


AccessCheck
AccessCheck  QuickInfo  Overview  Group

The AccessCheck function is used by a server application to check a client's access to an object against the access control associated with the object.

BOOL AccessCheck(

PSECURITY_DESCRIPTOR  pSecurityDescriptor,	// address of security descriptor
HANDLE  ClientToken,	// handle of client access token
DWORD  DesiredAccess,	// access mask to request
PGENERIC_MAPPING  GenericMapping,	// address of generic-mapping structure
PPRIVILEGE_SET  PrivilegeSet,	// address of privilege-set structure
LPDWORD  PrivilegeSetLength,	// size of privilege-set structure
LPDWORD  GrantedAccess,	// address of granted access mask
LPBOOL  AccessStatus	// address of flag indicating whether access granted
);
Parameters

pSecurityDescriptor

Points to a SECURITY_DESCRIPTOR structure against which access is checked.

ClientToken

Identifies an access token representing a client attempting to gain access.

This handle must be obtained from a communications session layer — for instance, a named pipe — to prevent possible security policy violations.

DesiredAccess

Specifies the access mask to be requested. This mask must have been mapped by the MapGenericMask function to contain no generic access rights.

GenericMapping

Points to the GENERIC_MAPPING structure associated with the object for which access is being checked.

PrivilegeSet

Points to a PRIVILEGE_SET structure that the function fills with any privileges used to perform the access validation. If no privileges were used, the buffer contains a privilege set consisting of zero privileges.

PrivilegeSetLength

Specifies the size, in bytes, of the buffer pointed to by the PrivilegeSet parameter.

GrantedAccess

Points to a variable the function fills with an access mask indicating which access rights were granted. If the function fails, this access mask is not supplied.

AccessStatus

Points to a flag indicating the success or failure of the access check. If AccessStatus is TRUE, the access token has the requested access to the object. If AccessStatus is FALSE, the access token does not have the requested access. When this parameter is FALSE, the application can use the GetLastError function to get extended error information.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The AccessCheck function compares the specified security descriptor with the specified access token and indicates, in the AccessStatus parameter, whether access is granted or denied. If access is granted, the requested access mask becomes the object's granted access mask.

Only the discretionary access-control list is examined during an access check.

See Also

AccessCheckAndAuditAlarm, AreAllAccessesGranted, AreAnyAccessesGranted, GENERIC_MAPPING, MapGenericMask, PrivilegeCheck, PRIVILEGE_SET, SECURITY_DESCRIPTOR


AccessCheckAndAuditAlarm
AccessCheckAndAuditAlarm  QuickInfo  Overview  Group

The AccessCheckAndAuditAlarm function performs an access validation and generates corresponding audit messages. An application can also use this function to determine whether necessary privileges are held by a client process. This function is generally used by a server application impersonating a client process. Alarms are not supported in the current version of Windows NT.

BOOL AccessCheckAndAuditAlarm(

LPCTSTR  SubsystemName,	// address of string for subsystem name
LPVOID  HandleId,	// address of handle identifier
LPTSTR  ObjectTypeName,	// address of string for object type
LPTSTR  ObjectName,	// address of string for object name
PSECURITY_DESCRIPTOR  SecurityDescriptor,	// address of security descriptor
DWORD  DesiredAccess,	// mask for requested access rights
PGENERIC_MAPPING  GenericMapping,	// address of GENERIC_MAPPING
BOOL  ObjectCreation,	// object-creation flag
LPDWORD  GrantedAccess,	// address of mask for granted rights
LPBOOL  AccessStatus,	// address of flag for results
LPBOOL  pfGenerateOnClose	// address of flag for audit generation
);
Parameters

SubsystemName

Points to a null-terminated string specifying the name of the subsystem calling the function — for example, "DEBUG" or "WIN32."

HandleId

Points to a unique 32-bit value representing the client's handle of the object. If the access is denied, this value is ignored and may be reused.

ObjectTypeName

Points to a null-terminated string specifying the type of object being created or accessed. This string appears in the audit log for the object.

ObjectName

Points to a null-terminated string specifying the name of the object being created or accessed. This string appears in the audit log for the object.

SecurityDescriptor

Points to the SECURITY_DESCRIPTOR structure against which access is checked.

DesiredAccess

Specifies an access mask giving the requested access rights. This mask must have been mapped to contain no generic access rights by the MapGenericMask function.

GenericMapping

Points to the GENERIC_MAPPING structure associated with the type of object being examined.

ObjectCreation

Specifies a flag that determines whether the calling application will create a new object when access is granted. If this flag is TRUE, the application creates a new object; if it is FALSE, the application opens an existing object.

GrantedAccess

Points to a buffer that receives an access mask indicating which access rights were granted, if the function succeeds.

AccessStatus

Points to a flag that the function sets to indicate the success or failure of the access check. If access is granted, this flag is TRUE; otherwise, it is FALSE.

pfGenerateOnClose

Points to a flag set by the audit-generation routine when the function returns. This flag must be passed to the ObjectCloseAuditAlarm function when the object handle is closed.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The AccessCheckAndAuditAlarm function compares the specified security descriptor with the impersonation access token of the calling process and indicates whether access is granted or denied. If access is granted, the requested access mask becomes the granted access mask for the object. This function also generates any necessary audit messages as a result of the access attempt.

This function requires the calling process to have the SE_AUDIT_NAME privilege. The test for this privilege is performed against the primary token of the calling process, not the impersonation token of the thread.

See Also

AccessCheck, AreAllAccessesGranted, AreAnyAccessesGranted, GENERIC_MAPPING, MapGenericMask, ObjectCloseAuditAlarm, ObjectOpenAuditAlarm, ObjectPrivilegeAuditAlarm, PrivilegeCheck, PrivilegedServiceAuditAlarm, SECURITY_DESCRIPTOR


AccessResource

The AccessResource function is not implemented in the Win32 API. Win32-based applications should use the LoadResource, LockResource, and FindResource functions.


AcsLan
AcsLan  QuickInfo

The AcsLan function is used to communicate with other computers or network peripheral devices, such as printers, using the data link control (DLC) protocol. The caller submits requests by filling in a command control block (CCB) and then calling AcsLan.

Commands submitted through AcsLan can complete synchronously or asynchronously. The DLC driver, not the caller, determines how a command completes. This is unlike the Netbios function, for example, which has commands complete synchronously or asynchronously as requested by the caller.

There are some differences between NT DLC and the CCB2 interface. The most notable difference is that the buffer pool must be specified on an open adapter instance basis and not specified per-SAP (service-access point). After an adapter has been opened using the DIR.OPEN.ADAPTER command, a buffer pool must be given to the DLC driver using BUFFER.CREATE.

ACSLAN_STATUS AcsLan(

PLLC_CCB  pCcb,	// address of command control block
PLLC_CCB * ppBadCcb	// address of pointer for invalid CCB
);
Parameters

pCcb

Points to an LLC_CCB structure describing the function being performed. For information about this structure, see documentation for IBM LAN.

ppBadCcb

Points to a pointer to an LLC_CCB structure. This parameter is used when a chain of LLC_CCB structures is submitted. If the parameter is not NULL on input, this pointer will contain a pointer to the first invalid LLC_CCB structure discovered in the chain.

Return Value

The function returns an ACSLAN_STATUS value. ACSLAN_STATUS is an enumerated type. The following values are defined:

Value	Meaning
ACSLAN_STATUS_COMMAND_ACCEPTED	The request has been processed and passed to the DLC driver. The command may or may not have already completed, depending on whether it is a synchronous or asynchronous command and depending on other timing considerations. This value does not mean that the command completed successfully. The caller must check the uchDlcStatus member in the LLC_CCB structure to determine whether the request succeeded or failed.
ACSLAN_STATUS_INVALID_CCB_POINTER	A pointer in the the LLC_CCB structure, or the parameter table is invalid.
ACSLAN_STATUS_CCB_IN_ERROR	A problem was detected with the LLC_CCB structure. The caller should check the values in the structure and resubmit it.
ACSLAN_STATUS_CHAINED_CCB_IN_ERROR	A problem was detected with an LLC_CCB structure in a chain of LLC_CCB structures.
ACSLAN_STATUS_SYSTEM_ERROR	This value is not used.
ACSLAN_STATUS_SYSTEM_STATUS	This value is not used.
ACSLAN_STATUS_INVALID_COMMAND	The command in the uchDlcCommand member of the LLC_CCB structure is unrecognized.
See Also

Netbios


ActivateKeyboardLayout
ActivateKeyboardLayout  QuickInfo  Overview  Group

The implementations of ActivateKeyboardLayout in Windows 95 and Windows NT are substantially different. To accommodate these differences, this reference page first presents the Windows 95 implementation in its entirety, followed by the Windows NT version.

Windows 95:

The ActivateKeyboardLayout function sets the input language for the current thread. This function accepts a keyboard layout handle that identifies a locale as well as the physical layout of the keyboard.

HKL ActivateKeyboardLayout(

HKL  hkl,	// handle of keyboard layout
UINT  Flags	// keyboard layout flags
);
Parameters

hkl

Handle of a keyboard layout or a zero-extended locale identifier. This parameter can be any valid keyboard layout handle obtained using the LoadKeyboardLayout or GetKeyboardLayoutList function or one of the following values:

Value	Meaning
HKL_NEXT	Selects the next layout in the keyboard layouts list maintained by the system.
HKL_PREV	Selects the previous layout in the keyboards layout list maintained by the system.
Flags

Specifies the keyboard layout flags. The value of this parameter can be:

Value	Meaning
KLF_REORDER	Reorders the keyboard layouts list by moving the given keyboard layout handle to the head of the list. If this value is not given, the list is rotated without a change of order. For example, if a user had an English layout active, as well as having French, German and Spanish layouts loaded (in that order), then activating the German layout with the KLF_REORDER bit set would produce the following order: German, English, French, Spanish. Activating the German layout without the KLF_REORDER value set would produce the following order: German, Spanish, English, French.
Return Value

If the function succeeds, the return value is the previous keyboard layout handle. Otherwise, it is zero. To get extended error information, use the GetLastError function.

Remarks

Several keyboard layouts can be loaded at any one time, but only one is active at a time. Loading multiple keyboard layouts makes it possible to rapidly switch between layouts.

An application can create a valid keyboard layout handle by setting the high word to zero and the low word to a locale identifier. Using such keyboard layout handles changes the input language without affecting the physical layout.

When multiple input method editors (IMEs) are allowed for each locale, passing in a keyboard layout handle in which the high word (the device handle) is zero activates the first IME in the list "belonging" to the locale.

See Also

LoadKeyboardLayout, GetKeyboardLayoutName, UnloadKeyboardLayout

Windows NT:

The ActivateKeyboardLayout function activates a different keyboard layout and sets the active keyboard layout for the entire system rather than the calling thread.

BOOL ActivateKeyboardLayout(

HKL  hkl,	// handle of keyboard layout
UINT  Flags	// keyboard layout flags
);
Parameters

hkl

Identifies the keyboard layout to be activated. The layout must have been loaded by a previous call to the LoadKeyboardLayout function. This parameter must be either the handle of a keyboard layout or one of the following values:

Value	Meaning
HKL_NEXT	Selects the next layout in the circular list of loaded layouts maintained by the system.
HKL_PREV	Selects the previous layout in the circular list of loaded layouts maintained by the system.
Flags

Specifies how the keyboard layout is to be activated. This parameter can be one of the following values:

Value	Meaning
KLF_REORDER	If this bit is set, the system's circular list of loaded keyboard layouts is reordered. If this bit is not set, the list is rotated without a change of order. For example, if a user had an English layout active, as well as having French, German and Spanish layouts loaded (in that order), then activating the German layout with the KLF_REORDER bit set would produce the following order: German, English, French, Spanish. Activating the German layout without the KLF_REORDER bit set would produce the following order: German, Spanish, English, French. If less than three keyboard layouts are loaded, the value of this flag is irrelevant.
KLF_UNLOADPREVIOUS	The previously active layout is unloaded.
Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Several keyboard layouts can be loaded at any one time, but only one is active at a time. Loading multiple keyboard layouts makes it possible to rapidly switch between layouts.

See Also

LoadKeyboardLayout, GetKeyboardLayoutName, UnloadKeyboardLayout


AddAccessAllowedAce
AddAccessAllowedAce  QuickInfo  Overview  Group

The AddAccessAllowedAce function adds an access-allowed ACE to an ACL. The access is granted to a specified SID.

An ACE is an access-control entry. An ACL is an access-control list. A SID is a security identifier.

BOOL AddAccessAllowedAce(

PACL  pAcl,	// address of access-control list
DWORD  dwAceRevision,	// ACL revision level
DWORD  AccessMask,	// access mask
PSID  pSid	// address of security identifier
);
Parameters

pAcl

Points to an ACL structure. This function adds an access-allowed ACE to this ACL. The ACE is in the form of an ACCESS_ALLOWED_ACE structure.

dwAceRevision

Specifies the revision level of the ACL being modified. Currently, this value must be ACL_REVISION.

AccessMask

Specifies the mask of access rights to be granted to the specified SID.

pSid

Points to the SID structure representing a process being granted access.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The addition of an access-allowed ACE to an ACL is the most common form of ACL modification.

The ACE_HEADER structure placed in the ACE by this function specifies a type and size, but provides no inheritance and no ACE flags.

See Also

ACCESS_ALLOWED_ACE, ACE_HEADER, ACL, AddAccessDeniedAce, AddAce, AddAuditAccessAce, DeleteAce, GetAce


AddAccessDeniedAce
AddAccessDeniedAce  QuickInfo  Overview  Group

The AddAccessDeniedAce function adds an access-denied ACE to an ACL. The access is denied to a specified SID.

An ACE is an access-control entry. An ACL is an access-control list. A SID is a security identifier.

BOOL AddAccessDeniedAce(

PACL  pAcl,	// address of access-control list
DWORD  dwAceRevision,	// ACL revision level
DWORD  AccessMask,	// access mask
PSID  pSid	// address of security identifier
);
Parameters

pAcl

Points to an ACL structure. This function adds an access-denied ACE to this ACL. The ACE is in the form of an ACCESS_DENIED_ACE structure.

dwAceRevision

Specifies the revision level of the ACL being modified. Currently, this value must be ACL_REVISION.

AccessMask

Specifies the mask of access rights being denied to the specified SID.

pSid

Points to the SID structure representing the process being denied access.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The ACE_HEADER structure placed in the ACE by this function specifies a type and size, but provides no ACE flags.

See Also

ACCESS_DENIED_ACE, ACE_HEADER, ACL, AddAccessAllowedAce, AddAce, AddAuditAccessAce, DeleteAce, GetAce


AddAce
AddAce  QuickInfo  Overview  Group

The AddAce function adds one or more ACEs to a specified ACL.

An ACE is an access-control entry. An ACL is an access-control list.

BOOL AddAce(

PACL  pAcl,	// address of access-control list
DWORD  dwAceRevision,	// ACL revision level
DWORD  dwStartingAceIndex,	// index of ACE position in ACL
LPVOID  pAceList,	// address of one or more ACEs
DWORD  nAceListLength	// size of buffer for ACEs
);
Parameters

pAcl

Points to an ACL structure. This function adds an ACE to this ACL.

dwAceRevision

Specifies the revision level of the ACL being modified. Currently, this value must be ACL_REVISION.

dwStartingAceIndex

Specifies the position in the ACL's list of ACEs at which to add new ACEs. A value of zero inserts the ACEs at the beginning of the list. A value of MAXDWORD appends the ACEs to the end of the list.

pAceList

Points to a list of one or more ACEs to be added to the specified ACL. The ACEs in the list must be stored contiguously.

nAceListLength

Specifies the size, in bytes, of the input buffer pointed to by the pAceList parameter.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Applications frequently use the FindFirstFreeAce and GetAce functions when using the AddAce function to manipulate an ACL. In addition, the ACL_SIZE_INFORMATION structure retrieved by the GetAclInformation function contains the size of the ACL and the number of ACEs it contains.

See Also

ACL, ACL_SIZE_INFORMATION, AddAccessAllowedAce, AddAccessDeniedAce, AddAuditAccessAce, DeleteAce, FindFirstFreeAce, GetAce, GetAclInformation


AddAtom
AddAtom  QuickInfo  Overview  Group

The AddAtom function adds a character string to the local atom table and returns a unique value (an atom) identifying the string.

ATOM AddAtom(

LPCTSTR  lpString	// address of string to add
);
Parameters

lpString

Points to the null-terminated string to be added. The string can have a maximum size of 255 bytes. Strings differing only in case are considered identical. The case of the first string added is preserved and returned by the GetAtomName function.

Return Value

If the function succeeds, the return value is the newly created atom.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

The AddAtom function stores no more than one copy of a given string in the atom table. If the string is already in the table, the function returns the existing atom and, in the case of a string atom, increments the string's reference count.

The MAKEINTATOM macro can be used to convert a WORD value into a string that can be added to the atom table by using the AddAtom function.

AddAtom returns a string atom whose value is in the range 0xC000 through 0xFFFF.

If lpString has the form "#1234", AddAtom returns an integer atom whose value is the 16-bit representation of the decimal number specified in the string (0x04D2, in this example). If the decimal value specified is 0x0000 or a value in the range 0xC000 through 0xFFFF, the return value is zero, indicating an error. If lpString is in the range 0x0001 through 0xBFFF, the return value is the low-order word of lpString.

See Also

DeleteAtom, FindAtom, GetAtomName, GlobalAddAtom, GlobalDeleteAtom, GlobalFindAtom, GlobalGetAtomName, MAKEINTATOM


AddAuditAccessAce
AddAuditAccessAce  QuickInfo  Overview  Group

The AddAuditAccessAce function adds a system-audit ACE to a system ACL. The access of a specified SID is audited.

An ACE is an access-control entry. An ACL is an access-control list. A SID is a security identifier.

BOOL AddAuditAccessAce(

PACL  pAcl,	// address of access-control list
DWORD  dwAceRevision,	// ACL revision level
DWORD  dwAccessMask,	// access mask
PSID  pSid,	// address of security identifier
BOOL  bAuditSuccess,	// flag for auditing successful access
BOOL  bAuditFailure	// flag for auditing unsuccessful access attempts
);
Parameters

pAcl

Points to an ACL structure. This function adds a system-audit ACE to this ACL. The ACE is in the form of an SYSTEM_AUDIT_ACE structure.

dwAceRevision

Specifies the revision level of the ACL being modified. Currently, this value must be ACL_REVISION.

dwAccessMask

Specifies the mask of access rights to be audited for the specified SID.

pSid

Points to the SID structure representing the process whose access is being audited.

bAuditSuccess

Specifies whether successful access attempts are to be audited. Set this flag to TRUE to enable auditing; otherwise, set it to FALSE.

bAuditFailure

Specifies whether unsuccessful access attempts are to be audited. Set this flag to TRUE to enable auditing; otherwise, set it to FALSE.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The ACE_HEADER structure placed in the ACE by this function specifies a type and size, but provides no ACE flags.

See Also

ACE_HEADER, ACL, AddAccessAllowedAce, AddAccessDeniedAce, AddAce, DeleteAce, GetAce, SID, SYSTEM_AUDIT_ACE


AddFontResource
AddFontResource  QuickInfo  Overview  Group

The AddFontResource function adds the font resource from the specified file to the Windows font table. The font can subsequently be used for text output by any Windows-based application.

int AddFontResource(

LPCTSTR  lpszFilename	// address of font-resource filename
);
Parameters

lpszFilename

Points to a null-terminated character string that contains a valid font file filename. The filename may specify either a .FON font resource file, a .FNT raw bitmap font file, a .TTF raw TrueType file, or a .FOT TrueType resource file.

Return Value

If the function succeeds, the return value specifies the number of fonts added.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

Any application that adds or removes fonts from the Windows font table should notify other windows of the change by sending a WM_FONTCHANGE message to all top-level windows in the operating system. The application should send this message by calling the SendMessage function and setting the hwnd parameter to HWND_BROADCAST.

When an application no longer needs a font resource that it loaded by calling the AddFontResource function, it must remove the resource by calling the RemoveFontResource function.

See Also

RemoveFontResource, SendMessage


AddForm [New - Windows NT]
AddForm  QuickInfo  Overview  Group

[New - Windows NT]

The AddForm function adds a form to the list of available forms that can be selected for the specified printer.

BOOL AddForm(

HANDLE  hPrinter,	// handle of printer object
DWORD  Level,	// data-structure level
LPBYTE  pForm	// address of form info. data structure
);
Parameters

hPrinter

Identifies the printer that supports printing with the specified form.

Level

Specifies the level of the structure to which pForm points. This value must be 1.

pForm

Points to a FORM_INFO_1 structure.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The printer handle identified by the hPrinter parameter is returned by the OpenPrinter function.

An application can determine which forms are available for a printer by calling the EnumForms function.

See Also

EnumForms, FORM_INFO_1, OpenPrinter


AddJob
AddJob  QuickInfo  Overview  Group

The AddJob function obtains a path string that specifies a file that you can use to store a spooled print job.

BOOL AddJob(

HANDLE  hPrinter,	// specifies printer for the print job
DWORD  Level,	// specifies version of print job information data structure
LPBYTE  pData,	// points to buffer to receive print job information data
DWORD  cbBuf,	// specifies size of buffer pointed to by pData
LPDWORD  pcbNeeded	// points to variable to receive size of print job information data
);
Parameters

hPrinter

Handle that specifies the printer for the print job. This must be a local printer that is configured as a spooled printer. If hPrinter is a handle to a remote printer connection, or if the printer is configured for direct printing, the AddJob function fails.

Level

Specifies the version of the print job information data structure that the function stores into the buffer pointed to by pData. Set this parameter to one.

pData

Points to a buffer to receive an ADDJOB_INFO_1 data structure and a path string.

cbBuf

Specifies the size, in bytes, of the buffer pointed to by pData. The buffer needs to be large enough to contain an ADDJOB_INFO_1 structure and a path string.

pcbNeeded

Points to a variable to receive the total size, in bytes, of the ADDJOB_INFO_1 data structure plus the path string. If this value is less than or equal to cbBuf and the function succeeds, this is the actual number of bytes written to the buffer pointed to by pData. If this number is greater than cbBuf, the buffer is too small, and you must call the function again with a buffer size at least as large as *pcbNeeded.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

You can call the CreateFile function to open the spool file specified by the Path member of the ADDJOB_INFO_1 structure, and then call the WriteFile function to write print job data to it. Once that is done, call ScheduleJob to notify the print spooler that the print job can now be scheduled by the spooler for printing.

See Also

ADDJOB_INFO_1, CreateFile, OpenPrinter, ScheduleJob, WriteFile


AddMonitor
AddMonitor  QuickInfo  Overview  Group

The AddMonitor function installs a local printer monitor and links the configuration, data, and monitor files. Future releases of Windows NT may allow remote installation of printer monitors.

BOOL AddMonitor (

LPTSTR  pName,	// address of server name
DWORD  Level,	// monitor info. structure level
LPBYTE  pMonitors	// address of monitor info structure
);
Parameters

pName

Points to a null-terminated string that specifies the name of the server on which the monitor should be installed. For this release of Windows NT,  monitors may only be installed locally, so this string should be NULL.

Level

Specifies the version of the structure to which pMonitors points. This value must be 2.

pMonitors

Points to a MONITOR_INFO_2 structure.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Before an application calls AddMonitor, all files required by the monitor must be copied to the SYSTEM32 directory.

An application can determine which printer monitors are currently installed by calling the EnumMonitors function.

A monitor added by AddMonitor may be removed by calling DeleteMonitor.

See Also

DeleteMonitor, EnumMonitors, MONITOR_INFO_2


AddPort
AddPort  QuickInfo  Overview  Group

The AddPort function adds the name of a port to the list of supported ports.

BOOL AddPort(

LPTSTR  pName,	// address of a server name
HWND  hWnd,	// handle of parent window
LPTSTR  pMonitorName	// address of a monitor name
);
Parameters

pName

Points to a null-terminated string that specifies the name of the server to which the port is connected. If this string is NULL, the port is local.

hWnd

Identifies the parent window of the AddPort dialog box.

pMonitorName

Points to a null-terminated string that specifies the monitor associated with the port.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The monitor name specified in pMonitorName can be retrieved by calling the EnumMonitors function.

An application can determine which ports are currently supported by calling the EnumPorts function.

See Also

EnumMonitors, EnumPorts


AddPrinter
AddPrinter  QuickInfo  Overview  Group

The AddPrinter function adds a printer to the list of supported printers for a specified server.

HANDLE AddPrinter(

LPTSTR  pName,	// address of server name
DWORD  Level,	// printer info. structure level
LPBYTE  pPrinter	// address of structure
);
Parameters

pName

Points to a null-terminated string that specifies the name of the server on which the printer's print processor should be installed. If this string is NULL, the print processor is installed locally.

Level

Specifies the version of the structure to which pPrinter points. This value must be 2.

pPrinter

Points to a PRINTER_INFO_2 structure that contains information about the printer. You must set the pPrinterName, pPortName, pDriverName, pPrintProcessor, and pDatatype members of this structure before calling AddPrinter.

Return Value

If the function succeeds, the return value is the handle of a new printer object.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

The following list identifies the members of the PRINTER_INFO_2 structure that can be set before this function is called.

Attributes	pPrintProcessor
DefaultPriority	Priority
pComment	pSecurityDescriptor
pDatatype	pSepFile
pDevMode	pShareName
pLocation	StartTime
pParameters	UntilTime
The Status, cJobs, and AveragePPM members of the PRINTER_INFO_2 structure are reserved for use by the GetPrinter function. They must not be set before calling AddPrinter.

If pSecurityDescriptor is NULL, the system assigns a default security descriptor to the printer.

After an application creates a printer object with the AddPrinter function, it must use the PrinterProperties function to specify the correct settings for the printer driver associated with the printer object.

The AddPrinter function returns an error if a printer object with the same name already exists, unless that object is marked as pending deletion. In that case, the existing printer will not be deleted, and the AddPrinter creation parameters will be used to change the existing printer settings (as if the application had used the SetPrinter function).

Windows NT:The caller of the AddPrinter function must have SERVER_ACCESS_ADMINISTER access to the server on which the printer is to be created. The handle returned by the function will have PRINTER_ALL_ACCESS permission, and can be used to perform administrative operations on the printer.

Windows 95: This access validation is not supported in Windows 95.

Use the EnumPrintProcessors function to enumerate the set of print processors installed on a server. Use the EnumPrintProcessorDatatypes function to enumerate the set of datatypes that a print processor supports.

See Also

ClosePrinter, DeletePrinter, EnumPrintProcessors, EnumPrintProcessorDatatypes, GetPrinter, PRINTER_INFO_2, PrinterProperties, SetPrinter


AddPrinterConnection [New - Windows NT]
AddPrinterConnection  Overview  Group

[New - Windows NT]

The AddPrinterConnection function adds a connection to the specified printer for the current user.

BOOL AddPrinterConnection (

LPTSTR  pName	// address of printer name
);
Parameters

pName

Points to a null-terminated string that specifies the name of a printer that the current user wishes to establish a connection to.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

When Windows NT makes a connection to a printer, it may need to copy printer driver files to the workstation. If the user does not have permission to copy files to the appropriate location, the AddPrinterConnection function fails, and GetLastError returns ERROR_ACCESS_DENIED.

A printer connection established by calling AddPrinterConnection will be enumerated when EnumPrinters is called with dwType set to PRINTER_ENUM_CONNECTION.

See Also

ConnectToPrinterDlg, DeletePrinterConnection, EnumPrinters


AddPrinterDriver
AddPrinterDriver  QuickInfo  Overview  Group

The AddPrinterDriver function installs a local or remote printer driver and links the configuration, data, and driver files.

BOOL AddPrinterDriver(

LPTSTR  pName,	// address of server name
DWORD  Level,	// printer info. structure level
LPBYTE  pDriverInfo	// address of printer info. structure
);
Parameters

pName

Points to a null-terminated string that specifies the name of the server on which the driver should be installed. If the driver will be installed locally, this string should be NULL.

Level

Specifies the version of the structure to which pDriverInfo points.

Windows 95: This value can be either 2 or 3.

Windows NT: This value must be 2.

pDriverInfo

Points to either a DRIVER_INFO_2 structure or a DRIVER_INFO_3 structure. If dwlevel is 2, this parameter receives a DRIVER_INFO_2 structure. If dwlevel is 3, this parameter receives a DRIVER_INFO_3 structure.

If the pEnvironment member of the structure pointed to by pDriverInfo is NULL, the current environment of the caller/client (not of the destination/server) is used.

Windows 95: This structure can be either DRIVER_INFO_2 or DRIVER_INFO_3.

Windows NT: This structure must be DRIVER_INFO_2.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Before an application calls AddPrinterDriver, all files required by the driver must be copied to the system's printer-driver directory. An application can retrieve the name of this directory by calling the GetPrinterDriverDirectory function.

An application can determine which printer drivers are currently installed by calling the EnumPrinterDrivers function.

See Also

DRIVER_INFO_2, EnumPrinterDrivers, GetPrinterDriverDirectory


AddPrintProcessor
AddPrintProcessor  QuickInfo  Overview  Group

The AddPrintProcessor function installs a print processor on the specified server and adds the print-processor name to an internal list of supported print processors.

BOOL AddPrintProcessor(

LPTSTR  pName,	// address of server name
LPTSTR  pEnvironment,	// address of environment name
LPTSTR  pPathName,	// address of path
LPTSTR  pPrintProcessorName	// address of print-processor name
);
Parameters

pName

Points to a null-terminated string that specifies the name of the server on which the print processor should be installed. If this parameter is NULL, the print processor is installed locally.

pEnvironment

Points to a null-terminated string that specifies the environment. For example, "Windows x86" specifies Windows running on an Intel 80386 or 80486 processor. If this parameter is NULL, the current environment of the caller/client (not of the destination/server) is used.

pPathName

Points to a null-terminated string that specifies the name of the file that contains the print processor. This file must be in the system print-processor directory.

pPrintProcessorName

Points to a null-terminated string that specifies the name of the print processor.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Before calling this function, an application should verify that the file containing the print processor is stored in the system print-processor directory. An application can retrieve the name of the system print-processor directory by calling the GetPrintProcessorDirectory function.

An application can determine the name of existing print processors by calling the EnumPrintProcessors function.

See Also

EnumPrintProcessors, GetPrintProcessorDirectory


AddPrintProvidor
AddPrintProvidor  QuickInfo  Overview  Group

The AddPrintProvidor function installs a local printer provider and links the configuration, data, and provider files. Future releases of Windows may allow remote installation of printer providers.

BOOL AddPrintProvidor (

LPTSTR  pName,	// address of server name
DWORD  Level,	// provider information structure level
LPBYTE  pProvidorInfo	// address of provider information structure
);
Parameters

pName

Points to a null-terminated string that specifies the name of the server on which the provider should be installed. For this release of Windows 95 and Windows NT, providers may only be installed locally, so this parameter should be NULL.

Level

Specifies the level of the structure to which pProvidorInfo points. This value must be 1.

pProvidorInfo

Points to a PROVIDOR_INFO_1 structure.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Before an application calls this function, all files required by the provider must be copied to the SYSTEM32 directory.

A provider added by AddPrintProvidor may be removed by calling DeletePrintProvidor.

See Also

DeletePrintProvidor, PROVIDOR_INFO_1


AddPropSheetPageProc [New - Windows NT]
AddPropSheetPageProc  QuickInfo  Overview  Group

[New - Windows NT]

The AddPropSheetPageProc function specifies an application-defined callback function that a property sheet extension uses to add a page to a property sheet.

BOOL CALLBACK AddPropSheetPageProc(

HPROPSHEETPAGE  hpage,
LPARAM  lParam
);
Parameters

hpage

Handle to a property sheet page.

lParam

Application-defined 32-bit value.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.


AdjustTokenGroups
AdjustTokenGroups  QuickInfo  Overview  Group

The AdjustTokenGroups function adjusts groups in the specified access token. TOKEN_ADJUST_GROUPS access is required to enable or disable groups in an access token.

BOOL AdjustTokenGroups(

HANDLE  TokenHandle,	// handle of token that contains groups
BOOL  ResetToDefault,	// flag for default settings
PTOKEN_GROUPS  NewState,	// address of new group information
DWORD  BufferLength,	// size of buffer for previous information
PTOKEN_GROUPS  PreviousState,	// address of previous group information
PDWORD  ReturnLength	// address of required buffer size
);
Parameters

TokenHandle

Identifies the access token containing the groups to be modified.

ResetToDefault

Specifies whether the groups are to be set to their default enabled and disabled states. If this value is TRUE, the groups are set to their default states and the NewState parameter is ignored. If this value is FALSE, the groups are set according to the information pointed to by the NewState parameter.

NewState

Points to a TOKEN_GROUPS structure containing the groups whose states are to be set. If the ResetToDefault parameter is FALSE, the function sets each of the groups to the value of that group's SE_GROUP_ENABLED flag in the TOKEN_GROUPS structure. If ResetToDefault is TRUE, this parameter is ignored.

BufferLength

Specifies the size, in bytes, of the buffer pointed to by the PreviousState parameter. This parameter can be NULL if the PreviousState parameter is NULL.

PreviousState

Points to a buffer receiving a TOKEN_GROUPS structure containing the previous state of any groups the function modifies. The token must be open for TOKEN_QUERY access to use this parameter. This parameter can be NULL.

If a buffer is specified but it does not contain enough space to receive the complete list of modified groups, no group states are changed and the function fails. In this case, the function sets the variable pointed to by the ReturnLength parameter to the number of bytes required to hold the complete list of modified groups.

ReturnLength

Points to a variable set by the function that contains the actual number of bytes needed for the buffer pointed to by the PreviousState parameter. This parameter can be NULL and is ignored if PreviousState is NULL.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The information retrieved in the PreviousState parameter is formatted as a TOKEN_GROUPS structure. This means a pointer to the buffer can be passed as the NewState parameter in a subsequent call to the AdjustTokenGroups function, restoring the original state of the groups.

The NewState parameter can list groups to be changed that are not present in the access token. This does not affect the successful modification of the groups in the token.

Mandatory groups cannot be disabled. They are identified by the SE_GROUP_MANDATORY flag in the TOKEN_GROUPS structure. If an attempt is made to disable any mandatory groups, AdjustTokenGroups fails and leaves the state of all groups unchanged.

See Also

AdjustTokenPrivileges, GetTokenInformation, OpenProcessToken, OpenThreadToken, SetTokenInformation, TOKEN_GROUPS


AdjustTokenPrivileges
AdjustTokenPrivileges  QuickInfo  Overview  Group

The AdjustTokenPrivileges function adjusts privileges in the specified access token. Enabling or disabling privileges in an access token requires TOKEN_ADJUST_PRIVILEGES access.

BOOL AdjustTokenPrivileges(

HANDLE  TokenHandle,	// handle of token that contains privileges
BOOL  DisableAllPrivileges,	// flag for disabling all privileges
PTOKEN_PRIVILEGES  NewState,	// address of new privilege information
DWORD  BufferLength,	// size of previous information buffer
PTOKEN_PRIVILEGES  PreviousState,	// address of previous information
PDWORD  ReturnLength	// address of required buffer size
);
Parameters

TokenHandle

Identifies the access token that contains the privileges to be modified.

DisableAllPrivileges

Specifies whether the function is to disable all of the token's privileges. If this value is TRUE, the privileges are disabled, and the NewState parameter is ignored. If it is FALSE, the function modifies privileges based on the information pointed to by the NewState parameter.

NewState

Points to a TOKEN_PRIVILEGES structure containing the privileges to be changed. If the DisableAllPrivileges parameter is FALSE, the function sets each of the token's privileges to the value of that privilege's SE_PRIVILEGE_ENABLED flag in the TOKEN_PRIVILEGES structure. If DisableAllPrivileges is TRUE, this parameter is ignored.

BufferLength

Specifies the size, in bytes, of the buffer pointed to by the PreviousState parameter. This parameter can be NULL if the PreviousState parameter is NULL.

PreviousState

Points to a buffer the function fills with a TOKEN_PRIVILEGES structure containing the previous state of any privileges the function modifies. The token must be open for TOKEN_QUERY access to use this parameter. This parameter can be NULL.

If a buffer is specified but does not contain enough space to receive the complete list of modified privileges, no privileges are changed and the function fails. In this case, the function sets the variable pointed to by the ReturnLength parameter to the number of bytes required to hold the complete list of modified privileges.

ReturnLength

Points to a variable receiving the actual number of bytes needed for the buffer pointed to by the PreviousState parameter. This parameter can be NULL and is ignored if PreviousState is NULL.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The information retrieved in the PreviousState parameter is formatted as a TOKEN_PRIVILEGES structure. This means that a pointer to the buffer can be passed as the NewState parameter in a subsequent call to the AdjustTokenPrivileges function, restoring the original state of the privileges.

The NewState parameter can list privileges to be changed that are not present in the access token. This does not affect the successful modification of the privileges in the token.

See Also

AdjustTokenGroups, GetTokenInformation, OpenProcessToken, OpenThreadToken, SetTokenInformation, TOKEN_PRIVILEGES


AdjustWindowRect
AdjustWindowRect  QuickInfo  Overview  Group

The AdjustWindowRect function calculates the required size of the window rectangle based on the desired client-rectangle size. The window rectangle can then be passed to the CreateWindowEx function to create a window whose client area is the desired size.

BOOL AdjustWindowRect(

LPRECT  lpRect,	// address of client-rectangle structure
DWORD  dwStyle,	// window styles
BOOL  bMenu	// menu-present flag
);
Parameters

lpRect

Points to a RECT structure that contains the coordinates of the top-left and bottom-right corners of the desired client area. When the function returns, the structure contains the coordinates of the top-left and bottom-right corners of the window to accommodate the desired client area.

dwStyle

Specifies the window styles of the window whose required size is to be calculated.

bMenu

Specifies whether the window has a menu.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

A client rectangle is the smallest rectangle that completely encloses a client area. A window rectangle is the smallest rectangle that completely encloses a window.

The AdjustWindowRect function also does not add extra rows when a menu bar wraps to two or more rows.

See Also

AdjustWindowRectEx, CreateWindowEx, RECT


AdjustWindowRectEx
AdjustWindowRectEx  QuickInfo  Overview  Group

The AdjustWindowRectEx function calculates the required size of the rectangle of a window with extended style based on the desired client-rectangle size. The window rectangle can then be passed to the CreateWindowEx function to create a window whose client area is the desired size.

BOOL AdjustWindowRectEx(

LPRECT  lpRect,	// address of client-rectangle structure
DWORD  dwStyle,	// window styles
BOOL  bMenu,	// menu-present flag
DWORD  dwExStyle	// extended style
);
Parameters

lpRect

Points to a RECT structure that contains the coordinates of the top-left and bottom-right corners of the desired client area. When the function returns, the structure contains the coordinates of the top-left and bottom-right corners of the window to accommodate the desired client area.

dwStyle

Specifies the window styles of the window whose required size is to be calculated.

bMenu

Specifies whether the window has a menu.

dwExStyle

Specifies the extended style of the window whose required size is to be calculated.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

A client rectangle is the smallest rectangle that completely encloses a client area. A window rectangle is the smallest rectangle that completely encloses a window.

The AdjustWindowRectEx function also does not add extra space when a menu bar wraps to two or more rows.

See Also

AdjustWindowRect, CreateWindowEx, RECT


AdvancedDocumentProperties
AdvancedDocumentProperties  QuickInfo  Overview  Group

The AdvancedDocumentProperties function displays a printer-configuration dialog box for the specified printer, allowing the user to configure that printer.

LONG AdvancedDocumentProperties(

HWND  hWnd,	// handle of dialog box's parent window
HANDLE  hPrinter,	// handle of printer object
LPTSTR  pDeviceName,	// address of driver name
PDEVMODE  pDevModeOutput,	// address of modified device mode structure
PDEVMODE  pDevModeInput	// address of original device mode structure
);
Parameters

hWnd

Identifies the parent window of the printer-configuration dialog box.

hPrinter

Identifies a printer object.

pDeviceName

Points to a null-terminated string specifying the name of the device for which a printer-configuration dialog box should be displayed.

pDevModeOutput

Points to a DEVMODE structure that will contain the configuration data specified by the user. An application can retrieve the number of bytes required for this structure by calling the AdvancedDocumentProperties function and setting pDevModeOutput to NULL.

pDevModeInput

Points to a DEVMODE structure that contains the configuration data used to initialize the controls of the printer-configuration dialog box.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

An application can obtain the printer handle identified by the hPrinter parameter by calling the OpenPrinter or AddPrinter function.

An application can obtain the name pointed to by the pDeviceName parameter by calling the GetPrinter function and then examining the pPrinterName member of the PRINTER_INFO_2 structure.

See Also

AddPrinter, DEVMODE, GetPrinter, OpenPrinter, PRINTER_INFO_2


AllocateAndInitializeSid
AllocateAndInitializeSid  QuickInfo  Overview  Group

The AllocateAndInitializeSid function allocates and initializes a security identifier (SID) with up to eight subauthorities.

BOOL AllocateAndInitializeSid(

PSID_IDENTIFIER_AUTHORITY  pIdentifierAuthority,	// address of identifier authority
BYTE  nSubAuthorityCount,	// count of subauthorities
DWORD  dwSubAuthority0,	// subauthority 0
DWORD  dwSubAuthority1,	// subauthority 1
DWORD  dwSubAuthority2,	// subauthority 2
DWORD  dwSubAuthority3,	// subauthority 3
DWORD  dwSubAuthority4,	// subauthority 4
DWORD  dwSubAuthority5,	// subauthority 5
DWORD  dwSubAuthority6,	// subauthority 6
DWORD  dwSubAuthority7,	// subauthority 7
PSID  *pSid	// address of pointer to SID
);
Parameters

pIdentifierAuthority

Points to an SID_IDENTIFIER_AUTHORITY structure, giving the top-level identifier authority value to set in the SID.

nSubAuthorityCount

Specifies the number of subauthorities to place in the SID. This parameter also identifies how many of the subauthority parameters have meaningful values. This parameter must contain a value from 1 through 8.

For example, a value of 3 indicates that the subauthority values specified by the dwSubAuthority0, dwSubAuthority1, and dwSubAuthority2 parameters have meaningful values and to ignore the remainder.

dwSubAuthority0 through dwSubAuthority7

Specify subauthority values to place in the SID.

pSid

Points to a variable that receives the address of the allocated and initialized SID structure.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

An SID allocated with this function must be freed by using the FreeSid function.

See Also

FreeSid, GetSidIdentifierAuthority, InitializeSid, SID_IDENTIFIER_AUTHORITY


AllocateLocallyUniqueId
AllocateLocallyUniqueId  QuickInfo  Overview  Group

The AllocateLocallyUniqueId function allocates a locally unique identifier (LUID).

BOOL AllocateLocallyUniqueId(

PLUID  Luid	// address of locally unique identifier
);
Parameters

Luid

Points to a buffer that receives the allocated LUID.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

An LUID is unique only within a single session. The same LUID value can be used on different computers or on the same computer after it has been restarted.

See Also

LookupPrivilegeValue


AllocConsole
AllocConsole  QuickInfo  Overview  Group

The AllocConsole function allocates a new console for the calling process.

BOOL AllocConsole(VOID)

Parameters

This function has no parameters.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

A process can only be associated with one console, so AllocConsole fails if the calling process already has a console. A process can use the FreeConsole function to detach itself from its current console, and then it can call AllocConsole to create a new console. If the calling process creates a child process, the child inherits the new console.

AllocConsole also sets up standard input, standard output, and standard error handles for the new console. The standard input handle is a handle to the console's input buffer, and the standard output and standard error handles are handles to the console's screen buffer. To retrieve these handles, use the GetStdHandle function.

This function is primarily used by graphics applications to create a console window. Graphics applications are initialized without a console. Console applications are normally initialized with a console, unless they are created as detached processes (by calling the CreateProcess function with the DETACHED_PROCESS flag).

See Also

CreateProcess, FreeConsole, GetStdHandle


AllocDStoCSAlias

The AllocDStoCSAlias function is obsolete. This function has no meaning in the 32-bit environment.


AllocResource

The AllocResource function is not implemented in the Win32 API. Win32-based applications should use the LoadResource, LockResource, and FindResource functions.


AllocSelector

The AllocSelector function is not implemented in the Win32 API. Win32-based applications should use the VirtualLock and VirtualUnlock functions.


AngleArc
AngleArc  QuickInfo  Overview  Group

The AngleArc function draws a line segment and an arc. The line segment is drawn from the current position to the beginning of the arc. The arc is drawn along the perimeter of a circle with the given radius and center. The length of the arc is defined by the given start and sweep angles.

BOOL AngleArc(

HDC  hdc,	// handle of device context
int  X,	// x-coordinate of circle's center
int  Y,	// y-coordinate of circle's center
DWORD  dwRadius,	// circle's radius
FLOAT  eStartAngle,	// arc's start angle
FLOAT  eSweepAngle	// arc's sweep angle
);
Parameters

hdc

Identifies a device context.

X

Specifies the logical x-coordinate of the center of the circle.

Y

Specifies the logical y-coordinate of the center of the circle.

dwRadius

Specifies the radius, in logical units, of the circle. This value must be positive.

eStartAngle

Specifies the start angle, in degrees, relative to the x-axis.

eSweepAngle

Specifies the sweep angle, in degrees, relative to the starting angle.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

The AngleArc function moves the current position to the ending point of the arc.

The arc drawn by this function may appear to be elliptical, depending on the current transformation and mapping mode. Before drawing the arc, AngleArc draws the line segment from the current position to the beginning of the arc.

The arc is drawn by constructing an imaginary circle around the specified center point with the specified radius. The starting point of the arc is determined by measuring counterclockwise from the x-axis of the circle by the number of degrees in the start angle. The ending point is similarly located by measuring counterclockwise from the starting point by the number of degrees in the sweep angle.

If the sweep angle is greater than 360 degrees, the arc is swept multiple times.

This function draws lines by using the current pen. The figure is not filled.

See Also

Arc, ArcTo, MoveToEx


AnimatePalette
AnimatePalette  QuickInfo  Overview  Group

The AnimatePalette function replaces entries in the specified logical palette.

BOOL AnimatePalette(

HPALETTE  hpal,	// handle of logical color palette
UINT  iStartIndex,	// first entry in logical palette
UINT  cEntries,	// count of entries in logical palette
CONST PALETTEENTRY  *ppe	// address of first replacement
);
Parameters

hpal

Identifies the logical palette.

iStartIndex

Specifies the first logical palette entry to be replaced.

cEntries

Specifies the number of entries to be replaced.

ppe

Points to the first member of an array of PALETTEENTRY structures used to replace the current entries.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

An application can determine whether a device supports palette operations by calling the GetDeviceCaps function and specifying the RASTERCAPS constant.

The AnimatePalette function only changes entries with the PC_RESERVED flag set in the corresponding palPalEntry member of the LOGPALETTE structure.

If the given palette is associated with the active window, the colors in the palette are replaced immediately.

See Also

CreatePalette, GetDeviceCaps, LOGPALETTE, PALETTEENTRY


AnsiLower
AnsiLower  QuickInfo

The AnsiLower function is obsolete.

For compatibility with 16-bit versions of Windows, this function is implemented as a macro that calls the CharLower function, which should be used for new Win32-based applications.


AnsiLowerBuff
AnsiLowerBuff  QuickInfo

The AnsiLowerBuff function is obsolete.

For compatibility with 16-bit versions of Windows, this function is implemented as a macro that calls the CharLowerBuff function, which should be used for new Win32-based applications.


AnsiNext
AnsiNext  QuickInfo

The AnsiNext function is obsolete.

For compatibility with 16-bit versions of Windows, this function is implemented as a macro that calls the CharNext function, which should be used for new Win32-based applications.


AnsiPrev
AnsiPrev  QuickInfo

The AnsiPrev function is obsolete.

For compatibility with 16-bit versions of Windows, this function is implemented as a macro that calls the CharPrev function, which should be used for new Win32-based applications.


AnsiToOem
AnsiToOem  QuickInfo  Overview  Group

The AnsiToOem function is obsolete.

For compatibility with 16-bit versions of Windows, this function is implemented as a macro that calls the CharToOem function, which should be used for new Win32-based applications.


AnsiToOemBuff
AnsiToOemBuff  QuickInfo  Overview  Group

The AnsiToOemBuff function is obsolete.

For compatibility with 16-bit versions of Windows, this function is implemented as a macro that calls the CharToOemBuff function, which should be used for new Win32-based applications.


AnsiUpper
AnsiUpper  QuickInfo

The AnsiUpper function is obsolete.

For compatibility with 16-bit versions of Windows, this function is implemented as a macro that calls the CharUpper function, which should be used for new Win32-based applications.


AnsiUpperBuff
AnsiUpperBuff  QuickInfo

The AnsiUpperBuff function is obsolete.

For compatibility with 16-bit versions of Windows, this function is implemented as a macro that calls the CharUpperBuff function, which should be used for new Win32-based applications.


AnyPopup
AnyPopup  QuickInfo  Overview  Group

The AnyPopup function indicates whether an owned, visible, top-level pop-up, or overlapped window exists on the screen. The function searches the entire Windows screen, not just the calling application's client area.

BOOL AnyPopup(VOID)

Parameters

This function has no parameters.

Return Value

If a pop-up window exists, the return value is TRUE even if the pop-up window is completely covered by other windows. Otherwise, it is FALSE.

Remarks

AnyPopup is a Windows version 1.x function and is retained for compatibility purposes. It is generally not useful.

This function does not detect unowned pop-up windows or windows that do not have the WS_VISIBLE style bit set.

See Also

GetLastActivePopup, ShowOwnedPopups


AppendMenu
AppendMenu  QuickInfo  Overview  Group

The AppendMenu function appends a new item to the end of the specified menu. An application can use this function to specify the content, appearance, and behavior of the menu item.

BOOL AppendMenu(

HMENU hMenu,	// handle of menu
UINT uFlags,	// menu item flags
UINT uIDNewItem,	// menu item identifier or pop-up menu handle
LPCTSTR lpNewItem	// menu item content
);
Parameters

hMenu

Identifies the menu to be changed.

uFlags

Specifies flags to control the appearance and behavior of the new menu item. This parameter can be a combination of the values listed in the following Remarks section.

uIDNewItem

Specifies either the identifier of the new menu item or, if the uFlags parameter is set to MF_POPUP, the handle of the pop-up menu.

lpNewItem

Specifies the content of the new menu item. The interpretation of lpNewItem depends on whether the uFlags parameter includes the MF_BITMAP, MF_OWNERDRAW, or MF_STRING flag, as follows:

Value	Description
MF_BITMAP	Contains a bitmap handle.
MF_OWNERDRAW	Contains a 32-bit value supplied by the application that can be used to maintain additional data related to the menu item. The value is in the itemData member of the structure pointed to by the lparam parameter of the WM_MEASURE or WM_DRAWITEM message sent when the menu is created or its appearance is updated.
MF_STRING	Contains a pointer to a null-terminated string.
Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The application must call the DrawMenuBar function whenever a menu changes, whether or not the menu is in a displayed window.

The following flags must be set in the uFlags parameter:

Value	Description
MF_BITMAP	Uses a bitmap as the item. The lpNewItem parameter contains the handle of the bitmap.
MF_CHECKED	Places a check mark next to the item. If the application provides check mark bitmaps (see SetMenuItemBitmaps), this flag displays the check mark bitmap next to the menu item.
MF_DISABLED	Disables the menu item so that it cannot be selected, but the flag does not gray it.
MF_ENABLED	Enables the menu item so that it can be selected and restores it from its grayed state.
MF_GRAYED	Disables the menu item and grays it so it cannot be selected.
MF_MENUBARBREAK	Functions the same as the MF_MENUBREAK flag except for pop-up menus, where the new column is separated from the old column by a vertical line.
MF_MENUBREAK	Places the item on a new line (for menu bars) or in a new column (for pop-up menus) without separating columns.
MF_OWNERDRAW	Specifies that the item is an owner-drawn item. Before the menu is displayed for the first time, the window that owns the menu receives a WM_MEASUREITEM message to retrieve the width and height of the menu item. The WM_DRAWITEM message is then sent to the window procedure of the owner window whenever the appearance of the menu item must be updated.
MF_POPUP	Specifies that the menu item is a pop-up item; that is, selecting it activates a pop-up menu. The uIDNewItem parameter specifies the handle of the pop-up menu. This flag is used to add a pop-up item to a menu bar or to a pop-up menu.
MF_SEPARATOR	Draws a horizontal dividing line. This flag is only used in a pop-up menu. The line cannot be grayed, disabled, or highlighted. The lpNewItem and uIDNewItem parameters are ignored.
MF_STRING	Specifies that the menu item is a text string; the lpNewItem parameter points to the string.
MF_UNCHECKED	Does not place a check mark next to the item (default). If the application supplies check mark bitmaps (see SetMenuItemBitmaps), this flag displays the unchecked bitmap next to the menu item.
The following list shows groups of flags that cannot be used together:

•	MF_DISABLED, MF_ENABLED, and MF_GRAYED

•	MF_BITMAP, MF_STRING, and MF_OWNERDRAW

•	MF_MENUBARBREAK and MF_MENUBREAK

•	MF_CHECKED and MF_UNCHECKED

See Also

CreateMenu, DeleteMenu, DestroyMenu, DrawMenuBar, InsertMenu, MF_BITMAP, MF_OWNERDRAW, ModifyMenu, RemoveMenu, SetMenuItemBitmaps


Arc
Arc  QuickInfo  Overview  Group

The Arc function draws an elliptical arc.

BOOL Arc(

HDC  hdc,	// handle of device context
int  nLeftRect,	// x-coordinate of bounding rectangle's upper-left corner
int  nTopRect,	// y-coordinate of bounding rectangle's upper-left corner
int  nRightRect,	// x-coordinate of bounding rectangle's lower-right corner
int  nBottomRect,	// y-coordinate of bounding rectangle's lower-right corner
int  nXStartArc,	// first radial ending point
int  nYStartArc,	// first radial ending point
int  nXEndArc,	// second radial ending point
int  nYEndArc	// second radial ending point
);
Parameters

hdc

Identifies the device context where drawing takes place.

nLeftRect

Specifies the logical x-coordinate of the upper-left corner of the bounding rectangle.

Windows 95: The sum of nLeftRect plus nRightRect must be less than 32768.

nTopRect

Specifies the logical y-coordinate of the upper-left corner of the bounding rectangle.

Windows 95: The sum of nTopRect plus nBottomRect must be less than 32768.

nRightRect

Specifies the logical x-coordinate of the lower-right corner of the bounding rectangle.

Windows 95: The sum of nLeftRect plus nRightRect must be less than 32768.

nBottomRect

Specifies the logical y-coordinate of the lower-right corner of the bounding rectangle.

Windows 95: The sum of nTopRect plus nBottomRect must be less than 32768.

nXStartArc

Specifies the logical x-coordinate of the ending point of the radial line defining the starting point of the arc.

nYStartArc

Specifies the logical y-coordinate of the ending point of the radial line defining the starting point of the arc.

nXEndArc

Specifies the logical x-coordinate of the ending point of the radial line defining the ending point of the arc.

nYEndArc

Specifies the logical y-coordinate of the ending point of the radial line defining the ending point of the arc.

Return Value

If the arc is drawn, the return value is TRUE; otherwise, it is FALSE.

Remarks

The points (nLeftRect, nTopRect) and (nRightRect, nBottomRect) specify the bounding rectangle. An ellipse formed by the given bounding rectangle defines the curve of the arc. The arc extends in the current drawing direction from the point where it intersects the radial from the center of the bounding rectangle to the (nXStartArc, nYStartArc) point. The arc ends where it intersects the radial from the center of the bounding rectangle to the (nXEndArc, nYEndArc) point. If the starting point and ending point are the same, a complete ellipse is drawn.

The arc is drawn using the current pen; it is not filled.

The current position is neither used nor updated by Arc.

Windows 95: The drawing direction is always counterclockwise.

Windows NT: Use the GetArcDirection and SetArcDirection functions to get and set the current drawing direction for a device context. The default drawing direction is counterclockwise.

Windows 95 only: The sum of the coordinates of the bounding rectangle cannot exceed 32,767. The sum of nLeftRect and nRightRect or nTopRect and nBottomRect parameters cannot exceed 32,767.

See Also

AngleArc, ArcTo, Chord, Ellipse, GetArcDirection, Pie, SetArcDirection


ArcTo
ArcTo  QuickInfo  Overview  Group

The ArcTo function draws an elliptical arc.

BOOL ArcTo(

HDC  hdc,	// handle of device context
int  nLeftRect,	// x-coordinate of bounding rectangle's upper-left corner
int  nTopRect,	// y-coordinate of bounding rectangle's upper-left corner
int  nRightRect,	// x-coordinate of bounding rectangle's lower-right corner
int  nBottomRect,	// y-coordinate of bounding rectangle's lower-right corner
int  nXRadial1,	// x-coordinate of the first radial ending point
int  nYRadial1,	// y-coordinate of the first radial ending point
int  nXRadial2,	// x-coordinate of the second radial ending point
int  nYRadial2	// y-coordinate of the second radial ending point
);
Parameters

hdc

Identifies the device context where drawing takes place.

nLeftRect

Specifies the logical x-coordinate of the upper-left corner of the bounding rectangle.

nTopRect

Specifies the logical y-coordinate of the upper-left corner of the bounding rectangle.

nRightRect

Specifies the logical x-coordinate of the lower-right corner of the bounding rectangle.

nBottomRect

Specifies the logical y-coordinate of the lower-right corner of the bounding rectangle.

nXRadial1

Specifies the logical x-coordinate of the endpoint of the radial defining the starting point of the arc.

nYRadial1

Specifies the logical y-coordinate of the endpoint of the radial defining the starting point of the arc.

nXRadial2

Specifies the logical x-coordinate of the endpoint of the radial defining the ending point of the arc.

nYRadial2

Specifies the logical y-coordinate of the endpoint of the radial defining the ending point of the arc.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

ArcTo is similar to the Arc function, except that the current position is updated.

The points (nLeftRect, nTopRect) and (nRightRect, nBottomRect) specify the bounding rectangle. An ellipse formed by the given bounding rectangle defines the curve of the arc. The arc extends counterclockwise from the point where it intersects the radial line from the center of the bounding rectangle to the (nXRadial1, nYRadial1) point. The arc ends where it intersects the radial line from the center of the bounding rectangle to the (nXRadial2, nYRadial2) point. If the starting point and ending point are the same, a complete ellipse is drawn.

A line is drawn from the current position to the starting point of the arc. If no error occurs, the current position is set to the ending point of the arc.

The arc is drawn using the current pen; it is not filled.

See Also

AngleArc, Arc, SetArcDirection


AreAllAccessesGranted
AreAllAccessesGranted  QuickInfo  Overview  Group

The AreAllAccessesGranted function checks whether a set of requested access rights has been granted. The access rights are represented as bit flags in a 32-bit access mask.

BOOL AreAllAccessesGranted(

DWORD  GrantedAccess,	// access mask for granted access rights
DWORD  DesiredAccess	// access mask for requested access rights
);
Parameters

GrantedAccess

An access mask that specifies the access rights that have been granted.

DesiredAccess

An access mask that specifies the access rights that have been requested. This mask must have been mapped from generic to specific and standard access rights, usually by calling the MapGenericMask function.

Return Value

If all the requested access rights have been granted, the return value is TRUE; otherwise, it is FALSE.

Remarks

The AreAllAccessesGranted function is commonly used by a server application to check the access rights of a client attempting to gain access to an object. When the bits set in the DesiredAccess parameter match the bits set in the GrantedAccess parameter, all requested rights have been granted.

See Also

AccessCheck, AreAnyAccessesGranted, MapGenericMask


AreAnyAccessesGranted
AreAnyAccessesGranted  QuickInfo  Overview  Group

The AreAnyAccessesGranted function tests whether any of a set of requested access rights has been granted. The access rights are represented as bit flags in a 32-bit access mask.

BOOL AreAnyAccessesGranted(

DWORD  GrantedAccess,	// access mask for granted access rights
DWORD  DesiredAccess	// access mask for access rights requested
);
Parameters

GrantedAccess

Specifies the granted access mask.

DesiredAccess

Specifies the access mask to be requested. This mask must have been mapped from generic to specific and standard access rights, usually by calling the MapGenericMask function.

Return Value

If any of the requested access rights have been granted, the return value is TRUE; otherwise, it is FALSE.

Remarks

The AreAnyAccessesGranted function is often used by a server application to check the access rights of a client attempting to gain access to an object. When any of the bits set in the DesiredAccess parameter match the bits set in the GrantedAccess parameter, at least one of the requested access rights has been granted.

See Also

AccessCheck, AreAllAccessesGranted, MapGenericMask


AreFileApisANSI
AreFileApisANSI  QuickInfo  Overview  Group

The AreFileApisANSI function determines whether a set of Win32 file functions is using the ANSI or OEM character set code page. This function is useful for 8-bit console input and output operations.

BOOL AreFileApisANSI (VOID)

Parameters

This function has no parameters.

Return Value

If the set of Win32 file functions is using the ANSI code page, the return value is TRUE.

If the set of Win32 file functions is using the OEM code page, the return value is FALSE.

Remarks

The SetFileApisToOEM function causes a set of Win32 file functions to use the OEM code page. The SetFileApisToANSI function causes the same set of Win32 file functions to use the ANSI code page. Use the AreFileApisANSI function to determine which code page the set of file functions is currently using. For a discussion of their usage, please refer to the Remarks sections of SetFileApisToOEM and SetFileApisToANSI.

The following is the set of Win32 file functions whose code page is ascertained by the AreFileApisANSI function:

_lopen	GetDriveType	LoadLibrary
CopyFile	GetFileAttributes	LoadLibraryEx
CreateDirectory	GetFullPathName	MoveFile
CreateFile	GetModuleFileName	MoveFileEx
CreateProcess	GetModuleHandle	OpenFile
DeleteFile	GetSystemDirectory	RemoveDirectory
FindFirstFile	GetTempFileName	SearchPath
FindNextFile	GetTempPath	SetCurrentDirectory
GetCurrentDirectory	GetVolumeInformation	SetFileAttributes
GetDiskFreeSpace	GetWindowsDirectory
See Also

SetFileApisToANSI, SetFileApisToOEM


ArrangeIconicWindows
ArrangeIconicWindows  QuickInfo  Overview  Group

The ArrangeIconicWindows function arranges all the minimized (iconic) child windows of the specified parent window.

UINT ArrangeIconicWindows(

HWND  hWnd	// handle of parent window
);
Parameters

hWnd

Identifies the parent window.

Return Value

If the function succeeds, the return value is the height of one row of icons.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

An application that maintains its own minimized child windows can use ArrangeIconicWindows to arrange icons in a parent window. This function can also arrange icons on the desktop. To retrieve the window handle of the desktop window, use the GetDesktopWindow function.

An application sends the WM_MDIICONARRANGE message to the multiple document interface (MDI) client window to prompt the client window to arrange its minimized MDI child windows.

See Also

CloseWindow, GetDesktopWindow


AttachThreadInput
AttachThreadInput  QuickInfo  Overview  Group

The AttachThreadInput function attaches the input processing mechanism of one thread to that of another thread.

BOOL AttachThreadInput(

DWORD  idAttach,	// thread to attach
DWORD  idAttachTo,	// thread to attach to
BOOL  fAttach	// attach or detach
);
Parameters

idAttach

Specifies the identifier of the thread to be attached to another thread.

idAttachTo

Specifies the identifier of the thread to be attached to.

fAttach

Specifies whether to attach or detach the threads. If this parameter is TRUE, the two threads are attached. If the parameter is FALSE, the threads are detached.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Normally, windows created in different threads process input independently of each other. That is, they have their own input states (focus, active, capture windows, key state, queue status, and so on), and they are not synchronized with the input processing of other threads. By using this function, a thread can attach its input processing to another thread. This also allows a thread to share its input states, so they can call the SetFocus function to set the keyboard focus to a window of a different thread; this also allows threads to get key state information. These capabilities are not normally possible.

AttachThreadInput fails if either of the specified threads does not have a message queue. The system creates a thread's message queue when the thread makes its first call to one of the Win32 USER or GDI functions.

Please note that key state, which can be ascertained by calls to the GetKeyState or GetKeyboardState function, is reset after a call to AttachThreadInput.

See Also

GetCurrentThreadId, GetKeyState, GetKeyboardState, GetWindowThreadProcessId, SetFocus


BackupEventLog
BackupEventLog  QuickInfo  Overview  Group

The BackupEventLog function saves the specified event log to a backup file. The function does not clear the event log.

BOOL BackupEventLog(

HANDLE  hEventLog,	// handle to event log
LPCTSTR  lpBackupFileName	// name of backup file
);
Parameters

hEventLog

Identifies the open event log. This handle is returned by the OpenEventLog or OpenBackupEventLog function.

lpBackupFileName

Points to a null-terminated string that names the backup file. The backup filename may contain a server name to save the backup file on a remote server.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

If the backup filename specifies a remote server, the event log handle must identify a log on the local computer. You cannot back up an event logfile from a remote server to a file on a remote server (even if the backup file and the original log are on the same server).

See Also

OpenBackupEventLog, OpenEventLog


BackupRead
BackupRead  QuickInfo  Overview  Group

The BackupRead function reads data associated with a specified file or directory into a buffer. You use this function to back up a file or directory.

BOOL BackupRead(

HANDLE  hFile,	// handle to file or directory
LPBYTE  lpBuffer,	// pointer to buffer to read to
DWORD  nNumberOfBytesToRead,	// number of bytes to read
LPDWORD  lpNumberOfBytesRead,	// pointer to variable to receive number of bytes read
BOOL  bAbort,	// termination type
BOOL  bProcessSecurity,	// process security flag
LPVOID  *lpContext	// pointer to pointer to internal context information
);
Parameters

hFile

Handle to the file or directory being backed up. The function reads data associated with this file. You obtain this handle by calling the CreateFile function.

The BackupRead function fails if CreateFile was called with the flag FILE_FLAG_NO_BUFFERING. In this case, the GetLastError function returns the value ERROR_INVALID_PARAMETER.

lpBuffer

Pointer to a buffer that the function writes data to.

nNumberOfBytesToRead

Specifies the length of the buffer.  The buffer size must be greater than the size of a WIN32_STREAM_ID structure.

lpNumberOfBytesRead

Pointer to a variable that, when the function returns, contains the number of bytes read.

If the function return value is TRUE, and the variable pointed to by lpNumberOfBytesRead is zero, then all the data associated with the file handle has been read.

bAbort

Indicates whether BackupRead terminated abnormally. If this value is TRUE, the operation terminates abnormally and all buffers are deallocated.

bProcessSecurity

Indicates whether the function will restore the access-control list (ACL) data for the file or directory.

If bProcessSecurity is TRUE, the ACL data will be backed up.

lpContext

Pointer to a variable that receives and holds a pointer to an internal data structure used by BackupRead to maintain context information during a backup operation.

You must set the variable pointed to by lpContext to NULL before the first call to BackupRead for the specified file or directory. The function allocates memory for the data structure, and then sets the variable to point to that structure. You must not change lpContext  or the variable that it points to between calls to BackupRead.

To release the memory used by the data structure, call BackupRead with the bAbort parameter set to TRUE when the backup operation is complete.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE, indicating that an I/O error occurred. To get extended error information, call GetLastError.

Remarks

BackupRead processes all of the data pertaining to an opened object as a series of discrete byte streams. Each stream is preceded by a 32-bit aligned WIN32_STREAM_ID structure.

Streams must be processed in the same order in which they were written to the tape. This ordering enables applications to compare the data backed up against the data on the source device. The data returned by BackupRead is to be used only as input to the BackupWrite function. This data is returned as one large data stream divided into substreams. The substreams are separated by WIN32_STREAM_ID headers.

If an error occurs while BackupRead is reading, the calling process can skip the bad data by calling the BackupSeek function.

See Also

BackupWrite, BackupSeek, WIN32_STREAM_ID


BackupSeek
BackupSeek  QuickInfo  Overview  Group

The BackupSeek function seeks forward in a data stream initially accessed by using the BackupRead or BackupWrite function.

BOOL BackupSeek(

HANDLE  hFile,	// handle of open file
DWORD  dwLowBytesToSeek,	// low-order 32 bits of number of bytes
DWORD  dwHighBytesToSeek,	// high-order 32 bits of number of bytes
LPDWORD  lpdwLowByteSeeked,	// address of number of bytes function seeks
LPDWORD  lpdwHighByteSeeked,	// address of number of bytes function seeks
LPVOID *  lpContext	//address of internal context information
);
Parameters

hFile

Identifies the file or directory being backed up. This handle is created by using the CreateFile function.

dwLowBytesToSeek

Specifies the low-order 32 bits of the number of bytes to seek.

dwHighBytesToSeek

Specifies the high-order 32 bits of the number of bytes to seek.

lpdwLowByteSeeked

Points to a doubleword that, when the function returns, contains the low-order 32 bits of the number of bytes the function actually seeks.

lpdwHighByteSeeked

Points to a doubleword that, when the function returns, contains the high-order 32 bits of the number of bytes the function actually seeks.

lpContext

Points to an internal data structure used by the function. This structure must be the same structure that was initialized by the BackupRead function. An application must not touch the contents of this structure.

Return Value

If the function could seek the requested amount, the function returns TRUE. Otherwise, it is FALSE.

Remarks

Applications use BackUpSeek to skip portions of a data stream that cause errors. This function does not seek across stream headers. If an application attempts to seek past the end of a substream, the function fails, the lpdwLowByteSeeked and lpdwHighByteSeeked parameters indicate the actual number of bytes the function seeks, and the file position is placed at the start of the next stream header.

See Also

BackupRead, BackupWrite, CreateFile


BackupWrite
BackupWrite  QuickInfo  Overview  Group

The BackupWrite function writes a stream of data from a buffer to a specified file or directory. The data must be divided into substreams separated by WIN32_STREAM_ID structures. You use this function to restore a file or directory that has been backed up.

BOOL BackupWrite(

HANDLE  hFile,	// handle to file or directory
LPBYTE  lpBuffer,	// pointer to buffer containing data to write
DWORD  nNumberOfBytesToWrite,	// number of bytes to write
LPDWORD  lpNumberOfBytesWritten,	// pointer to variable to receive number of bytes written
BOOL  bAbort,	// termination type
BOOL  bProcessSecurity,	// process security
LPVOID  *lpContext	// pointer to pointer to internal context information
);
Parameters

hFile

Handle to the file or directory being restored. The function writes data to this file. You obtain this handle by calling the CreateFile function.

The BackupWrite function fails if CreateFile was called with the flag FILE_FLAG_NO_BUFFERING. In this case, the GetLastError function returns the value ERROR_INVALID_PARAMETER.

lpBuffer

Pointer to a buffer that the function writes data from.

nNumberOfBytesToWrite

Specifies the length of the buffer.  The buffer size must be greater than the size of a WIN32_STREAM_ID structure.

lpNumberOfBytesWritten

Pointer to a variable that, when the function returns, contains the number of bytes written.

bAbort

Specifies whether BackupWrite terminated abnormally. If this value is TRUE, the operation terminated abnormally and all buffers were deallocated.

bProcessSecurity

Specifies whether the function will restore the access-control list (ACL) data for the file or directory.

If bProcessSecurity is TRUE, you need to have specified  WRITE_OWNER and WRITE_DAC access when opening the file or directory handle. If the handle does not have those access rights, the operating system denies access to the ACL data, and ACL data restoration will not occur.

lpContext

Pointer to a variable that receives and holds a pointer to an internal data structure used by BackupWrite to maintain context information during a restore operation.

You must set the variable pointed to by lpContext to NULL before the first call to BackupWrite for the specified file or directory. The function allocates memory for the data structure, and then sets the variable to point to that structure. You must not change lpContext or the variable that it points to between calls to BackupWrite.

To release the memory used by the data structure, call BackupWrite with the bAbort parameter set to TRUE when the restore operation is complete.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE, indicating that an I/O error occurred. To get extended error information, call GetLastError.

Remarks

The BACKUP_LINK stream type lets you restore files with hard links.

Data obtained by the BackupRead function should only be used as input to the BackupWrite function.

See Also

BackupRead, BackupSeek, CreateFile, WIN32_STREAM_ID


Beep
Beep  QuickInfo  Overview  Group

The Beep function generates simple tones on the speaker.

BOOL Beep(

DWORD  dwFreq,	// sound frequency, in hertz
DWORD  dwDuration	// sound duration, in milliseconds
);
Parameters

dwFreq

Windows NT:

Specifies the frequency, in hertz, of the sound. This parameter must be in the range 37 through 32,767 (0x25 through 0x7FFF).

Windows 95:

The parameter is ignored.

dwDuration

Windows NT:

Specifies the duration, in milliseconds, of the sound.

One value has a special meaning: If dwDuration is  − 1, the function operates asynchronously and produces sound until called again.

Windows 95:

The parameter is ignored.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Windows NT:

The Beep function is synchronous in all but one case; the function does not generally return control to its caller until the sound finishes. The exception to this occurs when dwDuration has the value  − 1. In that case, Beep is asynchronous, returning control immediately to its caller while the sound continues playing. The sound continues until the next call to Beep.

Windows 95:

The Beep function ignores the dwFreq and dwDuration parameters. On computers with a sound card, the function plays the default sound event. On computers without a sound card, the function plays the standard system beep.


BeginDeferWindowPos
BeginDeferWindowPos  QuickInfo  Overview  Group

The BeginDeferWindowPos function allocates memory for a multiple-window − position structure and returns the handle of the structure.

HDWP BeginDeferWindowPos(

int  nNumWindows	// number of windows
);
Parameters

nNumWindows

Specifies the initial number of windows for which to store position information. The DeferWindowPos function increases the size of the structure, if necessary.

Return Value

If the function succeeds, the return value identifies the multiple-window − position structure. If insufficient system resources are available to allocate the structure, the return value is NULL.

Remarks

The multiple-window − position structure is an internal structure; an application cannot access it directly.

DeferWindowPos fills the multiple-window − position structure with information about the target position for one or more windows about to be moved. The EndDeferWindowPos function accepts the handle of this structure and repositions the windows by using the information stored in the structure.

If any of the windows in the multiple-window − position structure have the SWP_HIDEWINDOW or SWP_SHOWWINDOW flag set, none of the windows are repositioned.

If Windows must increase the size of the multiple-window − position structure beyond the initial size specified by the nNumWindows parameter but cannot allocate enough memory to do so, Windows fails the entire window positioning sequence (BeginDeferWindowPos, DeferWindowPos, and EndDeferWindowPos). By specifying the maximum size needed, an application can detect and process failure early in the process.

See Also

DeferWindowPos, EndDeferWindowPos, SetWindowPos


BeginPaint
BeginPaint  QuickInfo  Overview  Group

The BeginPaint function prepares the specified window for painting and fills a PAINTSTRUCT structure with information about the painting.

HDC BeginPaint(

HWND  hwnd,	// handle of window
LPPAINTSTRUCT  lpPaint	// address of structure for paint information
);
Parameters

hwnd

Identifies the window to be repainted.

lpPaint

Points to the PAINTSTRUCT structure that will receive painting information.

Return Value

If the function succeeds, the return value is the handle of a display device context (DC) for the given window.

If the function fails, the return value is NULL, indicating that no display DC is available.

Remarks

BeginPaint automatically sets the clipping region of the DC to exclude any area outside the update region. The update region is set by the InvalidateRect or InvalidateRgn function and by the system after sizing, moving, creating, scrolling, or any other operation that affects the client area. If the update region is marked for erasing, BeginPaint sends a WM_ERASEBKGND message to the window.

An application should not call BeginPaint except in response to a WM_PAINT message. Each call to BeginPaint must have a corresponding call to the EndPaint function.

If the caret is in the area to be painted, BeginPaint automatically hides the caret to prevent it from being erased.

If the window's class has a background brush, BeginPaint uses that brush to erase the background of the update region before returning.

See Also

EndPaint, InvalidateRect, InvalidateRgn, PAINTSTRUCT, ValidateRect, ValidateRgn


BeginPath
BeginPath  QuickInfo  Overview  Group

The BeginPath function opens a path bracket in the specified device context (DC).

BOOL BeginPath(

HDC  hdc	// handle of device context
);
Parameters

hdc

Identifies the DC.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

After a path bracket is open, an application can begin calling GDI drawing functions to define the points that lie in the path. An application can close an open path bracket by calling the EndPath function.

When an application calls BeginPath for a DC, any previous paths are discarded from that DC.

Windows NT:

The following drawing functions define points in a path:

AngleArc	LineTo	Polyline
Arc	MoveToEx	PolylineTo
ArcTo	Pie	PolyPolygon
Chord	PolyBezier	PolyPolyline
CloseFigure	PolyBezierTo	Rectangle
Ellipse	PolyDraw	RoundRect
ExtTextOut	Polygon	TextOut
Windows 95:

When constructing a path, only the CloseFigure, ExtTextOut, LineTo, MoveToEx, PolyBezier, PolyBezierTo, Polygon, Polyline, PolylineTo, PolyPolygon, PolyPolyline, and TextOut functions are recorded.

See Also

EndPath, FillPath, PathToRegion, SelectClipPath, StrokeAndFillPath, StrokePath, WidenPath


BeginUpdateResource
BeginUpdateResource  QuickInfo  Overview  Group

The BeginUpdateResource function returns a handle that can be used by the UpdateResource function to add, delete, or replace resources in an executable file.

HANDLE BeginUpdateResource(

LPCTSTR  pFileName,	// address of file in which to update resources
BOOL  bDeleteExistingResources	// deletion option
);
Parameters

pFileName

Points to a null-terminated string that specifies a Windows executable file in which to update resources. An application must be able to obtain write access to this file; it cannot be currently executing. If pFileName does not specify a full path, Windows searches for the file in the current directory.

bDeleteExistingResources

Specifies whether to delete the pFileName parameter's existing resources. If this parameter is TRUE, existing resources are deleted and the updated executable file includes only resources added with the UpdateResource function. If this parameter is FALSE, the updated executable file includes existing resources unless they are explicitly deleted or replaced by using UpdateResource.

Return Value

If the function succeeds, the return value is a handle that can be used by the UpdateResource and EndUpdateResource functions. The return value is NULL if the specified file is not an executable file, the executable file is already loaded, the file does not exist, or the file cannot be opened for writing. To get extended error information, call GetLastError.

See Also

EndUpdateResource, UpdateResource


bind
bind  QuickInfo

The Windows Sockets bind function associates a local address with a socket.

int bind (

SOCKET s,
const struct sockaddr FAR * addr,
int namelen
);
Parameters

s

A descriptor identifying an unbound socket.

addr

The address to assign to the socket. The sockaddr structure is defined as follows:

    struct sockaddr {

        u_short    sa_family;

        char       sa_data[14];

    };

namelen

The length of the addr.

Return Value

If no error occurs, bind returns zero. Otherwise, it returns SOCKET_ERROR, and a specific error code may be retrieved by calling WSAGetLastError.

Error Codes

WSANOTINITIALISED	A successful WSAStartup must occur before using this function.
WSAENETDOWN	The Windows Sockets implementation has detected that the network subsystem has failed.
WSAEADDRINUSE	The specified address is already in use. (See the SO_REUSEADDR socket option under setsockopt.)
WSAEFAULT	The namelen argument is too small (less than the size of a struct sockaddr).
WSAEINPROGRESS	A blocking Windows Sockets call is in progress.
WSAEAFNOSUPPORT	The specified address family is not supported by this protocol.
WSAEINVAL	The socket is already bound to an address.
WSAENOBUFS	Not enough buffers available, too many connections.
WSAENOTSOCK	The descriptor is not a socket.
Remarks

This function is used on an unconnected datagram or stream socket, before subsequent calls to the connect or listen functions. When a socket is created with socket, it exists in a name space (address family), but it has no name assigned. The bind function establishes the local association (host address/port number) of the socket by assigning a local name to an unnamed socket.

In the Internet address family, a name consists of several components. For SOCK_DGRAM and SOCK_STREAM, the name consists of three parts: a host address, the protocol number (set implicitly to UDP or TCP, respectively), and a port number which identifies the application. If an application does not care what address is assigned to it, it may specify an Internet address equal to INADDR_ANY, a port equal to 0, or both. If the Internet address is equal to INADDR_ANY, any appropriate network interface will be used; this simplifies application programming in the presence of multi-homed hosts. If the port is specified as 0, the Windows Sockets implementation will assign a unique port to the application with a value between 1024 and 5000. The application may use getsockname after bind to learn the address that has been assigned to it, but note that getsockname will not necessarily fill in the Internet address until the socket is connected, since several Internet addresses may be valid if the host is multi-homed.

If an application needs to bind to an arbitrary port outside of the range 1024 to 5000, code similar to the following can be used:

SOCKADDR_IN sin;

SOCKET s;

u_short alport = IPPORT_RESERVED;

sin.sin_family = AF_INET;

sin.sin_addr.s_addr = 0;

for (;;) {

    sin.sin_port = htons(alport);

    if (bind(s, (LPSOCKADDR)&sin, sizeof (sin)) == 0) {

        /* it worked */

    }

    if ( GetLastError != WSAEADDRINUSE) {

        /* fail */

    }

    alport--;

    if (alport == IPPORT_RESERVED/2 ) {

        /* fail--all unassigned reserved ports are */

        /* in use. */

    }

}

See Also

connect, listen, getsockname, setsockopt, socket, WSACancelBlockingCall, WSAStartup


BitBlt
BitBlt  QuickInfo  Overview  Group

The BitBlt function performs a bit-block transfer of the color data corresponding to a rectangle of pixels from the specified source device context into a destination device context.

BOOL BitBlt(

HDC  hdcDest,	// handle of destination device context
int  nXDest,	// x-coordinate of destination rectangle's upper-left corner
int  nYDest,	// x-coordinate of destination rectangle's upper-left corner
int  nWidth,	// width of destination rectangle
int  nHeight,	// height of destination rectangle
HDC  hdcSrc,	// handle of source device context
int  nXSrc,	// x-coordinate of source rectangle's upper-left corner
int  nYSrc,	// y-coordinate of source rectangle's upper-left corner
DWORD  dwRop	// raster operation code
);
Parameters

hdcDest

Identifies the destination device context.

nXDest

Specifies the logical x-coordinate of the upper-left corner of the destination rectangle.

nYDest

Specifies the logical y-coordinate of the upper-left corner of the destination rectangle.

nWidth

Specifies the logical width of the source and destination rectangles.

nHeight

Specifies the logical height of the source and the destination rectangles.

hdcSrc

Identifies the source device context.

nXSrc

Specifies the logical x-coordinate of the upper-left corner of the source rectangle.

nYSrc

Specifies the logical y-coordinate of the upper-left corner of the source rectangle.

dwRop

Specifies a raster-operation code. These codes define how the color data for the source rectangle is to be combined with the color data for the destination rectangle to achieve the final color.

The following list shows some common raster operation codes:

Value	Description
BLACKNESS	Fills the destination rectangle using the color associated with index 0 in the physical palette. (This color is black for the default physical palette.)
DSTINVERT	Inverts the destination rectangle.
MERGECOPY	Merges the colors of the source rectangle with the specified pattern by using the Boolean AND operator.
MERGEPAINT	Merges the colors of the inverted source rectangle with the colors of the destination rectangle by using the Boolean OR operator.
NOTSRCCOPY	Copies the inverted source rectangle to the destination.
NOTSRCERASE	Combines the colors of the source and destination rectangles by using the Boolean OR operator and then inverts the resultant color.
PATCOPY	Copies the specified pattern into the destination bitmap.
PATINVERT	Combines the colors of the specified pattern with the colors of the destination rectangle by using the Boolean XOR operator.
PATPAINT	Combines the colors of the pattern with the colors of the inverted source rectangle by using the Boolean OR operator. The result of this operation is combined with the colors of the destination rectangle by using the Boolean OR operator.
SRCAND	Combines the colors of the source and destination rectangles by using the Boolean AND operator.
SRCCOPY	Copies the source rectangle directly to the destination rectangle.
SRCERASE	Combines the inverted colors of the destination rectangle with the colors of the source rectangle by using the Boolean AND operator.
SRCINVERT	Combines the colors of the source and destination rectangles by using the Boolean XOR operator.
SRCPAINT	Combines the colors of the source and destination rectangles by using the Boolean OR operator.
WHITENESS	Fills the destination rectangle using the color associated with index 1 in the physical palette. (This color is white for the default physical palette.)
Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

If a rotation or shear transformation is in effect in the source device context, BitBlt returns an error. If other transformations exist in the source device context (and a matching transformation is not in effect in the destination device context), the rectangle in the destination device context is stretched, compressed, or rotated as necessary.

If the color formats of the source and destination device contexts do not match, the BitBlt function converts the source color format to match the destination format.

When an enhanced metafile is being recorded, an error occurs if the source device context identifies an enhanced-metafile device context.

Not all devices support the BitBlt function. For more information, see the RC_BITBLT raster capability entry in GetDeviceCaps.

BitBlt returns an error if the source and destination device contexts represent different devices.

See Also

GetDeviceCaps, MaskBlt, PlgBlt, StretchBlt


BringWindowToTop
BringWindowToTop  QuickInfo  Overview  Group

The BringWindowToTop function brings the specified window to the top of the Z order. If the window is a top-level window, it is activated. If the window is a child window, the top-level parent window associated with the child window is activated.

BOOL BringWindowToTop(

HWND  hWnd	// handle of window
);
Parameters

hWnd

Identifies the window to bring to the top of the Z order.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Use BringWindowToTop to uncover any window that is partially or completely obscured by other windows.

Calling this function is similar to calling the SetWindowPos function to change a window's position in the Z order. BringWindowToTop does not make a window a top-level window.

If an application is not in the foreground and wants to be in the foreground, it should call the SetForegroundWindow function.

See Also

SetWindowPos, SetActiveWindow, SetForegroundWindow


BroadcastSystemMessage [New - Windows 95]
BroadcastSystemMessage  QuickInfo  Overview  Group

[New - Windows 95]

The BroadcastSystemMessage function sends a message to the given recipients. The recipients can be applications, installable drivers, Windows-based network drivers, system-level device drivers, or any combination of these system components.

long BroadcastSystemMessage(

DWORD  dwFlags,
LPDWORD  lpdwRecipients,
UINT  uiMessage,
WPARAM  wParam,
LPARAM  lParam
);
Parameters

dwFlags

Option flags. Can be a combination of the following values:

Value	Meaning
BSF_FLUSHDISK	Flush the disk after each recipient processes the message.
BSF_FORCEIFHUNG	Wait for the time-out period to elapse before returning, if a recipient appears to be in a hung state.
BSF_IGNORECURRENTTASK	Do not send the message to windows that belong to the current task. This prevents an application from receiving its own message.
BSF_LPARAMPOINTER	The lParam parameter is the address of a buffer.
BSF_NOHANG	Return without waiting for the time-out period to elapse if a recipient appears to be in a hung state.
BSF_POSTMESSAGE	Post the message. Do not use in combination with BSF_LPARAMPOINTER or BSF_QUERY.
BSF_QUERY	Send the message to one recipient at a time, sending to a subsequent recipient only if the current recipient returns TRUE.
lpdwRecipients

Address of a 32-bit variable that contains and receives information about the recipients of the message. The variable can be a combination of the following values:

Value	Meaning
BSM_ALLCOMPONENTS	Broadcast to all system components.
BSM_APPLICATIONS	Broadcast to applications.
BSM_INSTALLABLEDRIVERS	Broadcast to installable drivers.
BSM_NETDRIVER	Broadcast to Windows-based network drivers.
BSM_VXDS	Broadcast to all system-level device drivers.
When the function returns, this variable receives a combination of these values identifying which recipients actually received the message.

If this parameter is NULL, the function broadcasts to all components.

uiMessage

Identifier of the system message.

wParam

32-bit message-specific value.

lParam

32-bit message-specific value. If the lpdwRecipients parameter specifies the BSF_LPARAMPOINTER value, the lParam parameter must be the address of a buffer, and the first 16-bit value in the buffer must specify the total size of the buffer, in bytes.

Return Value

If the function succeeds, the return value is a positive value.

If the function is unable to broadcast the message, the return value is −1.

If the dwFlags parameter is BSF_QUERY and at least one recipient returned FALSE to the corresponding message, the return value is zero.

Remarks

If BSF_QUERY is not given, the function sends the given message to all requested recipients, ignoring values returned by those recipients.

If BSF_LPARAMPOINTER is given, the function may modify the address given by the lParam parameter to make the buffer available to requested recipients. It is recommended that the buffer itself contain no addresses, because these addresses will not be modified and may not be accessible to all requested recipients.


BrowseCallbackProc
BrowseCallbackProc  QuickInfo

Specifies an application-defined callback function used with the SHBrowseForFolder function. The browse dialog box calls this function to notify it about events. The BFFCALLBACK type defines a pointer to this callback function.

int BrowseCallbackProc(

HWND  hwnd,
UINT  uMsg,
LPARAM  lParam,
LPARAM  lpData
);
Parameters

hwnd

Handle of the browse dialog box. The callback function can send the following messages to this window:

BFFM_ENABLEOK	Enables the OK button if the wParam parameter is nonzero or disables it if wParam is zero.
BFFM_SETSELECTION	Selects the specified folder. The lParam parameter is the PIDL of the folder to select if wParam is FALSE, or it is the path of the folder otherwise.
BFFM_SETSTATUSTEXT	Sets the status text to the null-terminated string specified by the lParam parameter.
uMsg

Value identifying the event. This parameter can be one of the following values:

BFFM_INITIALIZED	The browse dialog box has finished initializing. lpData is NULL.
BFFM_SELCHANGED	The selection has changed. lpData is a pointer to the item identifier list for the newly selected folder.
lParam

Message-specific value. For more information, see the description of uMsg.

lpData

Application-defined value that was specified in the lParam member of the BROWSEINFO structure.

Return Value

Returns zero.

See Also

BROWSEINFO


BuildCommDCB
BuildCommDCB  QuickInfo  Overview  Group

The BuildCommDCB function fills a specified DCB structure with values specified in a device-control string. The device-control string uses the syntax of the mode command.

BOOL BuildCommDCB(

LPCTSTR  lpDef,	// pointer to device-control string
LPDCB  lpDCB	// pointer to device-control block
);
Parameters

lpDef

Pointer to a null-terminated string that specifies device-control information. The string must have the same form as the Windows NT or MS-DOS mode command's command-line arguments. For example, the following string specifies a baud rate of 1200, no parity, 8 data bits, and 1 stop bit:

baud=1200 parity=N data=8 stop=1

The device name is ignored if it is included in the string, but it must specify a valid device, as follows:

COM1: baud=1200 parity=N data=8 stop=1

Refer to the Windows NT or MS-DOS end-user documentation for further information on mode command syntax.

lpDCB

Pointer to a DCB structure to be filled in.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The BuildCommDCB function adjusts only those members of the DCB structure that are specifically affected by the lpDef parameter, with the following exceptions:

•	If the specified baud rate is 110, the function sets the stop bits to 2 to remain compatible with the Windows NT or MS-DOS mode command.

•	By default, BuildCommDCB disables XON/XOFF and hardware flow control. To enable flow control, you must explicitly set the appropriate members of the DCB structure.

The BuildCommDCB function only fills in the members of the DCB structure. To apply these settings to a serial port, use the SetCommState function.

There are older and newer forms of the mode command syntax. The BuildCommDCB function supports both forms. However, you cannot mix the two forms together.

The newer form of the mode command syntax lets you explicitly set the values of the flow control members of the DCB structure. If you use an older form of the mode syntax, the BuildCommDCB function sets the flow control members of the DCB structure, as follows:

•	For a string such as 96,n,8,1 or any other older-form mode string that doesn't end with an x or a p:

fInX, fOutX,fOutXDsrFlow,and fOutXCtsFlow are all set to FALSE

fDtrControl is set to DTR_CONTROL_ENABLE

fRtsControl is set to RTS_CONTROL_ENABLE

•	For a string such as 96,n,8,1,x or any other older-form mode string that finishes with an x:

fInX, fOutX are both set to TRUE

fOutXDsrFlow,fOutXCtsFlow are both set to FALSE.

fDtrControl is set to DTR_CONTROL_ENABLE

fRtsControl is set to RTS_CONTROL_ENABLE

•	For a string such as 96,n,8,1,p or any other older-form mode string that finishes with a p:

fInX, fOutX are both set to FALSE

fOutXDsrFlow,fOutXCtsFlow are both set to TRUE.

fDtrControl is set to DTR_CONTROL_HANDSHAKE

fRtsControl is set to RTS_CONTROL_HANDSHAKE

See Also

DCB, SetCommState


BuildCommDCBAndTimeouts
BuildCommDCBAndTimeouts  QuickInfo  Overview  Group

The BuildCommDCBAndTimeouts function translates a device-definition string into appropriate device-control block codes and then places these codes into a device control block. The function can also set up time-out values, including the possibility of no time-outs, for a device; the function's behavior in this regard varies based on the contents of the device-definition string.

BOOL BuildCommDCBAndTimeouts(

LPCTSTR  lpDef,	// address of the device-control string
LPDCB  lpDCB,	// address of the device-control block
LPCOMMTIMEOUTS  lpCommTimeouts	// address of comm. time-out structure
);
Parameters

lpDef

Points to a null-terminated string that specifies device-control information for the device. The function takes this string, parses it, and then sets appropriate values in the DCB structure pointed to by lpDCB.

lpDCB

Points to a DCB structure that the function fills with information from the device-control information string pointed to by lpDef. This DCB structure defines the control settings for a communications device.

lpCommTimeouts

Points to a COMMTIMEOUTS structure that the function can use to set device time-out values.

The BuildCommDcbAndTimeouts function modifies its time-out setting behavior based on the presence or absence of a "TO=xxx" substring in the string specified by lpDef:

•	If that string contains the substring "TO=ON", the function sets up total read and write time-out values for the device based on the time-out structure pointed to by lpCommTimeouts.

•	If that string contains the substring "TO=OFF", the function sets up the device with no time-outs.

•	If that string contains neither of the aforementioned "TO=xxx" substrings, the function ignores the time-out structure pointed to by lpCommTimeouts. The time-out structure will not be accessed.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

BuildCommDCB, COMMTIMEOUTS, DCB, GetCommTimeouts, SetCommTimeouts


CallMsgFilter
CallMsgFilter  QuickInfo  Overview  Group

The CallMsgFilter function passes the specified message and hook code to the hook procedures associated with the WH_SYSMSGFILTER and zhooks. A WH_SYSMSGFILTER or WH_MSGFILTER hook procedure is an application-defined callback function that examines and, optionally, modifies messages for a dialog box, message box, menu, or scroll bar.

BOOL CallMsgFilter(

LPMSG  lpMsg,	// address of structure with message data
int  nCode	// hook code
);
Parameters

lpMsg

Points to an MSG structure that contains the message to be passed to the hook procedures.

nCode

Specifies an application-defined code used by the hook procedure to determine how to process the message. The code must not have the same value as system-defined hook codes (MSGF_ and HC_) associated with the WH_SYSMSGFILTER and WH_MSGFILTER hooks.

Return Value

If the application should process the message further, the return value is zero; otherwise, it is nonzero.

Remarks

Windows calls CallMsgFilter to enable applications to examine and control the flow of messages during internal processing of dialog boxes, message boxes, menus, and scroll bars, or when the user activates a different window by pressing the ALT+TAB key combination.

An application installs a hook procedure by using the SetWindowsHookEx function.

See Also

MessageProc, MSG, SetWindowsHookEx, SysMsgProc


CallNamedPipe
CallNamedPipe  QuickInfo  Overview  Group

The CallNamedPipe function connects to a message-type pipe (and waits if an instance of the pipe is not available), writes to and reads from the pipe, and then closes the pipe.

BOOL CallNamedPipe(

LPCTSTR  lpNamedPipeName,	// address of pipe name
LPVOID  lpInBuffer,	// address of write buffer
DWORD  nInBufferSize,	// size, in bytes, of write buffer
LPVOID  lpOutBuffer,	// address of read buffer
DWORD  nOutBufferSize,	// size, in bytes, of read buffer
LPDWORD  lpBytesRead,	// address of number of bytes read
DWORD  nTimeOut	// time-out time, in milliseconds
);
Parameters

lpNamedPipeName

Points to a null-terminated string specifying the pipe name.

lpInBuffer

Points to the buffer containing the data written to the pipe.

nInBufferSize

Specifies the size, in bytes, of the write buffer.

lpOutBuffer

Points to the buffer that receives the data read from the pipe.

nOutBufferSize

Specifies the size, in bytes, of the read buffer.

lpBytesRead

Points to a 32-bit variable that receives the number of bytes read from the pipe.

nTimeOut

Specifies the number of milliseconds to wait for the named pipe to be available. In addition to numeric values, the following special values can be specified:

Value	Meaning
NMPWAIT_NOWAIT	Does not wait for the named pipe. If the named pipe is not available, the function returns an error.
NMPWAIT_WAIT_FOREVER	Waits indefinitely.
NMPWAIT_USE_DEFAULT_WAIT	Uses the default time-out specified in a call to the CreateNamedPipe function.
Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Calling CallNamedPipe is equivalent to calling the CreateFile (or WaitNamedPipe, if CreateFile cannot open the pipe immediately), TransactNamedPipe, and CloseHandle functions. CreateFile is called with an access flag of GENERIC_READ | GENERIC_WRITE, an inherit handle flag of FALSE, and a share mode of zero (indicating no sharing of this pipe instance).

If the message written to the pipe by the server process is longer than nOutBufferSize, CallNamedPipe returns FALSE, and GetLastError returns ERROR_MORE_DATA. The remainder of the message is discarded, because CallNamedPipe closes the handle to the pipe before returning.

CallNamedPipe fails if the pipe is a byte-type pipe.

See Also

CloseHandle, CreateFile, CreateNamedPipe, TransactNamedPipe, WaitNamedPipe


CallNextHookEx
CallNextHookEx  QuickInfo  Overview  Group

The CallNextHookEx function passes the hook information to the next hook procedure in the current hook chain. This function supersedes the DefHookProc function.

LRESULT CallNextHookEx(

HHOOK  hhk,	// handle of current hook
int  nCode,	// hook code passed to hook procedure
WPARAM  wParam,	// value passed to hook procedure
LPARAM  lParam	// value passed to hook procedure
);
Parameters

hhk

Identifies the current hook. An application receives this handle as a result of a previous call to the SetWindowsHookEx function.

nCode

Specifies the hook code passed to the current hook procedure. The next hook procedure uses this code to determine how to process the hook information.

wParam

Specifies the wParam value passed to the current hook procedure. The meaning of this parameter depends on the type of hook associated with the current hook chain.

lParam

Specifies the lParam value passed to the current hook procedure. The meaning of this parameter depends on the type of hook associated with the current hook chain.

Return Value

If the function succeeds, the return value is the value returned by the next hook procedure in the chain. The current hook procedure must also return this value. The meaning of the return value depends on the hook type. For more information, see the descriptions of the individual hook procedures.

Remarks

Hook procedures are installed in chains for particular hook types. CallNextHookEx calls the next hook in the chain.

Calling CallNextHookEx is optional. A hook procedure can call this function either before or after processing the hook information. If a hook procedure does not call CallNextHookEx, Windows does not call the hook procedures installed before the current hook procedure was installed.

See Also

SetWindowsHook, SetWindowsHookEx, UnhookWindowsHook, UnhookWindowsHookEx


CallWindowProc
CallWindowProc  QuickInfo  Overview  Group

The CallWindowProc function passes message information to the specified window procedure.

LRESULT CallWindowProc(

WNDPROC  lpPrevWndFunc,	// address of previous procedure
HWND  hWnd,	// handle of window
UINT  Msg,	// message
WPARAM  wParam,	// first message parameter
LPARAM  lParam	// second message parameter
);
Parameters

lpPrevWndFunc

Pointer to the previous window procedure.

If this value is obtained by calling the GetWindowLong function with the nIndex parameter set to GWL_WNDPROC or DWL_DLGPROC, it is actually either the address of a window or dialog box procedure, or a handle representing that address.

hWnd

Identifies the window procedure to receive the message.

Msg

Specifies the message.

wParam

Specifies additional message-specific information. The contents of this parameter depend on the value of the Msg parameter.

lParam

Specifies additional message-specific information. The contents of this parameter depend on the value of the Msg parameter.

Return Value

The return value specifies the result of the message processing and depends on the message sent.

Remarks

Use the CallWindowProc function for window subclassing. Usually, all windows with the same class share one window procedure. A subclass is a window or set of windows with the same class whose messages are intercepted and processed by another window procedure (or procedures) before being passed to the window procedure of the class.

The SetWindowLong function creates the subclass by changing the window procedure associated with a particular window, causing Windows to call the new window procedure instead of the previous one. An application must pass any messages not processed by the new window procedure to the previous window procedure by calling CallWindowProc. This allows the application to create a chain of window procedures.

If STRICT is defined, the lpPrevWndFunc parameter has the data type WNDPROC. The WNDPROC type is declared as follows:

LRESULT (CALLBACK* WNDPROC) (HWND, UINT, WPARAM, LPARAM);

If STRICT is not defined, the lpPrevWndFunc parameter has the data type FARPROC. The FARPROC type is declared as follows:

int (FAR WINAPI * FARPROC) ()

In C, the FARPROC declaration indicates a callback function that has an unspecified parameter list. In C++, however, the empty parameter list in the declaration indicates that a function has no parameters. This subtle distinction can break careless code. Following is one way to handle this situation:

#ifdef STRICT

  WNDPROC MyWindowProcedure

#else

  FARPROC MyWindowProcedure

#endif

...

    lResult = CallWindowProc(MyWindowProcedure, ...) ;

For further information about functions declared with empty argument lists, refer to The C++ Programming Language, Second Edition, by Bjarne Stroustrup.

Windows NT: The CallWindowProc function handles Unicode-to-ANSI conversion. You don't get the conversion if you call the window procedure directly.

See Also

FARPROC, GetWindowLong, SetClassLong, SetWindowLong, WNDPROC


CallWndProc
CallWndProc  QuickInfo  Overview  Group

The CallWndProc hook procedure is an application-defined or library-defined callback function that the system calls whenever the SendMessage function is called. Before passing the message to the destination window procedure, the system passes the message to the hook procedure. The hook procedure can examine the message; it cannot modify it.

LRESULT CALLBACK CallWndProc(

int  nCode,	// hook code
WPARAM  wParam,	// current-process flag
LPARAM  lParam	// address of structure with message data
);
Parameters

nCode

Specifies whether the hook procedure must process the message. If nCode is HC_ACTION, the hook procedure must process the message. If nCode is less than zero, the hook procedure must pass the message to the CallNextHookEx function without further processing and should return the value returned by CallNextHookEx.

wParam

Specifies whether the message is sent by the current process. If the message is sent by the current process, it is nonzero; otherwise, it is NULL.

lParam

Points to a CWPSTRUCT structure that contains details about the message.

Return Value

The return value should be zero.

Remarks

The CallWndProc hook procedure can examine the message, but it cannot modify it. After the hook procedure returns control to the system, the message is passed to the window procedure.

An application installs the hook procedure by specifying the WH_CALLWNDPROC hook type and the address of the hook procedure in a call to the SetWindowsHookEx function.

CallWndProc is a placeholder for the application-defined or library-defined function name.

See Also

CallNextHookEx, CWPSTRUCT, SendMessage, SetWindowsHookEx


CallWndRetProc [New - Windows 95]
CallWndRetProc  QuickInfo

[New - Windows 95]

The CallWndRetProc hook procedure is an application-defined or library-defined callback function the system calls after the SendMessage function is called. After passing the message to the destination window procedure, the system passes the message to the hook procedure. The hook procedure can examine the message; it cannot modify it.

LRESULT CALLBACK CallWndRetProc(

int  nCode,	// hook code
WPARAM  wParam,	// current-process flag
LPARAM  lParam	// address of structure with message data
);
Parameters

nCode

Specifies whether the hook procedure must process the message. If nCode is HC_ACTION, the hook procedure must process the message. If nCode is less than zero, the hook procedure must pass the message to the CallNextHookEx function without further processing and should return the value returned by CallNextHookEx.

wParam

Specifies whether the message is sent by the current process. If the message is sent by the current process, it is nonzero; otherwise, it is NULL.

lParam

Points to a CWPRETSTRUCT structure that contains details about the message.

Return Value

The return value should be zero.

Remarks

An application installs the hook procedure by specifying the WH_CALLWNDPROCRET hook type and the address of the hook procedure in a call to the SetWindowsHookEx function.

CallWndRetProc is a placeholder for the application-defined or library-defined function name.

See Also

CallNextHookEx, CallWndProc, CWPRETSTRUCT, SendMessage, SetWindowsHookEx


CancelDC
CancelDC  QuickInfo  Overview  Group

The CancelDC function cancels any pending operation on the specified device context (DC).

BOOL CancelDC(

HDC  hdc	// handle of device context
);
Parameters

hdc

Identifies the DC.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

The CancelDC function is used by multithreaded applications to cancel lengthy drawing operations. If thread A initiates a lengthy drawing operation, thread B may cancel that operation by calling this function.

If an operation is canceled, the affected thread returns an error and the result of its drawing operation is undefined. The results are also undefined if no drawing operation was in progress when the function was called.

See Also

CreateThread, GetCurrentThread


CascadeWindows [New - Windows 95]
CascadeWindows  QuickInfo

[New - Windows 95]

The CascadeWindows function cascades the specified windows or the child windows of the specified parent window.

WORD WINAPI CascadeWindows(

HWND hwndParent,	// handle of parent window
UINT wHow,	// types of windows not to arrange
CONST RECT * lpRect,	// rectangle to arrange windows in
UINT cKids,	// number of windows to arrange
const HWND FAR * lpKids	// array of window handles
);
Parameters

hwndParent

Identifies the parent window. If this parameter is NULL, the desktop window is assumed.

wHow

Specifies a cascade flag. The only flag currently available, MDITILE_SKIPDISABLED, prevents disabled MDI child windows from being cascaded.

lpRect

Points to a SMALL_RECT structure that specifies the rectangular area, in screen coordinates, within which the windows are arranged. This parameter can be NULL, in which case the client area of the parent window is used.

cKids

Specifies the number of elements in the array specified by the lpKids parameter. This parameter is ignored if lpKids is NULL.

lpKids

Points to an array of window handles identifying the windows to arrange. If this parameter is NULL, the child windows of the specified parent window (or of the desktop window) are arranged.

Return Value

If the function succeeds, the return value is the number of windows arranged.

If the function fails, the return value is zero.

See Also

SMALL_RECT


Catch
Catch  Overview  Group

The Catch function is not implemented in the Win32 API.

Structured exception handling is built into the Win32 API. For more information about structured exception handling, see Structured Exception Handling.


CBTProc
CBTProc  QuickInfo  Overview  Group

The CBTProc hook procedure is an application-defined or library-defined callback function that the system calls before activating, creating, destroying, minimizing, maximizing, moving, or sizing a window; before completing a system command; before removing a mouse or keyboard event from the system message queue; before setting the keyboard focus; or before synchronizing with the system message queue. The value returned by the hook procedure determines whether Windows allows or prevents one of these operations. A computer-based training (CBT) application uses this hook procedure to receive useful notifications from the system.

LRESULT CALLBACK CBTProc(

int  nCode,	// hook code
WPARAM  wParam,	// depends on hook code
LPARAM  lParam	// depends on hook code
);
Parameters

nCode

Specifies a code that the hook procedure uses to determine how to process the message. This parameter can be one of the following values:

Value	Meaning
HCBT_ACTIVATE	The system is about to activate a window.
HCBT_CLICKSKIPPED	The system has removed a mouse message from the system message queue. Upon receiving this hook code, a CBT application must install a WH_JOURNALPLAYBACK hook procedure in response to the mouse message.
HCBT_CREATEWND	A window is about to be created. The system calls the hook procedure before sending the WM_CREATE or WM_NCCREATE message to the window. If the hook procedure returns a nonzero value, the system destroys the window; the CreateWindow function returns NULL, but the WM_DESTROY message is not sent to the window. If the hook procedure returns zero, the window is created normally.
	At the time of the HCBT_CREATEWND notification, the window has been created, but its final size and position may not have been determined and its parent window may not have been established. It is possible to send messages to the newly created window, although it has not yet received WM_NCCREATE or WM_CREATE messages. It is also possible to change the position in the Z order of the newly created window by modifying the hwndInsertAfter member of the CBT_CREATEWND structure.
HCBT_DESTROYWND	A window is about to be destroyed.
HCBT_KEYSKIPPED	The system has removed a keyboard message from the system message queue. Upon receiving this hook code, a CBT application must install a WH_JOURNALPLAYBACK hook procedure in response to the keyboard message.
HCBT_MINMAX	A window is about to be minimized or maximized.
HCBT_MOVESIZE	A window is about to be moved or sized.
HCBT_QS	The system has retrieved a WM_QUEUESYNC message from the system message queue.
HCBT_SETFOCUS	A window is about to receive the keyboard focus.
HCBT_SYSCOMMAND	A system command is about to be carried out. This allows a CBT application to prevent task switching by means of hot keys.
If nCode is less than zero, the hook procedure must pass the message to the CallNextHookEx function without further processing and should return the value returned by CallNextHookEx.

wParam

Depends on the nCode parameter. For details, see the following Remarks section.

lParam

Depends on the nCode parameter. For details, see the following Remarks section.

Return Value

For operations corresponding to the following CBT hook codes, the return value must be 0 to allow the operation, or 1 to prevent it:

HCBT_ACTIVATE
HCBT_CREATEWND
HCBT_DESTROYWND
HCBT_MINMAX
HCBT_MOVESIZE
HCBT_SETFOCUS
HCBT_SYSCOMMAND

For operations corresponding to the following CBT hook codes, the return value is ignored:

HCBT_CLICKSKIPPED
HCBT_KEYSKIPPED
HCBT_QS

Remarks

The hook procedure should not install a WH_JOURNALPLAYBACK hook procedure except in the situations described in the preceding list of hook codes.

This hook procedure must be in a dynamic-link library (DLL). An application installs the hook procedure by specifying the WH_CBT hook type and the address of the hook procedure in a call to the SetWindowsHookEx function.

The following table describes the wParam and lParam parameters for each HCBT_ hook code:

Value	wParam	lParam
HCBT_ACTIVATE	Specifies the handle of the window about to be activated.	Specifies a long pointer to a CBTACTIVATESTRUCT structure containing the handle of the active window and specifies whether the activation is changing because of a mouse click.
HCBT_CLICKSKIPPED	Identifies the mouse message removed from the system message queue.	Specifies a long pointer to a MOUSEHOOKSTRUCT structure containing the hit-test code and the handle of the window for which the mouse message is intended.  The HCBT_CLICKSKIPPED value is sent to a CBTProc hook procedure only if a WH_MOUSE hook is installed. For a list of hit-test codes, see WM_NCHITTEST .
HCBT_CREATEWND	Specifies the handle of the new window.	Specifies a long pointer to a CBT_CREATEWND structure containing initialization parameters for the window. The parameters include the coordinates and dimensions of the window. By changing these parameters, a CBTProc hook procedure can set the initial size and position of the window.
HCBT_DESTROYWND	Specifies the handle of the window about to be destroyed.	Is undefined and must be set to zero.
HCBT_KEYSKIPPED	Identifies the virtual-key code.	Specifies the repeat count, scan code, key-transition code, previous key state, and context code. The HCBT_KEYSKIPPED value is sent to a CBTProc hook procedure only if a WH_KEYBOARD hook is installed. For more information, see the WM_KEYUP or WM_KEYDOWN message.
HCBT_MINMAX	Specifies the handle of the window being minimized or maximized.	Specifies, in the low-order word, a show-window value (SW_) specifying the operation. For a list of show-window values, see the ShowWindow. The high-order word is undefined.
HCBT_MOVESIZE	Specifies the handle of the window to be moved or sized.	Specifies a long pointer to a RECT structure containing the coordinates of the window. By changing the values in the structure, a CBTProc hook procedure can set the final coordinates of the window.
HCBT_QS	Is undefined and must be zero.	Is undefined and must be zero.
HCBT_SETFOCUS	Specifies the handle of the window gaining the keyboard focus.	Specifies the handle of the window losing the keyboard focus.
HCBT_SYSCOMMAND	Specifies a system-command value (SC_) specifying the system command. For more information about system-command values, see WM_SYSCOMMAND.	Contains the same data as the lParam value of a WM_SYSCOMMAND message: If a system menu command is chosen with the mouse, the low-order word contains the x-coordinate of the cursor, in screen coordinates, and the high-order word contains the y-coordinate; otherwise, the parameter is not used.
CBTProc is a placeholder for the application-defined or library-defined function name.

See Also

CallNextHookEx, CreateWindow, SetWindowsHookEx, WM_SYSCOMMAND


ChangeClipboardChain
ChangeClipboardChain  QuickInfo  Overview  Group

The ChangeClipboardChain function removes a specified window from the chain of clipboard viewers.

BOOL ChangeClipboardChain(

HWND  hWndRemove,	// handle of window to remove
HWND  hWndNewNext	// handle of next window
);
Parameters

hWndRemove

Identifies the window to be removed from the chain. The handle must have been passed to the SetClipboardViewer function.

hWndNewNext

Identifies the window that follows the hWndRemove window in the clipboard viewer chain. (This is the handle returned by SetClipboardViewer, unless the sequence was changed in response to a WM_CHANGECBCHAIN message.)

Return Value

The return value indicates the result of passing the WM_CHANGECBCHAIN message to the windows in the clipboard viewer chain. Because a window in the chain typically returns FALSE when it processes WM_CHANGECBCHAIN, the return value from ChangeClipboardChain is typically FALSE. If there is only one window in the chain, the return value is typically TRUE.

Remarks

The window identified by hWndNewNext replaces the hWndRemove window in the chain. The SetClipboardViewer function sends a WM_CHANGECBCHAIN message to the first window in the clipboard viewer chain.

See Also

SetClipboardViewer, WM_CHANGECBCHAIN


ChangeDisplaySettings
ChangeDisplaySettings  QuickInfo  Overview  Group

The ChangeDisplaySettings function changes the display settings to the specified graphics mode.

LONG ChangeDisplaySettings(

LPDEVMODE  lpDevMode,
DWORD  dwflags
);
Parameters

lpDevMode

Points to a DEVMODE structure that describes the graphics mode to switch to. The dmSize member must be initialized to the size, in bytes, of the DEVMODE structure. The following fields in the DEVMODE structure are used:

Member	Meaning
dmBitsPerPel	Bits per pixel
dmPelsWidth	Pixel width
dmPelsHeight	Pixel height
dmDisplayFlags	Mode flags
dmDisplayFrequency	Mode frequency
In addition to setting a value in one or more of the preceding DEVMODE members, you must also set the appropriate flags in the dmFields member. The flags indicate which members of the DEVMODE structure are used for the display settings change. If the appropriate bit is not set in dmFields, the display setting will not be changed. Set one or more of the following flags:

Flag	Meaning
DM_BITSPERPEL	Use the dmBitsPerPel value.
DM_PELSWIDTH	Use the dmPelsWidth value.
DM_PELSHEIGHT	Use the dmPelsHeight value.
DM_DISPLAYFLAGS	Use the dmDisplayFlags value.
DM_DISPLAYFREQENCY	Use the dmDisplayFrequency value.
If lpDevMode is NULL, all the values currently in the registry will be used for the display setting. Passing NULL for the lpDevMode parameter is the easiest way to return to the default mode after a dynamic mode change.

dwflags

Indicates how the graphics mode should be changed. May be one of the following:

Flag	Meaning
0	The graphics mode for the current screen will be changed dynamically.
CDS_UPDATEREGISTRY	The graphics mode for the current screen will be changed dynamically and the graphics mode will be updated in the registry. The mode information is stored in the USER profile.
CDS_TEST	The system tests if the requested graphics mode could be set.
If CDS_UPDATEREGISTRY is specified and it is possible to change the graphics mode dynamically, the information is stored in the registry and DISP_CHANGE_SUCCESSFUL is returned. If it is not possible to change the graphics mode dynamically, the information is stored in the registry and DISP_CHANGE_RESTART is returned. If the information could not be stored in the registry, the graphics mode is not changed and DISP_CHANGE_NOTUPDATED is returned.

Specifying CDS_TEST allows an application to determine which graphics modes are actually valid, without causing the system to change to that graphics mode.

Return Value

Returns one of the following values:

Value	Meaning
DISP_CHANGE_SUCCESSFUL	The settings change was successful.
DISP_CHANGE_RESTART	The computer must be restarted in order for the graphics mode to work.
DISP_CHANGE_BADFLAGS	An invalid set of flags was passed in.
DISP_CHANGE_FAILED	The display driver failed the specified graphics mode.
DISP_CHANGE_BADMODE	The graphics mode is not supported.
DISP_CHANGE_NOTUPDATED	Unable to write settings to the registry.
Remarks

Using the DEVMODE returned by the EnumDisplaySettings function ensures that the DEVMODE passed to ChangeDisplaySettings is valid and contains only values supported by the display driver.

When the display mode is changed dynamically, the WM_DISPLAYCHANGE message is sent to all running applications with the following message parameters:

Parameter	Meaning
wParam	New bits per pixel
LOWORD(lParam)	New pixel width
HIWORD(lParam)	New pixel height
See Also

CreateDC, DEVMODE, EnumDisplaySettings, WM_DISPLAYCHANGE


ChangeMenu
ChangeMenu  QuickInfo  Overview  Group

The ChangeMenu function has been replaced by the following specialized functions, which are available on both Windows NT and Windows 95:

Function	Description
AppendMenu	Appends a menu item to the end of a menu.
InsertMenu	Inserts a menu item into a menu.
ModifyMenu	Modifies a menu item in a menu.
RemoveMenu	Removes a menu item from a menu; if it is a pop-up item, the corresponding pop-up menu is not destroyed.
Windows 95 only:

Instead of using AppendMenu, InsertMenu, and ModifyMenu, applications written exclusively for Window 95 should use the following new functions, which are available only on Windows 95.

Function	Description
GetMenuItemInfo	Windows 95 only: Gets information about a menu item.
InsertMenuItem	Windows 95 only: Inserts a new menu item at the specified position in a menu bar or pop-up menu.
SetMenuItemInfo	Windows 95 only: Changes information about a menu item.
Applications written for versions earlier than Windows 3.0 can continue to call ChangeMenu . Applications written for Windows versions 3.0 and later should call these new functions.


ChangeSelector
ChangeSelector  Overview  Group

The ChangeSelector function is not implemented in the Win32 API. Win32-based applications running on Windows NT can use the VirtualLock and VirtualUnlock functions.


ChangeServiceConfig
ChangeServiceConfig  QuickInfo  Overview  Group

The ChangeServiceConfig function changes the configuration parameters of a service.

BOOL ChangeServiceConfig(

SC_HANDLE  hService,	// handle of service
DWORD  dwServiceType,	// type of service
DWORD  dwStartType,	// when to start service
DWORD  dwErrorControl,	// severity if service fails to start
LPCTSTR  lpBinaryPathName,	// address of service binary file name
LPCTSTR  lpLoadOrderGroup,	// address of load ordering group name
LPDWORD  lpdwTagId,	// address of variable to get tag identifier
LPCTSTR  lpDependencies,	// address of array of dependency names
LPCTSTR  lpServiceStartName,	// address of account name of service
LPCTSTR  lpPassword,	// address of password for service account
LPCTSTR  lpDisplayName	// address of display name
);
Parameters

hService

Identifies the service. This handle is returned by the OpenService or CreateService function and must have SERVICE_CHANGE_CONFIG access.

dwServiceType

A set of bit flags that specify the type of service. Specify SERVICE_NO_CHANGE if you are not changing the existing service type; otherwise, specify one of the following service type flags to indicate the service type. In addition, if you specify either of the SERVICE_WIN32 flags, you can also specify the SERVICE_INTERACTIVE_PROCESS flag to enable the service process to interact with the desktop.

Value	Meaning
SERVICE_WIN32_OWN_PROCESS	A service type flag that specifies a Win32 service that runs in its own process.
SERVICE_WIN32_SHARE_PROCESS	A service type flag that specifies a Win32 service that shares a process with other services.
SERVICE_KERNEL_DRIVER	A service type flag that specifies a Windows NT device driver.
SERVICE_FILE_SYSTEM_DRIVER	A service type flag that specifies a Windows NT file system driver.
SERVICE_INTERACTIVE_PROCESS	A flag that enables a Win32 service process to interact with the desktop.
dwStartType

Specifies when to start the service. This value can be the service type SERVICE_NO_CHANGE if the existing start type is not modified, or one of the following values can be specified:

Value	Meaning
SERVICE_BOOT_START	Specifies a device driver started by the operating system loader. This value is valid only if the service type is SERVICE_KERNEL_DRIVER or SERVICE_FILE_SYSTEM_DRIVER.
SERVICE_SYSTEM_START	Specifies a device driver started by the IoInitSystem function. This value is valid only if the service type is SERVICE_KERNEL_DRIVER or SERVICE_FILE_SYSTEM_DRIVER.
SERVICE_AUTO_START	Specifies a device driver or Win32 service started by the service control manager automatically during system startup.
SERVICE_DEMAND_START	Specifies a device driver or Win32 service started by the service control manager when a process calls the StartService function.
SERVICE_DISABLED	Specifies a device driver or Win32 service that can no longer be started.
dwErrorControl

Specifies the severity of the error if this service fails to start during startup, and determines the action taken by the startup program if failure occurs. One of the following values can be specified:

Value	Meaning
SERVICE_ERROR_IGNORE	The startup (boot) program logs the error but continues the startup operation.
SERVICE_ERROR_NORMAL	The startup program logs the error and puts up a message box pop-up but continues the startup operation.
SERVICE_ERROR_SEVERE	The startup program logs the error. If the last-known-good configuration is being started, the startup operation continues. Otherwise, the system is restarted with the last-known-good configuration.
SERVICE_ERROR_CRITICAL	The startup program logs the error, if possible. If the last-known-good configuration is being started, the startup operation fails. Otherwise, the system is restarted with the last-known good configuration.
SERVICE_NO_CHANGE	The existing StartType value is not to be changed.
lpBinaryPathName

Points to a null-terminated string that contains the fully qualified path to the service binary file. If the pointer is NULL, the path is not modified.

lpLoadOrderGroup

Points to a null-terminated string that names the load ordering group of which this service is a member. If the pointer is NULL, the group is not modified. If it points to an empty string, the service does not belong to a group.

The registry has a list of load ordering groups located at

HKEY_LOCAL_MACHINES\System\CurrentControlSet
\Control\ServiceGroupOrder.

The startup program uses this list to load groups of services in a specified order with respect to the other groups in the list. You can place a service in a group so that another service can depend on the group.

The order in which a service starts is determined by the following criteria:

1.	The order of groups in the registry's load-ordering group list. Services in groups in the load-ordering group list are started first, followed by services in groups not in the load-ordering group list, and then services that do not belong to a group.

2.	The service's dependencies listed in the lpDependencies parameter and the dependencies of other services dependent on the service.

lpdwTagId

Points to a 32-bit variable that receives a unique tag value for this service in the group specified in the lpLoadOrderGroup parameter. If no tag is requested, this parameter can be NULL.

You can use a tag for ordering service startup within a load ordering group by specifying a tag order vector in the registry located at

HKEY_LOCAL_MACHINE\System\CurrentControlSet
\Control\GroupOrderList.

Tags are only evaluated for SERVICE_KERNEL_DRIVER and SERVICE_FILE_SYSTEM_DRIVER type services that have SERVICE_BOOT_START or SERVICE_SYSTEM_START start types.

lpDependencies

Points to an array of null-separated names of services or load ordering groups that must start before this service. The array is double null-terminated. If the pointer is NULL, the dependencies are not modified. If it points to an empty string, the service has no dependencies. If a group name is specified, it must be prefixed by the SC_GROUP_IDENTIFIER character (defined in the WINSVC.H files) to differentiate it from a service name, because services and service groups share the same name space. Dependency on a service means that this service can only run if the service it depends on is running. Dependency on a group means that this service can run if at least one member of the group is running after an attempt to start all members of the group.

lpServiceStartName

Points to a null-terminated string. If NULL is specified, the name is not modified. If the service type is SERVICE_WIN32_OWN_PROCESS, this name is the account name in the form of "DomainName\Username", which the service process will be logged on as when it runs. If the account belongs to the built-in domain, ".\Username" can be specified. Services of type SERVICE_WIN32_SHARE_PROCESS are not allowed to specify an account other than LocalSystem.

If the service type is SERVICE_KERNEL_DRIVER or SERVICE_FILE_SYSTEM_DRIVER, this name is the Windows NT driver object name (that is, \FileSystem\Rdr or \Driver\Xns), which the input and output (I/O) system uses to load the device driver. If NULL is specified, the driver is run with a default object name created by the I/O system, based on the service name.

lpPassword

Points to a null-terminated string that contains the password to the account name specified by the lpServiceStartName parameter if the service type is SERVICE_WIN32_OWN_PROCESS or SERVICE_WIN32_SHARE_PROCESS. If the pointer is NULL, the password is not modified. If it points to an empty string, the service has no password. If the service type is SERVICE_KERNEL_DRIVER or SERVICE_FILE_SYSTEM_DRIVER, this parameter is ignored.

lpDisplayName

Points to a null-terminated string that is to be used by user interface programs to identify the service. This string has a maximum length of 256 characters. The name is case-preserved in the Service Control Manager. Display name comparisons are always case-insensitive.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Errors

The following error codes may be set by the service control manager. Other error codes may be set by the registry functions that are called by the service control manager.

Value	Meaning
ERROR_ACCESS_DENIED
	The specified handle was not opened with SERVICE_CHANGE_CONFIG access.
ERROR_CIRCULAR_DEPENDENCY
	A circular service dependency was specified.
ERROR_DUP_NAME
	The display name already exists in the service controller's database, either as a service name or as another display name.
ERROR_INVALID_HANDLE
	The specified handle is invalid.
ERROR_INVALID_PARAMETER
	A parameter that was specified is invalid.
ERROR_INVALID_SERVICE_ACCOUNT
	The account name does not exist, or a service is specified to share the same binary file as an already installed service but with an account name that is not the same as the installed service.
ERROR_SERVICE_MARKED_FOR_DELETE
	The service has been marked for deletion.
Remarks

The ChangeServiceConfig function changes the configuration information for the specified service in the service control manager database. This configuration information is initially specified by the CreateService function and can be queried (except for the password parameter) by using the QueryServiceConfig function.

Any of the configuration parameters specified for this function can be left unchanged by specifying NULL for a string parameter or SERVICE_NO_CHANGE for a doubleword parameter.

If the configuration is changed for a service that is running, with the exception of lpDisplayName, the changes do not take effect until the service is stopped.

See Also

CreateService, OpenService, QueryServiceConfig, StartService


CharLower
CharLower  QuickInfo  Overview  Group

The CharLower function converts a character string or a single character to lowercase. If the operand is a character string, the function converts the characters in place. This function supersedes the AnsiLower function.

LPTSTR CharLower(

LPTSTR  lpsz	// single character or address of string
);
Parameters

lpsz

Points to a null-terminated string or specifies a single character. If the high-order word of this parameter is zero, the low-order word must contain a single character to be converted.

Return Value

If the operand is a character string, the function returns a pointer to the converted string. Since the string is converted in place, the return value is equal to lpsz.

If the operand is a single character, the return value is a 32-bit value whose high-order word is zero, and low-order word contains the converted character.

There is no indication of success or failure. Failure is rare.

Remarks

Windows NT: To make the conversion, the function uses the language driver for the current language selected by the user at setup or by using the Control Panel. If no language has been selected, Windows completes the conversion by using internal default mapping. The conversion is made based on the code page associated with the process locale.

Windows 95: The function makes the conversion based on the information associated with the user's default locale, which is the locale selected by the user at setup or by using the Control Panel. Windows 95 does not have language drivers.

See Also

CharLowerBuff, CharUpper, CharUpperBuff


CharLowerBuff
CharLowerBuff  QuickInfo  Overview  Group

The CharLowerBuff function converts uppercase characters in a buffer to lowercase characters. The function converts the characters in place. The function supersedes the AnsiLowerBuff function.

DWORD CharLowerBuff(

LPTSTR  lpsz,	// points to buffer containing characters to process
DWORD  cchLength	// number of bytes or characters to process
);
Parameters

lpsz

Points to a buffer containing one or more characters to process.

cchLength

Specifies the size, in bytes (ANSI version) or characters (Unicode version), of the buffer pointed to by lpsz.

The function examines each character, and converts uppercase characters to lowercase characters. The function examines the number of bytes or characters indicated by cchLength, even if one or more characters are null characters.

Return Value

If the function succeeds, the return value is the number of bytes (ANSI version) or characters (Unicode version) processed.

For example, if CharLowerBuff("Acme of Operating Systems", 10) succeeds, the return value is 10.

Remarks

Windows NT: To make the conversion, the function uses the language driver for the current language selected by the user at setup or by using the Control Panel. If no language has been selected, Windows completes the conversion by using internal default mapping. The conversion is made based on the code page associated with the process locale.

Windows 95: The function makes the conversion based on the information associated with the user's default locale, which is the locale selected by the user at setup or by using the Control Panel. Windows 95 does not have language drivers.

See Also

CharLower, CharUpper, CharUpperBuff


CharNext
CharNext  QuickInfo  Overview  Group

The CharNext function returns a pointer to the next character in a string. This function supersedes the AnsiNext function.

LPTSTR CharNext(

LPCTSTR  lpsz	// address of current character
);
Parameters

lpsz

Points to a character in a null-terminated string.

Return Value

If the function succeeds, the return value is a pointer to the next character in the string, or to the terminating null character if at the end of the string.

If lpsz points to the terminating null character, the return value is equal to lpsz.

See Also

CharNextExA, CharPrev


CharNextExA
CharNextExA  QuickInfo

The CharNextExA function retrieves the address of the next character in a string. This function can handle strings consisting of either single- or multi-byte characters.

LPSTR CharNextExA(

WORD    CodePage,	// identifier of the code page
LPCSTR  lpCurrentChar ,	// address of current character
DWORD   dwFlags	// reserved; must be zero
);
Parameters

CodePage

Identifier of the code page to use to check lead-byte ranges. Can be one of the code-page values given in the "Code-Page Identifiers" table in Unicode and Character Set Constants or one of the following predefined values:

Value	Meaning
0	Use system default ANSI code page.
CP_ACP	Use system default ANSI code page.
CP_OEMCP	Use system default OEM code page.
lpCurrentChar

Pointer to a character in a null-terminated string.

dwFlags

Reserved; must be zero.

Return Value

If the function succeeds, the return value is a pointer to the next character in the string, or to the terminating null character if at the end of the string.

If lpCurrentChar points to the terminating null character, the return value is equal to lpCurrentChar.

See Also

CharNext, CharPrevExA


CharPrev
CharPrev  QuickInfo  Overview  Group

The CharPrev function returns a pointer to the preceding character in a string. This function supersedes the AnsiPrev function.

LPTSTR CharPrev(

LPCTSTR  lpszStart,	// address of first character
LPCTSTR  lpszCurrent	// address of current character
);
Parameters

lpszStart

Points to the beginning of the string.

lpszCurrent

Points to a character in a null-terminated string.

Return Value

If the function succeeds, the return value is a pointer to the preceding character in the string, or to the first character in the string if the lpszCurrent parameter equals the lpszStart parameter.

See Also

CharNext, CharPrevExA


CharPrevExA
CharPrevExA  QuickInfo

The CharPrevExA function retrieves the address of the preceding character in a string. This function can handle strings consisting of either single- or multi-byte characters.

LPSTR CharPrevExA(

WORD    CodePage,	// identifier of code page
LPCSTR  lpStart,	// address of first character
LPCSTR  lpCurrentChar,	// address of current character
DWORD   dwFlags	// reserved; must be zero
);
Parameters

CodePage

Identifier of the code page to use to check lead-byte ranges. Can be one of the code-page values given in the "Code-Page Identifiers" table in Unicode and Character Set Constants or one of the following predefined values:

Value	Meaning
0	Use system default ANSI code page.
CP_ACP	Use system default ANSI code page.
CP_OEMCP	Use system default OEM code page.
lpStart

Pointer to the beginning of the string.

lpCurrentChar

Pointer to a character in a null-terminated string.

dwFlags

Reserved; must be zero.

Return Value

If the function succeeds, the return value is a pointer to the preceding character in the string, or to the first character in the string if the lpCurrentChar parameter equals the lpStart parameter.

See Also

CharNextExA, CharPrev


CharToOem
CharToOem  QuickInfo  Overview  Group

The CharToOem function translates a string into the OEM-defined character set. (OEM stands for original equipment manufacturer.) This function supersedes the AnsiToOem function.

BOOL CharToOem(

LPCTSTR  lpszSrc,	// address of string to translate
LPSTR  lpszDst	// address of translated string
);
Parameters

lpszSrc

Points to the null-terminated string to translate.

lpszDst

Points to the buffer for the translated string. If the CharToOem function is being used as an ANSI function, the string can be translated in place by setting the lpszDst parameter to the same address as the lpszSrc parameter. This cannot be done if CharToOem is being used as a wide-character function.

Return Value

The return value is always TRUE.

See Also

CharToOemBuff, OemToChar, OemToCharBuff


CharToOemBuff
CharToOemBuff  QuickInfo  Overview  Group

The CharToOemBuff function translates a specified number of characters in a string into the OEM-defined character set. (OEM stands for original equipment manufacturer.) This function supersedes the AnsiToOemBuff function.

BOOL CharToOemBuff(

LPCTSTR  lpszSrc,	// address of string to translate
LPSTR  lpszDst,	// address of translated string
DWORD  cchDstLength	// length of string to translate, in characters
);
Parameters

lpszSrc

Points to the null-terminated string to translate.

lpszDst

Points to the buffer for the translated string. If the CharToOemBuff function is being used as an ANSI function, the string can be translated in place by setting the lpszDst parameter to the same address as the lpszSrc parameter. This cannot be done if CharToOemBuff is being used as a wide-character function.

cchDstLength

Specifies the number of characters to translate in the string identified by the lpszSrc parameter.

Return Value

The return value is always TRUE.

See Also

CharToOem, OemToChar, OemToCharBuff


CharUpper
CharUpper  QuickInfo  Overview  Group

The CharUpper function converts a character string or a single character to uppercase. If the operand is a character string, the function converts the characters in place. This function supersedes the AnsiUpper function.

LPTSTR CharUpper(

LPTSTR  lpsz	// single character or address of string
);
Parameters

lpsz

Points to a null-terminated string or specifies a single character. If the high-order word of this parameter is zero, the low-order word must contain a single character to be converted.

Return Value

If the operand is a character string, the function returns a pointer to the converted string. Since the string is converted in place, the return value is equal to lpsz.

If the operand is a single character, the return value is a 32-bit value whose high-order word is zero, and low-order word contains the converted character.

There is no indication of success or failure. Failure is rare.

Remarks

Windows NT: To make the conversion, the function uses the language driver for the current language selected by the user at setup or by using the Control Panel. If no language has been selected, Windows completes the conversion by using internal default mapping. The conversion is made based on the code page associated with the process locale.

Windows 95: The function makes the conversion based on the information associated with the user's default locale, which is the locale selected by the user at setup or by using the Control Panel. Windows 95 does not have language drivers.

See Also

CharLower, CharLowerBuff, CharUpperBuff


CharUpperBuff
CharUpperBuff  QuickInfo  Overview  Group

The CharUpperBuff function converts lowercase characters in a buffer to uppercase characters. The function converts the characters in place. The function supersedes the AnsiUpperBuff function.

DWORD CharUpperBuff(

LPTSTR  lpsz,	// points to buffer containing characters to process
DWORD  cchLength	// number of characters to process
);
Parameters

lpsz

Points to a buffer containing one or more characters to process.

cchLength

Specifies the size, in bytes (ANSI version) or characters (Unicode version), of the buffer pointed to by lpsz.

The function examines each character, and converts lowercase characters to uppercase characters. The function examines the number of bytes or characters indicated by cchLength, even if one or more characters are null characters.

Return Value

If the function succeeds, the return value is the number of bytes (ANSI version) or characters (Unicode version) processed.

For example, if CharUpperBuff("Zenith of API Sets", 10) succeeds, the return value is 10.

Remarks

Windows NT: To make the conversion, the function uses the language driver for the current language selected by the user at setup or by using the Control Panel. If no language has been selected, Windows completes the conversion by using internal default mapping. The conversion is made based on the code page associated with the process locale.

Windows 95: The function makes the conversion based on the information associated with the user's default locale, which is the locale selected by the user at setup or by using the Control Panel. Windows 95 does not have language drivers.

See Also

CharLower, CharLowerBuff, CharUpper


CheckColorsInGamut [New - Windows 95]
CheckColorsInGamut  QuickInfo  Overview  Group

[New - Windows 95]

The CheckColorsInGamut function indicates whether the specified color values are within the gamut of the specified device.

BOOL CheckColorsInGamut(

HDC  hdc,
LPVOID  lpaRGBQuad,
LPVOID  lpResult,
DWORD  nCount
);
Parameters

hdc

Handle to a device context.

lpaRGBQuad

Pointer to an array of RGBQUAD structures that contains the color values to check.

lpResult

Pointer to an array of bytes that receives the results of the color checking.

nCount

Count of elements in the array.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

For each specified color value, CheckColorsInGamut sets the corresponding byte in the results buffer to either CM_IN_GAMUT or CM_OUT_OF_GAMUT.

See Also

RGBQUAD


CheckDlgButton
CheckDlgButton  QuickInfo  Overview  Group

The CheckDlgButton function changes the check state of a button control.

BOOL CheckDlgButton(

HWND  hDlg,	// handle of dialog box
int  nIDButton,	// button-control identifier
UINT  uCheck	// check state
);
Parameters

hDlg

Identifies the dialog box that contains the button.

nIDButton

Identifies the button to modify.

uCheck

Specifies the check state of the button. This parameter can be one of the following values:

Value	Meaning
0	Sets the button state to unchecked. Same as the Windows 95 constant BST_UNCHECKED.
1	Sets the button state to checked. Same as the Windows 95 constant BST_CHECKED.
2	Sets the button state to grayed, indicating an indeterminate state. Use this value only if the button has the BS_3STATE or BS_AUTO3STATE style. Same as the Windows 95 constant BST_INDETERMINATE.
BST_CHECKED	Windows 95 only: Sets the button state to checked.
BST_INDETERMINATE	Windows 95 only: Sets the button state to grayed, indicating an indeterminate state. Use this value only if the button has the BS_3STATE or BS_AUTO3STATE style.
BST_UNCHECKED	Windows 95 only: Sets the button state to unchecked
Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The CheckDlgButton function sends a BM_SETCHECK message to the specified button control in the given dialog box.

See Also

CheckRadioButton, IsDlgButtonChecked


CheckMenuItem
CheckMenuItem  QuickInfo  Overview  Group

The CheckMenuItem function sets the state of the specified menu item's check mark attribute to either checked or unchecked.

DWORD CheckMenuItem(

HMENU hmenu,	// handle of menu
UINT uIDCheckItem,	// menu item to check or uncheck
UINT uCheck	// menu item flags
);
Parameters

hmenu

Identifies the menu of interest.

uIDCheckItem

Specifies the menu item whose check-mark attribute is to be set, as determined by the uCheck parameter.

uCheck

Specifies flags that control the interpretation of the uIDCheckItem parameter and the state of the menu item's check-mark attribute. This parameter can be a combination of either MF_BYCOMMAND or MF_BYPOSITION and MF_CHECKED or MF_UNCHECKED.

Value	Meaning
MF_BYCOMMAND	Indicates that the uIDCheckItem parameter gives the identifier of the menu item. The MF_BYCOMMAND flag is the default, if neither the MF_BYCOMMAND nor MF_BYPOSITION flag is specified.
MF_BYPOSITION	Indicates that the uIDCheckItem parameter gives the zero-based relative position of the menu item.
MF_CHECKED	Sets the check-mark attribute to the checked state.
MF_UNCHECKED	Sets the check-mark attribute to the unchecked state.
Return Value

The return value specifies the previous state of the menu item (either MF_CHECKED or MF_UNCHECKED). If the menu item does not exist, the return value is 0xFFFFFFFF.

Remarks

An item in a menu bar cannot have a check mark.

The uIDCheckItem parameter identifies a pop-up item or a command item. For a pop-up item, the uIDCheckItem parameter must specify the position of the item, because a pop-up item does not have an identifier. For a command item, the uIDCheckItem parameter can specify either the item's position or its identifier.

See Also

EnableMenuItem, GetMenuCheckMarkDimensions, GetMenuItemID, SetMenuItemBitmaps


CheckMenuRadioItem [New - Windows 95]
CheckMenuRadioItem  QuickInfo  Overview  Group

[New - Windows 95]

The CheckMenuRadioItem function checks a specified menu item and makes it a radio item. At the same time, the function unchecks all other menu items in the associated group and clears the radio-item type flag for those items.

BOOL API CheckMenuRadioItem(

HMENU  hmenu,
UINT  idFirst,
UINT  idLast,
UINT  idCheck,
UINT  uFlags
);
Parameters

hmenu

Handle to the menu that contains the group of menu items.

idFirst

Identifier or position of the first menu item in the group.

idLast

Identifier or position of the last menu item in the group.

idCheck

Identifier or position of the menu item to check.

uFlags

Value specifying the meaning of idFirst, idLast, and idCheck. If this parameter is MF_BYCOMMAND, the other parameters specify menu item identifiers. If it is MF_BYPOSITION, the other parameters specify the menu item positions.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, use the GetLastError function.

Remarks

The CheckMenuRadioItem function sets the MFT_RADIOCHECK type flag and the MFS_CHECKED state for the item specified by idCheck and, at the same time, clears both flags for all other items in the group. The checked item is displayed using a bullet bitmap instead of a check-mark bitmap.

For more information about menu item type and state flags, see the MENUITEMINFO structure.

See Also

MENUITEMINFO


CheckRadioButton
CheckRadioButton  QuickInfo  Overview  Group

The CheckRadioButton function adds a check mark to (checks) a specified radio button in a group and removes a check mark from (clears) all other radio buttons in the group.

BOOL CheckRadioButton(

HWND  hDlg,	// handle of dialog box
int  nIDFirstButton,	// identifier of first radio button in group
int  nIDLastButton,	// identifier of last radio button in group
int  nIDCheckButton	// identifier of radio button to select
);
Parameters

hDlg

Identifies the dialog box that contains the radio button.

nIDFirstButton

Specifies the identifier of the first radio button in the group.

nIDLastButton

Specifies the identifier of the last radio button in the group.

nIDCheckButton

Specifies the identifier of the radio button to select.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The CheckRadioButton function sends a BM_SETCHECK message to each of the radio buttons in the indicated group.

See Also

BM_SETCHECK, CheckDlgButton, IsDlgButtonChecked


ChildWindowFromPoint
ChildWindowFromPoint  QuickInfo  Overview  Group

The ChildWindowFromPoint function determines which, if any, of the child windows belonging to a parent window contains the specified point.

HWND ChildWindowFromPoint(

HWND  hWndParent,	// handle of parent window
POINT  Point	// structure with point coordinates
);
Parameters

hWndParent

Identifies the parent window.

Point

Specifies a POINT structure that defines the client coordinates of the point to be checked.

Return Value

If the function succeeds, the return value is the handle of the child window that contains the point, even if the child window is hidden or disabled. If the point lies outside the parent window, the return value is NULL. If the point is within the parent window but not within any child window, the return value is the handle of the parent window.

Remarks

Windows maintains an internal list, containing the handles of the child windows associated with a parent window. The order of the handles in the list depends on the Z order of the child windows. If more than one child window contains the given point, Windows returns the handle of the first window in the list that contains the point.

See Also

ChildWindowFromPointEx, POINT, WindowFromPoint


ChildWindowFromPointEx [New - Windows 95]
ChildWindowFromPointEx  QuickInfo

[New - Windows 95]

The ChildWindowFromPointEx function determines which, if any, of the child windows belonging to the given parent window contains the specified point. The function can ignore invisible, disabled, and transparent child windows.

HWND ChildWindowFromPointEx(

HWND  hwndParent,	// handle of parent window
POINT  pt,	// structure with point coordinates
UINT  uFlags	// skipping flags
);
Parameters

hwndParent

Identifies the parent window.

pt

Specifies a POINT structure that defines the client coordinates of the point to be checked.

uFlags

Specifies which child windows to skip. This parameter can be a combination of the following values:

Value	Meaning
CWP_ALL	Do not skip any child windows
CWP_SKIPINVISIBLE	Skip invisible child windows
CWP_SKIPDISABLED	Skip disabled child windows
CWP_SKIPTRANSPARENT	Skip transparent child windows
Return Value

If the function succeeds, the return value is the handle of the first child window that contains the point and meets the criteria specified by uFlags. If the point is within the parent window but not within any child window that meets the criteria, the return value is the handle of the parent window. If the point lies outside the parent window or if the function fails, the return value is NULL.

Remarks

Windows maintains an internal list that contains the handles of the child windows associated with a parent window. The order of the handles in the list depends on the Z order of the child windows. If more than one child window contains the given point, Windows returns the handle of the first window in the list that contains the point and meets the criteria specified by uFlags.

See Also

ChildWindowFromPoint, POINT, WindowFromPoint


ChooseColor
ChooseColor  QuickInfo  Overview  Group

The ChooseColor function creates a system-defined dialog box from which the user can select a color.

BOOL ChooseColor(

LPCHOOSECOLOR  lpcc	// address of structure with initialization data
);
Parameters

lpcc

Points to a CHOOSECOLOR structure that, when the function is called, contains information necessary to initialize the dialog box. When ChooseColor returns, this structure contains information about the user's color selection.

Return Value

If the user selects a color, the return value is TRUE. It is FALSE if an error occurs, the user chooses the Cancel button, or the user chooses the Close command on the System menu (often called the Control menu) to close the dialog box.

The CommDlgExtendedError function can be used to get extended error information, which may be one of the following values:

CDERR_FINDRESFAILURE	CDERR_MEMLOCKFAILURE
CDERR_INITIALIZATION	CDERR_NOHINSTANCE
CDERR_LOCKRESFAILURE	CDERR_NOHOOK
CDERR_LOADRESFAILURE	CDERR_NOTEMPLATE
CDERR_LOADSTRFAILURE	CDERR_STRUCTSIZE
CDERR_MEMALLOCFAILURE
Remarks

The dialog box does not support palettes. The color choices offered by the dialog box are limited to the system colors and dithered versions of those colors.

If the hook function (to which the lpfnHook member of the CHOOSECOLOR structure points) processes the WM_CTLCOLORDLG message, ChooseColor must return a handle for the brush that should be used to paint the control background.

See Also

CommDlgExtendedError, WM_CTLCOLORDLG, CHOOSECOLOR


ChooseFont
ChooseFont  QuickInfo  Overview  Group

The ChooseFont function creates a system-defined dialog box from which the user can select a font, a font style (such as bold or italic), a point size, an effect (such as strikeout or underline), and a text color.

BOOL ChooseFont(

LPCHOOSEFONT  lpcf	// address of structure with initialization data
);
Parameters

lpcf

Points to a CHOOSEFONT structure that, when the structure is called, contains information necessary to initialize the dialog box. When ChooseFont returns, this structure contains information about the user's font selection.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

The CommDlgExtendedError function can be used to get extended error information, which may be one of the following values:

CDERR_FINDRESFAILURE	CDERR_NOHINSTANCE
CDERR_INITIALIZATION	CDERR_NOHOOK
CDERR_LOCKRESFAILURE	CDERR_NOTEMPLATE
CDERR_LOADRESFAILURE	CDERR_STRUCTSIZE
CDERR_LOADSTRFAILURE	CFERR_MAXLESSTHANMIN
CDERR_MEMALLOCFAILURE	CFERR_NOFONTS
CDERR_MEMLOCKFAILURE
Remarks

If the hook function (to which the lpfnHook member of the CHOOSEFONT structure points) processes the WM_CTLCOLORDLG message, ChooseFont must return a handle for the brush that should be used to paint the control background.

An application can use the WM_CHOOSEFONT_GETLOGFONT message to retrieve a LOGFONT structure for the current logical font while the Font dialog box is open.

See Also

CommDlgExtendedError, WM_CHOOSEFONT_GETLOGFONT, WM_CTLCOLORDLG, CHOOSEFONT, LOGFONT


Chord
Chord  QuickInfo  Overview  Group

The Chord function draws a chord (a region bounded by the intersection of an ellipse and a line segment, called a "secant"). The chord is outlined by using the current pen and filled by using the current brush.

BOOL Chord(

HDC  hdc,	// handle of device context
int  nLeftRect,	// x-coordinate of the upper-left corner of the bounding rectangle
int  nTopRect,	// y-coordinate of the upper-left corner of the bounding rectangle
int  nRightRect,	// x-coordinate of the lower-right corner of the bounding rectangle
int  nBottomRect,	// y-coordinate of the lower-right corner of the bounding rectangle
int  nXRadial1,	// x-coordinate of the first radial's endpoint
int  nYRadial1,	// y-coordinate of the first radial's endpoint
int  nXRadial2,	// x-coordinate of the second radial's endpoint
int  nYRadial2	// y-coordinate of the second radial's endpoint
);
Parameters

hdc

Identifies the device context in which the chord appears.

nLeftRect

Specifies the x-coordinate of the upper-left corner of the bounding rectangle.

nTopRect

Specifies the y-coordinate of the upper-left corner of the bounding rectangle.

nRightRect

Specifies the x-coordinate of the lower-right corner of the bounding rectangle.

nBottomRect

Specifies the y-coordinate of the lower-right corner of the bounding rectangle.

nXRadial1

Specifies the x-coordinate of the endpoint of the radial defining the beginning of the chord.

nYRadial1

Specifies the y-coordinate of the endpoint of the radial defining the beginning of the chord.

nXRadial2

Specifies the x-coordinate of the endpoint of the radial defining the end of the chord.

nYRadial2

Specifies the y-coordinate of the endpoint of the radial defining the end of the chord.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The curve of the chord is defined by an ellipse that fits the specified bounding rectangle. The curve begins at the point where the ellipse intersects the first radial and extends counterclockwise to the point where the ellipse intersects the second radial. (A radial is a line segment drawn from the center of the ellipse to a specified endpoint on the ellipse.) The chord is closed by drawing a line from the intersection of the first radial and the curve to the intersection of the second radial and the curve.

If the starting point and ending point of the curve are the same, a complete ellipse is drawn.

The current position is neither used nor updated by Chord.

Windows 95 only: The sum of the coordinates of the bounding rectangle cannot exceed 32,767. The sum of nLeftRect and nRightRect or nTopRect and nBottomRect parameters cannot exceed 32,767.

See Also

AngleArc, Arc, ArcTo, Pie


ClearCommBreak
ClearCommBreak  QuickInfo  Overview  Group

The ClearCommBreak function restores character transmission for a specified communications device and places the transmission line in a nonbreak state.

BOOL ClearCommBreak(

HANDLE  hFile	// handle of communications device
);
Parameters

hFile

Identifies the communications device. The CreateFile function returns this handle.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

A communications device is placed in a break state by the SetCommBreak or EscapeCommFunction function. Character transmission is then suspended until the break state is cleared by calling ClearCommBreak.

See Also

ClearCommError, CreateFile, EscapeCommFunction, SetCommBreak


ClearCommError
ClearCommError  QuickInfo  Overview  Group

The ClearCommError function retrieves information about a communications error and reports the current status of a communications device. The function is called when a communications error occurs, and it clears the device's error flag to enable additional input and output (I/O) operations.

BOOL ClearCommError(

HANDLE  hFile,	// handle of communications device
LPDWORD  lpErrors,	// address of variable to receive error codes
LPCOMSTAT  lpStat	// address of buffer for communications status
);
Parameters

hFile

Identifies the communications device. The CreateFile function returns this handle.

lpErrors

Points to a 32-bit variable to be filled with a mask indicating the type of error. This parameter can be one or more of the following error values:

Value	Meaning
CE_BREAK	The hardware detected a break condition.
CE_DNS	Windows 95 only: A parallel device is not selected.
CE_FRAME	The hardware detected a framing error.
CE_IOE	An I/O error occurred during communications with the device.
CE_MODE	The requested mode is not supported, or the hFile parameter is invalid. If this value is specified, it is the only valid error.
CE_OOP	Windows 95 only: A parallel device signaled that it is out of paper.
CE_OVERRUN	A character-buffer overrun has occurred. The next character is lost.
CE_PTO	Windows 95 only: A time-out occurred on a parallel device.
CE_RXOVER	An input buffer overflow has occurred. There is either no room in the input buffer, or a character was received after the end-of-file (EOF) character.
CE_RXPARITY	The hardware detected a parity error.
CE_TXFULL	The application tried to transmit a character, but the output buffer was full.
lpStat

Points to a COMSTAT structure in which the device's status information is returned. If lpStat is NULL, no status information is returned.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

If a communications port has been set up with a TRUE value for the fAbortOnError member of the setup DCB structure, the communications software will terminate all read and write operations on the communications port when a communications error occurs. No new read or write operations will be accepted until the application acknowledges the communications error by calling the ClearCommError function.

The ClearCommError function fills the status buffer pointed to by the lpStat parameter with the current status of the communications device specified by the hFile parameter.

See Also

ClearCommBreak, COMSTAT, CreateFile, DCB


ClearEventLog
ClearEventLog  QuickInfo  Overview  Group

The ClearEventLog function clears the specified event log, and optionally saves the current copy of the logfile to a backup file.

BOOL ClearEventLog(

HANDLE  hEventLog,	// handle to event log
LPCTSTR  lpBackupFileName	// name of backup file
);
Parameters

hEventLog

Identifies the event log to be cleared. This handle is returned by the OpenEventLog function.

lpBackupFileName

Points to the null-terminated string specifying the name of a file in which a current copy of the event logfile will be placed. If this file already exists, the function fails.

The backup filename may contain a server name to save the backup file on a remote server.

If the lpBackupFileName parameter is NULL, the current event logfile is not backed up.

Return Value

If the function succeeds, the return value is TRUE. The given event log has been backed up (if lpBackupFileName is not NULL) and then cleared.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

This function fails if the event log is empty.

After this function returns, any handles that reference the cleared event log cannot be used to read the log.

If the backup filename specifies a remote server, the event log handle must identify a log on the local computer. You cannot back up an event logfile from a remote server to a file on a remote server (even if the backup file and the original log are on the same server).

ClearEventLog is used to optionally back up an existing logfile of the module represented by hEventLog. The function backs up the logfile to another file, and then clears the existing logfile. The caller must have write permission for the path specified, and must also have permission to move the current logfile. If a file already exists with the same name as lpBackupFileName, ClearEventLog fails.

See Also

OpenEventLog


ClientToScreen
ClientToScreen  QuickInfo  Overview  Group

The ClientToScreen function converts the client coordinates of a specified point to screen coordinates.

BOOL ClientToScreen(

HWND  hWnd,	// window handle for source coordinates
LPPOINT  lpPoint	// address of structure containing screen coordinates
);
Parameters

hWnd

Identifies the window whose client area is used for the conversion.

lpPoint

Points to a POINT structure that contains the client coordinates to be converted. The new screen coordinates are copied into this structure if the function succeeds.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

The ClientToScreen function replaces the client coordinates in the POINT structure with the screen coordinates. The screen coordinates are relative to the upper-left corner of the screen.

See Also

MapWindowPoints, POINT, ScreenToClient


ClipCursor
ClipCursor  QuickInfo  Overview  Group

The ClipCursor function confines the cursor to a rectangular area on the screen. If a subsequent cursor position (set by the SetCursorPos function or the mouse) lies outside the rectangle, Windows automatically adjusts the position to keep the cursor inside the rectangular area.

BOOL ClipCursor(

CONST RECT * lpRect	// address of structure with rectangle
);
Parameters

lprc

Points to the RECT structure that contains the screen coordinates of the upper-left and lower-right corners of the confining rectangle. If this parameter is NULL, the cursor is free to move anywhere on the screen.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The cursor is a shared resource. If an application confines the cursor, it must release the cursor by using ClipCursor before relinquishing control to another application.

The calling process must have WINSTA_WRITEATTRIBUTES access to the window station.

See Also

GetClipCursor, GetCursorPos, RECT, SetCursorPos


CloseClipboard
CloseClipboard  QuickInfo  Overview  Group

The CloseClipboard function closes the clipboard.

BOOL CloseClipboard(VOID)

Parameters

This function has no parameters.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

When the window has finished examining or changing the clipboard, close the clipboard by calling CloseClipboard. This enables other windows to access the clipboard.

Do not place an object on the clipboard after calling CloseClipboard.

See Also

GetOpenClipboardWindow, OpenClipboard


CloseDesktop [New - Windows NT]
CloseDesktop  QuickInfo  Overview  Group

[New - Windows NT]

The CloseDesktop function closes an open handle of a desktop object. A desktop is a secure object contained within a window station object. A desktop has a logical display surface and contains windows, menus and hooks.

BOOL CloseDesktop(

HDESK hDesktop	// handle of desktop to close
);
Parameters

hDesktop

Identifies the desktop to be closed. This handle is returned by the CreateDesktop and OpenDesktop functions.

Return Value

If the function succeeds, the return value is TRUE.

If the functions fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The CloseDesktop function will fail if any thread in the calling process is using the specified desktop handle or if the handle refers to the initial desktop of the calling process.

See Also

CreateDesktop, OpenDesktop


CloseEnhMetaFile
CloseEnhMetaFile  QuickInfo  Overview  Group

The CloseEnhMetaFile function closes an enhanced-metafile device context and returns a handle that identifies an enhanced-format metafile.

HENHMETAFILE CloseEnhMetaFile(

HDC  hdc	// handle of an enhanced-metafile device context
);
Parameters

hdc

Identifies an enhanced-metafile device context.

Return Value

If the function succeeds, the return value is a handle of an enhanced metafile.

If the function fails, the return value is NULL.

Remarks

An application can use the enhanced-metafile handle returned by this function to perform the following tasks:

•	Display a picture stored in an enhanced metafile

•	Create copies of the enhanced metafile

•	Enumerate, edit, or copy individual records in the enhanced metafile

•	Retrieve an optional description of the metafile contents from the enhanced-metafile header

•	Retrieve a copy of the enhanced-metafile header

•	Retrieve a binary copy of the enhanced metafile

•	Enumerate the colors in the optional palette

•	Convert an enhanced-format metafile into a Windows-format metafile

When the application no longer needs the enhanced metafile handle, it should release the handle by calling the DeleteEnhMetaFile function.

See Also

CopyEnhMetaFile, CreateEnhMetaFile, DeleteEnhMetaFile, EnumEnhMetaFile, GetEnhMetaFileBits, GetWinMetaFileBits, PlayEnhMetaFile


CloseEventLog
CloseEventLog  QuickInfo  Overview  Group

The CloseEventLog function closes the specified event log.

BOOL CloseEventLog(

HANDLE  hEventLog	// handle to event log
);
Parameters

hEventLog

Identifies the event log to be closed. This handle is returned by the OpenEventLog function.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

OpenEventLog


CloseFigure
CloseFigure  QuickInfo  Overview  Group

The CloseFigure function closes an open figure in a path.

BOOL CloseFigure(

HDC  hdc	// handle of device context
);
Parameters

hdc

Identifies the device context in which the figure will be closed.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The CloseFigure function closes the figure by drawing a line from the current position to the first point of the figure (usually, the point specified by the most recent call to the MoveTo function) and then connects the lines by using the line join style. If a figure is closed by using the LineTo function instead of CloseFigure, end caps are used to create the corner instead of a join.

The CloseFigure function should only be called if there is an open path bracket in the specified device context.

A figure in a path is open unless it is explicitly closed by using this function. (A figure can be open even if the current point and the starting point of the figure are the same.)

After a call to CloseFigure, adding a line or curve to the path starts a new figure.

See Also

BeginPath, EndPath, ExtCreatePen, LineTo, MoveTo


CloseHandle
CloseHandle  QuickInfo  Overview  Group

The CloseHandle function closes an open object handle.

BOOL CloseHandle(

HANDLE  hObject	// handle of object to close
);
Parameters

hObject

Identifies an open object handle.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The CloseHandle function closes handles to the following objects:

•	Console input or output

•	Event file

•	File mapping

•	Mutex

•	Named pipe

•	Process

•	Semaphore

•	Thread

CloseHandle invalidates the specified object handle, decrements the object's handle count, and performs object retention checks. Once the last handle of an object is closed, the object is removed from the operating system.

This function does not close module objects.

CloseHandle is used to close handles returned by calls to the CreateFile function.

See Also

CreateFile, DeleteFile


CloseMetaFile
CloseMetaFile  QuickInfo  Overview  Group

The CloseMetaFile function closes a metafile device context and returns a handle that identifies a Windows-format metafile.

This function is provided for compatibility with earlier versions of Microsoft Windows. Win32-based applications should use the CloseEnhMetaFile function.

HMETAFILE CloseMetaFile(

HDC  hdc	// handle of metafile device context
);
Parameters

hdc

Identifies a metafile device context used to create a Windows-format metafile.

Return Value

If the function succeeds, the return value is a handle of a Windows-format metafile.

If the function fails, the return value is NULL.

Remarks

A Windows-format metafile does not support the new curve, path, and transformation functions, such as PolyBezier, BeginPath, and SetWorldTransform. Applications that use these new functions and use metafiles to store pictures created by these functions should call the enhanced-format metafile functions.

To convert a Windows-format metafile into a new enhanced-format metafile, use the SetWinMetaFileBits function.

When an application no longer needs the Windows-format metafile handle, it should delete the handle by calling the DeleteMetaFile function.

See Also

BeginPath, CloseEnhMetaFile, CopyMetaFile, CreateMetaFile, DeleteMetaFile, EnumMetaFile, GetMetaFileBitsEx, PlayMetaFile, PolyBezier, SetWinMetaFileBits, SetWorldTransform


ClosePrinter
ClosePrinter  QuickInfo  Overview  Group

The ClosePrinter function closes the specified printer object.

BOOL ClosePrinter(

HANDLE  hPrinter	// handle of printer object
);
Parameters

hPrinter

Identifies the printer object to be closed.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

AddPrinter, OpenPrinter


CloseServiceHandle
CloseServiceHandle  QuickInfo  Overview  Group

The CloseServiceHandle function closes a handle to a service control manager database as returned by the OpenSCManager function, or it closes a handle to a service object as returned by either the OpenService or CreateService function.

BOOL CloseServiceHandle(

SC_HANDLE  hSCObject	// handle of service or service control manager database
);
Parameters

hSCObject

Identifies the service control manager database or the service object to close.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Errors

The following error code may be set by the service control manager. Other error codes may be set by registry functions that are called by the service control manager.

Value	Meaning
ERROR_INVALID_HANDLE	The specified handle is invalid.
Remarks

The CloseServiceHandle function does not destroy the service control manager object referred to by the handle. A service control manager object cannot be destroyed. A service object can be destroyed by calling the DeleteService function.

See Also

CreateService, DeleteService, OpenSCManager, OpenService


closesocket
closesocket  QuickInfo

The Windows Sockets closesocket function closes a socket.

int closesocket (

SOCKET s
);
Parameters

s

A descriptor identifying a socket.

Return Value

If no error occurs, closesocket returns zero. Otherwise, a value of SOCKET_ERROR is returned, and a specific error code may be retrieved by calling WSAGetLastError.

Error Codes

WSANOTINITIALISED	A successful WSAStartup must occur before using this function.
WSAENETDOWN	The Windows Sockets implementation has detected that the network subsystem has failed.
WSAENOTSOCK	The descriptor is not a socket.
WSAEINPROGRESS	A blocking Windows Sockets call is in progress.
WSAEINTR	The (blocking) call was canceled using WSACancelBlockingCall.
WSAEWOULDBLOCK	The socket is marked as nonblocking and SO_LINGER is set to a nonzero timeout value.
Remarks

This function closes a socket. More precisely, it releases the socket descriptor s, so that further references to s will fail with the error WSAENOTSOCK. If this is the last reference to the underlying socket, the associated naming information and queued data are discarded.

The semantics of closesocket are affected by the socket options SO_LINGER and SO_DONTLINGER as follows:

Option	Interval	Type of close	Wait for close?
SO_DONTLINGER	Don't care	Graceful	No
SO_LINGER	Zero	Hard	No
SO_LINGER	Nonzero	Graceful	Yes
If SO_LINGER is set (that is, if the l_onoff field of the linger structure is nonzero; see setsockopt) with a zero timeout interval (l_linger is zero), closesocket is not blocked even if queued data has not yet been sent or acknowledged. This is called a "hard" or "abortive" close, because the socket's virtual circuit is reset immediately, and any unsent data is lost. Any recv call on the remote side of the circuit will fail with WSAECONNRESET.

If SO_LINGER is set with a nonzero timeout interval, the closesocket call blocks until the remaining data has been sent or until the timeout expires. This is called a "graceful disconnect." Note that if the socket is set to nonblocking and SO_LINGER is set to a nonzero timeout, the call to closesocket will fail with an error of WSAEWOULDBLOCK.

If SO_DONTLINGER is set on a stream socket (that is, the l_onoff field of the linger structure is zero), the closesocket call will return immediately. However, any data queued for transmission will be sent if possible before the underlying socket is closed. This is also called a graceful disconnect. Note that in this case the Windows Sockets implementation may not release the socket and other resources for an arbitrary period, which may affect applications that expect to use all available sockets.

See Also

accept, socket, ioctlsocket, setsockopt, WSAAsyncSelect, WSACancelBlockingCall, WSAStartup


CloseSound

The CloseSound function has been deleted.

See Also

Beep, MessageBeep


CloseWindow
CloseWindow  QuickInfo  Overview  Group

The CloseWindow function minimizes (but does not destroy) the specified window.

BOOL CloseWindow(

HWND  hWnd	// handle of window to minimize
);
Parameters

hWnd

Identifies the window to be minimized.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The window is minimized by reducing it to the size of an icon and moving the window to the icon area of the screen. Windows displays the window's icon instead of the window and draws the window's title below the icon.

To destroy a window, an application must use the DestroyWindow function.

See Also

ArrangeIconicWindows, DestroyWindow, IsIconic, OpenIcon


CloseWindowStation [New - Windows NT]
CloseWindowStation  QuickInfo  Overview  Group

[New - Windows NT]

The CloseWindowStation function closes an open window station handle.

BOOL CloseWindowStation(

HWINSTA hWinSta	// handle of window station to close
);
Parameters

hWinSta

Identifies the window station to be closed. This handle is returned by the CreateWindowStation and OpenWindowStation functions.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The CloseWindowStation function will fail if the handle being closed is for the window station assigned to the calling process.

See Also

SetProcessWindowStation


ColorMatchToTarget [New - Windows 95]
ColorMatchToTarget  QuickInfo  Overview  Group

[New - Windows 95]

The ColorMatchToTarget function enables or disables preview for the specified device context. When preview is enabled, colors in subsequent output to the specified device context are displayed as they would appear on the target device. This is useful for checking how well the target maps the specified colors in an image. To enable preview, image color matching must be enabled for both the target and the preview device context.

BOOL ColorMatchToTarget(

HDC  hdc,
HDC  hdcTarget,
DWORD  uiAction
);
Parameters

hdc

Handle to the device context to use for preview, typically the display.

hdcTarget

Handle to the target device context, typically a printer.

uiAction

This parameter can have one of the following values:

Value	Meaning
CS_ENABLE	Enable preview; start matching colors through the target before displaying.
CS_DISABLE	Disable preview; stop matching colors through the target and restore the previous method for the preview device.
CS_DELETE_TRANSFORM	Disable preview and delete the color transformation used for previewing.
Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

If you use ColorMatchToTarget to enable preview, your next call to this function must be to disable preview; you must not nest calls to enable preview. While preview is enabled, any changes you make to the color space or gamut matching method are temporarily ignored, but take effect when preview is disabled.

This function creates a color transformation that translates colors for the target device first, then translates colors for the preview device. You need not delete the color transformation using CS_DELETE_TRANSFORM because the system deletes the transformation when either of the devices is removed from the system, or when the color space is deleted. However, if the transform is not going to be used again, an application can free up the space taken by it.


CombineRgn
CombineRgn  QuickInfo  Overview  Group

The CombineRgn function combines two regions and stores the result in a third region. The two regions are combined according to the specified mode.

int CombineRgn(

HRGN  hrgnDest,	// handle of destination region
HRGN  hrgnSrc1,	// handle of source region
HRGN  hrgnSrc2,	// handle of source region
int  fnCombineMode	// region combining mode
);
Parameters

hrgnDest

Identifies a new region with dimensions defined by combining two other regions. (This region must exist before CombineRgn is called.)

hrgnSrc1

Identifies the first of two regions to be combined.

hrgnSrc2

Identifies the second of two regions to be combined.

fnCombineMode

Specifies a mode indicating how the two regions will be combined. This parameter can be one of the following values:

Value	Description
RGN_AND	Creates the intersection of the two combined regions.
RGN_COPY	Creates a copy of the region identified by hrgnSrc1.
RGN_DIFF	Combines the parts of hrgnSrc1 that are not part of hrgnSrc2.
RGN_OR	Creates the union of two combined regions.
RGN_XOR	Creates the union of two combined regions except for any overlapping areas.
Return Value

The return value specifies the type of the resulting region. It can be one of the following values:

Value	Meaning
NULLREGION	The region is empty.
SIMPLEREGION	The region is a single rectangle.
COMPLEXREGION	The region is more than a single rectangle.
ERROR	No region is created.
Remarks

The three regions need not be distinct. For example, the hrgnSrc1 parameter can equal the hrgnDest parameter.

See Also

CreateEllipticRgn, CreateEllipticRgnIndirect, CreatePolygonRgn, CreatePolyPolygonRgn, CreateRectRgn, CreateRectRgnIndirect, CreateRoundRectRgn


CombineTransform
CombineTransform  QuickInfo  Overview  Group

The CombineTransform function concatenates two world-space to page-space transformations.

BOOL CombineTransform(

LPXFORM  lpxformResult,	// address of combined transformation
CONST XFORM *  lpxform1,	// address of first transformation
CONST XFORM *  lpxform2	// address of second transformation
);
Parameters

lpxformResult

Points to an XFORM structure that receives the combined transformation.

lpxform1

Points to an XFORM structure that identifies the first transformation.

lpxform2

Points to an XFORM structure that identifies the second transformation.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

Applying the combined transformation has the same effect as applying the first transformation and then applying the second transformation.

The three transformations need not be distinct. For example, lpxform1 can point to the same XFORM structure as lpxformResult.

See Also

GetWorldTransform, ModifyWorldTransform, SetWorldTransform, XFORM


CommandLineToArgvW
CommandLineToArgvW  QuickInfo  Overview  Group

The CommandLineToArgvW function parses a wide-character Unicode command-line string. It returns a pointer to a set of wide-character Unicode argument strings and a count of arguments, similar to the standard C run-time argv and argc values. The function provides a way to obtain a Unicode set of argv and argc values from a Unicode command-line string.

LPWSTR *  CommandLineToArgvW(

LPCWSTR   lpCmdLine,	// pointer to a command-line string
int *     pNumArgs	// pointer to a variable that receives the argument count
);
Parameters

lpCmdLine

Pointer to a null-terminated Unicode command-line string. An application will usually directly pass on the value returned by a call to GetCommandLineW.

*pNumArgs

Pointer to an integer variable that the function sets to the count of arguments parsed.

Return Value

If the function succeeds, the return value is a non-NULL pointer to the constructed argument list, which is a set of Unicode wide-character argument strings. It is the caller's responsibility to free the argument list's memory when it is no longer needed.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

See Also

GetCommandLine


CommConfigDialog [New - Windows 95]
CommConfigDialog  QuickInfo  Overview  Group

[New - Windows 95]

The CommConfigDialog function displays a driver-supplied configuration dialog box.

BOOL CommConfigDialog(

LPTSTR lpszName,	// address of device name string
HWND hWnd,	// handle of window
LPCOMMCONFIG lpCC,	// address of comm. configuration structure
);
Parameters

lpszName

Points to a null-terminated string specifying the name of the device for which a dialog box should be displayed.

hWnd

Identifies the window that owns the dialog box. This parameter can be any valid window handle, or it should be NULL if the dialog box is to have no owner.

lpCC

Points to a COMMCONFIG structure. This structure contains initial settings for the dialog box before the call, and changed values after the call.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

This function requires a dynamic-link library (DLL) provided by the communications hardware vendor.

See Also

COMMCONFIG


CommDlgExtendedError
CommDlgExtendedError  QuickInfo  Overview  Group

The CommDlgExtendedError function identifies the cause of the most recent error that has occurred during the execution of one of the following common dialog box functions:

ChooseColor	GetOpenFileName
ChooseFont	GetSaveFileName
FindText	PrintDlg
GetFileTitle	ReplaceText
DWORD CommDlgExtendedError(VOID)

Parameters

This function has no parameters.

Return Value

If the previous call to a common dialog box procedure succeeds, the return value is undefined. The return value is CDERR_DIALOGFAILURE if the dialog box could not be created. Otherwise, the return value is a nonzero integer that identifies an error condition.

Remarks

Following are the possible CommDlgExtendedError return values and their meanings:

Value	Meaning
CDERR_CHOOSECOLORCODES	Error codes for the Color common dialog box. these errors are in the range 0x5000 through 0x5FFF.
CDERR_DIALOGFAILURE	The common dialog box procedure's call to the DialogBox function failed. For example, this error occurs if the common dialog box call specifies an invalid window handle.
CDERR_FINDRESFAILURE	The common dialog box procedure failed to find a specified resource.
CDERR_GENERALCODES	General error codes for common dialog boxes. These errors are in the range 0x0000 through 0x0FFF.
CDERR_INITIALIZATION	The common dialog box procedure failed during initialization. This error often occurs when insufficient memory is available.
CDERR_LOADRESFAILURE	The common dialog box procedure failed to load a specified resource.
CDERR_LOADSTRFAILURE	The common dialog box procedure failed to load a specified string.
CDERR_LOCKRESFAILURE	The common dialog box procedure failed to lock a specified resource.
CDERR_MEMALLOCFAILURE	The common dialog box procedure was unable to allocate memory for internal structures.
CDERR_MEMLOCKFAILURE	The common dialog box procedure was unable to lock the memory associated with a handle.
CDERR_NOHINSTANCE	The ENABLETEMPLATE flag was specified in the Flags member of a structure for the corresponding common dialog box, but the application failed to provide a corresponding instance handle.
CDERR_NOHOOK	The ENABLEHOOK flag was specified in the Flags member of a structure for the corresponding common dialog box, but the application failed to provide a pointer to a corresponding hook function.
CDERR_NOTEMPLATE	The ENABLETEMPLATE flag was specified in the Flags member of a structure for the corresponding common dialog box, but the application failed to provide a corresponding template.
CDERR_REGISTERMSGFAIL	The RegisterWindowMessage function returned an error value when it was called by the common dialog box procedure.
CDERR_STRUCTSIZE	The lStructSize member of a structure for the corresponding common dialog box is invalid.
CFERR_CHOOSEFONTCODES	Error codes for the Font common dialog box. These errors are in the range 0x2000 through 0x2FFF.
CFERR_MAXLESSTHANMIN	The size specified in the nSizeMax member of the CHOOSEFONT structure is less than the size specified in the nSizeMin member.
CFERR_NOFONTS	No fonts exist.
FNERR_BUFFERTOOSMALL	The buffer for a filename is too small. (This buffer is pointed to by the lpstrFile member of the structure for a common dialog box.)
FNERR_FILENAMECODES	Error codes for the Open and Save As common dialog boxes. these errors are in the range 0x3000 through 0x3FFF.
FNERR_INVALIDFILENAME	A filename is invalid.
FNERR_SUBCLASSFAILURE	An attempt to subclass a list box failed because insufficient memory was available.
FRERR_BUFFERLENGTHZERO	A member in a structure for the corresponding common dialog box points to an invalid buffer.
FRERR_FINDREPLACECODES	Error codes for the Find and Replace common dialog boxes. these errors are in the range 0x4000 through 0x4FFF.
PDERR_CREATEICFAILURE	The PrintDlg function failed when it attempted to create an information context.
PDERR_DEFAULTDIFFERENT	An application called the PrintDlg function with the DN_DEFAULTPRN flag specified in the wDefault member of the DEVNAMES structure, but the printer described by the other structure members did not match the current default printer. (This error happens when an application stores the DEVNAMES structure and the user changes the default printer by using Control Panel.)
	To use the printer described by the DEVNAMES structure, the application should clear the DN_DEFAULTPRN flag and call the PrintDlg function again. To use the default printer, the application should replace the DEVNAMES structure (and the DEVMODE structure, if one exists) with NULL; this sets the default printer automatically.
PDERR_DNDMMISMATCH	The data in the DEVMODE and DEVNAMES structures describes two different printers.
PDERR_GETDEVMODEFAIL	The printer driver failed to initialize a DEVMODE structure. (This error value applies only to printer drivers written for Windows versions 3.0 and later.)
PDERR_INITFAILURE	The PrintDlg function failed during initialization, and there is no more specific extended error code to describe the failure. This is the generic default error code for the function.
PDERR_LOADDRVFAILURE	The PrintDlg function failed to load the device driver for the specified printer.
PDERR_NODEFAULTPRN	A default printer does not exist.
PDERR_NODEVICES	No printer drivers were found.
PDERR_PARSEFAILURE	The PrintDlg function failed to parse the strings in the [devices] section of the WIN.INI file.
PDERR_PRINTERCODES	Error codes for the Print common dialog box. These errors are in the range 0x1000 through 0x1FFF.
PDERR_PRINTERNOTFOUND	The [devices] section of the WIN.INI file did not contain an entry for the requested printer.
PDERR_RETDEFFAILURE	The PD_RETURNDEFAULT flag was specified in the Flags member of the PRINTDLG structure, but the hDevMode or hDevNames member was nonzero.
PDERR_SETUPFAILURE	The PrintDlg function failed to load the required resources.
See Also

ChooseColor, CHOOSECOLOR, ChooseFont, CHOOSEFONT, DEVMODE, DEVNAMES, DialogBox, FINDREPLACE, FindText, GetFileTitle, GetOpenFileName, GetSaveFileName, OPENFILENAME, PrintDlg, PRINTDLG, RegisterWindowMessage, ReplaceText


CompareFileTime
CompareFileTime  QuickInfo  Overview  Group

The CompareFileTime function compares two 64-bit file times.

LONG CompareFileTime(

CONST FILETIME *  lpFileTime1,	// address of first file time
CONST FILETIME *  lpFileTime2	// address of second file time
);
Parameters

lpFileTime1

Points to a FILETIME structure that specifies the first 64-bit file time.

lpFileTime2

Points to a FILETIME structure that specifies the second 64-bit file time.

Return Value

If the function succeeds, the return value is one of the following values:

Value	Meaning
−1	First file time is less than second file time.
0	First file time is equal to second file time.
+1	First file time is greater than second file time.
See Also

GetFileTime, FILETIME


CompareString
CompareString  QuickInfo  Overview  Group

The CompareString function compares two character strings, using the locale specified by the given identifier as the basis for the comparison.

int CompareString(

LCID  Locale,	// locale identifier
DWORD  dwCmpFlags,	// comparison-style options
LPCTSTR  lpString1,	// address of first string
int  cchCount1,	// size, in bytes or characters, of first string
LPCTSTR  lpString2,	// address of second string
int  cchCount2	// size, in bytes or characters, of second string
);
Parameters

Locale

Specifies the locale used for the comparison. This parameter can be one of the following predefined locale identifiers:

Value	Meaning
LOCALE_SYSTEM_DEFAULT	The system's default locale.
LOCALE_USER_DEFAULT	The current user's default locale.
This parameter can also be a locale identifier created by the MAKELCID macro.

dwCmpFlags

A set of flags that indicate how the function compares the two strings. By default, these flags are not set. This parameter can specify zero to get the default behavior, or it can be any combination of the following values:

Value	Meaning
NORM_IGNORECASE	Ignore case.
NORM_IGNOREKANATYPE	Do not differentiate between Hiragana and Katakana characters. Corresponding Hiragana and Katakana characters compare as equal.
NORM_IGNORENONSPACE	Ignore nonspacing characters.
NORM_IGNORESYMBOLS	Ignore symbols.
NORM_IGNOREWIDTH	Do not differentiate between a single-byte character and the same character as a double-byte character.
SORT_STRINGSORT	Treat punctuation the same as symbols.
lpString1

Points to the first string to be compared.

cchCount1

Specifies the size, in bytes (ANSI version) or characters (Unicode version), of the string pointed to by the lpString1 parameter. If this parameter is  − 1, the string is assumed to be null terminated and the length is calculated automatically.

lpString2

Points to the second string to be compared.

cchCount2

Specifies the size, in bytes (ANSI version) or characters (Unicode version), of the string pointed to by the lpString2 parameter. If this parameter is  − 1, the string is assumed to be null terminated and the length is calculated automatically.

Return Value

If the function succeeds, the return value is one of the following values:

Value	Meaning
1	The string pointed to by the lpString1 parameter is less in lexical value than the string pointed to by the lpString2 parameter.
2	The string pointed to by lpString1 is equal in lexical value to the string pointed to by lpString2.
3	The string pointed to by lpString1 is greater in lexical value than the string pointed to by lpString2.
If the function fails, the return value is zero. To get extended error information, call GetLastError. GetLastError may return one of the following error codes:

ERROR_INVALID_FLAGS

ERROR_INVALID_PARAMETER

Remarks

Notice that if the return value is 2, the two strings are "equal" in the collation sense, though not necessarily identical.

To maintain the C run-time convention of comparing strings, the value 2 can be subtracted from a non-zero return value. The meaning of < 0, ==0 and > 0 is then consistent with the C runtimes.

If the two strings are of different lengths, they are compared up to the length of the shortest one. If they are equal to that point, then the return value will indicate that the longer string is greater. For more information about locale identifiers, see Locale Identifiers.

Normally, strings are compared using what is called a "word sort" technique. In a word sort, all punctuation marks and other non-alphanumeric characters, except for the hyphen and the apostrophe, come before any alphanumeric character. The hyphen and the apostrophe are treated differently than the other non-alphanumeric symbols, in order to ensure that words such as "coop" and "co-op" stay together within a sorted list.

If the SORT_STRINGSORT flag is specified, strings are compared using what is called a "string sort" technique. In a string sort, the hyphen and apostrophe are treated just like any other non-alphanumeric symbols: they come before the alphanumeric symbols.

The following table shows a list of words sorted both ways:

Word Sort	String Sort		Word Sort	String Sort
billet	bill's		t-ant	t-ant
bills	billet		tanya	t-aria
bill's	bills		t-aria	tanya
cannot	can't		sued	sue's
cant	cannot		sues	sued
can't	cant		sue's	sues
con	co-op		went	we're
coop	con		were	went
co-op	coop		we're	were
The lstrcmp and lstrcmpi functions use a word sort. The CompareString and LCMapString functions default to using a word sort, but use a string sort if their caller sets the SORT_STRINGSORT flag.

The CompareString function is optimized to run at the highest speed when dwCmpFlags is set to 0 or NORM_IGNORECASE, and cchCount1 and cchCount2 have the value -1.

The CompareString function ignores Arabic Kashidas during the comparison. Thus, if two strings are identical save for the presence of Kashidas, CompareString returns a value of 2; the strings are considered "equal" in the collation sense, though they are not necessarily identical.

See Also

FoldString, GetSystemDefaultLCID, GetUserDefaultLCID, LCMapString, lstrcmp, lstrcmpi,MAKELCID


ConfigurePort
ConfigurePort  QuickInfo  Overview  Group

The ConfigurePort function displays the port-configuration dialog box for a port on the specified server.

BOOL ConfigurePort(

LPTSTR  pName,	// address of server name
HWND  hWnd,	// handle of parent window of the dialog box
LPTSTR  pPortName	// address of port name
);
Parameters

pName

Points to a null-terminated string that specifies the name of the server on which the given port exists. If this parameter is NULL, the port is local.

hWnd

Identifies the parent window of the port-configuration dialog box.

pPortName

Points to a null-terminated string that specifies the name of the port to be configured.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Before calling this function, an application should call the EnumPorts function to determine valid port names.

See Also

EnumPorts


connect
connect  QuickInfo

The Windows Sockets connect function establishes a connection to a peer.

int connect (

SOCKET s,
const struct sockaddr FAR * name,
int namelen
);
Parameters

s

A descriptor identifying an unconnected socket.

name

The name of the peer to which the socket is to be connected.

namelen

The length of the name.

Return Value

If no error occurs, connect returns zero. Otherwise, it returns SOCKET_ERROR, and a specific error code may be retrieved by calling WSAGetLastError.

On a blocking socket, the return value indicates success or failure of the connection attempt.

On a nonblocking socket, if the return value is SOCKET_ERROR, an application should call WSAGetLastError. If this indicates an error code of WSAEWOULDBLOCK, then your application can do one of the following:

•	Use select to determine the completion of the connection request by checking if the socket is writeable.

•	If your application is using the message-based WSAAsyncSelect to indicate interest in connection events, then your application will receive an FD_CONNECT message when the connect operation is complete.

Error Codes

WSANOTINITIALISED	A successful WSAStartup must occur before using this function.
WSAENETDOWN	The Windows Sockets implementation has detected that the network subsystem has failed.
WSAEADDRINUSE	The specified address is already in use.
WSAEINTR	The (blocking) call was canceled using WSACancelBlockingCall.
WSAEINPROGRESS	A blocking Windows Sockets call is in progress.
WSAEADDRNOTAVAIL	The specified address is not available from the local computer.
WSAEAFNOSUPPORT	Addresses in the specified family cannot be used with this socket.
WSAECONNREFUSED	The attempt to connect was forcefully rejected.
WSAEDESTADDREQ	A destination address is required.
WSAEFAULT	The namelen argument is incorrect.
WSAEINVAL	The socket is not already bound to an address.
WSAEISCONN	The socket is already connected.
WSAEMFILE	No more file descriptors are available.
WSAENETUNREACH	The network can't be reached from this host at this time.
WSAENOBUFS	No buffer space is available. The socket cannot be connected.
WSAENOTSOCK	The descriptor is not a socket.
WSAETIMEDOUT	Attempt to connect timed out without establishing a connection.
WSAEWOULDBLOCK	The socket is marked as nonblocking and the connection cannot be completed immediately. It is possible to select the socket while it is connecting by selecting it for writing.
Remarks

This function is used to create a connection to the specified foreign association. The parameter s specifies an unconnected datagram or stream socket If the socket is unbound, unique values are assigned to the local association by the system, and the socket is marked as bound. Note that if the address field of the name structure is all zeroes, connect will return the error WSAEADDRNOTAVAIL.

For stream sockets (type SOCK_STREAM), an active connection is initiated to the foreign host using name (an address in the name space of the socket). When the socket call completes successfully, the socket is ready to send and receive data.

For a datagram socket (type SOCK_DGRAM), a default destination is set, which will be used on subsequent send and recv calls.

See Also

accept, bind, getsockname, recv, socket, select, send, WSAAsyncSelect, WSACancelBlockingCall, WSAStartup


ConnectNamedPipe
ConnectNamedPipe  QuickInfo  Overview  Group

The ConnectNamedPipe function enables a named pipe server process to wait for a client process to connect to an instance of a named pipe. A client process connects by calling either the CreateFile or CallNamedPipe function.

BOOL ConnectNamedPipe(

HANDLE  hNamedPipe,	// handle of named pipe to connect
LPOVERLAPPED  lpOverlapped	// address of overlapped structure
);
Parameters

hNamedPipe

Identifies the server end of a named pipe instance. This handle is returned by the CreateNamedPipe function.

lpOverlapped

Points to an OVERLAPPED structure. This parameter can be NULL if an overlapped operation is not desired. For a description of how the wait mode and the overlapped mode of the hNamedPipe handle affect the behavior of this function, see the following Remarks section.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

A named pipe server process can use ConnectNamedPipe with a newly created pipe instance. It can also be used with an instance that was previously connected to another client process; in this case, the server process must first call the DisconnectNamedPipe function to disconnect the handle from the previous client before the handle can be reconnected to a new client. Otherwise, ConnectNamedPipe returns FALSE, and GetLastError returns ERROR_NO_DATA if the previous client has closed its handle or ERROR_PIPE_CONNECTED if it has not closed its handle.

The behavior of ConnectNamedPipe depends on two conditions: whether the pipe handle's wait mode is set to blocking or nonblocking and whether the function is set to execute synchronously or in overlapped mode. A server initially specifies a pipe handle's wait mode in the CreateNamedPipe function, and it can be changed by using the SetNamedPipeHandleState function. The function is executed as an overlapped operation if FILE_FLAG_OVERLAPPED was specified when the pipe handle was created and if the lpOverlapped parameter is not NULL. Otherwise, the function is executed synchronously. If an overlapped operation is used, the OVERLAPPED structure pointed to by lpOverlapped must contain a handle to a manual-reset event object (which the server can create by using the CreateEvent function).

If the lpOverlapped parameter is NULL, the system attempts to execute the operation synchronously. If the attempt succeeds, the function does not return until a client is connected or an error occurs. If the attempt fails, the function may fail in unpredictable ways. Successful synchronous operations result in the function returning TRUE if a client connects after the function is called. If a client connects before the function is called, the function returns FALSE and GetLastError returns ERROR_PIPE_CONNECTED. This can happen if a client connects in the interval between the call to CreateNamedPipe and the call to ConnectNamedPipe. In this situation, there is a good connection between client and server, even though the function returns FALSE.

If lpOverlapped is not NULL, the operation executes asynchronously. The function returns immediately with a return value of FALSE. If a client process connects before the function is called, GetLastError returns ERROR_PIPE_CONNECTED. Otherwise, GetLastError returns ERROR_IO_PENDING, which indicates that the operation is executing in the background. When this happens, the event object in the OVERLAPPED structure is set to the nonsignaled state before ConnectNamedPipe returns, and it is set to the signaled state when a client connects to this instance of the pipe. The server process can use any of the wait functions — WaitForSingleObject, WaitForMultipleObjects, WaitForSingleObjectEx, WaitForMultipleObjectsEx, or SleepEx — to determine when the state of the event object is signaled, and it can then use the GetOverlappedResult function to determine the results of the ConnectNamedPipe operation.

If the specified pipe handle is in nonblocking mode, ConnectNamedPipe always returns immediately. In nonblocking mode, ConnectNamedPipe returns TRUE the first time it is called for a pipe instance that is disconnected from a previous client. This indicates that the pipe is now available to be connected to a new client process. In all other situations when the pipe handle is in nonblocking mode, ConnectNamedPipe returns FALSE. In these situations, GetLastError returns ERROR_PIPE_LISTENING if no client is connected, ERROR_PIPE_CONNECTED if a client is connected, and ERROR_NO_DATA if a previous client has closed its pipe handle but the server has not disconnected. Note that a good connection between client and server exists only after the ERROR_PIPE_CONNECTED error is received.

Note that nonblocking mode is supported for compatibility with Microsoft LAN Manager version 2.0, and it should not be used to achieve asynchronous input and output (I/O) with named pipes.

See Also

CallNamedPipe, CreateEvent, CreateFile, CreateNamedPipe, DisconnectNamedPipe, GetOverlappedResult, SetNamedPipeHandleState, SleepEx, WaitForMultipleObjects, WaitForMultipleObjectsEx, WaitForSingleObject, WaitForSingleObjectEx, OVERLAPPED


ConnectToPrinterDlg
ConnectToPrinterDlg  QuickInfo  Overview  Group

The ConnectToPrinterDlg function displays a dialog box that lets users browse and connect to printers on a network. If the user selects a printer, the function attempts to create a connection to it; if a suitable driver is not installed on the server, the user is given the option of creating a printer locally.

HANDLE ConnectToPrinterDlg (

HWND  hwnd,	// handle of parent window of dialog box
DWORD  Flags	// reserved for future use, must be zero
);
Parameters

hwnd

Specifies the parent window of the dialog box.

Flags

This parameter is reserved for future use. Set it to zero.

Return Value

If the function succeeds and the user selects a printer, the return value is a handle to the selected printer.

If the function fails, or the user cancels the dialog box without selecting a printer, the return value is NULL.

Remarks

The ConnectToPrinterDlg function attempts to create a connection to the selected printer. However, if the server on which the printer resides does not have a suitable driver installed, the function offers the user the option of creating a printer locally. A calling application can determine whether the function has created a printer locally by calling GetPrinter with a PRINTER_INFO_2 structure, then examining that structure's Attributes member.

An application should call DeletePrinter to delete a local printer. An application should call DeletePrinterConnection to delete a connection to a printer.

See Also

AddPrinterConnection, ClosePrinter, DeletePrinter, DeletePrinterConnection, GetPrinter, PRINTER_INFO_2


ContinueDebugEvent
ContinueDebugEvent  QuickInfo  Overview  Group

The ContinueDebugEvent function enables a debugger to continue a thread that previously reported a debugging event.

BOOL ContinueDebugEvent(

DWORD  dwProcessId,	// process to continue
DWORD  dwThreadId,	// thread to continue
DWORD  dwContinueStatus	// continuation status
);
Parameters

dwProcessId

Identifies the process to continue.

dwThreadId

Identifies the thread to continue. The combination of process identifier and thread identifier must identify a thread that has previously reported a debugging event.

dwContinueStatus

Specifies how to continue the thread that reported the debugging event.

If the DBG_CONTINUE flag is specified for this parameter and the thread specified by the dwThreadId parameter previously reported an EXCEPTION_DEBUG_EVENT debugging event, the function stops all exception processing and continues the thread. For any other debugging event, this flag simply continues the thread.

If the DBG_EXCEPTION_NOT_HANDLED flag is specified for this parameter and the thread specified by dwThreadId previously reported an EXCEPTION_DEBUG_EVENT debugging event, the function continues exception processing. If this is a first-chance exception event, the search and dispatch logic of the structured exception handler is used; otherwise, the process is terminated. For any other debugging event, this flag simply continues the thread.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Only the thread that created dwProcessId with the CreateProcess function can call ContinueDebugEvent.

After this function succeeds, the specified thread continues. Depending on the debugging event previously reported by the thread, different actions occur. If the continued thread previously reported an EXIT_THREAD_DEBUG_EVENT debugging event, ContinueDebugEvent closes the handle the debugger has to the thread. If the continued thread previously reported an EXIT_PROCESS_DEBUG_EVENT debugging event, ContinueDebugEvent closes the handles the debugger has to the process and to the thread.

See Also

CreateProcess


ControlService
ControlService  QuickInfo  Overview  Group

The ControlService function sends a control code to a Win32 service.

BOOL ControlService(

SC_HANDLE  hService,	// handle of service
DWORD  dwControl,	// control code
LPSERVICE_STATUS  lpServiceStatus	// address of service status structure
);
Parameters

hService

Identifies the service. This handle is returned by the OpenService or CreateService function. The access required for this handle depends on the dwControl code requested.

dwControl

Specifies the requested control code. This value can be one of the standard control codes in the table, or it can be a user-defined control code in the range of 128 to 255, inclusive. For user-defined control codes, the hService handle must have SERVICE_USER_DEFINE_CONTROL access, and the service defines the action associated with the control code.

Value	Meaning
SERVICE_CONTROL_STOP
	Requests the service to stop. The hService handle must have SERVICE_STOP access.
SERVICE_CONTROL_PAUSE
	Requests the service to pause. The hService handle must have SERVICE_PAUSE_CONTINUE access.
SERVICE_CONTROL_CONTINUE
	Requests the paused service to resume. The hService handle must have SERVICE_PAUSE_CONTINUE access.
SERVICE_CONTROL_INTERROGATE
	Requests the service to update immediately its current status information to the service control manager. The hService handle must have SERVICE_INTERROGATE access.
SERVICE_CONTROL_SHUTDOWN
	The ControlService function fails if this control code is specified.
lpServiceStatus

Points to a SERVICE_STATUS structure where the latest status information of the service is returned. The information returned reflects the most recent status reported by the service to the service control manager.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Errors

The following error codes may be set by the service control manager. Other error codes may be set by the registry functions that are called by the service control manager.

Value	Meaning
ERROR_ACCESS_DENIED
	The specified handle was not opened with the necessary access.
ERROR_DEPENDENT_SERVICES_RUNNING
	The service cannot be stopped because other running services are dependent on it.
ERROR_INVALID_SERVICE_CONTROL
	The requested control code is not valid, or it is unacceptable to the service.
ERROR_SERVICE_CANNOT_ACCEPT_CTRL
	The requested control code cannot be sent to the service because the state of the service is SERVICE_STOPPED, SERVICE_START_PENDING, or SERVICE_STOP_PENDING.
ERROR_SERVICE_NOT_ACTIVE
	The service has not been started.
ERROR_SERVICE_REQUEST_TIMEOUT
	The service did not respond to the start request in a timely fashion.
Remarks

The ControlService function asks the service control manager to send the requested control code to the service. The service control manager sends the code if the service accepts the control and if the service is in a controllable state. The QueryServiceStatus or ControlService function returns a SERVICE_STATUS structure whose dwCurrentState and dwControlsAccepted members indicate the current state and controls accepted by a running Win32 service.

All running services accept the SERVICE_CONTROL_INTERROGATE control code by default. Each service specifies the other control codes that it accepts when it calls the SetServiceStatus function to report its status.

The following table shows the action of the service control manager in each of the possible service states:

Service state	Stop	Other controls
STOPPED	(c)	(c)
STOP_PENDING	(b)	(b)
START_PENDING	(a)	(b)
RUNNING	(a)	(a)
CONTINUE_PENDING	(a)	(a)
PAUSE_PENDING	(a)	(a)
PAUSED	(a)	(a)
(a) If the service accepts this control code, send the request to the service; otherwise, ControlService returns FALSE and GetLastError returns ERROR_INVALID_SERVICE_CONTROL.
(b) The service is not in a controllable state, so ControlService returns FALSE and GetLastError returns ERROR_SERVICE_CANNOT_ACCEPT_CTRL.
(c) The service is not in a controllable state, so ControlService returns FALSE and GetLastError returns ERROR_SERVICE_NOT_ACTIVE.
See Also

CreateService, OpenService, QueryServiceStatus, SetServiceStatus, SERVICE_STATUS


ConvertDefaultLocale
ConvertDefaultLocale  QuickInfo  Overview  Group

The ConvertDefaultLocale function converts a special default locale value to an actual locale identifier.

LCID ConvertDefaultLocale(

LCID  Locale	// special default locale value to be converted
);
Parameters

Locale

A special default locale value that the function converts to an actual locale identifier.

The following list shows the special default locale values:

Value	Description
LOCALE_SYSTEM_DEFAULT	The system's default locale.
LOCALE_USER_DEFAULT	The current user's default locale.
zero	The language-neutral default locale. This is equivalent to the locale identifier created by calling the MAKELCID macro with a language identifier consisting of the LANG_NEUTRAL and SUBLANG_NEUTRAL values.
Any sublanguage neutral default locale	A locale identifier constructed by calling MAKELCID with a language identifier consisting of a primary language value, such as LANG_ENGLISH, and the SUBLANG_NEUTRAL value.
Return Value

If the function succeeds, the return value is the appropriate actual locale identifier.

If the function fails, the return value is the Locale parameter. The function fails when Locale is not one of the special default locale values listed above.

Remarks

A call to ConvertDefaultLocale(LOCALE_SYSTEM_DEFAULT) is equivalent to a call to GetSystemDefaultLCID. A call to ConvertDefaultLocale(LOCALE_USER_DEFAULT) is equivalent to a call to GetUserDefaultLCID.

For more information about locale identifiers, see Locales and Language Identifiers.

See Also

GetSystemDefaultLCID, GetUserDefaultLCID


CopyAcceleratorTable
CopyAcceleratorTable  QuickInfo  Overview  Group

The CopyAcceleratorTable function copies the specified accelerator table. This function is used to obtain the accelerator-table data that corresponds to an accelerator-table handle, or to determine the size of the accelerator-table data.

int CopyAcceleratorTable(

HACCEL  hAccelSrc,	// handle of accelerator table to copy
LPACCEL  lpAccelDst,	// address of structure receiving copy
int  cAccelEntries	// number of entries in table being copied
);
Parameters

hAccelSrc

Identifies the accelerator table to copy.

lpAccelDst

Points to an array of ACCEL structures where the accelerator-table information is to be copied.

cAccelEntries

Specifies the number of ACCEL structures to copy to the buffer pointed to by the lpAccelDst parameter.

Return Value

If lpAccelDst is NULL, the return value specifies the number of accelerator-table entries in the original table. Otherwise, it specifies the number of accelerator-table entries that were copied.

See Also

ACCEL, CreateAcceleratorTable, DestroyAcceleratorTable, LoadAccelerators, TranslateAccelerator


CopyCursor
CopyCursor  QuickInfo  Overview  Group

The CopyCursor function copies a cursor.

HCURSOR CopyCursor(

HCURSOR  pcur	// handle of cursor to copy
);
Parameters

pcur

Identifies the cursor to be copied.

Return Value

If the function succeeds, the return value is the handle of the duplicate cursor.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

CopyCursor enables an application or dynamic-link library (DLL) to obtain the handle of a cursor shape owned by another module. Then if the other module is freed, the application is still able to use the cursor shape.

See Also

CopyIcon, GetCursor, SetCursor, ShowCursor


CopyEnhMetaFile
CopyEnhMetaFile  QuickInfo  Overview  Group

The CopyEnhMetaFile function copies the contents of an enhanced-format metafile to a specified file.

HENHMETAFILE CopyEnhMetaFile(

HENHMETAFILE  hemfSrc,	// handle of an enhanced metafile
LPCTSTR  lpszFile	// address of a filename string
);
Parameters

hemfSrc

Identifies the source-enhanced metafile.

lpszFile

Points to the name of the destination file. If this parameter is NULL, the source metafile is copied to memory.

Return Value

If the function succeeds, the return value is a handle of the copy of the enhanced metafile.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

Where text arguments must use Unicode characters, use this function as a wide-character function. Where text arguments must use characters from the Windows 3.x character set, use this function as an ANSI function.

Applications can use metafiles stored in memory for temporary operations.

When the application no longer needs the enhanced-metafile handle, it should delete the handle by calling the DeleteEnhMetaFile function.

See Also

DeleteEnhMetaFile


CopyFile
CopyFile  QuickInfo  Overview  Group

The CopyFile function copies an existing file to a new file.

BOOL CopyFile(

LPCTSTR  lpExistingFileName,	// address of name of an existing file
LPCTSTR  lpNewFileName,	// address of filename to copy to
BOOL  bFailIfExists	// flag for operation if file exists
);
Parameters

lpExistingFileName

Points to a null-terminated string that specifies the name of an existing file.

lpNewFileName

Points to a null-terminated string that specifies the name of the new file.

bFailIfExists

Specifies how this operation is to proceed if a file of the same name as that specified by lpNewFileName already exists. If this parameter is TRUE and the new file already exists, the function fails. If this parameter is FALSE and the new file already exists, the function overwrites the existing file and succeeds.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Security attributes for the existing file are not copied to the new file.

File attributes (FILE_ATTRIBUTE_*) for the existing file are copied to the new file. For example, if an existing file has the FILE_ATTRIBUTE_READONLY file attribute, a copy created through a call to CopyFile will also have the FILE_ATTRIBUTE_READONLY file attribute. For further information on file attributes, see CreateFile.

See Also

CreateFile, MoveFile


CopyIcon
CopyIcon  QuickInfo  Overview  Group

The CopyIcon function copies the specified icon from another module to the current module.

HICON CopyIcon(

HICON  hIcon	// handle of icon to copy
);
Parameters

hIcon

Identifies the icon to be copied.

Return Value

If the function succeeds, the return value is the handle of the duplicate icon.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

The CopyIcon function enables an application or dynamic-link library (DLL) to get its own handle of an icon owned by another module. If the other module is freed, the application icon will still be able to use the icon.

See Also

CopyCursor, DrawIcon, DrawIconEx


CopyImage [New - Windows 95]
CopyImage  QuickInfo  Overview  Group

The CopyImage function creates a new image (icon, cursor, or bitmap) and copies the attributes of the given image to the new one. If necessary, the function stretches the bits to fit the desired size of the new image.

HANDLE CopyImage(

HANDLE  hImage,	// handle of the image to copy
UINT  uType,	// type of image to copy
int  cxDesired,	// desired width of new image
int  cyDesired,	// desired height of new image
UINT  fuFlags	// copy flags
);
Parameters

hinst

Identifies an instance of the module that contains the image to be copied.

uType

Specifies the type of image to be copied. This parameter can be one of the following values:

Value	Meaning
IMAGE_BITMAP	Copies a bitmap.
IMAGE_CURSOR	Copies a cursor.
IMAGE_ICON	Copies an icon.
cxDesired

Specifies the desired width, in pixels, of the image.

cyDesired

Specifies the desired height, in pixels, of the image.

fuFlags

Specifies a combination of the following values:

Value	Meaning
LR_COPYDELETEORG	Deletes the original image after creating the copy.
LR_COPYRETURNORG	Creates an exact copy of the image, ignoring the cxDesired and cyDesired parameters.
LR_MONOCHROME	Creates a new monochrome image.
LR_COPYFROMRESOURCE	Windows 95 only: Tries to reload an icon or cursor resource from the original resource file rather than simply copying the current image. This is useful for creating a different-sized copy when the resource file contains multiple sizes of the resource. Without this flag, CopyImage stretches the original image to the new size. If this flag is set, CopyImage uses the size in the resource file closest to the desired size. This will succeed only if hImage was loaded by LoadIcon or LoadCursor, or by LoadImage with the LR_SHARED flag.
Return Value

If the function succeeds, the return value is the handle of the newly created image.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

See Also

LoadImage


CopyLZFile
CopyLZFile  QuickInfo  Overview  Group

The CopyLZFile function is obsolete. It is provided only for compatibility with 16-bit versions of Windows. For Win32-based applications, use the LZCopy function.


CopyMemory
CopyMemory  QuickInfo  Overview  Group

The CopyMemory function copies a block of memory from one location to another.

VOID CopyMemory (

PVOID  Destination,	// address of copy destination
CONST VOID *  Source,	// address of block to copy
DWORD  Length	// size, in bytes, of block to copy
);
Parameters

Destination

Points to the starting address of the copied block's destination.

Source

Points to the starting address of the block of memory to copy.

Length

Specifies the size, in bytes, of the block of memory to copy.

Return Value

This function has no return value.

Remarks

If the source and destination blocks overlap, the results are undefined. For overlapped blocks, use the MoveMemory function.

See Also

FillMemory, MoveMemory, ZeroMemory


CopyMetaFile
CopyMetaFile  QuickInfo  Overview  Group

The CopyMetaFile function copies the content of a Windows-format metafile to the specified file.

This function is provided for compatibility with 16-bit versions of Windows. Win32-based applications should use the CopyEnhMetaFile function.

HMETAFILE CopyMetaFile(

HMETAFILE  hmfSrc,	// handle of a Windows-format metafile
LPCTSTR  lpszFile	// address of a filename string
);
Parameters

hmfSrc

Identifies the source Windows-format metafile.

lpszFile

Points to the name of the destination file. If this parameter is NULL, the source metafile is copied to memory.

Return Value

If the function succeeds, the return value is a handle of the copy of the Windows-format metafile.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

The CopyMetaFile function supports only applications designed for Windows version 3.x. It does not record or play back the new graphics device interface functions, such as PolyBezier.

Where text arguments must use Unicode characters, use this function as a wide-character function. Where text arguments must use characters from the Windows 3.x character set, use this function as an ANSI function.

When the application no longer needs the Windows-format metafile handle, it should delete the handle by calling the DeleteMetaFile function.

See Also

DeleteMetaFile


CopyRect
CopyRect  QuickInfo  Overview  Group

The CopyRect function copies the coordinates of one rectangle to another.

BOOL CopyRect(

LPRECT  lprcDst,	// address of structure for destination rectangle
CONST RECT  *lprcSrc	// address of structure with source rectangle
);
Parameters

lprcDst

Points to the RECT structure that will receive the logical coordinates of the source rectangle.

lprcSrc

Points to the RECT structure whose coordinates are to be copied.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

RECT, SetRect, SetRectEmpty


CopySid
CopySid  QuickInfo  Overview  Group

The CopySid function copies a security identifier (SID) to a buffer.

BOOL CopySid(

DWORD  nDestinationSidLength,	// size of buffer for copied SID
PSID  pDestinationSid,	// address of buffer for copied SID
PSID  pSourceSid	// address of source SID
);
Parameters

nDestinationSidLength

Specifies the length, in bytes, of the buffer receiving the copy of the SID.

pDestinationSid

Points to a buffer receiving a copy of the source SID structure.

pSourceSid

Points to a SID structure the function copies to the buffer pointed to by the pDestinationSid parameter.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

An application can use the CopySid function to make a copy of a SID in an access token (in a TOKEN_GROUPS structure, for instance) to use in an access-control entry.

See Also

AllocateAndInitializeSid, EqualSid, GetLengthSid, GetSidIdentifierAuthority, GetSidLengthRequired, GetSidSubAuthority, GetSidSubAuthorityCount, InitializeSid, IsValidSid, SID


CountClipboardFormats
CountClipboardFormats  QuickInfo  Overview  Group

The CountClipboardFormats function retrieves the number of different data formats currently on the clipboard.

int CountClipboardFormats(VOID)

Parameters

This function has no parameters.

Return Value

If the function succeeds, the return value is the number of different data formats currently on the clipboard.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

See Also

EnumClipboardFormats, RegisterClipboardFormat


CountVoiceNotes

The CountVoiceNotes function has been deleted.

See Also

Beep, MessageBeep


CPlApplet
CPlApplet  Overview  Group

The CPlApplet function is a library-defined callback function that serves as the entry point for a Control Panel application.

LONG APIENTRY CPlApplet(

HWND  hwndCPl,	// handle of Control Panel window
UINT  uMsg,	// message
LONG  lParam1,	// first message parameter
LONG  lParam2	// second message parameter
);
Parameters

hwndCPl

Identifies the main window of the controlling application.

uMsg

Specifies the message being sent to the Control Panel application.

lParam1

Specifies additional message-specific information.

lParam2

Specifies additional message-specific information.

Return Value

The return value depends on the message. For more information, see the descriptions of the individual Control Panel messages.

Remarks

Use the hwndCPl parameter for dialog boxes or other windows that require a handle of a parent window.


CreateAcceleratorTable
CreateAcceleratorTable  QuickInfo  Overview  Group

The CreateAcceleratorTable function creates an accelerator table.

HACCEL CreateAcceleratorTable(

LPACCEL  lpaccl,	// address of structure array with accelerator data
int  cEntries	// number of structures in the array
);
Parameters

lpaccl

Points to an array of ACCEL structures that describes the accelerator table.

cEntries

Specifies the number of ACCEL structures in the array.

Return Value

If the function succeeds, the return value is the handle of the created accelerator table; otherwise, it is NULL.

Remarks

Before an application closes, it must use the DestroyAcceleratorTable function to destroy each accelerator table that it created by using the CreateAcceleratorTable function.

See Also

ACCEL, CopyAcceleratorTable, DestroyAcceleratorTable, LoadAccelerators, TranslateAccelerator


CreateBitmap
CreateBitmap  QuickInfo  Overview  Group

The CreateBitmap function creates a bitmap with the specified width, height, and color format (color planes and bits per pixel).

HBITMAP CreateBitmap(

int  nWidth,	// bitmap width, in pixels
int  nHeight,	// bitmap height, in pixels
UINT  cPlanes,	// number of color planes used by device
UINT  cBitsPerPel,	// number of bits required to identify a color
CONST VOID  *lpvBits	// address of array containing color data
);
Parameters

nWidth

Specifies the bitmap width, in pixels.

nHeight

Specifies the bitmap height, in pixels.

cPlanes

Specifies the number of color planes used by the device.

cBitsPerPel

Specifies the number of bits required to identify the color of a single pixel.

lpvBits

Points to an array of color data used to set the colors in a rectangle of pixels. Each scan line in the rectangle must be word aligned (scan lines that are not word aligned must be padded with zeros). If this parameter is NULL, the new bitmap is undefined.

Return Value

If the function succeeds, the return value is a handle of a bitmap.

If the function fails, the return value is NULL.

Remarks

After a bitmap is created, it can be selected into a device context by calling the SelectObject function.

While the CreateBitmap function can be used to create color bitmaps, for performance reasons applications should use CreateBitmap to create monochrome bitmaps and CreateCompatibleBitmap to create color bitmaps. When a color bitmap returned from CreateBitmap is selected into a device context, Windows must ensure that the bitmap matches the format of the device context it is being selected into. Since CreateCompatibleBitmap takes a device context, it returns a bitmap that has the same format as the specified device context. Because of this, subsequent calls to SelectObject are faster than with a color bitmap returned from CreateBitmap.

If the bitmap is monochrome, zeros represent the foreground color and ones represent the background color for the destination device context.

If an application sets the nWidth or nHeight parameters to zero, CreateBitmap returns the handle of a 1- by 1-pixel, monochrome bitmap.

When you no longer need the bitmap, call the DeleteObject function to delete it.

See Also

CreateBitmapIndirect, CreateCompatibleBitmap, CreateDIBitmap, DeleteObject, GetBitmapBits, SelectObject, SetBitmapBits


CreateBitmapIndirect
CreateBitmapIndirect  QuickInfo  Overview  Group

The CreateBitmapIndirect function creates a bitmap with the specified width, height, and color format (color planes and bits per pixel).

HBITMAP CreateBitmapIndirect(

CONST BITMAP *lpbm	// address of the bitmap data
);
Parameters

lpbm

Points to a BITMAP structure that contains information about the bitmap. If an application sets the bmWidth or bmHeight members to zero, CreateBitmapIndirect returns the handle of a 1- by 1-pixel, monochrome bitmap.

Return Value

If the function succeeds, the return value is a handle of the bitmap.

If the function fails, the return value is NULL.

Remarks

After a bitmap is created, it can be selected into a device context by calling the SelectObject function.

While the CreateBitmapIndirect function can be used to create color bitmaps, for performance reasons applications should use CreateBitmapIndirect to create monochrome bitmaps and CreateCompatibleBitmap to create color bitmaps. When a color bitmap returned from CreateBitmapIndirect is selected into a device context, Windows must ensure that the bitmap matches the format of the device context it is being selected into. Since CreateCompatibleBitmap takes a device context, it returns a bitmap that has the same format as the specified device context. Because of this, subsequent calls to SelectObject are faster than with a color bitmap returned from CreateBitmapIndirect.

If the bitmap is monochrome, zeros represent the foreground color and ones represent the background color for the destination device context.

When you no longer need the bitmap, call the DeleteObject function to delete it.

See Also

BitBlt, BITMAP, CreateBitmap, CreateCompatibleBitmap, CreateDIBitmap, DeleteObject, SelectObject


CreateBrushIndirect
CreateBrushIndirect  QuickInfo  Overview  Group

The CreateBrushIndirect function creates a logical brush that has the specified style, color, and pattern.

HBRUSH CreateBrushIndirect(

CONST LOGBRUSH *  lplb	// address of structure describing brush
);
Parameters

lplb

Points to a LOGBRUSH structure that contains information about the brush.

Return Value

If the function succeeds, the return value identifies a logical brush.

If the function fails, the return value is NULL.

Remarks

A brush is a bitmap that Windows uses to paint the interiors of filled shapes.

After an application creates a brush by calling CreateBrushIndirect, it can select it into any device context by calling the SelectObject function.

A brush created by using a monochrome bitmap (one color plane, one bit per pixel) is drawn using the current text and background colors. Pixels represented by a bit set to 0 are drawn with the current text color; pixels represented by a bit set to 1 are drawn with the current background color.

If the lbStyle member of the LOGBRUSH structure pointed to by lplb is BS_PATTERN, the bitmap pointed to by the lbHatch member of that structure cannot be a DIB section. A DIB section is a bitmap created by CreateDibSection. If that bitmap is a DIB section, the CreateBrushIndirect function fails.

When you no longer need the brush, call the DeleteObject function to delete it.

See Also

CreateDibSection, DeleteObject, GetBrushOrgEx, LOGBRUSH, SelectObject, SetBrushOrgEx


CreateCaret
CreateCaret  QuickInfo  Overview  Group

The CreateCaret function creates a new shape for the system caret and assigns ownership of the caret to the specified window. The caret shape can be a line, a block, or a bitmap.

BOOL CreateCaret(

HWND  hWnd,	// handle of owner window
HBITMAP  hBitmap,	// handle of bitmap for caret shape
int  nWidth,	// caret width
int  nHeight	// caret height
);
Parameters

hWnd

Identifies the window that owns the caret.

hBitmap

Identifies the bitmap that defines the caret shape. If this parameter is NULL, the caret is solid. If this parameter is (HBITMAP) 1, the caret is gray. If this parameter is a bitmap handle, the caret is the specified bitmap. The bitmap handle must have been created by the CreateBitmap, CreateDIBitmap, or LoadBitmap function.

If hBitmap is a bitmap handle, CreateCaret ignores the nWidth and nHeight parameters; the bitmap defines its own width and height.

nWidth

Specifies the width of the caret in logical units. If this parameter is zero, the width is set to the system-defined window border width. If hBitmap is a bitmap handle, CreateCaret ignores this parameter.

nHeight

Specifies the height, in logical units, of the caret. If this parameter is zero, the height is set to the system-defined window border height. If hBitmap is a bitmap handle, CreateCaret ignores this parameter.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The nWidth and nHeight parameters specify the caret's width and height, in logical units; the exact width and height, in pixels, depend on the window's mapping mode.

CreateCaret automatically destroys the previous caret shape, if any, regardless of the window that owns the caret. The caret is hidden until the application calls the ShowCaret function to make the caret visible.

The caret is a shared resource; there is only one caret in the system. A window should create a caret only when it has the keyboard focus or is active. The window should destroy the caret before losing the keyboard focus or becoming inactive.

You can retrieve the width or height of the system's window border by using the GetSystemMetrics function, specifying the SM_CXBORDER and SM_CYBORDER values. Using the window border width or height guarantees that the caret will be visible on a high-resolution screen.

See Also

CreateBitmap, CreateDIBitmap, DestroyCaret, GetSystemMetrics, HideCaret, LoadBitmap, ShowCaret


CreateColorSpace [New - Windows 95]
CreateColorSpace  QuickInfo  Overview  Group

[New - Windows 95]

The CreateColorSpace function creates a logical color space.

HCOLORSPACE CreateColorSpace(

LPLOGCOLORSPACE  lpLogColorSpace
);
Parameters

lpLogColorSpace

Pointer to the LOGCOLORSPACE structure.

Return Value

If the function succeeds, the return value is a handle that identifies a logical color space.

If the function fails, the return value is NULL.

Remarks

When you no longer need the color space, call the DeleteObject function to delete it.

See Also

DeleteObject, LOGCOLORSPACE


CreateCompatibleBitmap
CreateCompatibleBitmap  QuickInfo  Overview  Group

The CreateCompatibleBitmap function creates a bitmap compatible with the device that is associated with the specified device context.

HBITMAP CreateCompatibleBitmap(

HDC  hdc,	// handle of device context
int  nWidth,	// width of bitmap, in pixels
int  nHeight	// height of bitmap, in pixels
);
Parameters

hdc

Identifies a device context.

nWidth

Specifies the bitmap width, in pixels.

nHeight

Specifies the bitmap height, in pixels.

Return Value

If the function succeeds, the return value is a handle of the bitmap.

If the function fails, the return value is NULL.

Remarks

The color format of the bitmap created by this function matches the color format of the device identified by the hdc parameter. This bitmap can be selected into any memory device context that is compatible with the original device.

Because memory device contexts allow both color and monochrome bitmaps, the format of the bitmap returned by the CreateCompatibleBitmap function differs when the specified device context is a memory device context. However, a compatible bitmap that was created for a nonmemory device context always possesses the same color format and uses the same color palette as the specified device context.

If an application sets the nWidth or nHeight parameters to zero, CreateCompatibleBitmap returns the handle of a 1- by 1-pixel, monochrome bitmap.

If a DIB section, which is a bitmap created by the CreateDIBSection function, is selected into the device context identified by the hdc parameter, the CreateCompatibleBitmap function creates a DIB section.

When you no longer need the bitmap, call the DeleteObject function to delete it.

See Also

CreateDIBSection, DeleteObject, SelectObject


CreateCompatibleDC
CreateCompatibleDC  QuickInfo  Overview  Group

The CreateCompatibleDC function creates a memory device context (DC) compatible with the specified device.

HDC CreateCompatibleDC(

HDC  hdc	// handle of memory device context
);
Parameters

hdc

Identifies the device context. If this handle is NULL, the function creates a memory device context compatible with the application's current screen.

Return Value

If the function succeeds, the return value is the handle of a memory device context.

If the function fails, the return value is NULL.

Remarks

Before an application can use a memory device context for drawing operations, it must select a bitmap of the correct width and height into the device context. Once a bitmap has been selected, the device context can be used to prepare images that will be copied to the screen or printed.

This function can only be used with devices that support raster operations. An application can determine whether a device supports these operations by calling the GetDeviceCaps function.

When you no longer need the memory device context, call the DeleteDC function to delete it.

See Also

CreateCompatibleBitmap, DeleteDC, GetDeviceCaps


CreateConsoleScreenBuffer
CreateConsoleScreenBuffer  QuickInfo  Overview  Group

The CreateConsoleScreenBuffer function creates a console screen buffer and returns a handle of it.

HANDLE CreateConsoleScreenBuffer(

DWORD  dwDesiredAccess,	// access flag
DWORD  dwShareMode,	// buffer share mode
LPSECURITY_ATTRIBUTES  *lpSecurityAttributes,	// address of security attributes
DWORD  dwFlags,	// type of buffer to create
LPVOID  lpScreenBufferData	// reserved
);
Parameters

dwDesiredAccess

Specifies the desired access to the console screen buffer. This parameter can be one or both of the following values:

Value	Meaning
GENERIC_READ	Requests read access to the console screen buffer, enabling the process to read data from the buffer.
GENERIC_WRITE	Requests write access to the console screen buffer, enabling the process to write data to the buffer.
dwShareMode

Specifies how this console screen buffer can be shared. This parameter can be zero, indicating that the buffer cannot be shared, or it can be one or both of the following two values:

Value	Meaning
FILE_SHARE_READ	Other open operations can be performed on the console screen buffer for read access.
FILE_SHARE_WRITE	Other open operations can be performed on the console screen buffer for write access.
*lpSecurityAttributes

Points to a SECURITY_ATTRIBUTES structure that specifies the security attributes for the console screen buffer.

dwFlags

Specifies the type of console screen buffer to create. The only currently supported screen buffer type is CONSOLE_TEXTMODE_BUFFER.

lpScreenBufferData

Reserved for possible future use; should be NULL.

Return Value

If the function succeeds, the return value is a handle of the new console screen buffer.

If the function fails, the return value is INVALID_HANDLE_VALUE. To get extended error information, call GetLastError.

Remarks

A console can have multiple screen buffers but only one active screen buffer. Inactive screen buffers can be accessed for reading and writing, but only the active screen buffer is displayed. To make the new screen buffer the active screen buffer, use the SetConsoleActiveScreenBuffer function.

The calling process can use the returned handle in any function that requires a handle of a console screen buffer, subject to the limitations of access specified by the dwDesiredAccess parameter.

The calling process can use the DuplicateHandle function to create a duplicate screen buffer handle that has different access or inheritability from the original handle. However, DuplicateHandle cannot be used to create a duplicate that is valid for a different process (except through inheritance).

To close the screen buffer handle, use the CloseHandle function.

See Also

CloseHandle, DuplicateHandle, GetConsoleScreenBufferInfo, SECURITY_ATTRIBUTES, SetConsoleActiveScreenBuffer, SetConsoleScreenBufferSize


CreateCursor
CreateCursor  QuickInfo  Overview  Group

The CreateCursor function creates a cursor having the specified size, bit patterns, and hot spot.

HCURSOR CreateCursor(

HINSTANCE  hInst,	// handle of application instance
int  xHotSpot,	// horizontal position of hot spot
int  yHotSpot,	// vertical position of hot spot
int  nWidth,	// cursor width
int  nHeight,	// cursor height
CONST VOID  *pvANDPlane,	// address of AND bitmask array
CONST VOID  *pvXORPlane	// address of XOR bitmask array
);
Parameters

hInst

Identifies the current instance of the application creating the cursor.

xHotSpot

Specifies the horizontal position of the cursor's hot spot.

yHotSpot

Specifies the vertical position of the cursor's hot spot.

nWidth

Specifies the width, in pixels, of the cursor.

nHeight

Specifies the height, in pixels, of the cursor.

pvANDplane

Points to an array of bytes that contains the bit values for the AND bitmask of the cursor, as in a device-dependent monochrome bitmap.

pvXORplane

Points to an array of bytes that contains the bit values for the XOR bitmask of the cursor, as in a device-dependent monochrome bitmap.

Return Value

If the function succeeds, the return value identifies the cursor.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

The nWidth and nHeight parameters must specify a width and height that are supported by the current display driver, because the system cannot create cursors of other sizes. To determine the width and height supported by the display driver, use the GetSystemMetrics function, specifying the SM_CXCURSOR or SM_CYCURSOR value.

Before closing, an application must call the DestroyCursor function to free any system resources associated with the cursor.

See Also

CreateIcon, DestroyCursor, GetModuleHandle, GetSystemMetrics, SetCursor


CreateDC
CreateDC  QuickInfo  Overview  Group

The CreateDC function creates a device context (DC) for a device by using the specified name.

HDC CreateDC(

LPCTSTR  lpszDriver,	// address of string specifying driver name
LPCTSTR  lpszDevice,	// address of string specifying device name
LPCTSTR  lpszOutput,	// do not use; set to NULL
CONST DEVMODE  *lpInitData	// address of optional printer data
);
Parameters

lpszDriver

Applications written for earlier versions of Windows used this parameter to specify the filename (without extension) of the device driver.

Windows 95: In Win32-based applications, this parameter is ignored and should be NULL, with one exception: You may obtain a display device context by specifying the null-terminated string "DISPLAY". If this parameter is "DISPLAY", all other parameters must be NULL.

Windows NT: Points to a null-terminated character string that specifies either "DISPLAY" for a display driver, or the name of a printer driver, which is usually "WINSPOOL".

lpszDevice

Points to a null-terminated character string that specifies the name of the specific output device being used, as shown by the Print Manager (for example, "Epson FX-80"). It is not the printer model name. The lpszDevice parameter must be used.

lpszOutput

This parameter is ignored. Do not use it in a Win32 application. Win32-based applications should set this parameter to NULL. It exists to provide compatibility for applications written for earlier versions of Windows. For more information, see the following Remarks section.

lpInitData

Points to a DEVMODE structure containing device-specific initialization data for the device driver. The DocumentProperties function retrieves this structure filled in for a given device. The lpInitData parameter must be NULL if the device driver is to use the default initialization (if any) specified by the user.

Return Value

If the function succeeds, the return value is the handle of a device context for the specified device.

If the function fails, the return value is NULL.

Remarks

Applications written for earlier versions of Windows used the lpszOutput parameter to specify a port name or to print to a file. Win32-based applications do not need to specify a port name. Win32-based applications can print to a file by calling the StartDoc function with a DOCINFO structure whose lpszOutput member specifies the path of the output filename.

When you no longer need the device context, call the DeleteDC function to delete it.

See Also

DeleteDC, DEVMODE, DOCINFO, DocumentProperties, StartDoc


CreateDesktop [New - Windows NT]
CreateDesktop  QuickInfo  Overview  Group

[New - Windows NT]

The CreateDesktop function creates a new desktop on the window station associated with the calling process. It returns a handle that can be used to access the new desktop. The calling process must have an associated window station, either assigned by the system at process creation time or set by SetProcessWindowStation. A desktop is a secure object contained within a window station object. A desktop has a logical display surface and contains windows, menus, and hooks.

HDESK CreateDesktop(

LPCTSTR lpszDesktop,	// name of the new desktop
LPCTSTR lpszDevice,	// name of display device to assign to the desktop
LPDEVMODE pDevMode,	// reserved; must be NULL
DWORD dwFlags,	// flags to control interaction with other applications
DWORD dwDesiredAccess,	// specifies access of returned handle
LPSECURITY_ATTRIBUTES lpsa	// specifies security attributes of the desktop
);
Parameters

lpszDesktop

Points to a null-terminated string specifying the name of the desktop to be created. Desktop names are case-insensitive and may not contain backslash characters (\).

lpszDevice

If specified, points to a null-terminated string specifying the name of the display device to assign to the desktop. The name must begin with a backslash character (\). If lpszDevice is NULL, the default display driver loaded at boot time is used.

pDevMode

Reserved; must be NULL.

dwFlags

A bit flag parameter that controls how the calling application will cooperate with other applications on the desktop. This parameter can specify zero or the following value:

Value	Description
DF_ALLOWOTHERACCOUNTHOOK	Allows processes running in other accounts on the desktop to set hooks in this process.
dwDesiredAccess

Specifies the type of access to the desktop. This parameter can be one or more of the following values:

Value	Description
DESKTOP_CREATEMENU	Required to create a menu on the desktop.
DESKTOP_CREATEWINDOW	Required to create a window on the desktop.
DESKTOP_ENUMERATE	Required for the desktop to be enumerated.
DESKTOP_HOOKCONTROL	Required to establish any of the window hooks.
DESKTOP_JOURNALPLAYBACK	Required to perform journal playback on the desktop.
DESKTOP_JOURNALRECORD	Required to perform journal recording on the desktop.
DESKTOP_READOBJECTS	Required to read objects on the desktop.
DESKTOP_SWITCHDESKTOP	Required to activate the desktop using the SwitchDesktop function.
DESKTOP_WRITEOBJECTS	Required to write objects on the desktop.
lpsa

Points to a SECURITY_ATTRIBUTES structure that specifies the security attributes for the desktop.

If either lpsa or lpsa->lpSecurityDescriptor is NULL, the desktop inherits its security descriptor from the parent window station, and the resulting handle is not inheritable.

Return Value

If the function succeeds, the return value is a handle of the newly created desktop.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

The CreateDesktop function returns a handle that can be used to access the desktop.

See Also

SECURITY_ATTRIBUTES, SetProcessWindowStation, SwitchDesktop


CreateDialog
CreateDialog  QuickInfo  Overview  Group

The CreateDialog function creates a modeless dialog box from a dialog box template resource.

HWND CreateDialog(

HINSTANCE  hInstance,	// handle of application instance
LPCTSTR  lpTemplate,	// identifies dialog box template name
HWND  hWndParent,	// handle of owner window
DLGPROC  lpDialogFunc	// address of dialog box procedure
);
Parameters

hInstance

Identifies an instance of the module whose executable file contains the dialog box template.

lpTemplate

Identifies the dialog box template. This parameter is either the address of a null-terminated character string that specifies the name of the dialog box template or an integer value that specifies the resource identifier of the dialog box template. If the parameter specifies a resource identifier, its high-order word must be zero and its low-order word must contain the identifier. You can use the MAKEINTRESOURCE macro to create this value.

hWndParent

Identifies the window that owns the dialog box.

lpDialogFunc

Points to the dialog box procedure. For more information about the dialog box procedure, see DialogProc.

Return Value

If the function succeeds, the return value is the handle of the dialog box.

If the function fails, the return value is NULL.

Remarks

The CreateDialog function uses the CreateWindowEx function to create the dialog box. CreateDialog then sends a WM_INITDIALOG message (and a WM_SETFONT message if the template specifies the DS_SETFONT style) to the dialog box procedure. The function displays the dialog box if the template specifies the WS_VISIBLE style. Finally, CreateDialog returns the window handle of the dialog box.

After CreateDialog returns, the application displays the dialog box (if it is not already displayed) by using the ShowWindow function. The application destroys the dialog box by using the DestroyWindow function.

Windows 95 only: The system can support a maximum of 16,364 window handles.

See Also

CreateDialogIndirect, CreateDialogIndirectParam, CreateDialogParam, CreateWindowEx, DestroyWindow, DialogBox, DialogProc, ShowWindow, WM_INITDIALOG, WM_SETFONT


CreateDialogIndirect
CreateDialogIndirect  QuickInfo  Overview  Group

The CreateDialogIndirect function creates a modeless dialog box from a dialog box template in memory.

HWND CreateDialogIndirect(

HINSTANCE  hInstance,	// handle of application instance
LPCDLGTEMPLATE  lpName,	// address of dialog box template
HWND  hWndParent,	// handle of owner window
DLGPROC  lpDialogFunc	// address of dialog box procedure
);
Parameters

hInstance

Identifies the instance of the module that creates the dialog box.

lpName

Points to a global memory object that contains a dialog box template used to create the dialog box. This template is in the form of a DLGTEMPLATE structure followed by one or more DLGITEMTEMPLATE structures.

hWndParent

Identifies the window that owns the dialog box.

lpDialogFunc

Points to the dialog box procedure. For more information about the dialog box procedure, see DialogProc.

Return Value

If the function succeeds, the return value is the window handle of the dialog box.

If the function fails, the return value is NULL.

Remarks

The CreateDialogIndirect function uses the CreateWindowEx function to create the dialog box. CreateDialogIndirect then sends a WM_INITDIALOG message (and a WM_SETFONT message if the template specifies the DS_SETFONT style) to the dialog box procedure. The function displays the dialog box if the template specifies the WS_VISIBLE style. Finally, CreateDialogIndirect returns the window handle of the dialog box.

After CreateDialogIndirect returns, the application displays the dialog box (if it is not already displayed) by using the ShowWindow function. The application destroys the dialog box by using the DestroyWindow function.

Windows 95 only: The system can support a maximum of 16,364 window handles.

See Also

CreateDialog, CreateDialogIndirectParam, CreateDialogParam, CreateWindowEx, DestroyWindow, DialogProc, DLGITEMTEMPLATE, DLGTEMPLATE, ShowWindow, WM_INITDIALOG, WM_SETFONT


CreateDialogIndirectParam
CreateDialogIndirectParam  QuickInfo  Overview  Group

The CreateDialogIndirectParam function creates a modeless dialog box from a dialog box template in memory. Before displaying the dialog box, the function passes an application-defined value to the dialog box procedure as the lParam parameter of the WM_INITDIALOG message. An application can use this value to initialize dialog box controls.

HWND CreateDialogIndirectParam(

HINSTANCE  hInstance,	// handle of application instance
LPCDLGTEMPLATE  lpTemplate,	// address of dialog box template
HWND  hWndParent,	// handle of owner window
DLGPROC  lpDialogFunc,	// address of dialog box procedure
LPARAM  lParamInit	// initialization value
);
Parameters

hInstance

Identifies the instance of the module that will create the dialog box.

lpTemplate

Points to a global memory object that contains a dialog box template used to create the dialog box. This template is in the form of a DLGTEMPLATE structure followed by one or more DLGITEMTEMPLATE structures.

hWndParent

Identifies the window that owns the dialog box.

lpDialogFunc

Points to the dialog box procedure. For more information about the dialog box procedure, see DialogProc.

lParamInit

Specifies the value to pass to the dialog box in the lParam parameter of the WM_INITDIALOG message.

Return Value

If the function succeeds, the return value is the window handle of the dialog box.

If the function fails, the return value is NULL.

Remarks

The CreateDialogIndirectParam function uses the CreateWindowEx function to create the dialog box. CreateDialogIndirectParam then sends a WM_INITDIALOG message (and a WM_SETFONT message if the template specifies the DS_SETFONT style) to the dialog box procedure. The function displays the dialog box if the template specifies the WS_VISIBLE style. Finally, CreateDialogIndirectParam returns the window handle of the dialog box.

After CreateDialogIndirectParam returns, the application displays the dialog box (if it is not already displayed) by using the ShowWindow function. The application destroys the dialog box by using the DestroyWindow function.

Windows 95 only: The system can support a maximum of 16,364 window handles.

See Also

CreateDialog, CreateDialogIndirect, CreateDialogParam, CreateWindowEx, DestroyWindow, DLGITEMTEMPLATE, DLGTEMPLATE, DialogProc, ShowWindow, WM_INITDIALOG, WM_SETFONT


CreateDialogParam
CreateDialogParam  QuickInfo  Overview  Group

The CreateDialogParam function creates a modeless dialog box from a dialog box template resource. Before displaying the dialog box, the function passes an application-defined value to the dialog box procedure as the lParam parameter of the the WM_INITDIALOG message. An application can use this value to initialize dialog box controls.

HWND CreateDialogParam(

HINSTANCE  hInstance,	// handle of application instance
LPCTSTR  lpTemplateName,	// identifies dialog box template
HWND  hWndParent,	// handle of owner window
DLGPROC  lpDialogFunc,	// address of dialog box procedure
LPARAM  dwInitParam	// initialization value
);
Parameters

hInstance

Identifies an instance of the module whose executable file contains the dialog box template.

lpTemplateName

Identifies the dialog box template. This parameter is either the address of a null-terminated character string that specifies the name of the dialog box template or an integer value that specifies the resource identifier of the dialog box template. If the parameter specifies a resource identifier, its high-order word must be zero and low-order word must contain the identifier. You can use the MAKEINTRESOURCE macro to create this value.

hWndParent

Identifies the window that owns the dialog box.

lpDialogFunc

Points to the dialog box procedure. For more information about the dialog box procedure, see DialogProc .

dwInitParam

Specifies the value to pass to the dialog box procedure in the lParam parameter in the WM_INITDIALOG message.

Return Value

If the function succeeds, the return value is the window handle of the dialog box.

If the function fails, the return value is NULL.

Remarks

The CreateDialogParam function uses the CreateWindowEx function to create the dialog box. CreateDialogParam then sends a WM_INITDIALOG message (and a WM_SETFONT message if the template specifies the DS_SETFONT style) to the dialog box procedure. The function displays the dialog box if the template specifies the WS_VISIBLE style. Finally, CreateDialogParam returns the window handle of the dialog box.

After CreateDialogParam returns, the application displays the dialog box (if it is not already displayed) by using the ShowWindow function. The application destroys the dialog box by using the DestroyWindow function.

Windows 95 only: The system can support a maximum of 16,364 window handles.

See Also

CreateDialog, CreateDialogIndirect, CreateDialogIndirectParam, CreateWindowEx, DestroyWindow, DialogProc, MAKEINTRESOURCE, ShowWindow, WM_INITDIALOG, WM_SETFONT


CreateDIBitmap
CreateDIBitmap  QuickInfo  Overview  Group

The CreateDIBitmap function creates a device-dependent bitmap (DDB) from a device-independent bitmap (DIB) and, optionally, sets the bitmap bits.

HBITMAP CreateDIBitmap(

HDC  hdc,	// handle of device context
CONST BITMAPINFOHEADER *  lpbmih,	// address of bitmap size and format data
DWORD  fdwInit,	// initialization flag
CONST VOID  *lpbInit,	// address of initialization data
CONST BITMAPINFO *  lpbmi,	// address of bitmap color-format data
UINT  fuUsage	// color-data usage
);
Parameters

hdc

Identifies a device context.

lpbmih

Points to a BITMAPINFOHEADER structure.

If fdwInit is CBM_INIT, the function uses the BITMAPINFOHEADER structure to obtain the desired width and height of the bitmap as well as other information. Note that a positive value for the height indicates a bottom-up DIB while a negative value for the height indicates a top-down DIB. This scenario is compatible with the CreateDIBitmap function.

fdwInit

A set of bit flags that specify how the operating system initializes the bitmap's bits.

The following bit flag constant is defined:

Value	Meaning
CBM_INIT	If this flag is set, the operating system uses the data pointed to by the lpbInit and lpbmi parameters to initialize the bitmap's bits. If this flag is clear, the data pointed to by those parameters is not used.
If fdwInit is zero, the operating system does not initialize the bitmap's bits.

lpbInit

Points to an array of bytes containing the initial bitmap data. The format of the data depends on the biBitCount member of the BITMAPINFO structure to which the lpbmi parameter points.

lpbmi

Points to a BITMAPINFO structure that describes the dimensions and color format of the array pointed to by the lpbInit parameter.

fuUsage

Specifies whether the bmiColors member of the BITMAPINFO structure was initialized and, if so, whether bmiColors contains explicit red, green, blue (RGB) values or palette indices. The fuUsage parameter must be one of the following values:

Value	Meaning
DIB_PAL_COLORS	A color table is provided and consists of an array of 16-bit indices into the logical palette of the device context into which the bitmap is to be selected.
DIB_RGB_COLORS	A color table is provided and contains literal RGB values.
Return Value

If the function succeeds, the return value is a handle of the bitmap.

If the function fails, the return value is NULL.

Remarks

The CBM_CREATDIB flag for the fdwInit parameter is no longer supported.

When you no longer need the bitmap, call the DeleteObject function to delete it.

See Also

BITMAPINFOHEADER, BITMAPINFO, DeleteObject, GetDeviceCaps, GetSystemPaletteEntries, SelectObject


CreateDIBPatternBrush
CreateDIBPatternBrush  QuickInfo  Overview  Group

The CreateDIBPatternBrush function creates a logical brush that has the pattern specified by the specified device-independent bitmap (DIB). The brush can subsequently be selected into any device context that is associated with a device that supports raster operations.

This function is provided only for compatibility with applications written for versions of Windows earlier than 3.0. For Win32-based applications, use the CreateDIBPatternBrushPt function.

HBRUSH CreateDIBPatternBrush(

HGLOBAL  hglbDIBPacked,	// handle of device-independent bitmap
UINT  fuColorSpec	// color table data
);
Parameters

hglbDIBPacked

Identifies a global memory object containing a packed DIB, which consists of a BITMAPINFO structure immediately followed by an array of bytes defining the pixels of the bitmap.

fuColorSpec

Specifies whether the bmiColors member of the BITMAPINFO structure is initialized and, if so, whether this member contains explicit red, green, blue (RGB) values or indices into a logical palette. The fuColorSpec parameter must be one of the following values:

Value	Meaning
DIB_PAL_COLORS	A color table is provided and consists of an array of 16-bit indices into the logical palette of the device context into which the brush is to be selected.
DIB_RGB_COLORS	A color table is provided and contains literal RGB values.
Return Value

If the function succeeds, the return value identifies a logical brush.

If the function fails, the return value is NULL.

Remarks

When an application selects a two-color DIB pattern brush into a monochrome device context, Windows does not acknowledge the colors specified in the DIB; instead, it displays the pattern brush using the current background and foreground colors of the device context. Pixels mapped to the first color of the DIB (offset 0 in the DIB color table) are displayed using the foreground color; pixels mapped to the second color (offset 1 in the color table) are displayed using the background color.

When you no longer need the brush, call the DeleteObject function to delete it.

Windows 95: Creating brushes from bitmaps or DIBs larger than 8x8 pixels is not supported. If a larger bitmap is given, only a portion of the bitmap is used.

See Also

BITMAPINFO, CreateDIBPatternBrushPt, CreateHatchBrush, CreatePatternBrush, CreateSolidBrush, DeleteObject, SetBkColor, SetTextColor


CreateDIBPatternBrushPt
CreateDIBPatternBrushPt  QuickInfo  Overview  Group

The CreateDIBPatternBrushPt function creates a logical brush that has the pattern specified by the device-independent bitmap (DIB).

HBRUSH CreateDIBPatternBrushPt(

CONST VOID *  lpPackedDIB,	// address of structure and bitmap bits
UINT  iUsage	// usage flags
);
Parameters

lpPackedDIB

Points to a packed DIB consisting of a BITMAPINFO structure immediately followed by an array of bytes defining the pixels of the bitmap.

iUsage

Specifies whether the bmiColors member of the BITMAPINFO structure contains a valid color table and, if so, whether the entries in this color table contain explicit red, green, blue (RGB) values or palette indices. The iUsage parameter must be one of the following values:

Value	Meaning
DIB_PAL_COLORS	A color table is provided and consists of an array of 16-bit indices into the logical palette of the device context into which the brush is to be selected.
DIB_RGB_COLORS	A color table is provided and contains literal RGB values.
Return Value

If the function succeeds, the return value identifies a logical brush.

If the function fails, the return value is NULL.

Remarks

A brush is a bitmap that Windows uses to paint the interiors of filled shapes.

After an application creates a brush by calling CreateDIBPatternBrushPt, it can select that brush into any device context by calling the SelectObject function.

When you no longer need the brush, call the DeleteObject function to delete it.

Windows 95: Creating brushes from bitmaps or DIBs larger than 8x8 pixels is not supported. If a larger bitmap is given, only a portion of the bitmap is used.

See Also

BITMAPINFO, CreateDIBPatternBrush, CreateHatchBrush, CreatePatternBrush, CreateSolidBrush, DeleteObject, GetBrushOrgEx, SelectObject, SetBrushOrgEx


CreateDIBSection
CreateDIBSection  QuickInfo  Overview  Group

The CreateDIBSection function creates a device-independent bitmap (DIB) that applications can write to directly. The function gives you a pointer to the location of the bitmap's bit values. You can supply a handle to a file mapping object that the function will use to create the bitmap, or you can let the operating system allocate the memory for the bitmap.

HBITMAP CreateDIBSection(

HDC hdc,	// handle of device context
CONST BITMAPINFO *pbmi,	// address of structure containing bitmap size, format, and color data
UINT iUsage,	// color data type indicator: RGB values or palette indices
VOID **ppvBits,	// pointer to variable to receive a pointer to the bitmap's bit values
HANDLE hSection,	// optional handle to a file mapping object
DWORD dwOffset	// offset to the bitmap bit values within the file mapping object
);
Parameters

hdc

Handle to a device context. If the value of iUsage is DIB_PAL_COLORS, the function uses this device context's logical palette to initialize the device-independent bitmap's colors.

pbmi

Points to a BITMAPINFO structure that specifies various attributes of the device-independent bitmap, including the bitmap's dimensions and colors.

iUsage

Specifies the type of data contained in the bmiColors array member of the BITMAPINFO structure pointed to by pbmi: logical palette indices or literal RGB values. The following values are defined:

Value	Meaning
DIB_PAL_COLORS	The bmiColors member is an array of 16-bit indices into the logical palette of the device context specified by hdc.
DIB_RGB_COLORS	The BITMAPINFO structure contains an array of literal RGB values.
ppvBits

Points to a variable that receives a pointer to the location of the device-independent bitmap's bit values.

hSection

Handle to a file mapping object that the function will use to create the device-independent bitmap. This parameter can be NULL.

If hSection is not NULL, it must be a handle to a file mapping object created by calling the CreateFileMapping function. Handles created by other means will cause CreateDIBSection to fail.

If hSection is not NULL, the CreateDIBSection function locates the bitmap's bit values at offset dwOffset in the file mapping object referred to by hSection. An application can later retrieve the hSection handle by calling the GetObject function with the HBITMAP returned by CreateDIBSection.

If hSection is NULL, the operating system allocates memory for the device-independent bitmap. In this case, the CreateDIBSection function ignores the dwOffset parameter. An application cannot later obtain a handle to this memory: the dshSection member of the DIBSECTION structure filled in by calling the GetObject function will be NULL.

dwOffset

Specifies the offset from the beginning of the file mapping object referenced by hSection where storage for the bitmap's bit values is to begin. This value is ignored if hSection is NULL. The bitmap's bit values are aligned on doubleword boundaries, so dwOffset must be a multiple of the size of a DWORD.

Return Value

If the function succeeds, the return value is a handle to the newly created device-independent bitmap, and *ppvBits points to the bitmap's bit values.

If the function fails, the return value is NULL, and *ppvBits is NULL. To get extended error information, call GetLastError.

Remarks

As noted above, if hSection is NULL, the operating system allocates memory for the device-independent bitmap. The operating system closes the handle to that memory when you later delete the device-independent bitmap by calling the DeleteObject function. If hSection is not NULL, you must close the hSection memory handle yourself after calling DeleteObject to delete the bitmap.

Windows NT: You need to guarantee that the GDI subsystem has completed any drawing to a bitmap created by CreateDIBSection before you draw to the bitmap yourself. Access to the bitmap must be synchronized. Do this by calling the GdiFlush function. This applies to any use of the pointer to the bitmap's bit values, including passing the pointer in calls to functions such as SetDIBits.

See Also

BITMAPINFO, CreateFileMapping, DeleteObject, DIBSECTION, GetDIBColorTable, GetObject, GdiFlush, HBITMAP, SetDIBits SetDIBColorTable


CreateDirectory
CreateDirectory  QuickInfo  Overview  Group

The CreateDirectory function creates a new directory. If the underlying file system supports security on files and directories, the function applies a specified security descriptor to the new directory. Note that CreateDirectory does not have a template parameter, while CreateDirectoryEx does.

BOOL CreateDirectory(

LPCTSTR  lpPathName,	// pointer to a directory path string
LPSECURITY_ATTRIBUTES  lpSecurityAttributes	// pointer to a security descriptor
);
Parameters

lpPathName

Points to a null-terminated string that specifies the path of the directory to be created.

There is a default string size limit for paths of MAX_PATH characters. This limit is related to how the CreateDirectory function parses paths.

Windows NT: An application can transcend this limit and send in paths longer than MAX_PATH characters by calling the wide (W) version of CreateDirectory and prepending "\\?\" to the path. The "\\?\" tells the function to turn off path parsing; it lets paths longer than MAX_PATH be used with CreateDirectoryW. This also works with UNC names. The "\\?\" is ignored as part of the path. For example, "\\?\C:\myworld\private" is seen as "C:\myworld\private", and "\\?\UNC\bill_g_1\hotstuff\coolapps" is seen as "\\bill_g_1\hotstuff\coolapps".

lpSecurityAttributes

Points to a SECURITY_ATTRIBUTES structure that specifies the security attributes for the directory to be created. The file system must support this parameter for it to have an effect.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Windows NT

Some file systems, such as NTFS, support compression for individual files and directories. On volumes formatted for such a file system, a new directory inherits the compression attribute of its parent directory.

An application can obtain a handle to a directory by calling CreateFile with the FILE_FLAG_BACKUP_SEMANTICS flag set. For a code example, see CreateFile.

See Also

CreateDirectoryEx, CreateFile, RemoveDirectory, SECURITY_ATTRIBUTES


CreateDirectoryEx
CreateDirectoryEx  QuickInfo  Overview  Group

The CreateDirectoryEx function creates a new directory with a specified path that retains the attributes of a specified template directory. If the underlying file system supports security on files and directories, the function applies a specified security descriptor to the new directory. The new directory retains the other attributes of the specified template directory. Note that CreateDirectoryEx has a template parameter, while CreateDirectory does not.

BOOL CreateDirectoryEx(

LPCTSTR  lpTemplateDirectory,	// pointer to path string of template directory
LPCTSTR  lpNewDirectory,	// pointer to path string of directory to create
LPSECURITY_ATTRIBUTES  lpSecurityAttributes	// pointer to security descriptor
);
Parameters

lpTemplateDirectory

Points to a null-terminated string that specifies the path of the directory to use as a template when creating the new directory.

lpNewDirectory

Points to a null-terminated string that specifies the path of the directory to be created.

lpSecurityAttributes

Points to a SECURITY_ATTRIBUTES structure that supplies a security descriptor for the new directory. This parameter is optional. The target file system must support security on files and directories for this parameter to have an effect.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The CreateDirectoryEx function allows you to create directories that inherit stream information from other directories. This function is useful, for example, when dealing with Macintosh directories, which have a resource stream that is needed to properly identify directory contents as an attribute.

Windows NT

Some file systems, such as NTFS, support compression for individual files and directories. On volumes formatted for such a file system, a new directory inherits the compression attribute of its parent directory.

You can obtain a handle to a directory by calling CreateFile with the FILE_FLAG_BACKUP_SEMANTICS flag set. See CreateFile for a code example.

See Also

CreateDirectory, CreateFile, RemoveDirectory, SECURITY_ATTRIBUTES


CreateDiscardableBitmap
CreateDiscardableBitmap  QuickInfo  Overview  Group

The CreateDiscardableBitmap function creates a discardable bitmap that is compatible with the specified device. The bitmap has the same bits-per-pixel format and the same color palette as the device. An application can select this bitmap as the current bitmap for a memory device that is compatible with the specified device.

The CreateDiscardableBitmap function is included only for compatibility with earlier versions of Windows. For Win32-based applications, use the CreateCompatibleBitmap function.

HBITMAP CreateDiscardableBitmap(

HDC  hdc,	// handle of device context
int  nWidth,	// bitmap width
int  nHeight	// bitmap height
);
Parameters

hdc

Identifies a device context.

nWidth

Specifies the width, in bits, of the bitmap.

nHeight

Specifies the height, in bits, of the bitmap.

Return Value

If the function succeeds, the return value is a handle of the bitmap.

If the function fails, the return value is NULL.

Remarks

When you no longer need the bitmap, call the DeleteObject function to delete it.

See Also

CreateCompatibleBitmap, DeleteObject


CreateEllipticRgn
CreateEllipticRgn  QuickInfo  Overview  Group

The CreateEllipticRgn function creates an elliptical region.

HRGN CreateEllipticRgn(

int  nLeftRect,	// x-coordinate of the upper-left corner of the bounding rectangle
int  nTopRect,	// y-coordinate of the upper-left corner of the bounding rectangle
int  nRightRect,	// x-coordinate of the lower-right corner of the bounding rectangle
int  nBottomRect	// y-coordinate of the lower-right corner of the bounding rectangle
);
Parameters

nLeftRect

Specifies the x-coordinate of the upper-left corner of the bounding rectangle of the ellipse.

nTopRect

Specifies the y-coordinate of the upper-left corner of the bounding rectangle of the ellipse.

nRightRect

Specifies the x-coordinate of the lower-right corner of the bounding rectangle of the ellipse.

nBottomRect

Specifies the y-coordinate of the lower-right corner of the bounding rectangle of the ellipse.

Return Value

If the function succeeds, the return value is the handle of the region.

If the function fails, the return value is NULL.

Remarks

A bounding rectangle defines the size, shape, and orientation of the region: The long sides of the rectangle define the length of the ellipse's major axis; the short sides define the length of the ellipse's minor axis; and the center of the rectangle defines the intersection of the major and minor axes.

The coordinates of the bounding rectangle are specified in logical units.

See Also

CreateEllipticRgnIndirect, DeleteObject, SelectObject


CreateEllipticRgnIndirect
CreateEllipticRgnIndirect  QuickInfo  Overview  Group

The CreateEllipticRgnIndirect function creates an elliptical region.

HRGN CreateEllipticRgnIndirect(

CONST RECT  *lprc	// address of structure defining bounding rectangle
);
Parameters

lprc

Points to a RECT structure that contains the coordinates of the upper-left and lower-right corners of the bounding rectangle of the ellipse.

Return Value

If the function succeeds, the return value is the handle of the region.

If the function fails, the return value is NULL.

Remarks

A bounding rectangle defines the size, shape, and orientation of the region: The long sides of the rectangle define the length of the ellipse's major axis; the short sides define the length of the ellipse's minor axis; and the center of the rectangle defines the intersection of the major and minor axes.

The coordinates of the bounding rectangle are specified in logical units.

See Also

CreateEllipticRgn, DeleteObject, RECT, SelectObject


CreateEnhMetaFile
CreateEnhMetaFile  QuickInfo  Overview  Group

The CreateEnhMetaFile function creates a device context for an enhanced-format metafile. This device context can be used to store a device-independent picture.

HDC CreateEnhMetaFile(

HDC  hdcRef,	// handle of a reference device context
LPCTSTR  lpFilename,	// address of a filename string
CONST RECT *  lpRect,	// address of a bounding rectangle
LPCTSTR  lpDescription	// address of an optional description string
);
Parameters

hdcRef

Identifies a reference device for the enhanced metafile.

lpFilename

Points to the filename for the enhanced metafile to be created. If this parameter is NULL, the enhanced metafile is memory based and its contents are lost when it is deleted by using the DeleteEnhMetaFile function.

lpRect

Points to a RECT structure that specifies the dimensions (in .01-millimeter units) of the picture to be stored in the enhanced metafile.

lpDescription

Points to a string that specifies the name of the application that created the picture, as well as the picture's title.

Return Value

If the function succeeds, the return value is a handle of the device context for the enhanced metafile.

If the function fails, the return value is NULL.

Remarks

Where text arguments must use Unicode characters, use this function as a wide-character function. Where text arguments must use characters from the Windows 3.x character set, use this function as an ANSI function.

Windows uses the reference device identified by the hdcRef parameter to record the resolution and units of the device on which a picture originally appeared. If the hdcRef parameter is NULL, it uses the current display device for reference.

The left and top members of the RECT structure pointed to by the lpRect parameter must be less than the right and bottom members, respectively. Points along the edges of the rectangle are included in the picture. If lpRect is NULL, the graphics device interface (GDI) computes the dimensions of the smallest rectangle that surrounds the picture drawn by the application. The lpRect parameter should be provided where possible.

The string pointed to by the lpDescription parameter must contain a null character between the application name and the picture name and must terminate with two null characters — for example, "XYZ Graphics Editor\0Bald Eagle\0\0", where \0 represents the null character. If lpDescription is NULL, there is no corresponding entry in the enhanced-metafile header.

Applications use the device context created by this function to store a graphics picture in an enhanced metafile. The handle identifying this device context can be passed to any GDI function.

After an application stores a picture in an enhanced metafile, it can display the picture on any output device by calling the PlayEnhMetaFile function. When displaying the picture, Windows uses the rectangle pointed to by the lpRect parameter and the resolution data from the reference device to position and scale the picture.

The device context returned by this function contains the same default attributes associated with any new device context.

Applications must use the GetWinMetaFileBits function to convert an enhanced metafile to the older Windows metafile format.

The filename for the enhanced metafile should use the .EMF extension.

See Also

CloseEnhMetaFile, DeleteEnhMetaFile, GetEnhMetaFileDescription, GetEnhMetaFileHeader, GetWinMetaFileBits, PlayEnhMetaFile, RECT


CreateEvent
CreateEvent  QuickInfo  Overview  Group

The CreateEvent function creates a named or unnamed event object.

HANDLE CreateEvent(

LPSECURITY_ATTRIBUTES  lpEventAttributes,	// address of security attributes
BOOL  bManualReset,	// flag for manual-reset event
BOOL  bInitialState,	// flag for initial state
LPCTSTR  lpName	// address of event-object name
);
Parameters

lpEventAttributes

Points to a SECURITY_ATTRIBUTES structure that specifies the security attributes for the event object.

If lpEventAttributes is NULL, the event object is created with a default security descriptor and the resulting handle is not inheritable.

bManualReset

Specifies whether a manual-reset or auto-reset event object is created. If TRUE, then you must use the ResetEvent function to manually reset the state to nonsignaled. If FALSE, Windows automatically resets the state to nonsignaled after a single waiting thread has been released.

bInitialState

Specifies the initial state of the event object. If TRUE, the initial state is signaled; otherwise, it is nonsignaled.

lpName

Points to a null-terminated string specifying the name of the event object. The name is limited to MAX_PATH characters and can contain any character except the backslash path-separator character (\). Name comparison is case sensitive.

If lpName matches the name of an existing named event object, this function requests EVENT_ALL_ACCESS access to the existing object. In this case, the bManualReset and bInitialState parameters are ignored because they have already been set by the creating process. If the lpEventAttributes parameter is not NULL, it determines whether the handle can be inherited, but its security-descriptor member is ignored.

If lpName is NULL, the event object is created without a name.

If lpName matches the name of an existing semaphore, mutex, or file-mapping object, the function fails and the GetLastError function returns ERROR_INVALID_HANDLE. This occurs because event, mutex, semaphore, and file-mapping objects share the same name space.

Return Value

If the function succeeds, the return value is a handle of the event object. If the named event object existed before the function call, the GetLastError function returns ERROR_ALREADY_EXISTS. Otherwise, GetLastError returns zero.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

The handle returned by CreateEvent has EVENT_ALL_ACCESS access to the new event object and can be used in any function that requires a handle of an event object.

Any thread of the calling process can specify the event-object handle in a call to one of the wait functions (MsgWaitForMultipleObjects, WaitForSingleObject, WaitForMultipleObjects, WaitForSingleObjectEx, or WaitForMultipleObjectsEx). The single-object wait functions return when the state of the specified object is signaled. The multiple-object wait functions can be instructed to return either when any one or when all of the specified objects are signaled. When a wait function returns, the waiting thread is released to continue its execution.

The initial state of the event object is specified by the bInitialState parameter. Use the SetEvent function to set the state of an event object to signaled. Use the ResetEvent function to reset the state of an event object to nonsignaled.

When the state of a manual-reset event object is signaled, it remains signaled until it is explicitly reset to nonsignaled by the ResetEvent function. Any number of waiting threads, or threads that subsequently begin wait operations for the specified event object, can be released while the object's state is signaled.

When the state of an auto-reset event object is signaled, it remains signaled until a single waiting thread is released; the system then automatically resets the state to nonsignaled. If no threads are waiting, the event object's state remains signaled.

Multiple processes can have handles of the same event object, enabling use of the object for interprocess synchronization. The following object-sharing mechanisms are available:

•	A child process created by the CreateProcess function can inherit a handle of an event object if the lpEventAttributes parameter of CreateEvent enabled inheritance.

•	A process can specify the event-object handle in a call to the DuplicateHandle function to create a duplicate handle that can be used by another process.

•	A process can specify the name of an event object in a call to the OpenEvent or CreateEvent function.

Use the CloseHandle function to close the handle. The system closes the handle automatically when the process terminates. The event object is destroyed when its last handle has been closed.

See Also

CloseHandle, CreateProcess, DuplicateHandle, MsgWaitForMultipleObjects, OpenEvent, ResetEvent, SECURITY_ATTRIBUTES, SetEvent, WaitForMultipleObjects, WaitForMultipleObjectsEx, WaitForSingleObject, WaitForSingleObjectEx


CreateFile
CreateFile  QuickInfo  Overview  Group

The CreateFile function creates, opens, or truncates a file, pipe, communications resource, disk device, or console. It returns a handle that can be used to access the object. It can also open and return a handle to a directory.

HANDLE CreateFile(

LPCTSTR  lpFileName,	// address of name of the file
DWORD  dwDesiredAccess,	// access (read-write) mode
DWORD  dwShareMode,	// share mode
LPSECURITY_ATTRIBUTES  lpSecurityAttributes,	// address of security descriptor
DWORD  dwCreationDistribution,	// how to create
DWORD  dwFlagsAndAttributes,	// file attributes
HANDLE  hTemplateFile	// handle of file with attributes to copy
);
Parameters

lpFileName

Points to a null-terminated string that specifies the name of the file, pipe, communications resource, disk device, or console to create, open, or truncate.

If *lpFileName is a path, there is a default string size limit of MAX_PATH characters. This limit is related to how the CreateFile function parses paths.

Windows NT: You can transcend this limit and send in paths longer than MAX_PATH characters by calling the wide (W) version of CreateFile and prepending "\\?\" to the path. The "\\?\" tells the function to turn off path parsing. This lets you use paths that are nearly 32k Unicode characters long. You must use fully-qualified paths with this technique. This also works with UNC names. The "\\?\" is ignored as part of the path. For example, "\\?\C:\myworld\private" is seen as "C:\myworld\private", and "\\?\UNC\tom_1\hotstuff\coolapps" is seen as "\\tom_1\hotstuff\coolapps".

dwDesiredAccess

Specifies the type of access to the file or other object. An application can obtain read access, write access, read-write access, or device query access. You can use the following flag constants to build a value for this parameter. Both GENERIC_READ and GENERIC_WRITE must be set to obtain read-write access:

Value	Meaning
0	Allows an application to query device attributes without actually accessing the device.
GENERIC_READ	Specifies read access to the file. Data can be read from the file and the file pointer can be moved.
GENERIC_WRITE	Specifies write access to the file. Data can be written to the file and the file pointer can be moved.
dwShareMode

Specifies how this file can be shared. This parameter must be some combination of the following values:

Value	Meaning
0	Prevents the file from being shared.
FILE_SHARE_READ	Other open operations can be performed on the file for read access. If the CreateFile function is opening the client end of a mailslot, this flag is specified.
FILE_SHARE_WRITE	Other open operations can be performed on the file for write access.
lpSecurityAttributes

Points to a SECURITY_ATTRIBUTES structure that specifies the security attributes for the file. The file system must support this parameter for it to have an effect.

dwCreationDistribution

Specifies which action to take on files that exist, and which action to take when files do not exist. For more information about this parameter, see the following Remarks section. This parameter must be one of the following values:

Value	Meaning
CREATE_NEW	Creates a new file. The function fails if the specified file already exists.
CREATE_ALWAYS	Creates a new file. The function overwrites the file if it exists.
OPEN_EXISTING	Opens the file. The function fails if the file does not exist.
	See the "Remarks" section, following, for a discussion of why you should use the OPEN_EXISTING flag if you are using the CreateFile function for a device, including the console.
OPEN_ALWAYS	Opens the file, if it exists. If the file does not exist, the function creates the file as if dwCreationDistribution were CREATE_NEW.
TRUNCATE_EXISTING	Opens the file. Once opened, the file is truncated so that its size is zero bytes. The calling process must open the file with at least GENERIC_WRITE access. The function fails if the file does not exist.
dwFlagsAndAttributes

Specifies the file attributes and flags for the file.

Any combination of the following attributes is acceptable, except all other file attributes override FILE_ATTRIBUTE_NORMAL.

Attribute	Meaning
FILE_ATTRIBUTE_ARCHIVE	The file is an archive file. Applications use this attribute to mark files for backup or removal.
FILE_ATTRIBUTE_COMPRESSED	The file or directory is compressed. For a file, this means that all of the data in the file is compressed. For a directory, this means that compression is the default for newly created files and subdirectories.
FILE_ATTRIBUTE_NORMAL	The file has no other attributes set. This attribute is valid only if used alone.
FILE_ATTRIBUTE_HIDDEN	The file is hidden. It is not to be included in an ordinary directory listing.
FILE_ATTRIBUTE_READONLY	The file is read only. Applications can read the file but cannot write to it or delete it.
FILE_ATTRIBUTE_SYSTEM	The file is part of or is used exclusively by the operating system.
Any combination of the following flags is acceptable.

Flag	Meaning
FILE_FLAG_WRITE_THROUGH
	Instructs the operating system to write through any intermediate cache and go directly to the file. The operating system can still cache write operations, but cannot lazily flush them.
FILE_FLAG_OVERLAPPED
	Instructs the operating system to initialize the file, so ReadFile, WriteFile, ConnectNamedPipe, and TransactNamedPipe operations that take a significant amount of time to process return ERROR_IO_PENDING. When the operation is finished, an event is set to the signaled state.
	When you specify FILE_FLAG_OVERLAPPED, the ReadFile and WriteFile functions must specify an OVERLAPPED structure. That is, when FILE_FLAG_OVERLAPPED is specified, an application must perform overlapped reading and writing.
	When FILE_FLAG_OVERLAPPED is specified, the operating system does not maintain the file pointer. The file position must be passed as part of the lpOverlapped parameter (pointing to an OVERLAPPED structure) to the ReadFile and WriteFile functions.
	This flag also enables more than one operation to be performed simultaneously with the handle (a simultaneous read and write operation, for example).
FILE_FLAG_NO_BUFFERING
	Instructs the operating system to open the file with no intermediate buffering or caching. This can provide performance gains in some situations.  An application must meet certain requirements when working with files opened with FILE_FLAG_NO_BUFFERING: • File access must begin at offsets within the file that are integer multiples of the volume's sector size.  • File access must be for numbers of bytes that are integer multiples of the volume's sector size. For example, if the sector size is 512 bytes, an application can request reads and writes of 512, 1024, or 2048 bytes, but not of 335, 981, or 7171 bytes.  • Buffer addresses for read and write operations must be aligned on addresses in memory that are integer multiples of the volume's sector size.  An application can determine a volume's sector size by calling the GetDiskFreeSpace function.
FILE_FLAG_RANDOM_ACCESS
	Indicates that the file is accessed randomly. Windows uses this flag to optimize file caching.
FILE_FLAG_SEQUENTIAL_SCAN
	Indicates that the file is to be accessed sequentially from beginning to end. Windows uses this flag to optimize file caching. If an application moves the file pointer for random access, optimum caching may not occur; however, correct operation is still guaranteed.
	Specifying this flag can increase performance for applications that read large files using sequential access. Performance gains can be even more noticeable for applications that read large files mostly sequentially, but occasionally skip over small ranges of bytes.
FILE_FLAG_DELETE_ON_CLOSE
	Indicates that the operating system is to delete the file immediately after all of its handles have been closed. If you use this flag when you call CreateFile, then open the file again, and then close the handle for which you specified FILE_FLAG_DELETE_ON_CLOSE, the file will not be deleted until after you have closed the second and any other handle to the file.
FILE_FLAG_BACKUP_SEMANTICS
	Windows NT only: Indicates that the file is being opened or created for a backup or restore operation. The operating system ensures that the calling process overrides file security checks, provided it has the necessary permission to do so. The relevant permissions are SE_BACKUP_NAME and SE_RESTORE_NAME. A Windows NT application can also set this flag to obtain a handle to a directory. A directory handle can be passed to some Win32 functions in place of a file handle.
FILE_FLAG_POSIX_SEMANTICS
	Indicates that the file is to be accessed according to POSIX rules. This includes allowing multiple files with names, differing only in case, for file systems that support such naming. Use care when using this option because files created with this flag may not be accessible by applications written for MS-DOS, Windows 3.x, or Windows NT.
If the CreateFile function opens the client side of a named pipe, the dwFlagsAndAttributes parameter can also contain Security Quality of Service information. When the calling application specifies the SECURITY_SQOS_PRESENT flag, the dwFlagsAndAttributes parameter can contain one or more of the following values:

Value	Meaning
SECURITY_ANONYMOUS	Specifies to impersonate the client at the Anonymous impersonation level.
SECURITY_IDENTIFICATION	Specifies to impersonate the client at the Identification impersonation level.
SECURITY_IMPERSONATION	Specifies to impersonate the client at the Impersonation impersonation level.
SECURITY_DELEGATION	Specifies to impersonate the client at the Delegation impersonation level.
SECURITY_CONTEXT_TRACKING	Specifies that the security tracking mode is dynamic. If this flag is not specified, Security Tracking Mode is static.
SECURITY_EFFECTIVE_ONLY	Specifies that only the enabled aspects of the client's security context are available to the server. If you do not specify this flag, all aspects of the client's security context are available. This flag allows the client to limit the groups and privileges that a server can use while impersonating the client.
For more information, see Security.

hTemplateFile

Specifies a handle with GENERIC_READ access to a template file. The template file supplies extended attributes for the file being created.

Return Value

If the function succeeds, the return value is an open handle of the specified file. If the specified file exists before the function call and dwCreationDistribution is CREATE_ALWAYS or OPEN_ALWAYS, a call to GetLastError returns ERROR_ALREADY_EXISTS (even though the function has succeeded). If the file does not exist before the call, GetLastError returns zero.

If the function fails, the return value is INVALID_HANDLE_VALUE. To get extended error information, call GetLastError.

Remarks

When creating a new file, the CreateFile function performs the following actions:

•	Combines the file attributes and flags specified by dwFlagsAndAttributes with FILE_ATTRIBUTE_ARCHIVE.

•	Sets the file length to zero.

•	Copies the extended attributes supplied by the template file to the new file if the hTemplateFile parameter is specified.

When opening an existing file, CreateFile performs the following actions:

•	Combines the file flags specified by dwFlagsAndAttributes with existing file attributes. CreateFile ignores the file attributes specified by dwFlagsAndAttributes.

•	Sets the file length according to the value of dwCreationDistribution.

•	Ignores the hTemplateFile parameter.

•	Ignores the lpSecurityDescriptor member of the SECURITY_ATTRIBUTES structure if the lpSecurityAttributes parameter is not NULL. The other structure members are valid. The bInheritHandle member is the only way to indicate whether the file handle can be inherited.

If CreateFile opens the client end of a named pipe, the function uses any instance of the named pipe that is in the listening state. The opening process can duplicate the handle as many times as required but, once opened, the named pipe instance cannot be opened by another client. The access specified when a pipe is opened must be compatible with the access specified in the dwOpenMode parameter of the CreateNamedPipe function. For more information about pipes, see Pipes.

If CreateFile opens the client end of a mailslot, the function always returns a valid handle, even if the mailslot does not exist. In other words, there is no relationship between opening the client end and opening the server end of the mailslot. For more information about mailslots, see Mailslots.

CreateFile can create a handle to a communications resource, such as the serial port COM1. For communications resources, the dwCreationDistribution parameter must be OPEN_EXISTING, and the hTemplate parameter must be NULL. Read, write, or read-write access can be specified, and the handle can be opened for overlapped I/O. For more information about communications, see Communications.

CreateFile can create a handle to console input (CONIN$). If the process has an open handle to it as a result of inheritance or duplication, it can also create a handle to the active screen buffer (CONOUT$).

The calling process must be attached to an inherited console or one allocated by the AllocConsole function. For console handles, set the CreateFile parameters as follows:

Parameter	Value
lpFileName	Use the CONIN$ value to specify console input and the CONOUT$ value to specify console output.
	CONIN$ gets a handle of the console's input buffer, even if the SetStdHandle function redirected the standard input handle. To get the standard input handle, use the GetStdHandle function.
	CONOUT$ gets a handle of the active screen buffer, even if SetStdHandle redirected the standard output handle. To get the standard output handle, use GetStdHandle.
dwDesiredAccess	GENERIC_READ | GENERIC_WRITE is preferred, but either one can limit access.
dwShareMode	If the calling process inherited the console or if a child process should be able to access the console, this parameter must be FILE_SHARE_READ | FILE_SHARE_WRITE.
lpSecurityAttributes	If you want the console to be inherited, the bInheritHandle member of the SECURITY_ATTRIBUTES structure must be TRUE.
dwCreationDistribution	The user should specify OPEN_EXISTING when using CreateFile to open the console.
dwFlagsAndAttributes	Ignored.
hTemplateFile	Ignored.
The following list shows the effects of various settings of fwdAccess and lpFileName.

lpFileName	fwdAccess	Result
CON	GENERIC_READ	Opens console for input.
CON	GENERIC_WRITE	Opens console for output.
CON	GENERIC_READ\ GENERIC_WRITE	Windows 95: Causes CreateFile to fail; GetLastError returns ERROR_PATH_NOT_FOUND. Windows NT:  Causes CreateFile to fail; GetLastError returns ERROR_FILE_NOT_FOUND.
You can use the CreateFile function to open a disk drive or a partition on a disk drive. The function returns a handle to the disk device; that handle can be used with the DeviceIOControl function. The following requirements must be met in order for such a call to succeed:

•	The caller must have administrative privileges for the operation to succeed on a hard disk drive.

•	The lpFileName string should be of the form \\.\PHYSICALDRIVEx to open the hard disk x. Hard disk numbers start at zero. For example:

String	Meaning
\\.\PHYSICALDRIVE2	Obtains a handle to the third physical drive on the user's computer.
•	The lpFileName string should be \\.\x: to open a floppy drive x or a partition x on a hard disk. For example:

String	Meaning
\\.\A:	Obtains a handle to drive A on the user's computer.
\\.\C:	Obtains a handle to drive C on the user's computer.
Windows 95: This technique does not work for opening a logical drive. In Windows 95, specifying a string in this form causes CreateFile to return an error.

•	The dwCreationDistribution parameter must have the OPEN_EXISTING value.

•	When opening a floppy disk or a partition on a hard disk, you must set the FILE_SHARE_WRITE flag in the dwShareMode parameter.

The CloseHandle function is used to close a handle returned by CreateFile.

As noted above, specifying zero for dwDesiredAccess allows an application to query device attributes without actually accessing the device. This type of querying is useful, for example, if an application wants to determine the size of a floppy disk drive and the formats it supports without having a floppy in the drive.

As previously noted, if an application opens a file with FILE_FLAG_NO_BUFFERING set, buffer addresses for read and write operations must be aligned on memory addresses that are integer multiples of the volume's sector size. One way to do this is to use VirtualAlloc to allocate the buffer. The VirtualAlloc function allocates memory that is aligned on addresses that are integer multiples of the operating system's memory page size. Since both memory page and volume sector sizes are powers of 2, and memory pages are larger than volume sectors, this memory is also aligned on addresses that are integer multiples of a volume's sector size.

An application cannot create a directory with CreateFile; it must call CreateDirectory or CreateDirectoryEx to create a directory.

Windows NT:

You can obtain a handle to a directory by setting the FILE_FLAG_BACKUP_SEMANTICS flag. A directory handle can be passed to some Win32 functions in place of a file handle.

Some file systems, such as NTFS, support compression for individual files and directories. On volumes formatted for such a file system, a new directory inherits the compression attribute of its parent directory.

See Also

AllocConsole, CloseHandle, ConnectNamedPipe, CreateDirectory, CreateDirectoryEx, CreateNamedPipe, DeviceIOControl, GetDiskFreeSpace, GetOverlappedResult, GetStdHandle, OpenFile, OVERLAPPED, ReadFile, SECURITY_ATTRIBUTES, SetStdHandle TransactNamedPipe, VirtualAlloc, WriteFile


CreateFileMapping
CreateFileMapping  QuickInfo  Overview  Group

The CreateFileMapping function creates a named or unnamed file-mapping object for the specified file.

HANDLE CreateFileMapping(

HANDLE  hFile,	// handle of file to map
LPSECURITY_ATTRIBUTES  lpFileMappingAttributes,	// optional security attributes
DWORD  flProtect,	// protection for mapping object
DWORD  dwMaximumSizeHigh,	// high-order 32 bits of object size
DWORD  dwMaximumSizeLow,	// low-order 32 bits of object size
LPCTSTR  lpName	// name of file-mapping object
);
Parameters

hFile

Identifies the file from which to create a mapping object. The file must be opened with an access mode compatible with the protection flags specified by the flProtect parameter. It is recommended, though not required, that files you intend to map be opened for exclusive access.

If hFile is (HANDLE)0xFFFFFFFF, the calling process must also specify a mapping object size in the dwMaximumSizeHigh and dwMaximumSizeLow parameters. The function creates a file-mapping object of the specified size backed by the operating-system paging file rather than by a named file in the file system. The file-mapping object can be shared through duplication, through inheritance, or by name.

lpFileMappingAttributes

Points to a SECURITY_ATTRIBUTES structure that specifies the security attributes for the mapping object.

If lpFileMappingAttributes is NULL, the file-mapping object is created with a default security descriptor and the resulting handle is not inherited.

flProtect

Specifies the protection desired for the file view, when the file is mapped. This parameter can be one of the following values:

Value	Description
PAGE_READONLY	Gives read-only access to the committed region of pages. An attempt to write to or execute the committed region results in an access violation. The file specified by the hFile parameter must have been created with GENERIC_READ access.
PAGE_READWRITE	Gives read-write access to the committed region of pages. The file specified by hFile must have been created with GENERIC_READ and GENERIC_WRITE access.
PAGE_WRITECOPY	Gives copy on write access to the committed region of pages. The files specified by the hFile parameter must have been created with GENERIC_READ and GENERIC_WRITE access.
In addition, an application can specify certain section attributes by combining (using the bitwise OR operator) one or more of the following section attribute values with one of the preceding page protection values:

Value	Description
SEC_COMMIT	Allocates physical storage in memory or in the paging file on disk for all pages of a section. This is the default setting.
SEC_IMAGE	The file specified for a section's file mapping is an executable image file. Because the mapping information and file protection are taken from the image file, no other attributes are valid with SEC_IMAGE.
SEC_NOCACHE	All pages of a section are to be set as non-cacheable. This attribute is intended for architectures requiring various locking structures to be in memory that is never fetched into the processor's. On 80x86 and MIPS machines, using the cache for these structures only slows down the performance as the hardware keeps the caches coherent. Some device drivers require noncached data so that programs can write through to the physical memory. SEC_NOCACHE requires either the SEC_RESERVE or SEC_COMMIT to also be set.
SEC_RESERVE	Reserves all pages of a section without allocating physical storage. The reserved range of pages cannot be used by any other allocation operations until it is released. Reserved pages can be committed in subsequent calls to the VirtualAlloc function. This attribute is valid only if the hFile parameter is (HANDLE)0xFFFFFFFF; that is, a file mapping object backed by the operating sytem paging file.
dwMaximumSizeHigh

Specifies the high-order 32 bits of the maximum size of the file-mapping object.

dwMaximumSizeLow

Specifies the low-order 32 bits of the maximum size of the file-mapping object. If this parameter and dwMaximumSizeHig are zero, the maximum size of the file-mapping object is equal to the current size of the file identified by hFile.

lpName

Points to a null-terminated string specifying the name of the mapping object. The name can contain any character except the backslash character (\).

If this parameter matches the name of an existing named mapping object, the function requests access to the mapping object with the protection specified by flProtect.

If this parameter is NULL, the mapping object is created without a name.

Return Value

If the function succeeds, the return value is a handle of the file-mapping object. If the object existed before the function call, the GetLastError function returns ERROR_ALREADY_EXISTS, and the return value is a valid handle to the existing file-mapping object (with its current size, not the new specified size. If the mapping object did not exist, GetLastError returns zero.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

After a file-mapping object has been created, the size of the file must not exceed the size of the file-mapping object; if it does, not all of the file's contents will be available for sharing.

If an application specifies a size for the file-mapping object that is larger than the size of the actual named file on disk, the file on disk is grown to match the specified size of the file-mapping object.

The handle that CreateFileMapping returns has full access to the new file-mapping object. It can be used with any function that requires a handle to a file-mapping object. File-mapping objects can be shared either through process creation, through handle duplication, or by name. For information on duplicating handles, see DuplicateHandle. For information on opening a file-mapping object by name, see OpenFileMapping.

Windows 95: File handles that have been used to create file-mapping objects must not be used in subsequent calls to file I/O functions, such as ReadFile and WriteFile. In general, if a file handle has been used in a successful call to the CreateFileMapping function, do not use that handle unless you first close the corresponding file-mapping object.

Creating a file-mapping object creates the potential for mapping a view of the file but does not map the view. The MapViewOfFile and MapViewOfFileEx functions map a view of a file into a process's address space.

With one important exception, file views derived from a single file-mapping object are coherent, or identical, at a given time. If multiple processes have handles of the same file-mapping object, they see a coherent view of the data when they map a view of the file.

The exception has to do with remote files. Although CreateFileMapping works with remote files, it does not keep them coherent. For example, if two computers both map a file as writable, and both change the same page, each computer will only see its own writes to the page. When the data gets updated on the disk, it is not merged.

A mapped file and a file accessed by means of the input and output (I/O) functions (ReadFile and WriteFile) are not necessarily coherent.

To fully close a file mapping object, an application must unmap all mapped views of the file mapping object by calling UnmapViewOfFile, and close the file mapping object handle by calling CloseHandle. The order in which these functions are called does not matter. The call to UnmapViewOfFile is necessary because mapped views of a file mapping object maintain internal open handles to the object, and a file mapping object will not close until all open handles to it are closed.

Example

To implement a mapping-object creation function that fails if the object already exists, an application can use the following code.

hMap = CreateFileMapping(...);

if (hMap != NULL && GetLastError() == ERROR_ALREADY_EXISTS) {

    CloseHandle(hMap);

    hMap = NULL;

}

return hMap;

See Also

CloseHandle, DuplicateHandle, MapViewOfFile, MapViewOfFileEx, OpenFileMapping, ReadFile, SECURITY_ATTRIBUTES, UnmapViewOfFile, VirtualAlloc, WriteFile


CreateFont
CreateFont  QuickInfo  Overview  Group

The CreateFont function creates a logical font that has specific characteristics. The logical font can subsequently be selected as the font for any device.

HFONT CreateFont(

int  nHeight,	// logical height of font
int  nWidth,	// logical average character width
int  nEscapement,	// angle of escapement
int  nOrientation,	// base-line orientation angle
int  fnWeight,	// font weight
DWORD  fdwItalic,	// italic attribute flag
DWORD  fdwUnderline,	// underline attribute flag
DWORD  fdwStrikeOut,	// strikeout attribute flag
DWORD  fdwCharSet,	// character set identifier
DWORD  fdwOutputPrecision,	// output precision
DWORD  fdwClipPrecision,	// clipping precision
DWORD  fdwQuality,	// output quality
DWORD  fdwPitchAndFamily,	// pitch and family
LPCTSTR  lpszFace	// address of typeface name string
);
Parameters

nHeight

Specifies the height, in logical units, of the font's character cell or character. The character height value (also known as the em height) is the character cell height value minus the internal-leading value. The font mapper interprets the value specified in nHeight in the following manner:

Value	Meaning
> 0	The font mapper transforms this value into device units and matches it against the cell height of the available fonts.
0	The font mapper uses a default height value when it searches for a match.
< 0	The font mapper transforms this value into device units and matches its absolute value against the character height of the available fonts.
For all height comparisons, the font mapper looks for the largest font that does not exceed the requested size.

This mapping occurs when the font is used for the first time.

For the MM_TEXT mapping mode, you can use the following formula to specify a height for a font with a given point size:

nHeight = -MulDiv(PointSize, GetDeviceCaps(hDC, LOGPIXELSY), 72);

nWidth

Specifies the average width, in logical units, of characters in the requested font. If this value is zero, the font mapper chooses a "closest match" value. The "closest match" value is determined by comparing the absolute values of the difference between the current device's aspect ratio and the digitized aspect ratio of available fonts.

nEscapement

Specifies the angle, in tenths of degrees, between the escapement vector and the x-axis of the device. The escapement vector is parallel to the base line of a row of text.

Windows NT:

When the graphics mode is set to GM_ADVANCED, you can specify the escapement angle of the string independently of the orientation angle of the string's characters.

When the graphics mode is set to GM_COMPATIBLE, nEscapement specifies both the escapement and orientation. You should set nEscapement and nOrientation to the same value.

Windows 95:

The nEscapement parameter specifies both the escapement and orientation. You should set nEscapement and nOrientation to the same value.

nOrientation

Specifies the angle, in tenths of degrees, between each character's base line and the x-axis of the device.

fnWeight

Specifies the weight of the font in the range 0 through 1000. For example, 400 is normal and 700 is bold. If this value is zero, a default weight is used.

The following values are defined for convenience:

Value	Weight
FW_DONTCARE	0
FW_THIN	100
FW_EXTRALIGHT	200
FW_ULTRALIGHT	200
FW_LIGHT	300
FW_NORMAL	400
FW_REGULAR	400
FW_MEDIUM	500
FW_SEMIBOLD	600
FW_DEMIBOLD	600
FW_BOLD	700
FW_EXTRABOLD	800
FW_ULTRABOLD	800
FW_HEAVY	900
FW_BLACK	900
fdwItalic

Specifies an italic font if set to TRUE.

fdwUnderline

Specifies an underlined font if set to TRUE.

fdwStrikeOut

Specifies a strikeout font if set to TRUE.

fdwCharSet

Specifies the character set. The following values are predefined:

ANSI_CHARSET
DEFAULT_CHARSET
SYMBOL_CHARSET
SHIFTJIS_CHARSET
GB2312_CHARSET
HANGEUL_CHARSET
CHINESEBIG5_CHARSET
OEM_CHARSET

Windows 95 only:

JOHAB_CHARSET
HEBREW_CHARSET
ARABIC_CHARSET
GREEK_CHARSET
TURKISH_CHARSET
THAI_CHARSET
EASTEUROPE_CHARSET
RUSSIAN_CHARSET
MAC_CHARSET
BALTIC_CHARSET

The OEM_CHARSET value specifies a character set that is operating-system dependent.

You can use the DEFAULT_CHARSET value to allow the name and size of a font to fully describe the logical font. If the specified font name does not exist, a font from any character set can be substituted for the specified font, so you should use DEFAULT_CHARSET sparingly to avoid unexpected results.

Fonts with other character sets may exist in the operating system. If an application uses a font with an unknown character set, it should not attempt to translate or interpret strings that are rendered with that font.

This parameter is important in the font mapping process. To ensure consistent results, specify a specific character set. If you specify a typeface name in the lpszFace parameter, make sure that the fdwCharSet value matches the character set of the typeface specified in lpszFace.

fdwOutputPrecision

Specifies the output precision. The output precision defines how closely the output must match the requested font's height, width, character orientation, escapement, pitch, and font type. It can be one of the following values:

Value	Meaning
OUT_CHARACTER_PRECIS	Not used.
OUT_DEFAULT_PRECIS	Specifies the default font mapper behavior.
OUT_DEVICE_PRECIS	Instructs the font mapper to choose a Device font when the system contains multiple fonts with the same name.
OUT_OUTLINE_PRECIS	Windows NT: This value instructs the font mapper to choose from TrueType and other outline-based fonts. Windows 95: This value is not used.
OUT_RASTER_PRECIS	Instructs the font mapper to choose a raster font when the system contains multiple fonts with the same name.
OUT_STRING_PRECIS	This value is not used by the font mapper, but it is returned when raster fonts are enumerated.
OUT_STROKE_PRECIS	Windows NT: This value is not used by the font mapper, but it is returned when TrueType, other outline-based fonts, and vector fonts are enumerated.  Windows 95: This value is used to map vector fonts, and is returned when TrueType or vector fonts are enumerated.
OUT_TT_ONLY_PRECIS	Instructs the font mapper to choose from only TrueType fonts. If there are no TrueType fonts installed in the system, the font mapper returns to default behavior.
OUT_TT_PRECIS	Instructs the font mapper to choose a TrueType font when the system contains multiple fonts with the same name.
Applications can use the OUT_DEVICE_PRECIS, OUT_RASTER_PRECIS, and OUT_TT_PRECIS values to control how the font mapper chooses a font when the operating system contains more than one font with a given name. For example, if an operating system contains a font named Symbol in raster and TrueType form, specifying OUT_TT_PRECIS forces the font mapper to choose the TrueType version. Specifying OUT_TT_ONLY_PRECIS forces the font mapper to choose a TrueType font, even if it must substitute a TrueType font of another name.

fdwClipPrecision

Specifies the clipping precision. The clipping precision defines how to clip characters that are partially outside the clipping region. It can be one or more of the following values:

Value	Meaning
CLIP_DEFAULT_PRECIS	Specifies default clipping behavior.
CLIP_CHARACTER_PRECIS	Not used.
CLIP_STROKE_PRECIS	Not used by the font mapper, but is returned when raster, vector, or TrueType fonts are enumerated. Windows NT: For compatibility, this value is always returned when enumerating fonts.
CLIP_MASK	Not used.
CLIP_EMBEDDED	You must specify this flag to use an embedded read-only font.
CLIP_LH_ANGLES	When this value is used, the rotation for all fonts depends on whether the orientation of the coordinate system is left-handed or right-handed.  If not used, device fonts always rotate counterclockwise, but the rotation of other fonts is dependent on the orientation of the coordinate system. For more information about the orientation of coordinate systems, see the description of the nOrientation parameter
CLIP_TT_ALWAYS	Not used.
fdwQuality

Specifies the output quality. The output quality defines how carefully GDI must attempt to match the logical-font attributes to those of an actual physical font. It can be one of the following values:

Value	Meaning
DEFAULT_QUALITY	Appearance of the font does not matter.
DRAFT_QUALITY	Appearance of the font is less important than when the PROOF_QUALITY value is used. For GDI raster fonts, scaling is enabled, which means that more font sizes are available, but the quality may be lower. Bold, italic, underline, and strikeout fonts are synthesized if necessary.
PROOF_QUALITY	Character quality of the font is more important than exact matching of the logical-font attributes. For GDI raster fonts, scaling is disabled and the font closest in size is chosen. Although the chosen font size may not be mapped exactly when PROOF_QUALITY is used, the quality of the font is high and there is no distortion of appearance. Bold, italic, underline, and strikeout fonts are synthesized if necessary.
fdwPitchAndFamily

Specifies the pitch and family of the font. The two low-order bits specify the pitch of the font and can be one of the following values:

DEFAULT_PITCH
FIXED_PITCH
VARIABLE_PITCH

The four high-order bits specify the font family and can be one of the following values:

Value	Description
FF_DECORATIVE	Novelty fonts. Old English is an example.
FF_DONTCARE	Don't care or don't know.
FF_MODERN	Fonts with constant stroke width, with or without serifs. Pica, Elite, and Courier New® are examples.
FF_ROMAN	Fonts with variable stroke width and with serifs. MS® Serif is an example.
FF_SCRIPT	Fonts designed to look like handwriting. Script and Cursive are examples.
FF_SWISS	Fonts with variable stroke width and without serifs. MS Sans Serif is an example.
An application can specify a value for the fdwPitchAndFamily parameter by using the Boolean OR operator to join a pitch constant with a family constant.

Font families describe the look of a font in a general way. They are intended for specifying fonts when the exact typeface requested is not available.

lpszFace

Points to a null-terminated string that specifies the typeface name of the font. The length of this string must not exceed 32 characters, including the null terminator. The EnumFontFamilies function can be used to enumerate the typeface names of all currently available fonts.

If lpszFace is NULL or points to an empty string, GDI uses the first font that matches the other specified attributes.

Return Value

If the function succeeds, the return value is a handle of a logical font.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

When you no longer need the font, call the DeleteObject function to delete it.

To help protect the copyrights of vendors who provide fonts for Windows operating systems, applications should always report the exact name of a selected font. Because available fonts can vary from system to system, do not assume that the selected font is always the same as the requested font. For example, if you request a font named "Palatino," but no such font is available on the system, the font mapper will substitute a font that has similar attributes but a different name. Always report the name of the selected font to the user.

See Also

DeleteObject, SelectObject, EnumFontFamilies


CreateFontIndirect
CreateFontIndirect  QuickInfo  Overview  Group

The CreateFontIndirect function creates a logical font that has the characteristics specified in the specified structure. The font can subsequently be selected as the current font for any device context.

HFONT CreateFontIndirect(

CONST LOGFONT  *lplf	// address of logical font structure
);
Parameters

lplf

Points to a LOGFONT structure that defines the characteristics of the logical font.

Return Value

If the function succeeds, the return value is a handle of a logical font.

If the function fails, the return value is NULL.

Remarks

The CreateFontIndirect function creates a logical font with the characteristics specified in the LOGFONT structure. When this font is selected by using the SelectObject function, GDI's font mapper attempts to match the logical font with an existing physical font. If it fails to find an exact match, it provides an alternative whose characteristics match as many of the requested characteristics as possible.

When you no longer need the font, call the DeleteObject function to delete it.

See Also

DeleteObject, LOGFONT, SelectObject


CreateHalftonePalette
CreateHalftonePalette  QuickInfo  Overview  Group

The CreateHalftonePalette function creates a halftone palette for the specified device context.

HPALETTE CreateHalftonePalette(

HDC  hdc	// handle of device context
);
Parameters

hdc

Identifies the device context.

Return Value

If the function succeeds, the return value identifies a logical halftone palette.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

An application should create a halftone palette when the stretching mode of a device context is set to HALFTONE. The logical halftone palette returned by CreateHalftonePalette should then be selected and realized into the device context before the StretchBlt or StretchDIBits function is called.

When you no longer need the palette, call the DeleteObject function to delete it.

See Also

DeleteObject, RealizePalette, SelectPalette, SetStretchBltMode, StretchDIBits, StretchBlt


CreateHatchBrush
CreateHatchBrush  QuickInfo  Overview  Group

The CreateHatchBrush function creates a logical brush that has the specified hatch pattern and color.

HBRUSH CreateHatchBrush(

int  fnStyle,	// hatch style
COLORREF  clrref	// color value
);
Parameters

fnStyle

Specifies the hatch style of the brush. This parameter can be any one of the following values:

Value	Meaning
HS_BDIAGONAL	45-degree downward left-to-right hatch
HS_CROSS	Horizontal and vertical crosshatch
HS_DIAGCROSS	45-degree crosshatch
HS_FDIAGONAL	45-degree upward left-to-right hatch
HS_HORIZONTAL	Horizontal hatch
HS_VERTICAL	Vertical hatch
clrref

Specifies the foreground color of the brush that is used for the hatches.

Return Value

If the function succeeds, the return value identifies a logical brush.

If the function fails, the return value is NULL.

Remarks

A brush is a bitmap that Windows uses to paint the interiors of filled shapes.

After an application creates a brush by calling CreateHatchBrush, it can select that brush into any device context by calling the SelectObject function.

If an application uses a hatch brush to fill the backgrounds of both a parent and a child window with matching color, it may be necessary to set the brush origin before painting the background of the child window. You can do this by having your application call the SetBrushOrgEx function. Your application can retrieve the current brush origin by calling the GetBrushOrgEx function.

When you no longer need the brush, call the DeleteObject function to delete it.

See Also

CreateDIBPatternBrush, CreateDIBPatternBrushPt, CreatePatternBrush, CreateSolidBrush, DeleteObject, GetBrushOrgEx, SelectObject, SetBrushOrgEx


CreateIC
CreateIC  QuickInfo  Overview  Group

The CreateIC function creates an information context for the specified device. The information context provides a fast way to get information about the device without creating a device context.

HDC CreateIC(

LPCTSTR  lpszDriver,	// address of string specifying driver name
LPCTSTR  lpszDevice,	// address of string specifying device name
LPCTSTR  lpszOutput,	// address of string specifying port or file name
CONST DEVMODE *  lpdvmInit	// address of optional initialization data
);
Parameters

lpszDriver

Points to a null-terminated character string that specifies the name of the device driver (for example, "Epson").

lpszDevice

Points to a null-terminated character string that specifies the name of the specific output device being used, as shown by the Print Manager (for example, "Epson FX-80"). It is not the printer model name. The lpszDevice parameter must be used.

lpszOutput

Points to a null-terminated character string that specifies the file or device name for the physical output medium (file or output port). This parameter is ignored; it is present only to keep the function prototype identical with Windows version 3.1.

lpdvmInit

Points to a DEVMODE structure containing device-specific initialization data for the device driver. The DocumentProperties function retrieves this structure filled in for a given device. The lpdvmInit parameter must be NULL if the device driver is to use the default initialization (if any) specified by the user.

Return Value

If the function succeeds, the return value is the handle of an information context.

If the function fails, the return value is NULL.

Remarks

An error occurs if an application calls a GDI drawing function and supplies a handle identifying an information context.

When you no longer need the information device context, call the DeleteDC function to delete it.

See Also

DeleteDC, DocumentProperties, DEVMODE, GetDeviceCaps


CreateIcon
CreateIcon  QuickInfo  Overview  Group

The CreateIcon function creates an icon that has the specified size, colors, and bit patterns.

HICON CreateIcon(

HINSTANCE  hInstance,	// handle of application instance
int  nWidth,	// icon width
int  nHeight,	// icon height
BYTE  cPlanes,	// number of planes in XOR bitmask
BYTE  cBitsPixel,	// number of bits per pixel in XOR bitmask
CONST BYTE  *lpbANDbits,	// address of AND bitmask array
CONST BYTE  *lpbXORbits	// address of XOR bitmask array
);
Parameters

hInstance

Identifies the instance of the module creating the icon.

nWidth

Specifies the width, in pixels, of the icon.

nHeight

Specifies the height, in pixels, of the icon.

cPlanes

Specifies the number of planes in the XOR bitmask of the icon.

cBitsPixel

Specifies the number of bits per pixel in the XOR bitmask of the icon.

lpbANDbits

Points to an array of bytes that contains the bit values for the AND bitmask of the icon. This bitmask describes a monochrome bitmap.

lpbXORbits

Points to an array of bytes that contains the bit values for the XOR bitmask of the icon. This bitmask describes a monochrome or device-dependent color bitmap.

Return Value

If the function succeeds, the return value is the handle of an icon.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

The nWidth and nHeight parameters must specify a width and height supported by the current display driver, because the system cannot create icons of other sizes. To determine the width and height supported by the display driver, use the GetSystemMetrics function, specifying the SM_CXICON or SM_CYICON value.

CreateIcon applies the following truth table to the AND and XOR bitmasks:

AND bitmask	XOR bitmask	Display
0	0	Black
0	1	White
1	0	Screen
1	1	Reverse screen
Before closing, an application must call the DestroyIcon function to free system resources associated with the icon.

See Also

DestroyIcon, GetSystemMetrics


CreateIconFromResource
CreateIconFromResource  QuickInfo  Overview  Group

The CreateIconFromResource function creates an icon or cursor from resource bits describing the icon.

HICON CreateIconFromResource(

PBYTE  presbits,	// address of icon or cursor bits
DWORD  dwResSize,	// number of bytes in bit buffer
BOOL  fIcon,	// icon or cursor flag
DWORD  dwVer	// Windows format version
);
Parameters

presbits

Points to a buffer containing the icon or cursor resource bits. These bits are typically loaded by calls to the LookupIconIdFromDirectory (in Windows 95 you can also call LookupIconIdFromDirectoryEx) and LoadResource functions.

dwResSize

Specifies the size, in bytes, of the set of bits pointed to by the presbits parameter.

fIcon

Specifies whether an icon or a cursor is to be created. If this parameter is TRUE, an icon is to be created. If it is FALSE, a cursor is to be created.

dwVer

Specifies the version number of the icon or cursor format for the resource bits pointed to by the presbits parameter. This parameter can be one of the following values:

Format	dwVer
Windows 2.x	0x00020000
Windows 3.x	0x00030000
All Microsoft Win32-based applications use the Windows 3.x format for icons and cursors.

Return Value

If the function succeeds, the return value is the handle of the icon or cursor.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

The CreateIconFromResource, CreateIconIndirect, GetIconInfo, and LookupIconIdFromDirectory functions (and in Windows 95 the CreateIconFromResourceEx and LookupIconIdFromDirectoryEx functions) allow shell applications and icon browsers to examine and use resources from throughout the system.

See Also

CreateIconFromResource, CreateIconFromResourceEx, CreateIconIndirect, GetIconInfo, LoadResource, LookupIconIdFromDirectory LookupIconIdFromDirectoryEx


CreateIconFromResourceEx [New - Windows 95]
CreateIconFromResourceEx  QuickInfo

[New - Windows 95]

The CreateIconFromResourceEx function creates an icon or cursor from resource bits describing the icon.

HICON CreateIconFromResourceEx(

PBYTE  pbIconBits,	// address of icon or cursor bits
DWORD  cbIconBits,	// number of bytes in bit buffer
BOOL  fIcon,	// icon or cursor flag
DWORD  dwVersion,	// Windows format version
int  cxDesired,	// desired width of icon or cursor
int  cyDesired,	// desired height of icon or cursor
UINT  uFlags	// load resource flags
);
Parameters

pbIconBits

Points to a buffer containing the icon or cursor resource bits. These bits are typically loaded by calls to the LookupIconIdFromDirectoryEx and LoadResource functions.

cbIconBits

Specifies the size, in bytes, of the set of bits pointed to by the pbIconBits parameter.

fIcon

Specifies whether an icon or a cursor is to be created. If this parameter is TRUE, an icon is to be created. If it is FALSE, a cursor is to be created.

dwVersion

Specifies the version number of the icon or cursor format for the resource bits pointed to by the pbIconBits parameter. This parameter can be one of the following values:

Format	dwVersion
Windows 2.x	0x00020000
Windows 3.x	0x00030000
All Win32-based applications use the Windows 3.x format for icons and cursors.

cxDesired

Specifies the desired width, in pixels, of the icon or cursor. If this parameter is zero and uFlags does not include LR_LOADREALSIZE, the function uses the SM_CXICON or SM_CXCURSOR system metric value to set the width.

cyDesired

Specifies the desired height, in pixels, of the icon or cursor. If this parameter is zero and uFlags does not include LR_LOADREALSIZE, the function uses the SM_CYICON or SM_CYCURSOR system metric value to set the height.

uFlags

Specifies a combination of the following values:

Value	Meaning
LR_DEFAULTCOLOR	Uses the default color format.
LR_LOADREALSIZE	Sets the width and height as specified by the biWidth and biHeight members of the BITMAPINFOHEADER structure that defines the icon or cursor. The cxDesired and cyDesired parameters are ignored.
LR_MONOCHROME	Creates a monochrome icon or cursor.
Return Value

If the function succeeds, the return value is the handle of the icon or cursor.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

The CreateIconFromResourceEx, CreateIconFromResource, CreateIconIndirect, GetIconInfo, and LookupIconIdFromDirectoryEx functions allow shell applications and icon browsers to examine and use resources from throughout the system.

See Also

BITMAPINFOHEADER, CreateIconFromResource, CreateIconIndirect, GetIconInfo, LoadResource, LookupIconIdFromDirectoryEx


CreateIconIndirect
CreateIconIndirect  QuickInfo  Overview  Group

The CreateIconIndirect function creates an icon or cursor from an ICONINFO structure.

HICON CreateIconIndirect(

PICONINFO  piconinfo	// address of icon information structure
);
Parameters

piconinfo

Points to an ICONINFO structure the function uses to create the icon or cursor.

Return Value

If the function succeeds, the return value is the handle of the icon or cursor that is created.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

The system copies the bitmaps in the ICONINFO structure before creating the icon or cursor. The application must continue to manage the original bitmaps and delete them when they are no longer necessary.

See Also

CreateIcon, CreateIconFromResource, DestroyIcon, DrawIcon, GetIconInfo, ICONINFO, LoadIcon, LookupIconIdFromDirectory


CreateIoCompletionPort
CreateIoCompletionPort  QuickInfo  Overview  Group

The CreateIoCompletionPort function associates an instance of an opened file with a newly created or an existing input/output completion port.

Associating an instance of an opened file with an input/output completion port lets an application receive notification of the completion of asynchronous input/output operations involving that file.

Windows NT only:

CreateIoCompletionPort can create an input/output completion port without associating it with a file.

HANDLE CreateIoCompletionPort (

HANDLE FileHandle,	// file handle to associate with I/O completion port
HANDLE ExistingCompletionPort,	// optional handle to existing I/O completion port
DWORD CompletionKey,	// per-file completion key for I/O completion packets
DWORD NumberOfConcurrentThreads	// number of threads allowed to execute concurrently
);
Parameters

FileHandle

Handle to a file opened for overlapped input/output completion. You must specify the FILE_FLAG_OVERLAPPED flag to obtain such a handle.

The CreateIoCompletionPort function associates the file with an existing input/output completion port, or with one that the function creates.

Once an instance of an open file is associated with an I/O completion port, it cannot be used in ReadFileEx or WriteFileEx operations.

It is best not to share such an associated file through either handle inheritance or a call to the DuplicateHandle function. Input/output operations done with such duplicate handles will generate completion notifications.

Windows NT:

If FileHandle specifies INVALID_HANDLE_VALUE, CreateIoCompletionPort creates an input/output completion port without associating it with a file. In this case, the ExistingCompletionPort parameter must be NULL, and the CompletionKey parameter is ignored.

Windows 95:

Does not support specifying INVALID_HANDLE_VALUE for the FileHandle parameter.

ExistingCompletionPort

Handle to an existing I/O completion port. This parameter can be NULL.

If this parameter is not NULL, it specifies an existing completion port that the function is to associate with the file specified by FileHandle.

If this parameter is NULL, the function creates a new input/output completion port that it associates with the specified file.

CompletionKey

Specifies a per-file completion key that will be included in every input/output completion packet for the specified file.

NumberOfConcurrentThreads

Specifies the number of threads that are allowed to execute concurrently.

If one of the threads enters a wait state, then another thread is allowed to proceed. There may be brief periods when the number of active threads exceeds the specified value, but the operating system quickly brings the number back down.

A value of 0 for this parameter tells the operating system to allow as many threads as there are processors in the system.

Return Value

If the function succeeds, the return value is the handle of the I/O completion port that is associated with the specified file. This return value is not NULL.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

The Win32 I/O system can be instructed to send I/O completion notification packets to input/output completion ports, where they are queued up. The CreateIoCompletionPort function provides a mechanism for this.

When you perform an input/output operation with a file handle that has an associated input/output completion port, the I/O system sends a completion notification packet to the completion port when the I/O operation completes. The I/O completion port places the completion packet in a first-in-first-out queue. Use the GetQueuedCompletionStatus function to retrieve these queued I/O completion packets.

You can create an I/O completion port without an associated instance of an open file. To do this, just specify the INVALID_HANDLE_VALUE flag in FileHandle. Use PostQueuedCompletionStatus to write I/O completion notification packets to the port and GetQueuedCompletionStatus to retrieve the packets. This provides a means for different threads within a process to communicate with each other.

See Also

DuplicateHandle, GetQueuedCompletionStatus, PostQueuedCompletionStatus, ReadFileEx, WriteFileEx


CreateMailslot
CreateMailslot  QuickInfo  Overview  Group

The CreateMailslot function creates a mailslot with the specified name and returns a handle that a mailslot server can use to perform operations on the mailslot. The mailslot is local to the computer that creates it. An error occurs if a mailslot with the specified name already exists.

HANDLE CreateMailslot(

LPCTSTR  lpName,	// address of string for mailslot name
DWORD  nMaxMessageSize,	// maximum message size
DWORD  lReadTimeout,	// milliseconds before read time-out
LPSECURITY_ATTRIBUTES  lpSecurityAttributes	// address of security structure
);
Parameters

lpName

Points to a null-terminated string specifying the name of the mailslot. This name must have the following form:

\\.\mailslot\[path]name

The name field must be unique. The name may include multiple levels of pseudodirectories separated by backslashes. For example, both \\.\mailslot\example_mailslot_name and \\.\mailslot\abc\def\ghi are valid names.

nMaxMessageSize

Specifies the maximum size, in bytes, of a single message that can be written to the mailslots. To specify that the message can be of any size, set this value to zero.

lReadTimeout

Specifies the amount of time, in milliseconds, a read operation can wait for a message to be written to the mailslot before a time-out occurs. The following values have special meanings:

Value	Meaning
0	Returns immediately if no message is present. (The system does not treat an immediate return as an error.)
MAILSLOT_WAIT_FOREVER	Waits forever for a message.
This time-out value applies to all subsequent read operations and all inherited mailslot handles.

lpSecurityAttributes

Points to a SECURITY_ATTRIBUTES structure specifying the security attributes for the mailslot.

If lpSecurityAttributes is NULL, the mailslot is created with a default security descriptor, and the resulting handle is not inherited.

Return Value

If the function succeeds, the return value is a handle to the mailslot, for use in server mailslot operations.

If the function fails, the return value is INVALID_HANDLE_VALUE. To get extended error information, call GetLastError.

Remarks

The mailslot exists until one of the following conditions is true:

•	The last (possibly inherited or duplicated) handle to it is closed using the CloseHandle function.

•	The process owning the last (possibly inherited or duplicated) handle exits.

Both Windows NT and Windows 95 use the second method to destroy mailslots.

To write a message to a mailslot, a process uses the CreateFile function, specifying the mailslot name by using one of the following formats:

Format	Usage
\\.\mailslot\name	Retrieves a client handle to a local mailslot.
\\computername\mailslot\name	Retrieves a client handle to a remote mailslot.
\\domainname\mailslot\name	Retrieves a client handle to all mailslots with the given name in the specified domain.
\\*\mailslot\name	Retrieves a client handle to all mailslots with the given name in the system's primary domain.
If CreateFile specifies a domain or uses the asterisk format to specify the system's primary domain, the application cannot write more than 400 bytes at a time to the mailslot. If the application attempts to do so, the WriteFile function fails and GetLastError returns ERROR_BAD_NETPATH.

An application must specify the FILE_SHARE_READ flag when using CreateFile to retrieve a client handle to a mailslot.

See Also

CloseHandle, CreateFile, GetMailslotInfo, SECURITY_ATTRIBUTES, SetMailslotInfo, WriteFile


CreateMappedBitmap [New - Windows NT]
CreateMappedBitmap  QuickInfo  Overview  Group

[New - Windows NT]

The CreateMappedBitmap function creates a bitmap for use in a toolbar.

HBITMAP CreateMappedBitmap(

HINSTANCE  hInstance,
int  idBitmap,
UINT  wFlags,
LPCOLORMAP lpColorMap,
int  iNumMaps
);
Parameters

hInstance

Handle to the module instance with the executable file that contains the bitmap resource.

idBitmap

Resource identifier of the bitmap resource.

wFlags

Bitmap flag. This parameter can be zero or the following value:

Value	Meaning
CMB_MASKED	Uses a bitmap as a mask.
lpColorMap

Pointer to a COLORMAP structure that contains the color information needed to map the bitmaps. If this parameter is NULL, the function uses the default color map.

iNumMaps

Number of color maps pointed to by lpColorMap.

Return Value

If the function succeeds, the return value is the handle to the bitmap.

If the function fails, the return value is NULL.

Remarks

The function creates a new bitmap using the bitmap data and colors specified by the given bitmap resource and the color mapping information.

See Also

COLORMAP


CreateMDIWindow
CreateMDIWindow  QuickInfo  Overview  Group

The CreateMDIWindow function creates a multiple document interface (MDI) child window.

HWND CreateMDIWindow(

LPTSTR  lpClassName,	// address of registered child class name
LPTSTR  lpWindowName,	// address of window name
DWORD  dwStyle,	// window style
int  X,	// horizontal position of window
int  Y,	// vertical position of window
int  nWidth,	// width of window
int  nHeight,	// height of window
HWND  hWndParent,	// handle of parent window (MDI client)
HINSTANCE  hInstance,	// handle of application instance
LPARAM  lParam	// application-defined value
);
Parameters

lpClassName

Points to a null-terminated string specifying the window class of the MDI child window. The class name must have been registered by a call to the RegisterClass function.

lpWindowName

Points to a null-terminated string that represents the window name. Windows displays the name in the title bar of the child window.

dwStyle

Specifies the style of the MDI child window. If the MDI client window is created with the MDIS_ALLCHILDSTYLES window style, this parameter can be any combination of the window styles listed in the description of the CreateWindow function. Otherwise, this parameter can be one or more of the following values:

Value	Meaning
WS_MINIMIZE	Creates an MDI child window that is initially minimized.
WS_MAXIMIZE	Creates an MDI child window that is initially maximized.
WS_HSCROLL	Creates an MDI child window that has a horizontal scroll bar.
WS_VSCROLL	Creates an MDI child window that has a vertical scroll bar.
X

Specifies the initial horizontal position, in client coordinates, of the MDI child window. If this parameter is CW_USEDEFAULT, the MDI child window is assigned the default horizontal position.

Y

Specifies the initial vertical position, in client coordinates, of the MDI child window. If this parameter is CW_USEDEFAULT, the MDI child window is assigned the default vertical position.

nWidth

Specifies the initial width, in device units, of the MDI child window. If this parameter is CW_USEDEFAULT, the MDI child window is assigned the default width.

nHeight

Specifies the initial height, in device units, of the MDI child window. If this parameter is set to CW_USEDEFAULT, the MDI child window is assigned the default height.

hWndParent

Identifies the MDI client window that will be the parent of the new MDI child window.

hInstance

Identifies the instance of the application creating the MDI child window.

lParam

Specifies an application-defined value.

Return Value

If the function succeeds, the return value is the handle of the created window.

If the function fails, the return value is NULL.

Remarks

Using the CreateMDIWindow function is similar to sending the WM_MDICREATE message to an MDI client window, except that the function can create an MDI child window in a different thread, while the message cannot.

Windows 95 only: The system can support a maximum of 16,364 window handles.

See Also

CreateWindow, RegisterClass, WM_MDICREATE


CreateMenu
CreateMenu  QuickInfo  Overview  Group

The CreateMenu function creates a menu. The menu is initially empty, but it can be filled with menu items by using the AppendMenu and InsertMenu functions.

HMENU CreateMenu(VOID)

Parameters

This function has no parameters.

Return Value

If the function succeeds, the return value is the handle of the newly created menu.

If the function fails, the return value is NULL.

Remarks

Resources associated with a menu that is assigned to a window are freed automatically. If the menu is not assigned to a window, an application must free system resources associated with the menu before closing. An application frees menu resources by calling the DestroyMenu function.

Windows 95 only: The system can support a maximum of 16,364 menu handles.

See Also

AppendMenu, DestroyMenu, InsertMenu, SetMenu


CreateMetaFile
CreateMetaFile  QuickInfo  Overview  Group

The CreateMetaFile function creates a device context for a Windows-format metafile.

This function is provided for compatibility with earlier 16-bit versions of Microsoft Windows. Win32-based applications should use the CreateEnhMetaFile function.

HDC CreateMetaFile(

LPCTSTR  lpszFile	// address of filename string
);
Parameters

lpszFile

Points to the filename for the Windows-format metafile to be created. If this parameter is NULL, the Windows-format metafile is memory based and its contents are lost when it is deleted by using the DeleteMetaFile function.

Return Value

If the function succeeds, the return value is a handle of the device context for the Windows-format metafile.

If the function fails, the return value is NULL.

Remarks

Where text arguments must use Unicode characters, use this function as a wide-character function. Where text arguments must use characters from the Windows 3.x character set, use this function as an ANSI function.

CreateMetaFile is a Windows-format metafile function. This function supports only applications designed for Microsoft Windows version 3.x. It does not record or play back the new Win32 graphics device interface (GDI) functions such as PolyBezier.

The device context created by this function can be used to record GDI output functions in a Windows-format metafile. It cannot be used with GDI query functions such as GetTextColor. When the device context is used with a GDI output function, the return value of that function becomes TRUE if the function is recorded and FALSE otherwise. When an object is selected by using the SelectObject function, only a copy of the object is recorded. The object still belongs to the application.

To create a scalable Windows-format metafile, record the graphics output in the MM_ANISOTROPIC mapping mode. The file cannot contain functions that modify the viewport origin and extents, nor can it contain device-dependent functions such as the SelectClipRgn function. Once created, the Windows metafile can be scaled and rendered to any output device-format by defining the viewport origin and extents of the picture before playing it.

See Also

CloseMetaFile, CreateEnhMetaFile, DeleteMetaFile, GetTextColor, PolyBezier, SelectClipRgn, SelectObject


CreateMutex
CreateMutex  QuickInfo  Overview  Group

The CreateMutex function creates a named or unnamed mutex object.

HANDLE CreateMutex(

LPSECURITY_ATTRIBUTES  lpMutexAttributes,	// address of security attributes
BOOL  bInitialOwner,	// flag for initial ownership
LPCTSTR  lpName	// address of mutex-object name
);
Parameters

lpMutexAttributes

Points to a SECURITY_ATTRIBUTES structure that specifies the security attributes for the mutex object.

If lpMutexAttributes is NULL, the mutex object is created with a default security descriptor and the resulting handle is not inheritable.

bInitialOwner

Specifies the initial owner of the mutex object. If TRUE, the calling thread requests immediate ownership of the mutex object. Otherwise, the mutex is not owned.

lpName

Points to a null-terminated string specifying the name of the mutex object. The name is limited to MAX_PATH characters and can contain any character except the backslash path-separator character (\). Name comparison is case sensitive.

If lpName matches the name of an existing named mutex object, this function requests MUTEX_ALL_ACCESS access to the existing object. In this case, the bInitialOwner parameter is ignored because it has already been set by the creating process. If the lpMutexAttributes parameter is not NULL, it determines whether the handle can be inherited, but its security-descriptor member is ignored.

If lpName is NULL, the mutex object is created without a name.

If lpName matches the name of an existing event, semaphore, or file-mapping object, the function fails and the GetLastError function returns ERROR_INVALID_HANDLE. This occurs because event, mutex, semaphore, and file-mapping objects share the same name space.

Return Value

If the function succeeds, the return value is a handle of the mutex object. If the named mutex object existed before the function call, the GetLastError function returns ERROR_ALREADY_EXISTS. Otherwise, GetLastError returns zero.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

The handle returned by CreateMutex has MUTEX_ALL_ACCESS access to the new mutex object and can be used in any function that requires a handle of a mutex object.

Any thread of the calling process can specify the mutex-object handle in a call to one of the wait functions (MsgWaitForMultipleObjects, WaitForSingleObject, WaitForMultipleObjects, WaitForSingleObjectEx, or WaitForMultipleObjectsEx). The single-object wait functions return when the state of the specified object is signaled. The multiple-object wait functions can be instructed to return either when any one or when all of the specified objects are signaled. When a wait function returns, the waiting thread is released to continue its execution.

The state of a mutex object is signaled when it is not owned by any thread. The creating thread can use the bInitialOwner flag to request immediate ownership of the mutex. Otherwise, a thread must use one of the wait functions to request ownership. When the mutex's state is signaled, one waiting thread is granted ownership, the mutex's state changes to nonsignaled, and the wait function returns. Only one thread can own a mutex at any given time. The owning thread uses the ReleaseMutex function to release its ownership.

The thread that owns a mutex can specify the same mutex in repeated wait function calls without blocking its execution. Typically, you would not wait repeatedly for the same mutex, but this mechanism prevents a thread from deadlocking itself while waiting for a mutex that it already owns. However, to release its ownership, the thread must call ReleaseMutex once for each time that the mutex satisfied a wait.

Two or more processes can call CreateMutex to create the same named mutex. The first process actually creates the mutex, and subsequent processes open a handle of the existing mutex. This enables multiple processes to get handles of the same mutex, while relieving the user of the responsibility of ensuring that the creating process is started first. When using this technique, you should set the bInitialOwner flag to FALSE; otherwise, it can be difficult to be certain which process has initial ownership.

Multiple processes can have handles of the same mutex object, enabling use of the object for interprocess synchronization. The following object-sharing mechanisms are available:

•	A child process created by the CreateProcess function can inherit a handle of a mutex object if the lpMutexAttributes parameter of CreateMutex enabled inheritance.

•	A process can specify the mutex-object handle in a call to the DuplicateHandle function to create a duplicate handle that can be used by another process.

•	A process can specify the name of a mutex object in a call to the OpenMutex or CreateMutex function.

Use the CloseHandle function to close the handle. The system closes the handle automatically when the process terminates. The mutex object is destroyed when its last handle has been closed.

See Also

CloseHandle, CreateProcess, DuplicateHandle, MsgWaitForMultipleObjects, OpenMutex, ReleaseMutex, SECURITY_ATTRIBUTES, WaitForMultipleObjects, WaitForMultipleObjectsEx, WaitForSingleObject, WaitForSingleObjectEx


CreateNamedPipe
CreateNamedPipe  QuickInfo  Overview  Group

The CreateNamedPipe function creates an instance of a named pipe and returns a handle for subsequent pipe operations. A named pipe server process uses this function either to create the first instance of a specific named pipe and establish its basic attributes or to create a new instance of an existing named pipe.

HANDLE CreateNamedPipe(

LPCTSTR  lpName,	// address of pipe name
DWORD  dwOpenMode,	// pipe open mode
DWORD  dwPipeMode,	// pipe-specific modes
DWORD  nMaxInstances,	// maximum number of instances
DWORD  nOutBufferSize,	// output buffer size, in bytes
DWORD  nInBufferSize,	// input buffer size, in bytes
DWORD  nDefaultTimeOut,	// time-out time, in milliseconds
LPSECURITY_ATTRIBUTES  lpSecurityAttributes	// address of security attributes structure
);
Parameters

lpName

Points to the null-terminated string that uniquely identifies the pipe. The string must have the following form:

\\.\pipe\pipename

The pipename part of the name can include any character other than a backslash, including numbers and special characters. The entire pipe name string can be up to 256 characters long. Pipe names are not case sensitive.

dwOpenMode

Specifies the pipe access mode, the overlapped mode, the write-through mode, and the security access mode of the pipe handle.

This parameter must specify one of the following pipe access mode flags. The same mode must be specified for each instance of the pipe:

Mode	Description
PIPE_ACCESS_DUPLEX	The pipe is bidirectional; both server and client processes can read from and write to the pipe. This mode gives the server the equivalent of GENERIC_READ | GENERIC_WRITE access to the pipe. The client can specify GENERIC_READ or GENERIC_WRITE, or both, when it connects to the pipe using the CreateFile function.
PIPE_ACCESS_INBOUND	The flow of data in the pipe goes from client to server only. This mode gives the server the equivalent of GENERIC_READ access to the pipe. The client must specify GENERIC_WRITE access when connecting to the pipe.
PIPE_ACCESS_OUTBOUND	The flow of data in the pipe goes from server to client only. This mode gives the server the equivalent of GENERIC_WRITE access to the pipe. The client must specify GENERIC_READ access when connecting to the pipe.
This parameter can also include either or both of the following flags, which enable write-through mode and overlapped mode. These modes can be different for different instances of the same pipe.

Mode	Description
FILE_FLAG_WRITE_THROUGH
	Write-through mode is enabled. This mode affects only write operations on byte-type pipes and, then, only when the client and server processes are on different computers. If this mode is enabled, functions writing to a named pipe do not return until the data written is transmitted across the network and is in the pipe's buffer on the remote computer. If this mode is not enabled, the system enhances the efficiency of network operations by buffering data until a minimum number of bytes accumulate or until a maximum time elapses.
FILE_FLAG_OVERLAPPED
	Overlapped mode is enabled. If this mode is enabled, functions performing read, write, and connect operations that may take a significant time to be completed can return immediately. This mode enables the thread that started the operation to perform other operations while the time-consuming operation executes in the background. For example, in overlapped mode, a thread can handle simultaneous input and output (I/O) operations on multiple instances of a pipe or perform simultaneous read and write operations on the same pipe handle. If overlapped mode is not enabled, functions performing read, write, and connect operations on the pipe handle do not return until the operation is finished. The ReadFileEx and WriteFileEx functions can only be used with a pipe handle in overlapped mode. The ReadFile, WriteFile, ConnectNamedPipe, and TransactNamedPipe functions can execute either synchronously or as overlapped operations.
This parameter can include any combination of the following security access mode flags. These modes can be different for different instances of the same pipe. They can be specified without concern for what other dwOpenMode modes have been specified.

Mode	Description
WRITE_DAC	The caller will have write access to the named pipe's discretionary access control list (ACL).
WRITE_OWNER	The caller will have write access to the named pipe's owner.
ACCESS_SYSTEM_SECURITY	The caller will have write access to the named pipe's system ACL.
dwPipeMode

Specifies the type, read, and wait modes of the pipe handle.

One of the following type mode flags can be specified. The same type mode must be specified for each instance of the pipe. If you specify zero, the parameter defaults to byte-type mode.

Mode	Description
PIPE_TYPE_BYTE	Data is written to the pipe as a stream of bytes. This mode cannot be used with PIPE_READMODE_MESSAGE.
PIPE_TYPE_MESSAGE	Data is written to the pipe as a stream of messages. This mode can be used with either PIPE_READMODE_MESSAGE or PIPE_READMODE_BYTE.
One of the following read mode flags can be specified. Different instances of the same pipe can specify different read modes. If you specify zero, the parameter defaults to byte-read mode.

Mode	Description
PIPE_READMODE_BYTE	Data is read from the pipe as a stream of bytes. This mode can be used with either PIPE_TYPE_MESSAGE or PIPE_TYPE_BYTE.
PIPE_READMODE_MESSAGE	Data is read from the pipe as a stream of messages. This mode can be only used if PIPE_TYPE_MESSAGE is also specified.
One of the following wait mode flags can be specified. Different instances of the same pipe can specify different wait modes. If you specify zero, the parameter defaults to blocking mode.

Mode	Description
PIPE_WAIT	Blocking mode is enabled. When the pipe handle is specified in the ReadFile, WriteFile, or ConnectNamedPipe function, the operations are not completed until there is data to read, all data is written, or a client is connected. Use of this mode can mean waiting indefinitely in some situations for a client process to perform an action.
PIPE_NOWAIT	Nonblocking mode is enabled. In this mode, ReadFile, WriteFile, and ConnectNamedPipe always return immediately. Note that nonblocking mode is supported for compatibility with Microsoft LAN Manager version 2.0 and should not be used to achieve asynchronous I/O with named pipes.
nMaxInstances

Specifies the maximum number of instances that can be created for this pipe. The same number must be specified for all instances. Acceptable values are in the range 1 through PIPE_UNLIMITED_INSTANCES. If this parameter is PIPE_UNLIMITED_INSTANCES, the number of pipe instances that can be created is limited only by the availability of system resources.

nOutBufferSize

Specifies the number of bytes to reserve for the output buffer. For a discussion on sizing named pipe buffers, see the following Remarks section.

nInBufferSize

Specifies the number of bytes to reserve for the input buffer. For a discussion on sizing named pipe buffers, see the following Remarks section.

nDefaultTimeOut

Specifies the default time-out value, in milliseconds, if the WaitNamedPipe function specifies NMPWAIT_USE_DEFAULT_WAIT. Each instance of a named pipe must specify the same value.

lpSecurityAttributes

Points to a SECURITY_ATTRIBUTES structure that specifies the security attributes for the pipe. Since named pipes are implemented as a file system and that file system supports this parameter, this parameter will always have an effect when specified.

If this parameter is NULL, the pipe is created with a default security descriptor, and the resulting handle is not inherited.

Note that access to some security attributes can be granted by setting particular flags in the dwOpenMode parameter.

Return Value

If the function succeeds, the return value is a handle to the server end of a named pipe instance.

If the function fails, the return value is INVALID_HANDLE_VALUE. To get extended error information, call GetLastError. The return value is ERROR_INVALID_PARAMETER if nMaxInstances is greater than PIPE_UNLIMITED_INSTANCES.

Remarks

To create an instance of a named pipe by using CreateNamedPipe, the user must have FILE_CREATE_PIPE_INSTANCE access to the named pipe object. If a new named pipe is being created, the access control list (ACL) from the security attributes parameter defines the discretionary access control for the named pipe.

All instances of a named pipe must specify the same pipe type (byte-type or message-type), pipe access (duplex, inbound, or outbound), instance count, and time-out value. If different values are used, this function fails and GetLastError returns ERROR_ACCESS_DENIED.

The input and output buffer sizes are advisory. The actual buffer size reserved for each end of the named pipe is either the system default, the system minimum or maximum, or the specified size rounded up to the next allocation boundary.

An instance of a named pipe is always deleted when the last handle to the instance of the named pipe is closed.

See Also

ConnectNamedPipe, CreateFile, ReadFile, ReadFileEx, SECURITY_ATTRIBUTES, TransactNamedPipe, WaitNamedPipe, WriteFile, WriteFileEx


CreatePalette
CreatePalette  QuickInfo  Overview  Group

The CreatePalette function creates a logical color palette.

HPALETTE CreatePalette(

CONST LOGPALETTE  *lplgpl	// address of logical color palette
);
Parameters

lplgpl

Points to a LOGPALETTE structure that contains information about the colors in the logical palette.

Return Value

If the function succeeds, the return value is a handle that identifies a logical palette.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

An application can determine whether a device supports palette operations by calling the GetDeviceCaps function and specifying the RASTERCAPS constant.

Once an application creates a logical palette, it can select that palette into a device context by calling the SelectPalette function. A palette selected into a device context can be realized by calling the RealizePalette function.

When you no longer need the palette, call the DeleteObject function to delete it.

See Also

DeleteObject, GetDeviceCaps, LOGPALETTE, RealizePalette, SelectPalette


CreatePatternBrush
CreatePatternBrush  QuickInfo  Overview  Group

The CreatePatternBrush function creates a logical brush with the specified bitmap pattern. The bitmap cannot be a DIB section bitmap, which is created by the CreateDIBSection function.

HBRUSH CreatePatternBrush(

HBITMAP  hbmp	// handle of bitmap
);
Parameters

hbmp

Identifies the bitmap to be used to create the logical brush.

Return Value

If the function succeeds, the return value identifies a logical brush.

If the function fails, the return value is NULL.

Remarks

A pattern brush is a bitmap that Windows uses to paint the interiors of filled shapes.

After an application creates a brush by calling CreatePatternBrush, it can select that brush into any device context by calling the SelectObject function.

You can delete a pattern brush without affecting the associated bitmap by using the DeleteObject function. Therefore, you can then use this bitmap to create any number of pattern brushes.

A brush created by using a monochrome (1 bit per pixel) bitmap has the text and background colors of the device context to which it is drawn. Pixels represented by a 0 bit are drawn with the current text color; pixels represented by a 1 bit are drawn with the current background color.

The bitmap identified by hbmp cannot be a DIB section, which is a bitmap created by the CreateDIBSection function. If the bitmap is a DIB section, the CreatePatternBrush function fails.

Windows 95: Creating brushes from bitmaps or DIBs larger than 8x8 pixels is not supported. If a larger bitmap is given, only a portion of the bitmap is used.

See Also

CreateBitmap, CreateBitmapIndirect, CreateCompatibleBitmap, CreateDIBPatternBrush, CreateDIBPatternBrushPt, CreateDIBSection, CreateHatchBrush, DeleteObject, GetBrushOrgEx, LoadBitmap, SelectObject, SetBrushOrgEx


CreatePen
CreatePen  QuickInfo  Overview  Group

The CreatePen function creates a logical pen that has the specified style, width, and color. The pen can subsequently be selected into a device context and used to draw lines and curves.

HPEN CreatePen(

int  fnPenStyle,	// pen style
int  nWidth,	// pen width
COLORREF  crColor	// pen color
);
Parameters

fnPenStyle

Specifies the pen style. It can be any one of the following values:

Style	Description
PS_SOLID	Pen is solid.
PS_DASH	Pen is dashed. This style is valid only when the pen width is one or less in device units.
PS_DOT	Pen is dotted. This style is valid only when the pen width is one or less in device units.
PS_DASHDOT	Pen has alternating dashes and dots. This style is valid only when the pen width is one or less in device units.
PS_DASHDOTDOT	Pen has alternating dashes and double dots. This style is valid only when the pen width is one or less in device units.
PS_NULL	Pen is invisible.
PS_INSIDEFRAME	Pen is solid. When this pen is used in any graphics device interface (GDI) drawing function that takes a bounding rectangle, the dimensions of the figure are shrunk so that it fits entirely in the bounding rectangle, taking into account the width of the pen. This applies only to geometric pens.
nWidth

Specifies the width of the pen, in logical units. If nWidth is zero, the pen is a single pixel wide, regardless of the current transformation.

crColor

Specifies a color reference for the pen color.

Return Value

If the function succeeds, the return value is a handle that identifies a logical pen.

If the function fails, the return value is NULL.

Remarks

After an application creates a logical pen, it can select that pen into a device context by calling the SelectObject function. After a pen is selected into a device context, it can be used to draw lines and curves.

If the value specified by the nWidth parameter is zero, a line drawn with the created pen will always be a single pixel wide regardless of the current transformation.

If the value specified by nWidth is greater than 1, the fnPenStyle parameter must be PS_NULL, PS_SOLID, or PS_INSIDEFRAME.

If the value specified by nWidth is greater than 1 and fnPenStyle is PS_INSIDEFRAME, the line associated with the pen is drawn inside the frame of all primitives except polygons and polylines.

If the value specified by nWidth is greater than 1, fnPenStyle is PS_INSIDEFRAME, and the color specified by the crColor parameter does not match one of the entries in the logical palette, Windows draws lines by using a dithered color. Dithered colors are not available with solid pens.

When you no longer need the pen, call the DeleteObject function to delete it.

See Also

CreatePenIndirect, DeleteObject, ExtCreatePen, GetObject, RGB, SelectObject


CreatePenIndirect
CreatePenIndirect  QuickInfo  Overview  Group

The CreatePenIndirect function creates a logical cosmetic pen that has the style, width, and color specified in a structure.

HPEN CreatePenIndirect(

CONST LOGPEN *  lplgpn	// address of LOGPEN structure
);
Parameters

lplgpn

Points to the LOGPEN structure that specifies the pen's style, width, and color.

Return Value

If the function succeeds, the return value is a handle that identifies a logical cosmetic pen.

If the function fails, the return value is NULL.

Remarks

After an application creates a logical pen, it can select that pen into a device context by calling the SelectObject function. After a pen is selected into a device context, it can be used to draw lines and curves.

When you no longer need the pen, call the DeleteObject function to delete it.

See Also

CreatePen, DeleteObject, ExtCreatePen, GetObject, LOGPEN, RGB, SelectObject


CreatePipe
CreatePipe  QuickInfo  Overview  Group

The CreatePipe function creates an anonymous pipe, and returns handles to the read and write ends of the pipe.

BOOL CreatePipe(

PHANDLE  hReadPipe,	// address of variable for read handle
PHANDLE  hWritePipe,	// address of variable for write handle
LPSECURITY_ATTRIBUTES  lpPipeAttributes,	// address of security attributes
DWORD  nSize	// number of bytes reserved for pipe
);
Parameters

hReadPipe

Points to the variable that receives the read handle for the pipe.

hWritePipe

Points to the variable that receives the write handle for the pipe.

lpPipeAttributes

Points to a SECURITY_ATTRIBUTES structure that specifies the security attributes for the pipe. The file system must support this parameter for it to have an effect.

If lpPipeAttributes is NULL, the pipe is created with a default security descriptor, and the resulting handle is not inherited.

nSize

Specifies the buffer size for the pipe. The size is only a suggestion; the system uses the value to calculate an appropriate buffering mechanism. If this parameter is zero, the system uses the default buffer size.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

CreatePipe creates the pipe, assigning the specified pipe size to the storage buffer. CreatePipe also creates handles that the process uses to read from and write to the buffer in subsequent calls to the ReadFile and WriteFile functions.

When a process uses WriteFile to write to an anonymous pipe, the write operation is not completed until all bytes are written. If the pipe buffer is full before all bytes are written, WriteFile does not return until another process or thread uses ReadFile to make more buffer space available.

See Also

ReadFile, SECURITY_ATTRIBUTES, WriteFile


CreatePolygonRgn
CreatePolygonRgn  QuickInfo  Overview  Group

The CreatePolygonRgn function creates a polygonal region.

HRGN CreatePolygonRgn(

CONST POINT  *lppt,	// address of array of points
int  cPoints,	// number of points in array
int  fnPolyFillMode	// polygon-filling mode
);
Parameters

lppt

Points to an array of POINT structures that define the vertices of the polygon. The polygon is presumed closed. Each vertex can be specified only once.

cPoints

Specifies the number of points in the array.

fnPolyFillMode

Specifies the fill mode used to determine which pixels are in the region. This parameter can be one of the following values:

Value	Meaning
ALTERNATE	Selects alternate mode (fills area between odd-numbered and even-numbered polygon sides on each scan line).
WINDING	Selects winding mode (fills any region with a nonzero winding value).
For more information about these modes, see the SetPolyFillMode function.

Return Value

If the function succeeds, the return value is the handle of the region.

If the function fails, the return value is NULL.

See Also

CreatePolyPolygonRgn, DeleteObject, POINT, SelectObject, SetPolyFillMode


CreatePolyPolygonRgn
CreatePolyPolygonRgn  QuickInfo  Overview  Group

The CreatePolyPolygonRgn function creates a region consisting of a series of polygons. The polygons can overlap.

HRGN CreatePolyPolygonRgn(

CONST POINT  *lppt,	// address of array of points
CONST INT  *lpPolyCounts,	// address of array that contains vertex counts
int  nCount,	// number of integers in array of vertex counts
int  fnPolyFillMode	// polygon fill mode
);
Parameters

lppt

Points to an array of POINT structures that define the vertices of the polygons. The polygons are specified consecutively. Each polygon is presumed closed and each vertex is specified only once.

lpPolyCounts

Points to an array of integers, each of which specifies the number of points in one of the polygons in the array pointed to by lppt.

nCount

Specifies the total number of integers in the array pointed to by lpPolyCounts.

fnPolyFillMode

Specifies the fill mode used to determine which pixels are in the region. This parameter can be one of the following values:

Value	Meaning
ALTERNATE	Selects alternate mode (fills area between odd-numbered and even-numbered polygon sides on each scan line).
WINDING	Selects winding mode (fills any region with a nonzero winding value).
For more information about these modes, see the SetPolyFillMode function.

Return Value

If the function succeeds, the return value is the handle of the region.

If the function fails, the return value is zero.

See Also

CreatePolygonRgn, DeleteObject, POINT, SelectObject, SetPolyFillMode


CreatePopupMenu
CreatePopupMenu  QuickInfo  Overview  Group

The CreatePopupMenu function creates a pop-up menu. The menu is initially empty, but it can be filled with menu items by using the AppendMenu and InsertMenu functions (in Windows 95 you can also use the InsertMenuItem function to both append and insert menu items).

HMENU CreatePopupMenu(VOID)

Parameters

This function has no parameters.

Return Value

If the function succeeds, the return value is the handle of the newly created pop-up menu.

If the function fails, the return value is NULL.

Remarks

The application can add the pop-up menu to an existing menu or pop-up menu, or it can display a floating pop-up menu by calling the TrackPopupMenu function.

Resources associated with a pop-up menu that is assigned to a window are freed automatically. If the pop-up menu is not assigned to a window, an application must free system resources associated with the menu before closing. An application frees menu resources by calling the DestroyMenu function.

Windows 95 only: The system can support a maximum of 16,364 menu handles.

See Also

AppendMenu, CreateMenu, DestroyMenu, InsertMenu, SetMenu, TrackPopupMenu


CreatePrivateObjectSecurity
CreatePrivateObjectSecurity  QuickInfo  Overview  Group

The CreatePrivateObjectSecurity function allocates and initializes a self-relative security descriptor for a new protected server's object. This function is called when a new protected server object is being created.

BOOL CreatePrivateObjectSecurity(

PSECURITY_DESCRIPTOR  ParentDescriptor,	// address of parent directory SD
PSECURITY_DESCRIPTOR  CreatorDescriptor,	// address of creator SD
PSECURITY_DESCRIPTOR *  NewDescriptor,	// address of pointer to new SD
BOOL  IsDirectoryObject,	// container flag for new SD
HANDLE  Token,	// handle of client's access token
PGENERIC_MAPPING  GenericMapping	// address of access-rights structure
);
Parameters

ParentDescriptor

Points to the security descriptor for the parent directory in which a new object is being created. If there is no parent directory, this parameter can be NULL.

CreatorDescriptor

Points to a security descriptor provided by the creator of the object. If the object's creator does not explicitly pass security information for the new object, this parameter is intended to be NULL.

lppsdNew

Points to a pointer to the newly allocated security descriptor created when the function returns.

IsDirectoryObject

Specifies whether the new object is a container. A value of TRUE indicates the object contains other objects, such as a directory.

Token

Identifies the access token for the client process on whose behalf the object is being created. If this is an impersonation token, it must be at SecurityIdentification level or higher. For a full description of the SecurityIdentification impersonation level, see the SECURITY_IMPERSONATION_LEVEL enumerated type

A client token is used to retrieve default security information for the new object, such as its default owner, primary group, and discretionary access-control list. The token must be open for TOKEN_QUERY access.

GenericMapping

Points to a GENERIC_MAPPING structure that specifies the mapping from each generic right to specific rights for the object.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

If a system access-control list, or SACL, is specified in the SECURITY_DESCRIPTOR specified by CreatorDescriptor, Token must have SeSecurityPrivilege enabled, and the caller's token must have SeAuditPrivilege enabled. The CreatePrivateObjectSecurity function performs access/privilege checks to ensure this, and may generate audits during the process.

The CreatePrivateObjectSecurity function may send many messages to port objects. This can result in a significant delay before the function returns. Be sure to take this potential delay into account when designing an application that calls CreatePrivateObjectSecurity. An application that uses mutexes to lock structures, for example, usually seeks to avoid such potentially-long lockups.

See Also

DestroyPrivateObjectSecurity, GENERIC_MAPPING, GetPrivateObjectSecurity, GetTokenInformation, OpenProcessToken, SECURITY_DESCRIPTOR, SECURITY_IMPERSONATION_LEVEL, SetPrivateObjectSecurity


CreateProcess
CreateProcess  QuickInfo  Overview  Group

The CreateProcess function creates a new process and its primary thread. The new process executes the specified executable file.

BOOL CreateProcess(

LPCTSTR  lpApplicationName,	// pointer to name of executable module
LPTSTR  lpCommandLine,	// pointer to command line string
LPSECURITY_ATTRIBUTES  lpProcessAttributes,	// pointer to process security attributes
LPSECURITY_ATTRIBUTES  lpThreadAttributes,	// pointer to thread security attributes
BOOL  bInheritHandles,	// handle inheritance flag
DWORD  dwCreationFlags,	// creation flags
LPVOID  lpEnvironment,	// pointer to new environment block
LPCTSTR  lpCurrentDirectory,	// pointer to current directory name
LPSTARTUPINFO  lpStartupInfo,	// pointer to STARTUPINFO
LPPROCESS_INFORMATION  lpProcessInformation	// pointer to PROCESS_INFORMATION
);
Parameters

lpApplicationName

Pointer to a null-terminated string that specifies the module to execute.

The string can specify the full path and filename of the module to execute.

The string can specify a partial name. In that case, the function uses the current drive and current directory to complete the specification.

The lpApplicationName parameter can be NULL. In that case, the module name must be the first white space-delimited token in the lpCommandLine string.

The specified module can be a Win32-based application. It can be some other type of module (for example, MS-DOS or OS/2) if the appropriate subsystem is available on the local computer.

Windows NT : If the executable module is a 16-bit application, lpApplicationName should be NULL, and the string pointed to by lpCommandLine should specify the executable module. A 16-bit application is one that executes as a VDM or WOW process.

lpCommandLine

Pointer to a null-terminated string that specifies the command line to execute.

The lpCommandLine parameter can be NULL. In that case, the function uses the string pointed to by lpApplicationName as the command line.

If both lpApplicationName and lpCommandLine are non-NULL, *lpApplicationName specifies the module to execute, and *lpCommandLine specifies the command line. The new process can use GetCommandLine to retrieve the entire command line. C runtime processes can use the argc and argv arguments.

If lpApplicationName is NULL, the first white space-delimited token of the command line specifies the module name. If the filename does not contain an extension, .EXE is assumed. If the filename ends in a period (.) with no extension, or the filename contains a path, .EXE is not appended. If the filename does not contain a directory path, Windows searches for the executable file in the following sequence:

1.	The directory from which the application loaded.

2.	The current directory for the parent process.

3.	Windows 95: The Windows system directory. Use the GetSystemDirectory function to get the path of this directory.

Windows NT: The 32-bit Windows system directory. Use the GetSystemDirectory function to get the path of this directory. The name of this directory is SYSTEM32.

4.	Windows NT only: The 16-bit Windows system directory. There is no Win32 function that obtains the path of this directory, but it is searched. The name of this directory is SYSTEM.

5.	The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.

6.	The directories that are listed in the PATH environment variable.

If the process to be created is an MS-DOS - based or Windows-based application, lpCommandLine should be a full command line in which the first element is the application name. Because this also works well for Win32-based applications, it is the most robust way to set lpCommandLine.

lpProcessAttributes

Points to a SECURITY_ATTRIBUTES structure that specifies the security attributes for the created process.

If lpProcessAttributes is NULL, the process is created with a default security descriptor, and the resulting handle is not inherited.

lpThreadAttributes

Points to a SECURITY_ATTRIBUTES structure that specifies the security attributes for the primary thread of the new process. If lpThreadAttributes is NULL, the process is created with a default security descriptor, and the resulting handle is not inherited.

bInheritHandles

Indicates whether the new process inherits handles from the calling process. If TRUE, each inheritable open handle in the calling process is inherited by the new process. Inherited handles have the same value and access privileges as the original handles.

dwCreationFlags

Specifies additional flags that control the priority class and the creation of the process. The following creation flags can be specified in any combination, except as noted:

Value	Meaning
CREATE_DEFAULT_ERROR_MODE
	The new process does not inherit the error mode of the calling process. Instead, CreateProcess gives the new process the current default error mode. An application sets the current default error mode by calling SetErrorMode. This flag is particularly useful for multi-threaded shell applications that run with hard errors disabled.  The default behavior for CreateProcess is for the new process to inherit the error mode of the caller. Setting this flag changes that default behavior.
CREATE_NEW_CONSOLE
	The new process has a new console, instead of inheriting the parent's console. This flag cannot be used with the DETACHED_PROCESS flag.
CREATE_NEW_PROCESS_GROUP
	The new process is the root process of a new process group. The process group includes all processes that are descendants of this root process. The process ID of the new process group is the same as the process ID, which is returned in the lpProcessInformation parameter. Process groups are used by the GenerateConsoleCtrlEvent function to enable sending a CTRL+C or CTRL+BREAK signal to a group of console processes.
CREATE_SEPARATE_WOW_VDM
	This flag is only valid only launching a 16-bit Windows program.  If set, the new process is run in a private Virtual DOS Machine (VDM).  By default, all 16-bit Windows programs are run in a single, shared VDM.  The advantage of running separately is that a crash only kills the single VDM; any other programs running in distinct VDMs continue to function normally.  Also, 16-bit Windows applications which are run in separate VDMs have separate input queues. That means that if one application hangs momentarily, applications in separate VDMs continue to receive input.
CREATE_SHARED_WOW_VDM
	Windows NT: The flag is valid only when launching a 16-bit Windows program. If the DefaultSeparateVDM switch in the Windows section of WIN.INI is TRUE, this flag causes the CreateProcess function to override the switch and run the new process in the shared Virtual DOS Machine.
CREATE_SUSPENDED
	The primary thread of the new process is created in a suspended state, and does not run until the ResumeThread function is called.
CREATE_UNICODE_ENVIRONMENT
	If set, the environment block pointed to by lpEnvironment uses Unicode characters. If clear, the environment block uses ANSI characters.
DEBUG_PROCESS
	If this flag is set, the calling process is treated as a debugger, and the new process is a process being debugged. The system notifies the debugger of all debug events that occur in the process being debugged. If you create a process with this flag set, only the calling thread (the thread that called CreateProcess) can call the WaitForDebugEvent function.
DEBUG_ONLY_THIS_PROCESS
	If not set and the calling process is being debugged, the new process becomes another process being debugged by the calling process's debugger. If the calling process is not a process being debugged, no debugging-related actions occur.
DETACHED_PROCESS
	For console processes, the new process does not have access to the console of the parent process. The new process can call the AllocConsole function at a later time to create a new console. This flag cannot be used with the CREATE_NEW_CONSOLE flag.
The dwCreationFlags parameter also controls the new process's priority class, which is used in determining the scheduling priorities of the process's threads. If none of the following priority class flags is specified, the priority class defaults to NORMAL_PRIORITY_CLASS unless the priority class of the creating process is IDLE_PRIORITY_CLASS. In this case the default priority class of the child process is IDLE_PRIORITY_CLASS. One of the following flags can be specified:

Priority	Meaning
HIGH_PRIORITY_CLASS	Indicates a process that performs time-critical tasks that must be executed immediately for it to run correctly. The threads of a high-priority class process preempt the threads of normal-priority or idle-priority class processes. An example is Windows Task List, which must respond quickly when called by the user, regardless of the load on the operating system. Use extreme care when using the high-priority class, because a high-priority class CPU-bound application can use nearly all available cycles.
IDLE_PRIORITY_CLASS	Indicates a process whose threads run only when the system is idle and are preempted by the threads of any process running in a higher priority class. An example is a screen saver. The idle priority class is inherited by child processes.
NORMAL_PRIORITY_CLASS	Indicates a normal process with no special scheduling needs.
REALTIME_PRIORITY_CLASS	Indicates a process that has the highest possible priority. The threads of a real-time priority class process preempt the threads of all other processes, including operating system processes performing important tasks. For example, a real-time process that executes for more than a very brief interval can cause disk caches not to flush or cause the mouse to be unresponsive.
lpEnvironment

Points to an environment block for the new process. If this parameter is NULL, the new process uses the environment of the calling process.

An environment block consists of a null-terminated block of null-terminated strings. Each string is in the form:

name=value

Because the equal sign is used as a separator, it must not be used in the name of an environment variable.

If an application provides an environment block, rather than passing NULL for this parameter, the current directory information of the system drives is not automatically propagated to the new process. For a discussion of this situation and how to handle it, see the following Remarks section.

An environment block can contain Unicode or ANSI characters. If the environment block pointed to by lpEnvironment contains Unicode characters, the dwCreationFlags field's CREATE_UNICODE_ENVIRONMENT flag will be set. If the block contains ANSI characters, that flag will be clear.

Note that an ANSI environment block is terminated by two zero bytes: one for the last string, one more to terminate the block. A Unicode environment block is terminated by four zero bytes: two for the last string, two more to terminate the block.

lpCurrentDirectory

Points to a null-terminated string that specifies the current drive and directory for the child process. The string must be a full path and filename that includes a drive letter. If this parameter is NULL, the new process is created with the same current drive and directory as the calling process. This option is provided primarily for shells that need to start an application and specify its initial drive and working directory.

lpStartupInfo

Points to a STARTUPINFO structure that specifies how the main window for the new process should appear.

lpProcessInformation

Points to a PROCESS_INFORMATION structure that receives identification information about the new process.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The CreateProcess function is used to run a new program. The WinExec and LoadModule functions are still available, but they are implemented as calls to CreateProcess.

In addition to creating a process, CreateProcess also creates a thread object. The thread is created with an initial stack whose size is described in the image header of the specified program's executable file. The thread begins execution at the image's entry point.

The new process and the new thread handles are created with full access rights. For either handle, if a security descriptor is not provided, the handle can be used in any function that requires an object handle of that type. When a security descriptor is provided, an access check is performed on all subsequent uses of the handle before access is granted. If the access check denies access, the requesting process is not able to use the handle to gain access to the thread.

The process is assigned a 32-bit process identifier. The ID is valid until the process terminates. It can be used to identify the process, or specified in the OpenProcess function to open a handle to the process. The initial thread in the process is also assigned a 32-bit thread identifier. The ID is valid until the thread terminates and can be used to uniquely identify the thread within the system. These identifiers are returned in the PROCESS_INFORMATION structure.

When specifying an application name in the lpApplicationName or lpCommandLine strings, it doesn't matter whether the application name includes the filename extension, with one exception: an MS-DOS − based or Windows-based application whose filename extension is .COM must include the .COM extension.

The calling thread can use the WaitForInputIdle function to wait until the new process has finished its initialization and is waiting for user input with no input pending. This can be useful for synchronization between parent and child processes, because CreateProcess returns without waiting for the new process to finish its initialization. For example, the creating process would use WaitForInputIdle before trying to find a window associated with the new process.

The preferred way to shut down a process is by using the ExitProcess function, because this function notifies all dynamic-link libraries (DLLs) attached to the process of the approaching termination. Other means of shutting down a process do not notify the attached DLLs. Note that when a thread calls ExitProcess, other threads of the process are terminated without an opportunity to execute any additional code (including the thread termination code of attached DLLs).

ExitProcess, ExitThread, CreateThread, CreateRemoteThread, and a process that is starting (as the result of a call by CreateProcess) are serialized between each other within a process. Only one of these events can happen in an address space at a time. This means the following restrictions hold:

•	During process startup and DLL initialization routines, new threads can be created, but they do not begin execution until DLL initialization is done for the process.

•	Only one thread in a process can be in a DLL initialization or detach routine at a time.

•	The ExitProcess function does not return until no threads are in their DLL initialization or detach routines.

The created process remains in the system until all threads within the process have terminated and all handles to the process and any of its threads have been closed through calls to CloseHandle. The handles for both the process and the main thread must be closed through calls to CloseHandle. If these handles are not needed, it is best to close them immediately after the process is created.

When the last thread in a process terminates, the following events occur:

•	All objects opened by the process are implicitly closed.

•	The process's termination status (which is returned by GetExitCodeProcess) changes from its initial value of STILL_ACTIVE to the termination status of the last thread to terminate.

•	The thread object of the main thread is set to the signaled state, satisfying any threads that were waiting on the object.

•	The process object is set to the signaled state, satisfying any threads that were waiting on the object.

If the current directory on drive C is \MSVC\MFC, there is an environment variable called =C: whose value is C:\MSVC\MFC. As noted in the previous description of lpEnvironment, such current directory information for a system's drives does not automatically propagate to a new process when the CreateProcess function's lpEnvironment parameter is non-NULL. An application must manually pass the current directory information to the new process. To do so, the application must explicitly create the =X environment variable strings, get them into alphabetical order (because Windows NT and Windows 95 use a sorted environment), and then put them into the environment block specified by lpEnvironment. Typically, they will go at the front of the environment block, due to the previously mentioned environment block sorting.

One way to obtain the current directory variable for a drive X is to call GetFullPathName("X:",. .). That avoids an application having to scan the environment block. If the full path returned is X:\, there is no need to pass that value on as environment data, since the root directory is the default current directory for drive X of a new process.

The handle returned by the CreateProcess function has PROCESS_ALL_ACCESS access to the process object.

When a process is created with CREATE_NEW_PROCESS_GROUP specified, an implicit call to SetConsoleCtrlHandler(NULL,TRUE) is made on behalf of the new process; this means that the new process has CTRL-C disabled. This lets good shells handle CTRL-C themselves, and selectively pass that signal on to sub-processes. CTRL-BREAK is not disabled, and may be used to interrupt the process/process group.

The current directory specified by the lpcurrentDirectory parameter is the current directory for the child process. The current directory specified in item 2 under the lpCommandLine parameter is the current directory for the parent process.

See Also

AllocConsole, CloseHandle, CreateRemoteThread, CreateThread, ExitProcess, ExitThread, GenerateConsoleCtrlEvent, GetCommandLine, GetEnvironmentStrings, GetExitCodeProcess, GetFullPathName, GetStartupInfo, GetSystemDirectory, GetWindowsDirectory, LoadModule, OpenProcess, PROCESS_INFORMATION, ResumeThread, SECURITY_ATTRIBUTES, SetConsoleCtrlHandler, SetErrorMode, STARTUPINFO, TerminateProcess, WaitForInputIdle, WaitForDebugEvent, WinExec


CreateProcessAsUser [New - Windows NT]
CreateProcessAsUser  QuickInfo

[New - Windows NT]

The CreateProcessAsUser function creates a new process and its primary thread. The new process then executes a specified executable file. The CreateProcessAsUser function behaves just like the CreateProcess function, with one important difference: the created process runs in a context in which the system sees the user represented by the hToken parameter as if that user had logged on to the system and then called the CreateProcess function.

BOOL CreateProcessAsUser(

HANDLE hToken	// handle to a token that represents a logged-on user
LPCTSTR  lpApplicationName,	// pointer to name of executable module
LPTSTR  lpCommandLine,	// pointer to command line string
LPSECURITY_ATTRIBUTES  lpProcessAttributes,	// pointer to process security attributes
LPSECURITY_ATTRIBUTES  lpThreadAttributes,	// pointer to thread security attributes
BOOL  bInheritHandles,	// new process inherits handles
DWORD  dwCreationFlags,	// creation flags
LPVOID  lpEnvironment,	// pointer to new environment block
LPCTSTR  lpCurrentDirectory,	// pointer to current directory name
LPSTARTUPINFO  lpStartupInfo,	// pointer to STARTUPINFO
LPPROCESS_INFORMATION  lpProcessInformation	// pointer to PROCESS_INFORMATION
);
Parameters

hToken

Handle to a token that represents a user. You obtain such a token by calling the LogonUser function. The user represented by the token must have read and execute access to the application specified by the lpApplicationName or the lpCommandLine parameter.

The other parameters of the CreateProcessAsUser function behave just like the analogous parameters of the CreateProcess function.

lpApplicationName

Points to a null-terminated string specifying the full path and filename of the module to execute. If a partial name is specified, the current drive and current directory are used by default. If this parameter is NULL, the module name must be the first white space-delimited token in the lpCommandLine string. The specified module can be a Win32-based application, or it can be some other type of module (for example, MS-DOS or OS/2) if the appropriate subsystem is available on the local computer.

lpCommandLine

Points to a null-terminated string specifying the command line for the application to be executed. If this parameter is NULL, the lpApplicationName string is used as the command line. If both lpApplicationName and lpCommandLine are non-NULL, lpApplicationName specifies the module to execute and lpCommandLine is used as the command line. The new process can use GetCommandLine to retrieve the entire command line; or C runtime processes can use the argc/argv mechanism.

If lpApplicationName is NULL, the first white space-delimited token of the command line specifies the module name. If the filename does not contain an extension, .EXE is assumed. If the filename ends in a period (.) with no extension, or the filename contains a path, .EXE is not appended. If the filename does not contain a directory path, Windows searches for the executable file in the following sequence:

1.	The directory from which the application loaded.

2.	The current directory.

3.	Windows 95: The Windows system directory. Use the GetSystemDirectory function to get the path of this directory.

Windows NT: The 32-bit Windows system directory. Use the GetSystemDirectory function to get the path of this directory. The name of this directory is SYSTEM32.

4.	Windows NT only: The 16-bit Windows system directory. There is no Win32 function that obtains the path of this directory, but it is searched. The name of this directory is SYSTEM.

5.	The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.

6.	The directories that are listed in the PATH environment variable.

If the process to be created is an MS-DOS − based or Windows-based application, lpCommandLine should be a full command line in which the first element is the application name. Because this also works well for Win32-based applications, it is the most robust way to set lpCommandLine.

lpProcessAttributes

Points to a SECURITY_ATTRIBUTES structure that specifies the security attributes for the created process.

If lpProcessAttributes is NULL, the process is created with a default security descriptor, and the resulting handle is not inherited.

lpThreadAttributes

Points to a SECURITY_ATTRIBUTES structure that specifies the security attributes for the primary thread of the new process. If lpThreadAttributes is NULL, the process is created with a default security descriptor, and the resulting handle is not inherited.

bInheritHandles

Indicates whether the new process inherits handles from the calling process. If TRUE, each inheritable open handle in the calling process is inherited by the new process. Inherited handles have the same value and access privileges as the original handles.

dwCreationFlags

Specifies additional flags that control the priority class and the creation of the process. The following creation flags can be specified in any combination, except as noted:

Value	Meaning
CREATE_DEFAULT_ERROR_MODE
	The new process does not inherit the error mode of the calling process. Instead, CreateProcessAsUser gives the new process the current default error mode. An application sets the current default error mode by calling SetErrorMode. This flag is particularly useful for multi-threaded shell applications that run with hard errors disabled.  The default behavior for CreateProcessAsUser is for the new process to inherit the error mode of the caller. Setting this flag changes that default behavior.
CREATE_NEW_CONSOLE
	The new process has a new console, instead of inheriting the parent's console. This flag cannot be used with the DETACHED_PROCESS flag.
CREATE_NEW_PROCESS_GROUP
	The new process is the root process of a new process group. The process group includes all processes that are descendants of this root process. The process ID of the new process group is the same as the process ID, which is returned in the lpProcessInformation parameter. Process groups are used by the GenerateConsoleCtrlEvent function to enable sending a CTRL+C or CTRL+BREAK signal to a group of console processes.
CREATE_SEPARATE_WOW_VDM
	This flag is only valid only launching a 16-bit Windows program.  If set, the new process is run in a private Virtual DOS Machine (VDM).  By default, all 16-bit Windows programs are run in a single, shared VDM.  The advantage of running separately is that a crash only kills the single VDM; any other programs running in distinct VDMs continue to function normally.  Also, 16-bit Windows applications which are run in separate VDMs have separate input queues. That means that if one application hangs momentarily, applications in separate VDMs continue to receive input.
CREATE_SUSPENDED
	The primary thread of the new process is created in a suspended state, and does not run until the ResumeThread function is called.
CREATE_UNICODE_ENVIRONMENT
	If set, the environment block pointed to by lpEnvironment uses Unicode characters. If clear, the environment block uses ANSI characters.
DEBUG_PROCESS
	If set, the calling process is treated as a debugger, and the new process is a process being debugged. The system notifies the debugger of all debug events that occur in the process being debugged.
DEBUG_ONLY_THIS_PROCESS
	If not set and the calling process is being debugged, the new process becomes another process being debugged by the calling process's debugger. If the calling process is not a process being debugged, no debugging-related actions occur.
DETACHED_PROCESS
	For console processes, the new process does not have access to the console of the parent process. The new process can call the AllocConsole function at a later time to create a new console. This flag cannot be used with the CREATE_NEW_CONSOLE flag.
The dwCreationFlags parameter also controls the new process's priority class, which is used in determining the scheduling priorities of the process's threads. If none of the following priority class flags is specified, the priority class defaults to NORMAL_PRIORITY_CLASS unless the priority class of the creating process is IDLE_PRIORITY_CLASS. In this case the default priority class of the child process is IDLE_PRIORITY_CLASS. One of the following flags can be specified:

Priority	Meaning
HIGH_PRIORITY_CLASS	Indicates a process that performs time-critical tasks that must be executed immediately for it to run correctly. The threads of a high-priority class process preempt the threads of normal-priority or idle-priority class processes. An example is Windows Task List, which must respond quickly when called by the user, regardless of the load on the operating system. Use extreme care when using the high-priority class, because a high-priority class CPU-bound application can use nearly all available cycles.
IDLE_PRIORITY_CLASS	Indicates a process whose threads run only when the system is idle and are preempted by the threads of any process running in a higher priority class. An example is a screen saver. The idle priority class is inherited by child processes.
NORMAL_PRIORITY_CLASS	Indicates a normal process with no special scheduling needs.
REALTIME_PRIORITY_CLASS	Indicates a process that has the highest possible priority. The threads of a real-time priority class process preempt the threads of all other processes, including operating system processes performing important tasks. For example, a real-time process that executes for more than a very brief interval can cause disk caches not to flush or cause the mouse to be unresponsive.
lpEnvironment

Points to an environment block for the new process. If this parameter is NULL, the new process uses the environment of the calling process.

An environment block consists of a null-terminated block of null-terminated strings. Each string is in the form:

name=value

Because the equal sign is used as a separator, it must not be used in the name of an environment variable.

If an application provides an environment block, rather than passing NULL for this parameter, the current directory information of the system drives is not automatically propagated to the new process. For a discussion of this situation and how to handle it, see the following Remarks section.

An environment block can contain Unicode or ANSI characters. If the environment block pointed to by lpEnvironment contains Unicode characters, the dwCreationFlags field's CREATE_UNICODE_ENVIRONMENT flag will be set. If the block contains ANSI characters, that flag will be clear.

Note that an ANSI environment block is terminated by two zero bytes: one for the last string, one more to terminate the block. A Unicode environment block is terminated by four zero bytes: two for the last string, two more to terminate the block.

lpCurrentDirectory

Points to a null-terminated string that specifies the current drive and directory for the new process. The string must be a full path and filename that includes a drive letter. If this parameter is NULL, the new process is created with the same current drive and directory as the calling process. This option is provided primarily for shells that need to start an application and specify its initial drive and working directory.

lpStartupInfo

Points to a STARTUPINFO structure that specifies how the main window for the new process should appear.

lpProcessInformation

Points to a PROCESS_INFORMATION structure that receives identification information about the new process.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

This function requires the SeAssignPrimary and SeIncreaseQuota privileges. If they are not already enabled, CreateProcessAsUser will enable them for the duration of the call.

The process created will not run on the application desktop. Rather, Windows will create a separate desktop on which it can run. This desktop can never be made visible so any interactive operations will never get a response. This function should be used for processes that do not require a GUI.

In addition to creating a process, CreateProcessAsUser also creates a thread object. The thread is created with an initial stack whose size is described in the image header of the specified program's executable file. The thread begins execution at the image's entry point.

The new process and the new thread handles are created with full access rights. For either handle, if a security descriptor is not provided, the handle can be used in any function that requires an object handle of that type. When a security descriptor is provided, an access check is performed on all subsequent uses of the handle before access is granted. If the access check denies access, the requesting process is not able to use the handle to gain access to the thread.

If the lpProcessAttributes parameter is NULL, the default security descriptor for the user referenced in the hToken parameter will be used. This security descriptor may not allow access for the caller, in which case the process may not be opened again once it is run. The handle returned in the PROCESS_INFORMATION is valid and will continue to have all access. This is also true for thread attributes.

The process is assigned a 32-bit process identifier. The ID is valid until the process terminates. It can be used to identify the process, or specified in the OpenProcess function to open a handle to the process. The initial thread in the process is also assigned a 32-bit thread identifier. The ID is valid until the thread terminates and can be used to uniquely identify the thread within the system. These identifiers are returned in the PROCESS_INFORMATION structure.

When specifying an application name in the lpApplicationName or lpCommandLine strings, it doesn't matter whether the application name includes the filename extension, with one exception: an MS-DOS − based or Windows-based application whose filename extension is .COM must include the .COM extension.

The calling thread can use the WaitForInputIdle function to wait until the new process has finished its initialization and is waiting for user input with no input pending. This can be useful for synchronization between parent and child processes, because CreateProcessAsUser returns without waiting for the new process to finish its initialization. For example, the creating process would use WaitForInputIdle before trying to find a window associated with the new process.

The preferred way to shut down a process is by using the ExitProcess function, because this function notifies all dynamic-link libraries (DLLs) attached to the process of the approaching termination. Other means of shutting down a process do not notify the attached DLLs. Note that when a thread calls ExitProcess, other threads of the process are terminated without an opportunity to execute any additional code (including the thread termination code of attached DLLs).

ExitProcess, ExitThread, CreateThread, CreateRemoteThread, and a process that is starting (as the result of a call by CreateProcessAsUser) are serialized between each other within a process. Only one of these events can happen in an address space at a time. This means the following restrictions hold:

•	During process startup and DLL initialization routines, new threads can be created, but they do not begin execution until DLL initialization is done for the process.

•	Only one thread in a process can be in a DLL initialization or detach routine at a time.

•	The ExitProcess function does not return until no threads are in their DLL initialization or detach routines.

The created process remains in the system until all threads within the process have terminated and all handles to the process and any of its threads have been closed through calls to CloseHandle. The handles for both the process and the main thread must be closed through calls to CloseHandle. If these handles are not needed, it is best to close them immediately after the process is created.

When the last thread in a process terminates, the following events occur:

•	All objects opened by the process are implicitly closed.

•	The process's termination status (which is returned by GetExitCodeProcess) changes from its initial value of STILL_ACTIVE to the termination status of the last thread to terminate.

•	The thread object of the main thread is set to the signaled state, satisfying any threads that were waiting on the object.

•	The process object is set to the signaled state, satisfying any threads that were waiting on the object.

If the current directory on drive C is \MSVC\MFC, there is an environment variable called =C: whose value is C:\MSVC\MFC. As noted in the previous description of lpEnvironment, such current directory information for a system's drives does not automatically propagate to a new process when the CreateProcessAsUser function's lpEnvironment parameter is non-NULL. An application must manually pass the current directory information to the new process. To do so, the application must explicitly create the =X environment variable strings, get them into alphabetical order (because Windows NT uses a sorted environment), and then put them into the environment block specified by lpEnvironment. Typically, they will go at the front of the environment block, due to the previously mentioned Windows NT environment block sorting.

One way to obtain the current directory variable for a drive X is to call GetFullPathName("X:",. .). That avoids an application having to scan the environment block. If the full path returned is X:\, there is no need to pass that value on as environment data, since the root directory is the default current directory for drive X of a new process.

The handle returned by the CreateProcessAsUser function has PROCESS_ALL_ACCESS access to the process object.

When a process is created with CREATE_NEW_PROCESS_GROUP specified, an implicit call to SetConsoleCtrlHandler(NULL,TRUE) is made on behalf of the new process; this means that the new process has CTRL-C disabled. This lets good shells handle CTRL-C themselves, and selectively pass that signal on to sub-processes. CTRL-BREAK is not disabled, and may be used to interrupt the process/process group.

See Also

AllocConsole, CloseHandle, CreateProcess, CreateRemoteThread, CreateThread, ExitProcess, ExitThread, GenerateConsoleCtrlEvent, GetCommandLine, GetEnvironmentStrings, GetExitCodeProcess, GetFullPathName, GetStartupInfo, GetSystemDirectory, GetWindowsDirectory, ImpersonateLoggedOnUser, LoadModule, LogonUser, OpenProcess, PROCESS_INFORMATION, ResumeThread, SECURITY_ATTRIBUTES, SetConsoleCtrlHandler, SetErrorMode, STARTUPINFO, TerminateProcess, WaitForInputIdle, WinExec


CreatePropertySheetPage [New - Windows NT]
CreatePropertySheetPage  QuickInfo  Overview  Group

[New - Windows NT]

The CreatePropertySheetPage function creates a new page for a property sheet.

HPROPSHEETPAGE CreatePropertySheetPage(

LPCPROPSHEETPAGE  lppsp
);
Parameters

lppsp

Pointer to a PROPSHEETPAGE structure that defines a page to be included in a property sheet.

Return Value

If the function succeeds, the return value is the handle to the new property sheet.

If the function fails, the return value is NULL.

Remarks

An application uses the PropertySheet function to create a property sheet that includes the new page or uses the PSM_ADDPAGE message to add the new page to an existing property sheet.

Windows 95 only: The system can support a maximum of 16,364 window handles.

PropertySheet, PROPSHEETPAGE, PSM_ADDPAGE


CreateRectRgn
CreateRectRgn  QuickInfo  Overview  Group

The CreateRectRgn function creates a rectangular region.

HRGN CreateRectRgn(

int  nLeftRect,	// x-coordinate of region's upper-left corner
int  nTopRect,	// y-coordinate of region's upper-left corner
int  nRightRect,	// x-coordinate of region's lower-right corner
int  nBottomRect	// y-coordinate of region's lower-right corner
);
Parameters

nLeftRect

Specifies the x-coordinate of the upper-left corner of the region.

nTopRect

Specifies the y-coordinate of the upper-left corner of the region.

nRightRect

Specifies the x-coordinate of the lower-right corner of the region.

nBottomRect

Specifies the y-coordinate of the lower-right corner of the region.

Return Value

If the function succeeds, the return value is the handle of the region.

If the function fails, the return value is NULL.

Remarks

The region will be exclusive of the bottom and right edges.

See Also

CreateRectRgnIndirect, CreateRoundRectRgn, DeleteObject, SelectObject


CreateRectRgnIndirect
CreateRectRgnIndirect  QuickInfo  Overview  Group

The CreateRectRgnIndirect function creates a rectangular region.

HRGN CreateRectRgnIndirect(

CONST RECT  *lprc	// address of the rectangle
);
Parameters

lprc

Points to a RECT structure that contains the coordinates of the upper-left and lower-right corners of the rectangle that defines the region.

Return Value

If the function succeeds, the return value is the handle of the region.

If the function fails, the return value is NULL.

Remarks

The region will be exclusive of the bottom and right edges.

See Also

CreateRectRgn, CreateRoundRectRgn, DeleteObject, RECT, SelectObject


CreateRemoteThread
CreateRemoteThread  QuickInfo  Overview  Group

The CreateRemoteThread function creates a thread that runs in the address space of another process.

HANDLE CreateRemoteThread(

HANDLE  hProcess,	// handle to process to create thread in
LPSECURITY_ATTRIBUTES  lpThreadAttributes,	// address of thread security attributes
DWORD  dwStackSize,	// initial thread stack size, in bytes
LPTHREAD_START_ROUTINE  lpStartAddress,	// address of thread function
LPVOID  lpParameter,	// address of argument for new thread
DWORD  dwCreationFlags,	// creation flags
LPDWORD  lpThreadId	// address of returned thread identifier
);
Parameters

hProcess

Identifies the process in which the thread is to be created. The handle must have PROCESS_CREATE_THREAD access.

lpThreadAttributes

Points to a SECURITY_ATTRIBUTES structure that specifies the security attributes for the thread.

If lpThreadAttributes is NULL, the thread is created with a default security descriptor, and the resulting handle is not inherited.

dwStackSize

Specifies the size, in bytes, of the stack for the new thread. If this value is zero, the stack size defaults to the same size as that of the primary thread of the process. The stack is allocated automatically in the memory space of the process and is freed when the thread terminates. Note that the stack size grows as necessary.

lpStartAddress

Points to the starting address of the new thread. The address is logically a procedure that never returns and that accepts a single 32-bit pointer as an argument.

lpParameter

Points to a single 32-bit value passed to the thread.

dwCreationFlags

Specifies additional flags that control the creation of the thread. If the CREATE_SUSPENDED flag is specified, the thread is created in a suspended state and will not run until the ResumeThread function is called. If this value is zero, the thread runs immediately after creation.

lpThreadId

Points to a 32-bit variable that receives the thread identifier.

Return Value

If the function succeeds, the return value is a handle to the new thread.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

CreateRemoteThread causes a new thread of execution to begin in the address space of the specified process. The thread has access to all objects opened by the process.

The new thread handle is created with full access to the new thread. If a security descriptor is not provided, the handle may be used in any function that requires a thread object handle. When a security descriptor is provided, an access check is performed on all subsequent uses of the handle before access is granted. If the access check denies access, the requesting process cannot use the handle to gain access to the thread.

The thread execution begins at the function specified by the lpStartAddress parameter. If this function returns, the results are unspecified.

CreateRemoteThread may succeed even if lpStartAddress points to data, code, or is not accessible. If the start address is invalid when the thread runs, an exception occurs, and the thread terminates. Thread termination due to a invalid start address is handled as an error exit for the thread's process. This behavior is similar to the asynchronous nature of CreateProcess, where the process is created even if it refers to invalid or missing dynamic-link libraries (DLLs).

The thread is created with a thread priority of THREAD_PRIORITY_NORMAL. Use the GetThreadPriority and SetThreadPriority functions to get and set the priority value of a thread.

When a thread terminates, the thread object attains a signaled state, satisfying any threads that were waiting for the object.

The thread object remains in the system until the thread has terminated and all handles to it have been closed through a call to CloseHandle.

The ExitProcess, ExitThread, CreateThread, CreateRemoteThread functions, and a process that is starting (as the result of a CreateProcess call) are serialized between each other within a process. Only one of these events can happen in an address space at a time. This means the following restrictions hold:

•	During process startup and DLL initialization routines, new threads can be created, but they do not begin execution until DLL initialization is done for the process.

•	Only one thread in a process can be in a DLL initialization or detach routine at a time.

•	ExitProcess does not return until no threads are in their DLL initialization or detach routines.

See Also

CloseHandle, CreateProcess, CreateThread, ExitProcess, ExitThread, GetThreadPriority, ResumeThread, SECURITY_ATTRIBUTES, SetThreadPriority


CreateRoundRectRgn
CreateRoundRectRgn  QuickInfo  Overview  Group

The CreateRoundRectRgn function creates a rectangular region with rounded corners.

HRGN CreateRoundRectRgn(

int  nLeftRect,	// x-coordinate of the region's  upper-left corner
int  nTopRect,	// y-coordinate of the region's upper-left corner
int  nRightRect,	// x-coordinate of the region's lower-right corner
int  nBottomRect,	// y-coordinate of the region's lower-right corner
int  nWidthEllipse,	// height of ellipse for rounded corners
int  nHeightEllipse	// width of ellipse for rounded corners
);
Parameters

nLeftRect

Specifies the x-coordinate of the upper-left corner of the region.

nTopRect

Specifies the y-coordinate of the upper-left corner of the region.

nRightRect

Specifies the x-coordinate of the lower-right corner of the region.

nBottomRect

Specifies the y-coordinate of the lower-right corner of the region.

nWidthEllipse

Specifies the width of the ellipse used to create the rounded corners.

nHeightEllipse

Specifies the height of the ellipse used to create the rounded corners.

Return Value

If the function succeeds, the return value is the handle of the region.

If the function fails, the return value is NULL.

See Also

CreateRectRgn, CreateRectRgnIndirect, DeleteObject, SelectObject


CreateScalableFontResource
CreateScalableFontResource  QuickInfo  Overview  Group

The CreateScalableFontResource function creates a font resource file for a scalable font.

BOOL CreateScalableFontResource(

DWORD  fdwHidden,	// flag for read-only embedded font
LPCTSTR  lpszFontRes,	// address of filename for font resource
LPCTSTR  lpszFontFile,	// address of filename for scalable font
LPCTSTR  lpszCurrentPath	// address of path to font file
);
Parameters

fdwHidden

Specifies whether the font is a read-only embedded font. This parameter can be one of the following values:

Value	Meaning
0	The font has read-write permission.
1	The font has read-only permission and should be hidden from other applications in the system. When this flag is set, the font is not enumerated by the EnumFonts or EnumFontFamilies function.
lpszFontRes

Points to a null-terminated string specifying the name of the font resource file that this function creates.

lpszFontFile

Points to a null-terminated string specifying the name of the scalable font file that this function uses to create the font resource file.

lpszCurrentPath

Points to a null-terminated string specifying the path to the scalable font file.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The CreateScalableFontResource function is used by applications that install TrueType fonts. An application uses the CreateScalableFontResource function to create a font resource file (typically with a .FOT filename extension) and then uses the AddFontResource function to install the font. The TrueType font file (typically with a .TTF filename extension) must be in the SYSTEM subdirectory of the WINDOWS directory to be used by the AddFontResource function.

The CreateScalableFontResource function currently supports only TrueType-technology scalable fonts.

When the lpszFontFile parameter specifies only a filename and extension, the lpszCurrentPath parameter must specify a path. When the lpszFontFile parameter specifies a full path, the lpszCurrentPath parameter must be NULL or a pointer to NULL.

When only a filename and extension are specified in the lpszFontFile parameter and a path is specified in the lpszCurrentPath parameter, the string in lpszFontFile is copied into the .FOT file as the .TTF file that belongs to this resource. When the AddFontResource function is called, the operating system assumes that the .TTF file has been copied into the SYSTEM directory (or into the main Windows directory in the case of a network installation). The .TTF file need not be in this directory when the CreateScalableFontResource function is called, because the lpszCurrentPath parameter contains the directory information. A resource created in this manner does not contain absolute path information and can be used in any Windows installation.

When a path is specified in the lpszFontFile parameter and NULL is specified in the lpszCurrentPath parameter, the string in lpszFontFile is copied into the .FOT file. In this case, when the AddFontResource function is called, the .TTF file must be at the location specified in the lpszFontFile parameter when the CreateScalableFontResource function was called; the lpszCurrentPath parameter is not needed. A resource created in this manner contains absolute references to paths and drives and does not work if the .TTF file is moved to a different location.

See Also

AddFontResource, EnumFonts, EnumFontFamilies


CreateSemaphore
CreateSemaphore  QuickInfo  Overview  Group

The CreateSemaphore function creates a named or unnamed semaphore object.

HANDLE CreateSemaphore(

LPSECURITY_ATTRIBUTES  lpSemaphoreAttributes,	// address of security attributes
LONG  lInitialCount,	// initial count
LONG  lMaximumCount,	// maximum count
LPCTSTR  lpName	// address of semaphore-object name
);
Parameters

lpSemaphoreAttributes

Points to a SECURITY_ATTRIBUTES structure that specifies the security attributes for the semaphore object.

If lpSemaphoreAttributes is NULL, the semaphore object is created with a default security descriptor and the resulting handle is not inheritable.

lInitialCount

Specifies an initial count for the semaphore object. This value must be greater than or equal to zero and less than or equal to lMaximumCount. The state of a semaphore is signaled when its count is greater than zero and nonsignaled when it is zero. The count is decreased by one whenever a wait function releases a thread that was waiting for the semaphore. The count is increased by a specified amount by calling the ReleaseSemaphore function.

lMaximumCount

Specifies the maximum count for the semaphore object. This value must be greater than zero.

lpName

Points to a null-terminated string specifying the name of the semaphore object. The name is limited to MAX_PATH characters, and can contain any character except the backslash path-separator character (\). Name comparison is case sensitive.

If lpName matches the name of an existing named semaphore object, this function requests SEMAPHORE_ALL_ACCESS access to the existing object. In this case, the lInitialCount and lMaximumCount parameters are ignored because they have already been set by the creating process. If the lpSemaphoreAttributes parameter is not NULL, it determines whether the handle can be inherited, but its security-descriptor member is ignored.

If lpName is NULL, the semaphore object is created without a name.

If lpName matches the name of an existing event, mutex, or file-mapping object, the function fails and the GetLastError function returns ERROR_INVALID_HANDLE. This occurs because event, mutex, semaphore, and file-mapping objects share the same name space.

Return Value

If the function succeeds, the return value is a handle of the semaphore object. If the named semaphore object existed before the function call, the GetLastError function returns ERROR_ALREADY_EXISTS. Otherwise, GetLastError returns zero.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

The handle returned by CreateSemaphore has SEMAPHORE_ALL_ACCESS access to the new semaphore object and can be used in any function that requires a handle of a semaphore object.

Any thread of the calling process can specify the semaphore-object handle in a call to one of the wait functions (MsgWaitForMultipleObjects, WaitForSingleObject, WaitForMultipleObjects, WaitForSingleObjectEx, or WaitForMultipleObjectsEx). The single-object wait functions return when the state of the specified object is signaled. The multiple-object wait functions can be instructed to return either when any one or when all of the specified objects are signaled. When a wait function returns, the waiting thread is released to continue its execution.

The state of a semaphore object is signaled when its count is greater than zero, and nonsignaled when its count is equal to zero. The lInitialCount parameter specifies the initial count. Each time a waiting thread is released because of the semaphore's signaled state, the count of the semaphore is decreased by one. Use the ReleaseSemaphore function to increment a semaphore's count by a specified amount. The count can never be less than zero or greater than the value specified in the lMaximumCount parameter.

Multiple processes can have handles of the same semaphore object, enabling use of the object for interprocess synchronization. The following object-sharing mechanisms are available:

•	A child process created by the CreateProcess function can inherit a handle of a semaphore object if the lpSemaphoreAttributes parameter of CreateSemaphore enabled inheritance.

•	A process can specify the semaphore-object handle in a call to the DuplicateHandle function to create a duplicate handle that can be used by another process.

•	A process can specify the name of a semaphore object in a call to the OpenSemaphore or CreateSemaphore function.

Use the CloseHandle function to close the handle. The system closes the handle automatically when the process terminates. The semaphore object is destroyed when its last handle has been closed.

See Also

CloseHandle, CreateProcess, DuplicateHandle, OpenSemaphore, ReleaseSemaphore, SECURITY_ATTRIBUTES, WaitForMultipleObjects, WaitForMultipleObjectsEx, WaitForSingleObject, WaitForSingleObjectEx


CreateService
CreateService  QuickInfo  Overview  Group

The CreateService function creates a service object and adds it to the specified service control manager database.

SC_HANDLE CreateService(

SC_HANDLE  hSCManager,	// handle of service control manager database
LPCTSTR  lpServiceName,	// address of name of service to start
LPCTSTR  lpDisplayName,	// address of display name
DWORD  dwDesiredAccess,	// type of access to service
DWORD  dwServiceType,	// type of service
DWORD  dwStartType,	// when to start service
DWORD  dwErrorControl,	// severity if service fails to start
LPCTSTR  lpBinaryPathName,	// address of name of binary file
LPCTSTR  lpLoadOrderGroup,	// address of name of load ordering group
LPDWORD  lpdwTagId,	// address of variable to get tag identifier
LPCTSTR  lpDependencies,	// address of array of dependency names
LPCTSTR  lpServiceStartName,	// address of account name of service
LPCTSTR  lpPassword	// address of password for service account
);
Parameters

hSCManager

Identifies the service control manager database. The OpenSCManager function returns this handle which must have SC_MANAGER_CREATE_SERVICE access.

lpServiceName

Points to a null-terminated string that names the service to install. The maximum string length is 256 characters. The service control manager database preserves the case of the characters, but service name comparisons are always case insensitive. Forward-slash (/) and back-slash (\) are invalid service name characters.

lpDisplayName

Points to a null-terminated string that is to be used by user interface programs to identify the service. This string has a maximum length of 256 characters. The name is case-preserved in the service control manager. Display name comparisons are always case-insensitive.

dwDesiredAccess

Specifies the access to the service. Before granting the requested access, the system checks the access token of the calling process. Any or all of the following service object access types can be specified:

Access	Description
SERVICE_ALL_ACCESS	Includes STANDARD_RIGHTS_REQUIRED in addition to all of the access types listed in this table.
SERVICE_CHANGE_CONFIG	Enables calling of the ChangeServiceConfig function to change the service configuration.
SERVICE_ENUMERATE_DEPENDENTS	Enables calling of the EnumDependentServices function to enumerate all the services dependent on the service.
SERVICE_INTERROGATE	Enables calling of the ControlService function to ask the service to report its status immediately.
SERVICE_PAUSE_CONTINUE	Enables calling of the ControlService function to pause or continue the service.
SERVICE_QUERY_CONFIG	Enables calling of the QueryServiceConfig function to query the service configuration.
SERVICE_QUERY_STATUS	Enables calling of the QueryServiceStatus function to ask the service control manager about the status of the service.
SERVICE_START	Enables calling of the StartService function to start the service.
SERVICE_STOP	Enables calling of the ControlService function to stop the service.
SERVICE_USER_DEFINE_CONTROL	Enables calling of the ControlService function to specify a user-defined control code.
The STANDARD_RIGHTS_REQUIRED constant (defined in the WINNT.H file) enables the following service object access types:

Standard rights	Description
DELETE	Enables calling of the DeleteService function to delete the service.
READ_CONTROL	Enables calling of the QueryServiceObjectSecurity function to query the security descriptor of the service object.
WRITE_DAC|WRITE_OWNER	Enables calling of the SetServiceObjectSecurity function to modify the security descriptor of the service object.
The dwDesiredAccess parameter can specify any or all of the following generic access types:

Generic access	Service access
GENERIC_READ	Combines the following accesses: STANDARD_RIGHTS_READ, SERVICE_QUERY_CONFIG, SERVICE_QUERY_STATUS, and SERVICE_ENUMERATE_DEPENDENTS.
GENERIC_WRITE	Combines the following accesses: STANDARD_RIGHTS_WRITE and SERVICE_CHANGE_CONFIG.
GENERIC_EXECUTE	Combines the following accesses: STANDARD_RIGHTS_EXECUTE, SERVICE_START, SERVICE_STOP, SERVICE_PAUSE_CONTINUE, SERVICE_INTERROGATE, and SERVICE_USER_DEFINED_CONTROL.
dwServiceType

A set of bit flags that specify the type of service. You must specify one of the following service type flags to indicate the service type. In addition, if you specify either of the SERVICE_WIN32 flags, you can also specify the SERVICE_INTERACTIVE_PROCESS flag to enable the service process to interact with the desktop.

Value	Meaning
SERVICE_WIN32_OWN_PROCESS	A service-type flag that specifies a Win32 service that runs in its own process.
SERVICE_WIN32_SHARE_PROCESS	A service-type flag that specifies a Win32 service that shares a process with other services.
SERVICE_KERNEL_DRIVER	A service-type flag that specifies a Windows NT device driver.
SERVICE_FILE_SYSTEM_DRIVER	A service-type flag that specifies a Windows NT file system driver.
SERVICE_INTERACTIVE_PROCESS	A flag that enables a Win32 service process to interact with the desktop.
dwStartType

Specifies when to start the service. This member can be one of the following values:

Value	Meaning
SERVICE_BOOT_START	Specifies a device driver started by the operating system loader. This value is valid only if the service type is SERVICE_KERNEL_DRIVER or SERVICE_FILE_SYSTEM_DRIVER.
SERVICE_SYSTEM_START	Specifies a device driver started by the IoInitSystem function. This value is valid only if the service type is SERVICE_KERNEL_DRIVER or SERVICE_FILE_SYSTEM_DRIVER.
SERVICE_AUTO_START	Specifies a device driver or Win32 service started by the service control manager automatically during system startup.
SERVICE_DEMAND_START	Specifies a device driver or Win32 service started by the service control manager when a process calls the StartService function.
SERVICE_DISABLED	Specifies a device driver or Win32 service that can no longer be started.
dwErrorControl

Specifies the severity of the error if this service fails to start during startup, and determines the action taken by the startup program if failure occurs. One of the following values can be specified:

Value	Meaning
SERVICE_ERROR_IGNORE	The startup (boot) program logs the error but continues the startup operation.
SERVICE_ERROR_NORMAL	The startup program logs the error and displays a message but continues the startup operation.
SERVICE_ERROR_SEVERE	The startup program logs the error. If the last-known-good configuration is being started, the startup operation continues. Otherwise, the system is restarted with the last-known-good configuration.
SERVICE_ERROR_CRITICAL	The startup program logs the error, if possible. If the last-known-good configuration is being started, the startup operation fails. Otherwise, the system is restarted with the last-known-good configuration.
lpBinaryPathName

Points to a null-terminated string that contains the fully qualified path to the service binary file.

lpLoadOrderGroup

Points to a null-terminated string that names the load ordering group of which this service is a member. If the pointer is NULL or if it points to an empty string, the service does not belong to a group. The registry has a list of load ordering groups located at:

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control
\ServiceGroupOrder.

The startup program uses this list to load groups of services in a specified order with respect to the other groups in the list. You can place a service in a group so that another service can depend on the group.

The order in which a service starts is determined by the following criteria:

1.	The order of groups in the registry's load-ordering group list. Services in groups in the load-ordering group list are started first, followed by services in groups not in the load-ordering group list and then services that do not belong to a group.

2.	The service's dependencies listed in the lpDependencies parameter and the dependencies of other services dependent on the service.

lpdwTagId

Points to a 32-bit variable that receives a unique tag value for this service in the group specified in the lpLoadOrderGroup parameter. If no tag is requested, this parameter can be NULL.

You can use a tag for ordering service startup in a load ordering group by specifying a tag order vector in the registry located at:

HKEY_LOCAL_MACHINE\System\ CurrentControlSet
\Control\GroupOrderList.

Tags are only evaluated for SERVICE_KERNEL_DRIVER and SERVICE_FILE_SYSTEM_DRIVER type services that have SERVICE_BOOT_START or SERVICE_SYSTEM_START start types.

lpDependencies

Points to an array of null-separated names of services or load ordering groups that must start before this service. The array is double null-terminated. If the pointer is NULL or if it points to an empty string, the service has no dependencies. If a group name is specified, it must be prefixed by the SC_GROUP_IDENTIFIER character (defined in the WINSVC.H file) to differentiate it from a service name, because services and service groups share the same name space. Dependency on a service means that this service can only run if the service it depends on is running. Dependency on a group means that this service can run if at least one member of the group is running after an attempt to start all members of the group.

lpServiceStartName

Points to a null-terminated string. If the service type is SERVICE_WIN32_OWN_PROCESS, this name is the account name in the form of "DomainName\Username", which the service process will be logged on as when it runs. If the account belongs to the built-in domain, ".\Username" can be specified. Services of type SERVICE_WIN32_SHARE_PROCESS are not allowed to specify an account other than LocalSystem. If NULL is specified, the service will be logged on as the "LocalSystem" account, in which case, the lpPassword parameter must be NULL.

If the service type is SERVICE_KERNEL_DRIVER or SERVICE_FILE_SYSTEM_DRIVER, this name is the Windows NT driver object name (that is, \FileSystem\Rdr or \Driver\Xns), which the input and output (I/O) system uses to load the device driver. If NULL is specified, the driver is run with a default object name created by the I/O system, based on the service name.

lpPassword

Points to a null-terminated string that contains the password to the account name specified by the lpServiceStartName parameter, if the service type is SERVICE_WIN32_OWN_PROCESS or SERVICE_WIN32_SHARE_PROCESS. If the pointer is NULL or if it points to an empty string, the service has no password. If the service type is SERVICE_KERNEL_DRIVER or SERVICE_FILE_SYSTEM_DRIVER, this parameter is ignored.

Return Value

If the function succeeds, the return value is a handle to the service.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Errors

The following error codes can be set by the service control manager. Other error codes can be set by the registry functions that are called by the service control manager.

Value	Meaning
ERROR_ACCESS_DENIED	The handle to the specified service control manager database does not have SC_MANAGER_CREATE_SERVICE access.
ERROR_CIRCULAR_DEPENDENCY	A circular service dependency was specified.
ERROR_DUP_NAME	The display name already exists in the service control manager database either as a service name or as another display name.
ERROR_INVALID_HANDLE	The handle to the specified service control manager database is invalid.
ERROR_INVALID_NAME	The specified service name is invalid.
ERROR_INVALID_PARAMETER	A parameter that was specified is invalid.
ERROR_INVALID_SERVICE_ACCOUNT	The user account name specified in the lpServiceStartName parameter does not exist.
ERROR_SERVICE_EXISTS	The specified service already exists in this database.
Remarks

The CreateService function creates a service object and installs it in the service control manager database by creating a service name key in the registry with the following form:

HKEY_LOCAL_MACHINE\System\CurrentControlSet
\Services\lpServiceName

where lpServiceName is the service name specified for this function. Information specified for this function is saved as values under this key. Setup programs and the service itself can create any subkey under this service name key for any service specific information.

If the appropriate access rights are enabled, the calling process can use the returned handle to identify the newly created service in the following functions:

ChangeServiceConfig, ControlService, DeleteService, QueryServiceConfig, QueryServiceObjectSecurity, QueryServiceStatus, SetServiceObjectSecurity, StartService

The returned handle is only valid for the process that called CreateService. It can be closed by calling the CloseServiceHandle function.

See Also

ChangeServiceConfig, CloseServiceHandle, ControlService, DeleteService, EnumDependentServices, OpenSCManager, QueryServiceConfig, QueryServiceObjectSecurity, QueryServiceStatus, SetServiceObjectSecurity, StartService


CreateSolidBrush
CreateSolidBrush  QuickInfo  Overview  Group

The CreateSolidBrush function creates a logical brush that has the specified solid color.

HBRUSH CreateSolidBrush(

COLORREF  crColor	// brush color value
);
Parameters

crColor

Specifies the color of the brush.

Return Value

If the function succeeds, the return value identifies a logical brush.

If the function fails, the return value is NULL.

Remarks

A solid brush is a bitmap that Windows uses to paint the interiors of filled shapes.

After an application creates a brush by calling CreateSolidBrush, it can select that brush into any device context by calling the SelectObject function.

See Also

CreateDIBPatternBrush, CreateDIBPatternBrushPt, CreateHatchBrush, CreatePatternBrush, DeleteObject, SelectObject


CreateStatusWindow [New - Windows NT]
CreateStatusWindow  QuickInfo  Overview  Group

[New - Windows NT]

The CreateStatusWindow function creates a status window, which is typically used to display the status of an application. The window generally appears at the bottom of the parent window, and it contains the specified text.

HWND CreateStatusWindow(

LONG style,
LPCTSTR lpszText,
HWND hwndParent,
UINT wID
);
Parameters

style

Window styles for the status window. This parameter must include the WS_CHILD style and should also include the WS_VISIBLE style.

lpszText

Pointer to a null-terminated string that specifies the status text for the first part.

hwndParent

Handle to the parent window.

wID

Control identifier for the status window. The window procedure uses this value to identify messages it sends to the parent window.

Return Value

If the function succeeds, the return value is the handle for the status window.

If the function fails, the return value is NULL.

Remarks

The CreateStatusWindow function calls the CreateWindow function to create the window. It passes the parameters to CreateWindow without modification and sets the position, width, and height parameters to default values.

Windows 95 only: The system can support a maximum of 16,364 window handles.

See Also

CreateWindow


CreateTapePartition
CreateTapePartition  QuickInfo  Overview  Group

The CreateTapePartition function reformats a tape.

DWORD CreateTapePartition(

HANDLE  hDevice,	// handle of open device
DWORD  dwPartitionMethod,	// type of new partition
DWORD  dwCount,	// number of new partitions to create
DWORD  dwSize	// size of new partition, in megabytes
);
Parameters

hDevice

Identifies the device where the new partition is to be created. This handle is created by using the CreateFile function.

dwPartitionMethod

Specifies the type of partition to create. To determine what type of partitions your device supports, see the documentation for your hardware. This parameter can have one of the following values:

Value	Description
TAPE_FIXED_PARTITIONS	Partitions the tape based on the device's default definition of partitions. The dwCount and dwSize parameters are ignored.
TAPE_INITIATOR_PARTITIONS	Partitions the tape into the number and size of partitions specified by dwCount and dwSize, respectively, except for the last partition. The size of the last partition is the remainder of the tape.
TAPE_SELECT_PARTITIONS	Partitions the tape into the number of partitions specified by dwCount. The dwSize parameter is ignored. The size of the partitions is determined by the device's default partition size. For more specific information, refer to the documentation for your tape device.
dwCount

Specifies the number of partitions to create. The GetTapeParameters function provides the maximum number of partitions a tape can support.

dwSize

Specifies the size, in megabytes, of each partition. This value is ignored if the dwPartitionMethod parameter is TAPE_SELECT_PARTITIONS.

Return Value

If the function succeeds, the return value is NO_ERROR.

If the function fails, it may return one of the following error codes:

Error	Description
ERROR_BEGINNING_OF_MEDIA	An attempt to access data before the beginning-of-medium marker failed.
ERROR_BUS_RESET	A reset condition was detected on the bus.
ERROR_END_OF_MEDIA	The end-of-tape marker was reached during an operation.
ERROR_FILEMARK_DETECTED	A filemark was reached during an operation.
ERROR_SETMARK_DETECTED	A setmark was reached during an operation.
ERROR_NO_DATA_DETECTED	The end-of-data marker was reached during an operation.
ERROR_PARTITION_FAILURE	The tape could not be partitioned.
ERROR_INVALID_BLOCK_LENGTH	The block size is incorrect on a new tape in a multivolume partition.
ERROR_DEVICE_NOT_PARTITIONED	The partition information could not be found when a tape was being loaded.
ERROR_MEDIA_CHANGED	The tape that was in the drive has been replaced or removed.
ERROR_NO_MEDIA_IN_DRIVE	There is no media in the drive.
ERROR_NOT_SUPPORTED	The tape driver does not support a requested function.
ERROR_UNABLE_TO_LOCK_MEDIA	An attempt to lock the ejection mechanism failed.
ERROR_UNABLE_TO_UNLOAD_MEDIA	An attempt to unload the tape failed.
ERROR_WRITE_PROTECT	The media is write protected.
Remarks

Creating partitions reformats the tape. All previous information recorded on the tape is destroyed.

See Also

CreateFile, GetTapeParameters


CreateToolbarEx [New - Windows NT]
CreateToolbarEx  QuickInfo  Overview  Group

[New - Windows NT]

The CreateToolbarEx function creates a toolbar window and adds the specified buttons to the toolbar.

HWND CreateToolbarEx(

HWND  hwnd,
DWORD  ws,
UINT  wID,
int  nBitmaps,
HINSTANCE  hBMInst,
UINT  wBMID,
LPCTBBUTTON  lpButtons,
int  iNumButtons,
int dxButton,
int dyButton,
int  dxBitmap,
int  dyBitmap,
UINT  uStructSize
);
Parameters

hwnd

Handle to the parent window for the toolbar.

ws

Window styles for the toolbar. This parameter must specify at least the WS_CHILD style. It can also include a combination of styles as discussed in Toolbars and related topics.

wID

Control identifier for the toolbar.

nBitmaps

Number of button images contained in the bitmap specified by hBMInst and wBMID.

hBMInst

Module instance with the executable file that contains the bitmap resource.

wBMID

Resource identifier for the bitmap resource. If hBMInst is NULL, this parameter must be a valid bitmap handle.

lpButtons

Pointer to an array of TBBUTTON structures that contains information about the buttons to add to the toolbar.

iNumButtons

Number of buttons to add to the toolbar.

dxButton

Width, in pixels, of the buttons to add to the toolbar.

dyButton

Height, in pixels, of the buttons to add to the toolbar.

dxBitmap

Width, in pixels, of the button images to add to the buttons in the toolbar.

dyBitmap

Height, in pixels, of the button images to add to the buttons in the toolbar.

uStructSize

Size of a TBBUTTON structure.

Return Value

If the function succeeds, the return value is the window handle to the toolbarl

If the function fails, the return value is NULL.

Remarks

Windows 95 only: The system can support a maximum of 16,364 window handles.

See Also

TBBUTTON


CreateThread
CreateThread  QuickInfo  Overview  Group

The CreateThread function creates a thread to execute within the address space of the calling process.

HANDLE CreateThread(

LPSECURITY_ATTRIBUTES  lpThreadAttributes,	// address of thread security attributes
DWORD  dwStackSize,	// initial thread stack size, in bytes
LPTHREAD_START_ROUTINE  lpStartAddress,	// address of thread function
LPVOID  lpParameter,	// argument for new thread
DWORD  dwCreationFlags,	// creation flags
LPDWORD  lpThreadId	// address of returned thread identifier
);
Parameters

lpThreadAttributes

Points to a SECURITY_ATTRIBUTES structure that specifies the security attributes for the thread.

If lpThreadAttributes is NULL, the thread is created with a default security descriptor, and the resulting handle is not inherited.

dwStackSize

Specifies the size, in bytes, of the stack for the new thread. If 0 is specified, the stack size defaults to the same size as that of the primary thread of the process. The stack is allocated automatically in the memory space of the process and it is freed when the thread terminates. Note that the stack size grows, if necessary.

CreateThread tries to commit the number of bytes specified by dwStackSize, and fails if the size exceeds available memory.

lpStartAddress

Points to the application-supplied function to be executed by the thread and represents the starting address of the thread. The function accepts a single 32-bit argument and returns a 32-bit exit value.

lpParameter

Specifies a single 32-bit parameter value passed to the thread.

dwCreationFlags

Specifies additional flags that control the creation of the thread. If the CREATE_SUSPENDED flag is specified, the thread is created in a suspended state, and will not run until the ResumeThread function is called. If this value is zero, the thread runs immediately after creation.

lpThreadId

Points to a 32-bit variable that receives the thread identifier.

Return Value

If the function succeeds, the return value is a handle to the new thread.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Windows 95 only: CreateThread succeeds only when it is called in the context of a 32-bit program. A 32-bit DLL cannot create an additional thread when that DLL is being called by a 16-bit program.

Remarks

The new thread handle is created with full access to the new thread. If a security descriptor is not provided, the handle can be used in any function that requires a thread object handle. When a security descriptor is provided, an access check is performed on all subsequent uses of the handle before access is granted. If the access check denies access, the requesting process cannot use the handle to gain access to the thread.

The thread execution begins at the function specified by the lpStartAddress parameter. If this function returns, the DWORD return value is used to terminate the thread in an implicit call to the ExitThread function. Use the GetExitCodeThread function to get the thread's return value.

The CreateThread function may succeed even if lpStartAddress points to data, code, or is not accessible. If the start address is invalid when the thread runs, an exception occurs, and the thread terminates. Thread termination due to a invalid start address is handled as an error exit for the thread's process. This behavior is similar to the asynchronous nature of CreateProcess, where the process is created even if it refers to invalid or missing dynamic-link libraries (DLLs).

The thread is created with a thread priority of THREAD_PRIORITY_NORMAL. Use the GetThreadPriority and SetThreadPriority functions to get and set the priority value of a thread.

When a thread terminates, the thread object attains a signaled state, satisfying any threads that were waiting on the object.

The thread object remains in the system until the thread has terminated and all handles to it have been closed through a call to CloseHandle.

The ExitProcess, ExitThread, CreateThread, CreateRemoteThread functions, and a process that is starting (as the result of a call by CreateProcess) are serialized between each other within a process. Only one of these events can happen in an address space at a time. This means that the following restrictions hold:

•	During process startup and DLL initialization routines, new threads can be created, but they do not begin execution until DLL initialization is done for the process.

•	Only one thread in a process can be in a DLL initialization or detach routine at a time.

•	ExitProcess does not return until no threads are in their DLL initialization or detach routines.

A thread that uses functions from the C run-time libraries should use the beginthread and endthread C run-time functions for thread management rather than CreateThread and ExitThread. Failure to do so results in small memory leaks when ExitThread is called.

See Also

CloseHandle, CreateProcess, CreateRemoteThread, ExitProcess, ExitThread, GetExitCodeThread, GetThreadPriority, ResumeThread, SetThreadPriority, SECURITY_ATTRIBUTES


CreateUpDownControl [New - Windows NT]
CreateUpDownControl  QuickInfo  Overview  Group

[New - Windows NT]

The CreateUpDownControl function creates an up-down control.

HWND CreateUpDownControl(

DWORD  dwStyle,
int  x,
int  y,
int  cx,
int cy,
HWND  hParent,
int  nID,
HINSTANCE  hInst
HWND  hBuddy,
int  nUpper,
int  nLower,
int  nPos
);
Parameters

dwStyle

Window styles for the control. This parameter should include the WS_CHILD, WS_BORDER, and WS_VISIBLE styles, and it may include any of the window styles specific to the up-down control.

x

Horizontal coordinate, in client coordinates, of the upper-left corner of the control.

y

Vertical coordinate, in client coordinates, of the upper-left corner of the control.

cx

Width, in pixels, of the up-down control.

cy

Height, in pixels, of the up-down control.

hParent

Handle to the parent window of the up-down control

nID

Identifier for the up-down control.

hInst

Handle to the module instance of the application creating the up-down control.

hBuddy

Handle to the window associated with the up-down control. If this parameter is NULL, the control has no buddy window.

nUpper

Upper limit (range) of the up-down control.

nLower

Lower limit (range) of the up-down control.

nPos

Position of the control.

Return Value

If the function succeeds, the return value is the window handle of the up-down control.

If the function fails, the return value is NULL.

Remarks

Windows 95 only: The system can support a maximum of 16,364 window handles.


CreateWindow
CreateWindow  QuickInfo  Overview  Group

The CreateWindow function creates an overlapped, pop-up, or child window. It specifies the window class, window title, window style, and (optionally) the initial position and size of the window. The function also specifies the window's parent or owner, if any, and the window's menu.

HWND CreateWindow(

LPCTSTR  lpClassName,	// address of registered class name
LPCTSTR  lpWindowName,	// address of window name
DWORD  dwStyle,	// window style
int  x,	// horizontal position of window
int  y,	// vertical position of window
int  nWidth,	// window width
int  nHeight,	// window height
HWND  hWndParent,	// handle of parent or owner window
HMENU  hMenu,	// handle of menu or child-window identifier
HANDLE  hInstance,	// handle of application instance
LPVOID  lpParam	// address of window-creation data
);
Parameters

lpClassName

Points to a null-terminated string or is an integer atom. If this parameter is an atom, it must be a global atom created by a previous call to the GlobalAddAtom function. The atom, a 16-bit value less than 0xC000, must be in the low-order word of lpClassName; the high-order word must be zero.

If lpClassName is a string, it specifies the window class name. The class name can be any name registered with the RegisterClass function or any of the predefined control-class names. For a complete list, see the following Remarks section.

lpWindowName

Points to a null-terminated string that specifies the window name.

dwStyle

Specifies the style of the window being created. This parameter can be a combination of the window styles and control styles listed in the following Remarks section.

x

Specifies the initial horizontal position of the window. For an overlapped or pop-up window, the x parameter is the initial x-coordinate of the window's upper-left corner, in screen coordinates. For a child window, x is the x-coordinate of the upper-left corner of the window relative to the upper-left corner of the parent window's client area.

If this parameter is set to CW_USEDEFAULT, Windows selects the default position for the window's upper-left corner and ignores the y parameter. CW_USEDEFAULT is valid only for overlapped windows; if it is specified for a pop-up or child window, the x and y parameters are set to zero.

y

Specifies the initial vertical position of the window. For an overlapped or pop-up window, the y parameter is the initial y-coordinate of the window's upper-left corner, in screen coordinates. For a child window, y is the initial y-coordinate of the upper-left corner of the child window relative to the upper-left corner of the parent window's client area. For a list box, y is the initial y-coordinate of the upper-left corner of the list box's client area relative to the upper-left corner of the parent window's client area.

If an overlapped window is created with the WS_VISIBLE style bit set and the x parameter is set to CW_USEDEFAULT, Windows ignores the y parameter.

nWidth

Specifies the width, in device units, of the window. For overlapped windows, nWidth is either the window's width, in screen coordinates, or CW_USEDEFAULT. If nWidth is CW_USEDEFAULT, Windows selects a default width and height for the window; the default width extends from the initial x-coordinate to the right edge of the screen, and the default height extends from the initial y-coordinate to the top of the icon area. CW_USEDEFAULT is valid only for overlapped windows; if CW_USEDEFAULT is specified for a pop-up or child window, nWidth and nHeight are set to zero.

nHeight

Specifies the height, in device units, of the window. For overlapped windows, nHeight is the window's height, in screen coordinates. If nWidth is set to CW_USEDEFAULT, Windows ignores nHeight.

hWndParent

Identifies the parent or owner window of the window being created. A valid window handle must be supplied when a child window or an owned window is created. A child window is confined to the client area of its parent window. An owned window is an overlapped window that is destroyed when its owner window is destroyed or hidden when its owner is minimized; it is always displayed on top of its owner window. Although this parameter must specify a valid handle if the dwStyle parameter includes the WS_CHILD style, it is optional if dwStyle includes the WS_POPUP style.

hMenu

Identifies a menu, or specifies a child-window identifier depending on the window style. For an overlapped or pop-up window, hMenu identifies the menu to be used with the window; it can be NULL if the class menu is to be used. For a child window, hMenu specifies the child-window identifier, an integer value used by a dialog box control to notify its parent about events. The application determines the child-window identifier; it must be unique for all child windows with the same parent window.

hInstance

Identifies the instance of the module to be associated with the window.

lpParam

Points to a value passed to the window through the CREATESTRUCT structure referenced by the lParam parameter of the WM_CREATE message. If an application calls CreateWindow to create a multiple document interface (MDI) client window, lpParam must point to a CLIENTCREATESTRUCT structure.

Return Value

If the function succeeds, the return value is the handle of the new window.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

Before returning, CreateWindow sends a WM_CREATE message to the window procedure.

For overlapped, pop-up, and child windows, CreateWindow sends WM_CREATE, WM_GETMINMAXINFO, and WM_NCCREATE messages to the window. The lParam parameter of the WM_CREATE message contains a pointer to a CREATESTRUCT structure. If the WS_VISIBLE style is specified, CreateWindow sends the window all the messages required to activate and show the window.

If the window style specifies a title bar, the window title pointed to by lpWindowName is displayed in the title bar. When using CreateWindow to create controls, such as buttons, check boxes, and static controls, use lpWindowName to specify the text of the control.

The following predefined control classes can be specified in the lpClassName parameter:

Class	Meaning
BUTTON	Designates a small rectangular child window that represents a button the user can click to turn it on or off. Button controls can be used alone or in groups, and they can either be labeled or appear without text. Button controls typically change appearance when the user clicks them.
COMBOBOX	Designates a control consisting of a list box and a selection field similar to an edit control. When using this style, an application should either display the list box at all times or enable a drop-down list box.
	Depending on the style of the combo box, the user can or cannot edit the contents of the selection field. If the list box is visible, typing characters into the selection field highlights the first list box entry that matches the characters typed. Conversely, selecting an item in the list box displays the selected text in the selection field.
EDIT	Designates a rectangular child window into which the user can type text from the keyboard. The user selects the control and gives it the keyboard focus by clicking it or moving to it by pressing the TAB key. The user can type text when the edit control displays a flashing caret; use the mouse to move the cursor, select characters to be replaced, or position the cursor for inserting characters; or use the BACKSPACE key to delete characters.
	Edit controls use the variable-pitch system font and display characters from the ANSI character set. The WM_SETFONT message can also be sent to the edit control to change the default font.
	Edit controls expand tab characters into as many space characters as are required to move the caret to the next tab stop. Tab stops are assumed to be at every eighth character position.
LISTBOX	Designates a list of character strings. Specify this control whenever an application must present a list of names, such as filenames, from which the user can choose. The user can select a string by clicking it. A selected string is highlighted, and a notification message is passed to the parent window. Use a vertical or horizontal scroll bar with a list box to scroll lists that are too long for the control window. The list box automatically hides or shows the scroll bar, as needed.
MDICLIENT	Designates an MDI client window. This window receives messages that control the MDI application's child windows. The recommended style bits are WS_CLIPCHILDREN and WS_CHILD. Specify the WS_HSCROLL and WS_VSCROLL styles to create an MDI client window that allows the user to scroll MDI child windows into view.
SCROLLBAR	Designates a rectangle that contains a scroll box and has direction arrows at both ends. The scroll bar sends a notification message to its parent window whenever the user clicks the control. The parent window is responsible for updating the position of the scroll box, if necessary. Scroll bar controls have the same appearance and function as scroll bars used in ordinary windows. Unlike scroll bars, however, scroll bar controls can be positioned anywhere in a window for use whenever scrolling input is needed for a window.
	The scroll bar class also includes size box controls. A size box is a small rectangle the user can expand to change the size of the window.
STATIC	Designates a simple text field, box, or rectangle used to label, box, or separate other controls. Static controls take no input and provide no output.
The following window styles can be specified in the dwStyle parameter:

Style	Meaning
WS_BORDER	Creates a window that has a thin-line border.
WS_CAPTION	Creates a window that has a title bar (includes the WS_BORDER style).
WS_CHILD	Creates a child window. This style cannot be used with the WS_POPUP style.
WS_CHILDWINDOW	Same as the WS_CHILD style.
WS_CLIPCHILDREN	Excludes the area occupied by child windows when drawing occurs within the parent window. This style is used when creating the parent window.
WS_CLIPSIBLINGS	Clips child windows relative to each other; that is, when a particular child window receives a WM_PAINT message, the WS_CLIPSIBLINGS style clips all other overlapping child windows out of the region of the child window to be updated. If WS_CLIPSIBLINGS is not specified and child windows overlap, it is possible, when drawing within the client area of a child window, to draw within the client area of a neighboring child window.
WS_DISABLED	Creates a window that is initially disabled. A disabled window cannot receive input from the user.
WS_DLGFRAME	Creates a window that has a border of a style typically used with dialog boxes. A window with this style cannot have a title bar.
WS_GROUP	Specifies the first control of a group of controls. The user can change the keyboard focus from one control in the group to the next by using the direction keys. All controls defined with the WS_GROUP style after the first control belong to the same group. The next control with the WS_GROUP style ends the group and starts the next group.
WS_HSCROLL	Creates a window that has a horizontal scroll bar.
WS_ICONIC	Creates a window that is initially minimized. Same as the WS_MINIMIZE style.
WS_MAXIMIZE	Creates a window that is initially maximized.
WS_MAXIMIZEBOX	Creates a window that has a Maximize button.
WS_MINIMIZE	Creates a window that is initially minimized. Same as the WS_ICONIC style.
WS_MINIMIZEBOX	Creates a window that has a Minimize button.
WS_OVERLAPPED	Creates an overlapped window. An overlapped window has a title bar and a border. Same as the WS_TILED style.
WS_OVERLAPPEDWINDOW	Creates an overlapped window with the WS_OVERLAPPED, WS_CAPTION, WS_SYSMENU, WS_THICKFRAME, WS_MINIMIZEBOX, and WS_MAXIMIZEBOX styles. Same as the WS_TILEDWINDOW style.
WS_POPUP	Creates a pop-up window. This style cannot be used with the WS_CHILD style.
WS_POPUPWINDOW	Creates a pop-up window with WS_BORDER, WS_POPUP, and WS_SYSMENU styles. The WS_CAPTION and WS_POPUPWINDOW styles must be combined to make the System menu visible.
WS_SIZEBOX	Creates a window that has a sizing border. Same as the WS_THICKFRAME style.
WS_SYSMENU	Creates a window that has a System-menu box in its title bar. The WS_CAPTION style must also be specified.
WS_TABSTOP	Specifies a control that can receive the keyboard focus when the user presses the TAB key. Pressing the TAB key changes the keyboard focus to the next control with the WS_TABSTOP style.
WS_THICKFRAME	Creates a window that has a sizing border. Same as the WS_SIZEBOX style.
WS_TILED	Creates an overlapped window. An overlapped window has a title bar and a border. Same as the WS_OVERLAPPED style.
WS_TILEDWINDOW	Creates an overlapped window with the WS_OVERLAPPED, WS_CAPTION, WS_SYSMENU, WS_THICKFRAME, WS_MINIMIZEBOX, and WS_MAXIMIZEBOX styles. Same as the WS_OVERLAPPEDWINDOW style.
WS_VISIBLE	Creates a window that is initially visible.
WS_VSCROLL	Creates a window that has a vertical scroll bar.
The following button styles (in the BUTTON class) can be specified in the dwStyle parameter:

Style	Meaning
BS_3STATE	Creates a button that is the same as a check box, except that the box can be grayed as well as checked or unchecked. Use the grayed state to show that the state of the check box is not determined.
BS_AUTO3STATE	Creates a button that is the same as a three-state check box, except that the box changes its state when the user selects it. The state cycles through checked, grayed, and unchecked.
BS_AUTOCHECKBOX	Creates a button that is the same as a check box, except that the check state automatically toggles between checked and unchecked each time the user selects the check box.
BS_AUTORADIOBUTTON	Creates a button that is the same as a radio button, except that when the user selects it, Windows automatically sets the button's check state to checked and automatically sets the check state for all other buttons in the same group to unchecked.
BS_CHECKBOX	Creates a small, empty check box with text. By default, the text is displayed to the right of the check box. To display the text to the left of the check box, combine this flag with the BS_LEFTTEXT style (or on Windows 95 only, with the equivalent BS_RIGHTBUTTON style).
BS_DEFPUSHBUTTON	Creates a push button that behaves like a BS_PUSHBUTTON style button, but also has a heavy black border. If the button is in a dialog box, the user can select the button by pressing the ENTER key, even when the button does not have the input focus. This style is useful for enabling the user to quickly select the most likely (default) option.
BS_GROUPBOX	Creates a rectangle in which other controls can be grouped. Any text associated with this style is displayed in the rectangle's upper left corner.
BS_LEFTTEXT	Places text on the left side of the radio button or check box when combined with a radio button or check box style. Same as the Windows 95 BS_RIGHTBUTTON style.
BS_OWNERDRAW	Creates an owner-drawn button. The owner window receives a WM_MEASUREITEM message when the button is created and a WM_DRAWITEM message when a visual aspect of the button has changed. Do not combine the BS_OWNERDRAW style with any other button styles.
BS_PUSHBUTTON	Creates a push button that posts a WM_COMMAND message to the owner window when the user selects the button.
BS_RADIOBUTTON	Creates a small circle with text. By default, the text is displayed to the right of the circle. To display the text to the left of the circle, combine this flag with the BS_LEFTTEXT style (or on Windows 95 only, with the equivalent BS_RIGHTBUTTON style). Use radio buttons for groups of related, but mutually exclusive choices.
BS_USERBUTTON	Obsolete, but provided for compatibility with 16-bit versions of Windows. Win32-based applications should use BS_OWNERDRAW instead.
BS_BITMAP	Windows 95 only: Specifies that the button displays a bitmap.
BS_BOTTOM	Windows 95 only: Places text at the bottom of the button rectangle.
BS_CENTER	Windows 95 only: Centers text horizontally in the button rectangle.
BS_ICON	Windows 95 only: Specifies that the button displays an icon.
BS_LEFT	Windows 95 only: Left-justifies the text in the button rectangle. However, if the button is a check box or radio button that does not have the BS_RIGHTBUTTON style, the text is left justified on the right side of the check box or radio button.
BS_MULTILINE	Windows 95 only: Wraps the button text to multiple lines if the text string is too long to fit on a single line in the button rectangle.
BS_NOTIFY	Windows 95 only: Enables a button to send BN_DBLCLK, BN_KILLFOCUS, and BN_SETFOCUS notification messages to its parent window. Note that buttons send the BN_CLICKED notification message regardless of whether it has this style.
BS_PUSHLIKE	Windows 95 only: Makes a button (such as a check box, three-state check box, or radio button) look and act like a push button. The button looks raised when it isn't pushed or checked, and sunken when it is pushed or checked.
BS_RIGHT	Windows 95 only: Right-justifies text in the button rectangle. However, if the button is a check box or radio button that does not have the BS_RIGHTBUTTON style, the text is right justified on the right side of the check box or radio button.
BS_RIGHTBUTTON	Windows 95 only: Positions a radio button's circle or a check box's square on the right side of the button rectangle. Same as the BS_LEFTTEXT style.
BS_TEXT	Windows 95 only: Specifies that the button displays text.
BS_TOP	Windows 95 only: Places text at the top of the button rectangle.
BS_VCENTER	Windows 95 only: Places text in the middle (vertically) of the button rectangle.
The following combo box styles (in the COMBOBOX class) can be specified in the dwStyle parameter:

Style	Meaning
CBS_AUTOHSCROLL	Automatically scrolls the text in an edit control to the right when the user types a character at the end of the line. If this style is not set, only text that fits within the rectangular boundary is allowed.
CBS_DISABLENOSCROLL	Shows a disabled vertical scroll bar in the list box when the box does not contain enough items to scroll. Without this style, the scroll bar is hidden when the list box does not contain enough items.
CBS_DROPDOWN	Similar to CBS_SIMPLE, except that the list box is not displayed unless the user selects an icon next to the edit control.
CBS_DROPDOWNLIST	Similar to CBS_DROPDOWN, except that the edit control is replaced by a static text item that displays the current selection in the list box.
CBS_HASSTRINGS	Specifies that an owner-drawn combo box contains items consisting of strings. The combo box maintains the memory and address for the strings, so the application can use the CB_GETLBTEXT message to retrieve the text for a particular item.
CBS_LOWERCASE	Converts to lowercase any uppercase characters entered into the edit control of a combo box.
CBS_NOINTEGRALHEIGHT	Specifies that the size of the combo box is exactly the size specified by the application when it created the combo box. Normally, Windows sizes a combo box so that it does not display partial items.
CBS_OEMCONVERT	Converts text entered in the combo box edit control. The text is converted from the Windows character set to the OEM character set and then back to the Windows set. This ensures proper character conversion when the application calls the CharToOem function to convert a Windows string in the combo box to OEM characters. This style is most useful for combo boxes that contain filenames and applies only to combo boxes created with the CBS_SIMPLE or CBS_DROPDOWN style.
CBS_OWNERDRAWFIXED	Specifies that the owner of the list box is responsible for drawing its contents and that the items in the list box are all the same height. The owner window receives a WM_MEASUREITEM message when the combo box is created and a WM_DRAWITEM message when a visual aspect of the combo box has changed.
CBS_OWNERDRAWVARIABLE	Specifies that the owner of the list box is responsible for drawing its contents and that the items in the list box are variable in height. The owner window receives a WM_MEASUREITEM message for each item in the combo box when you create the combo box; the owner window receives a WM_DRAWITEM message when a visual aspect of the combo box has changed.
CBS_SIMPLE	Displays the list box at all times. The current selection in the list box is displayed in the edit control.
CBS_SORT	Automatically sorts strings entered into the list box.
CBS_UPPERCASE	Converts to uppercase any lowercase characters entered into the edit control of a combo box.
The following edit control styles (in the EDIT class) can be specified in the dwStyle parameter:

Style	Meaning
ES_AUTOHSCROLL	Automatically scrolls text to the right by 10 characters when the user types a character at the end of the line. When the user presses the ENTER key, the control scrolls all text back to position zero.
ES_AUTOVSCROLL	Automatically scrolls text up one page when the user presses the ENTER key on the last line.
ES_CENTER	Centers text in a multiline edit control.
ES_LEFT	Left-aligns text.
ES_LOWERCASE	Converts all characters to lowercase as they are typed into the edit control.
ES_MULTILINE	Designates a multiline edit control. The default is single-line edit control.
	When the multiline edit control is in a dialog box, the default response to pressing the ENTER key is to activate the default button. To use the ENTER key as a carriage return, use the ES_WANTRETURN style.
	When the multiline edit control is not in a dialog box and the ES_AUTOVSCROLL style is specified, the edit control shows as many lines as possible and scrolls vertically when the user presses the ENTER key. If you do not specify ES_AUTOVSCROLL, the edit control shows as many lines as possible and beeps if the user presses the ENTER key when no more lines can be displayed.
	If you specify the ES_AUTOHSCROLL style, the multiline edit control automatically scrolls horizontally when the caret goes past the right edge of the control. To start a new line, the user must press the ENTER key. If you do not specify ES_AUTOHSCROLL, the control automatically wraps words to the beginning of the next line when necessary. A new line is also started if the user presses the ENTER key. The window size determines the position of the word wrap. If the window size changes, the word wrapping position changes and the text is redisplayed.
	Multiline edit controls can have scroll bars. An edit control with scroll bars processes its own scroll bar messages. Note that edit controls without scroll bars scroll as described in the previous paragraphs and process any scroll messages sent by the parent window.
ES_NOHIDESEL	Negates the default behavior for an edit control. The default behavior hides the selection when the control loses the input focus and inverts the selection when the control receives the input focus. If you specify ES_NOHIDESEL, the selected text is inverted, even if the control does not have the focus.
ES_NUMBER	Windows 95 only: Allows only digits to be entered into the edit control.
ES_OEMCONVERT	Converts text entered in the edit control. The text is converted from the Windows character set to the OEM character set and then back to the Windows set. This ensures proper character conversion when the application calls the CharToOem function to convert a Windows string in the edit control to OEM characters. This style is most useful for edit controls that contain filenames.
ES_PASSWORD	Displays an asterisk (*) for each character typed into the edit control. You can use the EM_SETPASSWORDCHAR message to change the character that is displayed.
ES_READONLY	Prevents the user from typing or editing text in the edit control.
ES_RIGHT	Right-aligns text in a multiline edit control.
ES_UPPERCASE	Converts all characters to uppercase as they are typed into the edit control.
ES_WANTRETURN	Specifies that a carriage return be inserted when the user presses the ENTER key while entering text into a multiline edit control in a dialog box. If you do not specify this style, pressing the ENTER key has the same effect as pressing the dialog box's default push button. This style has no effect on a single-line edit control.
The following list box control styles (in the LISTBOX class) can be specified in the dwStyle parameter:

Style	Meaning
LBS_DISABLENOSCROLL	Shows a disabled vertical scroll bar for the list box when the box does not contain enough items to scroll. If you do not specify this style, the scroll bar is hidden when the list box does not contain enough items.
LBS_EXTENDEDSEL	Allows multiple items to be selected by using the SHIFT key and the mouse or special key combinations.
LBS_HASSTRINGS	Specifies that a list box contains items consisting of strings. The list box maintains the memory and addresses for the strings so the application can use the LB_GETTEXT message to retrieve the text for a particular item. By default, all list boxes except owner-drawn list boxes have this style. You can create an owner-drawn list box either with or without this style.
LBS_MULTICOLUMN	Specifies a multicolumn list box that is scrolled horizontally. The LB_SETCOLUMNWIDTH message sets the width of the columns.
LBS_MULTIPLESEL	Turns string selection on or off each time the user clicks or double-clicks a string in the list box. The user can select any number of strings.
LBS_NODATA	Specifies a no-data list box. Specify this style when the count of items in the list box will exceed one thousand. A no-data list box must also have the LBS_OWNERDRAWFIXED style, but must not have the LBS_SORT or LBS_HASSTRINGS style.
	A no-data list box resembles an owner-drawn list box except that it contains no string or bitmap data for an item. Commands to add, insert, or delete an item always ignore any given item data; requests to find a string within the list box always fail. Windows sends the WM_DRAWITEM message to the owner window when an item must be drawn. The itemID member of the DRAWITEMSTRUCT structure passed with the WM_DRAWITEM message specifies the line number of the item to be drawn. A no-data list box does not send a WM_DELETEITEM message.
LBS_NOINTEGRALHEIGHT	Specifies that the size of the list box is exactly the size specified by the application when it created the list box. Normally, Windows sizes a list box so that the list box does not display partial items.
LBS_NOREDRAW	Specifies that the list box's appearance is not updated when changes are made. You can change this style at any time by sending a WM_SETREDRAW message.
LBS_NOTIFY	Notifies the parent window with an input message whenever the user clicks or double-clicks a string in the list box.
LBS_OWNERDRAWFIXED	Specifies that the owner of the list box is responsible for drawing its contents and that the items in the list box are the same height. The owner window receives a WM_MEASUREITEM message when the list box is created and a WM_DRAWITEM message when a visual aspect of the list box has changed.
LBS_OWNERDRAWVARIABLE	Specifies that the owner of the list box is responsible for drawing its contents and that the items in the list box are variable in height. The owner window receives a WM_MEASUREITEM message for each item in the combo box when the combo box is created and a WM_DRAWITEM message when a visual aspect of the combo box has changed.
LBS_SORT	Sorts strings in the list box alphabetically.
LBS_STANDARD	Sorts strings in the list box alphabetically. The parent window receives an input message whenever the user clicks or double-clicks a string. The list box has borders on all sides.
LBS_USETABSTOPS	Enables a list box to recognize and expand tab characters when drawing its strings. The default tab positions are 32 dialog box units. A dialog box unit is a horizontal or vertical distance. One horizontal dialog box unit is equal to one-fourth of the current dialog box base-width unit. Windows calculates these units based on the height and width of the current system font. The GetDialogBaseUnits function returns the current dialog box base units in pixels.
LBS_WANTKEYBOARDINPUT	Specifies that the owner of the list box receives WM_VKEYTOITEM messages whenever the user presses a key and the list box has the input focus. This enables an application to perform special processing on the keyboard input.
The following scroll bar styles (in the SCROLLBAR class) can be specified in the dwStyle parameter:

Style	Meaning
SBS_BOTTOMALIGN	Aligns the bottom edge of the scroll bar with the bottom edge of the rectangle defined by the CreateWindow parameters x, y, nWidth, and nHeight. The scroll bar has the default height for system scroll bars. Use this style with the SBS_HORZ style.
SBS_HORZ	Designates a horizontal scroll bar. If neither the SBS_BOTTOMALIGN nor SBS_TOPALIGN style is specified, the scroll bar has the height, width, and position specified by the parameters of CreateWindow.
SBS_LEFTALIGN	Aligns the left edge of the scroll bar with the left edge of the rectangle defined by the parameters of CreateWindow. The scroll bar has the default width for system scroll bars. Use this style with the SBS_VERT style.
SBS_RIGHTALIGN	Aligns the right edge of the scroll bar with the right edge of the rectangle defined by the parameters of CreateWindow. The scroll bar has the default width for system scroll bars. Use this style with the SBS_VERT style.
SBS_SIZEBOX	Designates a size box. If you specify neither the SBS_SIZEBOXBOTTOMRIGHTALIGN nor the SBS_SIZEBOXTOPLEFTALIGN style, the size box has the height, width, and position specified by the parameters of CreateWindow.
SBS_SIZEBOXBOTTOMRIGHTALIGN	Aligns the lower-right corner of the size box with the lower-right corner of the rectangle specified by the parameters of CreateWindow. The size box has the default size for system size boxes. Use this style with the SBS_SIZEBOX style.
SBS_SIZEBOXTOPLEFTALIGN	Aligns the upper-left corner of the size box with the upper-left corner of the rectangle specified by the parameters of CreateWindow. The size box has the default size for system size boxes. Use this style with the SBS_SIZEBOX style.
SBS_SIZEGRIP	Windows 95 only: Same as SBS_SIZEBOX, but with a raised edge.
SBS_TOPALIGN	Aligns the top edge of the scroll bar with the top edge of the rectangle defined by the parameters of CreateWindow. The scroll bar has the default height for system scroll bars. Use this style with the SBS_HORZ style.
SBS_VERT	Designates a vertical scroll bar. If you specify neither the SBS_RIGHTALIGN nor the SBS_LEFTALIGN style, the scroll bar has the height, width, and position specified by the parameters of CreateWindow.
The following static control styles (in the STATIC class) can be specified in the dwStyle parameter. A static control can have only one of these styles:

Style	Description
SS_BITMAP	Specifies a bitmap is to be displayed in the static control. The given text is the name of a bitmap (not a filename) defined elsewhere in the resource file. The style ignores the nWidth and nHeight parameters; the control automatically sizes itself to accommodate the bitmap.
SS_BLACKFRAME	Specifies a box with a frame drawn in the same color as the window frames. This color is black in the default Windows color scheme.
SS_BLACKRECT	Specifies a rectangle filled with the current window frame color. This color is black in the default Windows color scheme.
SS_CENTER	Specifies a simple rectangle and centers the given text in the rectangle. The text is formatted before it is displayed. Words that extend past the end of a line are automatically wrapped to the beginning of the next centered line.
SS_CENTERIMAGE	Specifies that the midpoint of a static control with the SS_BITMAP or SS_ICON style is to remain fixed when the control is resized. The four sides are adjusted to accommodate a new bitmap or icon. If a static control has the SS_BITMAP style and the bitmap is smaller than the control's client area, the client area is filled with the color of the pixel in the upper-left corner of the bitmap. If a static control has the SS_ICON style, the icon does not appear to paint the client area.
SS_GRAYFRAME	Specifies a box with a frame drawn with the same color as the screen background (desktop). This color is gray in the default Windows color scheme.
SS_GRAYRECT	Specifies a rectangle filled with the current screen background color. This color is gray in the default Windows color scheme.
SS_ICON	Specifies an icon displayed in the dialog box. The given text is the name of an icon (not a filename) defined elsewhere in the resource file. The style ignores the nWidth and nHeight parameters; the icon automatically sizes itself.
SS_LEFT	Specifies a simple rectangle and left-aligns the given text in the rectangle. The text is formatted before it is displayed. Words that extend past the end of a line are automatically wrapped to the beginning of the next left-aligned line.
SS_LEFTNOWORDWRAP	Specifies a simple rectangle and left-aligns the given text in the rectangle. Tabs are expanded but words are not wrapped. Text that extends past the end of a line is clipped.
SS_METAPICT	Specifies a metafile picture is to be displayed in the static control. The given text is the name of a metafile picture (not a filename) defined elsewhere in the resource file. A metafile static control has a fixed size; the metafile picture is scaled to fit the static control's client area.
SS_NOPREFIX	Prevents interpretation of any ampersand (&) characters in the control's text as accelerator prefix characters. These are displayed with the ampersand removed and the next character in the string underlined. This static control style may be included with any of the defined static controls.
	An application can combine SS_NOPREFIX with other styles by using the bitwise OR (|) operator. This can be useful when filenames or other strings that may contain an ampersand (&) must be displayed in a static control in a dialog box.
SS_NOTIFY	Sends the parent window STN_CLICKED and STN_DBLCLK notification messages when the user clicks or double clicks the control.
SS_RIGHT	Specifies a simple rectangle and right-aligns the given text in the rectangle. The text is formatted before it is displayed. Words that extend past the end of a line are automatically wrapped to the beginning of the next right-aligned line.
SS_RIGHTIMAGE	Specifies that the bottom-right corner of a static control with the SS_BITMAP or SS_ICON style is to remain fixed when the control is resized. Only the top and left sides are adjusted to accommodate a new bitmap or icon.
SS_SIMPLE	Specifies a simple rectangle and displays a single line of left-aligned text in the rectangle. The text line cannot be shortened or altered in any way. The control's parent window or dialog box must not process the WM_CTLCOLORSTATIC message.
SS_WHITEFRAME	Specifies a box with a frame drawn with the same color as the window backgrounds. This color is white in the default Windows color scheme.
SS_WHITERECT	Specifies a rectangle filled with the current window background color. This color is white in the default Windows color scheme.
The following dialog box styles can be specified in the dwStyle parameter:

Style	Meaning
DS_3DLOOK	Windows 95 only: Gives the dialog box a nonbold font and draws three-dimensional borders around control windows in the dialog box. The DS_3DLOOK style is not required by Win32-based applications that are marked with version number 4.0 or greater; the system automatically applies the three dimensional look to dialog boxes created by these applications.
DS_ABSALIGN	Indicates that the coordinates of the dialog box are screen coordinates; otherwise, Windows assumes they are client coordinates.
DS_CENTER	Windows 95 only: Centers the dialog box in the working area; that is, the area not obscured by the tray.
DS_CENTERMOUSE	Windows 95 only: Centers the mouse cursor in the dialog box.
DS_CONTEXTHELP	Includes a question mark in the title bar of the dialog box. When the user clicks the question mark, the cursor changes to a question mark with a pointer. If the user then clicks a control in the dialog box, the control receives a WM_HELP message. The control should pass the message to the dialog procedure, which should call the WinHelp function using the HELP_WM_HELP command. The Help application displays a pop-up window that typically contains help for the control. Note that DS_CONTEXTHELP is just a placeholder. When the dialog box is created, the system checks for DS_CONTEXTHELP and, if it is there, adds WS_EX_CONTEXTHELP to the extended style of the dialog box.
DS_CONTROL	Creates a dialog box that works well as a child window of another dialog box, much like a page in a property sheet. This style allows the user to tab among the control windows of a child dialog box, use its accelerator keys, and so on.
DS_FIXEDSYS	Windows 95 only: Use SYSTEM_FIXED_FONT instead of SYSTEM_FONT.
DS_LOCALEDIT	Applies to 16-bit applications only. This style directs edit controls in the dialog box to allocate memory from the application's data segment. Otherwise, edit controls allocate storage from a global memory object.
DS_MODALFRAME	Creates a dialog box with a modal dialog-box frame that can be combined with a title bar and System menu by specifying the WS_CAPTION and WS_SYSMENU styles.
DS_NOFAILCREATE	Windows 95 only: Creates the dialog box even if errors occur — for example, if a child window cannot be created or if the system cannot create a special data segment for an edit control.
DS_NOIDLEMSG	Suppresses WM_ENTERIDLE messages that Windows would otherwise send to the owner of the dialog box while the dialog box is displayed.
DS_RECURSE	Dialog box style for control-like dialog boxes.
DS_SETFONT	Indicates that the dialog box template (the DLGTEMPLATE structure) contains two additional members specifying a font name and point size. The corresponding font is used to display text within the dialog box client area and within the dialog box controls. Windows passes the handle of the font to the dialog box and to each control by sending them the WM_SETFONT message.
DS_SETFOREGROUND	Does not apply to 16-bit versions of Microsoft Windows. This style brings the dialog box to the foreground. Internally, Windows calls the SetForegroundWindow function for the dialog box.
DS_SYSMODAL	Creates a system-modal dialog box. This style causes the dialog box to have the WS_EX_TOPMOST style, but otherwise has no effect on the dialog box or the behavior of other windows in the system when the dialog box is displayed.
Windows 95 only: The system can support a maximum of 16,364 window handles.

See Also

CharToOem, CLIENTCREATESTRUCT, CreateDialog, CREATESTRUCT, CreateWindowEx, DialogBox, DLGTEMPLATE, DRAWITEMSTRUCT, GetDialogBaseUnits, GlobalAddAtom, LB_GETTEXT, LB_SETCOLUMNWIDTH, MessageBox, RegisterClass, SetForegroundWindow, WM_COMMAND, WM_CREATE, WM_DELETEITEM, WM_DRAWITEM, WM_ENTERIDLE, WM_GETMINMAXINFO, WM_MEASUREITEM, WM_NCCREATE, WM_PAINT, WM_SETFONT, WM_SETREDRAW, WM_VKEYTOITEM


CreateWindowEx
CreateWindowEx  QuickInfo  Overview  Group

The CreateWindowEx function creates an overlapped, pop-up, or child window with an extended style; otherwise, this function is identical to the CreateWindow function. For more information about creating a window and for full descriptions of the other parameters of CreateWindowEx, see CreateWindow.

HWND CreateWindowEx(

DWORD  dwExStyle,	// extended window style
LPCTSTR  lpClassName,	// address of registered class name
LPCTSTR  lpWindowName,	// address of window name
DWORD  dwStyle,	// window style
int  x,	// horizontal position of window
int  y,	// vertical position of window
int  nWidth,	// window width
int  nHeight,	// window height
HWND  hWndParent,	// handle of parent or owner window
HMENU  hMenu,	// handle of menu, or child-window identifier
HINSTANCE  hInstance,	// handle of application instance
LPVOID  lpParam	// address of window-creation data
);
Parameters

dwExStyle

Specifies the extended style of the window. This parameter can be one of the following values:

Style	Meaning
WS_EX_ABSPOSITION	Specifies that a window has an absolute position. That is, the window does not move when the working area moves.
WS_EX_ACCEPTFILES	Specifies that a window created with this style accepts drag-drop files.
WS_EX_APPWINDOW	Windows 95 only: Forces a top-level window onto the application taskbar when the window is minimized.
WS_EX_CLIENTEDGE	Specifies that a window has a border with a sunken edge.
WS_EX_CONTEXTHELP	Includes a question mark in the title bar of the window. When the user clicks the question mark, the cursor changes to a question mark with a pointer. If the user then clicks a child window, the child receives a WM_HELP message. The child window should pass the message to the parent window procedure, which should call the WinHelp function using the HELP_WM_HELP command. The Help application displays a pop-up window that typically contains help for the child window.
WS_EX_CONTROLPARENT	Windows 95 only: Allows the user to navigate among the child windows of the window by using the TAB key.
WS_EX_DLGMODALFRAME	Creates a window that has a double border; the window can, optionally, be created with a title bar by specifying the WS_CAPTION style in the dwStyle parameter.
WS_EX_LEFT	Windows 95 only: Window has generic "left-aligned" properties. This is the default.
WS_EX_LEFTSCROLLBAR	Windows 95 only: If the shell language is Hebrew, Arabic, or another language that supports reading order alignment, the vertical scroll bar (if present) is to the left of the client area. For other languages, the style is ignored and not treated as an error.
WS_EX_LTRREADING	Windows 95 only: The window text is displayed using Left to Right reading-order properties. This is the default.
WS_EX_MDICHILD	Creates an MDI child window.
WS_EX_NOPARENTNOTIFY	Specifies that a child window created with this style does not send the WM_PARENTNOTIFY message to its parent window when it is created or destroyed.
WS_EX_OVERLAPPEDWINDOW	Windows 95 only: Combines the WS_EX_CLIENTEDGE and WS_EX_WINDOWEDGE styles.
WS_EX_PALETTEWINDOW	Windows 95 only: Combines the WS_EX_WINDOWEDGE, WS_EX_TOOLWINDOW, and WS_EX_TOPMOST styles.
WS_EX_RIGHT	Windows 95 only: Window has generic "right-aligned" properties. This depends on the window class. This style has an effect only if the shell language is Hebrew, Arabic, or another language that supports reading order alignment; otherwise, the style is ignored and not treated as an error.
WS_EX_RIGHTSCROLLBAR	Windows 95 only: Vertical scroll bar (if present) is to the right of the client area. This is the default.
WS_EX_RTLREADING	Windows 95 only: If the shell language is Hebrew, Arabic, or another language that supports reading order alignment, the window text is displayed using Right to Left reading-order properties. For other languages, the style is ignored and not treated as an error.
WS_EX_STATICEDGE	Windows 95 only: Creates a window with a three-dimensional border style intended to be used for items that do not accept user input.
WS_EX_TOOLWINDOW	Windows 95 only: Creates a tool window; that is, a window intended to be used as a floating toolbar. A tool window has a title bar that is shorter than a normal title bar, and the window title is drawn using a smaller font. A tool window does not appear in the task bar or in the window that appears when the user presses ALT+TAB.
WS_EX_TOPMOST	Specifies that a window created with this style should be placed above all non-topmost windows and should stay above them, even when the window is deactivated. To add or remove this style, use the SetWindowPos function.
WS_EX_TRANSPARENT	Specifies that a window created with this style is to be transparent. That is, any windows that are beneath the window are not obscured by the window. A window created with this style receives WM_PAINT messages only after all sibling windows beneath it have been updated.
WS_EX_WINDOWEDGE	Windows 95 only: Specifies that a window has a border with a raised edge.
Windows 95 only: Using the WS_EX_RIGHT style for static or edit controls has the same effect as using the SS_RIGHT or ES_RIGHT style, respectively. Using this style with button controls has the same effect as using BS_RIGHT and BS_RIGHTBUTTON styles.

lpClassName

Points to a null-terminated string or is an integer atom. If lpClassName is an atom, it must be a global atom created by a previous call to GlobalAddAtom. The atom, a 16-bit value less than 0xC000, must be in the low-order word of lpClassName; the high-order word must be zero.

If lpClassName is a string, it specifies the window class name. The class name can be any name registered with the RegisterClass function or any of the predefined control-class names.

lpWindowName

Points to a null-terminated string that specifies the window name.

dwStyle

Specifies the style of the window being created. For a list of the window styles that can be specified in dwStyle, see CreateWindow.

x

Specifies the initial horizontal position of the window. For an overlapped or pop-up window, the x parameter is the initial x-coordinate of the window's upper-left corner, in screen coordinates. For a child window, x is the x-coordinate of the upper-left corner of the window relative to the upper-left corner of the parent window's client area.

If x is set to CW_USEDEFAULT, Windows selects the default position for the window's upper-left corner and ignores the y parameter. CW_USEDEFAULT is valid only for overlapped windows; if it is specified for a pop-up or child window, the x and y parameters are set to zero.

y

Specifies the initial vertical position of the window. For an overlapped or pop-up window, the y parameter is the initial y-coordinate of the window's upper-left corner, in screen coordinates. For a child window, y is the initial y-coordinate of the upper-left corner of the child window relative to the upper-left corner of the parent window's client area. For a list box, y is the initial y-coordinate of the upper-left corner of the list box's client area relative to the upper-left corner of the parent window's client area.

If an overlapped window is created with the WS_VISIBLE style bit set and the x parameter is set to CW_USEDEFAULT, Windows ignores the y parameter.

nWidth

Specifies the width, in device units, of the window. For overlapped windows, nWidth is the window's width, in screen coordinates, or CW_USEDEFAULT. If nWidth is CW_USEDEFAULT, Windows selects a default width and height for the window; the default width extends from the initial x-coordinates to the right edge of the screen; the default height extends from the initial y-coordinate to the top of the icon area. CW_USEDEFAULT is valid only for overlapped windows; if CW_USEDEFAULT is specified for a pop-up or child window, the nWidth and nHeight parameter are set to zero.

nHeight

Specifies the height, in device units, of the window. For overlapped windows, nHeight is the window's height, in screen coordinates. If the nWidth parameter is set to CW_USEDEFAULT, Windows ignores nHeight.

hWndParent

Identifies the parent or owner window of the window being created. A valid window handle must be supplied when a child window or an owned window is created. A child window is confined to the client area of its parent window. An owned window is an overlapped window that is destroyed when its owner window is destroyed or hidden when its owner is minimized; it is always displayed on top of its owner window. Although this parameter must specify a valid handle if the dwStyle parameter includes the WS_CHILD style, it is optional if dwStyle includes the WS_POPUP style.

hMenu

Identifies a menu, or specifies a child-window identifier, depending on the window style. For an overlapped or pop-up window, hMenu identifies the menu to be used with the window; it can be NULL if the class menu is to be used. For a child window, hMenu specifies the child-window identifier, an integer value used by a dialog box control to notify its parent about events. The application determines the child-window identifier; it must be unique for all child windows with the same parent window.

hInstance

Identifies the instance of the module to be associated with the window.

lpParam

Points to a value passed to the window through the CREATESTRUCT structure referenced by the lParam parameter of the WM_CREATE message. If an application calls CreateWindow to create a multiple document interface client window, lpParam must point to a CLIENTCREATESTRUCT structure.

Return Value

If the function succeeds, the return value is the handle of the new window.

If the function fails, the return value is NULL.

Remarks

The CreateWindowEx function sends WM_NCCREATE, WM_NCCALCSIZE, and WM_CREATE messages to the window being created.

For information about the window control classes, window styles, and control styles used with this function, see the description of the CreateWindow function.

Windows 95 only: The system can support a maximum of 16,364 window handles.

See Also

CLIENTCREATESTRUCT, CREATESTRUCT, CreateWindow, GlobalAddAtom, RegisterClass, SetWindowPos, WM_CREATE, WM_NCCALCSIZE, WM_NCCREATE, WM_PAINT, WM_PARENTNOTIFY


CreateWindowStation [New - Windows NT]
CreateWindowStation  QuickInfo  Overview  Group

[New - Windows NT]

The CreateWindowStation function creates a window station object. It returns a handle that can be used to access the window station. A window station is a secure object that contains a set of global atoms, a clipboard, and a set of desktop objects.

HWINSTA CreateWindowStation(

LPTSTR lpwinsta,	// name of the new window station
DWORD dwReserved,	// reserved; must be NULL
DWORD dwDesiredAccess	// specifies access of returned handle
LPSECURITY_ATTRIBUTES lpsa,	// specifies security attributes of the window station
);
Parameters

lpwinsta

Optionally points to a null-terminated string specifying the name of the window station to be created. Window station names are case-insensitive and cannot contain backslash characters (\). Only members of the Administrators group are allowed to specify a name. If lpwinsta is NULL, the system forms a window station name using the logon session identifier for the calling process. To get this name, call the GetUserObjectInformation function.

dwReserved

Reserved; must be NULL.

dwDesiredAccess

Specifies the type of access to the window station. This parameter can be one or more of the following values:

Value	Description
WINSTA_ACCESSCLIPBOARD	Required to use the clipboard.
WINSTA_ACCESSGLOBALATOMS	Required to manipulate global atoms.
WINSTA_CREATEDESKTOP	Required to create new desktop objects on the window station.
WINSTA_ENUMDESKTOPS	Required to enumerate existing desktop objects.
WINSTA_ENUMERATE	Required for the window station to be enumerated.
WINSTA_EXITWINDOWS	Required to successfully call the ExitWindows or ExitWindowsEx functions.
WINSTA_READATTRIBUTES	Required to read the attributes of a window station object.
WINSTA_READSCREEN	Required to access screen contents.
WINSTA_WRITEATTRIBUTES	Required to modify the attributes of a window station object.
lpsa

Points to a SECURITY_ATTRIBUTES structure that specifies the security attributes for the window station.

If either lpsa or lpsa->lpSecurityDescriptor is NULL, the window station is assigned a security descriptor that grants GENERIC_ALL access to all users for the window station and any desktops created within the window station, and the resulting handle is not inheritable.

Return Value

If the function succeeds, the return value is the handle to the newly created window station.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

See Also

GetUserObjectInformation, OpenWindowStation


DdeAbandonTransaction
DdeAbandonTransaction  QuickInfo  Overview  Group

The DdeAbandonTransaction function abandons the specified asynchronous transaction and releases all resources associated with the transaction.

BOOL DdeAbandonTransaction(

DWORD  idInst,	// instance identifier
HCONV  hConv,	// handle of conversation
DWORD  idTransaction	// transaction identifier
);
Parameters

idInst

Specifies the application instance identifier obtained by a previous call to the DdeInitialize function.

hConv

Identifies the conversation in which the transaction was initiated. If this parameter is 0L, all transactions are abandoned (that is, the idTransaction parameter is ignored).

idTransaction

Specifies the identifier of the transaction to abandon. If this parameter is 0L, all active transactions in the specified conversation are abandoned.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Errors

The DdeGetLastError function can be used to get the error value, which may be one of the following values:

DMLERR_DLL_NOT_INITIALIZED
DMLERR_INVALIDPARAMETER
DMLERR_NO_ERROR
DMLERR_UNFOUND_QUEUE_ID

Remarks

Only a dynamic data exchange (DDE) client application should call DdeAbandonTransaction. If the server application responds to the transaction after the client has called DdeAbandonTransaction, the system discards the transaction results. This function has no effect on synchronous transactions.

See Also

DdeClientTransaction, DdeInitialize, DdeQueryConvInfo


DdeAccessData
DdeAccessData  QuickInfo  Overview  Group

The DdeAccessData function provides access to the data in the specified dynamic data exchange (DDE) object. An application must call the DdeUnaccessData function when it has finished accessing the data in the object.

LPBYTE DdeAccessData(

HDDEDATA  hData,	// handle of DDE object
LPDWORD  pcbDataSize	// address of variable that receives data length
);
Parameters

hData

Identifies the DDE object to access.

pcbDataSize

Points to a variable that receives the size, in bytes, of the DDE object identified by the hData parameter. If this parameter is NULL, no size information is returned.

Return Value

If the function succeeds, the return value is a pointer to the first byte of data in the DDE object.

If the function fails, the return value is NULL.

Errors

The DdeGetLastError function can be used to get the error value, which may be one of the following values:

DMLERR_DLL_NOT_INITIALIZED
DMLERR_INVALIDPARAMETER
DMLERR_NO_ERROR

Remarks

If the hData parameter has not been passed to a Dynamic Data Exchange Management Library (DDEML) function, an application can use the pointer returned by DdeAccessData for read-write access to the DDE object. If hData has already been passed to a DDEML function, the pointer should be used only for read access to the memory object.

See Also

DdeAddData, DdeCreateDataHandle, DdeFreeDataHandle, DdeUnaccessData


DdeAddData
DdeAddData  QuickInfo  Overview  Group

The DdeAddData function adds data to the specified dynamic data exchange (DDE) object. An application can add data starting at any offset from the beginning of the object. If new data overlaps data already in the object, the new data overwrites the old data in the bytes where the overlap occurs. The contents of locations in the object that have not been written to are undefined.

HDDEDATA DdeAddData(

HDDEDATA  hData,	// handle of DDE data object
LPBYTE  pSrc,	// address of source buffer
DWORD  cb,	// length of data
DWORD  cbOff	// offset within DDE data object
);
Parameters

hData

Identifies the DDE object that receives additional data.

pSrc

Points to a buffer containing the data to add to the DDE object.

cb

Specifies the length, in bytes, of the data to be added to the DDE object.

cbOff

Specifies an offset, in bytes, from the beginning of the DDE object. The additional data is copied to the object beginning at this offset.

Return Value

If the function succeeds, the return value is a new handle of the DDE object. The new handle is used in all references to the object.

If the function fails, the return value is zero.

Errors

The DdeGetLastError function can be used to get the error value, which may be one of the following values:

DMLERR_DLL_NOT_INITIALIZED
DMLERR_INVALIDPARAMETER
DMLERR_MEMORY_ERROR
DMLERR_NO_ERROR

Remarks

After a data handle has been used as a parameter in another Dynamic Data Exchange Management Library function or has been returned by a DDE callback function, the handle may be used only for read access to the DDE object identified by the handle.

If the amount of memory originally allocated is less than is needed to hold the added data, DdeAddData reallocates a global memory object of the appropriate size.

See Also

DdeAccessData, DdeCreateDataHandle, DdeUnaccessData


DdeCallback
DdeCallback  QuickInfo  Overview  Group

The DdeCallback function is an application-defined callback function that processes dynamic data exchange (DDE) transactions sent to the function in response to Dynamic Data Exchange Management Library (DDEML) calls by other applications.

HDDEDATA CALLBACK DdeCallback(

UINT  uType,	// transaction type
UINT  uFmt,	// clipboard data format
HCONV  hconv,	// handle of the conversation
HSZ  hsz1,	// handle of a string
HSZ  hsz2,	// handle of a string
HDDEDATA  hdata,	// handle of a global memory object
DWORD  dwData1,	// transaction-specific data
DWORD  dwData2	// transaction-specific data
);
Parameters

uType

Specifies the type of the current transaction. This parameter consists of a combination of transaction class flags and transaction type flags. The following table describes each of the transaction classes and provides a list of the transaction types in each class. For information about a specific transaction type, see the individual description of that type.

Class	Meaning
XCLASS_BOOL	A DDE callback function should return TRUE or FALSE when it finishes processing a transaction that belongs to this class. The XCLASS_BOOL transaction class consists of the following types:
	XTYP_ADVSTART XTYP_CONNECT
XCLASS_DATA	A DDE callback function should return a DDE handle, the CBR_BLOCK return code, or NULL when it finishes processing a transaction that belongs to this class. The XCLASS_DATA transaction class consists of the following types:
	XTYP_ADVREQ XTYP_REQUEST XTYP_WILDCONNECT
XCLASS_FLAGS	A DDE callback function should return DDE_FACK, DDE_FBUSY, or DDE_FNOTPROCESSED when it finishes processing a transaction that belongs to this class. The XCLASS_FLAGS transaction class consists of the following types:
	XTYP_ADVDATA XTYP_EXECUTE XTYP_POKE
XCLASS_NOTIFICATION	The transaction types that belong to this class are for notification purposes only. The return value from the callback function is ignored. The XCLASS_NOTIFICATION transaction class consists of the following types: XTYP_ADVSTOP XTYP_CONNECT_CONFIRM XTYP_DISCONNECT XTYP_ERROR XTYP_MONITOR XTYP_REGISTER XTYP_XACT_COMPLETE XTYP_UNREGISTER
uFmt

Specifies the format in which data is sent or received.

hconv

Identifies the conversation associated with the current transaction.

hsz1

Identifies a string. The meaning of this parameter depends on the type of the current transaction. For the meaning of this parameter, see the description of the transaction type.

hsz2

Identifies a string. The meaning of this parameter depends on the type of the current transaction. For the meaning of this parameter, see the description of the transaction type.

hdata

Identifies DDE data. The meaning of this parameter depends on the type of the current transaction. For the meaning of this parameter, see the description of the transaction type.

dwData1

Specifies transaction-specific data. For the meaning of this parameter, see the description of the transaction type.

dwData2

Specifies transaction-specific data. For the meaning of this parameter, see the description of the transaction type.

Return Value

The return value depends on the transaction class. For more information about the return values, see descriptions of the individual transaction types.

Remarks

The callback function is called asynchronously for transactions that do not involve the creation or termination of conversations. An application that does not frequently accept incoming messages will have reduced DDE performance because the DDEML uses messages to initiate transactions.

An application must register the callback function by specifying a pointer to the function in a call to the DdeInitialize function.

DdeCallback is a placeholder for the application-defined or library-defined function name.

See Also

DdeEnableCallback, DdeInitialize


DdeClientTransaction
DdeClientTransaction  QuickInfo  Overview  Group

The DdeClientTransaction function begins a data transaction between a client and a server. Only a dynamic data exchange (DDE) client application can call this function, and the application can use it only after establishing a conversation with the server.

HDDEDATA DdeClientTransaction(

LPBYTE  pData,	// address of data to pass to server
DWORD  cbData,	// length of data
HCONV  hConv,	// handle of conversation
HSZ  hszItem,	// handle of item name string
UINT  wFmt,	// clipboard data format
UINT  wType,	// transaction type
DWORD  dwTimeout,	// time-out duration
LPDWORD  pdwResult	// address of transaction result
);
Parameters

pData

Points to the beginning of the data the client must pass to the server.

Optionally, an application can specify the data handle (HDDEDATA) to pass to the server and in that case the cbData parameter should be set to 0xFFFFFFFF. This parameter is required only if the wType parameter is XTYP_EXECUTE or XTYP_POKE. Otherwise, this parameter should be NULL.

For the optional usage of this parameter, XTYP_POKE transactions where pData is a data handle, the handle must have been created by a previous call to the DdeCreateDataHandle function, employing the same data format specified in the wFmt parameter.

cbData

Specifies the length, in bytes, of the data pointed to by the pData parameter. A value of 0xFFFFFFFF indicates that pData is a data handle that identifies the data being sent.

hConv

Identifies the conversation in which the transaction is to take place.

hszItem

Identifies the data item for which data is being exchanged during the transaction. This handle must have been created by a previous call to the DdeCreateStringHandle function. This parameter is ignored (and should be set to 0L) if the wType parameter is XTYP_EXECUTE.

wFmt

Specifies the standard clipboard format in which the data item is being submitted or requested.

If the transaction specified by the wType parameter does not pass data or is XTYP_EXECUTE, this parameter should be zero.

If the transaction specified by the wType parameter references non-execute DDE data (XTYP_POKE, XTYP_ADVSTART, XTYP_ADVSTOP, XTYP_REQUEST), the wFmt value must be either a valid predefined (CF_) DDE format or a valid registered clipboard format.

wType

Specifies the transaction type. This parameter can be one of the following types:

Type	Meaning
XTYP_ADVSTART	Begins an advise loop. Any number of distinct advise loops can exist within a conversation. An application can alter the advise loop type by combining the XTYP_ADVSTART transaction type with one or more of the following flags:
Flag	Meaning
XTYPF_NODATA	Instructs the server to notify the client of any data changes without actually sending the data. This flag gives the client the option of ignoring the notification or requesting the changed data from the server.
XTYPF_ACKREQ	Instructs the server to wait until the client acknowledges that it received the previous data item before sending the next data item. This flag prevents a fast server from sending data faster than the client can process it.
XTYP_ADVSTOP	Ends an advise loop.
XTYP_EXECUTE	Begins an execute transaction.
XTYP_POKE	Begins a poke transaction.
XTYP_REQUEST	Begins a request transaction.
dwTimeout

Specifies the maximum length of time, in milliseconds, that the client will wait for a response from the server application in a synchronous transaction. This parameter should be TIMEOUT_ASYNC for asynchronous transactions.

pdwResult

Points to a variable that receives the result of the transaction. An application that does not check the result can use NULL for this value. For synchronous transactions, the low-order word of this variable contains any applicable DDE_ flags resulting from the transaction. This provides support for applications dependent on DDE_APPSTATUS bits. It is, however, recommended that applications no longer use these bits because they may not be supported in future versions of the Dynamic Data Exchange Management Library (DDEML). For asynchronous transactions, this variable is filled with a unique transaction identifier for use with the DdeAbandonTransaction function and the XTYP_XACT_COMPLETE transaction.

Return Value

If the function succeeds, the return value is a data handle that identifies the data for successful synchronous transactions in which the client expects data from the server. The return value is nonzero for successful asynchronous transactions and for synchronous transactions in which the client does not expect data. The return value is zero for all unsuccessful transactions.

Errors

The DdeGetLastError function can be used to get the error value, which may be one of the following values:

DMLERR_ADVACKTIMEOUT
DMLERR_BUSY
DMLERR_DATAACKTIMEOUT
DMLERR_DLL_NOT_INITIALIZED
DMLERR_EXECACKTIMEOUT
DMLERR_INVALIDPARAMETER
DMLERR_MEMORY_ERROR
DMLERR_NO_CONV_ESTABLISHED
DMLERR_NO_ERROR
DMLERR_NOTPROCESSED
DMLERR_POKEACKTIMEOUT
DMLERR_POSTMSG_FAILED
DMLERR_REENTRANCY
DMLERR_SERVER_DIED
DMLERR_UNADVACKTIMEOUT

Remarks

When an application has finished using the data handle returned by DdeClientTransaction, the application should free the handle by calling the DdeFreeDataHandle function.

Transactions can be synchronous or asynchronous. During a synchronous transaction, DdeClientTransaction does not return until the transaction either completes successfully or fails. Synchronous transactions cause a client to enter a modal loop while waiting for various asynchronous events. Because of this, a client application can still respond to user input while waiting on a synchronous transaction, but the application cannot begin a second synchronous transaction because of the activity associated with the first. DdeClientTransaction fails if any instance of the same task has a synchronous transaction already in progress.

During an asynchronous transaction, DdeClientTransaction returns after the transaction has begun, passing a transaction identifier for reference. When the server's DDE callback function finishes processing an asynchronous transaction, the system sends an XTYP_XACT_COMPLETE transaction to the client. This transaction provides the client with the results of the asynchronous transaction that it initiated by calling DdeClientTransaction. A client application can choose to abandon an asynchronous transaction by calling the DdeAbandonTransaction function.

See Also

DdeAbandonTransaction, DdeAccessData, DdeConnect, DdeConnectList, DdeCreateDataHandle, DdeCreateStringHandle, DdeFreeDataHandle, XTYP_ADVSTART, XTYP_ADVSTOP, XTYP_EXECUTE, XTYP_POKE, XTYP_REQUEST


DdeCmpStringHandles
DdeCmpStringHandles  QuickInfo  Overview  Group

The DdeCmpStringHandles function compares the values of two string handles. The value of a string handle is not related to the case of the associated string.

int DdeCmpStringHandles(

HSZ  hsz1,	// handle of first string
HSZ  hsz2	// handle of second string
);
Parameters

hsz1

Identifies the first string.

hsz2

Identifies the second string.

Return Value

The return value can be one of the following values:

Value	Meaning
−1	The value of hsz1 is either 0 or less than the value of hsz2.
0	The values of hsz1 and hsz2 are equal (both can be 0).
1	The value of hsz2 is either 0 or less than the value of hsz1.
Remarks

An application that must do a case-sensitive comparison of two string handles should compare the string handles directly. An application should use DdeCmpStringHandles for all other comparisons to preserve the case-insensitive nature of dynamic data exchange (DDE).

DdeCmpStringHandles cannot be used to sort string handles alphabetically.

See Also

DdeAccessData, DdeCreateStringHandle, DdeFreeStringHandle


DdeConnect
DdeConnect  QuickInfo  Overview  Group

The DdeConnect function establishes a conversation with a server application that supports the specified service name and topic name pair. If more than one such server exists, the system selects only one.

HCONV DdeConnect(

DWORD  idInst,	// instance identifier
HSZ  hszService,	// handle of service name string
HSZ  hszTopic,	// handle of topic name string
PCONVCONTEXT  pCC	// address of structure with context data
);
Parameters

idInst

Specifies the application instance identifier obtained by a previous call to the DdeInitialize function.

hszService

Identifies the string that specifies the service name of the server application with which a conversation is to be established. This handle must have been created by a previous call to the DdeCreateStringHandle function. If this parameter is 0L, a conversation is established with any available server.

hszTopic

Identifies the string that specifies the name of the topic on which a conversation is to be established. This handle must have been created by a previous call to DdeCreateStringHandle. If this parameter is 0L, a conversation on any topic supported by the selected server is established.

pCC

Points to the CONVCONTEXT structure that contains conversation context information. If this parameter is NULL, the server receives the default CONVCONTEXT structure during the XTYP_CONNECT or XTYP_WILDCONNECT transaction.

Return Value

If the function succeeds, the return value is the handle of the established conversation.

If the function fails, the return value is 0L.

Errors

The DdeGetLastError function can be used to get the error value, which may be one of the following values:

DMLERR_DLL_NOT_INITIALIZED
DMLERR_INVALIDPARAMETER
DMLERR_NO_CONV_ESTABLISHED
DMLERR_NO_ERROR

Remarks

The client application cannot make assumptions regarding the server selected. If an instance-specific name is specified in the hszService parameter, a conversation is established with only the specified instance. Instance-specific service names are passed to an application's dynamic data exchange (DDE) callback function during the XTYP_REGISTER and XTYP_UNREGISTER transactions.

All members of the default CONVCONTEXT structure are set to zero except cb, which specifies the size of the structure, and iCodePage, which specifies CP_WINANSI (the default code page) or CP_WINUNICODE, depending on whether the ANSI or Unicode version of the DdeInitialize function was called by the client application.

See Also

CONVCONTEXT, DdeConnectList, DdeCreateStringHandle, DdeDisconnect, DdeDisconnectList, DdeInitialize, XTYP_REGISTER, XTYP_UNREGISTER


DdeConnectList
DdeConnectList  QuickInfo  Overview  Group

The DdeConnectList function establishes a conversation with all server applications that support the specified service name and topic name pair. An application can also use this function to obtain a list of conversation handles by passing the function an existing conversation handle. The Dynamic Data Exchange Management Library removes the handles of any terminated conversations from the conversation list. The resulting conversation list contains the handles of all currently established conversations that support the specified service name and topic name.

HCONVLIST DdeConnectList(

DWORD  idInst,	// instance identifier
HSZ  hszService,	// handle of service name string
HSZ  hszTopic,	// handle of topic name string
HCONVLIST  hConvList,	// handle of conversation list
PCONVCONTEXT  pCC	// address of structure with context data
);
Parameters

idInst

Specifies the application instance identifier obtained by a previous call to the DdeInitialize function.

hszService

Identifies the string that specifies the service name of the server application with which a conversation is to be established. If this parameter is 0L, the system attempts to establish conversations with all available servers that support the specified topic name.

hszTopic

Identifies the string that specifies the name of the topic on which a conversation is to be established. This handle must have been created by a previous call to the DdeCreateStringHandle function. If this parameter is 0L, the system will attempt to establish conversations on all topics supported by the selected server (or servers).

hConvList

Identifies the conversation list to be enumerated. This parameter should be 0L if a new conversation list is to be established.

pCC

Points to the CONVCONTEXT structure that contains conversation-context information. If this parameter is NULL, the server receives the default CONVCONTEXT structure during the XTYP_CONNECT or XTYP_WILDCONNECT transaction.

Return Value

If the function succeeds, the return value is the handle of a new conversation list.

If the function fails, the return value is 0L. The handle of the old conversation list is no longer valid.

Errors

The DdeGetLastError function can be used to get the error value, which may be one of the following values:

DMLERR_DLL_NOT_INITIALIZED
DMLERR_INVALID_PARAMETER
DMLERR_NO_CONV_ESTABLISHED
DMLERR_NO_ERROR
DMLERR_SYS_ERROR

Remarks

An application must free the conversation list handle returned by this function, regardless of whether any conversation handles within the list are active. To free the handle, an application can call the DdeDisconnectList function.

All members of the default CONVCONTEXT structure are set to zero except cb, specifying the size of the structure, and iCodePage, specifying CP_WINANSI (the default code page) or CP_WINUNICODE, depending on whether the ANSI or Unicode version of the DdeInitialize function was called by the client application.

See Also

CONVCONTEXT, DdeConnect, DdeCreateStringHandle, DdeDisconnect, DdeDisconnectList, DdeInitialize, DdeQueryNextServer


DdeCreateDataHandle
DdeCreateDataHandle  QuickInfo  Overview  Group

The DdeCreateDataHandle function creates a dynamic data exchange (DDE) object and fills the object with data from the specified buffer. A DDE application uses this function during transactions that involve passing data to the partner application.

HDDEDATA DdeCreateDataHandle(

DWORD  idInst,	// instance identifier
LPBYTE  pSrc,	// address of source buffer
DWORD  cb,	// length of DDE object
DWORD  cbOff,	// offset from beginning of source buffer
HSZ  hszItem,	// handle of item name string
UINT  wFmt,	// clipboard data format
UINT  afCmd	// creation flags
);
Parameters

idInst

Specifies the application instance identifier obtained by a previous call to the DdeInitialize function.

pSrc

Points to a buffer that contains data to be copied to the DDE object. If this parameter is NULL, no data is copied to the object.

cb

Specifies the amount of memory, in bytes, to allocate for the DDE object. If this parameter is zero, the pSrc parameter is ignored.

cbOff

Specifies an offset, in bytes, from the beginning of the buffer pointed to by the pSrc parameter. The data beginning at this offset is copied from the buffer to the DDE object.

hszItem

Identifies the string that specifies the data item corresponding to the DDE object. This handle must have been created by a previous call to the DdeCreateStringHandle function. If the data handle is to be used in an XTYP_EXECUTE transaction, this parameter must be 0L.

wFmt

Specifies the standard clipboard format of the data.

afCmd

Specifies the creation flags. This parameter can be HDATA_APPOWNED, which specifies that the server application calling the DdeCreateDataHandle function owns the data handle this function creates. This flag enables the application to share the data handle with other Dynamic Data Exchange Management Library (DDEML) applications rather than creating a separate handle to pass to each application. If this flag is specified, the application must eventually free the shared memory object associated with the handle by using the DdeFreeDataHandle function. If this flag is not specified, the handle becomes invalid in the application that created the handle after the data handle is returned by the application's DDE callback function or is used as a parameter in another DDEML function.

Return Value

If the function succeeds, the return value is a data handle.

If the function fails, the return value is 0L.

Errors

The DdeGetLastError function can be used to get the error value, which may be one of the following values:

DMLERR_DLL_NOT_INITIALIZED
DMLERR_INVALIDPARAMETER
DMLERR_MEMORY_ERROR
DMLERR_NO_ERROR

Remarks

Any unfilled locations in the DDE object are undefined.

After a data handle has been used as a parameter in another DDEML function or has been returned by a DDE callback function, the handle may be used only for read access to the DDE object identified by the handle.

See Also

DdeAccessData, DdeCreateStringHandle, DdeFreeDataHandle, DdeGetData, DdeInitialize


DdeCreateStringHandle
DdeCreateStringHandle  QuickInfo  Overview  Group

The DdeCreateStringHandle function creates a handle that identifies the string pointed to by the psz parameter. A dynamic data exchange (DDE) client or server application can pass the string handle as a parameter to other Dynamic Data Exchange Management Library (DDEML) functions.

HSZ DdeCreateStringHandle(

DWORD  idInst,	// instance identifier
LPTSTR  psz,	// address of null-terminated string
int  iCodePage	// code page identifier
);
Parameters

idInst

Specifies the application instance identifier obtained by a previous call to the DdeInitialize function.

psz

Points to a buffer that contains the null-terminated string for which a handle is to be created. This string may be of any length.

iCodePage

Specifies the code page used to render the string. This value should be either CP_WINANSI (the default code page) or CP_WINUNICODE, depending on whether the ANSI or Unicode version of DdeInitialize was called by the client application.

Return Value

If the function succeeds, the return value is a string handle.

If the function fails, the return value is 0L.

Errors

The DdeGetLastError function can be used to get the error value, which may be one of the following values:

DMLERR_INVALIDPARAMETER
DMLERR_NO_ERROR
DMLERR_SYS_ERROR

Remarks

The value of a string handle is not related to the case of the string it identifies.

When an application either creates a string handle or receives one in the callback function and then uses the DdeKeepStringHandle function to keep it, the application must free that string handle when it is no longer needed.

An instance-specific string handle cannot be mapped from string handle to string and back to string handle. This is shown in the following example, in which the DdeQueryString function creates a string from a string handle and DdeCreateStringHandle creates a string handle from that string, but the two handles are not the same:

DWORD idInst;

DWORD cb;

HSZ hszInst, hszNew;

PSZ pszInst;

DdeQueryString(idInst, hszInst, pszInst, cb, CP_WINANSI);

hszNew = DdeCreateStringHandle(idInst, pszInst, CP_WINANSI);

// hszNew != hszInst !

See Also

DdeAccessData, DdeCmpStringHandles, DdeFreeStringHandle, DdeInitialize, DdeKeepStringHandle, DdeQueryString


DdeDisconnect
DdeDisconnect  QuickInfo  Overview  Group

The DdeDisconnect function terminates a conversation started by either the DdeConnect or DdeConnectList function and invalidates the specified conversation handle.

BOOL DdeDisconnect(

HCONV  hConv	// handle of conversation
);
Parameters

hConv

Identifies the active conversation to be terminated.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Errors

The DdeGetLastError function can be used to get the error value, which may be one of the following values:

DMLERR_DLL_NOT_INITIALIZED
DMLERR_NO_CONV_ESTABLISHED
DMLERR_NO_ERROR

Remarks

Any incomplete transactions started before calling DdeDisconnect are immediately abandoned. The XTYP_DISCONNECT transaction is sent to the dynamic data exchange (DDE) callback function of the partner in the conversation. Generally, only client applications must terminate conversations.

See Also

DdeConnect, DdeConnectList, DdeDisconnectList, XTYP_DISCONNECT


DdeDisconnectList
DdeDisconnectList  QuickInfo  Overview  Group

The DdeDisconnectList function destroys the specified conversation list and terminates all conversations associated with the list.

BOOL DdeDisconnectList(

HCONVLIST  hConvList	// handle of conversation list
);
Parameters

hConvList

Identifies the conversation list. This handle must have been created by a previous call to the DdeConnectList function.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Errors

The DdeGetLastError function can be used to get the error value, which may be one of the following values:

DMLERR_DLL_NOT_INITIALIZED
DMLERR_INVALIDPARAMETER
DMLERR_NO_ERROR

Remarks

An application can use the DdeDisconnect function to terminate individual conversations in the list.

See Also

DdeConnect, DdeConnectList, DdeDisconnect


DdeEnableCallback
DdeEnableCallback  QuickInfo  Overview  Group

The DdeEnableCallback function enables or disables transactions for a specific conversation or for all conversations currently established by the calling application.

After disabling transactions for a conversation, the operating system places the transactions for that conversation in a transaction queue associated with the application. The application should reenable the conversation as soon as possible to avoid losing queued transactions.

BOOL DdeEnableCallback(

DWORD  idInst,	// instance identifier
HCONV  hConv,	// handle of conversation
UINT  wCmd	// enable or disable function code
);
Parameters

idInst

Specifies the application-instance identifier obtained by a previous call to the DdeInitialize function.

hConv

Identifies the conversation to enable or disable. If this parameter is NULL, the function affects all conversations.

wCmd

Specifies the function code. This parameter can be one of the following values:

Value	Meaning
EC_ENABLEALL	Enables all transactions for the specified conversation.
EC_ENABLEONE	Enables one transaction for the specified conversation.
EC_DISABLE	Disables all blockable transactions for the specified conversation. A server application can disable the following transactions: XTYP_ADVSTART XTYP_ADVSTOP XTYP_EXECUTE XTYP_POKE XTYP_REQUEST A client application can disable the following transactions: XTYP_ADVDATA XTYP_XACT_COMPLETE
EC_QUERYWAITING	Determines whether any transactions are in the queue for the specified conversation.
Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

If the wCmd parameter is EC_QUERYWAITING, and the application transaction queue contains one or more unprocessed transactions that are not being processed, the return value is TRUE; otherwise, it is FALSE.

Errors

Use the DdeGetLastError function to retrieve the error value, which may be one of the following:

DMLERR_DLL_NOT_INITIALIZED
DMLERR_NO_ERROR
DMLERR_INVALIDPARAMETER

Remarks

An application can disable transactions for a specific conversation by returning the CBR_BLOCK return code from its dynamic data exchange (DDE) callback function. When you reenable the conversation by using the DdeEnableCallback function, the operating system generates the same transaction that was in process when the conversation was disabled.

Using the EC_QUERYWAITING flag does not change the enable state of the conversation and does not cause transactions to be issued within the context of the call to DdeEnableCallback.

If DdeEnableCallback is called with EC_QUERYWAITING and the return value is TRUE, an application should try to quickly allow message processing, return from its callback, or enable callbacks. Such a result does not guarantee that subsequent callbacks will be made. Calling DdeEnableCallback with EC_QUERYWAITING lets an application with blocked callbacks determine whether there are any transactions pending on the blocked conversation. Of course, even if such a call returns false, an application should always process messages in a timely manner.

See Also

DdeConnect, DdeConnectList, DdeDisconnect, DdeInitialize


DdeFreeDataHandle
DdeFreeDataHandle  QuickInfo  Overview  Group

The DdeFreeDataHandle function frees a dynamic data exchange (DDE) object and deletes the data handle associated with the object.

BOOL DdeFreeDataHandle(

HDDEDATA  hData	// handle of DDE object
);
Parameters

hData

Identifies the DDE object to be freed. This handle must have been created by a previous call to the DdeCreateDataHandle function or returned by the DdeClientTransaction function.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Errors

The DdeGetLastError function can be used to get the error value, which may be one of the following values:

DMLERR_INVALIDPARAMETER
DMLERR_NO_ERROR

Remarks

An application must call DdeFreeDataHandle under the following circumstances:

•	To free a DDE object that the application allocated by calling the DdeCreateDataHandle function if the object's data handle was never passed by the application to another Dynamic Data Exchange Management Library (DDEML) function

•	To free a DDE object that the application allocated by specifying the HDATA_APPOWNED flag in a call to DdeCreateDataHandle

•	To free a DDE object whose handle the application received from the DdeClientTransaction function

The system automatically frees an unowned object when its handle is returned by a DDE callback function or is used as a parameter in a DDEML function.

See Also

DdeAccessData, DdeCreateDataHandle, DdeClientTransaction


DdeFreeStringHandle
DdeFreeStringHandle  QuickInfo  Overview  Group

The DdeFreeStringHandle function frees a string handle in the calling application.

BOOL DdeFreeStringHandle(

DWORD  idInst,	// instance identifier
HSZ  hsz	// handle of string
);
Parameters

idInst

Specifies the application instance identifier obtained by a previous call to the DdeInitialize function.

hsz

Identifies the string handle to be freed. This handle must have been created by a previous call to the DdeCreateStringHandle function.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

An application can free string handles it creates with DdeCreateStringHandle but should not free those that the system passed to the application's dynamic data exchange (DDE) callback function or those returned in the CONVINFO structure by the DdeQueryConvInfo function.

See Also

CONVINFO, DdeCmpStringHandles, DdeCreateStringHandle, DdeInitialize, DdeKeepStringHandle, DdeQueryConvInfo, DdeQueryString


DdeGetData
DdeGetData  QuickInfo  Overview  Group

The DdeGetData function copies data from the specified dynamic data exchange (DDE) object to the specified local buffer.

DWORD DdeGetData(

HDDEDATA  hData,	// handle of DDE  object
LPBYTE  pDst,	// address of destination buffer
DWORD  cbMax,	// amount of data to copy
DWORD  cbOff	// offset to beginning of data
);
Parameters

hData

Identifies the DDE object that contains the data to copy.

pDst

Points to the buffer that receives the data. If this parameter is NULL, the DdeGetData function returns the amount of data, in bytes, that would be copied to the buffer.

cbMax

Specifies the maximum amount of data, in bytes, to copy to the buffer pointed to by the pDst parameter. Typically, this parameter specifies the length of the buffer pointed to by pDst.

cbOff

Specifies an offset within the DDE object. Data is copied from the object beginning at this offset.

Return Value

If the pDst parameter points to a buffer, the return value is the size, in bytes, of the memory object associated with the data handle or the size specified in the cbMax parameter, whichever is lower.

If the pDst parameter is NULL, the return value is the size, in bytes, of the memory object associated with the data handle.

Errors

The DdeGetLastError function can be used to get the error value, which may be one of the following values:

DMLERR_DLL_NOT_INITIALIZED
DMLERR_INVALIDPARAMETER
DMLERR_NO_ERROR

See Also

DdeAccessData, DdeCreateDataHandle, DdeFreeDataHandle


DdeGetLastError
DdeGetLastError  QuickInfo  Overview  Group

The DdeGetLastError function returns the most recent error value set by the failure of a Dynamic Data Exchange Management Library (DDEML) function and resets the error value to DMLERR_NO_ERROR.

UINT DdeGetLastError(

DWORD  idInst	// instance identifier
);
Parameters

idInst

Specifies the application instance identifier obtained by a previous call to the DdeInitialize function.

Return Value

If the function succeeds, the return value is the last error value. Following are the possible DDEML error values:

Value	Meaning
DMLERR_ADVACKTIMEOUT	A request for a synchronous advise transaction has timed out.
DMLERR_BUSY	The response to the transaction caused the DDE_FBUSY flag to be set.
DMLERR_DATAACKTIMEOUT	A request for a synchronous data transaction has timed out.
DMLERR_DLL_NOT_INITIALIZED	A DDEML function was called without first calling the DdeInitialize function, or an invalid instance identifier was passed to a DDEML function.
DMLERR_DLL_USAGE	An application initialized as APPCLASS_MONITOR has attempted to perform a dynamic data exchange (DDE) transaction, or an application initialized as APPCMD_CLIENTONLY has attempted to perform server transactions.
DMLERR_EXECACKTIMEOUT	A request for a synchronous execute transaction has timed out.
DMLERR_INVALIDPARAMETER	A parameter failed to be validated by the DDEML. Some of the possible causes follow:
	The application used a data handle initialized with a different item name handle than was required by the transaction. The application used a data handle that was initialized with a different clipboard data format than was required by the transaction. The application used a client-side conversation handle with a server-side function or vice versa. The application used a freed data handle or string handle. More than one instance of the application used the same object.
DMLERR_LOW_MEMORY	A DDEML application has created a prolonged race condition (in which the server application outruns the client), causing large amounts of memory to be consumed.
DMLERR_MEMORY_ERROR	A memory allocation has failed.
DMLERR_NO_CONV_ESTABLISHED	A client's attempt to establish a conversation has failed.
DMLERR_NOTPROCESSED	A transaction has failed.
DMLERR_POKEACKTIMEOUT	A request for a synchronous poke transaction has timed out.
DMLERR_POSTMSG_FAILED	An internal call to the PostMessage function has failed.
DMLERR_REENTRANCY	An application instance with a synchronous transaction already in progress attempted to initiate another synchronous transaction, or the DdeEnableCallback function was called from within a DDEML callback function.
DMLERR_SERVER_DIED	A server-side transaction was attempted on a conversation terminated by the client, or the server terminated before completing a transaction.
DMLERR_SYS_ERROR	An internal error has occurred in the DDEML.
DMLERR_UNADVACKTIMEOUT	A request to end an advise transaction has timed out.
DMLERR_UNFOUND_QUEUE_ID	An invalid transaction identifier was passed to a DDEML function. Once the application has returned from an XTYP_XACT_COMPLETE callback, the transaction identifier for that callback function  is no longer valid.
See Also

DdeEnableCallback, DdeInitialize, PostMessage


DdeImpersonateClient
DdeImpersonateClient  QuickInfo  Overview  Group

The DdeImpersonateClient function impersonates a dynamic data exchange (DDE) client application in a DDE client conversation.

BOOL DdeImpersonateClient(

HCONV  hConv	// handle of DDE conversation
);
Parameters

hConv

Identifies the DDE client conversation to be impersonated.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Impersonation is the ability of a process to take on the security attributes of another process. When a client in a DDE conversation requests information from a DDE server, the server impersonates the client. When the server requests access to an object, the system verifies the access against the client's security attributes.

When the impersonation is complete, the server normally calls the RevertToSelf function.

See Also

ImpersonateNamedPipeClient, RevertToSelf


DdeInitialize
DdeInitialize  QuickInfo  Overview  Group

The DdeInitialize function registers an application with the Dynamic Data Exchange Management Library (DDEML). An application must call this function before calling any other DDEML function.

UINT DdeInitialize(

LPDWORD  pidInst,	// address of instance identifier
PFNCALLBACK  pfnCallback,	// address of callback function
DWORD  afCmd,	// set of command and filter flags
DWORD  ulRes	// reserved
);
Parameters

pidInst

Points to the application instance identifier. At initialization, this parameter should point to 0. If the function succeeds, this parameter points to the instance identifier for the application. This value should be passed as the idInst parameter in all other DDEML functions that require it. If an application uses multiple instances of the DDEML dynamic-link library (DLL), the application should provide a different callback function for each instance.

If pidInst points to a nonzero value, reinitialization of the DDEML is implied. In this case, pidInst must point to a valid application-instance identifier.

pfnCallback

Points to the application-defined dynamic data exchange (DDE) callback function. This function processes DDE transactions sent by the system. For more information, see the DdeCallback callback function.

afCmd

Specifies a set of APPCMD_, CBF_, and MF_ flags. The APPCMD_ flags provide special instructions to DdeInitialize. The CBF_ flags specify filters that prevent specific types of transactions from reaching the callback function. The MF_ flags specify the types of DDE activity that a DDE monitoring application monitors. Using these flags enhances the performance of a DDE application by eliminating unnecessary calls to the callback function.

This parameter can be a combination of the following filter flags:

Flag	Meaning
APPCLASS_MONITOR	Makes it possible for the application to monitor DDE activity in the system. This flag is for use by DDE monitoring applications. The application specifies the types of DDE activity to monitor by combining one or more monitor flags with the APPCLASS_MONITOR flag. For details, see the following Remarks section.
APPCLASS_STANDARD	Registers the application as a standard (nonmonitoring) DDEML application.
APPCMD_CLIENTONLY	Prevents the application from becoming a server in a DDE conversation. The application can only be a client. This flag reduces consumption of resources by the DDEML. It includes the functionality of the CBF_FAIL_ALLSVRXACTIONS flag.
APPCMD_FILTERINITS	Prevents the DDEML from sending XTYP_CONNECT and XTYP_WILDCONNECT transactions to the application until the application has created its string handles and registered its service names or has turned off filtering by a subsequent call to the DdeNameService or DdeInitialize function. This flag is always in effect when an application calls DdeInitialize for the first time, regardless of whether the application specifies the flag. On subsequent calls to DdeInitialize, not specifying this flag turns off the application's service-name filters, but specifying it turns on the application's service name filters.
CBF_FAIL_ALLSVRXACTIONS	Prevents the callback function from receiving server transactions. The system returns DDE_FNOTPROCESSED to each client that sends a transaction to this application. This flag is equivalent to combining all CBF_FAIL_ flags.
CBF_FAIL_ADVISES	Prevents the callback function from receiving XTYP_ADVSTART and XTYP_ADVSTOP transactions. The system returns DDE_FNOTPROCESSED to each client that sends an XTYP_ADVSTART or XTYP_ADVSTOP transaction to the server.
CBF_FAIL_CONNECTIONS	Prevents the callback function from receiving XTYP_CONNECT and XTYP_WILDCONNECT transactions.
CBF_FAIL_EXECUTES	Prevents the callback function from receiving XTYP_EXECUTE transactions. The system returns DDE_FNOTPROCESSED to a client that sends an XTYP_EXECUTE transaction to the server.
CBF_FAIL_POKES	Prevents the callback function from receiving XTYP_POKE transactions. The system returns DDE_FNOTPROCESSED to a client that sends an XTYP_POKE transaction to the server.
CBF_FAIL_REQUESTS	Prevents the callback function from receiving XTYP_REQUEST transactions. The system returns DDE_FNOTPROCESSED to a client that sends an XTYP_REQUEST transaction to the server.
CBF_FAIL_SELFCONNECTIONS	Prevents the callback function from receiving XTYP_CONNECT transactions from the application's own instance. This flag prevents an application from establishing a DDE conversation with its own instance. An application should use this flag if it needs to communicate with other instances of itself but not with itself.
CBF_SKIP_ALLNOTIFICATIONS	Prevents the callback function from receiving any notifications. This flag is equivalent to combining all CBF_SKIP_ flags.
CBF_SKIP_CONNECT_CONFIRMS	Prevents the callback function from receiving XTYP_CONNECT_CONFIRM notifications.
CBF_SKIP_DISCONNECTS	Prevents the callback function from receiving XTYP_DISCONNECT notifications.
CBF_SKIP_REGISTRATIONS	Prevents the callback function from receiving XTYP_REGISTER notifications.
CBF_SKIP_UNREGISTRATIONS	Prevents the callback function from receiving XTYP_UNREGISTER notifications.
MF_CALLBACKS	Notifies the callback function whenever a transaction is sent to any DDE callback function in the system.
MF_CONV	Notifies the callback function whenever a conversation is established or terminated.
MF_ERRORS	Notifies the callback function whenever a DDE error occurs.
MF_HSZ_INFO	Notifies the callback function whenever a DDE application creates, frees, or increments the usage count of a string handle or whenever a string handle is freed as a result of a call to the DdeUninitialize function.
MF_LINKS	Notifies the callback function whenever an advise loop is started or ended.
MF_POSTMSGS	Notifies the callback function whenever the system or an application posts a DDE message.
MF_SENDMSGS	Notifies the callback function whenever the system or an application sends a DDE message.
ulRes

Reserved; must be set to zero.

Return Value

If the function succeeds, the return value is DMLERR_NO_ERROR.

If the function fails, the return value is one of the following values:

DMLERR_DLL_USAGE
DMLERR_INVALIDPARAMETER
DMLERR_SYS_ERROR

Remarks

An application that uses multiple instances of the DDEML must not pass DDEML objects between instances.

A DDE monitoring application should not attempt to perform DDE operations (establish conversations, issue transactions, and so on) within the context of the same application instance.

A synchronous transaction fails with a DMLERR_REENTRANCY error if any instance of the same task has a synchronous transaction already in progress.

The CBF_FAIL_ALLSVRACTIONS flag causes the DDEML to filter all server transactions and can be changed by a subsequent call to DdeInitialize. The APPCMD_CLIENTONLY flag prevents the DDEML from creating key resources for the server and cannot be changed by a subsequent call to DdeInitialize.

There is an ANSI version and a Unicode version of this function. The version called determines the type of the window procedures used to control DDE conversations (ANSI or Unicode), and the default value for the iCodePage member of the CONVCONTXT structure (CP_WINANSI or CP_WINUNICODE).

See Also

DdeClientTransaction, DdeConnect, DdeCreateDataHandle, DdeEnableCallback, DdeNameService, DdePostAdvise, DdeUninitialize XTYP_ADVSTART, XTYP_ADVSTOP, XTYP_CONNECT, XTYP_CONNECT_CONFIRM, XTYP_DISCONNECT, XTYP_EXECUTE, XTYP_POKE, XTYP_REGISTER, XTYP_REQUEST, XTYP_WILDCONNECT


DdeKeepStringHandle
DdeKeepStringHandle  QuickInfo  Overview  Group

The DdeKeepStringHandle function increments the usage count associated with the specified handle. This function enables an application to save a string handle passed to the application's dynamic data exchange (DDE) callback function. Otherwise, a string handle passed to the callback function is deleted when the callback function returns. This function should also be used to keep a copy of a string handle referenced by the CONVINFO structure returned by the DdeQueryConvInfo function.

BOOL DdeKeepStringHandle(

DWORD  idInst,	// instance identifier
HSZ  hsz	// handle of string
);
Parameters

idInst

Specifies the application instance identifier obtained by a previous call to the DdeInitialize function.

hsz

Identifies the string handle to be saved.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

See Also

CONVINFO, DdeCreateStringHandle, DdeFreeStringHandle, DdeInitialize, DdeQueryConvInfo, DdeQueryString


DdeNameService
DdeNameService  QuickInfo  Overview  Group

The DdeNameService function registers or unregisters the service names a dynamic data exchange (DDE) server supports. This function causes the system to send XTYP_REGISTER or XTYP_UNREGISTER transactions to other running Dynamic Data Exchange Management Library (DDEML) client applications.

A server application should call this function to register each service name that it supports and to unregister names it previously registered but no longer supports. A server should also call this function to unregister its service names just before terminating.

HDDEDATA DdeNameService(

DWORD  idInst,	// instance identifier
HSZ  hsz1,	// handle of service name string
HSZ  hsz2,	// reserved
UINT  afCmd	// service name flags
);
Parameters

idInst

Specifies the application instance identifier obtained by a previous call to the DdeInitialize function.

hsz1

Identifies the string that specifies the service name the server is registering or unregistering. An application that is unregistering all of its service names should set this parameter to 0L.

hsz2

Reserved; should be set to 0L.

afCmd

Specifies the service name flags. This parameter can be one of the following flags:

Flag	Meaning
DNS_REGISTER	Registers the given service name.
DNS_UNREGISTER	Unregisters the given service name. If the hsz1 parameter is 0L, all service names registered by the server will be unregistered.
DNS_FILTERON	Turns on service name initiation filtering. The filter prevents a server from receiving XTYP_CONNECT transactions for service names it has not registered. This is the default setting for this filter.
	If a server application does not register any service names, the application cannot receive XTYP_WILDCONNECT transactions.
DNS_FILTEROFF	Turns off service name initiation filtering. If this flag is specified, the server receives an XTYP_CONNECT transaction whenever another DDE application calls the DdeConnect function, regardless of the service name.
Return Value

If the funcion succeeds, it returns a nonzero value. That value is not a true HDDEDATA value, merely a Boolean indicator of success. The function is typed HDDEDATA to allow for possible future expansion of the function and a more sophisticated return value.

If the function fails, the return value is 0L.

Errors

The DdeGetLastError function can be used to get the error value, which may be one of the following values:

DMLERR_DLL_NOT_INITIALIZED
DMLERR_DLL_USAGE
DMLERR_INVALIDPARAMETER
DMLERR_NO_ERROR

Remarks

The service name identified by the hsz1 parameter should be a base name (that is, the name should contain no instance-specific information). The system generates an instance-specific name and sends it along with the base name during the XTYP_REGISTER and XTYP_UNREGISTER transactions. The receiving applications can then connect to the specific application instance.

See Also

DdeConnect, DdeConnectList, DdeInitialize, XTYP_REGISTER, XTYP_UNREGISTER


DdePostAdvise
DdePostAdvise  QuickInfo  Overview  Group

The DdePostAdvise function causes the system to send an XTYP_ADVREQ transaction to the calling (server) application's dynamic data exchange (DDE) callback function for each client with an active advise loop on the specified topic and item. A server application should call this function whenever the data associated with the topic name or item name pair changes.

BOOL DdePostAdvise(

DWORD  idInst,	// instance identifier
HSZ  hszTopic,	// handle of topic name string
HSZ  hszItem	// handle of item name string
);
Parameters

idInst

Specifies the application instance identifier obtained by a previous call to the DdeInitialize function.

hszTopic

Identifies a string that specifies the topic name. To send notifications for all topics with active advise loops, an application can set this parameter to 0L.

hszItem

Identifies a string that specifies the item name. To send notifications for all items with active advise loops, an application can set this parameter to 0L.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Errors

The DdeGetLastError function can be used to get the error value, which may be one of the following values:

DMLERR_DLL_NOT_INITIALIZED
DMLERR_DLL_USAGE
DMLERR_NO_ERROR

Remarks

A server that has nonenumerable topics or items should set the hszTopic and hszItem parameters to NULL so that the system generates transactions for all active advise loops. The server's DDE callback function returns NULL for any advise loops that must not be updated.

If a server calls DdePostAdvise with a topic, item, and format name set that includes the set currently being handled in an XTYP_ADVREQ callback, a stack overflow may result.

See Also

DdeInitialize, XTYP_ADVREQ


DdeQueryConvInfo
DdeQueryConvInfo  QuickInfo  Overview  Group

The DdeQueryConvInfo function obtains information about a dynamic data exchange (DDE) transaction and about the conversation in which the transaction takes place.

UINT DdeQueryConvInfo(

HCONV  hConv,	// handle of conversation
DWORD  idTransaction,	// transaction identifier
PCONVINFO  pConvInfo	// address of structure with conversation data
);
Parameters

hConv

Identifies the conversation.

idTransaction

Specifies the transaction. For asynchronous transactions, this parameter should be a transaction identifier returned by the DdeClientTransaction function. For synchronous transactions, this parameter should be QID_SYNC.

pConvInfo

Points to the CONVINFO structure that receives information about the transaction and conversation. The cb member of the CONVINFO structure must specify the length of the buffer allocated for the structure.

Return Value

If the function succeeds, the return value is the number of bytes copied into the CONVINFO structure.

If the function fails, the return value is FALSE.

Errors

The DdeGetLastError function can be used to get the error value, which may be one of the following values:

DMLERR_DLL_NOT_INITIALIZED
DMLERR_NO_CONV_ESTABLISHED
DMLERR_NO_ERROR
DMLERR_UNFOUND_QUEUE_ID

Remarks

An application should not free a string handle referenced by the CONVINFO structure. If an application must use one of these string handles, it should call the DdeKeepStringHandle function to create a copy of the handle.

If the idTransaction parameter is set to QID_SYNC, the hUser member of the CONVINFO structure is associated with the conversation and can be used to hold data associated with the conversation. If idTransaction is the identifier of an asynchronous transaction, the hUser member is associated only with the current transaction and is valid only for the duration of the transaction.

See Also

CONVINFO, DdeClientTransaction, DdeConnect, DdeConnectList, DdeKeepStringHandle, DdeQueryNextServer


DdeQueryNextServer
DdeQueryNextServer  QuickInfo  Overview  Group

The DdeQueryNextServer function obtains the next conversation handle in the specified conversation list.

HCONV DdeQueryNextServer(

HCONVLIST  hConvList,	// handle of conversation list
HCONV  hConvPrev	// previous conversation handle
);
Parameters

hConvList

Identifies the conversation list. This handle must have been created by a previous call to the DdeConnectList function.

hConvPrev

Identifies the conversation handle previously returned by this function. If this parameter is 0L, the function returns the first conversation handle in the list.

Return Value

If the list contains any more conversation handles, the return value is the next conversation handle in the list; otherwise, it is 0L.

See Also

DdeConnectList, DdeDisconnectList


DdeQueryString
DdeQueryString  QuickInfo  Overview  Group

The DdeQueryString function copies text associated with a string handle into a buffer.

DWORD DdeQueryString(

DWORD  idInst,	// instance identifier
HSZ  hsz,	// handle of string
LPTSTR  psz,	// address of destination buffer
DWORD  cchMax,	// length of buffer
int  iCodePage	// code page identifier
);
Parameters

idInst

Specifies the application instance identifier obtained by a previous call to the DdeInitialize function.

hsz

Identifies the string to copy. This handle must have been created by a previous call to the DdeCreateStringHandle function.

psz

Points to a buffer that receives the string. To obtain the length of the string, this parameter should be set to NULL.

cchMax

Specifies the length, in characters, of the buffer pointed to by the psz parameter. If the string is longer than (cchMax − 1), it will be truncated. If the psz parameter is set to NULL, this parameter is ignored.

iCodePage

Specifies the code page used to render the string. This value should be either CP_WINANSI or CP_WINUNICODE.

Return Value

If the psz parameter specified a valid pointer, the return value is the length, in characters, of the returned text (not including the terminating null character). If the psz parameter specified a NULL pointer, the return value is the length of the text associated with the hsz parameter (not including the terminating null character). If an error occurs, the return value is 0L.

Remarks

The string returned in the buffer is always null-terminated. If the string is longer than (cchMax − 1), only the first (cchMax − 1) characters of the string are copied.

If the psz parameter is NULL, this function obtains the length, in bytes, of the string associated with the string handle. The length does not include the terminating null character.

See Also

DdeCmpStringHandles, DdeCreateStringHandle, DdeFreeStringHandle, DdeInitialize


DdeReconnect
DdeReconnect  QuickInfo  Overview  Group

The DdeReconnect function allows a client Dynamic Data Exchange Management Library (DDEML) application to attempt to reestablish a conversation with a service that has terminated a conversation with the client. When the conversation is reestablished, the DDEML attempts to reestablish any preexisting advise loops.

HCONV DdeReconnect(

HCONV  hConv	// handle of conversation to reestablish
);
Parameters

hConv

Identifies the conversation to be reestablished. A client must have obtained the conversation handle by a previous call to the DdeConnect function or from an XTYP_DISCONNECT transaction.

Return Value

If the function succeeds, the return value is the handle of the reestablished conversation.

If the function fails, the return value is 0L.

Errors

The DdeGetLastError function can be used to get the error value, which may be one of the following values:

DMLERR_DLL_NOT_INITIALIZED
DMLERR_INVALIDPARAMETER
DMLERR_NO_CONV_ESTABLISHED
DMLERR_NO_ERROR

See Also

DdeConnect, DdeDisconnect


DdeSetQualityOfService
DdeSetQualityOfService  QuickInfo  Overview  Group

The DdeSetQualityOfService function specifies the quality of service a raw DDE application desires for future DDE conversations it initiates. The specified quality of service applies to any conversations started while those settings are in place. A DDE conversation's quality of service lasts for the duration of the conversation; calls to the DdeSetQualityOfService function during a given conversation do not affect that conversation's quality of service.

BOOL DdeSetQualityOfService(

HWND  hwndClient,	// handle of DDE client window that will start DDE conversations
CONST SECURITY_QUALITY_OF_SERVICE *  pqosNew,	// desired quality of service
PSECURITY_QUALITY_OF_SERVICE  pqosPrev	// prior quality of service
);
Parameters

hwndClient

Identifies the DDE client window that specifies the source of WM_DDE_INITIATE messages a client will send to start DDE conversations.

pqosNew

Points to a SECURITY_QUALITY_OF_SERVICE structure for the desired quality of service values.

pqosPrev

Points to a SECURITY_QUALITY_OF_SERVICE structure that the function will fill with the previous quality of service values associated with the window identified by hwndClient.

This parameter is optional. If an application has no interest in hwndClient's previous qos values, it should set pqosPrev to NULL.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The settings associated with a given hwndClient affect any conversation started subsequent to calling the DdeSetQualityOfService function. The settings remain in effect for the duration of any DDE conversation started under them. Once an application starts a DDE conversation using a particular quality of service value, it must terminate the conversation and restart the conversation in order to have a different value take effect. If a quality of service has not been specified for a given hwndClient prior to sending a WM_DDE_INITIATE with the wParam set to hwndClient, the system uses the following default quality of service values:

{

Length = sizeof(SECURITY_QUALITY_OF_SERVICE);

ImpersonationLevel = SecurityImpersonation;

ContextTrackingMode = SECURITY_STATIC_TRACKING;

EffectiveOnly = TRUE;

}

See Also

DdeConnect, DdeConnectList, DdeImpersonateClient, ImpersonateDdeClientWindow, SECURITY_QUALITY_OF_SERVICE, WM_DDE_INITIATE


DdeSetUserHandle
DdeSetUserHandle  QuickInfo  Overview  Group

The DdeSetUserHandle function associates an application-defined 32-bit value with a conversation handle or a transaction identifier. This is useful for simplifying the processing of asynchronous transactions. An application can use the DdeQueryConvInfo function to retrieve this value.

BOOL DdeSetUserHandle(

HCONV  hConv,	// handle of conversation
DWORD  id,	// transaction identifier
DWORD  hUser	// handle of application-defined value
);
Parameters

hConv

Identifies the conversation.

id

Specifies the transaction identifier to associate with the value specified by the hUser parameter. An application should set this parameter to QID_SYNC to associate hUser with the conversation identified by the hConv parameter.

hUser

Identifies the value to associate with the conversation handle.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Errors

The DdeGetLastError function can be used to get the error value, which may be one of the following values:

DMLERR_DLL_NOT_INITIALIZED
DMLERR_INVALIDPARAMETER
DMLERR_NO_ERROR
DMLERR_UNFOUND_QUEUE_ID

See Also

DdeQueryConvInfo


DdeUnaccessData
DdeUnaccessData  QuickInfo  Overview  Group

The DdeUnaccessData function unaccesses a dynamic data exchange (DDE) object. An application must call this function after it has finished accessing the object.

BOOL DdeUnaccessData(

HDDEDATA  hData	// handle of DDE object
);
Parameters

hData

Identifies the DDE object.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Errors

The DdeGetLastError function can be used to get the error value, which may be one of the following values:

DMLERR_DLL_NOT_INITIALIZED
DMLERR_INVALIDPARAMETER
DMLERR_NO_ERROR

See Also

DdeAccessData, DdeAddData, DdeCreateDataHandle, DdeFreeDataHandle


DdeUninitialize
DdeUninitialize  QuickInfo  Overview  Group

The DdeUninitialize function frees all Dynamic Data Exchange Management Library (DDEML) resources associated with the calling application.

BOOL DdeUninitialize(

DWORD  idInst	// instance identifier
);
Parameters

idInst

Specifies the application instance identifier obtained by a previous call to the DdeInitialize function.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

DdeUninitialize terminates any conversations currently open for the application.

See Also

DdeDisconnect, DdeDisconnectList, DdeInitialize


DebugActiveProcess
DebugActiveProcess  QuickInfo  Overview  Group

The DebugActiveProcess function allows a debugger to attach to an active process and then debug it.

BOOL DebugActiveProcess(

DWORD  dwProcessId	// process to be debugged
);
Parameters

dwProcessId

Specifies the identifier for the process to be debugged. The debugger gets debugging access to the process as if it created the process with the DEBUG_ONLY_THIS_PROCESS flag.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The debugger must have appropriate access to the target process; it must be able to open the process for PROCESS_ALL_ACCESS access. In the Win32 application programming interface (API) for Windows 95, this is always true if the process identifier is valid. However, In the Win32 API for Windows NT, DebugActiveProcess can fail if the target process was created with a security descriptor that denies the debugger appropriate access.

After the system checks the process identifier and determines that a valid debugging attachment is being made, the function returns TRUE. The debugger is then expected to wait for debugging events by using the WaitForDebugEvent function. The system suspends all threads in the process and sends the debugger events representing the current state of the process.

The system sends the debugger a single CREATE_PROCESS_DEBUG_EVENT debugging event representing the process specified by the dwProcessId parameter. The lpStartAddress member of the CREATE_PROCESS_DEBUG_INFO structure is NULL.

For each thread currently part of the process, the system sends a CREATE_THREAD_DEBUG_EVENT debugging event. The lpStartAddress member of the CREATE_THREAD_DEBUG_INFO structure is NULL.

For each dynamic-link library (DLL) currently loaded into the address space of the target process, the system sends a LOAD_DLL_DEBUG_EVENT debugging event. The system arranges for the first thread in the process to execute a breakpoint instruction after it resumes. Continuing this thread causes it to return to whatever it was doing before the debugger was attached.

After all of this has been done, the system resumes all threads in the process. When the first thread in the process resumes, it executes a breakpoint instruction that causes an EXCEPTION_DEBUG_EVENT debugging event to be sent to the debugger. All future debugging events are sent to the debugger by using the normal mechanism and rules.

See Also

CreateProcess, CREATE_PROCESS_DEBUG_INFO, CREATE_THREAD_DEBUG_INFO, WaitForDebugEvent


DebugBreak
DebugBreak  QuickInfo  Overview  Group

The DebugBreak function causes a breakpoint exception to occur in the current process so that the calling thread can signal the debugger and force it to take some action. If the process is not being debugged, the search logic of a standard exception handler is used. In most cases, this causes the calling process to terminate because of an unhandled breakpoint exception.

VOID DebugBreak(VOID)

Parameters

This function has no parameters.

Return Value

This function does not return a value.

See Also

DebugActiveProcess


DebugProc
DebugProc  QuickInfo  Overview  Group

The DebugProc hook procedure is an application-defined or library-defined callback function that Windows calls before calling the hook procedures associated with any other type of hook. The system passes information about the hook to be called to the DebugProc hook procedure, which examines the information and determines whether to allow the hook to be called.

LRESULT CALLBACK DebugProc(

int  nCode,	// hook code
WPARAM  wParam,	// type of hook about to be called
LPARAM  lParam	// address of structure with debugging information
);
Parameters

nCode

Specifies whether the hook procedure must process the message. If nCode is HC_ACTION, the hook procedure must process the message. If nCode is less than zero, the hook procedure must pass the message to the CallNextHookEx function without further processing and should return the value returned by CallNextHookEx.

wParam

Specifies the type of hook about to be called. This parameter can be one of the following values:

Value	Description
WH_CALLWNDPROC	Installs a hook procedure that monitors messages sent to a window procedure. For more information, see the description of the CallWndProc hook procedure.
WH_CALLWNDPROCRET	Windows 95 only: Installs a hook procedure that monitors messages that have just been processed by a window procedure. For more information, see the description of the CallWndRetProc hook procedure.
WH_CBT	Installs a hook procedure that receives notifications useful to a computer-based training (CBT) application. For more information, see the description of the CBTProc hook procedure.
WH_DEBUG	Installs a hook procedure useful for debugging other hook procedures. For more information, see the description of the DebugProc hook procedure.
WH_GETMESSAGE	Installs a hook procedure that monitors messages posted to a message queue. For more information, see the description of the GetMsgProc hook procedure.
WH_JOURNALPLAYBACK	Installs a hook procedure that posts messages previously recorded by a WH_JOURNALRECORD hook procedure. For more information, see the description of the JournalPlaybackProc hook procedure.
WH_JOURNALRECORD	Installs a hook procedure that records input messages posted to the system message queue. This hook is useful for recording macros. For more information, see the description of the JournalRecordProc hook procedure.
WH_KEYBOARD	Installs a hook procedure that monitors keystroke messages. For more information, see the description of the KeyboardProc hook procedure.
WH_MOUSE	Installs a hook procedure that monitors mouse messages. For more information, see the description of the MouseProc hook procedure.
WH_MSGFILTER	Installs a hook procedure that monitors messages generated as a result of an input event in a dialog box, message box, menu, or scroll bar. The hook procedure monitors these messages only for the application that installed the hook procedure. For more information, see the description of the MessageProc hook procedure.
WH_SHELL	Installs a hook procedure that receives notifications useful to a shell application. For more information, see the description of the ShellProc hook procedure.
WH_SYSMSGFILTER	Installs a hook procedure that monitors messages generated as a result of an input event in a dialog box, message box, menu, or scroll bar. The hook procedure monitors these messages for all applications in the system. For more information, see the description of the SysMsgProc hook procedure.
lParam

Points to a DEBUGHOOKINFO structure that contains the parameters to be passed to the destination hook procedure.

Return Value

To prevent the system from calling the hook, the return value must be a nonzero value. Otherwise, the hook procedure must pass the hook information to the CallNextHookEx function.

Remarks

An application installs this hook procedure by specifying the WH_DEBUG hook type and the address of the hook procedure in a call to the SetWindowsHookEx function.

CallWndProc is a placeholder for the application-defined or library-defined function name.

See Also

CallNextHookEx, CallWndProc, CBTProc, DEBUGHOOKINFO, GetMsgProc, JournalPlaybackProc, JournalRecordProc, KeyboardProc, MessageProc, MouseProc, SetWindowsHookEx, ShellProc, SysMsgProc


DefDlgProc
DefDlgProc  QuickInfo  Overview  Group

The DefDlgProc function carries out default message processing for a window procedure belonging to an application-defined dialog box class.

LRESULT DefDlgProc(

HWND  hDlg,	// handle of dialog box
UINT  Msg,	// message
WPARAM  wParam,	// first message parameter
LPARAM  lParam	// second message parameter
);
Parameters

hDlg

Identifies the dialog box.

Msg

Specifies the message number.

wParam

Specifies additional message-specific information.

lParam

Specifies additional message-specific information.

Return Value

The return value specifies the result of the message processing and depends on the message sent.

Remarks

The DefDlgProc function is the window procedure for the predefined class of dialog box. This procedure provides internal processing for the dialog box by forwarding messages to the dialog box procedure and carrying out default processing for any messages that the dialog box procedure returns as FALSE. Applications that create custom window procedures for their custom dialog boxes often use this function instead of the DefWindowProc to carry out default message processing.

Applications create custom dialog box classes by filling a WNDCLASS structure with appropriate information and registering the class with the RegisterClass function. Some applications fill the structure by using the GetClassInfo function, specifying the name of the predefined dialog box. In such cases, the applications modify at least the lpszClassName member before registering. In all cases, the cbWndExtra member of the WNDCLASS structure for a custom dialog box class must be set to at least DLGWINDOWEXTRA.

DefDlgProc must not be called by a dialog box procedure; doing so results in recursive execution.

See Also

DefWindowProc, GetClassInfo, RegisterClass, WNDCLASS


DeferWindowPos
DeferWindowPos  QuickInfo  Overview  Group

The DeferWindowPos function updates the specified multiple-window − position structure for the specified window. The function then returns the handle of the updated structure. The EndDeferWindowPos function uses the information in this structure to change the position and size of a number of windows simultaneously. The BeginDeferWindowPos function creates the structure.

HDWP DeferWindowPos(

HDWP  hWinPosInfo,	// handle of internal structure
HWND  hWnd,	// handle of window to position
HWND  hWndInsertAfter,	// placement-order handle
int  x,	// horizontal position
int  y,	// vertical position
int  cx,	// width
int  cy,	// height
UINT  uFlags	// window-positioning flags
);
Parameters

hWinPosInfo

Identifies a multiple-window − position structure that contains size and position information for one or more windows. This structure is returned by BeginDeferWindowPos or by the most recent call to DeferWindowPos.

hWnd

Identifies the window for which update information is stored in the structure.

hWndInsertAfter

Identifies the window that precedes the positioned window in the Z order. This parameter must be a window handle or one of the following values:

Value	Meaning
HWND_BOTTOM	Places the window at the bottom of the Z order. If the hWnd parameter identifies a topmost window, the window loses its topmost status and is placed at the bottom of all other windows.
HWND_NOTOPMOST	Places the window above all non-topmost windows (that is, behind all topmost windows). This flag has no effect if the window is already a non-topmost window.
HWND_TOP	Places the window at the top of the Z order.
HWND_TOPMOST	Places the window above all non-topmost windows. The window maintains its topmost position even when it is deactivated.
This parameter is ignored if the SWP_NOZORDER flag is set in the uFlags parameter.

x

Specifies the x-coordinate of the window's upper-left corner.

y

Specifies the y-coordinate of the window's upper-left corner.

cx

Specifies the window's new width, in pixels.

cy

Specifies the window's new height, in pixels.

uFlags

Specifies a combination of the following values that affect the size and position of the window:

Value	Meaning
SWP_DRAWFRAME	Draws a frame (defined in the window's class description) around the window.
SWP_HIDEWINDOW	Hides the window.
SWP_NOACTIVATE	Does not activate the window.
SWP_NOMOVE	Retains the current position (ignores the x and y parameters).
SWP_NOOWNERZORDER	Does not change the owner window's position in the Z order.
SWP_NOREDRAW	Does not redraw changes. If this flag is set, no repainting occurs. This applies to the client area, the nonclient area (including the title bar and scroll bars), and any part of the parent window uncovered as a result of the window being moved. When this flag is set, the application must explicitly invalidate or redraw any parts of the window and parent window that needs to be redrawn.
SWP_NOREPOSITION	Currently the same as the SWP_NOOWNERZORDER flag.
SWP_NOSENDCHANGING	Windows 95 only: Prevents the window from receiving the WM_WINDOWPOSCHANGING message.
SWP_NOSIZE	Retains the current size (ignores the cx and cy parameters).
SWP_NOZORDER	Retains the current Z order (ignores the hWndInsertAfter parameter).
SWP_SHOWWINDOW	Displays the window.
Return Value

The return value identifies the updated multiple-window − position structure. The handle returned by this function may differ from the handle passed to the function. The new handle that this function returns should be passed during the next call to the DeferWindowPos or EndDeferWindowPos function.

If insufficient system resources are available for the function to succeed, the return value is NULL.

Remarks

If a call to DeferWindowPos fails, the application should abandon the window-positioning operation and not call EndDeferWindowPos.

If SWP_NOZORDER is not specified, Windows places the window identified by the hWnd parameter in the position following the window identified by the hWndInsertAfter parameter. If hWndInsertAfter is NULL or HWND_TOP, Windows places the hWnd window at the top of the Z order. If hWndInsertAfter is set to HWND_BOTTOM, Windows places the hWnd window at the bottom of the Z order.

All coordinates for child windows are relative to the upper-left corner of the parent window's client area.

A window can be made a topmost window either by setting hWndInsertAfter to the HWND_TOPMOST flag and ensuring that the SWP_NOZORDER flag is not set, or by setting the window's position in the Z order so that it is above any existing topmost windows. When a non-topmost window is made topmost, its owned windows are also made topmost. Its owners, however, are not changed.

If neither the SWP_NOACTIVATE nor SWP_NOZORDER flag is specified (that is, when the application requests that a window be simultaneously activated and its position in the Z order changed), the value specified in hWndInsertAfter is used only in the following circumstances:

•	Neither the HWND_TOPMOST nor HWND_NOTOPMOST flag is specified in hWndInsertAfter.

•	The window identified by hWnd is not the active window.

An application cannot activate an inactive window without also bringing it to the top of the Z order. An application can change an activated window's position in the Z order without restrictions, or it can activate a window and then move it to the top of the topmost or non-topmost windows.

A topmost window is no longer topmost if it is repositioned to the bottom (HWND_BOTTOM) of the Z order or after any non-topmost window. When a topmost window is made non-topmost, its owners and its owned windows are also made non-topmost windows.

A non-topmost window may own a topmost window, but not vice versa. Any window (for example, a dialog box) owned by a topmost window is itself made a topmost window to ensure that all owned windows stay above their owner.

See Also

BeginDeferWindowPos, EndDeferWindowPos, ShowWindow


DefFrameProc
DefFrameProc  QuickInfo  Overview  Group

The DefFrameProc function provides default processing for any window messages that the window procedure of a multiple document interface (MDI) frame window does not process. All window messages that are not explicitly processed by the window procedure must be passed to the DefFrameProc function, not the DefWindowProc function.

LRESULT DefFrameProc(

HWND  hWnd,	// handle of MDI frame window
HWND  hWndMDIClient,	// handle of MDI client window
UINT  uMsg,	// message
WPARAM  wParam,	// first message parameter
LPARAM  lParam	// second message parameter
);
Parameters

hWnd

Identifies the MDI frame window.

hWndMDIClient

Identifies the MDI client window.

uMsg

Specifies the message to be processed.

wParam

Specifies additional message-specific information.

lParam

Specifies additional message-specific information.

Return Value

The return value specifies the result of the message processing and depends on the message. If the hWndMDIClient parameter is NULL, the return value is the same as for the DefWindowProc function.

Remarks

When an application's window procedure does not handle a message, it typically passes the message to the DefWindowProc function to process the message. MDI applications use the DefFrameProc and DefMDIChildProc functions instead of DefWindowProc to provide default message processing. All messages that an application would usually pass to DefWindowProc (such as nonclient messages and the WM_SETTEXT message) should be passed to DefFrameProc instead. The DefFrameProc function also handles the following messages:

Message	Response
WM_COMMAND	Activates the MDI child window that the user chooses. This message is sent when the user chooses an MDI child window from the Window menu of the MDI frame window. The window identifier accompanying this message identifies the MDI child window to be activated.
WM_MENUCHAR	Opens the System menu of the active MDI child window when the user presses the ALT+ − (minus) key combination.
WM_SETFOCUS	Passes the keyboard focus to the MDI client window, which in turn passes it to the active MDI child window.
WM_SIZE	Resizes the MDI client window to fit in the new frame window's client area. If the frame window procedure sizes the MDI client window to a different size, it should not pass the message to the DefWindowProc function.
See Also

DefMDIChildProc, DefWindowProc, WM_SETTEXT


DefHookProc
DefHookProc  QuickInfo  Overview  Group

The DefHookProc function is obsolete. It is provided only for compatibility with 16-bit versions of Windows. Win32-based applications should use the CallNextHookEx function.


DefineDosDevice
DefineDosDevice  QuickInfo  Overview  Group

The DefineDosDevice function lets an application define, redefine, or delete MS-DOS device names.

MS-DOS device names are stored as symbolic links in the object name space in 32-bit versions of Windows. The code that converts an MS-DOS path into a corresponding path in 32-bit versions of Windows uses these symbolic links to map MS-DOS devices and drive letters. The DefineDosDevice function provides a mechanism whereby a Win32-based application can modify the symbolic links used to implement the MS-DOS device name space.

BOOL DefineDosDevice(

DWORD  dwFlags,	// flags specifying aspects of device definition
LPCTSTR  lpDeviceName,	// address of MS-DOS device name string
LPCTSTR  lpTargetPath	// address of MS-DOS or path string for 32-bit Windows
);
Parameters

dwFlags

Specifies several controllable aspects of the DefineDosDevice function. One or more of the following values can be used:

Value	Meaning
DDD_RAW_TARGET_PATH	If this value is specified, the function does not convert the lpTargetPath string from an MS-DOS path to a path for a 32-bit version of Windows, but takes it as is.
DDD_REMOVE_DEFINITION	If this value is specified, the function removes the specified definition for the specified device. To determine which definition to remove, the function walks the list of mappings for the device, looking for a match of lpTargetPath against a prefix of each mapping associated with this device. The first mapping that matches is the one removed, and then the function returns. If lpTargetPath is NULL or a pointer to a NULL string, the function will remove the first mapping associated with the device and pop the most recent one pushed. If there is nothing left to pop, the device name will be removed. If this value is NOT specified, the string pointed to by the lpTargetPath parameter will become the new mapping for this device.
DDD_EXACT_MATCH_ON_REMOVE	If this value is specified along with DDD_REMOVE_DEFINITION, the function will use an exact match to determine which mapping to remove. Use this value to insure that you do not delete something that you did not define.
lpDeviceName

Points to an MS-DOS device name string specifying the device the function is defining, redefining, or deleting. The device name string must not have a trailing colon, unless a drive letter (C or D, for example) is being defined, redefined, or deleted.

lpTargetPath

Points to a path string that will implement this device. Points to an MS-DOS path string unless the DDD_RAW_TARGET_PATH flag is specified, in which case this parameter points to a path string for a 32-bit version of Windows.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

As stated in this function's introductory summary, the DefineDosDevice function provides a means whereby a Win32-based application can create and modify the symbolic links used to implement the MS-DOS device namespace. To retrieve the current mapping for a particular MS-DOS device name or to obtain a list of all MS-DOS devices known to the system, use the QueryDosDevice function.

MS-DOS Device names are global. Once defined, an MS-DOS device name remains visible to all processes until either it is explicitly removed or the system reboots.

Note that drive letters and device names defined at system boot time are protected from redefinition and deletion unless a user is running in administrative mode (ADMIN).

See Also

QueryDosDevice


DefineHandleTable
DefineHandleTable  QuickInfo  Overview  Group

The DefineHandleTable function is obsolete. It is provided as a macro to simplify porting of 16-bit Windows-based applications. It expands to TRUE after evaluating its argument. It has no other effect.


DefMDIChildProc
DefMDIChildProc  QuickInfo  Overview  Group

The DefMDIChildProc function provides default processing for any window message that the window procedure of a multiple document interface (MDI) child window does not process. A window message not processed by the window procedure must be passed to the DefMDIChildProc function, not to the DefWindowProc function.

LRESULT DefMDIChildProc(

HWND  hWnd,	// handle of MDI child window
UINT  uMsg,	// message
WPARAM  wParam,	// first message parameter
LPARAM  lParam	// second message parameter
);
Parameters

hWnd

Identifies the MDI child window.

uMsg

Specifies the message to be processed.

wParam

Specifies additional message-specific information.

lParam

Specifies additional message-specific information.

Return Value

The return value specifies the result of the message processing and depends on the message.

Remarks

The DefMDIChildProc function assumes that the parent window of the MDI child window identified by the hWnd parameter was created with the MDICLIENT class.

When an application's window procedure does not handle a message, it typically passes the message to the DefWindowProc function to process the message. MDI applications use the DefFrameProc and DefMDIChildProc functions instead of DefWindowProc to provide default message processing. All messages that an application would usually pass to DefWindowProc (such as nonclient messages and the WM_SETTEXT message) should be passed to DefMDIChildProc instead. In addition, DefMDIChildProc also handles the following messages:

Message	Response
WM_CHILDACTIVATE	Performs activation processing when MDI child windows are sized, moved, or displayed. This message must be passed.
WM_GETMINMAXINFO	Calculates the size of a maximized MDI child window, based on the current size of the MDI client window.
WM_MENUCHAR	Passes the message to the MDI frame window.
WM_MOVE	Recalculates MDI client scroll bars if they are present.
WM_SETFOCUS	Activates the child window if it is not the active MDI child window.
WM_SIZE	Performs operations necessary for changing the size of a window, especially for maximizing or restoring an MDI child window. Failing to pass this message to the DefMDIChildProc function produces highly undesirable results.
WM_SYSCOMMAND	Handles System menu commands: SC_NEXTWINDOW, SC_PREVWINDOW, SC_MOVE, SC_SIZE, and SC_MAXIMIZE.
See Also

DefFrameProc, DefWindowProc, WM_CHILDACTIVATE, WM_GETMINMAXINFO, WM_MENUCHAR, WM_MOVE, WM_SETFOCUS, WM_SETTEXT, WM_SIZE, WM_SYSCOMMAND


DefScreenSaverProc
DefScreenSaverProc  QuickInfo  Overview  Group

The DefScreenSaverProc function provides default processing for any messages that a screen saver application does not process.

LONG DefScreenSaverProc(

HWND  hWnd,	// handle of screen saver window
UINT  msg,	// message
WPARAM  wParam,	// first message parameter
LPARAM  lParam	// second message parameter
);
Parameters

hWnd

Identifies the screen saver window.

msg

Specifies the message to be processed. The DefScreenSaverProc function responds to messages that affect the screen saver's operation, as detailed in the Remarks section.

If a screen saver application must perform a different action in response to any of these messages, the application's ScreenSaverProc window procedure should process the message.

wParam

Specifies additional message-specific information.

lParam

Specifies additional message-specific information.

Return Value

The return value specifies the result of the message processing and depends on the message sent.

Remarks

A screen saver application's ScreenSaverProc window procedure should use DefScreenSaverProc instead of the DefWindowProc function to provide default message processing. The DefScreenSaverProc function passes any messages that do not affect screen saver operation to DefWindowProc.

The following table describes how the DefScreenSaverProc processes a variety of window messages:

Message	Action
WM_ACTIVATE, WM_ACTIVATEAPP, WM_NCACTIVATE	Closes the screen saver if the wParam parameter is FALSE. A wParam value of FALSE indicates that the screen saver is losing the input focus. The screen saver is closed by sending a WM_CLOSE message.
WM_SETCURSOR	Removes the cursor from the screen by setting the cursor to NULL.
WM_LBUTTONDOWN, WM_RBUTTONDOWN, WM_MBUTTONDOWN, WM_KEYDOWN, WM_KEYUP, WM_MOUSEMOVE	Calls the PostQuitMessage function to close the screen saver.
WM_DESTROY	Posts a WM_CLOSE message to close the screen saver window.
WM_SYSCOMMAND	Returns FALSE if the wParam parameter of WM_SYSCOMMAND is either SC_CLOSE or SC_SCREENSAVE.
See Also

DefWindowProc, PostQuitMessage, ScreenSaverProc, WM_ACTIVATE, WM_ACTIVATEAPP, WM_CLOSE, WM_DESTROY, WM_KEYDOWN, WM_KEYUP, WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_MOUSEMOVE, WM_NCACTIVATE, WM_RBUTTONDOWN, WM_SETCURSOR, WM_SYSCOMMAND


DefWindowProc
DefWindowProc  QuickInfo  Overview  Group

The DefWindowProc function calls the default window procedure to provide default processing for any window messages that an application does not process. This function ensures that every message is processed. DefWindowProc is called with the same parameters received by the window procedure.

LRESULT DefWindowProc(

HWND  hWnd,	// handle of window
UINT  Msg,	// message identifier
WPARAM  wParam,	// first message parameter
LPARAM  lParam	// second message parameter
);
Parameters

hWnd

Identifies the window procedure that received the message.

Msg

Specifies the message.

wParam

Specifies additional message information. The content of this parameter depends on the value of the Msg parameter.

lParam

Specifies additional message information. The content of this parameter depends on the value of the Msg parameter.

Return Value

The return value is the result of the message processing and depends on the message.

See Also

CallWindowProc, DefDlgProc, WindowProc


DeleteAce
DeleteAce  QuickInfo  Overview  Group

The DeleteAce function deletes an ACE from an ACL.

An ACE is an access-control entry. An ACL is an access-control list.

BOOL DeleteAce(

PACL  pAcl,	// address of access-control list
DWORD  dwAceIndex	// index of ACE position in ACL
);
Parameters

pAcl

Points to an ACL structure. The ACE specified by the dwAceIndex parameter is removed from this ACL.

dwAceIndex

Specifies the ACE to delete. A value of 0 corresponds to the first ACE in the ACL, 1 to the second ACE, and so on.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

An application can use the ACL_SIZE_INFORMATION structure retrieved by the GetAclInformation function to discover the size of the ACL and the number of ACEs it contains. The GetAce function retrieves information about an individual ACE.

See Also

ACL, ACL_SIZE_INFORMATION, AddAccessAllowedAce, AddAccessDeniedAce, AddAce, AddAuditAccessAce, GetAce, GetAclInformation


DeleteAtom
DeleteAtom  QuickInfo  Overview  Group

The DeleteAtom function decrements the reference count of a local string atom. If the atom's reference count is reduced to zero, DeleteAtom removes the string associated with the atom from the local atom table.

ATOM DeleteAtom(

ATOM  nAtom	// atom to delete
);
Parameters

nAtom

Identifies the atom and character string to be deleted.

Return Value

If the function succeeds, the return value is zero.

If the function fails, the return value is the nAtom parameter. To get extended error information, call GetLastError.

Remarks

A string atom's reference count specifies the number of times the atom has been added to or removed from the atom table. The AddAtom function increments the count on each call. DeleteAtom decrements the count on each call but removes the string only if the atom's reference count is zero.

The only way to ensure that an atom has been deleted from the atom table is to call this function repeatedly until it fails. When the reference count is reduced to zero, the next call to the FindAtom or DeleteAtom function fails.

DeleteAtom has no effect on an integer atom (an atom created by using the MAKEINTATOM macro). The function always returns zero for an integer atom.

See Also

AddAtom, FindAtom, GlobalAddAtom, GlobalDeleteAtom, GlobalFindAtom, MAKEINTATOM


DeleteColorSpace [New - Windows 95]
DeleteColorSpace  QuickInfo  Overview  Group

[New - Windows 95]

The DeleteColorSpace function deletes the specified color space, freeing all internal resources associated with it.

BOOL DeleteColorSpace(

HCOLORSPACE hColorSpace
);
Parameters

hColorSpace

Handle to the color space to delete.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.


DeleteCriticalSection
DeleteCriticalSection  QuickInfo  Overview  Group

The DeleteCriticalSection function releases all resources used by an unowned critical section object.

VOID DeleteCriticalSection(

LPCRITICAL_SECTION  lpCriticalSection	// address of critical section object
);
Parameters

lpCriticalSection

Points to the critical section object.

Return Value

This function does not return a value.

Remarks

Deleting a critical section object releases all system resources used by the object. Once deleted, the critical section object cannot be specified in the EnterCriticalSection or LeaveCriticalSection function.

See Also

EnterCriticalSection, InitializeCriticalSection, LeaveCriticalSection


DeleteDC
DeleteDC  QuickInfo  Overview  Group

The DeleteDC function deletes the specified device context (DC).

BOOL DeleteDC(

HDC  hdc	// handle of device context
);
Parameters

hdc

Identifies the device context.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

An application must not delete a device context whose handle was obtained by calling the GetDC function. Instead, it must call the ReleaseDC function to free the device context.

See Also

CreateDC, GetDC, ReleaseDC


DeleteEnhMetaFile
DeleteEnhMetaFile  QuickInfo  Overview  Group

The DeleteEnhMetaFile function deletes an enhanced-format metafile or an enhanced-format metafile handle.

BOOL DeleteEnhMetaFile(

HENHMETAFILE  hemf	// handle of an enhanced metafile
);
Parameters

hemf

Identifies an enhanced metafile.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

If the hemf parameter identifies an enhanced metafile stored in memory, this function deletes the metafile. If hemf identifies a metafile stored on a disk, the function deletes the metafile handle but does not destroy the actual metafile. An application can retrieve the file by calling the GetEnhMetaFile function.

See Also

CopyEnhMetaFile, CreateEnhMetaFile, GetEnhMetaFile


DeleteFile
DeleteFile  QuickInfo  Overview  Group

The DeleteFile function deletes an existing file.

BOOL DeleteFile(

LPCTSTR  lpFileName	// address of name of file to delete
);
Parameters

lpFileName

Points to a null-terminated string that specifies the file to be deleted.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

If an application attempts to delete a file that does not exist, the DeleteFile function fails.

Windows 95: This function deletes a file even if it is open for normal I/O or as a memory-mapped file. To prevent loss of data, close files before attempting to delete them.

Windows NT: This function fails if an application attempts to delete a file that is open for normal I/O or as a memory-mapped file.

To close an open file, use the CloseHandle function.

See Also

CloseHandle, CreateFile


DeleteForm
DeleteForm  QuickInfo  Overview  Group

The DeleteForm function removes a form name from the list of supported forms.

BOOL DeleteForm(

HANDLE  hPrinter,	// handle of printer object
LPTSTR  pFormName	// address of form name
);
Parameters

hPrinter

Indicates the open printer handle that this function is to be performed upon.

pFormName

Points to the form name to be removed.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The printer handle is obtained by calling the OpenPrinter function. DeleteForm can only delete form names that were added by using the AddForm function.

See Also

AddForm, OpenPrinter


DeleteMenu
DeleteMenu  QuickInfo  Overview  Group

The DeleteMenu function deletes an item from the specified menu. If the menu item invokes a pop-up menu, this function destroys the handle of the pop-up menu and frees the memory used by the pop-up menu.

BOOL DeleteMenu(

HMENU  hMenu,	// handle of menu
UINT  uPosition,	// menu item identifier or position
UINT  uFlags	// menu item flag
);
Parameters

hMenu

Identifies the menu to be changed.

uPosition

Specifies the menu item to be deleted, as determined by the uFlags parameter.

uFlags

Specifies how the uPosition parameter is interpreted. This parameter must be one of the following values:

Value	Meaning
MF_BYCOMMAND	Indicates that uPosition gives the identifier of the menu item. The MF_BYCOMMAND flag is the default flag if neither the MF_BYCOMMAND nor MF_BYPOSITION flag is specified.
MF_BYPOSITION	Indicates that uPosition gives the zero-based relative position of the menu item.
Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The application must call the DrawMenuBar function whenever a menu changes, whether or not the menu is in a displayed window.

See Also

DrawMenuBar, RemoveMenu


DeleteMetaFile
DeleteMetaFile  QuickInfo  Overview  Group

The DeleteMetaFile function deletes a Windows-format metafile or Windows-format metafile handle.

This function is provided for compatibility with 16-bit versions of Windows. Win32-based applications should use the DeleteEnhMetaFile function.

BOOL DeleteMetaFile(

HMETAFILE  hmf	// handle of Windows-format metafile
);
Parameters

hmf

Identifies a Windows-format metafile.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

A Windows-format metafile does not support the new curve, path, and transformation functions, such as PolyBezier, BeginPath, and SetWorldTransform. Applications that use these new functions and use metafiles to store pictures created by these functions should use the enhanced format metafile functions.

If the metafile identified by the hmf parameter is stored in memory (rather than on a disk), its content is lost when it is deleted by using the DeleteMetaFile function.

See Also

BeginPath, CopyMetaFile, CreateMetaFile, DeleteEnhMetaFile, GetMetaFile, PolyBezier, SetWorldTransform


DeleteMonitor
DeleteMonitor  QuickInfo  Overview  Group

The DeleteMonitor function removes a printer monitor added by the AddMonitor function.

BOOL DeleteMonitor(

LPTSTR  pName,	// address of server name
LPTSTR  pEnvironment,	// address of environment string
LPTSTR  pMonitorName	// address of monitor name
);
Parameters

pName

Points to a null-terminated string that specifies the name of the server from which the monitor is to be removed. If this parameter is NULL, the printer monitor is removed locally.

pEnvironment

Points to a null-terminated string that specifies the environment from which the monitor is to be removed (for example, "Windows NT x86", "Windows NT R4000", "Windows NT Alpha_AXP", or "Windows 4.0"). If this parameter is NULL, the monitor is removed from the current environment of the calling application and client machine (not of the destination application and print server).

pMonitorName

Points to a null-terminated string that specifies the name of the monitor to be removed.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

AddMonitor


DeleteObject
DeleteObject  QuickInfo  Overview  Group

The DeleteObject function deletes a logical pen, brush, font, bitmap, region, or palette, freeing all system resources associated with the object. After the object is deleted, the specified handle is no longer valid.

BOOL DeleteObject(

HGDIOBJ  hObject	// handle of graphic object
);
Parameters

hObject

Identifies a logical pen, brush, font, bitmap, region, or palette.

Return Value

If the function succeeds, the return value is TRUE.

If the given handle is not valid or is currently selected into a device context (DC), the return value is FALSE.

Remarks

Do not delete a drawing object (pen or brush) while it is still selected into a DC.

When a pattern brush is deleted, the bitmap associated with the brush is not deleted. The bitmap must be deleted independently.

See Also

SelectObject


DeletePort
DeletePort  QuickInfo  Overview  Group

The DeletePort function displays a dialog box that allows the user to delete a port name.

BOOL DeletePort(

LPTSTR  pName,	// address of server name
HWND  hWnd,	// handle of window that displays dialog box
LPTSTR  pPortName	// address of port name
);
Parameters

pName

Points to a null-terminated string that specifies the name of the server for which the port should be deleted. If this parameter is NULL, a local port is deleted.

hWnd

Identifies the parent window of the port-deletion dialog box.

pPortName

Points to a null-terminated string that specifies the name of the port that should be deleted.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

An application can retrieve the names of valid ports by calling the EnumPorts function.

The DeletePort function returns an error if a printer is currently connected to the specified port.

See Also

AddPort, EnumPorts


DeletePrinter
DeletePrinter  QuickInfo  Overview  Group

The DeletePrinter function deletes the specified printer object.

BOOL DeletePrinter(

HANDLE  hPrinter	// handle of printer object
);
Parameters

hPrinter

Identifies a printer object that will be deleted.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The printer handle hPrinter is obtained by calling the OpenPrinter or AddPrinter function. Most users will use OpenPrinter.

If there are print jobs remaining to be processed for the given printer, DeletePrinter marks the printer for pending deletion, and then deletes it when all the print jobs have been printed. No print jobs can be added to a printer that is marked for pending deletion.

A printer marked for pending deletion cannot be held, but its print jobs can be held, resumed, and restarted. If the printer is held and there are jobs for the printer, DeletePrinter fails with an InvalidState error.

See Also

AddPrinter, EnumPrinters, OpenPrinter


DeletePrinterConnection
DeletePrinterConnection  Overview  Group

The DeletePrinterConnection function deletes a connection to a printer that was established by a call to AddPrinterConnection or ConnectToPrinterDlg.

BOOL DeletePrinterConnection (

LPTSTR  pName	// address of printer name
);
Parameters

pName

Points to a null-terminated string that specifies the name of the printer connection to delete.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The DeletePrinterConnection function does not delete any printer drivers copied to the server on which the printer resides when the printer connection was established.

See Also

AddPrinterConnection, ConnectToPrinterDlg


DeletePrinterDriver
DeletePrinterDriver  QuickInfo  Overview  Group

The DeletePrinterDriver function removes the specified printer-driver name from the list of names of supported drivers for a server.

BOOL DeletePrinterDriver(

LPTSTR  pName,	// address of server name
LPTSTR  pEnvironment,	// address of environment
LPTSTR  pDriverName	// address of driver name
);
Parameters

pName

Points to a null-terminated string that specifies the name of the server from which the driver is to be deleted. If this parameter is NULL, the printer-driver name will be removed locally.

pEnvironment

Points to a null-terminated string that specifies the environment from which the driver is to be deleted (for example, "Windows NT x86", "Windows NT R4000", "Windows NT Alpha_AXP", or "Windows 4.0"). If this parameter is NULL, the driver name is deleted from the current environment of the calling application and client machine (not of the destination application and print server).

pDriverName

Points to a null-terminated string specifying the name of the driver that should be deleted.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The DeletePrinterDriver function does not delete the associated files, it merely removes the driver name from the list returned by the EnumPrinterDrivers function.

See Also

EnumPrinterDrivers


DeletePrintProcessor
DeletePrintProcessor  QuickInfo  Overview  Group

The DeletePrintProcessor function removes a printer processor added by the AddPrintProcessor function.

BOOL DeletePrintProcessor (

LPTSTR  pName,	// address of server name
LPTSTR  pEnvironment,	// address of environment string
LPTSTR  pPrintProcessorName	// address of processor name
);
Parameters

pName

Points to a null-terminated string that specifies the name of the server from which the processor is to be removed. If this parameter is NULL, the printer processor is removed locally.

pEnvironment

Points to a null-terminated string that specifies the environment from which the processor is to be removed (for example, "Windows NT x86", "Windows NT R4000", "Windows NT Alpha_AXP", or "Windows 4.0"). If this parameter is NULL, the processor is removed from the current environment of the calling application and client machine (not of the destination application and print server). NULL is the recommended value, as it provides maximum portability.

pPrintProcessorName

Points to a null-terminated string that specifies the name of the processor to be removed.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

AddPrintProcessor


DeletePrintProvidor
DeletePrintProvidor  QuickInfo  Overview  Group

The DeletePrintProvidor function removes a printer provider added by the AddPrintProvidor function.

BOOL DeletePrintProvidor (

LPTSTR  pName,	// address of server name
LPTSTR  pEnvironment,	// address of environment string
LPTSTR  pPrintProvidorName	// address of provider name
);
Parameters

pName

Points to a null-terminated string that specifies the name of the server from which the provider is to be removed. If this parameter is NULL, the printer provider is removed locally.

pEnvironment

Points to a null-terminated string that specifies the environment from which the provider is to be removed (for example, "Windows NT x86", "Windows NT R4000", "Windows NT Alpha_AXP", or "Windows 4.0"). If this parameter is NULL, the provider is removed from the current environment of the calling application and client machine (not of the destination application and print server). NULL is the recommended value because it provides maximum portability.

pPrintProvidorName

Points to a null-terminated string that specifies the name of the provider to be removed.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

AddPrintProvidor


DeleteService
DeleteService  QuickInfo  Overview  Group

The DeleteService function marks the specified service for deletion from the service control manager database.

BOOL DeleteService(

SC_HANDLE  hService	// handle of service
);
Parameters

hService

Identifies the service. This handle is returned by the OpenService or CreateService function, and it must have DELETE access.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Errors

The following error codes may be set by the service control manager. Others may be set by the registry functions that are called by the service control manager.

Value	Meaning
ERROR_ACCESS_DENIED	The specified handle was not opened with DELETE access.
ERROR_INVALID_HANDLE	The specified handle is invalid.
ERROR_SERVICE_MARKED_FOR_DELETE	The specified service has already been marked for deletion.
Remarks

The DeleteService function marks a service for deletion from the service control manager database. The database entry is not removed until all open handles to the service have been closed by calls to the CloseServiceHandle function, and the service is not running. A running service is stopped by a call to the ControlService function with the SERVICE_CONTROL_STOP control code. If the service cannot be stopped, the database entry is removed when the system is restarted.

The service control manager deletes the service by deleting the service key and its subkeys from the registry.

See Also

CloseServiceHandle, ControlService, CreateService, OpenService


DeregisterEventSource
DeregisterEventSource  QuickInfo  Overview  Group

The DeregisterEventSource function closes a handle returned by the RegisterEventSource function.

BOOL DeregisterEventSource(

HANDLE  hEventLog	// handle to event log
);
Parameters

hEventLog

Identifies the event log whose handle was returned by RegisterEventSource.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

RegisterEventSource


DestroyAcceleratorTable
DestroyAcceleratorTable  QuickInfo  Overview  Group

The DestroyAcceleratorTable function destroys an accelerator table. Before an application closes, it must use this function to destroy each accelerator table that it created by using the CreateAcceleratorTable function.

BOOL DestroyAcceleratorTable(

HACCEL  hAccel	// handle of accelerator table
);
Parameters

hAccel

Identifies the accelerator table to destroy. This handle must have been created by a call to the CreateAcceleratorTable function.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

CopyAcceleratorTable, CreateAcceleratorTable, LoadAccelerators, TranslateAccelerator


DestroyCaret
DestroyCaret  QuickInfo  Overview  Group

The DestroyCaret function destroys the caret's current shape, frees the caret from the window, and removes the caret from the screen.

If the caret shape is based on a bitmap, DestroyCaret does not free the bitmap.

BOOL DestroyCaret(VOID)

Parameters

This function has no parameters.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

DestroyCaret destroys the caret only if a window in the current task owns the caret. If a window that is not in the current task owns the caret, DestroyCaret does nothing and returns FALSE.

The caret is a shared resource; there is only one caret in the system. A window should create a caret only when it has the keyboard focus or is active. The window should destroy the caret before losing the keyboard focus or becoming inactive.

See Also

CreateCaret, HideCaret, ShowCaret


DestroyCursor
DestroyCursor  QuickInfo  Overview  Group

The DestroyCursor function destroys a cursor created by the CreateCursor function and frees any memory the cursor occupied. Do not use this function to destroy a cursor that was not created with the CreateCursor function.

BOOL DestroyCursor(

HCURSOR  hCursor	// handle of cursor to destroy
);
Parameters

hCursor

Identifies the cursor to be destroyed. The cursor must not be in use.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

CreateCursor


DestroyIcon
DestroyIcon  QuickInfo  Overview  Group

The DestroyIcon function destroys an icon and frees any memory the icon occupied.

BOOL DestroyIcon(

HICON  hIcon	// handle of icon to destroy
);
Parameters

hIcon

Identifies the icon to be destroyed. The icon must not be in use.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

CreateIcon


DestroyMenu
DestroyMenu  QuickInfo  Overview  Group

The DestroyMenu function destroys the given menu and frees any memory that the menu occupies.

BOOL DestroyMenu(

HMENU  hMenu	// handle of menu to destroy
);
Parameters

hMenu

Identifies the menu to be destroyed.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Before closing, an application must use this function to destroy a menu not assigned to a window. A menu that is assigned to a window is automatically destroyed when the application closes.

See Also

CreateMenu, DeleteMenu, RemoveMenu


DestroyPrivateObjectSecurity
DestroyPrivateObjectSecurity  QuickInfo  Overview  Group

The DestroyPrivateObjectSecurity function deletes a protected server object's security descriptor. This security descriptor must have been created by a call to the CreatePrivateObjectSecurity function.

BOOL DestroyPrivateObjectSecurity(

PSECURITY_DESCRIPTOR  * ObjectDescriptor	// address of pointer to SECURITY_DESCRIPTOR
);
Parameters

ObjectDescriptor

Points to a pointer to the SECURITY_DESCRIPTOR structure to be deleted.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

CreatePrivateObjectSecurity, GetPrivateObjectSecurity, SECURITY_DESCRIPTOR, SetPrivateObjectSecurity


DestroyPropertySheetPage [New - Windows NT]
DestroyPropertySheetPage  QuickInfo  Overview  Group

[New - Windows NT]

The DestroyPropertySheetPage function destroys a property sheet page. An application must call this function for pages that have not been passed to the PropertySheet function.

BOOL DestroyPropertySheetPage(

HPROPSHEETPAGE  hPSPage
);
Parameters

hPSPage

Handle to the property sheet page to delete.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

See Also

PropertySheet


DestroyWindow
DestroyWindow  QuickInfo  Overview  Group

The DestroyWindow function destroys the given window. The function sends WM_DESTROY and WM_NCDESTROY messages to the window to deactivate it and remove the keyboard focus from it. The function also destroys the window's menu, flushes the thread message queue, destroys timers, removes clipboard ownership, and breaks the clipboard viewer chain (if the window is at the top of the viewer chain).

If the given window is a parent or owner window, DestroyWindow automatically destroys the associated child or owned windows when it destroys the parent or owner window. The function first destroys child or owned windows, and then it destroys the parent or owner window.

DestroyWindow also destroys modeless dialog boxes created by the CreateDialog function.

BOOL DestroyWindow(

HWND  hWnd	// handle of window to destroy
);
Parameters

hWnd

Identifies the window to be destroyed.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

A thread cannot use DestroyWindow to destroy a window created by a different thread.

If the window being destroyed is a child window that does not have the WS_EX_NOPARENTNOTIFY style, a WM_PARENTNOTIFY message is sent to the parent.

See Also

CreateDialog, CreateWindow, CreateWindowEx, WM_DESTROY, WM_NCDESTROY, WM_PARENTNOTIFY


DeviceCapabilities
DeviceCapabilities  Overview  Group

The DeviceCapabilities function retrieves the capabilities of a printer device driver.

DWORD DeviceCapabilities(

LPCTSTR  pDevice,	// pointer to a printer-name string
LPCTSTR  pPort,	// pointer to a port-name string
WORD  fwCapability,	// device capability to query
LPTSTR  pOutput,	// pointer to the output
CONST DEVMODE *  pDevMode	// pointer to structure with device data
);
Parameters

pDevice

Pointer to a null-terminated string that contains the name of the printer. Note that this is the name of the printer, not of the printer driver.

pPort

Pointer to a null-terminated string that contains the name of the port to which the device is connected, such as "LPT1".

fwCapability

Specifies the capabilities to query. This parameter can be one of the following values:

Value	Meaning
DC_BINADJUST	Windows 95 only: Retrieves the page positioning for the paper source specified in the DEVMODE structure pointed to by pdevMode. The return value can be one of the following:
	DCBA_FACEUPNONE
	DCBA_FACEUPCENTER
	DCBA_FACEUPLEFT
	DCBA_FACEUPRIGHT
	DCBA_FACEDOWNNONE
	DCBA_FACEDOWNCENTER
	....DCBA_FACEDOWNLEFT
	DCBA_FACEDOWNRIGHT
DC_BINNAMES	Copies an array containing a list of the names of the paper bins. This array is in the form char PaperNames[cBinMax][cchBinName] where cchBinName is 24. If the pOutput parameter is NULL, the return value is the number of bin entries required. Otherwise, the return value is the number of bins copied.
DC_BINS	Retrieves a list of available bins. The function copies the list to the pOutput parameter as a WORD array. If pOutput is NULL, the function returns the number of supported bins to allow the application the opportunity to allocate a buffer with the correct size. For more information about these bins, see the description of the dmDefaultSource member of the DEVMODE structure.
DC_COPIES	Returns the number of copies the device can print.
DC_DRIVER	Returns the version number of the printer driver.
DC_DATATYPE_PRODUCED	Windows 95 only: The return value is the number of datatypes supported by the printer driver. If the function returns -1, the driver understands the "RAW" datatype only. The names of the supported datatypes are copied to an array. Use the names in the DOCINFO structure when calling the StartDoc function to specify the datatype.
DC_DUPLEX	Returns the level of duplex support. The function returns 1 if the printer is capable of duplex printing. Otherwise, the return value is zero.
DC_EMF_COMPLIANT	Windows 95 only: Determines if a printer driver supports enhanced metafile (EMF). A return value of 1 means the driver supports EMF. A return value of -1 means that the driver does not support EMF
DC_ENUMRESOLUTIONS	Returns a list of available resolutions. If pOutput is NULL, the function returns the number of available resolution configurations. Resolutions are represented by pairs of LONG integers representing the horizontal and vertical resolutions (specified in dots per inch).
DC_EXTRA	Returns the number of bytes required for the device-specific portion of the DEVMODE structure for the printer driver.
DC_FIELDS	Returns the dmFields member of the printer driver's DEVMODE structure. The dmFields member indicates which members in the device-independent portion of the structure are supported by the printer driver.
DC_FILEDEPENDENCIES	Returns a list of files that also need to be loaded when a driver is installed. If the pOutput parameter is NULL, the function returns the number of files. Otherwise, pOutput points to an array of filenames in the form char[chFileName, 64]. Each filename is a null-terminated string.
DC_MAXEXTENT	Returns a POINT structure containing the maximum paper size that the dmPaperLength and dmPaperWidth members of the printer driver's DEVMODE structure can specify.
DC_MINEXTENT	Returns a POINT structure containing the minimum paper size that the dmPaperLength and dmPaperWidth members of the printer driver's DEVMODE structure can specify.
DC_ORIENTATION	Returns the relationship between portrait and landscape orientations for a device, in terms of the number of degrees that portrait orientation is rotated counterclockwise to produce landscape orientation. The return value can be one of the following:
Value	Meaning
0	No landscape orientation.
90	Portrait is rotated 90 degrees to produce landscape. (For example, Hewlett-Packard PCL printers.)
270	Portrait is rotated 270 degrees to produce landscape. (For example, dot-matrix printers.)
DC_PAPERNAMES	Retrieves a list of supported paper names (for example, Letter or Legal). If the pOutput parameter is NULL, the function returns the number of paper sizes available. Otherwise, pOutput points to an array for the paper names in the form char[cPaperNames, 64]. Each paper name is a null-terminated string.
DC_PAPERS	Retrieves a list of supported paper sizes. The function copies the list to pOutput as a WORD array and returns the number of entries in the array. If pOutput is NULL, the function returns the number of supported paper sizes to allow the application the opportunity to allocate a buffer with the correct size. For more information on paper sizes, see the description of the dmPaperSize member of the DEVMODE structure.
DC_PAPERSIZE	Copies the dimensions of all supported paper sizes, in tenths of a millimeter, to an array of POINT structures pointed to by the pOutput parameter. The width (x-dimension) and length (y-dimension) of a paper size are returned as if the paper were in the DMORIENT_PORTRAIT orientation.
DC_SIZE	Returns the dmSize member of the printer driver's DEVMODE structure.
DC_TRUETYPE	Retrieves the abilities of the driver to use TrueType fonts. For DC_TRUETYPE, the pOutput parameter should be NULL. The return value can be one or more of the following:
Value	Meaning
DCTT_BITMAP	Device can print TrueType fonts as graphics. (For example, dot-matrix and PCL printers.)
DCTT_DOWNLOAD	Device can download TrueType fonts. (For example, PCL and PostScript printers.)
DCTT_DOWNLOAD_ OUTLINE	Windows 95 only: Device can download outline TrueType fonts.
DCTT_SUBDEV	Device can substitute device fonts for TrueType fonts. (For example, PostScript printers.)
DC_VERSION	Returns the specification version to which the printer driver conforms.
pOutput

Pointer to an array of bytes. The format of the array depends on the setting of the fwCapability parameter. If pOutput is zero, DeviceCapabilities returns the number of bytes required for the output data.

pDevMode

Pointer to a DEVMODE structure. If this parameter is NULL, DeviceCapabilities retrieves the current default initialization values for the specified printer driver. Otherwise, the function retrieves the values contained in the structure to which pDevMode points.

Return Value

If the function succeeds, the return value depends on the setting of the fwCapability parameter.

If the function fails, the return value is −1.

Remarks

In previous versions of Windows, the DeviceCapabilities function was implemented in the printer driver and you needed to call the LoadLibrary and GetProcAddress functions to get a pointer to the function. This is no longer necessary since DeviceCapabilities is part of the Win32 API and you can call it directly. You should not call LoadLibrary on the printer driver.

The DEVMODE structure pointed to by the pDevMode parameter may be obtained by calling the DocumentProperties function.

See Also

DEVMODE, DocumentProperties, GetDeviceCaps, GetProcAddress, LoadLibrary, POINT


DeviceIoControl
DeviceIoControl  QuickInfo  Overview  Group

The DeviceIoControl function sends a control code directly to a specified device driver, causing the corresponding device to perform the specified operation.

BOOL DeviceIoControl(

HANDLE  hDevice,	// handle to device of interest
DWORD  dwIoControlCode,	// control code of operation to perform
LPVOID  lpInBuffer,	// pointer to buffer to supply input data
DWORD  nInBufferSize,	// size of input buffer
LPVOID  lpOutBuffer,	// pointer to buffer to receive output data
DWORD  nOutBufferSize,	// size of output buffer
LPDWORD  lpBytesReturned,	// pointer to variable to receive output byte count
LPOVERLAPPED  lpOverlapped	// pointer to overlapped structure for asynchronous operation
);
Parameters

hDevice

Handle to the device that is to perform the operation. Call the CreateFile function to obtain a device handle.

dwIoControlCode

Specifies the control code for the operation. This value identifies the specific operation to be performed and the type of device on which the operation is to be performed. The following values are defined:

Value	Meaning
FSCTL_DISMOUNT_VOLUME	Dismounts a volume.
FSCTL_GET_COMPRESSION	Obtains the compression state of a file or directory
FSCTL_LOCK_VOLUME	Locks a volume.
FSCTL_READ_COMPRESSION	Reserved for future use.
FSCTL_SET_COMPRESSION	Sets the compression state of a file or directory.
FSCTL_UNLOCK_VOLUME	Unlocks a volume.
FSCTL_WRITE_COMPRESSION	Reserved for future use.
IOCTL_DISK_CHECK_VERIFY	Checks for change in a removable-media device.
IOCTL_DISK_EJECT_MEDIA	Ejects media from a SCSI device.
IOCTL_DISK_FORMAT_TRACKS	Formats a contiguous set of disk tracks.
IOCTL_DISK_GET_DRIVE_GEOMETRY	Obtains information on the physical disk's geometry.
IOCTL_DISK_GET_DRIVE_LAYOUT	Provides information about each partition on a disk.
IOCTL_DISK_GET_MEDIA_TYPES	Obtains information about media support.
IOCTL_DISK_GET_PARTITION_INFO	Obtains disk partition information.
IOCTL_DISK_LOAD_MEDIA	Loads media into a device.
IOCTL_DISK_MEDIA_REMOVAL	Enables or disables the media eject mechanism.
IOCTL_DISK_PERFORMANCE	Provides disk performance information.
IOCTL_DISK_REASSIGN_BLOCKS	Maps disk blocks to spare-block pool.
IOCTL_DISK_SET_DRIVE_LAYOUT	Partitions a disk.
IOCTL_DISK_SET_PARTITION_INFO	Sets the disk partition type.
IOCTL_DISK_VERIFY	Performs logical format of a disk extent.
IOCTL_SERIAL_LSRMST_INSERT	Enables or disables placement of a line and modem status data into the data stream.
For more detailed information on each control code, see its topic. In particular, each topic provides details on the usage of the lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, and lpBytesReturned parameters.

lpInBuffer

Pointer to a buffer that contains the data required to perform the operation.

This parameter can be NULL if the dwIoControlCode parameter specifies an operation that does not require input data.

nInBufferSize

Specifies the size, in bytes, of the buffer pointed to by lpInBuffer.

lpOutBuffer

Pointer to a buffer that receives the operation's output data.

This parameter can be NULL if the dwIoControlCode parameter specifies an operation that does not produce output data.

nOutBufferSize

Specifies the size, in bytes, of the buffer pointed to by lpOutBuffer.

lpBytesReturned

Pointer to a variable that receives the size, in bytes, of the data stored into the buffer pointed to by lpOutBuffer.

This parameter cannot be NULL. Even when an operation produces no output data, and lpOutBuffer can be NULL, the DeviceIoControl function makes use of the variable pointed to by lpBytesReturned. After such an operation, the value of the variable is without meaning.

lpOverlapped

Pointer to an OVERLAPPED structure to be used for asynchronous operations.

This parameter is ignored if the handle identified by hDevice was opened without specifying the FILE_FLAG_OVERLAPPED flag.

This parameter can be NULL if an overlapped (asynchronous) operation is not desired.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

If the lpOverlapped parameter is NULL or the handle identified by hDevice was opened without specifying the FILE_FLAG_OVERLAPPED flag, the DeviceIoControl function does not return until the operation has been completed, or an error occurs.

If the lpOverlapped parameter points to an OVERLAPPED structure and the FILE_FLAG_OVERLAPPED flag was specified when the hDevice handle was opened, DeviceIoControl is performed as an overlapped (asynchronous) operation. In this case, the OVERLAPPED structure must contain a handle to a manual-reset event object (created by using the CreateEvent function). For more information on manual-reset event objects, see Synchronization.

If the overlapped operation cannot be completed immediately, the function returns FALSE, and GetLastError returns the ERROR_IO_PENDING value, indicating that the operation is executing in the background. When this happens, the operating system sets the event object in the OVERLAPPED structure to the nonsignaled state before DeviceIoControl returns. The system then sets the event object to the signaled state when the operation has been completed. The calling thread can use any of the wait functions to determine the state of the event object, then use the GetOverlappedResult function to determine the results of the operation. The GetOverlappedResult function reports the success or failure of the operation and the number of bytes returned in the lpOutBuffer buffer.

See Also

CreateEvent, CreateFile, GetOverlappedResult, OVERLAPPED, WaitForMultipleObjects, WaitForSingleObject


DialogBox
DialogBox  QuickInfo  Overview  Group

The DialogBox function creates a modal dialog box from a dialog box template resource. DialogBox does not return control until the specified callback function terminates the modal dialog box by calling the EndDialog function.

int DialogBox(

HANDLE  hInstance,	// handle of application instance
LPCTSTR  lpTemplate,	// identifies dialog box template
HWND  hWndParent,	// handle of owner window
DLGPROC  lpDialogFunc	// address of dialog box procedure
);
Parameters

hInstance

Identifies an instance of the module whose executable file contains the dialog box template.

lpTemplate

Identifies the dialog box template. This parameter is either the address of a null-terminated character string that specifies the name of the dialog box template or an integer value that specifies the resource identifier of the dialog box template. If the parameter specifies a resource identifier, its high-order word must be zero and its low-order word must contain the identifier. You can use the MAKEINTRESOURCE macro to create this value.

hWndParent

Identifies the window that owns the dialog box.

lpDialogFunc

Points to the dialog box procedure. For more information about the dialog box procedure, see the DialogProc callback function.

Return Value

If the function succeeds, the return value is the nResult parameter in the call to the EndDialog function used to terminate the dialog box.

If the function fails, the return value is −1.

Remarks

The DialogBoxIndirect function uses the CreateWindowEx function to create the dialog box. DialogBox then sends a WM_INITDIALOG message (and a WM_SETFONT message if the template specifies the DS_SETFONT style) to the dialog box procedure. The function displays the dialog box (regardless of whether the template specifies the WS_VISIBLE style), disables the owner window, and starts its own message loop to retrieve and dispatch messages for the dialog box.

When the dialog box procedure calls the EndDialog function, DialogBox destroys the dialog box, ends the message loop, enables the owner window (if previously enabled), and returns the nResult parameter given by the dialog box procedure when it called EndDialog.

Windows 95 only: The system can support a maximum of 16,364 window handles.

See Also

CreateDialog, CreateWindowEx, DialogBoxIndirect, DialogBoxIndirectParam, DialogBoxParam, DialogProc, EndDialog, MAKEINTRESOURCE, WM_INITDIALOG, WM_SETFONT


DialogBoxIndirect
DialogBoxIndirect  QuickInfo  Overview  Group

The DialogBoxIndirect function creates a modal dialog box from a dialog box template in memory. The DialogBoxIndirect function does not return control until the specified callback function terminates the modal dialog box by calling the EndDialog function.

int DialogBoxIndirect(

HANDLE  hInstance,	// handle of application instance
LPDLGTEMPLATE  lpTemplate,	// identifies dialog box template
HWND  hWndParent,	// handle of owner window
DLGPROC  lpDialogFunc	// address of dialog box procedure
);
Parameters

hInstance

Identifies the instance of the module that creates the dialog box.

lpTemplate

Specifies the address of a global memory object that contains a dialog box template used to create the dialog box. The template is in the form of a DLGTEMPLATE structure followed by one or more DLGITEMTEMPLATE structures.

hWndParent

Identifies the window that owns the dialog box.

lpDialogFunc

Points to the dialog box procedure. For more information about the dialog box procedure, see the description of the DialogProc callback function.

Return Value

If the function succeeds, the return value is the nResult parameter given in the call to the EndDialog function used to terminate the dialog box.

If the function fails, the return value is −1.

Remarks

The DialogBoxIndirect function uses the CreateWindowEx function to create the dialog box. DialogBoxIndirect then sends a WM_INITDIALOG message (and a WM_SETFONT message if the template specifies the DS_SETFONT style) to the dialog box procedure. The function displays the dialog box (regardless of whether the template specifies the WS_VISIBLE style), disables the owner window, and starts its own message loop to retrieve and dispatch messages for the dialog box.

When the dialog box procedure calls the EndDialog function, DialogBoxIndirect destroys the dialog box, ends the message loop, enables the owner window (if previously enabled), and returns the nResult parameter given by the dialog box procedure when it called EndDialog.

Windows 95 only: The system can support a maximum of 16,364 window handles.

See Also

CreateWindowEx, DialogBox, DialogBoxIndirectParam, DialogBoxParam, DialogProc, DLGTEMPLATE, DLGITEMTEMPLATE, EndDialog, WM_INITDIALOG, WM_SETFONT


DialogBoxIndirectParam
DialogBoxIndirectParam  QuickInfo  Overview  Group

The DialogBoxIndirectParam function creates a modal dialog box from a dialog box template in memory. Before displaying the dialog box, the function passes an application-defined value to the dialog box procedure as the lParam parameter of the WM_INITDIALOG message. An application can use this value to initialize dialog box controls.

int DialogBoxIndirectParam(

HINSTANCE  hInstance,	// handle of application instance
LPCDLGTEMPLATE  hDialogTemplate,	// identifies dialog box template
HWND  hWndParent,	// handle of owner window
DLGPROC  lpDialogFunc,	// address of dialog box procedure
LPARAM  dwInitParam	// initialization value
);
Parameters

hInstance

Identifies the instance of the module that creates the dialog box.

hDialogTemplate

Specifies the address of a global memory object that contains a dialog box template used to create the dialog box. The template is in the form of a DLGTEMPLATE structure followed by one or more DLGITEMTEMPLATE structures.

hWndParent

Identifies the window that owns the dialog box.

lpDialogFunc

Points to the dialog box procedure. For more information about the dialog box procedure, see the DialogProc callback function.

dwInitParam

Specifies the value to pass to the dialog box in the lParam parameter of the WM_INITDIALOG message.

Return Value

If the function succeeds, the return value is the nResult parameter given in the call to the EndDialog function used to terminate the dialog box.

If the function fails, the return value is −1.

Remarks

The DialogBoxIndirectParam function uses the CreateWindowEx function to create the dialog box. DialogBoxIndirectParam then sends a WM_INITDIALOG message (and a WM_SETFONT message if the template specifies the DS_SETFONT style) to the dialog box procedure. The function displays the dialog box (regardless of whether the template specifies the WS_VISIBLE style), disables the owner window, and starts its own message loop to retrieve and dispatch messages for the dialog box.

When the dialog box procedure calls the EndDialog function, DialogBoxIndirectParam destroys the dialog box, ends the message loop, enables the owner window (if previously enabled), and returns the nResult parameter given by the dialog box procedure when it called EndDialog.

Windows 95 only: The system can support a maximum of 16,364 window handles.

See Also

CreateWindowEx, DialogBox, DialogBoxIndirect, DialogBoxParam, DialogProc, DLGTEMPLATE, DLGITEMTEMPLATE, EndDialog, WM_INITDIALOG, WM_SETFONT


DialogBoxParam
DialogBoxParam  QuickInfo  Overview  Group

The DialogBoxParam function creates a modal dialog box from a dialog box template resource. Before displaying the dialog box, the function passes an application-defined value to the dialog box procedure as the lParam parameter of the WM_INITDIALOG message. An application can use this value to initialize dialog box controls.

int DialogBoxParam(

HINSTANCE  hInstance,	// handle of application instance
LPCTSTR  lpTemplateName,	// identifies dialog box template
HWND  hWndParent,	// handle of owner window
DLGPROC  lpDialogFunc,	// address of dialog box procedure
LPARAM  dwInitParam	// initialization value
);
Parameters

hInstance

Identifies an instance of the module whose executable file contains the dialog box template.

lpTemplateName

Identifies the dialog box template. This parameter is either the address of a null-terminated character string that specifies the name of the dialog box template or an integer value that specifies the resource identifier of the dialog box template. If the parameter specifies a resource identifier, its high-order word must be zero and its low-order word must contain the identifier. You can use the MAKEINTRESOURCE macro to create this value.

hWndParent

Identifies the window that owns the dialog box.

lpDialogFunc

Points to the dialog box procedure. For more information about the dialog box procedure, see the DialogProc callback function.

dwInitParam

Specifies the value to pass to the dialog box in the lParam parameter of the WM_INITDIALOG message.

Return Value

If the function succeeds, the return value is the value of the nResult parameter given in the call to the EndDialog function used to terminate the dialog box.

If the function fails, the return value is −1.

Remarks

The DialogBoxParam function uses the CreateWindowEx function to create the dialog box. DialogBoxParam then sends a WM_INITDIALOG message (and a WM_SETFONT message if the template specifies the DS_SETFONT style) to the dialog box procedure. The function displays the dialog box (regardless of whether the template specifies the WS_VISIBLE style), disables the owner window, and starts its own message loop to retrieve and dispatch messages for the dialog box.

When the dialog box procedure calls the EndDialog function, DialogBoxParam destroys the dialog box, ends the message loop, enables the owner window (if previously enabled), and returns the nResult parameter given by the dialog box procedure when it called EndDialog.

Windows 95 only: The system can support a maximum of 16,364 window handles.

See Also

CreateWindowEx, DialogBox, DialogBoxIndirect, DialogBoxIndirectParam, DialogProc, EndDialog, MAKEINTRESOURCE, WM_INITDIALOG, WM_SETFONT


DialogProc
DialogProc  QuickInfo  Overview  Group

The DialogProc function is an application-defined callback function that processes messages sent to a modal or modeless dialog box.

BOOL CALLBACK DialogProc(

HWND  hwndDlg,	// handle of dialog box
UINT  uMsg,	// message
WPARAM  wParam,	// first message parameter
LPARAM  lParam	// second message parameter
);
Parameters

hwndDlg

Identifies the dialog box.

uMsg

Specifies the message.

wParam

Specifies additional message-specific information.

lParam

Specifies additional message-specific information.

Return Value

Except in response to the WM_INITDIALOG message, the dialog box procedure should return nonzero if it processes the message, and zero if it does not. In response to a WM_INITDIALOG message, the dialog box procedure should return zero if it calls the SetFocus function to set the focus to one of the controls in the dialog box. Otherwise, it should return nonzero, in which case the system sets the focus to the first control in the dialog box that can be given the focus.

Remarks

You should use the dialog box procedure only if you use the dialog box class for the dialog box. This is the default class and is used when no explicit class is given in the dialog box template. Although the dialog box procedure is similar to a window procedure, it must not call the DefWindowProc function to process unwanted messages. Unwanted messages are processed internally by the dialog box window procedure.

DialogProc is a placeholder for the application-defined function name.

See Also

CreateDialog, CreateDialogIndirect, CreateDialogIndirectParam, CreateDialogParam, DefWindowProc, DialogBox, DialogBoxIndirect, DialogBoxIndirectParam, DialogBoxParam, SetFocus, WM_INITDIALOG


DisableThreadLibraryCalls
DisableThreadLibraryCalls  QuickInfo  Overview  Group

The DisableThreadLibraryCalls function disables the DLL_THREAD_ATTACH and DLL_THREAD_DETACH notifications for the dynamic-link library (DLL) specified by hLibModule. This can reduce the size of the working code set for some applications.

BOOL DisableThreadLibraryCalls(

HMODULE  hLibModule	// dynamic-link library for which calls are to be disabled
);
Parameters

hLibModule

Specifies the dynamic-link library module for which the DLL_THREAD_ATTACH and DLL_THREAD_DETACH notifications are to be disabled.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. The DisableThreadLibraryCalls function fails if the DLL specified by hLibModule has active static thread local storage, or if hLibModule is an invalid module handle. To get extended error information, call GetLastError.

Remarks

The DisableThreadLibraryCalls function lets a DLL disable the DLL_THREAD_ATTACH and DLL_THREAD_DETACH notification calls. This can be a useful optimization for multithreaded applications that have many DLLs, frequently create and delete threads, and whose DLLs do not need these thread-level notifications of attachment/detachment. A remote procedure call (RPC) server application is an example of such an application. In these sorts of applications, DLL initialization routines often remain in memory to service DLL_THREAD_ATTACH and DLL_THREAD_DETACH notifications. By disabling the notifications, the DLL initialization code is not paged in because a thread is created or deleted, thus reducing the size of the application's working code set. To implement the optimization, modify a DLL's DLL_PROCESS_ATTACH code to call DisableThreadLibraryCalls.

See Also

FreeLibraryAndExitThread


DisconnectNamedPipe
DisconnectNamedPipe  QuickInfo  Overview  Group

The DisconnectNamedPipe function disconnects the server end of a named pipe instance from a client process.

BOOL DisconnectNamedPipe(

HANDLE  hNamedPipe	// handle of named pipe
);
Parameters

hNamedPipe

Identifies an instance of a named pipe. This handle must be created by the CreateNamedPipe function.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

If the client end of the named pipe is open, the DisconnectNamedPipe function forces that end of the named pipe closed. The client receives an error the next time it attempts to access the pipe. A client that is forced off a pipe by DisconnectNamedPipe must still use the CloseHandle function to close its end of the pipe.

When the server process disconnects a pipe instance, any unread data in the pipe is discarded. Before disconnecting, the server can make sure data is not lost by calling the FlushFileBuffers function, which does not return until the client process has read all the data.

The server process must call DisconnectNamedPipe to disconnect a pipe handle from its previous client before the handle can be connected to another client by using the ConnectNamedPipe function.

See Also

CloseHandle, ConnectNamedPipe, CreateNamedPipe, FlushFileBuffers


DispatchMessage
DispatchMessage  QuickInfo  Overview  Group

The DispatchMessage function dispatches a message to a window procedure. It is typically used to dispatch a message retrieved by the GetMessage function.

LONG DispatchMessage(

CONST MSG  * lpmsg	// address of structure with message
);
Parameters

lpmsg

Points to an MSG structure that contains the message.

Return Value

The return value specifies the value returned by the window procedure. Although its meaning depends on the message being dispatched, the return value generally is ignored.

Remarks

The MSG structure must contain valid message values. If the lpmsg parameter points to a WM_TIMER message and the lParam parameter of the WM_TIMER message is not NULL, lParam points to a function that is called instead of the window procedure.

See Also

GetMessage, MSG, PeekMessage, PostAppMessage, PostMessage, TranslateMessage, WM_TIMER


DlgDirList
DlgDirList  QuickInfo  Overview  Group

The DlgDirList function fills the specified list box with the names of all files matching the specified path or filename.

int DlgDirList(

HWND  hDlg,	// handle of dialog box with list box
LPTSTR  lpPathSpec,	// address of path or filename string
int  nIDListBox,	// identifier of list box
int  nIDStaticPath,	// identifier of static control
UINT  uFileType	// file attributes to display
);
Parameters

hDlg

Identifies the dialog box that contains the list box.

lpPathSpec

Points to a null-terminated string that contains the path or filename. DlgDirList modifies this string, which should be long enough to contain the modifications. For more information about this parameter, see the Remarks section.

nIDListBox

Specifies the identifier of a list box. If this parameter is zero, DlgDirList assumes that no list box exists and does not attempt to fill one.

nIDStaticPath

Specifies the identifier of the static control used for displaying the current drive and directory. If this parameter is zero, DlgDirList assumes that no such control is present.

uFileType

Specifies attributes of the filenames to be displayed. This parameter must be one or more of the following values:

Value	Description
DDL_ARCHIVE	Includes archived files.
DDL_DIRECTORY	Includes subdirectories. Subdirectory names are enclosed in square brackets ([ ]).
DDL_DRIVES	Includes drives. Drives are listed in the form [-x-], where x is the drive letter.
DDL_EXCLUSIVE	Includes only files with the specified attributes. By default, read-write files are listed even if DDL_READWRITE is not specified.
DDL_HIDDEN	Includes hidden files.
DDL_READONLY	Includes read-only files.
DDL_READWRITE	Includes read-write files with no additional attributes.
DDL_SYSTEM	Includes system files.
DDL_POSTMSGS	Posts messages to the application's message queue. By default, DlgDirList sends messages directly to the dialog box procedure.
Return Value

If a listing is made — even an empty listing — the return value is nonzero. If the input string does not contain a valid search path, the return value is zero.

Remarks

If you specify a zero-length string for the lpPathSpec parameter or if you specify only a directory name with no filename, the string will be changed to *.*

The lpPathSpec parameter has the following form:

[drive:] [[\u]directory[\idirectory]\u] [filename]

In this example, drive is a drive letter, directory is a valid directory name, and filename is a valid filename that must contain at least one wildcard (? or *).

If lpPathSpec includes a drive or directory name, or both, the current drive and directory are changed to the specified drive and directory before the list box is filled. The static control identified by the nIDStaticPath parameter is also updated with the new drive or directory name, or both.

After the list box is filled, DlgDirList updates lpPathSpec by removing the drive or directory portion, or both, of the path and filename.

DlgDirList sends the LB_RESETCONTENT and LB_DIR messages to the list box.

See Also

DlgDirListComboBox, DlgDirSelectComboBoxEx, DlgDirSelectEx


DlgDirListComboBox
DlgDirListComboBox  QuickInfo  Overview  Group

The DlgDirListComboBox function fills the specified combo box with a directory listing. It fills the list with the names of all files, drives, and subdirectories that match the specified attributes and path string.

int DlgDirListComboBox(

HWND  hDlg,	// handle of dialog box with combo box
LPTSTR  lpPathSpec,	// address of path or filename string
int  nIDComboBox,	// identifier of combo box
int  nIDStaticPath,	// identifier of static control
UINT  uFiletype	// file attributes to display
);
Parameters

hDlg

Identifies the dialog box that contains the combo box.

lpPathSpec

Points to a null-terminated string of the following form:

[drive:][\]][directory\[...]][filename]

If the specified string includes a drive or directory path, the DlgDirListComboBox function changes the current drive and directory before filling the list. After the list is filled, the drive and directory path are removed from the string specified by the lpPathSpec parameter.

nIDComboBox

Specifies the identifier of a combo box control in a dialog box. If nIDComboBox is zero, the DlgDirListComboBox function assumes no combo box exists and does not attempt to fill it.

nIDStaticPath

Specifies the identifier of the static text control in which the DlgDirListComboBox function is to display the current directory. If nIDStaticPath is zero, DlgDirListComboBox assumes no such control is present.

uFiletype

Specifies the attributes of the files to be displayed. It can be any combination of the following values:

Value	Meaning
DDL_ARCHIVE	Includes archived files.
DDL_DIRECTORY	Includes subdirectories. Subdirectory names are enclosed in square brackets ([ ]).
DDL_DRIVES	Includes drives. Drives are listed in the form [-x-], where x is the drive letter.
DDL_EXCLUSIVE	Includes only files with the specified attributes. By default, read-write files are listed even if DDL_READWRITE is not specified.
DDL_HIDDEN	Includes hidden files.
DDL_READONLY	Includes read-only files.
DDL_READWRITE	Includes read-write files with no additional attributes.
DDL_SYSTEM	Includes system files.
DDL_POSTMSGS	Posts messages to the application's message queue. By default, the DlgDirList function sends messages directly to the dialog box procedure.
Return Value

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. For example, if the string specified by lpPathSpec is not a valid path, the function fails. To get extended error information, call GetLastError.

Remarks

If the lpszPathSpec parameter points to a zero-length string or to a string specifying a drive, directory, or both — but no filename — the filename *.* (wildcards) is assumed.

Windows NT:

The directory listing displays long filenames, if any.

Windows 95:

The directory listing displays short filenames (the 8.3 form). You can use the SHGetFileInfo or GetFullPathName functions to get the corresponding long filename.

See Also

DlgDirList, DlgDirSelectComboBoxEx, GetFullPathName, SHGetFileInfo


DlgDirSelect
DlgDirSelect  Overview  Group

The DlgDirSelect function is not implemented in the Win32 API. Win32-based applications should use the DlgDirSelectEx function.


DlgDirSelectComboBox
DlgDirSelectComboBox  Overview  Group

The DlgDirSelectComboBox function is not implemented in the Win32 API. Win32-based applications should use the DlgDirSelectComboBoxEx function.


DlgDirSelectComboBoxEx
DlgDirSelectComboBoxEx  QuickInfo  Overview  Group

The DlgDirSelectComboBoxEx function retrieves the current selection from a combo box filled by using the DlgDirListComboBox function. The selection is interpreted as a drive letter, a file, or a directory name.

BOOL DlgDirSelectComboBoxEx(

HWND  hDlg,	// handle of dialog box with list box
LPTSTR  lpString,	// address of buffer for path string
int  nCount,	// number of characters in path string
int  nIDComboBox	// identifier of combo box
);
Parameters

hDlg

Identifies the dialog box that contains the combo box.

lpString

Points to the buffer that is to receive the selected path.

nCount

Specifies the length, in characters, of the buffer pointed to by the lpString parameter.

nIDComboBox

Specifies the integer identifier of the combo box control in the dialog box.

Return Value

If the current selection is a directory name, the return value is nonzero; otherwise, it is zero. To get extended error information, call GetLastError.

Remarks

If the current selection specifies a directory name or drive letter, the DlgDirSelectComboBoxEx function removes the enclosing square brackets (and hyphens for drive letters) so the name or letter is ready to be inserted into a new path or filename. If there is no selection, the contents of the buffer pointed to by lpString do not change.

The DlgDirSelectComboBox function does not allow more than one filename to be returned from a combo box.

DlgDirSelectComboBoxEx sends CB_GETCURSEL and CB_GETLBTEXT messages to the combo box.

In the Win32 API, you can use this function with all three types of combo boxes (CBS_SIMPLE, CBS_DROPDOWN, and CBS_DROPDOWNLIST).

See Also

CB_GETCURSEL, CB_GETLBTEXT DlgDirListComboBox, DlgDirSelectEx


DlgDirSelectEx
DlgDirSelectEx  QuickInfo  Overview  Group

The DlgDirSelectEx function retrieves the current selection from a single-selection list box. It assumes that the list box has been filled by the DlgDirList function and that the selection is a drive letter, filename, or directory name.

BOOL DlgDirSelectEx(

HWND  hDlg,	// handle of dialog box with list box
LPTSTR  lpString,	// address of buffer for path string
int  nCount,	// number of characters in path string
int  nIDListBox	// identifier of list box
);
Parameters

hDlg

Identifies the dialog box that contains the list box.

lpString

Points to a buffer that is to receive the selected path.

nCount

Specifies the length, in characters, of the buffer pointed to by lpString.

nIDListBox

Specifies the integer identifier of a list box in the dialog box.

Return Value

If the current selection is a directory name, the return value is nonzero; otherwise, it is zero. To get extended error information, call GetLastError.

Remarks

The DlgDirSelectEx function copies the selection to the buffer pointed to by the lpString parameter. If the current selection is a directory name or drive letter, DlgDirSelectEx removes the enclosing square brackets (and hyphens, for drive letters), so that the name or letter is ready to be inserted into a new path. If there is no selection, lpString does not change.

DlgDirSelectEx sends LB_GETCURSEL and LB_GETTEXT messages to the list box. The function does not allow more than one filename to be returned from a list box. The list box must not be a multiple-selection list box. If it is, this function does not return a zero value and lpString remains unchanged.

See Also

DlgDirList, DlgDirListComboBox, DlgDirSelectComboBoxEx, LB_GETCURSEL, LB_GETTEXT


DllEntryPoint
DllEntryPoint  QuickInfo  Overview  Group

The DllEntryPoint function is an optional method of entry into a dynamic-link library (DLL). If the function is used, it is called by the system when processes and threads are initialized and terminated, or upon calls to the LoadLibrary and FreeLibrary functions. DllEntryPoint is a placeholder for the library-defined function name. The actual name must be specified on the linker command line by the -entry switch.

BOOL WINAPI DllEntryPoint(

HINSTANCE  hinstDLL,	// handle of DLL module
DWORD  fdwReason,	// reason for calling function
LPVOID  lpvReserved	// reserved
);
Parameters

hinstDLL

Identifies a handle to the DLL. This handle can be used in subsequent calls to the GetModuleFileName function and other module functions.

fdwReason

Specifies a flag indicating why the DLL entry-point function is being called. This parameter can be one of the following values:

Value	Meaning
DLL_PROCESS_ATTACH
	Indicates that the DLL is attaching to the address space of the current process as a result of the process starting up or as a result of a call to LoadLibrary. DLLs can use this opportunity to initialize any instance data or to use the TlsAlloc function to allocate a thread local storage (TLS) index.
	During initial process startup or after a call to LoadLibrary, the operating system scans the list of loaded DLLs for the process. For each DLL that has not already been called with the DLL_PROCESS_ATTACH value, the system calls the DLL's entry-point function. This call is made in the context of the thread that caused the process address space to change, such as the primary thread of the process or the thread that called LoadLibrary.
DLL_THREAD_ATTACH
	Indicates that the current process is creating a new thread. When this occurs, the system calls the entry-point function of all DLLs currently attached to the process. The call is made in the context of the new thread. DLLs can use this opportunity to initialize a TLS slot for the thread. A thread calling the DLL entry-point function with the DLL_PROCESS_ATTACH value does not call the DLL entry-point function with the DLL_THREAD_ATTACH value.
	Note that a DLL's entry-point function is called with this value only by threads created after the DLL is attached to the process. When a DLL is attached by LoadLibrary, existing threads do not call the entry-point function of the newly loaded DLL.
DLL_THREAD_DETACH
	Indicates that a thread is exiting cleanly. If the DLL has stored a pointer to allocated memory in a TLS slot, it uses this opportunity to free the memory. The operating system calls the entry-point function of all currently loaded DLLs with this value. The call is made in the context of the exiting thread. There are cases in which the entry-point function is called for a terminating thread even if the DLL never attached to the thread — for example, the entry-point function was never called with the DLL_THREAD_ATTACH value in the context of the thread in either of these two situations:
•	The thread was the initial thread in the process, so the system called the entry-point function with the DLL_PROCESS_ATTACH value.

•	The thread was already running when a call to the LoadLibrary function was made, so the system never called the entry-point function for it.

DLL_PROCESS_DETACH
	Indicates that the DLL is detaching from the address space of the calling process as a result of either a clean process exit or of a call to FreeLibrary. The DLL can use this opportunity to call the TlsFree function to free any TLS indices allocated by using TlsAlloc and to free any thread local data. When a DLL detaches from a process as a result of process termination or as a result of a call to FreeLibrary, the operating system does not call the DLL's entry-point function with the DLL_THREAD_DETACH value for the individual threads of the process. The DLL is only given DLL_PROCESS_DETACH notification. DLLs can take this opportunity to clean up all resources for all threads attached and known to the DLL.
lpvReserved

Specifies further aspects of DLL initialization and cleanup.

If fdwReason is DLL_PROCESS_ATTACH, lpvReserved is NULL for dynamic loads and non-NULL for static loads.

If fdwReason is DLL_PROCESS_DETACH, lpvReserved is NULL if DllEntryPoint has been called by using FreeLibrary and non-NULL if DllEntryPoint has been called during process termination.

Return Value

When the system calls the DllEntryPoint function with the DLL_PROCESS_ATTACH value, the function returns TRUE if it succeeds or FALSE if initialization fails. If the return value is FALSE when DllEntryPoint is called because the process uses the LoadLibrary function, LoadLibrary returns NULL. If the return value is FALSE when DllEntryPoint is called during process initialization, the process terminates with an error. To get extended error information, call GetLastError.

When the system calls the DllEntryPoint function with any value other than DLL_PROCESS_ATTACH, the return value is ignored.

See Also

FreeLibrary, GetModuleFileName, LoadLibrary, TlsAlloc, TlsFree


DocumentProperties
DocumentProperties  QuickInfo  Overview  Group

The DocumentProperties function retrieves or modifies printer initialization information or displays a printer-configuration dialog box for the specified printer.

LONG DocumentProperties(

HWND  hWnd,	// handle of window that displays dialog box
HANDLE  hPrinter,	// handle of printer object
LPTSTR  pDeviceName,	// address of device name
PDEVMODE  pDevModeOutput,	// address of modified device mode structure
PDEVMODE  pDevModeInput,	// address of original device mode structure
DWORD  fMode	// mode flag
);
Parameters

hWnd

Identifies the parent window of the printer-configuration dialog box.

hPrinter

Identifies a printer object.

pDeviceName

Points to a null-terminated string that specifies the name of the device for which the printer-configuration dialog box should be displayed.

pDevModeOutput

Points to a DEVMODE structure that receives the printer configuration data specified by the user.

pDevModeInput

Points to a DEVMODE structure used to initialize the dialog box controls.

fMode

Specifies a mask of values that determines the operations the function performs. If this parameter is zero, the DocumentProperties function returns the number of bytes required by the printer driver's DEVMODE data structure. Otherwise, use one or more of the following constants to construct a value for this parameter; note, however, that in order to change the print settings, an application must specify at least one input value and one output value:

Value	Meaning
DM_IN_BUFFER	Input value. Before prompting, copying, or updating, the function merges the printer driver's current print settings with the settings in the DEVMODE structure specified by the pDevModeInput parameter. The function updates the structure only for those members specified by the DEVMODE structure's dmFields member. This value is also defined as DM_MODIFY. In cases of conflict during the merge, the settings in the DEVMODE structure specified by pDevModeInput override the printer driver's current print settings.
DM_IN_PROMPT	Input value. The function presents the printer driver's Print Setup dialog box and then changes the settings in the printer's DEVMODE data structure to those values specified by the user. This value is also defined as DM_PROMPT.
DM_OUT_BUFFER	Output value. The function writes the printer driver's current print settings, including private data, to the DEVMODE data structure specified by the pDevModeOutput parameter. The caller must allocate a buffer sufficiently large to contain the information. If the bit DM_OUT_BUFFER sets is clear, the pDevModeOutput parameter can be NULL. This value is also defined as DM_COPY.
Return Value

If the fMode parameter is zero, the return value is the size of the buffer required to contain the printer driver initialization data. Note that this buffer can be larger than a DEVMODE structure if the printer driver appends private data to the structure.

If the function displays the initialization dialog box, the return value is either IDOK or IDCANCEL, depending on which button the user selects.

If the function does not display the dialog box and is successful, the return value is IDOK.

If the function fails, the return value is less than zero.

Remarks

The printer object handle identified by the hPrinter parameter can be obtained by calling the OpenPrinter function.

The string pointed to by the pDeviceName parameter can be obtained by calling the GetPrinter function.

Note that the DEVMODE structure actually used by a printer driver contains the device-independent part (as defined above) followed by a driver-specific part that varies in size and content with each driver and driver version. Because of this driver dependence, it is very important for applications to query the driver for the correct size of the DEVMODE structure before allocating a buffer for it.

To make changes to print settings that are local to an application, an application should follow these steps:

1.	Get the number of bytes required for the full DEVMODE structure by calling DocumentProperties and specifying zero in the fMode parameter.

2.	Allocate memory for the full DEVMODE structure.

3.	Get the current printer settings by calling DocumentProperties. Pass a pointer to the DEVMODE structure allocated in Step 2 as the pDevModeOutput parameter and specify the DM_OUT_BUFFER value.

4.	Modify the appropriate members of the returned DEVMODE structure and indicate which members were changed by setting the corresponding bits in the dmFields member of the DEVMODE.

5.	Call DocumentProperties and pass the modified DEVMODE structure back as both the pDevModeInput and pDevModeOutput parameters and specify both the DM_IN_BUFFER and DM_OUT_BUFFER values (which are combined using the OR operator).

The DEVMODE structure returned by the third call to DocumentProperties can be used as an argument in a call to the CreateDC function.

To create a handle of a printer-device context using the current printer settings, you only need to call DocumentProperties twice, as described above. The first call gets the size of the full DEVMODE and the second call initializes the DEVMODE with the current printer settings. Pass the initialized DEVMODE to CreateDC to obtain the handle of the printer device context.

See Also

AdvancedDocumentProperties, CreateDC, DEVMODE, GetPrinter, OpenPrinter


DOS3Call
DOS3Call  Overview  Group

The DOS3Call function is not implemented in the Win32 API. Win32-based applications cannot call MS-DOS directly.


DosDateTimeToFileTime
DosDateTimeToFileTime  QuickInfo  Overview  Group

The DosDateTimeToFileTime function converts MS-DOS date and time values to a 64-bit file time.

BOOL DosDateTimeToFileTime(

WORD  wFatDate,	// 16-bit MS-DOS date
WORD  wFatTime,	// 16-bit MS-DOS time
LPFILETIME  lpFileTime	// address of buffer for 64-bit file time
);
Parameters

wFatDate

Specifies the MS-DOS date. The date is a packed 16-bit value with the following format:

Bits	Contents
0−4	Day of the month (1−31)
5−8	Month (1 = January, 2 = February, and so on)
9−15	Year offset from 1980 (add 1980 to get actual year)
wFatTime

Specifies the MS-DOS time. The time is a packed 16-bit value with the following format:

Bits	Contents
0−4	Second divided by 2
5−10	Minute (0−59)
11−15	Hour (0−23 on a 24-hour clock)
lpFileTime

Points to a FILETIME structure to receive the converted 64-bit file time.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

FILETIME, FileTimeToDosDateTime, FileTimeToSystemTime, SystemTimeToFileTime


DPtoLP
DPtoLP  QuickInfo  Overview  Group

The DPtoLP function converts device coordinates into logical coordinates. The conversion depends on the mapping mode of the device context (DC), the settings of the origins and extents for the window and viewport, and the world transformation.

BOOL DPtoLP(

HDC  hdc,	// handle of device context
LPPOINT  lpPoints,	// address of array of points
int  nCount	// count of points
);
Parameters

hdc

Identifies the DC.

lpPoints

Points to an array of POINT structures. The x- and y-coordinates contained in each POINT structure will be transformed.

nCount

Specifies the number of points in the array.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

This function fails if the device coordinates exceed 27 bits, or if the converted logical coordinates exceed 32 bits. In the case of such an overflow, the results for all the points are undefined.

See Also

LPtoDP, POINT


DragAcceptFiles
DragAcceptFiles  QuickInfo  Overview  Group

The DragAcceptFiles function registers whether a window accepts dropped files.

VOID DragAcceptFiles(

HWND  hWnd,	// handle of the registering window
BOOL  fAccept	// acceptance option
);
Parameters

hWnd

Identifies the window registering whether it accepts dropped files.

fAccept

Specifies whether the window identified by the hWnd parameter accepts dropped files. This value is TRUE to accept dropped files; it is FALSE to discontinue accepting dropped files.

Return Value

This function does not return a value.

Remarks

An application that calls DragAcceptFiles with the fAccept parameter set to TRUE has identified itself as able to process the WM_DROPFILES message from File Manager.

See Also

WM_DROPFILES


DragDetect
DragDetect  QuickInfo  Overview  Group

The DragDetect function captures the mouse and tracks its movement until the user releases the left button, presses the ESC key, or moves the mouse outside the "drag rectangle" around the given point. The width and height of the drag rectangle are specified by the SM_CXDRAG and SM_CYDRAG values returned by the GetSystemMetrics function.

BOOL DragDetect(

HWND  hwnd,
POINT  pt
);
hwnd

Handle of the window receiving mouse input.

pt

Initial position of the mouse, in screen coordinates. The function determines the coordinates of the drag rectangle by using this point.

Return Value

If the user moved the mouse outside of the drag rectangle while holding the left button down, the return value is TRUE.

If the user did not move the mouse outside of the drag rectangle while holding the left button down, the return value is FALSE.

Remarks

The system metrics for the drag rectangle are configurable, allowing for larger or smaller drag rectangles.

See Also

GetSystemMetrics


DragFinish
DragFinish  QuickInfo  Overview  Group

The DragFinish function releases memory that Windows allocated for use in transferring filenames to the application.

VOID DragFinish(

HDROP  hDrop	// handle of memory to free
);
Parameters

hDrop

Identifies the structure describing dropped files. This handle is retrieved from the wParam parameter of the WM_DROPFILES message.

Return Value

This function does not return a value.

See Also

WM_DROPFILES


DragQueryFile
DragQueryFile  QuickInfo  Overview  Group

The DragQueryFile function retrieves the filenames of dropped files.

UINT DragQueryFile(

HDROP  hDrop,	// handle of structure for dropped files
UINT  iFile,	// index of file to query
LPTSTR  lpszFile,	// buffer for returned filename
UINT  cch	// size of buffer for filename
);
Parameters

hDrop

Identifies the structure containing the filenames of the dropped files.

iFile

Specifies the index of the file to query. If the value of the iFile parameter is 0xFFFFFFFF, DragQueryFile returns a count of the files dropped. If the value of the iFile parameter is between zero and the total number of files dropped, DragQueryFile copies the filename with the corresponding value to the buffer pointed to by the lpszFile parameter.

lpszFile

Points to a buffer to receive the filename of a dropped file when the function returns. This filename is a null-terminated string. If this parameter is NULL, DragQueryFile returns the required size, in characters, of the buffer.

cch

Specifies the size, in characters, of the lpszFile buffer.

Return Value

When the function copies a filename to the buffer, the return value is a count of the characters copied, not including the terminating null character.

If the index value is 0xFFFFFFFF, the return value is a count of the dropped files.

If the index value is between zero and the total number of dropped files and the lpszFile buffer address is NULL, the return value is the required size, in characters, of the buffer, not including the terminating null character.

See Also

DragQueryPoint


DragQueryPoint
DragQueryPoint  QuickInfo  Overview  Group

The DragQueryPoint function retrieves the position of the mouse pointer at the time a file was dropped.

BOOL DragQueryPoint(

HDROP  hDrop,	// handle of structure for dropped file
LPPOINT  lppt	// address of structure for mouse coordinates
);
Parameters

hDrop

Identifies the structure describing the dropped file.

lppt

Points to a POINT structure that the function fills with the coordinates of the mouse pointer at the time the file was dropped.

Return Value

If the drop occurred in the client area of the window, the return value is TRUE; otherwise, it is FALSE.

The DragQueryPoint function fills the POINT structure with the coordinates of the mouse pointer at the time the user released the left mouse button. The window for which coordinates are returned is the window that received the WM_DROPFILES message.

See Also

DragQueryFile, POINT, WM_DROPFILES


DrawAnimatedRects [New - Windows 95]
DrawAnimatedRects  QuickInfo  Overview  Group

[New - Windows 95]

The DrawAnimatedRects function draws a wire-frame rectangle and animates it to indicate the opening of an icon or the minimizing or maximizing of a window.

BOOL WINAPI DrawAnimatedRects(

HWND hwnd,	// handle of clipping window
int idAni,	// type of animation
CONST RECT * lprcFrom,	// address of rectangle coordinates (minimized)
CONST RECT * lprcTo	// address of rectangle coordinates (restored)
);
Parameters

hwnd

Handle of the window to which the rectangle is clipped. If this parameter is NULL, the working area of the screen is used.

idAni

Windows 95: This parameter is reserved and must be zero.

Windows NT: Specifies the type of animation to perform. This parameter can be one of these values:

Value	Meaning
IDANI_OPEN	Draws the animated rectangle beginning with the position specified by the lprcFrom parameter and ending with the position specified by the lprcTo parameter.
IDANI_CLOSE	Draws the animated rectangle beginning with the position specified by the lprcTo parameter and ending with the position specified by the lprcFrom parameter.
lprcFrom

Points to a SMALL_RECT structure specifying the location and size of the icon or minimized window. Coordinates are relative to the rectangle specified by the lprcClip parameter.

lprcTo

Points to a SMALL_RECT structure specifying the location and size of the restored window. Coordinates are relative to the rectangle specified by the lprcClip parameter.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

See Also

SMALL_RECT


DrawCaption [New - Windows 95]
DrawCaption  QuickInfo  Overview  Group

[New - Windows 95]

The DrawCaption function draws a window caption.

void WINAPI DrawCaption(

HDC hdc,	// handle of device context
LPRECT lprc,	// address of bounding rectangle coordinates
HFONT hfont,	// handle of font for caption
HICON hicon,	// handle of icon in caption
LPSTR lpszText,	// address of caption string
WORD wFlags	// drawing options
);
Parameters

hdc

Identifies the device context.

lprc

Points to a RECT structure specifying the bounding rectangle for the window caption.

hfont

Identifies the font to use for caption text. To use the standard font, specify NULL for this parameter.

hicon

Identifies the icon to display in the caption. This parameter can be NULL.

lpszText

Points to a null-terminated string containing the caption text. This parameter can be NULL.

wFlags

Specifies drawing options. This parameter can be zero or more of the following values:

Value	Meaning
DC_ACTIVE	Uses the colors for an active caption.
DC_SMALLCAP	Draws a small caption. Uses the current small caption font if the hfont parameter is NULL.
If DC_SMALLCAP is specified, the function draws a normal window caption.

Return Value

This function does not return a value.

See Also

RECT


DrawEdge [New - Windows NT]
DrawEdge  QuickInfo  Overview  Group

[New - Windows NT]

The DrawEdge function draws one or more edges of rectangle.

BOOL DrawEdge(

HDC hdc,	// handle of device context
LPRECT qrc,	// address of rectangle coordinates
UINT edge,	// type of inner and outer edge to draw
UINT grfFlags	// type of border
);
Parameters

hdc

Identifies the device context.

qrc

Points to a RECT structure that contains the logical coordinates of the rectangle.

edge

Specifies the type of inner and outer edge to draw. This parameter must be a combination of one inner-border flag and one outer-border flag. The inner-border flags are as follows:

Value	Meaning
BDR_RAISEDINNER	Raised inner edge.
BDR_SUNKENINNER	Sunken inner edge.
The outer-border flags are as follows:

Value	Meaning
BDR_RAISEDOUTER	Raised outer edge.
BDR_SUNKENOUTER	Sunken outer edge.
Alternatively, the edge parameter can specify one of the following flags:

Value	Meaning
EDGE_BUMP	Combination of BDR_RAISEDOUTER and BDR_SUNKENINNER.
EDGE_ETCHED	Combination of BDR_SUNKENOUTER and BDR_RAISEDINNER.
EDGE_RAISED	Combination of BDR_RAISEDOUTER and BDR_RAISEDINNER.
EDGE_SUNKEN	Combination of BDR_SUNKENOUTER and BDR_SUNKENINNER.
grfFlags

Specifies the type of border. This parameter can be a combination of these values:

Value	Meaning
BF_ADJUST	Rectangle to be adjusted to leave space for client area.
BF_BOTTOM	Bottom of border rectangle.
BF_BOTTOMLEFT	Bottom and left side of border rectangle.
BF_BOTTOMRIGHT	Bottom and right side of border rectangle.
BF_DIAGONAL	Diagonal border.
BF_DIAGONAL_ENDBOTTOMLEFT	Diagonal border. The end point is the bottom-left corner of the rectangle; the origin is top-right corner.
BF_DIAGONAL_ENDBOTTOMRIGHT	Diagonal border. The end point is the bottom-right corner of the rectangle; the origin is top-left corner.
BF_DIAGONAL_ENDTOPLEFT	Diagonal border. The end point is the top-left corner of the rectangle; the origin is bottom-right corner.
BF_DIAGONAL_ENDTOPRIGHT	Diagonal border. The end point is the top-right corner of the rectangle; the origin is bottom-left corner.
BF_FLAT	Flat border.
BF_LEFT	Left side of border rectangle.
BF_MIDDLE	Interior of rectangle to be filled.
BF_MONO	One-dimensional border.
BF_RECT	Entire border rectangle.
BF_RIGHT	Right side of border rectangle.
BF_SOFT	Soft buttons instead of tiles.
BF_TOP	Top of border rectangle.
BF_TOPLEFT	Top and left side of border rectangle.
BF_TOPRIGHT	Top and right side of border rectangle.
Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

RECT


DrawEscape
DrawEscape  QuickInfo  Overview  Group

The DrawEscape function accesses drawing capabilities of a video display that are not directly available through the graphics device interface (GDI).

int DrawEscape(

HDC  hdc,	// handle of device context
int  nEscape,	// specifies escape function
int  cbInput,	// size of structure for input
LPCSTR  lpszInData	// address of structure for input
);
Parameters

hdc

Identifies the device context for the specified video display.

nEscape

Specifies the escape function to be performed.

cbInput

Specifies the number of bytes of data pointed to by the lpszInData parameter.

lpszInData

Points to the input structure required for the specified escape.

Return Value

The return value specifies the outcome of the function. It is greater than zero if the function is successful, except for the QUERYESCSUPPORT draw escape, which checks for implementation only. The return value is zero if the escape is not implemented. The return value is less than zero if an error occurred. To get extended error information, call GetLastError.

Remarks

When an application calls the DrawEscape function, the data identified by cbInput and lpszInData is passed directly to the specified display driver.


DrawFocusRect
DrawFocusRect  QuickInfo  Overview  Group

The DrawFocusRect function draws a rectangle in the style used to indicate that the rectangle has the focus.

BOOL DrawFocusRect(

HDC  hDC,	// handle of device context
CONST RECT  * lprc	// address of structure for rectangle
);
Parameters

hDC

Identifies the device context.

lprc

Points to a RECT structure that specifies the logical coordinates of the rectangle.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Because DrawFocusRect is an XOR function, calling it a second time with the same rectangle removes the rectangle from the screen.

This function draws a rectangle that cannot be scrolled. To scroll an area containing a rectangle drawn by this function, call DrawFocusRect to remove the rectangle from the screen, scroll the area, and then call DrawFocusRect again to draw the rectangle in the new position.

See Also

FrameRect, RECT


DrawFrameControl [New - Windows NT]
DrawFrameControl  QuickInfo  Overview  Group

[New - Windows NT]

The DrawFrameControl function draws a frame control of the specified type and style.

BOOL DrawFrameControl(

HDC  hdc,	// handle of device context
LPRECT  lprc,	// address of bounding rectangle
UINT  uType,	// frame-control type
UINT  uState	// frame-control state
);
Parameters

hdc

Identifies the device context of the window in which to draw the control.

lprc

Points to a RECT structure that contains the logical coordinates of the bounding rectangle for frame control.

uType

Specifies the type of frame control to draw. This parameter can be one of the following values:

Value	Meaning
DFC_BUTTON	Standard button
DFC_CAPTION	Title bar
DCF_MENU	Menu
DFC_SCROLL	Scroll bar
uState

Specifies the initial state of the frame control. If uType is DFC_BUTTON, uState can be one of the following values:

Value	Meaning
DFCS_BUTTON3STATE	Three-state button
DFCS_BUTTONCHECK	Check box
DFCS_BUTTONPUSH	Push button
DFCS_BUTTONRADIO	Radio button
DFCS_BUTTONRADIOIMAGE	Image for radio button (nonsquare needs image)
DFCS_BUTTONRADIOMASK	Mask for radio button (nonsquare needs mask)
If uType is DFC_CAPTION, uState can be one of the following values:

Value	Meaning
DFCS_CAPTIONCLOSE	Close button
DFCS_CAPTIONHELP	Windows 95 only: Help button
DFCS_CAPTIONMAX	Maximize button
DFCS_CAPTIONMIN	Minimize button
DFCS_CAPTIONRESTORE	Restore button
If uType is DFC_MENU, uState can be one of the following values:

Value	Meaning
DFCS_MENUARROW	Submenu arrow
DFCS_MENUBULLET	Bullet
DFCS_MENUCHECK	Check mark
If uType is DFC_SCROLL, uState can be one of the following values:

Value	Meaning
DFCS_SCROLLCOMBOBOX	Combo box scroll bar
DFCS_SCROLLDOWN	Down arrow of scroll bar
DFCS_SCROLLLEFT	Left arrow of scroll bar
DFCS_SCROLLRIGHT	Right arrow of scroll bar
DFCS_SCROLLSIZEGRIP	Size grip in bottom-right corner of window
DFCS_SCROLLUP	Up arrow of scroll bar
The following style can be used to adjust the bounding rectangle of the push button:

Value	Meaning
DFCS_ADJUSTRECT	Bounding rectangle is adjusted to exclude the surrounding edge of the push button.
One or more of the following values can be used to set the state of the control to be drawn:

Value	Meaning
DFCS_CHECKED	Button is checked.
DFCS_FLAT	Button has a flat border.
DFCS_INACTIVE	Button is inactive (grayed).
DFCS_MONO	Button has a monochrome border.
DFCS_PUSHED	Button is pushed.
Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

RECT


DrawIcon
DrawIcon  QuickInfo  Overview  Group

The DrawIcon function draws an icon in the client area of the window of the specified device context.

BOOL DrawIcon(

HDC  hDC,	// handle of device context
int  X,	// x-coordinate of upper-left corner
int  Y,	// y-coordinate of upper-left corner
HICON  hIcon	// handle of icon to draw
);
Parameters

hDC

Identifies the device context for a window.

X

Specifies the logical x-coordinate of the upper-left corner of the icon.

Y

Specifies the logical y-coordinate of the upper-left corner of the icon.

hIcon

Identifies the icon to be drawn.

Windows NT: The icon resource must have been previously loaded by using the LoadIcon function.

Windows 95: The icon resource must have been previously loaded by using the LoadIcon or LoadImage functions.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

DrawIcon places the icon's upper-left corner at the location specified by the X and Y parameters. The location is subject to the current mapping mode of the device context.

See Also

CreateIcon, DrawIconEx, LoadIcon


DrawIconEx [New - Windows NT]
DrawIconEx  QuickInfo  Overview  Group

The DrawIconEx function draws an icon or cursor in the client area of the window of the given device context, performing the specified raster operations, and stretching or compressing the icon or cursor as specified.

BOOL DrawIconEx(

HDC  hdc,	// handle of device context
int  xLeft,	// x-coordinate of upper left corner
int  yTop,	// y-coordinate of upper left corner
HICON  hIcon,	// handle of icon to draw
int  cxWidth,	// width of the icon
int  cyWidth,	// height of the icon
UINT  istepIfAniCur,	// index of frame in animated cursor
HBRUSH  hbrFlickerFreeDraw,	// handle of background brush
UINT  diFlags	// icon-drawing flags
);
Parameters

hdc

Identifies the device context for a window.

xLeft

Specifies the logical x-coordinate of the upper-left corner of the icon or cursor.

yTop

Specifies the logical y-coordinate of the upper-left corner of the icon or cursor.

hIcon

Identifies the icon or cursor to be drawn. This parameter can identify an animated cursor. The icon or cursor resource must have been previously loaded by using the LoadImage function.

cxWidth

Specifies the logical width of the icon or cursor.

cyWidth

Specifies the logical height of the icon or cursor.

istepIfAniCur

Specifies the index of the frame to draw, if hIcon identifies an animated cursor. This parameter is ignored if hIcon does not identify an animated cursor.

hbrFlickerFreeDraw

Identifies a brush that the system uses for flicker-free drawing. If hbrBkgnd is a valid brush handle, the system creates an offscreen bitmap using the given brush for the background color, draws the icon or cursor into the bitmap, and then copies the bitmap into the device context identified by hdc. If hbrBkgnd is NULL, the system draws the icon or cursor directly into the device context.

diFlags

Specifies the drawing flags. This parameter can be one of the following values:

Value	Meaning
DI_COMPAT	Draws the icon or cursor using the system default image rather than the user-specified image.
DI_DEFAULTSIZE	Draws the icon or cursor in its default width, ignoring the cxWidth and cyWidth parameters.
DI_IMAGE	Performs the raster operation specified by ropImage.
DI_MASK	Performs the raster operation specified by ropMask.
DI_NORMAL	Combination of DI_IMAGE and DI_MASK.
Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

DrawIconEx places the icon's upper-left corner at the location specified by the xLeft and yTop parameters. The location is subject to the current mapping mode of the device context.

See Also

CopyImage, DrawIcon, LoadImage


DrawInsert [New - Windows NT]
 DrawInsert  QuickInfo  Overview  Group

[New - Windows NT]

The DrawInsert function draws the insert icon in the parent window of the specified drag list box.

void DrawInsert(

HWND  handParent,
HWND  hLB,
int  nItem
);
Parameters

handParent

Handle to the parent window of the drag list box.

hLB

Handle to the drag list box.

nItem

Identifier of the icon item to be drawn.

Return Value

This function does not return a value.


DrawMenuBar
DrawMenuBar  QuickInfo  Overview  Group

The DrawMenuBar function redraws the menu bar of the specified window. If the menu bar changes after Windows has created the window, this function must be called to draw the changed menu bar.

BOOL DrawMenuBar(

HWND  hWnd	// handle of window with menu bar to redraw
);
Parameters

hWnd

Identifies the window whose menu bar needs redrawing.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

DeleteMenu, InsertMenuItem, RemoveMenu, SetMenuItemInfo


DrawState [New - Windows 95]
DrawState  QuickInfo  Overview  Group

[New - Windows 95]

The DrawState function displays an image and applies a visual effect to indicate a state, such as a disabled or default state.

BOOL WINAPI DrawState(

HDC hdc,	// handle of device context
HBRUSH hbr,	// handle of brush
DRAWSTATEPROC lpOutputFunc,	// address of callback function
LPARAM lData,	// image information
WPARAM wData,	// more image information
int x,	// horizontal location of image
int y,	// vertical location of image
int cx,	// width of image
int cy,	// height of image
UINT fuFlags	// image type and state
);
Parameters

hdc

Identifies the device context to draw in.

hbr

Identifies the brush used to draw the image, if the state specified by the fuFlags parameter is DSS_MONO. This parameter is ignored for other states.

lpOutputFunc

Points to an application-defined callback function used to render the image. This parameter is required if the image type in fuFlags is DST_COMPLEX. It is optional and can be NULL if the image type is DST_TEXT. For all other image types, this parameter is ignored. For more information about the callback function, see the DrawStateProc function.

lData

Specifies information about the image. The meaning of this parameter depends on the image type.

wData

Specifies information about the image. The meaning of this parameter depends on the image type. It is, however, zero extended for use with the DrawStateProc function.

x

Specifies the horizontal location at which to draw the image.

y

Specifies the vertical location at which to draw the image.

cx

Specifies the width of the image, in device units. This parameter is required if the image type is DST_COMPLEX. Otherwise, it can be zero to calculate the width of the image.

cy

Specifies the height of the image, in device units. This parameter is required if the image type is DST_COMPLEX. Otherwise, it can be zero to calculate the height of the image.

fuFlags

Specifies the image type and state. The type can be one of these values:

Value (type)	Meaning
DST_BITMAP	The image is a bitmap. The low-order word of the lData parameter is the bitmap handle.
DST_COMPLEX	The image is application defined. To render the image, DrawState calls the callback function specified by the lpOutputFunc parameter.
DST_ICON	The image is an icon. The low-order word of lData is the icon handle.
DST_PREFIXTEXT	The image is text that may contain an accelerator mnemonic. DrawState interprets the ampersand (&) prefix character as a directive to underscore the character that follows. The lData parameter specifies the address of the string, and the wData parameter specifies the length. If wData is zero, the string must be null-terminated.
DST_TEXT	The image is text. The lData parameter specifies the address of the string, and the wData parameter specifies the length. If wData is zero, the string must be null-terminated.
The state can be one of these values:

Value (state)	Meaning
DSS_NORMAL	Draws the image without any modification.
DSS_UNION	Dithers the image.
DSS_DISABLED	Embosses the image.
DSS_DEFAULT	Makes the image bold.
DSS_MONO	Draws the image using the brush specified by the hbr parameter.
For all states except DSS_NORMAL, the image is converted to monochrome before the visual effect is applied.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

See Also

DrawStateProc


DrawStateProc [New - Windows 95]
DrawStateProc  QuickInfo  Overview  Group

[New - Windows 95]

The DrawStateProc function is an application-defined callback function that renders a complex image for the DrawState function.

BOOL CALLBACK DrawStateProc(

HDC hdc,	// handle of device context
LPARAM lData,	// image information
WPARAM wData,	// more image information
int cx,	// width of image
int cy	// height of image
);
Parameters

hdc

Identifies the device context to draw in. The device context is a memory device context with a bitmap selected, the dimensions of which are at least as great as those specified by the cx and cy parameters.

lData

Specifies information about the image, which the application passed to DrawState.

wData

Specifies information about the image, which the application passed to DrawState.

cx

Specifies the image width, in device units, as specified by the call to DrawState.

cy

Specifies the image height, in device units, as specified by the call to DrawState.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

See Also

DrawState


DrawStatusText [New - Windows NT]
DrawStatusText  QuickInfo  Overview  Group

[New - Windows NT]

The DrawStatusText function draws the specified text in the style of a status window with borders.

void DrawStatusText(

HDC hdc,
LPRECT  lprc,
LPCTSTR  pszText,
UINT  uFlags
);
Parameters

hdc

Handle to the display context for the window.

lprc

Pointer to a RECT structure that contains the position, in client coordinates, of the rectangle in which the text is drawn. The function draws the borders just inside of the edges of the specified rectangle.

pszText

Pointer to a null-terminated string that specifies the text to display. Tab characters in the string determine whether the string is left-aligned, right-aligned, or centered.

uFlags

Text drawing flags. This parameter can be a combination of these values:

Value	Meaning
SBT_NOBORDERS	Prevents borders from being drawn around the specified text.
SBT_POPOUT	Draws highlighted borders that make the text stand out.
SBT_RTLREADING	Windows 95 only: Displays text using right-to-left reading order on Hebrew or Arabic systems.
Return Value

This function does not return a value.

See Also

RECT


DrawText
DrawText  QuickInfo  Overview  Group

The DrawText function draws formatted text in the specified rectangle. It formats the text according to the specified method (expanding tabs, justifying characters, breaking lines, and so forth).

int DrawText(

HDC  hDC,	// handle of device context
LPCTSTR  lpString,	// address of string to draw
int  nCount,	// string length, in characters
LPRECT  lpRect,	// address of structure with formatting dimensions
UINT  uFormat	// text-drawing flags
);
Parameters

hDC

Identifies the device context.

lpString

Points to the string to be drawn. If the nCount parameter is −1, the string must be null-terminated.

nCount

Specifies the number of characters in the string. If nCount is −1, then the lpString parameter is assumed to be a pointer to a null-terminated string and DrawText computes the character count automatically.

lpRect

Points to a RECT structure that contains the rectangle (in logical coordinates) in which the text is to be formatted.

uFormat

Specifies the method of formatting the text. It can be any combination of the following values:

Value	Description
DT_BOTTOM	Bottom-justifies text. This value must be combined with DT_SINGLELINE.
DT_CALCRECT	Determines the width and height of the rectangle. If there are multiple lines of text, DrawText uses the width of the rectangle pointed to by the lpRect parameter and extends the base of the rectangle to bound the last line of text. If there is only one line of text, DrawText modifies the right side of the rectangle so that it bounds the last character in the line. In either case, DrawText returns the height of the formatted text but does not draw the text.
DT_CENTER	Centers text horizontally.
DT_EXPANDTABS	Expands tab characters. The default number of characters per tab is eight.
DT_EXTERNALLEADING	Includes the font external leading in line height. Normally, external leading is not included in the height of a line of text.
DT_LEFT	Aligns text to the left.
DT_NOCLIP	Draws without clipping. DrawText is somewhat faster when DT_NOCLIP is used.
DT_NOPREFIX	Turns off processing of prefix characters. Normally, DrawText interprets the mnemonic-prefix character & as a directive to underscore the character that follows, and the mnemonic-prefix characters && as a directive to print a single &. By specifying DT_NOPREFIX, this processing is turned off.
DT_RIGHT	Aligns text to the right.
DT_SINGLELINE	Displays text on a single line only. Carriage returns and linefeeds do not break the line.
DT_TABSTOP	Sets tab stops. Bits 15−8 (high-order byte of the low-order word) of the uFormat parameter specify the number of characters for each tab. The default number of characters per tab is eight.
DT_TOP	Top-justifies text (single line only).
DT_VCENTER	Centers text vertically (single line only).
DT_WORDBREAK	Breaks words. Lines are automatically broken between words if a word would extend past the edge of the rectangle specified by the lpRect parameter. A carriage return-linefeed sequence also breaks the line.
Note that the DT_CALCRECT, DT_EXTERNALLEADING, DT_INTERNAL, DT_NOCLIP, and DT_NOPREFIX values cannot be used with the DT_TABSTOP value.

Return Value

If the function succeeds, the return value is the height of the text.

Remarks

The DrawText function uses the device context's selected font, text color, and background color to draw the text. Unless the DT_NOCLIP format is used, DrawText clips the text so that it does not appear outside the given rectangle. All formatting is assumed to have multiple lines unless the DT_SINGLELINE format is specified.

If the selected font is too large for the specified rectangle, the DrawText function does not attempt to substitute a smaller font.

See Also

GrayString, TabbedTextOut, TextOut, RECT


DrawTextEx [New - Windows 95]
DrawTextEx  QuickInfo  Overview  Group

[New - Windows 95]

The DrawTextEx function draws formatted text in the specified rectangle.

int DrawTextEx(

HDC hdc,	// handle of device context
LPTSTR lpchText,	// address of string to draw
int cchText,	// length of string to draw
LPRECT lprc,	// address of rectangle coordinates
UINT dwDTFormat,	// formatting options
LPDRAWTEXTPARAMS lpDTParams	// address of structure for more options
);
Parameters

hdc

Identifies the device context to draw in.

lpchText

Points to the string to draw. The string must be null-terminated if the cchText parameter is  −1.

cchText

Specifies the length, in characters, of the string specified by the lpchText parameter. If the string is null-terminated, this parameter can be  −1 to calculate the length.

lprc

Points to a RECT structure that contains the rectangle, in logical coordinates, in which the text is to be formatted.

dwDTFormat

Specifies formatting options. This parameter can be one or more of these values:

Value	Meaning
DT_BOTTOM	Justifies the text to the bottom pf the rectangle. This value must be combined with DT_SINGLELINE.
DT_CALCRECT	Determines the width and height of the rectangle. If there are multiple lines of text, DrawTextEx uses the width of the rectangle pointed to by the lprc parameter and extends the base of the rectangle to bound the last line of text. If there is only one line of text, DrawTextEx modifies the right side of the rectangle so that it bounds the last character in the line. In either case, DrawTextEx returns the height of the formatted text, but does not draw the text.
DT_CENTER	Centers text horizontally in the rectangle.
DT_EDITCONTROL	Duplicates the text-displaying characteristics of a multiline edit control. Specifically, the average character width is calculated in the same manner as for an edit control, and the function does not display a partially visible last line.
DT_END_ELLIPSIS or DT_PATH_ELLIPSIS	Replaces part of the given string with ellipses, if necessary, so that the result fits in the specified  rectangle. The given string is not modified unless the DT_MODIFYSTRING flag is specified. You can specify DT_END_ELLIPSIS to replace characters at the end of the string, or DT_PATH_ELLIPSIS to replace characters in the middle of the string. If the string contains backslash (\) characters, DT_PATH_ELLIPSIS preserves as much as possible of the text after the last backslash.
DT_EXPANDTABS	Expands tab characters. The default number of characters per tab is 8.
DT_EXTERNALLEADING	Includes the font external leading in line height. Normally, external leading is not included in the height of a line of text.
DT_LEFT	Aligns text to the left.
DT_MODIFYSTRING	Modifies the given string to match the displayed text. This flag has no effect unless the DT_END_ELLIPSIS or DT_PATH_ELLIPSIS flag is specified.
DT_NOCLIP	Draws without clipping. DrawTextEx is somewhat faster when DT_NOCLIP is used.
DT_NOPREFIX	Turns off processing of prefix characters. Normally, DrawTextEx interprets the ampersand (&) mnemonic-prefix character as a directive to underscore the character that follows, and the double ampersand (&&) mnemonic-prefix characters as a directive to print a single ampersand. By specifying DT_NOPREFIX, this processing is turned off.
DT_RIGHT	Aligns text to the right.
DT_RTLREADING	Layout in right to left reading order for bi-directional text when the font selected into the hdc is a Hebrew or Arabic. The default reading order for all text is left to right.
DT_SINGLELINE	Displays text on a single line only. Carriage returns and linefeeds do not break the line.
DT_TABSTOP	Sets tab stops. The DRAWTEXTPARAMS structure pointed to by the lpDTParams parameter specifies the number of average character widths per tab stop.
DT_TOP	Top justifies text (single line only).
DT_VCENTER	Centers text vertically (single line only).
DT_WORDBREAK	Breaks words. Lines are automatically broken between words if a word extends past the edge of the rectangle specified by the lprc parameter. A carriage return-linefeed sequence also breaks the line.
dwDTParams

Points to a DRAWTEXTPARAMS structure that specifies additional formatting options. This parameter can be NULL.

Return Value

If the function succeeds, the return value is the text height.

If the function fails, the return value is zero.

See Also

DrawText, DRAWTEXTPARAMS


DuplicateHandle
DuplicateHandle  QuickInfo  Overview  Group

The DuplicateHandle function duplicates an object handle.

BOOL DuplicateHandle(

HANDLE  hSourceProcessHandle,	// handle of process with handle to duplicate
HANDLE  hSourceHandle,	// handle to duplicate
HANDLE  hTargetProcessHandle,	// handle of process to duplicate to
LPHANDLE  lpTargetHandle,	// address of duplicate handle
DWORD  dwDesiredAccess,	// access for duplicate handle
BOOL  bInheritHandle,	// handle inheritance flag
DWORD  dwOptions	// optional actions
);
Parameters

hSourceProcessHandle

Identifies the process containing the handle to duplicate. The handle must have PROCESS_DUP_HANDLE access.

hSourceHandle

Identifies the handle to duplicate. This is an open object handle that is valid in the context of the source process. For a list of objects whose handles can be duplicated, see the following Remarks section.

hTargetProcessHandle

Identifies the process that is to receive the duplicated handle. The handle must have PROCESS_DUP_HANDLE access.

lpTargetHandle

Points to a variable receiving the value of the duplicate handle. This handle value is valid in the context of the target process. If lpTargetHandle is NULL, the function duplicates the handle, but does not return the duplicate handle value to the caller.

dwDesiredAccess

Specifies the access requested for the new handle. This parameter is ignored if the dwOptions parameter specifies the DUPLICATE_SAME_ACCESS flag. Otherwise, the flags that can be specified depend on the type of object whose handle is being duplicated. For the flags that can be specified for each object type, see the following Remarks section. Note that the new handle can have more access than the original handle.

bInheritHandle

Indicates whether the handle is inheritable. If TRUE, the duplicate handle can be inherited by new processes created by the target process. If FALSE, the new handle cannot be inherited.

dwOptions

Specifies optional actions. This parameter can be zero, or any combination of the following flags:

Value	Meaning
DUPLICATE_CLOSE_SOURCE	Closes the source handle. This occurs regardless of any error status returned.
DUPLICATE_SAME_ACCESS	Ignores the dwDesiredAccess parameter. The duplicate handle has the same access as the source handle.
Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

DuplicateHandle can be called by either the source process or the target process. It can also be invoked where the source and target process are the same. For example, a process can use DuplicateHandle to create a noninheritable duplicate of an inheritable handle, or a handle with different access than the original handle.

The duplicating process uses the GetCurrentProcess function to get a handle of itself. To get the other process handle, it may be necessary to use some form of interprocess communication (for example, named pipe or shared memory) to communicate the process identifier to the duplicating process. This identifier is then used in the OpenProcess function to open a handle.

If the process that calls DuplicateHandle is not the target process, the duplicating process must use interprocess communication to pass the value of the duplicate handle to the target process.

The duplicate handle is the same object handle as the source handle. This means that the state of the object is the same for both handles. For example, the current file mark for a file handle is always the same for both handles.

DuplicateHandle can duplicate handles to the following types of objects:

Object	Description
Console input	The handle is returned by the CreateFile function when CONIN$ is specified, or by the GetStdHandle function when STD_INPUT_HANDLE is specified. Console handles can be duplicated for use only in the same process.
Console screen buffer	The handle is returned by the CreateFile function when CONOUT$ is specified, or by the GetStdHandle function when STD_OUTPUT_HANDLE is specified. Console handles can be duplicated for use only in the same process.
Event	The handle is returned by the CreateEvent or OpenEvent function.
File or communications device	The handle is returned by the CreateFile function.
File mapping	The handle is returned by the CreateFileMapping function.
Mutex	The handle is returned by the CreateMutex or OpenMutex function.
Pipe	A named pipe handle is returned by the CreateNamedPipe or CreateFile function. An anonymous pipe handle is returned by the CreatePipe function.
Process	The handle is returned by the CreateProcess or OpenProcess function.
Registry key	The handle is returned by the RegCreateKey, RegCreateKeyEx, RegOpenKey, or RegOpenKeyEx function. Note that registry key handles returned by the RegConnectRegistry function cannot be used in a call to DuplicateHandle.
Semaphore	The handle is returned by the CreateSemaphore or OpenSemaphore function.
Thread	The handle is returned by the CreateProcess, CreateThread, or CreateRemoteThread function.
In addition to STANDARD_RIGHTS_REQUIRED, the following access flags can be specified in the dwDesiredAccess parameter for the different object types. Note that the new handle can have more access than the original handle. However, in some cases DuplicateHandle cannot create a duplicate handle with more access permission than the original handle. For example, a file handle created with GENERIC_READ access cannot be duplicated so that it has both GENERIC_READ and GENERIC_WRITE access.

Any combination of the following access flags is valid for handles to communications devices, console input, console screen buffers, files, and pipes:

Access	Description
GENERIC_READ	Enables read access.
GENERIC_WRITE	Enables write access.
Any combination of the following access flags is valid for file-mapping objects:

Access	Description
FILE_MAP_ALL_ACCESS	Specifies all possible access flags for the file-mapping object.
FILE_MAP_READ	Enables mapping the object into memory that permits read access.
FILE_MAP_WRITE	Enables mapping the object into memory that permits write access. For write access, PAGE_READWRITE protection must have been specified when the file-mapping object was created by the CreateFileMapping function.
Any combination of the following access flags is valid for mutex objects:

Access	Description
MUTEX_ALL_ACCESS	Specifies all possible access flags for the mutex object.
SYNCHRONIZE	Windows NT: Enables use of the mutex handle in any of the wait functions to acquire ownership of the mutex, or in the ReleaseMutex function to release ownership.
Any combination of the following access flags is valid for semaphore objects:

Access	Description
SEMAPHORE_ALL_ACCESS	Specifies all possible access flags for the semaphore object.
SEMAPHORE_MODIFY_STATE	Enables use of the semaphore handle in the ReleaseSemaphore function to modify the semaphore's count.
SYNCHRONIZE	Windows NT: Enables use of the semaphore handle in any of the wait functions to wait for the semaphore's state to be signaled.
Any combination of the following access flags is valid for event objects:

Access	Description
EVENT_ALL_ACCESS	Specifies all possible access flags for the event object.
EVENT_MODIFY_STATE	Enables use of the event handle in the SetEvent and ResetEvent functions to modify the event's state.
SYNCHRONIZE	Windows NT: Enables use of the event handle in any of the wait functions to wait for the event's state to be signaled.
Any combination of the following access flags is valid for handles to registry keys:

Value	Meaning
KEY_ALL_ACCESS	Specifies all possible flags for the registry key.
KEY_CREATE_LINK	Enables using the handle to create a link to a registry-key object.
KEY_CREATE_SUB_KEY	Enables using the handle to create a subkey of a registry-key object.
KEY_ENUMERATE_SUB_KEYS	Enables using the handle to enumerate the subkeys of a registry-key object.
KEY_EXECUTE	Equivalent to KEY_READ.
KEY_NOTIFY	Enables using the handle to request change notifications for a registry key or for subkeys of a registry key.
KEY_QUERY_VALUE	Enables using the handle to query a value of a registry-key object.
KEY_READ	Combines the STANDARD_RIGHTS_READ, KEY_QUERY_VALUE, KEY_ENUMERATE_SUB_KEYS, and KEY_NOTIFY values.
KEY_SET_VALUE	Enables using the handle to create or set a value of a registry-key object.
KEY_WRITE	Combines the STANDARD_RIGHTS_WRITE, KEY_SET_VALUE, and KEY_CREATE_SUB_KEY values.
Any combination of the following access flags is valid for process objects:

Access	Description
PROCESS_ALL_ACCESS	Specifies all possible access flags for the process object.
PROCESS_CREATE_PROCESS	Used internally.
PROCESS_CREATE_THREAD	Enables using the process handle in the CreateRemoteThread function to create a thread in the process.
PROCESS_DUP_HANDLE	Enables using the process handle as either the source or target process in the DuplicateHandle function to duplicate a handle.
PROCESS_QUERY_INFORMATION	Enables using the process handle in the GetExitCodeProcess and GetPriorityClass functions to read information from the process object.
PROCESS_SET_INFORMATION	Enables using the process handle in the SetPriorityClass function to set the process's priority class.
PROCESS_TERMINATE	Enables using the process handle in the TerminateProcess function to terminate the process.
PROCESS_VM_OPERATION	Enables using the process handle in the VirtualProtectEx and WriteProcessMemory functions to modify the virtual memory of the process.
PROCESS_VM_READ	Enables using the process handle in the ReadProcessMemory function to read from the virtual memory of the process.
PROCESS_VM_WRITE	Enables using the process handle in the WriteProcessMemory function to write to the virtual memory of the process.
SYNCHRONIZE	Windows NT: Enables using the process handle in any of the wait functions to wait for the process to terminate.
Any combination of the following access flags is valid for thread objects:

Access	Description
SYNCHRONIZE	Windows NT: Enables using the thread handle in any of the wait functions to wait for the thread to terminate.
THREAD_ALL_ACCESS	Specifies all possible access flags for the thread object.
THREAD_DIRECT_IMPERSONATION	Used internally.
THREAD_GET_CONTEXT	Enables using the thread handle in the GetThreadContext function to read the thread's context.
THREAD_IMPERSONATE	Used internally.
THREAD_QUERY_INFORMATION	Enables using the thread handle in the GetExitCodeThread, GetThreadPriority, and GetThreadSelectorEntry functions to read information from the thread object.
THREAD_SET_CONTEXT	Enables using the thread handle in the SetThreadContext function to set the thread's context.
THREAD_SET_INFORMATION	Enables using the thread handle in the SetThreadPriority function to set the thread's priority.
THREAD_SET_THREAD_TOKEN	Used internally.
THREAD_SUSPEND_RESUME	Enables using the thread handle in the SuspendThread or ResumeThread functions to suspend or resume a thread.
THREAD_TERMINATE	Enables using the thread handle in the TerminateThread function to terminate the thread.
See Also

CloseHandle, CreateEvent, CreateFile, CreateFileMapping, CreateMutex, CreateNamedPipe, CreatePipe, CreateProcess, CreateRemoteThread, CreateSemaphore, CreateThread, GetCurrentProcess, GetExitCodeProcess, GetExitCodeThread, GetPriorityClass, GetStdHandle, GetThreadContext, GetThreadPriority, GetThreadSelectorEntry, OpenEvent, OpenMutex, OpenProcess, OpenSemaphore, ReadProcessMemory, RegConnectRegistry, RegCreateKey, RegCreateKeyEx, RegOpenKey, RegOpenKeyEx, ReleaseMutex, ReleaseSemaphore, ResetEvent, ResumeThread, SetEvent, SetPriorityClass, SetThreadContext, SetThreadPriority, SuspendThread, TerminateProcess, TerminateThread, VirtualProtectEx, WriteProcessMemory


DuplicateToken
DuplicateToken  QuickInfo  Overview  Group

The DuplicateToken function creates a new access token that duplicates one already in existence.

BOOL DuplicateToken(

HANDLE  ExistingTokenHandle,	// handle of token to duplicate
SECURITY_IMPERSONATION_LEVEL  ImpersonationLevel,	// impersonation level
PHANDLE  DuplicateTokenHandle	// handle of duplicated token
);
Parameters

ExistingTokenHandle

Identifies an access token opened with TOKEN_DUPLICATE access.

ImpersonationLevel

Specifies a SECURITY_IMPERSONATION_LEVEL enumerated type that supplies the impersonation level of the new token.

DuplicateTokenHandle

Identifies the duplicate access token when the function returns. This handle has TOKEN_IMPERSONATE and TOKEN_QUERY access to the new token.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Impersonation is the ability of a process to take on the security attributes of another process. Usually, a server process impersonates a client process to complete a task involving objects to which the client normally has no access. If a client does not have an account on the server's domain, for example, the server must impersonate the client to gain access to secured objects.

See Also

DdeImpersonateClient, ImpersonateNamedPipeClient, RevertToSelf, SECURITY_IMPERSONATION_LEVEL


EditWordBreakProc
EditWordBreakProc  QuickInfo  Overview  Group

An EditWordBreakProc function is an application-defined callback function. A value of type EDITWORDBREAKPROC is a pointer to such a function.

Windows NT: A multiline edit control calls an EditWordBreakProc function whenever the control must break a line of text.

Windows 95: A multiline edit control or a rich edit control calls an EditWordBreakProc function whenever the control must break a line of text.

int CALLBACK EditWordBreakProc(

LPTSTR  lpch,	// address of edit text
int  ichCurrent,	// index of starting point
int  cch,	// length in characters of edit text
int  code	// action to take
);
Parameters

lpch

Points to the text of the edit control.

ichCurrent

Specifies an index to a character position in the buffer of text that identifies the point at which the function should begin checking for a word break.

cch

Specifies the number of characters in the edit control text.

code

Specifies the action to be taken by the callback function. This parameter can be one of the following values:

Value	Action
WB_ISDELIMITER	Checks whether the character at the current position is a delimiter.
WB_LEFT	Looks for the beginning of a word to the left of the current position.
WB_RIGHT	Looks for the beginning of a word to the right of the current position. (This is useful in right-aligned edit controls.)
Windows 95: Additional values for the code parameter are defined for rich edit controls. For a list of these values, see the description of the EM_FINDWORDBREAK message.

Return Value

If the code parameter specifies WB_ISDELIMITER, the return value is nonzero (TRUE) if the character at the current position is a delimiter, or zero if it is not. Otherwise, the return value is an index to the beginning of a word in the buffer of text.

Remarks

A carriage return followed by a linefeed must be treated as a single word by the callback function. Two carriage returns followed by a linefeed also must be treated as a single word.

An application must install the callback function by specifying the address of the callback function in an EM_SETWORDBREAKPROC message.

EditWordBreakProc is a placeholder for an application-defined function name.

See Also

SendMessage, EM_FINDWORDBREAK, EM_SETWORDBREAKPROC


EditWordBreakProcEx
EditWordBreakProcEx  QuickInfo  Overview  Group

An application-supplied callback function that determines the character index of the word break, or the character class and word break flags of the characters in the given text.

LONG EditWordBreakProcEx(

char  *pchText,
LONG  cchText,
BYTE  bCharSet,
INT  code
);
Parameters

pchText

Address of the text at the current position. If code specifies movement to the left, the text is in the elements pchText[-1] through pchText[-cchText] and pchText[0] is undefined. For all other actions, the text is in the elements pchText[0] through pchText[cchText - 1].

cchText

Number of characters in the buffer in the direction specified by code.

bCharSet

Character set of the text.

code

Wordbreak action to take. Can be one of the values described for the code parameter in the EM_FINDWORDBREAK message.

Return Value

Returns the character index of the word break, unless the code parameter is the WB_CLASSIFY or WB_ISDELIMITER value.

See Also

EM_FINDWORDBREAK


Ellipse
Ellipse  QuickInfo  Overview  Group

The Ellipse function draws an ellipse. The center of the ellipse is the center of the given bounding rectangle. The ellipse is outlined by using the current pen and is filled by using the current brush.

BOOL Ellipse(

HDC  hdc,	// handle of device context
int  nLeftRect,	// x-coord. of bounding rectangle's upper-left corner
int  nTopRect,	// y-coord. of bounding rectangle's upper-left corner
int  nRightRect,	// x-coord. of bounding rectangle's lower-right corner
int  nBottomRect	// y-coord. bounding rectangle's f lower-right corner
);
Parameters

hdc

Identifies the device context.

nLeftRect

Specifies the x-coordinate of the upper-left corner of the bounding rectangle.

nTopRect

Specifies the y-coordinate of the upper-left corner of the bounding rectangle.

nRightRect

Specifies the x-coordinate of the lower-right corner of the bounding rectangle.

nBottomRect

Specifies the y-coordinate of the lower-right corner of the bounding rectangle.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The current position is neither used nor updated by Ellipse.

Windows 95 only: The sum of the coordinates of the bounding rectangle cannot exceed 32,767. The sum of nLeftRect and nRightRect or nTopRect and nBottomRect parameters cannot exceed 32,767.

See Also

Arc, ArcTo


EmptyClipboard
EmptyClipboard  QuickInfo  Overview  Group

The EmptyClipboard function empties the clipboard and frees handles to data in the clipboard. The function then assigns ownership of the clipboard to the window that currently has the clipboard open.

BOOL EmptyClipboard(VOID)

Parameters

This function has no parameters.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Before calling EmptyClipboard, an application must open the clipboard by using the OpenClipboard function. If the application specifies a NULL window handle when opening the clipboard, EmptyClipboard succeeds but sets the clipboard owner to NULL.

See Also

OpenClipboard, SetClipboardData, WM_DESTROYCLIPBOARD


EnableEUDC

The EnableEUDC function enables or disables end-user-defined characters (EUDC). Enabling EUDC allows text output functions to retrieve information about end-user-defined characters from EUDC fonts. Disabling EUDC prevents output functions from accessing these fonts.

BOOL EnableEUDC(

BOOL  fEnableEUDC
);
Parameters

fEnableEUDC

Action flag. Can be TRUE to enable EUDC or FALSE to disable it.

Return Value

Returns TRUE if successful, FALSE otherwise.

Remarks

Applications call this function before and after adding, modifying, or deleting EUDC fonts. An application must disable EUDC before modifying a EUDC font or before adding or deleting a font from the registry. Application must enable EUDC after these changes to allow functions access to them.

See Also

ImmRegisterWord, ImmUnregisterWord


EnableMenuItem
EnableMenuItem  QuickInfo  Overview  Group

The EnableMenuItem function enables, disables, or grays the given menu item.

BOOL EnableMenuItem(

HMENU  hMenu,	// handle of menu
UINT  uIDEnableItem,	// menu item to enable, disable, or gray
UINT  uEnable	// menu item flags
);
Parameters

hMenu

Identifies the menu.

uIDEnableItem

Specifies the menu item to be enabled, disabled, or grayed, as determined by the uEnable parameter. This parameter specifies an item in a menu bar or in a pop-up menu.

uEnable

Specifies flags that control the interpretation of the uIDEnableItem parameter and indicate whether the menu item is enabled, disabled, or grayed. This parameter must be a combination of either MF_BYCOMMAND or MF_BYPOSITION and MF_ENABLED, MF_DISABLED, or MF_GRAYED.

Value	Meaning
MF_BYCOMMAND	Indicates that uIDEnableItem gives the identifier of the menu item. If neither the MF_BYCOMMAND nor MF_BYPOSITION flag is specified, the MF_BYCOMMAND flag is the default flag.
MF_BYPOSITION	Indicates that uIDEnableItem gives the zero-based relative position of the menu item.
MF_DISABLED	Indicates that the menu item is disabled, but not grayed, so it cannot be selected.
MF_ENABLED	Indicates that the menu item is enabled and restored from a grayed state so that it can be selected.
MF_GRAYED	Indicates that the menu item is disabled and grayed so that it cannot be selected.
Return Value

The return value specifies the previous state of the menu item (it is either MF_DISABLED, MF_ENABLED, or MF_GRAYED). If the menu item does not exist, the return value is 0xFFFFFFFF.

Remarks

An application must use the MF_BYPOSITION flag to specify the correct menu handle. If the menu handle of the menu bar is specified, the top-level menu item (an item in the menu bar) is affected. To set the state of an item in a pop-up or nested pop-up menu by position, an application must specify the handle of the pop-up menu.

When an application specifies the MF_BYCOMMAND flag, Windows checks all pop-up items that are subordinate to the menu identified by the specified menu handle. Therefore, unless duplicate menu items are present, specifying the menu handle of the menu bar is sufficient.

Windows NT: The CreateMenu, InsertMenu, ModifyMenu, and LoadMenuIndirect functions can also set the state (enabled, disabled, or grayed) of a menu item.

Windows 95: The CreateMenu, InsertMenuItem, SetMenuItemInfo, and LoadMenuIndirect functions can also set the state (enabled, disabled, or grayed) of a menu item.

See Also

CreateMenu, GetMenuItemID, InsertMenu, InsertMenuItem, LoadMenuIndirect, ModifyMenu, SetMenuItemInfo, WM_SYSCOMMAND


EnableScrollBar
EnableScrollBar  QuickInfo  Overview  Group

The EnableScrollBar function enables or disables one or both scroll bar arrows.

BOOL EnableScrollBar(

HWND  hWnd,	// handle of window or scroll bar
UINT  wSBflags,	// scroll bar type flag
UINT  wArrows	// scroll bar arrow flag
);
Parameters

hWnd

Identifies a window or a scroll bar control, depending on the value of the wSBflags parameter.

wSBflags

Specifies the scroll bar type. This parameter can be one of the following values:

Value	Meaning
SB_BOTH	Enables or disables the arrows on the horizontal and vertical scroll bars associated with the given window. The hWnd parameter must be the handle of the window.
SB_CTL	Identifies the scroll bar as a scroll bar control. The hWnd parameter must be the handle of the scroll bar control.
SB_HORZ	Enables or disables the arrows on the horizontal scroll bar associated with the given window. The hWnd parameter must be the handle of the window.
SB_VERT	Enables or disables the arrows on the vertical scroll bar associated with the given window. The hWnd parameter must be the handle of the window.
wArrows

Specifies whether the scroll bar arrows are enabled or disabled and indicates which arrows are enabled or disabled. This parameter can be one of the following values:

Value	Meaning
ESB_DISABLE_BOTH	Disables both arrows on a scroll bar.
ESB_DISABLE_DOWN	Disables the down arrow on a vertical scroll bar.
ESB_DISABLE_LEFT	Disables the left arrow on a horizontal scroll bar.
ESB_DISABLE_LTUP	Disables the left arrow on a horizontal scroll bar or the up arrow of a vertical scroll bar.
ESB_DISABLE_RIGHT	Disables the right arrow on a horizontal scroll bar.
ESB_DISABLE_RTDN	Disables the right arrow on a horizontal scroll bar or the down arrow of a vertical scroll bar.
ESB_DISABLE_UP	Disables the up arrow on a vertical scroll bar.
ESB_ENABLE_BOTH	Enables both arrows on a scroll bar.
Return Value

If the arrows are enabled or disabled as specified, the return value is TRUE. If the arrows are already in the requested state or an error occurs, the return value is FALSE.

See Also

ShowScrollBar


EnableWindow
EnableWindow  QuickInfo  Overview  Group

The EnableWindow function enables or disables mouse and keyboard input to the specified window or control. When input is disabled, the window does not receive input such as mouse clicks and key presses. When input is enabled, the window receives all input.

BOOL EnableWindow(

HWND  hWnd,	// handle of window
BOOL  bEnable	// flag for enabling or disabling input
);
Parameters

hWnd

Identifies the window to be enabled or disabled.

bEnable

Specifies whether to enable or disable the window. If this parameter is TRUE, the window is enabled. If the parameter is FALSE, the window is disabled.

Return Value

If the window was previously disabled, the return value is TRUE; otherwise, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

If the enabled state of a window is changing, a WM_ENABLE message is sent before this function returns. If a window is already disabled, all its child windows are implicitly disabled, although they are not sent a WM_ENABLE message.

A window must be enabled before it can be activated. For example, if an application is displaying a modeless dialog box and has disabled its main window, the application must enable the main window before destroying the dialog box. Otherwise, another window will receive the keyboard focus and be activated. If a child window is disabled, it is ignored when Windows tries to determine which window should receive mouse messages.

By default, a window is enabled when it is created. To create a window that is initially disabled, an application can specify the WS_DISABLED style in the CreateWindow or CreateWindowEx function. After a window has been created, an application can use the EnableWindow function to enable or disable the window.

An application can use this function to enable or disable a control in a dialog box. A disabled control cannot receive the keyboard focus, nor can a user access it.

See Also

CreateWindow, CreateWindowEx, IsWindowEnabled, WM_ENABLE


EndDeferWindowPos
EndDeferWindowPos  QuickInfo  Overview  Group

The EndDeferWindowPos function simultaneously updates the position and size of one or more windows in a single screen-refreshing cycle.

BOOL EndDeferWindowPos(

HDWP  hWinPosInfo	// handle of internal structure
);
Parameters

hWinPosInfo

Identifies a multiple-window − position structure that contains size and position information for one or more windows. This internal structure is returned by the BeginDeferWindowPos function or by the most recent call to the DeferWindowPos function.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

This function sends the WM_WINDOWPOSCHANGING and WM_WINDOWPOSCHANGED messages to each window identified in the internal structure.

See Also

BeginDeferWindowPos, DeferWindowPos, WM_WINDOWPOSCHANGED, WM_WINDOWPOSCHANGING


EndDialog
EndDialog  QuickInfo  Overview  Group

The EndDialog function destroys a modal dialog box, causing the system to end any processing for the dialog box.

BOOL EndDialog(

HWND  hDlg,	// handle of dialog box
int  nResult	// value to return
);
Parameters

hDlg

Identifies the dialog box to be destroyed.

nResult

Specifies the value to be returned to the application from the function that created the dialog box.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

Dialog boxes created by the DialogBox, DialogBoxParam, DialogBoxIndirect, and DialogBoxIndirectParam functions must be destroyed using the EndDialog function. An application calls EndDialog from within the dialog box procedure; the function must not be used for any other purpose.

A dialog box procedure can call EndDialog at any time, even during the processing of the WM_INITDIALOG message. If your application calls the function while WM_INITDIALOG is being processed, the dialog box is destroyed before it is shown and before the input focus is set.

EndDialog does not destroy the dialog box immediately. Instead, it sets a flag and allows the dialog box procedure to return control to the system. The system checks the flag before attempting to retrieve the next message from the application queue. If the flag is set, the system ends the message loop, destroys the dialog box, and uses the value in nResult as the return value from the function that created the dialog box.

See Also

DialogBox, DialogBoxIndirect, DialogBoxIndirectParam, DialogBoxParam, WM_INITDIALOG


EndDoc
EndDoc  QuickInfo  Overview  Group

The EndDoc function ends a print job. This function replaces the ENDDOC printer escape.

int EndDoc(

HDC  hdc	// handle of device context
);
Parameters

hdc

Identifies the device context for the print job.

Return Value

If the function succeeds, the return value is greater than zero.

If the function fails, the return value is less than or equal to zero. To get extended error information, call GetLastError.

Remarks

Applications should call EndDoc immediately after finishing a print job.

See Also

StartDoc


EndDocPrinter
EndDocPrinter  QuickInfo  Overview  Group

The EndDocPrinter function ends a print job for the given printer.

BOOL EndDocPrinter(

HANDLE  hPrinter	// handle of printer object
);
Parameters

hPrinter

Identifies a printer for which the print job should be ended.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

This function returns an error if the print job was not started by calling the StartDocPrinter function.

See Also

StartDocPrinter


EndPage
EndPage  QuickInfo  Overview  Group

The EndPage function informs the device that the application has finished writing to a page. This function is typically used to direct the device driver to advance to a new page. This function replaces the NEWFRAME printer escape.

int EndPage(

HDC  hdc	// handle of device context
);
Parameters

hdc

Identifies the device context for the print job.

Return Value

If the function succeeds, the return value is greater than zero.

If the function fails, the return value is less than or equal to zero. To get extended error information, call GetLastError.

Remarks

Use the ResetDC function to change the device mode, if necessary, after calling the EndPage function. Note that a call to ResetDC resets all device context attributes back to default values.

Windows 3.x: EndPage resets the device context attributes back to default values. You must re-select objects and set up the mapping mode again before printing the next page.

Windows 95: EndPage does not reset the device context attributes. However, the next StartPage call does reset the device context attributes to default values. At that time, you must re-select objects and set up the mapping mode again before printing the next page.

Windows NT: Beginning with Windows NT Version 3.5, neither EndPage or StartPage resets the device context attributes. Device context attributes remain constant across subsequent pages. You do not need to re-select objects and set up the mapping mode again before printing the next page; however, doing so will produce the same results and reduce code differences between Windows 95 and Windows NT.

See Also

ResetDC, StartPage


EndPagePrinter
EndPagePrinter  QuickInfo  Overview  Group

The EndPagePrinter function indicates the end of one page and the beginning of the next page for the specified printer.

BOOL EndPagePrinter(

HANDLE  hPrinter	// handle of printer object
);
Parameters

hPrinter

Identifies the printer for which the page will be concluded.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The printer-object handle hPrinter is obtained by calling the OpenPrinter function.

Each page in a print job begins with a StartPagePrinter function call and ends with an EndPagePrinter function call. The data for each page is written to the print file by using the WritePrinter function.

See Also

OpenPrinter, StartPagePrinter, WritePrinter


EndPaint
EndPaint  QuickInfo  Overview  Group

The EndPaint function marks the end of painting in the given window. This function is required for each call to the BeginPaint function, but only after painting is complete.

BOOL EndPaint(

HWND  hWnd,	// handle of window
CONST PAINTSTRUCT  *lpPaint	// address of structure for paint data
);
Parameters

hWnd

Identifies the window that has been repainted.

lpPaint

Points to a PAINTSTRUCT structure that contains the painting information retrieved by BeginPaint.

Return Value

This function always returns TRUE.

Remarks

If the caret was hidden by BeginPaint, EndPaint restores the caret to the screen.

See Also

BeginPaint, PAINTSTRUCT


EndPath
EndPath  QuickInfo  Overview  Group

The EndPath function closes a path bracket and selects the path defined by the bracket into the specified device context.

BOOL EndPath(

HDC  hdc	// handle of device context
);
Parameters

hdc

Identifies the device context into which the new path is selected.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError. GetLastError may return one of the following error codes:

ERROR_CAN_NOT_COMPLETE
ERROR_INVALID_PARAMETER

See Also

BeginPath


EndUpdateResource
EndUpdateResource  QuickInfo  Overview  Group

The EndUpdateResource function ends a resource update in an executable file.

BOOL EndUpdateResource(

HANDLE  hUpdate,	// update-file handle
BOOL  fDiscard	// write flag
);
Parameters

hUpdate

Specifies an update handle. This handle is returned by the BeginUpdateResource function.

fDiscard

Specifies whether to write resource updates to an executable file. If this parameter is TRUE, no changes are made to the executable file. If it is FALSE, the changes are made.

Return Value

If the function succeeds and the accumulated resource modifications specified by calls to the UpdateResource function are written to the specified executable file, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

BeginUpdateResource, UpdateResource


EnhMetaFileProc
EnhMetaFileProc  QuickInfo  Overview  Group

The EnhMetaFileProc function is an application-defined callback function that processes enhanced-format metafile records. This function is called by the EnumEnhMetaFile function.

int CALLBACK EnhMetaFileProc(

HDC  hDC,	// handle of device context
HANDLETABLE FAR  *lpHTable,	// address of metafile handle table
ENHMETARECORD FAR  *lpEMFR,	// address of metafile record
int  nObj,	// count of objects
LPARAM  lpData	// address of optional data
);
Parameters

hDC

Identifies the device context passed to EnumEnhMetaFile.

lpHTable

Points to a table of handles associated with the graphics objects (pens, brushes, and so on) in the metafile. The first entry contains the enhanced-metafile handle.

lpEMFR

Points to one of the records in the metafile. This record should not be modified. (If modification is necessary, it should be performed on a copy of the record.)

nObj

Specifies the number of objects with associated handles in the handle table.

lpData

Points to any application-supplied data.

Return Value

This function must return a nonzero value to continue enumeration; to stop enumeration, it must return zero.

Remarks

An application must register the callback function by passing its address to the EnumEnhMetaFile function.

EnhMetaFileProc is a placeholder for the application-supplied function name.

See Also

EnumEnhMetaFile


EnterCriticalSection
EnterCriticalSection  QuickInfo  Overview  Group

The EnterCriticalSection function waits for ownership of the specified critical section object. The function returns when the calling thread is granted ownership.

VOID EnterCriticalSection(

LPCRITICAL_SECTION  lpCriticalSection	// address of critical section object
);
Parameters

lpCriticalSection

Points to the critical section object.

Return Value

This function does not return a value.

Remarks

The threads of a single process can use a critical section object for mutual-exclusion synchronization. The process is responsible for allocating the memory used by a critical section object, which it can do by declaring a variable of type CRITICAL_SECTION. Before using a critical section, some thread of the process must call the InitializeCriticalSection function to initialize the object.

To enable mutually exclusive access to a shared resource, each thread calls EnterCriticalSection to request ownership of the critical section before executing any section of code that accesses the protected resource. If another thread currently owns the critical section object, EnterCriticalSection blocks the execution of the calling thread indefinitely until the other thread releases its ownership. If the critical section object is currently unowned, the system grants ownership to the requesting thread so it can access the resource. When it has finished executing the protected code, the thread uses the LeaveCriticalSection function to relinquish ownership, enabling another thread to become owner and access the protected resource.

Once a thread has ownership of a critical section, it can make additional calls to EnterCriticalSection without blocking its execution. This prevents a thread from deadlocking itself while waiting for a critical section that it already owns. To release its ownership, the thread must call LeaveCriticalSection once for each time that it entered the critical section.

For similar synchronization between the threads of different processes, use a mutex object.

See Also

CreateMutex, DeleteCriticalSection, InitializeCriticalSection, LeaveCriticalSection


EnumCalendarInfo
EnumCalendarInfo  QuickInfo  Overview  Group

The EnumCalendarInfo function enumerates calendar information for a specified locale. The CalType parameter specifies the type of calendar information to enumerate. The function returns the specified calendar information for all applicable calendars for the locale, or for a single requested calendar, depending on the value of the Calendar parameter.

The EnumCalendarInfo function enumerates the calendar information by calling an application-defined callback function. It passes the callback function a pointer to a string buffer containing the requested calendar information. This continues until either the last applicable calendar is found or the callback function returns FALSE.

BOOL EnumCalendarInfo(

CALINFO_ENUMPROC  lpCalInfoEnumProc,	// pointer to enumeration callback function
LCID  Locale,	// locale whose calendar information is of interest
CALID  Calendar,	// calendar whose information is of interest
CALTYPE  CalType	// type of calendar information of interest
);
Parameters

lpCalInfoEnumProc

Points to an application-defined callback function. For more information, see the EnumCalendarInfoProc callback function.

Locale

Specifies the locale to retrieve calendar information for. This parameter can be a locale identifier created by the MAKELCID macro, or one of the following predefined values:

LOCALE_SYSTEM_DEFAULT	Default system locale.
LOCALE_USER_DEFAULT	Default user locale.
Calendar

Specifies the calendar for which information is requested. The following values are defined:

Value	Meaning
ENUM_ALL_CALENDARS	Enumerate all applicable calendars for the locale specified by Locale.
1	Gregorian (localized)
2	Gregorian (English strings always)
3	Japanese era
4	Year of the Republic of China
5	Tangun Era (Korea)
CalType

Indicates the type of calendar information to be returned.  Note that only one CALTYPE value can be specified per call of this function.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError. GetLastError may return one of the following error codes:

ERROR_BADDB
ERROR_INVALID_FLAGS
ERROR_INVALID_PARAMETER

See Also

EnumCalendarInfoProc, EnumDateFormats


EnumCalendarInfoProc
EnumCalendarInfoProc  QuickInfo  Overview  Group

An EnumCalendarInfoProc function is an application-defined callback function. It is called as a result of a call to the EnumCalendarInfo function, and receives a pointer to a string buffer containing a calendar information string.

BOOL CALLBACK EnumCalendarInfoProc(

LPTSTR  lpCalendarInfoString	// pointer to calendar information string
);
Parameters

lpCalendarInfoString

Pointer to a string buffer containing a null-terminated calendar information string. This string is formatted according to the CALTYPE value passed to EnumCalendarInfo. Note that lpCalendarInfoString should be an LPWSTR for the Unicode (W) version of EnumCalendarInfo, and an LPSTR for the ANSI (A) version of EnumCalendarInfo.

Return Value

To continue enumeration, the callback function should return TRUE.

To stop enumeration, the callback function should return FALSE.

Remarks

EnumCalendarInfoProc is a placeholder for an application-defined function name.

An EnumCalendarInfoProc function can carry out any desired task.

An application registers an EnumCalendarInfoProc function by passing its address to the EnumCalendarInfo function.

A value of type CALINFO_ENUMPROC is a pointer to an EnumCalendarInfoProc function.

See Also

EnumCalendarInfo


EnumChildProc
EnumChildProc  QuickInfo  Overview  Group

The EnumChildProc function is an application-defined callback function that receives child window handles as a result of a call to the EnumChildWindows function.

BOOL CALLBACK EnumChildProc(

HWND  hwnd,	// handle of child window
LPARAM  lParam	// application-defined value
);
Parameters

hwnd

Identifies a child window of the parent window specified in EnumChildWindows.

lParam

Specifies the application-defined value given in EnumChildWindows.

Return Value

To continue enumeration, the callback function must return TRUE; to stop enumeration, it must return FALSE.

Remarks

The callback function can carry out any desired task.

An application must register this callback function by passing its address to EnumChildWindows. EnumChildProc is a placeholder for the application-defined function name.

See Also

EnumChildWindows


EnumChildWindows
EnumChildWindows  QuickInfo  Overview  Group

The EnumChildWindows function enumerates the child windows that belong to the specified parent window by passing the handle of each child window, in turn, to an application-defined callback function. EnumChildWindows continues until the last child window is enumerated or the callback function returns FALSE.

BOOL EnumChildWindows(

HWND  hWndParent,	// handle of parent window
WNDENUMPROC  lpEnumFunc,	// address of callback function
LPARAM  lParam	// application-defined value
);
Parameters

hWndParent

Identifies the parent window whose child windows are to be enumerated.

lpEnumFunc

Points to an application-defined callback function. For more information about the callback function, see the EnumChildProc callback function.

lParam

Specifies a 32-bit, application-defined value to be passed to the callback function.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

EnumChildWindows does not enumerate top-level windows owned by the given window, nor does it enumerate any other owned windows.

If a child window has created child windows of its own, this function enumerates those windows as well.

A child window that is moved or repositioned in the Z order during the enumeration process will be properly enumerated. The function does not enumerate a child window that is destroyed before being enumerated or that is created during the enumeration process.

This function is more reliable than calling the GetWindow function in a loop. An application that calls GetWindow to perform this task risks being caught in an infinite loop or referencing a handle to a window that has been destroyed.

See Also

EnumChildProc, EnumThreadWindows, EnumWindows, GetWindow


EnumClipboardFormats
EnumClipboardFormats  QuickInfo  Overview  Group

The EnumClipboardFormats function lets you enumerate the data formats that are currently available on the clipboard.

Clipboard data formats are stored in an ordered list. To perform an enumeration of clipboard data formats, you make a series of calls to the EnumClipboardFormats function. For each call, the format parameter specifies an available clipboard format, and the function returns the next available clipboard format.

UINT EnumClipboardFormats(

UINT  format	// specifies a known available clipboard format
);
Parameters

format

Specifies a clipboard format that is known to be available.

To start an enumeration of clipboard formats, set format to zero. When format is zero, the function retrieves the first available clipboard format. For subsequent calls during an enumeration, set format to the result of the previous EnumClipboardFormat call.

Return Value

If the function succeeds, the return value is the clipboard format that follows the specified format. In other words, the next available clipboard format.

If the function fails, the return value is zero. To get extended error information, call GetLastError. If the clipboard is not open, the function fails.

If there are no more clipboard formats to enumerate, the return value is zero. In this case, the GetLastError function returns the value NO_ERROR. This lets you distinguish between function failure and the end of enumeration.

Remarks

You must open the clipboard before enumerating its formats. Use the OpenClipboard function to open the clipboard. The EnumClipboardFormats function fails if the clipboard is not open.

The EnumClipboardFormats function enumerates formats in the order that they were placed on the clipboard. If you are copying information to the clipboard, add clipboard objects in order from the most descriptive clipboard format to the least descriptive clipboard format. If you are pasting information from the clipboard, retrieve the first clipboard format that you can handle. That will be the most descriptive clipboard format that you can handle.

The operating system provides automatic type conversions for certain clipboard formats. In the case of such a format, this function enumerates the given format, then enumerates the formats to which it can be converted. For more information about clipboard formats and automatic clipboard format type conversions, see the GetClipboardData and SetClipboardData functions.

See Also

CountClipboardFormats, GetClipboardData, OpenClipboard, RegisterClipboardFormat, SetClipboardData


EnumCodePagesProc
EnumCodePagesProc  QuickInfo  Overview  Group

An EnumCodePagesProc function is an application-defined callback function. It is called as a result of a call to the EnumSystemCodePages function, and receives a pointer to a string buffer containing a code page identifier.

BOOL CALLBACK EnumCodePagesProc(

LPTSTR  lpCodePageString	// pointer to code page identifier string
);
Parameters

lpCodePageString

Pointer to a string buffer containing a null-terminated code page identifier string.

Return Value

To continue enumeration, the callback function should return TRUE.

To stop enumeration, the callback function should return FALSE.

Remarks

EnumCodePagesProc is a placeholder for an application-defined function name.

An EnumCodePagesProc function can carry out any desired task.

An application registers an EnumCodePagesProc function by passing its address to the EnumSystemCodePages function.

A value of type CODEPAGE_ENUMPROC is a pointer to an EnumCodePagesProc function.

See Also

EnumSystemCodePages


EnumDateFormats
EnumDateFormats  QuickInfo  Overview  Group

The EnumDateFormats function enumerates the long or short date formats that are available for a specified locale, including date formats for any alternate calendars. The value of the dwFlags parameter determines whether the long or short date formats are enumerated. The function enumerates the date formats by passing date format string pointers, one at a time, to the specified application-defined callback function. This continues until the last date format is found or the callback function returns FALSE.

BOOL EnumDateFormats(

DATEFMT_ENUMPROC  lpDateFmtEnumProc,	// pointer to enumeration callback function
LCID  Locale,	// locale whose date formats are of interest
DWORD  dwFlags	// date formats to enumerate
);
Parameters

lpDateFmtEnumProc

Points to an application-defined callback function. The EnumDateFormats function enumerates date formats by making repeated calls to this callback function. For more information, see the EnumDateFormatsProc callback function.

Locale

Specifies the locale to retrieve date format information for. This parameter can be a locale identifier created by the MAKELCID macro, or one of the following predefined values:

LOCALE_SYSTEM_DEFAULT	Default system locale.
LOCALE_USER_DEFAULT	Default user locale.
dwFlags

Specifies the date formats that are of interest. Use one of the following values:

Value	Meaning
DATE_SHORTDATE	Return short date formats.
DATE_LONGDATE	Return long date formats.
Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError. GetLastError may return one of the following error codes:

ERROR_INVALID_PARAMETER
ERROR_BADDB
ERROR_INVALID FLAGS

Remarks

The DATE_SHORTDATE and DATE_LONGDATE flags are mutually exclusive. Use one or the other, but not both.

See Also

EnumDateFormatsProc, EnumCalendarInfo, EnumTimeFormats


EnumDateFormatsProc
EnumDateFormatsProc  QuickInfo  Overview  Group

An EnumDateFormatsProc function is an application-defined callback function. It is called as a result of a call to the EnumDateFormats function, and receives a pointer to a string buffer containing a date format string.

BOOL CALLBACK EnumDateFormatsProc(

LPTSTR  lpDateFormatString	// pointer to date format string
);
Parameters

lpDateFormatString

Pointer to a string buffer containing a null-terminated date format string. This string is a long or short date format, depending on the value of the dwFlags parameter passed to EnumDateFormats. Note that lpDateFormatString should be an LPWSTR for the Unicode (W) version of EnumDateFormats, and an LPSTR for the ANSI (A) version of EnumDateFormats.

Return Value

To continue enumeration, the callback function should return TRUE.

To stop enumeration, the callback function should return FALSE.

Remarks

EnumDateFormatsProc is a placeholder for an application-defined function name.

An EnumDateFormatsProc function can carry out any desired task.

An application registers an EnumDateFormatsProc function by passing its address to the EnumDateFormats function.

A value of type DATEFMT_ENUMPROC is a pointer to an EnumDateFormatsProc function.

See Also

EnumDateFormats


EnumDependentServices
EnumDependentServices  QuickInfo  Overview  Group

The EnumDependentServices function enumerates services that depend on another specified service; that is, the specified service must be running before the enumerated services can run. The name and status of each dependent service are provided.

BOOL EnumDependentServices(

SC_HANDLE  hService,	// handle of service
DWORD  dwServiceState,	// state of services to enumerate
LPENUM_SERVICE_STATUS  lpServices,	// address of service status buffer
DWORD  cbBufSize,	// size of service status buffer
LPDWORD  pcbBytesNeeded,	// address of variable for bytes needed
LPDWORD  lpServicesReturned	// address of variable for number returned
);
Parameters

hService

Handle that identifies the service. This handle is returned by the OpenService or CreateService function, and it must have SERVICE_ENUMERATE_DEPENDENTS access.

dwServiceState

Specifies the services to enumerate based on their running state. It must be one or both of the following values:

Value	Meaning
SERVICE_ACTIVE	Enumerates services that are in the following states: SERVICE_START_PENDING, SERVICE_STOP_PENDING, SERVICE_RUNNING, SERVICE_CONTINUE_PENDING, SERVICE_PAUSE_PENDING, and SERVICE_PAUSED.
SERVICE_INACTIVE	Enumerates services that are in the SERVICE_STOPPED state.
lpServices

Pointer to an array of ENUM_SERVICE_STATUS structures. Each structure receives name and service status information for a dependent service. The order of the services in this array is the reverse of the start order of the services. In other words, the first dependent service in the array is the one that would be started last, and the last service in the array is the one that would be started first.

cbBufSize

Specifies the size, in bytes, of the buffer pointed to by the lpServices parameter.

pcbBytesNeeded

Pointer to a variable that receives the number of bytes needed to store the array of service entries. The variable only receives this value if the buffer pointed to by lpServices is too small, indicated by function failure and the ERROR_MORE_DATA error; otherwise, the contents of *pcbBytesNeeded are undefined.

lpServicesReturned

Pointer to a variable that receives the number of service entries returned.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Errors

The following error codes may be set by the service control manager. Other error codes may be set by the registry functions that are called by the service control manager.

Value	Meaning
ERROR_ACCESS_DENIED
	The specified handle was not opened with SERVICE_ENUMERATE_DEPENDENTS access.
ERROR_INVALID_HANDLE
	The specified handle is invalid.
ERROR_INVALID_PARAMETER
	A parameter that was specified is invalid.
ERROR_MORE_DATA
	The buffer pointed to by lpServices is not large enough. The function sets the variable pointed to by lpServicesReturned to the actual number of service entries stored into the buffer. The function sets the variable pointed to by pcbBytesNeeded to the number of bytes required to store all of the service entries.
Remarks

The returned services entries are ordered in the reverse order of the start order, with group order taken into account. If you need to stop the dependent services, you can use the order of entries written to the lpServices buffer to stop the dependent services in the proper order.

See Also

CreateService, ENUM_SERVICE_STATUS, EnumServicesStatus, OpenService


EnumDesktopProc [New - Windows NT]
EnumDesktopProc  QuickInfo

[New - Windows NT]

The EnumDesktopProc function is an application-defined callback function that receives a desktop name as a result of a call to the EnumDesktops function.

BOOL CALLBACK EnumDesktopProc(

LPCSTR lpszDesktop,	// name of a desktop
LPARAM lParam	// value specified in EnumDesktops call
);
Parameters

lpszDesktop

Points to the null-terminated name of a desktop.

lParam

Specifies the application-defined value given in the EnumDesktops function.

Return Value

To continue enumeration, the callback function must return TRUE. To stop enumeration, it must return FALSE.

Remarks

The EnumDesktopProc function is a placeholder for the application-defined function name.

See Also

EnumDesktops


EnumDesktops [New - Windows NT]
EnumDesktops  QuickInfo  Overview  Group

[New - Windows NT]

The EnumDesktops function enumerates all desktops in the window station assigned to the calling process. The function does so by passing the name of each desktop, in turn, to an application-defined callback function.

BOOL EnumDesktops(

HWINSTA hwinsta,	// handle of window station to enumerate
DESKTOPENUMPROC lpEnumFunc,	// points to application's callback function
LPARAM lParam	// 32-bit value to pass to the callback function
);
Parameters

hwinsta

Specifies the handle of the window station whose desktops are to be enumerated. The CreateWindowStation, GetProcessWindowStation, and OpenWindowStation functions return a window station handle.

lpEnumFunc

Points to an application-defined EnumDesktopProc callback function.

dwDesiredAccess

Specifies a 32-bit application-defined value to be passed to the callback function.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The calling process must have WINSTA_ENUMDESKTOPS access to the window station. The EnumDesktops function enumerates only those desktops for which the calling process has DESKTOP_ENUMERATE access.

The EnumDesktops function repeatedly invokes the lpEnumFunc callback function until the last desktop is enumerated or the callback function returns FALSE.

See Also

CreateWindowStation, EnumDesktopProc, GetProcessWindowStation, OpenWindowStation


EnumDesktopWindows [New - Windows NT]
EnumDesktopWindows  QuickInfo  Overview  Group

[New - Windows NT]

The EnumDesktopWindows function enumerates all windows in a desktop by passing the handle of each window, in turn, to an application-defined callback function.

BOOL EnumDesktopWindows(

HDESK hDesktop,	// handle of desktop to enumerate
WNDENUMPROC lpfn,	// points to application's callback function
LPARAM lParam	// 32-bit value to pass to the callback function
);
Parameters

hDesktop

Specifies the handle of the desktop whose windows are to be enumerated. The CreateDesktop, OpenDesktop, and GetThreadDesktop functions return a desktop handle.

lpfn

Points to an application-defined EnumWindowsProc callback function.

lParam

Specifies a 32-bit application-defined value to be passed to the callback function.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The EnumDesktopWindows function repeatedly invokes the lpfn callback function until the last window is enumerated or the callback function returns FALSE.

See Also

CreateDesktop, EnumWindowsProc, GetThreadDesktop, OpenDesktop


EnumDisplaySettings [New - Windows NT]
EnumDisplaySettings  QuickInfo  Overview  Group

[New - Windows NT]

The EnumDisplaySettings function obtains information about one of a display device's graphics modes. You can obtain information for all of a display device's graphics modes by making a series of calls to this function.

BOOL EnumDisplaySettings(

LPCTSTR lpszDeviceName,	// specifies the display device
DWORD iModeNum,	// specifies the graphics mode
LPDEVMODE lpDevMode	// points to structure to receive settings
);
Parameters

lpszDeviceName

Pointer to a null-terminated string that specifies the display device whose graphics mode the function will obtain information about.

This parameter can be NULL. A NULL value specifies the current display device on the computer that the calling thread is running on.

If lpszDeviceName is not NULL, the string must be of the form \\.\DisplayX, where X can have the values 1, 2, or 3.

Windows 95: lpszDeviceName must be NULL.

iModeNum

Index value that specifies the graphics mode for which information is to be obtained.

Graphics mode indexes start at zero. To obtain information for all of a display device's graphics modes, make a series of calls to EnumDisplaySettings, as follows: Set iModeNum to zero for the first call, and increment iModeNum by one for each subsequent call. Continue calling the function until the return value is FALSE.

When you call EnumDisplaySettings with iModeNum set to zero, the operating system initializes and caches information about the display device. When you call EnumDisplaySettings with iModeNum set to a non-zero value, the function returns the information that was cached the last time the function was called with iModeNum set to zero.

lpDevMode

Pointer to a DEVMODE structure into which the function stores information about the specified graphics mode.

The EnumDisplaySettings function sets values for the following five DEVMODE members:

dmBitsPerPel
dmPelsWidth
dmPelsHeight
dmDisplayFlags
dmDisplayFrequency

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

The function fails if iModeNum is greater than the index of the display device's last graphics mode. As noted in the description of the iModeNum parameter, you can use this behavior to enumerate all of a display device's graphics modes.

See Also

CreateDC, CreateDesktop, DEVMODE


EnumEnhMetaFile
EnumEnhMetaFile  QuickInfo  Overview  Group

The EnumEnhMetaFile function enumerates the records within an enhanced-format metafile by retrieving each record and passing it to the specified callback function. The application-supplied callback function processes each record as required. The enumeration continues until the last record is processed or when the callback function returns zero.

BOOL EnumEnhMetaFile(

HDC  hdc,	// handle of device context
HENHMETAFILE  hemf,	// handle of enhanced metafile
ENHMFENUMPROC  lpEnhMetaFunc,	// address of callback function
LPVOID  lpData,	// address of callback-function data
CONST RECT *  lpRect	// address of bounding rectangle
);
Parameters

hdc

Identifies a device context. This handle is passed to the callback function.

hemf

Identifies an enhanced metafile.

lpEnhMetaFunc

Points to the application-supplied callback function. For more information, see the EnhMetaFileProc function.

lpData

Points to optional callback-function data.

lpRect

Points to a RECT structure that specifies the coordinates of the picture's upper-left and lower-right corners. The dimensions of this rectangle are specified in logical units.

Return Value

If the callback function successfully enumerates all the records in the enhanced metafile, the return value is TRUE; otherwise, it is FALSE.

Remarks

Points along the edge of the rectangle pointed to by the lpRect parameter are included in the picture. If the hdc parameter is NULL, Windows ignores lpRect.

If the callback function calls the PlayEnhMetaFileRecord function, hdc must identify a valid device context. Windows uses the device context's transformation and mapping mode to transform the picture displayed by the PlayEnhMetaFileRecord function.

You can use the EnumEnhMetaFile function to embed one enhanced-metafile within another.

See Also

EnhMetaFileProc, PlayEnhMetaFile, PlayEnhMetaFileRecord, RECT


EnumFontFamExProc [New - Windows 95]
EnumFontFamExProc  QuickInfo

[New - Windows 95]

The EnumFontFamExProc function is an application-supplied callback function that processes the fonts enumerated by the EnumFontFamiliesEx function. The system calls this callback function once for each enumerated font.

int CALLBACK EnumFontFamExProc(

ENUMLOGFONTEX * lpelfe,	// address of logical-font data
NEWTEXTMETRICEX * lpntme,	// address of physical-font data
int FontType,	// type of font
LPARAM lParam	// application-defined data
);
Parameters

lpelfe

Points to an ENUMLOGFONTEX structure that contains information about the logical attributes of the font.

lpntme

Points to a structure that contains information about the physical attributes of a font. The function uses the NEWTEXTMETRICEX structure for TrueType fonts; and the TEXTMETRIC structure for other fonts.

Windows 95: The NEWTEXTMETRICEX structure is not implemented. Use NEWTEXTMETRIC instead.

FontType

Specifies the type of the font. This parameter can be a combination of these values:

DEVICE_FONTTYPE
RASTER_FONTTYPE
TRUETYPE_FONTTYPE
lParam

Specifies the application-defined data passed by the EnumFontFamiliesEx function.

Return Value

The return value must be a nonzero value to continue enumeration; to stop enumeration, the return value must be zero.

Remarks

Unlike the EnumFontFamProc callback function, EnumFontFamExProc receives extended information about a font. The ENUMLOGFONTEX structure includes the localized name of the script (character set) and the NEWTEXTMETRICEX structure includes a font-coverage signature.

See Also

EnumFontFamiliesEx, EnumFontFamProc, ENUMLOGFONTEX, NEWTEXTMETRICEX, TEXTMETRIC


EnumFontFamilies
EnumFontFamilies  QuickInfo  Overview  Group

The EnumFontFamilies function enumerates the fonts in a specified font family that are available on a specified device. This function supersedes the EnumFonts function.

int EnumFontFamilies(

HDC  hdc,	// handle of device control
LPCTSTR  lpszFamily,	// address of family-name string
FONTENUMPROC  lpEnumFontFamProc,	// address of callback function
LPARAM  lParam	// address of application-supplied data
);
Parameters

hdc

Identifies the device context.

lpszFamily

Points to a null-terminated string that specifies the family name of the desired fonts. If lpszFamily is NULL, EnumFontFamilies randomly selects and enumerates one font of each available type family.

lpEnumFontFamProc

Specifies the procedure-instance address of the application-defined callback function. For information about the callback function, see the EnumFontFamProc function.

lParam

Points to application-supplied data. The data is passed to the callback function along with the font information.

Return Value

If the function succeeds, the return value is the last value returned by the callback function. Its meaning is implementation specific.

Remarks

The EnumFontFamilies function differs from the EnumFonts function in that it retrieves the style names associated with a TrueType font. With EnumFontFamilies, information can be retrieved about unusual font styles (for example, Outline) that could not be enumerated by using the EnumFonts function. Win32-based applications should use EnumFontFamilies instead of EnumFonts.

For each font having the typeface name specified by the lpszFamily parameter, the EnumFontFamilies function retrieves information about that font and passes it to the function pointed to by the lpEnumFontFamProc parameter. The application-defined callback function can process the font information as desired. Enumeration continues until there are no more fonts or the callback function returns zero.

See Also

EnumFontFamProc, EnumFonts


EnumFontFamiliesEx [New - Windows 95]
EnumFontFamiliesEx  QuickInfo

[New - Windows 95]

The EnumFontFamiliesEx function enumerates all fonts in the system that match the font characteristics given by the the LOGFONT structure. EnumFontFamiliesEx enumerates fonts based on typeface name, character set, or both. It is recommended that Win32-based applications use this function rather than EnumFontFamilies to enumerate fonts.

int EnumFontFamiliesEx(

HDC hdc,	// handle of device context
LPLOGFONT lpLogfont,	// address of logical font information
FONTENUMPROC lpEnumFontFamExProc,	// address of callback function
LPARAM lParam,	// application-supplied data
DWORD dwFlags	// reserved; must be zero
);
Parameters

hdc

Identifies the device context.

lpLogfont

Points to a LOGFONT structure that contains information about the fonts to enumerate. The function examines these members:

Member	Description
lfCharset	If set to DEFAULT_CHARSET, the function enumerates all fonts in all character sets. If set to a valid character set value, the function enumerates only fonts in the given character set.
lfFaceName	If set to an empty string, the function enumerates one font in each available typeface name. If set to a valid typeface name, the function enumerates all fonts with the specified name.
lfPitchAndFamily	Must be set to zero for all language versions of the operating system except Hebrew and Arabic. For these languages, set IfPitchAndFamily to MONO_FONT to enumerate only fonts that provide all codepage characters within the font.
lpEnumFontFamExProc

Points to the application-defined callback function. For more information about the callback function, see the EnumFontFamExProc function.

lParam

Specifies a 32-bit application-defined value. The function passes this value to the callback function along with font information.

dwFlags

Reserved; must be zero.

Return Value

If the function succeeds, the return value is the last value returned by the callback function. This value depends on which font families are available for the given device.

Remarks

EnumFontFamiliesEx does not use "tagged" typeface names to identify character sets. Instead, it always passes the correct typeface name and a separate character set value to the callback function. The function enumerates fonts based on the the values of the lfCharset and lfFacename members in the LOGFONT structure.

If lfCharset is DEFAULT_CHARSET and lfFaceName is an empty string, the function enumerates one font in every face in every character set. If lfFaceName is not empty, the function enumerates every font in the specified typeface regardless of character set.

If lfCharset is a valid character set value and lfFaceName is an empty string, the function enumerates every font in the specified character set. If lfFaceName is not empty, the function enumerates every font having the specified typeface and character set.

See Also

EnumFontFamilies, EnumFontFamExProc, LOGFONT


EnumFontFamProc
EnumFontFamProc  QuickInfo  Overview  Group

The EnumFontFamProc function is an application-defined callback function that retrieves data describing available fonts.

int CALLBACK EnumFontFamProc(

ENUMLOGFONT FAR*  lpelf,	// address of logical-font data
NEWTEXTMETRIC FAR*  lpntm,	// address of physical-font data
int  FontType,	// type of font
LPARAM  lParam	// address of application-defined data
);
Parameters

lpelf

Points to an ENUMLOGFONT structure that contains information about the logical attributes of the font. This structure is locally defined.

lpntm

Points to a NEWTEXTMETRIC structure that contains information about the physical attributes of the font, if the font is a TrueType font. If the font is not a TrueType font, this parameter points to a TEXTMETRIC structure.

FontType

Specifies the type of the font. This parameter can be a combination of the following values:

DEVICE_FONTTYPE
RASTER_FONTTYPE
TRUETYPE_FONTTYPE

lParam

Points to the application-defined data passed by the EnumFontFamilies function.

Return Value

The return value must be a nonzero value to continue enumeration; to stop enumeration, it must return zero.

Remarks

An application must register this callback function by passing its address to the EnumFontFamilies function.

The EnumFontFamProc function is a placeholder for the application-defined function name.

The AND (&) operator can be used with the RASTER_FONTTYPE, DEVICE_FONTTYPE, and TRUETYPE_FONTTYPE constants to determine the font type. If the RASTER_FONTTYPE bit is set, the font is a raster font. If the TRUETYPE_FONTTYPE bit is set, the font is a TrueType font. If neither bit is set, the font is a vector font. DEVICE_FONTTYPE is set when a device (for example, a laser printer) supports downloading TrueType fonts or when the font is a device-resident font; it is zero if the device is a display adapter, dot-matrix printer, or other raster device. An application can also use DEVICE_FONTTYPE to distinguish graphics device interface (GDI)-supplied raster fonts from device-supplied fonts. GDI can simulate bold, italic, underline, and strikeout attributes for GDI-supplied raster fonts, but not for device-supplied fonts.

See Also

EnumFontFamilies, EnumFontFamProc, EnumFonts, ENUMLOGFONT, NEWTEXTMETRIC, TEXTMETRIC


EnumFonts
EnumFonts  QuickInfo  Overview  Group

The EnumFonts function enumerates the fonts available on a specified device. For each font with the specified typeface name, the EnumFonts function retrieves information about that font and passes it to the application-defined callback function. This callback function can process the font information as desired. Enumeration continues until there are no more fonts or the callback function returns zero.

This function is provided for compatibility with earlier versions of Microsoft Windows. Win32-based applications should use the EnumFontFamilies function.

int EnumFonts(

HDC  hdc,	// handle of device context
LPCTSTR  lpFaceName,	// address of font typeface name string
FONTENUMPROC  lpFontFunc,	// address of callback function
LPARAM  lParam	// address of application-supplied data
);
Parameters

hdc

Identifies the device context.

lpFaceName

Points to a null-terminated character string that specifies the typeface name of the desired fonts. If lpFaceName is NULL, EnumFonts randomly selects and enumerates one font of each available typeface.

lpFontFunc

Points to the application-defined callback function. For more information about the callback function, see the EnumFontsProc function.

lParam

Points to any application-defined data. The data is passed to the callback function along with the font information.

Return Value

If the function succeeds, the return value is the last value returned by the callback function. Its meaning is defined by the application.

Remarks

Use EnumFontFamilies instead of EnumFonts. The EnumFontFamilies function differs from the EnumFonts function in that it retrieves the style names associated with a TrueType font. With EnumFontFamilies, you can retrieve information about unusual font styles (for example, Outline) that cannot be enumerated using the EnumFonts function.

See Also

EnumFontFamilies, EnumFontsProc, GetDeviceCaps


EnumFontsProc
EnumFontsProc  QuickInfo  Overview  Group

The EnumFontsProc function is an application-defined callback function that processes font data from the EnumFonts function.

int CALLBACK EnumFontsProc(

lplf  lplf,	// address of logical-font data
lptm  lptm,	// address of physical-font data
DWORD  dwType,	// font type
LPARAM  lpData	// address of application-defined data
);
Parameters

lplf

Points to a LOGFONT structure that contains information about the logical attributes of the font.

lptm

Points to a TEXTMETRIC structure that contains information about the physical attributes of the font.

dwType

Specifies the type of the font. This parameter can be a combination of the following values:

DEVICE_FONTTYPE
RASTER_FONTTYPE
TRUETYPE_FONTTYPE

lpData

Points to the application-defined data passed by EnumFonts.

Return Value

The return value must be a nonzero value to continue enumeration; to stop enumeration, it must be zero.

Remarks

The AND (&) operator can be used with the RASTER_FONTTYPE and DEVICE_FONTTYPE constants to determine the font type. The RASTER_FONTTYPE bit of the FontType parameter specifies whether the font is a raster or vector font. If the bit is one, the font is a raster font; if zero, it is a vector font. The DEVICE_FONTTYPE bit of FontType specifies whether the font is a device-based or graphics device interface (GDI)-based font. If the bit is one, the font is a device-based font; if zero, it is a GDI-based font.

If the device is capable of text transformations (scaling, italicizing, and so on) only the base font is enumerated. The user must inquire into the device's text-transformation abilities to determine which additional fonts are available directly from the device.

An application must register the EnumFontsProc function by passing its address to the EnumFonts function.

EnumFontsProc is a placeholder for the application-defined function name.

See Also

EnumFonts, LOGFONT, TEXTMETRIC


EnumForms
EnumForms  QuickInfo  Overview  Group

The EnumForms function enumerates the forms supported by the specified printer.

BOOL EnumForms(

HANDLE  hPrinter,	// handle of printer object
DWORD  Level,	// data-structure level
LPBYTE  pForm,	// points to buffer that receives form info. structure array
DWORD  cbBuf,	// count of bytes in buffer
LPDWORD  pcbNeeded,	// points to variable to receive count of bytes copied or required
LPDWORD  pcReturned	// points to variable to receive count of structures copied
);
Parameters

hPrinter

Identifies the printer for which the forms should be enumerated.

Level

Specifies the version of the structure to which pForm points. This value must be 1.

pForm

Points to a FORM_INFO_1 structure.

cbBuf

Specifies the size, in bytes, of the buffer to which pForm points.

pcbNeeded

Points to a variable that receives the number of bytes copied to or the number of bytes required for the array to which pForm points. If cbBuf is too small, this value specifies the number of bytes required; otherwise, this value specifies the number of bytes copied.

pcReturned

Points to a variable that receives the number of FORM_INFO_1 structures copied into the array to which pForm points.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The printer-object handle hPrinter is normally obtained by calling the OpenPrinter function. The AddPrinter function can also be used.

See Also

AddPrinter, FORM_INFO_1, OpenPrinter


EnumICMProfiles [New - Windows 95]
EnumICMProfiles  QuickInfo  Overview  Group

[New - Windows 95]

The EnumICMProfiles function enumerates the different color profiles that the system supports for the specified device context.

int EnumICMProfiles(

HDC hdc,
ICMENUMPROC  lpICMEnumFunc,
LPARAM  lParam
);
Parameters

hdc

Handle to the device context.

lpICMEnumFunc

Pointer to the application-defined callback function. For more information, see the EnumICMProfilesProc function.

lParam

Application-supplied data. The data is passed to the callback function along with the color profile information.

Return Value

Returns −1 if there are no color profiles to enumerate or image color matching is not enabled. Otherwise, it returns the last value returned by the callback function, which may be zero if the callback interrupted the enumeration.

See Also

EnumICMProfilesProc


EnumICMProfilesProc [New - Windows 95]
EnumICMProfilesProc  QuickInfo  Overview  Group

[New - Windows 95]

The EnumICMProfilesProc function is an application-defined callback function that processes color profile data from the EnumICMProfiles function.

int CALLBACK EnumICMProfilesProc(

LPTSTR lpszFilename,
LPARAM  lParam
);
Parameters

lpszFilename

Pointer to a null-terminated string specifying the name of the color profile file.

lParam

Application-supplied data passed by the EnumICMProfiles function.

Return Value

Returns a positive value to continue enumeration, or 0 to stop enumeration. The function must not return a negative value.

See Also

EnumICMProfiles


EnumJobs
EnumJobs  QuickInfo  Overview  Group

The EnumJobs function initializes an array of either JOB_INFO_1 or JOB_INFO_2 structures with data describing the specified print jobs for the specified printer.

BOOL EnumJobs(

HANDLE  hPrinter,	// handle of printer object
DWORD  FirstJob,	// location of first job in print queue to enumerate
DWORD  NoJobs,	// number of jobs to enumerate
DWORD  Level,	// structure level
LPBYTE  pJob,	// address of structure array
DWORD  cbBuf,	// size of array, in bytes
LPDWORD  pcbNeeded,	// addr. of variable with no. of bytes copied (or required)
LPDWORD  pcReturned	// addr. of variable with no. of job info. structures copied
);
Parameters

hPrinter

Handle to the printer object whose print jobs the function will enumerate.

FirstJob

Specifies the zero-based position within the print queue of the first print job to enumerate. For example, a value of 0 specifies that enumeration should begin at the first print job in the print queue; a value of 9 specifies that enumeration should begin at the tenth print job in the print queue.

NoJobs

Specifies the total number of print jobs to enumerate.

Level

Specifies whether the function should use JOB_INFO_1 or JOB_INFO_2 structures to store data for the enumerated jobs. A value of 1 specifies that the JOB_INFO_1 structure should be used; a value of 2 specifies that the JOB_INFO_2 structure should be used.

pJob

Points to an array of either JOB_INFO_1 or JOB_INFO_2 structures.

cbBuf

Specifies the size, in bytes, of the array pJob.

pcbNeeded

Points to a variable that receives the number of bytes copied if the function succeeds. If the function fails, the variable receives the number of bytes required.

pcReturned

Points to a variable that receives the number of JOB_INFO_1 or JOB_INFO_2 structures that were initialized.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The handle hPrinter is obtained by calling the OpenPrinter function.

The JOB_INFO_1 structure contains general print-job information; the JOB_INFO_2 structure has much more detailed information.

See Also

GetJob, JOB_INFO_1, JOB_INFO_2, OpenPrinter, SetJob


EnumLocalesProc
EnumLocalesProc  QuickInfo  Overview  Group

An EnumLocalesProc function is an application-defined callback function. It is called as a result of a call to the EnumSystemLocales function, and receives a pointer to a string buffer containing a locale identifier.

BOOL CALLBACK EnumLocalesProc(

LPTSTR  lpLocaleString	// pointer to locale identifier string
);
Parameters

lpLocaleString

Pointer to a string buffer containing a null-terminated locale identifier string. Note that lpLocaleString should be an LPWSTR for the Unicode (W) version of EnumLocalesProc, and an LPSTR for the ANSI (A) version of EnumLocalesProc.

Return Value

To continue enumeration, the callback function should return TRUE.

To stop enumeration, the callback function should return FALSE.

Remarks

EnumLocalesProc is a placeholder for an application-defined function name.

An application registers an EnumLocalesProc function by passing its address to the EnumSystemLocales function.

A value of type LOCALE_ENUMPROC is a pointer to an EnumLocalesProc function.

See Also

EnumSystemLocales


EnumMetaFile
EnumMetaFile  QuickInfo  Overview  Group

The EnumMetaFile function enumerates the records within a Windows-format metafile by retrieving each record and passing it to the specified callback function. The application-supplied callback function processes each record as required. The enumeration continues until the last record is processed or when the callback function returns zero.

This function is provided for compatibility with earlier versions of Microsoft Windows. Win32-based applications should use the EnumEnhMetaFile function.

BOOL EnumMetaFile(

HDC  hdc,	// handle of device context
HMETAFILE  hmf,	// handle of Windows-format metafile
MFENUMPROC  lpMetaFunc,	// address of callback function
LPARAM  lParam	// address of callback function data
);
Parameters

hdc

Identifies a device context. This handle is passed to the callback function.

hmf

Identifies a Windows-format metafile.

lpMetaFunc

Points to an application-supplied callback function. For more information, see the EnumMetaFileProc callback function.

lParam

Points to optional callback-function data.

Return Value

If the callback function successfully enumerates all the records in the Windows-format metafile, the return value is TRUE; otherwise, it is FALSE.

Remarks

A Windows-format metafile does not support the new curve, path, and transformation functions, such as PolyBezier, BeginPath, and SetWorldTransform. Applications that use these new functions and use metafiles to store pictures created by these functions should use the enhanced-format metafile functions.

To convert a Windows-format metafile into an enhanced-format metafile, use the SetWinMetaFileBits function.

You can use the EnumMetaFile function to embed one Windows-format metafile within another.

See Also

BeginPath, EnumEnhMetaFile, EnumMetaFileProc, PlayMetaFile, PlayMetaFileRecord, PolyBezier, SetWinMetaFileBits, SetWorldTransform


EnumMetaFileProc
EnumMetaFileProc  QuickInfo  Overview  Group

The EnumMetaFileProc function is an application-defined callback function that processes Windows-format metafile records. This function is called by the EnumMetaFile function.

This function is provided for compatibility with earlier versions of Microsoft Windows. Win32-based applications should use the EnhMetaFileProc and EnumEnhMetaFile functions.

int CALLBACK EnumMetaFileProc(

HDC  hDC,	// handle of device context
HANDLETABLE FAR  *lpHTable,	// address of metafile handle table
METARECORD FAR  *lpMFR,	// address of metafile record
int  nObj,	// count of objects
LPARAM  lpClientData	// address of optional data
);
Parameters

hDC

Identifies the device context passed to EnumMetaFile.

lpHTable

Points to a table of handles associated with the graphics objects (pens, brushes, and so on) in the metafile.

lpMFR

Points to one of the records in the metafile. This record should not be modified. (If modification is necessary, it should be performed on a copy of the record.)

nObj

Specifies the number of objects with associated handles in the handle table.

lpClientData

Points to any application-supplied data.

Return Value

This function must return a nonzero value to continue enumeration; to stop enumeration, it must return zero.

Remarks

An application must register the callback function by passing its address to the EnumMetaFile function.

EnumMetaFileProc is a placeholder for the application-supplied function name.

See Also

EnhMetaFileProc, EnumEnhMetaFile, EnumMetaFile


EnumMonitors
EnumMonitors  QuickInfo  Overview  Group

The EnumMonitors function initializes an array of MONITOR_INFO_1 structures with data describing the monitors for the specified server.

BOOL EnumMonitors(

LPTSTR  pName,	// address of server name
DWORD  Level,	// structure level
LPBYTE  pMonitors,	// address of structure array
DWORD  cbBuf,	// size, in bytes, of buffer
LPDWORD  pcbNeeded,	// addr. of variable with no. of bytes copied (or required)
LPDWORD  pcReturned	// addr. of variable with no. of job info. structures copied
);
Parameters

pName

Points to a null-terminated string that specifies the name of the server on which the monitors reside. If this parameter is NULL, the local monitors are enumerated.

Level

Specifies the version of the structure pointed to by pMonitors.

pMonitors

Points to an array of MONITOR_INFO_1 structures.

cbBuf

Specifies the size, in bytes, of the buffer pointed to by pMonitors.

pcbNeeded

Points to a variable that receives the number of bytes copied if the function succeeds or the number of bytes required if cbBuf is too small.

pcReturned

Points to a variable that receives the number of MONITOR_INFO_1 structures that were returned in the buffer pointed to by pMonitors.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

MONITOR_INFO_1


EnumObjects
EnumObjects  QuickInfo  Overview  Group

The EnumObjects function enumerates the pens or brushes available for the specified device context. This function calls the application-defined callback function once for each available object, supplying data describing that object. EnumObjects continues calling the callback function until the callback function returns zero or until all of the objects have been enumerated.

int EnumObjects(

HDC  hdc,	// handle of device context
int  nObjectType,	// object-type identifier
GOBJENUMPROC  lpObjectFunc,	// address of callback function
LPARAM  lParam	// address of application-supplied data
);
Parameters

hdc

Identifies the device context.

nObjectType

Specifies the object type. This parameter can be OBJ_BRUSH or OBJ_PEN.

lpObjectFunc

The address of the application-defined callback function. For more information about the callback function, see the EnumObjectsProc function.

lParam

Points to the application-defined data. The data is passed to the callback function along with the object information.

Return Value

The return value specifies the last value returned by the callback function. Its meaning is user-defined. The return value is -1 if there are too many objects to enumerate. In this case, the callback function is not called.

See Also

EnumObjectsProc, GetObject


EnumObjectsProc
EnumObjectsProc  QuickInfo  Overview  Group

The EnumObjectsProc function is an application-defined callback function that processes object data supplied by the EnumObjects function.

VOID CALLBACK EnumObjectsProc(

LPVOID  lpLogObject,	// address of graphic-object structure
LPARAM  lpData	// address of application-defined data
);
Parameters

lpLogObject

Points to a LOGPEN or LOGBRUSH structure describing the attributes of the object.

lpData

Points to the application-defined data passed by the EnumObjects function.

Return Value

This function does not return a value.

Remarks

An application must register this function by passing its address to the EnumObjects function. EnumObjectsProc is a placeholder for the application-defined function name.

See Also

EnumObjects, GlobalAlloc, GlobalLock, LOGPEN, LOGBRUSH


EnumPorts
EnumPorts  QuickInfo  Overview  Group

The EnumPorts function enumerates the ports that are available for printing on a specified server.

BOOL EnumPorts(

LPTSTR  pName,	// pointer to server name
DWORD  Level,	// specifies type of port info structure
LPBYTE  pPorts,	// pointer to buffer to receive array of port info. structures
DWORD  cbBuf,	// specifies size, in bytes, of buffer
LPDWORD  pcbNeeded,	// pointer to number of bytes stored into buffer (or required  // buffer size)
LPDWORD  pcReturned	// pointer to number of PORT_INFO_*. structures stored into buffer
);
Parameters

pName

Pointer to a null-terminated string that specifies the name of the server whose printer ports you wish to enumerate.

If pName is NULL, the function enumerates the local machine's printer ports.

Level

Specifies the type of data structures pointed to by pPorts.

Windows 95: This value can be 1 or 2.

Windows NT: This value must be 1.

pPorts

Pointer to a buffer that receives an array of PORT_INFO_1 or PORT_INFO_2 structures. Each structure contains data that describes an available printer port. The value of Level specifies the type of structure. A Level value of 1 specifies PORT_INFO_1 structures. A Level value of 2 specifies PORT_INFO_2 structures.

Windows 95: The buffer can receive either type of data structure.

Windows NT: The buffer can receive only PORT_INFO_1 data structures.

cbBuf

Specifies the size, in bytes, of the buffer pointed to by pPorts.

pcbNeeded

Pointer to a variable that the function sets to the size, in bytes, of the data that enumerates the printer ports. If cbBuf is smaller than this value, EnumPorts fails, GetLastError returns ERROR_INSUFFICIENT_BUFFER, and the variable pointed to by pcbNeeded represents the required buffer size. If cbBuf is equal to or greater than this value, the variable pointed to by pcbNeeded represents the number of bytes stored into the buffer.

pcReturned

Pointer to a variable that the function sets to the number of PORT_INFO_* structures that it stores into the buffer pointed to by pPorts. This is the number of printer ports that are available on the specified server.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The EnumPorts function can succeed even if the server specified by pName does not have a printer defined.

See Also

AddPort, DeletePort, PORT_INFO_1


EnumPrinterDrivers
EnumPrinterDrivers  QuickInfo  Overview  Group

The EnumPrinterDrivers function enumerates all of the printer drivers installed on the specified printer server.

BOOL EnumPrinterDrivers(

LPTSTR  pName,	// pointer to server name
LPTSTR  pEnvironment,	// pointer to environment name
DWORD  Level,	// structure level
LPBYTE  pDriverInfo,	// pointer to an array of structures
DWORD  cbBuf,	// size, in bytes, of array
LPDWORD  pcbNeeded,	// pointer to number of bytes copied (or required)
LPDWORD  pcReturned	// pointer to number of DRIVER_INFO. structures
);
Parameters

pName

Pointer to a null-terminated string that specifies the name of the server on which the printer drivers should be enumerated.

If pName is NULL, the function enumerates the local machine's printer drivers.

pEnvironment

Pointer to a null-terminated string that specifies the environment. For example, "Windows NT x86" specifies Windows NT running on an Intel 80386 or 80486 processor. If this parameter is NULL, the function uses the current environment of the caller/client (not of the destination/server).

Level

Specifies the type of DRIVER_INFO_* structures pointed to by pDriverInfo. This value must be 1, 2, or 3.

Windows NT: The value must be 1 or 2.

pDriverInfo

Pointer to a buffer that receives an array of DRIVER_INFO_1, DRIVER_INFO_2, or DRIVER_INFO_3 structures. Each structure contains data that describes an available printer driver.

Windows NT: The structures must be either DRIVER_INFO_1 or DRIVER_INFO_2.

cbBuf

Specifies the size, in bytes, of the buffer pointed to by pDriverInfo.

pcbNeeded

Pointer to a value that the function sets to the size in bytes of the data that enumerates the printer drivers. If cbBuf is smaller than this value, EnumPrinterDrivers fails, and the variable pointed to by pcbNeeded represents the required buffer size. If cbBuf is equal to or greater than this value, the variable pointed to by pcbNeeded represents the number of bytes stored into the buffer.

pcReturned

Pointer to a value that specifies the number of DRIVER_INFO_* structures that it stores into the buffer pointed to by pDriverInfo. This is the number of printer drivers installed on the specified print server.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

AddPrinterDriver, DRIVER_INFO_1, DRIVER_INFO_2, DRIVER_INFO_3, GetPrinterDriver


EnumPrinters
EnumPrinters  QuickInfo  Overview  Group

The EnumPrinters function enumerates available printers, print servers, domains, or print providers.

BOOL EnumPrinters(

DWORD  Flags,	// types of printer objects to enumerate
LPTSTR  Name,	// name of printer object
DWORD  Level,	// specifies type of printer info structure
LPBYTE  pPrinterEnum,	// pointer to buffer to receive printer info structures
DWORD  cbBuf,	// size, in bytes, of array
LPDWORD  pcbNeeded,	// pointer to variable with no. of bytes copied (or required)
LPDWORD  pcReturned	// pointer to variable with no. of printer info. structures copied
);
Parameters

Flags

Specifies the types of print objects that the function should enumerate. This value can be a combination of the following constants:

Value	Meaning
PRINTER_ENUM_LOCAL	The function ignores the Name parameter, and enumerates the locally installed printers. Windows 95 only: The function will also enumerate network printers because they are handled by the local print provider.
PRINTER_ENUM_NAME	The function enumerates the printer identified by Name. This can be a server, a domain, or a print provider. If Name is NULL, the function enumerates available print providers.
PRINTER_ENUM_SHARED	The function enumerates printers that have the shared attribute. Cannot be used in isolation; use an OR operation to combine with another PRINTER_ENUM type.
PRINTER_ENUM_CONNECTIONS	Windows NT only: The function enumerates the list of printers to which the user has made previous connections.
PRINTER_ENUM_NETWORK	Windows NT only: The function enumerates network printers in the computer's domain. This value is valid only if Level is 1.
PRINTER_ENUM_REMOTE	Windows NT only: The function enumerates network printers and print servers in the computer's domain. This value is valid only if Level is 1.
If Level is 4, you can only use the PRINTER_ENUM_CONNECTIONS and PRINTER_ENUM_LOCAL constants.

Name

If Level is 1, Flags contains PRINTER_ENUM_NAME, and Name is non-NULL, Name points to a null-terminated string that specifies the name of the object to enumerate. This string can be the name of a server, a domain, or a print provider.

If Level is 1, Flags contains PRINTER_ENUM_NAME, and Name is NULL, the function enumerates the available print providers.

If Level is 1, Flags contains PRINTER_ENUM_REMOTE, and Name is NULL, the function enumerates the printers in the user's domain.

If Level is 2 or 5, Name points to a null-terminated string that specifies the name of a server whose printers are to be enumerated. If this string is NULL, the function enumerates the printers installed on the local machine.

If Level is 4, Name should be NULL. The function always queries on the local machine.

When Name is NULL, it enumerates printers that are installed on the local machine. These printers include those that are physically attached to the local machine as well as remote printers to which it has a network connection.

Level

Specifies the type of data structures pointed to by pPrinterEnum. Legal values are 1, 2, 4, and 5, which correspond to the PRINTER_INFO_1, PRINTER_INFO_2,  PRINTER_INFO_4, and PRINTER_INFO_5 data structures.

Windows 95: This value may be 1, 2, or 5.

Windows NT: This value may be 1, 2, or 4.

pPrinterEnum

Pointer to a buffer that receives an array of PRINTER_INFO_1, PRINTER_INFO_2, PRINTER_INFO_4, or PRINTER_INFO_5 structures. Each structure contains data that describes an available print object. If Level is 1, the array contains PRINTER_INFO_1 structures. If Level is 2, the array contains PRINTER_INFO_2 structures. If Level is 4, the array contains PRINTER_INFO_4 structures. If Level is 5, the array contains PRINTER_INFO_5 structures.

Windows 95: The buffer cannot receive PRINTER_INFO_4 structures. It can receive any of the other types.

Windows NT: The buffer cannot receive PRINTER_INFO_5 structures. It can receive any of the other types.

cbBuf

Specifies the size, in bytes, of the array pointed to by pPrinterEnum.

pcbNeeded

Pointer to a value that receives the number of bytes copied if the function succeeds or the number of bytes required if cbBuf is too small.

pcReturned

Pointer to a value that receives the number of PRINTER_INFO_1, PRINTER_INFO_2, PRINTER_INFO_4, or PRINTER_INFO_5 structures that the function returns in the array to which pPrinterEnum points.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

If EnumPrinters returns a PRINTER_INFO_1 structure in which PRINTER_ENUM_CONTAINER is specified, this indicates that there is a hierarchy of printer objects. An application can enumerate the hierarchy by calling EnumPrinters again, setting Name to the value of the PRINTER_INFO_1 structure's pName member.

The EnumPrinters function does not retrieve security information. If PRINTER_INFO_2 structures are returned in the array pointed to by pPrinterEnum, their pSecurityDescriptor members will be set to NULL.

To get information about the default printer, call the GetProfileString function with the section name string set to "windows" and the key name string set to "device". The returned string contains the name of the default printer, the name of the printer DRV file, and the port to which the printer is attached.

Windows NT:

The PRINTER_INFO_4 structure provides an easy and extremely fast way to retrieve the names of the printers installed on a local machine, as well as the remote connections that a user has established. When EnumPrinters is called with a PRINTER_INFO_4 data structure, that function queries the registry for the specified information, then returns immediately. This differs from the behavior of EnumPrinters when called with other levels of PRINTER_INFO_* data structures. In particular, when EnumPrinters is called with a level 2 (PRINTER_INFO_2) data structure, it performs an OpenPrinter call on each remote connection. If a remote connection is down, or the remote server no longer exists, or the remote printer no longer exists, the function must wait for RPC to time out and consequently fail the OpenPrinter call. This can take a while. Passing a PRINTER_INFO_4 structure lets an application retrieve a bare minimium of required information; if more detailed information is desired, a subsequent EnumPrinter level 2 call can be made.

Windows 95:

To quickly enumerate local and network printers, use the PRINTER_INFO_5 structure. This causes EnumPrinters to query the registry rather than make remote calls, and is similar to using the PRINTER_INFO_4 structure on Windows NT as described in the preceding paragraph.

Examples

The following table shows the EnumPrinters output for various Flags values when the Level parameter is set to 1.

In the Name parameter column of the table, you should substitute an appropriate name for Print Provider, Domain, and Machine. For example, for Print Provider, you could use the name of the Windows NT network print provider: "Windows NT Remote Printers", or the name of the Windows 95 local print provider: "Windows 95 Local Print Provider". To get print provider names, call EnumPrinters with Name set to NULL.

Flags parameter	Name parameter	Result
PRINTER_ENUM_LOCAL	The Name parameter is ignored.	All local printers. Windows 95 only: Also enumerates network printers because they are installed locally.
PRINTER_ENUM_NAME	"Print Provider"	All domain names
PRINTER_ENUM_NAME	Windows NT only:  "Print Provider!Domain"	All printers and print servers in the computer's domain
PRINTER_ENUM_NAME	Windows NT only:  "Print Provider!!\\Machine"	All printers shared at \\Machine
PRINTER_ENUM_NAME	Windows NT: An empty string, "" Windows 95: The name of the local machine or the local print provider.	All local printers. Windows 95 only: Also enumerates network printers because they are installed locally.
PRINTER_ENUM_NAME	NULL	All print providers in the computer's domain
Windows NT only:  PRINTER_ENUM_CONNECTIONS	The Name parameter is ignored.	All connected remote printers
Windows NT only:  PRINTER_ENUM_NETWORK	The Name parameter is ignored.	All printers in the computer's domain
Windows NT only:  PRINTER_ENUM_REMOTE	An empty string, ""	All printers and print servers in the computer's domain
Windows NT only:  PRINTER_ENUM_REMOTE	"Print Provider"	Same as PRINTER_ENUM_NAME
Windows NT only:  PRINTER_ENUM_REMOTE	"Print Provider!Domain"	All printers and print servers in computer's domain, regardless of Domain specified.
See Also

AddPrinter, DeletePrinter, GetPrinter, GetProfileString, PRINTER_INFO_1, PRINTER_INFO_2, PRINTER_INFO_4, PRINTER_INFO_5, SetPrinter


EnumPrintProcessorDatatypes
EnumPrintProcessorDatatypes  QuickInfo

The EnumPrintProcessorDatatypes function enumerates the data types that a specifed print processor supports.

BOOL EnumPrintProcessorDatatypes(

LPTSTR  pName,	// points to server name string
LPTSTR  pPrintProcessorName,	// points to print processor name string
DWORD  Level,	// specifies version of print processor data type structures
LPBYTE  pDatatypes,	// points to buffer to receive print processor data type structures
DWORD   cbBuf,	// specifies size, in bytes, of buffer
LPDWORD  pcbNeeded,	// points to number of bytes copied (or required)
LPDWORD  pcReturned	// points to number of data structures obtained
);
Parameters

pName

Points to a null-terminated string that specifies the name of the server on which the print processor resides. If this parameter is NULL, the data types for the local print processor are enumerated.

pPrintProcessorName

Points to a null-terminated string that specifies the name of the print processor whose data types are to be enumerated.

Level

Specifies the version of the print-processor data type structures to be stored in the buffer pointed to by pDatatypes. This parameter must be 1.

pDatatypes

Points to an array of DATATYPES_INFO_1 structures. One structure is created for each available data type.

cbBuf

Specifies the size, in bytes, of the buffer pointed to by pDatatypes.

pcbNeeded

Points to a variable to receive the total size, in bytes, of the array of DATATYPES_INFO_1 structures.

If this value is less than or equal to cbBuf and the function succeeds, this is the number of bytes stored in the buffer pointed to by pDatatypes. If this number is greater than cbBuf, the buffer is too small, and you must call the function again with a buffer size at least as large as *pcbNeeded.

pcReturned

Points to a variable that the function sets to the number of data structures stored in the buffer pointed to by pDatatypes.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

DATATYPES_INFO_1, EnumPrintProcessors


EnumPrintProcessors
EnumPrintProcessors  QuickInfo  Overview  Group

The EnumPrintProcessors function enumerates the print processors installed on the specified server.

BOOL EnumPrintProcessors(

LPTSTR  pName,	// points to server name
LPTSTR  pEnvironment,	// points to environment name
DWORD  Level,	// structure level
LPBYTE  pPrintProcessorInfo,	// points to structure array
DWORD  cbBuf,	// array length in bytes
LPDWORD  pcbNeeded,	// points to number of bytes copied (or required)
LPDWORD  pcReturned	// points to number of job info. structures copied
);
Parameters

pName

Points to a null-terminated string that specifies the name of the server on which the print processors reside. If this parameter is NULL, the local print processors are enumerated.

pEnvironment

Points to a null-terminated string that specifies the environment. For example, "Windows NT x86" specifies Windows NT running on an Intel 80386 or 80486 processor. If this parameter is NULL, the current environment of the calling application and client machine (not of the destination application and print server) is used.

Level

Specifies the version of the structure to which pPrintProcessorInfo points. This value must be 1.

pPrintProcessorInfo

Points to an array of PRINTPROCESSOR_INFO_1 structures. One structure is created for each available print processor.

cbBuf

Specifies the size, in bytes, of the buffer pointed to by pPrintProcessorInfo.

pcbNeeded

Points to a value that specifies the number of bytes copied if the function succeeds or the number of bytes required if cbBuf is too small.

pcReturned

Points to a value that specifies the number of PRINTPROCESSOR_INFO_1 structures that returned in the array to which pPrintProcessorInfo points.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

AddPrintProcessor, EnumPrintProcessorDatatypes, PRINTPROCESSOR_INFO_1


EnumProps
EnumProps  QuickInfo  Overview  Group

The EnumProps function enumerates all entries in the property list of a window by passing them, one by one, to the specified callback function. EnumProps continues until the last entry is enumerated or the callback function returns FALSE.

int EnumProps(

HWND  hWnd,	// handle of window
PROPENUMPROC  lpEnumFunc	// address of callback function
);
Parameters

hWnd

Identifies the window whose property list is to be enumerated.

lpEnumFunc

Points to the callback function. For more information about the callback function, see the PropEnumProc function.

Return Value

The return value specifies the last value returned by the callback function. It is -1 if the function did not find a property for enumeration.

Remarks

An application can remove only those properties it has added. It must not remove properties added by other applications or by Windows itself.

See Also

EnumPropsEx, GetProp, PropEnumProc, RemoveProp, SetProp


EnumPropsEx
EnumPropsEx  QuickInfo  Overview  Group

The EnumPropsEx function enumerates all entries in the property list of a window by passing them, one by one, to the specified callback function. EnumPropsEx continues until the last entry is enumerated or the callback function returns FALSE.

int EnumPropsEx(

HWND  hWnd,	// handle of window
PROPENUMPROCEX  lpEnumFunc,	// address of callback function
LPARAM  lParam	// application-defined data
);
Parameters

hWnd

Identifies the window whose property list is to be enumerated.

lpEnumFunc

Points to the callback function. For more information about the callback function, see the PropEnumProcEx function.

lParam

Contains application-defined data to be passed to the callback function.

Return Value

The return value specifies the last value returned by the callback function. It is -1 if the function did not find a property for enumeration.

Remarks

An application can remove only those properties it has added. It must not remove properties added by other applications or by Windows itself.

See Also

EnumProps, GetProp, PropEnumProcEx, RemoveProp, SetProp


EnumProtocols
EnumProtocols  QuickInfo  Overview  Group

The EnumProtocols function obtains information about a specified set of network protocols that are active on a local host.

INT EnumProtocols(

LPDWORD  lpiProtocols,	// points to array of protocol identifiers
LPVOID  lpProtocolBuffer,	// points to buffer to receive protocol information
LPDWORD  lpdwBufferLength	// points to variable that specifies the size of the receiving buffer
);
Parameters

lpiProtocols

Points to a null-terminated array of protocol identifiers. The EnumProtocols function obtains information about the protocols specified by this array.

If lpiProtocols is NULL, the function obtains information about all available protocols.

The following protocol identifier values are defined:

Value	Protocol
IPPROTO_TCP	TCP/IP, a connection/stream-oriented protocol
IPPROTO_UDP	User Datagram Protocol (UDP/IP), a connectionless datagram protocol
ISOPROTO_TP4	ISO connection-oriented transport protocol
NSPROTO_IPX	IPX
NSPROTO_SPX	SPX
NSPROTO_SPXII	SPX II
lpProtocolBuffer

Points to a buffer that the function fills with an array of PROTOCOL_INFO data structures.

lpdwBufferLength

Points to a variable that, on input, specifies the size, in bytes, of the buffer pointed to by lpProtocolBuffer.

On output, the function sets this variable to the minimum buffer size needed to retrieve all of the requested information. For the function to succeed, the buffer must be at least this size.

Return Value

If the function succeeds, the return value is the number of PROTOCOL_INFO data structures written to the buffer pointed to by lpProtocolBuffer.

If the function fails, the return value is SOCKET_ERROR ( − 1). To get extended error information, call GetLastError. GetLastError may return the following extended error value:

Value	Meaning
ERROR_INSUFFICIENT_BUFFER	The buffer pointed to by lpProtocolBuffer was too small to receive all of the relevant PROTOCOL_INFO structures. Call the function with a buffer at least as large as the value returned in *lpdwBufferLength.
Remarks

In the following sample code, the EnumProtocols function obtains information about all protocols that are available on a system. The code then examines each of the protocols in greater detail.

SOCKET

OpenConnection (

    PTSTR ServiceName,

    PGUID ServiceType,

    BOOL Reliable,

    BOOL MessageOriented,

    BOOL StreamOriented,

    BOOL Connectionless,

    PINT ProtocolUsed

    )

{

    // local variables

    INT protocols[MAX_PROTOCOLS+1];

    BYTE buffer[2048];

    DWORD bytesRequired;

    INT err;

    PPROTOCOL_INFO protocolInfo;

    PCSADDR_INFO csaddrInfo;

    INT protocolCount;

    INT addressCount;

    INT i;

    DWORD protocolIndex;

    SOCKET s;

    // First look up the protocols installed on this machine.

    //

    bytesRequired = sizeof(buffer);

    err = EnumProtocols( NULL, buffer, &bytesRequired );

    if ( err <= 0 )

        return INVALID_SOCKET;

    // Walk through the available protocols and pick out the ones which

    // support the desired characteristics.

    //

    protocolCount = err;

    protocolInfo = (PPROTOCOL_INFO)buffer;

    for ( i = 0, protocolIndex = 0;

        i < protocolCount && protocolIndex < MAX_PROTOCOLS;

        i++, protocolInfo++ ) {

        // If connection-oriented support is requested, then check if

        // supported by this protocol.  We assume here that connection-

        // oriented support implies fully reliable service.

        //

        if ( Reliable ) {

            // Check to see if the protocol is reliable.  It must

            // guarantee both delivery of all data and the order in

            // which the data arrives.

            //

            if ( (protocolInfo->dwServiceFlags &

                    XP_GUARANTEED_DELIVERY) == 0

                ||

                    (protocolInfo->dwServiceFlags &

                    XP_GUARANTEED_ORDER) == 0 ) {

                continue;

                }

            // Check to see that the protocol matches the stream/message

            // characteristics requested.

            //

            if ( StreamOriented &&

                (protocolInfo->dwServiceFlags & XP_MESSAGE_ORIENTED)

                    != 0 &&

                (protocolInfo->dwServiceFlags & XP_PSEUDO_STREAM)

                     == 0 ) {

                continue;

                }

            if ( MessageOriented &&

                    (protocolInfo->dwServiceFlags & XP_MESSAGE_ORIENTED)

                              == 0 ) {

                continue;

                }

            }

        else if ( Connectionless ) {

            // Make sure that this is a connectionless protocol.

            //

            if ( (protocolInfo->dwServiceFlags & XP_CONNECTIONLESS)

                     != 0 )

                continue;

            }

        // This protocol fits all the criteria.  Add it to the list of

        // protocols in which we're interested.

        //

        protocols[protocolIndex++] = protocolInfo->iProtocol;

        }

See Also

GetAddressByName, PROTOCOL_INFO


EnumRegisterWordProc [New - Windows 95]
EnumRegisterWordProc  QuickInfo  Overview  Group

[New - Windows 95]

The EnumRegisterWordProc function is an application-defined callback function that process data of register string from the ImmEnumRegisterWord function.

UINT CALLBACK EnumRegisterWordProc(

LPCTSTR  lpReading,
DWORD  dwStyle,
LPCTSTR  lpszString,
LPVOID  lpData
);
Parameters

lpszReading

Pointer to a null-terminated string specifying the matched reading string.

dwStyle

Style of register string.

lpszString

Pointer to a null-terminated string specifying the matched register string.

lpData

Application-supplied data.

Return Value

Returns a nonzero value to continue enumeration; zero to stop enumeration.

See Also

ImmEnumRegisterWord


EnumResLangProc
EnumResLangProc  QuickInfo  Overview  Group

The EnumResLangProc function is an application-defined callback function that receives resource languages as a result of a call to the EnumResourceLanguages function.

BOOL CALLBACK EnumResLangProc(

HANDLE  hModule,	// resource-module handle
LPCTSTR  lpszType,	// address of resource type
LPCTSTR  lpszName,	// address of resource name
WORD  wIDLanguage,	// resource language identifier
LONG  lParam	// application-defined parameter
);
Parameters

hModule

Identifies the module whose executable file contains the resources for which the languages are being enumerated. If this parameter is NULL, the function enumerates the resource languages in the module used to create the current process.

lpszType

Points to a null-terminated string specifying the type name of the resource for which the language is being enumerated. For standard resource types, this parameter should be one of the following values:

Value	Meaning
RT_ACCELERATOR	Accelerator table
RT_BITMAP	Bitmap resource
RT_DIALOG	Dialog box
RT_FONT	Font resource
RT_FONTDIR	Font directory resource
RT_MENU	Menu resource
RT_RCDATA	Application-defined resource (raw data)
RT_STRING	String-table entry
RT_MESSAGETABLE	Message-table entry
RT_CURSOR	Hardware-dependent cursor resource
RT_GROUP_CURSOR	Hardware-independent cursor resource
RT_ICON	Hardware-dependent icon resource
RT_GROUP_ICON	Hardware-independent icon resource
RT_VERSION	Version resource
lpszName

Points to a null-terminated string specifying the name of the resource for which the language is being enumerated.

wIDLanguage

Specifies the language identifier for the resource for which the language is being enumerated. The EnumResourceLanguages function provides this value. For a list of the primary language identifiers and sublanguage identifiers that constitute a language identifier, see the MAKELANGID macro.

lParam

Specifies the application-defined parameter passed to the EnumResourceLanguages function. This parameter can be used in error checking.

Return Value

This callback function should return TRUE to continue enumeration; otherwise, it should return FALSE to stop enumeration.

Remarks

The EnumResLangProc function is a placeholder for the application-defined or library-defined function name.

See Also

EnumResourceLanguages, MAKELANGID


EnumResNameProc
EnumResNameProc  QuickInfo  Overview  Group

The EnumResNameProc function is an application-defined callback function that receives resource names as a result of a call to the EnumResourceNames function.

BOOL CALLBACK EnumResNameProc(

HANDLE  hModule,	// resource-module handle
LPCTSTR  lpszType,	// address of resource type
LPTSTR  lpszName,	// address of resource name
LONG  lParam	// application-defined parameter
);
Parameters

hModule

Identifies the module whose executable file contains the resources for which the names are being enumerated. If this parameter is NULL, the function enumerates the resource names in the module used to create the current process.

lpszType

Points to a null-terminated string specifying the type name of the resource for which the name is being enumerated. For standard resource types, this parameter should be one of the following values:

Value	Meaning
RT_ACCELERATOR	Accelerator table
RT_BITMAP	Bitmap resource
RT_DIALOG	Dialog box
RT_FONT	Font resource
RT_FONTDIR	Font directory resource
RT_MENU	Menu resource
RT_RCDATA	Application-defined resource (raw data)
RT_STRING	String-table entry
RT_MESSAGETABLE	Message-table entry
RT_CURSOR	Hardware-dependent cursor resource
RT_GROUP_CURSOR	Hardware-independent cursor resource
RT_ICON	Hardware-dependent icon resource
RT_GROUP_ICON	Hardware-independent icon resource
RT_VERSION	Version resource
lpszName

Points to a null-terminated string specifying the name of the resource for which the name is being enumerated.

lParam

Specifies the application-defined parameter passed to the EnumResourceNames function. This parameter can be used in error checking.

Return Value

This callback function should return TRUE to continue enumeration; otherwise, it should return FALSE to stop enumeration.

Remarks

The EnumResNameProc function is a placeholder for the application-defined or library-defined function name.

See Also

EnumResourceNames


EnumResourceLanguages
EnumResourceLanguages  QuickInfo  Overview  Group

The EnumResourceLanguages function searches a module for each resource of the specified type and name and passes the language of each resource it locates to a defined callback function.

BOOL EnumResourceLanguages(

HMODULE  hModule,	// resource-module handle
LPCTSTR  lpType,	// address of resource type
LPCTSTR  lpName,	// address of resource name
ENUMRESLANGPROC  lpEnumFunc,	// address of callback function
LONG  lParam	// application-defined parameter
);
Parameters

hModule

Identifies the module whose executable file contains the resources for which the languages are to be enumerated. If this parameter is NULL, the function enumerates the resource languages in the module used to create the current process.

lpType

Points to a null-terminated string specifying the type of the resource for which the language is being enumerated. For standard resource types, this parameter can be one of the following values:

Value	Meaning
RT_ACCELERATOR	Accelerator table
RT_BITMAP	Bitmap resource
RT_DIALOG	Dialog box
RT_FONT	Font resource
RT_FONTDIR	Font directory resource
RT_MENU	Menu resource
RT_RCDATA	Application-defined resource (raw data)
RT_STRING	String-table entry
RT_MESSAGETABLE	Message-table entry
RT_CURSOR	Hardware-dependent cursor resource
RT_GROUP_CURSOR	Hardware-independent cursor resource
RT_ICON	Hardware-dependent icon resource
RT_GROUP_ICON	Hardware-independent icon resource
RT_VERSION	Version resource
lpName

Points to a null-terminated string specifying the name of the resource for which the language is being enumerated.

lpEnumFunc

Points to the callback function to be called for each enumerated resource language. For more information, see the EnumResLangProc function.

lParam

Specifies an application-defined value passed to the callback function. This parameter may be used in error checking.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The EnumResourceLanguages function continues to enumerate resource languages until the callback function returns FALSE or all resource languages have been enumerated.

See Also

EnumResLangProc, EnumResourceNames, EnumResourceTypes


EnumResourceNames
EnumResourceNames  QuickInfo  Overview  Group

The EnumResourceNames function searches a module for each resource of the specified type and passes the name of each resource it locates to an application-defined callback function.

BOOL EnumResourceNames(

HINSTANCE  hModule,	// resource-module handling
LPCTSTR  lpszType,	// address of resource type
ENUMRESNAMEPROC  lpEnumFunc,	// address of callback function
LONG  lParam	// application-defined parameter
);
Parameters

hModule

Identifies the module whose executable file contains the resources for which the names are to be enumerated. If this parameter is NULL, the function enumerates the resource names in the module used to create the current process.

lpszType

Points to a null-terminated string specifying the type name of the resource for which the name is being enumerated. For standard resource types, this parameter can be one of the following values:

Value	Meaning
RT_ACCELERATOR	Accelerator table
RT_BITMAP	Bitmap resource
RT_DIALOG	Dialog box
RT_FONT	Font resource
RT_FONTDIR	Font directory resource
RT_MENU	Menu resource
RT_RCDATA	Application-defined resource (raw data)
RT_STRING	String-table entry
RT_MESSAGETABLE	Message-table entry
RT_CURSOR	Hardware-dependent cursor resource
RT_GROUP_CURSOR	Hardware-independent cursor resource
RT_ICON	Hardware-dependent icon resource
RT_GROUP_ICON	Hardware-independent icon resource
RT_VERSION	Version resource
lpEnumFunc

Points to the callback function to be called for each enumerated resource name. For more information, see the EnumResNameProc function.

lParam

Specifies an application-defined value passed to the callback function. This parameter can be used in error checking.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The EnumResourceNames function continues to enumerate resource names until the callback function returns FALSE or all resource names have been enumerated.

See Also

EnumResNameProc, EnumResourceLanguages, EnumResourceTypes


EnumResourceTypes
EnumResourceTypes  QuickInfo  Overview  Group

The EnumResourceTypes function searches a module for resources and passes each resource type it finds to an application-defined callback function.

BOOL EnumResourceTypes(

HMODULE  hModule,	// resource-module handle
ENUMRESTYPEPROC  lpEnumFunc,	// address of callback function
LONG  lParam	// application-defined parameter
);
Parameters

hModule

Identifies the module whose executable file contains the resources for which the types are to be enumerated. If this parameter is NULL, the function enumerates the resource types in the module used to create the current process.

lpEnumFunc

Points to the callback function to be called for each enumerated resource type. For more information, see the EnumResTypeProc function.

lParam

Specifies an application-defined value passed to the callback function.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The EnumResourceTypes function continues to enumerate resource types until the callback function returns FALSE or all resource types have been enumerated.

See Also

EnumResourceLanguages, EnumResourceNames, EnumResTypeProc


EnumResTypeProc
EnumResTypeProc  QuickInfo  Overview  Group

The EnumResTypeProc function is an application-defined callback function that receives resource types as a result of a call to the EnumResourceTypes function.

BOOL CALLBACK EnumResTypeProc(

HANDLE  hModule,	// resource-module handle
LPTSTR  lpszType,	// address of resource type
LONG  lParam	// application-defined parameter
);
Parameters

hModule

Identifies the module whose executable file contains the resources for which the types are to be enumerated. If this parameter is NULL, the function enumerates the resource types in the module used to create the current process.

lpszType

Points to a null-terminated string specifying the type name of the resource for which the type is being enumerated. For standard resource types, this parameter can be one of the following values:

Value	Meaning
RT_ACCELERATOR	Accelerator table
RT_BITMAP	Bitmap resource
RT_DIALOG	Dialog box
RT_FONT	Font resource
RT_FONTDIR	Font directory resource
RT_MENU	Menu resource
RT_RCDATA	Application-defined resource (raw data)
RT_STRING	String-table entry
RT_MESSAGETABLE	Message-table entry
RT_CURSOR	Hardware-dependent cursor resource
RT_GROUP_CURSOR	Hardware-independent cursor resource
RT_ICON	Hardware-dependent icon resource
RT_GROUP_ICON	Hardware-independent icon resource
RT_VERSION	Version resource
lParam

Specifies the application-defined parameter passed to the EnumResourceTypes function. This parameter can be used in error checking.

Return Value

The callback function should return TRUE to continue enumeration; otherwise, it should return FALSE to stop enumeration.

Remarks

The EnumResTypeProc function is a placeholder for the application-defined or library-defined function name.

See Also

EnumResourceTypes


EnumServicesStatus
EnumServicesStatus  QuickInfo  Overview  Group

The EnumServicesStatus function enumerates services in the specified service control manager database. The name and status of each service are provided.

BOOL EnumServicesStatus(

SC_HANDLE  hSCManager,	// handle of service control manager database
DWORD  dwServiceType,	// type of services to enumerate
DWORD  dwServiceState,	// state of services to enumerate
LPENUM_SERVICE_STATUS  lpServices,	// address of service status buffer
DWORD  cbBufSize,	// size of service status buffer
LPDWORD  pcbBytesNeeded,	// address of variable for bytes needed
LPDWORD  lpServicesReturned,	// address of variable for number returned
LPDWORD  lpResumeHandle	// address of variable for next entry
);
Parameters

hSCManager

Identifies the service control manager database. The OpenSCManager function returns this handle which must have SC_MANAGER_ENUMERATE_SERVICE access.

dwServiceType

Specifies the type of services to enumerate. It must be one or both of the following values:

Value	Meaning
SERVICE_WIN32	Enumerates services of type SERVICE_WIN32_OWN_PROCESS and SERVICE_WIN32_SHARE_PROCESS.
SERVICE_DRIVER	Enumerates services of type SERVICE_KERNEL_DRIVER and SERVICE_FILE_SYSTEM_DRIVER.
dwServiceState

Specifies the services to enumerate based on their running state. It must be one or both of the following values:

Value	Meaning
SERVICE_ACTIVE	Enumerates services that are in the following states: SERVICE_START_PENDING, SERVICE_STOP_PENDING, SERVICE_RUNNING, SERVICE_CONTINUE_PENDING, SERVICE_PAUSE_PENDING, and SERVICE_PAUSED.
SERVICE_INACTIVE	Enumerates services that are in the SERVICE_STOPPED state.
lpServices

Points to an array of ENUM_SERVICE_STATUS structures in which the name and service status information for each service in the database is returned.

cbBufSize

Specifies the size, in bytes, of the buffer pointed to by the lpServices parameter.

pcbBytesNeeded

Points to a variable that receives the number of bytes needed to return the remaining service entries.

lpServicesReturned

Points to a variable that receives the number of service entries returned.

lpResumeHandle

Points to a 32-bit variable that, on input, specifies the starting point of enumeration. The first time this function is called, the variable's value is set to zero. On output, the variable's value is zero if the function succeeds. If the function returns FALSE and the GetLastError function returns ERROR_MORE_DATA, the variable's value is used to indicate the next unread service entry when the function is called again to retrieve the additional data.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Errors

The following error codes may be set by the service control manager. Other error codes may be set by the registry functions that are called by the service control manager.

Value	Meaning
ERROR_ACCESS_DENIED
	The specified handle was not opened with SC_MANAGER_ENUMERATE_SERVICE access.
ERROR_INVALID_HANDLE
	The specified handle is invalid.
ERROR_INVALID_PARAMETER
	A parameter that was specified is invalid.
ERROR_MORE_DATA
	There are more service entries than would fit into the lpServices buffer. The actual number of service entries written to lpServices is returned in the lpServicesReturned parameter. The number of bytes required to get the remaining entries is returned in the pcbBytesNeeded parameter. The remaining services can be enumerated by additional calls to EnumServicesStatus with the lpResumeHandle parameter indicating the next service to read.
See Also

EnumDependentServices, ENUM_SERVICE_STATUS, OpenSCManager


EnumSystemCodePages
EnumSystemCodePages  QuickInfo  Overview  Group

The EnumSystemCodePages function enumerates the code pages that are either installed on or supported by a system. The dwFlags parameter determines whether the function enumerates installed or supported code pages. The function enumerates the code pages by passing code page identifiers, one at a time, to the specified application-defined callback function. This continues until all of the installed or supported code page identifiers have been passed to the callback function, or the callback function returns FALSE.

BOOL EnumSystemCodePages(

CODEPAGE_ENUMPROC  lpCodePageEnumProc,	// pointer to enumeration callback function
DWORD  dwFlags	// indicates which code pages to enumerate
);
Parameters

lpCodePageEnumProc

Points to an application-defined callback function. The EnumSystemCodePages function enumerates code pages by making repeated calls to this callback function. For more information, see the EnumCodePagesProc callback function.

dwFlags

Specifies the code pages to enumerate. This parameter can be one of the following values:

Value	Meaning
CP_INSTALLED	Enumerate only installed code pages.
CP_SUPPORTED	Enumerate all supported code pages.
Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError. GetLastError may return one of the following error codes:

ERROR_INVALID_PARAMETER
ERROR_BADDB
ERROR_INVALID FLAGS

Remarks

The CP_INSTALLED and CP_SUPPORTED flags are mutually exclusive.

See Also

EnumCodePagesProc


EnumSystemLocales
EnumSystemLocales  QuickInfo  Overview  Group

The EnumSystemLocales function enumerates the locales that are either installed on or supported by a system. The dwFlags parameter determines whether the function enumerates installed or supported system locales. The function enumerates locales by passing locale identifiers, one at a time, to the specified application-defined callback function. This continues until all of the installed or supported locale identifiers have been passed to the callback function or the callback function returns FALSE.

BOOL EnumSystemLocales(

LOCALE_ENUMPROC  lpLocaleEnumProc,	// pointer to enumeration callback function
DWORD  dwFlags	// indicates which locales to enumerate
);
Parameters

lpLocaleEnumProc

Points to an application-defined callback function. The EnumSystemLocales function enumerates locales by making repeated calls to this callback function. For more information, see the EnumLocalesProc callback function.

dwFlags

Specifies the locale identifiers to enumerate. This parameter can be one of the following values:

Value	Meaning
LCID_INSTALLED	Enumerate only installed locale identifiers.
LCID_SUPPORTED	Enumerate all supported locale identifiers.
Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError. GetLastError may return one of the following error codes:

ERROR_INVALID_PARAMETER
ERROR_BADDB
ERROR_INVALID FLAGS

Remarks

The LCID_INSTALLED and LCID_SUPPORTED flags are mutually exclusive.

See Also

EnumLocalesProc


EnumTaskWindows
EnumTaskWindows  QuickInfo  Overview  Group

The EnumTaskWindows function is now obsolete. It has been superseded by the EnumThreadWindows function.

To maintain compatibility for 16-bit applications, EnumTaskWindows has been replaced with a macro that calls EnumThreadWindows. Earlier applications can continue to call EnumTaskWindows as previously documented, but new applications should use EnumThreadWindows.


EnumThreadWindows
EnumThreadWindows  QuickInfo  Overview  Group

The EnumThreadWindows function enumerates all nonchild windows associated with a thread by passing the handle of each window, in turn, to an application-defined callback function. EnumThreadWindows continues until the last window is enumerated or the callback function returns FALSE. To enumerate child windows of a particular window, use the EnumChildWindows function. This function supersedes the EnumTaskWindows function.

BOOL EnumThreadWindows(

DWORD  dwThreadId,	// thread identifier
WNDENUMPROC  lpfn,	// address of callback function
LPARAM  lParam	// application-defined value
);
Parameters

dwThreadId

Identifies the thread whose windows are to be enumerated.

lpfn

Points to an application-defined callback function. For more information about the callback function, see the EnumThreadWndProc callback function.

lParam

Specifies a 32-bit, application-defined value to be passed to the callback function.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

See Also

EnumChildWindows, EnumThreadWndProc, EnumWindows


EnumThreadWndProc
EnumThreadWndProc  QuickInfo  Overview  Group

The EnumThreadWndProc function is an application-defined callback function that receives the window handles associated with a thread as a result of a call to the EnumThreadWindows function.

BOOL CALLBACK EnumThreadWndProc(

HWND  hwnd,	// handle of window
LPARAM  lParam	// application-defined value
);
Parameters

hwnd

Identifies a window associated with the thread specified in the EnumThreadWindows function.

lParam

Specifies the application-defined value given in the EnumThreadWindows function.

Return Value

To continue enumeration, the callback function must return TRUE; to stop enumeration, it must return FALSE.

Remarks

The callback function can perform any desired task.

An application must register this callback function by passing its address to the EnumThreadWindows function. EnumThreadWndProc is a placeholder for the application-defined function name.

See Also

EnumThreadWindows


EnumTimeFormats
EnumTimeFormats  QuickInfo  Overview  Group

The EnumTimeFormats function enumerates the time formats that are available for a specified locale. The function enumerates the time formats by passing a pointer to a string buffer containing a time format to an application-defined callback function. It continues to do so until the last time format is found or the callback function returns FALSE.

BOOL EnumTimeFormats(

TIMEFMT_ENUMPROC  lpTimeFmtEnumProc,	// pointer to enumeration callback function
LCID  Locale,	// locale whose time formats are of interest
DWORD  dwFlags	// currently unused
);
Parameters

lpTimeFmtEnumProc

Points to an application-defined callback function. See the EnumTimeFormatsProc callback function for further details.

Locale

Specifies the locale to retrieve time format information for. This parameter can be a locale identifier created by the MAKELCID macro, or one of the following predefined values:

LOCALE_SYSTEM_DEFAULT	Default system locale.
LOCALE_USER_DEFAULT	Default user locale.
dwFlags

Currently unused. Must be zero.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError. GetLastError may return one of the following error codes:

ERROR_INVALID_PARAMETER
ERROR_BADDB
ERROR_INVALID FLAGS

See Also

EnumTimeFormatsProc, EnumCalendarInfo, EnumDateFormats


EnumTimeFormatsProc
EnumTimeFormatsProc  QuickInfo  Overview  Group

An EnumTimeFormatsProc function is an application-defined callback function. It is called as a result of a call to the EnumTimeFormats function, and receives a pointer to a string buffer containing a time format string.

BOOL CALLBACK EnumTimeFormatsProc(

LPTSTR  lpTimeFormatString	// pointer to time format string
);
Parameters

lpTimeFormatString

Pointer to a string buffer containing a null-terminated time format string. Note that lpTimeFormatString should be an LPWSTR for the Unicode (W) version of EnumTimeFormatsProc, and an LPSTR for the ANSI (A) version of EnumTimeFormatsProc.

Return Value

To continue enumeration, the callback function should return TRUE.

To stop enumeration, the callback function should return FALSE.

Remarks

EnumTimeFormatsProc is a placeholder for an application-defined function name.

An EnumTimeFormatsProc function can carry out any task

An application registers an EnumTimeFormatsProc function by passing its address to the EnumTimeFormats function.

A value of type TIMEFMT_ENUMPROC is a pointer to an EnumTimeFormatsProc function.

See Also

EnumTimeFormats


EnumWindows
EnumWindows  QuickInfo  Overview  Group

The EnumWindows function enumerates all top-level windows on the screen by passing the handle of each window, in turn, to an application-defined callback function. EnumWindows continues until the last top-level window is enumerated or the callback function returns FALSE.

BOOL EnumWindows(

WNDENUMPROC  lpEnumFunc,	// address of callback function
LPARAM  lParam	// application-defined value
);
Parameters

lpEnumFunc

Points to an application-defined callback function. For more information, see the EnumWindowsProc callback function.

lParam

Specifies a 32-bit, application-defined value to be passed to the callback function.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

The EnumWindows function does not enumerate child windows.

This function is more reliable than calling the GetWindow function in a loop. An application that calls GetWindow to perform this task risks being caught in an infinite loop or referencing a handle of a window that has been destroyed.

See Also

EnumChildWindows, EnumWindowsProc, GetWindow


EnumWindowsProc
EnumWindowsProc  QuickInfo  Overview  Group

The EnumWindowsProc function is an application-defined callback function that receives top-level window handles as a result of a call to the EnumWindows function.

BOOL CALLBACK EnumWindowsProc(

HWND  hwnd,	// handle of parent window
LPARAM  lParam	// application-defined value
);
Parameters

hwnd

Identifies a top-level window.

lParam

Specifies the application-defined value given in EnumWindows.

Return Value

To continue enumeration, the callback function must return TRUE; to stop enumeration, it must return FALSE.

Remarks

The callback function can perform any desired task.

An application must register this callback function by passing its address to EnumWindows. EnumWindowsProc is a placeholder for the application-defined function name.

See Also

EnumWindows


EnumWindowStationProc [New - Windows NT]
EnumWindowStationProc  QuickInfo

[New - Windows NT]

The EnumWindowStationProc function is an application-defined callback function that receives a window station name as a result of a call to the EnumWindowStations function.

BOOL EnumWindowStationProc(

LPTSTR lpszWindowStation	// name of a window station
LPARAM lParam	// value specified in EnumWindowStations call
);
Parameters

lpszWindowStation

Points to the null-terminated name of a window station.

lParam

Specifies the application-defined value given in the EnumWindowStations function.

Return Value

To continue enumeration, the callback function must return TRUE. To stop enumeration, it must return FALSE.

See Also

EnumWindowStations


EnumWindowStations [New - Windows NT]
EnumWindowStations  QuickInfo  Overview  Group

[New - Windows NT]

The EnumWindowStations function enumerates all windowstations in the system by passing the name of each window station, in turn, to an application-defined callback function.

BOOL EnumWindowStations(

WINSTAENUMPROC lpEnumFunc,	// points to application's callback function
LPARAM lParam	// 32-bit value to pass to the callback function
);
Parameters

lpEnumFunc

Points to an application-defined EnumWindowStationProc callback function.

lParam

Specifies a 32-bit application-defined value to be passed to the callback function.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The EnumWindowStations function enumerates only those window stations for which the calling process has WINSTA_ENUMERATE access.

EnumWindowStations repeatedly invokes the lpEnumFunc callback function until the last window station is enumerated or the callback function returns FALSE.

See Also

EnumWindowStationProc


EqualPrefixSid
EqualPrefixSid  QuickInfo  Overview  Group

The EqualPrefixSid function tests two security-identifier (SID) prefix values for equality. An SID prefix is the entire SID except for the last subauthority value.

BOOL EqualPrefixSid(

PSID  pSid1,	// address of first SID to compare
PSID  pSid2	// address of second SID to compare
);
Parameters

pSid1

Points to the first SID structure to compare. This structure is assumed to be valid.

pSid2

Points to the second SID structure to compare. It also is assumed to be valid.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The EqualPrefixSid function enables a server application in one domain to verify an attempt by a user to log on to another domain. For example, if a user attempts to log on to RemoteDomain from a workstation in LocalDomain, the server for LocalDomain can request the SIDs for the user and the user's groups from RemoteDomain. The domain controller for RemoteDomain responds with the relevant SIDs.

All SIDs for a given domain necessarily have the same prefix. When the server receives the user's SIDs, it can call the EqualPrefixSid function for each SID, comparing the user or group SID against the SID for RemoteDomain. If any of the SID prefixes are not equal, the server refuses the logon attempt.

It is advisable to modify the SID for a domain before comparing it with a group or user SID. If the SID for RemoteDomain is S-1−1234−8, each group or user SID for that domain will have S-1−1234−8 as its prefix. To compare the SIDs by using the EqualPrefixSid function, an application copies the domain SID and adds any subauthority (RID) value to the copy, thereby creating an SID in the form S-1−1234−8−0. The application then uses the modified domain SID as a template against which the group and user SIDs are compared.

See Also

CopySid, EqualSid, IsValidSid, SID


EqualRect
EqualRect  QuickInfo  Overview  Group

The EqualRect function determines whether the two specified rectangles are equal by comparing the coordinates of their upper-left and lower-right corners.

BOOL EqualRect(

CONST RECT  *lprc1,	// address of structure with first rectangle
CONST RECT  *lprc2	// address of structure with second rectangle
);
Parameters

lprc1

Points to a RECT structure that contains the logical coordinates of the first rectangle.

lprc2

Points to a RECT structure that contains the logical coordinates of the second rectangle.

Return Value

If the two rectangles are identical, the return value is TRUE; otherwise, it is FALSE. To get extended error information, call GetLastError.

See Also

IsRectEmpty, PtInRect, RECT


EqualRgn
EqualRgn  QuickInfo  Overview  Group

The EqualRgn function checks the two specified regions to determine whether they are identical. The function considers two regions identical if they are equal in size and shape.

BOOL EqualRgn(

HRGN  hSrcRgn1,	// handle of first region
HRGN  hSrcRgn2	// handle of second region
);
Parameters

hSrcRgn1

Identifies a region.

hSrcRgn2

Identifies a region.

Return Value

If the two regions are equal, the return value is TRUE; otherwise, it is FALSE. A return value of ERROR means at least one of the region handles is invalid.

See Also

CreateRectRgn, CreateRectRgnIndirect


EqualSid
EqualSid  QuickInfo  Overview  Group

The EqualSid function tests two security identifier (SID) values for equality. Two SIDs must match exactly to be considered equal.

BOOL EqualSid(

PSID  pSid1,	// address of first SID to compare
PSID  pSid2	// address of second SID to compare
);
Parameters

pSid1

Points to the first SID structure to compare. This structure is assumed to be valid.

pSid2

Points to the second SID structure to compare. It also is assumed to be valid.

Return Value

If the SID structures are equal, the return value is TRUE; otherwise, it is FALSE. To get extended error information, call GetLastError.

If either SID structure is invalid, the return value is undefined.

See Also

EqualPrefixSid, IsValidSid, SID


EraseTape
EraseTape  QuickInfo  Overview  Group

The EraseTape function erases all or part of a tape.

DWORD EraseTape(

HANDLE  hDevice,	// handle of open device
DWORD  dwEraseType,	// type of erasure to perform
BOOL  bImmediate	// return after erase operation begins
);
Parameters

hDevice

Identifies the device where the tape is to be erased. This handle is created by using the CreateFile function.

dwEraseType

Specifies the erasing technique. This parameter can be one of the following values:

Value	Description
TAPE_ERASE_LONG	Erases the tape from the current position to the end of the current partition.
TAPE_ERASE_SHORT	Writes an erase gap or end-of-data marker at the current position.
bImmediate

Specifies whether to return as soon as the erase operation begins. If this parameter is TRUE, the function returns immediately; if it is FALSE, the function does not return until the erase operation has been completed.

Return Value

If the function succeeds, the return value is NO_ERROR.

If the function fails, the return value is one of the following error codes:

Error code	Description
ERROR_BEGINNING_OF_MEDIA	An attempt to access data before the beginning-of-medium marker failed.
ERROR_BUS_RESET	A reset condition was detected on the bus.
ERROR_END_OF_MEDIA	The end-of-tape marker was reached during an operation.
ERROR_FILEMARK_DETECTED	A filemark was reached during an operation.
ERROR_SETMARK_DETECTED	A setmark was reached during an operation.
ERROR_NO_DATA_DETECTED	The end-of-data marker was reached during an operation.
ERROR_PARTITION_FAILURE	The tape could not be partitioned.
ERROR_INVALID_BLOCK_LENGTH	The block size is incorrect on a new tape in a multivolume partition.
ERROR_DEVICE_NOT_PARTITIONED	The partition information could not be found when a tape was being loaded.
ERROR_MEDIA_CHANGED	The tape that was in the drive has been replaced or removed.
ERROR_NO_MEDIA_IN_DRIVE	There is no media in the drive.
ERROR_NOT_SUPPORTED	The tape driver does not support a requested function.
ERROR_UNABLE_TO_LOCK_MEDIA	An attempt to lock the ejection mechanism failed.
ERROR_UNABLE_TO_UNLOAD_MEDIA	An attempt to unload the tape failed.
ERROR_WRITE_PROTECT	The media is write protected.
Remarks

Some tape devices do not support certain tape operations. To determine your tape device's capabilities, see your tape device documentation and use the GetTapeParameters function.

See Also

CreateFile, GetTapeParameters


Escape
Escape  QuickInfo  Overview  Group

The Escape function allows applications to access capabilities of a particular device not directly available through GDI. Escape calls made by an application are translated and sent to the driver.

int Escape(

HDC  hdc,	// handle of device context
int  nEscape,	// escape function
int  cbInput,	// number of bytes in input structure
LPCSTR  lpvInData,	// address of input structure
LPVOID  lpvOutData	// address of output structure
);
Parameters

hdc

Identifies the device context.

nEscape

Specifies the escape function to be performed. This parameter must be one of the predefined escape values. Use the ExtEscape function if your application defines a private escape value.

cbInput

Specifies the number of bytes of data pointed to by the lpvInData parameter.

lpvInData

Points to the input structure required for the specified escape.

lpvOutData

Points to the structure that receives output from this escape. This parameter should be NULL if no data is returned.

Return Value

If the function succeeds, the return value is greater than zero, except with the QUERYESCSUPPORT printer escape, which checks for implementation only. If the escape is not implemented, the return value is zero.

If the function fails, the return value is an error. To get extended error information, call GetLastError.

Errors

If the function fails, the return value is one of the following values.

Value	Meaning
SP_ERROR	General error. If SP_ERROR is returned, Escape may set the last error value to: ERROR_INVALID_PARAMETER ERROR_DISK_FULL ERROR_NOT_ENOUGH_MEMORY ERROR_PRINT_CANCELLED
SP_OUTOFDISK	Not enough disk space is currently available for spooling, and no more space will become available.
SP_OUTOFMEMORY	Not enough memory is available for spooling.
SP_USERABORT	The user terminated the job through Windows Print Manager.
Remarks

The Win32 API provides six new functions that supersede some printer escapes:

Function	Description
AbortDoc	Terminates a print job. Supersedes the ABORTDOC escape.
EndDoc	Ends a print job. Supersedes the ENDDOC escape.
EndPage	Ends a page. Supersedes the NEWFRAME escape. Unlike NEWFRAME, this function is always called after printing a page.
SetAbortProc	Sets the abort function for a print job. Supersedes the SETABORTPROC escape.
StartDoc	Starts a print job. Supersedes the STARTDOC escape.
StartPage	Prepares printer driver to receive data.
The Win32 API provides six new indexes for the GetDeviceCaps function that supersede some printer escapes:

Index	Description
PHYSICALWIDTH	Width, in pixels, of the physical page. (Supersedes the GETPHYSPAGESIZE escape.)
PHYSICALHEIGHT	Height, in pixels, of the physical page. (Supersedes the GETPHYSPAGESIZE escape.)
PHYSICALOFFSETX	Offset in the x direction, in pixels, from the upper-left corner of the physical page where the actual printing or drawing begins. (Supersedes the GETPRINTINGOFFSET escape.)
PHYSICALOFFSETY	Offset in the y direction, in pixels, from the upper-left corner of the physical page where the actual printing or drawing begins. (Supersedes the GETPRINTINGOFFSET escape.)
SCALINGFACTORX	Scaling factor for the x-axis of a printer. (Supersedes the GETSCALINGFACTOR escape.)
SCALINGFACTORY	Scaling factor for the y-axis of a printer. (Supersedes the GETSCALINGFACTOR escape.)
Of the original printer escapes, only the following can be used by Win32-based application:

Escape	Description
QUERYYESCSUPPORT	Determines whether a particular escape is implemented by the device driver.
Following is a list of the obsolete printer escapes that are supported only for compatibility with 16-bit versions of Windows:

Escape	Description
ABORTDOC	Stops the current print job and erases everything the application has written to the device since the last ENDDOC escape.
ENDDOC	Ends a print job started by the STARTDOC escape.
GETPHYSPAGESIZE	Retrieves the physical page size and copies it to the specified location.
GETPRINTINGOFFSET	Retrieves the offset from the upper-left corner of the physical page where the actual printing or drawing begins.
GETSCALINGFACTOR	Retrieves the scaling factors for the x-axis and the y-axis of a printer.
NEWFRAME	Informs the printer that the application has finished writing to a page.
NEXTBAND	Informs the printer that the application has finished writing to a band.
PASSTHROUGH	Allows the application to send data directly to a printer.
SETABORTPROC	Sets the Abort function for a print job.
STARTDOC	Informs a printer driver that a new print job is starting.
See Also

AbortDoc, EndDoc, EndPage, ExtEscape, SetAbortProc, StartDoc, StartPage, ResetDC,


EscapeCommFunction
EscapeCommFunction  QuickInfo  Overview  Group

The EscapeCommFunction function directs a specified communications device to perform an extended function.

BOOL EscapeCommFunction(

HANDLE  hFile,	// handle of communications device
DWORD  dwFunc	// extended function to perform
);
Parameters

hFile

Identifies the communications device. The CreateFile function returns this handle.

dwFunc

Specifies the code of the extended function to perform. This parameter can be one of the following values:

Value	Meaning
CLRDTR	Clears the DTR (data-terminal-ready) signal.
CLRRTS	Clears the RTS (request-to-send) signal.
SETDTR	Sends the DTR (data-terminal-ready) signal.
SETRTS	Sends the RTS (request-to-send) signal.
SETXOFF	Causes transmission to act as if an XOFF character has been received.
SETXON	Causes transmission to act as if an XON character has been received.
SETBREAK	Suspends character transmission and places the transmission line in a break state until the ClearCommBreak function is called (or EscapeCommFunction is called with the CLRBREAK extended function code). The SETBREAK extended function code is identical to the SetCommBreak function. Note that this extended function does not flush data that has not been transmitted.
CLRBREAK	Restores character transmission and places the transmission line in a nonbreak state. The CLRBREAK extended function code is identical to the ClearCommBreak function.
Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

ClearCommBreak, CreateFile, SetCommBreak


ExcludeClipRect
ExcludeClipRect  QuickInfo  Overview  Group

The ExcludeClipRect function creates a new clipping region that consists of the existing clipping region minus the specified rectangle.

int ExcludeClipRect(

HDC  hdc,	// handle of device context
int  nLeftRect,	// x-coordinate of upper-left corner of rectangle
int  nTopRect,	// y-coordinate of upper-left corner of rectangle
int  nRightRect,	// x-coordinate of lower-right corner of rectangle
int  nBottomRect	// y-coordinate of lower-right corner of rectangle
);
Parameters

hdc

Identifies the device context.

nLeftRect

Specifies the logical x-coordinate of the upper-left corner of the rectangle.

nTopRect

Specifies the logical y-coordinate of the upper-left corner of the rectangle.

nRightRect

Specifies the logical x-coordinate of the lower-right corner of the rectangle.

nBottomRect

Specifies the logical y-coordinate of the lower-right corner of the rectangle.

Return Value

If the function succeeds, the return value specifies the new clipping region's complexity and can be any one of the following values:

Value	Meaning
NULLREGION	Region is empty.
SIMPLEREGION	Region is a single rectangle.
COMPLEXREGION	Region is more than one rectangle.
ERROR	No region was created.
Remarks

The lower and right edges of the given rectangle are not excluded from the clipping region.

See Also

IntersectClipRect


ExcludeUpdateRgn
ExcludeUpdateRgn  QuickInfo  Overview  Group

The ExcludeUpdateRgn function prevents drawing within invalid areas of a window by excluding an updated region in the window from a clipping region.

int ExcludeUpdateRgn(

HDC  hDC,	// handle of device context
HWND  hWnd	// handle of window
);
Parameters

hDC

Identifies the device context associated with the clipping region.

hWnd

Identifies the window to update.

Return Value

The return value specifies the complexity of the excluded region; it can be any one of the following values:

Value	Meaning
COMPLEXREGION	Region consists of more than one rectangle.
ERROR	An error occurred.
NULLREGION	Region is empty.
SIMPLEREGION	Region is a single rectangle.
See Also

BeginPaint, GetUpdateRect, GetUpdateRgn, UpdateWindow


ExitProcess
ExitProcess  QuickInfo  Overview  Group

The ExitProcess function ends a process and all its threads.

VOID ExitProcess(

UINT  uExitCode	// exit code for all threads
);
Parameters

uExitCode

Specifies the exit code for the process, and for all threads that are terminated as a result of this call. Use the GetExitCodeProcess function to retrieve the process's exit value. Use the GetExitCodeThread function to retrieve a thread's exit value.

Return Value

This function does not return a value.

Remarks

ExitProcess is the preferred method of ending a process. This function provides a clean process shutdown. This includes calling the entry-point function of all attached dynamic-link libraries (DLLs) with a value indicating that the process is detaching from the DLL. If a process terminates by calling TerminateProcess, the DLLs that the process is attached to are not notified of the process termination.

After all attached DLLs have executed any process termination value, this function terminates the current process.

Terminating a process causes the following:

1.	All of the object handles opened by the process are closed.

2.	All of the threads in the process terminate their execution.

3.	The state of the process object becomes signaled, satisfying any threads that had been waiting for the process to terminate.

4.	The states of all threads of the process become signaled, satisfying any threads that had been waiting for the threads to terminate.

5.	The termination status of the process changes from STILL_ACTIVE to the exit value of the process.

Terminating a process does not cause child processes to be terminated.

Terminating a process does not necessarily remove the process object from the operating system. A process object is deleted when the last handle to the process is closed.

The ExitProcess, ExitThread, CreateThread, CreateRemoteThread functions, and a process that is starting (as the result of a call by CreateProcess) are serialized between each other within a process. Only one of these events can happen in an address space at a time. This means the following restrictions hold:

•	During process startup and DLL initialization routines, new threads can be created, but they do not begin execution until DLL initialization is done for the process.

•	Only one thread in a process can be in a DLL initialization or detach routine at a time.

•	ExitProcess does not return until no threads are in their DLL initialization or detach routines.

See Also

CreateProcess, CreateRemoteThread, CreateThread, ExitThread, GetExitCodeProcess, GetExitCodeThread, OpenProcess, TerminateProcess


ExitThread
ExitThread  QuickInfo  Overview  Group

The ExitThread function ends a thread.

VOID ExitThread(

DWORD  dwExitCode	// exit code for this thread
);
Parameters

dwExitCode

Specifies the exit code for the calling thread. Use the GetExitCodeThread function to retrieve a thread's exit code.

Return Value

This function does not return a value.

Remarks

ExitThread is the preferred method of exiting a thread. When this function is called (either explicitly or by returning from a thread procedure), the current thread's stack is deallocated and the thread terminates. The entry-point function of all attached dynamic-link libraries (DLLs) is invoked with a value indicating that the thread is detaching from the DLL.

If the thread is the last thread in the process when this function is called, the thread's process is also terminated.

The state of the thread object becomes signaled, releasing any other threads that had been waiting for the thread to terminate. The thread's termination status changes from STILL_ACTIVE to the value of the dwExitCode parameter.

Terminating a thread does not necessarily remove the thread object from the operating system. A thread object is deleted when the last handle to the thread is closed.

The ExitProcess, ExitThread, CreateThread, CreateRemoteThread functions, and a process that is starting (as the result of a CreateProcess call) are serialized between each other within a process. Only one of these events can happen in an address space at a time. This means the following restrictions hold:

•	During process startup and DLL initialization routines, new threads can be created, but they do not begin execution until DLL initialization is done for the process.

•	Only one thread in a process can be in a DLL initialization or detach routine at a time.

•	ExitProcess does not return until no threads are in their DLL initialization or detach routines.

A thread that uses functions from the C run-time libraries should use the _beginthread and _endthread C run-time functions for thread management rather than CreateThread and ExitThread. Failure to do so results in small memory leaks when ExitThread is called.

See Also

CreateProcess, CreateRemoteThread, CreateThread, ExitProcess, FreeLibraryAndExitThread, GetExitCodeThread, TerminateThread


ExitWindows
ExitWindows  QuickInfo  Overview  Group

The ExitWindows function logs the current user off.

BOOL ExitWindows(

DWORD  dwReserved,	// reserved
UINT  uReserved	// reserved
);
Parameters

dwReserved

Reserved; must be zero.

uReserved

Reserved; must be zero.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Windows NT: The ExitWindows function asks applications if they want to terminate by sending the WM_QUERYENDSESSION message to the main window of all running applications.

Windows 95: The ExitWindows function sends the WM_QUERYENDSESSION message to all applications except the one that called ExitWindows.

An application agrees to terminate by returning TRUE when it receives this message (or by allowing the DefWindowProc function to process the message). If any application returns FALSE when it receives the WM_QUERYENDSESSION message, the shutdown is canceled.

After Windows processes the results of the WM_QUERYENDSESSION message, it sends the WM_ENDSESSION message with the wParam parameter set to TRUE if the system is shutting down and to FALSE if it is not.

Windows does not allow new applications to start up during the shutdown process.

See Also

DefWindowProc, ExitWindowsEx


ExitWindowsEx
ExitWindowsEx  QuickInfo  Overview  Group

The ExitWindowsEx function either logs off, shuts down, or shuts down and restarts the system.

BOOL ExitWindowsEx(

UINT  uFlags,	// shutdown operation
DWORD  dwReserved	// reserved
);
Parameters

uFlags

Specifies the type of shutdown. This parameter must be some combination of the following values:

Value	Meaning
EWX_FORCE	Forces processes to terminate. Instead of bringing up the "application not responding" dialog box for the user, this value forces an application to terminate if it does not respond.
EWX_LOGOFF	Shuts down all processes running in the security context of the process that called the ExitWindowsEx function. Then it logs the user off.
EWX_POWEROFF	Shuts down the system and turns off the power. The application must have the SE_SHUTDOWN_NAME privilege (for more information, see the Remarks section) and the system must support the power-off feature.
EWX_REBOOT	Shuts down the system and then restarts the system. The application must have the SE_SHUTDOWN_NAME privilege (for more information, see the Remarks section).
EWX_SHUTDOWN	Shuts down the system to a point at which it is safe to turn off the power. All file buffers have been flushed to disk, and all running processes have stopped. The application must have the SE_SHUTDOWN_NAME privilege (for more information, see the Remarks section).
dwReserved

Reserved; this parameter is ignored.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

To shut down or restart the system, the calling process must use the AdjustTokenPrivileges function to enable the SE_SHUTDOWN_NAME privilege. For more information about security privileges, see Security.

This function returns as soon as it has initiated the shutdown. The shutdown or logoff then proceeds asynchronously.

During a shutdown or log-off operation, applications that are shut down are allowed a specific amount of time to respond to the shutdown request. If the time expires, Windows displays a dialog box that allows the user to forcibly shut down the application, to retry the shutdown, or to cancel the shutdown request. If the EWX_FORCE value is specified, Windows always forces applications to close and does not display the dialog box.

The ExitWindowsEx function sends a separate notification message, CTRL_SHUTDOWN_EVENT or CTRL_LOGOFF_EVENT as the situation warrants, to console processes. A console process routes these messages to its HandlerRoutine functions, which are added and removed by calls to the SetConsoleCtrlHandler function. ExitWindowsEx sends these notification messages asynchronously; thus, an application cannot assume that the console notification messages have been handled when a call to ExitWindowsEx returns.

See Also

AdjustTokenPrivileges, ExitWindows, HandlerRoutine, SetConsoleCtrlHandler


ExpandEnvironmentStrings
ExpandEnvironmentStrings  QuickInfo  Overview  Group

The ExpandEnvironmentStrings function expands environment-variable strings and replaces them with their defined values.

DWORD ExpandEnvironmentStrings(

LPCTSTR  lpSrc,	// address of string with environment variables
LPTSTR  lpDst,	// address of string with expanded environment variables
DWORD  nSize	// maximum characters in expanded string
);
Parameters

lpSrc

Points to a null-terminated string that might contain references to environment-variable strings of the form:

%variableName%

For each such reference, the %variableName% portion is replaced with the current value of that environment variable.

The replacement rules are the same as those used by the command interpreter. Case is ignored when looking up the environment-variable name. If the name is not found, the %variableName% portion is left undisturbed.

lpDst

Points to a buffer to receive a copy of the source buffer, after all environment-variable name substitutions have been performed.

nSize

Specifies the maximum number of characters that can be stored in the buffer pointed to by the lpDst parameter, including the terminating null character.

Return Value

If the function succeeds, the return value is the number of characters stored in the destination buffer. If the number of characters is greater than the size of the destination buffer, the return value is the size of the buffer required to hold the expanded strings.

If the function fails, the return value is zero. To get extended error information, call GetLastError.


ExtCreatePen
ExtCreatePen  QuickInfo  Overview  Group

The ExtCreatePen function creates a logical cosmetic or geometric pen that has the specified style, width, and brush attributes.

HPEN ExtCreatePen(

DWORD  dwPenStyle,	// pen style
DWORD  dwWidth,	// pen width
CONST LOGBRUSH *  lplb,	// address of structure for brush attributes
DWORD  dwStyleCount,	// length of array containing custom style bits
CONST DWORD *  lpStyle	// optional array of custom style bits
);
Parameters

dwPenStyle

Specifies a combination of type, style, end cap, and join attributes. The values from each category are combined by using the bitwise OR operator (|).

The pen type can be one of the following values:

Type	Description
PS_GEOMETRIC	Pen is geometric.
PS_COSMETIC	Pen is cosmetic.
The pen style can be any one of the following values:

Style	Description
PS_ALTERNATE	Windows NT: Pen sets every other pixel. (This style is applicable only for cosmetic pens.) Windows 95: Not supported.
PS_SOLID	Pen is solid.
PS_DASH	Pen is dashed. Windows 95 only: This style is not supported for geometric lines.
PS_DOT	Pen is dotted. Windows 95 only: This style is not supported for geometric lines.
PS_DASHDOT	Pen has alternating dashes and dots. Windows 95 only: This style is not supported for geometric lines.
PS_DASHDOTDOT	Pen has alternating dashes and double dots. Windows 95 only: This style is not supported for geometric lines.
PS_NULL	Pen is invisible.
PS_USERSTYLE	Windows NT: Pen uses a styling array supplied by the user. Windows 95: Not supported.
PS_INSIDEFRAME	Pen is solid. When this pen is used in any graphics device interface (GDI) drawing function that takes a bounding rectangle, the dimensions of the figure are shrunk so that it fits entirely in the bounding rectangle, taking into account the width of the pen. This applies only to geometric pens.
The end cap is only specified for geometric pens. The end cap can be one of the following values:

End cap	Description
PS_ENDCAP_ROUND	End caps are round.
PS_ENDCAP_SQUARE	End caps are square.
PS_ENDCAP_FLAT	End caps are flat.
The join is only specified for geometric pens. The join can be one of the following values:

Line join	Description
PS_JOIN_BEVEL	Joins are beveled.
PS_JOIN_MITER	Joins are mitered when they are within the current limit set by the SetMiterLimit function. If it exceeds this limit, the join is beveled.
PS_JOIN_ROUND	Joins are round.
Windows 95 only: The PS_ENDCAP_ROUND, PS_ENDCAP_SQUARE, PS_ENDCAP_FLAT, PS_JOIN_BEVEL, PS_JOIN_MITER, and PS_JOIN_ROUND styles are supported only for geometric pens when used to draw paths.

dwWidth

Specifies the width of the pen. If the dwPenStyle parameter is PS_GEOMETRIC, the width is given in logical units. If dwPenStyle is PS_COSMETIC, the width must be set to 1.

lplb

Points to a LOGBRUSH structure. If dwPenStyle is PS_COSMETIC, the lbColor member specifies the color of the pen and the lbStyle member must be set to BS_SOLID. If dwPenStyle is PS_GEOMETRIC, all members must be used to specify the brush attributes of the pen.

dwStyleCount

Specifies the length, in doubleword units, of the lpStyle array. This value must be zero if dwPenStyle is not PS_USERSTYLE.

lpStyle

Points to an array of doubleword values. The first value specifies the length of the first dash in a user-defined style, the second value specifies the length of the first space, and so on. This pointer must be NULL if dwPenStyle is not PS_USERSTYLE.

Return Value

If the function succeeds, the return value is a handle that identifies a logical pen.

If the function fails, the return value is zero.

Remarks

A geometric pen can have any width and can have any of the attributes of a brush, such as dithers and patterns. A cosmetic pen can only be a single pixel wide and must be a solid color, but cosmetic pens are generally faster than geometric pens.

The width of a geometric pen is always specified in world units. The width of a cosmetic pen is always 1.

End cap and join are only specified for geometric pens.

After an application creates a logical pen, it can select that pen into a device context by calling the SelectObject function. After a pen is selected into a device context, it can be used to draw lines and curves.

If dwPenStyle is PS_COSMETIC and PS_USERSTYLE, the entries in the lpStyle array specify lengths of dashes and spaces in style units. A style unit is defined by the device where the pen is used to draw a line.

If dwPenStyle is PS_GEOMETRIC and PS_USERSTYLE, the entries in the lpStyle array specify lengths of dashes and spaces in logical units.

If dwPenStyle is PS_ALTERNATE, the style unit is ignored and every other pixel is set.

If the lbStyle member of the LOGBRUSH structure pointed to by lplb is BS_PATTERN, the bitmap pointed to by the lbHatch member of that structure cannot be a dib section. A dib section is a bitmap created by CreateDibSection. If that bitmap is a dib section, the ExtCreatePen function fails.

When an application no longer requires a given pen, it should call the DeleteObject function to delete the pen.

See Also

CreatePen, CreateDibSection, CreatePenIndirect, DeleteObject, GetObject, LOGBRUSH, SelectObject, SetMiterLimit


ExtCreateRegion
ExtCreateRegion  QuickInfo  Overview  Group

The ExtCreateRegion function creates a region from the specified region and transformation data.

HRGN ExtCreateRegion(

CONST XFORM *  lpXform,	// address of transformation data
DWORD  nCount,	// size of structure containing region data
CONST RGNDATA *  lpRgnData	// address of region data
);
Parameters

lpXform

Points to an XFORM structure that defines the transformation to be performed on the region. If this pointer is NULL, the identity transformation is used.

nCount

Specifies the number of bytes pointed to by lpRgnData.

lpRgnData

Points to a RGNDATA structure that contains the region data.

Return Value

If the function succeeds, the return value is the value of the region.

If the function fails, the return value is NULL.

Remarks

An application can retrieve data for a region by calling the GetRegionData function.

Windows 95 only: Regions are no longer limited to the 64K heap.

Windows 95 only: World transforms that involve either shearing or rotations are not supported. ExtCreateRegion fails if the transformation matrix is anything other than a scaling or translation of the region.

See Also

GetRegionData, RGNDATA, XFORM


ExtDeviceMode

The ExtDeviceMode function is not implemented in the Win32 API. Win32-based applications should use the DocumentProperties function.

See Also

GetRegionData, RGNDATA, XFORM


ExtensionPropSheetPageProc [New - Windows NT]
ExtensionPropSheetPageProc  QuickInfo  Overview  Group

[New - Windows NT]

The ExtensionPropSheetPageProc function specifies an application-defined callback function that receives the address of the AddPropSheetPageProc function, which resides in the module that creates a property sheet. A property sheet extension must export the ExtensionPropSheetPageProc function.

BOOL CALLBACK ExtensionPropSheetPageProc(

LPVOID lpv,
LPFNADDPROPSHEETPAGE  lpfnAddPropSheetPageProc,
LPARAM  lParam
);
Parameters

lpv

Pointer to an application-defined value that describes an item for which a property sheet page is to be created. This parameter can be NULL.

lpfnAddPropSheetPageProc

Pointer to the AddPropSheetPageProc function. The extension dynamic-link library (DLL) calls this function to add a page to the property sheet.

lParam

Application-defined 32-bit value.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

See Also

AddPropSheetPageProc


ExtEscape
ExtEscape  QuickInfo  Overview  Group

The ExtEscape function allows applications to access capabilities of a particular device that are not available through GDI.

int ExtEscape(

HDC  hdc,	// handle of device context
int  nEscape,	// escape function
int  cbInput,	// number of bytes in input structure
LPCSTR  lpszInData,	// address of input structure
int  cbOutput,	// number of bytes in output structure
LPSTR  lpszOutData	// address of output structure
);
Parameters

hdc

Identifies the device context.

nEscape

Specifies the escape function to be performed.

cbInput

Specifies the number of bytes of data pointed to by the lpszInData parameter.

lpszInData

Points to the input structure required for the specified escape.

cbOutput

Specifies the number of bytes of data pointed to by the lpszOutData parameter.

lpszOutData

Points to the structure that receives output from this escape. This parameter must not be NULL if ExtEscape is called as a query function. If no data is to be returned in this structure, set cbOutput to 0.

Return Value

The return value specifies the outcome of the function. It is greater than zero if the function is successful, except for the QUERYESCSUPPORT printer escape, which checks for implementation only. The return value is zero if the escape is not implemented. A return value less than zero indicates an error. To get extended error information, call GetLastError.

Remarks

Use this function to pass a driver-defined escape value to a device.

Use the Escape function to pass one of the escape values defined by Windows to a device. ExtEscape might not work properly with the escapes defined by Windows. In particular, escapes in which lpszInData points to a structure that contains a member that is a pointer will fail.

See Also

Escape, GetDeviceCaps


ExtFloodFill
ExtFloodFill  QuickInfo  Overview  Group

The ExtFloodFill function fills an area of the display surface with the current brush.

BOOL ExtFloodFill(

HDC  hdc,	// handle of device context
int  nXStart,	// x-coordinate where filling begins
int  nYStart,	// y-coordinate where filling begins
COLORREF  crColor,	// fill color
UINT  fuFillType	// fill type
);
Parameters

hdc

Identifies a device context.

nXStart

Specifies the logical x-coordinate of the point where filling is to begin.

nYStart

Specifies the logical y-coordinate of the point where filling is to begin.

crColor

Specifies the color of the boundary or of the area to be filled. The interpretation of crColor depends on the value of the fuFillType parameter.

fuFillType

Specifies the type of fill operation to be performed. It must be one of the following values:

Value	Meaning
FLOODFILLBORDER	The fill area is bounded by the color specified by the crColor parameter. This style is identical to the filling performed by the FloodFill function.
FLOODFILLSURFACE	The fill area is defined by the color that is specified by crColor. Filling continues outward in all directions as long as the color is encountered. This style is useful for filling areas with multicolored boundaries.
Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Following are some of the reasons this function might fail:

•	The filling could not be completed.

•	The given point has the boundary color specified by the crColor parameter (if FLOODFILLBORDER was requested).

•	The given point does not have the color specified by crColor (if FLOODFILLSURFACE was requested).

•	The point is outside the clipping region — that is, it is not visible on the device.

If the fuFillType parameter is FLOODFILLBORDER, Windows assumes that the area to be filled is completely bounded by the color specified by the crColor parameter. The function begins filling at the point specified by the nXStart and nYStart parameters and continues in all directions until it reaches the boundary.

If fuFillType is FLOODFILLSURFACE, Windows assumes that the area to be filled is a single color. The function begins to fill the area at the point specified by nXStart and nYStart and continues in all directions, filling all adjacent regions containing the color specified by crColor.

Only memory device contexts and devices that support raster-display operations support the ExtFloodFill function. To determine whether a device supports this technology, use the GetDeviceCaps function.

See Also

FloodFill, GetDeviceCaps


ExtractAssociatedIcon
ExtractAssociatedIcon  QuickInfo  Overview  Group

The ExtractAssociatedIcon function returns the handle of an indexed icon found in a file or an icon found in an associated executable file.

HICON ExtractAssociatedIcon(

HINSTANCE  hInst,	// application instance handle
LPTSTR  lpIconPath,	// path and filename of file for which icon is wanted
LPWORD  lpiIcon	// pointer to icon index
);
Parameters

hInst

Specifies the instance of the application calling the function.

lpIconPath

Points to a string that specifies the full path and filename of the file for which an icon is desired. The function extracts the icon handle from that file, or from an executable file associated with that file.

If the icon handle is obtained from an executable file, the function stores the full path and filename of that executable in the string pointed to by lpIconPath.

lpiIcon

Points to a WORD that specifies the index of the icon whose handle is to be obtained.

If the icon handle is obtained from an executable file, the function stores the icon's identifier in the WORD pointed to by lpiIcon.

Return Value

If the function succeeds, the return value is an icon handle. If the icon is extracted from an associated executable file, the function stores the full path and filename of the executable file in the string pointed to by lpIconPath, and stores the icon's identifier in the WORD pointed to by lpiIcon.

If the function fails, the return value is NULL.

Remarks

The ExtractAssociatedIcon function first looks for the indexed icon in the file specified by lpIconPath. If the function cannot obtain the icon handle from that file, and the file has an associated executable file, it looks in that executable file for an icon. Associations with executable files are based on filename extensions, are stored in the per-user part of the registry, and can be defined using File Manager's Associate command.

See Also

ExtractIcon


ExtractIcon
ExtractIcon  QuickInfo  Overview  Group

The ExtractIcon function retrieves the handle of an icon from the given executable file, dynamic-link library (DLL), or icon file.

HICON ExtractIcon(

HINSTANCE  hInst,	// instance handle
LPCTSTR  lpszExeFileName,	// filename of file with icon
UINT  nIconIndex	// index of icon to extract
);
Parameters

hInst

Identifies the instance of the application calling the function.

lpszExeFileName

Points to a null-terminated string specifying the name of an executable file, DLL, or icon file.

nIconIndex

Specifies the index of the icon to retrieve. If this value is 0, the function returns the handle of the first icon in the specified file. If this value is −1, the function returns the total number of icons in the specified file.

Return Value

If the function succeeds, the return value is the handle of an icon. If the file specified was not an executable file, DLL, or icon file, the return is 1. If no icons were found in the file, the return value is NULL.


ExtSelectClipRgn
ExtSelectClipRgn  QuickInfo  Overview  Group

The ExtSelectClipRgn function combines the specified region with the current clipping region by using the specified mode.

int ExtSelectClipRgn(

HDC  hdc,	// handle of device context
HRGN  hrgn,	// handle of region
int  fnMode	// region-selection mode
);
Parameters

hdc

Identifies the device context.

hrgn

Identifies the region to be selected. This handle can only be NULL when the RGN_COPY mode is specified.

fnMode

Specifies the operation to be performed. It must be one of the following values:

Value	Meaning
RGN_AND	The new clipping region combines the overlapping areas of the current clipping region and the region identified by hrgn.
RGN_COPY	The new clipping region is a copy of the region identified by hrgn. This is identical to SelectClipRgn. If the region identified by hrgn is NULL, the new clipping region is the default clipping region (the default clipping region is a null region).
RGN_DIFF	The new clipping region combines the areas of the current clipping region with those areas excluded from the region identified by hrgn.
RGN_OR	The new clipping region combines the current clipping region and the region identified by hrgn.
RGN_XOR	The new clipping region combines the current clipping region and the region identified by hrgn but excludes any overlapping areas.
Return Value

If the function succeeds, the return value specifies the new clipping region's complexity and can be any one of the following values:

Value	Meaning
NULLREGION	Region is empty.
SIMPLEREGION	Region is a single rectangle.
COMPLEXREGION	Region is more than one rectangle.
ERROR	An error occurred.
Remarks

If an error occurs when this function is called, the previous clipping region for the given device context is not affected.

The ExtSelectClipRgn function assumes that the coordinates for the given region are specified in device units.

Only a copy of the region identified by the hrgn parameter is used. The region itself can be reused after this call or it can be deleted.

See Also

SelectClipRgn


ExtTextOut
ExtTextOut  QuickInfo  Overview  Group

The ExtTextOut function draws a character string by using the currently selected font. An optional rectangle may be provided, to be used for clipping, opaquing, or both.

BOOL ExtTextOut(

HDC  hdc,	// handle of device context
int  X,	// x-coordinate of reference point
int  Y,	// y-coordinate of reference point
UINT  fuOptions,	// text-output options
CONST RECT  *lprc,	// optional clipping and/or opaquing rectangle
LPCTSTR  lpString,	// points to string
UINT  cbCount,	// number of characters in string
CONST INT *  lpDx	// address of array of intercharacter spacing values
);
Parameters

hdc

Identifies the device context.

X

Specifies the logical x-coordinate of the reference point used to position the string.

Y

Specifies the logical y-coordinate of the reference point used to position the string.

fuOptions

Specifies how to use the application-defined rectangle. This parameter can be a combination of the following values:

Value	Meaning
ETO_CLIPPED	The text will be clipped to the rectangle.
ETO_GLYPH_INDEX	Windows 95: The lpString array refers to an array returned from GetCharacterPlacement and should be parsed directly by GDI as no further language-specific processing is required. Glyph indexing only applies to TrueType fonts, but the flag can be used for Windows bitmap and vector fonts to indicate no further language processing is necessary and GDI should process the string directly. Note that all glyph indices are 16-bit values even though the string is assumed to be an array of 8-bit values for raster fonts.
ETO_OPAQUE	The current background color should be used to fill the rectangle.
ETO_RTLREADING	Windows 95: If this value is given and a Hebrew or Arabic font is selected into the device context, the string is output using right-to-left reading order. If this value is not given, the string is output in left- to-right order. The same effect can be achieved by setting the TA_RTLREADING value in SetTextAlign. This value is preserved for backward compatability.
The ETO_GLYPH_INDEX and ETO_RTLREADING values cannot be used together. Because ETO_GLYPH_INDEX implies that all language processing has been completed, the function ignores the ETO_RTLREADING flag if also given.

lprc

Points to an optional RECT structure that specifies the dimensions of a rectangle that is used for clipping, opaquing, or both.

lpString

Points to the character string to be drawn. The string does not need to be zero-terminated, since cbCount specifies the length of the string.

cbCount

Specifies the number of characters in the string.

lpDx

Points to an optional array of values that indicate the distance between origins of adjacent character cells. For example, lpDx[i] logical units separate the origins of character cell i and character cell i + 1.

Return Value

If the string is drawn, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The current text-alignment settings for the specified DC determine how the reference point is used to position the text. The text-alignment settings are retrieved by calling the GetTextAlign function. The text-alignment settings are altered by calling the SetTextAlign function.

If the lpDx parameter is NULL, the function uses the default spacing between characters. The character-cell origins and the contents of the array pointed to by the lpDx parameter are given in logical units. A character-cell origin is defined as the upper-left corner of the character cell.

By default, the current position is not used or updated by this function. However, an application can call the SetTextAlign function with the fMode parameter set to TA_UPDATECP to permit Windows to use and update the current position each time the application calls ExtTextOut for a given device context. When this flag is set, Windows ignores the X and Y parameters on subsequent ExtTextOut calls.

See Also

GetTextAlign, RECT, SetTextAlign


FatalAppExit
FatalAppExit  QuickInfo  Overview  Group

The FatalAppExit function displays a message box and terminates the application when the message box is closed. If Windows is running with a kernel debugger, the message box gives the user the opportunity to terminate the application or to cancel the message box and return to the application that called FatalAppExit.

VOID FatalAppExit(

UINT  uAction,	// reserved
LPCTSTR  lpMessageText	// address of string to display in message box
);
Parameters

uAction

Reserved; must be zero.

lpMessageText

Points to a null-terminated string that is displayed in the message box. The message is displayed on a single line. To accommodate low-resolution screens, the string should be no more than 35 characters in length.

Return Value

This function does not return a value.

Remarks

An application calls FatalAppExit only when it is not capable of terminating any other way. FatalAppExit may not always free an application's memory or close its files, and it may cause a general failure of Windows. An application that encounters an unexpected error should terminate by freeing all its memory and returning from its main message loop.

See Also

FatalExit


FatalExit
FatalExit  QuickInfo  Overview  Group

The FatalExit function transfers execution control to the debugger. The behavior of the debugger thereafter is specific to the type of debugger used.

VOID FatalExit(

int  ExitCode	// error code
);
Parameters

ExitCode

Specifies the error code associated with the exit.

Return Value

This function does not return a value.

Remarks

An application should only use FatalExit for debugging purposes. It should not call the function in a retail version of the application because doing so will terminate the application.

See Also

FatalAppExit


FileIOCompletionRoutine
FileIOCompletionRoutine  QuickInfo  Overview  Group

The FileIOCompletionRoutine function is called when an asynchronous input and output (I/O) function (ReadFileEx or WriteFileEx) is completed and the calling thread is in an alertable wait (using the SleepEx, WaitForSingleObjectEx, or WaitForMultipleObjectsEx function with the fAlertable flag set to TRUE).

VOID WINAPI FileIOCompletionRoutine(

DWORD  dwErrorCode,	// completion code
DWORD  dwNumberOfBytesTransfered,	// number of bytes transferred
LPOVERLAPPED  lpOverlapped	// address of structure with I/O information
);
Parameters

dwErrorCode

Specifies the I/O completion status. This parameter may be one of the following values:

Value	Meaning
0	The I/O was successful.
ERROR_HANDLE_EOF	The ReadFileEx function tried to read past the end of the file.
dwNumberOfBytesTransfered

Specifies the number of bytes transferred. If an error occurs, this parameter is zero.

lpOverlapped

Points to the OVERLAPPED structure specified by the asynchronous I/O function.

Windows does not use the hEvent member of the OVERLAPPED structure; the calling application may use this member to pass information to the completion routine. Windows does not use the OVERLAPPED structure after the completion routine is called, so the completion routine can deallocate the memory used by the overlapped structure.

Return Value

This function does not return a value.

Remarks

FileIOCompletionRoutine is a placeholder for an application-defined or library-defined function name.

Returning from this function allows another pending I/O completion routine to be called. All waiting completion routines are called before the alertable thread's wait is satisfied with a return code of WAIT_IO_COMPLETION. Windows may call the waiting completion routines in any order. They may or may not be called in the order the I/O functions are completed.

Each time Windows calls a completion routine, it uses some of the application's stack. If the completion routine does additional asynchronous I/O and alertable waits, the stack may grow.

See Also

OVERLAPPED, ReadFileEx, SleepEx, WaitForMultipleObjectsEx, WaitForSingleObjectEx, WriteFileEx


FileTimeToDosDateTime
FileTimeToDosDateTime  QuickInfo  Overview  Group

The FileTimeToDosDateTime function converts a 64-bit file time to MS-DOS date and time values.

BOOL FileTimeToDosDateTime(

CONST FILETIME *  lpFileTime,	// address of 64-bit file time
LPWORD  lpFatDate,	// address of variable for MS-DOS date
LPWORD  lpFatTime	// address of variable for MS-DOS time
);
Parameters

lpFileTime

Points to a FILETIME structure containing the 64-bit file time to convert to MS-DOS date and time format. The FILETIME structure has the following form:

typedef struct _FILETIME { // ft

    DWORD dwLowDateTime;

    DWORD dwHighDateTime;

} FILETIME;

lpFatDate

Points to a variable to receive the MS-DOS date. The date is a packed 16-bit value with the following format:

Bits	Contents
0−4	Day of the month (1−31)
5−8	Month (1 = January, 2 = February, etc.)
9−15	Year offset from 1980 (add 1980 to get actual year)
lpFatTime

Points to a variable to receive the MS-DOS time. The time is a packed 16-bit value with the following format:

Bits	Contents
0−4	Second divided by 2
5−10	Minute (0−59)
11−15	Hour (0−23 on a 24-hour clock)
Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The MS-DOS date format can represent only dates between 1/1/1980 and 12/31/2107; this conversion fails if the input file time is outside this range.

See Also

DosDateTimeToFileTime, FileTimeToSystemTime, SystemTimeToFileTime


FileTimeToLocalFileTime
FileTimeToLocalFileTime  QuickInfo  Overview  Group

The FileTimeToLocalFileTime function converts a file time based on the Coordinated Universal Time (UTC) to a local file time.

BOOL FileTimeToLocalFileTime(

CONST FILETIME *  lpFileTime,	// address of UTC file time to convert
LPFILETIME  lpLocalFileTime	// address of converted file time
);
Parameters

lpFileTime

Points to a FILETIME structure containing the UTC-based file time to be converted into a local file time.

lpLocalFileTime

Points to a FILETIME structure to receive the converted local file time. This parameter cannot be the same as the lpFileTime parameter.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

FILETIME, LocalFileTimeToFileTime


FileTimeToSystemTime
FileTimeToSystemTime  QuickInfo  Overview  Group

The FileTimeToSystemTime function converts a 64-bit file time to system time format.

BOOL FileTimeToSystemTime(

CONST FILETIME *  lpFileTime,	// pointer to file time to convert
LPSYSTEMTIME  lpSystemTime	// pointer to structure to receive system time
);
Parameters

lpFileTime

Pointer to a FILETIME structure containing the file time to convert to system date and time format.

The FileTimeToSystemTime function only works with FILETIME values that are less than 0x8000000000000000. The function fails with values equal to or greater than that.

lpSystemTime

Pointer to a SYSTEMTIME structure to receive the converted file time.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

As noted above, the function fails for FILETIME values that are equal to or greater than 0x8000000000000000.

See Also

DosDateTimeToFileTime, FILETIME, FileTimeToDosDateTime, SYSTEMTIME, SystemTimeToFileTime


FillConsoleOutputAttribute
FillConsoleOutputAttribute  QuickInfo  Overview  Group

The FillConsoleOutputAttribute function sets the text and background color attributes for a specified number of character cells, beginning at the specified coordinates in a screen buffer.

BOOL FillConsoleOutputAttribute(

HANDLE  hConsoleOutput,	// handle of screen buffer
WORD  wAttribute,	// color attribute to write
DWORD  nLength,	// number of character cells to write to
COORD  dwWriteCoord,	// x- and y-coordinates of first cell
LPDWORD  lpNumberOfAttrsWritten	// address of number of cells written to
);
Parameters

hConsoleOutput

Identifies a screen buffer. The handle must have GENERIC_WRITE access.

wAttribute

Specifies the foreground and background color attributes to write to the screen buffer. Any combination of the following values can be specified: FOREGROUND_BLUE, FOREGROUND_GREEN, FOREGROUND_RED, FOREGROUND_INTENSITY, BACKGROUND_BLUE, BACKGROUND_GREEN, BACKGROUND_RED, and BACKGROUND_INTENSITY. For example, the following combination of values produces white text on a black background:

FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE

nLength

Specifies the number of character cells to be set to the specified color attributes.

dwWriteCoord

Specifies a COORD structure containing the screen buffer coordinates of the first cell whose attributes are to be set.

lpNumberOfAttrsWritten

Points to the variable that receives the number of character cells whose attributes were actually set.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

If the number of character cells whose attributes are to be set extends beyond the end of the specified row in the screen buffer, the cells of the next row are set. If the number of cells to write to extends beyond the end of the screen buffer, the cells are written up to the end of the screen buffer.

The character values at the positions written to are not changed.

See Also

COORD, FillConsoleOutputCharacter, SetConsoleTextAttribute, WriteConsoleOutputAttribute


FillConsoleOutputCharacter
FillConsoleOutputCharacter  QuickInfo  Overview  Group

The FillConsoleOutputCharacter function writes a character to the screen buffer a specified number of times, beginning at the specified coordinates.

BOOL FillConsoleOutputCharacter(

HANDLE  hConsoleOutput,	// handle of screen buffer
TCHAR  cCharacter,	// character to write
DWORD  nLength,	// number of character cells to write to
COORD  dwWriteCoord,	// x- and y-coordinates of first cell
LPDWORD  lpNumberOfCharsWritten	// address of number of cells written to
);
Parameters

hConsoleOutput

Identifies a screen buffer. The handle must have GENERIC_WRITE access.

cCharacter

Specifies the character to write to the screen buffer.

nLength

Specifies the number of character cells to write the character to.

dwWriteCoord

Specifies a COORD structure containing the screen buffer coordinates of the first cell to write the character to.

lpNumberOfCharsWritten

Points to the variable that receives the number of characters actually written to the screen buffer.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

If the number of characters to write to extends beyond the end of the specified row in the screen buffer, characters are written to the next row. If the number of characters to write to extends beyond the end of the screen buffer, the characters are written up to the end of the screen buffer.

The attribute values at the positions written are not changed.

See Also

COORD, FillConsoleOutputAttribute, WriteConsoleOutputCharacter


FillMemory
FillMemory  QuickInfo  Overview  Group

The FillMemory function fills a block of memory with a specified value.

VOID FillMemory (

PVOID  Destination,	// address of block to fill
DWORD  Length,	// size, in bytes, of block to fill
BYTE  Fill	// the byte value with which to fill
);
Parameters

Destination

Points to the starting address of the block of memory to fill.

Length

Specifies the size, in bytes, of the block of memory to fill.

Fill

Specifies the byte value with which to fill the memory block.

Return Value

This function has no return value.

See Also

CopyMemory, MoveMemory, ZeroMemory


FillPath
FillPath  QuickInfo  Overview  Group

The FillPath function closes any open figures in the current path and fills the path's interior by using the current brush and polygon-filling mode.

BOOL FillPath(

HDC  hdc	// handle of device context
);
Parameters

hdc

Identifies a device context (DC) that contains a valid path.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError. GetLastError may return one of the following error codes:

ERROR_CAN_NOT_COMPLETE
ERROR_INVALID_PARAMETER
ERROR_NOT_ENOUGH_MEMORY

Remarks

After its interior is filled, the path is discarded from the DC identified by the hdc parameter.

See Also

BeginPath, SetPolyFillMode, StrokeAndFillPath, StrokePath


FillRect
FillRect  QuickInfo  Overview  Group

The FillRect function fills a rectangle by using the specified brush. This function includes the left and top borders, but excludes the right and bottom borders of the rectangle.

int FillRect(

HDC  hDC,	// handle of device context
CONST RECT  *lprc,	// address of structure with rectangle
HBRUSH  hbr	// handle of brush
);
Parameters

hDC

Identifies the device context.

lprc

Points to a RECT structure that contains the logical coordinates of the rectangle to be filled.

hbr

Identifies the brush used to fill the rectangle.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The brush identified by the hbr parameter may be either a handle to a logical brush or a color value. If specifying a handle to a logical brush, call one of the following functions to obtain the handle: CreateHatchBrush, CreatePatternBrush, or CreateSolidBrush. Additionally, you may retrieve a handle to one of the stock brushes by using the GetStockObject function. If specifying a color value for the hbr parameter, it must be one of the standard system colors (the value 1 must be added to the chosen color). For example:

FillRect(hdc, &rect, (HBRUSH) (COLOR_ENDCOLORS+1));

For a list of all the standard system colors, see GetSysColor.

When filling the specified rectangle, FillRect does not include the rectangle's right and bottom sides. GDI fills a rectangle up to, but not including, the right column and bottom row, regardless of the current mapping mode.

See Also

CreateHatchBrush, CreatePatternBrush, CreateSolidBrush, GetStockObject, RECT


FillRgn
FillRgn  QuickInfo  Overview  Group

The FillRgn function fills a region by using the specified brush.

BOOL FillRgn(

HDC  hdc,	// handle of device context
HRGN  hrgn,	// handle of region to be filled
HBRUSH  hbr	// handle of brush used to fill the region
);
Parameters

hdc

Identifies the device context.

hrgn

Identifies the region to be filled. The region's coordinates are presumed to be in logical units.

hbr

Identifies the brush to be used to fill the region.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

See Also

CreateBrushIndirect, CreateDIBPatternBrush, CreateHatchBrush, CreatePatternBrush, CreateSolidBrush, PaintRgn


FindAtom
FindAtom  QuickInfo  Overview  Group

The FindAtom function searches the local atom table for the specified character string and retrieves the atom associated with that string.

ATOM FindAtom(

LPCTSTR  lpString	// address of string to find
);
Parameters

lpString

Points to the null-terminated character string to search for.

Return Value

If the function succeeds, the return value is the atom associated with the given string.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

Even though Windows preserves the case of a string in an atom table, the search performed by the FindAtom function is not case sensitive.

See Also

AddAtom, DeleteAtom, GlobalAddAtom, GlobalDeleteAtom, GlobalFindAtom


FindClose
FindClose  QuickInfo  Overview  Group

The FindClose function closes the specified search handle. The FindFirstFile and FindNextFile functions use the search handle to locate files with names that match a given name.

BOOL FindClose(

HANDLE  hFindFile	// file search handle
);
Parameters

hFindFile

Identifies the search handle. This handle must have been previously opened by the FindFirstFile function.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

After the FindClose function is called, the handle specified by the hFindFile parameter cannot be used in subsequent calls to either the FindNextFile or FindClose function.

See Also

FindFirstFile, FindNextFile


FindCloseChangeNotification
FindCloseChangeNotification  QuickInfo  Overview  Group

The FindCloseChangeNotification function stops change notification handle monitoring.

BOOL FindCloseChangeNotification(

HANDLE  hChangeHandle	// handle of change notification to close
);
Parameter

hChangeHandle

Identifies a change notification handle created by the FindFirstChangeNotification function.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

After the FindCloseChangeNotification function is called, the handle specified by the hChangeHandle parameter cannot be used in subsequent calls to either the FindNextChangeNotification or FindCloseChangeNotification function.

See Also

FindFirstChangeNotification, FindNextChangeNotification, WaitForMultipleObjects, WaitForSingleObject


FindClosePrinterChangeNotification
FindClosePrinterChangeNotification  QuickInfo  Overview  Group

The FindClosePrinterChangeNotification function closes a change notification object created by calling the FindFirstPrinterChangeNotification function. The printer or print server associated with the change notification object will no longer be monitored by that object.

BOOL FindClosePrinterChangeNotification(

HANDLE  hChange	// handle of change notification object to close
);
Parameter

hChange

Handle to the change notification object to be closed. This is a handle created by calling the FindFirstPrinterChangeNotification function.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

After calling the FindClosePrinterChangeNotification function, you cannot use the hChange handle in subsequent calls to either FindFirstPrinterChangeNotification or FindNextPrinterChangeNotification.

The three Find*PrinterChangeNotification functions, in combination with the wait functions, provide an asynchronous, more resource-efficient alternative to the WaitForPrinterChange function.

See Also

FindFirstPrinterChangeNotification, FindNextPrinterChangeNotification, WaitForMultipleObjects, WaitForMultipleObjectsEx, WaitForPrinterChange, WaitForSingleObject, WaitForSingleObjectEx


FindExecutable
FindExecutable  QuickInfo  Overview  Group

The FindExecutable function retrieves the name and handle of the executable (.EXE) file associated with the specified filename.

HINSTANCE FindExecutable(

LPCTSTR  lpFile,	// address of string for filename
LPCTSTR  lpDirectory,	// address of string for default directory
LPTSTR  lpResult	// address of buffer for string for executable file on return
);
Parameters

lpFile

Points to a null-terminated string specifying a filename. This can be a document or executable file.

lpDirectory

Points to a null-terminated string specifying the default directory.

lpResult

Points to a buffer to receive the filename when the function returns. This filename is a null-terminated string specifying the executable file started when an "open" association is run on the file specified in the lpFile parameter.

Return Value

The return value for the FindExecutable function if valid only if the function fails. If it does fail, the return value is less than or equal to 32. Possible error values are listed in the Remarks section.

Remarks

When FindExecutable returns, the lpResult parameter may contain the path to the DDE server started if no server responds to a request to initiate a DDE conversation.

The FindExecutable function returns 31 if there is no association for the specified file type. Following are the other possible error values:

Value	Meaning
0	The system is out of memory or resources.
ERROR_FILE_NOT_FOUND	The specified file was not found.
ERROR_PATH_NOT_FOUND	The specified path was not found.
ERROR_BAD_FORMAT	The .EXE file is invalid (non-Win32 .EXE or error in .EXE image).
See Also

ShellExecute


FindFirstChangeNotification
FindFirstChangeNotification  QuickInfo  Overview  Group

The FindFirstChangeNotification function creates a change notification handle and sets up initial change notification filter conditions. A wait on a notification handle succeeds when a change matching the filter conditions occurs in the specified directory or subtree.

HANDLE FindFirstChangeNotification(

LPCTSTR  lpPathName,	// address of name of directory to watch
BOOL  bWatchSubtree,	// flag for monitoring directory or directory tree
DWORD  dwNotifyFilter	// filter conditions to watch for
);
Parameters

lpPathName

Points to a null-terminated string that specifies the path of the directory to watch.

bWatchSubtree

Specifies whether the function will monitor the directory or the directory tree. If this parameter is TRUE, the function monitors the directory tree rooted at the specified directory; if it is FALSE, it monitors only the specified directory.

dwNotifyFilter

Specifies the filter conditions that satisfy a change notification wait. This parameter can be one or more of the following values:

Value	Meaning
FILE_NOTIFY_CHANGE_FILE_NAME
	Any filename change in the watched directory or subtree satisfies a change notification wait. Changes include renames, creations, and deletions.
FILE_NOTIFY_CHANGE_DIR_NAME
	Any directory-name change in the watched directory or subtree satisfies a change notification wait. Changes include directory creations and deletions.
FILE_NOTIFY_CHANGE_ATTRIBUTES
	Any attribute change in the watched directory or subtree satisfies a change notification wait.
FILE_NOTIFY_CHANGE_SIZE
	Any file-size change in the watched directory or subtree satisfies a change notification wait. The operating system detects a change in file size only when the file is written to the disk. For operating systems that use extensive caching, detection occurs only when the cache is sufficiently flushed.
FILE_NOTIFY_CHANGE_LAST_WRITE
	Any change to the last write-time of files in the watched directory or subtree satisfies a change notification wait. The operating system detects a change to the last write-time only when the file is written to the disk. For operating systems that use extensive caching, detection occurs only when the cache is sufficiently flushed.
FILE_NOTIFY_CHANGE_SECURITY
	Any security-descriptor change in the watched directory or subtree satisfies a change notification wait.
Return Value

If the function succeeds, the return value is a handle of a find change notification object.

If the function fails, the return value is INVALID_HANDLE_VALUE. To get extended error information, call GetLastError.

Remarks

The WaitForSingleObject and WaitForMultipleObjects functions monitor the specified directory or subtree by using the handle returned by the FindFirstChangeNotification function. A wait is satisfied when one of the filter conditions occurs in the monitored directory or subtree.

After the wait has been satisfied, the application can respond to this condition and continue monitoring the directory by calling the FindNextChangeNotification function and the appropriate wait function. When the handle is no longer needed, it can be closed by using the FindCloseChangeNotification function.

See Also

FindCloseChangeNotification, FindNextChangeNotification, WaitForMultipleObjects, WaitForSingleObject


FindFirstFile
FindFirstFile  QuickInfo  Overview  Group

The FindFirstFile function searches a directory for a file whose name matches the specified filename. FindFirstFile examines subdirectory names as well as filenames.

HANDLE FindFirstFile(

LPCTSTR  lpFileName,	// address of name of file to search for
LPWIN32_FIND_DATA  lpFindFileData	// address of returned information
);
Parameters

lpFileName

Windows 95: Points to a null-terminated string that specifies a valid directory or path and filename, which can contain wildcard characters (* and ?). This string must not exceed MAX_PATH characters.

Windows NT: Points to a null-terminated string that specifies a valid directory or path and filename, which can contain wildcard characters (* and ?).

There is a default string size limit for paths of MAX_PATH characters. This limit is related to how the FindFirstFile function parses paths. An application can transcend this limit and send in paths longer than MAX_PATH characters by calling the wide (W) version of FindFirstFile and prepending "\\?\" to the path. The "\\?\" tells the function to turn off path parsing; it lets paths longer than MAX_PATH be used with FindFirstFileW. This also works with UNC names. The "\\?\" is ignored as part of the path. For example, "\\?\C:\myworld\private" is seen as "C:\myworld\private", and "\\?\UNC\bill_g_1\hotstuff\coolapps" is seen as "\\bill_g_1\hotstuff\coolapps".

lpFindFileData

Points to the WIN32_FIND_DATA structure that receives information about the found file or subdirectory. The structure can be used in subsequent calls to the FindNextFile or FindClose function to refer to the file or subdirectory.

Return Value

If the function succeeds, the return value is a search handle used in a subsequent call to FindNextFile or FindClose.

If the function fails, the return value is INVALID_HANDLE_VALUE. To get extended error information, call GetLastError.

Remarks

The FindFirstFile function opens a search handle and returns information about the first file whose name matches the specified pattern. Once the search handle is established, you can use the FindNextFile function to search for other files that match the same pattern. When the search handle is no longer needed, close it by using the FindClose function.

This function searches for files by name only; it cannot be used for attribute-based searches.

See Also

FindClose, FindNextFile, GetFileAttributes, SetFileAttributes, WIN32_FIND_DATA


FindFirstFreeAce
FindFirstFreeAce  QuickInfo  Overview  Group

The FindFirstFreeAce function retrieves a pointer to the first free byte in an access-control list (ACL).

BOOL FindFirstFreeAce(

PACL  pAcl,	// address of access-control list
LPVOID  *pAce	// address of pointer to first free byte
);
Parameters

pAcl

Points to an ACL structure.

pAce

Points to a pointer to the first free position in the ACL created when the function returns. If the ACL is invalid, this parameter is NULL. If the ACL is full, this parameter points to the byte immediately following the ACL.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

ACL, GetAce, GetAclInformation


FindFirstPrinterChangeNotification
FindFirstPrinterChangeNotification  QuickInfo  Overview  Group

The FindFirstPrinterChangeNotification function creates a change notification object and returns a handle to the object. You can then use this handle in a call to one of the wait functions to monitor changes to the printer or print server.

The FindFirstPrinterChangeNotification call specifies the type of changes to be monitored. You can specify a set of conditions to monitor for changes, a set of printer information fields to monitor, or both.

A wait operation on the change notification handle succeeds when one of the specified changes occurs in the specified printer or print server. You then call the FindNextPrinterChangeNotification function to retrieve information about the change, and to reset the change notification object for use in the next wait operation.

HANDLE FindFirstPrinterChangeNotification(

HANDLE  hPrinter,	// handle to printer or print server to monitor for changes
DWORD  fdwFlags,	// flags that specify the conditions to monitor
DWORD  fdwOptions,	// reserved, must be zero
LPVOID  pPrinterNotifyOptions	// pointer to structure specifying printer information to monitor
);
Parameters

hPrinter

Handle to the printer or print server that you want to monitor. This handle is obtained by calling the OpenPrinter function.

fdwFlags

A set of bit flags that specify the conditions that will cause the change notification object to enter a signaled state. A change notification occurs when one or more of the specified conditions are met. The fdwFlags parameter can be zero if pPrinterNotifyOptions is non-NULL.

You can set one or more of the following change notification constants:

Value	Meaning
PRINTER_CHANGE_FORM
	Notify of any changes to a form. You can set this general flag or one or more of the following specific flags: PRINTER_CHANGE_ADD_FORM PRINTER_CHANGE_SET_FORM PRINTER_CHANGE_DELETE_FORM
PRINTER_CHANGE_JOB
	Notify of any changes to a job. You can set this general flag or one or more of the following specific flags: PRINTER_CHANGE_ADD_JOB PRINTER_CHANGE_SET_JOB PRINTER_CHANGE_DELETE_JOB PRINTER_CHANGE_WRITE_JOB
PRINTER_CHANGE_PORT
	Notify of any changes to a port. You can set this general flag or one or more of the following specific flags: PRINTER_CHANGE_ADD_PORT PRINTER_CHANGE_CONFIGURE_PORT PRINTER_CHANGE_DELETE_PORT
PRINTER_CHANGE_PRINT_PROCESSOR
	Notify of any changes to a print processor. You can set this general flag or one or more of the following specific flags: PRINTER_CHANGE_ADD_PRINT_PROCESSOR PRINTER_CHANGE_DELETE_PRINT_PROCESSOR
PRINTER_CHANGE_PRINTER
	Notify of any changes to a printer. You can set this general flag or one or more of the following specific flags:  PRINTER_CHANGE_ADD_PRINTER PRINTER_CHANGE_SET_PRINTER PRINTER_CHANGE_DELETE_PRINTER PRINTER_CHANGE_FAILED_CONNECTION_PRINTER
PRINTER_CHANGE_PRINTER_DRIVER
	Notify of any changes to a printer driver. You can set this general flag or one or more of the following specific flags: PRINTER_CHANGE_ADD_PRINTER_DRIVER PRINTER_CHANGE_SET_PRINTER_DRIVER PRINTER_CHANGE_DELETE_PRINTER_DRIVER
PRINTER_CHANGE_ALL
	Notify if any of the preceding changes occur.
For descriptions of the more specific flags in the preceding table, see the FindNextPrinterChangeNotification function.

fdwOptions

Reserved; must be zero.

pPrinterNotifyOptions

Pointer to a PRINTER_NOTIFY_OPTIONS structure. The pTypes member of this structure points to an array of one or more PRINTER_NOTIFY_OPTIONS_TYPE structures, each of which specifies a printer information field to monitor. A change notification occurs when one or more of the specified fields changes. When a change occurs, the FindNextPrinterChangeNotification function can retrieve the new printer information. This parameter can be NULL if fdwFlags is nonzero.

For a list of fields that can be monitored, see PRINTER_NOTIFY_OPTIONS_TYPE.

Return Value

If the function succeeds, the return value is a handle to a change notification object associated with the specified printer or print server.

If the function fails, the return value is INVALID_HANDLE_VALUE. To get extended error information, call GetLastError.

Remarks

To monitor a printer or print server, call the FindFirstPrinterChangeNotification function, then use the returned change notification object handle in a call to one of the wait functions:WaitForSingleObject, WaitForSingleObjectEx, WaitForMultipleObjects, or WaitForMultipleObjectsEx. A wait operation on a change notification object is satisfied when the change notification object enters the signaled state. The system signals the object when one or more of the changes specified by fdwFlags or pPrinterNotifyOptions occurs in the monitored printer or print server.

When you call FindFirstPrinterChangeNotification, either fdwFlags must be nonzero or pPrinterNotifyOptions must be non-NULL. If both are specified, notifications will occur for both.

When a wait operation on a printer change notification object is satisfied, call the FindNextPrinterChangeNotification function to determine the cause of the notification. For a condition specified by fdwFlags, FindNextPrinterChangeNotification reports the condition or conditions that changed. For a printer information field specified by pPrinterNotifyOptions , FindNextPrinterChangeNotification reports the field or fields that changed as well as the new information for these fields. FindNextPrinterChangeNotification also resets the change notification object to the nonsignaled state so you can use it in another wait operation to continue monitoring the printer or print server.

Do not call the FindNextPrinterChangeNotification function if the change notification object is not in the signaled state. If the wait function returns the value WAIT_TIMEOUT, the change object is not in the signaled state. Call the FindNextPrinterChangeNotification function only if the wait function succeeds without timing out.

When you no longer need the change notification object, close it by calling the FindClosePrinterChangeNotification function.

The three Find*PrinterChangeNotification functions, in combination with the wait functions, provide an asynchronous and resource-efficient alternative to the WaitForPrinterChange function.

See Also

FindClosePrinterChangeNotification, FindNextPrinterChangeNotification, OpenPrinter, PRINTER_NOTIFY_OPTIONS, PRINTER_NOTIFY_OPTIONS_TYPE, WaitForMultipleObjects, WaitForMultipleObjectsEx, WaitForPrinterChange, WaitForSingleObject, WaitForSingleObjectEx


FindNextChangeNotification
FindNextChangeNotification  QuickInfo  Overview  Group

The FindNextChangeNotification function requests that the operating system signal a change notification handle the next time it detects an appropriate change.

BOOL FindNextChangeNotification(

HANDLE  hChangeHandle	// handle of change notification to signal
);
Parameters

hChangeHandle

Identifies a change notification handle created by the FindFirstChangeNotification function.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

After the FindNextChangeNotification function returns successfully, the application can wait for notification that a change has occurred by using the WaitForSingleObject or WaitForMultipleObjects function.

If a change occurs after a call to FindFirstChangeNotification but before a call to FindNextChangeNotification, the operating system records the change. When FindNextChangeNotification is executed, the recorded change immediately satisfies a wait for the change notification.

FindNextChangeNotification should not be used more than once on the same handle without using either WaitForSingleObject or WaitForMultipleObjects. An application may miss a change notification if it uses FindNextChangeNotification when there is a change request outstanding.

When hChangeHandle is no longer needed, close it by using the FindCloseChangeNotification function.

See Also

FindCloseChangeNotification, FindFirstChangeNotification, WaitForMultipleObjects, WaitForSingleObject


FindNextFile
FindNextFile  QuickInfo  Overview  Group

The FindNextFile function continues a file search from a previous call to the FindFirstFile function.

BOOL FindNextFile(

HANDLE  hFindFile,	// handle of search
LPWIN32_FIND_DATA  lpFindFileData	// address of structure for data on found file
);
Parameters

hFindFile

Identifies a search handle returned by a previous call to the FindFirstFile function.

lpFindFileData

Points to the WIN32_FIND_DATA structure that receives information about the found file or subdirectory. The structure can be used in subsequent calls to FindNextFile to refer to the found file or directory.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError. If no matching files can be found, the GetLastError function returns ERROR_NO_MORE_FILES.

Remarks

The FindNextFile function searches for files by name only; it cannot be used for attribute-based searches.

See Also

FindClose, FindFirstFile, GetFileAttributes, SetFileAttributes, WIN32_FIND_DATA


FindNextPrinterChangeNotification
FindNextPrinterChangeNotification  QuickInfo  Overview  Group

The FindNextPrinterChangeNotification function retrieves information about the most recent change notification for a change notification object associated with a printer or print server. Call this function when a wait operation on the change notification object is satisfied.

The function also resets the change notification object to the not-signaled state. You can then use the object in another wait operation to continue monitoring the printer or print server. The operating system will set the object to the signaled state the next time one of a specified set of changes occurs to the printer or print server. The FindFirstPrinterChangeNotification function creates the change notification object and specifies the set of changes to be monitored.

BOOL FindNextPrinterChangeNotification(

HANDLE  hChange,	// handle to change notification object of interest
PDWORD  pdwChange	// pointer to a value that indicates the condition that changed
LPVOID  pPrinterNotifyOptions,	// pointer to a structure that specifies a refresh flag
LPVOID  *ppPrinterNotifyInfo,	// pointer to a pointer that receives printer information buffer
);
Parameters

hChange

Handle to a change notification object associated with a printer or print server. You obtain such a handle by calling the FindFirstPrinterChangeNotification function. The operating system sets this change notification object to the signaled state when it detects one of the changes specified in the object's change notification filter.

pdwChange

Pointer to a doubleword variable whose bits are set to indicate the changes that occurred to cause the most recent notification. The bit flags that might be set correspond to those specified in the fdwFlags parameter of the FindFirstPrinterChangeNotification call. The system sets one or more of the following bit flags:

Value	Meaning
PRINTER_CHANGE_ADD_FORM
	A form was added to the server.
PRINTER_CHANGE_ADD_JOB
	A print job was sent to the printer.
PRINTER_CHANGE_ADD_PORT
	A port or monitor was added to the server.
PRINTER_CHANGE_ADD_PRINT_PROCESSOR
	A print processor was added to the server.
PRINTER_CHANGE_ADD_PRINTER
	A printer was added to the server.
PRINTER_CHANGE_ADD_PRINTER_DRIVER
	A printer driver was added to the server.
PRINTER_CHANGE_CONFIGURE_PORT
	A port was configured on the server.
PRINTER_CHANGE_DELETE_FORM
	A form was deleted from the server.
PRINTER_CHANGE_DELETE_JOB
	A job was deleted.
PRINTER_CHANGE_DELETE_PORT
	A port or monitor was deleted from the server.
PRINTER_CHANGE_DELETE_PRINT_PROCESSOR
	A print processor was deleted from the server.
PRINTER_CHANGE_DELETE_PRINTER
	A printer was deleted.
PRINTER_CHANGE_DELETE_PRINTER_DRIVER
	A printer driver was deleted from the server.
PRINTER_CHANGE_FAILED_CONNECTION_PRINTER
	A printer connection has failed.
PRINTER_CHANGE_SET_FORM
	A form was set on the server.
PRINTER_CHANGE_SET_JOB
	A job was set.
PRINTER_CHANGE_SET_PRINTER
	A printer was set.
PRINTER_CHANGE_SET_PRINTER_DRIVER
	A printer driver was set.
PRINTER_CHANGE_WRITE_JOB
	Job data was written.
pPrinterNotifyOptions

Pointer to a PRINTER_NOTIFY_OPTIONS structure. Set the Flags member of this structure to PRINTER_NOTIFY_OPTIONS_REFRESH, to cause the function to return the current data for all monitored printer information fields. The function ignores all other members of the structure. This parameter can be NULL.

ppPrinterNotifyInfo

Pointer to a pointer variable that receives the address of a system-allocated, read-only buffer. Call the FreePrinterNotifyInfo function to free the buffer when you are finished with it. This parameter can be NULL if no information is required.

The buffer contains a PRINTER_NOTIFY_INFO structure, which contains an array of PRINTER_NOTIFY_INFO_DATA structures. Each element of the array contains information about one of the fields specified in the pPrinterNotifyOptions parameter of the FindFirstPrinterChangeNotification call. Typically, the function provides data only for the fields that changed to cause the most recent notification. However, if the structure pointed to by the pPrinterNotifyOptions parameter specifies PRINTER_NOTIFY_OPTIONS_REFRESH, the function provides data for all monitored fields.

If the PRINTER_NOTIFY_INFO_DISCARDED bit is set in the Flags member of the PRINTER_NOTIFY_INFO structure, an overflow or error occurred, and notifications may have been lost. In this case, no additional notifications will be sent until you make a second FindNextPrinterChangeNotification call that specifies PRINTER_NOTIFY_OPTIONS_REFRESH.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Call the FindNextPrinterChangeNotification function after a wait operation on a notification object created by FindFirstPrinterChangeNotification has been satisfied. Calling FindNextPrinterChangeNotification lets you obtain information about the change that satisfied the wait operation, and resets the notification object so it can be signaled when the next change occurs.

Do not call the FindNextPrinterChangeNotification function if the change notification object is not in the signaled state. If a wait function returns the value WAIT_TIMEOUT, the change object is not in the signaled state. Call the FindNextPrinterChangeNotification function only if the wait function succeeds without timing out.

To continue monitoring the printer or print server for changes, repeat the cycle of calling one of the wait functions, and then calling the FindNextPrinterChangeNotification function to examine the change and reset the notification object. The wait functions are WaitForSingleObject, WaitForSingleObjectEx, WaitForMultipleObjects, and WaitForMultipleObjectsEx.

FindNextPrinterChangeNotification may combine multiple changes to the same printer information field into a single notification. When this occurs, the function typically collapses all changes for the field into a single entry in the array of PRINTER_NOTIFY_INFO_DATA structures in ppPrinterNotifyInfo; the single entry reports only the most current information. However, for some job and printer information fields, the function can return multiple array entries for the same field. In this case, the last array entry for the field reports the current data, and the earlier entries contain the data for the intermediate stages.

When you no longer need the change notification object, close it by calling the FindClosePrinterChangeNotification function.

The three Find*PrinterChangeNotification functions, in combination with the wait functions, provide an asynchronous, more resource-efficient alternative to the WaitForPrinterChange function.

See Also

FindClosePrinterChangeNotification, FindFirstPrinterChangeNotification, PRINTER_NOTIFY_INFO, PRINTER_NOTIFY_INFO_DATA, PRINTER_NOTIFY_OPTIONS, WaitForMultipleObjects, WaitForMultipleObjectsEx, WaitForPrinterChange, WaitForSingleObject, WaitForSingleObjectEx


FindResource
FindResource  QuickInfo  Overview  Group

The FindResource function determines the location of a resource with the specified type and name in the specified module.

HRSRC FindResource(

HMODULE  hModule,	// resource-module handle
LPCTSTR  lpName,	// address of resource name
LPCTSTR  lpType	// address of resource type
);
Parameters

hModule

Identifies the module whose executable file contains the resource.

lpName

Specifies the name of the resource. For more information, see the Remarks section.

lpType

Specifies the resource type. For more information, see the Remarks section. For standard resource types, this parameter can be one of the following values:

Value	Meaning
RT_ACCELERATOR	Accelerator table
RT_BITMAP	Bitmap resource
RT_DIALOG	Dialog box
RT_FONT	Font resource
RT_FONTDIR	Font directory resource
RT_MENU	Menu resource
RT_RCDATA	Application-defined resource (raw data)
RT_STRING	String-table entry
RT_MESSAGETABLE	Message-table entry
RT_CURSOR	Hardware-dependent cursor resource
RT_GROUP_CURSOR	Hardware-independent cursor resource
RT_ICON	Hardware-dependent icon resource
RT_GROUP_ICON	Hardware-independent icon resource
RT_VERSION	Version resource
Return Value

If the function succeeds, the return value is a handle to the specified resource's info block. To obtain a handle to the resource, pass this handle to the LoadResource function.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

If the high-order word of the lpName or lpType parameter is zero, the low-order word specifies the integer identifier of the name or type of the given resource. Otherwise, those parameters are long pointers to null-terminated strings. If the first character of the string is a pound sign (#), the remaining characters represent a decimal number that specifies the integer identifier of the resource's name or type. For example, the string "#258" represents the integer identifier 258.

An application should reduce the amount of memory required for the resources by referring to them by integer identifier instead of by name.

An application can use FindResource to find any type of resource, but this function should be used only if the application must access the binary resource data when making subsequent calls to LoadLibrary and LockResource.

To use a resource immediately, an application should use one of the following resource-specific functions to find and load the resources in one call:

Function	Action
FormatMessage	Loads and formats a message-table entry.
LoadAccelerators	Loads an accelerator table.
LoadBitmap	Loads a bitmap resource.
LoadCursor	Loads a cursor resource.
LoadIcon	Loads an icon resource.
LoadMenu	Loads a menu resource.
LoadString	Loads a string-table entry.
For example, an application can use the LoadIcon function to load an icon for display on the screen. However, the application should use FindResource and LoadResource if it is loading the icon to copy its data to another application.

See Also

FindResourceEx, FormatMessage, LoadAccelerators, LoadBitmap, LoadCursor, LoadIcon, LoadMenu, LoadResource, LoadString, LockResource, SizeofResource


FindResourceEx
FindResourceEx  QuickInfo  Overview  Group

The FindResourceEx function determines the location of the resource with the specified type, name, and language in the specified module.

HRSRC FindResourceEx(

HMODULE  hModule,	// resource-module handle
LPCTSTR  lpType,	// address of resource type
LPCTSTR  lpName,	// address of resource name
WORD  wLanguage	// resource language
);
Parameters

hModule

Identifies the module whose executable file contains the resource. If this parameter is NULL, the function searches the module used to create the current process.

lpType

Points to a null-terminated string specifying the type name of the resource. For more information, see the Remarks section. For standard resource types, this parameter can be one of the following values:

Value	Meaning
RT_ACCELERATOR	Accelerator table
RT_BITMAP	Bitmap resource
RT_DIALOG	Dialog box
RT_FONT	Font resource
RT_FONTDIR	Font directory resource
RT_MENU	Menu resource
RT_RCDATA	Application-defined resource (raw data)
RT_STRING	String-table entry
RT_MESSAGETABLE	Message-table entry
RT_CURSOR	Hardware-dependent cursor resource
RT_GROUP_CURSOR	Hardware-independent cursor resource
RT_ICON	Hardware-dependent icon resource
RT_GROUP_ICON	Hardware-independent icon resource
RT_VERSION	Version resource
lpName

Points to a null-terminated string specifying the name of the resource. For more information, see the Remarks section.

wLanguage

Specifies the language of the resource. If this parameter is MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), the current language associated with the calling thread is used.

To specify a language other than the current language, use the MAKELANGID macro to create this parameter. For more information, see the MAKELANGID macro.

Return Value

If the function succeeds, the return value is a handle to the specified resource's info block. To obtain a handle to the resource, pass this handle to the LoadResource function.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

If the high-word of the lpType or lpName parameter is zero, the low-word specifies the integer identifier of the type or name of the given resource. Otherwise, those parameters are pointers to null-terminated strings. If the first character of the string is a pound sign (#), the remaining characters represent a decimal number that specifies the integer identifier of the resource's name or type. For example, the string "#258" represents the integer identifier 258.

Applications should reduce the amount of memory required for the resources by referring to them by integer identifier instead of by name.

An application can use FindResource to find any type of resource, but this function should be used only if the application must access the binary resource data when making subsequent calls to the LoadLibrary and LockResource functions.

To use a resource immediately, an application should use the following resource-specific functions to find and load the resources in one call:

Function	Action
FormatMessage	Loads and formats a message-table entry.
LoadAccelerators	Loads an accelerator table.
LoadBitmap	Loads a bitmap resource.
LoadCursor	Loads a cursor resource.
LoadIcon	Loads an icon resource.
LoadMenu	Loads a menu resource.
LoadString	Loads a string-table entry.
For example, an application can use the LoadIcon function to load an icon for display on the screen. However, the application should use FindResource and LoadResource if it is loading the icon to copy its data to another application.

See Also

FindResource, FormatMessage, LoadAccelerators, LoadBitmap, LoadCursor, LoadIcon, LoadMenu, LoadString, LoadResource, MAKELANGID


FindText
FindText  QuickInfo  Overview  Group

The FindText function creates a system-defined modeless dialog box that enables the user to find text within a document.

HWND FindText(

LPFINDREPLACE  lpfr	// address of structure with initialization data
);
Parameter

lpfr

Points to a FINDREPLACE structure that contains information used to initialize the dialog box. When the user makes a selection in the dialog box, the system fills this structure with data that describes the user's selection and then sends a message to the application. This message contains a pointer to the FINDREPLACE structure.

Return Value

If the function succeeds, the return value is the window handle of the dialog box.

If the function fails, the return value is NULL. To get extended error information, call CommDlgExtendedError. CommDlgExtendedError may return one of the following error codes:

CDERR_FINDRESFAILURE	CDERR_MEMLOCKFAILURE
CDERR_INITIALIZATION	CDERR_NOHINSTANCE
CDERR_LOCKRESFAILURE	CDERR_NOHOOK
CDERR_LOADRESFAILURE	CDERR_NOTEMPLATE
CDERR_LOADSTRFAILURE	CDERR_STRUCTSIZE
CDERR_MEMALLOCFAILURE	FRERR_BUFFERLENGTHZERO
Remarks

FindText does not perform a search operation; it simply returns a string typed by the user (as well as related data such as the direction in which the search should occur). An application must perform the search by using this string.

An application can use the window handle returned by the function to communicate with or to close the dialog box.

The dialog box procedure for the Find dialog box passes user requests to the application by sending special messages. The lParam parameter of each of these messages contains a pointer to a FINDREPLACE structure. The procedure sends the messages to the window identified by the hwndOwner member of the FINDREPLACE structure. An application can register the identifier for these messages by specifying the "commdlg_FindReplace" string in a call to the RegisterWindowMessage function.

For the TAB key to function correctly, any application that calls FindText must also call the IsDialogMessage function in its main message loop. IsDialogMessage returns a value that indicates whether messages are intended for the Find dialog box.

If the hook function (pointed to by the lpfnHook member of the FINDREPLACE structure) processes the WM_CTLCOLORDLG message, the function must return a handle of the brush that should be used to paint the control background.

See Also

CommDlgExtendedError, FINDREPLACE, IsDialogMessage, RegisterWindowMessage, ReplaceText, WM_CTLCOLORDLG,


FindWindow
FindWindow  QuickInfo  Overview  Group

The FindWindow function retrieves the handle of the top-level window whose class name and window name match the specified strings. This function does not search child windows.

HWND FindWindow(

LPCTSTR  lpClassName,	// address of class name
LPCTSTR  lpWindowName	// address of window name
);
Parameters

lpClassName

Points to a null-terminated string that specifies the class name or is an atom that identifies the class-name string. If this parameter is an atom, it must be a global atom created by a previous call to the GlobalAddAtom function. The atom, a 16-bit value, must be placed in the low-order word of lpClassName; the high-order word must be zero.

lpWindowName

Points to a null-terminated string that specifies the window name (the window's title). If this parameter is NULL, all window names match.

Return Value

If the function succeeds, the return value is the handle of the window that has the specified class name and window name.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

See Also

EnumWindows, FindWindowEx, GetClassName, GlobalAddAtom


FindWindowEx [New - Windows 95]
FindWindowEx  QuickInfo

[New - Windows 95]

The FindWindowEx function retrieves the handle of a window whose class name and window name match the specified strings. The function searches child windows, beginning with the one following the given child window.

HWND FindWindowEx(

HWND  hwndParent,	// handle of parent window
HWND  hwndChildAfter,	// handle of a child window
LPCTSTR  lpszClass,	// address of class name
LPCTSTR  lpszWindow	// address of window name
);
Parameters

hwndParent

Identifies the parent window whose child windows are to be searched.

If hwndParent is NULL, the function uses the desktop window as the parent window. The function searches among windows that are child windows of the desktop.

hwndChildAfter

Identifies a child window. The search begins with the next child window in the Z order. hwndChildAfter must be a direct child window of hwndParent, not just a descendant window.

If hwndChildAfter is NULL, the search begins with the first child window of hwndParent.

Note that if both hwndParent and hwndChildAfter are NULL, the function searches all top-level windows.

lpszClass

Points to a null-terminated string that specifies the class name or is an atom that identifies the class-name string. If this parameter is an atom, it must be a global atom created by a previous call to the GlobalAddAtom function. The atom, a 16-bit value, must be placed in the low-order word of lpszClass; the high-order word must be zero.

lpszWindow

Points to a null-terminated string that specifies the window name (the window's title). If this parameter is NULL, all window names match.

Return Value

If the function succeeds, the return value is the handle of the window that has the specified class and window names.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

See Also

EnumWindows, FindWindow, GetClassName, GlobalAddAtom


FixBrushOrgEx
FixBrushOrgEx  QuickInfo  Overview  Group

The FixBrushOrgEx function is not implemented in the Win32 API. It is provided for compatibility with Win32s. If called, the function does nothing, and returns FALSE.

See Also

GetBrushOrgEx, SetBrushOrgEx


FlashWindow
FlashWindow  QuickInfo  Overview  Group

The FlashWindow function flashes the specified window once.

BOOL FlashWindow(

HWND  hWnd,	// handle of window to flash
BOOL  bInvert	// flash status
);
Parameters

hWnd

Identifies the window to be flashed. The window can be either open or minimized (iconic).

bInvert

Specifies whether the window is to be flashed or returned to its original state. The window is flashed from one state to the other if this parameter is TRUE. If it is FALSE, the window is returned to its original state (either active or inactive).

Windows NT: If the window is iconic, this parameter is ignored.

Windows 95: When an application is iconic, the fInvert parameter is not ignored. If this parameter is TRUE, the taskbar icon window flashes active/inactive.

Return Value

The return value specifies the window's state before the call to the FlashWindow function. If the window was active before the call, it is TRUE; otherwise, it is FALSE.

Remarks

Flashing a window means changing the appearance of its caption bar as if the window were changing from inactive to active status, or vice versa. (An inactive caption bar changes to an active caption bar; an active caption bar changes to an inactive caption bar.)

Typically, a window is flashed to inform the user that the window requires attention but that it does not currently have the keyboard focus.

The FlashWindow function flashes the window only once; for repeated flashing, the application should create a system timer.

Windows 95: If the application is iconic, the fInvet parameter is NOT ignored. If the fInvert parameter is TRUE, the taskbar icon window flashes activ/inactive. If fInvert is FALSE, the taskbar icon window flashes inactive meaning that it does not change colors. It flashes, as if it were being redrawn, but it does not provide the visual invert clue to the user.

Windows NT: This function always returns TRUE for iconic windows. If the window is iconic, FlashWindow simply flashes the icon; the bInvert parameter is ignored for iconic windows.


FlattenPath
FlattenPath  QuickInfo  Overview  Group

The FlattenPath function transforms any curves in the path that is selected into the current device context (DC), turning each curve into a sequence of lines.

BOOL FlattenPath(

HDC  hdc	// handle of device context
);
Parameters

hdc

Identifies a DC that contains a valid path.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError. GetLastError may return one of the following error codes:

ERROR_CAN_NOT_COMPLETE
ERROR_INVALID_PARAMETER
ERROR_NOT_ENOUGH_MEMORY

See Also

WidenPath


FloodFill
FloodFill  QuickInfo  Overview  Group

The FloodFill function fills an area of the display surface with the current brush. The area is assumed to be bounded as specified by the crFill parameter.

The FloodFill function is included only for compatibility with earlier versions of Windows. For Win32-based applications, use the ExtFloodFill function with FLOODFILLBORDER specified.

BOOL FloodFill(

HDC  hdc,	// handle of device context
int  nXStart,	// x-coordinate, where fill begins
int  nYStart,	// y-coordinate, where fill begins
COLORREF  crFill	// fill color
);
Parameters

hdc

Identifies a device context.

nXStart

Specifies the logical x-coordinate of the point where filling is to begin.

nYStart

Specifies the logical y-coordinate of the point where filling is to begin.

crFill

Specifies the color of the boundary or of the area to be filled.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Following are reasons this function might fail:

•	The fill could not be completed.

•	The given point has the boundary color specified by the crFill parameter.

•	The given point lies outside the current clipping region — that is, it is not visible on the device.

See Also

ExtFloodFill


FlushConsoleInputBuffer
FlushConsoleInputBuffer  QuickInfo  Overview  Group

The FlushConsoleInputBuffer function flushes the console input buffer. All input records currently in the input buffer are discarded.

BOOL FlushConsoleInputBuffer(

HANDLE  hConsoleInput	// handle of console input buffer
);
Parameters

hConsoleInput

Identifies the console input buffer. The handle must have GENERIC_WRITE access.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

GetNumberOfConsoleInputEvents, PeekConsoleInput, ReadConsoleInput, WriteConsoleInput


FlushFileBuffers
FlushFileBuffers  QuickInfo  Overview  Group

The FlushFileBuffers function clears the buffers for the specified file and causes all buffered data to be written to the file.

BOOL FlushFileBuffers(

HANDLE  hFile	// open handle to file whose buffers are to be flushed
);
Parameters

hFile

An open file handle. The function flushes this file's buffers. The file handle must have GENERIC_WRITE access to the file.

If hFile is a handle to a communications device, the function only flushes the transmit buffer.

If hFile is a handle to the server end of a named pipe, the function does not return until the client has read all buffered data from the pipe.

Windows NT: The function fails if hFile is a handle to console output. That is because console output is not buffered. The function returns FALSE, and GetLastError returns ERROR_INVALID_HANDLE.

Windows 95: The function does nothing if hFile is a handle to console output. That is because console output is not buffered. The function returns TRUE, but it does nothing.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The WriteFile and WriteFileEx functions typically write data to an internal buffer that the operating system writes to disk on a regular basis. The FlushFileBuffers function writes all of the buffered information for the specified file to disk.

You can pass the same file handle used with the _lread, _lwrite, _lcreat, and related functions to FlushFileBuffers.

See Also

_lread, _lwrite, _lcreat, WriteFile, WriteFileEx


FlushInstructionCache
FlushInstructionCache  QuickInfo  Overview  Group

The FlushInstructionCache function flushes the instruction cache for the specified process.

BOOL FlushInstructionCache(

HANDLE  hProcess,	// handle of process with cache to flush
LPCVOID  lpBaseAddress,	// address of region to flush
DWORD  dwSize	// length of region to flush
);
Parameters

hProcess

Identifies the process that has an instruction cache to flush.

lpBaseAddress

Points to the base of the region to be flushed. This parameter can be NULL.

dwSize

Specifies the length of the region to be flushed if the lpBaseAddress parameter is not NULL.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Windows 95: The FlushInstructionCache function always returns TRUE. windows 95 supports single-processor machines only.


FlushViewOfFile
FlushViewOfFile  QuickInfo  Overview  Group

The FlushViewOfFile function writes to the disk a byte range within a mapped view of a file.

BOOL FlushViewOfFile(

LPCVOID  lpBaseAddress,	// start address of byte range to flush
DWORD  dwNumberOfBytesToFlush	// number of bytes in range
);
Parameters

lpBaseAddress

Points to the base address of the byte range to be flushed to the disk representation of the mapped file.

dwNumberOfBytesToFlush

Specifies the number of bytes to flush.

If dwNumberOfBytesToFlush is zero, the file is flushed from the base address to the end of the mapping.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Flushing a range of a mapped view causes any dirty pages within that range to be written to the disk. Dirty pages are those whose contents have changed since the file view was mapped.

See Also

MapViewOfFile, UnmapViewOfFile


FMExtensionProc
FMExtensionProc  QuickInfo  Overview  Group

The FMExtensionProc function is an application-defined callback function that processes menu commands and messages sent to a File Manager extension dynamic-link library (DLL).

LONG WINAPI FMExtensionProc(

HWND  hwnd,	// handle of extension window
WORD  wEvent,	// menu-item identifier, or message
LONG  lParam	// additional message information
);
Parameters

hwnd

Identifies the File Manager window. An extension DLL should use this handle to specify the owner for any dialog box or message box that the DLL may display and to send request messages to File Manager.

wEvent

Specifies the message. This parameter can be one of the following values:

Value	Meaning
1−99	The user selected the menu item identified by this number.
FMEVENT_INITMENU	User selected the extension's menu.
FMEVENT_LOAD	File Manager is loading the extension DLL.
FMEVENT_SELCHANGE	Selection changed in File Manager's directory window or in Search Results window.
FMEVENT_UNLOAD	File Manager is unloading the extension DLL.
FMEVENT_USER_REFRESH	User chose the Refresh command from the Window menu.
lParam

Specifies 32 bits of additional message-specific information.

Return Value

The callback function should return the result of the message processing. The actual return value depends on the message processed.

Remarks

Whenever File Manager calls the FMExtensionProc function, it waits to refresh its directory windows (for changes in the file system) until after the function returns. This allows the extension to perform large numbers of file operations without excessive repainting by File Manager. It is not necessary for the extension to send the FM_REFRESH_WINDOWS message to notify File Manager to repaint its windows.


FoldString
FoldString  QuickInfo  Overview  Group

The FoldString function maps one string to another, performing a specified transformation option.

int FoldString(

DWORD  dwMapFlags,	// mapping transformation options
LPCTSTR  lpSrcStr,	// address of source string
int  cchSrc,	// size of source string, in bytes or characters
LPTSTR  lpDestStr,	// address of destination buffer
int  cchDest	// size of destination buffer, in bytes or characters
);
Parameters

dwMapFlags

A set of bit flags that indicate the type of transformation to be used during mapping. This value can be a combination of the following bit-flag constants:

Option	Meaning
MAP_FOLDCZONE	Fold compatibility zone characters into standard Unicode equivalents. For information about compatibility zone characters, see the following Remarks section.
MAP_FOLDDIGITS	Map all digits to Unicode characters 0 through 9.
MAP_PRECOMPOSED	Map accented characters to precomposed characters, in which the accent and base character are combined into a single character value. This value cannot be combined with MAP_COMPOSITE.
MAP_COMPOSITE	Map accented characters to composite characters, in which the accent and base character are represented by two character values. This value cannot be combined with MAP_PRECOMPOSED.
lpSrcStr

Points to the string to be mapped.

cchSrc

Specifies the size, in bytes (ANSI version) or characters (Unicode version), of the lpSrcStr buffer. If cchSrc is −1, lpSrcStr is assumed to be null-terminated, and the length is calculated automatically.

lpDestStr

Points to the buffer to store the mapped string.

cchDest

Specifies the size, in bytes (ANSI version) or characters (Unicode version), of the lpDestStr buffer. If cchDest is zero, the function returns the number of bytes or characters required to hold the mapped string, and the buffer pointed to by lpDestStr is not used.

Return Value

If the function succeeds, the return value is the number of bytes (ANSI version) or characters (Unicode version) written to the destination buffer, or if the cchDest parameter is zero, the number of bytes or characters required to hold the mapped string.

If the function fails, the return value is zero. To get extended error information, call GetLastError. GetLastError may return one of the following error codes:

ERROR_INSUFFICIENT_BUFFER
ERROR_INVALID_FLAGS
ERROR_INVALID_PARAMETER

Remarks

The mapped string is null-terminated if the source string is null-terminated.

The lpSrcStr and lpDestStr pointers must not be the same. If they are the same, the function fails and GetLastError returns ERROR_INVALID_PARAMETER.

The compatibility zone in Unicode consists of characters in the range 0xF900 through 0xFFEF that are assigned to characters from other character-encoding standards but are actually variants of characters that are already in Unicode. The compatibility zone is used to support round-trip mapping to these standards. Applications can use the MAP_FOLDCZONE flag to avoid supporting the duplication of characters in the compatibility zone.

See Also

LCMapString, CompareString


ForegroundIdleProc
ForegroundIdleProc  QuickInfo

The ForegroundIdleProc hook procedure is an application-defined callback function the system calls whenever the 32-bit foreground thread is about to become idle.

DWORD ForegroundIdleProc(

int  code,	// hook code
DWORD  wParam,	// not used
LONG  lParam	// not used
);
Parameters

code

Specifies whether the hook procedure must process the message. If code is HC_ACTION, the hook procedure must process the message. If code is less than zero, the hook procedure must pass the message to the CallNextHookEx function without further processing and should return the value returned by CallNextHookEx.

wParam

Not used.

lParam

Not used.

Remarks

An application installs this hook procedure by specifying the WH_FOREGROUNDIDLE hook type and the address of the hook procedure in a call to the SetWindowsHookEx function.

ForegroundIdleProc is a placeholder for the application-defined function name.

This is a thread-specific hook.

See Also

CallNextHookEx, SetWindowsHookEx


FormatMessage
FormatMessage  QuickInfo  Overview  Group

The FormatMessage function formats a message string. The function requires a message definition as input. The message definition can come from a buffer passed into the function. It can come from a message table resource in an already-loaded module. Or the caller can ask the function to search the system's message table resource(s) for the message definition. The function finds the message definition in a message table resource based on a message identifier and a language identifier. The function copies the formatted message text to an output buffer, processing any embedded insert sequences if requested.

DWORD FormatMessage(

DWORD  dwFlags,	// source and processing options
LPCVOID  lpSource,	// address of  message source
DWORD  dwMessageId,	// requested message identifier
DWORD  dwLanguageId,	// language identifier for requested message
LPTSTR  lpBuffer,	// address of message buffer
DWORD  nSize,	// maximum size of message buffer
va_list *  Arguments	// address of array of message inserts
);
Parameters

dwFlags

Contains a set of bit flags that specify aspects of the formatting process and how to interpret the lpSource parameter. The low-order byte of dwFlags specifies how the function handles line breaks in the output buffer. The low-order byte can also specify the maximum width of a formatted output line.

You can specify a combination of the following bit flags:

Value	Meaning
FORMAT_MESSAGE_ALLOCATE_BUFFER
	Specifies that the lpBuffer parameter is a pointer to a PVOID pointer, and that the nSize parameter specifies the minimum number of bytes (ANSI version) or characters (Unicode version) to allocate for an output message buffer. The function allocates a buffer large enough to hold the formatted message, and places a pointer to the allocated buffer at the address specified by lpBuffer. The caller should use the LocalFree function to free the buffer when it is no longer needed.
FORMAT_MESSAGE_IGNORE_INSERTS
	Specifies that insert sequences in the message definition are to be ignored and passed through to the output buffer unchanged. This flag is useful for fetching a message for later formatting. If this flag is set, the Arguments parameter is ignored.
FORMAT_MESSAGE_FROM_STRING
	Specifies that lpSource is a pointer to a null-terminated message definition. The message definition may contain insert sequences, just as the message text in a message table resource may. Cannot be used with FORMAT_MESSAGE_FROM_HMODULE or FORMAT_MESSAGE_FROM_SYSTEM.
FORMAT_MESSAGE_FROM_HMODULE
	Specifies that lpSource is a module handle containing the message-table resource(s) to search. If this lpSource handle is NULL, the current process's application image file will be searched. Cannot be used with FORMAT_MESSAGE_FROM_STRING.
FORMAT_MESSAGE_FROM_SYSTEM
	Specifies that the function should search the system message-table resource(s) for the requested message. If this flag is specified with FORMAT_MESSAGE_FROM_HMODULE, the function searches the system message table if the message is not found in the module specified by lpSource. Cannot be used with FORMAT_MESSAGE_FROM_STRING. If this flag is specified, an application can pass the result of the GetLastError function to retrieve the message text for a system-defined error.
FORMAT_MESSAGE_ARGUMENT_ARRAY
	Specifies that the Arguments parameter is not a va_list structure, but instead is just a pointer to an array of 32-bit values that represent the arguments.
The low-order byte of dwFlags can specify the maximum width of a formatted output line. Use the FORMAT_MESSAGE_MAX_WIDTH_MASK constant and bitwise Boolean operations to set and retrieve this maximum width value.

The following table shows how FormatMessage interprets the value of the low-order byte.

Value	Meaning
0	There are no output line width restrictions. The function stores line breaks that are in the message definition text into the output buffer.
a nonzero value other than FORMAT_MESSAGE_MAX_WIDTH_MASK	The nonzero value is the maximum number of characters in an output line. The function ignores regular line breaks in the message definition text. The function never splits a string delimited by white space across a line break. The function stores hard-coded line breaks in the message definition text into the output buffer. Hard-coded line breaks are coded with the %n escape sequence.
FORMAT_MESSAGE_MAX_WIDTH_MASK	The function ignores regular line breaks in the message definition text. The function stores hard-coded line breaks in the message definition text into the output buffer. The function generates no new line breaks.
lpSource

Specifies the location of the message definition. The type of this parameter depends upon the settings in the dwFlags parameter.

dwFlags Setting	Parameter Type
FORMAT_MESSAGE_FROM_HMODULE	lpSource is an hModule of the module that contains the message table to search.
FORMAT_MESSAGE_FROM_STRING	lpSource is an LPTSTR that points to unformatted message text. It will be scanned for inserts and formatted accordingly.
If neither of these flags is set in dwFlags, then lpSource is ignored.

dwMessageId

Specifies the 32-bit message identifier for the requested message. This parameter is ignored if dwFlags includes FORMAT_MESSAGE_FROM_STRING.

dwLanguageId

Specifies the 32-bit language identifier for the requested message. This parameter is ignored if dwFlags includes FORMAT_MESSAGE_FROM_STRING.

lpBuffer

Points to a buffer for the formatted (and null-terminated) message. If dwFlags includes FORMAT_MESSAGE_ALLOCATE_BUFFER, the function allocates a buffer using the LocalAlloc function, and places the address of the buffer at the address specified in lpBuffer.

nSize

If the FORMAT_MESSAGE_ALLOCATE_BUFFER flag is not set, this parameter specifies the maximum number of bytes (ANSI version) or characters (Unicode version) that can be stored in the output buffer. If FORMAT_MESSAGE_ALLOCATE_BUFFER is set, this parameter specifies the minimum number of bytes or characters to allocate for an output buffer.

Arguments

Points to an array of 32-bit values that are used as insert values in the formatted message. %1 in the format string indicates the first value in the Arguments array; %2 indicates the second argument; and so on.

The interpretation of each 32-bit value depends on the formatting information associated with the insert in the message definition. The default is to treat each value as a pointer to a null-terminated string.

By default, the Arguments parameter is of type va_list*, which is a language- and implementation-specific data type for describing a variable number of arguments. If you do not have a pointer of type va_list*, then specify the FORMAT_MESSAGE_ARGUMENT_ARRAY flag and pass a pointer to an array of 32-bit values; those values are input to the message formatted as the insert values.

Return Value

If the function succeeds, the return value is the number of bytes (ANSI version) or characters (Unicode version) stored in the output buffer, excluding the terminating null character.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

Each insert must have a corresponding element in the array pointed to by the Arguments parameter.

Within the message text, several escape sequences are supported for dynamically formatting the message. These escape sequences and their meanings are shown in the following table. All escape sequences start with the percent character (%).

Escape Sequence	Meaning
%0	Terminates a message text line without a trailing newline character. This escape sequence can be used to build up long lines or to terminate the message itself without a trailing newline character. It is useful for prompt messages.
%n!printf format string!	Identifies an insert. The value of n can be in the range 1 through 99. The printf format string (which must be bracketed by exclamation marks) is optional and defaults to !s! if not specified.
	The printf format string can contain the * specifier for either the precision or the width component. If * is specified for one component, the FormatMessage function uses insert %n+1; it uses %n+2 if * is specified for both components.
	Floating-point printf format specifiers  —  e, E, f, and g  —  are not supported. The workaround is to to use the sprintf function to format the floating-point number into a temporary buffer, then use that buffer as the insert string.
Any other nondigit character following a percent character is formatted in the output message without the percent character. Following are some examples:

Format string	Resulting output
%%	A single percent sign in the formatted message text.
%n	A hard line break when the format string occurs at the end of a line. This format string is useful when FormatMessage is supplying regular line breaks so the message fits in a certain width.
%space	A space in the formatted message text. This format string can be used to ensure the appropriate number of trailing spaces in a message text line.
%.	A single period in the formatted message text. This format string can be used to include a single period at the beginning of a line without terminating the message text definition.
%!	A single exclamation point in the formatted message text. This format string can be used to include an exclamation point immediately after an insert without its being mistaken for the beginning of a printf format string.
See Also

LoadString, LocalFree


FrameRect
FrameRect  QuickInfo  Overview  Group

The FrameRect function draws a border around the specified rectangle by using the specified brush. The width and height of the border are always one logical unit.

int FrameRect(

HDC  hDC,	// handle of device context
CONST RECT  * lprc,	// address of rectangle coordinates
HBRUSH  hbr	// handle of brush
);
Parameters

hDC

Identifies the device context in which the border is drawn.

lprc

Points to a RECT structure that contains the logical coordinates of the upper-left and lower-right corners of the rectangle.

hbr

Identifies the brush used to draw the border.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The brush identified by the hbr parameter must have been created by using the CreateHatchBrush, CreatePatternBrush, or CreateSolidBrush function, or retrieved by using the GetStockObject function.

If the bottom member of the RECT structure is less than or equal to the top member, or if the right member is less than or equal to the left member, the function does not draw the rectangle.

See Also

CreateHatchBrush, CreatePatternBrush, CreateSolidBrush, GetStockObject, RECT


FrameRgn
FrameRgn  QuickInfo  Overview  Group

The FrameRgn function draws a border around the specified region by using the specified brush.

BOOL FrameRgn(

HDC  hdc,	// handle of device context
HRGN  hrgn,	// handle of region to be framed
HBRUSH  hbr,	// handle of brush used to draw border
int  nWidth,	// width of region frame
int  nHeight	// height of region frame
);
Parameters

hdc

Identifies the device context.

hrgn

Identifies the region to be enclosed in a border. The region's coordinates are presumed to be in logical units.

hbr

Identifies the brush to be used to draw the border.

nWidth

Specifies the width, in logical units, of vertical brush strokes.

nHeight

Specifies the height, in logical units, of horizontal brush strokes.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

See Also

FillRgn, PaintRgn


FreeConsole
FreeConsole  QuickInfo  Overview  Group

The FreeConsole function detaches the calling process from its console.

BOOL FreeConsole(VOID)

Parameters

This function has no parameters.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

If other processes share the console, the console is not destroyed, but the calling process cannot refer to it.

A process can use FreeConsole to detach itself from its current console, and then it can call the AllocConsole function to create a new console.

See Also

AllocConsole


FreeDDElParam
FreeDDElParam  QuickInfo  Overview  Group

The FreeDDElParam function frees the memory specified by the lParam parameter of a posted DDE message. An application receiving a posted DDE message should call this function after it has used the UnpackDDElParam function to unpack the lParam value.

BOOL FreeDDElParam(

UINT  msg,	// posted DDE message
LONG  lParam	// lParam of message
);
Parameters

msg

Specifies the posted DDE message.

lParam

Specifies the lParam parameter of the posted DDE message.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

An application should call this function only for posted DDE messages.

This function frees the memory specified by the lParam parameter. It does not free the contents of lParam.

See Also

PackDDElParam, ReuseDDElParam, UnpackDDElParam


FreeEnvironmentStrings
FreeEnvironmentStrings  QuickInfo  Overview  Group

The FreeEnvironmentStrings function frees a block of environment strings.

BOOL FreeEnvironmentStrings(

LPTSTR  lpszEnvironmentBlock	// pointer to a block of environment strings
);
Parameters

lpszEnvironmentBlock

Pointer to a block of environment strings. The pointer to the block must be obtained by calling the GetEnvironmentStrings function.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

When GetEnvironmentStrings is called, it allocates memory for a block of environment strings. When the block is no longer needed, it should be freed by calling FreeEnvironmentStrings.

See Also

GetEnvironmentStrings


FreeLibrary
FreeLibrary  QuickInfo  Overview  Group

The FreeLibrary function decrements the reference count of the loaded dynamic-link library (DLL) module. When the reference count reaches zero, the module is unmapped from the address space of the calling process and the handle is no longer valid. This function supersedes the FreeModule function.

BOOL FreeLibrary(

HMODULE  hLibModule	// handle of loaded library module
);
Parameters

hLibModule

Identifies the loaded library module. The LoadLibrary or GetModuleHandle function returns this handle.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Each process maintains a reference count for each loaded library module. This reference count is incremented each time LoadLibrary is called and is decremented each time FreeLibrary is called. A DLL module loaded at process initialization due to load-time dynamic linking has a reference count of one. This count is incremented if the same module is loaded by a call to LoadLibrary.

Before unmapping a library module, the system enables the DLL to detach from the process by calling the DLL's DllEntryPoint function, if it has one, with the DLL_PROCESS_DETACH value. Doing so gives the DLL an opportunity to clean up resources allocated on behalf of the current process. After the entry-point function returns, the library module is removed from the address space of the current process.

Calling FreeLibrary does not affect other processes using the same library module.

See Also

DllEntryPoint, FreeLibraryAndExitThread, FreeModule, GetModuleHandle, LoadLibrary


FreeLibraryAndExitThread
FreeLibraryAndExitThread  QuickInfo  Overview  Group

The FreeLibraryAndExitThread function decrements the reference count of a loaded dynamic-link library (DLL) by one, and then calls ExitThread to terminate the calling thread. The function does not return.

The FreeLibraryAndExitThread function gives threads that are created and executed within a dynamic-link library an opportunity to safely unload the DLL and terminate themselves.

VOID FreeLibraryAndExitThread(

HMODULE  hLibModule,	// dynamic-link library whose reference count is to decrement
DWORD  dwExitCode	// exit code for thread
);
Parameters

hLibModule

Specifies the dynamic-link library module whose reference count the function decrements.

dwExitCode

Specifies the exit code for the calling thread.

Return Value

The function has no return value. The function does not return. Invalid hLibModule handles are ignored.

Remarks

The FreeLibraryAndExitThread function is implemented as:

    FreeLibrary(hLibModule);

    ExitThread(dwExitCode);

Refer to the reference pages for FreeLibrary and ExitThread for further information on those functions.

See Also

FreeLibrary, ExitThread, DisableThreadLibraryCalls


FreeModule
FreeModule  QuickInfo  Overview  Group

The FreeModule function is obsolete.

This function is provided only for compatibility with 16-bit versions of Windows. Win32-based applications should use the FreeLibrary function.


FreePrinterNotifyInfo
FreePrinterNotifyInfo  Overview  Group

The FreePrinterNotifyInfo function frees a system-allocated buffer that was returned by the FindNextPrinterChangeNotification function.

BOOL FreePrinterNotifyInfo(

PPRINTER_NOTIFY_INFO  pPrinterNotifyInfo	// pointer to a PRINTER_NOTIFY_INFO buffer
);
Parameters

pPrinterNotifyInfo

Pointer to a PRINTER_NOTIFY_INFO buffer returned from a call to the FindNextPrinterChangeNotification function. FreePrinterNotifyInfo deallocates this buffer.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

FindNextPrinterChangeNotification, PRINTER_NOTIFY_INFO


FreeProcInstance
FreeProcInstance  QuickInfo  Overview  Group

The FreeProcInstance function is obsolete.

This function is provided only for compatibility with 16-bit versions of Windows. Win32-based applications should not use this function; it has no meaning in the 32-bit environment.


FreeResource
FreeResource  QuickInfo  Overview  Group

The FreeResource function is obsolete. It is provided to simplify porting of 16-bit Windows-based applications. It is not necessary for Win32-based applications to free resources loaded by using the LoadResource function.

See Also

LoadResource, LockResource


FreeSelector
FreeSelector  Overview  Group

The FreeSelector function has been deleted.


FreeSid
FreeSid  QuickInfo  Overview  Group

The FreeSid function frees a security identifier (SID) previously allocated by using the AllocateAndInitializeSid function.

PVOID FreeSid(

PSID  pSid	// address of SID to free
);
Parameters

pSid

Points to the SID structure to free.

Return Value

This function does not return a value.

See Also

AllocateAndInitializeSid, SID


FSCTL_DISMOUNT_VOLUME
FSCTL_DISMOUNT_VOLUME  QuickInfo  Overview  Group

dwIoControlCode = FSCTL_DISMOUNT_VOLUME;   // operation code

lpvInBuffer = NULL; // address of input buffer; not used; must be NULL

cbInBuffer = 0;     // size of input buffer; not used; must be zero

lpvOutBuffer ;      // address of output buffer; not used; must be NULL

cbOutBuffer ;       // size of output buffer; not used; must be zero

lpcbBytesReturned ; // address of actual bytes of output; not used; must be NULL

The FSCTL_DISMOUNT_VOLUME DeviceIoControl operation dismounts a volume.

Parameters

lpvInBuffer

Points to an input buffer. Not used with this operation. Set to NULL.

cbInBuffer

Specifies the size, in bytes, of the buffer pointed to by lpvInBuffer. Not used with this operation. Set to zero.

lpvOutBuffer

Points to an output buffer. Not used with this operation. Set to NULL.

cbOutBuffer

Specifies the size, in bytes, of the buffer pointed to by lpvOutBuffer. Not used with this operation. Set to zero.

lpcbBytesReturned

Points to a DWORD that receives the actual size, in bytes, of the data stored into lpvOutBuffer. Not used with this operation. Set to NULL.

Return Value

If the operation succeeds, DeviceIoControl returns TRUE.

If the operation fails, DeviceIoControl returns FALSE. To get extended error information, call GetLastError.

Remarks

The hDevice handle passed to DeviceIoControl must be a handle to a volume, opened for direct access. An application can obtain such a handle by calling CreateFile with lpszName set to a string that looks like this:

\\.\X:

where X is a hard-drive partition letter, floppy disk drive, or CD-ROM drive. The application must also specify the FILE_SHARE_READ and FILE_SHARE_WRITE flags in the fdwShareMode parameter of CreateFile.

If the specified volume is locked, the operation fails.

A dismounted volume has the following properties:

•	There are no open files.

•	The operating system does not "know" about the volume.

The operating system tries to mount an unmounted volume as soon as any attempt is made to access it. For example, a call to GetLogicalDrives triggers the operating system to mount any unmounted volumes.

Dismounting a volume is useful whenever a volume needs to disappear for a while. For example, an application that changes a volume's file system from FAT to NTFS might follow these steps:

1.	Open the volume

2.	Lock the volume

3.	Format the volume

4.	Unlock the volume

5.	Dismount the volume

6.	Close the volume handle

A dismounting operation removes the volume from the FAT file system's "awareness." When the operating system mounts the volume, it appears as an NTFS volume.

See Also

CreateFile, DeviceIoControl, ExitThread, GetLogicalDrives


FSCTL_GET_COMPRESSION [New - Windows NT]
FSCTL_GET_COMPRESSION  QuickInfo

[New - Windows NT]

dwIoControlCode = FSCTL_GET_COMPRESSION;   // operation code

lpvInBuffer = NULL; // address of input buffer; not used; must be NULL

cbInBuffer = 0;     // size of input buffer; not used; must be zero

lpvOutBuffer ;      // address of output buffer

cbOutBuffer ;       // size of output buffer

lpcbBytesReturned ; // address of actual bytes of output

The FSCTL_GET_COMPRESSION DeviceIoControl operation obtains the current compression state of a file or directory on a volume whose file system supports per-stream compression.

Parameters

lpvInBuffer

Points to an input buffer. Not used with this operation. Set to NULL.

cbInBuffer

Specifies the size, in bytes, of the buffer pointed to by lpvInBuffer. Not used with this operation. Set to zero.

lpvOutBuffer

Points to a buffer that receives a USHORT indicating the current compression state of the file or directory.

The following values are defined:

Value	Meaning
COMPRESSION_FORMAT_NONE	The file or directory is not compressed.
COMPRESSION_FORMAT_LZNT1	The file or directory is compressed, using the LZNT1 compression format.
all other values	Reserved for future use.
cbOutBuffer

Specifies the size, in bytes, of the buffer pointed to by lpvOutBuffer. The buffer  must be large enough to contain one USHORT value.

lpcbBytesReturned

Points to a DWORD value that receives the actual size, in bytes, of the data stored into the buffer pointed to by lpvOutBuffer.

Return Value

If the operation succeeds, DeviceIoControl returns TRUE.

If the operation fails, DeviceIoControl returns FALSE. To get extended error information, call GetLastError.

Remarks

On this release, LZNT1 is the only compression algorithm implemented. Future releases may have additional compression methods.

COMPRESSION_FORMAT_DEFAULT is not a compression state so it is not included in the table under the lpvOutBuffer parameter. This value is only used with the FSCTL_SET_COMPRESSION operation

If the file system of the volume containing the specified file or directory does not support per-file or per-directory compression, the FSCTL_GET_COMPRESSION operation fails.

Windows NT version 3.51 supports file compression on volumes formatted with the NTFS file system.

You can set the compression state of a file or directory by using the FSCTL_SET_COMPRESSION DeviceIoControl operation. You can also compress or uncompress a file with that operation.

You can obtain the compression attribute of a file or directory by calling the GetFileAttributes function. The compression attribute indicates whether a file or directory is compressed. The compression state indicates whether a file or directory is compressed, and, if it is, the format of the compressed data.

See Also

DeviceIoControl, FSCTL_SET_COMPRESSION, GetFileAttributes


FSCTL_LOCK_VOLUME
FSCTL_LOCK_VOLUME  QuickInfo  Overview  Group

dwIoControlCode = FSCTL_LOCK_VOLUME;   // operation code

lpvInBuffer = NULL; // address of input buffer; not used; must be NULL

cbInBuffer = 0;     // size of input buffer; not used; must be zero

lpvOutBuffer ;      // address of output buffer; not used; must be NULL

cbOutBuffer ;       // size of output buffer; not used; must be zero

lpcbBytesReturned ; // address of actual bytes of output; not used; must be NULL

The FSCTL_LOCK_VOLUME DeviceIoControl operation locks a volume. A locked volume can be accessed only through handles to the file object (*hDevice) that locks the volume.

Parameters

lpvInBuffer

Points to an input buffer. Not used with this operation. Set to NULL.

cbInBuffer

Specifies the size, in bytes, of the buffer pointed to by lpvInBuffer. Not used with this operation. Set to zero.

lpvOutBuffer

Points to an output buffer. Not used with this operation. Set to NULL.

cbOutBuffer

Specifies the size, in bytes, of the buffer pointed to by lpvOutBuffer. Not used with this operation. Set to zero.

lpcbBytesReturned

Points to a DWORD that receives the actual size, in bytes, of the data stored in lpvOutBuffer. Not used with this operation. Set to NULL.

Return Value

If the operation succeeds, DeviceIoControl returns TRUE.

If the operation fails, DeviceIoControl returns FALSE. To get extended error information, call GetLastError.

Remarks

The hDevice handle passed to DeviceIoControl must be a handle to a volume, opened for direct access. An application can obtain such a handle by calling CreateFile with lpszName set to a string that looks like this:

\\.\X:

where X is a hard-drive partition letter, floppy disk drive, or CD-ROM drive. The application must also specify the FILE_SHARE_READ and FILE_SHARE_WRITE flags in the fdwShareMode parameter of CreateFile.

The FSCTL_LOCK_VOLUME operation fails if there are any open files on the volume. Conversely, success of this operation indicates there are no open files.

The operation is useful for applications that need exclusive access to a volume for a period of time—for example, disk utility programs.

A locked volume remains locked until one of the following occurs:

•	The application invokes the FSCTL_UNLOCK_VOLUME DeviceIoControl operation to unlock the volume.

•	The handle closes, either directly through CloseHandle, or indirectly when a process terminates.

The system flushes all cached data to the volume before locking it. For example, any data held in a lazy-write cache is written to the volume.

See Also

CloseHandle, CreateFile, DeviceIoControl, FSCTL_UNLOCK_VOLUME


FSCTL_SET_COMPRESSION [New - Windows NT]
FSCTL_SET_COMPRESSION  QuickInfo

[New - Windows NT]

dwIoControlCode = FSCTL_SET_COMPRESSION;   // operation code

lpvInBuffer ; 	        // address of input buffer

cbInBuffer ;         // size of input buffer

lpvOutBuffer = NULL; // address of output buffer; not used; must be NULL

cbOutBuffer = 0;     // size of output buffer; not used; must be zero

lpcbBytesReturned ;  // pointer to result of operation

The FSCTL_SET_COMPRESSION DeviceIoControl operation sets the compression state of a file or directory on a volume whose file system supports per-file and per-directory compression. You can use this operation to compress or uncompress a file or directory on such a volume.

Parameters

lpvInBuffer

Points to a buffer that contains a USHORT that specifies a new compression state for the file or directory.

The following values are defined:

Value	Meaning
COMPRESSION_FORMAT_NONE	Uncompress the file or directory.
COMPRESSION_FORMAT_DEFAULT	Compress the file or directory, using the default compression format.
COMPRESSION_FORMAT_LZNT1	Compress the file or directory, using the LZNT1 compression format.
all other values	Reserved for future use.
cbInBuffer

Specifies the size, in bytes, of the buffer pointed to by lpvInBuffer. The buffer must be large enough to contain one USHORT value.

lpvOutBuffer

Points to an output buffer. Not used with this operation. Set to NULL.

cbOutBuffer

Specifies the size, in bytes, of the buffer pointed to by lpvOutBuffer. Not used with this operation. Set to zero.

lpcbBytesReturned

Points to a DWORD that receives the result of the I/O control operation.

Return Value

If the operation succeeds, DeviceIoControl returns TRUE.

If the operation fails, DeviceIoControl returns FALSE. To get extended error information, call GetLastError.

Remarks

On this release, LZNT1 is the only compression algorithm implemented. As a result, LZNT1 will be used as the DEFAULT compression method. Future releases may have additional compression methods which may be used as the DEFAULT.

If the file system of the volume containing the specified file or directory does not support per-file or per-directory compression, the FSCTL_SET_COMPRESSION operation fails.

Windows NT release 3.51 supports file compression on volumes formatted with the NTFS file system.

The compression state change of the file or directory occurs synchronously with the call to DeviceIoControl.

You can obtain the compression state of a file or directory by using the FSCTL_GET_COMPRESSION DeviceIoControl operation.

You can obtain the compression attribute of a file or directory by calling the GetFileAttributes function. The compression attribute indicates whether a file or directory is compressed. The compression state indicates whether a file or directory is compressed and, if it is, the format of the compressed data.

See Also

DeviceIoControl, FSCTL_GET_COMPRESSION, GetFileAttributes


FSCTL_UNLOCK_VOLUME
FSCTL_UNLOCK_VOLUME  QuickInfo  Overview  Group

dwIoControlCode = FSCTL_UNLOCK_VOLUME;   // operation code

lpvInBuffer = NULL; // address of input buffer; not used; must be NULL

cbInBuffer = 0;     // size of input buffer; not used; must be zero

lpvOutBuffer ;      // address of output buffer; not used; must be NULL

cbOutBuffer ;       // size of output buffer; not used; must be zero

lpcbBytesReturned ; // address of actual bytes of output; not used; must be NULL

The FSCTL_UNLOCK_VOLUME DeviceIoControl operation unlocks a volume.

Parameters

lpvInBuffer

Points to an input buffer. Not used with this operation. Set to NULL.

cbInBuffer

Specifies the size, in bytes, of the buffer pointed to by lpvInBuffer. Not used with this operation. Set to zero.

lpvOutBuffer

Points to an output buffer. Not used with this operation. Set to NULL.

cbOutBuffer

Specifies the size, in bytes, of the buffer pointed to by lpvOutBuffer. Not used with this operation. Set to zero.

lpcbBytesReturned

Points to a DWORD that receives the actual size, in bytes, of the data stored in lpvOutBuffer. Not used with this operation. Set to NULL.

Return Value

If the operation succeeds, DeviceIoControl returns TRUE.

If the operation fails, DeviceIoControl returns FALSE. To get extended error information, call GetLastError.

Remarks

An application can call the FSCTL_LOCK_VOLUME DeviceIoControl operation to lock a volume.

The hDevice handle passed to DeviceIoControl must be a handle to a volume, opened for direct access. An application can obtain such a handle by calling CreateFile with lpszName set to a string that looks like this:

\\.\X:

where X is a hard-drive partition letter, floppy disk drive, or CD-ROM drive. The application must also specify the FILE_SHARE_READ and FILE_SHARE_WRITE flags in the fdwShareMode parameter of CreateFile.

See Also

CreateFile, DeviceIoControl, FSCTL_LOCK_VOLUME


GdiComment
GdiComment  QuickInfo  Overview  Group

The GdiComment function copies a comment from a buffer into a specified enhanced-format metafile.

BOOL GdiComment(

HDC  hdc,	// handle of a device context
UINT  cbSize,	// size of text buffer
CONST BYTE *  lpData	// address of text buffer
);
Parameters

hdc

Identifies an enhanced-metafile device context.

cbSize

Specifies the length of the comment buffer, in bytes.

lpData

Points to the buffer that contains the comment.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

A comment can include any kind of private information — for example, the source of a picture and the date it was created. A comment should begin with an application signature, followed by the data.

Comments should not contain application-specific or position-specific data. Position-specific data specifies the location of a record, and it should not be included because one metafile may be embedded within another metafile.

A public comment is a comment that begins with the comment signature identifier GDICOMMENT_IDENTIFIER. The following public comments are defined:

Comment	Description
GDICOMMENT_WINDOWS_METAFILE
	The GDICOMMENT_WINDOWS_METAFILE public comment contains a Windows-format metafile that is equivalent to an enhanced-format metafile. This comment is written only by the SetWinMetaFileBits function. The comment record, if given, follows the ENHMETAHEADER metafile record. The comment has the following form:
DWORD ident;         // This contains GDICOMMENT_IDENTIFIER.

DWORD iComment;      // This contains GDICOMMENT_WINDOWS_METAFILE.

DWORD nVersion;      // This contains the version number of the

                     // Windows-format metafile.

DWORD nChecksum;     // This is the additive DWORD checksum for

                     // the enhanced metafile.  The checksum

                     // for the enhanced metafile data including

                     // this comment record must be zero.

                     // Otherwise, the enhanced metafile has been

                     //  modified and the Windows-format

                     // metafile is no longer valid.

DWORD fFlags;        // This must be zero.

DWORD cbWinMetaFile; // This is the size, in bytes. of the

                     // Windows-format metafile data that follows.

GDICOMMENT_BEGINGROUP
	The GDICOMMENT_BEGINGROUP public comment identifies the beginning of a group of drawing records. It identifies an object within an enhanced metafile. The comment has the following form:
DWORD   ident;         // This contains GDICOMMENT_IDENTIFIER.

DWORD   iComment;      // This contains GDICOMMENT_BEGINGROUP.

RECTL   rclOutput;     // This is the bounding rectangle for the

                       // object in logical coordinates.

DWORD   nDescription;  // This is the number of characters in the

                       // optional Unicode description string that

                       // follows. This is zero if there is no

                       // description string.

GDICOMMENT_ENDGROUP
	The GDICOMMENT_ENDGROUP public comment identifies the end of a group of drawing records. The GDICOMMENT_BEGINGROUP comment and the GDICOMMENT_ENDGROUP comment must be included in a pair and may be nested. The comment has the following form:
DWORD   ident;       // This contains GDICOMMENT_IDENTIFIER.

DWORD   iComment;    // This contains GDICOMMENT_ENDGROUP.

GDICOMMENT_MULTIFORMATS
	The GDICOMMENT_MULTIFORMATS public comment allows multiple definitions of a picture to be included in an enhanced metafile. Using this comment, for example, an application can include an encapsulated PostScript definition as well as an enhanced metafile definition of a picture. When the record is played back, GDI selects and renders the first format recognized by the device. The comment has the following form:
DWORD   ident;          // This contains GDICOMMENT_IDENTIFIER.

DWORD   iComment;       // This contains GDICOMMENT_MULTIFORMATS.

RECTL   rclOutput;      // This is the bounding rectangle for the

                        // picture in logical coordinates.

DWORD   nFormats;       // This contains the number of formats in

                        // the comment.

EMRFORMAT aemrformat[1];// This is an array of EMRFORMAT structures

                        // in the order of preference.  The data

                        // for each format follows the last

                        // EMRFORMAT structure.

The EMRFORMAT structure has the following form:

typedef struct tagEMRFORMAT   {

    DWORD   dSignature;

    DWORD   nVersion;

    DWORD   cbData;

    DWORD   offData;

} EMRFORMAT;

See Also

CreateEnhMetaFile, EMRFORMAT, SetWinMetaFileBits


GdiFlush
GdiFlush  QuickInfo  Overview  Group

The GdiFlush function flushes the calling thread's current batch.

BOOL GdiFlush(VOID)

Parameters

This function has no parameters.

Return Value

If all functions in the current batch succeed, the return value is TRUE; otherwise, it is FALSE, indicating that at least one function returned an error.

Remarks

Batching enhances drawing performance by minimizing the amount of time needed to call GDI drawing functions that return Boolean values. The system accumulates the parameters for calls to these functions in the current batch and then calls the functions when the batch is flushed by any of the following means:

•	Calling the GdiFlush function

•	Reaching or exceeding the batch limit set by the GdiSetBatchLimit function

•	Filling the batching buffers

•	Calling any GDI function that does not return a Boolean value

The return value for GdiFlush applies only to the functions in the batch at the time GdiFlush is called. Errors that occur when the batch is flushed by any other means are never reported.

The GdiGetBatchLimit function returns the batch limit.

Note that the batch limit is maintained for each thread separately. In order to completely disable batching, call GdiSetBatchLimit(1) during the initialization of each thread.

An application should call GdiFlush before a thread goes away if there is a possibility that there are pending function calls in the graphics batch queue. The operating system does not execute such batched functions when a thread goes away.

A multithreaded application that serializes access to GDI objects with a mutex must ensure flushing the GDI batch queue by calling GdiFlush as each thread releases ownership of the GDI object. This prevents collisions of the GDI objects (device contexts, metafiles, and so on).

See Also

GdiGetBatchLimit, GdiSetBatchLimit


GdiGetBatchLimit
GdiGetBatchLimit  QuickInfo  Overview  Group

The GdiGetBatchLimit function returns the maximum number of function calls that can be accumulated in the calling thread's current batch. The system flushes the current batch whenever this limit is exceeded.

DWORD GdiGetBatchLimit(VOID)

Parameters

This function has no parameters.

Return Value

If the function succeeds, the return value is the batch limit.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

The batch limit is set by using the GdiSetBatchLimit function. Setting the limit to 1 effectively disables batching.

Only GDI drawing functions that return Boolean values can be batched; calls to any other GDI functions immediately flush the current batch. Exceeding the batch limit or calling the GdiFlush function also flushes the current batch.

When the system batches a function call, the function returns TRUE. The actual return value for the function is reported only if GdiFlush is used to flush the batch.

Note that the batch limit is maintained for each thread separately. In order to completely disable batching, call GdiSetBatchLimit(1) during the initialization of each thread.

See Also

GdiFlush, GdiSetBatchLimit


GdiSetBatchLimit
GdiSetBatchLimit  QuickInfo  Overview  Group

The GdiSetBatchLimit function sets the maximum number of functions that can be accumulated in the calling thread's current batch. The system flushes the current batch whenever this limit is exceeded.

DWORD GdiSetBatchLimit(

DWORD  dwLimit	// batch limit
);
Parameters

dwLimit

Specifies the batch limit to be set. A value of 0 sets the default limit. A value of 1 disables batching.

Return Value

If the function succeeds, the return value is the previous batch limit.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

Only GDI drawing functions that return Boolean values can be accumulated in the current batch; calls to any other GDI functions immediately flush the current batch. Exceeding the batch limit or calling the GdiFlush function also flushes the current batch.

When the system accumulates a function, the function returns TRUE to indicate it is in the batch. When the system flushes the current batch and executes the function for the second time, the return value is either TRUE or FALSE, depending on whether the function succeeds. This second return value is reported only if GdiFlush is used to flush the batch.

Note that the batch limit is maintained for each thread separately. In order to completely disable batching, call GdiSetBatchLimit(1) during the initialization of each thread.

See Also

GdiFlush, GdiGetBatchLimit


GenerateConsoleCtrlEvent
GenerateConsoleCtrlEvent  QuickInfo  Overview  Group

The GenerateConsoleCtrlEvent function sends a specified signal to a console process group that shares the console associated with the calling process.

BOOL GenerateConsoleCtrlEvent(

DWORD  dwCtrlEvent,	// signal to generate
DWORD  dwProcessGroupId	// process group to get signal
);
Parameters

dwCtrlEvent

Specifies the type of signal to generate. One of the following values is specified:

Value	Meaning
CTRL_C_EVENT	Generates a CTRL+C signal.
CTRL_BREAK_EVENT	Generates a CTRL+BREAK signal.
dwProcessGroupId

Specifies the identifier of the process group that receives the signal. A process group is created when the CREATE_NEW_PROCESS_GROUP flag is specified in a call to the CreateProcess function. The process identifier of the new process is also the process group identifier of a new process group. The process group includes all processes that are descendants of the root process. Only those processes in the group that share the same console as the calling process receive the signal. In other words, if a process in the group creates a new console, that process does not receive the signal, nor do its descendants.

If this parameter is zero, the signal is generated in all processes that share the console of the calling process.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

GenerateConsoleCtrlEvent causes the control handler functions of processes in the target group to be called. All console processes have a default handler function that calls the ExitProcess function. A console process can use the SetConsoleCtrlHandler function to install or remove other handler functions.

SetConsoleCtrlHandler can also enable an inheritable attribute that causes the calling process to ignore CTRL+C signals. If GenerateConsoleCtrlEvent sends a CTRL+C signal to a process for which this attribute is enabled, the handler functions for that process are not called. CTRL+BREAK signals always cause the handler functions to be called.

See Also

CreateProcess, ExitProcess, SetConsoleCtrlHandler


GetAce
GetAce  QuickInfo  Overview  Group

The GetAce function obtains a pointer to an ACE in an ACL.

An ACE is an access control entry. An ACL is an access control list.

BOOL GetAce(

PACL  pAcl,	// address of access-control list
DWORD  dwAceIndex,	// index of ACE to retrieve
LPVOID  *pAce	// address of pointer to ACE
);
Parameters

pAcl

Points to an ACL structure containing the ACE to be retrieved.

dwAceIndex

Specifies the ACE to which a pointer is retrieved. A value of 0 corresponds to the first ACE in the ACL, 1 to the second ACE, and so on.

pAce

Points to a pointer the function sets to the address of the ACE.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

ACL, AddAccessAllowedAce, AddAccessDeniedAce, AddAce, AddAuditAccessAce, GetAclInformation, InitializeAcl


GetAclInformation
GetAclInformation  QuickInfo  Overview  Group

The GetAclInformation function retrieves information about an access-control list (ACL).

BOOL GetAclInformation(

PACL  pAcl,	// address of access-control list
LPVOID  pAclInformation,	// address of ACL information
DWORD  nAclInformationLength,	// size of ACL information
ACL_INFORMATION_CLASS  dwAclInformationClass	// class of requested information
);
Parameters

pAcl

Points to an ACL structure. The function retrieves information about this ACL.

pAclInformation

Points to a buffer receiving the requested information. The structure put into the buffer depends on the information class requested in the dwAclInformationClass parameter.

nAclInformationLength

Specifies the size, in bytes, of the buffer pointed to by the pAclInformation parameter.

dwAclInformationClass

Specifies an ACL_INFORMATION_CLASS enumerated type that gives the class of information requested. This parameter can be one of two values from this enumerated type. If the value is AclRevisionInformation, the function fills the buffer pointed to by the pAclInformation parameter with an ACL_REVISION_INFORMATION structure.

If the value is AclSizeInformation, the function fills the buffer pointed to by the pAclInformation parameter with an ACL_SIZE_INFORMATION structure.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

ACL, ACL_REVISION_INFORMATION, ACL_SIZE_INFORMATION, GetAce, InitializeAcl, IsValidAcl, SetAclInformation


GetACP
GetACP  QuickInfo  Overview  Group

The GetACP function retrieves the current ANSI code-page identifier for the system.

UINT GetACP(VOID)

Parameters

This function has no parameters.

Return Value

If the function succeeds, the return value is the current ANSI code-page identifier for the system, or a default identifier if no code page is current.

Remarks

Following are the ANSI code-page identifiers:

Identifier	Meaning
874	Thai
932	Japan
936	Chinese (PRC, Singapore)
949	Korean
950	Chinese (Taiwan, Hong Kong)
1200	Unicode (BMP of ISO 10646)
1250	Windows 3.1 Eastern European
1251	Windows 3.1 Cyrillic
1252	Windows 3.1 Latin 1 (US, Western Europe)
1253	Windows 3.1 Greek
1254	Windows 3.1 Turkish
1255	Hebrew
1256	Arabic
1257	Baltic
See Also

GetCPInfo, GetOEMCP


GetActiveWindow
GetActiveWindow  QuickInfo  Overview  Group

The GetActiveWindow function retrieves the window handle of the active window associated with the thread that calls the function.

HWND GetActiveWindow(VOID)

Parameters

This function has no parameters.

Return Value

If the function succeeds, the return value is the handle of the active window associated with the thread that calls the function. If the calling thread does not have an active window, the return value is NULL.

See Also

SetActiveWindow


GetAddressByName [New - Windows NT]
GetAddressByName  QuickInfo  Overview  Group

[New - Windows NT]

The GetAddressByName function queries a name space, or a set of default name spaces, in order to obtain network address information for a specified network service. This process is known as service name resolution. A network service can also use the function to obtain local address information that it can use with the bind function.

INT GetAddressByName(

DWORD  dwNameSpace,	// name space to query for service address information
LPGUID  lpServiceType,	// the type of the service
LPTSTR  lpServiceName,	// the name of the service
LPINT  lpiProtocols,	// points to array of protocol identifiers
DWORD  dwResolution,	// set of bit flags that specify aspects of name resolution
LPSERVICE_ASYNC_INFO  lpServiceAsyncInfo,	// reserved for future use, must be NULL
LPVOID  lpCsaddrBuffer,	// points to buffer to receive address information
LPDWORD  lpdwBufferLength,	// points to variable with address buffer size information
LPTSTR  lpAliasBuffer,	// points to buffer to receive alias information
LPDWORD  lpdwAliasBufferLength	// points to variable with alias buffer size information
);
Parameters

dwNameSpace

Specifies the name space, or a set of default name spaces, that the operating system will query for network address information.

Use one of the following constants to specify a name space:

Value	Name Space
NS_DEFAULT	A set of default name spaces. The function queries each name space within this set. The set of default name spaces typically includes all the name spaces installed on the system. System administrators, however, can exclude particular name spaces from the set. This is the value that most applications should use for dwNameSpace.
NS_DNS	The Domain Name System used in the Internet for host name resolution.
NS_NETBT	The NetBIOS over TCP/IP layer. All Windows NT systems register their computer names with NetBIOS. This name space is used to convert a computer name to an IP address that uses this registration. Note that NS_NETBT may access a WINS server to perform the resolution.
NS_SAP	The Netware Service Advertising Protocol. This may access the Netware bindery if appropriate. NS_SAP is a dynamic name space that allows registration of services.
NS_TCPIP_HOSTS	Lookup value in the <systemroot>\system32\drivers\etc\hosts file.
NS_TCPIP_LOCAL	Local TCP/IP name resolution mechanisms, including comparisons against the local host name and looks up host names and IP addresses in cache of host to IP address mappings.
Most calls to GetAddressByName should use the special value NS_DEFAULT. This lets a client get by with no knowledge of which name spaces are available on an internetwork. The system administrator determines name space access. Name spaces can come and go without the client having to be aware of the changes.

lpServiceType

Points to a globally unique identifier (GUID) that specifies the type of the network service. The header file SVCGUID.H includes definitions of several GUID service types, and macros for working with them.

lpServiceName

Points to a zero-terminated string that uniquely represents the service name. For example, "MY SNA SERVER".

Setting lpServiceName to NULL is the equivalent of setting dwResolution to RES_SERVICE. The function operates in its second mode, obtaining the local address to which a service of the specified type should bind. The function stores the local address within the LocalAddr member of the CSADDR_INFO structures stored into *lpCsaddrBuffer.

If dwResolution is set to RES_SERVICE, the function ignores the lpServiceName parameter.

If dwNameSpace is set to NS_DNS, *lpServiceName is the name of the host.

lpiProtocols

Points to a zero-terminated array of protocol identifiers. The function restricts a name resolution attempt to name space providers that offer these protocols. This lets the caller limit the scope of the search.

If lpiProtocols is NULL, the function obtains information on all available protocols.

dwResolution

A set of bit flags that specify aspects of the service name resolution process. The following bit flags are defined:

Value	Meaning
RES_SERVICE	If this flag is set, the function obtains the address to which a service of the specified type should bind. This is the equivalent of setting lpServiceName to NULL. If this flag is clear, normal name resolution occurs.
RES_FIND_MULTIPLE	If this flag is set, the operating system performs an extensive search of all name spaces for the service. It will ask every appropriate name space to resolve the service name. If this flag is clear, the operating system stops looking for service addresses as soon as one is found.
RES_SOFT_SEARCH	This flag is valid if the name space supports multiple levels of searching. If this flag is valid and set, the operating system performs a simple and quick search of the name space. This is useful if an application only needs to obtain easy-to-find addresses for the service. If this flag is valid and clear, the operating system performs a more extensive search of the name space.
lplpServiceAsyncInfo

Reserved for future use; must be set to NULL.

lpCsaddrBuffer

Points to a buffer to receive one or more CSADDR_INFO data structures. The number of structures written to the buffer depends on the amount of information found in the resolution attempt. You should assume that multiple structures will be written, although in many cases there will only be one.

lpdwBufferLength

Points to a variable that, upon input, specifies the size, in bytes, of the buffer pointed to by lpCsaddrBuffer.

Upon output, this variable contains the total number of bytes required to store the array of CSADDR_INFO structures. If this value is less than or equal to the input value of *lpdwBufferLength, and the function is successful, this is the number of bytes actually stored in the buffer. If this value is greater than the input value of *lpdwBufferLength, the buffer was too small, and the output value of *lpdwBufferLength is the minimal required buffer size.

lpAliasBuffer

Points to a buffer to receive alias information for the network service.

If a name space supports aliases, the function stores an array of zero-terminated name strings into the buffer pointed to by lpAliasBuffer. There is a double zero-terminator at the end of the list. The first name in the array is the service's primary name. Names that follow are aliases. An example of a name space that supports aliases is DNS.

If a name space does not support aliases, it stores a double zero-terminator into the buffer.

This parameter is optional, and can be set to NULL.

lpdwAliasBufferLength

Points to a variable that, upon input, specifies the size, in bytes, of the buffer pointed to by lpAliasBuffer.

Upon output, this variable contains the total number of bytes required to store the array of name strings. If this value is less than or equal to the input value of *lpdwAliasBufferLength, and the function is successful, this is the number of bytes actually stored in the buffer. If this value is greater than the input value of *lpdwAliasBufferLength, the buffer was too small, and the output value of *lpdwAliasBufferLength is the minimal required buffer size.

If lpAliasBuffer is NULL, lpdwAliasBufferLength is meaningless and can also be NULL.

Return Value

If the function succeeds, the return value is the number of CSADDR_INFO data structures written to the buffer pointed to by lpCsaddrBuffer.

If the function fails, the return value is SOCKET_ERROR( − 1). To get extended error information, call GetLastError. GetLastError may return the following extended error value:

Value	Meaning
ERROR_INSUFFICIENT_BUFFER	The buffer pointed to by lpCsaddrBuffer was too small to receive all of the relevant CSADDR_INFO structures. Call the function with a buffer at least as large as the value returned in *lpdwBufferLength.
Remarks

This function is a more powerful version of the Windows Sockets function gethostbyname The GetAddressByName function works with multiple name services.

The GetAddressByName function lets a client obtain a Windows Sockets address for a network service. The client specifies the service of interest by its service type and service name.

Many name services support a default prefix or suffix that the name service provider considers when resolving service names. For example, in the DNS name space, if a domain is named "nt.microsoft.com", and "ftp millikan" is provided as input, the DNS software fails to resolve "millikan", but successfully resolves "millikan.nt.microsoft.com".

Note that the GetAddressByName function can search for a service address in two ways: within a particular name space, or within a set of default name spaces. Using a default name space, an administrator can specify that certain name spaces will be searched for service addresses only if specified by name. An administrator or name space setup program can also control the ordering of name space searches.

See Also

gethostbyname, CSADDR_INFO


GetArcDirection
GetArcDirection  QuickInfo  Overview  Group

The GetArcDirection function returns the current arc direction for the specified device context. Arc and rectangle functions use the arc direction.

int GetArcDirection(

HDC  hdc	// handle of device context
);
Parameters

hdc

Identifies the device context.

Return Value

If the function succeeds, the return value specifies the current arc direction. Following are the valid return values:

Value	Meaning
AD_COUNTERCLOCKWISE	Arcs and rectangles are drawn counterclockwise.
AD_CLOCKWISE	Arcs and rectangles are drawn clockwise.
If an error occurs, the return value is zero.

See Also

SetArcDirection


GetAspectRatioFilter
GetAspectRatioFilter  Overview  Group

The GetAspectRatioFilter function is not implemented in the Win32 API. Win32-based applications should use the GetAspectRatioFilterEx function.


GetAspectRatioFilterEx
GetAspectRatioFilterEx  QuickInfo  Overview  Group

The GetAspectRatioFilterEx function retrieves the setting for the current aspect-ratio filter.

BOOL GetAspectRatioFilterEx(

HDC  hdc,	// handle of device context
LPSIZE  lpAspectRatio	// address of aspect-ratio filter
);
Parameters

hdc

Identifies a device context.

lpAspectRatio

Points to a SIZE structure that receives the current aspect-ratio filter.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The aspect ratio is the ratio formed by the width and height of a pixel on a given device.

Windows provides a special filter, the aspect-ratio filter, to select fonts that were designed for a particular device. An application can specify that Windows should only retrieve fonts matching the specified aspect ratio by calling the SetMapperFlags function.

See Also

SetMapperFlags, SIZE


GetAsyncKeyState
GetAsyncKeyState  QuickInfo  Overview  Group

The GetAsyncKeyState function determines whether a key is up or down at the time the function is called, and whether the key was pressed after a previous call to GetAsyncKeyState.

SHORT GetAsyncKeyState(

int  vKey	// virtual-key code
);
Parameters

vKey

Specifies one of 256 possible virtual-key codes.

Windows NT: You can use left- and right-distinguishing constants to specify certain keys. See the Remarks section for further information.

Windows 95: Windows 95 does not support the left- and right-distinguishing constants available on Windows NT.

Return Value

If the function succeeds, the return value specifies whether the key was pressed since the last call to GetAsyncKeyState, and whether the key is currently up or down. If the most significant bit is set, the key is down, and if the least significant bit is set, the key was pressed after the previous call to GetAsyncKeyState. The return value is zero if a window in another thread or process currently has the keyboard focus.

Windows 95: Windows 95 does not support the left- and right-distinguishing constants. If you call GetAsyncKeyState on the Windows 95 platform with these constants, the return value is zero.

Remarks

You can use the virtual-key code constants VK_SHIFT, VK_CONTROL, and VK_MENU as values for the vKey parameter. This gives the state of the SHIFT, CTRL, or ALT keys without distinguishing between left and right.

Windows NT: You can use the following virtual-key code constants as values for vKey to distinguish between the left and right instances of those keys:

VK_LSHIFT	VK_RSHIFT
VK_LCONTROL	VK_RCONTROL
VK_LMENU	VK_RMENU
These left- and right-distinguishing constants are only available when you call the GetKeyboardState, SetKeyboardState, GetAsyncKeyState, GetKeyState, and MapVirtualKey functions.

Windows 95: Windows 95 does not support the left- and right-distinguishing constants, and returns 0 when you use these constants.

The GetAsyncKeyState function works with mouse buttons. However, it checks on the state of the physical mouse buttons, not on the logical mouse buttons that the physical buttons are mapped to. For example, the call GetAsyncKeyState(VK_LBUTTON) always returns the state of the left physical mouse button, which may mapped to the left or right logical mouse button. You can determine the system's current mapping of physical mouse buttons to logical mouse buttons by calling

GetSystemMetrics(SM_SWAPBUTTON)

which returns TRUE if the mouse buttons have been swapped.

See Also

GetKeyboardState, GetKeyState, GetSystemMetrics, MapVirtualKey, SetKeyboardState


GetAtomHandle
GetAtomHandle  Overview  Group

The GetAtomHandle function is not implemented in the Win32 API. This function is provided for compatibility with 16-bit versions of Windows. Win32-based applications should use the GetAtomName function.


GetAtomName
GetAtomName  QuickInfo  Overview  Group

The GetAtomName function retrieves a copy of the character string associated with the specified local atom. This function replaces the GetAtomHandle function.

UINT GetAtomName(

ATOM  nAtom,	// atom identifying character string
LPTSTR  lpBuffer,	// address of buffer for atom string
int  nSize	// size of buffer
);
Parameters

nAtom

Specifies the local atom that identifies the character string to be retrieved.

lpBuffer

Points to the buffer for the character string.

nSize

Specifies the size, in characters, of the buffer.

Return Value

If the function succeeds, the return value is the length of the string copied to the buffer, in characters, not including the terminating null character.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

The string returned for an integer atom (an atom created by the MAKEINTATOM macro) is a null-terminated string in which the first character is a pound sign (#) and the remaining characters represent the unsigned integer originally passed to MAKEINTATOM.

See Also

AddAtom, DeleteAtom, FindAtom, GlobalAddAtom, GlobalDeleteAtom, GlobalFindAtom, GlobalGetAtomName, MAKEINTATOM


GetBinaryType
GetBinaryType  QuickInfo  Overview  Group

The GetBinaryType function determines whether a file is executable, and if so, what type of executable file it is. That last property determines which subsystem an executable file runs under.

BOOL GetBinaryType (

LPCTSTR  lpApplicationName,	// points to fully qualified path of file to test
LPDWORD  lpBinaryType	// points to variable to receive binary type information
);
Parameters

lpApplicationName

Points to a null-terminated string that contains the fully qualified path of the file whose binary type the function shall determine.

lpBinaryType

Points to a variable to receive information about the executable type of the file specified by lpApplicationName. The function adjusts a set of bit flags in this variable. The following bit flag constants are defined:

Value	Description
SCS_32BIT_BINARY	A Win32-based application
SCS_DOS_BINARY	An MS-DOS − based application
SCS_OS216_BINARY	A 16-bit OS/2-based application
SCS_PIF_BINARY	A PIF file that executes an MS-DOS − based application
SCS_POSIX_BINARY	A POSIX − based application
SCS_WOW_BINARY	A 16-bit Windows-based application
Return Value

If the file is executable, the return value is TRUE. The function sets the variable pointed to by lpBinaryType to indicate the file's executable type.

If the function is not executable, or if the function fails, the return value is FALSE.


GetBitmapBits
GetBitmapBits  QuickInfo  Overview  Group

The GetBitmapBits function copies the bitmap bits of a specified bitmap into a buffer.

The GetBitmapBits function is not implemented in the Win32 API. This function is provided for compatibility with 16-bit versions of Windows. Win32-based applications should use the GetDIBits function.

LONG GetBitmapBits(

HBITMAP  hbmp,	// handle to bitmap
LONG  cbBuffer,	// number of bytes to copy to buffer
LPVOID  lpvBits	// address of buffer for bitmap bits
);
Parameters

hbmp

Identifies the bitmap of interest.

cbBuffer

Specifies the number of bytes to be copied.

lpvBits

Points to a buffer to receive the bitmap bits. This is stored as an array of byte values.

Return Value

If the function succeeds, the return value is the actual number of bytes in the bitmap.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

The bits in the destination buffer must be word-aligned. In other words, the buffer must begin at an even address in memory.

See Also

GetDIBits


GetBitmapDimension
GetBitmapDimension  Overview  Group

The GetBitmapDimension function is not implemented in the Win32 SDK. This function is provided for compatibility with 16-bit versions of Windows. Win32-based applications should use the GetBitmapDimensionEx function.


GetBitmapDimensionEx
GetBitmapDimensionEx  QuickInfo  Overview  Group

The GetBitmapDimensionEx function retrieves the dimensions of a bitmap. The retrieved dimensions must have been set by the SetBitmapDimensionEx function. The GetMapDimensionEx function replaces the GetMapDimension function.

BOOL GetBitmapDimensionEx(

HBITMAP  hBitmap,	// handle of bitmap
LPSIZE  lpDimension	// address of structure receiving dimensions
);
Parameters

hBitmap

Identifies the bitmap.

lpDimension

Points to a SIZE structure to receive the bitmap dimensions.

Return Value

If the function was successful, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The function returns a data structure that contains fields for the height and width of the bitmap. If those dimensions have not yet been set, the structure that is returned will have zeroes in those fields.

See Also

SetBitmapDimensionEx, SIZE


GetBkColor
GetBkColor  QuickInfo  Overview  Group

The GetBkColor function returns the current background color for the specified device context.

COLORREF GetBkColor(

HDC  hdc	// handle of device context
);
Parameters

hdc

Identifies the device context whose background color is to be returned.

Return Value

If the function succeeds, the return value is a COLORREF value for the current background color.

If the function fails, the return value is CLR_INVALID.

See Also

GetBkMode, SetBkColor


GetBkMode
GetBkMode  QuickInfo  Overview  Group

The GetBkMode function returns the current background mix mode for a specified device context. The background mix mode of a device context affects text, hatched brushes, and pen styles that are not solid lines.

int GetBkMode(

HDC  hdc	// handle to device context of interest
);
Parameters

hdc

Identifies the device context whose background mode is to be returned.

Return Value

If the function succeeds, the return value specifies the current background mix mode, either OPAQUE or TRANSPARENT.

If the function fails, the return value is zero.

See Also

GetBkColor, SetBkMode


GetBoundsRect
GetBoundsRect  QuickInfo  Overview  Group

The GetBoundsRect function obtains the current accumulated bounding rectangle for a specified device context.

Windows maintains an accumulated bounding rectangle for each application. An application can retrieve and set this rectangle.

UINT GetBoundsRect(

HDC  hdc,	// handle to device context of interest
LPRECT  lprcBounds,	// points to structure to receive bounding rectangle
UINT  flags	// specifies function options
);
Parameters

hdc

Identifies the device context whose bounding rectangle the function will return.

lprcBounds

Points to the RECT structure that will receive the current bounding rectangle. The application's rectangle is returned in logical coordinates, and the Windows rectangle is returned in screen coordinates.

flags

Specifies aspects of how the GetBoundsRect function will operate on a given call. This parameter can be the following value:

Value	Meaning
DCB_RESET	Clears the bounding rectangle after returning it. If this flag is not set, the bounding rectangle will not be cleared.
Return Value

The return value specifies the state of the accumulated bounding rectangle; it can be one of the following values:

Value	Meaning
0	An error occurred. The given device context handle is invalid.
DCB_DISABLE	Boundary accumulation is off.
DCB_ENABLE	Boundary accumulation is on.
DCB_RESET	The bounding rectangle is empty.
DCB_SET	The bounding rectangle is not empty.
Remarks

The DCB_SET value is a combination of the bit values DCB_ACCUMULATE and DCB_RESET. Applications that check the DCB_RESET bit to determine whether the bounding rectangle is empty must also check the DCB_ACCUMULATE bit. The bounding rectangle is empty only if the DCB_RESET bit is 1 and the DCB_ACCUMULATE bit is 0.

See Also

SetBoundsRect


GetBrushOrg

The GetBrushOrg function is not implemented in the Win32 API. This function is provided for compatibility with 16-bit versions of Windows. Win32-based applications should use the GetBrushOrgEx function.


GetBrushOrgEx
GetBrushOrgEx  QuickInfo  Overview  Group

The GetBrushOrgEx function retrieves the current brush origin for the specified device context. This function replaces the GetBrushOrg function.

BOOL GetBrushOrgEx(

HDC  hdc,	// handle of device context
LPPOINT  lppt	// address of structure of coordinates
);
Parameters

hdc

Identifies the device context.

lppt

Points to a POINT structure that receives the brush origin, in device coordinates.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

A brush is a bitmap that Windows uses to paint the interiors of filled shapes.

The brush origin is a set of coordinates with values between 0 and 7, specifying the location of one pixel in the bitmap. The default brush origin coordinates are (0,0). For horizontal coordinates, the value 0 corresponds to the leftmost column of pixels; the value 7 corresponds to the rightmost column. For vertical coordinates, the value 0 corresponds to the uppermost row of pixels; value 7 corresponds to the lowermost row. When Windows positions the brush at the start of any painting operation, it maps the origin of the brush to the location in the window's client area specified by the brush origin. For example, if the origin is set to (2,3), Windows maps the origin of the brush (0,0) to the location (2,3) on the window's client area.

If an application uses a brush to fill the backgrounds of both a parent and a child window with matching colors, it may be necessary to set the brush origin after painting the parent window but before painting the child window.

Windows NT: The operating system automatically tracks the origin of all window-managed device contexts and adjusts their brushes as necessary to maintain an alignment of patterns on the surface.

Windows 95: Automatic tracking of the brush origin is not supported. Applications must use the UnrealizeObject, SetBrushOrgEx, and SelectObject functions to align the brush before using it.

See Also

POINT, SelectObject, SetBrushOrgEx, UnrealizeObject


GetCapture
GetCapture  QuickInfo  Overview  Group

The GetCapture function retrieves the handle of the window (if any) that has captured the mouse. Only one window at a time can capture the mouse; this window receives mouse input whether or not the cursor is within its borders.

HWND GetCapture(VOID)

Parameters

This function has no parameters.

Return Value

If the function succeeds, the return value is the handle of the capture window associated with the current thread. If no window in the thread has captured the mouse, the return value is NULL.

Remarks

A NULL return value does not mean no other thread or process in the system has captured the mouse; it just means the current thread has not captured the mouse.

See Also

ReleaseCapture, SetCapture


GetCaretBlinkTime
GetCaretBlinkTime  QuickInfo  Overview  Group

The GetCaretBlinkTime function returns the elapsed time, in milliseconds, required to invert the caret's pixels.

UINT GetCaretBlinkTime(VOID)

Parameters

This function has no parameters.

Return Value

If the function succeeds, the return value is the blink time, in milliseconds.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

See Also

SetCaretBlinkTime


GetCaretPos
GetCaretPos  QuickInfo  Overview  Group

The GetCaretPos function copies the caret's position, in client coordinates, to the specified POINT structure.

BOOL GetCaretPos(

LPPOINT  lpPoint	// address of structure to receive coordinates
);
Parameters

lpPoint

Points to the POINT structure that is to receive the client coordinates of the caret.

Return Value

If the function succeeds, the return value is TRUE

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The caret position is always given in the client coordinates of the window that contains the caret.

See Also

SetCaretPos, POINT


GetCharABCWidths
GetCharABCWidths  QuickInfo  Overview  Group

The GetCharABCWidths function retrieves the widths, in logical units, of consecutive characters in a given range from the current TrueType font. This function succeeds only with TrueType fonts.

BOOL GetCharABCWidths(

HDC  hdc,	// handle of device context
UINT  uFirstChar,	// first character in range to query
UINT  uLastChar,	// last character in range to query
LPABC  lpabc	// address of character-width structure
);
Parameters

hdc

Identifies the device context.

uFirstChar

Specifies the first character in the group of consecutive characters from the current font.

uLastChar

Specifies the last character in the group of consecutive characters from the current font.

lpabc

Points to an array of ABC structures that receive the character widths when the function returns. This array must contain at least as many ABC structures as there are characters in the range specified by the uFirstChar and uLastChar parameters.

Return Value

If the function succeeds, the return value is TRUE

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The TrueType rasterizer provides ABC character spacing after a specific point size has been selected. "A" spacing is the distance added to the current position before placing the glyph. "B" spacing is the width of the black part of the glyph. "C" spacing is the distance added to the current position to provide white space to the right of the glyph. The total advanced width is given by A+B+C.

When the GetCharABCWidths function retrieves negative "A" or "C" widths for a character, that character includes underhangs or overhangs.

To convert the ABC widths to font design units, an application should use the value stored in the otmEMSquare member of a OUTLINETEXTMETRIC structure. This value can be retrieved by calling the GetOutlineTextMetrics function.

The ABC widths of the default character are used for characters outside the range of the currently selected font.

To retrieve the widths of characters in non-TrueType fonts, applications should use the GetCharWidth function.

See Also

GetCharWidth, GetOutlineTextMetrics, OUTLINETEXTMETRIC, ABC


GetCharABCWidthsFloat
GetCharABCWidthsFloat  QuickInfo  Overview  Group

The GetCharABCWidthsFloat function retrieves the widths, in logical units, of consecutive characters in a specified range from the current font.

BOOL GetCharABCWidthsFloat(

HDC  hdc,	// handle of device context
UINT  iFirstChar,	// first character in range to query
UINT  iLastChar,	// last character in range to query
LPABCFLOAT  lpABCF	// address of character-width structure
);
Parameters

hdc

Identifies the device context.

iFirstChar

Specifies the code point of the first character in the group of consecutive characters where the ABC widths are sought.

iLastChar

Specifies the code point of the last character in the group of consecutive characters where the ABC widths are sought. This range is inclusive. An error is returned if the specified last character precedes the specified first character.

lpABCF

Points to an application-defined buffer with an array of ABCFLOAT structures to receive the character widths when the function returns.

Return Value

If the function succeeds, the return value is TRUE

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Unlike the GetCharABCWidths function that returns widths only for TrueType fonts, the GetCharABCWidthsFloat function retrieves widths for any font. The widths returned by this function are in the IEEE floating-point format.

If the current world-to-device transformation is not identified, the returned widths may be noninteger values, even if the corresponding values in the device space are integers.

"A" spacing is the distance added to the current position before placing the glyph. "B" spacing is the width of the black part of the glyph. "C" spacing is the distance added to the current position to provide white space to the right of the glyph. The total advanced width is given by A+B+C.

The ABC spaces are measured along the character base line of the selected font.

The ABC widths of the default character are used for characters outside the range of the currently selected font.

See Also

ABCFLOAT, GetCharABCWidths, GetCharWidth, GetCharWidthFloat


GetCharacterPlacement [New - Windows 95]
GetCharacterPlacement  QuickInfo  Overview  Group

[New - Windows 95]

The GetCharacterPlacement function retrieves information about a character string, such as character widths, caret positioning, ordering within the string, and glyph rendering. The type of information returned depends on the dwFlags parameter and is based on the currently selected font in the given display context. The function copies the information to the specified GCP_RESULTS structure or to one or more arrays specified by the structure.

DWORD GetCharacterPlacement(

HDC  hdc,	// handle to device context
LPCTSTR  lpString,	// pointer to string
int  nCount,	// number of characters in string
int  nMaxExtent,	// maximum extent for displayed string
LPGCP_RESULTS  *lpResults,	// pointer to buffer for placement result
DWORD  dwFlags	// placement flags
);
Parameters

hdc

Identifies the device context.

lpString

Points to the character string to process.

nCount

Specifies the number of characters in the string.

nMaxExtent

Specifies the maximum extent (in logical units) to which the string is processed. Characters that, if processed, would exceed this extent are ignored. Computations for any required ordering or glyph arrays apply only to the included characters. This parameter is used only if the GCP_MAXEXTENT value is given in the dwFlags parameter. As the function processes the input string, each character and its extent is added to the output, extent, and other arrays only if the total extent has not yet exceeded the maximum. Once the limit is reached, processing will stop.

lpResults

Points to a GCP_RESULTS structure that receives the results of the function.

dwFlags

Specifies how to process the string into the required arrays. This parameter can be one or more of the following values:

Value	Meaning
GCP_CLASSIN	Specifies that the lpClass array contains preset classifications for characters. The classifications may be the same as on output. If the particular classification for a character is not known, the corresponding location in the array must be set to zero. for more information about the classifications, see GCP_RESULTS. This is useful only if GetFontLanguageInfo returned the GCP_REORDER flag.
GCP_DIACRITIC	Determines how diacritics in the string are handled. If this value is not set, diacritics are treated as zero-width characters. For example, a Hebrew string may contain diacritics, but you may not want to display them.  Use GetFontLanguageInfo to determine whether a font supports diacritics. If it does, you can use or not use the GCP_DIACRITIC flag in the call to GetCharacterPlacement, depending on the needs of your application.
GCP_DISPLAYZWG	For languages that need reordering or different glyph shapes depending on the positions of the characters within a word, nondisplayable characters often appear in the codepage. For example, in the Hebrew codepage, there are Left-To-Right and Right-To-Left markers, to help determine the final positioning of characters within the output strings. Normally these are not displayed and are removed from the lpGlyphs and lpDx arrays. You can use the GCP_DISPLAYZWG flag to display these characters.
GCP_GLYPHSHAPE	Specifies that some or all characters in the string are to be displayed using shapes other than the standard shapes defined in the currently selected font for the current code page. Some languages, such as Arabic, cannot support glyph creation unless this value is given. As a general rule, if GetFontLanguageInfo returns this value for a string, this value must be used with GetCharacterPlacement.
GCP_JUSTIFY	Adjusts the extents in the lpDx array so that the string length is the same as nMaxExtent. GCP_JUSTIFY may only be used in conjunction with GCP_MAXEXTENT.
GCP_JUSTIFYIN	Specifies that the lpDx array contains justification weights on input. Normally, a justification weight can be either 0 or 1, where 1 indicates that the width of the given character can be adjusted for justification. For languages in which GetFontLanguageInfo returns the GCP_KASHIDA flag, the justification weight can be one of the GCP_ARAJUST_* values.
GCP_KASHIDA	Use Kashidas as well as, or instead of, adjusted extents to modify the length of the string so that it is equal to the value given by nMaxExtent. In the lpDx array, a Kashida is indicated by a negative justification index. GCP_KASHIDA may be used only in conjunction with GCP_JUSTIFY and only if the font (and language) support Kashidas. Use GetFontLanguageInfo to determine whether the current font supports Kashidas. Using Kashidas to justifiy the string can result in the number of glyphs required being greater than the number of characters in the input string. Because of this, when Kashidas are used, the application cannot assume that setting the arrays to be the size of the input string will be sufficient. (The maximum possible will be approximately dxPageWidth/dxAveCharWidth, where dxPageWidth is the width of the document and dxAveCharWidth is the average character width as returned from a GetTextMetrics call). Note that just because GetFontLanguageInfo returns the GCP_KASHIDA flag does not mean that it has to be used in the call to GetCharacterPlacement, just that the option is available.
GCP_LIGATE	Use ligations wherever characters ligate. A ligation occurs where one glyph is used for two or more characters. For example, the letters "a" and "e" can ligate to "æ". For this to be used, however , both the language support and the font must support the required glyphs (the example given will NOT be processed by default in English).  Use GetFontLanguageInfo to determine whether the current font supports ligation. If it does and a specific maximum is required for the number of characters that will ligate, set the number in the first element of the lpGlyphs array. If normal ligation is required, set this value to zero. If GCP_LIGATE is not given, no ligation will take place. See GCP_RESULTS for more information. If the GCP_REORDER value is usually required for the character set but is not given, the output will be meaningless unless the string being passed in is already in visual ordering (that is, the result that gets put into lpGcpResults->lpOutString in one call to GetCharacterPlacement is the input string of a second call).  Note that just because GetFontLanguageInfo returns the GCP_LIGATE flag does not mean that it has to be used in the call to GetCharacterPlacement, just that the option is available.
GCP_MAXEXTENT	Compute extents of the string only as long as the resulting extent, in logical units, does not exceed the values given by the nMaxExtent parameter.
GCP_NEUTRALOVERRIDE	Certain languages only. Override the normal handling of neutrals and treat them as strong characters that match the strings reading order. Useful only with the GCP_REORDER flag.
GCP_NUMERICOVERRIDE	Certain languages only. Override the normal handling of numerics and treat them as strong characters that match the strings reading order. Useful only with the GCP_REORDER flag.
GCP_NUMERICSLATIN	Arabic/Thai only. Use standard Latin glyphs for numbers and override the system default. To determine if this option is available in the language of the font, use GetStringTypeEx to see if the language supports more than one number format.
GCP_NUMERICSLOCAL	Arabic/Thai only. Use local glyphs for numeric characters and override the system default. To determine if this option is available in the language of the font, use GetStringTypeEx to see if the language supports more than one number format.
GCP_REORDER	Reorder the string. Use for languages that are not SBCS and left-to-right reading order. If this value is not given, the string is assumed to be in display order already.  If this flag is set for Semitic languages and the lpClass array is used, the first two elements of the array are used to specify the reading order beyond the bounds of the string. GCP_CLASS_PREBOUNDRTL and GCP_CLASS_PREBOUNDLTR can be used to set the order. If no preset order is required, set the values to zero. These values can be combined with other values if theGCPCLASSIN flag is set. If the GCP_REORDER value is not given, the lpString parameter is taken to be visual ordered for languages where this is used, and the lpOutString and lpOrder fields are ignored. Use GetFontLanguageInfo to determine whether the current font supports reordering.
GCP_SYMSWAPOFF	Semitic languages only. Specifies that swappable characters are not reset. For example, in a right-to-left string, the '(' and ')' are not reversed.
GCP_USEKERNING	Use kerning pairs in the font (if any) when creating the widths arrays. Use GetFontLanguageInfo to determine whether the current font supports kerning pairs. Note that just because GetFontLanguageInfo returns the GCP_USEKERNING flag does not mean that it has to be used in the call to GetCharacterPlacement, just that the option is available. Most TrueType fonts have a kerning table, but you do not have to use it.
It is recommended that an application use the GetFontLanguageInfo function to determine whether the GCP_DIACRITIC, GCP_DBCS, GCP_USEKERNING, GCP_LIGATE, GCP_REORDER, GCP_GLYPHSHAPE, and GCP_KASHIDA values are valid for the currently selected font. If not valid, GetCharacterPlacement ignores the value.

The GCP_NODIACRITICS value is no longer defined and should not be used.

Return Value

If the function succeeds, the return value is the same as the return value from GetTextExtentPoint32, the width and height of the string.

If the function fails, the return value is zero.

Remarks

GetCharacterPlacement ensures that an application can correctly process text regardless of the international setting and type of fonts available. Applications use this function before using the ExtTextOut function and in place of the GetTextExtentPoint32 function (and occasionally in place of the GetCharWidth32 and GetCharABCWidths functions).

Using GetCharacterPlacement to retrieve intercharacter spacing and index arrays is not always necessary unless justification or kerning is required. For non-Latin fonts, applications can improve the speed at which the ExtTextOut function renders text by using GetCharacterPlacement to retrieve the intercharacter spacing and index arrays before calling ExtTextOut. This is especially useful when rendering the same text repeatedly or when using intercharacter spacing to position the caret. If the lpGlyphs output array is used in the call to ExtTextOut, the ETO_GLYPH_INDEX flag must be set.

GetCharacterPlacement checks the lpOrder, lpDx, lpCaretPos, lpOutString, and lpGlyphs members of the GCP_RESULTS structure and fills the corresponding arrays if these members are not set to NULL. If GetCharacterPlacement cannot fill an array, it sets the corresponding member to NULL. To ensure retrieval of valid information, the application is responsible for setting the member to a valid address before calling the function and for checking the value of the member after the call. If the GCP_JUSTIFY or GCP_USEKERNING values are given, the lpDx and/or lpCaretPos members must have valid addresses. Also, the lpDx member must have a valid address if GCP_JUSTIFYIN is given.

When computing justification, if the trailing characters in the string are spaces, the function reduces the length of the string and removes the spaces prior to computing the justification. If the array consists of only spaces, the function returns an error.

See Also

ExtTextOut, GCP_RESULTS, GetCharABCWidths, GetCharWidth32, GetFontLanguageInfo, GetStringTypeEx, GetTextExtentPoint32, GetTextMetrics


GetCharWidth
GetCharWidth  QuickInfo  Overview  Group

The GetCharWidth function retrieves the widths, in logical coordinates, of consecutive characters in a specified range from the current font.

GetCharWidth is maintained for compatibility with 16-bit versions of Windows. Win32-based applications should call the GetCharWidth32 function, which provides more accurate results.

BOOL GetCharWidth(

HDC  hdc,	// handle of device context
UINT  iFirstChar,	// first character in range to query
UINT  iLastChar,	// last character in range to query
LPINT  lpBuffer	// address of buffer for widths
);
Parameters

hdc

Identifies the device context.

iFirstChar

Specifies the first character in the group of consecutive characters.

iLastChar

Specifies the last character in the group of consecutive characters, which must not precede the specified first character.

lpBuffer

Points to a buffer to receive the widths.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The range is inclusive; that is, the returned widths include the widths of the characters specified by the iFirstChar and iLastChar parameters.

If a character does not exist in the current font, it is assigned the width of the default character.

See Also

GetCharABCWidths, GetCharABCWidthsFloat, GetCharWidth32, GetCharWidthFloat


GetCharWidth32
GetCharWidth32  QuickInfo  Overview  Group

The GetCharWidth32 function retrieves the widths, in logical coordinates, of consecutive characters in a specified range from the current font. This function supersedes the GetCharWidth function.

BOOL GetCharWidth32(

HDC  hdc,	// handle of device context
UINT  iFirstChar,	// first character in range to query
UINT  iLastChar,	// last character in range to query
LPINT  lpBuffer	// address of buffer for widths
);
Parameters

hdc

Identifies the device context.

iFirstChar

Specifies the first character in the group of consecutive characters.

iLastChar

Specifies the last character in the group of consecutive characters, which must not precede the specified first character.

lpBuffer

Points to a buffer to receive the widths.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The range is inclusive; that is, the returned widths include the widths of the characters specified by the iFirstChar and iLastChar parameters.

If a character does not exist in the current font, it is assigned the width of the default character.

See Also

GetCharABCWidths, GetCharABCWidthsFloat, GetCharWidth, GetCharWidthFloat


GetCharWidthFloat
GetCharWidthFloat  QuickInfo  Overview  Group

The GetCharWidthFloat function retrieves the fractional widths of consecutive characters in a specified range from the current font.

BOOL GetCharWidthFloat(

HDC  hdc,	// handle of device context
UINT  iFirstChar,	// first-character code point
UINT  iLastChar,	// last-character code point
PFLOAT  pxBuffer	// address of buffer that receives width-values
);
Parameters

hdc

Identifies the device context.

iFirstChar

Specifies the code point of the first character in the group of consecutive characters.

iLastChar

Specifies the code point of the last character in the group of consecutive characters.

pxBuffer

Points to a buffer to receive the character widths.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The returned widths are in the 32-bit IEEE floating-point format. (The widths are measured along the base line of the characters.)

If the iFirstChar parameter identifies the letter a and the iLastChar parameter identifies the letter z, GetCharWidthFloat retrieves the widths of all lowercase characters.

If a character does not exist in the current font, it is assigned the width of the default character.

See Also

GetCharABCWidths, GetCharABCWidthsFloat, GetCharWidth32


GetClassInfo
GetClassInfo  QuickInfo  Overview  Group

The GetClassInfo function retrieves information about a window class.

BOOL GetClassInfo(

HINSTANCE  hInstance,	// handle of application instance
LPCTSTR  lpClassName,	// address of class name string
LPWNDCLASS  lpWndClass	// address of structure for class data
);
Parameters

hInstance

Identifies the instance of the application that created the class. To retrieve information about classes defined by Windows (such as buttons or list boxes), set this parameter to NULL.

lpClassName

Points to a null-terminated string containing the class name. The name must be that of a preregistered class or a class registered by a previous call to the RegisterClass function. Alternatively, this parameter can be an integer atom. If so, it must be a global atom created by a previous call to the GlobalAddAtom function. The atom, a 16-bit value less than 0xC000, must be in the low-order word of lpClassName; the high-order word must be zero.

lpWndClass

Points to a WNDCLASS structure that receives the information about the class.

Return Value

If the function finds a matching class and successfully copies the data, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

GetClassLong, GetClassName, GetClassWord, GlobalAddAtom, RegisterClass, WNDCLASS


GetClassInfoEx
GetClassInfoEx  QuickInfo  Overview  Group

The GetClassInfoEx function retrieves information about a window class, including the handle of the small icon associated with the window class. GetClassInfo does not retrieve the handle of the small icon.

BOOL GetClassInfoEx(

HINSTANCE  hinst,	// handle of application instance
LPCTSTR  lpszClass,	// address of class name string
LPWNDCLASSEX  lpwcx,	// address of structure for class data
);
Parameters

hinst

Identifies the instance of the application that created the class. To retrieve information about classes defined by Windows (such as buttons or list boxes), set this parameter to NULL.

lpszClass

Points to a null-terminated string containing the class name. The name must be that of a preregistered class or a class registered by a previous call to the RegisterClass function. Alternatively, this parameter can be an integer atom. If this parameter is an integer atom, it must be a global atom created by a previous call to the GlobalAddAtom function. The atom, a 16-bit value less than 0xC000, must be in the low-order word of lpszClass; the high-order word must be zero.

lpwcx

Points to a WNDCLASSEX structure that receives the information about the class.

Windows NT: With Windows NT the hIconSm member of the WNDCLASSEX structure is always NULL.

Return Value

If the function finds a matching class and successfully copies the data, the return value is TRUE; otherwise, it is FALSE. To get extended error information, call GetLastError.

See Also

GetClassLong, GetClassName, GetClassWord, GlobalAddAtom, RegisterClassEx


GetClassLong
GetClassLong  QuickInfo  Overview  Group

The GetClassLong function retrieves the specified 32-bit (long) value from the WNDCLASS structure associated with the specified window.

DWORD GetClassLong(

HWND  hWnd,	// handle of window
int  nIndex	// offset of value to retrieve
);
Parameters

hWnd

Identifies the window and, indirectly, the class to which the window belongs.

nIndex

Specifies the 32-bit value to retrieve. To retrieve a 32-bit value from the extra class memory, specify the positive, zero-based byte offset of the value to be retrieved. Valid values are in the range zero through the number of bytes of extra class memory, minus four; for example, if you specified 12 or more bytes of extra class memory, a value of 8 would be an index to the third 32-bit integer. To retrieve any other value from the WNDCLASS structure, specify one of the following values:

Value	Action
GCW_ATOM	Retrieves an ATOM value that uniquely identifies the window class. This is the same atom that the RegisterClass function returns.
GCL_CBCLSEXTRA	Retrieves the size, in bytes, of the extra memory associated with the class.
GCL_CBWNDEXTRA	Retrieves the size, in bytes, of the extra window memory associated with each window in the class. For information on how to access this memory, see  GetWindowLong and GetWindowWord .
GCL_HBRBACKGROUND	Retrieves the handle of the background brush associated with the class.
GCL_HCURSOR	Retrieves the handle of the cursor associated with the class.
GCL_HICON	Retrieves the handle of the icon associated with the class.
GCL_HICONSM	Windows 95: Retrieves the handle of the small icon associated with the class. Windows NT: This constant is not valid for Windows NT.
GCL_HMODULE	Retrieves the handle of the module that registered the class.
GCL_MENUNAME	Retrieves the address of the menu name string. The string identifies the menu resource associated with the class.
GCL_STYLE	Retrieves the window-class style bits.
GCL_WNDPROC	Retrieves the address of the window procedure associated with the class.
Return Value

If the function succeeds, the return value is the requested 32-bit value.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

Reserve extra class memory by specifying a nonzero value in the cbClsExtra member of the WNDCLASS structure used with the RegisterClass function.

See Also

GetClassWord, GetWindowLong, GetWindowWord, RegisterClass, SetClassLong, SetClassWord, WNDCLASS


GetClassName
GetClassName  QuickInfo  Overview  Group

The GetClassName function retrieves the name of the class to which the specified window belongs.

int GetClassName(

HWND  hWnd,	// handle of window
LPTSTR  lpClassName,	// address of buffer for class name
int  nMaxCount	// size of buffer, in characters
);
Parameters

hWnd

Identifies the window and, indirectly, the class to which the window belongs.

lpClassName

Points to the buffer that is to receive the class name string.

nMaxCount

Specifies the length, in characters, of the buffer pointed to by the lpClassName parameter. The class name string is truncated if it is longer than the buffer.

Return Value

If the function succeeds, the return value is the number of characters copied to the specified buffer.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

See Also

FindWindow, GetClassInfo, GetClassLong, GetClassWord


GetClassWord
GetClassWord  QuickInfo  Overview  Group

The GetClassWord function retrieves the 16-bit (word) value at the specified offset into the extra class memory for the window class to which the specified window belongs.

WORD GetClassWord(

HWND  hWnd,	// handle of window
int  nIndex	// offset of value to retrieve
);
Parameters

hWnd

Identifies the window and, indirectly, the class to which the window belongs.

nIndex

Specifies the zero-based byte offset of the value to be retrieved. Valid values are in the range zero through the number of bytes of class memory, minus two; for example, if you specified 10 or more bytes of extra class memory, a value of eight would be an index to the fifth 16-bit integer. There is an additional valid value:

Value	Action
GCW_ATOM	Retrieves an ATOM value that uniquely identifies the window class. This is the same atom that the RegisterClass function returns.
GCW_HICONSM	Windows 95: Retrieves the handle of the small icon associated with the window. Windows NT: This constant is not valid for Windows NT.
Return Value

If the function succeeds, the return value is the requested 16-bit value.

If the function fails, the return value is otherwise, it is zero. To get extended error information, call GetLastError.

Remarks

Reserve extra class memory by specifying a nonzero value in the cbClsExtra member of the WNDCLASS structure used with the RegisterClass function.

Other than GCW_ATOM and GCW_HICONSM, the GCW_ values are obsolete in the Win32 API. You must use the GetClassLong function to retrieve the class values of a window.

See Also

GetClassLong, RegisterClass, SetClassLong, SetClassWord, WNDCLASS


GetClientRect
GetClientRect  QuickInfo  Overview  Group

The GetClientRect function retrieves the coordinates of a window's client area. The client coordinates specify the upper-left and lower-right corners of the client area. Because client coordinates are relative to the upper-left corner of a window's client area, the coordinates of the upper-left corner are (0,0).

BOOL GetClientRect(

HWND  hWnd,	// handle of window
LPRECT  lpRect	// address of structure for client coordinates
);
Parameters

hWnd

Identifies the window whose client coordinates are to be retrieved.

lpRect

Points to a RECT structure that receives the client coordinates. The left and top members are zero. The right and bottom members contain the width and height of the window.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is otherwise, it is FALSE. To get extended error information, call GetLastError.

See Also

GetWindowRect, RECT


GetClipboardData
GetClipboardData  QuickInfo  Overview  Group

The GetClipboardData function retrieves data from the clipboard in a specified format. The clipboard must have been opened previously.

HANDLE GetClipboardData(

UINT  uFormat	// clipboard format
);
Parameters

uFormat

Specifies a clipboard format. For a description of the clipboard formats, see the SetClipboardData function.

Return Value

If the function succeeds, the return value is the handle of a clipboard object in the specified format.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

An application can enumerate the available formats in advance by using the EnumClipboardFormats function.

The clipboard controls the handle that the GetClipboardData function returns, not the application. The application should copy the data immediately. The application cannot rely on being able to make long-term use of the handle. The application must not free the handle nor leave it locked.

The operating system performs implicit data format conversions between certain clipboard formats when an application calls the GetClipboardData function. For example, if the CF_OEMTEXT format is on the clipboard, a window can retrieve data in the CF_TEXT format. The format on the clipboard is converted to the requested format on demand. The following table shows the clipboard data type conversions that are available. Note that some of these automatic type conversions are not available on all platforms.

Clipboard Format	Conversion Format	Platform Support
CF_BITMAP	CF_DIB	Windows 95
CF_DIB	CF_BITMAP	Windows 95
CF_DIB	CF_PALETTE	Windows 95
CF_ENHMETAFILE	CF_METAFILEPICT	Windows 95, Windows NT
CF_METAFILEPICT	CF_ENHMETAFILE	Windows 95, Windows NT
CF_OEMTEXT	CF_TEXT	Windows 95, Windows NT
CF_OEMTEXT	CF_UNICODETEXT	Windows NT
CF_TEXT	CF_OEMTEXT	Windows 95, Windows NT
CF_TEXT	CF_UNICODETEXT	Windows NT
CF_UNICODETEXT	CF_OEMTEXT	Windows NT
CF_UNICODETEXT	CF_TEXT	Windows NT
If the operating system provides an automatic type conversion for a particular clipboard format, there is no advantage to placing the conversion format(s) on the clipboard.

If the system provides an automatic type conversion for a particular clipboard format, and you call EnumClipboardFormats to enumerate the clipboard data formats, the operating system first enumerates the format that is on the clipboard, followed by the formats to which it can be converted.

If the clipboard contains data in the CF_PALETTE format, the application should use the SelectPalette and RealizePalette functions to realize any other data in the clipboard against that logical palette.

See SetClipboardData for further information on specific clipboard data formats.

See Also

EnumClipboardFormats, SetClipboardData, RealizePalette, SelectPalette


GetClipboardFormatName
GetClipboardFormatName  QuickInfo  Overview  Group

The GetClipboardFormatName function retrieves from the clipboard the name of the specified registered format. The function copies the name to the specified buffer.

int GetClipboardFormatName(

UINT  format,	// clipboard format to retrieve
LPTSTR  lpszFormatName,	// address of buffer for name
int  cchMaxCount	// length of name string in characters
);
Parameters

format

Specifies the type of format to be retrieved. This parameter must not specify any of the predefined clipboard formats.

lpszFormatName

Points to the buffer that is to receive the format name.

cchMaxCount

Specifies the maximum length, in characters, of the string to be copied to the buffer. If the name exceeds this limit, it is truncated.

Return Value

If the function succeeds, the return value is the length, in characters, of the string copied to the buffer.

If the function fails, the return value is zero, indicating that the requested format does not exist or is predefined. To get extended error information, call GetLastError.

See Also

EnumClipboardFormats, RegisterClipboardFormat


GetClipboardOwner
GetClipboardOwner  QuickInfo  Overview  Group

The GetClipboardOwner function retrieves the window handle of the current owner of the clipboard.

HWND GetClipboardOwner(VOID)

Parameters

This function has no parameters.

Return Value

If the function succeeds, the return value is the handle of the window that owns the clipboard.

If the clipboard is not owned, the return value is NULL. To get extended error information, call GetLastError.

Remarks

The clipboard can still contain data even if the clipboard is not currently owned.

In general, the clipboard owner is the window that last placed data in clipboard. The EmptyClipboard function assigns clipboard ownership.

See Also

EmptyClipboard, GetClipboardViewer


GetClipboardViewer
GetClipboardViewer  QuickInfo  Overview  Group

The GetClipboardViewer function retrieves the handle of the first window in the clipboard viewer chain.

HWND GetClipboardViewer(VOID)

Parameters

This function has no parameters.

Return Value

If the function succeeds, the return value is the handle of the first window in the clipboard viewer chain.

If there is no clipboard viewer, the return value is NULL. To get extended error information, call GetLastError.

See Also

GetClipboardOwner, SetClipboardViewer


GetClipBox
GetClipBox  QuickInfo  Overview  Group

The GetClipBox function retrieves the dimensions of the tightest bounding rectangle that can be drawn around the current visible area on the device. The visible area is defined by the current clipping region or clip path, as well as any overlapping windows.

int GetClipBox(

HDC  hdc,	// handle of the device context
LPRECT  lprc	// address of structure with rectangle
);
Parameters

hdc

Identifies the device context.

lprc

Points to a RECT structure that is to receive the rectangle dimensions.

Return Value

If the function succeeds, the return value specifies the clipping box's complexity and can be any one of the following values:

Value	Meaning
NULLREGION	Region is empty.
SIMPLEREGION	Region is a single rectangle.
COMPLEXREGION	Region is more than one rectangle.
ERROR	An error occurred.
GetClipBox returns logical coordinates based on the given device context.

See Also

RECT


GetClipCursor
GetClipCursor  QuickInfo  Overview  Group

The GetClipCursor function retrieves the screen coordinates of the rectangular area to which the cursor is confined.

BOOL GetClipCursor(

LPRECT  lpRect	// address of structure for rectangle
);
Parameters

lpRect

Points to a RECT structure that receives the screen coordinates of the confining rectangle. The structure receives the dimensions of the screen if the cursor is not confined to a rectangle.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The cursor is a shared resource. If an application confines the cursor with the ClipCursor function, it must later release the cursor by using ClipCursor before relinquishing control to another application.

The calling process must have WINSTA_READATTRIBUTES access to the window station.

See Also

ClipCursor, GetCursorPos, RECT


GetClipRgn
GetClipRgn  QuickInfo  Overview  Group

The GetClipRgn function retrieves a handle identifying the current application-defined clipping region for the specified device context.

int GetClipRgn(

HDC  hdc,	// handle of device context
HRGN  hrgn	// handle of region
);
Parameters

hdc

Identifies the device context.

hrgn

Identifies an existing region before the function is called. After the function returns, this parameter identifies a copy of the current clipping region.

Return Value

If the function succeeds and there is no clipping region for the given device context, the return value is zero. If the function succeeds and there is a clipping region for the given device context, the return value is 1. If an error occurs, the return value is − 1.

Remarks

An application-defined clipping region is a clipping region identified by the SelectClipRgn function. It is not a clipping region created when the application calls the BeginPaint function.

If the function succeeds, the hrgn parameter identifies a copy of the current clipping region. Subsequent changes to this copy will not affect the current clipping region.

See Also

BeginPaint, SelectClipRgn


GetCodeHandle
GetCodeHandle  Overview  Group

The GetCodeHandle function is not implemented in the Win32 API. Win32-based applications should use the VirtualLock and VirtualUnlock functions.


GetCodeInfo
GetCodeInfo  Overview  Group

The GetCodeInfo function is not implemented in the WIN32 SDK. This function is included for compatability with 16-bit versions of Windows.


GetColorAdjustment
GetColorAdjustment  QuickInfo  Overview  Group

The GetColorAdjustment function retrieves the color adjustment values for the specified device context.

BOOL GetColorAdjustment(

HDC  hdc,	// handle of device context
LPCOLORADJUSTMENT  lpca	// address of COLORADJUSTMENT structure
);
Parameters

hdc

Identifies the device context.

lpca

Points to a COLORADJUSTMENT structure that receives the color adjustment values.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

SetColorAdjustment, COLORADJUSTMENT


GetColorSpace [New - Windows 95]
GetColorSpace  QuickInfo  Overview  Group

[New - Windows 95]

The GetColorSpace function retrieves the current handle to the logical color space from the specified device context.

HANDLE GetColorSpace(

HDC  hdc
);
Parameters

hdc

Handle to a device context.

Return Value

If the function succeeds, the return value is the current handle to the logical color space.

If the function fails, the return value is NULL.


GetCommandLine
GetCommandLine  QuickInfo  Overview  Group

The GetCommandLine function returns a pointer to the command-line string for the current process.

LPTSTR GetCommandLine(VOID)

Parameters

This function has no parameters.

Return Value

The return value is a pointer to the command-line string for the current process.

Remarks

Non-Unicode console processes written in C can use the argc and argv arguments to access the command-line arguments. The parameters of the command-line string, excluding the program name, are also available to such non-Unicode applications as a parameter of the WinMain function. The reason for the Unicode exclusion from these options is that WinMain, argc, and argv use the LPSTR data type for parameters, not the LPTSTR datatype.

See Also

CreateProcess, WinMain


GetCommConfig [New - Windows 95]
GetCommConfig  QuickInfo  Overview  Group

[New - Windows 95]

The GetCommConfig function gets the current configuration of a communications device.

BOOL GetCommConfig(

HANDLE hCommDev,	// handle of communications service
LPCOMMCONFIG lpCC,	// address of comm.configuration structure
LPDWORD lpdwSize	// address of size of buffer
);
Parameters

hCommDev

Identifies the open communications device.

lpCC

Points to the buffer that receives the COMMCONFIG structure.

lpdwSize

Points to a 32-bit variable that specifies the size, in bytes, of the buffer pointed to by lpCC. When the function returns, the variable contains the number of bytes copied if the function succeeds, or the number of bytes required if the buffer was too small.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, use the GetLastError function.

Remarks

An application can determine the maximum size of a device's configuration structure by calling the GetCommProperties function.

See Also

COMMCONFIG, GetCommProperties


GetCommMask
GetCommMask  QuickInfo  Overview  Group

The GetCommMask function retrieves the value of the event mask for a specified communications device.

BOOL GetCommMask(

HANDLE  hFile,	// handle of communications device
LPDWORD  lpEvtMask	// address of variable to get event mask
);
Parameters

hFile

Identifies the communications device. The CreateFile function returns this handle.

lpEvtMask

Points to the 32-bit variable to be filled with a mask of events that are currently enabled. This parameter can be one or more of the following values:

Value	Meaning
EV_BREAK	A break was detected on input.
EV_CTS	The CTS (clear-to-send) signal changed state.
EV_DSR	The DSR (data-set-ready) signal changed state.
EV_ERR	A line-status error occurred. Line-status errors are CE_FRAME, CE_OVERRUN, and CE_RXPARITY.
EV_EVENT1	An event of the first provider-specific type occured.
EV_EVENT2	An event of the second provider-specific type occured.
EV_PERR	A printer error occured.
EV_RING	A ring indicator was detected.
EV_RLSD	The RLSD (receive-line-signal-detect) signal changed state.
EV_RX80FULL	The receive buffer is 80 percent full.
EV_RXCHAR	A character was received and placed in the input buffer.
EV_RXFLAG	The event character was received and placed in the input buffer. The event character is specified in the device's DCB structure, which is applied to a serial port by using the SetCommState function.
EV_TXEMPTY	The last character in the output buffer was sent.
Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The GetCommMask function uses a 32-bit mask variable to indicate the set of events that can be monitored for a particular communications resource. A handle to the communications resource can be specified in a call to the WaitCommEvent function, which waits for one of the events to occur. To modify the event mask of a communications resource, use the SetCommMask function.

See Also

CreateFile, DCB, SetCommMask, WaitCommEvent,


GetCommModemStatus
GetCommModemStatus  QuickInfo  Overview  Group

The GetCommModemStatus function retrieves modem control-register values.

BOOL GetCommModemStatus(

HANDLE  hFile,	// handle of communications device
LPDWORD  lpModemStat	// address of control-register values
);
Parameters

hFile

Identifies the communications device. The CreateFile function returns this handle.

lpModemStat

Points to a 32-bit variable that specifies the current state of the modem control-register values. This parameter can be a combination of the following values:

Value	Meaning
MS_CTS_ON	The CTS (clear-to-send) signal is on.
MS_DSR_ON	The DSR (data-set-ready) signal is on.
MS_RING_ON	The ring indicator signal is on.
MS_RLSD_ON	The RLSD (receive-line-signal-detect) signal is on.
Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The GetCommModemStatus function is useful when you are using the WaitCommEvent function to monitor the CTS, RLSD, DSR, or ring indicator signals. To detect when these signals change state, use WaitCommEvent and then use GetCommModemStatus to determine the state after a change occurs.

The function fails if the hardware does not support the control-register values.

See Also

CreateFile, WaitCommEvent


GetCommProperties
GetCommProperties  QuickInfo  Overview  Group

The GetCommProperties function fills a buffer with information about the communications properties for a specified communications device.

BOOL GetCommProperties(

HANDLE  hFile,	// handle of communications device
LPCOMMPROP  lpCommProp	// address of communications properties structure
);
Parameters

hFile

Identifies the communications device. The CreateFile function returns this handle.

lpCommProp

Points to a COMMPROP structure in which the communications properties information is returned. This information can be used in subsequent calls to the SetCommState, SetCommTimeouts, or SetupComm function to configure the communications device.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The GetCommProperties function returns information from a device driver about the configuration settings that are supported by the driver.

See Also

COMMPROP, CreateFile, SetCommState, SetCommTimeouts, SetupComm


GetCommState
GetCommState  QuickInfo  Overview  Group

The GetCommState function fills in a device-control block (a DCB structure) with the current control settings for a specified communications device.

BOOL GetCommState(

HANDLE  hFile,	// handle of communications device
LPDCB  lpDCB	// address of device-control block structure
);
Parameters

hFile

Identifies the communications device. The CreateFile function returns this handle.

lpDCB

Points to the DCB structure in which the control settings information is returned.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

CreateFile, DCB, SetCommState


GetCommTimeouts
GetCommTimeouts  QuickInfo  Overview  Group

The GetCommTimeouts function retrieves the time-out parameters for all read and write operations on a specified communications device.

BOOL GetCommTimeouts(

HANDLE  hFile,	// handle of communications device
LPCOMMTIMEOUTS  lpCommTimeouts	// address of comm. time-outs structure
);
Parameters

hFile

Identifies the communications device. The CreateFile function returns this handle.

lpCommTimeouts

Points to a COMMTIMEOUTS structure in which the time-out information is returned.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

For more information about time-out values for communications devices, see the SetCommTimeouts function.

See Also

CreateFile, COMMTIMEOUTS, SetCommTimeouts


GetCompressedFileSize
GetCompressedFileSize  QuickInfo

The GetCompressedFileSize function obtains the compressed size, in bytes, of a specified file.

The GetCompressedFileSize function obtains the actual number of bytes of disk storage used to store a specified file. If the file is located on a volume that supports compression, and the file is compressed, the value obtained is the compressed size of the specified file. If the file is not located on a volume that supports compression, or if the file is not compressed, the value obtained is the actual file size, the same as the value returned by a call to GetFileSize.

DWORD GetCompressedFileSize(

LPCTSTR  lpFileName,	// pointer to name of file
LPDWORD  lpFileSizeHigh	// pointer to DWORD to receive high-order doubleword of file size
);
Parameters

lpFileName

Pointer to a null-terminated string that specifies the name of the file.

lpFileSizeHigh

Pointer to a DWORD variable that the function sets to the high-order doubleword of the compressed file size. The function's return value is the low-order doubleword of the compressed file size.

This parameter can be NULL if the high-order doubleword of the compressed file size is not needed. Files less than 4 gigabytes in size do not need the high-order doubleword.

Return Value

If the function succeeds, the return value is the low-order doubleword of the actual number of bytes of disk storage used to store the specified file, and if lpFileSizeHigh is non-NULL, the function puts the high-order doubleword of that actual value into the DWORD pointed to by that parameter. This is the compressed file size for compressed files, the actual file size for noncompressed files.

If the function fails, and lpFileSizeHigh is NULL, the return value is 0xFFFFFFFF. To get extended error information, call GetLastError.

If the function fails, and lpFileSizeHigh is non-NULL, the return value is 0xFFFFFFFF, and GetLastError returns a value other than NO_ERROR.

Remarks

Calling the GetCompressedFileSize function with the name of a nonseeking device, such as a pipe or a communications device, has no meaning.

Note that if the return value is 0xFFFFFFFF and lpFileSizeHigh is non-NULL, an application must call GetLastError to determine whether the function has succeeded or failed.

An application can determine whether a volume is compressed by calling GetVolumeInformation, then checking the status of the FS_VOL_IS_COMPRESSED flag in the DWORD pointed to by that function's lpFileSystemFlags parameter.

An application can determine whether a file is compressed by implementing the following pseudocode:

call GetVolumeInformation on the file's volume

if the file's volume is compressed

call GetCompressedFileSize on the file

call GetFileSize on the file

if the sizes don't match

the file is compressed

See Also

GetFileSize, GetVolumeInformation


GetComputerName
GetComputerName  QuickInfo  Overview  Group

The GetComputerName function retrieves the computer name of the current system. This name is established at system startup, when it is initialized from the registry.

BOOL GetComputerName(

LPTSTR  lpBuffer,	// address of name buffer
LPDWORD  nSize	// address of size of name buffer
);
Parameters

lpBuffer

Points to a buffer to receive the null-terminated character string containing the computer name.

nSize

Points to a variable that specifies the maximum size, in characters, of the buffer. This value should be large enough to contain MAX_COMPUTERNAME_LENGTH + 1 characters.

Return Value

If the function succeeds, the return value is TRUE and the variable at nSize contains the number of characters copied to the destination buffer, not including the terminating null character.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

SetComputerName


GetConsoleCP
GetConsoleCP  QuickInfo  Overview  Group

Windows NT: The GetConsoleCP function returns the identity of the input code page used by the console associated with the calling process. A console uses its input code page to translate keyboard input into the corresponding character value.

Windows 95: On Japanese and Korean implementations of Windows 95, the GetConsoleCP function returns the VM code page, because the OEM code page can be either 437 or DBCS. On all other implementations of Windows 95, the GetConsoleCP function returns the OEM code page.

UINT GetConsoleCP(VOID)

Parameters

This function has no parameters.

Return Value

The return value is a code that identifies the code page.

Remarks

A code page maps 256 character codes to individual characters. Different code pages include different special characters, typically customized for a language or a group of languages.

To set a console's input code page, use the SetConsoleCP function. To set and query a console's output code page, use the SetConsoleOutputCP and GetConsoleOutputCP functions.

See Also

GetConsoleOutputCP, SetConsoleCP, SetConsoleOutputCP


GetConsoleCursorInfo
GetConsoleCursorInfo  QuickInfo  Overview  Group

The GetConsoleCursorInfo function retrieves information about the size and visibility of the cursor for the specified console screen buffer.

BOOL GetConsoleCursorInfo(

HANDLE  hConsoleOutput,	// handle of console screen buffer
PCONSOLE_CURSOR_INFO  lpConsoleCursorInfo	// address of cursor information
);
Parameters

hConsoleOutput

Identifies a console screen buffer. The handle must have GENERIC_READ access.

lpConsoleCursorInfo

Points to a CONSOLE_CURSOR_INFO structure in which information about the console's cursor is returned.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

CONSOLE_CURSOR_INFO, SetConsoleCursorInfo


GetConsoleMode
GetConsoleMode  QuickInfo  Overview  Group

The GetConsoleMode function reports the current input mode of a console's input buffer or the current output mode of a console screen buffer.

BOOL GetConsoleMode(

HANDLE  hConsoleHandle,	// handle of console input or screen buffer
LPDWORD  lpMode	// current mode flags
);
Parameters

hConsoleHandle

Identifies a console input buffer or a screen buffer. The handle must have GENERIC_READ access.

lpMode

Points to a 32-bit variable that indicates the current mode of the specified buffer.

If the hConsoleHandle parameter is an input handle, the mode can be a combination of the following values. When a console is created, all input modes except ENABLE_WINDOW_INPUT are enabled by default.

Value	Meaning
ENABLE_LINE_INPUT	The ReadFile or ReadConsole function returns only when a carriage return character is read. If this mode is disabled, the functions return when one or more characters are available.
ENABLE_ECHO_INPUT	Characters read by the ReadFile or ReadConsole function are written to the active screen buffer as they are read. This mode can be used only if the ENABLE_LINE_INPUT mode is also enabled.
ENABLE_PROCESSED_INPUT	CTRL+C is processed by the system and is not placed in the input buffer. If the input buffer is being read by ReadFile or ReadConsole, other control keys are processed by the system and are not returned in the ReadFile or ReadConsole buffer. If the ENABLE_LINE_INPUT mode is also enabled, backspace, carriage return, and linefeed characters are handled by the system.
ENABLE_WINDOW_INPUT	User interactions that change the size of the console screen buffer are reported in the console's input buffer. Information about these events can be read from the input buffer by applications using the ReadConsoleInput function, but not by those using ReadFile or ReadConsole.
ENABLE_MOUSE_INPUT	If the mouse pointer is within the borders of the console window and the window has the keyboard focus, mouse events generated by mouse movement and button presses are placed in the input buffer. These events are discarded by ReadFile or ReadConsole, even when this mode is enabled.
If the hConsoleHandle parameter is a screen buffer handle, the mode can be a combination of the following values. When a screen buffer is created, both output modes are enabled by default.

Value	Meaning
ENABLE_PROCESSED_OUTPUT	Characters written by the WriteFile or WriteConsole function or echoed by the ReadFile or ReadConsole function are parsed for ASCII control sequences, and the correct action is performed. Backspace, tab, bell, carriage return, and linefeed characters are processed.
ENABLE_WRAP_AT_EOL_OUTPUT	When writing with WriteFile or WriteConsole or echoing with ReadFile or ReadConsole, the cursor moves to the beginning of the next row when it reaches the end of the current row. This causes the rows displayed in the console window to scroll up automatically when the cursor advances beyond the last row in the window. It also causes the contents of the screen buffer to scroll up (discarding the top row of the screen buffer) when the cursor advances beyond the last row in the screen buffer. If this mode is disabled, the last character in the row is overwritten with any subsequent characters.
Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

A console consists of an input buffer and one or more screen buffers. The mode of a console buffer determines how the console behaves during input or output (I/O) operations. One set of flag constants is used with input handles, and another set is used with screen buffer (output) handles. Setting the output modes of one screen buffer does not affect the output modes of other screen buffers.

The ENABLE_LINE_INPUT and ENABLE_ECHO_INPUT modes only affect processes that use ReadFile or ReadConsole to read from the console's input buffer. Similarly, the ENABLE_PROCESSED_INPUT mode primarily affects ReadFile and ReadConsole users, except that it also determines whether CTRL+C input is reported in the input buffer (to be read by the ReadConsoleInput function) or is passed to a function defined by the application.

The ENABLE_WINDOW_INPUT and ENABLE_MOUSE_INPUT modes determine whether user interactions involving window resizing and mouse actions are reported in the input buffer or discarded. These events can be read by ReadConsoleInput, but they are always filtered by ReadFile and ReadConsole.

The ENABLE_PROCESSED_OUTPUT and ENABLE_WRAP_AT_EOL_OUTPUT modes only affect processes using ReadFile or ReadConsole and WriteFile or WriteConsole.

To change a console's I/O modes, call SetConsoleMode function.

See Also

ReadConsole, ReadConsoleInput, ReadFile, SetConsoleMode, WriteConsole, WriteFile


GetConsoleOutputCP
GetConsoleOutputCP  QuickInfo  Overview  Group

Windows NT: The GetConsoleOutputCP function returns the identity of the output code page used by the console associated with the calling process. A console uses its output code page to translate the character values written by the various output functions into the images displayed in the console window.

Windows 95: On Japanese and Korean implementations of Windows 95, the GetConsoleOutputCP function returns the VM code page, because the OEM code page can be either 437 or DBCS. On all other implementations of Windows 95, the GetConsoleOutputCP function returns the OEM code page.

UINT GetConsoleOutputCP(VOID)

Parameters

This function has no parameters.

Return Value

The return value is a code that identifies the code page.

Remarks

A code page maps 256 character codes to individual characters. Different code pages include different special characters, typically customized for a language or a group of languages.

To set a console's output code page, use the SetConsoleOutputCP function. To set and query a console's input code page, use the SetConsoleCP and GetConsoleCP functions.

See Also

GetConsoleCP, SetConsoleCP, SetConsoleOutputCP


GetConsoleScreenBufferInfo
GetConsoleScreenBufferInfo  QuickInfo  Overview  Group

The GetConsoleScreenBufferInfo function retrieves information about the specified console screen buffer.

BOOL GetConsoleScreenBufferInfo(

HANDLE  hConsoleOutput,	// handle of console screen buffer
PCONSOLE_SCREEN_BUFFER_INFO  lpConsoleScreenBufferInfo	// address of screen buffer info.
);
Parameters

hConsoleOutput

Identifies a console screen buffer. The handle must have GENERIC_READ access.

lpConsoleScreenBufferInfo

Points to a CONSOLE_SCREEN_BUFFER_INFO structure in which the screen buffer information is returned.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The rectangle returned in the srWindow member of the CONSOLE_SCREEN_BUFFER_INFO structure can be modified and then passed to the SetConsoleWindowInfo function to scroll the screen buffer in the window, to change the size of the window, or both.

All coordinates returned in the CONSOLE_SCREEN_BUFFER_INFO structure are in character-cell coordinates, where the origin (0, 0) is at the upper-left corner of the screen buffer.

See Also

CONSOLE_SCREEN_BUFFER_INFO, GetLargestConsoleWindowSize, SetConsoleCursorPosition, SetConsoleScreenBufferSize, SetConsoleWindowInfo


GetConsoleTitle
GetConsoleTitle  QuickInfo  Overview  Group

The GetConsoleTitle function retrieves the title bar string for the current console window.

DWORD GetConsoleTitle(

LPTSTR  lpConsoleTitle,	// address of buffer for title
DWORD  nSize	// size of the buffer
);
Parameters

lpConsoleTitle

Points to a buffer that receives a null-terminated string containing the text that appears in the title bar of the console window.

nSize

Specifies the size, in characters, of the buffer pointed to by the lpConsoleTitle parameter.

Return Value

If the function succeeds, the return value is the length, in characters, of the string copied to the buffer.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

To set the title bar string for a console window, use the SetConsoleTitle function.

See Also

SetConsoleTitle


GetCPInfo
GetCPInfo  QuickInfo  Overview  Group

The GetCPInfo function retrieves information about any valid installed or available code page.

BOOL GetCPInfo(

UINT  CodePage,	// code page identifier
LPCPINFO  lpCPInfo	// address of structure for information
);
Parameters

CodePage

Specifies the code page about which information is to be retrieved. You can specify the code page identifier for any installed or available code page, or you can specify one of the following predefined values:

Value	Meaning
CP_ACP	Use the system default ANSI code page
CP_MACCP	Use the system default Macintosh code page
CP_OEMCP	Use the system default OEM code page
lpCPInfo

Points to a CPINFO structure that receives information about the code page.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError .

Remarks

If the specified code page is not installed or not available, GetCPInfo sets the last-error value to ERROR_INVALID_PARAMETER.

See Also

GetACP, GetOEMCP, CPINFO


GetCurrencyFormat
GetCurrencyFormat  QuickInfo  Overview  Group

The GetCurrencyFormat function formats a number string as a currency string for a specified locale.

int GetCurrencyFormat(

LCID  Locale,	// locale for which currency string is to be formatted
DWORD  dwFlags,	// bit flag that controls the function's operation
LPCTSTR  lpValue,	// pointer to input number string
CONST CURRENCYFMT *  lpFormat,	// pointer to a formatting information structure
LPTSTR  lpCurrencyStr,	// pointer to output buffer
int  cchCurrency	// size of output buffer
);
Parameters

Locale

Specifies the locale for which the currency string is to be formatted. If lpFormat is NULL, the function formats the string according to the currency format for this locale. If lpFormat is not NULL, the function uses the locale only for formatting information not specified in the CURRENCYFMT structure (for example, the locale's string value for the negative sign).

This parameter can be a locale identifier created by the MAKELCID macro, or one of the following predefined values:

LOCALE_SYSTEM_DEFAULT	Default system locale.
LOCALE_USER_DEFAULT	Default user locale.
dwFlags

A bit flag that controls the operation of the function. If lpFormat is non-NULL, this parameter must be zero.

If lpFormat is NULL, you can specify the LOCALE_NOUSEROVERRIDE flag to format the string using the system default currency format for the specified locale; or you can specify zero to format the string using any user overrides to the locale's default currency format.

lpValue

Points to a null-terminated string containing the number string to format.

This string can contain only the following characters:

•	Characters '0' through '9'

•	One decimal point (dot) if the number is a floating-point value

•	A minus sign in the first character position if the number is a negative value

All other characters are invalid. The function returns an error if the string pointed to by lpValue deviates from these rules.

lpFormat

Pointer to a CURRENCYFMT structure that contains currency formatting information. All members in the structure pointed to by lpFormat must contain appropriate values.

If lpFormat is NULL, the function uses the currency format of the specified locale.

lpCurrencyStr

Points to a buffer to receive the formatted currency string.

cchCurrency

Specifies the size, in bytes (ANSI version) or characters (Unicode version), of the lpCurrencyStr buffer. If cchCurrency is zero, the function returns the number of bytes or characters required to hold the formatted currency string, and the buffer pointed to by lpCurrencyStr is not used.

Return Value

If the function succeeds, the return value is the number of bytes (ANSI version) or characters (Unicode version) written to the buffer pointed to by lpCurrencyStr, or if the cchCurrency parameter is zero, the number of bytes or characters required to hold the formatted currency string.

If the function fails, the return value is zero. To get extended error information, call GetLastError. GetLastError may return one of the following error codes:

ERROR_INSUFFICIENT_BUFFER
ERROR_INVALID FLAGS
ERROR_INVALID_PARAMETER

See Also

GetNumberFormat, CURRENCYFMT


GetCurrentDirectory
GetCurrentDirectory  QuickInfo  Overview  Group

The GetCurrentDirectory function retrieves the current directory for the current process.

DWORD GetCurrentDirectory(

DWORD  nBufferLength,	// size, in characters, of directory buffer
LPTSTR  lpBuffer	// address of buffer for current directory
);
Parameters

nBufferLength

Specifies the length, in characters, of the buffer for the current directory string. The buffer length must include room for a terminating null character.

lpBuffer

Points to the buffer for the current directory string. This null-terminated string specifies the absolute path to the current directory.

Return Value

If the function succeeds, the return value specifies the number of characters written to the buffer, not including the terminating null character.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

If the buffer pointed to by lpBuffer is not large enough, the return value specifies the required size of the buffer, including the number of bytes necessary for a terminating null character.

See Also

CreateDirectory, GetSystemDirectory, GetWindowsDirectory, RemoveDirectory, SetCurrentDirectory


GetCurrentObject
GetCurrentObject  QuickInfo  Overview  Group

The GetCurrentObject function returns the currently selected object of the specified type.

HGDIOBJ GetCurrentObject(

HDC  hdc,	// handle of device context
UINT  uObjectType	// object-type identifier
);
Parameters

hdc

Identifies the device context.

uObjectType

Specifies the object type to be queried. This parameter can be one of the following values:

Value	Meaning
OBJ_PEN	Returns the current selected pen.
OBJ_BRUSH	Returns the current selected brush.
OBJ_PAL	Returns the current selected palette.
OBJ_FONT	Returns the current selected font.
OBJ_BITMAP	Returns the current selected bitmap if hdc is a memory device context.
Return Value

If the function succeeds, the return value is the handle of the specified object.

If the function fails, the return value is NULL.

Remarks

An application can use the GetCurrentObject and GetObject functions to retrieve descriptions of the graphic objects currently selected into the given device context.

See Also

DeleteObject, GetObject, SelectObject


GetCurrentPDB
GetCurrentPDB  Overview  Group

The GetCurrentPDB function is not implemented in the Win32 API. Win32-based applications should use the GetCommandLine and GetEnvironmentStrings functions.


GetCurrentPosition

The GetCurrentPosition function is not implemented in the Win32 API. Win32-based applications should use the GetCurrentPositionEx function.


GetCurrentPositionEx
GetCurrentPositionEx  QuickInfo  Overview  Group

The GetCurrentPositionEx function retrieves the current position in logical coordinates.

BOOL GetCurrentPositionEx(

HDC  hdc,	// handle of device context
LPPOINT  lpPoint	// address of structure receiving current position
);
Parameters

hdc

Identifies the device context.

lpPoint

Points to a POINT structure that receives the coordinates of the current position.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

See Also

MoveToEx, POINT


GetCurrentProcess
GetCurrentProcess  QuickInfo  Overview  Group

The GetCurrentProcess function returns a pseudohandle for the current process.

HANDLE GetCurrentProcess(VOID)

Parameters

This function has no parameters.

Return Value

The return value is a pseudohandle to the current process.

Remarks

A pseudohandle is a special constant that is interpreted as the current process handle. The calling process can use this handle to specify its own process whenever a process handle is required. Pseudohandles are not inherited by child processes.

This handle has the maximum possible access to the process object. For systems that support security descriptors, this is the maximum access allowed by the security descriptor for the calling process. For systems that do not support security descriptors, this is PROCESS_ALL_ACCESS.

A process can create a "real" handle to itself that is valid in the context of other processes, or that can be inherited by other processes, by specifying the pseudohandle as the source handle in a call to the DuplicateHandle function. A process can also use the OpenProcess function to open a real handle to itself.

The pseudohandle need not be closed when it is no longer needed. Calling the CloseHandle function with a pseudohandle has no effect. If the pseudohandle is duplicated by DuplicateHandle, the duplicate handle must be closed.

See Also

CloseHandle, DuplicateHandle, GetCurrentProcessId, GetCurrentThread, OpenProcess


GetCurrentProcessId
GetCurrentProcessId  QuickInfo  Overview  Group

The GetCurrentProcessId function returns the process identifier of the calling process.

DWORD GetCurrentProcessId(VOID)

Parameters

This function has no parameters.

Return Value

The return value is the process identifier of the calling process.

Remarks

Until the process terminates, the process identifier uniquely identifies the process throughout the system.

See Also

GetCurrentProcess, OpenProcess


GetCurrentTask
GetCurrentTask  Overview  Group

The GetCurrentTask function is not implemented in the Win32 API. Win32-based applications should use the GetCurrentThread or GetCurrentProcess function.


GetCurrentThread
GetCurrentThread  QuickInfo  Overview  Group

The GetCurrentThread function returns a pseudohandle for the current thread.

HANDLE GetCurrentThread(VOID)

Parameters

This function has no parameters.

Return Value

The return value is a pseudohandle for the current thread.

Remarks

A pseudohandle is a special constant that is interpreted as the current thread handle. The calling thread can use this handle to specify itself whenever a thread handle is required. Pseudohandles are not inherited by child processes.

This handle has the maximum possible access to the thread object. For systems that support security descriptors, this is the maximum access allowed by the security descriptor for the calling process. For systems that do not support security descriptors, this is THREAD_ALL_ACCESS.

The function cannot be used by one thread to create a handle that can be used by other threads to refer to the first thread. The handle is always interpreted as referring to the thread that is using it. A thread can create a "real" handle of itself that can be used by other threads, or inherited by other processes, by specifying the pseudohandle as the source handle in a call to the DuplicateHandle function.

The pseudohandle need not be closed when it is no longer needed. Calling the CloseHandle function with this handle has no effect. If the pseudohandle is duplicated by DuplicateHandle, the duplicate handle must be closed.

See Also

CloseHandle, DuplicateHandle, GetCurrentProcess, GetCurrentThreadId


GetCurrentThreadId
GetCurrentThreadId  QuickInfo  Overview  Group

The GetCurrentThreadId function returns the thread identifier of the calling thread.

DWORD GetCurrentThreadId(VOID)

Parameters

This function has no parameters.

Return Value

The return value is the thread identifier of the calling thread.

Remarks

Until the thread terminates, the thread identifier uniquely identifies the thread throughout the system.

See Also

GetCurrentThread


GetCurrentTime
GetCurrentTime  QuickInfo  Overview  Group

The GetCurrentTime function retrieves the number of milliseconds that have elapsed since Windows was started.

DWORD GetCurrentTime(VOID)

Parameters

This function has no parameters.

Return Value

If the function succeeds, the return value is the number of milliseconds that have elapsed since Windows was started.

Remarks

The GetCurrentTime function is identical to the GetTickCount function. Applications should use the GetTickCount function because its name matches more closely what the function does.

The GetCurrentTime and GetMessageTime functions return different times. GetMessageTime returns the Windows time when the given message was created, not the current Windows time.

The internal timer wraps around to zero if Windows is run continuously for approximately 49.7 days.

See Also

GetMessageTime, GetSystemTime, GetTickCount, SetSystemTime


GetCursor
GetCursor  QuickInfo  Overview  Group

The GetCursor function retrieves the handle of the current cursor.

HCURSOR GetCursor(VOID)

Parameters

This function has no parameters.

Return Value

If the function succeeds, the return value is the handle of the current cursor.

If there is no cursor, the return value is NULL.

See Also

SetCursor


GetCursorPos
GetCursorPos  QuickInfo  Overview  Group

The GetCursorPos function retrieves the cursor's position, in screen coordinates.

BOOL GetCursorPos(

LPPOINT  lpPoint	// address of structure for cursor position
);
Parameters

lpPoint

Points to a POINT structure that receives the screen coordinates of the cursor.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The cursor position is always given in screen coordinates and is not affected by the mapping mode of the window that contains the cursor.

The calling process must have WINSTA_READATTRIBUTES access to the window station.

See Also

ClipCursor, POINT, SetCursor, SetCursorPos, ShowCursor


GetDateFormat
GetDateFormat  QuickInfo  Overview  Group

The GetDateFormat function formats a date as a date string for a specified locale. The function formats either a specified date or the local system date.

int GetDateFormat(

LCID  Locale,	// locale for which date is to be formatted
DWORD  dwFlags,	// flags specifying function options
CONST SYSTEMTIME *  lpDate,	// date to be formatted
LPCTSTR  lpFormat,	// date format string
LPTSTR  lpDateStr,	// buffer for storing formatted string
int  cchDate	// size of buffer
);
Parameters

Locale

Specifies the locale for which the date string is to be formatted. If lpFormat is NULL, the function formats the string according to the date format for this locale. If lpFormat is not NULL, the function uses the locale only for information not specified in the format picture string (for example, the locale's day and month names).

This parameter can be a locale identifier created by the MAKELCID macro, or one of the following predefined values:

LOCALE_SYSTEM_DEFAULT	Default system locale.
LOCALE_USER_DEFAULT	Default user locale.
dwFlags

A set of bit flags that specify various function options. If lpFormat is non-NULL, this parameter must be zero.

If lpFormat is NULL, you can specify a combination of the following flags:

Flag	Meaning
LOCALE_NOUSEROVERRIDE	If set, the function formats the string using the system default date format for the specified locale. If not set, the function formats the string using any user overrides to the locale's default date format.
DATE_SHORTDATE	Use the short date format. This is the default. Cannot be used with DATE_LONGDATE.
DATE_LONGDATE	Use the long date format. Cannot be used with DATE_SHORTDATE.
DATE_USE_ALT_CALENDAR	Use the alternate calendar, if one exists, to format the date string. If this flag is set, the function uses the default format for that alternate calendar, rather than using any user overrides. The user overrides will be used only in the event that there is no default format for the specified alternate calendar.
lpDate

Pointer to a SYSTEMTIME structure that contains the date information to be formatted. If this pointer is NULL, the function uses the current local system date.

lpFormat

Pointer to a format picture string to use to form the date string. If lpFormat is NULL, the function uses the date format of the specified locale.

Use the following elements to construct a format picture string. If you use spaces to separate the elements in the format string, these spaces will appear in the same location in the output string. The letters must be in uppercase or lowercase as shown in the table (for example, "MM" not "mm"). Characters in the format string that are enclosed in single quotation marks will appear in the same location and unchanged in the output string.

Picture	Meaning
d	Day of month as digits with no leading zero for single-digit days.
dd	Day of month as digits with leading zero for single-digit days.
ddd	Day of week as a three-letter abbreviation. The function uses the LOCALE_SABBREVDAYNAME value associated with the specified locale.
dddd	Day of week as its full name. The function uses the LOCALE_SDAYNAME value associated with the specified locale.
M	Month as digits with no leading zero for single-digit months.
MM	Month as digits with leading zero for single-digit months.
MMM	Month as a three-letter abbreviation. The function uses the LOCALE_SABBREVMONTHNAME value associated with the specified locale.
MMMM	Month as its full name. The function uses the LOCALE_SMONTHNAME value associated with the specified locale.
y	Year as last two digits, but with no leading zero for years less than 10.
yy	Year as last two digits, but with leading zero for years less than 10.
yyyy	Year represented by full four digits.
gg	Period/era string. The function uses the CAL_SERASTRING value associated with the specified locale. This element is ignored if the date to be formatted does not have an associated era or period string.
For example, to get the date string

"Wed, Aug 31 94"

use the following picture string:

"ddd',' MMM dd yy"

lpDateStr

Pointer to a buffer that receives the formatted date string.

cchDate

Specifies the size, in bytes (ANSI version) or characters (Unicode version), of the lpDateStr buffer. If cchDate is zero, the function returns the number of bytes or characters required to hold the formatted date string, and the buffer pointed to by lpDateStr is not used.

Return Value

If the function succeeds, the return value is the number of bytes (ANSI version) or characters (Unicode version) written to the lpDateStr buffer, or if the cchDate parameter is zero, the number of bytes or characters required to hold the formatted date string.

If the function fails, the return value is zero. To get extended error information, call GetLastError. GetLastError may return one of the following error codes:

ERROR_INSUFFICIENT_BUFFER

ERROR_INVALID_FLAGS

ERROR_INVALID_PARAMETER

Remarks

The day name, abbreviated day name, month name, and abbreviated month name are all localized based on the given locale identifier.

The date values in the SYSTEMTIME structure pointed to by lpDate must be valid. The function checks each of the date values: year, month, day, and day of week. If the day of the week is incorrect, the function uses the correct value, and returns no error. If any of the other date values are outside the correct range, the function fails, and sets the last-error to ERROR_INVALID_PARAMETER.

The function ignores the time portions of the SYSTEMTIME structure pointed to by lpDate: wHour, wMinute, wSecond, and wMilliseconds.

The DATE_SHORTDATE and DATE_LONGDATE flag options are mutually exclusive. If neither one is specified and lpFormat is NULL, then DATE_SHORTDATE is the default.

No errors are returned for a bad format string. The function simply forms the best date string that it can. For example, the only year pictures that are valid are L"yyyy" and L"yy" (the 'L' indicates a Unicode (16-bit characters) string). If L"y" is passed in, the function  assumes L"yy". If L"yyy" is passed in, the function assumes L"yyyy". If more than 4 date (L"dddd") or 4 month (L"MMMM") pictures are passed in, then the function defaults to L"dddd" or L"MMMM".

Any text that should remain in its exact form in the date string should be enclosed within single quotation marks in the date format picture. The single quotation mark may also be used as an escape character to allow the single quotation mark itself to be displayed in the date string. However, the escape sequence must be enclosed within two single quotation marks. For example, to display the date as "May '93", the format string would be:  L"MMMM ''''yy" The first and last single quotation marks are the enclosing quotation marks. The second and third single quotation marks are the escape sequence to allow the single quotation mark to be displayed before the century.

See Also

GetTimeFormat, SYSTEMTIME


GetDC
GetDC  QuickInfo  Overview  Group

The GetDC function retrieves a handle of a display device context (DC) for the client area of the specified window. The display device context can be used in subsequent GDI functions to draw in the client area of the window.

This function retrieves a common, class, or private device context depending on the class style specified for the specified window. For common device contexts, GetDC assigns default attributes to the device context each time it is retrieved. For class and private device contexts, GetDC leaves the previously assigned attributes unchanged.

HDC GetDC(

HWND  hWnd	// handle of window
);
Parameters

hWnd

Identifies the window whose device context is to be retrieved.

Return Value

If the function succeeds, the return value identifies the device context for the given window's client area.

If the function fails, the return value is NULL.

Remarks

After painting with a common device context, the ReleaseDC function must be called to release the device context. Class and private device contexts do not have to be released. The number of device contexts is limited only by available memory.

See Also

ReleaseDC, GetWindowDC


GetDCEx
GetDCEx  QuickInfo  Overview  Group

The GetDCEx function retrieves the handle of a display device (DC) context for the specified window. The display device context can be used in subsequent GDI functions to draw in the client area.

This function is an extension to the GetDC function that gives an application more control over how and whether clipping occurs in the client area.

HDC GetDCEx(

HWND  hWnd,	// handle of window
HRGN  hrgnClip,	// handle of clip region
DWORD  flags	// device-context creation flags
);
Parameters

hWnd

Identifies the window where drawing will occur.

hrgnClip

Specifies a clipping region that may be combined with the visible region of the client window.

flags

Specifies how the device context is created. This parameter can be a combination of the following values:

Value	Meaning
DCX_WINDOW	Returns a device context corresponding to the window rectangle rather than the client rectangle.
DCX_CACHE	Returns a device context from the cache, rather than the OWNDC or CLASSDC window. Essentially overrides CS_OWNDC and CS_CLASSDC.
DCX_PARENTCLIP	Uses the visible region of the parent window. The parent's WS_CLIPCHILDREN and CS_PARENTDC style bits are ignored. The device context origin is set to the upper-left corner of the window identified by hWnd.
DCX_CLIPSIBLINGS	Excludes the visible regions of all sibling windows above the window identified by hWnd.
DCX_CLIPCHILDREN	Excludes the visible regions of all child windows below the window identified by hWnd.
DCX_NORESETATTRS	Does not reset the attributes of this device context to the default attributes when this device context is released.
DCX_LOCKWINDOWUPDATE	Allows drawing even if there is a LockWindowUpdate call in effect that would otherwise exclude this window. Used for drawing during tracking.
DCX_EXCLUDERGN	The clipping region identified by hrgnClip is excluded from the visible region of the returned device context.
DCX_INTERSECTRGN	The clipping region identified by hrgnClip is intersected with the visible region of the returned device context.
DCX_VALIDATE	When specified with DCX_INTERSECTUPDATE, causes the device context to be completely validated. Using this function with both DCX_INTERSECTUPDATE and DCX_VALIDATE is identical to using the BeginPaint function.
Return Value

If the function succeeds, the return value is the handle of the device context for the given window.

If the function fails, the return value is NULL. An invalid value for the hWnd parameter will cause the function to fail.

Remarks

Unless the display device context belongs to a window class, the ReleaseDC function must be called to release the device context after painting. Because only five common device contexts are available at any given time, failure to release a device context can prevent other applications from accessing a device context.

A device context belonging to the window's class is returned by the GetDC function if CS_CLASSDC, CS_OWNDC or CS_PARENTDC was specified as a style in the WNDCLASS structure when the class was registered.

See Also

BeginPaint, GetDC, GetWindowDC, ReleaseDC WNDCLASS


GetDCOrg

The GetDCOrg function is not implemented in the Win32 API. Win32-based applications should use the GetDCOrgEx function.


GetDCOrgEx
GetDCOrgEx  QuickInfo  Overview  Group

The GetDCOrgEx function obtains the final translation origin for a specified device context (DC). The final translation origin specifies an offset that Windows uses to translate device coordinates into client coordinates (for coordinates in an application's window). This function supersedes the GetDCOrg function.

BOOL GetDCOrgEx(

HDC  hdc,	// device-context handle
LPPOINT  lpPoint	// address of structure that receives translation origin
);
Parameters

hdc

Specifies the device context whose final translation origin is to be retrieved.

lpPoint

Points to a POINT structure that the function will set to the final translation origin, in device coordinates.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

The final translation origin is relative to the physical origin of the screen.

See Also

CreateIC, POINT


GetDefaultCommConfig [New - Windows 95]
GetDefaultCommConfig  QuickInfo

[New - Windows 95]

The GetDefaultCommConfig function gets the default configuration for a communications device.

BOOL GetDefaultCommConfig(

LPCSTR  lpszName,
LPCOMMCONFIG  lpCC,
LPDWORD  lpdwSize
);
Parameters

lpszName

Points to a null-terminated string specifying the name of the device.

lpCC

Points to the buffer that receives the COMMCONFIG structure.

lpdwSize

Points to a 32-bit variable that specifies the size, in bytes, of the buffer pointed to by lpCC. Upon return, the variable contains the number of bytes copied if the function succeeds, or the number of bytes required if the buffer was too small.

Return value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, use the GetLastError function.

See Also

COMMCONFIG


GetDesktopWindow
GetDesktopWindow  QuickInfo  Overview  Group

The GetDesktopWindow function returns the handle of the Windows desktop window. The desktop window covers the entire screen. The desktop window is the area on top of which all icons and other windows are painted.

HWND GetDesktopWindow(VOID)

Parameters

This function has no parameters.

Return Value

The return value is the handle of the desktop window.

See Also

GetWindow


GetDeviceCaps
GetDeviceCaps  QuickInfo  Overview  Group

The GetDeviceCaps function retrieves device-specific information about a specified device.

int GetDeviceCaps(

HDC  hdc,	// device-context handle
int  nIndex	// index of capability to query
);
Parameters

hdc

Identifies the device context.

nIndex

Specifies the item to return. This parameter can be one of the following values:

Index	Meaning
DRIVERVERSION	The device driver version.
TECHNOLOGY	Device technology. It can be any one of the following values:
Value	Meaning
DT_PLOTTER	Vector plotter
DT_RASDISPLAY	Raster display
DT_RASPRINTER	Raster printer
DT_RASCAMERA	Raster camera
DT_CHARSTREAM	Character stream
DT_METAFILE	Metafile
DT_DISPFILE	Display file
	If the hdc parameter identifies the device context of an enhanced metafile, the device technology is that of the referenced device as given to the CreateEnhMetaFile function. To determine whether it is an enhanced metafile device context, use the GetObjectType function.
HORZSIZE	Width, in millimeters, of the physical screen.
VERTSIZE	Height, in millimeters, of the physical screen.
HORZRES	Width, in pixels, of the screen.
VERTRES	Height, in raster lines, of the screen.
LOGPIXELSX	Number of pixels per logical inch along the screen width.
LOGPIXELSY	Number of pixels per logical inch along the screen height.
BITSPIXEL	Number of adjacent color bits for each pixel.
PLANES	Number of color planes.
NUMBRUSHES	Number of device-specific brushes.
NUMPENS	Number of device-specific pens.
NUMFONTS	Number of device-specific fonts.
NUMCOLORS	Number of entries in the device's color table.
ASPECTX	Relative width of a device pixel used for line drawing.
ASPECTY	Relative height of a device pixel used for line drawing.
ASPECTXY	Diagonal width of the device pixel used for line drawing.
PDEVICESIZE	Reserved.
CLIPCAPS	Flag that indicates the clipping capabilities of the device. If the device can clip to a rectangle, it is 1. Otherwise, it is 0.
SIZEPALETTE	Number of entries in the system palette. This index is valid only if the device driver sets the RC_PALETTE bit in the RASTERCAPS index and is available only if the driver is compatible with Windows version 3.0 or later.
NUMRESERVED	Number of reserved entries in the system palette. This index is valid only if the device driver sets the RC_PALETTE bit in the RASTERCAPS index and is available only if the driver is compatible with Windows version 3.0 or later.
COLORRES	Actual color resolution of the device, in bits per pixel. This index is valid only if the device driver sets the RC_PALETTE bit in the RASTERCAPS index and is available only if the driver is compatible with Windows version 3.0 or later.
PHYSICALWIDTH	For printing devices: the physical width, in device units.
PHYSICALHEIGHT	For printing devices: the physical height, in device units.
PHYSICALOFFSETX	For printing devices: the physical printable area horizontal margin.
PHYSICALOFFSETY	For printing devices: the physical printable area vertical margin.
SCALINGFACTORX	For printing devices: the scaling factor along the horizontal axis.
SCALINGFACTORY	For printing devices: the scaling factor along the vertical axis.
VREFRESH	Windows NT only: For display devices: the current vertical refresh rate of the device, in cycles per second (Hz).
DESKTOPHORZRES	Windows NT only: Width, in pixels, of the virtual desktop. This value may be larger than HORZRES if the device supports a virtual desktop or multiple displays.
DESKTOPVERTRES	Windows NT only: Height, in pixels, of the virtual desktop. This value may be larger than VERTRES if the device supports a virtual desktop or multiple displays.
BLTALIGNMENT	Windows NT only: Preferred horizontal drawing alignment, expressed as a multiple of pixels. For best drawing performance, windows should be horizontally aligned to a multiple of this value. A value of zero indicates that the device is accelerated, and any alignment may be used.
RASTERCAPS	Value that indicates the raster capabilities of the device, as shown in the following table:
Capability	Meaning
RC_BANDING	Requires banding support.
RC_BITBLT	Capable of transferring bitmaps.
RC_BITMAP64	Capable of supporting bitmaps larger than 64K.
RC_DI_BITMAP	Capable of supporting the SetDIBits and GetDIBits functions.
RC_DIBTODEV	Capable of supporting the SetDIBitsToDevice function.
RC_FLOODFILL	Capable of performing flood fills.
RC_GDI20_OUTPUT	Capable of supporting features of Windows 2.0.
RC_PALETTE	Specifies a palette-based device.
RC_SCALING	Capable of scaling.
RC_STRETCHBLT	Capable of performing the StretchBlt function.
RC_STRETCHDIB	Capable of performing the StretchDIBits function.
CURVECAPS	Value that indicates the curve capabilities of the device, as shown in the following table:
Value	Meaning
CC_NONE	Device does not support curves.
CC_CIRCLES	Device can draw circles.
CC_PIE	Device can draw pie wedges.
CC_CHORD	Device can draw chord arcs.
CC_ELLIPSES	Device can draw ellipses.
CC_WIDE	Device can draw wide borders.
CC_STYLED	Device can draw styled borders.
CC_WIDESTYLED	Device can draw borders that are wide and styled.
CC_INTERIORS	Device can draw interiors.
CC_ROUNDRECT	Device can draw rounded rectangles.
LINECAPS	Value that indicates the line capabilities of the device, as shown in the following table:
Value	Meaning
LC_NONE	Device does not support lines.
LC_POLYLINE	Device can draw a polyline.
LC_MARKER	Device can draw a marker.
LC_POLYMARKER	Device can draw multiple markers.
LC_WIDE	Device can draw wide lines.
LC_STYLED	Device can draw styled lines.
LC_WIDESTYLED	Device can draw lines that are wide and styled.
LC_INTERIORS	Device can draw interiors.
POLYGONALCAPS	Value that indicates the polygon capabilities of the device, as shown in the following table:
Value	Meaning
PC_NONE	Device does not support polygons.
PC_POLYGON	Device can draw alternate-fill polygons.
PC_RECTANGLE	Device can draw rectangles.
PC_WINDPOLYGON	Device can draw winding-fill polygons.
PC_SCANLINE	Device can draw a single scanline.
PC_WIDE	Device can draw wide borders.
PC_STYLED	Device can draw styled borders.
PC_WIDESTYLED	Device can draw borders that are wide and styled.
PC_INTERIORS	Device can draw interiors.
TEXTCAPS	Value that indicates the text capabilities of the device, as shown in the following table:
Bit	Meaning
TC_OP_CHARACTER	Device is capable of character output precision.
TC_OP_STROKE	Device is capable of stroke output precision.
TC_CP_STROKE	Device is capable of stroke clip precision.
TC_CR_90	Device is capable of 90-degree character rotation.
TC_CR_ANY	Device is capable of any character rotation.
TC_SF_X_YINDEP	Device can scale independently in the x- and y-directions.
TC_SA_DOUBLE	Device is capable of doubled character for scaling.
TC_SA_INTEGER	Device uses integer multiples only for character scaling.
TC_SA_CONTIN	Device uses any multiples for exact character scaling.
TC_EA_DOUBLE	Device can draw double-weight characters.
TC_IA_ABLE	Device can italicize.
TC_UA_ABLE	Device can underline.
TC_SO_ABLE	Device can draw strikeouts.
TC_RA_ABLE	Device can draw raster fonts.
TC_VA_ABLE	Device can draw vector fonts.
TC_RESERVED	Reserved; must be zero.
TC_SCROLLBLT	Device cannot scroll using a bit-block transfer. Note that this meaning may be the opposite of what you expect.
Return Value

The return value specifies the value of the desired item.

See Also

CreateEnhMetaFile, CreateIC, DeviceCapabilities, GetDIBits, GetObjectType, SetDIBits, SetDIBitsToDevice, StretchBlt, StretchDIBits


GetDeviceGammaRamp [New - Windows 95]
GetDeviceGammaRamp  QuickInfo  Overview  Group

[New - Windows 95]

The GetDeviceGammaRamp function retrieves the gamma ramp on direct color display boards.

BOOL GetDeviceGammaRamp(

HDC  hdc,
LPVOID  lpRamp
);
Parameters

hdc

Handle to the device context.

lpRamp

Pointer to a set of three arrays of 256-byte elements. These arrays are the mapping between color values in the frame buffer and DAC values. The first array is red, the next is green, and the final one is blue.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

Direct color display modes do not use color lookup tables. The direct color modes are usually 16-, 24-, or 32-bit. Not all direct color video boards support loadable gamma ramps. This function succeeds only for those drivers that support loadable gamma ramps in hardware.


GetDialogBaseUnits
GetDialogBaseUnits  QuickInfo  Overview  Group

The GetDialogBaseUnits function returns the dialog box base units used by Windows to create dialog boxes. Both Windows and applications use these units to convert the width and height of dialog boxes and controls from dialog units, as given in dialog box templates, to pixels, and vice versa.

LONG GetDialogBaseUnits(VOID)

Parameters

This function has no parameters.

Return Value

The return value is a 32-bit value that contains the dialog base units. The low-order word of the return value contains the horizontal dialog box base unit, and the high-order word contains the vertical dialog box base unit.

Remarks

The horizontal base unit is equal to the average width, in pixels, of the characters in the system font; the vertical base unit is equal to the height, in pixels, of the font. Furthermore, each horizontal base unit is equal to 4 horizontal dialog units; each vertical base unit is equal to 8 vertical dialog units. Therefore, to convert dialog units to pixels, an application applies the following formulas:

pixelX = (dialogunitX * baseunitX) / 4

pixelY = (dialogunitY * baseunitY) / 8

Similarly, to convert from pixels to dialog units, an application applies the following formulas:

dialogunitX = (pixelX * 4) / baseunitX

dialogunitY = (pixelY * 8) / baseunitY

The multiplication is performed before the division to avoid rounding problems if base units are not divisible by 4 or 8.

See Also

MapDialogRect


GetDIBColorTable
GetDIBColorTable  QuickInfo  Overview  Group

The GetDIBColorTable function retrieves RGB (red, green, blue) color values from a range of entries in the color table of the DIB section bitmap that is currently selected into a specified device context.

UINT GetDIBColorTable(

HDC hdc,	// handle of device context whose DIB is of interest
UINT uStartIndex,	// color table index of first entry to retrieve
UINT cEntries,	// number of color table entries to retrieve
RGBQUAD *pColors	// pointer to buffer that receives color table entries
);
Parameters

hdc

Specifies a device context. A DIB section bitmap must be selected into this device context.

uStartIndex

A zero-based color table index that specifies the first color table entry to retrieve.

cEntries

Specifies the number of color table entries to retrieve.

pColors

Points to a buffer that receives an array of RGBQUAD data structures containing color information from the DIB's color table. The buffer must be large enough to contain as many RGBQUAD data structures as the value of cEntries.

Return Value

If the function succeeds, the return value is the number of color table entries that the function retrieves.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

The GetDIBColorTable function should be called to retrieve the color table for DIB section bitmaps that use 1, 4, or 8 bits per pixel. The biBitCount member of a bitmap's associated BITMAPINFOHEADER structure specifies the number of bits per pixel. DIB section bitmaps with a biBitCount value greater than 8 do not have a color table, but they do have associated color masks. Call the GetObject function to retrieve those color masks.

See Also

BITMAPINFOHEADER, CreateDIBSection, DIBSECTION, GetObject, RGBQUAD, SetDIBColorTable


GetDIBits
GetDIBits  QuickInfo  Overview  Group

The GetDIBits function retrieves the bits of the specified bitmap and copies them into a buffer using the specified format.

int GetDIBits(

HDC  hdc,	// handle of device context
HBITMAP  hbmp,	// handle of bitmap
UINT  uStartScan,	// first scan line to set in destination bitmap
UINT  cScanLines,	// number of scan lines to copy
LPVOID  lpvBits,	// address of array for bitmap bits
LPBITMAPINFO  lpbi,	// address of structure with bitmap data
UINT  uUsage	// RGB or palette index
);
Parameters

hdc

Identifies the device context.

hbmp

Identifies the bitmap.

uStartScan

Specifies the first scan line to retrieve.

cScanLines

Specifies the number of scan lines to retrieve.

lpvBits

Points to a buffer to receive the bitmap data. If this parameter is NULL, the function passes the dimensions and format of the bitmap to the BITMAPINFO structure pointed to by the lpbi parameter.

lpbi

Points to a BITMAPINFO structure that specifies the desired format for the device-independent bitmap (DIB) data.

uUsage

Specifies the format of the bmiColors member of the BITMAPINFO structure. It must be one of the following values:

Value	Meaning
DIB_PAL_COLORS	The color table should consist of an array of 16-bit indices into the current logical palette.
DIB_RGB_COLORS	The color table should consist of literal red, green, blue (RGB) values.
Return Value

If the lpvBits parameter is non-NULL and the function succeeds, the return value is the number of scan lines copied from the bitmap.

Windows 95:

If the lpvBits parameter is NULL and GetDIBits successfully fills the BITMAPINFO structure, the return value is the total number of scan lines in the bitmap.

Windows NT:

If the lpvBits parameter is NULL and GetDIBits successfully fills the BITMAPINFO structure, the return value is non-zero.

If the function fails, the return value is zero.

Remarks

If the requested format for the DIB matches its internal format, the RGB values for the bitmap are copied. If the requested format doesn't match the internal format, a color table is synthesized. The following table describes the color table synthesized for each format.

Value	Meaning
1_BPP	The color table consists of a black and a white entry.
4_BPP	The color table consists of a mix of colors identical to the standard VGA palette.
8_BPP	The color table consists of a general mix of 256 colors defined by GDI. (Included in these 256 colors are the 20 colors found in the default logical palette.)
24_BPP	No color table is returned.
If the lpvBits parameter is a valid pointer, the first six members of the BITMAPINFOHEADER structure must be initialized to specify the size and format of the DIB. Note that a bottom-up DIB is specified by setting the height to a positive number, while a top-down DIB is specified by setting the height to a negative number. The bitmap's color table will be appended to the BITMAPINFO structure.

If lpvBits is NULL, GetDIBits examines the first member of the first structure pointed to by lpbi. This member must specify the size, in bytes, of a BITMAPCOREHEADER or a BITMAPINFOHEADER structure. The function uses the specified size to determine how the remaining members should be initialized.

If lpvBits is NULL and the bit count member of BITMAPINFO is initialized to zero, GetDIBits fills in BITMAPINFOHEADER or BITMAPCOREHEADER without the color table. This technique can be used to query bitmap attributes.

The bitmap identified by the hbmp parameter must not be selected into a device context when the application calls this function.

The origin for a bottom-up DIB is the lower-left corner of the bitmap; the origin for a top-down DIB is the upper-left corner.

See Also

BITMAPCOREHEADER, BITMAPINFO, BITMAPINFOHEADER, SetDIBits


GetDiskFreeSpace
GetDiskFreeSpace  QuickInfo  Overview  Group

The GetDiskFreeSpace function retrieves information about the specified disk, including the amount of free space on the disk.

BOOL GetDiskFreeSpace(

LPCTSTR  lpRootPathName,	// address of root path
LPDWORD  lpSectorsPerCluster,	// address of sectors per cluster
LPDWORD  lpBytesPerSector,	// address of bytes per sector
LPDWORD  lpNumberOfFreeClusters,	// address of number of free clusters
LPDWORD  lpTotalNumberOfClusters	// address of total number of clusters
);
Parameters

lpRootPathName

Points to a null-terminated string that specifies the root directory of the disk to return information about. If lpRootPathName is NULL, the function uses the root of the current directory.

lpSectorsPerCluster

Points to a variable for the number of sectors per cluster.

lpBytesPerSector

Points to a variable for the number of bytes per sector.

lpNumberOfFreeClusters

Points to a variable for the total number of free clusters on the disk.

lpTotalNumberOfClusters

Points to a variable for the total number of clusters on the disk.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

GetDriveType


GetDlgCtrlID
GetDlgCtrlID  QuickInfo  Overview  Group

The GetDlgCtrlID function returns the identifier of the specified control.

int GetDlgCtrlID(

HWND  hwndCtl	// handle of control
);
Parameters

hwndCtl

Identifies the control.

Return Value

If the function succeeds, the return value is the identifier of the control.

If the function fails, the return value is NULL. An invalid value for the hwndCtl parameter, for example, will cause the function to fail.

Remarks

GetDlgCtrlID accepts child window handles as well as handles of controls in dialog boxes. An application sets the identifier for a child window when it creates the window by assigning the identifier value to the hmenu parameter when calling the CreateWindow or CreateWindowEx function.

Although GetDlgCtrlID may return a value if hwndCtl identifies a top-level window, top-level windows cannot have identifiers and such a return value is never valid.

See Also

CreateWindow, CreateWindowEx, GetDlgItem


GetDlgItem
GetDlgItem  QuickInfo  Overview  Group

The GetDlgItem function retrieves the handle of a control in the specified dialog box.

HWND GetDlgItem(

HWND  hDlg,	// handle of dialog box
int  nIDDlgItem	// identifier of control
);
Parameters

hDlg

Identifies the dialog box that contains the control.

nIDDlgItem

Specifies the identifier of the control to be retrieved.

Return Value

If the function succeeds, the return value is the window handle of the given control.

If the function fails, the return value is NULL, indicating an invalid dialog box handle or a nonexistent control.

Remarks

You can use the GetDlgItem function with any parent-child window pair, not just with dialog boxes. As long as the hDlg parameter specifies a parent window and the child window has a unique identifier (as specified by the hMenu parameter in the CreateWindow or CreateWindowEx function that created the child window), GetDlgItem returns a valid handle to the child window.

See Also

CreateWindow, CreateWindowEx, GetDlgItemInt, GetDlgItemText


GetDlgItemInt
GetDlgItemInt  QuickInfo  Overview  Group

The GetDlgItemInt function translates the text of a specified control in a dialog box into an integer value.

UINT GetDlgItemInt(

HWND  hDlg,	// handle to dialog box
int  nIDDlgItem,	// control identifier
BOOL*  lpTranslated,	// points to variable to receive success/failure indicator
BOOL  bSigned	// specifies whether value is signed or unsigned
);
Parameters

hDlg

Handle to the dialog box that contains the control of interest.

nIDDlgItem

Dialog item identifier that specifies the control whose text is to be translated.

lpTranslated

Points to a Boolean variable that receives a function success/failure value. TRUE indicates success, FALSE indicates failure.

This parameter is optional: it can be NULL. In that case, the function returns no information about success or failure.

bSigned

Specifies whether the function should examine the text for a minus sign at the beginning and return a signed integer value if it finds one. TRUE specifies that this should be done, FALSE that it should not.

Return Value

If the function succeeds, the variable pointed to by lpTranslated is set to TRUE, and the return value is the translated value of the control text.

If the function fails, the variable pointed to by lpTranslated is set to FALSE, and the return value is zero. Note that, since zero is a possible translated value, a return value of zero does not by itself indicate failure.

If lpTranslated is NULL, the function returns no information about success or failure.

If the bSigned parameter is TRUE, specifying that the value to be retrieved is a signed integer value, cast the return value to an int type.

Remarks

The GetDlgItemInt function retrieves the text of the given control by sending the control a WM_GETTEXT message. The function translates the retrieved text by stripping any extra spaces at the beginning of the text and then converting the decimal digits. The function stops translating when it reaches the end of the text or encounters a nonnumeric character.

If the bSigned parameter is TRUE, the GetDlgItemInt function checks for a minus sign (−) at the beginning of the text and translates the text into a signed integer value. Otherwise, the function creates an unsigned integer value.

The GetDlgItemInt function returns zero if the translated value is greater than INT_MAX (for signed numbers) or UINT_MAX (for unsigned numbers).

See Also

GetDlgCtrlID, GetDlgItem, GetDlgItemText, SetDlgItemInt


GetDlgItemText
GetDlgItemText  QuickInfo  Overview  Group

The GetDlgItemText function retrieves the title or text associated with a control in a dialog box.

UINT GetDlgItemText(

HWND  hDlg,	// handle of dialog box
int  nIDDlgItem,	// identifier of control
LPTSTR  lpString,	// address of buffer for text
int  nMaxCount	// maximum size of string
);
Parameters

hDlg

Identifies the dialog box that contains the control.

nIDDlgItem

Specifies the identifier of the control whose title or text is to be retrieved.

lpString

Points to the buffer to receive the title or text.

nMaxCount

Specifies the maximum length, in characters, of the string to be copied to the buffer pointed to by lpString. If the length of the string exceeds the limit, the string is truncated.

Return Value

If the function succeeds, the return value specifies the number of characters copied to the buffer, not including the terminating null character.

If the function fails, the return value is zero.

Remarks

The GetDlgItemText function sends a WM_GETTEXT message to the control.

See Also

GetDlgItemInt, SetDlgItemInt, SetDlgItemText, WM_GETTEXT


GetDOSEnvironment
GetDOSEnvironment  Overview  Group

The GetDOSEnvironment function is not implemented in the Win32 API. Win32-based applications should use the GetEnvironmentStrings function.


GetDoubleClickTime
GetDoubleClickTime  QuickInfo  Overview  Group

The GetDoubleClickTime function retrieves the current double-click time for the mouse. A double-click is a series of two clicks of the mouse button, the second occurring within a specified time after the first. The double-click time is the maximum number of milliseconds that may occur between the first and second click of a double-click.

UINT GetDoubleClickTime(VOID)

Parameters

This function has no parameters.

Return Value

If the function succeeds, the return value specifies the current double-click time, in milliseconds.

See Also

SetDoubleClickTime


GetDriveType
GetDriveType  QuickInfo  Overview  Group

The GetDriveType function determines whether a disk drive is a removable, fixed, CD-ROM, RAM disk, or network drive.

UINT GetDriveType(

LPCTSTR  lpRootPathName	// address of root path
);
Parameters

lpRootPathName

Points to a null-terminated string that specifies the root directory of the disk to return information about. If lpRootPathName is NULL, the function uses the root of the current directory.

Return Value

The return value specifies the type of drive. It can be one of the following values:

Value	Meaning
0	The drive type cannot be determined.
1	The root directory does not exist.
DRIVE_REMOVABLE	The drive can be removed from the drive.
DRIVE_FIXED	The disk cannot be removed from the drive.
DRIVE_REMOTE	The drive is a remote (network) drive.
DRIVE_CDROM	The drive is a CD-ROM drive.
DRIVE_RAMDISK	The drive is a RAM disk.
See Also

GetDiskFreeSpace


GetEffectiveClientRect [New - Windows NT]
GetEffectiveClientRect  QuickInfo  Overview  Group

[New - Windows NT]

The GetEffectiveClientRect function calculates the dimensions of a rectangle in the client area. This function has limited utility.

void GetEffectiveClientRect(

HWND  hWnd,
LPRECT  lprc,
LPINT  lpInfo
);
Parameters

hWnd

Handle to the window that has the client area to check.

lprc

Pointer to a RECT structure that receives the dimensions of the rectangle.

lpInfo

Pointer to an array of 16-bit control identifiers for controls in the client area. Each control requires two array elements. The first element must be nonzero, and the second element must be the control identifier. The last element in the array must be zero.

Return Value

This function does not return a value.

See Also

RECT


GetEnhMetaFile
GetEnhMetaFile  QuickInfo  Overview  Group

The GetEnhMetaFile function creates a handle that identifies the enhanced-format metafile stored in the specified file.

HENHMETAFILE GetEnhMetaFile(

LPCTSTR  lpszMetaFile	// address of metafile name
);
Parameters

lpszMetaFile

Points to the null-terminated string that specifies the name of an enhanced metafile.

Return Value

If the function succeeds, the return value is a handle of the enhanced metafile.

If the function fails, the return value is NULL.

Remarks

When the application no longer needs an enhanced-metafile handle, it should delete the handle by calling the DeleteEnhMetaFile function.

A Windows-format metafile must be converted to the enhanced format before it can be processed by the GetEnhMetaFile function. To convert the file, use the SetWinMetaFileBits function.

Where text arguments must use Unicode characters, use this function as a wide-character function. Where text arguments must use characters from the Windows 3.x character set, use this function as an ANSI function.

Windows 95 only: The maximum length of the description string for an enhanced metafile is 16,384 bytes.

See Also

DeleteEnhMetaFile, GetEnhMetaFile, SetWinMetaFileBits


GetEnhMetaFileBits
GetEnhMetaFileBits  QuickInfo  Overview  Group

The GetEnhMetaFileBits function retrieves the contents of the specified enhanced-format metafile and copies them into a buffer.

UINT GetEnhMetaFileBits(

HENHMETAFILE  hemf,	// handle of metafile
UINT  cbBuffer,	// size of data buffer, in bytes
LPBYTE  lpbBuffer	// address of data buffer
);
Parameters

hemf

Identifies the enhanced metafile.

cbBuffer

Specifies the size, in bytes, of the buffer to receive the data.

lpbBuffer

Points to the buffer to receive the metafile data. The buffer must be sufficiently large to contain the data. If lpbBuffer is NULL, the function returns the size necessary to hold the data.

Return Value

If the function succeeds and the buffer pointer is NULL, the return value is the size of the enhanced metafile, in bytes.

If the function succeeds and the buffer pointer is a valid pointer, the return value is the number of bytes copied to the buffer.

If the function fails, the return value is zero.

Remarks

After the enhanced-metafile bits are retrieved, they can be used to create a memory-based metafile by calling the SetEnhMetaFileBits function.

The GetEnhMetaFileBits function does not invalidate the enhanced-metafile handle. The application must call the DeleteEnhMetaFile function to delete the handle when it is no longer needed.

The metafile contents retrieved by this function are in the enhanced format. To retrieve the metafile contents in the Windows format, use the GetWinMetaFileBits function.

See Also

DeleteEnhMetaFile, GetWinMetaFileBits, SetEnhMetaFileBits


GetEnhMetaFileDescription
GetEnhMetaFileDescription  QuickInfo  Overview  Group

The GetEnhMetaFileDescription function retrieves an optional text description from an enhanced-format metafile and copies the string to the specified buffer.

UINT GetEnhMetaFileDescription(

HENHMETAFILE  hemf,	// handle of enhanced metafile
UINT  cchBuffer,	// size of text buffer, in characters
LPTSTR  lpszDescription	// address of text buffer
);
Parameters

hemf

Identifies the enhanced metafile.

cchBuffer

Specifies the size, in characters, of the buffer to receive the data. Only this many characters will be copied.

lpszDescription

Points to the buffer to receive the optional text description.

Return Value

If the optional text description exists and the buffer pointer is NULL, the return value is the length of the text string, in characters.

If the optional text description exists and the buffer pointer is a valid pointer, the return value is the number of characters copied into the buffer.

If the optional text description does not exist, the return value is zero.

If the function fails, the return value is GDI_ERROR.

Remarks

The optional text description contains two strings, the first identifying the application that created the enhanced metafile and the second identifying the picture contained in the metafile. The strings are separated by a null character and terminated with two null characters — for example, "XYZ Graphics Editor\0Bald Eagle\0\0" where \0 represents the null character.

Where text arguments must use Unicode characters, use this function as a wide-character function. Where text arguments must use characters from the Windows 3.x character set, use this function as an ANSI function.

Windows 95 only: The maximum length of the description string for an enhanced metafile is 16,384 bytes.

See Also

CreateEnhMetaFile


GetEnhMetaFileHeader
GetEnhMetaFileHeader  QuickInfo  Overview  Group

The GetEnhMetaFileHeader function retrieves the record containing the header for the specified enhanced-format metafile.

UINT GetEnhMetaFileHeader(

HENHMETAFILE  hemf,	// handle of enhanced metafile
UINT  cbBuffer,	// size of buffer, in bytes
LPENHMETAHEADER  lpemh	// address of buffer to receive data
);
Parameters

hemf

Identifies the enhanced metafile for which the header is to be retrieved.

cbBuffer

Specifies the size, in bytes, of the buffer to receive the data. Only this many bytes will be copied.

lpemh

Points to an ENHMETAHEADER structure to receive the header record. If this parameter is NULL, the function returns the size of the header record.

Return Value

If the function succeeds and the structure pointer is NULL, the return value is the size of the record that contains the header; if the structure pointer is a valid pointer, the return value is the number of bytes copied. Otherwise, it is zero.

Remarks

An enhanced-metafile header contains such information as the metafile's size, in bytes; the dimensions of the picture stored in the metafile; the number of records stored in the metafile; the offset to the optional text description; the size of the optional palette, and the resolution of the device on which the picture was created.

The record that contains the enhanced-metafile header is always the first record in the metafile.

Windows 95 only: The maximum length of the description string for an enhanced metafile is 16,384 bytes.

See Also

ENHMETAHEADER, PlayEnhMetaFile


GetEnhMetaFilePaletteEntries
GetEnhMetaFilePaletteEntries  QuickInfo  Overview  Group

The GetEnhMetaFilePaletteEntries function retrieves optional palette entries from the specified enhanced metafile.

UINT GetEnhMetaFilePaletteEntries(

HENHMETAFILE  hemf,	// handle of enhanced metafile
UINT  cEntries,	// count of palette entries
LPPALETTEENTRY  lppe	// address of palette-entry array
);
Parameters

hemf

Identifies the enhanced metafile.

cEntries

Specifies the number of entries to be retrieved from the optional palette.

lppe

Points to an array of PALETTEENTRY structures to receive the palette colors. The array must contain at least as many structures as there are entries specified by the cEntries parameter.

Return Value

If the array pointer is NULL and the enhanced metafile contains an optional palette, the return value is the number of entries in the enhanced metafile's palette; if the array pointer is a valid pointer and the enhanced metafile contains an optional palette, the return value is the number of entries copied; if the metafile does not contain an optional palette, the return value is zero. Otherwise, the return value is GDI_ERROR.

Remarks

An application can store an optional palette in an enhanced metafile by calling the CreatePalette and SetPaletteEntries functions before creating the picture and storing it in the metafile. By doing this, the application can achieve consistent colors when the picture is displayed on a variety of devices.

An application that displays a picture stored in an enhanced metafile can call the GetEnhMetaFilePaletteEntries function to determine whether the optional palette exists. If it does, the application can call the GetEnhMetaFilePaletteEntries function a second time to retrieve the palette entries and then create a logical palette (by using the CreatePalette function), select it into its device context (by using the SelectPalette function), and then realize it (by using the RealizePalette function). After the logical palette has been realized, calling the PlayEnhMetaFile function displays the picture using its original colors.

See Also

CreatePalette, PALETTEENTRY, PlayEnhMetaFile, RealizePalette, SelectPalette


GetEnvironmentStrings
GetEnvironmentStrings  QuickInfo  Overview  Group

The GetEnvironmentStrings function returns the address of the environment block for the current process. This function replaces the GetDOSEnvironment function.

LPVOID GetEnvironmentStrings(VOID)

Parameters

This function has no parameters.

Return Value

The return value is a pointer to an environment block for the current process.

Remarks

Do not use the return value of GetEnvironmentStrings to get or set environment variables. Instead, use the GetEnvironmentVariable and SetEnvironmentVariable functions to access the environment variables within this block. When the block is no longer needed, it should be freed by calling FreeEnvironmentStrings.

A process can use this function's return value to specify the environment address used by the CreateProcess function.

See Also

CreateProcess, GetEnvironmentVariable, SetEnvironmentVariable, FreeEnvironmentStrings


GetEnvironmentVariable
GetEnvironmentVariable  QuickInfo  Overview  Group

The GetEnvironmentVariable function retrieves the value of the specified variable from the environment block of the calling process. The value is in the form of a null-terminated string of characters.

DWORD GetEnvironmentVariable(

LPCTSTR  lpName,	// address of environment variable name
LPTSTR  lpBuffer,	// address of buffer for variable value
DWORD  nSize	// size of buffer, in characters
);
Parameters

lpName

Points to a null-terminated string that specifies the environment variable.

lpBuffer

Points to a buffer to receive the value of the specified environment variable.

nSize

Specifies the size, in characters, of the buffer pointed to by the lpBuffer parameter.

Return Value

If the function succeeds, the return value is the number of characters stored into the buffer pointed to by lpBuffer, not including the terminating null character.

If the specified environment variable name was not found in the environment block for the current process, the return value is zero.

If the buffer pointed to by lpBuffer is not large enough, the return value is the buffer size, in characters, required to hold the value string and its terminating null character.

See Also

GetEnvironmentStrings, SetEnvironmentVariable


GetExceptionCode
GetExceptionCode  QuickInfo  Overview  Group

The GetExceptionCode function retrieves a code that identifies the type of exception that occurred. The function can be called only from within the filter expression or exception-handler block of a try-except exception handler.

DWORD GetExceptionCode(VOID)

Parameters

This function has no parameters.

Return Value

The return value identifies the type of exception. Following are the exception codes likely to occur due to common programming errors:

Value	Meaning
EXCEPTION_ACCESS_VIOLATION
	The thread attempted to read from or write to a virtual address for which it does not have the appropriate access.
EXCEPTION_BREAKPOINT
	A breakpoint was encountered.
EXCEPTION_DATATYPE_MISALIGNMENT
	The thread attempted to read or write data that is misaligned on hardware that does not provide alignment. For example, 16-bit values must be aligned on 2-byte boundaries, 32-bit values on 4-byte boundaries, and so on.
EXCEPTION_SINGLE_STEP
	A trace trap or other single-instruction mechanism signaled that one instruction has been executed.
EXCEPTION_ARRAY_BOUNDS_EXCEEDED
	The thread attempted to access an array element that is out of bounds, and the underlying hardware supports bounds checking.
EXCEPTION_FLT_DENORMAL_OPERAND
	One of the operands in a floating-point operation is denormal. A denormal value is one that is too small to represent as a standard floating-point value.
EXCEPTION_FLT_DIVIDE_BY_ZERO
	The thread attempted to divide a floating-point value by a floating-point divisor of zero.
EXCEPTION_FLT_INEXACT_RESULT
	The result of a floating-point operation cannot be represented exactly as a decimal fraction.
EXCEPTION_FLT_INVALID_OPERATION
	This exception represents any floating-point exception not included in this list.
EXCEPTION_FLT_OVERFLOW
	The exponent of a floating-point operation is greater than the magnitude allowed by the corresponding type.
EXCEPTION_FLT_STACK_CHECK
	The stack overflowed or underflowed as the result of a floating-point operation.
EXCEPTION_FLT_UNDERFLOW
	The exponent of a floating-point operation is less than the magnitude allowed by the corresponding type.
EXCEPTION_INT_DIVIDE_BY_ZERO
	The thread attempted to divide an integer value by an integer divisor of zero.
EXCEPTION_INT_OVERFLOW
	The result of an integer operation caused a carry out of the most significant bit of the result.
EXCEPTION_PRIV_INSTRUCTION
	The thread attempted to execute an instruction whose operation is not allowed in the current machine mode.
EXCEPTION_NONCONTINUABLE_EXCEPTION
	The thread attempted to continue execution after a noncontinuable exception occurred.
Remarks

The GetExceptionCode function can be called only from within the filter expression or exception-handler block of a try-except statement. The filter expression is evaluated if an exception occurs during execution of the try block, and it determines whether the except block is executed. The following example shows the structure of a try-except statement.

try {

    /* try block */

}

except (filter-expression) {

    /* exception handler block */

}

The filter expression can invoke a filter function. The filter function cannot call GetExceptionCode. However, the return value of GetExceptionCode can be passed as a parameter to a filter function. The return value of the GetExceptionInformation function can also be passed as a parameter to a filter function. GetExceptionInformation returns a pointer to a structure that includes the exception-code information.

In the case of nested try-except statements, each statement's filter expression is evaluated until one is evaluated as EXCEPTION_EXECUTE_HANDLER or EXCEPTION_CONTINUE_EXECUTION. Each filter expression can invoke GetExceptionCode to get the exception code.

The exception code returned is the code generated by a hardware exception, or the code specified in the RaiseException function for a software-generated exception.

See Also

GetExceptionInformation, RaiseException


GetExceptionInformation
GetExceptionInformation  QuickInfo  Overview  Group

The GetExceptionInformation function retrieves a machine-independent description of an exception, and information about the machine state that existed for the thread when the exception occurred. This function can be called only from within the filter expression of a try-except exception handler.

LPEXCEPTION_POINTERS GetExceptionInformation(VOID)

Parameters

This function has no parameters.

Return Value

The return value is a pointer to an EXCEPTION_POINTERS structure that contains pointers to two other structures: an EXCEPTION_RECORD structure containing a description of the exception, and a CONTEXT structure containing the machine-state information.

Remarks

The filter expression (from which the function is called) is evaluated if an exception occurs during execution of the try block, and it determines whether the except block is executed. The following example shows the structure of a try-except statement.

try {

    /* try block */

}

except (filter-expression) {

    /* exception handler block */

}

The filter expression can invoke a filter function. The filter function cannot call GetExceptionInformation. However, the return value of GetExceptionInformation can be passed as a parameter to a filter function.

To pass the EXCEPTION_POINTERS information to the exception-handler block, the filter expression or filter function must copy the pointer or the data to safe storage that the handler can later access.

In the case of nested try-except statements, each statement's filter expression is evaluated until one is evaluated as EXCEPTION_EXECUTE_HANDLER or EXCEPTION_CONTINUE_EXECUTION. Each filter expression can invoke GetExceptionInformation to get exception information.

See Also

CONTEXT, EXCEPTION_POINTERS, EXCEPTION_RECORD, GetExceptionCode


GetExitCodeProcess
GetExitCodeProcess  QuickInfo  Overview  Group

The GetExitCodeProcess function retrieves the termination status of the specified process.

BOOL GetExitCodeProcess(

HANDLE  hProcess,	// handle to the process
LPDWORD  lpExitCode	// address to receive termination status
);
Parameters

hProcess

Identifies the process. The handle must have PROCESS_QUERY_INFORMATION access.

lpExitCode

Points to a 32-bit variable to receive the process termination status.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

If the specified process has not terminated, the termination status returned is STILL_ACTIVE. If the process has terminated, the termination status returned may be one of the following:

•	The exit value specified in the ExitProcess or TerminateProcess function.

•	The return value from the main or WinMain function of the process.

•	The exception value for an unhandled exception that caused the process to terminate.

See Also

ExitProcess, ExitThread, TerminateProcess, WinMain


GetExitCodeThread
GetExitCodeThread  QuickInfo  Overview  Group

The GetExitCodeThread function retrieves the termination status of the specified thread.

BOOL GetExitCodeThread(

HANDLE  hThread,	// handle to the thread
LPDWORD  lpExitCode	// address to receive termination status
);
Parameters

hThread

Identifies the thread. The handle must have THREAD_QUERY_INFORMATION access.

lpExitCode

Points to a 32-bit variable to receive the thread termination status.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

If the specified thread has not terminated, the termination status returned is STILL_ACTIVE. If the thread has terminated, the termination status returned may be one of the following:

•	The exit value specified in the ExitThread or TerminateThread function.

•	The return value from the thread function.

•	The exit value of the thread's process.

See Also

ExitThread, GetExitCodeProcess, TerminateThread


GetExpandedName
GetExpandedName  QuickInfo  Overview  Group

The GetExpandedName function retrieves the original name of a compressed file, if the file was compressed by using the Microsoft File Compression Utility (COMPRESS.EXE) and the /r option was specified.

INT GetExpandedName(

LPTSTR  lpszSource,	// address of name of compressed file
LPTSTR  lpszBuffer	// address of buffer for original filename
);
Parameters

lpszSource

Points to a string that specifies the name of a compressed file.

lpszBuffer

Points to a buffer that receives the name of the compressed file.

Return Value

If the function succeeds, the return value is 1.

If the function fails, the return value is LZERROR_BADVALUE.

Note that GetExpandedName calls neither SetLastError nor SetLastErrorEx; thus, its failure does not affect a thread's last-error code.

Remarks

The contents of the buffer pointed to by the lpszBuffer parameter is the original filename if the file was compressed by using the /r option. If the /r option was not used, this function duplicates the name in the lpszSource parameter into the lpszBuffer buffer.


GetFileAttributes
GetFileAttributes  QuickInfo  Overview  Group

The GetFileAttributes function returns attributes for a specified file or directory.

DWORD GetFileAttributes(

LPCTSTR  lpFileName	// address of the name of a file or directory
);
Parameters

lpFileName

Points to a null-terminated string that specifies the name of a file or directory.

Windows NT

There is a default string size limit for paths of MAX_PATH characters. This limit is related to how the GetFileAttributes function parses paths. An application can transcend this limit and send in paths longer than MAX_PATH characters by calling the wide (W) version of GetFileAttributes and prepending "\\?\" to the path. The "\\?\" tells the function to turn off path parsing; it lets paths longer than MAX_PATH be used with GetFileAttributesW. This also works with UNC names. The "\\?\" is ignored as part of the path. For example, "\\?\C:\myworld\private" is seen as "C:\myworld\private", and "\\?\UNC\bill_g_1\hotstuff\coolapps" is seen as "\\bill_g_1\hotstuff\coolapps".

Windows 95

The lpFileName string must not exceed MAX_PATH characters. Windows 95 does not support the "\\?\" prefix.

Return Value

If the function succeeds, the return value contains the attributes of the specified file or directory.

If the function fails, the return value is 0xFFFFFFFF. To get extended error information, call GetLastError.

The attributes can be one or more of the following values:

Value	Meaning
FILE_ATTRIBUTE_ARCHIVE	The file or directory is an archive file or directory. Applications use this flag to mark files for backup or removal.
FILE_ATTRIBUTE_COMPRESSED	The file or directory is compressed. For a file, this means that all of the data in the file is compressed. For a directory, this means that compression is the default for newly created files and subdirectories.
FILE_ATTRIBUTE_DIRECTORY	The "file or directory" is a directory.
FILE_ATTRIBUTE_HIDDEN	The file or directory is hidden. It is not included in an ordinary directory listing.
FILE_ATTRIBUTE_NORMAL	The file or directory has no other attributes set. This attribute is valid only if used alone.
FILE_ATTRIBUTE_READONLY	The file or directory is read-only. Applications can read the file but cannot write to it or delete it. In the case of a directory, applications cannot delete it.
FILE_ATTRIBUTE_SYSTEM	The file or directory is part of, or is used exclusively by, the operating system.
See Also

DeviceIOControl, FindFirstFile, FindNextFile, SetFileAttributes


GetFileInformationByHandle
GetFileInformationByHandle  QuickInfo  Overview  Group

The GetFileInformationByHandle function retrieves information about the specified file.

BOOL GetFileInformationByHandle(

HANDLE  hFile,	// handle of file
LPBY_HANDLE_FILE_INFORMATION  lpFileInformation,	// address of structure
);
Parameters

hFile

Identifies the file for which information is returned.

lpFileInformation

Points to a BY_HANDLE_FILE_INFORMATION structure that receives the file information. The structure can be used in subsequent calls to GetFileInformationByHandle to refer to the information about the file.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Depending on the underlying network components of the operating system and the type of server connected to, the GetFileInformationByHandle function may fail, return partial information, or full information for the given file. In general, you should not use GetFileInformationByHandle unless your application is intended to be run on a limited set of operating system configurations.

See Also

BY_HANDLE_FILE_INFORMATION


GetFileResource
GetFileResource  Overview  Group

The GetFileResource function is not implemented in the Win32 API.


GetFileResourceSize
GetFileResourceSize  Overview  Group

The GetFileResourceSize function is is not implemented in the Win32 API.


GetFileSecurity
GetFileSecurity  QuickInfo  Overview  Group

The GetFileSecurity function obtains specified information about the security of a file or directory. The information obtained is constrained by the caller's access rights and privileges.

BOOL GetFileSecurity(

LPCTSTR  lpFileName,	// address of string for file name
SECURITY_INFORMATION  RequestedInformation,	// requested information
PSECURITY_DESCRIPTOR  pSecurityDescriptor,	// address of security descriptor
DWORD  nLength,	// size of security descriptor buffer
LPDWORD  lpnLengthNeeded	// address of required size of buffer
);
Parameters

lpFileName

Points to a null-terminated string specifying the file or directory for which security information is retrieved.

RequestedInformation

Specifies a SECURITY_INFORMATION structure that identifies the security information being requested.

pSecurityDescriptor

Points to a buffer that receives a copy of the security descriptor of the object specified by the lpFileName parameter. The calling process must have the right to view the specified aspects of the object's security status. The SECURITY_DESCRIPTOR structure is returned in self-relative format.

nLength

Specifies the size, in bytes, of the buffer pointed to by the pSecurityDescriptor parameter.

lpnLengthNeeded

Points to a variable the function sets to zero if the file descriptor is copied successfully. If the buffer is too small for the security descriptor, this variable receives the number of bytes required. If this variable's value is greater than that of the nLength parameter when the function returns, none of the security descriptor is copied to the buffer.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

In order to read the security descriptor of a file or directory, the calling process must have READ_CONTROL access or be the owner of the file or directory. Additionally, the caller must have the SE_SECURITY_NAME privilege to read the system access-control list.

See Also

GetKernelObjectSecurity, GetPrivateObjectSecurity, GetUserObjectSecurity, SECURITY_DESCRIPTOR, SECURITY_INFORMATION, SetFileSecurity


GetFileSize
GetFileSize  QuickInfo  Overview  Group

The GetFileSize function retrieves the size, in bytes, of the specified file.

DWORD GetFileSize(

HANDLE  hFile,	// handle of file to get size of
LPDWORD  lpFileSizeHigh,	// address of high-order word for file size
);
Parameters

hFile

Specifies an open handle of the file whose size is being returned. The handle must have been created with either GENERIC_READ or GENERIC_WRITE access to the file.

lpFileSizeHigh

Points to the variable where the high-order word of the file size is returned. This parameter can be NULL if the application does not require the high-order word.

Return Value

If the function succeeds, the return value is the low-order doubleword of the file size, and, if lpFileSizeHigh is non-NULL, the function puts the high-order doubleword of the file size into the variable pointed to by that parameter.

If the function fails and lpFileSizeHigh is NULL, the return value is 0xFFFFFFFF. To get extended error information, call GetLastError.

If the function fails and lpFileSizeHigh is non-NULL, the return value is 0xFFFFFFFF and GetLastError will return a value other than NO_ERROR.

Remarks

You cannot use the GetFileSize function with a handle of a nonseeking device such as a pipe or a communications device. To determine the file type for hFile, use the GetFileType function.

The GetFileSize function obtains the uncompressed size of a file. Use the GetCompressedFileSize function to obtain the compressed size of a file.

Note that if the return value is 0xFFFFFFFF and lpFileSizeHigh is non-NULL, an application must call GetLastError to determine whether the function has succeeded or failed. The following sample code illustrates this point:

//

// Case One: calling the function with

//           lpFileSizeHigh == NULL

// Try to obtain hFile's size

dwSize = GetFileSize (hFile, NULL) ;

// If we failed ...

if (dwSize == 0xFFFFFFFF) {

    // Obtain the error code.

    dwError = GetLastError() ;

    // Deal with that failure.

    .

    .

    .

    } // End of error handler

//

// Case Two: calling the function with

//           lpFileSizeHigh != NULL

// Try to obtain hFile's huge size.

dwSizeLow = GetFileSize (hFile, & dwSizeHigh) ;

// If we failed ...

if (dwSizeLow == 0xFFFFFFFF

    &&

    (dwError = GetLastError()) != NO_ERROR ){

    // Deal with that failure.

    .

    .

    .

    } // End of error handler.

See Also

GetCompressedFileSize, GetFileType


GetFileTime
GetFileTime  QuickInfo  Overview  Group

The GetFileTime function retrieves the date and time that a file was created, last accessed, and last modified.

BOOL GetFileTime(

HANDLE  hFile,	// identifies the file
LPFILETIME  lpCreationTime,	// address of creation time
LPFILETIME  lpLastAccessTime,	// address of last access time
LPFILETIME  lpLastWriteTime	// address of last write time
);
Parameters

hFile

Identifies the files for which to get dates and times. The file handle must have been created with GENERIC_READ access to the file.

lpCreationTime

Points to a FILETIME structure to receive the date and time the file was created. This parameter can be NULL if the application does not require this information.

lpLastAccessTime

Points to a FILETIME structure to receive the date and time the file was last accessed. The last access time includes the last time the file was written to, read from, or, in the case of executable files, run. This parameter can be NULL if the application does not require this information.

lpLastWriteTime

Points to a FILETIME structure to receive the date and time the file was last written to. This parameter can be NULL if the application does not require this information.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The FAT, NTFS, and HPFS file systems all support the file creation, last access, and last write time values.

Windows 95: The precision of the time for a file in a FAT file system is 2 seconds. The time precision for files in other file systems, such as those connected through a network depends on the file system but may also be limited by the remote device.

See Also

FILETIME, GetFileSize, GetFileType, SetFileTime


GetFileTitle
GetFileTitle  QuickInfo  Overview  Group

The GetFileTitle function returns the name of the file identified by the lpszFile parameter.

short GetFileTitle(

LPCTSTR  lpszFile,	// address of full path and filename for file
LPTSTR  lpszTitle,	// address of buffer that receives filename
WORD  cbBuf	// length of buffer
);
Parameters

lpszFile

Points to the name and location of a file.

lpszTitle

Points to a buffer into which the function is to copy the name of the file.

cbBuf

Specifies the length, in characters, of the buffer pointed to by the lpszTitle parameter.

Return Value

If the function succeeds, the return value is zero. If the filename is invalid, the return value is a negative number. If the buffer pointed to by the lpszTitle parameter is too small, the return value is a positive integer that specifies the required buffer size, in characters.

Remarks

GetFileTitle returns an error value if the buffer pointed to by the lpszFile parameter contains any of the following elements:

•	An empty string

•	A string containing a wildcard (*), opening bracket ([), or closing bracket (])

•	A string that ends with a colon (:), slash mark (/), or backslash (\)

•	A string whose length exceeded the length of the buffer

•	An invalid character (for example, a space or an unprintable character)

The required buffer size includes the terminating null character.

Note that sizes are specified and received as character counts, not bytes for UNICODE; the counts are valid for both the _A and _W versions of the function.

To get the buffer size needed for the name of a file, call the function with lpszTitle set to NULL and cbBuf set to zero. The function will return the required value.

Windows 95: On Windows 95, the GetFileTitle function retrieves the same text that the system would compose in displaying a filename to the user. This text is intended to be used for display purposes only and is in accordance with the user's preferences for display of filenames. There are two important implications of this enhancement. First, an application cannot expect to use the resultant text to call file system functions because it is merely a display name. Secondly, in preserving the function's "insufficient buffer" case, the return value for that codepath reflects the size of the text that would be composed in the normal case such that the caller may attempt to allocate sufficient storage and retrieve the result with a subsequent call to GetFileTitle. More generally, there is no guaranteed connection between the resultant text or return value and the characters in the original buffer passed by the application.

In porting applications to Windows 95, developers will need to update any code that relies on such behavior in previous versions of the operating system. The most common case is code that deliberately calls GetFileTitle with a NULL return buffer, passing size 0, and then uses the return value as an index into the original string. This technique is no longer supported. Applications can usually achieve similar results (and superior performance) with runtime library functions such as strrchr, wcsrchr, and _mbsrchr.

See Also

GetOpenFileName, GetSaveFileName


GetFileType
GetFileType  QuickInfo  Overview  Group

The GetFileType function returns the type of the specified file.

DWORD GetFileType(

HANDLE  hFile	// file handle
);
Parameters

hFile

Identifies an open file handle.

Return Value

The return value is one of the following values:

Value	Meaning
FILE_TYPE_UNKNOWN	The type of the specified file is unknown.
FILE_TYPE_DISK	The specified file is a disk file.
FILE_TYPE_CHAR	The specified file is a character file, typically an LPT device or a console.
FILE_TYPE_PIPE	The specified file is either a named or anonymous pipe.
See Also

GetFileSize, GetFileTime


GetFileVersionInfo
GetFileVersionInfo  QuickInfo  Overview  Group

The GetFileVersionInfo function returns version information about a specified file.

As with other file installation functions, GetFileVersionInfo works only with Win32 file images. It does not work with 16-bit Windows file images.

BOOL GetFileVersionInfo(

LPTSTR  lptstrFilename,	// pointer to filename string
DWORD  dwHandle,	// ignored
DWORD  dwLen,	// size of buffer
LPVOID  lpData	// pointer to buffer to receive file-version info.
);
Parameters

lptstrFilename

Pointer to a null-terminated filename string that specifies the file of interest.

dwHandle

This parameter is ignored.

dwLen

Specifies the size, in bytes, of the buffer pointed to by lpData.

Call the GetFileVersionInfoSize function to determine the size in bytes of a file's version information. dwLen should be equal to or greater than that value.

If the buffer pointed to by lpData is not large enough, the function truncates the file's-version information to the size of the buffer.

lpData

Pointer to a buffer to receive file-version information.

You can use this value in a subsequent call to the VerQueryValue function.

The file version information is always in Unicode format.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

GetFileVersionInfoSize, VerQueryValue, VS_VERSION_INFO


GetFileVersionInfoSize
GetFileVersionInfoSize  QuickInfo  Overview  Group

The GetFileVersionInfoSize function determines whether the operating system can obtain version information about a specified file. If version information is available, GetFileVersionInfoSize returns the size in bytes of that information.

As with other file installation functions, GetFileVersionInfo works only with Win32 file images. It does not work with 16-bit Windows file images.

DWORD GetFileVersionInfoSize(

LPTSTR  lptstrFilename,	// pointer to filename string
LPDWORD  lpdwHandle	// pointer to variable to receive zero
);
Parameters

lptstrFilename

Pointer to a null-terminated filename string that specifies the file of interest.

lpdwHandle

Pointer to a variable that the function sets to zero.

Return Value

If the function succeeds, the return value is the size in bytes of the file's version information.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

Call the GetFileVersionInfoSize function before calling the GetFileVersionInfo function.

See Also

GetFileVersionInfo, VerQueryValue


GetFocus
GetFocus  QuickInfo  Overview  Group

The GetFocus function retrieves the handle of the keyboard focus window associated with the thread that called the function.

HWND GetFocus(VOID)

Parameters

This function has no parameters.

Return Value

If the function succeeds, the return value is the handle of the keyboard focus window associated with the calling thread. If the calling thread does not contain a keyboard focus window, the return value is NULL.

Remarks

Although a return value of NULL means the calling thread does not have a keyboard focus window, another thread may have a keyboard focus window.

See Also

GetActiveWindow, GetCapture, SetFocus, WM_KILLFOCUS, WM_SETFOCUS


GetFontData
GetFontData  QuickInfo  Overview  Group

The GetFontData function retrieves font metric data for a TrueType font.

DWORD GetFontData(

HDC  hdc,	// handle of device context
DWORD  dwTable,	// metric table to query
DWORD  dwOffset,	// offset into table being queried
LPVOID  lpvBuffer,	// address of buffer for returned data
DWORD  cbData	// length of data to query
);
Parameters

hdc

Identifies the device context.

dwTable

Specifies the name of a font metric table from which the font data is to be retrieved. This parameter can identify one of the metric tables documented in the TrueType Font Files specification published by Microsoft Corporation. If this parameter is zero, the information is retrieved starting at the beginning of the font file.

dwOffset

Specifies the offset from the beginning of the font metric table to the location where the function should begin retrieving information. If this parameter is zero, the information is retrieved starting at the beginning of the table specified by the dwTable parameter. If this value is greater than or equal to the size of the table, an error occurs.

lpvBuffer

Points to a buffer to receive the font information. If this parameter is NULL, the function returns the size of the buffer required for the font data.

cbData

Specifies the length, in bytes, of the information to be retrieved. If this parameter is zero, GetFontData returns the size of the data specified in the dwTable parameter.

Return Value

If the function succeeds, the return value is the number of bytes returned.

If the function fails, the return value is GDI_ERROR.

Remarks

An application can sometimes use the GetFontData function to save a TrueType font with a document. To do this, the application determines whether the font can be embedded by checking the otmfsType member of the OUTLINETEXTMETRIC structure. If bit 1 of otmfsType is set, embedding is not permitted for the font. If bit 1 is clear, the font can be embedded. If bit 2 is set, the embedding is read-only. If embedding is permitted, the application can retrieve the entire font file, specifying zero for the dwTable, dwOffset, and cbData parameters.

If an application attempts to use this function to retrieve information for a non-TrueType font, an error occurs.

See Also

GetTextMetrics, OUTLINETEXTMETRIC


GetFontLanguageInfo [New - Windows 95]
GetFontLanguageInfo  QuickInfo

[New - Windows 95]

The GetFontLanguageInfo function returns information about the currently selected font for the specified display context. Applications typically use this information and the GetCharacterPlacement function to prepare a character string for display.

DWORD GetFontLanguageInfo(

HDC hdc	// handle to a device context
);
Parameters

hdc

Handle to a display context.

Return Value

The return value identifies characteristics of the currently selected font. The function returns 0 if the font is "normalized" and can be treated as a simple Latin font; it returns GCP_ERROR if an error occurs. Otherwise, the function returns a combination of the following values:

Value	Meaning
GCP_DBCS	The character set is DBCS.
GCP_DIACRITIC	The font/language contains diacritic glyphs
FLI_GLYPHS	The font contains extra glyphs not normally accessible using the codepage. Use GetCharacterPlacement to access the glyphs. This value is for information only and is not intended to be passed to GetCharacterPlacement.
GCP_GLYPHSHAPE	The font/language contains multiple glyphs per code point or per code point combination (supports shaping and/or ligation), and the font contains advanced glyph tables to provide extra glyphs for the extra shapes. If this value is given, the lpGlyphs array must be used with the GetCharacterPlacement function and the ETO_GLYPHINDEX value must be passed to the ExtTextOut function when the string is drawn.
GCP_KASHIDA	The font/ language permits Kashidas.
GCP_LIGATE	The font/language contains ligation glyphs which can be substituted for specific character combinations.
GCP_USEKERNING	The font contains a kerning table which can be used to provide better spacing between the characters and glyphs.
GCP_REORDER	The language requires reordering for display--for example, Hebrew or Arabic.
The return value, when masked with FLI_MASK, can be passed directly to the GetCharacterPlacement function.

See Also

ExtTextOut, GetCharacterPlacement


GetForegroundWindow
GetForegroundWindow  QuickInfo  Overview  Group

The GetForegroundWindow function returns the handle of the foreground window (the window with which the user is currently working). The system assigns a slightly higher priority to the thread that creates the foreground window than it does to other threads.

HWND GetForegroundWindow(VOID)

Parameters

This function has no parameters.

Return Value

The return value is the handle of the foreground window.

See Also

SetForegroundWindow


GetForm
GetForm  QuickInfo  Overview  Group

The GetForm function initializes a FORM_INFO_1 structure with data describing the specified form for a printer.

BOOL GetForm(

HANDLE  hPrinter,	// handle of printer
LPTSTR  pFormName,	// address of form name
DWORD  Level,	// structure level
LPBYTE  pForm,	// address of structure array
DWORD  cbBuf,	// count of bytes in array
LPDWORD  pcbNeeded	// addr. of variable with count of bytes retrieved (or required)
);
Parameters

hPrinter

Identifies the printer.

pFormName

Points to a null-terminated string that specifies the name of the form.

Level

Specifies the version of the structure to which pForm points. This value must be 1.

pForm

Points to an array of bytes that receives the initialized FORM_INFO_1 structure.

cbBuf

Specifies the size, in bytes, of the pForm array.

pcbNeeded

Points to a value that specifies the number of bytes copied if the function succeeds or the number of bytes required if cbBuf is too small.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The printer handle hPrinter is obtained by calling the OpenPrinter function.

See Also

AddForm, DeleteForm, OpenPrinter


GetFreeSpace
GetFreeSpace  QuickInfo  Overview  Group

The GetFreeSpace function is obsolete. It is provided to simplify porting of 16-bit Windows-based applications. Win32-based applications should use the GlobalMemoryStatus function.

DWORD GetFreeSpace(     WORD  w	// amount of free space
);


GetFullPathName
GetFullPathName  QuickInfo  Overview  Group

The GetFullPathName function retrieves the full path and filename of a specified file.

DWORD GetFullPathName(

LPCTSTR  lpFileName,	// address of name of file to find path for
DWORD  nBufferLength,	// size, in characters, of path buffer
LPTSTR  lpBuffer,	// address of path buffer
LPTSTR  *lpFilePart	// address of filename in path
);
Parameters

lpFileName

Points to a null-terminated string that specifies a valid filename. This string can use either short (the 8.3 form) or long filenames.

nBufferLength

Specifies the size, in characters, of the buffer for the drive and path.

lpBuffer

Points to a buffer that contains the null-terminated string for the name of the drive and path.

lpFilePart

Points to a variable that receives the address (in lpBuffer) of the final filename component in the path. This filename component is the long filename, if any, rather than the 8.3 form of the filename.

Return Value

If the GetFullPathName function succeeds, the return value is the length, in characters, of the string copied to lpBuffer, not including the terminating null character.

If the lpBuffer buffer is too small, the return value is the size of the buffer, in characters, required to hold the path.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

The GetFullPathName function merges the name of the current drive and directory with the specified filename to determine the full path and filename of the specified file. It also calculates the address of the filename portion of the full path and filename. This function does not verify that the resulting path and filename are valid or that they refer to an existing file on the associated volume.

See Also

GetShortPathName, GetTempPath, SearchPath


GetGlyphOutline
GetGlyphOutline  QuickInfo  Overview  Group

The GetGlyphOutline function retrieves the outline or bitmap for a character in the TrueType font that is selected into the specified device context.

DWORD GetGlyphOutline(

HDC  hdc,	// handle of device context
UINT  uChar,	// character to query
UINT  uFormat,	// format of data to return
LPGLYPHMETRICS  lpgm,	// address of structure for metrics
DWORD  cbBuffer,	// size of buffer for data
LPVOID  lpvBuffer,	// address of buffer for data
CONST MAT2 *  lpmat2	// address of transformation matrix structure
);
Parameters

hdc

Identifies the device context.

uChar

Specifies the character for which data is to be returned.

uFormat

Specifies the format in which the function returns the data. It can be one of the following values:

Value	Meaning
GGO_BITMAP	Returns the glyph bitmap. For information about memory allocation, see the following Remarks section.
GGO_NATIVE	Returns the curve data points in the rasterizer's native format and uses the font's design units. When this value is specified, any transformation specified in the lpMatrix parameter is ignored.
GGO_METRICS	Returns only the GLYPHMETRICS structure specified by lpgm. The other buffers are ignored. This value affects the meaning of the function's return value upon failure; see the following Return Value section.
lpgm

Points to the GLYPHMETRICS structure describing the placement of the glyph in the character cell.

cbBuffer

Specifies the size of the buffer where the function is to copy information about the outline character. If this value is zero, the function returns the required size of the buffer.

lpvBuffer

Points to the buffer where the function is to copy information about the outline character. If this value is NULL, the function returns the required size of the buffer.

lpmat2

Points to a MAT2 structure specifying a transformation matrix for the character.

Return Value

If GGO_BITMAP or GGO_NATIVE is specified, and the function succeeds, the return value is greater than zero; otherwise, the return value is GDI_ERROR. If one of these flags is specified, and the buffer size or address is zero, the return value specifies the required buffer size, in bytes.

If GGO_METRICS is specified, and the function fails, the return value is GDI_ERROR.

Remarks

The glyph outline returned by the GetGlyphOutline function is for a grid-fitted glyph. (A grid-fitted glyph is a glyph that has been modified so that its bitmapped image conforms as closely as possible to the original design of the glyph.) If an application needs an unmodified glyph outline, it can request the glyph outline for a character in a font whose size is equal to the font's em unit. The value for a font's em unit is stored in the otmEMSquare member of the OUTLINETEXTMETRIC structure.

The glyph bitmap returned by the GetGlyphOutline function when GGO_BITMAP is specified is a doubleword-aligned, row-oriented monochrome bitmap.

An application can rotate characters retrieved in bitmap format by specifying a 2-by-2 transformation matrix in the lpMatrix parameter.

See Also

FORM_INFO_1, GetOutlineTextMetrics, GLYPHMETRICS, MAT2, OUTLINETEXTMETRIC, POINT


GetGraphicsMode
GetGraphicsMode  QuickInfo  Overview  Group

The GetGraphicsMode function retrieves the current graphics mode for the specified device context.

int GetGraphicsMode(

HDC  hdc	// handle of device context
);
Parameters

hdc

Identifies the device context.

Return Value

If the function succeeds, the return value is the current graphics mode. It can be one of the following values:

Value	Meaning
GM_COMPATIBLE	The current graphics mode is the compatible graphics mode, a mode that is compatible with Windows version 3.1. In this graphics mode, an application cannot set or modify the world transformation for the specified device context. The compatible graphics mode is the default graphics mode.
GM_ADVANCED	Windows NT: The current graphics mode is the advanced graphics mode, a mode that allows world transformations. In this graphics mode, an application can set or modify the world transformation for the specified device context. Windows 95: The GM_ADVANCED value is not supported.
Otherwise, the return value is zero.

Remarks

An application can set the graphics mode for a device context by calling the SetGraphicsMode function.

See Also

SetGraphicsMode


GetHandleInformation [New - Windows NT]
GetHandleInformation  QuickInfo  Overview  Group

[New - Windows NT]

The GetHandleInformation function obtains information about certain properties of an object handle. The information is obtained as a set of bit flags.

BOOL GetHandleInformation (

HANDLE  hObject,	// handle to an object
LPDWORD  lpdwFlags	// points to variable to receive flags
);
Parameters

hObject

Specifies a handle to an object. The GetHandleInformation function obtains information about this object handle.

lpdwFlags

Points to a variable to receive a set of bit flags that specify properties of the object handle. The following flags are defined:

Value	Meaning
HANDLE_FLAG_INHERIT	If this flag is set, a child process created with the bInheritHandles parameter of CreateProcess set to TRUE will inherit the object handle.
HANDLE_FLAG_PROTECT_FROM_CLOSE	If this flag is set, calling the CloseHandle function will not close the object handle.
Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

CloseHandle, CreateProcess, SetHandleInformation


gethostbyaddr
gethostbyadd  QuickInfor

The Windows Sockets gethostbyaddr function gets host information corresponding to an address.

struct hostent FAR * gethostbyaddr (

const char FAR * addr,
int len,
int type
);
Parameters

addr

A pointer to an address in network byte order.

len

The length of the address, which must be 4 for PF_INET addresses.

type

The type of the address, which must be PF_INET.

Return Value

If the function succeeds, gethostbyaddr returns a pointer to the hostent structure previously described.

If the function fails, it returns a NULL pointer. To get extended error information, call WSAGetLastError.

Error Codes

WSANOTINITIALISED	A successful WSAStartup must occur before using this function.
WSAENETDOWN	The Windows Sockets implementation has detected that the network subsystem has failed.
WSAHOST_NOT_FOUND	Authoritative Answer Host not found.
WSATRY_AGAIN	Non-Authoritative Host not found, or SERVERFAIL.
WSANO_RECOVERY	Nonrecoverable errors: FORMERR, REFUSED, NOTIMP.
WSANO_DATA	Valid name, no data record of requested type.
WSAEINPROGRESS	A blocking Windows Sockets operation is in progress.
WSAEINTR	The (blocking) call was canceled using WSACancelBlockingCall.
Remarks

The gethostbyaddr function returns a pointer to the following structure, which contains the name(s) and address which correspond to the specified address.

struct hostent {

    char FAR *       h_name;

    char FAR * FAR * h_aliases;

    short            h_addrtype;

    short            h_length;

    char FAR * FAR * h_addr_list;

};

The members of this structure are:

Member	Usage
h_name	Official name of the host (PC).
h_aliases	A NULL-terminated array of alternate names.
h_addrtype	The type of address being returned; for Windows Sockets this is always PF_INET.
h_length	The length, in bytes, of each address; for PF_INET, this is always 4.
h_addr_list	A NULL-terminated list of addresses for the host. Addresses are returned in network byte order.
The macro h_addr is defined to be h_addr_list[0] for compatibility with older software.

The pointer that is returned points to a structure allocated by the Windows Sockets implementation. The application must never attempt to modify this structure or to free any of its components. Furthermore, only one copy of this structure is allocated per thread, and so the application should copy any information it needs before issuing any other Windows Sockets function calls.

See Also

gethostbyname, WSAAsyncGetHostByAddr, WSACancelBlockingCall, WSAStartup


gethostbyname
gethostbynam  QuickInfoe

The Windows Sockets gethostbyname function gets host information corresponding to a host name.

struct hostent FAR * gethostbyname (

const char FAR * name
);
Parameters

name

A pointer to the name of the host.

Return Value

If the function succeeds, gethostbyname returns a pointer to the hostent structure described above.

If the function fails, it returns a NULL pointer. To get extended error information, call WSAGetLastError.

Error Codes

WSANOTINITIALISED	A successful WSAStartup must occur before using this function.
WSAENETDOWN	The Windows Sockets implementation has detected that the network subsystem has failed.
WSAHOST_NOT_FOUND	Authoritative Answer Host not found.
WSATRY_AGAIN	Non-Authoritative Host not found, or SERVERFAIL.
WSANO_RECOVERY	Nonrecoverable errors: FORMERR, REFUSED, NOTIMP.
WSANO_DATA	Valid name, no data record of requested type.
WSAEINPROGRESS	A blocking Windows Sockets operation is in progress.
WSAEINTR	The (blocking) call was canceled using WSACancelBlockingCall.
Remarks

The gethostbyname function returns a pointer to a hostent structure as described under gethostbyaddr. The contents of this structure correspond to the host name name.

The pointer that is returned points to a structure allocated by the Windows Sockets implementation. The application must never attempt to modify this structure or to free any of its components. Furthermore, only one copy of this structure is allocated per thread, and so the application should copy any information which it needs before issuing any other Windows Sockets function calls.

A gethostbyname implementation must not resolve IP address strings passed to it. Such a request should be treated exactly as if an unknown host name were passed. An application with an IP address string to resolve should use inet_addr to convert the string to an IP address, then gethostbyaddr to obtain the hostent structure.

See Also

gethostbyaddr, inet_addr, WSAAsyncGetHostByName, WSACancelBlockingCall, WSAStartup


gethostname
gethostname  QuickInfo

The Windows Sockets gethostname function returns the standard host name for the local computer.

int PASCAL FAR gethostname (

char FAR * name,
int namelen
);
Parameters

name

A pointer to a buffer that will receive the host name.

namelen

The length of the buffer.

Return Value

If the function succeeds, gethostname returns zero.

If the function fails, it returns SOCKET_ERROR. To get extended error information, call WSAGetLastError.

Error Codes

WSAEFAULT	The namelen parameter is too small.
WSANOTINITIALISED	A successful WSAStartup must occur before using this function.
WSAENETDOWN	The Windows Sockets implementation has detected that the network subsystem has failed.
WSAEINPROGRESS	A blocking Windows Sockets operation is in progress.
Remarks

This function returns the name of the local host into the buffer specified by the name parameter. The host name is returned as a null-terminated string. The form of the host name is dependent on the Windows Sockets implementation — it may be a simple host name, or it may be a fully qualified domain name. However, it is guaranteed that the name returned will be successfully parsed by gethostbyname and WSAAsyncGetHostByName.

See Also

gethostbyname, WSAAsyncGetHostByName, WSAStartup


GetICMProfile [New - Windows 95]
GetICMProfile  QuickInfo  Overview  Group

[New - Windows 95]

The GetICMProfile function retrieves the name of the color profile file for the device associated with the specified device context.

BOOL GetICMProfile(

HDC  hdc,
DWORD  cbName,
LPTSTR  lpszFilename
);
Parameters

hdc

Handle to the device context.

cbName

Size, in bytes or characters, of the buffer that receives the filename, depending on whether the ANSI or Unicode version of the function is used.

lpszFilename

Pointer to the buffer that receives the null-terminated string specifying the full path of the color profile file.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

GetICMProfile fails if image color matching has not been enabled for the specified device context.


GetIconInfo
GetIconInfo  QuickInfo  Overview  Group

The GetIconInfo function retrieves information about the specified icon or cursor.

BOOL GetIconInfo(

HICON  hIcon,	// icon handle
PICONINFO  piconinfo	// address of icon structure
);
Parameters

hIcon

Identifies the icon or cursor. To retrieve information about a standard icon or cursor, specify one of the following values:

Value	Meaning
IDC_ARROW	Arrow cursor
IDC_IBEAM	I-beam cursor
IDC_WAIT	Hourglass cursor
IDC_CROSS	Crosshair cursor
IDC_UPARROW	Up arrow cursor
IDC_SIZENWSE	Sizing cursor, points northwest and southeast
IDC_SIZENESW	Sizeing cursor, points northeast and southwest
IDC_SIZEWE	Sizing cursor, points west and east
IDC_SIZENS	Sizing cursor, points north and south
IDC_SIZEALL	Sizing cursor, points north, south, east, and west
IDC_NO	"No" cursor
IDC_APPSTARTING	Application-starting cursor (arrow and hourglass)
IDC_HELP	Help cursor (arrow and question mark)
IDI_APPLICATION	Application icon
IDI_HAND	Stop sign icon
IDI_QUESTION	Question-mark icon
IDI_EXCLAMATION	Exclamation point icon
IDI_ASTERISK	Asterisk icon (letter "i" in a circle)
IDI_WINLOGO	Windows logo icon
piconinfo

Points to an ICONINFO structure. The function fills in the structure's members.

Return Value

If the function succeeds, the return value is TRUE and the function fills in the members of the specified ICONINFO structure.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

GetIconInfo creates bitmaps for the hbmMask and hbmColor members of ICONINFO. The calling application must manage these bitmaps and delete them when they are no longer necessary.

See Also

CreateIcon, CreateIconFromResource, CreateIconIndirect, DestroyIcon, DrawIcon, DrawIconEx, ICONINFO, LoadIcon, LookupIconIdFromDirectory


GetInputState
GetInputState  QuickInfo  Overview  Group

The GetInputState function determines whether there are mouse-button or keyboard messages in the calling thread's message queue.

BOOL GetInputState(VOID)

Parameters

This function has no parameters.

Return Value

If the queue contains one or more new mouse-button or keyboard messages, the return value is TRUE.

If the function fails, the return value is FALSE.

See Also

GetQueueStatus


GetInstanceData
GetInstanceData  Overview  Group

The GetInstanceData function is not implemented in the Win32 API. Each Win32-based application runs in its own address space.


GetJob
GetJob  QuickInfo  Overview  Group

The GetJob function retrieves print-job data for the specified printer.

BOOL GetJob(

HANDLE  hPrinter,	// handle of printer
DWORD  JobId,	// job identifier value
DWORD  Level,	// data-structure level
LPBYTE  pJob,	// address of data-structure array
DWORD  cbBuf,	// count of bytes in array
LPDWORD  pcbNeeded	// address of value that contains count of bytes retrieved (or required)
);
Parameters

hPrinter

Identifies the printer for which the print-job data is retrieved.

JobId

Identifies the print job for which data should be retrieved.

Level

Specifies the level of the structure to which pJob points. This value must be either 1 or 2.

pJob

Points to an array that contains either a JOB_INFO_1 or a JOB_INFO_2 structure. If Level is 1, this function stores the data in a JOB_INFO_1 structure; if Level is 2, this function stores the data in a JOB_INFO_2 structure.

cbBuf

Specifies the size, in bytes, of the array.

pcbNeeded

Points to a value that specifies the number of bytes copied if the function succeeds or the number of bytes required if cbBuf is too small.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

AddJob, JOB_INFO_1, JOB_INFO_2, ScheduleJob, SetJob


GetKBCodePage
GetKBCodePage  QuickInfo  Overview  Group

The GetKBCodePage function is provided for compatibility with earlier versions of Windows. In the Win32 application programming interface (API) it just calls the GetOEMCP function. New applications should use the GetOEMCP function.

UINT GetKBCodePage(VOID)

Parameters

This function has no parameters.

Return Value

If the function succeeds, the return value is an OEM code-page identifier, or it is the default identifier if the registry value is not readable. For a list of OEM code-page identifiers, see GetOEMCP.

See Also

GetACP, GetOEMCP


GetKernelObjectSecurity
GetKernelObjectSecurity  QuickInfo  Overview  Group

The GetKernelObjectSecurity function retrieves a copy of the security descriptor protecting a kernel object.

BOOL GetKernelObjectSecurity(

HANDLE  Handle,	// handle of object to query
SECURITY_INFORMATION  RequestedInformation,	// requested information
PSECURITY_DESCRIPTOR  pSecurityDescriptor,	// address of security descriptor
DWORD  nLength,	// size of buffer for security descriptor
LPDWORD  lpnLengthNeeded	// address of required size of buffer
);
Parameters

Handle

Identifies a kernel object.

RequestedInformation

Specifies a SECURITY_INFORMATION structure that identifies the security information being requested.

pSecurityDescriptor

Points to a buffer the function fills with a copy of the security descriptor of the specified object. The calling process must have the right to view the specified aspects of the object's security status. The SECURITY_DESCRIPTOR structure is returned in self-relative format.

nLength

Specifies the size, in bytes, of the buffer pointed to by the pSecurityDescriptor parameter.

lpnLengthNeeded

Points to a variable the function sets to zero if the descriptor is copied successfully. If the buffer is too small for the security descriptor, this variable receives the number of bytes required. If this variable's value is greater than the value of the nLength parameter when the function returns, none of the security descriptor is copied to the buffer.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

To read the kernel object's security descriptor, the calling process must be either granted READ_CONTROL access or be the object's owner. In addition, the calling process must have the SE_SECURITY_NAME privilege to read the system access-control list.

See Also

GetFileSecurity, GetPrivateObjectSecurity, GetUserObjectSecurity, SECURITY_DESCRIPTOR, SECURITY_INFORMATION, SetKernelObjectSecurity


GetKerningPairs
GetKerningPairs  QuickInfo  Overview  Group

The GetKerningPairs function retrieves the character-kerning pairs for the currently selected font for the specified device context.

DWORD GetKerningPairs(

HDC  hdc,	// handle of device context
DWORD  nNumPairs,	// number of kerning-pairs to be retrieved
LPKERNINGPAIR  lpkrnpair	// address of kerning-pair array
);
Parameters

hdc

Identifies the device context.

nNumPairs

Specifies the number of pairs that fit in the lpkrnpair array. If the font has more than nNumPairs kerning pairs, an error is returned.

lpkrnpair

Points to an array of KERNINGPAIR structures to receive the kerning pairs. The array must contain at least as many structures as specified by the nNumPairs parameter. If this parameter is NULL, the function returns the total number of kerning pairs for the font.

Return Value

If the function succeeds, the return value is the number of kerning pairs returned.

If the function fails, the return value is zero.

See Also

KERNINGPAIR


GetKeyboardLayout [New - Windows 95]
GetKeyboardLayout  QuickInfo

[New - Windows 95]

The GetKeyboardLayout function retrieves the active keyboard layout for a specified thread. If the dwLayout parameter is zero, the layout for the active thread is returned.

HKL GetKeyboardLayout(

DWORD dwLayout	// thread identifier
);
Parameters

dwLayout

Identifies the thread to query or is zero for the current thread.

Return Value

The return value is the keyboard layout handle for the thread. The low word contains a locale identifier identifying the input language and the high word contains a device handle identifying the physical layout of the keyboard.

See Also

ActivateKeyboardLayout, CreateThread, LoadKeyboardLayout


GetKeyboardLayoutList [New - Windows 95]
GetKeyboardLayoutList  QuickInfo

[New - Windows 95]

The GetKeyboardLayoutList function retrieves the keyboard layout handles corresponding to the current set of input locales in the system. The function copies the handles to the given buffer.

UINT GetKeyboardLayoutList(

int nBuff,	// size of buffer in array element
HKL FAR * lpList	// buffer for keyboard layout handles
);
Parameters

nBuff

Specifies the maximum number of handles that the buffer can hold.

lpList

Points to the buffer, an array, that receives the keyboard layout handles.

Return Value

If the function succeeds, the return value is the number of layout handles copied to the buffer or, if nBuff is zero, the return value is the size, in array elements, of the buffer needed to receive all current layout handles.

See Also

GetKeyboardLayout


GetKeyboardLayoutName
GetKeyboardLayoutName  QuickInfo  Overview  Group

The GetKeyboardLayoutName function retrieves the name of the active keyboard layout.

BOOL GetKeyboardLayoutName(

LPTSTR  pwszKLID	// address of buffer for layout name
);
Parameters

pwszKLID

Points to the buffer of at least KL_NAMELENGTH characters that is to receive the name of the keyboard layout, including the NULL terminator. This will be a copy of the string provided to the LoadKeyboardLayout function, unless layout substitution took place.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Windows NT:

GetKeyboardLayoutName gets the name of the active keyboard layout for the system.

Windows 95:

GetKeyboardLayoutName gets the name of the active keyboard layout for the calling thread.

See Also

ActivateKeyboardLayout, LoadKeyboardLayout, UnloadKeyboardLayout


GetKeyboardState
GetKeyboardState  QuickInfo  Overview  Group

The GetKeyboardState function copies the status of the 256 virtual keys to the specified buffer.

BOOL GetKeyboardState(

PBYTE  lpKeyState	// address of array to receive status data
);
Parameters

lpKeyState

Points to the 256-byte array that will receive the status data for each virtual key.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

An application can call this function to retrieve the current status of all the virtual keys. The status changes as a thread removes keyboard messages from its message queue. The status does not change as keyboard messages are posted to the message queue.

When the function returns, each member of the array pointed to by the lpKeyState parameter contains status data for a virtual key. If the high-order bit is 1, the key is down; otherwise, it is up. If the low-order bit is 1, the key is toggled. A key, such as the CAPS LOCK key, is toggled if it is turned on. The key is off and untoggled if the low-order bit is 0. A toggle key's indicator light (if any) on the keyboard will be on when the key is toggled, and off when the key is untoggled.

To retrieve status information for an individual key, use the GetKeyState function.

An application can use the virtual-key code constants VK_SHIFT, VK_CONTROL and VK_MENU as indices into the array pointed to by lpKeyState. This gives the status of the SHIFT, CTRL, or ALT keys without distinguishing between left and right. An application can also use the following virtual-key code constants as indices to distinguish between the left and right instances of those keys:

VK_LSHIFT	VK_RSHIFT
VK_LCONTROL	VK_RCONTROL
VK_LMENU	VK_RMENU
These left- and right-distinguishing constants are available to an application only through the GetKeyboardState, SetKeyboardState, GetAsyncKeyState, GetKeyState, and MapVirtualKey functions.

See Also

GetKeyState, GetAsyncKeyState, MapVirtualKey, SetKeyboardState


GetKeyboardType
GetKeyboardType  QuickInfo  Overview  Group

The GetKeyboardType function retrieves information about the current keyboard.

int GetKeyboardType(

int  nTypeFlag	// type of information to retrieve
);
Parameters

nTypeFlag

Specifies the type of keyboard information to be retrieved. This parameter can be one of the following values:

Value	Meaning
0	Keyboard type
1	Keyboard subtype
2	Number of function keys on the keyboard
Return Value

If the function succeeds, the return value specifies the requested information.

If the function fails, the return value is zero.

Remarks

The subtype is an original equipment manufacturer (OEM)-dependent value. The type may be one of the following values:

Value	Meaning
1	IBM® PC/XT® ( ) or compatible (83-key) keyboard
2	Olivetti® "ICO" (102-key) keyboard
3	IBM PC/AT® (84-key) or similar keyboard
4	IBM enhanced (101- or 102-key) keyboard
5	Nokia® 1050 and similar keyboards
6	Nokia 9140 and similar keyboards
7	Japanese keyboard
The application can also determine the number of function keys on a keyboard from the keyboard type. Following are the number of function keys for each keyboard type:

Type	Number of function keys
1	10
2	12 (sometimes 18)
3	10
4	12
5	10
6	24
7	Hardware dependent and specified by the OEM


GetKeyNameText
GetKeyNameText  QuickInfo  Overview  Group

The GetKeyNameText function retrieves a string that represents the name of a key.

int GetKeyNameText(

LONG  lParam,	// second parameter of keyboard message
LPTSTR  lpString,	// address of buffer for key name
int  nSize	// maximum length of key-name string length
);
Parameters

lParam

Specifies the second parameter of the keyboard message (such as WM_KEYDOWN) to be processed. The function interprets the following portions of lParam:

Bits	Meaning
16−23	Scan code.
24	Extended-key flag. Distinguishes some keys on an enhanced keyboard.
25	"Don't care" bit. The application calling this function sets this bit to indicate that the function should not distinguish between left and right CTRL and SHIFT keys, for example.
lpString

Points to a buffer that will receive the key name.

nSize

Specifies the maximum length, in characters, of the key name, including the terminating null character. (This parameter should be equal to the size of the buffer pointed to by the lpString parameter.)

Return Value

If the function succeeds, a null-terminated string is copied into the specified buffer, and the return value is the length of the string, in characters, not counting the terminating null character.

Remarks

The format of the key-name string depends on the current keyboard layout. The keyboard driver maintains a list of names in the form of character strings for keys with names longer than a single character. The key name is translated according to the layout of the currently installed keyboard. The name of a character key is the character itself. The names of dead keys are spelled out in full.


GetKeyState
GetKeyState  QuickInfo  Overview  Group

The GetKeyState function retrieves the status of the specified virtual key. The status specifies whether the key is up, down, or toggled (on, off — alternating each time the key is pressed).

SHORT GetKeyState(

int  nVirtKey	// virtual-key code
);
Parameters

nVirtKey

Specifies a virtual key. If the desired virtual key is a letter or digit (A through Z, a through z, or 0 through 9), nVirtKey must be set to the ASCII value of that character. For other keys, it must be a virtual-key code.

If a non-English keyboard layout is used, virtual keys with values in the range ASCII A through Z and 0 through 9 are used to specify most of the character keys. For example, for the German keyboard layout, the virtual key of value ASCII O (0x4F) refers to the "o" key, whereas VK_OEM_1 refers to the "o with umlaut" key.

Return Value

If the function succeeds, the return value specifies the status of the given virtual key. If the high-order bit is 1, the key is down; otherwise, it is up. If the low-order bit is 1, the key is toggled. A key, such as the CAPS LOCK key, is toggled if it is turned on. The key is off and untoggled if the low-order bit is 0. A toggle key's indicator light (if any) on the keyboard will be on when the key is toggled, and off when the key is untoggled.

Remarks

The key status returned from this function changes as a given thread reads key messages from its message queue. The status does not reflect the interrupt-level state associated with the hardware. Use the GetAsyncKeyState function to retrieve that information.

An application calls GetKeyState in response to a keyboard-input message. This function retrieves the state of the key when the input message was generated.

To retrieve state information for all the virtual keys, use the GetKeyboardState function.

An application can use the virtual-key code constants VK_SHIFT, VK_CONTROL, and VK_MENU as values for the nVirtKey parameter. This gives the status of the SHIFT, CTRL, or ALT keys without distinguishing between left and right. An application can also use the following virtual-key code constants as values for nVirtKey to distinguish between the left and right instances of those keys:

VK_LSHIFT	VK_RSHIFT
VK_LCONTROL	VK_RCONTROL
VK_LMENU	VK_RMENU
These left- and right-distinguishing constants are available to an application only through the GetKeyboardState, SetKeyboardState, GetAsyncKeyState, GetKeyState, and MapVirtualKey functions.

See Also

GetAsyncKeyState, GetKeyboardState, MapVirtualKey, SetKeyboardState


GetLargestConsoleWindowSize
GetLargestConsoleWindowSize  QuickInfo  Overview  Group

The GetLargestConsoleWindowSize function returns the size of the largest possible console window, based on the current font and the size of the display.

COORD GetLargestConsoleWindowSize(

HANDLE  hConsoleOutput	// handle of console screen buffer
);
Parameters

hConsoleOutput

Identifies a console screen buffer.

Return Value

If the function succeeds, the return value is a COORD structure that specifies the number of character cell rows (X member) and columns (Y member) in the largest possible console window. Otherwise, the members of the structure are zero.

To get extended error information, call GetLastError.

Remarks

The function does not take into consideration the size of the screen buffer, which means that the window size returned may be larger than the size of the screen buffer. The GetConsoleScreenBufferInfo function can be used to determine the maximum size of the console window, given the current screen buffer size, the current font, and the display size.

See Also

COORD, GetConsoleScreenBufferInfo, SetConsoleWindowInfo


GetLastActivePopup
GetLastActivePopup  QuickInfo  Overview  Group

The GetLastActivePopup function determines which pop-up window owned by the specified window was most recently active.

HWND GetLastActivePopup(

HWND  hWnd	// handle of owner window
);
Parameters

hWnd

Identifies the owner window.

Return Value

The return value identifies the most recently active pop-up window. The return value is the same as the hWnd parameter, if any of the following conditions are met:

•	The window identified by hWnd was most recently active.

•	The window identified by hWnd does not own any pop-up windows.

•	The window identified by hWnd is not a top-level window or it is owned by another window.

See Also

AnyPopup, ShowOwnedPopups


GetLastError
GetLastError  QuickInfo  Overview  Group

The GetLastError function returns the calling thread's last-error code value.

Most Win32 functions set their calling thread's last-error value when they fail; a few functions set it when they succeed.

DWORD GetLastError(VOID)

Parameters

This function has no parameters.

Return Value

The return value is the calling thread's last-error code value. Functions set this value by calling the SetLastError function. The Return Value section of each Win32 function's reference page notes the conditions under which the function sets the last-error code.

Remarks

The extended error codes returned by the GetLastError function are not guaranteed to be the same for all operating systems.

You should call the GetLastError function immediately when a function's return value indicates that such a call will return useful data. That is because some functions call SetLastError(0) when they succeed, wiping out the error code set by the most recently failed function.

As noted, most Win32 functions call SetLastError when they fail. Function failure is typically indicated by a return value error code such as FALSE, NULL, 0xFFFFFFFF, or −1. Some functions call SetLastError under conditions of success; those cases are noted in each function's reference page.

Note that the last-error code is maintained on a per-thread basis. Multiple threads do not overwrite each other's last-error code.

Error codes are 32-bit values (bit 31 is the most significant bit). Bit 29 is reserved for application-defined error codes; no Win32 error code has this bit set. If you are defining an error code for your application, set this bit to one. That indicates that the error code has been defined by an application, and ensures that your error code does not conflict with any error codes defined by the operating system.

See Also

SetLastError, SetLastErrorEx


GetLengthSid
GetLengthSid  QuickInfo  Overview  Group

The GetLengthSid function returns the length, in bytes, of a valid SID structure. A SID is a security identifier.

DWORD GetLengthSid(

PSID  pSid	// address of SID to query
);
Parameters

pSid

Points to the SID structure whose length is returned. The structure is assumed to be valid.

Return Value

If the function succeeds, the return value is the length, in bytes, of the SID structure. If the SID structure is not valid, the return value is undefined. To get extended error information, call GetLastError.

See Also

GetSidLengthRequired, GetSidSubAuthorityCount, IsValidSid, SID


GetLocaleInfo
GetLocaleInfo  QuickInfo  Overview  Group

The GetLocaleInfo function retrieves information about a locale.

int GetLocaleInfo(

LCID  Locale,	// locale identifier
LCTYPE  LCType,	// type of information
LPTSTR  lpLCData,	// address of buffer for information
int  cchData	// size of buffer
);
Parameters

Locale

Specifies the locale to retrieve information for. This parameter can be a locale identifier created by the MAKELCID macro, or one of the following predefined values:

LOCALE_SYSTEM_DEFAULT	Default system locale.
LOCALE_USER_DEFAULT	Default user locale.
LCType

Specifies one of the LCTYPE constants to indicate the type of information to be retrieved.

All LCTYPE values are mutually exclusive, with the exception of LOCALE_NOUSEROVERRIDE. An application may use the binary-OR operator to combine LOCALE_NOUSEROVERRIDE with any other LCTYPE value. If passed such an LCType value, the function bypasses user overrides, and returns the system default value for the requested LCID.

lpLCData

Points to a buffer to receive the requested data.

cchData

Specifies the size, in bytes (ANSI version) or characters (Unicode version), of the lpLCData buffer. If cchData is zero, the function returns the number of bytes or characters required to hold the information, and the buffer pointed to by lpLCData is not used.

Return Value

If the function succeeds, the return value is the number of bytes (ANSI version) or characters (Unicode version) written to the destination buffer, or if the cchData parameter is zero, the number of bytes or characters required to hold the locale information.

If the function fails, the return value is zero. To get extended error information, call GetLastError. GetLastError may return one of the following error codes:

ERROR_INSUFFICIENT_BUFFER

ERROR_INVALID_FLAGS

ERROR_INVALID_PARAMETER

Remarks

The GetLocaleInfo function always retrieves information in text format. If the information is a numeric value, the function converts the number to text using decimal notation.

See Also

GetStringTypeA, GetStringTypeEx, GetStringTypeW, GetSystemDefaultLCID, GetUserDefaultLCID, MAKELCID


GetLocalTime
GetLocalTime  QuickInfo  Overview  Group

The GetLocalTime function retrieves the current local date and time.

VOID GetLocalTime(

LPSYSTEMTIME  lpSystemTime	// address of system time structure
);
Parameters

lpSystemTime

Points to a SYSTEMTIME structure to receive the current local date and time.

Return Value

This function does not return a value.

See Also

GetSystemTime, SetLocalTime, SYSTEMTIME


GetLogColorSpace [New - Windows 95]
GetLogColorSpace  QuickInfo  Overview  Group

[New - Windows 95]

The GetLogColorSpace function retrieves information about the logical color space identified by the specified handle.

BOOL GetLogColorSpace(

HCOLORSPACE  hColorSpace,
LPLOGCOLORSPACE  lpbuffer,
DWORD  nSize
);
Parameters

hColorSpace

Handle to the logical color space.

lpBuffer

Pointer to the LOGCOLORSPACE structure that receives the logical color space information.

nSize

Maximum size of the buffer, in bytes.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

GetLogColorSpace copies as much information to the buffer as space allows. To determine the correct size of the buffer to use, applications should check the lcsSize member in the structure.

See Also

LOGCOLORSPACE


GetLogicalDrives
GetLogicalDrives  QuickInfo  Overview  Group

The GetLogicalDrives function returns a bitmask representing the currently available disk drives.

DWORD GetLogicalDrives(VOID)

Parameters

This function has no parameters.

Return Value

If the function succeeds, the return value is a bitmask representing the currently available disk drives. Bit position 0 (the least-significant bit) is drive A, bit position 1 is drive B, bit position 2 is drive C, and so on.

If the function fails, the return value is zero.

See Also

GetLogicalDriveStrings


GetLogicalDriveStrings
GetLogicalDriveStrings  QuickInfo  Overview  Group

The GetLogicalDriveStrings function fills a buffer with strings that specify valid drives in the system.

DWORD GetLogicalDriveStrings(

DWORD  nBufferLength,	// size of buffer
LPTSTR  lpBuffer	// address of buffer for drive strings
);
Parameters

nBufferLength

Specifies the maximum size, in characters, of the buffer pointed to by lpBuffer. This size does not include the terminating null character.

lpBuffer

Points to a buffer that receives a series of null-terminated strings, one for each valid drive in the system, that end with a second null character. The following example shows the buffer contents with <null> representing the terminating null character.

c:\<null>d:\<null><null>

Return Value

If the function succeeds, the return value is the length, in characters, of the strings copied to the buffer, not including the terminating null character. Note that an ANSI-ASCII null character uses one byte, but a Unicode null character uses two bytes.

If the buffer is not large enough, the return value is greater than nBufferLength. It is the size of the buffer required to hold the drive strings.

If the function fails, the return value is zero. To get extended error information, use the GetLastError function.

Remarks

Each string in the buffer may be used wherever a root directory is required, such as for the GetDriveType and GetDiskFreeSpace functions.

See Also

GetDriveType, GetDiskFreeSpace, GetLogicalDrives


GetMailslotInfo
GetMailslotInfo  QuickInfo  Overview  Group

The GetMailslotInfo function retrieves information about the specified mailslot.

BOOL GetMailslotInfo(

HANDLE  hMailslot,	// mailslot handle
LPDWORD  lpMaxMessageSize,	// address of maximum message size
LPDWORD  lpNextSize,	// address of size of next message
LPDWORD  lpMessageCount,	// address of number of messages
LPDWORD  lpReadTimeout	// address of read time-out
);
Parameters

hMailslot

Identifies a mailslot. The CreateMailslot function must create this handle.

lpMaxMessageSize

Points to a buffer specifying the maximum message size, in bytes, allowed for this mailslot, when the function returns. This value can be greater than or equal to the value specified in the cbMaxMsg parameter of the CreateMailslot function that created the mailslot. This parameter can be NULL.

lpNextSize

Points to a buffer specifying the size, in bytes, of the next message, when the function returns. The following value has special meaning:

Value	Meaning
MAILSLOT_NO_MESSAGE	There is no next message.
This parameter can be NULL.

lpMessageCount

Points to a buffer specifying the total number of messages waiting to be read, when the function returns. This parameter can be NULL.

lpReadTimeout

Points to a buffer specifying the amount of time, in milliseconds, a read operation can wait for a message to be written to the mailslot before a time-out occurs. This parameter is filled in when the function returns. This parameter can be NULL.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

CreateMailslot, SetMailslotInfo


GetMapMode
GetMapMode  QuickInfo  Overview  Group

The GetMapMode function retrieves the current mapping mode.

int GetMapMode(

HDC  hdc	// handle of device context
);
Parameters

hdc

Identifies the device context.

Return Value

If the function succeeds, the return value specifies the mapping mode.

If the function fails, the return value is zero.

Remarks

The following list describes the various mapping modes:

Value	Description
MM_ANISOTROPIC	Logical units are mapped to arbitrary units with arbitrarily scaled axes. Use the SetWindowExtEx and SetViewportExtEx functions to specify the units, orientation, and scaling that you want.
MM_HIENGLISH	Each logical unit is mapped to 0.001 inch. Positive x is to the right; positive y is up.
MM_HIMETRIC	Each logical unit is mapped to 0.01 millimeter. Positive x is to the right; positive y is up.
MM_ISOTROPIC	Logical units are mapped to arbitrary units with equally scaled axes; that is, one unit along the x-axis is equal to one unit along the y-axis. Use the SetWindowExtEx and SetViewportExtEx functions to specify the units and the orientation of the axes that you want. Graphics device interface makes adjustments as necessary to ensure the x and y units remain the same size (for example, if you set the window extent, the viewport will be adjusted to keep the units isotropic).
MM_LOENGLISH	Each logical unit is mapped to 0.01 inch. Positive x is to the right; positive y is up.
MM_LOMETRIC	Each logical unit is mapped to 0.1 millimeter. Positive x is to the right; positive y is up.
MM_TEXT	Each logical unit is mapped to one device pixel. Positive x is to the right; positive y is down.
MM_TWIPS	Each logical unit is mapped to one twentieth of a printer's point (1/1440 inch, also called a "twip"). Positive x is to the right; positive y is up.
See Also

SetMapMode, SetWindowExtEx, SetViewportExtEx


GetMenu
GetMenu  QuickInfo  Overview  Group

The GetMenu function retrieves the handle of the menu assigned to the given window.

HMENU GetMenu(

HWND  hWnd	// handle of window
);
Parameters

hWnd

Identifies the window whose menu handle is retrieved.

Return Value

If the function succeeds, the return value is the handle of the menu. If the given window has no menu, the return value is NULL. If the window is a child window, the return value is undefined.

See Also

GetSubMenu, SetMenu


GetMenuCheckMarkDimensions
GetMenuCheckMarkDimensions  QuickInfo  Overview  Group

Windows NT: The GetMenuCheckMarkDimensions function returns the dimensions of the default check mark bitmap. Windows displays this bitmap next to checked menu items. Before calling the SetMenuItemBitmaps function to replace the default check mark bitmap for a menu item, an application must determine the correct bitmap size by calling GetMenuCheckMarkDimensions.

Windows 95: This function is obsolete. Use the GetSystemMetrics with the CXMENUCHECK and CYMENUCHECK values to retrieve the bitmap dimensions.

LONG GetMenuCheckMarkDimensions(VOID)

Parameters

This function has no parameters.

Return Value

The return value specifies the height and width, in pixels, of the default check mark bitmap. The high-order word contains the height; the low-order word contains the width.

See Also

SetMenuItemBitmaps


GetMenuContextHelpId [New - Windows NT]
GetMenuContextHelpId  QuickInfo  Overview  Group

[New - Windows NT]

The GetMenuContextHelpId function retrieves the help context identifier associated with the specified menu.

DWORD GetMenuContextHelpId(

HMENU  hmenu
);
Parameters

hmenu

Handle to the menu for which the help context identifier is to be retrieved.

Return Value

Returns the help context identifier if the menu has one or zero otherwise.


GetMenuDefaultItem [New - Windows 95]
GetMenuDefaultItem  QuickInfo  Overview  Group

[New - Windows 95]

The GetMenuDefaultItem function determines the default menu item on the specified menu.

UINT WINAPI GetMenuDefaultItem(

HMENU  hMenu,
UINT  fByPos,
UINT  gmdiFlags
);
Parameters

hMenu

Handle to the menu for which to retrieve the default menu item.

fByPos

Value specifying whether to retrieve the menu item's identifier or its position. If this parameter is FALSE, the identifier is returned. Otherwise, the position is returned.

gmdiFlags

Value specifying how the function searches for menu items. This parameter can be zero or more of the following values:

Value	Meaning
GMDI_GOINTOPOPUPS	Specifies that if the default item is a pop-up item, the function is to search recursively in the corresponding pop-up menu. If the pop-up menu has no default item, the return value identifies the pop-up item. By default, the function returns the first default item on the specified menu, regardless of whether it is a pop-up item.
GMDI_USEDISABLED	Specifies that the function is to return a default item, even if it is disabled.  By default, the function skips disabled or grayed items.
Return Value

If the function succeeds, the return value is the identifier or position of the menu item.

If the function fails, the return value is − 1.


GetMenuItemCount
GetMenuItemCount  QuickInfo  Overview  Group

The GetMenuItemCount function determines the number of items in the specified menu bar or pop-up menu.

int GetMenuItemCount(

HMENU  hMenu	// handle of menu
);
Parameters

hMenu

Identifies the handle of the menu to be examined.

Return Value

If the function succeeds, the return value specifies the number of items in the menu.

If the function fails, the return value is −1. To get extended error information, call GetLastError.

See Also

GetMenuItemID


GetMenuItemID
GetMenuItemID  QuickInfo  Overview  Group

The GetMenuItemID function retrieves the menu item identifier of a menu item located at the specified position in a menu bar or pop-up menu.

UINT GetMenuItemID(

HMENU  hMenu,	// handle of menu
int  nPos	// position of menu item
);
Parameters

hMenu

Identifies the menu bar or pop-up menu that contains the item whose identifier is to be retrieved.

nPos

Specifies the zero-based relative position of the menu item whose identifier is to be retrieved.

Return Value

If the function succeeds, the return value specifies the identifier of the given menu item. If the menu item identifier is NULL or if the specified item invokes a pop-up menu, the return value is 0xFFFFFFFF.

See Also

GetMenuItemCount, GetMenuString


GetMenuItemInfo [New - Windows 95]
GetMenuItemInfo  QuickInfo  Overview  Group

[New - Windows 95]

The GetMenuItemInfo function retrieves information about a menu item.

BOOL WINAPI GetMenuItemInfo(

HMENU  hMenu,
UINT  uItem,
BOOL  fByPosition,
LPMENUITEMINFO  lpmii
);
Parameters

hMenu

Handle to the menu that contains the menu item.

uItem

Identifier or position of the menu item to get information about. The meaning of this parameter depends on the value of fByPosition.

fByPosition

Value specifying the meaning of uItem. If this parameter is FALSE, uItem is a menu item identifier. Otherwise, it is a menu item position.

lpmii

Pointer to a MENUITEMINFO structure that specifies the information to retrieve and receives information about the menu item.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, use the GetLastError function.

See Also

MENUITEMINFO


GetMenuItemRect [New - Windows 95]
GetMenuItemRect  QuickInfo  Overview  Group

[New - Windows 95]

The GetMenuItemRect function retrieves the bounding rectangle for the specified menu item.

BOOL WINAPI GetMenuItemRect(

HWND  hWnd,
HMENU  hMenu,
UINT  uItem,
LPRECT  lprcItem
);
Parameters

hWnd

Handle to the window containing the menu bar or pop-up menu.

hMenu

Handle to a menu bar or pop-up menu.

uItem

Zero-based position of the menu item.

lprcItem

Pointer to a RECT structure that receives the bounding rectangle of the specified menu item expressed in screen coordinates.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, use the GetLastError function.

See Also

RECT


GetMenuState
GetMenuState  QuickInfo  Overview  Group

The GetMenuState function retrieves the menu flags associated with the specified menu item. If the menu item activates a pop-up menu, this function also returns the number of items in the pop-up menu.

UINT GetMenuState(

HMENU hMenu,	// handle of menu
UINT uId,	// menu item to query
UINT uFlags	// menu flags
);
Parameters

hMenu

Identifies the menu that contains the menu item whose flags are to be retrieved.

uId

Specifies the menu item for which the menu flags are to be retrieved, as determined by the uFlags parameter.

uFlags

Specifies how the uId parameter is interpreted. This parameter can be one of the following values:

Value	Description
MF_BYCOMMAND	Indicates that the uId parameter gives the identifier of the menu item. The MF_BYCOMMAND flag is the default if neither the MF_BYCOMMAND nor MF_BYPOSITION flag is specified.
MF_BYPOSITION	Indicates that the uId parameter gives the zero-based relative position of the menu item.
Return Value

If the specified item does not exist, the return value is 0xFFFFFFFF.

If the menu item activates a pop-up menu, the low-order byte of the return value contains the menu flags associated with the item, and the high-order byte contains the number of items in the pop-up menu activated by the item.

Otherwise, the return value is a mask (Boolean OR) of the menu flags. Following are the menu flags associated with the menu item.

Value	Description
MF_CHECKED	Places a check mark next to the item (pop-up menus only).
MF_DISABLED	Disables the item.
MF_GRAYED	Disables and grays the item.
MF_HILITE	Highlights the item.
MF_MENUBARBREAK	Functions the same as the MF_MENUBREAK flag, except for pop-up menus where the new column is separated from the old column by a vertical line.
MF_MENUBREAK	Places the item on a new line (for menu bars) or in a new column (for pop-up menus) without separating columns.
MF_SEPARATOR	Creates a horizontal dividing line (for pop-up menus only).
See Also

GetMenu, GetMenuItemCount, GetMenuItemID, GetMenuString


GetMenuString
GetMenuString  QuickInfo  Overview  Group

The GetMenuString function copies the text string of the specified menu item into the specified buffer.

Windows 95: GetMenuString is obsolete; use GetMenuItemInfo instead. For GetMenuString, if nMaxCount is 0 or lpString is NULL, the function returns the length of the menu string.

int GetMenuString(

HMENU  hMenu,	// handle to the menu
UINT  uIDItem,	// menu item identifier
LPTSTR  lpString,	// pointer to the buffer for the string
int  nMaxCount,	// maximum length of the string
UINT  uFlag	// menu flags
);
Parameters

hMenu

Identifies the menu.

uIDItem

Specifies the menu item to be changed, as determined by the uFlag parameter.

lpString

Points to the buffer that is to receive the null-terminated string.

nMaxCount

Specifies the maximum length, in characters, of the string to be copied. If the string is longer than the maximum specified in the nMaxCount parameter, the extra characters are truncated.

uFlag

Specifies how the uIDItem parameter is interpreted. This parameter must be one of the following values:

Value	Meaning
MF_BYCOMMAND	Indicates that uIDItem gives the identifier of the menu item. If neither the MF_BYCOMMAND nor MF_BYPOSITION flag is specified, the MF_BYCOMMAND flag is the default flag.
MF_BYPOSITION	Indicates that uIDItem gives the zero-based relative position of the menu item.
Return Value

If the function succeeds, the return value specifies the number of characters copied to the buffer, not including the terminating null character.

If the function fails, the return value is zero.

Remarks

The nMaxCount parameter must be one larger than the number of characters in the text string to accommodate the terminating null character.

See Also

GetMenuItemID


GetMessage
GetMessage  QuickInfo  Overview  Group

The GetMessage function retrieves a message from the calling thread's message queue and places it in the specified structure. This function can retrieve both messages associated with a specified window and thread messages posted via the PostThreadMessage function. The function retrieves messages that lie within a specified range of message values. GetMessage does not retrieve messages for windows that belong to other threads or applications.

BOOL GetMessage(

LPMSG  lpMsg,	// address of structure with message
HWND  hWnd,	// handle of window
UINT  wMsgFilterMin,	// first message
UINT  wMsgFilterMax	// last message
);
Parameters

lpMsg

Points to an MSG structure that receives message information from the thread's message queue.

hWnd

Identifies the window whose messages are to be retrieved. One value has a special meaning:

Value	Meaning
NULL	GetMessage retrieves messages for any window that belongs to the calling thread and thread messages posted to the calling thread via PostThreadMessage.
wMsgFilterMin

Specifies the integer value of the lowest message value to be retrieved.

wMsgFilterMax

Specifies the integer value of the highest message value to be retrieved.

Return Value

If the function retrieves a message other than WM_QUIT, the return value is TRUE.

If the function retrieves the WM_QUIT, the return value is FALSE.

If there is an error, the return value is -1. For example, the function fails if hWnd is an invalid window handle.

Remarks

An application typically uses the return value to determine whether to end the main message loop and exit the program.

The GetMessage function only retrieves messages associated with the window identified by the hWnd parameter or any of its children as specified by the IsChild function, and within the range of message values given by the wMsgFilterMin and wMsgFilterMax parameters. If hWnd is NULL, GetMessage retrieves messages for any window that belongs to the calling thread and thread messages posted to the calling thread via PostThreadMessage. GetMessage does not retrieve messages for windows that belong to other threads nor for threads other than the calling thread. Thread messages, posted by the PostThreadmessage function, have a message hWnd value of NULL. If wMsgFilterMin and wMsgFilterMax are both zero, GetMessage returns all available messages (that is, no range filtering is performed).

The WM_KEYFIRST and WM_KEYLAST constants can be used as filter values to retrieve all messages related to keyboard input; the WM_MOUSEFIRST and WM_MOUSELAST constants can be used to retrieve all mouse messages. If the wMsgFilterMin and wMsgFilterMax parameters are both zero, the GetMessage function returns all available messages (that is, without performing any filtering).

GetMessage does not remove WM_PAINT messages from the queue. The messages remain in the queue until processed.

Note that the function return value can be TRUE, FALSE, or -1. Thus, you should avoid code like this:

while (GetMessage( lpMsg, hWnd, 0, 0)) ...

The possibility of a -1 return value means that such code can lead to fatal application errors.

See Also

IsChild, MSG, PeekMessage, PostMessage, PostThreadMessage, WaitMessage


GetMessageExtraInfo
GetMessageExtraInfo  QuickInfo  Overview  Group

The GetMessageExtraInfo function retrieves extra information associated with the last message retrieved by the GetMessage or PeekMessage function. This information may be added to a message by the driver for a pointing device or keyboard.

LONG GetMessageExtraInfo(VOID)

Parameters

This function has no parameters.

Return Value

If the function succeeds, the return value specifies the extra information. The meaning of the extra information is device specific.

See Also

GetMessage, PeekMessage


GetMessagePos
GetMessagePos  QuickInfo  Overview  Group

The GetMessagePos function returns a long value that gives the cursor position in screen coordinates. This position is the point occupied by the cursor when the last message retrieved by the GetMessage function occurred.

DWORD GetMessagePos(VOID)

Parameters

This function has no parameters.

Return Value

The return value specifies the x- and y-coordinates of the cursor position. The x coordinate is in the LOWORD and the y coordinate is in the HIWORD.

Remarks

As noted above, the x-coordinate is in the low-order word of the return value; the y-coordinate is in the high-order word. If the return value is assigned to a variable, you can use the MAKEPOINTS macro to obtain a POINTS structure from the return value. You can also use the LOWORD or HIWORD macro to extract the x- or y-coordinate.

To determine the current position of the cursor instead of the position when the last message occurred, use the GetCursorPos function.

See Also

GetCursorPos, GetMessage, GetMessageTime, HIWORD, LOWORD, MAKEPOINTS, POINTS


GetMessageTime
GetMessageTime  QuickInfo  Overview  Group

The GetMessageTime function returns the message time for the last message retrieved by the GetMessage function from the current thread's message queue. The time is a long integer that specifies the elapsed time, in milliseconds, from the time the system was started to the time the message was created (that is, placed in the thread's message queue).

LONG GetMessageTime(VOID)

Parameters

This function has no parameters.

Return Value

The return value specifies the message time.

Remarks

The return value from the GetMessageTime function does not necessarily increase between subsequent messages, because the value wraps to zero if the timer count exceeds the maximum value for a long integer.

To calculate time delays between messages, verify that the time of the second message is greater than the time of the first message; then, subtract the time of the first message from the time of the second message.

See Also

GetMessage, GetMessagePos


GetMetaFile
GetMetaFile  QuickInfo  Overview  Group

The GetMetaFile function creates a handle that identifies the given Windows-format metafile.

The GetMetaFile function is not implemented in the Win32 API. This function is provided for compatibility with 16-bit versions of Microsoft Windows. Win32-based applications should use the GetEnhMetaFile function.

HMETAFILE GetMetaFile(

LPCTSTR  lpszFile	// address of metafile name
);
Parameters

lpszFile

Points to the null-terminated string that specifies the name of a Windows-format metafile. (The metafile must already exist.)

Return Value

If the function succeeds, the return value is a handle of the Windows-format metafile.

If the function fails, the return value is NULL.

Remarks

A Windows-format metafile does not support the new curve, path, and transformation functions, such as PolyBezier, BeginPath, and SetWorldTransform. Applications that use these new functions and use metafiles to store pictures created by these functions should use the enhanced-format metafile functions.

An application can convert a Windows-format metafile into an enhanced-format metafile, by calling the SetWinMetaFileBits function.

When the application no longer needs the handle returned by GetMetaFile, it should delete the handle by using the DeleteMetaFile function.

Where text arguments must use Unicode characters, use the this function as a wide-character function. Where text arguments must use characters from the Windows 3.x character set, use this function as an ANSI function.

See Also

DeleteMetaFile, GetEnhMetaFile, SetWinMetaFileBits


GetMetaFileBits

The GetMetaFile function is not implemented in the Win32 API. This function is provided for compatibility with 16-bit versions of Microsoft Windows. Win32-based applications should use the GetMetaFileBitsEx function.


GetMetaFileBitsEx
GetMetaFileBitsEx  QuickInfo  Overview  Group

The GetMetaFileBitsEx function retrieves the contents of a Windows-format metafile and copies them into the specified buffer.

This function is provided for compatibility with earlier versions of Microsoft Windows. Win32-based applications should use the GetEnhMetaFileBits function.

UINT GetMetaFileBitsEx(

HMETAFILE  hmf,	// handle of metafile
UINT  nSize,	// size of metafile, in bytes
LPVOID  lpvData	// address of metafile data
);
Parameters

hmf

Identifies a Windows-format metafile.

nSize

Specifies the size, in bytes, of the buffer to receive the data.

lpvData

Points to the buffer to receive the metafile data. The buffer must be sufficiently large to contain the data. If lpvData is NULL, the function returns the number of bytes required to hold the data.

Return Value

If the function succeeds and the buffer pointer is NULL, the return value is the number of bytes required for the buffer; if the function succeeds and the buffer pointer is a valid pointer, the return value is the number of bytes copied.

If the function fails, the return value is zero.

Remarks

After the Windows-metafile bits are retrieved, they can be used to create a memory-based metafile by calling the SetMetaFileBitsEx function.

The GetMetaFileBitsEx function does not invalidate the metafile handle. An application must delete this handle by calling the DeleteMetaFile function.

A Windows-format metafile does not support the new curve, path, and transformation functions, such as PolyBezier, BeginPath, and SetWorldTransform. Applications that use these new functions and use metafiles to store pictures created by these functions should use the enhanced format metafile functions.

To convert a Windows-format metafile into an enhanced-format metafile, use the SetWinMetaFileBits function.

See Also

BeginPath, DeleteMetaFile, GetEnhMetaFileBits, PolyBezier, SetMetaFileBitsEx, SetWinMetaFileBits, SetWorldTransform


GetMetaRgn
GetMetaRgn  QuickInfo  Overview  Group

The GetMetaRgn function retrieves the current metaregion for the specified device context.

int GetMetaRgn(

HDC  hdc,	// handle of device context
HRGN  hrgn	// handle of region
);
Parameters

hdc

Identifies the device context.

hrgn

Identifies an existing region before the function is called. After the function returns, this parameter identifies a copy of the current metaregion.

Return Value

If the function succeeds, the return value is one.

If the function fails, the return value is zero.

Remarks

If the function succeeds, hrgn identifies a copy of the current metaregion. Subsequent changes to this copy will not affect the current metaregion.

The current clipping region of a device context is defined by the intersection of its clipping region and its metaregion.

See Also

SetMetaRgn


GetMiterLimit
GetMiterLimit  QuickInfo  Overview  Group

The GetMiterLimit function returns the miter limit for the specified device context.

BOOL GetMiterLimit(

HDC  hdc,	// handle of device context
PFLOAT  peLimit	// address of variable receiving miter limit
);
Parameters

hdc

Identifies the device context.

peLimit

Points to a floating-point value where the current miter limit will be returned.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The miter limit is used when drawing geometric lines that have miter joins.

See Also

ExtCreatePen, SetMiterLimit


GetModuleFileName
GetModuleFileName  QuickInfo  Overview  Group

The GetModuleFileName function retrieves the full path and filename for the executable file containing the specified module.

Windows 95 only: The GetModuleFilename function will return long filenames when an application's version number is greater than or equal to 4.00 and the long filename is available. Otherwise, it returns only 8.3 format filenames.

DWORD GetModuleFileName(

HMODULE  hModule,	// handle to module to find filename for
LPTSTR  lpFilename,	// pointer to buffer for module path
DWORD  nSize	// size of buffer, in characters
);
Parameters

hModule

Identifies the module whose executable filename is being requested. If this parameter is NULL, GetModuleFileName returns the path for the file used to create the calling process.

lpFilename

Points to a buffer that is filled in with the path and filename of the given module.

nSize

Specifies the length, in characters, of the lpFilename buffer. If the length of the path and filename exceeds this limit, the string is truncated.

Return Value

If the function succeeds, the return value is the length, in characters, of the string copied to the buffer.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

If a module is loaded in two processes, its module filename in one process may differ in case from its module filename in the other process.

See Also

GetModuleHandle, LoadLibrary


GetModuleHandle
GetModuleHandle  QuickInfo  Overview  Group

The GetModuleHandle function returns a module handle for the specified module if the file has been mapped into the address space of the calling process.

HMODULE GetModuleHandle(

LPCTSTR  lpModuleName	// address of module name to return handle for
);
Parameters

lpModuleName

Points to a null-terminated string that names a Win32 module (either a .DLL or .EXE file). If the filename extension is omitted, the default library extension .DLL is appended. The filename string can include a trailing point character (.) to indicate that the module name has no extension. The string does not have to specify a path. The name is compared (case independently) to the names of modules currently mapped into the address space of the calling process.

If this parameter is NULL, GetModuleHandle returns a handle of the file used to create the calling process.

Return Value

If the function succeeds, the return value is a handle to the specified module.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

The returned handle is not global, inheritable, or duplicative, and it cannot be used by another process.

The handles returned by GetModuleHandle and LoadLibrary can be used in the same functions — for example, GetProcAddress, FreeLibrary, or LoadResource. The difference between the two functions involves the reference count. LoadLibrary maps the module into the address space of the calling process, if necessary, and increments the module's reference count, if it is already mapped. GetModuleHandle, however, returns the handle of a mapped module without incrementing its reference count.

Note that the reference count is used in FreeLibrary to determine whether to unmap the function from the address space of the process. For this reason, use care when using a handle returned by GetModuleHandle in a call to FreeLibrary because doing so can cause a dynamic-link library (DLL) module to be unmapped prematurely.

This function must also be used carefully in a multithreaded application. There is no guarantee that the module handle remains valid between the time this function returns the handle and the time it is used by another function. For example, a thread might retrieve a module handle by calling GetModuleHandle. Before the thread uses the handle in another function, a second thread could free the module and the system could load another module, giving it the same handle as the module that was recently freed. The first thread would then be left with a module handle that refers to a module different than the one intended.

See Also

FreeLibrary, GetModuleFileName, GetProcAddress, LoadLibrary, LoadResource


GetModuleUsage
GetModuleUsage  Overview  Group

The GetModuleUsage function has been deleted. Each Win32-based application runs in its own address space.


GetMsgProc
GetMsgProc  QuickInfo  Overview  Group

The GetMsgProc hook procedure is an application-defined or library-defined callback function that the system calls whenever the GetMessage function has retrieved a message from an application message queue. Before passing the retrieved message to the destination window procedure, the system passes the message to the hook procedure.

LRESULT CALLBACK GetMsgProc(

int  code,	// hook code
WPARAM  wParam,	// removal flag
LPARAM  lParam	// address of structure with message
);
Parameters

code

Specifies whether the hook procedure must process the message. If code is HC_ACTION, the hook procedure must process the message. If code is less than zero, the hook procedure must pass the message to the CallNextHookEx function without further processing and should return the value returned by CallNextHookEx.

wParam

Specifies whether the message has been removed from the queue. This parameter can be one of the following values:

Value	Meaning
PM_NOREMOVE	Specifies that the message has not been removed from the queue. (An application called the PeekMessage function, specifying the PM_NOREMOVE flag.)
PM_REMOVE	Specifies that the message has been removed from the queue. (An application called GetMessage, or it called the PeekMessage function, specifying the PM_REMOVE flag.)
lParam

Points to an MSG structure that contains details about the message.

Return Value

The return value should be zero.

Remarks

The GetMsgProc hook procedure can examine or modify the message. After the hook procedure returns control to the system, the GetMessage function returns the message, along with any modifications, to the application that originally called it.

An application installs this hook procedure by specifying the WH_GETMESSAGE hook type and the address of the hook procedure in a call to the SetWindowsHookEx function.

GetMsgProc is a placeholder for the application-defined or library-defined function name.

See Also

CallNextHookEx, GetMessage, MSG, PeekMessage, SetWindowsHookEx


GetNameByType
GetNameByType  QuickInfo  Overview  Group

The GetNameByType function obtains the name of a network service. The network service is specified by its service type.

INT GetNameByType(

LPGUID  lpServiceType,	// points to network service type GUID
LPTSTR  lpServiceName,	// points to buffer to receive name of network service
DWORD  dwNameLength	// points to variable that specifies buffer size
);
Parameters

lpServiceType

Points to a globally unique identifier (GUID) that specifies the type of the network service. The header file SVCGUID.H includes definitions of several GUID service types, and macros for working with them.

lpServiceName

Points to a buffer to receive a zero-terminated string that uniquely represents the name of the network service.

dwNameLength

Points to a variable that, on input, specifies the size of the buffer pointed to by lpServiceName. On output, the variable contains the actual size of the service name string.

Return Value

If the function succeeds, the return value is not SOCKET_ERROR ( −1).

If the function fails, the return value is SOCKET_ERROR ( −1). To get extended error information, call GetLastError.

See Also

GetTypeByName


GetNamedPipeHandleState
GetNamedPipeHandleState  QuickInfo  Overview  Group

The GetNamedPipeHandleState function retrieves information about a specified named pipe. The information returned can vary during the lifetime of an instance of the named pipe.

BOOL GetNamedPipeHandleState(

HANDLE  hNamedPipe,	// handle of named pipe
LPDWORD  lpState,	// address of flags indicating pipe state
LPDWORD  lpCurInstances,	// address of number of current pipe instances
LPDWORD  lpMaxCollectionCount,	// address of max. bytes before remote transmission
LPDWORD  lpCollectDataTimeout,	// address of max. time before remote transmission
LPTSTR  lpUserName,	// address of user name of client process
DWORD  nMaxUserNameSize	// size, in characters, of user name buffer
);
Parameters

hNamedPipe

Identifies the named pipe for which information is wanted. The handle must have GENERIC_READ access to the named pipe.

lpState

Points to a 32-bit variable that indicates the current state of the handle. This parameter can be NULL if this information is not needed. Either or both of the following values can be specified:

Value	Meaning
PIPE_NOWAIT	The pipe handle is in nonblocking mode. If this flag is not specified, the pipe handle is in blocking mode.
PIPE_READMODE_MESSAGE	The pipe handle is in message-read mode. If this flag is not specified, the pipe handle is in byte-read mode.
lpCurInstances

Points to a 32-bit variable that receives the number of current pipe instances. This parameter can be NULL if this information is not required.

lpMaxCollectionCount

Points to a 32-bit variable that receives the maximum number of bytes to be collected on the client's computer before transmission to the server. This parameter must be NULL if the specified pipe handle is to the server end of a named pipe or if client and server processes are on the same computer. This parameter can be NULL if this information is not required.

lpCollectDataTimeout

Points to a 32-bit variable that receives the maximum time, in milliseconds, that can pass before a remote named pipe transfers information over the network. This parameter must be NULL if the specified pipe handle is to the server end of a named pipe or if client and server processes are on the same computer. This parameter can be NULL if this information is not required.

lpUserName

Points to a buffer that receives the null-terminated string containing the user name string of the client application. This parameter must be NULL if the specified pipe handle is to the client end of a named pipe. This parameter can be NULL if this information is not required.

nMaxUserNameSize

Specifies the size, in characters, of the buffer specified by the lpUserName parameter. This parameter is ignored if lpUserName is NULL.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The GetNamedPipeHandleState function returns successfully even if all of the pointers passed to it are NULL.

To set the pipe handle state, use the SetNamedPipeHandleState function.

See Also

SetNamedPipeHandleState


GetNamedPipeInfo
GetNamedPipeInfo  QuickInfo  Overview  Group

The GetNamedPipeInfo function retrieves information about the specified named pipe.

BOOL GetNamedPipeInfo(

HANDLE  hNamedPipe,	// handle of named pipe
LPDWORD  lpFlags,	// address of flags indicating type of pipe
LPDWORD  lpOutBufferSize,	// address of size, in bytes, of pipe's output buffer
LPDWORD  lpInBufferSize,	// address of size, in bytes, of pipe's input buffer
LPDWORD  lpMaxInstances	// address of max. number of pipe instances
);
Parameters

hNamedPipe

Identifies the named pipe instance. The handle must have GENERIC_READ access to the named pipe.

lpFlags

Points to a 32-bit variable that indicates the type of the named pipe and specifies whether the handle is to the server or client end of the pipe. This parameter can be NULL if this information is not required. Either or both of the following values can be specified:

Value	Meaning
PIPE_CLIENT_END	Windows 95 only: The handle refers to the client end of a named pipe instance. This is the default.
PIPE_SERVER_END	Windows 95 only: The handle refers to the server end of a named pipe instance. If this value is not specified, the handle refers to the client end of a named pipe instance.
PIPE_TYPE_MESSAGE	The named pipe is a message-type pipe. If this value is not specified, the pipe is a byte-type pipe.
lpOutBufferSize

Points to a 32-bit variable that receives the size, in bytes, of the buffer for outgoing data. If the buffer size is zero, the buffer is allocated as needed. This parameter can be NULL if this information is not required.

lpInBufferSize

Points to a 32-bit variable that receives the size, in bytes, of the buffer for incoming data. If the buffer size is zero, the buffer is allocated as needed. This parameter can be NULL if this information is not required.

lpMaxInstances

Points to a 32-bit variable that receives the maximum number of pipe instances that can be created. If the variable is set to PIPE_UNLIMITED_INSTANCES, the number of pipe instances that can be created is limited only by the availability of system resources. This parameter can be NULL if this information is not required.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

CreateNamedPipe, GetNamedPipeHandleState


GetNearestColor
GetNearestColor  QuickInfo  Overview  Group

The GetNearestColor function returns a color value identifying a color from the system palette that will be displayed when the specified color value is used.

COLORREF GetNearestColor(

HDC  hdc,	// handle of device context
COLORREF  crColor	// color to be matched
);
Parameters

hdc

Identifies the device context.

crColor

Specifies a color value that identifies a requested color.

Return Value

If the function succeeds, the return value identifies a color from the system palette that corresponds to the given color value.

If the function fails, the return value is CLR_INVALID. To get extended error information, call GetLastError.

See Also

GetDeviceCaps, GetNearestPaletteIndex, COLORREF


GetNearestPaletteIndex
GetNearestPaletteIndex  QuickInfo  Overview  Group

The GetNearestPaletteIndex function retrieves the index for the entry in the specified logical palette most closely matching a specified color value.

UINT GetNearestPaletteIndex(

HPALETTE  hpal,	// handle of logical color palette
COLORREF  crColor	// color to be matched
);
Parameters

hpal

Identifies a logical color palette.

crColor

Specifies a color to be matched.

Return Value

If the function succeeds, the return value is the index of an entry in a logical palette.

If the function fails, the return value is CLR_INVALID. To get extended error information, call GetLastError.

Remarks

An application can determine whether a device supports palette operations by calling the GetDeviceCaps function and specifying the RASTERCAPS constant.

If the given logical palette contains entries with the PC_EXPLICIT flag set, the return value is undefined.

See Also

GetDeviceCaps, GetNearestColor, GetPaletteEntries, GetSystemPaletteEntries, COLORREF


GetNextDlgGroupItem
GetNextDlgGroupItem  QuickInfo  Overview  Group

The GetNextDlgGroupItem function retrieves the handle of the first control in a group of controls that precedes (or follows) the specified control in a dialog box.

HWND GetNextDlgGroupItem(

HWND  hDlg,	// handle of dialog box
HWND  hCtl,	// handle of control
BOOL  bPrevious	// direction flag
);
Parameters

hDlg

Identifies the dialog box being searched.

hCtl

Identifies the control to be used as the starting point for the search. If this parameter is NULL, the function uses the last (or first) control in the dialog box as the starting point for the search.

bPrevious

Specifies how the function is to search the group of controls in the dialog box. If this parameter is TRUE, the function searches for the previous control in the group. If it is FALSE, the function searches for the next control in the group.

Return Value

If GetNextDlgGroupItem succeeds, the return value is the handle of the previous (or next) control in the group of controls.

Remarks

The GetNextDlgGroupItem function searches controls in the order (or reverse order) they were created in the dialog box template. The first control in the group must have the WS_GROUP style; all other controls in the group must have been consecutively created and must not have the WS_GROUP style.

When searching for the previous control, the function returns the first control it locates that is visible and not disabled. If the control given by hCtl has the WS_GROUP style, the function temporarily reverses the search to locate the first control having the WS_GROUP style, then resumes the search in the original direction, returning the first control it locates that is visible and not disabled, or returning hwndCtrl if no such control is found.

When searching for the next control, the function returns the first control it locates that is visible, not disabled, and does not have the WS_GROUP style. If it encounters a control having the WS_GROUP style, the function reverses the search, locates the first control having the WS_GROUP style, and returns this control if it is visible and not disabled. Otherwise, the function resumes the search in the original direction and returns the first control it locates that is visible and not disabled, or returns hCtl if no such control is found.

See Also

GetNextDlgTabItem


GetNextDlgTabItem
GetNextDlgTabItem  QuickInfo  Overview  Group

The GetNextDlgTabItem function retrieves the handle of the first control that has the WS_TABSTOP style that precedes (or follows) the specified control.

HWND GetNextDlgTabItem(

HWND  hDlg,	// handle of dialog box
HWND  hCtl,	// handle of known control
BOOL  bPrevious	// direction flag
);
Parameters

hDlg

Identifies the dialog box to be searched.

hCtl

Identifies the control to be used as the starting point for the search. If this parameter is NULL, the function uses the last (or first) control in the dialog box as the starting point for the search.

bPrevious

Specifies how the function is to search the dialog box. If this parameter is TRUE, the function searches for the previous control in the dialog box. If this parameter is FALSE, the function searches for the next control in the dialog box.

Return Value

If the function succeeds, the return value is the window handle of the previous (or next) control that has the WS_TABSTOP style set.

Remarks

The GetNextDlgTabItem function searches controls in the order (or reverse order) they were created in the dialog box template. The function returns the first control it locates that is visible, not disabled, and has the WS_TABSTOP style. If no such control exists, the function returns hCtl.

See Also

GetDlgItem, GetNextDlgGroupItem


GetNextWindow
GetNextWindow  QuickInfo  Overview  Group

The GetNextWindow function retrieves the handle of the next or previous window in the Z order. The next window is below the specified window; the previous window is above. Windows maintains separate Z orders for topmost windows, top-level windows, and child windows. If the specified window is a topmost window, the function retrieves the handle of the next (or previous) topmost window. If the specified window is a top-level window, the function retrieves the handle of the next (or previous) top-level window. If the specified window is a a child window, the function searches for a handle of the next (or previous) child window.

HWND GetNextWindow(

HWND  hWnd,	// handle of current window
UINT  wCmd	// direction flag
);
Parameters

hWnd

Identifies a window. The window handle retrieved is relative to this window, based on the value of the wCmd parameter.

wCmd

Specifies whether the function returns the handle of the next window or of the previous window. This parameter can be either of the following values:

Value	Meaning
GW_HWNDNEXT	Returns the handle of the window below the given window.
GW_HWNDPREV	Returns the handle of the window above the given window.
Return Value

If the function succeeds, the return value is the handle of the next (or previous) window. If there is no next (or previous) window, the return value is NULL. To get extended error information, call GetLastError.

Remarks

Using this function is the same as calling the GetWindow function with the GW_HWNDNEXT or GW_HWNDPREV flag set.

See Also

GetTopWindow


GetNumberFormat
GetNumberFormat  QuickInfo  Overview  Group

The GetNumberFormat function formats a number string as a number string customized for a specified locale.

int GetNumberFormat(

LCID  Locale,	// locale for which number string is to be formatted
DWORD  dwFlags,	// bit flag that controls the function's operation
LPCTSTR  lpValue,	// pointer to input number string
CONST NUMBERFMT *  lpFormat,	// pointer to a formatting information structure
LPTSTR  lpNumberStr,	// pointer to output buffer
int  cchNumber	// size of output buffer
);
Parameters

Locale

Specifies the locale for which the number string is to be formatted. If lpFormat is NULL, the function formats the string according to the number format for this locale. If lpFormat is not NULL, the function uses the locale only for formatting information not specified in the NUMBERFMT structure (for example, the locale's string value for the negative sign).

This parameter can be a locale identifier created by the MAKELCID macro, or one of the following predefined values:

LOCALE_SYSTEM_DEFAULT	Default system locale.
LOCALE_USER_DEFAULT	Default user locale.
dwFlags

Contains a bit flag that controls the operation of the function. If lpFormat is non-NULL, this parameter must be zero.

If lpFormat is NULL, you can specify the LOCALE_NOUSEROVERRIDE flag to format the string using the system default number format for the specified locale; or you can specify zero to format the string using any user overrides to the locale's default number format

lpValue

Points to a null-terminated string containing the number string to format.

This string can only contain the following characters:

•	Characters '0' through '9'

•	One decimal point (dot) if the number is a floating-point value

•	A minus sign in the first character position if the number is a negative value

All other characters are invalid. The function returns an error if the string pointed to by lpValue deviates from these rules.

lpFormat

Pointer to a NUMBERFMT structure that contains number formatting information. All members in the structure pointed to by lpFormat must contain appropriate values.

If lpFormat is NULL, the function uses the number format of the specified locale.

lpNumberStr

Points to a buffer to receive the formatted number string.

cchNumber

Specifies the size, in bytes (ANSI version) or characters (Unicode version), of the lpNumberStr buffer. If cchNumber is zero, the function returns the number of bytes or characters required to hold the formatted number string, and the buffer pointed to by lpNumberStr is not used.

Return Value

If the function succeeds, the return value is the number of bytes (ANSI version) or characters (Unicode version) written to the buffer pointed to by lpNumberStr, or if the cchNumber parameter is zero, the number of bytes or characters required to hold the formatted number string.

If the function fails, the return value is zero. To get extended error information, call GetLastError. GetLastError may return one of the following error codes:

ERROR_INSUFFICIENT_BUFFER
ERROR_INVALID FLAGS
ERROR_INVALID_PARAMETER

See Also

GetCurrencyFormat, NUMBERFMT


GetNumberOfConsoleInputEvents
GetNumberOfConsoleInputEvents  QuickInfo  Overview  Group

The GetNumberOfConsoleInputEvents function retrieves the number of unread input records in the console's input buffer.

BOOL GetNumberOfConsoleInputEvents(

HANDLE  hConsoleInput,	// handle of console input buffer
LPDWORD  lpcNumberOfEvents	// address for number of events
);
Parameters

hConsoleInput

Identifies the console input buffer. The handle must have GENERIC_READ access.

lpcNumberOfEvents

Points to a 32-bit variable that receives the number of unread input records in the console's input buffer.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The GetNumberOfConsoleInputEvents function reports the total number of unread input records in the input buffer, including keyboard, mouse, and window-resizing input records. Processes using the ReadFile or ReadConsole function can only read keyboard input. Processes using the ReadConsoleInput function can read all types of input records.

A process can specify a console input buffer handle in one of the wait functions (that is, the WaitForSingleObject or WaitForMultipleObjects function) to determine when there is unread console input. When the input buffer is not empty, the state of a console input buffer handle is signaled.

To read input records from a console input buffer without affecting the number of unread records, use the PeekConsoleInput function. To discard all unread records in a console's input buffer, use the FlushConsoleInputBuffer function.

See Also

FlushConsoleInputBuffer, PeekConsoleInput, ReadConsole, ReadConsoleInput, ReadFile, WaitForMultipleObjects, WaitForSingleObject


GetNumberOfConsoleMouseButtons
GetNumberOfConsoleMouseButtons  QuickInfo  Overview  Group

The GetNumberOfConsoleMouseButtons function retrieves the number of buttons on the mouse used by the current console.

BOOL GetNumberOfConsoleMouseButtons(

LPDWORD  lpNumberOfMouseButtons	// address of number of buttons
);
Parameters

lpNumberOfMouseButtons

Points to a 32-bit variable that receives the number of mouse buttons.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

When a console receives mouse input, an INPUT_RECORD structure containing a MOUSE_EVENT_RECORD structure is placed in the console's input buffer. The dwButtonState member of MOUSE_EVENT_RECORD has a bit indicating the state of each mouse button. The bit is 1 if the button is down and 0 if the button is up. To determine the number of bits that are significant, use GetNumberOfConsoleMouseButtons.

See Also

ReadConsoleInput, INPUT_RECORD, MOUSE_EVENT_RECORD


GetNumberOfEventLogRecords
GetNumberOfEventLogRecords  QuickInfo  Overview  Group

The GetNumberOfEventLogRecords function retrieves the number of records in the specified event log.

BOOL GetNumberOfEventLogRecords(

HANDLE  hEventLog,	// handle to event log
PDWORD  NumberOfRecords	// buffer for number of records
);
Parameters

hEventLog

Identifies the open event log. This handle is returned by the OpenEventLog or OpenBackupEventLog function.

NumberOfRecords

Points to a variable that receives the number of records in the given event log.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

GetOldestEventLogRecord, OpenBackupEventLog, OpenEventLog


GetObject
GetObject  QuickInfo  Overview  Group

The GetObject function obtains information about a specified graphics object. Depending on the graphics object, the function places a filled-in BITMAP, DIBSECTION, EXTLOGPEN, LOGBRUSH, LOGFONT, or LOGPEN structure, or a count of table entries (for a logical palette), into a specified buffer.

int GetObject(

HGDIOBJ  hgdiobj,	// handle to graphics object of interest
int  cbBuffer,	// size of buffer for object information
LPVOID  lpvObject	// pointer to buffer for object information
);
Parameters

hgdiobj

A handle to the graphics object of interest. This can be a handle to one of the following: a logical bitmap, a brush, a font, a palette, a pen, or a device independent bitmap created by calling the CreateDIBSection function.

cbBuffer

Specifies the number of bytes of information to be written to the buffer.

lpvObject

Points to a buffer that is to receive the information about the specified graphics object.

The following table shows the type of information the buffer receives for each type of graphics object you can specify with hgdiobj:

hgdiobj Type	Data Written to *lpvObject
HBITMAP	BITMAP
HBITMAP returned from a call to CreateDIBSection	DIBSECTION, if cbBuffer is set to sizeof(DIBSECTION), or BITMAP, if cbBuffer is set to sizeof(BITMAP)
HPALETTE	a WORD count of the number of entries in the logical palette
HPEN returned from a call to ExtCreatePen	EXTLOGPEN
HPEN	LOGPEN
HBRUSH	LOGBRUSH
HFONT	LOGFONT
If the lpvObject parameter is NULL, the function return value is the number of bytes required to store the information it writes to the buffer for the specified graphics object.

Return Value

If the function succeeds, and lpvObject is a valid pointer, the return value is the number of bytes stored into the buffer.

If the function succeeds, and lpvObject is NULL, the return value is the number of bytes required to hold the information the function would store into the buffer.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

The buffer pointed to by the lpvObject parameter must be sufficiently large to receive the information about the graphics object.

If hgdiobj identifies a bitmap created by calling CreateDIBSection, and the specified buffer is large enough, the GetObject function returns a DIBSECTION structure. In addition, the bmBits member of the BITMAP structure contained within the DIBSECTION will contain a pointer to the bitmap's bit values.

If hgdiobj identifies a bitmap created by any other means, GetObject returns only the width, height, and color format information of the bitmap. You can obtain the bitmap's bit values by calling the GetDIBits or GetBitmapBits function.

If hgdiobj identifies a logical palette, GetObject retrieves a two-byte integer that specifies the number of entries in the palette. The function does not retrieve the LOGPALETTE structure defining the palette. To retrieve information about palette entries, an application can call the GetPaletteEntries function.

See Also

CreateDIBSection, GetBitmapBits, GetDIBits, GetPaletteEntries, GetRegionData, BITMAP, DIBSECTION, EXTLOGPEN, LOGBRUSH, LOGFONT, LOGPALETTE, LOGPEN


GetObjectType
GetObjectType  QuickInfo  Overview  Group

The GetObjectType identifies the type of the specified object.

DWORD GetObjectType(

HGDIOBJ  h	// handle of graphic object
);
Parameters

h

Identifies the object.

Return Value

If the function succeeds, the return value identifies the object. This value can be one of the following:

Value	Meaning
OBJ_BITMAP	Bitmap
OBJ_BRUSH	Brush
OBJ_FONT	Font
OBJ_PAL	Palette
OBJ_PEN	Pen
OBJ_EXTPEN	Extended pen
OBJ_REGION	Region
OBJ_DC	Device context
OBJ_MEMDC	Memory device context
OBJ_METAFILE	Metafile
OBJ_METADC	Metafile device context
OBJ_ENHMETAFILE	Enhanced metafile
OBJ_ENHMETADC	Enhanced metafile device context
If the function fails, the return value is zero.

See Also

GetObject, SelectObject


GetOEMCP
GetOEMCP  QuickInfo  Overview  Group

The GetOEMCP function retrieves the current OEM code-page identifier for the system. (OEM stands for original equipment manufacturer.)

UINT GetOEMCP(VOID)

Parameters

This function has no parameters.

Return Value

If the function succeeds, the return value is the current OEM code-page identifier for the system or a default identifier if no code page is current.

Remarks

Following are the OEM code-page identifiers:

Identifier	Meaning
437	MS-DOS United States
708	Arabic (ASMO 708)
709	Arabic (ASMO 449+, BCON V4)
710	Arabic (Transparent Arabic)
720	Arabic (Transparent ASMO)
737	Greek (formerly 437G)
775	Baltic
850	MS-DOS Multilingual (Latin I)
852	MS-DOS Slavic (Latin II)
855	IBM Cyrillic (primarily Russian)
857	IBM Turkish
860	MS-DOS Portuguese
861	MS-DOS Icelandic
862	Hebrew
863	MS-DOS Canadian-French
864	Arabic
865	MS-DOS Nordic
866	MS-DOS Russian (former USSR)
869	IBM Modern Greek
874	Thai
932	Japan
936	Chinese (PRC, Singapore)
949	Korean
950	Chinese (Taiwan, Hong Kong)
1361	Korean (Johab)
See Also

GetACP


GetOldestEventLogRecord
GetOldestEventLogRecord  QuickInfo  Overview  Group

The GetOldestEventLogRecord function retrieves the absolute record number of the oldest record in the specified event log.

BOOL GetOldestEventLogRecord(

HANDLE  hEventLog,	// handle to event log
PDWORD  OldestRecord	// buffer for number of oldest record
);
Parameters

hEventLog

Identifies the open event log. This handle is returned by the OpenEventLog or OpenBackupEventLog function.

OldestRecord

Points to the variable that receives the absolute record number of the oldest record in the given event log.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

GetNumberOfEventLogRecords, OpenBackupEventLog, OpenEventLog


GetOpenClipboardWindow
GetOpenClipboardWindow  QuickInfo  Overview  Group

The GetOpenClipboardWindow function retrieves the handle of the window that currently has the clipboard open.

HWND GetOpenClipboardWindow(VOID)

Parameters

This function has no parameters.

Return Value

If the function succeeds, the return value is the handle of the window that has the clipboard open. If no window has the clipboard open, the return value is NULL. To get extended error information, call GetLastError.

Remarks

If an application or dynamic-link library (DLL) specifies a NULL window handle when calling the OpenClipboard function, the clipboard is opened but is not associated with a window. In such a case, GetOpenClipboardWindow returns NULL.

See Also

GetClipboardOwner, GetClipboardViewer, GetOpenClipboardWindow, OpenClipboard


GetOpenFileName
GetOpenFileName  QuickInfo  Overview  Group

The GetOpenFileName function creates a system-defined dialog box that enables the user to select a file to open.

BOOL GetOpenFileName(

LPOPENFILENAME  lpofn	// address of structure with initialization data
);
Parameters

lpofn

Points to an OPENFILENAME structure that contains information used to initialize the dialog box. When GetOpenFileName returns, this structure contains information about the user's file selection.

Return Value

If the user selects a file to open, the return value is TRUE. It is FALSE if an error occurs, the user chooses the Cancel button, the user chooses the Close command on the System menu to close the dialog box, or the buffer identified by the lpstrFile member of the OPENFILENAME structure is too small to contain the string that specifies the selected file.

To get extended error information, call CommDlgExtendedError. CommDlgExtendedError may return one of the following error codes:

CDERR_FINDRESFAILURE	CDERR_NOHINSTANCE
CDERR_INITIALIZATION	CDERR_NOHOOK
CDERR_LOCKRESFAILURE	CDERR_NOTEMPLATE
CDERR_LOADRESFAILURE	CDERR_STRUCTSIZE
CDERR_LOADSTRFAILURE	FNERR_BUFFERTOOSMALL
CDERR_MEMALLOCFAILURE	FNERR_INVALIDFILENAME
CDERR_MEMLOCKFAILURE	FNERR_SUBCLASSFAILURE
Remarks

If the hook function (pointed to by the lpfnHook member of the OPENFILENAME structure) processes the WM_CTLCOLORBTN, WM_CTLCOLORDLG, WM_CTLCOLORLISTBOX, WM_CTLCOLORMSGBOX, WM_CTLCOLORSCROLLBAR, or WM_CTLCOLORSTATIC message, GetOpenFileName must return a handle of the brush that should be used to paint the control background.

Ending the dialog box from within the hook function by calling the EndDialog function prevents the COMDLG32.DLL dynamic link library (DLL) from properly exiting its worker thread. For applications that dynamically load and/or unload COMDLG32.DLL, this type of exiting may result in an access violation during unloading as the worker thread's address space is invalidated.

See Also

CommDlgExtendedError, EndDialog, GetSaveFileName, OPENFILENAME


GetOutlineTextMetrics
GetOutlineTextMetrics  QuickInfo  Overview  Group

The GetOutlineTextMetrics function retrieves text metrics for TrueType fonts.

UINT GetOutlineTextMetrics(

HDC  hdc,	// handle of device context
UINT  cbData,	// size of metric data array
LPOUTLINETEXTMETRIC  lpOTM	// address of metric data array
);
Parameters

hdc

Identifies the device context.

cbData

Specifies the size, in bytes, of the array in which the text metrics are to be returned.

lpOTM

Points to an array of OUTLINETEXTMETRIC structures. If this parameter is NULL, the function returns the size of the buffer required for the retrieved metric data.

Return Value

If the function succeeds, the return value is TRUE or the size of the required buffer.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The OUTLINETEXTMETRIC structure contains most of the text metric information provided for TrueType fonts (including a TEXTMETRIC structure). The sizes returned in the OUTLINETEXTMETRIC structures are in logical units; they depend on the current mapping mode.

See Also

GetTextMetrics, OUTLINETEXTMETRIC, TEXTMETRIC


GetOverlappedResult
GetOverlappedResult  QuickInfo  Overview  Group

The GetOverlappedResult function returns the results of an overlapped operation on the specified file, named pipe, or communications device.

Windows 95: This function works only on serial devices or on files opened by using the DeviceIoControl function.

BOOL GetOverlappedResult(

HANDLE  hFile,	// handle of file, pipe, or communications device
LPOVERLAPPED  lpOverlapped,	// address of overlapped structure
LPDWORD  lpNumberOfBytesTransferred,	// address of actual bytes count
BOOL  bWait	// wait flag
);
Parameters

hFile

Identifies the file, named pipe, or communications device. This is the same handle that was specified when the overlapped operation was started by a call to the ReadFile, WriteFile, ConnectNamedPipe, TransactNamedPipe, DeviceIoControl, or WaitCommEvent function.

lpOverlapped

Points to an OVERLAPPED structure that was specified when the overlapped operation was started.

lpNumberOfBytesTransferred

Points to a 32-bit variable that receives the number of bytes that were actually transferred by a read or write operation. For a TransactNamedPipe operation, this is the number of bytes that were read from the pipe. For a DeviceIoControl operation, this is the number of bytes of output data returned by the device driver. For a ConnectNamedPipe or WaitCommEvent operation, this value is undefined.

bWait

Specifies whether the function should wait for the pending overlapped operation to be completed. If TRUE, the function does not return until the operation has been completed. If FALSE and the operation is still pending, the function returns FALSE and the GetLastError function returns ERROR_IO_INCOMPLETE.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The results reported by the GetOverlappedResult function are those of the specified handle's last overlapped operation to which the specified OVERLAPPED structure was provided, and for which the operation's results were pending. A pending operation is indicated when the function that started the operation returns FALSE, and the GetLastError function returns ERROR_IO_PENDING. When an I/O operation is pending, the function that started the operation resets the hEvent member of the OVERLAPPED structure to the nonsignaled state. Then when the pending operation has been completed, the system sets the event object to the signaled state.

If the bWait parameter is TRUE, GetOverlappedResult determines whether the pending operation has been completed by waiting for the event object to be in the signaled state.

If the hEvent member of the OVERLAPPED structure is NULL, the system uses the state of the hFile handle to signal when the operation has been completed. Use of file, named pipe, or communications-device handles for this purpose is discouraged. It is safer to use an event object because of the confusion that can occur when multiple simultaneous overlapped operations are performed on the same file, named pipe, or communications device. In this situation, there is no way to know which operation caused the object's state to be signaled.

Specify a manual-reset event object in the OVERLAPPED structure. If an auto-reset event object is used, the event handle must not be specified in any other wait operation in the interval between starting the overlapped operation and the call to GetOverlappedResult. For example, the event object is sometimes specified in one of the wait functions to wait for the operation's completion. When the wait function returns, the system sets an auto-reset event's state to nonsignaled, and a subsequent call to GetOverlappedResult with the bWait parameter set to TRUE causes the function to be blocked indefinitely.

See Also

ConnectNamedPipe, CreateEvent, DeviceIoControl, GetLastError, OVERLAPPED, ReadFile, TransactNamedPipe, WaitCommEvent, WriteFile


GetPaletteEntries
GetPaletteEntries  QuickInfo  Overview  Group

The GetPaletteEntries function retrieves a specified range of palette entries from the given logical palette.

UINT GetPaletteEntries(

HPALETTE  hpal,	// handle of logical color palette
UINT  iStartIndex,	// first entry to retrieve
UINT  nEntries,	// number of entries to retrieve
LPPALETTEENTRY  lppe	// address of array receiving entries
);
Parameters

hpal

Identifies the logical color palette.

iStartIndex

Specifies the first entry in the logical palette to be retrieved.

nEntries

Specifies the number of entries in the logical palette to be retrieved.

lppe

Points to an array of PALETTEENTRY structures to receive the palette entries. The array must contain at least as many structures as specified by the nEntries parameter.

Return Value

If the function succeeds and the handle of the logical color palette is a valid pointer (not NULL), the return value is the number of entries retrieved from the logical palette. If the function succeeds and handle of the logical color palette is NULL, the return value is the number of entries in the given palette.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

An application can determine whether a device supports palette operations by calling the GetDeviceCaps function and specifying the RASTERCAPS constant.

If the nEntries parameter specifies more entries than exist in the palette, the remaining members of the PALETTEENTRY structure are not altered.

See Also

GetDeviceCaps, GetSystemPaletteEntries, PALETTEENTRY


GetParent
GetParent  QuickInfo  Overview  Group

The GetParent function retrieves the handle of the specified child window's parent window.

HWND GetParent(

HWND  hWnd	// handle of child window
);
Parameters

hWnd

Identifies the window whose parent window handle is to be retrieved.

Return Value

If the function succeeds, the return value is the handle of the parent window. If the window has no parent window, the return value is NULL. To get extended error information, call GetLastError.

See Also

SetParent


GetPath
GetPath  QuickInfo  Overview  Group

The GetPath function retrieves the coordinates defining the endpoints of lines and the control points of curves found in the path that is selected into the specified device context.

int GetPath(

HDC  hdc,	// handle of device context
LPPOINT  lpPoints,	// address of array receiving path vertices
LPBYTE  lpTypes,	// address of array of path vertex types
int  nSize	// count of points defining path
);
Parameters

hdc

Identifies a device context that contains a closed path.

lpPoints

Points to an array of POINT structures that contains the line endpoints and curve control points.

lpTypes

Points to an array of bytes where the vertex types are placed. Values are one of the following:

Type	Description
PT_MOVETO	Specifies that the corresponding point in the lpPoints parameter starts a disjoint figure.
PT_LINETO	Specifies that the previous point and the corresponding point in lpPoints are the endpoints of a line.
PT_BEZIERTO	Specifies that the corresponding point in lpPoints is a control point or ending point for a Bézier curve.
	PT_BEZIERTO values always occur in sets of three. The point in the path immediately preceding them defines the starting point for the Bézier curve. The first two PT_BEZIERTO points are the control points, and the third PT_BEZIERTO point is the ending (if hard-coded) point.
A PT_LINETO or PT_BEZIERTO value may be combined with the following value (by using the bitwise operator OR) to indicate that the corresponding point is the last point in a figure and the figure should be closed:

Flag	Description
PT_CLOSEFIGURE	Specifies that the figure is automatically closed after the corresponding line or curve is drawn. The figure is closed by drawing a line from the line or curve endpoint to the point corresponding to the last PT_MOVETO.
nSize

Specifies the total number of POINT structures that may be placed in the array pointed to by lpPoints. This value must be the same as the number of bytes that may be placed in the array pointed to by lpTypes.

Return Value

If the nSize parameter is nonzero, the return value is the number of points enumerated. If nSize is 0, the return value is the total number of points in the path (and GetPath writes nothing to the buffers). If nSize is nonzero and is less than the number of points in the path, the return value is −1. To get extended error information, call GetLastError. GetLastError may return one of the following error codes:

ERROR_CAN_NOT_COMPLETE
ERROR_INVALID_PARAMETER
ERROR_BUFFER_OVERFLOW

Remarks

The device context identified by the hdc parameter must contain a closed path.

The points of the path are returned in logical coordinates. Points are stored in the path in device coordinates, so GetPath changes the points from device coordinates to logical coordinates by using the inverse of the current transformation.

The FlattenPath function may be called before GetPath to convert all curves in the path into line segments.

See Also

FlattenPath, POINT, PolyDraw, WidenPath


getpeername
getpeername  QuickInfo

The Windows Sockets getpeername function gets the address of the peer to which a socket is connected.

int getpeername(

SOCKET s,
struct sockaddr FAR * name,
int FAR * namelen
);
Parameters

s

A descriptor identifying a connected socket.

name

The structure which is to receive the name of the peer.

namelen

A pointer to the size of the name structure.

Return Value

If no error occurs, getpeername returns zero. Otherwise, a value of SOCKET_ERROR is returned, and a specific error code may be retrieved by calling WSAGetLastError.

Error Codes

WSANOTINITIALISED	A successful WSAStartup must occur before using this function.
WSAENETDOWN	The Windows Sockets implementation has detected that the network subsystem has failed.
WSAEFAULT	The namelen argument is not large enough.
WSAEINPROGRESS	A blocking Windows Sockets call is in progress.
WSAENOTCONN	The socket is not connected.
WSAENOTSOCK	The descriptor is not a socket.
Remarks

The getpeername function retrieves the name of the peer connected to the socket s and stores it in the socket address structure identified by name. It is used on a connected datagram or stream socket.

On return, the namelen argument contains the actual size of the name returned in bytes.

See Also

bind, getsockname, socket


GetPixel
GetPixel  QuickInfo  Overview  Group

The GetPixel function retrieves the red, green, blue (RGB) color value of the pixel at the specified coordinates.

COLORREF GetPixel(

HDC  hdc,	// handle of device context
int  nXPos,	// x-coordinate of pixel
int  nYPos	// y-coordinate of pixel
);
Parameters

hdc

Identifies the device context.

nXPos

Specifies the logical x-coordinate of the pixel to be examined.

nYPos

Specifies the logical y-coordinate of the pixel to be examined.

Return Value

If the function succeeds, the return value is an RGB value. If the pixel is outside of the current clipping region, the return value is CLR_INVALID.

Remarks

The pixel must be within the boundaries of the current clipping region.

Not all devices support GetPixel. An application should call GetDeviceCaps to determine whether a specified device supports this function.

See Also

GetDeviceCaps


GetPolyFillMode
GetPolyFillMode  QuickInfo  Overview  Group

The GetPolyFillMode function retrieves the current polygon fill mode.

int GetPolyFillMode(

HDC  hdc	// handle of device context
);
Parameters

hdc

Identifies the device context.

Return Value

If the function succeeds, the return value specifies the polygon fill mode, which can be either of the following values:

Value	Meaning
ALTERNATE	Selects alternate mode (fills area between odd-numbered and even-numbered polygon sides on each scan line).
WINDING	Selects winding mode (fills any region with a nonzero winding value).
If an error occurs, the return value is zero.

See Also

SetPolyFillMode


GetPrinter
GetPrinter  QuickInfo  Overview  Group

The GetPrinter function retrieves information about a specified printer.

BOOL GetPrinter(

HANDLE  hPrinter,	// handle to printer of interest
DWORD  Level,	// version of printer info data structure
LPBYTE  pPrinter,	// pointer to array of bytes that receives printer info. structure
DWORD  cbBuf,	// size, in bytes, of array of bytes
LPDWORD  pcbNeeded	// pointer to variable with count of bytes retrieved (or required)
);
Parameters

hPrinter

Handle to the printer of interest.

Level

Specifies the level, or type, of PRINTER_INFO_* structure that the function stores into the buffer pointed to by pPrinter.

Windows 95: This value can be 1, 2, or 5.

Windows NT: This value can be 1, 2, 3, or 4.

pPrinter

Pointer to a buffer that receives a PRINTER_INFO_* structure. This structure contains information about the specified printer. The type of structure is determined by the value of Level.

Windows 95: The buffer can receive a PRINTER_INFO_1, PRINTER_INFO_2, PRINTER_INFO_5 structure.

Windows NT: The buffer can receive a PRINTER_INFO_1, PRINTER_INFO_2, or PRINTER_INFO_3 or PRINTER_INFO_4, structure.

cbBuf

Specifies the size, in bytes, of the buffer pointed to by pPrinter.

pcbNeeded

Pointer to a variable that the function sets to the size in bytes of the printer information. If cbBuf is smaller than this value, GetPrinter fails, and the value represents the required buffer size. If cbBuf is equal to or greater than this value, GetPrinter succeeds, and the value represents the number of bytes stored into the buffer.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

If the structure returned in the buffer pointed to by the pPrinter parameter contains a pointer to a security descriptor, only those components of the security descriptor that the caller has permission to read will be present. An application that wants to retrieve particular security descriptor components must open the printer with sufficient access permission. The following table shows the security descriptor components that are retrieved for particular access permission values:

Access Permission	Security Descriptor Components Retrieved
READ_CONTROL	Owner, Primary Group, Discretionary access-control list (ACL)
ACCESS_SYSTEM_SECURITY	System ACL
See Also

AbortPrinter, AddPrinter, ClosePrinter, DeletePrinter, EnumPrinters, PRINTER_INFO_1, PRINTER_INFO_2, PRINTER_INFO_3, PRINTER_INFO_4, PRINTER_INFO_5, OpenPrinter, SetPrinter


GetPrinterData
GetPrinterData  QuickInfo  Overview  Group

The GetPrinterData function retrieves printer-configuration data for the specified printer.

DWORD GetPrinterData(

HANDLE  hPrinter,	// handle of printer object
LPTSTR  pValueName,	// address of data type
LPDWORD  pType,	// reserved
LPBYTE  pData,	// address of array of bytes that receives data
DWORD  nSize,	// size, in bytes, of array
LPDWORD  pcbNeeded	// address of variable with number of bytes retrieved (or required)
);
Parameters

hPrinter

Identifies the printer for which configuration data should be retrieved.

pValueName

Points to a null-terminated string that specifies the type of data that the function should retrieve.

pType

Points to a variable that receives the data type stored by the SetPrinterData function. GetPrinterData passes pType on as the lpdwType parameter of a RegQueryValueEx function call. This parameter may be NULL.

pData

Points to an array of bytes that receives the configuration data.

nSize

Specifies the size, in bytes, of the buffer pointed to by pData.

pcbNeeded

Points to a value that specifies the number of bytes copied if the function succeeds or the number of bytes required if nSize is too small.

Return Value

If the function succeeds, the return value is ERROR_SUCCESS.

If the function fails, the return value is an error value.

Remarks

The printer handle identified by the hPrinter parameter is obtained by calling the OpenPrinter function.

GetPrinterData retrieves printer-configuration data set by the SetPrinter function.

See Also

OpenPrinter, RegQueryValueEx, SetPrinter, SetPrinterData,


GetPrinterDriver
GetPrinterDriver  QuickInfo  Overview  Group

The GetPrinterDriver function retrieves driver data for the specified printer.

BOOL GetPrinterDriver(

HANDLE  hPrinter,	// printer object
LPTSTR  pEnvironment,	// address of environment
DWORD  Level,	// structure level
LPBYTE  pDriverInfo,	// address of structure array
DWORD  cbBuf,	// size, in bytes, of array
LPDWORD  pcbNeeded	// address of variable with number of bytes retrieved (or required)
);
Parameters

hPrinter

Identifies the printer for which the driver data should be retrieved.

pEnvironment

Points to a null-terminated string that specifies the environment. For example, "Windows NT x86" specifies Windows NT running on an Intel 80386 or 80486 processor. If this parameter is NULL, the current environment of the calling application and client machine (not of the destination application and print server) is used.

Level

Specifies the version of the structure to which lpbForm points. This value must be either 1, 2., or 3.

Windows 95

The value can be 1, 2, or 3.

Windows NT

The value must be either 1 or 2.

pDriverInfo

Points to either a DRIVER_INFO_1, DRIVER_INFO_2, or DRIVER_INFO_3structure. If Level is 1, this array receives a DRIVER_INFO_1 structure; if Level is 2, this array receives a DRIVER_INFO_2 structure, if Level is 3, this array receives a DRIVER_INFO_3 structure.

Windows 95

All three driver-information structures are supported..

Windows NT

DRIVER_INFO_3 structure is not supported.

cbBuf

Specifies the size, in bytes, of the array at which pDriverInfo points.

pcbNeeded

Points to a value that specifies the number of bytes copied if the function succeeds or the number of bytes required if cbBuf is too small.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The printer handle identified by the hPrinter parameter should be retrieved by calling the OpenPrinter function.

The DRIVER_INFO_2 and DRIVER_INFO_3 structures contain a full path and filename specifying the location of the printer driver. An application can use the path and filename to load a printer driver by calling the LoadLibrary function and supplying the path and filename as the single argument.

See Also

AddPrinterDriver, DRIVER_INFO_1, DRIVER_INFO_2, EnumPrinterDrivers, LoadLibrary, OpenPrinter


GetPrinterDriverDirectory
GetPrinterDriverDirectory  QuickInfo  Overview  Group

The GetPrinterDriverDirectory function retrieves the path of the printer-driver directory.

BOOL GetPrinterDriverDirectory(

LPTSTR  pName,	// address of server name
LPTSTR  pEnvironment,	// address of environment
DWORD  Level,	// address of structure
LPBYTE  pDriverDirectory,	// address of structure array that receives path
DWORD  cbBuf,	// size, in bytes, of array
LPDWORD  pcbNeeded	// address of variable with number of bytes retrieved (or required)
);
Parameters

pName

Points to a null-terminated string that specifies the name of the server on which the printer driver resides. If this parameter is NULL, the local driver-directory path is retrieved.

pEnvironment

Points to a null-terminated string that specifies the environment. For example, "Windows NT x86" specifies Windows NT running on an Intel 80386 or 80486 processor. If this parameter is NULL, the current environment of the calling application and client machine (not of the destination application and print server) is used.

Level

Specifies the structure level. This value must be 1.

pDriverDirectory

Points to an array of bytes that receives the path.

cbBuf

Specifies the size of the array to which pDriverDirectory points.

pcbNeeded

Points to a value that specifies the number of bytes copied if the function succeeds, or the number of bytes required if cbBuf is too small.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

AddPrinterDriver


GetPrintProcessorDirectory
GetPrintProcessorDirectory  QuickInfo  Overview  Group

The GetPrintProcessorDirectory function retrieves the path for the print processor on the specified server.

BOOL GetPrintProcessorDirectory(

LPTSTR  pName,	// address of server name
LPTSTR  pEnvironment,	// address of environment
DWORD  Level,	// structure level
LPBYTE  pPrintProcessorInfo,	// address of structure array
DWORD  cbBuf,	// size, in bytes, of array
LPDWORD  pcbNeeded	// address of variable with number of bytes retrieved (or required)
);
Parameters

pName

Points to a null-terminated string that specifies the name of the server. If this parameter is NULL, a local path is returned.

pEnvironment

Points to a null-terminated string that specifies the environment. For example, "Windows NT x86" specifies Windows NT running on an Intel 80386 or 80486 processor. If this parameter is NULL, the current environment of the calling application and client machine (not of the destination application and print server) is used.

Level

Specifies the structure level. This value must be 1.

pPrintProcessorInfo

Points to an array of bytes into which the path is copied.

cbBuf

Specifies the size of the buffer pointed to by pPrintProcessorInfo.

pcbNeeded

Points to a value that specifies the number of bytes copied if the function succeeds, or the number of bytes required if cbBuf is too small.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

AddPrintProcessor


GetPriorityClass
GetPriorityClass  QuickInfo  Overview  Group

The GetPriorityClass function returns the priority class for the specified process. This value, together with the priority value of each thread of the process, determines each thread's base priority level.

DWORD GetPriorityClass(

HANDLE  hProcess	// handle to the process
);
Parameters

hProcess

Identifies the process. The handle must have PROCESS_QUERY_INFORMATION access.

Return Value

If the function succeeds, the return value is the priority class of the specified process.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

The process's priority class is one of the following values:

Priority	Meaning
HIGH_PRIORITY_CLASS	Indicates a process that performs time-critical tasks that must be executed immediately for it to run correctly. The threads of a high-priority class process preempt the threads of normal or idle priority class processes. An example is Windows Task List, which must respond quickly when called by the user, regardless of the load on the operating system. Use extreme care when using the high-priority class, because a high-priority class CPU-bound application can use nearly all available cycles.
IDLE_PRIORITY_CLASS	Indicates a process whose threads run only when the system is idle and are preempted by the threads of any process running in a higher priority class. An example is a screen saver. The idle priority class is inherited by child processes.
NORMAL_PRIORITY_CLASS	Indicates a normal process with no special scheduling needs.
REALTIME_PRIORITY_CLASS	Indicates a process that has the highest possible priority. The threads of a real-time priority class process preempt the threads of all other processes, including operating system processes performing important tasks. For example, a real-time process that executes for more than a very brief interval can cause disk caches not to flush or cause the mouse to be unresponsive.
Remarks

Every thread has a base priority level determined by the thread's priority value and the priority class of its process. The operating system uses the base priority level of all executable threads to determine which thread gets the next slice of CPU time. Threads are scheduled in a round-robin fashion at each priority level, and only when there are no executable threads at a higher level will scheduling of threads at a lower level take place.

For a table that shows the base priority levels for each combination of priority class and thread priority value, see the SetPriorityClass function.

See Also

GetThreadPriority, SetPriorityClass, SetThreadPriority


GetPriorityClipboardFormat
GetPriorityClipboardFormat  QuickInfo  Overview  Group

The GetPriorityClipboardFormat function returns the first available clipboard format in the specified list.

int GetPriorityClipboardFormat(

UINT  * paFormatPriorityList,	// address of priority list
int  cFormats	// number of entries in list
);
Parameters

paFormatPriorityList

Points to an array of unsigned integers identifying clipboard formats, in priority order. For a description of the clipboard formats, see the SetClipboardData function.

cFormats

Specifies the number of entries in the paFormatPriorityList array. This value must not be greater than the number of entries in the list.

Return Value

If the function succeeds, the return value is the first clipboard format in the list for which data is available. If the clipboard is empty, the return value is NULL. If the clipboard contains data, but not in any of the specified formats, the return value is −1. To get extended error information, call GetLastError.

See Also

CountClipboardFormats, EnumClipboardFormats, GetClipboardFormatName, IsClipboardFormatAvailable, RegisterClipboardFormat, SetClipboardData


GetPrivateObjectSecurity
GetPrivateObjectSecurity  QuickInfo  Overview  Group

The GetPrivateObjectSecurity retrieves information from a protected server object's security descriptor.

BOOL GetPrivateObjectSecurity(

PSECURITY_DESCRIPTOR  ObjectDescriptor,	// address of SD to query
SECURITY_INFORMATION  SecurityInformation,	// requested information
PSECURITY_DESCRIPTOR  ResultantDescriptor,	// address of retrieved SD
DWORD  DescriptorLength,	// size of buffer for retrieved SD
PDWORD  ReturnLength	// address of buffer size required for SD
);
Parameters

ObjectDescriptor

Points to a SECURITY_DESCRIPTOR structure. This is the security descriptor to be queried.

SecurityInformation

Specifies a SECURITY_INFORMATION structure that identifies the security information being requested.

ResultantDescriptor

Points to a buffer receiving a copy of the requested information from the specified security descriptor. The SECURITY_DESCRIPTOR structure is returned in self-relative format.

DescriptorLength

Specifies the size, in bytes, of the buffer pointed to by the ResultantDescriptor parameter.

ReturnLength

Points to a variable the function sets to zero if the descriptor is copied successfully. If the buffer is too small for the security descriptor, this variable receives the number of bytes required. If this variable's value is greater than the value of the DescriptorLength parameter when the function returns, the function returns FALSE and none of the security descriptor is copied to the buffer.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

An application must perform appropriate access/privilege checks and audits before calling this function.

See Also

CreatePrivateObjectSecurity, DestroyPrivateObjectSecurity, GetFileSecurity, GetKernelObjectSecurity, GetUserObjectSecurity, SECURITY_DESCRIPTOR, SECURITY_INFORMATION, SetPrivateObjectSecurity


GetPrivateProfileInt
GetPrivateProfileInt  QuickInfo

The GetPrivateProfileInt function retrieves an integer associated with a key in the specified section of the given initialization file. This function is provided for compatibility with 16-bit Windows-based applications. Win32-based applications should store initialization information in the registry.

UINT GetPrivateProfileInt(

LPCTSTR  lpAppName,	// address of section name
LPCTSTR  lpKeyName,	// address of key name
INT  nDefault,	// return value if key name is not found
LPCTSTR  lpFileName	// address of initialization filename
);
Parameters

lpAppName

Points to a null-terminated string containing the section name in the initialization file.

lpKeyName

Points to the null-terminated string containing the key name whose value is to be retrieved. This value is in the form of a string; the GetPrivateProfileInt function converts the string into an integer and returns the integer.

nDefault

Specifies the default value to return if the key name cannot be found in the initialization file.

lpFileName

Points to a null-terminated string that names the initialization file. If this parameter does not contain a full path to the file, Windows searches for the file in the Windows directory.

Return Value

If the function succeeds, the return value is the integer equivalent of the string following the specified key name in the specified initialization file. If the key is not found, the return value is the specified default value. If the value of the key is less than zero, the return value is zero.

Remarks

The function searches the file for a key that matches the name specified by the lpKeyName parameter under the section name specified by the lpAppName parameter. A section in the initialization file must have the following form:

[section]
key=value
      .
      .
      .

The GetPrivateProfileInt function is not case-sensitive; the strings in lpAppName and lpKeyName can be a combination of uppercase and lowercase letters.

An application can use the GetProfileInt function to retrieve an integer value from the WIN.INI file.

Windows NT: Calls to private profile functions may be mapped to the registry instead of to the specified initialization files. This mapping occurs when the initialization file and section are specified in the registry under the following keys:

HKEY_LOCAL_MACHINE\Software\Microsoft\
        Windows NT\CurrentVersion\IniFileMapping

This mapping is likely if an application modifies system-component initialization files, such as CONTROL.INI, SYSTEM.INI, and WINFILE.INI. In these cases, the GetPrivateProfileInt function retrieves information from the registry, not from the initialization file; the change in the storage location has no effect on the function's behavior.

See Also

GetProfileInt, WritePrivateProfileString


GetPrivateProfileSection
GetPrivateProfileSection  QuickInfo

The GetPrivateProfileSection function retrieves all of the keys and values for the specified section from an initialization file. This function is provided for compatibility with 16-bit applications written for Windows. Win32-based applications should store initialization information in the registry.

Windows 95

The specified profile section must not exceed 32K.

Windows NT

The specified profile section has no size limit.

DWORD GetPrivateProfileSection(

LPCTSTR  lpAppName,	// address of section name
LPTSTR  lpReturnedString,	// address of return buffer
DWORD  nSize,	// size of return buffer
LPCTSTR  lpFileName	// address of initialization filename
);
Parameters

lpAppName

Points to a null-terminated string containing the section name in the initialization file.

lpReturnedString

Points to a buffer that receives the key name and value pairs associated with the named section. The buffer is filled with one or more null-terminated strings; the last string is followed by a second null character.

nSize

Specifies the size, in characters, of the buffer pointed to by the lpReturnedString parameter.

Windows 95

The maximum buffer size is 32,767 characters.

Windows NT

There is no maximum buffer size.

lpFileName

Points to a null-terminated string that names the initialization file. If this parameter does not contain a full path to the file, Windows searches for the file in the Windows directory.

Return Value

The return value specifies the number of characters copied to the buffer, not including the terminating null character. If the buffer is not large enough to contain all the key name and value pairs associated with the named section, the return value is equal to nSize minus two.

Remarks

The data in the buffer pointed to by the lpReturnedString parameter consists of one or more null-terminated strings, followed by a final null character. Each string has the following format:

key=string

The GetPrivateProfileSection function is not case-sensitive; the string pointed to by the lpAppName parameter can be a combination of uppercase and lowercase letters.

This operation is atomic; no updates to the specified initialization file are allowed while the key name and value pairs for the section are being copied to the buffer pointed to by the lpReturnedString parameter.

Windows NT: Calls to private profile functions may be mapped to the registry instead of to the specified initialization files. This mapping occurs when the initialization file and section are specified in the registry under the following keys:

HKEY_LOCAL_MACHINE\Software\Microsoft\
        Windows NT\CurrentVersion\IniFileMapping

This mapping is likely if an application modifies system-component initialization files, such as CONTROL.INI, SYSTEM.INI, and WINFILE.INI. In these cases, the GetPrivateProfileSection function retrieves information from the registry, not from the initialization file; the change in the storage location has no effect on the function's behavior.

See Also

GetProfileSection, WritePrivateProfileSection


GetPrivateProfileSectionNames [New - Windows NT]
GetPrivateProfileSectionNames  QuickInfo

[New - Windows NT]

The GetPrivateProfileSectionNames function retrieves the names of all sections in an initialization file. This function is provided for compatibility with 16-bit Windows-based applications. Win32-based applications should store initialization information in the registry.

DWORD GetPrivateProfileSectionNames(

LPTSTR  lpszReturnBuffer,	// address of return buffer
DWORD  nSize,	// size of return buffer
LPCTSTR  lpFileName	// address of initialization filename
);
Parameters

lpszReturnBuffer

Points to a buffer that receives the section names associated with the named file. The buffer is filled with one or more null-terminated strings; the last string is followed by a second null character.

nSize

Specifies the size, in characters, of the buffer pointed to by the lpszReturnBuffer parameter.

lpFileName

Points to a null-terminated string that names the initialization file. If this parameter is NULL, the function searches the WIN.INI file. If this parameter does not contain a full path to the file, Windows searches for the file in the Windows directory.

Return Value

The return value specifies the number of characters copied to the specified buffer, not including the terminating null character. If the buffer is not large enough to contain all the section names associated with the specified initialization file, the return value is equal to the length specified by nSize minus two.

Remarks

This operation is atomic; no updates to the initialization file are allowed while the section names are being copied to the buffer.

Calls to profile functions might be mapped to the registry instead of to the initialization files. When the operation has been mapped, the GetPrivateProfileSectionNames function retrieves information from the registry, not from the initialization file; the change in the storage location has no effect on the function's behavior.

See Also

GetPrivateProfileSection, WritePrivateProfileSection


GetPrivateProfileString
GetPrivateProfileString  QuickInfo

The GetPrivateProfileString function retrieves a string from the specified section in an initialization file. This function is provided for compatibility with 16-bit Windows-based applications. Win32-based applications should store initialization information in the registry.

DWORD GetPrivateProfileString(

LPCTSTR  lpAppName,	// points to section name
LPCTSTR  lpKeyName,	// points to key name
LPCTSTR  lpDefault,	// points to default string
LPTSTR  lpReturnedString,	// points to destination buffer
DWORD  nSize,	// size of destination buffer
LPCTSTR  lpFileName	// points to initialization filename
);
Parameters

lpAppName

Points to a null-terminated string that specifies the section containing the key name. If this parameter is NULL, the GetPrivateProfileString function copies all section names in the file to the supplied buffer.

lpKeyName

Points to the null-terminated string containing the key name whose associated string is to be retrieved. If this parameter is NULL, all key names in the section specified by the lpAppName parameter are copied to the buffer specified by the lpReturnedString parameter.

lpDefault

Points to a null-terminated string that specifies the default value for the given key if the key cannot be found in the initialization file. This parameter cannot be NULL.

lpReturnedString

Points to the buffer that receives the retrieved string.

nSize

Specifies the size, in characters, of the buffer pointed to by the lpReturnedString parameter.

lpFileName

Points to a null-terminated string that names the initialization file. If this parameter does not contain a full path to the file, Windows searches for the file in the Windows directory.

Return Value

If the function succeeds, the return value is the number of characters copied to the buffer, not including the terminating null character.

If neither lpAppName nor lpKeyName is NULL and the supplied destination buffer is too small to hold the requested string, the string is truncated and followed by a null character, and the return value is equal to nSize minus one.

If either lpAppName or lpKeyName is NULL and the supplied destination buffer is too small to hold all the strings, the last string is truncated and followed by two null characters. In this case, the return value is equal to nSize minus two.

Remarks

The GetPrivateProfileString function searches the specified initialization file for a key that matches the name specified by the lpKeyName parameter under the section heading specified by the lpAppName parameter. If it finds the key, the function copies the corresponding string to the buffer. If the key does not exist, the function copies the default character string specified by the lpDefault parameter. A section in the initialization file must have the following form:

[section]
key=string
      .
      .
      .

If lpAppName is NULL, GetPrivateProfileString copies all section names in the specified file to the supplied buffer. If lpKeyName is NULL, the function copies all key names in the specified section to the supplied buffer. An application can use this method to enumerate all of the sections and keys in a file. In either case, each string is followed by a null character and the final string is followed by a second null character. If the supplied destination buffer is too small to hold all the strings, the last string is truncated and followed by two null characters.

If the string associated with lpKeyName is enclosed in single or double quotation marks, the marks are discarded when the GetPrivateProfileString function retrieves the string.

The GetPrivateProfileString function is not case-sensitive; the strings can be a combination of uppercase and lowercase letters.

To retrieve a string from the WIN.INI file, use the GetProfileString function.

Windows NT: Calls to private profile functions may be mapped to the registry instead of to the specified initialization files. This mapping occurs when the initialization file and section are specified in the registry under the following keys:

HKEY_LOCAL_MACHINE\Software\Microsoft\
        Windows NT\CurrentVersion\IniFileMapping

This mapping is likely if an application modifies system-component initialization files, such as CONTROL.INI, SYSTEM.INI, and WINFILE.INI. In these cases, the GetPrivateProfileString function retrieves information from the registry, not from the initialization file; the change in the storage location has no effect on the function's behavior.

See Also

GetProfileString, WritePrivateProfileString


GetPrivateProfileStruct [New - Windows NT]
GetPrivateProfileStruct  QuickInfo

[New - Windows NT]

The GetPrivateProfileStruct function retrieves the data associated with the specified key in the given section of an initialization file. As it retrieves the data, the function calculates a checksum and compares it with the checksum calculated by the WritePrivateProfileStruct function when the data was added to the file. This function is provided for compatibility with 16-bit Windows-based applications. Win32-based applications should store initialization information in the registry.

BOOL GetPrivateProfileStruct(

LPCTSTR  lpszSection,	// address of section name
LPCTSTR  lpszKey,	// address of key name
LPVOID  lpStruct,	// address of return buffer
UINT  uSizeStruct,	// size of return buffer
LPCTSTR  szFile	// address of initialization filename
);
Parameters

lpszSection

Points to a null-terminated string containing the section name in the initialization file.

lpszKey

Points to the null-terminated string containing the key name whose data is to be retrieved.

lpStruct

Points to the buffer that receives the data associated with the file, section, and key names.

uSizeStruct

Specifies the size, in bytes, of the buffer pointed to by the lpStruct parameter.

szFile

Points to a null-terminated string that names the initialization file. If this parameter does not contain a full path to the file, Windows searches for the file in the Windows directory.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

A section in the initialization file must have the following form:

[section]
key=data
      .
      .
      .

Calls to private profile functions might be mapped to the registry instead of to the specified initialization files. This mapping is likely if an application modifies system-component initialization files, such as CONTROL.INI, SYSTEM.INI, and WINFILE.INI. In these cases, the GetPrivateProfileStruct function retrieves information from the registry, not from the initialization file; the change in the storage location has no effect on the function's behavior.

See Also

WritePrivateProfileStruct


GetProcAddress
GetProcAddress  QuickInfo  Overview  Group

The GetProcAddress function returns the address of the specified exported dynamic-link library (DLL) function.

FARPROC GetProcAddress(

HMODULE  hModule,	// handle to DLL module
LPCSTR  lpProcName	// name of function
);
Parameters

hModule

Identifies the DLL module that contains the function. The LoadLibrary or GetModuleHandle function returns this handle.

lpProcName

Points to a null-terminated string containing the function name, or specifies the function's ordinal value. If this parameter is an ordinal value, it must be in the low-order word; the high-order word must be zero.

Return Value

If the function succeeds, the return value is the address of the DLL's exported function.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

The GetProcAddress function is used to retrieve addresses of exported functions in DLLs.

The spelling and case of the function name pointed to by lpProcName must be identical to that in the EXPORTS statement of the source DLL's module-definition (.DEF) file.

The lpProcName parameter can identify the DLL function by specifying an ordinal value associated with the function in the EXPORTS statement. GetProcAddress verifies that the specified ordinal is in the range 1 through the highest ordinal value exported in the .DEF file. The function then uses the ordinal as an index to read the function's address from a function table. If the .DEF file does not number the functions consecutively from 1 to N (where N is the number of exported functions), an error can occur where GetProcAddress returns an invalid, non-NULL address, even though there is no function with the specified ordinal.

In cases where the function may not exist, the function should be specified by name rather than by ordinal value.

See Also

FreeLibrary, GetModuleHandle, LoadLibrary


GetProcessAffinityMask
GetProcessAffinityMask  QuickInfo  Overview  Group

The GetProcessAffinityMask function obtains a process affinity mask for the specified process and the system affinity mask for the system.

A process affinity mask is a bit vector in which each bit represents the processors that a process is allowed to run on. A system affinity mask is a bit vector in which each bit represents the processors that are configured into a system.

A process affinity mask is a proper subset of a system affinity mask. A process is only allowed to run on the processors configured into a system.

BOOL GetProcessAffinityMask(

HANDLE  hProcess,	// handle to the process of interest
LPDWORD  lpProcessAffinityMask,	// pointer to structure to receive process affinity mask
LPDWORD  lpSystemAffinityMask	// pointer to structure to receive system affinity mask
);
Parameters

hProcess

An open handle to the process whose affinity mask is desired. This handle must have PROCESS_QUERY_INFORMATION access.

lpProcessAffinityMask

Pointer to a DWORD that the function sets to the process affinity mask for the specified process.

lpSystemAffinityMask

Pointer to a DWORD that the function sets to the system affinity mask for the system.

Return Value

If the function succeeds, the return value is TRUE.

Windows 95: The successful function sets the DWORD variables pointed to by lpProcessAffinityMask and lpSystemAffinityMask to the value one.

Windows NT: The successful function sets the DWORD variables pointed to by lpProcessAffinityMask and lpSystemAffinityMask to the appropriate affinity masks.

If the function fails, the return value is FALSE, and the values of the DWORD variables pointed to by lpProcessAffinityMask and lpSystemAffinityMask are undefined.

See Also

SetThreadAffinityMask


GetProcessHeap
GetProcessHeap  QuickInfo  Overview  Group

The GetProcessHeap function obtains a handle to the heap of the calling process. This handle can then be used in calls to the HeapAlloc, HeapReAlloc, HeapFree, and HeapSize functions.

HANDLE GetProcessHeap(VOID)

Parameters

This function has no parameters.

Return Value

If the function succeeds, the return value is a handle to the calling process's heap.

If the function fails, the return value is NULL.

Remarks

GetProcessHeap allows Win32-based applications to allocate memory from the process heap without having to first create a heap with the HeapCreate function, as shown in this example:

HeapAlloc(GetProcessHeap(), 0, dwBytes);

Note that the handle obtained by calling the function should not be used in calls to the HeapDestroy function.

Note, also, that the HEAP_NO_SERIALIZE flag should not be specified when using the HeapAlloc, HeapFree, HeapReAlloc, and HeapSize functions to access the process heap. The system may create additional threads within the application's process, such as a Ctrl+C handler, that simultaneously access the process heap. For more information about HEAP_NO_SERIALIZE, see the HeapCreate function.

See Also

GetProcessHeaps, HeapAlloc, HeapCreate, HeapDestroy, HeapFree, HeapReAlloc, HeapSize


GetProcessHeaps
GetProcessHeaps  QuickInfo  Overview  Group

The GetProcessHeaps function obtains handles to all of the heaps that are valid for the calling process.

DWORD GetProcessHeaps(

DWORD  NumberOfHeaps,	// maximum number of heap handles buffer can receive
PHANDLE  ProcessHeaps	// points to buffer to receive array of heap handles
);
Parameters

NumberOfHeaps

Specifies the maximum number of heap handles that can be stored into the buffer pointed to by ProcessHeaps.

ProcessHeaps

Points to a buffer to receive an array of heap handles.

Return Value

The return value is the number of heap handles that are valid for the calling process.

If the return value is less than or equal to NumberOfHeaps, it is also the number of heap handles stored into the buffer pointed to by ProcessHeaps.

If the return value is greater than NumberOfHeaps, the buffer pointed to by ProcessHeaps is too small to hold all the valid heap handles of the calling process.The function will have stored no handles into that buffer. In this situation, use the return value to allocate a buffer that is large enough to receive the handles, and call the function again.

If the return value is zero, the function has failed, because every Win32 process has at least one valid heap, the process heap. To get extended error information, call GetLastError.

Remarks

Use the GetProcessHeap function to obtain a handle to the process heap of the calling process. The GetProcessHeaps function obtains a handle to that heap, plus handles to any additional private heaps created by calling the HeapCreate function.

See Also

GetProcessHeap , HeapCreate


GetProcessShutdownParameters
GetProcessShutdownParameters  QuickInfo  Overview  Group

The GetProcessShutdownParameters function retrieves shutdown parameters for the currently calling process.

BOOL GetProcessShutdownParameters(

LPDWORD  lpdwLevel,	// shutdown priority
LPDWORD  lpdwFlags	// shutdown flag
);
Parameters

lpdwLevel

Points to a variable that receives the shutdown priority level. Higher levels shut down first. System level shutdown orders are reserved for system components. Higher numbers shut down first. Following are the level conventions:

Value	Meaning
000−0FF	System reserved last shutdown range.
100−1FF	Application reserved last shutdown range.
200−2FF	Application reserved "in between" shutdown range.
300−3FF	Application reserved first shutdown range.
400−4FF	System reserved first shutdown range.
All processes start at shutdown level 0x280.

lpdwFlags

Points to a variable that receives the shutdown flags. It can be the following value:

Value	Meaning
SHUTDOWN_NORETRY	If this process takes longer than the specified timeout to shut down, do not display a retry dialog box for the user. Instead, just cause the process to directly exit.
Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

See Also

SetProcessShutdownParameters


GetProcessTimes
GetProcessTimes  QuickInfo  Overview  Group

The GetProcessTimes function obtains timing information about a specified process.

BOOL GetProcessTimes(

HANDLE  hProcess,	// specifies the process of interest
LPFILETIME  lpCreationTime,	// when the process was created
LPFILETIME  lpExitTime,	// when the process exited
LPFILETIME  lpKernelTime,	// time the process has spent in kernel mode
LPFILETIME  lpUserTime	// time the process has spent in user mode
);
Parameters

hProcess

An open handle that specifies the process whose timing information is sought. This handle must be created with PROCESS_QUERY_INFORMATION access.

lpCreationTime

Points to a FILETIME structure that receives the creation time of the process.

lpExitTime

Points to a FILETIME structure that receives the exit time of the process. If the process has not exited, the content of this structure is undefined.

lpKernelTime

Points to a FILETIME structure that receives the amount of time that the process has executed in kernel mode. The time that each of the threads of the process has executed in kernel mode is determined, and then all of those times are summed together to obtain this value.

lpUserTime

Points to a FILETIME structure that receives the amount of time that the process has executed in user mode. The time that each of the threads of the process has executed in user mode is determined, and then all of those times are summed together to obtain this value.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

All times are expressed using FILETIME data structures. Such a structure contains two 32-bit values that combine to form a 64-bit count of 100-nanosecond time units.

Process creation and exit times are points in time expressed as the amount of time that has elapsed since midnight on January 1, 1601 at Greenwich, England. The Win32 API provides several functions that an application can use to convert such values to more generally useful forms.

Process kernel mode and user mode times are amounts of time. For example, if a process has spent one second in kernel mode, this function will fill the FILETIME structure specified by lpKernelTime with a 64-bit value of ten million. That is the number of 100-nanosecond units in one second.

See Also

FILETIME, FileTimeToDosDateTime, FileTimeToLocalFileTime, FileTimeToSystemTime


GetProcessVersion [New - Windows NT]
GetProcessVersion  QuickInfo  Overview  Group

[New - Windows NT]

The GetProcessVersion function obtains the major and minor version numbers of the Windows version on which a specified process expects to run.

DWORD GetProcessVersion(

DWORD  ProcessId	// identifier specifying the process of interest
);
Parameters

ProcessId

Process identifier that specifies the process of interest. A ProcessId value of zero specifies the calling process.

Return Value

If the function succeeds, the return value is the version of Windows on which the process expects to run. The high word of the return value contains the major version number. The low word of the return value contains the minor version number.

If the function fails, the return value is zero. To get extended error information, call GetLastError. The function fails if ProcessId is an invalid value.

Remarks

The GetProcessVersion function performs less quickly when ProcessId is nonzero, specifying a process other than the calling process.

The version number returned by this function is the version number stamped in the image header of the .EXE file the process is running. Linker programs set this value.


GetProcessWindowStation
GetProcessWindowStation  QuickInfo  Overview  Group

The GetProcessWindowStation function returns a handle of the window station associated with the calling process.

HWINSTA GetProcessWindowStation(VOID)

Parameters

This function has no parameters.

Return Value

If the function succeeds, the return value is a handle of the window station associated with the calling process.

If the function fails, the return value is NULL. This can occur if the calling process is not an application written for Windows NT. To get extended error information, call GetLastError.

Remarks

The system associates a window station with a process when the process is created. A process can use the SetProcessWindowStation function to change its window station.

The calling process can use the returned handle in calls to the GetUserObjectInformation, GetUserObjectSecurity, SetUserObjectInformation, and SetUserObjectSecurity functions.

See Also

GetThreadDesktop, GetUserObjectInformation, GetUserObjectSecurity, SetProcessWindowStation, SetUserObjectInformation, SetUserObjectSecurity


GetProcessWorkingSetSize
GetProcessWorkingSetSize  QuickInfo  Overview  Group

The GetProcessWorkingSetSize function obtains the minimum and maximum working set sizes of a specified process.

The "working set" of a process is the set of memory pages currently visible to the process in physical RAM memory. These pages are resident and available for an application to use without triggering a page fault. The size of a process' working set is specified in bytes. The minimum and maximum working set sizes affect the virtual memory paging behavior of a process.

BOOL GetProcessWorkingSetSize(

HANDLE  hProcess,	// open handle to the process of interest
LPDWORD  lpMinimumWorkingSetSize,	// points to variable to receive minimum working set size
LPDWORD  lpMaximumWorkingSetSize	// points to variable to receive maximum working set size
);
Parameters

hProcess

An open handle to the process whose working set sizes will be obtained. The handle must have PROCESS_QUERY_INFORMATION access rights.

lpMinimumWorkingSetSize

Points to a variable that receives the minimum working set size of the specified process. The virtual memory manager attempts to keep at least this much memory resident in the process whenever the process is active.

lpMaximumWorkingSetSize

Points to a variable that receives the maximum working set size of the specified process. The virtual memory manager attempts to keep no more than this much memory resident in the process whenever the process is active when memory is in short supply.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

SetProcessWorkingSetSize


GetProfileInt
GetProfileInt  QuickInfo

The GetProfileInt function retrieves an integer from the specified key name in the given section of the WIN.INI file. This function is provided for compatibility with 16-bit Windows-based applications. Win32-based applications should store initialization information in the registry.

UINT GetProfileInt(

LPCTSTR  lpAppName,	// address of section name
LPCTSTR  lpKeyName,	// address of key name
INT  nDefault	// default value if key name is not found
);
Parameters

lpAppName

Points to a null-terminated string that specifies the section containing the key name.

lpKeyName

Points to the null-terminated string containing the key name whose value is to be retrieved. This value is in the form of a string; the GetProfileInt function converts the string into an integer and returns the integer.

nDefault

Specifies the default value to return if the key name cannot be found in the initialization file..

Return Value

If the function succeeds, the return value is the integer equivalent of the string following the key name in WIN.INI. If the function cannot find the key, the return value is the default value. If the value of the key is less than zero, the return value is zero.

Remarks

If the key name consists of digits followed by characters that are not numeric, the function returns only the value of the digits. For example, the function returns 102 for the following line: KeyName=102abc.

Windows NT: Calls to profile functions may be mapped to the registry instead of to the initialization files. This mapping occurs when the initialization file and section are specified in the registry under the following keys:

HKEY_LOCAL_MACHINE\Software\Microsoft\
        Windows NT\CurrentVersion\IniFileMapping

When the operation has been mapped, the GetProfileInt function retrieves information from the registry, not from the initialization file; the change in the storage location has no effect on the function's behavior.

See Also

GetPrivateProfileInt, WriteProfileString


GetProfileSection
GetProfileSection  QuickInfo

The GetProfileSection function retrieves all of the keys and values for the specified section of the WIN.INI file. This function is provided for compatibility with 16-bit Windows-based applications. Win32-based applications should store initialization information in the registry.

Windows 95

The specified profile section must not exceed 32K.

Windows NT

The specified profile section has no size limit.

DWORD GetProfileSection(

LPCTSTR  lpAppName,	// address of section name
LPTSTR  lpReturnedString,	// address of return buffer
DWORD  nSize	// size of return buffer
);
Parameters

lpAppName

Points to a null-terminated string containing the section name in the WIN.INI file.

lpReturnedString

Points to a buffer that receives the keys and values associated with the named section. The buffer is filled with one or more null-terminated strings; the last string is followed by a second null character.

nSize

Specifies the size, in characters, of the buffer pointed to by the lpReturnedString parameter.

Windows 95

The maximum buffer size is 32,767 characters.

Windows NT

There is no maximum buffer size.

Return Value

The return value specifies the number of characters copied to the specified buffer, not including the terminating null character. If the buffer is not large enough to contain all the keys and values associated with the named section, the return value is equal to the length specified by nSize minus two.

Remarks

The format of the returned keys and values is one or more null-terminated strings, followed by a final null character. Each string has the following form:

key=string

The GetProfileSection function is not case-sensitive; the strings can be a combination of uppercase and lowercase letters.

This operation is atomic; no updates to the WIN.INI file are allowed while the keys and values for the section are being copied to the buffer.

Windows NT: Calls to profile functions may be mapped to the registry instead of to the initialization files. This mapping occurs when the initialization file and section are specified in the registry under the following keys:

HKEY_LOCAL_MACHINE\Software\Microsoft\
        Windows NT\CurrentVersion\IniFileMapping

When the operation has been mapped, the GetProfileSection function retrieves information from the registry, not from the initialization file; the change in the storage location has no effect on the function's behavior.

See Also

GetPrivateProfileSection, WriteProfileSection


GetProfileString
GetProfileString  QuickInfo

The GetProfileString function retrieves the string associated with the specified key in the given section of the WIN.INI file. This function is provided for compatibility with 16-bit Windows-based applications. Win32-based applications should store initialization information in the registry.

DWORD GetProfileString(

LPCTSTR  lpAppName,	// address of section name
LPCTSTR  lpKeyName,	// address of key name
LPCTSTR  lpDefault,	// address of default string
LPTSTR  lpReturnedString,	// address of destination buffer
DWORD  nSize	// size of destination buffer
);
Parameters

lpAppName

Points to a null-terminated string that specifies the section containing the key. If this parameter is NULL, the function copies all section names in the file to the supplied buffer.

lpKeyName

Points to a null-terminated string containing the key name whose associated string is to be retrieved. If this parameter is NULL, the function copies all keys in the given section to the supplied buffer. Each string is followed by a null character, and the final string is followed by a second null character.

lpDefault

Points to the default value for the given key if the key cannot be found in the initialization file. This parameter cannot be NULL.

lpReturnedString

Points to a buffer that receives the character string.

nSize

Specifies the size, in characters, of the buffer pointed to by the lpReturnedString parameter.

Return Value

If the function succeeds, the return value is the number of characters copied to the buffer, not including the null-terminating character.

If neither lpAppName nor lpKeyName is NULL and the supplied destination buffer is too small to hold the requested string, the string is truncated and followed by a null character, and the return value is equal to nSize minus one.

If either lpAppName or lpKeyName is NULL and the supplied destination buffer is too small to hold all the strings, the last string is truncated and followed by two null characters. In this case, the return value is equal to nSize minus two.

Remarks

If the string associated with the lpKeyName parameter is enclosed in single or double quotation marks, the marks are discarded when the GetProfileString function returns the string.

The GetProfileString function is not case-sensitive; the strings can contain a combination of uppercase and lowercase letters.

A section in the WIN.INI file must have the following form:

[section]
key=string
      .
      .
      .

An application can use the GetPrivateProfileString function to retrieve a string from a specified initialization file.

The lpDefault parameter must point to a valid string, even if the string is empty (that is, even if its first character is a null character).

Windows NT: Calls to profile functions may be mapped to the registry instead of to the initialization files. This mapping occurs when the initialization file and section are specified in the registry under the following keys:

HKEY_LOCAL_MACHINE\Software\Microsoft\
        Windows NT\CurrentVersion\IniFileMapping

When the operation has been mapped, the GetProfileString function retrieves information from the registry, not from the initialization file; the change in the storage location has no effect on the function's behavior.

See Also

GetPrivateProfileString, WriteProfileString


GetProp
GetProp  QuickInfo  Overview  Group

The GetProp function retrieves a data handle from the property list of the given window. The given character string identifies the handle to be retrieved. The string and handle must have been added to the property list by a previous call to the SetProp function.

HANDLE GetProp(

HWND  hWnd,	// handle of window
LPCTSTR  lpString	// atom or address of string
);
Parameters

hWnd

Identifies the window whose property list is to be searched.

lpString

Points to a null-terminated character string or contains an atom that identifies a string. If this parameter is an atom, it must have been created by using the GlobalAddAtom function. The atom, a 16-bit value, must be placed in the low-order word of the lpString parameter; the high-order word must be zero.

Return Value

If the property list contains the given string, the return value is the associated data handle. Otherwise, the return value is NULL.

See Also

EnumProps, GlobalAddAtom, RemoveProp, SetProp


getprotobyname
getprotobynam  QuickInfoe

The Windows Sockets getprotobyname function gets protocol information corresponding to a protocol name.

struct protoent FAR * PASCAL FAR getprotobyname(

const char FAR * name
);
Parameters

name

A pointer to a protocol name.

Return Value

If the function succeeds, getprotobyname returns a pointer to the protoent structure described previously.

If the function fails, it returns a NULL pointer. To get extended error information, call WSAGetLastError.

Error Codes

WSANOTINITIALISED	A successful WSAStartup must occur before using this function.
WSAENETDOWN	The Windows Sockets implementation has detected that the network subsystem has failed.
WSANO_RECOVERY	Nonrecoverable errors: FORMERR, REFUSED, NOTIMP.
WSANO_DATA	Valid name, no data record of requested type.
WSAEINPROGRESS	A blocking Windows Sockets operation is in progress.
WSAEINTR	The (blocking) call was canceled using WSACancelBlockingCall.
Remarks

The getprotobyname function returns a pointer to the following structure, which contains the name(s) and protocol number that correspond to the given protocol name.

struct protoent {

    char FAR *        p_name;

    char FAR * FAR *  p_aliases;

    short             p_proto;

};

The members of this structure are:

Member	Usage
p_name	Official name of the protocol.
p_aliases	A NULL-terminated array of alternate names.
p_proto	The protocol number, in host byte order.
The pointer that is returned points to a structure allocated by the Windows Sockets library. The application must never attempt to modify this structure or to free any of its components. Furthermore, only one copy of this structure is allocated per thread, and so the application should copy any information it needs before issuing any other Windows Sockets function calls.

See Also

getprotobynumber, WSAAsyncGetProtoByName, WSACancelBlockingCall, WSAStartup


getprotobynumber
getprotobynumber  QuickInfo

The getprotobynumber function gets protocol information corresponding to a protocol number.

struct protoent FAR * PASCAL FAR getprotobynumber(

int proto
);
Parameters

proto

A protocol number, in host byte order.

Return Value

If the function succeeds, getprotobynumber returns a pointer to the protoent structure described previously.

If the function fails, it returns NULL. To get extended error information, call WSAGetLastError.

Error Codes

WSANOTINITIALISED	A successful WSAStartup must occur before using this function.
WSAENETDOWN	The Windows Sockets implementation has detected that the network subsystem has failed.
WSANO_RECOVERY	Nonrecoverable errors: FORMERR, REFUSED, NOTIMP.
WSANO_DATA	Valid name, no data record of requested type.
WSAEINPROGRESS	A blocking Windows Sockets operation is in progress.
WSAEINTR	The (blocking) call was canceled using WSACancelBlockingCall.
Remarks

This function returns a pointer to a protoent structure as described in getprotobyname. The contents of the structure correspond to the given protocol number.

The pointer that is returned points to a structure allocated by the Windows Sockets implementation. The application must never attempt to modify this structure or to free any of its components. Furthermore, only one copy of this structure is allocated per thread, and so the application should copy any information it needs before issuing any other Windows Sockets function calls.

See Also

getprotobyname, WSAAsyncGetProtoByNumber, WSACancelBlockingCall, WSAStartup,


GetQueuedCompletionStatus
GetQueuedCompletionStatus  QuickInfo  Overview  Group

The GetQueuedCompletionStatus function attempts to dequeue an I/O completion packet from a specified input/output completion port. If there is no completion packet queued, the function waits for a pending input/output operation associated with the completion port to complete. The function returns when it can dequeue a completion packet, or optionally when the function times out. If the function returns because of an I/O operation completion, it sets several variables that provide information about the operation.

BOOL GetQueuedCompletionStatus(

HANDLE CompletionPort,	// the I/O completion port of interest
LPDWORD lpNumberOfBytesTransferred,	// to receive number of bytes transferred during I/O
LPDWORD lpCompletionKey,	// to receive file's completion key
LPOVERLAPPED * lpOverlapped,	// to receive pointer to OVERLAPPED structure
DWORD dwMilliseconds	// optional timeout value
);
Parameters

CompletionPort

Handle to the input/output completion port of interest. Use the CreateIoCompletionPort function to create I/O completion ports.

lpNumberOfBytesTransferred

Points to a variable that the function sets to the number of bytes transferred during an I/O operation that has completed and is causing the function to return.

lpCompletionKey

Points to a variable that the function sets to the completion key value associated with the file handle whose I/O operation has completed and is causing the function to return. A completion key is a per-file key that is specified in a call to CreateIoCompletionPort.

lpOverlapped

Points to a variable that the function sets to the address of the OVERLAPPED structure that was specified when an input/output operation that has completed was started.

The following functions can be used to start input/output operations that complete using I/O completion ports. You must pass the function an OVERLAPPED structure and a file handle associated (by a call to CreateIoCompletionPort) with an I/O completion port to invoke the I/O completion port mechanism:

•	ConnectNamedPipe

•	DeviceIoControl

•	LockFileEx

•	ReadFile

•	TransactNamedPipe

•	WaitCommEvent

•	WriteFile

Even if both of the preceding conditions (passing the function a file handle associated with a completion port and a valid OVERLAPPED structure) are met, an application can prevent completion port notification. To do this, specify a valid event handle for the hEvent member of the OVERLAPPED structure, and set the low order bit of that event handle. A valid event handle whose low order bit is set keeps I/O completion from being queued to the completion port.

dwMilliseconds

Specifies the number of milliseconds that the caller is willing to wait for an input/output completion packet to appear at the I/O completion port. If a completion packet doesn't appear within the specified time, the function times out, returns FALSE, and sets *lpOverlapped to NULL.

Timing out is optional. If dwMilliseconds is -1, the function will never time out. If dwMilliseconds is zero and there is no I/O operation to dequeue, the function will timeout immediately.

Return Value

The GetQueuedCompletionStatus function's return value is TRUE if the function dequeues an I/O completion packet for a successful I/O operation from the completion port. The function stores valid values into the variables pointed to by lpNumberOfBytesTransferred, lpCompletionKey, and lpOverlapped.

The function's return value is FALSE, and *lpOverlapped is set to NULL, if the function does not dequeue an I/O completion packet from the completion port. The function does not store valid values into the variables pointed to by lpNumberOfBytesTransferred and lpCompletionKey. To get extended error information, call GetLastError.

The function's return value is FALSE, and *lpOverlapped is not NULL, if the function dequeues an I/O completion packet for a failed I/O operation from the completion port. The function stores valid values into the variables pointed to by lpNumberOfBytesTransferred, lpCompletionKey, and lpOverlapped. To get extended error information, call GetLastError.

Remarks

The Win32 I/O system can be instructed to send I/O completion notification packets to input/output completion ports, where they are queued up. The CreateIoCompletionPort function provides a mechanism for this.

When you perform an input/output operation with a file handle that has an associated input/output completion port, the I/O system sends a completion notification packet to the completion port when the I/O operation completes. The I/O completion port places the completion packet in a first-in-first-out queue. The GetQueuedCompletionStatus function retrieves these queued I/O completion packets.

A server application may have several threads calling GetQueuedCompletionStatus for the same completion port. As input operations complete, the operating system queues completion packets to the completion port. If threads are actively waiting in a call to this function, queued requests complete their call.

You can call the PostQueuedCompletionStatus function to post an I/O completion packet to an I/O completion port. The I/O completion packet will satisfy an outstanding call to the GetQueuedCompletionStatus function.

See Also

ConnectNamedPipe, CreateIoCompletionPort, DeviceIoControl, LockFileEx, OVERLAPPED, ReadFile, PostQueuedCompletionStatus, TransactNamedPipe, WaitCommEvent, WriteFile,


GetQueueStatus
GetQueueStatus  QuickInfo  Overview  Group

The GetQueueStatus function returns flags that indicate the type of messages found in the calling thread's message queue.

DWORD GetQueueStatus(

UINT  flags	// queue-status flags
);
Parameters

flags

Specifies queue-status flags giving the types of messages to check for. This parameter can be a combination of the following values:

Value	Meaning
QS_ALLEVENTS	An input, WM_TIMER, WM_PAINT, WM_HOTKEY, or posted message is in the queue.
QS_ALLINPUT	Any message is in the queue.
QS_HOTKEY	A WM_HOTKEY message is in the queue.
QS_INPUT	An input message is in the queue.
QS_KEY	A WM_KEYUP, WM_KEYDOWN, WM_SYSKEYUP, or WM_SYSKEYDOWN message is in the queue.
QS_MOUSE	A WM_MOUSEMOVE message or mouse-button message (WM_LBUTTONUP, WM_RBUTTONDOWN, and so on).
QS_MOUSEBUTTON	A mouse-button message (WM_LBUTTONUP, WM_RBUTTONDOWN, and so on).
QS_MOUSEMOVE	A WM_MOUSEMOVE message is in the queue.
QS_PAINT	A WM_PAINT message is in the queue.
QS_POSTMESSAGE	A posted message (other than those just listed) is in the queue.
QS_SENDMESSAGE	A message sent by another thread or application is in the queue.
QS_TIMER	A WM_TIMER message is in the queue.
Return Value

The high-order word of the return value indicates the types of messages currently in the queue. The low-order word indicates the types of messages that have been added to the queue and that are still in the queue since the last call to the GetQueueStatus, GetMessage, or PeekMessage function.

Remarks

The presence of a QS_ flag in the return value does not guarantee that a subsequent call to the PeekMessage or GetMessage function will return a message. GetMessage and PeekMessage perform some internal filtering that may cause the message to be processed internally. For this reason, the return value from GetQueueStatus should be considered only a hint as to whether GetMessage or PeekMessage should be called.

See Also

GetInputState, GetMessage, PeekMessage


GetRasterizerCaps
GetRasterizerCaps  QuickInfo  Overview  Group

The GetRasterizerCaps function returns flags indicating whether TrueType fonts are installed in the system.

BOOL GetRasterizerCaps(

LPRASTERIZER_STATUS  lprs,	// address of rasterizer information structure
UINT  cb	// number of bytes in structure
);
Parameters

lprs

Points to a RASTERIZER_STATUS structure to receive information about the rasterizer.

cb

Specifies the number of bytes to be copied into the structure pointed to by the lprs parameter.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The GetRasterizerCaps function enables applications and printer drivers to determine whether TrueType fonts are installed.

If the TT_AVAILABLE flag is set in the wFlags member of the RASTERIZER_STATUS structure, at least one TrueType font is installed. If the TT_ENABLED flag is set, TrueType is enabled for the system.

The actual number of bytes copied is either the member specified in the cb parameter or the length of the RASTERIZER_STATUS structure, whichever is less.

See Also

GetOutlineTextMetrics, RASTERIZER_STATUS


GetRegionData
GetRegionData  QuickInfo  Overview  Group

The GetRegionData function fills the specified buffer with data describing a region. This data includes the dimensions of the rectangles that make up the region.

DWORD GetRegionData(

HRGN  hRgn,	// handle of region
DWORD  dwCount,	// size of buffer containing region data
LPRGNDATA  lpRgnData	// address of buffer containing region data
);
Parameters

hRgn

Identifies the region.

dwCount

Specifies the size, in bytes, of the lpRgnData buffer.

lpRgnData

Points to a RGNDATA structure that receives the information. If this parameter is NULL, the return value contains the number of bytes needed for the region data.

Return Value

If the function succeeds and dwCount specifies an adequate number of bytes, the return value is 1. If dwCount is too small or lpRgnData is NULL, the return value is the required number of bytes.

If the function fails, the return value is zero.

Remarks

The GetRegionData function is used in conjunction with the ExtCreateRegion function.

See Also

ExtCreateRegion, RGNDATA


GetRgnBox
GetRgnBox  QuickInfo  Overview  Group

The GetRgnBox function retrieves the bounding rectangle of the specified region.

int GetRgnBox(

HRGN  hrgn,	// handle of a region
LPRECT  lprc	// address of structure that receives bounding rect.
);
Parameters

hrgn

Identifies the region.

lprc

Points to a RECT structure that receives the bounding rectangle.

Return Value

The return value specifies the region's complexity. It can be one of the following values:

Value	Meaning
NULLREGION	Region is empty.
SIMPLEREGION	Region is a single rectangle.
COMPLEXREGION	Region is more than a single rectangle.
If the hrgn parameter does not identify a valid region, the return value is zero.

See Also

RECT


GetROP2
GetROP2  QuickInfo  Overview  Group

The GetROP2 function retrieves the foreground mix mode of the specified device context. The mix mode specifies how the pen or interior color and the color already on the screen are combined to yield a new color.

int GetROP2(

HDC  hdc	// handle of device context
);
Parameters

hdc

Identifies the device context.

Return Value

If the function succeeds, the return value specifies the foreground mix mode.

If the function fails, the return value is zero.

Remarks

Following are the foreground mix modes:

Mix mode	Description
R2_BLACK	Pixel is always 0.
R2_COPYPEN	Pixel is the pen color.
R2_MASKNOTPEN	Pixel is a combination of the colors common to both the screen and the inverse of the pen.
R2_MASKPEN	Pixel is a combination of the colors common to both the pen and the screen.
R2_MASKPENNOT	Pixel is a combination of the colors common to both the pen and the inverse of the screen.
R2_MERGENOTPEN	Pixel is a combination of the screen color and the inverse of the pen color.
R2_MERGEPEN	Pixel is a combination of the pen color and the screen color.
R2_MERGEPENNOT	Pixel is a combination of the pen color and the inverse of the screen color.
R2_NOP	Pixel remains unchanged.
R2_NOT	Pixel is the inverse of the screen color.
R2_NOTCOPYPEN	Pixel is the inverse of the pen color.
R2_NOTMASKPEN	Pixel is the inverse of the R2_MASKPEN color.
R2_NOTMERGEPEN	Pixel is the inverse of the R2_MERGEPEN color.
R2_NOTXORPEN	Pixel is the inverse of the R2_XORPEN color.
R2_WHITE	Pixel is always 1.
R2_XORPEN	Pixel is a combination of the colors in the pen and in the screen, but not in both.
See Also

SetROP2


GetSaveFileName
GetSaveFileName  QuickInfo  Overview  Group

The GetSaveFileName function creates a system-defined dialog box that enables the user to select a file to save.

BOOL GetSaveFileName(

LPOPENFILENAME  lpofn	// address of structure with initialization data
);
Parameters

lpofn

Points to an OPENFILENAME structure that contains information used to initialize the dialog box. When GetSaveFileName returns, this structure contains information about the user's file selection.

Return Value

If the user selects a file to save, the return value is TRUE.

The return value is FALSE if an error occurs, the user clicks the Cancel button, the user chooses the Close command on the System menu to close the dialog box, or the buffer identified by the lpstrFile member of the OPENFILENAME structure is too small to contain the string that specifies the selected file.

To get extended error information, call CommDlgExtendedError. CommDlgExtendedError may return one of the following error codes:

CDERR_FINDRESFAILURE	CDERR_NOHINSTANCE
CDERR_INITIALIZATION	CDERR_NOHOOK
CDERR_LOCKRESFAILURE	CDERR_NOTEMPLATE
CDERR_LOADRESFAILURE	CDERR_STRUCTSIZE
CDERR_LOADSTRFAILURE	FNERR_BUFFERTOOSMALL
CDERR_MEMALLOCFAILURE	FNERR_INVALIDFILENAME
CDERR_MEMLOCKFAILURE	FNERR_SUBCLASSFAILURE
Remarks

If the hook function (pointed to by the lpfnHook member of the OPENFILENAME structure) processes the WM_CTLCOLORDLG message, GetSaveFileName must return a handle for the brush that should be used to paint the control background.

Ending the dialog box from within the hook function by calling the EndDialog function prevents the COMDLG32.DLL dynamic-link library (DLL) from properly exiting its worker thread. For applications that dynamically load or unload COMDLG32.DLL, this type of exiting may result in an access violation during unloading as the worker thread's address space is invalidated.

See Also

CommDlgExtendedError, GetOpenFilename, OPENFILENAME, WM_CTLCOLORDLG


GetScrollInfo [New - Windows NT]
GetScrollInfo  QuickInfo

[New - Windows NT]

The GetScrollInfo function retrieves the parameters of a scroll bar, including the minimum and maximum scrolling positions, the page size, and the position of the scroll box (thumb).

BOOL GetScrollInfo(

HWND  hwnd,	// handle of window with scroll bar
int  fnBar,	// scroll bar flag
LPSCROLLINFO  lpsi	// pointer to structure for scroll parameters
);
Parameters

hwnd

Identifies a scroll bar control or a window with a standard scroll bar, depending on the value of the fnBar parameter.

fnBar

Specifies the type of scroll bar for which to retrieve parameters. This parameter can be one of the following values:

Value	Meaning
SB_CTL	Retrieves the parameters for a scroll bar control. The hwnd parameter must be the handle of the scroll bar control.
SB_HORZ	Retrieves the parameters for the given window's standard horizontal scroll bar.
SB_VERT	Retrieves the parameters for the given window's standard vertical scroll bar.
lpsi

Points to a SCROLLINFO structure whose fMask member, upon entry to the function, specifies the scroll bar parameters to retrieve. Before returning, the function copies the specified parameters to the appropriate members of the structure.

The fMask member can be a combination of the following values:

Value	Meaning
SIF_PAGE	Copies the scroll page to the nPage member of the SCROLLINFO structure pointed to by lpsi.
SIF_POS	Copies the scroll position to the nPos member of the SCROLLINFO structure pointed to by lpsi.
SIF_RANGE	Copies the scroll range to the nMin and nMax members of the SCROLLINFO structure pointed to by lpsi.
Return Value

If the function retrieved any values, the return value is TRUE.

If the function does not retrieve any values, the return value is FALSE.

Remarks

The GetScrollInfo function enables applications to use 32-bit scroll positions. Although the messages that indicate scroll-bar position, WM_HSCROLL and WM_VSCROLL, provide only 16 bits of position data, the functions SetScrollInfo and GetScrollInfo provide 32 bits of scroll-bar position data. Thus, an application can call GetScrollInfo while processing either the WM_HSCROLL or WM_VSCROLL messages to obtain 32-bit scroll-bar position data.

The limitation on this technique applies to real-time scrolling of a window's contents. An application implements real-time scrolling by processing the WM_HSCROLL or WM_VSCROLL messages that carry the SB_THUMBTRACK notification value, thereby tracking the position of the scroll box (thumb) as the user moves it. Unfortunately, there is no function to retrieve the 32-bit position scroll-box position as the user moves the scroll box. Because GetScrollInfo provides only the static position, an application can obtain only 32-bit position data before or after a scroll operation.

See Also

SCROLLINFO, SetScrollInfo, WM_HSCROLL, WM_VSCROLL


GetScrollPos
GetScrollPos  QuickInfo  Overview  Group

The GetScrollPos function retrieves the current position of the scroll box (thumb) in the specified scroll bar. The current position is a relative value that depends on the current scrolling range. For example, if the scrolling range is 0 through 100 and the scroll box is in the middle of the bar, the current position is 50.

int GetScrollPos(

HWND  hWnd,	// handle of window with scroll bar
int  nBar	// scroll bar flags
);
Parameters

hWnd

Identifies a scroll bar control or a window with a standard scroll bar, depending on the value of the nBar parameter.

nBar

Specifies the scroll bar to be examined. This parameter can be one of the following values:

Value	Meaning
SB_CTL	Retrieves the position of the scroll box in a scroll bar control. The hWnd parameter must be the handle of the scroll bar control.
SB_HORZ	Retrieves the position of the scroll box in a window's standard horizontal scroll bar.
SB_VERT	Retrieves the position of the scroll box in a window's standard vertical scroll bar.
Return Value

If the function succeeds, the return value is the current position of the scroll box/

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

The GetScrollPos function enables applications to use 32-bit scroll positions. Although the messages that indicate scroll bar position, WM_HSCROLL and WM_VSCROLL, are limited to 16 bits of position data, the functions SetScrollPos, SetScrollRange, GetScrollPos, and GetScrollRange support 32-bit scroll bar position data. Thus, an application can call GetScrollPos while processing either the WM_HSCROLL or WM_VSCROLL messages to obtain 32-bit scroll bar position data.

The limitation on this technique applies to real-time scrolling of a window's content. An application implements such scrolling by processing the WM_HSCROLL or WM_VSCROLL messages that carry the SB_THUMBTRACK notification message, thereby tracking the position of the scroll box, also known as the thumb, while the user moves it. Unfortunately, there is no function to retrieve the thumb's 32-bit position while the user moves it. GetScrollPos provides static position data only; an application can therefore only obtain 32-bit position data before or after a scroll has taken place.

See Also

GetScrollRange, ScrollDC, ScrollWindow, SetScrollPos, SetScrollRange, WM_HSCROLL, WM_VSCROLL


GetScrollRange
GetScrollRange  QuickInfo  Overview  Group

The GetScrollRange function retrieves the current minimum and maximum scroll box (thumb) positions for the specified scroll bar.

For Windows 95, the GetScrollRange function exists for compatibility with operating system versions earlier than 4.0. With version 4.0 or later, use the GetScrollInfo function.

BOOL GetScrollRange(

HWND  hWnd,	// handle of window with scroll bar
int  nBar,	// scroll bar flags
LPINT  lpMinPos,	// address of variable that receives minimum position
LPINT  lpMaxPos	// address of variable that receives maximum position
);
Parameters

hWnd

Identifies a scroll bar control or a window with a standard scroll bar, depending on the value of the nBar parameter.

nBar

Specifies the scroll bar from which the positions are retrieved. This parameter can be one of the following values:

Value	Meaning
SB_CTL	Retrieves the positions of a scroll bar control. The hWnd parameter must be the handle of the scroll bar control.
SB_HORZ	Retrieves the positions of the window's standard horizontal scroll bar.
SB_VERT	Retrieves the positions of the window's standard vertical scroll bar.
lpMinPos

Points to the integer variable that receives the minimum position.

lpMaxPos

Points to the integer variable that receives the maximum position.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

If the specified window does not have standard scroll bars or is not a scroll bar control, the GetScrollRange function copies zero to the lpMinPos and lpMaxPos parameters.

The default range for a standard scroll bar is 0 through 100. The default range for a scroll bar control is empty (both values are zero).

The messages that indicate scroll bar position, WM_HSCROLL and WM_VSCROLL, are limited to 16 bits of position data. However, because SetScrollPos, SetScrollRange, GetScrollPos, and GetScrollRange support 32-bit scroll bar position data, there is a way to circumvent the 16-bit barrier for the WM_HSCROLL and WM_VSCROLL messages. See the GetScrollPos function for a description of the technique and its limits.

See Also

GetScrollPos, SetScrollPos, SetScrollRange, WM_HSCROLL, WM_VSCROLL


GetSecurityDescriptorControl
GetSecurityDescriptorControl  QuickInfo  Overview  Group

The GetSecurityDescriptorControl function retrieves a security descriptor's control and revision information.

BOOL GetSecurityDescriptorControl(

PSECURITY_DESCRIPTOR  pSecurityDescriptor,	// address of security descriptor
PSECURITY_DESCRIPTOR_CONTROL  pControl,	// address of  control structure
LPDWORD  lpdwRevision	// address of revision value
);
Parameters

pSecurityDescriptor

Points to a SECURITY_DESCRIPTOR structure whose control and revision information the function retrieves.

pControl

Points to a SECURITY_DESCRIPTOR_CONTROL structure receiving the security descriptor's control information.

lpdwRevision

Points to a variable receiving the security descriptor's revision value. This value is always set, even when GetSecurityDescriptorControl returns an error.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

GetSecurityDescriptorDacl, GetSecurityDescriptorGroup, GetSecurityDescriptorLength, GetSecurityDescriptorOwner, GetSecurityDescriptorSacl, IsValidSecurityDescriptor, SECURITY_DESCRIPTOR, SECURITY_DESCRIPTOR_CONTROL


GetSecurityDescriptorDacl
GetSecurityDescriptorDacl  QuickInfo  Overview  Group

The GetSecurityDescriptorDacl function retrieves a pointer to the discretionary access-control list (ACL) in a specified security descriptor.

BOOL GetSecurityDescriptorDacl(

PSECURITY_DESCRIPTOR  pSecurityDescriptor,	// address of security descriptor
LPBOOL  lpbDaclPresent,	// address of flag for presence of disc. ACL
PACL  *pDacl,	// address of pointer to ACL
LPBOOL  lpbDaclDefaulted	// address of flag for default disc. ACL
);
Parameters

pSecurityDescriptor

Points to the SECURITY_DESCRIPTOR structure containing the discretionary ACL. The function retrieves a pointer to it.

lpbDaclPresent

Points to a flag the function sets to indicate the presence of a discretionary ACL in the specified security descriptor. If this parameter is TRUE, the security descriptor contains a discretionary ACL, and the remaining output parameters in this function receive valid values. If this parameter is FALSE, the security descriptor does not contain a discretionary ACL, and the remaining output parameters do not receive valid values.

pDacl

Points to a pointer to an ACL structure. If a discretionary ACL exists, the function sets the pointer pointed to by pDacl to the address of the security descriptor's discretionary ACL. If a discretionary ACL does not exist, no value is stored.

If the function stores a NULL value in the pointer pointed to by pDacl, the security descriptor has a NULL discretionary ACL. A NULL discretionary ACL implicitly allows all access to an object.

lpbDaclDefaulted

Points to a flag set to the value of the SE_DACL_DEFAULTED flag in the SECURITY_DESCRIPTOR_CONTROL structure if a discretionary ACL exists for the security descriptor. If this flag is TRUE, the discretionary ACL was retrieved by a default mechanism; if FALSE, the discretionary ACL was explicitly specified by a user.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

ACL, GetSecurityDescriptorControl, GetSecurityDescriptorGroup, GetSecurityDescriptorLength, GetSecurityDescriptorOwner, GetSecurityDescriptorSacl, InitializeSecurityDescriptor, IsValidSecurityDescriptor, SECURITY_DESCRIPTOR, SECURITY_DESCRIPTOR_CONTROL, SetSecurityDescriptorDacl


GetSecurityDescriptorGroup
GetSecurityDescriptorGroup  QuickInfo  Overview  Group

The GetSecurityDescriptorGroup function retrieves the primary group information from a security descriptor.

BOOL GetSecurityDescriptorGroup(

PSECURITY_DESCRIPTOR  pSecurityDescriptor,	// address of security descriptor
PSID *  pGroup,	// address of pointer to group security identifier (SID)
LPBOOL  lpbGroupDefaulted	// address of flag for default
);
Parameters

pSecurityDescriptor

Points to a SECURITY_DESCRIPTOR structure whose primary group information the function retrieves.

pGroup

Points to a pointer to a SID structure identifying the primary group when the function returns. (A SID is a security identifier.) If the security descriptor does not contain a primary group, the function sets the pointer pointed to by pGroup to NULL and ignores the remaining output parameter, lpbGroupDefaulted. If the security descriptor contains a primary group, the function sets the pointer pointed to by pGroup to the address of the security descriptor's group SID structure and provides a valid value for the variable pointed to by lpbGroupDefaulted.

lpbGroupDefaulted

Points to a flag set to the value of the SE_GROUP_DEFAULTED flag in the SECURITY_DESCRIPTOR_CONTROL structure when the function returns. If the value stored in the variable pointed to by the pGroup parameter is NULL, no value is set.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

GetSecurityDescriptorControl, GetSecurityDescriptorDacl, GetSecurityDescriptorLength, GetSecurityDescriptorOwner, GetSecurityDescriptorSacl, IsValidSecurityDescriptor, SECURITY_DESCRIPTOR, SECURITY_DESCRIPTOR_CONTROL, SetSecurityDescriptorGroup, SID


GetSecurityDescriptorLength
GetSecurityDescriptorLength  QuickInfo  Overview  Group

The GetSecurityDescriptorLength function returns the length, in bytes, of a structurally valid SECURITY_DESCRIPTOR structure. The length includes the length of all associated structures, such as SID and ACL structures.

DWORD GetSecurityDescriptorLength(

PSECURITY_DESCRIPTOR  pSecurityDescriptor	// address of security descriptor
);
Parameters

pSecurityDescriptor

Points to the SECURITY_DESCRIPTOR structure whose length the function returns. The SECURITY_DESCRIPTOR structure is assumed to be valid.

Return Value

If the function succeeds, the return value is the length, in bytes, of the SECURITY_DESCRIPTOR structure. If the SECURITY_DESCRIPTOR structure is invalid, the return value is undefined.

Remarks

The minimum length of a security descriptor is SECURITY_DESCRIPTOR_MIN_LENGTH. A security descriptor of this length has no associated SID or ACL structures.

See Also

GetSecurityDescriptorControl, GetSecurityDescriptorDacl, GetSecurityDescriptorGroup, GetSecurityDescriptorOwner, GetSecurityDescriptorSacl, IsValidSecurityDescriptor, SECURITY_DESCRIPTOR


GetSecurityDescriptorOwner
GetSecurityDescriptorOwner  QuickInfo  Overview  Group

The GetSecurityDescriptorOwner function retrieves the owner information from a security descriptor.

BOOL GetSecurityDescriptorOwner(

PSECURITY_DESCRIPTOR  pSecurityDescriptor,	// address of security descriptor
PSID  * pOwner,	// address of pointer to owner security identifier (SID)
LPBOOL  lpbOwnerDefaulted	// address of flag for default
);
Parameters

pSecurityDescriptor

Points to a SECURITY_DESCRIPTOR structure whose owner information the function retrieves.

pOwner

Points to a pointer to a SID structure identifying the owner when the function returns. (A SID is a security identifier.) If the security descriptor does not contain an owner, the function sets the pointer pointed to by pOwner to NULL and ignores the remaining output parameter, lpbOwnerDefaulted. If the security descriptor contains an owner, the function sets the pointer pointed to by pOwner to the address of the security descriptor's owner SID structure and provides a valid value for the variable pointed to by lpbOwnerDefaulted.

lpbOwnerDefaulted

Points to a flag set to the value of the SE_OWNER_DEFAULTED flag in the SECURITY_DESCRIPTOR_CONTROL structure when the function returns. If the value stored in the variable pointed to by the pOwner parameter is NULL, no value is set.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

GetSecurityDescriptorControl, GetSecurityDescriptorDacl, GetSecurityDescriptorGroup, GetSecurityDescriptorLength, GetSecurityDescriptorSacl, IsValidSecurityDescriptor, SECURITY_DESCRIPTOR, SECURITY_DESCRIPTOR_CONTROL, SetSecurityDescriptorOwner, SID


GetSecurityDescriptorSacl
GetSecurityDescriptorSacl  QuickInfo  Overview  Group

The GetSecurityDescriptorSacl function retrieves a pointer to the system access-control list (ACL) in a specified security descriptor.

BOOL GetSecurityDescriptorSacl(

PSECURITY_DESCRIPTOR  pSecurityDescriptor,	// address of security descriptor
LPBOOL  lpbSaclPresent,	// address of flag for presence of system ACL
PACL  *pSacl,	// address of pointer to ACL
LPBOOL  lpbSaclDefaulted	// address of flag for default system ACL
);
Parameters

pSecurityDescriptor

Points to the SECURITY_DESCRIPTOR structure containing the system ACL to which the function retrieves a pointer to.

lpbSaclPresent

Points to a flag the function sets to indicate the presence of a system ACL in the specified security descriptor. If this parameter is TRUE, the security descriptor contains a system ACL, and the remaining output parameters in this function receive valid values. If this parameter is FALSE, the security descriptor does not contain a system ACL, and the remaining output parameters do not receive valid values.

pSacl

Points to a pointer to an ACL structure. If a system ACL exists, the function sets the pointer pointed to by pSacl to the address of the security descriptor's system ACL. If a system ACL does not exist, no value is stored.

If the function stores a NULL value in the pointer pointed to by pSacl, the security descriptor has a NULL system ACL.

lpbSaclDefaulted

Points to a flag set to the value of the SE_SACL_DEFAULTED flag in the SECURITY_DESCRIPTOR_CONTROL structure if a system ACL exists for the security descriptor.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

ACL, GetSecurityDescriptorControl, GetSecurityDescriptorDacl, GetSecurityDescriptorGroup, GetSecurityDescriptorLength, GetSecurityDescriptorOwner, InitializeSecurityDescriptor, IsValidSecurityDescriptor, SECURITY_DESCRIPTOR, SECURITY_DESCRIPTOR_CONTROL, SetSecurityDescriptorSacl


getservbyname
getservbynam  QuickInfoe

The Windows Sockets getservbyname function gets service information corresponding to a service name and protocol.

struct servent FAR * getservbyname (

const char FAR * name,
const char FAR * proto
);
Parameters

name

A pointer to a service name.

proto

An optional pointer to a protocol name. If this is NULL, getservbyname returns the first service entry for which the name matches the s_name or one of the s_aliases. Otherwise getservbyname matches both the name and the proto.

Return Value

If the function succeeds, getservbyname returns a pointer to the servent structure described in getservbyname.

If the function fails, it returns NULL. To get extended error information, call WSAGetLastError.

Error Codes

WSANOTINITIALISED	A successful WSAStartup must occur before using this function.
WSAENETDOWN	The Windows Sockets implementation has detected that the network subsystem has failed.
WSANO_RECOVERY	Nonrecoverable errors: FORMERR, REFUSED, NOTIMP.
WSANO_DATA	Valid name, no data record of requested type.
WSAEINPROGRESS	A blocking Windows Sockets operation is in progress.
WSAEINTR	The (blocking) call was canceled using WSACancelBlockingCall.
Remarks

The getservbyname function returns a pointer to the following structure, which contains the name(s) and service number that correspond to the given service name.

struct servent {

    char FAR *        s_name;

    char FAR * FAR *  s_aliases;

    short             s_port;

    char FAR *        s_proto;

};

The members of this structure are:

Members	Usage
s_name	Official name of the service.
s_aliases	A NULL-terminated array of alternate names.
s_port	The port number at which the service may be contacted. Port numbers are returned in network byte order.
s_proto	The name of the protocol to use when contacting the service.
The pointer that is returned points to a structure allocated by the Windows Sockets library. The application must never attempt to modify this structure or to free any of its components. Furthermore, only one copy of this structure is allocated per thread, and so the application should copy any information it needs before issuing any other Windows Sockets function calls.

See Also

getservbyport, WSAAsyncGetServByName, WSACancelBlockingCall, WSAStartup


getservbyport
getservbyport  QuickInfo

The Windows Sockets getservbyport function gets service information corresponding to a port and protocol.

struct servent FAR * getservbyport (

int port,
const char FAR * proto
);
Parameters

port

The port for a service, in network byte order.

proto

An optional pointer to a protocol name. If this is NULL, getservbyport returns the first service entry that matches the specified port. Otherwise, getservbyport matches both the port and the proto.

Return Value

If the function succeeds, getservbyport returns a pointer to the servent structure described previously.

If the function fails, it returns a NULL pointer. To get extended error information, call WSAGetLastError.

Error Codes

WSANOTINITIALISED	A successful WSAStartup must occur before using this function.
WSAENETDOWN	The Windows Sockets implementation has detected that the network subsystem has failed.
WSANO_RECOVERY	Nonrecoverable errors: FORMERR, REFUSED, NOTIMP.
WSANO_DATA	Valid name, no data record of requested type.
WSAEINPROGRESS	A blocking Windows Sockets operation is in progress.
WSAEINTR	The (blocking) call was canceled using WSACancelBlockingCall.
Remarks

The getservbyport function returns a pointer to a servent structure as described for getservbyname.

The pointer that is returned points to a structure allocated by the Windows Sockets implementation. The application must never attempt to modify this structure or to free any of its components. Furthermore, only one copy of this structure is allocated per thread, and so the application should copy any information it needs before issuing any other Windows Sockets function calls.

See Also

getservbyname, WSAAsyncGetServByPort, WSACancelBlockingCall, WSAStartup


GetService
GetService  QuickInfo  Overview  Group

The GetService function obtains information about a network service in the context of a set of default name spaces or a specified name space. The network service is specified by its type and name. The information about the service is obtained as a set of NS_SERVICE_INFO data structures.

INT GetService(

DWORD  dwNameSpace,	// specifies name space or spaces to search
PGUID  lpGuid,	// points to GUID service type
LPTSTR  lpServiceName,	// points to service name
DWORD  dwProperties,	// specifies service information to be obtained
LPVOID  lpBuffer,	// points to buffer to receive service information
LPDWORD  lpdwBufferSize,	// points to size of buffer, size of service information
LPSERVICE_ASYNC_INFO  lpServiceAsyncInfo	// reserved for future use, must be NULL
);
Parameters

dwNameSpace

Specifies the name space, or a set of default name spaces, that the operating system will query for information about the specified network service.

Use one of the following constants to specify a name space:

Value	Name Space
NS_DEFAULT	A set of default name spaces. The operating system will query each name space within this set. The set of default name spaces typically includes all the name spaces installed on the system. System administrators, however, can exclude particular name spaces from the set. NS_DEFAULT is the value that most applications should use for dwNameSpace.
NS_DNS	The Domain Name System used in the Internet for host name resolution.
NS_NETBT	The NetBIOS over TCP/IP layer. All Windows NT systems register their computer names with NetBIOS. This name space is used to resolve a computer name into an IP address using this registration. Note that NS_NETBT may access a WINS server to perform the resolution.
NS_SAP	The Netware Service Advertising Protocol. This may access the Netware bindery if appropriate. NS_SAP is a dynamic name space that allows registration of services.
NS_TCPIP_HOSTS	Looks up host names and IP addresses in the <systemroot>\system32\drivers\etc\hosts file.
NS_TCPIP_LOCAL	Local TCP/IP name resolution mechanisms, including comparisons against the local host name and looks up host names and IP addresses in cache of host to IP address mappings.
Most calls to GetService should use the special value NS_DEFAULT. This lets a client get by with no knowledge of which name spaces are available on an internetwork. The system administrator determines name space access. Name spaces can come and go without the client having to be aware of the changes.

lpGuid

Points to a globally unique identifier (GUID) that specifies the type of the network service. The header file SVCGRUID.H includes GUIDs from many well known services within the DNS and SAP name spaces.

lpServiceName

Points to a zero-terminated string that uniquely represents the service name. For example, "MY SNA SERVER".

dwProperties

A set of bit-flags that specify the service information that the function obtains. Each of these bit flag constants, other than PROP_ALL, corresponds to a particular member of the SERVICE_INFO data structure. If the flag is set, the function puts information into the corresponding member of the data structures stored in *lpBuffer. The following bit flags are defined:

Value	Name Space
PROP_COMMENT	If this flag is set, the function stores data in the lpComment member of the data structures stored in *lpBuffer.
PROP_LOCALE	If this flag is set, the function stores data in the lpLocale member of the data structures stored in *lpBuffer.
PROP_DISPLAY_HINT	If this flag is set, the function stores data in the dwDisplayHint member of the data structures stored in *lpBuffer.
PROP_VERSION	If this flag is set, the function stores data in the dwVersion member of the data structures stored in *lpBuffer.
PROP_START_TIME	If this flag is set, the function stores data in the dwTime member of the data structures stored in *lpBuffer.
PROP_MACHINE	If this flag is set, the function stores data in the lpMachineName member of the data structures stored in *lpBuffer.
PROP_ADDRESSES	If this flag is set, the function stores data in the lpServiceAddress member of the data structures stored in *lpBuffer.
PROP_SD	If this flag is set, the function stores data in the ServiceSpecificInfo member of the data structures stored in *lpBuffer.
PROP_ALL	If this flag is set, the function stores data in all of the members of the data structures stored in *lpBuffer.
lpBuffer

Points to a buffer to receive an array of NS_SERVICE_INFO structures and associated service information. Each NS_SERVICE_INFO structure contains service information in the context of a particular name space. Note that if dwNameSpace is NS_DEFAULT, the function stores more than one structure into the buffer; otherwise, just one structure is stored.

Each NS_SERVICE_INFO structure contains a SERVICE_INFO structure. The members of these SERVICE_INFO structures will contain valid data based on the bit-flags that are set in the dwProperties parameter. If a member's corresponding bit-flag is not set in dwProperties, the member's value is undefined.

The function stores the NS_SERVICE_INFO structures in a consecutive array, starting at the beginning of the buffer. The pointers in the contained SERVICE_INFO structures point to information that is stored in the buffer between the end of the NS_SERVICE_INFO structures and the end of the buffer.

lpdwBufferSize

Points to a variable that, on input, contains the size, in bytes, of the buffer pointed to by lpBuffer. On output, this variable contains the number of bytes required to store the requested information. If this output value is greater than the input value, the function has failed due to insufficient buffer size.

lpServiceAsyncInfo

This parameter is reserved for future use. It must be set to NULL.

Return Value

If the function succeeds, the return value is the number of NS_SERVICE_INFO structures stored in *lpBuffer. Zero indicates that no structures were stored.

If the function fails, the return value is SOCKET_ERROR ( - 1). To get extended error information, call GetLastError. GetLastError may return one of the following extended error values:

Value	Meaning
ERROR_INSUFFICIENT_BUFFER	The buffer pointed to by lpBuffer is too small to receive all of the requested information. Call the function with a buffer at least as large as the value returned in *lpdwBufferSize.
ERROR_SERVICE_NOT_FOUND	The specified service was not found, or the specified name space is not in use. The function return value is zero in this case.
See Also

SetService, NS_SERVICE_INFO, SERVICE_INFO


GetServiceDisplayName
GetServiceDisplayName  QuickInfo  Overview  Group

The GetServiceDisplayName function obtains the display name that is associated with a particular service name. The service name is the same as the service's registry key name.

BOOL GetServiceDisplayName(

SC_HANDLE  hSCManager,	// handle to a service control manager database
LPCTSTR  lpServiceName,	// the service name
LPTSTR  lpDisplayName,	// buffer to receive the service's display name
LPDWORD  lpcchBuffer	// size of display name buffer and display name
);
Parameters

hSCManager

Handle to a machine's service control manager database. This parameter is an RPC server handle as returned by the OpenSCManager function.

lpServiceName

Points to a null-terminated service name string. This name is the same as the service's registry key name.

lpDisplayName

Points to a buffer into which the function stores the service's display name as a null-terminated string. If the function fails, this buffer will contain an empty string.

lpcchBuffer

Points to a DWORD that contains the size, in characters, of the buffer pointed to by lpDisplayName. When the function returns, this DWORD contains the size, in characters, of the service's display name, excluding the NULL terminator.

If the buffer pointed to by lpDisplayName is too small to contain the display name, the function stores no data into it. When the function returns, the DWORD pointed to by lpcchBuffer contains the size in characters of the service's display name, excluding the NULL terminator.

Return Value

If the functions succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

There are two names for a service: the service name, which is the actual name of the service's key in the registry's Services section, and a more user-friendly display name that appears in the Services Control Panel application and is used with the NET START command. The GetServiceDisplayName and GetServiceKeyName functions let an application map one of these names to the other. An application passes a service's registry key name to GetServiceDisplayName, and obtains the service's user-friendly display name. An application passes a service's display name to GetServiceKeyName, and obtains the service's registry key name.

See Also

GetServiceKeyName, OpenSCManager


GetServiceKeyName
GetServiceKeyName  QuickInfo  Overview  Group

The GetServiceKeyName function obtains the service name that is associated with a particular service's display name. The service name is the same as the service's registry key name.

BOOL GetServiceKeyName(

SC_HANDLE  hSCManager,	// handle to a service control manager database
LPCTSTR  lpDisplayName,	// the service's display name
LPTSTR  lpServiceName,	// buffer to receive the service name
LPDWORD  lpcchBuffer	// size of service name buffer and service name
);
Parameters

hSCManager

Handle to a computer's service control manager database. This parameter is a remote procedure call (RPC) server handle as returned by OpenSCManager.

lpDisplayName

Points to a null-terminated service display name string.

lpServiceName

Points to a buffer into which the function stores the service name as a null-terminated string. If the function fails, this buffer will contain an empty string.

lpcchBuffer

Points to a DWORD that contains the size in characters of the buffer pointed to by the lpServiceName parameter. When the function returns, this DWORD contains the size, in characters, of the service name, excluding the NULL terminator.

If the buffer pointed to by lpServiceName is too small to contain the service name, the function stores no data in it. When the function returns, the DWORD pointed to by lpcchBuffer contains the size, in characters, of the service name, excluding the NULL terminator.

Return Value

If the functions succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

There are two names for a service: the service name, which is the actual name of the service's key in the registry's Services section, and a more user-friendly display name that appears in the Services Control Panel application and is used with the NET START command. The GetServiceDisplayName and GetServiceKeyName functions let an application map one of these names to the other. An application passes a service's registry key name to GetServiceDisplayName, and obtains the service's user-friendly display name. An application passes a service's display name to GetServiceKeyName, and obtains the service's registry key name.

See Also

GetServiceDisplayName, OpenSCManager


GetShortPathName
GetShortPathName  QuickInfo  Overview  Group

The GetShortPathName function obtains the short path form of a specified input path.

DWORD GetShortPathName(

LPCTSTR  lpszLongPath,	// points to a null-terminated path string
LPTSTR   lpszShortPath,	// points to a buffer to receive the null-terminated short form of the path
DWORD  cchBuffer	// specifies the size of the buffer pointed to by lpszShortPath
);
Parameters

lpszLongPath

Points to a null-terminated path string. The function obtains the short form of this path.

lpszShortPath

Points to a buffer to receive the null-terminated short form of the path specified by lpszLongPath.

cchBuffer

Specifies the size, in characters, of the buffer pointed to by lpszShortPath.

Return Value

If the function succeeds, the return value is the length, in characters, of the string stored in *lpszShortPath, not including the terminating null character.

If the function fails due to *lpszShortPath being too small to contain the short path string, the return value is the size, in characters, of the short path string. You need to call the function with a short path buffer that is at least as large as the short path string.

If the function fails for any other reason, the return value is zero. To get extended error information, call GetLastError.

Remarks

When an application calls this function and specifies a path on a volume that does not support 8.3 aliases, such as HPFS, the function fails with ERROR_INVALID_PARAMETER if the pathname is longer than 67 bytes.

The path specified by lpszLongPath does not have to be a fully qualified path or a long path. The short form may be longer than the specifed path.

If the specified path is already in its short form, there is no need for any conversion, and the function simply copies the specified path to the buffer for the short path.

You can set lpszShortPath to the same value as lpszLongPath; in other words, you can set the buffer for the short path to the address of the input path string.

See Also

GetFullPathName


GetSidIdentifierAuthority
GetSidIdentifierAuthority  QuickInfo  Overview  Group

The GetSidIdentifierAuthority function returns the address of the SID_IDENTIFIER_AUTHORITY structure in a specified security identifier (SID).

PSID_IDENTIFIER_AUTHORITY GetSidIdentifierAuthority(

PSID  pSid	// address of SID to query
);
Parameters

pSid

Points to the SID structure for which the address of the SID_IDENTIFIER_AUTHORITY structure is returned.

Return Value

If the function succeeds, the return value is the address of the SID_IDENTIFIER_AUTHORITY structure for the specified SID structure.

If the function fails, the return value is undefined. The function fails if the SID structure pointed to by the pSid parameter is invalid. To get extended error information, call GetLastError.

See Also

GetLengthSid, GetSidLengthRequired, GetSidSubAuthority, GetSidSubAuthorityCount, IsValidSid, SID, SID_IDENTIFIER_AUTHORITY


GetSidLengthRequired
GetSidLengthRequired  QuickInfo  Overview  Group

The GetSidLengthRequired function returns the length, in bytes, of the buffer required to store a SID structure with a specified number of subauthorities.

DWORD GetSidLengthRequired(

UCHAR  nSubAuthorityCount	// count of subauthorities
);
Parameters

nSubAuthorityCount

Specifies the number of subauthorities to be stored in the SID structure.

Return Value

The return value is the length, in bytes, of the buffer required to store the SID structure. This function cannot fail.

See Also

AllocateAndInitializeSid, GetLengthSid, GetSidIdentifierAuthority, GetSidSubAuthority, GetSidSubAuthorityCount, InitializeSid, IsValidSid, SID


GetSidSubAuthority
GetSidSubAuthority  QuickInfo  Overview  Group

The GetSidSubAuthority function returns the address of a specified subauthority in a SID structure. The subauthority value is a relative identifier (RID). A SID is a security identifier.

PDWORD GetSidSubAuthority(

PSID  pSid,	// address of security identifier to query
DWORD  nSubAuthority	// index of subauthority to retrieve
);
Parameters

pSid

Points to the SID structure from which the address of a subauthority is to be returned.

nSubAuthority

Specifies an index value identifying the subauthority array element whose address the function will return. The function performs no validation tests on this value. An application can call the GetSidSubAuthorityCount function to discover the range of acceptable values.

Return Value

If the function succeeds, the return value is the address of the specified SID subauthority. To get extended error information, call GetLastError.

If the function fails, the return value is undefined. The function fails if the specified SID structure is invalid or if the index value specified by the nSubAuthority parameter is out of bounds.

See Also

GetLengthSid, GetSidIdentifierAuthority, GetSidLengthRequired, GetSidSubAuthorityCount, IsValidSid, SID


GetSidSubAuthorityCount
GetSidSubAuthorityCount  QuickInfo  Overview  Group

The GetSidSubAuthorityCount function returns the address of the field in a SID structure containing the subauthority count. A SID is a security identifier.

PUCHAR GetSidSubAuthorityCount(

PSID  pSid	// address of security identifier to query
);
Parameters

pSid

Points to the SID structure from which a pointer to the subauthority count is returned.

Return Value

If the function succeeds, the return value is a pointer to the subauthority count for the specified SID structure.

If the function fails, the return value is undefined. The function fails if the specified SID structure is invalid. To get extended error information, call GetLastError.

See Also

GetLengthSid, GetSidIdentifierAuthority, GetSidLengthRequired, GetSidSubAuthority, IsValidSid, SID


getsockname
getsockname  QuickInfo

The Windows Sockets getsockname function gets the local name for a socket.

int getsockname (

SOCKET s,
struct sockaddr FAR * name,
int FAR * namelen
);
Parameters

s

A descriptor identifying a bound socket.

name

Receives the address (name) of the socket.

namelen

The size of the name buffer.

Return Value

If no error occurs, getsockname returns zero. Otherwise, a value of SOCKET_ERROR is returned, and a specific error code may be retrieved by calling WSAGetLastError.

Error Codes

WSANOTINITIALISED	A successful WSAStartup must occur before using this function.
WSAENETDOWN	The Windows Sockets implementation has detected that the network subsystem has failed.
WSAEFAULT	The namelen argument is not large enough.
WSAEINPROGRESS	A blocking Windows Sockets operation is in progress.
WSAENOTSOCK	The descriptor is not a socket.
WSAEINVAL	The socket has not been bound to an address with bind.
Remarks

The getsockname function retrieves the current name for the specified socket descriptor in name. It is used on a bound or connected socket specified by the s parameter. The local association is returned. This call is especially useful when a connect call has been made without doing a bind first; this call provides the only means by which you can determine the local association set by the system.

On return, the namelen argument contains the actual size of the name returned in bytes.

If a socket was bound to INADDR_ANY, indicating that any of the host's IP addresses should be used for the socket, getsockname will not necessarily return information about the host IP address, unless the socket has been connected with connect or accept. A Windows Sockets application must not assume that the IP address will be changed from INADDR_ANY unless the socket is connected. This is because for a multi-homed host, the IP address that will be used for the socket is unknown unless the socket is connected.

See Also

accept, bind, connect, getpeername, socket, WSAStartup


getsockopt
getsockopt  QuickInfo

The Windows Sockets getsockopt function retrieves a socket option.

int getsockopt (

SOCKET s,
int level,
int optname,
char FAR * optval,
int FAR * optlen
);
Parameters

s

A descriptor identifying a socket.

level

The level at which the option is defined; the only supported levels are SOL_SOCKET and IPPROTO_TCP.

optname

The socket option for which the value is to be retrieved.

optval

A pointer to the buffer in which the value for the requested option is to be returned.

optlen

A pointer to the size of the optval buffer.

Return Value

If no error occurs, getsockopt returns 0. Otherwise, a value of SOCKET_ERROR is returned, and a specific error code may be retrieved by calling WSAGetLastError.

Error Codes

WSANOTINITIALISED	A successful WSAStartup must occur before using this function.
WSAENETDOWN	The Windows Sockets implementation has detected that the network subsystem has failed.
WSAEFAULT	The optlen argument was invalid.
WSAEINPROGRESS	A blocking Windows Sockets operation is in progress.
WSAENOPROTOOPT	The option is unknown or unsupported. In particular, SO_BROADCAST is not supported on sockets of type SOCK_STREAM, while SO_ACCEPTCONN, SO_DONTLINGER, SO_KEEPALIVE, SO_LINGER and SO_OOBINLINE are not supported on sockets of type SOCK_DGRAM.
WSAENOTSOCK	The descriptor is not a socket.
Remarks

The getsockopt function retrieves the current value for a socket option associated with a socket of any type, in any state, and stores the result in optval. Options may exist at multiple protocol levels, but they are always present at the uppermost "socket" level. Options affect socket operations, such as whether an operation blocks or not, the routing of packets, out-of-band data transfer, and so on.

The value associated with the selected option is returned in the buffer optval. The integer pointed to by optlen should originally contain the size of this buffer; on return, it will be set to the size of the value returned. For SO_LINGER, this will be the size of a linger structure; for all other options it will be the size of an integer.

If the option was never set with setsockopt, then getsockopt returns the default value for the option.

The following options are supported for getsockopt. The "Type" heading identifies the type of data addressed by optval. The TCP_NODELAY option uses level IPPROTO_TCP; all other options use level SOL_SOCKET.

Value	Type	Meaning
SO_ACCEPTCONN	BOOL	Socket is in listen mode.
SO_BROADCAST	BOOL	Socket is configured for the transmission of broadcast messages.
SO_DEBUG	BOOL	Debugging is enabled.
SO_DONTLINGER	BOOL	If true, the SO_LINGER option is disabled.
SO_DONTROUTE	BOOL	Routing is disabled.
SO_ERROR	int	Retrieve error status and clear.
SO_KEEPALIVE	BOOL	Keepalive messages are being sent.
SO_LINGER	struct linger FAR *	Returns the current linger options.
SO_OOBINLINE	BOOL	Out-of-band data is being received in the normal data stream.
SO_RCVBUF	int	Buffer size for receive operations.
SO_REUSEADDR	BOOL	The socket may be bound to an address that is already in use.
SO_SNDBUF	int	Buffer size for send operations.
SO_TYPE	int	The type of the socket (for example, SOCK_STREAM).
TCP_NODELAY	BOOL	Disables the Nagle algorithm for send coalescing.
BSD options not supported for getsockopt are:

Value	Type	Meaning
SO_RCVLOWAT	int	Receive low-water mark.
SO_RCVTIMEO	int	Receive timeout.
SO_SNDLOWAT	int	Send low-water mark.
SO_SNDTIMEO	int	Send timeout.
IP_OPTIONS		Get options in IP header.
TCP_MAXSEG	int	Get TCP maximum segment size.
Calling getsockopt with an unsupported option will result in an error code of WSAENOPROTOOPT being returned from WSAGetLastError.

See Also

setsockopt, socket, WSAAsyncSelect, WSAStartup


GetStartupInfo
GetStartupInfo  QuickInfo  Overview  Group

The GetStartupInfo function retrieves the contents of the STARTUPINFO structure that was specified when the calling process was created.

VOID GetStartupInfo(

LPSTARTUPINFO  lpStartupInfo	// address of STARTUPINFO structure
);
Parameters

lpStartupInfo

Points to a STARTUPINFO structure that is filled in by the function.

Return Value

This function does not return a value.

Remarks

The STARTUPINFO structure was specified by the process that created the calling process. It can be used to specify properties associated with the main window of the calling process.

See Also

CreateProcess, STARTUPINFO


GetStdHandle
GetStdHandle  QuickInfo  Overview  Group

The GetStdHandle function returns a handle for the standard input, standard output, or standard error device.

HANDLE GetStdHandle(

DWORD  nStdHandle	// input, output, or error device
);
Parameters

nStdHandle

Specifies the device for which to return the handle. This parameter can have one of the following values:

Value	Meaning
STD_INPUT_HANDLE	Standard input handle
STD_OUTPUT_HANDLE	Standard output handle
STD_ERROR_HANDLE	Standard error handle
Return Value

If the function succeeds, the return value is a handle of the specified device.

If the function fails, the return value is the INVALID_HANDLE_VALUE flag. To get extended error information, call GetLastError.

Remarks

Handles returned by GetStdHandle can be used by applications that need to read from or write to the console. When a console is created, the standard input handle is a handle of the console's input buffer, and the standard output and standard error handles are handles of the console's active screen buffer. These handles can be used by the ReadFile and WriteFile functions, or by any of the console functions that access the console input buffer or a screen buffer (for example, the ReadConsoleInput, WriteConsole, or GetConsoleScreenBufferInfo functions).

All handles returned by this function have GENERIC_READ and GENERIC_WRITE access unless the SetStdHandle function has been used to set a standard handle to be some handle with a lesser access.

The standard handles of a process may be redirected by a call to SetStdHandle, in which case GetStdHandle returns the redirected handle. If the standard handles have been redirected, you can specify the CONIN$ value in a call to the CreateFile function to get a handle of a console's input buffer. Similarly, you can specify the CONOUT$ value to get a handle of a console's active screen buffer.

See Also

CreateFile, GetConsoleScreenBufferInfo, ReadConsoleInput, ReadFile, SetStdHandle, WriteConsole, WriteFile


GetStockObject
GetStockObject  QuickInfo  Overview  Group

The GetStockObject function retrieves a handle to one of the predefined stock pens, brushes, fonts, or palettes.

HGDIOBJ GetStockObject(

int  fnObject	// type of stock object
);
Parameters

fnObject

Specifies the type of stock object. This parameter can be any one of the following values:

Value	Meaning
BLACK_BRUSH	Black brush.
DKGRAY_BRUSH	Dark gray brush.
GRAY_BRUSH	Gray brush.
HOLLOW_BRUSH	Hollow brush (equivalent to NULL_BRUSH).
LTGRAY_BRUSH	Light gray brush.
NULL_BRUSH	Null brush (equivalent to HOLLOW_BRUSH).
WHITE_BRUSH	White brush.
BLACK_PEN	Black pen.
NULL_PEN	Null pen.
WHITE_PEN	White pen.
ANSI_FIXED_FONT	Windows fixed-pitch (monospace) system font.
ANSI_VAR_FONT	Windows variable-pitch (proportional space) system font.
DEVICE_DEFAULT_FONT	Windows NT only: Device-dependent font.
DEFAULT_GUI_FONT	Windows 95 only: Default font for user interface objects such as menus and dialog boxes.
OEM_FIXED_FONT	Original equipment manufacturer (OEM) dependent fixed-pitch (monospace) font.
SYSTEM_FONT	System font. By default, Windows uses the system font to draw menus, dialog box controls, and text. In Windows versions 3.0 and later, the system font is a proportionally spaced font; earlier versions of Windows used a monospace system font.
SYSTEM_FIXED_FONT	Fixed-pitch (monospace) system font used in Windows versions earlier than 3.0. This stock object is provided for compatibility with earlier versions of Windows.
DEFAULT_PALETTE	Default palette. This palette consists of the static colors in the system palette.
Return Value

If the function succeeds, the return value identifies the logical object requested.

If the function fails, the return value is NULL.

Remarks

Use the DKGRAY_BRUSH, GRAY_BRUSH, and LTGRAY_BRUSH stock objects only in windows with the CS_HREDRAW and CS_VREDRAW styles. Using a gray stock brush in any other style of window can lead to misalignment of brush patterns after a window is moved or sized. The origins of stock brushes cannot be adjusted.

The HOLLOW_BRUSH and NULL_BRUSH stock objects are equivalent.

The font used by the DEFAULT_GUI_FONT stock object could change. Use this stock object when you want to use the font that menus, dialog boxes, and other user interface objects use.

It is not necessary (but it is not harmful) to delete stock objects by calling DeleteObject.

See Also

DeleteObject, SelectObject


GetStretchBltMode
GetStretchBltMode  QuickInfo  Overview  Group

The GetStretchBltMode function retrieves the current stretching mode. The stretching mode defines how color data is added to or removed from bitmaps that are stretched or compressed when the StretchBlt function is called.

int GetStretchBltMode(

HDC  hdc	// handle of device context
);
Parameters

hdc

Identifies the device context.

Return Value

If the function succeeds, the return value is the current stretching mode.

If the function fails, the return value is zero.

See Also

SetStretchBltMode, StretchBlt


GetStringTypeA
GetStringTypeA  QuickInfo  Overview  Group

The GetStringTypeA function returns character-type information for the characters in the specified source string. For each character in the string, the function sets one or more bits in the corresponding 16-bit element of the output array. Each bit identifies a given character type, such as whether the character is a letter, a digit, or neither.

BOOL GetStringTypeA(

LCID  Locale,	// locale identifer
DWORD  dwInfoType,	// information-type options
LPCSTR  lpSrcStr,	// pointer to the source string
int  cchSrc,	// size, in bytes, of the source string
LPWORD  lpCharType	// pointer to the buffer for output
);
Parameters

Locale

Specifies the locale identifier. This value uniquely defines the ANSI code page to use to translate the string pointed to by lpSrcStr from ANSI to Unicode. The function then analyzes each Unicode character for character type information.

This parameter can be a locale identifier created by the MAKELCID macro, or one of the following predefined values:

LOCALE_SYSTEM_DEFAULT	Default system locale
LOCALE_USER_DEFAULT	Default user locale
Note that the Locale parameter does not exist in the GetStringTypeW function. Because of that parameter difference, an application cannot automatically invoke the proper A or W version of GetStringType* through the use of the #define UNICODE switch. An application can circumvent this limitation by using GetStringTypeEx, which is the recommended Win32 function.

dwInfoType

Specifies the type of character information the user wants to retrieve. The various types are divided into different levels (see the following Remarks section for a list of the information included in each type). This parameter can specify one of the following character type flags:

CT_CTYPE1	Retrieve character type information.
CT_CTYPE2	Retrieve bidirectional layout information.
CT_CTYPE3	Retrieve text processing information.
lpSrcStr

Points to the string for which character types are requested. If cchSrc is -1, the string is assumed to be null terminated. This must be an ANSI string. Note that this can be a double-byte character set (DBCS) string if the locale is appropriate for DBCS.

cchSrc

Specifies the size, in bytes, of the string pointed to by the lpSrcStr parameter. If this count includes a null terminator, the function returns character type information for the null terminator. If this value is -1, the string is assumed to be null terminated and the length is calculated automatically.

lpCharType

Points to an array of 16-bit values. The length of this array must be large enough to receive one 16-bit value for each character in the source string. When the function returns, this array contains one word corresponding to each character in the source string.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError. GetLastError may return one of the following error codes:

ERROR_INVALID_FLAGS

ERROR_INVALID_PARAMETER

Remarks

The lpSrcStr and lpCharType pointers must not be the same. If they are the same, the function fails and GetLastError returns ERROR_INVALID_PARAMETER.

The Locale parameter is only used to perform string conversion to Unicode. It has nothing to do with the CTYPEs the function returns. The CTYPEs are solely determined by Unicode code points, and do not vary on a locale basis. For example, Greek letters are C1_ALPHA for any Locale value.

The character-type bits are divided into several levels. The information for one level can be retrieved by a single call to this function. Each level is limited to 16 bits of information so that the other mapping routines, which are limited to 16 bits of representation per character, can also return character-type information.

The character types supported by this function include the following.

Ctype 1

These types support ANSI C and POSIX (LC_CTYPE) character-typing functions. A combination of these values is returned in the array pointed to by the lpCharType parameter when the dwInfoType parameter is set to CT_CTYPE1.

Name	Value	Meaning
C1_UPPER	0x0001	Uppercase
C1_LOWER	0x0002	Lowercase
C1_DIGIT	0x0004	Decimal digits
C1_SPACE	0x0008	Space characters
C1_PUNCT	0x0010	Punctuation
C1_CNTRL	0x0020	Control characters
C1_BLANK	0x0040	Blank characters
C1_XDIGIT	0x0080	Hexadecimal digits
C1_ALPHA	0x0100	Any linguistic character: alphabetic, syllabary, or ideographic
The following character types are either constant or computable from basic types and do not need to be supported by this function.

Type	Description
Alphanumeric	Alphabetic characters and digits (C1_ALPHA and C1_DIGIT)
Printable	Graphic characters and blanks (all C1_* types except C1_CNTRL)
Ctype 2

These types support proper layout of Unicode text. The direction attributes are assigned so that the bidirectional layout algorithm standardized by Unicode produces accurate results. These types are mutually exclusive. For more information about the use of these attributes, see The Unicode Standard: Worldwide Character Encoding, Volumes 1 and 2, Addison Wesley Publishing Company: 1991, 1992, ISBN 0201567881.

Name	Value	Meaning
Strong:
C2_LEFTTORIGHT	0x1	Left to right
C2_RIGHTTOLEFT	0x2	Right to left
Weak:
C2_EUROPENUMBER	0x3	European number, European digit
C2_EUROPESEPARATOR	0x4	European numeric separator
C2_EUROPETERMINATOR	0x5	European numeric terminator
C2_ARABICNUMBER	0x6	Arabic number
C2_COMMONSEPARATOR	0x7	Common numeric separator
Neutral:
C2_BLOCKSEPARATOR	0x8	Block separator
C2_SEGMENTSEPARATOR	0x9	Segment separator
C2_WHITESPACE	0xA	White space
C2_OTHERNEUTRAL	0xB	Other neutrals
Not applicable:
C2_NOTAPPLICABLE	0x0	No implicit directionality (for example, control codes)
Ctype 3

These types are intended to be placeholders for extensions to the POSIX types required for general text processing or for the standard C library functions. These types are supported in the current version of Windows NT. A combination of these values is returned when dwInfoType is set to CT_CTYPE3.

Name	Value	Meaning
C3_NONSPACING	0x1	Nonspacing mark
C3_DIACRITIC	0x2	Diacritic nonspacing mark
C3_VOWELMARK	0x4	Vowel nonspacing mark
C3_SYMBOL	0x8	Symbol
C3_KATAKANA	0x10	Katakana character
C3_HIRAGANA	0x20	Hiragana character
C3_HALFWIDTH	0x40	Half-width character
C3_FULLWIDTH	0x80	Full-width character
C3_IDEOGRAPH	0x100	Ideographic character
C3_KASHIDA	0x200	Arabic Kashida character
C3_ALPHA	0x8000	All linguistic characters (alphabetic, syllabary, and ideographic)
Not applicable:
C3_NOTAPPLICABLE	0x0	Not applicable
See Also

GetLocaleInfo, GetStringTypeEx, GetStringTypeW


GetStringTypeEx
GetStringTypeEx  QuickInfo  Overview  Group

The GetStringTypeEx function returns character-type information for the characters in the specified source string. For each character in the string, the function sets one or more bits in the corresponding 16-bit element of the output array. Each bit identifies a given character type, such as whether the character is a letter, a digit, or neither.

Unlike its close relatives GetStringTypeA and GetStringTypeW, GetStringTypeEx exhibits appropriate A or W behavior through the use of the #define UNICODE switch. It is the recommended Win32 function.

BOOL GetStringTypeEx(

LCID  Locale,	// locale identifer
DWORD  dwInfoType,	// information-type options
LPCTSTR  lpSrcStr,	// address of source string
int  cchSrc,	// size, in bytes or characters, of source string
LPWORD  lpCharType	// address of buffer for output
);
Parameters

Locale

Specifies the locale identifier. This value uniquely defines the ANSI code page to use to translate the string pointed to by lpSrcStr from ANSI to Unicode. The function then analyzes each Unicode character for character type information. Note that the W version of this function ignores this parameter.

This parameter can be a locale identifier created by the MAKELCID macro, or one of the following predefined values:

LOCALE_SYSTEM_DEFAULT	Default system locale
LOCALE_USER_DEFAULT	Default user locale
dwInfoType

Specifies the type of character information the user wants to retrieve. The various types are divided into different levels (see the following Remarks section for a list of the information included in each type). This parameter can specify one of the following character type flags:

CT_CTYPE1	Retrieve character type information.
CT_CTYPE2	Retrieve bidirectional layout information.
CT_CTYPE3	Retrieve text processing information.
lpSrcStr

Points to the string for which character types are requested. If cchSrc is -1, the string is assumed to be null terminated. This must be a Unicode string for the W version of this function, and an ANSI string for the A version. Note that for the A  version, this can be a double-byte character set (DBCS) string if the locale is appropriate for DBCS.

cchSrc

Specifies the size, in bytes (ANSI version) or characters (Unicode version), of the string pointed to by the lpSrcStr parameter. If this count includes a null terminator, the function returns character type information for the null terminator. If this value is -1, the string is assumed to be null terminated and the length is calculated automatically.

lpCharType

Points to an array of 16-bit values. The length of this array must be large enough to receive one 16-bit value for each character in the source string. When the function returns, this array contains one word corresponding to each character in the source string.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError. GetLastError may return one of the following error codes:

ERROR_INVALID_FLAGS

ERROR_INVALID_PARAMETER

Remarks

The GetStringTypeEx function exists to circumvent a limitation caused by the difference in parameters of GetStringTypeA and GetStringTypeW. That parameter difference prevents an application from automatically invoking the proper A or W version of GetStringType* through the use of the #define UNICODE switch. GetStringTypeEx, on the other hand, behaves properly as regards that switch. Thus, it is the recommended Win32 function.

The Locale parameter is only used to perform string conversion to Unicode. It has nothing to do with the CTYPEs the function returns. The CTYPEs are solely determined by Unicode code points, and do not vary on a locale basis. For example, Greek letters are C1_ALPHA for any Locale value.

The lpSrcStr and lpCharType pointers must not be the same. If they are the same, the function fails and GetLastError returns ERROR_INVALID_PARAMETER.

The character-type bits are divided into several levels. The information for one level can be retrieved by a single call to this function. Each level is limited to 16 bits of information so that the other mapping routines, which are limited to 16 bits of representation per character, can also return character-type information.

The character types supported by this function include the following.

Ctype 1

These types support ANSI C and POSIX (LC_CTYPE) character-typing functions. A combination of these values is returned in the array pointed to by the lpCharType parameter when the dwInfoType parameter is set to CT_CTYPE1.

Name	Value	Meaning
C1_UPPER	0x0001	Uppercase
C1_LOWER	0x0002	Lowercase
C1_DIGIT	0x0004	Decimal digits
C1_SPACE	0x0008	Space characters
C1_PUNCT	0x0010	Punctuation
C1_CNTRL	0x0020	Control characters
C1_BLANK	0x0040	Blank characters
C1_XDIGIT	0x0080	Hexadecimal digits
C1_ALPHA	0x0100	Any linguistic character: alphabetic, syllabary, or ideographic
The following character types are either constant or computable from basic types and do not need to be supported by this function.

Type	Description
Alphanumeric	Alphabetic characters and digits (C1_ALPHA and C1_DIGIT)
Printable	Graphic characters and blank (all C1_* types except C1_CNTRL)
Ctype 2

These types support proper layout of Unicode text. The direction attributes are assigned so that the bidirectional layout algorithm standardized by Unicode produces accurate results. These types are mutually exclusive. For more information about the use of these attributes, see The Unicode Standard: Worldwide Character Encoding, Volumes 1 and 2, Addison Wesley Publishing Company: 1991, 1992, ISBN 0201567881.

Name	Value	Meaning
Strong:
C2_LEFTTORIGHT	0x1	Left to right
C2_RIGHTTOLEFT	0x2	Right to left
Weak:
C2_EUROPENUMBER	0x3	European number, European digit
C2_EUROPESEPARATOR	0x4	European numeric separator
C2_EUROPETERMINATOR	0x5	European numeric terminator
C2_ARABICNUMBER	0x6	Arabic number
C2_COMMONSEPARATOR	0x7	Common numeric separator
Neutral:
C2_BLOCKSEPARATOR	0x8	Block separator
C2_SEGMENTSEPARATOR	0x9	Segment separator
C2_WHITESPACE	0xA	White space
C2_OTHERNEUTRAL	0xB	Other neutrals
Not applicable:
C2_NOTAPPLICABLE	0x0	No implicit directionality (for example, control codes)
Ctype 3

These types are intended to be placeholders for extensions to the POSIX types required for general text processing or for the standard C library functions. These types are supported in the current version of Windows NT. A combination of these values is returned when dwInfoType is set to CT_CTYPE3.

Name	Value	Meaning
C3_NONSPACING	0x1	Nonspacing mark
C3_DIACRITIC	0x2	Diacritic nonspacing mark
C3_VOWELMARK	0x4	Vowel nonspacing mark
C3_SYMBOL	0x8	Symbol
C3_KATAKANA	0x10	Katakana character
C3_HIRAGANA	0x20	Hiragana character
C3_HALFWIDTH	0x40	Half-width character
C3_FULLWIDTH	0x80	Full-width character
C3_IDEOGRAPH	0x100	Ideographic character
C3_KASHIDA	0x200	Arabic Kashida character
C3_ALPHA	0x8000	All linguistic characters (alphabetic, syllabary, and ideographic)
Not applicable:
C3_NOTAPPLICABLE	0x0	Not applicable
See Also

GetLocaleInfo, GetStringTypeA, GetStringTypeW


GetStringTypeW
GetStringTypeW  QuickInfo  Overview  Group

The GetStringTypeW function returns character-type information for the characters in the specified source string. For each character in the string, the function sets one or more bits in the corresponding 16-bit element of the output array. Each bit identifies a given character type, such as whether the character is a letter, a digit, or neither.

BOOL GetStringTypeW(

DWORD  dwInfoType,	// information-type options
LPCWSTR  lpSrcStr,	// address of source string
int  cchSrc,	// number of characters in string
LPWORD  lpCharType	// address of buffer for output
);
Parameters

dwInfoType

Specifies the type of character information the user wants to retrieve. The various types are divided into different levels (see the following Remarks section for a list of the information included in each type). This parameter can specify one of the following character type flags:

CT_CTYPE1	Retrieve character type information.
CT_CTYPE2	Retrieve bidirectional layout information.
CT_CTYPE3	Retrieve text processing information.
lpSrcStr

Points to the string for which character types are requested. If cchSrc is -1, the string is assumed to be null terminated. This must be a Unicode string.

cchSrc

Specifies the size, in characters, of the string pointed to by the lpSrcStr parameter. If this count includes a null terminator, the function returns character type information for the null terminator. If this value is -1, the string is assumed to be null terminated and the length is calculated automatically.

lpCharType

Points to an array of 16-bit values. The length of this array must be large enough to receive one 16-bit value for the number of characters specified in the cchSrc parameter. When the function returns, this array contains one word corresponding to each Unicode character in the source string.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError. GetLastError may return one of the following error codes:

ERROR_INVALID_FLAGS

ERROR_INVALID_PARAMETER

Remarks

Note that the GetStringTypeA function has one more parameter than the GetStringTypeW function: GetStringTypeA has a first parameter that is an LCID named Locale. This parameter does not exist in the GetStringTypeW function. Because of that parameter difference, an application cannot automatically invoke the proper A or W version of GetStringType* through the use of the #define UNICODE switch. An application can circumvent this limitation by using GetStringTypeEx; it is the recommended Win32 function.

The lpSrcStr and lpCharType pointers must not be the same. If they are the same, the function fails and GetLastError returns ERROR_INVALID_PARAMETER.

The character-type bits are divided into several levels. The information for one level can be retrieved by a single call to this function. Each level is limited to 16 bits of information so that the other mapping routines, which are limited to 16 bits of representation per character, can also return character-type information.

The character types supported by this function include the following.

Ctype 1

These types support ANSI C and POSIX (LC_CTYPE) character-typing functions. A combination of these values is returned in the array pointed to by the lpCharType parameter when the dwInfoType parameter is set to CT_CTYPE1.

Name	Value	Meaning
C1_UPPER	0x0001	Uppercase
C1_LOWER	0x0002	Lowercase
C1_DIGIT	0x0004	Decimal digits
C1_SPACE	0x0008	Space characters
C1_PUNCT	0x0010	Punctuation
C1_CNTRL	0x0020	Control characters
C1_BLANK	0x0040	Blank characters
C1_XDIGIT	0x0080	Hexadecimal digits
C1_ALPHA	0x0100	Any linguistic character: alphabetic, syllabary, or ideographic
The following character types are either constant or computable from basic types and do not need to be supported by this function.

Type	Description
Alphanumeric	Alphabetic characters and digits (C1_ALPHA and C1_DIGIT)
Printable	Graphic characters and blanks (all C1_* types except C1_CNTRL)
Ctype 2

These types support proper layout of Unicode text. The direction attributes are assigned so that the bidirectional layout algorithm standardized by Unicode produces accurate results. These types are mutually exclusive. For more information about the use of these attributes, see The Unicode Standard: Worldwide Character Encoding, Volumes 1 and 2, Addison Wesley Publishing Company: 1991, 1992, ISBN 0201567881.

Name	Value	Meaning
Strong:
C2_LEFTTORIGHT	0x1	Left to right
C2_RIGHTTOLEFT	0x2	Right to left
Weak:
C2_EUROPENUMBER	0x3	European number, European digit
C2_EUROPESEPARATOR	0x4	European numeric separator
C2_EUROPETERMINATOR	0x5	European numeric terminator
C2_ARABICNUMBER	0x6	Arabic number
C2_COMMONSEPARATOR	0x7	Common numeric separator
Neutral:
C2_BLOCKSEPARATOR	0x8	Block separator
C2_SEGMENTSEPARATOR	0x9	Segment separator
C2_WHITESPACE	0xA	White space
C2_OTHERNEUTRAL	0xB	Other neutrals
Not applicable:
C2_NOTAPPLICABLE	0x0	No implicit directionality (for example, control codes)
Ctype 3

These types are intended to be placeholders for extensions to the POSIX types required for general text processing or for the standard C library functions. These types are supported in the current version of Windows NT. A combination of these values is returned when dwInfoType is set to CT_CTYPE3.

Name	Value	Meaning
C3_NONSPACING	0x1	Nonspacing mark
C3_DIACRITIC	0x2	Diacritic nonspacing mark
C3_VOWELMARK	0x4	Vowel nonspacing mark
C3_SYMBOL	0x8	Symbol
C3_KATAKANA	0x10	Katakana character
C3_HIRAGANA	0x20	Hiragana character
C3_HALFWIDTH	0x40	Half-width character
C3_FULLWIDTH	0x80	Full-width character
C3_IDEOGRAPH	0x100	Ideographic character
C3_KASHIDA	0x200	Arabic Kashida character
C3_ALPHA	0x8000	All linguistic characters (alphabetic, syllabary, and ideographic)
Not applicable:
C3_NOTAPPLICABLE	0x0	Not applicable
See Also

GetLocaleInfo, GetStringTypeA, GetStringTypeEx


GetSubMenu
GetSubMenu  QuickInfo  Overview  Group

The GetSubMenu function retrieves the handle of the pop-up menu activated by the specified menu item.

HMENU GetSubMenu(

HMENU  hMenu,	// handle of menu
int  nPos	// menu item position
);
Parameters

hMenu

Identifies the menu.

nPos

Specifies the zero-based relative position in the given menu of an item that activates a pop-up menu.

Return Value

If the function succeeds, the return value is the handle of the pop-up menu activated by the menu item. If the menu item does not activate a pop-up menu, it is NULL.

See Also

CreatePopupMenu, GetMenu


GetSysColor
GetSysColor  QuickInfo  Overview  Group

The GetSysColor function retrieves the current color of the specified display element. Display elements are the parts of a window and the Windows display that appear on the system display screen.

DWORD GetSysColor(

int  nIndex	// display element
);
Parameters

nIndex

Specifies the display element whose color is to be retrieved. This parameter must be one of the following values:

Value	Meaning
COLOR_3DDKSHADOW	Windows 95 only: Dark shadow for three-dimensional display elements.
COLOR_3DFACE	Windows 95 only: Face color for three-dimensional display elements.
COLOR_3DHILIGHT	Windows 95 only: Highlight color for three-dimensional display elements (for edges facing the light source.)
COLOR_3DLIGHT	Windows 95 only: Light color for three-dimensional display elements (for edges facing the light source.)
COLOR_3DSHADOW	Windows 95 only: Shadow color for three-dimensional display elements (for edges facing away from the light source).
COLOR_ACTIVEBORDER	Active window border.
COLOR_ACTIVECAPTION	Active window caption.
COLOR_APPWORKSPACE	Background color of multiple document interface (MDI) applications.
COLOR_BACKGROUND	Desktop.
COLOR_BTNFACE	Windows NT only: Face shading on push buttons.
COLOR_BTNHILIGHT	Windows 95 only: Highlight color  for buttons (same as COLOR_3DHILIGHT).
COLOR_BTNSHADOW	Edge shading on push buttons.
COLOR_BTNTEXT	Text on push buttons.
COLOR_CAPTIONTEXT	Text in caption, size box, and scroll bar arrow box.
COLOR_GRAYTEXT	Grayed (disabled) text. This color is set to 0 if the current display driver does not support a solid gray color.
COLOR_HIGHLIGHT	Item(s) selected in a control.
COLOR_HIGHLIGHTTEXT	Text of item(s) selected in a control.
COLOR_INACTIVEBORDER	Inactive window border.
COLOR_INACTIVECAPTION	Inactive window caption.
COLOR_INACTIVECAPTIONTEXT	Color of text in an inactive caption.
COLOR_INFOBK	Windows 95 only: Background color for tooltip controls.
COLOR_INFOTEXT	Windows 95 only: Text color for tooltip controls.
COLOR_MENU	Menu background.
COLOR_MENUTEXT	Windows NT only: Text in menus.
COLOR_SCROLLBAR	Scroll bar gray area.
COLOR_WINDOW	Window background.
COLOR_WINDOWFRAME	Window frame.
COLOR_WINDOWTEXT	Text in windows.
Return Value

If the function succeeds, the return value is the red, green, blue (RGB) color value that specifies the color of the given element.

Remarks

System colors for monochrome displays are usually interpreted as shades of gray.

See Also

SetSysColors


GetSysColorBrush [New - Windows 95]
GetSysColorBrush  QuickInfo  Overview  Group

[New - Windows 95]

The GetSysColorBrush function retrieves a handle identifying a logical brush that corresponds to the specified color index.

HBRUSH GetSysColorBrush(

int  nIndex	// system color index
);
Parameters

nIndex

Specifies a color index. This value corresponds to the color used to paint one of the 21 window elements.

Return Value

If the function succeeds, the return value identifies a logical brush. To get extended error information, call GetLastError.

Remarks

A brush is a bitmap that Windows uses to paint the interiors of filled shapes. An application can retrieve the current system colors by calling the GetSysColor function. An application can set the current system colors by calling the SetSysColors function.

An application must not register a window class for a window using a system brush.

See Also

GetSysColor, SetSysColors


GetSysModalWindow
GetSysModalWindow  QuickInfo  Overview  Group

The GetSysModalWindow function is not implemented in the Win32 API.


GetSystemDefaultLangID
GetSystemDefaultLangID  QuickInfo  Overview  Group

The GetSystemDefaultLangID function retrieves the system default language identifier.

LANGID GetSystemDefaultLangID(VOID)

Parameters

This function has no parameters.

Return Value

If the function succeeds, the return value is the system default language identifier.

Remarks

For more information about language identifiers, see Language Identifiers and Locales.

See Also

GetUserDefaultLangID, MAKELANGID


GetSystemDefaultLCID
GetSystemDefaultLCID  QuickInfo  Overview  Group

The GetSystemDefaultLCID function retrieves the system default locale identifier.

LCID GetSystemDefaultLCID(VOID)

Parameters

This function has no parameters.

Return Value

If the function succeeds, the return value is the system default locale identifier.

Remarks

For more information about locale identifiers, see Locale Identifiers.

See Also

GetLocaleInfo, GetUserDefaultLCID, MAKELCID


GetSystemDir

The GetSystemDir function is not supported in the Win32 API. For Win32-based applications, use the GetSystemDirectory function to determine the system directory.


GetSystemDirectory
GetSystemDirectory  QuickInfo  Overview  Group

The GetSystemDirectory function retrieves the path of the Windows system directory. The system directory contains such files as Windows libraries, drivers, and font files.

UINT GetSystemDirectory(

LPTSTR  lpBuffer,	// address of buffer for system directory
UINT  uSize	// size of directory buffer
);
Parameters

lpBuffer

Points to the buffer to receive the null-terminated string containing the path. This path does not end with a backslash unless the system directory is the root directory. For example, if the system directory is named WINDOWS\SYSTEM on drive C, the path of the system directory retrieved by this function is C:\WINDOWS\SYSTEM.

uSize

Specifies the maximum size of the buffer, in characters. This value should be set to at least MAX_PATH.

Return Value

If the function succeeds, the return value is the length, in characters, of the string copied to the buffer, not including the terminating null character. If the length is greater than the size of the buffer, the return value is the size of the buffer required to hold the path.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

Applications should not create files in the system directory. If the user is running a shared version of Windows, the application does not have write access to the system directory. Applications should create files only in the directory returned by the GetWindowsDirectory function.

See Also

GetCurrentDirectory, GetWindowsDirectory, SetCurrentDirectory


GetSystemInfo
GetSystemInfo  QuickInfo  Overview  Group

The GetSystemInfo function returns information about the current system.

VOID GetSystemInfo(

LPSYSTEM_INFO  lpSystemInfo	// address of system information structure
);
Parameters

lpSystemInfo

Points to a SYSTEM_INFO structure to be filled in by this function.

Return Value

This function does not return a value.

See Also

SYSTEM_INFO


GetSystemMenu
GetSystemMenu  QuickInfo  Overview  Group

The GetSystemMenu function allows the application to access the System menu (also known as the Control menu) for copying and modifying.

HMENU GetSystemMenu(

HWND  hWnd,	// handle of window to own System menu
BOOL  bRevert	// reset flag
);
Parameters

hWnd

Identifies the window that will own a copy of the System menu.

bRevert

Specifies the action to be taken. If this parameter is FALSE, GetSystemMenu returns the handle of the copy of the System menu currently in use. The copy is initially identical to the System menu, but it can be modified.

If this parameter is TRUE, GetSystemMenu resets the System menu back to the Windows default state. The previous System menu, if any, is destroyed.

Return Value

If the bRevert parameter is FALSE, the return value is the handle of a copy of the System menu. If the bRevert parameter is TRUE, the return value is NULL.

Remarks

Any window that does not use the GetSystemMenu menu to make its own copy of the System menu receives the standard System menu.

The System menu initially contains items with various identifier values, such as SC_CLOSE, SC_MOVE, and SC_SIZE.

Menu items on the System menu send WM_SYSCOMMAND messages.

All predefined System menu items have identifier numbers greater than 0xF000. If an application adds commands to the System menu, it should use identifier numbers less than 0xF000.

Windows automatically grays items on the standard System menu, depending on the situation. The application can perform its own checking or graying by responding to the WM_INITMENU message that is sent before any menu is displayed.

See Also

GetMenu, WM_INITMENU, WM_SYSCOMMAND


GetSystemMetrics
GetSystemMetrics  QuickInfo  Overview  Group

The GetSystemMetrics function retrieves various system metrics and system configuration settings.

System metrics are the dimensions (widths and heights) of Windows display elements. All dimensions retrieved by GetSystemMetrics are in pixels.

int GetSystemMetrics(

int  nIndex	// system metric or configuration setting to retrieve
);
Parameters

nIndex

Specifies the system metric or configuration setting to retrieve. All SM_CX* values are widths. All SM_CY* values are heights. The following values are defined:

Value	Meaning
SM_ARRANGE	Windows 95 only: Flags specifying how the system arranged minimized windows. For more information about minimized windows, see the following Remarks section.
SM_CLEANBOOT	Windows 95 only: Value that specifies how the system was started: 0 Normal boot 1 Fail-safe boot 2 Fail-safe with network boot Fail-safe boot (also called SafeBoot) bypasses the user's startup files.
SM_CMETRICS	Windows 95 only: Number of system metrics and flags.
SM_CMOUSEBUTTONS	Number of buttons on mouse, or zero if no mouse is installed.
SM_CXBORDER,  SM_CYBORDER	Windows NT only: Width and height of window border.  Windows 95 only: Dimensions of a single border, in pixels.
SM_CXCURSOR,  SM_CYCURSOR	Windows NT only: Width and height of cursor. Windows 95 only: Dimensions of standard cursor bitmaps, in pixels.
SM_CXDLGFRAME, SM_CYDLGFRAME	Width and height of window frame for a window that has the WS_DLGFRAME style.  Windows 95 only: Obsolete; use SM_CX_FIXEDFRAME and SM_CYFIXEDFRAME instead.
SM_CXDOUBLECLK,  SM_CYDOUBLECLK	Windows NT only: Width and height of a rectangle around the location of a first click in a double-click sequence. The second click must occur within this rectangle for the system to consider the two clicks a double-click. Windows 95 only: Dimensions, in pixels, of the rectangle within which two successive mouse clicks must fall to generate a double-click. (The two clicks must also occur within a specified time.)
SM_CXFRAME, SM_CYFRAME	Width and height of window frame for a window that can be resized.  Windows 95 only: Obsolete; use SM_CX_FIXEDFRAME and SM_CYFIXEDFRAME instead.
SM_CXFULLSCREEN, SM_CYFULLSCREEN	Width and height of the client area for a full-screen window.
SM_CXHSCROLL,  SM_CYHSCROLL	Width and height of arrow bitmap on horizontal scrollbar.
SM_CXHTHUMB,	Width of horizontal scrollbar thumb box.
SM_CXICON,  SM_CYICON	The default width and height of an icon. These values are typically 32x32, but can vary depending on the installed display hardware. Windows 95 only: The LoadIcon function can only load icons of these dimensions.
SM_CXICONSPACING, SM_CYICONSPACING	Windows NT only: Width and height of rectangular cell that Program Manager uses to position tiled icons. Windows 95 only: Dimensions of a grid cell for items in large icon view, in pixels. Each item fits into a rectangle of this size when arranged. These values are always greater than or equal to SM_CXICON and SM_CYICON.
SM_CXMAXIMIZED, SM_CYMAXIMIZED	Windows 95 only: Default dimensions of a maximized top-level window, in pixels.
SM_CXMAXTRACK, SM_CYMAXTRACK	Windows 95 only: Default maximum dimensions of a window that has a caption and sizing borders. The user cannot drag the window frame to a size larger than these dimensions. A window can override these values by processing the WM_GETMINMAXINFO message.
SM_CXMENUCHECK, SM_CYMENUCHECK	Windows 95 only: Dimensions of the default menu check-mark bitmap, in pixels.
SM_CXMENUSIZE, SM_CYMENUSIZE	Windows 95 only: Dimensions of menu bar buttons (such as multiple document (MIDI) child close), in pixels.
SM_CXMINIMIZED, SM_CYMINIMIZED	Windows 95 only: Dimensions of a normal minimized window, in pixels.
SM_CXMINSPACING SM_CYMINSPACING	Windows 95 only: Dimensions of a grid cell for minimized windows, in pixels. Each minimized window fits into a rectangle this size when arranged. These values are always greater than or equal to SM_CXMINIMIZED and SM_CYMINIMIZED.
SM_CXMINTRACK, SM_CYMINTRACK	Minimum tracking width and height of a window. The user cannot drag the window frame to a size smaller than these dimensions. A window can override these values by processing the WM_GETMINMAXINFO message.
SM_CXSCREEN,  SM_CYSCREEN	Width and height of the screen.
SM_CXSIZE,  SM_CYSIZE	Windows NT only: Width and height of bitmaps contained in title bar. Windows 95 only: Dimensions of caption buttons, in pixels.
SM_CXSIZEFRAME, SM_CYSIXEFRAME	Windows 95 only: Dimensions, in pixels, of the window frame for a window that has the WS_THICKFRAME style. Formerly SM_CXFRAME and SM_CYFRAME.
SM_CXSMICON, SM_CYSICON	Windows 95 only: Recommended dimensions of a small icon, in pixels. Small icons typically appear in window captions and in small icon view.
SM_CXSMSIZE SM_CYSMSIZE	Windows 95 only: Dimensions of small caption buttons, in pixels.
SM_CXVSCROLL SM_CYHSCROLL	Windows 95 only: Width of vertical scrollbar and height of horizontal scrollbar, in pixels.
SM_CXHSCROLL SM_CYVSCROLL	Windows 95 only: Width of the arrow bitmap on a horizontal scrollbar, and height of the arrow bitmap on a vertical scrollbar.
SM_CXVSCROLL,  SM_CYVSCROLL	Windows NT only: Width and height of arrow bitmap on vertical scrollbar.
SM_CYVTHUMB	Height of vertical scrollbar thumb.
SM_CYCAPTION	Height of normal caption area.
SM_CYKANJIWINDOW	For double-byte character set versions of Windows, height of the Kanji window at the bottom of the screen.
SM_CYMENU	Height of single-line menu bar.
SM_CYSMCAPTION	Windows 95 only: Height of a small caption, in pixels.
SM_DBCSENABLED	TRUE or non-zero if the double-byte character set (DBCS) version of USER.EXE is installed; FALSE, or zero otherwise.
SM_DEBUG	TRUE or non-zero if the debugging version of USER.EXE is installed; FALSE, or zero, otherwise.
SM_MENUDROPALIGNMENT	TRUE, or non-zero if pop-up menus are right-aligned relative to the corresponding menu-bar item; FALSE, or zero if they are left-aligned.
SM_MIDEASTENABLED	Windows 95 only: TRUE if the system is enabled for Hebrew/Arabic languages.
SM_MOUSEPRESENT	TRUE or non-zero if a mouse is installed; FALSE, or zero, otherwise.
SM_NETWORK	Windows 95 only: The least significant bit is set if a network is present; otherwise, it is cleared. The other bits are reserved for future use.
SM_PENWINDOWS	TRUE or non-zero if the Microsoft Windows for Pen computing extensions are installed; zero, or FALSE, otherwise.
SM_SECURE	Windows 95 only: TRUE if security is present, FALSE otherwise.
SM_SHOWSOUNDS	TRUE or non-zero if the user requires an application to present information visually in situations where it would otherwise present the information only in audible form; FALSE, or zero, otherwise.
SM_SLOWMACHINE	Windows 95 only: TRUE if the computer has a low-end (slow) processor, FALSE otherwise.
SM_SWAPBUTTON	TRUE or non-zero if the meanings of the left and right mouse buttons are swapped; FALSE, or zero, otherwise.
Return Value

The return value is the requested system metric or configuration setting.

Remarks

System metrics may vary from display to display.

The SM_ARRANGE setting specifies how the system arranges minimized windows, and consists of a starting position and a direction. The starting position can be one of these values:

Value	Meaning
ARW_BOTTOMLEFT	Start at lower-left corner of screen (default position).
ARW_BOTTOMRIGHT	Start at lower-right corner of screen. Equivelant to ARW_STARTRIGHT.
ARW_HIDE	Hide minimized windows by moving them off of the visible area of the screen.
ARW_TOPLEFT	Start at upper-left corner of screen. Equivelant to ARV_STARTTOP.
ARW_TOPRIGHT	Start at upper-right corner of screen. Equivelant to ARW_STARTTOP | SRW_STARTRIGHT.

The direction in which to arrange can be one of these values:

Value	Meaning
ARW_DOWN	Arrange vertically, top to bottom.
ARW_LEFT	Arrange horizontally, left to right.
ARW_RIGHT	Arrange horizontally, right to left.
ARW_UP	Arrange vertically, bottom to top.


GetSystemPaletteEntries
GetSystemPaletteEntries  QuickInfo  Overview  Group

The GetSystemPaletteEntries function retrieves a range of palette entries from the system palette that is associated with the specified device context.

UINT GetSystemPaletteEntries(

HDC  hdc,	// handle of device context
UINT  iStartIndex,	// index of first entry to be retrieved
UINT  nEntries,	// number of entries to be retrieved
LPPALETTEENTRY  lppe	// array receiving system-palette entries
);
Parameters

hdc

Identifies the device context.

iStartIndex

Specifies the first entry to be retrieved from the system palette.

nEntries

Specifies the number of entries to be retrieved from the system palette.

lppe

Points to an array of PALETTEENTRY structures to receive the palette entries. The array must contain at least as many structures as specified by the nEntries parameter. If this parameter is NULL, the function returns the total number of entries in the palette.

Return Value

If the function succeeds, the return value is the number of entries retrieved from the palette.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

An application can determine whether a device supports palette operations by calling the GetDeviceCaps function and specifying the RASTERCAPS constant.

See Also

GetDeviceCaps, GetPaletteEntries, PALETTEENTRY


GetSystemPaletteUse
GetSystemPaletteUse  QuickInfo  Overview  Group

The GetSystemPaletteUse function retrieves the current state of the system (physical) palette for the specified device context.

UINT GetSystemPaletteUse(

HDC  hdc	// handle of device context
);
Parameters

hdc

Identifies the device context.

Return Value

If the function succeeds, the return value is the current state of the system palette. It can be any of the following values:

Value	Meaning
SYSPAL_NOSTATIC	The system palette contains no static colors except black and white.
SYSPAL_STATIC	The system palette contains static colors that will not change when an application realizes its logical palette.
SYSPAL_ERROR	The given device context is invalid or does not support a color palette.
To get extended error information, call GetLastError.

Remarks

By default, the system palette contains 20 static colors that are not changed when an application realizes its logical palette. An application can gain access to most of these colors by calling the SetSystemPaletteUse function.

The device context identified by the hdc parameter must represent a device that supports color palettes.

An application can determine whether or not a device supports color palettes by calling the GetDeviceCaps function and specifying the RASTERCAPS constant.

See Also

GetDeviceCaps, SetSystemPaletteUse


GetSystemPowerStatus [New - Windows 95]
GetSystemPowerStatus  QuickInfo  Overview  Group

[New - Windows 95]

The GetSystemPowerStatus function retrieves the power status of the system. The status indicates whether the system is running on AC or DC power, whether the battery is currently charging, and how much battery life currently remains.

BOOL GetSystemPowerStatus(

LPSYSTEM_POWER_STATUS  lpSystemPowerStatus
);
Parameters

lpSystemPowerStatus

Pointer to a SYSTEM_POWER_STATUS structure that receives status information.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

See Also

SYSTEM_POWER_STATUS


GetSystemTime
GetSystemTime  QuickInfo  Overview  Group

The GetSystemTime function retrieves the current system date and time. The system time is expressed in Coordinated Universal Time (UTC).

VOID GetSystemTime(

LPSYSTEMTIME  lpSystemTime	// address of system time structure
);
Parameters

lpSystemTime

Points to a SYSTEMTIME structure to receive the current system date and time.

Return Value

This function does not return a value.

Remarks

Windows 95: Early beta implementations of this function return local time rather than UTC.

See Also

GetLocalTime, GetSystemTimeAdjustment, SetSystemTime, SYSTEMTIME


GetSystemTimeAdjustment
GetSystemTimeAdjustment  QuickInfo  Overview  Group

The GetSystemTimeAdjustment function determines whether the system is applying periodic time adjustments to its time-of-day clock at each clock interrupt, along with the value and period of any such adjustments. Note that the period of such adjustments is equivalent to the time period between clock interrupts.

BOOL GetSystemTimeAdjustment(

PDWORD  lpTimeAdjustment,	// size, in 100-nanosecond units, of a periodic time adjustment
PDWORD  lpTimeIncrement,	// time, in 100-nanosecond units, between periodic time adjustments
PBOOL  lpTimeAdjustmentDisabled	// whether periodic time adjustment is disabled or enabled
);
Parameters

lpTimeAdjustment

Pointer to a DWORD that the function sets to the number of 100-nanosecond units added to the time-of-day clock at each periodic time adjustment.

lpTimeIncrement

Pointer to a DWORD that the function sets to the interval, counted in 100-nanosecond units, between periodic time adjustments. This interval is the time period between a system's clock interrupts.

lpTimeAdjustmentDisabled

Pointer to a BOOL that the function sets to indicate whether periodic time adjustment is in effect.

A value of TRUE indicates that periodic time adjustment is disabled. At each clock interrupt, the system merely adds the interval between clock interrupts to the time-of-day clock. The system is free, however, to adjust its time-of-day clock using other techniques. Such other techniques may cause the time-of-day clock to noticeably jump when adjustments are made.

A value of FALSE indicates that periodic time adjustment is being used to adjust the time-of-day clock. At each clock interrupt, the system adds the time increment specified by SetSystemTimeAdjustment's dwTimeIncrement parameter to the time-of-day clock. The system will not interfere with the time adjustment scheme, and will not attempt to synchronize time of day on its own via other techniques.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The GetSystemTimeAdjustment and SetSystemTimeAdjustment functions support algorithms that want to synchronize the time-of-day clock, reported by GetSystemTime and GetLocalTime, with another time source using a periodic time adjustment applied at each clock interrupt.

When periodic time adjustment is in effect, the system adds an adjusting value to the time-of-day clock at a periodic interval, at each clock interrupt. The GetSystemTimeAdjustment function lets a caller determine whether periodic time adjustment is enabled, and if it is, obtain the amount of each adjustment and the time between adjustments. The SetSystemTimeAdjustment function lets a caller enable or disable periodic time adjustment, and set the value of the adjusting increment.

See Also

SetSystemTimeAdjustment, GetSystemTime, GetLocalTime


GetSystemTimeAsFileTime
GetSystemTimeAsFileTime  QuickInfo  Overview  Group

The GetSystemTimeAsFileTime function obtains the current system date and time. The information is in Coordinated Universal Time (UTC) format.

VOID GetSystemTimeAsFileTime(

LPFILETIME  lpSystemTimeAsFileTime	// pointer to a file time structure
);
Parameters

lpSystemTimeAsFileTime

Pointer to a FILETIME structure to receive the current system date and time in UTC format.

Return Value

This function does not return a value.

Remarks

The GetSystemTimeAsFileTime function is equivalent to the following code sequence:

FILETIME ft;

SYSTEMTIME st;

GetSystemTime(&st);

SystemTimeToFileTime(&st,&ft);

Windows 95: The GetSystemTimeAsFileTime function is not available on the Windows 95 platform. If you need its functionality, use the preceding code sequence.

See Also

FILETIME, GetSystemTime, SYSTEMTIME, SystemTimeToFileTime


GetTabbedTextExtent
GetTabbedTextExtent  QuickInfo  Overview  Group

The GetTabbedTextExtent function computes the width and height of a character string. If the string contains one or more tab characters, the width of the string is based upon the specified tab stops. The GetTabbedTextExtent function uses the currently selected font to compute the dimensions of the string.

DWORD GetTabbedTextExtent(

HDC  hDC,	// handle of device context
LPCTSTR  lpString,	// address of character string
int  nCount,	// number of characters in string
int  nTabPositions,	// number of tab positions
LPINT  lpnTabStopPositions	// address of array of tab positions
);
Parameters

hDC

Identifies the device context.

lpString

Points to a character string.

nCount

Specifies the number of characters in the text string.

nTabPositions

Specifies the number of tab-stop positions in the array pointed to by the lpnTabStopPositions parameter.

lpnTabStopPositions

Points to an array containing the tab-stop positions, in device units. The tab stops must be sorted in increasing order; the smallest x-value should be the first item in the array.

Return Value

If the function succeeds, the return value is the dimensions of the string. The height is in the high-order word and the width is in the low-order word.

If the function fails, the return value is 0. GetTabbedTextExtent will fail if hDC is invalid and if nTabPositions is less than 0.

Remarks

The current clipping region does not affect the width and height returned by the GetTabbedTextExtent function.

Because some devices do not place characters in regular cell arrays (that is, they kern the characters), the sum of the extents of the characters in a string may not be equal to the extent of the string.

If the nTabPositions parameter is zero and the lpnTabStopPositions parameter is NULL, tabs are expanded to eight times the average character width.

If nTabPositions is 1, the tab stops are separated by the distance specified by the first value in the array to which lpnTabStopPositions points.

See Also

GetTextExtent, HIWORD, LOWORD, TabbedTextOut


GetTapeParameters
GetTapeParameters  QuickInfo  Overview  Group

The GetTapeParameters function retrieves information that describes the tape or the tape drive.

DWORD GetTapeParameters(

HANDLE  hDevice,	// handle of open device
DWORD  dwOperation,	// type of information requested
LPDWORD  lpdwSize,	// address of returned information
LPVOID  lpTapeInformation	// tape media or drive information
);
Parameters

hDevice

Identifies the device about which information is sought. This handle is created by using the CreateFile function.

dwOperation

Specifies the type of information requested. This parameter must be one of the following values:

Value	Description
GET_TAPE_MEDIA_INFORMATION	Retrieves information about the tape in the tape device.
GET_TAPE_DRIVE_INFORMATION	Retrieves information about the tape device.
lpdwSize

Points to a variable that receives the size, in bytes, of the buffer specified by the lpTapeInformation parameter. If the buffer is too small, this parameter receives the required size.

lpTapeInformation

Points to a structure that contains the requested information. If the dwOperation parameter is GET_TAPE_MEDIA_INFORMATION, lpTapeInformation points to a TAPE_GET_MEDIA_PARAMETERS structure.

If dwOperation is GET_TAPE_DRIVE_INFORMATION, lpTapeInformation points to a TAPE_GET_DRIVE_PARAMETERS structure.

Return Value

If the function succeeds, the return value is NO_ERROR.

If the function fails, the return value is one of the following error codes:

Error code	Description
ERROR_BEGINNING_OF_MEDIA	An attempt to access data before the beginning-of-medium marker failed.
ERROR_BUS_RESET	A reset condition was detected on the bus.
ERROR_END_OF_MEDIA	The end-of-tape marker was reached during an operation.
ERROR_FILEMARK_DETECTED	A filemark was reached during an operation.
ERROR_SETMARK_DETECTED	A setmark was reached during an operation.
ERROR_NO_DATA_DETECTED	The end-of-data marker was reached during an operation.
ERROR_PARTITION_FAILURE	The tape could not be partitioned.
ERROR_INVALID_BLOCK_LENGTH	The block size is incorrect on a new tape in a multivolume partition.
ERROR_DEVICE_NOT_PARTITIONED	The partition information could not be found when a tape was being loaded.
ERROR_MEDIA_CHANGED	The tape that was in the drive has been replaced or removed.
ERROR_NO_MEDIA_IN_DRIVE	There is no media in the drive.
ERROR_NOT_SUPPORTED	The tape driver does not support a requested function.
ERROR_UNABLE_TO_LOCK_MEDIA	An attempt to lock the ejection mechanism failed.
ERROR_UNABLE_TO_UNLOAD_MEDIA	An attempt to unload the tape failed.
ERROR_WRITE_PROTECT	The media is write protected.
Remarks

The block size range values (maximum and minimum) returned by the GetTapeParameters function called with the dwOperation parameter set to the GET_TAPE_DRIVE_INFORMATION value will indicate system limits, not drive limits. However, it is the tape drive device and the media present in the drive that determine the true block size limits. Thus, an application may not be able to set all the block sizes mentioned in the range obtained by specifying GET_TAPE_DRIVE_INFORMATION in dwOperation.

See Also

CreateFile, SetTapeParameters, TAPE_GET_DRIVE_PARAMETERS, TAPE_GET_MEDIA_PARAMETERS


GetTapePosition
GetTapePosition  QuickInfo  Overview  Group

The GetTapePosition function retrieves the current address of the tape, in logical or absolute blocks.

DWORD GetTapePosition(

HANDLE  hDevice,	// handle of open device
DWORD  dwPositionType,	// type of address to obtain
LPDWORD  lpdwPartition,	// address of current tape partition
LPDWORD  lpdwOffsetLow,	// address of low-order 32 bits of tape position
LPDWORD  lpdwOffsetHigh	// address of high-order 32 bits of tape position
);
Parameters

hDevice

Identifies the device on which to get the tape position. This handle is created by using CreateFile.

dwPositionType

Specifies the type of address to obtain. This parameter can be one of the following values:

Value	Description
TAPE_ABSOLUTE_POSITION	The lpdwOffsetLow and lpdwOffsetHigh parameters receive the device-specific block address. The dwPartition parameter receives zero.
TAPE_LOGICAL_POSITION	The lpdwOffsetLow and lpdwOffsetHigh parameters receive the logical block address. The dwPartition parameter receives the logical tape partition.
lpdwPartition

Points to a variable that receives the number of the current tape partition. Partitions are numbered logically from 1 through n, where 1 is the first partition on the tape and n is the last. When a device-specific block address is retrieved, or if the device supports only one partition, this parameter receives zero.

lpdwOffsetLow

Points to a variable that receives the low-order 32 bits of the current tape position.

lpdwOffsetHigh

Points to a variable that receives the high-order 32 bits of the current tape position. This parameter can be NULL if the high-order 32 bits are not required.

Return Value

If the function succeeds, the return value is NO_ERROR.

If the function fails, the return value is one of the following error codes:

Error code	Description
ERROR_BEGINNING_OF_MEDIA	An attempt to access data before the beginning-of-medium marker failed.
ERROR_BUS_RESET	A reset condition was detected on the bus.
ERROR_END_OF_MEDIA	The end-of-tape marker was reached during an operation.
ERROR_FILEMARK_DETECTED	A filemark was reached during an operation.
ERROR_SETMARK_DETECTED	A setmark was reached during an operation.
ERROR_NO_DATA_DETECTED	The end-of-data marker was reached during an operation.
ERROR_PARTITION_FAILURE	The tape could not be partitioned.
ERROR_INVALID_BLOCK_LENGTH	The block size is incorrect on a new tape in a multivolume partition.
ERROR_DEVICE_NOT_PARTITIONED	The partition information could not be found when a tape was being loaded.
ERROR_MEDIA_CHANGED	The tape that was in the drive has been replaced or removed.
ERROR_NO_MEDIA_IN_DRIVE	There is no media in the drive.
ERROR_NOT_SUPPORTED	The tape driver does not support a requested function.
ERROR_UNABLE_TO_LOCK_MEDIA	An attempt to lock the ejection mechanism failed.
ERROR_UNABLE_TO_UNLOAD_MEDIA	An attempt to unload the tape failed.
ERROR_WRITE_PROTECT	The media is write protected.
Remarks

A logical block address is relative to a partition. The first logical block address on each partition is zero.

Call the GetTapeParameters function to obtain information about the status, capabilities, and capacities of tape drives and media.

See Also

CreateFile, GetTapeParameters, SetTapePosition


GetTapeStatus
GetTapeStatus  QuickInfo  Overview  Group

The GetTapeStatus function indicates whether the tape device is ready to process tape commands.

DWORD GetTapeStatus(

HANDLE  hDevice	// handle of open device
);
Parameters

hDevice

Identifies the device for which to get the device status. This handle is created by using the CreateFile function.

Return Value

If the tape device is ready to accept appropriate tape-access commands without returning errors, the return value is NO_ERROR.

If the function fails, the return value is one of the following error codes:

Error code	Description
ERROR_BEGINNING_OF_MEDIA	An attempt to access data before the beginning-of-medium marker failed.
ERROR_BUS_RESET	A reset condition was detected on the bus.
ERROR_END_OF_MEDIA	The end-of-tape marker was reached during an operation.
ERROR_FILEMARK_DETECTED	A filemark was reached during an operation.
ERROR_SETMARK_DETECTED	A setmark was reached during an operation.
ERROR_NO_DATA_DETECTED	The end-of-data marker was reached during an operation.
ERROR_PARTITION_FAILURE	The tape could not be partitioned.
ERROR_INVALID_BLOCK_LENGTH	The block size is incorrect on a new tape in a multivolume partition.
ERROR_DEVICE_NOT_PARTITIONED	The partition information could not be found when a tape was being loaded.
ERROR_MEDIA_CHANGED	The tape that was in the drive has been replaced or removed.
ERROR_NO_MEDIA_IN_DRIVE	There is no media in the drive.
ERROR_NOT_SUPPORTED	The tape driver does not support a requested function.
ERROR_UNABLE_TO_LOCK_MEDIA	An attempt to lock the ejection mechanism failed.
ERROR_UNABLE_TO_UNLOAD_MEDIA	An attempt to unload the tape failed.
ERROR_WRITE_PROTECT	The media is write protected.
See Also

CreateFile


GetTempDrive
GetTempDrive  Overview  Group

The GetTempDrive function is not implemented in the Win32 API. Win32-based applications should use the GetTempPath function.


GetTempFileName
GetTempFileName  QuickInfo  Overview  Group

The GetTempFileName function creates a name for a temporary file. The filename is the concatenation of specified path and prefix strings, a hexadecimal string formed from a specified integer, and the .TMP extension.

The specified integer can be nonzero, in which case, the function creates the filename but does not create the file. If you specify zero for the integer, the function creates a unique filename and creates the file in the specified directory.

UINT GetTempFileName(

LPCTSTR  lpPathName,	// address of directory name for temporary file
LPCTSTR  lpPrefixString,	// address of filename prefix
UINT  uUnique,	// number used to create temporary filename
LPTSTR  lpTempFileName	// address of buffer that receives the new filename
);
Parameters

lpPathName

Points to a null-terminated string that specifies the directory path for the filename. This string must consist of characters in the ANSI character set. Applications typically specify a period (.) or the result of the GetTempPath function for this parameter. If this parameter is NULL, the function fails.

lpPrefixString

Points to a null-terminated prefix string. The function uses the first three characters of this string as the prefix of the filename. This string must consist of characters in the ANSI character set.

uUnique

Specifies an unsigned integer that the function converts to a hexadecimal string for use in creating the temporary filename.

If uUnique is nonzero, the function appends the hexadecimal string to lpPrefixString to form the temporary filename. In this case, the function does not create the specified file, and does not test whether the filename is unique.

If uUnique is zero, the function uses a hexadecimal string derived from the current system time. In this case, the function uses different values until it finds a unique filename, and then it creates the file in the lpPathName directory.

lpTempFileName

Points to the buffer that receives the temporary filename. This null-terminated string consists of characters in the ANSI character set. This buffer should be at least the length, in bytes, specified by MAX_PATH to accommodate the path.

Return Value

If the function succeeds, the return value specifies the unique numeric value used in the temporary filename. If the uUnique parameter is nonzero, the return value specifies that same number.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

The GetTempFileName function creates a temporary filename of the following form:

     path\preuuuu.TMP

The following table describes the filename syntax:

Component	Meaning
path	Path specified by the lpPathName parameter
pre	First three letters of the lpPrefixString string
uuuu	Hexadecimal value of uUnique
When Windows shuts down, temporary files whose names have been created by this function are not automatically deleted.

To avoid problems resulting from converting an ANSI character set string to a Windows string, an application should call the CreateFile function to create a temporary file.

If the uUnique parameter is zero, GetTempFileName attempts to form a unique number based on the current system time. If a file with the resulting filename exists, the number is increased by one and the test for existence is repeated. Testing continues until a unique filename is found. GetTempFileName then creates a file by that name and closes it. When uUnique is nonzero, no attempt is made to create and open the file.

See Also

CreateFile, GetTempPath


GetTempPath
GetTempPath  QuickInfo  Overview  Group

The GetTempPath function retrieves the path of the directory designated for temporary files. This function supersedes the GetTempDrive function.

DWORD GetTempPath(

DWORD  nBufferLength,	// size, in characters, of the buffer
LPTSTR  lpBuffer	// address of buffer for temp. path
);
Parameters

nBufferLength

Specifies the size, in characters, of the string buffer identified by lpBuffer.

lpBuffer

Points to a string buffer that receives the null-terminated string specifying the temporary file path.

Return Value

If the function succeeds, the return value is the length, in characters, of the string copied to lpBuffer, not including the terminating null character. If the return value is greater than nBufferLength, the return value is the size of the buffer required to hold the path.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

The GetTempPath function gets the temporary file path as follows:

1.	The path specified by the TMP environment variable.

2.	The path specified by the TEMP environment variable, if TMP is not defined.

3.	The current directory, if both TMP and TEMP are not defined.

See Also

GetTempFileName


GetTextAlign
GetTextAlign  QuickInfo  Overview  Group

The GetTextAlign function retrieves the text-alignment setting for the specified device context.

UINT GetTextAlign(

HDC  hdc	// handle of device context
);
Parameters

hdc

Identifies the device context.

Return Value

If the function succeeds, the return value is the status of the text-alignment flags.

If the function fails, the return value is GDI_ERROR. To get extended error information, call GetLastError.

For a list of status return values, see the Remarks section. The return value is a combination of one or more of the following values:

Value	Meaning
TA_BASELINE	The reference point is on the base line of the text.
TA_BOTTOM	The reference point is on the bottom edge of the bounding rectangle.
TA_TOP	The reference point is on the top edge of the bounding rectangle.
TA_CENTER	The reference point is aligned horizontally with the center of the bounding rectangle.
TA_LEFT	The reference point is on the left edge of the bounding rectangle.
TA_RIGHT	The reference point is on the right edge of the bounding rectangle.
TA_RTLREADING	Windows 95 only: The text is laid out in right to left reading order, as opposed to the default left to right order. This only applies when the font selected into the device context is either Hebrew or Arabic.
TA_NOUPDATECP	The current position is not updated after each text output call.
TA_UPDATECP	The current position is updated after each text output call.
When the current font has a vertical default base line (as with Kanji), the following values are used instead of TA_BASELINE and TA_CENTER:

Value	Meaning
VTA_BASELINE	The reference point is on the base line of the text.
VTA_CENTER	The reference point is aligned vertically with the center of the bounding rectangle.
Remarks

The bounding rectangle is a rectangle bounding all of the character cells in a string of text. Its dimensions can be obtained by calling the GetTextExtent function.

The text-alignment flags determine how the TextOut and ExtTextOut functions align a string of text in relation to the string's reference point provided to TextOut or ExtTextOut.

The text-alignment flags are not necessarily single bit flags and may be equal to zero. The flags must be examined in groups of related flags, as shown in the following list:

TA_LEFT, TA_RIGHT, and TA_CENTER
TA_BOTTOM, TA_TOP, and TA_BASELINE
TA_NOUPDATECP and TA_UPDATECP

If the current font has a vertical default base line, the related flags are as shown in the following list:

TA_LEFT, TA_RIGHT, and VTA_BASELINE
TA_BOTTOM, TA_TOP, and VTA_CENTER
TA_NOUPDATECP and TA_UPDATECP

To verify that a particular flag is set in the return value of this function, the application must perform the following steps:

1.	Apply the bitwise OR operator to the flag and its related flags.

2.	Apply the bitwise AND operator to the result and the return value.

3.	Test for the equality of this result and the flag.

See Also

ExtTextOut, GetTextExtent, SetTextAlign, TextOut


GetTextCharacterExtra
GetTextCharacterExtra  QuickInfo  Overview  Group

The GetTextCharacterExtra function retrieves the current intercharacter spacing for the specified device context.

int GetTextCharacterExtra(

HDC  hdc	// handle of device context
);
Parameters

hdc

Identifies the device context.

Return Value

If the function succeeds, the return value is the current intercharacter spacing.

If the function fails, the return value is 0x8000000.

Remarks

The intercharacter spacing defines the extra space, in logical units along the base line, that the TextOut or ExtTextOut functions add to each character as a line is written. The spacing is used to expand lines of text.

See Also

ExtTextOut, SetTextCharacterExtra, TextOut


GetTextCharsetInfo [New - Windows 95]
GetTextCharsetInfo  QuickInfo

[New - Windows 95]

The GetTextCharsetInfo function retrieves information about the character set for the currently selected font.

UINT GetTextCharsetInfo(

HDC hdc,	// handle of device context
LPFONTSIGNATURE * lpSig,	// address of buffer for font-signature data
DWORD dwFlags	// reserved; must be zero
);
Parameters

hdc

Identifies the device context.

lpSig

Points to the buffer that receives the font signature block. The block includes both the Unicode and ANSI sections. This parameter can be NULL if the block is not required. If the font is not a TrueType font, the function sets the font signature to all zeros. In this case, use TranslateCharsetInfo to retrieve the generic signatures for character sets if required.

dwFlags

Reserved; must be zero.

Return Value

If the function succeeds, the return value is the character set of the currently selected font for the given device context.

If the function fails, the return value is DEFAULT_CHARSET.


GetTextColor
GetTextColor  QuickInfo  Overview  Group

The GetTextColor function retrieves the current text color for the specified device context.

COLORREF GetTextColor(

HDC  hdc	// handle of device context
);
Parameters

hdc

Identifies the device context.

Return Value

If the function succeeds, the return value is the current text color as a COLORREF value.

If the function fails, the return value is CLR_INVALID.

Remarks

The text color defines the foreground color of characters drawn by using the TextOut or ExtTextOut function.

See Also

ExtTextOut, TextOut


GetTextExtent
GetTextExtent  Overview  Group

The GetTextExtent function is not implemented in the Win32 API. This function is included for compatibility with 16-bit versions of Windows. Win32-based applications should use the GetTextExtentPoint32 function.


GetTextExtentExPoint
GetTextExtentExPoint  QuickInfo  Overview  Group

The GetTextExtentExPoint function retrieves the number of characters in a specified string that will fit within a specified space and fills an array with the text extent for each of those characters. (A text extent is the distance between the beginning of the space and a character that will fit in the space.) This information is useful for word-wrapping calculations.

BOOL GetTextExtentExPoint(

HDC  hdc,	// handle of device context
LPCTSTR  lpszStr,	// address of character string
int  cchString,	// number of characters in string
int  nMaxExtent,	// maximum width for formatted string
LPINT  lpnFit,	// address of value specifying max. number of chars.
LPINT  alpDx,	// address of array for partial string widths
LPSIZE  lpSize	// address of structure with string dimensions
);
Parameters

hdc

Identifies the device context.

lpszStr

Points to the null-terminated string for which extents are to be retrieved.

cchString

Specifies the number of bytes in the string pointed to by the lpszStr parameter.

nMaxExtent

Specifies the maximum allowable width, in logical units, of the formatted string.

lpnFit

Points to an integer to receive a count of the maximum number of characters that will fit in the space specified by the nMaxExtent parameter. When the lpnFit parameter is NULL, the nMaxExtent parameter is ignored.

alpDx

Points to an array of integers to receive partial string extents. Each element in the array gives the distance, in logical units, between the beginning of the string and one of the characters that fits in the space specified by the nMaxExtent parameter. Although this array should have at least as many elements as characters specified by the cchString parameter, the function fills the array with extents only for as many characters as are given by the lpnFit parameter. If alpDx is NULL, the function does not compute partial string widths.

lpSize

Points to a SIZE structure that contains the dimensions of the string, in logical units when the function returns. This value cannot be NULL.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

If both the lpnFit and alpDx parameters are NULL, calling the GetTextExtentExPoint function is equivalent to calling the GetTextExtentPoint function.

See Also

GetTextExtentPoint, SIZE


GetTextExtentPoint
GetTextExtentPoint  QuickInfo  Overview  Group

The GetTextExtentPoint function computes the width and height of the specified string of text.

GetTextExtentPoint is provided for compatibility with 16-bit versions of Windows. Win32-based applications should call the GetTextExtentPoint32 function, which provides more accurate results.

BOOL GetTextExtentPoint(

HDC  hdc,	// handle of device context
LPCTSTR  lpString,	// address of text string
int  cbString,	// number of characters in string
LPSIZE  lpSize	// address of structure for string size
);
Parameters

hdc

Identifies the device context.

lpString

Points to the string of text. The string does not need to be zero-terminated, since cbString specifies the length of the string.

cbString

Specifies the number of characters in the string.

lpSize

Points to a SIZE structure in which the dimensions of the string are to be returned.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The GetTextExtentPoint function uses the currently selected font to compute the dimensions of the string. The width and height, in logical units, are computed without considering any clipping.

Because some devices kern characters, the sum of the extents of the characters in a string may not be equal to the extent of the string.

The calculated string width takes into account the intercharacter spacing set by the SetTextCharacterExtra function.

See Also

GetTextExtentPoint32, SetTextCharacterExtra, SIZE


GetTextExtentPoint32
GetTextExtentPoint32  QuickInfo  Overview  Group

The GetTextExtentPoint32 function computes the width and height of the specified string of text. This function supersedes the GetTextExtentPoint function.

BOOL GetTextExtentPoint32(

HDC  hdc,	// handle of device context
LPCTSTR  lpString,	// address of text string
int  cbString,	// number of characters in string
LPSIZE  lpSize	// address of structure for string size
);
Parameters

hdc

Identifies the device context.

lpString

Points to the string of text. The string does not need to be zero-terminated, since cbString specifies the length of the string.

cbString

Specifies the number of characters in the string.

lpSize

Points to a SIZE structure in which the dimensions of the string are to be returned.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The GetTextExtentPoint32 function uses the currently selected font to compute the dimensions of the string. The width and height, in logical units, are computed without considering any clipping.

Because some devices kern characters, the sum of the extents of the characters in a string may not be equal to the extent of the string.

The calculated string width takes into account the intercharacter spacing set by the SetTextCharacterExtra function.

See Also

GetTextExtentPoint, SetTextCharacterExtra, SIZE


GetTextFace
GetTextFace  QuickInfo  Overview  Group

The GetTextFace function retrieves the typeface name of the font that is selected into the specified device context.

int GetTextFace(

HDC  hdc,	// handle of device context
int  nCount,	// length of buffer receiving typeface name
LPTSTR  lpFaceName	// address of buffer receiving typeface name
);
Parameters

hdc

Identifies the device context.

nCount

Specifies the size, in characters, of the buffer.

lpFaceName

Points to the buffer that is to receive the typeface name. If this parameter is NULL, the function returns the number of characters in the name, including the terminating null character.

Return Value

If the function succeeds, the return value is the number of characters copied to the buffer.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

The typeface name is copied as a null-terminated character string.

If the name is longer than the number of characters specified by the nCount parameter, the name is truncated.

See Also

GetTextAlign, GetTextColor, GetTextExtentPoint32, GetTextMetrics


GetTextMetrics
GetTextMetrics  QuickInfo  Overview  Group

The GetTextMetrics function fills the specified buffer with the metrics for the currently selected font.

BOOL GetTextMetrics(

HDC  hdc,	// handle of device context
LPTEXTMETRIC  lptm	// address of text metrics structure
);
Parameters

hdc

Identifies the device context.

lptm

Points to the TEXTMETRIC structure that is to receive the metrics.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

GetTextAlign, GetTextExtent, GetTextFace, SetTextJustification, TEXTMETRIC


GetThreadContext
GetThreadContext  QuickInfo  Overview  Group

The GetThreadContext function retrieves the context of the specified thread.

BOOL GetThreadContext(

HANDLE  hThread,	// handle of thread with context
LPCONTEXT  lpContext	// address of context structure
);
Parameters

hThread

Identifies an open handle of a thread whose context is to be retrieved. The handle must have THREAD_GET_CONTEXT access to the thread.

lpContext

Points to the address of a CONTEXT structure that receives the appropriate context of the specified thread. The value of the ContextFlags member of this structure specifies which portions of a thread's context are retrieved. The CONTEXT structure is highly computer specific; two versions of the structure currently exist, one version for x86 processors and another for MIPS processors.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

GetThreadContext is used to retrieve the context of the specified thread. The function allows a selective context to be retrieved based on the value of the ContextFlags member of the CONTEXT structure. The thread handle identified by the hThread parameter is typically being debugged, but the function can also operate when it is not being debugged.

See Also

CONTEXT, SetThreadContext


GetThreadDesktop
GetThreadDesktop  QuickInfo  Overview  Group

The GetThreadDesktop function returns a handle to the desktop associated with a specified thread.

HDESK GetThreadDesktop(

DWORD  dwThreadId	// thread identifier
);
Parameters

dwThreadId

Identifies the thread for which to return the desktop handle. The GetCurrentThreadId and CreateProcess functions return thread identifiers.

Return Value

If the function succeeds, the return value is the handle of the desktop associated with the specified thread.

Remarks

The system associates a desktop with a thread when that thread is created. A thread can use the SetThreadDesktop function to change its desktop. The desktop associated with a thread must be on the window station associated with the thread's process.

The calling process can use the returned handle in calls to the GetUserObjectInformation, GetUserObjectSecurity, SetUserObjectInformation, and SetUserObjectSecurity functions.

Windows 95: Windows 95 does not support multiple desktops, so GetThreadDesktop always returns the same value.

See Also

GetCurrentThreadId, GetProcessWindowStation, GetUserObjectInformation, GetUserObjectSecurity, SetProcessWindowStation, SetThreadDesktop, SetUserObjectInformation, SetUserObjectSecurity


GetThreadLocale
GetThreadLocale  QuickInfo  Overview  Group

The GetThreadLocale function returns the calling thread's current locale.

LCID GetThreadLocale(VOID)

Parameters

This function has no parameters.

Return Value

The function returns the calling thread's 32-bit LCID locale identifier.

Remarks

When a thread is created, it is given the system default thread locale. The system reads the system default thread locale from the registry when the system boots. This system default can be modified for future process and thread creation using Control Panel's International application.

See Also

SetThreadLocale, GetSystemDefaultLCID, GetUserDefaultLCID


GetThreadPriority
GetThreadPriority  QuickInfo  Overview  Group

The GetThreadPriority function returns the priority value for the specified thread. This value, together with the priority class of the thread's process, determines the thread's base-priority level.

int GetThreadPriority(

HANDLE  hThread	// handle to thread
);
Parameters

hThread

Identifies the thread. The handle must have THREAD_QUERY_INFORMATION access.

Return Value

If the function succeeds, the return value is the thread's priority level.

If the function fails, the return value is THREAD_PRIORITY_ERROR_RETURN. To get extended error information, call GetLastError.

The thread's priority level is one of the following values:

Priority	Meaning
THREAD_PRIORITY_ABOVE_NORMAL
	Indicates 1 point above normal priority for the priority class.
THREAD_PRIORITY_BELOW_NORMAL
	Indicates 1 point below normal priority for the priority class.
THREAD_PRIORITY_HIGHEST
	Indicates 2 points above normal priority for the priority class.
THREAD_PRIORITY_IDLE
	Indicates a base-priority level of 1 for IDLE_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS, or HIGH_PRIORITY_CLASS processes, and a base-priority level of 16 for REALTIME_PRIORITY_CLASS processes.
THREAD_PRIORITY_LOWEST
	Indicates 2 points below normal priority for the priority class.
THREAD_PRIORITY_NORMAL
	Indicates normal priority for the priority class.
THREAD_PRIORITY_TIME_CRITICAL
	Indicates a base-priority level of 15 for IDLE_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS, or HIGH_PRIORITY_CLASS processes, and a base-priority level of 31 for REALTIME_PRIORITY_CLASS processes.
Remarks

Every thread has a base-priority level determined by the thread's priority value and the priority class of its process. The operating system uses the base-priority level of all executable threads to determine which thread gets the next slice of CPU time. Threads are scheduled in a round-robin fashion at each priority level, and only when there are no executable threads at a higher level will scheduling of threads at a lower level take place.

For a table that shows the base-priority levels for each combination of priority class and thread priority value, refer to the SetPriorityClass function.

See Also

GetPriorityClass, SetPriorityClass, SetThreadPriority


GetThreadSelectorEntry
GetThreadSelectorEntry  QuickInfo  Overview  Group

The GetThreadSelectorEntry function retrieves a descriptor table entry for the specified selector and thread.

BOOL GetThreadSelectorEntry(

HANDLE  hThread,	// handle of thread that contains selector
DWORD  dwSelector,	// number of selector value to look up
LPLDT_ENTRY  lpSelectorEntry	// address of selector entry structure
);
Parameters

hThread

Identifies a handle of the thread containing the specified selector. The handle must have THREAD_QUERY_INFORMATION access.

dwSelector

Specifies the global or local selector value to look up in the thread's descriptor tables.

lpSelectorEntry

Points to a structure that receives a copy of the descriptor table entry if the specified selector has an entry in the specified thread's descriptor table. This information can be used to convert a segment-relative address to a linear virtual address.

Return Value

If the function succeeds, the return value is TRUE. In that case, the structure pointed to by the lpSelectorEntry parameter receives a copy of the specified descriptor table entry.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

GetThreadSelectorEntry is only functional on x86-based systems. For systems that are not x86-based, the function returns FALSE.

Debuggers use this function to convert segment-relative addresses to linear virtual addresses. The ReadProcessMemory and WriteProcessMemory functions use linear virtual addresses.

See Also

ReadProcessMemory, WriteProcessMemory


GetThreadTimes
GetThreadTimes  QuickInfo  Overview  Group

The GetThreadTimes function obtains timing information about a specified thread.

BOOL GetThreadTimes(

HANDLE  hThread,	// specifies the thread of interest
LPFILETIME  lpCreationTime,	// when the thread was created
LPFILETIME  lpExitTime,	// when the thread was destroyed
LPFILETIME  lpKernelTime,	// time the thread has spent in kernel mode
LPFILETIME  lpUserTime	// time the thread has spent in user mode
);
Parameters

hThread

An open handle that specifies the thread whose timing information is sought. This handle must be created with THREAD_QUERY_INFORMATION access.

lpCreationTime

Points to a FILETIME structure that receives the creation time of the thread.

lpExitTime

Points to a FILETIME structure that receives the exit time of the thread. If the thread has not exited, the content of this structure is undefined.

lpKernelTime

Points to a FILETIME structure that receives the amount of time that the thread has executed in kernel mode.

lpUserTime

Points to a FILETIME structure that receives the amount of time that the thread has executed in user mode.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

All times are expressed using FILETIME data structures. Such a structure contains two 32-bit values that combine to form a 64-bit count of 100-nanosecond time units.

Thread creation and exit times are points in time expressed as the amount of time that has elapsed since midnight on January 1, 1601 at Greenwich, England. The Win32 API provides several functions that an application can use to convert such values to more generally useful forms; see Time and Date Functions, and the functions noted in the following See Also section.

Thread kernel mode and user mode times are amounts of time. For example, if a thread has spent one second in kernel mode, this function will fill the FILETIME structure specified by lpKernelTime with a 64-bit value of ten million. That is the number of 100-nanosecond units in one second.

See Also

FILETIME, FileTimeToDosDateTime, FileTimeToLocalFileTime, FileTimeToSystemTime


GetThresholdEvent

The GetThresholdEvent function is not implemented in the Win32 API.

See Also

Beep, MessageBeep


GetThresholdStatus

The GetThresholdStatus function is not implemented in the Win32 API.

See Also

Beep, MessageBeep


GetTickCount
GetTickCount  QuickInfo  Overview  Group

The GetTickCount function retrieves the number of milliseconds that have elapsed since Windows was started.

DWORD GetTickCount(VOID)

Parameters

This function has no parameters.

Return Value

If the function succeeds, the return value is the number of milliseconds that have elapsed since Windows was started.

Remarks

The GetTickCount function is identical to the GetCurrentTime function. Applications should use the GetTickCount function because its name matches more closely what the function does.

The GetTickCount and GetMessageTime functions return different times. GetMessageTime returns the Windows time when the given message was created, not the current Windows time.

The internal timer wraps around to zero if Windows is run continuously for approximately 49.7 days.

See Also

GetCurrentTime, GetMessageTime, GetSystemTime, SetSystemTime


GetTimeFormat
GetTimeFormat  QuickInfo  Overview  Group

The GetTimeFormat function formats a time as a time string for a specified locale. The function formats either a specified time or the local system time.

int GetTimeFormat(

LCID  Locale,	// locale for which time is to be formatted
DWORD  dwFlags,	// flags specifying function options
CONST SYSTEMTIME *  lpTime,	// time to be formatted
LPCTSTR  lpFormat,	// time format string
LPTSTR  lpTimeStr,	// buffer for storing formatted string
int  cchTime	// size, in bytes or characters, of the buffer
);
Parameters

Locale

Specifies the locale for which the time string is to be formatted. If lpFormat is NULL, the function formats the string according to the time format for this locale. If lpFormat is not NULL, the function uses the locale only for information not specified in the format picture string (for example, the locale's time markers).

This parameter can be a locale identifier created by the MAKELCID macro, or one of the following predefined values:

LOCALE_SYSTEM_DEFAULT	Default system locale.
LOCALE_USER_DEFAULT	Default user locale.
dwFlags

A set of bit flags that specify various function options. You can specify a combination of the following flags:

Flag	Meaning
LOCALE_NOUSEROVERRIDE	If set, the function formats the string using the system default time format for the specified locale. If not set, the function formats the string using any user overrides to the locale's default time format. This flag cannot be set if lpFormat is non-NULL.
TIME_NOMINUTESORSECONDS	Do not use minutes or seconds.
TIME_NOSECONDS	Do not use seconds.
TIME_NOTIMEMARKER	Do not use a time marker.
TIME_FORCE24HOURFORMAT	Always use a 24-hour time format.
lpTime

Pointer to a SYSTEMTIME structure that contains the time information to be formatted. If this pointer is NULL, the function uses the current local system time.

lpFormat

Pointer to a format picture to use to form the time string. If lpFormat is NULL, the function uses the time format of the specified locale.

Use the following elements to construct a format picture string. If you use spaces to separate the elements in the format string, these spaces will appear in the same location in the output string. The letters must be in uppercase or lowercase as shown (for example, "ss", not "SS"). Characters in the format string that are enclosed in single quotation marks will appear in the same location and unchanged in the output string.

Picture	Meaning
h	Hours with no leading zero for single-digit hours; 12-hour clock
hh	Hours with leading zero for single-digit hours; 12-hour clock
H	Hours with no leading zero for single-digit hours; 24-hour clock
HH	Hours with leading zero for single-digit hours; 24-hour clock
m	Minutes with no leading zero for single-digit minutes
mm	Minutes with leading zero for single-digit minutes
s	Seconds with no leading zero for single-digit seconds
ss	Seconds with leading zero for single-digit seconds
t	One character time marker string, such as A or P
tt	Multicharacter time marker string, such as AM or PM
For example, to get the time string

"11:29:40 PM"

use the following picture string:

"hh':'mm':'ss tt"

lpTimeStr

Pointer to a buffer that receives the formatted time string.

cchTime

Specifies the size, in bytes (ANSI version) or characters (Unicode version), of the lpTimeStr buffer. If cchTime is zero, the function returns the number of bytes or characters required to hold the formatted time string, and the buffer pointed to by lpTimeStr is not used.

Return Value

If the function succeeds, the return value is the number of bytes (ANSI version) or characters (Unicode version) written to the buffer pointed to by lpTimeStr. If the cchTime parameter is zero, the return value is the number of bytes or characters required to hold the formatted time string.

If the function fails, the return value is zero. To get extended error information, call GetLastError. GetLastError may return one of the following error codes:

ERROR_INSUFFICIENT_BUFFER

ERROR_INVALID_FLAGS

ERROR_INVALID_PARAMETER

Remarks

If a time marker exists and the TIME_NOTIMEMARKER flag is not set, the function localizes the time marker based on the specified locale identifier. Examples of time markers are "AM" and "PM" for US English.

The time values in the SYSTEMTIME structure pointed to by lpTime must be valid. The function checks each of the time values to determine that it is within the appropriate range of values. If any of the time values are outside the correct range, the function fails, and sets the last-error to ERROR_INVALID_PARAMETER.

The function ignores the date portions of the SYSTEMTIME structure pointed to by lpTime: wYear, wMonth, wDayOfWeek, and wDay.

If TIME_NOMINUTESORSECONDS or TIME_NOSECONDS is specified, the function removes the separator(s) preceding the minutes and/or seconds element(s).

If TIME_NOTIMEMARKER is specified, the function removes the separator(s) preceding and following the time marker.

If TIME_FORCE24HOURFORMAT is specified, the function displays any existing time marker, unless the TIME_NOTIMEMARKER flag is also set.

The function does not include milliseconds as part of the formatted time string.

To use the LOCALE_NOUSEROVERRIDE flag, lpFormat must be NULL.

No errors are returned for a bad format string. The function simply forms the best time string that it can. If more than two hour, minute, second, or time marker format pictures are passed in, then the function defaults to two. For example, the only time marker pictures that are valid are L"t" and L"tt" (the 'L' indicates a Unicode (16-bit characters) string). If L"ttt" is passed in, the function assumes L"tt".

See Also

GetDateFormat, SYSTEMTIME


GetTimeZoneInformation
GetTimeZoneInformation  QuickInfo  Overview  Group

The GetTimeZoneInformation function retrieves the current time-zone parameters. These parameters control the translations between Coordinated Universal Time (UTC) and local time.

DWORD GetTimeZoneInformation(

LPTIME_ZONE_INFORMATION  lpTimeZoneInformation	// address of time-zone settings
);
Parameters

lpTimeZoneInformation

Points to a TIME_ZONE_INFORMATION structure to receive the current time-zone parameters.

Return Value

If the function succeeds, the return value is one of the following values:

Value	Meaning
TIME_ZONE_ID_UNKNOWN	The operating system cannot determine the current time zone. This is usually because a previous call to the SetTimeZoneInformation function supplied only the bias (and no transition dates).
TIME_ZONE_ID_STANDARD	The operating system is operating in the range covered by the StandardDate member of the structure pointed to by the lpTimeZoneInformation parameter.
TIME_ZONE_ID_DAYLIGHT	The operating system is operating in the range covered by the DaylightDate member of the structure pointed to by the lpTimeZoneInformation parameter.
If the function fails, the return value is 0xFFFFFFFF. To get extended error information, call GetLastError.

Remarks

All translations between UTC time and local time are based on the following formula:

UTC = local time + bias

The bias is the difference, in minutes, between UTC time and local time.

See Also

SetTimeZoneInformation, TIME_ZONE_INFORMATION


GetTokenInformation
GetTokenInformation  QuickInfo  Overview  Group

The GetTokenInformation function retrieves a specified type of information about an access token. The calling process must have appropriate access rights to obtain the information.

BOOL GetTokenInformation(

HANDLE  TokenHandle,	// handle of access token
TOKEN_INFORMATION_CLASS  TokenInformationClass,	// type of information to retrieve
LPVOID  TokenInformation,	// address of retrieved information
DWORD  TokenInformationLength,	// size of information buffer
PDWORD  ReturnLength	// address of required buffer size
);
Parameters

TokenHandle

Identifies an access token from which information is retrieved.

TokenInformationClass

Specifies a variable of the TOKEN_INFORMATION_CLASS enumerated type identifying the type of information the function retrieves.

TokenInformation

Points to a buffer the function fills with the requested information. The structure put into this buffer depends upon the type of information specified by the TokenInformationClass parameter, as shown in the following list:

Token Information Class	Structure Returned
TokenUser	TOKEN_USER structure. TOKEN_QUERY access is needed to retrieve this information.
TokenGroups	TOKEN_GROUPS structure. TOKEN_QUERY access is needed to retrieve this information.
TokenPrivileges	TOKEN_PRIVILEGES structure. TOKEN_QUERY access is needed to retrieve this information.
TokenOwner	TOKEN_OWNER structure. TOKEN_QUERY access is needed to retrieve this information.
TokenPrimaryGroup	TOKEN_PRIMARY_GROUP structure. TOKEN_QUERY access is needed to retrieve this information.
TokenDefaultDacl	TOKEN_DEFAULT_DACL structure. TOKEN_QUERY access is needed to retrieve this information.
TokenSource	TOKEN_SOURCE structure. TOKEN_QUERY_SOURCE access is needed to retrieve this information.
TokenType	TOKEN_TYPE enumerated type. TOKEN_QUERY access is needed to retrieve this information.
TokenImpersonationLevel	SECURITY_IMPERSONATION_LEVEL enumerated type. TOKEN_QUERY access is needed to retrieve this information about a token. If the access token is not an impersonation token, the function fails.
TokenStatistics	TOKEN_STATISTICS structure. TOKEN_QUERY access is needed to retrieve this information.
The formats for the retrieved structures and enumerated types are listed in the following Remarks section.

TokenInformationLength

Specifies the size, in bytes, of the buffer pointed to by the TokenInformation parameter.

ReturnLength

Points to a variable receiving the actual number of bytes needed for the buffer pointed to by the TokenInformation parameter. If this value is larger than the value specified in the TokenInformationLength parameter, the function fails and stores no data in the buffer.

If the value of the TokenInformationClass parameter is TokenDefaultDacl and the token has no default access-control list, the function sets the variable pointed to by ReturnLength to zero and stores no data in the buffer.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

AdjustTokenGroups, AdjustTokenPrivileges, OpenProcessToken, OpenThreadToken, SetTokenInformation, SECURITY_IMPERSONATION_LEVEL, TOKEN_DEFAULT_DACL, TOKEN_GROUPS, TOKEN_INFORMATION_CLASS, TOKEN_OWNER, TOKEN_PRIMARY_GROUP, TOKEN_PRIVILEGES, TOKEN_SOURCE, TOKEN_STATISTICS, TOKEN_TYPE, TOKEN_USER


GetTopWindow
GetTopWindow  QuickInfo  Overview  Group

The GetTopWindow function examines the Z order of the child windows associated with the specified parent window and retrieves the handle of the child window at the top of the Z order.

HWND GetTopWindow(

HWND  hWnd	// handle of parent window
);
Parameters

hWnd

Identifies the parent window whose child windows are to be examined. If this parameter is NULL, the function returns a handle of the window at the top of the Z order.

Return Value

If the function succeeds, the return value is the handle of the child window at the top of the Z order. If the specified window has no child windows, the return value is NULL. To get extended error information, use the GetLastError function.

See Also

GetNextWindow, GetWindow


GetTypeByName
GetTypeByName  QuickInfo  Overview  Group

The GetTypeByName function obtains a service type GUID for a network service specified by name.

INT GetTypeByName(

LPTSTR  lpServiceName,	// points to the name of the network service
PGUID  lpServiceType	// points to a variable to receive network service type
);
Parameters

lpServiceName

Points to a zero-terminated string that uniquely represents the name of the service. For example, "MY SNA SERVER".

lpServiceType

Points to a variable to receive a globally unique identifier (GUID) that specifies the type of the network service. The header file SVCGUID.H includes definitions of several GUID service types and macros for working with them.

Return Value

If the function succeeds, the return value is zero.

If the function fails, the return value is SOCKET_ERROR( − 1). To get extended error information, call GetLastError. GetLastError may return the following extended error value:

Value	Meaning
ERROR_SERVICE_DOES_NOT_EXIST	The specified service type is unknown.
See Also

GetNameByType


GetUpdateRect
GetUpdateRect  QuickInfo  Overview  Group

The GetUpdateRect function retrieves the coordinates of the smallest rectangle that completely encloses the update region of the specified window. If the window was created with the CS_OWNDC style and the mapping mode is not MM_TEXT, GetUpdateRect retrieves the rectangle in logical coordinates. Otherwise, it retrieves the rectangle in client coordinates. If there is no update region, GetUpdateRect retrieves an empty rectangle (sets all coordinates to zero).

BOOL GetUpdateRect(

HWND  hWnd,	// handle of window
LPRECT  lpRect,	// address of update rectangle coordinates
BOOL  bErase	// erase flag
);
Parameters

hWnd

Identifies the window with an update region that is to be retrieved.

lpRect

Points to the RECT structure that receives the coordinates of the enclosing rectangle.

An application can set this parameter to NULL to determine whether an update region exists for the window. If this parameter is NULL, GetUpdateRect returns nonzero if an update region exists, and zero if one does not. This provides a simple and efficient means of determining whether a WM_PAINT message resulted from an invalid area.

bErase

Specifies whether the background in the update region is to be erased. If this parameter is TRUE and the update region is not empty, GetUpdateRect sends a WM_ERASEBKGND message to the specified window to erase the background.

Return Value

If the update region is not empty, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

The update rectangle retrieved by the BeginPaint function is identical to that retrieved by GetUpdateRect.

BeginPaint automatically validates the update region, so any call to GetUpdateRect made immediately after the call to BeginPaint retrieves an empty update region.

See Also

BeginPaint, GetUpdateRgn, InvalidateRect, RECT, UpdateWindow, ValidateRect


GetUpdateRgn
GetUpdateRgn  QuickInfo  Overview  Group

The GetUpdateRgn function retrieves the update region of a window by copying it into the specified region. The coordinates of the update region are relative to the upper-left corner of the window (that is, they are client coordinates).

int GetUpdateRgn(

HWND  hWnd,	// handle of window
HRGN  hRgn,	// handle of region
BOOL  bErase	// erase background flag
);
Parameters

hWnd

Identifies the window with an update region that is to be retrieved.

hRgn

Identifies the region to receive the update region.

bErase

Specifies whether the window background should be erased and whether nonclient areas of child windows should be drawn. If this parameter is FALSE, no drawing is done.

Return Value

The return value indicates the complexity of the resulting region; it can be one of the following values:

Value	Meaning
COMPLEXREGION	Region consists of more than one rectangle.
ERROR	An error occurred.
NULLREGION	Region is empty.
SIMPLEREGION	Region is a single rectangle.
Remarks

The BeginPaint function automatically validates the update region, so any call to GetUpdateRgn made immediately after the call to BeginPaint retrieves an empty update region.

See Also

GetUpdateRect, InvalidateRgn, UpdateWindow, ValidateRgn


GetUserDefaultLangID
GetUserDefaultLangID  QuickInfo  Overview  Group

The GetUserDefaultLangID function retrieves the user default language identifier.

LANGID GetUserDefaultLangID(VOID)

Parameters

This function has no parameters.

Return Value

If the function succeeds, the return value is the user default language identifier.

See Also

GetSystemDefaultLangID, MAKELANGID


GetUserDefaultLCID
GetUserDefaultLCID  QuickInfo  Overview  Group

The GetUserDefaultLCID function retrieves the user default locale identifier.

LCID GetUserDefaultLCID(VOID)

Parameters

This function has no parameters.

Return Value

If the function succeeds, the return value is the user default locale identifier.

Remarks

For more information about locale identifiers, see Locale Identifiers.

See Also

GetLocaleInfo, GetSystemDefaultLCID, MAKELCID


GetUserName
GetUserName  QuickInfo  Overview  Group

The GetUserName function retrieves the user name of the current thread. This is the name of the user currently logged onto the system.

BOOL GetUserName(

LPTSTR  lpBuffer,	// address of name buffer
LPDWORD  nSize	// address of size of name buffer
);
Parameters

lpBuffer

Points to the buffer to receive the null-terminated string containing the user's logon name. If this buffer is not large enough to contain the entire user name, the function fails.

nSize

Pointer to a DWORD that, on input, specifies the maximum size, in characters, of the buffer specified by the lpBuffer parameter. If this buffer is not large enough to contain the entire user name, the function fails. If the function succeeds, it will place the number of characters copied to the buffer into the DWORD that nSize points to.

Return Value

If the function succeeds, the return value is TRUE, and the variable pointed to by nSize contains the number of characters copied to the buffer specified by lpBuffer, including the terminating null character.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

If the current thread is impersonating another client, the GetUserName function returns the user name of the client that the thread is impersonating.

See Also

LookupAccountName


GetUserObjectInformation [New - Windows NT]
GetUserObjectInformation  QuickInfo  Overview  Group

[New - Windows NT]

The GetUserObjectInformation function returns information about a window station or desktop object.

BOOL GetUserObjectInformation(

HANDLE hObj	// handle of object to get information for
int nIndex	// type of information to get
PVOID pvInfo	// points to buffer that receives the information
DWORD nLength	// size, in bytes, of pvInfo buffer
LPDWORD lpnLengthNeeded	// receives required size, in bytes, of pvInfo buffer
);
Parameters

hObj

Identifies the window station or desktop object for which to return information. This can be an HDESK or HWINSTA handle (for example, a handle returned by CreateWindowStation, OpenWindowStation, CreateDesktop, or OpenDesktop).

nIndex

Specifies the object information to be retrieved. The parameter must be one of the following values:

Value	Description
UOI_FLAGS	Returns handle flags. The pvInfo parameter must point to a USEROBJECTFLAGS structure.
UOI_NAME	Returns a string containing the name of the object.
UOI_TYPE	Returns a string containing the type name of the object.
pvInfo

Points to a buffer to receive the object information.

nLength

Specifies the size, in bytes, of the buffer pointed to by the pvInfo parameter.

lpnLengthNeeded

Points to a variable receiving the number of bytes required to store the requested information. If this variable's value is greater than the value of the nLength parameter when the function returns, the function returns FALSE, and none of the information is copied to the pvInfo buffer. If the value of the variable pointed to by lpnLengthNeeded is less than or equal to the value of nLength, the entire information block is copied.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

CreateDesktop, CreateWindowStation, GetUserObjectSecurity, OpenDesktop, OpenWindowStation, SetUserObjectInformation, SetUserObjectSecurity, USEROBJECTFLAGS


GetUserObjectSecurity
GetUserObjectSecurity  QuickInfo  Overview  Group

The GetUserObjectSecurity function retrieves security information for the specified user object.

BOOL GetUserObjectSecurity(

HANDLE  hObj,	// handle of user object
PSECURITY_INFORMATION  pSIRequested,	// address of requested security information
PSECURITY_DESCRIPTOR  pSID,	// address of security descriptor
DWORD  nLength,	// size of buffer for security descriptor
LPDWORD  lpnLengthNeeded	// address of required size of buffer
);
Parameters

hObj

Identifies the user object for which to return security information.

pSIRequested

Points to a SECURITY_INFORMATION structure specifying the security information being requested.

pSID

Points to a SECURITY_DESCRIPTOR structure in self-relative format that contains the requested information when the function returns.

nLength

Specifies the length, in bytes, of the buffer pointed to by the pSID parameter.

lpnLengthNeeded

Points to a variable receiving the number of bytes required to store the complete security descriptor. If this variable's value is greater than the value of the nLength parameter when the function returns, the function returns FALSE and none of the security descriptor is copied to the buffer. Otherwise, the entire security descriptor is copied.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

CreatePrivateObjectSecurity, GetKernelObjectSecurity, GetPrivateObjectSecurity, SECURITY_DESCRIPTOR, SECURITY_INFORMATION, SetUserObjectSecurity


GetVersion
GetVersion  QuickInfo  Overview  Group

The GetVersion function returns the current version number of Windows and information about the operating system platform. This function has been superseded by GetVersionEx, which is the preferred method for obtaining system version number information. New applications should use GetVersionEx. The GetVersionEx function was developed because many existing Windows applications err when examining the DWORD return value of a GetVersion function call, transposing the major and minor version numbers packed into that DWORD. The GetVersionEx function forces applications to explicitly examine each element of version information, and allows for future enhancements to that information.

DWORD GetVersion(VOID)

Parameters

This function has no parameters.

Return Value

If the function succeeds, the return value is the major and minor version numbers of Windows and a code specifying the operating system platform. The low-order word contains the version number of Windows. The high-order byte specifies the minor version (revision) number, in hexadecimal notation. The low-order byte specifies the major version number, in hexadecimal notation.

The high-order word contains the information about the operating system platform. The high bit specifies the platform, as follows:

Value	Platform
0	Microsoft Windows NT
1	Microsoft Win32s with Windows 3.1
The remaining bits in the high word are reserved.

Remarks

This function does not return the current version number of MS-DOS.

See Also

GetVersionEx


GetVersionEx
GetVersionEx  QuickInfo  Overview  Group

The GetVersionEx function obtains extended information about the version of the operating system that is currently running.

BOOL GetVersionEx(

LPOSVERSIONINFO  lpVersionInformation	// points to version information structure
);
Parameters

lpVersionInformation

Points to an OSVERSIONINFO data structure that the function fills with operating system version information.

Before calling the GetVersionEx function, set the dwOSVersionInfoSize member of the OSVERSIONINFO data structure to sizeof(OSVERSIONINFO).

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

The function fails if the value of the dwOSVersionInfoSize member of the passed OSVERSIONINFO structure is too small. A value that is too small indicates that the data structure is not large enough to contain the current version information.

Remarks

The GetVersionEx function supersedes the GetVersion function and is the preferred method for obtaining operating system version number information. New applications should use the GetVersionEx function rather than the GetVersion function.

See Also

OSVERSIONINFO


GetViewportExt

The GetViewportExt function is not implemented in the Win32 API. This function is included for compatibility with 16-bit versions of Windows. Win32-based applications should use the GetViewportExtEx function.


GetViewportExtEx
GetViewportExtEx  QuickInfo  Overview  Group

The GetViewportExtEx function retrieves the x-extents and y-extents of the current viewport for the specified device context.

BOOL GetViewportExtEx(

HDC  hdc,	// handle of device context
LPSIZE  lpSize	// address of structure receiving viewport dimensions
);
Parameters

hdc

Identifies the device context.

lpSize

Points to a SIZE structure. The x- and y-extents, in device units, are placed in this structure.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

See Also

GetWindowExtEx, SetViewportExtEx, SetWindowExtEx


GetViewportOrg

The GetViewportOrg function has is not implemented in the Win32 API. This function is included for compatability with 16-bit versions of Windows. Win32-based applications should use the GetViewportOrgEx function.


GetViewportOrgEx
GetViewportOrgEx  QuickInfo  Overview  Group

The GetViewportOrgEx function retrieves the x-coordinates and y-coordinates of the viewport origin for the specified device context.

BOOL GetViewportOrgEx(

HDC  hdc,	// handle of device context
LPPOINT  lpPoint	// address of structure receiving the viewport origin
);
Parameters

hdc

Identifies the device context.

lpPoint

Points to a POINT structure that receives the origin coordinates.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

See Also

GetWindowOrgEx, POINT, SetViewportOrgEx, SetWindowOrgEx


GetVolumeInformation
GetVolumeInformation  QuickInfo  Overview  Group

The GetVolumeInformation function returns information about a file system and volume whose root directory is specified.

BOOL GetVolumeInformation(

LPCTSTR  lpRootPathName,	// address of root directory of the file system
LPTSTR  lpVolumeNameBuffer,	// address of name of the volume
DWORD  nVolumeNameSize,	// length of lpVolumeNameBuffer
LPDWORD  lpVolumeSerialNumber,	// address of volume serial number
LPDWORD  lpMaximumComponentLength,	// address of system's maximum filename length
LPDWORD  lpFileSystemFlags,	// address of file system flags
LPTSTR  lpFileSystemNameBuffer,	// address of name of file system
DWORD  nFileSystemNameSize	// length of lpFileSystemNameBuffer
);
Parameters

lpRootPathName

Points to a string that contains the root directory of the volume to be described. If this parameter is NULL, the root of the current directory is used.

lpVolumeNameBuffer

Points to a buffer that receives the name of the specified volume.

nVolumeNameSize

Specifies the length, in characters, of the volume name buffer. This parameter is ignored if the volume name buffer is not supplied.

lpVolumeSerialNumber

Points to a variable that receives the volume serial number. This parameter can be NULL if the serial number is not required.

lpMaximumComponentLength

Points to a doubleword value that receives the maximum length, in characters, of a filename component supported by the specified file system. A filename component is that portion of a filename between backslashes.

The value stored in variable pointed to by *lpMaximumComponentLength is used to indicate that long names are supported by the specified file system. For example, for a FAT file system supporting long names, the function stores the value 255, rather than the previous 8.3 indicator. Long names can also be supported on systems that use the NTFS and HPFS file systems.

lpFileSystemFlags

Points to a doubleword that receives flags associated with the specified file system. This parameter can be any combination of the following flags, with one exception: FS_FILE_COMPRESSION and FS_VOL_IS_COMPRESSED are mutually exclusive.

Value	Meaning
FS_CASE_IS_PRESERVED	If this flag is set, the file system preserves the case of filenames when it places a name on disk.
FS_CASE_SENSITIVE	If this flag is set, the file system supports case-sensitive filenames.
FS_UNICODE_STORED_ON_DISK	If this flag is set, the file system supports Unicode in filenames as they appear on disk.
FS_PERSISTENT_ACLS	If this flag is set, the file system preserves and enforces ACLs. For example, NTFS preserves and enforces ACLs, HPFS and FAT do not.
FS_FILE_COMPRESSION	The file system supports file-based compression.
FS_VOL_IS_COMPRESSED	The specified volume is a compressed volume; for example, a DoubleSpace volume.
lpFileSystemNameBuffer

Points to a buffer that receives the name of the file system (such as FAT, HPFS, or NTFS).

nFileSystemNameSize

Specifies the length, in characters, of the file system name buffer. This parameter is ignored if the file system name buffer is not supplied.

Return Value

If all the requested information is retrieved, the return value is TRUE; otherwise, it is FALSE. To get extended error information, call GetLastError.

Remarks

The FS_VOL_IS_COMPRESSED flag is the only indicator of volume-based compression. The file system name is not altered to indicate compression. This flag comes back set on a DoubleSpace volume, for example. With volume-based compression, an entire volume is either compressed or not compressed.

The FS_FILE_COMPRESSION flag indicates whether a file system supports file-based compression. With file-based compression, individual files can be compressed or not compressed.

The FS_FILE_COMPRESSION and FS_VOL_IS_COMPRESSED flags are mutually exclusive; both bits cannot come back set.

The maximum component length value, stored in the DWORD variable pointed to by lpMaximumComponentLength, is the only indicator that a volume supports longer-than-normal FAT (or other file system) file names. The file system name is not altered to indicate support for long file names.

The GetCompressedFileSize function obtains the compressed size of a file. The GetFileAttributes function can determine whether an individual file is compressed.

See Also

GetCompressedFileSize, GetFileAttributes, SetVolumeLabel


GetWindow
GetWindow  QuickInfo  Overview  Group

The GetWindow function retrieves the handle of a window that has the specified relationship to the specified window.

HWND GetWindow(

HWND  hWnd,	// handle of original window
UINT  uCmd	// relationship flag
);
Parameters

hWnd

Identifies a window. The window handle retrieved is relative to this window, based on the value of the uCmd parameter.

uCmd

Specifies the relationship between the specified window and the window whose handle is to be retrieved. This parameter can be one of the following values:

Value	Meaning
GW_CHILD	The retrieved handle identifies the child window at the top of the Z order, if the specified window is a parent window; otherwise, the retrieved handle is NULL. The function examines only child windows of the specified window. It does not examine descendant windows.
GW_HWNDFIRST	The retrieved handle identifies the window at the top of the Z order. If the specified window is a topmost window, the handle identifies the topmost window at the top of the Z order. If the specified window is a top-level window, the handle identifies the top-level window at the top of the Z order. If the specified window is a child window, the handle identifies the sibling window at the top of the Z order.
GW_HWNDLAST	The retrieved handle identifies the window at the bottom of the Z order. If the specified window is a topmost window, the handle identifies the topmost window at the bottom of the Z order. If the specified window is a top-level window, the handle identifies the top-level window at the bottom of the Z order. If the specified window is a child window, the handle identifies the sibling window at the bottom of the Z order.
GW_HWNDNEXT	The retrieved handle identifies the window below the specified window in the Z order. If the specified window is a topmost window, the handle identifies the topmost window below the specified window. If the specified window is a top-level window, the handle identifies the top-level window below the specified window. If the specified window is a child window, the handle identifies the sibling window below the specified window.
GW_HWNDPREV	The retrieved handle identifies the window above the specified window in the Z order. If the specified window is a topmost window, the handle identifies the topmost window above the specified window. If the specified window is a top-level window, the handle identifies the top-level window above the specified window. If the specified window is a child window, the handle identifies the sibling window above the specified window.
GW_OWNER	The retrieved handle identifies the specified window's owner window, if any.
Return Value

If the function succeeds, the return value is a window handle. If no window exists with the specified relationship to the specified window, the return value is NULL. To get extended error information, call GetLastError.

See Also

GetActiveWindow, GetNextWindow, GetTopWindow


GetWindowContextHelpId [New - Windows NT]
GetWindowContextHelpId  QuickInfo  Overview  Group

[New - Windows NT]

The GetWindowContextHelpId function retrieves the help context identifier, if any, associated with the specified window.

DWORD GetWindowContextHelpId(

HWND  hwnd
);
Parameters

hwnd

Handle to the window for which the help context identifier is to be retrieved.

Return Value

Returns the help context identifier if the window has one or zero otherwise.


GetWindowDC
GetWindowDC  QuickInfo  Overview  Group

The GetWindowDC function retrieves the device context (DC) for the entire window, including title bar, menus, and scroll bars. A window device context permits painting anywhere in a window, because the origin of the device context is the upper-left corner of the window instead of the client area.

GetWindowDC assigns default attributes to the window device context each time it retrieves the device context. Previous attributes are lost.

HDC GetWindowDC(

HWND  hWnd	// handle of window
);
Parameters

hWnd

Identifies the window with a device context that is to be retrieved.

Return Value

If the function succeeds, the return value is the handle of a device context for the specified window.

If the function fails, the return value is NULL, indicating an error or an invalid hWnd parameter.

Remarks

GetWindowDC is intended for special painting effects within a window's nonclient area. Painting in nonclient areas of any window is not recommended.

The GetSystemMetrics function can be used to retrieve the dimensions of various parts of the nonclient area, such as the title bar, menu, and scroll bars.

After painting is complete, the ReleaseDC function must be called to release the device context. Not releasing the window device context has serious effects on painting requested by applications.

See Also

BeginPaint, GetDC, GetSystemMetrics, ReleaseDC


GetWindowExt

The GetWindowExt function is not implemented in the Win32 API. This function is included for compatability with 16-bit versions of Windows. Win32-based applications should use the GetWindowExtEx function.


GetWindowExtEx
GetWindowExtEx  QuickInfo  Overview  Group

This function retrieves the x-extents and y-extents of the window for the specified device context.

BOOL GetWindowExtEx(

HDC  hdc,	// handle of device context
LPSIZE  lpSize	// address of structure receiving window extents
);
Parameters

hdc

Identifies the device context.

lpSize

Points to a SIZE structure. The x- and y-extents in page-space units are placed in this structure.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

See Also

GetViewportExtEx, SetViewportExtEx, SetWindowExtEx


GetWindowLong
GetWindowLong  QuickInfo  Overview  Group

The GetWindowLong function retrieves information about the specified window. The function also retrieves the 32-bit (long) value at the specified offset into the extra window memory of a window.

LONG GetWindowLong(

HWND  hWnd,	// handle of window
int  nIndex	// offset of value to retrieve
);
Parameters

hWnd

Identifies the window and, indirectly, the class to which the window belongs.

nIndex

Specifies the zero-based offset to the value to be retrieved. Valid values are in the range zero through the number of bytes of extra window memory, minus four; for example, if you specified 12 or more bytes of extra memory, a value of 8 would be an index to the third 32-bit integer. To retrieve any other value, specify one of the following values:

Value	Action
GWL_EXSTYLE	Retrieves the extended window styles.
GWL_STYLE	Retrieves the window styles.
GWL_WNDPROC	Retrieves the address of the window procedure, or a handle representing the address of the window procedure. You must use the CallWindowProc function to call the window procedure.
GWL_HINSTANCE	Retrieves the handle of the application instance.
GWL_HWNDPARENT	Retrieves the handle of the parent window, if any.
GWL_ID	Retrieves the identifier of the window.
GWL_USERDATA	Retrieves the 32-bit value associated with the window. Each window has a corresponding 32-bit value intended for use by the application that created the window.
The following values are also available when the hWnd parameter identifies a dialog box:

Value	Action
DWL_DLGPROC	Retrieves the address of the dialog box procedure, or a handle representing the address of the dialog box procedure. You must use the CallWindowProc function to call the dialog box procedure.
DWL_MSGRESULT	Retrieves the return value of a message processed in the dialog box procedure.
DWL_USER	Retrieves extra information private to the application, such as handles or pointers.
Return Value

If the function succeeds, the return value is the requested 32-bit value.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

Reserve extra window memory by specifying a nonzero value in the cbWndExtra member of the WNDCLASS structure used with the RegisterClass function.

See Also

CallWindowProc, GetWindowWord, RegisterClass, SetParent, SetWindowLong, SetWindowWord, WNDCLASS


GetWindowOrg

The GetWindowOrg function is not implemented in the Win32 API. This function is included for compatability with 16-bit versions of Windows. Win32-based applications should use the GetWindowOrgEx function.


GetWindowOrgEx
GetWindowOrgEx  QuickInfo  Overview  Group

The GetWindowOrgEx function retrieves the x-coordinates and y-coordinates of the window origin for the specified device context.

BOOL GetWindowOrgEx(

HDC  hdc,	// handle of device context
LPPOINT  lpPoint	// address of structure receiving the window origin
);
Parameters

hdc

Identifies the device context.

lpPoint

Points to a POINT structure that receives the coordinates, in page units, of the window origin.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

See Also

GetViewportOrgEx, SetViewportOrgEx, SetWindowOrgEx


GetWindowPlacement
GetWindowPlacement  QuickInfo  Overview  Group

The GetWindowPlacement function retrieves the show state and the restored, minimized, and maximized positions of the specified window.

BOOL GetWindowPlacement(

HWND  hWnd,	// handle of window
WINDOWPLACEMENT *  lpwndpl	// address of structure for position data
);
Parameters

hWnd

Identifies the window.

lpwndpl

Points to the WINDOWPLACEMENT structure that receives the show state and position information.

Before calling GetWindowPlacement, set the length member of the WINDOWPLACEMENT structure to sizeof(WINDOWPLACEMENT).

Windows 95 only: GetWindowPlacement fails if lpwndpl->length is not set correctly.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The flags member of WINDOWPLACEMENT retrieved by this function is always zero. If the window identified by the hWnd parameter is maximized, the showCmd member is SW_SHOWMAXIMIZED. If the window is minimized, showCmd is SW_SHOWMINIMIZED. Otherwise, it is SW_SHOWNORMAL.

See Also

SetWindowPlacement, WINDOWPLACEMENT


GetWindowRect
GetWindowRect  QuickInfo  Overview  Group

The GetWindowRect function retrieves the dimensions of the bounding rectangle of the specified window. The dimensions are given in screen coordinates that are relative to the upper-left corner of the screen.

BOOL GetWindowRect(

HWND  hWnd,	// handle of window
LPRECT  lpRect	// address of structure for window coordinates
);
Parameters

hWnd

Identifies the window.

lpRect

Points to a RECT structure that receives the screen coordinates of the upper-left and lower-right corners of the window.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

GetClientRect, RECT


GetWindowRgn [New - Windows NT]
GetWindowRgn  QuickInfo

[New - Windows NT]

The GetWindowRgn function obtains a copy of the window region of a window. The window region of a window is set by calling the SetWindowRgn function. The window region determines the area within the window where the operating system permits drawing. The operating system does not display any portion of a window that lies outside of the window region

int GetWindowRgn(

HWND  hWnd,	// handle to window whose window region is to be obtained
HRGN  hRgn	// handle to region that receives a copy of the window region
);
Parameters

hWnd

Handle to the window whose window region is to be obtained.

hrgn

Handle to a region. This region receives a copy of the window region.

Return Value

The return value specifies the type of the region that the function obtains. It can be one of the following values:

Value	Meaning
NULLREGION	The region is empty.
SIMPLEREGION	The region is a single rectangle.
COMPLEXREGION	The region is more than one rectangle.
ERROR	An error occurred; the region is unaffected.
Comments

The coordinates of a window's window region are relative to the upper-left corner of the window, not the client area of the window.

To set the window region of a window, call the SetWindowRgn function.

See Also

SetWindowRgn


GetWindowsDir

The GetWindowsDir function is not implemented in the Win32 API. This function is included for compatability with 16-bit versions of Windows. Win32-based applications should use the GetWindowsDirectory function to determine the Windows directory.


GetWindowsDirectory
GetWindowsDirectory  QuickInfo  Overview  Group

The GetWindowsDirectory function retrieves the path of the Windows directory. The Windows directory contains such files as Windows-based applications, initialization files, and Help files.

UINT GetWindowsDirectory(

LPTSTR  lpBuffer,	// address of buffer for Windows directory
UINT  uSize	// size of directory buffer
);
Parameters

lpBuffer

Points to the buffer to receive the null-terminated string containing the path. This path does not end with a backslash unless the Windows directory is the root directory. For example, if the Windows directory is named WINDOWS on drive C, the path of the Windows directory retrieved by this function is C:\WINDOWS. If Windows was installed in the root directory of drive C, the path retrieved is C:\.

uSize

Specifies the maximum size, in characters, of the buffer specified by the lpBuffer parameter. This value should be set to at least MAX_PATH to allow sufficient room in the buffer for the path.

Return Value

If the function succeeds, the return value is the length, in characters, of the string copied to the buffer, not including the terminating null character.

If the length is greater than the size of the buffer, the return value is the size of the buffer required to hold the path.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

The Windows directory is the directory where an application should store initialization and help files. If the user is running a shared version of Windows, the Windows directory is guaranteed to be private for each user.

If an application creates other files that it wants to store on a per-user basis, it should place them in the directory specified by the HOMEPATH environment variable. This directory will be different for each user, if so specified by an administrator, via the User Manager administrative tool. HOMEPATH always specifies either the user's home directory, which is guaranteed to be private for each user, or a default directory (for example, C:\USERS\DEFAULT) where the user will have all access.

See Also

GetCurrentDirectory, GetSystemDirectory


GetWindowTask
GetWindowTask  QuickInfo  Overview  Group

The GetWindowTask function is not implemented in the WIn32 API.

To maintain compatibility with 16-bit applications, GetWindowTask has been replaced with a macro that calls GetWindowThreadProcessId. Earlier applications can continue to call GetWindowTask as previously documented, but new applications should use GetWindowThreadProcessId.

Remarks

GetWindowTask is defined as returning a value with a HANDLE data type. GetWindowThreadProcessId returns a value with a DWORD data type. The macro that maps GetWindowTask to GetWindowThreadProcessId includes a cast to HANDLE, as follows:

#define GetWindowTask(hwnd) \\

    ((HANDLE) GetWindowThreadProcessId(hwnd, NULL))

See Also

GetWindowThreadProcessId


GetWindowText
GetWindowText  QuickInfo  Overview  Group

The GetWindowText function copies the text of the specified window's title bar (if it has one) into a buffer. If the specified window is a control, the text of the control is copied.

int GetWindowText(

HWND  hWnd,	// handle of window or control with text
LPTSTR  lpString,	// address of buffer for text
int  nMaxCount	// maximum number of characters to copy
);
Parameters

hWnd

Identifies the window or control containing the text.

lpString

Points to the buffer that will receive the text.

nMaxCount

Specifies the maximum number of characters to copy to the buffer. If the text exceeds this limit, it is truncated.

Return Value

If the function succeeds, the return value is the length, in characters, of the copied string, not including the terminating null character. If the window has no title bar or text, if the title bar is empty, or if the window or control handle is invalid, the return value is zero. To get extended error information, call GetLastError.

This function cannot retrieve the text of an edit control in another application.

Remarks

This function causes a WM_GETTEXT message to be sent to the specified window or control.

This function cannot retrieve the text of an edit control in another application.

See Also

GetWindowTextLength, SetWindowText, WM_GETTEXT


GetWindowTextLength
GetWindowTextLength  QuickInfo  Overview  Group

The GetWindowTextLength function retrieves the length, in characters, of the specified window's title bar text (if the window has a title bar). If the specified window is a control, the function retrieves the length of the text within the control.

int GetWindowTextLength(

HWND  hWnd	// handle of window or control with text
);
Parameters

hWnd

Identifies the window or control.

Return Value

If the function succeeds, the return value is the length, in characters, of the text. Under certain conditions, this value may actually be greater than the length of the text. For more information, see the following Remarks section.

If the window has no text, the return value is zero. To get extended error information, call GetLastError.

Remarks

This function causes a WM_GETTEXTLENGTH message to be sent to the specified window or control.

Under certain conditions, the GetWindowTextLength function may return a value that is larger than the actual length of the text. This occurs with certain mixtures of ANSI and Unicode, and is due to the operating system allowing for the possible existence of DBCS characters within the text. The return value, however, will always be at least as large as the actual length of the text; you can thus always use it to guide buffer allocation. This behavior can occur when an application uses both ANSI functions and common dialogs, which use Unicode. It can also occur when an application uses the ANSI flavor of GetWindowTextLength with a window whose window procedure is Unicode, or the Unicode flavor with a window whose window procedure is ANSI.

To obtain the exact length of the text, use the WM_GETTEXT, LB_GETTEXT, or CB_GETLBTEXT messages, or the GetWindowText function

See Also

CB_GETLBTEXT, GetWindowText, LB_GETTEXT, SetWindowText, WM_GETTEXT, WM_GETTEXTLENGTH


GetWindowThreadProcessId
GetWindowThreadProcessId  QuickInfo  Overview  Group

The GetWindowThreadProcessId function retrieves the identifier of the thread that created the specified window and, optionally, the identifier of the process that created the window. This function supersedes the GetWindowTask function.

DWORD GetWindowThreadProcessId(

HWND  hWnd,	// handle of window
LPDWORD  lpdwProcessId	// address of variable for process identifier
);
Parameters

hWnd

Identifies the window.

lpdwProcessId

Points to a 32-bit value that receives the process identifier. If this parameter is not NULL, GetWindowThreadProcessId copies the identifier of the process to the 32-bit value; otherwise, it does not.

Return Value

The return value is the identifier of the thread that created the window.

Remarks

This function replaces the GetWindowTask function of Windows version 3.x.


GetWindowWord
GetWindowWord  QuickInfo  Overview  Group

The GetWindowWord function retrieves a 16-bit (word) value at the specified offset into the extra window memory for the specified window.

WORD GetWindowWord(

HWND  hWnd,	// handle of window
int  nIndex	// offset of value to retrieve
);
Parameters

hWnd

Identifies the window and, indirectly, the class to which the window belongs.

nIndex

Specifies the zero-based byte offset of the value to be retrieved. Valid values are in the range zero through the number of bytes of extra window memory, minus two; for example, if you specified 10 or more bytes of extra window memory, a value of 8 would be an index to the fifth 16-bit integer.

Return Value

If the function succeeds, the return value is the requested 16-bit value.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

Reserve extra window memory by specifying a nonzero value in the cbWndExtra member of the WNDCLASS structure used with the RegisterClass function.

The GWW_ values are obsolete in Win32. You must use the GetWindowLong function to retrieve information about the window.

See Also

GetParent, GetWindowLong, RegisterClass, SetParent, SetWindowLong, SetWindowWord, WNDCLASS


GetWinFlags
GetWinFlags  Overview  Group

The GetWinFlags function is not implemented in the Win32 API. Win32-based applications should use the GetSystemInfo function.


GetWinMetaFileBits
GetWinMetaFileBits  QuickInfo  Overview  Group

The GetWinMetaFileBits function converts the enhanced-format records from a metafile into Windows-format records and stores the converted records in the specified buffer.

UINT GetWinMetaFileBits(

HENHMETAFILE  hemf,	// handle to the enhanced metafile
UINT  cbBuffer,	// buffer size
LPBYTE  lpbBuffer,	// pointer to buffer
INT  fnMapMode,	// mapping mode
HDC  hdcRef	// handle of reference device context
);
Parameters

hemf

Identifies the enhanced metafile.

cbBuffer

Specifies the size, in bytes, of the buffer into which the converted records are to be copied.

lpbBuffer

Points to the buffer into which the converted records are to be copied. If lpbBuffer is NULL, GetWinMetaFileBits returns the the number of bytes required to store the converted metafile records.

fnMapMode

Specifies the mapping mode to use in the converted metafile.

hdcRef

Identifies the reference device context.

Return Value

If the function succeeds and the buffer pointer is NULL, the return value is the number of bytes required to store the converted records; if the function succeeds and the buffer pointer is a valid pointer, the return value is the size of the metafile data in bytes.

If the function fails, the return value is zero.

Remarks

This function converts an enhanced metafile into a Windows-format metafile so that its picture can be displayed in an application that recognizes the older format.

Windows uses the reference device context to determine the resolution of the converted metafile.

The GetWinMetaFileBits function does not invalidate the enhanced metafile handle. An application should call the DeleteEnhMetaFile function to release the handle when it is no longer needed.

Due to the limitations of the Windows-format metafile, some information can be lost in the retrieved metafile contents. For example, an original call to the PolyBezier function in the enhanced metafile may be converted into a call to the Polyline function in the Windows-format metafile, because there is no equivalent PolyBezier function in the Windows format.

Windows 3.x applications define the viewport origin and extents of a picture stored in a Windows-format metafile. As a result, the Windows-format records created by GetWinMetaFileBits do not contain the SetViewportOrg and SetViewportExt functions. However, GetWinMetaFileBits does create Windows-format records for the SetWindowExt and SetMapMode functions.

To create a scalable Windows-format metafile, specify MM_ANISOTROPIC as the fnMapMode parameter.

The upper-left corner of the metafile picture is always mapped to the origin of the reference device.

See Also

DeleteEnhMetaFile, PolyBezier, Polyline, SetMapMode, SetViewportOrg, SetViewportExt, SetWindowExt


GetWorldTransform
GetWorldTransform  QuickInfo  Overview  Group

The GetWorldTransform function retrieves the current world-space to page-space transformation.

BOOL GetWorldTransform(

HDC  hdc,	// handle to the device context
LPXFORM  lpXform	// pointer to the structure receiving transformation
);
Parameters

hdc

Identifies the device context.

lpXform

Points to an XFORM structure that receives the current world-space to page-space transformation.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

The precision of the transformation may be altered if an application calls the ModifyWorldTransform function prior to calling GetWorldTransform. (This is because the internal format for storing transformation values uses a higher precision than a FLOAT value.)

See Also

ModifyWorldTransform, SetWorldTransform


GlobalAddAtom
GlobalAddAtom  QuickInfo  Overview  Group

The GlobalAddAtom function adds a character string to the global atom table and returns a unique value (an atom) identifying the string.

ATOM GlobalAddAtom(

LPCTSTR  lpString	// pointer to the string to add
);
Parameters

lpString

Points to the null-terminated string to be added. The string can have a maximum size of 255 bytes. Strings that differ only in case are considered identical. The case of the first string of this name added to the table is preserved and returned by the GlobalGetAtomName function.

Return Value

If the function succeeds, the return value is the newly created atom.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

If the string already exists in the global atom table, the atom for the existing string is returned and the atom's reference count is incremented.

The string associated with the atom is not deleted from memory until its reference count is zero. For more information, see the GlobalDeleteAtom function.

Global atoms are not deleted automatically when the application terminates. For every call to the GlobalAddAtom function, there must be a corresponding call to the GlobalDeleteAtom function.

GlobalAddAtom returns a string atom whose value is in the range 0xC000 through 0xFFFF.

If the lpString parameter has the form "#1234", GlobalAddAtom returns an integer atom whose value is the 16-bit representation of the decimal number specified in the string (0x04D2, in this example). If the decimal value specified is 0x0000 or a value in the range 0xC000 through 0xFFFF, the return value is zero, indicating an error. If lpString is in the range 0x0001 through 0xBFFF, the return value is the low-order word of lpString.

The MAKEINTATOM macro can be used to convert a WORD value into a string that can be added to the atom table by using the GlobalAddAtom function.

See Also

AddAtom, DeleteAtom, FindAtom, GetAtomName, GlobalDeleteAtom, GlobalFindAtom, GlobalGetAtomName, MAKEINTATOM


GlobalAlloc
GlobalAlloc  QuickInfo  Overview  Group

The GlobalAlloc function allocates the specified number of bytes from the heap. In the linear Win32 API environment, there is no difference between the local heap and the global heap.

HGLOBAL GlobalAlloc(

UINT  uFlags,	// object allocation attributes
DWORD  dwBytes	// number of bytes to allocate
);
Parameters

uFlags

Specifies how to allocate memory. If zero is specified, the default is GMEM_FIXED. Except for the incompatible combinations that are specifically noted, any combination of the following flags can be used. To indicate whether the function allocates fixed or movable memory, specify one of the first four flags:

Flag	Meaning
GMEM_FIXED	Allocates fixed memory. This flag cannot be combined with the GMEM_MOVEABLE or GMEM_DISCARDABLE flag. The return value is a pointer to the memory block. To access the memory, the calling process simply casts the return value to a pointer.
GMEM_MOVEABLE	Allocates movable memory. This flag cannot be combined with the GMEM_FIXED flag. The return value is the handle of the memory object. The handle is a 32-bit quantity that is private to the calling process. To translate the handle into a pointer, use the GlobalLock function.
GPTR	Combines the GMEM_FIXED and GMEM_ZEROINIT flags.
GHND	Combines the GMEM_MOVEABLE and GMEM_ZEROINIT flags.
GMEM_DDESHARE	Allocates memory to be used by the dynamic data exchange (DDE) functions for a DDE conversation. Unlike Windows version 3. x, this memory is not shared globally. However, this flag is available for compatibility purposes. It may be used by some applications to enhance the performance of DDE operations and should, therefore, be specified if the memory is to be used for DDE.  Only processes that use DDE or the clipboard for interprocess communications should specify this flag.
GMEM_DISCARDABLE	Allocates discardable memory. This flag cannot be combined with the GMEM_FIXED flag. Some Win32-based applications may ignore this flag.
GMEM_LOWER	Ignored. This flag is provided only for compatibility with Windows version 3. x.
GMEM_NOCOMPACT	Does not compact or discard memory to satisfy the allocation request.
GMEM_NODISCARD	Does not discard memory to satisfy the allocation request.
GMEM_NOT_BANKED	Ignored. This flag is provided only for compatibility with Windows version 3. x.
GMEM_NOTIFY	Ignored. This flag is provided only for compatibility with Windows version 3. x.
GMEM_SHARE	Same as the GMEM_DDESHARE flag.
GMEM_ZEROINIT	Initializes memory contents to zero.
dwBytes

Specifies the number of bytes to allocate. If this parameter is zero and the uFlags parameter specifies the GMEM_MOVEABLE flag, the function returns a handle to a memory object that is marked as discarded.

Return Value

If the function succeeds, the return value is the handle of the newly allocated memory object.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

If the heap does not contain sufficient free space to satisfy the request, GlobalAlloc returns NULL.

Because NULL is used to indicate an error, virtual address zero is never allocated. It is, therefore, easy to detect the use of a NULL pointer.

All memory is created with execute access; no special function is required to execute dynamically generated code.

Memory allocated with this function is guaranteed to be aligned on an 8-byte boundary.

The GlobalAlloc and LocalAlloc functions are limited to a combined total of 65,536 handles for GMEM_MOVEABLE and LMEM_MOVEABLE memory per process. This limitation does not apply to GMEM_FIXED or LMEM_FIXED memory.

If this function succeeds, it allocates at least the amount of memory requested. If the actual amount allocated is greater than the amount requested, the process can use the entire amount. To determine the actual number of bytes allocated, use the GlobalSize function.

See Also

GlobalFree, GlobalLock, GlobalReAlloc, GlobalSize, LocalAlloc


GlobalCompact
GlobalCompact  QuickInfo  Overview  Group

The GlobalCompact function is obsolete. It has no meaning in the 32-bit environment.


GlobalDeleteAtom
GlobalDeleteAtom  QuickInfo  Overview  Group

The GlobalDeleteAtom function decrements the reference count of a global string atom. If the atom's reference count reaches zero, GlobalDeleteAtom removes the string associated with the atom from the global atom table.

ATOM GlobalDeleteAtom(

ATOM  nAtom	// atom to delete
);
Parameters

nAtom

Identifies the atom and character string to be deleted.

Return Value

If the function succeeds, the return value is zero.

If the function fails, the return value is the nAtom parameter. To get extended error information, call GetLastError.

Remarks

A string atom's reference count specifies the number of times the string has been added to or removed from the atom table. The GlobalAddAtom function increments the reference count of a string that already exists in the global atom table each time it is called.

The only way to ensure that an atom has been deleted from the atom table is to call this function repeatedly until it fails. When the reference count is decremented to zero, the next GlobalFindAtom or GlobalDeleteAtom function call fails.

GlobalDeleteAtom has no effect on an integer atom (an atom created by using the MAKEINTATOM macro). The function always returns zero for an integer atom.

See Also

AddAtom, DeleteAtom, FindAtom, GlobalAddAtom, GlobalFindAtom, MAKEINTATOM


GlobalDiscard
GlobalDiscard  QuickInfo  Overview  Group

The GlobalDiscard function discards the specified global memory block. The lock count of the memory object must be zero.

HGLOBAL GlobalDiscard(

HGLOBAL  hglbMem	// handle to the global memory object
);
Parameters

hglbMem

Identifies the global memory object. This handle is returned by either the GlobalAlloc or GlobalReAlloc function.

Return Value

If the function succeeds, the return value is the handle of the memory object.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

GlobalDiscard discards only global objects that the calling process allocated with the GMEM_DISCARDABLE flag. If a process attempts to discard a fixed or locked object, the function fails.

Although GlobalDiscard discards the object's memory block, the handle of the object remains valid. A process can subsequently pass the handle to the GlobalReAlloc function to allocate another global memory block identified by the same handle.

See Also

GlobalAlloc, GlobalReAlloc


GlobalDosAlloc
GlobalDosAlloc  Overview  Group

The GlobalDosAlloc function has been deleted. Win32-based applications should use the VirtualLock and VirtualUnlock functions.


GlobalDosFree
GlobalDosFree  Overview  Group

The GlobalDosFree function has been deleted. Win32-based applications should use the VirtualLock and VirtualUnlock functions.


GlobalFindAtom
GlobalFindAtom  QuickInfo  Overview  Group

The GlobalFindAtom function searches the global atom table for the specified character string and retrieves the global atom associated with that string.

ATOM GlobalFindAtom(

LPCTSTR  lpString	// pointer to the string to find
);
Parameters

lpString

Points to the null-terminated character string to search for.

Return Value

If the function succeeds, the return value is the global atom associated with the given string.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

Even though Windows preserves the case of a string in an atom table as it was originally entered, the search performed by GlobalFindAtom is not case sensitive.

See Also

AddAtom, DeleteAtom, FindAtom, GetAtomName, GlobalAddAtom, GlobalDeleteAtom, GlobalGetAtomName


GlobalFix
GlobalFix  Overview  Group

The GlobalFix function is obsolete. It has no meaning in the 32-bit environment. Win32-based applications should use the VirtualLock and VirtualUnlock functions.


GlobalFlags
GlobalFlags  QuickInfo  Overview  Group

The GlobalFlags function returns information about the specified global memory object.

UINT GlobalFlags(

HGLOBAL  hMem	// handle to the global memory object
);
Parameters

hMem

Identifies the global memory object. This handle is returned by either the GlobalAlloc or GlobalReAlloc function.

Return Value

If the function succeeds, the return value is a 32-bit value specifying the allocation flags and the lock count for the memory object.

If the function fails, the return value is the GMEM_INVALID_HANDLE flag, indicating that the global handle is not valid. To get extended error information, call GetLastError.

Remarks

The low-order byte of the low-order word of the return value contains the lock count of the object. To retrieve the lock count from the return value, use the GMEM_LOCKCOUNT mask with the bitwise AND (&) operator. The lock count of memory objects allocated with the GMEM_FIXED flag is always zero.

The high-order byte of the low-order word of the return value indicates the allocation flags of the memory object. It can be zero or any combination of the following flags:

Flag	Meaning
GMEM_DDESHARE	Memory was allocated for use by the dynamic data exchange (DDE) functions. Unlike Windows version  3. x, this memory is not shared globally. However, this flag is available for compatibility purposes and may be used by some applications to enhance the performance of DDE operations. Only processes that use DDE or the clipboard for interprocess communications should specify this flag.
GMEM_DISCARDABLE	The object's memory block can be discarded.
GMEM_DISCARDED	The object's memory block has been discarded.
See Also

GlobalAlloc, GlobalDiscard, GlobalLock, GlobalReAlloc, GlobalUnlock, LocalFlags


GlobalFree
GlobalFree  QuickInfo  Overview  Group

The GlobalFree function frees the specified global memory object and invalidates its handle.

HGLOBAL GlobalFree(

HGLOBAL  hMem	// handle to the global memory object
);
Parameters

hMem

Identifies the global memory object. This handle is returned by either the GlobalAlloc or GlobalReAlloc function.

Return Value

If the function succeeds, the return value is NULL.

If the function fails, the return value is equal to the handle of the global memory object. To get extended error information, call GetLastError.

Remarks

Heap corruption or an access violation exception (EXCEPTION_ACCESS_VIOLATION) may occur if the process tries to examine or modify the memory after it has been freed.

If the hgblMem parameter is NULL, GlobalFree fails and the system generates an access violation exception.

Both GlobalFree and LocalFree will free a locked memory object. A locked memory object has a lock count greater than zero. The GlobalLock function locks a global memory object and increments the lock count by one. The GlobalUnlock function unlocks it and decrements the lock count by one. To get the lock count of a global memory object, use the GlobalFlags function.

Windows NT: However, if an application is running under a debug (DBG) version of Windows NT, such as the one distributed on the SDK CD-ROM, both GlobalFree and LocalFree enter a breakpoint just before freeing a locked object. This lets a programmer double-check the intended behavior. Typing G while using the debugger in this situation lets the freeing operation occur.

See Also

GlobalAlloc, GlobalFlags, GlobalLock, GlobalReAlloc, GlobalUnlock, LocalFree


GlobalGetAtomName
GlobalGetAtomName  QuickInfo  Overview  Group

The GlobalGetAtomName function retrieves a copy of the character string associated with the specified global atom.

UINT GlobalGetAtomName(

ATOM  nAtom,	// atom identifier
LPTSTR  lpBuffer,	// pointer to the buffer for the atom string
int  nSize	// size of the buffer
);
Parameters

nAtom

Identifies the global atom associated with the character string to be retrieved.

lpBuffer

Points to the buffer for the character string.

nSize

Specifies the size, in characters, of the buffer.

Return Value

If the function succeeds, the return value is the length of the string copied to the buffer, in characters, not including the terminating null character.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

The string returned for an integer atom (an atom created by the MAKEINTATOM macro) is a null-terminated string in which the first character is a pound sign (#) and the remaining characters represent the unsigned integer originally passed to MAKEINTATOM.

See Also

AddAtom, DeleteAtom, FindAtom, GlobalAddAtom, GlobalDeleteAtom, GlobalFindAtom, MAKEINTATOM


GlobalHandle
GlobalHandle  QuickInfo  Overview  Group

The GlobalHandle function retrieves the handle associated with the specified pointer to a global memory block.

HGLOBAL GlobalHandle(

LPCVOID  pMem	// pointer to the global memory block
);
Parameters

pMem

Points to the first byte of the global memory block. This pointer is returned by the GlobalLock function.

Return Value

If the function succeeds, the return value is the handle of the specified global memory object.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

When the GlobalAlloc function allocates a memory object with the GMEM_MOVEABLE flag, it returns the handle of the object. The GlobalLock function converts this handle into a pointer to the memory block, and GlobalHandle converts the pointer back into a handle.

See Also

GlobalAlloc, GlobalLock


GlobalLock
GlobalLock  QuickInfo  Overview  Group

The GlobalLock function locks a global memory object and returns a pointer to the first byte of the object's memory block. The memory block associated with a locked memory object cannot be moved or discarded. For memory objects allocated with the GMEM_MOVEABLE flag, the function increments the lock count associated with the memory object.

LPVOID GlobalLock(

HGLOBAL  hMem	// address of the global memory object
);
Parameters

hMem

Identifies the global memory object. This handle is returned by either the GlobalAlloc or GlobalReAlloc function.

Return Value

If the function succeeds, the return value is a pointer to the first byte of the memory block.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

The internal data structures for each memory object include a lock count that is initially zero. For movable memory objects, GlobalLock increments the count by one, and the GlobalUnlock function decrements the count by one. For each call that a process makes to GlobalLock for an object, it must eventually call GlobalUnlock. Locked memory will not be moved or discarded, unless the memory object is reallocated by using the GlobalReAlloc function. The memory block of a locked memory object remains locked until its lock count is decremented to zero, at which time it can be moved or discarded.

Memory objects allocated with the GMEM_FIXED flag always have a lock count of zero. For these objects, the value of the returned pointer is equal to the value of the specified handle.

If the specified memory block has been discarded or if the memory block has a zero-byte size, this function returns NULL.

Discarded objects always have a lock count of zero.

See Also

GlobalAlloc, GlobalFlags, GlobalReAlloc, GlobalUnlock


GlobalLRUNewest
GlobalLRUNewest  QuickInfo  Overview  Group

The GlobalLRUNewest function is obsolete. It has no meaning in the 32-bit environment. Win32-based applications should use the VirtualLock and VirtualUnlock functions.


GlobalLRUOldest
GlobalLRUOldest  QuickInfo  Overview  Group

The GlobalLRUOldest function is obsolete. It has no meaning in the 32-bit environment. Win32-based applications should use the VirtualLock and VirtualUnlock functions.


GlobalMemoryStatus
GlobalMemoryStatus  QuickInfo  Overview  Group

The GlobalMemoryStatus function retrieves information about current available memory. The function returns information about both physical and virtual memory. This function supersedes the GetFreeSpace function.

VOID GlobalMemoryStatus(

LPMEMORYSTATUS  lpBuffer	// pointer to the memory status structure
);
Parameters

lpBuffer

Points to a MEMORYSTATUS structure in which information about current memory availability is returned. Before calling this function, the calling process should set the dwLength member of this structure.

Return Value

This function does not return a value.

Remarks

An application can use the GlobalMemoryStatus function to determine how much memory it can allocate without severely impacting other applications.

The information returned is volatile, and there is no guarantee that two sequential calls to this function will return the same information.

See Also

MEMORYSTATUS


GlobalNotify
GlobalNotify  Overview  Group

The GlobalNotify function is not implemented in the Win32 SDK. Win32-based applications should use the GlobalFlags function.


GlobalPageLock
GlobalPageLock  Overview  Group

The GlobalPageLock function is not implemented in the Win32 API. Win32-based applications should use the VirtualLock and VirtualUnlock functions.


GlobalPageUnlock
GlobalPageUnlock  Overview  Group

The GlobalPageUnlock function is not implemented in the Win32 API. Win32-based applications should use the VirtualLock and VirtualUnlock functions.


GlobalReAlloc
GlobalReAlloc  QuickInfo  Overview  Group

The GlobalReAlloc function changes the size or attributes of a specified global memory object. The size can increase or decrease.

HGLOBAL GlobalReAlloc(

HGLOBAL  hMem,	// handle to the global memory object
DWORD  dwBytes,	// new size of the block
UINT  uFlags	// how to reallocate object
);
Parameters

hMem

Identifies the global memory object to be reallocated. This handle is returned by either the GlobalAlloc or GlobalReAlloc function.

dwBytes

Specifies the new size, in bytes, of the memory block. If this parameter is zero and the uFlags parameter specifies the GMEM_MOVEABLE flag, the function returns the handle of a memory object that is marked as discarded. If uFlags specifies the GMEM_MODIFY flag, this parameter is ignored.

uFlags

Specifies how to reallocate the global memory object. If the GMEM_MODIFY flag is specified, this parameter modifies the attributes of the memory object, and the dwBytes parameter is ignored. Otherwise, this parameter controls the reallocation of the memory object.

The GMEM_MODIFY flag can be combined with either or both of the following flags:

Flag	Meaning
GMEM_DISCARDABLE	Allocates discardable memory if the GMEM_MODIFY flag is also specified. This flag is ignored, unless the object was previously allocated as movable or the GMEM_MOVEABLE flag is also specified.
GMEM_MOVEABLE	Windows NT only: Changes a fixed memory object to a movable memory object if the GMEM_MODIFY flag is also specified.
If this parameter does not specify GMEM_MODIFY, it can be any combination of the following flags:

Flag	Meaning
GMEM_MOVEABLE	If dwBytes is zero, discards a previously movable and discardable memory block. If the lock count of the object is not zero or if the block is not movable and discardable, the function fails.  If dwBytes is nonzero, enables the system to move the reallocated block to a new location without changing the movable or fixed attribute of the memory object. If the object is fixed, the handle returned may be different from the handle specified by the hMem parameter. If the object is movable, the block can be moved without invalidating the handle, even if the object is currently locked by a previous call to the GlobalLock function. To get the new address of the memory block, use GlobalLock.
GMEM_NOCOMPACT	Prevents memory from being compacted or discarded to satisfy the allocation request.
GMEM_ZEROINIT	Causes the additional memory contents to be initialized to zero if the memory object is growing in size.
Return Value

If the function succeeds, the return value is the handle of the reallocated memory object.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

If GlobalReAlloc reallocates a movable object, the return value is the handle of the memory object. To convert the handle to a pointer, use the GlobalLock function.

If GlobalReAlloc reallocates a fixed object, the value of the handle returned is the address of the first byte of the memory block. To access the memory, a process can simply cast the return value to a pointer.

If GlobalReAlloc fails, the original memory is not freed, and the original handle and pointer are still valid.

See Also

GlobalAlloc, GlobalFree, GlobalLock


GlobalSize
GlobalSize  QuickInfo  Overview  Group

The GlobalSize function retrieves the current size, in bytes, of the specified global memory object.

DWORD GlobalSize(

HGLOBAL  hMem	// handle to the global memory object
);
Parameters

hMem

Identifies the global memory object. This handle is returned by either the GlobalAlloc or GlobalReAlloc function.

Return Value

If the function succeeds, the return value is the size, in bytes, of the specified global memory object.

If the specified handle is not valid or if the object has been discarded, the return value is zero. To get extended error information, call GetLastError.

Remarks

The size of a memory block may be larger than the size requested when the memory was allocated.

To verify that the specified object's memory block has not been discarded, use the GlobalFlags function before calling GlobalSize.

See Also

GlobalAlloc, GlobalFlags, GlobalReAlloc


GlobalUnfix
GlobalUnfix  Overview  Group

The GlobalUnfix function is obsolete. It has no meaning in the 32-bit environment.


GlobalUnlock
GlobalUnlock  QuickInfo  Overview  Group

The GlobalUnlock function decrements the lock count associated with a memory object that was allocated with the GMEM_MOVEABLE flag. This function has no effect on memory objects allocated with the GMEM_FIXED flag.

BOOL GlobalUnlock(

HGLOBAL  hMem	// handle to the global memory object
);
Parameters

hMem

Identifies the global memory object. This handle is returned by either the GlobalAlloc or GlobalReAlloc function.

Return Value

If the memory object is still locked after decrementing the lock count, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError. If GetLastError returns NO_ERROR, the memory object is unlocked.

Remarks

The internal data structures for each memory object include a lock count that is initially zero. For movable memory objects, the GlobalLock function increments the count by one, and GlobalUnlock decrements the count by one. For each call that a process makes to GlobalLock for an object, it must eventually call GlobalUnlock. Locked memory will not be moved or discarded, unless the memory object is reallocated by using the GlobalReAlloc function. The memory block of a locked memory object remains locked until its lock count is decremented to zero, at which time it can be moved or discarded.

Memory objects allocated with the GMEM_FIXED flag always have a lock count of zero. If the specified memory block is fixed memory, this function returns TRUE.

If the memory object is already unlocked, GlobalUnlock returns FALSE and GetLastError reports ERROR_NOT_LOCKED. Memory objects allocated with the LMEM_FIXED flag always have a lock count of zero and cause the ERROR_NOT_LOCKED error.

A process should not rely on the return value to determine the number of times it must subsequently call GlobalUnlock for a memory object.

See Also

GlobalAlloc, GlobalFlags, GlobalLock, GlobalReAlloc


GlobalUnWire
GlobalUnWire  Overview  Group

The GlobalUnWire function is obsolete. Applications that need to lock a global memory object should use the GlobalLock and GlobalUnlock functions.

This function is provided only for compatibility with 16-bit versions of Windows. New Win32-based applications should not use this function.


GlobalWire
GlobalWire  Overview  Group

The GlobalWire function is obsolete. Win32-based applications should use the GlobalLock and GlobalUnlock functions.


GrayString
GrayString  QuickInfo  Overview  Group

The GrayString function draws gray text at the specified location. The function draws the text by copying it into a memory bitmap, graying the bitmap, and then copying the bitmap to the screen. The function grays the text regardless of the selected brush and background. GrayString uses the font currently selected for the specified device context.

If the lpOutputFunc parameter is NULL, GDI uses the TextOut function, and the lpData parameter is assumed to be a pointer to the character string to be output. If the characters to be output cannot be handled by TextOut (for example, the string is stored as a bitmap), the application must supply its own output function.

BOOL GrayString(

HDC  hDC,	// handle to the device context
HBRUSH  hBrush,	// handle to the brush for graying
GRAYSTRINGPROC  lpOutputFunc,	// pointer to the callback function
LPARAM  lpData,	// pointer to application-defined data
int  nCount,	// number of characters to output
int  X,	// horizontal position
int  Y,	// vertical position
int  nWidth,	// width
int  nHeight	// height
);
Parameters

hDC

Identifies the device context.

hBrush

Identifies the brush to be used for graying. If this parameter is NULL, the text is grayed with the same brush that was used to draw window text.

lpOutputFunc

Points to the application-defined function that will draw the string, or, if TextOut is to be used to draw the string, it is a NULL pointer. For details, see the OutputProc callback function.

lpData

Specifies a pointer to data to be passed to the output function. If the lpOutputFunc parameter is NULL, lpData must be a pointer to the string to be output.

nCount

Specifies the number of characters to be output. If the nCount parameter is zero, GrayString calculates the length of the string (assuming lpData is a pointer to the string). If nCount is −1 and the function pointed to by lpOutputFunc returns FALSE, the image is shown but not grayed.

X

Specifies the device x-coordinate of the starting position of the rectangle that encloses the string.

Y

Specifies the device y-coordinate of the starting position of the rectangle that encloses the string.

nWidth

Specifies the width, in device units, of the rectangle that encloses the string. If this parameter is zero, GrayString calculates the width of the area, assuming lpData is a pointer to the string.

nHeight

Specifies the height, in device units, of the rectangle that encloses the string. If this parameter is zero, GrayString calculates the height of the area, assuming lpData is a pointer to the string.

Return Value

If the string is drawn, the return value is TRUE. If the return value is FALSE, either the TextOut function or the application-defined output function returned FALSE, or there was insufficient memory to create a memory bitmap for graying.

Remarks

Without calling GrayString, an application can draw grayed strings on devices that support a solid gray color. The system color COLOR_GRAYTEXT is the solid-gray system color used to draw disabled text. The application can call the GetSysColor function to retrieve the color value of COLOR_GRAYTEXT. If the color is other than zero (black), the application can call the SetTextColor function to set the text color to the color value and then draw the string directly. If the retrieved color is black, the application must call GrayString to gray the text.

See Also

DrawText, GetSysColor, OutputProc, SetTextColor, TabbedTextOut, TextOut


Handler
Handler  QuickInfo  Overview  Group

A Handler function is a function that a service process specifies as the control handling function of a particular service. The function can have any application-defined name.

VOID Handler(

DWORD  fdwControl	// requested control code
);
Parameters

fdwControl

Indicates the requested control code. This value can be one of the standard control codes in the table, or it can be a user-defined control code in the range of 128 to 255, inclusive. For user-defined control codes, the service defines the action associated with the control code.

Value	Meaning
SERVICE_CONTROL_STOP
	Requests the service to stop.
SERVICE_CONTROL_PAUSE
	Requests the service to pause.
SERVICE_CONTROL_CONTINUE
	Requests the paused service to resume.
SERVICE_CONTROL_INTERROGATE
	Requests the service to immediately report its current status information to the service control manager.
SERVICE_CONTROL_SHUTDOWN
	Requests the service to perform cleanup tasks, because the system is shutting down. Due to extremely limited time available for shutdown, this control should only be used by services that absolutely need to shut down —  for instance, when the eventlog service needs to clear a dirty bit in the files that it maintains, or when the server service needs to shut down so that network connections aren't made when the system is in the shutdown state. If the service takes time to shut down, and sends out STOP_PENDING status messages, it is highly recommended that these messages include a waithint so that the service controller will know how long to wait before indicating to the system that service shutdown is complete. The system gives the service control manager a limited amount of time (about 20 seconds) to complete service shutdown, after which time system shutdown proceeds regardless of whether service shutdown is complete.
Return Value

This function does not return a value.

Remarks

When a Win32 service is started, its ServiceMain function should immediately call the RegisterServiceCtrlHandler function to specify a Handler function to handle control requests.

Whenever it receives a control request from the service control manager, the control dispatcher in the main thread of a Win32 service process invokes the control handler function for the specified service. After handling the control request, the control handler must call the SetServiceStatus function to report its current status to the service control manager.

See Also

RegisterServiceCtrlHandler, ServiceMain, SetServiceStatus


HandlerRoutine
HandlerRoutine  QuickInfo  Overview  Group

A HandlerRoutine function is a function that a console process specifies to handle control signals received by the process. The function can have any name.

BOOL HandlerRoutine(

DWORD  dwCtrlType	//  control signal type
);
Parameters

dwCtrlType

Indicates the type of control signal received by the handler. This value is one of the following:

Signal	Description
CTRL_C_EVENT	A CTRL+C signal was received, either from keyboard input or from a signal generated by the GenerateConsoleCtrlEvent function.
CTRL_BREAK_EVENT	A CTRL+BREAK signal was received, either from keyboard input or from a signal generated by GenerateConsoleCtrlEvent.
CTRL_CLOSE_EVENT	A signal that the system sends to all processes attached to a console when the user closes the console (either by choosing the Close command from the console window's System menu, or by choosing the End Task command from the Task List).
CTRL_LOGOFF_EVENT	A signal that the system sends to all console processes when a user is logging off. This signal does not indicate which user is logging off, so no assumptions can be made.
CTRL_SHUTDOWN_EVENT	A signal that the system sends to all console processes when the system is shutting down.
Return Value

If the function handles the control signal, it should return TRUE. If it returns FALSE, the next handler function in the list of handlers for this process is used.

Remarks

Each console process has its own list of HandlerRoutine functions. Initially, this list contains only a default handler function that calls ExitProcess. A console process adds or removes additional handler functions by calling the SetConsoleCtrlHandler function, which does not affect the list of handler functions for other processes. When a console process receives any of the control signals, its handler functions are called on a last-registered, first-called basis until one of the handlers returns TRUE. If none of the handlers returns TRUE, the default handler is called.

The CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT, and CTRL_SHUTDOWN_EVENT signals give the process an opportunity to clean up before termination. A HandlerRoutine called to handle any of these signals can do one of the following after performing any cleanup operations:

•	Call the ExitProcess function to terminate the process.

•	Return FALSE. If none of the registered handler functions returns TRUE, the default handler terminates the process.

•	Return TRUE. In this case, no other handler functions are called, and the system displays a pop-up dialog box that asks the user whether to terminate the process. The system also displays the dialog box if the process does not respond within a certain time-out period (5 seconds for CTRL_CLOSE_EVENT, and 20 seconds for CTRL_LOGOFF_EVENT and CTRL_SHUTDOWN_EVENT).

A process can use the SetProcessShutdownParameters function to prevent the CTRL_LOGOFF_EVENT and CTRL_SHUTDOWN_EVENT dialog box from being displayed. In this case, the system just terminates the process when a HandlerRoutine returns TRUE or when the time-out period elapses.

See Also

ExitProcess, GenerateConsoleCtrlEvent, GetProcessShutdownParameters, SetConsoleCtrlHandler, SetProcessShutdownParameters


HeapAlloc
HeapAlloc  QuickInfo  Overview  Group

The HeapAlloc function allocates a block of memory from a heap. The allocated memory is not movable.

LPVOID HeapAlloc(

HANDLE  hHeap,	// handle to the private heap block
DWORD  dwFlags,	// heap allocation control flags
DWORD  dwBytes	// number of bytes to allocate
);
Parameters

hHeap

Specifies the heap from which the memory will be allocated. This parameter is a handle returned by the HeapCreate or GetProcessHeap function.

dwFlags

Specifies several controllable aspects of heap allocation. Specifying any of these flags will override the corresponding flag specified when the heap was created with HeapCreate. You can specify one or more of the following flags:

Flag	Meaning
HEAP_GENERATE_EXCEPTIONS	Specifies that the operating system will raise an exception to indicate a function failure, such as an out-of-memory condition, instead of returning NULL.
HEAP_NO_SERIALIZE	Specifies that mutual exclusion will not be used while this function is accessing the heap. For more information about HEAP_NO_SERIALIZE, see the Remarks section of HeapCreate.
HEAP_ZERO_MEMORY	Specifies that the allocated memory will be initialized to zero.
dwBytes

Specifies the number of bytes to be allocated.

If the heap specified by the hHeap parameter is a "non-growable" heap, dwBytes must be less than 0x7FFF8. You create a non-growable heap by calling the HeapCreate function with a nonzero value.

Return Value

If the function succeeds, the return value is a pointer to the allocated memory block.

If the function fails and you have not specified HEAP_GENERATE_EXCEPTIONS, the return value is NULL.

If the function fails and you have specified HEAP_GENERATE_EXCEPTIONS, the function may generate the following exceptions:

Value	Meaning
STATUS_NO_MEMORY	The allocation attempt failed because of a lack of available memory or heap corruption.
STATUS_ACCESS_VIOLATION	The allocation attempt failed because of heap corruption or improper function parameters.
Note that heap corruption can lead to either exception. It depends upon the nature of the heap corruption.

If the function fails, it does not call SetLastError. An application cannot call GetLastError for extended error information.

Remarks

If HeapAlloc succeeds, it allocates at least the amount of memory requested. If the actual amount allocated is greater than the amount requested, the process can use the entire amount. To determine the actual size of the allocated block, use the HeapSize function.

To free a block of memory allocated by HeapAlloc, use the HeapFree function.

Memory allocated by HeapAlloc is not movable. Since the memory is not movable, it is possible for the heap to become fragmented.

Note that if HEAP_ZERO_MEMORY is not specified, the allocated memory will not be initialized to zero.

See Also

GetProcessHeap, HeapCreate, HeapDestroy, HeapFree, HeapReAlloc, HeapSize, SetLastError


HeapCompact
HeapCompact  QuickInfo  Overview  Group

The HeapCompact function attempts to compact a specified heap. It compacts the heap by coalescing adjacent free blocks of memory and decommitting large free blocks of memory.

UINT HeapCompact(

HANDLE  hHeap,	// handle to the heap to compact
DWORD  dwFlags	// bit-flags that control heap access during function operation
);
Parameters

hHeap

Handle to the heap that the function will attempt to compact.

dwFlags

A set of bit flags that control heap access during function operation. The following bit flag has meaning:

Value	Meaning
HEAP_NO_SERIALIZE	If this flag is set, heap access is not serialized while the HeapCompact function accesses the heap; heap access is not mutually exclusive. It is safe to set this flag only in a limited set of specific situations. For a discussion of those situations and heap serialization in general, see the Remarks section of  HeapCreate .  If this flag is clear, heap access is serialized while HeapCompact accesses the heap; heap access is mutually exclusive. This is the safe and simple default condition.
Return Value

If the function succeeds, the return value is the size, in bytes, of the largest committed free block in the heap. This is an unsigned integer value.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

In the unlikely case that there is absolutely no space available in the heap, the function return value is zero, and GetLastError returns the value NO_ERROR.

Remarks

There is no guarantee that an application can successfully allocate a memory block of the size returned by HeapCompact. Other threads or the commit threshold might prevent such an allocation.

See Also

HeapCreate, HeapValidate


HeapCreate
HeapCreate  QuickInfo  Overview  Group

The HeapCreate function creates a heap object that can be used by the calling process. The function reserves a contiguous block in the virtual address space of the process and allocates physical storage for a specified initial portion of this block.

HANDLE HeapCreate(

DWORD  flOptions,	// heap allocation flag
DWORD  dwInitialSize,	// initial heap size
DWORD  dwMaximumSize	// maximum heap size
);
Parameters

flOptions

Specifies optional attributes for the new heap. These flags will affect subsequent access to the new heap through calls to the heap functions (HeapAlloc, HeapFree, HeapReAlloc, and HeapSize). You can specify one or more of the following flags:

Flag	Meaning
HEAP_GENERATE_EXCEPTIONS	Specifies that the system will raise an exception to indicate a function failure, such as an out-of-memory condition, instead of returning NULL.
HEAP_NO_SERIALIZE	Specifies that mutual exclusion will not be used when the heap functions allocate and free memory from this heap. The default, occurring when the HEAP_NO_SERIALIZE flag is not specified, is to serialize access to the heap. Serialization of heap access allows two or more threads to simultaneously allocate and free memory from the same heap.
dwInitialSize

Specifies the initial size, in bytes, of the heap. This value determines the initial amount of physical storage that is allocated for the heap. The value is rounded up to the next page boundary. To determine the size of a page on the host computer, use the GetSystemInfo function.

dwMaximumSize

If dwMaximumSize is a nonzero value, it specifies the maximum size, in bytes, of the heap. The HeapCreate function rounds dwMaximumSize up to the next page boundary, and then reserves a block of that size in the process's virtual address space for the heap. If allocation requests made by the HeapAlloc or HeapReAlloc functions exceed the initial amount of physical storage specified by dwInitialSize, the system allocates additional pages of physical storage for the heap, up to the heap's maximum size.

In addition, if dwMaximumSize is nonzero, the heap cannot grow, and an absolute limitation arises: the maximum size of a memory block in the heap is a bit less than 0x7FFF8 bytes. Requests to allocate larger blocks will fail, even if the maximum size of the heap is large enough to contain the block.

If dwMaximumSize is zero, it specifies that the heap is growable. The heap's size is limited only by available memory. Requests to allocate blocks larger than 0x7FFF8 bytes do not automatically fail; the system calls VirtualAlloc to obtain the memory needed for such large blocks. Applications that need to allocate large memory blocks should set dwMaximumSize to zero.

Return Value

If the function succeeds, the return value is a handle of the newly created heap.

If the function fails, the return value is is NULL. To get extended error information, call GetLastError.

Remarks

The HeapCreate function creates a private heap object from which the calling process can allocate memory blocks by using the HeapAlloc function. The initial size determines the number of committed pages that are initially allocated for the heap. The maximum size determines the total number of reserved pages. These pages create a contiguous block in the process's virtual address space into which the heap can grow. If requests by HeapAlloc exceed the current size of committed pages, additional pages are automatically committed from this reserved space, assuming that the physical storage is available.

The memory of a private heap object is accessible only to the process that created it. If a dynamic-link library (DLL) creates a private heap, the heap is created in the address space of the process that called the DLL, and it is accessible only to that process.

The system uses memory from the private heap to store heap support structures, so not all of the specified heap size is available to the process. For example, if the HeapAlloc function requests 64 kilobytes (K) from a heap with a maximum size of 64K, the request may fail because of system overhead.

If the HEAP_NO_SERIALIZE flag is not specified (the simple default), the heap will serialize access within the calling process. Serialization ensures mutual exclusion when two or more threads attempt to simultaneously allocate or free blocks from the same heap. There is a small performance cost to serialization, but it must be used whenever multiple threads allocate and free memory from the same heap.

Setting the HEAP_NO_SERIALIZE flag eliminates mutual exclusion on the heap. Without serialization, two or more threads that use the same heap handle might attempt to allocate or free memory simultaneously, likely causing corruption in the heap. The HEAP_NO_SERIALIZE flag can, therefore, be safely used only in the following situations:

•	The process has only one thread.

•	The process has multiple threads, but only one thread calls the heap functions for a specific heap.

•	The process has multiple threads, and the application provides its own mechanism for mutual exclusion to a specific heap.

See Also

GetProcessHeap, GetProcessHeaps, GetSystemInfo, HeapAlloc, HeapDestroy, HeapFree, HeapReAlloc, HeapSize, HeapValidate, VirtualAlloc,


HeapDestroy
HeapDestroy  QuickInfo  Overview  Group

The HeapDestroy function destroys the specified heap object. HeapDestroy decommits and releases all the pages of a private heap object, and it invalidates the handle of the heap.

BOOL HeapDestroy(

HANDLE  hHeap	// handle to the heap
);
Parameters

hHeap

Specifies the heap to be destroyed. This parameter should be a heap handle returned by the HeapCreate function. A heap handle returned by the GetProcessHeap function should not be used.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Processes can call HeapDestroy without first calling the HeapFree function to free memory allocated from the heap.

See Also

GetProcessHeap, HeapAlloc, HeapCreate, HeapFree, HeapReAlloc, HeapSize


HeapFree
HeapFree  QuickInfo  Overview  Group

The HeapFree function frees a memory block allocated from a heap by the HeapAlloc or HeapReAlloc function.

BOOL HeapFree(

HANDLE  hHeap,	// handle to the heap
DWORD  dwFlags,	// heap freeing flags
LPVOID  lpMem	// pointer to the memory to free
);
Parameters

hHeap

Specifies the heap whose memory block the function frees. This parameter is a handle returned by the HeapCreate or GetProcessHeap function.

dwFlags

Specifies several controllable aspects of freeing a memory block. Only one flag is currently defined; however, all other flag values are reserved for future use. Specifying this flag will override the corresponding flag specified in the flOptions parameter when the heap was created by using the HeapCreate function:

Flag	Meaning
HEAP_NO_SERIALIZE	Specifies that mutual exclusion will not be used while the function is accessing the heap. For more information about HEAP_NO_SERIALIZE, see the Remarks for the HeapCreate function.
lpMem

Points to the memory block to free. This pointer is returned by the HeapAlloc or HeapReAlloc function.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, it returns FALSE and calls SetLastError. An application can call GetLastError for extended error information.

See Also

GetProcessHeap, HeapAlloc, HeapCreate, HeapDestroy, HeapReAlloc, HeapSize, SetLastError


HeapLock
HeapLock  QuickInfo  Overview  Group

The HeapLock function attempts to acquire the critical section object, or lock, that is associated with a specified heap.

If the function succeeds, the calling thread owns the heap lock. Only the calling thread will be able to allocate or release memory from the heap. The execution of any other thread of the calling process will be blocked if that thread attempts to allocate or release memory from the heap. Such threads will remain blocked until the thread that owns the heap lock calls the HeapUnlock function.

BOOL HeapLock(

HANDLE  hHeap	// handle to the heap to lock for exclusive thread access
);
Parameters

hHeap

Handle to the heap to lock for exclusive access by the calling thread.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The HeapLock function is primarily useful for preventing the allocation and release of heap memory by other threads while the calling thread uses the HeapWalk function.

Each call to HeapLock must be matched by a corresponding call to the HeapUnlock function. Failure to call HeapUnlock will block the execution of any other threads of the calling process that attempt to access the heap.

See Also

HeapUnlock, HeapWalk


HeapReAlloc
HeapReAlloc  QuickInfo  Overview  Group

The HeapReAlloc function reallocates a block of memory from a heap. This function enables you to resize a memory block and change other memory block properties. The allocated memory is not movable.

LPVOID HeapReAlloc(

HANDLE  hHeap,	// handle to a heap block
DWORD  dwFlags,	// heap reallocation flags
LPVOID  lpMem,	// pointer to the memory to reallocate
DWORD  dwBytes	// number of bytes to reallocate
);
Parameters

hHeap

Specifies the heap from which the memory will be reallocated. This is a handle returned by the HeapCreate or GetProcessHeap function.

dwFlags

Specifies several controllable aspects of heap reallocation. Specifying any of these flags will override the corresponding flag specified in the flOptions parameter when the heap was created by using the HeapCreate function. You can specify one or more of the following flags:

Flag	Meaning
HEAP_GENERATE_EXCEPTIONS	Specifies that the operating-system will raise an exception to indicate a function failure, such as an out-of-memory condition, instead of returning NULL.
HEAP_NO_SERIALIZE	Specifies that mutual exclusion will not be used while this function is accessing the heap. For more information about HEAP_NO_SERIALIZE, see the Remarks section of HeapCreate.
HEAP_REALLOC_IN_PLACE_ONLY	Specifies that there can be no movement when reallocating a memory block to a larger size. If this flag is not specified and the reallocation request is for a larger size, the function may move the block to a new location. If this flag is specified and the block cannot be enlarged without moving, the function will fail, leaving the original memory block unchanged.
HEAP_ZERO_MEMORY	If the reallocation request is for a larger size, this flag specifies that the additional region of memory beyond the original size will be initialized to zero. The contents of the memory block up to its original size are unaffected.
lpMem

Points to the block of memory that the function reallocates. This pointer is returned by an earlier call to the HeapAlloc or HeapReAlloc function.

dwBytes

Specifies the new size of the memory block, in bytes. A memory block's size can be increased or decreased by using this function.

If the heap specified by the hHeap parameter is a "non-growable" heap, dwBytes must be less than 0x7FFF8. You create a non-growable heap by calling the HeapCreate function with a nonzero value.

Return Value

If the function succeeds, the return value is a pointer to the reallocated memory block.

If the function fails and you have not specified HEAP_GENERATE_EXCEPTIONS, the return value is NULL.

If the function fails and you have specified HEAP_GENERATE_EXCEPTIONS, the function may generate the following exceptions:

Value	Meaning
STATUS_NO_MEMORY	The reallocation attempt failed for lack of available memory.
STATUS_ACCESS_VIOLATION	The reallocation attempt failed because of heap corruption or improper function parameters.
If the function fails, it calls SetLastError. An application can call GetLastError for extended error information.

Remarks

If HeapReAlloc succeeds, it allocates at least the amount of memory requested. If the actual amount allocated is greater than the amount requested, the process can use the entire amount. To determine the actual size of the reallocated block, use the HeapSize function.

To free a block of memory allocated by HeapReAlloc, use the HeapFree function.

See Also

GetProcessHeap, HeapAlloc, HeapCreate, HeapDestroy, HeapFree, HeapSize, SetLastError


HeapSize
HeapSize  QuickInfo  Overview  Group

The HeapSize function returns the size, in bytes, of a memory block allocated from a heap by the HeapAlloc or HeapReAlloc function.

DWORD HeapSize(

HANDLE  hHeap,	// handle to the heap
DWORD dwFlags,	// heap size control flags
LPCVOID  lpMem	// pointer to memory to return size for
);
Parameters

hHeap

Specifies the heap in which the memory block resides. This handle is returned by the HeapCreate or GetProcessHeap function.

dwFlags

Specifies several controllable aspects of accessing the memory block. Only one flag is currently defined; however, all other flag values are reserved for future use. Specifying this flag will override the corresponding flag specified in the flOptions parameter when the heap was created by using the HeapCreate function:

Value	Meaning
HEAP_NO_SERIALIZE	Specifies that mutual exclusion will not be used while the function is accessing the heap. For more information about HEAP_NO_SERIALIZE, see the Remarks for HeapCreate.
lpMem

Points to the memory block whose size the function will obtain. This is a pointer returned by the HeapAlloc or HeapReAlloc function.

Return Value

If the function succeeds, the return value is the size, in bytes, of the allocated memory block.

If the function fails, the return value is 0xFFFFFFFF. The function does not call SetLastError. An application cannot call GetLastError for extended error information.

See Also

GetProcessHeap, HeapAlloc, HeapCreate, HeapDestroy, HeapFree, HeapReAlloc, SetLastError


HeapUnlock
HeapUnlock  QuickInfo  Overview  Group

The HeapUnlock function releases ownership of the critical section object, or lock, that is associated with a specified heap. The HeapUnlock function reverses the action of the HeapLock function.

BOOL HeapUnlock(

HANDLE  hHeap	// handle to the heap to unlock
);
Parameters

hHeap

Handle to the heap to unlock.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The HeapLock function is primarily useful for preventing the allocation and release of heap memory by other threads while the calling thread uses the HeapWalk function. The HeapUnlock function is the inverse of HeapLock.

Each call to HeapLock must be matched by a corresponding call to the HeapUnlock function. Failure to call HeapUnlock will block the execution of any other threads of the calling process that attempt to access the heap.

See Also

HeapLock, HeapWalk


HeapValidate
HeapValidate  QuickInfo  Overview  Group

The HeapValidate function attempts to validate a specified heap. The function scans all the memory blocks in the heap, and verifies that the heap control structures maintained by the operating system's heap manager are in a consistent state. You can also use the HeapValidate function to validate a single memory block within a specified heap, without checking the validity of the entire heap.

BOOL HeapValidate(

HANDLE  hHeap,	// handle to the heap of interest
DWORD  dwFlags,	// bit flags that control heap access during function operation
LPCVOID  lpMem	// optional pointer to individual memory block to validate
);
Parameters

hHeap

Handle to the heap of interest. The HeapValidate function attempts to validate this heap, or a single memory block within this heap.

dwFlags

A set of bit flags that control heap access during function operation. The following bit flag has meaning:

Value	Meaning
HEAP_NO_SERIALIZE	If this flag is set, heap access is not serialized while the HeapValidate function accesses the heap; heap access is not mutually exclusive. It is safe to set this flag only in a limited set of specific situations. For a discussion of those situations and heap serialization in general, see the Remarks section of HeapCreate .  If this flag is clear, heap access is serialized while HeapValidate accesses the heap; heap access is mutually exclusive. This is the safe and simple default condition.
lpMem

Points to a memory block within the specified heap. This parameter may be NULL.

If this parameter is NULL, the function attempts to validate the entire heap specified by hHeap.

If this parameter is not NULL, the function attempts to validate the memory block pointed to by lpMem. It does not attempt to validate the rest of the heap.

Return Value

If the specified heap or memory block is valid, the return value is TRUE.

If the specified heap or memory block is invalid, the return value is FALSE. On a system set up for debugging, the HeapValidate function then displays debugging messages that describe the part of the heap or memory block that is invalid, and stops at a hard-coded breakpoint so that you can examine the system to determine the source of the invalidity. The HeapValidate function does not set the thread's last error value.

Remarks

There are heap control structures for each memory block in a heap, and for the heap as a whole. When you use the HeapValidate function to validate a complete heap, it checks all of these control structures for consistency.

When you use HeapValidate to validate a single memory block within a heap, it checks only the control structures pertaining to that element. HeapValidate can only validate allocated memory blocks. Calling HeapValidate on a freed memory block will return FALSE because there are no control structures to validate.

If you want to validate the heap elements enumerated by the HeapWalk function, you should only call HeapValidate on the elements that have the PROCESS_HEAP_ENTRY_BUSY bit flag in the wFlags member of the PROCESS_HEAP_ENTRY structure. HeapValidate returns FALSE for all heap elements that do not have this bit set.

See Also

HeapCreate, HeapWalk, PROCESS_HEAP_ENTRY


HeapWalk
HeapWalk  QuickInfo

The HeapWalk function enumerates the memory blocks in a specified heap.

BOOL HeapWalk(

HANDLE  hHeap,	// handle to the heap to enumerate
LPPROCESS_HEAP_ENTRY  lpEntry	// points to structure that maintains enumeration state information
);
Parameters

hHeap

Handle to the heap whose memory blocks you wish to enumerate.

dwFlags

Points to a PROCESS_HEAP_ENTRY structure that maintains state informationfor a particular heap enumeration.

If the HeapWalk function succeeds, returning the value TRUE, this structure's members contain information about the next memory block in the heap.

To initiate a heap enumeration, set the lpData field of the PROCESS_HEAP_ENTRY structure to NULL. To continue a particular heap enumeration, call the HeapWalk function repeatedly, with no changes to hHeap, lpEntry, or any of the members of the PROCESS_HEAP_ENTRY structure.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

If the heap enumeration terminates successfully by reaching the end of the heap, the function returns FALSE, and GetLastError returns the error code ERROR_NO_MORE_ITEMS.

Remarks

To initiate a heap enumeration, call HeapWalk with the lpData field of the PROCESS_HEAP_ENTRY structure pointed to by lpEntry set to NULL.

To continue a heap enumeration, call HeapWalk with the same hHeap and lpEntry values, and with the PROCESS_HEAP_ENTRY structure unchanged from the preceding call to HeapWalk. Repeat this process until you have no need for further enumeration, or until the function returns FALSE and GetLastError returns ERROR_NO_MORE_ITEMS, indicating that all of the heap's memory blocks have been enumerated.

No special call of HeapWalk is needed to terminate the heap enumeration, since no enumeration state data is maintained outside the contents of the PROCESS_HEAP_ENTRY structure.

HeapWalk can fail in a multithreaded application if the heap is not locked during the heap enumeration. Use the HeapLock and HeapUnlock functions to control heap locking during heap enumeration.

See Also

HeapLock, HeapUnlock, HeapValidate, PROCESS_HEAP_ENTRY


HideCaret
HideCaret  QuickInfo  Overview  Group

The HideCaret function removes the caret from the screen. Hiding a caret does not destroy its current shape or invalidate the insertion point.

BOOL HideCaret(

HWND  hWnd	// handle to the window with the caret
);
Parameters

hWnd

Identifies the window that owns the caret. If this parameter is NULL, HideCaret searches the current task for the window that owns the caret.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

HideCaret hides the caret only if the specified window owns the caret. If the specified window does not own the caret, HideCaret does nothing and returns FALSE.

Hiding is cumulative. If your application calls HideCaret five times in a row, it must also call ShowCaret five times before the caret is displayed.

See Also

CreateCaret, DestroyCaret, GetCaretPos, SetCaretPos, ShowCaret


HiliteMenuItem
HiliteMenuItem  QuickInfo  Overview  Group

The HiliteMenuItem function highlights or removes the highlighting from an item in a menu bar.

BOOL HiliteMenuItem(

HWND  hwnd,	// handle to the window with the menu
HMENU  hmenu,	// handle to the menu
UINT  uItemHilite,	// menu item to highlight or unhighlight
UINT  uHilite	// highlight flags
);
Parameters

hwnd

Identifies the window that contains the menu.

hmenu

Identifies the menu bar that contains the item to be highlighted.

uItemHilite

Specifies the menu item to be highlighted. This parameter is either the identifier of the menu item or the offset of the menu item in the menu bar, depending on the value of the uHilite parameter.

uHilite

Specifies flags that control the interpretation of the uItemHilite parameter and indicates whether the menu item is highlighted. This parameter must be a combination of either MF_BYCOMMAND or MF_BYPOSITION and MF_HILITE or MF_UNHILITE.

Value	Meaning
MF_BYCOMMAND	Indicates that uItemHilite gives the identifier of the menu item.
MF_BYPOSITION	Indicates that uItemHilite gives the zero-based relative position of the menu item.
MF_HILITE	Highlights the menu item. If this flag is not specified, the highlighting is removed from the item.
MF_UNHILITE	Removes highlighting from the menu item.
Return Value

If the menu item is set to the specified highlight state, the return value is TRUE; otherwise, it is FALSE.

Remarks

The MF_HILITE and MF_UNHILITE flags can be used only with the HiliteMenuItem function; they cannot be used with the ModifyMenu function.

See Also

ModifyMenu


htonl
htonl  QuickInfo

The Windows Sockets htonl function converts a u_long from host to network byte order.

This function takes a 32-bit number in host byte order and returns a 32-bit number in network byte order.

u_long htonl (

u_long hostlong
);
Parameters

hostlong

A 32-bit number in host byte order.

Return Value

The htonl function returns the value in network byte order.

See Also

htons, ntohl, ntohs


htons
htons  QuickInfo

The Windows Sockets htons function converts a u_short from host byte order to network byte order.

u_short htons (

u_short hostshort
);
Parameters

hostshort

A 16-bit number in host byte order.

Return Value

The htons function returns the value in network byte order.

Remarks

This function takes a 16-bit number in host byte order and returns a 16-bit number in network byte order.

See Also

htonl, ntohl, ntohs


ImageList_Add [New - Windows NT]
ImageList_Add  QuickInfo  Overview  Group

[New - Windows NT]

The ImageList_Add function adds an image or images to an image list.

int WINAPI ImageList_Add(

HIMAGELIST  himl,	// handle to the image list
HBITMAP  hbmImage,	// handle to the bitmap containing the image
HBITMAP  hbmMask	// handle to the bitmap containing the mask
);
Parameters

himl

Handle to the image list.

hbmImage

Handle to the bitmap that contains the image or images. The number of images is inferred from the width of the bitmap.

hbmMask

Handle to the bitmap that contains the mask. If no mask is used with the image list, this parameter is ignored.

Return Value

If the function succeeds, the return value is the index of the first new image.

If the function fails, the return value is − 1.

Remarks

The ImageList_Add function copies the bitmap to an internal data structure. Be sure to use the DeleteObject function to delete hbmImage and hbmMask after the function returns.

See Also

DeleteObject


ImageList_AddIcon [New - Windows NT]
ImageList_AddIcon  QuickInfo

[New - Windows NT]

The ImageList_AddIcon macro adds an icon or cursor to an image list. ImageList_AddIcon calls the ImageList_ReplaceIcon function.

int ImageList_AddIcon(

HIMAGELIST  himl,	// handle to the image list
HICON hicon	// handle to the icon or cursor
);
Parameters

himl

Handle to the image list. If this parameter identifies a masked image list, the macro copies both the image and mask bitmaps of the icon or cursor. If this parameter identifies a nonmasked image list, the macro copies only the image bitmap.

hicon

Handle to the icon or cursor that contains the bitmap and mask for the new image.

Return Value

If the macro succeeds, the return value is the index of the new image.

If the macro fails, the return value is  − 1.

Remarks

Because the system does not save hicon, you can destroy it after the macro returns if the icon or cursor was created by the CreateIcon function. You do not need to destroy hicon if it was loaded by the LoadIcon function; the system automatically frees an icon resource when it is no longer needed.

The ImageList_AddIcon macro is defined as follows:

#define  ImageList_AddIcon(himl, hicon) ImageList_ReplaceIcon(himl, -1, hicon)

See Also

CreateIcon, ImageList_ReplaceIcon, LoadIcon


ImageList_AddMasked [New - Windows NT]
ImageList_AddMasked  QuickInfo  Overview  Group

[New - Windows NT]

The ImageList_AddMasked function adds an image or images to an image list, generating a mask from the specified bitmap.

int WINAPI ImageList_AddMasked(

HIMAGELIST  himl,	// handle to the image list
HBITMAP  hbmImage,	// handle to the bitmap
COLORREF  crMask	// color used to generate mask
);
Parameters

himl

Handle to the image list.

hbmImage

Handle to the bitmap that contains one or more images. The number of images is inferred from the width of the bitmap.

crMask

Color used to generate the mask. Each pixel of this color in the specified bitmap is changed to black, and the corresponding bit in the mask is set to one.

Return Value

If the function succeeds, the return value is the index of the first new image.

If the function fails, the return value is  − 1.

Remarks

The ImageList_AddMasked function copies the bitmap to an internal data structure. Be sure to use the DeleteObject function to delete hbmImage and crMask after the function returns.

See Also

DeleteObject


ImageList_BeginDrag [New - Windows NT]
ImageList_BeginDrag  QuickInfo  Overview  Group

[New - Windows NT]

The ImageList_BeginDrag function begins dragging an image.

BOOL WINAPI ImageList_BeginDrag(

HIMAGELIST  himlTrack,
int  iTrack,
int  dxHotspot,
int  dyHotspot
);
Parameters

himlTrack

Handle to the image list.

iTrack

Index of the image to drag.

dxHotspot and dyHotspot

Location of the drag position relative to the upper-left corner of the image.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

This function creates a temporary image list that is used for dragging. In response to subsequent WM_MOUSEMOVE messages, you can move the drag image by using the ImageList_DragMove function. To end the drag operation, you can use the ImageList_EndDrag function.

See Also

ImageList_DragMove, ImageList_EndDrag, WM_MOUSEMOVE


ImageList_Create [New - Windows NT]
ImageList_Create  QuickInfo  Overview  Group

[New - Windows NT]

The ImageList_Create function creates a new image list.

HIMAGELIST WINAPI ImageList_Create(

int  cx,
int  cy,
UINT  flags,
int  cInitial,
int  cGrow
);
Parameters

cx

Specifies the width, in pixels, of each image.

cy

Specifies the height, in pixels, of each image.

flags

Flags specifying the type of image list to create. This parameter can be a combination of the following values:

Value	Meaning
ILC_COLOR	Use the default behavior if none of the other ILC_COLOR* flags is specified. Typically, the default is ILC_COLOR4; but for older display drivers, the default is ILC_COLORDDB.
ILC_COLOR4	Use a 4-bit (16 color) device-independent bitmap (DIB) section as the bitmap for the image list.
ILC_COLOR8	Use an 8-bit DIB section. The colors used for the color table are the same colors as the halftone palette.
ILC_COLOR16	Use a 16-bit  (32/64k color) DIB section.
ILC_COLOR24	Use a 24-bit DIB section.
ILC_COLOR32	Use a 32-bit DIB section.
ILC_COLORDDB	Use a device-dependent bitmap.
ILC_MASK	Uses a mask. The image list contains two bitmaps, one of which is a monochrome bitmap used as a mask. If this value is not included, the image list contains only one bitmap.
ILC_PALETTE	Uses a color palette with the image list.
cInitial

Number of images that the image list initially contains.

cGrow

Amount of images by which the image list can grow when the system needs to resize the list to make room for new images. This parameter represents the number of new images that the resized image list can contain.

Return Value

If the function succeeds, the return value is the handle to the image list.

If the function fails, the return value NULL.


ImageList_Destroy [New - Windows NT]
ImageList_Destroy  QuickInfo  Overview  Group

[New - Windows NT]

The ImageList_Destroy function destroys an image list.

BOOL WINAPI ImageList_Destroy(

HIMAGELIST  himl
);
Parameters

himl

Handle to the image list to destroy.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.


ImageList_DragEnter [New - Windows NT]
ImageList_DragEnter  QuickInfo  Overview  Group

[New - Windows NT]

The ImageList_DragEnter function locks updates to the specified window during a drag operation and displays the drag image at the specified position within the window.

BOOL WINAPI ImageList_DragEnter(

HWND  hwndLock,
int  x,
int  y
);
Parameters

hwndLock

Handle to the window that owns the drag image.

x

Specifies the x-coordinate at which to display the drag image. The coordinate is relative to the upper-left corner of the window, not the client area.

y

Specifies the y-coordinate at which to display the drag image. The coordinate is relative to the upper-left corner of the window, not the client area.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

To begin a drag operation, use the ImageList_BeginDrag function.

See Also

ImageList_BeginDrag


ImageList_DragLeave [New - Windows NT]
ImageList_DragLeave  QuickInfo  Overview  Group

[New - Windows NT]

The ImageList_DragLeave function unlocks the specified window and hides the drag image, allowing the window to be updated.

BOOL WINAPI ImageList_DragLeave(

HWND  hwndLock	//
);
Parameters

hwndLock

Handle to the window that owns the drag image.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.


ImageList_DragMove [New - Windows NT]
ImageList_DragMove  QuickInfo  Overview  Group

[New - Windows NT]

The ImageList_DragMove function moves the image that is being dragged during a drag-and-drop operation. This function is typically called in response to a WM_MOUSEMOVE message.

BOOL WINAPI ImageList_DragMove(

int  x,	//
int  y	//
);
Parameters

x and y

New drag position.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

To begin a drag operation, use the ImageList_BeginDrag function.

See Also

ImageList_BeginDrag, WM_MOUSEMOVE


ImageList_DragShowNolock [New - Windows NT]
ImageList_DragShowNolock  QuickInfo  Overview  Group

[New - Windows NT]

The ImageList_DragShowNolock function shows or hides the image being dragged.

BOOL WINAPI ImageList_DragShowNolock(

BOOL  fShow	//
);
Parameters

fShow

Value specifying whether to show or hide the image being dragged. Specify TRUE to show the image, FALSE to hide the image.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.


ImageList_Draw [New - Windows NT]
ImageList_Draw  QuickInfo  Overview  Group

[New - Windows NT]

The ImageList_Draw function draws an image list item in the specified device context.

BOOL WINAPI ImageList_Draw(

HIMAGELIST  himl,
int  i,
HDC  hdcDst,
int  x,
int  y,
UINT  fStyle
);
Parameters

himl and i

Handle to the image list, and the index of the image to draw.

hdcDst

Handle to the destination device context.

x

Specifies the x-coordinate at which to draw within the specified device context.

y

Specifies the y-coordinate at which to draw within the specified device context.

fStyle

Flag specifying the drawing style. This parameter can be one or more of the following values:

Value	Meaning
ILD_BLEND25,  ILD_FOCUS	Draws the image, blending 25 percent with the system highlight color. This value has no effect if the image list does not contain a mask.
ILD_BLEND50,  ILD_SELECTED,  ILD_BLEND	Draws the image, blending 50 percent with the system highlight color. This value has no effect if the image list does not contain a mask.
ILD_MASK	Draws the mask.
ILD_NORMAL	Draws the image using the background color for the image list. If the background color is the CLR_NONE value, the image is drawn transparently using the mask.
ILD_TRANSPARENT	Draws the image transparently using the mask, regardless of the background color. This value has no effect if the image list does not contain a mask.
Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.


ImageList_DrawEx [New - Windows NT]
ImageList_DrawEx  QuickInfo  Overview  Group

[New - Windows NT]

The ImageList_DrawEx function draws an image list item in the specified device context. The function uses the specified drawing style and blends the image with the specified color.

BOOL WINAPI ImageList_DrawEx(

HIMAGELIST  himl,
int  i,
int  x,
int  y,
int  dx,
int  dy,
COLORREF  rgbBk,
COLORREF  rgbFg,
UINT  fStyle
);
Parameters

himl

Handle to the image list

i

Index of the image to draw.

hdcDst

Handle to the destination device context.

x

Specifies the x-coordinate at which to draw within the specified device context.

y

Specifies the y-coordinate at which to draw within the specified device context.

dx and dy

Portion of the image to draw, relative to the upper-left corner of the image. If these parameters are zero, the function draws the entire image. The function does not ensure that the parameters are valid.

rgbBk

Background color of the image. This parameter can be an application-defined RGB value or one of the following values:

Value	Meaning
CLR_NONE	No background color. The image is drawn transparently.
CLR_DEFAULT	Default background color. The image is drawn using the background color of the image list.
This parameter is used only if the image list identified by himl was created with the ILC_MASK value.

rgbFg

Foreground color of the image. This parameter can be an application-defined RGB value or one of the following values:

Value	Meaning
CLR_NONE	No blend color. The image is blended with the color of the destination device context.
CLR_DEFAULT	Default foreground color. The image is drawn using the system highlight color as the foreground color.
This parameter is used only if fStyle includes the ILD_BLEND25 or ILD_BLEND50 value.

fStyle

Flag specifying the drawing style. This parameter can be one or more of the following values:

Value	Meaning
ILD_BLEND25,  ILD_FOCUS	Draws the image, blending 25 percent with the blend color specified by rgbFG. This value has no effect if the image list does not contain a mask.
ILD_BLEND50,  ILD_SELECTED,  ILD_BLEND	Draws the image, blending 50 percent with the blend color specified by rgbFG. This value has no effect if the image list does not contain a mask.
ILD_MASK	Draws the mask.
ILD_NORMAL	Draws the image using the background color for the image list. If the background color is the CLR_NONE value, the image is drawn transparently using the mask.
ILD_TRANSPARENT	Draws the image transparently using the mask, regardless of the background color. This value has no effect if the image list does not contain a mask.
See Also

RGB


ImageList_EndDrag [New - Windows NT]
ImageList_EndDrag  QuickInfo  Overview  Group

[New - Windows NT]

The ImageList_EndDrag function ends a drag operation.

BOOL WINAPI ImageList_EndDrag(VOID)

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.


ImageList_ExtractIcon [New - Windows NT]
ImageList_ExtractIcon  QuickInfo  Overview  Group

[New - Windows NT]

The ImageList_ExtractIcon function creates an icon or cursor based on an image and mask in an image list. ImageList_ExtractIcon is a macro that calls the ImageList_GetIcon function.

HICON WINAPI ImageList_ExtractIcon(

HINSTANCE  hi,
HIMAGELIST  himl,
int  i
);
Parameters

hi

Ignored; set to zero.

himl

Handle to the image list.

i

Index of the image.

Return Value

If the function succeeds, the return value is the handle of the icon or cursor.

If the function fails, the return value is NULL.

See Also

ImageList_GetIcon


ImageList_GetBkColor [New - Windows NT]
ImageList_GetBkColor  QuickInfo  Overview  Group

[New - Windows NT]

The ImageList_GetBkColor function retrieves the current background color for an image list.

COLORREF WINAPI ImageList_GetBkColor(

HIMAGELIST  himl
);
Parameters

himl

Handle to the image list.

Return Value

The return value is the background color.


ImageList_GetDragImage [New - Windows NT]
ImageList_GetDragImage  QuickInfo  Overview  Group

[New - Windows NT]

The ImageList_GetDragImage function retrieves the temporary image list that is used for the drag image. The function also retrieves the current drag position, and the offset of the drag image relative to the drag position.

HIMAGELIST WINAPI ImageList_GetDragImage(

POINT FAR* ppt,
POINT FAR* pptHotspot
);
Parameters

ppt

Pointer to a POINT structure that receives the current drag position. Can be NULL.

pptHotSpot

Pointer to a POINT structure that receives the offset of the drag image relative to the drag position. Can be NULL.

Return Value

If the function succeeds, the return value is the handle of the image list.

If the function fails, the return value is NULL.

Remarks

The temporary image list is destroyed when the ImageList_EndDrag function is called. To begin a drag operation, use the ImageList_BeginDrag function.

See Also

ImageList_BeginDrag, ImageList_EndDrag, POINT


ImageList_GetIcon [New - Windows NT]
ImageList_GetIcon  QuickInfo  Overview  Group

[New - Windows NT]

The ImageList_GetIcon function creates an icon or cursor based on an image and mask in an image list.

HICON WINAPI ImageList_GetIcon(

HIMAGELIST himl,	//
int  i,	//
UINT  flags	//
);
Parameters

himl

Handle to the image list.

i

Index of the image.

flags

Combination of flags that specify the drawing style. For a list of values, see the description of the ImageList_Draw function.

Return Value

If the function succeeds, the return value is the handle of the icon or cursor.

If the function fails, the return value is NULL.

See Also

ImageList_Draw


ImageList_GetIconSize [New - Windows NT]
ImageList_GetIconSize  QuickInfo  Overview  Group

[New - Windows NT]

The ImageList_GetIconSize function retrieves the dimensions of images in an image list. All images in an image list have the same dimensions.

BOOL WINAPI ImageList_GetIconSize(

HIMAGELIST  himl,
int FAR  * cx,
int FAR  * cy
);
Parameters

himl

Handle to the image list.

cx

Pointer to integer variable that receives the width, in pixels, of each image.

cy

Pointer to integer variable that receives the height, in pixels, of each image.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.


ImageList_GetImageCount [New - Windows NT]
ImageList_GetImageCount  QuickInfo  Overview  Group

[New - Windows NT]

The ImageList_GetImageCount function retrieves the number of images in an image list.

int WINAPI ImageList_GetImageCount(;

HIMAGELIST  himl
);
Parameters

himl

Handle to the image list.

Return Value

The ImageList_GetImageCount function returns the number of images.


ImageList_GetImageInfo [New - Windows NT]
ImageList_GetImageInfo  QuickInfo  Overview  Group

[New - Windows NT]

The ImageList_GetImageInfo function retrieves information about an image.

BOOL WINAPI ImageList_GetImageInfo(

HIMAGELIST  himl,
int  i,
IMAGEINFO FAR*  pImageInfo
);
Parameters

himl

Handle to the image list.

i

Index of the image.

pImageInfo

Pointer to an IMAGEINFO structure that receives information about the image. The information in this structure can be used to directly manipulate the bitmaps for the image.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

See Also

IMAGEINFO


ImageList_LoadBitmap [New - Windows NT]
ImageList_LoadBitmap  QuickInfo  Overview  Group

[New - Windows NT]

The ImageList_LoadBitmap function creates an image list from the specified bitmap resource. ImageList_LoadBitmap is a macro that calls the ImageList_LoadImage function.

HIMAGELIST WINAPI ImageList_LoadBitmap(

HINSTANCE  hi,
LPCSTR  lpbmp,
int  cx,
int  cGrow,
COLORREF  crMask
);
Parameters

hi

Handle to the instance that contains the bitmap resource.

lpbmp

Name of the resource.

cx

Width of each image. The height of each image and the initial number of images are inferred by the dimensions of the specified bitmap.

cGrow

Amount of images by which the image list can grow when the system needs to resize the list to make room for new images. This parameter represents the number of new images that the resized image list can contain.

crMask

Color used to generate a mask. Each pixel of this color in the specified bitmap is changed to black, and the corresponding bit in the mask is set to one. If this parameter is the CLR_NONE value, no mask is generated.

Return Value

If the function succeeds, the return value is the image list.

If the function fails, the return value is NULL.

See Also

ImageList_LoadImage


ImageList_LoadImage [New - Windows NT]
ImageList_LoadImage  QuickInfo  Overview  Group

[New - Windows NT]

The ImageList_LoadImage function creates an image list from the specified bitmap, cursor, or icon resource.

HIMAGELIST WINAPI ImageList_LoadImage(

HINSTANCE  hi,
LPCSTR  lpbmp,
int  cx,
int  cGrow,
COLORREF  crMask,
UINT  uType,
UINT   uFlags
);
Parameters

hi

Handle to the instance that contains the resource.

If the hi parameter is zero, the low-order word of this parameter must be the identifier of the OEM image to load. The OEM image identifiers are defined in WINUSER.H. Following are the identifier prefixes and their meanings:

Prefix	Meaning
OBM_	OEM bitmaps
OIC_	OEM icons
OCR_	OEM cursors
lpbmp

Pointer to a null-terminated string that contains the name of the image to load.

If the uFlags parameter specifies the LR_LOADFROMFILE value, the lpbmp parameter must be the name of the file that contains the image.

cx

Width of each image. The height of each image and the initial number of images are inferred by the dimensions of the specified resource.

cGrow

Amount of images by which the image list can grow when the system needs to resize the list to make room for new images. This parameter represents the number of new images that the resized image list can contain.

crMask

Color used to generate a mask. Each pixel of this color in the specified bitmap, cursor, or icon is changed to black, and the corresponding bit in the mask is set to 1. If this parameter is the CLR_NONE value, no mask is generated.

uType

Flag that specifies the type of image to load. This parameter can be one of the following values:

Value	Meaning
IMAGE_BITMAP	Loads a bitmap.
IMAGE_CURSOR	Loads a cursor.
IMAGE_ICON	Loads an icon.
uFlags

Flags that specify how to load the image. This parameter can be a combination of the following values:

Value	Meaning
LR_DEFAULTCOLOR	Uses the color format of the display.
LR_LOADDEFAULTSIZE	Uses the width or height specified by the system metric values for cursors and icons if the cx parameter is set to zero. If this value is not specified and cx is set to zero, the function sets the size to that specified in the resource. If the resource contains multiple images, the function sets the size to that of the first image.
LR_LOADFROMFILE	Loads the image from the file specified by the lpbmp parameter.
LR_LOADMAP3DCOLORS	Searches the color table for the image and replaces the following shades of gray with the corresponding three-dimensional color:
Dk Gray, RGB(128, 128, 128)	COLOR_3DSHADOW
Gray,  RGB(192, 192, 192)	COLOR_3DFACE
Lt Gray,  RGB(223, 223, 223)	COLOR_3DLIGHT
LR_LOADTRANSPARENT	Retrieves the color value of the first pixel in the image and replaces the corresponding entry in the color table with the default window color (the COLOR_WINDOW display color). All pixels in the image that use that entry become the default window value color. This value applies only to images that have corresponding color tables.
LR_MONOCHROME	Loads the image in black and white.
LR_SHARED	Shares the image handle if the image is loaded multiple times. Do not use this value for images that have nontraditional sizes that might change after loading or for images that are loaded from a file.
Return Value

If the function succeeds, the return value is the handle of the image list.

If the function fails, the return value is NULL.

See Also

RGB


ImageList_Merge [New - Windows NT]
ImageList_Merge  QuickInfo  Overview  Group

[New - Windows NT]

The ImageList_Merge function creates a new image by combining two existing images. The function also creates a new image list to store the image.

HIMAGELIST WINAPI ImageList_Merge(

HIMAGELIST  himl1,
int  i1,
HIMAGELIST  himl2,
int  i2,
int  dx,
int  dy
);
Parameters

himl1

Handle to the first image list.

i1

Index of the first existing image.

himl2

Handle to the second image list.

i2

Index of the second existing image.

dx and dy

Offset of the second image relative to the first image.

Return Value

If the function succeeds, the return value is the handle of the new image list.

If the function fails, the return value is NULL.

Remarks

The new image consists of the second existing image drawn transparently over the first. The mask for the new image is the result of performing a logical OR operation on the masks of the two existing images.


ImageList_Read [New - Windows NT]
ImageList_Read  QuickInfo  Overview  Group

[New - Windows NT]

The ImageList_Read function reads an image list from a stream.

HIMAGELIST WINAPI ImageList_Read(

LPSTREAM  pstm
);
Parameters

pstm

Pointer to the stream.

Return Value

If the function succeeds, the return value is the image list.

If the function fails, the return value is NULL.


ImageList_Remove [New - Windows NT]
ImageList_Remove  QuickInfo  Overview  Group

[New - Windows NT]

The ImageList_Remove function removes an image from an image list.

BOOL WINAPI ImageList_Remove(

HIMAGELIST  himl,
int  i
);
// Related macro

BOOL ImageList_RemoveAll(himl);

Parameters

himl

Handle to the image list.

i

Index of the image to remove. If the i parameter is  − 1, the function removes all images.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.


ImageList_Replace [New - Windows NT]
ImageList_Replace  QuickInfo  Overview  Group

[New - Windows NT]

The ImageList_Replace function replaces an image in an image list with a new image.

BOOL WINAPI ImageList_Replace(

HIMAGELIST  himl,
int  i,
HBITMAP  hbmImage,
HBITMAP  hbmMask
);
Parameters

himl

Handle to the image list.

i

Index of the image to replace.

hbmImage

Handle to the bitmap that contains the image.

hbmMask

Handle to the bitmap that contains the mask. If no mask is used with the image list, this parameter is ignored.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

The ImageList_Replace function copies the bitmap to an internal data structure. Be sure to use the DeleteObject function to delete hbmImage and hbmMask after the function returns.

See Also

DeleteObject


ImageList_ReplaceIcon [New - Windows NT]
ImageList_ReplaceIcon  QuickInfo  Overview  Group

[New - Windows NT]

The ImageList_ReplaceIcon function replaces an image with an icon or cursor.

int WINAPI ImageList_ReplaceIcon(

HIMAGELIST  himl,
int  i,
HICON  hicon
);
Parameters

himl

Handle to the image list.

i

Index of the image to replace.

hicon

Handle to the icon or cursor that contains the bitmap and mask for the new image.

Return Value

If the function succeeds, the return value is the index of the image.

If the function fails, the return value is  − 1.

Remarks

Because the system does not save hicon, you can destroy it after the function returns if the icon or cursor was created by the CreateIcon function. You do not need to destroy hicon if it was loaded by the LoadIcon function; the system automatically frees an icon resource when it is no longer needed.

See Also

CreateIcon, LoadIcon


ImageList_SetBkColor [New - Windows NT]
ImageList_SetBkColor  QuickInfo  Overview  Group

[New - Windows NT]

The ImageList_SetBkColor function sets the background color for an image list.

COLORREF WINAPI ImageList_SetBkColor(

HIMAGELIST  himl,	//
COLORREF  clrBk	//
);
Parameters

himl

Handle to the image list.

clrBk

Background color to set. This parameter can be the CLR_NONE value; in that case, images are drawn transparently using the mask.

Return Value

If the function succeeds, the return value is the previous background color.

If the function fails, the return value is the CLR_NONE value.


ImageList_SetDragCursorImage [New - Windows NT]
ImageList_SetDragCursorImage  QuickInfo  Overview  Group

[New - Windows NT]

The ImageList_SetDragCursorImage function creates a new drag image by combining the specified image (typically a mouse cursor image) with the current drag image.

BOOL WINAPI ImageList_SetDragCursorImage(

HIMAGELIST  himlDrag,
int  iDrag,
int  dxHotspot,
int  dyHotspot
);
Parameters

himlDrag

Handle to the image list that contains the new image to combine with the drag image.

iDrag

Index of the new image to combine with the drag image.

dxHotspot and dyHotspot

Position of the hot spot within the new image.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.


ImageList_SetIconSize [New - Windows NT]
ImageList_SetIconSize  QuickInfo  Overview  Group

[New - Windows NT]

The ImageList_SetIconSize function sets the dimensions of images in an image list and removes all images from the list.

BOOL WINAPI ImageList_SetIconSize(

HIMAGELIST  himl,
int  cx,
int  cy
);
Parameters

himl

Handle to the image list.

cx

Width, in pixels, of the images in the image list. All images in an image list have the same dimensions.

cy

Height, in pixels, of the images in the image list. All images in an image list have the same dimensions.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.


ImageList_SetOverlayImage [New - Windows NT]
ImageList_SetOverlayImage  QuickInfo  Overview  Group

[New - Windows NT]

The ImageList_SetOverlayImage function adds the index of an image to the list of images to be used as overlay masks. Up to four indices can be added to the list.

BOOL WINAPI ImageList_SetOverlayImage(

HIMAGELIST  himl,
int  iImage,
int  iOverlay
);
Parameters

himl

Handle to the image list.

iImage

Image to use as an overlay mask.

iOverlay

One-based index of the overlay mask.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

An overlay mask is an image drawn transparently over another image. You draw an overlay mask over an image by using the ImageList_Draw or ImageList_DrawEx function with the index of the overlay mask. The index must be specified by using the INDEXTOOVERLAYMASK macro.

See Also

ImageList_Draw, ImageList_DrawEx, INDEXTOOVERLAYMASK


ImageList_Write [New - Windows NT]
ImageList_Write  QuickInfo  Overview  Group

[New - Windows NT]

The ImageList_Write function writes an image list to a stream.

HIMAGELIST WINAPI ImageList_Write(

HIMAGELIST  himl,	//
LPSTREAM  pstm	//
);
Parameters

himl

Handle to the image list.

pstm

Pointer to the stream.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.


ImmAssociateContext [New - Windows 95]
ImmAssociateContext  QuickInfo  Overview  Group

[New - Windows 95]

The ImmAssociateContext function associates the specified input context with the specified window. If hIMC is NULL, the function removes any association the window may have with an input context. By default, the system associates the default input context with each window as it is created.

HIMC ImmAssociateContext(

HWND  hWnd,
HIMC  hIMC
);
Parameters

hWnd

Handle to the window to be associated with the input context.

hIMC

Handle to the input context.

Return Value

Returns the handle to the input context previously associated with the window.

Remarks

If an application associates an input context with a window, the application must remove that association before destroying the input context. One way to do this is to save and reassociate the handle to the default input context with the window.


ImmConfigureIME [New - Windows 95]
ImmConfigureIME  QuickInfo  Overview  Group

[New - Windows 95]

The ImmConfigureIME function displays the configuration dialog box for the IME.

BOOL ImmConfigureIME(

HKL  hKL,
HWND  hWnd,
DWORD  dwMode,
LPVOID  lpdata
);
Parameters

hKL

Handle to the keyboard layout.

hWnd

Handle to the parent window for the dialog box.

dwMode

Type of dialog box to display. This parameter can be one of the following values:

Value	Meaning
IME_CONFIG_GENERAL	Displays general purpose configuration dialog box.
IME_CONFIG_REGWORD	Displays register word dialog box.
IME_CONFIG_SELECTDICTIONARY	Displays dictionary selection dialog box.
lpData

Pointer to supplemental data. If dwMode is IME_CONFIG_REGWORD, this parameter must be the address of a REGISTERWORD structure.

If dwMode is not IME_CONFIG_REGWORD, this parameter is ignored.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

The ImmConfigureIME function is called by the Control Panel.


ImmCreateContext [New - Windows 95]
ImmCreateContext  QuickInfo  Overview  Group

[New - Windows 95]

The ImmCreateContext function creates a new input context, allocating memory for the context and initializing it. An application calls this function to prepare its own input context.

HIMC ImmCreateContext(void);

Return Value

If the function succeeds, the return value is the handle to the new input context.

If the function fails, the return value is NULL.


ImmDestroyContext [New - Windows 95]
ImmDestroyContext  QuickInfo  Overview  Group

[New - Windows 95]

The ImmDestroyContext function releases the input context and frees any memory associated with it.

BOOL ImmDestroyContext(

HIMC  hIMC
);
Parameters

hIMC

Handle to the input context to free.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

Any application that creates an input context by using the ImmCreateContext function must call this function to free the context before it terminates.

See Also

ImmCreateContext


ImmEnumRegisterWord [New - Windows 95]
ImmEnumRegisterWord  QuickInfo  Overview  Group

[New - Windows 95]

The ImmEnumRegisterWord function enumerates the register strings having the specified reading string, style, and register string.

UINT ImmEnumRegisterWord(

HKL  hKL,
REGISTERWORDENUMPROC  lpfnEnumProc,
LPCTSTR  lpszReading,
DWORD  dwStyle,
LPCTSTR  lpszRegister,
LPVOID  lpData
);
Parameters

hKL

Handle to the keyboard layout.

lpfnEnumProc

Pointer to the callback function. For more information, see EnumRegisterWordProc.

lpszReading

Pointer to the reading string to be enumerated. If NULL, this function enumerates all available reading strings that match with the specified dwStyle and lpszRegister.

dwStyle

Style to be enumerate. If zero, this function enumerates all available styles that match with the specified lpszReading and lpszRegister.

lpszRegister

Pointer to the register string to enumerate. If NULL, this function enumerates all register strings that match with the specified lpszReading and dwStyle.

lpData

Application-supplied data. The function passes this parameter to the callback function.

Return Value

Returns the last value return by the callback function. Its meaning is defined by the application. The function returns zero if it cannot enumerate the register strings.

Remarks

If dwStyle is zero and both lpszReading and lpszRegister are NULL, the ImmEnumRegisterWord function enumerates all register strings in the IME dictionary.

See Also

EnumRegisterWordProc


ImmEscape [New - Windows 95]
ImmEscape  QuickInfo  Overview  Group

[New - Windows 95]

The ImmEscape function carries out IME-specific subfunctions and is used mainly for country-specific functions.

LRESULT ImmEscape(

HKL  hKL,
HIMC  hIMC,
UINT  uEscape,
LPVOID  lpData
);
Parameters

hKL

Handle to the keyboard layout.

hIMC

Handle to the input context.

uEscape

Index of the subfunction. For more information about the escape, see the "IME Escapes" table in Input Method Editor Constants.

lpData

Subfunction-specific data.

Return Value

Returns zero on error; otherwise, returns an escape-specific value.


ImmGetCandidateList [New - Windows 95]
ImmGetCandidateList  QuickInfo  Overview  Group

[New - Windows 95]

The ImmGetCandidateList function retrieves a specified candidate list, copying the list to the specified buffer.

DWORD ImmGetCandidateList(

HIMC  hIMC,
DWORD  deIndex,
LPCANDIDATELIST  lpCandList,
DWORD  dwBufLen
);
Parameters

hIMC

Handle to the input context.

deIndex

Zero-based index of the candidate list.

lpCandList

Pointer to the CANDIDATELIST structure that receives the candidate list.

dwBufLen

Size of the buffer, in bytes. If zero, the function returns the size in bytes required to receive the complete candidate list.

Return Value

If the function succeeds, the return value is the number of bytes copied to the specified buffer.

If the function fails, the return value is zero.

See Also

CANDIDATELIST


ImmGetCandidateListCount [New - Windows 95]
ImmGetCandidateListCount  QuickInfo  Overview  Group

[New - Windows 95]

The ImmGetCandidateListCount function retrieves the size, in bytes, of the candidate lists.

DWORD ImeGetCandidateListCount(

HIMC  hIMC,
LPDWORD  lpdwListCount
);
Parameters

hIMC

Handle to the input context.

lpdwListCount

Pointer to the 32-bit variable that receives the size of the candidate lists.

Return Value

Returns the number of bytes required to receive all candidate lists.

Remarks

Applications typically call this function in response to a IMN_OPENCANDIDATE or IMN_CHANGECANDIDATE message.

See Also

IMN_CHANGECANDIDATE, IMN_OPENCANDIDATE


ImmGetCandidateWindow [New - Windows 95]
ImmGetCandidateWindow  QuickInfo  Overview  Group

[New - Windows 95]

The ImmGetCandidateWindow function gets information about the candidate list window.

BOOL ImmGetCandidateWindow(

HIMC  hIMC,
DWORD  dwBufLen,
LPCANDIDATEFORM  lpCandidate
);
Parameters

hIMC

Handle to the input context.

dwBufLen

Size, in bytes, of the buffer that receives the information.

lpCandidate

Pointer to the CANDIDATEFORM structure that receives information about the candidate window.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

See Also

CANDIDATEFORM


ImmGetCompositionFont [New - Windows 95]
ImmGetCompositionFont  QuickInfo  Overview  Group

[New - Windows 95]

The ImmGetCompositionFont function retrieves information about the logical font currently used to display characters in the composition window.

BOOL ImmGetCompositionFont(

HIMC  hIMC,
LPLOGFONT  lplf
);
Parameters

hIMC

Handle to the input context.

lplf

Pointer to a LOGFONT structure that receives the font information.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

See Also

LOGFONT


ImmGetCompositionString [New - Windows 95]
ImmGetCompositionString  QuickInfo  Overview  Group

[New - Windows 95]

The ImmGetCompositionString function retrieves information about the composition string.

LONG ImmGetCompositionString(

HIMC  hIMC,
DWORD  dwIndex,
LPVOID  lpBuf,
DWORD  dwBufLen
);
Parameters

hIMC

Handle to the input context.

dwIndex

Index of the information to retrieve. This parameter can be one of the values given in the "IME Composition String Values" table in Input Method Editor Constants. For each value except GCS_CURSORPOS and GCS_DELTASTART, the function copies the requested information to the specified buffer. The function returns the cursor and delta position values in the low 16-bits of the return value.

lpBuf

Pointer to the buffer that receives the requested information.

dwBufLen

Size of the buffer, in bytes. If zero, the ImmGetCompositionString function returns the buffer size needed for the complete information.

Return Value

Returns the number of bytes copied to the destination buffer or, if dwBufLen is zero, the buffer size, in bytes, needed to receive all of the requested information. On an error, the function returns one of the following negative error values:

Value	Meaning
IMM_ERROR_NODATA	Composition data is not ready in the input context.
IMM_ERROR_GENERAL	General error detected by IME.
Remarks

An application calls this function in response to the WM_IME_COMPOSITION or WM_IME_STARTCOMPOSITION message. The IMM removes the information when an application calls the ImmReleaseContext function.

See Also

ImmReleaseContext, WM_IME_COMPOSITION


ImmGetCompositionWindow [New - Windows 95]
ImmGetCompositionWindow  QuickInfo  Overview  Group

[New - Windows 95]

The ImmGetCompositionWindow function gets information about the composition window.

BOOL ImmGetCompositionWindow(

HIMC  hIMC,
LPCOMPOSITIONFORM  lpCompForm
);
Parameters

hIMC

Handle to the input context.

lpCompForm

Pointer to the COMPOSITIONFORM structure that receives information about the composition window.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

See Also

COMPOSITIONFORM


ImmGetContext [New - Windows 95]
ImmGetContext  QuickInfo  Overview  Group

[New - Windows 95]

The ImmGetContext function retrieves the input context associated with the specified window.

HIMC ImmGetContext(

HWND  hWnd
);
Parameters

hWnd

Handle to the window to retrieve the input context for.

Return Value

Returns the handle to the input context.

Remarks

An application should routinely use this function to retrieve the current input context before attempting to access information in the context.


ImmGetConversionList [New - Windows 95]
ImmGetConversionList  QuickInfo  Overview  Group

[New - Windows 95]

The ImmGetConversionList function retrieves the list of characters or words from one character or word.

UINT ImmGetConversionList(

HKL  hKL,
HIMC  hIMC,
LPCTSTR  lpSrc,
LPCANDIDATELIST  lpDst,
DWORD  dwBufLen,
UINT  uFlag
);
Parameters

hKL

Handle to the keyboard layout.

hIMC

Handle to the input context.

lpSrc

Pointer to a null-terminated character string.

lpDst

Pointer to the CANDIDATELIST structure that receives the conversion result.

dwBufLen

Size of the destination buffer, in bytes. If zero, the function returns the buffer size needed for the complete conversion result.

uFlag

Action flag. This parameter can be one of the following values:

Value	Meaning
GCL_CONVERSION	Source string is the reading string. The function copies the result string to the destination buffer.
GCL_REVERSECONVERSION	Source string is the result string. The function copies the reading string to the destination buffer.
GCL_REVERSE_LENGTH	Source string is the result string. The function returns the size in bytes of the reading string that would be created if GCL_REVERSECONVERSION were given.
Return Value

Returns the number of bytes copied to the specified buffer or, if dwBufLen is zero, the buffer size needed to receive the list.

See Also

CANDIDATELIST


ImmGetConversionStatus [New - Windows 95]
ImmGetConversionStatus  QuickInfo  Overview  Group

[New - Windows 95]

The ImmGetConversionStatus function gets the current conversion status.

BOOL ImmGetConversionStatus(

HIMC  hIMC,
LPDWORD  lpfdwConversion,
LPDWORD  lpfdwSentence
);
Parameters

hIMC

Handle to the input context for which to retrieve information.

lpfdwConversion

Pointer to a 32-bit variable that receives a combination of conversion mode values. For more information, see the "IME Conversion Mode Values" table in Input Method Editor Constants.

lpfdwSentence

Pointer to a 32-bit variable that receives a sentence mode value. For more information, see the "IME Sentence Mode Values" table in Input Method Editor Constants.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

Conversion and sentence mode values are set only if the IME supports those modes.


ImmGetDefaultIMEWnd [New - Windows 95]
ImmGetDefaultIMEWnd  QuickInfo  Overview  Group

[New - Windows 95]

The ImmGetDefaultIMEWnd function gets the default window handle to the IME class.

HWND ImmGetDefaultIMEWnd(

HWND  hWnd
);
Parameters

hWnd

Handle to the window for the application.

Return Value

If the function succeeds, the return value is the default window handle to the IME class.

If the function fails, the return value is NULL.

Remarks

The system creates a default IME window for every thread. The IME window is created based on the IME class. The application can send WM_IME_CONTROL to this window.

See Also

WM_IME_CONTROL


ImmGetDescription [New - Windows 95]
ImmGetDescription  QuickInfo  Overview  Group

[New - Windows 95]

The ImmGetDescription function copies the description of the IME to the specified buffer.

UINT ImmGetDescription(

HKL  hKL,
LPTSTR  lpszDescription,
UINT  uBufLen
);
Parameters

hKL

Handle to the keyboard layout.

lpszDescription

Pointer to the buffer that receives the null-terminated string describing the IME.

uBufLen

Size of the buffer, in bytes. If zero, the function returns the buffer size needed for the complete description, not including terminating null character.

Return Value

Returns the number of bytes copied to the buffer or, if uBufLen is zero, the buffer size in bytes needed to receive the description. Neither value includes the terminating null character.


ImmGetGuideLine [New - Windows 95]
ImmGetGuideLine  QuickInfo  Overview  Group

[New - Windows 95]

The ImmGetGuideLine function gets information about errors. Applications use the information to notify users.

DWORD ImmGetGuideLine(dwBufLen

HIMC  hIMC,
DWORD  dwIndex,
LPTSTR  lpBuf,
DWORD  dwBufLen
);
Parameters

hIMC

Handle to the input context.

dwIndex

Type of guideline information to retrieve. Can be one of the following values:

Value	Meaning
GGL_LEVEL	Returns the error level.
GGL_INDEX	Returns the error index.
GGL_STRING	Retrieves the error message string.
GGL_PRIVATE	Returns information about reverse conversion.
lpBuf

Pointer to the buffer that receives the error message string. This parameter can be NULL if dwIndex is not GGL_STRING or GGL_PRIVATE if dwBufLen is zero.

dwBufLen

Size, in bytes, of the buffer pointed to by lpBuf. If zero, the function returns the buffer size needed to receive the error message string, not including the terminating null character.

Return Value

The return value is an error level, an error index, or the size of an error message string, depending on the value of the dwIndex parameter. If dwIndex is GGL_LEVEL, the return value is one of the following:

Value	Meaning
GL_LEVEL_ERROR	Error. The IME may not be able to continue.
GL_LEVEL_FATAL	Fatal error. The IME cannot continue, and data may be lost.
GL_LEVEL_INFORMATION	No error, but information is available for the user.
GL_LEVEL_NOGUIDELINE	No error. Remove previous error message if still visible.
GL_LEVEL_WARNING	Unexpected input or other result. The user should be warned, but the IME can continue.
If dwIndex is GGL_INDEX, the return value is one of the following:

Value	Meaning
GL_ID_CANNOTSAVE	The dictionary or the statistics data cannot be saved.
GL_ID_NOCONVERT	The IME cannot convert any more.
GL_ID_NODICTIONARY	The IME cannot find the dictionary, or the dictionary has an unexpected format.
GL_ID_NOMODULE	The IME can not find the module that IME needs.
GL_ID_READINGCONFLICT	For example, some vowels cannot put together.
GL_ID_TOOMANYSTROKE	There are too many strokes for one character or one clause.
GL_ID_TYPINGERROR	Typing error. The IME can not handle this typing.
GL_ID_UNKNOWN	Unknown error. The application should refer to the error message string.
GL_ID_INPUTREADING	IME accepts reading character input.
GL_ID_INPUTRADICAL	IME accepts radical character input.
GL_ID_INPUTCODE	IME accepts character code input.
GL_ID_CHOOSECANDIDATE	IME accepts candidate string selection.
GL_ID_REVERSECONVERSION	Information about reverse conversion is available.
If dwIndex is GGL_STRING, the return value is the number of bytes of the string copied to the buffer, or if dwBufLen is zero, the return value is the buffer size needed to receive the string.

If dwIndex is GGL_PRIVATE, the return value is the number of bytes of information copied to the buffer. If dwIndex is GGL_PRIVATE and dwBufLen is zero, the return value is the buffer size needed to receive the information.

Remarks

Applications typically call this function after receiving an IMN_GUIDELINE message.


ImmGetIMEFileName [New - Windows 95]
ImmGetIMEFileName  QuickInfo  Overview  Group

[New - Windows 95]

The ImmGetIMEFileName function gets the filename of the IME associated with the specified keyboard layout.

BOOL ImmGetIMEFileName(

HKL  hKL,
LPTSTR  lpszFileName,
UINT  uBufLen
);
Parameters

hKL

Handle to the keyboard layout.

lpszFileName

Pointer to the buffer that receives the filename.

uBufLen

Size in bytes of the buffer. If zero, the function returns the buffer size in bytes needed to receive the filename, not including the termintaing null character.

Return Value

The return value is the number of bytes in the filename copied to the buffer, or if uBufLen is zero, the return value is the buffer size needed for the filename. In either case, the terminating null character is not included.

Remarks

In the registry, the system stores the filename as the IME name value in HKEY_LOCAL_MACHINE root under the \System\CurrentControlSet\control\keyboard layouts\hKL key.


ImmGetOpenStatus [New - Windows 95]
ImmGetOpenStatus  QuickInfo  Overview  Group

[New - Windows 95]

The ImmGetOpenStatus function checks whether the IME is open or closed.

BOOL WINAPI ImmGetOpenStatus(

HIMC  hIMC
);
Parameters

hIMC

Handle to the input context.

Return Value

The return value is TRUE if the IME is open, FALSE otherwise.


ImmGetProperty [New - Windows 95]
ImmGetProperty  QuickInfo  Overview  Group

[New - Windows 95]

The ImmGetProperty function gets the property and capabilities of the IME associated with the specified keyboard layout.

BOOL ImmGetProperty(

HKL  hKL,
DWORD  fdwIndex
);
Parameters

hKL

Handle to the keyboard layout.

fdwIndex

Type of property information to retrieve. This parameter can be one of the following values:

Value	Meaning
IGP_PROPERTY	Property information.
IGP_CONVERSION	Conversion capabilities.
IGP_SENTENCE	Sentence mode capabilities.
IGP_UI	User interface capabilities.
IGP_SETCOMPSTR	Composition string capabilities.
IGP_SELECT	Selection inheritance capabilities.
IGP_GETIMEVERSION	Retrieves the Windows version number for which the specified IME was created.
Return Value

Returns the property or capability value, depending on the value of the dwIndex parameter. If dwIndex is IGP_PROPERTY, returns a combination of the following values:

Value	Meaning
IME_PROP_AT_CARET	If set, conversion window is at the caret position. If clear, the window is near caret position.
IME_PROP_SPECIAL_UI	If set, IME has a nonstandard user interface. The application should not draw in the IME window.
IME_PROP_CANDLIST_START_FROM_1	If set, strings in the candidate list are numbered starting at 1. If clear, strings start at 0.
IME_PROP_UNICODE	If set, strings for the input context have Unicode characters. If clear, strings have single and double-byte characters.
If dwIndex is IGP_UI, the return value is a combination of the following values:

Value	Meaning
UI_CAP_2700	Supports text escapement values of 0 or 2700.
UI_CAP_ROT90	Supports text escapement values of 0, 900, 1800, or 2700.
UI_CAP_ROTANY	Supports any text escapement value.
If dwIndex is IGP_SETCOMPSTR, the return value is a combination of the following values:

Value	Meaning
SCS_CAP_COMPSTR	Can create the composition string by using the SCS_SETSTR value of the ImmSetCompositionString function.
SCS_CAP_MAKEREAD	Can create the reading string from corresponding composition string when using the SCS_SETSTR value of the ImmSetCompositionString function.
If dwIndex is IGP_SELECT, the return value is a combination of the following values:

Value	Meaning
SELECT_CAP_CONVMODE	Inherits conversion mode when a new IME is selected.
SELECT_CAP_SENTENCE	Inherits sentence mode when a new IME is selected.
If dwIndex is IGP_GETIMEVERSION, the return value is one of the following values:

Value	Meaning
IMEVER_0310	The IME was created for Windows 3.1
IMEVER_0400	The IME was created for Windows 95.


ImmGetRegisterWordStyle [New - Windows 95]
ImmGetRegisterWordStyle  QuickInfo  Overview  Group

[New - Windows 95]

The ImmGetRegisterWordStyle function gets a list of the styles support by the IME associated with the specified keyboard layout.

UINT ImmGetRegisterWordStyle(

HKL  hKL,
UINT  nItem,
LPSTYLEBUF  lpStyleBuf
);
Parameters

hKL

Handle to the keyboard layout.

nItem

Maximum number of styles that the buffer can hold.

lpStyleBuf

Pointer to the STYLEBUF structure that receives the style information.

Return Value

The return value is the number of layout handles copied to the buffer, or if nItems is zero, the return value is the buffer size in array elements needed to receive all available style information.

See Also

STYLEBUF


ImmGetStatusWindowPos [New - Windows 95]
ImmGetStatusWindowPos  QuickInfo  Overview  Group

[New - Windows 95]

The ImmGetStatusWindowPos function gets the position of the status window.

BOOL ImmGetStatusWindowPos(

HIMC  hIMC,
LPPOINT  lpptPos
);
Parameters

hIMC

Handle to the input context.

lpptPos

Pointer to the POINT structure that receives the position coordinates. These are screen coordinates, relative to the upper-left corner of the screen.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

See Also

POINT


ImmGetVirtualKey [New - Windows 95]
ImmGetVirtualKey  QuickInfo  Overview  Group

[New - Windows 95]

The ImmGetVirtualKey function recovers the original virtual-key value associated with a key input message that has already been processed by the IME.

UINT ImmGetVirtualKey(

HWND  hWnd
);
Parameters

hWnd

Handle to the window that receives the key message.

Return Value

The return value is the original virtual-key value.

Remarks

Although the IME sets the virtual-key value to VK_PROCESSKEY after processing a key input message, an application can recover the original virtual-key value with the ImmGetVirtualKey function. This function can be used only for key input messages containing the VK_PROCESSKEY value.


ImmInstallIME [New - Windows 95]
ImmInstallIME  QuickInfo  Overview  Group

[New - Windows 95]

The ImmInstallIME function installs an IME into the system.

HKL ImmInstallIME(

LPCTSTR  lpszIMEFileName,
LPCTSTR  lpszLayoutText
);
Parameters

lpszIMEFileName

Pointer to a null-terminated string that specifies the full path of the IME.

lpszLayoutText

Pointer to a null-terminated string that specifies the name of the IME. This name also specifies the layout text of the IME.

Return Value

The return value is the handle to the keyboard layout for the IME.

Remarks

This function is intended to be used by IME setup programs only.


ImmIsIME [New - Windows 95]
ImmIsIME  QuickInfo  Overview  Group

[New - Windows 95]

The ImmIsIME function checks whether the specified handle identifies an IME.

BOOL ImmIsIME(

HKL  hKL
);
Parameters

hKL

Handle to the keyboard layout to check.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.


ImmIsUIMessage [New - Windows 95]
ImmIsUIMessage  QuickInfo  Overview  Group

[New - Windows 95]

The ImmIsUIMessage function checks for messages intended for the IME window and sends those messages to the specified window.

BOOL ImmIsUIMessage(

HWND  hWndIME,
UINT  msg,
WPARAM  wParam,
LPARAM  lParam
);
Parameters

hWndIME

Handle to a window belonging to the IME window class.

msg

Message to check.

wParam

32-bit message-specific parameter.

lParam

32-bit message-specific parameter.

Return Value

If the message is processed by the IME window, the return value is TRUE.

If the message is not processed by the IME window, the return value is FALSE.

Remarks

An application typically uses this function to display any composition string or candidate list specified by IME. If hWndIME is NULL, the function checks whether the message is a user interface message.


ImmNotifyIME [New - Windows 95]
ImmNotifyIME  QuickInfo  Overview  Group

[New - Windows 95]

The ImmNotifyIME function notifies the IME about changes to the status of the input context.

BOOL ImmNotifyIME(

HIMC  hIMC,
DWORD  dwAction,
DWORD  dwIndex,
DWORD  dwValue
);
Parameters

hIMC

Handle to the input context.

dwAction

Notification code. This parameter can be one of the following values:

Value	Meaning
NI_CHANGECANDIDATELIST	An application changed the current selected candidate; dwIndex is an index of a candidate list to be selected and dwValue is not used.
NI_CLOSECANDIDATE	An application directs the IME to close a candidate list; dwIndex is the index of the list to close; dwValue is not used. The IME sends a IMN_CLOSECANDIDATE message to the application if it closes the list.
NI_COMPOSITIONSTR	An application directs the IME to carry out an action on the composition string; dwValue is not used and dwIndex can be CPS_CANCEL, CPS_COMPLETE, CPS_CONVERT, or CPS_REVERT.
NI_OPENCANDIDATE	An application directs the IME to open a candidate list; dwIndex is the index of the list to open; dwValue is not used. The IME sends a IMN_OPENCANDIDATE message to the application if it opens the list.
NI_SELECTCANDIDATESTR	An application selected one of candidates; dwIndex is an index of a candidate list to be selected and dwValue is an index of a candidate string in the selected candidate list.
NI_SETCANDIDATE_PAGESIZE	The dwIndex parameter specifies the candidate list to be changed and must have a value in the range 0 to 31.
NI_SETCANDIDATE_PAGESTART	The dwIndex parameter specifies the candidate list to be changed and must have a value in the range 0 to 31.
dwIndex

Index of a candidate list or, if dwAction is NI_COMPOSITIONSTR, one of the following values:

Value	Meaning
CPS_CANCEL	Clear the composition string and set the status to no composition string.
CPS_COMPLETE	Set the composition string as the result string.
CPS_CONVERT	Convert the composition string.
CPS_REVERT	Cancel the current composition string and revert to the unconverted string.
dwValue

Index of a candidate string or not used, depending on the value of the dwAction parameter.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.


ImmRegisterWord [New - Windows 95]
ImmRegisterWord  QuickInfo  Overview  Group

[New - Windows 95]

The ImmRegisterWord function registers a string into the dictionary of the IME associated with the specified keyboard layout.

BOOL ImmRegisterWord(

HKL  hKL,
LPCTSR  lpszReading,
DWORD  dwStyle,
LPCTSTR  lpszRegister
);
Parameters

hKL

Handle to the keyboard layout.

lpszReading

Pointer to a null-terminated string specifying the reading string associated with the string to register.

dwStyle

Style of the register string. This parameter can be IME_REGWORD_STYLE_EUDC to indicate the string is in the EUDC range, or any value in the reserved range IME_REGWORD_STYLE_USER_FIRST to IME_REGWORD_STYLE_USER_LAST to indicate a private style maintained by the specified IME.

lpszRegister

Pointer to a null-terminated string specifying the string to register.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.


ImmReleaseContext [New - Windows 95]
ImmReleaseContext  QuickInfo  Overview  Group

[New - Windows 95]

The ImmReleaseContext function releases the input context and unlocks the memory associated in the context. An application must call this function for each call to the ImmGetContext function.

BOOL ImmReleaseContext(

HWND  hWnd,
HIMC  hIMC
);
Parameters

hWnd

Handle to the window for which the input context was previously retrieved.

hIMC

Handle to the input context.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

See Also

ImmGetContext


ImmSetCandidateWindow [New - Windows 95]
ImmSetCandidateWindow  QuickInfo  Overview  Group

[New - Windows 95]

The ImmSetCandidateWindow function sets information about the candidate list window.

BOOL ImmSetCandidateWindow(

HIMC  hIMC,
LPCANDIDATEFORM  lpCandidate
);
Parameters

hIMC

Handle to the input context.

lpCandidate

Pointer to the CANDIDATEFORM structure that contains information about the candidate window.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

ImmSetCandidateWindow causes an IMN_SETCANDIDATEPOS message to be sent to the application.

See Also

CANDIDATEFORM


ImmSetCompositionFont [New - Windows 95]
ImmSetCompositionFont  QuickInfo  Overview  Group

[New - Windows 95]

The ImmSetCompositionFont function sets the logical font to be used to display characters in the composition window.

BOOL ImmSetCompositionFont(

HIMC  hIMC,
LPLOGFONT  lplf
);
Parameters

hIMC

Handle to the input context.

lplf

Pointer to the LOGFONT structure containing the font information to set.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

Even if an application never uses the composition window, it must set the appropriate font to ensure that characters are displayed properly. This is especially true for vertical writing.

This function causes a IMN_SETCOMPOSITIONFONT message to be sent to the application.

See Also

IMN_SETCOMPOSITIONFONT, LOGFONT


ImmSetCompositionString [New - Windows 95]
ImmSetCompositionString  QuickInfo  Overview  Group

[New - Windows 95]

The ImmSetCompositionString function sets the characters, attributes, and clauses of the composition and reading strings.

BOOL ImmSetCompositionString(

HIMC  hIMC,
DWORD  dwIndex,
LPCVOID  lpComp,
DWORD  dwCompLen,
LPCVOID  lpRead,
DWORD  dwReadLen
);
Parameters

hIMC

Handle to the input context.

dwIndex

Type of information to set. This parameter can be one of one of the following values:

Value	Meaning
SCS_SETSTR	Sets the composition string, the reading string, or both. At least one of the lpComp and lpRead parameters must point to a valid string. If either string is too long, the IME truncates it.
SCS_CHANGEATTR	Sets attributes for the composition string, the reading string, or both. At least one of the lpComp and lpRead parameters must point to a valid attribute array.
SCS_CHANGECLAUSE	Sets the clause information for the composition string, the reading string, or both. At least one of the lpComp and lpRead parameters must point to a valid clause information array.
lpComp

Pointer to the buffer containing the information to set for the composition string. The information is as specified by the dwIndex value.

dwCompLen

Size in bytes of the information buffer for the composition string.

lpRead

Pointer to the buffer containing the information to set for the reading string. The information is as specified by the dwIndex value.

dwReadLen

Size, in bytes, of the information buffer for the reading string.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

When changing attributes, all characters in a clause must have the same attribute. Converted characters must be either ATTR_CONVERTED or ATTR_TARGET_CONVERTED; unconverted characters either ATTR_INPUT or ATTR_TARGET_NOTCONVERTED.

When changing clause information, only the target clause can be changed and only one boundary of the clause can be changed at a time. The target clause has the ATTR_TARGET_CONVERTED or ATTR_TARGET_NOTCONVERTED attribute.

When the IME completes the changes, it sends a WM_IME_COMPOSITION message to the application notifying it of the changes.

See Also

WM_IME_COMPOSITION


ImmSetCompositionWindow [New - Windows 95]
ImmSetCompositionWindow  QuickInfo  Overview  Group

[New - Windows 95]

The ImmSetCompositionWindow function sets the position of the composition window.

BOOL ImmSetCompositionWindow(

HIMC  hIMC,
LPCOMPOSITIONFORM  lpCompForm
);
Parameters

hIMC

Handle to the input context.

lpCompForm

Pointer to the COMPOSITIONFORM structure that contains the new position and other related information about the composition window.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

The ImmSetCompositionWindow function causes a IMN_SETSCOMPOSITIONWINDOW message to be sent to the application.

See Also

COMPOSITIONFORM


ImmSetConversionStatus [New - Windows 95]
ImmSetConversionStatus  QuickInfo  Overview  Group

[New - Windows 95]

The ImmSetConversionStatus function sets the current conversion status.

BOOL ImmSetConversionStatus(

HIMC  hIMC,
DWORD  fdwConversion,
DWORD  fdwSentence
);
Parameters

hIMC

Handle to the input context.

fdwConvStatus

Conversion mode values. For more information, see the "IME Conversion Mode Values" table in Input Method Editor Constants.

fdwSentence

Sentence mode values. For more information, see the "IME Sentence Mode Values" table in Input Method Editor Constants.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

This function sends a IMN_SETCONVERSIONSTATUS message to the application.


ImmSetOpenStatus [New - Windows 95]
ImmSetOpenStatus  QuickInfo  Overview  Group

[New - Windows 95]

The ImmSetOpenStatus function opens or closes the IME.

BOOL ImmSetOpenStatus(

HIMC  hIMC,
BOOL  fOpen
);
Parameters

hIMC

Handle to the input context.

fOpen

Open flag. If TRUE, the IME is opened; otherwise, it is closed.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

This function causes a IMN_SETOPENSTATUS message to be sent to the application.

See Also

IMN_SETOPENSTATUS


ImmSetStatusWindowPos [New - Windows 95]
ImmSetStatusWindowPos  QuickInfo  Overview  Group

[New - Windows 95]

The ImmSetStatusWindowPos function sets the position of the status window.

BOOL ImmSetStatusWindowPos(

HIMC  hIMC,
LPPOINT  lpptPos
);
Parameters

hIMC

Handle to the input context.

lpptPos

Pointer to the POINT structure that receives the new position of the status window.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

The ImmSetStatusWindowPos function causes a IMN_SETSTATUSWINDOWPOS message to be sent to the application.

See Also

IMN_SETSTATUSWINDOWPOS, POINT


ImmSimulateHotKey [New - Windows 95]
ImmSimulateHotKey  QuickInfo  Overview  Group

[New - Windows 95]

The ImmSimulateHotKey function simulates the specified IME hot key, causing the same response as if the user had pressed the hot key in the specified window.

BOOL ImmSimulateHotKey(

HWND  hWnd,
DWORD  dwHotKeyID
);
Parameters

hWnd

Handle to the window.

dwHotKeyID

Identifier of the IME hot key. Can be one of the values specified in the "IME Hot Key Identifiers" table in Input Method Editor Constants.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.


ImmUnregisterWord [New - Windows 95]
ImmUnregisterWord  QuickInfo  Overview  Group

[New - Windows 95]

The ImmUnregisterWord function removes a register string from the dictionary of the IME associated with the specified keyboard layout.

BOOL ImmUnregisterWord(

HKL  hKL,
LPCTSTR  lpszReading,
DWORD  dwStyle,
LPCTSTR  lpszUnregister
);
Parameters

hKL

Handle to the keyboard layout.

lpszReading

Pointer to a null-terminated string specifying the reading string associated with the string to remove.

dwStyle

Style of the register string. Can be IME_REGWORD_STYLE_EUDC to indicate the string is in the EUDC range, or any value in the reserved range IME_REGWORD_STYLE_USER_FIRST to IME_REGWORD_STYLE_USER_LAST to indicate a private style maintained by the specified IME.

lpszUnregister

Pointer to a null-terminated string specifying the register string to remove.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.


ImpersonateDdeClientWindow
ImpersonateDdeClientWindow  QuickInfo  Overview  Group

The ImpersonateDdeClientWindow function enables a DDE server application to impersonate a DDE client application's security context in order to protect secure server data from unauthorized DDE clients.

BOOL ImpersonateDdeClientWindow(

HWND  hWndClient,	// handle of DDE client window
HWND  hWndServer	// handle of DDE server window
);
Parameters

hWndClient

Identifies the DDE client window to impersonate. The client window must have established a DDE conversation with the server window identified by the hWndServer parameter.

hWndServer

Identifies the DDE server window. An application must create the server window before calling this function.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

An application should call the RevertToSelf function to undo the impersonation set by the ImpersonateDdeClientWindow function.

A DDEML application should use the DdeImpersonateClient function.

See Also

DdeImpersonateClient, RevertToSelf


ImpersonateLoggedOnUser [New - Windows NT]
ImpersonateLoggedOnUser  QuickInfo

[New - Windows NT]

The ImpersonateLoggedOnUser function lets the calling thread impersonate a user. The user is represented by a token handle obtained by calling the LogonUser function.

BOOL ImpersonateLoggedOnUser(

HANDLE hToken	// handle to a token that represents a logged-on user
);
Parameters

hToken

Handle to a token that represents a logged-on user. You obtain this token handle by calling the LogonUser function.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError .

Remarks

The impersonation lasts until the thread exits or until it calls RevertToSelf. Only token handles from LogonUser can be supplied to this function. If a thread opens its token and then tries to use that token in this call, it will fail with ERROR_BAD_TOKEN_TYPE.

See Also

CreateProcessAsUser, LogonUser


ImpersonateNamedPipeClient
ImpersonateNamedPipeClient  QuickInfo  Overview  Group

The ImpersonateNamedPipeClient function impersonates a named-pipe client application.

BOOL ImpersonateNamedPipeClient(

HANDLE  hNamedPipe	// handle of a named pipe
);
Parameters

hNamedPipe

Identifies a named pipe.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError function.

Remarks

The ImpersonateNamedPipeClient function allows the server end of a named pipe to impersonate the client end. When this function is called, the named-pipe file system changes the thread of the calling process to start impersonating the security context of the last message read from the pipe. Only the server end of the pipe can call this function.

The server can call the RevertToSelf function when the impersonation is complete.

See Also

DdeImpersonateClient, DuplicateToken, RevertToSelf


ImpersonateSelf
ImpersonateSelf  QuickInfo  Overview  Group

The ImpersonateSelf function obtains an access token that impersonates the security context of the calling process. The token is assigned to the calling thread.

BOOL ImpersonateSelf(

SECURITY_IMPERSONATION_LEVEL  ImpersonationLevel	// impersonation level
);
Parameters

ImpersonationLevel

Specifies a SECURITY_IMPERSONATION_LEVEL enumerated type that supplies the impersonation level of the new token.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The ImpersonateSelf function is used for tasks, such as enabling a privilege for a single thread rather than for the entire process or for changing the default discretionary access-control list for a single thread.

The server can call the RevertToSelf function when the impersonation is complete.

See Also

DuplicateToken, ImpersonateNamedPipeClient, RevertToSelf, SECURITY_IMPERSONATION_LEVEL


inet_addr
inet_addr  QuickInfo

The Windows Sockets inet_addr function converts a string containing a dotted address into an in_addr.

unsigned long inet_addr (

const char FAR * cp
);
Parameters

cp

A character string representing a number expressed in the Internet standard "." notation.

Return Value

If no error occurs, inet_addr returns an unsigned long containing a suitable binary representation of the Internet address given. If the passed-in string does not contain a legitimate Internet address (for example, if a portion of an "a.b.c.d" address exceeds 255), inet_addr returns the value INADDR_NONE.

Remarks

This function interprets the character string specified by the cp parameter. This string represents a numeric Internet address expressed in the Internet standard "." notation. The value returned is a number suitable for use as an Internet address. All Internet addresses are returned in network order (bytes ordered from left to right).

Internet Addresses

Values specified using the "." notation take one of the following forms:

          a.b.c.d          a.b.c          a.b          a

When four parts are specified, each is interpreted as a byte of data and assigned, from left to right, to the four bytes of an Internet address. Note that when an Internet address is viewed as a 32-bit integer quantity on the Intel architecture, the bytes referred to above appear as "d.c.b.a". That is, the bytes on an Intel processor are ordered from right to left.

Note  The following notations are used only by Berkeley and nowhere else on the Internet. In the interests of compatibility with their software, the Berkeley notations are supported as specified.

When a three-part address is specified, the last part is interpreted as a 16-bit quantity and placed in the right most two bytes of the network address. This makes the three-part address format convenient for specifying Class B network addresses as "128.net.host".

When a two-part address is specified, the last part is interpreted as a 24-bit quantity and placed in the right-most three bytes of the network address. This makes the two-part address format convenient for specifying Class A network addresses as "net.host".

When only one part is given, the value is stored directly in the network address without any byte rearrangement.

See Also

inet_ntoa


inet_ntoa
inet_ntoa  QuickInfo

The Windows Sockets inet_ntoa function converts a network address into a string in dotted format.

char FAR * inet_ntoa (

struct in_addr in
);
Parameters

in

A structure that represents an Internet host address.

Return Value

If the function succeeds, inet_ntoa returns a char pointer to a static buffer containing the text address in standard "." notation.

If the function fails, it returns NULL. The data should be copied before another Windows Sockets call is made.

Remarks

This function takes an Internet address structure specified by the in parameter. It returns an ASCII string representing the address in "." notation as "a.b.c.d". Note that the string returned by inet_ntoa resides in memory allocated by the Windows Sockets implementation. If the application needs to use the memory differently, it should copy the information to a private application buffer. The data is guaranteed to be valid until the next Windows Sockets function call within the same thread, but no longer.

See Also

inet_addr


InflateRect
InflateRect  QuickInfo  Overview  Group

The InflateRect function increases or decreases the width and height of the specified rectangle. The InflateRect function adds dx units to the left and right ends of the rectangle and dy units to the top and bottom. The dx and dy parameters are signed values; positive values increase the width and height, and negative values decrease them.

BOOL InflateRect(

LPRECT  lprc,	// address of rectangle
int  dx,	// amount to increase or decrease width
int  dy	// amount to increase or decrease height
);
Parameters

lprc

Points to the RECT structure that increases or decreases in size.

dx

Specifies the amount to increase or decrease the rectangle width. This parameter must be negative to decrease the width.

dy

Specifies the amount to increase or decrease the rectangle height. This parameter must be negative to decrease the height.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

IntersectRect, OffsetRect, RECT, UnionRect


InitAtomTable
InitAtomTable  QuickInfo  Overview  Group

The InitAtomTable function initializes the local atom table and sets it to the specified size.

BOOL InitAtomTable(

DWORD  nSize	// size of atom table
);
Parameters

nSize

Specifies the size, in table entries, of the atom table. This value should be a prime number.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

An application need not use this function to use a local atom table. The default size of the local and global atom tables is 37 table entries. If an application does use InitAtomTable, however, it should call the function before any other atom-management function.

If an application uses a large number of local atoms, it can reduce the time required to add an atom to the local atom table or to find an atom in the table by increasing the size of the table. However, this increases the amount of memory required to maintain the table.

The size of the global atom table cannot be changed.

See Also

AddAtom, DeleteAtom, FindAtom, GetAtomName, GlobalAddAtom, GlobalDeleteAtom, GlobalFindAtom, GlobalGetAtomName


InitCommonControls [New - Windows NT]
InitCommonControls  QuickInfo  Overview  Group

[New - Windows NT]

The InitCommonControls function ensures that the common control dynamic-link library (DLL) is loaded.

void InitCommonControls(VOID);

Return Value

This function does not return a value.


InitializeAcl
InitializeAcl  QuickInfo  Overview  Group

The InitializeAcl function creates a new ACL structure.

An ACL is an access-control list.

BOOL InitializeAcl(

PACL  pAcl,	// address of access-control list
DWORD  nAclLength,	// size of access-control list
DWORD  dwAclRevision	// revision level of access-control list
);
Parameters

pAcl

Points to an ACL structure initialized by this function.

nAclLength

Specifies the length, in bytes, of the buffer pointed to by the pAcl parameter. This value must be large enough to contain the ACL header and all of the access-control entries (ACEs) to be stored in the ACL.

When calculating the size of an ACL, note that each ACE in an ACL gets the SID specified by its SidStart member copied to the ACE structure, starting at the ACE's SidStart member. Thus, each ACE added to the ACL requires room for the ACE plus room for its SID minus the size of the SidStart member (a DWORD).

For example, the size of an ACL buffer large enough to contain a single ACCESS_ALLOWED_ACE is :

    cbAcl =    sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE)

             + GetLengthSid(pSid) - sizeof(DWORD) ;

Another example: the size of an ACL buffer large enough to contain seven ACCESS_DENIED_ACE structures is :

    cbAcl =  sizeof(ACL) +  7 * ( sizeof(ACCESS_DENIED_ACE) - sizeof(DWORD)) +

             GetLengthSid(pSid1) + GetLengthSid(pSid2) + ... + GetLengthSid(pSid7)

dwAclRevision

Specifies the revision level of the ACL. This parameter must be set to the current revision level, defined as ACL_REVISION for this version of Windows.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The ACL initialized by this function contains no ACEs. It is empty, as opposed to being a nonexistent ACL. If an empty ACL is applied to an object, it implicitly denies all access to that object.

See Also

ACCESS_ALLOWED_ACE, ACCESS_DENIED_ACE, ACL, AddAccessAllowedAce, AddAccessDeniedAce, AddAce, AddAuditAccessAce, DeleteAce, GetAce, GetAclInformation, IsValidAcl, SetAclInformation, SID,


InitializeCriticalSection
InitializeCriticalSection  QuickInfo  Overview  Group

The InitializeCriticalSection function initializes a critical section object.

VOID InitializeCriticalSection(

LPCRITICAL_SECTION  lpCriticalSection	// address of critical section object
);
Parameters

lpCriticalSection

Points to the critical section object.

Return Value

This function does not return a value.

Remarks

The threads of a single process can use a critical section object for mutual-exclusion synchronization. The process is responsible for allocating the memory used by a critical section object, which it can do by declaring a variable of type CRITICAL_SECTION. Before using a critical section, some thread of the process must call the InitializeCriticalSection function to initialize the object.

Once a critical section object has been initialized, the threads of the process can specify the object in the EnterCriticalSection and LeaveCriticalSection functions to provide mutually exclusive access to a shared resource. For similar synchronization between the threads of different processes, use a mutex object.

A critical section object cannot be moved or copied. The process must also not modify the object, but must treat it as logically opaque. Use only the functions provided in the Win32 application programming interface (API) to manage critical section objects.

See Also

CreateMutex, DeleteCriticalSection, EnterCriticalSection, LeaveCriticalSection


InitializeSecurityDescriptor
InitializeSecurityDescriptor  QuickInfo  Overview  Group

The InitializeSecurityDescriptor function initializes a new security descriptor.

BOOL InitializeSecurityDescriptor(

PSECURITY_DESCRIPTOR  pSecurityDescriptor,	// address of security descriptor
DWORD  dwRevision	// revision level
);
Parameters

pSecurityDescriptor

Points to a SECURITY_DESCRIPTOR structure that the function initializes.

dwRevision

Specifies the revision level to assign to the security descriptor. This must be SECURITY_DESCRIPTOR_REVISION.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The InitializeSecurityDescriptor function initializes a security descriptor in absolute format, rather than self-relative format.

The InitializeSecurityDescriptor function initializes a security descriptor to have no system ACL, no discretionary ACL, no owner, no primary group, and all control flags set to FALSE (NULL). Thus, except for its revision level, it is empty.

See Also

GetSecurityDescriptorControl, GetSecurityDescriptorDacl, GetSecurityDescriptorGroup, GetSecurityDescriptorLength, GetSecurityDescriptorOwner, GetSecurityDescriptorSacl, IsValidSecurityDescriptor, SECURITY_DESCRIPTOR, SetSecurityDescriptorDacl, SetSecurityDescriptorGroup, SetSecurityDescriptorOwner, SetSecurityDescriptorSacl


InitializeSid
InitializeSid  QuickInfo  Overview  Group

The InitializeSid function initializes a SID structure. An SID is a security identifier.

BOOL InitializeSid(

PSID  Sid,	// address of SID to initialize
PSID_IDENTIFIER_AUTHORITY  pIdentifierAuthority,	// address of identifier authority
BYTE  nSubAuthorityCount	// count of subauthorities
);
Parameters

Sid

Points to a SID structure to be initialized.

pIdentifierAuthority

Points to a SID_IDENTIFIER_AUTHORITY structure to set in the SID structure.

nSubAuthorityCount

Specifies the number of subauthorities to set in the SID. Values of the subauthority must be set separately, as described in the following Remarks section.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Although the InitializeSid function sets the number of subauthorities for the SID, it does not set the subauthority values. This must be done separately, using functions, such as GetSidSubAuthority.

An application can use the AllocateAndInitializeSid function to initialize a SID and set its subauthority values.

See Also

AllocateAndInitializeSid, GetLengthSid, GetSidIdentifierAuthority, GetSidLengthRequired, GetSidSubAuthority, GetSidSubAuthorityCount, IsValidSid, SID, SID_IDENTIFIER_AUTHORITY


InitiateSystemShutdown
InitiateSystemShutdown  QuickInfo  Overview  Group

The InitiateSystemShutdown function initiates a shutdown and optional restart of the specified computer.

BOOL InitiateSystemShutdown(

LPTSTR  lpMachineName,	// address of name of computer to shut down
LPTSTR  lpMessage,	// address of message to display in dialog box
DWORD  dwTimeout,	// time to display dialog box
BOOL  bForceAppsClosed,	// force applications with unsaved changes flag
BOOL  bRebootAfterShutdown	// reboot flag
);
Parameters

lpMachineName

Points to the null-terminated string that specifies the network name of the computer to shut down. If lpMachineName is NULL or points to an empty string, the function shuts down the local computer.

lpMessage

Points to a null-terminated string that specifies a message to display in the shutdown dialog box. This parameter can be NULL if no message is required.

dwTimeout

Specifies the time (in seconds) that the dialog box should be displayed. While this dialog box is displayed, the shutdown can be stopped by the AbortSystemShutdown function.

If dwTimeout is not zero, InitiateSystemShutdown displays a dialog box on the specified computer. The dialog box displays the name of the user who called the function, displays the message specified by the lpMessage parameter, and prompts the user to log off. The dialog box beeps when it is created and remains on top of other windows in the system. The dialog box can be moved but not closed. A timer counts down the remaining time before a forced shutdown. If the user logs off, the system shuts down immediately. Otherwise, the computer is shut down when the timer expires.

If dwTimeout is zero, the computer shuts down without displaying the dialog box, and the shutdown cannot be stopped by AbortSystemShutdown.

bForceAppsClosed

Specifies whether applications with unsaved changes are to be forcibly closed. If this parameter is TRUE, such applications are closed. If this parameter is FALSE, a dialog box is displayed prompting the user to close the applications.

bRebootAfterShutdown

Specifies whether the computer is to restart immediately after shutting down. If this parameter is TRUE, the computer is to restart. If this parameter is FALSE, the system flushes all caches to disk, clears the screen, and displays a message indicating that it is safe to power down.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

To shut down the local computer, the calling process must have the SE_SHUTDOWN_NAME privilege. To shut down a remote computer, the calling process must have the SE_REMOTE_SHUTDOWN_NAME privilege on the remote computer. By default, users can enable the SE_SHUTDOWN_NAME privilege on the computer they are logged onto, and administrators can enable the SE_REMOTE_SHUTDOWN_NAME privilege on remote computers.

Common failures include an invalid or inaccessible computer name or insufficient privilege.

See Also

AbortSystemShutdown


InSendMessage
InSendMessage  QuickInfo  Overview  Group

The InSendMessage function specifies whether the current window procedure is processing a message that was sent from another thread by a call to the SendMessage function.

BOOL InSendMessage(VOID)

Parameters

This function has no parameters.

Return Value

If the window procedure is processing a message sent to it from another thread by the SendMessage function, the return value is TRUE; otherwise, the return value is FALSE.

See Also

PostThreadMessage, ReplyMessage, SendMessage


InsertMenu
InsertMenu  QuickInfo  Overview  Group

The InsertMenu function inserts a new menu item into a menu, moving other items down the menu.

BOOL InsertMenu(

HMENU hMenu,	// handle of menu
UINT uPosition,	// menu item that new menu item precedes
UINT uFlags,	// menu item flags
UINT uIDNewItem,	// menu item identifier or pop-up menu handle
LPCTSTR lpNewItem	// menu item content
);
Parameters

hMenu

Identifies the menu to be changed.

uPosition

Specifies the menu item before which the new menu item is to be inserted, as determined by the uFlags parameter.

uFlags

Specifies flags that control the interpretation of the uPosition parameter and the content, appearance, and behavior of the new menu item. This parameter must be a combination of one of the following required values and at least one of the values listed in the following Remarks section.

Value	Description
MF_BYCOMMAND	Indicates that the uPosition parameter gives the identifier of the menu item. The MF_BYCOMMAND flag is the default if neither the MF_BYCOMMAND nor MF_BYPOSITION flag is specified.
MF_BYPOSITION	Indicates that the uPosition parameter gives the zero-based relative position of the new menu item. If uPosition is 0xFFFFFFFF, the new menu item is appended to the end of the menu.
uIDNewItem

Specifies either the identifier of the new menu item or, if the uFlags parameter has the MF_POPUP flag set, the handle of the pop-up menu.

lpNewItem

Specifies the content of the new menu item. The interpretation of lpNewItem depends on whether the uFlags parameter includes the MF_BITMAP, MF_OWNERDRAW, or MF_STRING flag, as follows:

Value	Description
MF_BITMAP	Contains a bitmap handle.
MF_OWNERDRAW	Contains a 32-bit value supplied by the application that can be used to maintain additional data related to the menu item. The value is in the itemData member of the structure pointed to by the lparam parameter of the WM_MEASUREITEM or WM_DRAWITEM message sent when the menu item is created or its appearance is updated.
MF_STRING	Contains a pointer to a null-terminated string (the default).
Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The application must call the DrawMenuBar function whenever a menu changes, whether or not the menu is in a displayed window.

The following list describes the flags that can be set in the uFlags parameter:

Value	Description
MF_BITMAP	Uses a bitmap as the menu item. The lpNewItem parameter contains the handle of the bitmap.
MF_CHECKED	Places a check mark next to the menu item. If the application provides check mark bitmaps (see SetMenuItemBitmaps), this flag displays the check mark bitmap next to the menu item.
MF_DISABLED	Disables the menu item so that it cannot be selected, but does not gray it.
MF_ENABLED	Enables the menu item so that it can be selected and restores it from its grayed state.
MF_GRAYED	Disables the menu item and grays it so it cannot be selected.
MF_MENUBARBREAK	Functions the same as the MF_MENUBREAK flag except for pop-up menus where the new column is separated from the old column by a vertical line.
MF_MENUBREAK	Places the item on a new line (for menu bars) or in a new column (for pop-up menus) without separating columns.
MF_OWNERDRAW	Specifies that the item is an owner-drawn item. Before the menu is displayed for the first time, the window that owns the menu receives a WM_MEASUREITEM message to retrieve the width and height of the menu item. The WM_DRAWITEM message is then sent to the window procedure of the owner window whenever the appearance of the menu item must be updated.
MF_POPUP	Specifies that the menu item is a pop-up item; that is, selecting it activates a pop-up menu. The uIDNewItem parameter specifies the handle of the pop-up menu. This flag is used to add a pop-up item to a menu bar or to a pop-up menu.
MF_SEPARATOR	Draws a horizontal dividing line. This flag is used only in a pop-up menu. The dividing line cannot be grayed, disabled, or highlighted. The lpNewItem and uIDNewItem parameters are ignored.
MF_STRING	Specifies that the menu item is a text string; the lpNewItem parameter points to the string.
MF_UNCHECKED	Does not place a check mark next to the menu item (default). If the application supplies check mark bitmaps (see the SetMenuItemBitmaps function), this flag displays the unchecked bitmap next to the menu item.
The following list shows groups of flags that cannot be used together:

•	MF_BYCOMMAND and MF_BYPOSITION

•	MF_DISABLED, MF_ENABLED, and MF_GRAYED

•	MF_BITMAP, MF_STRING, MF_OWNERDRAW, and MF_SEPARATOR

•	MF_MENUBARBREAK and MF_MENUBREAK

•	MF_CHECKED and MF_UNCHECKED

See Also

AppendMenu, DeleteMenu, DrawMenuBar, ModifyMenu, RemoveMenu, SetMenuItemBitmaps, WM_DRAWITEM, WM_MEASUREITEM


InsertMenuItem [New - Windows 95]
InsertMenuItem  QuickInfo  Overview  Group

[New - Windows 95]

The InsertMenuItem function inserts a new menu item at the specified position in a menu bar or pop-up menu.

BOOL WINAPI InsertMenuItem(

HMENU  hMenu,
UINT  uItem,
BOOL  fByPosition,
LPMENUITEMINFO  lpmii
);
Parameters

hMenu

Handle to the menu in which the new menu item is inserted.

uItem

Identifier or position of the menu item before which to insert the new item. The meaning of this parameter depends on the value of fByPosition.

fByPosition

Value specifying the meaning of uItem. If this parameter is FALSE, uItem is a menu item identifier. Otherwise, it is a menu item position.

lpmii

Pointer to a MENUITEMINFO structure that contains information about the new menu item.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, use the GetLastError function.

See Also

MENUITEMINFO


Int32x32To64
Int32x32To64  QuickInfo  Overview  Group

The Int32x32To64 function multiplies two signed 32-bit integers, returning a signed 64-bit integer result. The function performs optimally on all Win32 platforms.

LONGLONG Int32x32To64(

LONG  Multiplier,	// specifies first signed 32-bit integer for the multiplication
LONG  Multiplicand	// specifies second signed 32-bit integer for the multiplication
);
Parameters

Multiplier

Specifies the first signed 32-bit integer for the multiplication.

Multiplicand

Specifies the second signed 32-bit integer for the multiplication.

Return Value

The return value is the signed 64-bit integer result of the multiplication.

Remarks

This function is implemented on all platforms by optimal inline code: a single multiply instruction that returns a 64-bit result.

Please note that the function's return value is a 64-bit value, not a LARGE_INTEGER structure.

See Also

UInt32x32To64


Int64ShllMod32
Int64ShllMod32  QuickInfo  Overview  Group

The Int64ShllMod32 function performs a left logical shift operation on an unsigned 64-bit integer value. The function provides improved shifting code for left logical shifts where the shift count is in the range 0 − 31.

DWORDLONG Int64ShllMod32(

DWORDLONG  Value,	// specifies unsigned 64-bit integer to shift left logically
DWORD  ShiftCount	// specifies a shift count in the range 0 − 31
);
Parameters

Value

Specifies the unsigned 64-bit integer to be shifted.

ShiftCount

Specifies a shift count in the range 0 − 31.

Return Value

The return value is the unsigned 64-bit integer result of the left logical shift operation.

Remarks

The shift count is the number of bit positions that the value's bits move.

In a left logical shift operation on an unsigned value, the value's bits move to the left, and vacated bits on the right side of the value are set to zero.

A compiler can generate optimal code for a left logical shift operation when the shift count is a constant. However, if the shift count is a variable whose range of values is unknown, the compiler must assume the worst case, leading to non-optimal code: code that calls a subroutine, or code that is inline but branches. By restricting the shift count to the range 0 − 31, the Int64ShllMod32 function lets the compiler generate optimal or near-optimal code.

Please note that the Int64ShllMod32 function's Value parameter and return value are 64-bit values, not LARGE_INTEGER structures.

See Also

Int64ShraMod32, Int64ShrlMod32


Int64ShraMod32
Int64ShraMod32  QuickInfo  Overview  Group

The Int64ShraMod32 function performs a right arithmetic shift operation on a signed 64-bit integer value. The function provides improved shifting code for right arithmetic shifts where the shift count is in the range 0 − 31.

LONGLONG Int64ShraMod32(

LONGLONG  Value,	// specifies signed 64-bit integer to shift right arithmetically
DWORD  ShiftCount	// specifies a shift count in the range 0 − 31
);
Parameters

Value

Specifies the signed 64-bit integer to be shifted.

ShiftCount

Specifies a shift count in the range 0 − 31.

Return Value

The return value is the signed 64-bit integer result of the right arithmetic shift operation.

Remarks

The shift count is the number of bit positions that the value's bits move.

In a right arithmetic shift operation on a signed value, the value's bits move to the right, and vacated bits on the left side of the value are set to the value of the sign bit.

A compiler can generate optimal code for a right arithmetic shift operation when the shift count is a constant. However, if the shift count is a variable whose range of values is unknown, the compiler must assume the worst case, leading to non-optimal code: code that calls a subroutine, or code that is inline but branches. By restricting the shift count to the range 0 − 31, the Int64ShraMod32 function lets the compiler generate optimal or near-optimal code.

Please note that the Int64ShraMod32 function's Value parameter and return value are 64-bit values, not LARGE_INTEGER structures.

See Also

Int64ShllMod32, Int64ShrlMod32


Int64ShrlMod32
Int64ShrlMod32  QuickInfo  Overview  Group

The Int64ShrlMod32 function performs a right logical shift operation on an unsigned 64-bit integer value. The function provides improved shifting code for right logical shifts where the shift count is in the range 0 − 31.

DWORDLONG Int64ShrlMod32(

DWORDLONG  Value,	// specifies unsigned 64-bit integer to shift right logically
DWORD  ShiftCount	// specifies a shift count in the range 0 − 31
);
Parameters

Value

Specifies the unsigned 64-bit integer to be shifted.

ShiftCount

Specifies a shift count in the range 0 − 31.

Return Value

The return value is the unsigned 64-bit integer result of the right logical shift operation.

Remarks

The shift count is the number of bit positions that the value's bits move.

In a right logical shift operation on an unsigned value, the value's bits move to the right, and vacated bits on the left side of the value are set to zero.

A compiler can generate optimal code for a right logical shift operation when the shift count is a constant. However, if the shift count is a variable whose range of values is unknown, the compiler must assume the worst case, leading to non-optimal code: code that calls a subroutine, or code that is inline but branches. By restricting the shift count to the range 0 − 31, the Int64ShrlMod32 function lets the compiler generate optimal or near-optimal code.

Please note that the Int64ShrlMod32 function's Value parameter and return value are 64-bit values, not LARGE_INTEGER structures.

See Also

Int64ShllMod32, Int64ShraMod32


InterlockedDecrement
InterlockedDecrement  QuickInfo  Overview  Group

The InterlockedDecrement function both decrements (decreases by one) the value of the specified 32-bit variable and checks the resulting value. The function prevents more than one thread from using the InterlockedDecrement or InterlockedIncrement function to access the same variable simultaneously.

LONG InterlockedDecrement(

LPLONG  lpAddend	// address of the variable to decrement
);
Parameters

lpAddend

Points to the 32-bit variable to decrement.

Return Value

If the result of the decrement is zero, the return value is zero.

If the result of the decrement is less than zero, the return value is less than zero. If the result of the decrement is greater than zero, the return value is greater than zero. A nonzero return value may not be equal to the result of the decrement.

Remarks

InterlockedDecrement, InterlockedExchange, and InterlockedIncrement provide a simple mechanism for synchronizing access to a variable that is shared by multiple threads. The threads of different processes can use this mechanism if the variable is in shared memory.

The variable pointed to by the lpAddend parameter must be aligned on a 32-bit boundary; otherwise, this function will fail on multiprocessor x86 systems.

See Also

InterlockedExchange, InterlockedIncrement


InterlockedExchange
InterlockedExchange  QuickInfo  Overview  Group

The InterlockedExchange function atomically exchanges a pair of 32-bit values.

LONG InterlockedExchange(

LPLONG  Target,	// address of 32-bit value to exchange
LONG  Value	// new value for the LONG value pointed to by Target
);
Parameters

Target

Address of the LONG value to exchange. The function sets this LONG value to Value, and returns its prior value.

Value

Specifies a new value for the LONG value pointed to by Target.

Return Value

The function returns the prior value of the LONG value pointed to by Target.

Remarks

InterlockedExchange, InterlockedDecrement, and InterlockedIncrement provide a simple mechanism for synchronizing access to a variable that is shared by multiple threads. The threads of different processes can use this mechanism if the variable is in shared memory.

The variable pointed to by the Target parameter must be aligned on a 32-bit boundary; otherwise, this function will fail on multiprocessor x86 systems.

See Also

InterlockedDecrement, InterlockedIncrement


InterlockedIncrement
InterlockedIncrement  QuickInfo  Overview  Group

The InterlockedIncrement function both increments (increases by one) the value of the specified 32-bit variable and checks the resulting value. The function prevents more than one thread from using the InterlockedDecrement or InterlockedIncrement function to access the same variable simultaneously.

LONG InterlockedIncrement(

LPLONG  lpAddend	// address of the variable to increment
);
Parameters

lpAddend

Points to the 32-bit variable to increment.

Return Value

If the result of the increment is zero, the return value is zero.

If the result of the increment is less than zero, the return value is less than zero. If the result of the increment is greater than zero, the return value is greater than zero. A nonzero return value may not be equal to the result of the increment.

Remarks

InterlockedDecrement, InterlockedIncrement, and InterlockedExchange provide a simple mechanism for synchronizing access to a variable that is shared by multiple threads. The threads of different processes can use this mechanism if the variable is in shared memory.

The variable pointed to by the lpAddend parameter must be aligned on a 32-bit boundary; otherwise, this function will fail on multiprocessor x86 systems.

See Also

InterlockedDecrement, InterlockedExchange


IntersectClipRect
IntersectClipRect  QuickInfo  Overview  Group

The IntersectClipRect function creates a new clipping region from the intersection of the current clipping region and the specified rectangle.

int IntersectClipRect(

HDC  hdc,	// handle of device context
int  nLeftRect,	// x-coordinate of upper-left corner of rectangle
int  nTopRect,	// y-coordinate of upper-left corner of rectangle
int  nRightRect,	// x-coordinate of lower-right corner of rectangle
int  nBottomRect	// y-coordinate of lower-right corner of rectangle
);
Parameters

hdc

Identifies the device context.

nLeftRect

Specifies the logical x-coordinate of the upper-left corner of the rectangle.

nTopRect

Specifies the logical y-coordinate of the upper-left corner of the rectangle.

nRightRect

Specifies the logical x-coordinate of the lower-right corner of the rectangle.

nBottomRect

Specifies the logical y-coordinate of the lower-right corner of the rectangle.

Return Value

If the function succeeds, the return value specifies the new clipping region's type and can be any one of the following values:

Value	Meaning
NULLREGION	Region is empty.
SIMPLEREGION	Region is a single rectangle.
COMPLEXREGION	Region is more than one rectangle.
ERROR	An error occurred. (The current clipping region is unaffected.)
Remarks

The lower and rightmost edges of the given rectangle are excluded from the clipping region.

See Also

ExcludeClipRect


IntersectRect
IntersectRect  QuickInfo  Overview  Group

The IntersectRect function calculates the intersection of two source rectangles and places the coordinates of the intersection rectangle into the destination rectangle. If the source rectangles do not intersect, an empty rectangle (in which all coordinates are set to zero) is placed into the destination rectangle.

BOOL IntersectRect(

LPRECT  lprcDst,	// address of structure for intersection
CONST RECT  * lprcSrc1,	// address of structure with first rectangle
CONST RECT  * lprcSrc2	// address of structure with second rectangle
);
Parameters

lprcDst

Points to the RECT structure that is to receive the intersection of the rectangles pointed to by the lprcSrc1 and lprcSrc2 parameters.

lprcSrc1

Points to the RECT structure that contains the first source rectangle.

lprcSrc2

Points to the RECT structure that contains the second source rectangle.

Return Value

If the rectangles intersect, the return value is TRUE; otherwise, it is FALSE. To get extended error information, call GetLastError.

See Also

InflateRect, OffsetRect, RECT, UnionRect


InvalidateRect
InvalidateRect  QuickInfo  Overview  Group

The InvalidateRect function adds a rectangle to the specified window's update region. The update region represents the portion of the window's client area that must be redrawn.

BOOL InvalidateRect(

HWND  hWnd,	// handle of window with changed update region
CONST RECT  * lpRect,	// address of rectangle coordinates
BOOL  bErase	// erase-background flag
);
Parameters

hWnd

Identifies the window whose update region has changed. If this parameter is NULL, Windows invalidates and redraws all windows, and sends the WM_ERASEBKGND and WM_NCPAINT messages to the window procedure before the function returns.

lpRect

Points to a RECT structure that contains the client coordinates of the rectangle to be added to the update region. If this parameter is NULL, the entire client area is added to the update region.

bErase

Specifies whether the background within the update region is to be erased when the update region is processed. If this parameter is TRUE, the background is erased when the BeginPaint function is called. If this parameter is FALSE, the background remains unchanged.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

The invalidated areas accumulate in the update region until the region is processed when the next WM_PAINT message occurs or until the region is validated by using the ValidateRect or ValidateRgn function.

Windows sends a WM_PAINT message to a window whenever its update region is not empty and there are no other messages in the application queue for that window.

If the bErase parameter is TRUE for any part of the update region, the background is erased in the entire region, not just in the given part.

See Also

BeginPaint, InvalidateRgn, RECT, ValidateRect, ValidateRgn, WM_ERASEBKGND, WM_NCPAINT, WM_PAINT,


InvalidateRgn
InvalidateRgn  QuickInfo  Overview  Group

The InvalidateRgn function invalidates the client area within the specified region by adding it to the current update region of a window. The invalidated region, along with all other areas in the update region, is marked for painting when the next WM_PAINT message occurs.

BOOL InvalidateRgn(

HWND  hWnd,	// handle of window with changed update region
HRGN  hRgn,	// handle of region to add
BOOL  bErase	// erase-background flag
);
Parameters

hWnd

Identifies the window with an update region that is to be modified.

hRgn

Identifies the region to be added to the update region. The region is assumed to have client coordinates. If this parameter is NULL, the entire client area is added to the update region.

bErase

Specifies whether the background within the update region should be erased when the update region is processed. If this parameter is TRUE, the background is erased when the BeginPaint function is called. If the parameter is FALSE, the background remains unchanged.

Return Value

This function always returns TRUE.

Remarks

Invalidated areas accumulate in the update region until the next WM_PAINT message is processed or until the region is validated by using the ValidateRect or ValidateRgn function.

Windows sends a WM_PAINT message to a window whenever its update region is not empty and there are no other messages in the application queue for that window.

The specified region must have been created by using one of the region functions.

If the bErase parameter is TRUE for any part of the update region, the background in the entire region is erased, not just in the specified part.

See Also

BeginPaint, InvalidateRect, ValidateRect, ValidateRgn, WM_PAINT


InvertRect
InvertRect  QuickInfo  Overview  Group

The InvertRect function inverts a rectangle in a window by performing a logical NOT operation on the color values for each pixel in the rectangle's interior.

BOOL InvertRect(

HDC  hDC,	// handle of device context
CONST RECT  * lprc	// address of structure with rectangle
);
Parameters

hDC

Identifies the device context.

lprc

Points to a RECT structure that contains the logical coordinates of the rectangle to be inverted.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

On monochrome screens, InvertRect makes white pixels black and black pixels white. On color screens, the inversion depends on how colors are generated for the screen. Calling InvertRect twice for the same rectangle restores the display to its previous colors.

See Also

FillRect, RECT


InvertRgn
InvertRgn  QuickInfo  Overview  Group

The InvertRgn function inverts the colors in the specified region.

BOOL InvertRgn(

HDC  hdc,	// handle of device context
HRGN  hrgn	// handle of region to be inverted
);
Parameters

hdc

Identifies the device context.

hrgn

Identifies the region for which colors are inverted. The region's coordinates are presumed to be logical coordinates.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

On monochrome screens, the InvertRgn function makes white pixels black and black pixels white. On color screens, this inversion is dependent on the type of technology used to generate the colors for the screen.

See Also

FillRgn, PaintRgn


IOCTL_DISK_CHECK_VERIFY
IOCTL_DISK_CHECK_VERIFY  QuickInfo  Overview  Group

The IOCTL_DISK_CHECK_VERIFY DeviceIoControl operation determines whether a device's media is accessible; for example, whether the media is in the device.

dwIoControlCode = IOCTL_DISK_CHECK_VERIFY ;   // operation code

lpvInBuffer = NULL;       // address of input buffer; not used; must be NULL

cbInBuffer = 0;           // size of input buffer; not used; must be zero

lpvOutBuffer = NULL;      // address of output buffer; not used; must be NULL

cbOutBuffer = 0;          // size of output buffer; not used; must be zero

lpcbBytesReturned;        // address of actual bytes of output

Parameters

lpvInBuffer

Points to an input buffer. Not used with this operation. Set to NULL.

cbInBuffer

Specifies the size, in bytes, of the buffer pointed to by lpvInBuffer. Not used with this operation. Set to zero.

lpvOutBuffer

Points to an output buffer. Not used with this operation. Set to NULL.

cbOutBuffer

Specifies the size, in bytes, of the buffer pointed to by lpvOutBuffer. Not used with this operation. Set to zero.

lpcbBytesReturned

Points to a DWORD that receives the actual size, in bytes, of the data stored into lpvOutBuffer.

Return Value

If the operation succeeds and the device media is accessible, DeviceIoControl returns TRUE.

If the operation fails, DeviceIoControl returns FALSE.

See Also

DeviceIoControl


IOCTL_DISK_EJECT_MEDIA
IOCTL_DISK_EJECT_MEDIA  QuickInfo  Overview  Group

The IOCTL_DISK_EJECT_MEDIA DeviceIoControl operation causes media to be ejected from a SCSI device.

dwIoControlCode = IOCTL_DISK_EJECT_MEDIA;   // operation code

lpvInBuffer = NULL;       // address of input buffer; not used; must be NULL

cbInBuffer = 0;           // size of input buffer; not used; must be zero

lpvOutBuffer = NULL;      // address of output buffer; not used; must be NULL

cbOutBuffer = 0;          // size of output buffer; not used; must be zero

lpcbBytesReturned;        // address of actual bytes of output

Parameters

lpvInBuffer

Points to an input buffer. Not used with this operation. Set to NULL.

cbInBuffer

Specifies the size, in bytes, of the buffer pointed to by lpvInBuffer. Not used with this operation. Set to zero.

lpvOutBuffer

Points to an output buffer. Not used with this operation. Set to NULL.

cbOutBuffer

Specifies the size, in bytes, of the buffer pointed to by lpvOutBuffer. Not used with this operation. Set to zero.

lpcbBytesReturned

Points to a DWORD that receives the actual size, in bytes, of the data stored into lpvOutBuffer.

Return Value

If the operation succeeds, DeviceIoControl returns TRUE.

If the operation fails, DeviceIoControl returns FALSE. To get extended error information, call GetLastError.

Remarks

IOCTL_DISK_EJECT_MEDIA may or may not be supported on SCSI devices that support removable media.

See Also

DeviceIoControl, IOCTL_DISK_MEDIA_REMOVAL, IOCTL_DISK_LOAD_MEDIA


IOCTL_DISK_FORMAT_TRACKS
IOCTL_DISK_FORMAT_TRACKS  QuickInfo  Overview  Group

The IOCTL_DISK_FORMAT_TRACKS DeviceIoControl operation formats a specified, contiguous set of tracks on a disk.

dwIoControlCode = IOCTL_DISK_FORMAT_TRACKS;   // operation code

lpvInBuffer;              // address of input buffer

cbInBuffer;               // size of input buffer

lpvOutBuffer = NULL;      // address of output buffer; not used; must be NULL

cbOutBuffer = 0;          // size of output buffer; not used; must be zero

lpcbBytesReturned;        // address of actual bytes of output

Parameters

lpvInBuffer

Points to a buffer that contains a FORMAT_PARAMETERS data structure.

cbInBuffer

Specifies the size, in bytes, of the buffer pointed to by lpvInBuffer, which must be large enough to contain a FORMAT_PARAMETERS data structure.

lpvOutBuffer

Points to an output buffer. Not used with this operation. Set to NULL.

cbOutBuffer

Specifies the size, in bytes, of the buffer pointed to by lpvOutBuffer. Not used with this operation. Set to zero.

lpcbBytesReturned

Points to a DWORD that receives the actual size, in bytes, of the data stored into lpvOutBuffer.

Return Value

If the operation succeeds, DeviceIoControl returns TRUE.

If the operation fails, DeviceIoControl returns FALSE. To get extended error information, call GetLastError.

Remarks

This device I/O control operation is for floppy disk devices only.

See Also

DeviceIoControl, FORMAT_PARAMETERS


IOCTL_DISK_GET_DRIVE_GEOMETRY
IOCTL_DISK_GET_DRIVE_GEOMETRY  QuickInfo  Overview  Group

The IOCTL_DISK_GET_DRIVE_GEOMETRY DeviceIoControl operation returns information about the physical disk's geometry: type, number of cylinders, tracks per cylinder, sectors per track, and bytes per sector.

dwIoControlCode = IOCTL_DISK_GET_DRIVE_GEOMETRY;   // operation code

lpvInBuffer = NULL; // address of input buffer; not used; must be NULL

cbInBuffer = 0;     // size of input buffer; not used; must be zero

lpvOutBuffer ;      // address of output buffer

cbOutBuffer ;       // size of output buffer

lpcbBytesReturned ; // address of actual bytes of output

Parameters

lpvInBuffer

Points to an input buffer. Not used with this operation. Set to NULL.

cbInBuffer

Specifies the size, in bytes, of the buffer pointed to by lpvInBuffer. Not used with this operation. Set to zero.

lpvOutBuffer

Points to a buffer that will receive a DISK_GEOMETRY data structure.

cbOutBuffer

Specifies the size, in bytes, of the buffer pointed to by lpvOutBuffer, which must be greater than or equal to the size of a DISK_GEOMETRY data structure.

lpcbBytesReturned

Points to a DWORD that receives the actual size, in bytes, of the data stored into lpvOutBuffer.

Return Value

If the operation succeeds, DeviceIoControl returns TRUE.

If the operation fails, DeviceIoControl returns FALSE. To get extended error information, call GetLastError.

Remarks

This device I/O control operation is for disk devices.

See Also

DeviceIoControl, DISK_GEOMETRY, IOCTL_DISK_GET_MEDIA_TYPES


IOCTL_DISK_GET_DRIVE_LAYOUT
IOCTL_DISK_GET_DRIVE_LAYOUT  QuickInfo  Overview  Group

The IOCTL_DISK_GET_DRIVE_LAYOUT DeviceIoControl operation returns information about the number of partitions on a disk and the features of each partition.

dwIoControlCode = IOCTL_DISK_GET_DRIVE_LAYOUT;   // operation code

lpvInBuffer = NULL; // address of input buffer; not used; must be NULL

cbInBuffer = 0;     // size of input buffer; not used; must be zero

lpvOutBuffer ;      // address of output buffer

cbOutBuffer ;       // size of output buffer

lpcbBytesReturned ; // address of actual bytes of output

Parameters

lpvInBuffer

Points to an input buffer. Not used with this operation. Set to NULL.

cbInBuffer

Specifies the size, in bytes, of the buffer pointed to by lpvInBuffer. Not used with this operation. Set to zero.

lpvOutBuffer

Points to a buffer that will receive a DRIVE_LAYOUT_INFORMATION structure and a series of PARTITION_INFORMATION structures, one of the latter for each partition on the drive.

cbOutBuffer

Specifies the size, in bytes, of the buffer pointed to by lpvOutBuffer, which must be large enough to contain one DRIVE_LAYOUT_INFORMATION data structure and as many PARTITION_INFORMATION data structures as there are partitions on the drive.

lpcbBytesReturned

Points to a DWORD that receives the actual size, in bytes, of the data stored into lpvOutBuffer.

Return Value

If the operation succeeds, DeviceIoControl returns TRUE.

If the operation fails, DeviceIoControl returns FALSE. To get extended error information, call GetLastError.

Remarks

This device I/O control operation is for disk devices. Floppy disk drivers, however, do not need to handle this operation.

See Also

DeviceIoControl, DRIVE_LAYOUT_INFORMATION, IOCTL_DISK_SET_DRIVE_LAYOUT, PARTITION_INFORMATION


IOCTL_DISK_GET_MEDIA_TYPES
IOCTL_DISK_GET_MEDIA_TYPES  QuickInfo  Overview  Group

The IOCTL_DISK_GET_MEDIA_TYPES DeviceIoControl operation returns information about the types of media a device driver supports.

dwIoControlCode = IOCTL_DISK_GET_MEDIA_TYPES;   // operation code

lpvInBuffer = NULL; // address of input buffer; not used; must be NULL

cbInBuffer = 0;     // size of input buffer; not used; must be zero

lpvOutBuffer ;      // address of output buffer

cbOutBuffer ;       // size of output buffer

lpcbBytesReturned;  // address of actual bytes of output

Parameters

lpvInBuffer

Points to an input buffer. Not used with this operation. Set to NULL.

cbInBuffer

Specifies the size, in bytes, of the buffer pointed to by lpvInBuffer. Not used with this operation. Set to zero.

lpvOutBuffer

Points to a buffer that will receive an array of DISK_GEOMETRY data structures specifying the media types the device driver supports.

cbOutBuffer

Specifies the size, in bytes, of the buffer pointed to by lpvOutBuffer, which must be large enough to contain as many DISK_GEOMETRY structures as there are media that the driver supports.

lpcbBytesReturned

Points to a DWORD that receives the actual size, in bytes, of the data stored into lpvOutBuffer.

Return Value

If the operation succeeds, DeviceIoControl returns TRUE.

If the operation fails, DeviceIoControl returns FALSE. To get extended error information, call GetLastError.

Remarks

This device I/O control operation is for all class drivers, as well as non-computer system interface (SCSI) hard drives and floppy disk devices.

See Also

DeviceIoControl, DISK_GEOMETRY, IOCTL_DISK_GET_DRIVE_GEOMETRY


IOCTL_DISK_GET_PARTITION_INFO
IOCTL_DISK_GET_PARTITION_INFO  QuickInfo  Overview  Group

The IOCTL_DISK_GET_PARTITION_INFO DeviceIoControl operation returns information about the type, size, and nature of a disk partition.

dwIoControlCode = IOCTL_DISK_GET_PARTITION_INFO ;   // operation code

lpvInBuffer = NULL;   // address of input buffer; not used; must be NULL

cbInBuffer = 0;       // size of input buffer; not used; must be zero

lpvOutBuffer;         // address of output buffer

cbOutBuffer;          // size of output buffer

lpcbBytesReturned;    // address of actual bytes of output

Parameters

lpvInBuffer

Points to an input buffer. Not used with this operation. Set to NULL.

cbInBuffer

Specifies the size, in bytes, of the buffer pointed to by lpvInBuffer. Not used with this operation. Set to zero.

lpvOutBuffer

Points to a buffer that will receive a PARTITION_INFORMATION data structure.

cbOutBuffer

Specifies the size, in bytes, of the buffer pointed to by lpvOutBuffer, which must be large enough to contain a PARTITION_INFORMATION data structure.

lpcbBytesReturned

Points to a DWORD that receives the actual size, in bytes, of the data stored into lpvOutBuffer.

Return Value

If the operation succeeds, DeviceIoControl returns TRUE.

If the operation fails, DeviceIoControl returns FALSE. To get extended error information, call GetLastError.

Remarks

This device I/O control operation is for disk devices. Floppy disk drivers, however, do not need to handle this operation.

See Also

DeviceIoControl, IOCTL_DISK_SET_PARTITION_INFO, PARTITION_INFORMATION


IOCTL_DISK_LOAD_MEDIA
IOCTL_DISK_LOAD_MEDIA  QuickInfo  Overview  Group

The IOCTL_DISK_LOAD_MEDIA DeviceIoControl operation causes media to be loaded into a device.

dwIoControlCode = IOCTL_DISK_LOAD_MEDIA;   // operation code

lpvInBuffer = NULL;   // address of input buffer; not used; must be NULL

cbInBuffer = 0;       // size of input buffer; not used; must be zero

lpvOutBuffer = NULL;  // address of output buffer; not used; must be NULL

cbOutBuffer = 0;      // size of output buffer; not used; must be zero

lpcbBytesReturned;    // address of actual bytes of output

Parameters

lpvInBuffer

Points to an input buffer. Not used with this operation. Set to NULL.

cbInBuffer

Specifies the size, in bytes, of the buffer pointed to by lpvInBuffer. Not used with this operation. Set to zero.

lpvOutBuffer

Points to an output buffer. Not used with this operation. Set to NULL.

cbOutBuffer

Specifies the size, in bytes, of the buffer pointed to by lpvOutBuffer. Not used with this operation. Set to zero.

lpcbBytesReturned

Points to a DWORD that receives the actual size, in bytes, of the data stored into lpvOutBuffer.

Remarks

The IOCTL_DISK_LOAD_MEDIA is valid only for devices that support loadable media.

See Also

DeviceIoControl, IOCTL_DISK_EJECT_MEDIA, IOCTL_DISK_MEDIA_REMOVAL


IOCTL_DISK_MEDIA_REMOVAL
IOCTL_DISK_MEDIA_REMOVAL  QuickInfo  Overview  Group

The IOCTL_DISK_MEDIA_REMOVAL DeviceIoControl operation enables or disables the mechanism that ejects media, for those devices possessing that locking capability.

dwIoControlCode = IOCTL_DISK_MEDIA_REMOVAL;   // operation code

lpvInBuffer;              // address of input buffer

cbInBuffer;               // size of input buffer

lpvOutBuffer = NULL;      // address of output buffer; not used; must be NULL

cbOutBuffer = 0;          // size of output buffer; not used; must be zero

lpcbBytesReturned;        // address of actual bytes of output

Parameters

lpvInBuffer

Points to a buffer that contains a PREVENT_MEDIA_REMOVAL data structure.

A TRUE value for that structure's PreventMediaRemoval member specifies that media removal is prevented (the device is locked). A FALSE value specifies that media removal is allowed.

cbInBuffer

Specifies the size, in bytes, of the buffer pointed to by lpvInBuffer, which must be large enough to contain a PREVENT_MEDIA_REMOVAL data structure.

lpvOutBuffer

Points to an output buffer. Not used with this operation. Set to NULL.

cbOutBuffer

Specifies the size, in bytes, of the buffer pointed to by lpvOutBuffer. Not used with this operation. Set to zero.

lpcbBytesReturned

Points to a DWORD that receives the actual size, in bytes, of the data stored into lpvOutBuffer.

Return Value

If the operation succeeds, DeviceIoControl returns TRUE.

If the operation fails, DeviceIoControl returns FALSE. To get extended error information, call GetLastError.

Remarks

The IOCTL_DISK_MEDIA_REMOVAL operation is valid only for devices that support removable media.

See Also

DeviceIoControl, IOCTL_DISK_EJECT_MEDIA, IOCTL_DISK_LOAD_MEDIA, PREVENT_MEDIA_REMOVAL


IOCTL_DISK_PERFORMANCE
IOCTL_DISK_PERFORMANCE  QuickInfo  Overview  Group

The IOCTL_DISK_PERFORMANCE DeviceIoControl operation provides disk performance information.

dwIoControlCode = IOCTL_DISK_PERFORMANCE;   // operation code

lpvInBuffer = NULL; // address of input buffer; not used; must be NULL

cbInBuffer = 0;     // size of input buffer; not used; must be zero

lpvOutBuffer;       // address of output buffer

cbOutBuffer;        // size of output buffer

lpcbBytesReturned;  // address of actual bytes of output

Parameters

lpvInBuffer

Points to an input buffer. Not used with this operation. Set to NULL.

cbInBuffer

Specifies the size, in bytes, of the buffer pointed to by lpvInBuffer. Not used with this operation. Set to zero.

lpvOutBuffer

Points to a buffer that will receive a DISK_PERFORMANCE data structure.

cbOutBuffer

Specifies the size, in bytes, of the buffer pointed to by lpvOutBuffer, which must be large enough to contain a DISK_PERFORMANCE data structure.

lpcbBytesReturned

Points to a DWORD that receives the actual size, in bytes, of the data stored into lpvOutBuffer.

Return Value

If the operation succeeds, DeviceIoControl returns TRUE.

If the operation fails, DeviceIoControl returns FALSE. To get extended error information, call GetLastError.

Remarks

This device I/O control operation is for disk devices.

See Also

DeviceIoControl, DISK_PERFORMANCE


IOCTL_DISK_REASSIGN_BLOCKS
IOCTL_DISK_REASSIGN_BLOCKS  QuickInfo  Overview  Group

The IOCTL_DISK_REASSIGN_BLOCKS DeviceIoControl operation directs the disk device to map one or more blocks to its spare-block pool.

dwIoControlCode = IOCTL_DISK_REASSIGN_BLOCKS;   // operation code

lpvInBuffer;              // address of input buffer

cbInBuffer;               // size of input buffer

lpvOutBuffer = NULL;      // address of output buffer; not used; must be NULL

cbOutBuffer = 0;          // size of output buffer; not used; must be zero

lpcbBytesReturned;        // address of actual bytes of output

Parameters

lpvInBuffer

Points to a buffer that contains a REASSIGN_BLOCKS data structure specifying the blocks to reassign to its spare block pool.

cbInBuffer

Specifies the size, in bytes, of the buffer pointed to by lpvInBuffer, which must be large enough to contain the REASSIGN_BLOCKS data structure. Note that this structure is really a header followed by an array of block specifiers; thus, it varies in size according to the number of blocks to be reassigned; each block after the first adds the size of a DWORD to the overall size.

lpvOutBuffer

Points to an output buffer. Not used with this operation. Set to NULL.

cbOutBuffer

Specifies the size, in bytes, of the buffer pointed to by lpvOutBuffer. Not used with this operation. Set to zero.

lpcbBytesReturned

Points to a DWORD that receives the actual size, in bytes, of the data stored into lpvOutBuffer.

Return Value

If the operation succeeds, DeviceIoControl returns TRUE.

If the operation fails, DeviceIoControl returns FALSE. To get extended error information, call GetLastError.

Remarks

This device I/O control operation is for disk devices.

See Also

DeviceIoControl, REASSIGN_BLOCKS


IOCTL_DISK_SET_DRIVE_LAYOUT
IOCTL_DISK_SET_DRIVE_LAYOUT  QuickInfo  Overview  Group

The IOCTL_DISK_SET_DRIVE_LAYOUT DeviceIoControl operation partitions a disk as specified by drive layout and partition information data.

dwIoControlCode = IOCTL_DISK_SET_DRIVE_LAYOUT;   // operation code

lpvInBuffer;              // address of input buffer

cbInBuffer;               // size of input buffer

lpvOutBuffer = NULL;      // address of output buffer; not used; must be NULL

cbOutBuffer = 0;          // size of output buffer; not used; must be zero

lpcbBytesReturned;        // address of actual bytes of output

Parameters

lpvInBuffer

Points to a buffer that contains drive layout and partition information data. The data exists as a DRIVE_LAYOUT_INFORMATION data structure and a series of PARTITION_INFORMATION data structures, one of the latter for each proposed partition on the drive.

cbInBuffer

Specifies the size, in bytes, of the buffer pointed to by lpvInBuffer, which must be large enough to contain one DRIVE_LAYOUT_INFORMATION data structure and as many PARTITION_INFORMATION data structures as there are proposed partitions on the drive.

lpvOutBuffer

Points to an output buffer. Not used with this operation. Set to NULL.

cbOutBuffer

Specifies the size, in bytes, of the buffer pointed to by lpvOutBuffer. Not used with this operation. Set to zero.

lpcbBytesReturned

Points to a DWORD that receives the actual size, in bytes, of the data stored into lpvOutBuffer.

Return Value

If the operation succeeds, DeviceIoControl returns TRUE.

If the operation fails, DeviceIoControl returns FALSE. To get extended error information, call GetLastError.

Remarks

This device I/O control operation is for disk devices. Floppy disk drivers, however, need not handle this operation.

See Also

DeviceIoControl, DRIVE_LAYOUT_INFORMATION, IOCTL_DISK_GET_DRIVE_LAYOUT, PARTITION_INFORMATION


IOCTL_DISK_SET_PARTITION_INFO
IOCTL_DISK_SET_PARTITION_INFO  QuickInfo  Overview  Group

The IOCTL_DISK_SET_PARTITION_INFO DeviceIoControl operation sets the partition type of the specified disk partition.

dwIoControlCode = IOCTL_DISK_SET_PARTITION_INFO;   // operation code

lpvInBuffer;              // address of input buffer

cbInBuffer;               // size of input buffer

lpvOutBuffer = NULL;      // address of output buffer; not used; must be NULL

cbOutBuffer = 0;          // size of output buffer; not used; must be zero

lpcbBytesReturned;        // address of actual bytes of output

Parameters

lpvInBuffer

Points to a buffer that contains the partition data to be set. The data exists as a SET_PARTITION_INFORMATION data structure.

cbInBuffer

Specifies the size, in bytes, of the buffer pointed to by lpvInBuffer, which must be large enough to contain a SET_PARTITION_INFORMATION data structure.

lpvOutBuffer

Points to an output buffer. Not used with this operation. Set to NULL.

cbOutBuffer

Specifies the size, in bytes, of the buffer pointed to by lpvOutBuffer. Not used with this operation. Set to zero.

lpcbBytesReturned

Points to a DWORD that receives the actual size, in bytes, of the data stored into lpvOutBuffer. Not used with this operation. Set to NULL.

Return Value

If the operation succeeds, DeviceIoControl returns TRUE.

If the operation fails, DeviceIoControl returns FALSE. To get extended error information, call GetLastError.

Remarks

This device I/O control operation is for disk devices. Floppy disk drivers, however, need not handle this operation.

See Also

DeviceIoControl, IOCTL_DISK_GET_PARTITION_INFO, SET_PARTITION_INFORMATION


IOCTL_DISK_VERIFY
IOCTL_DISK_VERIFY  QuickInfo  Overview  Group

The IOCTL_DISK_VERIFY DeviceIoControl operation performs a logical format of a specified extent on a disk.

dwIoControlCode = IOCTL_DISK_VERIFY;   // operation code

lpvInBuffer;          // address of input buffer

cbInBuffer;           // size of input buffer

lpvOutBuffer = NULL;  // address of output buffer; not used; must be NULL

cbOutBuffer = 0;      // size of output buffer; not used; must be zero

lpcbBytesReturned;    // address of actual bytes of output

Parameters

lpvInBuffer

Points to a buffer that contains a VERIFY_INFORMATION data structure.

cbInBuffer

Specifies the size, in bytes, of the buffer pointed to by lpvInBuffer, which must be large enough to contain a VERIFY_INFORMATION data structure.

lpvOutBuffer

Points to an output buffer. Not used with this operation. Set to NULL.

cbOutBuffer

Specifies the size, in bytes, of the buffer pointed to by lpvOutBuffer. Not used with this operation. Set to zero.

lpcbBytesReturned

Points to a DWORD that receives the actual size, in bytes, of the data stored into lpvOutBuffer.

Return Value

If the operation succeeds, DeviceIoControl returns TRUE.

If the operation fails, DeviceIoControl returns FALSE. To get extended error information, call GetLastError.

Remarks

This device I/O control operation is for disk devices. Floppy disk drivers, however, need not handle this operation.

See Also

DeviceIoControl, IOCTL_DISK_CHECK_VERIFY, VERIFY_INFORMATION


IOCTL_SERIAL_LSRMST_INSERT
IOCTL_SERIAL_LSRMST_INSERT  QuickInfo  Overview  Group

The IOCTL_SERIAL_LSRMST_INSERT DeviceIoControl operation enables or disables the placement of line status and modem status values into the regular data stream that an application acquires through the ReadFile function.

When this line-status and modem-status data placement mode is enabled, status values are preceded in the data stream by an escape character. The user-definable escape character is set by the IOCTL_SERIAL_LSRMST_INSERT operation. Status values consist of 1 to 3 BYTEs. See the Remarks section below for status value details.

dwIoControlCode = IOCTL_SERIAL_LSRMST_INSERT;     // operation code

lpvInBuffer;            // address of input buffer

cbInBuffer;             // size of input buffer

lpvOutBuffer = NULL;    // address of output buffer; not used; must be NULL

cbOutBuffer = 0;        // size of output buffer; not used; must be zero

lpcbBytesReturned;      // address of actual bytes of output

Parameters

lpvInBuffer

Points to a buffer that contains a single BYTE.

If the BYTE is a nonzero value, it is the desired line-status and modem-status value escape character. The operation will turn the LSRMST_INSERT line-status and modem-status data placement mode on.

If the BYTE is zero, the operation will turn the LSRMST_INSERT line-status and modem-status data placement mode off.

The escape character can not be the XON or XOFF character.

cbInBuffer

Specifies the size, in bytes, of the buffer pointed to by lpvInBuffer. For this operation, this value should be 1.

lpvOutBuffer

Points to an output buffer. Not used with this operation. Set to NULL.

cbOutBuffer

Specifies the size, in bytes, of the buffer pointed to by lpvOutBuffer. Not used with this operation. Set to zero.

lpcbBytesReturned

Points to a DWORD that receives the actual size, in bytes, of the data stored into lpvOutBuffer.

Return Value

If the operation succeeds, DeviceIoControl returns TRUE.

If the operation fails, DeviceIoControl returns FALSE. To get extended error information, call GetLastError.

Remarks

Note that an application that uses this scheme must examine each character in the data stream to determine the presence of modem-status or line-status data.

The following values follow the designated escape character in the data stream if the LSRMST_INSERT mode has been turned on :

Value	Meaning
SERIAL_LSRMST_ESCAPE	Indicates the reception of the escape character itself into the data stream.
SERIAL_LSRMST_LSR_DATA	Indicates that a line status change occurred, and data was available in the receive hardware buffer. Following this BYTE is a BYTE value of the line status register is the BYTE present in the receive hardware buffer when the line status change was processed.
SERIAL_LSRMST_LSR_NODATA	Indicates that a line status change occurred, but no data was available in the receive hardware buffer.
SERIAL_LSRMST_MST	Indicates that a modem status change occurred. Following this BYTE is a BYTE that is the value of the modem status register when the modem status change was processed.
See Also

DeviceIoControl, ReadFile


ioctlsocket
ioctlsocket  QuickInfo

The Windows Sockets ioctlsocket function controls the mode of a socket.

int ioctlsocket (

SOCKET s,
long cmd,
u_long FAR * argp
);
Parameters

s

A descriptor identifying a socket.

cmd

The command to perform on the socket s.

argp

A pointer to a parameter for cmd.

Return Value

If the function succeeds, ioctlsocket returns zero.

If the function fails, a value of SOCKET_ERROR is returned. To get extended error information, call WSAGetLastError.

Error Codes

WSANOTINITIALISED	A successful WSAStartup must occur before using this function.
WSAENETDOWN	The Windows Sockets implementation has detected that the network subsystem has failed.
WSAEINVAL	The cmd parameter is not valid, or argp is not an acceptable parameter for cmd, or the command is not applicable to the type of socket supplied.
WSAEINPROGRESS	A blocking Windows Sockets operation is in progress.
WSAENOTSOCK	The descriptor s is not a socket.
Remarks

This function may be used on any socket in any state. It is used to get or set operating parameters associated with the socket, independent of the protocol and communications subsystem. The following commands are supported:

Command	Semantics
FIONBIO	Enable or disable nonblocking mode on the socket s. argp points at an unsigned long, which is nonzero if nonblocking mode is to be enabled and zero if it is to be disabled. When a socket is created, it operates in blocking mode (that is, nonblocking mode is disabled). This is consistent with BSD sockets.
	The WSAAsyncSelect function automatically sets a socket to nonblocking mode. If WSAAsyncSelect has been issued on a socket, then any attempt to use ioctlsocket to set the socket back to blocking mode will fail with WSAEINVAL. To set the socket back to blocking mode, an application must first disable WSAAsyncSelect by calling WSAAsyncSelect with the lEvent parameter equal to zero.
FIONREAD	Determine the amount of data that can be read atomically from socket s. argp points at an unsigned long in which ioctlsocket stores the result. If s is of type SOCK_STREAM, FIONREAD returns the total amount of data that can be read in a single recv; this is normally the same as the total amount of data queued on the socket. If s is of type SOCK_DGRAM, FIONREAD returns the size of the first datagram queued on the socket.
SIOCATMARK	Determine whether all out-of-band data has been read. This applies only to a socket of type SOCK_STREAM that has been configured for in-line reception of any out-of-band data (SO_OOBINLINE). If no out-of-band data is waiting to be read, the operation returns TRUE. Otherwise, it returns FALSE, and the next recv or recvfrom performed on the socket will retrieve some or all of the data preceding the "mark"; the application should use the SIOCATMARK operation to determine whether any data remains. If there is any normal data preceding the "urgent" (out-of-band) data, it will be received in order. (Note that a recv or recvfrom will never mix out-of-band and normal data in the same call.) argp points at a BOOL in which ioctlsocket stores the result.
Compatibility

This function is a subset of ioctl as used in Berkeley sockets. In particular, there is no command equivalent to FIOASYNC, while SIOCATMARK is the only socket-level command supported.

See Also

getsockopt, socket, setsockopt, WSAAsyncSelect, WSAStartup


IsBadCodePtr
IsBadCodePtr  QuickInfo  Overview  Group

The IsBadCodePtr function determines whether the calling process has read access to the memory at the specified address.

BOOL IsBadCodePtr(

FARPROC  lpfn	// address of function
);
Parameters

lpfn

Points to an address in memory.

Return Value

If the calling process has read access to the specified memory, the return value is FALSE; otherwise, it is TRUE. To get extended error information, call GetLastError.

Remarks

IsBadCodePtr checks the read access only at the specified address and does not guarantee read access to a range of memory.

In a preemptive multitasking environment, it is possible for some other thread to change the process's access to the memory being tested. Even when the function indicates that the process has read access to the specified memory, you should use structured exception handling when attempting to access the memory. Use of structured exception handling enables the system to notify the process if an access violation exception occurs, giving the process an opportunity to handle the exception.

See Also

IsBadHugeReadPtr, IsBadHugeWritePtr, IsBadReadPtr, IsBadStringPtr, IsBadWritePtr


IsBadHugeReadPtr
IsBadHugeReadPtr  QuickInfo  Overview  Group

The IsBadHugeReadPtr function verifies that the calling process has read access to the specified range of memory.

BOOL IsBadHugeReadPtr(

CONST VOID  * lp,	// address of memory block
UINT  ucb	// size of block
);
Parameters

lp

Points to the first byte of the memory block.

ucb

Specifies the size, in bytes, of the memory block. If this parameter is zero, the return value is FALSE.

Return Value

If the calling process has read access to all bytes in the specified memory range, the return value is FALSE; otherwise, it is TRUE. To get extended error information, call GetLastError.

Remarks

If the calling process has read access to some, but not all, of the bytes in the specified memory range, the return value is TRUE.

In a preemptive multitasking environment, it is possible for some other thread to change the process's access to the memory being tested. Even when the function indicates that the process has read access to the specified memory, you should use structured exception handling when attempting to access the memory. Use of structured exception handling enables the system to notify the process if an access violation exception occurs, giving the process an opportunity to handle the exception.

IsBadHugeReadPtr is available for compatibility with earlier versions of Windows that distinguish between normal memory allocations and huge allocations occupying multiple segments. In the Win32 API, this function is equivalent to the IsBadReadPtr function.

See Also

IsBadHugeWritePtr, IsBadReadPtr, IsBadStringPtr, IsBadWritePtr


IsBadHugeWritePtr
IsBadHugeWritePtr  QuickInfo  Overview  Group

The IsBadHugeWritePtr function verifies that the calling process has write access to the specified range of memory.

BOOL IsBadHugeWritePtr(

LPVOID  lp,	// address of memory block
UINT  ucb	// size of block
);
Parameters

lp

Points to the first byte of the memory block.

ucb

Specifies the size, in bytes, of the memory block. If this parameter is zero, the return value is FALSE.

Return Value

If the calling process has write access to all bytes in the specified memory range, the return value is FALSE; otherwise, it is TRUE. To get extended error information, call GetLastError.

Remarks

If the calling process has write access to some, but not all, of the bytes in the specified memory range, the return value is TRUE.

In a preemptive multitasking environment, it is possible for some other thread to change the process's access to the memory being tested. Even when the function indicates that the process has write access to the specified memory, you should use structured exception handling when attempting to access the memory. Use of structured exception handling enables the system to notify the process if an access violation exception occurs, giving the process an opportunity to handle the exception.

IsBadHugeWritePtr is available for compatibility with earlier versions of Windows, which distinguish between normal memory allocations and huge allocations occupying multiple segments. In the Win32 API, this function is equivalent to the IsBadWritePtr function.

See Also

IsBadHugeReadPtr, IsBadReadPtr, IsBadStringPtr, IsBadWritePtr


IsBadReadPtr
IsBadReadPtr  QuickInfo  Overview  Group

The IsBadReadPtr function verifies that the calling process has read access to the specified range of memory.

BOOL IsBadReadPtr(

CONST VOID  * lp,	// address of memory block
UINT  ucb	// size of block
);
Parameters

lp

Points to the first byte of the memory block.

ucb

Specifies the size, in bytes, of the memory block. If this parameter is zero, the return value is FALSE.

Return Value

If the calling process has read access to all bytes in the specified memory range, the return value is FALSE; otherwise, it is TRUE. To get extended error information, call GetLastError.

Remarks

If the calling process has read access to some, but not all, of the bytes in the specified memory range, the return value is TRUE.

In a preemptive multitasking environment, it is possible for some other thread to change the process's access to the memory being tested. Even when the function indicates that the process has read access to the specified memory, you should use structured exception handling when attempting to access the memory. Use of structured exception handling enables the system to notify the process if an access violation exception occurs, giving the process an opportunity to handle the exception.

See Also

IsBadHugeReadPtr, IsBadHugeWritePtr, IsBadStringPtr, IsBadWritePtr


IsBadStringPtr
IsBadStringPtr  QuickInfo  Overview  Group

The IsBadStringPtr function verifies that the calling process has read access to a range of memory pointed to by a string pointer.

BOOL IsBadStringPtr(

LPCTSTR  lpsz,	// address of string
UINT  ucchMax	// maximum size of string
);
Parameters

lpsz

Points to a null-terminated string, either Unicode or ASCII.

ucchMax

Specifies the maximum size, in characters, of the string. The function checks for read access in all bytes up to the string's terminating null character or up to the number of bytes specified by this parameter, whichever is smaller. If this parameter is zero, the return value is FALSE.

Return Value

If the calling process has read access to all bytes up to the string's terminating null character or up to the number of bytes specified by ucchMax, the return value is FALSE; otherwise, it is TRUE. To get extended error information, call GetLastError.

Remarks

If the calling process has read access to some, but not all, of the bytes in the specified memory range, the return value is TRUE.

In a preemptive multitasking environment, it is possible for some other thread to change the process's access to the memory being tested. Even when the function indicates that the process has read access to the specified memory, you should use structured exception handling when attempting to access the memory. Use of structured exception handling enables the system to notify the process if an access violation exception occurs, giving the process an opportunity to handle the exception.

See Also

IsBadCodePtr, IsBadHugeReadPtr, IsBadHugeWritePtr, IsBadReadPtr, IsBadWritePtr


IsBadWritePtr
IsBadWritePtr  QuickInfo  Overview  Group

The IsBadWritePtr function verifies that the calling process has write access to the specified range of memory.

BOOL IsBadWritePtr(

LPVOID  lp,	// address of memory block
UINT  ucb	// size of block
);
Parameters

lp

Points to the first byte of the memory block.

ucb

Specifies the size, in bytes, of the memory block. If this parameter is zero, the return value is FALSE.

Return Value

If the calling process has write access to all bytes in the specified memory range, the return value is FALSE; otherwise, it is TRUE. To get extended error information, call GetLastError.

Remarks

If the calling process has write access to some, but not all, of the bytes in the specified memory range, the return value is TRUE.

In a preemptive multitasking environment, it is possible for some other thread to change the process's access to the memory being tested. Even when the function indicates that the process has write access to the specified memory, you should use structured exception handling when attempting to access the memory. Use of structured exception handling enables the system to notify the process if an access violation exception occurs, giving the process an opportunity to handle the exception.

See Also

IsBadCodePtr, IsBadHugeReadPtr, IsBadHugeWritePtr, IsBadReadPtr


IsCharAlpha
IsCharAlpha  QuickInfo  Overview  Group

The IsCharAlpha function determines whether a character is an alphabetic character. This determination is based on the semantics of the language selected by the user during setup or by using Control Panel.

BOOL IsCharAlpha(

TCHAR  ch	// character to test
);
Parameters

ch

Specifies the character to be tested.

Return Value

If the character is alphabetic, the return value is TRUE.

If the character is not alphabetic, the return value is FALSE.

To get extended error information, call GetLastError.

See Also

IsCharAlphaNumeric


IsCharAlphaNumeric
IsCharAlphaNumeric  QuickInfo  Overview  Group

The IsCharAlphaNumeric function determines whether a character is either an alphabetic or a numeric character. This determination is based on the semantics of the language selected by the user during setup or by using Control Panel.

BOOL IsCharAlphaNumeric(

TCHAR  ch	// character to test
);
Parameters

ch

Specifies the character to be tested.

Return Value

If the character is alphanumeric, the return value is TRUE.

If the character is not alphanumeric, the return value is FALSE.

To get extended error information, call GetLastError.

See Also

IsCharAlpha


IsCharLower
IsCharLower  QuickInfo  Overview  Group

The IsCharLower function determines whether a character is lowercase. This determination is based on the semantics of the language selected by the user during setup or by using Control Panel.

BOOL IsCharLower(

TCHAR  ch	// character to test
);
Parameters

ch

Specifies the character to be tested.

Return Value

If the character is lowercase, the return value is TRUE.

If the character is not lowercase, the return value is FALSE.

To get extended error information, call GetLastError.

See Also

IsCharUpper


IsCharUpper
IsCharUpper  QuickInfo  Overview  Group

The IsCharUpper function determines whether a character is uppercase. This determination is based on the semantics of the language selected by the user during setup or by using Control Panel.

BOOL IsCharUpper(

TCHAR  ch	// character to test
);
Parameters

ch

Specifies the character to be tested.

Return Value

If the character is uppercase, the return value is TRUE.

If the character is not uppercase, the return value is FALSE.

To get extended error information, call GetLastError.

See Also

IsCharLower


IsChild
IsChild  QuickInfo  Overview  Group

The IsChild function tests whether a window is a child window or descendant window of a specified parent window. A child window is the direct descendant of a specified parent window if that parent window is in the chain of parent windows; the chain of parent windows leads from the original overlapped or pop-up window to the child window.

BOOL IsChild(

HWND  hWndParent,	// handle of parent window
HWND  hWnd	// handle of window to test
);
Parameters

hWndParent

Identifies the parent window.

hWnd

Identifies the window to be tested.

Return Value

If the window is a child or descendant window of the specified parent window, the return value is TRUE.

If the window is not a child or descendant window of the specified parent window, the return value is FALSE.

See Also

IsWindow, SetParent


IsClipboardFormatAvailable
IsClipboardFormatAvailable  QuickInfo  Overview  Group

The IsClipboardFormatAvailable function determines whether the clipboard contains data in the specified format.

BOOL IsClipboardFormatAvailable(

UINT  format	// clipboard format
);
Parameters

format

Specifies a standard or registered clipboard format. For a description of the clipboard formats, see the SetClipboardData function.

Return Value

If the clipboard format is available, the return value is TRUE.

If the clipboard is not available, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Typically, an application that recognizes only one clipboard format would call this function when processing the WM_INITMENU or WM_INITMENUPOPUP message. The application would then enable or disable the Paste menu item, depending on the return value. Applications that recognize more than one clipboard format should use the GetPriorityClipboardFormat function for this purpose.

See Also

CountClipboardFormats, EnumClipboardFormats, GetPriorityClipboardFormat, RegisterClipboardFormat, SetClipboardData, WM_INITMENU, WM_INITMENUPOPUP


IsDBCSLeadByte
IsDBCSLeadByte  QuickInfo  Overview  Group

The IsDBCSLeadByte function determines whether a character is a lead byte — that is, the first byte of a character in a double-byte character set (DBCS).

BOOL IsDBCSLeadByte(

BYTE  TestChar	// character to test
);
Parameters

TestChar

Specifies the character to be tested.

Return Value

If the character is a lead byte, the return value is TRUE.

If the character is not a lead byte, the return value is FALSE.

To get extended error information, call GetLastError.

Remarks

Lead bytes are unique to double-byte character sets. A lead byte introduces a double-byte character. Lead bytes occupy a specific range of byte values. The IsDBCSLeadByte function uses the ANSI code page to check lead-byte ranges.

See Also

MultiByteToWideChar


IsDBCSLeadByteEx [New - Windows NT]
IsDBCSLeadByteEx  QuickInfo  Overview  Group

[New - Windows NT]

The IsDBCSLeadByteEx function determines whether a character is a lead byte — that is, the first byte of a character in a double-byte character set (DBCS).

BOOL IsDBCSLeadByteEx(

UINT  CodePage,	// identifier of code page
BYTE  TestChar	// character to test
);
Parameters

CodePage

Identifier of the code page to use to check lead-byte ranges. Can be one of the code-page values given in the "Code-Page Identifiers" table in Unicode and Character Set Constants or one of the following predefined values:

Value	Meaning
0	Use system default ANSI code page.
CP_ACP	Use system default ANSI code page.
CP_OEMCP	Use system default OEM code page.
TestChar

Character to test.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.


IsDialogMessage
IsDialogMessage  QuickInfo  Overview  Group

The IsDialogMessage function determines whether a message is intended for the specified dialog box and, if it is, processes the message.

BOOL IsDialogMessage(

HWND  hDlg,	// handle of dialog box
LPMSG  lpMsg	// address of structure with message
);
Parameters

hDlg

Identifies the dialog box.

lpMsg

Points to an MSG structure that contains the message to be checked.

Return Value

If the message has been processed, the return value is TRUE.

If the message has not been processed, the return value is FALSE.

Remarks

Although the IsDialogMessage function is intended for modeless dialog boxes, you can use it with any window that contains controls, enabling the windows to provide the same keyboard selection as is used in a dialog box.

When IsDialogMessage processes a message, it checks for keyboard messages and converts them into selection commands for the corresponding dialog box. For example, the TAB key, when pressed, selects the next control or group of controls, and the DOWN ARROW key, when pressed, selects the next control in a group.

Because the IsDialogMessage function performs all necessary translating and dispatching of messages, a message processed by IsDialogMessage must not be passed to the TranslateMessage or DispatchMessage function.

IsDialogMessage sends WM_GETDLGCODE messages to the dialog box procedure to determine which keys should be processed.

IsDialogMessage can send DM_GETDEFID and DM_SETDEFID messages to the window. These messages are defined in the WINUSER.H header file as WM_USER and WM_USER + 1, so conflicts are possible with application-defined messages having the same values.

See Also

DispatchMessage, DM_GETDEFID, DM_SETDEFID, MSG, TranslateMessage, WM_GETDLGCODE, WM_USER


IsDlgButtonChecked
IsDlgButtonChecked  QuickInfo  Overview  Group

The IsDlgButtonChecked function determines whether a button control has a check mark next to it or whether a three-state button control is grayed, checked, or neither.

UINT IsDlgButtonChecked(

HWND  hDlg,	// handle of dialog box
int  nIDButton	// button identifier
);
Parameters

hDlg

Identifies the dialog box that contains the button control.

nIDButton

Specifies the integer identifier of the button control.

Return Value

The return value from a button created with the BS_AUTOCHECKBOX, BS_AUTORADIOBUTTON, BS_AUTO3STATE, BS_CHECKBOX, BS_RADIOBUTTON, or BS_3STATE style can be one of the following:

Value	Meaning
0	Button is unchecked. Same as the Windows 95 constant BST_UNCHECKED.
1	Button is checked. Same as the Windows 95 constant BST_CHECKED.
2	Button is grayed, indicating an indeterminate state (applies only if the button has the BS_3STATE or BS_AUTO3STATE style). Same as the Windows 95 constant BST_INDETERMINATE.
BST_CHECKED	Windows 95 only: Button is checked.
BST_INDETERMINATE	Windows 95 only: Button is grayed, indicating an indeterminate state (applies only if the button has the BS_3STATE or BS_AUTO3STATE style).
BST_UNCHECKED	Windows 95 only: Button is unchecked
If the button has any other style, the return value is zero.

Remarks

The IsDlgButtonChecked function sends a BM_GETCHECK message to the specified button control.

See Also

CheckDlgButton


IsIconic
IsIconic  QuickInfo  Overview  Group

The IsIconic function determines whether the specified window is minimized (iconic).

BOOL IsIconic(

HWND  hWnd	// handle of window
);
Parameters

hWnd

Identifies the window.

Return Value

If the window is iconic, the return value is TRUE.

If the is not iconic, the return value is FALSE.

See Also

IsZoomed


IsMenu
IsMenu  QuickInfo  Overview  Group

The IsMenu function determines whether a handle is a menu handle.

BOOL IsMenu(

HMENU  hMenu	// handle to test
);
Parameters

hMenu

The handle to be tested.

Return Value

If hMenu is a menu handle, the function returns TRUE; if it is not, the function returns FALSE.


IsRectEmpty
IsRectEmpty  QuickInfo  Overview  Group

The IsRectEmpty function determines whether the specified rectangle is empty. A empty rectangle is one that has no area; that is, the coordinate of the right side is less than or equal to the coordinate of the left side, or the coordinate of the bottom side is less than or equal to the coordinate of the top side.

BOOL IsRectEmpty(

CONST RECT  * lprc	// address of structure with rectangle
);
Parameters

lprc

Points to a RECT structure that contains the logical coordinates of the rectangle.

Return Value

If the rectangle is empty, the return value is TRUE; otherwise, it is FALSE. To get extended error information, call GetLastError.

See Also

EqualRect, PtInRect, RECT


IsTask
IsTask  Overview  Group

The IsTask function is not implemented in the WIn32 API.


IsTextUnicode
IsTextUnicode  QuickInfo  Overview  Group

The IsTextUnicode function determines whether a buffer probably contains a form of Unicode text. The function uses various statistical and deterministic methods to make its determination, under the control of flags passed via lpi. When the function returns, the results of such tests are reported via lpi. If all specified tests are passed, the function returns TRUE; otherwise, it returns FALSE.

DWORD IsTextUnicode(

CONST LPVOID  lpBuffer,	// pointer to an input buffer to be examined
int  cb,	// the size in bytes of the input buffer
LPINT  lpi	// pointer to flags that condition text examination and receive results
);
Parameters

lpBuffer

Pointer to the input buffer to be examined.

cb

Specifies the size, in bytes, of the input buffer pointed to by lpBuffer.

lpi

Pointer to an int that, upon entry to the function, contains a set of flags that specify the tests to be applied to the input buffer text. Upon exit from the function, that same int contains a set of bit flags indicating the results of the specified tests: 1 if the contents of the buffer pass a test, 0 for failure. Only flags that are set upon entry to the function are significant upon exit.

If lpi is NULL, the function uses all available tests to determine whether the data in the buffer is probably Unicode text.

Here are the constants used with *lpi's bit flags:

Value	Meaning
IS_TEXT_UNICODE_ASCII16	The text is Unicode, and contains nothing but zero-extended ASCII values/characters.
IS_TEXT_UNICODE_REVERSE_ASCII16	Same as the preceding, except that the Unicode text is byte-reversed.
IS_TEXT_UNICODE_STATISTICS	The text is probably Unicode, with the determination made by applying statistical analysis. Absolute certainty is not guaranteed. See the note in the following Remarks section.
IS_TEXT_UNICODE_REVERSE_STATISTICS	Same as the preceding, except that the probably-Unicode text is byte-reversed.
IS_TEXT_UNICODE_CONTROLS	The text contains Unicode representations of one or more of these non-printing characters: RETURN, LINEFEED, SPACE, CJK_SPACE, TAB.
IS_TEXT_UNICODE_REVERSE_CONTROLS	Same as the preceding, except that the Unicode characters are byte-reversed.
IS_TEXT_UNICODE_BUFFER_TOO_SMALL	There are too few characters in the buffer for meaningful analysis (fewer than two bytes).
IS_TEXT_UNICODE_SIGNATURE	The text contains the Unicode byte-order mark (BOM) 0xFEFF as its first character.
IS_TEXT_UNICODE_REVERSE_SIGNATURE	The text contains the Unicode byte-reversed byte-order mark (Reverse BOM) 0xFFFE as its first character.
IS_TEXT_UNICODE_ILLEGAL_CHARS	The text contains one of these Unicode-illegal characters: embedded Reverse BOM, UNICODE_NUL, CRLF (packed into one WORD), or 0xFFFF.
IS_TEXT_UNICODE_ODD_LENGTH	The number of characters in the string is odd. A string of odd length cannot (by definition) be Unicode text.
IS_TEXT_UNICODE_NULL_BYTES	The text contains null bytes, which indicate non-ASCII text.
IS_TEXT_UNICODE_UNICODE_MASK	This flag constant is a combination of IS_TEXT_UNICODE_ASCII16, IS_TEXT_UNICODE_STATISTICS, IS_TEXT_UNICODE_CONTROLS, IS_TEXT_UNICODE_SIGNATURE.
IS_TEXT_UNICODE_REVERSE_MASK	This flag constant is a combination of IS_TEXT_UNICODE_REVERSE_ASCII16, IS_TEXT_UNICODE_REVERSE_STATISTICS, IS_TEXT_UNICODE_REVERSE_CONTROLS, IS_TEXT_UNICODE_REVERSE_SIGNATURE.
IS_TEXT_UNICODE_NOT_UNICODE_MASK	This flag constant is a combination of IS_TEXT_UNICODE_ILLEGAL_CHARS, IS_TEXT_UNICODE_ODD_LENGTH, and two currently unused bit flags.
IS_TEXT_UNICODE_NOT_ASCII_MASK	This flag constant is a combination of IS_TEXT_UNICODE_NULL_BYTES and three currently unused bit flags.
Return Value

The function returns TRUE if the data in the buffer passes the specified tests.

The function returns FALSE if the data in the buffer does not pass the specified tests.

In either case, the int pointed to by lpi contains the results of the specific tests the function applied to make its determination.

Remarks

As noted in the preceding table of flag constants, the IS_TEXT_UNICODE_STATISTICS and IS_TEXT_UNICODE_REVERSE_STATISTICS tests use statistical analysis. These tests are not foolproof. The statistical tests assume certain amounts of variation between low and high bytes in a string, and some ASCII strings can slip through. For example, if lpBuffer points to the ASCII string 0x41, 0x0A, 0x0D, 0x1D (A\n\r^Z), the string passes the IS_TEXT_UNICODE_STATISTICS test, though failure would be preferable.


IsValidAcl
IsValidAcl  QuickInfo  Overview  Group

The IsValidAcl function validates an access-control list (ACL).

BOOL IsValidAcl(

PACL  pAcl	// address of access-control list
);
Parameters

pAcl

Points to an ACL structure validated by this function. This must be a non-NULL value.

Return Value

If the ACL is valid, the return value is TRUE.

If the ACL is not valid, the return value is FALSE.

To get extended error information, call GetLastError.

Remarks

This function checks the revision level of the ACL and verifies that the number of access-control entries (ACEs) specified in the AceCount member of the ACL structure fits the space specified by the AclSize member of the ACL structure.

If pAcl is NULL, the application will fail with an access violation.

See Also

ACL, GetAclInformation, InitializeAcl


IsValidCodePage
IsValidCodePage  QuickInfo  Overview  Group

The IsValidCodePage determines whether a specified code page is valid.

BOOL IsValidCodePage(

UINT  CodePage	// specifies code page to check
);
Parameters

CodePage

Specifies the code page to check. Each code page is identified by a unique number.

Return Value

If the code page is valid, the return value is TRUE.

If the code page is not valid, the return value is FALSE.

To get extended error information, call GetLastError.

Remarks

A code page is considered valid only if it is installed in the system.

Following are the code-page identifiers:

Identifier	Meaning
037	EBCDIC
437	MS-DOS  United States
500	EBCDIC "500V1"
708	Arabic (ASMO 708)
709	Arabic (ASMO 449+, BCON V4)
710	Arabic (Transparent Arabic)
720	Arabic (Transparent ASMO)
737	Greek (formerly 437G)
775	Baltic
850	MS-DOS  Multilingual (Latin I)
852	MS-DOS  Slavic (Latin II)
855	IBM Cyrillic (primarily Russian)
857	IBM Turkish
860	MS-DOS  Portuguese
861	MS-DOS Icelandic
862	Hebrew
863	MS-DOS Canadian-French
864	Arabic
865	MS-DOS Nordic
866	MS-DOS Russian
869	IBM Modern Greek
874	Thai
875	EBCDIC
932	Japan
936	Chinese (PRC, Singapore)
949	Korean
950	Chinese (Taiwan, Hong Kong)
1026	EBCDIC
1200	Unicode (BMP of ISO 10646)
1250	Windows 3.1 Eastern European
1251	Windows 3.1 Cyrillic
1252	Windows 3.1 US (ANSI)
1253	Windows 3.1 Greek
1254	Windows 3.1 Turkish
1255	Hebrew
1256	Arabic
1257	Baltic
1361	Korean (Johab)
10000	Macintosh Roman
10001	Macintosh Japanese
10006	Macintosh Greek I
10007	Macintosh Cyrillic
10029	Macintosh Latin 2
10079	Macintosh Icelandic
10081	Macintosh Turkish
See Also

GetACP, GetCPInfo, GetOEMCP


IsValidLocale
IsValidLocale  QuickInfo  Overview  Group

The IsValidLocale function applies a validity test to a locale identifier. The dwFlags parameter determines the nature of the validity test. Currently, the function tests whether a locale identifier is installed or supported on the calling system.

BOOL IsValidLocale(

LCID  Locale	// locale indentifier to validate
DWORD  dwFlags	// specifies validity test
);
Parameters

Locale

Specifies the locale identifier to be validated. You can use the MAKELCID macro to create a locale identifier.

dwFlags

Specifies the validity test to apply to the locale identifier. This parameter can be one of the following values:

Value	Meaning
LCID_INSTALLED	Test whether the locale identifier is both supported and installed.
LCID_SUPPORTED	Test whether the locale identifier is supported.
Return Value

If the locale identifier passes the specified validity test, the return value is TRUE.

If the locale identifier does not pass the specified validity test, the return value is FALSE.

Remarks

If the LCID_INSTALLED flag is specified and this function returns TRUE, the locale identifier is both supported and installed on the system.

If the LCID_SUPPORTED flag is specified and this function returns TRUE, the locale identifier is supported in the release, but not necessarily installed on the system.

See Also

GetLocaleInfo


IsValidSecurityDescriptor
IsValidSecurityDescriptor  QuickInfo  Overview  Group

The IsValidSecurityDescriptor function validates a SECURITY_DESCRIPTOR structure. Validation is performed by checking the revision level of each component in the security descriptor.

BOOL IsValidSecurityDescriptor(

PSECURITY_DESCRIPTOR  pSecurityDescriptor	// address of security descriptor
);
Parameters

pSecurityDescriptor

Points to a SECURITY_DESCRIPTOR structure that the function validates.

Return Value

If the structure of the security descriptor is valid, the return value is TRUE.

If the structure of the security descriptor is not valid, the return value is FALSE. To get extended error information, call GetLastError.

See Also

GetSecurityDescriptorControl, GetSecurityDescriptorDacl, GetSecurityDescriptorGroup, GetSecurityDescriptorLength, GetSecurityDescriptorOwner, GetSecurityDescriptorSacl, InitializeSecurityDescriptor, SECURITY_DESCRIPTOR, SetSecurityDescriptorDacl, SetSecurityDescriptorGroup, SetSecurityDescriptorOwner, SetSecurityDescriptorSacl


IsValidSid
IsValidSid  QuickInfo  Overview  Group

The IsValidSid function validates a SID structure by verifying that the revision number is within a known range and that the number of subauthorities is less than the maximum. A SID is a security identifier.

BOOL IsValidSid(

PSID  pSid	// address of SID to query
);
Parameters

pSid

Points to the SID structure to validate. This must be a non-NULL value.

Return Value

If the SID structure is valid, the return value is TRUE.

If the SID structure is not valid, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

If pSid is NULL, the application will fail with an access violation.

See Also

GetLengthSid, GetSidIdentifierAuthority, GetSidLengthRequired, GetSidSubAuthority, GetSidSubAuthorityCount, SID


IsWindow
IsWindow  QuickInfo  Overview  Group

The IsWindow function determines whether the specified window handle identifies an existing window.

BOOL IsWindow(

HWND  hWnd	// handle of window
);
Parameters

hWnd

Specifies the window handle.

Return Value

If the window handle identifies an existing window, the return value is TRUE; otherwise, it is FALSE.

See Also

IsWindowEnabled, IsWindowVisible


IsWindowEnabled
IsWindowEnabled  QuickInfo  Overview  Group

The IsWindowEnabled function determines whether the specified window is enabled for mouse and keyboard input.

BOOL IsWindowEnabled(

HWND  hWnd	// handle of window to test
);
Parameters

hWnd

Identifies the window to test.

Return Value

If the window is enabled, the return value is TRUE; otherwise, it is FALSE.

Remarks

A child window receives input only if it is both enabled and visible.

See Also

EnableWindow, IsWindowVisible


IsWindowUnicode
IsWindowUnicode  QuickInfo  Overview  Group

The IsWindowUnicode function determines whether the specified window is a native Unicode window.

BOOL IsWindowUnicode(

HWND  hWnd	// handle of window
);
Parameters

hWnd

Identifies the window.

Return Value

If the window is a native Unicode window, the return value is TRUE.

If the window is not a native Unicode window, the return value is FALSE.

Remarks

The system does automatic two-way translation (Unicode to ANSI-ASCII) for window messages. For example, if an ANSI-ASCII window message is sent to a Unicode window, the system translates that message into a Unicode message before calling the window procedure. The system calls the IsWindowUnicode function to determine whether to translate the message.

When this function returns FALSE, the window is a native ANSI-ASCII window.


IsWindowVisible
IsWindowVisible  QuickInfo  Overview  Group

The IsWindowVisible function retrieves the visibility state of the specified window.

BOOL IsWindowVisible(

HWND  hWnd	// handle of window
);
Parameters

hWnd

Identifies the window.

Return Value

If the specified window is visible on the screen (has the WS_VISIBLE style), the return value is TRUE; otherwise, it is FALSE. Because the return value specifies whether the window has the WS_VISIBLE style, it may be TRUE even if the window is totally obscured by other windows.

Remarks

The visibility state of a window is indicated by the WS_VISIBLE style bit. When WS_VISIBLE is set, the window is displayed and subsequent drawing into it is displayed as long as the window has the WS_VISIBLE style.

Any drawing to a window with the WS_VISIBLE style will not be displayed if the window is obscured by other windows or is clipped by its parent window.

See Also

ShowWindow


IsZoomed
IsZoomed  QuickInfo  Overview  Group

The IsZoomed function determines whether a window is maximized.

BOOL IsZoomed(

HWND  hWnd	// handle of window
);
Parameters

hWnd

Identifies the window.

Return Value

If the window is zoomed, the return value is TRUE.

If the window is not zoomed, the return value is FALSE.

See Also

IsIconic


JournalPlaybackProc
JournalPlaybackProc  QuickInfo  Overview  Group

The JournalPlaybackProc hook procedure is a callback function that inserts mouse and keyboard messages into the system message queue. Typically, an application uses this hook procedure to play back a series of mouse and keyboard messages recorded previously by the JournalRecordProc hook procedure. As long as a JournalPlaybackProc hook procedure is installed, regular mouse and keyboard input is disabled.

LRESULT CALLBACK JournalPlaybackProc(

int  code,	// hook code
WPARAM  wParam,	// undefined
LPARAM  lParam	// address of message being processed
);
Parameters

code

Specifies a code the hook procedure uses to determine how to process the message. This parameter can be one of the following values:

Value	Meaning
HC_GETNEXT	The hook procedure must copy the current mouse or keyboard message to the EVENTMSG structure pointed to by the lParam parameter.
HC_NOREMOVE	An application has called the PeekMessage function with wRemoveMsg set to PM_NOREMOVE, indicating that the message is not removed from the message queue after PeekMessage processing.
HC_SKIP	The hook procedure must prepare to copy the next mouse or keyboard message to the EVENTMSG structure pointed to by lParam. Upon receiving the HC_GETNEXT code, the hook procedure must copy the message to the structure.
HC_SYSMODALOFF	A system-modal dialog box has been destroyed. The hook procedure must resume playing back the messages.
HC_SYSMODALON	A system-modal dialog box is being displayed. Until the dialog box is destroyed, the hook procedure must stop playing back messages.
If code is less than zero, the hook procedure must pass the message to the CallNextHookEx function without further processing and should return the value returned by CallNextHookEx.

wParam

Specifies a NULL value.

lParam

Points to an EVENTMSG structure that represents a message being processed by the hook procedure. This parameter is valid only when the code parameter is HC_GETNEXT.

Return Value

To have the system wait before processing the message, the return value must be the amount of time, in clock ticks, that the system should wait. (This value can be computed by calculating the difference between the time members in the current and previous input messages.) To process the message immediately, the return value should be zero. The return value is used only if the hook code is HC_GETNEXT; otherwise, it is ignored.

Remarks

A JournalPlaybackProc hook procedure should copy an input message to the lParam parameter. The message must have been previously recorded by using a JournalRecordProc hook procedure, which should not modify the message.

To retrieve the same message over and over, the hook procedure can be called several times with the code parameter set to HC_GETNEXT without an intervening call with code set to HC_SKIP.

If code is HC_GETNEXT and the return value is greater than zero, the system sleeps for the number of milliseconds specified by the return value. When the system continues, it calls the hook procedure again with code set to HC_GETNEXT to retrieve the same message. The return value from this new call to JournalPlaybackProc should be zero; otherwise, the system will go back to sleep for the number of milliseconds specified by the return value, call JournalPlaybackProc again, and so on. The system will appear to be hung.

Unlike most other global hook procedures, the JournalRecordProc and JournalPlaybackProc hook procedures are always called in the context of the thread that set the hook.

After the hook procedure returns control to the system, the message continues to be processed. If code is HC_SKIP, the hook procedure must prepare to return the next recorded event message on its next call.

An application installs a JournalPlaybackProc hook procedure by specifying the WH_JOURNALPLAYBACK hook type and the address of the hook procedure in a call to the SetWindowsHookEx function.

A Win32 JournalRecordProc hook procedure does not need to live in a dynamic-link library. A Win32 JournalRecordProc hook procedure can live in the application itself.

If the user presses CTRL+ESCAPE, ALT+ESCAPE, or CTRL+ALT+DEL during journal playback, the system stops the playback, unhooks the journal playback procedure, and posts a WM_CANCELJOURNAL message to the journaling application.

If the hook procedure returns a message in the range WM_KEYFIRST to WM_KEYLAST, the following conditions apply:

•	The paramL member of the EVENTMSG structure specifies the virtual key code of the key that was pressed.

•	The paramH member of the EVENTMSG structure specifies the scan code.

•	There's no way to specify a repeast count. The event is always taken to represent one key event.

JournalPlaybackProc is a placeholder for an application-defined or library-defined function name.

See Also

CallNextHookEx, EVENTMSG, JournalRecordProc, PeekMessage, SetWindowsHookEx, WM_CANCELJOURNAL


JournalRecordProc
JournalRecordProc  QuickInfo  Overview  Group

The JournalRecordProc hook procedure is a callback function that records messages the system removes from the system message queue. Later, an application can use a JournalPlaybackProc hook procedure to play back the messages.

LRESULT CALLBACK JournalRecordProc(

int  code,	// hook code
WPARAM  wParam,	// undefined
LPARAM  lParam	// address of message being processed
);
Parameters

code

Specifies how to process the message. This parameter can be one of the following values:

Value	Meaning
HC_ACTION	The lParam parameter points to an EVENTMSG structure containing information about a message removed from the system queue. The hook procedure must record the contents of the structure by copying them to a buffer or file.
HC_SYSMODALOFF	A system-modal dialog box has been destroyed. The hook procedure must resume recording.
HC_SYSMODALON	A system-modal dialog box is being displayed. Until the dialog box is destroyed, the hook procedure must stop recording.
If code is less than zero, the hook procedure must pass the message to the CallNextHookEx function without further processing and should return the value returned by CallNextHookEx.

wParam

Specifies a NULL value.

lParam

Points to an EVENTMSG structure that contains the message to be recorded.

Return Value

The return value is ignored.

Remarks

A JournalRecordProc hook procedure must copy but not modify the messages. After the hook procedure returns control to the system, the message continues to be processed.

An application installs a JournalRecordProc hook procedure by specifying the WH_JOURNALRECORD hook type and the address of the hook procedure in a call to the SetWindowsHookEx function.

A Win32 JournalRecordProc hook procedure does not need to live in a dynamic-link library. A Win32 JournalRecordProc hook procedure can live in the application itself.

Unlike most other global hook procedures, the JournalRecordProc and JournalPlaybackProc hook procedures are always called in the context of the thread that set the hook.

An application that has installed a JournalRecordProc hook procedure should watch for the VK_CANCEL virtual keycode (which is implemented as the CTRL+BREAK key combination on most keyboards). This virtual keycode should be interpreted by the application as a signal that the user wishes to stop journal recording. The application should respond by ending the recording sequence and removing the JournalRecordProc hook procedure. Removal is important. It prevents a journaling application from locking up the system by hanging inside a hook procedure.

This role as a signal to stop journal recording means that a CTRL+BREAK key combination cannot itself be recorded. Since the CTRL+C key combination has no such role as a journaling signal, it can be recorded. There are three other key combinations that cannot be recorded: CTRL+ESCAPE, ALT+ESCAPE, and CTRL+ALT+DEL. Those three key combinations cause the system to stop all journaling activities (record or playback), remove all journaling hooks, and post a WM_CANCELJOURNAL message to the journaling application.

JournalRecordProc is a placeholder for an application-defined or library-defined function name.

See Also

CallNextHookEx, EVENTMSG, JournalPlaybackProc, SetWindowsHookEx, WM_CANCELJOURNAL


keybd_event
keybd_event  QuickInfo  Overview  Group

The keybd_event function synthesizes a keystroke. The system can use such a synthesized keystroke to generate a WM_KEYUP or WM_KEYDOWN message. The keyboard driver's interrupt handler calls the keybd_event function.

VOID keybd_event(

BYTE  bVk,	// virtual-key code
BYTE  bScan,	// hardware scan code
DWORD  dwFlags,	// flags specifying various function options
DWORD  dwExtraInfo	// additional data associated with keystroke
);
Parameters

bVk

Specifies a virtual-key code. The code must be a value in the range 1 to 254.

bScan

Specifies a hardware scan code for the key.

dwFlags

A set of flag bits that specify various aspects of function operation. An application can use any combination of the following predefined constant values to set the flags:

Value	Meaning
KEYEVENTF_EXTENDEDKEY	If specified, the scan code was preceded by a prefix byte having the value 0xE0 (224).
KEYEVENTF_KEYUP	If specified, the key is being released. If not specified, the key is being depressed.
dwExtraInfo

Specifies an additional 32-bit value associated with the key stroke.

Return Value

This function has no return value.

Remarks

Although keybd_event passes an OEM-dependent hardware scan code to Windows, applications should not use the scan code. Windows converts scan codes to virtual-key codes internally and clears the up/down bit in the scan code before passing it to applications.

An application can simulate a press of the PRINTSCREEN key in order to obtain a screen snapshot and save it to the Windows clipboard. To do this, call keybd_event with the bVk parameter set to VK_SNAPSHOT, and the bScan parameter set to 0 for a snapshot of the full screen or set bScan to 1 for a snapshot of the active window.

See Also

GetAsyncKeyState, GetKeyState, MapVirtualKey, SetKeyboardState


KeyboardProc
KeyboardProc  QuickInfo  Overview  Group

The KeyboardProc hook procedure is an application-defined or library-defined callback function the system calls whenever an application calls the GetMessage or PeekMessage function and there is a keyboard message (WM_KEYUP or WM_KEYDOWN) to be processed.

LRESULT CALLBACK KeyboardProc(

int  code,	// hook code
WPARAM  wParam,	// virtual-key code
LPARAM  lParam	// keystroke-message information
);
Parameters

code

Specifies a code the hook procedure uses to determine how to process the message. This parameter can be one of the following values:

Value	Meaning
HC_ACTION	The wParam and lParam parameters contain information about a keystroke message.
HC_NOREMOVE	The wParam and lParam parameters contain information about a keystroke message, and the keystroke message has not been removed from the message queue. (An application called the PeekMessage function, specifying the PM_NOREMOVE flag.)
If code is less than zero, the hook procedure must pass the message to the CallNextHookEx function without further processing and should return the value returned by CallNextHookEx.

wParam

Specifies the virtual-key code of the key that generated the keystroke message.

lParam

Specifies the repeat count, scan code, extended-key flag, context code, previous key-state flag, and transition-state flag. This parameter can be a combination of the following values:

Value	Description
0−15	Specifies the repeat count. The value is the number of times the keystroke is repeated as a result of the user's holding down the key.
16−23	Specifies the scan code. The value depends on the original equipment manufacturer (OEM).
24	Specifies whether the key is an extended key, such as a function key or a key on the numeric keypad. The value is 1 if the key is an extended key; otherwise, it is 0.
25−28	Reserved.
29	Specifies the context code. The value is 1 if the ALT key is down; otherwise, it is 0.
30	Specifies the previous key state. The value is 1 if the key is down before the message is sent; it is 0 if the key is up.
31	Specifies the transition state. The value is 0 if the key is being pressed and 1 if it is being released.
For more information about the lParam parameter, see Keystroke Message Flags.Return Value

To prevent Windows from passing the message to the rest of the hook chain or to the target window procedure, the return value must be a nonzero value. To allow Windows to pass the message to the target window procedure, bypassing the remaining procedures in the chain, the return value must be zero.

Remarks

An application installs the hook procedure by specifying the WH_KEYBOARD hook type and the address of the hook procedure in a call to the SetWindowsHookEx function.

KeyboardProc is a placeholder for the application-defined or library-defined function name.

See Also

CallNextHookEx, GetMessage, PeekMessage, SetWindowsHookEx, WM_KEYUP, WM_KEYDOWN


KillTimer
KillTimer  QuickInfo  Overview  Group

The KillTimer function destroys the specified timer. The system searches the message queue for any pending WM_TIMER messages associated with the timer and removes them.

BOOL KillTimer(

HWND  hWnd,	// handle of window that installed timer
UINT  uIDEvent	// timer identifier
);
Parameters

hWnd

Identifies the window associated with the specified timer. This value must be the same as the hWnd value passed to the SetTimer function that created the timer.

uIDEvent

Specifies the timer to be destroyed. If the window handle passed to SetTimer is valid, this parameter must be the same as the uIDEvent value passed to SetTimer. If the application calls SetTimer with hWnd set to NULL, this parameter must be the timer identifier returned by SetTimer.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

SetTimer, WM_TIMER


LBItemFromPt [New - Windows NT]
LBItemFromPt  QuickInfo  Overview  Group

[New - Windows NT]

The LBItemFromPt function retrieves the index of the item at the specified point in a list box.

int LBItemFromPt(

HWND  hLB,
POINT  pt,
BOOL  bAutoScroll
);
Parameters

hLB

Handle to the list box to check.

pt

POINT structure that contains the screen coordinates to check.

bAutoScroll

Scroll flag. If this parameter is TRUE and the point is directly above or below the list box, the function scrolls the list box by one line and returns  − 1. Otherwise, the function does not scroll the list box.

Return Value

The return value is the item identifier if the point is over a list item, or  − 1 otherwise.

Remarks

The LBItemFromPt function only scrolls the list box if a minimum amount of time has passed since it last did so. Timing prevents the list box from scrolling too quickly if the function is called repeatedly in rapid succession — for example, when DL_DRAGGING notification messages or WM_MOUSEMOVE messages are processed.

If the specified point is outside the client area of the list box and bAutoScroll is TRUE, the function scrolls the list box instead of returning an item identifier.

See Also

DL_DRAGGING, POINT, WM_MOUSEMOVE


LCMapString
LCMapString  QuickInfo  Overview  Group

The LCMapString function maps one character string to another, performing a specified locale-dependent transformation. The function can also be used to generate a sort key for the input string.

int LCMapString(

LCID  Locale,	// locale identifier
DWORD  dwMapFlags,	// mapping transformation type
LPCTSTR  lpSrcStr,	// address of source string
int  cchSrc,	// number of characters in source string
LPTSTR  lpDestStr,	// address of destination buffer
int  cchDest	// size of destination buffer
);
Parameters

Locale

Specifies a locale identifier. The locale provides a context for the string mapping or sort key generation. An application can use the MAKELCID macro to create a locale identifier.

dwMapFlags

A set of flags that indicate the type of transformation to be used during string mapping or sort key generation. An application can specify more than one of these options on a single transformation, although some combinations are illegal. The following mapping options are defined; restrictions are noted following the table:

Option	Meaning
LCMAP_BYTEREV	Windows NT only: Use byte reversal. For example, if you pass in 0x3450 0x4822 the result is 0x5034 0x2248.
LCMAP_FULLWIDTH	Map single-byte characters to double-byte characters.
LCMAP_HALFWIDTH	Map double-byte characters to single-byte characters.
LCMAP_HIRAGANA	Map double-byte Katakana characters to double-byte Hiragana characters.
LCMAP_KATAKANA	Map double-byte Hiragana characters to double-byte Katakana characters.
LCMAP_LOWERCASE	Use lowercase.
LCMAP_SORTKEY	Produce a normalized wide-character sort key.
LCMAP_UPPERCASE	Use uppercase.
NORM_IGNORECASE	Ignore case.
NORM_IGNOREKANATYPE	Do not differentiate between Hiragana and Katakana characters. Corresponding Hiragana and Katakana will compare as equal.
NORM_IGNORENONSPACE	Ignore nonspacing. This flag also removes Japanese accent characters.
NORM_IGNORESYMBOLS	Ignore symbols.
NORM_IGNOREWIDTH	Do not differentiate between a single-byte character and the same character as a double-byte character.
SORT_STRINGSORT	Treat punctuation the same as symbols.
If the LCMAP_SORTKEY flag is not specified, the LCMapString function performs string mapping. In this case the following restrictions apply:

•	LCMAP_LOWERCASE and LCMAP_UPPERCASE are mutually exclusive.

•	LCMAP_HIRAGANA and LCMAP_KATAKANA are mutually exclusive.

•	LCMAP_HALFWIDTH and LCMAP_FULLWIDTH are mutually exclusive.

•	SORT_STRINGSORT, NORM_IGNOREKANATYPE, NORM_IGNOREWIDTH, and NORM_IGNORECASE are not valid.

•	LCMAP_LOWERCASE and LCMAP_UPPERCASE are not valid in combination with any of the following flags: LCMAP_HIRAGANA, LCMAP_KATAKANA, LCMAP_HALFWIDTH, and LCMAP_FULLWIDTH.

When the LCMAP_SORTKEY flag is specified, the LCMapString function generates a sort key. In this case the following restriction applies:

•	All LCMAP_* options are invalid, with the sole exception of LCMAP_BYTEREV. In other words, LCMAP_SORTKEY is mutually exclusive with all other LCMAP_* flags, with the sole exception of LCMAP_BYTEREV. LCMAP_BYTEREV is valid for Windows NT only.

lpSrcStr

Pointer to a source string that the function maps or uses for sort key generation.

cchSrc

Specifies the number of bytes (ANSI version) or characters (Unicode version) in the string pointed to by the lpSrcStr parameter.

This count can include the NULL terminator, or not include it. If the NULL terminator is included in the character count, it does not greatly affect the mapping behavior. That is because NULL is considered to be unsortable, and always maps to itself.

A cchSrc value of −1 specifies that the string pointed to by lpSrcStr is null-terminated. If this is the case, and LCMapString is being used in its string-mapping mode, the function calculates the string's length itself, and null-terminates the mapped string stored into *lpDestStr.

lpDestStr

Pointer to a buffer into which the function stores the mapped string or sort key.

If LCMAP_SORTKEY is specified, LCMapString stores a sort key into the buffer. The sort key is stored as an array of byte values in the following format:

[all Unicode sort weights] 0x01 [all Diacritic weights] 0x01 [all Case weights] 0x01 [all Special weights] 0x00

Note that the sort key is null-terminated. This is true regardless of the value of cchSrc. Also note that, even if some of the sort weights are absent from the sort key, due to the presence of one or more ignore flags in dwMapFlags, the 0x01 separators and the 0x00 terminator are still present.

cchDest

Specifies the size in bytes (ANSI version) or characters (Unicode version) of the buffer pointed to by lpDestStr.

If the function is being used for string mapping, the size is a character count. If space for a NULL terminator is included in cchSrc, then cchDest must also include space for a NULL terminator.

If the function is being used to generate a sort key, the size is a byte count. This byte count must include space for the sort key 0x00 terminator.

If cchDest is zero, the function's return value is the number of characters, or bytes if LCMAP_SORTKEY is specified, required to hold the mapped string or sort key. In this case, the buffer pointed to by lpDestStr is not used.

Return Value

If the function succeeds, and the value of cchDest is nonzero, the return value is the number of characters, or bytes if LCMAP_SORTKEY is specified, written to the buffer. This count includes room for a NULL terminator.

If the function succeeds, and the value of cchDest is zero, the return value is the size of the buffer in characters, or bytes if LCMAP_SORTKEY is specified, required to receive the translated string or sort key. This size includes room for a NULL terminator.

If the function fails, the return value is 0. To get extended error information, call GetLastError. GetLastError may return one of the following error codes:

ERROR_INSUFFICIENT_BUFFER
ERROR_INVALID_FLAGS
ERROR_INVALID_PARAMETER

Remarks

The mapped string is null terminated if the source string is null terminated.

The A version of this function maps strings to and from Unicode based on the specified LCID's default ANSI code page.

If the LCMAP_HIRAGANA flag is specified to map Katakana characters to Hiragana characters, and LCMAP_FULLWIDTH is not specified, the function only maps full-width characters to Hiragana. In this case, any half-width Katakana characters are placed as-is in the output string, with no mapping to Hiragana. An application must specify LCMAP_FULLWIDTH if it wants half-width Katakana characters mapped to Hiragana.

The lpSrcStr and lpDestStr pointers must not be the same. If they are the same, the function fails, and GetLastError returns ERROR_INVALID_PARAMETER.

Even if the wide-character Unicode version of this function is called, the output string is only in WCHAR or CHAR format if the string mapping mode of LCMapString is used. If the sort key generation mode is used, specified by LCMAP_SORTKEY, the output is an array of byte values. An application can compare sort keys by using a byte-by-byte comparison.

An application can call the function with the NORM_IGNORENONSPACE and NORM_IGNORESYMBOLS flags set, and all other options flags cleared, in order to simply strip characters from the input string. If this is done with an input string that is not null-terminated, it is possible for LCMapString to return an empty string and not return an error.

The LCMapString function ignores the Arabic Kashida. If an application calls the function to create a sort key for a string containing an Arabic Kashida, there will be no sort key value for the Kashida.

The function treats the hyphen and apostrophe a bit differently than other punctuation symbols, so that words like coop and co-op stay together in a list. All punctuation symbols other than the hyphen and apostrophe sort before the alphanumeric characters. An application can change this behavior by setting the SORT_STRINGSORT flag. See CompareString for a more detailed discussion of this issue.

When LCMapString is used to generate a sort key, by setting the LC_MAPSORTKEY flag, the sort key stored into *lpDestStr may contain an odd number of bytes. The LCMAP_BYTEREV option (Windows NT only) only reverses an even number of bytes. If both options are chosen, the last (odd-positioned) byte in the sort key is not reversed. If the terminating 0x00 byte is an odd-positioned byte, then it remains the last byte in the sort key. If the terminating 0x00 byte is an even-positioned byte, it exchanges positions with the byte that precedes it.

See Also

CompareString, FoldString, MAKELCID


LeaveCriticalSection
LeaveCriticalSection  QuickInfo  Overview  Group

The LeaveCriticalSection function releases ownership of the specified critical section object.

VOID LeaveCriticalSection(

LPCRITICAL_SECTION  lpCriticalSection	// address of critical section object
);
Parameters

lpCriticalSection

Points to the critical section object.

Return Value

This function does not return a value.

Remarks

A thread uses the EnterCriticalSection function to acquire ownership of a critical section object. Once a thread owns a critical section, it can make additional calls to EnterCriticalSection without blocking its execution. This prevents a thread from deadlocking itself while waiting for a critical section that it already owns. To release its ownership, the thread must call LeaveCriticalSection once for each time that it entered the critical section.

If a thread calls LeaveCriticalSection when it does not have ownership of the specified critical section object, an error occurs that may cause another thread using EnterCriticalSection to wait indefinitely.

The threads of a single process can use a critical section object to provide mutually exclusive access to a shared resource. For similar synchronization between the threads of different processes, use a mutex object.

See Also

CreateMutex, DeleteCriticalSection, EnterCriticalSection, InitializeCriticalSection


LimitEmsPages
LimitEmsPages  Overview  Group

The LimitEmsPages function is obsolete.

This function is provided only for compatibility with 16-bit versions of Windows. New Win32-based applications do not require this function.


LineDDA
LineDDA  QuickInfo  Overview  Group

The LineDDA function determines which pixels should be highlighted for a line defined by the specified starting and ending points.

BOOL LineDDA(

int  nXStart,	// x-coordinate of line's starting point
int  nYStart,	// y-coordinate of line's starting point
int  nXEnd,	// x-coordinate of line's ending point
int  nYEnd,	// y-coordinate of line's ending point
LINEDDAPROC  lpLineFunc,	// address of application-defined callback function
LPARAM  lpData	// address of application-defined data
);
Parameters

nXStart

Specifies the x-coordinate of the line's starting point.

nYStart

Specifies the y-coordinate of the line's starting point.

nXEnd

Specifies the x-coordinate of the line's ending point.

nYEnd

Specifies the y-coordinate of the line's ending point.

lpLineFunc

Specifies the address of an application-defined callback function. For more information, see the LineDDAProc callback function.

lpData

Points to the application-defined data.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

The LineDDA function passes the coordinates for each point along the line, except for the line's ending point, to the application-defined callback function. In addition to passing the coordinates of a point, this function passes any existing application-defined data.

The coordinates passed to the callback function match pixels on a video display only if the default transformations and mapping modes are used.

See Also

LineDDAProc


LineDDAProc
LineDDAProc  QuickInfo  Overview  Group

A LineDDAProc function is an application-defined callback function that processes coordinates from the LineDDA function. A value of type LINEDDAPROC is a pointer to such a function.

VOID CALLBACK LineDDAProc(

int  X,	// x-coordinate of point being evaluated
int  Y,	// y-coordinate of point being evaluated
LPARAM  lpData	// address of application-defined data
);
Parameters

X

Specifies the x-coordinate of the current point.

Y

Specifies the y-coordinate of the current point.

lpData

Points to the application-defined data.

Remarks

LineDDAProc is a placeholder for an application-defined function name.

An application registers a LineDDAProc function by passing its address to the LineDDA function.

See Also

LineDDA


LineTo
LineTo  QuickInfo  Overview  Group

The LineTo function draws a line from the current position up to, but not including, the specified point.

BOOL LineTo(

HDC  hdc,	// device context handle
int  nXEnd,	// x-coordinate of line's ending point
int  nYEnd	// y-coordinate of line's ending point
);
Parameters

hdc

Identifies a device context.

nXEnd

Specifies the x-coordinate of the line's ending point.

nYEnd

Specifies the y-coordinate of the line's ending point.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

The coordinates of the line's ending point are specified in logical units.

The line is drawn by using the current pen and, if the pen is a geometric pen, the current brush.

If LineTo succeeds, the current position is set to the specified ending point.

See Also

MoveToEx, Polyline, PolylineTo


listen
listen  QuickInfo

The Windows Sockets listen function establishes a socket to listen for incoming connection.

int listen (

SOCKET s,
int backlog
);
Parameters

s

A descriptor identifying a bound, unconnected socket.

backlog

The maximum length to which the queue of pending connections may grow.

Remarks

To accept connections, a socket is first created with socket, a backlog for incoming connections is specified with listen, and then the connections are accepted with accept. The listen function applies only to sockets that support connections, in other words, those of type SOCK_STREAM. The socket s is put into "passive" mode where incoming connections are acknowledged and queued pending acceptance by the process.

This function is typically used by servers that could have more than one connection request at a time: if a connection request arrives with the queue full, the client will receive an error with an indication of WSAECONNREFUSED.

The listen function attempts to continue to function correctly when there are no available descriptors. It will accept connections until the queue is emptied. If descriptors become available, a later call to listen or accept will refill the queue to the current or most recent "backlog," if possible, and resume listening for incoming connections.

Compatibility

The backlog parameter is currently limited (silently) to 5. As in 4.3BSD, illegal values (less than 1 or greater than 5) are replaced by the nearest legal value.

Return Value

If the function succeeds, listen returns zero.

If the function failes, a value of SOCKET_ERROR is returned. To get extended error information, call WSAGetLastError.

Error Codes

WSANOTINITIALISED	A successful WSAStartup must occur before using this function.
WSAENETDOWN	The Windows Sockets implementation has detected that the network subsystem has failed.
WSAEADDRINUSE	An attempt has been made to listen on an address in use.
WSAEINPROGRESS	A blocking Windows Sockets operation is in progress.
WSAEINVAL	The socket has not been bound with bind or is already connected.
WSAEISCONN	The socket is already connected.
WSAEMFILE	No more file descriptors are available.
WSAENOBUFS	No buffer space is available.
WSAENOTSOCK	The descriptor is not a socket.
WSAEOPNOTSUPP	The referenced socket is not of a type that supports the listen operation.
See Also

accept, bind, connect, socket, WSAStartup


LoadAccelerators
LoadAccelerators  QuickInfo  Overview  Group

The LoadAccelerators function loads the specified accelerator table.

HACCEL LoadAccelerators(

HINSTANCE  hInstance,	// handle of application instance
LPCTSTR  lpTableName	// address of table-name string
);
Parameters

hInstance

Identifies an instance of the module whose executable file contains the accelerator table to load.

lpTableName

Points to a null-terminated string that names the accelerator table to load. Alternatively, this parameter can specify the resource identifier of an accelerator-table resource in the low-order word and zero in the high-order word. The MAKEINTRESOURCE macro can be used to create this value.

Return Value

If the function succeeds, the return value is the handle of the loaded accelerator table.

If the function fails, the return value is NULL.

Remarks

If the accelerator table has not yet been loaded, the function loads it from the specified executable file.

Accelerator tables loaded from resources are freed automatically when the application terminates.

See Also

CopyAcceleratorTable, CreateAcceleratorTable, DestroyAcceleratorTable, MAKEINTRESOURCE


LoadBitmap
LoadBitmap  QuickInfo  Overview  Group

The LoadBitmap function loads the specified bitmap resource from a module's executable file.

HBITMAP LoadBitmap(

HINSTANCE  hInstance,	// handle of application instance
LPCTSTR  lpBitmapName	// address of bitmap resource name
);
Parameters

hInstance

Identifies the instance of the module whose executable file contains the bitmap to be loaded.

lpBitmapName

Points to a null-terminated string that contains the name of the bitmap resource to be loaded. Alternatively, this parameter can consist of the resource identifier in the low-order word and zero in the high-order word. The MAKEINTRESOURCE macro can be used to create this value.

Return Value

If the function succeeds, the return value is the handle of the specified bitmap.

If the function fails, the return value is NULL.

Remarks

If the bitmap pointed to by the lpBitmapName parameter does not exist or there is insufficient memory to load the bitmap, the function fails.

An application can use the LoadBitmap function to access the predefined bitmaps used by the Win32 API. To do so, the application must set the hInstance parameter to NULL and the lpBitmapName parameter to one of the following values:

OBM_BTNCORNERS	OBM_OLD_RESTORE
OBM_BTSIZE	OBM_OLD_RGARROW
OBM_CHECK	OBM_OLD_UPARROW
OBM_CHECKBOXES	OBM_OLD_ZOOM
OBM_CLOSE	OBM_REDUCE
OBM_COMBO	OBM_REDUCED
OBM_DNARROW	OBM_RESTORE
OBM_DNARROWD	OBM_RESTORED
OBM_DNARROWI	OBM_RGARROW
OBM_LFARROW	OBM_RGARROWD
OBM_LFARROWD	OBM_RGARROWI
OBM_LFARROWI	OBM_SIZE
OBM_MNARROW	OBM_UPARROW
OBM_OLD_CLOSE	OBM_UPARROWD
OBM_OLD_DNARROW	OBM_UPARROWI
OBM_OLD_LFARROW	OBM_ZOOM
OBM_OLD_REDUCE	OBM_ZOOMD
Bitmap names that begin with OBM_OLD represent bitmaps used by Windows versions earlier than 3.0.

For an application to use any of the OBM_ constants, the constant OEMRESOURCE must be defined before the WINDOWS.H header file is included.

The application must call the DeleteObject function to delete each bitmap handle returned by the LoadBitmap function.

See Also

CreateBitmap, DeleteObject, LoadCursor, LoadIcon, MAKEINTRESOURCE


LoadCursor
LoadCursor  QuickInfo  Overview  Group

The LoadCursor function loads the specified cursor resource from the executable (.EXE) file associated with an application instance.

HCURSOR LoadCursor(

HINSTANCE  hInstance,	// handle of application instance
LPCTSTR  lpCursorName	// name string or cursor resource identifier
);
Parameters

hInstance

Identifies an instance of the module whose executable file contains the cursor to be loaded.

lpCursorName

Points to a null-terminated string that contains the name of the cursor resource to be loaded. Alternatively, this parameter can consist of the resource identifier in the low-order word and zero in the high-order word. The MAKEINTRESOURCE macro can also be used to create this value.

To use one of the Win32 predefined cursors, the application must set the hInstance parameter to NULL and the lpCursorName parameter to one the following values:

Value	Description
IDC_APPSTARTING	Standard arrow and small hourglass
IDC_ARROW	Standard arrow
IDC_CROSS	Crosshair
IDC_IBEAM	Text I-beam
IDC_ICON	Windows NT only: Empty icon
IDC_NO	Slashed circle
IDC_SIZE	Windows NT only: Four-pointed arrow
IDC_SIZEALL	Same as IDC_SIZE
IDC_SIZENESW	Double-pointed arrow pointing northeast and southwest
IDC_SIZENS	Double-pointed arrow pointing north and south
IDC_SIZENWSE	Double-pointed arrow pointing northwest and southeast
IDC_SIZEWE	Double-pointed arrow pointing west and east
IDC_UPARROW	Vertical arrow
IDC_WAIT	Hourglass
Return Value

If the function succeeds, the return value is the handle of the newly loaded cursor.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

LoadCursor only loads the cursor resource if it has not been loaded; otherwise, it retrieves the handle of the existing resource. This function returns a valid cursor handle only if the lpCursorName parameter points to a cursor resource. If lpCursorName points to any type of resource other than a cursor (such as an icon), the return value is not NULL, even though it is not a valid cursor handle.

The LoadCursor function searches the cursor resource most appropriate for the cursor for the current display device. The cursor resource can be a color or monochrome bitmap.

See Also

LoadImage, MAKEINTRESOURCE, SetCursor, SetCursorPos, ShowCursor


LoadCursorFromFile
LoadCursorFromFile  QuickInfo  Overview  Group

The LoadCursorFromFile function creates a cursor based on data contained in a file. The file is specified by its name or by a system cursor identifier. The function returns a handle to the newly created cursor. Files containing cursor data may be in either cursor (.CUR) or animated cursor (.ANI) format.

HCURSOR LoadCursorFromFile (

LPCTSTR  lpFileName	// pointer to name of cursor file, or system cursor identifier
);
Parameters

lpFileName

Indicates the source of the file data to be used to create the cursor. The data in the file must be in either .CUR or .ANI format.

If the high-order word of lpszFileName is nonzero, it is a pointer to a string that is a fully qualified name of a file containing cursor data.

If the high-order word of lpszFileName is zero, the low-order word is a system cursor identifier. The function then searches the [Cursors] entry in the WIN.INI file for the file associated with the name of that system cursor. Here is a list of system cursor names and identifiers:

System Cursor Names	System Cursor Identifiers
"Arrow"	OCR_NORMAL
"IBeam"	OCR_IBEAM
"Wait"	OCR_WAIT
"Crosshair"	OCR_CROSS
"UpArrow"	OCR_UP
"Size"	OCR_SIZE
"Icon"	OCR_ICON
"SizeNWSE"	OCR_SIZENWSE
"SizeNESW"	OCR_SIZENESW
"SizeWE"	OCR_SIZEWE
"SizeNS"	OCR_SIZENS
"SizeAll"	OCR_SIZEALL
"No"	OCR_NO
"AppStarting"	OCR_APPSTARTING
For example, if the WIN.INI file contains the following :

[Cursors]

Arrow = "arrow.ani"

Then the call

LoadCursorFromFile((LPWSTR)OCR_NORMAL)

causes the LoadCursorFromFile function to obtain cursor data from the file ARROW.ANI. If the WIN.INI file doesn't contain an entry for the specified system cursor, the function fails and returns NULL.

Return Value

If the function is successful, the return value is a handle to the new cursor.

If the function fails, the return value is NULL. To get extended error information, call GetLastError. GetLastError may return the following value:

Value	Meaning
ERROR_FILE_NOT_FOUND	The specified file could not be found.
See Also

LoadCursor, SetCursor, SetSystemCursor


LoadIcon
LoadIcon  QuickInfo  Overview  Group

The LoadIcon function loads the specified icon resource from the executable (.EXE) file associated with an application instance.

HICON LoadIcon(

HINSTANCE  hInstance,	// handle of application instance
LPCTSTR  lpIconName	// icon-name string or icon resource identifier
);
Parameters

hInstance

Identifies an instance of the module whose executable file contains the icon to be loaded. This parameter must be NULL when a standard icon is being loaded.

lpIconName

Points to a null-terminated string that contains the name of the icon resource to be loaded. Alternatively, this parameter can contain the resource identifier in the low-order word and zero in the high-order word. Use the MAKEINTRESOURCE macro to create this value.

To use one of the Windows predefined icons, set the hInstance parameter to NULL and the lpIconName parameter to one of the following values:

Value	Description
IDI_APPLICATION	Default application icon.
IDI_ASTERISK	Asterisk (used in informative messages).
IDI_EXCLAMATION	Exclamation point (used in warning messages).
IDI_HAND	Hand-shaped icon (used in serious warning messages).
IDI_QUESTION	Question mark (used in prompting messages).
IDI_WINLOGO	Windows 95 only: Windows logo.
Return Value

If the function succeeds, the return value is the handle of the newly loaded icon.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

LoadIcon loads the icon resource only if it has not been loaded; otherwise, it retrieves a handle to the existing resource. The function searches the icon resource for the icon most appropriate for the current display. The icon resource can be a color or monochrome bitmap.

Windows 95 only: LoadIcon can only load an icon whose size conforms to the SM_CXICON and SM_CYICON system metric values. Use the LoadImage function to load icons of other sizes.

See Also

CreateIcon, LoadImage, MAKEINTRESOURCE


LoadImage [New - Windows 95]
LoadImage  QuickInfo  Overview  Group

[New - Windows 95]

The LoadImage function loads an icon, cursor, or bitmap.

HANDLE LoadImage(

HINSTANCE  hinst,	// handle of the instance that contains the image
LPCTSTR  lpszName,	// name or identifier of image
UINT  uType,	// type of image
int  cxDesired,	// desired width
int  cyDesired,	// desired height
UINT  fuLoad	// load flags
);
Parameters

hinst

Identifies an instance of the module that contains the image to be loaded. To load an OEM image, set this parameter to zero.

lpszName

Identifies the image to load.

If the hinst parameter is non-NULL and the fuLoad parameter does not include LR_LOADFROMFILE, lpszName is a pointer to a null-terminated string that contains the name of the image resource in the hinst module.

If hinst is NULL and LR_LOADFROMFILE is not specified, the low-order word of this parameter must be the identifier of the OEM image to load. The OEM image identifiers are defined in WINUSER.H and have the following prefixes:

Prefix	Meaning
OBM_	OEM bitmaps
OIC_	OEM icons
OCR_	OEM cursors
Windows 95: If the fuLoad parameter includes the LR_LOADFROMFILE value, lpszName is the name of the file that contains the image.

Windows NT: LR_LOADFROMFILE is not supported.

uType

Specifies the type of image to be loaded. This parameter can be one of the following values:

Value	Meaning
IMAGE_BITMAP	Loads a bitmap.
IMAGE_CURSOR	Loads a cursor.
IMAGE_ICON	Loads an icon.
cxDesired

Specifies the desired width, in pixels, of the icon or cursor. If this parameter is zero and fuLoad does not include LR_LOADREALSIZE, the function uses the SM_CXICON or SM_CXCURSOR system metric value to set the width.

cyDesired

Specifies the desired height, in pixels, of the icon or cursor. If this parameter is zero and fuLoad does not include LR_LOADREALSIZE, the function uses the SM_CYICON or SM_CYCURSOR system metric value to set the height.

fuLoad

Specifies a combination of the following values:

Value	Meaning
LR_DEFAULTCOLOR	The default flag; it does nothing. All it means is "not LR_MONOCHROME".
LR_LOADREALSIZE	Loads the image without any stretching.
LR_CREATEDIBSECTION	Windows 95 only: When the uType parameter specifies IMAGE_BITMAP, causes the function to return a DIB section bitmap rather than a compatible bitmap. This flag is useful for loading a bitmap without mapping it to the colors of the display device.
LR_DEFAULTSIZE	Windows 95 only: Uses the width or height specified by the system metric values for cursors and icons, if the cxDesired or cyDesired values are set to zero. If this flag is not specified and cxDesired and cyDesired are set to zero, the function sets the size to that specified in the resource. If the resource contains multiple images, the function sets the size to that of the first image.
LR_LOADFROMFILE	Windows 95 only: Loads the image from the file specified by the lpszName parameter. If this flag is not specified, lpszName is the name of the resource.
LR_LOADMAP3DCOLORS	Windows 95 only: Searches the color table for the image and replaces the following shades of gray with the corresponding 3D color:
Color	Replaced with
Dk Gray, RGB(128,128,128)	COLOR_3DSHADOW
Gray, RGB(192,192,192)	COLOR_3DFACE
Lt Gray, RGB(223,223,223)	COLOR_3DLIGHT
LR_LOADTRANSPARENT	Windows 95 only: Retrieves the color value of the first pixel in the image and replaces the corresponding entry in the color table with the default window color (COLOR_WINDOW). All pixels in the image that use that entry become the default window color. This value applies only to images that have corresponding color tables.  If fuLoad includes both the LR_LOADTRANSPARENT and LR_LOADMAP3DCOLORS values, LRLOADTRANSPARENT takes precedence. However, the color table entry is replaced with COLOR_3DFACE rather than COLOR_WINDOW.
LR_MONOCHROME	Windows 95 only: Loads the image in black and white.
LR_SHARED	Windows 95 only: Shares the image handle if the image is loaded multiple times. If LR_SHARED is not set, a second call to LoadImage for the same resource will load the image again and return a different handle. Do not use LR_SHARED for images that have non-standard sizes, that may change after loading, or that are loaded from a file.
Return Value

If the function succeeds, the return value is the handle of the newly loaded image.

If the function fails, the return value is NULL.

See Also

CopyImage, GetSystemMetrics, LoadBitmap, LoadCursor, LoadIcon


LoadKeyboardLayout
LoadKeyboardLayout  QuickInfo  Overview  Group

The implementations of LoadKeyboardLayout in Windows 95 and Windows NT are substantially different. To accommodate these differences, this reference page first presents the Windows 95 implementation in its entirety, followed by the Windows NT version.

Windows 95:

The LoadKeyboardLayout function loads a new keyboard layout into the system. Several keyboard layouts can be loaded at a time, but only one per process is active at a time. Loading multiple keyboard layouts makes it possible to rapidly switch between layouts.

HKL LoadKeyboardLayout(

LPCTSTR  pwszKLID,	// name of layout to load
UINT  Flags	// keyboard layout flags
);
Parameters

pwszKLID

Points to the buffer that specifies the name of the keyboard layout. This name is a string composed from the hexadecimal value of the primary language identifier (low word) and a device identifier (high word). For example, U.S. English has a language identifier of 0x0409, so the primary U.S. English layout is named "00000409". Variants of U.S. English layout, such as the Dvorak layout, are named "00010409", "00020409", and so on. For a list of the primary language identifiers and secondary language identifiers that make up a language identifier, see the MAKELANGID macro.

Flags

Specifies how the keyboard layout is to be loaded. This parameter can be one of the following values:

Value	Meaning
KLF_ACTIVATE	If the given layout is not already loaded, the function loads and activates the layout for the current thread, inserting the layout at the head of the keyboard layouts list in front of the previously active layout. If the layout is already loaded and the KLF_REORDER value is not given, the function simply rotates the keyboard layouts list, making the next layout the active layout.
KLF_NOTELLSHELL	Prevents a ShellProc hook procedure from receiving an HSHELL_LANGUAGE hook code when the new layout is loaded. This value is typically used when an application loads multiple layouts, one after another. Applying this value to all but the last layout delays the shell's processing until all layouts have been added.
KLF_REORDER	Moves the given layout to the head of the keyboard layouts list, making that layout the active layout for the current thread. This value reorders the keyboard layouts list even if KLF_ACTIVATE is not given.
KLF_REPLACELANG	If the new layout has the same language identifier as a current layout, the new layout replaces the current one as the layout for that language. If this value is not given and the layouts have the same language identifiers, the current layout is not replaced and the function returns NULL.
KLF_SUBSTITUTE_OK	Substitues the given keyboard layout with another layout preferred by the user. The substitution occurs only if the registry key HKEY_CURRENT_USER\Keyboard Layout\Substitutes explicitly defines a substitution layout. For example, if the key includes the value name "00000409" with value "00010409", loading the U.S. English layout ("00000409") causes the Dvorak U.S. English layout ("00010409") to be loaded instead. The system uses KLF_SUBSTITUTE_OK when booting and it is recommended that all applications use this value too.
Return Value

If the function succeeds, the return value is the keyboard layout handle of the layout matched with the requested name or NULL if no matching keyboard is available.

Remarks

If a layout is to be loaded with the same language as a previously loaded one and the KLF_REPLACELANG flag is not set, the call fails. Only one loaded layout may be associated with a given language. (It is acceptable for multiple IMEs to be loaded with associations to the same language.)

An application can and will typically want to load the default layout or IME for a language and can do so by specifying only a string version of the language identifier. If an application wants to load a specific layout or IME, it should read the registry to determine the specific layout identifier to pass to LoadKeyboardLayout. In this case, a request to activate the default keyboard layout handle for a locale will activate the first matching one. A specific IME should be activated using an explicit keyboard layout handle returned from one of GetKeyboardLayout, GetKeyboardLayoutList or LoadKeyboardLayout.

See Also

ActivateKeyboardLayout, GetKeyboardLayout, GetKeyboardLayoutName, MAKELANGID, UnloadKeyboardLayout

Windows NT:

The LoadKeyboardLayout function loads a keyboard layout.

HKL LoadKeyboardLayout(

LPCTSTR  pwszKLID,	// address of buffer for layout name
UINT  Flags	// keyboard layout flags
);
Parameters

pwszKLID

Points to the buffer that specifies the name of the keyboard layout. The name should be derived from the hexadecimal value of the language identifier corresponding to the layout. For example, U.S. English has a language identifier of 0x0409, so the primary U.S. English layout is named "00000409". Variants of U.S. English layout, such as the Dvorak layout, are named "00010409",  "00020409", and so on. For a list of the primary language identifiers and sub-language identifiers that make up a language identifier, see the MAKELANGID macro.

Flags

Specifies how the keyboard layout is to be loaded. This parameter can be one of the following values:

Value	Meaning
KLF_ACTIVATE	The function loads the layout if it is not already loaded, and activates it. This value activates the layout for the entire system not just the calling thread.
KLF_REORDER	This flag is meaningful only if the KLF_ACTIVATE flag is set and the layout is already loaded. If these conditions are met and the KLF_REORDER bit is set, the function removes the specified layout from its position in the system's circular list of loaded layouts, and places it at the head of the list as the active layout.
	If the KLF_ACTIVATE bit is set and the layout is loaded but the KLF_REORDER bit is not set, the function simply rotates the system's circular list of loaded layouts.
	If the KLF_ACTIVATE flag is set and the layout is not already loaded, it is loaded as the active layout and inserted in the system's circular list of keyboard layouts ahead of the previously active layout.
KLF_SUBSTITUTE_OK	The specified layout is looked up in the user's profile (in the registry under the key HKEY_CURRENT_USER\Keyboard Layout\Substitutes) to find a substitution layout preferred by the user. For example, if there was a value in this section of name "00000409" equal to "00010409", loading the U.S. English layout ("00000409") with the KLF_SUBSTITUTE_OK flag set would cause the Dvorak U.S. English layout ("00010409") to be loaded.
KLF_UNLOADPREVIOUS	If KLF_ACTIVATE is specified, and the layout is loaded and activated successfully, the function unloads the previously active layout. Otherwise, the function ignores this flag.
Return Value

If the function succeeds, the return value is the handle of the keyboard layout.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

Several keyboard layouts can be loaded at a time, but only one at a time is active. Loading multiple keyboard layouts makes it possible to switch rapidly between layouts.

See Also

ActivateKeyboardLayout, GetKeyboardLayoutName, UnloadKeyboardLayout


LoadLibrary
LoadLibrary  QuickInfo  Overview  Group

The LoadLibrary function maps the specified executable module into the address space of the calling process.

HINSTANCE LoadLibrary(

LPCTSTR  lpLibFileName	// address of filename of executable module
);
Parameters

lpLibFileName

Points to a null-terminated string that names the Win32 module (either a .DLL or .EXE file). The name specified is the filename of the module and is not related to the name stored in the library module itself, as specified by the LIBRARY keyword in the module-definition (.DEF) file.

If the string specifies a path but the file does not exist in the specified directory, the function fails.

If a path is not specified and the filename extension is omitted, the default library extension .DLL is appended. However, the filename string can include a trailing point character (.) to indicate that the module name has no extension. When no path is specified, the function searches for the file in the following sequence:

1.	The directory from which the application loaded.

2.	The current directory.

3.	Windows 95: The Windows system directory. Use the GetSystemDirectory function to get the path of this directory.

Windows NT: The 32-bit Windows system directory. Use the GetSystemDirectory function to get the path of this directory. The name of this directory is SYSTEM32.

4.	Windows NT only: The 16-bit Windows system directory. There is no Win32 function that obtains the path of this directory, but it is searched. The name of this directory is SYSTEM.

5.	The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.

6.	The directories that are listed in the PATH environment variable.

The first directory searched is the one directory containing the image file used to create the calling process (for more information, see the CreateProcess function). Doing this allows private dynamic-link library (DLL) files associated with a process to be found without adding the process's installed directory to the PATH environment variable.

Once the function obtains a fully qualified path to a library module file, the path is compared (case independently) to the full paths of library modules currently loaded into the calling process. These libraries include those loaded when the process was starting up as well as those previously loaded by LoadLibrary but not unloaded by FreeLibrary. If the path matches the path of an already loaded module, the function just increments the reference count for the module and returns the module handle for that library.

Return Value

If the function succeeds, the return value is a handle to the module.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

LoadLibrary can be used to map a DLL module and return a handle that can be used in GetProcAddress to get the address of a DLL function. LoadLibrary can also be used to map other executable modules. For example, the function can specify an .EXE file to get a handle that can be used in FindResource or LoadResource.

Module handles are not global or inheritable. A call to LoadLibrary by one process does not produce a handle that another process can use — for example, in calling GetProcAddress. The other process must make its own call to LoadLibrary for the module before calling GetProcAddress.

If the module is a DLL not already mapped for the calling process, the system calls the DLL's DllEntryPoint function with the DLL_PROCESS_ATTACH value. If the DLL's entry-point function does not return TRUE, LoadLibrary fails and returns NULL.

See Also

DllEntryPoint, FindResource, FreeLibrary, GetProcAddress, GetSystemDirectory, GetWindowsDirectory, LoadResource


LoadLibraryEx
LoadLibraryEx  QuickInfo  Overview  Group

The LoadLibraryEx function maps a specified executable module into the address space of the calling process. The executable module can be a .DLL or an .EXE file. The specified module may cause other modules to be mapped into the address space.

HINSTANCE LoadLibraryEx(

LPCTSTR  lpLibFileName,	// points to name of executable module
HANDLE  hFile,	// reserved, must be NULL
DWORD  dwFlags	// entry-point execution flag
);
Parameters

lpLibFileName

Points to a null-terminated string that names a Win32 executable module (either a .DLL or an .EXE file). The name specified is the filename of the executable module. This name is not related to the name stored in a library module itself, as specified by the LIBRARY keyword in the module-definition (.DEF) file.

If the string specifies a path, but the file does not exist in the specified directory, the function fails.

If the string does not specify a path, and the filename extension is omitted, the function appends the default library extension .DLL to the filename. However, the filename string can include a trailing point character (.) to indicate that the module name has no extension.

If the string does not specify a path, the function uses a standard search strategy to find the file. See the Remarks for more information.

If mapping the specified module into the address space causes the operating system to map in other, associated executable modules, the function can use either the standard search strategy or an alternate search strategy to find those modules. See the Remarks for more information.

Once the function obtains a fully qualified path to a library module file, the path is compared (in a case-independent manner) to the full paths of library modules that are currently loaded into the calling process. That set of libraries includes those that were loaded when the process was starting up, as well as those previously loaded by calls to LoadLibrary or LoadLibraryEx but not yet unloaded by calls to FreeLibrary. If the path matches the path of an already loaded module, the function just increments the reference count for the module, and returns the module handle for that library.

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:

Flag	Meaning
DONT_RESOLVE_DLL_REFERENCES
	Windows NT only:  If this value is given, and the executable module is a dynamic-link library (DLL), the operating system does not call the DllEntryPoint function for process and thread initialization and termination. Also, the system does not load additional executable modules that are referenced by the specified module. If this value is not given, and the executable module is a DLL, the operating system calls the DllEntryPoint function for process and thread initialization and termination. The system loads additional executable modules that are referenced by the specified module. The behavior of the function is then identical to that of LoadLibrary in this regard.
LOAD_LIBRARY_AS_DATAFILE
	If this value is given, the function does a simple mapping of the file into the address space. Nothing is done relative to executing or preparing to execute the code in the mapped file. The function loads the module as if it were a data file. You can use the module handle that the function returns in this case with the Win32 functions that operate on resources. Use this flag when you want to load a DLL in order to extract messages or resources from it, and have no intention of executing its code. If this value is not given, the function maps the file into the address space in the manner that is normal for an executable module. The behavior of the function is then identical to that of LoadLibrary in this regard.
LOAD_WITH_ALTERED_SEARCH_PATH
	If this value is given, and lpLibFileName specifies a path, the function uses the alternate file search strategy discussed in the Remarks section following to find associated executable modules that the specified module causes to be loaded. If this value is not given, or if lpLibFileName does not specify a path, the function uses the standard search strategy discussed in the Remarks section following to find associated executable modules that the specified module causes to be loaded. The behavior of the function is then identical to that of LoadLibrary in this regard.
Return Value

If the function succeeds, the return value is a handle to the mapped executable module.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

Note that the DONT_RESOLVE_DLL_REFERENCES flag is only implemented on the Windows NT platform. It is not implemented on the Windows 95 platform.

The calling process can use the handle returned by this function to identify the module in calls to the GetProcAddress, FindResource, and LoadResource functions.

The LoadLibraryEx function is very similar to the LoadLibrary function. The differences consist of a set of optional behaviors that LoadLibraryEx provides. First, LoadLibraryEx can map a DLL module without calling the DllEntryPoint function of the DLL. Second, LoadLibraryEx can use either of two file search strategies to find executable modules that are associated with the specified module. Third, LoadLibraryEx can load a module in a way that is optimized for the case where the module will never be executed, loading the module as if it were a data file. You select these optional behaviors by setting the dwFlags parameter; if dwFlags is zero, LoadLibraryEx behaves identically to LoadLibrary.

If no path is specified, the LoadLibraryEx function uses the same standard file search strategy that LoadLibrary, SearchPath, and OpenFile use to find the executable module and any associated executable modules that it causes to be loaded. This standard strategy searches for a file in the following sequence:

1.	The directory from which the application loaded.

2.	The current directory.

3.	Windows 95: The Windows system directory. Use the GetSystemDirectory function to get the path of this directory.

Windows NT: The 32-bit Windows system directory. Use the GetSystemDirectory function to get the path of this directory. The name of this directory is SYSTEM32.

4.	Windows NT only: The 16-bit Windows system directory. There is no Win32 function that obtains the path of this directory, but it is searched. The name of this directory is SYSTEM.

5.	The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.

6.	The directories that are listed in the PATH environment variable.

If a path is specified, and the dwFlags parameter is set to LOAD_WITH_ALTERED_SEARCH_PATH, the LoadLibraryEx function uses an alternate file search strategy to find any executable modules that the specified module causes to be loaded. This alternate strategy searches for a file in the following sequence:

1.	The directory specified by the lpLibFileName path. In other words, the directory that the specified executable module is in.

2.	The current directory.

3.	Windows 95: The Windows system directory. Use the GetSystemDirectory function to get the path of this directory.

Windows NT: The 32-bit Windows system directory. Use the GetSystemDirectory function to get the path of this directory. The name of this directory is SYSTEM32.

4.	Windows NT only: The 16-bit Windows system directory. There is no Win32 function that obtains the path of this directory, but it is searched. The name of this directory is SYSTEM.

5.	The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.

6.	The directories that are listed in the PATH environment variable.

Note that the standard file search strategy and the alternate search strategy differ in just one way: the standard strategy starts its search in the calling application's directory, and the alternate strategy starts its search in the directory of the executable module that LoadLibraryEx is loading.

If you specify the alternate search strategy, its behavior continues until all associated executable modules have been located. Once the system starts processing DLL initialization routines, the system reverts to the standard search strategy.

See Also

DllEntryPoint, FindResource, FreeLibrary, GetProcAddress, GetSystemDirectory, GetWindowsDirectory, LoadLibrary, LoadResource, OpenFile, SearchPath


LoadMenu
LoadMenu  QuickInfo  Overview  Group

The LoadMenu function loads the specified menu resource from the executable (.EXE) file associated with an application instance.

HMENU LoadMenu(

HINSTANCE  hInstance,	// handle of application instance
LPCTSTR  lpMenuName	// menu name string or menu-resource identifier
);
Parameters

hInstance

Identifies the instance of the module containing the menu resource to be loaded.

lpMenuName

Points to a null-terminated string that contains the name of the menu resource. Alternatively, this parameter can consist of the resource identifier in the low-order word and zero in the high-order word. To create this value, use the MAKEINTRESOURCE macro.

Return Value

If the function succeeds, the return value is the handle of the menu resource.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

The DestroyMenu function is used, before an application closes, to destroy the menu and free memory that the loaded menu occupied.

See Also

LoadMenuIndirect, MAKEINTRESOURCE


LoadMenuIndirect
LoadMenuIndirect  QuickInfo  Overview  Group

The LoadMenuIndirect function loads the specified menu template in memory.

HMENU LoadMenuIndirect(

CONST MENUTEMPLATE  *lpMenuTemplate	// address of menu template
);
Parameters

lpMenuTemplate

Windows NT: Points to a menu template.

Windows 95: Points to a menu template or an extended menu template.

A menu template consists of a MENUITEMTEMPLATEHEADER structure followed by one or more contiguous MENUITEMTEMPLATE structures. In Windows 95, an extended menu template consists of a MENUEX_TEMPLATE_HEADER structure followed by one or more contiguous MENUEX_TEMPLATE_ITEM structures.

Return Value

If the function succeeds, the return value is the handle of the menu.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

For both the ANSI and the Unicode version of this function, the strings in the MENUITEMTEMPLATE structure must be Unicode strings.

See Also

LoadMenu, MENUITEMTEMPLATE, MENUITEMTEMPLATEHEADER


LoadModule
LoadModule  QuickInfo  Overview  Group

The LoadModule function loads and executes a Windows-based application or creates a new instance of an existing Windows-based application.

This function is provided for compatibility with earlier versions of Windows. For Win32-based applications, use the CreateProcess function.

DWORD LoadModule(

LPCSTR  lpModuleName,	// address of filename to load
LPVOID  lpParameterBlock	// address of parameter block for new module
);
Parameters

lpModuleName

Points to a null-terminated string that contains the filename of the application to run. If the lpModuleName parameter does not contain a directory path, Windows searches for the executable file in this order:

1.	The directory from which the application loaded.

2.	The current directory.

3.	Windows 95: The Windows system directory. Use the GetSystemDirectory function to get the path of this directory.

Windows NT: The 32-bit Windows system directory. Use the GetSystemDirectory function to get the path of this directory. The name of this directory is SYSTEM32.

4.	Windows NT only: The 16-bit Windows system directory. There is no Win32 function that obtains the path of this directory, but it is searched. The name of this directory is SYSTEM.

5.	The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.

6.	The directories that are listed in the PATH environment variable.

lpParameterBlock

Points to an application-defined LOADPARMS32 structure that defines the new application's parameter block.

Set all unused members to NULL, except for lpCmdLine, which must point to a null-terminated string if it is not used.

Return Value

If the function succeeds, the return value is greater than 31.

If the function fails, the return value is an error value, which may be one of the following:

Value	Meaning
0	The system is out of memory or resources.
ERROR_BAD_FORMAT	The .EXE file is invalid (non-Win32 .EXE or error in .EXE image).
ERROR_FILE_NOT_FOUND	The specified file was not found.
ERROR_PATH_NOT_FOUND	The specified path was not found.
Remarks

Win32-based applications should use the CreateProcess function. In the Win32 API, the implementation of the LoadModule function calls CreateProcess. The following section describes how each parameter for CreateProcess is formed:

CreateProcess parameter	Value
lpszImageName	LoadModule lpModuleName parameter.
lpszCommandLine	LoadModule lpParameterBlock->lpCmdLine.
lpsaProcess	NULL.
lpsaThread	NULL.
fInheritHandles	FALSE.
fdwCreate	0.
lpvEnvironment	LoadModule lpParameterBlock->lpEnvAddress.
lpszCurDir	NULL.
lpsiStartInfo	The structure is initialized to zero. The cb member is set to the size of the structure, and the wShowWindow member is set to the value of the second word of the LoadModule lpParameterBlock->lpCmdShow parameter.
lppiProcInfo.hProcess	The handle is immediately closed.
lppiProcInfo.hThread	The handle is immediately closed.
See Also

CreateProcess, GetSystemDirectory, GetWindowsDirectory, ShowWindow, STARTUPINFO, WinExec


LoadResource
LoadResource  QuickInfo  Overview  Group

The LoadResource function loads the specified resource into global memory.

HGLOBAL LoadResource(

HMODULE  hModule,	// resource-module handle
HRSRC  hResInfo	// resource handle
);
Parameters

hModule

Identifies the module whose executable file contains the resource. If hModule is NULL, Windows loads the resource from the module that was used to create the current process.

hResInfo

Identifies the resource to be loaded. This handle must be created by using the FindResource or FindResourceEx function.

Return Value

If the function succeeds, the return value is a handle to the global memory block containing the data associated with the resource.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

Windows 95: The system does not automatically free resources loaded using the LoadResource function. Applications must use the FreeResource function function to explicitly discard a resource that is no longer needed.

Windows NT: The system automatically frees resources. Calling the FreeRource function is not necessary to free a resource loaded by using the LoadResource function.

See Also

FindResource, FindResourceEx, LoadLibrary, LoadModule, LockResource


LoadString
LoadString  QuickInfo  Overview  Group

The LoadString function loads a string resource from the executable file associated with a specified module, copies the string into a buffer, and appends a terminating null character.

int LoadString(

HINSTANCE  hInstance,	// handle of module containing string resource
UINT  uID,	// resource identifier
LPTSTR  lpBuffer,	// address of buffer for resource
int  nBufferMax	// size of buffer
);
Parameters

hInstance

Identifies an instance of the module whose executable file contains the string resource.

uID

Specifies the integer identifier of the string to be loaded.

lpBuffer

Points to the buffer to receive the string.

nBufferMax

Specifies the size of the buffer in bytes (ANSI version) or characters (Unicode version). The string is truncated and null terminated if it is longer than the number of characters specified.

Return Value

If the function succeeds, the return value is the number of bytes (ANSI version) or characters (Unicode version) copied into the buffer, not including the null-terminating character, or zero if the string resource does not exist. To get extended error information, call GetLastError.

See Also

FormatMessage, LoadAccelerators, LoadBitmap, LoadCursor, LoadIcon, LoadMenu, LoadMenuIndirect


LocalAlloc
LocalAlloc  QuickInfo  Overview  Group

The LocalAlloc function allocates the specified number of bytes from the heap. In the linear Win32 API environment, there is no difference between the local heap and the global heap.

HLOCAL LocalAlloc(

UINT  uFlags,	// allocation attributes
UINT  uBytes	// number of bytes to allocate
);
Parameters

uFlags

Specifies how to allocate memory. If zero is specified, the default is the LMEM_FIXED flag. Except for the incompatible combinations that are specifically noted, any combination of the following flags can be specified. To indicate whether the function allocates fixed or movable memory, specify one of the first six flags:

Flag	Meaning
LMEM_FIXED
	Allocates fixed memory. This flag cannot be combined with the LMEM_MOVEABLE or LMEM_DISCARDABLE flag. The return value is a pointer to the memory block. To access the memory, the calling process simply casts the return value to a pointer.
LMEM_MOVEABLE
	Allocates movable memory. This flag cannot be combined with the LMEM_FIXED flag. The return value is the handle of the memory object. The handle is a 32-bit quantity that is private to the calling process. To translate the handle into a pointer, use the LocalLock function.
LPTR
	Combines the LMEM_FIXED and LMEM_ZEROINIT flags.
LHND
	Combines the LMEM_MOVEABLE and LMEM_ZEROINIT flags.
NONZEROLHND
	Same as the LMEM_MOVEABLE flag.
NONZEROLPTR
	Same as the LMEM_FIXED flag.
LMEM_DISCARDABLE
	Allocates discardable memory. This flag cannot be combined with the LMEM_FIXED flag. Some Win32-based applications may ignore this flag.
LMEM_NOCOMPACT
	Does not compact or discard memory to satisfy the allocation request.
LMEM_NODISCARD
	Does not discard memory to satisfy the allocation request.
LMEM_ZEROINIT
	Initializes memory contents to zero.
uBytes

Specifies the number of bytes to allocate. If this parameter is zero and the uFlags parameter specifies the LMEM_MOVEABLE flag, the function returns a handle to a memory object that is marked as discarded.

Return Value

If the function succeeds, the return value is the handle of the newly allocated memory object.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

If the heap does not contain sufficient free space to satisfy the request, LocalAlloc returns NULL.

The GlobalAlloc and LocalAlloc functions are limited to a combined total of 65,536 handles for GMEM_MOVEABLE and LMEM_MOVEABLE memory per process. This limitation does not apply to GMEM_FIXED or LMEM_FIXED memory.

If this function succeeds, it allocates at least the amount requested. If the amount allocated is greater than the amount requested, the process can use the entire amount. To determine the actual number of bytes allocated, use the LocalSize function.

See Also

GlobalAlloc, LocalFree, LocalLock, LocalReAlloc, LocalSize


LocalCompact
LocalCompact  QuickInfo  Overview  Group

The LocalCompact function is not implemented in the Win32 API.


LocalDiscard
LocalDiscard  QuickInfo  Overview  Group

The LocalDiscard function discards the specified local memory object. The lock count of the memory object must be zero.

HLOCAL LocalDiscard(

HLOCAL  hlocMem	// handle of local memory object
);
Parameters

hlocMem

Identifies the local memory object. This handle is returned by either the LocalAlloc or LocalReAlloc function.

Return Value

If the function succeeds, the return value is the handle of the local memory object.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

LocalDiscard discards only local objects allocated by a process with the LMEM_DISCARDABLE flag. If a process attempts to discard a fixed or locked object, the function fails.

Although LocalDiscard discards the object's memory block, the handle of the object remains valid. A process can subsequently pass the handle to the LocalReAlloc function to allocate another local memory object identified by the same handle.

See Also

LocalAlloc, LocalReAlloc


LocalFileTimeToFileTime
LocalFileTimeToFileTime  QuickInfo  Overview  Group

The LocalFileTimeToFileTime function converts a local file time to a file time based on the Coordinated Universal Time (UTC).

BOOL LocalFileTimeToFileTime(

CONST FILETIME *  lpLocalFileTime,	// address of local file time to convert
LPFILETIME  lpFileTime	// address of converted file time
);
Parameters

lpLocalFileTime

Points to a FILETIME structure that specifies the local file time to be converted into a UTC-based file time.

lpFileTime

Points to a FILETIME structure to receive the converted UTC-based file time. This parameter cannot be the same as the lpLocalFileTime parameter.

Return Value

If the function succeeds, the return value is TRUE; otherwise, it is FALSE. To get extended error information, use the GetLastError function.

See Also

FILETIME, FileTimeToLocalFileTime


LocalFlags
LocalFlags  QuickInfo  Overview  Group

The LocalFlags function returns information about the specified local memory object.

UINT LocalFlags(

HLOCAL  hMem	// handle of local memory object
);
Parameters

hMem

Identifies the local memory object. This handle is returned by either the LocalAlloc or LocalReAlloc function.

Return Value

If the function succeeds, the return value is a 32-bit value that specifies the allocation flags and the lock count for the memory object.

If the function fails, the return value is the LMEM_INVALID_HANDLE flag, indicating that the local handle is not valid. To get extended error information, call GetLastError.

Remarks

The low-order byte of the low-order word of the return value contains the lock count of the object. To retrieve the lock count from the return value, use the LMEM_LOCKCOUNT mask with the bitwise AND (&) operator. The lock count of memory objects allocated with the LMEM_FIXED flag is always zero.

The high-order byte of the low-order word of the return value indicates the allocation flags of the memory object. It can be zero or any combination of the following flags:

Value	Description
LMEM_DISCARDABLE	The object's memory block can be discarded.
LMEM_DISCARDED	The object's memory block has been discarded.
See Also

GlobalFlags, LocalAlloc, LocalDiscard, LocalLock, LocalReAlloc, LocalUnlock


LocalFree
LocalFree  QuickInfo  Overview  Group

The LocalFree function frees the specified local memory object and invalidates its handle.

HLOCAL LocalFree(

HLOCAL  hMem	// handle of local memory object
);
Parameters

hMem

Identifies the local memory object. This handle is returned by either the LocalAlloc or LocalReAlloc function.

Return Value

If the function succeeds, the return value is NULL.

If the function fails, the return value is equal to the handle of the local memory object. To get extended error information, call GetLastError.

Remarks

If the process tries to examine or modify the memory after it has been freed, heap corruption may occur or an access violation exception (EXCEPTION_ACCESS_VIOLATION) may be generated.

If the hMem parameter is NULL, LocalFree ignores the parameter and returns NULL.

LocalFree succeeds even if the memory object is locked by a previous call to the LocalLock function. The LocalLock function locks a local memory object and increments the lock count by one. The LocalUnlock function unlocks it and decrements the lock count by one. To get the lock count of a local memory object, use the LocalFlags function. LocalFree will free a locked memory object. A locked memory object has a lock count greater than zero.

Both GlobalFree and LocalFree will free a locked memory object. However, if you run an application under a debug version of Windows NT or Windows 95, both GlobalFree and LocalFree will issue a message that tells you that this is happening. If you are debugging the application, GlobalFree and LocalFree will enter a hard-coded breakpoint just before freeing a locked object. This lets you double-check the intended behavior.

See Also

GlobalFree, LocalAlloc, LocalFlags, LocalLock, LocalReAlloc, LocalUnlock


LocalHandle
LocalHandle  QuickInfo  Overview  Group

The LocalHandle function retrieves the handle associated with the specified pointer to a local memory object.

HLOCAL LocalHandle(

LPCVOID  pMem	// address of local memory object
);
Parameters

pMem

Points to the first byte of the local memory object. This pointer is returned by the LocalLock function.

Return Value

If the function succeeds, the return value is the handle of the specified local memory object.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

When the LocalAlloc function allocates a local memory object with the LMEM_MOVEABLE flag, it returns the handle of the object. The LocalLock function converts this handle into a pointer to the object's memory block, and LocalHandle converts the pointer back into a handle.

See Also

LocalAlloc, LocalLock


LocalInit
LocalInit  Overview  Group

The LocalInit function has been deleted.


LocalLock
LocalLock  QuickInfo  Overview  Group

The LocalLock function locks a local memory object and returns a pointer to the first byte of the object's memory block. The memory block associated with a locked memory object cannot be moved or discarded. For memory objects allocated with the LMEM_MOVEABLE flag, the function increments the object's lock count.

LPVOID LocalLock(

HLOCAL  hMem	// handle of local memory object
);
Parameters

hMem

Identifies the local memory object. This handle is returned by either the LocalAlloc or LocalReAlloc function.

Return Value

If the function succeeds, the return value is a pointer to the first byte of the memory block.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

The internal data structures for each memory object include a lock count that is initially zero. For movable memory objects, LocalLock increments the count by one, and the LocalUnlock function decrements the count by one. For each call that a process makes to LocalLock for an object, it must eventually call LocalUnlock. Locked memory will not be moved or discarded unless the memory object is reallocated by using the LocalReAlloc function. The memory block of a locked memory object remains locked in memory until its lock count is decremented to zero, at which time it can be moved or discarded.

Memory objects allocated with the LMEM_FIXED flag always have a lock count of zero. For these objects, the value of the returned pointer is equal to the value of the specified handle.

If the specified memory block has been discarded or if the memory block has a zero-byte size, this function returns NULL.

Discarded objects always have a lock count of zero.

See Also

LocalAlloc, LocalFlags, LocalReAlloc, LocalUnlock


LocalReAlloc
LocalReAlloc  QuickInfo  Overview  Group

The LocalReAlloc function changes the size or the attributes of a specified local memory object. The size can increase or decrease.

HLOCAL LocalReAlloc(

HLOCAL  hMem,	// handle of local memory object
UINT  uBytes,	// new size of block
UINT  uFlags	// how to reallocate object
);
Parameters

hMem

Identifies the local memory object to be reallocated. This handle is returned by either the LocalAlloc or LocalReAlloc function.

uBytes

Specifies the new size, in bytes, of the memory block. If this parameter is zero and the uFlags parameter specifies the LMEM_MOVEABLE flag, the function returns a handle to a memory object that is marked as discarded. If uFlags specifies the LMEM_MODIFY flag, this parameter is ignored.

uFlags

Specifies how to reallocate the local memory object. If the LMEM_MODIFY flag is specified, this parameter modifies the attributes of the memory object, and the uBytes parameter is ignored. Otherwise, this parameter controls the reallocation of the memory object.

The LMEM_MODIFY flag can be combined with either or both of the following flags:

Flag	Meaning
LMEM_DISCARDABLE
	Allocates discardable memory if the LMEM_MODIFY flag is also specified. This flag is ignored, unless the object was previously allocated as movable or the LMEM_MOVEABLE flag is also specified.
LMEM_MOVEABLE
	You cannot combine LMEM_MOVEABLE with LMEM_MODIFY to change a fixed memory object into a movable one. The function returns an error if an application attempts this.
If uFlags does not specify LMEM_MODIFY, this parameter can be any combination of the following flags:

Flag	Meaning
LMEM_MOVEABLE
	If uBytes is zero, discards a previously movable and discardable memory block. If the object's lock count is not zero or the block is not movable and discardable, the function fails.
	If uBytes is nonzero, enables the system to move the reallocated block to a new location without changing the movable or fixed attribute of the memory object. If the object is fixed, the handle returned may be different from the handle specified in the hMem parameter. If the object is movable, the block can be moved without invalidating the handle, even if the object is currently locked by a previous call to the LocalLock function. To get the new address of the memory block, use LocalLock.
LMEM_NOCOMPACT
	Prevents memory from being compacted or discarded to satisfy the allocation request.
LMEM_ZEROINIT
	Causes the additional memory contents to be initialized to zero if the memory object is growing in size.
Return Value

If the function succeeds, the return value is the handle of the reallocated memory object.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

If LocalReAlloc reallocates a movable object, the return value is the handle of the memory object. To convert the handle to a pointer, use the LocalLock function.

If LocalReAlloc reallocates a fixed object, the value of the handle returned is the address of the first byte of the memory block. To access the memory, a process can simply cast the return value to a pointer.

See Also

LocalAlloc, LocalFree, LocalLock


LocalShrink
LocalShrink  QuickInfo  Overview  Group

The LocalShrink function is obsolete. It has no meaning in the 32-bit envronment.


LocalSize
LocalSize  QuickInfo  Overview  Group

The LocalSize function returns the current size, in bytes, of the specified local memory object.

UINT LocalSize(

HLOCAL  hMem	// handle of local memory object
);
Parameters

hMem

Identifies the local memory object. This handle is returned by the LocalAlloc, LocalReAlloc, or LocalHandle function.

Return Value

If the function succeeds, the return value is the size, in bytes, of the specified local memory object. If the specified handle is not valid or if the object has been discarded, the return value is zero. To get extended error information, call GetLastError.

Remarks

The size of a memory block may be larger than the size requested when the memory was allocated.

To verify that the specified object's memory block has not been discarded, call the LocalFlags function before calling LocalSize.

See Also

LocalAlloc, LocalFlags, LocalHandle, LocalReAlloc


LocalUnlock
LocalUnlock  QuickInfo  Overview  Group

The LocalUnlock function decrements the lock count associated with a memory object that was allocated with the LMEM_MOVEABLE flag. This function has no effect on memory objects allocated with the LMEM_FIXED flag.

BOOL LocalUnlock(

HLOCAL  hMem	// handle of local memory object
);
Parameters

hMem

Identifies the local memory object. This handle is returned by either the LocalAlloc or LocalReAlloc function.

Return Value

If the memory object is still locked after decrementing the lock count, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError. If GetLastError returns NO_ERROR, the memory object is unlocked.

Remarks

The internal data structures for each memory object include a lock count that is initially zero. For movable memory objects, the LocalLock function increments the count by one, and LocalUnlock decrements the count by one. For each call that a process makes to LocalLock for an object, it must eventually call LocalUnlock. Locked memory will not be moved or discarded unless the memory object is reallocated by using the LocalReAlloc function. The memory block of a locked memory object remains locked until its lock count is decremented to zero, at which time it can be moved or discarded.

If the memory object is already unlocked, LocalUnlock returns FALSE and GetLastError reports ERROR_NOT_LOCKED. Memory objects allocated with the LMEM_FIXED flag always have a lock count of zero and cause the ERROR_NOT_LOCKED error.

A process should not rely on the return value to determine the number of times it must subsequently call LocalUnlock for the memory block.

See Also

LocalAlloc, LocalFlags, LocalLock, LocalReAlloc


LockFile
LockFile  QuickInfo  Overview  Group

The LockFile function locks a region in an open file. Locking a region prevents other processes from accessing the region.

BOOL LockFile(

HANDLE  hFile,	// handle of file to lock
DWORD  dwFileOffsetLow,	// low-order word of lock region offset
DWORD  dwFileOffsetHigh,	// high-order word of lock region offset
DWORD  nNumberOfBytesToLockLow,	// low-order word of length to lock
DWORD  nNumberOfBytesToLockHigh	// high-order word of length to lock
);
Parameters

hFile

Identifies the file with a region to be locked. The file handle must have been created with GENERIC_READ or GENERIC_WRITE access to the file (or both).

dwFileOffsetLow

Specifies the low-order word of the starting byte offset in the file where the lock should begin.

dwFileOffsetHigh

Specifies the high-order word of the starting byte offset in the file where the lock should begin.

nNumberOfBytesToLockLow

Specifies the low-order word of the length of the byte range to be locked.

nNumberOfBytesToLockHigh

Specifies the high-order word of the length of the byte range to be locked.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Locking a region of a file gives the locking process exclusive access to the specified region. File locks are not inherited by processes created by the locking process.

Locking a region of a file denies all other processes both read and write access to the specified region. Locking a region that goes beyond the current end-of-file position is not an error.

Locks may not overlap an existing locked region of the file.

The UnlockFile function unlocks a file region locked by LockFile.

See Also

CreateFile, UnlockFile


LockFileEx
LockFileEx  QuickInfo  Overview  Group

The LockFileEx function locks a byte range within an open file for shared or exclusive access.

BOOL LockFileEx(

HANDLE  hFile,	// handle of file to lock
DWORD  dwFlags,	// functional behavior modification flags
DWORD  dwReserved,	// reserved, must be set to zero
DWORD  nNumberOfBytesToLockLow,	// low-order 32 bits of length to lock
DWORD  nNumberOfBytesToLockHigh,	// high-order 32 bits of length to lock
LPOVERLAPPED  lpOverlapped	// addr. of structure with lock region start offset
);
Parameters

hFile

Identifies an open handle to a file that is to have a range of bytes locked for shared or exclusive access. The handle must have been created with either GENERIC_READ or GENERIC_WRITE access to the file.

dwFlags

Specifies flags that modify the behavior of this function. This parameter may be one or more of the following values:

Value	Meaning
LOCKFILE_FAIL_IMMEDIATELY	If this value is specified, the function returns immediately if it is unable to acquire the requested lock. Otherwise, it waits.
LOCKFILE_EXCLUSIVE_LOCK	If this value is specified, the function requests an exclusive lock. Otherwise, it requests a shared lock.
dwReserved

Reserved parameter; must be set to zero.

nNumberOfBytesToLockLow

Specifies the low-order 32 bits of the length of the byte range to lock.

nNumberOfBytesToLockHigh

Specifies the high-order 32 bits of the length of the byte range to lock.

lpOverlapped

Points to an OVERLAPPED structure that the function uses with the locking request. This structure, which is required, contains the file offset of the beginning of the lock range.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE or NULL. To get extended error information, call GetLastError.

Remarks

Locking a region of a file is used to acquire shared or exclusive access to the specified region of the file. File locks are not inherited by a new process during process creation.

Locking a portion of a file for exclusive access denies all other processes both read and write access to the specified region of the file. Locking a region that goes beyond the current end-of-file position is not an error.

Locking a portion of a file for shared access denies all other processes write access to the specified region of the file, but allows other processes to read the locked region.

If an exclusive lock is requested for a file that is already locked either shared or exclusively by other threads, this call waits until the lock is granted, unless the LOCKFILE_FAIL_IMMEDIATELY flag is specified.

Locks may not overlap an existing locked region of the file.

See Also

CreateFile, LockFile, OVERLAPPED, UnlockFile, UnlockFileEx


LockResource
LockResource  QuickInfo  Overview  Group

The LockResource function locks the specified resource in memory.

LPVOID LockResource(

HGLOBAL  hResData	// handle to resource to lock
);
Parameters

hResData

Identifies the resource to be locked. The LoadResource function returns this handle.

Return Value

If the loaded resource is locked, the return value is a pointer to the first byte of the resource; otherwise, it is NULL.

Remarks

It is not necessary for Win32-based applications to unlock resources that were locked by the LockResource function.

Trying to lock a resource by using the handle returned by the FindResource or FindResourceEx function will not work. You will get back a value that is incorrect and points to random data.

See Also

FindResource, FindResourceEx, LoadResource


LockSegment
LockSegment  QuickInfo  Overview  Group

The LockSegment function is obsolete. It has no meaning in the 32-bit envronment.


LockServiceDatabase
LockServiceDatabase  QuickInfo  Overview  Group

The LockServiceDatabase function locks a specified database.

SC_LOCK LockServiceDatabase(

SC_HANDLE  hSCManager	// handle of service control manager database
);
Parameters

hSCManager

Identifies the service control manager database. The OpenSCManager function returns this handle, which must have SC_MANAGER_LOCK access.

Return Value

If the function succeeds, the return value is a lock to the specified service control manager database.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Errors

The following error code may be set by the service control manager. Other error codes may be set by registry functions that are called by the service control manager.

Value	Meaning
ERROR_ACCESS_DENIED	The specified handle was not opened with SC_MANAGER_LOCK access.
ERROR_INVALID_HANDLE	The specified handle is invalid.
ERROR_SERVICE_DATABASE_LOCKED	The database is locked.
Remarks

The LockServiceDatabase function tries to acquire a lock on the specified database. Only one process at a time can have a lock on a database.

A lock is a protocol used by setup and configuration programs and the service control manager to serialize access to the service tree in the registry. The only time the service control manager acquires a lock is when it is starting a service. Setup and configuration programs are expected to acquire a lock before using the ChangeServiceConfig or SetServiceObjectSecurity function to reconfigure a service. They should also acquire a lock before using the registry functions to reconfigure a service. The lock prevents the service control manager from starting a service while it is being reconfigured.

A call to the StartService function to start a service in a locked database fails. All other service control manager functions are not affected by a lock.

The lock is held until the SC_LOCK handle is specified in a subsequent call to the UnlockServiceDatabase function. If a process that is holding a lock terminates, the service control manager automatically cleans up and releases the lock.

See Also

ChangeServiceConfig, OpenSCManager, QueryServiceLockStatus, SetServiceObjectSecurity, StartService, UnlockServiceDatabase


LockWindowUpdate
LockWindowUpdate  QuickInfo  Overview  Group

The LockWindowUpdate function disables or reenables drawing in the specified window. Only one window can be locked at a time.

BOOL LockWindowUpdate(

HWND  hWndLock	// handle of window to lock
);
Parameters

hWndLock

Specifies the window in which drawing will be disabled. If this parameter is NULL, drawing in the locked window is enabled.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE, indicating that an error occurred or another window was already locked.

Remarks

If an application with a locked window (or any locked child windows) calls the GetDC, GetDCEx, or BeginPaint function, the called function returns a device context with a visible region that is empty. This will occur until the application unlocks the window by calling LockWindowUpdate, specifying a value of NULL for hWndLock.

If an application attempts to draw within a locked window, the system records the extent of the attempted operation in a bounding rectangle. When the window is unlocked, the system invalidates the area within this bounding rectangle, forcing an eventual WM_PAINT message to be sent to the previously locked window and its child windows. If no drawing has occurred while the window updates were locked, no area is invalidated.

LockWindowUpdate does not make the given window invisible and does not clear the WS_VISIBLE style bit.

A locked window cannot be moved.

See Also

BeginPaint, GetDC, GetDCEx, WM_PAINT


LogonUser [New - Windows NT]
LogonUser  QuickInfo

[New - Windows NT]

The LogonUser function attempts to perform a user logon operation. You specify the user with a user name and domain, and authenticate the user with a clear-text password. If the function succeeds, you receive a handle to a token that represents the logged-on user. You can then use this token handle to impersonate the specified user, or to create a process running in the context of the specified user.

BOOL LogonUser(

LPTSTR lpszUsername,	// string that specifies the user name
LPTSTR lpszDomain,	// string that specifies the domain or servero
LPTSTR lpszPassword,	// string that specifies the password
DWORD dwLogonType,	// specifies the type of logon operation
DWORD dwLogonProvider,	// specifies the logon provider
PHANDLE phToken	// pointer to variable to receive token handle
);
Parameters

lpszUsername

Pointer to a zero-terminated string that specifies the user name. This is the name of the user account to log on to.

lpszDomain

Pointer to a zero-terminated string that specifies the domain or server to log on to.

lpszPasswordc

Pointer to a zero-terminated string that specifies the clear-text password for the user account specified by lpszUsername.

dwLogonType

Specifies the type of logon operation to perform. The following logon types are defined:

Value	Meaning
LOGON32_LOGON_BATCH	Indicates a batch-type logon. For example, this can be a logon without a user present on either the console or at the other end of a network connection.
LOGON32_LOGON_INTERACTIVE	Indicates a logon in which the user has an active connection of some type, either through a console or through a network connection, such as a telnet-style connection.
LOGON32_LOGON_SERVICE	Indicates a service-type logon. The account provided must have the service privilege enabled.
dwLogonProvider

Specifies the logon provider. The following logon providers are defined:

Value	Meaning
LOGON32_PROVIDER_DEFAULT	Use the standard logon provider. This is the recommended value for dwLogonProvider. It gives an application the maximum upward compatibility with future releases of Windows NT.
phToken

Pointer to a HANDLE variable that receives a handle to a token that represents the specified user.

You can use this token handle in calls to the ImpersonateLoggedOnUser and CreateProcessAsUser functions.

When you no longer need this handle, close it by calling the CloseHandle function.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError .

Remarks

The process that calls LogonUser must have the SeTcbPrivilege privilege. The privilege does not need to be enabled. The LogonUser function enables the privilege as necessary. The function fails if the calling process does not have the SeTcbPrivilege privilege, and GetLastError returns the error code ERROR_PRIVILEGE_NOT_HELD.

A user is considered logged on as long as at least one token exists. If you call CreateProcessAsUser and then close the token, the system considers the user as still logged on until the process (and all child processes) have ended.

See Also

CreateProcessAsUser, ImpersonateLoggedOnUser


LookupAccountName
LookupAccountName  QuickInfo  Overview  Group

The LookupAccountName function accepts the name of a system and an account as input. It retrieves a security identifier (SID) for the account and the name of the domain on which the account was found.

BOOL LookupAccountName(

LPCTSTR  lpSystemName,	// address of string for system name
LPCTSTR  lpAccountName,	// address of string for account name
PSID  Sid,	// address of security identifier
LPDWORD  cbSid,	// address of size of security identifier
LPTSTR  ReferencedDomainName,	// address of string for referenced domain
LPDWORD  cbReferencedDomainName,	// address of size of domain string
PSID_NAME_USE  peUse	// address of SID-type indicator
);
Parameters

lpSystemName

Points to a null-terminated string specifying the system. This string can be the name of a remote computer. If this string is NULL, the account name is looked up on the local system.

lpAccountName

Points to a null-terminated string specifying the account name.

Sid

Points to a buffer receiving the SID structure that corresponds to the account name pointed to by the lpAccountName parameter.

cbSid

Specifies the size of the buffer pointed to by the Sid parameter. If the specified size is too small, the function sets this variable to the required buffer size.

ReferencedDomainName

Points to a buffer receiving the name of the domain where the account name is found.

cbReferencedDomainName

Specifies the size of the ReferencedDomainName buffer in characters. If the specified size is too small, the function sets this variable to the required buffer size.

peUse

Points to a SID_NAME_USE enumerated type indicating the type of the account when the function returns.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The LookupAccountName function attempts to find a security identifier for the specified name by first checking a list of well-known SIDs. If the name does not correspond to a well-known SID, the function checks built-in and administratively defined local accounts. Next, the function checks the primary domain. If the name is not found there, trusted domains are checked.

See Also

EqualPrefixSid, GetUserName, LookupAccountSid


LookupAccountSid
LookupAccountSid  QuickInfo  Overview  Group

The LookupAccountSid function accepts a security identifier (SID) as input. It retrieves the name of the account for this SID and the name of the first domain on which this SID is found.

BOOL LookupAccountSid(

LPCTSTR  lpSystemName,	// address of string for system name
PSID  Sid,	// address of security identifier
LPTSTR  Name,	// address of string for account name
LPDWORD  cbName,	// address of size account string
LPTSTR  ReferencedDomainName,	// address of string for referenced domain
LPDWORD  cbReferencedDomainName,	// address of size domain string
PSID_NAME_USE  peUse	// address of structure for SID type
);
Parameters

lpSystemName

Points to a null-terminated string specifying the system. This string can be the name of a remote computer. If this string is NULL, the SID is looked up on the local system.

Sid

Points to a SID structure for which the account name is looked up.

Name

Points to a buffer receiving a null-terminated string representing the account name corresponding to the Sid parameter.

cbName

Specifies the size of the buffer pointed to by the Name parameter. If the specified size is too small, the function sets this variable to the required buffer size.

ReferencedDomainName

Points to a buffer that will receive a null-terminated string giving the name of the domain where the account name was found.

For Windows NT systems, the domain name returned for most accounts in the local computer's security database is the computer's name as of the last start of the system. Backslashes are excluded. If the computer's name changes, the old name continues to be returned as the domain name until the system is restarted.

For Windows NT Server systems, the domain name returned for most accounts in the local computer's security database is the name of the domain for which the Windows NT Server is a domain controller.

Some accounts are predefined by the system. The domain name returned for these accounts is BUILTIN.

cbReferencedDomainName

Specifies the size of the buffer pointed to by the ReferencedDomainName parameter. If the specified size is too small, the function sets this variable to the required buffer size.

peUse

Points to an SID_NAME_USE enumerated type indicating the type of the account when the function returns.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The LookupAccountSid function attempts to find a name for the specified security identifier by first checking a list of well-known SIDs. If the supplied SID does not correspond to a well-known SID, the function checks built-in and administratively defined local accounts. Next, the function checks the primary domain. Security identifiers not recognized by the primary domain are checked against the trusted domains corresponding to their SID prefixes.

See Also

EqualPrefixSid, LookupAccountName


LookupIconIdFromDirectory
LookupIconIdFromDirectory  QuickInfo  Overview  Group

The LookupIconIdFromDirectory function searches through icon or cursor data for the icon or cursor that best fits the current display device.

int LookupIconIdFromDirectory(

PBYTE  presbits,	// address of resource data
BOOL  fIcon	// look for icon or cursor
);
Parameters

presbits

Points to the icon or cursor directory data. Because this function does not validate the resource data, it causes a general protection (GP) fault or returns an undefined value if presbits is not pointing to valid resource data.

fIcon

Specifies whether an icon or a cursor is sought. If this parameter is TRUE, the function is searching for an icon; if the parameter is FALSE, the function is searching for a cursor.

Return Value

If the function succeeds, the return value is an integer resource identifier for the icon or cursor that best fits the current display device.

Remarks

A resource file of type RT_GROUP_ICON (RT_GROUP_CURSOR indicates cursors) contains icon (or cursor) data in several device-dependent and device-independent formats. LookupIconIdFromDirectory searches the resource file for the icon (or cursor) that best fits the current display device and returns its integer identifier. The FindResource and FindResourceEx functions use the MAKEINTRESOURCE macro with this identifier to locate the resource in the module.

The icon directory is loaded from a resource file with resource type RT_GROUP_ICON (or RT_GROUP_CURSOR for cursors), and an integer resource name for the specific icon to be loaded. LookupIconIdFromDirectory returns an integer identifier that is the resource name of the icon that best fits the current display device.

The LoadIcon, LoadCursor, and LoadImage (in Windows 95) functions use this function to search the specified resource data for the icon or cursor that best fits the current display device.

See Also

CreateIconFromResource, CreateIconIndirect, FindResource, FindResourceEx, GetIconInfo, LoadCursor, LoadIcon, LoadImage, LookupIconIdFromDirectoryEx, MAKEINTRESOURCE


LookupIconIdFromDirectoryEx [New - Windows 95]
LookupIconIdFromDirectoryEx  QuickInfo

[New - Windows 95]

The LookupIconIdFromDirectoryEx function searches through icon or cursor data for the icon or cursor that best fits the current display device.

int LookupIconIdFromDirectoryEx(

PBYTE  presbits,	// address of resource data
BOOL  fIcon,	// icon or cursor flag
int  cxDesired,	// desired width of icon or cursor
int  cyDesired,	// desired height of icon or cursor
UINT  Flags	// resource flags
);
Parameters

presbits

Points to the icon or cursor directory data. Because this function does not validate the resource data, it causes a general protection (GP) fault or returns an undefined value if presbits is not pointing to valid resource data.

fIcon

Specifies whether an icon or a cursor is sought. If this parameter is TRUE, the function is searching for an icon; if the parameter is FALSE, the function is searching for a cursor.

cxDesired

Specifies the desired width, in pixels, of the icon. If this parameter is zero and Flags does not include LR_LOADREALSIZE, the function uses the SM_CXICON or SM_CXCURSOR system metric value.

cyDesired

Specifies the desired height, in pixels, of the icon. If this parameter is zero and Flags does not include LR_LOADREALSIZE, the function uses the SM_CYICON or SM_CYCURSOR system metric value.

Flags

Specifies a combination of the following values:

Value	Meaning
LR_DEFAULTCOLOR	Uses the default color format.
LR_LOADREALSIZE	Sets the width and height as specified by the biWidth and biHeight members of the BITMAPINFOHEADER structure that defines the icon or cursor. The cxDesired and cyDesired parameters are ignored.
LR_MONOCHROME	Creates a monochrome icon or cursor.
Return Value

If the function succeeds, the return value is an integer resource identifier for the icon or cursor that best fits the current display device.

Remarks

A resource file of type RT_GROUP_ICON (RT_GROUP_CURSOR indicates cursors) contains icon (or cursor) data in several device-dependent and device-independent formats. LookupIconIdFromDirectoryEx searches the resource file for the icon (or cursor) that best fits the current display device and returns its integer identifier. The FindResource and FindResourceEx functions use the MAKEINTRESOURCE macro with this identifier to locate the resource in the module.

The icon directory is loaded from a resource file with resource type RT_GROUP_ICON (or RT_GROUP_CURSOR for cursors), and an integer resource name for the specific icon to be loaded. LookupIconIdFromDirectoryEx returns an integer identifier that is the resource name of the icon that best fits the current display device.

The LoadIcon, LoadImage, and LoadCursor functions use this function to search the specified resource data for the icon or cursor that best fits the current display device.

See Also

CreateIconFromResourceEx, CreateIconIndirect, FindResource, FindResourceEx, GetIconInfo, LoadCursor, LoadIcon, LoadImage, LookupIconIdFromDirectory, MAKEINTRESOURCE


LookupPrivilegeDisplayName
LookupPrivilegeDisplayName  QuickInfo  Overview  Group

The LookupPrivilegeDisplayName function retrieves a displayable name representing a specified privilege.

BOOL LookupPrivilegeDisplayName(

LPCTSTR  lpSystemName,	// address of string specifying the system
LPCTSTR  lpName,	// address of string specifying the privilege
LPTSTR  lpDisplayName,	// address of string receiving the displayable name
LPDWORD  cbDisplayName,	// address of size of string for displayable name
LPDWORD  lpLanguageId	// address of language identifier
);
Parameters

lpSystemName

Points to a null-terminated string specifying the name of the system on which the displayable privilege name is looked up. If a null string is specified, the function attempts to find the displayable name on the local system.

lpName

Points to a null-terminated string specifying the name of the privilege, as defined in the WINNT.H header file. For example, this string could be SE_REMOTE_SHUTDOWN_NAME.

lpDisplayName

Points to a buffer receiving a null-terminated string giving the privilege's displayable name. For example, if the lpName parameter is SE_REMOTE_SHUTDOWN_NAME, the displayable name is, "Force shutdown from a remote system".

cbDisplayName

Points to a variable specifying the size, in characters, of the lpDisplayName buffer. When the function returns, this parameter contains the length of the displayable privilege name, not including the terminating null character. If the buffer pointed to by the lpDisplayName parameter is too small, this variable contains the required size when the function returns.

lpLanguageId

Points to a variable receiving the language identifier for the returned displayable name.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

For this release of Windows NT, only the privileges specified in the Defined Privileges section of WINNT.H are supported by this function.

See Also

LookupPrivilegeName, LookupPrivilegeValue


LookupPrivilegeName
LookupPrivilegeName  QuickInfo  Overview  Group

The LookupPrivilegeName function retrieves the name corresponding to the privilege represented on a specific system by a specified locally unique identifier (LUID).

BOOL LookupPrivilegeName(

LPCTSTR  lpSystemName,	// address of string specifying the system
PLUID  lpLuid,	// address of locally unique identifier
LPTSTR  lpName,	// address of string specifying the privilege
LPDWORD  cbName	// address of size of string for displayable name
);
Parameters

lpSystemName

Points to a null-terminated string specifying the name of the system on which the privilege name is looked up. If a null string is specified, the function attempts to find the privilege name on the local system.

lpLuid

Points to the locally unique identifier by which the privilege is known on the target system.

lpName

Points to a buffer receiving a null-terminated string that represents the privilege's name. For example, this string could be SE_SECURITY_NAME.

cbName

Points to a variable specifying the size, in characters, of the lpName buffer. When the function returns, this parameter contains the length of the privilege name, not including the terminating null character. If the buffer pointed to by the lpName parameter is too small, this variable contains the required size when the function returns.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

For this release of Windows NT, only the privileges specified in the Defined Privileges section of WINNT.H are supported by this function.

See Also

LookupPrivilegeDisplayName, LookupPrivilegeValue


LookupPrivilegeValue
LookupPrivilegeValue  QuickInfo  Overview  Group

The LookupPrivilegeValue function retrieves the locally unique identifier (LUID) used on a specified system to locally represent the specified privilege name.

BOOL LookupPrivilegeValue(

LPCTSTR  lpSystemName,	// address of string specifying the system
LPCTSTR  lpName,	// address of string specifying the privilege
PLUID  lpLuid	// address of locally unique identifier
);
Parameters

lpSystemName

Points to a null-terminated string specifying the name of the system on which the privilege name is looked up. If a null string is specified, the function attempts to find the privilege name on the local system.

lpName

Points to a null-terminated string specifying the privilege's name. For example, this string could be SE_SECURITY_NAME.

lpLuid

Points to a variable receiving the locally unique identifier by which the privilege is known on the system specified by the lpSystemName parameter.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

For this release of Windows NT, only the privileges specified in the Defined Privileges section of WINNT.H are supported by this function.

See Also

LookupPrivilegeDisplayName, LookupPrivilegeName


LPtoDP
LPtoDP  QuickInfo  Overview  Group

The LPtoDP function converts logical coordinates into device coordinates. The conversion depends on the mapping mode of the device context, the settings of the origins and extents for the window and viewport, and the world transformation.

BOOL LPtoDP(

HDC  hdc,	// handle of device context
LPPOINT  lpPoints,	// array of points
int  nCount	// count of points
);
Parameters

hdc

Identifies the DC.

lpPoints

Points to an array of POINT structures. The x-coordinates and y-coordinates contained in each of the POINT structures will be transformed.

nCount

Specifies the number of points in the array.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

This function fails if the logical coordinates exceed 32 bits, or if the converted device coordinates exceed 27 bits. In the case of such an overflow, the results for all the points are undefined.

See Also

DPtoLP, POINT


lstrcat
lstrcat  QuickInfo  Overview  Group

The lstrcat function appends one string to another.

LPTSTR lstrcat(

LPTSTR  lpString1,	// address of buffer for concatenated strings
LPCTSTR  lpString2	// address of string to add to string1
);
Parameters

lpString1

Points to a null-terminated string. The buffer must be large enough to contain both strings.

lpString2

Points to the null-terminated string to be appended to the string specified in the lpString1 parameter.

Return Value

If the function succeeds, the return value is a pointer to the buffer.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

See Also

lstrcmp, lstrcmpi, lstrcpy, lstrlen


lstrcmp
lstrcmp  QuickInfo  Overview  Group

The lstrcmp function compares two character strings. The comparison is case sensitive.

int lstrcmp(

LPCTSTR  lpString1,	// address of first string
LPCTSTR  lpString2	// address of second string
);
Parameters

lpString1

Points to the first null-terminated string to be compared.

lpString2

Points to the second null-terminated string to be compared.

Return Value

If the function succeeds and the string pointed to by lpString1 is less than the string pointed to by lpString2, the return value is negative; if the string pointed to by lpString1 is greater than the string pointed to by lpString2, it is positive. If the strings are equal, the return value is zero.

Remarks

The lstrcmp function compares two strings by checking the first characters against each other, the second characters against each other, and so on until it finds an inequality or reaches the ends of the strings.

The function returns the difference of the values of the first unequal characters it encounters. For example, lstrcmp determines that "abcz" is greater than "abcdefg" and returns the difference of z and d.

The language (locale) selected by the user at setup time, or via the control panel, determines which string is greater (or whether the strings are the same). If no language (locale) is selected, Windows performs the comparison by using default values. In the Windows United States language functions, uppercase characters have lower values than lowercase characters.

With a double-byte character set (DBCS) version of Windows, this function can compare two DBCS strings.

The Win32 lstrcmp function uses a word sort, rather than a string sort. A word sort treats hyphens and apostrophes differently than it treats other symbols that are not alphanumeric, in order to ensure that words such as "coop" and "co-op" stay together within a sorted list. Note that in 16-bit versions of Windows, lstrcmp  uses a string sort. For a detailed discussion of word sorts and string sorts, see the Remarks section of the reference page for the CompareString function .

See Also

CompareString, lstrcat, lstrcmpi, lstrcpy, lstrlen


lstrcmpi
lstrcmpi  QuickInfo  Overview  Group

The lstrcmpi function compares two character strings. The comparison is not case sensitive.

int lstrcmpi(

LPCTSTR  lpString1,	// address of first string
LPCTSTR  lpString2	// address of second string
);
Parameters

lpString1

Points to the first null-terminated string to be compared.

lpString2

Points to the second null-terminated string to be compared.

Return Value

If the function succeeds and the string pointed to by lpString1 is less than the string pointed to by lpString2, the return value is negative; if the string pointed to by lpString1 is greater than the string pointed to by lpString2, it is positive. If the strings are equal, the return value is zero.

Remarks

The lstrcmpi function compares two strings by checking the first characters against each other, the second characters against each other, and so on until it finds an inequality or reaches the ends of the strings.

The function returns the difference of the values of the first unequal characters it encounters. For example, lstrcmpi determines that "abcz" is greater than "abcdefg" and returns the difference of z and d.

The language (locale) selected by the user at setup time, or by using the control panel, determines which string is greater (or whether the strings are the same). If no language (locale) is selected, Windows performs the comparison by using default values.

For some locales, the lstrcmpi function may be insufficient. If this occurs, use CompareString to ensure proper comparison. For example, in Japan call CompareString with the IGNORE_CASE, IGNORE_KANATYPE, and IGNORE_WIDTH values to achieve the most appropriate non-exact string comparison. The IGNORE_KANATYPE and IGNORE_WIDTH values are ignored in non-Asian locales, so you can set these values for all locales and be guaranteed to have a culturally correct "insensitive" sorting regardless of the locale. Note that specifying these values slows performance, so use them only when necessary.

With a double-byte character set (DBCS) version of Windows, this function can compare two DBCS strings.

The Win32 lstrcmpi function uses a word sort, rather than a string sort. A word sort treats hyphens and apostrophes differently than it treats other symbols that are not alphanumeric, in order to ensure that words such as "coop" and "co-op" stay together within a sorted list. Note that in 16-bit versions of Windows, lstrcmpi uses a string sort. For a detailed discussion of word sorts and string sorts, see the Remarks section of the reference page for the CompareString function .

See Also

CompareString, lstrcat, lstrcmp, lstrcpy, lstrlen


lstrcpy
lstrcpy  QuickInfo  Overview  Group

The lstrcpy function copies a string to a buffer.

LPTSTR lstrcpy(

LPTSTR  lpString1,	// address of buffer
LPCTSTR  lpString2	// address of string to copy
);
Parameters

lpString1

Points to a buffer to receive the contents of the string pointed to by the lpString2 parameter. The buffer must be large enough to contain the string, including the terminating null character.

lpString2

Points to the null-terminated string to be copied.

Return Value

If the function succeeds, the return value is a pointer to the buffer.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

With a double-byte character set (DBCS) version of Windows, this function can be used to copy a DBCS string.

See Also

lstrcat, lstrcmp, lstrcmpi, lstrlen


lstrcpyn
lstrcpyn  QuickInfo  Overview  Group

The lstrcpyn function copies a specified number of characters from a source string into a buffer.

LPTSTR lstrcpyn(

LPTSTR  lpString1,	// address of target buffer
LPCTSTR  lpString2,	// address of source string
int  iMaxLength	// number of bytes or characters to copy
);
Parameters

lpString1

Points to a buffer into which the function copies characters. The buffer must be large enough to contain the number of bytes (ANSI version) or characters (Unicode version) specified by iMaxLength, including room for a terminating null character.

lpString2

Points to a null-terminated string from which the function copies characters.

iMaxLength

Specifies the number bytes (ANSI version) or characters (Unicode version) to be copied from the string pointed to by lpString2 into the buffer pointed to by lpString1, including a terminating null character.

Return Value

If the function succeeds, the return value is a pointer to the buffer.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

Note that the buffer pointed to by lpString1 must be large enough to include a terminating null character, and the string length value specified by iMaxLength includes room for a terminating null character. Thus, the following code

TCHAR chBuffer[512] ;

lstrcpyn(chBuffer, "abcdefghijklmnop", 4) ;

... copies the string "abc", followed by a terminating null character, to chBuffer.

See Also

lstrcat, lstrcmp, lstrcmpi, lstrcpy, lstrlen


lstrlen
lstrlen  QuickInfo  Overview  Group

The lstrlen function returns the length in bytes (ANSI version) or characters (Unicode version) of the specified string (not including the terminating null character).

int lstrlen(

LPCTSTR  lpString	// address of string to count
);
Parameters

lpString

Points to a null-terminated string.

Return Value

If the function succeeds, the return value specifies the length of the string in bytes (ANSI version) or characters (Unicode version).

See Also

lstrcat, lstrcmp, lstrcmpi, lstrcpy


LZClose
LZClose  QuickInfo  Overview  Group

The LZClose function closes a file that was opened by using the LZOpenFile function.

VOID LZClose(

INT  hFile	// LZ file handle identifying file to be closed
);
Parameters

hFile

Identifies the source file to be closed.

Return Value

This function does not return a value.

Remarks

The handle identifying the file must be retrieved by calling the LZOpenFile function. If the handle is retrieved by calling the CreateFile or OpenFile function, an error occurs.

If the file is compressed by using the Microsoft File Compression Utility (COMPRESS.EXE) and opened by using LZOpenFile, LZClose frees any global heap space that was allocated to expand the file.

See Also

CreateFile, LZOpenFile, OpenFile


LZCopy
LZCopy  QuickInfo  Overview  Group

The LZCopy function copies a source file to a destination file. If the source file is compressed with the Microsoft File Compression Utility (COMPRESS.EXE), this function creates a decompressed destination file. If the source file is not compressed, this function duplicates the original file.

LONG LZCopy(

INT  hfSource,	// LZ file handle identifying source file
INT  hfDest	// LZ file handle identifying destination file
);
Parameters

hfSource

Identifies the source file.

hfDest

Identifies the destination file.

Return Value

If the function succeeds, the return value specifies the size, in bytes, of the destination file.

If the function fails, the return value is an LZERROR_* code. These codes have values less than zero. Note that LZCopy calls neither SetLastError nor SetLastErrorEx; thus, its failure does not affect a thread's last-error code.

Here is a list of the LZERROR_* codes that LZCopy can return upon failure:

Value	Meaning
LZERROR_BADINHANDLE	The handle identifying the source file is not valid. The file cannot be read.
LZERROR_BADOUTHANDLE	The handle identifying the destination file is not valid. The file cannot be written.
LZERROR_GLOBALLOC	The maximum number of open compressed files has been exceeded or local memory cannot be allocated.
LZERROR_GLOBLOCK	The LZ file handle cannot be locked down.
LZERROR_READ	The source file format is not valid.
Remarks

The handles identifying the source and destination files must be retrieved by calling the LZInit or LZOpenFile function.

The preferred function to use for copying files is LZCopy. The CopyLZFile function is provided for compatibility with 16-bit versions of Windows.

If the function succeeds, the file identified by the hfDest parameter is always uncompressed.

See Also

CopyLZFile, LZInit, LZOpenFile


LZDone
LZDone  QuickInfo  Overview  Group

The LZDone function is obsolete. It is provided only for compatibility with 16-bit versions of Windows. Win32-based applications should use the LZOpenFile function.


LZInit
LZInit  QuickInfo  Overview  Group

The LZInit function allocates memory for the internal data structures required to decompress files, and then creates and initializes them.

INT LZInit(

INT  hfSource	// handle of source file
);
Parameters

hfSource

Identifies the source file.

Return Value

If the function succeeds, the return value is a new LZ file handle.

If the function fails, the return value is an LZERROR_* code. These codes have values less than zero. Note that LZInit calls neither SetLastError nor SetLastErrorEx; thus, its failure does not affect a thread's last-error code.

Here is a list of the LZERROR_* codes that LZInit can return upon failure:

Value	Meaning
LZERROR_BADINHANDLE	The handle identifying the source file is not valid. The file cannot be read.
LZERROR_GLOBALLOC	The maximum number of open compressed files has been exceeded or local memory cannot be allocated.
LZERROR_GLOBLOCK	The LZ file handle cannot be locked down.
LZERROR_UNKNOWNALG	The file is compressed with an unrecognized compression algorithm.
Remarks

A maximum of 16 compressed files can be open at any given time. Similarly, a maximum of 16 uncompressed files can be open at any given time. An application should be careful to close the handle returned by LZInit when it is done using the file; otherwise, the application can inadvertently hit the 16-file limit.

The handle this function returns is compatible only with the functions in LZEXPAND.DLL; it should not be used for other file operations.


LZOpenFile
LZOpenFile  QuickInfo  Overview  Group

The LZOpenFile function creates, opens, reopens, or deletes the specified file.

INT LZOpenFile(

LPTSTR  lpFileName,	// address of name of file to be opened
LPOFSTRUCT  lpReOpenBuf,	// address of open file structure
WORD  wStyle	// action to take
);
Parameters

lpFileName

Points to a string that specifies the name of a file.

lpReOpenBuf

Points to the OFSTRUCT structure that is to receive information about the file when the file is first opened. The structure can be used in subsequent calls to the LZOpenFile function to refer to the open file.

The szPathName member of this structure contains characters from the original equipment manufacturer (OEM) character set.

wStyle

Specifies the action to take. This parameter can be a combination of the following values:

Value	Meaning
OF_CANCEL	Ignored. In the Win32-based application programming interface (API), the OF_PROMPT style produces a dialog box containing a Cancel button.
OF_CREATE	Directs LZOpenFile to create a new file. If the file already exists, it is truncated to zero length.
OF_DELETE	Deletes the file.
OF_EXIST	Opens the file and then closes it to test for a file's existence.
OF_PARSE	Fills the OFSTRUCT structure but carries out no other action.
OF_PROMPT	Displays a dialog box if the requested file does not exist. The dialog box informs the user that Windows cannot find the file, and it contains Retry and Cancel buttons. Choosing the Cancel button directs LZOpenFile to return a "file not found" error message.
OF_READ	Opens the file for reading only.
OF_READWRITE	Opens the file for reading and writing.
OF_REOPEN	Opens the file using information in the reopen buffer.
OF_SHARE_DENY_NONE	Opens the file without denying other processes read or write access to the file. LZOpenFile fails if the file has been opened in compatibility mode by any other process.
OF_SHARE_DENY_READ	Opens the file and denies other processes read access to the file. LZOpenFile fails if the file has been opened in compatibility mode or has been opened for read access by any other process.
OF_SHARE_DENY_WRITE	Opens the file and denies other processes write access to the file. LZOpenFile fails if the file has been opened in compatibility mode or has been opened for write access by any other process.
OF_SHARE_EXCLUSIVE	Opens the file in exclusive mode, denying other processes both read and write access to the file. LZOpenFile fails if the file has been opened in any other mode for read or write access, even by the current process.
OF_WRITE	Opens the file for writing only.
Return Value

If the function succeeds and the value specified by the wStyle parameter is not OF_READ, the return value is a handle identifying the file. If the file is compressed and opened with wStyle set to OF_READ, the return value is a special file handle.

If the function fails, the return value is an LZERROR_* code. These codes have values less than zero. Note that LZOpenFile calls neither SetLastError nor SetLastErrorEx; thus, its failure does not affect a thread's last-error code.

Here is a list of the LZERROR_* codes that LZOpenFile can return upon failure:

Value	Meaning
LZERROR_BADINHANDLE	The handle identifying the source file is not valid. The file cannot be read.
LZERROR_GLOBALLOC	The maximum number of open compressed files has been exceeded or local memory cannot be allocated.
Remarks

If the wStyle parameter is the OF_READ flag (or OF_READ and any of the OF_SHARE_ flags) and the file is compressed, LZOpenFile calls the LZInit function, which performs the required initialization for the decompression operations.

The handle this function returns is compatible only with the functions in LZEXPAND.DLL; it should not be used for other file operations.

See Also

LZClose, LZInit, LZRead


LZRead
LZRead  QuickInfo  Overview  Group

The LZRead function reads (at most) the specified number of bytes from a file and copies them into a buffer.

INT LZRead(

INT  hFile,	// LZ file handle of file
LPSTR  lpBuffer,	// address of buffer for bytes
INT  cbRead	// count of bytes
);
Parameters

hFile

Identifies the source file.

lpBuffer

Points to a buffer that receives the bytes read from the file.

cbRead

Specifies the count of bytes to be read.

Return Value

If the function succeeds, the return value specifies the number of bytes read.

If the function fails, the return value is an LZERROR_* code. These codes have values less than zero. Note that LZRead calls neither SetLastError nor SetLastErrorEx; thus, its failure does not affect a thread's last-error code.

Here is a list of the LZERROR_* codes that LZRead can return upon failure:

Value	Meaning
LZERROR_BADINHANDLE	The handle identifying the source file is not valid. The file cannot be read.
LZERROR_BADOUTHANDLE	The handle identifying the destination file is not valid. The file cannot be written.
LZERROR_BADVALUE	One of the input parameters is not valid.
LZERROR_GLOBALLOC	The maximum number of open compressed files has been exceeded or local memory cannot be allocated.
LZERROR_GLOBLOCK	The LZ file handle cannot be locked down.
LZERROR_READ	The source file format is not valid.
LZERROR_WRITE	There is insufficient space for the output file.
Remarks

The handle identifying the file must be retrieved by calling either the LZInit or LZOpenFile function.

If the file is compressed, LZRead emulates the _lread function on an expanded image of the file and copies the bytes of data into the specified buffer.

Applications must call the LZOpenFile, LZSeek, and LZRead functions instead of the OpenFile, _llseek, and _lread functions.

See Also

LZInit, LZOpenFile, LZSeek


LZSeek
LZSeek  QuickInfo  Overview  Group

The LZSeek function moves a file pointer a number of bytes from a starting position.

LONG LZSeek(

INT  hFile,	// handle of source file
LONG  lOffset,	// number of bytes to move
INT  iOrigin	// starting position
);
Parameters

hFile

Identifies the source file.

lOffset

Specifies the number of bytes by which to move the file pointer.

iOrigin

Specifies the starting position of the pointer. This parameter must be one of the following values:

Value	Meaning
0	Moves the file pointer lOffset bytes from the beginning of the file.
1	Moves the file pointer lOffset bytes from the current position.
2	Moves the file pointer lOffset bytes from the end of the file.
Return Value

If the function succeeds, the return value specifies the offset from the beginning of the file to the new pointer position.

If the function fails, the return value is an LZERROR_* code. These codes have values less than zero. Note that LZSeek calls neither SetLastError nor SetLastErrorEx; thus, its failure does not affect a thread's last-error code.

Upon failure, LZSeek can return the following LZERROR_* codes:

Value	Meaning
LZERROR_BADINHANDLE	The handle identifying the source file is not valid. The file cannot be read.
LZERROR_BADVALUE	One of the parameters is outside the range of acceptable values.
LZERROR_GLOBLOCK	The LZ file handle cannot be locked down.
Remarks

The handle identified by the hFile parameter must be retrieved by calling either the LZInit or LZOpenFile function.

If the file is compressed, LZSeek emulates the _llseek function on an expanded image of the file.

See Also

LZInit, LZOpenFile


LZStart
LZStart  QuickInfo  Overview  Group

The LZStart function is obsolete. It is provided only for compatibility with 16-bit versions of Windows. Win32-based applications should use the LZCopy function.


MakeAbsoluteSD
MakeAbsoluteSD  QuickInfo  Overview  Group

The MakeAbsoluteSD function creates a security descriptor in absolute format by using a security descriptor in self-relative format as a template.

BOOL MakeAbsoluteSD(

PSECURITY_DESCRIPTOR  pSelfRelativeSecurityDescriptor,	// address self-relative SD
PSECURITY_DESCRIPTOR  pAbsoluteSecurityDescriptor,	// address of absolute SD
LPDWORD  lpdwAbsoluteSecurityDescriptorSize,	// address of size of absolute SD
PACL  pDacl,	// address of discretionary ACL
LPDWORD  lpdwDaclSize,	// address of size of discretionary ACL
PACL  pSacl,	// address of system ACL
LPDWORD  lpdwSaclSize,	// address of size of system ACL
PSID  pOwner,	// address of owner SID
LPDWORD  lpdwOwnerSize,	// address of size of owner SID
PSID  pPrimaryGroup,	// address of primary-group SID
LPDWORD  lpdwPrimaryGroupSize	// address of size of group SID
);
Parameters

pSelfRelativeSecurityDescriptor

Points to a SECURITY_DESCRIPTOR structure in self-relative format. The function creates an absolute-format version of this security descriptor without modifying the original security descriptor.

pAbsoluteSecurityDescriptor

Points to a buffer that the function fills with the main body of an absolute-format security descriptor. This information is formatted as a SECURITY_DESCRIPTOR structure.

lpdwAbsoluteSecurityDescriptorSize

Points to a variable specifying the size of the buffer pointed to by the pAbsoluteSecurityDescriptor parameter. If the buffer is not large enough for the security descriptor, the function fails and sets this variable to the minimum required size.

pDacl

Points to a buffer the function fills with the discretionary access-control list (ACL) of the absolute-format security descriptor. The main body of the absolute-format security descriptor references this pointer.

lpdwDaclSize

Points to a variable specifying the size of the buffer pointed to by the pDacl parameter. If the buffer is not large enough for the ACL, the function fails and sets this variable to the minimum required size.

pSacl

Points to a buffer the function fills with the system ACL of the absolute-format security descriptor. The main body of the absolute-format security descriptor references this pointer.

lpdwSaclSize

Points to a variable specifying the size of the buffer pointed to by the pSacl parameter. If the buffer is not large enough for the ACL, the function fails and sets this variable to the minimum required size.

pOwner

Points to a buffer the function fills with the security identifier (SID) of the owner of the absolute-format security descriptor. The main body of the absolute-format security descriptor references this pointer.

lpdwOwnerSize

Points to a variable specifying the size of the buffer pointed to by the pOwner parameter. If the buffer is not large enough for the SID, the function fails and sets this variable to the minimum required size.

pPrimaryGroup

Points to a buffer the function fills with the SID of the absolute-format security descriptor's primary group. The main body of the absolute-format security descriptor references this pointer.

lpdwPrimaryGroupSize

Points to a variable specifying the size of the buffer pointed to by the pPrimaryGroup parameter. If the buffer is not large enough for the SID, the function fails and sets this variable to the minimum required size.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

A security descriptor in absolute format contains pointers to the information it contains, rather than the information itself. A security descriptor in self-relative format contains the information in a contiguous block of memory. In a self-relative security descriptor, a SECURITY_DESCRIPTOR structure always starts the information, but the security descriptor's other components can follow the structure in any order. Instead of using memory addresses, the components of the self-relative security descriptor are identified by offsets from the beginning of the security descriptor. This format is useful when an security descriptor must be stored on a floppy disk or transmitted by means of a communications protocol.

A server that copies secured objects to various media can use the MakeAbsoluteSD function to create an absolute security descriptor from a self-relative security descriptor and the MakeSelfRelativeSD function to create a self-relative security descriptor from an absolute security descriptor.

See Also

MakeSelfRelativeSD, SECURITY_DESCRIPTOR


MakeDragList [New - Windows NT]
MakeDragList  QuickInfo  Overview  Group

[New - Windows NT]

The MakeDragList function changes the specified single-selection list box to a drag list box.

BOOL MakeDragList(

HWND  hLB
);
Parameters

hLB

Handle to the single-selection list box.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.


MakeProcInstance
MakeProcInstance  QuickInfo  Overview  Group

The MakeProcInstance function is obsolete. Win32 functions can be called directly.

This function is provided only for compatibility with 16-bit versions of Windows. Win32-based applications should not use this function.


MakeSelfRelativeSD
MakeSelfRelativeSD  QuickInfo  Overview  Group

The MakeSelfRelativeSD function creates a security descriptor in self-relative format by using a security descriptor in absolute format as a template.

BOOL MakeSelfRelativeSD(

PSECURITY_DESCRIPTOR  pAbsoluteSecurityDescriptor,	// address of absolute SD
PSECURITY_DESCRIPTOR  pSelfRelativeSecurityDescriptor,	// address self-relative SD
LPDWORD  lpdwBufferLength	// address of SD size
);
Parameters

pAbsoluteSecurityDescriptor

Points to a SECURITY_DESCRIPTOR structure in absolute format. The function creates a version of this security descriptor in self-relative format without modifying the original.

pSelfRelativeSecurityDescriptor

Points to a buffer the function fills with a security descriptor in self-relative format.

lpdwBufferLength

Points to a variable specifying the size of the buffer pointed to by the pSelfRelativeSecurityDescriptor parameter. If the buffer is not large enough for the security descriptor, the function fails and sets this variable to the minimum required size.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

A security descriptor in absolute format contains pointers to the information it contains, rather than containing the information itself. A security descriptor in self-relative format contains the information in a contiguous block of memory. In a self-relative security descriptor, a SECURITY_DESCRIPTOR structure always starts the information, but the security descriptor's other components can follow the structure in any order. Instead of using memory addresses, the components of the security descriptor are identified by offsets from the beginning of the security descriptor. This format is useful when an security descriptor must be stored on a floppy disk or transmitted by means of a communications protocol.

A server that copies secured objects to various media can use the MakeSelfRelativeSD function to create a self-relative security descriptor from an absolute security descriptor and the MakeAbsoluteSD function to create an absolute security descriptor from a self-relative security descriptor.

See Also

MakeAbsoluteSD, SECURITY_DESCRIPTOR


MapDialogRect
MapDialogRect  QuickInfo  Overview  Group

The MapDialogRect function converts (maps) the specified dialog box units to screen units (pixels). The function replaces the coordinates in the specified RECT structure with the converted coordinates, which allows the structure to be used to create a dialog box or position a control within a dialog box.

BOOL MapDialogRect(

HWND  hDlg,	// handle of dialog box
LPRECT  lpRect	// address of structure with rectangle
);
Parameters

hDlg

Identifies a dialog box. This function accepts only handles for dialog boxes created by one of the dialog box creation functions; handles for other windows are not valid.

lpRect

Points to a RECT structure that contains the dialog box coordinates to be converted.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

The MapDialogRect function assumes that the initial coordinates in the RECT structure represent dialog box units. To convert these coordinates from dialog box units to pixels, the function retrieves the current horizontal and vertical base units for the dialog box, then applies the following formulas:

left   = (left   * baseunitX) / 4

right  = (right  * baseunitX) / 4

top    = (top    * baseunitY) / 8

bottom = (bottom * baseunitY) / 8

In most cases, the base units for the dialog box are the same as those retrieved by using the GetDialogBaseUnits function. If the dialog box template has the DS_SETFONT style, however, the base units are the average width and height, in pixels, of the characters in the font given by the template.

See Also

CreateDialog, CreateDialogIndirect, CreateDialogIndirectParam, CreateDialogParam, DialogBox, DialogBoxIndirect, DialogBoxIndirectParam, DialogBoxParam, GetDialogBaseUnits, RECT


MapGenericMask
MapGenericMask  QuickInfo  Overview  Group

The MapGenericMask function maps the generic access rights in an access mask to specific and standard access rights. The function applies a mapping supplied in a GENERIC_MAPPING structure.

VOID MapGenericMask(

PDWORD  AccessMask,	// address of access mask
PGENERIC_MAPPING  GenericMapping	// address of GENERIC_MAPPING structure
);
Parameters

AccessMask

Points to an access mask receiving the specific and standard rights mapped from generic access rights.

GenericMapping

Points to a GENERIC_MAPPING structure specifying a mapping of generic access types to specific and standard access types.

Return Value

This function does not return a value.

Remarks

After calling the MapGenericMask function, the access mask pointed to by the AccessMask parameter has none of its generic bits (GenericRead, GenericWrite, GenericExecute, or GenericAll) or undefined bits set, although it can have other bits set. If bits other than the generic bits are provided on input, this function does not clear them.

See Also

AccessCheck, AreAllAccessesGranted, AreAnyAccessesGranted, GENERIC_MAPPING


MapViewOfFile
MapViewOfFile  QuickInfo  Overview  Group

The MapViewOfFile function maps a view of a file into the address space of the calling process.

LPVOID MapViewOfFile(

HANDLE  hFileMappingObject,	// file-mapping object to map into address space
DWORD  dwDesiredAccess,	// access mode
DWORD  dwFileOffsetHigh,	// high-order 32 bits of file offset
DWORD  dwFileOffsetLow,	// low-order 32 bits of file offset
DWORD  dwNumberOfBytesToMap	// number of bytes to map
);
Parameters

hFileMappingObject

Identifies an open handle of a file-mapping object. The CreateFileMapping and OpenFileMapping functions return this handle.

dwDesiredAccess

Specifies the type of access to the file view and, therefore, the protection of the pages mapped by the file. This parameter can be one of the following values:

Value	Meaning
FILE_MAP_WRITE	Read-write access. The hFileMappingObject parameter must have been created with PAGE_READWRITE protection. A read-write view of the file is mapped.
FILE_MAP_READ	Read-only access. The hFileMappingObject parameter must have been created with PAGE_READWRITE or PAGE_READ protection. A read-only view of the file is mapped.
FILE_MAP_ALL_ACCESS	Same as FILE_MAP_WRITE.
FILE_MAP_COPY	Copy on write access. If you create the map with PAGE_WRITECOPY and the view with FILE_MAP_COPY, you will receive a view to file. If you write to it, the pages are automatically swappable and the modifications you make will not go to the original data file. Windows 95: You must pass PAGE_WRITECOPY to CreateFileMapping; otherwise, an error will be returned. If you share the mapping between multiple processes using DuplicateHandle or OpenFileMapping and one process writes to a view, the modification is propagated to the other process. The original file does not change. Windows NT: There is no restriction as to how the hFileMappingObject parameter must be created. Copy on write is valid for any type of view.  If you share the mapping between multiple processes using DuplicateHandle or OpenFileMapping and one process writes to a view, the modification is not propagated to the other process. The original file does not change.
dwFileOffsetHigh

Specifies the high-order 32 bits of the file offset where mapping is to begin.

dwFileOffsetLow

Specifies the low-order 32 bits of the file offset where mapping is to begin. The combination of the high and low offsets must specify an offset within the file that matches the system's memory allocation granularity, or the function fails. That is, the offset must be a multiple of the allocation granularity. Use the GetSystemInfo function, which fills in the members of a SYSTEM_INFO structure, to obtain the system's memory allocation granularity.

dwNumberOfBytesToMap

Specifies the number of bytes of the file to map. If dwNumberOfBytesToMap is zero, the entire file is mapped.

Return Value

If the function succeeds, the return value is the starting address of the mapped view.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

Mapping a file makes the specified portion of the file visible in the address space of the calling process.

Multiple views of a file (or a file-mapping object and its mapped file) are said to be "coherent" if they contain identical data at a specified time. This occurs if the file views are derived from the same file-mapping object. A process can duplicate a file-mapping object handle into another process by using the DuplicateHandle function, or another process can open a file-mapping object by name by using the OpenFileMapping function.

A mapped view of a file is not guaranteed to be coherent with a file being accessed by the ReadFile or WriteFile function.

Windows 95 only: MapViewOfFile may require the swapfile to grow. If the swapfile cannot, MapViewOfFile fails.

See Also

CreateFileMapping, DuplicateHandle, GetSystemInfo, MapViewOfFileEx, OpenFileMapping, UnmapViewOfFile, SYSTEM_INFO


MapViewOfFileEx
MapViewOfFileEx  QuickInfo  Overview  Group

The MapViewOfFileEx function maps a view of a file into the address space of the calling process. This extended function allows the calling process to specify a suggested memory address for the mapped view.

This function is available for Win32-based applications only.

LPVOID MapViewOfFileEx(

HANDLE  hFileMappingObject,	// file-mapping object to map into address space
DWORD  dwDesiredAccess,	// access mode
DWORD  dwFileOffsetHigh,	// high-order 32 bits of file offset
DWORD  dwFileOffsetLow,	// low-order 32 bits of file offset
DWORD  dwNumberOfBytesToMap,	// number of bytes to map
LPVOID  lpBaseAddress	// suggested starting address for mapped view
);
Parameters

hFileMappingObject

Identifies an open handle to a file-mapping object. The CreateFileMapping and OpenFileMapping functions return this handle.

dwDesiredAccess

Specifies the type of access to the file-mapping object and, therefore, the page protection of the pages mapped by the file. This parameter can be one of the following values:

Value	Meaning
FILE_MAP_WRITE	Read-and-write access. The hFileMappingObject parameter must have been created with PAGE_READWRITE protection. A read-write view of the file is mapped.
FILE_MAP_READ	Read-only access. The hFileMappingObject parameter must have been created with PAGE_READWRITE or PAGE_READ protection. A read-only view of the file is mapped.
FILE_MAP_ALL_ACCESS	Same as FILE_MAP_WRITE.
FILE_MAP_COPY	Copy on write access. If you create the map with PAGE_WRITECOPY and the view with FILE_MAP_COPY, you will reeive a view to file. If you write to it, the pages are automatically swappable and the modifications you make will not go to the original data file. Windows 95: You must pass PAGE_WRITECOPY to CreateFileMapping; otherwise, an error will be returned. If you share the mapping between multiple processes using DuplicateHandle or OpenFileMapping and one process writes to a view, the modification is propagated to the other process. The original file does not change. Windows NT: There is no restriction as to how the hFileMappingObject parameter must be created. Copy on write is valid for any type of view.  If you share the mapping between multiple processes using DuplicateHandle or OpenFileMapping and one process writes to a view, the modification is not propagated to the other process. The original file does not change.
dwFileOffsetHigh

Specifies the high-order 32 bits of the file offset where mapping is to begin.

dwFileOffsetLow

Specifies the low-order 32 bits of the file offset where mapping is to begin. The combination of the high and low offsets must specify an offset within the file that matches the system's memory allocation granularity, or the function fails. That is, the offset must be a multiple of the allocation granularity. Use the GetSystemInfo function, which fills in the members of a SYSTEM_INFO structure, to obtain the system's memory allocation granularity.

dwNumberOfBytesToMap

Specifies the number of bytes of the file to map. If dwNumberOfBytesToMap is zero, the entire file is mapped.

lpBaseAddress

Points to the memory address in the calling process's address space where mapping should begin. This must be a multiple of the system's memory allocation granularity, or the function fails. Use the GetSystemInfo function, which fills in the members of a SYSTEM_INFO structure, to obtain the system's memory allocation granularity. If there is not enough address space at the specified address, the function fails.

If lpBaseAddress is NULL, the operating system chooses the mapping address. In this case, this function is equivalent to the MapViewOfFile function.

Return Value

If the function succeeds, the return value is the starting address of the mapped view.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

Mapping a file makes the specified portion of the file visible in the address space of the calling process.

If a suggested mapping address is supplied, the file is mapped at the specified address (rounded down to the nearest 64K boundary) if there is enough address space at the specified address. If there is not, the function fails.

Typically, the suggested address is used to specify that a file should be mapped at the same address in multiple processes. This requires the region of address space to be available in all involved processes. No other memory allocation, including use of the VirtualAlloc function to reserve memory, can take place in the region used for mapping.

Windows 95: If the lpBaseAddress parameter specifies a base offset, the function succeeds only if the same memory region is available for the memory mapped file in all other 32-bit processes.

Windows NT: If the lpBaseAddress parameter specifies a base offset, the function succeeds if the given memory region is not already in use by the calling process. the system does not guarantee that the same memory region is available for the memory mapped file in other 32-bit processes.

Multiple views of a file (or a file-mapping object and its mapped file) are said to be "coherent" if they contain identical data at a specified time. This occurs if the file views are derived from the same file-mapping object. A process can duplicate a file-mapping object handle into another process by using the DuplicateHandle function, or another process can open a file-mapping object by name by using the OpenFileMapping function.

A mapped view of a file is not guaranteed to be coherent with a file being accessed by the ReadFile or WriteFile function.

See Also

CreateFileMapping, DuplicateHandle, GetSystemInfo, MapViewOfFile, OpenFileMapping, ReadFile, UnmapViewOfFile, SYSTEM_INFO, VirtualAlloc, WriteFile


MapVirtualKey
MapVirtualKey  QuickInfo  Overview  Group

The MapVirtualKey function translates (maps) a virtual-key code into a scan code or character value, or translates a scan code into a virtual-key code.

UINT MapVirtualKey(

UINT  uCode,	// virtual-key code or scan code
UINT  uMapType	// translation to perform
);
Parameters

uCode

Specifies the virtual-key code or scan code for a key. How this value is interpreted depends on the value of the uMapType parameter.

uMapType

Specifies the translation to perform. The value of this parameter depends on the value of the uCode parameter:

Value	Meaning
0	uCode is a virtual-key code and is translated into a scan code. If it is a virtual-key code that does not distinguish between left- and right-hand keys, the left-hand scan code is returned. If there is no translation, the function returns 0.
1	uCode is a scan code and is translated into a virtual-key code that does not distinguish between left- and right-hand keys. If there is no translation, the function returns 0.
2	uCode is a virtual-key code and is translated into an unshifted character value in the low-order word of the return value. Dead keys (diacritics) are indicated by setting the top bit of the return value. If there is no translation, the function returns 0.
3	uCode is a scan code and is translated into a virtual-key code that distinguishes between left- and right-hand keys. If there is no translation, the function returns 0.
Return Value

The return value is either a scan code, a virtual-key code, or a character value, depending on the value of uCode and uMapType. If there is no translation, the return value is zero.

Remarks

An application can use MapVirtualKey to translate scan codes to the virtual-key code constants VK_SHIFT, VK_CONTROL, and VK_MENU, and vice versa. These translations do not distinguish between the left and right instances of the SHIFT, CTRL, or ALT keys. An application can get the scan code corresponding to the left or right instance of one of these keys by calling MapVirtualKey with uCode set to one of the following virtual-key code constants:

VK_LSHIFT	VK_RSHIFT
VK_LCONTROL	VK_RCONTROL
VK_LMENU	VK_RMENU
These left- and right-distinguishing constants are available to an application only through the GetKeyboardState, SetKeyboardState, GetAsyncKeyState, GetKeyState, and MapVirtualKey functions.

See Also

GetAsyncKeyState, GetKeyboardState, GetKeyState, SetKeyboardState


MapVirtualKeyEx [New - Windows 95]
MapVirtualKeyEx  QuickInfo

[New - Windows 95]

The MapVirtualKeyEx function translates (maps) a virtual-key code into a scan code or character value, or translates a scan code into a virtual-key code. The function translates the codes using the input language and physical keyboard layout identified by the given keyboard layout handle.

UINT MapVirtualKeyEx(

UINT  uCode,	// virtual-key code or scan code
UINT  uMapType,	// translation to perform
HKL  dwhkl	// keyboard layout handle
);
Parameters

uCode

Specifies the virtual-key code or scan code for a key. How this value is interpreted depends on the value of the uMapType parameter.

uMapType

Specifies the translation to perform. The value of this parameter depends on the value of the uCode parameter:

Value	Meaning
0	uCode is a virtual-key code and is translated into a scan code. If it is a virtual-key code that does not distinguish between left- and right-hand keys, the left-hand scan code is returned. If there is no translation, the function returns 0.
1	uCode is a scan code and is translated into a virtual-key code that does not distinguish between left- and right-hand keys. If there is no translation, the function returns 0.
2	uCode is a virtual-key code and is translated into an unshifted character value in the low order word of the return value. Dead keys (diacritics) are indicated by setting the top bit of the return value. If there is no translation, the function returns 0.
3	uCode is a scan code and is translated into a virtual-key code that distinguishes between left- and right-hand keys. If there is no translation, the function returns 0.
dwhkl

Identifies the keyboard layout to use for translating the given code. This parameter can be any keyboard layout handle previously returned by the LoadKeyboardLayout function.

Return Value

The return value is either a scan code, a virtual-key code, or a character value, depending on the value of uCode and uMapType. If there is no translation, the return value is zero.

Remarks

An application can use MapVirtualKeyEx to translate scan codes to the virtual-key code constants VK_SHIFT, VK_CONTROL, and VK_MENU, and vice versa. These translations do not distinguish between the left and right instances of the SHIFT, CTRL, or ALT keys. An application can get the scan code corresponding to the left or right instance of one of these keys by calling MapVirtualKeyEx with uCode set to one of the following virtual-key code constants:

VK_LSHIFT	VK_RSHIFT
VK_LCONTROL	VK_RCONTROL
VK_LMENU	VK_RMENU
These left- and right-distinguishing constants are available to an application only through the GetKeyboardState, SetKeyboardState, GetAsyncKeyState, GetKeyState, MapVirtualKey, and MapVirtualKeyEx functions.

See Also

GetAsyncKeyState, GetKeyboardState, GetKeyState, LoadKeyboardLayout, MapVirtualKey, SetKeyboardState


MapWindowPoints
MapWindowPoints  QuickInfo  Overview  Group

The MapWindowPoints function converts (maps) a set of points from a coordinate space relative to one window to a coordinate space relative to another window.

int MapWindowPoints(

HWND  hWndFrom,	// handle of window to be mapped from
HWND  hWndTo,	// handle of window to be mapped to
LPPOINT  lpPoints,	// address of structure array with points to map
UINT  cPoints	// number of structures in array
);
Parameters

hWndFrom

Identifies the window from which points are converted. If this parameter is NULL or HWND_DESKTOP, the points are presumed to be in screen coordinates.

hWndTo

Identifies the window to which points are converted. If this parameter is NULL or HWND_DESKTOP, the points are converted to screen coordinates.

lpPoints

Points to an array of POINT structures that contain the set of points to be converted. This parameter can also point to a RECT structure, in which case the cPoints parameter should be set to 2.

cPoints

Specifies the number of POINT structures in the array pointed to by the lpPoints parameter.

Return Value

If the function succeeds, the low-order word of the return value is the number of pixels added to the horizontal coordinate of each source point in order to compute the horizontal coordinate of each destination point; the high-order word is the number of pixels added to the vertical coordinate of each source point in order to compute the vertical coordinate of each destination point.

See Also

ClientToScreen, POINT, RECT, ScreenToClient


MaskBlt
MaskBlt  QuickInfo  Overview  Group

The MaskBlt function combines the color data for the source and destination bitmaps using the specified mask and raster operation.

BOOL MaskBlt(

HDC  hdcDest,	// handle of destination device context
int  nXDest,	// x-coord. of upper-left corner of destination rectangle
int  nYDest,	// y-coord. of upper-left corner of destination rectangle
int  nWidth,	// width of source and destination rectangles
int  nHeight,	// height of source and destination rectangles
HDC  hdcSrc,	// handle of source device context
int  nXSrc,	// x-coord. of upper-left corner of source rectangle
int  nYSrc,	// y-coord. of upper-left corner of source rectangle
HBITMAP  hbmMask,	// handle of monochrome bit mask
int  xMask,	// horizontal pixel offset into the mask bitmap
int  yMask,	// vertical pixel offset into the mask bitmap
DWORD  dwRop	// raster operation code
);
Parameters

hdcDest

Identifies the destination device context.

nXDest

Specifies the logical x-coordinate of the upper-left corner of the destination rectangle.

nYDest

Specifies the logical y-coordinate of the upper-left corner of the destination rectangle.

nWidth

Specifies the width, in logical units, of the destination rectangle and source bitmap.

nHeight

Specifies the height, in logical units, of the destination rectangle and source bitmap.

hdcSrc

Identifies the device context from which the bitmap is to be copied. It must be zero if the dwRop parameter specifies a raster operation that does not include a source.

nXSrc

Specifies the logical x-coordinate of the upper-left corner of the source bitmap.

nYSrc

Specifies the logical y-coordinate of the upper-left corner of the source bitmap.

hbmMask

Identifies the monochrome mask bitmap combined with the color bitmap in the source device context.

xMask

Specifies the horizontal pixel offset for the mask bitmap specified by the hbmMask parameter.

yMask

Specifies the vertical pixel offset for the mask bitmap specified by the hbmMask parameter.

dwRop

Specifies both foreground and background ternary raster operation codes that the function uses to control the combination of source and destination data. The background raster operation code is stored in the high-order byte of the high-order word of this value; the foreground raster operation code is stored in the low-order byte of the high-order word of this value; the low-order word of this value is ignored, and should be zero. The macro MAKEROP4 creates such combinations of foreground and background raster operation codes.

For a discussion of foreground and background in the context of this function, see the following Remarks section.

For a list of common raster operation codes, see BitBlt .

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

A value of 1 in the mask specified by hbmMask indicates that the foreground raster operation code specified by dwRop should be applied at that location. A value of 0 in the mask indicates that the background raster operation code specified by dwRop should be applied at that location.

If the raster operations require a source, the mask rectangle must cover the source rectangle. If it does not, the function will fail. If the raster operations do not require a source, the mask rectangle must cover the destination rectangle. If it does not, the function will fail.

If a rotation or shear transformation is in effect for the source device context when this function is called, an error occurs. However, other types of transformation are allowed.

If the color formats of the source, pattern, and destination bitmaps differ, this function converts the pattern or source format, or both, to match the destination format.

If the mask bitmap is not a monochrome bitmap, an error occurs.

When an enhanced metafile is being recorded, an error occurs (and the function returns FALSE) if the source device context identifies an enhanced-metafile device context.

Not all devices support the MaskBlt function. An application should call the GetDeviceCaps function to determine whether a device supports this function.

If no mask bitmap is supplied, this function behaves exactly like BitBlt, using the foreground raster operation code.

The pixel offsets in the mask bitmap map to the point (0,0) in the source device context's bitmap. This is useful in cases where a mask bitmap contains a set of masks; an application can easily apply any one of them to a mask-block transfer task by adjusting the pixel offsets and rectangle sizes sent to MaskBlt.

See Also

BitBlt, GetDeviceCaps, PlgBlt, StretchBlt


MenuHelp [New - Windows NT]
MenuHelp  QuickInfo  Overview  Group

[New - Windows NT]

The MenuHelp function processes WM_MENUSELECT and WM_COMMAND messages and displays help text about the current menu in the specified status window.

void MenuHelp(

UINT uMsg,
WPARAM wParam,
LPARAM lParam,
HMENU hMainMenu,
HINSTANCE hInst,
HWND hwndStatus,
UINT FAR * lpwIDs
);
Parameters

uMsg

WM_MENUSELECT or WM_COMMAND message.

wParam

First message parameter.

lParam

Second message parameter.

hMainMenu

Handle to the application's main menu.

hInst

Handle to the module that contains the string resources.

hwndStatus

Handle to the status window.

lpwIDs

Pointer to an array that contains pairs of string resource identifiers and menu handles. The function searches the array for the handle to the selected menu and, if found, uses the corresponding resource identifier to load the appropriate help string.

Return Value

This function does not return a value.

See Also

WM_COMMAND, WM_MENUSELECT


MenuItemFromPoint [New - Windows 95]
MenuItemFromPoint  QuickInfo  Overview  Group

[New - Windows 95]

The MenuItemFromPoint function determines which menu item, if any, is at the specified location.

UINT WINAPI MenuItemFromPoint(

HWND  hWnd,
HMENU  hMenu,
POINT  ptScreen
);
Parameters

hWnd

Handle to the window containing the menu bar or pop-up menu.

hMenu

Handle to the menu containing the menu items to hit test.

ptScreen

POINT structure specifying the location to test. If hMenu specifies a menu bar, this parameter is in window coordinates. Otherwise, it is in client coordinates.

Return Value

Returns the zero-based position of the menu item at the specified location or −1 if no menu item is at the specified location.

See Also

POINT


MessageBeep
MessageBeep  QuickInfo  Overview  Group

The MessageBeep function plays a waveform sound. The waveform sound for each sound type is identified by an entry in the [sounds] section of the registry.

BOOL MessageBeep(

UINT  uType	// sound type
);
Parameters

uType

Specifies the sound type, as identified by an entry in the [sounds] section of the registry. This parameter can be one of the following values:

Value	Sound
0xFFFFFFFF	Standard beep using the computer speaker
MB_ICONASTERISK	SystemAsterisk
MB_ICONEXCLAMATION	SystemExclamation
MB_ICONHAND	SystemHand
MB_ICONQUESTION	SystemQuestion
MB_OK	SystemDefault
Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

After queuing the sound, the MessageBeep function returns control to the calling function and plays the sound asynchronously.

If it cannot play the specified alert sound, MessageBeep attempts to play the system default sound. If it cannot play the system default sound, the function produces a standard beep sound through the computer speaker.

The user can disable the warning beep by using the Control Panel Sound application.

See Also

FlashWindow, MessageBox


MessageBox
MessageBox  QuickInfo  Overview  Group

The MessageBox function creates, displays, and operates a message box. The message box contains an application-defined message and title, plus any combination of predefined icons and push buttons.

int MessageBox(

HWND  hWnd,	// handle of owner window
LPCTSTR  lpText,	// address of text in message box
LPCTSTR  lpCaption,	// address of title of message box
UINT  uType	// style of message box
);
Parameters

hWnd

Identifies the owner window of the message box to be created. If this parameter is NULL, the message box has no owner window.

lpText

Points to a null-terminated string containing the message to be displayed.

lpCaption

Points to a null-terminated string used for the dialog box title. If this parameter is NULL, the default title Error is used.

uType

Specifies the contents and behavior of the dialog box. This parameter can be a combination of the following values:

Value	Meaning
MB_ABORTRETRYIGNORE	The message box contains three push buttons: Abort, Retry, and Ignore.
MB_APPLMODAL	The user must respond to the message box before continuing work in the window identified by the hWnd parameter. However, the user can move to the windows of other applications and work in those windows.  Depending on the hierarchy of windows in the application, the user may be able to move to other windows within the application. All child windows of the parent of the message box are automatically disabled, but popup windows are not.  MB_APPLMODAL is the default value if neither MB_SYSTEMMODAL nor MB_TASKMODAL is specified.
MB_DEFAULT_DESKTOP_ONLY	The desktop currently receiving input must be a default desktop; otherwise, the function fails. A default desktop is one an application runs on after the user has logged on.
MB_DEFBUTTON1	The first button is the default button. Note that the first button is always the default unless MB_DEFBUTTON2, MB_DEFBUTTON3, or MB_DEFBUTTON4 is specified.
MB_DEFBUTTON2	The second button is a default button.
MB_DEFBUTTON3	The third button is a default button.
MB_DEFBUTTON4	The fourth button is a default button.
MB_HELP	Windows 95: Adds a Help button to the message box. Choosing the Help button   or pressing F1 generates a Help event.
MB_ICONASTERISK	Same as MB_ICONINFORMATION.
MB_ICONERROR	Windows 95: Same as MB_ICONHAND.
MB_ICONEXCLAMATION	An exclamation-point icon appears in the message box.
MB_ICONHAND	Same as MB_ICONSTOP.
MB_ICONINFORMATION	An icon consisting of a lowercase letter i in a circle appears in the message box.
MB_ICONQUESTION	A question-mark icon appears in the message box.
MB_ICONSTOP	A stop-sign icon appears in the message box.
MB_ICONWARNING	Windows 95: Same as MB_ICONEXCLAMATION.
MB_OK	The message box contains one push button: OK.
MB_OKCANCEL	The message box contains two push buttons: OK and Cancel.
MB_RETRYCANCEL	The message box contains two push buttons: Retry and Cancel.
MB_RIGHT	Windows 95: The text is right-justified.
MB_RTLREADING	Windows 95: Displays message and caption text using right-to-left reading order on Hebrew and Arabic systems.
MB_SERVICE_NOTIFICATION	Windows NT: The caller is a service notifying the user of an event. The function displays a message box on the current active desktop, even if there is no user logged on to the computer. If this flag is set, the hWnd parameter must be NULL. This is so the message box can appear on a desktop other than the desktop corresponding to the hWnd.
MB_SETFOREGROUND	The message box becomes the foreground window. Internally, Windows calls the SetForegroundWindow function for the message box.
MB_SYSTEMMODAL	All applications are suspended until the user responds to the message box. Unless the application specifies MB_ICONHAND, the message box does not become modal until after it is created; consequently, the owner window and other windows continue to receive messages resulting from its activation. Use system-modal message boxes to notify the user of serious, potentially damaging errors that require immediate attention (for example, running out of memory).
MB_TASKMODAL	Same as MB_APPLMODAL except that all the top-level windows belonging to the current task are disabled if the hWnd parameter is NULL. Use this flag when the calling application or library does not have a window handle available but still needs to prevent input to other windows in the current application without suspending other applications.
MB_YESNO	The message box contains two push buttons: Yes and No.
MB_YESNOCANCEL	The message box contains three push buttons: Yes, No, and Cancel.
Return Value

The return value is zero if there is not enough memory to create the message box.

If the function succeeds, the return value is one of the following menu-item values returned by the dialog box:

Value	Meaning
IDABORT	Abort button was selected.
IDCANCEL	Cancel button was selected.
IDIGNORE	Ignore button was selected.
IDNO	No button was selected.
IDOK	OK button was selected.
IDRETRY	Retry button was selected.
IDYES	Yes button was selected.
If a message box has a Cancel button, the function returns the IDCANCEL value if either the ESC key is pressed or the Cancel button is selected. If the message box has no Cancel button, pressing ESC has no effect.

Remarks

When you use a system-modal message box to indicate that the system is low on memory, the strings pointed to by the lpText and lpCaption parameters should not be taken from a resource file, because an attempt to load the resource may fail.

When an application calls MessageBox and specifies the MB_ICONHAND and MB_SYSTEMMODAL flags for the uType parameter, Windows displays the resulting message box regardless of available memory. When these flags are specified, Windows limits the length of the message box text to three lines. Windows does not automatically break the lines to fit in the message box, however, so the message string must contain carriage returns to break the lines at the appropriate places.

If you create a message box while a dialog box is present, use the handle of the dialog box as the hWnd parameter. The hWnd parameter should not identify a child window, such as a control in a dialog box.

Windows 95 only: The system can support a maximum of 16,364 window handles.

See Also

FlashWindow, MessageBeep, MessageBoxEx, SetForegroundWindow


MessageBoxEx
MessageBoxEx  QuickInfo  Overview  Group

The MessageBoxEx function creates, displays, and operates a message box. The message box contains an application-defined message and title, plus any combination of predefined icons and push buttons. The wLanguageId parameter specifies which set of language resources is used for the predefined push buttons. For full descriptions of the other parameters of MessageBoxEx, see  MessageBox .

int MessageBoxEx(

HWND  hWnd,	// handle of owner window
LPCTSTR  lpText,	// address of text in message box
LPCTSTR  lpCaption,	// address of title of message box
UINT  uType,	// style of message box
WORD  wLanguageId	// language identifier
);
Parameters

hWnd

Identifies the owner window of the message box to be created. If this parameter is NULL, the message box has no owner window.

lpCaption

Points to a null-terminated string containing the message to be displayed.

lpszTitle

Points to a null-terminated string used for the dialog box title. If this parameter is NULL, the default title Error is used.

uType

Specifies the contents and behavior of the dialog box. This parameter can be a combination of the following values:

Value	Meaning
MB_ABORTRETRYIGNORE	The message box contains three push buttons: Abort, Retry, and Ignore.
MB_APPLMODAL	The user must respond to the message box before continuing work in the window identified by the hWnd parameter. However, the user can move to the windows of other applications and work in those windows. MB_APPLMODAL is the default if neither MB_SYSTEMMODAL nor MB_TASKMODAL is specified.
MB_DEFAULT_DESKTOP_ONLY	The desktop currently receiving input must be a default desktop; otherwise, the function fails. A default desktop is one an application runs on after the user has logged on.
MB_DEFBUTTON1	The first button is the default button. Note that the first button is always the default unless MB_DEFBUTTON2, MB_DEFBUTTON3, or MB_DEFBUTTON4 is specified.
MB_DEFBUTTON2	The second button is a default button.
MB_DEFBUTTON3	The third button is a default button.
MB_DEFBUTTON4	The fourth button is a default button.
MB_HELP	Windows 95: Adds a Help button to the message box. Choosing the Help button   or pressing F1 generates a Help event.
MB_ICONASTERISK	Same as MB_ICONINFORMATION.
MB_ICONERROR	Windows 95: Same as MB_ICONHAND.
MB_ICONEXCLAMATION	An exclamation-point icon appears in the message box.
MB_ICONHAND	Same as MB_ICONSTOP.
MB_ICONINFORMATION	An icon consisting of a lowercase letter i in a circle appears in the message box.
MB_ICONQUESTION	A question-mark icon appears in the message box.
MB_ICONSTOP	A stop-sign icon appears in the message box.
MB_ICONWARNING	Windows 95: Same as MB_ICONEXCLAMATION.
MB_OK	The message box contains one push button: OK.
MB_OKCANCEL	The message box contains two push buttons: OK and Cancel.
MB_RETRYCANCEL	The message box contains two push buttons: Retry and Cancel.
MB_RIGHT	Windows 95: The text is right-justified.
MB_RTLREADING	Windows 95: Displays message and caption text using right-to-left reading order on Hebrew and Arabic systems.
MB_SERVICE_NOTIFICATION	Windows NT: The caller is a service notifying the user of an event. The function displays a message box on the current active desktop, even if there is no user logged on to the computer. If this flag is set, the hWnd parameter must be NULL. This is so the message box can appear on a desktop other than the desktop corresponding to the hWnd.
MB_SETFOREGROUND	The message box becomes the foreground window. Internally, Windows calls the SetForegroundWindow function for the message box.
MB_SYSTEMMODAL	All applications are suspended until the user responds to the message box. Unless the application specifies MB_ICONHAND, the message box does not become modal until after it is created; consequently, the owner window and other windows continue to receive messages resulting from its activation. Use system-modal message boxes to notify the user of serious, potentially damaging errors that require immediate attention (for example, running out of memory).
MB_TASKMODAL	Same as MB_APPLMODAL except that all the top-level windows belonging to the current task are disabled if the hWnd parameter is NULL. Use this flag when the calling application or library does not have a window handle available but still needs to prevent input to other windows in the current application without suspending other applications.
MB_YESNO	The message box contains two push buttons: Yes and No.
MB_YESNOCANCEL	The message box contains three push buttons: Yes, No, and Cancel.
wLanguageId

Specifies the language in which to display the text contained in the predefined push buttons. This value must be in the form returned by the MAKELANGID macro. For this release, the set of values is limited. For a list of the possible primary language identifiers and sublanguage identifiers, and a discussion of current language availability limitations, see the following Remarks section.

Return Value

If the function succeeds, the return value is a nonzero menu-item value returned by the dialog box.

Value	Meaning
IDABORT	Abort button was selected.
IDCANCEL	Cancel button was selected.
IDIGNORE	Ignore button was selected.
IDNO	No button was selected.
IDOK	OK button was selected.
IDRETRY	Retry button was selected.
IDYES	Yes button was selected.
If a message box has a Cancel button, the function returns the IDCANCEL value when either the ESC key or Cancel button is pressed. If the message box has no Cancel button, pressing the ESC key has no effect.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

When you create a system-modal message box to indicate that the system is low on memory, the strings passed as the lpText and lpCaption parameters should not be taken from a resource file, because an attempt to load the resource may fail.

When an application calls the MessageBoxEx function and specifies the MB_ICONHAND and MB_SYSTEMMODAL flags for the uType parameter, the Win32 API displays the resulting message box regardless of available memory. When you specify these flags, Windows limits the length of the message-box text to one line.

If you create a message box while a dialog box is present, use the handle of the dialog box as the hWnd parameter. The hWnd parameter should not identify a child window, such as a dialog box.

The table that follows shows the set of language identifiers and sublanguage identifiers, along with a description of each. Note that each localized release usually contains only resources for that language. Thus, for example, the U.S. version offers LANG_ENGLISH, the French version offers LANG_FRENCH, the German version offers LANG_GERMAN, and the Japanese version offers LANG_JAPANESE. Each version offers LANG_NEUTRAL. This limits the set of values that can be used with the wLanguageId parameter. However, this may not apply in all cases. You should always enumerate the locales that are installed on a system before using an LCID, whether in this function or any other that requires an LCID.

Primary Language Identifiers and Sublanguage Identifiers

Primary language: LANG_ NEUTRAL
Sublanguage: SUBLANG_ DEFAULT
Description: Default sublanguage

Primary language: LANG_ ALBANIAN
Sublanguage: None
Description: Albanian

Primary language: LANG_ ARABIC
Sublanguage: None
Description: Arabic

Primary language: LANG_ BAHASA
Sublanguage: None
Description: Bahasa (Indonesian)

Primary language: LANG_ BULGARIAN
Sublanguage: None
Description: Bulgarian

Primary language: LANG_ CATALAN
Sublanguage: None
Description: Catalan

Primary language: LANG_ CHINESE
Sublanguage: SUBLANG_ CHINESE_SIMPLIFIED
Description: Simplified Chinese

Primary language: LANG_ CHINESE
Sublanguage: SUBLANG_ CHINESE_TRADITIONAL
Description: Traditional Chinese

Primary language: LANG_ CZECH
Sublanguage: None
Description: Czech

Primary language: LANG_ DANISH
Sublanguage: None
Description: Danish

Primary language: LANG_ DUTCH
Sublanguage: SUBLANG_ DUTCH
Description: Dutch

Primary language: LANG_ DUTCH
Sublanguage: SUBLANG_ DUTCH_BELGIAN
Description: Belgian Dutch

Primary language: LANG_ ENGLISH
Sublanguage: SUBLANG_ ENGLISH_AUS
Description: Australian English

Primary language: LANG_ ENGLISH
Sublanguage: SUBLANG_ ENGLISH_UK
Description: UK English

Primary language: LANG_ ENGLISH
Sublanguage: SUBLANG_ ENGLISH_US
Description: US English

Primary language: LANG_ FINNISH
Sublanguage: None
Description: Finnish

Primary language: LANG_ FRENCH
Sublanguage: SUBLANG_ FRENCH
Description: French

Primary language: LANG_ FRENCH
Sublanguage: SUBLANG_ FRENCH_BELGIAN
Description: Belgian French

Primary language: LANG_ FRENCH
Sublanguage: SUBLANG_ FRENCH_CANADIAN
Description: Canadian French

Primary language: LANG_ FRENCH
Sublanguage: SUBLANG_ FRENCH_SWISS
Description: Swiss French

Primary language: LANG_ GERMAN
Sublanguage: SUBLANG_ GERMAN
Description: German

Primary language: LANG_ GERMAN
Sublanguage: SUBLANG_ GERMAN_SWISS
Description: Swiss German

Primary language: LANG_ GREEK
Sublanguage: None
Description: Greek

Primary language: LANG_ HEBREW
Sublanguage: None
Description: Hebrew

Primary language: LANG_ HUNGARIAN
Sublanguage: None
Description: Hungarian

Primary language: LANG_ ICELANDIC
Sublanguage: None
Description: Icelandic

Primary language: LANG_ ITALIAN
Sublanguage: SUBLANG_ ITALIAN
Description: Italian

Primary language: LANG_ ITALIAN
Sublanguage: SUBLANG_ ITALIAN_SWISS
Description: Swiss Italian

Primary language: LANG_ JAPANESE
Sublanguage: None
Description: Japanese

Primary language: LANG_ KOREAN
Sublanguage: None
Description: Korean

Primary language: LANG_ NORWEGIAN
Sublanguage: SUBLANG_ NORWEGIAN_BOKMAL
Description: Norwegian − Bokmal

Primary language: LANG_ NORWEGIAN
Sublanguage: SUBLANG_ NORWEGIAN_NYNORSK
Description: Norwegian − Nynorsk

Primary language: LANG_ POLISH
Sublanguage: None
Description: Polish

Primary language: LANG_ PORTUGUESE
Sublanguage: SUBLANG_ PORTUGUESE
Description: Portuguese

Primary language: LANG_ PORTUGUESE
Sublanguage: SUBLANG_ PORTUGUESE_BRAZILIAN
Description: Brazilian Portuguese

Primary language: LANG_ RHAETO_ROMAN
Sublanguage: None
Description: Rhaeto-Romanic

Primary language: LANG_ ROMANIAN
Sublanguage: None
Description: Romanian

Primary language: LANG_ RUSSIAN
Sublanguage: None
Description: Russian

Primary language: LANG_ SERBO_CROATIAN
Sublanguage: SUBLANG_ SERBO_CROATIAN_CYRILLIC
Description: Serbo-Croatian (Cyrillic)

Primary language: LANG_ SERBO_CROATIAN
Sublanguage: SUBLANG_ SERBO_CROATIAN_LATIN
Description: Croato-Serbian (Latin)

Primary language: LANG_ SLOVAK
Sublanguage: None
Description: Slovak

Primary language: LANG_ SPANISH
Sublanguage: SUBLANG_ SPANISH
Description: Spanish

Primary language: LANG_ SPANISH
Sublanguage: SUBLANG_ SPANISH_MEXICAN
Description: Spanish Mexican

Primary language: LANG_ SWEDISH
Sublanguage: None
Description: Swedish

Primary language: LANG_ THAI
Sublanguage: None
Description: Thai

Primary language: LANG_ TURKISH
Sublanguage: None
Description: Turkish

Primary language: LANG_ URDU
Sublanguage: None
Description: Urdu

Windows 95 only: The system can support a maximum of 16,364 window handles.

See Also

MAKELANGID, MessageBeep, MessageBox, SetForegroundWindow


MessageBoxIndirect [New - Windows 95]
MessageBoxIndirect  QuickInfo  Overview  Group

[New - Windows 95]

The MessageBoxIndirect function creates, displays, and operates a message box. The message box contains application-defined message text and title, any icon, and any combination of predefined push buttons.

BOOL API MessageBoxIndirect(

LPMSGBOXPARAMS lpMsgBoxParams	// address of structure for message box parameters
);
Parameters

lpMsgBoxParams

Points to a MSGBOXPARAMS structure that contains information used to display the message box.

Remarks

Windows 95 only: The system can support a maximum of 16,364 window handles.

See Also

MSGBOXPARAMS


MessageProc
MessageProc  QuickInfo  Overview  Group

The MessageProc hook procedure is an application-defined callback function the system calls after an input event occurs in a dialog box, message box, menu, or scroll bar, but before the message generated by the input event is processed. The hook procedure can monitor messages for a dialog box, message box, menu, or scroll bar created by a particular application or all applications.

LRESULT CALLBACK MessageProc(

int  code,	// hook code
WPARAM  wParam,	// undefined
LPARAM  lParam	// address of structure with message data
);
Parameters

code

Specifies the type of input event that generated the message. This parameter can be one of the following values:

Value	Meaning
MSGF_DDEMGR	The input event occurred while the Dynamic Data Exchange Management Library (DDEML) was waiting for a synchronous transaction to finish. For more information about DDEML, see Dynamic Data Exchange Management Library
MSGF_DIALOGBOX	The input event occurred in a message box or dialog box.
MSGF_MENU	The input event occurred in a menu.
MSGF_NEXTWINDOW	The input event occurred as a result of the user's pressing the ALT+TAB key combination to activate a different window.
MSGF_SCROLLBAR	The input event occurred in a scroll bar.
If code is less than zero, the hook procedure must pass the message to the CallNextHookEx function without further processing and return the value returned by CallNextHookEx.

wParam

Specifies a NULL value.

lParam

Points to an MSG structure.

Return Value

If the hook procedure processes the message, the return value must be a nonzero value. Otherwise, it must be zero.

Remarks

An application installs the hook procedure by specifying the WH_MSGFILTER hook type and the address of the hook procedure in a call to the SetWindowsHookEx function.

If an application that uses the DDEML and performs synchronous transactions must process messages before they are dispatched, it must use the WH_MSGFILTER hook.

MessageProc is a placeholder for the application-defined function name.

See Also

CallNextHookEx, SetWindowsHookEx, MSG


midiInGetID
midiInGetID  QuickInfo

The midiInGetID function gets the device identifier for a Musical Instrument Digital Interface (MIDI) input device.

MMRESULT midiInGetID(

HMIDIIN  hmi,	// identifier of MIDI input device to query
LPUINT  puDeviceID	// address of buffer for device identifier
);
Parameters

hmi

Identifies a handle of the MIDI input device.

puDeviceID

Points to a variable that will receive the device identifier.

Return Value

If the function succeeds, the return value is zero.

If the function fails, the return value is an error code that can be MMSYSERR_INVALHANDLE, indicating that the hmi parameter specifies an invalid handle.


midiOutGetID
midiOutGetID  QuickInfo

The midiOutGetID function retrieves the device identifier for the specified Musical Instrument Digital Interface (MIDI) output device.

MMRESULT midiOutGetID(

HMIDIOUT  hmo,	// handle of device to return ID for
PUINT  puDeviceID	// address of buffer for device ID
);
Parameters

hmo

Identifies the MIDI output device.

puDeviceID

Points to a variable that will receive the the device identifier.

Return Value

If the function succeeds, the return value is zero.

If the function fails, the return value is an error code, which can be MMSYSERR_INVALHANDLE, indicating that the hmo parameter specifies an invalid handle.


MidiProc
MidiProc  QuickInfo  Overview  Group

The MidiProc function is an application-defined callback function that processes Musical Instrument Digital Interface (MIDI) device messages. An application can specify the address of this function when it calls the midiInOpen or midiOutOpen function.

void CALLBACK MidiProc(

HMIDIIN  hMidiIn,	// handle of MIDI device
UINT  uMsg,	// MIDI message
DWORD  dwInstance,	// callback instance data
DWORD  dwParam1,	// application-defined parameter
DWORD  dwParam2	// application-defined parameter
);
Parameters

hMidiIn

Identifies the MIDI device.

uMsg

Specifies a MIDI message.

dwInstance

Specifies the instance data supplied by using the midiInOpen or midiOutOpen function.

dwParam1

Specifies a parameter for the message.

dwParam2

Specifies a parameter for the message.

Return Value

This function does not return a value.

Remarks

MidiProc is a placeholder for the application-defined function name.

There are several differences between MidiProc functions under Windows NT and under Windows 3.1 :

•	Under Windows 3.1, a MidiProc function is called at interrupt time. The call to a MidiProc function occurs on a separate thread under Windows NT.

•	Under Windows 3.1, a MidiProc function has to be in a dynamic link library. Under Windows NT, there is no such restriction.

•	Under Windows 3.1, a MidiProc function must be exported in a .DEF file. Under Windows NT, that is not necessary.

If source code must be compatible with Windows 3.1, it should follow the Windows 3.1 rules as noted briefly above and specified more fully in the Windows 3.1 documentation.

One other item should be noted carefully. There is a limited set of APIs that a Windows 3.1 MidiProc function may call. In Win32, that strict limitation has been removed. However, it is strongly recommended that a Windows NT MidiProc function restrain its calls to APIs in the same set, with the addition of the API SetEvent. Here is the Windows NT recommended list:

EnterCriticalSection	PostThreadMessage
LeaveCriticalSection	SetEvent
midiOutLongMsg	timeGetSystemTime
midiOutShortMsg	timeGetTime
OutputDebugString	timeKillEvent
PostMessage	timeSetEvent
If an application's MidiProc function does stray from this list, it should be careful not to call APIs that take a long time to complete.

If a Win32 MidiProc shares data with other code, a Critical Section or similar mutual exclusion mechanism should be used to protect the integrity of the data.

See Also

midiInOpen, midiOutOpen, TimeProc, WaveProc, MMIOProc


MMIOProc
MMIOProc  QuickInfo  Overview  Group

An MMIOProc function is a custom input/output (I/O) procedure installed by the mmioInstallIOProc function. It is application-defined, and of type MMIOPROC.

LRESULT CALLBACK MMIOProc(

LPSTR  lpmmioinfo,	// address of structure with file information
UINT  uMsg,	// specifies sent message
LONG  lParam1,	// application-defined parameter
LONG  lParam2	// application-defined parameter
);
Parameters

lpmmioinfo

Points to an MMIOINFO structure containing information about the open file.

The I/O procedure must maintain the lDiskOffset member in this structure to indicate the file offset to the next read or write location. The I/O procedure can use the adwInfo[] member to store state information. The I/O procedure should not modify any other members of the MMIOINFO structure.

uMsg

Specifies a message indicating the requested I/O operation. Messages that can be received include MMIOM_OPEN, MMIOM_CLOSE, MMIOM_READ, MMIOM_SEEK, MMIOM_WRITE, and MMIOM_WRITEFLUSH.

lParam1

Specifies an application-defined parameter for the message.

lParam2

Specifies an application-defined parameter for the message.

Return Value

The return value depends on the message specified by uMsg. If the I/O procedure does not recognize a message, it should return zero.

Remarks

MMIOProc is a placeholder for the application-defined function name.

The four-character code specified by the fccMMIOProc member in the MMIOINFO structure associated with a file identifies a filename extension for a custom storage system. When an application calls mmioOpen with a filename such as "one.xyz+two", the I/O procedure associated with the four-character code "XYZ" is called to open the "two" element of the file "one.xyz".

The mmioInstallIOProc function maintains a separate list of installed I/O procedures for each Windows-based application. Therefore, different applications can use the same I/O procedure identifier for different I/O procedures without conflict. However, installing an I/O procedure globally enables any process to use the procedure.

If an application calls mmioInstallIOProc more than once to register the same I/O procedure, then it must call mmioInstallIOProc to remove the procedure once for each time it installed the procedure.

mmioInstallIOProc will not prevent an application from installing two different I/O procedures with the same identifier, or installing an I/O procedure with one of the predefined identifiers ("DOS ", "MEM "). The most recently installed procedure takes precedence, and the most recently installed procedure is the first one to be removed.

When searching for a specified I/O procedure, local procedures are searched first, then global procedures.

See Also

MMIOINFO, mmioInstallIOProc, MMIOM_OPEN, MMIOM_CLOSE, MMIOM_READ, MMIOM_SEEK, MMIOM_WRITE, MMIOM_WRITEFLUSH, mmioOpen


mmsystemGetVersion
mmsystemGetVersion  QuickInfo  Overview  Group

The mmsystemGetVersion function is obsolete. It is provided only for compatibility with 16-bit versions of Windows. If it is necessary to obtain a version number, use the Win32 function GetVersionEx.


ModifyMenu
ModifyMenu  QuickInfo  Overview  Group

The ModifyMenu function changes an existing menu item. This function is used to specify the content, appearance, and behavior of the menu item.

BOOL ModifyMenu(

HMENU hMnu,	// handle of menu
UINT uPosition,	// menu item to modify
UINT uFlags,	// menu item flags
UINT uIDNewItem,	// menu item identifier or pop-up menu handle
LPCTSTR lpNewItem	// menu item content
);
Parameters

hMnu

Identifies the menu to be changed.

uPosition

Specifies the menu item to be changed, as determined by the uFlags parameter.

uFlags

Specifies flags that control the interpretation of the uPosition parameter and the content, appearance, and behavior of the menu item. This parameter must be a combination of one of the following required values and at least one of the values listed in the following Remarks section.

Value	Meaning
MF_BYCOMMAND	Indicates that the uPosition parameter gives the identifier of the menu item. The MF_BYCOMMAND flag is the default if neither the MF_BYCOMMAND nor MF_BYPOSITION flag is specified.
MF_BYPOSITION	Indicates that the uPosition parameter gives the zero-based relative position of the menu item.
uIDNewItem

Specifies either the identifier of the modified menu item or, if uFlags is set to the MF_POPUP flag, the handle of the pop-up menu.

lpNewItem

Points to the content of the changed menu item. The interpretation of this parameter depends on whether the uFlags parameter includes the MF_BITMAP, MF_OWNERDRAW, or MF_STRING flag.

Value	Meaning
MF_BITMAP	Contains a bitmap handle.
MF_OWNERDRAW	Contains a 32-bit value supplied by an application that is used to maintain additional data related to the menu item. The value is in the itemData member of the structure pointed to by the lparam parameter of the WM_MEASUREITEM or WM_DRAWITEM messages sent when the menu item is created or its appearance is updated.
MF_STRING	Contains a pointer to a null-terminated string (the default).
Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

If ModifyMenu replaces a menu item that activates a pop-up menu, the function destroys the old pop-up menu and frees the memory used by it.

The application must call the DrawMenuBar function whenever a menu changes, whether or not the menu is in a displayed window. To change the attributes of existing menu items, it is much faster to use the CheckMenuItem and EnableMenuItem functions.

The following list describes the flags that may be set in the uFlags parameter:

Value	Meaning
MF_BITMAP	Uses a bitmap as the menu item. The lpNewItem parameter contains the handle of the bitmap.
MF_BYCOMMAND	Indicates that the uPosition parameter specifies the identifier of the menu item (the default).
MF_BYPOSITION	Indicates that the uPosition parameter specifies the zero-based relative position of the new menu item.
MF_CHECKED	Places a check mark next to the item. If your application provides check mark bitmaps (see the SetMenuItemBitmaps function), this flag displays a checked bitmap next to the menu item.
MF_DISABLED	Disables the menu item so that it cannot be selected, but this flag does not gray it.
MF_ENABLED	Enables the menu item so that it can be selected and restores it from its grayed state.
MF_GRAYED	Disables the menu item and grays it so that it cannot be selected.
MF_MENUBARBREAK	Functions the same as the MF_MENUBREAK flag, except for pop-up menus where the new column is separated from the old column by a vertical line.
MF_MENUBREAK	Places the item on a new line (for menu bars) or in a new column (for pop-up menus) without separating columns.
MF_OWNERDRAW	Specifies that the item is an owner-drawn item. Before the menu is displayed for the first time, the window that owns the menu receives a WM_MEASUREITEM message to retrieve the width and height of the menu item. The WM_DRAWITEM message is then sent to the window procedure of the owner window whenever the appearance of the menu item must be updated.
MF_POPUP	Specifies that the menu item is a pop-up item; that is, selecting it activates a pop-up menu. The uIDNewItem parameter specifies the handle of the pop-up menu. This flag is used to add a pop-up item to a menu bar or to a pop-up menu.
MF_SEPARATOR	Draws a horizontal dividing line. This flag is used only in a pop-up menu. The dividing line cannot be grayed, disabled, or highlighted. The lpNewItem and uIDNewItem parameters are ignored.
MF_STRING	Specifies that the menu item is a text string; the lpNewItem parameter points to the string.
MF_UNCHECKED	Does not place a check mark next to the item (the default). If your application supplies check mark bitmaps (see the SetMenuItemBitmaps function), this flag displays an unchecked bitmap next to the menu item.
The following list shows groups of flags that cannot be used together:

•	MF_BYCOMMAND and MF_BYPOSITION

•	MF_DISABLED, MF_ENABLED, and MF_GRAYED

•	MF_BITMAP, MF_STRING, MF_OWNERDRAW, and MF_SEPARATOR

•	MF_MENUBARBREAK and MF_MENUBREAK

•	MF_CHECKED and MF_UNCHECKED

See Also

AppendMenu, CheckMenuItem, DrawMenuBar, EnableMenuItem, SetMenuItemBitmaps, WM_DRAWITEM, WM_MEASUREITEM


ModifyWorldTransform
ModifyWorldTransform  QuickInfo  Overview  Group

The ModifyWorldTransform function changes the world transformation for a device context using the specified mode.

BOOL ModifyWorldTransform(

HDC  hdc,	// handle of device context
CONST XFORM *  lpXform,	// address of transformation data
DWORD  iMode	// modification mode
);
Parameters

hdc

Specifies the device context.

lpXform

Points to an XFORM structure used to modify the world transformation for the given device context.

iMode

Specifies how the transformation data modifies the current world transformation. This parameter must be one of the following values:

Value	Description
MWT_IDENTITY	Resets the current world transformation by using the identity matrix. If this mode is specified, the XFORM structure pointed to by lpXform is ignored.
MWT_LEFTMULTIPLY	Multiplies the current transformation by the data in the XFORM structure. (The data in the XFORM structure becomes the left multiplicand, and the data for the current transformation becomes the right multiplicand.)
MWT_RIGHTMULTIPLY	Multiplies the current transformation by the data in the XFORM structure. (The data in the XFORM structure becomes the right multiplicand, and the data for the current transformation becomes the left multiplicand.)
Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

The ModifyWorldTransform function will fail unless graphics mode for the specified device context has been set to GM_ADVANCED by previously calling the SetGraphicsMode function. Likewise, it will not be possible to reset the graphics mode for the device context to the default GM_COMPATIBLE mode, unless world transform has first been reset to the default identity transform by calling SetWorldTransform or ModifyWorldTransform.

See Also

GetWorldTransform, SetWorldTransform, SetGraphicsMode, XFORM


mouse_event
mouse_event  QuickInfo  Overview  Group

The mouse_event function synthesizes mouse motion and button clicks.

VOID mouse_event(

DWORD  dwFlags,	// flags specifying various motion/click variants
DWORD  dx,	// horizontal mouse position or position change
DWORD  dy,	// vertical mouse position or position change
DWORD  cButtons,	// unused, reserved for future use, set to zero
DWORD  dwExtraInfo	// 32 bits of application-defined information
);
Parameters

dwFlags

A set of flag bits that specify various aspects of mouse motion and button clicking. The bits in this parameter can be any reasonable combination of the following values:

Value	Meaning
MOUSEEVENTF_ABSOLUTE	Specifies that the dx and dy parameters contain normalized absolute coordinates. If not set, those parameters contain relative data: the change in position since the last reported position. This flag can be set, or not set, regardless of what kind of mouse or mouse-like device, if any, is connected to the system. For further information about relative mouse motion, see the following Remarks section.
MOUSEEVENTF_MOVE	Specifies that movement occurred.
MOUSEEVENTF_LEFTDOWN	Specifies that the left button changed to down.
MOUSEEVENTF_LEFTUP	Specifies that the left button changed to up.
MOUSEEVENTF_RIGHTDOWN	Specifies that the right button changed to down.
MOUSEEVENTF_RIGHTUP	Specifies that the right button changed to up.
MOUSEEVENTF_MIDDLEDOWN	Specifies that the middle button changed to down.
MOUSEEVENTF_MIDDLEUP	Specifies that the middle button changed to up.
The flag bits that specify mouse button status are set to indicate changes in status, not ongoing conditions. For example, if the left mouse button is pressed and held down, MOUSEEVENTF_LEFTDOWN is set when the left button is first pressed, but not for subsequent motions. Similarly, MOUSEEVENTF_LEFTUP is set only when the button is first released.

dx

Specifies the mouse's absolute position along the x-axis or its amount of motion since the last mouse event was generated, depending on the setting of MOUSEEVENTF_ABSOLUTE. Absolute data is given as the mouse's actual x-coordinate; relative data is given as the number of mickeys moved.

dy

Specifies the mouse's absolute position along the y-axis or its amount of motion since the last mouse event was generated, depending on the setting of MOUSEEVENTF_ABSOLUTE. Absolute data is given as the mouse's actual y-coordinate; relative data is given as the number of mickeys moved.

cButtons

This parameter is currently unused. It is reserved for future use. It must be set to zero.

dwExtraInfo

Specifies an additional 32-bit value associated with the mouse event. An application calls GetMessageExtraInfo to obtain this extra information.

Return Value

This function has no return value.

Remarks

If the mouse has moved, indicated by MOUSEEVENTF_MOVE being set, dx and dy hold information about that motion. The information is given as absolute or relative integer values.

If MOUSEEVENTF_ABSOLUTE value is specified, dx and dy contain normalized absolute coordinates between 0 and 65,535. The event procedure maps these coordinates onto the display surface. Coordinate (0,0) maps onto the upper-left corner of the display surface, (65535,65535) maps onto the lower-right corner.

If the MOUSEEVENTF_ABSOLUTE value is not specified, dx and dy specify relative motions from when the last mouse event was generated (the last reported position). Positive values mean the mouse moved right (or down); negative values mean the mouse moved left (or up).

Relative mouse motion is subject to the effects of the mouse speed and the two mouse threshold values. An end user sets these three values with the Mouse Tracking Speed slider of Control Panel's Mouse option. An application obtains and sets these values with the SystemParametersInfo function. The operating system applies two tests to the specified relative mouse motion. If the specified distance along either the x or y axis is greater than the first mouse threshold value, and the mouse speed is not zero, the operating system doubles the distance. If the specified distance along either the x or y axis is greater than the second mouse threshold value, and the mouse speed is equal to two, the operating system doubles the distance that resulted from applying the first threshold test. It is thus possible for the operating system to multiply relatively-specified mouse motion along the x or y axis by up to four times.

The mouse_event function is used to synthesize mouse events by applications that need to do so. It is also used by applications that need to obtain more information from the mouse than its position and button state. For example, if a tablet manufacturer wants to pass pen-based information to its own applications, it can write a dynamic-link library (DLL) that communicates directly to the tablet hardware, obtains the extra information, and saves it in a queue. The DLL then calls mouse_event with the standard button and x/y position data, along with, in the dwExtraInfo parameter, some pointer or index to the queued extra information. When the application needs the extra information, it calls the DLL with the pointer or index stored in dwExtraInfo, and the DLL returns the extra information.

See Also

GetMessageExtraInfo, SystemParametersInfo


MouseProc
MouseProc  QuickInfo  Overview  Group

The MouseProc hook procedure is an application-defined or library-defined callback function the system calls whenever an application calls the GetMessage or PeekMessage function and there is a mouse message to be processed.

LRESULT CALLBACK MouseProc(

int  nCode,	// hook code
WPARAM  wParam,	// message identifier
LPARAM  lParam	// mouse coordinates
);
Parameters

nCode

Specifies a code the hook procedure uses to determine how to process the message. This parameter can be one of the following values:

Value	Meaning
HC_ACTION	The wParam and lParam parameters contain information about a mouse message.
HC_NOREMOVE	The wParam and lParam parameters contain information about a mouse message, and the mouse message has not been removed from the message queue. (An application called the PeekMessage function, specifying the PM_NOREMOVE flag.)
If nCode is less than zero, the hook procedure must pass the message to the CallNextHookEx function without further processing and should return the value returned by CallNextHookEx.

wParam

Specifies the identifier of the mouse message.

lParam

Points to a MOUSEHOOKSTRUCT structure.

Return Value

To enable the system to process the message, the return value must be zero. To discard the message, the return value must be a nonzero value.

Remarks

The hook procedure must not install a JournalPlaybackProc callback function.

An application installs the hook procedure by specifying the WH_MOUSE hook type and the address of the hook procedure in a call to the SetWindowsHookEx function.

MouseProc is a placeholder for the application-defined or library-defined function name.

See Also

CallNextHookEx, GetMessage, JournalPlaybackProc, MOUSEHOOKSTRUCT, PeekMessage, SetWindowsHookEx


MoveFile
MoveFile  QuickInfo  Overview  Group

The MoveFile function renames an existing file or a directory (including all its children).

BOOL MoveFile(

LPCTSTR  lpExistingFileName,	// address of name of the existing file
LPCTSTR  lpNewFileName	// address of new name for the file
);
Parameters

lpExistingFileName

Points to a null-terminated string that names an existing file or directory.

lpNewFileName

Points to a null-terminated string that specifies the new name of a file or directory. The new name must not already exist. A new file may be on a different file system or drive. A new directory must be on the same drive.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The MoveFile function will move (rename) either a file or a directory (including all its children) either in the same directory or across directories. The one caveat is that the MoveFile function will fail on directory moves when the destination is on a different volume.

See Also

CopyFile, MoveFileEx


MoveFileEx
MoveFileEx  QuickInfo  Overview  Group

The MoveFileEx function renames an existing file.

BOOL MoveFileEx(

LPCTSTR  lpExistingFileName,	// address of name of the existing file
LPCTSTR  lpNewFileName,	// address of new name for the file
DWORD  dwFlags	// flag to determine how to move file
);
Parameters

lpExistingFileName

Points to a null-terminated string that names an existing file.

lpNewFileName

Points to a null-terminated string that specifies the new name of lpExistingFileName. When moving a file, the destination can be on a different file system or drive. When moving a directory, the destination must be on the same drive. If dwFlags specifies both MOVEFILE_REPLACE_EXISTING and MOVEFILE_DELAY_UNTIL_REBOOT, lpNewFileName can be NULL. In this case, the function registers the lpExistingFileName file to be deleted when the system reboots.

dwFlags

A set of bit flags that specify how to move the file. You can specify any combination of the following values:

Value	Meaning
MOVEFILE_REPLACE_EXISTING
	If a file of the name specified by lpNewFileName already exists, the function replaces its contents with those specified by lpExistingFileName.
MOVEFILE_COPY_ALLOWED
	If the file is to be moved to a different volume, the function simulates the move by using the CopyFile and DeleteFile functions. Cannot be combined with the MOVEFILE_DELAY_UNTIL_REBOOT flag.
MOVEFILE_DELAY_UNTIL_REBOOT
	Windows NT only: The function does not move the file until the operating system is restarted. The system moves the file immediately after AUTOCHK is executed, but before creating any paging files. Consequently, this parameter enables the function to delete paging files from previous startups.
Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

An application cannot specify both MOVEFILE_DELAY_UNTIL_REBOOT and MOVEFILE_COPY_ALLOWED for dwFlags. Function calls that do so will fail.

Windows NT only: If the dwFlags parameter specifies MOVEFILE_REPLACE_EXISTING and MOVEFILE_DELAY_UNTIL_REBOOT, the function stores entries under the following registry key:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\
Session Manager\FileRenameOperations

The system uses these registry entries to complete the operation at reboot.

See Also

CopyFile, DeleteFile, MoveFile


MoveMemory
MoveMemory  QuickInfo  Overview  Group

The MoveMemory function moves a block of memory from one location to another.

VOID MoveMemory (

PVOID  Destination,	// address of move destination
CONST VOID *  Source,	// address of block to move
DWORD  Length	// size, in bytes, of block to move
);
Parameters

Destination

Points to the starting address of the destination of the move.

Source

Points to the starting address of the block of memory to move.

Length

Specifies the size, in bytes, of the block of memory to move.

Return Value

This function has no return value.

Remarks

The source and destination blocks may overlap.

See Also

CopyMemory, FillMemory, ZeroMemory


MoveTo

The MoveTo function is not implemented in the Win32 API. Win32-based applications should use the MoveToEx function.


MoveToEx
MoveToEx  QuickInfo  Overview  Group

The MoveToEx function updates the current position to the specified point and optionally returns the previous position.

BOOL MoveToEx(

HDC  hdc,	// handle of device context
int  X,	// x-coordinate of new current position
int  Y,	// y-coordinate of new current position
LPPOINT  lpPoint	// address of old current position
);
Parameters

hdc

Identifies a device context.

X

Specifies the x-coordinate of the new position, in logical units.

Y

Specifies the y-coordinate of the new position, in logical units.

lpPoint

Points to a POINT structure in which the previous current position is stored. If this parameter is a NULL pointer, the previous position is not returned.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

The MoveToEx function affects all drawing functions.

See Also

AngleArc, LineTo, POINT, PolyBezierTo, PolylineTo


MoveWindow
MoveWindow  QuickInfo  Overview  Group

The MoveWindow function changes the position and dimensions of the specified window. For a top-level window, the position and dimensions are relative to the upper-left corner of the screen. For a child window, they are relative to the upper-left corner of the parent window's client area.

BOOL MoveWindow(

HWND  hWnd,	// handle of window
int  X,	// horizontal position
int  Y,	// vertical position
int  nWidth,	// width
int  nHeight,	// height
BOOL  bRepaint	// repaint flag
);
Parameters

hWnd

Identifies the window.

X

Specifies the new position of the left side of the window.

Y

Specifies the new position of the top of the window.

nWidth

Specifies the new width of the window.

nHeight

Specifies the new height of the window.

bRepaint

Specifies whether the window is to be repainted. If this parameter is TRUE, the window receives a WM_PAINT message. If the parameter is FALSE, no repainting of any kind occurs. This applies to the client area, the nonclient area (including the title bar and scroll bars), and any part of the parent window uncovered as a result of moving a child window. If this parameter is FALSE, the application must explicitly invalidate or redraw any parts of the window and parent window that need redrawing.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

If the bRepaint parameter is TRUE, Windows sends the WM_PAINT message to the window procedure immediately after moving the window (that is, the MoveWindow function calls the UpdateWindow function). If bRepaint is FALSE, Windows places the WM_PAINT message in the message queue associated with the window. The message loop dispatches the WM_PAINT message only after dispatching all other messages in the queue.

MoveWindow sends WM_WINDOWPOSCHANGING, WM_WINDOWPOSCHANGED, WM_MOVE, WM_SIZE, and WM_NCCALCSIZE messages to the window.

See Also

SetWindowPos, UpdateWindow, WM_GETMINMAXINFO, WM_PAINT


MsgWaitForMultipleObjects
MsgWaitForMultipleObjects  QuickInfo  Overview  Group

The MsgWaitForMultipleObjects function returns when one of the following occurs:

•	Either any one or all of the specified objects are in the signaled state.

•	A specified type of input becomes available in the thread's input queue.

•	The time-out interval elapses.

Note that MsgWaitForMultipleObjects doesn't return if there was previously unread input of the specified type in the queue. It only wakes up when input arrives.

DWORD MsgWaitForMultipleObjects(

DWORD  nCount,	// number of handles in handle array
LPHANDLE  pHandles,	// address of object-handle array
BOOL  fWaitAll,	// wait for all or wait for one
DWORD  dwMilliseconds,	// time-out interval in milliseconds
DWORD  dwWakeMask	// type of input events to wait for
);
Parameters

nCount

Specifies the number of object handles in the array pointed to by pHandles. The maximum number of object handles is MAXIMUM_WAIT_OBJECTS minus one.

pHandles

Points to an array of object handles. For a list of the object types whose handles can be specified, see the following Remarks section. The array can contain handles of objects of different types.

Windows NT: The handles must have SYNCHRONIZE access.

fWaitAll

Specifies the wait type. If TRUE, the function returns when all objects in the pHandles array are signaled at the same time. If FALSE, the function returns when any one of the objects is signaled. In the latter case, the return value indicates the object whose state caused the function to return.

dwMilliseconds

Specifies the time-out interval, in milliseconds. The function returns if the interval elapses, even if the conditions specified by the fWaitAll or dwWakeMask parameter are not satisfied. If dwMilliseconds is zero, the function tests the states of the specified objects and returns immediately. If dwMilliseconds is INFINITE, the function's time-out interval never elapses.

dwWakeMask

Specifies the types of input that will cause the function to return. This parameter can be any combination of the following values:

Value	Meaning
QS_ALLINPUT	Any message is in the queue.
QS_HOTKEY	A WM_HOTKEY message is in the queue.
QS_INPUT	An input message is in the queue.
QS_KEY	A WM_KEYUP, WM_KEYDOWN, WM_SYSKEYUP, or WM_SYSKEYDOWN message is in the queue.
QS_MOUSE	A WM_MOUSEMOVE message or mouse-button message (WM_LBUTTONUP, WM_RBUTTONDOWN, and so on).
QS_MOUSEBUTTON	A mouse-button message (WM_LBUTTONUP, WM_RBUTTONDOWN, and so on).
QS_MOUSEMOVE	A WM_MOUSEMOVE message is in the queue.
QS_PAINT	A WM_PAINT message is in the queue.
QS_POSTMESSAGE	A posted message (other than those just listed) is in the queue.
QS_SENDMESSAGE	A message sent by another thread or application is in the queue.
QS_TIMER	A WM_TIMER message is in the queue.
Return Value

If the function succeeds, the return value indicates the event that caused the function to return. The successful return value is one of the following:

Value	Meaning
WAIT_OBJECT_0 to (WAIT_OBJECT_0 + nCount − 1)	If fWaitAll is TRUE, the return value indicates that the state of all specified objects is signaled. If fWaitAll is FALSE, the return value minus WAIT_OBJECT_0 indicates the pHandles array index of the object that satisfied the wait.
WAIT_OBJECT_0 + nCount	Input of the type specified in the dwWakeMask parameter is available in the thread's input queue.
WAIT_ABANDONED_0 to (WAIT_ABANDONED_0 + nCount − 1)	If fWaitAll is TRUE, the return value indicates that the state of all specified objects is signaled and at least one of the objects is an abandoned mutex object. If fWaitAll is FALSE, the return value minus WAIT_ABANDONED_0 indicates the pHandles array index of an abandoned mutex object that satisfied the wait.
WAIT_TIMEOUT	The time-out interval elapsed and the conditions specified by the fWaitAll and dwWakeMask parameters were not satisfied.
If the function fails, the return valueis 0xFFFFFFFF. To get extended error information, call GetLastError.

Remarks

The MsgWaitForMultipleObjects function determines whether the conditions exist that satisfy the wait. If the wait is not satisfied, the calling thread enters an efficient wait state, using very little processor time while waiting for one of the conditions of the wait to be satisfied.

When fWaitAll is TRUE, the function's wait condition is satisfied only when the state of all objects is signaled at the same time. The function does not modify the state of the specified objects until all objects are simultaneously signaled. For example, a mutex can be signaled, but the thread does not get ownership until the other objects are also signaled. In the meantime, some other thread may get ownership of the mutex, thereby delaying satisfaction of the condition.

The system adjusts the state of some types of objects after the object's signaled state satisfies a wait condition. For example, the count of a semaphore object is decreased by one.

The MsgWaitForMultipleObjects function can specify handles of any of the following object types in the pHandles array:

Object	Description
Change notification	The handle is returned by the FindFirstChangeNotification function. A change notification object's state is signaled when a specified type of change occurs within a specified directory or directory tree.
Console input	The handle is returned by the CreateFile function when CONIN$ is specified, or by the GetStdHandle function. The object's state is signaled when there is unread input in the console's input buffer and it is nonsignaled when the input buffer is empty.
Event	The handle is returned by the CreateEvent or OpenEvent function. An event object's state is set explicitly to signaled by the SetEvent or PulseEvent function. A manual-reset event object's state must be reset explicitly to nonsignaled by the ResetEvent function. For an auto-reset event object, the wait function resets the object's state to nonsignaled before returning. Event objects are also used in overlapped operations, in which the state is set by the system.
Mutex	The handle is returned by the CreateMutex or OpenMutex function. A mutex object's state is signaled when it is not owned by any thread. The wait function requests ownership of the mutex for the calling thread, changing the mutex's state to nonsignaled when ownership is granted.
Process	The handle is returned by the CreateProcess or OpenProcess function. A process object's state is signaled when the process terminates.
Thread	The handle is returned by the CreateProcess, CreateThread, or CreateRemoteThread function. A thread object's state is signaled when the thread terminates.
Semaphore	The handle is returned by the CreateSemaphore or OpenSemaphore function. A semaphore object maintains a count between zero and some maximum value. Its state is signaled when its count is greater than zero and nonsignaled when its count is zero. If the current state is signaled, the wait function decreases the count by one.
In some circumstances, you can specify a handle of a file, named pipe, or communications device as a synchronization object in a wait function. However, their use for this purpose is discouraged. For more information, see Synchronization.

The following code fragment illustrates the use of MsgWaitForMultipleObjects in a main message loop that also needs to wait for one or more objects to become signaled.

int MessageLoop (

  HANDLE* lphObjects,  // handles that need to be waited on

  int     cObjects     // number of handles to wait on

  ){

  // message loop lasts until we get a WM_QUIT message

  // upon which we shall return from the function

  while (TRUE) {

    // block-local variable

    DWORD result ;

    // wait for any message sent or posted to this queue

    // or for one of the passed handles to become signaled

      result = MsgWaitForMultipleObjects(cObjects, lphObjects,

                                 FALSE, INFINITE, QS_ALLINPUT);

      // result tells us the type of event we have:

      // a message or a signaled handle

      // if there are one or more messages in the queue ...

      if (result == (WAIT_OBJECT_0 + cObjects)) {

         // block-local variable

         MSG msg ;

         // read all of the messages in this next loop

         // removing each message as we read it

         while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {

            // if it's a quit message we're out of here

            if (msg.message == WM_QUIT)  return 1;

            // otherwise dispatch it

            DispatchMessage(&msg);

         } // end of PeekMessage while loop

      } else {

         // one of the handles became signaled

         // deal with that

         DoStuff (result - WAIT_OBJECT_0) ;

      } // end of else-clause

   } // end of the always while-loop

} // end of function

See Also

CreateEvent, CreateFile, CreateMutex, CreateProcess, CreateRemoteThread, CreateSemaphore, CreateThread, FindFirstChangeNotification, GetStdHandle, OpenEvent, OpenMutex, OpenProcess, OpenSemaphore, PulseEvent, ResetEvent, SetEvent, Sleep, WaitForMultipleObjects, WaitForMultipleObjectsEx, WaitForSingleObject


MulDiv
MulDiv  QuickInfo  Overview  Group

The MulDiv function multiplies two 32-bit values and then divides the 64-bit result by a third 32-bit value. The return value is rounded up or down to the nearest integer.

int MulDiv(

int  nNumber,	// 32-bit signed multiplicand
int  nNumerator,	// 32-bit signed multiplier
int  nDenominator	// 32-bit signed divisor
);
Parameters

nNumber

Specifies the multiplicand.

nNumerator

Specifies the multiplier.

nDenominator

Specifies the number by which the result of the multiplication (nNumber * nNumerator) is to be divided.

Return Value

If the function succeeds, the return value is the result of the multiplication and division. If either an overflow occurred or nDenominator was 0, the return value is −1.

See Also

Int32x32To64, UInt32x32To64


MultiByteToWideChar
MultiByteToWideChar  QuickInfo  Overview  Group

The MultiByteToWideChar function maps a character string to a wide-character (Unicode) string. The character string mapped by this function is not necessarily from a multibyte character set.

int MultiByteToWideChar(

UINT  CodePage,	// code page
DWORD  dwFlags,	// character-type options
LPCSTR  lpMultiByteStr,	// address of string to map
int  cchMultiByte,	// number of characters in string
LPWSTR  lpWideCharStr,	// address of wide-character buffer
int  cchWideChar	// size of buffer
);
Parameters

CodePage

Specifies the code page to be used to perform the conversion. This parameter can be given the value of any codepage that is installed or available in the system. The following values may be used to specify one of the system default code pages:

Value	Meaning
CP_ACP	ANSI code page
CP_MACCP	Macintosh code page
CP_OEMCP	OEM code page
dwFlags

A set of bit flags that indicate whether to translate to precomposed or composite wide characters (if a composite form exists), whether to use glyph characters in place of control characters, and how to deal with invalid characters. You can specify a combination of the following flag constants:

Value	Meaning
MB_PRECOMPOSED	Always use precomposed characters — that is, characters in which a base character and a nonspacing character have a single character value. This is the default translation option. Cannot be used with MB_COMPOSITE.
MB_COMPOSITE	Always use composite characters — that is, characters in which a base character and a nonspacing character have different character values. Cannot be used with MB_PRECOMPOSED.
MB_ERR_INVALID_CHARS	If the function encounters an invalid input character, it fails and GetLastError returns ERROR_NO_UNICODE_TRANSLATION.
MB_USEGLYPHCHARS	Use glyph characters instead of control characters.
A composite character consists of a base character and a nonspacing character, each having different character values. A precomposed character has a single character value for a base/non-spacing character combination. In the character è, the e is the base character and the accent grave mark is the nonspacing character.

The function's default behavior is to translate to the precomposed form. If a precomposed form does not exist, the function attempts to translate to a composite form.

The flags MB_PRECOMPOSED and MB_COMPOSITE are mutually exclusive. The MB_USEGLYPHCHARS flag and the MB_ERR_INVALID_CHARS can be set regardless of the state of the other flags.

lpMultiByteStr

Points to the character string to be converted.

cchMultiByte

Specifies the size in bytes of the string pointed to by the lpMultiByteStr parameter. If this value is −1, the string is assumed to be null terminated and the length is calculated automatically.

lpWideCharStr

Points to a buffer that receives the translated string.

cchWideChar

Specifies the size, in wide characters, of the buffer pointed to by the lpWideCharStr parameter. If this value is zero, the function returns the required buffer size, in wide characters, and makes no use of the lpWideCharStr buffer.

Return Value

If the function succeeds, and cchWideChar is nonzero, the return value is the number of wide characters written to the buffer pointed to by lpWideCharStr.

If the function succeeds, and cchWideChar is zero, the return value is the required size, in wide characters, for a buffer that can receive the translated string.

If the function fails, the return value is zero. To get extended error information, call GetLastError. GetLastError may return one of the following error codes:

ERROR_INSUFFICIENT_BUFFER

ERROR_INVALID_FLAGS

ERROR_INVALID_PARAMETER

ERROR_NO_UNICODE_TRANSLATION

Remarks

The lpMultiByteStr and lpWideCharStr pointers must not be the same. If they are the same, the function fails, and GetLastError returns the value ERROR_INVALID_PARAMETER.

The function fails if MB_ERR_INVALID_CHARS is set and it encounters an invalid character in the source string.  An invalid character is one that would translate to the default character if MB_ERR_INVALID_CHARS was not set, but is not the default character in the source string, or when a lead byte is found in a string and there is no valid trail byte for DBCS strings. When an invalid character is found, and MB_ERR_INVALID_CHARS is set, the function returns 0 and sets GetLastError with the error ERROR_NO_UNICODE_TRANSLATION.

See Also

WideCharToMultiByte


NDdeGetErrorString
NDdeGetErrorString  QuickInfo  Overview  Group

The NDdeGetErrorString function is called to convert an error code returned by the NetDDE DSDM interface API into an error string explaining the reason for the returned error.

UINT NDdeGetErrorString (

UINT  uErrorCode,	// Error code to get string for
LPTSTR  lpszErrorString,	// buffer to hold error string
DWORD  cBufSize	// size of buffer
);
Parameters

uErrorCode

Error code to be converted.

lpszErrorString

Address of a buffer to accept the translated error string. Must not be NULL. If the buffer is not large enough to store the complete error string, the string will be truncated.

cBufSize

Defines the size of the buffer allocated to receive the error string.

Return Value

If the function succeeds, the return value is zero.

If the function fails, the return value is a nonzero error code. If the lpszErrorString buffer is not large enough to accept the complete error string, and the string is truncated, the function returns the value NDDE_BUF_TOO_SMALL.


NDdeGetShareSecurity
NDdeGetShareSecurity  QuickInfo  Overview  Group

The NDdeGetShareSecurity function is called to get the SECURITY_DESCRIPTOR associated with the DDE share. This is done usually for editing.

UINT NDdeGetShareSecurity(

LPTSTR  lpszServer,	// server to execute on
LPTSTR  lpszShareName,	// name of share to delete
SECURITY_INFORMATION  si,	// requested information
PSECURITY_DESCRIPTOR  pSD,	// address of SD buffer
DWORD  cbSD,	// size of SD buffer
LPDWORD  lpcbsdRequired	// address of required size for SD buffer
);
Parameters

lpszServer

Address of the server name on which the DSDM will be modified.

lpszShareName

Address of the share name whose security descriptor is to be retrieved from the DSDM. This parameter should not be NULL.

si

Identifies the SECURITY_INFORMATION to be retrieved from the SECURITY_DESCRIPTOR associated with the share.

pSD

Address of a buffer that will accept the retrieved self-relative SECURITY_DESCRIPTOR. This parameter can be NULL. If this parameter is NULL, the DSDM determines the size of the requested security information and returns the number of bytes needed in the lpcbsdRequired parameter along with the NDDE_BUF_TOO_SMALL error code.

cbSD

Specifies the size of the buffer provided and referenced by the pSD parameter to accept the retrieved security descriptor. It must be 0 if pSD is NULL.

lpcbsdRequired

Address of the variable into which the actual size of the retrieved security descriptor is stored. Must not be NULL.

Return Value

If the function succeeds, the return value is NDDE_NO_ERROR.

If the function fails, the return value is an error code, which can be translated into a text error message by calling NDdeGetErrorString. If the pSD parameter was NULL, it returns NDDE_BUF_TOO_SMALL.

See Also

SECURITY_INFORMATION


NDdeGetTrustedShare
NDdeGetTrustedShare  QuickInfo  Overview  Group

The NDdeGetTrustedShare function is called to retrieve the options associated with a currently "trusted" DDE share.

UINT NDdeGetTrustedShare (

LPTSTR  lpszServer,	// server to execute on
LPTSTR  lpszShareName,	// name of share to query
LPDWORD  lpdwTrustOptions,	// trust options in effect
LPDWORD  lpdwShareModId0,	// first word of share modify identifier
LPDWORD  lpdwShareModId1	// second word of share modify identifier
);
Parameters

lpszServer

Address of the server name on which the DSDM will be modified.

lpszShareName

Address of the share name whose trusted status is being queried. This parameter should not be NULL.

lpdwTrustOptions

Address of a variable into which the TRUST_SHARE_OPTIONS will be stored. Must not be NULL.

lpdwShareModId0

Address of a variable into which the first word of the trusted share modify identifier will be stored. Must not be NULL.

lpdwShareModId1

Address of a variable into which the second word of the trusted share modify identifier will be stored. Must not be NULL.

Return Value

If the function succeeds, the return value is NDDE_NO_ERROR.

If the function fails, the return value is an error code, which can be translated into a text error message by calling NDdeGetErrorString.

Remarks

The trusted share modify identifier reflects the version of the DDE share in the NetDDE DSDM at the time the DDE share was initially promoted to trust status. The trusted share modify identifier is primarily used to purge obsolete trusted shares. However, the user does not need to purge obsolete trusted shares. The NetDDE Agent purges obsolete shares on the user's behalf.


NDdeIsValidAppTopicList
NDdeIsValidAppTopicList  QuickInfo  Overview  Group

The NDdeIsValidAppTopicList function is called to validate an application and topic string ("AppName|TopicName") for proper syntax.

BOOL NDdeIsValidAppTopicList (

LPTSTR targetTopic	// points to app and topic string
);
Parameters

targetTopic

Address of the application and topic string  to validate. Must not be NULL.

Return Value

If targetTopic has valid syntax, the return value is TRUE.

If the function fails, the return value is FALSE.


NDdeIsValidShareName
NDdeIsValidShareName  QuickInfo  Overview  Group

The NDdeIsValidShareName function is called to validate a share name for proper syntax.

BOOL NDdeIsValidShareName (

LPTSTR  shareName	// points to share name to validate
);
Parameters

shareName

Address of a share name to validate. Must not be NULL.

Return Value

If the share name has valid syntax, the return value is TRUE.

If the function fails, the return value is FALSE.


NDdeSetShareSecurity
NDdeSetShareSecurity  QuickInfo  Overview  Group

The NDdeSetShareSecurity function is called to set the SECURITY_DESCRIPTOR associated with the DDE share. This is done usually after editing the DACL assigned to the DDE share.

UINT NDdeSetShareSecurity(

LPTSTR  lpszServer,	// server to execute on
LPTSTR  lpszShareName,	// name of share to delete
SECURITY_INFORMATION  si,	// type of information
PSECURITY_DESCRIPTOR  pSD	// address of security descriptor to set
);
Parameters

lpszServer

Address of the server name on which the DSDM will be modified.

lpszShareName

Address of the share name whose security descriptor is to be modified in the DSDM. This parameter should not be NULL.

si

Specifies a SECURITY_INFORMATION structure identifying the contents of the security descriptor pointed to by the pSD parameter.

pSD

Address of the SECURITY_DESCRIPTOR that will be the source of the security information modified in the DDE share. This parameter must not be NULL and should point to a valid security descriptor.

Return Value

If the function succeeds, the return value is NDDE_NO_ERROR.

If the function fails, the return value is an error code, which can be translated into a text error message by calling NDdeGetErrorString.

Remarks

To modify the SECURITY_DESCRIPTOR associated with a DDE share in the DSDM, the user must have appropriate privileges; for example, the share creator has such rights.

See Also

SECURITY_INFORMATION


NDdeSetTrustedShare
NDdeSetTrustedShare  QuickInfo  Overview  Group

The NDdeSetTrustedShare function is called to promote the referenced DDE share to trusted status within the current user's context.

UINT NDdeSetTrustedShare (

LPTSTR  lpszServer,	// server to execute on
LPTSTR  lpszShareName,	// name of share to delete
DWORD  dwTrustOptions	// trust options to apply
);
Parameters

lpszServer

Address of the server name on which the DSDM will be modified.

lpszShareName

Address of the share name being promoted to trusted status. This parameter should not be NULL.

dwTrustOptions

Specifies the options affecting the trusted status of the DDE share. The following TRUST_SHARE_OPTIONS options are available:

Option	Meaning
NDDE_TRUST_SHARE_START	Allow the application to be started in the user's context.
NDDE_TRUST_SHARE_INIT	Allow a client to initiate to the application if it is already running in the user's context.
NDDE_TRUST_SHARE_DEL	Remove the share's trusted status.
NDDE_TRUST_CMD_SHOW	Start the application with CmdShow field defined here overriding the CmdShow specified in the DDE share DSDM.
NDDE_CMD_SHOW_MASK	CmdShow value used to override the DDE share CmdShow if the NDDE_TRUST_CMD_SHOW is set.
Return Value

If the function succeeds, the return value is NDDE_NO_ERROR.

If the function fails, the return value is an error code, which can be translated into a text error message by calling NDdeGetErrorString.

Remarks

If NDdeSetTrustedShare is called with dwTrustOptions set to 0, the trusted share loses its trusted status.


NDdeShareAdd
NDdeShareAdd  QuickInfo  Overview  Group

The NDdeShareAdd function is called to create and add a new DDE share to the NetDDE Share Database Manager (DSDM).

UINT NDdeShareAdd (

LPTSTR  lpszServer,	// server to execute on
UINT  nLevel,	// info level must be 2
PSECURITY_DESCRIPTOR  pSD,	// initial security descriptor
LPBYTE  lpBuffer,	// address of NDDESHAREINFO
DWORD  cBufSize	// size of supplied buffer
);
Parameters

lpszServer

Address of the server name on which the DSDM will be modified.

nLevel

Must always be 2.

pSD

Address of the SECURITY_DESCRIPTOR that will be associated with this share and against which access checks will be performed on subsequent initiates to this share. This parameter can optionally be NULL, in which case the DSDM creates a default SECURITY_DESCRIPTOR that grants "Full Control" to the CREATOR_OWNER and "Read and Link" to everyone.

lpBuffer

Address of the NDDESHAREINFO structure that defines the ApplicationTopic list associated with the DDE share being created as well as other parameters. This parameter must not be NULL.

cBufSize

Size of the structure identified by lpBuffer. It must not be 0.

Return Value

If the function succeeds, the return value is NDDE_NO_ERROR.

If the function fails, the return value is an error code, which can be translated into a text error message by calling NDdeGetErrorString.

See Also

NDDESHAREINFO


NDdeShareDel
NDdeShareDel  QuickInfo  Overview  Group

The NDdeShareDel function is called to delete a DDE share from the NetDDE DSDM.

UINT NDdeShareDel (

LPTSTR  lpszServer,	// server to execute on
LPTSTR  lpszShareName,	// name of share to delete
UINT  wReserved	// must be 0
);
Parameters

lpszServer

Address of the server name on which the DSDM will be modified.

lpszShareName

Address of the share name that is to be deleted from the DSDM. This parameter should not be NULL.

wReserved

Must be 0.

Return Value

If the function succeeds, the return value is NDDE_NO_ERROR.

If the function fails, the return value is an error code which can be translated into a text error message by calling NDdeGetErrorString.

Remarks

To delete a DDE share from the DSDM, the user must have appropriate privileges. The share creator has delete rights.


NDdeShareEnum
NDdeShareEnum  QuickInfo  Overview  Group

The NDdeShareEnum function is called to list the available DDE shares in the NetDDE DSDM.

UINT NDdeShareEnum (

LPTSTR  lpszServer,	// server to execute on
UINT  nLevel,	// must be 0
LPBYTE  lpBuffer,	// pointer to buffer
DWORD  cBufSize,	// size of buffer
LPDWORD  lpnEntriesRead,	// number of names returned
LPDWORD  lpcbTotalAvailable	// number of bytes available
);
Parameters

lpszServer

Address of the server name on which the DSDM will be modified.

nLevel

Must be 0.

lpBuffer

Address of a buffer supplied to accept the list of DDE shares. The list of DDE shares is stored as a sequence of null-separated strings terminating with a double null at the end. This parameter can be NULL. If lpBuffer is NULL, the DSDM returns the size of buffer required to hold the list of shares in the lpcbTotalAvailable field.

cBufSize

Specifies the size of the supplied buffer addressed by lpBuffer. Must be 0 if lpBuffer is NULL.

lpnEntriesRead

Address of a variable to receive the total number of shares being enumerated. Must not be NULL.

lpcbTotalAvailable

Address of a variable to receive the total number of bytes needed in the buffer to store the list of DDE shares. Must not be NULL.

Return Value

If the function succeeds, the return value is NDDE_NO_ERROR.

If the function fails, the return value is an error code, which can be translated into a text error message by calling NDdeGetErrorString. If the lpBuffer parameter is NULL, it returns NDDE_BUF_TOO_SMALL.


NDdeShareGetInfo
NDdeShareGetInfo  QuickInfo  Overview  Group

The NDdeShareGetInfo function is called to retrieve DDE share information from the NetDDE DSDM. This is usually done for editing.

UINT NDdeShareGetInfo (

LPTSTR  lpszServer,	// server to execute on
LPTSTR  lpszShareName,	// name of share
UINT  nLevel,	// info level must be 2
LPBYTE  lpBuffer,	// contains (NDDESHAREINFO) + data
DWORD  cBufSize,	// size of buffer
LPDWORD  lpnTotalAvailable,	// number of bytes available
LPWORD  lpnItems	// item mask for partial getinfo
);
Parameters

lpszServer

Address of the server name on which the DSDM will be modified.

lpszShareName

Address of the share name whose information is to be retrieved from the DSDM. This parameter should not be NULL.

nLevel

Must be 2.

lpBuffer

Address of a buffer that is to accept the NDDESHAREINFO structure and associated data pointed to by NDDESHAREINFO pointer fields. This field can be NULL. If lpBuffer is NULL, then the DSDM calculates the number of bytes required to store the requested share information and returns that value in the lpnTotalAvailable field along with the NDDE_BUF_TOO_SMALL error.

cBufSize

Defines the size of the buffer addressed by the lpBuffer field. If lpBuffer is NULL, then cBufSize should be 0.

lpnTotalAvailable

Address of a varaible that receives the count of the total number of bytes needed to store the requested share information. Must not be NULL.

lpnItems

Address of an item selection mask for partial share information retrieval. For the first release of Windows NT, the item selection mask must be 0.

Return Value

If the function succeeds, the return value is NDDE_NO_ERROR.

If the function fails, the return value is an error code, which can be translated into a text error message by calling NDdeGetErrorString. If the lpBuffer parameter is NULL, it returns NDDE_BUF_TOO_SMALL.

See Also

NDDESHAREINFO structure


NDdeShareSetInfo
NDdeShareSetInfo  QuickInfo  Overview  Group

The NDdeShareSetInfo function is called to modify DDE share information stored in the NetDDE DSDM. This is usually done after editing.

UINT NDdeShareSetInfo (

LPTSTR  lpszServer,	// server to execute on
LPTSTR  lpszShareName,	// name of share
UINT  nLevel,	// information level must be 2
LPBYTE  lpBuffer,	// address of NDDESHAREINFO
DWORD  cBufSize,	// size of buffer
WORD  sParmNum	// parameter index
);
Parameters

lpszServer

Address of the server name on which the DSDM will be modified.

lpszShareName

Address of the share name whose information is to be modified in the DSDM. This parameter should not be NULL.

nLevel

Must be 2.

lpBuffer

Address of the NDDESHAREINFO structure that defines the new DDE share information to be stored in the DSDM. Currently the DDE share information is modified as a whole, that is, no partial edits are made. Must not be NULL.

cBufSize

Size of the DDE share information addressed by lpBuffer.

sParmNum

Parameter index being modified. Current implementation does not support partial modification and, hence, it must be 0.

Return Value

If the function succeeds, the return value is NDDE_NO_ERROR.

If the function fails, the return value is an error code, which can be translated into a text error message by calling NDdeGetErrorString.

See Also

NDDESHAREINFO


NDdeTrustedShareEnum
NDdeTrustedShareEnum  QuickInfo  Overview  Group

The NDdeTrustedShareEnumfunction lists the names of all network DDE shares that are trusted in the context of the calling process.

UINT NDdeTrustedShareEnum (

LPTSTR  lpszServer,	// server to execute on
UINT  nLevel,	// must be 0
LPBYTE  lpBuffer,	// pointer to buffer
DWORD  cBufSize,	// size of buffer
LPDWORD  lpnEntriesRead,	// number of names returned
LPDWORD  lpcbTotalAvailable	// number of bytes available
);
Parameters

lpszServer

Address of the server name on which the DSDM will be modified.

nLevel

Must be 0.

lpBuffer

Address of a buffer supplied to accept the list of trusted DDE shares. The list of trusted DDE shares is stored as a sequence of null-separated strings terminating with a double null at the end. This parameter can be NULL. If the lpBuffer is NULL, the DSDM returns the size of buffer required to hold the list of shares in the lpcbTotalAvailable field.

cBufSize

Specifies the size of the supplied buffer addressed by lpBuffer. Must be 0 if lpBuffer is NULL.

lpnEntriesRead

Address of a variable to receive the total number of trusted shares being enumerated. Must not be NULL.

lpcbTotalAvailable

Address of a variable to receive the total number of bytes needed in the buffer to store the list of trusted DDE shares. Must not be NULL.

Return Value

If the function succeeds, the return value is NDDE_NO_ERROR.

If the function fails, the return value is an error code, which can be translated into a text error message by calling NDdeGetErrorString. If the lpBuffer parameter is NULL, it returns NDDE_BUF_TOO_SMALL.


NetAccessAdd
NetAccessAdd  QuickInfo

Note  The NetAccessAdd function works only when remoted to a downlevel system. Use Win32 (GetFileSecurity, SetFileSecurity) functions for Windows NT.

NetAccessAdd creates a new Access Control List (ACL) for a resource.

Security Requirements

Admin group membership is required to successfully execute NetAccessAdd.

NET_API_STATUS
NetAccessAdd (

LPTSTR servername,
DWORD level,
LPBYTE buf,
LPDWORD parm_err
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

level

Level of information provided. Must be 1.

buf

A pointer to a buffer containing the access information structure.

parm_err

Optional pointer to a DWORD to return the index of the first parameter in error when ERROR_INVALID_PARAMETER is returned. If NULL the parameter is not returned on error.


NetAccessCheck
NetAccessCheck  QuickInfo

Note  The NetAccessCheck function works only when remoted to a downlevel system. Use Win32 (AccessCheck) function for Windows NT.

NetAccessCheck verifies that a user has permission to perform a specified operation on a particular resource.

Security Requirements

Admin group membership is required to successfully execute NetAccessCheck.

NET_API_STATUS
NetAccessCheck (

LPWSTR servername,
LPWSTR username,
LPWSTR resource,
DWORD operation,
LPDWORD result
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

username

A pointer to a Unicode string containing the name of the user to check for access to the resource.

resource

A pointer to a Unicode string containing the resource for which to check user permissions.

operation

Points to a DWORD specifying the type of access operation requested.

Symbolic constant	Value	Meaning
ACCESS_READ	0x01	Permission to read data from a resource and, by default, execute the resource.
ACCESS_WRITE	0x02	Permission to write data to the resource.
ACCESS_CREATE	0x04	Permission to create an instance of the resource (for example, a file); data can be written to the resource when creating it.
ACCESS_EXEC	0x08	Permission to execute the resource.
ACCESS_DELETE	0x10	Permission to delete the resource.
ACCESS_ATRIB	0x20	Permission to modify the resource's attributes (for example, the date and time a file was last modified).
ACCESS_PERM	0x40	Permission to modify the permissions (read, write, create, execute, and delete) assigned to a resource for a user, group, or application.
ACCESS_ALL	0x7F	Permission to read, write, create,execute, or delete a resource, or to modify attributes or permissions in which the user permissions for the specified resource are returned.
result

Points to a DWORD in which the result of the access check is returned.


NetAccessDel
NetAccessDel  QuickInfo

Note  The NetAccessDel function works only when remoted to a downlevel system. Use Win32 (GetFileSecurity, SetFileSecurity) functions for Windows NT.

NetAccessDel deletes the access control list for a particular resource.

Security Requirements

Admin group membership or P permission for the resource is required to successfully execute NetAccessDel.

NET_API_STATUS
NetAccessDel (

LPTSTR servername,
LPTSTR resource
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

resource

A pointer to a Unicode string containing the name of the resource for which to remove the access control entry.


NetAccessEnum
NetAccessEnum  QuickInfo

Note  The NetAccessEnum function works only when remoted to a downlevel system. Use Win32 (GetFileSecurity, SetFileSecurity) functions for Windows NT.

NetAccessEnum retrieves information about each access permision record.

NetAccessEnum is being phased out and is available only at levels 0 and 1 for Windows networking. It is recommended that NetAccessEnum not be used because it is unlikely to be supported in future releases.

Security Requirements

NetAccessEnum does not require admin group membership to execute but will return only records for entries for which the user has 'P' permission if the caller does not have admin group membership.

NET_API_STATUS
NetAccessEnum (

LPTSTR servername,
LPTSTR BasePath,
DWORD Recursive,
DWORD level,
LPBYTE * bufptr,
DWORD prefmaxlen,
LPDWORD entriesread,
LPDWORD totalentries,
LPDWORD resume_handle
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

BasePath

A pointer to a Unicode string that contains a base path for the resources. A NULL pointer or NULL string means no base path is to be used. The path can be specified as a universal naming convention (UNC) path.

Recursive

A flag to enables or disable recursive searching. If Recursive is 0, NetAccessEnum returns entries only for the resource named as the base path by BasePath and for the resources directly below that base path. If Recursive is nonzero, NetAccessEnum returns entries for all access control lists (ACLs) that have BasePath at the beginning of the resource name.

level

Level of information required. Only 0 and 1 are valid.

bufptr

On return a pointer to the return information structure is returned in the address pointed to by bufptr.

prefmaxlen

Preferred maximum length of returned data (in 8-bit bytes).

entriesread

On return the actual enumerated element count is located in the DWORD pointed to by entriesread.

totalentries

On return the total number of entries that could have been enumerated from the current resume position is located in the DWORD pointed to by totalentries.

resume_handle

On return, a resume handle is stored in the DWORD pointed to by resume_handle, and is used to continue an existing access search. The handle should be zero on the first call and left unchanged for subsequent calls. If resume_handle is NULL, then no resume handle is stored.


NetAccessGetInfo
NetAccessGetInfo  QuickInfo

Note  The NetAccessGetInfo function works only when remoted to a downlevel system. Use Win32 (GetFileSecurity, SetFileSecurity) functions for Windows NT.

NetAccessGetInfo retrieves the access control information for a specific resource.

Security Requirements

Admin group membership or P permission is required to successfully execute NetAccessGetInfo.

NET_API_STATUS
NetAccessGetInfo (

LPTSTR servername,
LPTSTR resource,
DWORD level,
LPBYTE * bufptr
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

resource

A pointer to a Unicode string containing the name of the resource on which to return access control information.

level

Level of information required. 0 and 1 are valid.

bufptr

A pointer to the return information structure is returned in the address pointed to by bufptr.


NetAccessGetUserPerms
NetAccessGetUserPerms  QuickInfo

Note  The NetAccessGetUserPerms function works only when remoted to a downlevel system. Use Win32 (GetFileSecurity, SetFileSecurity) functions for Windows NT.

NetAccessGetUserPerms returns a specified user's or group's access permissions for a particular resource.

Security Requirements

Admin group membership or P permission for the resource is required to successfully execute NetAccessGetUserPerms.except when users request their own access permissions to a resource. In this case no special group membership is required.

NET_API_STATUS
NetAccessGetUserPerms (

LPTSTR servername,
LPTSTR UGname,
LPTSTR resource,
LPDWORD Perms
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

UGname

A pointer to a Unicode string containing the name of the user or group to query permissions for.

resource

A pointer to a Unicode string containing the resource for which to query user permissions.

Perms

Points to a DWORD in which the user permissions for the specified resource are returned.


NetAccessSetInfo
NetAccessSetInfo  QuickInfo

Note  The NetAccessSetInfo functions works only when remoted to a downlevel system. Use Win32 (GetFileSecurity, SetFileSecurity) functions for Windows NT.

NetAccessSetInfo changes the access control list for a resource.

Security Requirements

Admin group membership or P permission for the resource is required to successfully execute NetAccessSetInfo.

NET_API_STATUS
NetAccessSetInfo (

LPTSTR servername,
LPTSTR resource,
DWORD level,
LPBYTE buf,
LPDWORD parm_err
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

resource

A pointer to a Unicode string containing the name of the resource for which the access information should be changed.

level

Level of information to set. Only 1 and 1002 are valid.

buf

A pointer to a buffer containing the access entry information.

parm_err

Optional pointer to a DWORD to return the index of the first parameter in error when ERROR_INVALID_PARAMETER is returned. If NULL the parameter is not returned on error.


NetAlertRaise
NetAlertRaise  QuickInfo

NetAlertRaise notifies all registered clients that a particular event occurred.

Security Requirements

No special group membership is required to successfully execute NetAlertRaise.

NET_API_STATUS
NetAlertRaise (

LPTSTR AlertEventName,
LPVOID Buffer,
DWORD BufferSize
);
Parameters

AlertEventName

Points to a Unicode string that specifies which type of alert to raise.

Buffer

Points to the data to be sent to the clients listening for this alert. The data should consist of the STD_ALERT data structure followed by any additional alert data.

BufferSize

Specifies the size of the buffer in bytes.


NetAlertRaiseEx
NetAlertRaiseEx  QuickInfo

NetAlertRaiseEx simplifies the raising of an admin alert.

Security Requirements

No special group membership is required to successfully execute NetAlertRaiseEx.

NET_API_STATUS
NetAlertRaiseEx (

LPTSTR AlertEventName,
LPVOID VariableInfo,
DWORD VariableInfoSize,
LPTSTR ServiceName
);
Parameters

AlertEventName

Points to a Unicode string that specifies which type of alert to raise.

VariableInfo

Information to put into the admin alert.

VariableInfoSize

Number of bytes of variable information.

ServiceName

Name of the service raising the admin alert.


NetApiBufferAllocate
NetApiBufferAllocate  QuickInfo

NetApiBufferAllocate allocates ByteCount bytes of memory from the heap.

NET_API_STATUS
NetApiBufferAllocate (

DWORD ByteCount,
LPVOID * Buffer
);
Parameters

ByteCount

The number of bytes to allocate.

buffer

A pointer to the location to store the pointer to the allocated buffer.


NetApiBufferFree
NetApiBufferFree  QuickInfo

NetApiBufferFree frees the memory allocated by NetApiBufferAllocate.

NET_API_STATUS
NetApiBufferFree (

LPVOID Buffer
);
Parameters

Buffer

A pointer to an API information buffer previously returned on an function call.


NetApiBufferReallocate
NetApiBufferReallocate  QuickInfo

NetApiBufferReallocate changes the size of a buffer allocated with NetApiBufferAllocate.

NET_API_STATUS
NetApiBufferReallocate (

LPVOID OldBuffer,
DWORD NewByteCount,
LPVOID NewBuffer
);
Parameters

OldBuffer

A pointer to the buffer to reallocate.

NewByteCount

The new size of the buffer.

NewBuffer

A pointer to an API information buffer previously returned on an function call.


NetApiBufferSize
NetApiBufferSize  QuickInfo

NetApiBufferSize returns the size in bytes of the buffer allocated via NetApiBufferAllocate.

NET_API_STATUS
NetApiBufferSize (

LPVOID buffer,
DWORD ByteCount
);
Parameters

buffer

A pointer to an API information buffer previously returned on an function call.

ByteCount

The size of the buffer.


NetAuditClear
NetAuditClear  QuickInfo

NetAuditClear clears the audit log on a server and, optionally, saves the entries in a backup file.

Security Requirements

Admin group membership is required to successfully execute NetAuditClear.

NET_API_STATUS
NetAuditClear (

LPTSTR server,
LPTSTR backupfile ,
LPTSTR service
);
Parameters

server

Points to a Unicode string that contains the name of the server on which to execute NetAuditClear. A NULL pointer or NULL string specifies the local computer.

backupfile

Points to a Unicode string that contains a name for the optional backup file. The calling application must have create and write permissions for the path specified by backupfile, and the path must already exist. A NULL pointer specifies not to back up the audit log.

service

Points to a Unicode string that contains the name of the service that owns the desired audit log to which the operation is to be performed.


NetAuditRead
NetAuditRead  QuickInfo

NetAuditRead reads from the audit log on a server.

Security Requirements

Admin or accounts, comm, print, or server operator group membership is required to successfully execute NetAuditRead.

NET_API_STATUS
NetAuditRead (

LPTSTR server,
LPTSTR service,
LPHLOG auditloghandle,
DWORD offset,
LPDWORD reserved1,
DWORD reserved2,
DWORD offsetflag,
LPBYTE * bufptr,
DWORD prefmaxlen,
LPDWORD bytesread,
LPDWORD totalavailable
);
Parameters

server

Points to a Unicode string that contains the name of the server on which to execute NetAuditRead. A NULL pointer or NULL string specifies the local computer.

service

Points to a Unicode string that contains the name of the service that owns the desired audit log to which the operation is to be performed.

auditloghandle

Points to the handle for the audit log. An application calling NetAuditRead for the first time must initialize the audit log handle as follows. The most significant bit (MSB) is the leftmost bit; the least significant bit (LSB) is the rightmost bit. After the first call, each call to NetAuditRead must be given the value for the handle returned by the previous call.

auditloghandle	Value	xxx
4.19.2.1	(MSB) − 64	0
4.19.2.2	− 0 (LSB)	1
offset

Specifies the record offset at which to begin reading. This parameter is ignored unless bit 1 in the offsetflag parameter is set. If offsetflag bit 1 is set, offset is taken as an offset based on the record number (not bytes) at which the returned data should begin. Note that the record offset parameter is zero-based from both directions, depending upon the direction of the read. If reading backward, record 0 is the last record in the log. If reading forward, record 0 is the first record in the log.

reserved1

Reserved. Must be NULL.

reserved2

Reserved. Must be zero.

offsetflag

Specifies the open flags, as follows:

Bit(s)	Meaning
4.19.2.3	If 0, the log is read forward. If 1, the log is read backward and records are returned in the buffer in reverse chronological order (newest records first).
4.19.2.4	If 0, reading proceeds sequentially. If 1, reading proceeds from the nth record from the start of the log, where n is the offset parameter.
4.19.2.5	Reserved; must be 0.
bufptr

On return a pointer to the returned information is returned in the address pointed to by bufptr. After a successful read operation, this buffer contains a sequence of audit entries with the accompanying variable-length data structures.

prefmaxlen

Preferred maximum length of returned data (in 8-bit bytes).

bytesread

On return the actual number of bytes read into the buffer is located in the DWORD pointed to by bytesread.

totalavailable

On return the total bytes available to be read from the log is located in the DWORD pointed to by totalavailable.


Netbios
Netbios  QuickInfo  Overview  Group

The Netbios function interprets and executes the specified network control block (NCB).

UCHAR Netbios(

PNCB  pncb	// address of network control block
);
Parameters

pncb

Points to an NCB structure describing the network control block to process.

Return Value

For synchronous requests, the return value is the return code of the NCB structure. That value is also returned in the ncb_retcode member of the NCB structure.

There are two return value possibilities for accepted asynchronous requests. If the asynchronous command has already completed when Netbios returns to its caller, the return value is the return code of the NCB structure, just as if it were a synchronous NCB structure. If the asynchronous command is still pending when Netbios returns to its caller, the return value is zero.

If the address specified by the pncb parameter is invalid, the return value is NRC_BADNCB.

Remarks

Netbios is primarily for applications written for the IBM NetBIOS system that need to be ported to Windows. Applications that do not have this requirement typically use other interfaces, such as mailslots and named pipes, instead of Netbios.

Netbios contains extensions to the standard IBM NetBIOS 3.0 specification to allow POST routines to be called from C and to operate efficiently in the Windows environment.

When an asynchronous network control block finishes and the ncb_post member is nonzero, the routine specified in ncb_post is called with a single parameter of type PNCB. This parameter contains the address of the finishing network control block. (In the standard IBM NetBIOS 3.0, the address of the network control block is supplied in a nonportable interface.)

Another extension to the NCB structure is a handle of an event (the ncb_event member). The event is set to the nonsignaled state by the system when an asynchronous NetBIOS command is accepted, and it is set to the signaled state when the asynchronous NetBIOS command finishes.

Using ncb_event to submit asynchronous requests requires fewer system resources than using ncb_post. Also, when ncb_event is nonzero, the pending request is canceled if the thread terminates before the request is processed. This is not true for requests sent by using ncb_post.

Only manual reset events should be used with Netbios. A specified event should not be associated with more than one active asynchronous NetBIOS command.

See Also

NCB


NetConfigGet
NetConfigGet  QuickInfo

NetConfigGet retrieves the value of a single specified entry for a particular component on the local computer or on a remote server.

Security Requirements

Admin or accounts, comm, print, or server operator group membership is required to successfully execute NetConfigGet on a remote server.

NET_API_STATUS
NetConfigGet (

LPTSTR server,
LPTSTR component,
LPTSTR parameter,
LPBYTE * bufptr
);
Parameters

server

Points to a Unicode string that contains the name of the server on which to execute NetConfigGet. A NULL pointer or NULL string specifies the local computer.

component

Points to a Unicode string that specifies which configuration component to search.

parameter

Points to a Unicode string that specifies the entry for the component specified whose value is to be returned.

bufptr

On return a pointer to the returned information is returned in the address pointed to by bufptr.


NetConfigGetAll
NetConfigGetAll  QuickInfo

NetConfigGetAll retrieves all the configuration information for a given component on a local or a remote computer.

Security Requirements

Admin or account, comm, print, or server operator group membership is required to successfully execute NetConfigGetAll on a remote server.

NET_API_STATUS
NetConfigGetAll (

LPTSTR server,
LPTSTR component,
LPBYTE * bufptr
);
Parameters

server

Points to a Unicode string that contains the name of the server on which to execute NetConfigGet. A NULL pointer or NULL string specifies the local computer.

component

Points to a Unicode string that specifies which configuration component to search.

bufptr

On return a pointer to the returned information is returned in the address pointed to by bufptr.


NetConfigSet
NetConfigSet  QuickInfo

NetConfigSet sets the value of a single specified entry for a particular component on the local computer or on a remote server.

Security Requirements

Admin or server operator group membership is required to successfully execute NetConfigSet on a remote server.

NET_API_STATUS
NetConfigSet (

LPTSTR server,
LPTSTR reserved1,
LPTSTR component,
DWORD level,
DWORD reserved2,
LPBYTE buf,
DWORD reserved3
);
Parameters

server

Points to a Unicode string that contains the name of the server on which to execute NetConfigSet. A NULL pointer or NULL string specifies the local computer.

reserved1

Reserved. Must be NULL.

component

Points to a Unicode string that specifies which configuration component to set.

level

Information level of request. Must be zero.

reserved2

Reserved. Must be zero.

buf

Buffer containing a CONFIG_INFO_0 structure.

reserved3

Reserved. Must be zero.


NetConnectionEnum
NetConnectionEnum  QuickInfo

NetConnectionEnum lists all connections made to a shared resource on the server or all connections established from a particular computer. If there is more than one user using this connection, then it is possible to get more than one structure for the same connection, but with a different user name. The NetConnectionEnum function is obsolete. It is provided only for compatibility with LAN Manager and 16-bit versions of Windows. Win32-based applications should use the WNetEnumResource function.

Security Requirements

Admin or server, print, or comm operator group membership is required to successfully execute NetConnectionEnum.

NET_API_STATUS
NetConnectionEnum (

LPTSTR servername,
LPTSTR qualifier,
DWORD level,
LPBYTE * bufptr,
DWORD prefmaxlen,
LPDWORD entriesread,
LPDWORD totalentries,
LPDWORD resumehandle
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

qualifier

A pointer to a Unicode string containing a share name or computer name for the connections of interest. If it is a share name, then all the connections made to that share name are listed. If it is a computer name (for example, it starts with two backslash characters), then NetConnectionEnum lists all connections made from that computer to the server specified.

level

Level of information required. 0 and 1 are valid.

bufptr

On return a pointer to the return information structure is returned in the address pointed to by bufptr.

prefmaxlen

Prefered maximum length of returned data (in 8-bit bytes).

entriesread

On return the actual enumerated element count is located in the DWORD pointed to by entriesread.

totalentries

On return the total number of entries that could have been enumerated from the current resume position is located in the DWORD pointed to by totalentries.

resume_handle

On return, a resume handle is stored in the DWORD pointed to by resume_handle, and is used to continue an existing connection search. The handle should be zero on the first call and left unchanged for subsequent calls. If resume_handle is NULL, then no resume handle is stored.


NetErrorLogClear
NetErrorLogClear  QuickInfo

NetErrorLogClear clears the error log and optionally saves the entries in a backup file.

Security Requirements

Admin group membership is required to successfully execute NetErrorLogClear on a remote server.

NET_API_STATUS
NetErrorLogClear (

LPTSTR server,
LPTSTR backupfile,
LPBYTE reserved
);
Parameters

server

Points to a Unicode string that contains the name of the server on which to execute NetErrorLogClear. A NULL pointer or NULL string specifies the local computer.

backupfile

Points to a Unicode string that assigns a name for an optional backup file. The calling application must have write permission for the path specified by backupfile. A NULL pointer indicates not to back up the error log.

reserved

Reserved. Must be NULL.


NetErrorLogRead
NetErrorLogRead  QuickInfo

NetErrorLogRead reads from the specified error log.

Security Requirements

No special group membership is required to successfully execute NetErrorLogRead.

NET_API_STATUS
NetErrorLogRead (

LPTSTR server,
LPTSTR reserved1,
LPHLOG errloghandle,
DWORD offset,
LPDWORD reserved2,
DWORD reserved3,
DWORD offsetflag,
LPBYTE * bufptr,
DWORD prefmaxlen,
LPDWORD bytesread,
LPDWORD totalbytes
);
Parameters

server

Points to a Unicode string that contains the name of the server on which to execute NetErrorLogClear. A NULL pointer or NULL string specifies the local computer.

reserved1

Reserved. Must be NULL.

errloghandle

Points to the error log handle. An application calling NetErrorLogRead for the first time must initialize the 128-bit error log handle.

offset

Specifies the record offset at which to begin reading. This parameter is ignored unless bit 1 of offsetflag is set. If used, offset is taken as an offset of the record number (not bytes) at which to begin reading. Note that the record offset parameter is zero-based from both directions, depending upon the direction it is read.

reserved2

Reserved. Must be NULL.

reserved3

Reserved. Must be zero.

offsetflag

Specifies the open flags, bitmapped as follows:

Bit(s)	Value
4.16.2.1	If 0, the log is read forward. If 1, the log is read backward and records are returned in reverse chronological order.
4.16.2.2	If 0, the read proceeds normally (sequentially). If 1, the read proceeds from the nth record from the start of the log, where n is the offset parameter.
4.16.2.3	Reserved; must be 0.
bufptr

On return a pointer to the return information buffer is returned in the address pointed to by bufptr.

prefmaxlen

Preferred maximum length of returned data (in 8-bit bytes).

bytesread

On return the actual number of bytes read into the buffer is located in the DWORD pointed to by bytesread.

totalbytes

On return the total bytes available to be read from the log is located in the DWORD pointed to by totalbytes.


NetFileClose
NetFileClose  QuickInfo

NetFileClose forces a resource to close. This function can be used when an error prevents closure by other means.

Security Requirements

Admin or server operator group membership is required to successfully execute NetFileClose.

NET_API_STATUS
NetFileClose (

LPTSTR servername,
DWORD fileid
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

fileid

The file identifier of the opened resource instance to be closed.


NetFileEnum
NetFileEnum  QuickInfo

NetFileEnum supplies information about some or all open files on a server, allowing the user to supply a resume handle and get required information through repeated calls to the function.

Security Requirements

Admin or server operator group membership is required to successfully execute NetFileEnum.

NET_API_STATUS
NetFileEnum (

LPTSTR servername,
LPTSTR basepath,
LPTSTR username,
DWORD level,
LPBYTE * bufptr,
DWORD prefmaxlen,
LPDWORD entriesread,
LPDWORD totalentries,
LPDWORD resume_handle
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

basepath

A pointer to a Unicode string containing a qualifier for the returned information. If NULL then all open resources are enumerated, else only resources that have basepath as a prefix are enumerated. A prefix is the path component up to a back-slash.

username

A pointer to a Unicode string that specifies the name of the user. If not NULL, username serves as a qualifier to the enumeration. The files returned are limited to those that have user names matching the qualifier. If username is NULL, no user-name qualifier is used.

level

Level of information required. 2 and 3 are valid.

bufptr

On return a pointer to the return information structure is returned in the address pointed to by bufptr.

prefmaxlen

Prefered maximum length of returned data (in 8-bit bytes).

entriesread

On return the actual enumerated element count is located in the DWORD pointed to by entriesread.

totalentries

On return the total number of entries that could have been enumerated from the current resume position is located in the DWORD pointed to by totalentries.

resume_handle

On return, a resume handle is stored in the DWORD pointed to by resume_handle, and is used to continue an existing file search. The handle should be zero on the first call and left unchanged for subsequent calls. If resume_handle is NULL, then no resume handle is stored.


NetFileGetInfo
NetFileGetInfo  QuickInfo

NetFileGetInfo retrieves information about a particular opening of a server resource.

Security Requirements

Admin or server operator group membership is required to successfully execute NetFileGetInfo.

NET_API_STATUS
NetFileGetInfo (

LPTSTR servername,
DWORD fileid,
DWORD level,
LPBYTE * bufptr
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

fileid

The file identifier of the open resource to return information on. The fileid value must be that returned in a previous enumeration call.

level

Level of information required. 2 and 3 are valid.

bufptr

On return a pointer to the return information structure is returned in the address pointed to by bufptr.


NetGetDCName
NetGetDCName  QuickInfo

NetGetDCName returns the name of the Primary Domain Controller for the specified domain.

Security Requirements

No special group membership is required to successfully execute NetGetDCName.

NET_API_STATUS
NetGetDCName (

LPWSTR servername,
LPWSTR domainname,
LPBYTE * bufptr
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

domainname

A pointer to a Unicode string containing the name of the domain. A NULL pointer or string indicates that the name of the domain controller for the primary domain is to be returned.

bufptr

A pointer to the buffer containing the domain controller name is returned in the address pointed to by bufptr.


NetGetDisplayInformationIndex

The NetGetDisplayInformationIndex function gets the index of the first display information entry whose name begins with or alphabetically follows a specified string. You can use this function to determine a starting index for subsequent calls to the NetQueryDisplayInformation function.

Security Requirements

No special group membership is required to successfully execute NetGetDisplayInformationIndex.

NET_API_STATUS
NetGetDisplayInformationIndex (

LPWSTR   ServerName,	// pointer to name of server to get information from
DWORD    Level,	// level of information to retrieve
LPWSTR   Prefix,	// pointer to prefix string
LPDWORD  Index	// receives index of entry
);
Parameters

ServerName

Points to a null-terminated Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

Level

Specifies one of the following values to indicate the level of information to be queried:

Value	Meaning
1	Query all Local and Global (normal) user accounts.
2	Query all Workstation and Server (BDC) user accounts.
3	Query all Global Groups.
Prefix

Points to a null-terminated Unicode string containing the prefix to search for.

Index

Points to a 32-bit variable that receives the index of the entry.

Return Value

If the function succeeds, the return value is NERR_Success.

If the function fails, the return value is one of the following error codes:

Value	Meaning
ERROR_ACCESS_DENIED	The caller does not have access to the requested information.
ERROR_INVALID_LEVEL	The value specified for the Level parameter is invalid.
See Also

NetQueryDisplayInformation


NetGroupAdd
NetGroupAdd  QuickInfo

NetGroupAdd creates a global group in the security database.

Security Requirements

Admin or account operator group membership is required to successfully execute NetGroupAdd.

NET_API_STATUS
NetGroupAdd (

LPWSTR servername,
DWORD level,
LPBYTE buf,
LPDWORD parm_err
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

level

Level of information provided. Must be 0 1, or 2.

buf

A pointer to a buffer containing the global group information structure.

parm_err

Optional pointer to a DWORD to return the index of the first parameter in error when ERROR_INVALID_PARAMETER is returned. If NULL the parameter is not returned on error.


NetGroupAddUser
NetGroupAddUser  QuickInfo

NetGroupAddUser gives an existing user account membership in an existing global group.

Security Requirements

Admin or account operator group membership is required to successfully execute NetGroupAddUser.

NET_API_STATUS
NetGroupAddUser (

LPWSTR servername,
LPWSTR GroupName,
LPWSTR username
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

GroupName

A pointer to a Unicode string containing the name of the global group to which the user is to be given membership.

Username

A pointer to a Unicode string containing the name of the user to be given global group membership.


NetGroupDel
NetGroupDel  QuickInfo

NetGroupDel deletes a global group account from the accounts database.

Security Requirements

Admin or account operator group membership is required to successfully execute NetGroupDel.

NET_API_STATUS
NetGroupDel (

LPWSTR servername,
LPWSTR groupname
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

groupname

A pointer to a Unicode string containing the name of the global group account to delete.


NetGroupDelUser
NetGroupDelUser  QuickInfo

NetGroupDelUser removes a user from a particular global group in the user account database.

Security Requirements

Admin or account operator group membership is required to successfully execute NetGroupDelUser.

NET_API_STATUS
NetGroupDelUser (

LPWSTR servername,
LPWSTR GroupName,
LPWSTR Username
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

GroupName

A pointer to a Unicode string containing the name of the global group from which the user membership is to be removed.

Username

A pointer to a Unicode string containing the name of the user to remove from the global group.


NetGroupEnum
NetGroupEnum  QuickInfo

NetGroupEnum retrieves information about each global group account.

Security Requirements

Admin or account operator group membership is required to successfully execute NetGroupEnum.

NET_API_STATUS
NetGroupEnum (

LPWSTR servername,
DWORD level,
LPBYTE * bufptr,
DWORD prefmaxlen,
LPDWORD entriesread,
LPDWORD totalentries,
LPDWORD resume_handle
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

level

Level of information required. 0 and 1 are valid.

bufptr

On return a pointer to the return information structure is returned in the address pointed to by bufptr.

prefmaxlen

Preferred maximum length of returned data (in 8-bit bytes).

entriesread

On return the actual enumerated element count is located in the DWORD pointed to by entriesread.

totalentries

On return the total number of entries that could have been enumerated from the current resume position is located in the DWORD pointed to by totalentries.

resume_handle

On return, a resume handle is stored in the DWORD pointed to by resume_handle, and is used to continue an existing global group search. The handle should be zero on the first call and left unchanged for subsequent calls. If resume_handle is NULL, then no resume handle is stored.


NetGroupGetInfo
NetGroupGetInfo  QuickInfo

NetGroupGetInfo retrieves information about a particular global group account on a server.

Security Requirements

Admin or account operator group membership is required to successfully execute NetGroupGetInfo.

NET_API_STATUS
NetGroupGetInfo (

LPWSTR servername,
LPWSTR groupname,
DWORD level,
LPBYTE * bufptr
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

groupname

A pointer to a Unicode string containing the name of the global group account to return information on.

level

Level of information required. 0, 1, and 2 are valid.

bufptr

A pointer to the return information structure is returned in the address pointed to by bufptr.


NetGroupGetUsers
NetGroupGetUsers  QuickInfo

NetGroupGetUsers retrieves a list of the members of a particular global group in the user account database.

Security Requirements

Admin or account operator group membership is required to successfully execute NetGroupGetUsers except when the request is made by a user who has membership in the specified global group, in which case no special group membership is required.

NET_API_STATUS
NetGroupGetUsers (

LPWSTR servername,
LPWSTR groupname,
DWORD level,
LPBYTE * bufptr,
DWORD prefmaxlen,
LPDWORD entriesread,
LPDWORD totalentries,
LPDWORD ResumeHandle
);
Parameters

servername

pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

groupname

A pointer to a Unicode string containing the name of the global group whose members are to be listed.

level

Level of information required. Only 0 and 1 are valid.

bufptr

On return a pointer to the return information structure is returned in the address pointed to by bufptr.

prefmaxlen

Preferred maximum length of returned data (in 8-bit bytes).

entriesread

On return the actual enumerated element count is located in the DWORD pointed to by entriesread.

totalentries

On return the total number of entries that could have been enumerated from the current resume position is located in the DWORD pointed to by totalentries.

ResumeHandle

On return, a resume handle is stored in the DWORD pointed to by ResumeHandle, and is used to continue an existing usergroup search. The handle should be zero on the first call and left unchanged for subsequent calls. If ResumeHandle is NULL, then no resume handle is stored.


NetGroupSetInfo
NetGroupSetInfo  QuickInfo

NetGroupSetInfo sets the parameters of a global group account.

Security Requirements

Admin or account operator group membership is required to successfully execute NetGroupSetInfo.

NET_API_STATUS
NetGroupSetInfo (

LPWSTR servername,
LPWSTR groupname,
DWORD level,
LPBYTE buf,
LPDWORD parm_err
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

groupname

A pointer to a Unicode string containing the name of the global group account to set information on.

level

Level of information to set. Only 0, 1, and 2 are valid.

buf

A pointer to a buffer containing the global group information.

parm_err

Optional pointer to a DWORD to return the index of the first parameter in error when ERROR_INVALID_PARAMETER is returned. If NULL the parameter is not returned on error.


NetGroupSetUsers
NetGroupSetUsers  QuickInfo

NetGroupSetUsers sets the global group membership for the specified global group. Each user specified is made a member of the global group. Users that are not specified but are currently members of the global group will have their membership revoked.

Security Requirements

Admin or account operator group membership is required to successfully execute NetGroupSetUsers on a remote server.

NET_API_STATUS
NetGroupSetUsers (

LPWSTR servername,
LPWSTR groupname,
DWORD level,
LPBYTE buf,
DWORD totalentries
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

groupname

A pointer to a Unicode string containing the name of the global group to which the specified users belong.

level

Level of information supplied. Only 0 is valid.

buf

Points to the buffer in which the data to be set is stored. This data consists of a sequence of _GROUP_USERS_INFO_0 data structures.

totalentries

On return the total number of entries that could have been enumerated from the current resume position is located in the DWORD pointed to by totalentries.


NetLocalGroupAdd
NetLocalGroupAdd  QuickInfo

NetLocalGroupAdd creates a local group in the security database.

Security Requirements

Admin or account operator group membership is required to successfully execute NetLocalGroupAdd.

NET_API_STATUS
NetLocalGroupAdd (

LPWSTR servername,
DWORD level,
LPBYTE buf,
LPDWORD parm_err
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

level

Level of information provided. Must be 0 or 1.

buf

A pointer to a buffer containing the local group information structure.

parm_err

Optional pointer to a DWORD to return the index of the first parameter in error when ERROR_INVALID_PARAMETER is returned. If NULL the parameter is not returned on error.


NetLocalGroupAddMember
NetLocalGroupAddMember  QuickInfo

NetLocalGroupAddMember gives an existing user account or global group membership in an existing local group.

Security Requirements

Admin or account operator group membership is required to successfully execute NetLocalGroupAddMember.

NET_API_STATUS
NetLocalGroupAddMember (

LPWSTR servername,
LPWSTR groupname,
PSID membersid
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

groupname

A pointer to a Unicode string containing the name of the local group to which the user or global group is to be given membership.

membersid

A pointer to the SID of a user or global group from the local, primary, or trust domains to be given local group membership.


NetLocalGroupAddMembers

The NetLocalGroupAddMembers function adds one or more existing user accounts or global groups as members of an existing local group. The function does not change the membership status of users or global groups that are currently members of the local group

Security Requirements

Admin or account operator group membership is required to successfully execute NetLocalGroupAddMembers on a remote server.

NET_API_STATUS
NetLocalGroupAddMembers (

LPWSTR  servername,	// pointer to name of server on which to execute this function
LPWSTR  groupname,	// pointer to name of local group to add members to
DWORD   level,	// level of information provided for new members
LPBYTE  buf,	// pointer to buffer containing information for new members
DWORD   membercount	// number of new members being added
);
Parameters

servername

Points to a null-terminated Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

groupname

Points to a null-terminated Unicode string containing the name of the local group to which the specified users or global groups will be added.

level

Specifies one of the following values to indicate the level of information provided:

Value	Meaning
0	The buf parameter points to an array of LOCALGROUP_MEMBERS_INFO_0 structures.
3	The buf parameter points to an array of LOCALGROUP_MEMBERS_INFO_3 structures.
buf

Points to a buffer containing the data for the new members. This data consists of a sequence of LOCALGROUP_MEMBERS_INFO_0 or LOCALGROUP_MEMBERS_INFO_3 data structures.

membercount

Specifies the number of entries in the buffer pointed to by buf.

Return Value

If the function succeeds, the return value is NERR_Success.

If the function fails, the return value is one of the following error codes:

Value	Meaning
NERR_GroupNotFound	The local group specified by the groupname parameter does not exist.
ERROR_NO_SUCH_MEMBER	One or more of the new members doesn't exist. Therefore, no new members were added.
ERROR_MEMBER_IN_ALIAS	One or more of the members specified were already members of the local group. Therefore, no new members were added.
ERROR_INVALID_MEMBER	One or more of the members cannot be added because it has an invalid account type. Therefore, no new members were added.
Remarks

Use the NetLocalGroupAddMembers function instead of the NetLocalGroupAddMember function, which is obsolete.

See Also

NetLocalGroupAdd, NetLocalGroupDelMembers, NetLocalGroupGetMembers


NetLocalGroupDel
NetLocalGroupDel  QuickInfo

NetLocalGroupDel deletes a local group account and all its members from the accounts database.

Security Requirements

Admin or account operator group membership is required to successfully execute NetLocalGroupDel.

NET_API_STATUS
NetLocalGroupDel (

LPWSTR servername,
LPWSTR groupname
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

groupname

A pointer to a Unicode string containing the name of the local group account to delete.


NetLocalGroupDelMember
NetLocalGroupDelMember  QuickInfo

NetLocalGroupDelMember removes a member from a particular local group in the security database.

Security Requirements

Admin or account operator group membership is required to successfully execute NetLocalGroupDelMember.

NET_API_STATUS
NetLocalGroupDelMember (

LPWSTR servername,
LPWSTR groupname,
PSID membersid
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

groupname

A pointer to a Unicode string containing the name of the local group from which the user membership is to be removed.

membersid

A pointer to a SID of a user or global group to remove from the local group.


NetLocalGroupDelMembers

The NetLocalGroupDelMembers function removes one or more members from an existing local group.

Security Requirements

Admin or account operator group membership is required to successfully execute NetLocalGroupDelMembers on a remote server.

NET_API_STATUS
NetLocalGroupDelMembers (

LPWSTR  servername,	// pointer to name of server on which to execute this function
LPWSTR  groupname,	// pointer to name of local group to delete members from
DWORD   level,	// level of information provided for members to be deleted
LPBYTE  buf,	// pointer to buffer containing information for members
DWORD   membercount	// number of members being deleted
);
Parameters

servername

Points to a null-terminated Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

groupname

Points to a null-terminated Unicode string containing the name of the local group from which the specified users or global groups will be removed.

level

Specifies one of the following values to indicate the level of information provided:

Value	Meaning
0	The buf parameter points to an array of LOCALGROUP_MEMBERS_INFO_0 structures.
3	The buf parameter points to an array of LOCALGROUP_MEMBERS_INFO_3 structures.
buf

Points to the buffer containing data that describes the removed members. This data consists of a sequence of LOCALGROUP_MEMBERS_INFO_0 or LOCAL_GROUP_MEMBERS_INFO_3 data structures.

membercount

Specifies the number of entries in the array pointed to by buf.

Return Value

If the function succeeds, the return value is NERR_Success.

If the function fails, the return value is one of the following error codes:

Value	Meaning
NERR_GroupNotFound	The local group specified by the groupname parameter does not exist.
ERROR_NO_SUCH_MEMBER	One or more of the members doesn't exist. Therefore, no members were deleted.
ERROR_MEMBER_IN_ALIAS	One or more of the members specified were not members of the local group. Therefore, no members were deleted.
Remarks

Use the NetLocalGroupDelMembers function instead of the NetLocalGroupDelMember function, which is obsolete.

See Also

NetLocalGroupAddMembers, NetLocalGroupDel, NetLocalGroupGetMembers


NetLocalGroupEnum
NetLocalGroupEnum  QuickInfo

NetLocalGroupEnum retrieves information about each local group account.

Security Requirements

Admin or account operator group membership is required to successfully execute NetLocalGroupEnum.

NET_API_STATUS
NetLocalGroupEnum (

LPWSTR servername,
DWORD level,
LPBYTE * bufptr,
DWORD prefmaxlen,
LPDWORD entriesread,
LPDWORD totalentries,
LPDWORD resumehandle
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

level

Level of information required. 0 and 1 are valid.

bufptr

On return a pointer to the return information structure is returned in the address pointed to by bufptr.

prefmaxlen

Preferred maximum length of returned data (in 8-bit bytes).

entriesread

On return the actual enumerated element count is located in the DWORD pointed to by entriesread.

totalentries

On return the total number of entries that could have been enumerated from the current resume position is located in the DWORD pointed to by totalentries.

resumehandle

On return, a resume handle is stored in the DWORD pointed to by resumehandle, and is used to continue an existing local group search. The handle should be zero on the first call and left unchanged for subsequent calls. If resumehandle is NULL, then no resume handle is stored.


NetLocalGroupGetInfo
NetLocalGroupGetInfo  QuickInfo

NetLocalGroupGetInfo retrieves information about a particular local group account on a server.

Security Requirements

Admin or account operator group membership is required to successfully execute NetLocalGroupGetInfo.

NET_API_STATUS
NetLocalGroupGetInfo (

LPWSTR servername,
LPWSTR groupname,
DWORD level,
LPBYTE * bufptr
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

groupname

A pointer to a Unicode string containing the name of the local group account to return information on.

level

Level of information required. 0 and 1 are valid.

bufptr

A pointer to the return information structure is returned in the address pointed to by bufptr.


NetLocalGroupGetMembers
NetLocalGroupGetMembers  QuickInfo

NetLocalGroupGetMembers retrieves a list of the members of a particular local group in the security database.

Security Requirements

Admin or account operator group membership is required to successfully execute NetLocalGroupGetMembers except when the request is made by a user who has membership in the specified local group in which case no special group membership is required.

NET_API_STATUS
NetLocalGroupGetMembers (

LPWSTR servername,
LPWSTR localgroupname,
DWORD level,
LPBYTE * bufptr,
DWORD prefmaxlen,
LPDWORD entriesread,
LPDWORD totalentries,
LPDWORD resumehandle
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

localgroupname

A pointer to a Unicode string containing the name of the local group whose members are to be listed.

level

Level of information required. Levels 0 and 1 are valid.

bufptr

On return a pointer to the return information structure is returned in the address pointed to by bufptr.

prefmaxlen

Prefered maximum length of returned data (in 8-bit bytes).

entriesread

On return the actual enumerated element count is located in the DWORD pointed to by entriesread.

totalentries

On return the total number of entries that could have been enumerated from the current resume position is located in the DWORD pointed to by totalentries.

resumehandle

On return, a resume handle is stored in the DWORD pointed to by resumehandle, and is used to continue an existing usergroup search. The handle should be zero on the first call and left unchanged for subsequent calls. If resumehandle is NULL, then no resume handle is stored.


NetLocalGroupSetInfo
NetLocalGroupSetInfo  QuickInfo

NetLocalGroupSetInfo sets the parameters of a local group.

Security Requirements

Admin or account operator group membership is required to successfully execute NetLocalGroupSetInfo.

NET_API_STATUS
NetLocalGroupSetInfo (

LPWSTR servername,
LPWSTR groupname,
DWORD level,
LPBYTE buf,
LPDWORD parm_err
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

groupname

A pointer to a Unicode string containing the name of the local group account to set information on.

level

Level of information to set. 0, 1, and 1002 are valid.

buf

A pointer to a buffer containing the local group information.

parm_err

Optional pointer to a DWORD to return the index of the first parameter in error when ERROR_INVALID_PARAMETER is returned. If NULL the parameter is not returned on error.


NetLocalGroupSetMembers
NetLocalGroupSetMembers  QuickInfo

NetLocalGroupSetMembers sets the local group membership for the specified local group. Each user or global group specified is made a member of the local group. Users or global groups that are not specified but are currently members of the local group will have their membership revoked.

Security Requirements

Admin or account operator group membership is required to successfully execute NetLocalGroupSetMembers on a remote server.

NET_API_STATUS
NetLocalGroupSetMembers (

LPWSTR servername,
LPWSTR groupname,
DWORD level,
LPBYTE buf,
DWORD totalentries
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

groupname

A pointer to a Unicode string containing the name of the local group to which the specified users or global groups belong.

level

Level of information supplied. Only 0 is valid.

buf

Points to the buffer in which the data to be set is stored. This data consists of a sequence of LOCALGROUP_MEMBERS_INFO_0 data structures.

totalentries

On return the total number of entries that could have been enumerated from the current resume position is located in the DWORD pointed to by totalentries.


NetMessageBufferSend
NetMessageBufferSend  QuickInfo

NetMessageBufferSend sends a buffer of information to a registered message alias.

Security Requirements

No special group membership is required to execute NetMessage buffer send locally. Admin, accounts, print, or server operator group membership is required to successfully execute NetMessageBufferSend on a remote server.

NET_API_STATUS
NetMessageBufferSend (

LPTSTR servername,
LPTSTR msgname,
LPTSTR fromname,
LPBYTE buf,
DWORD buflen
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

msgname

A pointer to a Unicode string containing the message name to which the message buffer should be sent.

fromname

A pointer to a Unicode string containing the message name sending the information. fromname is a new parameter for Windows networking. This parameter is needed for sending alerts from the computer name rather than the logged on user. If a NULL is specified the message is send from the logged on user as with LAN Manager 2.x.

buf

A pointer to a buffer of message text.

buflen

The length in bytes of the message text in buf.


NetMessageNameAdd
NetMessageNameAdd  QuickInfo

NetMessageNameAdd registers a message alias in the message name table. NetMessageNameAdd requires that the Messenger service be started.

Security Requirements

Admin group membership is required to successfully execute NetMessageNameAdd on a remote server.

NET_API_STATUS
NetMessageNameAdd (

LPTSTR servername,
LPTSTR msgname
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

msgname

A pointer to a Unicode string of limit 15 characters containing the message name to be added.

Note  The forward action flag from the LAN Manager 2.x NetMessageNameAdd is no longer a parameter because message forwarding is no longer supported. If the NetMessageNameAdd function detects that a forwarded version of msgname exists on the network, the function will fail with error NERR_Already_Exists.


NetMessageNameDel
NetMessageNameDel  QuickInfo

NetMessageNameDel deletes a message alias from the table of message aliases on a computer. NetMessageNameDel requires that the Messenger service be started.

Security Requirements

Admin group membership is required to successfully execute NetMessageNameDel on a remote server.

NET_API_STATUS
NetMessageNameDel (

LPTSTR servername,
LPTSTR msgname
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

msgname

A pointer to a Unicode string of limit 15 characters containing the message name to be deleted.


NetMessageNameEnum
NetMessageNameEnum  QuickInfo

NetMessageNameEnum lists the message aliases that will receive messages on a specified computer. NetMessageNameEnum requires that the Messenger service be started.

Security Requirements

Admin group membership is required to successfully execute NetMessageNameEnum on a remote server.

NET_API_STATUS
NetMessageNameEnum (

LPTSTR servername,
DWORD level,
LPBYTE * bufptr,
DWORD prefmaxlen,
LPDWORD entriesread,
LPDWORD totalentries,
LPDWORD resume_handle
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

level

Level of information required. 0 and 1 are valid.

bufptr

On return a pointer to the return information structure is returned in the address pointed to by bufptr.

prefmaxlen

Prefered maximum length of returned data (in 8-bit bytes).

entriesread

On return the actual enumerated element count is located in the DWORD pointed to by entriesread.

totalentries

On return the total number of entries that could have been enumerated from the current resume position is located in the DWORD pointed to by totalentries.

resume_handle

On return, a resume handle is stored in the DWORD pointed to by resume_handle, and is used to continue an existing message name search. The handle should be zero on the first call and left unchanged for subsequent calls. If resume_handle is NULL, then no resume handle is stored.


NetMessageNameGetInfo
NetMessageNameGetInfo  QuickInfo

NetMessageNameGetInfo retrieves information about a particular message alias in the message name table. NetMessageNameGetInfo requires that the Messenger service be started.

Security Requirements

Admin group membership is required to successfully execute NetMessageNameGetInfo on a remote server.

NET_API_STATUS
NetMessageNameGetInfo (

LPTSTR servername,
LPTSTR msgname,
DWORD level,
LPBYTE * bufptr
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

msgname

A pointer to a Unicode string containing the message name to return information on.

level

Level of information required. 0 and 1 are valid.

bufptr

On return a pointer to the return information structure is returned in the address pointed to by bufptr.


NetQueryDisplayInformation

The NetQueryDisplayInformation function returns user, computer, or group account information. Use this function to quickly enumerate account information for display in user interfaces.

Security Requirements

No special group membership is required to successfully execute NetQueryDisplayInformation.

NET_API_STATUS
NetQueryDisplayInformation(

LPWSTR   ServerName,	// pointer to name of server to get information from
DWORD    Level,	// level of information to retrieve
DWORD    Index,	// index of first entry to get information for
DWORD    EntriesRequested,	// number of entries to get information for
DWORD    PreferredMaximumLength,	// preferred maximum size, in bytes, of returned buffer
LPDWORD  ReturnedEntryCount,	// receives number of entries for which information is returned
PVOID    * SortedBuffer	// receives pointer to system-allocated buffer
);
Parameters

ServerName

Points to a null-terminated Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

Level

Specifies one of the following values to indicate the level of information requested:

Value	Meaning
1	Return all Local and Global (normal) user accounts. The returned buffer will contain an array of NET_DISPLAY_USER structures.
2	Return all Workstation and Server (BDC) user accounts. The returned buffer will contain an array of NET_DISPLAY_MACHINE structures.
3	Return all Global Groups. The returned buffer will contain an array of NET_DISPLAY_GROUP structures.
Index

Specifies the index of the first entry to retrieve information for. Specify zero to retrieve account information beginning with the first display information entry. If a call to NetQueryDisplayInformation returns ERROR_MORE_DATA, you can get data for additional entries by setting Index to the value returned in the next_index member of the last entry in SortedBuffer. To retrieve information for entries beginning with a specified prefix, set Index to the index returned by a call to the NetGetDisplayInformationIndex function.

EntriesRequested

Specifies the maximum number of entries to get information for.

PreferredMaximumLength

Specifies the preferred maximum size, in 8-bit bytes, of the system-allocated buffer returned in *SortedBuffer.

ReturnedEntryCount

Points to a 32-bit variable that receives the number of entries in the buffer returned in *SortedBuffer. Zero indicates that there are no entries with an index as large as that specified. Entries may be returned when the function's return value is either NERR_Success or ERROR_MORE_DATA.

SortedBuffer

Points to a variable that receives a pointer to a system-allocated buffer containing a sorted list of the requested information. This buffer contains an array of NET_DISPLAY_USER, NET_DISPLAY_MACHINE or NET_DISPLAY_GROUP structures. Use NetApiBufferFree to deallocate the buffer.

Return Value

If the function returns account information, the return value is one of the following values:

Value	Meaning
NERR_Success	There are no more entries to be returned.
ERROR_MORE_DATA	More entries are available. That is, the last entry returned in the SortedBuffer buffer is not the last entry available. To get information for additional entries, call NetQueryDisplayInformation again with the Index parameter set to the value returned in the next_index member of the last entry in SortedBuffer.
If the function fails, the return value is one of the following error codes:

Value	Meaning
ERROR_ACCESS_DENIED	The caller does not have access to the requested information.
ERROR_INVALID_LEVEL	The Level parameter specifies an invalid value.
Remarks

The NetQueryDisplayInformation function is remotable. The server specified by the Server parameter can be any Windows NT workstation or server; it cannot be a LAN Manager or Windows for Workgroups server.

The NetQueryDisplayInformation and NetGetDisplayInformationIndex functions provide a very efficient mechanism for enumerating User and Global group accounts. When possible, use these functions instead of the NetUserEnum and NetGroupEnum functions.

See Also

NetApiBufferFree, NetGetDisplayInformationIndex, NetGroupEnum, NetUserEnum.


NetRemoteTOD
NetRemoteTOD  QuickInfo

NetRemoteTOD returns a server's time of day.

Security Requirements

No special group membership is required to successfully execute NetRemoteTOD.

NET_API_STATUS
NetRemoteTOD (

LPTSTR UncServerName,
LPBYTE * BufferPtr
);
Parameters

UncServerName

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

BufferPtr

On return a pointer to the return information structure is returned in the address pointed to by BufferPtr.

Remarks

The remote time-of-day information is available at one information level:

typedef struct _TIME_OF_DAY_INFO {
    DWORD    tod_elapsedt;
    DWORD    tod_msecs;
    DWORD    tod_hours;
    DWORD    tod_mins;
    DWORD    tod_secs;
    DWORD    tod_hunds;
    LONG     tod_timezone;
    DWORD    tod_tinterval;
    DWORD    tod_day;
    DWORD    tod_month;
    DWORD    tod_year;
    DWORD    tod_weekday;
} TIME_OF_DAY_INFO, *PTIME_OF_DAY_INFO, *LPTIME_OF_DAY_INFO;


NetReplExportDirAdd
NetReplExportDirAdd  QuickInfo

NetReplExportDirAdd registers an existing directory in the export path to be replicated. The default values for locktime and lockcount (both 0) are assumed.

Security Requirements

Admin or server operator group membership is required to successfully execute NetReplExportDirAdd.

NET_API_STATUS
NetReplExportDirAdd (

LPTSTR servername,
DWORD level,
LPBYTE buf,
LPDWORD parm_err
);
Parameters

servername

A pointer to a null-terminated Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

level

Level of information to add. Only level 1 is valid.

buf

A pointer to a buffer containing the directory control information structure.

parm_err

Optional pointer to a DWORD to return the index of the first parameter in error when ERROR_INVALID_PARAMETER is returned. If NULL the parameter is not returned on error.


NetReplExportDirDel
NetReplExportDirDel  QuickInfo

NetReplExportDirDel deregisters a replicated directory.

Security Requirements

Admin or server operator group membership is required to successfully execute NetReplExportDirDel.

NET_API_STATUS
NetReplExportDirDel (

LPTSTR servername,
LPTSTR dirname
);
Parameters

servername

A pointer to a null-terminated Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

dirname

A pointer to a null-terminated Unicode string containing the name of a replicated directory to deregister.


NetReplExportDirEnum
NetReplExportDirEnum  QuickInfo

NetReplExportDirEnum lists the replicated directories in the export path.

Security Requirements

No special group membership is required to successfully execute NetReplExportDirEnum.

NET_API_STATUS
NetReplExportDirEnum (

LPTSTR servername,
DWORD level,
LPBYTE * bufptr,
DWORD prefmaxlen,
LPDWORD entriesread,
LPDWORD totalentries,
LPDWORD resumehandle
);
Parameters

servername

A pointer to a null-terminated Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

level

Level of information to return. Levels 0,1, and 2 are valid.

bufptr

On return, an array of the specified information structure is returned in the address pointed to by bufptr.

prefmaxlen

Preferred maximum length of returned data (in 8-bit bytes). A value of 0xFFFFFFFF indicates that all available entries should be returned.

entriesread

On return, the actual enumerated element count is located in the DWORD pointed to by entriesread.

totalentries

On return, the total number of entries that could have been enumerated from the current resume position is located in the DWORD pointed to by totalentries.

resumehandle

On return, a resume handle is stored in the DWORD pointed to by resumehandle, and is used to continue an existing use search. The handle should be zero on the first call and left unchanged for subsequent calls. If resumehandle is NULL, then no resume handle is stored.


NetReplExportDirGetInfo
NetReplExportDirGetInfo  QuickInfo

NetReplExportDirGetInfo retrieves a replicated directory control information.

Security Requirements

No special group membership is required to successfully execute NetReplExportDirGetInfo.

NET_API_STATUS
NetReplExportDirGetInfo (

LPTSTR servername,
LPTSTR dirname,
DWORD level,
LPBYTE * bufptr
);
Parameters

servername

A pointer to a null-terminated Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

dirname

A pointer to a null-terminated Unicode string containing the directory name to return control information about.

level

Level of information to return. Levels 0, 1, and 2 are valid.

bufptr

On return a pointer to the return information structure is written in the address pointed to by bufptr.


NetReplExportDirLock
NetReplExportDirLock  QuickInfo

NetReplExportDirLock locks a replicated directory so that replication from it can be suspended. This function increments the lock reference count for the specified directory.

Security Requirements

Admin or server operator group membership is required to successfully execute NetReplExportDirLock.

NET_API_STATUS
NetReplExportDirLock (

LPTSTR servername,
LPTSTR dirname
);
Parameters

servername

A pointer to a null-terminated Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

dirname

A pointer to a null-terminated Unicode string containing the directory name to lock.


NetReplExportDirSetInfo
NetReplExportDirSetInfo  QuickInfo

NetReplExportDirSetInfo modifies the control information of a replicated directory.

Security Requirements

Admin or server operator group membership is required to successfully execute NetReplExportDirSetInfo.

NET_API_STATUS
NetReplExportDirSetInfo (

LPTSTR servername,
LPTSTR dirname,
DWORD level,
LPBYTE buf,
LPDWORD parm_err
);
Parameters

servername

A pointer to a null-terminated Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

dirname

A pointer to a null-terminated Unicode string containing the directory name to return control information about.

level

Level of information to set. Levels 1, 1000, and 1001 are valid.

buf

A pointer to a buffer containing the control information structure that corresponds to the specified level.

parm_err

Optional pointer to a DWORD to return the identifier of the first parameter in error when ERROR_INVALID_PARAMETER is returned. If NULL the parameter is not returned on error.


NetReplExportDirUnlock
NetReplExportDirUnlock  QuickInfo

NetReplExportDirUnlock unlocks a directory so that replication from it can resume. This function decrements the lock reference count for the specified directory.

Security Requirements

Admin or server operator group membership is required to successfully execute NetReplExportDirUnlock.

NET_API_STATUS
NetReplExportDirUnlock (

LPTSTR servername,
LPTSTR dirname,
DWORD unlockforce
);
Parameters

servername

A pointer to a null-terminated Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

dirname

A pointer to a null-terminated Unicode string containing the directory name to unlock.

unlockforce

A value that indicates the force level to unlock the directory.

Force levels:

REPL_UNLOCK_NOFORCE

Unlocks the directory by decrementing the lock reference count. The lock reference count may or may not return to 0, so the directory could still be locked.

REPL_UNLOCK_FORCE

Unlocks the directory completely by removing all outstanding locks on the directory. The lock reference count is set to 0.


NetReplGetInfo
NetReplGetInfo  QuickInfo

NetReplGetInfo retrieves the Replicator service configuration information.

Security Requirements

No special group membership is required to successfully execute NetReplGetInfo.

NET_API_STATUS
NetReplGetInfo (

LPTSTR servername,
DWORD level,
LPBYTE * bufptr
);
Parameters

servername

A pointer to a null-terminated Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

level

Level of information required. Only level 0 is valid.

bufptr

On return a pointer to the return information structure is written in the address pointed to by bufptr.


NetReplImportDirAdd
NetReplImportDirAdd  QuickInfo

NetReplImportDirAdd registers an existing directory in the import path to receive replication from a master.

Security Requirements

Admin or replicator group membership is required to successfully execute NetReplImportDirAdd.

NET_API_STATUS
NetReplImportDirAdd (

LPTSTR servername,
DWORD level,
LPBYTE buf,
LPDWORD parm_err
);
Parameters

servername

A pointer to a null-terminated Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

level

Level of information to add. Only level 0 is valid.

buf

A pointer to a buffer containing the directory name.

parm_err

Optional pointer to a DWORD to return the index of the first parameter in error when ERROR_INVALID_PARAMETER is returned. If NULL the parameter is not returned on error.


NetReplImportDirDel
NetReplImportDirDel  QuickInfo

NetReplImportDirDel deregisters directory so that it no longer receives updates from the master. Note that this function does not actually delete the directory from the file system. Also, the directory may be automatically re-registered by the Replicator service at any time. To prevent importing of a directory that is being exported by some Replicator service, use the NetReplImportDirLock function instead.

Security Requirements

Admin or replicator group membership is required to successfully execute NetReplImportDirDel.

NET_API_STATUS
NetReplImportDirDel (

LPTSTR servername,
LPTSTR dirname
);
Parameters

servername

A pointer to a null-terminated Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

dirname

A pointer to a null-terminated Unicode string containing the name of a replicated directory to deregister.


NetReplImportDirEnum
NetReplImportDirEnum  QuickInfo

NetReplImportDirEnum lists the replicated directories in the import path.

Security Requirements

No special group membership is required to successfully execute NetReplImportDirEnum.

NET_API_STATUS
NetReplImportDirEnum (

LPTSTR servername,
DWORD level,
LPBYTE * bufptr,
DWORD prefmaxlen,
LPDWORD entriesread,
LPDWORD totalentries,
LPDWORD resumehandle
);
Parameters

servername

A pointer to a null-terminated Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

level

Level of information to return. Levels 0 or 1 are valid.

bufptr

On return, an array of the specified information structure is returned in the address pointed to by bufptr.

prefmaxlen

Preferred maximum length of returned data (in 8-bit bytes). A value of 0xFFFFFFFF indicates that all available entries should be returned.

entriesread

On return, the actual enumerated element count is located in the DWORD pointed to by entriesread.

totalentries

On return, the total number of entries that could have been enumerated from the current resume position is located in the DWORD pointed to by totalentries.

resumehandle

On return, a resume handle is stored in the DWORD pointed to by resumehandle, and is used to continue an existing use search. The handle should be zero on the first call and left unchanged for subsequent calls. If resumehandle is NULL, then no resume handle is stored.


NetReplImportDirGetInfo
NetReplImportDirGetInfo  QuickInfo

NetReplImportDirGetInfo retrieves the status information on a client replicated directory.

Security Requirements

No special group membership is required to successfully execute NetReplImportDirGetInfo.

NET_API_STATUS
NetReplImportDirGetInfo (

LPTSTR servername,
LPTSTR dirname,
DWORD level,
LPBYTE * bufptr
);
Parameters

servername

A pointer to a null-terminated Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

dirname

A pointer to a null-terminated Unicode string containing the directory name to return control information about.

level

Level of information to return. Levels 0 and 1 are valid.

bufptr

On return a pointer to the return information structure is written in the address pointed to by bufptr.


NetReplImportDirLock
NetReplImportDirLock  QuickInfo

NetReplImportDirLock locks a replicated directory so that replication to it can be suspended. This function increments the lock reference count for the specified directory.

Security Requirements

Admin or replicator group membership is required to successfully execute NetReplImportDirLock.

NET_API_STATUS
NetReplImportDirLock (

LPTSTR servername,
LPTSTR dirname
);
Parameters

servername

A pointer to a null-terminated Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

dirname

A pointer to a null-terminated Unicode string containing the directory name to lock.


NetReplImportDirUnlock
NetReplImportDirUnlock  QuickInfo

NetReplImportDirUnlock unlocks a directory so that replication to it can resume. This function decrements the lock reference count for the specified directory.

Security Requirements

Admin or replicator group membership is required to successfully execute NetReplImportDirUnlock.

NET_API_STATUS
NetReplImportDirUnlock (

LPTSTR servername,
LPTSTR dirname,
DWORD unlockforce
);
Parameters

servername

A pointer to a null-terminated Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

dirname

A pointer to a null-terminated Unicode string containing the directory name to unlock.

unlockforce

A value that indicates the force level to unlock the directory.

Force levels:

REPL_UNLOCK_NOFORCE

Unlocks the directory by decrementing the lock reference count. The lock reference count may or may not return to 0, so the directory could still be locked.

REPL_UNLOCK_FORCE

Unlocks the directory completely by removing all outstanding locks on the directory. The lock reference count is set to 0.


NetReplSetInfo
NetReplSetInfo  QuickInfo

NetReplSetInfo modifies the Replicator service configuration information.

Security Requirements

Admin or server operator group membership is required to successfully execute NetReplSetInfo.

NET_API_STATUS
NetReplSetInfo (

LPTSTR servername,
DWORD level,
LPBYTE buf,
LPDWORD parm_err
);
Parameters

servername

A pointer to a null-terminated Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

level

Level of information to set 0, 1000, 1001, 1002, and 1003 are valid levels.

buf

A pointer to a buffer containing the configuration information structure that corresponds to the specified level.

parm_err

Optional pointer to a DWORD to return the identifier of the first parameter in error when ERROR_INVALID_PARAMETER is returned. If NULL the parameter is not returned on error.


NetScheduleJobAdd
NetScheduleJobAdd  QuickInfo

NetScheduleJobAdd submits a job to run at a computer at a specified time and date in future. NetScheduleJobAdd requires that the Schedule service be started at computer where job is submitted to.

Security Requirements

Admin group membership is required to successfully execute NetScheduleJobAdd on a remote server.

NET_API_STATUS
NetScheduleJobAdd (

LPWSTR Servername,
LPBYTE Buffer,
LPDWORD JobId
);
Parameters

Servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

Buffer

A pointer to a buffer containing AT_INFO data structure describing job to be submitted.

JobId

A pointer to a job identifier for a newly submitted job. This entry is valid only if function returns success.

By choosing values in AT_INFO appropriately one may submit jobs with different types of execution periodicity. If DaysOfMonth and DaysOfWeek are both zero, then job will be executed only once, the first time JobTime at server is reached. After being executed, the job will be deleted.

If one sets bits in DaysOfMonth and/or DaysOfWeek, but does not set the bit flag JOB_RUN_PERIODICALLY, a job will execute at JobTime once for each day listed in days bitmasks. After each execution, the corresponding bit in days bitmasks will be cleared. Once the last bit in days bitmasks is cleared, the job will be deleted.

If one sets bits in DaysOfMonth and/or DaysOfWeek, and at the same time sets the bit flag JOB_RUN_PERIODICALLY, a job will execute at JobTime whenever a day with corresponding bit in days bitmasks is reached. This job is thus executed periodically and does not get deleted as a result of repeated executions. The only way to delete this job is by an explicit call to NetScheduleJobDel( ).


NetScheduleJobDel
NetScheduleJobDel  QuickInfo

NetScheduleJobDel deletes a range of jobs queued to run at a computer. NetScheduleJobDel requires that the Schedule service be started at computer where job deletion request is being sent to.

Security Requirements

Admin group membership is required to successfully execute NetScheduleJobDel on a remote server.

NET_API_STATUS
NetScheduleJobDel (

LPWSTR Servername,
DWORD MinJobId,
DWORD MaxJobId
);
Parameters

Servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

MinJobId

Minimum job identifier. Jobs with job identifier smaller than MinJobId will not be deleted.

MaxJobId

Maximum job identifier. Jobs with job identifier bigger than MaxJobId will not be deleted.

This function deletes all jobs whose job identifier is in the range MinJobId through MaxJobId. To delete all jobs at the server, one may call this function with MinJobId equal to 0 and MaxJobId equal to (DWORD) − 1. To delete just one particular job, one may choose MinJobId and MaxJobId both equal to that particular job's identifier.


NetScheduleJobEnum
NetScheduleJobEnum  QuickInfo

NetScheduleJobEnum lists the jobs queued on a specified computer. NetScheduleJobEnum requires that the Schedule service be started.

Security Requirements

Admin group membership is required to successfully execute NetScheduleJobEnum on a remote server.

NET_API_STATUS
NetScheduleJobEnum(

LPWSTR Servername,
LPBYTE * PointerToBuffer,
DWORD PreferredMaximumLength,
LPDWORD EntriesRead,
LPDWORD TotalEntries,
LPDWORD ResumeHandle
);
Parameters

Servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

PointerToBuffer

On return a pointer to the return information structure is returned in the address pointed to by PointerToBuffer. The return information structure is an array of AT_ENUM data structures.

PreferredMaximumLength

Preferred maximum length of returned data (in 8-bit bytes).

EntriesRead

On return the actual enumerated element count is located in the DWORD pointed to by EntriesRead.

TotalEntries

On return the total number of entries that could have been enumerated from the current resume position is located in the DWORD pointed to by TotalEntries.

ResumeHandle

On return, a resume handle is stored in the DWORD pointed to by ResumeHandle, and is used to continue an job enumeration. The handle should be zero on the first call and left unchanged for subsequent calls. If ResumeHandle is NULL, then no resume handle is stored.

Note that each entry returned contains the JobId field of AT_ENUM structure. The value of this field may be used in calls that require job identifier argument, such as in a call to NetScheduleJobDel( ).


NetScheduleJobGetInfo
NetScheduleJobGetInfo  QuickInfo

NetScheduleJobGetInfo retrieves information about a particular job queued on a specified computer. NetScheduleJobGetInfo requires that the Schedule service be started.

Security Requirements

Admin group membership is required to successfully execute NetScheduleJobGetInfo on a remote server.

NET_API_STATUS
NetScheduleJobGetInfo (

LPWSTR Servername,
DWORD JobId,
LPBYTE * PointerToBuffer
);
Parameters

Servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

JobId

A job identifier of a job in question.

PointerToBuffer

On return a pointer to the buffer containing AT_INFO data structure describing job in question.


NetServerDiskEnum
NetServerDiskEnum  QuickInfo

NetServerDiskEnum retrieves a list of disk drives on a server.

Security Requirements

Admin or server operator group membership is required to successfully execute NetServerDiskEnum on a remote computer. No special group membership is required for local calls.

NET_API_STATUS
NetServerDiskEnum (

LPTSTR servername,
DWORD level,
LPBYTE * bufptr,
DWORD prefmaxlen,
LPDWORD entriesread,
LPDWORD totalentries,
LPDWORD resume_handle
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

level

Level of information required. 0 is the only valid level.

bufptr

On return a pointer to the return information structure is returned in the address pointed to by bufptr.

prefmaxlen

Prefered maximum length of returned data (in 8-bit bytes).

entriesread

On return the actual enumerated element count is located in the DWORD pointed to by entriesread.

totalentries

On return the total number of entries that could have been enumerated from the current resume position is located in the DWORD pointed to by totalentries.

resume_handle

On return, a resume handle is stored in the DWORD pointed to by resume_handle, and is used to continue an existing server disk search. The handle should be zero on the first call and left unchanged for subsequent calls. If resume_handle is NULL, then no resume handle is stored.


NetServerEnum
NetServerEnum  QuickInfo

NetServerEnum lists all servers of the specified type(s) that are visible in the specified domain(s). For example, an application can call NetServerEnum to list all domain controllers only or all SQL servers only.

Note  If you require information on the type, name, and comment for a specific server, use the WNetEnumResource function.

Security Requirements

No special group membership is required to successfully execute NetServerEnum.

NET_API_STATUS
NetServerEnum (

LPTSTR servername,
DWORD level,
LPBYTE * bufptr,
DWORD prefmaxlen,
LPDWORD entriesread,
LPDWORD totalentries,
DWORD servertype,
LPTSTR domain,
LPDWORD resume_handle
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

level

Level of information required. 100 and 101 are valid.

bufptr

On return a pointer to the return information structure is returned in the address pointed to by bufptr.

prefmaxlen

Preferred maximum length of returned data (in 8-bit bytes).

entriesread

On return the actual enumerated element count is located in the doubleword pointed to by entriesread.

totalentries

return the total number of entries that could have been enumerated from the current resume position is located in the doubleword pointed to by totalentries.

servertype

A doubleword mask that filters server entries to return from the enumeration. The defined mask bits are:

Symbolic constant	Value	Meaning
SV_TYPE_WORKSTATION	0x00000001	All LAN Manager workstation
SV_TYPE_SERVER	0x00000002	All LAN Manager server
SV_TYPE_SQLSERVER	0x00000004	Any server running with Microsoft SQL Server
SV_TYPE_DOMAIN_CTRL	0x00000008	Primary domain controller
SV_TYPE_DOMAIN_BAKCTRL	0x00000010	Backup domain controller
SV_TYPE_TIMESOURCE	0x00000020	Server running the timesource service
SV_TYPE_AFP	0x00000040	Apple File Protocol servers
SV_TYPE_NOVELL	0x00000080	Novell servers
SV_TYPE_DOMAIN_MEMBER	0x00000100	Domain Member
SV_TYPE_PRINT	0x00000200	Server sharing print queue
SV_TYPE_DIALIN	0x00000400	Server running dialin service
SV_TYPE_XENIX_SERVER	0x00000800	Xenix server
SV_TYPE_NT	0x00001000	Windows NT server
SV_TYPE_WFW	0x00002000	Server running Windows for Workgroups
SV_TYPE_POTENTIAL_BROWSER	0x00010000	Server that can run the browser service
SV_TYPE_BACKUP_BROWSER	0x00020000	Server running a browser service as backup
SV_TYPE_MASTER_BROWSER	0x00040000	Server running the master browser service
SV_TYPE_DOMAIN_MASTER	0x00080000	Server running the domain master browser
SV_TYPE_DOMAIN_ENUM	0x80000000	Domain announcement
SV_TYPE_ALL	0xffffffff	All servers
domain

A pointer to a Unicode string containing the name of the domain for which a list of servers is to returned. The domain must be the primary domain, one of the other domains for the workstation or the logon domain.

resume_handle

 This parameter is reserved. It should be set to zero.


NetServerGetInfo
NetServerGetInfo  QuickInfo

NetServerGetInfo retrieves information about the specified server.

Security Requirements

Admin or accounts, comm, print, or server operator group membership is required to successfully execute NetServerGetInfo at level 102 or higher. No special group membership is required for level 100 or level 101 calls.

NET_API_STATUS
NetServerGetInfo (

LPTSTR servername,
DWORD level,
LPBYTE * bufptr
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

level

Level of information required. 100, 101, and 102 are valid for all platforms. 302, 402, 403, and 502 are valid for the appropriate platform.

bufptr

On return a pointer to the return information structure is returned in the address pointed to by bufptr.


NetServerSetInfo
NetServerSetInfo  QuickInfo

NetServerSetInfo sets a server's operating parameters; it can set them individually or collectively. This information is stored such that it remains in effect after the system has been reinitialized.

Security Requirements

Admin or server operator group membership is required to successfully execute NetServerSetInfo.

NET_API_STATUS
NetServerSetInfo (

LPTSTR servername,
DWORD level,
LPBYTE buf,
LPDWORD parm_err
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

level

Level of information to set. 100, 101, and 102 are valid for all platforms. 302, 402, 403, and 502 are valid for the appropriate platform. In addition, 1001 − 1006, 1009 − 1011, 1016 − 1018, 1021, 1022, 1028, 1029, and 1037 − 1043 are valid based on the restrictions for downlevel systems described preceding.

buf

A pointer to a buffer containing the server information.

parm_err

Optional pointer to a DWORD to return the index of the first parameter in error when ERROR_INVALID_PARAMETER is returned. If NULL the parameter is not returned on error.


NetServerTransportAdd
NetServerTransportAdd  QuickInfo

NetServerTransportAdd binds the server to the transport.

Security Requirements

Admin group membership is required to successfully execute NetServerTransportAdd.

NET_API_STATUS
NetServerTransportAdd (

LPTSTR servername,
DWORD level,
LPBYTE bufptr
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

level

Level of information required. Only 0 is valid.

bufptr

A pointer to a buffer containing the server transport information structure.


NetServerTransportDel
NetServerTransportDel  QuickInfo

NetServerTransportDel unbinds the transport from the server.

Security Requirements

Admin group membership is required to successfully execute NetServerTransportDel.

NET_API_STATUS
NetServerTransportDel (

LPWSTR servername,
LPWSTR transportname
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

transportname

A pointer to a Unicode string containing the name of the transport from which to unbind.


NetServerTransportEnum
NetServerTransportEnum  QuickInfo

NetServerTransportEnum supplies information about transports that are managed by the server.

Security Requirements

No special group membership is required to successfully execute NetServerTransportEnum.

NET_API_STATUS
NetServerTransportEnum (

LPTSTR servername,
DWORD level,
LPBYTE * bufptr,
DWORD prefmaxlen,
LPDWORD entriesread,
LPDWORD totalentries,
LPDWORD resumehandle
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

level

Level of information required. Only 0 is valid.

bufptr

On return a pointer to the return information structure is returned in the address pointed to by bufptr.

prefmaxlen

Preferred maximum length of returned data (in 8-bit bytes).

entriesread

On return the actual enumerated element count is located in the DWORD pointed to by entriesread.

totalentries

On return the total number of entries that could have been enumerated from the current resume position is located in the DWORD pointed to by totalentries.

resumehandle

On return, a resume handle is stored in the DWORD pointed to by resumehandle, and is used to continue an existing server transport search. The handle should be zero on the first call and left unchanged for subsequent calls. If resumehandle is NULL, then no resume handle is stored.


NetServiceControl
NetServiceControl  QuickInfo

NetServiceControl controls the operations of network services.

Security Requirements

Admin, Power User or Server Operator group membership is required to successfully execute NetServiceControl unless the value of the opcode parameter is SERVICE_CTRL_INTERROGATE. In that case, no special group membership is required.

NET_API_STATUS
NetServiceControl (

LPTSTR servername,
LPTSTR service,
DWORD opcode,
DWORD arg,
LPBYTE * bufptr
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

service

A pointer to a Unicode string containing the name of the service to receive the control command.

opcode

Control code to send to service:

Value	Meaning
SERVICE_CTRL_INTERROGATE	Obtain the status of the service
SERVICE_CTRL_PAUSE	Pause the service
SERVICE_CTRL_CONTINUE	Continue the paused service
SERVICE_CTRL_UNINSTALL	Stop the service
arg

Service specific contol argument to send to service

bufptr

A pointer to the return information structure is returned in the address pointed to by bufptr.


NetServiceEnum
NetServiceEnum  QuickInfo

NetServiceEnum retrieves information about all started services, including paused services.

Security Requirements

No special group membership is required to successfully execute NetServiceEnum.

NET_API_STATUS
NetServiceEnum (

LPTSTR servername,
DWORD level,
LPBYTE * bufptr,
DWORD prefmaxlen,
LPDWORD entriesread,
LPDWORD totalentries,
LPDWORD resume_handle
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

level

Level of information required, 0, 1, and 2 are valid.

bufptr

On return a pointer to the return information structure is returned in the address pointed to by bufptr.

prefmaxlen

Prefered maximum length of returned data (in 8-bit bytes).

entriesread

On return the actual enumerated element count is located in the DWORD pointed to by entriesread.

totalentries

On return the total number of entries that could have been enumerated from the current resume position is located in the DWORD pointed to by totalentries.

resume_handle

On return, a resume handle is stored in the DWORD pointed to by resume_handle, and is used to continue an existing service search. The handle should be zero on the first call and left unchanged for subsequent calls. If resume_handle is NULL, then no resume handle is stored.


NetServiceGetInfo
NetServiceGetInfo  QuickInfo

NetServiceGetInfo retrieves information about a particular started service.

Security Requirements

No special group membership is required to successfully execute NetServiceGetInfo.

NET_API_STATUS
NetServiceGetInfo (

LPTSTR servername,
LPTSTR service,
DWORD level,
LPBYTE * bufptr
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

service

A pointer to a Unicode string containing the name of the service.

level

Level of information required. 0, 1, and 2 are valid.

bufptr

On return a pointer to the return information structure is returned in the address pointed to by bufptr.


NetServiceInstall
NetServiceInstall  QuickInfo

NetServiceInstall starts a network service.

Security Requirements

Admin, Power User or Server Operator group membership is required to successfully execute NetServiceInstall.

NET_API_STATUS
NetServiceInstall (

LPTSTR servername,
LPTSTR service,
DWORD argc,
LPTSTR argv[ ],
LPBYTE * bufptr
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

service

A pointer to a Unicode string containing the name of the service to start.

bufptr

On return a pointer to a SERVICE_INFO_2 structure is returned in the address pointed to by bufptr.

cmdargs

A pointer to a set of command line arguments to pass to the starting service as command line arguments.


NetSessionDel
NetSessionDel  QuickInfo

NetSessionDel ends a session between a server and a workstation.

Security Requirements

Admin or server operator group membership is required to successfully execute NetSessionDel.

NET_API_STATUS
NetSessionDel (

LPTSTR servername,
LPTSTR UncClientName,
LPTSTR username,
DWORD reserved
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

UncClientName

A pointer to a Unicode string containing the computer name of the client to disconnect. If UncClientName is NULL, then all the sessions of the user in username will be deleted on the server specified.

username

A pointer to a Unicode string containing the name of the user whose session is to be terminated. A NULL indicates that all users' sessions from the client name specified are to be terminated.

reserved

Reserved, must be zero.


NetSessionEnum
NetSessionEnum  QuickInfo

NetSessionEnum provides information about all current sessions.

Security Requirements

Admin or server operator group membership is required to successfully execute NetSessionEnum at level 1 or level 2. No special group membership is required for level 0 or level 10 calls.

NET_API_STATUS
NetSessionEnum (

LPTSTR servername,
LPTSTR UncClientName,
LPTSTR username,
DWORD level,
LPBYTE * bufptr,
DWORD prefmaxlen,
LPDWORD entriesread,
LPDWORD totalentries,
LPDWORD resume_handle
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

UncClientName

A pointer to a Unicode string containing the name of the computer session for which information is to be returned. A NULL pointer or string specifies that all computer sessions on the server are to be enumerated.

username

A pointer to a Unicode string containing the name of the the user for which to enumerate the sessions. A NULL pointer or string specifies that sessions for all users are to be enumerated.

level

Level of information required. 0, 1, 2, and 10 are valid.

bufptr

On return a pointer to the return information structure is returned in the address pointed to by bufptr.

prefmaxlen

Prefered maximum length of returned data (in 8-bit bytes).

entriesread

On return the actual enumerated element count is located in the DWORD pointed to by entriesread.

totalentries

On return the total number of entries that could have been enumerated from the current resume position is located in the DWORD pointed to by totalentries.

resume_handle

On return, a resume handle is stored in the DWORD pointed to by resume_handle, and is used to continue an existing session search. The handle should be zero on the first call and left unchanged for subsequent calls. If resume_handle is NULL, then no resume handle is stored.


NetSessionGetInfo
NetSessionGetInfo  QuickInfo

NetSessionGetInfo retrieves information about a session established between a particular server and workstation.

Security Requirements

Admin or server operator group membership is required to successfully execute NetSessionGetInfo at level 1 or level 2. No special group membership is required for level 0 or level 10 calls.

NET_API_STATUS
NetSessionGetInfo (

LPTSTR servername,
LPTSTR UncClientName,
LPTSTR username,
DWORD level,
LPBYTE * bufptr
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

UncClientName

A pointer to a Unicode string containing the name of the computer session for which information is to be returned. This field cannot be NULL.

username

A pointer to a Unicode string containing the name of the user whose session information is to be returned. This field cannot be NULL.

level

Level of information required. 0, 1, 2, and 10 are valid.

bufptr

On return a pointer to the return information structure is returned in the address pointed to by bufptr.


NetShareAdd
NetShareAdd  QuickInfo

NetShareAdd shares a server resource.

Security Requirements

Admin or comm, print, or server operator group membership is required to successfully execute NetShareAdd. The print operator can add only printer queues. The comm operator can add only communication-device queues.

NET_API_STATUS
NetShareAdd (

LPTSTR servername,
DWORD level,
LPBYTE buf,
LPDWORD parm_err
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

level

Level of information provided. Must be 2 or 502.

buf

A pointer to a buffer containing the share information structure.

parm_err

Optional pointer to a DWORD to return the index of the first parameter in error when ERROR_INVALID_PARAMETER is returned. If NULL the parameter is not returned on error.


NetShareCheck
NetShareCheck  QuickInfo

NetShareCheck checks whether or not a server is sharing a device.

Security Requirements

No special group membership is required to successfully execute NetShareCheck.

NET_API_STATUS
NetShareCheck (

LPTSTR servername,
LPTSTR device,
LPDWORD type
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

device

A pointer to a Unicode string containing the name of the device to check for shared access.

type

On return the address pointed to by the type parameter contains the type of share the device is offered with. This field is set only if success was returned.


NetShareDel
NetShareDel  QuickInfo

NetShareDel deletes a share name from a server's list of shared resources, disconnecting all connections to the shared resource.

Security Requirements

Admin or comm, print, or server operator group membership is required to successfully execute NetShareDel. The print operator can delete only printer queues. The comm operator can delete only communication-device queues.

NET_API_STATUS
NetShareDel (

LPTSTR servername,
LPTSTR netname,
DWORD reserved
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

netname

A pointer to a Unicode string containing the netname of the share to delete.

reserved

Reserved, must be zero.


NetShareEnum
NetShareEnum  QuickInfo

NetShareEnum retrieves information about each shared resource on a server. The NetShareEnum function is obsolete. It is provided only for compatibility with LAN Manager and 16-bit versions of Windows. Win32-based applications should use the WNetEnumResource function.

Security Requirements

Admin or comm, print, or server operator group membership is required to successfully execute NetShareEnum at level 2. No special group membership is required for level 0 or level 1 calls.

NET_API_STATUS
NetShareEnum (

LPTSTR servername,
DWORD level,
LPBYTE * bufptr,
DWORD prefmaxlen,
LPDWORD entriesread,
LPDWORD totalentries,
LPDWORD resume_handle
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

level

Level of information required. 0, 1, 2, and 502 are valid.

bufptr

On return a pointer to the return information structure is returned in the address pointed to by bufptr.

prefmaxlen

Prefered maximum length of returned data (in 8-bit bytes).

entriesread

On return the actual enumerated element count is located in the DWORD pointed to by entriesread.

totalentries

On return the total number of entries that could have been enumerated from the current resume position is located in the DWORD pointed to by totalentries.

resume_handle

On return, a resume handle is stored in the DWORD pointed to by resume_handle, and is used to continue an existing share search. The handle should be zero on the first call and left unchanged for subsequent calls. If resume_handle is NULL, then no resume handle is stored.


NetShareGetInfo
NetShareGetInfo  QuickInfo

NetShareGetInfo retrieves information about a particular shared resource on a server.

Security Requirements

Admin or comm, print, or server operator group membership is required to successfully execute NetShareGetInfo at level 2. No special group membership is required for level 0 or level 1 calls.

NET_API_STATUS
NetShareGetInfo (

LPTSTR servername,
LPTSTR netname,
DWORD level,
LPBYTE * bufptr
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

netname

A pointer to a Unicode string containing the netname of the share to return information on.

level

Level of information required. 0, 1, 2, and 502 are valid.

bufptr

On return a pointer to the return information structure is returned in the address pointed to by bufptr.


NetShareSetInfo
NetShareSetInfo  QuickInfo

NetShareSetInfo sets the parameters of a shared resource.

Security Requirements

Admin or comm, print, or server operator group membership is required to successfully execute NetShareSetInfo. The print operator can set information only about printer queues. The comm operator can set information only about communication-device queues.

NET_API_STATUS
NetShareSetInfo (

LPTSTR servername,
LPTSTR netname,
DWORD level,
LPBYTE buf,
LPDWORD parm_err
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

netname

A pointer to a Unicode string containing the netname of the share to set information on.

level

Level of information to set. 1, 2, 502, 1004 − 1006, and 1501 are valid.

buf

A pointer to a buffer containing the share information.

parm_err

Optional pointer to a DWORD to return the index of the first parameter in error when ERROR_INVALID_PARAMETER is returned. If NULL the parameter is not returned on error.


NetStatisticsGet
NetStatisticsGet  QuickInfo

NetStatisticsGet retrieves operating statistics for a service. Currently, only the Workstation and Server services are supported.

Security Requirements

Admin or server operator group membership is required to successfully execute NetStatisticsGet on a remote server.

NET_API_STATUS
NetStatisticsGet (

LPTSTR server,
LPTSTR service,
DWORD level,
DWORD options,
LPBYTE * bufptr
);
Parameters

server

Points to a Unicode string that contains the name of the server on which to execute NetConfigGet. A NULL pointer or NULL string specifies the local computer.

service

Points to a Unicode string that contains the name of the service about which to get the statistics. Only the values SERVER and WORKSTATION are currently allowed.

level

Specifies the level of detail requested; must be 0.

options

Must be 0.

bufptr

On return a pointer to the returned information is returned in the address pointed to by bufptr.


NetUseAdd
NetUseAdd  QuickInfo

NetUseAdd establishes a connection between a local or NULL device name and a shared resource by redirecting the local or NULL (UNC) device name to the shared resource. The NetUseAdd function is obsolete. It is provided only for compatibility with LAN Manager and 16-bit versions of Windows. Win32-based applications should use the WNetAddConnection2 function.

Security Requirements

No special group membership is required for this call. This function cannot be executed on a remote server.

NET_API_STATUS
NetUseAdd (

LPTSTR UncServerName,
DWORD Level,
LPBYTE Buf,
LPDWORD ParmError
);
Parameters

UncServerName

Must be NULL.

Level

Level of information to set. 1 and 2 are valid.

Buf

A pointer to a buffer containing the use information structure.

ParmError

Optional pointer to a DWORD to return the index of the first parameter in error when ERROR_INVALID_PARAMETER is returned. If NULL the parameter is not returned on error.


NetUseDel
NetUseDel  QuickInfo

NetUseDel ends a connection to a shared resource. The NetUseDel function is obsolete. It is provided only for compatibility with LAN Manager and 16-bit versions of Windows. Win32-based applications should use the WNetCancelConnection2 function.

Security Requirements

No special group membership is required for this call. This function cannot be executed on a remote server.

NET_API_STATUS
NetUseDel (

LPTSTR UncServerName,
LPTSTR UseName,
DWORD ForceCond
);
Parameters

UncServerName

Must be NULL.

UseName

A pointer to a Unicode string containing the path of the use to delete.

ForceCond

Level of force to use in deleting the use.


NetUseEnum
NetUseEnum  QuickInfo

NetUseEnum lists all current connections between the local computer and resources on remote servers. The NetUseEnum function is obsolete. It is provided only for compatibility with LAN Manager and 16-bit versions of Windows. Win32-based applications should use the WNetEnumResource function.

Security Requirements

No special group membership is required for this call. This function cannot be executed on a remote server.

NET_API_STATUS
NetUseEnum (

LPTSTR UncServerName,
DWORD Level,
LPBYTE * BufPtr,
DWORD PreferredMaximumSize,
LPDWORD EntriesRead,
LPDWORD TotalEntries,
LPDWORD ResumeHandle
);
Parameters

UncServerName

Must be NULL.

Level

Level of information provided. Must be 0, 1, or 2.

BufPtr

On return a pointer to the return information structure is returned in the address pointed to by BufPtr.

PreferredMaximumSize

Prefered maximum length of returned data (in 8-bit bytes).

EntriesRead

On return the actual enumerated element count is located in the DWORD pointed to by EntriesRead.

TotalEntries

On return the total number of entries that could have been enumerated from the current resume position is located in the DWORD pointed to by TotalEntries.

ResumeHandle

On return, a resume handle is stored in the DWORD pointed to by ResumeHandle, and is used to continue an existing use search. The handle should be zero on the first call and left unchanged for subsequent calls. If ResumeHandle is NULL, then no resume handle is stored.


NetUseGetInfo
NetUseGetInfo  QuickInfo

NetUseGetInfo retrieves information about a connection to a shared resource. The NetUseGetInfo function is obsolete. It is provided only for compatibility with LAN Manager and 16-bit versions of Windows. Win32-based applications should use the WNetGetConnection function.

Security Requirements

No special group membership is required for this call. This function cannot be executed on a remote server.

NET_API_STATUS
NetUseGetInfo (

LPTSTR UncServerName,
LPTSTR UseName,
DWORD Level,
LPBYTE * BufPtr
);
Parameters

UncServerName

Must be NULL.

UseName

A pointer to a Unicode string containing the local or remote name active use to return information on.

Level

Level of information required. 0, 1, and 2 are valid.

BufPtr

On return a pointer to the return information structure is returned in the address pointed to by BufPtr.


NetUserAdd
NetUserAdd  QuickInfo

NetUserAdd adds a user account.

Security Requirements

Admin or account operator group membership is required to successfully execute NetUserAdd.

NET_API_STATUS
NetUserAdd (

LPWSTR servername,
DWORD level,
LPBYTE buf,
LPDWORD parm_err
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

level

Level of information provided. Must be 1, 2, or 3.

buf

A pointer to a buffer containing the user information structure.

parm_err

Optional pointer to a DWORD to return the index of the first parameter in error when ERROR_INVALID_PARAMETER is returned. If NULL the parameter is not returned on error.


NetUserChangePassword [New - Windows NT]
NetUserChangePassword  QuickInfo

[New - Windows NT]

The NetUserChangePassword function changes a user's password for a specified network server or domain.

Security Requirements

A server or domain can be configured to require that a user log on to change the password on a user account. If that is the case, you need administrator or account operator access to change the password for another user acount. If logging on is not required, you can change the password for any user account, so long as you know the current password.

NET_API_STATUS NetUserChangePassword(

LPWSTR  domainname,	// pointer to server or domain name string
LPWSTR  username,	// pointer to user name string
LPWSTR  oldpassword,	// pointer to old password string
LPWSTR  newpassword,	// pointer to new password string
);
Parameters

domainname

Pointer to a null-terminated Unicode string that specifies the name of a remote server or domain. The NetUserChangePassword function changes the user's password on that remote server or domain.

A domainname value of NULL specifies the logon domain of the caller.

username

Pointer to a null-terminated Unicode string that specifies a user name. The NetUserChangePassword function changes the password for that user.

A username value of NULL specifies the logon user name of the caller.

oldpassword

Pointer to a null-terminated Unicode string that specifies the user's old password on the server or domain.

newpassword

Pointer to a null-terminated Unicode string that specifies the user's new password on the server or domain.

Return Value

The function returns a NET_API_STATUS value.


NetUserDel
NetUserDel  QuickInfo

NetUserDel deletes a user account from the accounts database.

Security Requirements

Admin or account operator group membership is required to successfully execute NetUserDel.

NET_API_STATUS
NetUserDel (

LPWSTR servername,
LPWSTR username
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

username

A pointer to a Unicode string containing the name of the user account to delete.


NetUserEnum
NetUserEnum  QuickInfo

NetUserEnum provides resumable enumeration of information about each user account in a domain.

Security Requirements

Admin or account operator group membership is required to successfully execute NetUserEnum at levels 1 and 2. No special group membership is required at level 0 or 10.

NET_API_STATUS
NetUserEnum (

LPWSTR servername,
DWORD level,
DWORD filter,
LPBYTE * bufptr,
DWORD prefmaxlen,
LPDWORD entriesread,
LPDWORD totalentries,
LPDWORD resumehandle
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

level

Level of information required. 0, 1, 2, 3, 10, 11, and 20 are valid.

filter

Specifies a filter of account types ot enumerate. 0 implies all account types. Allowable values are:

FILTER_TEMP_DUPLICATE_ACCOUNTS

FILTER_NORMAL_ACCOUNT

FILTER_INTERDOMAIN_TRUST_ACCOUNT

FILTER_WORKSTATION_TRUST_ACCOUNT

FILTER_SERVER_TRUST_ACCOUNT

bufptr

On return a pointer to the return information structure is returned in the address pointed to by bufptr.

prefmaxlen

Preferred maximum length of returned data (in 8-bit bytes).

entriesread

On return the actual enumerated element count is located in the DWORD pointed to by entriesread.

totalentries

On return the total number of entries that could have been enumerated from the current resume position is located in the DWORD pointed to by totalentries. EXCEPTION: If the call is to a computer that is running OS/2 LANMAN, the totalentries will always reflect the total number of entries in the database no matter where it is in the resume sequence.

resumehandle

On return, a resume handle is stored in the DWORD pointed to by resumehandle and is used to continue an existing user search. The handle should be zero on the first call and left unchanged for subsequent calls. If resumehandle is NULL, then no resume handle is stored.


NetUserGetGroups
NetUserGetGroups  QuickInfo

NetUserGetGroups retrieves a list of global groups to which a specified user belongs.

Security Requirements

Admin or account operator group membership is required to successfully execute NetUserGetGroups.

NET_API_STATUS
NetUserGetGroups (

LPWSTR servername,
LPWSTR username,
DWORD level,
LPBYTE * bufptr,
DWORD prefmaxlen,
LPDWORD entriesread,
LPDWORD totalentries
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

username

A pointer to a Unicode string containing the name of the user to return global group membership for.

level

Level of information required. Only 0 or 1 are valid.

bufptr

On return a pointer to the return information structure is returned in the address pointed to by bufptr. The returned information is an array of GROUP_USERS_INFO_x structures.

prefmaxlen

Prefered maximum length of returned data (in 8-bit bytes).

entriesread

On return the actual enumerated element count is located in the DWORD pointed to by entriesread.

totalentries

On return the total number of entries that could have been enumerated from the current resume position is located in the b pointed to by totalentries.


NetUserGetInfo
NetUserGetInfo  QuickInfo

NetUserGetInfo retrieves information about a particular user account on a server.

Security Requirements

No special group membership is required to successfully execute NetUserGetInfo. This is a change from LAN Manager, which required administer or account operator privilege to call this function at information levels above 0 (except for the user's own account, which could use level 11).

NET_API_STATUS
NetUserGetInfo (

LPWSTR servername,
LPWSTR username,
DWORD level,
LPBYTE * bufptr
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

username

A pointer to a Unicode string containing the name of the user account on which to return information.

level

Level of information required. 0, 1, 2, 3,10,11, and 20 are valid.

bufptr

A pointer to the return information structure is returned in the address pointed to by bufptr.


NetUserGetLocalGroups
NetUserGetLocalGroups  QuickInfo

NetUserGetLocalGroups retrieves a list of local groups to which a specified user belongs.

Security Requirements

Admin or account operator group membership is required to successfully execute NetUserGetLocalGroups.

NET_API_STATUS
NetUserGetLocalGroups (

LPWSTR servername,
LPWSTR username,
DWORD level,
DWORD flags,
LPBYTE * bufptr,
DWORD prefmaxlen,
LPDWORD entriesread,
LPDWORD totalentries
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

username

A pointer to a Unicode string containing the name of the user to return global group membership for.

level

Level of information required. Only 0 is valid.

flags

Bitmask of flags. Currently, only LG_INCLUDE_INDIRECT is defined. If this bit is set, the function will also return localgroups the user is a member of indirectly (i.e., by the virtue of being in a globalgroup that itself is a member of one or more localgroups).

bufptr

On return a pointer to the return information structure is returned in the address pointed to by bufptr. The returned information is an array of LOCALGROUP_USERS_INFO_0 structures.

prefmaxlen

Preferred maximum length of returned data (in 8-bit bytes).

entriesread

On return the actual enumerated element count is located in the DWORD pointed to by entriesread.

totalentries

On return the total number of entries that could have been enumerated from the current resume position is located in the DWORD pointed to by totalentries.


NetUserModalsGet
NetUserModalsGet  QuickInfo

NetUserModalsGet retrieves global information for all users and global groups in the user account database.

Security Requirements

Admin or account operator group membership is required to successfully execute NetUserModalsGet.

NET_API_STATUS
NetUserModalsGet (

LPWSTR servername,
DWORD level,
LPBYTE * bufptr
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

level

Level of information required. 0, 1, and 2 are valid.

bufptr

A pointer to the return information structure is returned in the address pointed to by bufptr.


NetUserModalsSet
NetUserModalsSet  QuickInfo

NetUserModalsSet sets global information for all users and global groups in the user account database.

Security Requirements

Admin or account operator group membership is required to successfully execute NetUserModalsSet.

NET_API_STATUS
NetUserModalsSet (

LPWSTR servername,
DWORD level,
LPBYTE buf,
LPDWORD parm_err
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

username

A pointer to a Unicode string containing the name of the user account to set information on.

level

Level of information to set. 0, 1, and 2 are valid.

buf

A pointer to a buffer containing the user modals information.

parm_err

Optional pointer to a DWORD to return the index of the first parameter in error when ERROR_INVALID_PARAMETER is returned. If NULL the parameter is not returned on error.


NetUserSetGroups
NetUserSetGroups  QuickInfo

NetUserSetGroups sets global group memberships for a specified user account.

Security Requirements

Admin or account operator group membership is required to successfully execute NetUserSetGroups.

NET_API_STATUS
NetUserSetGroups (

LPWSTR servername,
LPWSTR username,
DWORD level,
LPBYTE buf,
DWORD num_entries
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

username

A pointer to a Unicode string containing the name of the user to set global group memberships for.

level

Level of information required. Only 0 or 1 are valid.

buf

A pointer to an array of global groups information structures.

num_entries

Number of global group information structures contained in the array pointed to by buf.


NetUserSetInfo
NetUserSetInfo  QuickInfo

NetUserSetInfo sets the parameters of a user account.

Security Requirements

Admin or account operator group membership is required to successfully execute NetUserSetInfo. A user may call NetUserSetInfo to set certain information on his/her own account.

NET_API_STATUS
NetUserSetInfo (

LPWSTR servername,
LPWSTR username,
DWORD level,
LPBYTE buf,
LPDWORD parm_err
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

username

A pointer to a Unicode string containing the name of the user account to set information on.

level

Level of information to set. 0, 1, 2, 3, or 20.

buf

A pointer to a buffer containing the user information.

parm_err

Optional pointer to a DWORD to return the index of the first parameter in error when ERROR_INVALID_PARAMETER is returned. If NULL the parameter is not returned on error.


NetWkstaGetInfo
NetWkstaGetInfo  QuickInfo

NetWkstaGetInfo returns information about the configuration elements for a workstation.

Security Requirements

Security requirements are described with the data structures for the information levels above.

NET_API_STATUS
NetWkstaGetInfo (

LPTSTR servername,
DWORD level,
LPBYTE * bufptr
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

level

Level of information required. 100, 101, 102, 302, 402, and 502 are valid.

bufptr

On return a pointer to the return information structure is returned in the address pointed to by bufptr.


NetWkstaSetInfo
NetWkstaSetInfo  QuickInfo

NetWkstaSetInfo configures a workstation. This information is stored such that it remains in effect after the system has been reinitialized.

Security Requirements

Admin group membership is required to successfully execute NetWkstaSetInfo.

NET_API_STATUS
NetWkstaSetInfo (

LPTSTR servername,
DWORD level,
LPBYTE buf,
LPDWORD parm_err
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

level

Level of information to set. 100, 101, 102, 302, 402, and 502 are valid. In addition, 1010 − 1013, 1018, 1023, 1027, 1028, 1032, 1033, 1035, and 1041-1062 are valid based on the restrictions mentioned preceding.

buf

A pointer to a buffer containing the workstation information.

parm_err

Optional pointer to a DWORD to return the index of the first parameter in error when ERROR_INVALID_PARAMETER is returned. If NULL the parameter is not returned on error.


NetWkstaTransportAdd
NetWkstaTransportAdd  QuickInfo

NetWkstaTransportAdd binds the redirector to the transport.

Security Requirements

Admin group membership is required to successfully execute NetWkstaTransportAdd.

NET_API_STATUS
NetWkstaTransportAdd (

LPTSTR servername,
DWORD level,
LPBYTE buf
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

level

Level of information required. Only 0 is valid.

buf

A pointer to a buffer containing the server transport information structure.


NetWkstaTransportDel
NetWkstaTransportDel  QuickInfo

NetWkstaTransportDel unbinds the transport from the redirector.

Security Requirements

Admin group membership is required to successfully execute NetWkstaTransportDel.

NET_API_STATUS
NetWkstaTransportDel (

LPTSTR servername,
LPTSTR transportname,
DWORD ucond
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

transportname

A pointer to a Unicode string containing the name of the transport from which to unbind.

ucond

Force level to delete connections on the transport binding.


NetWkstaTransportEnum
NetWkstaTransportEnum  QuickInfo

NetWkstaTransportEnum supplies information about transports that are managed by the redirector.

Security Requirements

No special group membership is required to successfully execute NetWkstaTransportEnum.

NET_API_STATUS
NetWkstaTransportEnum (

LPTSTR servername,
DWORD level,
LPBYTE * bufptr,
DWORD prefmaxlen,
LPDWORD entriesread,
LPDWORD totalentries,
LPDWORD resumehandle
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

level

Level of information required. Only 0 is valid.

bufptr

On return a pointer to the return information structure is returned in the address pointed to by bufptr.

prefmaxlen

Preferred maximum length of returned data (in 8-bit bytes).

entriesread

On return the actual enumerated element count is located in the DWORD pointed to by entriesread.

totalentries

On return the total number of entries that could have been enumerated from the current resume position is located in the DWORD pointed to by totalentries.

resumehandle

On return, a resume handle is stored in the DWORD pointed to by resumehandle, and is used to continue an existing workstation transport search. The handle should be zero on the first call and left unchanged for subsequent calls. If resumehandle is NULL, then no resume handle is stored.


NetWkstaUserEnum
NetWkstaUserEnum  QuickInfo

NetWkstaUserEnum lists information about all current users on the workstation.

Security Requirements

Admin group membership is required to successfully execute NetWkstaUserEnum both locally and on a remote server.

NET_API_STATUS
NetWkstaUserEnum (

LPTSTR servername,
DWORD level,
LPBYTE * bufptr,
DWORD prefmaxlen,
LPDWORD entriesread,
LPDWORD totalentries,
LPDWORD resumehandle
);
Parameters

servername

A pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

level

Level of information provided. Must be 0 or 1.

bufptr

On return a pointer to the return information structure is returned in the address pointed to by bufptr.

prefmaxlen

Prefered maximum length of returned data (in 8-bit bytes).

entriesread

On return the actual enumerated element count is located in the DWORD pointed to by entriesread.

totalentries

On return the total number of entries that could have been enumerated from the current resume position is located in the DWORD pointed to by totalentries.

resumehandle

On return, a resume handle is stored in the DWORD pointed to by resumehandle, and is used to continue an existing use search. The handle should be zero on the first call and left unchanged for subsequent calls. If resumehandle is NULL, then no resume handle is stored.


NetWkstaUserGetInfo
NetWkstaUserGetInfo  QuickInfo

NetWkstaUserGetInfo returns the user-specific information about the configuration elements for a workstation.

Security Requirements

Security requirements are described with the data structures for the information levels above. This function only works locally.

NET_API_STATUS
NetWkstaUserGetInfo (

LPTSTR reserved,
DWORD level,
LPBYTE * bufptr
);
Parameters

reserved

This field must be set to NULL.

level

Level of information required. 0 and 1 are valid.

bufptr

On return a pointer to the return information structure is returned in the address pointed to by bufptr.


NetWkstaUserSetInfo
NetWkstaUserSetInfo  QuickInfo

NetWkstaUserSetInfo sets the user-specific information about the configuration elements for a workstation.

Security Requirements

Security requirements are described with the data structures for the information levels above. This function only works locally.

NET_API_STATUS
NetWkstaUserSetInfo (

LPTSTR reserved,
DWORD level,
LPBYTE * buf,
LPDWORD parm_err
);
Parameters

reserved

This field must be set to zero.

level

Level of information required. 0 and 1 are valid.

buf

On return a pointer to the return information structure is returned in the address pointed to by buf.

parm_err

Optional pointer to a DWORD to return the index of the first parameter in error when ERROR_INVALID_PARAMETER is returned. If NULL the parameter is not returned on error.


NotifyBootConfigStatus
NotifyBootConfigStatus  QuickInfo  Overview  Group

The NotifyBootConfigStatus function notifies the service control manager as to the acceptability of the configuration that booted the system.

An acceptable configuration triggers the storage of that configuration as the last-known good configuration; an unacceptable configuration triggers a system reboot.

BOOL NotifyBootConfigStatus(

BOOL  BootAcceptable	// indicates acceptability of boot configuration
);
Parameters

BootAcceptable

Specifies whether the configuration that booted the system is acceptable. If this parameter's value is TRUE, the service control manager saves the configuration that booted the system as the last-known good configuration. If the parameter's value is FALSE, the system immediately reboots, using the previously saved last-known good configuration.

Return Value

If the BootAcceptable parameter is FALSE, the function does not return.

If the last-known good configuration was successfully saved, the return value is TRUE.

If an error occurs, the return value is FALSE. To get extended error information, call GetLastError.

Errors

The following error codes may be set by the service control manager. Other error codes may be set by the registry functions that are called by the service control manager to deal with the configuration registry.

Value	Meaning
ERROR_ACCESS_DENIED	The caller does not have permission to perform this operation.  A hard-coded DACL associated with the service control manager object determines who can perform a NotifyBootConfigStatus operation. Only the operating system and members of the local adminstrators group can do so.
Remarks

The NotifyBootConfigStatus function is used to save the configuration from which  a running system was booted. This is a useful thing to do once the configuration has been checked and found to be acceptable. In this way, the latest acceptable modifications to the configuration are saved away as the last-known good configuration.

If the boot configuration is found to be unacceptable, this function can be called to instigate a reboot with the existing last-known good configuration. This function can only be called by a process running in the LocalSystem or the Administrator's security context.


NotifyChangeEventLog
NotifyChangeEventLog  QuickInfo  Overview  Group

The NotifyChangeEventLog function lets an application receive notification when an event is written to the event log file specified by hEventLog. When the event is written to the event log file, the function causes the event object specified by hEvent to become signaled.

BOOL NotifyChangeEventLog(

HANDLE  hEventLog,	// special default locale value to be converted
HANDLE  hEvent	// special default locale value to be converted
);
Parameters

hEventLog

Handle to an event log file, obtained by calling OpenEventLog. When an event is written to this log file, the event specified by hEvent becomes signaled.

hEvent

A handle to a Win32 event. This is the event that becomes signaled when an event is written to the event log file specified by hEventLog.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The NotifyChangeEventLog function does not work with remote handles. If hEventLog is the handle of an event log on a remote computer, the NotifiyChangeEventLog function returns FALSE, and GetLastError  returns ERROR_INVALID_HANDLE.

See Also

OpenEventLog


ntohl
ntohl  QuickInfo

The Windows Sockets ntohl function converts a u_long from network byte order to host byte order.

u_long ntohl (

u_long netlong
);
Parameters

netlong

A 32-bit number in network byte order.

Return Value

ntohl returns the value in host byte order.

Remarks

This function takes a 32-bit number in network byte order and returns a 32-bit number in host byte order.

See Also

htonl, htons, ntohs


ntohs
ntohs  QuickInfo

The Windows Sockets ntohs function converts a u_short from network byte order to host byte order.

u_short ntohs (

u_short netshort
);
Parameters

netshort

A 16-bit number in network byte order.

Return Value

ntohs returns the value in host byte order.

Remarks

This function takes a 16-bit number in network byte order and returns a 16-bit number in host byte order.

See Also

htonl, htons, ntohl


ObjectCloseAuditAlarm
ObjectCloseAuditAlarm  QuickInfo  Overview  Group

The ObjectCloseAuditAlarm function generates audit messages when a handle of an object is deleted. Alarms are not supported in the current version of Windows NT.

BOOL ObjectCloseAuditAlarm(

LPCTSTR  SubsystemName,	// address of string for subsystem name
LPVOID  HandleId,	// address of handle identifier
BOOL  GenerateOnClose	// flag for audit generation
);
Parameters

SubsystemName

Points to a null-terminated string specifying the name of the subsystem calling the function, for example, "DEBUG" or "WIN32".

HandleId

Specifies a unique 32-bit value representing the client's handle of the object. This should be the same value that was passed to the AccessCheckAndAuditAlarm or ObjectOpenAuditAlarm function.

GenerateOnClose

Specifies a flag set by a call to the AccessCheckAndAuditAlarm or ObjectOpenAuditAlarm function when the object handle is created.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The ObjectCloseAuditAlarm function requires the calling application to have the SE_AUDIT_NAME privilege. The test for this privilege is always performed against the primary token of the calling process, allowing the calling process to impersonate a client.

The ObjectCloseAuditAlarm function may send many messages to port objects. This can result in a significant delay before the function returns. The design of applications calling ObjectCloseAuditAlarm can take this potential delay into account. For example, this consideration may affect the design of an application that uses mutexes to lock structures.

See Also

AccessCheck, AccessCheckAndAuditAlarm, AreAllAccessesGranted, AreAnyAccessesGranted, MapGenericMask, ObjectOpenAuditAlarm, ObjectPrivilegeAuditAlarm, PrivilegeCheck, PrivilegedServiceAuditAlarm


ObjectOpenAuditAlarm
ObjectOpenAuditAlarm  QuickInfo  Overview  Group

The ObjectOpenAuditAlarm function generates audit messages when a client application attempts to gain access to an object or to create a new one. Alarms are not supported in the current version of Windows NT.

BOOL ObjectOpenAuditAlarm(

LPCTSTR  SubsystemName,	// address of string for subsystem name
LPVOID  HandleId,	// address of handle identifier
LPTSTR  ObjectTypeName,	// address of string for object type
LPTSTR  ObjectName,	// address of string for object name
PSECURITY_DESCRIPTOR  pSecurityDescriptor,	// address of security descriptor
HANDLE  ClientToken,	// handle of client's access token
DWORD  DesiredAccess,	// mask for desired access rights
DWORD  GrantedAccess,	// mask for granted access rights
PPRIVILEGE_SET  Privileges,	// address of privileges
BOOL  ObjectCreation,	// flag for object creation
BOOL  AccessGranted,	// flag for results
LPBOOL  GenerateOnClose	// address of flag for audit generation
);
Parameters

SubsystemName

Points to a null-terminated string specifying the subsystem calling this function, for example, "DEBUG" or "WIN32".

HandleId

Points to a unique 32-bit value representing the client's handle of the object. If the access is denied, this parameter is ignored.

ObjectTypeName

Points to a null-terminated string specifying the type of object to which the client is requesting access. This string appears in the audit log for the object.

ObjectName

Points to a null-terminated string specifying the name of the object to which the client gained access or attempted to gain access. This string appears in the audit log for the object.

pSecurityDescriptor

Points to the SECURITY_DESCRIPTOR structure for the object being accessed.

ClientToken

Identifies an access token representing the client requesting the operation. This handle must be obtained by opening the token of a thread impersonating the client. The token must be open for TOKEN_QUERY access.

DesiredAccess

Specifies the desired access mask. This mask must have been previously mapped by the MapGenericMask function to contain no generic access rights.

GrantedAccess

Specifies an access mask indicating which access rights are granted. This access mask is intended to be the same value set by one of the access-checking functions in its GrantedAccess parameter. Examples of access-checking functions include AccessCheckAndAuditAlarm and AccessCheck.

Privileges

Points to a PRIVILEGE_SET structure that specifies the set of privileges required for the access attempt. This parameter can be NULL.

ObjectCreation

Specifies a flag that determines whether the application creates a new object when access is granted. When this flag is TRUE, the application creates a new object; when it is FALSE, the application opens an existing object.

AccessGranted

Specifies a flag indicating whether access was granted or denied in a previous call to an access-checking function, such as AccessCheck. If access was granted, this flag is TRUE. If not, it is FALSE.

GenerateOnClose

Points to a flag set by the audit-generation routine when the function returns. This flag must be passed to the ObjectCloseAuditAlarm function when the object handle is closed.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The ObjectOpenAuditAlarm function requires the calling application to have the SE_AUDIT_NAME privilege. The test for this privilege is always performed against the primary token of the calling process, not the impersonation token of the thread. This allows the calling process to impersonate a client during the call.

The ObjectOpenAuditAlarm function may send many messages to port objects. This can result in a significant delay before the function returns. The design of applications calling ObjectOpenAuditAlarm can take this potential delay into account. For example, this consideration may affect the design of an application using mutexes to lock structures.

See Also

AccessCheck, AccessCheckAndAuditAlarm, AreAllAccessesGranted, AreAnyAccessesGranted, MapGenericMask, ObjectCloseAuditAlarm, ObjectPrivilegeAuditAlarm, PrivilegeCheck, PrivilegedServiceAuditAlarm, PRIVILEGE_SET, SECURITY_DESCRIPTOR,


ObjectPrivilegeAuditAlarm
ObjectPrivilegeAuditAlarm  QuickInfo  Overview  Group

The ObjectPrivilegeAuditAlarm function generates audit messages as a result of a client's attempt to perform a privileged operation on a server application object using an already opened handle of that object. Alarms are not supported in the current version of Windows NT.

BOOL ObjectPrivilegeAuditAlarm(

LPCTSTR  lpszSubsystem,	// address of string for subsystem name
LPVOID  lpvHandleId,	// address of handle identifier
HANDLE  hClientToken,	// handle of client's access token
DWORD  dwDesiredAccess,	// mask for desired access rights
PPRIVILEGE_SET  pps,	// address of privileges
BOOL  fAccessGranted	// flag for results
);
Parameters

lpszSubsystem

Points to a null-terminated string specifying the name of the subsystem calling the function; for example, "DEBUG" or "WIN32".

lpvHandleId

Points to a unique 32-bit value representing the client's handle of the object.

hClientToken

Identifies an access token representing the client requesting the operation. This handle must be obtained by opening the token of a thread impersonating the client. The token must be open for TOKEN_QUERY access.

dwDesiredAccess

Specifies an access mask indicating the privileged access types being used or whose use is being attempted. The access mask can be mapped by the MapGenericMask function so it does not contain any generic access types.

pps

Points to a PRIVILEGE_SET structure specifying the set of privileges required for the requested operation. The information in this structure is supplied by a call to the PrivilegeCheck function. This parameter can be NULL.

fAccessGranted

Specifies a flag indicating whether access was granted or denied in a previous call to an access-checking function such as PrivilegeCheck. If access was granted, this flag is TRUE. If not, it is FALSE.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The ObjectPrivilegeAuditAlarm function requires the calling process to have SE_AUDIT_NAME privilege. The test for this privilege is always performed against the primary token of the calling process, not the impersonation token of the thread. This allows the calling process to impersonate a client during the call.

The ObjectPrivilegeAuditAlarm function can send many messages to port objects. This can result in a significant delay before the function returns. The design of applications calling ObjectPrivilegeAuditAlarm can take this potential delay into account. For example, this consideration may affect the design of an application using mutexes to lock structures.

See Also

AccessCheck, AccessCheckAndAuditAlarm, AreAllAccessesGranted, AreAnyAccessesGranted, MapGenericMask, ObjectCloseAuditAlarm, ObjectOpenAuditAlarm, PrivilegeCheck, PrivilegedServiceAuditAlarm, PRIVILEGE_SET


OemKeyScan
OemKeyScan  QuickInfo  Overview  Group

The OemKeyScan function maps OEM ASCII codes 0 through 0x0FF into the OEM scan codes and shift states. The function provides information that allows a program to send OEM text to another program by simulating keyboard input.

DWORD OemKeyScan(

WORD  wOemChar	// ASCII value of OEM character
);
Parameters

wOemChar

Specifies the ASCII value of the OEM character.

Return Value

If the function succeeds, the low-order word of the return value contains the scan code of the given OEM character, and the high-order word contains the shift state, which can be a combination of the following flag bits:

Bit	Meaning
1	Either SHIFT key is pressed.
2	Either CTRL key is pressed.
4	Either ALT key is pressed.
If the character cannot be produced by a single keystroke using the current keyboard layout, the return value is 0xFFFFFFFF.

Remarks

This function does not provide translations for characters that require CTRL+ALT or dead keys. Characters not translated by this function must be copied by simulating input using the ALT+ keypad mechanism. The NUMLOCK key must be off.

This function does not provide translations for characters that cannot be typed with one keystroke using the current keyboard layout, such as characters with diacritics requiring dead keys. Characters not translated by this function may be simulated using the ALT+ keypad mechanism. The NUMLOCK key must be on.

This function is implemented using the VkKeyScan function.

See Also

VkKeyScan


OemToAnsi
OemToAnsi  QuickInfo  Overview  Group

The OemToAnsi function is obsolete.

For compatibility with 16-bit versions of Windows, this function is implemented as a macro that calls the OemToChar function, which should be used for new Win32-based applications.


OemToAnsiBuff
OemToAnsiBuff  QuickInfo  Overview  Group

The OemToAnsiBuff function is obsolete.

For compatibility with 16-bit versions of Windows, this function is implemented as a macro that calls the OemToCharBufffunction, which should be used for Win32-based applications.


OemToChar
OemToChar  QuickInfo  Overview  Group

The OemToChar function translates a string from the OEM-defined character set into either an ANSI or a wide-character string. (OEM stands for original equipment manufacturer.) This function supersedes the OemToAnsi function.

BOOL OemToChar(

LPCSTR  lpszOemStr,	// address of string to translate
LPTSTR  lpszStr	// address of buffer for translated string
);
Parameters

lpszOemStr

Points to a null-terminated string of characters from the OEM-defined character set.

lpszStr

Points to the buffer for the translated string. If the OemToChar function is being used as an ANSI function, the string can be translated in place by setting the lpszStr parameter to the same address as the lpszOemStr parameter. This cannot be done if OemToChar is being used as a wide-character function.

Return Value

The return value is always TRUE.

See Also

CharToOem, CharToOemBuff, OemToCharBuff


OemToCharBuff
OemToCharBuff  QuickInfo  Overview  Group

The OemToCharBuff function translates a specified number of characters in a string from the OEM-defined character set into either an ANSI or a wide-character string. (OEM stands for original equipment manufacturer.) This function supersedes the OemToAnsiBuff function.

BOOL OemToCharBuff(

LPCSTR  lpOemStr,	// address of string to translate
LPTSTR  lpszStr,	// address of buffer for translated string
DWORD  cchString	// size of buffer
);
Parameters

lpOemStr

Points to a buffer containing one or more characters from the OEM-defined character set.

lpszStr

Points to the buffer for the translated string. If the OemToCharBuff function is being used as an ANSI function, the string can be translated in place by setting the lpszStr parameter to the same address as the lpOemStr parameter. This cannot be done if the OemToCharBuff function is being used as a wide-character function.

cchString

Specifies the number of characters to translate in the buffer identified by the lpOemStr parameter.

Return Value

The return value is always TRUE.

See Also

CharToOem, CharToOemBuff, OemToChar


OffsetClipRgn
OffsetClipRgn  QuickInfo  Overview  Group

The OffsetClipRgn function moves the clipping region of a device context by the specified offsets.

int OffsetClipRgn(

HDC  hdc,	// handle of device context
int  nXOffset,	// offset along x-axis
int  nYOffset	// offset along y-axis
);
Parameters

hdc

Identifies the device context.

nXOffset

Specifies the number of logical units to move left or right.

nYOffset

Specifies the number of logical units to move up or down.

Return Value

If the function succeeds, the return value specifies the new region's complexity and can be any one of the following values:

Value	Meaning
NULLREGION	Region is empty.
SIMPLEREGION	Region is a single rectangle.
COMPLEXREGION	Region is more than one rectangle.
ERROR	An error occurred. (The current clipping region is unaffected.)
See Also

SelectClipRgn


OffsetRect
OffsetRect  QuickInfo  Overview  Group

The OffsetRect function moves the specified rectangle by the specified offsets.

BOOL OffsetRect(

LPRECT  lprc,	// address of structure with rectangle
int  x,	// horizontal offset
int  y	// vertical offset
);
Parameters

lprc

Points to a RECT structure that contains the logical coordinates of the rectangle to be moved.

x

Specifies the amount to move the rectangle left or right. This parameter must be a negative value to move the rectangle to the left.

y

Specifies the amount to move the rectangle up or down. This parameter must be a negative value to move the rectangle up.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

InflateRect, IntersectRect, UnionRect, RECT


OffsetRgn
OffsetRgn  QuickInfo  Overview  Group

The OffsetRgn function moves a region by the specified offsets.

int OffsetRgn(

HRGN  hrgn,	// handle of region
int  nXOffset,	// offset along x-axis
int  nYOffset	// offset along y-axis
);
Parameters

hrgn

Identifies the region to be moved.

nXOffset

Specifies the number of logical units to move left or right.

nYOffset

Specifies the number of logical units to move up or down.

Return Value

The return value specifies the new region's complexity. It can be one of the following values:

Value	Meaning
NULLREGION	Region is empty.
SIMPLEREGION	Region is a single rectangle.
COMPLEXREGION	Region is more than one rectangle.
ERROR	An error occurred; region is unaffected.


OffsetViewportOrg

The OffsetViewportOrg function is not implemented in the Win32 API. Win32-based applications should use the OffsetViewportOrgEx function.


OffsetViewportOrgEx
OffsetViewportOrgEx  QuickInfo  Overview  Group

The OffsetViewportOrgEx function modifies the viewport origin for a device context using the specified horizontal and vertical offsets.

BOOL OffsetViewportOrgEx(

HDC  hdc,	// handle of device context
int  nXOffset,	// horizontal offset
int  nYOffset,	// vertical offset
LPPOINT  lpPoint	// address of structure receiving original origin
);
Parameters

hdc

Identifies the device context.

nXOffset

Specifies the horizontal offset, in device units.

nYOffset

Specifies the vertical offset, in device units.

lpPoint

Points to a POINT structure. The previous viewport origin, in device units, is placed in this structure. If lpPoint is NULL, the previous viewport origin is not returned.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

The new origin is the sum of the current origin and the horizontal and vertical offsets.

See Also

GetViewportOrgEx, OffsetWindowOrgEx, SetViewportOrgEx


OffsetWindowOrg

The OffsetWindowOrg function is not implemented in the Win32 API. Win32-based applications should use the OffsetWindowOrgEx function.


OffsetWindowOrgEx
OffsetWindowOrgEx  QuickInfo  Overview  Group

The OffsetWindowOrgEx function modifies the window origin for a device context using the specified horizontal and vertical offsets.

BOOL OffsetWindowOrgEx(

HDC  hdc,	// handle of device context
int  nXOffset,	// horizontal offset
int  nYOffset,	// vertical offset
LPPOINT  lpPoint	// address of structure receiving the original origin
);
Parameters

hdc

Identifies the device context.

nXOffset

Specifies the horizontal offset, in logical units.

nYOffset

Specifies the vertical offset, in logical units.

lpPoint

Points to a POINT structure. The logical coordinates of the previous window origin are placed in this structure. If lpPoint is NULL, the previous origin is not returned.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

GetViewportOrgEx, OffsetViewportOrgEx, POINT


OpenBackupEventLog
OpenBackupEventLog  QuickInfo  Overview  Group

The OpenBackupEventLog function opens a handle of a backup event log. This handle can be used with the BackupEventLog function.

HANDLE OpenBackupEventLog(

LPCTSTR  lpszUNCServerName,	// backup file server name
LPCTSTR  lpszFileName	// backup filename
);
Parameters

lpszUNCServerName

Points to a null-terminated string that specifies the Universal Naming Convention (UNC) name of the server on which this operation is to be performed. If this parameter is NULL, the operation is performed on the local computer.

lpszFileName

Points to a null-terminated string that specifies the name of the backup file. The backup filename may contain a server name to open a backup file on a remote server (in this case, the lpszUNCServerName parameter must be NULL).

Return Value

If the function succeeds, the return value is a handle of the backup event log.

If the function fails, the return value is NULL.

Remarks

If the backup filename specifies a remote server, lpszUNCServerName must be NULL. You cannot use this function to open a file on a remote server.

See Also

BackupEventLog


OpenClipboard
OpenClipboard  QuickInfo  Overview  Group

The OpenClipboard function opens the clipboard for examination and prevents other applications from modifying the clipboard content.

BOOL OpenClipboard(

HWND  hwnd	// handle of window opening clipboard
);
Parameters

hwnd

Identifies the window to be associated with the open clipboard. If this parameter is NULL, the open clipboard is associated with the current task.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

OpenClipboard fails if another window has the clipboard open.

An application should call the CloseClipboard function after every successful call to OpenClipboard.

The window identified by the hwnd parameter does not become the clipboard owner unless the EmptyClipboard function is called.

See Also

CloseClipboard, EmptyClipboard


OpenDesktop [New - Windows NT]
OpenDesktop  QuickInfo  Overview  Group

[New - Windows NT]

The OpenDesktop function returns a handle to an existing desktop. A desktop is a secure object contained within a window station object. A desktop has a logical display surface and contains windows, menus and hooks.

HDESK OpenDesktop(

LPCTSTR lpszDesktopName	// name of the desktop to open
DWORD dwFlags	// flags to control interaction with other applications
BOOL fInherit	// specifies whether returned handle is inheritable
DWORD dwDesiredAccess	// specifies access of returned handle
);
Parameters

lpszDesktopName

Points to null-terminated string specifying the name of the desktop to be opened. Desktop names are case-insensitive.

dwFlags

A bit flag parameter that controls how the calling application will cooperate with other applications on the desktop. This parameter can specify zero or the following value:

Value	Description
DF_ALLOWOTHERACCOUNTHOOK	Allows processes running in other accounts on the desktop to set hooks in this process.
fInherit

Specifies whether the returned handle is inherited when a new process is created. If this value is TRUE, new processes will inherit the handle.

dwDesiredAccess

Specifies the type of access to the desktop. This parameter can be one or more of the following values:

Value	Description
DESKTOP_CREATEMENU	Required to create a menu on the desktop.
DESKTOP_CREATEWINDOW	Required to create a window on the desktop.
DESKTOP_ENUMERATE	Required for the desktop to be enumerated.
DESKTOP_HOOKCONTROL	Required to establish any of the window hooks.
DESKTOP_JOURNALPLAYBACK	Required to perform journal playback on the desktop.
DESKTOP_JOURNALRECORD	Required to perform journal recording on the desktop.
DESKTOP_READOBJECTS	Required to read objects on the desktop.
DESKTOP_SWITCHDESKTOP	Required to activate the desktop using SwitchDesktop.
DESKTOP_WRITEOBJECTS	Required to write objects on the desktop.
Return Value

If the function succeeds, the return value is the handle to the opened desktop.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

The calling process must have an associated window station, either assigned by the system at process creation time or set by the SetProcessWindowStation function.

See Also

CreateDesktop, SetProcessWindowStation, SetThreadDesktop, SwitchDesktop


OpenEvent
OpenEvent  QuickInfo  Overview  Group

The OpenEvent function returns a handle of an existing named event object.

HANDLE OpenEvent(

DWORD  fdwAccess,	// access flag
BOOL  fInherit,	// inherit flag
LPCTSTR  lpszEventName	// address of event-object name
);
Parameters

fdwAccess

Specifies the requested access to the event object. For systems that support object security, the function fails if the security descriptor of the specified object does not permit the requested access for the calling process.

This parameter can be any combination of the following values:

Access	Description
EVENT_ALL_ACCESS	Specifies all possible access flags for the event object.
EVENT_MODIFY_STATE	Enables use of the event handle in the SetEvent and ResetEvent functions to modify the event's state.
SYNCHRONIZE	Windows NT: Enables use of the event handle in any of the wait functions to wait for the event's state to be signaled.
fInherit

Specifies whether the returned handle is inheritable. If TRUE, a process created by the CreateProcess function can inherit the handle; otherwise, the handle cannot be inherited.

lpszEventName

Points to a null-terminated string that names the event to be opened. Name comparisons are case sensitive.

Return Value

If the function succeeds, the return value is a handle of the event object.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

The OpenEvent function enables multiple processes to open handles of the same event object. The function succeeds only if some process has already created the event by using the CreateEvent function. The calling process can use the returned handle in any function that requires a handle of an event object, subject to the limitations of the access specified in the fdwAccess parameter.

The handle can be duplicated by using the DuplicateHandle function. Use the CloseHandle function to close the handle. The system closes the handle automatically when the process terminates. The event object is destroyed when its last handle has been closed.

See Also

CloseHandle, CreateEvent, CreateProcess, DuplicateHandle, MsgWaitForMultipleObjects, PulseEvent, ResetEvent, SetEvent, WaitForMultipleObjects, WaitForMultipleObjectsEx, WaitForSingleObject, WaitForSingleObjectEx


OpenEventLog
OpenEventLog  QuickInfo  Overview  Group

The OpenEventLog function opens a handle of an event log.

HANDLE OpenEventLog(

LPCTSTR  lpszUNCServerName,	// address of server name
LPCTSTR  lpszSourceName	// address of source name
);
Parameters

lpszUNCServerName

Points to a null-terminated string that specifies the Universal Naming Convention (UNC) name of the server on which the event log is to be opened. If this parameter is NULL, the log is opened on the local computer.

lpszSourceName

Points to a null-terminated string that specifies the name of the source that the returned handle will reference. The source name must be a subkey of a logfile entry under the EventLog key in the registry. For example, the source name WinApp would be valid if the registry had the following form:

HKEY_LOCAL_MACHINE

  System

    CurrentControlSet

      Services

        EventLog

          Application

            WinApp

          Security

          System

If the source name cannot be found, the event logging service uses the Application logfile with no message files for the event identifier or category.

Return Value

If the function succeeds, the return value is the handle of an event log.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

See Also

ClearEventLog, CloseEventLog, GetNumberOfEventLogRecords, GetOldestEventLogRecord, ReadEventLog, ReportEvent


OpenFile
OpenFile  QuickInfo  Overview  Group

The OpenFile function creates, opens, reopens, or deletes a file.

This function is provided for compatibility with 16-bit versions of Windows. In particular, the OpenFile function cannot open a named pipe. Win32-based applications should use the CreateFile function.

HFILE OpenFile(

LPCSTR  lpszFile,	// address of filename
LPOFSTRUCT  lpOpenBuff,	// address of buffer for file information
UINT  fuMode	// action and attributes
);
Parameters

lpszFile

Points to a null-terminated string that names the file to be opened. The string must consist of characters from the Windows 3.x character set. The OpenFile function does not support Unicode filenames.

lpOpenBuff

Points to the OFSTRUCT structure that receives information about the file when it is first opened. The structure can be used in subsequent calls to the OpenFile function to refer to the open file.

The OFSTRUCT structure contains a pathname string member whose length is limited to OFS_MAXPATHNAME characters. OFS_MAXPATHNAME is currently defined to be 128. Because of this, you cannot use the OpenFile function to open a file whose path length exceeds 128 characters. The CreateFile function does not have such a path length limitation.

fuMode

Specifies the action to take. The following values can be combined by using the bitwise OR operator:

Value	Meaning
OF_CANCEL	Ignored. In the Win32 application programming interface (API), the OF_PROMPT style produces a dialog box containing a Cancel button.
OF_CREATE	Creates a new file. If the file already exists, it is truncated to zero length.
OF_DELETE	Deletes the file.
OF_EXIST	Opens the file and then closes it. Used to test for a file's existence.
OF_PARSE	Fills the OFSTRUCT structure but carries out no other action.
OF_PROMPT	Displays a dialog box if the requested file does not exist. The dialog box informs the user that Windows cannot find the file, and it contains Retry and Cancel buttons. Choosing the Cancel button directs OpenFile to return a file-not-found error message.
OF_READ	Opens the file for reading only.
OF_READWRITE	Opens the file for reading and writing.
OF_REOPEN	Opens the file using information in the reopen buffer.
OF_SHARE_COMPAT	For MS-DOS−based file systems using the Win32 API, opens the file with compatibility mode, allowing any process on a specified computer to open the file any number of times. Other efforts to open with any other sharing mode fail. On the Windows NT platform, this flag is mapped to the CreateFile function's FILE_SHARE_READ | FILE_SHARE_WRITE flags.
OF_SHARE_DENY_NONE	Opens the file without denying read or write access to other processes. On MS-DOS-based file systems using the Win32 API, if the file has been opened in compatibility mode by any other process, the function fails. On the Windows NT platform, this flag is mapped to the CreateFile function's FILE_SHARE_READ | FILE_SHARE_WRITE flags.
OF_SHARE_DENY_READ	Opens the file and denies read access to other processes. On MS-DOS-based file systems using the Win32 API, if the file has been opened in compatibility mode or for read access by any other process, the function fails.  On the Windows NT platform, this flag is mapped to the CreateFile function's FILE_SHARE_WRITE flag.
OF_SHARE_DENY_WRITE	Opens the file and denies write access to other processes. On MS-DOS-based file systems using the Win32 API, if the file has been opened in compatibility mode or for write access by any other process, the function fails.  On the Windows NT platform, this flag is mapped to the CreateFile function's FILE_SHARE_WRITE flag.
OF_SHARE_EXCLUSIVE	Opens the file with exclusive mode, denying both read and write access to other processes. If the file has been opened in any other mode for read or write access, even by the current process, the function fails.
OF_VERIFY	Verifies that the date and time of the file are the same as when it was previously opened. This is useful as an extra check for read-only files.
OF_WRITE	Opens the file for writing only.
Return Value

If the function succeeds, the return value specifies a file handle.

If the function fails, the return value is HFILE_ERROR. To get extended error information, call GetLastError.

Remarks

If the lpszFile parameter specifies a filename and extension only, this function searches for a matching file in the following directories, in the order shown:

1.	The directory from which the application loaded.

2.	The current directory.

3.	Windows 95: The Windows system directory. Use the GetSystemDirectory function to get the path of this directory.

Windows NT: The 32-bit Windows system directory. Use the GetSystemDirectory function to get the path of this directory. The name of this directory is SYSTEM32.

4.	Windows NT only: The 16-bit Windows system directory. There is no Win32 function that obtains the path of this directory, but it is searched. The name of this directory is SYSTEM.

5.	The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.

6.	The directories that are listed in the PATH environment variable.

The lpszFile parameter cannot contain wildcard characters.

To close the file after use, call the _lclose function.

See Also

CreateFile, GetSystemDirectory, GetWindowsDirectory, _lclose, OFSTRUCT


OpenFileMapping
OpenFileMapping  QuickInfo  Overview  Group

The OpenFileMapping function opens a named file-mapping object.

HANDLE OpenFileMapping(

DWORD  dwDesiredAccess,	// access mode
BOOL  bInheritHandle,	// inherit flag
LPCTSTR  lpName	// address of name of file-mapping object
);
Parameters

dwDesiredAccess

Specifies the access to the file-mapping object.

Windows NT:

This access is checked against any security descriptor on the target file-mapping object.

Windows 95:

Windows 95 does not support security descriptors on file mapping objects.

This parameter can be one of the following values:

Value	Meaning
FILE_MAP_WRITE	Read-write access. The target file-mapping object must have been created with PAGE_READWRITE protection. A read-write view of the file is mapped.
FILE_MAP_READ	Read-only access. The target file-mapping object must have been created with PAGE_READWRITE or PAGE_READ protection. A read-only view of the file is mapped.
FILE_MAP_ALL_ACCESS	Same as FILE_MAP_WRITE.
FILE_MAP_COPY	Copy-on-write access. The target file-mapping object must have been created with PAGE_WRITECOPY protection. A copy-on-write view of the file is mapped.
bInheritHandle

Specifies whether the returned handle is to be inherited by a new process during process creation. A value of TRUE indicates that the new process inherits the handle.

lpName

Points to a string that names the file-mapping object to be opened. If there is an open handle to a file-mapping object by this name and the security descriptor on the mapping object does not conflict with the dwDesiredAccess parameter, the open operation succeeds.

Return Value

If the function succeeds, the return value is an open handle to the specified file-mapping object.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

The handle that OpenFileMapping returns can be used with any function that requires a handle to a file-mapping object.

See Also

CreateFileMapping


OpenIcon
OpenIcon  QuickInfo  Overview  Group

The OpenIcon function restores a minimized (iconic) window to its previous size and position; it then activates the window.

BOOL OpenIcon(

HWND  hwnd	// handle of window
);
Parameters

hwnd

Identifies the window to be restored and activated.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

OpenIcon sends a WM_QUERYOPEN message to the given window.

See Also

CloseWindow, IsIconic, ShowWindow


OpenInputDesktop [New - Windows NT]
OpenInputDesktop  QuickInfo  Overview  Group

[New - Windows NT]

The OpenInputDesktop function returns a handle to the desktop that receives user input. The input desktop is a desktop on the window station associated with the logged-on user.

HDESK OpenInputDesktop(

DWORD dwFlags	// flags to control interaction with other applications
BOOL fInherit	// specifies whether returned handle is inheritable
DWORD dwDesiredAccess	// specifies access of returned handle
);
Parameters

dwFlags

A bit flag parameter that controls how the calling application will cooperate with other applications on the desktop. This parameter can specify zero or the following value:

Value	Description
DF_ALLOWOTHERACCOUNTHOOK	Allows processes running in other accounts on the desktop to set hooks in this process.
fInherit

Specifies whether the returned handle is inherited when a new process is created. If this value is TRUE, new processes will inherit the handle.

dwDesiredAccess

Specifies the type of access to the desktop. This parameter can be one or more of the following values:

Value	Description
DESKTOP_CREATEMENU	Required to create a menu on the desktop.
DESKTOP_CREATEWINDOW	Required to create a window on the desktop.
DESKTOP_ENUMERATE	Required for the desktop to be enumerated.
DESKTOP_HOOKCONTROL	Required to establish any of the window hooks.
DESKTOP_JOURNALPLAYBACK	Required to perform journal playback on the desktop.
DESKTOP_JOURNALRECORD	Required to perform journal recording on the desktop.
DESKTOP_READOBJECTS	Required to read objects on the desktop.
DESKTOP_SWITCHDESKTOP	Required to activate the desktop using SwitchDesktop.
DESKTOP_WRITEOBJECTS	Required to write objects on the desktop.
Return Value

If the function succeeds, the return value is a handle of the desktop that receives user input.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

The calling process must have an associated window station, either assigned by the system at process creation time or set by SetProcessWindowStation The window station associated with the calling process must be capable of receiving input.

An application can use the SwitchDesktop function to change the input desktop.

See Also

SetProcessWindowStation, SwitchDesktop


OpenMutex
OpenMutex  QuickInfo  Overview  Group

The OpenMutex function returns a handle of an existing named mutex object.

HANDLE OpenMutex(

DWORD  fdwAccess,	// access flag
BOOL  fInherit,	// inherit flag
LPCTSTR  lpszMutexName	// address of mutex-object name
);
Parameters

fdwAccess

Specifies the requested access to the mutex object. For systems that support object security, the function fails if the security descriptor of the specified object does not permit the requested access for the calling process.

This parameter can be any combination of the following values:

Access	Description
MUTEX_ALL_ACCESS	Specifies all possible access flags for the mutex object.
SYNCHRONIZE	Windows NT: Enables use of the mutex handle in any of the wait functions to acquire ownership of the mutex, or in the ReleaseMutex function to release ownership.
fInherit

Specifies whether the returned handle is inheritable. If TRUE, a process created by the CreateProcess function can inherit the handle; otherwise, the handle cannot be inherited.

lpszMutexName

Points to a null-terminated string that names the mutex to be opened. Name comparisons are case sensitive.

Return Value

If the function succeeds, the return value is a handle of the mutex object.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

The OpenMutex function enables multiple processes to open handles of the same mutex object. The function succeeds only if some process has already created the mutex by using the CreateMutex function. The calling process can use the returned handle in any function that requires a handle of a mutex object, subject to the limitations of the access specified in the fdwAccess parameter.

The handle can be duplicated by using the DuplicateHandle function. Use the CloseHandle function to close the handle. The system closes the handle automatically when the process terminates. The mutex object is destroyed when its last handle has been closed.

See Also

CloseHandle, CreateMutex, CreateProcess, DuplicateHandle, MsgWaitForMultipleObjects, ReleaseMutex, WaitForMultipleObjects, WaitForMultipleObjectsEx, WaitForSingleObject, WaitForSingleObjectEx


OpenPrinter
OpenPrinter  QuickInfo  Overview  Group

The OpenPrinter function retrieves a handle identifying the specified printer or print server.

BOOL OpenPrinter(

LPTSTR  pPrinterName,	// address of printer or server name
LPHANDLE  phPrinter,	// address of printer or server handle
LPPRINTER_DEFAULTS  pDefault	// address of printer defaults structure
);
Parameters

pPrinterName

Points to a null-terminated string that specifies the name of the printer or print server.

phPrinter

Points to a variable that receives the handle identifying the opened printer or print server object.

pDefault

Points to a PRINTER_DEFAULTS structure. This value can be NULL.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The pDefault parameter allows an application to specify the data type and device mode values that are used for printing documents submitted by the StartDocPrinter function. However, these values can be overridden by using the SetJob function once a document has been started.

The DesiredAccess member of the PRINTER_DEFAULTS data structure pointed to by pDefault specifies the accesses that an application wishes to perform using the handle returned by OpenPrinter. If an application wishes to open a printer to perform administrative tasks, such as the SetPrinter function, it should open the printer with PRINTER_ALL_ACCESS access. If an application wishes only to perform basic printing operations, an access value that includes PRINTER_ACCESS_USE is sufficient.

Windows 95: OpenPrinter ignores the DesiredAccess member of PRINTER_DEFAULTS.

An application can determine what permissions a client has on a print server, or obtain a handle to a print server to call WaitForPrinterChange. To do so, it should call OpenPrinter with pPrinterName set to the name of the server and should specify a server access mask value such as SERVER_ALL_ACCESS. The pDatatype and pDevMode members of the PRINTER_DEFAULTS data structure should be set to NULL. The handle returned by such a call may be passed to the ClosePrinter or WaitForPrinterChange function.

If a user does not hold permission to open a specified printer or print server with the desired access, the OpenPrinter call will fail, and GetLastError will return the value ERROR_ACCESS_DENIED.

See Also

ClosePrinter, SetPrinter, StartDocPrinter, WaitForPrinterChange, PRINTER_DEFAULTS


OpenProcess
OpenProcess  QuickInfo  Overview  Group

The OpenProcess function returns a handle of an existing process object.

HANDLE OpenProcess(

DWORD  fdwAccess,	// access flag
BOOL  fInherit,	// handle inheritance flag
DWORD  IDProcess	// process identifier
);
Parameters

fdwAccess

Specifies the access to the process object. For operating systems that support security checking, this access is checked against any security descriptor for the target process. Any combination of the following access flags can be specified in addition to the STANDARD_RIGHTS_REQUIRED access flags:

Access	Description
PROCESS_ALL_ACCESS	Specifies all possible access flags for the process object.
PROCESS_CREATE_PROCESS	Used internally.
PROCESS_CREATE_THREAD	Enables using the process handle in the CreateRemoteThread function to create a thread in the process.
PROCESS_DUP_HANDLE	Enables using the process handle as either the source or target process in the DuplicateHandle function to duplicate a handle.
PROCESS_QUERY_INFORMATION	Enables using the process handle in the GetExitCodeProcess and GetPriorityClass functions to read information from the process object.
PROCESS_SET_INFORMATION	Enables using the process handle in the SetPriorityClass function to set the priority class of the process.
PROCESS_TERMINATE	Enables using the process handle in the TerminateProcess function to terminate the process.
PROCESS_VM_OPERATION	Enables using the process handle in the VirtualProtectEx and WriteProcessMemory functions to modify the virtual memory of the process.
PROCESS_VM_READ	Enables using the process handle in the ReadProcessMemory function to read from the virtual memory of the process.
PROCESS_VM_WRITE	Enables using the process handle in the WriteProcessMemory function to write to the virtual memory of the process.
SYNCHRONIZE	Windows NT: Enables using the process handle in any of the wait functions to wait for the process to terminate.
fInherit

Specifies whether the returned handle can be inherited by a new process created by the current process. If TRUE, the handle is inheritable.

IDProcess

Specifies the process identifier of the process to open.

Return Value

If the function succeeds, the return value is an open handle of the specified process.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

The handle returned by the OpenProcess function can be used in any function that requires a handle to a process, provided the appropriate access rights were requested.

See Also

CreateProcess, CreateRemoteThread, DuplicateHandle, GetCurrentProcess, GetCurrentProcessId, GetExitCodeProcess, GetPriorityClass, ReadProcessMemory, SetPriorityClass, TerminateProcess, VirtualProtectEx, WriteProcessMemory,


OpenProcessToken
OpenProcessToken  QuickInfo  Overview  Group

The OpenProcessToken function opens the access token associated with a process.

BOOL OpenProcessToken(

HANDLE  hProcess,	// handle of process
DWORD  dwAccessMask,	// desired access to process
PHANDLE  phToken	// address of handle of open access token
);
Parameters

hProcess

Identifies the process whose access token is opened.

dwAccessMask

Specifies an access mask that specifies the requested types of access to the access token. These requested access types are compared with the token's discretionary access-control list (ACL) to determine which accesses are granted or denied. The following access rights have been defined for access tokens.

Value	Meaning
TOKEN_ADJUST_DEFAULT	Required to change the default ACL, primary group, or owner of an access token.
TOKEN_ADJUST_GROUPS	Required to change the groups specified in an access token.
TOKEN_ADJUST_PRIVILEGES	Required to change the privileges specified in an access token.
TOKEN_ALL_ACCESS	Combines the STANDARD_RIGHTS_REQUIRED standard access rights and all individual access rights for tokens.
TOKEN_ASSIGN_PRIMARY	Required to attach a primary token to a process in addition to the SE_CREATE_TOKEN_NAME privilege.
TOKEN_DUPLICATE	Required to duplicate an access token.
TOKEN_EXECUTE	Combines the STANDARD_RIGHTS_EXECUTE standard access rights and the TOKEN_IMPERSONATE access right.
TOKEN_IMPERSONATE	Required to attach an impersonation access token to a process.
TOKEN_QUERY	Required to query the contents of an access token.
TOKEN_QUERY_SOURCE	Required to query the source of an access token.
TOKEN_READ	Combines the STANDARD_RIGHTS_READ standard access rights and the TOKEN_QUERY access right.
TOKEN_WRITE	Combines the STANDARD_RIGHTS_WRITE standard access rights and the TOKEN_ADJUST_PRIVILEGES, TOKEN_ADJUST_GROUPS, and TOKEN_ADJUST_DEFAULT access rights.
phToken

Points to a handle identifying the newly-opened access token when the function returns.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

AdjustTokenGroups, AdjustTokenPrivileges, GetTokenInformation, OpenThreadToken, SetTokenInformation


OpenSCManager
OpenSCManager  QuickInfo  Overview  Group

The OpenSCManager function establishes a connection to the service control manager on the specified computer and opens the specified database.

SC_HANDLE OpenSCManager(

LPCTSTR  lpszMachineName,	// address of machine name string
LPCTSTR  lpszDatabaseName,	// address of database name string
DWORD  fdwDesiredAccess	// type of access
);
Parameters

lpszMachineName

Points to a null-terminated string that names the target computer. If the pointer is NULL or if it points to an empty string, the function connects to the service control manager on the local computer.

lpszDatabaseName

Points to a null-terminated string that names the service control manager database to open. This string should specify ServicesActive. If the pointer is NULL, the ServicesActive database is opened by default.

fdwDesiredAccess

Specifies the access to the service control manager. Before granting the requested access, the system checks the access token of the calling process against the discretionary access-control list of the security descriptor associated with the service control manager object. The SC_MANAGER_CONNECT access type is implicitly specified by calling this function. In addition, any or all of the following service control manager object access types can be specified:

Type	Description
SC_MANAGER_ALL_ACCESS
	Includes STANDARD_RIGHTS_REQUIRED, in addition to all of the access types listed in this table.
SC_MANAGER_CONNECT
	Enables connecting to the service control manager.
SC_MANAGER_CREATE_SERVICE
	Enables calling of the CreateService function to create a service object and add it to the database.
SC_MANAGER_ENUMERATE_SERVICE
	Enables calling of the EnumServicesStatus function to list the services that are in the database.
SC_MANAGER_LOCK
	Enables calling of the LockServiceDatabase function to acquire a lock on the database.
SC_MANAGER_QUERY_LOCK_STATUS
	Enables calling of the QueryServiceLockStatus function to retrieve the lock status information for the database.
The fdwDesiredAccess parameter can specify any or all of the following generic access types:

Generic access	Service manager access
GENERIC_READ	Combines the following access: STANDARD_RIGHTS_READ, SC_MANAGER_ENUMERATE_SERVICE, and SC_MANAGER_QUERY_LOCK_STATUS.
GENERIC_WRITE	Combines the following access: STANDARD_RIGHTS_WRITE, SC_MANAGER_CREATE_SERVICE, and SC_MANAGER_MODIFY_BOOT_CONFIG.
GENERIC_EXECUTE	Combines the following access: STANDARD_RIGHTS_EXECUTE, SC_MANAGER_CONNECT, and SC_MANAGER_LOCK.
Return Value

If the function succeeds, the return value is a handle to the specified service control manager database.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Errors

The following error codes may be set by the service control manager. Other error codes may be set by the registry functions that are called by the service control manager.

Error code	Meaning
ERROR_ACCESS_DENIED	The requested access was denied.
ERROR_DATABASE_DOES_NOT_EXIST	The specified database does not exist.
ERROR_INVALID_PARAMETER	A parameter that was specified is invalid.
Remarks

When a process uses the OpenSCManager function to open a handle to a service control manager database, the system performs a security check before granting the requested access. All processes are permitted SC_MANAGER_CONNECT, SC_MANAGER_ENUMERATE_SERVICE, and SC_MANAGER_QUERY_LOCK_STATUS access to all service control manager databases. This enables any process to open a service control manager database handle that it can use in the OpenService, EnumServicesStatus, and QueryServiceLockStatus functions. Only processes with Administrator privileges are able to open a database handle used by the CreateService and LockServiceDatabase functions.

The calling process can use the returned handle to identify the database in the following functions, if the appropriate access rights are enabled:

CreateService
EnumServicesStatus
LockServiceDatabase
OpenService
QueryServiceLockStatus

The returned handle is only valid for the process that called the OpenSCManager function. It can be closed by calling the CloseServiceHandle function.

See Also

CloseServiceHandle, CreateService, EnumServicesStatus, LockServiceDatabase, OpenService, QueryServiceLockStatus


OpenSemaphore
OpenSemaphore  QuickInfo  Overview  Group

The OpenSemaphore function returns a handle of an existing named semaphore object.

HANDLE OpenSemaphore(

DWORD  fdwAccess,	// access flag
BOOL  fInherit,	// inherit flag
LPCTSTR  lpszSemName	// address of semaphore-object name
);
Parameters

fdwAccess

Specifies the requested access to the semaphore object. For systems that support object security, the function fails if the security descriptor of the specified object does not permit the requested access for the calling process.

This parameter can be any combination of the following values:

Access	Description
SEMAPHORE_ALL_ACCESS	Specifies all possible access flags for the semaphore object.
SEMAPHORE_MODIFY_STATE	Enables use of the semaphore handle in the ReleaseSemaphore function to modify the semaphore's count.
SYNCHRONIZE	Windows NT: Enables use of the semaphore handle in any of the wait functions to wait for the semaphore's state to be signaled.
fInherit

Specifies whether the returned handle is inheritable. If TRUE, a process created by the CreateProcess function can inherit the handle; otherwise, the handle cannot be inherited.

lpszSemName

Points to a null-terminated string that names the semaphore to be opened. Name comparisons are case sensitive.

Return Value

If the function succeeds, the return value is a handle of the semaphore object.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

The OpenSemaphore function enables multiple processes to open handles of the same semaphore object. The function succeeds only if some process has already created the semaphore by using the CreateSemaphore function. The calling process can use the returned handle in any function that requires a handle of a semaphore object, subject to the limitations of the access specified in the fdwAccess parameter.

The handle can be duplicated by using the DuplicateHandle function. Use the CloseHandle function to close the handle. The system closes the handle automatically when the process terminates. The semaphore object is destroyed when its last handle has been closed.

See Also

CloseHandle, CreateSemaphore, DuplicateHandle, MsgWaitForMultipleObjects, ReleaseSemaphore, WaitForMultipleObjects, WaitForMultipleObjectsEx, WaitForSingleObject, WaitForSingleObjectEx


OpenService
OpenService  QuickInfo  Overview  Group

The OpenService function opens a handle to an existing service.

SC_HANDLE OpenService(

SC_HANDLE  schSCManager,	// handle of service control manager database
LPCTSTR  lpszServiceName,	// address of name of service to start
DWORD  fdwDesiredAccess	// type of access to service
);
Parameters

schSCManager

Identifies the service control manager database. The OpenSCManager function returns this handle.

lpszServiceName

Points to a null-terminated string that names the service to open. The maximum string length is 256 characters. The service control manager database preserves the case of the characters, but service name comparisons are always case insensitive. A slash (/), backslash (\), comma, and space are invalid service name characters.

fdwDesiredAccess

Specifies the access to the service. Before granting the requested access, the system checks the access token of the calling process against the discretionary access-control list of the security descriptor associated with the service object. Any or all of the following service object access types can be specified:

Access	Description
SERVICE_ALL_ACCESS
	Includes STANDARD_RIGHTS_REQUIRED in addition to all of the access types listed in this table.
SERVICE_CHANGE_CONFIG
	Enables calling of the ChangeServiceConfig function to change the service configuration.
SERVICE_ENUMERATE_DEPENDENTS
	Enables calling of the EnumDependentServices function to enumerate all the services dependent on the service.
SERVICE_INTERROGATE
	Enables calling of the ControlService function to ask the service to report its status immediately.
SERVICE_PAUSE_CONTINUE
	Enables calling of the ControlService function to pause or continue the service.
SERVICE_QUERY_CONFIG
	Enables calling of the QueryServiceConfig function to query the service configuration.
SERVICE_QUERY_STATUS
	Enables calling of the QueryServiceStatus function to ask the service control manager about the status of the service.
SERVICE_START
	Enables calling of the StartService function to start the service.
SERVICE_STOP
	Enables calling of the ControlService function to stop the service.
SERVICE_USER_DEFINE_CONTROL
	Enables calling of the ControlService function to specify a user-defined control code.
STANDARD_RIGHTS_REQUIRED enables the following service object access types:

Standard rights	Description
DELETE	Enables calling of the DeleteService function to delete the service.
READ_CONTROL	Enables calling of the QueryServiceObjectSecurity function to query the security descriptor of the service object.
WRITE_DAC|WRITE_OWNER	Enables calling of the SetServiceObjectSecurity function to modify the security descriptor of the service object.
The fdwDesiredAccess parameter can specify any or all of the following generic access types:

Generic access	Service access
GENERIC_READ	Combines the following access: STANDARD_RIGHTS_READ, SERVICE_QUERY_CONFIG, SERVICE_QUERY_STATUS, and SERVICE_ENUMERATE_DEPENDENTS.
GENERIC_WRITE	Combines the following access: STANDARD_RIGHTS_WRITE and SERVICE_CHANGE_CONFIG.
GENERIC_EXECUTE	Combines the following access: STANDARD_RIGHTS_EXECUTE, SERVICE_START, SERVICE_STOP, SERVICE_PAUSE_CONTINUE, SERVICE_INTERROGATE, and SERVICE_USER_DEFINED_CONTROL.
Return Value

If the function succeeds, the return value is a handle to the service.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Errors

The following error codes can be set by the service control manager. Others can be set by the registry functions that are called by the service control manager.

Error code	Meaning
ERROR_ACCESS_DENIED	The specified service control manager database handle does not have access to the service.
ERROR_INVALID_HANDLE	The specified handle is invalid.
ERROR_INVALID_NAME	The specified service name is invalid.
ERROR_SERVICE_DOES_NOT_EXIST	The specified service does not exist.
Remarks

The calling process can use the returned handle to identify the service in the following functions, if the appropriate access rights are enabled:

ChangeServiceConfig
ControlService
DeleteService
EnumDependentServices
QueryServiceConfig
QueryServiceObjectSecurity
QueryServiceStatus
SetServiceObjectSecurity
StartService

The returned handle is only valid for the process that called OpenService. It can be closed by calling the CloseServiceHandle function.

See Also

ChangeServiceConfig, ControlService, CreateService, DeleteService, EnumDependentServices, OpenSCManager, QueryServiceConfig, QueryServiceObjectSecurity, QueryServiceStatus, SetServiceObjectSecurity, StartService


OpenSound

The OpenSound function has been deleted.

See Also

Beep, MessageBeep


OpenThreadToken
OpenThreadToken  QuickInfo  Overview  Group

The OpenThreadToken function opens the access token associated with a thread.

BOOL OpenThreadToken(

HANDLE  hThread,	// handle of thread
DWORD  dwAccessMask,	// access to process
BOOL  fOpenAsSelf,	// flag for process or thread security
PHANDLE  phToken	// address of handle of open access token
);
Parameters

hThread

Identifies the thread whose access token is opened.

dwAccessMask

Specifies an access mask that specifies the requested types of access to the access token. These requested access types are reconciled against the token's discretionary access-control list (ACL) to determine which accesses are granted or denied. The following access rights have been defined for access tokens.

Value	Meaning
TOKEN_ADJUST_DEFAULT	Required to change the default ACL, primary group, or owner of an access token.
TOKEN_ADJUST_GROUPS	Required to change the groups specified in an access token.
TOKEN_ADJUST_PRIVILEGES	Required to change the privileges specified in an access token.
TOKEN_ALL_ACCESS	Combines the STANDARD_RIGHTS_REQUIRED standard access rights and all individual access rights for tokens.
TOKEN_ASSIGN_PRIMARY	Required to attach a primary token to a process in addition to the SE_CREATE_TOKEN_NAME privilege.
TOKEN_DUPLICATE	Required to duplicate an access token.
TOKEN_EXECUTE	Combines the STANDARD_RIGHTS_EXECUTE standard access rights and the TOKEN_IMPERSONATE access right.
TOKEN_IMPERSONATE	Required to attach an impersonation access token to a process.
TOKEN_QUERY	Required to query the contents of an access token.
TOKEN_QUERY_SOURCE	Required to query the source of an access token.
TOKEN_READ	Combines the STANDARD_RIGHTS_READ standard access rights and the TOKEN_QUERY access right.
TOKEN_WRITE	Combines the STANDARD_RIGHTS_WRITE standard access rights and the TOKEN_ADJUST_PRIVILEGES, TOKEN_ADJUST_GROUPS, and TOKEN_ADJUST_DEFAULT access rights.
fOpenAsSelf

Specifies a flag indicating whether the access check is to be made against the security context of the thread calling the OpenThreadToken function or against the security context of the process for the calling thread.

If this parameter is FALSE, the access check is performed using the security context for the calling thread. If the thread is impersonating a client, this security context can be that of a client process. If this parameter is TRUE, the access check is made using the security context of the process for the calling thread.

phToken

Points to a handle identifying the newly opened access token when the function returns.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The fOpenAsSelf parameter allows a server process to open the access token for a client process when the client process has specified the SecurityIdentification impersonation level for the SECURITY_IMPERSONATION_LEVEL enumerated type. Without this parameter, the calling process is not be able to open the client's access token using the client's security context, because it is impossible to open executive-level objects using the SecurityIdentification impersonation level.

See Also

AdjustTokenGroups, AdjustTokenPrivileges, GetTokenInformation, OpenProcessToken, SetThreadToken, SetTokenInformation


OpenWindowStation [New - Windows NT]
OpenWindowStation  QuickInfo  Overview  Group

[New - Windows NT]

The OpenWindowStation function returns a handle to an existing window station.

HWINSTA OpenWindowStation(

LPCTSTR lpszWinStaName,	// name of the window station to open
BOOL fInherit,	// specifies whether returned handle is inheritable
DWORD dwDesiredAccess	// specifies access of returned handle
);
Parameters

lpszWinStaName

Points to a null-terminated string specifying the name of the window station to be opened. Window station names are case-insensitive.

fInherit

Specifies whether the returned handle is inherited when a new process is created. If this value is TRUE, new processes will inherit the handle.

dwDesiredAccess

Specifies the type of access to the window station. This parameter can be one or more of the following values:

Value	Description
WINSTA_ACCESSCLIPBOARD	Required to use the clipboard.
WINSTA_ACCESSGLOBALATOMS	Required to manipulate global atoms.
WINSTA_CREATEDESKTOP	Required to create new desktop objects on the window station.
WINSTA_ENUMDESKTOPS	Required to enumerate existing desktop objects.
WINSTA_ENUMERATE	Required for the window station to be enumerated.
WINSTA_EXITWINDOWS	Required to successfully call the ExitWindows and ExitWindowsEx functions.
WINSTA_READATTRIBUTES	Required to read the attributes of a window station object.
WINSTA_READSCREEN	Required to access screen contents.
WINSTA_WRITEATTRIBUTES	Required to modify the attributes of a window station object.
Return Value

If the function succeeds, the return value is the handle to the specified window station.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

See Also

ExitWindows, ExitWindowsEx


OutputDebugString
OutputDebugString  QuickInfo  Overview  Group

The OutputDebugString function sends a string to the debugger for the current application.

VOID OutputDebugString(

LPCTSTR  lpszOutputString	// address of string to be displayed
);
Parameters

lpszOutputString

Points to the null-terminated string to be displayed.

Return Value

This function does not return a value.

Remarks

If the application has no debugger, the system debugger displays the string. If the application has no debugger and the system debugger is not active, OutputDebugString does nothing.


OutputProc
OutputProc  QuickInfo  Overview  Group

The OutputProc function is an application-defined callback function that draws a string as a result of a call to the GrayString function.

BOOL CALLBACK OutputProc(

HDC  hdc,	// handle of device context
LPARAM  lpData,	// address of string to be drawn
int  cchData	// length of string to be drawn
);
Parameters

hdc

Identifies a device context with a bitmap of at least the width and height specified by the nWidth and nHeight parameters passed to GrayString.

lpData

Points to the string to be drawn.

cchData

Specifies the length, in characters, of the string.

Return Value

If it succeeds, the callback function should return TRUE.

If the function fails, the return value is FALSE.

Remarks

The callback function must draw an image relative to the coordinates (0,0).

OutputProc is a placeholder for the application-defined function name.

See Also

GrayString


PackDDElParam
PackDDElParam  QuickInfo  Overview  Group

The PackDDElParam function packs a DDE lParam value into an internal structure used for sharing DDE data between processes.

LONG PackDDElParam(

UINT  uMsg,	// DDE message to be posted
UINT  uLow,	// low-order word of lParam of message
UINT  uHigh	// high-order word of lParam of message
);
Parameters

uMsg

Specifies the DDE message to be posted.

uLow

Specifies a value that corresponds to the Windows 3.x low-order word of an lParam parameter for the DDE message being posted.

uHigh

Specifies a value that corresponds to the Windows 3.x high-order word of an lParam parameter for the DDE message being posted.

Return Value

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero.

Remarks

The return value must be posted as the lParam parameter of a DDE message; it must not be used for any other purpose. Once the application posts a return value, it need not perform any action to dispose of the lParam parameter.

PackDDElParam eases the porting of 16-bit DDE applications to 32-bit DDE applications.

An application should call this function only for posted DDE messages.

See Also

FreeDDElParam, ReuseDDElParam, UnpackDDElParam


PageSetupDlg
PageSetupDlg  Overview  Group

The PageSetupDlg function creates a Page Setup dialog box that enables the user to specify the attributes of a printed page, including the paper size, source, orientation, and margins.

BOOL PageSetupDlg(

LPPAGESETUPDLG  lppsd	pointer to a structure
);
Parameters

lppsd

Pointer to a PAGESETUPDLG structure that contains information used to initialize the dialog box and receives information about the user's selections when the function returns.

Return Value

Returns TRUE if the function sets up the page attributes; otherwise, returns FALSE if an error occurs or the user cancels or closes the dialog box. To get extended error information, use the CommDlgExtendedError function .

See Also

CommDlgExtendedError, PAGESETUPDLG


PaintDesktop [New - Windows 95]
PaintDesktop  QuickInfo  Overview  Group

[New - Windows 95]

The PaintDesktop function fills the clipping region in the specified device context with the desktop pattern or wallpaper. The function is provided primarily for shell desktops.

BOOL WINAPI PaintDesktop(

HDC hdc	\\
);
Parameters

hdc

Identifies the device context.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.


PaintRgn
PaintRgn  QuickInfo  Overview  Group

The PaintRgn function paints the specified region by using the brush currently selected into the device context.

BOOL PaintRgn(

HDC  hdc,	// handle of device context
HRGN  hrgn	// handle of region to be painted
);
Parameters

hdc

Identifies the device context.

hrgn

Identifies the region to be filled. The region's coordinates are presumed to be logical coordinates.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

See Also

FillRgn


PatBlt
PatBlt  QuickInfo  Overview  Group

The PatBlt function paints the given rectangle using the brush that is currently selected into the specified device context. The brush color and the surface color(s) are combined by using the given raster operation.

BOOL PatBlt(

HDC  hdc,	// handle of device context
int  nXLeft,	// x-coord. of upper-left corner of rect. to be filled
int  nYLeft,	// y-coord. of upper-left corner of rect. to be filled
int  nWidth,	// width of rectangle to be filled
int  nHeight,	// height of rectangle to be filled
DWORD  dwRop	// raster operation code
);
Parameters

hdc

Identifies the device context.

nXLeft

Specifies the x-coordinate, in logical units, of the upper-left corner of the rectangle to be filled.

nYLeft

Specifies the y-coordinate, in logical units, of the upper-left corner of the rectangle to be filled.

nWidth

Specifies the width, in logical units, of the rectangle.

nHeight

Specifies the height, in logical units, of the rectangle.

dwRop

Specifies the raster operation code. This code may be one of the following values:

Value	Meaning
PATCOPY	Copies the specified pattern into the destination bitmap.
PATINVERT	Combines the colors of the specified pattern with the colors of the destination rectangle by using the Boolean OR operator.
DSTINVERT	Inverts the destination rectangle.
BLACKNESS	Fills the destination rectangle using the color associated with index 0 in the physical palette. (This color is black for the default physical palette.)
WHITENESS	Fills the destination rectangle using the color associated with index 1 in the physical palette. (This color is white for the default physical palette.)
Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The values of the dwRop parameter for this function are a limited subset of the full 256 ternary raster-operation codes; in particular, an operation code that refers to a source rectangle cannot be used.

Not all devices support the PatBlt function. For more information, see the description of the RC_BITBLT capability in the GetDeviceCaps function.

See Also

GetDeviceCaps


PathToRegion
PathToRegion  QuickInfo  Overview  Group

The PathToRegion function creates a region from the path that is selected into the specified device context.

HRGN PathToRegion(

HDC  hdc	// handle of device context
);
Parameters

hdc

Identifies a device context that contains a closed path.

Return Value

If the function succeeds, the return value identifies a valid region.

If the function fails, the return value is zero. To get extended error information, call GetLastError. GetLastError may return one of the following error codes:

ERROR_CAN_NOT_COMPLETE
ERROR_INVALID_PARAMETER
ERROR_NOT_ENOUGH_MEMORY

Remarks

The device context identified by the hdc parameter must contain a closed path.

After PathToRegion converts a path into a region, Windows discards the closed path from the specified device context.

See Also

BeginPath, EndPath , SetPolyFillMode,


PeekConsoleInput
PeekConsoleInput  QuickInfo  Overview  Group

The PeekConsoleInput function reads data from the specified console input buffer without removing it from the buffer.

BOOL PeekConsoleInput(

HANDLE  hConsoleInput,	// handle of a console input buffer
PINPUT_RECORD  pirBuffer,	// address of the buffer for peek data
DWORD  cInRecords,	// number of records to read
LPDWORD  lpcRead	// address of number of records read
);
Parameters

hConsoleInput

Identifies the input buffer. The handle must have GENERIC_READ access.

pirBuffer

Points to an INPUT_RECORD buffer that receives the input buffer data.

cInRecords

Specifies the size, in records, of the buffer pointed to by the pirBuffer parameter.

lpcRead

Points to a 32-bit variable that receives the number of input records read.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

If the number of records requested exceeds the number of records available in the buffer, the number available is read. If no data is available, the function returns immediately.

See Also

INPUT_RECORD, ReadConsoleInput, WriteConsoleInput


PeekMessage
PeekMessage  QuickInfo  Overview  Group

The PeekMessage function checks a thread message queue for a message and places the message (if any) in the specified structure.

BOOL PeekMessage(

LPMSG  lpMsg,	// address of structure for message
HWND  hWnd,	// handle of window
UINT  uMsgFilterMin,	// first message
UINT  uMsgFilterMax,	// last message
UINT  wRemoveMsg	// removal flags
);
Parameters

lpMsg

Points to an MSG structure that contains message information from the Windows-based application queue.

hWnd

Identifies the window whose messages are to be examined.

uMsgFilterMin

Specifies the value of the first message in the range of messages to be examined.

uMsgFilterMax

Specifies the value of the last message in the range of messages to be examined.

wRemoveMsg

Specifies how messages are handled. This parameter can be one of the following values:

Value	Meaning
PM_NOREMOVE	Messages are not removed from the queue after processing by PeekMessage.
PM_REMOVE	Messages are removed from the queue after processing by PeekMessage.
You can optionally combine the value PM_NOYIELD with either PM_NOREMOVE or PM_REMOVE. However, PM_NOYIELD has no effect on 32-bit Windows applications. It is defined in Win32 solely to provide compatibility with applications written for previous versions of Windows, where it was used to prevent the current task from halting and yielding system resources to another task. 32-bit Windows applications always run simultaneously.

Return Value

If a message is available, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

Unlike the GetMessage function, the PeekMessage function does not wait for a message to be placed in the queue before returning.

PeekMessage retrieves only messages associated with the window identified by the hWnd parameter or any of its children as specified by the IsChild function, and within the range of message values given by the uMsgFilterMin and uMsgFilterMax parameters. If hWnd is NULL, PeekMessage retrieves messages for any window that belongs to the current thread making the call. (PeekMessage does not retrieve messages for windows that belong to other threads.) If hWnd is −1, PeekMessage only returns messages with a hWnd value of NULL, as posted by the PostAppMessage function. If uMsgFilterMin and uMsgFilterMax are both zero, PeekMessage returns all available messages (that is, no range filtering is performed).

The WM_KEYFIRST and WM_KEYLAST constants can be used as filter values to retrieve all keyboard messages; the WM_MOUSEFIRST and WM_MOUSELAST constants can be used to retrieve all mouse messages.

The PeekMessage function normally does not remove WM_PAINT messages from the queue. WM_PAINT messages remain in the queue until they are processed. However, if a WM_PAINT message has a null update region, PeekMessage does remove it from the queue.

See Also

GetMessage, IsChild, MSG, PostAppMessage, WaitMessage


PeekNamedPipe
PeekNamedPipe  QuickInfo  Overview  Group

The PeekNamedPipe function copies data from a named or anonymous pipe into a buffer without removing it from the pipe. It also returns information about data in the pipe.

BOOL PeekNamedPipe(

HANDLE  hPipe,	// handle of pipe to copy from
LPVOID  lpvBuffer,	// address of data buffer
DWORD  cbBuffer,	// size, in bytes, of data buffer
LPDWORD  lpcbRead,	// address of number of bytes read
LPDWORD  lpcbAvail,	// address of total number of bytes available
LPDWORD  lpcbMessage	// address of unread bytes in this message
);
Parameters

hPipe

Identifies the pipe. This parameter can be a handle to a named pipe instance, as returned by the CreateNamedPipe or CreateFile function, or it can be a handle to the read end of an anonymous pipe, as returned by the CreatePipe function. The handle must have GENERIC_READ access to the pipe.

lpvBuffer

Points to a buffer that receives data read from the pipe. This parameter can be NULL if no data is to be read.

cbBuffer

Specifies the size, in bytes, of the buffer specified by the lpvBuffer parameter. This parameter is ignored if lpvBuffer is NULL.

lpcbRead

Points to a 32-bit variable that receives the number of bytes read from the pipe. This parameter can be NULL if no data is to be read.

lpcbAvail

Points to a 32-bit variable that receives the total number of bytes available to be read from the pipe. This parameter can be NULL if no data is to be read.

lpcbMessage

Points to a 32-bit variable that receives the number of bytes remaining in this message. This parameter will be zero for byte-type named pipes or for anonymous pipes. This parameter can be NULL if no data is to be read.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

PeekNamedPipe is similar to the ReadFile function with the following exceptions:

•	The data read from the pipe is not removed from the pipe's buffer.

•	The function always returns immediately, even if there is no data in the pipe. The wait mode of a named pipe handle (blocking or nonblocking) has no effect on the function.

•	The function can return additional information about the contents of the pipe.

If the specified handle is a named pipe handle in byte-read mode, the function reads all available bytes up to the size specified in cbBuffer. For a named pipe handle in message-read mode, the function reads the next message in the pipe. If the message is larger than cbBuffer, the function returns TRUE after reading the specified number of bytes. In this situation, lpcbMessage will receive the number of bytes remaining in the message.

See Also

CreateFile, CreateNamedPipe, CreatePipe, ReadFile, WriteFile


Pie
Pie  QuickInfo  Overview  Group

The Pie function draws a pie-shaped wedge bounded by the intersection of an ellipse and two radials. The pie is outlined by using the current pen and filled by using the current brush.

BOOL Pie(

HDC  hdc,	// handle of device context
int  nLeftRect,	// x-coord. of bounding rectangle's upper-left corner
int  nTopRect,	// y-coord. of bounding rectangle's upper-left corner
int  nRightRect,	// x-coord. of bounding rectangle's lower-right corner
int  nBottomRect,	// y-coord. of bounding rectangle's lower-right corner
int  nXRadial1,	// x-coord. of first radial's endpoint
int  nYRadial1,	// y-coord. of first radial's endpoint
int  nXRadial2,	// x-coord. of second radial's endpoint
int  nYRadial2	// y-coord. of second radial's endpoint
);
Parameters

hdc

Identifies the device context.

nLeftRect

Specifies the x-coordinate of the upper-left corner of the bounding rectangle.

nTopRect

Specifies the y-coordinate of the upper-left corner of the bounding rectangle.

nRightRect

Specifies the x-coordinate of the lower-right corner of the bounding rectangle.

nBottomRect

Specifies the y-coordinate of the lower-right corner of the bounding rectangle.

nXRadial1

Specifies the x-coordinate of the endpoint of the first radial.

nYRadial1

Specifies the y-coordinate of the endpoint of the first radial.

nXRadial2

Specifies the x-coordinate of the endpoint of the second radial.

nYRadial2

Specifies the y-coordinate of the endpoint of the second radial.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The curve of the pie is defined by an ellipse that fits the specified bounding rectangle. The curve begins at the point where the ellipse intersects the first radial and extends counterclockwise to the point where the ellipse intersects the second radial. (A radial is a line drawn from the center of the ellipse to the specified endpoint on the ellipse.)

The current position is neither used nor updated by the Pie function.

Windows 95 only: The sum of the coordinates of the bounding rectangle cannot exceed 32,767. The sum of nLeftRect and nRightRect or nTopRect and nBottomRect parameters cannot exceed 32,767.

See Also

AngleArc, Arc, ArcTo, Chord


PlayEnhMetaFile
PlayEnhMetaFile  QuickInfo  Overview  Group

The PlayEnhMetaFile function displays the picture stored in the specified enhanced-format metafile.

BOOL PlayEnhMetaFile(

HDC  hdc,	// handle of a device context
HENHMETAFILE  hemf,	// handle of an enhanced metafile
CONST RECT *  lpRect	// address of bounding rectangle
);
Parameters

hdc

Identifies the device context for the output device on which the picture will appear.

hemf

Identifies the enhanced metafile.

lpRect

Points to a RECT structure that contains the coordinates of the bounding rectangle used to display the picture. The coordinates are specified in logical units.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

When an application calls the PlayEnhMetaFile function, Windows uses the picture frame in the enhanced-metafile header to map the picture onto the rectangle pointed to by the lpRect parameter. (This picture may be sheared or rotated by setting the world transform in the output device before calling PlayEnhMetaFile.) Points along the edges of the rectangle are included in the picture.

An enhanced-metafile picture can be clipped by defining the clipping region in the output device before playing the enhanced metafile.

If an enhanced metafile contains an optional palette, an application can achieve consistent colors by setting up a color palette on the output device before calling PlayEnhMetaFile. To retrieve the optional palette, use the GetEnhMetaFilePaletteEntries function.

An enhanced metafile can be embedded in a newly created enhanced metafile by calling PlayEnhMetaFile and playing the source enhanced metafile into the device context for the new enhanced metafile.

The states of the output device context are preserved by this function. Any object created but not deleted in the enhanced metafile is deleted by this function.

To stop this function, an application can call the CancelDC function from another thread to terminate the operation. In this case, the function returns FALSE.

Windows 95: PlayEnhMetaFile is subject to the limitations of the Windows 95 GDI. For example, Windows 95 supports only 16-bit signed coordinates. For records that contain 32-bit values, Windows 95 fails to play the record if the values are not in the range -32,768 to 32,767.

See Also

CancelDC, GetEnhMetaFileHeader, GetEnhMetaFilePaletteEntries, RECT, SetWorldTransform


PlayEnhMetaFileRecord
PlayEnhMetaFileRecord  QuickInfo  Overview  Group

The PlayEnhMetaFileRecord function plays an enhanced-metafile record by executing the graphics device interface (GDI) functions identified by the record.

BOOL PlayEnhMetaFileRecord(

HDC  hdc,	// handle of device context
LPHANDLETABLE  lpHandletable,	// address of metafile handle table
CONST ENHMETARECORD *  lpEnhMetaRecord,	// address of metafile record
UINT  nHandles	// count of handles
);
Parameters

hdc

Identifies the device context passed to the EnumEnhMetaFile function.

lpHandletable

Points to a table of handles identifying GDI objects used when playing the metafile. The first entry in this table contains the enhanced-metafile handle.

lpEnhMetaRecord

Points to the enhanced-metafile record to be played.

nHandles

Specifies the number of handles in the handle table.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

This is an enhanced-metafile function.

An application typically uses PlayEnhMetaFileRecord in conjunction with the EnumEnhMetaFile function to process and play an enhanced-format metafile one record at a time.

The hdc, lpHandletable, and nHandles parameters must be exactly those passed to the EnhMetaFileProc callback procedure by the EnumEnhMetaFile function.

If PlayEnhMetaFileRecord does not recognize a record, it ignores the record and returns TRUE.

Windows 95: PlayEnhMetaFileRecord is subject to the limitations of the Windows 95 GDI. For example, Windows 95 supports only 16-bit signed coordinates. For records that contain 32-bit values, Windows 95 fails to play the record if the values are not in the range -32,768 to 32,767.

See Also

EnumEnhMetaFile, PlayEnhMetaFile


PlayMetaFile
PlayMetaFile  QuickInfo  Overview  Group

The PlayMetaFile function displays the picture stored in the given Windows-format metafile on the specified device.

This function is provided for compatibility with 16-bit versions of Windows. Win32-based applications should use the PlayEnhMetaFile function.

BOOL PlayMetaFile(

HDC  hdc,	// handle of the device context
HMETAFILE  hmf	// handle of the metafile
);
Parameters

hdc

Identifies a device context.

hmf

Identifies a Windows-format metafile.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

A Windows-format metafile does not support the new curve, path, and transformation functions such as PolyBezier, BeginPath, and SetWorldTransform. Applications that use these new functions and use metafiles to store pictures created by these functions should use the enhanced-format metafile functions.

To convert a Windows-format metafile into an enhanced format metafile, use the SetWinMetaFileBits function.

A Windows-format metafile can be played multiple times.

A Windows-format metafile can be embedded in a second Windows-format metafile by calling the PlayMetaFile function and playing the source metafile into the device context for the target metafile.

Any object created but not deleted in the Windows-format metafile is deleted by this function.

To stop this function, an application can call the CancelDC function from another thread to terminate the operation. In this case, the function returns FALSE.

See Also

BeginPath, CancelDC, PolyBezier, SetWinMetaFileBits, SetWorldTransform


PlayMetaFileRecord
PlayMetaFileRecord  QuickInfo  Overview  Group

The PlayMetaFileRecord function plays a Windows-format metafile record by executing the graphics device interface (GDI) function contained within that record.

This function is provided for compatibility with 16-bit versions of Microsoft Windows. Win32-based applications should use the PlayEnhMetaFileRecord function.

BOOL PlayMetaFileRecord(

HDC  hdc,	// handle of device context
LPHANDLETABLE  lpHandletable,	// address of metafile handle table
LPMETARECORD  lpMetaRecord,	// address of metafile record
UINT  nHandles	// count of handles
);
Parameters

hdc

Identifies a device context.

lpHandletable

Points to a table of handles identifying GDI objects used when playing the metafile.

lpMetaRecord

Points to the Windows-format metafile record.

nHandles

Specifies the number of handles in the handle table.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

A Windows-format metafile does not support the new curve, path, and transformation functions, such as PolyBezier, BeginPath, and SetWorldTransform. Applications that use these new functions and use metafiles to store pictures created by these functions, should use the enhanced format metafile functions.

To convert a Windows-format metafile into an enhanced-format metafile, use the SetWinMetaFileBits function.

An application typically uses PlayMetaFileRecord in conjunction with the EnumMetaFile function to process and play a Windows-format metafile one record at a time.

The lpHandletable and nHandles parameters must be identical to those passed to the EnumMetaFileProc callback procedure by EnumMetaFile.

If the PlayMetaFileRecord function does not recognize a record, it ignores the record and returns TRUE.

See Also

BeginPath, EnumMetaFile, PlayMetaFile, PolyBezier, SetWinMetaFileBits, SetWorldTransform


PlgBlt
PlgBlt  QuickInfo  Overview  Group

The PlgBlt function performs a bit-block transfer of the bits of color data from the specified rectangle in the source device context to the specified parallelogram in the destination device context. If the given bitmask handle identifies a valid monochrome bitmap, the function uses this bitmap to mask the bits of color data from the source rectangle.

BOOL PlgBlt(

HDC  hdcDest,	// handle of destination device context
CONST POINT *  lpPoint,	// vertices of destination parallelogram
HDC  hdcSrc,	// handle of source device context
int  nXSrc,	// x-coord. of upper-left corner of source rect.
int  nYSrc,	// y-coord. of upper-left corner of source rect.
int  nWidth,	// width of source rectangle
int  nHeight,	// height of source rectangle
HBITMAP  hbmMask,	// handle of bitmask
int  xMask,	// x-coord. of upper-left corner of bitmask rect.
int  yMask	// y-coord. of upper-left corner of bitmask rect.
);
Parameters

hdcDest

Identifies the destination device context.

lpPoint

Points to an array of three points in logical space that identify three corners of the destination parallelogram. The upper-left corner of the source rectangle is mapped to the first point in this array, the upper-right corner to the second point in this array, and the lower-left corner to the third point. The lower-right corner of the source rectangle is mapped to the implicit fourth point in the parallelogram.

hdcSrc

Identifies the source device context.

nXSrc

Specifies the x-coordinate, in logical units, of the upper-left corner of the source rectangle.

nYSrc

Specifies the y-coordinate, in logical units, of the upper-left corner of the source rectangle.

nWidth

Specifies the width, in logical units, of the source rectangle.

nHeight

Specifies the height, in logical units, of the source rectangle.

hbmMask

Identifies an optional monochrome bitmap that is used to mask the colors of the source rectangle.

xMask

Specifies the x-coordinate of the upper-left corner of the the monochrome bitmap.

yMask

Specifies the y-coordinate of the upper-left corner of the the monochrome bitmap.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The fourth vertex of the parallelogram (D) is defined by treating the first three points (A, B, and C) as vectors and computing D = B + C − A.

If the bitmask exists, a value of 1 in the mask indicates that the source pixel color should be copied to the destination. A value of 0 in the mask indicates that the destination pixel color is not to be changed.

If the mask rectangle is smaller than the source and destination rectangles, the function replicates the mask pattern.

Scaling, translation, and reflection transformations are allowed in the source device context; however, rotation and shear transformations are not.

If the mask bitmap is not a monochrome bitmap, an error occurs.

The stretching mode for the destination device context is used to determine how to stretch or compress the pixels, if that is necessary.

When an enhanced metafile is being recorded, an error occurs if the source device context identifies an enhanced-metafile device context.

The destination coordinates are transformed according to the destination device context; the source coordinates are transformed according to the source device context. If the source transformation has a rotation or shear, an error is returned.

If the destination and source rectangles do not have the same color format, PlgBlt converts the source rectangle to match the destination rectangle.

Not all devices support the PlgBlt function. For more information, see the description of the RC_BITBLT raster capability in the GetDeviceCaps function.

If the source and destination device contexts represent incompatible devices, PlgBlt returns an error.

See Also

BitBlt, GetDeviceCaps, MaskBlt, SetStretchBltMode, StretchBlt


PolyBezier
PolyBezier  QuickInfo  Overview  Group

The PolyBezier function draws one or more Bézier curves.

BOOL PolyBezier(

HDC  hdc,	// handle of device context
CONST POINT *  lppt,	// address of endpoints and control points
DWORD  cPoints	// count of endpoints and control points
);
Parameters

hdc

Identifies a device context.

lppt

Points to an array of POINT structures that contain the endpoints and control points of the curve(s).

cPoints

Specifies the number of points in the lppt array. This value must be one more than three times the number of curves to be drawn, because each Bézier curve requires two control points and an endpoint, and the initial curve requires an additional starting point.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

Th Polybezier function draws cubic Bézier curves by using the endpoints and control points specified by the lppt parameter. The first curve is drawn from the first point to the fourth point by using the second and third points as control points. Each subsequent curve in the sequence needs exactly three more points: the ending point of the previous curve is used as the starting point, the next two points in the sequence are control points, and the third is the ending point.

The current position is neither used nor updated by the PolyBezier function. The figure is not filled.

This function draws lines by using the current pen.

See Also

MoveToEx, POINT, PolyBezierTo


PolyBezierTo
PolyBezierTo  QuickInfo  Overview  Group

The PolyBezierTo function draws one or more Bézier curves.

BOOL PolyBezierTo(

HDC  hdc,	// handle of device context
CONST POINT *  lppt,	// address of endpoints and control points
DWORD  cCount	// count of endpoints and control points
);
Parameters

hdc

Identifies a device context.

lppt

Points to an array of POINT structures that contains the endpoints and control points.

cCount

Specifies the number of points in the lppt array. This value must be three times the number of curves to be drawn, because each Bézier curve requires two control points and an ending point.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

This function draws cubic Bézier curves by using the control points specified by the lppt parameter. The first curve is drawn from the current position to the third point by using the first two points as control points. For each subsequent curve, the function needs exactly three more points, and uses the ending point of the previous curve as the starting point for the next.

PolyBezierTo moves the current position to the ending point of the last Bézier curve. The figure is not filled.

This function draws lines by using the current pen.

See Also

MoveToEx, POINT, PolyBezier


PolyDraw
PolyDraw  QuickInfo  Overview  Group

The PolyDraw function draws a set of line segments and Bézier curves.

BOOL PolyDraw(

HDC  hdc,	// handle of a device context
CONST POINT *  lppt,	// address of array of points
CONST BYTE *  lpbTypes,	// address of line and curve identifiers
int  cCount	// count of points
);
Parameters

hdc

Identifies a device context.

lppt

Points to an array of POINT structures that contains the endpoints for each line segment and the endpoints and control points for each Bézier curve.

lpbTypes

Points to an array that specifies how each point in the lppt array is used. Types can be one of the following:

Type	Meaning
PT_MOVETO	Specifies that this point starts a disjoint figure. This point becomes the new current position.
PT_LINETO	Specifies that a line is to be drawn from the current position to this point, which then becomes the new current position.
PT_BEZIERTO	Specifies that this point is a control point or ending point for a Bézier curve.
	PT_BEZIERTO types always occur in sets of three. The current position defines the starting point for the Bézier curve. The first two PT_BEZIERTO points are the control points, and the third PT_BEZIERTO point is the ending point. The ending point becomes the new current position. If there are not three consecutive PT_BEZIERTO points, an error results.
A PT_LINETO or PT_BEZIERTO type can be combined with the following value by using the bitwise operator OR to indicate that the corresponding point is the last point in a figure and the figure is closed:

Value	Meaning
PT_CLOSEFIGURE	Specifies that the figure is automatically closed after the PT_LINETO or PT_BEZIERTO type for this point is done. A line is drawn from this point to the most recent PT_MOVETO or MoveTo point.
	This value is combined with the PT_LINETO type for a line, or with the PT_BEZIERTO type of the ending point for a Bézier curve, by using the bitwise operator OR.
	The current position is set to the ending point of the closing line.
cCount

Specifies the total number of points in the lppt array, the same as the number of bytes in the lpbTypes array.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

The PolyDraw function can be used in place of consecutive calls to MoveTo, LineTo, and PolyBezierTo functions to draw disjoint figures. The lines and curves are drawn using the current pen and figures are not filled. If there is an active path started by calling BeginPath, PolyDraw adds to the path.

The points contained in the lppt array and in the lpbTypes array indicate whether each point is part of a MoveTo, LineTo, or PolyBezierTo operation. It is also possible to close figures.

This function updates the current position.

See Also

BeginPath, EndPath, LineTo, MoveTo, POINT, PolyBezierTo, PolyLine


Polygon
Polygon  QuickInfo  Overview  Group

The Polygon function draws a polygon consisting of two or more vertices connected by straight lines. The polygon is outlined by using the current pen and filled by using the current brush and polygon fill mode.

BOOL Polygon(

HDC  hdc,	// handle of device context
CONST POINT  *lpPoints,	// address of polygon's vertices
int  nCount	// count of polygon's vertices
);
Parameters

hdc

Identifies the device context.

lpPoints

Points to an array of POINT structures that specify the vertices of the polygon.

nCount

Specifies the number of vertices in the array. This value must be greater than or equal to 2.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The polygon is closed automatically by drawing a line from the last vertex to the first.

The current position is neither used nor updated by the Polygon function.

See Also

GetPolyFillMode, POINT, Polyline, PolylineTo, PolyPolygon, SetPolyFillMode


Polyline
Polyline  QuickInfo  Overview  Group

The Polyline function draws a series of line segments by connecting the points in the specified array.

BOOL Polyline(

HDC  hdc,	// handle of device context
CONST POINT  *lppt,	// address of array containing endpoints
int  cPoints	// number of points in the array
);
Parameters

hdc

Identifies a device context.

lppt

Points to an array of POINT structures. Each structure in the array identifies a point in logical space.

cPoints

Specifies the number of points in the array. This number must be greater than or equal to two.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

The lines are drawn from the first point through subsequent points by using the current pen. Unlike the LineTo function, the Polyline function neither uses nor updates the current position.

See Also

LineTo, MoveToEx, POINT, PolylineTo, PolyPolyline


PolylineTo
PolylineTo  QuickInfo  Overview  Group

The PolylineTo function draws one or more straight lines.

BOOL PolylineTo(

HDC  hdc,	// handle of device context
CONST POINT *  lppt,	// address of array of points
DWORD  cCount	// number of points in array
);
Parameters

hdc

Identifies the device context.

lppt

Points to an array of POINT structures that contains the vertices of the line.

cCount

Specifies the number of points in the array.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

A line is drawn from the current position to the first point specified by the lppt parameter by using the current pen. For each additional line, the function draws from the ending point of the previous line to the next point specified by lppt.

PolylineTo moves the current position to the ending point of the last line.

If the line segments drawn by this function form a closed figure, the figure is not filled.

See Also

LineTo, MoveToEx, POINT, Polyline


PolyPolygon
PolyPolygon  QuickInfo  Overview  Group

The PolyPolygon function draws a series of closed polygons. Each polygon is outlined by using the current pen and filled by using the current brush and polygon fill mode. The polygons drawn by this function can overlap.

BOOL PolyPolygon(

HDC  hdc,	// handle of device context
CONST POINT  *lpPoints,	// points to array of vertices for all polygons
LPINT  lpPolyCounts,	// points to array with count of vertices for each polygon
int  nCount	// count of polygons
);
Parameters

hdc

Identifies the device context.

lpPoints

Points to an array of POINT structures that define the vertices of the polygons. The polygons are specified consecutively. Each polygon is closed automatically by drawing a line from the last vertex to the first. Each vertex should be specified once.

lpPolyCounts

Points to an array of integers, each of which specifies the number of points in the corresponding polygon. Each integer must be greater than or equal to 2.

nCount

Specifies the total number of polygons.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The current position is neither used nor updated by this function.

See Also

GetPolyFillMode, POINT, Polygon, Polyline, PolylineTo, SetPolyFillMode


PolyPolyline
PolyPolyline  QuickInfo  Overview  Group

The PolyPolyline function draws multiple series of connected line segments.

BOOL PolyPolyline(

HDC  hdc,	// handle of a device context
CONST POINT *  lppt,	// address of an array of points
CONST DWORD *  lpdwPolyPoints,	// address of an array of values
DWORD  cCount	// number of counts in the second array
);
Parameters

hdc

Identifies the device context.

lppt

Points to an array of POINT structures that contains the vertices of the polylines. The polylines are specified consecutively.

lpdwPolyPoints

Points to an array of variables specifying the number of points in the lppt array for the corresponding polygon. Each entry must be greater than or equal to two.

cCount

Specifies the total number of counts in the lpdwPolyPoints array.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

The line segments are drawn by using the current pen. The figures formed by the segments are not filled.

The current position is neither used nor updated by this function.

See Also

POINT, Polyline, PolylineTo


PolyTextOut
PolyTextOut  QuickInfo  Overview  Group

The PolyTextOut function draws several strings using the font and text colors currently selected in the specified device context.

BOOL PolyTextOut(

HDC  hdc,	// handle of device context
CONST POLYTEXT *  pptxt,	// address of array of structures that identify strings
int  cStrings	// number of structures in array
);
Parameters

hdc

Identifies the device context.

pptxt

Points to an array of POLYTEXT structures describing the strings to be drawn. The array contains one structure for each string to be drawn.

cStrings

Specifies the number of POLYTEXT structures in the pptxt array.

Return Value

If the function is successful, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Each POLYTEXT structure contains the coordinates of a reference point that Windows uses to align the corresponding string of text. An application can specify how the reference point is used by calling the SetTextAlign function. An application can determine the current text-alignment setting for the specified device context by calling the GetTextAlign function.

To draw a single string of text, the application should call the ExtTextOut function.

See Also

ExtTextOut, GetTextAlign, POLYTEXT, SetTextAlign


PostAppMessage
PostAppMessage  QuickInfo  Overview  Group

The PostAppMessage function is retained only for compatibility with 16-bit versions of Windows. Win32-based applications should use the PostThreadMessage function.

Remarks

The PostAppMessage function used a process identifier as its first parameter, but its replacement, the PostThreadMessage function, uses a thread identifier as its first parameter.

See Also

PostThreadMessage


PostMessage
PostMessage  QuickInfo  Overview  Group

The PostMessage function places (posts) a message in the message queue associated with the thread that created the specified window and then returns without waiting for the thread to process the message. Messages in a message queue are retrieved by calls to the GetMessage or PeekMessage function.

BOOL PostMessage(

HWND  hwnd,	// handle of destination window
UINT  uMsg,	// message to post
WPARAM  wParam,	// first message parameter
LPARAM  lParam	// second message parameter
);
Parameters

hwnd

Identifies the window whose window procedure is to receive the message. Two values have special meanings:

Value	Meaning
HWND_BROADCAST	The message is posted to all top-level windows in the system, including disabled or invisible unowned windows, overlapped windows, and pop-up windows. The message is not posted to child windows.
NULL	The function behaves like a call to PostThreadMessage with the dwThreadId parameter set to the identifier of the current thread.
uMsg

Specifies the message to be posted.

wParam

Specifies additional message-specific information.

lParam

Specifies additional message-specific information.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

A 32-bit application should not post messages less than WM_USER that contain pointers.

See Also

GetMessage, PeekMessage, PostThreadMessage, SendDlgItemMessage, SendMessage


PostQueuedCompletionStatus [New - Windows NT]
PostQueuedCompletionStatus  QuickInfo

[New - Windows NT]

The PostQueuedCompletionStatus function lets you post an I/O completion packet to an I/O completion port. The I/O completion packet will satisfy an outstanding call to the GetQueuedCompletionStatus function. The GetQueuedCompletionStatus function returns with the three values passed as the second, third, and fourth parameters of the call to PostQueuedCompletionStatus.

BOOL PostQueuedCompletionStatus(

HANDLE CompletionPort,	// handle to an I/O completion port
DWORD dwNumberOfBytesTransferred,	// value to return via  //     GetQueuedCompletionStatus'  //     lpNumberOfBytesTranferred
DWORD dwCompletionKey,	// value to return via  //     GetQueuedCompletionStatus'  //     lpCompletionKey
LPOVERLAPPED lpOverlapped	// value to return via  //     GetQueuedCompletionStatus' lpOverlapped
);
Parameters

CompletionPort

Handle to an I/O completion port that you want to post an I/O completion packet to.

dwNumberOfBytesTransferred

Specifies a value to be returned through the lpNumberOfBytesTransferred parameter of the GetQueuedCompletionStatus function.

dwCompletionKey

Specifies a value to be returned through the lpCompletionKey parameter of the GetQueuedCompletionStatus function.

lpOverlapped

Specifies a value to be returned through the lpOverlapped parameter of the GetQueuedCompletionStatus function.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError .

Remarks

For more information concerning dwNumberOfBytesTransferred, dwCompletionKey, and lpOverlapped, see GetQueuedCompletionStatus and the descriptions of the parameters those values are returned through.

See Also

CreateIoCompletionPort, GetQueuedCompletionStatus, OVERLAPPED


PostQuitMessage
PostQuitMessage  QuickInfo  Overview  Group

The PostQuitMessage function indicates to Windows that a thread has made a request to terminate (quit). It is typically used in response to a WM_DESTROY message.

VOID PostQuitMessage(

int  nExitCode	// exit code
);
Parameters

nExitCode

Specifies an application exit code. This value is used as the wParam parameter of the WM_QUIT message.

Return Value

This function does not return a value.

Remarks

The PostQuitMessage function posts a WM_QUIT message to the thread's message queue and returns immediately; the function simply indicates to the system that the thread is requesting to quit at some time in the future.

When the thread retrieves the WM_QUIT message from its message queue, it should exit its message loop and return control to Windows. The exit value returned to Windows must be the wParam parameter of the WM_QUIT message.

See Also

GetMessage, PeekMessage, PostMessage, WM_DESTROY, WM_QUIT


PostThreadMessage
PostThreadMessage  QuickInfo  Overview  Group

The PostThreadMessage function places (posts) a message in the message queue of the specified thread and then returns without waiting for the thread to process the message.

BOOL PostThreadMessage(

DWORD  dwThreadId,	// thread identifier
UINT  uMsg,	// message to post
WPARAM  wParam,	// first message parameter
LPARAM  lParam	// second message parameter
);
Parameters

dwThreadId

Identifies the thread to which the message will be posted.

The function fails if the specified thread does not have a message queue. The system creates a thread's message queue when the thread makes its first call to one of the Win32 USER or GDI functions.

uMsg

Specifies the type of message to be posted.

wParam

Specifies additional message-specific information.

lParam

Specifies additional message-specific information.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

This function replaces the PostAppMessage function. New Win32-based applications should use PostThreadMessage. The thread to which the message is posted retrieves the message by calling the GetMessage or PeekMessage function. The hwnd member of the returned MSG structure is NULL.

See Also

GetCurrentThreadId, GetMessage, GetWindowThreadProcessId, MSG, PeekMessage, PostMessage


PrepareTape
PrepareTape  QuickInfo  Overview  Group

The PrepareTape function prepares the tape to be accessed or removed.

DWORD PrepareTape(

HANDLE  hDevice,	// handle of open device
DWORD  dwOperation,	// preparation method
BOOL  bImmediate	// return after operation begins
);
Parameters

hDevice

Identifies the device preparing the tape. This handle is created by using the CreateFile function.

dwOperation

Specifies how the tape device is to be prepared. This parameter can be one of the following values:

Value	Meaning
TAPE_FORMAT	Performs a low-level format of the tape. Currently, only the QIC117 device supports this feature.
TAPE_LOAD	Loads the tape and moves the tape to the beginning.
TAPE_LOCK	Locks the tape ejection mechanism so that the tape is not ejected accidentally.
TAPE_TENSION	Adjusts the tension by moving the tape to the end of the tape and back to the beginning. This option is not supported by all devices. This value is ignored if it is not supported.
TAPE_UNLOAD	Moves the tape to the beginning for removal from the device. After a successful unload operation, the device returns errors to applications that attempt to access the tape, until the tape is loaded again.
TAPE_UNLOCK	Unlocks the tape ejection mechanism.
bImmediate

Specifies whether to return as soon as the preparation begins. If this parameter is TRUE, the function returns immediately. If it is FALSE, the function does not return until the operation has been completed.

Return Value

If the function succeeds, the return value is NO_ERROR.

If the function fails, the return value is one of the following error codes:

Error	Description
ERROR_BEGINNING_OF_MEDIA	An attempt to access data before the beginning-of-medium marker failed.
ERROR_BUS_RESET	A reset condition was detected on the bus.
ERROR_END_OF_MEDIA	The end-of-tape marker was reached during an operation.
ERROR_FILEMARK_DETECTED	A filemark was reached during an operation.
ERROR_SETMARK_DETECTED	A setmark was reached during an operation.
ERROR_NO_DATA_DETECTED	The end-of-data marker was reached during an operation.
ERROR_PARTITION_FAILURE	The tape could not be partitioned.
ERROR_INVALID_BLOCK_LENGTH	The block size is incorrect on a new tape in a multivolume partition.
ERROR_DEVICE_NOT_PARTITIONED	The partition information could not be found when a tape was being loaded.
ERROR_MEDIA_CHANGED	The tape that was in the drive has been replaced or removed.
ERROR_NO_MEDIA_IN_DRIVE	There is no media in the drive.
ERROR_NOT_SUPPORTED	The tape driver does not support a requested function.
ERROR_UNABLE_TO_LOCK_MEDIA	An attempt to lock the ejection mechanism failed.
ERROR_UNABLE_TO_UNLOAD_MEDIA	An attempt to unload the tape failed.
ERROR_WRITE_PROTECT	The media is write protected.
Remarks

Some tape devices do not support certain tape operations. See your tape device documentation and use the GetTapeParameters function to determine your tape device's capabilities.

See Also

CreateFile, GetTapeParameters


PrintDlg
PrintDlg  QuickInfo  Overview  Group

The PrintDlg function displays a Print dialog box or a Print Setup dialog box. The Print dialog box enables the user to specify the properties of a particular print job. The Print Setup dialog box allows the user to select additional job properties and to configure the printer.

BOOL PrintDlg(

LPPRINTDLG  lppd	// address of structure with initialization data
);
Parameters

lppd

Points to a PRINTDLG structure that contains information used to initialize the dialog box. When PrintDlg returns, this structure contains information about the user's selections.

Return Value

If the function succeeds in configuring the printer, the return value is TRUE. It is FALSE if an error occurs, the user chooses the Cancel button, or the user chooses the Close command on the System menu to close the dialog box. (The return value is also FALSE if the user chooses the Setup button to display the Print Setup dialog box, chooses the OK button in the Print Setup dialog box, and then chooses the Cancel button in the Print dialog box.)

The CommDlgExtendedError function can be used to get extended error information, which may be one of the following values:

CDERR_FINDRESFAILURE	PDERR_CREATEICFAILURE
CDERR_INITIALIZATION	PDERR_DEFAULTDIFFERENT
CDERR_LOADRESFAILURE	PDERR_DNDMMISMATCH
CDERR_LOADSTRFAILURE	PDERR_GETDEVMODEFAIL
CDERR_LOCKRESFAILURE	PDERR_INITFAILURE
CDERR_MEMALLOCFAILURE	PDERR_LOADDRVFAILURE
CDERR_MEMLOCKFAILURE	PDERR_NODEFAULTPRN
CDERR_NOHINSTANCE	PDERR_NODEVICES
CDERR_NOHOOK	PDERR_PARSEFAILURE
CDERR_NOTEMPLATE	PDERR_PRINTERNOTFOUND
CDERR_STRUCTSIZE	PDERR_RETDEFFAILURE
Remarks

If the hook function (pointed to by the lpfnPrintHook or lpfnSetupHook member of the PRINTDLG structure) processes the WM_CTLCOLORDLG message, the hook function must return a handle for the brush that should be used to paint the control background.

If you specify the PD_RETURNDC value in the Flags member of the PRINTDLG structure and the user selects Print To File from the Print dialog box, you can use the DC returned in the hDC member of the structure to generate output, but only after you prepare the file for output by specifying the name of the file in the lpszOutput member of the DOCINFO structure and calling the StartDoc function.

See Also

CommDlgExtendedError, CreateDC, DOCINFO, PRINTDLG, StartDoc, WM_CTLCOLORDLG


PrinterMessageBox
PrinterMessageBox  QuickInfo  Overview  Group

The PrinterMessageBox function displays a message box that lets an application that is printing notify the user of a printing job error. If the owner of the job is logged on remotely, the function sends a net popup to the owner. If the user selects Cancel in the message box, the function cancels the print job; otherwise, the function clears the job error status, and the system tries to print the job again.

HPRINTER PrinterMessageBox (

HANDLE  hPrinter,	// handle of printer
DWORD  dwError,	// error identifier
HWND  hwndOwner,	// handle of owner window
LPTSTR  pText,	// pointer to message box text
LPTSTR  pCaption,	// pointer to message box title
DWORD  dwType	// style of message box
);
Parameters

hPrinter

Identifies the printer to which the job was sent.

dwError

Specifies the error that occurred. This parameter can be one of the following values:

Value	Meaning
ERROR_OUT_OF_PAPER	The printer is out of paper.
ERROR_NOT_READY	The printer is not ready.
hwndOwner

Identifies an owner window for the message box the function creates. If this parameter is NULL, the message box has no owner window.

pText

Points to a null-terminated string that specifies the message to be displayed.

pCaption

Points to a null-terminated string that specifies the dialog box title. If this parameter is NULL, the function uses the default title "Error".

dwType

Specifies the contents and behavior of the dialog box. This parameter can be a combination of any of the values accepted by the MessageBox function's fourth parameter; however, it is recommended that an application use the following combination:

   MB_ICONSTOP | MB_RETRYCANCEL | MB_SETFOREGROUND

Return Value

If PrinterMessageBox sends a net popup, the return value is IDOK. Otherwise, the function returns the value returned by the message box the function displays. Two typical return values are the following:

Value	Meaning
IDCANCEL	Cancel button was selected.
IDRETRY	Retry button was selected.
For a more complete list of message box return values, see MessageBox.

See Also

MessageBox


PrinterProperties
PrinterProperties  QuickInfo  Overview  Group

The PrinterProperties function displays a printer-properties dialog box for the specified printer.

BOOL PrinterProperties(

hwnd  hwnd,	// handle of parent window
HANDLE  hPrinter	// handle of printer object
);
Parameters

hwnd

Identifies the parent window of the dialog box.

hPrinter

Identifies a printer object.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

OpenPrinter


PrivilegeCheck
PrivilegeCheck  QuickInfo  Overview  Group

The PrivilegeCheck function tests the security context represented by a specific access token to discover whether it contains the specified privileges. This function is typically called by a server application to check the privileges of a client's access token.

BOOL PrivilegeCheck(

HANDLE  hClientToken,	// handle of client's access token
PPRIVILEGE_SET  pps,	// address of privileges
LPBOOL  lpfResult	// address of flag for result
);
Parameters

hClientToken

Identifies an access token representing a client process. This handle must have been obtained by opening the token of a thread impersonating the client. The token must be open for TOKEN_QUERY access.

pps

Points to a PRIVILEGE_SET structure specifying the privileges required.

The specified access token is checked to see which of the specified privileges are present. When a privilege specified in the PRIVILEGE_SET structure is found in the access token, the function sets the SE_PRIVILEGE_USED_FOR_ACCESS attribute for that privilege in the corresponding LUID_AND_ATTRIBUTES structure.

lpfResult

Points to a flag the function sets to indicate whether the access token contains any or all of the specified privileges. If PRIVILEGE_SET_ALL_NECESSARY is specified in the Control member of the PRIVILEGE_SET structure pointed to by the pps parameter, this flag is TRUE only if all requested privileges are present in the access token. If PRIVILEGE_SET_ALL_NECESSARY is not specified, and if any of the privileges are present, this flag is TRUE.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

AccessCheck, AccessCheckAndAuditAlarm, AreAllAccessesGranted, AreAnyAccessesGranted, LookupPrivilegeDisplayName, LookupPrivilegeName, LookupPrivilegeValue, LUID_AND_ATTRIBUTES, ObjectPrivilegeAuditAlarm, PRIVILEGE_SET, PrivilegedServiceAuditAlarm


PrivilegedServiceAuditAlarm
PrivilegedServiceAuditAlarm  QuickInfo  Overview  Group

The PrivilegedServiceAuditAlarm function generates audit messages when an attempt is made to perform privileged system service operations. Alarms are not supported in the current version of Windows NT.

BOOL PrivilegedServiceAuditAlarm(

LPCTSTR  lpszSubsystem,	// address of string for subsystem name
LPCTSTR  lpszService,	// address of string for service name
HANDLE  hClientToken,	// handle of access token
PPRIVILEGE_SET  pps,	// address of privileges
BOOL  fAccessGranted	// flag for granted access rights
);
Parameters

lpszSubsystem

Points to a null-terminated string specifying the name of the subsystem calling the function, such as "DEBUG" or "WIN32".

lpszService

Points to a null-terminated string specifying the name of the privileged subsystem service. For example, "RESET RUNTIME LOCAL SECURITY POLICY" might be specified by a local security authority service used to update the local security policy database.

hClientToken

Identifies an access token representing the client that requested the operation. This handle must have been obtained by opening the token of a thread impersonating the client. The token must be open for TOKEN_QUERY access.

pps

Points to a PRIVILEGE_SET structure containing the privileges required to perform the operation. The information in this structure is supplied by a call to the PrivilegeCheck function.

fAccessGranted

Specifies a flag indicating whether access was granted or denied in a previous call to an access-checking function, such as PrivilegeCheck. If access is granted, this flag is TRUE. If access is denied, it is FALSE.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The PrivilegedServiceAuditAlarm function requires the calling process to have SE_AUDIT_NAME privilege. The test for this privilege is always performed against the primary token of the calling process. This allows the calling process to impersonate a client during the call.

The PrivilegedServiceAuditAlarm function can send many messages to port objects. This can result in a significant delay before the function returns. The design of applications calling PrivilegedServiceAuditAlarm can take this potential delay into account. For example, this consideration may affect the design of an application that uses mutexes to lock structures.

See Also

AccessCheck, AccessCheckAndAuditAlarm, AreAllAccessesGranted, AreAnyAccessesGranted, MapGenericMask, ObjectCloseAuditAlarm, ObjectOpenAuditAlarm, ObjectPrivilegeAuditAlarm, PrivilegeCheck, PRIVILEGE_SET


ProfClear
ProfClear  Overview  Group

The ProfClear function is not implemented in the Win32 API.


ProfFinish
ProfFinish  Overview  Group

The ProfFinish function is not implemented in the Win32 API.


ProfFlush
ProfFlush  Overview  Group

The ProfFlush function is not implemented in the Win32 API.


ProfInsChk
ProfInsChk  Overview  Group

The ProfInsChk function is not implemented in the Win32 API.


ProfSampRate
ProfSampRate  Overview  Group

The ProfSampRate function is not implemented in the Win32 API.


ProfSetup
ProfSetup  Overview  Group

The ProfSetup function is not implemented in the Win32 API.


ProfStart
ProfStart  Overview  Group

The ProfStart function is not implemented in the Win32 API.


ProfStop
ProfStop  Overview  Group

The ProfStop function is not implemented in the Win32 API.


PropEnumProc
PropEnumProc  QuickInfo  Overview  Group

A PropEnumProc function is an application-defined callback function that receives property entries from a window's property list. A PropEnumProc function is called as a result of a call to the EnumProps function. A value of type PROPENUMPROC is a pointer to a PropEnumProc function.

BOOL CALLBACK PropEnumProc(

HWND  hwnd,	// handle to window whose property list is being enumerated
LPCTSTR  lpszString,	// string component of property
HANDLE  hData	// data handle component of property
);
Parameters

hwnd

Handle to the window whose property list is being enumerated.

lpszString

Pointer to a null-terminated string. This string is the string component of a property list entry. This is the string that was specified, along with a data handle, when the property was added to the window's property list via a call to the SetProp function.

hData

Handle to data. This handle is the data component of a property list entry.

Return Value

The callback function should return TRUE to continue the property list enumeration.

The callback function should return FALSE to stop the property list enumeration.

Remarks

The following restrictions apply to this callback function:

•	The callback function must not yield control or do anything that might yield control to other tasks.

•	The callback function can call the RemoveProp function. However, RemoveProp can remove only the property passed to the callback function through the callback function's parameters.

•	The callback function should not attempt to add properties.

PropEnumProc is a placeholder for the application-defined function name.

See Also

EnumProps, EnumPropsEx, PropEnumProcEx, RemoveProp, SetProp


PropEnumProcEx
PropEnumProcEx  QuickInfo  Overview  Group

A PropEnumProcEx function is an application-defined callback function that receives property entries from a window's property list. A PropEnumProcEx function is called as a result of a call to the EnumPropsEx function. A value of type PROPENUMPROCEX is a pointer to a PropEnumProcEx function.

BOOL CALLBACK PropEnumProcEx(

HWND  hwnd,	// handle of window with property
LPCTSTR  lpszString,	// string component of property
HANDLE  hData,	// data handle component of property
DWORD  dwData	// application-defined data
);
Parameters

hwnd

Handle to the window whose property list is being enumerated.

lpszString

Pointer to a null-terminated string. This string is the string component of a property list entry. This is the string that was specified, along with a data handle, when the property was added to the window's property list via a call to the SetProp function.

hData

Handle to data. This handle is the data component of a property list entry.

dwData

Application-defined data. This is the value that was specified as the lParam parameter of the call to EnumPropsEx that initiated the enumeration.

Return Value

The callback function should return TRUE to continue the property list enumeration.

The callback function should return FALSE to stop the property list enumeration.

Remarks

The following restrictions apply to this callback function:

•	The callback function must not yield control or do anything that might yield control to other tasks.

•	The callback function can call the RemoveProp function. However, RemoveProp can remove only the property passed to the callback function through the callback function's parameters.

•	The callback function should not attempt to add properties.

PropEnumProcEx is a placeholder for the application-defined function name.

See Also

EnumProps, EnumPropsEx, PropEnumProc, RemoveProp, SetProp


PropertySheet [New - Windows NT]
PropertySheet  Overview  Group

[New - Windows NT]

The PropertySheet function creates a property sheet and adds the pages defined in the specified property sheet header structure.

int PropertySheet(

LPCPROPSHEETHEADER  lppsph
);
Parameters

lppsph

Pointer to a PROPSHEETHEADER structure that defines the frame and pages of a property sheet.

Return Value

Returns a positive value if successful or − 1 otherwise.

If the dwFlags member of the PROPSHEETHEADER structure specifies the PSH_MODELESS flag, the successful return value is the window handle of the property sheet dialog.

The following return values have a special meaning:

Value	Meaning
ID_PSREBOOTSYSTEM	A page sent the PSM_REBOOTSYSTEM message to the property sheet. The computer must be restarted for the user's changes to take effect.
ID_PSRESTARTWINDOWS	A page sent the PSM_RESTARTWINDOWS message to the property sheet. Windows must be restarted for the user's changes to take effect.
Remarks

By default, PropertySheet creates a modal dialog. If the dwFlags member of the PROPSHEETHEADER structure specifies the PSH_MODELESS flag, PropertySheet creates a modeless dialog and returns immediately after the dialog is created. In this case, the PropertySheet return value is the window handle of the modeless dialog.

For a modeless property sheet, your message loop should use PSM_ISDIALOGMESSAGE to pass messages to the property sheet dialog. Your message loop should use PSM_GETCURRENTPAGEHWND to determine when to destroy the dialog. When the user selects the OK or Cancel button, PSM_GETCURRENTPAGEHWND returns NULL, and you can then use the DestroyWindow function to destroy the dialog.

See Also

DestroyWindow, PROPSHEETHEADER, PSM_GETCURRENTPAGEHWND, PSM_ISDIALOGMESSAGE, PSM_REBOOTSYSTEM, PSM_RESTARTWINDOWS


PropSheetPageProc [New - Windows NT]
PropSheetPageProc  QuickInfo  Overview  Group

[New - Windows NT]

The PropSheetPageProc function specifies an application-defined callback function that a property sheet calls when a page is created and when it is about to be destroyed. An application can use this function to perform initialization and cleanup operations for the page.

UINT CALLBACK PropSheetPageProc(

HWND  hwnd,
UINT  uMsg,
LPPROPSHEETPAGE  ppsp
);
Parameters

hwnd

Reserved; must be NULL.

uMsg

Action flag. This parameter can be one of the following values:

Value	Meaning
PSPCB_CREATE	A page is being created. Return nonzero to allow the page to be created or zero to prevent it.
PSPCB_RELEASE	A page is being destroyed. The return value is ignored.
ppsp

Pointer to a PROPSHEETPAGE structure that defines the page being created or destroyed.

Return Value

The return value depends on the value of uMsg.

Remarks

An application must specify the address of this callback function in the pfnCallback member of a PROPSHEETPAGE structure before specifying the address of the structure in a call to the CreatePropertySheetPage function.

See Also

CreatePropertySheetPage, PROPSHEETPAGE


PropSheetProc [New - Windows NT]
PropSheetProc  QuickInfo  Overview  Group

[New - Windows NT]

The PropSheetProc function specifies an application-defined callback function that the system calls when the property sheet is being initialized.

int CALLBACK PropSheetProc(

HWND  hwndDlg,
UINT  uMsg,
LPARAM  lParam
);
Parameters

hwndDlg

Handle to the property sheet dialog box.

uMsg

Action flag. Currently, only the PSCB_INITIALIZED value is defined, which indicates that the property sheet is being initialized.

lParam

Always zero.

Return Value

The function returns zero.

Remarks

An application must specify the address of this callback function in the pfnCallback member of a PROPSHEETHEADER structure before specifying the address of the structure in a call to the PropertySheet function.

See Also

PropertySheet, PROPSHEETHEADER


PtInRect
PtInRect  QuickInfo  Overview  Group

The PtInRect function determines whether the specified point lies within the specified rectangle. A point is within a rectangle if it lies on the left or top side or is within all four sides. A point on the right or bottom side is considered outside the rectangle.

BOOL PtInRect(

CONST RECT  *lprc,	// address of structure with rectangle
POINT  pt	// structure with point
);
Parameters

lprc

Points to a RECT structure that contains the specified rectangle.

pt

Specifies a POINT structure that contains the specified point.

Return Value

If the specified point lies within the rectangle, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

EqualRect, IsRectEmpty, POINT, RECT


PtInRegion
PtInRegion  QuickInfo  Overview  Group

The PtInRegion function determines whether the specified point is inside the specified region.

BOOL PtInRegion(

HRGN  hrgn,	// handle of region
int  X,	// x-coordinate of point
int  Y	// y-coordinate of point
);
Parameters

hrgn

Identifies the region to be examined.

X

Specifies the x-coordinate of the point.

Y

Specifies the y-coordinate of the point.

Return Value

If the specified point is in the region, the return value is TRUE.

If the function fails, the return value is FALSE.

See Also

RectInRegion


PtVisible
PtVisible  QuickInfo  Overview  Group

The PtVisible function indicates whether the specified point is within the clipping region of a device context.

BOOL PtVisible(

HDC  hdc,	// handle of device context
int  X,	// x-coordinate of point
int  Y	// y-coordinate of point
);
Parameters

hdc

Identifies the device context.

X

Specifies the logical x-coordinate of the point.

Y

Specifies the logical y-coordinate of the point.

Return Value

If the specified point is within the clipping region of the device context, the return value is TRUE; otherwise, it is FALSE.

See Also

RectVisible


PulseEvent
PulseEvent  QuickInfo  Overview  Group

The PulseEvent function provides a single operation that sets (to signaled) the state of the specified event object and then resets it (to nonsignaled) after releasing the appropriate number of waiting threads.

BOOL PulseEvent(

HANDLE  hEvent	// handle of event object
);
Parameters

hEvent

Identifies the event object. The CreateEvent or OpenEvent function returns this handle, which must have EVENT_MODIFY_STATE access.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

For a manual-reset event object, all waiting threads that can be released immediately are released. The function then resets the event object's state to nonsignaled and returns.

For an auto-reset event object, the function resets the state to nonsignaled and returns after releasing a single waiting thread, even if multiple threads are waiting.

If no threads are waiting, or if no thread can be released immediately, PulseEvent simply sets the event object's state to nonsignaled and returns.

Note that for a thread using the multiple-object wait functions (WaitForMultipleObjects, WaitForMultipleObjectsEx, and MsgWaitForMultipleObjects) to wait for all specified objects to be signaled, PulseEvent can set the event object's state to signaled and reset it to nonsignaled without causing the wait function to return. This happens if not all of the specified objects are simultaneously signaled.

See Also

CreateEvent, MsgWaitForMultipleObjects, OpenEvent, ResetEvent, SetEvent, WaitForMultipleObjects, WaitForMultipleObjectsEx, WaitForSingleObject, WaitForSingleObjectEx


PurgeComm
PurgeComm  QuickInfo  Overview  Group

The PurgeComm function can discard all characters from the output or input buffer of a specified communications resource. It can also terminate pending read or write operations on the resource.

BOOL PurgeComm(

HANDLE  hCommDev,	// handle of communications resource
DWORD  fdwAction	// action to perform
);
Parameters

hCommDev

Identifies the communications resource. The CreateFile function returns this handle.

fdwAction

Specifies the action to take. This parameter can be a combination of the following values:

Value	Meaning
PURGE_TXABORT	Terminates all outstanding write operations and returns immediately, even if the write operations have not been completed.
PURGE_RXABORT	Terminates all outstanding read operations and returns immediately, even if the read operations have not been completed.
PURGE_TXCLEAR	Clears the output buffer (if the device driver has one).
PURGE_RXCLEAR	Clears the input buffer (if the device driver has one).
Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

If a thread uses PurgeComm to flush an output buffer, the deleted characters are not transmitted. To empty the output buffer while ensuring that the contents are transmitted, call the FlushFileBuffers function (a synchronous operation). Note, however, that FlushFileBuffers is subject to flow control but not to write time-outs, and it will not return until all pending write operations have been transmitted.

See Also

CreateFile


QueryDosDevice
QueryDosDevice  QuickInfo  Overview  Group

The QueryDosDevice function lets an application obtain information about MS-DOS device names. The function can obtain the current mapping for a particular MS-DOS device name. The function can also obtain a list of all existing MS-DOS device names.

MS-DOS device names are stored as symbolic links in the Windows NT object name space. The code that converts an MS-DOS path into a corresponding Windows NT path uses these symbolic links to map MS-DOS devices and drive letters. The QueryDosDevice function provides a mechanism whereby a Win32-based application can query the names of the symbolic links used to implement the MS-DOS device namespace as well as the value of each specific symbolic link.

DWORD QueryDosDevice(

LPCTSTR  lpDeviceName,	// address of MS-DOS device name string
LPTSTR  lpTargetPath,	// address of buffer for storing query results
DWORD  ucchMax	// maximum storage capacity of buffer
);
Parameters

lpDeviceName

Pointer to an MS-DOS device name string specifying the target of the query.

This parameter can be NULL. In that case, the QueryDosDevice function will store a list of all existing MS-DOS device names into the buffer pointed to by lpTargetPath.

lpTargetPath

Pointer to a buffer that will receive the result of the query. The function fills this buffer with one or more null-terminated strings. The final null-terminated string is followed by an additional NULL.

If lpDeviceName is non-NULL, the function obtains information about the particular MS-DOS device specified by lpDeviceName. The first null-terminated string stored into the buffer is the current mapping for the device. The other null-terminated strings represent undeleted prior mappings for the device.

If lpDeviceName is NULL, the function obtains a list of all existing MS-DOS device names. Each null-terminated string stored into the buffer is the name of an existing MS-DOS device.

ucchMax

Specifies the maximum number of characters that can be stored into the buffer pointed to by lpTargetPath.

Return Value

If the function succeeds, the return value is the number of characters stored into the buffer pointed to by lpTargetPath.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

The DefineDosDevice function provides a means whereby a Win32-based application can create and modify the symbolic links used to implement the MS-DOS device namespace.

MS-DOS device names are global. Once defined, an MS-DOS device name remains visible to all processes until either it is explicity removed or the system reboots.

See Also

DefineDosDevice


QueryPerformanceCounter
QueryPerformanceCounter  QuickInfo  Overview  Group

The QueryPerformanceCounter function retrieves the current value of the high-resolution performance counter, if one exists.

BOOL QueryPerformanceCounter(

LARGE_INTEGER  *lpliPerformanceCount	// address of current counter value
);
Parameters

lpliPerformanceCount

Points to a variable that the function sets, in counts, to the current performance-counter value. If the installed hardware does not support a high-resolution performance counter, this parameter can be to zero.

Return Value

If the installed hardware supports a high-resolution performance counter, the return value is TRUE.

If the installed hardware does not support a high-resolution performance counter, the return value is FALSE.

See Also

QueryPerformanceFrequency


QueryPerformanceFrequency
QueryPerformanceFrequency  QuickInfo  Overview  Group

The QueryPerformanceFrequency function retrieves the frequency of the high-resolution performance counter, if one exists.

BOOL QueryPerformanceFrequency(

LARGE_INTEGER  *lpliPerformanceFreq	// address of current frequency
);
Parameters

lpliPerformanceFreq

Points to a variable that the function sets, in counts per second, to the current performance-counter frequency. If the installed hardware does not support a high-resolution performance counter, this parameter can be to zero.

Return Value

If the installed hardware supports a high-resolution performance counter, the return value is TRUE.

If the installed hardware does not support a high-resolution performance counter, the return value is FALSE. To get extended error information, call GetLastError.

See Also

QueryPerformanceCounter


QueryServiceConfig
QueryServiceConfig  QuickInfo  Overview  Group

The QueryServiceConfig function retrieves the configuration parameters of the specified service.

BOOL QueryServiceConfig(

SC_HANDLE  schService,	// handle of service
LPQUERY_SERVICE_CONFIG  lpqscServConfig,	// address of service config. structure
DWORD  cbBufSize,	// size of service configuration buffer
LPDWORD  lpcbBytesNeeded	// address of variable for bytes needed
);
Parameters

schService

Identifies the service. This handle is returned by the OpenService or CreateService function, and it must have SERVICE_QUERY_CONFIG access.

lpqscServConfig

Points to a QUERY_SERVICE_CONFIG structure in which the service configuration information is returned.

cbBufSize

Specifies the size, in bytes, of the buffer pointed to by the lpqscServConfig parameter.

lpcbBytesNeeded

Points to a variable that receives the number of bytes needed to return all the configuration information.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Errors

The following error codes can be set by the service control manager. Others can be set by the registry functions that are called by the service control manager.

Value	Meaning
ERROR_ACCESS_DENIED	The specified handle was not opened with SERVICE_QUERY_CONFIG access.
ERROR_INSUFFICIENT_BUFFER	There is more service configuration information than would fit into the lpqscServConfig buffer. The number of bytes required to get all the information is returned in the lpcbBytesNeeded parameter. Nothing is written to the lpqscServConfig buffer.
ERROR_INVALID_HANDLE	The specified handle is invalid.
Remarks

The QueryServiceConfig function returns the service configuration information kept in the registry for a particular service. This configuration information was first set via the CreateService function, and may have been updated via the ChangeServiceConfig function. If the service was running when the configuration information was last changed, the information returned with the QueryServiceConfig will not reflect the true configuration of the service that is running. Instead, it will reflect the configuration of the service when it is run next. Upon stopping the service, the service control manager database will be updated with the configuration that is stored in the registry. The DisplayName key is an exception to this. When the DisplayName key is changed, it takes effect immediately regardless of whether the service is running.

The lpqscServConfig buffer must be large enough to hold the strings pointed to by the members of the QUERY_SERVICE_CONFIG structure.

See Also

ChangeServiceConfig, CreateService, OpenService, QUERY_SERVICE_CONFIG, QueryServiceObjectSecurity, QueryServiceStatus


QueryServiceLockStatus
QueryServiceLockStatus  QuickInfo  Overview  Group

The QueryServiceLockStatus function retrieves the lock status of the specified service control manager database.

BOOL QueryServiceLockStatus(

SC_HANDLE  schSCManager,	// handle of svc. ctrl. mgr. database
LPQUERY_SERVICE_LOCK_STATUS  lpqslsLockStat,	// address of lock status structure
DWORD  cbBufSize,	// size of service configuration buffer
LPDWORD  lpcbBytesNeeded	// address of variable for bytes needed
);
Parameters

schSCManager

Identifies the service control manager database. The OpenSCManager function returns this handle, which must have SC_MANAGER_QUERY_LOCK_STATUS access.

lpqslsLockStat

Points to a QUERY_SERVICE_LOCK_STATUS structure in which the lock status of the specified database is returned.

cbBufSize

Specifies the size, in bytes, of the buffer pointed to by the lpqslsLockStat parameter.

lpcbBytesNeeded

Points to a variable that receives the number of bytes needed to return all the lock status information.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Errors

The following error codes may be set by the service control manager. Other error codes may be set by the registry functions that are called by the service control manager.

Value	Meaning
ERROR_ACCESS_DENIED
	The specified handle was not opened with SC_MANAGER_QUERY_LOCK_STATUS access.
ERROR_INSUFFICIENT_BUFFER
	There is more lock status information than would fit into the lpqslsLockStat buffer. The number of bytes required to get all the information is returned in the lpcbBytesNeeded parameter. Nothing is written to the lpqslsLockStat buffer.
ERROR_INVALID_HANDLE
	The specified handle is invalid.
Remarks

The QueryServiceLockStatus function returns a QUERY_SERVICE_LOCK_STATUS structure that indicates whether the specified database is locked. If the database is locked, the structure provides the account name of the user that holds the lock and the length of time that the lock has been held.

A process calls the LockServiceDatabase function to lock a service control manager database and the UnlockServiceDatabase function to release the lock.

The lpqslsLockStat buffer must be large enough to hold the string pointed to by the lpLockOwner member of the QUERY_SERVICE_LOCK_STATUS structure.

See Also

LockServiceDatabase, OpenSCManager, QUERY_SERVICE_LOCK_STATUS, UnlockServiceDatabase


QueryServiceObjectSecurity
QueryServiceObjectSecurity  QuickInfo  Overview  Group

The QueryServiceObjectSecurity function retrieves a copy of the security descriptor protecting a service object.

BOOL QueryServiceObjectSecurity(

SC_HANDLE  schService,	// handle of service
SECURITY_INFORMATION  fdwSecurityInfo,	// type of security information requested
PSECURITY_DESCRIPTOR  psdSecurityDesc,	// address of security descriptor
DWORD  cbBufSize,	// size of security descriptor buffer
LPDWORD  lpcbBytesNeeded	// address of variable for bytes needed
);
Parameters

schService

Identifies the service. This handle is returned by the OpenService or CreateService function, and it must have READ_CONTROL access.

fdwSecurityInfo

Specifies the security information being requested. Any or all of the following flags can be specified:

Value	Meaning
OWNER_SECURITY_INFORMATION
	Requests the object's owner security identifier (SID).
GROUP_SECURITY_INFORMATION
	Requests the object's primary group SID.
DACL_SECURITY_INFORMATION
	Requests the object's discretionary access control list (ACL).
SACL_SECURITY_INFORMATION
	Requests the object's system ACL. The calling process must have SeSecurityPrivilege privilege.
psdSecurityDesc

Points to a buffer that receives a copy of the security descriptor of the specified service object. The calling process must have the appropriate access to view the specified aspects of the object's security descriptor. The SECURITY_DESCRIPTOR structure is returned in self-relative format.

cbBufSize

Specifies the size, in bytes, of the buffer pointed to by the psdSecurityDesc parameter.

lpcbBytesNeeded

Points to a variable that receives the number of bytes needed to return all the requested security descriptor information.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Errors

The following error codes may be set by the service control manager. Other error codes may be set by the registry functions that are called by the service control manager.

Value	Meaning
ERROR_ACCESS_DENIED
	The specified handle was not opened with READ_CONTROL access, or the calling process is not the owner of the object.
ERROR_INVALID_HANDLE
	The specified handle is invalid.
ERROR_INSUFFICIENT_BUFFER
	There is more security descriptor information than would fit into the psdSecurityDesc buffer. The number of bytes required to get all the information is returned in the lpcbBytesNeeded parameter. Nothing is written to the psdSecurityDesc buffer.
ERROR_INVALID_PARAMETER
	The specified security information is invalid.
Remarks

The initial security descriptor of a service object is created by the service control manager, based on the security descriptor of the process that called the CreateService function to create the service. The security descriptor can be changed by calling the SetServiceObjectSecurity function.

See Also

CreateService, OpenService, SECURITY_DESCRIPTOR, SetServiceObjectSecurity


QueryServiceStatus
QueryServiceStatus  QuickInfo  Overview  Group

The QueryServiceStatus function retrieves the current status of the specified service.

BOOL QueryServiceStatus(

SC_HANDLE  schService,	// handle of service
LPSERVICE_STATUS  lpssServiceStatus	// address of service status structure
);
Parameters

schService

Identifies the service. This handle is returned by the OpenService or the CreateService function, and it must have SERVICE_QUERY_STATUS access.

lpssServiceStatus

Points to a SERVICE_STATUS structure in which the status information is returned.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Errors

The following error codes may be set by the service control manager. Other error codes may be set by the registry functions that are called by the service control manager.

Value	Meaning
ERROR_ACCESS_DENIED	The specified handle was not opened with SERVICE_QUERY_STATUS access.
ERROR_INVALID_HANDLE	The specified handle is invalid.
Remarks

The QueryServiceStatus function returns the most recent service status information reported to the service control manager. The service may have just changed its status and may not have updated the service control manager yet. Applications can find out the absolutely latest service status by interrogating the service directly by using the ControlService function with the SERVICE_CONTROL_INTERROGATE control code.

See Also

ControlService, CreateService, OpenService, SERVICE_STATUS, SetServiceStatus


RaiseException
RaiseException  QuickInfo  Overview  Group

The RaiseException function raises an exception in the calling thread.

VOID RaiseException(

DWORD  dwExceptionCode,	// exception code
DWORD  dwExceptionFlags,	// continuable exception flag
DWORD  cArguments,	// number of arguments in array
CONST DWORD *  lpArguments	// address of array of arguments
);
Parameters

dwExceptionCode

Specifies the application-defined exception code of the exception being raised. The filter expression and exception-handler block of an exception handler can use the GetExceptionCode function to retrieve this value.

Note that the system will clear bit 28 of dwExceptionCode. This bit is a reserved exception bit, used by the system for its own purposes. For example, after calling the RaiseException function with a dwExceptionCode value of 0xEFFFFFFF Windows displays a message indicating that the exception number is 0xEFFFFFFF.

dwExceptionFlags

Specifies the exception flags. This can be either zero to indicate a continuable exception, or EXCEPTION_NONCONTINUABLE to indicate a noncontinuable exception. Any attempt to continue execution after a noncontinuable exception causes the EXCEPTION_NONCONTINUABLE_EXCEPTION exception.

cArguments

Specifies the number of arguments in the lpArguments array. This value must not exceed EXCEPTION_MAXIMUM_PARAMETERS. This parameter is ignored if lpArguments is NULL.

lpArguments

Points to an array of 32-bit arguments. This parameter can be NULL. These arguments can contain any application-defined data that needs to be passed to the filter expression of the exception handler.

Return Value

This function does not return a value.

Remarks

The RaiseException function enables a process to use structured exception handling to handle private, software-generated, application-defined exceptions.

Raising an exception causes the exception dispatcher to go through the following search for an exception handler:

1.	The system first attempts to notify the process's debugger, if any.

2.	If the process is not being debugged, or if the associated debugger does not handle the exception, the system attempts to locate a frame-based exception handler by searching the stack frames of the thread in which the exception occurred. The system searches the current stack frame first, then proceeds backward through preceding stack frames.

3.	If no frame-based handler can be found, or no frame-based handler handles the exception, the system makes a second attempt to notify the process's debugger.

4.	If the process is not being debugged, or if the associated debugger does not handle the exception, the system provides default handling based on the exception type. For most exceptions, the default action is to call the ExitProcess function.

The values specified in the dwExceptionCode, dwExceptionFlags, cArguments, and lpArguments parameters can be retrieved in the filter expression of a try-except frame-based exception handler by calling the GetExceptionInformation function. A debugger can retrieve these values by calling the WaitForDebugEvent function.

See Also

ExitProcess, GetExceptionCode, GetExceptionInformation, WaitForDebugEvent


RasCreatePhonebookEntry
RasCreatePhonebookEntry  Overview  Group

The RasCreatePhonebookEntry function creates a new phonebook entry. The function displays a dialog box in which the user types information about the phonebook entry.

DWORD RasCreatePhonebookEntry(

HWND  hwnd,	// handle to the parent window of the dialog box
LPTSTR  lpszPhonebook	// pointer to the full path and filename of the phonebook file
);
Parameters

hwnd

Handle to the parent window of the dialog box.

lpszPhonebook

Points to a null-terminated string that specifies the full path and filename of the phonebook file. Currently, this parameter is ignored.

Windows 95: Dial-up networking stores phonebook entries in the registry rather than in a phonebook file.

Return Value

If the function succeeds, the return value is zero.

If the function fails, the return value is the following error code:

Value	Description
ERROR_CANNOT_OPEN_PHONEBOOK
	The phonebook is corrupted or missing components.
See Also

RasEditPhonebookEntry, RasGetEntryDialParams, RasSetEntryDialParams


RasDial
RasDial  QuickInfo  Overview  Group

The RasDial function establishes a Remote Access Service (RAS) connection between a RAS client and a RAS server. The connection data includes callback and user authentication information.

DWORD RasDial(

LPRASDIALEXTENSIONS  lpRasDialExtensions,	// pointer to function extensions data
LPTSTR  lpszPhonebook,	// pointer to full path and filename of phonebook file
LPRASDIALPARAMS  lpRasDialParams,	// pointer to calling parameters data
DWORD  dwNotifierType,	// specifies type of RasDial event handler
LPVOID  lpvNotifier,	// specifies a handler for RasDial events
LPHRASCONN  lphRasConn	// pointer to variable to receive connection handle
);
Parameters

lpRasDialExtensions

Windows NT

Points to a RASDIALEXTENSIONS structure that specifies a set of RasDial extended features to enable. If you do not need to enable any of the extensions, set this parameter to NULL.

Windows 95

This parameter is ignored. On Windows 95, RasDial always uses the default behaviors for the RASDIALEXTENSIONS options.

lpszPhonebook

Windows NT

Points to a string that specifies the full path and filename of the phonebook file. This parameter can be NULL, and typically is; in that case, RasDial uses the default phonebook file RASPHONE.PBK.

Windows 95

This parameter is ignored. Dial-up networking stores phonebook entries in the registry rather than in a phonebook file.

lpRasDialParams

Points to a RASDIALPARAMS structure that specifies calling parameters for the RAS connection.

The caller must set the RASDIALPARAMS structure's dwSize member to the sizeof(RASDIALPARAMS) to identify the version of the structure being passed.

dwNotifierType

Specifies the nature of the lpvNotifier parameter. If lpvNotifier is NULL, dwNotifierType is ignored. If lpvNotifier is not NULL, set dwNotifierType to one of the following values:

Value	Meaning
0xFFFFFFFF	The lpvNotifier parameter is a handle to a window to receive progress notification messages. In a progress notification message, wParam is the equivalent of the rasconnstate parameter of RasDialFunc and RasDialFunc1, and lParam is the equivalent of the dwError parameter of RasDialFunc and RasDialFunc1.  The progress notification message uses a system registered message code. You can obtain the value of this message code as follows:  {UINT unMsg =    RegisterWindowMessageA( RASDIALEVENT );  if (unMsg == 0)        unMsg = WM_RASDIALEVENT;     }
0	The lpvNotifier parameter points to a RasDialFunc callback function.
1	The lpvNotifier parameter points to a RasDialFunc1 callback function.
lpvNotifier

Specifies a window handle or a RasDialFunc or RasDialFunc1 callback function to receive RasDial event notifications. The dwNotifierType parameter specifies the nature of lpvNotifier. Please refer to its description preceding for further detail.

If this parameter is not NULL, RasDial sends the window a message, or calls the callback function, for each RasDial event. Additionally, the RasDial call operates asynchronously: RasDial returns immediately, before the connection is established, and communicates its progress via the window or callback function.

If lpvNotifier is NULL, the RasDial call operates synchronously: RasDial does not return until the connection attempt has completed successfully or failed.

If lpvNotifier is not NULL, notifications to the window or callback function can occur at any time after the initial call to RasDial. Notifications end when one of the following events occurs:

•	The connection is established. In other words, the RAS connection state is RASCS_Connected.

•	The connection fails. In other words, dwError is nonzero.

•	RasHangUp is called on the connection.

The callback notifications are made in the context of a thread captured during the initial call to RasDial.

lphRasConn

Points to a variable of type HRASCONN. You must set the HRASCONN variable to NULL before calling RasDial. If RasDial succeeds, it stores a handle to the RAS connection into *lphRasConn.

Return Value

If the function succeeds, the immediate return value is zero. In addition, the function stores a handle to the RAS connection into the variable pointed to by lphRasConn.

If the function fails, the immediate return value is a nonzero error value, either from the set listed in the RAS header file or ERROR_NOT_ENOUGH_MEMORY.

Remarks

Errors that occur after the immediate return can be detected by RasGetConnectStatus. Data is available until an application calls RasHangUp to hang up the connection.

An application must eventually call RasHangUp whenever a non-NULL connection handle is stored into *lphRasConn. This applies even if RasDial returns a nonzero (error) value.

An application can safely call RasHangUp from a RasDial notifier callback function. If this is done, however, the hangup does not occur until the routine returns.

Windows NT

If the structure pointed to by lpRasDialExtensions enables RDEOPT_PausedStates, the RasDial function pauses whenever it enters a state in which the RASCS_PAUSED bit is set to one. To restart RasDial from such a paused state, call RasDial again, passing the connection handle returned from the original RasDial call in *lphRasConn. The same notifier used in the original RasDial call must be used when restarting from a paused state.

To specify that RasDial should enter a RASCS_CallbackSetByCaller state, set lpRasDialParams->szCallbackNumber to "*" on the initial call to RasDial. When your notification handler is called with this state, you can set the the callback number to a number supplied by the user.

Windows 95

Windows 95 does not support the RASCS_CallbackSetByCaller state or any of the other paused states.

See Also

RasDialFunc, RasDialFunc1, RasGetConnectStatus, RasHangUp, RASDIALEXTENSIONS, RASDIALPARAMS, WM_RASDIALEVENT


RasDialFunc
RasDialFunc  QuickInfo  Overview  Group

The RasDialFunc function is an application-defined or library-defined callback function that the RasDial function calls when a change of state occurs during a Remote Access Service (RAS) connection process.

VOID RasDialFunc(

UINT  unMsg,	// type of event that has occurred
RASCONNSTATE  rasconnstate,	// connection state about to be entered
DWORD  dwError	// error that may have occurred
);
Parameters

unMsg

Specifies the type of event that has occurred. Currently, the only event defined is WM_RASDIALEVENT.

rasconnstate

Specifies a RASCONNSTATE enumerator value that indicates the state the RasDial remote access connection process is about to enter.

dwError

Indicates the error that has occurred, or zero if no error has occurred.

RasDial calls RasDialFunc with dwError set to zero upon entry to each connection state. If an error occurs within a state, RasDialFunc is called again with a nonzero dwError value.

Remarks

A RasDial connection operation is suspended during a call to a RasDialFunc callback function. For that reason, your RasDialFunc implementation should generally return as quickly as possible. There are two exceptions to that rule. Asynchronous (slow) devices such as modems often have time-out periods measured in seconds rather than milliseconds; a less-than-prompt return from a RasDialFunc function is generally not a problem. The prompt return requirement also does not apply when dwError is nonzero, indicating that an error has occurred. It is safe, for example, to put up an error dialog box and wait for user input.

Your RasDialFunc implementation should not depend on the order or occurrence of particular RASCONNSTATE connection states, because this may vary between platforms.

Do not call the RasDial function from within a RasDialFunc callback function. You can call the RasGetConnectStatus, RasEnumEntries, RasEnumConnections, RasGetErrorString, and RasHangUp functions from within the callback function. For example, calling RasGetConnectStatus from within a callback function would be useful for determining the name and type of the connecting device.

Note that, for convenience, RasHangUp can be called from within a RasDialFunc callback function. However, much of the hang-up processing occurs after the RasDialFunc callback function has returned.

RasDialFunc is a placeholder for the application-defined or library-defined function name.

See Also

RASCONNSTATE, RasDial, RasDialFunc1, RasEnumConnections, RasEnumEntries, RasGetConnectStatus, RasGetErrorString, RasHangUp


RasDialFunc1
RasDialFunc1  QuickInfo  Overview  Group

A RasDialFunc1 function is an application-defined or library-defined callback function that the RasDial function calls when a change of state occurs during a remote access connection process. A RasDialFunc1 function is comparable to a RasDialFunc function, but is enhanced by the addition of two parameters: a handle to the Remote Access Server (RAS) connection, and an extended error code.

VOID RasDialFunc1(

HRASCONN  hrasconn,	// handle to RAS connection
UINT  unMsg,	// type of event that has occurred
RASCONNSTATE  rascs,	// connection state about to be entered
DWORD  dwError	// error that may have occurred
DWORD  dwExtendedError	// extended error information for some errors
);
Parameters

hrasconn

Provides a handle to the RAS connection, as returned by RasDial.

unMsg

Specifies the type of event that has occurred. Currently, the only event defined is WM_RASDIALEVENT.

rascs

Specifies a RASCONNSTATE enumerator value that indicates the state the RasDial remote access connection process is about to enter.

dwError

Specifies the error that has occurred. If no error has occurred, dwError is zero.

RasDial calls RasDialFunc1 with dwError set to zero upon entry to each connection state. If an error occurs within a state, RasDial calls RasDialFunc1 again with a nonzero dwError value.

In some error cases, the dwExtendedError parameter contains extended error information.

dwExtendedError

Specifies extended error information for certain nonzero values of dwError. For all other values of dwError, dwExtendedError is zero.

The contents of dwExtendedError are defined for values of dwError as follows:

dwError	dwExtendedError
ERROR_SERVER_NOT_RESPONDING	Specifies the NetBIOS error that occurred.
ERROR_NETBIOS_ERROR	Specifies the NetBIOS error that occurred.
ERROR_AUTH_INTERNAL	Specifies an internal diagnostics code.
ERROR_CANNOT_GET_LANA	Specifies a routing error code, which is a RAS error.
Remarks

A RasDial connection operation is suspended during a call to a RasDialFunc1 callback function. For that reason, your RasDialFunc1 implementation should generally return as quickly as possible. There are two exceptions to that rule. Asynchronous (slow) devices such as modems often have time-out periods measured in seconds rather than milliseconds; a less-than-prompt return from a RasDialFunc1 function is generally not a problem. The prompt return requirement also does not apply when dwError is nonzero, indicating that an error has occurred. It is safe, for example, to put up an error dialog box and wait for user input.

Your RasDialFunc1 implementation should not depend on the order or occurrence of particular RASCONNSTATE connection states, because this may vary between platforms.

Do not call the RasDial function from within a RasDialFunc1 callback function. You can call the RasGetConnectStatus, RasEnumEntries, RasEnumConnections, RasGetErrorString, and RasHangUp functions from within the callback function. For example, calling RasGetConnectStatus from within a callback function would be useful for determining the name and type of the connecting device.

Note that, for convenience, RasHangUp can be called from within a RasDialFunc1 callback function. However, much of the hang-up processing occurs after the RasDialFunc1 callback function has returned.

RasDialFunc1 is a placeholder for the application-defined or library-defined function name.

See Also

RasDial, RasDialFunc, RASCONNSTATE, RasEnumConnections, RasEnumEntries, RasGetConnectStatus, RasGetErrorString, RasHangUp


RasEditPhonebookEntry
RasEditPhonebookEntry  Overview  Group

The RasEditPhonebookEntry function edits an existing phonebook entry. The function displays a dialog box in which the user can modify the existing information.

DWORD RasEditPhonebookEntry(

HWND  hwnd,	// handle to the parent window of the dialog box
LPTSTR  lpszPhonebook,	// pointer to the full path and filename of the phonebook file
LPTSTR  lpszEntryName	// pointer to the phonebook entry name
);
Parameters

hwnd

Handle to the parent window of the dialog box.

lpszPhonebook

Points to a null-terminated string that specifies the full path and filename of the phonebook file. Currently, this parameter is ignored.

Windows 95: Dial-up networking stores phonebook entries in the registry rather than in a phonebook file.

lpszEntryName

Points to a null-terminated string that specifies the name of an existing entry in the phonebook file.

Return Value

If the function succeeds, the return value is zero.

If the function fails, the return value can be one of the following error codes:

Value	Description
ERROR_BUFFER_INVALID
	The phonebook entry buffer is invalid.
ERROR_CANNOT_OPEN_PHONEBOOK
	The phonebook is corrupted or missing components.
ERROR_CANNOT_FIND_PHONEBOOK_ENTRY
	The phonebook entry does not exist.
See Also

RasCreatePhonebookEntry, RasGetEntryDialParams, RasSetEntryDialParams


RasEnumConnections
RasEnumConnections  QuickInfo  Overview  Group

The RasEnumConnections function lists all active Remote Access Service (RAS) connections. It returns each connection's handle and phonebook entry name.

DWORD RasEnumConnections(

LPRASCONN  lprasconn,	// buffer to receive connections data
LPDWORD  lpcb,	// size in bytes of buffer
LPDWORD  lpcConnections	// number of connections written to buffer
);
Parameters

lprasconn

Points to a buffer that receives an array of RASCONN structures, one for each RAS connection. Before calling the function, an application must set the dwSize member of the first RASCONN structure in the buffer to sizeof(RASCONN) in order to identify the version of the structure being passed.

lpcb

Points to a variable that contains the size, in bytes, of the buffer specified by lprasconn. On return, the function sets this variable to the number of bytes required to enumerate the RAS connections.

lpcConnections

Points to a variable that the function sets to the number of RASCONN structures written to the buffer specified by lprasconn.

Return Value

If the function succeeds, the return value is zero.

If the function fails, the return value is a nonzero error value listed in the RAS header file or one of ERROR_BUFFER_TOO_SMALL or ERROR_NOT_ENOUGH_MEMORY.

Remarks

If a connection was made without specifying a phonebook entry name, the information returned for that connection will give the connection phone number preceded by ".".

See Also

RASCONN, RasEnumEntries, RasGetConnectStatus


RasEnumEntries
RasEnumEntries  QuickInfo  Overview  Group

The RasEnumEntries function lists all entry names in a remote access phonebook.

DWORD RasEnumEntries (

LPTSTR  reserved,	// reserved, must be NULL
LPTSTR  lpszPhonebook,	// pointer to full path and filename of phonebook file
LPRASENTRYNAME  lprasentryname,	// buffer to receive phonebook entries
LPDWORD  lpcb,	// size in bytes of buffer
LPDWORD  lpcEntries	// number of entries written to buffer
);
Parameters

reserved

Reserved; must be NULL.

lpszPhonebook

Windows NT

Points to a string that specifies the full path and filename of the phonebook file. This parameter can be NULL, and typically is; in that case, RasEnumEntries uses the default phonebook file RASPHONE.PBK.

Windows 95

This parameter is ignored. Dial-up networking stores phonebook entries in the registry rather than in a phonebook file.

lprasentryname

Points to a buffer that receives an array of RASENTRYNAME structures, one for each phonebook entry. Before calling the function, an application must set the dwSize member of the first RASENTRYNAME structure in the buffer to sizeof(RASENTRYNAME) in order to identify the version of the structure being passed.

lpcb

Points to a variable that contains the size, in bytes, of the buffer specified by lprasentryname. On return, the function sets this variable to the number of bytes required to successfully complete the call.

lpcEntries

Points to a variable that the function, if successful, sets to the number of phonebook entries written to the buffer specified by lprasentryname.

Return Value

If the function succeeds, the return value is zero.

If the function fails, the return value is a nonzero error value listed in the RAS header file or one of ERROR_BUFFER_TOO_SMALL or ERROR_NOT_ENOUGH_MEMORY.

See Also

RASENTRYNAME, RasEnumConnections


RasGetConnectStatus
RasGetConnectStatus  QuickInfo  Overview  Group

The RasGetConnectStatus function retrieves information on the current status of the specified remote access connection. An application can use this call to determine when an asynchronous RasDial call has completed.

DWORD RasGetConnectStatus(

HRASCONN  hrasconn,	// handle to RAS connection of interest
LPRASCONNSTATUS  lprasconnstatus	// buffer to receive status data
);
Parameters

hrasconn

Identifies the remote access connection for which to retrieve the status. This handle must have been obtained from RasDial or RasEnumConnections.

lprasconnstatus

Points to a RASCONNSTATUS structure that the function fills with status information. Before calling the function, an application must set the dwSize member of the structure to sizeof(RASCONNSTATUS) in order to identify the version of the structure being passed.

Return Value

If the function succeeds, the return value is zero.

If the function fails, the return value is a nonzero error value listed in the RAS header file or one of ERROR_BUFFER_TOO_SMALL or ERROR_NOT_ENOUGH_MEMORY.

See Also

RASCONNSTATUS, RasDial, RasEnumConnections


RasGetEntryDialParams
RasGetEntryDialParams  Overview  Group

The RasGetEntryDialParams function retrieves the connection information saved by the last successful call to the RasDial or RasSetEntryDialParams function for a specified phonebook entry.

DWORD RasGetEntryDialParams(

LPTSTR  lpszPhonebook,	// pointer to the full path and filename of the phonebook file
LPRASDIALPARAMS  lprasdialparams,	// pointer to a structure that receives the connection parameters
LPBOOL  lpfPassword	// indicates whether the user's password was retrieved
);
Parameters

lpszPhonebook

Points to a null-terminated string that specifies the full path and filename of the phonebook file. Currently, this parameter is ignored.

Windows 95: Dial-up networking stores phonebook entries in the registry rather than in a phonebook file.

lprasdialparams

Points to a RASDIALPARAMS structure that receives the connection parameters associated with the phonebook entry specified by the szEntryName member. On entry, the dwSize member must specify the size of the RASDIALPARAMS structure, and the szEntryName member must specify a valid phonebook entry.

lpfPassword

Points to a flag that indicates whether the function retrieved the password associated with the user name for the phonebook entry. The function sets this flag to TRUE if the user's password was returned in the szPassword member of the RASDIALPARAMS structure pointed to by lprasdialparams.

Return Value

If the function succeeds, the return value is zero.

If the function fails, the return value can be one of the following error codes:

Value	Description
ERROR_BUFFER_INVALID
	The lprasdialparams or lpfPassword pointer is invalid, or the lprasdialparams buffer is invalid.
ERROR_CANNOT_OPEN_PHONEBOOK
	The phonebook is corrupted or missing components.
ERROR_CANNOT_FIND_PHONEBOOK_ENTRY
	The phonebook entry does not exist.
See Also

RasDial, RASDIALPARAMS, RasCreatePhonebookEntry, RasEditPhonebookEntry, RasSetEntryDialParams


RasGetErrorString
RasGetErrorString  QuickInfo  Overview  Group

The RasGetErrorString function obtains an error message string for a specified Remote Access Service (RAS) error value.

DWORD RasGetErrorString (

UINT  uErrorValue,	// error to get string for
LPTSTR  lpszErrorString,	// buffer to hold error string
DWORD  cBufSize	// size, in characters, of buffer
);
Parameters

uErrorValue

Specifies the error value of interest. These are values returned by one of the RAS functions: those listed in the RAS header file.

lpszErrorString

Points to a buffer that the function will write the error string to. This parameter must not be NULL.

cBufSize

Specifies the size, in characters, of the buffer pointed to by lpszErrorString.

Return Value

If the function succeeds, the return value is zero.

If the function fails, the return value is a nonzero error value. This value is ERROR_INVALID_PARAMETER or the GetLastError value returned from the functions GlobalAlloc or LoadString. The function does not set a thread's last error information; that is, there is no GetLastError information set by the RasGetErrorString function.

Remarks

There is no way to determine in advance the exact size in characters of an error message, and thus the size of buffer required. Error messages will generally be 80 characters or fewer in size; a buffer size of 256 characters will always be adequate. A buffer of insufficient size causes the RasGetErrorString function to fail, returning ERROR_INSUFFICIENT_BUFFER. Note that buffer sizes are specified in characters, not bytes; thus, the Unicode version of RasGetErrorString requires a 512 byte buffer to guarantee that every error message will fit.

See Also

GlobalAlloc, LoadString


RasGetProjectionInfo
RasGetProjectionInfo  QuickInfo  Overview  Group

The RasGetProjectionInfo function obtains information about a remote access projection operation for a specified remote access component protocol.

DWORD RasGetProjectionInfo(

HRASCONN  hrasconn,	// handle that specifies remote access connection of interest
RASPROJECTION  rasprojection,	// specifies type of projection information to obtain
LPVOID  lpprojection,	// points to buffer that receives projection information
LPDWORD  lpcb	// points to variable that specifies buffer size
);
Parameters

hrasconn

Handle to the remote access connection of interest. An application obtains a Remote Access Service (RAS) connection handle from the RasDial or RasEnumConnections function.

rasprojection

A RASPROJECTION enumerated type value that specifies the protocol of interest.

lpprojection

Points to a buffer that will receive the information specified by the rasprojection parameter. The information will be in a structure appropriate to the rasprojection value:

rasprojection value	Data structure
RASP_Amb	RASAMB
RASP_PppNbf	RASPPPNBF
RASP_PppIpx	RASPPPIPX
RASP_PppIp	RASPPPIP
lpcb

Points to a variable that, on entry, specifies the size in bytes of the buffer pointed to by lpprojection. On exit, this variable contains the size of buffer needed to contain the specified projection information.

Return Value

If the function succeeds, the return value is zero.

If the function fails, the return value is an error code. The function may return a nonzero RAS error code, or one of the following error codes:

Value	Meaning
ERROR_BUFFER_TOO_SMALL	The buffer pointed to by lpprojection is not large enough to contain the requested information.
ERROR_INVALID_HANDLE	The hrasconn parameter is not a valid handle.
ERROR_INVALID_PARAMETER	One of the parameters is invalid.
ERROR_INVALID_SIZE	The dwSize member of the structure pointed to by lpprojection specifies an invalid size.
ERROR_PROTOCOL_NOT_CONFIGURED	The control protocol for which information was requested neither succeeded nor failed, because the connection's phonebook entry did not require that an attempt to negotiate the protocol be made. This is a RAS error code.
Remarks

Remote access projection is the process whereby a remote access server and a remote client negotiate network protocol-specific information. A remote access server uses this network protocol-specific information to represent a remote client on the network.

Windows NT: Remote access projection information is not available until the operating system has executed the RasDial RASCS_Projected state on the remote access connection. If RasGetProjectionInfo is called prior to the RASCS_Projected state, it returns ERROR_PROJECTION_NOT_COMPLETE.

Windows 95: Windows 95 Dial-Up Networking does not support the RASCS_Projected state. The projection phase may be done during the RASCS_Authenticate state. If the authentication is successful, the connection operation proceeds to the RASCS_Authenticated state, and projection information is available for successfully configured protocols. If RasGetProjectionInfo is called prior to the RASCS_Authenticated state, it returns ERROR_PROTOCOL_NOT_CONFIGURED.

See Also

RASAMB, RasDial, RasEnumConnections, RASPPPNBF, RASPPPIPX, RASPPPIP, RASPROJECTION


RasHangUp
RasHangUp  QuickInfo  Overview  Group

The RasHangUp function terminates a remote access connection. The connection is specified with a Remote Access Service (RAS) connection handle. The function releases all RASAPI32.DLL resources associated with the handle.

DWORD RasHangUp(

HRASCONN  hrasconn	// handle to the RAS connection to hang up
);
Parameters

hrasconn

Identifies the remote access connection to terminate. This is a handle returned from a previous call to RasDial or RasEnumConnections.

Return Value

If the function succeeds, the return value is zero.

If the function fails, the return value is a nonzero error value listed in the RAS header file, or ERROR_INVALID_HANDLE.

Remarks

The connection is terminated even if the RasDial call has not yet been completed.

After this call, the hrasconn handle can no longer be used.

An application should not call RasHangUp and then immediately exit. The connection state machine needs time to properly terminate. If the system prematurely terminates the state machine, the state machine may fail to properly close a port, leaving the port in an inconsistent state. A simple way to avoid this problem is to call Sleep(3000) after returning from RasHangUp; after that pause, the application can exit. A more responsive way to avoid the problem is, after returning from RasHangUp, to call RasGetConnectStatus(hrasconn) and Sleep(0) in a loop until RasGetConnectStatus returns ERROR_INVALID_HANDLE.

See Also

RASCONN, RasDial, RasEnumConnections, RasGetConnectStatus, Sleep


RasSetEntryDialParams
RasSetEntryDialParams  Overview  Group

The RasSetEntryDialParams function changes the connection information saved by the last successful call to the RasDial or RasSetEntryDialParams function for a specified phonebook entry.

DWORD RasSetEntryDialParams(

LPTSTR  lpszPhonebook,	// pointer to the full path and filename of the phonebook file
LPRASDIALPARAMS  lprasdialparams,	// pointer to a structure with the new connection parameters
BOOL    fRemovePassword	// indicates whether to remove password from entry's parameters
);
Parameters

lpszPhonebook

Points to a null-terminated string that specifies the full path and filename of the phonebook file. Currently, this parameter is ignored.

Windows 95: Dial-up networking stores phonebook entries in the registry rather than in a phonebook file.

lprasdialparams

Points to a RASDIALPARAMS structure containing the connection parameters to be associated with the phonebook entry. RasSetEntryDialParams uses the structure's members as follows:

Member	Description
dwSize	Must specify the sizeof(RASDIALPARAMS) to identify the version of the structure.
szEntryName	A null-terminated string that identifies the phonebook entry to set parameters for.
szPhoneNumber	Not used. Set to NULL.
szCallbackNumber	A null-terminated string containing the callback phone number. If szCallbackNumber is an empty string ( "" ), the callback number is not changed.
szUserName	A null-terminated string containing the logon name of the user associated with this entry. If szUserName is an empty string, the user name is not changed.
szPassword	A null-terminated string containing the password for the user specified by szUserName. If szUserName is an empty string, the password is not changed. If szPassword is an empty string and fRemovePassword is FALSE, the password is set to the empty string. If fRemovePassword is TRUE, the password stored in this phonebook entry for the user specified by szUserName is removed regardless of the contents of the szPassword string.
szDomain	A null-terminated string containing the name of the domain to log on to. If szDomain is an empty string, the domain name is not changed.
fRemovePassword

Indicates whether to remove the phonebook entry's stored password for the user specified by lprasdialparams->szUserName. If fRemovePassword is TRUE, the password is removed.

Return Value

If the function succeeds, the return value is zero.

If the function fails, the return value can be one of the following error codes:

Value	Description
ERROR_BUFFER_INVALID
	The address or buffer specified by lprasdialparams is invalid.
ERROR_CANNOT_OPEN_PHONEBOOK
	The phonebook is corrupted or missing components.
ERROR_CANNOT_FIND_PHONEBOOK_ENTRY
	The phonebook entry does not exist.
See Also

RASDIALPARAMS, RasCreatePhonebookEntry, RasEditPhonebookEntry, RasGetEntryDialParams


ReadConsole
ReadConsole  QuickInfo  Overview  Group

The ReadConsole function reads character input from the console input buffer and removes it from the buffer.

BOOL ReadConsole(

HANDLE  hConsoleInput,	// handle of a console input buffer
LPVOID  lpvBuffer,	// address of buffer to receive data
DWORD  cchToRead,	// number of characters to read
LPDWORD  lpcchRead,	// address of number of characters read
LPVOID  lpvReserved	// reserved
);
Parameters

hConsoleInput

Identifies the console input buffer. The handle must have GENERIC_READ access.

lpvBuffer

Points to a buffer that receives the data read from the console input buffer.

cchToRead

Specifies the number of characters to read. Because the function can read either 2-byte Unicode or 1-byte ANSI characters, the size of the buffer pointed to by the lpvBuffer parameter should be at least cchToRead * sizeof(TCHAR).

lpcchRead

Points to a 32-bit variable that receives the number of characters actually read.

lpvReserved

Reserved; must be NULL.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

ReadConsole reads keyboard input from a console's input buffer. It behaves like the ReadFile function, except that it can read in either Unicode (wide-character) or ANSI mode. To have applications that maintain a single set of sources compatible with both modes, use ReadConsole rather than ReadFile. Although ReadConsole can only be used with a console input buffer handle, ReadFile can be used with other handles (such as files or pipes). ReadConsole fails if used with a standard handle that has been redirected to be something other than a console handle.

All of the input modes that affect the behavior of ReadFile have the same effect on ReadConsole. To retrieve and set the input modes of a console input buffer, use the GetConsoleMode and SetConsoleMode functions.

If the input buffer contains input events other than keyboard events (such as mouse events or window-resizing events), they are discarded. Those events can only be read by using the ReadConsoleInput function.

See Also

GetConsoleMode, ReadConsoleInput, ReadFile, SetConsoleMode, WriteConsole


ReadConsoleInput
ReadConsoleInput  QuickInfo  Overview  Group

The ReadConsoleInput function reads data from a console input buffer and removes it from the buffer.

BOOL ReadConsoleInput(

HANDLE  hConsoleInput,	// handle of a console input buffer
PINPUT_RECORD  pirBuffer,	// address of the buffer for read data
DWORD  cInRecords,	// number of records to read
LPDWORD  lpcRead	// address of number of records read
);
Parameters

hConsoleInput

Identifies the input buffer. The handle must have GENERIC_READ access.

pirBuffer

Points to an INPUT_RECORD buffer that receives the input buffer data.

cInRecords

Specifies the size, in input records, of the buffer pointed to by the pirBuffer parameter.

lpcRead

Points to a 32-bit variable that receives the number of input records read.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

If the number of records requested in the cInRecords parameter exceeds the number of records available in the buffer, the number available is read. The function does not return until at least one input record has been read.

A process can specify a console input buffer handle in one of the wait functions (for example, the WaitForSingleObject or WaitForMultipleObjects function) to determine when there is unread console input. When the input buffer is not empty, the state of a console input buffer handle is signaled.

To determine the number of unread input records in a console's input buffer, use the GetNumberOfConsoleInputEvents function. To read input records from a console input buffer without affecting the number of unread records, use the PeekConsoleInput function. To discard all unread records in a console's input buffer, use the FlushConsoleInputBuffer function.

See Also

FlushConsoleInputBuffer, GetNumberOfConsoleInputEvents, INPUT_RECORD, PeekConsoleInput, ReadConsole, ReadFile, WaitForSingleObject, WaitForMultipleObjects, WriteConsoleInput


ReadConsoleOutput
ReadConsoleOutput  QuickInfo  Overview  Group

The ReadConsoleOutput function reads character and color attribute data from a rectangular block of character cells in a console screen buffer, and the function writes the data to a rectangular block at a specified location in the destination buffer.

BOOL ReadConsoleOutput(

HANDLE  hConsoleOutput,	// handle of a console screen buffer
PCHAR_INFO  pchiDestBuffer,	// address of buffer that receives data
COORD  coordDestBufferSize,	// column-row size of destination buffer
COORD  coordDestBufferCoord,	// upper-left cell to write to
PSMALL_RECT  psrctSourceRect	// address of rectangle to read from
);
Parameters

hConsoleOutput

Identifies the screen buffer. The handle must have GENERIC_READ access.

pchiDestBuffer

Points to a destination buffer that receives the data read from the screen buffer. This pointer is treated as the origin of a two-dimensional array of CHAR_INFO structures whose size is specified by the coordDestBufferSize parameter.

coordDestBufferSize

Specifies the size, in character cells, of the pchiDestBuffer parameter. The X member of the COORD structure is the number of columns; the Y member is the number of rows.

coordDestBufferCoord

Specifies the coordinates of the upper-left cell in the pchiDestBuffer parameter that receives the data read from the screen buffer. The X member of the COORD structure is the column, and the Y member is the row.

psrctSourceRect

Points to a SMALL_RECT structure. On input, the structure members specify the upper-left and lower-right coordinates of the screen buffer rectangle from which the function is to read. On output, the structure members specify the actual rectangle that the function copied from.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

ReadConsoleOutput treats the screen buffer and the destination buffer as two-dimensional arrays (columns and rows of character cells). The rectangle pointed to by the psrctSourceRect parameter specifies the size and location of the block to be read from the screen buffer. A destination rectangle of the same size is located with its upper-left cell at the coordinates of the coordDestBufferCoord parameter in the pchiDestBuffer array. Data read from the cells in the screen buffer source rectangle is copied to the corresponding cells in the destination buffer. If the corresponding cell is outside the boundaries of the destination buffer rectangle (whose dimensions are specified by the coordDestBufferSize parameter), the data is not copied.

Cells in the destination buffer corresponding to coordinates that are not within the boundaries of the screen buffer are left unchanged. In other words, these are the cells for which no screen buffer data is available to be read.

Before ReadConsoleOutput returns, it sets the members of the structure pointed to by the psrctSourceRect parameter to the actual screen buffer rectangle whose cells were copied into the destination buffer. This rectangle reflects the cells in the source rectangle for which there existed a corresponding cell in the destination buffer, because ReadConsoleOutput clips the dimensions of the source rectangle to fit the boundaries of the screen buffer.

If the rectangle specified by psrctSourceRect lies completely outside the boundaries of the screen buffer, or if the corresponding rectangle is positioned completely outside the boundaries of the destination buffer, no data is copied. In this case, the function returns with the members of the structure pointed to by the psrctSourceRect parameter set such that the Right member is less than the Left, or the Bottom member is less than the Top. To determine the size of the screen buffer, use the GetConsoleScreenBufferInfo function.

The ReadConsoleOutput function has no effect on the screen buffer's cursor position. The contents of the screen buffer are not changed by the function.

See Also

CHAR_INFO, COORD, ReadConsoleOutputAttribute, ReadConsoleOutputCharacter, SMALL_RECT, WriteConsoleOutput


ReadConsoleOutputAttribute
ReadConsoleOutputAttribute  QuickInfo  Overview  Group

The ReadConsoleOutputAttribute function copies a specified number of foreground and background color attributes from consecutive cells of a console screen buffer, beginning at a specified location.

BOOL ReadConsoleOutputAttribute(

HANDLE  hConsoleOutput,	// handle of a console screen buffer
LPWORD  lpwAttribute,	// address of buffer to receive attributes
DWORD  cReadCells,	// number of character cells to read from
COORD  coordReadCoord,	// coordinates of first cell to read from
LPDWORD  lpcNumberRead	// address of number of cells read from
);
Parameters

hConsoleOutput

Identifies a console screen buffer. The handle must have GENERIC_READ access.

lpwAttribute

Points to a buffer that receives the attributes read from the screen buffer.

cReadCells

Specifies the number of screen buffer character cells from which to read. The size of the buffer pointed to by the lpwAttribute parameter should be cReadCells * sizeof(WORD).

coordReadCoord

Specifies the coordinates of the first cell in the screen buffer from which to read. The X member of the COORD structure is the column, and the Y member is the row.

lpcNumberRead

Points to a 32-bit variable that receives the number of attributes actually read.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

If the number of attributes to be read from extends beyond the end of the specified screen buffer row, attributes are read from the next row. If the number of attributes to be read from extends beyond the end of the screen buffer, attributes up to the end of the screen buffer are read.

Each attribute specifies the foreground (text) and background colors in which that character cell is drawn. The attribute values are some combination of the following values: FOREGROUND_BLUE, FOREGROUND_GREEN, FOREGROUND_RED, FOREGROUND_INTENSITY, BACKGROUND_BLUE, BACKGROUND_GREEN, BACKGROUND_RED, and BACKGROUND_INTENSITY. For example, the following combination of values produces red text on a white background:

FOREGROUND_RED | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE

See Also

COORD, ReadConsoleOutput, ReadConsoleOutputCharacter, WriteConsoleOutput, WriteConsoleOutputAttribute, WriteConsoleOutputCharacter


ReadConsoleOutputCharacter
ReadConsoleOutputCharacter  QuickInfo  Overview  Group

The ReadConsoleOutputCharacter function copies a number of characters from consecutive cells of a console screen buffer, beginning at a specified location.

BOOL ReadConsoleOutputCharacter(

HANDLE  hConsoleOutput,	// handle of a console screen buffer
LPTSTR  lpReadBuffer,	// address of buffer to receive characters
DWORD  cchRead,	// number of character cells to read from
COORD  coordReadCoord,	// coordinates of first cell to read from
LPDWORD  lpcNumberRead	// address of number of cells read from
);
Parameters

hConsoleOutput

Identifies a console screen buffer. The handle must have GENERIC_READ access.

lpReadBuffer

Points to a buffer that receives the characters read from the screen buffer.

cchRead

Specifies the number of screen buffer character cells from which to read. The size of the buffer pointed to by the lpReadBuffer parameter should be cchRead * sizeof(TCHAR).

coordReadCoord

Specifies the coordinates of the first cell in the screen buffer from which to read. The X member of the COORD structure is the column, and the Y member is the row.

lpcNumberRead

Points to a 32-bit variable that receives the number of characters actually read.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

If the number of characters to be read from extends beyond the end of the specified screen buffer row, characters are read from the next row. If the number of characters to be read from extends beyond the end of the screen buffer, characters up to the end of the screen buffer are read.

See Also

COORD, ReadConsoleOutput, ReadConsoleOutputAttribute, WriteConsoleOutput, WriteConsoleOutputAttribute, WriteConsoleOutputCharacter


ReadEventLog
ReadEventLog  QuickInfo  Overview  Group

The ReadEventLog function reads a whole number of entries from the specified event log. The function can be used to read log entries in forward or reverse chronological order.

BOOL ReadEventLog(

HANDLE  hEventLog,	// handle of event log
DWORD  dwReadFlags,	// specifies how to read log
DWORD  dwRecordOffset,	// number of first record
LPVOID  lpBuffer,	// address of buffer for read data
DWORD  nNumberOfBytesToRead,	// number of bytes to read
DWORD  *pnBytesRead,	// number of bytes read
DWORD  *pnMinNumberOfBytesNeeded	// number of bytes required for next record
);
Parameters

hEventLog

Identifies the event log to read. This handle is returned by the OpenEventLog function.

dwReadFlags

Specifies how the read operation is to proceed. This parameter can be any combination of the following values:

Value	Meaning
EVENTLOG_FORWARDS_READ	The log is read in forward chronological order.
EVENTLOG_BACKWARDS_READ	The log is read in reverse chronological order.
EVENTLOG_SEEK_READ	The read operation proceeds from the record specified by the dwRecordOffset parameter. If this flag is used, dwReadFlags must also specify EVENTLOG_FORWARDS_READ or EVENTLOG_BACKWARDS_READ. If the buffer is large enough, more than one record can be read at the specified seek position; the additional flag indicates the direction for successive read operations.
EVENTLOG_SEQUENTIAL_READ	The read operation proceeds sequentially from the last call to the ReadEventLog function using this handle.
dwRecordOffset

Specifies the log-entry record number at which the read operation should start. This parameter is ignored unless the dwReadFlags parameter includes the EVENTLOG_SEEK_READ flag.

lpBuffer

Points to a buffer for the data read from the event log. This parameter cannot be NULL, even if the nNumberOfBytesToRead parameter is zero.

The buffer will be filled with an EVENTLOGRECORD structure.

nNumberOfBytesToRead

Specifies the size, in bytes, of the buffer. This function will read as many whole log entries as will fit in the buffer; the function will not return partial entries, even if there is room in the buffer.

pnBytesRead

Points to a variable that receives the number of bytes read by the function.

pnMinNumberOfBytesNeeded

Points to a variable that receives the number of bytes required for the next log entry. This count is valid only if ReadEventLog returns zero and GetLastError returns ERROR_INSUFFICIENT_BUFFER.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

When this function returns, the read position in the error log is adjusted by the number of records read. Only a whole number of event log records will be returned.

Note  The configured filename for this source may also be the configured filename for other sources (several sources can exist as subkeys under a single logfile). Therefore, this function may return events that were logged by more than one source.

See Also

ClearEventLog, CloseEventLog, EVENTLOGRECORD, OpenEventLog, ReportEvent


ReadFile
ReadFile  QuickInfo  Overview  Group

The ReadFile function reads data from a file, starting at the position indicated by the file pointer. After the read operation has been completed, the file pointer is adjusted by the number of bytes actually read, unless the file handle is created with the overlapped attribute. If the file handle is created for overlapped input and output (I/O), the application must adjust the position of the file pointer after the read operation.

BOOL ReadFile(

HANDLE  hFile,	// handle of file to read
LPVOID  lpBuffer,	// address of buffer that receives data
DWORD  nNumberOfBytesToRead,	// number of bytes to read
LPDWORD  lpNumberOfBytesRead,	// address of number of bytes read
LPOVERLAPPED  lpOverlapped	// address of structure for data
);
Parameters

hFile

Identifies the file to be read. The file handle must have been created with GENERIC_READ access to the file.

Windows NT

For asynchronous read operations, hFile can be any handle opened with the FILE_FLAG_OVERLAPPED flag by the CreateFile function, or a socket handle returned by the socket or accept functions.

Windows 95

For asynchronous read operations, hFile can be a communications resource, mailslot, or named pipe handle opened with the FILE_FLAG_OVERLAPPED flag by CreateFile, or a socket handle returned by the socket or accept functions. Windows 95 does not support asynchronous read operations on disk files.

lpBuffer

Points to the buffer that receives the data read from the file.

nNumberOfBytesToRead

Specifies the number of bytes to be read from the file.

lpNumberOfBytesRead

Points to the number of bytes read. ReadFile sets this value to zero before doing any work or error checking. If this parameter is zero when ReadFile returns TRUE on a named pipe, the other end of the message-mode pipe called the WriteFile function with nNumberOfBytesToWrite set to zero.

lpOverlapped

Points to an OVERLAPPED structure. This structure is required if hFile was created with FILE_FLAG_OVERLAPPED.

This parameter should not be NULL if hFile was created with FILE_FLAG_OVERLAPPED. It should point to a valid OVERLAPPED structure. If the file identified by the hFile parameter was created with FILE_FLAG_OVERLAPPED and lpOverlapped is NULL, the function fails in unpredictable ways.

If hFile was not created with FILE_FLAG_OVERLAPPED and lpOverlapped is NULL, the read operation starts at the current file position and ReadFile does not return until the operation has been completed. The function operates synchronously.

If hFile was created with FILE_FLAG_OVERLAPPED and lpOverlapped is not NULL, the read operation starts at the offset specified in the OVERLAPPED structure and ReadFile may return before the read operation has been completed. In this case, ReadFile returns FALSE and the GetLastError function returns ERROR_IO_PENDING. The calling process can continue while the read operation finishes. The event specified in the OVERLAPPED structure is set to the signaled state upon completion of the read operation.

If hFile is not created with FILE_FLAG_OVERLAPPED and lpOverlapped is not NULL, the read operation starts at the offset specified in the OVERLAPPED structure. ReadFile does not return until the read operation has been completed.

Return Value

If the function succeeds, the return value is TRUE. If the return value is TRUE and the number of bytes read is zero, the file pointer was beyond the current end of the file at the time of the read operation.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

If part of the file is locked by another process and the read operation overlaps the locked portion, this function fails.

Applications must not read from nor write to the input buffer that a read operation is using until the read operation completes. A premature access to the input buffer may lead to corruption of the data read into that buffer.

Characters can be read from the console input buffer by using ReadFile with a handle to console input. The console mode determines the exact behavior of the ReadFile function.

If a named pipe is being read in message mode and the next message is longer than the nNumberOfBytesToRead parameter specifies, ReadFile returns FALSE and GetLastError returns ERROR_MORE_DATA. The remainder of the message may be read by a subsequent call to the ReadFile or PeekNamedPipe function.

When reading from a communications device, the behavior of ReadFile is governed by the current communication timeouts as set and retrieved using the SetCommTimeouts and GetCommTimeouts functions. Unpredictable results can occur if you fail to set the timeout values. For more information about communication timeouts, see COMMTIMEOUTS.

If ReadFile attempts to read from a mailslot whose buffer is too small, the function returns FALSE and GetLastError returns ERROR_INSUFFICIENT_BUFFER.

If the anonymous write pipe handle has been closed and ReadFile attempts to read using the corresponding anonymous read pipe handle, the function returns FALSE and GetLastError returns ERROR_BROKEN_PIPE.

The ReadFile function may fail and return ERROR_INVALID_USER_BUFFER or ERROR_NOT_ENOUGH_MEMORY whenever there are too many outstanding asynchronous I/O requests.

If hFile is a handle to a named pipe, the Offset and OffsetHigh members of the OVERLAPPED structure pointed to by lpOverlapped must be zero, or the function will fail.

The ReadFile code to check for the end-of-file condition (eof) differs for synchronous and asynchronous read operations.

When a synchronous read operation reaches the end of a file, ReadFile returns TRUE and sets *lpNumberOfBytesRead to zero. The following sample code tests for end-of-file for a synchronous read operation:

// attempt a synchronous read operation

bResult = ReadFile(hFile, &inBuffer, nBytesToRead, &nBytesRead, NULL) ;

// check for eof

if (bResult &&  nBytesRead == 0, ) {

// we're at the end of the file

}

An asynchronous read operation can encounter the end of a file during the initiating call to ReadFile, or during subsequent asynchronous operation.

If EOF is detected at ReadFile time for an asynchronous read operation, ReadFile returns FALSE and GetLastError returns ERROR_HANDLE_EOF.

If EOF is detected during subsequent asynchronous operation, the call to GetOverlappedResult to obtain the results of that operation returns FALSE and GetLastError returns ERROR_HANDLE_EOF.

The following sample code illustrates testing for end-of-file for an asynchronous read operation:

// set up overlapped structure fields

// to simplify this sample, we'll eschew an event handle

gOverLapped.Offset     = 0;

gOverLapped.OffsetHigh = 0;

gOverLapped.hEvent     = NULL;

// attempt an asynchronous read operation

bResult = ReadFile(hFile, &inBuffer, nBytesToRead, &nBytesRead,

 &gOverlapped) ;

// if there was a problem, or the async. operation's still pending ...

if (!bResult) {

// deal with the error code

switch (dwError = GetLastError()) {

case ERROR_HANDLE_EOF: {

// we're reached the end of the file

// during the call to ReadFile

// code to handle that

}

case ERROR_IO_PENDING: {

// asynchronous i/o is still in progress

// do something else for a while

GoDoSomethingElse() ;

// check on the results of the asynchronous read

bResult = GetOverlappedResult(hFile, &gOverlapped,

&nBytesRead, FALSE) ;

// if there was a problem ...

if (!bResult) {

// deal with the error code

switch (dwError = GetLastError()) {

case ERROR_HANDLE_EOF: {

// we're reached the end of the file

//during asynchronous operation

}

// deal with other error cases

} // end switch

} // end if

} // end case

// deal with other error cases

} // end switch

} // end if

See Also

CreateFile, GetCommTimeouts, GetOverlappedResult, OVERLAPPED, PeekNamedPipe, ReadFileEx, SetCommTimeouts, WriteFile


ReadFileEx
ReadFileEx  QuickInfo  Overview  Group

The ReadFileEx function reads data from a file asynchronously. It is designed solely for asynchronous operation, unlike the ReadFile function, which is designed for both synchronous and asynchronous operation. ReadFileEx lets an application perform other processing during a file read operation.

The ReadFileEx function reports its completion status asynchronously, calling a specified completion routine when reading is completed and the calling thread is in an alertable wait state.

BOOL ReadFileEx(

HANDLE  hFile,	// handle of file to read
LPVOID  lpBuffer,	// address of buffer
DWORD  nNumberOfBytesToRead,	// number of bytes to read
LPOVERLAPPED  lpOverlapped,	// address of offset
LPOVERLAPPED_COMPLETION_ROUTINE  lpCompletionRoutine	// address of completion routine
);
Parameters

hFile

An open handle that specifies the file entity to be read from. This file handle must have been created with the FILE_FLAG_OVERLAPPED flag and must have GENERIC_READ access to the file.

Windows NT : hFile can be any handle opened with the FILE_FLAG_OVERLAPPED flag by the CreateFile function, or a socket handle returned by the socket or accept functions.

Windows 95 : hFile can be a communications resource, mailslot, or named pipe handle opened with the FILE_FLAG_OVERLAPPED flag by CreateFile, or a socket handle returned by the socket or accept functions. Windows 95 does not support asynchronous operations on disk files.

lpBuffer

Points to a buffer that receives the data read from the file.

This buffer must remain valid for the duration of the read operation. The application should not use this buffer until the read operation is completed.

nNumberOfBytesToRead

Specifies the number of bytes to be read from the file.

lpOverlapped

Points to an OVERLAPPED data structure that supplies data to be used during the asynchronous (overlapped) file read operation.

If the file specified by hFile supports the concept of byte offsets, the caller of ReadFileEx must specify a byte offset within the file at which reading should begin. The caller specifies the byte offset by setting the OVERLAPPED structure's Offset and OffsetHigh members.

If the file entity specified by hFile does not support the concept of byte offsets — for example, if it is a named pipe — the caller must set the Offset and OffsetHigh members to zero, or ReadFileEx fails.

The ReadFileEx function ignores the OVERLAPPED structure's hEvent member. An application is free to use that member for its own purposes in the context of a ReadFileEx call. ReadFileEx signals completion of its read operation by calling, or queueing a call to, the completion routine pointed to by lpCompletionRoutine, so it does not need an event handle.

The ReadFileEx function does use the OVERLAPPED structure's Internal and InternalHigh members. An application should not set these members.

The OVERLAPPED data structure pointed to by lpOverlapped must remain valid for the duration of the read operation. It should not be a variable that can go out of scope while the file read operation is in progress.

lpCompletionRoutine

Points to the completion routine to be called when the read operation is complete and the calling thread is in an alertable wait state. For more information about the completion routine, see FileIOCompletionRoutine.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

If the function succeeds, the calling thread has an asynchronous I/O (input/output) operation pending: the overlapped read operation from the file. When this I/O operation completes, and the calling thread is blocked in an alertable wait state, the system calls the function pointed to by lpCompletionRoutine, and the wait state completes with a return code of WAIT_IO_COMPLETION.

If the function succeeds, and the file reading operation completes, but the calling thread is not in an alertable wait state, the system queues the completion routine call, holding the call until the calling thread enters an alertable wait state. For information about alertable waits and overlapped input/output operations, see Synchronization and Overlapped Input and Output.

If ReadFileEx attempts to read past the end of the file, the function returns FALSE, and GetLastError returns ERROR_HANDLE_EOF.

Remarks

If a portion of the file specified by hFile is locked by another process, and the read operation specified in a call to ReadFileEx overlaps the locked portion, the call to ReadFileEx fails.

If ReadFileEx attempts to read data from a mailslot whose buffer is too small, the function returns FALSE, and GetLastError returns ERROR_INSUFFICIENT_BUFFER.

Applications must not read from nor write to the input buffer that a read operation is using until the read operation completes. A premature access to the input buffer may lead to corruption of the data read into that buffer.

The ReadFileEx function may fail if there are too many outstanding asynchronous I/O requests. In the event of such a failure, GetLastError can return ERROR_INVALID_USER_BUFFER or ERROR_NOT_ENOUGH_MEMORY.

If hFile is a handle to a named pipe or other file entity that doesn't support the byte-offset concept, the Offset and OffsetHigh members of the OVERLAPPED structure pointed to by lpOverlapped must be zero, or ReadFileEx fails.

An application uses the WaitForSingleObjectEx, WaitForMultipleObjectsEx, and SleepEx functions to enter an alertable wait state. For more information about alertable waits and overlapped input/output, refer to those functions' reference and the "Synchronization"  topic mentioned previously.

Windows 95: On this platform, neither ReadFileEx nor WriteFileEx can be used by the comm ports to communicate. However, you can use ReadFile and WriteFile to perform asynchronous communication.

See Also

CreateFile, FileIOCompletionRoutine, OVERLAPPED, ReadFile, SleepEx, WaitForMultipleObjectsEx, WaitForSingleObjectEx, WriteFileEx, Synchronization


ReadPrinter
ReadPrinter  QuickInfo  Overview  Group

The ReadPrinter function retrieves data from the specified printer.

BOOL ReadPrinter(

HANDLE  hPrinter,	// handle of printer object
LPVOID  lpBuf,	// address of array of bytes that receives data
DWORD  cbBuf,	// size, in bytes, of array
LPDWORD  lpdwBytes	// address of variable with number of bytes retrieved
);
Parameters

hPrinter

Identifies the printer for which to retrieve data.

lpBuf

Points to an array of bytes that receives the printer data.

cbBuf

Specifies the size, in bytes, of the buffer to which lpBuf points.

lpdwBytes

Points to a variable that receives the number of bytes of data copied into the array to which lpBuf points.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

ReadPrinter returns an error if the device or the printer is not bidirectional.

See Also

OpenPrinter


ReadProcessMemory
ReadProcessMemory  QuickInfo  Overview  Group

The ReadProcessMemory function reads memory in a specified process. The entire area to be read must be accessible, or the operation fails.

BOOL ReadProcessMemory(

HANDLE  hProcess,	// handle of the process whose memory is read
LPCVOID  lpBaseAddress,	// address to start reading
LPVOID  lpBuffer,	// address of buffer to place read data
DWORD  cbRead,	// number of bytes to read
LPDWORD  lpNumberOfBytesRead	// address of number of bytes read
);
Parameters

hProcess

Identifies an open handle of a process whose memory is read. The handle must have PROCESS_VM_READ access to the process.

lpBaseAddress

Points to the base address in the specified process to be read. Before any data transfer occurs, the system verifies that all data in the base address and memory of the specified size is accessible for read access. If this is the case, the function proceeds; otherwise, the function fails.

lpBuffer

Points to a buffer that receives the contents from the address space of the specified process.

cbRead

Specifies the requested number of bytes to read from the specified process.

lpNumberOfBytesRead

Points to the actual number of bytes transferred into the specified buffer. If lpNumberOfBytesRead is NULL, the parameter is ignored.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

The function fails if the requested read operation crosses into an area of the process that is inaccessible.

Remarks

ReadProcessMemory copies the data in the specified address range from the address space of the specified process into the specified buffer of the current process. Any process that has a handle with PROCESS_VM_READ access can call the function. The process whose address space is read is typically, but not necessarily, being debugged.

The entire area to be read must be accessible. If it is not, the function fails as noted previously.

See Also

WriteProcessMemory


RealizePalette
RealizePalette  QuickInfo  Overview  Group

The RealizePalette function maps palette entries from the current logical palette to the system palette.

UINT RealizePalette(

HDC  hdc	// handle of device context
);
Parameters

hdc

Identifies the device context (DC) into which a logical palette has been selected.

Return Value

If the function succeeds, the return value is the number of entries in the logical palette mapped to the system palette.

If the function fails, the return value is GDI_ERROR. To get extended error information, call GetLastError.

Remarks

An application can determine whether a device supports palette operations by calling the GetDeviceCaps function and specifying the RASTERCAPS constant.

The RealizePalette function modifies the palette for the device associated with the specified device context. If the device context is a memory DC, the color table for the bitmap selected into the DC is modified. If the device context is a display DC, the physical palette for that device is modified.

A logical color palette is a buffer between color-intensive applications and the system, allowing these applications to use as many colors as needed without interfering with colors displayed by other windows.

When an application's window has the focus and it calls the RealizePalette function, Windows attempts to realize as many of the requested colors as possible. The same is also true for applications with inactive windows.

See Also

CreatePalette, GetDeviceCaps, SelectPalette


Rectangle
Rectangle  QuickInfo  Overview  Group

The Rectangle function draws a rectangle. The rectangle is outlined by using the current pen and filled by using the current brush.

BOOL Rectangle(

HDC  hdc,	// handle of device context
int  nLeftRect,	// x-coord. of bounding rectangle's upper-left corner
int  nTopRect,	// y-coord. of bounding rectangle's upper-left corner
int  nRightRect,	// x-coord. of bounding rectangle's lower-right corner
int  nBottomRect	// y-coord. of bounding rectangle's lower-right corner
);
Parameters

hdc

Identifies the device context.

nLeftRect

Specifies the logical x-coordinate of the upper-left corner of the rectangle.

nTopRect

Specifies the logical y-coordinate of the upper-left corner of the rectangle.

nRightRect

Specifies the logical x-coordinate of the lower-right corner of the rectangle.

nBottomRect

Specifies the logical y-coordinate of the lower-right corner of the rectangle.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The current position is neither used nor updated by Rectangle.

See Also

RoundRect


RectInRegion
RectInRegion  QuickInfo  Overview  Group

The RectInRegion function determines whether any part of the specified rectangle is within the boundaries of a region.

BOOL RectInRegion(

HRGN  hrgn,	// handle of region
CONST RECT  *lprc	// address of structure with rectangle
);
Parameters

hrgn

Identifies the region.

lprc

Points to a RECT structure containing the coordinates of the rectangle. The lower and right edges of the rectangle are not included.

Return Value

If any part of the specified rectangle lies within the boundaries of the region, the return value is TRUE.

If the function fails, the return value is FALSE.

See Also

PtInRegion, RECT


RectVisible
RectVisible  QuickInfo  Overview  Group

The RectVisible function determines whether any part of the specified rectangle lies within the clipping region of a device context.

BOOL RectVisible(

HDC  hdc,	// handle of the device context
CONST RECT  *lprc	// address of rectangle structure
);
Parameters

hdc

Identifies the device context.

lprc

Points to a RECT structure that contains the logical coordinates of the specified rectangle.

Return Value

If some portion of the specified rectangle lies within the clipping region, the return value is TRUE.

If the function fails, the return value is FALSE.

See Also

CreateRectRgn, PtVisible, RECT, SelectClipRgn


recv
recv  QuickInfo

The Windows Sockets recv function receives data from a socket.

int recv (

SOCKET s,
char FAR * buf,
int len,
int flags
);
Parameters

s

A descriptor identifying a connected socket.

buf

A buffer for the incoming data.

len

The length of buf.

flags

Specifies the way the call is made.

Return Value

If the function succeeds, recv returns the number of bytes received. If the connection has been closed, it returns zero.

If the function fails, a value of SOCKET_ERROR is returned. To get extended error information, call WSAGetLastError.

Error Codes

WSANOTINITIALISED	A successful WSAStartup must occur before using this function.
WSAENETDOWN	The Windows Sockets implementation has detected that the network subsystem has failed.
WSAENOTCONN	The socket is not connected.
WSAEINTR	The (blocking) call was canceled using WSACancelBlockingCall.
WSAEINPROGRESS	A blocking Windows Sockets operation is in progress.
WSAENOTSOCK	The descriptor is not a socket.
WSAEOPNOTSUPP	MSG_OOB was specified, but the socket is not of type SOCK_STREAM.
WSAESHUTDOWN	The socket has been shut down; it is not possible to recv on a socket after shutdown has been invoked with how set to 0 or 2.
WSAEWOULDBLOCK	The socket is marked as nonblocking and the receive operation would block.
WSAEMSGSIZE	The datagram was too large to fit into the specified buffer and was truncated.
WSAEINVAL	The socket has not been bound with bind.
WSAECONNABORTED	The virtual circuit was aborted due to timeout or other failure.
WSAECONNRESET	The virtual circuit was reset by the remote side.
Remarks

This function is used on connected datagram or stream sockets specified by the s parameter and is used to read incoming data.

For sockets of type SOCK_STREAM, as much information as is currently available up to the size of the buffer supplied is returned. If the socket has been configured for in-line reception of out-of-band data (socket option SO_OOBINLINE) and out-of-band data is unread, only out-of-band data will be returned. The application may use the ioctlsocket SIOCATMARK to determine whether any more out-of-band data remains to be read.

For datagram sockets, data is extracted from the first enqueued datagram, up to the size of the buffer supplied. If the datagram is larger than the buffer supplied, the buffer is filled with the first part of the datagram, the excess data is lost, and recv returns the error WSAEMSGSIZE.

If no incoming data is available at the socket, the recv call waits for data to arrive unless the socket is nonblocking. In this case a value of SOCKET_ERROR is returned with the error code set to WSAEWOULDBLOCK. The select or WSAAsyncSelect calls can be used to determine when more data arrives.

If the socket is of type SOCK_STREAM and the remote side has shut down the connection gracefully, a recv will complete immediately with 0 bytes received. If the connection has been reset, a recv will fail with the error WSAECONNRESET.

Flags may be used to influence the behavior of the function invocation beyond the options specified for the associated socket. That is, the semantics of this function are determined by the socket options and the flags parameter. The latter is constructed by using a bitwise OR operation with any of the following values:

Value	Meaning
MSG_PEEK	Peek at the incoming data. The data is copied into the buffer but is not removed from the input queue.
MSG_OOB	Process out-of-band data (See the Remarks section for a discussion of this topic.)
See Also

bind, recvfrom, send, select, shutdown, socket, WSAAsyncSelect, WSACancelBlockingCall, WSAStartup


recvfrom
recvfrom  QuickInfo

The Windows Sockets recvfrom function receives a datagram and stores the source address.

int recvfrom (

SOCKET s,
char FAR * buf,
int len,
int flags,
struct sockaddr FAR * from,
int FAR * fromlen
);
Parameters

s

A descriptor identifying a bound socket.

buf

A buffer for the incoming data.

len

The length of buf.

flags

Specifies the way the call is made.

from

An optional pointer to a buffer to hold the source address upon return.

fromlen

An optional pointer to the size of the from buffer.

Return Value

If the function succeeds, recvfrom returns the number of bytes received. If the connection has been closed, it returns zero.

If the function fails, a value of SOCKET_ERROR is returned. To get extended error information, call WSAGetLastError.

Error Codes

WSANOTINITIALISED	A successful WSAStartup must occur before using this function.
WSAENETDOWN	The Windows Sockets implementation has detected that the network subsystem has failed.
WSAEFAULT	The fromlen argument was invalid: the from buffer was too small to accommodate the peer address.
WSAEINTR	The (blocking) call was canceled using WSACancelBlockingCall.
WSAEINPROGRESS	A blocking Windows Sockets operation is in progress.
WSAEINVAL	The socket has not been bound with bind.
WSAENOTCONN	The socket is not connected (SOCK_STREAM only).
WSAENOTSOCK	The descriptor is not a socket.
WSAEOPNOTSUPP	MSG_OOB was specified, but the socket is not of type SOCK_STREAM.
WSAESHUTDOWN	The socket has been shut down; it is not possible to recvfrom on a socket after shutdown has been invoked with how set to 0 or 2.
WSAEWOULDBLOCK	The socket is marked as nonblocking and the recvfrom operation would block.
WSAEMSGSIZE	The datagram was too large to fit into the specified buffer and was truncated.
WSAECONNABORTED	The virtual circuit was aborted due to timeout or other failure.
WSAECONNRESET	The virtual circuit was reset by the remote side.
Remarks

This function is used to read incoming data on a (possibly connected) socket and capture the address from which the data was sent.

For sockets of type SOCK_STREAM, as much information as is currently available up to the size of the buffer supplied is returned. If the socket has been configured for in-line reception of out-of-band data (socket option SO_OOBINLINE) and out-of-band data is unread, only out-of-band data will be returned. The application may use the ioctlsocket SIOCATMARK to determine whether any more out-of-band data remains to be read. The from and fromlen parameters are ignored for SOCK_STREAM sockets.

For datagram sockets, data is extracted from the first enqueued datagram, up to the size of the buffer supplied. If the datagram is larger than the buffer supplied, the buffer is filled with the first part of the message, the excess data is lost, and recvfrom returns the error code WSAEMSGSIZE.

If from is nonzero, and the socket is of type SOCK_DGRAM, the network address of the peer that sent the data is copied to the corresponding socket address structure. The value pointed to by fromlen is initialized to the size of this structure, and is modified on return to indicate the actual size of the address stored there.

If no incoming data is available at the socket, the recvfrom call waits for data to arrive unless the socket is nonblocking. In this case a value of SOCKET_ERROR is returned with the error code set to WSAEWOULDBLOCK. The select or WSAAsyncSelect calls may be used to determine when more data arrives.

If the socket is of type SOCK_STREAM and the remote side has shut down the connection gracefully, a recvfrom will complete immediately with zero bytes received. If the connection has been reset, recv will fail with the error WSAECONNRESET.

You can use the flags parameter to influence the behavior of the function invocation beyond the options specified for the associated socket. That is, the semantics of the recvfrom function are determined by the socket options and the flags parameter. The latter is constructed by using a bitwise OR operation with any of the following values:

Value	Meaning
MSG_PEEK	Peek at the incoming data. The data is copied into the buffer but is not removed from the input queue.
MSG_OOB	Process out-of-band data (See the Remarks section for a discussion of this topic.)
See Also

bind, recv, select, send, shutdown, socket, WSAAsyncSelect, WSACancelBlockingCall, WSAStartup


RedrawWindow
RedrawWindow  QuickInfo  Overview  Group

The RedrawWindow function updates the specified rectangle or region in a window's client area.

BOOL RedrawWindow(

HWND  hwnd,	// handle of window
CONST RECT  *lprcUpdate,	// address of structure with update rectangle
HRGN  hrgnUpdate,	// handle of update region
UINT  afuRedraw	// array of redraw flags
);
Parameters

hwnd

Identifies the window to be redrawn. If this parameter is NULL, the desktop window is updated.

lprcUpdate

Points to a RECT structure containing the coordinates of the update rectangle. This parameter is ignored if the hrgnUpdate parameter identifies a region.

hrgnUpdate

Identifies the update region. If both the hrgnUpdate and lprcUpdate parameters are NULL, the entire client area is added to the update region.

afuRedraw

Specifies one or more redraw flags. This parameter can be a combination of flags that invalidate or validate a window, control repainting, and control which windows are affected by RedrawWindow.

The following flags are used to invalidate the window:

Flag (invalidation)	Description
RDW_ERASE	Causes the window to receive a WM_ERASEBKGND message when the window is repainted. The RDW_INVALIDATE flag must also be specified; otherwise, RDW_ERASE has no effect.
RDW_FRAME	Causes any part of the nonclient area of the window that intersects the update region to receive a WM_NCPAINT message. The RDW_INVALIDATE flag must also be specified; otherwise, RDW_FRAME has no effect. The WM_NCPAINT message is typically not sent during the execution of RedrawWindow unless either RDW_UPDATENOW or RDW_ERASENOW is specified.
RDW_INTERNALPAINT	Causes a WM_PAINT message to be posted to the window regardless of whether any portion of the window is invalid.
RDW_INVALIDATE	Invalidates lprcUpdate or hrgnUpdate (only one may be non-NULL). If both are NULL, the entire window is invalidated.
The following flags are used to validate the window:

Flag (validation)	Description
RDW_NOERASE	Suppresses any pending WM_ERASEBKGND messages.
RDW_NOFRAME	Suppresses any pending WM_NCPAINT messages. This flag must be used with RDW_VALIDATE and is typically used with RDW_NOCHILDREN. RDW_NOFRAME should be used with care, as it could cause parts of a window to be painted improperly.
RDW_NOINTERNALPAINT	Suppresses any pending internal WM_PAINT messages. This flag does not affect WM_PAINT messages resulting from a non-NULL update area.
RDW_VALIDATE	Validates lprcUpdate or hrgnUpdate (only one may be non-NULL). If both are NULL, the entire window is validated. This flag does not affect internal WM_PAINT messages.
The following flags control when repainting occurs. RedrawWindow will not repaint unless one of these flags is specified.

Flag	Description
RDW_ERASENOW	Causes the affected windows (as specified by the RDW_ALLCHILDREN and RDW_NOCHILDREN flags) to receive WM_NCPAINT and WM_ERASEBKGND messages, if necessary, before the function returns. WM_PAINT messages are received at the ordinary time.
RDW_UPDATENOW	Causes the affected windows (as specified by the RDW_ALLCHILDREN and RDW_NOCHILDREN flags) to receive WM_NCPAINT, WM_ERASEBKGND, and WM_PAINT messages, if necessary, before the function returns.
By default, the windows affected by RedrawWindow depend on whether the given window has the WS_CLIPCHILDREN style. Child windows that are not the WS_CLIPCHILDREN style are unaffected; non-WS_CLIPCHILDREN windows are recursively validated or invalidated until a WS_CLIPCHILDREN window is encountered. The following flags control which windows are affected by the RedrawWindow function:

Flag	Description
RDW_ALLCHILDREN	Includes child windows, if any, in the repainting operation.
RDW_NOCHILDREN	Excludes child windows, if any, from the repainting operation.
Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

When RedrawWindow is used to invalidate part of the desktop window, the desktop window does not receive a WM_PAINT message. To repaint the desktop, an application uses the RDW_ERASE flag to generate a WM_ERASEBKGND message.

See Also

GetUpdateRect, GetUpdateRgn, InvalidateRect, InvalidateRgn, RECT, UpdateWindow


RegCloseKey
RegCloseKey  QuickInfo  Overview  Group

The RegCloseKey function releases the handle of the specified key.

LONG RegCloseKey(

HKEY  hKey	// handle of key to close
);
Parameters

hKey

Identifies the open key to close.

Return Value

If the function succeeds, the return value is ERROR_SUCCESS.

If the function fails, the return value is an error value.

Remarks

The handle for a specified key should not be used after it has been closed, because it will no longer be valid. Key handles should not be left open any longer than necessary.

The RegCloseKey function does not necessarily write information to the registry before returning; it can take as much as several seconds for the cache to be flushed to the hard disk. If an application must explicitly write registry information to the hard disk, it can use the RegFlushKey function. RegFlushKey, however, uses many system resources and should be called only when necessary.

See Also

RegCreateKey, RegCreateKeyEx, RegDeleteKey, RegFlushKey, RegOpenKey, RegOpenKeyEx, RegSetValue, RegSetValueEx


RegConnectRegistry
RegConnectRegistry  QuickInfo  Overview  Group

The RegConnectRegistry function establishes a connection to a predefined registry handle on another computer.

LONG RegConnectRegistry(

LPTSTR  lpszComputerName,	// address of name of remote computer
HKEY  hKey,	// predefined registry handle
PHKEY  phkResult	// address of buffer for remote registry handle
);
Parameters

lpszComputerName

Points to a null-terminated string containing the name of the remote computer. The string has the following form:

\\computername

If lpszComputerName is NULL, the local computer name is used.

hKey

Specifies the predefined handle of the registry on the remote computer. Currently, the following values can be used:

HKEY_LOCAL_MACHINE
HKEY_USERS

An application cannot specify the HKEY_CLASSES_ROOT or HKEY_CURRENT_USER value for this parameter.

phkResult

Points to a variable that receives a key handle identifying the predefined handle on the remote computer.

Return Value

If the function succeeds, the return value is ERROR_SUCCESS.

If the function fails, the return value is an error value.

Remarks

When a handle returned by RegConnectRegistry is no longer needed, it should be closed by calling RegCloseKey.

See Also

RegCloseKey


RegCreateKey
RegCreateKey  QuickInfo  Overview  Group

The RegCreateKey function creates the specified key. If the key already exists in the registry, the function opens it. This function is provided for compatibility with Windows version 3.1. Win32-based applications should use the RegCreateKeyEx function.

LONG RegCreateKey(

HKEY  hKey,	// handle of an open key
LPCTSTR  lpszSubKey,	// address of name of subkey to open
PHKEY  phkResult	// address of buffer for opened handle
);
Parameters

hKey

Identifies a currently open key or any of the following predefined reserved handle values:

HKEY_CLASSES_ROOT
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS

The key opened or created by this function is a subkey of the key identified by hKey.

lpszSubKey

Points to a null-terminated string specifying the name of a key that this function opens or creates. This key must be a subkey of the key identified by the hKey parameter.

If hKey is one of the predefined keys, lpszSubKey may be NULL. In that case, the handle returned by using phkResult is the same hKey handle passed in to the function.

phkResult

Points to a variable that receives the handle of the opened or created key.

Return Value

If the function succeeds, the return value is ERROR_SUCCESS.

If the function fails, the return value is an error value.

Remarks

An application can use the RegCreateKey function to create several keys at once. For example, an application can create a subkey four levels deep at the same time as the three preceding subkeys by specifying a string of the following form for the lpszSubKey parameter:

subkey1\subkey2\subkey3\subkey4

The key identified by the hKey parameter must have been opened with KEY_CREATE_SUB_KEY access (KEY_WRITE access includes KEY_CREATE_SUB_KEY access).

If the lpszSubKey parameter is the address of an empty string, the function opens and then passes back the key identified by the hKey parameter.

See Also

RegCloseKey, RegCreateKeyEx, RegDeleteKey, RegOpenKey, RegOpenKeyEx, RegSetValue


RegCreateKeyEx
RegCreateKeyEx  QuickInfo  Overview  Group

The RegCreateKeyEx function creates the specified key. If the key already exists in the registry, the function opens it.

LONG RegCreateKeyEx(

HKEY  hKey,	// handle of an open key
LPCTSTR  lpszSubKey,	// address of subkey name
DWORD  dwReserved,	// reserved
LPTSTR  lpszClass,	// address of class string
DWORD  fdwOptions,	// special options flag
REGSAM  samDesired,	// desired security access
LPSECURITY_ATTRIBUTES  lpSecurityAttributes,	// address of key security structure
PHKEY  phkResult,	// address of buffer for opened handle
LPDWORD  lpdwDisposition	// address of disposition value buffer
);
Parameters

hKey

Identifies a currently open key or any of the following predefined reserved handle values:

HKEY_CLASSES_ROOT
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS

The key opened or created by the RegCreateKeyEx function is a subkey of the key identified by the hKey parameter.

lpszSubKey

Points to a null-terminated string specifying the name of a subkey that this function opens or creates. The subkey specified must be a subkey of the key identified by the hKey parameter. This subkey must not begin with the backslash character ('\'). This parameter cannot be NULL.

dwReserved

Reserved; must be zero.

lpszClass

Points to a null-terminated string that specifies the class (object type) of this key. This parameter is ignored if the key already exists.

fdwOptions

Specifies special options for the key. Currently, this parameter can be one of the following values:

Value	Meaning
REG_OPTION_VOLATILE	Windows 95: This value is ignored in Windows 95. That is, even if REG_OPTION_VOLATILE is specified, the RegCreateKeyEx function creates a nonvolatile key and returns ERROR_SUCCESS. Windows NT: This key is volatile; the information is stored in memory and is not preserved when the system is restarted. The RegSaveKey function does not save volatile keys.
REG_OPTION_NON_VOLATILE	This key is not volatile; the information is stored in a file and is preserved when the system is restarted. The RegSaveKey function saves keys that are not volatile.
By default, keys are not volatile. This option is ignored if the key already exists.

The RegSaveKey function only saves nonvolatile keys. It does not save volatile keys.

samDesired

Specifies an access mask that specifies the desired security access for the new key. This parameter can be a combination of the following values:

Value	Meaning
KEY_ALL_ACCESS	Combination of KEY_QUERY_VALUE, KEY_ENUMERATE_SUB_KEYS, KEY_NOTIFY, KEY_CREATE_SUB_KEY, KEY_CREATE_LINK, and KEY_SET_VALUE access.
KEY_CREATE_LINK	Permission to create a symbolic link.
KEY_CREATE_SUB_KEY	Permission to create subkeys.
KEY_ENUMERATE_SUB_KEYS	Permission to enumerate subkeys.
KEY_EXECUTE	Permission for read access.
KEY_NOTIFY	Permission for change notification.
KEY_QUERY_VALUE	Permission to query subkey data.
KEY_READ	Combination of KEY_QUERY_VALUE, KEY_ENUMERATE_SUB_KEYS, and KEY_NOTIFY access.
KEY_SET_VALUE	Permission to set subkey data.
KEY_WRITE	Combination of KEY_SET_VALUE and KEY_CREATE_SUB_KEY access.
lpSecurityAttributes

Points to a SECURITY_ATTRIBUTES structure that specifies the security attributes for the new key.

If this parameter is NULL, the key receives a default security descriptor. If the operating system does not support security, this parameter is ignored.

phkResult

Points to a variable that receives the handle of the opened or created key.

lpdwDisposition

Points to a variable that receives one of the following disposition values:

Value	Meaning
REG_CREATED_NEW_KEY	The key did not exist and was created.
REG_OPENED_EXISTING_KEY	The key existed and was simply opened without being changed.
Return Value

If the function succeeds, the return value is ERROR_SUCCESS.

If the function fails, the return value is an error value.

Remarks

The key that the RegCreateKeyEx function creates has no values. An application can use the RegSetValue or RegSetValueEx function to set key values.

The key identified by the hKey parameter must have been opened with KEY_CREATE_SUB_KEY access. To open the key, use the RegCreateKeyEx or RegOpenKeyEx function.

An application cannot create a key under HKEY_USERS or HKEY_MACHINE.

An application can use RegCreateKeyEx to temporarily lock a portion of the registry. When the locking process creates a new key, it receives the disposition value REG_CREATED_NEW_KEY, indicating that it "owns" the lock. Another process attempting to create the same key receives the disposition value REG_OPENED_EXISTING_KEY, indicating that another process already owns the lock.

See Also

RegCreateKey, RegDeleteKey, RegOpenKey, RegOpenKeyEx, RegSaveKey, SECURITY_ATTRIBUTES


RegDeleteKey
RegDeleteKey  QuickInfo  Overview  Group

Windows 95: The RegDeleteKey function deletes a key and all its descendents.

Windows NT: The RegDeleteKey function deletes the specified key. This function cannot delete a key that has subkeys.

LONG RegDeleteKey(

HKEY  hKey,	// handle of open key
LPCTSTR  lpszSubKey	// address of name of subkey to delete
);
Parameters

hKey

Identifies a currently open key or any of the following predefined reserved handle values:

HKEY_CLASSES_ROOT
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS

The key specified by the lpszSubKey parameter must be a subkey of the key identified by hKey.

lpszSubKey

Points to a null-terminated string specifying the name of the key to delete. This parameter cannot be NULL, and the specified key must not have subkeys.

Return Value

If the function succeeds, the return value is ERROR_SUCCESS.

If the function fails, the return value is an error value.

Remarks

If the function succeeds, RegDeleteKey removes the specified key from the registry. The entire key, including all of its values, is removed.

To open the key, use the RegCreateKeyEx or RegOpenKeyEx function. Do not use the RegCreateKey or RegOpenKey functions.

See Also

RegCloseKey, RegCreateKeyEx, RegOpenKeyEx


RegDeleteValue
RegDeleteValue  QuickInfo  Overview  Group

The RegDeleteValue function removes a named value from the specified registry key.

LONG RegDeleteValue(

HKEY  hKey,	// handle of key
LPTSTR  lpszValue	// address of value name
);
Parameters

hKey

Identifies a currently open key or any of the following predefined reserved handle values:

HKEY_CLASSES_ROOT
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS

lpszValue

Points to a null-terminated string that names the value to remove. If this parameter is NULL or points to an empty string, the value set by the RegSetValue function is removed.

Return Value

If the function succeeds, the return value is ERROR_SUCCESS.

If the function fails, the return value is an error value.

Remarks

The key identified by the hKey parameter must have been opened with KEY_SET_VALUE access (KEY_WRITE access includes KEY_SET_VALUE access).

See Also

RegSetValue, RegSetValueEx


RegEnumKey
RegEnumKey  QuickInfo  Overview  Group

The RegEnumKey function enumerates subkeys of the specified open registry key. The function retrieves the name of one subkey each time it is called. This function is provided for compatibility with Windows version 3.1. Win32-based applications should use the RegEnumKeyEx function.

LONG RegEnumKey(

HKEY  hKey,	// handle of key to query
DWORD  iSubKey,	// index of subkey to query
LPTSTR  lpszName,	// address of buffer for subkey name
DWORD  cchName	// size of subkey buffer
);
Parameters

hKey

Identifies a currently open key or any of the following predefined reserved handle values:

HKEY_CLASSES_ROOT
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS

The keys returned are relative to the key identified by hKey.

iSubKey

Specifies the index of the subkey to retrieve. This value should be zero for the first call to the RegEnumKey function and then incremented for subsequent calls.

Because subkeys are not ordered, any new subkey will have an arbitrary index. This means that the function may return subkeys in any order.

lpszName

Points to a buffer that receives the name of the subkey, including the terminating null character. This function copies only the name of the subkey, not the full key hierarchy, to the buffer.

cchName

Specifies the size, in characters, of the buffer pointed to by the lpszName parameter, in characters. To determine the required buffer size, use the RegQueryInfoKey function to determine the size of the largest subkey for the key identified by the hKey parameter. The maximum required buffer size is (MAX_PATH + 1) characters.

Return Value

If the function succeeds, the return value is ERROR_SUCCESS.

If the function fails, the return value is an error value.

Remarks

To enumerate subkeys, an application should initially call the RegEnumKey function with the iSubKey parameter set to zero. The application should then increment the iSubKey parameter and call the RegEnumKey function until there are no more subkeys (until the function returns ERROR_NO_MORE_ITEMS).

The application can also set iSubKey to the index of the last key on the first call to the function and decrement the index until the subkey with index 0 is enumerated. To retrieve the index of the last subkey, use the RegQueryInfoKey.

While an application is using the RegEnumKey function, it should not make calls to any registration functions that might change the key being queried.

The key identitied by the hKey parameter must have been opened with KEY_ENUMERATE_SUB_KEYS access (KEY_READ access includes KEY_ENUMERATE_SUB_KEYS access). To open the key, use the RegCreateKeyEx or RegOpenKeyEx function.

See Also

RegCloseKey, RegCreateKeyEx, RegDeleteKey, RegEnumKeyEx, RegOpenKeyEx, RegQueryInfoKey, RegQueryValue


RegEnumKeyEx
RegEnumKeyEx  QuickInfo  Overview  Group

The RegEnumKeyEx function enumerates subkeys of the specified open registry key. The function retrieves information about one subkey each time it is called. Unlike the RegEnumKey function, RegEnumKeyEx retrieves the class name of the subkey and the time it was last modified.

LONG RegEnumKeyEx(

HKEY  hKey,	// handle of key to enumerate
DWORD  iSubkey,	// index of subkey to enumerate
LPTSTR  lpszName,	// address of buffer for subkey name
LPDWORD  lpcchName,	// address for size of subkey buffer
LPDWORD  lpdwReserved,	// reserved
LPTSTR  lpszClass,	// address of buffer for class string
LPDWORD  lpcchClass,	// address for size of class buffer
PFILETIME  lpftLastWrite	// address for time key last written to
);
Parameters

hKey

Identifies a currently open key or any of the following predefined reserved handle values:

HKEY_CLASSES_ROOT
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS

The enumerated keys are subkeys of the key identified by hKey.

iSubkey

Specifies the index of the subkey to retrieve. This parameter should be zero for the first call to the RegEnumKeyEx function and then incremented for subsequent calls.

Because subkeys are not ordered, any new subkey will have an arbitrary index. This means that the function may return subkeys in any order.

lpszName

Points to a buffer that receives the name of the subkey, including the terminating null character. The function copies only the name of the subkey, not the full key hierarchy, to the buffer.

lpcchName

Points to a variable that specifies the size, in characters, of the buffer specified by the lpszName parameter. This size should include the terminating null character. When the function returns, the variable pointed to by lpcchName contains the number of characters stored in the buffer. The count returned does not include the terminating null character.

lpdwReserved

Reserved; must be NULL.

lpszClass

Points to a buffer that contains the class of the enumerated subkey when the function returns. This parameter can be NULL if the class is not required.

lpcchClass

Points to a variable that specifies the size, in characters, of the buffer specified by the lpszClass parameter. The size should include the terminating null character. When the function returns, lpcchClass contains the number of characters stored in the buffer. The count returned does not include the terminating null character. This parameter can be NULL only if lpszClass is NULL.

lpftLastWrite

Points to a variable that receives the time the enumerated subkey was last written to.

Return Value

If the function succeeds, the return value is ERROR_SUCCESS.

If the function fails, the return value is an error value.

Remarks

To enumerate subkeys, an application should initially call the RegEnumKeyEx function with the iSubKey parameter set to zero. The application should then increment the iSubKey parameter and call RegEnumKeyEx until there are no more subkeys (until the function returns ERROR_NO_MORE_ITEMS).

The application can also set iSubKey to the index of the last subkey on the first call to the function and decrement the index until the subkey with the index 0 is enumerated. To retrieve the index of the last subkey, use the RegQueryInfoKey function.

While an application is using the RegEnumKeyEx function, it should not make calls to any registration functions that might change the key being enumerated.

The key identified by hKey must have been opened with KEY_ENUMERATE_SUB_KEYS access (KEY_READ includes KEY_ENUMERATE_SUB_KEYS). Use the RegCreateKeyEx or RegOpenKeyEx function to open the key.

See Also

RegCreateKeyEx, RegDeleteKey, RegEnumKey, RegOpenKeyEx, RegQueryInfoKey


RegEnumValue
RegEnumValue  QuickInfo  Overview  Group

The RegEnumValue function enumerates the values for the specified open registry key. The function copies one indexed value name and data block for the key each time it is called.

LONG RegEnumValue(

HKEY  hKey,	// handle of key to query
DWORD  iValue,	// index of value to query
LPTSTR  lpszValue,	// address of buffer for value string
LPDWORD  lpcchValue,	// address for size of value buffer
LPDWORD  lpdwReserved,	// reserved
LPDWORD  lpdwType,	// address of buffer for type code
LPBYTE  lpbData,	// address of buffer for value data
LPDWORD  lpcbData	// address for size of data buffer
);
Parameters

hKey

Identifies a currently open key or any of the following predefined reserved handle values:

HKEY_CLASSES_ROOT
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS

The enumerated values are associated with the key identified by hKey.

iValue

Specifies the index of the value to retrieve. This parameter should be zero for the first call to the RegEnumValue function and then be incremented for subsequent calls.

Because values are not ordered, any new value will have an arbitrary index. This means that the function may return values in any order.

lpszValue

Points to a buffer that receives the name of the value, including the terminating null character.

lpcchValue

Points to a variable that specifies the size, in characters, of the buffer pointed to by the lpszValue parameter. This size should include the terminating null character. When the function returns, the variable pointed to by lpcchValue contains the number of characters stored in the buffer. The count returned does not include the terminating null character.

lpdwReserved

Reserved; must be NULL.

lpdwType

Points to a variable that receives the type code for the value entry. The type code can be one of the following values:

Value	Meaning
REG_BINARY	Binary data in any form.
REG_DWORD	A 32-bit number.
REG_DWORD_LITTLE_ENDIAN	A 32-bit number in little-endian format (same as REG_DWORD). In little-endian format, the most significant byte of a word is the high-order word. This is the most common format for computers running Windows NT and Windows 95.
REG_DWORD_BIG_ENDIAN	A 32-bit number in big-endian format. In big-endian format, the most significant byte of a word is the low-order word.
REG_EXPAND_SZ	A null-terminated string that contains unexpanded references to environment variables (for example, "%PATH%"). It will be a Unicode or ANSI string depending on whether you use the Unicode or ANSI functions.
REG_LINK	A Unicode symbolic link.
REG_MULTI_SZ	An array of null-terminated strings, terminated by two null characters.
REG_NONE	No defined value type.
REG_RESOURCE_LIST	A device-driver resource list.
REG_SZ	A null-terminated string. It will be a Unicode or ANSI string, depending on whether you use the Unicode or ANSI functions.
The lpdwType parameter can be NULL if the type code is not required.

lpbData

Points to a buffer that receives the data for the value entry. This parameter can be NULL if the data is not required.

lpcbData

Points to a variable that specifies the size, in bytes, of the buffer pointed to by the lpbData parameter. When the function returns, the variable pointed to by the lpcbData parameter contains the number of bytes stored in the buffer. This parameter can be NULL, only if lpbData is NULL.

Return Value

If the function succeeds, the return value is ERROR_SUCCESS.

If the function fails, the return value is an error value.

Remarks

To enumerate values, an application should initially call the RegEnumValue function with the iValue parameter set to zero. The application should then increment iValue and call the RegEnumValue function until there are no more values (until the function returns ERROR_NO_MORE_ITEMS).

The application can also set iValue to the index of the last value on the first call to the function and decrement the index until the value with index 0 is enumerated. To retrieve the index of the last value, use the RegQueryInfoKey function.

While using RegEnumValue, an application should not call any registration functions that might change the key being queried.

The key identified by the hKey parameter must have been opened with KEY_QUERY_VALUE access. To open the key, use the RegCreateKeyEx or RegOpenKeyEx function.

To determine the maximum size of the name and data buffers, use the RegQueryInfoKey function.

See Also

RegCreateKeyEx, RegEnumKey, RegEnumKeyEx, RegOpenKeyEx, RegQueryInfoKey


RegFlushKey
RegFlushKey  QuickInfo  Overview  Group

The RegFlushKey function writes all the attributes of the specified open key into the registry.

LONG RegFlushKey(

HKEY  hKey	// handle of key to write
);
Parameters

hKey

Identifies a currently open key or any of the following predefined reserved handle values:

HKEY_CLASSES_ROOT
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS

Return Value

If the function succeeds, the return value is ERROR_SUCCESS.

If the function fails, the return value is an error value.

Remarks

It is not necessary to call RegFlushKey to change a key. Registry changes are flushed to disk by the registry using its lazy flusher. Registry changes are also flushed to disk at system shutdown.

Unlike RegCloseKey, the RegFlushKey function returns only when all the data has been written to the registry.

The RegFlushKey function may also write out parts of or all of the other keys. Calling this function excessively can have a negative effect on an application's performance.

An application should only call RegFlushKey if it requires absolute certainty that registry changes are on disk. In general, RegFlushKey rarely, if ever, need be used.

See Also

RegCloseKey, RegDeleteKey


RegGetKeySecurity
RegGetKeySecurity  QuickInfo  Overview  Group

The RegGetKeySecurity function retrieves a copy of the security descriptor protecting the specified open registry key.

LONG RegGetKeySecurity(

HKEY  hKey,	// open handle of key to set
SECURITY_INFORMATION  SecInf,	// descriptor contents
PSECURITY_DESCRIPTOR  pSecDesc,	// address of descriptor for key
LPDWORD  lpcbSecDesc	// address of size of buffer and descriptor
);
Parameters

hKey

Identifies an open key for which to retrieve the security descriptor.

SecInf

Specifies a SECURITY_INFORMATION structure that indicates the requested security information.

pSecDesc

Points to a buffer that receives a copy of the requested security descriptor.

lpcbSecDesc

Points to a variable that specifies the size, in bytes, of the buffer pointed to by the pSecDesc parameter. When the function returns, the variable contains the number of bytes written to the buffer.

Return Value

If the function succeeds, the return value is ERROR_SUCCESS.

If the function fails, the return value is an error value.

Remarks

If the buffer specified by the pSecDesc parameter is too small, the function returns ERROR_INSUFFICIENT_BUFFER and the lpcbSecDesc parameter contains the number of bytes required for the requested security descriptor.

To read the security descriptor for the specified key, the calling process must have been granted READ_CONTROL access when the key was opened, or it must be the owner of the key. (READ_CONTROL access is granted by the KEY_READ, KEY_WRITE, KEY_EXECUTE, and KEY_ALL_ACCESS access rights.) In addition, the caller must have the SE_SECURITY_NAME privilege to read the system access-control list (SACL).

For more information about security, see Security.

See Also

RegDeleteKey, RegOpenKeyEx, RegSetKeySecurity, SECURITY_INFORMATION


RegisterClass
RegisterClass  QuickInfo  Overview  Group

The RegisterClass function registers a window class for subsequent use in calls to the CreateWindow or CreateWindowEx function.

ATOM RegisterClass(

CONST WNDCLASS  *lpwc	// address of structure with class data
);
Parameters

lpwc

Points to a WNDCLASS structure. You must fill the structure with the appropriate class attributes before passing it to the function.

Return Value

If the function succeeds, the return value is an atom that uniquely identifies the class being registered.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

All window classes that an application registers are unregistered when it terminates.

See Also

CreateWindow, CreateWindowEx, GetClassInfo, GetClassName, UnregisterClass, WindowProc, WNDCLASS


RegisterClassEx [New - Windows 95]
RegisterClassEx  QuickInfo  Overview  Group

[New - Windows 95]

The RegisterClassEx function registers a window class for subsequent use in calls to the CreateWindow or CreateWindowEx function.

ATOM RegisterClassEx(

CONST WNDCLASSEX FAR  *lpwcx	// address of structure with class data
);
Parameters

lpwcx

Points to a WNDCLASSEX structure. You must fill the structure with the appropriate class attributes before passing it to the function.

Return Value

If the function succeeds, the return value is an atom that uniquely identifies the class being registered.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

All window classes that an application registers are unregistered when it terminates.

See Also

CreateWindow, CreateWindowEx, GetClassInfoEx, GetClassName, UnregisterClass, WindowProc


RegisterClipboardFormat
RegisterClipboardFormat  QuickInfo  Overview  Group

The RegisterClipboardFormat function registers a new clipboard format. This format can then be used as a valid clipboard format.

UINT RegisterClipboardFormat(

LPCTSTR  lpszFormat	// address of name string
);
Parameters

lpszFormat

Points to a null-terminated string that names the new format.

Return Value

If the function succeeds, the return value identifies the registered clipboard format.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

If a registered format with the specified name already exists, a new format is not registered and the return value identifies the existing format. This enables more than one application to copy and paste data using the same registered clipboard format.

Registered clipboard formats are identified by values in the range 0xC000 through 0xFFFF.

See Also

CountClipboardFormats, EnumClipboardFormats, GetClipboardFormatName


RegisterDialogClasses
RegisterDialogClasses  QuickInfo  Overview  Group

The RegisterDialogClasses function registers any nonstandard window classes required by a screen saver's configuration dialog box.

BOOL RegisterDialogClasses(

HANDLE  hinst	// handle of application instance
);
Parameters

hinst

Identifies an instance of the module registering the window classes.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The RegisterDialogClasses function should not be exported. It is called by routines defined in the SCRNSAVE.LIB file.

If a screen saver does not register any special window classes for the configuration dialog box, the RegisterDialogClasses function must return TRUE.

See Also

ScreenSaverConfigureDialog


RegisterEventSource
RegisterEventSource  QuickInfo  Overview  Group

The RegisterEventSource function returns a handle that can be used with the ReportEvent function to log an event.

Any source name can be used; it will be carried in the event log record so that Event Viewer can use it for filtering.

HANDLE RegisterEventSource(

LPCTSTR  lpszUNCServer,	// server name for source
LPCTSTR  lpszSource	// source name for registered handle
);
Parameters

lpszUNCServer

Points to a null-terminated string that specifies the Universal Naming Convention (UNC) name of the server on which this operation is to be performed. If this parameter is NULL, the operation is performed on the local computer.

lpszSource

Points to a null-terminated string that specifies the name of the source referenced by the returned handle. The source name must be a subkey of a logfile entry under the EventLog key in the registry. For example, the source name WinApp would be valid if the registry had the following form:

HKEY_LOCAL_MACHINE

  System

    CurrentControlSet

      Services

        EventLog

          Application

            WinApp

          Security

          System

If the source name cannot be found, the event logging service uses the Application logfile with no message files for the event identifier or category.

Return Value

If the function succeeds, the return value is a handle that can be used with the ReportEvent function.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

See Also

DeregisterEventSource, ReportEvent


RegisterHotKey
RegisterHotKey  QuickInfo  Overview  Group

The RegisterHotKey function defines a hot key for the current thread.

BOOL RegisterHotKey(

HWND  hwnd,	// window to receive hot-key notification
int  idHotKey,	// identifier of hot key
UINT  fuModifiers,	// key-modifier flags
UINT  uVirtKey	// virtual-key code
);
Parameters

hwnd

Identifies the window that will receive WM_HOTKEY messages generated by the hot key. If this parameter is NULL, WM_HOTKEY messages are posted to the message queue of the calling thread and must be processed in the message loop.

idHotKey

Specifies the identifier of the hot key. No other hot key in the calling thread should have the same identifier. An application must specify a value in the range 0x0000 through 0xBFFF. A shared dynamic-link library (DLL) must specify a value in the range 0xC000 through 0xFFFF (the range returned by the GlobalAddAtom function). To avoid conflicts with hot-key identifiers defined by other shared DLLs, a DLL should use the GlobalAddAtom function to obtain the hot-key identifier.

fuModifiers

Specifies keys that must be pressed in combination with the key specified by the nVirtKey parameter in order to generate the WM_HOTKEY message. The fuModifiers parameter can be a combination of the following values:

Value	Meaning
MOD_ALT	Either ALT key must be held down.
MOD_CONTROL	Either CTRL key must be held down.
MOD_SHIFT	Either SHIFT key must be held down.
uVirtKey

Specifies the virtual-key code of the hot key.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

When a key is pressed, the system looks for a match against all thread hot keys. Upon finding a match, the system posts the WM_HOTKEY message to the message queue of the thread that registered the hot key. This message is posted to the beginning of the queue so it is removed by the next iteration of the message loop.

This function cannot associate a hot key with a window created by another thread.

RegisterHotKey fails if the keystrokes specified for the hot key have already been registered by another hot key.

If the window identified by the hwnd parameter already registered a hot key with the same identifier as that specified by the idHotKey parameter, the new values for the fuModifiers and uVirtKey parameters replace the previously specified values for these parameters.

See Also

GlobalAddAtom, UnregisterHotKey, WM_HOTKEY


RegisterServiceCtrlHandler
RegisterServiceCtrlHandler  QuickInfo  Overview  Group

The RegisterServiceCtrlHandler function registers a function to handle service control requests for a service.

SERVICE_STATUS_HANDLE RegisterServiceCtrlHandler(

LPCTSTR  lpszServiceName,	// address of name of service
LPHANDLER_FUNCTION  lpHandlerProc	// address of handler function
);
Parameters

lpszServiceName

Points to a null-terminated string that names the service run by the calling thread. This is the service name that was specified in the CreateService function when the service was created.

lpHandlerProc

Points to the Handler function to be registered.

Return Value

If the function succeeds, the return value is a service status handle.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Errors

The following error codes may be set by the service control manager. Other error codes may be set by the registry functions that are called by the service control manager.

Value	Meaning
ERROR_INVALID_NAME	The specified service name is invalid.
ERROR_SERVICE_DOES_NOT_EXIST	The specified service does not exist.
Remarks

The ServiceMain function of a new service should immediately call the RegisterServiceCtrlHandler function to register a control handling function with the control dispatcher. This enables the control dispatcher to invoke the specified function when it receives control requests for this service. The threads of the calling process can use the service status handle returned by this function to identify the service in subsequent calls to the SetServiceStatus function.

This function must be called before the first SetServiceStatus call because it returns a service status handle for the caller to use so that no other service can inadvertently set this service's status, which is maintained by the service control manager. It also needs to be called before the first SetServiceStatus so that a control handler is in place to field control requests by the time the service specifies the controls it accepts through the SetServiceStatus function.

When the control handler function is invoked with a control request, it must call SetServiceStatus to notify the service control manager of its latest status, regardless of whether the status of the service has changed.

The service status handle does not have to be closed.

See Also

CreateService, Handler, ServiceMain, SetServiceStatus


RegisterWindowMessage
RegisterWindowMessage  QuickInfo  Overview  Group

The RegisterWindowMessage function defines a new window message that is guaranteed to be unique throughout the system. The returned message value can be used when calling the SendMessage or PostMessage function.

UINT RegisterWindowMessage(

LPCTSTR  lpsz	// address of message string
);
Parameters

lpsz

Points to a null-terminated string that specifies the message to be registered.

Return Value

If the message is successfully registered, the return value is a message identifier in the range 0xC000 through 0xFFFF.

If the function fails, the return value is zero.

Remarks

The RegisterWindowMessage function is typically used to register messages for communicating between two cooperating applications.

If two different applications register the same message string, the applications return the same message value. The message remains registered until the Windows session ends.

Only use RegisterWindowMessage when more than one application must process the same message. For sending private messages within a window class, an application can use any integer in the range WM_USER through 0x7FFF. (Messages in this range are private to a window class, not to an application. For example, predefined control classes such as BUTTON, EDIT, LISTBOX, and COMBOBOX may use values in this range.)

See Also

PostAppMessage, PostMessage, SendMessage


RegLoadKey
RegLoadKey  QuickInfo  Overview  Group

The RegLoadKey function creates a subkey under HKEY_USER or HKEY_LOCAL_MACHINE and stores registration information from a specified file into that subkey. This registration information is in the form of a hive. A hive is a discrete body of keys, subkeys, and values that is rooted at the top of the registry hierarchy. A hive is backed by a single file and .LOG file.

LONG RegLoadKey(

HKEY  hKey,	// handle of open key
LPCTSTR  lpszSubKey,	// address of name of subkey
LPCTSTR  lpszFile	// address of filename for registry information
);
Parameters

hKey

Specifies the key where the subkey will be created. This can be a predefined reserved handle value, or a handle returned by a call to RegConnectRegistry. The predefined reserved handle values are:

HKEY_LOCAL_MACHINE
HKEY_USERS

This function always loads information at the top of the registry hierarchy. The HKEY_CLASSES_ROOT and HKEY_CURRENT_USER handle values cannot be specified for this parameter, because they represent subsets of the HKEY_LOCAL_MACHINE and HKEY_USERS handle values, respectively.

lpszSubKey

Points to a null-terminated string that specifies the name of the key to be created under hKey. This subkey is where the registration information from the file will be loaded.

lpszFile

Points to a null-terminated string containing the name of a file that has registration information. This file must have been created with the RegSaveKey function. Under the file allocation table (FAT) file system, the filename may not have an extension.

Return Value

If the function succeeds, the return value is ERROR_SUCCESS.

If the function fails, the return value is an error value.

Remarks

A call to RegLoadKey fails if the calling process does not have the SE_RESTORE_PRIVILEGE privilege.

If hKey is a handle returned by RegConnectRegistry, then the path specified in lpszFile is relative to the remote computer.

See Also

RegConnectRegistry, RegDeleteKey, RegReplaceKey, RegRestoreKey, RegSaveKey, RegUnloadKey


RegNotifyChangeKeyValue
RegNotifyChangeKeyValue  QuickInfo  Overview  Group

The RegNotifyChangeKeyValue function indicates when a registry key or any of its subkeys has changed.

LONG RegNotifyChangeKeyValue(

HKEY  hKey,	// handle of key to watch
BOOL  fWatchSubTree,	// flag for subkey notification
DWORD  fdwNotifyFilter,	// changes to be reported
HANDLE  hEvent,	// handle of signaled event
BOOL  fAsync	// flag for asynchronous reporting
);
Parameters

hKey

Identifies a currently open key or any of the following predefined reserved handle values:

HKEY_CLASSES_ROOT
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS

fWatchSubTree

Specifies a flag that indicates whether to report changes in the specified key and all of its subkeys or only in the specified key. If this parameter is TRUE, the function reports changes in the key and its subkeys. If the parameter is FALSE, the function reports changes only in the key.

fdwNotifyFilter

Specifies a set of flags that control which changes should be reported. This parameter can be a combination of the following values:

Value	Meaning
REG_NOTIFY_CHANGE_NAME	Changes to key names that occur in the specified key or in the specified key and its subkeys cause a change notification. This includes key creations and deletions.
REG_NOTIFY_CHANGE_ATTRIBUTES	Attribute changes that occur in a key or in a key and its subkeys cause a change notification.
REG_NOTIFY_CHANGE_LAST_SET	Changes to the last write time that occur in a key or in a key and its subkeys cause a change notification.
REG_NOTIFY_CHANGE_SECURITY	Security-descriptor changes that occur in a key or in a key and its subkeys cause a change notification.
hEvent

Identifies an event. If the fAsync parameter is TRUE, the function returns immediately and changes are reported by signaling this event. If fAsync is FALSE, hEvent is ignored.

fAsync

Specifies a flag that indicates how the function reports changes. If this parameter is TRUE, the function returns immediately and reports changes by signaling the specified event. When this parameter is FALSE, the function does not return until a change has occurred.

If hEvent does not specify a valid event, the fAsync parameter cannot be TRUE.

Return Value

If the function succeeds, the return value is ERROR_SUCCESS.

If the function fails, the return value is an error value.

Remarks

If the key identified by the hKey parameter is closed, the event is signaled. This means that an application should not depend on the key being open after returning from a wait operation on the event.

RegNotifyChangeKeyValue does not work with remote handles. If RegNotifyChangeKeyValue is called with an hKey value that is a remote handle, it returns ERROR_INVALID_HANDLE.

See Also

RegDeleteKey, RegEnumKey, RegEnumKeyEx, RegEnumValue, RegQueryInfoKey, RegQueryValue, RegQueryValueEx


RegOpenKey
RegOpenKey  QuickInfo  Overview  Group

The RegOpenKey function opens the specified key. This function is provided for compatibility with Windows version 3.1. Win32-based applications should use the RegOpenKeyEx function.

LONG RegOpenKey(

HKEY  hKey,	// handle of open key
LPCTSTR  lpszSubKey,	// address of name of subkey to open
PHKEY  phkResult	// address of handle of open key
);
Parameters

hKey

Identifies a currently open key or any of the following predefined reserved handle values:

HKEY_CLASSES_ROOT
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS

The key opened by the RegOpenKey function is a subkey of the key identified by hKey.

lpszSubKey

Points to a null-terminated string containing the name of the key to open. This key must be a subkey of the key identified by the hKey parameter. If this parameter is NULL or a pointer to an empty string, the function returns the same handle that was passed in.

phkResult

Points to a variable that receives the handle of the opened key.

Return Value

If the function succeeds, the return value is ERROR_SUCCESS.

If the function fails, the return value is an error value.

Remarks

The RegOpenKey function uses the default security access mask to open a key. If opening the key requires a different mask, the function fails, returning ERROR_ACCESS_DENIED. An application should use the RegOpenKeyEx function to specify an access mask in this situation.

Unlike the RegCreateKey function, RegOpenKey does not create the specified key if the key does not exist in the database.

See Also

RegCreateKey, RegCreateKeyEx, RegDeleteKey, RegOpenKeyEx


RegOpenKeyEx
RegOpenKeyEx  QuickInfo  Overview  Group

The RegOpenKeyEx function opens the specified key.

LONG RegOpenKeyEx(

HKEY  hKey,	// handle of open key
LPCTSTR  lpszSubKey,	// address of name of subkey to open
DWORD  dwReserved,	// reserved
REGSAM  samDesired,	// security access mask
PHKEY  phkResult	// address of handle of open key
);
Parameters

hKey

Identifies a currently open key or any of the following predefined reserved handle values:

HKEY_CLASSES_ROOT
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS

lpszSubKey

Points to a null-terminated string containing the name of the subkey to open. If this parameter is NULL or a pointer to an empty string, the function will open a new handle of the key identified by the hKey parameter. In this case, the function will not close the handles previously opened.

dwReserved

Reserved; must be zero.

samDesired

Specifies an access mask that describes the desired security access for the new key. This parameter can be a combination of the following values:

Value	Meaning
KEY_ALL_ACCESS	Combination of KEY_QUERY_VALUE, KEY_ENUMERATE_SUB_KEYS, KEY_NOTIFY, KEY_CREATE_SUB_KEY, KEY_CREATE_LINK, and KEY_SET_VALUE access.
KEY_CREATE_LINK	Permission to create a symbolic link.
KEY_CREATE_SUB_KEY	Permission to create subkeys.
KEY_ENUMERATE_SUB_KEYS	Permission to enumerate subkeys.
KEY_EXECUTE	Permission for read access.
KEY_NOTIFY	Permission for change notification.
KEY_QUERY_VALUE	Permission to query subkey data.
KEY_READ	Combination of KEY_QUERY_VALUE, KEY_ENUMERATE_SUB_KEYS, and KEY_NOTIFY access.
KEY_SET_VALUE	Permission to set subkey data.
KEY_WRITE	Combination of KEY_SET_VALUE and KEY_CREATE_SUB_KEY access.
phkResult

Points to a variable that receives the handle of the opened key.

Return Value

If the function succeeds, the return value is ERROR_SUCCESS.

If the function fails, the return value is an error value.

Remarks

Unlike the RegCreateKeyEx function, the RegOpenKeyEx function does not create the specified key if the key does not exist in the registry.

See Also

RegCreateKeyEx, RegDeleteKey, RegOpenKey


RegQueryInfoKey
RegQueryInfoKey  QuickInfo  Overview  Group

The RegQueryInfoKey function retrieves information about a specified registry key.

LONG RegQueryInfoKey (

HKEY  hKey,	// handle of key to query
LPTSTR  lpszClass,	// address of buffer for class string
LPDWORD  lpcchClass,	// address of size of class string buffer
LPDWORD  lpdwReserved,	// reserved
LPDWORD  lpcSubKeys,	// address of buffer for number of subkeys
LPDWORD  lpcchMaxSubkey,	// address of buffer for longest subkey name length
LPDWORD  lpcchMaxClass,	// address of buffer for longest class string length
LPDWORD  lpcValues,	// address of buffer for number of value entries
LPDWORD  lpcchMaxValueName,	// address of buffer for longest value name length
LPDWORD  lpcbMaxValueData,	// address of buffer for longest value data length
LPDWORD  lpcbSecurityDescriptor,	// address of buffer for security descriptor length
PFILETIME  lpftLastWriteTime	// address of buffer for last write time
);
Parameters

hKey

Identifies a currently open key or any of the following predefined reserved handle values:

HKEY_CLASSES_ROOT
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS

lpszClass

Points to a buffer that receives the key's class name.

lpcchClass

Points to a variable that specifies the size, in characters, of the buffer pointed to by the lpszClass parameter. This size should include the terminating null character. When the function returns, this variable contains the length of the class string stored in the buffer. The count returned does not include the terminating null character. If the buffer is not big enough, the function returns ERROR_MORE_DATA, and the variable contains the size of the string, in characters, without counting the null character.

lpdwReserved

Reserved; must be NULL.

lpcSubKeys

Points to a variable that receives the number of subkeys contained by the specified key.

lpcchMaxSubkey

Points to a variable that receives the length, in characters, of the key's subkey with the longest name. The count returned does not include the terminating null character.

lpcchMaxClass

Points to a variable that receives the length, in characters, of the longest string specifying a subkey class. The count returned does not include the terminating null character.

lpcValues

Points to a variable that receives the number of values associated with the key.

lpcchMaxValueName

Points to a variable that receives the length, in characters, of the key's longest value name. The count returned does not include the terminating null character.

lpcbMaxValueData

Points to a variable that receives the length, in bytes, of the longest data component among the key's values.

lpcbSecurityDescriptor

Points to a variable that receives the length, in bytes, of the key's security descriptor.

lpftLastWriteTime

Points to a variable that receives a FILETIME structure, indicating the last time the key or any of its value entries was modified.

Return Value

If the function succeeds, the return value is ERROR_SUCCESS.

If the function fails, the return value is an error value.

Remarks

The key identified by the hKey parameter must have been opened with KEY_QUERY_VALUE access (KEY_READ access includes KEY_QUERY_VALUE access).

Windows 95: If the lpszClass parameter is a valid address, but the lpcchClass parameter is not (for example, it is NULL), the function returns ERROR_SUCCESS instead of ERROR_INVALID_PARAMETER. To ensure compatibility with other platforms, always verify that lpcchClass is valid before calling the function.

See Also

FILETIME, RegDeleteKey, RegEnumKey, RegEnumKeyEx, RegEnumValue, RegQueryValue, RegQueryValueEx


RegQueryMultipleValues
RegQueryMultipleValues  QuickInfo

The RegQueryMultipleValues function retrieves the type and data for a list of value names associated with an open registry key.

LONG RegQueryMultipleValues(

HKEY  hKey,	// handle of key to query
PVALENT  val_list,	// address of array of value entry structures
DWORD  num_vals,	// size of array of value entry structures
LPTSTR  lpValueBuf,	// address of buffer for value information
LPDWORD  ldwTotsize	// address of size of value buffer
);
Parameters

hKey

Identifies a currently open key or any of the pre-defined reserved handle values:

HKEY_CLASSES_ROOT
HEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS

val_list

Address of an array of VALENT structures that describe one or more value entries. When the function returns, val_list contains an element for each value entry. The VALENT structure has the following format:

typedef struct value_ent {  /* val */

    LPCTSTR  ve_valuename;

    DWORD    ve_valuelen;

    DWORD    ve_valueptr;

    DWORD    ve_type;

} RECT;

num_vals

Specifies the size, in bytes, of the array pointed to by the val_list parameter. If num_vals is not a multiple of the size of a VALENT structure, the extra space in the array is ignored. If the buffer pointed to by the val_list parameter is too small,the ldwTotsize parameter receives the required size, in bytes, and the buffer is filled to the size specified by num_vals when the function was called; extra bytes are ignored.

lpValueBuf

Pointer to a buffer that receives value names and data. The data in the buffer is doubleword-aligned; padding is inserted as necessary.

ldwTotsize

Pointer to a value that specifies the size of the output buffer pointed to by the lpValueBuf parameter. When the function returns, ldwTotsize contains the number of bytes copied to the buffer, including padding. If the buffer is too small, ldwTotsize receives the required size, in bytes, and the buffer is filled to the size specified by ldwTotsize.

Return Value

If the function succeeds, the return value is ERROR_SUCCESS..

If the function fails, the return value is is an error value that can include one of the following:

Value	Meaning
ERROR_INSUFFICIENT_BUFFER	The buffer pointed to by val_list or lpValueBuf was too small.
ERROR_CANTREAD	RegQueryMultipleValues cannot instantiate or access the provider of the dynamic key.
ERROR_TRANSFER_TOO_LONG	The total length of the requested data (num_vals + ldwTotSize) is more than the system limit of one megabyte. In this case, RegQueryMultipleValues returns only the first one megabyte of data.
Remarks

The RegQueryMultipleValues function allows an application to query one or more values of a static or dynamic key. If the target key is a static key, the system provides all of the values in an atomic fashion. To prevent excessive serialization, the aggregate data returned by the function can not exceed one megabyte.

If the target key is a dynamic key, its provider must provide all the values in an atomic fashion. This means the provider should fill the results buffer synchronously, providing a consistent view of all the values in the buffer while avoiding excessive serialization. The provider can provide at most one megabyte of total output data during an atomic call to this function.

RegQueryMultipleValues is supported remotely; that is, the hKey parameter passed to the function can refer to a remote computer.


RegQueryValue
RegQueryValue  QuickInfo  Overview  Group

The RegQueryValue function retrieves the value associated with the unnamed value for a specified key in the registry. Values in the registry have name, type, and data components. This function retrieves the data for a key's first value that has a NULL name. This function is provided for compatibility with Windows version 3.1. Win32-based applications should use the RegQueryValueEx function.

LONG RegQueryValue(

HKEY  hKey,	// handle of key to query
LPCTSTR  lpszSubKey,	// address of name of subkey to query
LPTSTR  lpszValue,	// address of buffer for returned string
PLONG  pcbValue	// address of buffer for size of returned string
);
Parameters

hKey

Identifies a currently open key or any of the following predefined reserved handle values:

HKEY_CLASSES_ROOT
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS

lpszSubKey

Points to a null-terminated string containing the name of the subkey of the hKey parameter for which a value is to be retrieved. If this parameter is NULL or points to an empty string, the function retrieves the value set by the RegSetValue function for the key identified by hKey.

lpszValue

Points to a buffer that receives the value associated with the lpszSubKey parameter. The buffer should be big enough to contain the terminating null character. This parameter can be NULL if the data is not required.

If lpszValue is NULL, and pcbValue is not NULL, the function places the size in bytes of the data referenced by the value key, including the terminating null character, into the variable pointed to by pcbValue. This lets an application determine how to best preallocate a buffer for the value key's data.

pcbValue

Points to a variable specifying the size, in bytes, of the buffer pointed to by the lpszValue parameter. When the function returns, this variable contains the size of the data copied to lpszValue, including the terminating null character.

If the buffer specified by lpszValue parameter is not large enough to hold the data, the function returns the value ERROR_MORE_DATA, and stores the required buffer size, in bytes, into the variable pointed to by pcbValue.

If lpszValue is NULL, the function returns ERROR_SUCCESS, and stores the size of the string, in bytes, into the variable pointed to by pcbValue. This lets an application determine the best way to allocate a buffer for the value key's data.

In all cases the value returned in pcbValue always includes the size of the terminating null character in the string.

Return Value

If the function succeeds, the return value is ERROR_SUCCESS.

If the function fails, the return value is an error value.

Remarks

The key identified by the hKey parameter must have been opened with KEY_QUERY_VALUE access (KEY_READ access includes KEY_QUERY_VALUE access).

If the ANSI version of this function is used (either by explicitly calling RegQueryValue or by not defining Unicode before including the WINDOWS.H file), this function converts the stored Unicode string to an ANSI string before copying it to the buffer specified by the lpszValue parameter.

See Also

RegEnumKey, RegEnumKeyEx, RegEnumValue, RegQueryInfoKey, RegQueryValueEx, RegSetValue, RegSetValueEx


RegQueryValueEx
RegQueryValueEx  QuickInfo  Overview  Group

The RegQueryValueEx function retrieves the type and data for a specified value name associated with an open registry key.

LONG RegQueryValueEx(

HKEY  hKey,	// handle of key to query
LPTSTR  lpszValueName,	// address of name of value to query
LPDWORD  lpdwReserved,	// reserved
LPDWORD  lpdwType,	// address of buffer for value type
LPBYTE  lpbData,	// address of data buffer
LPDWORD  lpcbData	// address of data buffer size
);
Parameters

hKey

Identifies a currently open key or any of the following predefined reserved handle values:

HKEY_CLASSES_ROOT
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS

lpszValueName

Points to a null-terminated string containing the name of the value to be queried.

lpdwReserved

Reserved; must be NULL.

lpdwType

Points to a variable that receives the key's value type. The value returned through this parameter will be one of the following:

Value	Meaning
REG_BINARY	Binary data in any form.
REG_DWORD	A 32-bit number.
REG_DWORD_LITTLE_ENDIAN	A 32-bit number in little-endian format (same as REG_DWORD). In little-endian format, the most significant byte of a word is the high-order word. This is the most common format for computers running Windows NT and Windows 95.
REG_DWORD_BIG_ENDIAN	A 32-bit number in big-endian format. In big-endian format, the most significant byte of a word is the low-order word.
REG_EXPAND_SZ	A null-terminated string that contains unexpanded references to environment variables (for example, "%PATH%"). It will be a Unicode or ANSI string depending on whether you use the Unicode or ANSI functions.
REG_LINK	A Unicode symbolic link.
REG_MULTI_SZ	An array of null-terminated strings, terminated by two null characters.
REG_NONE	No defined value type.
REG_RESOURCE_LIST	A device-driver resource list.
REG_SZ	A null-terminated string. It will be a Unicode or ANSI string depending on whether you use the Unicode or ANSI functions.
The lpdwType parameter can be NULL if the type is not required.

lpbData

Points to a buffer that receives the value's data. This parameter can be NULL if the data is not required.

lpcbData

Points to a variable that specifies the size, in bytes, of the buffer pointed to by the lpbData parameter. When the function returns, this variable contains the size of the data copied to lpbData.

If the buffer specified by lpbData parameter is not large enough to hold the data, the function returns the value ERROR_MORE_DATA, and stores the required buffer size, in bytes, into the variable pointed to by lpcbData.

If lpbData is NULL, and lpcbData is non-NULL, the function returns ERROR_SUCCESS, and stores the size of the data, in bytes, in the variable pointed to by lpcbData. This lets an application determine the best way to allocate a buffer for the value key's data.

If the data has the REG_SZ, REG_MULTI_SZ or REG_EXPAND_SZ type, then lpData will also include the size of the terminating null character.

The lpcbData parameter can be NULL only if lpbData is NULL.

Return Value

If the function succeeds, the return value is ERROR_SUCCESS.

If the function fails, the return value is an error value.

Remarks

The key identified by hKey must have been opened with KEY_QUERY_VALUE access. To open the key, use the RegCreateKeyEx or RegOpenKeyEx function.

This function does not expand the environment-variable names in the value data when the value type is REG_EXPAND_SZ. The ExpandEnvironmentStrings function can be used to expand the environment-variable names.

If the value data has the REG_SZ, REG_MULTI_SZ or REG_EXPAND_SZ type, and the ANSI version of this function is used (either by explicitly calling RegQueryValueEx or by not defining Unicode before including the WINDOWS.H file), this function converts the stored Unicode string to an ANSI string before copying it to the buffer pointed to by lpbData.

When calling the RegQueryValueEx function with hKey set to the HKEY_PERFORMANCE_DATA handle and a value string of a specified object, the returned data structure sometimes has unrequested objects. Don't be surprised; this is normal behavior. When calling the RegQueryValueEx function, you should always expect to walk the returned data structure to look for the requested object.

See Also

ExpandEnvironmentStrings, RegCreateKeyEx, RegEnumKey, RegEnumKeyEx, RegEnumValue, RegOpenKeyEx, RegQueryInfoKey, RegQueryValue


RegReplaceKey
RegReplaceKey  QuickInfo  Overview  Group

The RegReplaceKey function replaces the file backing a key and all its subkeys with another file, so that when the system is next started, the key and subkeys will have the values stored in the new file.

LONG RegReplaceKey(

HKEY  hKey,	// handle of open key
LPCTSTR  lpSubKey,	// address of name of subkey
LPCTSTR  lpNewFile,	// address of filename for file with new data
LPCTSTR  lpOldFile	// address of filename for backup file
);
Parameters

hKey

Identifies a currently open key or any of the following predefined reserved handle values:

HKEY_CLASSES_ROOT
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS

lpSubKey

Points to a null-terminated string containing the name of a key whose subkeys and values are replaced by this function. This key must be a subkey of the key identified by the hKey parameter. This parameter can be NULL.

The selected key must be the root of a hive; that is, it must be an immediate descendent of HKEY_LOCAL_MACHINE or HKEY_USERS.

lpNewFile

Points to a null-terminated string containing the name of the file with registration information. This file is typically created by using the RegSaveKey function. Under the file allocation table (FAT) file system, the filename may not have an extension.

lpOldFile

Points to a null-terminated string containing the name of a file that receives a backup copy of the registry information being replaced. If this file is created under the FAT file system, it should not have an extension.

Return Value

If the function succeeds, the return value is ERROR_SUCCESS.

If the function fails, the return value is an error value.

Remarks

The file specified by the lpNewFile parameter remains open until the system is restarted.

A process must have the SE_RESTORE_NAME privilege to call this function.

If hKey is a handle returned by RegConnectRegistry, then the paths specified in lpNewFile and lpOldFile are relative to the remote computer.

See Also

RegConnectRegistry, RegDeleteKey, RegLoadKey, RegRestoreKey


RegRestoreKey
RegRestoreKey  QuickInfo  Overview  Group

The RegRestoreKey function reads the registry information in a specified file and copies it over the specified key. This registry information may be in the form of a key and multiple levels of subkeys.

LONG RegRestoreKey(

HKEY  hKey,	// handle of key where restore begins
LPCTSTR  lpszFile,	// address of filename containing saved tree
DWORD  fdw	// optional flags
);
Parameters

hKey

Identifies a currently open key or any of the following predefined reserved handle values:

HKEY_CLASSES_ROOT
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS

Any information contained in this key and its descendent keys is overwritten by the information in the file pointed to by the lpszFile parameter.

lpszFile

Points to a null-terminated string containing the name of the file with registry information. This file is typically created by using the RegSaveKey function. Under the file allocation table (FAT) file system, the filename may not have an extension.

fdw

Specifies a flag indicating whether the key is volatile. (A volatile key is valid only until the next time the system is started.) This parameter is optional; if no value is specified, the key is not volatile.

This parameter can be the REG_WHOLE_HIVE_VOLATILE flag set. Instead of restoring the given key, this flag causes a new, volatile (memory only) set of registry information to be created. (A hive is a large set of registry information, typically containing all of the pertinent information for part of the system. For example, HKEY_LOCAL_MACHINE\Hardware is a volatile hive.)

If REG_WHOLE_HIVE_VOLATILE is specified, the key identified by the hKey parameter must be either the HKEY_USERS or HKEY_LOCAL_MACHINE value.

Return Value

If the function succeeds, the return value is ERROR_SUCCESS.

If the function fails, the return value is an error value.

Remarks

If the calling process does not have the SE_RESTORE_NAME privilege or if any subkeys of the hKey parameter are open, RegRestoreKey fails.

This function replaces the keys and values below the specified key with the keys and values that are subsidiary to the top-level key in the file, no matter what the name of the top-level key in the file might be. For example, hKey might identify a key A with subkeys B and C, while the lpszFile parameter specifies a file containing key X with subkeys Y and Z. After a call to RegRestoreKey, the registry would contain key A with subkeys Y and Z. The value entries of A would be replaced by the value entries of X.

The new information in the file specified by lpszFile overwrites the contents of the key specified by the hKey parameter, except for the key name.

If hKey represents a key in a remote computer, the path described by lpszFile is relative to the remote computer.

See Also

RegDeleteKey, RegLoadKey, RegReplaceKey, RegSaveKey


RegSaveKey
RegSaveKey  QuickInfo  Overview  Group

The RegSaveKey function saves the specified key and all of its subkeys and values to a new file.

LONG RegSaveKey(

HKEY  hKey,	// handle of key where save begins
LPCTSTR  lpszFile,	// address of filename to save to
LPSECURITY_ATTRIBUTES  lpsa	// address of security structure
);
Parameters

hKey

Specifies a handle of the key where the save operation is to begin, or any of the following predefined reserved handle values:

HKEY_CLASSES_ROOT
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS

lpszFile

Points to a null-terminated string containing the name of the file in which the specified key and subkeys are saved. This file cannot already exist. If this filename includes an extension, it cannot be used on file allocation table (FAT) file systems by the RegLoadKey, RegReplaceKey, or RegRestoreKey function.

lpsa

Points to a SECURITY_ATTRIBUTES structure for the new file. If this parameter is NULL, the file receives a default security descriptor.

Return Value

If the function succeeds, the return value is ERROR_SUCCESS.

If the function fails, the return value is an error value.

Remarks

If hKey represents a key on a remote computer, the path described by lpszFile is relative to the remote computer.

The caller of this function must possess the SeBackupPrivilege security privilege.

The RegSaveKey function saves only nonvolatile keys. It does not save volatile keys. A key is made volatile or nonvolatile at its creation; see RegCreateKeyEx.

See Also

RegCreateKeyEx, RegDeleteKey, RegLoadKey, RegReplaceKey, RegRestoreKey, SECURITY_ATTRIBUTES


RegSetKeySecurity
RegSetKeySecurity  QuickInfo  Overview  Group

The RegSetKeySecurity function sets the security of an open registry key.

LONG RegSetKeySecurity(

HKEY  hKey,	// open handle of key to set
SECURITY_INFORMATION  si,	// descriptor contents
PSECURITY_DESCRIPTOR  psd	// address of descriptor for key
);
Parameters

hKey

Identifies an open key for which the security descriptor is set.

si

Specifies a SECURITY_INFORMATION structure that indicates the contents of the supplied security descriptor.

Because subkeys are not ordered, any new subkey will have an arbitrary index. This means the function may return subkeys in any order.

psd

Points to a SECURITY_DESCRIPTOR structure that specifies the security attributes to set for the specified key.

Return Value

If the function succeeds, the return value is ERROR_SUCCESS.

If the function fails, the return value is an error value.

Remarks

This function succeeds only if the following conditions are met:

•	If the key's owner or group is being set, the caller must have WRITE_OWNER permission or have the SE_TAKE_OWNERSHIP_NAME privilege.

•	If the key's discretionary access-control list (DACL) is being set, the caller must have WRITE_DAC permission or be the object's owner.

•	If the key's system access-control list (SACL) is being set, the caller must have the SE_SECURITY_NAME privilege.

If hKey is one of the predefined keys, the predefined key should be closed with RegCloseKey. That ensures that the new security information is in effect the next time the predefined key is referenced.

See Also

RegCloseKey, RegDeleteKey, RegGetKeySecurity, SECURITY_INFORMATION


RegSetValue
RegSetValue  QuickInfo  Overview  Group

The RegSetValue function associates a value with a specified key. This value must be a text string and cannot have a name. This function is provided for compatibility with Windows version 3.1. Win32-based applications should use the RegSetValueEx function, which allows an application to set any number of named values of any data type.

LONG RegSetValue(

HKEY  hKey,	// handle of key to set value for
LPCTSTR  lpSubKey,	// address of subkey name
DWORD  dwType,	// type of value
LPCTSTR  lpData,	// address of value data
DWORD  cbData	// size of value data
);
Parameters

hKey

Identifies a currently open key or any of the following predefined reserved handle values:

HKEY_CLASSES_ROOT
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS

lpSubKey

Points to a null-terminated string containing the name of the subkey with which a value is associated. This parameter can be null or a pointer to an empty string. In this case, the value will be added to the key identified by the hKey parameter.

dwType

Specifies the type of information to be stored. This parameter must be the REG_SZ type. To store other data types, use the RegSetValueEx function.

lpData

Points to a null-terminated string containing the value to set for the specified key.

cbData

Specifies the length, in characters, of the string pointed to by the lpData parameter, not including the terminating null character.

Return Value

If the function succeeds, the return value is ERROR_SUCCESS.

If the function fails, the return value is an error value.

Remarks

If the key specified by the lpSubKey parameter does not exist, the RegSetValue function creates it.

Value lengths are limited by available memory. Long values (more than 2048 bytes) should be stored as files with the filenames stored in the registry. This helps the registry perform efficiently.

The key identified by the hKey parameter must have been opened with KEY_SET_VALUE access. To open the key, use the RegCreateKeyEx or RegOpenKeyEx function. If the ANSI version of this function is used (either by explicitly calling RegSetValue or by not defining Unicode before including the WINDOWS.H file), the lpData parameter must be an ANSI character string. The string is converted to Unicode before it is stored in the registry.

See Also

RegCreateKeyEx, RegFlushKey, RegOpenKeyEx, RegQueryValue, RegQueryValueEx, RegSetValueEx


RegSetValueEx
RegSetValueEx  QuickInfo  Overview  Group

The RegSetValueEx function stores data in the value field of an open registry key. It can also set additional value and type information for the specified key.

LONG RegSetValueEx(

HKEY  hKey,	// handle of key to set value for
LPCTSTR  lpValueName,	// address of value to set
DWORD  Reserved,	// reserved
DWORD  dwType,	// flag for value type
CONST BYTE *  lpData,	// address of value data
DWORD  cbData	// size of value data
);
Parameters

hKey

Identifies a currently open key or any of the following predefined reserved handle values:

HKEY_CLASSES_ROOT
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS

lpValueName

Points to a string containing the name of the value to set. If a value with this name is not already present in the key, the function adds it to the key.

If this parameter is NULL or points to an empty string and the dwType parameter is the REG_SZ type, this function sets the same value the RegSetValue function would set.

Reserved

Reserved; must be zero.

dwType

Specifies the type of information to be stored as the value's data. This parameter can be one of the following values:

Value	Meaning
REG_BINARY	Binary data in any form.
REG_DWORD	A 32-bit number.
REG_DWORD_LITTLE_ENDIAN	A 32-bit number in little-endian format (same as REG_DWORD). In little-endian format, the most significant byte of a word is the high-order word. This is the most common format for computers running Windows NT and Windows 95.
REG_DWORD_BIG_ENDIAN	A 32-bit number in big-endian format. In big-endian format, the most significant byte of a word is the low-order word.
REG_EXPAND_SZ	A null-terminated string that contains unexpanded references to environment variables (for example, "%PATH%"). It will be a Unicode or ANSI string depending on whether you use the Unicode or ANSI functions.
REG_LINK	A Unicode symbolic link.
REG_MULTI_SZ	An array of null-terminated strings, terminated by two null characters.
REG_NONE	No defined value type.
REG_RESOURCE_LIST	A device-driver resource list.
REG_SZ	A null-terminated string. It will be a Unicode or ANSI string depending on whether you use the Unicode or ANSI functions.
lpData

Points to a buffer containing the data to be stored with the specified value name.

cbData

Specifies the size, in bytes, of the information pointed to by the lpData parameter. If the data is of type REG_SZ, REG_EXPAND_SZ, or REG_MULTI_SZ, cbData must include the size of the terminating null character.

Return Value

If the function succeeds, the return value is ERROR_SUCCESS.

If the function fails, the return value is an error value.

Remarks

Value lengths are limited by available memory. Long values (more than 2048 bytes) should be stored as files with the filenames stored in the registry. This helps the registry perform efficiently. Application elements such as icons, bitmaps, and executable files should be stored as files and not be placed in the registry.

The key identified by the hKey parameter must have been opened with KEY_SET_VALUE access. To open the key, use the RegCreateKeyEx or RegOpenKeyEx function.

If dwType is the REG_SZ, REG_MULTI_SZ or REG_EXPAND_SZ type and the ANSI version of this function is used (either by explicitly calling RegSetValueEx or by not defining Unicode before including the WINDOWS.H file), the data pointed to by the lpData parameter must be an ANSI character string. The string is converted to Unicode before it is stored in the registry.

See Also

RegCreateKeyEx, RegFlushKey, RegOpenKeyEx, RegQueryValue, RegQueryValueEx, RegSetValue


RegUnLoadKey
RegUnLoadKey  QuickInfo  Overview  Group

The RegUnLoadKey function unloads the specified key and subkeys from the registry.

LONG RegUnLoadKey(

HKEY  hKey,	// handle of open key
LPCTSTR  lpszSubKey	// address of name of subkey to unload
);
Parameters

hKey

Specifies the key to be unloaded. This can be a predefined reserved handle value, or a handle returned by a call to RegConnectRegistry. The predefined reserved handle values are:

HKEY_LOCAL_MACHINE
HKEY_USERS

lpszSubKey

Points to a null-terminated string containing the name of the subkey to be unloaded. The key referred to by the lpszSubKey parameter must have been created by using the RegLoadKey function.

Return Value

If the function succeeds, the return value is ERROR_SUCCESS.

If the function fails, the return value is an error value.

Remarks

This function removes a hive from the registry but does not modify the file containing the registry information. A hive is a discrete body of keys, subkeys, and values that is rooted at the top of the registry hierarchy.

Windows NT only: The calling process must have the SE_RESTORE_NAME privilege. For more information about privileges, see Security.

See Also

RegConnectRegistry, RegDeleteKey, RegLoadKey, RegRestoreKey


ReleaseCapture
ReleaseCapture  QuickInfo  Overview  Group

The ReleaseCapture function releases the mouse capture from a window in the current thread and restores normal mouse input processing. A window that has captured the mouse receives all mouse input, regardless of the position of the cursor, except when a mouse button is clicked while the cursor hot spot is in the window of another thread.

BOOL ReleaseCapture(VOID)

Parameters

This function has no parameters.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

An application calls this function after calling the SetCapture function.

Windows 95 only: Calling this function causes the window that is losing the mouse capture to receive a WM_CAPTURECHANGED message.

See Also

GetCapture, SetCapture


ReleaseDC
ReleaseDC  QuickInfo  Overview  Group

The ReleaseDC function releases a device context (DC), freeing it for use by other applications. The effect of the ReleaseDC function depends on the type of device context. It frees only common and window device contexts. It has no effect on class or private device contexts.

int ReleaseDC(

HWND  hwnd,	// handle of window
HDC  hdc	// handle of device context
);
Parameters

hwnd

Identifies the window whose device context is to be released.

hdc

Identifies the device context to be released.

Return Value

The return value specifies whether the device context is released. If the device context is released, the return value is 1.

If the device context is not released, the return value is zero.

Remarks

The application must call the ReleaseDC function for each call to the GetWindowDC function and for each call to the GetDC function that retrieves a common device context.

An application cannot use the ReleaseDC function to release a device context that was created by calling the CreateDC function; instead, it must use the DeleteDC function.

See Also

CreateDC, DeleteDC, GetDC, GetWindowDC


ReleaseMutex
ReleaseMutex  QuickInfo  Overview  Group

The ReleaseMutex function releases ownership of the specified mutex object.

BOOL ReleaseMutex(

HANDLE  hMutex	// handle of mutex object
);
Parameters

hMutex

Identifies the mutex object. The CreateMutex or OpenMutex function returns this handle.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The ReleaseMutex function fails if the calling thread does not own the mutex object.

A thread gets ownership of a mutex by specifying a handle of the mutex in one of the wait functions. The thread that creates a mutex object can also get immediate ownership without using one of the wait functions. When the owning thread no longer needs to own the mutex object, it calls the ReleaseMutex function.

While a thread has ownership of a mutex, it can specify the same mutex in additional wait-function calls without blocking its execution. This prevents a thread from deadlocking itself while waiting for a mutex that it already owns. However, to release its ownership, the thread must call ReleaseMutex once for each time that the mutex satisfied a wait.

See Also

CreateMutex, WaitForMultipleObjects, WaitForMultipleObjectsEx, WaitForSingleObject, WaitForSingleObjectEx


ReleaseSemaphore
ReleaseSemaphore  QuickInfo  Overview  Group

The ReleaseSemaphore function increases the count of the specified semaphore object by a specified amount.

BOOL ReleaseSemaphore(

HANDLE  hSemaphore,	// handle of the semaphore object
LONG  cReleaseCount,	// amount to add to current count
LPLONG  lplPreviousCount	// address of previous count
);
Parameters

hSemaphore

Identifies the semaphore object. The CreateSemaphore or OpenSemaphore function returns this handle, which must have SEMAPHORE_MODIFY_STATE access.

cReleaseCount

Specifies the amount by which the semaphore object's current count is to be increased. The value must be greater than zero. If the specified amount would cause the semaphore's count to exceed the maximum count that was specified when the semaphore was created, the count is not changed and the function returns FALSE.

lplPreviousCount

Points to a 32-bit variable to receive the previous count for the semaphore. This parameter can be NULL if the previous count is not required.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The state of a semaphore object is signaled when its count is greater than zero and nonsignaled when its count is equal to zero. The process that calls the CreateSemaphore function specifies the semaphore's initial count. Each time a waiting thread is released because of the semaphore's signaled state, the count of the semaphore is decreased by one.

Typically, an application uses a semaphore to limit the number of threads using a resource. Before a thread uses the resource, it specifies the semaphore handle in a call to one of the wait functions. When the wait function returns, it decreases the semaphore's count by one. When the thread has finished using the resource, it calls ReleaseSemaphore to increase the semaphore's count by one.

Another use of ReleaseSemaphore is during an application's initialization. The application can create a semaphore with an initial count of zero. This sets the semaphore's state to nonsignaled and blocks all threads from accessing the protected resource. When the application finishes its initialization, it uses ReleaseSemaphore to increase the count to its maximum value, to permit normal access to the protected resource.

See Also

CreateSemaphore, MsgWaitForMultipleObjects, OpenSemaphore, WaitForMultipleObjects, WaitForMultipleObjectsEx, WaitForSingleObject, WaitForSingleObjectEx


RemoveDirectory
RemoveDirectory  QuickInfo  Overview  Group

The RemoveDirectory function deletes an existing empty directory.

BOOL RemoveDirectory(

LPCTSTR  lpszDir	// address of directory to remove
);
Parameters

lpszDir

Points to a null-terminated string that specifies the path of the directory to be removed. The path must specify an empty directory, and the calling process must have delete access to the directory.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

CreateDirectory


RemoveFontResource
RemoveFontResource  QuickInfo  Overview  Group

The RemoveFontResource function removes the fonts in the specified file from the Windows font table.

BOOL RemoveFontResource(

LPCTSTR  lpFileName	// address of font-resource filename
);
Parameters

lpFileName

Points to a null-terminated string that names a font resource file.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

An application that adds or removes fonts from the Windows public font table should notify other windows of the change by sending a WM_FONTCHANGE message to all top-level windows in the system. The application sends this message by calling the SendMessage function with the hwnd parameter set to HWND_BROADCAST.

If there are outstanding references to a font, the associated resource remains loaded until no device context is using it.

See Also

AddFontResource, SendMessage


RemoveMenu
RemoveMenu  QuickInfo  Overview  Group

The RemoveMenu function deletes a menu item from the specified menu. If the menu item activates a pop-up menu, RemoveMenu does not destroy the pop-up menu or its handle, allowing the menu to be reused. Before this function is called, the GetSubMenu function should retrieve the handle of the pop-up menu.

BOOL RemoveMenu(

HMENU  hmenu,	// handle of menu
UINT  uItem,	// menu item identifier or position
UINT  fuFlags	// menu item flag
);
Parameters

hmenu

Identifies the menu to be changed.

uItem

Specifies the menu item to be deleted, as determined by the fuFlags parameter.

fuFlags

Specifies how the uItem parameter is interpreted. This parameter must be one of the following values:

Value	Meaning
MF_BYCOMMAND	Indicates that uItem gives the identifier of the menu item. If neither the MF_BYCOMMAND nor MF_BYPOSITION flag is specified, the MF_BYCOMMAND flag is the default flag.
MF_BYPOSITION	Indicates that uItem gives the zero-based relative position of the menu item.
Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The application must call the DrawMenuBar function whenever a menu changes, whether or not the menu is in a displayed window.

See Also

CreatePopupMenu, DeleteMenu, DrawMenuBar, GetSubMenu


RemoveProp
RemoveProp  QuickInfo  Overview  Group

The RemoveProp function removes an entry from the property list of the specified window. The specified character string identifies the entry to be removed.

HANDLE RemoveProp(

HWND  hwnd,	// handle of window
LPCTSTR  lpsz	// atom or address of string
);
Parameters

hwnd

Identifies the window whose property list is to be changed.

lpsz

Points to a null-terminated character string or contains an atom that identifies a string. If this parameter is an atom, it must have been created using the AddAtom function. The atom, a 16-bit value, must be placed in the low-order word of lpsz; the high-order word must be zero.

Return Value

If the function succeeds, the return value identifies the specified string. If the string cannot be found in the specified property list, the return value is NULL.

Remarks

An application must free the data handles associated with entries removed from a property list. The application can remove only those properties it has added. It must not remove properties added by other applications or by Windows itself.

The RemoveProp function returns the data handle associated with the string so that the application can free the data associated with the handle.

See Also

AddAtom, EnumProps, EnumPropsEx, GetProp, SetProp


ReplaceText
ReplaceText  QuickInfo  Overview  Group

The ReplaceText function creates a system-defined modeless dialog box that enables the user to find and replace text within a document.

HWND ReplaceText(

LPFINDREPLACE  lpfr	// address of structure with initialization data
);
Parameters

lpfr

Points to a FINDREPLACE structure that contains information used to initialize the dialog box. When the user makes a selection in the dialog box, the system fills this structure with information about the user's selection and then sends a message to the application. This message contains a pointer to the FINDREPLACE structure.

Return Value

If the function succeeds, the return value is the window handle of the dialog box. It is NULL if an error occurs.

The CommDlgExtendedError function can be used to get extended error information, which may be one of the following values:

CDERR_FINDRESFAILURE	CDERR_MEMLOCKFAILURE
CDERR_INITIALIZATION	CDERR_NOHINSTANCE
CDERR_LOADRESFAILURE	CDERR_NOHOOK
CDERR_LOADSTRFAILURE	CDERR_NOTEMPLATE
CDERR_LOCKRESFAILURE	CDERR_STRUCTSIZE
CDERR_MEMALLOCFAILURE	FRERR_BUFFERLENGTHZERO
Remarks

ReplaceText does not perform a text replacement operation; it simply returns a string typed by the user (as well as related data). An application must perform the replacement using this string.

An application can use the window handle returned by the function to communicate with or to close the dialog box.

The dialog box procedure for ReplaceText passes user requests to the application by sending special messages. The lParam parameter of each of these messages contains a pointer to a FINDREPLACE structure. The procedure sends the messages to the window identified by the hwndOwner member of the FINDREPLACE structure. An application can register the identifier for these messages by specifying the "commdlg_FindReplace" string in a call to the RegisterWindowMessage function.

For the TAB key to function correctly, any application that calls ReplaceText must also call the IsDialogMessage function in its main message loop. IsDialogMessage returns a value that indicates whether messages are intended for the Replace dialog box.

See Also

CommDlgExtendedError, FINDREPLACE, IsDialogMessage, RegisterWindowMessage, WM_CTLCOLORDLG


ReplyMessage
ReplyMessage  QuickInfo  Overview  Group

The ReplyMessage function is used to reply to a message sent through the SendMessage function without returning control to the function that called SendMessage.

BOOL ReplyMessage(

LRESULT  lResult	// message-specific reply
);
Parameters

lResult

Specifies the result of the message processing. The possible values are based on the message sent.

Return Value

If the calling thread was processing a message sent from another thread or process, the return value is TRUE; otherwise, it is FALSE.

Remarks

By calling this function, the window procedure that receives the message allows the thread that called SendMessage to continue to run as though the thread receiving the message had returned control. The thread that calls the ReplyMessage function also continues to run.

If the message was not sent through SendMessage or if the message was sent by the same thread, ReplyMessage has no effect.

See Also

InSendMessage, SendMessage


ReportEvent
ReportEvent  QuickInfo  Overview  Group

The ReportEvent function writes an entry at the end of the specified event log.

BOOL ReportEvent(

HANDLE  hEventSource,	// handle returned by RegisterEventSource
WORD  fwEventType,	// event type to log
WORD  fwCategory,	// event category
DWORD  IDEvent,	// event identifier
PSID  pUserSid,	// user security identifier (optional)
WORD  cStrings,	// number of strings to merge with message
DWORD  cbData,	// size of binary data, in bytes
LPCTSTR  *plpszStrings,	// array of strings to merge with message
LPVOID  lpvData	// address of binary data
);
Parameters

hEventSource

Identifies the event log. This handle is returned by the RegisterEventSource function.

fwEventType

Specifies the type of event being logged. This parameter can be one of the following values:

Value	Meaning
EVENTLOG_ERROR_TYPE	Error event
EVENTLOG_WARNING_TYPE	Warning event
EVENTLOG_INFORMATION_TYPE	Information event
EVENTLOG_AUDIT_SUCCESS	Success Audit event
EVENTLOG_AUDIT_FAILURE	Failure Audit event
For more information about event types, see Event Logging.

fwCategory

Specifies the event category. This is source-specific information; the category can have any value.

IDEvent

Specifies the event identifier. The event identifier specifies the message that goes with this event as an entry in the message file associated with the event source.

pUserSid

Points to the current user's security identifier. This parameter can be NULL if the security identifier is not required.

cStrings

Specifies the number of strings in the array pointed to by the plpszStrings parameter. A value of zero indicates that no strings are present.

cbData

Specifies the number of bytes of event-specific raw (binary) data to write to the log. If this parameter is zero, no event-specific data is present.

plpszStrings

Points to a buffer containing an array of null-terminated strings that are merged into the message before Event Viewer displays the string to the user. This parameter must be a valid pointer (or NULL), even if cStrings is zero.

lpvData

Points to the buffer containing the binary data. This parameter must be a valid pointer (or NULL), even if the cbData parameter is zero.

Return Value

If the function succeeds, the return value is TRUE, indicating that the entry was written to the log.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

This function is used to log an event. The entry is written to the end of the configured logfile for the source identified by the hEventSource parameter. The ReportEvent function adds the time, the user name, the entry's length, and the offsets before storing the entry in the log.

See Also

ClearEventLog, CloseEventLog, OpenEventLog, ReadEventLog, RegisterEventSource


ResetDC
ResetDC  QuickInfo  Overview  Group

The ResetDC function updates the given printer or plotter device context, based on the information in the specified structure.

HDC ResetDC(

HDC  hdc,	// handle of device context
CONST DEVMODE *  lpInitData	// address of structure with device context information
);
Parameters

hdc

Identifies the device context to update.

lpInitData

Points to a DEVMODE structure containing information about the new device context.

Return Value

If the function succeeds, the return value is the handle of the original device context.

If the function fails, the return value is NULL.

Remarks

An application will typically use the ResetDC function when a window receives a WM_DEVMODECHANGE message. ResetDC can also be used to change the paper orientation or paper bins while printing a document.

The ResetDC function cannot be used to change the driver name, device name, or the output port. When the user changes the port connection or device name, the application must delete the original device context and create a new device context with the new information.

An application can pass an information device context to the ResetDC function. In that situation, ResetDC will always return a printer device context.

See Also

DeviceCapabilities, DEVMODE, Escape


ResetDisplay [New - Windows 95]
ResetDisplay  QuickInfo  Overview  Group

[New - Windows 95]

The ResetDisplay function informs the system that the display resolution is to be changed. A Control Panel application calls this function after updating the registry.

BOOL API ResetDisplay(VOID)

Parameters

This function has no parameters.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

This function does the following:

1.	Broadcasts a WM_DISPLAYCHANGE message, with wParam = FALSE, indicating the display resolution is about to change.

2.	Changes the display resolution and updates various internal variables.

3.	Moves windows and icons that are no longer visible, if any.

4.	Invalidates the entire desktop to force a repainting.

5.	Broadcasts a WM_DISPLAYCHANGE message, with wParam = TRUE, indicating that the display resolution has changed.

The logical dots per inch and number of colors do not change.

See Also

WM_DISPLAYCHANGE


ResetEvent
ResetEvent  QuickInfo  Overview  Group

The ResetEvent function sets the state of the specified event object to nonsignaled.

BOOL ResetEvent(

HANDLE  hEvent	// handle of event object
);
Parameters

hEvent

Identifies the event object. The CreateEvent or OpenEvent function returns this handle, which must have EVENT_MODIFY_STATE access.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The state of an event object remains nonsignaled until it is explicitly set to signaled by the SetEvent or PulseEvent function. This nonsignaled state blocks the execution of any threads that have specified the event object in a call to one of the wait functions.

The ResetEvent function is used primarily for manual-reset event objects, which must be set explicitly to the nonsignaled state. Auto-reset event objects automatically change from signaled to nonsignaled after a single waiting thread is released.

See Also

CreateEvent, OpenEvent, PulseEvent, SetEvent


ResetPrinter
ResetPrinter  QuickInfo  Overview  Group

The ResetPrinter function lets an application specify the data type and device mode values that are used for printing documents submitted by the StartDocPrinter function. These values can be overridden by using the SetJob function once document printing has started.

BOOL ResetPrinter (

HANDLE  hPrinter,	// printer handle
LPPRINTER_DEFAULTS  pDefault	// address of printer defaults structure
);
Parameters

hPrinter

Identifies a printer.

pDefault

Points to a PRINTER_DEFAULTS structure.

The ResetPrinter function ignores the DesiredAccess member of the PRINTER_DEFAULTS structure. Set that member to zero.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

OpenPrinter, PRINTER_DEFAULTS, StartDocPrinter, SetJob


ResizePalette
ResizePalette  QuickInfo  Overview  Group

The ResizePalette function increases or decreases the size of a logical palette based on the specified value.

BOOL ResizePalette(

HPALETTE  hpal	// handle of logical palette
UINT  nEntries,	// number of entries in logical palette
);
Parameters

hpal

Identifies the palette to be changed.

nEntries

Specifies the number of entries in the palette after it has been resized.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

An application can determine whether a device supports palette operations by calling the GetDeviceCaps function and specifying the RASTERCAPS constant.

If an application calls ResizePalette to reduce the size of the palette, the entries remaining in the resized palette are unchanged. If the application calls ResizePalette to enlarge the palette, the additional palette entries are set to black (the red, green, and blue values are all 0) and their flags are set to zero.

See Also

GetDeviceCaps


RestoreDC
RestoreDC  QuickInfo  Overview  Group

The RestoreDC function restores a device context (DC) to the specified state. The device context is restored by popping state information off a stack created by earlier calls to the SaveDC function.

BOOL RestoreDC(

HDC  hdc,	// handle of device context
int  nSavedDC	// specifies state to be restored
);
Parameters

hdc

Identifies the device context.

nSavedDC

Specifies the instance of the device context to be restored. If this parameter is positive, nSavedDC represents a specific instance of the device context to be restored. If this parameter is negative, nSavedDC represents an instance relative to the current device context. For example, −1 restores the most recently saved state.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

The stack can contain the state information for several instances of the device context. If the state specified by the given parameter is not at the top of the stack, RestoreDC deletes all state information between the top of the stack and the specified instance.

See Also

SaveDC


ResumeThread
ResumeThread  QuickInfo  Overview  Group

The ResumeThread function decrements a thread's suspend count. When the suspend count is decremented to zero, the execution of the thread is resumed.

DWORD ResumeThread(

HANDLE  hThread	// identifies thread to restart
);
Parameters

hThread

Specifies a handle for the thread to be restarted. The handle must have THREAD_SUSPEND_RESUME access to the thread.

Return Value

If the function succeeds, the return value is the thread's previous suspend count.

If the function fails, the return value is 0xFFFFFFFF. To get extended error information, call GetLastError.

Remarks

The ResumeThread function checks the suspend count of the subject thread. If the suspend count is 0, the thread is not currently suspended. Otherwise, the subject thread's suspend count is decremented. If the resulting value is 0, then the execution of the subject thread is resumed.

If the return value is 0, the specified thread was not suspended. If the return value is 1, the specified thread was suspended but was restarted. If the return value is greater than 1, the specified thread is still suspended.

Note that while reporting debug events, all threads within the reporting process are frozen. Debuggers are expected to use the SuspendThread and ResumeThread functions to limit the set of threads that can execute within a process. By suspending all threads in a process except for the one reporting a debug event, it is possible to "single step" a single thread. The other threads are not released by a continue operation if they are suspended.

See Also

SuspendThread


ReuseDDElParam
ReuseDDElParam  QuickInfo  Overview  Group

The ReuseDDElParam function allows an application to reuse a packed DDE lParam parameter, rather than allocating a new packed lParam. Using this function reduces reallocations for applications that pass packed DDE messages.

LONG ReuseDDElParam(

LONG  lParam,	// posted lParam to be reused
UINT  uMsgIn,	// identifier of received message
UINT  uMsgOut,	// identifier of posted message
UINT  uLow,	// low-order word of new lParam
UINT  uHigh	// high-order word of new lParam
);
Parameters

lParam

Specifies the lParam parameter of the posted DDE message being reused.

uMsgIn

Specifies the identifier of the received DDE message.

uMsgOut

Specifies the identifier of the DDE message to be posted. The DDE message will reuse the packed lParam parameter.

uLow

Specifies the value to be packed into the low-order word of the reused lParam parameter.

uHigh

Specifies the value to be packed into the high-order word of the reused lParam parameter.

Return Value

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero.

Remarks

The return value must be posted as the lParam parameter of a DDE message; it must not be used for any other purpose. Once the return value is posted, the posting application need not perform any action to dispose of the lParam parameter.

Use ReuseDDElParam instead of FreeDDElParam if the lParam parameter will be reused in a responding message. ReuseDDElParam returns the lParam appropriate for reuse.

This function allocates or frees lParam parameters as needed, depending on the packing requirements of the incoming and outgoing messages. This reduces reallocations in passing DDE messages.

See Also

FreeDDElParam, PackDDElParam, UnpackDDElParam


RevertToSelf
RevertToSelf  QuickInfo  Overview  Group

The RevertToSelf function terminates the impersonation of a client application.

BOOL RevertToSelf(VOID)

Parameters

This function has no parameters.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

It is advisable for a process to call the RevertToSelf function after finishing any impersonation begun by using the DdeImpersonateClient, ImpersonateNamedPipeClient, or ImpersonateSelf function.

See Also

DdeImpersonateClient, ImpersonateNamedPipeClient, ImpersonateSelf


RoundRect
RoundRect  QuickInfo  Overview  Group

The RoundRect function draws a rectangle with rounded corners. The rectangle is outlined by using the current pen and filled by using the current brush.

BOOL RoundRect(

HDC  hdc,	// handle of device context
int  nLeftRect,	// x-coord. of bounding rectangle's upper-left corner
int  nTopRect,	// y-coord. of bounding rectangle's upper-left corner
int  nRightRect,	// x-coord. of bounding rectangle's lower-right corner
int  nBottomRect,	// y-coord. of bounding rectangle's lower-right corner
int  nWidth,	// width of ellipse used to draw rounded corners
int  nHeight	// height of ellipse used to draw rounded corners
);
Parameters

hdc

Identifies the device context.

nLeftRect

Specifies the x-coordinate of the upper-left corner of the rectangle.

nTopRect

Specifies the y-coordinate of the upper-left corner of the rectangle.

nRightRect

Specifies the x-coordinate of the lower-right corner of the rectangle.

nBottomRect

Specifies the y-coordinate of the lower-right corner of the rectangle.

nWidth

Specifies the width of the ellipse used to draw the rounded corners.

nHeight

Specifies the height of the ellipse used to draw the rounded corners.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The current position is neither used nor updated by this function.

Windows 95 only: The sum of the coordinates of the bounding rectangle cannot exceed 32,767. The sum of nLeftRect and nRightRect or nTopRect and nBottomRect parameters cannot exceed 32,767.

See Also

Rectangle


SaveDC
SaveDC  QuickInfo  Overview  Group

The SaveDC function saves the current state of the specified device context (DC) by copying data describing selected objects and graphic modes (such as the bitmap, brush, palette, font, pen, region, drawing mode, and mapping mode) to a context stack.

int SaveDC(

HDC  hdc	// handle of device context
);
Parameters

hdc

Identifies the device context to be saved.

Return Value

If the function succeeds, the return value identifies the saved device context.

If the function fails, the return value is zero.

Remarks

The SaveDC function can be used any number of times to save any number of instances of the device context's state.

A saved state can later be restored by using the RestoreDC function.

See Also

RestoreDC


ScaleViewportExt

The ScaleViewportExt function is not implemented in the Win32 API. Win32-based applications should use the ScaleViewportExtEx function.


ScaleViewportExtEx
ScaleViewportExtEx  QuickInfo  Overview  Group

The ScaleViewportExtEx function modifies the viewport for a device context (DC) by using the ratios formed by the specified multiplicands and divisors.

BOOL ScaleViewportExtEx(

HDC  hdc,	// handle of device context
int  Xnum,	// horizontal multiplicand
int  Xdenom,	// horizontal divisor
int  Ynum,	// vertical multiplicand
int  Ydenom,	// vertical divisor
LPSIZE  lpSize	// address of previous viewport extents
);
Parameters

hdc

Identifies the device context.

Xnum

Specifies the amount by which to multiply the current horizontal extent.

Xdenom

Specifies the amount by which to divide the current horizontal extent.

Ynum

Specifies the amount by which to multiply the current vertical extent.

Ydenom

Specifies the amount by which to divide the current vertical extent.

lpSize

Points to a SIZE structure. The previous viewport extents (in device units) are placed in this structure. If lpSize is NULL, nothing is returned.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

The viewport extents are modified as follows:

    xNewVE = (xOldVE * Xnum) / Xdenom

    yNewVE = (yOldVE * Ynum) / Ydenom

See Also

GetViewportExtEx, SIZE


ScaleWindowExt

The ScaleWindowExt function is not implemented in the Win32 API. Win32-based applications should use the ScaleWindowExtEx function.


ScaleWindowExtEx
ScaleWindowExtEx  QuickInfo  Overview  Group

The ScaleWindowExtEx function modifies the window for a device context using the ratios formed by the specified multiplicands and divisors.

BOOL ScaleWindowExtEx(

HDC  hdc,	// handle of device context
int  Xnum,	// horizontal multiplicand
int  Xdenom,	// horizontal divisor
int  Ynum,	// vertical multiplicand
int  Ydenom,	// vertical divisor
LPSIZE  lpSize	// address of previous window extents
);
Parameters

hdc

Identifies the device context.

Xnum

Specifies the amount by which to multiply the current horizontal extent.

Xdenom

Specifies the amount by which to divide the current horizontal extent.

Ynum

Specifies the amount by which to multiply the current vertical extent.

Ydenom

Specifies the amount by which to divide the current vertical extent.

lpSize

Points to a SIZE structure. The previous window extents (in logical units) are placed in this structure. If lpSize is NULL, nothing is returned.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

The window extents are modified as follows:

    xNewWE = (xOldWE * Xnum) / Xdenom

    yNewWE = (yOldWE * Ynum) / Ydenom

See Also

GetWindowExtEx, SIZE


ScheduleJob
ScheduleJob  QuickInfo  Overview  Group

The ScheduleJob function requests that the print spooler schedule a specified print job for printing.

BOOL ScheduleJob(

HANDLE  hPrinter,	// specifies printer for the print job
DWORD  dwJobID	// print job identifier
);
Parameters

hPrinter

Handle that specifies a printer for the print job. This must be a local printer that is configured as a spooled printer. If hPrinter is a handle to a remote printer connection, or if the printer is configured for direct printing, the ScheduleJob function fails.

hPrinter must be the same printer handle specifed in the call to AddJob that obtained the dwJobID print job identifer.

dwJobID

Specifies the print job to be scheduled. You obtain this print job identifer by calling the AddJob function.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

You obtain a printer handle by calling the OpenPrinter function.

You must successfully call the AddJob function before calling the ScheduleJob function. AddJob obtains the print job identifer that you pass to ScheduleJob as dwJobID. Both calls must use the same value for hPrinter.

The ScheduleJob function checks for a valid spool file. If there is an invalid spool file, or if it is empty, ScheduleJob deletes both the spool file and the corresponding print job entry in the print spooler.

See Also

AddJob, OpenPrinter


ScreenSaverConfigureDialog
ScreenSaverConfigureDialog  QuickInfo  Overview  Group

The ScreenSaverConfigureDialog function receives messages sent to a screen saver's configuration dialog box. A screen saver that allows user configuration must support this function.

BOOL ScreenSaverConfigureDialog(

HWND  hwndDlg,	// handle of dialog box
UINT  uMsg,	// message
WPARAM  wParam,	// first message parameter
LPARAM  lParam	// second message parameter
);
Parameters

hwndDlg

Identifies the configuration dialog box.

uMsg

Specifies the message.

wParam

Specifies additional message-specific information.

lParam

Specifies additional message-specific information.

Return Value

If the function processes the message, the return value is TRUE; otherwise, it is FALSE, except in response to a WM_INITDIALOG message. In response to a WM_INITDIALOG message, ScreenSaverConfigureDialog should return FALSE if it calls the SetFocus function to set the keyboard focus to one of the controls in the dialog box. Otherwise, the function should return TRUE, in which case the system sets the keyboard focus to the first control in the dialog box that can be given the focus.

Remarks

The dialog box template for the configuration dialog box must have the DLG_SCRNSAVECONFIGURE identifier.

The dialog box procedure is used only if the application specifies the default window class (WC_DIALOG) for the dialog box. The application uses the default class if no explicit class is given in the dialog box template. Although the dialog box procedure is similar to a window procedure, it must not call the DefWindowProc function to process unwanted messages. Unwanted messages are processed internally by the default dialog box procedure.

The ScreenSaverConfigureDialog function must be exported by including it in the EXPORTS statement in the application's module-definition (.DEF) file.

See Also

DefWindowProc, RegisterDialogClasses, SetFocus


ScreenSaverProc
ScreenSaverProc  QuickInfo  Overview  Group

The ScreenSaverProc function receives messages sent to the specified screen saver window.

LONG ScreenSaverProc(

HWND  hwnd,	// handle of screen saver window
UINT  uMsg,	// message
WPARAM  wParam,	// first message parameter
LPARAM  lParam	// second message parameter
);
Parameters

hwnd

Identifies the window.

uMsg

Specifies the message.

wParam

Specifies additional message-specific information.

lParam

Specifies additional message-specific information.

Return Value

The return value is the result of the message processing and depends on the message sent.

Remarks

A screen saver's ScreenSaverProc window procedure should use the DefScreenSaverProc function instead of the DefWindowProc function to provide default message processing. The DefScreenSaverProc function passes any messages that do not affect screen saver operations to DefWindowProc.

The ScreenSaverProc function must be exported by including it in the EXPORTS statement in the application's module-definition (.DEF) file.

See Also

DefScreenSaverProc, DefWindowProc


ScreenToClient
ScreenToClient  QuickInfo  Overview  Group

The ScreenToClient function converts the screen coordinates of a specified point on the screen to client coordinates.

BOOL ScreenToClient(

HWND  hwnd,	// window handle for source coordinates
LPPOINT  lpPoint	// address of structure containing coordinates
);
Parameters

hwnd

Identifies the window whose client area will be used for the conversion.

lpPoint

Points to a POINT structure that contains the screen coordinates to be converted.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

The function uses the window identified by the hwnd parameter and the screen coordinates given in the POINT structure to compute client coordinates. It then replaces the screen coordinates with the client coordinates. The new coordinates are relative to the upper-left corner of the specified window's client area.

The ScreenToClient function assumes the specified point is in screen coordinates.

See Also

ClientToScreen, MapWindowPoints, POINT


ScrollConsoleScreenBuffer
ScrollConsoleScreenBuffer  QuickInfo  Overview  Group

The ScrollConsoleScreenBuffer function moves a block of data in a screen buffer. The effects of the move can be limited by specifying a clipping rectangle, so the contents of the screen buffer outside the clipping rectangle are unchanged.

BOOL ScrollConsoleScreenBuffer(

HANDLE  hConsoleOutput,	// handle of a console screen buffer
PSMALL_RECT  psrctSourceRect,	// address of screen buffer rect. to move
PSMALL_RECT  psrctClipRect,	// address of affected screen buffer rect.
COORD  coordDestOrigin,	// new location of screen buffer rect.
PCHAR_INFO  pchiFill	// address of fill character and color
);
Parameters

hConsoleOutput

Identifies a console screen buffer. The handle must have GENERIC_WRITE access.

psrctSourceRect

Points to a SMALL_RECT structure whose members specify the upper-left and lower-right coordinates of the screen buffer rectangle to be moved.

psrctClipRect

Points to a SMALL_RECT structure whose members specify the upper-left and lower-right coordinates of the screen buffer rectangle that is affected by the scrolling. This pointer can be NULL.

coordDestOrigin

Specifies the upper-left corner of the new location of the psrctSourceRect contents.

pchiFill

Points to a CHAR_INFO structure that specifies the character and color attributes to be used in filling the cells within the intersection of psrctSourceRect and psrctClipRect that were left empty as a result of the move.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

ScrollConsoleScreenBuffer copies the contents of a rectangular region of a screen buffer, specified by the psrctSourceRect parameter, to another area of the screen buffer. The target rectangle has the same dimensions as the psrctSourceRect rectangle with its upper-left corner at the coordinates specified by the coordDestOrigin parameter. Those parts of psrctSourceRect that do not overlap with the target rectangle are filled in with the character and color attributes specified by the pchiFill parameter.

The clipping rectangle applies to changes made in both the psrctSourceRect rectangle and the target rectangle. For example, if the clipping rectangle does not include a region that would have been filled by the contents of pchiFill, the original contents of the region are left unchanged.

If the scroll or target regions extend beyond the dimensions of the screen buffer, they are clipped. For example, if psrctSourceRect is the region contained by (0,0) and (19,19) and coordDestOrigin is (10,15), the target rectangle is the region contained by (10,15) and (29,34). However, if the screen buffer is 50 characters wide and 30 characters high, the target rectangle is clipped to (10,15) and (29,29). Changes to the screen buffer are also clipped according to psrctClipRect, if the parameter specifies a SMALL_RECT structure. If the clipping rectangle is specified as (0,0) and (49,19), only the changes that occur in that region of the screen buffer are made.

See Also

CHAR_INFO, SetConsoleWindowInfo, SMALL_RECT


ScrollDC
ScrollDC  QuickInfo  Overview  Group

The ScrollDC function scrolls a rectangle of bits horizontally and vertically.

BOOL ScrollDC(

HDC  hdc,	// handle of device context
int  dx,	// horizontal scroll units
int  dy,	// vertical scroll units
CONST RECT  *lprcScroll,	// address of structure for scrolling rectangle
CONST RECT  *lprcClip,	// address of structure for clipping rectangle
HRGN  hrgnUpdate,	// handle of scrolling region
LPRECT  lprcUpdate	// address of structure for update rectangle
);
Parameters

hdc

Identifies the device context that contains the bits to be scrolled.

dx

Specifies the amount, in device units, of horizontal scrolling. This parameter must be a negative value to scroll to the left.

dy

Specifies the amount, in device units, of vertical scrolling. This parameter must be a negative value to scroll up.

lprcScroll

Points to the RECT structure containing the coordinates of the scrolling rectangle.

lprcClip

Points to the RECT structure containing the coordinates of the clipping rectangle. Only device bits within the clipping rectangle are affected. Bits scrolled from the outside of the rectangle to the inside are painted; bits scrolled from the inside of the rectangle to the outside are not painted.

hrgnUpdate

Identifies the region uncovered by the scrolling process. ScrollDC defines this region; it is not necessarily a rectangle.

lprcUpdate

Points to the RECT structure that receives the coordinates of the rectangle bounding the scrolling update region. This is the largest rectangular area that requires repainting. When the function returns, the values in the structure are in client coordinates, regardless of the mapping mode for the specified device context. This allows applications to use the update region in a call to the InvalidateRgn function, if required.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

If the lprcUpdate parameter is NULL, Windows does not compute the update rectangle. If both the hrgnUpdate and lprcUpdate parameters are NULL, Windows does not compute the update region. If hrgnUpdate is not NULL, Windows proceeds as though it contains a valid handle of the region uncovered by the scrolling process (defined by ScrollDC).

When you must scroll the entire client area of a window, use the ScrollWindow function; otherwise, use ScrollDC.

See Also

InvalidateRgn, RECT, ScrollWindow


ScrollWindow
ScrollWindow  QuickInfo  Overview  Group

The ScrollWindow function scrolls the content of the specified window's client area. This function exists for backward compatibility. For new applications, use the ScrollWindowEx function.

BOOL ScrollWindow(

HWND  hwnd,	// handle of window to scroll
int  dx,	// amount of horizontal scrolling
int  dy,	// amount of vertical scrolling
CONST RECT *  lprcScroll,	// address of structure with scroll rectangle
CONST RECT *  lprcClip	// address of structure with clip rectangle
);
Parameters

hwnd

Identifies the window where the client area is to be scrolled.

dx

Specifies the amount, in device units, of horizontal scrolling. If the window being scrolled has the CS_OWNDC or CS_CLASSDC style, then this parameter uses logical units rather than device units. This parameter must be a negative value to scroll the content of the window to the left.

dy

Specifies the amount, in device units, of vertical scrolling. If the window being scrolled has the CS_OWNDC or CS_CLASSDC style, then this parameter uses logical units rather than device units. This parameter must be a negative value to scroll the content of the window up.

lprcScroll

Points to the RECT structure specifying the portion of the client area to be scrolled. If this parameter is NULL, the entire client area is scrolled.

lprcClip

Points to the RECT structure containing the coordinates of the clipping rectangle. Only device bits within the clipping rectangle are affected. Bits scrolled from the outside of the rectangle to the inside are painted; bits scrolled from the inside of the rectangle to the outside are not painted.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

If the caret is in the window being scrolled, ScrollWindow automatically hides the caret to prevent it from being erased and then restores the caret after the scrolling is finished. The caret position is adjusted accordingly.

The area uncovered by ScrollWindow is not repainted, but it is combined into the window's update region. The application eventually receives a WM_PAINT message notifying it that the region must be repainted. To repaint the uncovered area at the same time the scrolling is in action, call the UpdateWindow function immediately after calling ScrollWindow.

If the lprcScroll parameter is NULL, the positions of any child windows in the window are offset by the amount specified by the dx and dy parameters; invalid (unpainted) areas in the window are also offset. ScrollWindow is faster when lprcScroll is NULL.

If lprcScroll is not NULL, the positions of child windows are not changed and invalid areas in the window are not offset. To prevent updating problems when lprcScroll is not NULL, call UpdateWindow to repaint the window before calling ScrollWindow.

See Also

RECT, ScrollDC, ScrollWindowEx, UpdateWindow


ScrollWindowEx
ScrollWindowEx  QuickInfo  Overview  Group

The ScrollWindowEx function scrolls the content of the specified window's client area. This function is similar to the ScrollWindow function, but it has additional features.

int ScrollWindowEx(

HWND  hwnd,	// handle of window to scroll
int  dx,	// amount of horizontal scrolling
int  dy,	// amount of vertical scrolling
CONST RECT  *lprcScroll,	// address of structure with scroll rectangle
CONST RECT  *lprcClip,	// address of structure with clip rectangle
HRGN  hrgnUpdate,	// handle of update region
LPRECT  lprcUpdate,	// address of structure for update rectangle
UINT  fuScroll	// scrolling flags
);
Parameters

hwnd

Identifies the window where the client area is to be scrolled.

dx

Specifies the amount, in device units, of horizontal scrolling. This parameter must be a negative value to scroll to the left.

dy

Specifies the amount, in device units, of vertical scrolling. This parameter must be a negative value to scroll up.

lprcScroll

Points to the RECT structure specifying the portion of the client area to be scrolled. If this parameter is NULL, the entire client area is scrolled.

lprcClip

Points to the RECT structure containing the coordinates of the clipping rectangle. Only device bits within the clipping rectangle are affected. Bits scrolled from the outside of the rectangle to the inside are painted; bits scrolled from the inside of the rectangle to the outside are not painted.

hrgnUpdate

Identifies the region that is modified to hold the region invalidated by scrolling. This parameter may be NULL.

lprcUpdate

Points to the RECT structure receiving the boundaries of the rectangle invalidated by scrolling. This parameter may be NULL.

fuScroll

Specifies flags that control scrolling. This parameter can be one of the following values:

Value	Meaning
SW_ERASE	Erases the newly invalidated region by sending a WM_ERASEBKGND message to the window when specified with the SW_INVALIDATE flag.
SW_INVALIDATE	Invalidates the region identified by the hrgnUpdate parameter after scrolling.
SW_SCROLLCHILDREN	Scrolls all child windows that intersect the rectangle pointed to by the lprcScroll parameter. The child windows are scrolled by the number of pixels specified by the dx and dy parameters. Windows sends a WM_MOVE message to all child windows that intersect the lprcScroll rectangle, even if they do not move.
Return Value

If the function succeeds, the return value is SIMPLEREGION (rectangular invalidated region), COMPLEXREGION (nonrectangular invalidated region; overlapping rectangles), or NULLREGION (no invalidated region).

If the function fails, the return value is ERROR.

Remarks

If the SW_INVALIDATE and SW_ERASE flags are not specified, ScrollWindowEx does not invalidate the area that is scrolled from. If either of these flags is set, ScrollWindowEx invalidates this area. The area is not updated until the application calls the UpdateWindow function, calls the RedrawWindow function (specifying the RDW_UPDATENOW or RDW_ERASENOW flag), or retrieves the WM_PAINT message from the application queue.

If the window has the WS_CLIPCHILDREN style, the returned areas specified by hrgnUpdate and lprcUpdate represent the total area of the scrolled window that must be updated, including any areas in child windows that need updating.

If the SW_SCROLLCHILDREN flag is specified, Windows does not properly update the screen if part of a child window is scrolled. The part of the scrolled child window that lies outside the source rectangle is not erased and is not properly redrawn in its new destination. To move child windows that do not lie completely within the rectangle specified by lprcScroll, use the DeferWindowPos function. The cursor is repositioned if the SW_SCROLLCHILDREN flag is set and the caret rectangle intersects the scroll rectangle.

All input and output coordinates (for lprcScroll, lprcClip, lprcUpdate, and hrgnUpdate) are determined as client coordinates, regardless of whether the window has the CS_OWNDC or CS_CLASSDC class style. Use the LPtoDP and DPtoLP functions to convert to and from logical coordinates, if necessary.

See Also

DeferWindowPos, DPtoLP, LPtoDP, RECT, RedrawWindow, ScrollDC, ScrollWindow, UpdateWindow


SearchPath
SearchPath  QuickInfo  Overview  Group

The SearchPath function searches for the specified file.

DWORD SearchPath(

LPCTSTR  lpszPath,	// address of search path
LPCTSTR  lpszFile,	// address of filename
LPCTSTR  lpszExtension,	// address of extension
DWORD  cchReturnBuffer,	// size, in characters, of buffer
LPTSTR  lpszReturnBuffer,	// address of buffer for found filename
LPTSTR  *plpszFilePart	// address of pointer to file component
);
Parameters

lpszPath

Points to a null-terminated string that specifies the path to be searched for the file. If this parameter is NULL, the function searches for a matching file in the following directories in the following sequence:

1.	The directory from which the application loaded.

2.	The current directory.

3.	Windows 95: The Windows system directory. Use the GetSystemDirectory function to get the path of this directory.

Windows NT: The 32-bit Windows system directory. Use the GetSystemDirectory function to get the path of this directory. The name of this directory is SYSTEM32.

4.	Windows NT only: The 16-bit Windows system directory. There is no Win32 function that obtains the path of this directory, but it is searched. The name of this directory is SYSTEM.

5.	The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.

6.	The directories that are listed in the PATH environment variable.

lpszFile

Points to a null-terminated string that specifies the name of the file to search for.

lpszExtension

Points to a null-terminated string that specifies an extension to be added to the filename when searching for the file. The first character of the filename extension must be a period (.). The extension is added only if the specified filename does not end with an extension.

If a filename extension is not required or if the filename contains an extension, this parameter can be NULL.

cchReturnBuffer

Specifies the length, in characters, of the buffer that receives the valid path and filename.

lpszReturnBuffer

Points to the buffer for the valid path and filename of the file found.

plpszFilePart

Points to the address (within lpszReturnBuffer) of the last component of the valid path and filename, which is the address of the character immediately following the final backslash (\) in the path.

Return Value

If the function succeeds, the value returned is the length, in characters, of the string copied to the buffer, not including the terminating null character. If the return value is greater than cchReturnBuffer, the value returned is the size of the buffer required to hold the path.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

See Also

FindFirstFile, FindNextFile, GetSystemDirectory, GetWindowsDirectory


select
select  QuickInfo

The Windows Sockets select function determines the status of one or more sockets, waiting if necessary.

int select (

int nfds,
fd_set FAR * readfds,
fd_set FAR * writefds,
fd_set FAR * exceptfds,
const struct timeval FAR * timeout
);
Parameters

nfds

This argument is ignored and included only for the sake of compatibility.

readfds

An optional pointer to a set of sockets to be checked for readability.

writefds

An optional pointer to a set of sockets to be checked for writability

exceptfds

An optional pointer to a set of sockets to be checked for errors.

timeout

The maximum time for select to wait, or NULL for blocking operation.

Return Value

If the function succeeds, select returns the total number of descriptors that are ready and contained in the fd_set structures, or zero if the time limit expired.

If the function fails,a value of SOCKET_ERROR is returned. To get extended error information, call WSAGetLastError.

Error Codes

WSANOTINITIALISED	A successful WSAStartup must occur before using this function.
WSAENETDOWN	The Windows Sockets implementation has detected that the network subsystem has failed.
WSAEINVAL	The timeout value is not valid.
WSAEINTR	The (blocking) call was canceled using WSACancelBlockingCall.
WSAEINPROGRESS	A blocking Windows Sockets operation is in progress.
WSAENOTSOCK	One of the descriptor sets contains an entry that is not a socket.
Remarks

This function is used to determine the status of one or more sockets. For each socket, the caller may request information on read, write, or error status. The set of sockets for which a given status is requested is indicated by an fd_set structure. Upon return, the structure is updated to reflect the subset of these sockets that meet the specified condition, and select returns the number of sockets meeting the conditions. A set of macros is provided for manipulating an fd_set. These macros are compatible with those used in the Berkeley software, but the underlying representation is completely different.

The parameter readfds identifies those sockets that are to be checked for readability. If the socket is currently listening, it will be marked as readable if an incoming connection request has been received, so that an accept is guaranteed to complete without blocking. For other sockets, readability means that queued data is available for reading or, for sockets of type SOCK_STREAM, that the virtual socket corresponding to the socket has been closed, so that a recv or recvfrom is guaranteed to complete without blocking. If the virtual circuit was closed gracefully, then a recv will return immediately with zero bytes read; if the virtual circuit was reset, then a recv will complete immediately with the error code WSAECONNRESET. The presence of out-of-band data will be checked if the socket option SO_OOBINLINE has been enabled (see setsockopt).

The parameter writefds identifies those sockets that are to be checked for writeability. If a socket is connecting (nonblocking), writability means that the connection establishment successfully completed. If the socket is not in the process of connecting, writability means that a send or sendto will complete without blocking. [It is not specified how long this guarantee can be assumed to be valid, particularly in a multithreaded environment.]

The parameter exceptfds identifies those sockets that are to be checked for the presence of out-of-band data or any exceptional error conditions. Note that out-of-band data will only be reported in this way if the option SO_OOBINLINE is FALSE. For a SOCK_STREAM, the breaking of the connection by the peer or due to KEEPALIVE failure will be indicated as an exception. This specification does not define which other errors will be included. If a socket is connecting (nonblocking), failure of the connect attempt is indicated in exceptfds.

Any of readfds, writefds, or exceptfds may be given as NULL if no descriptors are of interest.

Four macros are defined in the header file WINSOCK.H for manipulating the descriptor sets. The variable FD_SETSIZE determines the maximum number of descriptors in a set. (The default value of FD_SETSIZE is 64, which may be modified by #defining FD_SETSIZE to another value before #including WINSOCK.H.) Internally, an fd_set is represented as an array of SOCKETs; the last valid entry is followed by an element set to INVALID_SOCKET. The macros are:

FD_CLR(s, *set)	Removes the descriptor s from set.
FD_ISSET(s, *set)	Nonzero if s is a member of the set, zero otherwise.
FD_SET(s, *set)	Adds descriptor s to set.
FD_ZERO(*set)	Initializes the set to the NULL set.
The parameter timeout controls how long the select may take to complete. If timeout is a null pointer, select will block indefinitely until at least one descriptor meets the specified criteria. Otherwise, timeout points to a timeval structure which specifies the maximum time that select should wait before returning. If the timeval is initialized to {0, 0}, select will return immediately; this is used to "poll" the state of the selected sockets. If this is the case, then the select call is considered nonblocking and the standard assumptions for nonblocking calls apply. For example, the blocking hook must not be called, and the Windows Sockets implementation must not yield.

See Also

accept, connect, recv, recvfrom, send, sendto, setsockopt, WSAAsyncSelect WSACancelBlockingCall, WSAStartup


SelectClipPath
SelectClipPath  QuickInfo  Overview  Group

The SelectClipPath function selects the current path as a clipping region for a device context, combining the new region with any existing clipping region by using the specified mode.

BOOL SelectClipPath(

HDC  hdc,	// handle of device context
int  iMode	// clipping mode
);
Parameters

hdc

Identifies the device context of the path.

iMode

Specifies the way to use the path. The following values are allowed:

Value	Meaning
RGN_AND	The new clipping region includes the intersection (overlapping areas) of the current clipping region and the current path.
RGN_COPY	The new clipping region is the current path.
RGN_DIFF	The new clipping region includes the areas of the current clipping region with those of the current path excluded.
RGN_OR	The new clipping region includes the union (combined areas) of the current clipping region and the current path.
RGN_XOR	The new clipping region includes the union of the current clipping region and the current path but without the overlapping areas.
Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError. GetLastError may return one of the following error codes:

ERROR_CAN_NOT_COMPLETE
ERROR_INVALID_PARAMETER
ERROR_NOT_ENOUGH_MEMORY

Remarks

The device context identified by the hdc parameter must contain a closed path.

See Also

BeginPath, EndPath


SelectClipRgn
SelectClipRgn  QuickInfo  Overview  Group

The SelectClipRgn function selects a region as the current clipping region for the specified device context.

int SelectClipRgn(

HDC  hdc,	// handle of device context
HRGN  hrgn	// handle of region to be selected
);
Parameters

hdc

Identifies the device context.

hrgn

Identifies the region to be selected.

Return Value

If the function succeeds, the return value specifies the region's complexity and can be any one of the following values:

Value	Meaning
NULLREGION	Region is empty.
SIMPLEREGION	Region is a single rectangle.
COMPLEXREGION	Region is more than one rectangle.
ERROR	An error occurred. (The previous clipping region is unaffected.)
Remarks

Only a copy of the selected region is used. The region itself can be selected for any number of other device contexts or it can be deleted.

The SelectClipRgn function assumes that the coordinates for a region are specified in device units.

To remove a device-context's clipping region, specify a NULL region handle.

See Also

ExtSelectClipRgn


SelectObject
SelectObject  QuickInfo  Overview  Group

The SelectObject function selects an object into the specified device context. The new object replaces the previous object of the same type.

HGDIOBJ SelectObject(

HDC  hdc,	// handle of device context
HGDIOBJ  hgdiobj	// handle of object
);
Parameters

hdc

Identifies the device context.

hgdiobj

Identifies the object to be selected. The specified object must have been created by using one of the following functions:

Object	Functions
Bitmap	CreateBitmap, CreateBitmapIndirect, CreateCompatibleBitmap, CreateDIBitmap, CreateDIBSection
	(Bitmaps can be selected for memory device contexts only, and for only one device context at a time.)
Brush	CreateBrushIndirect, CreateDIBPatternBrush, CreateDIBPatternBrushPt, CreateHatchBrush, CreatePatternBrush, CreateSolidBrush
Font	CreateFont, CreateFontIndirect
Pen	CreatePen, CreatePenIndirect
Region	CombineRgn, CreateEllipticRgn, CreateEllipticRgnIndirect, CreatePolygonRgn, CreateRectRgn, CreateRectRgnIndirect
Return Value

If the selected object is not a region and the function succeeds, the return value is the handle of the object being replaced. If the selected object is a region and the function succeeds, the return value is one of the following values:

Value	Meaning
SIMPLEREGION	Region consists of a single rectangle.
COMPLEXREGION	Region consists of more than one rectangle.
NULLREGION	Region is empty.
If an error occurs and the selected object is not a region, the return value is NULL. Otherwise, it is GDI_ERROR.

Remarks

This function returns the previously selected object of the specified type. An application should always replace a new object with the original, default object after it has finished drawing with the new object.

An application cannot select a bitmap into more than one device context at a time.

See Also

CombineRgn, CreateBitmap, CreateBitmapIndirect, CreateBrushIndirect, CreateCompatibleBitmap, CreateDIBitmap, CreateDIBPatternBrush, CreateEllipticRgn, CreateEllipticRgnIndirect, CreateFont, CreateFontIndirect, CreateHatchBrush, CreatePatternBrush, CreatePen, CreatePenIndirect, CreatePolygonRgn, CreateRectRgn, CreateRectRgnIndirect, CreateSolidBrush, SelectClipRgn, SelectPalette


SelectPalette
SelectPalette  QuickInfo  Overview  Group

The SelectPalette function selects the specified logical palette into a device context.

HPALETTE SelectPalette(

HDC  hdc,	// handle of device context
HPALETTE  hpal,	// handle of logical color palette
BOOL  bForceBackground	// foreground/background mode
);
Parameters

hdc

Identifies the device context.

hpal

Identifies the logical palette to be selected.

bForceBackground

Specifies whether the logical palette is forced to be a background palette. If this value is TRUE, the RealizePalette function causes the logical palette to be mapped to the colors already in the physical palette in the best possible way. This is always done, even if the window for which the palette is realized belongs to a thread without active focus.

If this value is FALSE, RealizePalette causes the logical palette to be copied into the device palette when the application is in the foreground. (If the hdc parameter is a memory device context, this parameter is ignored.)

Return Value

If the function succeeds, the return value identifies the device context's previous logical palette.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

An application can determine whether a device supports palette operations by calling the GetDeviceCaps function and specifying the RASTERCAPS constant.

An application can select a logical palette into more than one device context. However, changes to a logical palette will affect all device contexts for which it is selected.

An application might call the SelectPalette function with the bForceBackground parameter set to TRUE if the child windows of a top-level window each realize their own palettes. However, only the child window that needs to realize its palette must set bForceBackground to TRUE; other child windows must set this value to FALSE.

See Also

CreatePalette, GetDeviceCaps, RealizePalette


send
send  QuickInfo

The Windows Sockets send function sends data on a connected socket.

int send (

SOCKET s,
const char FAR * buf,
int len,
int flags
);
Parameters

s

A descriptor identifying a connected socket.

buf

A buffer containing the data to be transmitted.

len

The length of the data in buf.

flags

Specifies the way the call is made.

Return Value

If the function succeeds, send returns the total number of characters sent. (Note that this may be less than the number indicated by len.)

If the function fails, a value of SOCKET_ERROR is returned. To get extended error information, call WSAGetLastError.

Error Codes

WSANOTINITIALISED	A successful WSAStartup must occur before using this function.
WSAENETDOWN	The Windows Sockets implementation has detected that the network subsystem has failed.
WSAEACCES	The requested address is a broadcast address, but the appropriate flag was not set.
WSAEINTR	The (blocking) call was canceled using WSACancelBlockingCall.
WSAEINPROGRESS	A blocking Windows Sockets operation is in progress.
WSAEFAULT	The buf argument is not in a valid part of the user address space.
WSAENETRESET	The connection must be reset because the Windows Sockets implementation dropped it.
WSAENOBUFS	The Windows Sockets implementation reports a buffer deadlock.
WSAENOTCONN	The socket is not connected.
WSAENOTSOCK	The descriptor is not a socket.
WSAEOPNOTSUPP	MSG_OOB was specified, but the socket is not of type SOCK_STREAM.
WSAESHUTDOWN	The socket has been shutdown; it is not possible to send on a socket after shutdown has been invoked with how set to 1 or 2.
WSAEWOULDBLOCK	The socket is marked as nonblocking and the requested operation would block.
WSAEMSGSIZE	The socket is of type SOCK_DGRAM, and the datagram is larger than the maximum supported by the Windows Sockets implementation.
WSAEINVAL	The socket has not been bound with bind.
WSAECONNABORTED	The virtual circuit was aborted due to timeout or other failure.
WSAECONNRESET	The virtual circuit was reset by the remote side.
Remarks

The send function is used on connected datagram or stream sockets and is used to write outgoing data on a socket. For datagram sockets, care must be taken not to exceed the maximum IP packet size of the underlying subnets, which is given by the iMaxUdpDg element in the WSAData structure returned by WSAStartup. If the data is too long to pass atomically through the underlying protocol the error WSAEMSGSIZE is returned, and no data is transmitted.

Note that the successful completion of a send does not indicate that the data was successfully delivered.

If no buffer space is available within the transport system to hold the data to be transmitted, send will block unless the socket has been placed in a nonblocking I/O mode. On nonblocking SOCK_STREAM sockets, the number of bytes written may be between 1 and the requested length, depending on buffer availability on both the local and foreign hosts. The select call may be used to determine when it is possible to send more data.

The flags parameter may be used to influence the behavior of the function invocation beyond the options specified for the associated socket. That is, the semantics of this function are determined by the socket options and the flags parameter. The latter is constructed by using a bitwise OR operation with any of the following values:

Value	Meaning
MSG_DONTROUTE	Specifies that the data should not be subject to routing. A Windows Sockets supplier may choose to ignore this flag.
MSG_OOB	Send out-of-band data (SOCK_STREAM only)
See Also

bind, recv, recvfrom, socket, select, sendto, shutdown, WSACancelBlockingCall, WSAStartup,


SendAsyncProc
SendAsyncProc  QuickInfo  Overview  Group

A SendAsyncProc function is an application-defined callback function that the operating system calls when the SendMessageCallback function is called. The system passes the message to the callback function after passing the message to the destination window procedure. A value of type SENDASYNCPROC is a pointer to such a function.

VOID CALLBACK SendAsyncProc(

HWND  hwnd,	// handle of destination window
UINT  uMsg,	// message
DWORD  dwData,	// application-defined value
LRESULT  lResult	// result of message processing
);
Parameters

hwnd

Identifies the window whose window procedure received the message.

If the SendMessageCallback function was called with its hwnd parameter set to HWND_BROADCAST, the operating system calls the SendAsyncProc function once for each top-level window.

uMsg

Specifies the message.

dwData

Specifies an application-defined value sent from the SendMessageCallback function.

lResult

Specifies the result of the message processing and depends on the message.

Return Value

This callback function does not return a value.

Remarks

SendAsyncProc is a placeholder for an application-defined function name.

You install a SendAsyncProc application-defined callback function by passing a SENDASYNCPROC pointer to the SendMessageCallback function.

See Also

SendMessage, SendMessageCallback


SendDlgItemMessage
SendDlgItemMessage  QuickInfo  Overview  Group

The SendDlgItemMessage function sends a message to the specified control in a dialog box.

LONG SendDlgItemMessage(

HWND  hwndDlg,	// handle of dialog box
int  idControl,	// identifier of control
UINT  uMsg,	// message to send
WPARAM  wParam,	// first message parameter
LPARAM  lParam	// second message parameter
);
Parameters

hwndDlg

Identifies the dialog box that contains the control.

idControl

Specifies the identifier of the control that receives the message.

uMsg

Specifies the message to be sent.

wParam

Specifies additional message-specific information.

lParam

Specifies additional message-specific information.

Return Value

The return value specifies the result of the message processing and depends on the message sent.

Remarks

The SendDlgItemMessage function does not return until the message has been processed.

Using SendDlgItemMessage is identical to retrieving a handle of the specified control and calling the SendMessage function.

See Also

SendMessage


SendMessage
SendMessage  QuickInfo  Overview  Group

The SendMessage function sends the specified message to a window or windows. The function calls the window procedure for the specified window and does not return until the window procedure has processed the message. The PostMessage function, in contrast, posts a message to a thread's message queue and returns immediately.

LRESULT SendMessage(

HWND  hwnd,	// handle of destination window
UINT  uMsg,	// message to send
WPARAM  wParam,	// first message parameter
LPARAM  lParam	// second message parameter
);
Parameters

hwnd

Identifies the window whose window procedure will receive the message. If this parameter is HWND_BROADCAST, the message is sent to all top-level windows in the system, including disabled or invisible unowned windows, overlapped windows, and pop-up windows; but the message is not sent to child windows.

uMsg

Specifies the message to be sent.

wParam

Specifies additional message-specific information.

lParam

Specifies additional message-specific information.

Return Value

The return value specifies the result of the message processing and depends on the message sent.

Remarks

If the specified window was created by the calling thread, the window procedure is called immediately as a subroutine. If the specified window was created by a different thread, Windows switches to that thread and calls the appropriate window procedure.

See Also

InSendMessage, PostMessage, SendDlgItemMessage


SendMessageCallback
SendMessageCallback  QuickInfo  Overview  Group

The SendMessageCallback function sends the specified message to a window or windows. The function calls the window procedure for the specified window and returns immediately. After the window procedure processes the message, the system calls the specified callback function, passing the result of the message processing and an application-defined value to the callback function.

BOOL SendMessageCallback(

HWND  hwnd,	// handle of destination window
UINT  uMsg,	// message to send
WPARAM  wParam,	// first message parameter
PARAM  lParam,	// second message parameter
SENDASYNCPROC  lpResultCallBack,	// function to receive message value
DWORD  dwData	// value to pass to callback function
);
Parameters

hwnd

Identifies the window whose window procedure will receive the message. If this parameter is HWND_BROADCAST, the message is sent to all top-level windows in the system, including disabled or invisible unowned windows, overlapped windows, and pop-up windows; but the message is not sent to child windows.

uMsg

Specifies the message to be sent.

wParam

Specifies additional message-specific information.

lParam

Specifies additional message-specific information.

lpResultCallBack

Points to a callback function that the system calls after the window procedure processes the message. See SendAsyncProc for information on suitable callback functions.

If  hwnd is HWND_BROADCAST, the operating system calls the SendAsyncProc callback function once for each top-level window.

dwData

Specifies an application-defined value to be sent to the callback function pointed to by the lpfnResultCallBack parameter.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

InSendMessage, PostMessage, SendAsyncProc, SendDlgItemMessage, SendMessage, SendMessageTimeout, SendNotifyMessage


SendMessageTimeout
SendMessageTimeout  QuickInfo  Overview  Group

The SendMessageTimeout function sends the specified message to a window or windows. The function calls the window procedure for the specified window and, if the specified window belongs to a different thread, does not return until the window procedure has processed the message or the specified time-out period has elapsed. If the window receiving the message belongs to the same queue as the current thread, the window procedure is called directly—the time-out value is ignored.

LRESULT SendMessageTimeout(

HWND  hwnd,	// handle of destination window
UINT  uMsg,	// message to send
WPARAM  wParam,	// first message parameter
LPARAM  lParam,	// second message parameter
UINT  fuFlags,	// how to send the message
UINT  uTimeout,	// time-out duration
LPDWORD  lpdwResult	// return value for synchronous call
);
Parameters

hwnd

Identifies the window whose window procedure will receive the message. If this parameter is HWND_TOPMOST, the message is sent to all top-level windows in the system, including disabled or invisible unowned windows.

uMsg

Specifies the message to be sent.

wParam

Specifies additional message-specific information.

lParam

Specifies additional message-specific information.

fuFlags

Specifies how to send the message. This parameter can be a combination of the following values:

Value	Meaning
SMTO_ABORTIFHUNG	Returns without waiting for the time-out period to elapse if the receiving process appears to be in a "hung" state.
SMTO_BLOCK	Prevents the calling thread from processing any other requests until the function returns.
SMTO_NORMAL	The calling thread is not prevented from processing other requests while waiting for the function to return.
uTimeout

Specifies the duration, in milliseconds, of the time-out period.

lpdwResult

Specifies the result of the message processing and depends on the message sent.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

InSendMessage, PostMessage, SendDlgItemMessage, SendMessage, SendMessageCallback, SendNotifyMessage


SendNotifyMessage
SendNotifyMessage  QuickInfo  Overview  Group

The SendNotifyMessage function sends the specified message to a window. If the window was created by the calling thread, SendNotifyMessage calls the window procedure for the window and does not return until the window procedure has processed the message. If the window was created by a different thread, SendNotifyMessage passes the message to the window procedure and returns immediately; it does not wait for the window procedure to finish processing the message.

BOOL SendNotifyMessage(

HWND  hwnd,	// handle of destination window
UINT  uMsg,	// message to send
WPARAM  wParam,	// first message parameter
LPARAM  lParam	// second message parameter
);
Parameters

hwnd

Identifies the window whose window procedure will receive the message. If this parameter is HWND_BROADCAST, the message is sent to all top-level windows in the system, including disabled or invisible unowned windows, overlapped windows, and pop-up windows; but the message is not sent to child windows.

uMsg

Specifies the message to be sent.

wParam

Specifies additional message-specific information.

lParam

Specifies additional message-specific information.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

PostMessage, PostThreadMessage, SendMessage


sendto
sendto  QuickInfo

The Windows Sockets sendto function sends data to a specific destination.

int sendto (

SOCKET s,
const char FAR * buf,
int len,
int flags,
const struct sockaddr FAR * to,
int tolen
);
Parameters

s

A descriptor identifying a socket.

buf

A buffer containing the data to be transmitted.

len

The length of the data in buf.

flags

Specifies the way in which the call is made.

to

An optional pointer to the address of the target socket.

tolen

The size of the address in to.

Return Value

If the function succeeds, sendto returns the total number of characters sent. (Note that this may be less than the number indicated by len.)

If the function fails, a value of SOCKET_ERROR is returned. To get extended error information, call WSAGetLastError.

Error Codes

WSANOTINITIALISED	A successful WSAStartup must occur before using this function.
WSAENETDOWN	The Windows Sockets implementation has detected that the network subsystem has failed.
WSAEACCES	The requested address is a broadcast address, but the appropriate flag was not set.
WSAEINTR	The (blocking) call was canceled using WSACancelBlockingCall.
WSAEINPROGRESS	A blocking Windows Sockets operation is in progress.
WSAEFAULT	The buf or to parameters are not part of the user address space, or the to argument is too small (less than the size of a socket address structure).
WSAENETRESET	The connection must be reset because the Windows Sockets implementation dropped it.
WSAENOBUFS	The Windows Sockets implementation reports a buffer deadlock.
WSAENOTCONN	The socket is not connected (SOCK_STREAM only).
WSAENOTSOCK	The descriptor is not a socket.
WSAEOPNOTSUPP	MSG_OOB was specified, but the socket is not of type SOCK_STREAM.
WSAESHUTDOWN	The socket has been shut down; it is not possible to sendto on a socket after shutdown has been invoked with how set to 1 or 2.
WSAEWOULDBLOCK	The socket is marked as nonblocking and the requested operation would block.
WSAEMSGSIZE	The socket is of type SOCK_DGRAM, and the datagram is larger than the maximum supported by the Windows Sockets implementation.
WSAECONNABORTED	The virtual circuit was aborted due to timeout or other failure.
WSAECONNRESET	The virtual circuit was reset by the remote side.
WSAEADDRNOTAVAIL	The specified address is not available from the local computer.
WSAEAFNOSUPPORT	Addresses in the specified family cannot be used with this socket.
WSAEDESTADDRREQ	A destination address is required.
WSAENETUNREACH	The network can't be reached from this host at this time.
Remarks

The sendto function is used on datagram or stream sockets and is used to write outgoing data on a socket. For datagram sockets, care must be taken not to exceed the maximum IP packet size of the underlying subnets, which is given by the iMaxUdpDg element in the WSAData structure returned by WSAStartup. If the data is too long to pass atomically through the underlying protocol, the error WSAEMSGSIZE is returned, and no data is transmitted.

Note that the successful completion of a sendto does not indicate that the data was successfully delivered.

The sendto function is normally used on a SOCK_DGRAM socket to send a datagram to a specific peer socket identified by the to parameter. On a SOCK_STREAM socket, the to and tolen parameters are ignored; in this case the sendto is equivalent to send.

To send a broadcast (on a SOCK_DGRAM only), the address in the to parameter should be constructed using the special IP address INADDR_BROADCAST (defined in WINSOCK.H) together with the intended port number. It is generally inadvisable for a broadcast datagram to exceed the size at which fragmentation may occur, which implies that the data portion of the datagram (excluding headers) should not exceed 512 bytes.

If no buffer space is available within the transport system to hold the data to be transmitted, sendto will block unless the socket has been placed in a nonblocking I/O mode. On nonblocking SOCK_STREAM sockets, the number of bytes written can be between 1 and the requested length, depending on buffer availability on both the local and foreign hosts. The select call can be used to determine when it is possible to send more data.

The flags parameter can be used to influence the behavior of the function invocation beyond the options specified for the associated socket. That is, the semantics of this function are determined by the socket options and the flags parameter. The latter is constructed by using a bitwise OR operation with any of the following values:

Value	Meaning
MSG_DONTROUTE	Specifies that the data should not be subject to routing. A Windows Sockets supplier may choose to ignore this flag.
MSG_OOB	Send out-of-band data (SOCK_STREAM only).
See Also

recv, recvfrom, socket, select, send, shutdown, WSACancelBlockingCall, WSAStartup,


ServiceMain
ServiceMain  QuickInfo  Overview  Group

A ServiceMain function is a function that a service process specifies as the entry point function of a particular service. The function can have any application-defined name.

VOID ServiceMain(

DWORD  dwArgc,	// number of arguments
LPTSTR  *lpszArgv	// address of array of argument string pointers
);
Parameters

dwArgc

Specifies the number of arguments in the lpszArgv array.

lpszArgv

Points to an array of pointers that point to null-terminated argument strings. The first argument in the array is the name of the service, and subsequent arguments are any strings passed to the service by the process that called the StartService function to start the service.

Return Value

This function does not return a value.

Remarks

A service process can start one or more services. For each service that it can start, a service process has a SERVICE_TABLE_ENTRY structure that specifies the service name and a pointer to the ServiceMain function for that service.

When the service control manager receives a request to start a service, it starts the service process (if it is not already running). The main thread of the service process calls the StartServiceCtrlDispatcher function with a pointer to an array of SERVICE_TABLE_ENTRY structures. Then the service control manager sends a start request to the service control dispatcher for this service process. The service control dispatcher creates a new thread to execute the ServiceMain function of the service being started.

This function should immediately call the RegisterServiceCtrlHandler function to specify a Handler function to handle control requests. Next, it should call the SetServiceStatus function to send status information to the service control manager. After these calls, the function completes the initialization tasks of the service, and then it waits for the service to terminate.

A ServiceMain function does not return until the service is ready to terminate.

See Also

Handler, RegisterServiceCtrlHandler, SetServiceStatus, SERVICE_TABLE_ENTRY, StartServiceCtrlDispatcher


SetAbortProc
SetAbortProc  QuickInfo  Overview  Group

The SetAbortProc function sets the application-defined abort function that allows a print job to be canceled during spooling. This function replaces the SETABORTPROC printer escape.

int SetAbortProc(

HDC  hdc,	// handle of device context
ABORTPROC  lpAbortProc	// address of abort function
);
Parameters

hdc

Identifies the device context for the print job.

lpAbortProc

Points to the application-defined abort function. For more information about the callback function, see the AbortProc callback function.

Return Value

If the function succeeds, the return value is greater than zero.

If the function fails, the return value is SP_ERROR. To get extended error information, call GetLastError.

See Also

AbortDoc, AbortProc


SetAclInformation
SetAclInformation  QuickInfo  Overview  Group

The SetAclInformation function sets information about an access-control list (ACL).

BOOL SetAclInformation(

PACL  pAcl,	// address of access-control list
LPVOID  lpvAclInfo,	// address of ACL information
DWORD  cbAclInfo,	// size of ACL information
ACL_INFORMATION_CLASS  aclic	// specifies class of requested info
);
Parameters

pAcl

Points to an ACL structure. The function sets information in this ACL.

lpvAclInfo

Points to a buffer containing the information to be set. For the current version of Windows NT, this must be an ACL_REVISION_INFORMATION structure.

cbAclInfo

Specifies the size, in bytes, of the buffer pointed to by the pAclInfo parameter.

aclic

Specifies an ACL_INFORMATION_CLASS enumerated type that gives the class of information requested.

Currently, this parameter can be AclRevisionInformation. This means that the buffer pointed to by the lpvAclInfo parameter contains an ACL_REVISION_INFORMATION structure.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

ACL, ACL_INFORMATION_CLASS, ACL_REVISION_INFORMATION, GetAclInformation, InitializeAcl, IsValidAcl


SetActiveWindow
SetActiveWindow  QuickInfo  Overview  Group

The SetActiveWindow function makes the specified top-level window associated with the thread calling this function the active window.

HWND SetActiveWindow(

HWND  hwnd	// handle of window to activate
);
Parameters

hwnd

Identifies the top-level window to be activated.

Return Value

If the function succeeds, the return value is the handle of the window that was previously active.

Remarks

Applications must use the SetActiveWindow function carefully, because the function allows an application to arbitrarily take over the active window and keyboard focus. Usually, Windows takes care of all activation.

If the window identified by the hwnd parameter was created by the calling thread, the active window status of the calling thread is set to hwnd. Otherwise, the active window status of the calling thread is set to NULL.

The SetActiveWindow function activates a window, but it only brings the window to the foreground if the window is owned by the thread making the call to SetActiveWindow.

The SetForegroundWindow window function, on the other hand, activates a window and forces the thread that created the window into the foreground. An application should call SetForegroundWindow if it wants to put itself into the foreground.

See Also

GetActiveWindow, SetForegroundWindow, WM_ACTIVATE


SetArcDirection
SetArcDirection  QuickInfo  Overview  Group

The SetArcDirection sets the drawing direction to be used for arc and rectangle functions.

int SetArcDirection(

HDC  hdc,	// identifies the device context
int  ArcDirection	// specifies the new arc direction
);
Parameters

hdc

Identifies the device context.

ArcDirection

Specifies the new arc direction. This parameter can be one of the following values:

Value	Meaning
AD_COUNTERCLOCKWISE	Figures drawn counterclockwise.
AD_CLOCKWISE	Figures drawn clockwise.
Return Value

If the function succeeds, the return value specifies the old arc direction.

If the function fails, the return value is zero.

Remarks

The default direction is counterclockwise.

The SetArcDirection function specifies the direction in which the following functions draw:

Arc	ArcTo
Chord	Ellipse
Pie	Rectangle
RoundRect


SetBitmapBits
SetBitmapBits  QuickInfo  Overview  Group

The SetBitmapBits function sets the bits of color data for a bitmap to the specified values.

The SetBitmapBits function is included only for compatibility with earlier versions of Windows. For Win32-based applications, use the SetDIBits function.

LONG SetBitmapBits(

HBITMAP  hbmp,	// handle of bitmap
DWORD  cBytes,	// number of bytes in bitmap array
CONST VOID  *lpBits	// address of array with bitmap bits
);
Parameters

hbmp

Identifies the bitmap to be set.

cBytes

Specifies the number of bytes pointed to by the lpBits parameter.

lpBits

Points to an array of bytes that contain color data for the specified bitmap.

Return Value

If the function succeeds, the return value is the number of bytes used in setting the bitmap bits.

If the function fails, the return value is zero.

Remarks

The array identified by lpBits must be WORD aligned.

See Also

GetBitmapBits, SetDIBits


SetBitmapDimension
SetBitmapDimension  Overview  Group

The SetBitmapDimension function has been deleted. Win32-based applications should use the SetBitmapDimensionEx function.


SetBitmapDimensionEx
SetBitmapDimensionEx  QuickInfo  Overview  Group

The SetBitmapDimensionEx function assigns preferred dimensions to a bitmap. These dimensions can be used by applications; however, they are not used by Windows.

BOOL SetBitmapDimensionEx(

HBITMAP  hBitmap,	// handle of bitmap
int  nWidth,	// bitmap width in .01-mm units
int  nHeight,	// bitmap height in .01-mm units
LPSIZE  lpSize	// address of structure for original dimensions
);
Parameters

hBitmap

Identifies the bitmap.  The bitmap cannot be a DIB section bitmap.

nWidth

Specifies the width, in 0.1-millimeter units, of the bitmap.

nHeight

Specifies the height, in 0.1-millimeter units, of the bitmap.

lpSize

Points to a SIZE structure to receive the previous dimensions of the bitmap. This pointer can be NULL.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

An application can retrieve the dimensions assigned to a bitmap with the SetBitmapDimensionEx function by calling the GetBitmapDimensionEx function.

The bitmap identified by hBitmap cannot be a dib section, which is a bitmap created by the CreateDIBSection function. If the bitmap is a dib section, the SetBitmapDimensionEx function fails.

See Also

CreateDIBSection, GetBitmapDimensionEx, SIZE


SetBkColor
SetBkColor  QuickInfo  Overview  Group

The SetBkColor function sets the current background color to the specified color value, or to the nearest physical color if the device cannot represent the specified color value.

COLORREF SetBkColor(

HDC  hdc,	// handle of device context
COLORREF  crColor	// background color value
);
Parameters

hdc

Identifies the device context.

crColor

Specifies the new background color.

Return Value

If the function succeeds, the return value specifies the previous background color as a COLORREF value.

If the function fails, the return value is CLR_INVALID.

Remarks

This function fills the gaps between styled lines drawn using a pen created by the CreatePen function; it does not fill the gaps between styled lines drawn using a pen created by the ExtCreatePen function.

If the background mode is OPAQUE, the background color is used to fill gaps between styled lines, gaps between hatched lines in brushes, and character cells. The background color is also used when converting bitmaps from color to monochrome and vice versa.

See Also

CreatePen, GetBkMode, SetBkMode, COLORREF, ExtCreatePen


SetBkMode
SetBkMode  QuickInfo  Overview  Group

The SetBkMode function sets the background mix mode of the specified device context. The background mix mode is used with text, hatched brushes, and pen styles that are not solid lines.

int SetBkMode(

HDC  hdc,	// handle of device context
int  iBkMode	// flag specifying background mode
);
Parameters

hdc

Identifies the device context.

iBkMode

Specifies the background mode. This parameter can be either of the following values:

Value	Description
OPAQUE	Background is filled with the current background color before the text, hatched brush, or pen is drawn.
TRANSPARENT	Background remains untouched.
Return Value

If the function succeeds, the return value specifies the previous background mode.

If the function fails, the return value is zero.

Remarks

The SetBkMode function affects the line styles for lines drawn using a pen created by the CreatePen function. SetBkMode does not affect lines drawn using a pen created by the ExtCreatePen function.

The iBkMode parameter can also be set to driver-specific values. GDI passes such values to the device driver and otherwise ignores them.

See Also

CreatePen, ExtCreatePen, GetBkMode


SetBoundsRect
SetBoundsRect  QuickInfo  Overview  Group

The SetBoundsRect function controls the accumulation of bounding rectangle information for the specified device context. Windows can maintain a bounding rectangle for all drawing operations. An application can examine and set this rectangle. The drawing boundaries are useful for invalidating bitmap caches.

UINT SetBoundsRect(

HDC  hdc,	// handle of device context
CONST RECT  *lprcBounds,	// address of rectangle coordinates
UINT  flags	// controls rectangle combination
);
Parameters

hdc

Identifies the device context for which to accumulate bounding rectangles.

lprcBounds

Points to a RECT structure used to set the bounding rectangle. Rectangle dimensions are in logical coordinates. This parameter can be NULL.

flags

Specifies how the new rectangle will be combined with the accumulated rectangle. This parameter can be a combination of the following values:

Value	Description
DCB_ACCUMULATE	Adds the rectangle specified by the lprcBounds parameter to the bounding rectangle (using a rectangle union operation). Using both DCB_RESET and DCB_ACCUMULATE sets the bounding rectangle to the rectangle specified by the lprcBounds parameter.
DCB_DISABLE	Turns off boundary accumulation.
DCB_ENABLE	Turns on boundary accumulation, which is disabled by default.
DCB_RESET	Clears the bounding rectangle.
Return Value

If the function succeeds, the return value specifies the previous state of the bounding rectangle. This state can be a combination of the following values:

Value	Meaning
DCB_DISABLE	Boundary accumulation is off.
DCB_ENABLE	Boundary accumulation is on. DCB_ENABLE and DCB_DISABLE are mutually exclusive.
DCB_RESET	Bounding rectangle is empty.
DCB_SET	Bounding rectangle is not empty. DCB_SET and DCB_RESET are mutually exclusive.
Remarks

The DCB_SET value is a combination of the bit values DCB_ACCUMULATE and DCB_RESET. Applications that check the DCB_RESET bit to determine whether the bounding rectangle is empty must also check the DCB_ACCUMULATE bit. The bounding rectangle is empty only if the DCB_RESET bit is 1 and the DCB_ACCUMULATE bit is 0.

See Also

GetBoundsRect, RECT


SetBrushOrg

The SetBrushOrg function is not implemented in the Win32 API. Win32-based applications should use the SetBrushOrgEx function.


SetBrushOrgEx
SetBrushOrgEx  QuickInfo  Overview  Group

The SetBrushOrgEx function sets the brush origin that GDI assigns to the next brush an application selects into the specified device context. The function supersedes the SetBrushOrg function.

BOOL SetBrushOrgEx(

HDC  hdc,	// handle of device context
int  nXOrg,	// x-coordinate of new origin
int  nYOrg,	// y-coordinate of new origin
LPPOINT  lppt	// points to previous brush origin
);
Parameters

hdc

Identifies the device context.

nXOrg

Specifies the x-coordinate, in device units, of the new brush origin. This value must be in the range 0 through 7.

nYOrg

Specifies the y-coordinate, in device units, of the new brush origin. This value must be in the range 0 through 7.

lppt

Points to a POINT structure that receives the previous brush origin.

This parameter can be NULL if the previous brush origin is not required.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

A brush is a bitmap that the operating system uses to paint the interiors of filled shapes.

The brush origin is a pair of coordinates with values between 0 and 7, specifying the location of one pixel in the bitmap. The default brush origin coordinates are (0,0). For horizontal coordinates, the value 0 corresponds to the leftmost column of pixels; the value 7 corresponds to the rightmost column. For vertical coordinates, the value 0 corresponds to the uppermost row of pixels; the value 7 corresponds to the lowermost row.

When the operating system positions the brush at the start of any painting operation, it maps the origin of the brush to the location on the window's client area specified by the brush origin. For example, if the brush origin is (2,3), the operating system maps the origin of the brush, (0,0), to the location (2,3) on the window's client area.

The operating system automatically tracks the origin of all window-managed device contexts and adjusts their brushes as necessary to maintain an alignment of patterns on the surface. The brush origin that is set with this call is relative to the upper-left corner of the client area.

An application should call SetBrushOrgEx after setting the bitmap stretching mode to HALFTONE via SetStretchBltMode. This must be done to avoid brush misalignment.

Windows NT: The operating system automatically tracks the origin of all window-managed device contexts and adjusts their brushes as necessary to maintain an alignment of patterns on the surface.

Windows 95: Automatic tracking of the brush origin is not supported. Applications must use the UnrealizeObject, SetBrushOrgEx, and SelectObject functions to align the brush before using it.

See Also

GetBrushOrgEx, POINT, SelectObject, SetStretchBltMode, UnrealizeObject


SetCapture
SetCapture  QuickInfo  Overview  Group

The SetCapture function sets the mouse capture to the specified window belonging to the current thread. Once a window has captured the mouse, all mouse input is directed to that window, regardless of whether the cursor is within the borders of that window. Only one window at a time can capture the mouse.

If the mouse cursor is over a window created by another thread, the system will direct mouse input to the specified window only if a mouse button is down.

HWND SetCapture(

HWND  hwnd	// handle of window to receive mouse capture
);
Parameters

hwnd

Identifies the window in the current thread that is to capture the mouse.

Return Value

If the function succeeds, the return value is the handle of the window that had previously captured the mouse. If there is no such window, the return value is NULL.

Remarks

Only the foreground window can capture the mouse. When a background window attempts to do so, the window receives messages only for mouse events that occur when the cursor hot spot is within the visible portion of the window. Also, even if the foreground window has captured the mouse, the user can still click another window, bringing it to the foreground.

When the window no longer requires all mouse input, the thread that created the window should call the ReleaseCapture function to release the mouse.

This function cannot be used to capture mouse input meant for another process.

Windows 95 only: Calling this function causes the window that is losing the mouse capture to receive a WM_CAPTURECHANGED message.

See Also

GetCapture, ReleaseCapture


SetCaretBlinkTime
SetCaretBlinkTime  QuickInfo  Overview  Group

The SetCaretBlinkTime function sets the caret blink time to the specified number of milliseconds. The blink time is the elapsed time, in milliseconds, required to invert the caret's pixels.

BOOL SetCaretBlinkTime(

UINT  wMSeconds	// blink time, in milliseconds
);
Parameters

wMSeconds

Specifies the new blink time, in milliseconds.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The caret is a shared resource; there is only one caret in the system. A window should set the caret blink time only if it owns the caret. The window should restore the previous blink time before losing the keyboard focus or becoming inactive.

See Also

GetCaretBlinkTime


SetCaretPos
SetCaretPos  QuickInfo  Overview  Group

The SetCaretPos function moves the caret to the specified coordinates. If the window that owns the caret was created with the CS_OWNDC class style, then the specified coordinates are subject to the mapping mode of the device context associated with that window.

BOOL SetCaretPos(

int  nX,	// horizontal position
int  nY	// vertical position
);
Parameters

nX

Specifies the new x-coordinate of the caret.

nY

Specifies the new y-coordinate of the caret.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

SetCaretPos moves the caret whether or not the caret is hidden.

The caret is a shared resource; there is only one caret in the system. A window can set the caret position only if it owns the caret.

See Also

GetCaretPos, HideCaret, ShowCaret


SetClassLong
SetClassLong  QuickInfo  Overview  Group

The SetClassLong function replaces the specified 32-bit (long) value at the specified offset into the extra class memory or the WNDCLASS structure for the class to which the specified window belongs.

DWORD SetClassLong(

HWND  hwnd,	// handle of window
int  nIndex,	// index of value to change
LONG  lNewVal	// new value
);
Parameters

hwnd

Identifies the window and, indirectly, the class to which the window belongs.

nIndex

Specifies the 32-bit value to replace. To set a 32-bit value in the extra class memory, specify the positive, zero-based byte offset of the value to be set. Valid values are in the range zero through the number of bytes of extra class memory, minus four; for example, if you specified 12 or more bytes of extra class memory, a value of 8 would be an index to the third 32-bit integer. To set any other value from the WNDCLASS structure, specify one of the following values:

Value	Action
GCL_CBCLSEXTRA	Sets the size, in bytes, of the extra memory associated with the class. Setting this value does not change the number of extra bytes already allocated.
GCL_CBWNDEXTRA	Sets the size, in bytes, of the extra window memory associated with each window in the class. Setting this value does not change the number of extra bytes already allocated. For information on how to access this memory, see SetWindowLong and SetWindowWord.
GCL_HBRBACKGROUND	Replaces the handle of the background brush associated with the class.
GCL_HCURSOR	Replaces the handle of the cursor associated with the class.
GCL_HICON	Replaces the handle of the icon associated with the class.
GCL_HMODULE	Replaces the handle of the module that registered the class.
GCL_MENUNAME	Replaces the address of the menu name string. The string identifies the menu resource associated with the class.
GCL_STYLE	Replaces the window-class style bits.
GCL_WNDPROC	Replaces the address of the window procedure associated with the class.
lNewVal

Specifies the replacement value.

Return Value

If the function succeeds, the return value is the previous value of the specified 32-bit integer.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

If you use the SetClassLong function and the GCL_WNDPROC index to replace the window procedure, the window procedure must conform to the guidelines specified in the description of the WindowProc callback function.

Calling SetClassLong with the GCL_WNDPROC index creates a subclass of the window class that affects all windows subsequently created with the class. An application should not subclass a window created by another process.

Reserve extra class memory by specifying a nonzero value in the cbClsExtra member of the WNDCLASS structure used with the RegisterClass function.

Use the SetClassLong function with care. For example, it is possible to change the background color for a class by using SetClassLong, but this change does not immediately repaint all windows belonging to the class.

See Also

GetClassLong, GetClassWord, RegisterClass, SetClassWord, SetWindowLong, SetWindowWord, WindowProc, WNDCLASS


SetClassWord
SetClassWord  QuickInfo  Overview  Group

The SetClassWord function replaces the 16-bit (word) value at the specified offset into the extra class memory for the window class to which the specified window belongs.

WORD SetClassWord(

HWND  hwnd,	// handle of window
int  nIndex,	// index of value to change
WORD  wNewWord	// new value
);
Parameters

hwnd

Identifies the window and, indirectly, the class to which the window belongs.

nIndex

Specifies the zero-based byte offset of the value to be replaced. Valid values are in the range zero through the number of bytes of class memory minus two; for example, if you specified 10 or more bytes of extra class memory, a value of 8 would be an index to the fifth 16-bit integer.

wNewWord

Specifies the replacement value.

Return Value

If the function succeeds, the return value is the previous value of the specified 16-bit integer.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

Reserve extra class memory by specifying a nonzero value in the cbClsExtra member of the WNDCLASS structure used with the RegisterClass function.

The GCW_ values are obsolete in the Win32 API. You must use the SetClassLong function to set the class values previously set by using the GCW_ values with the SetClassWord function.

See Also

GetClassLong, GetClassWord, RegisterClass, SetClassLong, WNDCLASS


SetClipboardData
SetClipboardData  QuickInfo  Overview  Group

The SetClipboardData function places data on the clipboard in a specified clipboard format. The window must be the current clipboard owner, and the application must have called the OpenClipboard function. (When responding to the WM_RENDERFORMAT and WM_RENDERALLFORMATS messages, the clipboard owner must not call OpenClipboard before calling SetClipboardData.)

HANDLE SetClipboardData(

UINT  uFormat,	// clipboard format
HANDLE  hData	// data handle
);
Parameters

uFormat

Specifies a clipboard format. This parameter can be a registered format or any of the standard clipboard formats listed in the following Remarks section. For information about registered clipboard formats, see the RegisterClipboardFormat function.

hData

Identifies the data in the specified format. This parameter can be NULL, indicating that the window provides data in the specified clipboard format (renders the format) upon request. If a window delays rendering, it must process the WM_RENDERFORMAT and WM_RENDERALLFORMATS messages.

Once SetClipboardData is called, the system owns the object identified by the hData parameter. The application can read the data, but must not free the handle or leave it locked. If the hData parameter identifies a memory object, the object must have been allocated using the GlobalAlloc function with the GMEM_MOVEABLE and GMEM_DDESHARE flags.

Return Value

If the function succeeds, the return value is the handle of the data.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

The uFormat parameter can identify a registered clipboard format, or it can be one of the following values:

Value	Meaning
CF_BITMAP	A handle to a bitmap (HBITMAP).
CF_DIB	A memory object containing a BITMAPINFO structure followed by the bitmap bits.
CF_DIF	Software Arts' Data Interchange Format.
CF_DSPBITMAP	Bitmap display format associated with a private format. The hData parameter must be a handle of data that can be displayed in bitmap format in lieu of the privately formatted data.
CF_DSPENHMETAFILE	Enhanced metafile display format associated with a private format. The hData parameter must be a handle of data that can be displayed in enhanced metafile format in lieu of the privately formatted data.
CF_DSPMETAFILEPICT	Metafile-picture display format associated with a private format. The hData parameter must be a handle of data that can be displayed in metafile-picture format in lieu of the privately formatted data.
CF_DSPTEXT	Text display format associated with a private format. The hData parameter must be a handle of data that can be displayed in text format in lieu of the privately formatted data.
CF_ENHMETAFILE	A handle of an enhanced metafile (HENHMETAFILE).
CF_GDIOBJFIRST through CF_GDIOBJLAST	Windows 95 only: Range of integer values for application-defined GDI object clipboard formats. Handles associated with clipboard formats in this range are not automatically deleted using the GlobalFree function when the clipboard is emptied. Also, when using values in this range, the hData parameter is not a handle to a GDI object, but is a handle allocated by the GlobalAlloc function with the GMEM_DDESHARE and GMEM_MOVEABLE flags.
CF_HDROP	Windows 95 only: A handle of type HDROP that identifies a list of files. An application can retrieve information about the files by passing the handle to the DragQueryFile functions.
CF_LOCALE	Windows 95 only: The data is a handle to the locale identifier associated with text in the clipboard. When you copy data having the CF_TEXT format to the clipboard, the system automatically sets the CF_LOCALE format to the current input locale. You can use the CF_LOCALE format to associate a different locale with the clipboard text. An application that pastes text from the clipboard can retrieve this format to determine which character set was used to generate the text. Note that the clipboard does not support plain text in multiple character sets. To achieve this, use a fomatted text data type such as RTF instead.
CF_METAFILEPICT	Handle of a metafile picture format as defined by the METAFILEPICT structure. When passing a CF_METAFILEPICT handle by means of dynamic data exchange (DDE), the application responsible for deleting hData should also free the metafile referred to by the CF_METAFILEPICT handle.
CF_OEMTEXT	Text format containing characters in the OEM character set. Each line ends with a carriage return/linefeed (CR-LF) combination. A null character signals the end of the data.
CF_OWNERDISPLAY	Owner-display format. The clipboard owner must display and update the clipboard viewer window, and receive the WM_ASKCBFORMATNAME, WM_HSCROLLCLIPBOARD, WM_PAINTCLIPBOARD, WM_SIZECLIPBOARD, and WM_VSCROLLCLIPBOARD messages. The hData parameter must be NULL.
CF_PALETTE	Handle of a color palette. Whenever an application places data in the clipboard that depends on or assumes a color palette, it should place the palette on the clipboard as well.
	If the clipboard contains data in the CF_PALETTE (logical color palette) format, the application should use the SelectPalette and RealizePalette functions to realize (compare) any other data in the clipboard against that logical palette.
	When displaying clipboard data, Windows clipboard always uses as its current palette any object on the clipboard that is in the CF_PALETTE format.
CF_PENDATA	Data for the pen extensions to the Microsoft Windows for Pen Computing.
CF_PRIVATEFIRST through CF_PRIVATELAST	Range of integer values for private clipboard formats. Handles associated with private clipboard formats are not freed automatically; the clipboard owner must free such handles, typically in response to the WM_DESTROYCLIPBOARD message.
CF_RIFF	Represents audio data more complex than can be represented in a CF_WAVE standard wave format.
CF_SYLK	Microsoft Symbolic Link (SYLK) format.
CF_TEXT	Text format. Each line ends with a carriage return/linefeed (CR-LF) combination. A null character signals the end of the data. Use this format for ANSI text.
CF_WAVE	Represents audio data in one of the standard wave formats, such as 11 kHz or 22 kHz pulse code modulation (PCM).
CF_TIFF	Tagged-image file format.
CF_UNICODETEXT	Windows NT only: Unicode text format. Each line ends with a carriage return/linefeed (CR-LF) combination. A null character signals the end of the data.
The operating system performs implicit data format conversions between certain clipboard formats when an application calls the GetClipboardData function. For example, if the CF_OEMTEXT format is on the clipboard, a window can retrieve data in the CF_TEXT format. The format on the clipboard is converted to the requested format on demand. The following table shows the clipboard data type conversions that are available. Note that some of these automatic type conversions are not available on all platforms.

Clipboard Format	Conversion Format	Platform Support
CF_BITMAP	CF_DIB	Windows 95
CF_DIB	CF_BITMAP	Windows 95
CF_DIB	CF_PALETTE	Windows 95
CF_ENHMETAFILE	CF_METAFILEPICT	Windows 95, Windows NT
CF_METAFILEPICT	CF_ENHMETAFILE	Windows 95, Windows NT
CF_OEMTEXT	CF_TEXT	Windows 95, Windows NT
CF_OEMTEXT	CF_UNICODETEXT	Windows NT
CF_TEXT	CF_OEMTEXT	Windows 95, Windows NT
CF_TEXT	CF_UNICODETEXT	Windows NT
CF_UNICODETEXT	CF_OEMTEXT	Windows NT
CF_UNICODETEXT	CF_TEXT	Windows NT
If the operating system provides an automatic type conversion for a particular clipboard format, there is no advantage to placing the conversion format(s) on the clipboard.

When copying bitmaps, it is best to place only the CF_DIB format on the clipboard. This is because the colors in a device-dependent bitmap (CF_BITMAP) are relative to the system palette, which may change before the bitmap is pasted. If only the CF_DIB format is on the clipboard and a window requests the CF_BITMAP format, the system renders the device-dependent bitmap using the current palette at that time.

If you place the CF_BITMAP format on the clipboard (and not CF_DIB), the system renders the CF_DIB clipboard format as soon as the clipboard is closed. This ensures that the correct palette is used to generate the device-independent bitmap (DIB). Conversions between other clipboard formats occur upon demand.

Windows platforms support two clipboard formats for metafiles: CF_ENHMETAFILE and CF_METAFILEPICT. Specify CF_ENHMETAFILE for enhanced metafiles and CF_METAFILEPICT for Windows metafiles.

See Also

BITMAPINFO, GetClipboardData, GlobalAlloc, GlobalFree, METAFILEPICT, OpenClipboard, RealizePalette, RegisterClipboardFormat, SelectPalette, WM_ASKCBFORMATNAME, WM_DESTROYCLIPBOARD, WM_HSCROLLCLIPBOARD, WM_PAINTCLIPBOARD, WM_RENDERFORMAT, WM_RENDERALLFORMATS, WM_SIZECLIPBOARD, WM_VSCROLLCLIPBOARD


SetClipboardViewer
SetClipboardViewer  QuickInfo  Overview  Group

The SetClipboardViewer function adds the specified window to the chain of clipboard viewers. Clipboard viewer windows receive a WM_DRAWCLIPBOARD message whenever the content of the clipboard changes.

HWND SetClipboardViewer(

HWND  hwnd	// handle of clipboard viewer window
);
Parameters

hwnd

Identifies the window to be added to the clipboard chain.

Return Value

If the function succeeds, the return value identifies the next window in the clipboard viewer chain. If an error occurs or there are no other windows in the clipboard viewer chain, the return value is NULL. To get extended error information, call GetLastError.

Remarks

The windows that are part of the clipboard viewer chain, called clipboard viewer windows, must process the clipboard messages WM_CHANGECBCHAIN and WM_DRAWCLIPBOARD. Each clipboard viewer window calls the SendMessage function to pass these messages to the next window in the clipboard viewer chain.

A clipboard viewer window must eventually remove itself from the clipboard viewer chain by calling the ChangeClipboardChain function — for example, in response to the WM_DESTROY message.

See Also

ChangeClipboardChain, GetClipboardViewer, SendMessage, WM_CHANGECBCHAIN, WM_DRAWCLIPBOARD


SetColorAdjustment
SetColorAdjustment  QuickInfo  Overview  Group

The SetColorAdjustment function sets the color adjustment values for a device context using the specified values.

BOOL SetColorAdjustment(

HDC  hdc,	// handle to device context
CONST COLORADJUSTMENT *  lpca	// pointer to COLORADJUSTMENT structure
);
Parameters

hdc

Identifies the device context.

lpca

Points to a COLORADJUSTMENT structure containing the color adjustment values.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The color adjustment values are used to adjust the input color of the source bitmap for calls to the StretchBlt and StretchDIBits functions when HALFTONE mode is set.

See Also

COLORADJUSTMENT, SetStretchBltMode, StretchBlt, StretchDIBits


SetColorSpace [New - Windows 95]
SetColorSpace  QuickInfo  Overview  Group

[New - Windows 95]

The SetColorSpace function sets the color space for the specified device context, defining the endpoints of the logical RGB space in CIE XYZ space.

BOOL SetColorSpace(

HDC  hdc	// handle to the device context
HCOLORSPACE  hColorSpace	// handle to the logical color space
);
Parameters

hdc

Handle to the device context.

hColorSpace

Handle to the logical color space.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

See Also

RGB


SetCommBreak
SetCommBreak  QuickInfo  Overview  Group

The SetCommBreak function suspends character transmission for a specified communications device and places the transmission line in a break state until the ClearCommBreak function is called.

BOOL SetCommBreak(

HANDLE  hCommDev	// handle of communications device
);
Parameters

hCommDev

Identifies the communications device. The CreateFile function returns this handle.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The SetCommBreak function does not flush data that has not been transmitted.

See Also

ClearCommBreak, CreateFile


SetCommConfig [New - Windows 95]
SetCommConfig  QuickInfo  Overview  Group

[New - Windows 95]

The SetCommConfig function sets the current configuration of a communications device.

BOOL SetCommConfig(

HANDLE hCommDev,	// handle of communications device
LPBYTE lpCC,	// address of comm. configuration services
DWORD dwSize	// size of structure
);
Parameters

hCommDev

Identifies the open communications device.

lpCC

Points to a COMMCONFIG structure.

dwSize

Specifies the size, in bytes, of the structure pointed to by lpCC.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

COMMCONFIG


SetCommMask
SetCommMask  QuickInfo  Overview  Group

The SetCommMask function specifies a set of events to be monitored for a communications device.

BOOL SetCommMask(

HANDLE  hCommDev,	// handle of communications device
DWORD  fdwEvtMask	// mask that identifies enabled events
);
Parameters

hCommDev

Identifies the communications device. The CreateFile function returns this handle.

fdwEvtMask

Specifies the events to be enabled. A value of zero disables all events. This parameter can be a combination of the following values:

Value	Meaning
EV_BREAK	A break was detected on input.
EV_CTS	The CTS (clear-to-send) signal changed state.
EV_DSR	The DSR (data-set-ready) signal changed state.
EV_ERR	A line-status error occurred. Line-status errors are CE_FRAME, CE_OVERRUN, and CE_RXPARITY.
EV_RING	A ring indicator was detected.
EV_RLSD	The RLSD (receive-line-signal-detect) signal changed state.
EV_RXCHAR	A character was received and placed in the input buffer.
EV_RXFLAG	The event character was received and placed in the input buffer. The event character is specified in the device's DCB structure, which is applied to a serial port by using the SetCommState function.
EV_TXEMPTY	The last character in the output buffer was sent.
Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The SetCommMask function specifies the set of events that can be monitored for a particular communications resource. A handle to the communications resource can be specified in a call to the WaitCommEvent function, which waits for one of the events to occur. To get the current event mask of a communications resource, use the GetCommMask function.

If SetCommMask is called for a communications resource while an overlapped wait is pending for that resource, WaitCommEvent returns an error.

See Also

CreateFile, DCB, GetCommMask, SetCommState, WaitCommEvent


SetCommState
SetCommState  QuickInfo  Overview  Group

The SetCommState function configures a communications device according to the specifications in a device-control block (a DCB structure). The function reinitializes all hardware and control settings, but it does not empty output or input queues.

BOOL SetCommState(

HANDLE  hCommDev,	// handle of communications device
LPDCB  lpdcb	// address of device-control block structure
);
Parameters

hCommDev

Identifies the communications device. The CreateFile function returns this handle.

lpdcb

Points to a DCB structure containing the configuration information for the specified communications device.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The SetCommState function uses a DCB structure to specify the desired configuration. The GetCommState function returns the current configuration.

To set only a few members of the DCB structure, you should modify a DCB structure that has been filled in by a call to GetCommState. This ensures that the other members of the DCB structure have appropriate values.

The SetCommState function fails if the XonChar member of the DCB structure is equal to the XoffChar member.

When SetCommState is used to configure the 8250, the following restrictions apply to the values for the DCB structure's ByteSize and StopBits members:

•	The number of data bits must be 5 to 8 bits.

•	The use of 5 data bits with 2 stop bits is an invalid combination, as are 6, 7, or 8 data bits with 1.5 stop bits.

See Also

BuildCommDCB, CreateFile, DCB, GetCommState


SetCommTimeouts
SetCommTimeouts  QuickInfo  Overview  Group

The SetCommTimeouts function sets the time-out parameters for all read and write operations on a specified communications device.

BOOL SetCommTimeouts(

HANDLE  hCommDev,	// handle of communications device
LPCOMMTIMEOUTS  lpctmo	// address of communications time-out structure
);
Parameters

hCommDev

Identifies the communications device. The CreateFile function returns this handle.

lpctmo

Points to a COMMTIMEOUTS structure that contains the new time-out values.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

COMMTIMEOUTS, GetCommTimeouts, ReadFile, ReadFileEx, WriteFile, WriteFileEx


SetComputerName
SetComputerName  QuickInfo  Overview  Group

The SetComputerName function sets the computer name to be used the next time the system is restarted.

BOOL SetComputerName(

LPCTSTR  lpszName	// address of new computer name
);
Parameters

lpszName

Points to a null-terminated character string that specifies the name that will be the computer name the next time the computer is started. The name must not be longer than MAX_COMPUTERNAME_LENGTH characters.

Windows 95: If this string contains one or more characters that are outside the standard character set, those characters are coerced into standard characters.

Windows NT: If this string contains one or more characters that are outside the standard character set, SetComputerName returns ERROR_INVALID_PARAMETER. It does not coerce the characters outside the standard set.

The standard character set includes letters, numbers, and the following symbols: ! @ # $ % ^ & ' ) ( . - _ { } ~ .

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Applications using this function must have administrator rights.

See Also

GetComputerName


SetConsoleActiveScreenBuffer
SetConsoleActiveScreenBuffer  QuickInfo  Overview  Group

The SetConsoleActiveScreenBuffer function sets the specified screen buffer to be the currently displayed console screen buffer.

BOOL SetConsoleActiveScreenBuffer(

HANDLE  hConsoleOutput	// handle of console screen buffer
);
Parameters

hConsoleOutput

Identifies a console screen buffer.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

A console can have multiple screen buffers. SetConsoleActiveScreenBuffer determines which one is displayed. You can write to an inactive screen buffer and then use SetConsoleActiveScreenBuffer to display the buffer's contents.

See Also

CreateConsoleScreenBuffer


SetConsoleCP
SetConsoleCP  QuickInfo  Overview  Group

The SetConsoleCP function sets the input code page used by the console associated with the calling process. A console uses its input code page to translate keyboard input into the corresponding character value.

BOOL SetConsoleCP(

UINT  IDCodePage	// code page to set
);
Parameters

IDCodePage

Specifies the identifier of the code page to set. The identifiers of the code pages available on the local computer are stored in the registry under the following key.

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\CodePage

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

A code page maps 256 character codes to individual characters. Different code pages include different special characters, typically customized for a language or a group of languages.

To determine a console's current input code page, use the GetConsoleCP function. To set and retrieve a console's output code page, use the SetConsoleOutputCP and GetConsoleOutputCP functions.

See Also

GetConsoleCP, GetConsoleOutputCP, SetConsoleOutputCP


SetConsoleCtrlHandler
SetConsoleCtrlHandler  QuickInfo  Overview  Group

The SetConsoleCtrlHandler function adds or removes an application-defined HandlerRoutine function from the list of handler functions for the calling process. If no handler function is specified, the function sets an inheritable attribute that determines whether the calling process ignores CTRL+C signals.

BOOL SetConsoleCtrlHandler(

PHANDLER_ROUTINE  pHandlerRoutine,	// address of handler function
BOOL  fAdd	// handler to add or remove
);
Parameters

pHandlerRoutine

Points to the application-defined HandlerRoutine function to add or remove. This parameter can be NULL.

fAdd

Specifies whether to add or remove the function pointed to by the pHandlerRoutine parameter from the handler list. If this parameter is TRUE, the handler is added; if it is FALSE, the handler is removed.

If the pHandlerRoutine parameter is NULL, a TRUE value causes the calling process to ignore CTRL+C input, and a FALSE value restores normal processing of CTRL+C input. This attribute of ignoring or processing CTRL+C is inherited by child processes.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Each console process has its own list of application-defined HandlerRoutine functions that handle CTRL+C and CTRL+BREAK signals. The handler functions also handle signals generated by the system when the user closes the console, logs off, or shuts down the system. Initially, the handler list for each process contains only a default handler function that calls the ExitProcess function. A console process adds or removes additional handler functions by calling the SetConsoleCtrlHandler function, which does not affect the list of handler functions for other processes. When a console process receives any of the control signals, its handler functions are called on a last-registered, first-called basis until one of the handlers returns TRUE. If none of the handlers returns TRUE, the default handler is called.

For console processes, the CTRL+C and CTRL+BREAK key combinations are typically treated as signals (CTRL_C_EVENT and CTRL_C_BREAK_EVENT). When a console window with the keyboard focus receives CTRL+C or CTRL+BREAK, the signal is typically passed to all processes sharing that console.

CTRL+BREAK is always treated as a signal, but typical CTRL+C behavior can be changed in three ways that prevent the handler functions from being called:

•	The SetConsoleMode function can disable the ENABLE_PROCESSED_INPUT mode for a console's input buffer, so CTRL+C is reported as keyboard input rather than as a signal.

•	Calling SetConsoleCtrlHandler with the NULL and TRUE arguments causes the calling process to ignore CTRL+C signals. This attribute is inherited by child processes, but it can be enabled or disabled by any process without affecting existing processes.

•	If a console process is being debugged and CTRL+C signals have not been disabled, the kernel generates a DBG_CONTROL_C exception. This exception is raised only for the benefit of the debugger, and an application should never use an exception handler to deal with it. If the debugger handles the exception, an application will not notice the CTRL+C, with one exception: alertable waits will terminate. If the debugger passes the exception on unhandled, CTRL+C is passed to the console process and treated as a signal, as previously discussed.

A console process can use the GenerateConsoleCtrlEvent function to send a CTRL+C or CTRL+BREAK signal to a console process group.

The system generates CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT, and CTRL_SHUTDOWN_EVENT signals when the user closes the console, logs off, or shuts down the system so that the process has an opportunity to clean up before termination. Console functions, or any C run-time functions that call console functions, may not work reliably during processing of any of the three signals mentioned previously. The reason is that some or all of the internal console cleanup routines may have been called before executing the process signal handler.

See Also

ExitProcess, GenerateConsoleCtrlEvent, GetConsoleMode, HandlerRoutine, SetConsoleMode


SetConsoleCursorInfo
SetConsoleCursorInfo  QuickInfo  Overview  Group

The SetConsoleCursorInfo function sets the size and visibility of the cursor for the specified console screen buffer.

BOOL SetConsoleCursorInfo(

HANDLE  hConsoleOutput,	// handle of console screen buffer
PCONSOLE_CURSOR_INFO  pcci	// address of cursor information
);
Parameters

hConsoleOutput

Identifies a console screen buffer. The handle must have GENERIC_WRITE access.

pcci

Points to a CONSOLE_CURSOR_INFO structure containing the new specifications for the screen buffer's cursor.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

When a screen buffer's cursor is visible, its appearance can vary, ranging from completely filling a character cell to showing up as a horizontal line at the bottom of the cell. The dwSize member of the CONSOLE_CURSOR_INFO structure specifies the percentage of a character cell that is filled by the cursor. If this member is less than 1 or greater than 100, SetConsoleCursorInfo fails.

See Also

CONSOLE_CURSOR_INFO, GetConsoleCursorInfo, SetConsoleCursorPosition


SetConsoleCursorPosition
SetConsoleCursorPosition  QuickInfo  Overview  Group

The SetConsoleCursorPosition function sets the cursor position in the specified console screen buffer.

BOOL SetConsoleCursorPosition(

HANDLE  hConsoleOutput,	// handle of console screen buffer
COORD  coordCursor	// new cursor position coordinates
);
Parameters

hConsoleOutput

Identifies a console screen buffer. The handle must have GENERIC_WRITE access.

coordCursor

Specifies a COORD structure containing the new cursor position. The coordinates are the column and row of a screen buffer character cell. The coordinates must be within the boundaries of the screen buffer.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The cursor position determines where characters written by the WriteFile or WriteConsole function, or echoed by the ReadFile or ReadConsole function, are displayed. To determine the current position of the cursor, use the GetConsoleScreenBufferInfo function.

If the new cursor position is not within the boundaries of the screen buffer's window, the window origin changes to make the cursor visible.

See Also

GetConsoleCursorInfo, GetConsoleScreenBufferInfo, ReadConsole, ReadFile, SetConsoleCursorInfo, WriteConsole, WriteFile


SetConsoleMode
SetConsoleMode  QuickInfo  Overview  Group

The SetConsoleMode function sets the input mode of a console's input buffer or the output mode of a console screen buffer.

BOOL SetConsoleMode(

HANDLE  hConsole,	// handle of console input or screen buffer
DWORD  fdwMode	// input or output mode to set
);
Parameters

hConsole

Identifies a console input buffer or a screen buffer. The handle must have GENERIC_WRITE access.

fdwMode

Specifies the input or output mode to set. If the hConsole parameter is an input handle, the mode can be a combination of the following values. When a console is created, all input modes except ENABLE_WINDOW_INPUT are enabled by default.

Value	Meaning
ENABLE_LINE_INPUT	The ReadFile or ReadConsole function returns only when a carriage return character is read. If this mode is disabled, the functions return when one or more characters are available.
ENABLE_ECHO_INPUT	Characters read by the ReadFile or ReadConsole function are written to the active screen buffer as they are read. This mode can be used only if the ENABLE_LINE_INPUT mode is also enabled.
ENABLE_PROCESSED_INPUT	CTRL+C is processed by the system and is not placed in the input buffer. If the input buffer is being read by ReadFile or ReadConsole, other control keys are processed by the system and are not returned in the ReadFile or ReadConsole buffer. If the ENABLE_LINE_INPUT mode is also enabled, backspace, carriage return, and linefeed characters are handled by the system.
ENABLE_WINDOW_INPUT	User interactions that change the size of the console screen buffer are reported in the console's input buffer. Information about these events can be read from the input buffer by applications using the ReadConsoleInput function, but not by those using ReadFile or ReadConsole.
ENABLE_MOUSE_INPUT	If the mouse pointer is within the borders of the console window and the window has the keyboard focus, mouse events generated by mouse movement and button presses are placed in the input buffer. These events are discarded by ReadFile or ReadConsole, even when this mode is enabled.
If the hConsole parameter is a screen buffer handle, the mode can be a combination of the following values. When a screen buffer is created, both output modes are enabled by default.

Value	Meaning
ENABLE_PROCESSED_OUTPUT	Characters written by the WriteFile or WriteConsole function or echoed by the ReadFile or ReadConsole function are examined for ASCII control sequences and the correct action is performed. Backspace, tab, bell, carriage return, and linefeed characters are processed.
ENABLE_WRAP_AT_EOL_OUTPUT	When writing with WriteFile or WriteConsole or echoing with ReadFile or ReadConsole, the cursor moves to the beginning of the next row when it reaches the end of the current row. This causes the rows displayed in the console window to scroll up automatically when the cursor advances beyond the last row in the window. It also causes the contents of the screen buffer to scroll up (discarding the top row of the screen buffer) when the cursor advances beyond the last row in the screen buffer. If this mode is disabled, the last character in the row is overwritten with any subsequent characters.
Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

A console consists of an input buffer and one or more screen buffers. The mode of a console buffer determines how the console behaves during input and output (I/O) operations. One set of flag constants is used with input handles, and another set is used with screen buffer (output) handles. Setting the output modes of one screen buffer does not affect the output modes of other screen buffers.

The ENABLE_LINE_INPUT and ENABLE_ECHO_INPUT modes only affect processes that use ReadFile or ReadConsole to read from the console's input buffer. Similarly, the ENABLE_PROCESSED_INPUT mode primarily affects ReadFile and ReadConsole users, except that it also determines whether CTRL+C input is reported in the input buffer (to be read by the ReadConsoleInput function) or is passed to a HandlerRoutine function defined by the application.

The ENABLE_WINDOW_INPUT and ENABLE_MOUSE_INPUT modes determine whether user interactions involving window resizing and mouse actions are reported in the input buffer or discarded. These events can be read by ReadConsoleInput, but they are always filtered by ReadFile and ReadConsole.

The ENABLE_PROCESSED_OUTPUT and ENABLE_WRAP_AT_EOL_OUTPUT modes only affect processes using ReadFile or ReadConsole and WriteFile or WriteConsole.

To determine the current mode of a console input buffer or a screen buffer, use the GetConsoleMode function.

See Also

GetConsoleMode, HandlerRoutine, ReadConsole, ReadConsoleInput, ReadFile, WriteConsole, WriteFile


SetConsoleOutputCP
SetConsoleOutputCP  QuickInfo  Overview  Group

The SetConsoleOutputCP function sets the output code page used by the console associated with the calling process. A console uses its output code page to translate the character values written by the various output functions into the images displayed in the console window.

BOOL SetConsoleOutputCP(

UINT  IDCodePage	// code page to set
);
Parameters

IDCodePage

Specifies the identifier of the code page to set. The identifiers of the code pages available on the local computer are stored in the registry under the following key.

   HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\CodePage

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

A code page maps 256 character codes to individual characters. Different code pages include different special characters, typically customized for a language or a group of languages.

To determine a console's current output code page, use the GetConsoleOutputCP function. To set and retrieve a console's input code page, use the SetConsoleCP and GetConsoleCP functions.

See Also

GetConsoleCP, GetConsoleOutputCP, SetConsoleCP


SetConsoleScreenBufferSize
SetConsoleScreenBufferSize  QuickInfo  Overview  Group

The SetConsoleScreenBufferSize function changes the size of the specified console screen buffer.

BOOL SetConsoleScreenBufferSize(

HANDLE  hConsoleOutput,	// handle of console screen buffer
COORD  coordSize	// new size in character rows and cols.
);
Parameters

hConsoleOutput

Identifies a console screen buffer. The handle must have GENERIC_WRITE access.

coordSize

Specifies a COORD structure containing the new size, in rows and columns, of the screen buffer. The specified width and height cannot be less than the width and height of the screen buffer's window. The specified dimensions also cannot be less than the minimum size allowed by the system. This minimum depends on the current font size for the console (selected by the user) and the SM_CXMIN and SM_CYMIN values returned by the GetSystemMetrics function.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

COORD, GetConsoleScreenBufferInfo, SetConsoleWindowInfo


SetConsoleTextAttribute
SetConsoleTextAttribute  QuickInfo  Overview  Group

The SetConsoleTextAttribute function sets the foreground (text) and background color attributes of characters written to the screen buffer by the WriteFile or WriteConsole function, or echoed by the ReadFile or ReadConsole function. This function affects only text written after the function call.

BOOL SetConsoleTextAttribute(

HANDLE  hConsoleOutput,	// handle of console screen buffer
WORD  wAttr	// text and background colors
);
Parameters

hConsoleOutput

Identifies a console screen buffer. The handle must have GENERIC_READ access.

wAttr

Specifies the foreground and background color attributes. Any combination of the following values can be specified: FOREGROUND_BLUE, FOREGROUND_GREEN, FOREGROUND_RED, FOREGROUND_INTENSITY, BACKGROUND_BLUE, BACKGROUND_GREEN, BACKGROUND_RED, and BACKGROUND_INTENSITY. For example, the following combination of values produces white text on a black background:

FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

To determine the current color attributes of a screen buffer, call the GetConsoleScreenBufferInfo function.

See Also

GetConsoleScreenBufferInfo, ReadConsole, ReadFile, WriteConsole, WriteFile


SetConsoleTitle
SetConsoleTitle  QuickInfo  Overview  Group

The SetConsoleTitle function sets the title bar string for the current console window.

BOOL SetConsoleTitle(

LPTSTR  lpszTitle	// address of new title
);
Parameters

lpszTitle

Points to a null-terminated string that contains the string to appear in the title bar of the console window.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

GetConsoleTitle


SetConsoleWindowInfo
SetConsoleWindowInfo  QuickInfo  Overview  Group

The SetConsoleWindowInfo function sets the current size and position of a console screen buffer's window.

BOOL SetConsoleWindowInfo(

HANDLE  hConsoleOutput,	// handle of console screen buffer
BOOL  fAbsolute,	// coordinate type flag
PSMALL_RECT  psrctWindowRect	// address of new window rectangle
);
Parameters

hConsoleOutput

Identifies a console screen buffer. The handle must have GENERIC_WRITE access.

fAbsolute

Specifies how the coordinates in the structure pointed to by the psrctWindowRect parameter are used. If fAbsolute is TRUE, the coordinates specify the new upper-left and lower-right corners of the window. If it is FALSE, the coordinates are offsets to the current window-corner coordinates.

psrctWindowRect

Points to a SMALL_RECT structure that contains values that determine the new upper-left and lower-right corners of the window.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The function fails if the specified window rectangle extends beyond the boundaries of the screen buffer. This means that the Top and Left members of the psrctWindowRect rectangle (or the calculated top and left coordinates, if fAbsolute is FALSE) cannot be less than zero. Similarly, the Bottom and Right members (or the calculated bottom and right coordinates) cannot be greater than (screen buffer height − 1) and (screen buffer width − 1), respectively. The function also fails if the Right member (or calculated right coordinate) is less than or equal to the Left member (or calculated left coordinate) or if the Bottom member (or calculated bottom coordinate) is less than or equal to the Top member (or calculated top coordinate).

For consoles with more than one screen buffer, changing the window location for one screen buffer does not affect the window locations of the other screen buffers.

To determine the current size and position of a screen buffer's window, use the GetConsoleScreenBufferInfo function. This function also returns the maximum size of the window, given the current screen buffer size, the current font size, and the screen size. The GetLargestConsoleWindowSize function returns the maximum window size given the current font and screen sizes, but it does not consider the size of the screen buffer.

SetConsoleWindowInfo can be used to scroll the contents of the screen buffer by shifting the position of the window rectangle without changing its size.

See Also

GetConsoleScreenBufferInfo, GetLargestConsoleWindowSize, SMALL_RECT, ScrollConsoleScreenBuffer


SetCurrentDirectory
SetCurrentDirectory  QuickInfo  Overview  Group

The SetCurrentDirectory function changes the current directory for the current process.

BOOL SetCurrentDirectory(

LPCTSTR  lpszCurDir	// address of name of new current directory
);
Parameters

lpszCurDir

Points to a null-terminated string that specifies the path to the new current directory. This parameter may be a relative path or a fully qualified path. In either case, the fully qualified path of the specified directory is calculated and stored as the current directory.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Each process has a single current directory made up of two parts:

•	A disk designator that is either a drive letter followed by a colon, or a server name and share name (\\servername\sharename)

•	A directory on the disk designator

See Also

GetCurrentDirectory


SetCursor
SetCursor  QuickInfo  Overview  Group

The SetCursor function establishes the cursor shape.

HCURSOR SetCursor(

HCURSOR  hcur	// handle of cursor
);
Parameters

hcur

Identifies the cursor. The cursor must have been created by the CreateCursor or loaded by one of the following functions:

Windows 95: LoadCursor function or LoadImage

Windows NT: LoadCursor

If this parameter is NULL, the cursor is removed from the screen.

Return Value

The return value is the handle of the previous cursor, if there was one. If there was no previous cursor, the return value is NULL.

Remarks

The cursor is set only if the new cursor is different from the previous cursor; otherwise, the function returns immediately.

The cursor is a shared resource. A window should set the cursor shape only when the cursor is in its client area or when the window is capturing mouse input. In systems without a mouse, the window should restore the previous cursor before the cursor leaves the client area or before it relinquishes control to another window.

If your application must set the cursor while it is in a window, make sure the class cursor for the specified window's class is set to NULL. If the class cursor is not NULL, the system restores the class cursor each time the mouse is moved.

The cursor is not shown on the screen if the internal cursor display count is less than zero. This occurs if the application uses the ShowCursor function to hide the cursor more times than to show the cursor.

See Also

CreateCursor, LoadCursor, LoadImage, SetCursorPos, ShowCursor


SetCursorPos
SetCursorPos  QuickInfo  Overview  Group

The SetCursorPos function moves the cursor to the specified screen coordinates. If the new coordinates are not within the screen rectangle set by the most recent ClipCursor function, Windows automatically adjusts the coordinates so that the cursor stays within the rectangle.

BOOL SetCursorPos(

int  X,	// horizontal position
int  Y	// vertical position
);
Parameters

X

Specifies the new x-coordinate, in screen coordinates, of the cursor.

Y

Specifies the new y-coordinate, in screen coordinates, of the cursor.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The cursor is a shared resource. A window should move the cursor only when the cursor is in its client area.

The calling process must have WINSTA_WRITEATTRIBUTES access to the window station.

See Also

ClipCursor, GetCursorPos, SetCaretPos, SetCursor, ShowCursor


SetDebugErrorLevel
SetDebugErrorLevel  QuickInfo  Overview  Group

The SetDebugErrorLevel function sets the minimum error level at which Windows will generate debugging events and pass them to a debugger.

VOID SetDebugErrorLevel(

DWORD  dwLevel	// debugging error level
);
Parameters

dwLevel

Specifies the minimum error level for debugging events. If an error is equal to or above this level, Windows generates a debugging event. This parameter must be one of the following values:

Value	Meaning
0	Does not report any errors. This value is the default error level.
SLE_ERROR	Reports only ERROR level debugging events.
SLE_MINORERROR	Reports only MINORERROR level and ERROR level debugging events.
SLE_WARNING	Reports WARNING level, MINORERROR level, and ERROR level debugging events.
Return Value

This function does not return a value.

Remarks

The debugger calls SetDebugErrorLevel to specify the types of errors that it should be notified about.

If the debugging error level is greater than the error that occurred, the value for the GetLastError function is set, but the kernel does not generate a debugging event.


SetDefaultCommConfig [New - Windows 95]
SetDefaultCommConfig  QuickInfo

[New - Windows 95]

The SetDefaultCommConfig function sets the default configuration for a communications device.

BOOL SetDefaultCommConfig(

LPCSTR lpszName,	//
LPCOMMCONFIG lpCC,	//
DWORD dwSize	//
);
Parameters

lpszName

Points to a null-terminated string specifying the name of the device.

lpCC

Points to a COMMCONFIG structure. If this parameter is NULL, the default configuration is set to the device driver's defaults.

dwSize

Specifies the size, in bytes, of the structure pointed to by lpCC.

Return value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

COMMCONFIG


SetDeviceGammaRamp [New - Windows 95]
SetDeviceGammaRamp  QuickInfo  Overview  Group

[New - Windows 95]

The SetDeviceGammaRamp function sets the gamma ramp on direct color display boards.

BOOL SetDeviceGammaRamp(

HDC  hdc,
LPVOID  lpRamp
);
Parameters

hdc

Handle to the device context.

lpRamp

Pointer to a set of three arrays of 256-byte elements. These arrays are the mapping between color values in the frame buffer and DAC values. The first array is red, the next is green, and the final one is blue.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

Direct color display modes do not use color look-up tables. The direct color modes are usually 16-, 24-, or 32-bit. Not all direct color video boards support loadable gamma ramps. This function succeeds only for those drivers that support loadable gamma ramps in hardware.


SetDIBColorTable
SetDIBColorTable  QuickInfo  Overview  Group

The SetDIBColorTable function sets RGB (red, green, blue) color values in a range of entries in the color table of the device-independent bitmap (DIB) that is currently selected into a specified device context.

UINT SetDIBColorTable(

HDC hdc,	// handle of device context whose DIB is of interest
UINT uStartIndex,	// color table index of first entry to set
UINT cEntries,	// number of color table entries to set
RGBQUAD *pColors	// pointer to array of color table entries
);
Parameters

hdc

Specifies a device context. A device-independent bitmap must be selected into this device context.

uStartIndex

A zero-based color table index that specifies the first color table entry to set.

cEntries

Specifies the number of color table entries to set.

pColors

Points to an array of RGBQUAD structures containing new color information for the DIB's color table.

Return Value

If the function succeeds, the return value is the number of color table entries that the function sets.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

This function should be called to set the color table for device-independent bitmaps that use 1, 4, or 8 bits per pixel. The biBitCount member of a bitmap's associated BITMAPINFOHEADER structure specifies the number of bits per pixel. Device-independent bitmaps with a biBitCount value greater than 8 do not have a color table.

See Also

BITMAPINFOHEADER, CreateDIBSection, GetDIBColorTable, GetObject, DIBSECTION, RGBQUAD


SetDIBits
SetDIBits  QuickInfo  Overview  Group

The SetDIBits function sets the pixels in a bitmap using the color data found in the specified device-independent bitmap (DIB).

int SetDIBits(

HDC  hdc,	// handle of device context
HBITMAP  hbmp,	// handle of bitmap
UINT  uStartScan,	// starting scan line
UINT  cScanLines,	// number of scan lines
CONST VOID *  lpvBits,	// array of bitmap bits
CONST BITMAPINFO *  lpbmi,	// address of structure with bitmap data
UINT  fuColorUse	// type of color indices to use
);
Parameters

hdc

Identifies a device context.

hbmp

Identifies the bitmap that is to be altered using the color data from the specified DIB.

uStartScan

Specifies the starting scan line for the device-independent color data in the array pointed to by the lpvBits parameter.

cScanLines

Specifies the number of scan lines found in the array containing device-independent color data.

lpvBits

Points to the DIB color data, stored as an array of bytes. The format of the bitmap values depends on the biBitCount member of the BITMAPINFO structure pointed to by the lpbmi parameter.

lpbmi

Points to a BITMAPINFO data structure that contains information about the DIB.

fuColorUse

Specifies whether the bmiColors member of the BITMAPINFO structure was provided and, if so, whether bmiColors contains explicit red, green, blue (RGB) values or palette indices. The fuColorUse parameter must be one of the following values:

Value	Meaning
DIB_PAL_COLORS	The color table consists of an array of 16-bit indices into the logical palette of the device context identified by the hdc parameter.
DIB_RGB_COLORS	The color table is provided and contains literal RGB values.
Return Value

If the function succeeds, the return value is the number of scan lines copied.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

Optimal bitmap drawing speed is obtained when the bitmap bits are indices into the system palette.

Applications can retrieve the system palette colors and indices by calling the GetSystemPaletteEntries function. After the colors and indices are retrieved, the application can create the DIB. For more information, see System Palette.

The device context identified by the hdc parameter is used only if the DIB_PAL_COLORS constant is set for the fuColorUse parameter; otherwise it is ignored.

The bitmap identified by the hbmp parameter must not be selected into a device context when the application calls this function.

The origin for bottom-up DIBs is the lower-left corner of the bitmap; the origin for top-down DIBs is the upper-left corner of the bitmap.

See Also

BITMAPINFO, GetSystemPaletteEntries


SetDIBitsToDevice
SetDIBitsToDevice  QuickInfo  Overview  Group

The SetDIBitsToDevice function sets the pixels in the specified rectangle on the device that is associated with the destination device context using color data from a device-independent bitmap (DIB).

int SetDIBitsToDevice(

HDC  hdc,	// handle of device context
int  XDest,	// x-coordinate of upper-left corner of dest. rect.
int  YDest,	// y-coordinate of upper-left corner of dest. rect.
DWORD  dwWidth,	// source rectangle width
DWORD  dwHeight,	// source rectangle height
int  XSrc,	// x-coordinate of lower-left corner of source rect.
int  YSrc,	// y-coordinate of lower-left corner of source rect.
UINT  uStartScan,	// first scan line in array
UINT  cScanLines,	// number of scan lines
CONST VOID *  lpvBits,	// address of array with DIB bits
CONST BITMAPINFO *  lpbmi,	// address of structure with bitmap info.
UINT  fuColorUse	// RGB or palette indices
);
Parameters

hdc

Identifies the device context.

XDest

Specifies the x-coordinate, in logical units, of the upper-left corner of the destination rectangle.

YDest

Specifies the y-coordinate, in logical units, of the upper-left corner of the destination rectangle.

dwWidth

Specifies the width, in logical units, of the DIB.

dwHeight

Specifies the height, in logical units, of the DIB.

XSrc

Specifies the x-coordinate, in logical units, of the lower-left corner of the DIB.

YSrc

Specifies the y-coordinate, in logical units, of the lower-left corner of the DIB.

uStartScan

Specifies the starting scan line in the DIB.

cScanLines

Specifies the number of DIB scan lines contained in the array pointed to by the lpvBits parameter.

lpvBits

Points to DIB color data stored as an array of bytes.

lpbmi

Points to a BITMAPINFO structure that contains information about the DIB.

fuColorUse

Specifies whether the bmiColors member of the BITMAPINFO structure contains explicit red, green, blue (RGB) values or indices into a palette. The fuColorUse parameter must be one of the following values:

Value	Meaning
DIB_PAL_COLORS	The color table consists of an array of 16-bit indices into the currently selected logical palette.
DIB_RGB_COLORS	The color table contains literal RGB values.
Return Value

If the function succeeds, the return value is the number of scan lines set.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

Optimal bitmap drawing speed is obtained when the bitmap bits are indices into the system palette.

Applications can retrieve the system palette colors and indices by calling the GetSystemPaletteEntries function. After the colors and indices are retrieved, the application can create the DIB. For more information about the system palette, see Colors.

The origin of a bottom-up DIB is the lower-left corner of the bitmap; the origin of a top-down DIB is the upper-left corner.

To reduce the amount of memory required to set bits from a large device-independent bitmap on a device surface, an application can band the output by repeatedly calling SetDIBitsToDevice, placing a different portion of the bitmap into the lpvBits array each time. The values of the uStartScan and cScanLines parameters identify the portion of the bitmap contained in the lpvBits array.

Windows 95: The SetDIBitsToDevice function returns an error if it is called by a process that is running in the background while a full-screen MS-DOS runs in the foreground.

See Also

BITMAPINFO, GetSystemPaletteEntries, SetDIBits, StretchDIBits


SetDlgItemInt
SetDlgItemInt  QuickInfo  Overview  Group

The SetDlgItemInt function sets the text of a control in a dialog box to the string representation of a specified integer value.

BOOL SetDlgItemInt(

HWND  hwndDlg,	// handle of dialog box
int  idControl,	// identifier of control
UINT  uValue,	// value to set
BOOL  fSigned	// signed or unsigned indicator
);
Parameters

hwndDlg

Identifies the dialog box that contains the control.

idControl

Specifies the control to be changed.

uValue

Specifies the integer value used to generate the item text.

fSigned

Specifies whether the uValue parameter is signed or unsigned. If this parameter is TRUE, uValue is signed. If this parameter is TRUE and uValue is less than zero, a minus sign is placed before the first digit in the string. If this parameter is FALSE, uValue is unsigned.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

To set the new text, this function sends a WM_SETTEXT message to the specified control.

See Also

GetDlgItemInt, SetDlgItemText, WM_SETTEXT


SetDlgItemText
SetDlgItemText  QuickInfo  Overview  Group

The SetDlgItemText function sets the title or text of a control in a dialog box.

BOOL SetDlgItemText(

HWND  hwndDlg,	// handle of dialog box
int  idControl,	// identifier of control
LPCTSTR  lpsz	// text to set
);
Parameters

hwndDlg

Identifies the dialog box that contains the control.

idControl

Identifies the control with a title or text that is to be set.

lpsz

Points to the null-terminated string that contains the text to be copied to the control.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The SetDlgItemText function sends a WM_SETTEXT message to the specified control.

See Also

GetDlgItemInt, GetDlgItemText, SetDlgItemInt, WM_SETTEXT


SetDoubleClickTime
SetDoubleClickTime  QuickInfo  Overview  Group

The SetDoubleClickTime function sets the double-click time for the mouse. A double-click is a series of two clicks of a mouse button, the second occurring within a specified time after the first. The double-click time is the maximum number of milliseconds that may occur between the first and second clicks of a double-click.

BOOL SetDoubleClickTime(

UINT  uInterval	// double-click interval
);
Parameters

uInterval

Specifies the number of milliseconds that may occur between the first and second clicks of a double-click. If this parameter is set to zero, Windows uses the default double-click time of 500 milliseconds.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

The SetDoubleClickTime function alters the double-click time for all windows in the system.

See Also

GetDoubleClickTime


SetEndOfFile
SetEndOfFile  QuickInfo  Overview  Group

The SetEndOfFile function moves the end-of-file (EOF) position for the specified file to the current position of the file pointer.

BOOL SetEndOfFile(

HANDLE  hFile	// handle of file whose EOF is to be set
);
Parameters

hFile

Identifies the file to have its EOF position moved. The file handle must have been created with GENERIC_WRITE access to the file.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

This function can be used to truncate or extend a file. If the file is extended, the contents of the file between the old EOF position and the new position are not defined.

If you called CreateFileMapping to create a file-mapping object for hFile, you must first call UnmapViewOfFile to unmap all views and call CloseHandle to close the file-mapping object before you can call SetEndOfFile.

See Also

CloseHandle, CreateFile, CreateFileMapping, UnmapViewOfFile


SetEnhMetaFileBits
SetEnhMetaFileBits  QuickInfo  Overview  Group

The SetEnhMetaFileBits function creates a memory-based enhanced-format metafile from the supplied data.

HENHMETAFILE SetEnhMetaFileBits(

UINT  cbBuffer,	// buffer size
CONST BYTE *  lpData	// buffer that contains enhanced metafile data
);
Parameters

cbBuffer

Specifies the size, in bytes, of the data provided.

lpData

Points to a buffer that contains enhanced-metafile data. (It is assumed that the data in the buffer was obtained by calling the GetEnhMetaFileBits function.)

Return Value

If the function succeeds, the return value is a handle of a memory-based enhanced metafile.

If the function fails, the return value is NULL.

Remarks

When the application no longer needs the enhanced-metafile handle, it should delete the handle by calling the DeleteEnhMetaFile function.

The SetEnhMetaFileBits function does not accept metafile data in the Windows format. To import Windows-format metafiles, use the SetWinMetaFileBits function.

See Also

DeleteEnhMetaFile, GetEnhMetaFileBits, SetWinMetaFileBits


SetEnvironmentVariable
SetEnvironmentVariable  QuickInfo  Overview  Group

The SetEnvironmentVariable function sets the value of an environment variable for the current process.

BOOL SetEnvironmentVariable(

LPCTSTR  lpszName,	// address of environment variable name
LPCTSTR  lpszValue	// address of new value for variable
);
Parameters

lpszName

Points to a null-terminated string that specifies the environment variable whose value is being set. The operating system creates the environment variable if it does not exist and lpszValue is not NULL.

lpszValue

Points to a null-terminated string containing the new value of the specified environment variable. If this parameter is NULL, the variable is deleted from the current process's environment.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

GetEnvironmentVariable


SetErrorMode
SetErrorMode  QuickInfo  Overview  Group

The SetErrorMode function controls how the operating system handles several types of serious errors. You can specify that the operating system will handle these errors or that the application will receive and handle them.

UINT SetErrorMode(

UINT  fuErrorMode	// set of bit flags that specify error-handling properties
);
Parameters

fuErrorMode

A set of bit flags that specify system error-handling properties. The following error mode bit flag constants are defined; you can set any combination of them:

Value	Action
SEM_FAILCRITICALERRORS	If this flag is set, the operating system does not display the critical-error-handler message box when such an error occurs. Instead, the operating system sends the error to the calling process.
SEM_NOALIGNMENTFAULTEXCEPT	If this flag is set, the operating system automatically fixes memory alignment faults and makes them invisible to the application. It does this for the calling process and any descendant processes.  This flag always affects MIPS processors. It has no effect on x86 processors. If the registry value \CurrentControlSet\Control\Session Manager:EnableAlignmentFaultExceptions is set to REG_DWORD 0x0, this key has no effect on ALPHA processors. That is the system default. If the registry key is set to REG_DWORD 0x1, the SEM_NOALIGNMENTFAULTEXCEPT flag does affect ALPHA processors.
SEM_NOGPFAULTERRORBOX	If this flag is set, the operating system does not display the general-protection-fault message box when such an error occurs. This flag should only be set by debugging applications that handle general protection (GP) faults themselves via an appropriate exception handler.
SEM_NOOPENFILEERRORBOX	If this flag is set, the operating system does not display a message box when it fails to find a a file. Instead, the error is returned to the calling process.
Return Value

The return value is the previous state of the error-mode bit flags.

Remarks

A child process inherits the error mode of its parent process.

The default state for the error mode properties set by this function is OFF.

On some non-x86 processors misaligned memory references cause an alignment fault exception. The SEM_NOALIGNMENTFAULTEXCEPT flag lets you control whether the operating system automatically fixes such alignment faults, or makes them visible to an application.

The SEM_NOALIGNMENTFAULTEXCEPT flag always affects MIPS processors. It never affects x86 processors. It affects ALPHA processors only if the registry key \CurrentControlSet\Control\Session Manager:EnableAlignmentFaultExceptions is set to REG_DWORD 0x1. The default setting for that registry key is REG_DWORD 0x0.

On an x86 platform, an application doesn't need to do anything to have the operating system automatically fix misaligned memory references. The operating system does not make alignment faults visible to an application.

On a MIPS platform, an application must explicitly call SetErrorMode, setting the SEM_NOALIGNMENTFAULTEXCEPT flag, to have the operating system automatically fix alignment faults. The default setting is for the operating system to make alignment faults visible to an application.

On an ALPHA platform, the operating system automatically fixes alignment faults, unless the aforementioned registry key is set to REG_DWORD 0x1. When that registry key is set to REG_DWORD 0x1, the operating system makes alignment faults visible to an application, and an application must then call SetErrorMode to have the operating system automatically fix alignment faults.

Specifying the SEM_NOALIGNMENTFAULTEXCEPT flag on x86 systems is not an error, but implementations of Windows NT are free to silently ignore and not properly preserve the flag. This means that code sequences such as the following are not always valid on x86 systems:

SetErrorMode(SEM_NOALIGNMENTFAULTEXCEPT);

fuOldErrorMode = SetErrorMode(0);

ASSERT(fuOldErrorMode == SEM_NOALIGNMENTFAULTEXCEPT);


SetEvent
SetEvent  QuickInfo  Overview  Group

The SetEvent function sets the state of the specified event object to signaled.

BOOL SetEvent(

HANDLE  hEvent	// handle of event object
);
Parameters

hEvent

Identifies the event object. The CreateEvent or OpenEvent function returns this handle, which must have EVENT_MODIFY_STATE access.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The state of a manual-reset event object remains signaled until it is set explicitly to the nonsignaled state by the ResetEvent function. Any number of waiting threads, or threads that subsequently begin wait operations for the specified event object, can be released while the object's state is signaled.

The state of an auto-reset event object remains signaled until a single waiting thread is released, at which time the system automatically sets the state to nonsignaled. If no threads are waiting, the event object's state remains signaled.

See Also

CreateEvent, MsgWaitForMultipleObjects, OpenEvent, PulseEvent, ResetEvent, WaitForMultipleObjects, WaitForMultipleObjectsEx, WaitForSingleObject, WaitForSingleObjectEx


SetFileApisToANSI
SetFileApisToANSI  QuickInfo  Overview  Group

The SetFileApisToANSI function causes a set of Win32 file functions to use the ANSI character set code page. This function is useful for 8-bit console input and output operations.

VOID SetFileApisToANSI (VOID)

Parameters

This function has no parameters.

Return Value

This function has no return value.

Remarks

The SetFileApisToANSI function complements the SetFileApisToOEM function, which causes the same set of Win32 file functions to use the OEM character set code page.

The 8-bit console functions use the OEM code page by default. All other functions use the ANSI code page by default. This means that strings returned by the console functions may not be processed correctly by other functions, and vice versa. For example, if the FindFirstFileA function returns a string that contains certain extended ANSI characters, and the 8-bit console functions are set to use the OEM code page, then the WriteConsoleA function will not display the string properly.

Use the AreFileApisANSI function to determine which code page the set of file functions is currently using. Use the SetConsoleCP and SetConsoleOutputCP functions to set the code page for the 8-bit console functions.

To solve the problem of code page incompatibility, it is best to use Unicode for console applications. Console applications that use Unicode are much more versatile than those that use 8-bit console functions. Barring that solution, a console application can call the SetFileApisToOEM function to cause the set of Win32 file functions to use OEM character set strings rather than ANSI character set strings. Use the SetFileApisToANSI function to set those functions back to the ANSI code page.

SetFileApisToANSI and SetFileApisToOEM affect these Win32 functions:

_lopen	GetDriveType	LoadLibrary
CopyFile	GetFileAttributes	LoadLibraryEx
CreateDirectory	GetFullPathName	MoveFile
CreateFile	GetModuleFileName	MoveFileEx
CreateProcess	GetModuleHandle	OpenFile
DeleteFile	GetSystemDirectory	RemoveDirectory
FindFirstFile	GetTempFileName	SearchPath
FindNextFile	GetTempPath	SetCurrentDirectory
GetCurrentDirectory	GetVolumeInformation	SetFileAttributes
GetDiskFreeSpace	GetWindowsDirectory
When dealing with command lines, a console application should obtain the command line in Unicode form, and then convert it to OEM form using the relevant character-to-OEM functions. Note also that the argv function uses the ANSI character set.

See Also

AreFileApisANSI, FindFirstFileA, SetFileApisToOEM, SetConsoleCP, SetConsoleOutputCP, WriteConsoleA,


SetFileApisToOEM
SetFileApisToOEM  QuickInfo  Overview  Group

The SetFileApisToOEM function causes a set of Win32 file functions to use the OEM character set code page. This function is useful for 8-bit console input and output operations.

VOID SetFileApisToOEM(VOID)

Parameters

This function has no parameters.

Return Value

This function has no return value.

Remarks

The SetFileApisToOEM function is complemented by the SetFileApisToANSI function, which causes the same set of Win32 file functions to use the ANSI character set code page.

The 8-bit console functions use the OEM code page by default. All other functions use the ANSI code page by default. This means that strings returned by the console functions may not be processed correctly by other functions, and vice versa. For example, if the FindFirstFileA function returns a string that contains certain extended ANSI characters, and the 8-bit console functions are set to use the OEM code page, then the WriteConsoleA function will not display the string properly.

Use the AreFileApisANSI function to determine which code page the set of file functions is currently using. Use the SetConsoleCP and SetConsoleOutputCP functions to set the code page for the 8-bit console functions.

To solve the problem of code page incompatibility, it is best to use Unicode for console applications. Console applications that use Unicode are much more versatile than those that use 8-bit console functions. Barring that solution, a console application can call the SetFileApisToOEM function to cause the set of Win32 file functions to use OEM character set strings rather than ANSI character set strings. Use the SetFileApisToANSI function to set those functions back to the ANSI code page.

SetFileApisToANSI and SetFileApisToOEM affect these Win32 functions:

_lopen	GetDriveType	LoadLibrary
CopyFile	GetFileAttributes	LoadLibraryEx
CreateDirectory	GetFullPathName	MoveFile
CreateFile	GetModuleFileName	MoveFileEx
CreateProcess	GetModuleHandle	OpenFile
DeleteFile	GetSystemDirectory	RemoveDirectory
FindFirstFile	GetTempFileName	SearchPath
FindNextFile	GetTempPath	SetCurrentDirectory
GetCurrentDirectory	GetVolumeInformation	SetFileAttributes
GetDiskFreeSpace	GetWindowsDirectory
When dealing with command lines, a console application should obtain the command line in Unicode form, and then convert it to OEM form using the relevant character-to-OEM functions. Note also that the argv function uses the ANSI character set.

See Also

AreFileApisANSI, FindFirstFileA, SetConsoleCP, SetConsoleCP, SetConsoleOutputCP, SetFileApisToANSI, WriteConsoleA,


SetFileAttributes
SetFileAttributes  QuickInfo  Overview  Group

The SetFileAttributes function sets a file's attributes.

BOOL SetFileAttributes(

LPCTSTR  lpFileName,	// address of filename
DWORD  dwFileAttributes	// address of attributes to set
);
Parameters

lpFileName

Points to a string that specifies the name of the file whose attributes are to be set.

Windows 95: This string must not exceed MAX_PATH characters.

Windows NT: There is a default string size limit for paths of MAX_PATH characters. This limit is related to how the SetFileAttributes function parses paths. An application can transcend this limit and send in paths longer than MAX_PATH characters by calling the wide (W) version of SetFileAttributes and prepending "\\?\" to the path. The "\\?\" tells the function to turn off path parsing; it lets paths longer than MAX_PATH be used with SetFileAttributesW. This also works with UNC names. The "\\?\" is ignored as part of the path. For example, "\\?\C:\myworld\private" is seen as "C:\myworld\private", and "\\?\UNC\bill_g_1\hotstuff\coolapps" is seen as "\\bill_g_1\hotstuff\coolapps".

dwFileAttributes

Specifies the file attributes to set for the file. This parameter can be a combination of the following values. However, all other values override FILE_ATTRIBUTE_NORMAL.

Value	Meaning
FILE_ATTRIBUTE_ARCHIVE	The file is an archive file. Applications use this value to mark files for backup or removal.
FILE_ATTRIBUTE_NORMAL	The file has no other attributes set. This value is valid only if used alone.
FILE_ATTRIBUTE_HIDDEN	The file is hidden. It is not included in an ordinary directory listing.
FILE_ATTRIBUTE_READONLY	The file is read-only. Applications can read the file but cannot write to it or delete it.
FILE_ATTRIBUTE_SYSTEM	The file is part of the operating system or is used exclusively by it.
FILE_ATTRIBUTE_TEMPORARY	The file is being used for temporary storage. File systems attempt to keep all of the data in memory for quicker access rather than flushing the data back to mass storage. A temporary file should be deleted by the application as soon as it is no longer needed.
Windows 95 only: FILE_ATTRIBUTE_ATOMIC_WRITE	Reserved for future use; do not specify.
Windows 95 only: FILE_ATTRIBUTE_XACTION_WRITE	Reserved for future use; do not specify.
Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

You cannot use the SetFileAttribute function to set a file's compression state. Setting FILE_ATTRIBUTE_COMPRESSED in the dwFileAttributes parameter does nothing. Use the DeviceIoControl function and the FSCTL_SET_COMPRESSION operation to set a file's compression state.

See Also

DeviceIoControl, FSCTL_SET_COMPRESSION, GetFileAttributes


SetFilePointer
SetFilePointer  QuickInfo  Overview  Group

The SetFilePointer function moves the file pointer of an open file.

DWORD SetFilePointer(

HANDLE  hFile,	// handle of file
LONG  lDistanceToMove,	// number of bytes to move file pointer
PLONG  lpDistanceToMoveHigh,	// address of high-order word of distance to move
DWORD  dwMoveMethod	// how to move
);
Parameters

hFile

Identifies the file whose file pointer is to be moved. The file handle must have been created with GENERIC_READ or GENERIC_WRITE access to the file.

lDistanceToMove

Specifies the number of bytes to move the file pointer. A positive value moves the pointer forward in the file and a negative value moves it backward.

lpDistanceToMoveHigh

Points to the high-order word of the 64-bit distance to move. If the value of this parameter is NULL, SetFilePointer can operate only on files whose maximum size is 2^32 − 2. If this parameter is specified, the maximum file size is 2^64 − 2. This parameter also receives the high-order word of the new value of the file pointer.

dwMoveMethod

Specifies the starting point for the file pointer move. This parameter can be one of the following values:

Value	Meaning
FILE_BEGIN	The starting point is zero or the beginning of the file. If FILE_BEGIN is specified, DistanceToMove is interpreted as an unsigned location for the new file pointer.
FILE_CURRENT	The current value of the file pointer is the starting point.
FILE_END	The current end-of-file position is the starting point.
Return Value

If the SetFilePointer function succeeds, the return value is the low-order doubleword of the new file pointer, and if lpDistanceToMoveHigh is not NULL, the function puts the high-order doubleword of the new file pointer into the LONG pointed to by that parameter.

If the function fails and lpDistanceToMoveHigh is NULL, the return value is 0xFFFFFFFF. To get extended error information, call GetLastError.

If the function fails, and lpDistanceToMoveHigh is non-NULL, the return value is 0xFFFFFFFF and GetLastError will return a value other than NO_ERROR.

Remarks

You cannot use the SetFilePointer function with a handle to a nonseeking device, such as a pipe or a communications device. To determine the file type for hFile, use the GetFileType function.

You should be careful when setting the file pointer in a multithreaded application. For example, an application whose threads share a file handle, update the file pointer, and read from the file must protect this sequence by using a critical section object or mutex object. For more information about these objects, see Using Mutex Objects and Critical Section Objects.

If the hFile file handle was opened with the FILE_FLAG_NO_BUFFERING flag set, an application can move the file pointer only to sector-aligned positions. A sector-aligned position is a position that is a whole number multiple of the volume's sector size. An application can obtain a volume's sector size by calling the GetDiskFreeSpace function. If an application calls SetFilePointer with distance-to-move values that result in a position that is not sector-aligned and a handle that was opened with FILE_FLAG_NO_BUFFERING, the function fails, and GetLastError returns ERROR_INVALID_PARAMETER.

Note that if the return value is 0xFFFFFFFF and if lpDistanceToMoveHigh is non-NULL, an application must call GetLastError to determine whether the function has succeeded or failed. The following sample code illustrates this point:

//

// Case One: calling the function with

//           lpDistanceToMoveHigh == NULL

// try to move hFile's file pointer some distance

dwPointer = SetFilePointer (hFile, lDistance,

                            NULL, FILE_BEGIN) ;

// if we failed ...

if (dwPointer == 0xFFFFFFFF) {

    // obtain the error code

    dwError = GetLastError() ;

    // deal with that failure

    .

    .

    .

    } // end of error handler

//

// Case Two: calling the function with

//           lpDistanceToMoveHigh != NULL

// try to move hFile's file pointer some huge distance

dwPointerLow = SetFilePointer (hFile, lDistanceLow,

                               & lDistanceHigh, FILE_BEGIN) ;

// if we failed ...

if (dwPointerLow == 0xFFFFFFFF

    &&

    (dwError = GetLastError()) != NO_ERROR ){

    // deal with that failure

    .

    .

    .

    } // end of error handler

See Also

GetDiskFreeSpace, GetFileType, ReadFile, ReadFileEx, WriteFile, WriteFileEx


SetFileSecurity
SetFileSecurity  QuickInfo  Overview  Group

The SetFileSecurity function sets the security of a file or directory object.

BOOL SetFileSecurity(

LPCTSTR  lpszFile,	// address of string for filename
SECURITY_INFORMATION  si,	// type of information to set
PSECURITY_DESCRIPTOR  psd	// address of security descriptor
);
Parameters

lpszFile

Points to a null-terminated string specifying the file or directory for which security is set.

si

Specifies a SECURITY_INFORMATION structure identifying the contents of the security descriptor pointed to by the psd parameter.

psd

Points to a SECURITY_DESCRIPTOR structure.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The SetFileSecurity function is successful only if the following conditions are met:

•	If the object's owner is being set, the calling process must have either WRITE_OWNER permission or be the object's owner.

•	If the object's discretionary access-control list (ACL) is being set, the calling process must have either WRITE_DAC permission or be the object's owner.

•	If the object's system ACL is being set, the SE_SECURITY_NAME privilege must be enabled for the calling process.

See Also

GetFileSecurity, SECURITY_DESCRIPTOR, SECURITY_INFORMATION, SetKernelObjectSecurity, SetPrivateObjectSecurity, SetUserObjectSecurity


SetFileTime
SetFileTime  QuickInfo  Overview  Group

The SetFileTime function sets the date and time that a file was created, last accessed, or last modified.

BOOL SetFileTime(

HANDLE  hFile,	// identifies the file
CONST FILETIME *  lpftCreation,	// time the file was created
CONST FILETIME *  lpftLastAccess,	// time the file was last accessed
CONST FILETIME *  lpftLastWrite	// time the file was last written
);
Parameters

hFile

Identifies the file for which to set the dates and times. The file handle must have been created with GENERIC_WRITE access to the file.

lpftCreation

Points to a FILETIME structure that contains the date and time the file was created. This parameter can be NULL if the application does not need to set this information.

lpftLastAccess

Points to a FILETIME structure that contains the date and time the file was last accessed. The last access time includes the last time the file was written to, read from, or (in the case of executable files) run. This parameter can be NULL if the application does not need to set this information.

lpftLastWrite

Points to a FILETIME structure that contains the date and time the file was last written to. This parameter can be NULL if the application does not want to set this information.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The FAT, NTFS, and HPFS file systems all support the file creation, last access, and last write time values.

See Also

FILETIME, GetFileSize, GetFileTime, GetFileType


SetFocus
SetFocus  QuickInfo  Overview  Group

The SetFocus function sets the keyboard focus to the specified window. All subsequent keyboard input is directed to this window. The window, if any, that previously had the keyboard focus loses it.

HWND SetFocus(

HWND  hwnd	// handle of window to receive focus
);
Parameters

hwnd

Identifies the window that will receive the keyboard input. If this parameter is NULL, keystrokes are ignored.

Return Value

If the function succeeds, the return value is the handle of the window that previously had the keyboard focus. If there is no such window or if the hwnd parameter is invalid, the return value is NULL.

Remarks

If the window identified by the hwnd parameter was created by the calling thread, the keyboard-focus status of the calling thread is set to hwnd.

The SetFocus function sends a WM_KILLFOCUS message to the window that loses the keyboard focus and a WM_SETFOCUS message to the window that receives the keyboard focus. It also activates either the window that receives the focus or the parent of the window that receives the focus.

If a window is active but does not have the focus (that is, no window has the focus), any key pressed will produce the WM_SYSCHAR, WM_SYSKEYDOWN, or WM_SYSKEYUP message. If the VK_MENU key is also pressed, the lParam parameter of the message will have bit 30 set. Otherwise, the messages produced do not have this bit set.

If an application is not in the foreground, and wants to be in the foreground, it should call the SetForegroundWindow function.

See Also

GetActiveWindow, GetFocus, SetActiveWindow, SetCapture, SetForegroundWindow, WM_KILLFOCUS, WM_SETFOCUS, WM_SYSCHAR, WM_SYSKEYDOWN, WM_SYSKEYUP


SetForegroundWindow
SetForegroundWindow  QuickInfo  Overview  Group

The SetForegroundWindow function puts the thread that created the specified window into the foreground and activates the window. Keyboard input is directed to the window, and various visual cues are changed for the user.

BOOL SetForegroundWindow(

HWND  hwnd	// handle of window to bring to foreground
);
Parameters

hwnd

Identifies the window that should be activated and brought to the foreground.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The foreground window is the window at the top of the Z order. It is the window that the user is working with. The system assigns a slightly higher priority to the thread that created the foreground window than it does to other threads.

SetForegroundWindow activates a window and forces the thread that created the window into the foreground.

An application should call SetForegroundWindow if it wants to put itself into the foreground. A good example is a debugger when it hits a breakpoint.

Unlike SetForegroundWindow, the SetActiveWindow function activates a window, but it only brings the window to the foreground if the window is owned by the thread making the SetActiveWindow call.

See Also

GetForegroundWindow, SetActiveWindow


SetForm
SetForm  QuickInfo  Overview  Group

The SetForm function sets the form information for the specified printer.

BOOL SetForm(

HANDLE  hPrinter,	// handle of printer object
LPTSTR  lpszForm,	// address of form name
DWORD  dwLevel,	// structure level
LPBYTE  lpbForm	// address of structure array
);
Parameters

hPrinter

Identifies the printer for which the form information is set.

lpszForm

Points to a null-terminated string that specifies the form name for which the form information is set.

dwLevel

Specifies the version of the structure to which lpbForm points. This value must be 1.

lpbForm

Points to a FORM_INFO_1 structure.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The printer handle hPrinter is obtained by calling the OpenPrinter function.

See Also

FORM_INFO_1, OpenPrinter


SetGraphicsMode
SetGraphicsMode  QuickInfo  Overview  Group

The SetGraphicsMode function sets the graphics mode for the specified device context.

int SetGraphicsMode(

HDC  hdc,	// handle of the device context
int  iMode	// graphics mode
);
Parameters

hdc

Identifies the device context.

iMode

Specifies the graphics mode. This parameter can be one of the following values:

Value	Meaning
GM_COMPATIBLE	Sets the graphics mode that is compatible with Windows version 3.1. This is the default mode. If this value is specified, the application can only modify the world-to-device transform by calling functions that set window and viewport extents and origins, but not by using SetWorldTransform or ModifyWorldTransform; calls to those functions will fail. Examples of functions that set window and viewport extents and origins are SetViewportExtEx and SetWindowExtEx.
GM_ADVANCED	Windows NT: Sets the advanced graphics mode that allows world transformations. This value must be specified if the application will set or modify the world transformation for the specified device context. In this mode all graphics, including text output, fully comforms to the world-to-device transformation specified in the device context. Windows 95: The GM_ADVANCED value is not supported. However, enhanced metafiles are assumed to be played in GM_ADVANCED mode, and Windows 95 ensures that enhanced metafiles on Windows 95 look the same as they do on Windows NT.
Return Value

If the function succeeds, the return value is the old graphics mode.

If the function fails, the return value is zero.

Remarks

There are three areas in which graphics output differs according to the graphics mode:

1.	Text Output: In the GM_COMPATIBLE mode, TrueType (or vector font) text output behaves much the same way as raster font text output with respect to the world-to-device transform in the DC. The TrueType text is always written from left to right and right side up, even if the rest of the graphics will be flipped in the x or y axis. Only the height of the TrueType (or vector font) text is scaled appropriately. The only way to write nonhorizontal text in the GM_COMPATIBLE mode is to specify nonzero escapement and orientation for the logical font selected in this device context.

In the GM_ADVANCED mode, TrueType (or vector font) text output fully conforms to the world-to-device transform in the device context. The raster fonts only have very limited transformation capabilities (stretching by some integer factors). Graphics device interface (GDI) tries to produce the best output it can with raster fonts for non-trivial transforms.

2.	Rectangle Exclusion: If the default GM_COMPATIBLE graphics mode is set, the system excludes bottom and rightmost edges when it draws rectangles.

The GM_ADVANCED graphics mode is required if applications want to draw rectangles that are bottom-right inclusive.

3.	Arc Drawing: If the default GM_COMPATIBLE graphics mode is set, GDI draws arcs using the current arc direction in the device space. With this convention, arcs do not respect page-to-device transforms that require a flip along the x or y axis.

If the GM_ADVANCED graphics mode is set, GDI always draws arcs in the counterclockwise direction in logical space. This is equivalent to the statement that, in the GM_ADVANCED graphics mode, both arc control points and arcs themselves fully respect the device context's world-to-device transform.

See Also

CreateDC, GetArcDirection, GetDC, GetGraphicsMode, ModifyWorldTransform; SetArcDirection, SetViewportExtent, SetViewportExtEx, SetWindowExtent, SetWindowExtEx, SetWorldTransform


SetHandleCount
SetHandleCount  QuickInfo  Overview  Group

The SetHandleCount function changes the number of file handles available to a process.

The SetHandleCount function is not necessary under the Windows NT implementation of Win32; in fact, it has no effect when called under Windows NT.

The SetHandleCount function may be necessary under other implementations of Win32, such as Win32s, in order to increase the default number of available file handles. Under Win32s, this default is 20.

UINT SetHandleCount(

UINT  cHandles	// number of file handles needed
);
Parameters

cHandles

Specifies the number of file handles needed by the application. The maximum value is implementation-dependent. Under Win32s, the maximum value is 255.

Return Value

Under Windows NT, this function has no effect, and the return value is simply the value of the cHandles parameter.

Under other implementations of Win32, such as Win32s, the return value specifies the number of file handles actually available to the application. It may be fewer than the number specified by the cHandles parameter.

Remarks

Under Windows NT, the maximum number of files that an application can open is determined by the amount of available non-paged memory pool, because each open file handle consumes part of that resource.


SetHandleInformation [New - Windows NT]
SetHandleInformation  QuickInfo  Overview  Group

[New - Windows NT]

The SetHandleInformation function sets certain properties of an object handle. The information is specified as a set of bit flags.

BOOL GetHandleInformation (

HANDLE  hObject,	// handle to an object
DWORD  dwMask,	// specifies flags to change
DWORD  dwFlags	// specifies new values for flags
);
Parameters

hObject

Specifies a handle to an object. The SetHandleInformation function sets information associated with this object handle.

dwMask

A mask that specifies the bit flags to be changed. Use the same flag constants shown in the description of dwFlags.

dwFlags

A set of bit flags that specify properties of the object handle. The following flags are defined:

Value	Meaning
HANDLE_FLAG_INHERIT	If this flag is set, a child process created with the bInheritHandles parameter of CreateProcess set to TRUE will inherit the object handle.
HANDLE_FLAG_PROTECT_FROM_CLOSE	If this flag is set, calling the CloseHandle function will not close the object handle.
Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Note that you must set a change mask bit flag in dwMask in order to set or clear the associated bit flag in dwFlags.

See Also

CreateProcess, CloseHandle, GetHandleInformation


SetICMMode [New - Windows 95]
SetICMMode  QuickInfo  Overview  Group

[New - Windows 95]

The SetICMMode function enables or disables image color matching for the specified device context.

int SetICMMode(

HDC  hdc,
int  fICM
);
Parameters

hdc

Handle to the device context.

fICM

Set to ICM_ON to turn on image color matching; ICM_OFF to turn it off; and ICM_QUERY to return the current mode.

Return Value

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero.

If ICM_QUERY is specified, the function returns ICM_ON or ICM_OFF to indicate the current mode.

Remarks

This function fails if an appropriate color profile cannot be found for the device.


SetICMProfile [New - Windows 95]
SetICMProfile  QuickInfo  Overview  Group

[New - Windows 95]

The SetICMProfile function sets the color profile for the specified device context.

BOOL SetICMProfile(

HDC  hdc,
LPTSTR  lpFileName
);
Parameters

hdc

Handle to the device context.

lpFileName

Pointer to a null-terminated string that names the color profile file.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.


SetJob
SetJob  QuickInfo  Overview  Group

The SetJob function pauses, resumes, cancels, or restarts a print job on the specified printer. The function can also be used to set print job parameters such as the job priority, the document name, and so forth.

BOOL SetJob(

HANDLE  hPrinter,	// handle of printer object
DWORD  dwJob,	// job-identification value
DWORD  dwLevel,	// structure level
LPBYTE  lpbJob,	// address of job info structures
DWORD  dwCommand	// job-command value
);
Parameters

hPrinter

Identifies the printer.

dwJob

Specifies the print job.

dwLevel

Specifies the version of the structure to which lpbJob points. This value must be 0, 1, or 2.

lpbJob

Points to either a JOB_INFO_1 or JOB_INFO_2 structure. If dwLevel is 0, this pointer must be NULL; if dwLevel is 1, the array contains a JOB_INFO_1 structure and if dwLevel is 2, the array contains a JOB_INFO_2 structure.

dwCommand

Specifies the operation which should be performed. This parameter can be one of the following values:

Value	Meaning
JOB_CONTROL_CANCEL	Deletes a print job.
JOB_CONTROL_PAUSE	Pauses a print job.
JOB_CONTROL_RESTART	Restarts a print job. A job can only be restarted if it was printing.
JOB_CONTROL_RESUME	Resumes a paused print job.
Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The SetJob function can be used to set various job parameters by supplying a pointer to a JOB_INFO_1 or JOB_INFO_2 structure that contains the necessary data.

To remove or delete all the print jobs for a particular printer, call the SetPrinter function and set the PRINTER_CONTROL_PURGE value.

The following members of a JOB_INFO_1 or JOB_INFO_2 structure are ignored on a call to SetJob:

JobId, pPrinterName, pMachineName, pDrivername, Size, Submitted, and Time.

A client must have PRINTER_ACCESS_ADMINISTER access permission to a printer in order to change the order of jobs on the printer.

If an application does not wish to set the job position, it should specify the JOB_POSITION_UNSPECIFIED (0) value for the Position member.

See Also

JOB_INFO_1, JOB_INFO_2, OpenPrinter, SetPrinter


SetKernelObjectSecurity
SetKernelObjectSecurity  QuickInfo  Overview  Group

The SetKernelObjectSecurity function sets the security of a kernel object. For example, this can be a process, thread, or event.

BOOL SetKernelObjectSecurity(

HANDLE  hObject,	// handle of object
SECURITY_INFORMATION  si,	// type of information to set
PSECURITY_DESCRIPTOR  psd	// address of security descriptor
);
Parameters

hObject

Identifies a kernel object for which security information is set.

si

Specifies a SECURITY_INFORMATION structure identifying the contents of the security descriptor pointed to by the psd parameter.

psd

Points to a SECURITY_DESCRIPTOR structure containing the new security information.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The SetKernelObjectSecurity function is successful only if the following conditions are met:

•	If the object's owner is being set, the calling process must have either WRITE_OWNER permission or be the object's owner.

•	If the object's discretionary access-control list (ACL) is being set, the calling process must have either WRITE_DAC permission or be the object's owner.

•	If the object's system ACL is being set, the SE_SECURITY_NAME privilege must be enabled for the calling process.

See Also

GetKernelObjectSecurity, SECURITY_DESCRIPTOR, SECURITY_INFORMATION, SetFileSecurity, SetPrivateObjectSecurity, SetUserObjectSecurity


SetKeyboardState
SetKeyboardState  QuickInfo  Overview  Group

The SetKeyboardState function copies a 256-byte array of keyboard key states into the calling thread's keyboard-input state table. This is the same table accessed by the GetKeyboardState and GetKeyState functions. Changes made to this table do not affect keyboard input to any other thread.

BOOL SetKeyboardState(

LPBYTE  lpbKeyState	// address of array with virtual-key codes
);
Parameters

lpbKeyState

Points to a 256-byte array that contains keyboard key states.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Because the SetKeyboardState function alters the input state of the calling thread and not the global input state of the system, an application cannot use SetKeyboardState to set the NUM LOCK, CAPS LOCK, or SCROLL LOCK indicator lights on the keyboard.

See Also

GetAsyncKeyState, GetKeyboardState, GetKeyState, MapVirtualKey


SetLastError
SetLastError  QuickInfo  Overview  Group

The SetLastError function sets the last-error code for the calling thread.

VOID SetLastError(

DWORD  fdwError	// per-thread error code
);
Parameters

fdwError

Specifies the last-error code for the thread.

Remarks

Error codes are 32-bit values (bit 31 is the most significant bit). Bit 29 is reserved for application-defined error codes; no Win32 API error code has this bit set. If you are defining an error code for your application, set this bit to indicate that the error code has been defined by your application and to ensure that your error code does not conflict with any system-defined error codes.

This function is intended primarily for dynamic-link libraries (DLLs). Calling this function after an error occurs lets the DLL emulate the behavior of a Win32 function.

Most Win32 functions call SetLastError when they fail. Function failure is typically indicated by a return value error code such as FALSE, NULL, 0xFFFFFFFF, or −1. Some functions call SetLastError under conditions of success; those cases are noted in each function's reference page.

Applications can retrieve the value saved by this function by using the GetLastError function. The use of GetLastError is optional; an application can call it to find out the specific reason for a function failure.

The last-error code is kept in thread local storage so that multiple threads do not overwrite each other's values.

See Also

GetLastError, SetLastErrorEx, TlsGetValue


SetLastErrorEx
SetLastErrorEx  QuickInfo  Overview  Group

The SetLastErrorEx function sets the last-error code. In Windows 95 and in Windows NT, this function is identical to the SetLastError function. The second parameter is not implemented.

VOID SetLastErrorEx(

DWORD  fdwError,	// per-thread error code
DWORD  fdwType	// error type
);
Parameters

fdwError

Specifies the last-error code for the thread.

fdwType

Specifies the error type. If this process is being controlled by a debugging process, the debugger may take action based on the error type. This parameter can have one of the following values:

Value	Meaning
SLE_ERROR	Invalid data was passed to the function, and complete failure has occurred.
SLE_MINORERROR	Invalid data was passed to the function, but the function has recovered.
SLE_WARNING	Potentially invalid data was passed to the function, but the function has recovered.
0	The last-error code is set without reporting anything to the debugger. Specifying this value is equivalent to using the SetLastError function.
Remarks

Error codes are 32-bit values (bit 31 is the most significant bit). Bit 29 is reserved for application-defined error codes; no Win32 API error code has this bit set. If you are defining an error code for your application, set this bit to indicate that the error code has been defined by the application and to ensure that your error code does not conflict with any system-defined error codes.

This function is intended primarily for dynamic-link libraries (DLLs). Calling this function after an error occurs allows the DLL to emulate the behavior of the Win32 API.

Most Win32 functions call SetLastError when they fail. Function failure is typically indicated by a return value error code such as FALSE, NULL, 0xFFFFFFFF, or −1. Some functions call SetLastError under conditions of success; those cases are noted in each function's reference page.

Applications can retrieve the value saved by this function by using the GetLastError function.

The last-error code is kept in thread local storage so that multiple threads do not overwrite each other's values.

See Also

GetLastError, SetLastError


SetLocaleInfo
SetLocaleInfo  QuickInfo  Overview  Group

The SetLocaleInfo function sets an item of locale information. It does so by making an entry in the process portion of the locale table. This setting only affects the user override portion of the locale settings; it does not set the system defaults.

Only certain types of locale information, or LCTYPE values, can be set by this function. See the following Remarks section for a list of valid LCTYPE values.

The locale information is always passed in as a null-terminated Unicode string in the Unicode (W) version of the function, and as a null-terminated ANSI string in the ANSI (A) version. No integers are allowed by this function; any numeric values must be specified as Unicode or ANSI text. Each LCTYPE has a particular format, as noted in Locale Identifiers.

BOOL SetLocaleInfo(

LCID  Locale,	// locale identifier
LCTYPE  LCType,	// type of information to set
LPCTSTR  lpLCData	// pointer to information to set
);
Parameters

Locale

Specifies the locale whose information the function will set.

LCType

Specifies the type of locale information to be set by the function. Note that only one LCTYPE may be specified per call. Not all LCTYPE values are valid; see the list of valid LCTYPE values in the following Remarks section.

lpLCData

Points to a null-terminated string containing the locale information the function will set. This should be an LPWSTR for the Unicode (W) version of the function, and an LPSTR for the ANSI (A) version. The information must be in the specified LCTYPE's particular format.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError. GetLastError may return one of the following error codes:

ERROR_INVALID_ACCESS

ERROR_INVALID_FLAGS

ERROR_INVALID_PARAMETER

Remarks

The following LCTYPE values are valid for this function:

LOCALE_ICALENDARTYPE	LOCALE_SDATE
LOCALE_ICURRDIGITS	LOCALE_SDECIMAL
LOCALE_ICURRENCY	LOCALE_SGROUPING
LOCALE_IDIGITS	LOCALE_SLIST
LOCALE_IFIRSTDAYOFWEEK	LOCALE_SLONGDATE
LOCALE_IFIRSTWEEKOFYEAR	LOCALE_SMONDECIMALSEP
LOCALE_ILZERO	LOCALE_SMONGROUPING
LOCALE_IMEASURE	LOCALE_SMONTHOUSANDSEP
LOCALE_INEGCURR	LOCALE_SNEGATIVESIGN
LOCALE_INEGNUMBER	LOCALE_SPOSITIVESIGN
LOCALE_ITIME	LOCALE_SSHORTDATE
LOCALE_S1159	LOCALE_STHOUSAND
LOCALE_S2359	LOCALE_STIME
LOCALE_SCURRENCY	LOCALE_STIMEFORMAT
See Also

GetLocaleInfo


SetLocalTime
SetLocalTime  QuickInfo  Overview  Group

The SetLocalTime function sets the current local time and date.

BOOL SetLocalTime(

CONST SYSTEMTIME *  lpst	// address of local time to set
);
Parameters

lpst

Points to a SYSTEMTIME structure that contains the current local date and time.

The wDayOfWeek member of the SYSTEMTIME structure is ignored.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The application must have system-time privilege (the SE_SYSTEMTIME_NAME privilege) for this function to succeed. This privilege is disabled by default. Use the AdjustTokenPrivileges function to enable this privilege and again to disable it after the time has been set.

For more information about security privileges, see Security.

See Also

AdjustTokenPrivileges, GetLocalTime, GetSystemTime, SetSystemTimeAdjustment, SYSTEMTIME


SetMailslotInfo
SetMailslotInfo  QuickInfo  Overview  Group

The SetMailslotInfo function sets the time-out value used by the specified mailslot for a read operation.

BOOL SetMailslotInfo(

HANDLE  hMailslot,	// mailslot handle
DWORD  dwReadTimeout	// read time-out
);
Parameters

hMailslot

Identifies a mailslot. The CreateMailslot function must create this handle.

dwReadTimeout

Specifies the amount of time, in milliseconds, a read operation can wait for a message to be written to the mailslot before a time-out occurs. The following values have special meanings:

Value	Meaning
0	Returns immediately if no message is present. (The system does not treat an immediate return as an error.)
MAILSLOT_WAIT_FOREVER	Waits forever for a message.
This time-out value applies to all subsequent read operations and to all inherited mailslot handles.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The initial time-out value used by a mailslot for a read operation is typically set by CreateMailslot when the mailslot is created.

See Also

CreateMailslot, GetMailslotInfo


SetMapMode
SetMapMode  QuickInfo  Overview  Group

The SetMapMode function sets the mapping mode of the specified device context. The mapping mode defines the unit of measure used to transform page-space units into device-space units, and also defines the orientation of the device's x and y axes.

int SetMapMode(

HDC  hdc,	// handle of device context
int  fnMapMode	// new mapping mode
);
Parameters

hdc

Identifies the device context.

fnMapMode

Specifies the new mapping mode. It can be any one of the following values:

Value	Description
MM_ANISOTROPIC	Logical units are mapped to arbitrary units with arbitrarily scaled axes. Use the SetWindowExtEx and SetViewportExtEx functions to specify the units, orientation, and scaling that you want.
MM_HIENGLISH	Each logical unit is mapped to 0.001 inch. Positive x is to the right; positive y is up.
MM_HIMETRIC	Each logical unit is mapped to 0.01 millimeter. Positive x is to the right; positive y is up.
MM_ISOTROPIC	Logical units are mapped to arbitrary units with equally scaled axes; that is, one unit along the x-axis is equal to one unit along the y-axis. Use the SetWindowExtEx and SetViewportExtEx functions to specify the units and the orientation of the axes that you want. Graphics device interface (GDI) makes adjustments as necessary to ensure the x and y units remain the same size (for example, if you set the window extent, the viewport will be adjusted to keep the units isotropic).
MM_LOENGLISH	Each logical unit is mapped to 0.01 inch. Positive x is to the right; positive y is up.
MM_LOMETRIC	Each logical unit is mapped to 0.1 millimeter. Positive x is to the right; positive y is up.
MM_TEXT	Each logical unit is mapped to one device pixel. Positive x is to the right; positive y is down.
MM_TWIPS	Each logical unit is mapped to one twentieth of a printer's point (1/1440 inch, also called a "twip"). Positive x is to the right; positive y is up.
Return Value

If the function succeeds, the return value identifies the previous mapping mode.

If the function fails, the return value is zero.

Remarks

The MM_TEXT mode allows applications to work in device pixels, whose size varies from device to device.

The MM_HIENGLISH, MM_HIMETRIC, MM_LOENGLISH, MM_LOMETRIC, and MM_TWIPS modes are useful for applications drawing in physically meaningful units (such as inches or millimeters).

The MM_ISOTROPIC mode ensures a 1:1 aspect ratio.

The MM_ANISOTROPIC mode allows the x-coordinates and y-coordinates to be adjusted independently.

See Also

GetMapMode, SetViewportExtEx, SetViewportOrgEx, SetWindowExtEx, SetWindowOrgEx


SetMapperFlags
SetMapperFlags  QuickInfo  Overview  Group

The SetMapperFlags function alters the algorithm the font mapper uses when it maps logical fonts to physical fonts.

DWORD SetMapperFlags(

HDC  hdc,	// handle of device context
DWORD  dwFlag	// font-mapper flag
);
Parameters

hdc

Identifies the device context that contains the font-mapper flag.

dwFlag

Specifies whether the font mapper should attempt to match a font's aspect ratio to the current device's aspect ratio. If bit zero is set, the mapper selects only matching fonts.

Return Value

If the function succeeds, the return value is the previous value of the font-mapper flag.

If the function fails, the return value is GDI_ERROR. To get extended error information, call GetLastError.

Remarks

If the dwFlag parameter is set and no matching fonts exist, Windows chooses a new aspect ratio and retrieves a font that matches this ratio.

The remaining bits of the dwFlag parameter must be zero.

See Also

GetAspectRatioFilterEx


SetMenu
SetMenu  QuickInfo  Overview  Group

The SetMenu function assigns a new menu to the specified window.

BOOL SetMenu(

HWND  hwnd,	// handle of window
HMENU  hmenu	// handle of menu
);
Parameters

hwnd

Identifies the window to which the menu is to be assigned.

hmenu

Identifies the new menu. If this parameter is NULL, the window's current menu is removed.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The window is redrawn to reflect the menu change.

The SetMenu function replaces the previous menu, if any, but it does not destroy it. An application should call the DestroyMenu function to accomplish this task.

See Also

DestroyMenu, GetMenu


SetMenuContextHelpId [New - Windows NT]
SetMenuContextHelpId  QuickInfo  Overview  Group

[New - Windows NT]

The SetMenuContextHelpId function associates a help context identifier with a menu. All items in the menu share this identifier. It is not possible to attach a help context identifier to the individual menu items.

BOOL SetMenuContextHelpId(

HMENU  hmenu,
DWORD  dwContextHelpId
);
Parameters

hmenu

Handle to the menu with which to associate the help context identifier.

dwContextHelpId

Help context identifier.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.


SetMenuDefaultItem [New - Windows 95]
SetMenuDefaultItem  QuickInfo  Overview  Group

[New - Windows 95]

The SetMenuDefaultItem function sets the default menu item for the specified menu.

BOOL SetMenuDefaultItem(

HMENU  hMenu,
UINT  uItem,
UINT  fByPos
);
Parameters

hMenu

Handle to the menu to set the default item for.

uItem

Identifier or position of the new default menu item or − 1 for no default item. The meaning of this parameter depends on the value of fByPos.

fByPos

Value specifying the meaning of uItem. If this parameter is FALSE, uItem is a menu item identifier. Otherwise, it is a menu item position.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, use the GetLastError function.


SetMenuItemBitmaps
SetMenuItemBitmaps  QuickInfo  Overview  Group

The SetMenuItemBitmaps function associates the specified bitmap with a menu item. Whether the menu item is checked or unchecked, Windows displays the appropriate bitmap next to the menu item.

BOOL SetMenuItemBitmaps(

HMENU  hmenu,	// handle of menu
UINT  uItem,	// menu item to receive new bitmaps
UINT  fuFlags,	// menu item flags
HBITMAP  hbmUnchecked,	// handle of unchecked bitmap
HBITMAP  hbmChecked	// handle of checked bitmap
);
Parameters

hmenu

Identifies the menu containing the item to receive new check mark bitmaps.

uItem

Specifies the menu item to be changed, as determined by the fuFlags parameter.

fuFlags

Specifies how the uItem parameter is interpreted. The fuFlags parameter must be one of the following values:

Value	Meaning
MF_BYCOMMAND	Indicates that uItem gives the identifier of the menu item. If neither MF_BYCOMMAND nor MF_BYPOSITION is specified, MF_BYCOMMAND is the default flag.
MF_BYPOSITION	Indicates that uItem gives the zero-based relative position of the menu item.
hbmUnchecked

Identifies the bitmap displayed when the menu item is not checked.

hbmChecked

Identifies the bitmap displayed when the menu item is checked.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

If either the hbmUnchecked or hbmChecked parameter is NULL, Windows displays nothing next to the menu item for the corresponding check state. If both parameters are NULL, Windows displays the default check mark bitmap when the item is checked and removes the bitmap when the item is not checked.

When the menu is destroyed, these bitmaps are not destroyed; it is up to the application to destroy them.

Windows NT: The GetMenuCheckMarkDimensions function retrieves the dimensions of the default check mark used for menu items. These values are used to determine the appropriate size for the bitmaps supplied with this function.

Windows 95: GetMenuCheckMarkDimensions is obsolete. Use GetsystemMetrics with the CXMENUCHECK and CYMENUCHECK values to retrieve the bitmap dimensions.

See Also

GetMenu, GetMenuCheckMarkDimensions


SetMenuItemInfo [New - Windows 95]
SetMenuItemInfo  QuickInfo  Overview  Group

[New - Windows 95]

The SetMenuItemInfo function changes information about a menu item.

BOOL WINAPI SetMenuItemInfo(

HMENU  hMenu,
UINT  uItem,
BOOL  fByPosition,
LPMENUITEMINFO  lpmii
);
Parameters

hMenu

Handle to the menu that contains the menu item.

uItem

Identifier or position of the menu item to change. The meaning of this parameter depends on the value of fByPosition.

fByPosition

Value specifying the meaning of uItem. If this parameter is FALSE, uItem is a menu item identifier. Otherwise, it is a menu item position.

lpmii

Pointer to a MENUITEMINFO structure that contains information about the menu item and specifies which menu item attributes to change.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, use the GetLastError function.

See Also

MENUITEMINFO


SetMessageExtraInfo [New - Windows 95]
SetMessageExtraInfo  QuickInfo  Overview  Group

[New - Windows 95]

The SetMessageExtraInfo function sets the extra message information for the current thread. Extra message information is an application- or driver-defined 32-bit value associated with the current thread's message queue. An application can use the GetMessageExtraInfo function to retrieve a thread's extra message information.

LPARAM SetMessageExtraInfo(

LPARAM  lParam	// application-defined 32-bit value
);
Parameters

lParam

Specifies the 32-bit value to associate with the current thread.

Return Value

The return value is the previous 32-bit value.

See Also

GetMessageExtraInfo


SetMessageQueue
SetMessageQueue  QuickInfo  Overview  Group

The SetMessageQueue function creates a new message queue. It is useful in Windows version 3.x applications that require a queue that contains more than eight messages (the maximum size of the default queue). It does nothing running with Win32, because queues are expanded dynamically as necessary.

BOOL SetMessageQueue(

int  cMessagesMax	// size of message queue
);


SetMetaFileBits

The SetMetaFileBits function is not implemented in the Win32 API. Win32-based applications should use the SetMetaFileBitsEx function.


SetMetaFileBitsEx
SetMetaFileBitsEx  QuickInfo  Overview  Group

The SetMetaFileBitsEx function creates a memory-based Windows-format metafile from the supplied data.

This function is provided for compatibility with earlier versions of Microsoft Windows. Win32-based applications should use the SetEnhMetaFileBits function.

HMETAFILE SetMetaFileBitsEx(

UINT  nSize,	// size of Windows-format metafile
CONST BYTE *  lpData	// address of buffer containing metafile data
);
Parameters

nSize

Specifies the size, in bytes, of the Windows-format metafile.

lpData

Points to a buffer that contains the Windows-format metafile. (It is assumed that the data was obtained by using the GetMetaFileBitsEx function.)

Return Value

If the function succeeds, the return value is a handle of a memory-based Windows-format metafile.

If the function fails, the return value is NULL.

Remarks

A Windows-format metafile does not support the new curve, path, and transformation functions such as PolyBezier, BeginPath, and SetWorldTransform. Applications that use these new functions and use metafiles to store pictures created by these functions should use the enhanced-format metafile functions.

To convert a Windows-format metafile into an enhanced-format metafile, use the SetWinMetaFileBits function.

When the application no longer needs the metafile handle returned by SetMetaFileBitsEx, it should delete it by calling the DeleteMetaFile function.

See Also

BeginPath, DeleteMetaFile, GetMetaFileBitsEx, PolyBezier, SetEnhMetaFileBits, SetWinMetaFileBits, SetWorldTransform


SetMetaRgn
SetMetaRgn  QuickInfo  Overview  Group

The SetMetaRgn function intersects the current clipping region for the specified device context with the current metaregion and saves the combined region as the new metaregion for the specified device context. The clipping region is reset to a null region.

int SetMetaRgn(

HDC  hdc	// handle of device context
);
Parameters

hdc

Identifies the device context.

Return Value

If the function succeeds, the return value specifies the new clipping region's complexity and can be any one of the following values:

Value	Meaning
NULLREGION	Region is empty.
SIMPLEREGION	Region is a single rectangle.
COMPLEXREGION	Region is more than one rectangle.
ERROR	An error occurred. (The previous clipping region is unaffected.)
Remarks

The current clipping region of a device context is defined by the intersection of its clipping region and its metaregion.

The SetMetaRgn function should only be called after an application's original device context was saved by calling the SaveDC function.

See Also

GetMetaRgn, SaveDC


SetMiterLimit
SetMiterLimit  QuickInfo  Overview  Group

The SetMiterLimit function sets the limit for the length of miter joins for the specified device context.

BOOL SetMiterLimit(

HDC  hdc,	// handle of device context
FLOAT  eNewLimit,	// new miter limit
PFLOAT  peOldLimit	// previous miter limit
);
Parameters

hdc

Identifies the device context.

eNewLimit

Specifies the new miter limit for the device context.

peOldLimit

Points to a floating-point value that receives the previous miter limit. If this parameter is NULL, the previous miter limit is not returned.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The miter length is defined as the distance from the intersection of the line walls on the inside of the join to the intersection of the line walls on the outside of the join. The miter limit is the maximum allowed ratio of the miter length to the line width.

The default miter limit is 10.0.

See Also

ExtCreatePen


SetNamedPipeHandleState
SetNamedPipeHandleState  QuickInfo  Overview  Group

The SetNamedPipeHandleState function sets the read mode and the blocking mode of the specified named pipe. If the specified handle is to the client end of a named pipe and if the named pipe server process is on a remote computer, the function can also be used to control local buffering.

BOOL SetNamedPipeHandleState(

HANDLE  hNamedPipe,	// handle of named pipe
LPDWORD  lpdwMode,	// address of new pipe mode
LPDWORD  lpcbMaxCollect,	// address of max. bytes before remote transmission
LPDWORD  lpdwCollectDataTimeout	// address of max. time before remote transmission
);
Parameters

hNamedPipe

Identifies the named pipe instance. This parameter can be a handle to the server end of the pipe, as returned by the CreateNamedPipe function, or to the client end of the pipe, as returned by the CreateFile function. The handle must have GENERIC_WRITE access to the named pipe.

lpdwMode

Points to a 32-bit variable that supplies the new mode. The mode is a combination of a read-mode flag and a wait-mode flag. This parameter can be NULL if the mode is not being set. One of the following read modes can be specified:

Mode	Description
PIPE_READMODE_BYTE	Data is read from the pipe as a stream of bytes. This mode is the default if no read-mode flag is specified.
PIPE_READMODE_MESSAGE	Data is read from the pipe as a stream of messages. The function fails if this flag is specified for a byte-type pipe.
One of the following wait modes can be specified:

Mode	Description
PIPE_WAIT	Blocking mode is enabled. This mode is the default if no wait-mode flag is specified. When a blocking mode pipe handle is specified in the ReadFile, WriteFile, or ConnectNamedPipe function, operations are not finished until there is data to read, all data is written, or a client is connected. Use of this mode can mean waiting indefinitely in some situations for a client process to perform an action.
PIPE_NOWAIT	Nonblocking mode is enabled. In this mode, ReadFile, WriteFile, and ConnectNamedPipe always return immediately. Note that nonblocking mode is supported for compatibility with Microsoft® LAN Manager version 2.0 and should not be used to achieve asynchronous input and output (I/O) with named pipes.
lpcbMaxCollect

Points to a 32-bit variable that specifies the maximum number of bytes collected on the client computer before transmission to the server. This parameter must be NULL if the specified pipe handle is to the server end of a named pipe or if client and server processes are on the same machine. This parameter is ignored if the client process specifies the FILE_FLAG_WRITE_THROUGH flag in the CreateFile function when the handle was created. This parameter can be NULL if the collection count is not being set.

lpdwCollectDataTimeout

Points to a 32-bit variable that specifies the maximum time, in milliseconds, that can pass before a remote named pipe transfers information over the network. This parameter must be NULL if the specified pipe handle is to the server end of a named pipe or if client and server processes are on the same computer. This parameter is ignored if the client process specified the FILE_FLAG_WRITE_THROUGH flag in the CreateFile function when the handle was created. This parameter can be NULL if the collection count is not being set.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

ConnectNamedPipe, CreateFile, CreateNamedPipe, GetNamedPipeHandleState, ReadFile, WriteFile


SetPaletteEntries
SetPaletteEntries  QuickInfo  Overview  Group

The SetPaletteEntries function sets RGB (red, green, blue) color values and flags in a range of entries in a logical palette.

UINT SetPaletteEntries(

HPALETTE  hpal,	// handle of logical palette
UINT  iStart,	// index of first entry to set
UINT  cEntries,	// number of entries to set
CONST PALETTEENTRY  *lppe	// address of array of structures
);
Parameters

hpal

Identifies the logical palette.

iStart

Specifies the first logical-palette entry to be set.

cEntries

Specifies the number of logical-palette entries to be set.

lppe

Points to the first member of an array of PALETTEENTRY structures containing the RGB values and flags.

Return Value

If the function succeeds, the return value is the number of entries that were set in the logical palette.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

An application can determine whether or not a device supports palette operations by calling the GetDeviceCaps function and specifying the RASTERCAPS constant.

Even if a logical palette has been selected and realized, changes to the palette do not affect the physical palette in the surface. RealizePalette must be called again to set the new logical palette into the surface.

See Also

GetDeviceCaps, RealizePalette, PALETTEENTRY


SetParent
SetParent  QuickInfo  Overview  Group

The SetParent function changes the parent window of the specified child window.

HWND SetParent(

HWND  hwndChild,	// handle of window whose parent is changing
HWND  hwndNewParent	// handle of new parent window
);
Parameters

hwndChild

Identifies the child window.

hwndNewParent

Identifies the new parent window. If this parameter is NULL, the desktop window becomes the new parent window.

Return Value

If the function succeeds, the return value is the handle of the previous parent window.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

An application can use the SetParent function to set the parent window of a pop-up, overlapped, or child window. The new parent window and the child window must belong to the same application.

If the window identified by the hwndChild parameter is visible, Windows performs the appropriate redrawing and repainting.

See Also

GetParent


SetPixel
SetPixel  QuickInfo  Overview  Group

The SetPixel function sets the pixel at the specified coordinates to the specified color.

COLORREF SetPixel(

HDC  hdc,	// handle of device context
int  X,	// x-coordinate of pixel
int  Y,	// y-coordinate of pixel
COLORREF  crColor	// pixel color
);
Parameters

hdc

Identifies the device context.

X

Specifies the x-coordinate, in logical units, of the point to be set.

Y

Specifies the y-coordinate, in logical units, of the point to be set.

crColor

Specifies the color to be used to paint the point.

Return Value

If the function succeeds, the return value is the RGB value that the function sets the pixel to. This value may differ from the color specified by crColor; that happens when an exact match for the specified color cannot be found.

If the function fails, the return value is −1. To get extended error information, call GetLastError.

Remarks

The function fails if the pixel coordinates lie outside of the current clipping region.

Not all devices support the SetPixel function. For more information, see GetDeviceCaps.

See Also

GetDeviceCaps, SetPixelV


SetPixelV
SetPixelV  QuickInfo  Overview  Group

The SetPixelV function sets the pixel at the specified coordinates to the closest approximation of the specified color. The point must be in the clipping region and the visible part of the device surface.

BOOL SetPixelV(

HDC  hdc,	// handle of device context
int  X,	// x-coordinate of pixel
int  Y,	// y-coordinate of pixel
COLORREF  crColor	// new pixel color
);
Parameters

hdc

Identifies the device context.

X

Specifies the x-coordinate, in logical units, of the point to be set.

Y

Specifies the y-coordinate, in logical units, of the point to be set.

crColor

Specifies the color to be used to paint the point.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Not all devices support the SetPixelV function. For more information, see the description of the RC_BITBLT capability in the GetDeviceCaps function.

SetPixelV is faster than SetPixel because it does not need to return the color value of the point actually painted.

See Also

GetDeviceCaps, SetPixel


SetPolyFillMode
SetPolyFillMode  QuickInfo  Overview  Group

The SetPolyFillMode function sets the polygon fill mode for functions that fill polygons.

int SetPolyFillMode(

HDC  hdc,	// handle of device context
int  iPolyFillMode	// polygon fill mode
);
Parameters

hdc

Identifies the device context.

iPolyFillMode

Specifies the new fill mode. This parameter can be either of the following values:

Value	Meaning
ALTERNATE	Selects alternate mode (fills the area between odd-numbered and even-numbered polygon sides on each scan line).
WINDING	Selects winding mode (fills any region with a nonzero winding value).
Return Value

The return value specifies the previous filling mode. If an error occurs, the return value is zero.

Remarks

In general, the modes differ only in cases where a complex, overlapping polygon must be filled (for example, a five-sided polygon that forms a five-pointed star with a pentagon in the center). In such cases, ALTERNATE mode fills every other enclosed region within the polygon (that is, the points of the star), but WINDING mode fills all regions (that is, the points and the pentagon).

When the fill mode is ALTERNATE, GDI fills the area between odd-numbered and even-numbered polygon sides on each scan line. That is, GDI fills the area between the first and second side, between the third and fourth side, and so on.

When the fill mode is WINDING, GDI fills any region that has a nonzero winding value. This value is defined as the number of times a pen used to draw the polygon would go around the region. The direction of each edge of the polygon is important.

See Also

GetPolyFillMode


SetPrinter
SetPrinter  QuickInfo  Overview  Group

The SetPrinter function sets the specified printer by pausing printing, resuming printing, or clearing all print jobs. The function can also be used to set printer data.

BOOL SetPrinter(

HANDLE  hPrinter,	// handle of printer object
DWORD  dwLevel,	// structure level
LPBYTE  lpbPrinter,	// address of array containing printer data
DWORD  dwCommand	// printer-state command
);
Parameters

hPrinter

Identifies the printer.

dwLevel

Windows 95: Specifies the type of data contained in lpbPrinter. This parameter must be 0, 2, 3, 4, or 5. This parameter must be zero if dwCommand is not equal to zero.

Windows NT: Specifies the type of data contained in lpbPrinter. This parameter must be 0, 2, or 3. This parameter must be zero if dwCommand is not equal to zero.

lpbPrinter

Windows 95: Contains either a DWORD value indicating the printer status or points to an array of bytes that may contain printer data. If dwLevel is 0, and the dwCommand parameter is PRINTER_CONTROL_STATUS, lpbPrinter must contain a DWORD value that specifies the new printer status to set. For a list of the possible status values, see the Status member of the PRINTER_INFO_2 structure. Note that PRINTER_STATUS_PAUSED and PRINTER_STATUS_PENDING_DELETION are not valid status values to set. Otherwise, when dwLevel is 0, this parameter must be NULL. If dwLevel is 2, 3, 4, or 5, lpbPrinter points to an array that contains PRINTER_INFO_2, PRINTER_INFO_3, PRINTER_INFO_4, or PRINTER_INFO_5 structures, respectively.

Windows NT: Contains either a DWORD value indicating the printer status or points to an array of bytes that may contain printer data. For a list of the possible status values, see the Status member of the PRINTER_INFO_2 structure. Note that PRINTER_STATUS_PAUSED and PRINTER_STATUS_PENDING_DELETION are not valid status values to set. Otherwise, when dwLevel is 0, this parameter must be NULL. If dwLevel is 2 or 3, lpbPrinter points to an array that contains PRINTER_INFO_2 or PRINTER_INFO_3 structures, respectively.

dwCommand

Specifies the new printer state. This parameter can be zero or one of the following values. If it is zero, the printer retains its original state and the printer data is reconfigured by using the structure to which lpbPrinter points.

Value	Meaning
PRINTER_CONTROL_PAUSE	Pauses the printer.
PRINTER_CONTROL_PURGE	Deletes all print jobs in the printer.
PRINTER_CONTROL_RESUME	Resumes a paused printer.
PRINTER_CONTROL_SET_STATUS	Windows 95: Sets the printer status.
If dwCommand is any of the above values, dwLevel must be zero.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The handle hPrinter is obtained by calling the OpenPrinter function.

To modify the current printer settings, an application should call GetPrinter to retrieve the current settings into a PRINTER_INFO_2 structure, modify the members of that structure as necessary, and then call the SetPrinter function.

The SetPrinter function ignores the following members of a PRINTER_INFO_2 structure:

pServerName, AveragePPM, Status, and cJobs

Pausing a printer suspends scheduling of all print jobs for that printer, except for the one print job that may be currently printing. Print jobs can be submitted to a paused printer, but no jobs will be scheduled to print on that printer until printing is resumed. If a printer is cleared, all print jobs for that printer are deleted, except for the current print job.

If the printer data structure contains a pointer to a security descriptor, only those components of the security descriptor that the caller has permission to write should be present. An application that wants to write particular security descriptor components must open the printer with sufficient access permission to modify those components. The following table shows the security descriptor components that can be modified for particular access permission values:

Access Permission	Modifiable Security Descriptor Components
WRITE_OWNER	Owner, primary proup
WRITE_DAC	Discretionary access-control list (ACL)
ACCESS_SYSTEM_SECURITY	System ACL
If the calling application lacks a required permission, SetPrinter fails. Those components of a security descriptor that an application does not wish to modify should be NULL or not be present, as appropriate. If you do not want to modify the security descriptor, and are calling SetPrinter with a PRINTER_INFO_2 structure, set the pSecurityDescriptor member of that structure to NULL.

Windows 95: SetPrinter does not update the pShareName member in the PRINTER_INFO_2 structure.

Windows 95: SetPrinter is not supported when called against a Windows NT printer from a Windows 95 machine using the printer's UNC name.

See Also

AddPrinter, GetPrinter, OpenPrinter, PRINTER_INFO_2, PRINTER_INFO_3


SetPrinterData
SetPrinterData  QuickInfo  Overview  Group

The SetPrinterData function sets the configuration data for a printer.

DWORD SetPrinterData(

HANDLE  hPrinter,	// handle of printer object
LPTSTR  lpszType,	// address of data type
DWORD  dwType,	// flag for value type
LPBYTE  lpbData,	// address of array that specifies printer data
DWORD  cbData	// size, in bytes, of array
);
Parameters

hPrinter

Identifies the printer for which the configuration data should be set.

lpszType

Points to a null-terminated string that specifies the type of data to be set.

dwType

Specifies the type of information to be stored as the value's data. This parameter can be one of the following values:

Value	Meaning
REG_BINARY	Binary data in any form.
REG_DWORD	A 32-bit number.
REG_DWORD_LITTLE_ENDIAN	A 32-bit number in little-endian format (same as REG_DWORD). In little-endian format, the most significant byte of a word is the high-order word. This is the most common format for computers running Windows NT and Windows 95.
REG_DWORD_BIG_ENDIAN	A 32-bit number in big-endian format. In big-endian format, the most significant byte of a word is the low-order word.
REG_EXPAND_SZ	A null-terminated string that contains unexpanded references to environment variables (for example, "%PATH%"). It will be a Unicode or ANSI string depending on whether you use the Unicode or ANSI functions.
REG_LINK	A Unicode symbolic link.
REG_MULTI_SZ	An array of null-terminated strings, terminated by two null characters.
REG_NONE	No defined value type.
REG_RESOURCE_LIST	A device-driver resource list.
REG_SZ	A null-terminated string. It will be a Unicode or ANSI string depending on whether you use the Unicode or ANSI functions.
lpbData

Points to an array of bytes that contains the printer configuration data.

cbData

Specifies the size, in bytes, of the array.

Return Value

If the function succeeds, the return value is ERROR_SUCCESS.

If the function fails, the return value is an error value.

Remarks

The handle hPrinter is obtained by calling the OpenPrinter function.

Existing configuration data for a printer can be retrieved by calling the GetPrinter function.

See Also

GetPrinter, OpenPrinter


SetPriorityClass
SetPriorityClass  QuickInfo  Overview  Group

The SetPriorityClass function sets the priority class for the specified process. This value together with the priority value of each thread of the process determines each thread's base priority level.

BOOL SetPriorityClass(

HANDLE  hProcess,	// handle to the process
DWORD  fdwPriority	// priority class value
);
Parameters

hProcess

Identifies the process. The handle must have PROCESS_SET_INFORMATION access.

fdwPriority

Specifies the priority class for the process. Specify one of the following values:

Priority	Meaning
HIGH_PRIORITY_CLASS	Indicates a process that performs time-critical tasks that must be executed immediately for it to run correctly. The threads of a high-priority class process preempt the threads of normal or idle priority class processes. An example is Windows Task List, which must respond quickly when called by the user, regardless of the load on the operating system. Use extreme care when using the high-priority class, because a high-priority class CPU-bound application can use nearly all available cycles.
IDLE_PRIORITY_CLASS	Indicates a process whose threads run only when the system is idle and are preempted by the threads of any process running in a higher priority class. An example is a screen saver. The idle-priority class is inherited by child processes.
NORMAL_PRIORITY_CLASS	Indicates a normal process with no special scheduling needs.
REALTIME_PRIORITY_CLASS	Indicates a process that has the highest possible priority. The threads of a real-time priority class process preempt the threads of all other processes, including operating system processes performing important tasks. For example, a real-time process that executes for more than a very brief interval can cause disk caches not to flush or cause the mouse to be unresponsive.
Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Every thread has a base priority level determined by the thread's priority value and the priority class of its process. The system uses the base priority level of all executable threads to determine which thread gets the next slice of CPU time. Threads are scheduled in a round-robin fashion at each priority level, and only when there are no executable threads at a higher level will scheduling of threads at a lower level take place.

The base priority level of a thread is in the range 1 through 31. Following are the normal base priority levels for each priority class:

Class	Normal base priority
HIGH_PRIORITY_CLASS	13
IDLE_PRIORITY_CLASS	4
NORMAL_PRIORITY_CLASS	9 if the window of the process is in the foreground; and 7 if the window is in the background
REALTIME_PRIORITY_CLASS	24
The SetThreadPriority function enables setting the base priority level of a thread relative to the priority class of its process. For example, specifying THREAD_PRIORITY_HIGHEST in a call to SetThreadPriority for a thread of an IDLE_PRIORITY_CLASS process sets the thread's base priority level to 6.

For IDLE_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS, and HIGH_PRIORITY_CLASS processes, the system dynamically boosts a thread's base priority level when events occur that are important to the thread. REALTIME_PRIORITY_CLASS processes do not receive dynamic boosts.

The initial priority class of a process can be specified in the CreateProcess function. If not specified, the priority class defaults to NORMAL_PRIORITY_CLASS unless the priority class of the creating process is IDLE_PRIORITY_CLASS. In this case, the default priority class of the child process is IDLE_PRIORITY_CLASS.

Be very careful when manipulating priorities to ensure that a high-priority thread does not consume all of the available CPU time. A thread with a base priority level above 11 interferes with the normal operation of the operating system.

The following table shows the base priority levels for each combination of priority class and thread priority value. Note that for IDLE_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS, and HIGH_PRIORITY_CLASS, this base level can receive dynamic boosts.

Base	Priority class/thread priority
1	Idle, normal, or high class, THREAD_PRIORITY_IDLE
2	Idle class, THREAD_PRIORITY_LOWEST
3	Idle class, THREAD_PRIORITY_BELOW_NORMAL
4	Idle class, THREAD_PRIORITY_NORMAL
5	Background normal class, THREAD_PRIORITY_LOWEST Idle class, THREAD_PRIORITY_ABOVE_NORMAL
6	Background normal class, THREAD_PRIORITY_BELOW_NORMAL Idle class, THREAD_PRIORITY_HIGHEST
7	Foreground normal class, THREAD_PRIORITY_LOWEST Background normal class, THREAD_PRIORITY_NORMAL
8	Foreground normal class, THREAD_PRIORITY_BELOW_NORMAL Background normal class, THREAD_PRIORITY_ABOVE_NORMAL
9	Foreground normal class, THREAD_PRIORITY_NORMAL Background normal class, THREAD_PRIORITY_HIGHEST
10	Foreground normal class, THREAD_PRIORITY_ABOVE_NORMAL
11	High class, THREAD_PRIORITY_LOWEST Foreground normal class, THREAD_PRIORITY_HIGHEST
12	High class, THREAD_PRIORITY_BELOW_NORMAL
13	High class, THREAD_PRIORITY_NORMAL
14	High class, THREAD_PRIORITY_ABOVE_NORMAL
15	Idle, normal, or high class, THREAD_PRIORITY_TIME_CRITICAL High class, THREAD_PRIORITY_HIGHEST
16	Real-time class, THREAD_PRIORITY_IDLE
22	Real-time class, THREAD_PRIORITY_LOWEST
23	Real-time class, THREAD_PRIORITY_BELOW_NORMAL
24	Real-time class, THREAD_PRIORITY_NORMAL
25	Real-time class, THREAD_PRIORITY_ABOVE_NORMAL
26	Real-time class, THREAD_PRIORITY_HIGHEST
31	Real-time class, THREAD_PRIORITY_TIME_CRITICAL
See Also

CreateProcess, CreateThread, GetPriorityClass, GetThreadPriority, SetThreadPriority


SetPrivateObjectSecurity
SetPrivateObjectSecurity  QuickInfo  Overview  Group

The SetPrivateObjectSecurity function modifies a private object's security descriptor.

BOOL SetPrivateObjectSecurity(

SECURITY_INFORMATION  si,	// type of security information
PSECURITY_DESCRIPTOR  psdSource,	// address of SD to apply to object
PSECURITY_DESCRIPTOR  *lppsdTarget,	// address of object's SD
PGENERIC_MAPPING  pgm,	// address of access-mapping structure
HANDLE  hClientToken	// handle of client access token
);
Parameters

si

Specifies a SECURITY_INFORMATION structure identifying the contents of the security descriptor pointed to by the psdSource parameter.

psdSource

Points to a SECURITY_DESCRIPTOR structure to be applied to the object.

lppsdTarget

Points to a pointer to a SECURITY_DESCRIPTOR structure to be altered by this function. This security descriptor must be in self-relative form.

pgm

Points to a GENERIC_MAPPING structure specifying the mapping of generic to specific and standard access types for the object.

hClientToken

Identifies the access token for the client on whose behalf the private object's security is being modified. This parameter is required to ensure that the client has provided a legitimate value for a new owner security identifier (SID). The token must be open for TOKEN_QUERY access.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The object's security descriptor must be in self-relative form.

If necessary, the SetPrivateObjectSecurity function allocates additional memory to produce a larger security descriptor.

The SetPrivateObjectSecurity function is successful only if the following conditions are met:

•	If the object's owner is being set, the calling process must have either WRITE_OWNER permission or be the object's owner.

•	If the object's discretionary access-control list (ACL) is being set, the calling process must have either WRITE_DAC permission or be the object's owner.

•	If the object's system ACL is being set, the SE_SECURITY_NAME privilege must be enabled for the calling process.

The process calling this function must not be impersonating a client.

See Also

CreatePrivateObjectSecurity, DestroyPrivateObjectSecurity, GENERIC_MAPPING, GetPrivateObjectSecurity, SECURITY_DESCRIPTOR, SECURITY_INFORMATION, SetFileSecurity, SetKernelObjectSecurity, SetUserObjectSecurity


SetProcessShutdownParameters
SetProcessShutdownParameters  QuickInfo  Overview  Group

The SetProcessShutdownParameters function sets shutdown parameters for the currently calling process. This function sets a shutdown order for a process relative to the other processes in the system.

BOOL SetProcessShutdownParameters(

DWORD  dwLevel,	// shutdown priority
DWORD  dwFlags	// shutdown flags
);
Parameters

dwLevel

Specifies the shutdown priority for a process relative to other processes in the system. The system shuts down processes from high dwLevel values to low. The highest and lowest shutdown priorities are reserved for system components. This parameter must be in the following range of values:

Value	Meaning
000−0FF	System reserved last shutdown range.
100−1FF	Application reserved last shutdown range.
200−2FF	Application reserved "in between" shutdown range.
300−3FF	Application reserved first shutdown range.
400−4FF	System reserved first shutdown range.
All processes start at shutdown level 0x280.

dwFlags

Specifies a flags parameter. It can be the following value:

Value	Meaning
SHUTDOWN_NORETRY	Specifies whether to retry the shutdown if the specified time-out period expires. If this flag is specified, the system terminates the process without displaying a retry dialog box for the user.
Return Value

If the function is succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

Applications running in the system security context do not get shut down by the operating system. They get notified of shutdown or logoff through the callback function installable via SetConsoleCtrlHandler. They also get notified in the order specified by the dwLevel parameter.

See Also

GetProcessShutdownParameters, SetConsoleCtrlHandler


SetProcessWindowStation [New - Windows NT]
SetProcessWindowStation  QuickInfo  Overview  Group

[New - Windows NT]

The SetProcessWindowStation function assigns a window station to the calling process. This enables the process to access objects in the window station such as desktops, the clipboard, and global atoms. All subsequent operations on the window station use the access rights granted to hWinSta.

BOOL SetProcessWindowStation(

HWINSTA hWinSta	// handle of window station to assign to this process
);
Parameters

hWinSta

Identifies the window station to be assigned to the calling process. This handle is returned by the CreateWindowStation and OpenWindowStation functions.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

CreateWindowStation, OpenWindowStation, SetThreadDesktop


SetProcessWorkingSetSize
SetProcessWorkingSetSize  QuickInfo  Overview  Group

The SetProcessWorkingSetSize function sets the minimum and maximum working set sizes for a specified process.

The working set of a process is the set of memory pages currently visible to the process in physical RAM memory. These pages are resident and available for an application to use without triggering a page fault. The size of the working set of a process is specified in bytes. The minimum and maximum working set sizes affect the virtual memory paging behavior of a process.

BOOL SetProcessWorkingSetSize(

HANDLE  hProcess,	// open handle to the process of interest
DWORD  dwMinimumWorkingSetSize,	// specifies minimum working set size
DWORD  dwMaximumWorkingSetSize	// specifies maximum working set size
);
Parameters

hProcess

An open handle to the process whose working set sizes will be set. The handle must have PROCESS_QUERY_INFORMATION access rights.

dwMinimumWorkingSetSize

Specifies a minimum working set size for the process. The virtual memory manager attempts to keep at least this much memory resident in the process whenever the process is active.

If both dwMinimumWorkingSetSize and dwMaximumWorkingSetSize have the value 0xffffffff, the function temporarily trims the working set of the specified process to zero. This essentially swaps the process out of physical RAM memory.

dwMaximumWorkingSetSize

Specifies a maximum working set size for the process. The virtual memory manager attempts to keep no more than this much memory resident in the process whenever the process is active and memory is in short supply.

If both dwMinimumWorkingSetSize and dwMaximumWorkingSetSize have the value 0xffffffff, the function temporarily trims the working set of the specified process to zero. This essentially swaps the process out of physical RAM memory.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. Call GetLastError to obtain extended error information.

Remarks

The working set of the specified process can be emptied by specifying the value 0xffffffff for both the minimum and maximum working set sizes.

If the values of either dwMinimumWorkingSetSize or dwMaximumWorkingSetSize are greater than the process' current working set sizes, the specified process must have the SE_INC_BASE_PRIORITY_PRIVILEGE privilege. Users in the Administrators and Power Users groups generally have this privilege.

The operating system allocates working set sizes on a first-come, first-served basis. For example, if an application successfully sets 40 megabytes as its minimum working set size on a 64-megabyte system, and a second application requests a 40-megabyte working set size, the operating system denies the second application's request.

Using the SetProcessWorkingSetSize function to set an application's minimum and maximum working set sizes does not guarantee that the requested memory will be reserved, or that it will remain resident at all times. When the application is idle, or a low-memory situation causes a demand for memory, the operating system can reduce the application's working set. An application can use the VirtualLock function to lock ranges of the application's virtual address space in memory; however, that can potentially degrade the performance of the system.

When you increase the working set size of an application, you are taking away physical memory from the rest of the system. This can degrade the performance of other applications and the system as a whole. It can also lead to failures of operations that require physical memory to be present; for example, creating processes, threads, and kernel pool. Thus, you must use the SetProcessWorkingSetSize function carefully. You must always consider the performance of the whole system when you are designing an application.

See Also

GetProcessWorkingSetSize, VirtualLock


SetProp
SetProp  QuickInfo  Overview  Group

The SetProp function adds a new entry or changes an existing entry in the property list of the specified window. The function adds a new entry to the list if the specified character string does not exist already in the list. The new entry contains the string and the handle. Otherwise, the function replaces the string's current handle with the specified handle.

BOOL SetProp(

HWND  hwnd,	// handle of window
LPCTSTR  lpsz,	// atom or address of string
HANDLE  hData	// handle of data
);
Parameters

hwnd

Identifies the window whose property list receives the new entry.

lpsz

Points to a null-terminated string or contains an atom that identifies a string. If this parameter is an atom, it must be a global atom created by a previous call to the GlobalAddAtom function. The atom, a 16-bit value, must be placed in the low-order word of lpsz; the high-order word must be zero.

hData

Identifies data to be copied to the property list. The data handle can identify any value useful to the application.

Return Value

If the data handle and string are added to the property list, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

Before destroying a window (that is, before processing the WM_DESTROY message), an application must remove all entries it has added to the property list. The application must use the RemoveProp function to remove the entries.

See Also

EnumProps, EnumPropsEx, GetProp, GlobalAddAtom, RemoveProp


SetRect
SetRect  QuickInfo  Overview  Group

The SetRect function sets the coordinates of the specified rectangle. This is equivalent to assigning the left, top, right, and bottom arguments to the appropriate members of the RECT structure.

BOOL SetRect(

LPRECT  lprc,	// address of structure with rectangle to set
int  nLeft,	// left side
int  nTop,	// top side
int  nRight,	// right side
int  nBottom	// bottom side
);
Parameters

lprc

Points to the RECT structure that contains the rectangle to be set.

nLeft

Specifies the x-coordinate of the rectangle's upper-left corner.

nTop

Specifies the y-coordinate of the rectangle's upper-left corner.

nRight

Specifies the x-coordinate of the rectangle's lower-right corner.

nBottom

Specifies the y-coordinate of the rectangle's lower-right corner.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

CopyRect, SetRectEmpty, RECT


SetRectEmpty
SetRectEmpty  QuickInfo  Overview  Group

The SetRectEmpty function creates an empty rectangle in which all coordinates are set to zero.

BOOL SetRectEmpty(

LPRECT  lprc	// address of structure with rectangle set to empty
);
Parameters

lprc

Points to the RECT structure that contains the coordinates of the rectangle.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

CopyRect, RECT, SetRect


SetRectRgn
SetRectRgn  QuickInfo  Overview  Group

The SetRectRgn function changes a region into a rectangular region with the specified coordinates.

BOOL SetRectRgn(

HRGN  hrgn,	// handle of region
int  nLeftRect,	// x-coordinate of upper-left corner of rectangle
int  nTopRect,	// y-coordinate of upper-left corner of rectangle
int  nRightRect,	// x-coordinate of lower-right corner of rectangle
int  nBottomRect	// y-coordinate of lower-right corner of rectangle
);
Parameters

hrgn

Identifies the region.

nLeftRect

Specifies the x-coordinate of the upper-left corner of the rectangular region.

nTopRect

Specifies the y-coordinate of the upper-left corner of the rectangular region.

nRightRect

Specifies the x-coordinate of the lower-right corner of the rectangular region.

nBottomRect

Specifies the y-coordinate of the lower-right corner of the rectangular region.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

The region does not include the lower and right boundaries of the rectangle.

See Also

CreateRectRgn


SetResourceHandler
SetResourceHandler  Overview  Group

The SetResourceHandler function is not implemented in the Win32 API. Calculated resources do not work in the 32-bit environment.


SetROP2
SetROP2  QuickInfo  Overview  Group

The SetROP2 function sets the current foreground mix mode. GDI uses the foreground mix mode to combine pens and interiors of filled objects with the colors already on the screen. The foreground mix mode defines how colors from the brush or pen and the colors in the existing image are to be combined.

int SetROP2(

HDC  hdc,	// handle of device context
int  fnDrawMode	// drawing mode
);
Parameters

hdc

Identifies the device context.

fnDrawMode

Specifies the new mix mode. This parameter can be any one of the following values:

Mix mode	Description
R2_BLACK	Pixel is always 0.
R2_COPYPEN	Pixel is the pen color.
R2_MASKNOTPEN	Pixel is a combination of the colors common to both the screen and the inverse of the pen.
R2_MASKPEN	Pixel is a combination of the colors common to both the pen and the screen.
R2_MASKPENNOT	Pixel is a combination of the colors common to both the pen and the inverse of the screen.
R2_MERGENOTPEN	Pixel is a combination of the screen color and the inverse of the pen color.
R2_MERGEPEN	Pixel is a combination of the pen color and the screen color.
R2_MERGEPENNOT	Pixel is a combination of the pen color and the inverse of the screen color.
R2_NOP	Pixel remains unchanged.
R2_NOT	Pixel is the inverse of the screen color.
R2_NOTCOPYPEN	Pixel is the inverse of the pen color.
R2_NOTMASKPEN	Pixel is the inverse of the R2_MASKPEN color.
R2_NOTMERGEPEN	Pixel is the inverse of the R2_MERGEPEN color.
R2_NOTXORPEN	Pixel is the inverse of the R2_XORPEN color.
R2_WHITE	Pixel is always 1.
R2_XORPEN	Pixel is a combination of the colors in the pen and in the screen, but not in both.
Return Value

If the function succeeds, the return value specifies the previous mix mode.

If the function fails, the return value is zero.

Remarks

Mix modes define how GDI combines source and destination colors when drawing with the current pen. The mix modes are binary raster operation codes, representing all possible Boolean functions of two variables, using the binary operations AND, OR, and XOR (exclusive OR), and the unary operation NOT. The mix mode is for raster devices only; it is not available for vector devices.

See Also

GetROP2


SetScrollInfo [New - Windows NT]
SetScrollInfo  QuickInfo

[New - Windows NT]

The SetScrollInfo function sets the parameters of a scroll bar, including the minimum and maximum scrolling positions, the page size, and the position of the scroll box (thumb). The function also redraws the scroll bar, if requested.

int SetScrollInfo(

HWND  hwnd,	// handle of window with scroll bar
int  fnBar,	// scroll bar flag
LPSCROLLINFO  lpsi,	// pointer to structure with scroll parameters
BOOL  fRedraw	// redraw flag
);
Parameters

hwnd

Identifies a scroll bar control or a window with a standard scroll bar, depending on the value of the fnBar parameter.

fnBar

Specifies the type of scroll bar for which to set parameters. This parameter can be one of the following values:

Value	Meaning
SB_CTL	Sets the parameters of a scroll bar control. The hwnd parameter must be the handle of the scroll bar control.
SB_HORZ	Sets the parameters of the given window's standard horizontal scroll bar.
SB_VERT	Sets the parameters of the given window's standard vertical scroll bar.
lpsi

Points to a SCROLLINFO structure whose fMask member, upon entry to the function, specifies the scroll bar parameters to set.

The fMask member can be a combination of the following values:

Value	Meaning
SIF_DISABLENOSCROLL	Disables the scroll bar instead of removing it, if the scroll bar's new parameters make the scroll bar unnecessary.
SIF_PAGE	Sets the scroll page to the value specified in the nPage member of the SCROLLINFO structure pointed to by lpsi.
SIF_POS	Sets the scroll position to the value specified in the nPos member of the SCROLLINFO structure pointed to by lpsi.
SIF_RANGE	Sets the scroll range to the value specified in the nMin and nMax members of the SCROLLINFO structure pointed to by lpsi.
fRedraw

Specifies whether the scroll bar is redrawn to reflect the changes to the scroll bar. If this parameter is TRUE, the scroll bar is redrawn, otherwise, it is not redrawn.

Return Value

The return value is the current position of the scroll box.

Remarks

The SetScrollInfo function performs range checking on the values specified by the nPage and nPos members of the SCROLLINFO structure. The nPage member must specify a value from 0 to nMax - nMin +1. The nPos member must specify a value between nMin and nMax - max(nPage  − 1, 0). If either value is beyond its range, the function sets it to a value that is just within the range.

See Also

GetScrollInfo, SCROLLINFO


SetScrollPos
SetScrollPos  QuickInfo  Overview  Group

The SetScrollPos function sets the position of the scroll box (thumb) in the specified scroll bar and, if requested, redraws the scroll bar to reflect the new position of the scroll box. The SetScrollPos function is provided for compatibility with Windows 3.x. Win32-based applications should use the SetScrollInfo function.

int SetScrollPos(

HWND  hwnd,	// handle of window with scroll bar
int  fnBar,	// scroll bar flag
int  nPos,	// new position of scroll box
BOOL  fRedraw	// redraw flag
);
Parameters

hwnd

Identifies a scroll bar control or a window with a standard scroll bar, depending on the value of the fnBar parameter.

fnBar

Specifies the scroll bar to be set. This parameter can be one of the following values:

Value	Meaning
SB_CTL	Sets the position of the scroll box in a scroll bar control. The hwnd parameter must be the handle of the scroll bar control.
SB_HORZ	Sets the position of the scroll box in a window's standard horizontal scroll bar.
SB_VERT	Sets the position of the scroll box in a window's standard vertical scroll bar.
nPos

Specifies the new position of the scroll box. The position must be within the scrolling range. For more information about the scrolling range, see the SetScrollRange function.

fRedraw

Specifies whether the scroll bar is redrawn to reflect the new scroll box position. If this parameter is TRUE, the scroll bar is redrawn. If it is FALSE, the scroll bar is not redrawn.

Return Value

If the function succeeds, the return value is the previous position of the scroll box.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

If the scroll bar is redrawn by a subsequent call to another function, setting the fRedraw parameter to FALSE is useful.

Because the messages that indicate scroll bar position, WM_HSCROLL and WM_VSCROLL, are limited to 16 bits of position data, applications that rely solely on those messages for position data have a practical maximum value of 65,535 for the SetScrollPos function's nPos parameter.

However, because the SetScrollPos, SetScrollRange, GetScrollPos, and GetScrollRange functions support 32-bit scroll bar position data, there is a way to circumvent the 16-bit barrier of the WM_HSCROLL and WM_VSCROLL messages. See GetScrollPos for a description of the technique and its limits.

See Also

GetScrollPos, GetScrollRange, ScrollDC, ScrollWindow, SetScrollRange


SetScrollRange
SetScrollRange  QuickInfo  Overview  Group

The SetScrollRange function sets the minimum and maximum position values for the specified scroll bar. It can also be used to hide or show a standard scroll bar.The SetScrollRange function is provided for compatibility with Windows 3.x. Win32-based applications should use the SetScrollInfo function.

BOOL SetScrollRange(

HWND  hwnd,	// handle of window with scroll bar
int  fnBar,	// scroll bar flag
int  nMinPos,	// minimum scrolling position
int  nMaxPos,	// maximum scrolling position
BOOL  fRedraw	// redraw flag
);
Parameters

hwnd

Identifies a scroll bar control or a window with a standard scroll bar, depending on the value of the fnBar parameter.

fnBar

Specifies the scroll bar to be set. This parameter can be one of the following values:

Value	Meaning
SB_CTL	Sets the range of a scroll bar control. The hwnd parameter must be the handle of the scroll bar control.
SB_HORZ	Sets the range of a window's standard horizontal scroll bar.
SB_VERT	Sets the range of a window's standard vertical scroll bar.
nMinPos

Specifies the minimum scrolling position.

nMaxPos

Specifies the maximum scrolling position.

fRedraw

Specifies whether the scroll bar should be redrawn to reflect the change. If this parameter is TRUE, the scroll bar is redrawn. If it is FALSE, the scroll bar is not redrawn.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

An application should not call the SetScrollRange function to hide a scroll bar while processing a scroll bar message.

If the call to SetScrollRange immediately follows a call to the SetScrollPos function, the fRedraw parameter in SetScrollPos must be zero to prevent the scroll bar from being drawn twice.

The default range for a standard scroll bar is 0 through 100. The default range for a scroll bar control is empty (both the nMinPos and nMaxPos parameter values are zero). The difference between the values specified by the nMinPos and nMaxPos parameters must not be greater than the value of MAXLONG.

Because the messages that indicate scroll bar position, WM_HSCROLL and WM_VSCROLL, are limited to 16 bits of position data, applications that rely solely on those messages for position data have a practical maximum value of 65,535 for the SetScrollRange function's nMaxPos parameter.

However, because the SetScrollPos, SetScrollRange, GetScrollPos, and GetScrollRange functions support 32-bit scroll bar position data, there is a way to circumvent the 16-bit barrier of the WM_HSCROLL and WM_VSCROLL messages. See GetScrollPos for a description of the technique and its limits.

See Also

GetScrollPos, GetScrollRange, SetScrollPos


SetSecurityDescriptorDacl
SetSecurityDescriptorDacl  QuickInfo  Overview  Group

The SetSecurityDescriptorDacl function sets information in a discretionary access-control list (ACL). If a discretionary ACL is already present in the security descriptor, it is replaced.

BOOL SetSecurityDescriptorDacl(

PSECURITY_DESCRIPTOR  psd,	// address of security descriptor
BOOL  fDaclPresent,	// flag for presence of discretionary ACL
PACL  pAcl,	// address of discretionary ACL
BOOL  fDaclDefaulted	// flag for default discretionary ACL
);
Parameters

psd

Points to the SECURITY_DESCRIPTOR structure to which the function adds the discretionary ACL. This security descriptor must be in absolute format, meaning that its members must be pointers to other structures, rather than offsets to contiguous data.

fDaclPresent

Specifies a flag indicating the presence of a discretionary ACL in the security descriptor. If this parameter is TRUE, the function sets the SE_DACL_PRESENT flag in the SECURITY_DESCRIPTOR_CONTROL structure and uses the values in the pAcl and fDaclDefaulted parameters. If it is FALSE, the function clears the SE_DACL_PRESENT flag, and pAcl and fDaclDefaulted are ignored.

pAcl

Points to an ACL structure specifying the discretionary ACL for the security descriptor. If this parameter is NULL, a NULL discretionary ACL is assigned to the security descriptor, allowing all access to the object. The discretionary ACL is referenced by, not copied into, the security descriptor.

fDaclDefaulted

Specifies a flag indicating the source of the discretionary ACL. If this flag is TRUE, the discretionary ACL has been retrieved by some default mechanism. If FALSE, the discretionary ACL has been explicitly specified by a user. The function stores this value in the SE_DACL_DEFAULTED flag of the SECURITY_DESCRIPTOR_CONTROL structure. If this parameter is not specified, the SE_DACL_DEFAULTED flag is cleared.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

There is an important difference between an empty and a nonexistent discretionary ACL. When a discretionary ACL is empty, it contains no access-control entries and no access rights have been explicitly granted. As a result, access to the object is implicitly denied. When an object has no DACL, on the other hand, no protection is assigned to the object, and any access request is granted.

There are three possible outcomes in different configurations of the fDaclPresent flag and the pAcl parameter:

•	When the pACL parameter points to a discretionary ACL and the fDaclPresent flag is TRUE, a discretionary ACL is specified and it must contain access-allowed ACEs to allow access to the object.

•	When the pACL parameter does not point to a discretionary ACL and the fDaclPresent flag is TRUE, a NULL discretionary ACL is specified. All access is allowed.

•	When the pACL parameter does not point to a discretionary ACL and the fDaclPresent flag is FALSE, a discretionary ACL can be provided for the object through an inheritance or default mechanism.

See Also

ACL, GetSecurityDescriptorDacl, InitializeSecurityDescriptor, IsValidSecurityDescriptor, SECURITY_DESCRIPTOR, SECURITY_DESCRIPTOR_CONTROL, SetSecurityDescriptorGroup, SetSecurityDescriptorOwner, SetSecurityDescriptorSacl


SetSecurityDescriptorGroup
SetSecurityDescriptorGroup  QuickInfo  Overview  Group

The SetSecurityDescriptorGroup function sets the primary group information of an absolute-format security descriptor, replacing any primary group information already present in the security descriptor.

BOOL SetSecurityDescriptorGroup(

PSECURITY_DESCRIPTOR  psd,	// address of security descriptor
PSID  psidGroup,	// address of SID for group
BOOL  fGroupDefaulted	// flag for default
);
Parameters

psd

Points to the SECURITY_DESCRIPTOR structure whose primary group is set by this function. The function replaces any existing primary group with the new primary group.

psidGroup

Points to a SID structure the function sets as the security descriptor's new primary group. The SID structure is referenced by, not copied into, the security descriptor. If this parameter is NULL, the function clears the security descriptor's primary group information. This marks the security descriptor as having no primary group.

fGroupDefaulted

Specifies a flag indicating whether the primary group information was derived from a default mechanism. If this flag is TRUE, it is default information, and the function stores this value as the SE_GROUP_DEFAULTED flag in the SECURITY_DESCRIPTOR_CONTROL structure. If this parameter is zero, the SE_GROUP_DEFAULTED flag is cleared.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

GetSecurityDescriptorGroup, InitializeSecurityDescriptor, SECURITY_DESCRIPTOR, SECURITY_DESCRIPTOR_CONTROL, SetSecurityDescriptorDacl, SetSecurityDescriptorOwner, SetSecurityDescriptorSacl, SID


SetSecurityDescriptorOwner
SetSecurityDescriptorOwner  QuickInfo  Overview  Group

The SetSecurityDescriptorOwner function sets the owner information of an absolute-format security descriptor. It replaces any owner information already present in the security descriptor.

BOOL SetSecurityDescriptorOwner(

PSECURITY_DESCRIPTOR  psd,	// address of security descriptor
PSID  psidOwner,	// address of SID for owner
BOOL  fOwnerDefaulted	// flag for default
);
Parameters

psd

Points to the SECURITY_DESCRIPTOR structure whose owner is set by this function. The function replaces any existing owner with the new owner.

psidOwner

Points to a SID structure the function sets as the security descriptor's new primary owner. The SID structure is referenced by, not copied into, the security descriptor. If this parameter is NULL, the function clears the security descriptor's owner information. This marks the security descriptor as having no owner.

fOwnerDefaulted

Specifies a flag indicating whether the owner information is derived from a default mechanism. If this flag is TRUE, it is default information. The function stores this value as the SE_OWNER_DEFAULTED flag in the SECURITY_DESCRIPTOR_CONTROL structure. If this parameter is zero, the SE_OWNER_DEFAULTED flag is cleared.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

GetSecurityDescriptorOwner, InitializeSecurityDescriptor, IsValidSecurityDescriptor, SECURITY_DESCRIPTOR, SECURITY_DESCRIPTOR_CONTROL, SetSecurityDescriptorDacl, SetSecurityDescriptorGroup, SetSecurityDescriptorSacl, SID


SetSecurityDescriptorSacl
SetSecurityDescriptorSacl  QuickInfo  Overview  Group

The SetSecurityDescriptorSacl function sets information in a system access-control list (ACL). If there is already a system ACL present in the security descriptor, it is replaced.

BOOL SetSecurityDescriptorSacl(

PSECURITY_DESCRIPTOR  psd,	// address of security descriptor
BOOL  fSaclPresent,	// flag for presence of system ACL
PACL  pAcl,	// address of system ACL
BOOL  fSaclDefaulted	// flag for default system ACL
);
Parameters

psd

Points to the SECURITY_DESCRIPTOR structure to which the function adds the system ACL. This security descriptor must be in absolute format, meaning that its members must be pointers to other structures, rather than offsets to contiguous data.

fSaclPresent

Specifies a flag indicating the presence of a system ACL in the security descriptor. If this parameter is TRUE, the function sets the SE_SACL_PRESENT flag in the SECURITY_DESCRIPTOR_CONTROL structure and uses the values in the pAcl and fSaclDefaulted parameters. If it is FALSE, the function does not set the SE_SACL_PRESENT flag, and pAcl and fSaclDefaulted are ignored.

pAcl

Points to an ACL structure that specifies the system ACL for the security descriptor. If this parameter is NULL, a NULL system ACL is assigned to the security descriptor. The system ACL is referenced by, not copied into, the security descriptor.

fSaclDefaulted

Specifies a flag indicating the source of the system ACL. If this flag is TRUE, the system ACL has been retrieved by some default mechanism. If it is FALSE, the system ACL has been explicitly specified by a user. The function stores this value in the SE_SACL_DEFAULTED flag of the SECURITY_DESCRIPTOR_CONTROL structure. If this parameter is not specified, the SE_SACL_DEFAULTED flag is cleared.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

ACL, GetSecurityDescriptorSacl, InitializeSecurityDescriptor, IsValidSecurityDescriptor, SECURITY_DESCRIPTOR, SECURITY_DESCRIPTOR_CONTROL, SetSecurityDescriptorDacl, SetSecurityDescriptorGroup, SetSecurityDescriptorOwner


SetService
SetService  QuickInfo  Overview  Group

The SetService function registers or deregisters a network service within one or more name spaces. The function can also add or remove a network service type within one or more name spaces.

INT SetService(

DWORD  dwNameSpace,	// specifies name space(s) to operate within
DWORD  dwOperation,	// specifies operation to perform
DWORD  dwFlags,	// set of bit flags that modify function operation
LPSERVICEINFO  lpServiceInfo,	// points to structure containing service information
LPSERVICE_ASYNC_INFO  lpServiceAsyncInfo,	// reserved for future use, must be NULL
LPDWORD  lpdwStatusFlags	// points to set of status bit flags
);
Parameters

dwNameSpace

Specifies the name space, or a set of default name spaces, within which the function will operate.

Use one of the following constants to specify a name space:

Value	Name Space
NS_DEFAULT	A set of default name spaces. The function queries each name space within this set. The set of default name spaces typically includes all the name spaces installed on the system. System administrators, however, can exclude particular name spaces from the set. NS_DEFAULT is the value that most applications should use for dwNameSpace.
NS_DNS	The Domain Name System used in the Internet to resolve the name of the host.
NS_NDS	The NetWare 4 provider.
NS_NETBT	The NetBIOS over TCP/IP layer. All Windows NT and Windows 95 systems register their computer names with NetBIOS. This name space is used to convert a computer name to an IP address that uses this registration.
NS_SAP	The NetWare Service Advertising Protocol. This can access the Netware bindery, if appropriate. NS_SAP is a dynamic name space that enables the registration of services.
NS_TCPIP_HOSTS	Lookup value in the <systemroot>\system32\drivers\etc\posts file.
NS_TCPIP_LOCAL	Local TCP/IP name resolution mechanisms, including comparisons against the local host name and lookup value in the cache of host to IP address mappings.
dwOperation

Specifies the operation that the function will perform. Use one of the following values to specify an operation:

Value	Meaning
SERVICE_REGISTER	Register the network service with the name space. This operation may be used with the SERVICE_FLAG_DEFER and SERVICE_FLAG_HARD bit flags.
SERVICE_DEREGISTER	Deregister the network service from the name space. This operation can be used with the SERVICE_FLAG_DEFER and SERVICE_FLAG_HARD bit flags.
SERVICE_FLUSH	Perform any operation that was called with the SERVICE_FLAG_DEFER bit flag set to one.
SERVICE_ADD_TYPE	Add a service type to the name space.  For this operation, use the ServiceSpecificInfo member of the SERVICE_INFO structure pointed to by lpServiceInfo to pass a SERVICE_TYPE_INFO_ABS structure. You must also set the ServiceType member of the SERVICE_INFO structure. Other SERVICE_INFO members are ignored.
SERVICE_DELETE_TYPE	Remove a service type, added by a previous call specifying the SERVICE_ADD_TYPE operation,  from the name space.
dwFlags

A set of bit flags that modify the function's operation. You can set one or more of the following bit flags:

Value	Name Space
SERVICE_FLAG_DEFER	This bit flag is valid only if the operation is SERVICE_REGISTER or SERVICE_DEREGISTER. If this bit flag is one, and it is valid, the name-space provider should defer the registration or deregistration operation until a SERVICE_FLUSH operation is requested.
SERVICE_FLAG_HARD	This bit flag is valid only if the operation is SERVICE_REGISTER or SERVICE_DEREGISTER. If this bit flag is one, and it is valid, the name-space provider updates any relevant persistent store information when the operation is performed.  For example: If the operation involves deregistration in a name space that uses a persistent store, the name-space provider would remove the relevant persistent store information.
lpService_Info

Points to a SERVICE_INFO structure that contains information about the network service or service type.

lpServiceAsyncInfo

This parameter is reserved for future use. It must be set to NULL.

lpdwStatusFlags

A set of bit flags that receive function status information. The following bit flag is defined:

Value	Meaning
SET_SERVICE_PARTIAL_SUCCESS	One or more name-space providers were unable to successfully perform the requested operation.
Return Value

If the function succeeds, the return value is not SOCKET_ERROR.

If the function fails, the return value is SOCKET_ERROR. To get extended error information, call GetLastError. GetLastError may return the following extended error value:

Value	Meaning
ERROR_ALREADY_REGISTERED	The function tried to register a service that was already registered.
See Also

GetService, SERVICE_INFO, SERVICE_TYPE_INFO_ABS


SetServiceBits
SetServiceBits  QuickInfo  Overview  Group

The SetServiceBits function registers a service's service type with the Service Control Manager and the Server service. The Server service can then announce the registered service type as one it currently supports. The LAN Manager functions NetServerGetInfo and NetServerEnum obtain a specified machine's supported service types.

A service type is represented as a set of bit flags; the SetServiceBits function sets or clears combinations of those bit flags.

BOOL SetServiceBits (

SERVICE_STATUS_HANDLE  hServiceStatus,	// service status handle
DWORD  dwServiceBits,	// service type bits to set or clear
BOOL  bSetBitsOn,	// flag to set or clear the service type bits
BOOL bUpdateImmediately	// flag to announce server type immediately
);
Parameters

hServiceStatus

A handle to the Service Control Manager's status information structure for a service. A service obtains a SERVICE_STATUS_HANDLE value by calling the RegisterServiceCtrlHandler function. It is the service's handle for making calls to the Service Control Manager.

dwServiceBits

A set of bit flags that specifies a service type.

Certain bit flags (0xC00F3F7B) are reserved for use by Microsoft. The SetServiceBits function fails with the error ERROR_INVALID_DATA if any of these bit flags are set in dwServiceBits. There are 18 of these bit flags:

Bit Flag Constant	Value
SV_TYPE_WORKSTATION	0x00000001
SV_TYPE_SERVER	0x00000002
SV_TYPE_DOMAIN_CTRL	0x00000008
SV_TYPE_DOMAIN_BAKCTRL	0x00000010
SV_TYPE_TIME_SOURCE	0x00000020
SV_TYPE_AFP	0x00000040
SV_TYPE_DOMAIN_MEMBER	0x00000100
SV_TYPE_PRINTQ_SERVER	0x00000200
SV_TYPE_DIALIN_SERVER	0x00000400
SV_TYPE_XENIX_SERVER	0x00000800
SV_TYPE_SERVER_UNIX	0x00000800
SV_TYPE_NT	0x00001000
SV_TYPE_WFW	0x00002000
SV_TYPE_POTENTIAL_BROWSER	0x00010000
SV_TYPE_BACKUP_BROWSER	0x00020000
SV_TYPE_MASTER_BROWSER	0x00040000
SV_TYPE_DOMAIN_MASTER	0x00080000
SV_TYPE_LOCAL_LIST_ONLY	0x40000000
SV_TYPE_DOMAIN_ENUM	0x80000000
Certain bit flags (0x00300084) are defined by Microsoft, but are not specifically reserved for systems software. There are four of these bit flags:

Bit Flag Constant	Value
SV_TYPE_SV_TYPE_SQLSERVER	0x00000004
SV_TYPE_NOVELL	0x00000080
SV_TYPE_DOMAIN_CTRL	0x00100000
SV_TYPE_DOMAIN_BAKCTRL	0x00200000
Certain bit flags (0x3FC0C000) are not defined by Microsoft, and their use is not coordinated by Microsoft. Developers of applications that use these bits should be aware that other applications may also use them, thus creating a conflict. There are 10 of these bit flags:

Value	Value
0x00004000	0x02000000
0x00008000	0x04000000
0x00400000	0x08000000
0x00800000	0x10000000
0x01000000	0x20000000
bSetBitsOn

A BOOLEAN that specifies whether the function is to set or clear the bit flags that are set in dwServiceBit. The value TRUE specifies that the bits are to be set; FALSE specifies clearing.

bUpdateImmediately

A BOOLEAN that specifies whether the Server service is to perform an immediate update, announcing the new service type. The value TRUE specifies an immediate update; FALSE specifies otherwise.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

NetServerGetInfo, NetServerEnum,RegisterServiceCtrlHandler, SetServiceStatus


SetServiceObjectSecurity
SetServiceObjectSecurity  QuickInfo  Overview  Group

The SetServiceObjectSecurity function sets the security descriptor of a service object.

BOOL SetServiceObjectSecurity(

SC_HANDLE  schService,	// handle of service
SECURITY_INFORMATION  fdwSecurityInfo,	// type of security information requested
PSECURITY_DESCRIPTOR  psdSecurityDesc	// address of security descriptor
);
Parameters

schService

Identifies the service. This handle is returned by the OpenService or CreateService function. The access required for this handle depends on the security information specified in the fdwSecurityInfo parameter.

fdwSecurityInfo

Specifies the security information to be set. Any or all of the following flags can be specified:

Value	Meaning
OWNER_SECURITY_INFORMATION	Sets the object's owner security identifier (SID). The schService handle must have WRITE_OWNER access, or the calling process must be the object's owner.
GROUP_SECURITY_INFORMATION	Sets the object's primary group SID. The schService handle must have WRITE_OWNER access, or the calling process must be the object's owner.
DACL_SECURITY_INFORMATION	Sets the object's discretionary access control list (ACL). The schService handle must have WRITE_DAC access, or the calling process must be the object's owner.
SACL_SECURITY_INFORMATION	Sets the object's system ACL. The calling process must have SeSecurityPrivilege privilege.
psdSecurityDesc

Points to a SECURITY_DESCRIPTOR structure containing the new security information.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Errors

The following error codes may be set by the service control manager. Other error codes may be set by the registry functions that are called by the service control manager.

Value	Meaning
ERROR_ACCESS_DENIED
	The specified handle was not opened with the required access, or the calling process is not the owner of the object.
ERROR_INVALID_HANDLE
	The specified handle is invalid.
ERROR_INVALID_PARAMETER
	The specified security information or security descriptor is invalid.
ERROR_SERVICE_MARKED_FOR_DELETE
	The specified service has been marked for deletion.
Remarks

The SetServiceObjectSecurity function sets the specified portions of the service object's security descriptor, based on the information specified in the psdSecurityDesc buffer. This function replaces any or all of the security information associated with the service object, according to the flags set in the fdwSecurityInfo parameter and subject to the calling process's access rights.

The initial security descriptor of a service object is created by the service control manager, based on the security descriptor of the process that called the CreateService function to create the service. The security descriptor can be changed by calling the SetServiceObjectSecurity function.

See Also

CreateService, OpenService, QueryServiceObjectSecurity, SECURITY_DESCRIPTOR


SetServiceStatus
SetServiceStatus  QuickInfo  Overview  Group

The SetServiceStatus function updates the service control manager's status information for the calling service.

BOOL SetServiceStatus(

SERVICE_STATUS_HANDLE  sshServiceStatus,	// service status handle
LPSERVICE_STATUS  lpssServiceStatus	// address of status structure
);
Parameters

sshServiceStatus

Specifies a handle to the service control manager's status information structure for the current service. This handle is returned by the RegisterServiceCtrlHandler function.

lpssServiceStatus

Points to the SERVICE_STATUS structure the contains the latest status information for the calling service.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Errors

The following error codes may be set by the service control manager. Other error codes may be set by the registry functions that are called by the service control manager.

Value	Meaning
ERROR_INVALID_HANDLE	The specified handle is invalid.
ERROR_INVALID_DATA	The specified service status structure is invalid.
Remarks

A Win32 service's ServiceMain function first calls the RegisterServiceCtrlHandler function to get the service's SERVICE_STATUS_HANDLE. Then it immediately calls the SetServiceStatus function to notify the service control manager of its SERVICE_START_PENDING status.

When a Win32 service receives a control request, the service's Handler function must call this function, even if the service's status did not change. A service can also use this function at any time and by any thread of the service to notify the service control manager of status changes. Examples of such unsolicited status updates include:

•	Checkpoint updates that occur when the service is in transition from one state to another (that is, SERVICE_START_PENDING).

•	An update made necessary by the expected occurrence of a fatal error that causes the service to stop.

A service can call this function only after it has called RegisterServiceCtrlHandler to get a service status handle.

See Also

Handler, RegisterServiceCtrlHandler, SERVICE_STATUS, ServiceMain, SetServiceBits


setsockopt
setsockopt  QuickInfo

The Windows Sockets setsockopt function sets a socket option.

int setsockopt (

SOCKET s,
int level,
int optname,
const char FAR * optval,
int optlen
);
Parameters

s

A descriptor identifying a socket.

level

The level at which the option is defined; the only supported levels are SOL_SOCKET and IPPROTO_TCP.

optname

The socket option for which the value is to be set.

optval

A pointer to the buffer in which the value for the requested option is supplied.

optlen

The size of the optval buffer.

Return Value

If the function succeeds, setsockopt returns zero.

If the function fails, a value of SOCKET_ERROR is returned. To get extended error information, call WSAGetLastError.

Error Codes

WSANOTINITIALISED	A successful WSAStartup must occur before using this function.
WSAENETDOWN	The Windows Sockets implementation has detected that the network subsystem has failed.
WSAEFAULT	The optval parameter is not in a valid part of the process address space.
WSAEINPROGRESS	A blocking Windows Sockets operation is in progress.
WSAEINVAL	The level parameter is not valid, or the information in optval is not valid.
WSAENETRESET	Connection has timed out when SO_KEEPALIVE is set.
WSAENOPROTOOPT	The option is unknown or unsupported. In particular, SO_BROADCAST is not supported on sockets of type SOCK_STREAM, while SO_DONTLINGER, SO_KEEPALIVE, SO_LINGER and SO_OOBINLINE are not supported on sockets of type SOCK_DGRAM.
WSAENOTCONN	Connection has been reset when SO_KEEPALIVE is set.
WSAENOTSOCK	The descriptor is not a socket.
Remarks

The setsockopt function sets the current value for a socket option associated with a socket of any type, in any state. Although options may exist at multiple protocol levels, this specification only defines options that exist at the uppermost "socket" level. Options affect socket operations, such as whether expedited data is received in the normal data stream, whether broadcast messages can be sent on the socket, and so on.

There are two types of socket options: Boolean options that enable or disable a feature or behavior, and options that require an integer value or structure. To enable a Boolean option, optval points to a nonzero integer. To disable the option, optval points to an integer equal to zero. The optlen parameter should be equal to sizeof(int) for Boolean options. For other options, optval points to the an integer or structure that contains the desired value for the option, and optlen is the length of the integer or structure.

The SO_LINGER option controls the action taken when unsent data is queued on a socket and a closesocket is performed. See closesocket for a description of the way the SO_LINGER settings affect the semantics of closesocket. The application sets the desired behavior by creating a linger structure (pointed to by the optval argument) with the following elements:

struct linger {

int    l_onoff;

int    l_linger;

}

To enable SO_LINGER, the application should set l_onoff to a nonzero value, set l_linger to zero or the desired timeout (in seconds), and call setsockopt. To enable SO_DONTLINGER (i.e. disable SO_LINGER) l_onoff should be set to zero and setsockopt should be called.

By default, a socket cannot be bound (see bind) to a local address that is already in use. On occasions, however, it may be desirable to "re-use" an address in this way. Since every connection is uniquely identified by the combination of local and remote addresses, there is no problem with having two sockets bound to the same local address as long as the remote addresses are different. To inform the Windows Sockets implementation that a bind on a socket should not be disallowed because the desired address is already in use by another socket, the application should set the SO_REUSEADDR socket option for the socket before issuing the bind. Note that the option is interpreted only at the time of the bind: it is therefore unnecessary (but harmless) to set the option on a socket that is not to be bound to an existing address, and setting or resetting the option after the bind has no effect on this or any other socket.

An application can request that the Windows Sockets implementation enable the use of "keep-alive" packets on TCP connections by turning on the SO_KEEPALIVE socket option. A Windows Sockets implementation need not support the use of keepalives: if it does, the precise semantics are implementation-specific but should conform to section 4.2.3.6 of RFC 1122: Requirements for Internet Hosts — Communication Layers. If a connection is dropped as the result of keepalives, the error code WSAENETRESET is returned to any calls in progress on the socket, and any subsequent calls will fail with WSAENOTCONN.

The TCP_NODELAY option disables the Nagle algorithm. The Nagle algorithm is used to reduce the number of small packets sent by a host by buffering unacknowledged send data until a full-size packet can be sent. However, for some applications this algorithm can impede performance, and TCP_NODELAY can be used to turn it off. You should not set TCP_NODELAY unless the impact of doing so is well understood and desired, since setting TCP_NODELAY can have a significant negative impact of network performance. TCP_NODELAY is the only supported socket option that uses level IPPROTO_TCP; all other options use level SOL_SOCKET.

Windows Sockets suppliers are encouraged (but not required) to supply output debug information if the SO_DEBUG option is set by an application. The mechanism for generating the debug information and the form it takes are beyond the scope of this documentation.

The following options are supported for setsockopt. The Type identifies the type of data addressed by optval.

Value	Type	Meaning
SO_BROADCAST	BOOL	Allow transmission of broadcast messages on the socket.
SO_DEBUG	BOOL	Record debugging information.
SO_DONTLINGER	BOOL	Don't block close waiting for unsent data to be sent. Setting this option is equivalent to setting SO_LINGER with l_onoff set to zero.
SO_DONTROUTE	BOOL	Don't route: send directly to interface.
SO_KEEPALIVE	BOOL	Send keepalive messages.
SO_LINGER	struct linger FAR *	Linger on close if unsent data is present.
SO_OOBINLINE	BOOL	Receive out-of-band data in the normal data stream.
SO_RCVBUF	int	Specify buffer size for receives.
SO_REUSEADDR	BOOL	Allow the socket to be bound to an address that is already in use. (See bind.)
SO_SNDBUF	int	Specify buffer size for sends.
TCP_NODELAY	BOOL	Disables the Nagle algorithm for send coalescing.
The following BSD options are not supported for setsockopt.

Value	Type	Meaning
SO_ACCEPTCONN	BOOL	Socket is listening
SO_ERROR	int	Get error status and clear
SO_RCVLOWAT	int	Receive low-water mark
SO_RCVTIMEO	int	Receive timeout
SO_SNDLOWAT	int	Send low-water mark
SO_SNDTIMEO	int	Send timeout
SO_TYPE	int	Type of the socket
IP_OPTIONS		Set options field in IP header.
See Also

bind, getsockopt, ioctlsocket, socket, WSAAsyncSelect, WSAStartup


SetSoundNoise

The SetSoundNoise function has been deleted.

See Also

Beep, MessageBeep


SetStdHandle
SetStdHandle  QuickInfo  Overview  Group

The SetStdHandle function is used to set the handle for the standard input, standard output, or standard error device. The specified handle can be used by subsequent calls to the GetStdHandle function to refer to the input, output, or error device.

BOOL SetStdHandle(

DWORD  IDStdHandle,	// input, output, or error device
HANDLE  hHandle	// handle to be a standard handle
);
Parameters

IDStdHandle

Specifies the handle to be set. This parameter can have one of the following values:

Value	Meaning
STD_INPUT_HANDLE	Standard input handle
STD_OUTPUT_HANDLE	Standard output handle
STD_ERROR_HANDLE	Standard error handle
hHandle

Supplies the handle to store as standard input, standard output, or standard error.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The standard handles of a process may have been redirected by a call to SetStdHandle, in which case GetStdHandle will return the redirected handle. If the standard handles have been redirected, you can specify the CONIN$ value in a call to the CreateFile function to get a handle of a console's input buffer. Similarly, you can specify the CONOUT$ value to get a handle of the console's active screen buffer.

See Also

CreateFile, GetStdHandle


SetStretchBltMode
SetStretchBltMode  QuickInfo  Overview  Group

The SetStretchBltMode function sets the bitmap stretching mode in the specified device context.

int SetStretchBltMode(

HDC  hdc,	// handle of device context
int  iStretchMode	// bitmap stretching mode
);
Parameters

hdc

Identifies the device context.

iStretchMode

Specifies the stretching mode. It can be one of the following values:

Value	Description
BLACKONWHITE	Performs a Boolean AND operation using the color values for the eliminated and existing pixels. If the bitmap is a monochrome bitmap, this mode preserves black pixels at the expense of white pixels.
COLORONCOLOR	Deletes the pixels. This mode deletes all eliminated lines of pixels without trying to preserve their information.
HALFTONE	Maps pixels from the source rectangle into blocks of pixels in the destination rectangle. The average color over the destination block of pixels approximates the color of the source pixels.
	After setting the HALFTONE stretching mode, an application must call the SetBrushOrgEx function to set the brush origin. If it fails to do so, brush misalignment occurs.
STRETCH_ANDSCANS	Windows 95: Same as BLACKONWHITE.
STRETCH_DELETESCANS	Windows 95: Same as COLORONCOLOR.
STRETCH_HALFTONE	Windows 95: Same as HALFTONE.
STRETCH_ORSCANS	Windows 95: Same as WHITEONBLACK.
WHITEONBLACK	Performs a Boolean OR operation using the color values for the eliminated and existing pixels. If the bitmap is a monochrome bitmap, this mode preserves white pixels at the expense of black pixels.
Return Value

If the function succeeds, the return value is the previous stretching mode.

If the function fails, the return value is zero.

Remarks

The stretching mode defines how Windows combines rows or columns of a bitmap with existing pixels on a display device when an application calls the StretchBlt function.

The BLACKONWHITE (STRETCH_ANDSCANS) and WHITEONBLACK (STRETCH_ORSCANS) modes are typically used to preserve foreground pixels in monochrome bitmaps. The COLORONCOLOR (STRETCH_DELETESCANS) mode is typically used to preserve color in color bitmaps.

The HALFTONE mode requires more processing of the source image than the other three modes; it is slower than the others but produces higher quality images. Also note that SetBrushOrgEx must be called after setting the HALFTONE mode to avoid brush misalignment.

Additional stretching modes might also be available depending on the capabilities of the device driver.

See Also

SetBrushOrgEx, StretchBlt


SetSwapAreaSize
SetSwapAreaSize  QuickInfo  Overview  Group

The SetSwapAreaSize function is obsolete. It has no meaning in the 32-bit environment.


SetSysColors
SetSysColors  QuickInfo  Overview  Group

The SetSysColors function sets the colors for one or more display elements. Display elements are the various parts of a window and the Windows display that appear on the system display screen.

BOOL WINAPI SetSysColors(

int  cDspElements,	// number of elements to change
CONST INT  *lpnDspElements,	// address of array of elements
CONST COLORREF  *lpdwRgbValues	// address of array of RGB values
);
Parameters

cDspElements

Specifies the number of display elements in the array pointed to by the lpnDspElements parameter.

lpnDspElements

Points to an array of integers that specify the display elements to be changed. For a list of display elements, see the GetSysColor function.

lpdwRgbValues

Points to an array of unsigned long integers that contains the new red, green, blue (RGB) color value for each display element in the array pointed to by the lpnDspElements parameter.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The SetSysColors function sends a WM_SYSCOLORCHANGE message to all windows to inform them of the change in color. It also directs Windows to repaint the affected portions of all currently visible windows.

The SetSysColors function changes the current Windows session only. The new colors are not saved when Windows terminates.

See Also

GetSysColor


SetSysModalWindow
SetSysModalWindow  QuickInfo  Overview  Group

The SetSysModalWindow function is not implemented in the Win32 API. The new input model does not allow for System Modal windows.


SetSystemCursor
SetSystemCursor  QuickInfo  Overview  Group

The SetSystemCursor function replaces the contents of the system cursor specified by dwCursorId with the contents of the cursor specified by hCursor, and then destroys hCursor. This function lets an application customize the system cursors.

BOOL SetSystemCursor (

HCURSOR  hCursor,	// set specified system cursor to this cursor's contents,  // then destroy this
DWORD  dwCursorID	// system cursor specified by its identifier
);
Parameters

hCursor

Handle to a cursor. The function replaces the contents of the system cursor specified by dwCursorID with the contents of the cursor handled by hCursor. Then the function destroys hCursor by calling DestroyCursor(hCursor).

dwCursorID

A system cursor identifier. The function replaces the contents of this system cursor with the contents of the cursor handled by hCursor.

Following is a list of system cursor identifiers:

Value	Description
OCR_NORMAL	normal arrow cursor
OCR_IBEAM	I-beam cursor
OCR_WAIT	larger hourglass cursor
OCR_CROSS	crosshair cursor
OCR_UP	up arrow cursor
OCR_SIZE	size cursor
OCR_ICON	icon cursor
OCR_SIZENWSE	NW to SE sizing cursor
OCR_SIZENESW	NE to SW sizing cursor
OCR_SIZEWE	horizontal sizing cursor
OCR_SIZENS	vertical sizing cursor
OCR_SIZEALL	horizontal and vertical sizing cursor
OCR_SIZENO	international no symbol cursor
OCR_APPSTARTING	smaller hourglass with arrow cursor
Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

DestroyCursor, LoadCursor, LoadCursorFromFile, SetCursor


SetSystemPaletteUse
SetSystemPaletteUse  QuickInfo  Overview  Group

The SetSystemPaletteUse function allows an application to specify whether the system palette contains 2 or 20 static colors. The default system palette contains 20 static colors. (Static colors cannot be changed when an application realizes a logical palette.)

UINT SetSystemPaletteUse(

HDC  hdc,	// handle of device context
UINT  uUsage	// palette-usage flag
);
Parameters

hdc

Identifies the device context. This device context must refer to a device that supports color palettes.

uUsage

Specifies the new use of the system palette. This parameter can be one of the following values:

Value	Meaning
SYSPAL_NOSTATIC	The system palette contains two static colors (black and white).
SYSPAL_STATIC	The system palette contains static colors that will not change when an application realizes its logical palette.
Return Value

If the function succeeds, the return value is the previous usage of the system palette (it can be either SYSPAL_NOSTATIC or SYSPAL_STATIC).

If the function fails, the return value is SYSPAL_ERROR. To get extended error information, call GetLastError.

Remarks

An application can determine whether a device supports palette operations by calling the GetDeviceCaps function and specifying the RASTERCAPS constant.

When an application window moves to the foreground and the SYSPAL_NOSTATIC value is set, the application must call the GetSysColor function to save the current system colors setting. It must also call SetSysColors to set reasonable values using only black and white. When the application returns to the background or terminates, the previous system colors must be restored.

If the function returns SYSPAL_ERROR, the specified device context is invalid or does not support color palettes.

An application must call this function only when its window is maximized and has the input focus.

If an application calls SetSystemPaletteUse with uUsage set to SYSPAL_NOSTATIC, Windows continues to set aside two entries in the system palette for pure white and pure black, respectively.

After calling this function with uUsage set to SYSPAL_NOSTATIC, an application must take the following steps:

1.	Realize the logical palette.

2.	Call the GetSysColor function to save the current system-color settings.

3.	Call the SetSysColors function to set the system colors to reasonable values using black and white. For example, adjacent or overlapping items (such as window frames and borders) should be set to black and white, respectively.

4.	Send the WM_SYSCOLORCHANGE message to other top-level windows to allow them to be redrawn with the new system colors.

When the application's window loses focus or closes, the application must perform the following steps:

1.	Call SetSystemPaletteUse with the uUsage parameter set to SYSPAL_STATIC.

2.	Realize the logical palette.

3.	Restore the system colors to their previous values.

4.	Send the WM_SYSCOLORCHANGE message.

See Also

GetDeviceCaps, GetSysColor, SetSysColors


SetSystemPowerState [New - Windows 95]
SetSystemPowerState  QuickInfo  Overview  Group

[New - Windows 95]

The SetSystemPowerState function suspends the system by shutting power down. Depending on the ForceFlag parameter, the function either suspends operation immediately or requests permission from all applications and device drivers before doing so.

BOOL SetSystemPowerState(

BOOL  fSuspend,
BOOL  fForce
);
Parameters

fSuspend

Suspension technique. If TRUE, the system suspends using RAM-alive technique. Otherwise, suspends using hibernate technique.

fForce

Forced suspension. If TRUE, the function sends a PBT_APMSUSPEND message to each application and driver, then immediately suspends operation. If FALSE, the function sends a PBT_APMQUERYSUSPEND message to each application to request permission to suspend operation.

Return Value

If power has been suspended and subsequently restored, the return value is TRUE.

If the system did not suspend, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

If any application or driver denies permission to suspend operation, the function sends a PBT_APMQUERYSUSPENDFAILED message to each application and driver. If power is suspended, this function returns only after system operation is resumed and related WM_POWERBROADCAST messages have been sent to all applications and drivers.

See Also

PBT_APMQUERYSUSPEND, PBT_APMQUERYSUSPENDFAILED, PBT_APMSUSPEND, WM_POWERBROADCAST


SetSystemTime
SetSystemTime  QuickInfo  Overview  Group

The SetSystemTime function sets the current system time and date. The system time is expressed in Coordinated Universal Time (UTC).

BOOL SetSystemTime(

CONST SYSTEMTIME *  lpst	// address of system time to set
);
Parameters

lpst

Points to a SYSTEMTIME structure that contains the current system date and time.

The wDayOfWeek member of the SYSTEMTIME structure is ignored.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The application must have system-time privilege (the SE_SYSTEMTIME_NAME privilege) for this function to succeed. This privilege is disabled by default. Use the AdjustTokenPrivileges function to enable the privilege and again to disable it after the time has been set.

For more information about security privileges, see Security.

See Also

AdjustTokenPrivileges, GetSystemTime, SetSystemTimeAdjustment, SYSTEMTIME, SystemTimeToTzSpecificLocalTime


SetSystemTimeAdjustment
SetSystemTimeAdjustment  QuickInfo  Overview  Group

The SetSystemTimeAdjustment function tells the system to enable or disable periodic time adjustments to its time of day clock. Such time adjustments are used to synchronize the time of day with some other source of time information. When periodic time adjustments are enabled, they are applied at each clock interrupt.

BOOL SetSystemTimeAdjustment(

DWORD  dwTimeAdjustment,	// size, in 100-nanosecond units, of a periodic time adjustment
PBOOL  bTimeAdjustmentDisabled	// whether periodic time adjustment is to be disabled or enabled
);
Parameters

dwTimeAdjustment

Specifies the number of 100-nanosecond units added to the time-of-day clock at each clock interrupt if periodic time adjustment is enabled.

bTimeAdjustmentDisabled

Specifies the time adjustment mode that the system is to use. Periodic system time adjustments can be disabled or enabled.

A value of TRUE specifies that periodic time adjustment is to be disabled. The system is free to adjust time of day using its own internal mechanisms. The value of dwTimeAdjustment is ignored. The system's internal adjustment mechanisms may cause the time-of-day clock to jump noticeably when adjustments are made.

A value of FALSE specifies that periodic time adjustment is to be enabled, and will be used to adjust the time-of-day clock. The system will not interfere with the time adjustment scheme, and will not attempt to synchronize time of day on its own. The system will add the value of dwTimeAdjustment to the time of day at each clock interrupt.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError. One way the function can fail is if the caller does not possess the SE_SYSTEMTIME_NAME privilege.

Remarks

The GetSystemTimeAdjustment and SetSystemTimeAdjustment functions support algorithms that synchronize the time-of-day clock, reported via GetSystemTime and GetLocalTime, with another time source using a periodic time adjustment.

The SetSystemTimeAdjustment function supports two modes of time synchronization: time-adjustment − disabled and time-adjustment − enabled.

In the first mode, bTimeAdjustmentDisabled is set to FALSE.  At each clock interrupt, the system adds the value of dwTimeAdjustment to the time of day. The clock interrupt rate may be determined by calling GetSystemTimeAdjustment, and looking at the returned value of the DWORD value pointed to by lpTimeIncrement.

In the second mode, bTimeAdjustmentDisabled is set to TRUE.  At each clock interrupt, the system adds the interval between clock interrupts to the time of day. No adjustment to that interval is made. The system is free to periodically refresh the time-of-day clock using other techniques. Such other techniques may cause the time-of-day clock to jump noticeably when adjustments are made.

An application must have system-time privilege (the SE_SYSTEMTIME_NAME privilege) for this function to succeed. The SE_SYSTEMTIME_NAME privilege is disabled by default. Use the AdjustTokenPrivileges function to enable the privilege before calling SetSystemTimeAdjustment, and then to disable the privilege after the SetSystemTimeAdjustment call.

See Also

AdjustTokenPrivileges, GetSystemTimeAdjustment, SetLocalTime, SetSystemTime, SystemTimeToTzSpecificLocalTime


SetTapeParameters
SetTapeParameters  QuickInfo  Overview  Group

The SetTapeParameters function either specifies the block size of a tape or configures the tape device.

DWORD SetTapeParameters(

HANDLE  hDevice,	// handle of open device
DWORD  dwOperation,	// type of information to set
LPVOID  lpTapeInformation	// address of buffer with information to set
);
Parameters

hDevice

Identifies the device for which to set configuration information. This handle is created by using the CreateFile function.

dwOperation

Specifies the type of information to set. This parameter must be one of the following values:

Value	Description
SET_TAPE_MEDIA_INFORMATION	Sets the tape-specific information specified by the lpTapeInformation parameter.
GET_TAPE_DRIVE_INFORMATION	Sets the device-specific information specified by lpTapeInformation.
lpTapeInformation

Points to a structure that contains the information to set. If the dwOperation parameter is SET_TAPE_MEDIA_INFORMATION, lpTapeInformation points to a TAPE_SET_MEDIA_PARAMETERS structure.

If dwOperation is SET_TAPE_DRIVE_INFORMATION, lpTapeInformation points to a TAPE_SET_DRIVE_PARAMETERS structure.

Return Value

If the function succeeds, the return value is NO_ERROR.

If the function fails, the return value is one of the following error codes:

Error	Description
ERROR_BEGINNING_OF_MEDIA	An attempt to access data before the beginning-of-medium marker failed.
ERROR_BUS_RESET	A reset condition was detected on the bus.
ERROR_END_OF_MEDIA	The end-of-tape marker was reached during an operation.
ERROR_FILEMARK_DETECTED	A filemark was reached during an operation.
ERROR_SETMARK_DETECTED	A setmark was reached during an operation.
ERROR_NO_DATA_DETECTED	The end-of-data marker was reached during an operation.
ERROR_PARTITION_FAILURE	The tape could not be partitioned.
ERROR_INVALID_BLOCK_LENGTH	The block size is incorrect on a new tape in a multivolume partition.
ERROR_DEVICE_NOT_PARTITIONED	The partition information could not be found when a tape was being loaded.
ERROR_MEDIA_CHANGED	The tape that was in the drive has been replaced or removed.
ERROR_NO_MEDIA_IN_DRIVE	There is no media in the drive.
ERROR_NOT_SUPPORTED	The tape driver does not support a requested function.
ERROR_UNABLE_TO_LOCK_MEDIA	An attempt to lock the ejection mechanism failed.
ERROR_UNABLE_TO_UNLOAD_MEDIA	An attempt to unload the tape failed.
ERROR_WRITE_PROTECT	The media is write protected.
See Also

GetTapeParameters, TAPE_SET_DRIVE_PARAMETERS, TAPE_SET_MEDIA_PARAMETERS


SetTapePosition
SetTapePosition  QuickInfo  Overview  Group

The SetTapePosition sets the tape position on the specified device.

DWORD SetTapePosition(

HANDLE  hDevice,	// handle of open device
DWORD  dwPositionMethod,	// type of positioning to perform
DWORD  dwPartition,	// new tape partition
DWORD  dwOffsetLow,	// low-order 32 bits of tape position
DWORD  dwOffsetHigh,	// high-order 32 bits of tape position
BOOL  bImmediate	// return after operation begins
);
Parameters

hDevice

Identifies the device on which to set the tape position. This handle is created by using the CreateFile function.

dwPositionMethod

Specifies the type of positioning to perform. This parameter must be one of the following values:

Value	Meaning
TAPE_ABSOLUTE_BLOCK	Moves the tape to the device-specific block address specified by the dwOffsetLow and dwOffsetHigh parameters. The dwPartition parameter is ignored.
TAPE_LOGICAL_BLOCK	Moves the tape to the block address specified by dwOffsetLow and dwOffsetHigh in the partition specified by dwPartition.
TAPE_REWIND	Moves the tape to the beginning of the current partition. The dwPartition, dwOffsetLow, and dwOffsetHigh parameters are ignored.
TAPE_SPACE_END_OF_DATA	Moves the tape to the end of the data on the partition specified by dwPartition.
TAPE_SPACE_FILEMARKS	Moves the tape forward (or backward) the number of filemarks specified by dwOffsetLow and dwOffsetHigh in the current partition. The dwPartition parameter is ignored.
TAPE_SPACE_RELATIVE_BLOCKS	Moves the tape forward (or backward) the number of blocks specified by dwOffsetLow and dwOffsetHigh in the current partition. The dwPartition parameter is ignored.
TAPE_SPACE_SEQUENTIAL_FMKS	Moves the tape forward (or backward) to the first occurrence of n filemarks in the current partition, where n is the number specified by dwOffsetLow and dwOffsetHigh. The dwPartition parameter is ignored.
TAPE_SPACE_SEQUENTIAL_SMKS	Moves the tape forward (or backward) to the first occurrence of n setmarks in the current partition, where n is the number specified by dwOffsetLow and dwOffsetHigh. The dwPartition parameter is ignored.
TAPE_SPACE_SETMARKS	Moves the tape forward (or backward) the number of setmarks specified by dwOffsetLow and dwOffsetHigh in the current partition. The dwPartition parameter is ignored.
dwPartition

Specifies the partition to position within. If dwPartition is zero, the current partition is used. Partitions are numbered logically from 1 through n, where 1 is the first partition on the tape and n is the last.

dwOffsetLow

Specifies the low-order 32 bits of the block address or count for the position operation specified by the dwPositionMethod parameter.

dwOffsetHigh

Specifies the high-order 32 bits of the block address or count for the position operation specified by the dwPositionMethod parameter. If the high-order 32 bits are not required, this parameter should be zero.

bImmediate

Indicates whether to return as soon as the move operation begins. If this parameter is TRUE, the function returns immediately; if FALSE, the function does not return until the move operation has been completed.

Return Value

If the function succeeds, the return value is NO_ERROR.

If the function fails, the return value is one of the following error codes:

Error	Description
ERROR_BEGINNING_OF_MEDIA	An attempt to access data before the beginning-of-medium marker failed.
ERROR_BUS_RESET	A reset condition was detected on the bus.
ERROR_END_OF_MEDIA	The end-of-tape marker was reached during an operation.
ERROR_FILEMARK_DETECTED	A filemark was reached during an operation.
ERROR_SETMARK_DETECTED	A setmark was reached during an operation.
ERROR_NO_DATA_DETECTED	The end-of-data marker was reached during an operation.
ERROR_PARTITION_FAILURE	The tape could not be partitioned.
ERROR_INVALID_BLOCK_LENGTH	The block size is incorrect on a new tape in a multivolume partition.
ERROR_DEVICE_NOT_PARTITIONED	The partition information could not be found when a tape was being loaded.
ERROR_MEDIA_CHANGED	The tape that was in the drive has been replaced or removed.
ERROR_NO_MEDIA_IN_DRIVE	There is no media in the drive.
ERROR_NOT_SUPPORTED	The tape driver does not support a requested function.
ERROR_UNABLE_TO_LOCK_MEDIA	An attempt to lock the ejection mechanism failed.
ERROR_UNABLE_TO_UNLOAD_MEDIA	An attempt to unload the tape failed.
ERROR_WRITE_PROTECT	The media is write protected.
Remarks

If the offset specified by dwOffsetLow and dwOffsetHigh specifies the number of blocks, filemarks, or setmarks to move, a positive offset moves the tape forward to the end of the last block, filemark, or setmark. A negative offset moves the tape backward to the beginning of the last block, filemark, or setmark. If the offset is zero, the tape does not move.

To obtain information about the status, capabilities, and capacities of tape drives and media, call the GetTapeParameters function.

See Also

CreateFile, GetTapeParameters, GetTapePosition


SetTextAlign
SetTextAlign  QuickInfo  Overview  Group

The SetTextAlign function sets the text-alignment flags for the specified device context.

UINT SetTextAlign(

HDC  hdc,	// handle of device context
UINT  fMode	// text-alignment flag
);
Parameters

hdc

Identifies the device context.

fMode

Specifies the text alignment by using a mask of the values in the following list. Only one flag can be chosen from those that affect horizontal and vertical alignment. In addition, only one of the two flags that alter the current position can be chosen.

Value	Meaning
TA_BASELINE	The reference point will be on the base line of the text.
TA_BOTTOM	The reference point will be on the bottom edge of the bounding rectangle.
TA_TOP	The reference point will be on the top edge of the bounding rectangle.
TA_CENTER	The reference point will be aligned horizontally with the center of the bounding rectangle.
TA_LEFT	The reference point will be on the left edge of the bounding rectangle.
TA_RIGHT	The reference point will be on the right edge of the bounding rectangle.
TA_NOUPDATECP	The current position is not updated after each text output call. The reference point is passed to the text output function.
TA_RTLREADING	Windows 95 only: The text is laid out in right to left reading order, as opposed to the default left to right order. This applies only when the font selected into the device context is either Hebrew or Arabic.
TA_UPDATECP	The current position is updated after each text output call. The current position is used as the reference point.
When the current font has a vertical default base line, as with Kanji, the following values must be used instead of TA_BASELINE and TA_CENTER:

Value	Meaning
VTA_BASELINE	The reference point will be on the base line of the text.
VTA_CENTER	The reference point will be aligned vertically with the center of the bounding rectangle.
The default values are TA_LEFT, TA_TOP, and TA_NOUPDATECP.

Return Value

If the function succeeds, the return value is the previous text-alignment setting.

If the function fails, the return value is GDI_ERROR. To get extended error information, call GetLastError.

Remarks

The TextOut and ExtTextOut functions use the text-alignment flags to position a string of text on a display or other device. The flags specify the relationship between a reference point and a rectangle that bounds the text. The reference point is either the current position or a point passed to a text output function.

The rectangle that bounds the text is formed by the character cells in the text string.

See Also

ExtTextOut, TextOut


SetTextCharacterExtra
SetTextCharacterExtra  QuickInfo  Overview  Group

The SetTextCharacterExtra function sets the intercharacter spacing. Intercharacter spacing is added to each character, including break characters, when Windows writes a line of text.

int SetTextCharacterExtra(

HDC  hdc,	// handle of device context
int  nCharExtra	// extra-space value
);
Parameters

hdc

Identifies the device context.

nCharExtra

Specifies the amount of extra space, in logical units, to be added to each character. If the current mapping mode is not MM_TEXT, the nCharExtra parameter is transformed and rounded to the nearest pixel.

Return Value

If the function succeeds, the return value is the previous intercharacter spacing.

If the function fails, the return value is 0x80000000.

See Also

DrawText, GetTextCharacterExtra, TextOut


SetTextColor
SetTextColor  QuickInfo  Overview  Group

The SetTextColor function sets the text color for the specified device context to the specified color.

COLORREF SetTextColor(

HDC  hdc,	// handle of device context
COLORREF  crColor	// text color
);
Parameters

hdc

Identifies the device context.

crColor

Specifies the color of the text.

Return Value

If the function succeeds, the return value is a color reference for the previous text color.

If the function fails, the return value is CLR_INVALID. To get extended error information, call GetLastError.

Remarks

The text color is used to draw the face of each character written by the TextOut and ExtTextOut functions. The text color is also used in converting bitmaps from color to monochrome and vice versa.

See Also

BitBlt, ExtTextOut, RGB, SetBkColor, StretchBlt, TextOut


SetTextJustification
SetTextJustification  QuickInfo  Overview  Group

The SetTextJustification function specifies the amount of space Windows should add to the break characters in a string of text. The space is added when an application calls the TextOut or ExtTextOut functions.

BOOL SetTextJustification(

HDC  hdc,	// handle of device context
int  nBreakExtra,	// length of extra space, in logical units
int  nBreakCount	// count of space characters in line of text
);
Parameters

hdc

Identifies the device context.

nBreakExtra

Specifies the total extra space, in logical units, to be added to the line of text. If the current mapping mode is not MM_TEXT, the value identified by the nBreakExtra parameter is transformed and rounded to the nearest pixel.

nBreakCount

Specifies the number of break characters in the line.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The break character is usually the space character (ASCII 32), but it may be defined by a font as some other character. The GetTextMetrics function can be used to retrieve a font's break character.

The TextOut function distributes the specified extra space evenly among the break characters in the line.

The GetTextExtentPoint32 function is always used with the SetTextJustification function. The GetTextExtentPoint32 function computes the width of a given line before justification. This width must be known before an appropriate nBreakExtra value can be computed.

SetTextJustification can be used to justify a line that contains multiple strings in different fonts. In this case, each string must be justified separately.

Because rounding errors can occur during justification, Windows keeps a running error term that defines the current error value. When justifying a line that contains multiple runs, GetTextExtentPoint automatically uses this error term when it computes the extent of the next run, allowing TextOut to blend the error into the new run. After each line has been justified, this error term must be cleared to prevent it from being incorporated into the next line. The term can be cleared by calling SetTextJustification with nBreakExtra set to zero.

See Also

ExtTextOut, GetTextExtentPoint32, GetTextMetrics, TextOut


SetThreadAffinityMask
SetThreadAffinityMask  QuickInfo  Overview  Group

The SetThreadAffinityMask function sets a processor affinity mask for a specified thread.

A thread affinity mask is a bit vector in which each bit represents the processors that a thread is allowed to run on.

A thread affinity mask must be a proper subset of the process affinity mask for the containing process of a thread. A thread is only allowed to run on the processors its process is allowed to run on.

DWORD SetThreadAffinityMask (

HANDLE  hThread,	// handle to the thread of interest
DWORD  dwThreadAffinityMask	// a thread affinity mask
);
Parameters

hThread

A handle to the thread whose affinity mask the function sets. This handle must have THREAD_SET_INFORMATION access.

dwThreadAffinityMask

Windows 95: This value must be 1.

Windows NT: Specifies an affinity mask for the thread.

Return Value

If the function succeeds, the return value is nonzero.

Windows 95: The return value is 1. To succeed, hThread must be valid and dwThreadAffinityMask must be 1.

Windows NT: The return value is the thread's previous affinity mask.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

See Also

GetProcessAffinityMask


SetThreadContext
SetThreadContext  QuickInfo  Overview  Group

The SetThreadContext function sets the context in the specified thread.

BOOL SetThreadContext(

HANDLE  hThread,	// handle of thread with context
CONST CONTEXT *  lpContext	// address of context structure
);
Parameters

hThread

Identifies an open handle of a thread whose context is to be written to. The handle must have THREAD_SET_CONTEXT access to the thread.

lpContext

Points to the address of a CONTEXT structure that contains the context to be set in the specified thread. The value of the ContextFlags member of this structure specifies which portions of a thread's context to set. Some values in the CONTEXT structure that cannot be specified are silently set to the correct value. This includes bits in the CPU status register that specify the privileged processor mode, global enabling bits in the debugging register, and other states that must be controlled by the operating system.

Return Value

If the context was set, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The function allows the selective context to be set based on the value of the ContextFlags member of the context structure. The thread handle identified by the hThread parameter is typically being debugged, but the function can also operate even when it is not being debugged.

See Also

CONTEXT, GetThreadContext


SetThreadDesktop [New - Windows NT]
SetThreadDesktop  QuickInfo  Overview  Group

[New - Windows NT]

The SetThreadDesktop function assigns a desktop to the calling thread. All subsequent operations on the desktop use the access rights granted to hDesk.

BOOL SetThreadDesktop(

HDESK hDesk	// handle of the desktop to assign to this thread
);
Parameters

hDesk

Identifies the desktop to be assigned to the calling thread. This handle is returned by the CreateDesktop, GetThreadDesktop, and OpenDesktop functions.

This function will fail if the calling thread has any windows or hooks on its current desktop (unless hDesk is a handle to the current desktop).

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

CreateDesktop, GetThreadDesktop, OpenDesktop, SetProcessWindowStation


SetThreadLocale
SetThreadLocale  QuickInfo  Overview  Group

The SetThreadLocale function sets the calling thread's current locale.

BOOL SetThreadLocale (

LCID  Locale	// locale identifier
);
Parameters

Locale

Specifies the new locale for the calling thread. This parameter can be a locale identifier created by the MAKELCID macro, or one of the following predefined values:

LOCALE_SYSTEM_DEFAULT	Default system locale.
LOCALE_USER_DEFAULT	Default user locale.
 For more information, see Locale Identifiers..

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

When a thread is created, it is given the system default thread locale. The system reads the system default thread locale from the registry when the system boots. This system default can be modified for future process and thread creation using Control Panel's International application.

See Also

GetThreadLocale, GetSystemDefaultLCID, GetUserDefaultLCID


SetThreadPriority
SetThreadPriority  QuickInfo  Overview  Group

The SetThreadPriority function sets the priority value for the specified thread. This value, together with the priority class of the thread's process, determines the thread's base priority level.

BOOL SetThreadPriority(

HANDLE  hThread,	// handle to the thread
int  nPriority	// thread priority level
);
Parameters

hThread

Identifies the thread. The handle must have THREAD_SET_INFORMATION access.

nPriority

Specifies the priority value for the thread. This parameter can be one of the following values:

Priority	Meaning
THREAD_PRIORITY_ABOVE_NORMAL	Indicates 1 point above normal priority for the priority class.
THREAD_PRIORITY_BELOW_NORMAL	Indicates 1 point below normal priority for the priority class.
THREAD_PRIORITY_HIGHEST	Indicates 2 points above normal priority for the priority class.
THREAD_PRIORITY_IDLE	Indicates a base priority level of 1 for IDLE_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS, or HIGH_PRIORITY_CLASS processes, and a base priority level of 16 for REALTIME_PRIORITY_CLASS processes.
THREAD_PRIORITY_LOWEST	Indicates 2 points below normal priority for the priority class.
THREAD_PRIORITY_NORMAL	Indicates normal priority for the priority class.
THREAD_PRIORITY_TIME_CRITICAL	Indicates a base priority level of 15 for IDLE_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS, or HIGH_PRIORITY_CLASS processes, and a base priority level of 31 for REALTIME_PRIORITY_CLASS processes.
Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Every thread has a base priority level determined by the thread's priority value and the priority class of its process. The system uses the base priority level of all executable threads to determine which thread gets the next slice of CPU time. Threads are scheduled in a round-robin fashion at each priority level, and only when there are no executable threads at a higher level does scheduling of threads at a lower level take place.

The SetThreadPriority function enables setting the base priority level of a thread relative to the priority class of its process. For example, specifying THREAD_PRIORITY_HIGHEST in a call to SetThreadPriority for a thread of an IDLE_PRIORITY_CLASS process sets the thread's base priority level to 6. For a table that shows the base priority levels for each combination of priority class and thread priority value, see the SetPriorityClass function.

For IDLE_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS, and HIGH_PRIORITY_CLASS processes, the system dynamically boosts a thread's base priority level when events occur that are important to the thread. REALTIME_PRIORITY_CLASS processes do not receive dynamic boosts.

All threads initially start at THREAD_PRIORITY_NORMAL. Use the GetPriorityClass and SetPriorityClass functions to get and set the priority class of a process. Use the GetThreadPriority function to get the priority value of a thread.

Use the priority class of a process to differentiate between applications that are time critical and those that have normal or below normal scheduling requirements. Use thread priority values to differentiate the relative priorities of the tasks of a process. For example, a thread that handles input for a window could have a higher priority level than a thread that performs intensive calculations for the CPU.

When manipulating priorities, be very careful  to ensure that a high-priority thread does not consume all of the available CPU time. A thread with a base priority level above 11 interferes with the normal operation of the operating system. Using REALTIME_PRIORITY_CLASS may cause disk caches to not flush, hang the mouse, and so on.

See Also

GetPriorityClass, GetThreadPriority, SetPriorityClass


SetThreadToken [New - Windows NT]
SetThreadToken  QuickInfo  Overview  Group

[New - Windows NT]

The SetThreadToken function assigns an impersonation token to a thread. The function can also cause a thread to stop using an impersonation token.

BOOL SetThreadToken(

PHANDLE  Thread,	// points to a handle to the thread
HANDLE  Token	// handle to the impersonation token
);
Parameters

Thread

Points to a handle to the thread to which the function assigns the impersonation token.

If Thread is NULL, the function assigns the impersonation token to the calling thread.

Token

An open handle to the impersonation token to assign to the thread.

This handle must have been opened with TOKEN_IMPERSONATE access rights.

If Token is NULL, the function causes the thread to stop using an impersonation token.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

OpenThreadToken


SetTimer
SetTimer  QuickInfo  Overview  Group

The SetTimer function creates a timer with the specified time-out value.

UINT SetTimer(

HWND  hwnd,	// handle of window for timer messages
UINT  idTimer,	// timer identifier
UINT  uTimeout,	// time-out value
TIMERPROC  tmprc	// address of timer procedure
);
Parameters

hwnd

Identifies the window to be associated with the timer. If this parameter is NULL, no window is associated with the timer and the idTimer parameter is ignored.

idTimer

Specifies a nonzero timer identifier. If the hwnd parameter is NULL, this parameter is ignored.

uTimeout

Specifies the time-out value, in milliseconds.

tmprc

Points to the function to be notified when the time-out value elapses. For more information about the function, see the TimerProc callback function.

If tmprc is NULL, the system posts a WM_TIMER message to the application queue. The hwnd member of the message's MSG structure contains the value of the hwnd parameter.

Return Value

If the function succeeds, the return value is an integer identifying the new timer. An application can pass this value, or the string identifier, if it exists, to the KillTimer function to destroy the timer. If the function fails to create a timer, the return value is zero.

Remarks

An application can process WM_TIMER messages by including a WM_TIMER case statement in the window procedure or by specifying a TimerProc callback function when creating the timer.

The wParam parameter of the WM_TIMER message contains the value of the idTimer parameter.

See Also

KillTimer, MSG, TimerProc, WM_TIMER


SetTimeZoneInformation
SetTimeZoneInformation  QuickInfo  Overview  Group

The SetTimeZoneInformation function sets the current time-zone parameters. These parameters control translations from Coordinated Universal Time (UTC) to local time.

BOOL SetTimeZoneInformation(

CONST TIME_ZONE_INFORMATION *  lptzi	// address of time-zone settings
);
Parameters

lptzi

Points to a TIME_ZONE_INFORMATION structure that contains the time-zone parameters to set.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

All translations between UTC and local time are based on the following formula:

UTC = local time + bias

The bias is the difference, in minutes, between UTC and local time.

See Also

GetTimeZoneInformation, TIME_ZONE_INFORMATION


SetTokenInformation
SetTokenInformation  QuickInfo  Overview  Group

The SetTokenInformation function sets various types of information for a specified access token. The information it sets replaces existing information. The calling process must have appropriate access rights to set the information.

BOOL SetTokenInformation(

HANDLE  hToken,	// handle of access token
TOKEN_INFORMATION_CLASS  tic,	// type of information to set
LPVOID  lpvInformation,	// address of information to set
DWORD  cbInformation	// size of information buffer
);
Parameters

hToken

Identifies the access token for which information is to be set.

tic

Specifies a variable of the TOKEN_INFORMATION_CLASS enumerated type identifying the type of information the function sets. The valid values from TOKEN_INFORMATION_CLASS are TokenOwner, TokenPrimaryGroup, and TokenDefaultDacl. For more information about these values, see the description of the lpvInformation parameter, following.

lpvInformation

Points to a buffer containing the information set in the access token. The structure of this buffer depends on the type of information specified by the tic parameter. The following three values are valid in calls to this function:

Token Information Class	Structure Provided
TokenOwner	TOKEN_OWNER structure. TOKEN_ADJUST_DEFAULT access is needed to set owner information. A valid owner value is a user or group identifier with an attribute allowing assignment as the owner of objects.
TokenPrimaryGroup	TOKEN_PRIMARY_GROUP structure. TOKEN_ADJUST_DEFAULT access is needed to set primary group information.
TokenDefaultDacl	TOKEN_DEFAULT_DACL structure. TOKEN_ADJUST_DEFAULT access is needed to set information in the default discretionary access-control list (ACL). The ACL structure provided as a new default discretionary ACL is not validated for correctness or consistency. If the lpvInformation parameter is NULL, the current default discretionary ACL is removed and no replacement is established.
The formats for the structures this function can set are listed in the following Remarks section.

cbInformation

Specifies the length, in bytes, of the buffer pointed to by lpvInformation.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

To set privilege information, an application can call the AdjustTokenPrivileges function. To set a token's groups, an application can call the AdjustTokenGroups function.

Token-type information can be set only when an access token is created.

See Also

AdjustTokenGroups, AdjustTokenPrivileges, GetTokenInformation, OpenProcessToken, OpenThreadToken, TOKEN_DEFAULT_DACL, TOKEN_INFORMATION_CLASS, TOKEN_OWNER, TOKEN_PRIMARY_GROUP


SetUnhandledExceptionFilter
SetUnhandledExceptionFilter  QuickInfo  Overview  Group

The SetUnhandledExceptionFilter function lets an application supersede the top-level exception handler that Win32 places at the top of each thread and process.

After calling this function, if an exception occurs in a process that is not being debugged, and the exception makes it to the Win32 unhandled exception filter, that filter will call the exception filter function specified by the lpTopLevelExceptionFilter parameter.

LPTOP_LEVEL_EXCEPTION_FILTER SetUnhandledExceptionFilter(

LPTOP_LEVEL_EXCEPTION_FILTER  lpTopLevelExceptionFilter	// exception filter function
);
Parameters

lpTopLevelExceptionFilter

Supplies the address of a top-level exception filter function that will be called whenever the UnhandledExceptionFilter function gets control, and the process is not being debugged. A value of NULL for this parameter specifies default handling within UnhandledExceptionFilter.

The filter function has syntax congruent to that of UnhandledExceptionFilter: It takes a single parameter of type LPEXCEPTION_POINTERS, and returns a value of type LONG. The filter function should return one of the following values:

Value	Meaning
EXCEPTION_EXECUTE_HANDLER	Return from UnhandledExceptionFilter and execute the associated exception handler. This usually results in process termination.
EXCEPTION_CONTINUE_EXECUTION	Return from UnhandledExceptionFilter and continue execution from the point of the exception. Note that the filter function is free to modify the continuation state by modifying the exception information supplied through its LPEXCEPTION_POINTERS parameter.
EXCEPTION_CONTINUE_SEARCH	Proceed with normal execution of UnhandledExceptionFilter . That means obeying the SetErrorMod flags, or invoking the Application Error pop-up message box.
Return Value

The SetUnhandledExceptionFilter function returns the address of the previous exception filter established with the function. A NULL return value means that there is no current top-level exception handler.

Remarks

Issuing SetUnhandledExceptionFilter replaces the existing top-level exception filter for all existing and all future threads in the calling process.

The exception handler specified by lpTopLevelExceptionFilter is executed in the context of the thread that caused the fault. This can affect the exception handler's ability to recover from certain exceptions, such as an invalid stack.

See Also

UnhandledExceptionFilter


SetupComm
SetupComm  QuickInfo  Overview  Group

The SetupComm function initializes the communications parameters for a specified communications device.

BOOL SetupComm(

HANDLE  hCommDev,	// handle of communications device
DWORD  cbInQueue,	// size of input buffer
DWORD  cbOutQueue	// size of output buffer
);
Parameters

hCommDev

Identifies the communications device. The CreateFile function returns this handle.

cbInQueue

Specifies the recommended size, in bytes, of the device's internal input buffer.

cbOutQueue

Specifies the recommended size, in bytes, of the device's internal output buffer.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

After a process uses the CreateFile function to open a handle to a communications device, it can call SetupComm to set the communications parameters for the device. If it does not set them, the device uses the default parameters when the first call to another communications function occurs.

The cbInQueue and cbOutQueue parameters specify the recommended sizes for the internal buffers used by the driver for the specified device. For example, YMODEM protocol packets are slightly larger than 1024 bytes. Therefore, a recommended buffer size might be 1200 bytes for YMODEM communications. For Ethernet-based communications, a recommended buffer size might be 1600 bytes, which is slightly larger than a single Ethernet frame.

The device driver receives the recommended buffer sizes, but is free to use any input and output (I/O) buffering scheme, as long as it provides reasonable performance and data is not lost due to overrun (except under extreme circumstances). For example, the function can succeed even though the driver does not allocate a buffer, as long as some other portion of the operating system provides equivalent functionality.

If the device driver determines that the recommended buffer sizes involve transfers beyond its ability to handle, the function can fail.

See Also

CreateFile, SetCommState


SetUserObjectInformation [New - Windows NT]
SetUserObjectInformation  QuickInfo  Overview  Group

[New - Windows NT]

The SetUserObjectInformation function sets information about a window station or desktop object.

BOOL SetUserObjectInformation(

HANDLE hObject	// handle of the object for which to set information
int nIndex	// type of information to set
PVOID lpvInfo	// points to a buffer that contains the information
DWORD cbInfo	// size, in bytes, of lpvInfo buffer
);
Parameters

hObject

Identifies the window station or desktop object for which to set object information. This value can be an HDESK or HWINSTA handle (for example, a handle returned by CreateWindowStation, OpenWindowStation, CreateDesktop, or OpenDesktop).

nIndex

Specifies the object information to be set. This parameter must specify the following value:

Value	Description
UOI_FLAGS	Sets the object's handle flags. The lpvInfo parameter must point to a USEROBJECTFLAGS structure.
lpvInfo

Points to a buffer containing the object information.

cbInfo

Specifies the size, in bytes, of the information contained in the buffer pointed to by lpvInfo.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails the return value is FALSE. To get extended error information, call GetLastError.

See Also

CreateDesktop, CreateWindowStation, GetUserObjectInformation, OpenDesktop,.OpenWindowStation, USEROBJECTFLAGS


SetUserObjectSecurity
SetUserObjectSecurity  QuickInfo  Overview  Group

The SetUserObjectSecurity function sets the security of a user object. This can be, for example, a window or a DDE conversation.

BOOL SetUserObjectSecurity(

HANDLE  hObject,	// handle of user object
PSECURITY_INFORMATION  psi,	// address of security information
PSECURITY_DESCRIPTOR  psd	// address of security descriptor
);
Parameters

hObject

Identifies a user object for which security information is set.

psi

Points to a SECURITY_INFORMATION structure describing the security information being set.

psd

Points to a SECURITY_DESCRIPTOR structure containing the new security information.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The SetUserObjectSecurity function applies changes specified in a security descriptor to the security descriptor assigned to a user object. The object's security descriptor must be in self-relative form. If necessary, this function allocates additional memory to increase the size of the security descriptor.

The SetUserObjectSecurity function is successful only if the following conditions are met:

•	If the object's owner is being set, the calling process must either have WRITE_OWNER permission or be the object's owner.

•	If the object's discretionary access-control list (ACL) is being set, the calling process must either have WRITE_DAC permission or be the object's owner.

•	If the object's system ACL is being set, the SE_SECURITY_NAME privilege must be enabled for the calling process.

See Also

GetUserObjectSecurity, SECURITY_DESCRIPTOR, SECURITY_INFORMATION, SetFileSecurity, SetKernelObjectSecurity, SetPrivateObjectSecurity


SetViewportExt

The SetViewportExt function is not implemented in the Win32 API. Win32-based applications should use the SetViewportExtEx function.


SetViewportExtEx
SetViewportExtEx  QuickInfo  Overview  Group

The SetViewportExtEx function sets the horizontal and vertical extents of the viewport for a device context by using the specified values.

BOOL SetViewportExtEx(

HDC  hdc,	// handle of device context
int  nXExtent,	// new horizontal viewport extent
int  nYExtent,	// new vertical viewport extent
LPSIZE  lpSize	// original viewport extent
);
Parameters

hdc

Identifies the device context.

nXExtent

Specifies the horizontal extent, in device units, of the viewport.

nYExtent

Specifies the vertical extent, in device units, of the viewport.

lpSize

Points to a SIZE structure. The previous viewport extents (in device units) are placed in this structure. If lpSize is NULL, nothing is returned.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

When the following mapping modes are set, calls to the SetWindowExtEx and SetViewportExtEx functions are ignored.

•	MM_HIENGLISH

•	MM_HIMETRIC

•	MM_LOENGLISH

•	MM_LOMETRIC

•	MM_TEXT

•	MM_TWIPS

When MM_ISOTROPIC mode is set, an application must call the SetWindowExtEx function before it calls SetViewportExtEx.

See Also

GetViewportExtEx, SetWindowExtEx, SIZE,


SetViewportOrg

The SetViewportOrg function is not implemented in the Win32 API. Win32-based applications should use the SetViewportOrgEx function.


SetViewportOrgEx
SetViewportOrgEx  QuickInfo  Overview  Group

The SetViewportOrgEx function sets the viewport origin of a device context by using the specified coordinates.

BOOL SetViewportOrgEx(

HDC  hdc,	// handle of device context
int  X,	// new x-coordinate of viewport origin
int  Y,	// new y-coordinate of viewport origin
LPPOINT  lpPoint	// address of structure receiving original origin
);
Parameters

hdc

Identifies the device context.

X

Specifies the x-coordinate, in device units, of the new viewport origin.

Y

Specifies the y-coordinate, in device units, of the new viewport origin.

lpPoint

Points to a POINT structure. The previous viewport origin (in device coordinates) is placed in this structure. If lpPoint is NULL, nothing is returned.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

See Also

GetViewportOrgEx, POINT, SetWindowOrgEx


SetVoiceAccent

The SetVoiceAccent function is not implemented in the Win32 API.

See Also

Beep, MessageBeep


SetVoiceEnvelope

The SetVoiceEnvelope function is not implemented in the Win32 API.

See Also

Beep, MessageBeep


SetVoiceNote

The SetVoiceNote function is not implemented in the Win32 API.

See Also

Beep, MessageBeep


SetVoiceQueueSize

The SetVoiceQueueSize function is not implemented in the Win32 API.

See Also

Beep, MessageBeep


SetVoiceSound

The SetVoiceSound function is not implemented in the Win32 API.

See Also

Beep, MessageBeep


SetVoiceThreshold

The SetVoiceThreshold function is not implemented in the Win32 API.

See Also

Beep, MessageBeep


SetVolumeLabel
SetVolumeLabel  QuickInfo  Overview  Group

The SetVolumeLabel function sets the label of a file system volume.

BOOL SetVolumeLabel(

LPCTSTR  lpRootPathName,	// address of name of root directory for volume
LPCTSTR  lpVolumeName	// name for the volume
);
Parameters

lpRootPathName

Points to a null-terminated string specifying the root directory of a file system volume. This is the volume the function will label. If this parameter is NULL, the root of the current directory is used.

lpVolumeName

Points to a string specifying a name for the volume. If this parameter is NULL, the function deletes the name of the specified volume.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

GetVolumeInformation


SetWindowContextHelpId [New - Windows NT]
SetWindowContextHelpId  QuickInfo  Overview  Group

[New - Windows NT]

The SetWindowContextHelpId function associates a help context identifier with the specified window.

BOOL SetWindowContextHelpId(

HWND  hwnd,
DWORD  dwContextHelpId
);
Parameters

hwnd

Handle to the window with which to associate the help context identifier.

dwContextHelpId

Help context identifier.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

If a child window does not have a help context identifier, it inherits the identifier of its parent window. Likewise, if an owned window does not have a help context identifier, it inherits the identifier of its owner window. This inheritance of help context identifiers allows an application to set just one identifier for a dialog box and all of its controls.


SetWindowExt

The SetWindowExt function is not implemented in the Win32 API. Win32-based applications should use the SetWindowExtEx function.


SetWindowExtEx
SetWindowExtEx  QuickInfo  Overview  Group

The SetWindowExtEx function sets the horizontal and vertical extents of the window for a device context by using the specified values.

BOOL SetWindowExtEx(

HDC  hdc,	// handle of device context
int  nXExtent,	// new horizontal window extent
int  nYExtent,	// new vertical window extent
LPSIZE  lpSize	// original window extent
);
Parameters

hdc

Identifies the device context.

nXExtent

Specifies the window's horizontal extent in logical units.

nYExtent

Specifies the window's vertical extent in logical units.

lpSize

Points to a SIZE structure. The previous window extents (in logical units) are placed in this structure. If lpSize is NULL, nothing is returned.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

When the following mapping modes are set, calls to the SetWindowExtEx and SetViewportExtEx functions are ignored:

•	MM_HIENGLISH

•	MM_HIMETRIC

•	MM_LOENGLISH

•	MM_LOMETRIC

•	MM_TEXT

•	MM_TWIPS

When MM_ISOTROPIC mode is set, an application must call the SetWindowExtEx function before calling SetViewportExtEx.

See Also

GetWindowExtEx, SetViewportExtEx, SIZE


SetWindowLong
SetWindowLong  QuickInfo  Overview  Group

The SetWindowLong function changes an attribute of the specified window. The function also sets a 32-bit (long) value at the specified offset into the extra window memory of a window.

LONG SetWindowLong(

HWND  hwnd,	// handle of window
int  nIndex,	// offset of value to set
LONG  lNewLong	// new value
);
Parameters

hwnd

Identifies the window and, indirectly, the class to which the window belongs.

nIndex

Specifies the zero-based offset to the value to be set. Valid values are in the range zero through the number of bytes of extra window memory, minus 4; for example, if you specified 12 or more bytes of extra memory, a value of 8 would be an index to the third 32-bit integer. To set any other value, specify one of the following values:

Value	Action
GWL_EXSTYLE	Sets a new extended window style.
GWL_STYLE	Sets a new window style.
GWL_WNDPROC	Sets a new address for the window procedure.
GWL_HINSTANCE	Sets a new application instance handle.
GWL_ID	Sets a new identifier of the window.
GWL_USERDATA	Sets the 32-bit value associated with the window. Each window has a corresponding 32-bit value intended for use by the application that created the window.
The following values are also available when the hwnd parameter identifies a dialog box:

Value	Action
DWL_DLGPROC	Sets the new address of the dialog box procedure.
DWL_MSGRESULT	Sets the return value of a message processed in the dialog box procedure.
DWL_USER	Sets new extra information that is private to the application, such as handles or pointers.
lNewLong

Specifies the replacement value.

Return Value

If the function succeeds, the return value is the previous value of the specified 32-bit integer.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

If the previous value of the specified 32-bit integer is zero, and the function succeeds, the return value is zero, but the function does not clear the last error information. This makes it difficult to determine success or failure. To deal with this, you should clear the last error information by calling SetLastError(0) before calling SetWindowLong. Then, function failure will be indicated by a return value of zero and a GetLastError result that is non-zero.

Remarks

The SetWindowLong function fails if the window specified by the hwnd parameter does not belong to the same process as the calling thread.

If you use the SetWindowLong function and the GWL_WNDPROC index to replace the window procedure, the window procedure must conform to the guidelines specified in the description of the WindowProc callback function.

Calling SetWindowLong with the GWL_WNDPROC index creates a subclass of the window class used to create the window. An application should not subclass a window created by another process. The SetWindowLong function creates the window subclass by changing the window procedure associated with a particular window, causing Windows to call the new window procedure instead of the previous one. An application must pass any messages not processed by the new window procedure to the previous window procedure by calling CallWindowProc. This allows the application to create a chain of window procedures.

Reserve extra window memory by specifying a nonzero value in the cbWndExtra member of the WNDCLASS structure used with the RegisterClass function.

You must not call SetWindowLong with the GWL_HWNDPARENT index to change the parent of a child window. Instead, use the SetParent function.

See Also

CallWindowProc, GetWindowLong, GetWindowWord, RegisterClass, SetParent, SetWindowWord, WindowProc, WNDCLASS


SetWindowOrg

The SetWindowOrg function is not implemented in the Win32 API. Win32-based applications should use the SetWindowOrgEx function.


SetWindowOrgEx
SetWindowOrgEx  QuickInfo  Overview  Group

The SetWindowOrgEx function sets the window origin of the device context by using the specified coordinates.

BOOL SetWindowOrgEx(

HDC  hdc,	// handle of device context
int  X,	// new x-coordinate of window origin
int  Y,	// new y-coordinate of window origin
LPPOINT  lpPoint	// address of structure receiving original origin
);
Parameters

hdc

Identifies the device context.

X

Specifies the logical x-coordinate of the new window origin.

Y

Specifies the logical y-coordinate of the new window origin.

lpPoint

Points to a POINT structure. The previous origin of the window is placed in this structure. If lpPoint is NULL, nothing is returned.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

See Also

GetViewportOrgEx, GetWindowOrgEx, POINT, SetViewportOrgEx


SetWindowPlacement
SetWindowPlacement  QuickInfo  Overview  Group

The SetWindowPlacement function sets the show state and the restored, minimized, and maximized positions of the specified window.

BOOL SetWindowPlacement(

HWND  hwnd,	// handle of window
CONST WINDOWPLACEMENT *  lpwndpl	// address of structure with position data
);
Parameters

hwnd

Identifies the window.

lpwndpl

Points to a WINDOWPLACEMENT structure that specifies the new show state and window positions.

Before calling SetWindowPlacement, set the length member of the WINDOWPLACEMENT structure to sizeof(WINDOWPLACEMENT).

Windows 95 only: SetWindowPlacement fails if lpwndpl->length is not set correctly.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

GetWindowPlacement, WINDOWPLACEMENT


SetWindowPos
SetWindowPos  QuickInfo  Overview  Group

The SetWindowPos function changes the size, position, and Z order of a child, pop-up, or top-level window. Child, pop-up, and top-level windows are ordered according to their appearance on the screen. The topmost window receives the highest rank and is the first window in the Z order.

BOOL SetWindowPos(

HWND  hwnd,	// handle of window
HWND  hwndInsertAfter,	// placement-order handle
int  x,	// horizontal position
int  y,	// vertical position
int  cx,	// width
int  cy,	// height
UINT  fuFlags	// window-positioning flags
);
Parameters

hwnd

Identifies the window.

hwndInsertAfter

Identifies the window to precede the positioned window in the Z order. This parameter must be a window handle or one of the following values:

Value	Meaning
HWND_BOTTOM	Places the window at the bottom of the Z order. If the hwnd parameter identifies a topmost window, the window loses its topmost status and is placed at the bottom of all other windows.
HWND_NOTOPMOST	Places the window above all non-topmost windows (that is, behind all topmost windows). This flag has no effect if the window is already a non-topmost window.
HWND_TOP	Places the window at the top of the Z order.
HWND_TOPMOST	Places the window above all non-topmost windows. The window maintains its topmost position even when it is deactivated.
For more information about how this parameter is used, see the following Remarks section.

x

Specifies the new position of the left side of the window.

y

Specifies the new position of the top of the window.

cx

Specifies the new width of the window, in pixels.

cy

Specifies the new height of the window, in pixels.

fuFlags

Specifies the window sizing and positioning flags. This parameter can be a combination of the following values:

Value	Meaning
SWP_DRAWFRAME	Draws a frame (defined in the window's class description) around the window.
SWP_FRAMECHANGED	Sends a WM_NCCALCSIZE message to the window, even if the window's size is not being changed. If this flag is not specified, WM_NCCALCSIZE is sent only when the window's size is being changed.
SWP_HIDEWINDOW	Hides the window.
SWP_NOACTIVATE	Does not activate the window. If this flag is not set, the window is activated and moved to the top of either the topmost or non-topmost group (depending on the setting of the hwndInsertAfter parameter).
SWP_NOCOPYBITS	Discards the entire contents of the client area. If this flag is not specified, the valid contents of the client area are saved and copied back into the client area after the window is sized or repositioned.
SWP_NOMOVE	Retains the current position (ignores the x and y parameters).
SWP_NOSIZE	Retains the current size (ignores the cx and cy parameters).
SWP_NOREDRAW	Does not redraw changes. If this flag is set, no repainting of any kind occurs. This applies to the client area, the nonclient area (including the title bar and scroll bars), and any part of the parent window uncovered as a result of the window being moved. When this flag is set, the application must explicitly invalidate or redraw any parts of the window and parent window that need redrawing.
SWP_NOZORDER	Retains the current Z order (ignores the hwndInsertAfter parameter).
SWP_SHOWWINDOW	Displays the window.
Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

If the SWP_SHOWWINDOW or SWP_HIDEWINDOW flag is set, the window cannot be moved or sized.

All coordinates for child windows are client coordinates (relative to the upper-left corner of the parent window's client area).

A window can be made a topmost window either by setting the hwndInsertAfter parameter to HWND_TOPMOST and ensuring that the SWP_NOZORDER flag is not set, or by setting a window's position in the Z order so that it is above any existing topmost windows. When a non-topmost window is made topmost, its owned windows are also made topmost. Its owners, however, are not changed.

If neither the SWP_NOACTIVATE nor SWP_NOZORDER flag is specified (that is, when the application requests that a window be simultaneously activated and its position in the Z order changed), the value specified in hwndInsertAfter is used only in the following circumstances:

•	Neither the HWND_TOPMOST nor HWND_NOTOPMOST flag is specified in hwndInsertAfter.

•	The window identified by hwnd is not the active window.

An application cannot activate an inactive window without also bringing it to the top of the Z order. Applications can change an activated window's position in the Z order without restrictions, or it can activate a window and then move it to the top of the topmost or non-topmost windows.

If a topmost window is repositioned to the bottom (HWND_BOTTOM) of the Z order or after any non-topmost window, it is no longer topmost. When a topmost window is made non-topmost, its owners and its owned windows are also made non-topmost windows.

A non-topmost window can own a topmost window, but the reverse cannot occur. Any window (for example, a dialog box) owned by a topmost window is itself made a topmost window, to ensure that all owned windows stay above their owner.

If an application is not in the foreground, and should be in the foreground, it must call the SetForegroundWindow function.

See Also

MoveWindow, SetActiveWindow, SetForegroundWindow


SetWindowRgn [New - Windows NT]
SetWindowRgn  QuickInfo

[New - Windows NT]

The SetWindowRgn function sets the window region of a window. The window region determines the area within the window where the operating system permits drawing. The operating system does not display any portion of a window that lies outside of the window region

int SetWindowRgn(

HWND  hWnd,	// handle to window whose window region is to be set
HRGN  hRgn,	// handle to region
BOOL  bRedraw	// window redraw flag
);
Parameters

hWnd

Handle to the window whose window region is to be set.

hRgn

Handle to a region. The function sets the window region of the window to this region.

If hRgn is NULL, the function sets the window region to NULL.

bRedraw

Boolean value that specifies whether the operating system redraws the window after setting the window region. If bRedraw is TRUE, the operating system does so; otherwise, it does not.

Typically, you set bRedraw to TRUE if the window is visible.

Return Value

If the function succeeds, the return value is non-zero.

If the function fails, the return value is zero.

Comments

If the bRedraw parameter is TRUE, the system sends the WM_WINDOWPOSCHANGING and WM_WINDOWPOSCHANGED messages to the window.

The coordinates of a window's window region are relative to the upper-left corner of the window, not the client area of the window.

After a successful call to SetWindowRgn, the operating system owns the region specified by the region handle hRgn. The operating system does not make a copy of the region. Thus, you should not make any further function calls with this region handle. In particular, do not close this region handle.

To obtain the window region of a window, call the GetWindowRgn function.

See Also

GetWindowRgn, WM_WINDOWPOSCHANGING


SetWindowsHook
SetWindowsHook  QuickInfo  Overview  Group

The SetWindowsHook function is not implemented in the Win32 API. Win32-based applications should use the SetWindowsHookEx function.


SetWindowsHookEx
SetWindowsHookEx  QuickInfo  Overview  Group

The SetWindowsHookEx function installs an application-defined hook procedure into a hook chain. An application installs a hook procedure to monitor the system for certain types of events. A hook procedure can monitor events associated either with a specific thread or with all threads in the system. This function supersedes the SetWindowsHook function.

HHOOK SetWindowsHookEx(

int  idHook,	// type of hook to install
HOOKPROC  hkprc,	// address of hook procedure
HINSTANCE  hMod,	// handle of application instance
DWORD  dwThreadID	// identity of thread to install hook for
);
Parameters

idHook

Specifies the type of hook procedure to be installed. This parameter can be one of the following values:

Value	Description
WH_CALLWNDPROC	Installs a hook procedure that monitors messages before the system sends them to the destination window procedure. For more information,  the CallWndProc hook procedure.
WH_CALLWNDPROCRET	Windows 95 only: Installs a hook procedure that monitors messages after they have been processed by the destination window procedure. For more information, see  the CallWndRetProc hook procedure.
WH_CBT	Installs a hook procedure that receives notifications useful to a computer-based training (CBT) application. For more information, see the CBTProc hook procedure.
WH_DEBUG	Installs a hook procedure useful for debugging other hook procedures. For more information, see the DebugProc hook procedure.
WH_GETMESSAGE	Installs a hook procedure that monitors messages posted to a message queue. For more information, see the GetMsgProc hook procedure.
WH_JOURNALPLAYBACK	Installs a hook procedure that posts messages previously recorded by a WH_JOURNALRECORD hook procedure. For more information, see the JournalPlaybackProc hook procedure.
WH_JOURNALRECORD	Installs a hook procedure that records input messages posted to the system message queue. This hook is useful for recording macros. For more information, see the JournalRecordProc hook procedure.
WH_KEYBOARD	Installs a hook procedure that monitors keystroke messages. For more information, see the KeyboardProc hook procedure.
WH_MOUSE	Installs a hook procedure that monitors mouse messages. For more information, see the MouseProc hook procedure.
WH_MSGFILTER	Installs a hook procedure that monitors messages generated as a result of an input event in a dialog box, message box, menu, or scroll bar. For more information, see  the MessageProc hook procedure.
WH_SHELL	Installs a hook procedure that receives notifications useful to shell applications. For more information, see  the ShellProc hook procedure.
WH_SYSMSGFILTER	Installs a hook procedure that monitors messages generated as a result of an input event in a dialog box, message box, menu, or scroll bar. The hook procedure monitors these messages for all applications in the system. For more information, see  the SysMsgProc hook procedure.
hkprc

Points to the hook procedure. If the dwThreadID parameter is zero or specifies the identifier of a thread created by a different process, the hkprc parameter must point to a hook procedure in a dynamic-link library (DLL). Otherwise, hkprc can point to a hook procedure in the code associated with the current process.

hMod

Identifies the DLL containing the hook procedure pointed to by the hkprc parameter. The hMod parameter must be set to NULL if the dwThreadID parameter specifies a thread created by the current process and if the hook procedure is within the code associated with the current process.

dwThreadID

Specifies the identifier of the thread with which the hook procedure is to be associated. If this parameter is zero, the hook procedure is associated with all existing threads.

Return Value

If the function succeeds, the return value is the handle of the hook procedure.

If the function fails, the return value is NULL.

Remarks

An error may occur if the hMod parameter is NULL and the dwThreadId parameter is zero or specifies the identifier of a thread created by another process.

Chaining to the next hook procedure (that is, calling the CallNextHookEx function) is optional. An application or library can call the next hook procedure either before or after any processing in its own hook procedure.

Before terminating, an application must call the UnhookWindowsHookEx function to free system resources associated with the hook.

The scope of a hook depends on the hook type. Some hooks can be set only with system scope; others can also be set for only a specific thread, as shown in the following list:

Hook	Scope
WH_CALLWNDPROC	Thread or system
WH_CBT	Thread or system
WH_DEBUG	Thread or system
WH_GETMESSAGE	Thread or system
WH_JOURNALPLAYBACK	System only
WH_JOURNALRECORD	System only
WH_KEYBOARD	Thread or system
WH_MOUSE	Thread or system
WH_MSGFILTER	Thread or system
WH_SHELL	Thread or system
WH_SYSMSGFILTER	System only
For a specified hook type, thread hooks are called first, then system hooks.

The system hooks are a shared resource, and installing one affects all applications. All system hook functions must be in libraries. System hooks should be restricted to special-purpose applications or to use as a development aid during application debugging. Libraries that no longer need a hook should remove the hook procedure.

See Also

CallNextHookEx, CallWndProc, CBTProc, DebugProc, GetMsgProc, JournalPlaybackProc, JournalRecordProc, KeyboardProc, MouseProc, MessageProc, ShellProc, SysMsgProc, UnhookWindowsHookEx


SetWindowText
SetWindowText  QuickInfo  Overview  Group

The SetWindowText function changes the text of the specified window's title bar (if it has one). If the specified window is a control, the text of the control is changed.

BOOL SetWindowText(

HWND  hwnd,	// handle of window or control
LPCTSTR  lpsz	// address of string
);
Parameters

hwnd

Identifies the window or control whose text is to be changed.

lpsz

Points to a null-terminated string to be used as the new title or control text.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The SetWindowText function causes a WM_SETTEXT message to be sent to the specified window or control. If the window is a list box control created with the WS_CAPTION style, however, SetWindowText sets the text for the control, not for the list box entries.

The SetWindowText function does not expand tab characters (ASCII code 0x09). Tab characters are displayed as vertical bar (|) characters.

See Also

GetWindowText, WM_SETTEXT


SetWindowWord
SetWindowWord  QuickInfo  Overview  Group

The SetWindowWord function replaces the 16-bit (word) value at the specified offset into the extra window memory for the specified window.

WORD SetWindowWord(

HWND  hwnd,	// handle of window
int  nIndex,	// offset of value to set
WORD  wNewWord	// new value
);
Parameters

hwnd

Identifies the window and, indirectly, the class to which the window belongs.

nIndex

Specifies the zero-based byte offset of the value to be replaced. Valid values are in the range zero through the number of bytes of window memory, minus two; for example, if you specified 10 or more bytes of extra window memory, a value of 8 would be an index to the fifth 16-bit integer.

wNewWord

Specifies the replacement value.

Return Value

If the function succeeds, the return value is the previous value of the specified 16-bit integer.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

Reserve extra window memory by specifying a nonzero value in the cbWndExtra member of the WNDCLASS structure used with the RegisterClass function.

The GWW_ values are obsolete in the Win32 API. You must use the SetWindowLong function to set information about the window.

See Also

GetParent, GetWindowLong, GetWindowWord, RegisterClass, SetParent, SetWindowLong, WNDCLASS


SetWinMetaFileBits
SetWinMetaFileBits  QuickInfo  Overview  Group

The SetWinMetaFileBits function converts a metafile from the older Windows format to the new enhanced format and stores the new metafile in memory.

HENHMETAFILE SetWinMetaFileBits(

UINT  cbBuffer,	// size of buffer
CONST BYTE *  lpbBuffer,	// address of buffered metafile data
HDC  hdcRef,	// handle of reference device context
CONST METAFILEPICT *  lpmfp	// suggested size of metafile picture
);
Parameters

cbBuffer

Specifies the size, in bytes, of the buffer that contains the Windows-format metafile.

lpbBuffer

Points to a buffer that contains the Windows-format metafile data. (It is assumed that the data was obtained by using the GetMetaFileBitsEx or GetWinMetaFileBits function.)

hdcRef

Identifies a reference device context.

lpmfp

Points to a METAFILEPICT structure that contains the suggested size of the metafile picture and the mapping mode that was used when the picture was created.

Return Value

If the function succeeds, the return value is a handle of a memory-based enhanced metafile.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

Windows uses the reference device context's resolution data and the data in the METAFILEPICT structure to scale a picture. If the hdcRef parameter is NULL, Windows uses resolution data for the current output device. If the lpmfp parameter is NULL, Windows uses the MM_ANISOTROPIC mapping mode to scale the picture so that it fits the entire device surface. The hMF field in the METAFILEPICT structure is not used.

When the application no longer needs the enhanced metafile handle, it should delete it by calling the DeleteEnhMetaFile function.

The handle returned by this function can be used with other enhanced-metafile functions.

If the reference device context is not identical to the device in which the metafile was originally created, some GDI functions that use device units may not draw the picture correctly.

See Also

DeleteEnhMetaFile, GetWinMetaFileBits, GetMetaFileBitsEx, METAFILEPICT, PlayEnhMetaFile


SetWorldTransform
SetWorldTransform  QuickInfo  Overview  Group

The SetWorldTransform function sets a two-dimensional linear transformation between world space and page space for the specified device context. This transformation can be used to scale, rotate, shear, or translate graphics output.

BOOL SetWorldTransform(

HDC  hdc,	// handle of device context
CONST XFORM *  lpXform	// address of transformation data
);
Parameters

hdc

Identifies the device context.

lpXform

Points to an XFORM structure that contains the transformation data.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

For any coordinates (x, y) in world space, the transformed coordinates in page space (x', y') can be determined by the following algorithm:

x' = x * eM11 + y * eM21 + eDx,

y' = x * eM12 + y * eM22 + eDy,

where the transformation matrix is represented by the following:

| eM11 eM12 0 |

| eM21 eM22 0 |

| eDx  eDy  1 |

The mapping mode (defined by the current window and viewport extents origins) serves to define units and scales.

The world transformation is usually used to scale or rotate logical images in a device-independent way.

The default world transformation is the identity matrix with zero offset.

The SetWorldTransform function will fail unless the graphics mode for the given device context has been set to GM_ADVANCED by previously calling the SetGraphicsMode function. Likewise, it will not be possible to reset the graphics mode for the device context to the default GM_COMPATIBLE mode, unless the world transformation has first been reset to the default identity transformation by calling SetWorldTransform or ModifyWorldTransform.

See Also

GetWorldTransform, ModifyWorldTransform, SetGraphicsMode, SetMapMode, SetViewportExtEx, SetViewportOrgEx, SetWindowExtEx, SetWindowOrgEx, XFORM


SHAddToRecentDocs [New - Windows 95]
SHAddToRecentDocs  QuickInfo

[New - Windows 95]

Adds a document to the shell's list of recently used documents or clears all documents from the list. The user accesses the list through the Start menu of the Windows taskbar.

WINSHELLAPI void WINAPI SHAddToRecentDocs(

UINT  uFlags,
LPCVOID  pv
);
Parameters

uFlags

Flag that indicates the meaning of the pv parameter. This parameter can be one of the following values:

SHARD_PATH	pv is the address of a path string.
SHARD_PIDL	pv is the address of an item identifier list.
pv

Pointer to a buffer that contains the path and filename of the document, or the address of an ITEMIDLIST structure that contains an item identifier list uniquely identifying the document. If this parameter is NULL, the function clears all documents from the list.

Return Value

No return value.


SHAppBarMessage [New - Windows 95]
SHAppBarMessage  QuickInfo

[New - Windows 95]

Sends an appbar message to the system.

WINSHELLAPI UINT APIENTRY SHAppBarMessage(

DWORD  dwMessage,
PAPPBARDATA  pabd
);
Parameters

dwMessage

Identifier of the appbar message to send. This parameter can be one of the following values:

ABM_ACTIVATE	Notifies the system that an appbar has been activated.
ABM_GETAUTOHIDEBAR	Retrieves the handle of the autohide appbar associated with a particular edge of the screen.
ABM_GETSTATE	Retrieves the autohide and always-on-top states of the Windows taskbar.
ABM_GETTASKBARPOS	Retrieves the bounding rectangle of the Windows taskbar.
ABM_NEW	Registers a new appbar and specifies the message identifier that the system should use to send notification messages to the appbar.
ABM_QUERYPOS	Requests a size and screen position for an appbar.
ABM_REMOVE	Unregisters an appbar, removing bar from the system's internal list.
ABM_SETAUTOHIDEBAR	Registers or unregisters an autohide appbar for an edge of the screen.
ABM_SETPOS	Sets the size and screen position of an appbar.
ABM_WINDOWPOSCHANGED	Notifies the system when an appbar's position has changed.
pabd

Pointer to an APPBARDATA structure. The content of the structure depends on the value of dwMessage.

Return Value

Returns a message-dependent value. For more information, see the documentation for the individual appbar messages.

See Also

APPBARDATA


SHBrowseForFolder [New - Windows 95]
SHBrowseForFolder  QuickInfo

[New - Windows 95]

Displays a dialog box that enables the user to select a shell folder.

WINSHELLAPI LPITEMIDLIST WINAPI SHBrowseForFolder(

LPBROWSEINFO  lpbi
);
Parameter

lpbi

Pointer to a BROWSEINFO structure that contains information used to display the dialog box.

Return Value

Returns a pointer to an item identifier list that specifies the location of the selected folder relative to the root of the name space. If the user chooses the Cancel button in the dialog box, the return value is NULL.

The calling application is responsible for freeing the returned item identifier list using the shell's task allocator.

See Also

BROWSEINFO


SHChangeNotify [New - Windows 95]
SHChangeNotify  QuickInfo

[New - Windows 95]

Notifies the system of an event that an application has performed. An application should use this function if it performs an action that may affect the shell.

WINSHELLAPI void WINAPI SHChangeNotify(

LONG  wEventId,
UINT  uFlags,
LPCVOID  dwItem1,
LPCVOID  dwItem2
);
Parameters

wEventId

Array of flags that specifies the events. This parameter can be a combination of the following values:

SHCNE_ASSOCCHANGED	Changed a file type association.
SHCNE_ATTRIBUTES	Changed a file's attributes.
SHCNE_CREATE	Created a file.
SHCNE_DELETE	Deleted a file.
SHCNE_DRIVEADD	Added a network drive.
SHCNE_DRIVEADDGUI	Added a network drive by way of a graphic user interface.
SHCNE_DRIVEREMOVED	Removed a network drive.
SHCNE_INTERRUPT	Performed the event as a result of a system interrupt.
SHCNE_MEDIAINSERTED	Added removable media, such as a CD-ROM.
SHCNE_MEDIAREMOVED	Removed a removable medium, such as a CD-ROM.
SHCNE_MKDIR	Created a new directory.
SHCNE_NETSHARE	Shared a resource on the network.
SHCNE_NETUNSHARE	Stopped sharing a resource.
SHCNE_RENAMEFOLDER	Renamed a folder.
SHCNE_RENAMEITEM	Renamed an item in a folder.
SHCNE_RMDIR	Removed a directory.
SHCNE_SERVERDISCONNECT	Disconnected a network server.
SHCNE_UPDATEDIR	Updated the contents of a directory.
SHCNE_UPDATEIMAGE	Changed an image in the system global image list.
SHCNE_UPDATEITEM	Changed the properties of a printer or file.
uFlags

Flag that indicates the meaning of dwItem1 and dwItem2. This parameter can be one of the following values:

SHCNF_DWORD	The dwItem1 and dwItem2 parameters are doubleword values.
SHCNF_FLUSH	Flushes the system event buffer. The function does not return until the system is finished processing the given event.
SHCNF_FLUSHNOWAIT	Flushes the system event buffer. The function returns immediately regardless of whether the system is finished processing the given event.
SHCNF_IDLIST	dwItem1 and dwItem2 are the addresses of item identifier lists.
SHCNF_PATH	dwItem1 and dwItem2 are path names.
SHCNF_PRINTER	dwItem1 and dwItem2 are printer "friendly" names.
dwItem1

First event-dependent value.

dwItem2

Second event-dependent value.

Return Value

No return value.


ShellAbout
ShellAbout  QuickInfo  Overview  Group

The ShellAbout function displays a Shell About dialog box.

int ShellAbout (

HWND  hWnd,	// handle of parent window
LPCTSTR  szApp,	// title bar and first line text
LPCTSTR  szOtherStuff,	// other dialog text
HICON  hIcon	// icon to display
);
Parameters

hWnd

Identifies a parent window. This parameter can be NULL.

szApp

Points to text that the function displays in the title bar of the Shell About dialog box and on the first line of the dialog box after the text "Microsoft Windows" or "Microsoft Windows NT." If the text contains a "#" separator, dividing it into two parts, the function displays the first part in the title bar, and the second part on the first line after the text "Microsoft Windows" or "Microsoft Windows NT."

szOtherStuff

Points to text that the function displays in the dialog box after the version and copyright information.

hIcon

Identifies an icon that the function displays in the dialog box. If this parameter is NULL, the function displays the Microsoft Windows or Microsoft Windows NT icon.

Return Value

If the function succeeds in displaying the dialog box, the return value is TRUE; otherwise the return value is FALSE.

Remarks

Please note that the ShellAbout function dialog box uses text and a default icon that are specific to either Microsoft Windows or Microsoft Windows NT.

An example of a Shell About dialog box can be seen by selecting the About Program Manager command in Program Manager.


ShellExecute
ShellExecute  QuickInfo  Overview  Group

The ShellExecute function opens or prints a specified file. The file can be an executable file or a document file. See ShellExecuteEx also.

HINSTANCE ShellExecute(

HWND  hwnd,	// handle to parent window
LPCTSTR  lpOperation,	// pointer to string that specifies operation to perform
LPCTSTR  lpFile,	// pointer to filename string
LPTSTR  lpParameters,	// pointer to string that specifies executable-file parameters
LPCTSTR  lpDirectory,	// pointer to string that specifies default directory
INT  nShowCmd	// whether file is shown when opened
);
Parameters

hwnd

Specifies a parent window. This window receives any message boxes that an application produces. For example, an application may report an error by producing a message box.

lpOperation

Pointer to a null-terminated string that specifies the operation to perform. The following operation strings are valid:

String	Meaning
"open"	The function opens the file specified by lpFile. The file can be an executable file or a document file.
"print"	The function prints the file specified by lpFile. The file should be a document file. If the file is an executable file, the function opens the file, as if "open" had been specified.
The lpOperation parameter can be NULL. In that case, the function opens the file specified by lpFile.

lpFile

Pointer to a null-terminated string that specifies the file to open or print. The function can open an executable file or a document file. The function can print a document file.

lpParameters

If lpFile specifies an executable file, lpParameters is a pointer to a null-terminated string that specifies parameters to be passed to the application.

If lpFile specifies a document file, lpParameters should be NULL.

lpDirectory

Pointer to a null-terminated string that specifies the default directory.

nShowCmd

If lpFile specifies an executable file, nShowCmd specifies how the application is to be shown when it is opened.  This parameter can be one of the following values:

Value	Meaning
SW_HIDE	Hides the window and activates another window.
SW_MAXIMIZE	Maximizes the specified window.
SW_MINIMIZE	Minimizes the specified window and activates the next top-level window in the Z order.
SW_RESTORE	Activates and displays the window. If the window is minimized or maximized, Windows restores it to its original size and position. An application should specify this flag when restoring a minimized window.
SW_SHOW	Activates the window and displays it in its current size and position.
SW_SHOWDEFAULT	Sets the show state based on the SW_ flag specified in the STARTUPINFO structure passed to the CreateProcess function by the program that started the application. An application should call ShowWindow with this flag to set the initial show state of its main window.
SW_SHOWMAXIMIZED	Activates the window and displays it as a maximized window.
SW_SHOWMINIMIZED	Activates the window and displays it as a minimized window.
SW_SHOWMINNOACTIVE	Displays the window as a minimized window. The active window remains active.
SW_SHOWNA	Displays the window in its current state. The active window remains active.
SW_SHOWNOACTIVATE	Displays a window in its most recent size and position. The active window remains active.
SW_SHOWNORMAL	Activates and displays a window. If the window is minimized or maximized, Windows restores it to its original size and position. An application should specify this flag when displaying the window for the first time.
If lpFile specifies a document file, nShowCmd should be zero.

Return Value

If the function succeeds, the return value is the instance handle of the application that was run, or the handle of a dynamic data exchange (DDE) server application.

If the function fails, the return value is an error value that is less than or equal to 32. The following table lists these error values:

Value	Meaning
0	The operating system is out of memory or resources.
ERROR_FILE_NOT_FOUND	The specified file was not found.
ERROR_PATH_NOT_FOUND	The specified path was not found.
ERROR_BAD_FORMAT	The .EXE file is invalid (non-Win32 .EXE or error in .EXE image).
SE_ERR_ACCESSDENIED	Windows 95 only: The operating system denied access to the specified file.
SE_ERR_ASSOCINCOMPLETE	The filename association is incomplete or invalid.
SE_ERR_DDEBUSY	The DDE transaction could not be completed because other DDE transactions were being processed.
SE_ERR_DDEFAIL	The DDE transaction failed.
SE_ERR_DDETIMEOUT	The DDE transaction could not be completed because the request timed out.
SE_ERR_DLLNOTFOUND	Windows 95 only: The specified dynamic-link library was not found.
SE_ERR_FNF	Windows 95 only: The specified file was not found.
SE_ERR_NOASSOC	There is no application associated with the given filename extension.
SE_ERR_OOM	Windows 95 only: There was not enough memory to complete the operation.
SE_ERR_PNF	Windows 95 only: The specified path was not found.
SE_ERR_SHARE	A sharing violation occurred.
Remarks

The file specified by the lpFile parameter can be a document file or an executable file. If the file is a document file, the ShellExecute function opens or prints it, depending on the value of the lpOperation parameter. If the file is an executable file, the ShellExecute function opens it, even if lpOperation specifies printing.

Windows 95: You can use ShellExecute to open or explore a Windows 95 folder. To open a folder, use either of the following calls:

ShellExecute(handle, NULL, "path_to_folder", NULL, NULL, SW_SHOWNORMAL);

or

ShellExecute(handle, "open", "path_to_folder", NULL, NULL, SW_SHOWNORMAL);

To explore a folder, use the following call:

ShellExecute(handle, "explore", "path_to_folder", NULL, NULL, SW_SHOWNORMAL);

If lpOperation is NULL, the function opens the file specified by lpFile. If lpOperation is "open" or "explore", the function will force a open window or explorer.

See Also

FindExecutable, ShellExecuteEx


ShellExecuteEx
ShellExecuteEx  QuickInfo  Overview  Group

The ShellExecuteEx function performs an action on a file. The file can be an executable file or a document.

WINSHELLAPI BOOL WINAPI ShellExecuteEx(

LPSHELLEXECUTEINFO  lpExecInfo	// pointer to SHELLEXECUTEINFO structure
);
Parameters

lpExecInfo

Pointer to a SHELLEXECUTEINFO structure that contains and receives information about the application to start.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

If the function succeeds, it sets the hInstApp member of the SHELLEXECUTEINFO structure to the instance handle of the application that the function started. If the function fails, hInstApp is one of the SE_ERR_ error values indicating the cause of the failure. (An instance handle will always be greater than 32, and an error value less than 32.) Note that the SE_ERR_ error values are for compatibility with the ShellExecute function; use the GetLastError function to retrieve error information.

Last error values returned by GetLastError correspond to the SE_ERR_ values and may be one of the following:

Value	Meaning
ERROR_FILE_NOT_FOUND	The specified file was not found.
ERROR_PATH_NOT_FOUND	The specified path was not found.
ERROR_DDE_FAIL	The DDE transaction failed.
ERROR_NO_ASSOCIATION	There is no application associated with the given filename extension.
ERROR_ACCESS_DENIED
ERROR_DLL_NOT_FOUND
ERROR_CANCELLED	The function prompted the user for the location of the application, but the user cancelled the request.
ERROR_NOT_ENOUGH_MEMORY
ERROR_SHARING_VIOLATION	A sharing violation occurred.
See Also

ShellExecute, SHELLEXECUTEINFO


ShellProc
ShellProc  QuickInfo  Overview  Group

The ShellProc hook procedure is an application-defined or library-defined callback function a shell application uses to receive useful notifications from the system.

LRESULT CALLBACK ShellProc(

int  nCode,	// hook code
WPARAM  wParam,	// event-specific information
LPARAM  lParam	// undefined
);
Parameters

nCode

Specifies the hook code. This parameter can be one of the following values:

Value	Meaning
HSHELL_ACTIVATESHELLWINDOW	The shell should activate its main window.
HSHELL_GETMINRECT	Windows 95 only: A window is being minimized or maximized and the system needs the coordinates of the minimized rectangle for the window. The wParam parameter contains the handle of the window, and the lParam parameter contains the address of a RECT structure that receives the coordinates.
HSHELL_LANGUAGE	Windows 95 only: Keyboard language was changed or a new keyboard layout was loaded.
HSHELL_REDRAW	Windows 95 only: The title of a window in the task bar has been redrawn. The wParam parameter contains the handle of the window.
HSHELL_TASKMAN	Windows 95 only: The user has selected the task list. The wParam parameter is undefined and should be ignored. A shell application that provides a task list should return TRUE to prevent Windows from starting its task list.
HSHELL_WINDOWACTIVATED	Windows 95 only: The activation has changed to a different top-level, unowned window. The wParam parameter contains the handle of the window.
HSHELL_WINDOWCREATED	A top-level, unowned window has been created. The window exists when the system calls a ShellProc function.
HSHELL_WINDOWDESTROYED	A top-level, unowned window is about to be destroyed. The window still exists when the system calls a ShellProc function.
If nCode is less than zero, the hook procedure must pass the message to the CallNextHookEx function without further processing and should return the value returned by CallNextHookEx.

wParam

Specifies additional information the shell application may require. If the nCode parameter is HSHELL_ACTIVATESHELLWINDOW, the wParam parameter is not used. If nCode is HSHELL_WINDOWCREATED or HSHELL_WINDOWDESTROYED, wParam specifies the handle of the window being created or destroyed, respectively.

lParam

Windows 95:

Specifies additional information. The exact value depends on the value of the nCode parameter. If nCode is HSHELL_GETMINRECT, lParam is LPRECT. If nCode is HSHELL_WINDOWSACTIVATED, lParam is fFullScreen. If nCode is HSHELL_REDRAW, lParam is fNewFlash.

Windows NT:

This parameter must be zero.

Return Value

The return value should be zero.

Remarks

An application installs the hook procedure by specifying the WH_SHELL hook type and the address of the hook procedure in a call to the SetWindowsHookEx function.

ShellProc is a placeholder for the application-defined or library-defined function name.

See Also

CallNextHookEx, SendMessage, SetWindowsHookEx


SHFileOperation [New - Windows 95]
SHFileOperation  QuickInfo

[New - Windows 95]

Performs a copy, move, rename, or delete operation on a file system object.

WINSHELLAPI int WINAPI SHFileOperation(

LPSHFILEOPSTRUCT  lpFileOp
);
Parameter

lpFileOp

Pointer to an SHFILEOPSTRUCT structure that contains information the function needs to carry out the operation.

Return Value

Returns zero if successful or nonzero if an error occurs.

See Also

SHFILEOPSTRUCT


SHFreeNameMappings [New - Windows 95]
SHFreeNameMappings  QuickInfo

[New - Windows 95]

Frees a filename mapping object that was retrieved by the SHFileOperation function.

WINSHELLAPI void WINAPI SHFreeNameMappings(;

HANDLE  hNameMappings
);
Parameter

hNameMappings

Handle of the filename mapping object to free.

Return Value

No return value.


SHGetDesktopFolder [New - Windows 95]
SHGetDesktopFolder  QuickInfo

[New - Windows 95]

Retrieves the IShellFolder interface for the desktop folder, which is the root of the shell's name space.

WINSHELLAPI HRESULT WINAPI SHGetDesktopFolder(

LPSHELLFOLDER * ppshf
);
Parameter

ppshf

Address that receives an IShellFolder interface pointer for the desktop folder. The calling application is responsible for eventually freeing the interface by calling its Release method.

Return Value

Returns NOERROR if successful or an OLE-defined error result otherwise.

See Also

IShellFolder


SHGetFileInfo [New - Windows 95]
SHGetFileInfo  QuickInfo

[New - Windows 95]

Retrieves information about an object in the file system, such as a file, a folder, a directory, or a drive root.

WINSHELLAPI DWORD WINAPI SHGetFileInfo(

LPCSTR  pszPath,
DWORD  dwFileAttributes,
SHFILEINFO FAR  *psfi,
UINT  cbFileInfo,
UINT  uFlags
);
Parameters

pszPath

Pointer to a buffer that contains the path and filename. Both absolute and relative paths are valid. If uFlags includes the SHGFI_PIDL, value pszPath must be the address of an ITEMIDLIST structure that contains the list of item identifiers that uniquely identifies the file within the shell's name space.

This string can use either short (the 8.3 form) or long filenames.

dwFileAttributes

Array of file attribute flags (FILE_ATTRIBUTE_ values). If uFlags does not include the SHGFI_USEFILEATTRIBUTES value, this parameter is ignored.

psfi and cbFileInfo

Address and size, in bytes, of the SHFILEINFO structure that receives the file information.

uFlags

Flag that specifies the file information to retrieve. This parameter can be a combination of the following values:

SHGFI_ATTRIBUTES	Retrieves the file attribute flags. The flags are copied to the dwAttributes member of the structure specified by psfi.
SHGFI_DISPLAYNAME	Retrieves the display name for the file. The name is copied to the szDisplayName member of the structure specified by psfi. The returned display name uses the long filename, if any, rather than the 8.3 form of the filename.
SHGFI_EXETYPE	Returns the type of the executable file if pszPath identifies an executable file. For more information, see the comments below.
SHGFI_ICON	Retrieves the handle of the icon that represents the file and the index of the icon within the system image list. The handle is copied to the hIcon member of the structure specified by psfi, and the index is copied to the iIcon member. The return value is the handle of the system image list.
SHGFI_ICONLOCATION	Retrieves the name of the file that contains the icon representing the file. The name is copied to the szDisplayName member of the structure specified by psfi.
SHGFI_LARGEICON	Modifies SHGFI_ICON, causing the function to retrieve the file's large icon.
SHGFI_LINKOVERLAY	Modifies SHGFI_ICON, causing the function to add the link overlay to the file's icon.
SHGFI_OPENICON	Modifies SHGFI_ICON, causing the function to retrieve the file's open icon. A container object displays an open icon to indicate that the container is open.
SHGFI_PIDL	Indicates that pszPath is the address of an ITEMIDLIST structure rather than a path name.
SHGFI_SELECTED	Modifies SHGFI_ICON, causing the function to blend the file's icon with the system highlight color.
SHGFI_SHELLICONSIZE	Modifies SHGFI_ICON, causing the function to retrieve a shell-sized icon. If this flag is not specified, the function sizes the icon according to the system metric values.
SHGFI_SMALLICON	Modifies SHGFI_ICON, causing the function to retrieve the file's small icon.
SHGFI_SYSICONINDEX	Retrieves the index of the icon within the system image list. The index is copied to the iIcon member of the structure specified by psfi. The return value is the handle of the system image list.
SHGFI_TYPENAME	Retrieves the string that describes the file's type. The string is copied to the szTypeName member of the structure specified by psfi.
SHGFI_USEFILEATTRIBUTES	Indicates that the function should use the dwFileAttributes parameter.
To retrieve the executable file type, uFlags must specify only SHGFI_EXETYPE. The return value specifies the type of the executable file:

0	Nonexecutable file or an error condition.
LOWORD = NE or PE HIWORD = 3.0, 3.5, or 4.0	Windows application
LOWORD = MZ HIWORD = 0	MS-DOS .EXE, .COM or .BAT file
LOWORD = PE HIWORD = 0	Win32 console application
Return Value

•	Returns a value whose meaning depends on the uFlags parameter. If uFlags specifies the SHGFI_EXETYPE value, the return value indicates the type of the executable file. For more information, see the comments below.

•	If uFlags includes the SHGFI_ICON or SHGFI_SYSICONINDEX value, the return value is the handle of the system image list that contains the large icon images. If the SHGFI_SMALLICON value is also included, the return value is the handle of the image list that contains the small icon images.

•	If uFlags does not include SHGFI_EXETYPE, SHGFI_ICON, SHGFI_SYSICONINDEX, or SHGFI_SMALLICON, the return value is nonzero the function succeeds, or zero otherwise.


SHGetInstanceExplorer [New - Windows 95]
SHGetInstanceExplorer  QuickInfo

[New - Windows 95]

Retreives the address of the Explorer's IUnknown interface.

WINSHELLAPI HRESULT WINAPI SHGetInstanceExplorer(

IUnknown  **ppunk
);
Parameter

ppunk

Pointer to a value that receives the address of the Explorer's IUnknown interface.

Return Value

Returns NOERROR if successful or E_FAIL otherwise.


SHGetNameMappingCount [New - Windows 95]
SHGetNameMappingCount  QuickInfo

[New - Windows 95]

Retrieves the number of SHNAMEMAPPING structures in a filename mapping object.

int SHGetNameMappingCount(

HANDLE  hNameMappings
);
Parameter

hNameMapping

Handle of a filename mapping object retrieved by the SHFileOperation function.

Return Value

Returns the number of SHNAMEMAPPING structures.

The SHGetNameMappingCount macro is defined as follows.

#define SHGetNameMappingCount(_hnm) \
    DSA_GetItemCount(_hnm)

See Also

SHFileOperation, SHNAMEMAPPING


SHGetNameMappingPtr [New - Windows 95]
SHGetNameMappingPtr  QuickInfo

[New - Windows 95]

Retrieves the address of a SHNAMEMAPPING structure contained in a file mapping object.

lpshnm = SHGetNameMappingPtr(

HANDLE  hNameMappings,
int  iItem
);
Parameters

hNameMapping

Handle of a filename mapping object retrieved by the SHFileOperation function.

iItem

Index of the SHNAMEMAPPING structure to be retrieved.

Return Value

Returns the address of the SHNAMEMAPPING structure specified by iItem.

The SHGetNameMappingPtr macro is defined as follows.

#define SHGetNameMappingPtr(_hnm, _iItem) \
    (LPSHNAMEMAPPING)DSA_GetItemPtr(_hnm, _iItem)

See Also

SHFileOperation, SHNAMEMAPPING


SHGetPathFromIDList [New - Windows 95]
SHGetPathFromIDList  QuickInfo

[New - Windows 95]

Converts an item identifier list to a file system path.

WINSHELLAPI BOOL WINAPI SHGetPathFromIDList(

LPCITEMIDLIST  pidl,
LPSTR  pszPath
);
Parameters

pidl

Pointer to an item identifier list that specifies a file or directory location relative to the root of the name space (the desktop).

pszPath

Pointer to a buffer that receives the file system path. The size of this buffer is assumed to be MAX_PATH bytes.

Return Value

Returns TRUE if successful or FALSE if an error occurs — for example, if the location specified by the pidl parameter is not part of the file system.


SHGetSpecialFolderLocation [New - Windows 95]
SHGetSpecialFolderLocation  QuickInfo

[New - Windows 95]

WINSHELLAPI HRESULT WINAPI SHGetSpecialFolderLocation(;

HWND  hwndOwner,
int  nFolder,
LPITEMIDLIST  * ppidl
);
Retrieves the location of a special folder.

Parameters

hwndOwner

Handle of the owner window that the client should specify if it displays a dialog box or message box.

nFolder

Value specifying the folder to retrieve the location of. This parameter can be one of the following values:

CSIDL_BITBUCKET	Recycle bin — file system directory containing file objects in the user's recycle bin. The location of this directory is not in the registry; it is marked with the hidden and system attributes to prevent the user from moving or deleting it.
CSIDL_CONTROLS	Control Panel — virtual folder containing icons for the control panel applications.
CSIDL_DESKTOP	Windows desktop — virtual folder at the root of the name space.
CSIDL_DESKTOPDIRECTORY	File system directory used to physically store file objects on the desktop (not to be confused with the desktop folder itself).
CSIDL_DRIVES	My Computer — virtual folder containing everything on the local computer: storage devices, printers, and Control Panel. The folder may also contain mapped network drives.
CSIDL_FONTS	Virtual folder containing fonts.
CSIDL_NETHOOD	File system directory containing objects that appear in the network neighborhood.
CSIDL_NETWORK	Network Neighborhood — virtual folder representing the top level of the network hierarchy.
CSIDL_PERSONAL	File system directory that serves as a common respository for documents.
CSIDL_PRINTERS	Printers folder — virtual folder containing installed printers.
CSIDL_PROGRAMS	File system directory that contains the user's program groups (which are also file system directories).
CSIDL_RECENT	File system directory that contains the user's most recently used documents.
CSIDL_SENDTO	File system directory that contains Send To menu items.
CSIDL_STARTMENU	File system directory containing Start menu items.
CSIDL_STARTUP	File system directory that corresponds to the user's Startup program group.
CSIDL_TEMPLATES	File system directory that serves as a common repository for document templates.
ppidl

Address that receives a pointer to an item identifier list specifying the folder's location relative to the root of the name space (the desktop).

Return Value

Returns NOERROR if successful or an OLE-defined error result otherwise.


SHLoadInProc [New - Windows 95]
SHLoadInProc  QuickInfo

[New - Windows 95]

Creates an instance of the specified object class from within the context of the shell's process.

WINSHELLAPI HRESULT WINAPI SHLoadInProc(

REFCLSID  rclsid
);
Parameter

rclsid

CLSID of the object class to be created.

Return Value

Returns NOERROR if successful or an OLE-defined error result otherwise.


ShowCaret
ShowCaret  QuickInfo  Overview  Group

The ShowCaret function makes the caret visible on the screen at the caret's current position. When the caret becomes visible, it begins flashing automatically.

BOOL ShowCaret(

HWND  hwnd	// handle of window with caret
);
Parameters

hwnd

Identifies the window that owns the caret. If this parameter is NULL, ShowCaret searches the current task for the window that owns the caret.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

ShowCaret shows the caret only if the specified window owns the caret, the caret has a shape, and the caret has not been hidden two or more times in a row. If one or more of these conditions is not met, ShowCaret does nothing and returns FALSE.

Hiding is cumulative. If your application calls HideCaret five times in a row, it must also call ShowCaret five times before the caret reappears.

The caret is a shared resource; there is only one caret in the system. A window should show a caret only when the window has the keyboard focus or is active.

See Also

CreateCaret, DestroyCaret, GetCaretPos, HideCaret, SetCaretPos


ShowCursor
ShowCursor  QuickInfo  Overview  Group

The ShowCursor function displays or hides the cursor.

int ShowCursor(

BOOL  bShow	// cursor visibility flag
);
Parameters

bShow

Specifies whether the internal display counter is to be incremented or decremented. If bShow is TRUE, the display count is incremented by one. If bShow is FALSE, the display count is decremented by one.

Return Value

The return value specifies the new display counter.

Remarks

This function sets an internal display counter that determines whether the cursor should be displayed. The cursor is displayed only if the display count is greater than or equal to 0. If a mouse is installed, the initial display count is 0. If no mouse is installed, the display count is −1.

See Also

ClipCursor, GetCursorPos, SetCursor, SetCursorPos


ShowHideMenuCtl [New - Windows NT]
ShowHideMenuCtl  QuickInfo  Overview  Group

[New - Windows NT]

The ShowHideMenuCtl function sets or removes the specified menu item's check-mark attribute, and shows or hides the corresponding control. The function adds a check mark to the specified menu item if it does not have one and then displays the corresponding control. If the menu item already has a check mark, the function removes the check mark and hides the corresponding control.

BOOL ShowHideMenuCtl(

HWND  hWnd,	// handle to MDI child window
UINT  uFlags,	// message
LPINT  lpInfo	// first message parameter
);
Parameters

hWnd

Handle to the window that contains the menu and controls.

uFlags

Identifier of the menu item to receive or lose a check mark.

lpInfo

Pointer to an array that contains pairs of values. The second value in the first pair must be the handle to the application's main menu. Each subsequent pair consists of a menu item identifier and a control window identifier. The function searches the array for a value that matches uFlags and, if the value is found, checks or unchecks the menu item and shows or hides the corresponding control.

Return Value

If the function shows or hides the control, the return value is TRUE.

If the function does not show or hide the control, the return value is FALSE.


ShowOwnedPopups
ShowOwnedPopups  QuickInfo  Overview  Group

The ShowOwnedPopups function shows or hides all pop-up windows owned by the specified window.

BOOL ShowOwnedPopups(

HWND  hwnd,	// handle of window
BOOL  fShow	// window visibility flag
);
Parameters

hwnd

Identifies the window that owns the pop-up windows to be shown or hidden.

fShow

Specifies whether pop-up windows are to be shown or hidden. If this parameter is TRUE, all hidden pop-up windows are shown. If this parameter is FALSE, all visible pop-up windows are hidden.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

ShowOwnedPopups shows only windows hidden by a previous call to ShowOwnedPopups. For example, if a pop-up window is hidden by using the ShowWindow function, subsequently calling ShowOwnedPopups with the fShow parameter set to TRUE does not cause the window to be shown.

See Also

IsWindowVisible, ShowWindow


ShowScrollBar
ShowScrollBar  QuickInfo  Overview  Group

The ShowScrollBar function shows or hides the specified scroll bar.

BOOL ShowScrollBar(

HWND  hwnd,	// handle of window with scroll bar
int  fnBar,	// scroll bar flag
BOOL  fShow	// scroll bar visibility flag
);
Parameters

hwnd

Identifies a scroll bar control or a window with a standard scroll bar, depending on the value of the fnBar parameter.

fnBar

Specifies the scroll bar(s) to be shown or hidden. This parameter can be one of the following values:

Value	Meaning
SB_BOTH	Shows or hides a window's standard horizontal and vertical scroll bars.
SB_CTL	Shows or hides a scroll bar control. The hwnd parameter must be the handle of the scroll bar control.
SB_HORZ	Shows or hides a window's standard horizontal scroll bars.
SB_VERT	Shows or hides a window's standard vertical scroll bar.
fShow

Specifies whether the scroll bar is shown or hidden. If this parameter is TRUE, the scroll bar is shown; otherwise, it is hidden.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

While processing a scroll bar message, an application should not call this function to hide a scroll bar.

See Also

GetScrollPos, GetScrollRange, ScrollDC, ScrollWindow, SetScrollPos, SetScrollRange


ShowWindow
ShowWindow  QuickInfo  Overview  Group

The ShowWindow function sets the specified window's show state.

BOOL ShowWindow(

HWND  hwnd,	// handle of window
int  nCmdShow	// show state of window
);
Parameters

hwnd

Identifies the window.

nCmdShow

Specifies how the window is to be shown. This parameter can be one of the following values:

Value	Meaning
SW_HIDE	Hides the window and activates another window.
SW_MAXIMIZE	Maximizes the specified window.
SW_MINIMIZE	Minimizes the specified window and activates the next top-level window in the Z order.
SW_RESTORE	Activates and displays the window. If the window is minimized or maximized, Windows restores it to its original size and position. An application should specify this flag when restoring a minimized window.
SW_SHOW	Activates the window and displays it in its current size and position.
SW_SHOWDEFAULT	Sets the show state based on the SW_ flag specified in the STARTUPINFO structure passed to the CreateProcess function by the program that started the application. An application should call ShowWindow with this flag to set the initial show state of its main window.
SW_SHOWMAXIMIZED	Activates the window and displays it as a maximized window.
SW_SHOWMINIMIZED	Activates the window and displays it as a minimized window.
SW_SHOWMINNOACTIVE	Displays the window as a minimized window. The active window remains active.
SW_SHOWNA	Displays the window in its current state. The active window remains active.
SW_SHOWNOACTIVATE	Displays a window in its most recent size and position. The active window remains active.
SW_SHOWNORMAL	Activates and displays a window. If the window is minimized or maximized, Windows restores it to its original size and position. An application should specify this flag when displaying the window for the first time.
Return Value

If the window was previously visible, the return value is TRUE. If the window was previously hidden, the return value is FALSE.

Remarks

ShowWindow must be called only once per program with the WinMain function's nCmdShow parameter. Subsequent calls to ShowWindow must use one of the values in the preceding list, instead of the one specified by the WinMain function's nCmdShow parameter.

As noted in the discussion of the nCmdShow parameter, an application should call ShowWindow with nCmdShow set to SW_SHOWDEFAULT to use application startup information that affects how a window is displayed. For example, Program Manager specifies that applications start with a minimized main window. Win32-based applications also use the application startup information when calling ShowWindow for the first time and set nCmdShow to SW_SHOW. This behavior is designed for the following situations:

•	Applications that create their main window by calling CreateWindow with the WS_VISIBLE flag set.

•	Applications that create their main window by calling CreateWindow with the WS_VISIBLE flag cleared, and later call ShowWindow with the SW_SHOW flag set to make it visible.

See Also

CreateProcess, CreateWindow, ShowOwnedPopups, STARTUPINFO, WinMain


ShowWindowAsync [New - Windows 95]
ShowWindowAsync  QuickInfo

[New - Windows 95]

The ShowWindowAsync function sets the show state of a window created by a different thread.

BOOL ShowWindowAsync(

HWND  hwnd,	// handle of window
int  nCmdShow	// show state of window
);
Parameters

hwnd

Identifies the window.

nCmdShow

Specifies how the window is to be shown. For a list of possible values, see the description of the ShowWindow function.

Return Value

If the window was previously visible, the return value is TRUE.

If the window was previously hidden, the return value is FALSE.

Remarks

This function posts a show-window event to the message queue of the given window. An application can use this function to avoid becoming hung while waiting for a hung application to finish processing a show-window event.

See Also

ShowWindow


shutdown
shutdown  QuickInfo

The Windows Sockets shutdown function disables send or receive operations on a socket.

int shutdown (

SOCKET s,
int how
);
Parameters

s

A descriptor identifying a socket.

how

A flag that describes what types of operation will no longer be allowed.

Return Value

If the function succeeds, shutdown returns zero.

If the function fails, a value of SOCKET_ERROR is returned. To get extended error information, call WSAGetLastError.

Error Codes

WSANOTINITIALISED	A successful WSAStartup must occur before using this function.
WSAENETDOWN	The Windows Sockets implementation has detected that the network subsystem has failed.
WSAEINVAL	The how parameter is not valid.
WSAEINPROGRESS	A blocking Windows Sockets operation is in progress.
WSAENOTCONN	The socket is not connected (SOCK_STREAM only).
WSAENOTSOCK	The descriptor is not a socket.
Remarks

The shutdown function is used on all types of sockets to disable reception, transmission, or both.

If how is zero, subsequent receives on the socket will be disallowed. This has no effect on the lower protocol layers. For TCP, the TCP window is not changed, and incoming data will be accepted (but not acknowledged) until the window is exhausted. For UDP, incoming datagrams are accepted and queued. In no case will an ICMP error packet be generated.

If how is 1, subsequent sends are disallowed. For TCP sockets, a FIN will be sent.

Setting how to 2 disables both sends and receives as described previously.

Note that shutdown does not close the socket, and resources attached to the socket will not be freed until closesocket is invoked.

The shutdown function does not block, regardless of the SO_LINGER setting on the socket.

An application should not rely on being able to reuse a socket after it has been shut down. In particular, a Windows Sockets implementation is not required to support the use of connect on such a socket.

See Also

closesocket, connect, socket, WSAStartup


SizeofResource
SizeofResource  QuickInfo  Overview  Group

The SizeofResource function returns the size, in bytes, of the specified resource.

DWORD SizeofResource(

HINSTANCE  hModule,	// resource-module handle
HRSRC  hrsrc	// resource handle
);
Parameters

hModule

Identifies the module whose executable file contains the resource.

hrsrc

Identifies the resource. This handle must be created by using the FindResource or FindResourceEx function.

Return Value

If the function succeeds, the return value is the number of bytes in the resource.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

The value returned may be larger than the actual resource because of alignment. An application should not rely upon this value for the exact size of a resource.

See Also

FindResource, FindResourceEx , LoadResource, LockResource


Sleep
Sleep  QuickInfo  Overview  Group

The Sleep function suspends the execution of the current thread for a specified interval.

VOID Sleep(

DWORD  cMilliseconds	// sleep time in milliseconds
);
Parameters

cMilliseconds

Specifies the time, in milliseconds, for which to suspend execution. A value of zero causes the thread to relinquish the remainder of its time slice to any other thread of equal priority that is ready to run. If there are no other threads of equal priority ready to run, the function returns immediately, and the thread continues execution. A value of INFINITE causes an infinite delay.

Return Value

This function does not return a value.

Remarks

A thread can relinquish the remainder of its time slice by calling this function with a sleep time of zero milliseconds.

See Also

SleepEx


SleepEx
SleepEx  QuickInfo  Overview  Group

The SleepEx function causes the current thread to enter a wait state until the specified interval of time has passed, or until an I/O completion callback function is called.

This function is available only in the Win32 API.

DWORD SleepEx(

DWORD  dwTimeout,	// time-out interval in milliseconds
BOOL  fAlertable	// early completion flag
);
Parameters

dwTimeout

Specifies the time, in milliseconds, that the delay is to occur. A value of zero causes the function to return immediately. A value of INFINITE causes an infinite delay.

fAlertable

Specifies whether the function may terminate early due to an I/O completion callback function. If fAlertable is FALSE, the function does not return until the time-out period has elapsed. If an I/O completion callback occurs, the function does not return and the I/O completion function is not executed.

If fAlertable is TRUE and the thread that called this function is the same thread that called the extended I/O function (ReadFileEx or WriteFileEx), the function returns when either the time-out period has elapsed or when an I/O completion callback function occurs. If an I/O completion callback occurs, the I/O completion function is executed.

Return Value

The return value is zero if the specified time interval expired.

The return value is WAIT_IO_COMPLETION if the function returned due to one or more I/O completion callback functions. This can happen only if fAlertable is TRUE, and if the thread that called the SleepEx function is the same thread that called the extended I/O function.

Remarks

This function can be used with the ReadFileEx or WriteFileEx functions to suspend a thread until an I/O operation has been completed. These functions specify a completion routine that is to be executed when the I/O operation has been completed. For the completion routine to be executed, the thread that called the I/O function must be in an alertable wait state when the completion callback function occurs. A thread goes into an alertable wait state by calling either SleepEx, WaitForSingleObjectEx, or WaitForMultipleObjectsEx with the function's fAlertable parameter set to TRUE.

A thread can relinquish the remainder of its time slice by calling this function with a sleep time of zero milliseconds.

See Also

ReadFileEx, Sleep, WaitForMultipleObjectsEx, WaitForSingleObjectEx, WriteFileEx


socket
socket  QuickInfo

TheWindows Sockets socket function creates a socket.

SOCKET socket (

int af,
int type,
int protocol
);
Parameters

af

An address format specification. The only format currently supported is PF_INET, which is the ARPA Internet address format.

type

A type specification for the new socket.

protocol

A particular protocol to be used with the socket, or zero if the caller does not wish to specify a protocol.

Return Value

If the function succeeds, socket returns a descriptor referencing the new socket.

If the function fails, a value of INVALID_SOCKET is returned. To get extended error information, call WSAGetLastError.

Error Codes

WSANOTINITIALISED	A successful WSAStartup must occur before using this function.
WSAENETDOWN	The Windows Sockets implementation has detected that the network subsystem has failed.
WSAEAFNOSUPPORT	The specified address family is not supported.
WSAEINPROGRESS	A blocking Windows Sockets operation is in progress.
WSAEMFILE	No more file descriptors are available.
WSAENOBUFS	No buffer space is available. The socket cannot be created.
WSAEPROTONOSUPPORT	The specified protocol is not supported.
WSAEPROTOTYPE	The specified protocol is the wrong type for this socket.
WSAESOCKTNOSUPPORT	The specified socket type is not supported in this address family.
Remarks

The socket function allocates a socket descriptor of the specified address family, data type and protocol, as well as related resources. If a protocol is not specified (that is, equal to zero), the default for the specified connection mode is used.

Only a single protocol exists to support a particular socket type using a given address format. However, the address family may be given as AF_UNSPEC (unspecified), in which case the protocol parameter must be specified. The protocol number to use is particular to the "communication domain" in which communication is to take place.

The following type specifications are supported:

Value	Meaning
SOCK_STREAM	Provides sequenced, reliable, two-way, connection-based byte streams with an out-of-band data transmission mechanism. Uses TCP for the Internet address family.
SOCK_DGRAM	Supports datagrams, which are connectionless, unreliable buffers of a fixed (typically small) maximum length. Uses UDP for the Internet address family.
Sockets of type SOCK_STREAM are full-duplex byte streams. A stream socket must be in a connected state before any data can be sent or received on it. A connection to another socket is created with a connect call. Once connected, data can be transferred using send and recv calls. When a session has been completed, a closesocket must be performed. Out-of-band data can also be transmitted as described in send and received as described in recv.

The communications protocols used to implement a SOCK_STREAM socket ensure that data is not lost or duplicated. If data for which the peer protocol has buffer space cannot be successfully transmitted within a reasonable length of time, the connection is considered broken and subsequent calls will fail with the error code set to WSAETIMEDOUT.

SOCK_DGRAM sockets allow sending and receiving of datagrams to and from arbitrary peers using sendto and recvfrom. If such a socket is connected to a specific peer, datagrams can be sent to that peer send and can be received from (only) this peer using recv.

See Also

accept, bind, closesocket, connect, getsockname, getsockopt, ioctlsocket, listen, recv, recvfrom, select, send, sendto, setsockopt, shutdown, WSAStartup


SoundSentryProc [New - Windows NT]
SoundSentryProc  QuickInfo

[New - Windows NT]

The SoundSentryProc function is a library-defined callback function that produces a customized visual signal when the SoundSentry accessibility feature is on and a Windows-based application (or a non-Windows-based application running in a window) generates a sound through the computer's built-in speaker.

LRESULT CALLBACK SoundSentryProc(

DWORD  dwMillisec,	// duration of visual signal
DWORD  fdwEffect	// effect-type flag
);
Parameters

dwMillisec

Specifies the duration, in milliseconds, of the visual signal that is displayed when a Windows-based application (or a non-Windows-based application running in a window) generates a sound.

fdwEffect

Specifies the type of visual signal to display. Currently, this value must always be SSWF_CUSTOM.

Return Value

If the visual signal was or will be displayed correctly, the return value is TRUE. If the signal is asynchronous and the status is not available when the function is called, it should return TRUE.

If an error prevented the signal from being displayed, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The library that contains the SoundSentryProc function must be a 32-bit DLL, and the DLL must export a function with the name "SoundSentryProc."

The SoundSentryProc function is called only after an application or library calls the SystemParametersInfo function, specifying the SPI_SETSOUNDSENTRY value and the address of a SOUNDSENTRY structure whose iWindowsEffect member is set to SSWF_CUSTOM.

See Also

SOUNDSENTRY, SystemParametersInfo


StartDoc
StartDoc  QuickInfo  Overview  Group

The StartDoc function starts a print job. This function replaces the STARTDOC printer escape.

int StartDoc(

HDC  hdc,	// handle of device context
CONST DOCINFO *  lpdi	// address of structure with file names
);
Parameters

hdc

Identifies the device context for the print job.

lpdi

Points to a DOCINFO structure containing the name of the document file and the name of the output file.

Return Value

If the function succeeds, the return value is greater than zero. This value is the print job identifier for the document.

If the function fails, the return value is less than or equal to zero. To get extended error information, call GetLastError.

Remarks

Applications should call the StartDoc function immediately before beginning a print job. Using this function ensures that multipage documents are not interspersed with other print jobs.

Applications can use the value returned by StartDoc to retrieve or set the priority of a print job. Call the GetJob or SetJob function and supply this value as one of the required arguments.

See Also

DOCINFO, EndDoc, GetJob, SetJob


StartDocPrinter
StartDocPrinter  QuickInfo  Overview  Group

The StartDocPrinter function informs the print spooler that a document is to be spooled for printing.

DWORD StartDocPrinter(

HANDLE  hPrinter,	// handle of printer object
DWORD  dwLevel,	// structure level
LPBYTE  lpbDocInfo	// address of structure
);
Parameters

hPrinter

Identifies the printer.

dwLevel

Specifies the version of the structure to which lpbDocInfo points. This value must be 1 for Windows NT. For Windows 95, you can also select a value of 2. (See DOC_INFO_2 following.)

lpbDocInfo

Points to a DOC_INFO_1 structure or a DOC_INFO_2 structure. If dwlevel is 1, the function stores the data in a DOC_INFO_1 structure. If dwlevel is 2, the function stores the data in a DOC_INFO_2 structure.

Windows 95 only: The DOC_INFO_2 structure has the following form:

typedef struct _DOC_INFO_2 { // dci2

    LPTSTR pDocName;

    LPTSTR pOutputFile;

    LPTSTR pDatatype;

    DWORD dwMode;

    DWORD JobId;

} DOC_INFO_2;

Return Value

If the function succeeds, the return value identifies the print job.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

The printer handle identified by the hPrinter parameter is obtained by calling the OpenPrinter function.

The return value will never be greater than 2^31 − 1.

See Also

DOC_INFO_1, OpenPrinter


StartPage
StartPage  QuickInfo  Overview  Group

The StartPage function prepares the printer driver to accept data.

int StartPage(

HDC  hDC	// handle of device context
);
Parameters

hDC

Identifies the device context for the print job.

Return Value

If the function succeeds, the return value is greater than zero.

If the function fails, the return value is less than or equal to zero. To get extended error information, call GetLastError.

Remarks

The system disables the ResetDC function between calls to the StartPage and EndPage functions. This means that an application cannot change the device mode except at page boundaries.

See Also

EndPage, ResetDC


StartPagePrinter
StartPagePrinter  QuickInfo  Overview  Group

The StartPagePrinter function informs the spooler that a page is about to be printed on the specified printer.

BOOL StartPagePrinter(

HANDLE  hPrinter	// handle of printer object
);
Parameters

hPrinter

Identifies a printer.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The printer handle identified by the hPrinter parameter is obtained by calling the OpenPrinter function.

When an application has finished writing a page, it should call the EndPagePrinter function to inform the spooler that the page is complete.

See Also

EndPagePrinter, OpenPrinter


StartService
StartService  QuickInfo  Overview  Group

The StartService function starts the execution of a service.

BOOL StartService(

SC_HANDLE  schService,	// handle of service
DWORD  dwNumServiceArgs,	// number of arguments
LPCTSTR  *lpszServiceArgs	// address of array of argument string pointers
);
Parameters

schService

Identifies the service. This handle is returned by the OpenService or CreateService function, and it must have SERVICE_START access.

dwNumServiceArgs

Specifies the number of argument strings in the lpszServiceArgs array. If lpszServiceArgs is NULL, this parameter can be zero.

lpszServiceArgs

Points to an array of pointers that point to null-terminated argument strings passed to a Win32 service. Driver services do not receive these arguments. If no arguments are passed to the service being started, this parameter can be NULL. The new service accesses these arguments through its ServiceMain function. Note that in the array of arguments passed to the ServiceMain function, the first argument (argv[0]) is the name of the service by default, followed by the arguments, if any, in the lpszServiceArgs array.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Errors

The following error codes can be set by the service control manager. Others can be set by the registry functions that are called by the service control manager.

Value	Meaning
ERROR_ACCESS_DENIED	The specified handle was not opened with SERVICE_START access.
ERROR_INVALID_HANDLE	The specified handle is invalid.
ERROR_PATH_NOT_FOUND	The service binary file could not be found.
ERROR_SERVICE_ALREADY_RUNNING	An instance of the service is already running.
ERROR_SERVICE_DATABASE_LOCKED	The database is locked.
ERROR_SERVICE_DEPENDENCY_DELETED	The service depends on a service that does not exist or has been marked for deletion.
ERROR_SERVICE_DEPENDENCY_FAIL	The service depends on another service that has failed to start.
ERROR_SERVICE_DISABLED	The service has been disabled.
ERROR_SERVICE_LOGON_FAILED	The service could not be logged on.
ERROR_SERVICE_MARKED_FOR_DELETE	The service has been marked for deletion.
ERROR_SERVICE_NO_THREAD	A thread could not be created for the Win32 service.
ERROR_SERVICE_REQUEST_TIMEOUT	The service did not respond to the start request in a timely fashion.
Remarks

When a driver service is started, the StartService function does not return until the device driver has finished initializing.

When a Win32 service is started, the service control manager spawns the service process, if necessary. If the specified service shares a process with other services, the required process may already exist. The StartService function does not wait for the first status update from the new service (which may take a while). Instead, it returns when the service control manager receives notification from the service control dispatcher that the ServiceMain thread for this service was created successfully.

For a Win32 service, the service control manager sets the following default status values before returning from StartService:

•	Current state of the service is set to SERVICE_START_PENDING.

•	Controls accepted is set to none (zero).

•	The CheckPoint value is set to zero.

•	The WaitHint time is set to 2 seconds.

The calling process can determine if the new service has finished its initialization by calling the QueryServiceStatus function periodically to query the service's status.

This function cannot be called from within a service.

See Also

ControlService, CreateService, OpenService, QueryServiceStatus, ServiceMain


StartServiceCtrlDispatcher
StartServiceCtrlDispatcher  QuickInfo  Overview  Group

The StartServiceCtrlDispatcher function connects the main thread of a service process to the service control manager, which causes the thread to be the service control dispatcher thread for the calling process.

BOOL StartServiceCtrlDispatcher(

LPSERVICE_TABLE_ENTRY  lpsteServiceTable	// address of service table
);
Parameters

lpsteServiceTable

Points to an array of SERVICE_TABLE_ENTRY structures containing one entry for each service that can execute in the calling process. The members of the last entry in the table must have NULL values to designate the end of the table.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Errors

The following error code can be set by the service control manager. Other error codes can be set by the registry functions that are called by the service control manager.

Value	Meaning
ERROR_INVALID_DATA	The specified dispatch table contains entries that are not in the proper format.
Remarks

When the service control manager starts a service process, it waits for the process to call the StartServiceCtrlDispatcher function. The main thread of a service process should make this call as soon as possible after it starts up. If StartServiceCtrlDispatcher succeeds, it connects the calling thread to the service control manager and does not return until all running services in the process have terminated. The service control manager uses this connection to send control and service start requests to the main thread of the service process. The main thread acts as a dispatcher by invoking the appropriate Handler function to handle control requests, or by creating a new thread to execute the appropriate ServiceMain function when a new service is started.

The lpsteServiceTable parameter contains an entry for each service that can run in the calling process. Each entry specifies the ServiceMain function for that service. For SERVICE_WIN32_SHARE_PROCESS services, each entry must contain the name of a service. This name is the service name that was specified by the CreateService function when the service was installed. For SERVICE_WIN32_OWN_PROCESS services, the service name in the table entry is ignored.

If a service runs in its own process, the main thread of the service process should immediately call StartServiceCtrlDispatcher. All initialization tasks are done in the service's ServiceMain function when the service is started.

If multiple services share a process and some common process-wide initialization needs to be done before any ServiceMain function is called, the main thread can do the work before calling StartServiceCtrlDispatcher, as long as it takes less than 30 seconds. Otherwise, another thread must be created to do the process-wide initialization, while the main thread calls StartServiceCtrlDispatcher and becomes the service control dispatcher. Any service-specific initialization should still be done in the individual service main functions.

See Also

ControlService, Handler, RegisterServiceCtrlHandler, ServiceMain, SERVICE_TABLE_ENTRY


StartSound

The StartSound function has been deleted.

See Also

Beep, MessageBeep


StopSound

The StopSound function has been deleted.

See Also

Beep, MessageBeep


StretchBlt
StretchBlt  QuickInfo  Overview  Group

The StretchBlt function copies a bitmap from a source rectangle into a destination rectangle, stretching or compressing the bitmap to fit the dimensions of the destination rectangle, if necessary. Windows stretches or compresses the bitmap according to the stretching mode currently set in the destination device context.

BOOL StretchBlt(

HDC  hdcDest,	// handle of destination device context
int  nXOriginDest,	// x-coordinate of upper-left corner of dest. rect.
int  nYOriginDest,	// y-coordinate of upper-left corner of dest. rect.
int  nWidthDest,	// width of destination rectangle
int  nHeightDest,	// height of destination rectangle
HDC  hdcSrc,	// handle of source device context
int  nXOriginSrc,	// x-coordinate of upper-left corner of source rectangle
int  nYOriginSrc,	// y-coordinate of upper-left corner of source rectangle
int  nWidthSrc,	// width of source rectangle
int  nHeightSrc,	// height of source rectangle
DWORD  dwRop	// raster operation code
);
Parameters

hdcDest

Identifies the destination device context.

nXOriginDest

Specifies the x-coordinate, in logical units, of the upper-left corner of the destination rectangle.

nYOriginDest

Specifies the y-coordinate, in logical units, of the upper-left corner of the destination rectangle.

nWidthDest

Specifies the width, in logical units, of the destination rectangle.

nHeightDest

Specifies the height, in logical units, of the destination rectangle.

hdcSrc

Identifies the source device context.

nXOriginSrc

Specifies the x-coordinate, in logical units, of the upper-left corner of the source rectangle.

nYOriginSrc

Specifies the y-coordinate, in logical units, of the upper-left corner of the source rectangle.

nWidthSrc

Specifies the width, in logical units, of the source rectangle.

nHeightSrc

Specifies the height, in logical units, of the source rectangle.

dwRop

Specifies the raster operation to be performed. Raster operation codes define how Windows combines colors in output operations that involve a brush, a source bitmap, and a destination bitmap.

See the BitBlt function for a list of common raster operation codes.

Return Value

If the function was successful, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

StretchBlt stretches or compresses the source bitmap in memory and then copies the result to the destination rectangle. The color data for pattern or destination pixels is merged after the stretching or compression occurs.

When an enhanced metafile is being recorded, an error occurs (and the function returns FALSE) if the source device context identifies an enhanced-metafile device context.

If the specified raster operation requires a brush, Windows uses the brush currently selected into the destination device context.

The destination coordinates are transformed by using the transformation currently specified for the destination device context; the source coordinates are transformed by using the transformation currently specified for the source device context.

If the source transformation has a rotation or shear, an error occurs.

If destination, source, and pattern bitmaps do not have the same color format, StretchBlt converts the source and pattern bitmaps to match the destination bitmap.

If StretchBlt must convert a monochrome bitmap to a color bitmap, it sets white bits (1) to the background color and black bits (0) to the foreground color. To convert a color bitmap to a monochrome bitmap, it sets pixels that match the background color to white (1) and sets all other pixels to black (0). The foreground and background colors of the device context with color are used.

StretchBlt creates a mirror image of a bitmap if the signs of the nWidthSrc and nWidthDest parameters or of the nHeightSrc and nHeightDest parameters differ. If nWidthSrc and nWidthDest have different signs, the function creates a mirror image of the bitmap along the x-axis. If nHeightSrc and nHeightDest have different signs, the function creates a mirror image of the bitmap along the y-axis.

Not all devices support the StretchBlt function. For more information, see the GetDeviceCaps function.

See Also

BitBlt, GetDeviceCaps, MaskBlt, PlgBlt, SetStretchBltMode


StretchDIBits
StretchDIBits  QuickInfo  Overview  Group

The StretchDIBits function copies the color data for a rectangle of pixels in a device-independent bitmap (DIB) to the specified destination rectangle. If the destination rectangle is larger than the source rectangle, this function stretches the rows and columns of color data to fit the destination rectangle. If the destination rectangle is smaller than the source rectangle, this function compresses the rows and columns by using the specified raster operation.

int StretchDIBits(

HDC  hdc,	// handle of device context
int  XDest,	// x-coordinate of upper-left corner of dest. rect.
int  YDest,	// y-coordinate of upper-left corner of dest. rect.
int  nDestWidth,	// width of destination rectangle
int  nDestHeight,	// height of destination rectangle
int  XSrc,	// x-coordinate of upper-left corner of source rect.
int  YSrc,	// y-coordinate of upper-left corner of source rect.
int  nSrcWidth,	// width of source rectangle
int  nSrcHeight,	// height of source rectangle
CONST VOID  *lpBits,	// address of bitmap bits
CONST BITMAPINFO *  lpBitsInfo,	// address of bitmap data
UINT  iUsage,	// usage
DWORD  dwRop	// raster operation code
);
Parameters

hdc

Identifies the destination device context.

XDest

Specifies the x-coordinate, in logical units, of the upper-left corner of the destination rectangle.

YDest

Specifies the y-coordinate, in logical units, of the upper-left corner of the destination rectangle.

nDestWidth

Specifies the width, in logical units, of the destination rectangle.

nDestHeight

Specifies the height, in logical units, of the destination rectangle.

XSrc

Specifies the x-coordinate, in pixels, of the source rectangle in the DIB.

YSrc

Specifies the y-coordinate, in pixels, of the source rectangle in the DIB.

nSrcWidth

Specifies the width, in pixels, of the source rectangle in the DIB.

nSrcHeight

Specifies the height, in pixels, of the source rectangle in the DIB.

lpBits

Points to the DIB bits, which are stored as an array of bytes.

lpBitsInfo

Points to a BITMAPINFO structure that contains information about the DIB.

iUsage

Specifies whether the bmiColors member of the BITMAPINFO structure was provided and, if so, whether bmiColors contains explicit red, green, blue (RGB) values or indices. The iUsage parameter must be one of the following values:

Value	Description
DIB_PAL_COLORS	The array contains 16-bit indices into the logical palette of the source device context.
DIB_RGB_COLORS	The color table contains literal RGB values.
dwRop

Specifies how the source pixels, the destination device context's current brush, and the destination pixels are to be combined to form the new image.

Return Value

If the function succeeds, the return value is the number of scan lines copied.

If the function fails, the return value is GDI_ERROR. To get extended error information, call GetLastError.

Remarks

The origin of a bottom-up DIB is the bottom-left corner; the origin of a top-down DIB is the upper-left corner.

StretchDIBits creates a mirror image of a bitmap if the signs of the nSrcWidth and nDestWidth parameters, or of the nSrcHeight and nDestHeight parameters differ. If nSrcWidth and nDestWidth have different signs, the function creates a mirror image of the bitmap along the x-axis. If nSrcHeight and nDestHeight have different signs, the function creates a mirror image of the bitmap along the y-axis.

See Also

SetMapMode, SetStretchBltMode, BITMAPINFO


StrokeAndFillPath
StrokeAndFillPath  QuickInfo  Overview  Group

The StrokeAndFillPath function closes any open figures in a path, strokes the outline of the path by using the current pen, and fills its interior by using the current brush.

BOOL StrokeAndFillPath(

HDC  hdc	// handle of device context
);
Parameters

hdc

Identifies the device context.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError. GetLastError may return one of the following error codes:

ERROR_CAN_NOT_COMPLETE
ERROR_INVALID_PARAMETER
ERROR_NOT_ENOUGH_MEMORY

Remarks

The device context identified by the hdc parameter must contain a closed path.

The StrokeAndFillPath function has the same effect as closing all the open figures in the path, and stroking and filling the path separately, except that the filled region will not overlap the stroked region even if the pen is wide.

See Also

BeginPath, FillPath, SetPolyFillMode, StrokePath


StrokePath
StrokePath  QuickInfo  Overview  Group

The StrokePath function renders the specified path by using the current pen.

BOOL StrokePath(

HDC  hdc	// handle of device context
);
Parameters

hdc

Identifies a device context that contains a closed path.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError. GetLastError may return one of the following error codes:

ERROR_CAN_NOT_COMPLETE
ERROR_INVALID_PARAMETER
ERROR_NOT_ENOUGH_MEMORY

Remarks

The device context identified by the hdc parameter must contain a closed path.

See Also

BeginPath, EndPath , ExtCreatePen


SubtractRect
SubtractRect  QuickInfo  Overview  Group

The SubtractRect function obtains the coordinates of a rectangle determined by subtracting one rectangle from another.

BOOL SubtractRect(

LPRECT  lprcDest,	// pointer to destination rectangle
CONST RECT *  lprcSrc1,	// pointer to rectangle to subtract from
CONST RECT *  lprcSrc2	// pointer to rectangle to subtract
);
Parameters

lprcDest

Points to a RECT structure that receives the coordinates of the rectangle determined by subtracting the rectangle pointed to by lprcSrc2 from the rectangle pointed to by lprcSrc1.

lprcSrc1

Points to a RECT structure from which the function subtracts the rectangle pointed to by lprcSrc2.

lprcSrc2

Points to a RECT structure that the function subtracts from the rectangle pointed to by lprcSrc1.

Return Value

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero.

Remarks

The function only subtracts the rectangle specified by lprcSrc2 from the rectangle specified by lprcSrc1 when the rectangles intersect completely in either the x- or y-direction. For example, if *lprcSrc1 has the coordinates (10,10,100,100) and *lprcSrc2 has the coordinates (50,50,150,150), the function sets the coordinates of the rectangle pointed to by lprcDest to (10,10,100,100). If *lprcSrc1 has the coordinates (10,10,100,100) and *lprcSrc2 has the coordinates (50,10,150,150), however, the function sets the coordinates of the rectangle pointed to by lprcDest to (10,10,50,100).

See Also

IntersectRect, RECT, UnionRect


SuspendThread
SuspendThread  QuickInfo  Overview  Group

The SuspendThread function suspends the specified thread.

DWORD SuspendThread(

HANDLE  hThread	// handle to the thread
);
Parameters

hThread

Identifies the thread. The handle must have THREAD_SUSPEND_RESUME access.

Return Value

If the function succeeds, the return value is the thread's previous suspend count; otherwise, it is 0xFFFFFFFF. To get extended error information, use the GetLastError function.

Remarks

If the function succeeds, execution of the specified thread is suspended and the thread's suspend count is incremented.

Suspending a thread causes the thread to stop executing user-mode (application) code.

Each thread has a suspend count (with a maximum value of MAXIMUM_SUSPEND_COUNT). If the suspend count is greater than zero, the thread is suspended; otherwise, the thread is not suspended and is eligible for execution. Calling SuspendThread causes the target thread's suspend count to be incremented. Attempting to increment past the maximum suspend count causes an error without incrementing the count.

The ResumeThread function decrements the suspend count of a suspended thread.

See Also

ResumeThread


SwapMouseButton
SwapMouseButton  QuickInfo  Overview  Group

The SwapMouseButton function reverses or restores the meaning of the left and right mouse buttons.

BOOL SwapMouseButton(

BOOL  fSwap	// reverse or restore buttons
);
Parameters

fSwap

Specifies whether the mouse button meanings are reversed or restored. If this parameter is TRUE, the left button generates right-button messages and the right button generates left-button messages. If this parameter is FALSE, the buttons are restored to their original meanings.

Return Value

If the meaning of the mouse buttons was reversed previously, before the function was called, the return value is TRUE.

If the meaning of the mouse buttons was not reversed, the return value is FALSE.

Remarks

Button swapping is provided as a convenience to people who use the mouse with their left hands. The SwapMouseButton function is usually called by Control Panel only. Although an application is free to call the function, the mouse is a shared resource and reversing the meaning of its buttons affects all applications.

See Also

SetDoubleClickTime


SwitchDesktop [New - Windows NT]
SwitchDesktop  QuickInfo  Overview  Group

[New - Windows NT]

The SwitchDesktop function makes a desktop visible and activates it. This enables the desktop to receive input from the user. The calling process must have DESKTOP_SWITCHDESKTOP access to the desktop for the SwitchDesktop function to succeed.

BOOL SwitchDesktop(

HDESK hDesk	// handle of desktop to activate
);
Parameters

hDesk

Identifies the desktop to be made visible and active. This handle is returned by the CreateDesktop and OpenDesktop functions.

The SwitchDesktop function will fail if the desktop belongs to an invisible window station.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

CreateDesktop, OpenDesktop


SwitchStackBack
SwitchStackBack  Overview  Group

The SwitchStackBack function is not implemented in the Win32 API. Win32-based applications should use the VirtualLock and VirtualUnlock functions.


SwitchStackTo
SwitchStackTo  Overview  Group

The SwitchStackTo function is not implemented in the Win32 API. Win32-based applications should use the VirtualLock and VirtualUnlock functions.


SyncAllVoices

The SyncAllVoices function has been deleted.

See Also

Beep, MessageBeep


SysMsgProc
SysMsgProc  QuickInfo  Overview  Group

The SysMsgProc hook procedure is a library-defined callback function the system calls after an input event occurs in a dialog box, message box, menu, or scroll bar, but before the message generated by the input event is processed. The hook procedure can monitor messages for any dialog box, message box, menu, or scroll bar in the system.

LRESULT CALLBACK SysMsgProc(

int  nCode,	// message flag
WPARAM  wParam,	// undefined
LPARAM  lParam	// address of structure with message data
);
Parameters

nCode

Specifies the type of input event that generated the message. This parameter can be one of the following values:

Value	Meaning
MSGF_DIALOGBOX	The input event occurred in a message box or dialog box.
MSGF_MENU	The input event occurred in a menu.
MSGF_SCROLLBAR	The input event occurred in a scroll bar.
MSGF_NEXTWINDOW	The input event occurred as a result of the user's pressing the ALT+TAB key combination to activate a different window.
If nCode is less than zero, the hook procedure must pass the message to the CallNextHookEx function without further processing and should return the value returned by CallNextHookEx.

wParam

Specifies a NULL value.

lParam

Points to an MSG message structure.

Return Value

If the hook procedure processes the message, the return value must be nonzero. Otherwise, it must be zero.

Remarks

An application installs the hook procedure by specifying the WH_SYSMSGFILTER hook type and the address of the hook procedure in a call to the SetWindowsHookEx function.

SysMsgProc is a placeholder for the library-defined function name.

See Also

CallNextHookEx, MSG, SetWindowsHookEx


SystemParametersInfo
SystemParametersInfo  QuickInfo  Overview  Group

The SystemParametersInfo function queries or sets systemwide parameters. This function can also update the user profile while setting a parameter.

BOOL SystemParametersInfo(

UINT  uiAction,	// system parameter to query or set
UINT  uiParam,	// depends on action to be taken
PVOID  pvParam,	// depends on action to be taken
UINT  fWinIni	// user profile update flag
);
Parameters

uiAction

Specifies the systemwide parameter to query or set. This parameter can be one of the following values:

Value	Meaning
SPI_GETACCESSTIMEOUT	Retrieves information about the time-out period associated with the accessibility features. The uiParam parameter specifies the size of an ACCESSTIMEOUT structure, and pvParam points to the ACCESSTIMEOUT structure that receives the information.
SPI_GETANIMATION	Windows 95 only: Retrieves the animation effects associated with user actions. The pvParam parameter is the pointer to an ANIMATIONINFO structure that contains the retrieved metrics.
SPI_GETBEEP	Determines whether the warning beeper is on (TRUE) or off (FALSE). The pvParam parameter points to a BOOL variable.
SPI_GETBORDER	Retrieves the border multiplier factor that determines the width of a window's sizing border. The pvParam parameter points to an integer variable.
SPI_GETDEFAULTINPUTLANG	Windows 95 only: Returns the keyboard layout handle for the system default input language. The uiParam is not used. The pvParam parameter points to the 32-bit variable that receives the keyboard layout handle for the default language.
SPI_GETDRAGFULLWINDOWS	Windows 95 only: Determines whether dragging of full windows is enabled. The pvParam parameter points to a BOOL variable that receives TRUE if enabled, or FALSE otherwise.
SPI_GETFASTTASKSWITCH	Determines whether fast task switching is enabled. The pvParam parameter points to a BOOL variable that receives TRUE if enabled, or FALSE otherwise.
SPI_GETFILTERKEYS	Retrieves information about the FilterKeys accessibility feature. The uiParam parameter specifies the size of the FILTERKEYS structure, and pvParam points to the FILTERKEYS structure that receives the information.
SPI_GETGRIDGRANULARITY	Retrieves the current granularity value of the desktop sizing grid. The pvParam parameter points to an integer variable that receives the granularity.
SPI_GETHIGHCONTRAST	Windows 95 only: Retrieves information about the HighContrast accessibility feature. The pvParam parameter is the pointer to the HIGHCONTRAST structure that receives the information.
SPI_GETICONMETRICS	Windows 95 only: Retrieves the metrics associated with icons. The pvParam parameter points to the ICONMETRICS structure to fill in.
SPI_GETICONTITLELOGFONT	Retrieves the logical font information for the current icon-title font. The uiParam parameter specifies the size of a LOGFONT structure, and the pvParam parameter points to the LOGFONT structure to fill in.
SPI_GETICONTITLEWRAP	Determines whether icon-title wrapping is enabled. The pvParam parameter points to a BOOL variable that receives TRUE if enabled, or FALSE otherwise.
SPI_GETKEYBOARDDELAY	Retrieves the keyboard repeat-delay setting. The pvParam parameter points to an integer variable that receives the setting.
SPI_GETKEYBOARDPREF	Windows 95 only: Determines whether the user relies on the keyboard instead of the mouse, and wants applications to display keyboard interfaces that would otherwise be hidden. The uiParam parameter points to a BOOL variable that receives TRUE if the user relies on the keyboard; the variable receives FALSE otherwise.
SPI_GETKEYBOARDSPEED	Retrieves the keyboard repeat-speed setting. The pvParam parameter points to a DWORD variable that receives the setting.
SPI_GETLOWPOWERACTIVE	Windows 95 only: Determines whether the low-power phase of screen saving is enabled or not. The pvParam parameter points to a BOOL variable that receives TRUE if enabled, or FALSE if disabled.
SPI_GETLOWPOWERTIMEOUT	Windows 95 only: Retrieves the time-out value for the low-power phase of screen saving. The pvParam parameter points to an integer value that receives the value.
SPI_GETMENUDROPALIGNMENT	Determines whether pop-up menus are left-aligned or right-aligned, relative to the corresponding menu-bar item. The pvParam parameter points to a BOOL variable that receives TRUE if left-aligned, or FALSE otherwise.
SPI_GETMINIMIZEDMETRICS	Windows 95 only: Retrieves the metrics associated with minimized windows. The uiParam parameter specifies the size of the MINIMIZEDMETRICS structure. The pvParam parameter points to the MINIMIZEDMETRICS structure to fill in.
SPI_GETMOUSE	Retrieves the two mouse threshold values and the mouse speed. The pvParam parameter points to an array of three integers that receives these values. See mouse_event for further information.
SPI_GETMOUSEKEYS	Retrieves information about the MouseKeys accessibility feature. The uiParam parameter specifies the size of a MOUSEKEYS structure, and pvParam points to the MOUSEKEYS structure that receives the information.
SPI_GETNONCLIENTMETRICS	Windows 95 only: Retrieves the metrics associated with the nonclient area of nonminimized windows. The pvParam parameter points to the NONCLIENTMETRICS structure to fill in.
SPI_GETPOWEROFFACTIVE	Windows 95 only: Determines whether the power-off phase of screen saving is enabled or not. The pvParam parameter points to a BOOL variable that receives TRUE if enabled, or FALSE if disabled.
SPI_GETPOWEROFFTIMEOUT	Windows 95 only: Retrieves the time-out value for the power-off phase of screen saving. The pvParam parameter points to an integer value that receives the value.
SPI_GETSCREENREADER	Windows 95 only: Determines whether a screen reviewer utility is running (TRUE) or not (FALSE). A screen reviewer utility directs textual information to an output device, such as a speech synthesizer or Braille display. When this flag is set, an application should provide textual information in situations where it would otherwise present the information graphically. The pvParam parameter points to a BOOL variable.
SPI_GETSCREENSAVEACTIVE	Determines whether screen saving is enabled. The pvParam parameter points to a BOOL variable that receives TRUE if enabled, or FALSE otherwise.
SPI_GETSCREENSAVETIMEOUT	Retrieves the screen saver time-out value, in seconds. The pvParam parameter points to an integer variable that receives the value.
SPI_GETSERIALKEYS	Windows 95 only: Retrieves information about the SerialKeys accessibility feature. The pvParam parameter points to the SERIALKEYS structure that receives the information.
SPI_GETSHOWSOUNDS	Determines whether the user requires an application to present information visually in situations where it would otherwise present the information only in audible form. The uiParam parameter points to a BOOL variable. Using this value is equivalent to calling GetSystemMetrics (SM_GETSHOWSOUNDS). That is the recommended call.
SPI_GETSOUNDSENTRY	Retrieves information about the SoundSentry accessibility feature. The uiParam parameter specifies the size of a SOUNDSENTRY structure, and pvParam points to the SOUNDSENTRY structure that receives the information.
SPI_GETSTICKYKEYS	Retrieves information about the MouseKeys accessibility feature. The uiParam parameter specifies the size of a STICKYKEYS structure, and pvParam points to the STICKYKEYS structure that receives the information.
SPI_GETTOGGLEKEYS	Retrieves information about the ToggleKeys accessibility feature. The uiParam parameter specifies the size of a TOGGLEKEYS structure, and pvParam points to the TOGGLEKEYS structure that receives the information.
SPI_GETWORKAREA	Windows 95 only: Retrieves the size of the working area. The working area is the portion of the screen not obscured by the tray. The pvParam parameter points to the RECT structure that receives the coordinates of the working area.
SPI_ICONHORIZONTALSPACING	Sets the width of an icon cell. The uiParam parameter specifies the width, in pixels.
SPI_ICONVERTICALSPACING	Sets the height of an icon cell. The uiParam parameter specifies the height, in pixels.
SPI_LANGDRIVER	Windows 95: Identifies the language driver. The pvParam parameter points to a character array that receives the filename of the language driver.
SPI_SETACCESSTIMEOUT	Sets the time-out period associated with the accessibility features. The uiParam parameter specifies the size of the ACCESSTIMEOUT structure, and pvParam points to the ACCESSTIMEOUT structure that contains the new parameters.
SPI_SETANIMATION	Windows 95 only: Sets the animation effects associated with user actions. The pvParam parameter points to an ANIMATIONINFO structure that contains the new metrics.
SPI_SETBEEP	Turns the warning beeper on or off. The uiParam parameter specifies TRUE for on, or FALSE for off.
SPI_SETBORDER	Sets the border multiplier factor that determines the width of a window's sizing border. The uiParam parameter specifies the new value.
SPI_SETDEFAULTINPUTLANG	Windows 95 only: Sets the default input language for the system shell and applications. The specified language must be displayable using the current system character set. The uiParam parameter is not used. The pvParam parameter points to a 32-bit variable that contains the keyboard layout handle for the default language.
SPI_SETDESKPATTERN	Sets the current desktop pattern by causing Windows to read the Pattern= setting from the WIN.INI file.
SPI_SETDESKWALLPAPER	Sets the desktop wallpaper. The pvParam parameter points to a null-terminated string containing the name of a bitmap file.
SPI_SETDOUBLECLICKTIME	Sets the double-click time for the mouse to the value of the uiParam parameter. The double-click time is the maximum number of milliseconds that can occur between the first and second clicks of a double-click.
SPI_SETDOUBLECLKHEIGHT	Sets the height of the double-click rectangle to the value of the uiParam parameter. The double-click rectangle is the rectangle within which the second click of a double-click must fall for it to be registered as a double-click.
SPI_SETDOUBLECLKWIDTH	Sets the width of the double-click rectangle to the value of the uiParam parameter. The double-click rectangle is the rectangle within which the second click of a double-click must fall for it to be registered as a double-click.
SPI_SETDRAGFULLWINDOWS	Windows 95 only: Sets dragging of full windows either on or off. The uiParam parameter specifies TRUE for on, or FALSE for off.
SPI_SETDRAGHEIGHT	Windows 95 only: Sets the height, in pixels, of the rectangle used to detect the start of a drag operation.
SPI_SETDRAGWIDTH	Windows 95 only: Sets the width, in pixels, of the rectangle used to detect the start of a drag operation.
SPI_SETFASTTASKSWITCH	Turns fast task switching on or off. The uiParam parameter specifies TRUE for on, or FALSE for off.
SPI_SETFILTERKEYS	Sets the parameters of the FilterKeys accessibility feature. The uiParam parameter specifies the size of the FILTERKEYS structure, and pvParam points to the FILTERKEYS structure that contains the new parameters.
SPI_SETGRIDGRANULARITY	Sets the granularity of the desktop sizing grid to the value of the uiParam parameter.
SPI_SETHIGHCONTRAST	Windows 95 only: Sets the parameters of the HighContrast accessibility feature. The pvParam parameter is the address of the HIGHCONTRAST structure that contains the new parameters.
SPI_SETICONMETRICS	Windows 95 only: Sets the metrics associated with icons. The pvParam parameter points to an ICONMETRICS structure that contains the new metrics.
SPI_SETICONTITLELOGFONT	Sets the font that is used for icon titles. The uiParam parameter specifies the size of a LOGFONT structure, and the lParam parameter points to a LOGFONT structure.
SPI_SETICONTITLEWRAP	Turns icon-title wrapping on or off. The uiParam parameter specifies TRUE for on, or FALSE for off.
SPI_SETKEYBOARDDELAY	Sets the keyboard repeat-delay setting to the value of the uiParam parameter.
SPI_SETKEYBOARDPREF	Windows 95 only: Sets the keyboard preference. The uiParam parameter specifies TRUE if the user relies on the keyboard instead of the mouse, and wants applications to display keyboard interfaces that would otherwise be hidden; uiParam is FALSE otherwise.
SPI_SETKEYBOARDSPEED	Sets the keyboard repeat-speed setting to the value of the uiParam parameter.
SPI_SETLANGTOGGLE	Windows 95 only: Sets the hot key set for switching between input languages. The uiParam and pvParam parameters are not used. The value sets the shortcut keys in the keyboard property sheets by reading the registry again. The registry must be set before this flag is used. the path in the registry is \HKEY_CURRENT_USER\keyboard layout\toggle. Valid values are "1" = ALT+SHIFT, "2" = CTRL+SHIFT, and "3" = none.
SPI_SETLOWPOWERACTIVE	Windows 95 only: Activates or deactivates the low-power phase of screen saving. Set uiParam to 1 to activate, or 0 to deactivate. The pvParam parameter must be NULL.
SPI_SETLOWPOWERTIMEOUT	Windows 95 only: Retrieves the time-out value, in seconds, for the low-power phase of screen saving. The uiParam parameter specifies the new value. The pvParam parameter must be NULL.
SPI_SETMENUDROPALIGNMENT	Sets the alignment value of pop-up menus. The uiParam parameter specifies TRUE for right alignment, or FALSE for left alignment.
SPI_SETMINIMIZEDMETRICS	Windows 95 only: Sets the metrics associated with minimized windows. The pvParam parameter points to a MINIMIZEDMETRICS structure that contains the new metrics.
SPI_SETMOUSE	Sets the two mouse threshold values and the mouse speed. The pvParam parameter points to an array of three integers that specifies these values. See mouse_event for further information.
SPI_SETMOUSEBUTTONSWAP	Swaps or restores the meaning of the left and right mouse buttons. The uiParam parameter specifies TRUE to swap the meanings of the buttons, or FALSE to to restore their original meanings.
SPI_SETMOUSEKEYS	Sets the parameters of the MouseKeys accessibility feature. The uiParam parameter specifies the size of the MOUSEKEYS structure, and pvParam points to the MOUSEKEYS structure that contains the new parameters.
SPI_SETNONCLIENTMETRICS	Windows 95 only: Sets the metrics associated with the nonclient area of nonminimized windows. The pvParam parameter is the address of a NONCLIENTMETRICS structure that contains the new metrics.
SPI_SETPENWINDOWS	Windows 95 only: Specifies that pen windows is being loaded or unloaded. The uiParam parameter is TRUE when loading and FALSE when unloading pen windows. The lParam parameter is NULL.
SPI_SETPOWEROFFACTIVE	Windows 95 only: Activates or deactivates the  power-off phase of screen saving. Set uiParam to 1 to activate, or 0 to deactivate. The pvParam parameter must be NULL.
SPI_SETPOWEROFFTIMEOUT	Windows 95 only: Retrieves the time-out value, in seconds, for the power-off phase of screen saving. The uiParam parameter specifies the new value. The pvParam parameter must be NULL.
SPI_SETSCREENREADER	Windows 95 only: Indicates whether a screen review utility is running. The uiParam parameter specifies TRUE for on, or FALSE for off.
SPI_SETSCREENSAVEACTIVE	Sets the state of the screen saver. The uiParam parameter specifies TRUE to activate screen saving, or FALSE to deactivate it.
SPI_SETSCREENSAVETIMEOUT	Sets the screen saver time-out value to the value of the uiParam parameter. This value is the amount of time, in seconds, that the system must be idle before the screen saver activates.
SPI_SETSERIALKEYS	Windows 95 only: Sets the parameters of the SerialKeys accessibility feature. The pvParam parameter is the address of the SERIALKEYS structure that contains the new parameters.
SPI_SETSHOWSOUNDS	Sets the ShowSounds accessibility feature as on or off. The uiParam parameter specifies TRUE for on, or FALSE for off.
SPI_SETSOUNDSENTRY	Sets the parameters of the SoundSentry accessibility feature. The uiParam parameter specifies the size of the SOUNDSENTRY structure, and pvParam points to the SOUNDSENTRY structure that contains the new parameters.
SPI_SETSTICKYKEYS	Sets the parameters of the StickyKeys accessibility feature. The uiParam parameter specifies the size of the STICKYKEYS structure, and pvParam points to the STICKYKEYS structure that contains the new parameters.
SPI_SETTOGGLEKEYS	Sets the parameters of the ToggleKeys accessibility feature. The uiParam parameter specifies the size of the TOGGLEKEYS structure, and pvParam points to the TOGGLEKEYS structure that contains the new parameters.
SPI_SETWORKAREA	Windows 95 only: Sets the size of the working area. The working area is the portion of the screen not obscured by the tray. The pvParam parameter points to the RECT structure that contains the coordinates of the working area.
uiParam

Depends on the system parameter being queried or set. For more information about systemwide parameters, see the uiAction parameter. If not otherwise indicated, specify zero.

pvParam

Depends on the system parameter being queried or set. For more information about systemwide parameters, see the uiAction parameter. If not otherwise indicated, specify zero.

fWinIni

If a system parameter is being set, specifies whether the user profile is to be updated, and if so, whether the WM_WININICHANGE message is to be broadcast to all top-level windows to notify them of the change. This parameter can be zero or can be one of the following values:

Value	Action
SPIF_UPDATEINIFILE	Writes the new system-wide parameter setting to the user profile.
SPIF_SENDWININICHANGE	Broadcasts the WM_WININICHANGE message after updating the user profile.
Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

This function is intended for use with applications, such as Control Panel, that allow the user to customize the Windows environment.

A keyboard layout name should be derived from the hexadecimal value of the language identifier corresponding to the layout. For example, U.S. English has a language identifier of 0x0409, so the primary U.S. English layout is named "00000409." Variants of U.S. English layout, such as the Dvorak layout, are named "00010409," "00020409" and so on. For a list of the primary language identifiers and sublanguage identifiers that make up a language identifier, see the MAKELANGID macro.

See Also

ACCESSTIMEOUT, ANIMATIONINFO, FILTERKEYS, GetLastError, GetSystemMetrics, HIGHCONTRAST, ICONMETRICS, LOGFONT, MAKELANGID, MINIMIZEDMETRICS, mouse_event, MOUSEKEYS, NONCLIENTMETRICS, RECT, SERIALKEYS, SOUNDSENTRY, STICKYKEYS, TOGGLEKEYS, WM_WININICHANGE


SystemTimeToFileTime
SystemTimeToFileTime  QuickInfo  Overview  Group

The SystemTimeToFileTime function converts a system time to a file time.

BOOL SystemTimeToFileTime(

CONST SYSTEMTIME *  lpst,	// address of system time to convert
LPFILETIME  lpft	// address of buffer for converted file time
);
Parameters

lpst

Points to a SYSTEMTIME structure that contains the time to be converted.

The wDayOfWeek member of the SYSTEMTIME structure is ignored.

lpft

Points to a FILETIME structure to receive the converted system time.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

DosDateTimeToFileTime, FILETIME, FileTimeToDosDateTime, FileTimeToSystemTime, SYSTEMTIME


SystemTimeToTzSpecificLocalTime
SystemTimeToTzSpecificLocalTime  QuickInfo  Overview  Group

The SystemTimeToTzSpecificLocalTime function converts a Coordinated Universal Time (UTC) to a specified time zone's corresponding local time.

BOOL SystemTimeToTzSpecificLocalTime (

LPTIME_ZONE_INFORMATION  lpTimeZoneInformation,	// pointer to time zone of interest
LPSYSTEMTIME  lpUniversalTime,	// pointer to universal time of interest
LPSYSTEMTIME  lpLocalTime	// pointer to structure to receive local time
);
Parameters

lpTimeZoneInformation

Pointer to a TIME_ZONE_INFORMATION structure that specifies the time zone of interest.

If lpTimeZoneInformation is NULL, the function uses the currently active time zone.

lpUniversalTime

Pointer to a SYSTEMTIME structure that specifies a UTC. The function converts this universal time to the specified time zone's corresponding local time.

lpLocalTime

Pointer to a SYSTEMTIME structure that receives the local time information.

Return Value

If the function succeeds, the return value is TRUE, and the function sets the members of the SYSTEMTIME structure pointed to by lpLocalTime to the appropriate local time values.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The SystemTimeToTzSpecificLocalTime function works in Windows NT. If called in Windows 95, the function fails, and returns FALSE.

See Also

GetSystemTime, GetTimeZoneInformation, SYSTEMTIME, TIME_ZONE_INFORMATION


TabbedTextOut
TabbedTextOut  QuickInfo  Overview  Group

The TabbedTextOut function writes a character string at a specified location, expanding tabs to the values specified in an array of tab-stop positions. Text is written in the currently selected font.

LONG TabbedTextOut(

HDC  hdc,	// handle of device context
int  x,	// x-coordinate of starting position
int  y,	// y-coordinate of starting position
LPCTSTR  lpString,	// address of string
int  nCount,	// number of characters in string
int  nTabPositions,	// number of tabs in array
LPINT  lpnTabStopPositions,	// address of array for tab positions
int  nTabOrigin	// x-coordinate for tab expansion
);
Parameters

hdc

Identifies the device context.

x

Specifies the x-coordinate of the starting point of the string, in logical units.

y

Specifies the y-coordinate of the starting point of the string, in logical units.

lpString

Points to the character string to draw. The string does not need to be zero-terminated, since nCount specifies the length of the string.

nCount

Specifies the number of characters in the string.

nTabPositions

Specifies the number of values in the array of tab-stop positions.

lpnTabStopPositions

Points to an array containing the tab-stop positions, in device units. The tab stops must be sorted in increasing order; the smallest x-value should be the first item in the array.

Windows 95 only: A tab stop can be specified as a negative value, which causes text to be right-aligned on the tab stop rather than left-aligned.

nTabOrigin

Specifies the x-coordinate of the starting position from which tabs are expanded, in logical units.

Return Value

If the function succeeds, the return value is the dimensions, in logical units, of the string. The height is in the high-order word and the width is in the low-order word.

Remarks

If the nTabPositions parameter is zero and the lpnTabStopPositions parameter is NULL, tabs are expanded to eight times the average character width.

If nTabPositions is 1, the tab stops are separated by the distance specified by the first value in the lpnTabStopPositions array.

If the lpnTabStopPositions array contains more than one value, a tab stop is set for each value in the array, up to the number specified by nTabPositions.

The nTabOrigin parameter allows an application to call the TabbedTextOut function several times for a single line. If the application calls TabbedTextOut more than once with the nTabOrigin set to the same value each time, the function expands all tabs relative to the position specified by nTabOrigin.

By default, the current position is not used or updated by the TabbedTextOut function. If an application needs to update the current position when it calls TabbedTextOut, the application can call the SetTextAlign function with the wFlags parameter set to TA_UPDATECP. When this flag is set, Windows ignores the x and y parameters on subsequent calls to the TabbedTextOut function, using the current position instead.

See Also

DrawText, GetTabbedTextExtent, GrayString, SetTextAlign, TextOut


TerminateProcess
TerminateProcess  QuickInfo  Overview  Group

The TerminateProcess function terminates the specified process and all of its threads.

BOOL TerminateProcess(

HANDLE  hProcess,	// handle to the process
UINT  uExitCode	// exit code for the process
);
Parameters

hProcess

Identifies the process to terminate. The handle must have PROCESS_TERMINATE access.

uExitCode

Specifies the exit code for the process and for all threads terminated as a result of this call. Use the GetExitCodeProcess function to retrieve the process's exit value. Use the GetExitCodeThread function to retrieve a thread's exit value.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The TerminateProcess function is used to unconditionally cause a process to exit. Use it only in extreme circumstances. The state of global data maintained by dynamic-link libraries (DLLs) may be compromised if TerminateProcess is used rather than ExitProcess.

TerminateProcess causes all threads within a process to terminate, and causes a process to exit, but DLLs attached to the process are not notified that the process is terminating.

Terminating a process causes the following:

1.	All of the object handles opened by the process are closed.

2.	All of the threads in the process terminate their execution.

3.	The state of the process object becomes signaled, satisfying any threads that had been waiting for the process to terminate.

4.	The states of all threads of the process become signaled, satisfying any threads that had been waiting for the threads to terminate.

5.	The termination status of the process changes from STILL_ACTIVE to the exit value of the process.

Terminating a process does not cause child processes to be terminated.

Terminating a process does not necessarily remove the process object from the system. A process object is deleted when the last handle to the process is closed.

See Also

ExitProcess, OpenProcess, GetExitCodeProcess, GetExitCodeThread,


TerminateThread
TerminateThread  QuickInfo  Overview  Group

The TerminateThread function terminates a thread.

BOOL TerminateThread(

HANDLE  hThread,	// handle to the thread
DWORD  dwExitCode	// exit code for the thread
);
Parameters

hThread

Identifies the thread to terminate. The handle must have THREAD_TERMINATE access.

dwExitCode

Specifies the exit code for the thread. Use the GetExitCodeThread function to retrieve a thread's exit value.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

TerminateThread is used to cause a thread to exit. When this occurs, the target thread has no chance to execute any user-mode code and its initial stack is not deallocated. DLLs attached to the thread are not notified that the thread is terminating.

TerminateThread is a dangerous function that should only be used in the most extreme cases. You should call TerminateThread only if you know exactly what the target thread is doing, and you control all of the code that the target thread could possibly be running at the time of the termination. For example, TerminateThread can result in the following problems:

•	If the target thread owns a critical section, the critical section will not be released.

•	If the target thread is executing certain kernel32 calls when it is terminated, the kernel32 state for the thread's process could be inconsistent.

•	If the target thread is manipulating the global state of a shared DLL, the state of the DLL could be destroyed, affecting other users of the DLL.

A thread cannot protect itself against TerminateThread, other than by controlling access to its handles. The thread handle returned by the CreateThread and CreateProcess functions has THREAD_TERMINATE access, so any caller holding one of these handles can terminate your thread.

If the target thread is the last thread of a process when this function is called, the thread's process is also terminated.

The state of the thread object becomes signaled, releasing any other threads that had been waiting for the thread to terminate. The thread's termination status changes from STILL_ACTIVE to the value of the dwExitCode parameter.

Terminating a thread does not necessarily remove the thread object from the system. A thread object is deleted when the last thread handle is closed.

See Also

CreateProcess, CreateThread, ExitThread, GetExitCodeThread


TextOut
TextOut  QuickInfo  Overview  Group

The TextOut function writes a character string at the specified location, using the currently selected font.

BOOL TextOut(

HDC  hdc,	// handle of device context
int  nXStart,	// x-coordinate of starting position
int  nYStart,	// y-coordinate of starting position
LPCTSTR  lpString,	// address of string
int  cbString	// number of characters in string
);
Parameters

hdc

Identifies the device context.

nXStart

Specifies the logical x-coordinate of the reference point that Windows uses to align the string.

nYStart

Specifies the logical y-coordinate of the reference point that Windows uses to align the string.

lpString

Points to the string to be drawn. The string does not need to be zero-terminated, since cbString specifies the length of the string.

cbString

Specifies the number of characters in the string.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The interpretation of the reference point depends on the current text-alignment mode. An application can retrieve this mode by calling the GetTextAlign function; an application can alter this mode by calling the SetTextAlign function.

By default, the current position is not used or updated by this function. However, an application can call the SetTextAlign function with the fMode parameter set to TA_UPDATECP to permit Windows to use and update the current position each time the application calls TextOut for a specified device context. When this flag is set, Windows ignores the nXStart and nYStart parameters on subsequent TextOut calls.

When the TextOut function is placed inside a path bracket, the system generates a path for the TrueType text that includes each character plus its character box. The region generated is the character box minus the text, rather than the text itself. You can obtain the region enclosed by the outline of the TrueType text by setting the background mode to transparent before placing the TextOut function in the path bracket. Following is sample code that demonstrates this procedure.

// Obtain the window's client rectangle

GetClientRect(hwnd, &r);

// THE FIX: by setting the background mode

// to transparent, the region is the text itself

// SetBkMode(hdc, TRANSPARENT);

// Bracket begin a path

BeginPath(hdc);

// Send some text out into the world

TextOut(hdc, r.left, r.top, "Defenestration can be hazardous", 4);

// Bracket end a path

EndPath(hdc);

// Derive a region from that path

SelectClipPath(hdc, RGN_AND);

// This generates the same result as SelectClipPath()

// SelectClipRgn(hdc, PathToRegion(hdc));

// Fill the region with grayness

FillRect(hdc, &r, GetStockObject(GRAY_BRUSH));

See Also

GetTextAlign, SetTextAlign, TabbedTextOut


Throw
Throw  Overview  Group

The Throw function is not implemented in the Win32 API.

Structured exception handling is built into the Win32 application programming interface. For more information about structured exception handling, see Structured Exception Handling.


TileWindows [New - Windows 95]
TileWindows  QuickInfo

[New - Windows 95]

The TileWindows function tiles the specified windows, or the child windows of the specified parent window.

WORD WINAPI TileWindows(

HWND hwndParent,	// handle of parent window
WORD wFlags,	// types of windows not to arrange
LPCRECT lpRect,	// rectangle to arrange windows in
WORD cChildrenb,	// number of windows to arrange
const HWND FAR *ahwndChildren	// array of window handles
);
Parameters

hwndParent

Identifies the parent window. If this parameter is NULL, the desktop window is assumed.

wFlags

Specifies the types of windows not to arrange, and whether to tile vertically or horizontally. This parameter can be one of the following values combined with zero or more of the values listed with the CascadeWindows function:

Value	Meaning
MDITILE_HORIZONTAL	Tiles windows horizontally.
MDITILE_VERTICAL	Tiles windows vertically.
lpRect

Points to a SMALL_RECT structure that specifies the rectangular area, in screen coordinates, within which the windows are arranged. If this parameter is NULL, the client area of the parent window is used.

cChildren

Specifies the number of elements in the array specified by the ahwndChildren parameter. This parameter is ignored if ahwndChildren is NULL.

ahwndChildren

Points to an array of window handles identifying the windows to arrange. If this parameter is NULL, the child windows of the specified parent window (or of the desktop window) are arranged.

Return Value

If the function succeeds, the return value is the number of windows arranged.

If the function fails, the return value is zero.

See Also

CascadeWindows, SMALL_RECT


TimerProc
TimerProc  QuickInfo  Overview  Group

The TimerProc function is an application-defined callback function that processes WM_TIMER messages.

VOID CALLBACK TimerProc(

HWND  hwnd,	// handle of window for timer messages
UINT  uMsg,	// WM_TIMER message
UINT  idEvent,	// timer identifier
DWORD  dwTime	// current system time
);
Parameters

hwnd

Identifies the window associated with the timer.

uMsg

Specifies the WM_TIMER message.

idEvent

Specifies the timer's identifier.

dwTime

Specifies the system time, in Coordinated Universal Time (UTC) format.

Return Value

This function does not return a value.

Remarks

TimerProc is a placeholder for the application-defined function name.

See Also

KillTimer, SetTimer, WM_TIMER


TlsAlloc
TlsAlloc  QuickInfo  Overview  Group

The TlsAlloc function allocates a thread local storage (TLS) index. Any thread of the process can subsequently use this index to store and retrieve values that are local to the thread.

DWORD TlsAlloc(VOID)

Parameters

This function has no parameters.

Return Value

If the function succeeds, the return value is a TLS index.

If the function fails, the return value is 0xFFFFFFFF. To get extended error information, call GetLastError.

Remarks

The threads of the process can use the TLS index in subsequent calls to the TlsFree, TlsSetValue, or TlsGetValue functions.

TLS indexes are typically allocated during process or dynamic-link library (DLL) initialization. Once allocated, each thread of the process can use a TLS index to access its own TLS storage slot. To store a value in its slot, a thread specifies the index in a call to TlsSetValue. The thread specifies the same index in a subsequent call to TlsGetValue, to retrieve the stored value.

The constant TLS_MINIMUM_AVAILABLE defines the minimum number of TLS indexes available in each process. This minimum is guaranteed to be at least 64 for all systems.

TLS indexes are not valid across process boundaries. A DLL cannot assume that an index assigned in one process is valid in another process.

A DLL might use TlsAlloc, TlsSetValue, TlsGetValue, and TlsFree as follows:

1.	When a DLL attaches to a process, the DLL uses TlsAlloc to allocate a TLS index. The DLL then allocates some dynamic storage and uses the TLS index in a call to TlsSetValue to store the address in the TLS slot. This concludes the per-thread initialization for the initial thread of the process. The TLS index is stored in a global or static variable of the DLL.

2.	Each time the DLL attaches to a new thread of the process, the DLL allocates some dynamic storage for the new thread and uses the TLS index in a call to TlsSetValue to store the address in the TLS slot. This concludes the per-thread initialization for the new thread.

3.	Each time an initialized thread makes a DLL call requiring the data in its dynamic storage, the DLL uses the TLS index in a call to TlsGetValue to retrieve the address of the dynamic storage for that thread.

For additional information on thread local storage, see Thread Local Storage.

See Also

TlsFree, TlsGetValue, TlsSetValue


TlsFree
TlsFree  QuickInfo  Overview  Group

The TlsFree function releases a thread local storage (TLS) index, making it available for reuse.

BOOL TlsFree(

DWORD  dwTlsIndex	// TLS index to free
);
Parameters

dwTlsIndex

Specifies a TLS index that was allocated by the TlsAlloc function.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

If the threads of the process have allocated dynamic storage and used the TLS index to store pointers to this storage, they should free the storage before calling TlsFree. The TlsFree function does not free any dynamic storage that has been associated with the TLS index. It is expected that DLLs call this function (if at all) only during their process detach routine.

For a brief discussion of typical uses of the TLS functions, see the Remarks section of the TlsAlloc function.

See Also

TlsAlloc, TlsGetValue, TlsSetValue


TlsGetValue
TlsGetValue  QuickInfo  Overview  Group

The TlsGetValue function retrieves the value in the calling thread's thread local storage (TLS) slot for a specified TLS index. Each thread of a process has its own slot for each TLS index.

LPVOID TlsGetValue(

DWORD  dwTlsIndex	// TLS index to retrieve value for
);
Parameters

dwTlsIndex

Specifies a TLS index that was allocated by the TlsAlloc function.

Return Value

If the function succeeds, the return value is the value stored in the calling thread's TLS slot associated with the specified index.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Note that the data stored in a TLS slot can have a value of zero. In this case, the return value is zero and GetLastError returns NO_ERROR.

Remarks

TLS indexes are typically allocated by the TlsAlloc function during process or DLL initialization. Once allocated, each thread of the process can use a TLS index to access its own TLS storage slot for that index. The storage slot for each thread is initialized to NULL. A thread specifies a TLS index in a call to TlsSetValue, to store a value in its slot. The thread specifies the same index in a subsequent call to TlsGetValue, to retrieve the stored value.

TlsSetValue and TlsGetValue were implemented with speed as the primary goal. These functions perform minimal parameter validation and error checking. In particular, this function succeeds if dwTlsIndex is in the range 0 through (TLS_MINIMUM_AVAILABLE − 1). It is up to the programmer to ensure that the index is valid.

Win32 functions that return indications of failure call SetLastError when they fail. They generally do not call SetLastError when they succeed. The TlsGetValue function is an exception to this general rule. The TlsGetValue function calls SetLastError to clear a thread's last error when it succeeds. That allows checking for the error-free retrieval of NULL values.

See Also

GetLastError, SetLastError, TlsAlloc, TlsFree, TlsSetValue


TlsSetValue
TlsSetValue  QuickInfo  Overview  Group

The TlsSetValue function stores a value in the calling thread's thread local storage (TLS) slot for a specified TLS index. Each thread of a process has its own slot for each TLS index.

BOOL TlsSetValue(

DWORD  dwTlsIndex,	// TLS index to set value for
LPVOID  lpvTlsValue	// value to be stored
);
Parameters

dwTlsIndex

Specifies a TLS index that was allocated by the TlsAlloc function.

lpvTlsValue

Specifies the value to be stored in the calling thread's TLS slot specified by dwTlsIndex.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

TLS indexes are typically allocated by the TlsAlloc function during process or DLL initialization. Once allocated, each thread of the process can use a TLS index to access its own TLS storage slot for that index. The storage slot for each thread is initialized to NULL. A thread specifies a TLS index in a call to TlsSetValue, to store a value in its slot. The thread specifies the same index in a subsequent call to TlsGetValue, to retrieve the stored value.

TlsSetValue and TlsGetValue were implemented with speed as the primary goal. These functions perform minimal parameter validation and error checking. In particular, this function succeeds if dwTlsIndex is in the range 0 through (TLS_MINIMUM_AVAILABLE − 1). It is up to the programmer to ensure that the index is valid.

See Also

TlsAlloc, TlsFree, TlsGetValue


ToAscii
ToAscii  QuickInfo  Overview  Group

The ToAscii function translates the specified virtual-key code and keyboard state to the corresponding Windows character or characters.

int ToAscii(

UINT  uVirtKey,	// virtual-key code
UINT  uScanCode,	// scan code
PBYTE  lpbKeyState,	// address of key-state array
LPWORD  lpwTransKey,	// buffer for translated key
UINT  fuState	// active-menu flag
);
Parameters

uVirtKey

Specifies the virtual-key code to be translated.

uScanCode

Specifies the hardware scan code of the key to be translated. The high-order bit of this value is set if the key is up.

lpbKeyState

Points to a 256-byte array that contains the current keyboard state. Each element (byte) in the array contains the state of one key. If the high-order bit of a byte is set, the key is down.

The low bit, if set, indicates that the key is toggled on. In this function, only the toggle bit of the CAPS LOCK key is relevant. The toggle state of the NUM LOCK and SCROLL LOCK keys is ignored.

lpwTransKey

Points to the buffer that will receive the translated Windows character or characters.

fuState

Specifies whether a menu is active. This parameter must be 1 if a menu is active, or 0 otherwise.

Return Value

If the specified key is a dead key, the return value is negative. Otherwise, it is one of the following values:

Value	Meaning
0	The specified virtual key has no translation for the current state of the keyboard.
1	One Windows character was copied to the buffer.
2	Two characters were copied to the buffer. This usually happens when a dead-key character (accent or diacritic) stored in the keyboard layout cannot be composed with the specified virtual key to form a single character.
Remarks

The parameters supplied to the ToAscii function might not be sufficient to translate the virtual-key code, because a previous dead key is stored in the keyboard layout.

Typically, ToAscii performs the translation based on the virtual-key code. In some cases, however, bit 15 of the uScanCode parameter may be used to distinguish between a key press and a key release.

Although NUM LOCK is a toggle key that affects keyboard behavior, ToAscii ignores the toggle setting (the low bit) of lpbKeyState(VK_NUMLOCK, because the uVirtKey parameter alone is sufficient to distinguish the cursor movement keys (VK_HOME, VK_INSERT, and so on) from the numeric keys (VK_DECIMAL, VK_NUMPAD0 - VK_NUMPAD9).

See Also

OemKeyScan, ToUnicode, VkKeyScan


ToAsciiEx [New - Windows 95]
ToAsciiEx  QuickInfo

[New - Windows 95]

The ToAsciiEx function translates the specified virtual-key code and keyboard state to the corresponding Windows character or characters. The function translates the code using the input language and physical keyboard layout identified by the given keyboard layout handle.

int ToAsciiEx(

UINT uVirtKey,	// virtual-key code
UINT ScanCode,	// scan code
BYTE *lpbKeyState,	// address of key-state array
DWORD *lpdwTransKey,	// buffer for translated key
UINT fuState,	// active-menu flag
HKL hkl	// keyboard layout handle
);
Parameters

uVirtKey

Specifies the virtual-key code to be translated.

uScanCode

Specifies the hardware scan code of the key to be translated. The high-order bit of this value is set if the key is up (not pressed).

lpbKeyState

Points to a 256-byte array that contains the current keyboard state. Each element (byte) in the array contains the state of one key. If the high-order bit of a byte is set, the key is down (pressed).

lpdwTransKey

Points to a doubleword buffer that receives the translated Windows character or characters.

fuState

Specifies whether a menu is active. This parameter must be 1 if a menu is active, zero otherwise.

hkl

Identifies the keyboard layout to use to translate the given code. This parameter can be any keyboard layout handle previously returned by the LoadKeyboardLayout function.

Return Value

If the function succeeds, the return value is the number of characters copied to the translated-key buffer. This number is typically greater than one for a ligated key or for an accent and a dead-key character. The function returns a negative value if the specified key is a dead key and returns zero if no conversion was done.

Remarks

The parameters supplied to the ToAsciiEx function might not be sufficient to translate the virtual-key code, because a previous dead key is stored in the keyboard layout.

Typically, ToAsciiEx performs the translation based on the virtual-key code. In some cases, however, bit 15 of the uScanCode parameter may be used to distinguish between a key press and a key release. The scan code is used for translating ALT+number key combinations.

See Also

LoadKeyboardLayout, MapVirtualKeyEx, OemKeyScan, ToAscii, VkKeyScan


ToUnicode
ToUnicode  QuickInfo  Overview  Group

The ToUnicode function translates the specified virtual-key code and keyboard state to the corresponding Unicode character or characters.

int ToUnicode(

UINT  wVirtKey,	// virtual-key code
UINT  wScanCode,	// scan code
PBYTE  lpKeyState,	// address of key-state array
LPWSTR  pwszBuff,	// buffer for translated key
int  cchBuff,	// size of translated key buffer
UINT  wFlags	// set of function-conditioning flags
);
Parameters

wVirtKey

Specifies the virtual-key code to be translated.

wScanCode

Specifies the hardware scan code of the key to be translated. The high-order bit of this value is set if the key is up.

lpKeyState

Points to a 256-byte array that contains the current keyboard state. Each element (byte) in the array contains the state of one key. If the high-order bit of a byte is set, the key is down.

pwszBuff

Points to the buffer that receives the translated Unicode character or characters.

cchBuff

Specifies the size in characters of the buffer pointed to by the pwszBuff parameter.

wFlags

A set of bit flags that condition the behavior of the function. Set bit 0 if a menu is active. Bits 1 through 31 are reserved.

Return Value

The function returns one of the following values:

Value	Meaning
− 1	The specified virtual key is a dead-key character (accent or diacritic). This value is returned regardless of the keyboard layout, even if several characters have been typed and are stored in the keyboard state. If possible, even with Unicode keyboard layouts, the function has written a spacing version of the dead-key character to the buffer specified by pwszBuffer. For example, the function writes the character SPACING ACUTE (0x00B4), rather than the character NON_SPACING ACUTE (0x0301).
0	The specified virtual key has no translation for the current state of the keyboard. Nothing was written to the buffer specified by pwszBuffer.
1	One character was written to the buffer specified by pwszBuffer.
2 or more	Two or more characters were written to the buffer specified by pwszBuff. The most common cause for this is that a dead-key character (accent or diacritic) stored in the keyboard layout could not be combined with the specified virtual key to form a single character.
Remarks

The parameters supplied to the ToUnicode function might not be sufficient to translate the virtual-key code because a previous dead key is stored in the keyboard layout.

Typically, ToUnicode performs the translation based on the virtual-key code. In some cases, however, bit 15 of the wScanCode parameter can be used to distinguish between a key press and a key release.

See Also

ToAscii, VkKeyScan


TrackPopupMenu
TrackPopupMenu  QuickInfo  Overview  Group

The TrackPopupMenu function displays a floating pop-up menu at the specified location and tracks the selection of items on the pop-up menu. The floating pop-up menu can appear anywhere on the screen.

BOOL TrackPopupMenu(

HMENU hMenu,	// handle of pop-up menu
UINT uFlags,	// screen-position and mouse-button flags
int x,	// horizontal position, in screen coordinates
int y,	// vertical position, in screen coordinates
int nReserved,	// reserved, must be zero
HWND hWnd,	// handle of owner window
CONST RECT * prcRect	// points to RECT that specifies no-dismissal area
);
Parameters

hMenu

Identifies the pop-up menu to be displayed. The handle can be obtained by calling CreatePopupMenu to create a new pop-up menu, or by calling GetSubMenu to retrieve the handle of a pop-up menu associated with an existing menu item.

uFlags

A set of bit flags that specify function options.

Use one of the following bit flag constants to specify how the function positions the popup menu horizontally:

Value	Meaning
TPM_CENTERALIGN	If this flag is set, the function centers the pop-up menu horizontally relative to the coordinate specified by the x parameter.
TPM_LEFTALIGN	If this flag is set, the function positions the pop-up menu so that its left side is aligned with the coordinate specified by the x parameter.
TPM_RIGHTALIGN	Positions the pop-up menu so that its right side is aligned with the coordinate specified by the x parameter.
Use one of the following bit flag constants to specify which mouse button the pop-up menu tracks:

Value	Meaning
TPM_LEFTBUTTON	If this flag is set, the pop-up menu tracks the left mouse button.
TPM_RIGHTBUTTON	If this flag is set, the pop-up menu tracks the right mouse button
x

Specifies the horizontal location of the pop-up menu, in screen coordinates.

y

Specifies the vertical location of the pop-up menu, in screen coordinates.

nReserved

Reserved; must be zero.

hWnd

Identifies the window that owns the pop-up menu. This window receives all messages from the menu. The window does not receive a WM_COMMAND message from the menu until the function returns.

prcRect

Points to a RECT structure that specifies the portion of the screen in which the user can select without dismissing the pop-up menu. If this parameter is NULL, the pop-up menu is dismissed if the user clicks outside the pop-up menu.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

CreatePopupMenu, GetSubMenu, RECT, WM_COMMAND


TrackPopupMenuEx [New - Windows 95]
TrackPopupMenuEx  QuickInfo  Overview  Group

[New - Windows 95]

The TrackPopupMenuEx function displays a floating pop-up menu at the specified location and tracks the selection of items on the pop-up menu. The floating pop-up menu can appear anywhere on the screen.

BOOL TrackPopupMenuEx(

HMENU  hmenu,
UINT  fuFlags,
int  x,
int  y,
HWND  hwnd,
LPTPMPARAMS  lptpm
);
Parameters

hmenu

Handle to the pop-up menu to be displayed. This handle can be obtained by calling the CreatePopupMenu function to create a new pop-up menu or by calling the GetSubMenu function to retrieve the handle to a pop-up menu associated with an existing menu item.

fuFlags

Positioning and other options. This parameter, which can be zero or more of the values listed with the TrackPopupMenu function, may also include one of the following values:

Value	Meaning
TPM_HORIZONTAL	If the menu cannot be shown at the specified location without overlapping the excluded rectangle, the system tries to accommodate the requested horizontal alignment before the requested vertical alignment.
TPM_VERTICAL	If the menu cannot be shown at the specified location without overlapping the excluded rectangle, the system tries to accommodate the requested vertical alignment before the requested horizontal alignment.
The excluded rectangle is a portion of the screen that the menu should not overlap; it is specified by lptpm.

x

Horizontal location of the pop-up menu, in screen coordinates.

y

Vertical location of the pop-up menu, in screen coordinates.

hwnd

Handle to the window that owns the pop-up menu. This window receives all messages from the menu. The window does not receive a WM_COMMAND message from the menu until the function returns.

lptpm

Pointer to a TPMPARAMS structure that specifies an area of the screen the menu should not overlap. This parameter can be NULL.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, use the GetLastError function.

See Also

CreatePopupMenu, GetSubMenu, TPMPARAMS, TrackPopupMenu, WM_COMMAND


TransactNamedPipe
TransactNamedPipe  QuickInfo  Overview  Group

The TransactNamedPipe function combines into a single network operation the functions that write a message to and read a message from the specified named pipe.

BOOL TransactNamedPipe(

HANDLE  hNamedPipe,	// handle of named pipe
LPVOID  lpvWriteBuf,	// address of write buffer
DWORD  cbWriteBuf,	// size of the write buffer, in bytes
LPVOID  lpvReadBuf,	// address of read buffer
DWORD  cbReadBuf,	// size of read buffer, in bytes
LPDWORD  lpcbRead,	// address of variable for bytes actually read
LPOVERLAPPED  lpo	// address of overlapped structure
);
Parameters

hNamedPipe

Identifies the named pipe returned by the CreateNamedPipe or CreateFile function.

lpvWriteBuf

Points to the buffer containing the data written to the pipe.

cbWriteBuf

Specifies the size, in bytes, of the write buffer.

lpvReadBuf

Points to the buffer that receives the data read from the pipe.

cbReadBuf

Specifies the size, in bytes, of the read buffer.

lpcbRead

Points to the variable that receives the number of bytes read from the pipe.

lpo

Points to an OVERLAPPED structure. If this parameter is NULL or if the FILE_FLAG_OVERLAPPED flag was not specified in the CreateNamedPipe or CreateFile function when the handle was created, TransactNamedPipe does not return until the operation is finished.

If this parameter is not NULL and FILE_FLAG_OVERLAPPED was specified when the handle was created, TransactNamedPipe is executed as an overlapped operation. The OVERLAPPED structure should contain a manual-reset event object (which can be created by using the CreateEvent function). If the operation cannot be completed immediately, TransactNamedPipe returns FALSE and GetLastError returns ERROR_IO_PENDING. In this situation, the event object is set to the nonsignaled state before TransactNamedPipe returns, and it is set to the signaled state when the transaction has finished. For more information about overlapped operations, see Pipes.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

TransactNamedPipe fails if the server did not create the pipe as a message-type pipe or if the pipe handle is not in message-read mode. A pipe handle can be set to message-read mode with the SetNamedPipeHandleState function. The wait mode of the specified pipe handle (blocking or nonblocking) has no effect on TransactNamedPipe.

The function cannot be completed successfully until data is written into the buffer specified by the lpvReadBuf parameter. The lpo parameter is available to enable the calling thread to perform other tasks while the operation is executing in the background.

If the message to be read is longer than the buffer specified by the cbReadBuf parameter, TransactNamedPipe returns FALSE and the GetLastError function returns ERROR_MORE_DATA. The remainder of the message can be read by a subsequent call to ReadFile, ReadFileEx, or PeekNamedPipe.

See Also

CreateEvent, CreateFile, CreateNamedPipe, PeekNamedPipe, ReadFile, ReadFileEx, SetNamedPipeHandleState, OVERLAPPED


TranslateAccelerator
TranslateAccelerator  QuickInfo  Overview  Group

The TranslateAccelerator function processes accelerator keys for menu commands. The function translates a WM_KEYDOWN or WM_SYSKEYDOWN message to a WM_COMMAND or WM_SYSCOMMAND message (if there is an entry for the key in the specified accelerator table) and then sends the WM_COMMAND or WM_SYSCOMMAND message directly to the appropriate window procedure. TranslateAccelerator does not return until the window procedure has processed the message.

int TranslateAccelerator(

HWND  hwnd,	// handle of destination window
HACCEL  haccl,	// handle of accelerator table
LPMSG  lpmsg	// address of structure with message
);
Parameters

hwnd

Identifies the window whose messages are to be translated.

haccl

Identifies an accelerator table. The accelerator table must have been loaded by a call to the LoadAccelerators function or created by a call to the CreateAcceleratorTable function.

lpmsg

Points to an MSG structure that contains message information retrieved from the calling thread's message queue by using the GetMessage or PeekMessage function.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

To differentiate the message from messages sent by menus or controls, the high-order word of the lParam parameter of the WM_COMMAND or WM_SYSCOMMAND message contains the value 1.

Accelerator key combinations used to select items from the System menu are translated into WM_SYSCOMMAND messages; all other accelerator key combinations are translated into WM_COMMAND messages.

When TranslateAccelerator returns a nonzero value and the message is translated, the application should not use the TranslateMessage function to process the message again.

An accelerator need not correspond to a menu command.

If the accelerator command corresponds to a menu item, the application is sent WM_INITMENU and WM_INITMENUPOPUP messages, as if the user were trying to display the menu. However, these messages are not sent if any of the following conditions exist:

•	The window is disabled.

•	The menu item is disabled.

•	The accelerator key combination does not correspond to an item on the System menu and the window is minimized.

•	A mouse capture is in effect. For information about mouse capture, see the SetCapture function.

If the specified window is the active window and no window has the keyboard focus (which is generally the case if the window is minimized), TranslateAccelerator translates WM_SYSKEYUP and WM_SYSKEYDOWN messages instead of WM_KEYUP and WM_KEYDOWN messages.

If an accelerator keystroke occurs that corresponds to a menu item when the window that owns the menu is minimized, TranslateAccelerator does not send a WM_COMMAND message. However, if an accelerator keystroke occurs that does not match any of the items in the window's menu or in the System menu, the function sends a WM_COMMAND message, even if the window is minimized.

See Also

CreateAcceleratorTable, GetMessage, LoadAccelerators, MSG, PeekMessage, SetCapture, TranslateMessage, WM_COMMAND, WM_INITMENU, WM_INITMENUPOPUP, WM_KEYDOWN, WM_SYSKEYDOWN, WM_SYSCOMMAND


TranslateCharsetInfo [New - Windows 95]
TranslateCharsetInfo  QuickInfo  Overview  Group

[New - Windows 95]

The TranslateCharsetInfo function translates based on the specified character set, code page, or font signature value, setting all members of the destination structure to appropriate values.

UINT TranslateCharsetInfo(

DWORD FAR * lpSrc,
LPCHARSETINFO lpCs,
DWORD  dwFlags
);
Parameters

lpSrc

Address or value as defined by the dwFlags parameter. If dwFlags is TCI_SRCFONTSIG, this parameter is the address of the fsCsb member of a FONTSIGNATURE structure. Otherwise, this parameter is a 32-bit value.

lpCs

Pointer to a CHARSETINFO structure that receives the translated character set information.

dwFlags

Translation flags. This parameter can be one of the following values:

Value	Meaning
TCI_SRCCHARSET	Source contains the character set value in the low word, and zero in the high word.
TCI_SRCCODEPAGE	Source is a code-page value in the low word and zero in the high word.
TCI_SRCFONTSIG	Source is the code-page bitfield portion of a FONTSIGNATURE structure. On input this should have only one Windows code-page bit set, either for an ANSI code-page value or for a common ANSI and OEM value (for OEM values, bits 32-63 must be clear.). On output this will have only one bit set. If the TCI_SRCFONTSIG value is given, the lpSrc parameter must be the address of the codepage bit field. If any other TCI_ value is given, the lpSrc parameter must be a value not an address.
See Also

CHARSETINFO, FONTSIGNATURE


TranslateMDISysAccel
TranslateMDISysAccel  QuickInfo  Overview  Group

The TranslateMDISysAccel function processes accelerator keystrokes for System menu commands of the multiple document interface (MDI) child windows associated with the specified MDI client window. The function translates WM_KEYUP and WM_KEYDOWN messages to WM_SYSCOMMAND messages and sends them to the appropriate MDI child windows.

BOOL TranslateMDISysAccel(

HWND  hwndClient,	// handle of MDI client window
LPMSG  lpmsg	// address of structure with message data
);
Parameters

hwndClient

Identifies the MDI client window.

lpmsg

Points to a message retrieved by using the GetMessage or PeekMessage function. The message must be an MSG structure and contain message information from the application's message queue.

Return Value

If TranslateMDISysAccel translates a message into a system command, the return value is TRUE; otherwise, it is FALSE.

See Also

GetMessage, PeekMessage, TranslateAccelerator, MSG, WM_KEYDOWN, WM_KEYUP, WM_SYSCOMMAND


TranslateMessage
TranslateMessage  QuickInfo  Overview  Group

The TranslateMessage function translates virtual-key messages into character messages. The character messages are posted to the calling thread's message queue, to be read the next time the thread calls the GetMessage or PeekMessage function.

BOOL TranslateMessage(

CONST MSG  *lpmsg	// address of structure with message
);
Parameters

lpmsg

Points to an MSG structure that contains message information retrieved from the calling thread's message queue by using the GetMessage or PeekMessage function.

Return Value

If the message is translated (that is, a character message is posted to the thread's message queue), the return value is TRUE; otherwise, it is FALSE.

Windows NT: The TranslateMessage function returns TRUE for function and arrow keys as well as for character and digit keys.

Remarks

The TranslateMessage function does not modify the message pointed to by the lpmsg parameter.

WM_KEYDOWN and WM_KEYUP combinations produce a WM_CHAR or WM_DEADCHAR message. WM_SYSKEYDOWN and WM_SYSKEYUP combinations produce a WM_SYSCHAR or WM_SYSDEADCHAR message.

TranslateMessage produces WM_CHAR messages only for keys that are mapped to ASCII characters by the keyboard driver.

If applications process virtual-key messages for some other purpose, they should not call TranslateMessage. For instance, an application should not call TranslateMessage if the TranslateAccelerator function returns TRUE.

See Also

GetMessage, PeekMessage, TranslateAccelerator, WM_CHAR, WM_DEADCHAR, WM_KEYDOWN, WM_KEYUP, WM_SYSCHAR, WM_SYSDEADCHAR, WM_SYSKEYDOWN, WM_SYSKEYUP


TransmitCommChar
TransmitCommChar  QuickInfo  Overview  Group

The TransmitCommChar function transmits a specified character ahead of any pending data in the output buffer of the specified communications device.

BOOL TransmitCommChar(

HANDLE  hCommDev,	// handle of communications device
char  chTransmit	// character to transmit
);
Parameters

hCommDev

Identifies the communications device. The CreateFile function returns this handle.

chTransmit

Specifies the character to be transmitted.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The TransmitCommChar function is useful for sending an interrupt character (such as a CTRL+C) to a host system.

If the device is not transmitting, TransmitCommChar cannot be called repeatedly. Once TransmitCommChar places a character in the output buffer, the character must be transmitted before the function can be called again. If the previous character has not yet been sent, TransmitCommChar returns an error.

Character transmission is subject to normal flow control and handshaking. This function can only be called synchronously.

See Also

CreateFile, WaitCommEvent


TransmitFile [New - Windows NT]
TransmitFile  QuickInfo

[New - Windows NT]

The TransmitFile function transmits file data over a connected socket handle. The function uses the operating system's cache manager to retrieve the file data. This function provides high-performance file data transfer over sockets.

BOOL TransmitFile(

SOCKET  hSocket,	// handle to a connected socket
HANDLE  hFile,	// handle to an open file
DWORD   nNumberOfBytesToWrite,	// number of bytes to transmit
DWORD   nNumberOfBytesPerSend,	// number of bytes per sockets send operation
LPOVERLAPPED  lpOverlapped,	// pointer to overlapped I/O data structure
LPTRANSMIT_FILE_BUFFERS  lpTransmitBuffers,	// pointer to data to send before and after file data
DWORD   dwReserved	// reserved; must be zero
);
Parameters

hSocket

Handle to a connected socket. The function will transmit the file data over this socket.

The socket specified by hSocket must be a virtual circuit socket. A socket of type SOCK_STREAM, SOCK_SEQPACKET, or SOCK_RDM is a virtual circuit socket. The TransmitFile function does not support datagram sockets.

hFile

Handle to an open file. The function transmits this file's data. The operating system reads the file data sequentially. You can improve caching performance by opening the handle with the FILE_FLAG_SEQUENTIAL_SCAN .

nNumberOfBytesToWrite

Specifies the number of bytes to transmit. The function completes when it has sent this many bytes, or an error occurs.

Set this parameter to zero to transmit the entire file.

nNumberOfBytesPerSend

Specifies the size of each socket send operation. This specification is for use by the sockets layer of the operating system.

Set this parameter to zero to indicate that the sockets layer should use an intelligent default send size.

This parameter is useful for message protocols that have limitations on the size of individual send requests.

lpOverlapped

Pointer to an OVERLAPPED structure. If the socket handle has been opened as overlapped, specify this parameter in order to achieve an overlapped (aysnchronous) I/O operation.

Note that, by default, socket handles are opened as overlapped.

Note that you can use this parameter to specify an offset within the file at which to start the file data transfer. You do that by setting the Offset and OffsetHigh fields of the OVERLAPPED structure. If lpOverlapped is NULL, the transmission of data always starts at the current byte offset in the file.

When lpOverlapped is not NULL, the overlapped I/O may not finish before TransmitFile returns. In that case, the TransmitFile function returns FALSE, and GetLastError returns ERROR_IO_PENDING. This lets the caller continue processing while the file transmission operation completes. The operating system will set the event specified by the hEvent field of the OVERLAPPED structure, or the socket specified by hSocket, to the signalled state upon completion of the data transmission request.

lpTransmitBuffers

Pointer to a TRANSMIT_FILE_BUFFERS data structure that contains pointers to data to send before and after the file data is sent.

Set this parameter to NULL if you only want to transmit the file data.

dwReserved

Reserved; must be zero.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Note that the function returns FALSE if an overlapped I/O operation is not complete before TransmitFile returns. In that case, GetLastError returns ERROR_IO_PENDING.

Remarks

The Windows NT Server optimizes the TransmitFile function for high performance. The Windows NT Workstation optimizes the function for minimum memory and resource utilization. Expect better performance results when using TransmitFile on Windows NT Server.

See Also

OVERLAPPED, TRANSMIT_FILE_BUFFERS


UInt32x32To64
UInt32x32To64  QuickInfo  Overview  Group

The UInt32x32To64 function multiplies two unsigned 32-bit integers, returning an unsigned 64-bit integer result. The function performs optimally on all Win32 platforms.

DWORDLONG UInt32x32To64(

DWORD  Multiplier,	// specifies first unsigned 32-bit integer for the multiplication
DWORD  Multiplicand	// specifies second unsigned 32-bit integer for the multiplication
);
Parameters

Multiplier

Specifies the first unsigned 32-bit integer for the multiplication.

Multiplicand

Specifies the second unsigned 32-bit integer for the multiplication.

Return Value

The return value is the unsigned 64-bit integer result of the multiplication.

Remarks

This function is implemented on all platforms by optimal inline code: a single multiply instruction that returns a 64-bit result.

Please note that the function's return value is a 64-bit value, not a LARGE_INTEGER structure.

See Also

Int32x32To64


UndeleteFile
UndeleteFile  QuickInfo  Overview  Group

The UndeleteFile function is an application-defined callback function that File Manager calls when the user chooses the Undelete command from the File Manager File menu.

DWORD APIENTRY UndeleteFile(

HWND  hwndOwner,	// handle of File Manager window
LPSTR  lpszDir	// address of name of initial directory
);
Parameters

hwndOwner

Identifies the File Manager window. An "undelete" dynamic-link library (DLL) should use this handle to specify the owner window for any dialog box or message box the DLL may display.

lpszDir

Points to a null-terminated string that contains the name of the initial directory.

Return Value

If the function succeeds, the return value is one of the following:

Value	Meaning
−l	An error occurred.
IDOK	A file was undeleted. File Manager repaints its windows.
IDCANCEL	No file was undeleted.


UnhandledExceptionFilter
UnhandledExceptionFilter  QuickInfo  Overview  Group

The UnhandledExceptionFilter function passes unhandled exceptions to the debugger, if the process is being debugged. Otherwise, it optionally displays an Application Error message box and causes the exception handler to be executed. This function can be called only from within the filter expression of a try-except exception handler.

LONG UnhandledExceptionFilter(

STRUCT _EXCEPTION_POINTERS *  lpexpExceptionInfo	// address of exception info
);
Parameters

lpexpExceptionInfo

Points to an EXCEPTION_POINTERS structure containing a description of the exception and the processor context at the time of the exception. This pointer is the return value of a call to the GetExceptionInformation function.

Return Value

The function returns one of the following values:

Value	Meaning
EXCEPTION_CONTINUE_SEARCH	The process is being debugged, so the exception should be passed (as second chance) to the application's debugger.
EXCEPTION_EXECUTE_HANDLER	If the SEM_NOGPFAULTERRORBOX flag was specified in a previous call to SetErrorMode, no Application Error message box is displayed. The function returns control to the exception handler, which is free to take any appropriate action.
Remarks

If the process is not being debugged, the function displays an Application Error message box, depending on the current error mode. The default behavior is to display the dialog box, but this can be disabled by specifying SEM_NOGPFAULTERRORBOX in a call to the SetErrorMode function.

The system uses UnhandledExceptionFilter internally to handle exceptions that occur during process and thread creation.

See Also

EXCEPTION_POINTERS, GetExceptionInformation, SetErrorMode, SetUnhandledExceptionFilter, UnhandledExceptionFilter


UnhookWindowsHook
UnhookWindowsHook  QuickInfo  Overview  Group

The UnhookWindowsHook function is obsolete, but is provided for compatibility with 16-bit versions of Windows. For Win32-based applications, use the UnhookWindowsHookEx function.

BOOL UnhookWindowsHook(

int  nCode,	// type of hook to remove procedure from
HOOKPROC  hkprc	// address of hook procedure
);


UnhookWindowsHookEx
UnhookWindowsHookEx  QuickInfo  Overview  Group

The UnhookWindowsHookEx function removes a hook procedure installed in a hook chain by the SetWindowsHookEx function.

BOOL UnhookWindowsHookEx(

HHOOK  hhook	// handle of hook procedure to remove
);
Parameters

hhook

Identifies the hook to be removed. This parameter is a hook handle obtained by a previous call to SetWindowsHookEx.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

The hook procedure can be in the state of being called by another thread even after UnhookWindowsHookEx returns. If the hook procedure is not being called concurrently, the hook procedure is removed immediately before UnhookWindowsHookEx returns.

See Also

SetWindowsHookEx, UnhookWindowsHook


UnionRect
UnionRect  QuickInfo  Overview  Group

The UnionRect function creates the union of two rectangles. The union is the smallest rectangle that contains both source rectangles.

BOOL UnionRect(

LPRECT  lprcDst,	// address of structure for union
CONST RECT  *lprcSrc1,	// address of structure with first rectangle
CONST RECT  *lprcSrc2	// address of structure with second rectangle
);
Parameters

lprcDst

Points to the RECT structure that will receive a rectangle containing the rectangles pointed to by the lprcSrc1 and lprcSrc2 parameters.

lprcSrc1

Points to the RECT structure that contains the first source rectangle.

lprcSrc2

Points to the RECT structure that contains the second source rectangle.

Return Value

If the specified structure contains a nonempty rectangle, the return value is TRUE; otherwise, it is FALSE. To get extended error information, call GetLastError.

Remarks

Windows ignores the dimensions of an empty rectangle — that is, a rectangle in which all coordinates are set to zero, so that it has no height or no width.

See Also

InflateRect, IntersectRect, OffsetRect, RECT


UnloadKeyboardLayout
UnloadKeyboardLayout  QuickInfo  Overview  Group

The UnloadKeyboardLayout function removes a keyboard layout.

BOOL UnloadKeyboardLayout(

HKL  hkl	// handle of keyboard layout
);
Parameters

hkl

Identifies the keyboard layout to unload.

Return Value

If the function succeeds, the return value is the handle of the keyboard layout; otherwise, it is NULL. To get extended error information, use the GetLastError function.

Remarks

Windows 95: UnloadKeyboardLayout cannot unload the system default keyboard layout. This ensures that an appropriate character set is always available for the user to type commands for the shell or names for the file system.

Windows NT: UnloadKeyboardLayout can unload the system default keyboard layout.

See Also

ActivateKeyboardLayout, GetKeyboardLayoutName, LoadKeyboardLayout


UnlockFile
UnlockFile  QuickInfo  Overview  Group

The UnlockFile function unlocks a region in an open file. Unlocking a region enables other processes to access the region.

BOOL UnlockFile(

HANDLE  hFile,	// handle of file to unlock
DWORD  dwFileOffsetLow,	// low-order word of lock region offset
DWORD  dwFileOffsetHigh,	// high-order word of lock region offset
DWORD  cbUnlockLow,	// low-order word of length to unlock
DWORD  cbUnlockHigh	// high-order word of length to unlock
);
Parameters

hFile

Identifies a file that contains a region locked with LockFile. The file handle must have been created with either GENERIC_READ or GENERIC_WRITE access to the file.

dwFileOffsetLow

Specifies the low-order word of the starting byte offset in the file where the locked region begins.

dwFileOffsetHigh

Specifies the high-order word of the starting byte offset in the file where the locked region begins.

cbUnlockLow

Specifies the low-order word of the length of the byte range to be unlocked.

cbUnlockHigh

Specifies the high-order word of the length of the byte range to be unlocked.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Unlocking a region of a file releases a lock on the file. The region to unlock must correspond exactly to an existing locked region. For example, two adjacent regions of a file cannot be locked separately and then unlocked as a single region that spans both locked regions.

A process should not be terminated with a portion of a file locked and a file that has locked regions should not be closed.

This function works on a file allocation table (FAT) − based file system only if the operating system is running SHARE.EXE.

See Also

CreateFile, LockFile


UnlockFileEx
UnlockFileEx  QuickInfo  Overview  Group

The UnlockFileEx function unlocks a previously locked byte range in an open file.

BOOL UnlockFileEx(

HANDLE  hFile,	// handle of file to unlock
DWORD  dwReserved,	// reserved, must be set to zero
DWORD  nNumberOfBytesToUnlockLow,	// low order 32-bits of length to unlock
DWORD  nNumberOfBytesToUnlockHigh,	// high order 32-bits of length to unlock
LPOVERLAPPED  lpOverlapped	// addr. of struct. with unlock region start offset
);
Parameters

hFile

Identifies an open handle to a file that is to have an existing locked region unlocked. The handle must have been created with either GENERIC_READ or GENERIC_WRITE access to the file.

dwReserved

Reserved parameter; must be zero.

nNumberOfBytesToUnlockLow

Specifies the low-order 32-bits of the length of the byte range to unlock.

nNumberOfBytesToUnlockHigh

Specifies the high-order 32-bits of the length of the byte range to unlock.

lpOverlapped

Points to an OVERLAPPED structure that the function uses with the unlocking request. This structure contains the file offset of the beginning of the unlock range.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE or NULL. To get extended error information, call GetLastError.

Remarks

Unlocking a region of a file releases a previously acquired lock on a file. The region to unlock must correspond exactly to an existing locked region. Two adjacent regions of a file can not be locked separately and then unlocked using a single region that spans both locked regions.

If a process terminates with a portion of a file locked or closes a file that has outstanding locks, the behavior is not specified.

See Also

CreateFile, LockFile, LockFileEx, OVERLAPPED, UnlockFile


UnlockResource
UnlockResource  QuickInfo  Overview  Group

The UnlockResource function is obsolete. It is not necessary for Win32-based applications to unlock resources.

See Also

LoadResource, LockResource


UnlockSegment
UnlockSegment  QuickInfo  Overview  Group

The UnlockSegment function is obsolete. Segments have no meaning in the 32-bit environment.


UnlockServiceDatabase
UnlockServiceDatabase  QuickInfo  Overview  Group

The UnlockServiceDatabase function unlocks a service control manager database by releasing the specified lock.

BOOL UnlockServiceDatabase(

SC_LOCK  sclLock	// service control manager database lock to be released
);
Parameters

sclLock

Specifies a lock obtained from a previous call to the LockServiceDatabase function.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Errors

The following error codes may be set by the service control manager. Other error codes may be set by the registry functions that are called by the service control manager.

Value	Meaning
ERROR_INVALID_SERVICE_LOCK	The specified lock is invalid.
See Also

LockServiceDatabase, QueryServiceLockStatus


UnmapViewOfFile
UnmapViewOfFile  QuickInfo  Overview  Group

The UnmapViewOfFile function unmaps a mapped view of a file from the calling process's address space.

BOOL UnmapViewOfFile(

LPVOID  lpBaseAddress	// address where mapped view begins
);
Parameters

lpBaseAddress

Points to the base address of the mapped view of a file that is to be unmapped. This value must be identical to the value returned by a previous call to the MapViewOfFile or MapViewOfFileEx function.

Return Value

If the function succeeds, the return value is TRUE, and all dirty pages within the specified range are written "lazily" to disk.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Although an application may close the file handle used to create a file mapping object, the system holds the corresponding file open until the last view of the file is unmapped.

Windows 95: Files for which the last view has not yet been unmapped are held open with the same sharing restrictions as the original file handle.

Windows NT: Files for which the last view has not yet been unmapped are held open with no sharing restrictions.

See Also

MapViewOfFile, MapViewOfFileEx


UnpackDDElParam
UnpackDDElParam  QuickInfo  Overview  Group

The UnpackDDElParam function unpacks a DDE lParam value received from a posted DDE message.

BOOL UnpackDDElParam(

UINT  uMsg,	// posted DDE message
LONG  lParam,	// lParam of posted DDE message
PUINT  puLow,	// address of low-order word of lParam
PUINT  puHigh	// address of high-order word of lParam
);
Parameters

uMsg

Specifies the posted DDE message.

lParam

Specifies the lParam parameter of the posted DDE message that was received. The application must free the memory object specified by the lParam parameter by calling the FreeDDElParam function.

puLow

Points to a value the function will set to the low-order word of lParam.

puHigh

Points to a value the function will set to the high-order word of lParam.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

PackDDElParam eases the porting of 16-bit DDE applications to 32-bit DDE applications.

See Also

FreeDDElParam, PackDDElParam, ReuseDDElParam


UnrealizeObject
UnrealizeObject  QuickInfo  Overview  Group

The UnrealizeObject function resets a logical palette. It directs the system to realize the palette as though it had not previously been realized. The next time the application calls the RealizePalette function for the specified palette, the system completely remaps the logical palette to the system palette.

If hgdiobj is a brush, UnrealizeObject does nothing, and the function returns TRUE. Use SetBrushOrgEx to set the origin of a brush.

BOOL UnrealizeObject(

HGDIOBJ  hgdiobj	// logical palette handle
);
Parameters

hgdiobj

Identifies the logical palette to be reset.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The UnrealizeObject function should not be used with stock objects. The default palette, obtained by calling GetStockObject(DEFAULT_PALETTE), is a stock object.

A palette identified by hgdiobj can be the currently selected palette of a device context.

See Also

GetStockObject, RealizePalette, SetBrushOrgEx


UnregisterClass
UnregisterClass  QuickInfo  Overview  Group

The UnregisterClass function removes a window class, freeing the memory required for the class.

BOOL UnregisterClass(

LPCTSTR  lpszClass,	// address of class name string
HINSTANCE  hinst	// handle of application instance
);
Parameters

lpszClass

Points to a null-terminated string or is an integer atom. If this parameter is an integer atom, it must be a global atom created by a previous call to the GlobalAddAtom function. The atom, a 16-bit value less than 0xC000, must be in the low-order word of lpszClass; the high-order word must be zero.

If lpszClass is a string, it specifies the window class name. This class name must have been registered by a previous call to the RegisterClass function. System global classes, such as dialog box controls, cannot be unregistered.

hinst

Identifies the instance of the module that created the class.

Return Value

If the function succeeds, the return value is TRUE. If the class could not be found or if a window still exists that was created with the class, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Before calling this function, an application must destroy all windows created with the specified class.

All window classes that an application registers are unregistered when it terminates.

See Also

GlobalAddAtom, RegisterClass


UnregisterHotKey
UnregisterHotKey  QuickInfo  Overview  Group

The UnregisterHotKey function frees a hot key previously registered by the calling thread.

BOOL UnregisterHotKey(

HWND  hwnd,	// window associated with hot key
int  idHotKey	// identifier of hot key
);
Parameters

hwnd

Identifies the window associated with the hot key to be freed. This parameter should be NULL if the hot key is not associated with a window.

idHotKey

Specifies the identifier of the hot key to be freed.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

RegisterHotKey, WM_HOTKEY


UpdateColors
UpdateColors  QuickInfo  Overview  Group

The UpdateColors function updates the client area of the specified device context by remapping the current colors in the client area to the currently realized logical palette.

BOOL UpdateColors(

HDC  hdc	// handle of device context
);
Parameters

hdc

Identifies the device context.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

An application can determine whether a device supports palette operations by calling the GetDeviceCaps function and specifying the RASTERCAPS constant.

An inactive window with a realized logical palette may call UpdateColors as an alternative to redrawing its client area when the system palette changes.

The UpdateColors function typically updates a client area faster than redrawing the area. However, because UpdateColors performs the color translation based on the color of each pixel before the system palette changed, each call to this function results in the loss of some color accuracy.

This function must be called soon after a WM_PALETTECHANGED message is received.

See Also

GetDeviceCaps, RealizePalette


UpdateICMRegKey
UpdateICMRegKey  Overview  Group

The UpdateICMRegKey function installs, removes, or queries registry entries that identify ICC color profiles or color-matching DLLs. The function carries out the action specified by the nCommand parameter.

BOOL UpdateICMRegKey(

DWORD  dwReserved,
DWORD  CMID,
LPTSTR  lpszFileName,
UINT  nCommand
);
Parameters

dwReserved

Reserved; must be zero.

CMID

Profile identifier of the color-matching DLL to use with the profile.

lpszFileName

Pointer to a zero-terminated string that specifies the filename of an ICC color profile or address of a DEVMODE structure, depending on the value of nCommand.

nCommand

Action flag. This parameter can have one of the following values:

ICM_ADDPROFILE	Adds the ICC profile to the ICM branch in the registry.
ICM_DELETEPROFILE	Deletes the ICC profile from the ICM branch in the registry.
ICM_QUERYPROFILE	Determines if the profile is in the ICM branch of the registry.
ICM_SETDEFAULTPROFILE	Makes the profile first among equals.
ICM_REGISTERICMATCHER	Equates a CMID to a color-matching DLL.
ICM_UNREGISTERICMATCHER	Removes the reference between CMID and a color-matching DLL.
ICM_QUERYMATCH	Determines if a profile exists based on the DEVMODE pointed to by lpszFileName.
Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is NULL.

Remarks

GDI uses the registry to keep track of ICC profiles installed in the system (listed in the registry). Although not required, if ICC profiles are copied to a local directory, they should be placed in the Color directory in the Windows System directory.

See Also

DEVMODE


UpdateResource
UpdateResource  QuickInfo  Overview  Group

The UpdateResource function adds, deletes, or replaces a resource in an executable file.

BOOL UpdateResource(

HANDLE  hUpdateFile,	// update-file handle
LPCTSTR  lpszType,	// address of resource type to update
LPCTSTR  lpszName,	// address of resource name to update
WORD  IDLanguage,	// language identifier of resource
LPVOID  lpvData,	// address of resource data
DWORD  cbData	// length of resource data, in bytes
);
Parameters

hUpdateFile

Specifies an update-file handle. This handle is returned by the BeginUpdateResource function.

lpszType

Points to a null-terminated string specifying the resource type to be updated. This parameter can also be an integer value passed to the MAKEINTRESOURCE macro, or it can be one of the following predefined resource types:

Value	Meaning
RT_ACCELERATOR	Accelerator table
RT_BITMAP	Bitmap resource
RT_DIALOG	Dialog box
RT_FONT	Font resource
RT_FONTDIR	Font directory resource
RT_MENU	Menu resource
RT_RCDATA	Application-defined resource (raw data)
RT_STRING	String-table entry
RT_MESSAGETABLE	Message-table entry
RT_CURSOR	Hardware-dependent cursor resource
RT_GROUP_CURSOR	Hardware-independent cursor resource
RT_ICON	Hardware-dependent icon resource
RT_GROUP_ICON	Hardware-independent icon resource
RT_VERSION	Version resource
lpszName

Points to a null-terminated string specifying the name of the resource to be updated. This parameter can also be an integer value passed to the MAKEINTRESOURCE macro.

IDLanguage

Specifies the language identifier of the resource to be updated. For a list of the primary language identifiers and sublanguage identifiers that make up a language identifier, see the MAKELANGID macro

lpvData

Points to the resource data to be inserted into the executable file. If the resource is one of the predefined types, the data must be valid and properly aligned. Note that this is the raw binary data stored in the executable file, not the data provided by LoadIcon, LoadString, or other resource-specific load functions. All data containing strings or text must be in Unicode format; lpvData must not point to ANSI data.

If lpvData is NULL, the specified resource is deleted from the executable file.

cbData

Specifies the size, in bytes, of the resource data at lpvData.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

An application can use UpdateResource repeatedly to make changes to the resource data. Each call to UpdateResource contributes to an internal list of additions, deletions, and replacements but does not actually write the data to the executable file. The application must use the EndUpdateResource function to write the accumulated changes to the executable file.

See Also

BeginUpdateResource, EndUpdateResource, LoadIcon, LoadString, LockResource, MAKEINTRESOURCE, MAKELANGID, SizeofResource


UpdateWindow
UpdateWindow  QuickInfo  Overview  Group

The UpdateWindow function updates the client area of the specified window by sending a WM_PAINT message to the window if the window's update region is not empty. The function sends a WM_PAINT message directly to the window procedure of the specified window, bypassing the application queue. If the update region is empty, no message is sent.

BOOL UpdateWindow(

HWND  hwnd	// handle of window
);
Parameters

hwnd

Identifies the window to be updated.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

See Also

ExcludeUpdateRgn, GetUpdateRect, GetUpdateRgn, InvalidateRect, InvalidateRgn, WM_PAINT


ValidateRect
ValidateRect  QuickInfo  Overview  Group

The ValidateRect function validates the client area within a rectangle by removing the rectangle from the update region of the specified window.

BOOL ValidateRect(

HWND  hwnd,	// handle of window
CONST RECT  *lprc	// address of validation rectangle coordinates
);
Parameters

hwnd

Identifies the window whose update region is to be modified. If this parameter is NULL, Windows invalidates and redraws all windows and sends the WM_ERASEBKGND and WM_NCPAINT messages to the window procedure before the function returns.

lprc

Points to a RECT structure that contains the client coordinates of the rectangle to be removed from the update region. If this parameter is NULL, the entire client area is removed.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

The BeginPaint function automatically validates the entire client area. Neither the ValidateRect nor ValidateRgn function should be called if a portion of the update region must be validated before the next WM_PAINT message is generated.

Windows continues to generate WM_PAINT messages until the current update region is validated.

See Also

BeginPaint, InvalidateRect, InvalidateRgn, RECT, ValidateRgn, WM_PAINT


ValidateRgn
ValidateRgn  QuickInfo  Overview  Group

The ValidateRgn function validates the client area within a region by removing the region from the current update region of the specified window.

BOOL ValidateRgn(

HWND  hwnd,	// handle of window
HRGN  hrgn	// handle of valid region
);
Parameters

hwnd

Identifies the window whose update region is to be modified.

hrgn

Identifies a region that defines the area to be removed from the update region. If this parameter is NULL, the entire client area is removed.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

The specified region must have been created by a region function. The region coordinates are assumed to be client coordinates.

The BeginPaint function automatically validates the entire client area. Neither the ValidateRect nor ValidateRgn function should be called if a portion of the update region must be validated before the next WM_PAINT message is generated.

See Also

BeginPaint, ExcludeUpdateRgn, InvalidateRect, InvalidateRgn, ValidateRect, WM_PAINT


VerFindFile
VerFindFile  QuickInfo  Overview  Group

The VerFindFile function determines where to install a file based on whether it locates another version of the file in the system. The values VerFindFile returns in the specified buffers are used in a subsequent call to VerInstallFile.

As with the other file installation functions, VerFindFile will only work with Win32 file images. 16-bit Windows file images are not supported.

DWORD VerFindFile(

DWORD  dwFlags,	// bit flags that condition function behavior
LPTSTR  szFileName,	// file to be installed
LPTSTR  szWinDir,	// Windows directory
LPTSTR  szAppDir,	// directory where related files are being installed
LPTSTR  szCurDir,	// receives path of directory where file is currently installed
PUINT  lpuCurDirLen,	// size of string in szCurDir
LPTSTR  szDestDir,	// receives path of recommended destination directory
PUINT  lpuDestDirLen	// size of string in szDestDir
);
Parameters

dwFlags

Contains a bitmask of flags. This parameter can be the following value:

Flag	Description
VFFF_ISSHAREDFILE	The source file can be shared by multiple applications. An application can use this information to determine where the file should be copied.
All other values are reserved.

szFileName

Points to the name of the file to be installed. The filename can include only the filename and extension, not a path.

szWinDir

Points to the directory in which Windows is running or will be run. This string is returned by the GetWindowsDirectory function.

szAppDir

Points to the directory where the installation program is installing a set of related files. If the installation program is installing an application, this is the directory where the application will reside. This parameter also points to the application's current directory unless otherwise specified.

szCurDir

Points to a buffer that receives the path to a current version of the file being installed. The path is a zero-terminated string. If a current version is not installed, the buffer will contain a zero-length string. The buffer should be at least _MAX_PATH characters long, although this is not required.

lpuCurDirLen

Points to a variable that contains the length of the szCurDir buffer. This pointer must not be NULL.

When the function returns, lpuCurDirLen contains the size, in characters, of the data returned in szCurDir, including the terminating null character. If the buffer is too small to contain all the data, lpuCurDirLen will be the size of the buffer required to hold the path.

szDestDir

Points to a buffer that receives the path to the installation location recommended by VerFindFile. The path is a zero-terminated string. The buffer should be at least _MAX_PATH characters long, although this is not required.

lpuDestDirLen

Points to a variable that contains the length of the szDestDir buffer. This pointer must not be NULL.

When the function returns, lpuDestDirLen contains the size, in characters, of the data returned in szDestDir, including the terminating null character. If the buffer is too small to contain all the data, lpuDestDirLen will be the size of the buffer needed to hold the path.

Return Value

The return value is a bitmask that indicates the status of the file. It can be one or more of the following values:

Value	Meaning
VFF_CURNEDEST	The currently installed version of the file is not in the recommended destination.
VFF_FILEINUSE	Windows is using the currently installed version of the file; therefore, the file cannot be overwritten or deleted.
VFF_BUFFTOOSMALL	At least one of the buffers was too small to contain the corresponding string. An application should check the output buffers to determine which buffer was too small.
All other values are reserved.

Remarks

VerFindFile searches for a copy of the specified file by using the OpenFile function. However, it determines the system directory from the specified Windows directory, or searches the path.

If the dwFlags parameter indicates that the file is private to this application (not VFFF_ISSHAREDFILE), VerFindFile recommends installing the file in the application's directory. Otherwise, if the system is running a shared copy of Windows, the function recommends installing the file in the Windows directory. If the system is running a private copy of Windows, the function recommends installing the file in the system directory.

See Also

GetWindowsDirectory, OpenFile, VerInstallFile


VerInstallFile
VerInstallFile  QuickInfo  Overview  Group

The VerInstallFile function attempts to install the specified file based on information returned from the VerFindFile function. VerInstallFile decompresses the file, if necessary, assigns a unique filename, and checks for errors, such as outdated files.

As with the other file installation functions, VerInstallFile will only work with Win32 file images. 16-bit Windows file images are not supported.

DWORD VerInstallFile(

DWORD  dwFlags,	// bit flags that condition function behavior
LPTSTR  szSrcFileName,	// file to install
LPTSTR  szDestFileName,	// new name of file to install
LPTSTR  szSrcDir,	// source directory of file to install
LPTSTR  szDestDir,	// directory in which to install file
LPTSTR  szCurDir,	// directory where file is currently installed
LPTSTR  szTmpFile,	// receives name of temporary copy of file used during installation
PUINT  lpuTmpFileLen	// size of string in szTmpFile
);
Parameters

dwFlags

Contains a bitmask of flags. This parameter can be one of the following values:

Flag	Description
VIFF_FORCEINSTALL	Installs the file regardless of mismatched version numbers. The function checks only for physical errors during installation.
VIFF_DONTDELETEOLD	Installs the file without deleting the previously installed file, if the previously installed file is not in the destination directory.
All other values are reserved.

szSrcFileName

Points to the name of the file to be installed. This is the filename in the directory pointed to by the szSrcDir parameter; the filename can include only the filename and extension, not a path.

szDestFileName

Points to the name VerInstallFile will give the new file upon installation. This filename may be different from the filename in the szSrcFileName directory. The new name should include only the filename and extension, not a path.

szSrcDir

Points to a buffer that contains the name of the directory where the new file is found.

szDestDir

Points to a buffer that contains the name of the directory where the new file should be installed. VerFindFile returns this value in its szDestDir parameter.

szCurDir

Points to a buffer that contains the name of the directory where the preexisting version of this file is found. VerFindFile returns this value in its szCurDir parameter.

szTmpFile

Points to a buffer that should be empty upon the initial call to VerInstallFile. The function fills the buffer with the name of a temporary copy of the source file. The buffer should be at least _MAX_PATH characters long, although this is not required.

lpuTmpFileLen

Points to a variable that contains the length of the szTmpFile buffer. This pointer must not be NULL.

When the function returns, lpuTmpFileLen contains the size, in characters, of the data returned in szTmpFile, including the terminating null character. If the buffer is too small to contain all the data, lpuTmpFileLen will be the size of the buffer required to hold the data.

Return Value

The return value is a bitmask that indicates exceptions. It can be one or more of the following values:

Value	Meaning
VIF_TEMPFILE	The temporary copy of the new file is in the destination directory. The cause of failure is reflected in other flags.
VIF_MISMATCH	The new and preexisting files differ in one or more attributes. This error can be overridden by calling VerInstallFile again with the VIFF_FORCEINSTALL flag set.
VIF_SRCOLD	The file to install is older than the preexisting file. This error can be overridden by calling VerInstallFile again with the VIFF_FORCEINSTALL flag set.
VIF_DIFFLANG	The new and preexisting files have different language or code-page values. This error can be overridden by calling VerInstallFile again with the VIFF_FORCEINSTALL flag set.
VIF_DIFFCODEPG	The new file requires a code page that cannot be displayed by the version of Windows currently running. This error can be overridden by calling VerInstallFile with the VIFF_FORCEINSTALL flag set.
VIF_DIFFTYPE	The new file has a different type, subtype, or operating system from the preexisting file. This error can be overridden by calling VerInstallFile again with the VIFF_FORCEINSTALL flag set.
VIF_WRITEPROT	The preexisting file is write protected. This error can be overridden by calling VerInstallFile again with the VIFF_FORCEINSTALL flag set.
VIF_FILEINUSE	The preexisting file is in use by Windows and cannot be deleted.
VIF_OUTOFSPACE	The function cannot create the temporary file due to insufficient disk space on the destination drive.
VIF_ACCESSVIOLATION	A read, create, delete, or rename operation failed due to an access violation.
VIF_SHARINGVIOLATION	A read, create, delete, or rename operation failed due to a sharing violation.
VIF_CANNOTCREATE	The function cannot create the temporary file. The specific error may be described by another flag.
VIF_CANNOTDELETE	The function cannot delete the destination file, or cannot delete the existing version of the file located in another directory. If the VIF_TEMPFILE bit is set, the installation failed, and the destination file probably cannot be deleted.
VIF_CANNOTDELETECUR	The existing version of the file could not be deleted and VIFF_DONTDELETEOLD was not specified.
VIF_CANNOTRENAME	The function cannot rename the temporary file, but already deleted the destination file.
VIF_OUTOFMEMORY	The function cannot complete the requested operation due to insufficient memory. Generally, this means the application ran out of memory attempting to expand a compressed file.
VIF_CANNOTREADSRC	The function cannot read the source file. This could mean that the path was not specified properly.
VIF_CANNOTREADDST	The function cannot read the destination (existing) files. This prevents the function from examining the file's attributes.
VIF_BUFFTOOSMALL	The szTmpFile buffer was too small to contain the name of the temporary source file. When the function returns, lpuTmpFileLen contains the size of the buffer required to hold the filename.
All other values are reserved.

Remarks

VerInstallFile copies the file from the source directory to the destination directory. If szCurDir indicates that a previous version of the file exists on the system, VerInstallFile compares the files' version stamp information. If the previously installed version of the file is more recent than the new version, or if the files' attributes are significantly different, for example, if they are in different languages, then VerInstallFile returns with one or more recoverable error codes.

VerInstallFile leaves the temporary file in the destination directory. The application can either override the error or delete the temporary file. If the application overrides the error, VerInstallFile deletes the previously installed version and renames the temporary file with the original filename.

See Also

VerFindFile


VerLanguageName
VerLanguageName  QuickInfo  Overview  Group

The VerLanguageName function converts the specified binary Microsoft language identifier into a text representation of the language.

DWORD VerLanguageName(

DWORD  idLang,	// Microsoft language identifier
LPTSTR  lpszLang,	// address of buffer for language string
DWORD  cbLang	// size of buffer
);
Parameters

idLang

Specifies the binary Microsoft language identifier. For example, VerLanguageName translates 0x040A into Castilian Spanish. If VerLanguageName does not recognize the identifier, the lpszLang parameter points to a default string ("Language-Neutral"). For a complete list of the language identifiers supported by Win32, see the following Remarks section.

lpszLang

Points to the buffer to receive the null-terminated string representing the language specified by the idLang parameter.

cbLang

Indicates the size of the buffer, in characters, pointed to by lpszLang.

Return Value

If the return value is less than or equal to the buffer size, the return value is the size, in characters, of the string returned in the buffer. This value does not include the terminating null character.

If the return value is greater than the buffer size, the return value is the size of the buffer required to hold the entire string. The string is truncated to the length of the existing buffer.

If an error occurs, the return value is zero. Unknown language identifiers do not produce errors.

Remarks

Typically, an installation program uses this function to translate a language identifier returned by the VerQueryValue function. The text string may be used in a dialog box that asks the user how to proceed in the event of a language conflict.

Following are the possible language identifiers and their corresponding languages:

Identifier	Language
0x0000	Language-Neutral
0x0400	Process Default Language
0x0401	Arabic
0x0402	Bulgarian
0x0403	Catalan
0x0404	Traditional Chinese
0x0804	Simplified Chinese
0x0405	Czech
0x0406	Danish
0x0407	German
0x0807	Swiss German
0x0408	Greek
0x0409	U.S. English
0x0809	U.K. English
0x0C09	Australian English
0x1009	Canadian English
0x040A	Castilian Spanish
0x080A	Mexican Spanish
0x0C0A	Modern Spanish
0x040B	Finnish
0x040C	French
0x080C	Belgian French
0x0C0C	Canadian French
0x100C	Swiss French
0x040D	Hebrew
0x040E	Hungarian
0x040F	Icelandic
0x0410	Italian
0x0810	Swiss Italian
0x0411	Japanese
0x0412	Korean
0x0413	Dutch
0x0813	Belgian Dutch
0x0414	Norwegian — Bokmål
0x0814	Norwegian — Nynorsk
0x0415	Polish
0x0416	Brazilian Portuguese
0x0816	Portuguese
0x0417	Rhaeto-Romanic
0x0418	Romanian
0x0419	Russian
0x041A	Croato-Serbian (Latin)
0x081A	Serbo-Croatian (Cyrillic)
0x041B	Slovak
0x041C	Albanian
0x041D	Swedish
0x041E	Thai
0x041F	Turkish
0x0420	Urdu
0x0421	Bahasa
See Also

VerQueryValue


VerQueryValue
VerQueryValue  QuickInfo  Overview  Group

The VerQueryValue function returns selected version information from the specified version-information resource. To retrieve the appropriate resource, the GetFileVersionInfo function must be called before VerQueryValue.

As with the other file installation functions, VerQueryValue will only work with Win32 file images. 16-bit Windows file images are not supported.

BOOL VerQueryValue(

const LPVOID  pBlock,	// address of buffer for version resource
LPTSTR  lpSubBlock,	// address of value to retrieve
LPVOID  *lplpBuffer,	// address of buffer for version pointer
PUINT  puLen	// address of version-value length buffer
);
Parameters

pBlock

Points to the buffer containing the version-information resource returned by GetFileVersionInfo.

lpSubBlock

Points to a zero-terminated string specifying which version-information value to retrieve. The string consists of names separated by backslashes (\) and can have one of the following forms:

Form	Description
\	Specifies the root block. The function retrieves a pointer to the VS_FIXEDFILEINFO structure for the version-information resource.
\VarFileInfo\Translation	Specifies the translation table in the variable information structure. The function retrieves a pointer to an array of language and character-set identifiers. An application uses these identifiers to create the name of a language-specific structure in the version-information resource.
\StringFileInfo\lang-charset\string-name	Specifies a value in a language-specific structure. The lang-charset name is a concatenation of a language and character-set identifier pair found in the translation table for the resource. The lang-charset name must be specified as a hexadecimal string. The string-name name is one of the predefined strings described in the following Remarks section.
lplpBuffer

Points to a buffer that receives a pointer to the version-information value.

puLen

Points to a buffer that receives the length, in characters, of the version-information value.

Return Value

If the specified structure exists and version information is available, the return value is nonzero. If the address of the length buffer is zero, no value is available for the specified version-information name. If the specified name does not exist or the specified resource is not valid, the return value is zero.

Remarks

The Win32 API contains the following predefined version information strings:

CompanyName FileDescription FileVersion InternalName LegalCopyright OriginalFilename ProductName ProductVersion

The following example shows how to retrieve the FileDescription string-value from a block of version information:

VerQueryValue(pBlock,

              TEXT("\\StringFileInfo\\040904E4\\FileDescription"),

              &lpBuffer,

              &dwBytes);

Call the GetFileVersionInfoSize and GetFileVersionInfo functions to properly initialize the pBlock buffer before calling the VerQueryValue function.

See Also

GetFileVersionInfo, GetFileVersionInfoSize, VS_FIXEDFILEINFO, VS_VERSION_INFO


VirtualAlloc
VirtualAlloc  QuickInfo  Overview  Group

The VirtualAlloc function reserves or commits a region of pages in the virtual address space of the calling process. Memory allocated by this function is automatically initialized to zero.

LPVOID VirtualAlloc(

LPVOID  lpvAddress,	// address of region to reserve or commit
DWORD  cbSize,	// size of region
DWORD  fdwAllocationType,	// type of allocation
DWORD  fdwProtect	// type of access protection
);
Parameters

lpvAddress

Specifies the desired starting address of the region to allocate. If the memory is being reserved, the specified address is rounded down to the next 64-kilobyte boundary. If the memory is already reserved and is being committed, the address is rounded down to the next page boundary. To determine the size of a page on the host computer, use the GetSystemInfo function. If this parameter is NULL, the system determines where to allocate the region.

cbSize

Specifies the size, in bytes, of the region. If the lpvAddress parameter is NULL, this value is rounded up to the next page boundary. Otherwise, the allocated pages include all pages containing one or more bytes in the range from lpvAddress to (lpvAddress+cbSize). This means that a 2-byte range straddling a page boundary causes both pages to be included in the allocated region.

fdwAllocationType

Specifies the type of allocation. You can specify any combination of the following flags:

Flag	Meaning
MEM_COMMIT	Allocates physical storage in memory or in the paging file on disk for the specified region of pages.
	An attempt to commit an already committed page will not cause the function to fail. This means that a range of committed or decommitted pages can be committed without having to worry about a failure.
MEM_RESERVE	Reserves a range of the process's virtual address space without allocating any physical storage. The reserved range cannot be used by any other allocation operations (the malloc function, the LocalAlloc function, and so on) until it is released. Reserved pages can be committed in subsequent calls to the VirtualAlloc function.
MEM_TOP_DOWN	Allocates memory at the highest possible address.
fdwProtect

Specifies the type of access protection. If the pages are being committed, any one of the following flags can be specified, along with the PAGE_GUARD and PAGE_NOCACHE protection modifier flags, as desired:

Flag	Meaning
PAGE_READONLY	Enables read access to the committed region of pages. An attempt to write to the committed region results in an access violation. If the system differentiates between read-only access and execute access, an attempt to execute code in the committed region results in an access violation.
PAGE_READWRITE	Enables both read and write access to the committed region of pages.
PAGE_EXECUTE	Enables execute access to the committed region of pages. An attempt to read or write to the committed region results in an access violation.
PAGE_EXECUTE_READ	Enables execute and read access to the committed region of pages. An attempt to write to the committed region results in an access violation.
PAGE_EXECUTE_READWRITE	Enables execute, read, and write access to the committed region of pages.
PAGE_GUARD	Pages in the region become guard pages. Any attempt to read from or write to a guard page causes the operating system to raise a STATUS_GUARD_PAGE exception and turn off the guard page status. Guard pages thus act as a one-shot access alarm. The PAGE_GUARD flag is a page protection modifier. An application uses it with one of the other page protection flags, with one exception: It cannot be used with PAGE_NOACCESS. When an access attempt leads the operating system to turn off guard page status, the underlying page protection takes over. If a guard page exception occurs during a system service, the service typically returns a failure status indicator.
PAGE_NOACCESS	Disables all access to the committed region of pages. An attempt to read from, write to, or execute in the committed region results in an access violation exception, called a general protection (GP) fault.
PAGE_NOCACHE	Allows no caching of the committed regions of pages. The hardware attributes for the physical memory should be specified as "no cache." This is not recommended for general usage. It is useful for device drivers; for example, mapping a video frame buffer with no caching. This flag is a page protection modifier, only valid when used with one of the page protections other than PAGE_NOACCESS.
Return Value

If the function succeeds, the return value is the base address of the allocated region of pages.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

VirtualAlloc can perform the following operations:

•	Commit a region of pages reserved by a previous call to the VirtualAlloc function.

•	Reserve a region of free pages.

•	Reserve and commit a region of free pages.

You can use VirtualAlloc to reserve a block of pages and then make additional calls to VirtualAlloc to commit individual pages from the reserved block. This enables a process to reserve a range of its virtual address space without consuming physical storage until it is needed.

Each page in the process's virtual address space is in one of three states:

State	Meaning
Free	The page is not committed or reserved and is not accessible to the process. VirtualAlloc can reserve, or simultaneously reserve and commit, a free page.
Reserved	The range of addresses cannot be used by other allocation functions, but the page is not accessible and has no physical storage associated with it. VirtualAlloc can commit a reserved page, but it cannot reserve it a second time. The VirtualFree function can release a reserved page, making it a free page.
Committed	Physical storage is allocated for the page, and access is controlled by a protection code. The system initializes and loads each committed page into physical memory only at the first attempt to read or write to that page. When the process terminates, the system releases the storage for committed pages. VirtualAlloc can commit an already committed page. This means that you can commit a range of pages, regardless of whether they have already been committed, and the function will not fail. VirtualFree can decommit a committed page, releasing the page's storage, or it can simultaneously decommit and release a committed page.
If the lpvAddress parameter is not NULL, the function uses the lpvAddress and cbSize parameters to compute the region of pages to be allocated. The current state of the entire range of pages must be compatible with the type of allocation specified by the fdwAllocationType parameter. Otherwise, the function fails and none of the pages are allocated. This compatibility requirement does not preclude committing an already committed page; see the preceding list.

The PAGE_GUARD protection modifier flag establishes guard pages. Guard pages act as one-shot access alarms. See Guard Pages.

See Also

GlobalAlloc, HeapAlloc, VirtualFree, VirtualLock, VirtualProtect, VirtualQuery


VirtualFree
VirtualFree  QuickInfo  Overview  Group

The VirtualFree function releases or decommits (or both) a region of pages within the virtual address space of the calling process.

BOOL VirtualFree(

LPVOID  lpvAddress,	// address of region of committed pages
DWORD  cbSize,	// size of region
DWORD  fdwFreeType	// type of free operation
);
Parameters

lpvAddress

Points to the base address of the region of pages to be freed. If the fdwFreeType parameter includes the MEM_RELEASE flag, this parameter must be the base address returned by the VirtualAlloc function when the region of pages was reserved.

cbSize

Specifies the size, in bytes, of the region to be freed. If the fdwFreeType parameter includes the MEM_RELEASE flag, this parameter must be zero. Otherwise, the region of affected pages includes all pages containing one or more bytes in the range from the lpvAddress parameter to (lpvAddress+cbSize). This means that a 2-byte range straddling a page boundary causes both pages to be freed.

fdwFreeType

Specifies the type of free operation. One, but not both, of the following flags can be specified:

Flag	Meaning
MEM_DECOMMIT	Decommits the specified region of committed pages.
	An attempt to decommit an uncommitted page will not cause the function to fail. This means that a range of committed or uncommitted pages can be decommitted without having to worry about a failure.
MEM_RELEASE	Releases the specified region of reserved pages. If this flag is specified, the cbSize parameter must be zero, or the function fails.
Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

VirtualFree can perform one of the following operations:

•	Decommit a region of committed or uncommitted pages.

•	Release a region of reserved pages.

•	Decommit and release a region of committed or uncommitted pages.

To release a region of pages, the entire range of pages must be in the same state (all reserved or all committed) and the entire region originally reserved by the VirtualAlloc function must be released at the same time. If only part of the pages in the original reserved region are committed, you must first call VirtualFree to decommit the committed pages and then call VirtualFree again to release the entire block.

Pages that have been released are free pages available for subsequent allocation operations. Attempting to read from or write to a free page results in an access violation exception.

VirtualFree can decommit an uncommitted page; this means that a range of committed or uncommitted pages can be decommitted without having to worry about a failure. Decommitting a page releases its physical storage, either in memory or in the paging file on disk. If a page is decommitted but not released, its state changes to reserved, and it can be committed again by a subsequent call to VirtualAlloc. Attempting to read from or write to a reserved page results in an access violation exception.

The current state of the entire range of pages must be compatible with the type of free operation specified by the fdwFreeType parameter. Otherwise, the function fails and no pages are released or decommitted.

See Also

GlobalAlloc, GlobalFree, VirtualAlloc


VirtualLock
VirtualLock  QuickInfo  Overview  Group

The VirtualLock function locks the specified region of the process's virtual address space into memory, ensuring that subsequent access to the region will not incur a page fault.

BOOL VirtualLock(

LPVOID  lpvAddress,	// address of first byte of range to lock
DWORD  cbSize	// number of bytes in range to lock
);
Parameters

lpvAddress

Points to the base address of the region of pages to be locked.

cbSize

Specifies the size, in bytes, of the region to be locked. The region of affected pages includes all pages that contain one or more bytes in the range from the lpvAddress parameter to (lpvAddress+cbSize). This means that a 2-byte range straddling a page boundary causes both pages to be locked.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

All pages in the specified region must be committed. Memory protected with the PAGE_NOACCESS flag cannot be locked.

Locking pages into memory may degrade the performance of the system by reducing the available RAM and forcing the system to swap out other critical pages to the paging file. By default, a process can lock a maximum of 30 pages. The default limit is intentionally small to avoid severe performance degradation. Applications that need to lock larger numbers of pages must first call the SetProcessWorkingSetSize function to increase their minimum and maximum working set sizes. The maximum number of pages that a process can lock is equal to the number of pages in its minimum working set minus a small overhead.

Pages that a process has locked remain resident even when the process is idle for extended periods.

To unlock a region of locked pages, use the VirtualUnlock function. Locked pages are automatically unlocked when the process terminates.

This function is not like the GlobalLock or LocalLock function in that it does not increment a lock count and translate a handle into a pointer. There is no lock count for virtual pages, so multiple calls to the VirtualUnlock function are never required to unlock a region of pages.

Windows 95

On Windows 95, the VirtualLock function is implemented as a stub that has no effect and always returns TRUE.

See Also

GlobalLock, LocalLock, SetProcessWorkingSetSize, VirtualUnlock


VirtualProtect
VirtualProtect  QuickInfo  Overview  Group

The VirtualProtect function changes the access protection on a region of committed pages in the virtual address space of the calling process. This function differs from VirtualProtectEx, which changes the access protection of any process.

BOOL VirtualProtect(

LPVOID  lpvAddress,	// address of region of committed pages
DWORD  cbSize,	// size of the region
DWORD  fdwNewProtect,	// desired access protection
PDWORD  pfdwOldProtect	// address of variable to get old protection
);
Parameters

lpvAddress

Points to the base address of the region of pages whose access protection attributes are to be changed.

cbSize

Specifies the size, in bytes, of the region whose access protection attributes are to be changed. The region of affected pages includes all pages containing one or more bytes in the range from the lpvAddress parameter to (lpvAddress+cbSize). This means that a 2-byte range straddling a page boundary causes the protection attributes of both pages to be changed.

fdwNewProtect

Specifies the new access protection. You can specify any one of the following flags, along with the PAGE_GUARD and PAGE_NOCACHE protection modifier flags, as necessary:

Value	Meaning
PAGE_READONLY	Enables read access to the committed region of pages. An attempt to write to the committed region results in an access violation. If the system differentiates between read-only access and execute access, an attempt to execute code in the committed region results in an access violation.
PAGE_READWRITE	Enables both read and write access to the committed region of pages.
PAGE_WRITECOPY	Gives copy-on-write access to the committed region of pages.
PAGE_EXECUTE	Enables execute access to the committed region of pages. An attempt to read or write to the committed region results in an access violation.
PAGE_EXECUTE_READ	Enables execute and read access to the committed region of pages. An attempt to write to the committed region results in an access violation.
PAGE_EXECUTE_READWRITE	Enables execute, read, and write access to the committed region of pages.
PAGE_EXECUTE_WRITECOPY	Enables execute, read, and write access to the committed region of pages. The pages are shared read-on-write and copy-on-write.
PAGE_GUARD	Pages in the region become guard pages. Any attempt to access a guard page causes the operating system to raise a STATUS_GUARD_PAGE exception and turn off the guard page status. Guard pages thus act as a one-shot access alarm. The PAGE_GUARD flag is a page protection modifier. An application uses it with one of the other page protection flags, with one exception: it cannot be used with PAGE_NOACCESS. When an access attempt leads the operating system to turn off guard page status, the underlying page protection takes over. If a guard page exception occurs during a system service, the service typically returns a failure status indicator.
PAGE_NOACCESS	Disables all access to the committed region of pages. An attempt to read from, write to, or execute in the committed region results in an access violation exception, called a general protection (GP) fault.
PAGE_NOCACHE	Allows no caching of the committed regions of pages. The hardware attributes for the physical memory should be specified as "no cache." This is not recommended for general usage. It is useful for device drivers; for example, mapping a video frame buffer with no caching. This flag is a page protection modifier, only valid when used with one of the page protections other than PAGE_NOACCESS.
pfdwOldProtect

Points to a variable that the function sets to the previous access protection value of the first page in the specified region of pages. If this parameter is NULL or does not point to a valid variable, the function fails.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

You can set the access protection value on committed pages only. If the state of any page in the specified region is not committed, the function fails and returns without modifying the access protection of any pages in the specified region.

The VirtualProtect function changes the access protection of memory in the calling process, and the VirtualProtectEx function changes the access protection of memory in a specified process.

The PAGE_GUARD protection modifier flag establishes guard pages. Guard pages act as one-shot access alarms. See Guard Pages for further discussion of guard pages.

See Also

VirtualAlloc, VirtualProtectEx


VirtualProtectEx
VirtualProtectEx  QuickInfo  Overview  Group

The VirtualProtectEx function changes the access protection on a region of committed pages in the virtual address space of a specified process. Note that this function differs from VirtualProtect, which changes the access protection on the calling process only.

BOOL VirtualProtectEx(

HANDLE  hProcess,	// handle of process
LPVOID  lpvAddress,	// address of region of committed pages
DWORD  cbSize,	// size of region
DWORD  fdwNewProtect,	// desired access protection
PDWORD  pfdwOldProtect	// address of variable to get old protection
);
Parameters

hProcess

Identifies the process whose memory protection is to be changed. The handle must have PROCESS_VM_OPERATION access. For more information on PROCESS_VM_OPERATION, see OpenProcess.

lpvAddress

Points to the base address of the region of pages whose access protection attributes are to be changed.

cbSize

Specifies the size, in bytes, of the region whose access protection attributes are changed. The region of affected pages includes all pages containing one or more bytes in the range from the lpvAddress parameter to (lpvAddress+cbSize). This means that a 2-byte range straddling a page boundary causes the protection attributes of both pages to be changed.

fdwNewProtect

Specifies the new access protection. Any one of the following flags can be specified, along with the PAGE_GUARD and PAGE_NOCACHE protection modifier flags, as desired:

Value	Meaning
PAGE_READONLY	Enables read access to the committed region of pages. An attempt to write to the committed region results in an access violation. If the system differentiates between read-only access and execute access, an attempt to execute code in the committed region results in an access violation.
PAGE_READWRITE	Enables both read and write access to the committed region of pages.
PAGE_WRITECOPY	Gives copy-on-write access to the committed region of pages.
PAGE_EXECUTE	Enables execute access to the committed region of pages. An attempt to read or write to the committed region results in an access violation.
PAGE_EXECUTE_READ	Enables execute and read access to the committed region of pages. An attempt to write to the committed region results in an access violation.
PAGE_EXECUTE_READWRITE	Enables execute, read, and write access to the committed region of pages.
PAGE_EXECUTE_WRITECOPY	Enables execute, read, and write access to the committed region of pages. The pages are shared read-on-write and copy-on-write.
PAGE_GUARD	Pages in the region become guard pages. Any attempt to read from or write to a guard page causes the operating system to raise a STATUS_GUARD_PAGE exception, and turn off the guard page status. Guard pages thus act as a one-shot access alarm. The PAGE_GUARD flag is a page protection modifier. An application uses it with one of the other page protection flags, with one exception: it cannot be used with PAGE_NOACCESS. When an access attempt leads the operating system to turn off guard page status, the underlying page protection takes over. If a guard page exception occurs during a system service, the service typically returns a failure status indicator.
PAGE_NOACCESS	Disables all access to the committed region of pages. An attempt to read from, write to, or execute in the committed region results in an access violation exception, called a general protection (GP) fault.
PAGE_NOCACHE	Allows no caching of the committed regions of pages. The hardware attributes for the physical memory should be set to "no cache." This is not recommended for general usage. It is useful for device drivers; for example, mapping a video frame buffer with no caching. This flag is a page protection modifier, only valid when used with one of the page protections other than PAGE_NOACCESS.
pfdwOldProtect

Points to a variable that receives the previous access protection of the first page in the specified region of pages. If this parameter is NULL or does not point to a valid variable, the function fails.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The access protection value can be set only on committed pages. If the state of any page in the specified region is not committed, the function fails and returns without modifying the access protection of any pages in the specified region.

VirtualProtectEx is identical to the VirtualProtect function except that it changes the access protection of memory in a specified process.

The PAGE_GUARD protection modifier flag establishes guard pages. Guard pages act as one-shot access alarms. See Guard Pages. for further discussion of guard pages.

See Also

VirtualAlloc, VirtualProtect, VirtualQueryEx


VirtualQuery
VirtualQuery  QuickInfo  Overview  Group

The VirtualQuery function provides information about a range of pages in the virtual address space of the calling process.

DWORD VirtualQuery(

LPCVOID  lpvAddress,	// address of region
PMEMORY_BASIC_INFORMATION  pmbiBuffer,	// address of information buffer
DWORD  cbLength	// size of buffer
);
Parameters

lpvAddress

Points to the base address of the region of pages to be queried. This value is rounded down to the next page boundary. To determine the size of a page on the host computer, use the GetSystemInfo function.

pmbiBuffer

Points to a MEMORY_BASIC_INFORMATION structure in which information about the specified page range is returned.

cbLength

Specifies the size, in bytes, of the buffer pointed to by the pmbiBuffer parameter.

Return Value

The return value is the actual number of bytes returned in the information buffer.

Remarks

VirtualQuery provides information about a region of consecutive pages beginning at a specified address that share the following attributes:

•	The state of all pages is the same with the MEM_COMMIT, MEM_RESERVE, MEM_FREE, MEM_PRIVATE, MEM_MAPPED, or MEM_IMAGE flag.

•	If the initial page is not free, all pages in the region are part of the same initial allocation of pages reserved by a call to the VirtualAlloc function.

•	The access of all pages is the same with the PAGE_READONLY, PAGE_READWRITE, PAGE_NOACCESS, PAGE_WRITECOPY, PAGE_EXECUTE, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_EXECUTE_WRITECOPY, PAGE_GUARD, or PAGE_NOCACHE flag.

The function determines the attributes of the first page in the region and then scans subsequent pages until it scans the entire range of pages or until it encounters a page with a nonmatching set of attributes. The function returns the attributes and the size, in bytes, of the region of pages with matching attributes. For example, if there is a 40 megabyte (MB) region of free memory, and VirtualQuery is called on a page that is 10 MB into the region, the function will obtain a state of MEM_FREE and a size of 30 MB.

This function reports on a region of pages in the memory of the calling process, and the VirtualQueryEx function reports on a region of pages in the memory of a specified process.

See Also

GetSystemInfo, MEMORY_BASIC_INFORMATION, VirtualQueryEx


VirtualQueryEx
VirtualQueryEx  QuickInfo  Overview  Group

The VirtualQueryEx function provides information about a range of pages within the virtual address space of a specified process.

DWORD VirtualQueryEx(

HANDLE  hProcess,	// handle of process
LPCVOID  lpvAddress,	// address of region
PMEMORY_BASIC_INFORMATION  pmbiBuffer,	// address of information buffer
DWORD  cbLength	// size of buffer
);
Parameters

hProcess

Identifies the process whose memory information is queried. The handle must have PROCESS_QUERY_INFORMATION access.

lpvAddress

Points to the base address of the region of pages to be queried. This value is rounded down to the next page boundary. To determine the size of a page on the host computer, use the GetSystemInfo function.

pmbiBuffer

Points to a MEMORY_BASIC_INFORMATION structure in which information about the specified page range is returned.

cbLength

Specifies the size, in bytes, of the buffer pointed to by the pmbiBuffer parameter.

Return Value

The return value is the actual number of bytes returned in the information buffer.

Remarks

VirtualQueryEx provides information about a region of consecutive pages beginning at a specified address that share the following attributes:

•	The state of all pages is the same with the MEM_COMMIT, MEM_RESERVE, MEM_FREE, MEM_PRIVATE, MEM_MAPPED, or MEM_IMAGE flag.

•	If the initial page is not free, all pages in the region are part of the same initial allocation of pages reserved by a call to the VirtualAlloc function.

•	The access of all pages is the same with the PAGE_READONLY, PAGE_READWRITE, PAGE_NOACCESS, PAGE_WRITECOPY, PAGE_EXECUTE, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_EXECUTE_WRITECOPY, PAGE_GUARD, or PAGE_NOCACHE flag.

The VirtualQueryEx function determines the attributes of the first page in the region and then scans subsequent pages until it scans the entire range of pages, or until it encounters a page with a nonmatching set of attributes. The function returns the attributes and the size, in bytes, of the region of pages with matching attributes. For example, if there is a 40 megabyte (MB) region of free memory, and VirtualQueryEx is called on a page that is 10 MB into the region, the function will obtain a state of MEM_FREE and a size of 30 MB.

This function is identical to the VirtualQuery function, except that it enables access to information about memory in a specified process.

See Also

GetSystemInfo, MEMORY_BASIC_INFORMATION, VirtualAlloc, VirtualProtectEx, VirtualQuery


VirtualUnlock
VirtualUnlock  QuickInfo  Overview  Group

The VirtualUnlock function unlocks a specified range of pages in the virtual address space of a process, enabling the system to swap the pages out to the paging file if necessary.

BOOL VirtualUnlock(

LPVOID  lpvAddress,	// address of first byte of range
DWORD  cbSize	// number of bytes in range
);
Parameters

lpvAddress

Points to the base address of the region of pages to be unlocked.

cbSize

Specifies the size, in bytes, of the region being unlocked. The region of affected pages includes all pages containing one or more bytes in the range from the lpvAddress parameter to (lpvAddress+cbSize). This means that a 2-byte range straddling a page boundary causes both pages to be unlocked.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

For the function to succeed, the range specified need not match a range passed to a previous call to the VirtualLock function, but all pages in the range must be locked.

See Also

VirtualLock


VkKeyScan
VkKeyScan  QuickInfo  Overview  Group

The VkKeyScan function translates a character to the corresponding virtual-key code and shift state for the current keyboard.

SHORT VkKeyScan(

TCHAR  ch	// character to translate
);
Parameters

ch

Specifies the character to be translated into a virtual-key code.

Return Value

If the function succeeds, the low-order byte of the return value contains the virtual-key code and the high-order byte contains the shift state, which can be a combination of the following flag bits:

Bit	Meaning
1	Either SHIFT key is pressed.
2	Either CTRL key is pressed.
4	Either ALT key is pressed.
If the function finds no key that translates to the passed character code, both the low-order and high-order bytes contain −1.

Remarks

For keyboard layouts that use the right-hand ALT key as a shift key (for example, the French keyboard layout), the shift state is represented by the value 6, because the right-hand ALT key is converted internally into CTRL+ALT.

Translations for the numeric keypad (VK_NUMPAD0 through VK_DIVIDE) are ignored. This function is intended to translate characters into keystrokes from the main keyboard section only. For example, the character "7" is translated into VK_7, not VK_NUMPAD7.

VkKeyScan is used by applications that send characters by using the WM_KEYUP and WM_KEYDOWN messages.

See Also

GetAsyncKeyState, GetKeyboardState, GetKeyNameText, GetKeyState, SetKeyboardState, WM_KEYDOWN, WM_KEYUP


VkKeyScanEx [New - Windows 95]
VkKeyScanEx  QuickInfo

[New - Windows 95]

The VkKeyScanEx function translates a character to the corresponding virtual-key code and shift state. The function translates the character using the input language and physical keyboard layout identified by the given keyboard layout handle.

SHORT VkKeyScanEx(

UINT  uChar,	// character to translate
HKL  hkl	// keyboard layout handle
);
Parameters

uChar

Specifies the character to be translated into a virtual-key code.

hkl

Identifies the keyboard layout to use to translate the character. This parameter can be any keyboard layout handle previously returned by the LoadKeyboardLayout function.

Return Value

If the function succeeds, the low-order byte of the return value contains the virtual-key code and the high-order byte contains the shift state, which can be a combination of the following flag bits:

Bit	Meaning
1	Either SHIFT key is pressed.
2	Either CTRL key is pressed.
4	Either ALT key is pressed.
If the function finds no key that translates to the passed character code, both the low-order and high-order bytes contain −1.

Remarks

For keyboard layouts that use the right-hand ALT key as a shift key (for example, the French keyboard layout), the shift state is represented by the value 6, because the right-hand ALT key is converted internally into CTRL+ALT.

Translations for the numeric keypad (VK_NUMPAD0 through VK_DIVIDE) are ignored. This function is intended to translate characters into keystrokes from the main keyboard section only. For example, the character "7" is translated into VK_7, not VK_NUMPAD7.

VkKeyScanEx is used by applications that send characters by using the WM_KEYUP and WM_KEYDOWN messages.

See Also

GetAsyncKeyState, GetKeyboardState, GetKeyNameText, GetKeyState, LoadKeyboardLayout, SetKeyboardState, ToAsciiEx, VkKeyScan


WaitCommEvent
WaitCommEvent  QuickInfo  Overview  Group

The WaitCommEvent function waits for an event to occur for a specified communications device. The set of events that are monitored by this function is contained in the event mask associated with the device handle.

BOOL WaitCommEvent(

HANDLE  hCommDev,	// handle of communications device
LPDWORD  lpfdwEvtMask,	// address of variable for event that occurred
LPOVERLAPPED  lpo,	// address of overlapped structure
);
Parameters

hCommDev

Identifies the communications device. The CreateFile function returns this handle.

lpfdwEvtMask

Points to a 32-bit variable that receives a mask indicating the type of event that occurred. If an error occurs, the value is zero; otherwise, it is one of the following values:

Value	Meaning
EV_BREAK	A break was detected on input.
EV_CTS	The CTS (clear-to-send) signal changed state.
EV_DSR	The DSR (data-set-ready) signal changed state.
EV_ERR	A line-status error occurred. Line-status errors are CE_FRAME, CE_OVERRUN, and CE_RXPARITY.
EV_RING	A ring indicator was detected.
EV_RLSD	The RLSD (receive-line-signal-detect) signal changed state.
EV_RXCHAR	A character was received and placed in the input buffer.
EV_RXFLAG	The event character was received and placed in the input buffer. The event character is specified in the device's DCB structure, which is applied to a serial port by using the SetCommState function.
EV_TXEMPTY	The last character in the output buffer was sent.
lpo

Points to an OVERLAPPED structure. This parameter is ignored if the hCommDev handle was opened without specifying the FILE_FLAG_OVERLAPPED flag. If an overlapped operation is not desired, this parameter can be NULL.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The WaitCommEvent function monitors a set of events for a specified communications resource. To set and query the current event mask of a communications resource, use the SetCommMask and GetCommMask functions.

If the lpo parameter is NULL or the hCommDev handle was opened without specifying the FILE_FLAG_OVERLAPPED flag, WaitCommEvent does not return until one of the specified events or an error occurs.

If lpo points to an OVERLAPPED structure and FILE_FLAG_OVERLAPPED was specified when the hCommDev handle was opened, WaitCommEvent is performed as an overlapped operation. In this case, the OVERLAPPED structure must contain a handle to a manual-reset event object (created by using the CreateEvent function).

If the overlapped operation cannot be completed immediately, the function returns FALSE and the GetLastError function returns ERROR_IO_PENDING, indicating that the operation is executing in the background. When this happens, the system sets the hEvent member of the OVERLAPPED structure to the not-signaled state before WaitCommEvent returns, and then it sets it to the signaled state when one of the specified events or an error occurs. The calling process can use a wait function to determine the event object's state and then use the GetOverlappedResult function to determine the results of the WaitCommEvent operation. GetOverlappedResult reports the success or failure of the operation, and the variable pointed to by the lpfdwEvtMask parameter is set to indicate the event that occurred.

If a process attempts to change the device handle's event mask by using the SetCommMask function while an overlapped WaitCommEvent operation is in progress, WaitCommEvent returns immediately. The variable pointed to by the lpfdwEvtMask parameter is set to zero.

See Also

CreateFile, DCB, GetCommMask, GetOverlappedResult, OVERLAPPED, SetCommMask, SetCommState


WaitForDebugEvent
WaitForDebugEvent  QuickInfo  Overview  Group

The WaitForDebugEvent function waits for a debugging event to occur in a process being debugged.

BOOL WaitForDebugEvent(

LPDEBUG_EVENT  lpde,	// address of structure for event information
DWORD  dwTimeout	// number of milliseconds to wait for event
);
Parameters

lpde

Points to a DEBUG_EVENT structure that is filled with information about the debugging event.

dwTimeout

Specifies the number of milliseconds to wait for a debugging event. If this parameter is zero, the function tests for a debugging event and returns immediately. If the parameter is INFINITE, the function does not return until a debugging event has occurred.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Only the thread that created the process being debugged can call WaitForDebugEvent.

See Also

ContinueDebugEvent, CreateProcess, DebugActiveProcess, DebugBreak, DEBUG_EVENT, OutputDebugString


WaitForInputIdle
WaitForInputIdle  QuickInfo  Overview  Group

The WaitForInputIdle function waits until the given process is waiting for user input with no input pending, or until the time-out interval has elapsed.

The WaitForInputIdle function only works with GUI applications. If a console application calls the function, it returns immediately, with no wait.

DWORD WaitForInputIdle(

HANDLE  hProcess,	// handle to process
DWORD  dwTimeout	// time-out interval in milliseconds
);
Parameters

hProcess

Identifies the process.

dwTimeout

Specifies the time-out interval, in milliseconds. If dwTimeout is INFINITE, the function does not return until the process is idle.

Return Value

The following table shows the possible return values:

Value	Meaning
0	The wait was satisfied successfully.
WAIT_TIMEOUT	The wait was terminated because the time-out interval elapsed.
0xFFFFFFFF	An error occurred. To get extended error information, use the GetLastError function.
Remarks

The WaitForInputIdle function enables a thread to suspend its execution until a specified process has finished its initialization and is waiting for user input with no input pending. This can be useful for synchronizing a parent process and a newly created child process. When a parent process creates a child process, the CreateProcess function returns without waiting for the child process to finish its initialization. Before trying to communicate with the child process, the parent process can use WaitForInputIdle to determine when the child's initialization has been completed. For example, the parent process should use WaitForInputIdle before trying to find a window associated with the child process.

The WaitForInputIdle function can be used at any time, not just during application startup.

See Also

CreateProcess


WaitForMultipleObjects
WaitForMultipleObjects  QuickInfo  Overview  Group

The WaitForMultipleObjects function returns either when any one or when all of the specified objects are in the signaled state, or when the time-out interval elapses.

DWORD WaitForMultipleObjects(

DWORD  cObjects,	// number of handles in handle array
CONST HANDLE *  lphObjects,	// address of object-handle array
BOOL  fWaitAll,	// wait flag
DWORD  dwTimeout	// time-out interval in milliseconds
);
Parameters

cObjects

Specifies the number of object handles in the array pointed to by lphObjects. The maximum number of object handles is MAXIMUM_WAIT_OBJECTS.

lphObjects

Points to an array of object handles. For a list of the object types whose handles can be specified, see the following Remarks section. The array can contain handles of objects of different types.

Windows NT: The handles must have SYNCHRONIZE access.

fWaitAll

Specifies the wait type. If TRUE, the function returns when all objects in the lphObjects array are signaled at the same time. If FALSE, the function returns when any one of the objects is signaled. In the latter case, the return value indicates the object whose state caused the function to return.

dwTimeout

Specifies the time-out interval, in milliseconds. The function returns if the interval elapses, even if the conditions specified by the fWaitAll parameter are not satisfied. If dwTimeout is zero, the function tests the states of the specified objects and returns immediately. If dwTimeout is INFINITE, the function's time-out interval never elapses.

Return Value

If the function succeeds, the return value indicates the event that caused the function to return.

If the function fails, the return value is WAIT_FAILED. To get extended error information, call GetLastError.

The return value upon success is one of the following values:

Value	Meaning
WAIT_OBJECT_0 to (WAIT_OBJECT_0 + cObjects − 1)	If fWaitAll is TRUE, the return value indicates that the state of all specified objects is signaled.  If fWaitAll is FALSE, the return value minus WAIT_OBJECT_0 indicates the lphObjects array index of the object that satisfied the wait. If more than one object became signalled during the call, this is the array index of the signalled object with the smallest index value of all the signalled objects.
WAIT_ABANDONED_0 to (WAIT_ABANDONED_0 + cObjects − 1)	If fWaitAll is TRUE, the return value indicates that the state of all specified objects is signaled and at least one of the objects is an abandoned mutex object.  If fWaitAll is FALSE, the return value minus WAIT_ABANDONED_0 indicates the lphObjects array index of an abandoned mutex object that satisfied the wait.
WAIT_TIMEOUT	The time-out interval elapsed and the conditions specified by the fWaitAll parameter are not satisfied.
Remarks

The WaitForMultipleObjects function determines whether the conditions exist that satisfy the wait. If the wait is not satisfied, the calling thread enters an efficient wait state, consuming very little processor time while waiting for one of the conditions of the wait to be satisfied.

When fWaitAll is TRUE, the function's wait condition is satisfied only when the state of all objects is signaled at the same time. The function does not modify the state of the specified objects until all objects are simultaneously signaled. For example, a mutex can be signaled, but the thread does not get ownership until the other objects are also signaled. In the meantime, some other thread may get ownership of the mutex, thereby delaying satisfaction of the wait condition.

The system adjusts the state of some types of objects after the object's signaled state satisfies a wait condition. For example, the count of a semaphore object is decreased by one.

The WaitForMultipleObjects function can specify handles of any of the following object types in the lphObjects array:

Object	Description
Change notification	The handle is returned by the FindFirstChangeNotification function. A change notification object's state is signaled when a specified type of change occurs within a specified directory or directory tree.
Console input	The handle is returned by the CreateFile function when CONIN$ is specified, or by the GetStdHandle function. The object's state is signaled when there is unread input in the console's input buffer, and it is nonsignaled when the input buffer is empty.
Event	The handle is returned by the CreateEvent or OpenEvent function. An event object's state is set explicitly to signaled by the SetEvent or PulseEvent function. A manual-reset event object's state must be reset explicitly to nonsignaled by the ResetEvent function. For an auto-reset event object, the wait function resets the object's state to nonsignaled before returning. Event objects are also used in overlapped operations, in which the state is set by the system.
Mutex	The handle is returned by the CreateMutex or OpenMutex function. A mutex object's state is signaled when it is not owned by any thread. The wait function requests ownership of the mutex for the calling thread, changing the mutex's state to nonsignaled when ownership is granted.
Process	The handle is returned by the CreateProcess or OpenProcess function. A process object's state is signaled when the process terminates.
Thread	The handle is returned by the CreateProcess, CreateThread, or CreateRemoteThread function. A thread object's state is signaled when the thread terminates.
Semaphore	The handle is returned by the CreateSemaphore or OpenSemaphore function. A semaphore object maintains a count between zero and some maximum value. Its state is signaled when its count is greater than zero and nonsignaled when its count is zero. If the current state is signaled, the wait function decreases the count by one.
An abandoned mutex object is not released by the thread that owned the mutex object before the owning thread terminated. Ownership of the mutex object is granted to the calling thread, and the mutex is set to nonsignaled.

In some circumstances, a wait function can specify a handle of a file, named pipe, or communications device as an object to wait for. However, their use for this purpose is discouraged.

See Also

CreateEvent, CreateFile, CreateMutex, CreateProcess, CreateRemoteThread, CreateSemaphore, CreateThread, FindFirstChangeNotification, GetStdHandle, MsgWaitForMultipleObjects, OpenEvent, OpenMutex, OpenProcess, OpenSemaphore, PulseEvent, ResetEvent, SetEvent, Sleep, WaitForMultipleObjectsEx, WaitForSingleObject


WaitForMultipleObjectsEx
WaitForMultipleObjectsEx  QuickInfo  Overview  Group

The WaitForMultipleObjectsEx function is an extended wait function that can be used to perform an alertable wait. This enables the function to return when the system queues an I/O completion routine to be executed by the calling thread. The function also returns either when any one or when all of the specified objects are in the signaled state, or when the time-out interval elapses.

DWORD WaitForMultipleObjectsEx(

DWORD  cObjects,	// number of handles in handle array
CONST HANDLE *  lphObjects,	// address of object-handle array
BOOL  fWaitAll,	// wait flag
DWORD  dwTimeout,	// time-out interval in milliseconds
BOOL  fAlertable	// alertable wait flag
);
Parameters

cObjects

Specifies the number of object handles to wait for in the array pointed to by lphObjects. The maximum number of object handles is MAXIMUM_WAIT_OBJECTS.

lphObjects

Points to an array of object handles. For a list of the object types whose handles can be specified, see the following Remarks section. The array can contain handles of objects of different types.

Windows NT: The handles must have SYNCHRONIZE access.

fWaitAll

Specifies the wait type. If TRUE, the function returns when all objects in the lphObjects array are signaled at the same time. If FALSE, the function returns when any one of the objects is signaled. In the latter case, the return value indicates the object whose state caused the function to return.

dwTimeout

Specifies the time-out interval, in milliseconds. The function returns if the interval elapses, even if the conditions specified by the fWaitAll parameter are not satisfied and no completion routines are queued. If dwTimeout is zero, the function tests the states of the specified objects and checks for queued completion routines and then returns immediately. If dwTimeout is INFINITE, the function's time-out interval never elapses.

fAlertable

Specifies whether the function returns when the system queues an I/O completion routine for execution by the calling thread. If TRUE, the function returns and the completion routine is executed. If FALSE, the function does not return and the completion routine is not executed.

A completion routine is queued for execution when the ReadFileEx or WriteFileEx function in which it was specified has been completed. The wait function returns and the completion routine is executed only if fAlertable is TRUE and the calling thread is the thread that initiated the read or write operation.

Return Value

If the function succeeds, the return value indicates the event that caused the function to return.

If the function fails, the return value is 0xFFFFFFFF. To get extended error information, call GetLastError.

The return value on success is one of the following values:

Value	Meaning
WAIT_OBJECT_0 to (WAIT_OBJECT_0 + cObjects − 1)	If fWaitAll is TRUE, the return value indicates that the state of all specified objects is signaled.  If fWaitAll is FALSE, the return value minus WAIT_OBJECT_0 indicates the lphObjects array index of the object that satisfied the wait. If more than one object became signalled during the call, this is the array index of the signalled object with the smallest index value of all the signalled objects.
WAIT_ABANDONED_0 to (WAIT_ABANDONED_0 + cObjects − 1)	If fWaitAll is TRUE, the return value indicates that the state of all specified objects is signaled, and at least one of the objects is an abandoned mutex object.  If fWaitAll is FALSE, the return value minus WAIT_ABANDONED_0 indicates the lphObjects array index of an abandoned mutex object that satisfied the wait.
WAIT_IO_COMPLETION	One or more I/O completion routines are queued for execution.
WAIT_TIMEOUT	The time-out interval elapsed, the conditions specified by the fWaitAll parameter were not satisfied, and no completion routines are queued.
Remarks

The WaitForMultipleObjectsEx function determines whether the conditions exist that satisfy the wait. If the wait is not satisfied, the calling thread enters an efficient wait state, using very little processor time while waiting for one of the conditions of the wait to be satisfied.

When fWaitAll is TRUE, the function's wait condition is satisfied only when the state of all objects is signaled at the same time. The function does not modify the state of the specified objects until all objects are simultaneously signaled. For example, a mutex can be signaled, but the thread does not get ownership until the other objects are also signaled. In the meantime, some other thread may get ownership of the mutex, thereby delaying satisfaction of the wait condition.

The system adjusts the state of some types of objects after the object's signaled state satisfies a wait condition. For example, the count of a semaphore object is decreased by one.

The WaitForMultipleObjectsEx function can specify handles of any of the following object types in the lphObjects array:

Object	Description
Change notification	The handle is returned by the FindFirstChangeNotification function. A change notification object's state is signaled when a specified type of change occurs within a specified directory or directory tree.
Console input	The handle is returned by the CreateFile function when CONIN$ is specified, or by the GetStdHandle function. The object's state is signaled when there is unread input in the console's input buffer, and it is nonsignaled when the input buffer is empty.
Event	The handle is returned by the CreateEvent or OpenEvent function. An event object's state is set explicitly to signaled by the SetEvent or PulseEvent function. A manual-reset event object's state must be reset explicitly to nonsignaled by the ResetEvent function. For an auto-reset event object, the wait function resets the object's state to nonsignaled before returning. Event objects are also used in overlapped operations, in which the state is set by the system.
Mutex	The handle is returned by the CreateMutex or OpenMutex function. A mutex object's state is signaled when it is not owned by any thread. The wait function requests ownership of the mutex for the calling thread, changing the mutex's state to nonsignaled when ownership is granted.
Process	The handle is returned by the CreateProcess or OpenProcess function. A process object's state is signaled when the process terminates.
Thread	The handle is returned by the CreateProcess, CreateThread, or CreateRemoteThread function. A thread object's state is signaled when the thread terminates.
Semaphore	The handle is returned by the CreateSemaphore or OpenSemaphore function. A semaphore object maintains a count between zero and some maximum value. Its state is signaled when its count is greater than zero and nonsignaled when its count is zero. If the current state is signaled, the wait function decreases the count by one.
An abandoned mutex object is not released by the thread that owned the mutex object before the owning thread terminated. Ownership of the mutex object is granted to the calling thread, and the mutex is set to nonsignaled.

In some circumstances, a wait function can specify a handle of a file, named pipe, or communications device as an object to wait for. However, their use for this purpose is discouraged.

See Also

CreateEvent, CreateFile, CreateMutex, CreateProcess, CreateRemoteThread, CreateSemaphore, CreateThread, FindFirstChangeNotification, GetStdHandle, OpenEvent, OpenMutex, OpenProcess, OpenSemaphore, MsgWaitForMultipleObjects, PulseEvent, ReadFileEx, ResetEvent, SetEvent, SleepEx, WaitForMultipleObjects, WaitForSingleObjectEx, WriteFileEx


WaitForPrinterChange
WaitForPrinterChange  QuickInfo  Overview  Group

The WaitForPrinterChange function is obsolete. Applications should use the FindFirstPrinterChangeNotification, FindNextPrinterChangeNotification, and FindClosePrinterChangeNotification functions to monitor the occurrence of requested changes on a printer or print server.when one or more requested changes occur on a printer or print server.


WaitForSingleObject
WaitForSingleObject  QuickInfo  Overview  Group

The WaitForSingleObject function returns when the specified object is in the signaled state or when the time-out interval elapses.

DWORD WaitForSingleObject(

HANDLE  hObject,	// handle of object to wait for
DWORD  dwTimeout	// time-out interval in milliseconds
);
Parameters

hObject

Identifies the object. For a list of the object types whose handles can be specified, see the following Remarks section.

Windows NT: The handle must have SYNCHRONIZE access.

dwTimeout

Specifies the time-out interval, in milliseconds. The function returns if the interval elapses, even if the object's state is nonsignaled. If dwTimeout is zero, the function tests the object's state and returns immediately. If dwTimeout is INFINITE, the function's time-out interval never elapses.

Return Value

If the function succeeds, the return value indicates the event that caused the function to return.

If the function fails, the return value is WAIT_FAILED. To get extended error information, call GetLastError.

The return value on success is one of the following values:

Value	Meaning
WAIT_ABANDONED	The specified object is a mutex object that was not released by the thread that owned the mutex object before the owning thread terminated. Ownership of the mutex object is granted to the calling thread, and the mutex is set to nonsignaled.
WAIT_OBJECT_0	The state of the specified object is signaled.
WAIT_TIMEOUT	The time-out interval elapsed, and the object's state is nonsignaled.
Remarks

The WaitForSingleObject function checks the current state of the specified object. If the object's state is nonsignaled, the calling thread enters an efficient wait state. The thread consumes very little processor time while waiting for one of the conditions of the wait to be satisfied.

The system adjusts the state of some types of objects after the object's signaled state satisfies a wait condition. For example, the count of a semaphore object is decreased by one.

The WaitForSingleObject function can wait for the following objects:

Object	Description
Change notification	The handle is returned by the FindFirstChangeNotification function. A change notification object's state is signaled when a specified type of change occurs within a specified directory or directory tree.
Console input	The handle is returned by the CreateFile function when CONIN$ is specified, or by the GetStdHandle function. The object's state is signaled when there is unread input in the console's input buffer, and it is nonsignaled when the input buffer is empty.
Event	The handle is returned by the CreateEvent or OpenEvent function. An event object's state is set explicitly to signaled by the SetEvent or PulseEvent function. A manual-reset event object's state must be reset explicitly to nonsignaled by the ResetEvent function. For an auto-reset event object, the wait function resets the object's state to nonsignaled before returning. Event objects are also used in overlapped operations, in which the state is set by the system.
Mutex	The handle is returned by the CreateMutex or OpenMutex function. A mutex object's state is signaled when it is not owned by any thread. The wait function requests ownership of the mutex for the calling thread, changing the mutex's state to nonsignaled when ownership is granted.
Process	The handle is returned by the CreateProcess or OpenProcess function. A process object's state is signaled when the process terminates.
Thread	The handle is returned by the CreateProcess, CreateThread, or CreateRemoteThread function. A thread object's state is signaled when the thread terminates.
Semaphore	The handle is returned by the CreateSemaphore or OpenSemaphore function. A semaphore object maintains a count between zero and some maximum value. Its state is signaled when its count is greater than zero and nonsignaled when its count is zero. If the current state is signaled, the wait function decreases the count by one.
In some circumstances, a wait function can specify a handle of a file, named pipe, or communications device as an object to wait for. However, their use for this purpose is discouraged.

See Also

CreateEvent, CreateFile, CreateMutex, CreateProcess, CreateRemoteThread, CreateSemaphore, CreateThread, FindFirstChangeNotification, GetStdHandle, OpenEvent, OpenMutex, OpenProcess, OpenSemaphore, PulseEvent, ResetEvent, SetEvent, Sleep, WaitForMultipleObjects, WaitForSingleObjectEx


WaitForSingleObjectEx
WaitForSingleObjectEx  QuickInfo  Overview  Group

The WaitForSingleObjectEx function is an extended wait function that can be used to perform an alertable wait. This enables the function to return when the system queues an I/O completion routine to be executed by the calling thread. The function also returns when the specified object is in the signaled state or when the time-out interval elapses.

DWORD WaitForSingleObjectEx(

HANDLE  hObject,	// handle of object to wait for
DWORD  dwTimeout,	// time-out interval in milliseconds
BOOL  fAlertable	// return to execute I/O completion routine if TRUE
);
Parameters

hObject

Identifies the object. For a list of the object types whose handles can be specified, see the following Remarks section.

Windows NT: The handle must have SYNCHRONIZE access.

dwTimeout

Specifies the time-out interval, in milliseconds. The function returns if the interval elapses, even if the object's state is nonsignaled and no completion routines are queued. If dwTimeout is zero, the function tests the object's state and checks for queued completion routines and then returns immediately. If dwTimeout is INFINITE, the function's time-out interval never elapses.

fAlertable

Specifies whether the function returns when the system queues an I/O completion routine for execution by the calling thread. If TRUE, the function returns and the completion routine is executed. If FALSE, the function does not return, and the completion routine is not executed.

A completion routine is queued for execution when the ReadFileEx or WriteFileEx function in which it was specified has been completed. The wait function returns and the completion routine is executed only if fAlertable is TRUE, and the calling thread is the thread that initiated the read or write operation.

Return Value

If the function succeeds, the return value indicates the event that caused the function to return.

If the function fails, the return value is 0xFFFFFFFF. To get extended error information, call GetLastError.

The successful return value is one of the following:

Value	Meaning
WAIT_OBJECT_0	The state of the specified object is signaled.
WAIT_ABANDONED	The specified object is a mutex object that was not released by the thread that owned the mutex object before the owning thread terminated. Ownership of the mutex object is granted to the calling thread, and the mutex is set to nonsignaled.
WAIT_IO_COMPLETION	One or more I/O completion routines are queued for execution.
WAIT_TIMEOUT	The time-out interval elapsed, and the object's state is nonsignaled.
Remarks

The WaitForSingleObjectEx function determines whether the conditions exist that satisfy the wait. If the wait is not satisfied, the calling thread enters an efficient wait state, consuming very little processor time while waiting for one of the conditions of the wait to be satisfied.

The system adjusts the state of some types of objects after the object's signaled state satisfies a wait condition. For example, the count of a semaphore object is decreased by one.

The WaitForSingleObjectEx function can wait for the following objects:

Object	Description
Change notification	The handle is returned by the FindFirstChangeNotification function. A change notification object's state is signaled when a specified type of change occurs within a specified directory or directory tree.
Console input	The handle is returned by the CreateFile function when CONIN$ is specified, or by the GetStdHandle function. The object's state is signaled when there is unread input in the console's input buffer, and it is nonsignaled when the input buffer is empty.
Event	The handle is returned by the CreateEvent or OpenEvent function. An event object's state is set explicitly to signaled by the SetEvent or PulseEvent function. A manual-reset event object's state must be reset explicitly to nonsignaled by the ResetEvent function. For an auto-reset event object, the wait function resets the object's state to nonsignaled before returning. Event objects are also used in overlapped operations, in which the state is set by the system.
Mutex	The handle is returned by the CreateMutex or OpenMutex function. A mutex object's state is signaled when it is not owned by any thread. The wait function requests ownership of the mutex for the calling thread, changing the mutex's state to nonsignaled when ownership is granted.
Process	The handle is returned by the CreateProcess or OpenProcess function. A process object's state is signaled when the process terminates.
Thread	The handle is returned by the CreateProcess, CreateThread, or CreateRemoteThread function. A thread object's state is signaled when the thread terminates.
Semaphore	The handle is returned by the CreateSemaphore or OpenSemaphore function. A semaphore object maintains a count between zero and some maximum value. Its state is signaled when its count is greater than zero and nonsignaled when its count is zero. If the current state is signaled, the wait function decreases the count by one.
In some circumstances, a wait function can specify a handle of a file, named pipe, or communications device as an object to wait for. However, their use for this purpose is discouraged.

See Also

CreateEvent, CreateFile, CreateMutex, CreateProcess, CreateRemoteThread, CreateSemaphore, CreateThread, FindFirstChangeNotification, GetStdHandle, OpenEvent, OpenMutex, OpenProcess, OpenSemaphore, PulseEvent, ReadFileEx, ResetEvent, SetEvent, SleepEx, WaitForMultipleObjectsEx, WaitForSingleObject, WriteFileEx


WaitMessage
WaitMessage  QuickInfo  Overview  Group

BOOL WaitMessage(VOID)

The WaitMessage function yields control to other threads when a thread has no other messages in its message queue. The WaitMessage function suspends the thread and does not return until a new message is placed in the thread's message queue.

Parameters

This function has no parameters.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

GetMessage, PeekMessage


WaitNamedPipe
WaitNamedPipe  QuickInfo  Overview  Group

The WaitNamedPipe function waits until either a time-out interval elapses or an instance of the specified named pipe is available to be connected to (that is, the pipe's server process has a pending ConnectNamedPipe operation on the pipe).

BOOL WaitNamedPipe(

LPCTSTR  lpszPipeName,	// address of name of pipe to wait for
DWORD  dwTimeout	// time-out interval, in milliseconds
);
Parameters

lpszPipeName

Points to a null-terminated string that specifies the name of the named pipe. The string must include the name of the computer on which the server process is executing. A period may be used for the servername if the pipe is local. The following pipe name format is used:

\\servername\pipe\pipename

dwTimeout

Specifies the number of milliseconds that the function will wait for an instance of the named pipe to be available. One of the following values can be used instead of specifying a number of milliseconds:

Value	Meaning
NMPWAIT_USE_DEFAULT_WAIT	The time-out interval is the default value specified by the server process in the CreateNamedPipe function.
NMPWAIT_WAIT_FOREVER	The function does not return until an instance of the named pipe is available.
Return Value

If an instance of the pipe is available before the time-out interval elapses, the return value is TRUE. Otherwise, it is FALSE. To get extended error information, call GetLastError.

Remarks

If no instances of the specified named pipe exist, the WaitNamedPipe function returns immediately, regardless of the time-out value.

If the function succeeds, the process should use the CreateFile function to open a handle to the named pipe. A return value of TRUE indicates that there is at least one instance of the pipe available. A subsequent CreateFile call to the pipe can fail, because the instance was closed by the server or opened by another client.

See Also

CallNamedPipe, ConnectNamedPipe, CreateFile, CreateNamedPipe


WaitSoundState

The WaitSoundState function has been deleted.

See Also

Beep, MessageBeep


WaveProc
WaveProc  QuickInfo  Overview  Group

The WaveProc function is an application-defined callback function that processes messages sent to a waveform device. The address of the WaveProc function can be specified as the callback-address parameter for the waveInOpen or waveOutOpen function.

void CALLBACK WaveProc(

HWAVE  hWave,	// handle of waveform device
UINT  uMsg,	// sent message
DWORD  dwInstance,	// instance data
DWORD  dwParam1,	// application-defined parameter
DWORD  dwParam2	// application-defined parameter
);
Parameters

hWave

Identifies the waveform device associated with the callback.

uMsg

Specifies the message.

dwInstance

Specifies the user instance data specified with waveInOpen or waveOutOpen.

dwParam1

Specifies an application-defined parameter for the message.

dwParam2

Specifies an application-defined parameter for the message.

Return Value

This function does not return a value.

Remarks

WaveProc is a placeholder for the application-defined function name.

There are several differences between WaveProc functions under Windows NT and under Windows 3.1:

•	Under Windows 3.1, a WaveProc function is called at interrupt time. The call to a WaveProc function occurs on a separate thread under Windows NT.

•	Under Windows 3.1, a WaveProc function has to be in a dynamic-link library. Under Windows NT, there is no such restriction.

•	Under Windows 3.1, a WaveProc function must be exported in a .DEF file. Under Windows NT, that is not necessary.

If source code must be compatible with Windows 3.1, it should follow the Windows 3.1 rules as briefly noted earlier and as specified more fully in the Windows 3.1 documentation.

One other item should be noted carefully. There is a limited set of functions that a Windows 3.1 WaveProc function can call. In Win32, that strict limitation has been removed. However, it is strongly recommended that a Windows NT WaveProc function restrain its calls to functions in the same set, with the addition of the function SetEvent. Following is the Windows NT recommended list:

EnterCriticalSection	PostThreadMessage
LeaveCriticalSection	SetEvent
midiOutLongMsg	timeGetSystemTime
midiOutShortMsg	timeGetTime
OutputDebugString	timeKillEvent
PostMessage	timeSetEvent
If an application's WaveProc function does stray from this list, it should be careful not to call functions that take a long time to complete.

A WaveProc function should not call other Wave* functions; if it does, it will probably deadlock.

If a Win32 WaveProc shares data with other code, a Critical Section or similar mutual exclusion mechanism should be used to protect the integrity of the data.

See Also

MidiProc, TimeProc, MMIOProc, SetEvent, WAVEHDR, waveInOpen, waveOutOpen


WideCharToMultiByte
WideCharToMultiByte  QuickInfo  Overview  Group

The WideCharToMultiByte function maps a wide-character string to a new character string. The new character string is not necessarily from a multibyte character set.

int WideCharToMultiByte(

UINT  CodePage,	// code page
DWORD  dwFlags,	// performance and mapping flags
LPCWSTR  lpWideCharStr,	// address of wide-character string
int  cchWideChar,	// number of characters in string
LPSTR  lpMultiByteStr,	// address of buffer for new string
int  cchMultiByte,	// size of buffer
LPCSTR  lpDefaultChar,	// address of default for unmappable characters
LPBOOL  lpUsedDefaultChar	// address of flag set when default char. used
);
Parameters

CodePage

Specifies the code page used to perform the conversion. This parameter can be given the value of any codepage that is installed or available in the system. The following values may be used to specify one of the system default code pages:

Value	Meaning
CP_ACP	ANSI code page
CP_MACCP	Macintosh code page
CP_OEMCP	OEM code page
dwFlags

A set of bit flags that specify the handling of unmapped characters. The function performs more quickly when none of these flags is set. The following flag constants are defined:

Value	Meaning
WC_COMPOSITECHECK	Convert composite characters to precomposed characters.
WC_DISCARDNS	Discard nonspacing characters during conversion.
WC_SEPCHARS	Generate separate characters during conversion. This is the default conversion behavior.
WC_DEFAULTCHAR	Replace exceptions with the default character during conversion.
When WC_COMPOSITECHECK is specified, the function converts composite characters to precomposed characters. A composite character consists of a base character and a nonspacing character, each having different character values. A precomposed character has a single character value for a base/nonspacing character combination. In the character è, the e is the base character, and the accent grave mark is the nonspacing character.

When an application specifies WC_COMPOSITECHECK, it can use the last 3 flags in this list (WC_DISCARDNS, WC_SEPCHARS, and WC_DEFAULTCHAR) to customize the conversion to precomposed characters. These flags determine the function's behavior when there is no precomposed mapping for a base/nonspace character combination in a wide-character string. These last 3 flags can only be used if the WC_COMPOSITECHECK flag is set.

The function's default behavior is to generate separate characters (WC_SEPCHARS) for unmapped composite characters.

lpWideCharStr

Points to the wide-character string to be converted.

cchWideChar

Specifies the number of characters in the string pointed to by the lpWideCharStr parameter. If this value is −1, the string is assumed to be null-terminated and the length is calculated automatically.

lpMultiByteStr

Points to the buffer to receive the translated string.

cchMultiByte

Specifies the size in characters of the buffer pointed to by the lpMultiByteStr parameter. If this value is zero, the function returns the number of bytes required for the buffer. (In this case, the lpMultiByteStr buffer is not used.)

lpDefaultChar

Points to the character used if a wide character cannot be represented in the specified code page. If this parameter is NULL, a system default value is used. The function is faster when both lpDefaultChar and lpUsedDefaultChar are NULL.

lpUsedDefaultChar

Points to a flag that indicates whether a default character was used. The flag is set to TRUE if one or more wide characters in the source string cannot be represented in the specified code page. Otherwise, the flag is set to FALSE. This parameter may be NULL. The function is faster when both lpDefaultChar and lpUsedDefaultChar are NULL.

Return Value

If the function succeeds, and cchMultiByte is nonzero, the return value is the number of characters written to the buffer pointed to by lpMultiByteStr.

If the function succeeds, and cchMultiByte is zero, the return value is the required size, in bytes, for a buffer that can receive the translated string.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError. GetLastError may return one of the following error codes:

ERROR_INSUFFICIENT_BUFFER

ERROR_INVALID_FLAGS

ERROR_INVALID_PARAMETER

Remarks

The lpMultiByteStr and lpWideCharStr pointers must not be the same. If they are the same, the function fails, and GetLastError returns ERROR_INVALID_PARAMETER.

An application can use the lpDefaultChar parameter to change the default character used for the conversion.

As noted earlier, the WideCharToMultiByte function operates most efficiently when both lpDefaultChar and lpUsedDefaultChar are NULL. The following table shows the behavior of WideCharToMultiByte for the four combinations of lpDefaultChar and lpUsedDefaultChar :

lpDefaultChar	lpUsedDefaultChar	Result
NULL	NULL	No default checking. This is the most efficient, quick way to use this function.
non-NULL	NULL	Uses the specified default character, but does not set lpUsedDefaultChar
NULL	non-NULL	Uses the system default character and sets lpUsedDefaultChar if necessary.
non-NULL	non-NULL	Uses the specified default character and sets lpUsedDefaultChar if necessary.
See Also

MultiByteToWideChar


WidenPath
WidenPath  QuickInfo  Overview  Group

The WidenPath function redefines the current path as the area that would be painted if the path were stroked using the pen currently selected into the given device context.

BOOL WidenPath(

HDC  hdc	// handle of device context
);
Parameters

hdc

Identifies a device context that contains a closed path.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError. GetLastError may return one of the following error codes:

ERROR_CAN_NOT_COMPLETE
ERROR_INVALID_PARAMETER
ERROR_NOT_ENOUGH_MEMORY

Remarks

The WidenPath function is successful only if the current pen is a geometric pen created by the ExtCreatePen function, or if the pen is created with the CreatePen function and has a width, in device units, of more than one.

The device context identified by the hdc parameter must contain a closed path.

Any Bézier curves in the path are converted to sequences of straight lines approximating the widened curves. As such, no Bézier curves remain in the path after WidenPath is called.

See Also

BeginPath, CreatePen, EndPath, ExtCreatePen, SetMiterLimit


WindowFromDC
WindowFromDC  QuickInfo  Overview  Group

The WindowFromDC function returns the handle of the window associated with the given display device context (DC). Output functions that use the given device context draw into this window.

HWND WindowFromDC(

HDC  hdc	// handle of window
);
Parameters

hdc

Identifies the device context from which a handle for the associated window is to be retrieved.

Return Value

If the function succeeds, the return value is the handle of the window associated with the given display device context.

If the function fails, the return value is NULL.

See Also

GetDC, GetDCEx, GetWindowDC


WindowFromPoint
WindowFromPoint  QuickInfo  Overview  Group

The WindowFromPoint function retrieves the handle of the window that contains the specified point.

HWND WindowFromPoint(

POINT  pt	// structure with point
);
Parameters

pt

Specifies a POINT structure that defines the point to be checked.

Return Value

If the function succeeds, the return value is the handle of the window that contains the point. If no window exists at the given point, the return value is NULL.

Remarks

The WindowFromPoint function does not retrieve the handle of a hidden or disabled window, even if the point is within the window. An application should use the ChildWindowFromPoint function for a nonrestrictive search.

See Also

ChildWindowFromPoint, POINT, WindowFromDC


WindowProc
WindowProc  QuickInfo  Overview  Group

The WindowProc function is an application-defined callback function that processes messages sent to a window.

LRESULT CALLBACK WindowProc(

HWND  hwnd,	// handle of window
UINT  uMsg,	// message identifier
WPARAM  wParam,	// first message parameter
LPARAM  lParam	// second message parameter
);
Parameters

hwnd

Identifies the window.

uMsg

Specifies the message.

wParam

Specifies additional message information. The contents of this parameter depend on the value of the uMsg parameter.

lParam

Specifies additional message information. The contents of this parameter depend on the value of the uMsg parameter.

Return Value

The return value is the result of the message processing and depends on the message sent.

Remarks

WindowProc is a placeholder for the application-defined function name.

See Also

CallWindowProc, DefWindowProc, RegisterClass


WinExec
WinExec  QuickInfo  Overview  Group

The WinExec function runs the specified application.

This function is provided for compatibility with earlier versions of Windows. For Win32-based applications, use the CreateProcess function.

UINT WinExec(

LPCSTR  lpszCmdLine,	// address of command line
UINT  fuCmdShow	// window style for new application
);
Parameters

lpszCmdLine

Points to a null-terminated character string that contains the command line (filename plus optional parameters) for the application to be executed. If the name of the executable file in the lpszCmdLine parameter does not contain a directory path, Windows searches for the executable file in this sequence:

1.	The directory from which the application loaded.

2.	The current directory.

3.	The Windows system directory. The GetSystemDirectory function retrieves the path of this directory.

4.	The Windows directory. The GetWindowsDirectory function retrieves the path of this directory.

5.	The directories listed in the PATH environment variable.

fuCmdShow

Specifies how a Windows-based application window is to be shown and is used to supply the wShowWindow member of the STARTUPINFO parameter to the CreateProcess function. For a list of the acceptable values, see the description of the nCmdShow parameter of the ShowWindow function. For a non-Windows − based application, the PIF file, if any, for the application determines the window state.

Return Value

If the function succeeds, the return value is greater than 31.

If the function fails, the return value is one of the following error values:

Value	Meaning
0	The system is out of memory or resources.
ERROR_BAD_FORMAT	The .EXE file is invalid (non-Win32 .EXE or error in .EXE image).
ERROR_FILE_NOT_FOUND	The specified file was not found.
ERROR_PATH_NOT_FOUND	The specified path was not found.
Remarks

Win32-based applications should use the CreateProcess function rather than this function. The WinExec function exists in Win32 to provide compatibility with earlier versions of Windows. For more information about how the WinExec function is implemented, see the Remarks section of the LoadModule function.

In Win32, the WinExec function returns when the launched process calls the GetMessage function or a time-out limit is reached. To avoid waiting for the time out delay, call the GetMessage function as soon as possible in any process launched by a call to WinExec.

See Also

CreateProcess, GetMessage, GetSystemDirectory, GetWindowsDirectory, LoadModule, ShowWindow


WinHelp
WinHelp  QuickInfo  Overview  Group

The WinHelp function starts Windows Help (WINHELP.EXE) and passes additional data indicating the nature of the help requested by the application. The application specifies the name and, where required, the directory path of the help file to display.

BOOL WinHelp(

HWND  hwnd,	// handle of window requesting Help
LPCTSTR  lpszHelp,	// address of directory-path string
UINT  uCommand,	// type of Help
DWORD  dwData	// additional data
);
Parameters

hwnd

Identifies the window requesting Help. The WinHelp function uses this handle to keep track of which applications have requested Help.

lpszHelp

Points to a null-terminated string containing the path, if necessary, and the name of the Help file that the Help application is to display.

The filename may be followed by an angle bracket (>) and the name of a secondary window if the topic is to be displayed in a secondary window rather than in the primary window. The name of the secondary window must have been defined in the [WINDOWS] section of the Help project (.HPJ) file.

uCommand

Specifies the type of help requested. For a list of possible values and how they affect the value to place in the dwData parameter, see the Remarks section.

dwData

Specifies additional data. The value used depends on the value of the uCommand parameter. For a list of possible values, see the Remarks section.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE.

Remarks

Before closing the window that requested Help, the application must call WinHelp with the uCommand parameter set to HELP_QUIT. Until all applications have done this, Windows Help will not terminate. Note that calling WinHelp with the HELP_QUIT command is not necessary if you used the HELP_CONTEXTPOPUP command to start Help

The following table shows the possible values for the uCommand parameter and the corresponding formats of the dwData parameter:

uCommand	Action	dwData
HELP_COMMAND	Executes a Help macro or macro string.	Address of a string that specifies the name of the Help macro(s) to execute. If the string specifies multiple macros names, the names must be separated by semicolons. You must use the short form of the macro name for some macros because Help does not support the long name.
HELP_CONTENTS	Displays the topic specified by the Contents option in the [OPTIONS] section of the .HPJ file. This is for backward compatibility. New applications should provide a .CNT file and use the HELP_FINDER command.	Ignored, set to 0.
HELP_CONTEXT	Displays the topic identified by the specified context identifier defined in the [MAP] section of the .HPJ file.	Unsigned long integer containing the context identifier for the topic.
HELP_CONTEXTPOPUP	Displays, in a pop-up window, the topic identified by the specified context identifier defined in the [MAP] section of the .HPJ file.	Unsigned long integer containing the context identifier for a topic.
HELP_FORCEFILE	Ensures that WinHelp is displaying the correct help file. If the incorrect help file is being displayed, WinHelp opens the correct one; otherwise, there is no action.	Ignored, set to 0.
HELP_HELPONHELP	Displays help on how to use Windows Help, if the WINHELP.HLP file is available.	Ignored, set to 0.
HELP_INDEX	Displays the Index in the Help Topics dialog box. This command is for backward compatibility. New applications should use the HELP_FINDER command.	Ignored, set to 0.
HELP_KEY	Displays the topic in the keyword table that matches the specified keyword, if there is an exact match. If there is more than one match, displays the Index with the topics listed in the Topics Found list box.	Address of a keyword string.
HELP_MULTIKEY	Displays the topic specified by a keyword in an alternative keyword table.	Address of a MULTIKEYHELP structure that specifies a table footnote character and a keyword.
HELP_PARTIALKEY	Displays the topic in the keyword table that matches the specified keyword, if there is an exact match. If there is more than one match, displays the Index tab. To display the Index without passing a keyword (the third result), you should use a pointer to an empty string.	Address of a keyword  string.
HELP_QUIT	Informs the Help application that it is no longer needed. If no other applications have asked for Help, Windows closes the Help application.	Ignored, set to 0.
HELP_SETCONTENTS	Specifies the Contents topic. The Help application displays this topic when the user clicks the Contents button.	Unsigned long integer containing the context identifier for the Contents topic.
HELP_SETINDEX	Specifies a keyword table to be displayed in the Index of the Help Topics dialog box.	Unsigned long integer containing the context identifier for the Index topic.
HELP_SETWINPOS	Displays the Help window, if it is minimized or in memory, and sets its size and position as specified.	Address of a HELPWININFO structure that specifies the size and position of either a primary or secondary Help window.
See Also

HELPWININFO, MULTIKEYHELP


WinMain
WinMain  QuickInfo  Overview  Group

The WinMain function is called by the system as the initial entry point for a Windows-based application.

int WINAPI WinMain(

HINSTANCE  hInstance,	// handle of current instance
HINSTANCE  hPrevInstance,	// handle of previous instance
LPSTR  lpszCmdLine,	// pointer to command line
int  nCmdShow	// show state of window
);
Parameters

hInstance

Identifies the current instance of the application.

hPrevInstance

Identifies the previous instance of the application. For a Win32-based application, this parameter is always NULL.

lpszCmdLine

Points to a null-terminated string specifying the command line for the application.

nCmdShow

Specifies how the window is to be shown. This parameter can be one of the following values:

Value	Meaning
SW_HIDE	Hides the window and activates another window.
SW_MINIMIZE	Minimizes the specified window and activates the top-level window in the system's list.
SW_RESTORE	Activates and displays a window. If the window is minimized or maximized, Windows restores it to its original size and position (same as SW_SHOWNORMAL).
SW_SHOW	Activates a window and displays it in its current size and position.
SW_SHOWMAXIMIZED	Activates a window and displays it as a maximized window.
SW_SHOWMINIMIZED	Activates a window and displays it as an icon.
SW_SHOWMINNOACTIVE	Displays a window as an icon. The active window remains active.
SW_SHOWNA	Displays a window in its current state. The active window remains active.
SW_SHOWNOACTIVATE	Displays a window in its most recent size and position. The active window remains active.
SW_SHOWNORMAL	Activates and displays a window. If the window is minimized or maximized, Windows restores it to its original size and position (same as SW_RESTORE).
Return Value

If the function succeeds, terminating when it receives a WM_QUIT message, it should return the exit value contained in that message's wParam parameter. If the function terminates before entering the message loop, it should return 0.

Remarks

WinMain initializes an application, and then performs a message retrieval-and-dispatch loop that is the top-level control structure for the remainder of the application's execution. The loop terminates when a WM_QUIT message is received. At that point, WinMain exits the application, returning the value passed in the WM_QUIT message's wParam parameter. If WM_QUIT was received as a result of calling PostQuitMessage, the value of wParam is the value of the PostQuitMessage function's nExitCode parameter.

See Also

DispatchMessage, GetMessage, PostQuitMessage, TranslateMessage


WNetAddConnection
WNetAddConnection  QuickInfo  Overview  Group

The WNetAddConnection function enables the calling application to connect a local device to a network resource. A successful connection is persistent, meaning that Windows automatically restores the connection during subsequent logon operations.

This function is provided for compatibility with earlier versions of Microsoft Windows. For new applications, use the WNetAddConnection2 function.

DWORD WNetAddConnection(

LPTSTR  lpszRemoteName,	// address of network device name
LPTSTR  lpszPassword,	// address of password
LPTSTR  lpszLocalName	// address of local device name
);
Parameters

lpszRemoteName

Points to a null-terminated string that specifies the network resource to connect to.

lpszPassword

Points to a null-terminated string that specifies the password to be used to make a connection. This parameter is usually the password associated with the current user.

If this parameter is NULL, the default password is used. If the string is empty, no password is used.

lpszLocalName

Points to a null-terminated string that specifies the name of a local device to be redirected, such as F: or LPT1. The case of the characters in the string is not important. If the string is NULL, a connection to the network resource is made without redirecting the local device.

Return Value

If the function succeeds, the return value is NO_ERROR.

If the function fails, the return value is an error code. To get extended error information, call GetLastError. GetLastError may return one of the following error codes:

Value	Meaning
ERROR_ACCESS_DENIED	Access is denied.
ERROR_ALREADY_ASSIGNED	The device specified in the lpszLocalName parameter is already connected.
ERROR_BAD_DEV_TYPE	The device type and the resource type do not match.
ERROR_BAD_DEVICE	The value specified in lpszLocalName is invalid.
ERROR_BAD_NET_NAME	The value specified in the lpszRemoteName parameter is not valid or cannot be located.
ERROR_BAD_PROFILE	The user profile is in an incorrect format.
ERROR_CANNOT_OPEN_PROFILE	The system is unable to open the user profile to process persistent connections.
ERROR_DEVICE_ALREADY_REMEMBERED	An entry for the device specified in lpszLocalName is already in the user profile.
ERROR_EXTENDED_ERROR	A network-specific error occurred. To get a description of the error, use the WNetGetLastError function.
ERROR_INVALID_PASSWORD	The specified password is invalid.
ERROR_NO_NET_OR_BAD_PATH	The operation cannot be performed because either a network component is not started or the specified name cannot be used.
ERROR_NO_NETWORK	The network is not present.
The function returns error codes and sets the error code values returned by GetLastError.

See Also

WNetAddConnection2, WNetCancelConnection, WNetCancelConnection2, WNetGetConnection, WNetGetLastError


WNetAddConnection2
WNetAddConnection2  QuickInfo  Overview  Group

The WNetAddConnection2 function makes a connection to a network resource. The function can redirect a local device to the network resource.

The WNetAddConnection2 function supersedes the WNetAddConnection function. If you pass a handle to a window that the provider of network resources can use as an owner window for dialog boxes, use the WNetAddConnection3 function.

DWORD WNetAddConnection2(

LPNETRESOURCE  lpNetResource,	// points to structure that specifies connection details
LPCTSTR  lpPassword,	// points to password string
LPCTSTR  lpUsername,	// points to user name string
DWORD  fdwConnection	// set of bit flags that specify connection options
);
Parameters

lpNetResource

Points to a NETRESOURCE structure that specifies details of the proposed connection: information about the network resource, the local device, and the network resource provider.

You must specify the following members of the NETRESOURCE structure:

Member	Description
dwType	Specifies the type of network resource to connect to. If lpLocalName points to a non-empty string, this member can be RESOURCETYPE_DISK or RESOURCETYPE_PRINT. If lpLocalName is NULL or points to an empty string, dwType can be RESOURCETYPE_DISK, RESOURCETYPE_PRINT, or RESOURCETYPE_ANY.
lpLocalName	Points to a null-terminated string that specifies the name of a local device to be redirected, such as "F:" or "LPT1". The string is treated in a case-insensitive manner. If the string is empty or lpLocalName is NULL, the function makes a connection to the network resource without redirecting a local device.
lpRemoteName	Points to a null-terminated string that specifies the network resource to connect to. The string can be up to MAX_PATH characters in length. The string must follow the network provider's naming conventions.
lpProvider	Points to a null-terminated string that specifies the network provider to connect to. If lpProvider is NULL or points to an empty string, the operating system attempts to determine the correct provider by parsing the string pointed to by lpRemoteName.
	You should set this member only if you know for sure which network provider you want to use. Otherwise, let the operating system determine which provider the network name maps to.
	If this member is not NULL, the operating system attempts to make a connection only to the named network provider.
The WNetAddConnection2 function ignores the other members of the NETRESOURCE structure.

lpPassword

Points to a null-terminated string that specifies a password to be used in making the network connection.

If lpPassword is NULL, the function uses the current default password associated with the user specified by lpUserName.

If lpPassword points to an empty string, the function does not use a password.

lpUsername

Points to a null-terminated string that specifies a user name to be used in making the connection.

If lpUserName is NULL, the function uses the default user name. The user context for the process provides the default user name.

The lpUserName parameter is specified when users want to connect to a network resource for which they have been assigned a user name or account other than the default user name or account.

The user-name string represents a security context. It may be specific to a network provider.

fdwConnection

A set of bit flags that specify connection options. The following bit flag constant is currently defined:

Value	Meaning
CONNECT_UPDATE_PROFILE	The network resource connection should be remembered.  If this bit flag is set, the operating system automatically attempts to restore the connection when the user logs on. The operating system remembers only successful connections that redirect local devices. It does not remember unsuccessful connections or deviceless connections. A deviceless connection occurs when lpLocalName is NULL or points to an empty string. If this bit flag is clear, the operating system will not automatically restore the connection at logon.
Return Value

If the function succeeds, the return value is NO_ERROR.

If the function fails, the return value is an error code. Returning an error code provides compatibility with the behavior of the Windows 3.1 function WNetAddConnection. You can also call the GetLastError function to obtain the (same) error code. One of the following error codes may be returned when WNetAddConnection2 fails:

Value	Meaning
ERROR_ACCESS_DENIED	Access to the network resource was denied.
ERROR_ALREADY_ASSIGNED	The local device specified by lpLocalName is already connected to a network resource.
ERROR_BAD_DEV_TYPE	The type of local device and the type of network resource do not match.
ERROR_BAD_DEVICE	The value specified by lpLocalName is invalid.
ERROR_BAD_NET_NAME	The value specified by lpRemoteName is not acceptable to any network resource provider. The resource name is invalid, or the named resource cannot be located.
ERROR_BAD_PROFILE	The user profile is in an incorrect format.
ERROR_BAD_PROVIDER	The value specified by lpProvider does not match any provider.
ERROR_BUSY	The router or provider is busy, possibly initializing. The caller should retry.
ERROR_CANCELLED	The attempt to make the connection was cancelled by the user through a dialog box from one of the network resource providers, or by a called resource.
ERROR_CANNOT_OPEN_PROFILE	The system is unable to open the user profile to process persistent connections.
ERROR_DEVICE_ALREADY_REMEMBERED	An entry for the device specified in lpLocalName is already in the user profile.
ERROR_EXTENDED_ERROR	A network-specific error occured. Call the WNetGetLastError function to get a description of the error.
ERROR_INVALID_PASSWORD	The specified password is invalid.
ERROR_NO_NET_OR_BAD_PATH	A network component has not started, or the specified name could not be handled.
ERROR_NO_NETWORK	There is no network present.
See Also

WNetAddConnection, WNetAddConnection3, WNetCancelConnection2, WNetGetConnection, WNetGetLastError, NETRESOURCE


WNetAddConnection3
WNetAddConnection3  QuickInfo  Overview  Group

The WNetAddConnection3 function makes a connection to a network resource. The function can redirect a local device to the network resource.

The WNetAddConnection3 function is similar to the WNetAddConnection2 function. The main difference is that WNetAddConnection3 has an additional parameter, a handle to a window that the provider of network resources can use as an owner window for dialog boxes.

DWORD WNetAddConnection3(

HWND  hwndOwner,	// handle to an owner window for network provider dialog boxes
LPNETRESOURCE  lpNetResource,	// address of structure that specifies connection details
LPTSTR  lpPassword,	// address of password string
LPTSTR  lpUserName,	// address of user name string
DWORD  fdwConnection	// set of bit flags that specify connection options
);
Parameters

hwndOwner

Specifies a window that the provider of network resources can use as an owner window for dialog boxes.

The hwndOwner parameter may be NULL. If it is, a call to WNetAddConnection3 is equivalent to calling the WNetAddConnection2 function.

lpNetResource

Points to a NETRESOURCE data structure that specifies details of the proposed connection: information about the network resource, the local device, and the network resource provider.

You must specify the following members of the NETRESOURCE structure:

Member	Description
dwType	Specifies the type of network resource to connect to. If lpLocalName points to a non-empty string, this member can be RESOURCETYPE_DISK or RESOURCETYPE_PRINT. If lpLocalName is NULL or points to an empty string, dwType can be RESOURCETYPE_DISK, RESOURCETYPE_PRINT, or RESOURCETYPE_ANY.
lpLocalName	Points to a null-terminated string that specifies the name of a local device to be redirected, such as "F:" or "LPT1". The string is treated in a case-insensitive manner. If the string is empty or lpLocalName is NULL, the function makes a connection to the network resource without redirecting a local device.
lpRemoteName	Points to a null-terminated string that specifies the network resource to connect to. The string can be up to MAX_PATH characters in length . The string must follow the network provider's naming conventions.
lpProvider	Points to a null-terminated string that specifies the network provider to connect to. If lpProvider is NULL or points to an empty string, the operating system attempts to determine the correct provider by parsing the string pointed to by lpRemoteName.
	You should set this member only if you know for sure which network provider you want to use. Otherwise, let the operating system determine which network provider the network name maps to.
	If this member is not NULL, the operating system attempts to make a connection only to the named network provider.
The WNetAddConnection3 function ignores the other members of the NETRESOURCE structure.

lpPassword

Points to a null-terminated string that specifies a password to be used in making the network connection.

If lpPassword is NULL, the function uses the current default password associated with the user specified by lpUserName.

If lpPassword points to an empty string, the function does not use a password.

lpUserName

Points to a null-terminated string that specifies a user name to be used in making the connection.

If lpUserName is NULL, the function uses the default user name. The user context for the process provides the default user name.

The lpUserName parameter is specified when users want to connect to a network resource for which they have been assigned a user name or account other than the default user name or account.

The user-name string represents a security context. It may be specific to a network provider.

fdwConnection

A set of bit flags that specify connection options. The following bit flag constants are currently defined:

Value	Meaning
CONNECT_UPDATE_PROFILE	The network resource connection should be remembered.  If this bit flag is set, the operating system automatically attempts to restore the connection when the user logs on. The operating system remembers only successful connections that redirect local devices. It does not remember unsuccessful connections and deviceless connections. A deviceless connection occurs when lpLocalName is NULL or points to an empty string. If this bit flag is clear, the operating system will not automatically restore the connection at logon.
Return Value

If the function succeeds, the return value is NO_ERROR.

If the function fails, the return value is an error code. Returning an error code provides compatibility with the behavior of the Windows 3.1 function WNetAddConnection. You can also call the GetLastError function to obtain the (same) error code. One of the following error codes may be returned when WNetAddConnection3 fails:

Value	Meaning
ERROR_ACCESS_DENIED	Access to the network resource was denied.
ERROR_ALREADY_ASSIGNED	The local device specified by lpLocalName is already connected to a network resource.
ERROR_BAD_DEV_TYPE	The type of local device and the type of network resource do not match.
ERROR_BAD_DEVICE	The value specified by lpLocalName is invalid.
ERROR_BAD_NET_NAME	The value specified by lpRemoteName is not acceptable to any network resource provider. The resource name is invalid, or the named resource cannot be located.
ERROR_BAD_PROFILE	The user profile is in an incorrect format.
ERROR_BAD_PROVIDER	The value specified by lpProvider does not match any provider.
ERROR_BUSY	The router or provider is busy, possibly initializing. The caller should retry.
ERROR_CANCELLED	The attempt to make the connection was cancelled by the user through a dialog box from one of the network resource providers or by a called resource.
ERROR_CANNOT_OPEN_PROFILE	The system is unable to open the user profile to process persistent connections.
ERROR_DEVICE_ALREADY_REMEMBERED	An entry for the device specified in lpLocalName is already in the user profile.
ERROR_EXTENDED_ERROR	A network-specific error occured. Call the WNetGetLastError function to get a description of the error.
ERROR_INVALID_PASSWORD	The specified password is invalid.
ERROR_NO_NET_OR_BAD_PATH	A network component has not started, or the specified name could not be handled.
ERROR_NO_NETWORK	There is no network present.
See Also

NETRESOURCE, WNetAddConnection2, WNetCancelConnection2, WNetGetConnection, WNetGetLastError


WNetCancelConnection
WNetCancelConnection  QuickInfo  Overview  Group

The WNetCancelConnection function breaks an existing network connection.

The function is provided for compatibility with earlier versions of Microsoft Windows. For new applications, use the WNetCancelConnection2 function.

DWORD WNetCancelConnection(

LPTSTR  lpszName,	// address of resource name to be disconnected
BOOL  fForce	// flag for unconditional disconnect
);
Parameters

lpszName

Points to a null-terminated string that specifies the name of either the redirected local device or the remote network resource to disconnect from. When this parameter specifies a redirected local device, only the specified redirection is broken, and Windows will not restore the connection during subsequent logon operations. When this parameter specifies a remote network resource, the connection to that remote network resource is broken.

fForce

Specifies whether the disconnection is to occur even if there are open files or jobs on the connection. If this parameter is FALSE, the function fails if there are open files or jobs.

Return Value

If the function succeeds, the return value is NO_ERROR.

If the function fails, the return value is an error code. To get extended error information, call GetLastError. GetLastError may return one of the following error codes:

Value	Meaning
ERROR_BAD_PROFILE	The user profile is in an incorrect format.
ERROR_CANNOT_OPEN_PROFILE	The system is unable to open the user profile to process persistent connections.
ERROR_DEVICE_IN_USE	The device is in use by an active process and cannot be disconnected.
ERROR_EXTENDED_ERROR	A network-specific error occurred. To get a description of the error, use the WNetGetLastError function.
ERROR_NOT_CONNECTED	The name specified by the lpszName parameter is not a redirected device, or the system is not currently connected to the device specified by the parameter.
ERROR_OPEN_FILES	There are open files, and the fForce parameter is FALSE.
The function returns error codes for compatibility with Windows version 3.1. For compatibility with the Win32 API, the function also sets the error code value returned by GetLastError.

See Also

WNetAddConnection, WNetAddConnection2, WNetCancelConnection2, WNetGetConnection, WNetGetLastError


WNetCancelConnection2
WNetCancelConnection2  QuickInfo  Overview  Group

The WNetCancelConnection2 function breaks an existing network connection. It can also be used to remove remembered network connections that are not currently connected. This function supersedes WNetCancelConnection.

DWORD WNetCancelConnection2(

LPTSTR  lpszName,	// address of resource name to disconnect
DWORD  fdwConnection,	// connection type flags
BOOL  fForce	// flag for unconditional disconnect
);
Parameters

lpszName

Points to a null-terminated string that specifies the name of either the redirected local device or the remote network resource to disconnect from. If this parameter specifies a redirected local resource, only the specified redirection is broken; otherwise, all connections to the remote network resource are broken.

fdwConnection

Specifies a bitmask for the connection type. The following values are defined:

Value	Meaning
0	No information about the connection is stored.
CONNECT_UPDATE_PROFILE	The user profile is updated with the information that this is no longer a persistent connection. Windows will not restore this connection during subsequent logon operations. Disconnecting resources using remote names has no effect on persistent connections.
fForce

Specifies whether the disconnection should occur even if there are open files or jobs on the connection. If this parameter is FALSE, the function fails if there are open files or jobs.

Return Value

If the function succeeds, the return value is NO_ERROR.

If the function fails, the return value is an error code. To get extended error information, call GetLastError. GetLastError may return one of the following error codes:

Value	Meaning
ERROR_BAD_PROFILE	The user profile is in an incorrect format.
ERROR_CANNOT_OPEN_PROFILE	The system is unable to open the user profile to process persistent connections.
ERROR_DEVICE_IN_USE	The device is in use by an active process and cannot be disconnected.
ERROR_EXTENDED_ERROR	A network-specific error occurred. To get a description of the error, use the WNetGetLastError function.
ERROR_NOT_CONNECTED	The name specified by the lpszName parameter is not a redirected device, or the system is not currently connected to the device specified by the parameter.
ERROR_OPEN_FILES	There are open files, and the fForce parameter is FALSE.
See Also

WNetAddConnection, WNetAddConnection2, WNetAddConnection3, WNetCancelConnection, WNetGetConnection, WNetGetLastError


WNetCloseEnum
WNetCloseEnum  QuickInfo  Overview  Group

The WNetCloseEnum function ends a network resource enumeration started by the WNetOpenEnum function.

DWORD WNetCloseEnum(

HANDLE  hEnum	// handle of enumeration
);
Parameters

hEnum

Identifies an enumeration instance. This handle must be returned by the WNetOpenEnum function.

Return Value

If the function succeeds, the return value is NO_ERROR.

If the function fails, the return value is an error code. To get extended error information, call GetLastError. GetLastError may return one of the following error codes:

Value	Meaning
ERROR_NO_NETWORK	A network is not present. This condition is tested before the handle specified in the hEnum parameter is tested for validity.
ERROR_INVALID_HANDLE	hEnum is not a valid handle.
ERROR_EXTENDED_ERROR	A network-specific error occurred. To get a description of the error, use the WNetGetLastError function.
The function returns error codes for compatibility with Windows version 3.1. For compatibility with Windows NT, the function also sets the error code value returned by GetLastError.

See Also

WNetEnumResource, WNetGetLastError, WNetOpenEnum


WNetConnectionDialog
WNetConnectionDialog  QuickInfo  Overview  Group

The WNetConnectionDialog function starts a general browsing dialog box for connecting to network resources.

DWORD WNetConnectionDialog(

HWND  hwnd,	// handle of window owning dialog box
DWORD  fdwResourceType	// resource type to allow connections to
);
Parameters

hwnd

Identifies the owning window.

fdwResourceType

Specifies the resource type to allow connections to. This parameter can be the following value:

Value	Meaning
RESOURCETYPE_DISK	Connects to disk resources.
Return Value

If the function succeeds, the return value is NO_ERROR. If the user cancels the dialog box, it is 0xFFFFFFFF.

If the function fails, the return value is an error code. To get extended error information, call GetLastError. GetLastError may return one of the following error codes:

Value	Meaning
ERROR_EXTENDED_ERROR	A network-specific error occurred. To get a description of the error, use the WNetGetLastError function.
ERROR_INVALID_PASSWORD	The specified password is invalid.
ERROR_NO_NETWORK	No network is present.
ERROR_NOT_ENOUGH_MEMORY	There is insufficient memory to start the dialog box.
The function returns error codes for compatibility with Windows version 3.1. For compatibility with the Win32 API, the function also sets the error code value returned by the GetLastError function.

Remarks

If the user chooses OK in the dialog box, the requested network connections will have been performed when WNetConnectionDialog returns.

If the function attempts to make a connection and the provider returns the message ERROR_INVALID_PASSWORD, Windows prompts the user to enter a password and uses the new password in another attempt to make the connection.

See Also

WNetAddConnection2, WNetCancelConnection2, WNetDisconnectDialog, WNetGetLastError


WNetDisconnectDialog
WNetDisconnectDialog  QuickInfo  Overview  Group

The WNetDisconnectDialog function starts a general browsing dialog box for disconnecting from network resources.

DWORD WNetDisconnectDialog(

HWND  hwnd,	// handle of window owning dialog box
DWORD  fdwResourceType	// resource type to disconnect from
);
Parameters

hwnd

Identifies the owning window.

fdwResourceType

Specifies the resource type to disconnect from. This parameter may be one of the following values:

Value	Meaning
RESOURCETYPE_DISK	Disconnects from disk resources.
RESOURCETYPE_PRINT	Disconnects from print resources.
Return Value

If the function succeeds, the return value is NO_ERROR. If the user cancels out of the dialog box, it is 0xFFFFFFFF.

If the function fails, the return value is an error code. To get extended error information, call GetLastError. GetLastError may return one of the following error codes:

Value	Meaning
ERROR_EXTENDED_ERROR	A network-specific error occurred. To get a description of the error, use the WNetGetLastError function.
ERROR_NO_NETWORK	No network is present.
ERROR_NOT_ENOUGH_MEMORY	There is insufficient memory to start the dialog box.
The function returns error codes for compatibility with Windows version 3.1. For compatibility with the Win32 API, the function also sets the error code value returned by GetLastError.

Remarks

If the user chooses OK in the dialog box, the requested network disconnections will have been performed when WNetDisconnectDialog returns.

See Also

WNetAddConnection2, WNetCancelConnection2, WNetConnectionDialog, WNetGetLastError


WNetEnumResource
WNetEnumResource  QuickInfo  Overview  Group

The WNetEnumResource function continues a network-resource enumeration started by the WNetOpenEnum function.

DWORD WNetEnumResource(

HANDLE  hEnum,	// handle of enumeration
LPDWORD  lpcEntries,	// address of entries to list
LPVOID  lpvBuffer,	// address of buffer for results
LPDWORD  lpcbBuffer	// address of buffer size variable
);
Parameters

hEnum

Identifies an enumeration instance. This handle must be returned by WNetOpenEnum.

lpcEntries

Points to a variable specifying the number of entries requested. If the number requested is 0xFFFFFFFF, the function returns as many entries as possible.

When the function finishes successfully, the variable pointed to by this parameter contains the number of entries actually read.

lpvBuffer

Points to the buffer that receives the enumeration results, which are returned as an array of NETRESOURCE structures. The buffer is valid until the next call using the handle given by the hEnum parameter. The order of NETRESOURCE structures in the array is not predictable.

lpcbBuffer

Points to a variable that specifies the size, in bytes, of the lpvBuffer parameter. If the buffer is too small to receive even one entry, this parameter receives the required size of the buffer.

Return Value

If the function succeeds, the return value is one of the following values:

Value	Meaning
NO_ERROR	The enumeration succeeded, and the buffer contains the requested data. The calling application can continue to call WNetEnumResource to complete the enumeration.
ERROR_NO_MORE_ITEMS	There are no more entries. The buffer contents are undefined.
If the function fails, the return value is an error code. To get extended error information, call GetLastError. GetLastError may return one of the following error codes:

Value	Meaning
ERROR_MORE_DATA	The buffer is too small for even one entry.
ERROR_INVALID_HANDLE	The handle given by the hEnum parameter is not valid.
ERROR_NO_NETWORK	No network is present. This condition is tested before hEnum is tested for validity.
ERROR_EXTENDED_ERROR	A network-specific error occurred. To get a description of the error, use the WNetGetLastError function.
The function returns error codes for compatibility with Windows version 3.1. For compatibility with the Win32 API, the function also sets the error code value returned by GetLastError.

Remarks

An application cannot set the lpvBuffer parameter to NULL and retrieve the required buffer size from the lpcbBuffer parameter. Instead, the application should allocate a buffer of a reasonable size — 16 kilobytes (K) is typical — and use the value of lpcbBuffer for error detection.

See Also

NETRESOURCE, WNetCloseEnum, WNetGetLastError, WNetOpenEnum


WNetGetConnection
WNetGetConnection  QuickInfo  Overview  Group

The WNetGetConnection function retrieves the name of the network resource associated with a local device.

DWORD WNetGetConnection(

LPTSTR  lpszLocalName,	// address of local name
LPTSTR  lpszRemoteName,	// address of buffer for remote name
LPDWORD  lpcchBuffer	// address of buffer size, in characters
);
Parameters

lpszLocalName

Points to a null-terminated string that specifies the name of the local device to get the network name for.

lpszRemoteName

Points to a buffer that receives the null-terminated remote name used to make the connection.

lpcchBuffer

Points to a variable that specifies the size, in characters, of the buffer pointed to by the lpszRemoteName parameter. If the function fails because the buffer is not big enough, this parameter returns the required buffer size.

Return Value

If the function succeeds, the return value is NO_ERROR.

If the function fails, the return value is an error code. To get extended error information, call GetLastError. GetLastError may return one of the following error codes:

Value	Meaning
ERROR_BAD_DEVICE	The string pointed to by the lpszLocalName parameter is invalid.
ERROR_NOT_CONNECTED	The device specified by lpszLocalName is not redirected.
ERROR_MORE_DATA	The buffer is too small. The lpcchBuffer parameter points to a variable that contains the required buffer size.
ERROR_CONNECTION_UNAVAIL	The device is not currently connected, but it is a persistent connection.
ERROR_NO_NETWORK	No network is present.
ERROR_EXTENDED_ERROR	A network-specific error occurred. To get a description of the error, use the WNetGetLastError function.
ERROR_NO_NET_OR_BAD_PATH	None of the providers recognized this local name as having a connection. However, the network is not available for at least one provider to whom the connection may belong.
The WNetGetConnection function returns error codes for compatibility with Windows version 3.1. For compatibility with the Win32 API, the function also sets the error code value returned by GetLastError.

See Also

WNetAddConnection2, WNetAddConnection3, WNetGetLastError, WNetGetUser


WNetGetLastError
WNetGetLastError  QuickInfo  Overview  Group

The WNetGetLastError function retrieves the most recent extended error code set by a Windows network function.

DWORD WNetGetLastError(

LPDWORD  lpdwErrorCode,	// address of error code
LPTSTR  lpszDescription,	// address of string describing error
DWORD  cchDescription,	// size of description buffer, in characters
LPTSTR  lpszName,	// address of buffer for provider name
DWORD  cchName	// size of provider name buffer
);
Parameters

lpdwErrorCode

Points to the variable that receives the error code reported by the network provider. The error code is specific to the network provider.

lpszDescription

Points to the buffer that receives the null-terminated string describing the error.

cchDescription

Specifies the size, in characters, of the buffer pointed to by the lpszDescription parameter. If the buffer is too small for the error string, the string is truncated but still null-terminated. A buffer of at least 256 characters is recommended.

lpszName

Points to the buffer that receives the null-terminated string identifying the network provider that raised the error.

cchName

Specifies the size, in characters, of the buffer pointed to by the lpszName parameter. If the buffer is too small for the error string, the string is truncated but still null-terminated.

Return Value

If the function successfully obtains the last error reported by the provider, the return value is NO_ERROR. If the caller supplies an invalid buffer, it is ERROR_INVALID_ADDRESS.

Remarks

WNetGetLastError is used to obtain errors that are specific to a network provider. It should be used when a Windows network function (or the GetLastError function) returns ERROR_EXTENDED_ERROR. Like GetLastError, the function returns extended error information, which is maintained on a per-thread basis. Unlike GetLastError, the WNetGetLastError function can also return a string for reporting errors that are not described by any existing error code.

See Also

GetLastError


WNetGetResourceInformation

The WNetGetResourceInformation function retrieves enumeration information for a network resource. You typically use this function when the user specifies an object. Call this function in conjunction with WNetGetResourceParent to determine the placement and nature of the resource in the browse hierarchy. Unlike WNetGetResourceParent, WNetGetResourceInformation always tries to determine the network provider that owns the resource and the type of the resource, although it might not currently be accessible (or even exist if the type of the resource was specified by the caller).

DWORD WNetGetResourceInformation(

LPNETRESOURCE lpNetResource,	// specifies the network resource
LPVOID lpBuffer,	// pointer to a buffer for results
LPDWORD cbBuffer,	// size of the buffer
LPTSTR *lplpSystem	// pointer to a string in the buffer
);
Parameters

lpNetResource

Specifies the network resource for which the information is required. The lpRemoteName member of the NETRESOURCE structure specifies the remote name of the network resource. The user typically provides this.

Determining the values of the lpProvider and especially the dwType members of the NETRESOURCE structure is a time-consuming operation. If the calling application has these values, it should fill them in. Otherwise, it should set them to NULL. All other members in the NETRESOURCE structure are ignored.

lpBuffer

Points to the buffer that receives the result. The first field in the buffer is a NETRESOURCE structure. The dwScope, lpRemoteName, lpProvider, dwType, and dwUsage members of the structure are returned; all other members are set to NULL.

The remote name pointed to by lpRemoteName is in the same syntax as that returned from an enumeration, so that the calling application can perform a case-sensitive string comparison to determine whether the lpRemoteName resource is enumerated.

The provider name pointed to by lpProvider is always returned when it is known to which network the resource belongs. If the resource cannot be found on any of the networks, then lpRemoteName is returned as NULL, and lpProvider can be non-NULL if a parent for the resource is known to be on one of the networks.

The dwScope member is returned as RESOURCE_CONTEXT if the network resource is part of the user's network context. Otherwise, it is returned as zero.

cbBuffer

Specifies the size of the buffer passed to WNetGetResourceInformation. If the buffer is too small to receive even one entry, the function returns the required size of the buffer in this variable, as well the value WN_MORE_DATA.

lplpSystem

Points to a string in the buffer pointed to by lpBuffer that specifies the part of the resource that is accessed through system-resource type-specific functions rather than WNet functions.

For example, if the input remote resource name is "\\SERVER\SHARE\DIR", then lpRemoteName is returned pointing to "\\SERVER\SHARE" and lplpSystem points to "\DIR". Both strings are stored in the buffer pointed to by lpBuffer.

Return Value

The WNetGetResourceInformation function returns one of the following values:

Value	Meaning
WN_BAD_NETNAME	The network resource specified by the lpRemoteName member of the NETRESOURCE structure does not exist for any network. If the lpProvider member of the NETRESOURCE structure is not NULL, then a parent of the specified network resource does exist and can be accessed by calls to WNetGetResourceParent.
WN_EXTENDED_ERROR	A network-specific error occurred. Call WNetGetLastError to obtain a description of the error.
WN_MORE_DATA	The buffer is too small for the information. In this case, the function returns the required size of the buffer in cbBuffer.
WN_NO_NETWORK	The network is not present.
WN_SUCCESS	The call is successful.
See Also

NETRESOURCE, WNetCloseEnum, WNetGetLastError, WNetGetResourceParent, WNetOpenEnum


WNetGetResourceParent

The WNetGetResourceParent function lets you navigate up from a resource. It enables browsing to commence based on the name of a network resource. This function also allows navigating up from a browsed resource to find connectable resources.

You can call WNetGetResourceParent for names that were returned by WNetEnumResource. Unlike WNetGetResourceInformation, if the resource syntactically has a parent, the parent is returned by WNetGetResourceParent, whether or not the parent actually exists.

DWORD WNetGetResourceParent(

LPNETRESOURCE lpNetResource,	// specifies the network resource
LPVOID lpBuffer,	// pointer to a buffer for results
LPDWORD lpBufferSize,	// size, in bytes, of the buffer
);
Parameters

lpNetResource

Specifies the network resource for which the parent name is required. You can obtain the NETRESOURCE structure by calling WNetEnumResource or by constructing it yourself. The lpRemoteName member of the structure specifies the remote name of the network resource.

If the calling application has the values of the lpProvider and dwType members of the NETRESOURCE structure (as it would from a call to WNetGetResourceInformation), it should fill them in. Otherwise, it should set the members to NULL. All other members in the NETRESOURCE structure are ignored.

lpBuffer

Points to the buffer that receives the result, which is a single NETRESOURCE structure for the parent resource. The lpRemoteName, lpProvider, dwType, and dwUsage members are returned; all other members are set to NULL.

The remote name pointed to by lpRemoteName is in the same syntax as that returned from an enumeration, so that the caller can perform a case-sensitive string comparison to determine whether an enumerated resource is this resource.

The provider name pointed to by lpProvider is returned only if it is known to which network the resource belongs. If several networks could own the resource, (as might be the case for a resource such as "\\SERVER"), then lpProvider will be set to NULL. If a resource has no parent on any of the networks, then lpRemoteName is returned as NULL. If it is known that a network owns a parent of the resource, but the resource itself is not valid, then lpProvider is returned as a non-null value, together with a return status of WN_BAD_NETNAME.

Note that if a network shows that the object is on the network, but has no parent (for example, a server that is not part of a workgroup), then WNetGetResourceParent might return with lpRemoteName and lpProvider both set to NULL.

The RESOURCEUSAGE_CONNECTABLE value in the dwUsage member does not indicate that the resource can currently be connected to, but that the resource is connectable when it is available on the network.

lpBufferSize

Specifies the size, in bytes, of the buffer passed to WNetGetResourceParent. If the buffer is too small to hold the NETRESOURCE information, the function returns the required size of the buffer in this variable, as well as the value WN_MORE_DATA.

Return Value

The WNetGetResourceParent function returns one of the following values:

Value	Meaning
WN_ACCESS_DENIED	The user is authenticated to the network, but does not have sufficient permissions (access rights).
WN_BAD_NETNAME	The name pointed to by the lpRemoteName member is not a syntactically valid name for a remote resource for any network.
WN_BAD_PROVIDER	The name pointed to by the lpProvider member does not match any network provider.
WN_MORE_DATA	The buffer is too small for the information. In this case, the function returns the required size of the buffer in lpBufferSize.
WN_NOT_AUTHENTICATED	The caller does not have the necessary permissions to obtain the name of the parent.
WN_SUCCESS	The call is successful.
See Also

NETRESOURCE, WNetCloseEnum, WNetEnumResource, WNetGetLastError, WNetGetResourceInformation,WNetOpenEnum


WNetGetUniversalName
WNetGetUniversalName  QuickInfo  Overview  Group

The WNetGetUniversalName function takes a drive-based path for a network resource and obtains a data structure that contains a more universal form of the name.

DWORD WNetGetUniversalName(

LPCTSTR  lpLocalPath,	// address of drive-based path for a network resource
DWORD  dwInfoLevel,	// specifies form of universal name to be obtained
LPVOID  lpBuffer,	// address of buffer that receives universal name data structure
LPDWORD  lpBufferSize	// address of variable that specifies size of buffer
);
Parameters

lpLocalPath

Points to a null-terminated string that is a drive-based path for a network resource.

For example, if drive H has been mapped to a network drive share, and the network resource of interest is a file named SAMPLE.DOC in the directory \WIN32\EXAMPLES on that share, the drive-based path is H:\WIN32\EXAMPLES\SAMPLE.DOC.

dwInfoLevel

Specifies the type of data structure that the function will store in the buffer pointed to by lpBuffer. This parameter can be one of the following values:

Value	Meaning
UNIVERSAL_NAME_INFO_LEVEL	The function will store a UNIVERSAL_NAME_INFO data structure in the buffer.
REMOTE_NAME_INFO_LEVEL_	The function will store a REMOTE_NAME_INFO data structure in the buffer.
The UNIVERSAL_NAME_INFO data structure points to a Universal Naming Convention (UNC) name string.

The REMOTE_NAME_INFO data structure points to a UNC name string and two additional connection information strings.

lpBuffer

Points to a buffer that receives the type of data structure specified by the dwInfoLevel parameter.

lpBufferSize

Points to a variable that specifies the size in bytes of the buffer pointed to by lpBuffer.

If the function succeeds, it sets the variable pointed to by lpBufferSize to the size in bytes of the data structure stored in the buffer. If the function fails because the buffer is too small, indicated by the ERROR_MORE_DATA error code, it sets the variable pointed to by lpBufferSize to the required buffer size.

Return Value

If the function succeeds, the return value is NO_ERROR.

If the function fails, the return value is an error code. To get extended error information, call GetLastError. GetLastError may return one of the following error codes:

Value	Meaning
ERROR_BAD_DEVICE	The string pointed to by lpLocalPath is invalid.
ERROR_CONNECTION_UNAVAIL	There is no current connection to the remote device, but there is a remembered (persistent) connection to it.
ERROR_EXTENDED_ERROR	A network-specific error occurred. Use the WNetGetLastError function to obtain a description of the error.
ERROR_MORE_DATA	The buffer pointed to by lpBuffer is too small. The function sets the variable pointed to by lpBufferSize to the required buffer size.
ERROR_NOT_SUPPORTED	The dwInfoLevel parameter was set to UNIVERSAL_NAME_INFO_LEVEL, but the network provider does not support UNC  names. This function is not supported by any of the network providers.
ERROR_NO_NET_OR_BAD_PATH	None of the providers recognized this local name as having a connection. However, the network is not available for at least one provider to whom the connection may belong.
ERROR_NO_NETWORK	There is no network present.
ERROR_NOT_CONNECTED	The device specified by lpLocalPath is not redirected.
Remarks

A universal form of a local drive-based path identifies a network resource in an unambiguous, computer-independent manner. The name can then be passed to processes on other computers, allowing those processes to obtain access to the resource.

The WNetGetUniversalName function currently supports one universal name form: universal naming convention (UNC) names, which look like the following:

\\servername\sharename\path\file

Using the example from the preceding description of the lpLocalPath parameter, if the shared network drive is on a server named COOLSERVER, and the share name is HOTSHARE, the UNC name for the network resource whose drive-based name is H:\WIN32\EXAMPLES\SAMPLE.DOC would be

\\coolserver\hotshare\win32\examples\sample.doc

The UNIVERSAL_NAME_INFO data structure contains a pointer to a UNC name string. The REMOTE_NAME_INFO data structure contains a pointer to a UNC name string. It also includes pointers to two other useful strings. A process can pass the REMOTE_NAME_INFO structure's lpszConnectionInfo member into the WNetAddConnection2 function to connect a local device to the network resource, and then append the string pointed to by the lpszRemainingPath member to the local device string. The resulting string can be passed to Win32 functions that use a drive-based path.

See Also

REMOTE_NAME_INFO, UNIVERSAL_NAME_INFO, WNetAddConnection2, WNetGetLastError


WNetGetUser
WNetGetUser  QuickInfo  Overview  Group

The WNetGetUser function retrieves the current default user name or the user name used to establish a network connection.

DWORD WNetGetUser(

LPTSTR  lpszLocalName,	// address of local name to get user name for
LPTSTR  lpszUserName,	// address of buffer for user name
LPDWORD  lpcchBuffer	// address of buffer size variable
);
Parameters

lpszLocalName

Points to a null-terminated string that specifies either the name of the local device to return the user name for or the name of a network that the user has made a connection to.

If this parameter is NULL, Windows returns the name of the current user for the process.

If this parameter is a network name and the user is connected to that resource using different names, the network provider may not be able to resolve which user name to return. In this case, the provider may make an arbitrary choice from the possible user names.

lpszUserName

Points to a buffer that receives the null-terminated user name.

lpcchBuffer

Points to a variable that specifies the size, in characters, of the buffer pointed to by lpszUserName. If the call fails because the buffer is not big enough, this variable contains the required buffer size.

Return Value

If the function succeeds, the return value is NO_ERROR.

If the function fails, the return value is an error code. To get extended error information, call GetLastError. GetLastError may return one of the following error codes:

Value	Meaning
ERROR_NOT_CONNECTED	The device specified by lpszLocalName is not a redirected device or a connected network name.
ERROR_MORE_DATA	The buffer is too small.
ERROR_NO_NETWORK	No network is present.
ERROR_EXTENDED_ERROR	A network-specific error occurred. To get a description of the error, use the WNetGetLastError function.
ERROR_NO_NET_OR_BAD_PATH	None of the providers recognized this local name as having a connection. However, the network is not available for at least one provider to whom the connection may belong.
The function returns error codes for compatibility with Windows version 3.1. For compatibility with the Win32 API, the function also sets the error code value returned by GetLastError.

See Also

WNetGetConnection, WNetGetLastError


WNetOpenEnum
WNetOpenEnum  QuickInfo  Overview  Group

The WNetOpenEnum function starts an enumeration of network resources or existing connections.

DWORD WNetOpenEnum(

DWORD  fdwScope,	// scope of enumeration
DWORD  fdwType,	// resource types to list
DWORD  fdwUsage,	// resource usage to list
LPNETRESOURCE  lpNetResource,	// address of resource structure
LPHANDLE  lphEnum	// address of enumeration handle buffer
);
Parameters

fdwScope

Specifies the scope of the enumeration. This parameter can be one of the following values:

Value	Meaning
RESOURCE_CONNECTED	All currently connected resources (the fdwUsage parameter is ignored).
RESOURCE_GLOBALNET	All resources on the network.
RESOURCE_REMEMBERED	All remembered (persistent) connections (fdwUsage is ignored).
fdwType

Specifies the resource types to enumerate. This parameter can be a combination of the following values:

Value	Meaning
RESOURCETYPE_ANY	All resources (this value cannot be combined with RESOURCETYPE_DISK or RESOURCETYPE_PRINT).
RESOURCETYPE_DISK	All disk resources.
RESOURCETYPE_PRINT	All print resources.
If a network provider cannot distinguish between print and disk resources, it may enumerate all resources.

fdwUsage

Specifies the resource usage to be enumerated. This parameter can be a combination of the following values:

Value	Meaning
0	All resources
RESOURCEUSAGE_CONNECTABLE	All connectable resources
RESOURCEUSAGE_CONTAINER	All container resources
This parameter is ignored if the fdwScope parameter is not RESOURCE_GLOBALNET.

lpNetResource

Points to a NETRESOURCE structure specifying the container to enumerate.

If this parameter is NULL, the root of the network is assumed. Windows organizes a network as a hierarchy; the root is the topmost container in the network. For more information about the Windows network functions, see Networks.

If this parameter is not NULL, it must point to a NETRESOURCE structure. This structure can be filled in by the application or be returned by a call to the WNetEnumResource function. The NETRESOURCE structure must specify a container resource; that is, the RESOURCEUSAGE_CONTAINER value must be specified in the dwUsage member.

To enumerate all network resources, an application can begin the enumeration by calling WNetOpenEnum with lpNetResource set to NULL and then use the returned handle with WNetEnumResource to enumerate resources. If one of the resources in the NETRESOURCE array returned by the WNetEnumResource function is a container resource, WNetOpenEnum can be used to open the resource for further enumeration.

If the fdwScope parameter is not RESOURCE_GLOBALNET, this parameter must be NULL.

lphEnum

Points to a variable filled with an enumeration handle that can be used in a subsequent call to WNetEnumResource.

Return Value

If the function succeeds, the return value is NO_ERROR.

If the function fails, the return value is an error code. To get extended error information, call GetLastError. GetLastError may return one of the following error codes:

Value	Meaning
ERROR_NOT_CONTAINER	The lpNetResource parameter does not point to a container.
ERROR_INVALID_PARAMETER	Either the fdwScope or fdwType parameter is invalid, or there is a bad combination of parameters.
ERROR_NO_NETWORK	No network is present.
ERROR_EXTENDED_ERROR	A network-specific error occurred. To get a description of the error, use the WNetGetLastError function.
The function returns error codes for compatibility with Windows version 3.1. For compatibility with Windows NT, the function also sets the error code value returned by GetLastError.

Remarks

The WNetOpenEnum function is used to begin enumeration of the resources in a single container. The following examples show the hierarchical structure of a Microsoft LAN Manager network and a Novell Netware network:

LanMan (container, in this case the provider)

  ACCOUNTING (container, in this case the domain)

    \\ACCTSPAY (container, in this case the server)

      PAYFILES (disk)

      LASERJET (print)

Netware (container, in this case the provider)

  MARKETING (container, in this case the server)

    SYS (disk, first one on any Netware server)

    ANOTHERVOLUME (disk)

    LASERJET (print)

See Also

NETRESOURCE, WNetCloseEnum, WNetEnumResource, WNetGetLastError


WriteConsole
WriteConsole  QuickInfo  Overview  Group

The WriteConsole function writes a character string to a console screen buffer beginning at the current cursor location.

BOOL WriteConsole(

HANDLE  hConsoleOutput,	// handle of a console screen buffer
CONST VOID  *lpvBuffer,	// address of buffer to write from
DWORD  cchToWrite,	// number of characters to write
LPDWORD  lpcchWritten,	// address of number of characters written
LPVOID  lpvReserved	// reserved
);
Parameters

hConsoleOutput

Identifies the console screen buffer to be written to. The handle must have GENERIC_WRITE access.

lpvBuffer

Points to a buffer that contains characters to be written to the screen buffer.

cchToWrite

Specifies the number of characters to write.

lpcchWritten

Points to a 32-bit variable that receives the number of characters actually written.

lpvReserved

Reserved; must be NULL.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

WriteConsole writes characters to a console screen buffer. It behaves like the WriteFile function, except it can write in either Unicode (wide-character) or ANSI mode. To create an application that maintains a single set of sources compatible with both modes, use WriteConsole rather than WriteFile. Although WriteConsole can be used only with a console screen buffer handle, WriteFile can be used with other handles (such as files or pipes). WriteConsole fails if used with a standard handle that has been redirected to be something other than a console handle.

Although an application can use WriteConsole in ANSI mode to write ANSI characters, consoles do not support ANSI escape sequences. However, some Win32 functions provide equivalent functionality: for example, SetCursorPos, SetConsoleTextAttribute, and GetConsoleCursorInfo.

WriteConsole writes characters to the screen buffer at the current cursor position. The cursor position advances as characters are written. The SetConsoleCursorPosition function sets the current cursor position.

Characters are written using the foreground and background color attributes associated with the screen buffer. The SetConsoleTextAttribute function changes these colors. To determine the current color attributes and the current cursor position, use GetConsoleScreenBufferInfo.

All of the input modes that affect the behavior of WriteFile have the same effect on WriteConsole. To retrieve and set the output modes of a console screen buffer, use the GetConsoleMode and SetConsoleMode functions.

See Also

GetConsoleCursorInfo, GetConsoleMode, GetConsoleScreenBufferInfo, ReadConsole, SetConsoleCursorPosition, SetConsoleMode, SetConsoleTextAttribute, SetCursorPos, WriteFile


WriteConsoleInput
WriteConsoleInput  QuickInfo  Overview  Group

The WriteConsoleInput function writes data directly to the console input buffer.

BOOL WriteConsoleInput(

HANDLE  hConsoleInput,	// handle of a console input buffer
PINPUT_RECORD  pirBuffer,	// address of the buffer for write data
DWORD  cInRecords,	// number of records to write
LPDWORD  lpcWritten	// address of number of records written
);
Parameters

hConsoleInput

Identifies the input buffer. The handle must have GENERIC_WRITE access.

pirBuffer

Points to an INPUT_RECORD buffer containing data to be written to the input buffer.

cInRecords

Specifies the number of input records to be written.

lpcWritten

Points to a 32-bit variable that receives the number of input records actually written.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

WriteConsoleInput places input records into the input buffer behind any pending events in the buffer. The input buffer grows dynamically, if necessary, to hold as many events as are written.

See Also

INPUT_RECORD, PeekConsoleInput, ReadConsoleInput


WriteConsoleOutput
WriteConsoleOutput  QuickInfo  Overview  Group

The WriteConsoleOutput function writes character and color attribute data to a specified rectangular block of character cells in a console screen buffer. The data to be written is taken from a correspondingly sized rectangular block at a specified location in the source buffer.

BOOL WriteConsoleOutput(

HANDLE  hConsoleOutput,	// handle of a console screen buffer
PCHAR_INFO  pchiSrcBuffer,	// address of buffer with data to write
COORD  coordSrcBufferSize,	// column-row size of source buffer
COORD  coordSrcBufferCoord,	// upper-left cell to write from
PSMALL_RECT  psrctDestRect	// address of rectangle to write to
);
Parameters

hConsoleOutput

Identifies the screen buffer. The handle must have GENERIC_WRITE access.

pchiSrcBuffer

Points to a source buffer that contains the data to be written to the screen buffer. This pointer is treated as the origin of a two-dimensional array of CHAR_INFO structures whose size is specified by the coordSrcBufferSize parameter.

coordSrcBufferSize

Specifies the size, in character cells, of the buffer pointed to by the pchiSrcBuffer parameter. The X member of the COORD structure is the number of columns; the Y member is the number of rows.

coordSrcBufferCoord

Specifies the coordinates of the upper-left cell in the buffer pointed to by the pchiSrcBuffer parameter to write data from. The X member of the COORD structure is the column, and the Y member is the row.

psrctDestRect

Points to a SMALL_RECT structure. On input, the structure members specify the upper-left and lower-right coordinates of the screen buffer rectangle to write to. On output, the structure members specify the actual rectangle that was written to.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

WriteConsoleOutput treats the source buffer and the destination screen buffer as two-dimensional arrays (columns and rows of character cells). The rectangle pointed to by the psrctDestRect parameter specifies the size and location of the block to be written to in the screen buffer. A rectangle of the same size is located with its upper-left cell at the coordinates of the coordSrcBufferCoord parameter in the pchiSrcBuffer array. Data from the cells that are in the intersection of this rectangle and the source buffer rectangle (whose dimensions are specified by the coordSrcBufferSize parameter) is written to the destination rectangle.

Cells in the destination rectangle whose corresponding source location are outside the boundaries of the source buffer rectangle are left unaffected by the write operation. In other words, these are the cells for which no data is available to be written.

Before WriteConsoleOutput returns, it sets the members of psrctDestRect to the actual screen buffer rectangle affected by the write operation. This rectangle reflects the cells in the destination rectangle for which there existed a corresponding cell in the source buffer, because WriteConsoleOutput clips the dimensions of the destination rectangle to the boundaries of the screen buffer.

If the rectangle specified by psrctDestRect lies completely outside the boundaries of the screen buffer, or if the corresponding rectangle is positioned completely outside the boundaries of the source buffer, no data is written. In this case, the function returns with the members of the structure pointed to by the psrctDestRect parameter set such that the Right member is less than the Left, or the Bottom member is less than the Top. To determine the size of the screen buffer, use the GetConsoleScreenBufferInfo function.

WriteConsoleOutput has no effect on the cursor position.

See Also

CHAR_INFO, COORD, GetConsoleScreenBufferInfo, ReadConsoleOutput, ReadConsoleOutputAttribute, ReadConsoleOutputCharacter, SMALL_RECT, WriteConsoleOutputAttribute, WriteConsoleOutputCharacter


WriteConsoleOutputAttribute
WriteConsoleOutputAttribute  QuickInfo  Overview  Group

The WriteConsoleOutputAttribute function copies a number of foreground and background color attributes to consecutive cells of a console screen buffer, beginning at a specified location.

BOOL WriteConsoleOutputAttribute(

HANDLE  hConsoleOutput,	// handle of a console screen buffer
LPWORD  lpwAttribute,	// address of buffer to write attributes from
DWORD  cWriteCells,	// number of character cells to write to
COORD  coordWrite,	// coordinates of first cell to write to
LPDWORD  lpcWritten	// address of number of cells written to
);
Parameters

hConsoleOutput

Identifies the screen buffer. The handle must have GENERIC_WRITE access.

lpwAttribute

Points to a buffer that contains the attributes to write to the screen buffer.

cWriteCells

Specifies the number of screen buffer character cells to write to.

coordWrite

Specifies the column and row coordinates of the first cell in the screen buffer to write to.

lpcWritten

Points to a 32-bit variable that receives the number of attributes actually written to the screen buffer.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

If the number of attributes to be written to extends beyond the end of the specified row in the screen buffer, attributes are written to the next row. If the number of attributes to be written to extends beyond the end of the screen buffer, the attributes are written up to the end of the screen buffer.

The character values at the positions written to are not changed.

Each attribute specifies the foreground (text) and background colors in which that character cell is drawn. The attribute values are some combination of the following values: FOREGROUND_BLUE, FOREGROUND_GREEN, FOREGROUND_RED, FOREGROUND_INTENSITY, BACKGROUND_BLUE, BACKGROUND_GREEN, BACKGROUND_RED, and BACKGROUND_INTENSITY. For example, the following combination of values produces red text on a white background:

FOREGROUND_RED | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE

See Also

ReadConsoleOutput, ReadConsoleOutputAttribute, ReadConsoleOutputCharacter, WriteConsoleOutput, WriteConsoleOutputCharacter


WriteConsoleOutputCharacter
WriteConsoleOutputCharacter  QuickInfo  Overview  Group

The WriteConsoleOutputCharacter function copies a number of characters to consecutive cells of a console screen buffer, beginning at a specified location.

BOOL WriteConsoleOutputCharacter(

HANDLE  hConsoleOutput,	// handle of a console screen buffer
LPTSTR  lpWriteBuffer,	// address of buffer to write characters from
DWORD  cchWrite,	// number of character cells to write to
COORD  coordWriteCoord,	// coordinates of first cell to write to
LPDWORD  lpcWritten	// address of number of cells written to
);
Parameters

hConsoleOutput

Identifies the screen buffer. The handle must have GENERIC_WRITE access.

lpWriteBuffer

Points to a buffer that contains the characters to write to the screen buffer.

cchWrite

Specifies the number of screen buffer character cells to write to.

coordWriteCoord

Specifies the column and row coordinates of the first cell in the screen buffer to write to.

lpcWritten

Points to a 32-bit variable that receives the number of characters actually written.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

If the number of characters to be written to extends beyond the end of the specified row in the screen buffer, characters are written to the next row. If the number of characters to be written to extends beyond the end of the screen buffer, characters are written up to the end of the screen buffer.

The attribute values at the positions written to are not changed.

See Also

ReadConsoleOutput, ReadConsoleOutputAttribute, ReadConsoleOutputCharacter, WriteConsoleOutput, WriteConsoleOutputAttribute


WriteFile
WriteFile  QuickInfo  Overview  Group

The WriteFile function writes data to a file and is designed for both synchronous and asynchronous operation. The function starts writing data to the file at the position indicated by the file pointer. After the write operation has been completed, the file pointer is adjusted by the number of bytes actually written, except when the file is opened with FILE_FLAG_OVERLAPPED. If the file handle was created for overlapped input and output (I/O), the application must adjust the position of the file pointer after the write operation is finished.

BOOL WriteFile(

HANDLE  hFile,	// handle of file to write to
LPCVOID  lpBuffer,	// address of data to write to file
DWORD  nNumberOfBytesToWrite,	// number of bytes to write
LPDWORD  lpNumberOfBytesWritten,	// address of number of bytes written
LPOVERLAPPED  lpOverlapped	// addr. of structure needed for overlapped I/O
);
Parameters

hFile

Identifies the file to be written to. The file handle must have been created with GENERIC_WRITE access to the file.

Windows NT

For asynchronous write operations, hFile can be any handle opened with the FILE_FLAG_OVERLAPPED flag by the CreateFile function, or a socket handle returned by the socket or accept functions.

Windows 95

For asynchronous write operations, hFile can be a communications resource, mailslot, or named pipe handle opened with the FILE_FLAG_OVERLAPPED flag by CreateFile, or a socket handle returned by the socket or accept functions. Windows 95 does not support asynchronous write operations on disk files.

lpBuffer

Points to the buffer containing the data to be written to the file.

nNumberOfBytesToWrite

Specifies the number of bytes to write to the file.

Unlike the MS-DOS operating system, Windows NT interprets a value of zero as specifying a null write operation. A null write operation does not write any bytes but does cause the time stamp to change.

Named pipe write operations across a network are limited to 65535 bytes.

lpNumberOfBytesWritten

Points to the number of bytes written by this function call. WriteFile sets this value to zero before doing any work or error checking.

lpOverlapped

Points to an OVERLAPPED structure. This structure is required if hFile was opened with FILE_FLAG_OVERLAPPED.

This parameter should not be NULL if hFile was opened with FILE_FLAG_OVERLAPPED. It should point to a valid OVERLAPPED structure. If hFile was created with FILE_FLAG_OVERLAPPED and lpOverlapped is NULL, the function fails in unpredictable ways.

If hFile was not created with FILE_FLAG_OVERLAPPED and lpOverlapped is NULL, the write operation starts at the current file position and WriteFile does not return until the operation has been completed.

If hFile was created with FILE_FLAG_OVERLAPPED and lpOverlapped is not NULL, the write operation starts at the offset specified in the OVERLAPPED structure and WriteFile may return before the write operation has been completed. In this case, WriteFile returns FALSE and the GetLastError function returns ERROR_IO_PENDING. This allows the calling process to continue processing while the write operation is being completed. The event specified in the OVERLAPPED structure is set to the signaled state upon completion of the write operation.

If hFile was not created with FILE_FLAG_OVERLAPPED and lpOverlapped is not NULL, the write operation starts at the offset specified in the OVERLAPPED structure and WriteFile does not return until the write operation has been completed.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

If part of the file is locked by another process and the write operation overlaps the locked portion, this function fails.

Applications must not read from nor write to the input buffer that a read operation is using until the read operation completes. A premature access to the input buffer may lead to corruption of the data read into that buffer.

Characters can be written to the screen buffer using WriteFile with a handle to console output. The exact behavior of the function is determined by the console mode. The data is written to the current cursor position. The cursor position is updated after the write operation.

Unlike the MS-DOS operating system, Windows NT interprets zero bytes to write as specifying a null write operation and WriteFile does not truncate or extend the file. To truncate or extend a file, use the SetEndOfFile function.

When writing to a nonblocking, byte-mode pipe handle with insufficient buffer space, WriteFile returns TRUE with *lpNumberOfBytesWritten < nNumberOfBytesToWrite.

When an application uses the WriteFile function to write to a pipe, the write operation may not finish if the pipe buffer is full. The write operation is completed when a read operation (using the ReadFile function) makes more buffer space available.

If the anonymous read pipe handle has been closed and WriteFile attempts to write using the corresponding anonymous write pipe handle, the function returns FALSE and GetLastError returns ERROR_BROKEN_PIPE.

The WriteFile function may fail with ERROR_INVALID_USER_BUFFER or ERROR_NOT_ENOUGH_MEMORY whenever there are too many outstanding asynchronous I/O requests.

If hFile is a handle to a named pipe, the Offset and OffsetHigh members of the OVERLAPPED structure pointed to by lpOverlapped must be zero, or the function will fail.

See Also

CreateFile, GetLastError, GetOverlappedResult, OVERLAPPED, ReadFile, SetEndOfFile, WriteFileEx


WriteFileEx
WriteFileEx  QuickInfo  Overview  Group

The WriteFileEx function writes data to a file. It is designed solely for asynchronous operation, unlike WriteFile, which is designed for both synchronous and asynchronous operation.

WriteFileEx reports its completion status asynchronously, calling a specified completion routine when writing is completed and the calling thread is in an alertable wait state.

BOOL WriteFileEx(

HANDLE  hFile;	// handle to output file
LPCVOID  lpBuffer;	// pointer to input buffer
DWORD  nNumberOfBytesToWrite;	// number of bytes to write
LPOVERLAPPED  lpOverlapped;	// pointer to async. i/o data
LPOVERLAPPED_COMPLETION_ROUTINE  lpCompletionRoutine;	// ptr. to completion routine
);
Parameters

hFile

An open handle that specifies the file entity to be written to. This file handle must have been created with the FILE_FLAG_OVERLAPPED flag and with GENERIC_WRITE access to the file.

Windows NT : hFile can be any handle opened with the FILE_FLAG_OVERLAPPED flag by the CreateFile function, or a socket handle returned by the socket or accept functions.

Windows 95 : hFile can be a communications resource, mailslot, or named pipe handle opened with the FILE_FLAG_OVERLAPPED flag by CreateFile, or a socket handle returned by the socket or accept functions. Windows 95 does not support asynchronous operations on disk files.

lpBuffer

Points to the buffer containing the data to be written to the file.

This buffer must remain valid for the duration of the write operation. The caller must not use this buffer until the write operation is completed.

nNumberOfBytesToWrite

Specifies the number of bytes to write to the file.

If nNumberOfBtyesToWrite is zero, this function does nothing; in particular, it does not truncate the file. For additional discussion, see the following Remarks section.

lpOverlapped

Points to an OVERLAPPED data structure that supplies data to be used during the overlapped (asynchronous) write operation.

For files that support byte offsets, you must specify a byte offset at which to start writing to the file. You specify this offset by setting the Offset and OffsetHigh members of the OVERLAPPED structure. For files that do not support byte offsets — named pipes, for example — you must set Offset and OffsetHigh to zero, or WriteFileEx fails.

The WriteFileEx function ignores the OVERLAPPED structure's hEvent member. An application is free to use that member for its own purposes in the context of a WriteFileEx call. WriteFileEx signals completion of its writing operation by calling, or queueing a call to, the completion routine pointed to by lpCompletionRoutine, so it does not need an event handle.

The WriteFileEx function does use the Internal and InternalHigh members of the OVERLAPPED structure. You should not change the value of these members.

The OVERLAPPED data structure must remain valid for the duration of the write operation. It should not be a variable that can go out of scope while the write operation is pending completion.

lpCompletionRoutine

Points to a completion routine to be called when the write operation has been completed and the calling thread is in an alertable wait state. For more information about this completion routine, see FileIOCompletionRoutine.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

If the WriteFileEx function succeeds, the calling thread has an asynchronous I/O (input/output) operation pending: the overlapped write operation to the file. When this I/O operation finishes, and the calling thread is blocked in an alertable wait state, the operating system calls the function pointed to by lpCompletionRoutine, and the wait completes with a return code of WAIT_IO_COMPLETION.

If the function succeeds and the file-writing operation finishes, but the calling thread is not in an alertable wait state, the system queues the call to *lpCompletionRoutine, holding the call until the calling thread enters an alertable wait state. See Synchronization for more information about alertable wait states and overlapped input/output operations.

Remarks

If part of the output file is locked by another process, and the specified write operation overlaps the locked portion, the WriteFileEx function fails.

Applications must not read from nor write to the input buffer that a read operation is using until the read operation completes. A premature access to the input buffer may lead to corruption of the data read into that buffer.

The WriteFileEx function may fail, returning the messages ERROR_INVALID_USER_BUFFER or ERROR_NOT_ENOUGH_MEMORY if there are too many outstanding asynchronous I/O requests.

If hFile is a handle to a named pipe, or other file entity that doesn't support byte offsets, the Offset and OffsetHigh members of the OVERLAPPED structure pointed to by lpOverlapped must be zero, or the WriteFileEx function fails.

An application uses the WaitForSingleObjectEx, WaitForMultipleObjectsEx, and SleepEx functions to enter an alertable wait state. Refer to those functions and the overview Synchronization for more information about alertable wait states and overlapped input/output operations.

Windows 95: On this platform, neither WriteFileEx nor ReadFileEx can be used by the comm ports to communicate. However, you can use WriteFile and ReadFile to perform asynchronous communication.

See Also

CreateFile, FileIOCompletionRoutine, OVERLAPPED, ReadFileEx, SetEndOfFile, SleepEx, WaitForMultipleObjectsEx, WaitForSingleObjectEx, WriteFile


WritePrinter
WritePrinter  QuickInfo  Overview  Group

The WritePrinter function informs the print spooler that data should be written to the specified printer.

BOOL WritePrinter(

HANDLE  hPrinter,	// handle of printer object
LPVOID  pBuf,	// address of array that contains printer data
DWORD  cbBuf,	// size, in bytes, of array
LPDWORD  lpdwWritten	// addr. of variable with count of bytes written
);
Parameters

hPrinter

Identifies the printer.

pBuf

Points to an array of bytes that contains the data that should be written to the printer.

cbBuf

Specifies the size, in bytes, of the array.

lpdwWritten

Points to a value that specifies the number of bytes of data that were written to the printer.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

See Also

OpenPrinter


WritePrivateProfileSection
WritePrivateProfileSection  QuickInfo

The WritePrivateProfileSection function replaces the keys and values under the specified section in an initialization file.

This function is provided for compatibility with 16-bit Windows-based applications. Win32-based applications should store initialization information in the registry.

BOOL WritePrivateProfileSection(

LPCTSTR  lpszSection,	// address of string with section name
LPCTSTR  lpszKeysAndValues,	// address of string with data
LPCTSTR  lpszFile	// address of string with filename
);
Parameters

lpszSection

Points to a null-terminated string containing the name of the section in which data is written. This section name is typically the name of the calling application.

lpszKeysAndValues

Points to a buffer containing the new key names and associated values that are written to the named section.

lpszFile

Points to a null-terminated string containing the name of the initialization file. If this parameter does not contain a full path for the file, the function searches the Windows directory for the file. If the file does not exist and lpszFile does not contain a full path, the function creates the file in the Windows directory. The function does not create a file if lpszFile contains the full path and filename of a file that does not exist.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

The data in the buffer pointed to by the lpszKeysAndValues parameter consists of one or more null-terminated strings, followed by a final null character. Each string has the following form:

key=string

The WritePrivateProfileSection function is not case-sensitive; the string pointed to by the lpszSection parameter can be a combination of uppercase and lowercase letters.

If no section name matches the string pointed to by the lpszSection parameter, WritePrivateProfileSection creates the section at the end of the specified initialization file and initializes the new section with the specified key name and value pairs.

WritePrivateProfileSection deletes the existing keys and values for the named section and inserts the key names and values in the buffer pointed to by the lpszKeysAndValues parameter. The function does not attempt to correlate old and new key names; if the new names appear in a different order from the old names, any comments associated with preexisting keys and values in the initialization file will probably be associated with incorrect keys and values.

This operation is atomic; no operations that read from or write to the specified initialization file are allowed while the information is being written.

Windows 95

Windows 95 keeps a cached version of WIN.INI to improve performance. If all three parameters are NULL, the function flushes the cache. The function always returns FALSE after flushing the cache, regardless of whether the flush succeeds or fails.

Windows NT

Windows NT maps most .INI file references to the registry, using the mapping defined under the following registry key:

HKEY_LOCAL_MACHINE\Software\Microsoft\
        Windows NT\CurrentVersion\IniFileMapping

This mapping is likely if an application modifies system-component initialization files, such as as CONTROL.INI, SYSTEM.INI, and WINFILE.INI. In this case, the WritePrivateProfileSection function writes information to the registry, not to the initialization file; the change in the storage location has no effect on the function's behavior.

See Also

GetPrivateProfileSection, RegCreateKeyEx, RegSetValueEx, WriteProfileSection


WritePrivateProfileString
WritePrivateProfileString  QuickInfo

The WritePrivateProfileString function copies a string into the specified section of the specified initialization file.

This function is provided for compatibility with 16-bit Windows-based applications. WIn32-based applications should store initialization information in the registry.

BOOL WritePrivateProfileString(

LPCTSTR  lpszSection,	// address of section name
LPCTSTR  lpszKey,	// address of key name
LPCTSTR  lpszString,	// address of string to add
LPCTSTR  lpszFile	// address of initialization filename
);
Parameters

lpszSection

Points to a null-terminated string containing the name of the section to which the string will be copied. If the section does not exist, it is created. The name of the section is case-independent; the string can be any combination of uppercase and lowercase letters.

lpszKey

Points to the null-terminated string containing the name of the key to be associated with a string. If the key does not exist in the specified section, it is created. If this parameter is NULL, the entire section, including all entries within the section, is deleted.

lpszString

Points to a null-terminated string to be written to the file. If this parameter is NULL, the key pointed to by the lpszKey parameter is deleted.

Windows 95: This platform does not support the use of the TAB (\t) character as part of this parameter.

lpszFile

Points to a null-terminated string that names the initialization file.

Return Value

If the function successfully copies the string to the initialization file, the return value is TRUE.

If the function fails, or if it flushes the cached version of the most recently accessed initialization file, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Windows 95

Windows 95 keeps a cached version of WIN.INI to improve performance. If all three parameters are NULL, the function flushes the cache. The function always returns FALSE after flushing the cache, regardless of whether the flush succeeds or fails.

A section in the initialization file must have the following form:

[section]
key=string
      .
      .
      .

If the lpszFile parameter does not contain a full path and filename for the file, WritePrivateProfileString searches the Windows directory for the file. If the file does not exist, this function creates the file in the Windows directory.

If lpszFile contains a full path and filename and the file does not exist, WriteProfileString creates the file. The specified directory must already exist.

Windows NT

Windows NT maps most .INI file references to the registry, using the mapping defined under the following registry key:

HKEY_LOCAL_MACHINE\Software\Microsoft\
        Windows NT\CurrentVersion\IniFileMapping

Windows NT keeps a cache for the IniFleMapping registry key. Calling WritePrivateProfileStringW with the value of all arguments set to NULL will cause Windows NT to refresh its cache of the IniFileMappingKey for the specified .INI file.

An application using the WritePrivateProfileStringW function to enter .INI file information into the registry should follow these guidelines:

•	Ensure that no .INI file of the specified name exists on the system.

•	Ensure that there is a key entry in the registry that specifies the .INI file. This entry should be under the path HKEY_LOCAL_MACHINE\SOFTWARE \Microsoft\Windows NT\CurrentVersion\IniFileMapping.

•	Specify a value for that .INI file key entry that specifies a section. That is to say, an application must specify a section name, as it would appear within an .INI file or registry entry. Here is an example: [My Section].

•	For system files, specify SYS for an added value.

•	For application files, specify USR within the added value. Here is an example: "My Section: USR: App Name\Section". And, since USR indicates a mapping under HKEY_CURRENT_USER, the application should also create a key under HKEY_CURRENT_USER that specifies the application name listed in the added value. For the example just given, that would be "App Name".

•	After following the preceding steps, an application setup program should call WritePrivateProfileStringW with the first three parameters set to NULL, and the fourth parameter set to the INI filename. For example:

WritePrivateProfileStringW( NULL, NULL, NULL, L"appname.ini" );

Such a call causes the mapping of an .INI file to the registry to take effect before the next system reboot. The operating system re-reads the mapping information into shared memory. A user will not have to reboot their computer after installing an application in order to have future invocations of the application see the mapping of the .INI file to the registry.

The following sample code illustrates the preceding guidelines and is based on several assumptions:

•	There is an application named "App Name."

•	That application uses an .INI file named "appname.ini."

•	There is a section in the .INI file that we want to look like this:

[Section1]

  FirstKey = It all worked out okay.

  SecondKey = By golly, it works.

  ThirdKey = Another test.

•	The user will not have to reboot the system in order to have future invocations of the application see the mapping of the .INI file to the registry.

Here is the sample code :

// include files

#include <stdio.h>

#include <windows.h>

// a main function

main()

{

  // local variables

  CHAR inBuf[80];

  HKEY  hKey1, hKey2;

  DWORD  dwDisposition;

  LONG   lRetCode;

  // try to create the .INI file key

  lRetCode = RegCreateKeyEx ( HKEY_LOCAL_MACHINE,

                              "SOFTWARE\\Microsoft\\Windows NT

                               \\CurrentVersion\\IniFileMapping\\appname.ini",

                              0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE,

                              NULL, &hKey1,

                              &dwDisposition);

  // if we failed, note it, and leave

  if (lRetCode != ERROR_SUCCESS){

    printf ("Error in creating appname.ini key\n");

    return (0) ;

    }

  // try to set a section value

  lRetCode = RegSetValueEx ( hKey1,

                             "Section1",

                             0,

                             REG_SZ,

                             "USR:App Name\\Section1",

                             20);

  // if we failed, note it, and leave

  if (lRetCode != ERROR_SUCCESS) {

    printf ( "Error in setting Section1 value\n");

    return (0) ;

    }

  // try to create an App Name key

  lRetCode = RegCreateKeyEx ( HKEY_CURRENT_USER,

                              "App Name",

                              0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE,

                              NULL, &hKey2,

                              &dwDisposition);

  // if we failed, note it, and leave

  if (lRetCode != ERROR_SUCCESS) {

    printf ("Error in creating App Name key\n");

    return (0) ;

    }

  // force the operating system to re-read the mapping into shared memory

  //    so that future invocations of the application will see it

  //    without the user having to reboot the system

  WritePrivateProfileStringW( NULL, NULL, NULL, L"appname.ini" );

  // if we get this far, all has gone well

  // let's write some added values

  WritePrivateProfileString ("Section1", "FirstKey",

                             "It all worked out okay.", "appname.ini");

  WritePrivateProfileString ("Section1", "SecondKey",

                             "By golly, it works.", "appname.ini");

  WritePrivateProfileSection ("Section1", "ThirdKey = Another Test.",

                              "appname.ini");

  // let's test our work

  GetPrivateProfileString ("Section1", "FirstKey",

                           "Bogus Value: Get didn't work", inBuf, 80,

                           "appname.ini");

  printf ("%s", inBuf);

  // okay, we are outta here

  return(0);

}

See Also

GetPrivateProfileString, WriteProfileString


WritePrivateProfileStruct [New - Windows NT]
WritePrivateProfileStruct  QuickInfo

[New - Windows NT]

The WritePrivateProfileStruct function copies data into the specified key in the given section of an initialization file. As it copies the data, the function calculates a checksum and appends it to the end of the data. The GetPrivateProfileStruct function uses the checksum to ensure the integrity of the data. This function is provided for compatibility with 16-bit Windows-based applications. Win32-based applications should store initialization information in the registry.

BOOL WritePrivateProfileStruct(

LPCTSTR  lpszSection,	// address of section name
LPCTSTR  lpszKey,	// address of key name
LPVOID  lpvStruct,	// address of buffer that contains data to add
UINT  uSizeStruct,	// size, in bytes, of the buffer
LPCTSTR  lpszFile	// address of initialization filename
);
Parameters

lpszSection

Points to a null-terminated string containing the name of the section to which the string will be copied. If the section does not exist, it is created. The name of the section is case independent, the string can be any combination of uppercase and lowercase letters.

lpszKey

Points to the null-terminated string containing the name of the key to be associated with a string. If the key does not exist in the specified section, it is created. If this parameter is NULL, the entire section, including all keys and entries within the section, is deleted.

lpvStruct

Points to a buffer that contains the data to copy. If this parameter is NULL, the given key is deleted.

uSizeStruct

Specifies the size, in bytes, of the buffer pointed to by the lpvStruct parameter.

lpszFile

Points to a null-terminated string that names the initialization file. If this parameter is NULL, the given information is copied into the WIN.INI file.

Return Value

If the function successfully copies the string to the initialization file, the return value is TRUE.

If the function fails, or if it flushes the cached version of the most recently accessed initialization file, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Windows 95 keeps a cached version of WIN.INI to improve performance. If all three parameters are NULL, the function flushes the cache. The function always returns FALSE after flushing the cache, regardless of whether the flush succeeds or fails.

A section in the initialization file must have the following form:

[section]
key=string
      .
      .
      .

If the lpszFile parameter does not contain a full path and filename for the file, WritePrivateProfileString searches the Windows directory for the file. If the file does not exist, this function creates the file in the Windows directory.

If lpszFile contains a full path and filename and the file does not exist, WriteProfileString creates the file. The specified directory must already exist.

See Also

GetPrivateProfileString, WriteProfileString


WriteProcessMemory
WriteProcessMemory  QuickInfo  Overview  Group

The WriteProcessMemory function writes memory in a specified process. The entire area to be written to must be accessible, or the operation fails.

BOOL WriteProcessMemory(

HANDLE  hProcess,	// handle of process whose memory is written to
LPVOID  lpBaseAddress,	// address to start writing to
LPVOID  lpBuffer,	// address of buffer to write data to
DWORD  cbWrite,	// number of bytes to write
LPDWORD  lpNumberOfBytesWritten	// actual number of bytes written
);
Parameters

hProcess

Identifies an open handle of a process whose memory is to be written to. The handle must have PROCESS_VM_WRITE and PROCESS_VM_OPERATION access to the process.

lpBaseAddress

Points to the base address in the specified process to be written to. Before any data transfer occurs, the system verifies that all data in the base address and memory of the specified size is accessible for write access. If this is the case, the function proceeds; otherwise, the function fails.

lpBuffer

Points to the buffer that supplies data to be written into the address space of the specified process.

cbWrite

Specifies the requested number of bytes to write into the specified process.

lpNumberOfBytesWritten

Points to the actual number of bytes transferred into the specified process. This parameter is optional. If lpNumberOfBytesWritten is NULL, the parameter is ignored.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError. The function will fail if the requested write operation crosses into an area of the process that is inaccessible.

Remarks

WriteProcessMemory copies the data from the specified buffer in the current process to the address range of the specified process. Any process that has a handle with PROCESS_VM_WRITE and PROCESS_VM_OPERATION access to the process to be written to can call the function. The process whose address space is being written to is typically, but not necessarily, being debugged.

The entire area to be written to must be accessible. If it is not, the function fails as noted previously.

See Also

ReadProcessMemory


WriteProfileSection
WriteProfileSection  QuickInfo

The WriteProfileSection function replaces the contents of the specified section in the WIN.INI file with the specified keys and values.

This function is provided for compatibility with 16-bit Windows applications. Win32-based applications should store initialization information in the registry.

BOOL WriteProfileSection(

LPCTSTR  lpszSection,	// address of section name
LPCTSTR  lpszKeysAndValues	// address of buffer with data
);
Parameters

lpszSection

Points to a null-terminated string containing the name of the section in which data is written. This section name is typically the name of the calling application.

lpszKeysAndValues

Points to a buffer containing the new key names and associated values that are written to the named section.

Return Value

If the function succeeds, the return value is TRUE.

If the function fails, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Windows 95

If there is no section in WIN.INI that matches the specified section name, WriteProfileSection creates the section at the end of the file and initializes the new section with the key name and value pairs specified in the lpszKeysAndValues parameter.

Keys and values in the lpszKeysAndValues buffer consist of one or more null-terminated strings, followed by a final null character. Each string has the following form:

key=string

The WriteProfileSection function is not case-sensitive; the strings can be a combination of uppercase and lowercase letters.

WriteProfileSection deletes the existing keys and values for the named section and inserts the key names and values in the buffer pointed to by lpszKeysAndValues. The function does not attempt to correlate old and new key names; if the new names appear in a different order from the old names, any comments associated with preexisting keys and values in the initialization file will probably be associated with incorrect keys and values.

This operation is atomic; no other operations that read from or write to the initialization file are allowed while the information is being written.

Windows NT

Windows NT maps most .INI file references to the registry, using the mapping defined under the following registry key:

HKEY_LOCAL_MACHINE\Software\Microsoft\
        Windows NT\CurrentVersion\IniFileMapping

When the operation has been mapped, the WriteProfileSection function writes information to the registry, not to the initialization file; the change in the storage location has no effect on the function's behavior.

See Also

GetProfileSection, WritePrivateProfileSection


WriteProfileString
WriteProfileString  QuickInfo

The WriteProfileString function copies a string into the specified section of the WIN.INI file.

This function is provided for compatibility with 16-bit Windows-based applications. Win32-based applications should store initialization information in the registry.

BOOL WriteProfileString(

LPCTSTR  lpszSection,	// address of section name
LPCTSTR  lpszKey,	// address of key name
LPCTSTR  lpszString	// address of string to write
);
Parameters

lpszSection

Points to a null-terminated string that specifies the section to which the string is to be copied. If the section does not exist, it is created. The name of the section is not case-sensitive; the string can be any combination of uppercase and lowercase letters.

lpszKey

Points to a null-terminated string containing the key to be associated with the string. If the key does not exist in the specified section, it is created. If this parameter is NULL, the entire section, including all entries in the section, is deleted.

lpszString

Points to a null-terminated string to be written to the file. If this parameter is NULL, the key pointed to by the lpszKey parameter is deleted.

Windows 95: This platform does not support the use of the TAB (\t) character as part of this parameter.

Return Value

If the function successfully copies the string to the WIN.INI file, the return value is TRUE.

If the function fails, or if it flushes the cached version of WIN.INI, the return value is FALSE. To get extended error information, call GetLastError.

Remarks

Windows 95:

Windows 95 keeps a cached version of WIN.INI to improve performance. If all three parameters are NULL, the function flushes the cache. The function always returns FALSE after flushing the cache, regardless of whether the flush succeeds or fails.

A section in the WIN.INI file must have the following form:

[section]
key=string
    .
    .
    .

Windows NT

Windows NT maps most .INI file references to the registry, using the mapping defined under the following registry key:

HKEY_LOCAL_MACHINE\Software\Microsoft\
        Windows NT\CurrentVersion\IniFileMapping

When the operation has been mapped, the WriteProfileString function writes information to the registry, not to the initialization file; the change in the storage location has no effect on the function's behavior.

See Also

GetProfileString, WritePrivateProfileString


WriteTapemark
WriteTapemark  QuickInfo  Overview  Group

The WriteTapemark function writes a specified number of filemarks, setmarks, short filemarks, or long filemarks to a tape device. These tapemarks divide a tape partition into smaller areas.

DWORD WriteTapemark(

HANDLE  hDevice,	// handle of open device
DWORD  dwTapemarkType,	// type of tapemarks to write
DWORD  dwTapemarkCount,	// number of tapemarks to write
BOOL  bImmediate	// return after write begins
);
Parameters

hDevice

Identifies the device on which to write tapemarks. This handle is created by using the CreateFile function.

dwTapemarkType

Specifies the type of tapemarks to write. This parameter can be one of the following values:

Value	Description
TAPE_FILEMARKS	Writes the number of filemarks specified by the dwTapemarkCount parameter.
TAPE_LONG_FILEMARKS	Writes the number of long filemarks specified by dwTapemarkCount.
TAPE_SETMARKS	Writes the number of setmarks specified by dwTapemarkCount.
TAPE_SHORT_FILEMARKS	Writes the number of short filemarks specified by dwTapemarkCount.
dwTapemarkCount

Specifies the number of tapemarks to write.

bImmediate

Specifies whether to return as soon as the operation begins. If this parameter is TRUE, the function returns immediately; if it is FALSE, the function does not return until the operation has been completed.

Return Value

If the function succeeds, the return value is NO_ERROR.

If the function fails, the return value is one of the following error codes:

Error	Description
ERROR_BEGINNING_OF_MEDIA	An attempt to access data before the beginning-of-medium marker failed.
ERROR_BUS_RESET	A reset condition was detected on the bus.
ERROR_END_OF_MEDIA	The end-of-tape marker was reached during an operation.
ERROR_FILEMARK_DETECTED	A filemark was reached during an operation.
ERROR_SETMARK_DETECTED	A setmark was reached during an operation.
ERROR_NO_DATA_DETECTED	The end-of-data marker was reached during an operation.
ERROR_PARTITION_FAILURE	The tape could not be partitioned.
ERROR_INVALID_BLOCK_LENGTH	The block size is incorrect on a new tape in a multivolume partition.
ERROR_DEVICE_NOT_PARTITIONED	The partition information could not be found when a tape was being loaded.
ERROR_MEDIA_CHANGED	The tape that was in the drive has been replaced or removed.
ERROR_NO_MEDIA_IN_DRIVE	There is no media in the drive.
ERROR_NOT_SUPPORTED	The tape driver does not support a requested function.
ERROR_UNABLE_TO_LOCK_MEDIA	An attempt to lock the ejection mechanism failed.
ERROR_UNABLE_TO_UNLOAD_MEDIA	An attempt to unload the tape failed.
ERROR_WRITE_PROTECT	The media is write protected.
Remarks

Filemarks, setmarks, short filemarks, and long filemarks are special recorded elements that denote the linear organization of the tape. None of these marks contain user data. Filemarks are the most general marks; setmarks provide a hierarchy not available with filemarks.

A short filemark contains a short erase gap that cannot be overwritten unless the write operation is performed from the beginning of the partition or from an earlier long filemark.

A long filemark contains a long erase gap that allows an application to position the tape at the beginning of the filemark and to overwrite the filemark and the erase gap.

See Also

CreateFile


WSAAsyncGetHostByAddr
WSAAsyncGetHostByAddr  QuickInfo

The Windows Sockets WSAAsyncGetHostByAddr function gets host information corresponding to an address in an asynchronous fashion.

HANDLE WSAAsyncGetHostByAddr (

HWND hWnd,
unsigned int wMsg,
const char FAR * addr,
int len,
int type,
char FAR * buf,
int buflen
);
Parameters

hWnd

The handle of the window that should receive a message when the asynchronous request completes.

wMsg

The message to be received when the asynchronous request completes.

addr

A pointer to the network address for the host. Host addresses are stored in network byte order.

len

The length of the address, which must be 4 for PF_INET.

type

The type of the address, which must be PF_INET.

buf

A pointer to the data area to receive the hostent data. Note that this must be larger than the size of a hostent structure. This is because the data area supplied is used by the Windows Sockets implementation to contain not only a hostent structure but any and all of the data which is referenced by members of the hostent structure. It is recommended that you supply a buffer of MAXGETHOSTSTRUCT bytes.

buflen

The size of data area buf above.

Return Value

The return value specifies whether or not the asynchronous operation was successfully initiated. Note that it does not imply success or failure of the operation itself.

If the operation was successfully initiated, WSAAsyncGetHostByAddr returns a nonzero value of type HANDLE which is the asynchronous task handle for the request. This value can be used in two ways. It can be used to cancel the operation using WSACancelAsyncRequest. It can also be used to match up asynchronous operations and completion messages, by examining the wParam message argument.

If the asynchronous operation could not be initiated, WSAAsyncGetHostByAddr returns a zero value, and a specific error number may be retrieved by calling WSAGetLastError.

Error Codes

The following error codes may be set when an application window receives a message. As previously described, they may be extracted from the lParam in the reply message using the WSAGETASYNCERROR macro.

WSAENETDOWN	The Windows Sockets implementation has detected that the network subsystem has failed.
WSAENOBUFS	Buffer space is insufficient or unavailable.
WSAHOST_NOT_FOUND	Authoritative Answer Host not found.
WSATRY_AGAIN	Non-Authoritative Host not found, or SERVERFAIL.
WSANO_RECOVERY	Nonrecoverable errors: FORMERR, REFUSED, NOTIMP.
WSANO_DATA	Valid name, no data record of requested type.
The following errors may occur at the time of the function call, and indicate that the asynchronous operation could not be initiated.

WSANOTINITIALISED	A successful WSAStartup must occur before using this function.
WSAENETDOWN	The Windows Sockets implementation has detected that the network subsystem has failed.
WSAEINPROGRESS	A blocking Windows Sockets operation is in progress.
WSAEWOULDBLOCK	The asynchronous operation cannot be scheduled at this time due to resource or other constraints within the Windows Sockets implementation.
Remarks

This function is an asynchronous version of gethostbyaddr, and is used to retrieve host name and address information corresponding to a network address. The Windows Sockets implementation initiates the operation and returns to the caller immediately, passing back an asynchronous task handle that the application may use to identify the operation. When the operation is completed, the results (if any) are copied into the buffer provided by the caller and a message is sent to the application's window.

When the asynchronous operation is complete, the application's window hWnd receives message wMsg. The wParam argument contains the asynchronous task handle as returned by the original function call. The high 16 bits of lParam contain any error code. The error code can be any error as defined in WINSOCK.H. An error code of zero indicates successful completion of the asynchronous operation. On successful completion, the buffer supplied to the original function call contains a hostent structure. To access the elements of this structure, the original buffer address should be cast to a hostent structure pointer and accessed as appropriate.

Note that if the error code is WSAENOBUFS, it indicates that the size of the buffer specified by buflen in the original call was too small to contain all the resultant information. In this case, the low 16 bits of lParam contain the size of buffer required to supply ALL the requisite information. If the application decides that the partial data is inadequate, it may reissue the WSAAsyncGetHostByAddr function call with a buffer large enough to receive all the desired information (no smaller than the low 16 bits of lParam).

The error code and buffer length should be extracted from the lParam using the macros WSAGETASYNCERROR and WSAGETASYNCBUFLEN, defined in WINSOCK.H as:

#define WSAGETASYNCERROR(lParam)  HIWORD(lParam)

#define WSAGETASYNCBUFLEN(lParam)  LOWORD(lParam)

The use of these macros will maximize the portability of the source code for the application.

The buffer supplied to this function is used by the Windows Sockets implementation to construct a hostent structure together with the contents of data areas referenced by members of the same hostent structure. To avoid the WSAENOBUFS error previously noted, the application should provide a buffer of at least MAXGETHOSTSTRUCT bytes (as defined in WINSOCK.H).

Notes for Windows Sockets Suppliers

It is the responsibility of the Windows Sockets implementation to ensure that messages are successfully posted to the application. If a PostMessage operation fails, the Windows Sockets implementation must repost that message as long as the window exists.

Windows Sockets suppliers should use the WSAMAKEASYNCREPLY macro when constructing the lParam in the message.

See Also

gethostbyaddr, PostMessage, WSACancelAsyncRequest, WSAStartup


WSAAsyncGetHostByName
WSAAsyncGetHostByName  QuickInfo

The Windows Sockets WSAAsyncGetHostByName function gets host information corresponding to a host name in an asynchronous fashion.

HANDLE WSAAsyncGetHostByName (

HWND hWnd,
unsigned int wMsg,
const char FAR * name,
char FAR * buf,
int buflen
);
Parameters

hWnd

The handle of the window that should receive a message when the asynchronous request completes.

wMsg

The message to be received when the asynchronous request completes.

name

A pointer to the name of the host.

buf

A pointer to the data area to receive the hostent data. Note that this must be larger than the size of a hostent structure. This is because the data area supplied is used by the Windows Sockets implementation to contain not only a hostent structure but any and all of the data referenced by members of the hostent structure. It is recommended that you supply a buffer of MAXGETHOSTSTRUCT bytes.

buflen

The size of data area buf above.

Return Value

The return value specifies whether the asynchronous operation was successfully initiated. Note that it does not imply success or failure of the operation itself.

If the operation was successfully initiated, WSAAsyncGetHostByName returns a nonzero value of type HANDLE, which is the asynchronous task handle for the request. This value can be used in two ways. It can be used to cancel the operation using WSACancelAsyncRequest. It can also be used to match up asynchronous operations and completion messages, by examining the wParam message argument.

If the asynchronous operation could not be initiated, WSAAsyncGetHostByName returns a zero value, and a specific error number may be retrieved by calling WSAGetLastError.

Error Codes

The following error codes may be set when an application window receives a message. As previously described, they may be extracted from the lParam in the reply message using the WSAGETASYNCERROR macro.

WSAENETDOWN	The Windows Sockets implementation has detected that the network subsystem has failed.
WSAENOBUFS	Buffer space is insufficien or unavailable.
WSAHOST_NOT_FOUND	Authoritative Answer Host not found.
WSATRY_AGAIN	Non-Authoritative Host not found, or SERVERFAIL.
WSANO_RECOVERY	Nonrecoverable errors: FORMERR, REFUSED, NOTIMP.
WSANO_DATA	Valid name, no data record of requested type.
The following errors may occur at the time of the function call, and indicate that the asynchronous operation could not be initiated.

WSANOTINITIALISED	A successful WSAStartup must occur before using this function.
WSAENETDOWN	The Windows Sockets implementation has detected that the network subsystem has failed.
WSAEINPROGRESS	A blocking Windows Sockets operation is in progress.
WSAEWOULDBLOCK	The asynchronous operation cannot be scheduled at this time due to resource or other constraints within the Windows Sockets implementation.
Remarks

This function is an asynchronous version of gethostbyname, and is used to retrieve host name and address information corresponding to a host name. The Windows Sockets implementation initiates the operation and returns to the caller immediately, passing back an asynchronous task handle that the application may use to identify the operation. When the operation is completed, the results (if any) are copied into the buffer provided by the caller and a message is sent to the application's window.

When the asynchronous operation is complete, the application's window hWnd receives message wMsg. The wParam argument contains the asynchronous task handle as returned by the original function call. The high 16 bits of lParam contain any error code. The error code may be any error as defined in WINSOCK.H. An error code of zero indicates successful completion of the asynchronous operation. On successful completion, the buffer supplied to the original function call contains a hostent structure. To access the elements of this structure, the original buffer address should be cast to a hostent structure pointer and accessed as appropriate.

Note that if the error code is WSAENOBUFS, it indicates that the size of the buffer specified by buflen in the original call was too small to contain all the resultant information. In this case, the low 16 bits of lParam contain the size of buffer required to supply ALL the requisite information. If the application needs more data, it may reissue the WSAAsyncGetHostByName function call with a buffer large enough to receive all the desired information (no smaller than the low 16 bits of lParam).

The error code and buffer length should be extracted from the lParam using the macros WSAGETASYNCERROR and WSAGETASYNCBUFLEN, defined in WINSOCK.H as:

#define WSAGETASYNCERROR(lParam)   HIWORD(lParam)

#define WSAGETASYNCBUFLEN(lParam)  LOWORD(lParam)

The use of these macros will maximize the portability of the source code for the application.

The buffer supplied to this function is used by the Windows Sockets implementation to construct a hostent structure together with the contents of data areas referenced by members of the same hostent structure. To avoid the WSAENOBUFS error previously noted, the application should provide a buffer of at least MAXGETHOSTSTRUCT bytes (as defined in WINSOCK.H).

Notes for Windows Sockets Suppliers

It is the responsibility of the Windows Sockets implementation to ensure that messages are successfully posted to the application. If a PostMessage operation fails, the Windows Sockets implementation must repost that message as long as the window exists.

Windows Sockets suppliers should use the WSAMAKEASYNCREPLY macro when constructing the lParam in the message.

See Also

gethostbyname, PostMessage, WSACancelAsyncRequest, WSAStartup


WSAAsyncGetProtoByName
WSAAsyncGetProtoByName  QuickInfo

The Windows Sockets WSAAsyncGetProtoByName function gets protocol information corresponding to a protocol name in an asynchronous fashion.

HANDLE WSAAsyncGetProtoByName (

HWND hWnd,
unsigned int wMsg,
const char FAR * name,
char FAR * buf,
int buflen
);
Parameters

hWnd

The handle of the window which should receive a message when the asynchronous request completes.

wMsg

The message to be received when the asynchronous request completes.

name

A pointer to the protocol name to be resolved.

buf

A pointer to the data area to receive the protoent data. Note that this must be larger than the size of a protoent structure. This is because the data area supplied is used by the Windows Sockets implementation to contain not only a protoent structure but any and all of the data referenced by members of the protoent structure. It is recommended that you supply a buffer of MAXGETHOSTSTRUCT bytes.

buflen

The size of data area buf above.

Return Value

The return value specifies whether or not the asynchronous operation was successfully initiated. Note that it does not imply success or failure of the operation itself.

If the operation was successfully initiated, WSAAsyncGetProtoByName returns a nonzero value of type HANDLE, which is the asynchronous task handle for the request. This value can be used in two ways. It can be used to cancel the operation using WSACancelAsyncRequest. It can also be used to match up asynchronous operations and completion messages, by examining the wParam message argument.

If the asynchronous operation could not be initiated, WSAAsyncGetProtoByName returns a zero value, and a specific error number may be retrieved by calling WSAGetLastError.

Error Codes

The following error codes may be set when an application window receives a message. As previously described, they may be extracted from the lParam in the reply message using the WSAGETASYNCERROR macro.

WSAENETDOWN	The Windows Sockets implementation has detected that the network subsystem has failed.
WSAENOBUFS	Buffer space is insufficient or unavailable.
WSAHOST_NOT_FOUND	Authoritative Answer Host not found.
WSATRY_AGAIN	Non-Authoritative Host not found, or SERVERFAIL.
WSANO_RECOVERY	Nonrecoverable errors: FORMERR, REFUSED, NOTIMP.
WSANO_DATA	Valid name, no data record of requested type.
The following errors may occur at the time of the function call, and indicate that the asynchronous operation could not be initiated.

WSANOTINITIALISED	A successful WSAStartup must occur before using this function.
WSAENETDOWN	The Windows Sockets implementation has detected that the network subsystem has failed.
WSAEINPROGRESS	A blocking Windows Sockets operation is in progress.
WSAEWOULDBLOCK	The asynchronous operation cannot be scheduled at this time due to resource or other constraints within the Windows Sockets implementation.
Remarks

This function is an asynchronous version of getprotobyname, and is used to retrieve the protocol name and number corresponding to a protocol name. The Windows Sockets implementation initiates the operation and returns to the caller immediately, passing back an asynchronous task handle that the application may use to identify the operation. When the operation is completed, the results (if any) are copied into the buffer provided by the caller and a message is sent to the application's window.

When the asynchronous operation is complete, the application's window hWnd receives message wMsg. The wParam argument contains the asynchronous task handle as returned by the original function call. The high 16 bits of lParam contain any error code. The error code may be any error as defined in WINSOCK.H. An error code of zero indicates successful completion of the asynchronous operation. On successful completion, the buffer supplied to the original function call contains a protoent structure. To access the elements of this structure, the original buffer address should be cast to a protoent structure pointer and accessed as appropriate.

Note that if the error code is WSAENOBUFS, it indicates that the size of the buffer specified by buflen in the original call was too small to contain all the resultant information. In this case, the low 16 bits of lParam contain the size of buffer required to supply ALL the requisite information. If the application decides that the partial data is inadequate, it may reissue the WSAAsyncGetProtoByName function call with a buffer large enough to receive all the desired information (no smaller than the low 16 bits of lParam).

The error code and buffer length should be extracted from the lParam using the macros WSAGETASYNCERROR and WSAGETASYNCBUFLEN, defined in WINSOCK.H as:

#define WSAGETASYNCERROR(lParam)   HIWORD(lParam)

#define WSAGETASYNCBUFLEN(lParam)  LOWORD(lParam)

The use of these macros will maximize the portability of the source code for the application.

The buffer supplied to this function is used by the Windows Sockets implementation to construct a protoent structure together with the contents of data areas referenced by members of the same protoent structure. To avoid the WSAENOBUFS error previously noted, the application should provide a buffer of at least MAXGETHOSTSTRUCT bytes (as defined in WINSOCK.H).

Notes for Windows Sockets Suppliers

It is the responsibility of the Windows Sockets implementation to ensure that messages are successfully posted to the application. If a PostMessage operation fails, the Windows Sockets implementation must repost that message as long as the window exists.

Windows Sockets suppliers should use the WSAMAKEASYNCREPLY macro when constructing the lParam in the message.

See Also

getprotobyname, PostMessage, WSACancelAsyncRequest, WSAStartup


WSAAsyncGetProtoByNumber
WSAAsyncGetProtoByNumber  QuickInfo

The Windows Sockets WSAAsyncGetProtoByNumber function gets protocol information corresponding to a protocol number in an asynchronous fashion.

HANDLE WSAAsyncGetProtoByNumber (

HWND hWnd,
unsigned int wMsg,
int number,
char FAR * buf,
int buflen
);
Parameters

hWnd

The handle of the window which should receive a message when the asynchronous request completes.

wMsg

The message to be received when the asynchronous request completes.

number

The protocol number to be resolved, in host byte order.

buf

A pointer to the data area to receive the protoent data. Note that this must be larger than the size of a protoent structure. This is because the data area supplied is used by the Windows Sockets implementation to contain not only a protoent structure but any and all of the data which is referenced by members of the protoent structure. It is recommended that you supply a buffer of MAXGETHOSTSTRUCT bytes.

buflen

The size of data area buf above.

Return Value

The return value specifies whether or not the asynchronous operation was successfully initiated. Note that it does not imply success or failure of the operation itself.

If the operation was successfully initiated, WSAAsyncGetProtoByNumber returns a nonzero value of type HANDLE, which is the asynchronous task handle for the request. This value can be used in two ways. It can be used to cancel the operation using WSACancelAsyncRequest. It can also be used to match up asynchronous operations and completion messages, by examining the wParam message argument.

If the asynchronous operation could not be initiated, WSAAsyncGetProtoByNumber returns a zero value, and a specific error number may be retrieved by calling WSAGetLastError.

Error Codes

The following error codes may be set when an application window receives a message. As previously described, they may be extracted from the lParam in the reply message using the WSAGETASYNCERROR macro.

WSAENETDOWN	The Windows Sockets implementation has detected that the network subsystem has failed.
WSAENOBUFS	Buffer space is insufficient or unavailable.
WSAHOST_NOT_FOUND	Authoritative Answer Host not found.
WSATRY_AGAIN	Non-Authoritative Host not found, or SERVERFAIL.
WSANO_RECOVERY	Nonrecoverable errors: FORMERR, REFUSED, NOTIMP.
WSANO_DATA	Valid name, no data record of requested type.
The following errors may occur at the time of the function call, and indicate that the asynchronous operation could not be initiated.

WSANOTINITIALISED	A successful WSAStartup must occur before using this function.
WSAENETDOWN	The Windows Sockets implementation has detected that the network subsystem has failed.
WSAEINPROGRESS	A blocking Windows Sockets operation is in progress.
WSAEWOULDBLOCK	The asynchronous operation cannot be scheduled at this time due to resource or other constraints within the Windows Sockets implementation.
Remarks

This function is an asynchronous version of getprotobynumber, and is used to retrieve the protocol name and number corresponding to a protocol number. The Windows Sockets implementation initiates the operation and returns to the caller immediately, passing back an asynchronous task handle, which the application may use to identify the operation. When the operation is completed, the results (if any) are copied into the buffer provided by the caller and a message is sent to the application's window.

When the asynchronous operation is complete, the application's window hWnd receives message wMsg. The wParam argument contains the asynchronous task handle as returned by the original function call. The high 16 bits of lParam contain any error code. The error code may be any error as defined in WINSOCK.H. An error code of zero indicates successful completion of the asynchronous operation. On successful completion, the buffer supplied to the original function call contains a protoent structure. To access the elements of this structure, the original buffer address should be cast to a protoent structure pointer and accessed as appropriate.

Note that if the error code is WSAENOBUFS, it indicates that the size of the buffer specified by buflen in the original call was too small to contain all the resultant information. In this case, the low 16 bits of lParam contain the size of buffer required to supply ALL the requisite information. If the application decides that the partial data is inadequate, it may reissue the WSAAsyncGetProtoByNumber function call with a buffer large enough to receive all the desired information (no smaller than the low 16 bits of lParam).

The error code and buffer length should be extracted from the lParam using the macros WSAGETASYNCERROR and WSAGETASYNCBUFLEN, defined in WINSOCK.H as:

#define WSAGETASYNCERROR(lParam)   HIWORD(lParam)

#define WSAGETASYNCBUFLEN(lParam)  LOWORD(lParam)

The use of these macros will maximize the portability of the source code for the application.

The buffer supplied to this function is used by the Windows Sockets implementation to construct a protoent structure together with the contents of data areas referenced by members of the same protoent structure. To avoid the WSAENOBUFS error previously noted, the application should provide a buffer of at least MAXGETHOSTSTRUCT bytes (as defined in WINSOCK.H).

Notes for Windows Sockets Suppliers

It is the responsibility of the Windows Sockets implementation to ensure that messages are successfully posted to the application. If a PostMessage operation fails, the Windows Sockets implementation must repost that message as long as the window exists.

Windows Sockets suppliers should use the WSAMAKEASYNCREPLY macro when constructing the lParam in the message.

See Also

getprotobynumber, PostMessage, WSACancelAsyncRequest, WSAStartup


WSAAsyncGetServByName
WSAAsyncGetServByName  QuickInfo

The Windows Sockets WSAAsyncGetServByName function gets service information corresponding to a service name and port in an asynchronous fashion.

HANDLE WSAAsyncGetServByName (

HWND hWnd,
unsigned int wMsg,
const char FAR * name,
const char FAR * proto,
char FAR * buf,
int buflen
);
Parameters

hWnd

The handle of the window that should receive a message when the asynchronous request completes.

wMsg

The message to be received when the asynchronous request completes.

name

A pointer to a service name.

proto

A pointer to a protocol name. This may be NULL, in which case WSAAsyncGetServByName will search for the first service entry for which s_name or one of the s_aliases matches the given name. Otherwise, WSAAsyncGetServByName matches both name and proto.

buf

A pointer to the data area to receive the servent data. Note that this must be larger than the size of a servent structure. This is because the data area supplied is used by the Windows Sockets implementation to contain not only a servent structure but any and all of the data which is referenced by members of the servent structure. It is recommended that you supply a buffer of MAXGETHOSTSTRUCT bytes.

buflen

The size of data area buf  above.

Return Value

The return value specifies whether or not the asynchronous operation was successfully initiated. Note that it does not imply success or failure of the operation itself.

If the operation was successfully initiated, WSAAsyncGetServByName returns a nonzero value of type HANDLE, which is the asynchronous task handle for the request. This value can be used in two ways. It can be used to cancel the operation using WSACancelAsyncRequest. It can also be used to match up asynchronous operations and completion messages, by examining the wParam message argument.

If the asynchronous operation could not be initiated, WSAAsyncServByName returns a zero value, and a specific error number may be retrieved by calling WSAGetLastError.

Error Codes

The following error codes may be set when an application window receives a message. As previously described, they may be extracted from the lParam in the reply message using the WSAGETASYNCERROR macro.

WSAENETDOWN	The Windows Sockets implementation has detected that the network subsystem has failed.
WSAENOBUFS	Buffer space is insufficient or unavailable.
WSAHOST_NOT_FOUND	Authoritative Answer Host not found.
WSATRY_AGAIN	Non-Authoritative Host not found, or SERVERFAIL.
WSANO_RECOVERY	Nonrecoverable errors: FORMERR, REFUSED, NOTIMP.
WSANO_DATA	Valid name, no data record of requested type.
The following errors may occur at the time of the function call, and indicate that the asynchronous operation could not be initiated.

WSANOTINITIALISED	A successful WSAStartup must occur before using this function.
WSAENETDOWN	The Windows Sockets implementation has detected that the network subsystem has failed.
WSAEINPROGRESS	A blocking Windows Sockets operation is in progress.
WSAEWOULDBLOCK	The asynchronous operation cannot be scheduled at this time due to resource or other constraints within the Windows Sockets implementation.
Remarks

This function is an asynchronous version of getservbyname, and is used to retrieve service information corresponding to a service name. The Windows Sockets implementation initiates the operation and returns to the caller immediately, passing back an asynchronous task handle that the application may use to identify the operation. When the operation is completed, the results (if any) are copied into the buffer provided by the caller and a message is sent to the application's window.

When the asynchronous operation is complete, the application's window hWnd receives message wMsg. The wParam argument contains the asynchronous task handle as returned by the original function call. The high 16 bits of lParam contain any error code. The error code may be any error as defined in WINSOCK.H. An error code of zero indicates successful completion of the asynchronous operation. On successful completion, the buffer supplied to the original function call contains a hostent structure. To access the elements of this structure, the original buffer address should be cast to a hostent structure pointer and accessed as appropriate.

Note that if the error code is WSAENOBUFS, it indicates that the size of the buffer specified by buflen in the original call was too small to contain all the resultant information. In this case, the low 16 bits of lParam contain the size of buffer required to supply ALL the requisite information. If the application decides that the partial data is inadequate, it may reissue the WSAAsyncGetServByName function call with a buffer large enough to receive all the desired information (no smaller than the low 16 bits of lParam).

The error code and buffer length should be extracted from the lParam using the macros WSAGETASYNCERROR and WSAGETASYNCBUFLEN, defined in WINSOCK.H as:

#define WSAGETASYNCERROR(lParam)   HIWORD(lParam)

#define WSAGETASYNCBUFLEN(lParam)  LOWORD(lParam)

The use of these macros will maximize the portability of the source code for the application.

The buffer supplied to this function is used by the Windows Sockets implementation to construct a hostent structure together with the contents of data areas referenced by members of the same hostent structure. To avoid the WSAENOBUFS error noted above, the application should provide a buffer of at least MAXGETHOSTSTRUCT bytes (as defined in WINSOCK.H).

Notes for Windows Sockets Suppliers

It is the responsibility of the Windows Sockets implementation to ensure that messages are successfully posted to the application. If a PostMessage operation fails, the Windows Sockets implementation must repost that message as long as the window exists.

Windows Sockets suppliers should use the WSAMAKEASYNCREPLY macro when constructing the lParam in the message.

See Also

getservbyname, PostMessage, WSACancelAsyncRequest, WSAStartup


WSAAsyncGetServByPort
WSAAsyncGetServByPort  QuickInfo

The Windows Sockets WSAAsyncGetServByPort function gets service information corresponding to a port and protocol in an asynchronous fashion.

HANDLE WSAAsyncGetServByPort (

HWND hWnd,
unsigned int wMsg,
int port,
const char FAR * proto,
char FAR * buf,
int buflen
);
Parameters

hWnd

The handle of the window that should receive a message when the asynchronous request completes.

wMsg

The message to be received when the asynchronous request completes.

port

The port for the service, in network byte order.

proto

A pointer to a protocol name. This may be NULL, in which case WSAAsyncGetServByPort will search for the first service entry that matches the specified port. Otherwise, WSAAsyncGetServByPort matches both port and proto.

buf

A pointer to the data area to receive the servent data. Note that this must be larger than the size of a servent structure. This is because the data area supplied is used by the Windows Sockets implementation to contain not only a servent structure but any and all of the data referenced by members of the servent structure. It is recommended that you supply a buffer of MAXGETHOSTSTRUCT bytes.

buflen

The size of data area buf  above.

Return Value

The return value specifies whether the asynchronous operation was successfully initiated. Note that it does not imply success or failure of the operation itself.

If the operation was successfully initiated, WSAAsyncGetServByPort returns a nonzero value of type HANDLE, which is the asynchronous task handle for the request. This value can be used in two ways. It can be used to cancel the operation using WSACancelAsyncRequest. It can also be used to match up asynchronous operations and completion messages, by examining the wParam message argument.

If the asynchronous operation could not be initiated, WSAAsyncGetServByPort returns a zero value, and a specific error number may be retrieved by calling WSAGetLastError.

Error Codes

The following error codes may be set when an application window receives a message. As previously described, they may be extracted from the lParam in the reply message using the WSAGETASYNCERROR macro.

WSAENETDOWN	The Windows Sockets implementation has detected that the network subsystem has failed.
WSAENOBUFS	Buffer space is insufficient or unavailable.
WSAHOST_NOT_FOUND	Authoritative Answer Host not found.
WSATRY_AGAIN	Non-Authoritative Host not found, or SERVERFAIL.
WSANO_RECOVERY	Nonrecoverable errors: FORMERR, REFUSED, NOTIMP.
WSANO_DATA	Valid name, no data record of requested type.
The following errors may occur at the time of the function call, and indicate that the asynchronous operation could not be initiated.

WSANOTINITIALISED	A successful WSAStartup must occur before using this function.
WSAENETDOWN	The Windows Sockets implementation has detected that the network subsystem has failed.
WSAEINPROGRESS	A blocking Windows Sockets operation is in progress.
WSAEWOULDBLOCK	The asynchronous operation cannot be scheduled at this time due to resource or other constraints within the Windows Sockets implementation.
Remarks

This function is an asynchronous version of getservbyport, and is used to retrieve service information corresponding to a port number. The Windows Sockets implementation initiates the operation and returns to the caller immediately, passing back an asynchronous task handle that the application may use to identify the operation. When the operation is completed, the results (if any) are copied into the buffer provided by the caller and a message is sent to the application's window.

When the asynchronous operation is complete the application's window hWnd receives message wMsg. The wParam argument contains the asynchronous task handle as returned by the original function call. The high 16 bits of lParam contain any error code. The error code may be any error as defined in WINSOCK.H. An error code of zero indicates successful completion of the asynchronous operation. On successful completion, the buffer supplied to the original function call contains a servent structure. To access the elements of this structure, the original buffer address should be cast to a servent structure pointer and accessed as appropriate.

Note that if the error code is WSAENOBUFS, it indicates that the size of the buffer specified by buflen in the original call was too small to contain all the resultant information. In this case, the low 16 bits of lParam contain the size of buffer required to supply ALL the requisite information. If the application needs more information, it may reissue the WSAAsyncGetServByPort function call with a buffer large enough to receive all the desired information (no smaller than the low 16 bits of lParam).

The error code and buffer length should be extracted from the lParam using the macros WSAGETASYNCERROR and WSAGETASYNCBUFLEN, defined in WINSOCK.H as:

#define WSAGETASYNCERROR(lParam)   HIWORD(lParam)

#define WSAGETASYNCBUFLEN(lParam)  LOWORD(lParam)

The use of these macros will maximize the portability of the source code for the application.

The buffer supplied to this function is used by the Windows Sockets implementation to construct a servent structure together with the contents of data areas referenced by members of the same servent structure. To avoid the WSAENOBUFS error previously noted, the application should provide a buffer of at least MAXGETHOSTSTRUCT bytes (as defined in WINSOCK.H).

Notes for Windows Sockets Suppliers

It is the responsibility of the Windows Sockets implementation to ensure that messages are successfully posted to the application. If a PostMessage operation fails, the Windows Sockets implementation must repost that message as long as the window exists.

Windows Sockets suppliers should use the WSAMAKEASYNCREPLY macro when constructing the lParam in the message.

See Also

getservbyport, PostMessage, WSACancelAsyncRequest, WSAStartup


WSAAsyncSelect
WSAAsyncSelect  QuickInfo

The Windows Sockets WSAAsyncSelect function requests event notification for a socket.

int WSAAsyncSelect (

SOCKET s,
HWND hWnd,
unsigned int wMsg,
long lEvent
);
Parameters

s

A descriptor identifying the socket for which event notification is required.

hWnd

A handle identifying the window that should receive a message when a network event occurs.

wMsg

The message to be received when a network event occurs.

lEvent

A bitmask which specifies a combination of network events in which the application is interested.

Return Value

The return value is zero if the application's declaration of interest in the network event set was successful. Otherwise, the value SOCKET_ERROR is returned, and a specific error number may be retrieved by calling WSAGetLastError.

Error Codes

WSANOTINITIALISED	A successful WSAStartup must occur before using this function.
WSAENETDOWN	The Windows Sockets implementation has detected that the network subsystem has failed.
WSAEINVAL	Indicates that one of the specified parameters was invalid.
WSAEINPROGRESS	A blocking Windows Sockets operation is in progress.
	Additional error codes may be set when an application window receives a message. This error code is extracted from the lParam in the reply message using the WSAGETSELECTERROR macro. Possible error codes for each network event are listed following:
Event: FD_CONNECT

Error Code	Meaning
WSAEADDRINUSE	The specified address is already in use.
WSAEADDRNOTAVAIL	The specified address is not available from the local computer.
WSAEAFNOSUPPORT	Addresses in the specified family cannot be used with this socket.
WSAECONNREFUSED	The attempt to connect was forcefully rejected.
WSAEDESTADDRREQ	A destination address is required.
WSAEFAULT	The namelen argument is incorrect.
WSAEINVAL	The socket is already bound to an address.
WSAEISCONN	The socket is already connected.
WSAEMFILE	No more file descriptors are available.
WSAENETUNREACH	The network can't be reached from this host at this time.
WSAENOBUFS	No buffer space is available. The socket cannot be connected.
WSAENOTCONN	The socket is not connected.
WSAENOTSOCK	The descriptor is a file, not a socket.
WSAETIMEDOUT	Attempt to connect timed out without establishing a connection
Event: FD_CLOSE

Error Code	Meaning
WSAENETDOWN	The Windows Sockets implementation has detected that the network subsystem has failed.
WSAECONNRESET	The connection was reset by the remote side.
WSAECONNABORTED	The connection was aborted due to timeout or other failure.
Event: FD_READ, Event: FD_WRITE, Event: FD_OOB, Event: FD_ACCEPT

Error Code	Meaning
WSAENETDOWN	The Windows Sockets implementation has detected that the network subsystem has failed.
Notes for Windows Sockets Suppliers

It is the responsibility of the Windows Sockets Supplier to ensure that messages are successfully posted to the application. If a PostMessage operation fails, the Windows Sockets implementation must repost that message as long as the window exists.

Windows Sockets suppliers should use the WSAMAKESELECTREPLY macro when constructing the lParam in the message.

When a socket is closed, the Windows Sockets supplier should purge any messages remaining for posting to the application window. However, the application must be prepared to receive, and discard, any messages that may have been posted prior to the closesocket.

Remarks

This function is used to request that the Windows Sockets DLL should send a message to the window hWnd whenever it detects any of the network events specified by the lEvent parameter. The message that should be sent is specified by the wMsg parameter. The socket for which notification is required is identified by s.

This function automatically sets socket s to nonblocking mode.

The lEvent parameter is constructed by using a bitwise OR operation with any of the values specified in the following list.

Value	Meaning
FD_READ	Want to receive notification of readiness for reading
FD_WRITE	Want to receive notification of readiness for writing
FD_OOB	Want to receive notification of the arrival of out-of-band data
FD_ACCEPT	Want to receive notification of incoming connections
FD_CONNECT	Want to receive notification of completed connection
FD_CLOSE	Want to receive notification of socket closure
Issuing a WSAAsyncSelect for a socket cancels any previous WSAAsyncSelect for the same socket. For example, to receive notification for both reading and writing, the application must call WSAAsyncSelect with both FD_READ and FD_WRITE, as follows:

rc = WSAAsyncSelect(s, hWnd, wMsg, FD_READ|FD_WRITE);

It is not possible to specify different messages for different events. The following code will not work; the second call will cancel the effects of the first, and only FD_WRITE events will be reported with message wMsg2:

rc = WSAAsyncSelect(s, hWnd, wMsg1, FD_READ);

rc = WSAAsyncSelect(s, hWnd, wMsg2, FD_WRITE);

To cancel all notification  — that is, to indicate that the Windows Sockets implementation should send no further messages related to network events on the socket − lEvent should be set to zero.

rc = WSAAsyncSelect(s, hWnd, 0, 0);

Although in this instance WSAAsyncSelect immediately disables event message posting for the socket, it is possible that messages may be waiting in the application's message queue. The application must therefore be prepared to receive network event messages even after cancellation. Closing a socket with closesocket also cancels WSAAsyncSelect message sending, but the same caveat about messages in the queue prior to the closesocket still applies.

Since an accepted socket has the same properties as the listening socket used to accept it, any WSAAsyncSelect events set for the listening socket apply to the accepted socket. For example, if a listening socket has WSAAsyncSelect events FD_ACCEPT, FD_READ, and FD_WRITE, then any socket accepted on that listening socket will also have FD_ACCEPT, FD_READ, and FD_WRITE events with the same wMsg value used for messages. If a different wMsg or events are desired, the application should call WSAAsyncSelect, passing the accepted socket and the desired new information. (Note that there is a timing window between the accept call and the call to WSAAsyncSelect to change the events or wMsg. An application that desires a different wMsg for the listening and accepted sockets should ask for only FD_ACCEPT events on the listening socket, then set appropriate events after the accept. Since FD_ACCEPT is never sent for a connected socket and FD_READ, FD_WRITE, FD_OOB, and FD_CLOSE are never sent for listening sockets, this will not impose difficulties.)

When one of the nominated network events occurs on the specified socket s, the application's window hWnd receives message wMsg. The wParam argument identifies the socket on which a network event has occurred. The low word of lParam specifies the network event that has occurred. The high word of lParam contains any error code. The error code be any error as defined in WINSOCK.H.

The error and event codes may be extracted from the lParam using the macros WSAGETSELECTERROR and WSAGETSELECTEVENT, defined in WINSOCK.H as:

#define WSAGETSELECTERROR(lParam)  HIWORD(lParam)

#define WSAGETSELECTEVENT(lParam)  LOWORD(lParam)

The use of these macros will maximize the portability of the source code for the application.

The possible network event codes that may be returned are as follows:

Value	Meaning
FD_READ	Socket s is ready for reading.
FD_WRITE	Socket s is ready for writing.
FD_OOB	Out-of-band data is ready for reading on socket s.
FD_ACCEPT	Socket s is ready for accepting a new incoming connection.
FD_CONNECT	Connection on socket s completed.
FD_CLOSE	Connection identified by socket s has been closed.
Although WSAAsyncSelect can be called with interest in multiple events, the application window will receive a single message for each network event.

As in the case of the select function, WSAAsyncSelect will frequently be used to determine when a data transfer operation (send or recv) can be issued with the expectation of immediate success. Nevertheless, a robust application must be prepared for the possibility that it may receive a message and issue a Windows Sockets function call which returns WSAEWOULDBLOCK immediately. For example, the following sequence of events is possible:

1.	Data arrives on socket s; Windows Sockets posts WSAAsyncSelect message.

2.	Application processes some other message.

3.	While processing, application issues an ioctlsocket(s, FIONREAD...) and notices that there is data ready to be read.

4.	Application issues a recv(s,...) to read the data.

5.	Application loops to process next message, eventually reaching the WSAAsyncSelect message, indicating that data is ready to read.

6.	Application issues recv(s,...), which fails with the error WSAEWOULDBLOCK.

Other sequences are possible.

The Windows Sockets DLL will not continually flood an application with messages for a particular network event. Having successfully posted notification of a particular event to an application window, no further message(s) for that network event will be posted to the application window until the application makes the function call which implicitly reenables notification of that network event.

Event	Reenabling function
FD_READ	recv or recvfrom
FD_WRITE	send or sendto
FD_OOB	recv
FD_ACCEPT	accept
FD_CONNECT	NONE
FD_CLOSE	NONE
Any call to the reenabling routine, even one that fails, results in reenabling of message posting for the relevant event.

For FD_READ, FD_OOB, and FD_ACCEPT events, message posting is "level-triggered." This means that if the reenabling routine is called and the relevant event is still valid after the call, a WSAAsyncSelect message is posted to the application. This allows an application to be event-driven and not concern itself with the amount of data that arrives at any one time. Consider the following sequence:

1.	Windows Sockets DLL receives 100 bytes of data on socket s and posts an FD_READ message.

2.	The application issues recv( s, buffptr, 50, 0) to read 50 bytes.

3.	The Windows Sockets DLL posts another FD_READ message, since there is still data to be read.

With these semantics, an application need not read all available data in response to an FD_READ message — a single recv in response to each FD_READ message is appropriate. If an application issues multiple recv calls in response to a single FD_READ, it may receive multiple FD_READ messages. Such an application may need to disable FD_READ messages before starting the recv calls by calling WSAAsyncSelect with the FD_READ event not set.

If an event is true when the application initially calls WSAAsyncSelect or when the reenabling function is called, then a message is posted as appropriate. For example, if an application calls listen, a connect attempt is made, then the application calls WSAAsyncSelect specifying FD_ACCEPT, the Windows Sockets implementation posts an FD_ACCEPT message immediately.

The FD_WRITE event is handled slightly differently. An FD_WRITE message is posted when a socket is first connected with connect or accepted with accept, and then after a send or sendto fails with WSAEWOULDBLOCK and buffer space becomes available. Therefore, an application can assume that sends are possible starting from the first FD_WRITE message and lasting until a send returns WSAEWOULDBLOCK. After such a failure, the application will be notified that sends are again possible with an FD_WRITE message.

The FD_OOB event is used only when a socket is configured to receive out-of-band data separately. If the socket is configured to receive out-of-band data in-line, the out-of-band (expedited) data is treated as normal data and the application should register an interest in, and will receive, FD_READ events, not FD_OOB events. An application can set or inspect the way in which out-of-band data is to be handled by using setsockopt or getsockopt for the SO_OOBINLINE option.

The error code in an FD_CLOSE message indicates whether the socket close was graceful or abortive. If the error code is zero, then the close was graceful; if the error code is WSAECONNRESET, then the socket's virtual socket was reset. This applies only to sockets of type SOCK_STREAM.

The FD_CLOSE message is posted when a close indication is received for the virtual circuit corresponding to the socket. In TCP terms, this means that the FD_CLOSE is posted when the connection goes into the FIN WAIT or CLOSE WAIT states. This results from the remote end performing a shutdown on the send side or a closesocket.

Please note your application will receive ONLY an FD_CLOSE message to indicate closure of a virtual circuit. It will NOT receive an FD_READ message to indicate this condition.

See Also

accept, closesocket, getsockopt, ioctlsocket, listen, PostMessage, recv, recvfrom, select, send, sendto, setsockopt, WSAStartup


WSACancelAsyncRequest
WSACancelAsyncRequest  QuickInfo

The Windows Sockets WSACancelAsyncRequest function cancels an incomplete asynchronous operation.

int WSACancelAsyncRequest(

HANDLE hAsyncTaskHandle
);
Parameters

hAsyncTaskHandle

Specifies the asynchronous operation to be canceled.

Return Value

The value returned by WSACancelAsyncRequest is zero if the operation was successfully canceled. Otherwise the value SOCKET_ERROR is returned, and a specific error number may be retrieved by calling WSAGetLastError.

Error Codes

WSANOTINITIALISED	A successful WSAStartup must occur before using this function.
WSAENETDOWN	The Windows Sockets implementation has detected that the network subsystem has failed.
WSAEINVAL	Indicates that the specified asynchronous task handle was invalid
WSAEINPROGRESS	A blocking Windows Sockets operation is in progress.
WSAEALREADY	The asynchronous routine being canceled has already completed.
Remarks

The WSACancelAsyncRequest function is used to cancel an asynchronous operation initiated by one of the WSAAsyncGetXByY family of functions such as WSAAsyncGetHostByName. The operation to be canceled is identified by the hAsyncTaskHandle parameter, which should be set to the asynchronous task handle as returned by the initiating function.

An attempt to cancel an existing asynchronous WSAAsyncGetXByY operation can fail with an error code of WSAEALREADY for two reasons. First, the original operation has already completed and the application has dealt with the resultant message. Second, the original operation has already completed but the resultant message is still waiting in the application window queue.

Notes for Windows Sockets Suppliers

It is unclear whether the application can usefully distinguish between WSAEINVAL and WSAEALREADY, since in both cases the error indicates that there is no asynchronous operation in progress with the indicated handle. [Trivial exception: zero is always an invalid asynchronous task handle.] The Windows Sockets specification does not prescribe how a conformant Windows Sockets implementation should distinguish between the two cases. For maximum portability, a Windows Sockets application should treat the two errors as equivalent.

See Also

WSAAsyncGetHostByAddr, WSAAsyncGetHostByName, WSAAsyncGetProtoByName, WSAAsyncGetProtoByNumber, WSAAsyncGetServByName, WSAAsyncGetServByPort, WSAStartup


WSACancelBlockingCall
WSACancelBlockingCall  QuickInfo

The Windows Sockets WSACancelBlockingCall function cancels a blocking call that is currently in progress.

int WSACancelBlockingCall(void);

Return Value

The value returned by WSACancelBlockingCall is zero if the operation was successfully canceled. Otherwise, the value SOCKET_ERROR is returned, and a specific error number may be retrieved by calling WSAGetLastError.

Error Codes

WSANOTINITIALISED	A successful WSAStartup must occur before using this function.
WSAENETDOWN	The Windows Sockets implementation has detected that the network subsystem has failed.
WSAEINVAL	Indicates that there is no outstanding blocking call.
Remarks

This function cancels any outstanding blocking operation for this task. It is typically used in two situations:

1.	An application is processing a message that was received while a blocking call is in progress. In this case, WSAIsBlocking will be true.

2.	A blocking call is in progress, and Windows Sockets has called back to the application's "blocking hook" function (as established by WSASetBlockingHook).

In each case, the original blocking call will terminate as soon as possible with the error WSAEINTR. In (1), the termination will not take place until Windows message scheduling has caused control to revert to the blocking routine in Windows Sockets. In (2), the blocking call will be terminated as soon as the blocking hook function completes.

In the case of a blocking connect operation, the Windows Sockets implementation will terminate the blocking call as soon as possible, but it may not be possible for the socket resources to be released until the connection has completed (and then been reset) or timed out. This is likely to be noticeable only if the application immediately tries to open a new socket (if no sockets are available), or to connect to the same peer.

Canceling an accept or a select call does not adversely impact the sockets passed to these calls. Only the particular call fails; any operation that was legal before the cancel is legal after the cancel, and the state of the socket is not affected in any way.

Canceling any operation other than accept and select can leave the socket in an indeterminate state. If an application cancels a blocking operation on a socket, the only operation that the application can depend on being able to perform on the socket is a call to closesocket, although other operations may work on some Windows Sockets implementations. If an application needs maximum portability, it must not depend on performing operations after a cancel. An application can reset the connection by setting the timeout on SO_LINGER to zero.

If a cancel operation compromised the integrity of a SOCK_STREAM's data stream in any way, the Windows Sockets implementation must reset the connection and fail all future operations other than closesocket with WSAECONNABORTED.

Note that it is possible that the network operation completes before the WSACancelBlockingCall is processed, for example if data is received into the user buffer at interrupt time while the application is in a blocking hook. In this case, the blocking operation will return successfully as if WSACancelBlockingCall had never been called. The WSACancelBlockingCall still succeeds in this case; the only way to know with certainty that an operation was actually canceled is to check for a return code of WSAEINTR from the blocking call.

See Also

accept, closesocket, connect, select, WSAStartup


WSACleanup
WSACleanup  QuickInfo

The Windows Sockets WSACleanup function terminates use of the Windows Sockets DLL.

int WSACleanup(void);

Return Value

The return value is zero if the operation was successful. Otherwise the value SOCKET_ERROR is returned, and a specific error number may be retrieved by calling WSAGetLastError.

Error Codes

WSANOTINITIALISED	A successful WSAStartup must occur before using this function.
WSAENETDOWN	The Windows Sockets implementation has detected that the network subsystem has failed.
WSAEINPROGRESS	A blocking Windows Sockets operation is in progress.
Remarks

An application or DLL is required to perform a (successful) WSAStartup call before it can use Windows Sockets services. When it has completed the use of Windows Sockets, the application or DLL must call WSACleanup to deregister itself from a Windows Sockets implementation and allow the implementation to free any resources allocated on behalf of the application or DLL. Any open SOCK_STREAM sockets that are connected when WSACleanup is called are reset; sockets that have been closed with closesocket but still have pending data to be sent are not affected — the pending data is still sent.

There must be a call to WSACleanup for every call to WSAStartup made by a task. Only the final WSACleanup for that task does the actual cleanup; the preceding calls simply decrement an internal reference count in the Windows Sockets DLL. A naive application can ensure that WSACleanup was called enough times by calling WSACleanup in a loop until it returns WSANOTINITIALISED.

Attempting to call WSACleanup from within a blocking hook and then failing to check the return code is a common error in Windows Sockets programming. If an application needs to quit while a blocking call is outstanding, the application must first cancel the blocking call with WSACancelBlockingCall then issue the WSACleanup call once control has been returned to the application.

Notes for Windows Sockets Suppliers

Well-behaved Windows Sockets applications will make a WSACleanup call to indicate deregistration from a Windows Sockets implementation. This function can thus, for example, be utilized to free up resources allocated to the specific application.

A Windows Sockets implementation must be prepared to deal with an application that terminates without invoking WSACleanup — for example, as a result of an error.

In a multithreaded environment, WSACleanup terminates Windows Sockets operations for all threads.

A Windows Sockets implementation must ensure that WSACleanup leaves things in a state in which the application can invoke WSAStartup to reestablish Windows Sockets usage.

See Also

WSACancelBlockingCall, WSAStartup,


WSAGetLastError
WSAGetLastError  QuickInfo

The Windows Sockets WSAGetLastError function gets the error status for the last operation that failed.

int WSAGetLastError(void);

Return Value

The return value indicates the error code for the last Windows Sockets function performed by this thread.

Notes for Windows Sockets Suppliers

The use of the WSAGetLastError function to retrieve the last error code, rather than relying on a global error variable (compare errno), is required in order to provide compatibility with future multithreaded environments.

Note that in a nonpreemptive Windows environment WSAGetLastError is used to retrieve only Windows Sockets function errors. In a preemptive environment, WSAGetLastError will invoke GetLastError, which is used to retrieve the error status for all Win32 functions on a per-thread basis. For portability, an application should use WSAGetLastError immediately after the Windows Sockets function that failed. For more information, see Error Codes.

Remarks

This function returns the last network error that occurred. When a particular Windows Sockets function indicates that an error has occurred, this function should be called to retrieve the appropriate error code.

See Also

GetLastError, WSASetLastError


WSAIsBlocking
WSAIsBlocking  QuickInfo

The Windows Sockets WSAIsBlocking function determines if a blocking call is in progress.

BOOL WSAIsBlocking(void);

Return Value

The return value is TRUE if there is an outstanding blocking function awaiting completion. Otherwise, it is FALSE.

Remarks

This function allows a task to determine if it is executing while waiting for a previous blocking call to complete.

Although a call issued on a blocking socket appears to an application program as though it "blocks," the Windows Sockets DLL has to relinquish the processor to allow other applications to run. This means that it is possible for the application that issued the blocking call to be reentered, depending on the message(s) it receives. In this instance, the WSAIsBlocking function can be used to ascertain whether the task has been reentered while waiting for an outstanding blocking call to complete. Note that Windows Sockets prohibits more than one outstanding call per thread.

Notes for Windows Sockets Suppliers

A Windows Sockets implementation must prohibit more than one outstanding blocking call per thread.


WSASetBlockingHook
WSASetBlockingHook  QuickInfo

The Windows Sockets WSASetBlockingHook function establishes an application-specific blocking hook function.

FARPROC WSASetBlockingHook(

FARPROC lpBlockFunc
);
Parameters

lpBlockFunc

A pointer to the procedure instance address of the blocking function to be installed.

Return Value

The return value is a pointer to the procedure-instance of the previously installed blocking function. The application or library that calls the WSASetBlockingHook  function should save this return value so that it can be restored if necessary. (If "nesting" is not important, the application can simply discard the value returned by WSASetBlockingHook and eventually use WSAUnhookBlockingHook to restore the default mechanism.) If the operation fails, a NULL pointer is returned, and a specific error number can be retrieved by calling WSAGetLastError.

Error Codes

WSANOTINITIALISED	A successful WSAStartup must occur before using this function.
WSAENETDOWN	The Windows Sockets implementation has detected that the network subsystem has failed.
WSAEINPROGRESS	A blocking Windows Sockets operation is in progress.
Remarks

This function installs a new function which a Windows Sockets implementation should use to implement blocking socket function calls.

A Windows Sockets implementation includes a default mechanism by which blocking socket functions are implemented. The function WSASetBlockingHook gives the application the ability to execute its own function at blocking time in place of the default function.

When an application invokes a blocking Windows Sockets operation, the Windows Sockets implementation initiates the operation and then enters a loop similar to the following pseudocode:

for(;;) {

    /* flush messages for good user response */

    while (BlockingHook)

        ;

    /* check for WSACancelBlockingCall */

    if(operation_cancelled)

       break;

    /* check to see if operation completed */

    if(operation_complete)

        break;        /* normal completion */

}

Note that Windows Sockets implementations can perform the above steps in a different order; for example, the check for operation completion may occur before calling the blocking hook. The default BlockingHook function is equivalent to:

BOOL DefaultBlockingHook(void)

{

    MSG msg;

    BOOL ret;

    /* get the next message, if any */

    ret = (BOOL) PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);

    /* if we got one, process it */

    if (ret) {

        TranslateMessage(&msg);

        DispatchMessage(&msg);

    }

    /* TRUE if we got a message */

    return ret;

}

The WSASetBlockingHook function is provided to support those applications that require more complex message processing — for example, those employing the MDI (multiple document interface) model. It is not intended as a mechanism for performing general applications functions. In particular, the only Windows Sockets function that can be issued from a custom blocking hook function is WSACancelBlockingCall, which will cause the blocking loop to terminate.

This function must be implemented on a per-task basis for non-multithreaded versions of Windows and on a per-thread basis for multithreaded versions of Windows such as Windows NT. It thus provides for a particular task or thread to replace the blocking mechanism without affecting other tasks or threads.

In multithreaded versions of Windows, there is no default blocking hook — blocking calls block the thread that makes the call. However, an application can install a specific blocking hook by calling WSASetBlockingHook.

This allows easy portability of applications that depend on the blocking hook behavior.

See Also

WSACancelBlockingCall, WSAUnhookBlockingHook


WSASetLastError
WSASetLastError  QuickInfo

The Windows Sockets WSASetLastError function sets the error code that can be retrieved by WSAGetLastError.

void WSASetLastError(

int iError
);
Parameters

iError

Specifies the error code to be returned by a subsequent WSAGetLastError call.

Return Value

This function does not return a value.

Error Codes

WSANOTINITIALISED	A successful WSAStartup must occur before using this function.
Remarks

This function allows an application to set the error code to be returned by a subsequent WSAGetLastError call for the current thread. Note that any subsequent Windows Sockets function called by the application will override the error code as set by this function.

Notes for Windows Sockets Suppliers

In a Win32 environment, this function will invoke SetLastError.

See Also

SetLastError, WSAGetLastError


WSAStartup
WSAStartup  QuickInfo

int WSAStartup(

WORD wVersionRequested,
LPWSADATA lpWSAData
);
Parameters

wVersionRequested

The highest version of Windows Sockets support that the caller can use. The high-order byte specifies the minor version (revision) number; the low-order byte specifies the major version number.

lpWSAData

A pointer to the WSADATA data structure that is to receive details of the Windows Sockets implementation.

Return Value

WSAStartup returns zero if successful. Otherwise, it returns one of the error codes listed below. Note that the normal mechanism whereby the application calls WSAGetLastError to determine the error code cannot be used, since the Windows Sockets DLL may not have established the client data area where the "last error" information is stored.

Notes for Windows Sockets Suppliers

Each Windows Sockets application MUST make a WSAStartup call before issuing any other Windows Sockets API calls. This function can thus be used for initialization purposes.

Further issues are discussed in the notes for WSACleanup.

Error Codes

WSASYSNOTREADY	Indicates that the underlying network subsystem is not ready for network communication.
WSAVERNOTSUPPORTED	The version of Windows Sockets support requested is not provided by this particular Windows Sockets implementation.
WSAEINVAL	The Windows Sockets version specified by the application is not supported by this DLL.
Remarks

This function must be the first Windows Sockets function called by an application or DLL. It allows an application or DLL to specify the version of Windows Sockets required and to retrieve details of the specific Windows Sockets implementation. The application or DLL may only issue further Windows Sockets functions after a successful WSAStartup invocation.

In order to support future Windows Sockets implementations and applications that may have functionality differences from Windows Sockets 1.1, a negotiation takes place in WSAStartup. The caller of WSAStartup and the Windows Sockets DLL indicate to each other the highest version that they can support, and each confirms that the other's highest version is acceptable. Upon entry to WSAStartup, the Windows Sockets DLL examines the version requested by the application. If this version is higher than the lowest version supported by the DLL, the call succeeds and the DLL returns in wHighVersion the highest version it supports and in wVersion the minimum of its high version and wVersionRequested. The Windows Sockets DLL then assumes that the application will use wVersion. If the wVersion field of the WSADATA structure is unacceptable to the caller, it should call WSACleanup and either search for another Windows Sockets DLL or fail to initialize.

This negotiation allows both a Windows Sockets DLL and a Windows Sockets application to support a range of Windows Sockets versions. An application can successfully use a Windows Sockets DLL if there is any overlap in the version ranges. The following chart gives examples of how WSAStartup works in conjunction with different application and Windows Sockets DLL versions:

App versions	DLL Versions	wVersionRequested	wVersion	wHighVersion	End Result
1.1	1.1	1.1	1.1	1.1	use 1.1
1.0 1.1	1.0	1.1	1.0	1.0	use 1.0
1.0	1.0 1.1	1.0	1.0	1.1	use 1.0
1.1	1.0 1.1	1.1	1.1	1.1	use 1.1
1.1	1.0	1.1	1.0	1.0	Application fails
1.0	1.1	1.0	---	---	WSAVERNOTSUPPORTED
1.0 1.1	1.0 1.1	1.1	1.1	1.1	use 1.1
1.1 2.0	1.1	2.0	1.1	1.1	use 1.1
2.0	1.1	2.0	1.1	1.1	Application fails
The following code fragment demonstrates how an application that supports only version 1.1 of Windows Sockets makes a WSAStartup call:

WORD wVersionRequested;

WSADATA wsaData;

int err;

wVersionRequested = MAKEWORD(1, 1);

err = WSAStartup(wVersionRequested, &wsaData);

if (err != 0)

    /* Tell the user that we couldn't find a useable */

    /* winsock.dll.     */

    return;

/* Confirm that the Windows Sockets DLL supports 1.1.*/

/* Note that if the DLL supports versions greater */

/* than 1.1 in addition to 1.1, it will still return */

/* 1.1 in wVersion since that is the version we */

/* requested. */

if ( LOBYTE( wsaData.wVersion ) != 1 ||

        HIBYTE( wsaData.wVersion ) != 1 ) {

    /* Tell the user that we couldn't find a useable */

    /* winsock.dll. */

    WSACleanup();

    return;

}

/* The Windows Sockets DLL is acceptable. Proceed. */

This code fragment demonstrates how a Windows Sockets DLL that supports only version 1.1 performs the WSAStartup negotiation:

/* Make sure that the version requested is >= 1.1. */

/* The low byte is the major version and the high */

/* byte is the minor version.   */

if ( LOBYTE( wVersionRequested ) < 1 ||

        ( LOBYTE( wVersionRequested ) == 1 &&

        HIBYTE( wVersionRequested ) < 1 )

    return WSAVERNOTSUPPORTED;

/* Since we only support 1.1, set both wVersion and */

/* wHighVersion to 1.1. */

lpWsaData->wVersion = MAKEWORD( 1, 1 );

lpWsaData->wHighVersion = MAKEWORD( 1, 1 );

Once an application or DLL has made a successful WSAStartup call, it may proceed to make other Windows Sockets calls as needed. When it has finished using the services of the Windows Sockets DLL, the application or DLL must call WSACleanup in order to allow the Windows Sockets DLL to free any resources for the application.

Details of the actual Windows Sockets implementation are described in the WSAData structure defined as follows:

struct WSAData {

    WORD            wVersion;

    WORD            wHighVersion;

    char            szDescription[WSADESCRIPTION_LEN+1];

    char            szSystemStatus[WSASYSSTATUS_LEN+1];

    unsigned short  iMaxSockets;

    unsigned short  iMaxUdpDg;

    char FAR *      lpVendorInfo;

};

The members of this structure are:

Members	Usage
wVersion	The version of the Windows Sockets specification that the Windows Sockets DLL expects the caller to use.
wHighVersion	The highest version of the Windows Sockets specification that this DLL can support (also encoded as shown previously). Typically, this will be the same as wVersion.
szDescription	A null-terminated ASCII string into which the Windows Sockets DLL copies a description of the Windows Sockets implementation, including vendor identification. The text (up to 256 characters in length) may contain any characters, but vendors are cautioned against including control and formatting characters: the most likely use that an application will put this to is to display it (possibly truncated) in a status message.
szSystemStatus	A null-terminated ASCII string into which the Windows Sockets DLL copies relevant status or configuration information. The Windows Sockets DLL should use this field only if the information might be useful to the user or support staff: it should not be considered an extension of the szDescription field.
iMaxSockets	The maximum number of sockets that a single process can open. A Windows Sockets implementation can provide a global pool of sockets for allocation to any process; alternatively, it can allocate per-process resources for sockets. The number may well reflect the way the Windows Sockets DLL or the networking software was configured. Application writers may use this number as a crude indication of whether the Windows Sockets implementation is usable by the application. For example, an X Windows server might check iMaxSockets when first started: if it is less than 8, the application would display an error message instructing the user to reconfigure the networking software. (This is a situation in which the szSystemStatus text might be used.) Obviously, there is no guarantee that a particular application can actually allocate iMaxSockets sockets, since there may be other Windows Sockets applications in use.
iMaxUdpDg	The size, in bytes, of the largest UDP datagram that can be sent or received by a Windows Sockets application. If the implementation imposes no limit, iMaxUdpDg is zero. In many implementations of Berkeley sockets, there is an implicit limit of 8192 bytes on UDP datagrams (which are fragmented if necessary). A Windows Sockets implementation can impose a limit based, for instance, on the allocation of fragment reassembly buffers. The minimum value of iMaxUdpDg for a Windows Sockets-compliant implementation is 512. Note that regardless of the value of iMaxUdpDg, it is inadvisable to attempt to send a broadcast datagram larger than the Maximum Transmission Unit (MTU) for the network. (Windows Sockets does not provide a mechanism to discover the MTU, but it must be no less than 512 bytes.)
lpVendorInfo	A far pointer to a vendor-specific data structure. The definition of this structure (if supplied) is beyond the scope of this documentation.
An application or DLL can call WSAStartup more than once if it needs to obtain the WSAData structure information more than once. However, the wVersionRequired parameter is assumed to be the same on all calls to WSAStartup; that is, an application or DLL cannot change the version of Windows Sockets it expects after the initial call to WSAStartup.

There must be one WSACleanup call corresponding to every WSAStartup call to allow third-party DLLs to make use of a Windows Sockets DLL on behalf of an application. This means, for example, that if an application calls WSAStartup three times, it must call WSACleanup three times. The first two calls to WSACleanup do nothing except decrement an internal counter; the final WSACleanup call for the task deallocates all necessary resources for the task.

See Also

send, sendto, WSACleanup


WSAUnhookBlockingHook
WSAUnhookBlockingHook  QuickInfo

The Windows Sockets WSAUnhookBlockingHook function restores the default blocking hook function.

int WSAUnhookBlockingHook(

void
);
Remarks

This function removes any previous blocking hook that has been installed and reinstalls the default blocking mechanism.

WSAUnhookBlockingHook will always install the default mechanism, not the previous mechanism. If an application needs to nest blocking hooks — that is, to establish a temporary blocking hook function and then revert to the previous mechanism (whether the default or one established by an earlier WSASetBlockingHook) — it must save and restore the value returned by WSASetBlockingHook; it cannot use WSAUnhookBlockingHook.

In multithreaded versions of Windows such as Windows NT, there is no default blocking hook. Calling WSAUnhookBlockingHook disables any blocking hook installed by the application and any blocking calls made block the thread that made the call.

Return Value

The return value is zero if the operation was successful. Otherwise, the value SOCKET_ERROR is returned, and a specific error number may be retrieved by calling WSAGetLastError.

Error Codes

WSANOTINITIALISED	A successful WSAStartup must occur before using this function.
See Also

WSASetBlockingHook


wsprintf
wsprintf  QuickInfo  Overview  Group

The wsprintf function formats and stores a series of characters and values in a buffer. Any arguments are converted and copied to the output buffer according to the corresponding format specification in the format string. The function appends a terminating null character to the characters it writes, but the return value does not include the terminating null character in its character count.

int wsprintf(

LPTSTR  lpOut,	// address of buffer for output
LPCTSTR  lpFmt	// address of format-control string
...	// optional arguments
);
Parameters

lpOut

Points to a buffer to receive the formatted output.

lpFmt

Points to a null-terminated string that contains the format-control specifications. In addition to ordinary ASCII characters, a format specification for each argument appears in this string. For more information about the format specification, see the Remarks section.

...

Specifies one or more optional arguments. The number and type of argument parameters depend on the corresponding format-control specifications in the lpFmt parameter.

Return Value

If the function succeeds, the return value is the number of characters stored in the output buffer, not counting the terminating null character.

If the function fails, the return value is less than the length of the format-control string. To get extended error information, call GetLastError.

Remarks

The format-control string contains format specifications that determine the output format for the arguments following the lpFmt parameter. Format specifications, discussed below, always begin with a percent sign (%). If a percent sign is followed by a character that has no meaning as a format field, the character is not formatted (for example, %% produces a single percent-sign character).

The format-control string is read from left to right. When the first format specification (if any) is encountered, it causes the value of the first argument after the format-control string to be converted and copied to the output buffer according to the format specification. The second format specification causes the second argument to be converted and copied, and so on. If there are more arguments than format specifications, the extra arguments are ignored. If there are not enough arguments for all of the format specifications, the results are undefined.

A format specification has the following form:

%[-][#][0][width][.precision]type

Each field is a single character or a number signifying a particular format option. The type characters that appear after the last optional format field determine whether the associated argument is interpreted as a character, a string, or a number. The simplest format specification contains only the percent sign and a type character (for example, %s). The optional fields control other aspects of the formatting. Following are the optional and required fields and their meanings:

Field	Meaning
−	Pad the output with blanks or zeros to the right to fill the field width, justifying output to the left. If this field is omitted, the output is padded to the left, justifying it to the right.
#	Prefix hexadecimal values with 0x (lowercase) or 0X (uppercase).
0	Pad the output value with zeros to fill the field width. If this field is omitted, the output value is padded with blank spaces.
width	Copy the specified minimum number of characters to the output buffer. The width field is a nonnegative integer. The width specification never causes a value to be truncated; if the number of characters in the output value is greater than the specified width, or if the width field is not present, all characters of the value are printed, subject to the precision specification.
.precision	For numbers, copy the specified minimum number of digits to the output buffer. If the number of digits in the argument is less than the specified precision, the output value is padded on the left with zeros. The value is not truncated when the number of digits exceeds the specified precision. If the specified precision is 0 or omitted entirely, or if the period (.) appears without a number following it, the precision is set to 1.
	For strings, copy the specified maximum number of characters to the output buffer.
type	Output the corresponding argument as a character, a string, or a number. This field can be any of the following character sequences:
Sequence	Insert
c	A single character. The wsprintf function ignores character arguments with a numeric value of zero. This sequence is interpreted as type WCHAR when the calling application uses the #define UNICODE compile flag and as type CHAR otherwise.
C	A single character. This sequence is interpreted as type CHAR when the calling application uses the #define UNICODE compile flag and as type WCHAR otherwise.
d	A signed decimal integer argument. This sequence is equivalent to the i sequence.
hc, hC	A single character. The wsprintf function ignores character arguments with a numeric value of zero. This sequence is always interpreted as type CHAR, even when the calling application uses the #define UNICODE compile flag.
hs, hS	A string. This sequence is always interpreted as type LPSTR, even when the calling application uses the #define UNICODE compile flag.
i	A signed decimal integer. This sequence is equivalent to the d sequence.
lc, lC	A single character. The wsprintf function ignores character arguments with a numeric value of zero. This sequence is always interpreted as type WCHAR, even when the calling application does not use the #define UNICODE compile flag.
ld	A long signed decimal integer. This sequence is equivalent to the li sequence.
li	A long signed decimal integer. This sequence is equivalent to the ld sequence.
ls, lS	A string. This sequence is always interpreted as type LPWSTR, even when the calling application does not use the #define UNICODE compile flag. This sequence is equivalent to the ws sequence.
lu	A long unsigned integer.
lx, lX	A long unsigned hexadecimal integer in lowercase or uppercase.
s	A string. This sequence is interpreted as type LPWSTR when the calling application uses the #define UNICODE compile flag and as type LPSTR otherwise.
S	A string. This sequence is interpreted as type LPSTR when the calling application uses the #define UNICODE compile flag and as type LPWSTR otherwise.
u	An unsigned integer argument.
x, X	An unsigned hexadecimal integer in lowercase or uppercase.
Note  Unlike other Windows functions, wsprintf uses the C calling convention (_cdecl), rather than the Pascal calling convention. As a result, it is the responsibility of the calling process to pop arguments off the stack, and arguments are pushed on the stack from right to left. In C-language modules, the C compiler performs this task.

See Also

wvsprintf


wvsprintf
wvsprintf  QuickInfo  Overview  Group

The wvsprintf function formats and stores a series of characters and values in a buffer. The items pointed to by the argument list are converted and copied to an output buffer according to the corresponding format specification in the format-control string. The function appends a terminating null character to the characters it writes, but the return value does not include the terminating null character in its character count.

int wvsprintf(

LPTSTR  lpOutput,	// address of buffer for output
LPCTSTR  lpFormat,	// address of format-control string
va_list  arglist	// variable argument list of format-control arguments
);
Parameters

lpOutput

Points to a buffer to receive the formatted output.

lpFormat

Points to a null-terminated string that contains the format-control specifications. In addition to ordinary ASCII characters, a format specification for each argument appears in this string. For more information about the format specification, see the wsprintf function.

arglist

A variable argument list; each element of the list specifies an argument for the format-control string. The number, type, and interpretation of the arguments depend on the corresponding format-control specifications in the lpFmt parameter.

Return Value

If the function succeeds, the return value is the number of characters stored in the buffer, not counting the terminating null character.

If the function fails, the return value is less than the length of the format-control string. To get extended error information, call GetLastError.

Remarks

The function copies the format-control string into the output buffer character by character, starting with the first character in the string. When it encounters a format specification in the string, the function retrieves the value of the next available argument (starting with the first argument in the list), converts that value into the specified format, and copies the result to the output buffer. The function continues to copy characters and expand format specifications in this way until it reaches the end of the format-control string. If there are more arguments than format specifications, the extra arguments are ignored. If there are not enough arguments for all of the format specifications, the results are undefined.

See Also

wsprintf


Yield
Yield  Overview  Group

The Yield function is obsolete. In the Win32-based application programming interface (API), this function does nothing.

Threads that contain windows should use the DispatchMessage, PeekMessage, or TranslateMessage functions. The message-loop functions handle message synchronization properly and yield at the appropriate times.

Threads that do not contain windows should use the Sleep function with a sleep time of zero milliseconds to give up the remainder of their current time slice.

See Also

DispatchMessage, PeekMessage, Sleep, TranslateMessage


ZeroMemory
ZeroMemory  QuickInfo  Overview  Group

The ZeroMemory function fills a block of memory with zeros.

VOID ZeroMemory(

PVOID  Destination	// address of block to fill with zeros
DWORD  Length	// size, in bytes, of block to fill with zeros
);
Parameters

Destination

Points to the starting address of the block of memory to fill with zeros.

Length

Specifies the size, in bytes, of the block of memory to fill with zeros.

Return Value

This function has no return value.

See Also

CopyMemory, FillMemory, MoveMemory


Interfaces

The following interfaces are arranged in alphabetical order by interface name. The methods are listed following their interfaces.

The shell interfaces and methods are used with shell extensions, shell links, name spaces, and appbars. The rich edit OLE interfaces and methods are used with rich text edit controls.

•	Shell Library Interfaces

IContextMenu
ICopyHook
IEnumIDList
IExtractIcon
IShellExtInit
IShellFolder
IShellLink
IShellPropSheetExt

•	Rich Edit OLE Interfaces

IRichEditOle
IRichEditOleCallback


IContextMenu [New - Windows 95]
IContextMenu

[New - Windows 95]

Designates an interface that enables the shell to retrieve extensions to context menus.

Methods in Vtable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments reference count.
Release	Decrements reference count.
IContextMenu Methods	Description
QueryContextMenu	Adds commands to a context menu.
InvokeCommand	Carries out a menu command, either in response to user input or otherwise. For an example, see IExtractIcon.
GetCommandString	Retrieves the language-independent name of a menu command or the help text for a menu command.


IContextMenu::GetCommandString [New - Windows 95]
IContextMenu::GetCommandString  QuickInfo

[New - Windows 95]

Retrieves the language-independent command string or the help text for a context menu item.

HRESULT STDMETHODCALLTYPE GetCommandString(

LPCONTEXTMENU pIface,
UINT idCmd,
UINT uFlags,
UINT *pwReserved,
LPSTR pszName,
UINT cchMax
);
Parameters

pIface

Pointer to the IContextMenu interface. In C++, this parameter is implicit.

idCmd

Menu item identifier offset.

uFlags

Flag specifying the information to retrieve. This parameter can be one of the following values:

Value	Meaning
GCS_HELPTEXT	Returns the help text for the menu item.
GCS_VALIDATE	Validates that the menu item exists.
GCS_VERB	Returns the language-independent command name for the menu item.
pwReserved

Reserved. Applications must specify NULL when calling this method, and handles must ignore this parameter when called.

pszName and cchMax

Address and size of the buffer that receives the null-terminated string.

Return Value

Returns NOERROR if successful or an OLE-defined error code otherwise.

The language-independent command name is a name that can be passed to the IContextMenu::InvokeCommand method to activates a command by an application. The help text is a description that the Explorer displays in its status bar; it should be reasonably short (under 40 characters).

See Also

IContextMenu


IContextMenu::InvokeCommand [New - Windows 95]
IContextMenu::InvokeCommand  QuickInfo

[New - Windows 95]

Carries out the command associated with a context menu item.

HRESULT STDMETHODCALLTYPE InvokeCommand(

LPCONTEXTMENU pIface,
LPCMINVOKECOMMANDINFO lpici
);
Parameters

pIface

Pointer to the IContextMenu interface. In C++, this parameter is implicit.

lpici

Pointer to a CMINVOKECOMMANDINFO structure containing information about the command.

Return Value

Returns NOERROR if successful or an OLE-defined error code otherwise.

The shell calls this method when the user chooses a command that the handler added to a context menu. This method may also be called by an application without any corresponding user action.

See Also

CMINVOKECOMMANDINFO, IContextMenu


IContextMenu::QueryContextMenu [New - Windows 95]
IContextMenu::QueryContextMenu  QuickInfo

[New - Windows 95]

Adds menu items to the specified menu. The menu items should be inserted at a given position in the menu, and their menu item identifiers must be in a given range.

HRESULT STDMETHODCALLTYPE QueryContextMenu(

LPCONTEXTMENU pIface,
HMENU hmenu,
UINT indexMenu,
UINT idCmdFirst,
UINT idCmdLast,
UINT uFlags
);
Parameters

pIface

Pointer to the IContextMenu interface. In C++, this parameter is implicit.

hmenu

Handle of the menu. The handler should specify this handle when calling the InsertMenu or InsertMenuItem function.

indexMenu

Zero-based position at which to insert the first menu item.

idCmdFirst and idCmdLast

Minimum and maximum values that the handler can specify for menu item identifiers. The actual identifier of each menu item should be idCmdFirst plus a menu identifier offset in the range zero through (idCmdLast − idCmdFirst).

uFlags

Flag specifying zero or more of the following values:

CMF_DEFAULTONLY	The user is activating the default action, typically by double-clicking. A context menu extension or drag and drop handler should not add any menu items if this value is specified. A name space extension should add only the default item (if any).
CMF_EXPLORER	Context menu handlers should ignore this value. This value is specified if the context menu is for an object in the left pane of the explorer.
CMF_NORMAL	Indicates normal operation. A context menu extension, name space extension, or drag and drop handler can add any menu items.
CMF_VERBSONLY	Context menu handlers should ignore this value. This value is specified if the context menu is for a shortcut object.
The remaining bits of the low-order word are reserved by the system. The high-order word may be used for context-specific communications.

Return Value

Returns an HRESULT structure in which, if the method is successful, the code member contains the menu identifier offset of the last menu item added.

See Also

IContextMenu, InsertMenu, InsertMenuItem


ICopyHook [New - Windows 95]
ICopyHook

[New - Windows 95]

Designates an interface that allows a copy hook handler to prevent a folder or printer object from being copied, moved, deleted, or renamed. The shell calls a copy hook handler whenever file system directories are about to be copied, moved, deleted, or renamed, as well as whenever the status of a printer is about to change.

The shell initializes the copy hook handler interface directly — that is, without using the IShellExtInit interface first. A folder object can have multiple copy hook handlers. A copy hook handler interface has one method, CopyCallBack.

Methods in Vtable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments reference count.
Release	Decrements reference count.
IContextMenu Methods	Description
CopyCallBack	Carries out a move, copy, delete, or rename operation on a folder object, or prevents the shell from carrying out the operation.


ICopyHook::CopyCallback [New - Windows 95]
ICopyHook::CopyCallback  QuickInfo

[New - Windows 95]

Either allows the shell to carry out a move, copy, delete, or rename operation on a folder object, or prevents the shell from carrying out the operation. The shell calls each copy hook handler registered for a folder object until either all the handlers have been called or any handler returns IDCANCEL.

HRESULT STDMETHODCALLTYPE CopyCallback(

ICopyHook FAR * pCopyHook,
HWND hwnd,
UINT wFunc,
UINT wFlags,
LPCSTR pszSrcFile,
DWORD dwSrcAttribs,
LPCSTR pszDestFile,
DWORD dwDestAttribs
);
Parameters

pCopyHook

Pointer to the ICopyHook interface. In C++, this parameter is implicit.

hwnd

Handle of the window that the copy hook handler should use as the parent window for any user interface elements the handler may need to display. If FOF_SILENT is specified, the method should ignore this parameter.

wFunc

Operation to perform. This parameter can be one of the following values:

FO_COPY	Copies the file specified by pszSrcFile to the location specified by pszDestFile.
FO_DELETE	Deletes the file specified by pszSrcFile.
FO_MOVE	Moves the file specified by pszSrcFile to the location specified by pszDestFile.
FO_RENAME	Renames the file specified by pszSrcFile.
PO_DELETE	Deletes the printer specified by pszSrcFile.
PO_PORTCHANGE	Changes the printer port. The pszSrcFile and pszDestFile parameters contain double null-terminated lists of strings. Each list contains the printer name followed by the port name. The port name in pszSrcFile is the current printer port, and the port name in pszDestFile is the new printer port.
PO_RENAME	Renames the printer specified by pszSrcFile.
PO_REN_PORT	Combination of PO_RENAME and PO_PORTCHANGE.
wFlags

Flags that control the operation. This parameter can be a combination of the following values:

FOF_ALLOWUNDO	Preserves undo information (if possible).
FOF_CONFIRMMOUSE	Not implemented.
FOF_FILESONLY	Not implemented. The shell calls a copy hook handler only for folder objects, not files.
FOF_MULTIDESTFILES	The SHFileOperation function specified multiple destination files (one for each source file) rather than one directory where all the source files are to be deposited. A copy hook handler typically ignores this value.
FOF_NOCONFIRMATION	Responds with "yes to all" for any dialog box that is displayed.
FOF_NOCONFIRMMKDIR	Does not confirm the creation of any needed directories if the operation requires a new directory to be created.
FOF_RENAMEONCOLLISION	Gives the file being operated on a new name (such as, "Copy #1 of ...") in a copy, move, or rename operation if a file of the target name already exists.
FOF_SILENT	Displays no progress dialog box.
FOF_SIMPLEPROGRESS	Displays a progress dialog box, but the dialog box does not show the names of the files.
pszSrcFile

Pointer to a string that contains the name of the source file.

dwSrcAttribs

Attributes of the source file. This parameter can be a combination of any of the file attribute flags (FILE_ATTRIBUTE_*) defined in the Windows header files.

pszDestFile

Pointer to a string that contains the name of the destination file.

dwDestAttribs

Attributes of the source file. This parameter can be a combination of any of the file attribute flags (FILE_ATTRIBUTE_*) defined in the Windows header files.

Return Value

Returns an integer value that indicates whether the shell should perform the operation. It can be one of the following values:

IDYES	Allows the operation.
IDNO	Prevents the operation on this file, but continues with any other operations (for example, a batch copy operation).
IDCANCEL	Prevents the current operation and cancels any pending operations.
See Also

ICopyHook


IEnumIDList [New - Windows 95]
IEnumIDList

[New - Windows 95]

Designates an interface used to enumerate item identifiers. The IShellFolder::EnumObjects method creates an IEnumIDList interface.

Methods in Vtable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments reference count.
Release	Decrements reference count.
IEnumIDList Methods	Description
Clone	Creates a new item enumeration object having the same contents and state as the given one.
Next	Retrieves one or more item identifiers and advances the current position.
Reset	Returns to the beginning of the enumeration sequence.
Skip	Skips over one or more items in the enumeration sequence.


IEnumIDList::Clone [New - Windows 95]
IEnumIDList::Clone  QuickInfo

[New - Windows 95]

Creates a new item enumeration object with the same contents and state as the current one.

HRESULT STDMETHODCALLTYPE Clone(

IEnumIDList FAR * pEnumIDList,
IEnumIDList **ppenum
);
Parameters

pEnumIDList

Pointer to the IEnumIDList interface. In C++, this parameter is implicit.

ppenum

Address that receives a pointer to the new enumeration object. The calling application must eventually free the new object by calling its Release method.

Return Value

Returns NOERROR if successful or an OLE-defined error value otherwise.

This method makes it possible to record a particular point in the enumeration sequence and then return to that point at a later time.

See Also

IEnumIDList


IEnumIDList::Next [New - Windows 95]
IEnumIDList::Next  QuickInfo

[New - Windows 95]

Retrieves the specified number of item identifiers in the enumeration sequence and advances the current position.

HRESULT STDMETHODCALLTYPE Next(

EnumIDList FAR * pEnumIDList,
LONG celt,
PITEMIDLIST *rgelt,
LONG *pceltFetched
);
Parameters

EnumIDList

Address of the IEnumIDList interface. In C++, this parameter is implicit.

celt

Number of item identifiers to retrieve. If the number of identifiers requested is more than remains in the sequence, only the remaining elements are retrieved.

rgelt

Address of an array in which to return the item identifiers. The calling application is responsible for freeing the returned item identifier lists by using the shell's allocator.

pceltFetched

Pointer to a value that receives a count of the item identifiers actually returned in rgelt. This parameter can be NULL if (and only if) celt is one.

Return Value

Returns NOERROR if successful, S_FALSE if there are no more items in the enumeration sequence, or an OLE-defined error value if an error occurs.

If this method returns any value other than NOERROR, no entries in the rgelt array are valid on exit. They are all in an indeterminate state.

See Also

IEnumIDList


IEnumIDList::Reset [New - Windows 95]
IEnumIDList::Reset  QuickInfo

[New - Windows 95]

Returns to the beginning of the enumeration sequence.

HRESULT STDMETHODCALLTYPE Reset(

IEnumIDList FAR * pEnumIDList
);
Parameter

pEnumIDList

Pointer to the IEnumIDList interface. In C++, this parameter is implicit.

Return Value

Returns NOERROR if successful or an OLE-defined error value otherwise.

See Also

IEnumIDList


IEnumIDList::Skip [New - Windows 95]
IEnumIDList::Skip  QuickInfo

[New - Windows 95]

Skips over the specified number of elements in the enumeration sequence.

HRESULT STDMETHODCALLTYPE Skip(

IEnumIDList FAR * pEnumIDList,
ULONG celt
);
Parameters

pEnumIDList

Pointer to the IEnumIDList interface. In C++, this parameter is implicit.

celt

Number of item identifiers to skip.

Return Value

Returns NOERROR if successful or an OLE-defined error value otherwise.

See Also

IEnumIDList


IExtractIcon [New - Windows 95]
IExtractIcon

[New - Windows 95]

Designates an interface that enables the shell to retrieve icons for file objects or folders.

Methods in Vtable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments reference count.
Release	Decrements reference count.
IExtractIcon Methods	Description
GetIconLocation	Retrieves the icon location for a file object.
ExtractIcon	Extracts an icon from the specified location.


IExtractIcon::Extract [New - Windows 95]
IExtractIcon::Extract  QuickInfo

[New - Windows 95]

Extracts an icon image from the specified location.

HRESULT STDMETHODCALLTYPE Extract(

LPEXTRACTICON pIface,
LPCSTR pszFile,
UINT nIconIndex,
HICON *phiconLarge,
HICON *phiconSmall,
UINT nIconSize
);
Parameters

pIface

Pointer to the IExtractIcon interface. In C++, this parameter is implicit.

pszFile

Pointer to a null-terminated string specifying the icon location.

nIconIndex

Icon index.

phiconLarge and phiconSmall

Addresses of variables that receive the handles of the large and small icons, respectively.

nIconSize

Value specifying the size, in pixels, of the large icon required. The size specified can be the width or height. The width of an icon always equals its height.

Return Value

Returns NOERROR if the function extracted the icon or S_FALSE if the calling application should extract the icon.

The icon location and index are the same values returned by the IExtractIcon::GetIconLocation method. If this function returns S_FALSE, these values must specify an icon filename and index. If this function does not return S_FALSE, the calling application should make no assumptions about the meanings of the pszFile and nIconIndex parameters.

See Also

IExtractIcon, IExtractIcon::GetIconLocation


IExtractIcon::GetIconLocation [New - Windows 95]
IExtractIcon::GetIconLocation  QuickInfo

[New - Windows 95]

Retrieves the location and index of an icon.

HRESULT STDMETHODCALLTYPE GetIconLocation(

LPEXTRACTICON pIface,
UINT uFlags,
LPSTR szIconFile,
INT cchMax,
int *piIndex,
UINT *pwFlags
);
Parameters

pIface

Pointer to the IExtractIcon interface. In C++, this parameter is implicit.

uFlags

Flags. This parameter can be zero or the following values:

GIL_FORSHELL	The icon is to be displayed in a shell folder.
GIL_OPENICON	The icon is for a folder that is open.
szIconFile and cchMax

Address and size of the buffer that receives the icon location. The icon location is a null-terminated string that typically specifies the name of an icon file.

piIndex

Pointer to an integer that receives the icon index.

pwFlags

Pointer to an unsigned integer that receives zero or more of the following values:

GIL_DONTCACHE	The icon should not be cached.
GIL_NOTFILENAME	The location is not a filename. To extract the icon from the location, use the IExtractIcon::Extract method.
GIL_PERCLASS	All file objects of this class have the same icon.
GIL_PERINSTANCE	Each file object of this class has its own icon.
GIL_SIMULATEDOC	The shell should create a document icon using the specified icon.
Return Value

Returns NOERROR if the function returned a valid location or S_FALSE if the shell should use a default icon.

See Also

IExtractIcon, IExtractIcon::Extract


IRichEditOle [New - Windows NT]
IRichEditOle

[New - Windows NT]

Specifies an interface used by the client of a rich text edit control to carry out OLE-related operations. The IRichEditOle interface has the following methods:

Methods in Vtable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments reference count.
Release	Decrements reference count.
IRichEditOle Methods	Description
GetClientSite	Retrieves an IOleClientSite interface to use when creating a new object.
GetObjectCount	Returns the number of objects contained in a rich edit control.
GetLinkCount	Returns the number of objects in a rich edit control that are links.
GetObject	Returns information from a REOBJECT structure about an object in a rich edit control.
InsertObject	Inserts an object into a rich edit control.
ConvertObject	Converts an object to a new type.
ActivateAs	Unloads objects of the old class, telling OLE to treat those objects as objects of the new class, and reloading the objects.
SetHostNames	Sets the "host names" to be given to objects as they are inserted to a rich edit control.
SetLinkAvailable	Sets the value of the link available bit in the object's flags.
SetDvaspect	Sets the aspect that a rich edit control uses to draw an object.
HandsOffStorage	Tells a rich edit control to release its reference to the storage interface associated with the specified object.
SaveCompleted	Tells a rich edit control that the most recent save operation has been completed, and that it should hold on to a different storage for the object.
InPlaceDeactivate	Tells a rich edit control to deactivate the currently active in-place object, if any.
ContextSensitiveHelp	Tells a rich edit control to transition into or out of context-sensitive help mode.
GetClipboardData	Retrieves a clipboard object for a range in an edit control.
ImportDataObject	Imports a clipboard object into a rich edit control, replacing the current selection.


IRichEditOle::ActivateAs [New - Windows NT]
IRichEditOle::ActivateAs

[New - Windows NT]

Handles OLE "Activate As" behavior by unloading all objects of the old class, telling OLE to treat those objects as objects of the new class, and reloading the objects. If objects cannot be reloaded, they are deleted.

HRESULT ActivateAs(

REFCLSID rclsid,
REFCLSID rclsidAs
);
Parameters

rclsid

Class identifier of the old class.

rclsidAs

Class identifier of the new class.

Return Value

Returns success status. Use GetScode to retrieve an SCODE. Can be S_OK on success or an SCODE returned from OLE.

See Also

IRichEditOle


IRichEditOle::ContextSensitiveHelp [New - Windows NT]
IRichEditOle::ContextSensitiveHelp

[New - Windows NT]

Tells a rich edit control that it should transition into or out of context sensitive help mode. A rich edit control calls the ContextSensitiveHelp method of any in place object which is currently active if a state change is occuring.

HRESULT ContextSensitiveHelp(

BOOL fEnterMode
);
Parameter

fEnterMode

TRUE if entering context sensitive help mode; otherwise, FALSE.

Return Value

Returns success status. Can use GetScode to retrieve an SCODE. Can be S_OK on success or some other value returned by OLE.

See Also

IRichEditOle


IRichEditOle::ConvertObject [New - Windows NT]
IRichEditOle::ConvertObject

[New - Windows NT]

Converts an object to a new type. This call does reload the object but does not force an update; the caller must do this.

HRESULT ConvertObject(

LONG iob,
REFCLSID rclsidNew,
LPCSTR lpstrUserTypeNew
);
Parameters

iob

Index of the object to convert. If this parameter is REO_IOB_SELECTION, the selected object is to be converted.

rclsidNew

Class identifier of the class to which the object is to be converted.

szUserTypeNew

User-visible type name of the class to which the object is to be converted.

Return Value

Returns success status. Use GetScode to retrieve an SCODE. Can be S_OK on success or E_INVALIDARG if the index is invalid, or an SCODE returned from OLE.

See Also

IRichEditOle


IRichEditOle::GetClientSite [New - Windows NT]
IRichEditOle::GetClientSite

[New - Windows NT]

Retrieves an IOleClientSite interface to be used when creating a new object. All objects inserted into a rich edit control must use client site interfaces returned by this function. A client site may be used with exactly one object.

HRESULT GetClientSite(

LPOLECLIENTSITE FAR * lplpolesite
);
Parameter

lplpoleclientsite

Pointer to the pointer variable that receives the address of the IOleClientSite interface.

Return Value

Returns success status. Use GetScode to retrieve an SCODE. Can be S_OK on success or E_OUTOFMEMORY if memory could not be allocated for the client site.

See Also

IRichEditOle


IRichEditOle::GetClipboardData [New - Windows NT]
IRichEditOle::GetClipboardData

[New - Windows NT]

Retrieves a clipboard object for a range in an edit control.

HRESULT GetClipboardData(

CHARRANGE FAR * lpchrg,
DWORD reco,
LPDATAOBJECT FAR * lplpdataobj
);
Parameters

lpchrg

Pointer to the CHARRANGE structure specifying the range to create the clipboard object for.

reco

Clipboard operation flag. Can be one of these values.

RECO_COPY	Copy to the clipboard.
RECO_CUT	Cut to the clipboard.
RECO_DRAG	Drag operation (drag and drop)
RECO_DROP	Drop operation (drag and drop).
RECO_PASTE	Paste from the clipboard.
lplpdataobj

Pointer to the DATAOBJECT structure that receives the clipboard object representing the range specified in the lpchrg parameter.

Return Value

Returns success status.

See Also

CHARRANGE, IRichEditOle


IRichEditOle::GetLinkCount [New - Windows NT]
IRichEditOle::GetLinkCount

[New - Windows NT]

Returns the number of objects in a rich edit control that are links.

LONG GetLinkCount();

Return Value

Returns the number of links.

See Also

IRichEditOle


IRichEditOle::GetObject [New - Windows NT]
IRichEditOle::GetObject

[New - Windows NT]

Returns information from a REOBJECT structure about an object in a rich edit control.

HRESULT GetObject(

LONG iob,
REOBJECT FAR * lpreobject,
DWORD dwFlags
);
Parameters

iob

Zero-based index specifying which object to return information about. If this parameter is REO_IOB_USE_CP, information about the object at the character position specified by the REOBJECT structure is returned.

lpreobject

Pointer to a REOBJECT structure that receives information about the object. The reference count of the interfaces returned in this structure has been incremented; it is the responsibility of the caller to use the Release function to decrement the count.

dwFlags

Operation flags specifying which interfaces to return in the structure. Can be a combination of these values:

REO_GETOBJ_POLEOBJ	Get OLE object interface.
REO_GETOBJ_PSTG	Get Storage interface.
REO_GETOBJ_POLESITE	Get OLE site interface.
REO_GETOBJ_NO_INTERFACES	Get no interfaces.
REO_GETOBJ_ALL_INTERFACES	Get all interfaces.
Return Value

Returns success status. Use GetScode to retrieve an SCODE. Can be S_OK on success or E_INVALIDARG if no buffer for the REOBJECT structure was given, or the iob or character position is invalid.

See Also

IRichEditOle, REOBJECT


IRichEditOle::GetObjectCount [New - Windows NT]
IRichEditOle::GetObjectCount

[New - Windows NT]

Returns the number of objects currently contained in a rich edit control.

LONG GetObjectCount();

Return Value

Returns the number of objects.

See Also

IRichEditOle


IRichEditOle::HandsOffStorage [New - Windows NT]
IRichEditOle::HandsOffStorage

[New - Windows NT]

Tells a rich edit control to release its reference to the storage interface associated with the specified object. This call does not call the object's IPersistStorage::HandsOffStorage method, the caller must do that.

HRESULT HandsOffStorage(

LONG iob
);
Parameter

iob

Index of the object whose storage is to be released. If this parameter is REO_IOB_SELECTION, the selected object's storage is to be released.

Return Value

Returns success status. Use GetScode to retrieve an SCODE. Can be S_OK on success or E_INVALIDARG if the index is invalid.

See Also

IPersistStorage::HandsOffStorage, IRichEditOle


IRichEditOle::ImportDataObject [New - Windows NT]
IRichEditOle::ImportDataObject

[New - Windows NT]

Imports a clipboard object into a rich edit control, replacing the current selection.

HRESULT ImportDataObject(

LPDATAOBJECT lpdataobj,
CLIPFORMAT cf,
HGLOBAL hMetaPict
);
Parameters

lpdataobj

Pointer to a DATAOBJECT structure specifying the clipboard object to import.

cf

Clipboard format to use or zero to use the best available format.

hMetaPict

Handle to a metafile containing the icon view of an object. Used only if the DVASPECT_ICON display aspect is required by Paste Special command.

Return Value

Returns success status.

See Also

IRichEditOle


IRichEditOle::InPlaceDeactivate [New - Windows NT]
IRichEditOle::InPlaceDeactivate

[New - Windows NT]

Tells a rich edit control to deactivate the currently active in-place object, if any.

HRESULT InPlaceDeactivate();

Return Value

Returns success status. Can use GetScode to retrieve an SCODE. Can be S_OK on success or some other value returned by OLE. No error is returned if there is no active in-place object.

See Also

IRichEditOle


IRichEditOle::InsertObject [New - Windows NT]
IRichEditOle::InsertObject

[New - Windows NT]

Inserts an object into a rich edit control.

HRESULT InsertObject(

REOBJECT FAR * lpreobject
);
Parameter

lpreobject

Pointer to a REOBJECT structure containing the object information and interfaces. The rich edit control automatically increments the reference count for the interfaces if it holds onto them, so the caller can safely release the interfaces if not needed.

Return Value

Returns success status. Use GetScode to retrieve an SCODE. Can be S_OK on success or E_OUTOFMEMORY if memory could not be allocated to insert the object.

If the cp member of the REOBJECT structure is REO_CP_SELECTION, the selection is replaced with the specified object.

See Also

IRichEditOle, REOBJECT


IRichEditOle::SaveCompleted [New - Windows NT]
IRichEditOle::SaveCompleted

[New - Windows NT]

Tells a rich edit control that the most recent save operation has been completed, and that it should hold on to a different storage for the object.

HRESULT SaveCompleted(

LONG iob,
LPSTORAGE lpstg
);
Parameters

iob

Index of the object whose storage is being specified. If this parameter is REO_IOB_SELECTION, the selected object is used.

pstg

New storage for the object. If the storage is not NULL, the rich edit control releases any storage it is currently holding for the object, and uses this new storage instead.

Return Value

Returns success status. Use GetScode to retrieve an SCODE. Can be S_OK on success or E_INVALIDARG if the index is invalid.

See Also

IRichEditOle


IRichEditOle::SetDvaspect [New - Windows NT]
IRichEditOle::SetDvaspect

[New - Windows NT]

Sets the aspect that a rich edit control uses to draw an object. This call does not change the drawing information cached in the object; this must be done by the caller. The call does cause the object to be redrawn.

HRESULT SetDvaspect(

LONG iob,
DWORD dvaspect
);
Parameters

iob

Index of the object whose aspect is to be set. If this parameter is REO_IOB_SELECTION, the aspect of the selected object is to be set.

dvaspect

Aspect to use when drawing. The values are defined by OLE.

Return Value

Returns success status. Use GetScode to retrieve an SCODE. Can be S_OK on success or E_INVALIDARG if the index is invalid.

See Also

IRichEditOle


IRichEditOle::SetHostNames [New - Windows NT]
IRichEditOle::SetHostNames

[New - Windows NT]

Sets the "host names" to be given to objects as they are inserted to a rich edit control. The host names are used in the user interface of servers to describe the container context of opened objects.

HRESULT SetHostNames(

LPCSTR lpstrContainerApp,
LPCSTR lpstrContainerObj
);
Parameters

szContainerApp

Null-terminated name of the container application.

szContainerObj

Null-terminated name of the container document or object.

Return Value

Returns success status. Use GetScode to retrieve an scode. Can be S_OK on success or E_OUTOFMEMORY if memory could not be allocated to remember the strings.

See Also

IRichEditOle


IRichEditOle::SetLinkAvailable [New - Windows NT]
IRichEditOle::SetLinkAvailable

[New - Windows NT]

Sets the value of the link available bit in the object's flags. The link available bit defaults to TRUE. It should be set to FALSE if any errors occur on the link which would indicate problems connecting to the linked object or application. When those problems are repaired, the bit should be set to TRUE again.

HRESULT SetLinkAvailable(

LONG iob,
BOOL fAvailable
);
Parameters

iob

Index of object whose bit is to be set. If this parameter is REO_IOB_SELECTION, the bit on the selected object is to be set.

fAvailable

Value to set the bit to. Can be TRUE or FALSE.

Return Value

Returns success status. Use GetScode to retrieve an SCODE. Can be S_OK on success or E_INVALIDARG if the index is invalid.

See Also

IRichEditOle


IRichEditOleCallback [New - Windows NT]
IRichEditOleCallback

[New - Windows NT]

Specifies an interface used by a rich text edit control to retrieve OLE-related information from its client. A rich edit control's client is responsible for implementing this interface and assigning it to the control by using the EM_SETOLEINTERFACE message. The IRichEditOleCallback interface has the following methods:

Methods in Vtable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments reference count.
Release	Decrements reference count.
IRichEditOleCallback Methods	Description
GetNewStorage	Provides storage for a new object pasted from the clipboard or read in from an RTF stream.
GetInPlaceContext	Provides the application and document level interfaces and information required to support in-place activation.
ShowContainerUI	Tells the application whether to display its container user interface.
QueryInsertObject	Queries the application as to whether an object should be inserted.
DeleteObject	Notification that an object is about to be deleted from a rich edit control.
QueryAcceptData	Called on a paste or drag to determine if the data pasted/dragged should be accepted.
ContextSensitiveHelp	Tells the application that it should transition into or out of context sensitive help mode.
GetClipboardData	Allows the client to supply its own clipboard object.
GetDragDropEffect	Allows the client to specify the effects of a drop operation.
GetContextMenu	Queries the application for a context menu to use on a right mouse button down event.


IRichEditOleCallback::ContextSensitiveHelp [New - Windows NT]
IRichEditOleCallback::ContextSensitiveHelp

[New - Windows NT]

Tells the application that it should transition into or out of context sensitive help mode. This member should implement the functionality described for IOleInPlaceSite::ContextSensitiveHelp (as described in the OLE documentation).

HRESULT ContextSensitiveHelp(

BOOL fEnterMode
);
Parameter

fEnterMode

TRUE if entering context sensitive help mode; otherwise, FALSE.

Return Value

Returns success status.

See Also

IRichEditOleCallback


IRichEditOleCallback::DeleteObject [New - Windows NT]
IRichEditOleCallback::DeleteObject

[New - Windows NT]

Notification that an object is about to be deleted from a rich edit control. The object is not necessarily being released when this member is called.

HRESULT DeleteObject(

LPOLEOBJECT lpoleobj
);
Parameter

lpoleobj

Pointer to the OLEOBJECT structure specifying the object that is being deleted.

Return Value

No return value.

See Also

IRichEditOleCallback


IRichEditOleCallback::GetClipboardData [New - Windows NT]
IRichEditOleCallback::GetClipboardData

[New - Windows NT]

Allows the client to supply its own clipboard object.

HRESULT GetClipboardData(

CHARRANGE FAR * lpchrg,
DWORD reco,
LPDATAOBJECT FAR * lplpdataobj
);
Parameters

lpchrg

Pointer to the CHARRANGE structure specifying the range the clipboard object is for.

reco

Clipboard operation flag. Can be one of these values.

RECO_COPY	Copy to the clipboard.
RECO_CUT	Cut to the clipboard.
RECO_DRAG	Drag operation (drag and drop)
RECO_DROP	Drop operation (drag and drop).
RECO_PASTE	Paste from the clipboard.
lplpdataobj

Pointer to the pointer variable that receives the address of the IDataObject implementation representing the range specified in the lpchrg parameter. The value of lppdataobj is ignored if an error is returned.

Return Value

Returns success status. If the SCODE of the return value is E_NOTIMPL, the rich edit control creates its own clipboard object. If the SCODE of the return value is a failure other than E_NOTIMPL the operation fails.

See Also

CHARRANGE, IDataObject, IRichEditOleCallback


IRichEditOleCallback::GetContextMenu [New - Windows NT]
IRichEditOleCallback::GetContextMenu

[New - Windows NT]

Queries the application for a context menu to use on a right mouse down.

HRESULT GetContextMenu(

WORD seltyp,
LPOLEOBJECT lpoleobj,
CHARRANGE FAR * lpchrg,
HMENU FAR * lphmenu
);
Parameters

seltype

selection type

lpoleobj

Pointer to a OLEOBJECT structure specifying the first selected OLE object if the selection contains one or more objects NULL otherwise. The caller must use AddRef to increment the object reference count if it holds onto it.

lpchrg

Pointer to a CHARRANGE structure containing the current selection.

lphmenu

Pointer to a variable containing the handle of a context menu to use. This parameter is ignored if an error is returned. A rich edit control destroys the menu when it is finished with it so the client should not.

Return Value

Returns success status.

See Also

CHARRANGE, IRichEditOleCallback


IRichEditOleCallback::GetDragDropEffect [New - Windows NT]
IRichEditOleCallback::GetDragDropEffect

[New - Windows NT]

Allows the client to specify the effects of a drop operation.

HRESULT GetDragDropEffect(

BOOL fDrag,
DWORD grfKeyState,
LPDWORD pdwEffect
);
Parameters

fDrag

TRUE if the query is for a IDropTarget::DragEnter or IDropTarget::DragOver FALSE if the query is for IDropTarget::Drop.

grfKeyState

Key state as defined by OLE.

pdwEffect

Pointer to the variable that contains the effect normally used by a rich edit control. On return, the variable is set to the effect to use.

Return Value

No return value.

See Also

IDropTarget::DragEnter, IDropTarget::DragOver, IDropTarget::Drop IRichEditOleCallback


IRichEditOleCallback::GetInPlaceContext [New - Windows NT]
IRichEditOleCallback::GetInPlaceContext

[New - Windows NT]

Provides the application and document level interfaces and information required to support in-place activation.

HRESULT GetInPlaceContext(

LPOLEINPLACEFRAME FAR * lplpFrame,
LPOLEINPLACEUIWINDOW FAR * lplpDoc,
LPOLEINPLACEFRAMEINFO lpFrameInfo
);
Parameters

lplpframe

Pointer to the pointer variable that receives the address of the IOleInPlaceFrame interface that represents the frame window of the a rich edit control client. Use the AddRef method to increment the reference count the rich edit control releases the interface when it no longer needed.

lplpDoc

Pointer to the pointer variable that receives the address of the IOleInPlaceUIWindow interface that represents the document window of the rich edit control client. An interface need not be returned if the frame and document windows are the same. Use the AddRef method to increment the reference count the rich edit control releases the interface when it no longer needed.

lpFrameInfo

Pointer to the OLEINPLACEFRAMEINFO structure that receives the accelerator information.

Return Value

Returns success status.

See Also

IOleInPlaceFrame, IRichEditOleCallback, OLEINPLACEFRAMEINFO


IRichEditOleCallback::GetNewStorage [New - Windows NT]
IRichEditOleCallback::GetNewStorage

[New - Windows NT]

Provides storage for a new object pasted from the clipboard or read in from an RTF stream.

HRESULT GetNewStorage(

LPSTORAGE FAR * lplpstg
);
Parameter

lplpstg

Address to the pointer variable that receives the address of the IStorage interface created for the new object.

Return Value

Returns success status.

This method must be implemented to allow cut/copy/paste and drag and drop of OLE objects.

See Also

IRichEditOleCallback, IStorage


IRichEditOleCallback::QueryAcceptData [New - Windows NT]
IRichEditOleCallback::QueryAcceptData

[New - Windows NT]

Called on a paste or drag to determine if the data pasted/dragged should be accepted.

HRESULT QueryAcceptData(

LPDATAOBJECT lpdataobj,
CLIPFORMAT FAR * lpcfFormat,
DWORD reco,
BOOL fReally,
HGLOBAL hMetaPict
);
Parameters

lpdataobj

Pointer to the DATAOBJECT structure specifying the data object being pasted or dragged.

lpcfFormat

Pointer to the clipboard format that will be used for the paste or drop operation. If the value pointed to by lpcfFormat is zero, the best available format will be used. If the callback changes the value pointed to by lpcfFormat, the rich edit control only uses that format and the operation will fail if the format is not available.

reco

Clipboard operation flag. Can be one of these values.

RECO_DROP	Drop operation (drag and drop).
RECO_PASTE	Paste from the clipboard.
fReally

Nonzero if the paste or drop is actually happening, zero if this is just a query, such as for EM_CANPASTE.

hMetaPict

Handle to a metafile containing the icon view of an object if DVASPECT_ICON is being imposed on a object by Paste Special.

Return Value

Returns success status. If the SCODE of the result is a failure SCODE, the rich edit control refuses the data and terminates the operation. If the SCODE of the result is S_OK, the control checks the data itself for acceptable formats. A return of a successful SCODE other than S_OK means that the callback either checked the data itself (if fReally is FALSE) or imported the data itself (if fReally is TRUE).

If the application returns a successful result other than S_OK, a rich edit control will not check the read-only state of the edit control.

See Also

IRichEditOleCallback


IRichEditOleCallback::QueryInsertObject [New - Windows NT]
IRichEditOleCallback::QueryInsertObject

[New - Windows NT]

Queries the application as to whether an object should be inserted. This member is called when pasting and when reading RTF.

HRESULT QueryInsertObject(

LPCLSID lpclsid,
LPSTORAGE lpstg,
LONG cp
);
Parameters

lpclsid

Class identifier of the object to be inserted.

lpstg

Storage containing the object.

cp

Character position at which the object will be inserted.

Return Value

Returns success status. If the SCODE of the result is not S_OK, the object is not inserted.

See Also

IRichEditOleCallback


IRichEditOleCallback::ShowContainerUI [New - Windows NT]
IRichEditOleCallback::ShowContainerUI

[New - Windows NT]

Tells the application whether to display its container user interface. The rich edit control looks ahead for doubleclicks and defers the call if appropriate (as described in the OLE documentation). Applications may defer hiding adornments until an IOleInPlaceFrame::SetBorderSpace call is received.

HRESULT ShowContainerUI(

BOOL fShow
);
Parameters

fShow

Show container UI flag. TRUE to show, FALSE otherwise.

Return Value

Returns success status.

This function is called by the OnUIActivate and OnUIDeActivate methods of the IOleInPlaceSite interface.

See Also

IRichEditOleCallback, OnUIActivate, OnUIDeActivate


IShellExtInit [New - Windows 95]
IShellExtInit

[New - Windows 95]

Designates an interface used to initialize a property sheet extension, context menu extension, or drag and drop handler.

Methods in Vtable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments reference count.
Release	Decrements reference count.
IShellExtInit Method	Description
Initialize	Initializes the shell extension.


IShellExtInit::Initialize [New - Windows 95]
IShellExtInit::Initialize  QuickInfo

[New - Windows 95]

Initializes a property sheet extension, context menu extension, or drag and drop handler.

HRESULT STDMETHODCALLTYPE Initialize(

LPSHELLEXTINIT pIface,
LPCITEMIDLIST pidlFolder,
LPDATAOBJECT lpdobj,
HKEY hkeyProgID
);
Parameters

pIface

Pointer to the IShellExtInit interface. In C++, this parameter is implicit.

pidlFolder

Pointer to an structure ITEMIDLIST (item identifier list) that uniquely identifies a folder. This parameter is NULL for property sheet extensions and context menu extensions. For non-default drag and drop menu extensions, this parameter must specify the target folder.

lpdobj

Pointer to an IDataObject interface object that can be used to retrieve the objects being acted upon.

hkeyProgID

Registry key for the file object or folder type.

Return Value

Returns NOERROR if successful or an OLE-defined error value otherwise.

This is the first method that the shell calls after it creates an instance of a property sheet extension, context menu extension, or drag and drop handler.

The meanings of some parameters depend on the extension type. For drag and drop handlers, the item identifier list specifies the destination folder (the drop target), the IDataObject interface identifies the items being dropped, and the registry key specifies the file class of the destination folder.

For property sheet extensions and context menu extensions, the item identifier list specifies the folder that contains the selected file objects, the IDataObject interface identifies the selected file objects, and the registry key specifies the file class of the file object that has the focus.

See Also

IShellExtInit, ITEMIDLIST


IShellFolder [New - Windows 95]
IShellFolder

[New - Windows 95]

Designates an interface implemented by the shell and used to determine the contents of a folder.

Methods in Vtable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments reference count.
Release	Decrements reference count.
IShellFolder Methods	Description
ParseDisplayName	Translates a display name into an item identifier list.
EnumObjects	Enumerates the objects in the folder.
BindToObject	Retrieves the IShellFolder interface for the specified subfolder.
BindToStorage	Reserved; this function is not currently implemented.
CompareIDs	Compares two item identifier lists and returns the result.
CreateViewObject	Reserved for use by the shell; do not use.
GetAttributesOf	Retrieves the attributes of the specified file object or subfolder.
GetUIObjectOf	Creates an OLE interface that can be used to carry out operations on a file object or subfolder.
GetDisplayNameOf	Retreives the display name of a file object or subfolder.
SetNameOf	Sets the display name of the specified file object or subfolder and changes its identifier accordingly.


IShellFolder::BindToObject [New - Windows 95]
IShellFolder::BindToObject  QuickInfo

[New - Windows 95]

Creates an IShellFolder object for a subfolder.

HRESULT STDMETHODCALLTYPE BindToObject(

LPSHELLFOLDER pIface,
LPCITEMIDLIST pidl,
LPBC pbcReserved,
REFIID riid,
LPVOID *ppvOut
);
Parameters

pIface

Pointer to the IShellFolder interface. In C++, this parameter is implicit.

pidl

Pointer to an ITEMIDLIST structure that identifies the subfolder relative to its parent folder.

pbcReserved

Reserved; applications should specify NULL for this parameter.

riid

Identifier of the interface to return. This parameter must point to the IID_IShellFolder interface identifier.

ppvOut

Address that receives the interface pointer. If an error occurs, a NULL pointer is returned in this address.

Return Value

Returns NOERROR if successful or an OLE-defined error value otherwise.

See Also

IShellFolder, ITEMIDLIST


IShellFolder::BindToStorage [New - Windows 95]
IShellFolder::BindToStorage  QuickInfo

[New - Windows 95]

This method is reserved for future use and is not currently implemented.


IShellFolder::CompareIDs [New - Windows 95]
IShellFolder::CompareIDs  QuickInfo

[New - Windows 95]

Determines the relative ordering of two file objects or folders, given their item identifier lists.

HRESULT STDMETHODCALLTYPE CompareIDs(

LPSHELLFOLDER pIface,
LPARAM lParam,
LPCITEMIDLIST pidl1,
LPCITEMIDLIST pidl2
);
Parameters

pIface

Pointer to the IShellFolder interface. In C++, this parameter is implicit.

lParam

Value specifying the type of comparison to perform. The calling application should always specify zero, indicating that the two items should be sorted by name.

pidl1 and pidl2

Addresses of two ITEMIDLIST structures that uniquely identify the items to be compared. Both item identifier lists are relative to the parent folder.

Return Value

Returns a handle to a result code. If this method is successful, the CODE field of the status code (SCODE) has the following meaning:

CODE field	Meaning
Less than zero	The first item should precede the second (pidl1 < pidl2).
Greater than zero	The first item should follow the second (pidl1 > pidl2)
Zero	The two items are the same (pidl1 = pidl2).
See Also

IShellFolder, ITEMIDLIST


IShellFolder::CreateViewObject [New - Windows 95]
IShellFolder::CreateViewObject  QuickInfo

[New - Windows 95]

This method is reserved for use by the shell and should not be called by applications.


IShellFolder::EnumObjects [New - Windows 95]
IShellFolder::EnumObjects  QuickInfo

[New - Windows 95]

Creates an item enumeration object (an IEnumIDList interface) that can be used to enumerate the contents of a folder.

HRESULT STDMETHODCALLTYPE EnumObjects(

LPSHELLFOLDER pIface,
HWND hwndOwner,
DWORD grfFlags,
LPENUMIDLIST *ppenumIDList
);
Parameters

pIface

Pointer to the IShellFolder interface. In C++, this parameter is implicit.

hwndOwner

Handle of the owner window that the client should specify if it displays a dialog box or message box.

grfFlags

Flags determining which items to enclude in the enumeration. For a list of possible values, see the description of the SHCONTF type.

ppenumIDList

Address that receives a pointer to the IEnumIDList interface created by this method. If an error occurs, a NULL pointer is returned in this address.

Return Value

Returns NOERROR if successful or an OLE-defined error value otherwise.

Remarks

The calling application must free the returned IEnumIDList object by calling its Release method.

This method is similar to the IOleContainer::EnumObjects method defined by OLE.

See Also

IEnumIDList, IShellFolder


IShellFolder::GetAttributesOf [New - Windows 95]
IShellFolder::GetAttributesOf  QuickInfo

[New - Windows 95]

Retrieves the attributes of one or more file objects or subfolders.

HRESULT STDMETHODCALLTYPE GetAttributesOf(

LPSHELLFOLDER pIface,
UINT cidl,
LPCITEMIDLIST *apidl,
ULONG *rgfInOut
);
Parameters

pIface

Pointer to the IShellFolder interface. In C++, this parameter is implicit.

cidl

Number of file objects to get the attributes of.

apidl

Pointer to an array of pointers to ITEMIDLIST structures, each of which uniquely identifies a file object relative to the parent folder. Each ITEMIDLIST structure must contain exactly one SHITEMID structure followed by a terminating zero.

rgfInOut

Address of an array of values that specify file object attributes. The calling application should initialize each array element by specifying which file object attributes to retrieve.

Return Value

Returns NOERROR if successful or an OLE-defined error value otherwise.

This method returns the actual attributes of each file object in the corresponding array element; it may return all attributes or just the requested attributes.

The following tables list the attribute flags that may be returned by this method. File object attributes include capability flags, display attributes, contents flags, and miscellaneous attributes.

A file object's capability flags may include zero or more of the following values:

SFGAO_CANCOPY	The specified file objects or folders can be copied (same value as the DROPEFFECT_COPY flag).
SFGAO_CANDELETE	The specified file objects or folders can be deleted.
SFGAO_CANLINK	It is possible to create shortcuts for the specified file objects or folders (same value as the DROPEFFECT_LINK flag).
SFGAO_CANMOVE	The specified file objects or folders can be moved (same value as the DROPEFFECT_MOVE flag).
SFGAO_CANRENAME	The specified file objects or folders can be renamed.
SFGAO_CAPABILITYMASK	Mask for the capability flags.
SFGAO_DROPTARGET	The specified file objects or folders are drop targets.
SFGAO_HASPROPSHEET	The specified file objects or folders have property sheets.
A file object's display attributes may include zero or more of the following values:

SFGAO_DISPLAYATTRMASK	Mask for the display attributes.
SFGAO_GHOSTED	The specified file objects or folders should be displayed using a ghosted icon.
SFGAO_LINK	The specified file objects are shortcuts.
SFGAO_READONLY	The specified file objects or folders are read-only.
SFGAO_SHARE	The specified folders are shared.
A file object's contents flags may include zero or more of the following values:

SFGAO_CONTENTSMASK	Mask for the contents attributes.
SFGAO_HASSUBFOLDER	The specified folders have subfolders (and are, therefore, expandable in the left pane of Windows Explorer).
A file object may have zero or more of the following miscellaneous attributes:

SFGAO_FILESYSTEM	The specified folders or file objects are part of the file system (that is, they are files, directories, or root directories).
SFGAO_FILESYSANCESTOR	The specified folders contain one or more file system folders.
SFGAO_FOLDER	The specified items are folders.
SFGAO_REMOVABLE	The specified file objects or folders are on removable media.
SFGAO_VALIDATE	Validate cached information.
See Also

IShellFolder, ITEMIDLIST, SHITEMID


IShellFolder::GetDisplayNameOf [New - Windows 95]
IShellFolder::GetDisplayNameOf  QuickInfo

[New - Windows 95]

Retrieves the display name for the specified file object or subfolder.

HRESULT STDMETHODCALLTYPE GetDisplayNameOf(

LPSHELLFOLDER pIface,
LPCITEMIDLIST pidl,
DWORD uFlags,
LPSTRRET lpName
);
Parameters

pIface

Pointer to the IShellFolder interface. In C++, this parameter is implicit.

pidl

Pointer to an ITEMIDLIST structure that uniquely identifes the file object or subfolder relative to the parent folder.

uFlags

Value indicating the type of display name to return. For a list of possible values, see the description of the SHGNO enumerated type.

lpName

Pointer to a STRRET structure in which to return the display name. The string returned in this structure depends on the type of display name requested.

Return Value

Returns NOERROR if successful or an OLE-defined error value otherwise.

See Also

IShellFolder, ITEMIDLIST, STRRET


IShellFolder::GetUIObjectOf [New - Windows 95]
IShellFolder::GetUIObjectOf  QuickInfo

[New - Windows 95]

Returns an interface that can be used to carry out actions on the specified file objects or folders — typically, to create context menus or carry out drag and drop operations.

HRESULT STDMETHODCALLTYPE GetUIObjectOf(

LPSHELLFOLDER pIface,
HWND hwndOwner,
UINT cidl,
LPCITEMIDLIST *apidl,
REFIID riid,
UINT *prgfReserved,
LPVOID *ppvOut
);
Parameters

pIface

Pointer to the IShellFolder interface. In C++, this parameter is implicit.

hwndOwner

Handle of the owner window that the client should specify if it displays a dialog box or message box.

cidl

Number of file objects or subfolders specified by apidl.

apidl

Pointer to an array of pointers to ITEMIDLIST structures, each of which uniquely identifies a file object or subfolder relative to the parent folder. Each item identifier list must contain exactly one SHITEMID structure followed by a terminating zero.

riid

Identifier of the interface to return. This parameter can be a pointer to the IID_IExtractIcon, IID_IContextMenu, IID_IDataObject, or IID_IDropTarget interface identifier.

prgfReserved

Reserved for future versions of Windows; must be NULL.

ppvOut

Address that receives the interface pointer. If an error occurs, a NULL pointer is returned in this address.

Return Value

Returns NOERROR if successful or an OLE-defined error value otherwise.

See Also

IShellFolder, ITEMIDLIST, SHITEMID


IShellFolder::ParseDisplayName [New - Windows 95]
IShellFolder::ParseDisplayName  QuickInfo

[New - Windows 95]

Translates a file object or folder's display name into an item identifier.

HRESULT STDMETHODCALLTYPE IShellFolder::ParseDisplayName(

LPSHELLFOLDER pIface,
WND hwndOwner,
LPBC pbcReserved,
LPWSTR lpwszDisplayName,
ULONG *pchEaten,
LPITEMIDLIST *ppidl,
ULONG *pdwAttributes
);
Parameters

pIface

Pointer to the IShellFolder interface. In C++, this parameter is implicit.

hwndOwner

Handle of the owner window that the client should specify if it displays a dialog box or message box.

pbcReserved

Reserved; this parameter is always NULL.

lpwszDisplayName

Pointer to a null-terminated Unicode string specifying the display name. This parameter must be a display name for parsing — that is, a display name retrieved using the SHGDN_FORPARSING value.

pchEaten

Pointer to an unsigned long value that receives the number of characters of the display name that were parsed.

ppidl

Address that receives a pointer to the new item identifier list for the object. If an error occurs, a NULL is returned in this address.

The returned item identifier list specifies the relative path (from the parent folder) that corresponds to the specified display name. It contains only one SHITEMID structure followed by a terminating zero.

pdwAttributes

Address that receives the attributes of the file object.

Return Value

Returns NOERROR if successful or an OLE-defined error value otherwise.

Remarks

This method is similar to the 	IParseDisplayName::ParseDisplayName method defined by OLE.

See Also

IParseDisplayName::ParseDisplayName, IShellFolder, IShellLink, SHITEMID


IShellFolder::SetNameOf [New - Windows 95]
IShellFolder::SetNameOf  QuickInfo

[New - Windows 95]

Changes the name of a file object or subfolder, changing its item identifier in the process.

HRESULT STDMETHODCALLTYPE SetNameOf(

LPSHELLFOLDER pIface,
HWND hwndOwner,
LPCITEMIDLIST pidl,
LPCOLESTR lpszName,
DWORD uFlags,
LPITEMIDLIST *ppidlOut
);
Parameters

pIface

Pointer to the IShellFolder interface. In C++, this parameter is implicit.

hwndOwner

Handle of the owner window that the client should specify if it displays a dialog box or message box.

pidl

Pointer to an ITEMIDLIST structure that uniquely identifies the file object or subfolder relative to the parent folder.

lpszName

Pointer to a null-terminated string that specifies the new display name.

uFlags

Value indicating the type of name specified by the lpszName parameter. For a list of possible values, see the description of the SHCONTF enumerated type.

ppidlOut

Address in which the method returns a pointer to the new ITEMIDLIST structure. This parameter can be NULL, and in that case, the method does not return the new ITEMIDLIST for the object.

If this parameter is not NULL, this method frees the specified ITEMIDLIST structure and allocates a new one using the task allocator. The calling application is responsible for freeing the new ITEMIDLIST structure. If an error occurs, the method returns NULL in this address.

Return Value

Returns NOERROR if successful or an OLE-defined error value otherwise.

See Also

IShellFolder, ITEMIDLIST


IShellLink [New - Windows 95]
IShellLink

[New - Windows 95]

Designates an interface that allows an application to create and resolve shell links.

Methods in Vtable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments reference count.
Release	Decrements reference count.
IShellLink Methods	Description
GetArguments	Retrieves the command-line arguments associated with a shell link object.
GetDescription	Retrieves the description string for a shell link object.
GetHotkey	Retrieves the hot key for a shell link object.
GetIconLocation	Retrieves the location (path and index) of the icon for a shell link object.
GetIDList	Retrieves the list of item identifiers for a shell link object.
GetPath	Retrieves the path and filename of a shell link object.
GetShowCmd	Retrieves the show (SW_) command for a shell link object.
GetWorkingDirectory	Retrieves the name of the working directory for a shell link object.
Resolve	Resolves a shell link by searching for the shell link object and updating the shell link path and its list of identifiers (if necessary).
SetArguments	Sets the command-line arguments associated with a shell link object.
SetDescription	Sets the description string for a shell link object.
SetHotkey	Sets the hot key for a shell link object.
SetIconLocation	Sets the location (path and index) of the icon for a shell link object.
SetIDList	Sets the list of item identifiers for a shell link object.
SetPath	Sets the path and filename of a shell link object.
SetRelativePath	Sets the relative path for a shell link object.
SetShowCmd	Sets the show (SW_) command for a shell link object.
SetWorkingDirectory	Sets the name of the working directory for a shell link object.


IShellLink::GetArguments [New - Windows 95]
IShellLink::GetArguments  QuickInfo

[New - Windows 95]

Retrieves the command-line arguments associated with a shell link object.

HRESULT STDMETHODCALLTYPE GetArguments(

ISHELLLINK FAR * pShlLnk,
LPSTR pszArgs,
int cchMaxPath
);
Parameters

pShlLnk

Pointer to the IShellLink interface. In C++, this parameter is implicit.

pszArgs

Pointer to a buffer that receives the command-line arguments.

cchMaxPath

Maximum number of characters to copy to the buffer pointed to by pszArgs.

Return Value

Returns NOERROR if successful or an OLE-defined error value otherwise.

See Also

IShellLink


IShellLink::GetDescription [New - Windows 95]
IShellLink::GetDescription  QuickInfo

[New - Windows 95]

Retrieves the description string for a shell link object.

RESULT STDMETHODCALLTYPE GetDescription(

ISHELLLINK FAR * pShlLnk,
LPSTR pszName,
int cchMaxName
);
Parameters

pShlLnk

Pointer to the IShellLink interface. In C++, this parameter is implicit.

pszName

Pointer to a buffer that receives the description string.

cchMaxName

Maximum number of characters to copy to the buffer pointed to by pszName.

Return Value

Returns NOERROR if successful or an OLE-defined error value otherwise.

See Also

IShellLink


IShellLink::GetHotkey [New - Windows 95]
IShellLink::GetHotkey  QuickInfo

[New - Windows 95]

Retrieves the hot key for a shell link object.

HRESULT STDMETHODCALLTYPE GetHotkey(

ISHELLLINK FAR * pShlLnk,
WORD *pwHotkey
);
Parameters

pShlLnk

Pointer to the IShellLink interface. In C++, this parameter is implicit.

pwHotkey

Pointer to the hot key. The virtual-key code is in the low-order byte, and the modifier flags are in the high-order byte. The modifier flags can be a combination of the following values:

HOTKEYF_ALT	ALT key
HOTKEYF_CONTROL	CTRL key
HOTKEYF_EXT	Extended key
HOTKEYF_SHIFT	SHIFT key
Return Value

Returns NOERROR if successful or an OLE-defined error value otherwise.

See Also

IShellLink


IShellLink::GetIconLocation [New - Windows 95]
IShellLink::GetIconLocation  QuickInfo

[New - Windows 95]

Retrieves the location (path and index) of the icon for a shell link object.

HRESULT STDMETHODCALLTYPE GetIconLocation(

ISHELLLINK FAR * pShlLnk,
LPSTR pszIconPath,
int cchIconPath,
int *piIcon
);
Parameters

pShlLnk

Pointer to the IShellLink interface. In C++, this parameter is implicit.

pszIconPath

Pointer to a buffer that receives the path of the file containing the icon.

cchIconPath

Maximum number of characters to copy to the buffer pointed to by pszIconPath.

piIcon

Pointer to a value that receives the index of the icon.

Return Value

Returns NOERROR if successful or an OLE-defined error value otherwise.

See Also

IShellLink


IShellLink::GetIDList [New - Windows 95]
IShellLink::GetIDList  QuickInfo

[New - Windows 95]

Retrieves the list of item identifiers for a shell link object.

HRESULT STDMETHODCALLTYPE GetIDList(

ISHELLLINK FAR * pShlLnk,
LPITEMIDLIST * ppidl
);
Parameters

pShlLnk

Pointer to the IShellLink interface. In C++, this parameter is implicit.

ppidl

Pointer to a pointer to a list of item identifiers.

Return Value

Returns NOERROR if successful or an OLE-defined error value otherwise.

See Also

IShellLink


IShellLink::GetPath [New - Windows 95]
IShellLink::GetPath  QuickInfo

[New - Windows 95]

Retrieves the path and filename of a shell link object.

HRESULT STDMETHODCALLTYPE GetPath(

IShellLink FAR * pShlLnk,
LPSTR pszFile,
int cchMaxPath,
WIN32_FIND_DATA *pfd,
DWORD fFlags
);
Parameters

pShlLnk

Pointer to the IShellLink interface. In C++, this parameter is implicit.

pszFile

Pointer to a buffer that receives the path and filename of the shell link object.

cchMaxPath

Maximum number of bytes to copy to the buffer pointed to by pszFile.

pfd

Pointer to a WIN32_FIND_DATA structure that contains information about the shell link object.

fFlags

Flags that specify the type of path information to retrieve. This parameter can be a combination of the following values:

SLGP_SHORTPATH	Retrieves the standard short (8.3) filename.
SLGP_UNCPRIORITY	Retrieves the Universal Naming Convention (UNC) path name of the file.
Return Value

Returns NOERROR if successful or an OLE-defined error value otherwise.

See Also

IShellLink, WIN32_FIND_DATA


IShellLink::GetShowCmd [New - Windows 95]
IShellLink::GetShowCmd  QuickInfo

[New - Windows 95]

Retrieves the show command for a shell link object.

HRESULT STDMETHODCALLTYPE GetShowCmd(

ISHELLLINK FAR * pShlLnk,
int *piShowCmd
);
Parameters

pShlLnk

Pointer to the IShellLink interface. In C++, this parameter is implicit.

piShowCmd

Pointer to the show command. For a list of show commands, see the description of the ShowWindow function.

Return Value

Returns NOERROR if successful or an OLE-defined error value otherwise.

See Also

IShellLink, ShowWindow


IShellLink::GetWorkingDirectory [New - Windows 95]
IShellLink::GetWorkingDirectory  QuickInfo

[New - Windows 95]

Retrieves the name of the working directory for a shell link object.

HRESULT STDMETHODCALLTYPE GetWorkingDirectory(

ISHELLLINK FAR * pShlLnk,
LPSTR pszDir,
int cchMaxPath
);
Parameters

pShlLnk

Pointer to the IShellLink interface. In C++, this parameter is implicit.

pszDir

Pointer to a buffer that receives the name of the working directory.

cchMaxPath

Maximum number of characters to copy to the buffer pointed to by pszDir. The name of the working directory is truncated if it is longer than the maximum specified by this parameter.

Return Value

Returns NOERROR if successful or an OLE-defined error value otherwise.

See Also

IShellLink


IShellLink::Resolve [New - Windows 95]
IShellLink::Resolve  QuickInfo

[New - Windows 95]

Resolves a shell link. The system searches for the shell link object and updates the shell link path and its list of identifiers (if necessary).

HRESULT STDMETHODCALLTYPE Resolve(

ISHELLLINK FAR * pShlLnk,
HWND hwnd,
DWORD fFlags
);
Parameters

pShlLnk

Pointer to the IShellLink interface. In C++, this parameter is implicit.

hwnd

Handle of a window that the shell uses as the parent window for a dialog box. The shell displays the dialog box if it needs to prompt the user for more information while resolving a shell link.

fFlags

Action flags. This parameter can be a combination of the following values:

SLR_ANY_MATCH	Resolves the link, displaying a dialog box if the system needs information from the user.
SLR_NO_UI	Prevents the shell from displaying a dialog box if it cannot resolve the shell link. When this flag is specified, the high-order word of fFlags specifies a timeout duration, in milliseconds. The function returns if the link cannot be resolved within the timeout duration. If the high-order word is set to zero, the timeout duration defaults to 3000 milliseconds (3 seconds).
SLR_UPDATE	Directs the shell to update the path to the link and the list of identifiers if the link object has been changed. If this value is used, it is not necessary to call the IPersistFile::IsDirty method to determine whether the link object has changed.
Return Value

Returns NOERROR if successful or an OLE-defined error value otherwise.

Remarks

When this method is called, the system retrieves the path associated with the current link object and searches for the object in that path. If the system finds the object, it resolves the link. If the system cannot find the object, it looks in the same directory for an object with the same file creation time and attributes, but with a different name. This type of search resolves a link to an object that has been renamed.

If the system still cannot find the link object, it searches the subdirectories of the current directory. It does a recursive search of the directory tree looking for a match with either the same name or creation time. If it does not find a match after that, the shell displays a dialog box prompting the user for a location. An application can suppress the dialog box by specifying the SLR_NO_UI value in a call to this method.

See Also

IShellLink


IShellLink::SetArguments [New - Windows 95]
IShellLink::SetArguments  QuickInfo

[New - Windows 95]

Sets the command-line arguments for a shell link object.

HRESULT STDMETHODCALLTYPE SetArguments(

ISHELLLINK FAR * pShlLnk,
LPCSTR pszArgs
);
Parameters

pShlLnk

Pointer to the IShellLink interface. In C++, this parameter is implicit.

pszArgs

Pointer to a buffer that contains the new command-line arguments.

Return Value

Returns NOERROR if successful or an OLE-defined error value otherwise.

This method is useful when creating a link to an application that takes special flags as arguments, such as a compiler.

See Also

IShellLink


IShellLink::SetDescription [New - Windows 95]
IShellLink::SetDescription  QuickInfo

[New - Windows 95]

Sets the description for a shell link object. The description can be any application-defined string.

HRESULT STDMETHODCALLTYPE SetDescription(

ISHELLLINK FAR * pShlLnk,
LPCSTR pszName
);
Parameters

pShlLnk

Pointer to the IShellLink interface. In C++, this parameter is implicit.

pszName

Pointer to a buffer containing the new description string.

Return Value

Returns NOERROR if successful or an OLE-defined error value otherwise.

See Also

IShellLink


IShellLink::SetHotkey [New - Windows 95]
IShellLink::SetHotkey  QuickInfo

[New - Windows 95]

Sets a hot key for a shell link object.

HRESULT STDMETHODCALLTYPE SetHotkey(

ISHELLLINK FAR * pShlLnk,
WORD wHotkey
);
Parameters

pShlLnk

Pointer to the IShellLink interface. In C++, this parameter is implicit.

wHotkey

Hot key. The virtual-key code is in the low-order byte, and the modifier flags are in the high-order byte. The modifier flags can be a combination of the values specified in the description of the IShellLink::GetHotkey method.

Return Value

Returns NOERROR if successful or an OLE-defined error value otherwise.

Setting a hot key allows the user to activate the object by pressing a particular combination of keys.

See Also

IShellLink, IShellLink::GetHotkey


IShellLink::SetIconLocation [New - Windows 95]
IShellLink::SetIconLocation  QuickInfo

[New - Windows 95]

Sets the location (path and index) of the icon for a shell link object.

HRESULT STDMETHODCALLTYPE SetIconLocation(

ISHELLLINK FAR * pShlLnk,
LPCSTR pszIconPath,
int iIcon
);
Parameters

pShlLnk

Pointer to the IShellLink interface. In C++, this parameter is implicit.

pszIconPath

Pointer to a buffer that contains the path of the file containing the icon.

iIcon

Index of the icon.

Return Value

Returns NOERROR if successful or an OLE-defined error value otherwise.

See Also

IShellLink


IShellLink::SetIDList [New - Windows 95]
IShellLink::SetIDList  QuickInfo

[New - Windows 95]

Sets the list of item identifiers for a shell link object.

HRESULT STDMETHODCALLTYPE SetIDList(

ISHELLLINK FAR * pShlLnk,
LPCITEMIDLIST pidl
);
Parameters

pShlLnk

Pointer to the IShellLink interface. In C++, this parameter is implicit.

pidl

Pointer to a list of item identifiers.

Return Value

Returns NOERROR if successful or an OLE-defined error value otherwise.

This method is useful when an application needs to set a shell link to an object that is not a file, such as a Control Panel application, a printer, or another computer.

See Also

IShellLink


IShellLink::SetPath [New - Windows 95]
IShellLink::SetPath  QuickInfo

[New - Windows 95]

Sets the path and filename of a shell link object.

HRESULT STDMETHODCALLTYPE SetPath(

ISHELLLINK FAR * pShlLnk,
LPCSTR pszFile
);
Parameters

pShlLnk

Pointer to the IShellLink interface. In C++, this parameter is implicit.

pszFile

Pointer to a buffer that contains the new path.

Return Value

Returns NOERROR if successful or an OLE-defined error value otherwise.

See Also

IShellLink


IShellLink::SetRelativePath [New - Windows 95]
IShellLink::SetRelativePath  QuickInfo

[New - Windows 95]

Sets the relative path to the shell link object.

HRESULT STDMETHODCALLTYPE SetRelativePath(

ISHELLLINK FAR * pShlLnk,
LPCSTR pszPathRel,
LPCITEMIDLIST pidlRel
);
Parameters

pShlLnk

Pointer to the IShellLink interface. In C++, this parameter is implicit.

pszPathRel

Pointer to a buffer that contains the new relative path.

pidlRel

Pointer to a list of item identifiers that identify the object.

Return Value

Returns NOERROR if successful or an OLE-defined error value otherwise.

See Also

IShellLink


IShellLink::SetShowCmd [New - Windows 95]
IShellLink::SetShowCmd  QuickInfo

[New - Windows 95]

Sets the show command for a shell link object. The show command sets the initial show state of the window.

HRESULT STDMETHODCALLTYPE SetShowCmd(

ISHELLLINK FAR * pShlLnk,
int iShowCmd
);
Parameters

pShlLnk

Pointer to the IShellLink interface. In C++, this parameter is implicit.

iShowCmd

Show command. For a list of the show commands, see the description of the ShowWindow function.

Return Value

Returns NOERROR if successful or an OLE-defined error value otherwise.

See Also

IShellLink, ShowWindow


IShellLink::SetWorkingDirectory [New - Windows 95]
IShellLink::SetWorkingDirectory  QuickInfo

[New - Windows 95]

Sets the name of the working directory for a shell link object.

HRESULT STDMETHODCALLTYPE SetWorkingDirectory(

ISHELLLINK FAR * pShlLnk,
LPCSTR pszDir
);
Parameters

pShlLnk

Pointer to the IShellLink interface. In C++, this parameter is implicit.

pszDir

Pointer to a buffer that contains the name of the new working directory.

Return Value

Returns NOERROR if successful or an OLE-defined error value otherwise.

The working directory must be set only if the object requires it to be set. For example, if an application creates a shell link to a Microsoft Word document that uses a template that resides in a different directory, the application would use this method to set the working directory.

See Also

IShellLink


IShellPropSheetExt [New - Windows 95]
IShellPropSheetExt

[New - Windows 95]

Designates an interface that allows a property sheet handler to add or replace pages in the property sheet for a file object.

Methods in Vtable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments reference count.
Release	Decrements reference count.
i

IShellPropSheetExt Methods	Description
AddPages	Adds one or more pages to a property sheet for a file object.
ReplacePage	Replaces a page in a property sheet for a control panel object.


IShellPropSheetExt::AddPages [New - Windows 95]
IShellPropSheetExt::AddPages  QuickInfo

[New - Windows 95]

Adds one or more pages to a property sheet that the shell displays for a file object. When it is about to display the property sheet, the shell calls the AddPages method of each property sheet handler registered to the file type.

HRESULT STDMETHODCALLTYPE AddPages(

IShellPropSheetExt FAR * pProp,
LPFNADDPROPSHEETPAGE lpfnAddPage,
LPARAM lParam
);
Parameters

pProp

Pointer to the IShellPropSheetExt interface. In C++, this parameter is implicit.

lpfnAddPage

Pointer to a function that the property sheet handler calls to add a page to the property sheet. The function takes a property sheet handle returned by the CreatePropertySheetPage function and the lParam parameter passed to the AddPages method.

lParam

Parameter to pass to the function specified by lpfnAddPage.

Return Value

Returns NOERROR if successful or an OLE-defined error value otherwise.

For each page it needs to add to a property sheet, a property sheet handler fills a PROPSHEETPAGE structure, calls CreatePropertySheetPage, and then calls the function specified by lpfnAddPage.

See Also

CreatePropertySheetPage, IShellPropSheetExt, PROPSHEETPAGE


IShellPropSheetExt::ReplacePage [New - Windows 95]
IShellPropSheetExt::ReplacePage  QuickInfo

[New - Windows 95]

Replaces a page in a property sheet for a control panel object.

HRESULT STDMETHODCALLTYPE ReplacePage(

IShellPropSheetExt FAR * pProp,
UINT uPageID,
LPFNADDPROPSHEETPAGE lpfnReplacePage,
LPARAM lParam
);
Parameters

pProp

Pointer to the IShellPropSheetExt interface. In C++, this parameter is implicit.

uPageID

Identifier of the page to replace. The values for this parameter for control panels can be found in the CPLEXT.H header file.

lpfnReplacePage

Pointer to a function that the property sheet handler calls to replace a page to the property sheet. The function takes a property sheet handle returned by the CreatePropertySheetPage function and the lParam parameter passed to the ReplacePage method.

lParam

Parameter to pass to the function specified by lpfnReplacePage.

Return Value

Returns NOERROR if successful or an OLE-defined error value otherwise.

To replace a page, a property sheet handler fills a PROPSHEETPAGE structure, calls CreatePropertySheetPage, and then calls the function specified by lpfnReplacePage.

See Also

CreatePropertySheetPage, IShellPropSheetExt, PROPSHEETPAGE


ABM_ACTIVATE
ABM_ACTIVATE  QuickInfo

SHAppBarMessage(ABM_ACTIVATE, pabd);

Notifies the system that an appbar has been activated. An appbar should call this message in response to the WM_ACTIVATE message.

Parameter

pabd

Pointer to an APPBARDATA structure that identifies the appbar to activate. You must specify the cbSize and hWnd members when sending this message; all other members are ignored.

Return Value

Always returns TRUE.

Remarks

This message is ignored if the hWnd member of the structure pointed to by pabd identifies an autohide appbar. The system automatically sets the Z order for an autohide appbar.

See Also

APPBARDATA


ABM_GETAUTOHIDEBAR
ABM_GETAUTOHIDEBAR  QuickInfo

hwndAutoHide = (HWND) SHAppBarMessage(ABM_GETAUTOHIDEBAR, pabd);

Retrieves the handle of the autohide appbar associated with an edge of the screen.

Parameter

pabd

Pointer to an APPBARDATA structure that specifies the screen edge. You must specify the cbSize, hWnd, and uEdge members when sending this message; all other members are ignored.

Return Value

Returns the handle of the autohide appbar. The return value is NULL if an error occurs or if no autohide appbar is associated with the given edge.

See Also

APPBARDATA


ABM_GETSTATE
ABM_GETSTATE  QuickInfo

fuState = (UINT) SHAppBarMessage(ABM_GETSTATE, pabd);

Retrieves the autohide and always-on-top states of the Windows taskbar.

Parameter

pabd

Pointer to an APPBARDATA structure. You must specify the cbSize and hWnd members when sending this message; all other members are ignored.

Return Value

Returns zero if the taskbar is not in the autohide or always-on-top state. Otherwise, the return value is one or both of the following values:

ABS_ALWAYSONTOP	The taskbar is in the always-on-top state.
ABS_AUTOHIDE	The taskbar is in the autohide state.
See Also

APPBARDATA


ABM_GETTASKBARPOS
ABM_GETTASKBARPOS  QuickInfo

fResult = (BOOL) SHAppBarMessage(ABM_GETTASKBARPOS, pabd);

Retrieves the bounding rectangle of the Windows taskbar.

Parameter

pabd

Pointer to an APPBARDATA structure whose rc member receives the bounding rectangle, in screen coordinates, of the taskbar. You must specify the cbSize and hWnd when sending this message; all other members are ignored.

Return Value

Returns TRUE if successful or FALSE otherwise.

See Also

APPBARDATA


ABM_NEW
ABM_NEW  QuickInfo

fRegistered = (BOOL) SHAppBarMessage(ABM_NEW, pabd);

Registers a new appbar and specifies the message identifier that the system should use to send notification messages to the appbar. An appbar should send this message before sending any other appbar messages.

Parameter

pabd

Pointer to an APPBARDATA structure that contains the new appbar's window handle and message identifier. You must specify the cbSize, hWnd, and uCallbackMessage members when sending this message; all other members are ignored.

Return Value

Returns TRUE if successful or FALSE if an error occurs or the appbar is already registered.

See Also

APPBARDATA


ABM_QUERYPOS
ABM_QUERYPOS  QuickInfo

SHAppBarMessage(ABM_QUERYPOS, pabd);

Requests a size and screen position for an appbar. The message proposes a screen edge and a bounding rectangle for the appbar. The system adjusts the bounding rectangle so that the appbar does not interfere with the Windows taskbar or any other appbars. An appbar should send this message before sending the ABM_SETPOS message.

Parameter

pabd

Pointer to an APPBARDATA structure. The uEdge member specifies a screen edge, and the rc member contains the proposed bounding rectangle. When the SHAppBarMessage function returns, rc contains the approved bounding rectangle. You must specify the cbSize, hWnd, uEdge, and rc members when sending this message; all other members are ignored.

Return Value

Always returns TRUE.

See Also

APPBARDATA


ABM_REMOVE
ABM_REMOVE  QuickInfo

SHAppBarMessage(ABM_REMOVE, pabd);

Unregisters an appbar, removing it from the system's internal list. The system no longer sends notification messages to the appbar nor prevents other applications from using the screen area occupied by the appbar.

Parameter

pabd

Pointer to an APPBARDATA structure that contains the handle of the appbar to unregister. You must specify the cbSize and hWnd members when sending this message; all other members are ignored.

Return Value

Always returns TRUE.

This message causes the system to send the ABN_POSCHANGED notification message to all appbars.

See Also

APPBARDATA


ABM_SETAUTOHIDEBAR
ABM_SETAUTOHIDEBAR  QuickInfo

fSuccess = (BOOL) SHAppBarMessage(ABM_SETAUTOHIDEBAR, pabd);

Registers or unregisters an autohide appbar for an edge of the screen. The system allows only one autohide appbar for each edge on a first come, first served basis.

Parameter

pabd

Pointer to an APPBARDATA structure. The uEdge member specifies the screen edge. The lParam parameter is set to TRUE to register the appbar or FALSE to unregister it. You must specify the cbSize, hWnd, uEdge, and lParam members when sending this message; all other members are ignored.

Return Value

Returns TRUE if successful or FALSE if an error occurs or an autohide appbar is already registered for the given edge.

See Also

APPBARDATA


ABM_SETPOS
ABM_SETPOS  QuickInfo

SHAppBarMessage(ABM_SETPOS, pabd);

Sets the size and screen position of an appbar. The message specifies a screen edge to and the bounding rectangle for the appbar. The system may adjust the bounding rectangle so that the appbar does not interfere with the Windows taskbar or any other appbars.

Parameters

pabd

Pointer to an APPBARDATA structure. The uEdge member specifies a screen edge, and the rc member contains the bounding rectangle. When the SHAppBarMessage function returns, rc contains the approved bounding rectangle. You must specify the cbSize, hWnd, uEdge, and rc members when sending this message; all other members are ignored.

Return Value

Always returns TRUE.

This message causes the system to send the ABN_POSCHANGED notification message to all appbars.

See Also

APPBARDATA


ABM_WINDOWPOSCHANGED
ABM_WINDOWPOSCHANGED  QuickInfo

SHAppBarMessage(ABM_WINDOWPOSCHANGED, pabd);

Notifies the system when an appbar's position has changed. An appbar should call this message in response to the WM_WINDOWPOSCHANGED message.

Parameter

pabd

Pointer to an APPBARDATA structure that identifies the appbar to activate. You must specify the cbSize and hWnd members when sending this message; all other members are ignored.

Return Value

Always returns TRUE.

Remarks

This message is ignored if the hWnd member of the structure pointed to by pabd identifies an autohide appbar.

See Also

APPBARDATA


ABN_FULLSCREENAPP
ABN_FULLSCREENAPP  QuickInfo

ABN_FULLSCREENAPP

fOpen = (BOOL) lParam;

Notifies an appbar when a full-screen application is opening or closing. When a full-screen application is opening, an appbar must drop to the bottom of the Z order. When it is closing, the appbar should restore its Z order position. This notification is sent in the form of an application-defined message that is set by the ABM_NEW message.

Parameter

fOpen

Flag specifying whether a full screen application is opening or closing. This parameter is TRUE if opening or FALSE if closing.

Return Value

No return value.


ABN_POSCHANGED
ABN_POSCHANGED  QuickInfo

Notifies an appbar when an event has occurred that may effect the appbar's size and position. Events include changes in the taskbar's size, position, and visibility state, as well as the addition, removal, or resizing of another appbar on the same side of the screen.

Return Value

No return value.

Remarks

An appbar should respond to this notification message by sending the ABM_QUERYPOS and ABM_SETPOS messages. If its position has changed, the appbar should call the MoveWindow function to move itself to the new position.

See Also

MoveWindow


ABN_STATECHANGE
ABN_STATECHANGE  QuickInfo

ABN_STATECHANGE

Notifies an appbar that the taskbar's autohide or always-on-top state has changed — that is, the user has checked or unchecked the "Always on top" or "Auto hide" check box on the taskbar's property sheet. An appbar can use this notification message to set its state to conform to that of the taskbar, if desired.

Return Value

No return value.


ABN_WINDOWARRANGE
ABN_WINDOWARRANGE  QuickInfo

ABN_WINDOWARRANGE

fBeginning = (BOOL) lParam;

Notifies an appbar that the user has selected the Cascade, Tile Horizontally, or Tile Vertically command from the taskbar's context menu.

Parameter

fBeginning

Flag specifying whether the cascade or tile operation is beginning. This parameter is TRUE if the operation is beginning and the windows have not yet been moved. It is FALSE if the operation has completed.

Return Value

No return value.

Remarks

The system sends this notification message twice — first with lParam set to TRUE and then with lParam set to FALSE. The first notification is sent before the windows are cascaded or tiled, and the second is sent after the cascade or tile operation has occurred.


ACM_OPEN [New - Windows NT]
ACM_OPEN  QuickInfo  Overview  Group

[New - Windows NT]

ACM_OPEN

wParam = 0;

lParam = (LPARAM) (LPSTR) lpszName;

// Corresponding macro

BOOL Animate_Open(hwnd, lpszName);

// Related macro

BOOL Animate_Close(hwnd);

The ACM_OPEN message opens an AVI clip and displays its first frame in an animation control.

Parameters

hwnd

Handle to the animation control.

lpszName

Pointer to a buffer that contains the path of the .AVI file or the name of an AVI resource. Alternatively, this parameter can consist of the AVI resource identifier in the low-order word and zero in the high-order word. To create this value, use the MAKEINTRESOURCE macro. If this parameter is NULL, the system closes the .AVI file that was previously opened for the specified animation control, if any.

The AVI file or resource specified by lpszName must not contain audio. It must be silent.

Return Value

If the operation succeeds, the return value is TRUE.

If the operation fails, the return value is FALSE.

Remarks

You can only open silent AVI clips. AVI files or resources containing audio will not load. ACM_OPEN and Animate_Open fail if lpszSource specifies a non-silent AVI clip.

You can use Animate_Close to close an .AVI file or AVI resource that was previously opened for the specified animation control.

The Animate_Open macro is defined as follows:

#define Animate_Open(hwnd, szName)   \

    (BOOL)SendMessage(hwnd, ACM_OPEN, 0, (LPARAM)(LPTSTR)(szName))

The Animate_Close macro is defined as follows:

#define Animate_Close(hwnd)                 Animate_Open(hwnd, NULL)

The Animate_Close macro always returns FALSE.

See Also

MAKEINTRESOURCE


ACM_PLAY [New - Windows NT]
ACM_PLAY  QuickInfo  Overview  Group

[New - Windows NT]

ACM_PLAY

wParam = (WPARAM) (UINT) cRepeat;

lParam = (LPARAM) MAKELONG(wFrom, wTo);

// Corresponding macro

BOOL Animate_Play(hwndAnim, wFrom, wTo, cRepeat);

// Related macro

BOOL Animate_Seek(hwndAnim, wFrame);

The ACM_PLAY message plays an AVI clip in an animation control. The control plays the clip in the background while the thread continues executing.

Parameters

cRepeat

Number of times to replay the AVI clip. A value of  − 1 means replay the clip indefinitely.

hwndAnim

Handle to the animation control in which to play the AVI clip.

wFrom

Zero-based index of the frame where playing begins. The value must be less than 65,536. A value of zero means begin with the first frame in the AVI clip.

wTo

Zero-based index of the frame where playing ends. The value must be less than 65,536. A value of  − 1 means end with the last frame in the AVI clip.

wFrame

Zero-based index of the frame to display.

Return Value

If the operation succeeds, the return value is TRUE.

If the operation fails, the return value is FALSE.

Remarks

You can use Animate_Seek to direct the animation control to display a particular frame of the AVI clip.

The Animate_Play macro is defined as follows:

#define Animate_Play(hwnd, from, to, rep)   \

    (BOOL)SendMessage(hwnd, ACM_PLAY, (WPARAM)(UINT)(rep),  \

        (LPARAM)MAKELONG(from, to))

The Animate_Seek macro is defined as follows:

#define Animate_Seek(hwnd, frame)           Animate_Play(hwnd, frame, frame, 1)


ACM_STOP [New - Windows NT]
ACM_STOP  QuickInfo  Overview  Group

[New - Windows NT]

ACM_STOP

wParam = 0;

lParam = 0;

// Corresponding macro

BOOL Animate_Stop(hwnd);

The ACM_STOP message stops playing an AVI clip in an animation control.

Parameters

hwnd

Handle to the animation control.

Return Value

If the operation succeeds, the return value is TRUE.

If the operation fails, the return value is FALSE.


ACN_START [New - Windows NT]
ACN_START  QuickInfo  Overview  Group

[New - Windows NT]

ACN_START

The ACN_START notification message notifies an animation control's parent window that the associated AVI clip has started playing. This notification message is sent in the form of a WM_COMMAND message.

Return Value

No return value.

See Also

WM_COMMAND


ACN_STOP [New - Windows NT]
ACN_STOP  QuickInfo  Overview  Group

[New - Windows NT]

ACN_STOP

The ACN_STOP notification message notifies an animation control's parent window that the associated AVI clip has stopped playing. This notification message is sent in the form of a WM_COMMAND message.

Return Value

No return value.

See Also

WM_COMMAND


BM_CLICK
BM_CLICK  QuickInfo  Overview  Group

BM_CLICK

wParam = 0;     // not used; must be zero

lParam = 0;     // not used; must be zero

An application sends a BM_CLICK message to simulate the user clicking a button. This message causes the button to receive a WM_LBUTTONDOWN and a WM_LBUTTONUP message, and the button's parent window to receive a BN_CLICKED notification message.

Parameters

This message has no parameters.

Return Value

This message does not return a value.

See Also

BN_CLICKED, WM_LBUTTONDOWN, WM_LBUTTONUP


BM_GETCHECK
BM_GETCHECK  QuickInfo  Overview  Group

BM_GETCHECK

wParam = 0;     // not used; must be zero

lParam = 0;     // not used; must be zero

An application sends a BM_GETCHECK message to retrieve the check state of a radio button or check box.

Parameters

This message has no parameters.

Return Value

The return value from a button created with the BS_AUTOCHECKBOX, BS_AUTORADIOBUTTON, BS_AUTO3STATE, BS_CHECKBOX, BS_RADIOBUTTON, or BS_3STATE style can be one of the following:

Value	Meaning
0	Button is unchecked. Same as the Windows 95 constant BST_UNCHECKED.
1	Button is checked. Same as the Windows 95 constant BST_CHECKED.
2	Button is grayed, indicating an indeterminate state (applies only if the button has the BS_3STATE or BS_AUTO3STATE style). Same as the Windows 95 constant BST_INDETERMINATE.
BST_CHECKED	Windows 95 only: Button is checked.
BST_INDETERMINATE	Windows 95 only: Button is grayed, indicating an indeterminate state (applies only if the button has the BS_3STATE or BS_AUTO3STATE style).
BST_UNCHECKED	Windows 95 only: Button is unchecked
If the button has any other style, the return value is zero.

See Also

BM_GETSTATE, BM_SETCHECK


BM_GETIMAGE [New - Windows 95]
BM_GETIMAGE

[New - Windows 95]

BM_GETIMAGE

wParam = 0;     // not used, must be zero

lParam = 0;     // not used, must be zero

An application sends a BM_GETIMAGE message to retrieve the handle of the image (icon or bitmap) associated with the button.

Parameters

This message has no parameters.

Return Value

The return value is the handle of the image, if any; otherwise, it is NULL.

See Also

BM_SETIMAGE


BM_GETSTATE
BM_GETSTATE  QuickInfo  Overview  Group

BM_GETSTATE

wParam = 0;     // not used; must be zero

lParam = 0;     // not used; must be zero

An application sends a BM_GETSTATE message to determine the state of a button or check box.

Parameters

This message has no parameters.

Return Value

The return value specifies the current state of the button. You can use the following bitmasks to extract information about the state:

Value	Meaning
0x0003	Specifies the check state (radio buttons and check boxes only). A value of zero indicates the button is unchecked; a value of 1 indicates the button is checked. A radio button is checked when it contains a dot; a check box is checked when it contains an X. A value of 2 indicates the check state is indeterminate (applies only if the button has the BS_3STATE or BS_AUTO3STATE style). A three-state check box is grayed when its state is indeterminate.
0x0004	Specifies the highlight state. A nonzero value indicates that the button is highlighted. A button is automatically highlighted when the user positions the cursor over it and presses and holds the left mouse button. The highlighting is removed when the user releases the mouse button. Same as the Windows 95 constant BST_PUSHED.
0x0008	Specifies the focus state. A nonzero value indicates that the button has the keyboard focus. Same as the Windows 95 constant BST_FOCUS.
BST_CHECKED	Windows 95 only: Indicates the button is checked. Same as the Windows NT return value of 1.
BST_FOCUS	Windows 95 only: Indicates the button has the keyboard focus. Same as the Windows NT return value of 0x0008.
BST_INDETERMINATE	Windows 95 only: Indicates the button is grayed because the state of the button is indeterminate. This value applies only if the button has the BS_3STATE or BS_AUTO3STATE style. Same as the Windows NT return value of 2.
BST_PUSHED	Windows 95 only: Indicates the button is highlighted as if the user had pushed it. Same as the Windows NT return value of 0x0004.
BST_UNCHECKED	Windows 95 only: Indicates the button is unchecked. Same as the Windows NT return value of zero.
See Also

BM_GETCHECK, BM_SETSTATE


BM_SETCHECK
BM_SETCHECK  QuickInfo  Overview  Group

BM_SETCHECK

wParam = (WPARAM) fCheck; // check state

lParam = 0;               // not used; must be zero

An application sends a BM_SETCHECK message to set the check state of a radio button or check box.

Parameters

fCheck

Value of wParam. Specifies the check state. This parameter can be one of the following values:

Value	Meaning
0	Sets the button state to unchecked. Same as the Windows 95 constant BST_UNCHECKED.
1	Sets the button state to checked. Same as the Windows 95 constant BST_CHECKED.
2	Sets the button state to grayed, indicating an indeterminate state. Use this value only if the button has the BS_3STATE or BS_AUTO3STATE style. Same as the Windows 95 constant BST_INDETERMINATE.
BST_CHECKED	Windows 95 only: Sets the button state to checked.
BST_INDETERMINATE	Windows 95 only: Sets the button state to grayed, indicating an indeterminate state. Use this value only if the button has the BS_3STATE or BS_AUTO3STATE style.
BST_UNCHECKED	Windows 95 only: Sets the button state to unchecked
Return Value

This message always returns zero.

Remarks

The BM_SETCHECK message has no effect on push buttons.

See Also

BM_GETCHECK, BM_GETSTATE, BM_SETSTATE


BM_SETIMAGE [New - Windows 95]
BM_SETIMAGE

[New - Windows 95]

BM_SETIMAGE

wParam = 0;                         // not used, must be zero

lParam = (LPARAM) (HANDLE) hImage;  // handle of the image

An application sends a BM_SETIMAGE message to associate a new image (icon or bitmap) with the button.

Parameters

hImage

Value of lParam. Identifies the image to associate with the button.

Return Value

The return value is the handle of the image previously associated with the button, if any; otherwise, it is NULL.

See Also

BM_GETIMAGE


BM_SETSTATE
BM_SETSTATE  QuickInfo  Overview  Group

BM_SETSTATE

wParam = (WPARAM) fState;   // highlight state

lParam = 0;                 // not used; must be zero

An application sends a BM_SETSTATE message to change the highlight state of a button. The highlight state indicates whether the button is highlighted as if the user had pushed it.

Parameters

fState

Value of wParam. Specifies whether the button is to be highlighted. A value of TRUE highlights the button. A value of FALSE removes any highlighting.

Return Value

This message always returns zero.

Remarks

Highlighting only affects the appearance of a button. It has no effect on the check state of a radio button or check box.

A button is automatically highlighted when the user positions the cursor over it and presses and holds the left mouse button. The highlighting is removed when the user releases the mouse button.

See Also

BM_GETSTATE, BM_SETCHECK


BM_SETSTYLE
BM_SETSTYLE  QuickInfo  Overview  Group

BM_SETSTYLE

wParam =  (WPARAM) LOWORD(dwStyle); // style

lParam =  MAKELPARAM(fRedraw, 0);   // redraw flag

An application sends a BM_SETSTYLE message to change the style of a button.

Parameters

dwStyle

Value of wParam. Specifies the button style. For an explanation of button styles, see the following Remarks section.

fRedraw

Value of the low-order word of lParam. Specifies whether the button is to be redrawn. A value of TRUE redraws the button; a value of FALSE does not redraw the button.

Return Value

This message always returns zero.

Remarks

Following are the available button styles:

Style	Meaning
BS_3STATE	Creates a button that is the same as a check box, except that the box can be grayed as well as checked or unchecked. Use the grayed state to show that the state of the check box is not determined.
BS_AUTO3STATE	Creates a button that is the same as a three-state check box, except that the box changes its state when the user selects it. The state cycles through checked, grayed, and unchecked.
BS_AUTOCHECKBOX	Creates a button that is the same as a check box, except that the check state automatically toggles between checked and unchecked each time the user selects the check box.
BS_AUTORADIOBUTTON	Creates a button that is the same as a radio button, except that when the user selects it, Windows automatically sets the button's check state to checked and automatically sets the check state for all other buttons in the same group to unchecked.
BS_CHECKBOX	Creates a small, empty check box with text. By default, the text is displayed to the right of the check box. To display the text to the left of the check box, combine this flag with the BS_LEFTTEXT style (or on Windows 95 only, with the equivalent BS_RIGHTBUTTON style).
BS_DEFPUSHBUTTON	Creates a push button that behaves like a BS_PUSHBUTTON style button, but also has a heavy black border. If the button is in a dialog box, the user can select the button by pressing the ENTER key, even when the button does not have the input focus. This style is useful for enabling the user to quickly select the most likely (default) option.
BS_GROUPBOX	Creates a rectangle in which other controls can be grouped. Any text associated with this style is displayed in the rectangle's upper left corner.
BS_LEFTTEXT	Places text on the left side of the radio button or check box when combined with a radio button or check box style. Same as the Windows 95 BS_RIGHTBUTTON style.
BS_OWNERDRAW	Creates an owner-drawn button. The owner window receives a WM_MEASUREITEM message when the button is created and a WM_DRAWITEM message when a visual aspect of the button has changed. Do not combine the BS_OWNERDRAW style with any other button styles.
BS_PUSHBUTTON	Creates a push button that posts a WM_COMMAND message to the owner window when the user selects the button.
BS_RADIOBUTTON	Creates a small circle with text. By default, the text is displayed to the right of the circle. To display the text to the left of the circle, combine this flag with the BS_LEFTTEXT style (or on Windows 95 only, with the equivalent BS_RIGHTBUTTON style). Use radio buttons for groups of related, but mutually exclusive choices.
BS_USERBUTTON	Obsolete, but provided for compatibility with 16-bit versions of Windows. Win32-based applications should use BS_OWNERDRAW instead.
BS_BITMAP	Windows 95 only: Specifies that the button displays a bitmap.
BS_BOTTOM	Windows 95 only: Places text at the bottom of the button rectangle.
BS_CENTER	Windows 95 only: Centers text horizontally in the button rectangle.
BS_ICON	Windows 95 only: Specifies that the button displays an icon.
BS_LEFT	Windows 95 only: Left-justifies the text in the button rectangle. However, if the button is a check box or radio button that does not have the BS_RIGHTBUTTON style, the text is left justified on the right side of the check box or radio button.
BS_MULTILINE	Windows 95 only: Wraps the button text to multiple lines if the text string is too long to fit on a single line in the button rectangle.
BS_NOTIFY	Windows 95 only: Enables a button to send BN_DBLCLK, BN_KILLFOCUS, and BN_SETFOCUS notification messages to its parent window. Note that buttons send the BN_CLICKED notification message regardless of whether it has this style.
BS_PUSHLIKE	Windows 95 only: Makes a button (such as a check box, three-state check box, or radio button) look and act like a push button. The button looks raised when it isn't pushed or checked, and sunken when it is pushed or checked.
BS_RIGHT	Windows 95 only: Right-justifies text in the button rectangle. However, if the button is a check box or radio button that does not have the BS_RIGHTBUTTON style, the text is right justified on the right side of the check box or radio button.
BS_RIGHTBUTTON	Windows 95 only: Positions a radio button's circle or a check box's square on the right side of the button rectangle. Same as the BS_LEFTTEXT style.
BS_TEXT	Windows 95 only: Specifies that the button displays text.
BS_TOP	Windows 95 only: Places text at the top of the button rectangle.
BS_VCENTER	Windows 95 only: Places text in the middle (vertically) of the button rectangle.
See Also

WM_COMMAND, WM_DRAWITEM, WM_MEASUREITEM


BN_CLICKED
BN_CLICKED  QuickInfo  Overview  Group

BN_CLICKED

idButton = (int) LOWORD(wParam);    // identifier of button

hwndButton = (HWND) lParam;         // handle of button

The BN_CLICKED notification message is sent when the user clicks a mouse button. The parent window of the button receives this notification message through the WM_COMMAND message. Unlike the other button notification messages, this message is intended for applications written for any version of Windows.

Remarks

A disabled button does not send a BN_CLICKED notification message to its parent window.

See Also

WM_COMMAND


BN_DBLCLK [New - Windows 95]
BN_DBLCLK  QuickInfo  Overview  Group

[New - Windows 95]

BN_DBLCLK

idButton = (int) LOWORD(wParam);    // identifier of button

hwndButton = (HWND) lParam;         // handle of button

The BN_DBLCLK notification message is sent when the user double-clicks a button that has the BS_OWNERDRAW or BS_RADIOBUTTON style. The parent window of the button receives this notification message through a WM_COMMAND message.

BN_DBLCLK is the same as the BN_DOUBLECLICKED notification message.

This notification is provided for compatibility with applications written for versions of Windows earlier than version 3.0. New applications should use the BS_OWNERDRAW button style and the DRAWITEMSTRUCT structure for this task.

See Also

BN_CLICKED, BN_DOUBLECLICKED, WM_COMMAND


BN_DISABLE
BN_DISABLE  QuickInfo  Overview  Group

BN_DISABLE

The BN_DISABLE notification message is sent when a button is disabled. The parent window of the button receives this notification message through the WM_COMMAND message.

This notification message is provided for compatibility with applications written for versions of Windows earlier than version 3.0. New applications should use the BS_OWNERDRAW button style and the DRAWITEMSTRUCT structure for this task.

See Also

DRAWITEMSTRUCT, WM_COMMAND, WM_DRAWITEM


BN_DOUBLECLICKED
BN_DOUBLECLICKED  QuickInfo  Overview  Group

BN_DOUBLECLICKED

The BN_DOUBLECLICKED notification message is sent when the user double-clicks a button that has the BS_OWNERDRAW or BS_RADIOBUTTON style. The parent window of the button receives this notification message through the WM_COMMAND message.

BN_DOUBLECLICKED is the same as the Windows 95 BN_DBLCLK notification message.

This notification is provided for compatibility with applications written for versions of Windows earlier than version 3.0. New applications should use the BS_OWNERDRAW button style and the DRAWITEMSTRUCT structure for this task.

See Also

BN_DBLCLK, DRAWITEMSTRUCT, WM_COMMAND, WM_DRAWITEM


BN_HILITE
BN_HILITE  QuickInfo  Overview  Group

BN_HILITE

The BN_HILITE notification message is sent when the user selects a button. The parent window of the button receives this notification message through the WM_COMMAND message.

This notification message is provided for compatibility with applications written for versions of Windows earlier than version 3.0. New applications should use the BS_OWNERDRAW button style and the DRAWITEMSTRUCT structure for this task.

BN_HILITE is the same as the Windows 95 BN_PUSHED notification message.

See Also

BN_PUSHED, BN_UNHILITE, DRAWITEMSTRUCT, WM_COMMAND, WM_DRAWITEM


BN_KILLFOCUS [New - Windows 95]
BN_KILLFOCUS  QuickInfo  Overview  Group

[New - Windows 95]

BN_KILLFOCUS

The BN_KILLFOCUS notification message is sent when a button loses the keyboard focus. The button must have the BS_NOTIFY style to send this notification message. The parent window of the button receives this notification message through the WM_COMMAND message.

See Also

BN_SETFOCUS, WM_COMMAND


BN_PAINT
BN_PAINT  QuickInfo  Overview  Group

BN_PAINT

The BN_PAINT notification message is sent when a button should be painted. The parent window of the button receives this notification message through the WM_COMMAND message.

This notification message is provided for compatibility with applications written for versions of Windows earlier than version 3.0. New applications should use the BS_OWNERDRAW button style and the DRAWITEMSTRUCT structure for this task.

See Also

DRAWITEMSTRUCT, WM_COMMAND, WM_DRAWITEM


BN_PUSHED [New - Windows 95]
BN_PUSHED  QuickInfo

[New - Windows 95]

BN_PUSHED

The BN_PUSHED notification message is sent when the push state of a button is set to pushed. The parent window of the button receives this notification message through the WM_COMMAND message.

BN_PUSHED is the same as the BN_HILITE notification message.

This notification message is provided for compatibility with applications written for versions of Windows earlier than version 3.0. New applications should use the BS_OWNERDRAW button style and the DRAWITEMSTRUCT structure for this task.

See Also

BN_HILITE, BN_UNPUSHED, DRAWITEMSTRUCT, WM_COMMAND, WM_DRAWITEM


BN_SETFOCUS [New - Windows 95]
BN_SETFOCUS  QuickInfo  Overview  Group

[New - Windows 95]

BN_SETFOCUS

The BN_SETFOCUS notification message is sent when a button receives the keyboard focus. The button must have the BS_NOTIFY style to send this notification message. The parent window of the button receives this notification message through the WM_COMMAND message.

See Also

BN_KILLFOCUS, WM_COMMAND


BN_UNHILITE
BN_UNHILITE  QuickInfo  Overview  Group

BN_HILITE

The BN_UNHILITE notification message is sent when the highlight should be removed from a button. The parent window of the button receives this notification message through the WM_COMMAND message.

BN_UNHILITE is the same as the Windows 95 BN_UNPUSHED notification message.

This notification message is provided for compatibility with applications written for versions of Windows earlier than version 3.0. New applications should use the BS_OWNERDRAW button style and the DRAWITEMSTRUCT structure for this task.

See Also

BN_HILITE, BN_UNPUSHED, DRAWITEMSTRUCT, WM_COMMAND, WM_DRAWITEM


BN_UNPUSHED [New - Windows 95]
BN_UNPUSHED  QuickInfo

[New - Windows 95]

BN_PUSHED

The BN_UNPUSHED notification message is sent when the push state of a button is set to unpushed. The parent window of the button receives this notification message through the WM_COMMAND message.

BN_UNPUSHED is the same as the BN_UNHILITE notification message.

This notification message is provided for compatibility with applications written for versions of Windows earlier than version 3.0. New applications should use the BS_OWNERDRAW button style and the DRAWITEMSTRUCT structure for this task.

See Also

BN_PUSHED, DRAWITEMSTRUCT, WM_COMMAND, WM_DRAWITEM


CB_ADDSTRING
CB_ADDSTRING  QuickInfo  Overview  Group

CB_ADDSTRING

wParam = 0;                         // not used; must be zero

lParam = (LPARAM) (LPCTSTR) lpsz;    // address of string to add

An application sends a CB_ADDSTRING message to add a string to the list box of a combo box. If the combo box does not have the CBS_SORT style, the string is added to the end of the list. Otherwise, the string is inserted into the list, and the list is sorted.

Parameters

lpsz

Value of lParam. Points to the null-terminated string to be added. If you create the combo box with an owner-drawn style but without the CBS_HASSTRINGS style, the value of the lpsz parameter is stored as item data rather than the string it would otherwise point to. The item data can be retrieved or modified by sending the CB_GETITEMDATA or CB_SETITEMDATA message.

Return Value

The return value is the zero-based index to the string in the list box of the combo box. If an error occurs, the return value is CB_ERR. If insufficient space is available to store the new string, it is CB_ERRSPACE.

Remarks

If you create an owner-drawn combo box with the CBS_SORT style but without the CBS_HASSTRINGS style, the WM_COMPAREITEM message is sent one or more times to the owner of the combo box so the new item can be properly placed in the list.

To insert a string at a specific location within the list, use the CB_INSERTSTRING message.

See Also

CB_DIR, CB_INSERTSTRING, WM_COMPAREITEM


CB_DELETESTRING
CB_DELETESTRING  QuickInfo  Overview  Group

CB_DELETESTRING

wParam = (WPARAM) index;  // item to delete

lParam = 0;               // not used; must be zero

An application sends a CB_DELETESTRING message to delete a string in the list box of a combo box.

Parameters

index

Value of wParam. Specifies the zero-based index of the string to delete.

Return Value

The return value is a count of the strings remaining in the list. If the index parameter specifies an index greater than the number of items in the list, the return value is CB_ERR.

Remarks

If you create the combo box with an owner-drawn style but without the CBS_HASSTRINGS style, Windows sends a WM_DELETEITEM message to the owner of the combo box so the application can free any additional data associated with the item.

See Also

CB_RESETCONTENT, WM_DELETEITEM


CB_DIR
CB_DIR  QuickInfo  Overview  Group

CB_DIR

wParam = (WPARAM) (UINT) uAttrs;          // file attributes

lParam = (LPARAM) (LPCTSTR) lpszFileSpec; // address of filename

An application sends a CB_DIR message to add a list of filenames to the list box of a combo box.

Parameters

uAttrs

Value of wParam. Specifies the attributes of the files to be added to the list box. It can be any combination of the following values:

Value	Meaning
DDL_ARCHIVE	Includes archived files.
DDL_DIRECTORY	Includes subdirectories. Subdirectory names are enclosed in square brackets ([ ]).
DDL_DRIVES	Includes drives. Drives are listed in the form [-x-], where x is the drive letter.
DDL_EXCLUSIVE	Includes only files with the specified attributes. By default, read-write files are listed even if DDL_READWRITE is not specified.
DDL_HIDDEN	Includes hidden files.
DDL_READONLY	Includes read-only files.
DDL_READWRITE	Includes read-write files with no additional attributes.
DDL_SYSTEM	Includes system files.
lpszFileSpec

Value of lParam. Points to the null-terminated string that specifies the filename to add to the list. If the filename contains any wildcards (for example, *.*), all files that match and have the attributes specified by the uAttrs parameter are added to the list.

Return Value

The return value is the zero-based index of the last filename added to the list. If an error occurs, the return value is CB_ERR. If insufficient space is available to store the new strings, it is CB_ERRSPACE.

See Also

CB_ADDSTRING, CB_INSERTSTRING, DlgDirList, DlgDirListComboBox


CB_FINDSTRING
CB_FINDSTRING  QuickInfo  Overview  Group

CB_FINDSTRING

wParam = (WPARAM) indexStart;        // item before start of search

lParam = (LPARAM) (LPCSTR) lpszFind  // prefix string address

An application sends a CB_FINDSTRING message to search the list box of a combo box for an item beginning with the characters in a specified string.

Parameters

indexStart

Value of wParam. Specifies the zero-based index of the item preceding the first item to be searched. When the search reaches the bottom of the list box, it continues from the top of the list box back to the item specified by the indexStart parameter. If indexStart is −1, the entire list box is searched from the beginning.

lpszFind

Value of lParam. Points to the null-terminated string that contains the prefix to search for. The search is not case sensitive, so this string can contain any combination of uppercase and lowercase letters.

Return Value

The return value is the zero-based index of the matching item. If the search is unsuccessful, it is CB_ERR.

Remarks

If you create the combo box with an owner-drawn style but without the CBS_HASSTRINGS style, what the CB_FINDSTRING message does depends on whether your application uses the CBS_SORT style. If you use the CBS_SORT style, WM_COMPAREITEM messages are sent to the owner of the combo box to determine which item matches the specified string. If you do not use the CBS_SORT style, the CB_FINDSTRING message searches for a list item that matches the value of the lpszFind parameter.

See Also

CB_FINDSTRINGEXACT, CB_SELECTSTRING, CB_SETCURSEL, WM_COMPAREITEM


CB_FINDSTRINGEXACT
CB_FINDSTRINGEXACT  QuickInfo  Overview  Group

CB_FINDSTRINGEXACT

wParam = (WPARAM) indexStart;      // item before start of search

lParam = (LPARAM)(LPCSTR)lpszFind; // address of string to search for

An application sends a CB_FINDSTRINGEXACT message to find the first list box string in a combo box that matches the string specified in the lpszFind parameter.

Parameters

indexStart

Value of wParam. Specifies the zero-based index of the item preceding the first item to be searched. When the search reaches the bottom of the list box, it continues from the top of the list box back to the item specified by the indexStart parameter. If indexStart is −1, the entire list box is searched from the beginning.

lpszFind

Value of lParam. Points to the null-terminated string to search for. This string can contain a complete filename, including the extension. The search is not case sensitive, so this string can contain any combination of uppercase and lowercase letters.

Return Value

The return value is the zero-based index of the matching item. If the search is unsuccessful, it is CB_ERR.

Remarks

If you create the combo box with an owner-drawn style but without the CBS_HASSTRINGS style, what the CB_FINDSTRINGEXACT message does depends on whether your application uses the CBS_SORT style. If you use the CBS_SORT style, WM_COMPAREITEM messages are sent to the owner of the combo box to determine which item matches the specified string. If you do not use the CBS_SORT style, the CB_FINDSTRINGEXACT message searches for a list item that matches the value of the lpszFind parameter.

See Also

CB_FINDSTRING, CB_SELECTSTRING, WM_COMPAREITEM


CB_GETCOUNT
CB_GETCOUNT  QuickInfo  Overview  Group

CB_GETCOUNT

wParam = 0;     // not used; must be zero

lParam = 0;     // not used; must be zero

An application sends a CB_GETCOUNT message to retrieve the number of items in the list box of a combo box.

Parameters

This message has no parameters.

Return Value

The return value is the number of items in the list box. If an error occurs, it is CB_ERR.

Remarks

The index is zero-based, so the returned count is one greater than the index value of the last item.


CB_GETCURSEL
CB_GETCURSEL  QuickInfo  Overview  Group

CB_GETCURSEL

wParam = 0;     // not used; must be zero

lParam = 0;     // not used; must be zero

An application sends a CB_GETCURSEL message to retrieve the index of the currently selected item, if any, in the list box of a combo box.

Parameters

This message has no parameters.

Return Value

The return value is the zero-based index of the currently selected item. If no item is selected, it is CB_ERR.

See Also

CB_SELECTSTRING, CB_SETCURSEL


CB_GETDROPPEDCONTROLRECT
CB_GETDROPPEDCONTROLRECT  QuickInfo  Overview  Group

CB_GETDROPPEDCONTROLRECT

wParam = 0;                         // not used; must be zero

lParam = (LPARAM) (RECT FAR*) lprc; // address of RECT structure

An application sends a CB_GETDROPPEDCONTROLRECT message to retrieve the screen coordinates of the drop-down list box of a combo box.

Parameters

lprc

Value of lParam. Points to the RECT structure that is to receive the coordinates.

Return Value

This message always returns CB_OKAY.

See Also

RECT


CB_GETDROPPEDSTATE
CB_GETDROPPEDSTATE  QuickInfo

CB_GETDROPPEDSTATE

wParam = 0;     // not used; must be zero

lParam = 0;     // not used; must be zero

An application sends a CB_GETDROPPEDSTATE message to determine whether the list box of a combo box is dropped down.

Parameters

This message has no parameters.

Return Value

If the list box is visible, the return value is TRUE; otherwise, it is FALSE.

See Also

CB_SHOWDROPDOWN


CB_GETDROPPEDWIDTH [New - Windows 95]
CB_GETDROPPEDWIDTH  QuickInfo

[New - Windows 95]

CB_GETDROPPEDWIDTH

wParam = 0;     // not used, must be zero

lParam = 0;     // not used, must be zero

An application sends the CB_GETDROPPEDWIDTH message to retrieve the minimum allowable width, in pixels, of the list box of a combo box with the CBS_DROPDOWN or CBS_DROPDOWNLIST style.

Parameters

This message has no parameters.

Return Value

If the message succeeds, the return value is the width, in pixels.

If the message fails, the return value is CB_ERR.

Remarks

By default, the minimum allowable width of the drop-down list box is 0. The width of the list box is either the minimum allowable width or the combo box width, whichever is larger.

See Also

CB_SETDROPPEDWIDTH


CB_GETEDITSEL
CB_GETEDITSEL  QuickInfo  Overview  Group

CB_GETEDITSEL

wParam = (WPARAM) (LPDWORD) lpdwStart; // receives starting position

lParam = (LPARAM) (LPDWORD) lpdwEnd;   // receives ending position

An application sends a CB_GETEDITSEL message to get the starting and ending character positions of the current selection in the edit control of a combo box.

Parameters

lpdwStart

Value of wParam. Points to a 32-bit value that receives the starting position of the selection. This parameter can be set to NULL.

lpdwEnd

Value of lParam. Points to a 32-bit value that receives the ending position of the selection. This parameter can be set to NULL.

Return Value

The return value is a zero-based 32-bit value with the starting position of the selection in the low-order word and with the ending position of the first character after the last selected character in the high-order word.

See Also

CB_SETEDITSEL


CB_GETEXTENDEDUI
CB_GETEXTENDEDUI  QuickInfo  Overview  Group

CB_GETEXTENDEDUI

wParam = 0;     // not used; must be zero

lParam = 0;     // not used; must be zero

An application sends a CB_GETEXTENDEDUI message to determine whether a combo box has the default user interface or the extended user interface.

Parameters

This message has no parameters.

Return Value

If the combo box has the extended user interface, the return value is TRUE; otherwise, it is FALSE.

Remarks

By default, the F4 key opens or closes the list and the DOWN ARROW changes the current selection. In a combo box with the extended user interface, the F4 key is disabled and pressing the DOWN ARROW key opens the drop-down list.

See Also

CB_SETEXTENDEDUI


CB_GETHORIZONTALEXTENT [New - Windows 95]
CB_GETHORIZONTALEXTENT  QuickInfo

[New - Windows 95]

CB_GETHORIZONTALEXTENT

wParam = 0;     // not used, must be zero

lParam = 0;     // not used, must be zero

An application sends the CB_GETHORIZONTALEXTENT message to retrieve from a combo box the width, in pixels, by which the list box can be scrolled horizontally (the scrollable width). This is applicable only if the list box has a horizontal scroll bar.

Parameters

This message has no parameters.

Return Value

The return value is the scrollable width, in pixels.

See Also

CB_SETHORIZONTALEXTENT


CB_GETITEMDATA
CB_GETITEMDATA  QuickInfo  Overview  Group

CB_GETITEMDATA

wParam = (WPARAM) index;  // item index

lParam = 0;               // not used; must be zero

An application sends a CB_GETITEMDATA message to a combo box to retrieve the application-supplied 32-bit value associated with the specified item in the combo box.

Parameters

index

Value of wParam. Specifies the zero-based index of the item.

Return Value

The return value is the 32-bit value associated with the item. If an error occurs, it is CB_ERR.

If the item is in an owner-drawn combo box created without the CBS_HASSTRINGS style, the return value is the 32-bit value contained in the lParam parameter of the CB_ADDSTRING or CB_INSERTSTRING message that added the item to the combo box. If the CBS_HASSTRINGS style was not used, the return value is the lParam parameter contained in a CB_SETITEMDATA message.

See Also

CB_ADDSTRING, CB_INSERTSTRING, CB_SETITEMDATA


CB_GETITEMHEIGHT
CB_GETITEMHEIGHT  QuickInfo  Overview  Group

CB_GETITEMHEIGHT

wParam = (WPARAM) index;  // item index

lParam = 0;               // not used; must be zero

An application sends a CB_GETITEMHEIGHT message to determine the height of list items or the selection field in a combo box.

Parameters

index

Value of wParam. Specifies the combo box component whose height is to be retrieved.

This parameter must be −1 to retrieve the height of the selection field. It must be zero to retrieve the height of list items, unless the combo box has the CBS_OWNERDRAWVARIABLE style. In that case, the index parameter is the zero-based index of a specific list item.

Return Value

The return value is the height, in pixels, of the list items in a combo box. If the combo box has the CBS_OWNERDRAWVARIABLE style, it is is the height of the item specified by the index parameter. If index is −1, the return value is the height of the edit control (or static-text) portion of the combo box. If an error occurs, the return value is CB_ERR.

See Also

CB_SETITEMHEIGHT, WM_MEASUREITEM


CB_GETLBTEXT
CB_GETLBTEXT  QuickInfo  Overview  Group

CB_GETLBTEXT

wParam = (WPARAM) index;                // item index

lParam = (LPARAM) (LPCSTR) lpszBuffer;  // address of buffer

An application sends a CB_GETLBTEXT message to retrieve a string from the list of a combo box.

Parameters

index

Value of wParam. Specifies the zero-based index of the string to retrieve.

lpszBuffer

Value of lParam. Points to the buffer that receives the string. The buffer must have sufficient space for the string and a terminating null character. You can send a CB_GETLBTEXTLEN message prior to the CB_GETLBTEXT message to retrieve the length, in bytes, of the string.

Return Value

The return value is the length of the string, in bytes, excluding the terminating null character. If the index parameter does not specify a valid index, the return value is CB_ERR.

Remarks

If you create the combo box with an owner-drawn style but without the CBS_HASSTRINGS style, the buffer pointed to by the lpszBuffer parameter of the message receives the 32-bit value associated with the item (the item data).

See Also

CB_GETLBTEXTLEN


CB_GETLBTEXTLEN
CB_GETLBTEXTLEN  QuickInfo  Overview  Group

CB_GETLBTEXTLEN

wParam = (WPARAM) index;  // item index

lParam = 0;               // not used; must be zero

An application sends a CB_GETLBTEXTLEN message to retrieve the length, in characters, of a string in the list of a combo box.

Parameters

index

Value of wParam. Specifies the zero-based index of the string.

Return Value

The return value is the length of the string, in characters, excluding the terminating null character. Under certain conditions, this value may actually be greater than the length of the text. For more information, see the following Remarks section.

If the index parameter does not specify a valid index, the return value is CB_ERR.

Remarks

Under certain conditions, the return value is larger than the actual length of the text. This occurs with certain mixtures of ANSI and Unicode, and is due to the operating system allowing for the possible existence of double-byte character set (DBCS) characters within the text. The return value, however, will always be at least as large as the actual length of the text; so you can always use it to guide buffer allocation. This behavior can occur when an application uses both ANSI functions and common dialogs, which use Unicode.

To obtain the exact length of the text, use the WM_GETTEXT, LB_GETTEXT, or CB_GETLBTEXT messages, or the GetWindowText function.

See Also

CB_GETLBTEXT, GetWindowText, LB_GETTEXT, WM_GETTEXT


CB_GETLOCALE
CB_GETLOCALE  QuickInfo  Overview  Group

CB_GETLOCALE

wParam = 0; // not used; must be zero

lParam = 0; // not used; must be zero

An application sends a CB_GETLOCALE message to retrieve the current locale of the combo box. The locale is used to determine the correct sorting order of displayed text for combo boxes with the CBS_SORT style and text added by using the CB_ADDSTRING message.

Parameters

This message has no parameters.

Return Value

The return value is a 32-bit value that specifies the current locale of the combo box. The high word contains the country code and the low-order word contains the language identifier.

Remarks

The language identifier is made up of a sublanguage identifier and a primary language identifier. The PRIMARYLANGID macro obtains the primary language identifier and the SUBLANGID macro obtains the sublanguage identifier.

See Also

CB_ADDSTRING, CB_SETLOCALE, PRIMARYLANGID, SUBLANGID


CB_GETTOPINDEX [New - Windows 95]
CB_GETTOPINDEX  QuickInfo

[New - Windows 95]

CB_GETTOPINDEX

wParam = 0;     // not used, must be zero

lParam = 0;     // not used, must be zero

An application sends the CB_GETTOPINDEX message to retrieve the zero-based index of the first visible item in the list box portion of a combo box. Initially the item with index 0 is at the top of the list box, but if the list box contents have been scrolled, another item may be at the top.

Parameters

This message has no parameters.

Return Value

If the message is successful, the return value is the index of the first visible item in the list box of the combo box.

If the message fails, the return value is CB_ERR.

See Also

CB_SETTOPINDEX


CB_INITSTORAGE [New - Windows 95]
CB_INITSTORAGE  QuickInfo

[New - Windows 95]

CB_INITSTORAGE

wParam = (WPARAM) (int) cItems;     // number of items to add

lParam = (LPARAM) (DWORD) cb;       // amount of memory to allocate, in bytes

An application sends the CB_INITSTORAGE message before adding a large number of items to the list box portion of a combo box. This message allocates memory for storing list box items.

Parameters

cItems

Specifies the number of items to add.

cb

Specifies the amount of memory to allocate for item strings, in bytes.

Return Value

If the message is successful, the return value is the maximum number of items that the memory object can store.

If the message fails, the return value is CB_ERR.

Remarks

This message helps speed up the initialization of combo boxes that have a large number of items (over 100). It preallocates the specified amount of memory so that subsequent CB_ADDSTRING, CB_INSERTSTRING and CB_DIR messages take the shortest possible time. You can use estimates for the cItems and cb parameters. If you overestimate, some extra memory is allocated, if you underestimate, the normal allocation is used for items that exceed the preallocated amount.

See Also

CB_ADDSTRING, CB_DIR, CB_INSERTSTRING


CB_INSERTSTRING
CB_INSERTSTRING  QuickInfo  Overview  Group

CB_INSERTSTRING

wParam = (WPARAM) index;         // item index

lParam = (LPARAM) (LPCTSTR) lpsz; // address of string to insert

An application sends a CB_INSERTSTRING message to insert a string into the list box of a combo box. Unlike the CB_ADDSTRING message, the CB_INSERTSTRING message does not cause a list with the CBS_SORT style to be sorted.

Parameters

index

Value of wParam. Specifies the zero-based index of the position at which to insert the string. If this parameter is −1, the string is added to the end of the list.

lpsz

Value of lParam. Points to the null-terminated string to be inserted. If you create the combo box with an owner-drawn style but without the CBS_HASSTRINGS style, the value of the lpsz parameter is stored rather than the string it would otherwise point to.

Return Value

The return value is the index of the position at which the string was inserted. If an error occurs, the return value is CB_ERR. If there is insufficient space available to store the new string, it is CB_ERRSPACE.

See Also

CB_ADDSTRING, CB_DIR


CB_LIMITTEXT
CB_LIMITTEXT  QuickInfo  Overview  Group

CB_LIMITTEXT

wParam = (WPARAM) cchLimit;   // maximum number of characters

lParam = 0;                   // not used; must be zero

An application sends a CB_LIMITTEXT message to limit the length of the text the user may type into the edit control of a combo box.

Parameters

cchLimit

Value of wParam. Specifies the maximum number of characters the user can enter. If this parameter is zero, the text length is set to 0x7FFFFFFE characters.

Return Value

The return value is always TRUE.

Remarks

If the combo box does not have the CBS_AUTOHSCROLL style, setting the text limit to be larger than the size of the edit control has no effect.

The CB_LIMITTEXT message limits only the text the user can enter. It has no effect on any text already in the edit control when the message is sent, nor does it affect the length of the text copied to the edit control when a string in the list box is selected.

The default limit to the text a user can enter in the edit control is 30,000 characters.


CB_RESETCONTENT
CB_RESETCONTENT  QuickInfo  Overview  Group

CB_RESETCONTENT

wParam = 0;     // not used; must be zero

lParam = 0;     // not used; must be zero

An application sends a CB_RESETCONTENT message to remove all items from the list box and edit control of a combo box.

Parameters

This message has no parameters.

Return Value

This message always returns CB_OKAY.

Remarks

If you create the combo box with an owner-drawn style but without the CBS_HASSTRINGS style, the owner of the combo box receives a WM_DELETEITEM message for each item in the combo box.

See Also

CB_DELETESTRING, WM_DELETEITEM


CB_SELECTSTRING
CB_SELECTSTRING  QuickInfo  Overview  Group

CB_SELECTSTRING

wParam = (WPARAM) indexStart;          // item before first selection

lParam = (LPARAM) (LPCSTR) lpszSelect; // address of prefix string

An application sends a CB_SELECTSTRING message to search the list of a combo box for an item that begins with the characters in a specified string. If a matching item is found, it is selected and copied to the edit control.

Parameters

indexStart

Value of wParam. Specifies the zero-based index of the item preceding the first item to be searched. When the search reaches the bottom of the list, it continues from the top of the list back to the item specified by the indexStart parameter. If indexStart is −1, the entire list is searched from the beginning.

lpszSelect

Value of lParam. Points to the null-terminated string that contains the prefix to search for. The search is not case sensitive, so this string can contain any combination of uppercase and lowercase letters.

Return Value

If the string is found, the return value is the index of the selected item. If the search is unsuccessful, the return value is CB_ERR and the current selection is not changed.

Remarks

A string is selected only if the characters from the starting point match the characters in the prefix string.

If you create the combo box with an owner-drawn style but without the CBS_HASSTRINGS style, what the CB_SELECTSTRING message does depends on whether you use the CBS_SORT style. If the CBS_SORT style is used, the system sends WM_COMPAREITEM messages to the owner of the combo box to determine which item matches the specified string. If you do not use the CBS_SORT style, CB_SELECTSTRING attempts to match the DWORD value against the value of the lpszSelect parameter.

See Also

CB_FINDSTRING, CB_FINDSTRINGEXACT, CB_SETCURSEL, WM_COMPAREITEM


CB_SETCURSEL
CB_SETCURSEL  QuickInfo  Overview  Group

CB_SETCURSEL

wParam = (WPARAM) index;  // item index

lParam = 0;               // not used; must be zero

An application sends a CB_SETCURSEL message to select a string in the list of a combo box. If necessary, the list scrolls the string into view. The text in the edit control of the combo box changes to reflect the new selection, and any previous selection in the list is removed.

Parameters

index

Value of wParam. Specifies the zero-based index of the string to select. If the index parameter is −1, any current selection in the list is removed and the edit control is cleared.

Return Value

If the message is successful, the return value is the index of the item selected. If index is greater than the number of items in the list or if index is set to −1, the return value is CB_ERR and the selection is cleared.

See Also

CB_FINDSTRING, CB_GETCURSEL, CB_SELECTSTRING


CB_SETDROPPEDWIDTH [New - Windows 95]
CB_SETDROPPEDWIDTH  QuickInfo

[New - Windows 95]

CB_SETDROPPEDWIDTH

wParam = (WPARAM) wWidth,     // width of list box, in pixels

lParam = 0,                   // not used, must be zero

An application sends the CB_SETDROPPEDWIDTH message to set the maximum allowable width, in pixels, of the list box of a combo box with the CBS_DROPDOWN or CBS_DROPDOWNLIST style.

Parameters

wWidth

Specifies the width of the list box, in pixels.

Return Value

If the message is successful, The return value is the new width of the list box.

If the message fails, the return value is CB_ERR.

Remarks

By default, the minimum allowable width of the drop-zdown list box is 0. The width of the list box is either the minimum allowable width or the combo box width, whichever is larger.

See Also

CB_GETDROPPEDWIDTH


CB_SETEDITSEL
CB_SETEDITSEL  QuickInfo  Overview  Group

CB_SETEDITSEL

wParam = 0;                                // not used; must be zero

lParam = MAKELPARAM((ichStart), (ichEnd);  // start and end position

An application sends a CB_SETEDITSEL message to select characters in the edit control of a combo box.

Parameters

ichStart

Value of the low-order word of lParam; this specifies the starting position. If this parameter is set to −1, the selection, if any, is removed.

ichEnd

Value of the high-order word of lParam; this specifies the ending position. If this parameter is set to −1, all text from the starting position to the last character in the edit control is selected.

Return Value

If the message succeeds, the return value is TRUE. If the message is sent to a combo box with the CBS_DROPDOWNLIST style, it is CB_ERR.

Remarks

The positions are zero-based. The first character of the edit control is in the zero position. The first character after the last selected character is in the ending position. For example, to select the first four characters of the edit control, use a starting position of 0 and an ending position of 4.

See Also

CB_GETEDITSEL


CB_SETEXTENDEDUI
CB_SETEXTENDEDUI  QuickInfo  Overview  Group

CB_SETEXTENDEDUI

wParam = (WPARAM) (BOOL) fExtended;    // extended user interface flag

lParam = 0;                            // not used; must be zero

An application sends a CB_SETEXTENDEDUI message to select either the default user interface or the extended user interface for a combo box that has the CBS_DROPDOWN or CBS_DROPDOWNLIST style.

Parameters

fExtended

Value of wParam. Specifies whether the combo box uses the extended user interface or the default user interface. A value of TRUE selects the extended user interface; a value of FALSE selects the standard user interface.

Return Value

If the operation succeeds, the return value is CB_OKAY. If an error occurs, it is CB_ERR.

Remarks

By default, the F4 key opens or closes the list and the DOWN ARROW changes the current selection. In the extended user interface, the F4 key is disabled and the DOWN ARROW key opens the drop-down list.

See Also

CB_GETEXTENDEDUI


CB_SETHORIZONTALEXTENT [New - Windows 95]
CB_SETHORIZONTALEXTENT  QuickInfo

[New - Windows 95]

CB_SETHORIZONTALEXTENT

wParam = (WPARAM) cxExtent;            // scrollable width of list box, in pixels

lParam = 0;                            // not used, must be zero

An application sends the CB_SETHORIZONTALEXTENT message to set the width, in pixels, by which a list box can be scrolled horizontally (the scrollable width). If the width of the list box is smaller than this value, the horizontal scroll bar horizontally scrolls items in the list box. If the width of the list box is equal to or greater than this value, the horizontal scroll bar is hidden or, if the combo box has the CBS_DISABLENOSCROLL style, disabled.

Parameters

cxExtent

Specifies the scrollable width of the list box, in pixels.

Return Value

No return value.

See Also

CB_GETHORIZONTALEXTENT


CB_SETITEMDATA
CB_SETITEMDATA  QuickInfo  Overview  Group

CB_SETITEMDATA

wParam = (WPARAM) index;            // item index

lParam = (LPARAM) (DWORD) dwData;   // item data

An application sends a CB_SETITEMDATA message to set the 32-bit value associated with the specified item in a combo box.

Parameters

index

Value of wParam. Specifies the item's zero-based index.

dwData

Value of lParam. Specifies the new value to be associated with the item.

Return Value

If an error occurs, the return value is CB_ERR.

Remarks

If the specified item is in an owner-drawn combo box created without the CBS_HASSTRINGS style, this message replaces the 32-bit value in the lParam parameter of the CB_ADDSTRING or CB_INSERTSTRING message that added the item to the combo box.

See Also

CB_ADDSTRING, CB_GETITEMDATA, CB_INSERTSTRING


CB_SETITEMHEIGHT
CB_SETITEMHEIGHT  QuickInfo  Overview  Group

CB_SETITEMHEIGHT

wParam = (WPARAM) index;        // item index

lParam = (LPARAM) (int) height; // item height

An application sends a CB_SETITEMHEIGHT message to set the height of list items or the selection field in a combo box.

Parameters

index

Value of wParam. Specifies the component of the combo box for which to set the height.

This parameter must be −1 to set the height of the selection field. It must be zero to set the height of list items, unless the combo box has the CBS_OWNERDRAWVARIABLE style. In that case, the index parameter is the zero-based index of a specific list item.

height

Value of lParam. Specifies the height, in pixels, of the combo box component identified by index.

Return Value

If the index or height is invalid, the return value is CB_ERR.

Remarks

The selection field height in a combo box is set independently of the height of the list items. An application must ensure that the height of the selection field is not smaller than the height of a particular list item.

See Also

CB_GETITEMHEIGHT, WM_MEASUREITEM


CB_SETLOCALE
CB_SETLOCALE  QuickInfo  Overview  Group

CB_SETLOCALE

wParam = (WPARAM) (WORD) wLocaleID; // locale identifier

lParam = 0;                         // not used; must be zero

An application sends a CB_SETLOCALE message to set the current locale of the combo box. If the combo box has the CBS_SORT style and strings are added using CB_ADDSTRING, the locale of a combo box affects how list items are sorted.

Parameters

wLocaleID

Value of wParam. Specifies the locale identifier for the combo box to use for sorting when adding text.

Return Value

The return value is the previous locale identifier. If wParam specifies a locale not installed on the system, the return value is CB_ERR and the current combo box locale is not changed.

Remarks

Use the MAKELCID macro to construct a locale identifier and the MAKELANGID macro to construct a language identifier. The language identifier is made up of a primary language identifier and a sublanguage identifier.

See Also

CB_ADDSTRING, CB_GETLOCALE, MAKELANGID, MAKELCID


CB_SETTOPINDEX [New - Windows 95]
CB_SETTOPINDEX  QuickInfo

[New - Windows 95]

CB_SETTOPINDEX

wParam = (WPARAM) index;            // zero-based index of item list

lParam = 0;                         // not used, must be zero

An application sends the CB_SETTOPINDEX message to ensure that a particular item is visible in the list box of a combo box. The system scrolls the list box contents so that either the specified item appears at the top of the list box or the maximum scroll range has been reached.

Parameters

index

Specifies the zero-based index of the list item.

Return Value

If the message is successful, the return value is zero.

If the message fails, the return value is CB_ERR.

See Also

CB_GETTOPINDEX


CB_SHOWDROPDOWN
CB_SHOWDROPDOWN  QuickInfo  Overview  Group

CB_SHOWDROPDOWN

wParam = (WPARAM) (BOOL) fShow;     // the show/hide flag

lParam = 0;                         // not used; must be zero

An application sends a CB_SHOWDROPDOWN message to show or hide the list box of a combo box that has the CBS_DROPDOWN or CBS_DROPDOWNLIST style.

Parameters

fShow

Value of wParam. Specifies whether the drop-down list box is to be shown or hidden. A value of TRUE shows the list box; a value of FALSE hides it.

Return Value

The return value is always TRUE.

Remarks

This message has no effect on a combo box created with the CBS_SIMPLE style.

See Also

CB_GETDROPPEDSTATE


CBN_CLOSEUP
CBN_CLOSEUP  QuickInfo  Overview  Group

CBN_CLOSEUP

idComboBox = (int) LOWORD(wParam);  // identifier of combo box

hwndComboBox = (HWND) lParam;       // handle of combo box

The CBN_CLOSEUP notification message is sent when the list box of a combo box has been closed. The parent window of the combo box receives this notification message through the WM_COMMAND message.

Remarks

This notification message is not sent to a combo box that has the CBS_SIMPLE style.

In general, you cannot predict the order in which notifications will be sent. In particular, a CBN_SELCHANGE notification message may occur either before or after a CBN_CLOSEUP notification message.

See Also

CBN_DROPDOWN, CBN_SELCHANGE, WM_COMMAND


CBN_DBLCLK
CBN_DBLCLK  QuickInfo  Overview  Group

CBN_DBLCLK

idComboBox = (int) LOWORD(wParam);  // identifier of combo box

hwndComboBox = (HWND) lParam;       // handle of combo box

The CBN_DBLCLK notification message is sent when the user double-clicks a string in the list box of a combo box. The parent window of the combo box receives this notification message through the WM_COMMAND message.

Remarks

This notification message occurs only for a combo box with the CBS_SIMPLE style. In a combo box with the CBS_DROPDOWN or CBS_DROPDOWNLIST style, a double-click cannot occur because a single click closes the list box.

See Also

CBN_SELCHANGE, WM_COMMAND


CBN_DROPDOWN
CBN_DROPDOWN  QuickInfo  Overview  Group

CBN_DROPDOWN

idComboBox = (int) LOWORD(wParam);  // identifier of combo box

hwndComboBox = (HWND) lParam;       // handle of combo box

The CBN_DROPDOWN notification message is sent when the list box of a combo box is about to be made visible. The parent window of the combo box receives this notification message through the WM_COMMAND message.

Remarks

This notification message can occur only for a combo box with the CBS_DROPDOWN or CBS_DROPDOWNLIST style.

See Also

CBN_CLOSEUP, WM_COMMAND


CBN_EDITCHANGE
CBN_EDITCHANGE  QuickInfo  Overview  Group

CBN_EDITCHANGE

idComboBox = (int) LOWORD(wParam);  // identifier of combo box

hwndComboBox = (HWND)lParam;        // handle of combo box

The CBN_EDITCHANGE notification message is sent after the user has taken an action that may have altered the text in the edit control portion of a combo box. Unlike the CBN_EDITUPDATE notification message, this notification message is sent after Windows updates the screen. The parent window of the combo box receives this notification message through the WM_COMMAND message.

Remarks

If the combo box has the CBS_DROPDOWNLIST style, this notification message does not occur.

See Also

CBN_EDITUPDATE, WM_COMMAND


CBN_EDITUPDATE
CBN_EDITUPDATE  QuickInfo  Overview  Group

CBN_EDITUPDATE

idComboBox = (int) LOWORD(wParam);  // identifier of combo box

hwndComboBox = (HWND) lParam;       // handle of combo box

The CBN_EDITUPDATE notification message is sent when the edit control portion of a combo box is about to display altered text. This notification message is sent after the control has formatted the text, but before it displays the text. The parent window of the combo box receives this notification message through the WM_COMMAND message.

Remarks

If the combo box has the CBS_DROPDOWNLIST style, this notification message does not occur.

See Also

CBN_EDITCHANGE, WM_COMMAND


CBN_ERRSPACE
CBN_ERRSPACE  QuickInfo  Overview  Group

CBN_ERRSPACE

idComboBox = (int) LOWORD(wParam);  // identifier of combo box

hwndComboBox = (HWND) lParam;       // handle of combo box

The CBN_ERRSPACE notification message is sent when a combo box cannot allocate enough memory to meet a specific request. The parent window of the combo box receives this notification message through the WM_COMMAND message.

See Also

WM_COMMAND


CBN_KILLFOCUS
CBN_KILLFOCUS  QuickInfo  Overview  Group

CBN_KILLFOCUS

idComboBox = (int) LOWORD(wParam);  // identifier of combo box

hwndComboBox = (HWND) lParam;       // handle of combo box

The CBN_KILLFOCUS notification message is sent when a combo box loses the keyboard focus. The parent window of the combo box receives this notification message through the WM_COMMAND message.

See Also

CBN_SETFOCUS, WM_COMMAND


CBN_SELCHANGE
CBN_SELCHANGE  QuickInfo  Overview  Group

CBN_SELCHANGE

idComboBox = (int) LOWORD(wParam);  // identifier of combo box

hwndComboBox = (HWND) lParam;       // handle of combo box

The CBN_SELCHANGE notification message is sent when the selection in the list box of a combo box is about to be changed as a result of the user either clicking in the list box or changing the selection by using the arrow keys. The parent window of the combo box receives this message through the WM_COMMAND message.

See Also

CBN_DBLCLK, WM_COMMAND


CBN_SELENDCANCEL
CBN_SELENDCANCEL  QuickInfo  Overview  Group

CBN_SELENDCANCEL

idComboBox = (int) LOWORD(wParam);  // identifier of combo box

hwndComboBox = (HWND) lParam;       // handle of combo box

The CBN_SELENDCANCEL notification message is sent when the user selects an item, but then selects another control or closes the dialog box. It indicates the user's initial selection is to be ignored. The parent window of the combo box receives this notification message through the WM_COMMAND message.

Remarks

In a combo box with the CBS_SIMPLE style, the CBN_SELENDCANCEL notification message is not sent. The CBN_SELENDOK notification message is sent immediately before every CBN_SELCHANGE notification message.

If the WS_EX_NOPARENTNOTIFY extended window style is specified for the combo box, the CBN_SELENDCANCEL notification message is not sent.

See Also

CBN_SELCHANGE, CBN_SELENDOK, WM_COMMAND


CBN_SELENDOK
CBN_SELENDOK  QuickInfo  Overview  Group

CBN_SELENDOK

idComboBox = (int) LOWORD(wParam);  // identifier of combo box

hwndComboBox = (HWND) lParam;       // handle of combo box

The CBN_SELENDOK notification message is sent when the user selects a list item, or selects an item and then closes the list. It indicates that the user's selection is to be processed. The parent window of the combo box receives this notification message through the WM_COMMAND message.

Remarks

In a combo box with the CBS_SIMPLE style, the CBN_SELENDOK notification message is sent immediately before every CBN_SELCHANGE notification message.

If the WS_EX_NOPARENTNOTIFY extended window style is specified for the combo box, the CBN_SELENDOK notification message is not sent.

See Also

CBN_SELCHANGE, CBN_SELENDCANCEL, WM_COMMAND


CBN_SETFOCUS
CBN_SETFOCUS  QuickInfo  Overview  Group

CBN_SETFOCUS

idComboBox = (int) LOWORD(wParam);  // identifier of combo box

hwndComboBox = (HWND) lParam;       // handle of combo box

The CBN_SETFOCUS notification message is sent when a combo box receives the keyboard focus. The parent window of the combo box receives this notification message through the WM_COMMAND message.

See Also

CBN_KILLFOCUS, WM_COMMAND


CDM_GETFILEPATH
CDM_GETFILEPATH  Overview  Group

CDM_GETFILEPATH

wParam = (WPARAM) cbBufSize;

lParam = (LPARAM) (LPTSTR) lpszFileBuf;

// Corresponding macro

int CommDlg_OpenSave_GetFilePath(hwndDlg, lpszFileBuf, cbBufSize);

Retrieves the path and filename of the selected file in the common Open or Save As dialog box. The common dialog box must have been created with the OFN_EXPLORER flag; otherwise, the message fails.

Parameters

hwndDlg

Handle of the common dialog box to receive the message.

lpszFileBuf

Address of the buffer that receives the filename and path.

cbBufSize

Size, in bytes, of the buffer.

Return Value

Returns the number of bytes copied to the buffer specified by lpszFileBuf, including the terminating NULL character. If the buffer is too small, the return value is the required size, in bytes, of the buffer. If the message fails, the return value is zero.


CDM_GETFOLDERIDLIST
CDM_GETFOLDERIDLIST  Overview  Group

CDM_GETFOLDERIDLIST

wParam = (WPARAM) cbBufSize;

lParam = (LPARAM) (LPVOID) pidl;

// Corresponding macro

int CommDlg_OpenSave_GetFolderIDList(hwndDlg, pidl, cbBufSize);

Retrieves the address of the item identifier list corresponding to the folder that the common Open or Save As dialog box currently has open.

Parameters

hwndDlg

Handle of the common dialog box to receive the message.

pidl

Address of the buffer that receives the list of item identifiers.

cbBufSize

Size, in bytes, of the buffer.

Return Value

Returns the number of bytes copied to the buffer specified by pidl. If the buffer is too small, the return value is the required size, in bytes, of the buffer. If the message fails, the return value is zero.


CDM_GETFOLDERPATH
CDM_GETFOLDERPATH  Overview  Group

CDM_GETFOLDERPATH

wParam = (WPARAM) cbBufSize;

lParam = (LPARAM) (LPTSTR) lpszFolderBuf;

// Corresponding macro

int CommDlg_OpenSave_GetFolderPath(hwndDlg, lpszFolderBuf, cbBufSize);

Retrieves the path and name of the currently open folder or directory for the common Open or Save As dialog box. The common dialog box must have been created with the OFN_EXPLORER flag; otherwise, the message fails.

Parameters

hwndDlg

Handle of the common dialog box to receive the message.

lpszFolderBuf

Address of the buffer that receives the path and name.

cbBufSize

Size, in bytes, of the buffer.

Return Value

Returns the number of bytes copied to the buffer specified by lpszFileBuf, including the terminating NULL character. If the buffer is too small, the return value is the required size, in bytes, of the buffer. If the message fails, the return value is zero.


CDM_GETSPEC
CDM_GETSPEC  Overview  Group

CDM_GETSPEC

wParam = (WPARAM) cbBufSize;

lParam = (LPARAM) (LPTSTR) lpszFileBuf;

// Corresponding macro

int CommDlg_OpenSave_GetSpec(hwndDlg, lpszFileBuf, cbBufSize);

Retrieves the filename (not including the path) of the currently selected file in the common Open or Save As dialog box. The common dialog box must have been created with the OFN_EXPLORER flag; otherwise, the message fails.

Parameters

hwndDlg

Handle of the common dialog box to receive the message.

lpszFileBuf

Address of the buffer that receives the path and name.

cbBufSize

Size, in bytes, of the buffer.

Return Value

Returns is the number of bytes copied to the buffer specified by lpszFileBuf, including the terminating NULL character. If the buffer is too small, the return value is the required size, in bytes, of the buffer. If the message fails, the return value is zero.


CDM_HIDECONTROL
CDM_HIDECONTROL  Overview  Group

CDM_HIDECONTROL
wParam = idCtl;
lParam = 0;

// corresponding macro
void CommDlg_OpenSave_HideControl(hdlg, idCtl);

Hides the given control.

Parameters

idCtl

Identifier of the control to hide.

Return Value

No return value.


CDM_SETCONTROLTEXT
CDM_SETCONTROLTEXT  Overview  Group

CDM_SETCONTROLTEXT
wParam = idCtl;
lParam = lpszText;

// corresponding macro
void CommDlg_OpenSave_SetControlText(hdlg, idCtl, lpszText)

Sets the text for the given control.

Parameters

idCtl

Identifier of the control to hide.

lpszText

Address of a null-terminated string specifying the new text for the control.

Return Value

No return value.


CDM_SETDEFEXT
CDM_SETDEFEXT  Overview  Group

CDM_SETDEFEXT
wParam = 0;
lParam = lpszExt;

// corresponding macro
void CommDlg_OpenSave_SetDefExt(hdlg, lpszExt)

Sets the default filename extension for the dialog box.

Parameters

lpszExt

Address of the new filename extension. Must not include the dot (.).

Return Value

No return value.


CDN_FILEOK
CDN_FILEOK  Overview  Group

CDN_FILEOK

lpon = (LPOFNOTIFY) lParam;

Sent when the Open or Save As dialog box is about to close. This notification is sent as a WM_NOTIFY message to the hook function for the dialog box.

Parameters

lpon

Address of an OFNOTIFY structure that contains file information. The structure include the address of an OPENFILENAME structure whose lpstrFile member specifies the address of the selected filename.

Remarks

The system sends this notification only if the dialog box was created using the OFN_EXPLORER value.

Return Value

Return nonzero to prevent the dialog box from closing. You must use the SetWindowLong function with the DWL_MSGRESULT value to return a result from the hook function.

See Also

OFNOTIFY, OPENFILENAME, SetWindowLong


CDN_FOLDERCHANGE
CDN_FOLDERCHANGE  Overview  Group

CDN_FOLDERCHANGE

lpon = (LPOFNOTIFY) lParam;

Sent when a new folder is opened in the Open or Save As dialog box. This notification is sent as a WM_NOTIFY message to the hook function for the dialog box.

Parameters

lpon

Address of an OFNOTIFY structure that contains file information.

The system sends this notification only if the dialog box was created using the OFN_EXPLORER value.

Return Value

The return value is ignored.

See Also

OFNOTIFY, WM_NOTIFY


CDN_HELP
CDN_HELP  Overview  Group

CDN_HELP

lpon = (LPOFNOTIFY) lParam;

Sent when the user clicks the Help button in the Open or Save As dialog box. This notification is sent as a WM_NOTIFY message to the hook function for the dialog box.

Parameters

lpon

Address of an OFNOTIFY structure that contains file information.

The system sends this notification only if the dialog box was created using the OFN_EXPLORER value.

Return Value

The return value is ignored.

See Also

OFNOTIFY, WM_NOTIFY


CDN_INITDONE
CDN_INITDONE  Overview  Group

CDN_INITDONE

lpon = (LPOFNOTIFY) lParam;

Sent when the system has finished arranging controls in the Open or Save As dialog box to make room for the controls of the child dialog box. This notification is sent as a WM_NOTIFY message to the hook function for the dialog box.

Parameters

lpon

Address of an OFNOTIFY structure that contains file information.

Return Value

The return value is ignored.

Remarks

The system sends this notification only if the dialog box was created using the OFN_EXPLORER value.

See Also

OFNOTIFY, WM_NOTIFY


CDN_SELCHANGE
CDN_SELCHANGE  Overview  Group

CDN_SELCHANGE

lpon = (LPOFNOTIFY) lParam;

Sent when the user selects a new file or folder in the file list of the common Open or Save As dialog box. This notification is sent as a WM_NOTIFY message to the hook function for the dialog box.

Parameters

lpon

Address of an OFNOTIFY structure that contains file information.

Return Value

The return value is ignored.

Remarks

The system sends this notification only if the dialog box was created using the OFN_EXPLORER value.

See Also

OFNOTIFY, WM_NOTIFY


CDN_SHAREVIOLATION
CDN_SHAREVIOLATION  Overview  Group

CDN_SHAREVIOLATION

lpon = (LPOFNOTIFY) lParam;

Sent when the Open or Save As common dialog box encounters a sharing violation on the file about to be returned. This notification is sent as a WM_NOTIFY message to the hook function for the dialog box.

Parameters

lpon

Address of an OFNOTIFY structure that contains file information. The pszFile member points to the name of the file that had the sharing violation.

Return Value

Returns one of these values:

OFN_SHAREFALLTHROUGH	Specifies that the filename is returned by the dialog box.
OFN_SHARENOWARN	Specifies no further action.
OFN_SHAREWARN	Specifies that the user receives the standard warning message for this error.
Remarks

You must use the SetWindowLong function with the DWL_MSGRESULT value to return a result from the hook function.

The system sends this notification only if the dialog box was created using the OFN_EXPLORER value.

See Also

OFNOTIFY, SetWindowLong, WM_NOTIFY


CDN_TYPECHANGE
CDN_TYPECHANGE  Overview  Group

CDN_TYPECHANGE

lpon = (LPOFNOTIFY) lParam;

Sent when the user selects a new file type from the list of file types in the Open or Save As dialog box. This notification is sent as a WM_NOTIFY message to the hook function for the dialog box.

Parameters

lpon

Address of an OFNOTIFY structure that contains file information.

Return Value

The return value is ignored.

Remarks

The system sends this notification only if the dialog box was created using the OFN_EXPLORER value.

See Also

OFNOTIFY, WM_NOTIFY


COLOROKSTRING
COLOROKSTRING  Overview  Group

msg = uColorOkMsg;
wParam = 0;
lParam = (LPCHOOSECOLOR) lpcc;

Sent to the hook function of a Color dialog box after the user has selected a color and clicked the OK button.

Parameters

uColorOkMsg

Message identifier for the ColorOk message. This value is the same as returned by the RegisterWindowMessage function for the COLOROKSTRING string.

lpcc

Address of the CHOOSECOLOR structure that contains the RGB color value of the selected color in the rgbResult member.

Return Value

Return a zero to accept the selected color and let the dialog box close; return a nonzero value to reject the color and force the dialog box to remain open.

See Also

CHOOSECOLOR, RegisterWindowMessage


CPL_DBLCLK
CPL_DBLCLK  QuickInfo  Overview  Group

CPL_DBLCLK

uAppNum = (UINT) lParam1;   // application number

lData = (LONG) lParam2;     // application-defined value

The CPL_DBLCLK message is sent to a Control Panel application when the user double-clicks the icon of a dialog box supported by the application.

Parameters

uAppNum

Value of lParam1. Specifies the dialog box number. This number must be in the range zero through one less than the value returned in response to the CPL_GETCOUNT message (CPL_GETCOUNT − 1).

lData

Value of lParam2. Specifies the value that the Control Panel application loaded into the lData member of the CPLINFO or NEWCPLINFO structure for the dialog box. The application loads lData member in response to the CPL_INQUIRE or CPL_NEWINQUIRE message.

Return Value

If a Control Panel application processes this message successfully, the return value is zero; otherwise, it is nonzero.

Remarks

In response to this message, a Control Panel application must display the corresponding dialog box.

See Also

CPL_GETCOUNT, CPL_INQUIRE, CPL_NEWINQUIRE, CPL_SELECT, CPLINFO, NEWCPLINFO


CPL_EXIT
CPL_EXIT  QuickInfo  Overview  Group

CPL_EXIT

The CPL_EXIT message is sent once to a Control Panel application before the controlling application releases the DLL containing the application.

Parameters

This function has no parameters.

Return Value

If a Control Panel application processes this message successfully, it should return zero.

Remarks

This message is sent after the last CPL_STOP message is sent.

In response to this message, a Control Panel application must free any memory that it has allocated and perform global-level cleanup.

See Also

CPL_STOP, FreeLibrary


CPL_GETCOUNT
CPL_GETCOUNT  QuickInfo  Overview  Group

CPL_GETCOUNT

The CPL_GETCOUNT message is sent to a Control Panel application to retrieve the number of dialog boxes supported by the application.

Parameters

This function has no parameters.

Return Value

A Control Panel application should return the number of dialog boxes it supports.

Remarks

This message is sent immediately after the CPL_INIT message.

See Also

CPL_INIT


CPL_INIT
CPL_INIT  QuickInfo  Overview  Group

CPL_INIT

The CPL_INIT message is sent to a Control Panel application to prompt it to perform global initialization, especially memory allocation.

Parameters

This function has no parameters.

Return Value

If initialization succeeds, a Control Panel application should return nonzero. Otherwise, it should return zero. If the application returns zero, the controlling application ends communication and releases the DLL containing the Control Panel application.

Remarks

Because this is the only way a Control Panel application can signal an error condition, the application should allocate memory in response to this message.

This message is sent immediately after the DLL containing the application is loaded.

See Also

FreeLibrary


CPL_INQUIRE
CPL_INQUIRE  QuickInfo  Overview  Group

CPL_INQUIRE

uAppNum = (UINT) lParam1;     // application number

lpcpli = (LPCPLINFO) lParam2; // structure for application info.

The CPL_INQUIRE message is sent to a Control Panel application to request information about a dialog box that the application supports.

This message has been superseded by the CPL_NEWINQUIRE message. The CPL_INQUIRE message is provided for compatibility with Windows versions 3.0 and earlier. Win32-based applications should use CPL_NEWINQUIRE.

Parameters

uAppNum

Value of lParam1. Specifies the dialog box number. This number must be in the range zero through one less than the value returned in response to the CPL_GETCOUNT message (CPL_GETCOUNT − 1).

lpcpli

Value of lParam2. Points to a CPLINFO structure. The application must fill this structure with resource identifiers for the icon, short name, description, and any user-defined value associated with the dialog box.

Return Value

If a Control Panel application processes this message successfully, it should return zero.

Remarks

This message is sent once for each dialog box supported by the Control Panel application. It is sent immediately after the CPL_GETCOUNT message. The application can perform initialization for the dialog box when it receives this message. If the application must allocate memory, it should do so in response to the CPL_INIT message.

See Also

CPL_GETCOUNT, CPL_INIT, CPL_NEWINQUIRE, CPLINFO


CPL_NEWINQUIRE
CPL_NEWINQUIRE  QuickInfo  Overview  Group

CPL_NEWINQUIRE

uAppNum = (UINT) lParam1;         // application number

lpncpli = (LPNEWCPLINFO) lParam2; // structure for appl. info.

The CPL_NEWINQUIRE message is sent to a Control Panel application to request information about a dialog box that the application supports.

Parameters

uAppNum

Value of lParam1. Specifies the dialog box number. This number must be in the range zero through one less than the value returned in response to the CPL_GETCOUNT message (CPL_GETCOUNT − 1).

lpncpli

Value of lParam2. Specifies the address of a NEWCPLINFO structure. The Control Panel application should fill this structure with information about the dialog box.

Return Value

If a Control Panel application processes this message successfully, it should return zero.

Remarks

This message is sent once for each dialog box supported by the application. It is sent immediately after the CPL_GETCOUNT message. Upon receiving this message, the application can initialize the dialog box. If the application must allocate memory, it should do so in response to the CPL_INIT message.

See Also

CPL_GETCOUNT, CPL_INIT, CPL_INQUIRE, NEWCPLINFO


CPL_SELECT
CPL_SELECT  QuickInfo  Overview  Group

CPL_SELECT

uAppNum = (UINT) lParam1;   // application number

lData = (LONG) lParam2;     // application-defined value

The CPL_SELECT message is sent to a Control Panel application when the user selects the icon of a dialog box supported by the application.

Parameters

uAppNum

Value of lParam1. Specifies the dialog box number.

lData

Value of lParam2. Specifies the value that the Control Panel application loaded into the lData member of the CPLINFO or NEWCPLINFO structure for the dialog box. The application loads the lData member in response to the CPL_INQUIRE or CPL_NEWINQUIRE message.

Return Value

If a Control Panel application processes this message successfully, it should return zero.

See Also

CPL_DBLCLK, CPL_INQUIRE, CPL_NEWINQUIRE, CPLINFO, NEWCPLINFO


CPL_STOP
CPL_STOP  QuickInfo  Overview  Group

CPL_STOP

uAppNum = (UINT) lParam1;   // application number

lData = (LONG) lParam2;     // application-defined value

The CPL_STOP message is sent once for each dialog box when the application controlling the Control Panel application closes.

Parameters

uAppNum

Value of lParam1. Specifies the dialog box number.

lData

Value of lParam2. Specifies the value that the Control Panel application loaded into the lData member of the CPLINFO or NEWCPLINFO structure for the dialog box. The application loads lData member in response to the CPL_INQUIRE or CPL_NEWINQUIRE message.

Return Value

If a Control Panel application processes this message successfully, it should return zero.

Remarks

In response to this message, a Control Panel application must perform cleanup for the given dialog box.

See Also

CPL_EXIT, CPL_GETCOUNT, CPL_INQUIRE, CPL_NEWINQUIRE, CPLINFO, NEWCPLINFO


DBT_CONFIGCHANGED [New - Windows 95]
DBT_CONFIGCHANGED  QuickInfo  Overview  Group

[New - Windows 95]

dwData = (DWORD) lParam;

The DBT_CONFIGCHANGED device message indicates that the current configuration has changed, due to a dock or undock. An application or driver that stores data in the registry under the HKEY_CURRENT_CONFIG key should update the data.

Parameters

dwData

Pointer to a DEV_BROADCAST_HDR structure identifying the device. lParam is zero.

Return Value

Return TRUE.

See Also

DEV_BROADCAST_HDR


DBT_DEVICEARRIVAL [New - Windows 95]
DBT_DEVICEARRIVAL  QuickInfo  Overview  Group

[New - Windows 95]

dwData = (DWORD) lParam;

The DBT_DEVICEARRIVAL device message is sent when a device has been inserted and is now available.

Parameters

dwData

Address of a DEV_BROADCAST_HDR structure identifying the device inserted.

Return Value

Return TRUE.

See Also

DEV_BROADCAST_HDR


DBT_DEVICEQUERYREMOVE [New - Windows 95]
DBT_DEVICEQUERYREMOVE  QuickInfo  Overview  Group

[New - Windows 95]

dwData = (DWORD) lParam;

The DBT_DEVICEQUERYREMOVE device message is sent to request permission to remove a device. Any application can deny this request and cancel the removal.

Parameters

dwData

Address of a DEV_BROADCAST_HDR structure identifying the device to remove.

Return Value

Return TRUE to grant permission, FALSE otherwise.

See Also

DEV_BROADCAST_HDR


DBT_DEVICEQUERYREMOVEFAILED [New - Windows 95]
DBT_DEVICEQUERYREMOVEFAILED  QuickInfo  Overview  Group

[New - Windows 95]

dwData = (DWORD) lParam;

The DBT_DEVICEQUERYREMOVEFAILED device message is sent when a request to remove a device has been canceled.

Parameters

dwData

Address of a DEV_BROADCAST_HDR structure identifying the device.

Return Value

Return TRUE.

See Also

DEV_BROADCAST_HDR


DBT_DEVICEREMOVECOMPLETE [New - Windows 95]
DBT_DEVICEREMOVECOMPLETE  QuickInfo  Overview  Group

[New - Windows 95]

dwData = (DWORD) lParam;

The DBT_DEVICEREMOVECOMPLETE device message is sent when a device has been removed.

Parameters

dwData

Address of a DEV_BROADCAST_HDR structure identifying the device removed.

Return Value

Return TRUE.

Remarks

The operating system may send a DBT_DEVICEREMOVECOMPLETE message without sending corresponding DBT_DEVICEQUERYREMOVE and DBT_DEVICEREMOVEPENDING messages. In such cases, the applications and drivers must recover from the loss of the device the best they can.

See Also

DBT_DEVICEQUERYREMOVE, DBT_DEVICEREMOVEPENDING, DEV_BROADCAST_HDR


DBT_DEVICEREMOVEPENDING [New - Windows 95]
DBT_DEVICEREMOVEPENDING  QuickInfo  Overview  Group

[New - Windows 95]

dwData = (DWORD) lParam;

The DBT_DEVICEREMOVEPENDING device message is sent when the device is about to be removed. This message is the last chance for applications and drivers to prepare for the removal of the device.

Parameters

dwData

Address of a DEV_BROADCAST_HDR structure identifying the device to remove.

Return Value

Return TRUE.

See Also

DEV_BROADCAST_HDR


DBT_DEVICETYPESPECIFIC [New - Windows 95]
DBT_DEVICETYPESPECIFIC  QuickInfo  Overview  Group

[New - Windows 95]

dwData = (DWORD) lParam;

The DBT_DEVICETYPESPECIFIC device message is sent when a device-specific event occurs.

Parameters

dwData

Address of a DEV_BROADCAST_HDR structure identifying the device. lParam is application-defined. May be zero.

Return Value

Return TRUE.

See Also

DEV_BROADCAST_HDR


DBT_USERDEFINED
DBT_USERDEFINED  QuickInfo

dwData = (DWORD) lParam;

The DBT_USERDEFINED device message identifies a user-defined system message. DBT_USERDEFINED is sent as the wParam parameter of the WM_DEVICECHANGE message.

dwData

Address of the user-defined data. The data must be in the format specified by the _DEV_BROADCAST_USERDEFINED structure. lParam is application-defined. May be zero.

See Also

_DEV_BROADCAST_USERDEFINED, WM_DEVICECHANGE


DL_BEGINDRAG [New - Windows NT]
DL_BEGINDRAG  QuickInfo  Overview  Group

[New - Windows NT]

DL_BEGINDRAG

idCtl = (int) wParam;

pDragInfo = (LPDRAGLISTINFO) lParam;

The DL_BEGINDRAG notification message notifies the parent window of a drag list box that the user has clicked the left mouse button on a list item. A drag list box sends DL_BEGINDRAG in the form of a drag list message.

Parameters

idCtl

Control identifier of the drag list box.

pDragInfo

Pointer to a DRAGLISTINFO structure that contains the DL_BEGINDRAG notification code, the handle to the drag list box, and the cursor position.

Return Value

The parent window should return TRUE to begin a drag operation or FALSE to prevent a drag operation.

Remarks

When processing this notification message, a window procedure typically determines the list item at the specified cursor position by using the LBItemFromPt function and then returns TRUE or FALSE, depending on whether the item should be dragged. Before returning TRUE, the window procedure should save the index of the list item, so the application knows which item to move or copy when the drag operation is completed.

See Also

DRAGLISTINFO, LBItemFromPt


DL_CANCELDRAG [New - Windows NT]
DL_CANCELDRAG  QuickInfo  Overview  Group

[New - Windows NT]

DL_CANCELDRAG

idCtl = (int) wParam;

pDragInfo = (LPDRAGLISTINFO) lParam;

The DL_CANCELDRAG notification message signals that the user has canceled a drag operation by clicking the right mouse button or pressing the ESC key. A drag list box sends DL_CANCELDRAG to its parent window in the form of a drag list message.

Parameters

idCtl

Control identifier of the drag list box.

pDragInfo

Pointer to a DRAGLISTINFO structure that contains the DL_CANCELDRAG notification code, the handle to the drag list box, and the cursor position.

Return Value

No return value.

Remarks

By processing the DL_CANCELDRAG notification message, an application can reset its internal state to indicate that dragging is not in effect.

See Also

DRAGLISTINFO


DL_DRAGGING [New - Windows NT]
DL_DRAGGING  QuickInfo  Overview  Group

[New - Windows NT]

DL_DRAGGING

idCtl = (int) wParam;

pDragInfo = (LPDRAGLISTINFO) lParam;

The DL_DRAGGING notification message signals that the user has moved the mouse while dragging an item. DL_DRAGGING is also sent periodically during dragging even if the mouse is not moved. A drag list box sends this notification to its parent window in the form of a drag list message.

Parameters

idCtl

Control identifier of the drag list box.

pDragInfo

Pointer to a DRAGLISTINFO structure that contains the DL_DRAGGING notification code, the handle to the drag list box, and the cursor position.

Return Value

The return value determines the type of mouse cursor that the drag list should set; it can be the DL_STOPCURSOR, DL_COPYCURSOR, or DL_MOVECURSOR value. If any other value is returned, the cursor does not change.

Remarks

A window procedure typically processes the DL_DRAGGING notification message by determining the item under the cursor and then drawing an insert icon. To get the item under the cursor, use the LBItemFromPt function, specifying TRUE for the bAutoScroll parameter. This option causes the drag list box to scroll periodically if the cursor is above or below its client area. To draw the insert icon, use the DrawInsert function.

See Also

DrawInsert, DRAGLISTINFO, LBItemFromPt


DL_DROPPED [New - Windows NT]
DL_DROPPED  QuickInfo  Overview  Group

[New - Windows NT]

DL_BEGINDRAG

idCtl = (int) wParam;

pDragInfo = (LPDRAGLISTINFO) lParam;

The DL_DROPPED notification message signals that the user has completed a drag operation by releasing the left mouse button. A drag list box sends DL_DROPPED to its parent window in the form of a drag list message.

Parameters

idCtl

Control identifier of the drag list box.

pDragInfo

Pointer to a DRAGLISTINFO structure that contains the DL_DROPPED notification code, the handle to the drag list box, and the cursor position.

Return Value

No return value.

Remarks

A window procedure typically processes this notification message by inserting or copying the dragged list item before the list item under the cursor. To retrieve the index of the item at the cursor position, use the LBItemFromPoint function. Note that the DL_DROPPED notification message is sent even if the cursor is not on a list item. In that case, LBItemFromPoint returns − 1.

See Also

DRAGLISTINFO


DM_GETDEFID
DM_GETDEFID  QuickInfo  Overview  Group

DM_GETDEFID

An application sends a DM_GETDEFID message to retrieve the identifier of the default push button control for a dialog box.

Parameters

This message has no parameters.

Return Value

If a default push button exists, the high-order word of the return value contains the value DC_HASDEFID and the low-order word contains the control identifier. Otherwise, the return value is zero.

Remarks

The DefDlgProc function processes this message.

See Also

DefDlgProc, DM_SETDEFID


DM_REPOSITION [New - Windows 95]
DM_REPOSITION  QuickInfo

[New - Windows 95]

DM_REPOSITION

wParam = 0;

lParam = 0;

The DM_REPOSITION message repositions a top-level dialog box so that it fits within the desktop area. An application can send this message to a dialog box after resizing it to ensure that the entire dialog box remains visible.

Parameters

This message has no parameters.

Return Value

This message has no return value.

Remarks

This message has no effect if the dialog box is a child window.


DM_SETDEFID
DM_SETDEFID  QuickInfo  Overview  Group

DM_SETDEFID

wParam = idControl; // identifier of new default push button

This message has been replaced by EM_SETLIMITTEXT. An application sends a DM_SETDEFID message to change the identifier of the default push button for a dialog box.

Parameters

idControl

Value of wParam. Specifies the identifier of a push button control that will become the default.

Remarks

This message is processed by the DefDlgProc function. To set the default push button, the function can send WM_GETDLGCODE and BM_SETSTYLE messages to the given control and the current default push button.

Using the DM_SETDEFID message can result in more than one button appearing to have the default push button state. When Windows brings up a dialog, it draws the first push button in the dialog template with the default state border. Sending a DM_SETDEFID message to change the default button will not always remove the default state border from the first push button. In these cases, the application should send a BM_SETSTYLE message to change the first push button border style.

Return Value

The return value is always TRUE.

See Also

DefDlgProc, BM_SETSTYLE, DM_GETDEFID, WM_GETDLGCODE


EM_CANPASTE [New - Windows NT]
EM_CANPASTE  QuickInfo  Overview  Group

[New - Windows NT]

EM_CANPASTE

wParam = (WPARAM) (UINT) uFormat;

lParam = 0;

The EM_CANPASTE message determines whether a rich edit control can paste a specified clipboard format.

Parameters

uFormat

Value identifying the clipboard format to try, or zero to try any format currently on the clipboard.

Return Value

Returns a nonzero value if the clipboard format can be pasted or zero otherwise.


EM_CANUNDO
EM_CANUNDO  QuickInfo  Overview  Group

EM_CANUNDO

wParam = 0; // not used; must be zero

lParam = 0; // not used; must be zero

An application sends an EM_CANUNDO message to determine whether an edit-control operation can be undone; that is, whether the control can respond to the EM_UNDO message.

Parameters

This message has no parameters.

Return Value

If the edit control can correctly process the EM_UNDO message, the return value is TRUE; otherwise, it is FALSE.

See Also

EM_UNDO


EM_CHARFROMPOS [New - Windows 95]
EM_CHARFROMPOS  QuickInfo  Overview  Group

[New - Windows 95]

EM_CHARFROMPOS

wParam = 0;

lParam = MAKELPARAM(x, y)

An application sends an EM_CHARFROMPOS message to retrieve the zero-based character index and zero-based line index of the character nearest the specified point in an edit control.

Parameters

x

Value of the low-order word of lParam. Specifies the x-coordinate of a point in the edit control's client area. The coordinate is relative to the upper-left corner of the client area.

y

Value of the high-order word of lParam. Specifies the y-coordinate of a point in the edit control's client area. The coordinate is relative to the upper-left corner of the client area.

Return Value

The return value specifies the character index in the low-order word and the line index in the high-order word. For single-line edit controls, the line index is always 0. The return value is the last character in the edit control if the given point is beyond the last character in the control. The return value is −1 if the specified point is outside the client area of the edit control.

See Also

EM_POSFROMCHAR


EM_DISPLAYBAND [New - Windows NT]
EM_DISPLAYBAND  QuickInfo  Overview  Group

[New - Windows NT]

EM_DISPLAYBAND

wParam = 0;

lParam = (LPARAM) (LPRECT) lprc;

The EM_DISPLAYBAND message displays a portion of a rich edit control's contents, as previously formatted for a device using the EM_FORMATRANGE message.

Parameters

lprc

Pointer to a RECT structure specifying the area of the device to display to.

Return Value

If the operation succeeds, the return value is TRUE.

If the operation fails, the return value is FALSE.

Remarks

Text and OLE objects are clipped by the rectangle. The application does not need to set the clipping region.

See Also

EM_FORMATRANGE, RECT


EM_EMPTYUNDOBUFFER
EM_EMPTYUNDOBUFFER  QuickInfo  Overview  Group

EM_EMPTYUNDOBUFFER

wParam = 0; // not used; must be zero

lParam = 0; // not used; must be zero

An application sends an EM_EMPTYUNDOBUFFER message to reset the undo flag of an edit control. The undo flag is set whenever an operation within the edit control can be undone.

Parameters

This message has no parameters.

Return Value

This message does not return a value.

Remarks

The undo flag is automatically reset whenever the edit control receives a WM_SETTEXT or EM_SETHANDLE message.

See Also

EM_CANUNDO, EM_SETHANDLE, EM_UNDO, WM_SETTEXT


EM_EXGETSEL [New - Windows NT]
EM_EXGETSEL  QuickInfo  Overview  Group

[New - Windows NT]

EM_EXGETSEL

wParam = 0;

lParam = (LPARAM) (CHARRANGE FAR *) lpchr;

The EM_EXGETSEL message retrieves the starting and ending character positions of the selection in a rich edit control.

Parameters

lpchr

Pointer to a CHARRANGE structure that receives the selection range.

Return Value

No return value.

See Also

CHARRANGE


EM_EXLIMITTEXT [New - Windows NT]
EM_EXLIMITTEXT  QuickInfo  Overview  Group

[New - Windows NT]

EM_EXGETSEL

wParam = 0;

lParam = (LPARAM) (DWORD) cchTextMax;

The EM_EXLIMITTEXT message sets an upper limit to the amount of text in a rich edit control.

Parameters

cchTextMax

Maximum amount of text or zero for the default maximum. An OLE object counts as a single character. The default maximum is 32K.

Return Value

No return value.


EM_EXLINEFROMCHAR [New - Windows NT]
EM_EXLINEFROMCHAR  QuickInfo  Overview  Group

[New - Windows NT]

EM_EXLINEFROMCHAR

wParam = 0;

lParam = (LPARAM) (DWORD) ichCharPos;

The EM_EXLINEFROMCHAR message determines which line contains the specified character in a rich edit control.

Parameters

ichCharPos

Zero-based index of the character.

Return Value

Returns the zero-based index of the line.


EM_EXSETSEL [New - Windows NT]
EM_EXSETSEL  QuickInfo  Overview  Group

[New - Windows NT]

EM_EXSETSEL

wParam = 0;

lParam = (LPARAM) (CHARRANGE FAR *) ichCharRange;

The EM_EXSETSEL message selects a range of characters in a rich edit control.

Parameters

ichCharPos

Zero-based index of the character.

Return Value

Returns the zero-based index of the line.


EM_FINDTEXT [New - Windows NT]
EM_FINDTEXT  QuickInfo  Overview  Group

[New - Windows NT]

EM_FINDTEXT

wParam = (WPARAM) (UINT) fuFlags;

lParam = (LPARAM) (FINDTEXT FAR *) lpFindText;

The EM_FINDTEXT message finds text within a rich edit control.

Parameters

fuFlags

Zero or more of the FT_MATCHCASE and FT_WHOLEWORD values.

lpFindText

Pointer to a FINDTEXT structure containing information about the find operation.

Return Value

Returns the zero-based character position of the next match, or  − 1 if there are no more matches.

See Also

FINDTEXT


EM_FINDTEXTEX
EM_FINDTEXTEX  Overview  Group

EM_FINDTEXTEX

wParam = (WPARAM) (UINT) fuFlags;

lParam = (LPARAM) (FINDTEXT FAR *) lpFindText;

Finds text within a rich edit control.

Parameters

fuFlags

Zero or more of the FT_MATCHCASE and FT_WHOLEWORD values.

lpFindText

Address of a FINDTEXTEX structure containing information about the find operation.

Return Value

Returns the zero-based character position of the next match or  − 1 if there are no more matches.

See Also

FINDTEXTEX


EM_FINDWORDBREAK [New - Windows NT]
EM_FINDWORDBREAK  QuickInfo  Overview  Group

[New - Windows NT]

EM_FINDWORDBREAK

wParam = (WPARAM) (UINT) code;

lParam = (LPARAM) (DWORD) ichStart;

The EM_FINDWORDBREAK message finds the next word break before or after the specified character position, or retrieves information about the character at that position.

Parameters

code

Action to take. This parameter can be one of these values:

Value	Meaning
WB_CLASSIFY	Returns the character class and word break flags of the character at the specified position.
WB_ISDELIMITER	Returns TRUE if the character at the specified position is a delimiter, or FALSE otherwise.
WB_LEFT	Finds the nearest character before the specified position that begins a word.
WB_LEFTBREAK	Finds the next word end before the specified position.
WB_MOVEWORDLEFT	Finds the next character that begins a word before the specified position. This value is used during CTRL+LEFT key processing.
WB_MOVEWORDRIGHT	Finds the next character that begins a word after the specified position. This value is used during CTRL+RIGHT key processing.
WB_RIGHT	Finds the next character that begins a word after the specified position.
WB_RIGHTBREAK	Finds the next end-of-word delimiter after the specified position.
ichStart

Zero-based character position to start from.

Return Value

Returns the character index of the word break, unless the code parameter is the WB_CLASSIFY or WB_ISDELIMITER value. For more information, see the description of the code parameter.

Remarks

If code is WB_LEFT and WB_RIGHT, the word break procedure finds word breaks only after delimiters. This matches the functionality of an edit control. If code is WB_MOVEWORDLEFT or WB_MOVEWORDRIGHT, the word break procedure also compares character classes and word break flags.

For information about character classes and word break flags, see Word and Line Breaks.


EM_FMTLINES
EM_FMTLINES  QuickInfo  Overview  Group

EM_FMTLINES

wParam = (WPARAM) (BOOL) fAddEOL;   // linebreak flag

lParam = 0;                         // not used; must be zero

An application sends an EM_FMTLINES message to set the inclusion flag of soft linebreak characters on or off within a multiline edit control. A soft linebreak consists of two carriage returns and a linefeed and is inserted at the end of a line that is broken because of wordwrapping.

Parameters

fAddEOL

Value of wParam. Specifies whether soft-linebreak characters are to be inserted. A value of TRUE inserts the characters; a value of FALSE removes them.

Return Value

The return value is identical to the fAddEOL parameter.

Remarks

This message affects only the buffer returned by the EM_GETHANDLE message and the text returned by the WM_GETTEXT message. It has no effect on the display of the text within the edit control.

The EM_FMTLINES message does not affect a line that ends with a hard linebreak. A hard linebreak consists of one carriage return and a linefeed.

Note that the size of the text changes when this message is processed.

See Also

EM_GETHANDLE, WM_GETTEXT


EM_FORMATRANGE [New - Windows NT]
EM_FORMATRANGE  QuickInfo  Overview  Group

[New - Windows NT]

EM_FORMATRANGE

wParam = (WPARAM) (BOOL) fRender;

lParam = (LPARAM) (FORMATRANGE FAR *) lpFmt;

The EM_FORMATRANGE message formats a range of text in a rich edit control for a specific device.

Parameters

fRender

Value specifying whether to render the text. If this parameter is nonzero, the text is rendered. Otherwise, the text is just measured.

lpFmt

Pointer to a FORMATRANGE structure containing information about the output device, or NULL to free information cached by the control.

This message is typically used with the EM_DISPLAYBAND message to format a rich edit control's contents for an output device such as a printer.

It is very important to free cached information after the last time you use this message. In addition, after using this message for one device, you must free cached information before using it again for a different device.

Return Value

Returns the index of the last character that fits in the region plus one.

See Also

EM_DISPLAYBAND, FORMATRANGE


EM_GETCHARFORMAT [New - Windows NT]
EM_GETCHARFORMAT  QuickInfo  Overview  Group

[New - Windows NT]

EM_GETCHARFORMAT

wParam = (WPARAM) (BOOL) fSelection;

lParam = (LPARAM) (CHARFORMAT FAR *) lpFmt;

The EM_GETCHARFORMAT message determines the current character formatting in a rich edit control.

Parameters

fSelection

Value specifying whether to get the default character formatting or the current selection's character formatting. If this parameter is zero, the default formatting is returned. Otherwise, the current selection's formatting is returned.

lpFmt

Pointer to a CHARFORMAT structure to fill in. If the selection formatting is being retrieved, the structure receives the attributes of the first character, and the dwMask member specifies which attributes are consistent throughout the entire selection.

Return Value

Returns the value of the dwMask member of the CHARFORMAT structure.

See Also

CHARFORMAT


EM_GETEVENTMASK [New - Windows NT]
EM_GETEVENTMASK  QuickInfo  Overview  Group

[New - Windows NT]

EM_GETEVENTMASK

wParam = 0;  // not used; must be zero

lParam = 0;  // not used; must be zero

The EM_GETEVENTMASK message retrieves the event mask for an rich edit control. The event mask specifies which notification messages the control sends to its parent window.

Return Value

Returns the event mask for the rich edit control.


EM_GETFIRSTVISIBLELINE
EM_GETFIRSTVISIBLELINE  QuickInfo  Overview  Group

EM_GETFIRSTVISIBLELINE

wParam = 0; // not used; must be zero

lParam = 0; // not used; must be zero

An application sends an EM_GETFIRSTVISIBLELINE message to determine the uppermost visible line in an edit control.

Parameters

This message has no parameters.

Return Value

The return value is the zero-based index of the uppermost visible line in a multiline edit control. For single-line edit controls, the return value is the zero-based index of the first visible character.


EM_GETHANDLE
EM_GETHANDLE  QuickInfo  Overview  Group

EM_GETHANDLE

wParam = 0; // not used; must be zero

lParam = 0; // not used; must be zero

An application sends an EM_GETHANDLE message to retrieve a handle of the memory currently allocated for a multiline edit control's text.

Parameters

This message has no parameters.

Return Value

The return value is a memory handle identifying the buffer that holds the content of the edit control. If an error occurs, such as sending the message to a single-line edit control, the return value is zero.

Remarks

In a 16-bit Windows-based application, the handle is a local memory handle and can be used only by functions that take a local memory handle as a parameter. The application can send this message to a multiline edit control in a dialog box only if it created the dialog box with the DS_LOCALEDIT style flag set. If the DS_LOCALEDIT style is not set, the return value is still nonzero, but the return value will not be meaningful.

See Also

EM_SETHANDLE


EM_GETIMECOLOR
EM_GETIMECOLOR  QuickInfo  Overview  Group

EM_GETIMECOLOR
wParam = (WPARAM) 0;
lParam = (LPARAM) (COMPCOLOR *) aCompColor;

Retrieves the IME composition color. This message is available only in Asian-language versions of the operating system.

Parameters

aCompColor

Address of a 4-element array of COMPCOLOR structures that receives the composition color.

Return Value

Returns nonzero if successful, zero otherwise.

See Also

COMPCOLOR


EM_GETIMEOPTIONS
EM_GETIMEOPTIONS  QuickInfo  Overview  Group

EM_GETIMEOPTIONS
wParam = (WPARAM) 0;
lParam = (LPARAM) 0;

Retrieves the current IME options. This message is available only in Asian-language versions of the operating system.

Return Value

Returns a combination of the IME option values described for the EM_SETIMEOPTIONS message.

See Also

EM_SETIMEOPTIONS


EM_GETLIMITTEXT [New - Windows 95]
EM_GETLIMITTEXT  QuickInfo  Overview  Group

[New - Windows 95]

EM_GETLIMITTEXT

wParam = 0;  // not used, must be zero

lParam = 0;  // not used, must be zero

An application sends the EM_GETLIMITTEXT message to retrieve the current text limit, in characters, for an edit control.

Parameters

This message has no parameters.

Return Value

The return value is the text limit.

See Also

EM_SETLIMITTEXT


EM_GETLINE
EM_GETLINE  QuickInfo  Overview  Group

EM_GETLINE

wParam = (WPARAM) line;          // line number to retrieve

lParam = (LPARAM) (LPCSTR) lpch; // address of buffer for line

An application sends an EM_GETLINE message to copy a line of text from an edit control and place it in a specified buffer.

Parameters

line

Value of wParam. Specifies the zero-based index of the line to retrieve from a multiline edit control. A value of zero specifies the topmost line. This parameter is ignored by a single-line edit control.

lpch

Value of lParam. Points to the buffer that receives a copy of the line. The first word of the buffer specifies the maximum number of characters that can be copied to the buffer.

Return Value

The return value is the number of characters copied. The return value is zero if the line number specified by the line parameter is greater than the number of lines in the edit control.

Remarks

The copied line does not contain a terminating null character.

See Also

EM_LINELENGTH, WM_GETTEXT


EM_GETLINECOUNT
EM_GETLINECOUNT  QuickInfo  Overview  Group

EM_GETLINECOUNT

wParam = 0; // not used; must be zero

lParam = 0; // not used; must be zero

An application sends an EM_GETLINECOUNT message to retrieve the number of lines in a multiline edit control.

Parameters

This message has no parameters.

Return Value

The return value is an integer specifying the number of lines in the multiline edit control. If no text is in the edit control, the return value is 1.

See Also

EM_GETLINE, EM_LINELENGTH


EM_GETMARGINS [New - Windows 95]
EM_GETMARGINS  QuickInfo  Overview  Group

[New - Windows 95]

EM_GETMARGINS

wParam = 0;  // not used, must be zero

lParam = 0;  // not used, must be zero

An application sends the EM_GETMARGINS message to retrieve the widths of the left and right margins for an edit control.

Parameters

This message has no parameters.

Return Value

Returns the width of the left margin in the low-order word, and the width of the right margin in the high-order word.

See Also

EM_SETMARGINS


EM_GETMODIFY
EM_GETMODIFY  QuickInfo  Overview  Group

EM_GETMODIFY

wParam = 0; // not used; must be zero

lParam = 0; // not used; must be zero

An application sends an EM_GETMODIFY message to determine whether the content of an edit control has been modified.

Parameters

This message has no parameters.

Return Value

If the content of edit control has been modified, the return value is TRUE; otherwise, it is FALSE.

Remarks

Windows maintains an internal flag indicating whether the content of the edit control has been changed. This flag is cleared when the edit control is first created; alternatively, an application can send an EM_SETMODIFY message to the edit control to clear the flag.

See Also

EM_SETMODIFY


EM_GETOLEINTERFACE [New - Windows NT]
EM_GETOLEINTERFACE  QuickInfo  Overview  Group

[New - Windows NT]

EM_GETOLEINTERFACE

wParam = 0;

lParam = (LPARAM) (LPVOID FAR *) ppObject;

The EM_GETOLEINTERFACE message retrieves an IRichEditOle object that a client can use to access a rich edit control's OLE functionality.

Parameters

ppObject

Address at which the control stores a pointer to the IRichEditOle object. The control calls the AddRef function for the object before returning, so the calling application must call the Release function when it is done with the object.

Return Value

Returns a nonzero value if successful, or zero otherwise.

See Also

IRichEditOle


EM_GETOPTIONS
EM_GETOPTIONS  QuickInfo  Overview  Group

EM_GETOPTIONS
wParam = (WPARAM) 0;
lParam = (LPARAM) 0;

Retrieves the rich edit control options.

Return Value

Returns the current option values. Can be a combination of values describedfor the EM_SETOPTIONS message.

See Also

EM_SETOPTIONS


EM_GETPARAFORMAT [New - Windows NT]
EM_GETPARAFORMAT  QuickInfo  Overview  Group

[New - Windows NT]

EM_GETPARAFORMAT

wParam = 0;

lParam = (LPARAM) (PARAFORMAT FAR *) lpFmt;

The EM_GETPARAFORMAT message retrieves the paragraph formatting of the current selection in a rich edit control.

Parameters

lpFmt

Pointer to a PARAFORMAT structure that receives the paragraph formatting attributes of the current selection.

If more than one paragraph is selected, the structure receives the attributes of the first paragraph, and the dwMask member specifies which attributes are consistent throughout the entire selection.

Return Value

Returns the value of the dwMask member of the PARAFORMAT structure.

See Also

PARAFORMAT


EM_GETPASSWORDCHAR
EM_GETPASSWORDCHAR  QuickInfo  Overview  Group

EM_GETPASSWORDCHAR

wParam = 0; // not used; must be zero

lParam = 0; // not used; must be zero

An application sends an EM_GETPASSWORDCHAR message to retrieve the password character displayed in an edit control when the user enters text.

Parameters

This message has no parameters.

Return Value

The return value specifies the character to be displayed in place of the character typed by the user. The return value is NULL if no password character exists.

Remarks

If the edit control is created with the ES_PASSWORD style, the default password character is set to an asterisk (*).

See Also

EM_SETPASSWORDCHAR


EM_GETPUNCTUATION
EM_GETPUNCTUATION  QuickInfo  Overview  Group

EM_GETPUNCTUATION
wParam = (WPARAM) (UINT) fType;
lParam = (LPARAM) (PUNCTUATION FAR *) punctTable;

Gets the current punctuation characters for the rich edit control. This message is available only in Asian-language versions of the operating system.

Parameters

fType

Punctuation type flag. Can be one of the following values:

Value	Meaning
PC_LEADING	Leading punctuation characters
PC_FOLLOWING	Following punctuation characters
PC_DELIMITER	Delimiter
The PC_OVERFLOW value is not supported.

punctTable

Address of a PUNCTUATION structure that receives the punctuation characters.

Return Value

Returns nonzero if successful; zero otherwise.

See Also

PUNCTUATION


EM_GETRECT
EM_GETRECT  QuickInfo  Overview  Group

EM_GETRECT

wParam = 0;                    // not used; must be zero

lParam (LPARAM) (LPRECT) lprc; // address of structure for rectangle

An application sends an EM_GETRECT message to retrieve the formatting rectangle of an edit control. The formatting rectangle is the limiting rectangle of the text. The limiting rectangle is independent of the size of the edit-control window.

Parameters

lprc

Value of lParam. Points to the RECT structure that receives the formatting rectangle.

Return Value

The return value is not a meaningful value.

Remarks

You can modify the formatting rectangle of a multiline edit control by using the EM_SETRECT and EM_SETRECTNP messages.

See Also

EM_SETRECT, EM_SETRECTNP, RECT


EM_GETSEL
EM_GETSEL  QuickInfo  Overview  Group

EM_GETSEL

wParam = (WPARAM) (LPDWORD) lpdwStart; // receives starting position

lParam = (LPARAM) (LPDWORD) lpdwEnd;   // receives ending position

An application sends an EM_GETSEL message to get the starting and ending character positions of the current selection in an edit control.

Parameters

lpdwStart

Value of wParam. Points to a 32-bit value that receives the starting position of the selection. This parameter can be NULL.

lpdwEnd

Value of lParam. Points to a 32-bit value that receives the position of the first nonselected character after the end of the selection. This parameter can be NULL.

Return Value

The return value is a zero-based 32-bit value with the starting position of the selection in the low-order word and the position of the first character after the last selected character in the high-order word.

See Also

EM_SETSEL


EM_GETSELTEXT [New - Windows NT]
EM_GETSELTEXT  QuickInfo  Overview  Group

[New - Windows NT]

EM_GETSELTEXT

wParam = 0;

lParam = (LPARAM) (LPSTR) lpBuf;

The EM_GETSELTEXT message retrieves the currently selected text in a rich edit control.

Parameters

lpBuf

Pointer to a buffer that receives the selected text. The calling application must ensure that the buffer is large enough to hold the selected text.

Return Value

Returns the number of characters copied, not including the terminating null character.


EM_GETTEXTRANGE [New - Windows NT]
EM_GETTEXTRANGE  QuickInfo  Overview  Group

[New - Windows NT]

EM_GETTEXTRANGE

wParam = 0;

lParam = (LPARAM) (TEXTRANGE FAR *) lpRange;

The EM_GETTEXTRANGE message retrieves a specified range of characters from a rich edit control.

Parameters

lpRange

Pointer to a TEXTRANGE structure that specifies the range of characters to retrieve and a buffer to copy the characters to.

Return Value

Returns the number of characters copied, not including the terminating null character.

See Also

TEXTRANGE


EM_GETTHUMB [New - Windows NT]
EM_GETTHUMB  QuickInfo

[New - Windows NT]

EM_GETTHUMB

wParam = 0;  // not used, must be zero

lParam = 0;  // not used, must be zero

An application sends the EM_GETTHUMB message to retrieve the position of the scroll box (thumb) in a multiline edit control.

Parameters

This message has no parameters.

Return Value

The return value is the position of the scroll box.


EM_GETWORDBREAKPROC
EM_GETWORDBREAKPROC  QuickInfo  Overview  Group

EM_GETWORDBREAKPROC

wParam = 0; // not used; must be zero

lParam = 0; // not used; must be zero

An application sends an EM_GETWORDBREAKPROC message to an edit control to retrieve the address of the current wordwrap function.

Parameters

This message has no parameters.

Return Value

The return value specifies the address of the application-defined wordwrap function. The return value is NULL if no wordwrap function exists.

Remarks

A wordwrap function scans a text buffer that contains text to be sent to the display, looking for the first word that does not fit on the current display line. The wordwrap function places this word at the beginning of the next line on the display. A wordwrap function defines the point at which Windows should break a line of text for multiline edit controls, usually at a space character that separates two words.

See Also

EditWordBreakProc, EM_FMTLINES, EM_SETWORDBREAKPROC


EM_GETWORDBREAKPROCEX
EM_GETWORDBREAKPROCEX  QuickInfo  Overview  Group

EM_GETWORDBREAKPROCEX
wParam = (WPARAM) 0;
lParam = (LPARAM) 0;

Retrieves the address of the currently registered extended word break procedure.

Return Value

Returns the address of the current procedure.


EM_GETWORDWRAPMODE
EM_GETWORDWRAPMODE  QuickInfo  Overview  Group

EM_GETWORDWRAPMODE
wParam = (WPARAM) 0;
lParam = (LPARAM) 0:

Gets the current word wrapping and word breaking options for the rich edit control. This message is available only in Asian-language versions of the operating system.

Return Value

Returns the current word wrapping and word breaking options.

Remarks

This message must not be sent by the application-defined word breaking procedure.


EM_HIDESELECTION [New - Windows NT]
EM_HIDESELECTION  QuickInfo  Overview  Group

[New - Windows NT]

EM_HIDESELECTION

wParam = (WPARAM) (BOOL) fHide;

lParam = (LPARAM) (BOOL) fChangeStyle;

The EM_HIDESELECTION message hides or shows the selection in a rich edit control.

Parameters

fHide

Value specifying whether to hide or show the selection. If this parameter is zero, the selection is shown. Otherwise, the selection is hidden.

fChangeStyle

Value specifying whether to change the control's ES_NOHIDESEL window style. If this parameter is zero, the selection is temporarily shown or hidden. Otherwise, the style is changed.

If this parameter is nonzero and the control has the focus, the selection is hidden or shown as appropriate.

Return Value

No return value.


EM_LIMITTEXT
EM_LIMITTEXT  QuickInfo

EM_LIMITTEXT

wParam = (WPARAM) cchMax;   // text length, in characters

lParam = 0;                 // not used; must be zero

An application sends an EM_LIMITTEXT message to limit the amount of text the user may enter into an edit control.

Parameters

cchMax

Value of wParam. Specifies the maximum number of characters the user can enter. If this parameter is zero, the text length is set to 0x7FFFFFFE characters for single-line edit controls or 0xFFFFFFFF for multiline edit controls.

Return Value

This message does not return a value.

Remarks

The EM_LIMITTEXT message limits only the text the user can enter. It has no effect on any text already in the edit control when the message is sent, nor does it affect the length of the text copied to the edit control by the WM_SETTEXT message. If an application uses the WM_SETTEXT message to place more text into an edit control than is specified in the EM_LIMITTEXT message, the user can edit the entire contents of the edit control.

The default limit to the amount of text a user can enter in an edit control is 30,000 characters.

See Also

WM_SETTEXT


EM_LINEFROMCHAR
EM_LINEFROMCHAR  QuickInfo  Overview  Group

EM_LINEFROMCHAR

wParam = (WPARAM) ich;  // character index

lParam = 0;             // not used; must be zero

An application sends an EM_LINEFROMCHAR message to retrieve the index of the line that contains the specified character index in a multiline edit control. A character index is the number of characters from the beginning of the edit control.

Parameters

ich

Value of wParam. Specifies the character index of the character contained in the line whose number is to be retrieved. If the ich parameter is −1, either the line number of the current line (the line containing the caret) is retrieved or, if there is a selection, the line number of the line containing the beginning of the selection is retrieved.

Return Value

The return value is the zero-based line number of the line containing the character index specified by ich.

See Also

EM_LINEINDEX


EM_LINEINDEX
EM_LINEINDEX  QuickInfo  Overview  Group

EM_LINEINDEX

wParam = (WPARAM) line; // line number

lParam = 0;             // not used; must be zero

An application sends an EM_LINEINDEX message to retrieve the character index of a line in a multiline edit control. The character index is the number of characters from the beginning of the edit control to the specified line.

Parameters

line

Value of wParam. Specifies the zero-based line number. A value of −1 specifies the current line number (the line that contains the caret).

Return Value

The return value is the character index of the line specified in the line parameter, or it is −1 if the specified line number is greater than the number of lines in the edit control.

See Also

EM_LINEFROMCHAR


EM_LINELENGTH
EM_LINELENGTH  QuickInfo  Overview  Group

EM_LINELENGTH

wParam = (WPARAM) ich;  // character index

lParam = 0;             // not used; must be zero

An application sends an EM_LINELENGTH message to retrieve the length of a line, in characters, in an edit control.

Parameters

ich

Value of wParam. Specifies the character index of a character in the line whose length is to be retrieved when EM_LINELENGTH is sent to a multiline edit control. If this parameter is −1, the message returns the number of unselected characters on lines containing selected characters. For example, if the selection extended from the fourth character of one line through the eighth character from the end of the next line, the return value would be 10 (three characters on the first line and seven on the next).

Return Value

The return value is the length, in characters, of the line specified by the ich parameter when an EM_LINELENGTH message is sent to a multiline edit control. The return value is the length, in characters, of the text in the edit control when an EM_LINELENGTH message is sent to a single-line edit control.

Remarks

Use the EM_LINEINDEX message to retrieve a character index for a given line number within a multiline edit control.

See Also

EM_LINEINDEX


EM_LINESCROLL
EM_LINESCROLL  QuickInfo  Overview  Group

EM_LINESCROLL

wParam = (WPARAM) cxScroll; // characters to scroll horizontally

lParam = (LPARAM) cyScroll; // lines to scroll vertically

An application sends an EM_LINESCROLL message to scroll the text vertically or horizontally in a multiline edit control.

Parameters

cxScroll

Value of wParam. Specifies the number of characters to scroll horizontally.

cyScroll

Value of lParam. Specifies the number of lines to scroll vertically.

Return Value

If the message is sent to a multiline edit control, the return value is TRUE; if the message is sent to a single-line edit control, the return value is FALSE.

Remarks

The edit control does not scroll vertically past the last line of text in the edit control. If the current line plus the number of lines specified by the cyScroll parameter exceeds the total number of lines in the edit control, the value is adjusted so that the last line of the edit control is scrolled to the top of the edit-control window.

The EM_LINESCROLL message can be used to scroll horizontally past the last character of any line.


EM_PASTESPECIAL [New - Windows NT]
EM_PASTESPECIAL  QuickInfo  Overview  Group

[New - Windows NT]

EM_PASTESPECIAL

wParam = (WPARAM) (UINT) uFormat;

lParam = 0;

The EM_PASTESPECIAL message pastes a specific clipboard format in a rich edit control.

Parameters

uFormat

Clipboard format to paste. For a list of clipboard formats, see SetClipboardData.

Return Value

No return value.

See Also

SetClipboardData


EM_POSFROMCHAR [New - Windows 95]
EM_POSFROMCHAR  QuickInfo  Overview  Group

[New - Windows 95]

EM_POSFROMCHAR

wParam = (WPARAM)wCharIndex;       // zero-based index of character

lParam = 0;                 // not used, must be zero

An application sends the EM_POSFROMCHAR message to retrieve the coordinates of the specified character in an edit control.

Parameters

wCharIndex

Value of wParam. Specifies the zero-based index of the character.

Return Value

The return value specifies the coordinates of the upper-left corner of the character. If wCharIndex is greater than the index of the last character in the control, the return value specifies the coordinates of the position just past the last character in the control. The x-coordinate is in the low-order word and the y-coordinate is in the high-order word. The coordinates are relative to the upper-left corner of the edit control's client area.

Remarks

For a single-line edit control, the y-coordinate is always zero. A returned coordinate can be negative if the character has been scrolled outside the edit control's client area. The coordinates are truncated to integer values.

See Also

EM_CHARFROMPOS


EM_REPLACESEL
EM_REPLACESEL  QuickInfo  Overview  Group

EM_REPLACESEL

fCanUndo = (BOOL) wParam ;          // flag that specifies whether replacement can be undone

lpszReplace = (LPCTSTR) lParam ;  // pointer to replacement text string

An application sends an EM_REPLACESEL message to replace the current selection in an edit control with the specified text.

Parameters

fCanUndo

Value of wParam. Specifies whether the replacement operation can be undone. If this is TRUE, the operation can be undone. If this is FALSE , the operation cannot be undone.

lpszReplace

Value of lParam. Points to a null-terminated string containing the replacement text.

Return Value

This message does not return a value.

Remarks

Use the EM_REPLACESEL message to replace only a portion of the text in an edit control. To replace all of the text, use the WM_SETTEXT message.

If there is no current selection, the replacement text is inserted at the current location of the caret.

See Also

WM_SETTEXT


EM_REQUESTRESIZE [New - Windows NT]
EM_REQUESTRESIZE  QuickInfo  Overview  Group

[New - Windows NT]

EM_REQUESTRESIZE

wParam = 0;

lParam = 0;

The EM_REQUESTRESIZE message forces a rich edit control to send an EN_REQUESTRESIZE notification message to its parent window.

Return Value

No return value.

Remarks

This message is useful during WM_SIZE processing for the parent of a bottomless rich edit control.

See Also

EN_REQUESTRESIZE, WM_SIZE


EM_SCROLL
EM_SCROLL  QuickInfo  Overview  Group

EM_SCROLL

wParam = (WPARAM) (INT) nScroll;    // scroll action

lParam = 0;                         // not used; must be zero

An application sends an EM_SCROLL message to scroll the text vertically in a multiline edit control. This message is equivalent to sending a WM_VSCROLL message to the edit control.

Parameters

nScroll

Value of wParam. Specifies the action the scroll bar is to take. This parameter may be one of the following values:

Value	Meaning
SB_LINEDOWN	Scrolls down one line.
SB_LINEUP	Scrolls up one line.
SB_PAGEDOWN	Scrolls down one page.
SB_PAGEUP	Scrolls up one page.
Return Value

If the message is successful, the high-order word of the return value is TRUE, and the low-order word is the number of lines that the command scrolls. The number returned may not be the same as the actual number of lines scrolled if the scrolling moves to the beginning or the end of the text. If the nScroll parameter specifies an invalid value, the return value is FALSE.

Remarks

An application should use the EM_LINESCROLL message to scroll to a specific line or character position.

An application should use the EM_SCROLLCARET message to scroll the caret into view.

See Also

EM_LINESCROLL, EM_SCROLLCARET, WM_VSCROLL


EM_SCROLLCARET
EM_SCROLLCARET  QuickInfo  Overview  Group

EM_SCROLLCARET

wParam = 0 ;    // not used now; reserved for future use; must be zero

lParam = 0 ;    // not used now; reserved for future use;  must be zero

An application sends an EM_SCROLLCARET message to scroll the caret into view in an edit control.

Parameters

wParam

This parameter is currently unused. It is reserved for future use. It should be set to zero.

lParam

This parameter is currently unused. It is reserved for future use. It should be set to zero.

Return Value

The return value is nonzero if the message is sent to an edit control.

Remarks

In previous versions of Windows, scrolling the caret into view was done by specifying wParam = FALSE in the EM_SETSEL message. A Win32-based application should use the EM_SCROLLCARET message to scroll the caret into view.

See Also

EM_SETSEL


EM_SELECTIONTYPE [New - Windows NT]
EM_SELECTIONTYPE  QuickInfo  Overview  Group

[New - Windows NT]

EM_SELECTIONTYPE

wParam = 0;

lParam = 0;

The EM_SELECTIONTYPE message determines the selection type for a rich edit control.

Return Value

Returns SEL_EMPTY if the selection is empty, or one or more of the following values:

Value	Contents of the selection
SEL_TEXT	Text
SEL_OBJECT	At least one OLE object
SEL_MULTICHAR	More than one character of text
SEL_MULTIOBJECT	More than one OLE object
Remarks

This message is useful during WM_SIZE processing for the parent of a bottomless rich edit control.

See Also

WM_SIZE


EM_SETBKGNDCOLOR [New - Windows NT]
EM_SETBKGNDCOLOR  QuickInfo  Overview  Group

[New - Windows NT]

EM_SETBKGNDCOLOR

wParam = (WPARAM) (BOOL) fUseSysColor;

lParam = (LPARAM) (COLORREF) clr;

The EM_SETBKGNDCOLOR message sets the background color for a rich edit control.

Parameters

fUseSysColor

Value specifying whether to use the system color. If this parameter is nonzero, the background is set to the window background system color. Otherwise, the background is set to the specified color.

clr

COLORREF structure specifying the color if fUseSysColor is zero.

Return Value

Returns the old background color.

See Also

COLORREF


EM_SETCHARFORMAT [New - Windows NT]
EM_SETCHARFORMAT  QuickInfo  Overview  Group

[New - Windows NT]

EM_SETCHARFORMAT

wParam = (WPARAM) (UINT) uFlags;

lParam = (LPARAM) (CHARFORMAT FAR *) lpFmt;

The EM_SETCHARFORMAT message sets character formatting in a rich edit control.

Parameters

uFlags

Character formatting that applies to the control. This parameter can be zero or more of these values:

Value	Meaning
SCF_SELECTION	Applies the formatting to the current selection, or sets the default formatting if the selection is empty.
SCF_WORD	Applies the formatting to the selected word or words. If the selection is empty but the insertion point is inside a word, the formatting is applied to the word. This value must be used in conjunction with the SCF_SELECTION value.
lpFmt

Pointer to a CHARFORMAT structure specifying the character formatting to use. Only the formatting attributes specified by the dwMask member are changed.

Return Value

Returns a nonzero value if successful or zero otherwise.

Remarks

If this parameter is zero, the default character formatting is used.

See Also

CHARFORMAT


EM_SETEVENTMASK [New - Windows NT]
EM_SETEVENTMASK  QuickInfo  Overview  Group

[New - Windows NT]

EM_SETEVENTMASK

wParam = 0;

lParam = (LPARAM) (DWORD) dwMask;

The EM_SETEVENTMASK message sets the event mask for a rich edit control. The event mask specifies which notification messages the control sends to its parent window.

Parameters

dwMask

New event mask for the rich edit control.

Return Value

Returns the previous event mask.


EM_SETHANDLE
EM_SETHANDLE  QuickInfo  Overview  Group

EM_SETHANDLE

wParam = (WPARAM) (HLOCAL) hloc; // handle of memory buffer

lParam = 0;                      // not used; must be zero

An application sends an EM_SETHANDLE message to set the handle of the memory that will be used by a multiline edit control.

Parameters

hloc

Value of wParam. Identifies the memory the edit control uses to store the currently displayed text instead of allocating its own memory. If necessary, the control reallocates this memory.

Return Value

This message does not return a value.

Remarks

Before an application sets a new memory handle, it should send an EM_GETHANDLE message to retrieve the handle of the current memory buffer and should free that memory.

An edit control automatically reallocates the given buffer whenever it needs additional space for text, or it removes enough text so that additional space is no longer needed.

Sending an EM_SETHANDLE message clears the undo buffer (EM_CANUNDO returns zero) and the internal modification flag (EM_GETMODIFY returns zero). The edit control window is redrawn.

An application can send this message to a multiline edit control in a dialog box only if it has created the dialog box with the DS_LOCALEDIT style flag set.

See Also

EM_CANUNDO, EM_GETHANDLE, EM_GETMODIFY


EM_SETIMECOLOR
EM_SETIMECOLOR  QuickInfo  Overview  Group

EM_SETIMECOLOR
wParam = (WPARAM) 0;
lParam = (LPARAM) (COMPCOLOR *) aCompColor;

Sets the IME composition color. This message is available only in Asian-language versions of the operating system.

Parameters

aCompColor

Address of a four-element array of COMPCOLOR structures that receives the composition color.

Return Value

Returns nonzero if successful, zero otherwise.

See Also

EM_GETIMECOLOR, COMPCOLOR


EM_SETIMEOPTIONS
EM_SETIMEOPTIONS  QuickInfo  Overview  Group

EM_SETIMEOPTIONS
wParam = (WPARAM) 0;
lParam = (LPARAM) (int) fOptions;

Sets the IME options. This message is available only in Asian-language versions of the operating system.

Parameters

fOptions

IME option flag. Can be a combination of the following values:

IMF_CLOSESTATUSWINDOW	Closes the IME status window when the control receives the input focus.
IMF_FORCEACTIVE	Activates the IME when the control receives the input focus.
IMF_FORCEDISABLE	Disables the IME when the control receives the input focus.
IMF_FORCEENABLE	Enables the IME when the control receives the input focus.
IMF_FORCEINACTIVE	Inactivates the IME when the control receives the input focus.
IMF_FORCENONE	Disables IME handling.
IMF_FORCEREMEMBER	Restores the previous IME status when the control receives the input focus.
Return Value

Returns nonzero if successful, zero otherwise.

See Also

EM_GETIMEOPTIONS


EM_SETLIMITTEXT [New - Windows 95]
EM_SETLIMITTEXT  QuickInfo  Overview  Group

[New - Windows 95]

EM_SETLIMITTEXT

wParam = (WPARAM) cbMax;    // new text limits, in bytes

lParam = 0;                 // not used, must be zero

An application sends the EM_SETLIMITTEXT message to set the text limit for an edit control. The text limit is the maximum amount of text, in bytes, that the edit control can contain.

Parameters

cbMax

Value of wParam. Specifies the new text limit, in bytes. If this parameter is 0, Windows sets the maximum text limit. The maximum text limit is 32,766 bytes for a single-line edit control, and 65,535 bytes for a multiline edit control.

Return Value

This message does not return a value.

Remarks

The EM_SETLIMITTEXT message replaces the EM_LIMITTEXT message.

See Also

EM_GETLIMITTEXT


EM_SETMARGINS [New - Windows 95]
EM_SETMARGINS  QuickInfo  Overview  Group

[New - Windows 95]

EM_SETMARGINS

wParam = (WPARAM) fwMargin;	// left and/or right margins

lParam = (LPARAM) MAKELONG(wLeft, wRight);	// width of left or right margins, in pixels

An application sends the EM_SETMARGINS message to set the widths of the left and right margins for an edit control. The message redraws the control to reflect the new margins.

Parameters

fwMargin

Value of wParam. Specifies the margins to set. This parameter can be a combination of the following values:

Value	Meaning
EC_LEFTMARGIN	Sets the left margin.
EC_RIGHTMARGIN	Sets the right margin.
EC_USEFONTINFO	Uses information about the current font of the edit control to set the margins. For a single-line edit control, margins are set to the average width of characters in the font. For a multiline edit control, the right margin is set to the "A" width of the font (the distance added to the current position before drawing a character), and the left margin is set to the "C" width (the distance added to the current position to provide white space to the right of a character).
If EC_USEFONTINFO is specified, the lParam parameter is ignored.

wLeft

Value of the low-order word of lParam. Specifies the width of the left margin, in pixels. This value is ignored if fwMargin does not include EC_LEFTMARGIN or if EC_USEFONTINFO is specified.

wRight

Value of the high-order word of lParam. Specifies the width of the right margin, in pixels. This value is ignored if fwMargin does not include EC_RIGHTMARGIN or if EC_USEFONTINFO is specified.

Return Value

This message does not return a value.

See Also

EM_GETMARGINS


EM_SETMODIFY
EM_SETMODIFY  QuickInfo  Overview  Group

EM_SETMODIFY

wParam = (WPARAM) (UINT) fModified;    // modification flag

lParam = 0;                            // not used; must be zero

An application sends an EM_SETMODIFY message to set or clear the modification flag for an edit control. The modification flag indicates whether the text within the edit control has been modified. It is automatically set whenever the user changes the text. An EM_GETMODIFY message can be sent to retrieve the value of the modification flag.

Parameters

fModified

Value of wParam. Specifies the new value for the modification flag. A value of TRUE indicates the text has been modified, and a value of FALSE indicates it has not been modified.

Return Value

This message does not return a value.

See Also

EM_GETMODIFY


EM_SETOLEINTERFACE [New - Windows NT]
EM_SETOLEINTERFACE  Overview  Group

[New - Windows NT]

EM_SETOLEINTERFACE

wParam = 0;

lParam = (LPARAM) (IRichEditOleCallback FAR *) lpObj;

The EM_SETOLEINTERFACE message gives a rich edit control an IRichEditOleCallback object that the control uses to get OLE-related resources and information from the client.

Parameters

lpObj

Pointer to an IRichEditOleCallback object. The control calls the AddRef function for the object before returning.

Return Value

Returns a nonzero value if successful or zero otherwise.


EM_SETOPTIONS
EM_SETOPTIONS  QuickInfo  Overview  Group

EM_SETOPTIONS
wParam = (WPARAM) (UINT) fOperation;
lParam = (LPARAM) (UINT) fOptions;

Sets the options for a rich edit control.

Parameters

fOperation

Operation flag. Can be one of these values:

ECOOP_SET	Set the options to those specified by fOptions.
ECOOP_OR	Combine the specified options with the current options.
ECOOP_AND	Retain only those current options that are also specified by fOptions.
ECOOP_XOR	Retain only those current options that are not specified by fOptions.
fOptions

Rich edit control options. Can be a combination of these values:

Value	Meaning
ECO_AUTOWORDSELECTION	Automatic selection of word on doubleclick.
ECO_AUTOVSCROLL	Same as ES_AUTOVSCROLL style.
ECO_AUTOHSCROLL	Same as ES_AUTOHSCROLL style.
ECO_NOHIDESEL	Same as ES_NOHIDESEL style.
ECO_READONLY	Same as ES_READONLY style.
ECO_WANTRETURN	Same as ES_WANTRETURN style.
ECO_SAVESEL	Same as ES_SAVESEL style.
ECO_SELECTIONBAR	Same as ES_SELECTIONBAR style.
ECO_VERTICAL	Same as ES_VERTICAL style. Available in Asian-language versions only.
Return Value

Returns current option of edit control.


EM_SETPARAFORMAT [New - Windows NT]
EM_SETPARAFORMAT  QuickInfo  Overview  Group

[New - Windows NT]

EM_SETPARAFORMAT

wParam = 0;  // not used; must be zero

lParam = (LPARAM) (PARAFORMAT FAR *) lpFmt;

The EM_SETPARAFORMAT message sets the paragraph formatting for the current selection in a rich edit control.

Parameters

lpFmt

Pointer to a PARAFORMAT structure specifying the new paragraph formatting attributes. Only the attributes specified by the dwMask member are changed.

Return Value

Returns a nonzero value if successful, or zero otherwise.

See Also

PARAFORMAT


EM_SETPASSWORDCHAR
EM_SETPASSWORDCHAR  QuickInfo  Overview  Group

EM_SETPASSWORDCHAR

wParam = (WPARAM) (UINT) ch;    // character to display

lParam = 0;                     // not used; must be zero

An application sends an EM_SETPASSWORDCHAR message to set or remove the password character for a single-line edit control when the user types text. When a password character is set, that character is displayed in place of each character the user types.

Parameters

ch

Value of wParam. Specifies the character to be displayed in place of the character typed by the user. If this parameter is zero, the characters typed by the user are displayed.

Return Value

This message does not return a value.

Remarks

When the EM_SETPASSWORDCHAR message is received by an edit control, the edit control redraws all visible characters by using the character specified by the ch parameter.

If the edit control is created with the ES_PASSWORD style, the default password character is set to an asterisk (*). This style is removed if an EM_SETPASSWORDCHAR message is sent with the ch parameter set to zero.

See Also

EM_GETPASSWORDCHAR


EM_SETPUNCTUATION
EM_SETPUNCTUATION  QuickInfo  Overview  Group

EM_SETPUNCTUATION
wParam = (WPARAM) (UINT) fType;
lParam = (LPARAM) (PUNCTUATION FAR *) punctTable;

Sets the punctuation characters for a rich edit control. This message is available only in Asian-language versions of the operating system.

Parameters

fType

Punctuation type flag. Can be one of the following values:

Value	Meaning
PC_LEADING	Leading punctuation characters.
PC_FOLLOWING	Following punctuation characters.
PC_DELIMITER	Delimiter.
The PC_OVERFLOW value is not supported.

punctTable

Address of a PUNCTUATION structure that contains the punctuation characters.

Return Value

Returns nonzero if successful; zero otherwise.

See Also

PUNCTUATION


EM_SETREADONLY
EM_SETREADONLY  QuickInfo  Overview  Group

EM_SETREADONLY

wParam = (WPARAM) (BOOL) fReadOnly;  // read-only flag

lParam = 0;                          // not used; must be zero

An application sends an EM_SETREADONLY message to set or remove the read-only style (ES_READONLY) of an edit control.

Parameters

fReadOnly

Value of wParam. Specifies whether to set or remove the ES_READONLY style. A value of TRUE sets the ES_READONLY style; a value of FALSE removes the ES_READONLY style.

Return Value

If the operation succeeds, the return value is nonzero; otherwise, it is zero.

Remarks

When an edit control has the ES_READONLY style, the user cannot change the text within the edit control.

To determine whether an edit control has the ES_READONLY style, use the GetWindowLong function with the GWL_STYLE flag.

See Also

GetWindowLong


EM_SETRECT
EM_SETRECT  QuickInfo  Overview  Group

EM_SETRECT

wParam = 0;                         // not used; must be zero

lParam = (LPARAM) (LPRECT) lprc;    // address of new rectangle

An application sends an EM_SETRECT message to set the formatting rectangle of a multiline edit control. The formatting rectangle is the limiting rectangle of the text. The limiting rectangle is independent of the size of the edit control window. When the edit control is first created, the formatting rectangle is the same as the client area of the edit control window. By using the EM_SETRECT message, an application can make the formatting rectangle larger or smaller than the edit control window.

This message is processed only by multiline edit controls.

Parameters

lprc

Value of lParam. Points to a RECT structure that specifies the new dimensions of the rectangle.

Return Value

This message does not return a value.

Remarks

The EM_SETRECT message causes the text of the edit control to be redrawn. To change the size of the formatting rectangle without redrawing the text, use the EM_SETRECTNP message.

If the edit control does not have a horizontal scroll bar, and the formatting rectangle is set to be larger than the edit control window, lines of text exceeding the width of the edit control window (but smaller than the width of the formatting rectangle) are clipped instead of wrapped.

If the edit control contains a border, the formatting rectangle is reduced by the size of the border. If you are adjusting the rectangle returned by an EM_GETRECT message, you must remove the size of the border before using the rectangle with the EM_SETRECT message.

See Also

EM_GETRECT, EM_SETRECTNP, RECT


EM_SETRECTNP
EM_SETRECTNP  QuickInfo  Overview  Group

EM_SETRECTNP

wParam = 0;                         // not used; must be zero

lParam = (LPARAM) (LPRECT) lprc;    // address of new rectangle

An application sends an EM_SETRECTNP message to set the formatting rectangle of a multiline edit control. The formatting rectangle is the limiting rectangle of the text. The limiting rectangle is independent of the size of the edit control window. When the edit control is first created, the formatting rectangle is the same as the client area of the edit control window. By using the EM_SETRECTNP message, an application can make the formatting rectangle larger or smaller than the edit control window.

The EM_SETRECTNP message is identical to the EM_SETRECT message, except that the edit control window is not redrawn.

This message is processed only by multiline edit controls.

Parameters

lprc

Value of lParam. Points to a RECT structure that specifies the new dimensions of the rectangle.

Return Value

This message does not return a value.

See Also

EM_SETRECT, RECT


EM_SETSEL
EM_SETSEL  QuickInfo  Overview  Group

EM_SETSEL

wParam = (WPARAM) (INT) nStart;    // starting position

lParam = (LPARAM) (INT) nEnd;      // ending position

An application sends an EM_SETSEL message to select a range of characters in an edit control.

Parameters

nStart

Value of wParam. Specifies the starting character position of the selection.

nEnd

Specifies the ending character position of the selection.

Return Value

This message does not return a value.

Remarks

If the nStart parameter is 0 and the nEnd parameter is −1, all the text in the edit control is selected. If nStart is −1, any current selection is removed. The caret is placed at the end of the selection indicated by the greater of the two values nEnd and nStart.

In previous versions of Windows, the wParam parameter is a flag that is set to FALSE to scroll the caret into view or set to TRUE to omit the scrolling. A Win32-based application should use the EM_SCROLLCARET message to scroll the caret into view.

In earlier versions of Windows, the starting and ending positions of the selection are indicated by the low- and high-order words, respectively, of the lParam parameter.

See Also

EM_GETSEL, EM_REPLACESEL, EM_SCROLLCARET


EM_SETTABSTOPS
EM_SETTABSTOPS  QuickInfo  Overview  Group

EM_SETTABSTOPS

wParam = (WPARAM) cTabs;             // number of tab stops

lParam = (LPARAM) (LPDWORD) lpdwTabs;  // tab stop array

An application sends an EM_SETTABSTOPS message to set the tab stops in a multiline edit control. When text is copied to the control, any tab character in the text causes space to be generated up to the next tab stop.

This message is processed only by multiline edit controls.

Parameters

cTabs

Value of wParam. Specifies the number of tab stops contained in the lpdwTabs parameter. If this parameter is zero, the lpdwTabs parameter is ignored and default tab stops are set at every 32 dialog box units. If this parameter is 1, tab stops are set at every n dialog box units, where n is the distance pointed to by the ldpwTabs parameter. If the cTabs parameter is greater than 1, lpdwTabs points to an array of tab stops.

lpdwTabs

Value of lParam. Points to an array of unsigned integers specifying the tab stops, in dialog units. If the cTabs parameter is 1, lpdwTabs points to an unsigned integer containing the distance between all tab stops, in dialog box units.

Return Value

If all the tabs are set, the return value is TRUE; otherwise, it is FALSE.

Remarks

The EM_SETTABSTOPS message does not automatically redraw the edit control window. If the application is changing the tab stops for text already in the edit control, it should call the InvalidateRect function to redraw the edit control window.

See Also

GetDialogBaseUnits, InvalidateRect


EM_SETTARGETDEVICE [New - Windows NT]
EM_SETTARGETDEVICE  QuickInfo  Overview  Group

[New - Windows NT]

EM_SETTARGETDEVICE

wParam = (WPARAM) (HDC) hdcTarget;

lParam = (LPARAM) (int) cxLineWidth;

The EM_SETTARGETDEVICE message sets the target device and line width used for WYSIWYG (what you see is what you get) formatting in a rich edit control.

Parameters

hdcTarget

Handle to a device context for the target device.

cxLineWidth

Line width to use for formatting.

Return Value

Returns a nonzero value if successful or zero otherwise.


EM_SETWORDBREAK
EM_SETWORDBREAK  QuickInfo

The EM_SETWORDBREAK message is not supported. Applications that must replace the default wordwrap function of a multiline edit control with an application-defined wordwrap function should use the EM_SETWORDBREAKPROC message.


EM_SETWORDBREAKPROC
EM_SETWORDBREAKPROC  QuickInfo  Overview  Group

EM_SETWORDBREAKPROC

wParam = 0;                                 // not used; must be zero

lParam = (LPARAM)(EDITWORDBREAKPROC)ewbprc; // function address

An application sends the EM_SETWORDBREAKPROC message to an edit control to replace the default wordwrap function with an application-defined wordwrap function.

Parameters

ewbprc

Value of lParam. Specifies the address of the application-defined wordwrap function. For more information about breaking lines, see the description of the EditWordBreakProc callback function.

Return Value

This message does not return a value.

Remarks

A wordwrap function scans a text buffer that contains text to be sent to the screen, looking for the first word that does not fit on the current screen line. The wordwrap function places this word at the beginning of the next line on the screen.

A wordwrap function defines the point at which Windows should break a line of text for multiline edit controls, usually at a space character that separates two words. Either a multiline or a single-line edit control might call this function when the user presses arrow keys in combination with the CTRL key to move the caret to the next word or previous word. The default wordwrap function breaks a line of text at a space character. The application-defined function may define the wordwrap to occur at a hyphen or a character other than the space character.

See Also

EditWordBreakProc, EM_FMTLINES, EM_GETWORDBREAKPROC


EM_SETWORDBREAKPROCEX
EM_SETWORDBREAKPROCEX  QuickInfo  Overview  Group

EM_SETWORDBREAKPROCEX
wParam = (WPARAM) 0;
lParam = (LPARAM) pfnWordBreakProcEx;

Sets the extended word-break procedure.

Parameters

pfnWordBreakprocEx

Address of an EditWordBreakProcEx function or NULL to use the default procedure.

Return Value

Returns the address of the previous extended word-break procedure.

See Also

EditWordBreakProcEx, EM_GETWORDBREAKPROCEX


EM_SETWORDWRAPMODE
EM_SETWORDWRAPMODE  QuickInfo  Overview  Group

EM_SETWORDWRAPMODE
wParam = (WPARAM) (UINT) fOptions;
lParam = (LPARAM) 0:

Sets the word-wrapping and word-breaking options for the rich edit control. This message is available only in Asian-language versions of the operating system.

Parameters

fOptions

Options flag. Can be a combination of the following values:

Value	Meaning
WBF_WORDWRAP	Enables Asian-specific word-wrap operation, such as Kinsoku in Japanese.
WBF_WORDBREAK	Enables English word-breaking operation.
WBF_OVERFLOW	Recognizes overflow punctuation. (Not currently supported.)
WBF_LEVEL1	Sets level 1 punctuation table as default.
WBF_LEVEL2	Sets level 2 punctuation table as default.
WBF_CUSTOM	Sets application-defined punctuation table.
Return Value

Returns the current word-wrapping and word-breaking options.

Remarks

This message must not be sent by the application-defined word-breaking procedure.


EM_STREAMIN [New - Windows NT]
EM_STREAMIN  QuickInfo  Overview  Group

[New - Windows NT]

EM_STREAMIN

wParam = (WPARAM) (UINT) uFormat;

lParam = (LPARAM) (EDITSTREAM FAR *) lpStream;

The EM_STREAMIN message replaces the contents of a rich edit control with the specified data stream.

Parameters

uFormat

One of the following data formats, optionally combined with the SFF_SELECTION flag:

Value	Meaning
SF_TEXT	Text
SF_RTF	Rich-text format
If the SFF_SELECTION flag is specified, the stream replaces the contents of the current selection. Otherwise, the stream replaces the entire contents of the control.

lpStream

Pointer to an EDITSTREAM structure. The control reads (streams in) the data by repeatedly calling the function specified by the structure's pfnCallback member.

Return Value

Returns the number of characters read.

See Also

EDITSTREAM


EM_STREAMOUT [New - Windows NT]
EM_STREAMOUT  QuickInfo  Overview  Group

[New - Windows NT]

EM_STREAMOUT

wParam = (WPARAM) (UINT) uFormat;

lParam = (LPARAM) (EDITSTREAM FAR *) lpStream;

The EM_STREAMOUT message writes (streams out) the contents of a rich edit control to the specified data stream.

Parameters

uFormat

Value specifying one of the following data formats, optionally combined with the SFF_SELECTION flag:

Value	Meaning
SF_TEXT	Text with spaces in place of OLE objects
SF_RTF	Rich-text format (RTF)
SF_RTFNOOBJS	RTF with spaces in place of OLE object.
SF_TEXTIZED	Text with a text representation of OLE objects.
The SF_RTFNOOBJS option is useful if an application stores OLE objects itself, as RTF representation of OLE objects is not very compact.

If the SFF_SELECTION flag is specified, only the contents of the current selection are streamed out. Otherwise, the entire contents of the control are streamed out.

lpStream

Pointer to an EDITSTREAM structure. The control streams out the data by repeatedly calling the function specified by the structure's pfnCallback member.

Return Value

Returns the number of characters written to the data stream.

See Also

EDITSTREAM


EM_UNDO
EM_UNDO  QuickInfo  Overview  Group

EM_UNDO

wParam = 0; // not used; must be zero

lParam = 0; // not used; must be zero

An application sends an EM_UNDO message to undo the last edit control operation.

Parameters

This message has no parameters.

Return Value

For a single-line edit control, the return value is always TRUE. For a multiline edit control, the return value is TRUE if the undo operation is successful, or FALSE if the undo operation fails.

Remarks

An undo operation can also be undone. For example, you can restore deleted text with the first EM_CANUNDO message, and remove the text again with a second EM_CANUNDO message as long as there is no intervening edit operation.

See Also

EM_CANUNDO


EN_CHANGE
EN_CHANGE  QuickInfo  Overview  Group

EN_CHANGE

idEditCtrl = (int) LOWORD(wParam); // identifier of edit control

hwndEditCtrl = (HWND) lParam;      // handle of edit control

The EN_CHANGE notification message is sent when the user has taken an action that may have altered text in an edit control. Unlike the EN_UPDATE notification message, this notification message is sent after Windows updates the screen. The parent window of the edit control receives this notification message through the WM_COMMAND message.

See Also

EN_UPDATE, WM_COMMAND


EN_CORRECTTEXT
EN_CORRECTTEXT  Overview  Group

EN_CORRECTTEXT
wParam = (WPARAM) (UINT) uID;
lParam = (LPARAM) (ENCORRECTTEXT FAR *) lpEnCorrectText;

Notifies a rich edit control's parent window that a SYV_CORRECT gesture occurred. A rich edit control sends this notification message in the form of a WM_NOTIFY message.

Parameters

uID

Identifier of the rich edit control.

lpEnCorrectText

Pointer to an ENCORRECTTEXT structure specifying the selection to be corrected.

Return Value

Returns zero to ignore the action, nonzero to process it.

Remarks

This message is sent only if pen capabilities are available.

See Also

ENCORRECTTEXT, WM_NOTIFY


EN_DROPFILES [New - Windows NT]
EN_DROPFILES  QuickInfo  Overview  Group

[New - Windows NT]

EN_DROPFILES

wParam = (WPARAM) (UINT) uID;

lParam = (LPARAM) (ENDROPFILES FAR *) lpEnDropFiles;

The EN_DROPFILE notification message notifies a rich edit control's parent window that the user is attempting to drop files into the control. A rich edit control sends this notification message in the form of a WM_NOTIFY message when it receives the WM_DROPFILES message.

Parameters

uID

Identifier of the rich edit control.

lpEnDropFiles

Pointer to an ENDROPFILES structure.

Return Value

Returns a nonzero value to allow the drop operation or zero to ignore the drop.

Remarks

For a rich edit control to receive WM_DROPFILES messages, the parent window must register the control as a drop target by using the DragAcceptFiles function. The control does not register itself.

See Also

DragAcceptFiles, ENDROPFILES, WM_DROPFILES, WM_NOTIFY


EN_ERRSPACE
EN_ERRSPACE  QuickInfo  Overview  Group

EN_ERRSPACE

idEditCtrl = (int) LOWORD(wParam); // identifier of edit control

hwndEditCtrl = (HWND) lParam;      // handle of edit control

The EN_ERRSPACE notification message is sent when an edit control cannot allocate enough memory to meet a specific request. The parent window of the edit control receives this notification message through the WM_COMMAND message.

See Also

WM_COMMAND


EN_HSCROLL
EN_HSCROLL  QuickInfo  Overview  Group

EN_HSCROLL

idEditCtrl = (int) LOWORD(wParam); // identifier of edit control

hwndEditCtrl = (HWND) lParam;      // handle of edit control

The EN_HSCROLL notification message is sent when the user clicks an edit control's horizontal scroll bar. The parent window of the edit control receives this notification message through the WM_COMMAND message. The parent window is notified before the screen is updated.

See Also

EN_VSCROLL, WM_COMMAND


EN_IMECHANGE
EN_IMECHANGE  Overview  Group

EN_IMECHANGE
wParam = (WPARAM) (UINT) uID;
lParam = (LPARAM) 0;

Notifies a rich edit control's parent that the IME conversion status has changed. This message is available only for Asian-language versions of the operating system.

Parameters

uID

Identifier of the rich edit control.

Return Value

Returns zero.


EN_KILLFOCUS
EN_KILLFOCUS  QuickInfo  Overview  Group

EN_KILLFOCUS

idEditCtrl = (int) LOWORD(wParam); // identifier of edit control

wNotifyCode = HIWORD(wParam);      // notification code

hwndEditCtrl = (HWND) lParam;      // handle of edit control

The EN_KILLFOCUS notification message is sent when an edit control loses the keyboard focus. The parent window of the edit control receives this notification message through the WM_COMMAND message.

Remarks

In previous versions of Windows, the notification code was in HIWORD(lParam).

See Also

EN_SETFOCUS, WM_COMMAND


EN_MAXTEXT
EN_MAXTEXT  QuickInfo  Overview  Group

EN_MAXTEXT

idEditCtrl = (int) LOWORD(wParam); // identifier of edit control

hwndEditCtrl = (HWND) lParam;      // handle of edit control

The EN_MAXTEXT notification message is sent when the current text insertion has exceeded the specified number of characters for the edit control. The text insertion has been truncated.

This message is also sent when an edit control does not have the ES_AUTOHSCROLL style and the number of characters to be inserted would exceed the width of the edit control.

This message is also sent when an edit control does not have the ES_AUTOVSCROLL style and the total number of lines resulting from a text insertion would exceed the height of the edit control.

The parent window of the edit control receives this notification message through the WM_COMMAND message.

See Also

WM_COMMAND


EN_MSGFILTER [New - Windows NT]
EN_MSGFILTER  QuickInfo  Overview  Group

[New - Windows NT]

EN_MSGFILTER

wParam = (WPARAM) (UINT) uID;

lParam = (LPARAM) (MSGFILTER) lpMsgFilter;

The EN_MSGFILTER notification message notifies a rich edit control's parent window of a keyboard or mouse event in the control. A rich edit control sends this notification message in the form of a WM_NOTIFY message.

Parameters

uID

Identifier of the rich edit control.

lpMsgFilter

Pointer to a MSGFILTER structure containing information about the keyboard or mouse message. If the parent window modifies this structure and returns a nonzero value, the modified message is processed instead of the original one.

Return Value

Returns a nonzero value if the control should process the event, or zero if the control should ignore the event.

See Also

MSGFILTER, WM_NOTIFY


EN_OLEOPFAILED
EN_OLEOPFAILED  QuickInfo  Overview  Group

EN_OLEOPFAILED
wParam = (WPARAM) (UINT) uID;
lParam = (LPARAM) (ENOLEOPFAILED *) lpeoof;

Notifies a rich edit control's parent window that a user action on an OLE object has failed.

Parameters

uID

Identifier of the rich edit control.

lpeoof

Pointer to an ENOLEOPFAILED structure that contains information about the failure.

Return Value

Returns zero.

ENOLEOPFAILED


EN_PROTECTED [New - Windows NT]
EN_PROTECTED  QuickInfo  Overview  Group

[New - Windows NT]

EN_PROTECTED

wParam = (WPARAM) (UINT) uID;

lParam = (LPARAM) (ENPROTECTED FAR *) lpEnProtected;

The EN_PROTECTED notification message notifies a rich edit control's parent window that the user is taking an action that would change a protected range of text. A rich edit control sends this notification message in the form of a WM_NOTIFY message.

Parameters

uID

Identifier of the rich edit control.

lpEnProtected

Pointer to an ENPROTECTED structure containing information about the message that triggered the notification.

Return Value

Returns zero to allow the operation or a nonzero value to prevent it.

Remarks

If zero is returned and the msg, wParam, and lParam members of the ENPROTECTED structure are changed, the control processes the revised message instead of the original message.

See Also

ENPROTECTED, WM_NOTIFY


EN_REQUESTRESIZE [New - Windows NT]
EN_REQUESTRESIZE  QuickInfo  Overview  Group

[New - Windows NT]

EN_REQUESTRESIZE

wParam = (WPARAM) (UINT) uID;

lParam = (LPARAM) (REQRESIZE FAR *) lpReSize;

The EN_REQUESTRESIZE notification message notifies a rich edit control's parent window that the control's contents are either smaller or larger than the control's window size. A rich edit control sends this notification message in the form of a WM_NOTIFY message.

Parameters

uID

Identifier of the rich edit control.

lpReSize

Pointer to a REQRESIZE structure.

Return Value

No return value.

Remarks

To support the bottomless behavior of a rich edit control, the parent window must resize the control when it receives this notification message.

See Also

REQRESIZE, WM_NOTIFY


EN_SAVECLIPBOARD
EN_SAVECLIPBOARD  QuickInfo  Overview  Group

EN_SAVECLIPBOARD
wParam = (WPARAM) (UINT) uID;
lParam = (LPARAM) (ENSAVECLIPBOARD *) lpesc;

Notifies the rich edit control's parent window that the control is closing and the clipboard contains information.

Parameters

uID

Identifier of the rich edit control.

lpesc

Pointer to an ENSAVECLIPBOARD structure that contains information about clipboard information.

Return Value

Returns zero if the clipboard should be made available to other applications, nonzero if the clipboard should not be saved.

See Also

ENSAVECLIPBOARD


EN_SELCHANGE [New - Windows NT]
EN_SELCHANGE  QuickInfo  Overview  Group

[New - Windows NT]

EN_SELCHANGE

wParam = (WPARAM) (UINT) uID;

lParam = (LPARAM) (SELCHANGE FAR *) lpSelChange;

The EN_SELCHANGE notification message notifies a rich edit control's parent window that the current selection has changed. A rich edit control sends this notification message in the form of a WM_NOTIFY message.

Parameters

uID

Identifier of the rich edit control.

lpSelChange

Pointer to a SELCHANGE structure.

Return Value

No return value.

See Also

SELCHANGE, WM_NOTIFY


EN_SETFOCUS
EN_SETFOCUS  QuickInfo  Overview  Group

EN_SETFOCUS

idEditCtrl = (int) LOWORD(wParam); // identifier of edit control

wNotifyCode = HIWORD(wParam);      // notification code

hwndEditCtrl = (HWND) lParam;      // handle of edit control

The EN_SETFOCUS notification message is sent when an edit control receives the keyboard focus. The parent window of the edit control receives this notification message through the WM_COMMAND message.

Remarks

In previous versions of Windows, the notification code was in HIWORD(lParam).

See Also

EN_KILLFOCUS, WM_COMMAND


EN_STOPNOUNDO
EN_STOPNOUNDO  QuickInfo  Overview  Group

EN_STOPNOUNDO
wParam = (WPARAM) (UINT) uID;
lParam = (LPARAM) (NMHDR FAR *) lpNmHdr;

Notifies a rich edit control's parent window that an action occurred for which the control cannot allocate enough memory to maintain the undo state. A rich edit control sends this notification message in the form of a WM_NOTIFY message.

Parameters

uID

Identifier of the rich edit control.

lpNmHdr

Pointer to an NMHDR structure.

Return Value

Returns zero to continue the action, nonzero to stop it.

See Also

NMHDR, WM_NOTIFY


EN_UPDATE
EN_UPDATE  QuickInfo  Overview  Group

EN_UPDATE

idEditCtrl = (int) LOWORD(wParam); // identifier of edit control

hwndEditCtrl = (HWND) lParam;      // handle of edit control

The EN_UPDATE notification message is sent when an edit control is about to display altered text. This notification message is sent after the control has formatted the text, but before it displays the text. This makes it possible to resize the edit control window, if necessary. The parent window of the edit control receives this notification message through the WM_COMMAND message.

See Also

EN_CHANGE, WM_COMMAND


EN_VSCROLL
EN_VSCROLL  QuickInfo  Overview  Group

EN_VSCROLL

idEditCtrl = (int) LOWORD(wParam); // identifier of edit control

hwndEditCtrl = (HWND) lParam;      // handle of edit control

The EN_VSCROLL notification message is sent when the user clicks an edit control's vertical scroll bar. The parent window of the edit control receives this notification message through the WM_COMMAND message. The parent window is notified before the screen is updated.

See Also

EN_HSCROLL, WM_COMMAND


FILEOKSTRING
FILEOKSTRING  Overview  Group

msg = uFileOkMsg;
wParam = 0;
lParam = (LPOPENFILENAME) lpofn;

Sent to the hook function of a Open or Save As dialog box after the user has selected a filename and clicked the OK button. This message has been superseded by the CDN_FILEOK message.

Parameters

uFileOkMsg

Message identifier for the FileOk message. This value is the same as returned by the RegisterWindowMessage function for the FILEOKSTRING string.

lpofn

Address of the OPENFILENAME structure that contains the selected filename in the lpstrFile member.

Return Value

Return zero to accept the filename and let the dialog box close; return the value 1 to reject the filename and force the dialog box to remain open.

See Also

OPENFILENAME, RegisterWindowMessage


FINDMSGSTRING
FINDMSGSTRING  Overview  Group

msg = uFindMsg;
wParam = 0;
lParam = (LPFINDREPLACE) lpfr;

Sent to the window procedure of the owner window of a Find or Replace dialog box after the user has clicked the OK button.

Parameters

uFindMsg

Message identifier for the Find message. This value is the same as returned by the RegisterWindowMessage function for the FINDMSGSTRING string.

lpfr

Address of the FINDREPLACE structure that contains the information to use to carry out the search or replacement.

Return Value

No return value.

Remarks

The Flags member of the FINDREPLACE structure is set to FR_DIALOGTERM when the user has closed the dialog box.

See Also

FINDREPLACE, RegisterWindowMessage


FM_GETDRIVEINFO
FM_GETDRIVEINFO  QuickInfo

FM_GETDRIVEINFO

wParam = 0;                                        // not used, must be zero

lParam = (LPARAM) (LPFMS_GETDRIVEINFO) lpfmsgdi;   // drive data

A File Manager extension sends an FM_GETDRIVEINFO message to retrieve drive information from the active File Manager window.

Parameters

lpfmsgdi

Value of lParam. Points to an FMS_GETDRIVEINFO structure that receives drive information.

Return Value

The return value is always nonzero.

Remarks

If 0xFFFFFFFF is returned in the dwTotalSpace or dwFreeSpace member of the FMS_GETDRIVEINFO structure, the extension library must compute the value or values.

See Also

FMExtensionProc, FMS_GETDRIVEINFO


FM_GETFILESEL
FM_GETFILESEL  QuickInfo

FM_GETFILESEL

wParam = (WPARAM) index;                            // index of selected file

lParam = (LPARAM) (LPFMS_GETFILESEL) lpfmsgfs;      // file data

A File Manager extension sends an FM_GETFILESEL message to retrieve information about a selected file from the active File Manager window (either the directory window or the Search Results window).

Parameters

index

Value of wParam. Specifies the zero-based index of the selected file to retrieve.

lpfmsgfs

Value of lParam. Points to an FMS_GETFILESEL structure that receives information about the selection.

Return Value

The return value is the zero-based index of the selected file that was retrieved.

Remarks

An extension can use the FM_GETSELCOUNT message to get the count of selected files.

See Also

FMExtensionProc, FMS_GETFILESEL, FM_GETFILESELLFN, FM_GETSELCOUNT, FM_GETSELCOUNTLFN


FM_GETFILESELLFN
FM_GETFILESELLFN  QuickInfo

FM_GETFILESELLFN

wParam = (WPARAM) index;                       // index of selected file

lParam = (LPARAM) (LPFMS_GETFILESEL) lpfmsgfs; // selection data

A File Manager extension sends an FM_GETFILESELLFN message to retrieve information about a selected file from the active File Manager window (either the directory window or the Search Results window). The selected file can have a long filename.

Parameters

index

Value of wParam. Specifies the zero-based index of the selected file to retrieve.

lpfmsgfs

Value of lParam. Points to an FMS_GETFILESEL structure that receives information about the selection.

Return Value

The return value is the zero-based index of the selected file that was retrieved.

Remarks

Only extensions that support long filenames (for example, network-aware extensions) should use this message.

An extension can use the FM_GETSELCOUNT message to get the count of selected files.

See Also

FMExtensionProc, FM_GETFILESEL, FM_GETSELCOUNT, FM_GETSELCOUNTLFN


FM_GETFOCUS
FM_GETFOCUS  QuickInfo

FM_GETFOCUS

wParam = 0;     // not used, must be zero

lParam = 0;     // not used, must be zero

A File Manager extension sends a FM_GETFOCUS message to retrieve the type of the File Manager window that has the input focus.

Parameters

This message has no parameters.

Return Value

The return value is the type of File Manager window that has input focus. It can be one of the following values:

Value	Meaning
FMFOCUS_DIR	Directory portion of a directory window
FMFOCUS_TREE	Tree portion of a directory window
FMFOCUS_DRIVES	Drive bar of a directory window
FMFOCUS_SEARCH	Search Results window


FM_GETSELCOUNT
FM_GETSELCOUNT  QuickInfo

FM_GETSELCOUNT

wParam = 0; // not used, must be zero

lParam = 0; // not used, must be zero

A File Manager extension sends a FM_GETSELCOUNT message to retrieve a count of the selected files in the active File Manager window (either the directory window or the Search Results window).

Parameters

This message has no parameters.

Return Value

The return value is the number of selected files.

See Also

FM_GETFILESEL, FM_GETFILESELLFN, FM_GETSELCOUNTLFN


FM_GETSELCOUNTLFN
FM_GETSELCOUNTLFN  QuickInfo

FM_GETSELCOUNTLFN

wParam = 0; // not used, must be zero

lParam = 0; // not used, must be zero

A File Manager extension sends an FM_GETSELCOUNTLFN message to retrieve the number of selected files in the active File Manager window (either the directory window or the Search Results window). The count includes files that have long filenames.

Parameters

This message has no parameters.

Return Value

The return value is the number of selected files.

Remarks

Only extensions that support long filenames (for example, network-aware extensions) should use this message.

See Also

FM_GETFILESEL, FM_GETFILESELLFN, FM_GETSELCOUNT


FM_REFRESH_WINDOWS
FM_REFRESH_WINDOWS  QuickInfo

FM_REFRESH_WINDOWS

wParam = (WPARAM) (BOOL) fRepaint;  // repaint flag

lParam = 0;                         // not used, must be zero

A File Manager extension sends an FM_REFRESH_WINDOWS message to cause File Manager to repaint either its active window or all of its windows.

Parameters

fRepaint

Value of wParam. Specifies whether File Manager repaints its active window or all of its windows. If this parameter is TRUE, File Manager repaints all of its windows. Otherwise, File Manager repaints only its active window.

Return Value

This message does not return a meaningful value.

Remarks

File-system changes caused by an extension are automatically detected by File Manager. An extension should use this message only in situations where drive connections are made or canceled.

See Also

FMExtensionProc


FM_RELOAD_EXTENSIONS
FM_RELOAD_EXTENSIONS  QuickInfo

FM_RELOAD_EXTENSIONS

wParam = 0; // not used, must be zero

lParam = 0; // not used, must be zero

A File Manager extension (or another application) sends an FM_RELOAD_EXTENSIONS message to cause File Manager to reload all extension DLLs listed in the [AddOns] section of the WINFILE.INI file.

Parameters

This message has no parameters.

Return Value

This message does not return a meaningful value.

Remarks

Other applications can use the PostMessage function to send this message to File Manager. To obtain the appropriate File Manager window handle, an application can specify "WFS_Frame" as the lpszClassName parameter in a call to the FindWindow function.

See Also

FindWindow, FMExtensionProc, PostMessage


FMEVENT_HELPMENUITEM
FMEVENT_HELPMENUITEM  QuickInfo

FMEVENT_HELPMENUITEM

uItem = (UINT) lParam;  /* command item for which help is sought */

The FMEVENT_HELPMENUITEM message is sent to a File Manager extension DLL procedure when the user presses F1 on a menu or toolbar command item. The extension should call WinHelp, with that function's hwnd parameter set to the value of the extension procedure's hwnd parameter.

Parameters

uItem

Identifies the menu or toolbar command item for which help is sought. The extension procedure uses this value to determine how best to call WinHelp.

Return Value

An extension DLL procedure should return zero if it processes this message.

See Also

FMExtensionProc, WinHelp, FMEVENT_HELPSTRING


FMEVENT_HELPSTRING
FMEVENT_HELPSTRING  QuickInfo

FMEVENT_HELPSTRING

lpfmshs = (LPFMS_HELPSTRING) lParam;  /* pointer to data transfer structure */

The FMEVENT_HELPSTRING message is sent to a File Manager extension DLL procedure when File Manager wants a help string for a menu or toolbar command item.

Parameters

lpfmshs

Points to an FMS_HELPSTRING structure that communicates command item help string data.

The FMS_HELPSTRING structure identifies the command item for which a help string is wanted, along with a handle to its menu. An application then writes the appropriate help string to the FMS_HELPSTRING structure's szHelp member.

Return Value

An extension DLL procedure should return zero if it processes this message.

See Also

FMExtensionProc, FMEVENT_HELPMENUITEM


FMEVENT_INITMENU
FMEVENT_INITMENU  QuickInfo

FMEVENT_INITMENU

hmenu = (HMENU) lParam; /* handle of File Manager menu */

The FMEVENT_INITMENU message is sent to an extension DLL when the user selects the menu for the extension from the File Manager menu bar. The extension can use this notification to initialize menu items in the menu.

Parameters

hmenu

Specifies the handle of the File Manager menu bar.

Return Value

An extension DLL should return zero if it processes this message.

Remarks

An extension DLL receives this message only when the user selects the top-level menu. If the extension contains submenus, it must initialize them at the same time it initializes the top-level menu.

See Also

FMExtensionProc


FMEVENT_LOAD
FMEVENT_LOAD  QuickInfo

FMEVENT_LOAD

lpfmsld = (LPFMS_LOAD) lParam;  /* address of struct. with delta */

The FMEVENT_LOAD message is sent to an extension DLL when File Manager is loading the DLL.

Parameters

lpfmsld

Points to an FMS_LOAD structure that specifies the menu-item delta value. An extension DLL should save the menu-item delta value and fill the other structure members with information about the extension.

Return Value

An extension DLL must return TRUE to continue loading the DLL. If the DLL returns FALSE, File Manager calls the FreeLibrary function and ends any communication with the extension DLL.

Remarks

An application should fill the dwSize, szMenuName, and hMenu members in the FMS_LOAD structure. It should also save the value of the wMenuDelta member and use it to identify menu items when modifying the menu.

See Also

FMExtensionProc, FMS_LOAD, FreeLibrary


FMEVENT_SELCHANGE
FMEVENT_SELCHANGE  QuickInfo

FMEVENT_SELCHANGE

The FMEVENT_SELCHANGE message is sent to an extension DLL when the user selects a filename in the File Manager directory window or Search Results window.

Parameters

This message has no parameters.

Return Value

An extension DLL should return zero if it processes this message.

Remarks

Changes in the tree portion of the directory window do not produce this message.

Because the user can change the selection many times, the extension DLL must return promptly after processing this message to avoid slowing the selection process for the user.

See Also

FMExtensionProc


FMEVENT_TOOLBARLOAD
FMEVENT_TOOLBARLOAD  QuickInfo

FMEVENT_TOOLBARLOAD

lpfmstbl = (LPFMS_TOOLBARLOAD) lParam;   /* toolbar data */

The FMEVENT_TOOLBARLOAD message is sent to an extension DLL when File Manager is loading its toolbar. This message allows an extension DLL to add a button to the File Manager toolbar.

Parameters

lpfmstbl

Points to an FMS_TOOLBARLOAD structure. If the extension DLL adds a button to the toolbar in File Manager, the DLL should fill the structure with information about the button.

.

Return Value

An extension DLL must return TRUE to add the button to the toolbar. If the DLL returns FALSE, File Manager does not add the button.

See Also

FMExtensionProc, FMS_TOOLBARLOAD


FMEVENT_UNLOAD
FMEVENT_UNLOAD  QuickInfo

FMEVENT_UNLOAD

The FMEVENT_UNLOAD message is sent to an extension DLL when File Manager is unloading the DLL.

Parameters

This message has no parameters.

Return Value

An extension DLL should return zero if it processes this message.

Remarks

The hwnd and hMenu values passed with the FMEVENT_LOAD and FMEVENT_INITMENU messages may not be valid at the time this message is sent.

See Also

FMExtensionProc


FMEVENT_USER_REFRESH
FMEVENT_USER_REFRESH  QuickInfo

FMEVENT_USER_REFRESH

The FMEVENT_USER_REFRESH message is sent to an extension DLL when the user chooses the Refresh command from the Window menu in File Manager. The extension can use this notification to update its menu.

Parameters

This message has no parameters.

Return Value

An extension DLL should return zero if it processes this message.

See Also

FMExtensionProc


HDM_DELETEITEM [New - Windows NT]
HDM_DELETEITEM  QuickInfo  Overview  Group

[New - Windows NT]

HDM_DELETEITEM

wParam = (WPARAM) (int) index;

lParam = 0;

// Corresponding macro

BOOL Header_DeleteItem(hwndHD, index);

The HDM_DELETEITEM message deletes an item from a header control.

Parameters

hwndHD

Handle to the header control.

index

Index of the item to delete.

Return Value

If the operation succeeds, the return value is TRUE.

If the operation fails, the return value is FALSE.


HDM_GETITEM [New - Windows NT]
HDM_GETITEM  QuickInfo  Overview  Group

[New - Windows NT]

HDM_GETITEM

wParam = (WPARAM) (int) index;

lParam = (LPARAM) (HD_ITEM FAR*) phdi;

// Corresponding macro

BOOL Header_GetItem(hwndHD, index, phdi);

The HDM_GETITEM message retrieves information about an item in a header control.

Parameters

hwndHD

Handle to the header control.

index

Index of the item for which information is to be retrieved.

phdi

Pointer to an HD_ITEM structure. When the message is sent, the mask member indicates the type of information being requested. When the message returns, the other members receive the requested information. If the mask member specifies zero, the message returns TRUE but copies no information to the structure.

Return Value

If the operation succeeds, the return value is TRUE.

If the operation fails, the return value is FALSE.

See Also

HD_ITEM


HDM_GETITEMCOUNT [New - Windows NT]
HDM_GETITEMCOUNT  QuickInfo  Overview  Group

[New - Windows NT]

HDM_GETITEMCOUNT

wParam = 0;

lParam = 0;

// Corresponding macro

int Header_GetItemCount(hwndHD);

The HDM_GETITEMCOUNT message retrieves a count of the items in a header control.

Parameters

hwndHD

Handle to the header control.

Return Value

If the operation succeeds, the return value is the number of items.

If the operation fails, the return value is − 1.


HDM_HITTEST [New - Windows NT]
HDM_HITTEST  QuickInfo  Overview  Group

[New - Windows NT]

HDM_HITTEST

wParam = 0;

lParam = (LPARAM) (HD_HITTESTINFO FAR *) phdhti;

The HDM_HITTEST message tests a point to determine which header item, if any, is at the specified point.

Parameters

phdhti

Pointer to an HD_HITTESTINFO structure that contains the position to test and receives information about the results of the test.

Return Value

Returns the index of the item at the specified position, if any, or  − 1 otherwise.

See Also

HD_HITTESTINFO


HDM_INSERTITEM [New - Windows NT]
HDM_INSERTITEM  QuickInfo  Overview  Group

[New - Windows NT]

HDM_INSERTITEM

wParam = (WPARAM) (int) index;

lParam = (LPARAM) (const HD_ITEM FAR*) phdi;

// Corresponding macro

int Header_InsertItem(hwndHD, index, phdi);

The HDM_INSERTITEM message inserts a new item into a header control.

Parameters

hwndHD

Handle to the header control.

index

Index of the item after which the new item is to be inserted. The new item is inserted at the end of the header control if index is greater than or equal to the number of items in the control. If index is zero, the new item is inserted at the beginning of the header control.

phdi

Pointer to an HD_ITEM structure that contains information about the new item.

Return Value

If the operation succeeds, the return value is the index of the new item.

If the operation fails, the return value is − 1.

See Also

HD_ITEM


HDM_LAYOUT [New - Windows NT]
HDM_LAYOUT  QuickInfo

[New - Windows NT]

HDM_LAYOUT

wParam = 0;

lParam = (LPARAM) (HD_LAYOUT FAR*) playout;

// Corresponding macro

BOOL Header_Layout(hwndHD, playout);

The HDM_LAYOUT message retrieves the size and position of a header control within a given rectangle. This message is used to determine the appropriate dimensions for a new header control that is to occupy the given rectangle.

Parameters

hwndHD

Handle to the header control.

playout

Pointer to an HD_LAYOUT structure. The prc member specifies the coordinates of a rectangle, and the pwpos member receives the size and position for the header control within the rectangle.

Return Value

If the operation succeeds, the return value is TRUE.

If the operation fails, the return value is FALSE.

See Also

HD_LAYOUT


HDM_SETITEM [New - Windows NT]
HDM_SETITEM  QuickInfo

[New - Windows NT]

HDM_SETITEM

wParam = (WPARAM) (int) index;

lParam = (LPARAM) (const HD_ITEM FAR*) phdi;

// Corresponding macro

BOOL Header_SetItem(hwndHD, index, phdi);

The HDM_SETITEM message sets the attributes of the specified item in a header control.

Parameters

hwndHD

Handle to the header control.

index

Index of the item whose attributes are to be changed.

phdi

Pointer to an HD_ITEM structure. When the message is sent, the mask member indicates the attributes to set. The other members specify new attributes.

Return Value

If the operation succeeds, the return value is TRUE.

If the operation fails, the return value is FALSE.

Remarks

The HDN_ITEMCHANGING notification message is sent to the parent window before the item attributes are changed. The parent window can return FALSE to prevent the changes, and in that case, HDM_SETITEM returns FALSE. If the parent window returns TRUE, the changes are made and the parent window receives the HDN_ITEMCHANGED notification message.

See Also

HD_ITEM, HDN_ITEMCHANGED, HDN_ITEMCHANGING


HDN_BEGINTRACK [New - Windows NT]
HDN_BEGINTRACK  QuickInfo  Overview  Group

[New - Windows NT]

HDN_BEGINTRACK

phdn = (HD_NOTIFY FAR *) lParam;

The HDN_BEGINTRACK notification message notifies a header control's parent window that the user has begun dragging a divider in the control (that is, the user has pressed the left mouse button while the mouse cursor is on a divider in the header control). This notification message is sent in the form of a WM_NOTIFY message.

Parameters

phdn

Pointer to an HD_NOTIFY structure that contains information about the header control and the item whose divider is to be dragged.

Return Value

Returns FALSE to allow tracking of the divider or TRUE to prevent tracking.

See Also

HD_NOTIFY, WM_NOTIFY


HDN_DIVIDERDBLCLICK [New - Windows NT]
HDN_DIVIDERDBLCLICK  QuickInfo  Overview  Group

[New - Windows NT]

HDN_DIVIDERDBLCLICK

phdn = (HD_NOTIFY FAR *) lParam;

The HDN_DIVIDERDBLCLICK notification message notifies a header control's parent window that the user double-clicked the divider area of the control. This notification message is sent in the form of a WM_NOTIFY message.

Parameters

phdn

Pointer to an HD_NOTIFY structure that contains information about the header control and the item whose divider was double-clicked.

Return Value

No return value.

See Also

HD_NOTIFY, WM_NOTIFY


HDN_ENDTRACK [New - Windows NT]
HDN_ENDTRACK  QuickInfo  Overview  Group

[New - Windows NT]

HDN_ENDTRACK

phdn = (HD_NOTIFY FAR *) lParam;

The HDN_ENDTRACK notification message notifies a header control's parent window that the user has finished dragging a divider. This notification message sent in the form of a WM_NOTIFY message.

Parameters

phdn

Pointer to an HD_NOTIFY structure that contains information about the header control and the item whose divider was dragged.

Return Value

No return value.

See Also

HD_NOTIFY, WM_NOTIFY


HDN_ITEMCHANGED [New - Windows NT]
HDN_ITEMCHANGED  QuickInfo  Overview  Group

[New - Windows NT]

HDN_ITEMCHANGED

phdr = (HD_NOTIFY FAR *) lParam;

The HDN_ITEMCHANGED notification message notifies a header control's parent window that the attributes of a header item have changed. This notification message is sent in the form of a WM_NOTIFY message.

Parameters

phdr

Pointer to an HD_NOTIFY structure that contains information about the header control, including the attributes that have changed.

Return Value

No return value.

See Also

HD_NOTIFY, WM_NOTIFY


HDN_ITEMCHANGING [New - Windows NT]
HDN_ITEMCHANGING  QuickInfo  Overview  Group

[New - Windows NT]

HDN_ITEMCHANGING

phdr = (HD_NOTIFY FAR *) lParam;

The HDN_ITEMCHANGING notification message notifies a header control's parent window that the attributes of a header item are about to change. This notification message is sent in the form of a WM_NOTIFY message.

Parameters

phdr

Pointer to an HD_NOTIFY structure that contains information about the header control and the header item, including the attributes that are about to change.

Return Value

Returns FALSE to allow the changes or TRUE to prevent them.

See Also

HD_NOTIFY, WM_NOTIFY


HDN_ITEMCLICK [New - Windows NT]
HDN_ITEMCLICK  QuickInfo  Overview  Group

[New - Windows NT]

HDN_ITEMCLICK

phdr = (HD_NOTIFY FAR *) lParam;

The HDN_ITEMCLICK notification message notifies a header control's parent window that the user clicked the control. This notification message is sent in the form of a WM_NOTIFY message.

Parameters

phdr

Pointer to an HD_NOTIFY structure that identifies the header control and specifies the index of the header item that was clicked and the mouse button used to click the item. The pitem member is set to NULL.

Return Value

No return value.

Remarks

A header control sends this notification message after the user releases the left mouse button.

See Also

HD_NOTIFY, WM_NOTIFY


HDN_ITEMDBLCLICK [New - Windows NT]
HDN_ITEMDBLCLICK  QuickInfo  Overview  Group

[New - Windows NT]

HDN_ITEMDBLCLICK

pnmhdr = (NMHDR FAR *) lParam;

The HDN_ITEMDBLCLICK notification message notifies a header control's parent window that the user double-clicked the control. This notification message is sent in the form of a WM_NOTIFY message. Only header controls that have the HDS_BUTTONS style send this notification.

Parameters

pnmhdr

Pointer to an NMHDR structure that contains the handle and identifier of the header control and the HDN_ITEMDBLCLICK notification code.

Return Value

No return value.

Remarks

A control that has the HDS_DIVIDERTRACK style does not send this notification when the user double-clicks the divider.

See Also

NMHDR, WM_NOTIFY


HDN_TRACK [New - Windows NT]
HDN_TRACK  QuickInfo  Overview  Group

[New - Windows NT]

HDN_TRACK

phdr = (HD_NOTIFY FAR *) lParam;

The HDN_TRACK notification message notifies a header control's parent window that the user is dragging a divider in the header control. This notification message is sent in the form of a WM_NOTIFY message.

Parameters

phdr

Pointer to an HD_NOTIFY structure that contains information about the header control and the item whose divider is being dragged.

Return Value

Returns FALSE to continue tracking the divider or TRUE to end tracking.

See Also

HD_NOTIFY, WM_NOTIFY


HELPMSGSTRING

msg = uHelpMsg;
wParam = (HWND) hdlg;
lParam = (LPVOID) lpStruct;

Sent to the window procedure of the owner window of a dialog box after the user has clicked the Help button. This message is available only if the dialog box was created using a SHOWHELP value in the Flags member of the corresponding structure. For Open and Save As dialog boxes, this message has been superseded by the CDN_HELP message.

Parameters

uHelpMsg

Message identifier for the Help message. This value is the same as returned by the RegisterWindowMessage function for the HELPMSGSTRING string.

hdlg

Handle of the common dialog box.

lpStruct

Address of the structure for the dialog box. Can be a CHOOSECOLOR, CHOOSEFONT, OPENFILENAME, FINDREPLACE, PRINTDLG or PAGESETUPDLG structure.

Return Value

No return value.

Remarks

Applications can check the lCustData member of the given structure to determine which instance of the dialog box is requesting help.

See Also

CDN_HELP, CHOOSECOLOR, CHOOSEFONT, OPENFILENAME, FINDREPLACE, PRINTDLG, PAGESETUPDLG, RegisterWindowMessage


HKM_GETHOTKEY [New - Windows NT]
HKM_GETHOTKEY  QuickInfo  Overview  Group

[New - Windows NT]

HKM_GETHOTKEY

wParam = 0;

lParam = 0;

The HKM_GETHOTKEY message retrieves the virtual-key code and modifier flags of a hot key from a hot-key control.

Return Value

Returns the virtual-key code and modifier flags. The virtual-key code is in the low-order byte, and the modifier flags are in the high-order byte. The modifier flags can be a combination of the following values:

Value	Meaning
HOTKEYF_ALT	ALT key
HOTKEYF_CONTROL	CTRL key
HOTKEYF_EXT	Extended key
HOTKEYF_SHIFT	SHIFT key
Remarks

The 16-bit value returned by this message can be used as the wParam parameter in the WM_SETHOTKEY message.

See Also

WM_SETHOTKEY


HKM_SETHOTKEY [New - Windows NT]
HKM_SETHOTKEY  QuickInfo  Overview  Group

[New - Windows NT]

HKM_SETHOTKEY

wParam = MAKEWORD(bVKHotKey, bfMods);

lParam = 0;

The HKM_SETHOTKEY message sets the hot key combination for a hot-key control.

Parameters

bVKHotKey

Virtual-key code of the hot key.

bfMods

Modifier flags indicating the keys that, when used in combination with bVKHotKey, define a hot-key combination. For a list of modifier flag values, see the description of the HKM_GETHOTKEY message.

Return Value

No return value.

See Also

HKM_GETHOTKEY


HKM_SETRULES [New - Windows NT]
HKM_SETRULES  QuickInfo  Overview  Group

[New - Windows NT]

HKM_SETRULES

wParam = (WPARAM) fwCombInv;

lParam = MAKELPARAM(fwModInv, 0);

The HKM_SETRULES message defines the invalid combinations and the default modifier combination for a hot-key control.

Parameters

fwCombInv

Array of flags that specify invalid key combinations. This parameter can be a combination of the following values:

Value	Meaning
HKCOMB_A	ALT
HKCOMB_C	CTRL
HKCOMB_CA	CTRL+ALT
HKCOMB_NONE	Unmodified keys
HKCOMB_S	SHIFT
HKCOMB_SA	SHIFT+ALT
HKCOMB_SC	SHIFT+CTRL
HKCOMB_SCA	SHIFT+CTRL+ALT
fwModInv

Array of flags that specify the key combination to use when the user enters an invalid combination. For a list of modifier flag values, see the description of the HKM_GETHOTKEY message.

Return Value

No return value.

Remarks

When a user enters an invalid key combination, as defined by flags specified in fwCombInv, the system uses the bitwise-OR operator to combine the keys entered by the user with the flags specified in fwModInv. The resulting key combination is converted into a string and then displayed in the hot-key control.

See Also

HKM_GETHOTKEY


IMC_CLOSESTATUSWINDOW

msg = (UINT) WM_IME_CONTROL;
wParam = (WPARAM) IMC_CLOSESTATUSWINDOW;
lParam = (LPARAM) 0;

An application sends the IMC_CLOSESTATUSWINDOW message to the IME window to hide the status window.

Return Value

Returns zero if successful, nonzero otherwise.

Remarks

When the status window of IME is already hidden, this message does nothing. Although an application may send this message to the IME window, the application does not receive the corresponding IMN_CLOSESTATUSWINDOW message.


IMC_GETCANDIDATEPOS [New - Windows 95]
IMC_GETCANDIDATEPOS  QuickInfo  Overview  Group

[New - Windows 95]

msg = (UINT) WM_IME_CONTROL;
wParam = (WPARAM) IMC_GETCANDIDATEPOS;
lParam = (LPARAM) &CandForm;

An application sends the IMC_GETCANDIDATEPOS message to an IME window to get the position of the candidate window. Because the IME may adjust the position of a candidate window, an application uses this message to get the actual position to decide whether to reposition the window.

Parameters

lParam

Pointer to the CANDIDATEFORM structure that receives the position of the candidate window.

Return Value

Returns zero if successful, nonzero otherwise.

Remarks

The returned position is in window coordinates relative to the window having the current input focus.

See Also

CANDIDATEFORM


IMC_GETCOMPOSITIONCOLOR
IMC_GETCOMPOSITIONCOLOR  Overview  Group

msg = WM_IME_CONTROL;
wParam = (WPARAM) IMC_GETCOMPOSITIONCOLOR;
lParam = (LPARAM) (COLORREF *) aCompCr;

Gets the current IME composition colors. Available only in Asian-language versions of the operating system.

Parameters

aCompCr

Address of an array of COLORREF values identifying the composition colors. The array has the following elements:

Element	Meaning
aCompCr[0]	Foreground color of character currently being entered
aCompCr[1]	Foreground color of character currently being converted (already converted)
aCompCr[2]	Foreground color of character given from conversion
aCompCr[3]	Foreground color of character currently being converted (yet to be converted)
aCompCr[4]	Background color of character currently being entered
aCompCr[5]	Background color of character currently being converted (already converted)
aCompCr[6]	Background color of character given from conversion
aCompCr[7]	Background color of character currently being converted (yet to be converted)
Return Value

Returns TRUE.

See Also

COLORREF


IMC_GETCOMPOSITIONFONT [New - Windows 95]
IMC_GETCOMPOSITIONFONT  QuickInfo  Overview  Group

[New - Windows 95]

msg = (UINT) WM_IME_CONTROL;
wParam = (WPARAM) IMC_GETCOMPOSITIONFONT;
lParam = (LPARAM) &LogFont;

An application sends the IMC_GETCOMPOSITIONFONT message to an IME window to retrieve the logical font used for displaying intermediate characters in the composition window.

Parameters

lParam

Pointer to the LOGFONT structure that receives information about the logical font.

Return Value

Returns zero if successful, nonzero otherwise.

See Also

LOGFONT


IMC_GETCOMPOSITIONWINDOW [New - Windows 95]
IMC_GETCOMPOSITIONWINDOW  QuickInfo  Overview  Group

[New - Windows 95]

msg = (UINT) WM_IME_CONTROL;
wParam = (WPARAM) IMC_GETCOMPOSITIONWINDOW;
lParam = (LPARAM) &CompForm;

An application sends the IMC_GETCOMPOSITIONWINDOW message to an IME window to get the position of the composition window. Because the IME may adjust the position of a composition window, an application uses this message to get the actual position to decide whether to reposition the window.

Parameters

lParam

Pointer to the COMPOSITIONFORM structure that receives the position of the composition window.

Return Value

Returns zero if successful, nonzero otherwise.

Remarks

The returned position is in window coordinates relative to the window having the current input focus.

See Also

COMPOSITIONFORM


IMC_GETCONVERSIONMODE [New - Windows 95]
IMC_GETCONVERSIONMODE  QuickInfo  Overview  Group

[New - Windows 95]

msg = (UINT) WM_IME_CONTROL;
wParam = (WPARAM) IMC_GETCONVERSIONMODE;
lParam = 0;

An application sends the IMC_GETCONVERSIONMODE message to an IME window to obtain the current conversion mode. The window retrieves the current conversion mode from the current input context.

Return Value

Returns a combination of the values given in the "IME Conversion Modes" table in Input Method Editor Constants.


IMC_GETOPENSTATUS [New - Windows 95]
IMC_GETOPENSTATUS  QuickInfo  Overview  Group

[New - Windows 95]

msg = (UINT) WM_IME_CONTROL;
wParam = (WPARAM) IMC_GETOPENSTATUS;
lParam = 0;

An application sends the IMC_GETOPENSTATUS message to an IME window to determine whether the IME is open.

Return Value

Returns nonzero if the current IME is open, 0 otherwise.


IMC_GETSENTENCEMODE [New - Windows 95]
IMC_GETSENTENCEMODE  QuickInfo  Overview  Group

[New - Windows 95]

msg = (UINT) WM_IME_CONTROL;
wParam = (WPARAM) IMC_GETSENTENCEMODE;
lParam = 0;

An application sends the IMC_GETSENTENCEMODE message to an IME window to obtain current sentence mode.

Return Value

Returns a combination of the values given in the "IME Sentence Modes" table in Input Method Editor Constants.


IMC_GETSTATUSWINDOWPOS [New - Windows 95]
IMC_GETSTATUSWINDOWPOS  QuickInfo  Overview  Group

[New - Windows 95]

msg = (UINT) WM_IME_CONTROL;
wParam = (WPARAM) IMC_GETSTATUSWINDOWPOS;
lParam = 0;

An application sends the IMC_GETSTATUSWINDOWPOS message to an IME window to get the position of the status window.

Return Value

Returns a POINTS structure that contains the x- and y-coordinates of the status window position.

See Also

POINTS


IMC_OPENSTATUSWINDOW

msg = (UINT) WM_IME_CONTROL;
wParam = (WPARAM) IMC_OPENSTATUSWINDOW;
lParam = (LPARAM) 0;

An application sends the IMC_OPENSTATUSWINDOW message to the IME window to show the status window. This message is ignored if the system is not in the show IME status mode. The user can set or clear the show IME status mode from the task bar.

Return Value

Returns zero if successful, nonzero otherwise.

Remarks

If the status window is already shown, this message does nothing. Although the application may send this message to the IME window, the application does not receive the corresponding IMN_OPENSTATUSWINDOW message.


IMC_SETCANDIDATEPOS [New - Windows 95]
IMC_SETCANDIDATEPOS  QuickInfo  Overview  Group

[New - Windows 95]

msg = (UINT) WM_IME_CONTROL;
wParam = (WPARAM) IMC_SETCANDIDATEPOS;
lParam = (LPARAM) &CandForm;

An application sends the IMC_SETCANDIDATEPOS message to an IME window to set the position of the candidate window. This message is intended for applications that display composition characters on their own but use the IME window to display candidates.

Parameters

lParam

Pointer to the CANDIDATEFORM structure that contains the x- and y-coordinates for the candidate window. The application should set the dwIndex member in the structure.

Return Value

Return zero if successful, nonzero otherwise.

See Also

CANDIDATEFORM


IMC_SETCOMPOSITIONCOLOR
IMC_SETCOMPOSITIONCOLOR  Overview  Group

msg = WM_IME_CONTROL;
wParam = (WPARAM) IMC_SETCOMPOSITIONCOLOR;
lParam = (LPARAM) (COLORREF *) aCompCr;

Sets the IME composition colors. Available only in Asian-language versions of the operating system.

Parameters

aCompCr

Address of an array of COLORREF values identifying the composition colors. The array has the following elements:

Element	Meaning
aCompCr[0]	foreground color of character currently being entered
aCompCr[1]	foreground color of character currently being converted (already converted)
aCompCr[2]	foreground color of character given from conversion
aCopmCr[3]	foreground color of character currently being converted (yet to be converted)
aCompCr[4]	background color of character currently being entered
aCompCr[5]	background color of character currently being converted (already converted)
aCompCr[6]	background color of character given from conversion
aCompCr[7]	background color of character currently being converted (yet to be converted)
Return Value

Returns TRUE.

See Also

COLORREF


IMC_SETCOMPOSITIONFONT [New - Windows 95]
IMC_SETCOMPOSITIONFONT  QuickInfo  Overview  Group

[New - Windows 95]

msg = (UINT) WM_IME_CONTROL;
wParam = (WPARAM) IMC_SETCOMPOSITIONFONT;
lParam = (LPARAM) &LogFont;

An application sends the IMC_SETCOMPOSITIONFONT message to an IME window to specify the logical font to use for displaying intermediate characters in the composition window.

Parameters

lParam

Pointer to the LOGFONT structure that contains information about the logical font.

Return Value

Returns zero if successful, nonzero otherwise.

Remarks

When processing this message, the IME window changes the current selected font in the input context.

See Also

LOGFONT


IMC_SETCOMPOSITIONWINDOW [New - Windows 95]
IMC_SETCOMPOSITIONWINDOW  QuickInfo  Overview  Group

[New - Windows 95]

msg = (UINT) WM_IME_CONTROL;
wParam = (WPARAM) IMC_SETCOMPOSITIONWINDOW;
lParam = (LPARAM) &CompForm;

An application sends the IMC_SETCOMPOSITIONWINDOW message to an IME window to set the style of the composition window. The message set this style in the current input context and the style is subsequently applied to each IME window that receives that input context.

Parameters

lParam

Pointer to the COMPOSITIONFORM structure that contains the style information.

Return Value

Returns zero if successful, nonzero otherwise.

Remarks

By default, the IME window has the CFS_POINT style. This means the IME window uses the current caret position and window client area when it opens composition window.

See Also

COMPOSITIONFORM


IMC_SETCONVERSIONMODE [New - Windows 95]
IMC_SETCONVERSIONMODE  QuickInfo  Overview  Group

[New - Windows 95]

msg = (UINT) WM_IME_CONTROL;
wParam = (WPARAM) IMC_SETCONVERSIONMODE;
lParam = (LPARAM) cMode;

An application sends the IMC_SETCONVERSIONMODE message to an IME window to set current conversion mode.

Parameters

lParam

Conversion mode. Can be one of the values given in the "IME Conversion Modes" table in Input Method Editor Constants.

Return Value

Returns zero if successful, nonzero otherwise.


IMC_SETOPENSTATUS [New - Windows 95]
IMC_SETOPENSTATUS  QuickInfo  Overview  Group

[New - Windows 95]

msg = (UINT) WM_IME_CONTROL;
wParam = (WPARAM) IMC_SETOPENSTATUS;
lParam = (LPARAM) bOpen;

An application sends the IMC_SETOPENSTATUS message to an IME window to open or close the current IME.

Parameters

lParam

Open status. If TRUE, the IME is opened, closed otherwise.

Return Value

Returns zero if successful, nonzero otherwise.

Remarks

When processing this message, the IME window changes the current input context.


IMC_SETSENTENCEMODE [New - Windows 95]
IMC_SETSENTENCEMODE  QuickInfo  Overview  Group

[New - Windows 95]

msg = (UINT) WM_IME_CONTROL;
wParam = (WPARAM) IMC_SETSENTENCEMODE;
lParam = 0;

An application sends the IMC_SETSENTENCEMODE message to an IME window to set the current sentence mode.

Parameters

lParam

Sentence mode. Can be one of the values given in the "IME Sentence Modes" table in Input Method Editor Constants.

Return Value

Returns zero if successful, nonzero otherwise.


IMC_SETSTATUSWINDOWPOS [New - Windows 95]
IMC_SETSTATUSWINDOWPOS  QuickInfo  Overview  Group

[New - Windows 95]

msg = (UINT) WM_IME_CONTROL;
wParam = (WPARAM) IMC_SETSTATUSWINDOWPOS;
lParam = (LPARAM) &pts;

An application sends the IMC_SETSTATUSWINDOWPOS message to an IME window to set the position of the status window.

Parameters

lParam

Pointer to a POINTS structure that contains the x- and y-coordinates of the position of the status window.

Return Value

Returns zero if successful, nonzero otherwise.

See Also

POINTS


IMN_CHANGECANDIDATE [New - Windows 95]
IMN_CHANGECANDIDATE  QuickInfo  Overview  Group

[New - Windows 95]

fCandidates = (DWORD) lParam;

The IMN_CHANGECANDIDATE message is sent to the application when an IME is about to change the content of the candidate window. An application should process this notification message if it displays candidates itself. The application receives this notification message through the WM_IME_NOTIFY message.

Parameters

fCandidates

Candidate lists flag. Each bit corresponds to a candidate list: bit 0 to the first list, bit 1 to the second, and so on. If a specified bit is 1, the corresponding candidate window is about to be changed.

Return Value

No return value.

Remarks

The IME window changes the appearance of the candidate window when it processes this message. An application can get information about the system window with the ImmGetCandidateListCount and ImmGetCandidateList functions.

See Also

ImmGetCandidateList, ImmGetCandidateListCount, WM_IME_NOTIFY


IMN_CLOSECANDIDATE [New - Windows 95]
IMN_CLOSECANDIDATE  QuickInfo  Overview  Group

[New - Windows 95]

fCandidate = (DWORD) lParam;

The IMN_CLOSECANDIDATE message is sent to the application when an IME is about to close the candidate window. An application should process this message if it displays candidates itself. The application receives this notification message through the WM_IME_NOTIFY message.

Parameters

fCandidates

Candidate lists flag. Each bit corresponds to a candidate list: bit 0 to the first list, bit 1 to the second, and so on. If a specified bit is 1, the corresponding candidate window is about to be closed.

Return Value

No return value.

Remarks

By default, the IME window destroys a candidate window when it processes this message.

See Also

WM_IME_NOTIFY


IMN_CLOSESTATUSWINDOW(preliminary-Windows 95) [New - Windows 95]
IMN_CLOSESTATUSWINDOW  Overview  Group

[New - Windows 95]

The IMN_CLOSESTATUSWINDOW message is sent to the application when an IME is about to close the status window. An application should process this notification message if it displays the status window for the IME. The application receives this notification message through the WM_IME_NOTIFY message.

Return Value

No return value.

Remarks

The IME window closes the status window when it processes this message.

See Also

WM_IME_NOTIFY


IMN_GUIDELINE(preliminary-Windows 95) [New - Windows 95]
IMN_GUIDELINE  QuickInfo  Overview  Group

[New - Windows 95]

The IMN_GUIDELINE message is sent when an IME is about to show an error message or other information. An application processes this message by calling the ImmGetGuideLine function to retrieve the error message or information from the IME. The application receives this notification message through the WM_IME_NOTIFY message.

Return Value

No return value.

Remarks

The IME window displays the error message or information string in an information window.

See Also

ImmGetGuideLine, WM_IME_NOTIFY


IMN_OPENCANDIDATE [New - Windows 95]
IMN_OPENCANDIDATE  QuickInfo  Overview  Group

[New - Windows 95]

fCandidate = (DWORD) lParam;

The IMN_OPENCANDIDATE message is sent to the application when an IME is about to open the candidate window. An application should process this message if it displays candidates itself. The application can retrieve a list of candidates to display by using the ImmGetCandidateList function. The application receives this notification message through the WM_IME_NOTIFY message.

Parameters

fCandidates

Candidate lists flag. Each bit corresponds to a candidate list: bit 0 to the first list, bit 1 to the second, and so on. If a specified bit is 1, the corresponding candidate window is about to be opened.

Return Value

No return value.

Remarks

By default, the IME window creates a candidate window when it processes this message.

See Also

ImmGetCandidateList, WM_IME_NOTIFY


IMN_OPENSTATUSWINDOW(preliminary-Windows 95) [New - Windows 95]
IMN_OPENSTATUSWINDOW  QuickInfo  Overview  Group

[New - Windows 95]

The IMN_OPENSTATUSWINDOW message is sent when an IME is about to create the status window. An application processes this message to display the status window for the IME by itself. The application receives this notification message through the WM_IME_NOTIFY message.

Return Value

No return value.

Remarks

The IME window creates a status window when it processes this message and sets the strings to display in the window into the input context. Applications can get information about the status window by using the ImmGetConversionStatus function.

See Also

ImmGetConversionStatus, WM_IME_NOTIFY


IMN_SETCANDIDATEPOS [New - Windows 95]
IMN_SETCANDIDATEPOS  QuickInfo  Overview  Group

[New - Windows 95]

fCandidates = (DWORD) lParam;

The IMN_SETCANDIDATEPOS message is sent when the IME is about to move the candidate window. An application should process this message if it displays the candidate window itself. The application receives this notification message through the WM_IME_NOTIFY message.

Parameters

fCandidates

Candidate lists flag. Each bit corresponds to a candidate list: bit 0 to the first list, bit 1 to the second, and so on. If a specified bit is 1, the corresponding candidate window is about to be moved.

Return Value

No return value.

Remarks

The IME window moves the candidate window when it processes this message.

See Also

WM_IME_NOTIFY


IMN_SETCOMPOSITIONFONT(preliminary-Windows 95) [New - Windows 95]
IMN_SETCOMPOSITIONFONT  QuickInfo  Overview  Group

[New - Windows 95]

The IMN_SETCOMPOSITIONFONT message is sent when the font of the input context is updated. The application receives this notification message through the WM_IME_NOTIFY message.

Return Value

No return value.

Remarks

The application can get information about the font by using the ImmGetCompositionFont function. The IME window subsequently uses the font to draw the composition string.

See Also

ImmGetCompositionFont, WM_IME_NOTIFY


IMN_SETCOMPOSITIONWINDOW(preliminary-Windows 95) [New - Windows 95]
IMN_SETCOMPOSITIONWINDOW  QuickInfo  Overview  Group

[New - Windows 95]

The IMN_SETCOMPOSITIONWINDOW message is sent when the style or position of the composition window is updated. The application receives this notification message through the WM_IME_NOTIFY message.

Return Value

No return value.

Remarks

The application can get information about the composition form by using the IMC_GETCOMPOSITIONWINDOW message.

See Also

IMC_GETCOMPOSITIONWINDOW, WM_IME_NOTIFY


IMN_SETCONVERSIONMODE(preliminary-Windows 95) [New - Windows 95]
IMN_SETCONVERSIONMODE  QuickInfo  Overview  Group

[New - Windows 95]

The IMN_SETCONVERSIONMODE message is sent when the conversion mode of the input context is updated. The application receives this notification message through the WM_IME_NOTIFY message.

Return Value

No return value.

Remarks

The application can get information about the conversion mode by using the ImmGetConversionStatus function.

See Also

ImmGetConversionStatus, WM_IME_NOTIFY


IMN_SETOPENSTATUS(preliminary-Windows 95) [New - Windows 95]
IMN_SETOPENSTATUS  QuickInfo  Overview  Group

[New - Windows 95]

The IMN_SETOPENSTATUS message is sent when the open status of the input context is updated. The application receives this notification message through the WM_IME_NOTIFY message.

Return Value

No return value.

Remarks

The application can get information about the open status by using the ImmGetOpenStatus function.

See Also

ImmGetOpenStatus, WM_IME_NOTIFY


IMN_SETSENTENCEMODE(preliminary-Windows 95) [New - Windows 95]
IMN_SETSENTENCEMODE  QuickInfo  Overview  Group

[New - Windows 95]

The IMN_SETSENTENCEMODE message is sent when the sentence mode of the input context is updated. The application receives this notification message through the WM_IME_NOTIFY message.

Return Value

No return value.

Remarks

The application can get information about the sentence mode by using the ImmGetConversionStatus function.

See Also

ImmGetConversionStatus, WM_IME_NOTIFY


IMN_SETSTATUSWINDOWPOS(preliminary-Windows 95) [New - Windows 95]
IMN_SETSTATUSWINDOWPOS  QuickInfo  Overview  Group

[New - Windows 95]

The IMN_SETSTATUSWINDOWPOS message is sent when the status window position in the input context is updated. The application receives this notification message through the WM_IME_NOTIFY message.

Return Value

No return value.

Remarks

The application can get information about the status window position by using the IMC_GETSTATUSWINDOWPOS message.

See Also

IMC_GETSTATUSWINDOWPOS, WM_IME_NOTIFY


LB_ADDFILE
LB_ADDFILE  QuickInfo  Overview  Group

LB_ADDFILE

wParam = 0;                               // not used; must be zero

lParam = (LPARAM) (LPCTSTR) lpszFilename; // name of file to add

An application sends an LB_ADDFILE message to add the specified filename to a list box that contains a directory listing.

Parameters

lpszFilename

Value of lParam. Points to the name of the file to add.

Return Value

The return value is the zero-based index of the file that was added, or LB_ERR if an error occurs.

Remarks

The list box to which lpszFilename is added must have been filled by the DlgDirList function.

See Also

DlgDirList, LB_ADDSTRING


LB_ADDSTRING
LB_ADDSTRING  QuickInfo  Overview  Group

LB_ADDSTRING

wParam = 0;                         // not used; must be zero

lParam = (LPARAM) (LPCTSTR) lpsz;   // address of string to add

An application sends an LB_ADDSTRING message to add a string to a list box. If the list box does not have the LBS_SORT style, the string is added to the end of the list. Otherwise, the string is inserted into the list and the list is sorted.

Parameters

lpsz

Value of lParam. Points to the null-terminated string that is to be added.

If you create the list box with an owner-drawn style but without the LBS_HASSTRINGS style, the value of the lpsz parameter is stored as item data instead of the string it would otherwise point to. You can send the LB_GETITEMDATA and LB_SETITEMDATA messages to retrieve or modify the item data.

Return Value

The return value is the zero-based index of the string in the list box. If an error occurs, the return value is LB_ERR. If there is insufficient space to store the new string, the return value is LB_ERRSPACE.

Remarks

If you create an owner-drawn list box with the LBS_SORT style but not the LBS_HASSTRINGS style, the system sends the WM_COMPAREITEM message one or more times to the owner of the list box to place the new item properly in the list box.

See Also

LB_DELETESTRING, LB_INSERTSTRING, LB_SELECTSTRING, WM_COMPAREITEM


LB_DELETESTRING
LB_DELETESTRING  QuickInfo  Overview  Group

LB_DELETESTRING

wParam = (WPARAM) index;    // index of string to delete

lParam = 0;                 // not used; must be zero

An application sends an LB_DELETESTRING message to delete a string in a list box.

Parameters

index

Value of wParam. Specifies the zero-based index of the string to be deleted.

Windows 95 only: The wParam parameter is limited to 16-bit values. This means list boxes cannot contain more than 32,767 items. Although the number of items is restricted, the total size in bytes of the items in a listbox is limited only by available memory.

Return Value

The return value is a count of the strings remaining in the list. The return value is LB_ERR if the index parameter specifies an index greater than the number of items in the list.

Remarks

If an application creates the list box with an owner-drawn style but without the LBS_HASSTRINGS style, the system sends a WM_DELETEITEM message to the owner of the list box so the application can free any additional data associated with the item.

See Also

LB_ADDSTRING, LB_INSERTSTRING, WM_DELETEITEM


LB_DIR
LB_DIR  QuickInfo  Overview  Group

LB_DIR

wParam = (WPARAM) (UINT) uAttrs;          // file attributes

lParam = (LPARAM) (LPCTSTR) lpszFileSpec; // filename address

An application sends an LB_DIR message to add a list of filenames to a list box.

Parameters

uAttrs

Value of wParam. Specifies the attributes of the files to be added to the list box. This parameter can be a combination of the following values:

Value	Description
DDL_ARCHIVE	Includes archived files.
DDL_DIRECTORY	Includes subdirectories. Subdirectory names are enclosed in square brackets ([ ]).
DDL_DRIVES	Includes drives. Drives are listed in the form [-x-], where x is the drive letter.
DDL_EXCLUSIVE	Includes only files with the specified attributes. By default, read-write files are listed even if DDL_READWRITE is not specified.
DDL_HIDDEN	Includes hidden files.
DDL_READONLY	Includes read-only files.
DDL_READWRITE	Includes read-write files with no additional attributes.
DDL_SYSTEM	Includes system files.
lpszFileSpec

Value of lParam. Points to the null-terminated string that specifies the filename to add to the list. If the filename contains wildcards (for example, *.*), all files that match the wildcards and have the attributes specified by the uAttrs parameter are added to the list.

Return Value

The return value is the zero-based index of the last filename added to the list. If an error occurs, the return value is LB_ERR. If there is insufficient space to store the new strings, the return value is LB_ERRSPACE.

See Also

DlgDirList


LB_FINDSTRING
LB_FINDSTRING  QuickInfo  Overview  Group

LB_FINDSTRING

wParam = (WPARAM) indexStart;           // item before start of search

lParam = (LPARAM) (LPCTSTR) lpszFind;   // search string address

An application sends an LB_FINDSTRING message to find the first string in a list box that contains the specified prefix.

Parameters

indexStart

Value of wParam. Specifies the zero-based index of the item before the first item to be searched. When the search reaches the bottom of the list box, it continues from the top of the list box back to the item specified by the indexStart parameter. If indexStart is −1, the entire list box is searched from the beginning.

Windows 95 only: The wParam parameter is limited to 16-bit values. This means list boxes cannot contain more than 32,767 items. Although the number of items is restricted, the total size in bytes of the items in a listbox is limited only by available memory.

lpszFind

Value of lParam. Points to the null-terminated string that contains the prefix to search for. The search is case independent, so this string can contain any combination of uppercase and lowercase letters.

Return Value

The return value is the index of the matching item, or LB_ERR if the search was unsuccessful.

Remarks

If you create the list box with an owner-drawn style but without the LBS_HASSTRINGS style, this message returns the index of the item with a long value (supplied as the lParam parameter of the LB_ADDSTRING or LB_INSERTSTRING message) that matches the value supplied as the lpszFind parameter.

See Also

LB_ADDSTRING, LB_INSERTSTRING, LB_SELECTSTRING


LB_FINDSTRINGEXACT
LB_FINDSTRINGEXACT  QuickInfo  Overview  Group

LB_FINDSTRINGEXACT

wParam = (WPARAM) indexStart;      // item before start of search

lParam = (LPARAM)(LPCSTR)lpszFind; // address of search string

An application sends a LB_FINDSTRINGEXACT message to find the first list box string that matches the string specified in the lpszFind parameter.

Parameters

indexStart

Value of wParam. Specifies the zero-based index of the item before the first item to be searched. When the search reaches the bottom of the list box, it continues from the top of the list box back to the item specified by the indexStart parameter. If indexStart is  − 1, the entire list box is searched from the beginning.

Windows 95 only: The wParam parameter is limited to 16-bit values. This means list boxes cannot contain more than 32,767 items. Although the number of items is restricted, the total size in bytes of the items in a listbox is limited only by available memory.

lpszFind

Value of lParam. Points to the null-terminated string to search for. This string can contain a complete filename, including the extension. The search is not case sensitive, so this string can contain any combination of uppercase and lowercase letters.

Return Value

The return value is the zero-based index of the matching item, or LB_ERR if the search was unsuccessful.

Remarks

If an application creates the list box with an owner-drawn style but without the LBS_HASSTRINGS style, the action taken by LB_FINDSTRINGEXACT depends on whether the LBS_SORT style is used. If LBS_SORT is used, the system sends WM_COMPAREITEM messages to the list box owner to determine which item matches the specified string. Otherwise, LB_FINDSTRINGEXACT attempts to match the 32-bit value against the value of the lpszFind parameter.

See Also

LB_FINDSTRING, LB_SELECTSTRING, WM_COMPAREITEM


LB_GETANCHORINDEX
LB_GETANCHORINDEX  QuickInfo  Overview  Group

LB_GETANCHORINDEX

wParam = 0; // not used; must be zero

lParam = 0; // not used; must be zero

An application sends an LB_GETANCHORINDEX message to retrieve the index of the anchor item—that is, the item from which a multiple selection starts. A multiple selection spans all items from the anchor item to the caret item.

Parameters

This message has no parameters.

Return Value

The return value is the index of the anchor item.

See Also

LB_SETANCHORINDEX


LB_GETCARETINDEX
LB_GETCARETINDEX  QuickInfo  Overview  Group

LB_GETCARETINDEX

wParam = 0; // not used; must be zero

lParam = 0; // not used; must be zero

An application sends an LB_GETCARETINDEX message to determine the index of the item that has the focus rectangle in a multiple-selection list box. The item may or may not be selected.

Parameters

This message has no parameters.

Return Value

The return value is the zero-based index of the list box item that has the focus rectangle. If the list box is a single-selection list box, the return value is the zero-based index of the item that is selected, if any.

See Also

LB_SETCARETINDEX


LB_GETCOUNT
LB_GETCOUNT  QuickInfo  Overview  Group

LB_GETCOUNT

wParam = 0; // not used; must be zero

lParam = 0; // not used; must be zero

An application sends an LB_GETCOUNT message to retrieve the number of items in a list box.

Parameters

This message has no parameters.

Return Value

The return value is the number of items in the list box, or LB_ERR if an error occurs.

Remarks

The returned count is one greater than the index value of the last item (the index is zero-based).

See Also

LB_SETCOUNT


LB_GETCURSEL
LB_GETCURSEL  QuickInfo  Overview  Group

LB_GETCURSEL

wParam = 0;     // not used; must be zero

lParam = 0;     // not used; must be zero

Send an LB_GETCURSEL message to retrieve the index of the currently selected item, if any, in a single-selection list box. For a multiple selection list box, the message retrieves the index of the first selected item (the base item), if any.

Parameters

This message has no parameters.

Return Value

The return value is the zero-based index of the currently selected item or of the base item in a multiple selection.

If there is no selection, the return value is LB_ERR.

Remarks

Use the LB_GETCARETINDEX message to retrieve the index of the item that has the focus rectangle in a multiple-selection list box.

See Also

LB_GETCARETINDEX, LB_SETCURSEL


LB_GETHORIZONTALEXTENT
LB_GETHORIZONTALEXTENT  QuickInfo  Overview  Group

LB_GETHORIZONTALEXTENT

wParam = 0; // not used; must be zero

lParam = 0; // not used; must be zero

An application sends an LB_GETHORIZONTALEXTENT message to retrieve from a list box the width, in pixels, by which the list box can be scrolled horizontally (the scrollable width) if the list box has a horizontal scroll bar.

Parameters

This message has no parameters.

Return Value

The return value is the scrollable width, in pixels, of the list box.

Remarks

To respond to the LB_GETHORIZONTALEXTENT message, the list box must have been defined with the WS_HSCROLL style.

See Also

LB_SETHORIZONTALEXTENT


LB_GETITEMDATA
LB_GETITEMDATA  QuickInfo  Overview  Group

LB_GETITEMDATA

wParam = (WPARAM) index;    // item index

lParam = 0;                 // not used; must be zero

An application sends an LB_GETITEMDATA message to retrieve the application-defined 32-bit value associated with the specified list box item.

Parameters

index

Value of wParam. Specifies the index of the item.

Windows 95 only: The wParam parameter is limited to 16-bit values. This means list boxes cannot contain more than 32,767 items. Although the number of items is restricted, the total size in bytes of the items in a listbox is limited only by available memory.

Return Value

The return value is the 32-bit value associated with the item, or LB_ERR if an error occurs. If the item is in an owner-drawn list box and was created without the LBS_HASSTRINGS style, this 32-bit value was in the lParam parameter of the LB_ADDSTRING or LB_INSERTSTRING message that added the item to the list box. Otherwise, it is the value in the lParam of an LB_SETITEMDATA message.

See Also

LB_ADDSTRING, LB_INSERTSTRING, LB_SETITEMDATA


LB_GETITEMHEIGHT
LB_GETITEMHEIGHT  QuickInfo  Overview  Group

LB_GETITEMHEIGHT

wParam = (WPARAM) index;    // item index

lParam = 0;                 // not used; must be zero

An application sends an LB_GETITEMHEIGHT message to retrieve the height of items in a list box.

Parameters

index

Value of wParam. Specifies the zero-based index of the list box item. This index is used only if the list box has the LBS_OWNERDRAWVARIABLE style; otherwise, it must be  zero.

Windows 95 only: The wParam parameter is limited to 16-bit values. This means list boxes cannot contain more than 32,767 items. Although the number of items is restricted, the total size in bytes of the items in a listbox is limited only by available memory.

Return Value

The return value is the height, in pixels, of each item in the list box. The return value is the height of the item specified by the index parameter if the list box has the LBS_OWNERDRAWVARIABLE style. The return value is LB_ERR if an error occurs.

See Also

LB_SETITEMHEIGHT


LB_GETITEMRECT
LB_GETITEMRECT  QuickInfo  Overview  Group

LB_GETITEMRECT

wParam = (WPARAM) index;            // item index

lParam = (LPARAM) (RECT FAR*) lprc; // address of rectangle

An application sends an LB_GETITEMRECT message to retrieve the dimensions of the rectangle that bounds a list box item as it is currently displayed in the list box.

Parameters

index

Value of wParam. Specifies the zero-based index of the item.

Windows 95 only: The wParam parameter is limited to 16-bit values. This means list boxes cannot contain more than 32,767 items. Although the number of items is restricted, the total size in bytes of the items in a listbox is limited only by available memory.

lprc

Value of lParam. Points to a RECT structure that will receive the client coordinates for the item in the list box.

Return Value

If an error occurs, the return value is LB_ERR.

See Also

RECT


LB_GETLOCALE
LB_GETLOCALE  QuickInfo  Overview  Group

LB_GETLOCALE

wParam = 0; // not used; must be zero

lParam = 0; // not used; must be zero

An application sends an LB_GETLOCALE message to retrieve the current locale of the list box. You can use the locale to determine the correct sorting order of displayed text (for list boxes with the LBS_SORT style) and of text added by the LB_ADDSTRING message.

Parameters

This message has no parameters.

Return Value

The return value is a 32-bit value that specifies the current locale of the list box. The high-order word contains the country code and the low-order word contains the language identifier.

Remarks

The language identifier consists of a sublanguage identifier and a primary language identifier. Use the PRIMARYLANGID macro to extract the primary language identifier from the low-order word of the return value, and the SUBLANGID macro to extract the sublanguage identifier.

See Also

LB_ADDSTRING, LB_SETLOCALE, PRIMARYLANGID, SUBLANGID


LB_GETSEL
LB_GETSEL  QuickInfo  Overview  Group

LB_GETSEL

wParam = (WPARAM) index;    // item index

lParam = 0;                 // not used; must be zero

An application sends an LB_GETSEL message to retrieve the selection state of an item.

Parameters

index

Value of wParam. Specifies the zero-based index of the item.

Windows 95 only: The wParam parameter is limited to 16-bit values. This means list boxes cannot contain more than 32,767 items. Although the number of items is restricted, the total size in bytes of the items in a listbox is limited only by available memory.

Return Value

If an item is selected, the return value is greater than zero; otherwise, it is zero. If an error occurs, the return value is LB_ERR.

See Also

LB_SETSEL


LB_GETSELCOUNT
LB_GETSELCOUNT  QuickInfo  Overview  Group

LB_GETSELCOUNT

wParam = 0; // not used; must be zero

lParam = 0; // not used; must be zero

An application sends an LB_GETSELCOUNT message to retrieve the total number of selected items in a multiple-selection list box.

Parameters

This message has no parameters.

Return Value

The return value is the count of selected items in the list box. If the list box is a single-selection list box, the return value is LB_ERR.

See Also

LB_SETSEL


LB_GETSELITEMS
LB_GETSELITEMS  QuickInfo  Overview  Group

LB_GETSELITEMS

wParam = (WPARAM) cItems;           // maximum number of items

lParam = (LPARAM) (LPINT) lpnItems; // address of buffer

An application sends an LB_GETSELITEMS message to fill a buffer with an array of integers that specify the item numbers of selected items in a multiple-selection list box.

Parameters

cItems

Value of wParam. Specifies the maximum number of selected items whose item numbers are to be placed in the buffer.

Windows 95 only: The wParam parameter is limited to 16-bit values. This means list boxes cannot contain more than 32,767 items. Although the number of items is restricted, the total size in bytes of the items in a listbox is limited only by available memory.

lpnItems

Value of lParam. Points to a buffer large enough for the number of integers specified by the cItems parameter.

Return Value

The return value is the number of items placed in the buffer. If the list box is a single-selection list box, the return value is LB_ERR.

See Also

LB_GETSELCOUNT


LB_GETTEXT
LB_GETTEXT  QuickInfo  Overview  Group

LB_GETTEXT

wParam = (WPARAM) index;                // item index

lParam = (LPARAM) (LPCTSTR) lpszBuffer; // address of buffer

An application sends an LB_GETTEXT message to retrieve a string from a list box.

Parameters

index

Value of wParam. Specifies the zero-based index of the string to retrieve.

Windows 95 only: The wParam parameter is limited to 16-bit values. This means list boxes cannot contain more than 32,767 items. Although the number of items is restricted, the total size in bytes of the items in a listbox is limited only by available memory.

lpszBuffer

Value of lParam. Points to the buffer that will receive the string. The buffer must have sufficient space for the string and a terminating null character. An LB_GETTEXTLEN message can be sent before the LB_GETTEXT message to retrieve the length, in characters, of the string.

Return Value

The return value is the length of the string, in characters, excluding the terminating null character. If index does not specify a valid index, the return value is LB_ERR.

Remarks

If you create the list box with an owner-drawn style but without the LBS_HASSTRINGS style, the buffer pointed to by the lpszBuffer parameter will receive the 32-bit value associated with the item (the item data).

See Also

LB_GETTEXTLEN


LB_GETTEXTLEN
LB_GETTEXTLEN  QuickInfo  Overview  Group

LB_GETTEXTLEN

wParam = (WPARAM) index;    // item index

lParam = 0;                 // not used; must be zero

An application sends an LB_GETTEXTLEN message to retrieve the length of a string in a list box.

Parameters

index

Value of wParam. Specifies the zero-based index of the string.

Windows 95 only: The wParam parameter is limited to 16-bit values. This means list boxes cannot contain more than 32,767 items. Although the number of items is restricted, the total size in bytes of the items in a listbox is limited only by available memory.

Return Value

The return value is the length of the string, in characters, excluding the terminating null character. Under certain conditions, this value may actually be greater than the length of the text. For more information, see the following Remarks section.

If the index parameter does not specify a valid index, the return value is LB_ERR.

Remarks

Under certain conditions, the return value is larger than the actual length of the text. This occurs with certain mixtures of ANSI and Unicode, and is due to the operating system allowing for the possible existence of double-byte character set (DBCS) characters within the text. The return value, however, will always be at least as large as the actual length of the text; you can thus always use it to guide buffer allocation. This behavior can occur when an application uses both ANSI functions and common dialogs, which use Unicode.

To obtain the exact length of the text, use the WM_GETTEXT, LB_GETTEXT, or CB_GETLBTEXT messages, or the GetWindowText function.

See Also

CB_GETLBTEXT, GetWindowText, LB_GETTEXT, WM_GETTEXT


LB_GETTOPINDEX
LB_GETTOPINDEX  QuickInfo  Overview  Group

LB_GETTOPINDEX

wParam = 0; // not used; must be zero

lParam = 0; // not used; must be zero

An application sends an LB_GETTOPINDEX message to retrieve the index of the first visible item in a list box. Initially the item with index 0 is at the top of the list box, but if the list box contents have been scrolled another item may be at the top.

Parameters

This message has no parameters.

Return Value

The return value is the index of the first visible item in the list box.

See Also

LB_SETTOPINDEX


LB_INITSTORAGE [New - Windows 95]
LB_INITSTORAGE  QuickInfo

[New - Windows 95]

LB_INITSTORAGE

wParam = (WPARAM) (int) cItems;  // number of items to add

lParam = (LPARAM) (DWORD) cb;   // amount of memory to allocate, in bytes

Allocates memory for storing list box items. An application sends this message before adding a large number of items to a list box.

Parameters

cItems

Specifies the number of items to add.

Windows 95 only: The wParam parameter is limited to 16-bit values. This means list boxes cannot contain more than 32,767 items. Although the number of items is restricted, the total size in bytes of the items in a listbox is limited only by available memory.

cb

Specifies the amount of memory, in bytes, to allocate for item strings.

Return Value

The return value is the maximum number of items that the memory object can store before another memory reallocation is needed, if successful. It is LB_ERRSPACE if not enough memory is available.

Remarks

This message helps speed up the initialization of list boxes that have a large number of items (more than 100). It preallocates the specified amount of memory so that subsequent LB_ADDSTRING, LB_INSERTSTRING, LB_DIR, and LB_ADDFILE messages take the shortest possible time. You can use estimates for the cItems and cb parameters. If you overestimate, some extra memory is allocated; if you underestimate, the normal allocation is used for items that exceed the preallocated amount.

See Also

LB_ADDFILE, LB_ADDSTRING, LB_DIR, LB_INSERTSTRING


LB_INSERTSTRING
LB_INSERTSTRING  QuickInfo  Overview  Group

LB_INSERTSTRING

wParam = (WPARAM) index;          // item index

lParam = (LPARAM) (LPCTSTR) lpsz; // address of string to insert

An application sends an LB_INSERTSTRING message to insert a string into a list box. Unlike the LB_ADDSTRING message, the LB_INSERTSTRING message does not cause a list with the LBS_SORT style to be sorted.

Parameters

index

Value of wParam. Specifies the zero-based index of the position at which to insert the string. If this parameter is −1, the string is added to the end of the list.

Windows 95 only: The wParam parameter is limited to 16-bit values. This means list boxes cannot contain more than 32,767 items. Although the number of items is restricted, the total size in bytes of the items in a listbox is limited only by available memory.

lpsz

Value of lParam. Points to the null-terminated string to be inserted.

If you create the list box with an owner-drawn style but without the LBS_HASSTRINGS style, the value of the lpsz parameter is stored as item data instead of the string it would otherwise point to. You can send the LB_GETITEMDATA and LB_SETITEMDATA messages to retrieve or modify the item data.

Return Value

The return value is the index of the position at which the string was inserted. If an error occurs, the return value is LB_ERR. If there is insufficient space to store the new string, the return value is LB_ERRSPACE.

See Also

LB_ADDSTRING, LB_SELECTSTRING


LB_ITEMFROMPOINT [New - Windows 95]
LB_ITEMFROMPOINT  QuickInfo

[New - Windows 95]

LB_ITEMFROMPOINT

wParam = 0;                                // not used, must be zero

lParam = (LPARAM) MAKELPARAM(xPos, yPos);  // coordinates of point

An application sends this message to retrieve the zero-based index of the item nearest the specified point in a list box.

Parameters

xPos

Value of the low-order word of lParam. Specifies the x-coordinate of a point, relative to the upper-left corner of the client area of the list box.

yPos

Value of the high-order word of lParam. Specifies the y-coordinate of a point, relative to the upper-left corner of the client area of the list box.

Return Value

The return value contains the index of the nearest item in the low-order word. The high-order word is zero if the specified point is in the client area of the list box, or one if it is outside the client area.


LB_RESETCONTENT
LB_RESETCONTENT  QuickInfo  Overview  Group

LB_RESETCONTENT

wParam = 0; // not used; must be zero

lParam = 0; // not used; must be zero

An application sends an LB_RESETCONTENT to remove all items from a list box.

Parameters

This message has no parameters.

Return Value

This message does not return a value.

Remarks

If you create the list box with an owner-drawn style but without the LBS_HASSTRINGS style, the owner of the list box receives a WM_DELETEITEM message for each item in the list box.

See Also

WM_DELETEITEM


LB_SELECTSTRING
LB_SELECTSTRING  QuickInfo  Overview  Group

LB_SELECTSTRING

wParam = (WPARAM) indexStart;        // item before start of search

lParam = (LPARAM)(LPCTSTR)lpszFind;  // address of search string

An application sends an LB_SELECTSTRING message to search a list box for an item that begins with the characters in a specified string. If a matching item is found, the item is selected.

Parameters

indexStart

Value of wParam. Specifies the zero-based index of the item before the first item to be searched. When the search reaches the bottom of the list box, it continues from the top of the list box back to the item specified by the indexStart parameter. If indexStart is −1, the entire list box is searched from the beginning.

Windows 95 only: The wParam parameter is limited to 16-bit values. This means list boxes cannot contain more than 32,767 items. Although the number of items is restricted, the total size in bytes of the items in a listbox is limited only by available memory.

lpszFind

Value of lParam. Points to the null-terminated string that contains the prefix to search for. The search is case independent, so this string can contain any combination of uppercase and lowercase letters.

Return Value

If the search is successful, the return value is the index of the selected item. If the search is unsuccessful, the return value is LB_ERR and the current selection is not changed.

Remarks

The list box is scrolled, if necessary, to bring the selected item into view.

Do not use this message with a list box that has the LBS_MULTIPLESEL style.

An item is selected only if its initial characters from the starting point match the characters in the string specified by the lpszFind parameter.

If you create the list box with an owner-drawn style but without the LBS_HASSTRINGS style, this message returns the index of the item whose long value (supplied as the lParam parameter of the LB_ADDSTRING or LB_INSERTSTRING message) matches the value supplied as the lParam parameter of LB_SELECTSTRING.

See Also

LB_ADDSTRING, LB_FINDSTRING, LB_INSERTSTRING


LB_SELITEMRANGE
LB_SELITEMRANGE  QuickInfo  Overview  Group

LB_SELITEMRANGE

wParam = (WPARAM) (BOOL) fSelect;   // selection flag

lParam = MAKELPARAM(wFirst, wLast); // first and last items

An application sends an LB_SELITEMRANGE message to select one or more consecutive items in a multiple-selection list box.

Parameters

fSelect

Value of wParam. Specifies how to set the selection. If the fSelect parameter is TRUE, the string is selected and highlighted; if fSelect is zero, the highlight is removed and the string is no longer selected.

wFirst

Value of the low-order word of lParam. Specifies the zero-based index of the first item to select.

wLast

Value of the high-order word of lParam. Specifies the zero-based index of the last item to select.

Return Value

If an error occurs, the return value is LB_ERR.

Remarks

Use this message only with multiple-selection list boxes.

This message can select a range only within the first 65,536 items.

See Also

LB_SELITEMRANGEEX, LB_SETSEL


LB_SELITEMRANGEEX
LB_SELITEMRANGEEX  QuickInfo  Overview  Group

LB_SELITEMRANGEEX

wParam = (WPARAM) wFirst; // first item

lParam = (LPARAM) wLast); // last item

An application sends an LB_SELITEMRANGEEX message to select one or more consecutive items in a multiple-selection list box.

Parameters

wFirst

Value of wParam. Specifies the zero-based index of the first item to select.

Windows 95 only: The wParam parameter is limited to 16-bit values. This means list boxes cannot contain more than 32,767 items. Although the number of items is restricted, the total size in bytes of the items in a listbox is limited only by available memory.

wLast

Value of lParam. Specifies the zero-based index of the last item to select.

Return Value

If an error occurs, the return value is LB_ERR.

Remarks

If the wFirst parameter is less than the wLast parameter, the specified range of items is selected. If wFirst is greater than wLast, the selection is removed from the specified range of items.

Use this message only with multiple-selection list boxes.

This message can select a range only within the first 65,536 items.

See Also

LB_SELITEMRANGE, LB_SETSEL


LB_SETANCHORINDEX
LB_SETANCHORINDEX  QuickInfo  Overview  Group

LB_SETANCHORINDEX

wParam = (WPARAM) index; // index to set as anchor

lParam = 0;              // not used; must be zero

An application sends an LB_SETANCHORINDEX message to set the anchor item—that is, the item from which a multiple selection starts. A multiple selection spans all items from the anchor item to the caret item.

Parameters

index

Value of wParam. Specifies the index of the new anchor item.

Windows 95 only: The wParam parameter is limited to 16-bit values. This means list boxes cannot contain more than 32,767 items. Although the number of items is restricted, the total size in bytes of the items in a listbox is limited only by available memory.

Return Value

If the message succeeds, the return value is zero.

If the message fails, the return value is LB_ERR.

See Also

LB_GETANCHORINDEX


LB_SETCARETINDEX
LB_SETCARETINDEX  QuickInfo  Overview  Group

LB_SETCARETINDEX

wParam = (WPARAM) index;            // item index

lParam = MAKELPARAM(fScroll, 0);    // flag for scrolling item

An application sends an LB_SETCARETINDEX message to set the focus rectangle to the item at the specified index in a multiple-selection list box. If the item is not visible, it is scrolled into view.

Parameters

index

Value of wParam. Specifies the zero-based index of the list box item that is to receive the focus rectangle.

Windows 95 only: The wParam parameter is limited to 16-bit values. This means list boxes cannot contain more than 32,767 items. Although the number of items is restricted, the total size in bytes of the items in a listbox is limited only by available memory.

fScroll

Value of lParam. If this value is FALSE, the item is scrolled until it is fully visible; if it is TRUE, the item is scrolled until it is at least partially visible.

Return Value

If an error occurs, the return value is LB_ERR.

See Also

LB_GETCARETINDEX


LB_SETCOLUMNWIDTH
LB_SETCOLUMNWIDTH  QuickInfo  Overview  Group

LB_SETCOLUMNWIDTH

wParam = (WPARAM) cxColumn; // column width in pixels

lParam = 0;                 // not used; must be zero

An application sends an LB_SETCOLUMNWIDTH message to a multiple-column list box (created with the LBS_MULTICOLUMN style) to set the width, in pixels, of all columns in the list box.

Parameters

cxColumn

Value of wParam. Specifies the width, in pixels, of all columns.

Return Value

This message does not return a value.

See Also

LB_SETTABSTOPS


LB_SETCOUNT
LB_SETCOUNT  QuickInfo  Overview  Group

LB_SETCOUNT

wParam = (WPARAM) (int) cItems; // count of list box items

lParam = 0;                     // not used; must be zero

An application sends an LB_SETCOUNT message to set the count of items in a list box created with the LBS_NODATA style and not created with the LBS_HASSTRINGS style.

Parameters

cItems

Value of wParam. Specifies the new count of items in the list box.

Windows 95 only: The wParam parameter is limited to 16-bit values. This means list boxes cannot contain more than 32,767 items. Although the number of items is restricted, the total size in bytes of the items in a listbox is limited only by available memory.

Return Value

If an error occurs, the return value is LB_ERR. If there is insufficient memory to store the items, the return value is LB_ERRSPACE.

Remarks

The LB_SETCOUNT message is supported only by list boxes created with the LBS_NODATA style and not created with the LBS_HASSTRINGS style. All other list boxes return LB_ERR.

See Also

LB_GETCOUNT


LB_SETCURSEL
LB_SETCURSEL  QuickInfo  Overview  Group

LB_SETCURSEL

wParam = (WPARAM) index;    // item index

lParam = 0;                 // not used; must be zero

An application sends an LB_SETCURSEL message to select a string and scroll it into view, if necessary. When the new string is selected, the list box removes the highlight from the previously selected string.

Parameters

index

Value of wParam. Specifies the zero-based index of the string that is selected. If the index parameter is -1, the list box is set to have no selection.

Windows 95 only: The wParam parameter is limited to 16-bit values. This means list boxes cannot contain more than 32,767 items. Although the number of items is restricted, the total size in bytes of the items in a listbox is limited only by available memory.

Return Value

If an error occurs, the return value is LB_ERR. If the index parameter is −1, the return value is LB_ERR even though no error occurred.

Remarks

Use this message only with single-selection list boxes. You cannot use it to set or remove a selection in a multiple-selection list box.

See Also

LB_GETCURSEL


LB_SETHORIZONTALEXTENT
LB_SETHORIZONTALEXTENT  QuickInfo  Overview  Group

LB_SETHORIZONTALEXTENT

wParam = (WPARAM) cxExtent; // horizontal scroll width

lParam = 0;                 // not used; must be zero

An application sends an LB_SETHORIZONTALEXTENT message to set the width, in pixels, by which a list box can be scrolled horizontally (the scrollable width). If the width of the list box is smaller than this value, the horizontal scroll bar horizontally scrolls items in the list box. If the width of the list box is equal to or greater than this value, the horizontal scroll bar is hidden.

Parameters

cxExtent

Value of wParam. Specifies the number of pixels by which the list box can be scrolled.

Windows 95 only: The wParam parameter is limited to 16-bit values.

Return Value

This message does not return a value.

Remarks

To respond to the LB_SETHORIZONTALEXTENT message, the list box must have been defined with the WS_HSCROLL style.

See Also

LB_GETHORIZONTALEXTENT


LB_SETITEMDATA
LB_SETITEMDATA  QuickInfo  Overview  Group

LB_SETITEMDATA

wParam = (WPARAM) index;    // item index

lParam = (LPARAM) dwData;   // value to associate with item

An application sends an LB_SETITEMDATA message to set a 32-bit value associated with the specified item in a list box.

Parameters

index

Value of wParam. Specifies the zero-based index of the item.

Windows 95 only: The wParam parameter is limited to 16-bit values. This means list boxes cannot contain more than 32,767 items. Although the number of items is restricted, the total size in bytes of the items in a listbox is limited only by available memory.

dwData

Value of lParam. Specifies the 32-bit value to be associated with the item.

Return Value

If an error occurs, the return value is LB_ERR.

Remarks

If the item is in an owner-drawn list box created without the LBS_HASSTRINGS style, this message replaces the 32-bit value contained in the lParam parameter of the LB_ADDSTRING or LB_INSERTSTRING message that added the item to the list box.

See Also

LB_ADDSTRING, LB_GETITEMDATA, LB_INSERTSTRING


LB_SETITEMHEIGHT
LB_SETITEMHEIGHT  QuickInfo  Overview  Group

LB_SETITEMHEIGHT

wParam = (WPARAM) index;        // item index

lParam = MAKELPARAM(cyItem, 0); // item height

An application sends an LB_SETITEMHEIGHT message to set the height, in pixels, of items in a list box. If the list box has the LBS_OWNERDRAWVARIABLE style, this message sets the height of the item specified by the index parameter. Otherwise, this message sets the height of all items in the list box.

Parameters

index

Value of wParam. Specifies the zero-based index of the item in the list box. Use this parameter only if the list box has the LBS_OWNERDRAWVARIABLE style; otherwise, set it to zero.

Windows 95 only: The wParam parameter is limited to 16-bit values. This means list boxes cannot contain more than 32,767 items. Although the number of items is restricted, the total size in bytes of the items in a listbox is limited only by available memory.

cyItem

Value of lParam. Specifies the height, in pixels, of the item.

Return Value

If the index or height is invalid, the return value is LB_ERR.

See Also

LB_GETITEMHEIGHT


LB_SETLOCALE
LB_SETLOCALE  QuickInfo  Overview  Group

LB_SETLOCALE

wParam = (WPARAM) wLocaleID;    // locale identifier

lParam = 0;                     // not used; must be zero

An application sends an LB_SETLOCALE message to set the current locale of the list box. You can use the locale to determine the correct sorting order of displayed text (for list boxes with the LBS_SORT style) and of text added by the LB_ADDSTRING message.

Parameters

wLocaleID

Value of wParam. Specifies the locale identifier that the list box will use for sorting when adding text.

Return Value

The return value is the previous locale identifier. If the wLocaleID parameter specifies a locale that is not installed on the system, the return value is LB_ERR and the current list box locale is not changed.

Remarks

Use the MAKELCID macro to construct a locale identifier.

See Also

LB_ADDSTRING, LB_GETLOCALE, MAKELCID


LB_SETSEL
LB_SETSEL  QuickInfo  Overview  Group

LB_SETSEL

wParam = (WPARAM) (BOOL) fSelect;   // selection flag

lParam = (LPARAM) (UINT) index;     // item index

An application sends an LB_SETSEL message to select a string in a multiple-selection list box.

Parameters

fSelect

Value of wParam. Specifies how to set the selection. If the fSelect parameter is TRUE, the string is selected and highlighted; if fSelect is FALSE, the highlight is removed and the string is no longer selected.

index

Value of lParam. Specifies the zero-based index of the string to set. If index is −1, the selection is added to or removed from all strings, depending on the value of fSelect.

Return Value

If an error occurs, the return value is LB_ERR.

Remarks

Use this message only with multiple-selection list boxes.

See Also

LB_GETSEL, LB_SELITEMRANGE


LB_SETTABSTOPS
LB_SETTABSTOPS  QuickInfo  Overview  Group

LB_SETTABSTOPS

wParam = (WPARAM) cTabs;            // number of tab stops

lParam = (LPARAM) (LPINT) lpnTabs;  // address of tab-stop array

An application sends an LB_SETTABSTOPS message to set the tab-stop positions in a list box.

Parameters

cTabs

Value of wParam. Specifies the number of tab stops in the list box.

lpnTabs

Value of lParam. Points to the first member of an array of integers containing the tab stops, in dialog box units. The tab stops must be sorted in ascending order; backward tabs are not allowed.

Return Value

If all the specified tabs are set, the return value is TRUE; otherwise, it is FALSE.

Remarks

To respond to the LB_SETTABSTOPS message, the list box must have been created with the LBS_USETABSTOPS style.

If cTabs parameter is 0 and lpnTabs is NULL, the default tab stop is two dialog box units. If cTabs is 1, the list box will have tab stops separated by the distance specified by lpnTabs.

If lpnTabs points to more than a single value, a tab stop will be set for each value in lpnTabs, up to the number specified by cTabs.

A dialog box unit is a horizontal or vertical distance. One horizontal dialog box unit is equal to 0.25 of the current dialog box base-width unit. These units are computed based on the height and width of the current system font. The GetDialogBaseUnits function returns the current dialog box base units, in pixels.

See Also

GetDialogBaseUnits


LB_SETTOPINDEX
LB_SETTOPINDEX  QuickInfo  Overview  Group

LB_SETTOPINDEX

wParam = (WPARAM) index;    // item index

lParam = 0;                 // not used; must be zero

An application sends an LB_SETTOPINDEX message to ensure that a particular item in a list box is visible.

Parameters

index

Value of wParam. Specifies the zero-based index of the item in the list box.

Windows 95 only: The wParam parameter is limited to 16-bit values. This means list boxes cannot contain more than 32,767 items. Although the number of items is restricted, the total size in bytes of the items in a listbox is limited only by available memory.

Return Value

If an error occurs, the return value is LB_ERR.

Remarks

The system scrolls the list box contents so that either the specified item appears at the top of the list box or the maximum scroll range has been reached.

See Also

LB_GETTOPINDEX


LBN_DBLCLK
LBN_DBLCLK  QuickInfo  Overview  Group

LBN_DBLCLK

idListBox = (int) LOWORD(wParam);  // identifier of list box

hwndListBox = (HWND) lParam;       // handle of list box

An application sends the LBN_DBLCLK notification message when the user double-clicks a string in a list box. The parent window of the list box receives this notification message through the WM_COMMAND message.

Remarks

Only a list box that has the LBS_NOTIFY style will send this notification message.

See Also

LBN_SELCHANGE, WM_COMMAND


LBN_ERRSPACE
LBN_ERRSPACE  QuickInfo  Overview  Group

LBN_ERRSPACE

idListBox = (int) LOWORD(wParam);  // identifier of list box

hwndListBox = (HWND) lParam;       // handle of list box

An application sends the LBN_ERRSPACE notification message when a list box cannot allocate enough memory to meet a specific request. The parent window of the list box receives this notification message through the WM_COMMAND message.

See Also

WM_COMMAND


LBN_KILLFOCUS
LBN_KILLFOCUS  QuickInfo  Overview  Group

LBN_KILLFOCUS

idListBox = (int) LOWORD(wParam);  // identifier of list box

hwndListBox = (HWND) lParam;       // handle of list box

An application sends the LBN_KILLFOCUS notification message when a list box loses the keyboard focus. The parent window of the list box receives this notification message through the WM_COMMAND message.

See Also

LBN_SETFOCUS, WM_COMMAND


LBN_SELCANCEL
LBN_SELCANCEL  QuickInfo  Overview  Group

LBN_SELCANCEL

idListBox = (int) LOWORD(wParam);  // identifier of list box

hwndListBox = (HWND) lParam;       // handle of list box

An application sends the LBN_SELCANCEL notification message when the user cancels the selection in a list box. The parent window of the list box receives this notification message through the WM_COMMAND message.

Remarks

This notification message applies only to list boxes of the LBS_NOTIFY style.

See Also

LB_SETCURSEL, LBN_DBLCLK, LBN_SELCHANGE, WM_COMMAND


LBN_SELCHANGE
LBN_SELCHANGE  QuickInfo  Overview  Group

LBN_SELCHANGE

idListBox = (int) LOWORD(wParam);  // identifier of list box

hwndListBox = (HWND) lParam;       // handle of list box

An application sends the LBN_SELCHANGE notification message when the selection in a list box is about to change. The parent window of the list box receives this notification message through the WM_COMMAND message.

Remarks

This notification message is not sent if the LB_SETCURSEL message changes the selection.

This notification message applies only to a list box that has the LBS_NOTIFY style.

For a multiple-selection list box, the LBN_SELCHANGE notification is sent whenever the user presses an arrow key, even if the selection does not change.

See Also

LB_SETCURSEL, LBN_DBLCLK, LBN_SELCANCEL, WM_COMMAND


LBN_SETFOCUS
LBN_SETFOCUS  QuickInfo  Overview  Group

LBN_SETFOCUS

idListBox = (int) LOWORD(wParam);  // identifier of list box

hwndListBox = (HWND) lParam;       // handle of list box

An application sends the LBN_SETFOCUS notification message when a list box receives the keyboard focus. The parent window of the list box receives this notification message through the WM_COMMAND message.

See Also

LBN_KILLFOCUS, WM_COMMAND


LBSELCHSTRING
LBSELCHSTRING  Overview  Group

msg = uLBSelChMsg;
wParam = (UINT) idListBox;
lParam = MAKELONG (iItem, iType);

Sent to the hook function of a Open or Save As dialog box after the user changed the selection in the Filename list box. This message has been superseded by the CDN_SELCHANGE and CDN_TYPECHANGE messages.

Parameters

uLBSelChMsg

Message identifier for the Selection Change message. This value is the same as returned by the RegisterWindowMessage function for the LBSELCHSTRING string.

idListBox

Identifier of the list box in which the selection changed.

iItem

Item number of the selected string in the list box.

iType

Type of selection change. Can be one of these values:

CD_LBSELCHANGE	The item identified by iItem is the only item selected in a single-selection list box.
CD_LBSELSUB	The item identified by iItem is no longer selected in a multiple-selection list box.
CD_LBSELADD	The item identified by iItem is one of the items selected in a multiple-selection list box.
CD_LBSELNOITEMS	No items exist in a multiple-selection list box.
Return Value

No return value.

See Also

CDN_SELCHANGE, CDN_TYPECHANGE, RegisterWindowMessage


LVM_ARRANGE [New - Windows NT]
LVM_ARRANGE  QuickInfo  Overview  Group

[New - Windows NT]

LVM_ARRANGE

wParam = (WPARAM) (int) code;

lParam = 0;

// Corresponding macro

BOOL ListView_Arrange(HWND hwnd, UINT code);

The LVM_ARRANGE message arranges items in icon view. You can send this message explicitly or by using the ListView_Arrange macro.

Parameters

hwnd

Handle to the list view control.

code

Specifies the alignment, which can be one of the following values:

Value	Meaning
LVA_ALIGNLEFT	Aligns items along the left edge of the window.
LVA_ALIGNTOP	Aligns items along the top edge of the window.
LVA_DEFAULT	Aligns items according to the list view control's current alignment styles (the default value).
LVA_SNAPTOGRID	Snaps all icons to the nearest grid position.
Return Value

Returns TRUE if successful or FALSE otherwise.


LVM_CREATEDRAGIMAGE [New - Windows NT]
LVM_CREATEDRAGIMAGE  QuickInfo  Overview  Group

[New - Windows NT]

LVM_CREATEDRAGIMAGE

wParam = (WPARAM) (int) iItem;

lParam = (LPARAM) (LPPOINT) lpptUpLeft;

// Corresponding macro

HIMAGELIST ListView_CreateDragImage(HWND hwnd, int iItem,

LPPOINT lpptUpLeft);

The LVM_CREATEDRAGIMAGE message creates a drag image list for the specified item. You can send this message explicitly or by using the ListView_CreateDragImage macro.

Parameters

hwnd

Handle to the list view control.

iItem

Index of the item.

lpptUpLeft

Pointer to a POINT structure that receives the initial location of the upper-left corner of the image, in view coordinates.

Return Value

Returns the handle to the drag image list if successful or NULL otherwise.

See Also

POINT


LVM_DELETEALLITEMS [New - Windows NT]
LVM_DELETEALLITEMS  QuickInfo  Overview  Group

[New - Windows NT]

LVM_DELETEALLITEMS

wParam = 0;

lParam = 0;

// Corresponding macro

BOOL ListView_DeleteAllItems(HWND hwnd);

The LVM_DELETEALLITEMS message removes all items from a list view control. You can send this message explicitly or by using the ListView_DeleteAllItems macro.

Parameters

hwnd

Handle to the list view control.

Return Value

Returns TRUE if successful or FALSE otherwise.


LVM_DELETECOLUMN [New - Windows NT]
LVM_DELETECOLUMN  QuickInfo  Overview  Group

[New - Windows NT]

LVM_DELETECOLUMN

wParam = (WPARAM) (int) iCol;

lParam = 0;

// Corresponding macro

BOOL ListView_DeleteColumn(HWND hwnd, int iCol);

The LVM_DELETECOLUMN message removes a column from a list view control. You can send this message explicitly or by using the ListView_DeleteColumn macro.

Parameters

hwnd

Handle to the list view control.

iCol

Index of the column to delete.

Return Value

Returns TRUE if successful or FALSE otherwise.


LVM_DELETEITEM [New - Windows NT]
LVM_DELETEITEM  QuickInfo  Overview  Group

[New - Windows NT]

LVM_DELETEITEM

wParam = (WPARAM) (int) iItem;

lParam = 0;

// Corresponding macro

BOOL ListView_DeleteItem(HWND hwnd, int iItem);

The LVM_DELETEITEM message removes an item from a list view control. You can send this message explicitly or by using the ListView_DeleteItem macro.

Parameters

hwnd

Handle to the list view control.

iItem

Index of the list view item to delete.

Return Value

Returns TRUE if successful or FALSE otherwise.


LVM_EDITLABEL [New - Windows NT]
LVM_EDITLABEL  QuickInfo  Overview  Group

[New - Windows NT]

LVM_EDITLABEL

wParam = (WPARAM) (int) iItem;

lParam = 0;

// Corresponding macro

HWND ListView_EditLabel(HWND hwnd, int iItem);

The LVM_EDITLABEL message begins in-place editing of the specified list view item's text. The message implicitly selects and focuses the specified item. You can send this message explicitly or by using the ListView_EditLabel macro.

Parameters

hwnd

Handle to the list view control.

iItem

Index of the list view item. To cancel editing, set iItem to −1.

Return Value

Returns the handle of the edit control that is used to edit the item text if successful or NULL otherwise.

Remarks

When the user completes or cancels editing, the edit control is destroyed and the handle is no longer valid. You can safely subclass the edit control, but you should not destroy it.

The control must have the focus before you send this message to the control. Focus can be set using the SetFocus function.

See Also

WM_CANCELMODE, SetFocus


LVM_ENSUREVISIBLE [New - Windows NT]
LVM_ENSUREVISIBLE  QuickInfo  Overview  Group

[New - Windows NT]

LVM_ENSUREVISIBLE

wParam = (WPARAM) (int) iItem;

lParam = (LPARAM) (BOOL) fPartialOk;

// Corresponding macro

BOOL ListView_EnsureVisible(HWND hwnd, int i, BOOL fPartialOK);

The LVM_ENSUREVISIBLE message ensures that a list view item is entirely or at least partially visible, scrolling the list view control if necessary. You can send this message explicitly or by using the ListView_EnsureVisible macro.

Parameters

hwnd

Handle to the list view control.

i

Index of the list view item.

fPartialOK

Value specifying whether the item must be entirely visible. If this parameter is TRUE, no scrolling occurs if the item is at least partially visible.

Return Value

Returns TRUE if successful or FALSE otherwise.


LVM_FINDITEM [New - Windows NT]
LVM_FINDITEM  QuickInfo  Overview  Group

[New - Windows NT]

LVM_FINDITEM

wParam = (WPARAM) (int) iStart;

lParam = (LPARAM) (const LV_FINDINFO FAR *) plvfi;

// Corresponding macro

int ListView_FindItem(HWND hwnd, int iStart,

    const LV_FINDINFO FAR* plvfi);

The LVM_FINDITEM message searches for a list view item with the specified characteristics. You can send this message explicitly or by using the ListView_FindItem macro.

Parameters

hwnd

Handle to the list view control.

iStart

Index of the item to begin the search with or −1 to start from the beginning. The specified item is itself excluded from the search.

plvfi

Pointer to an LV_FINDINFO structure that contains information about what to search for.

Return Value

Returns the index of the item if successful or −1 otherwise.

See Also

LV_FINDINFO


LVM_GETBKCOLOR [New - Windows NT]
LVM_GETBKCOLOR  QuickInfo  Overview  Group

[New - Windows NT]

LVM_GETBKCOLOR

wParam = 0;

lParam = 0;

// Corresponding macro

COLORREF ListView_GetBkColor(HWND hwnd);

The LVM_GETBKCOLOR message retrieves the background color of a list view control. You can send this message explicitly or by using the ListView_GetBkColor macro.

Parameters

hwnd

Handle to the list view control.

Return Value

Returns the background color of the list view control.


LVM_GETCALLBACKMASK [New - Windows NT]
LVM_GETCALLBACKMASK  QuickInfo  Overview  Group

[New - Windows NT]

LVM_GETCALLBACKMASK

wParam = 0;

lParam = 0;

// Corresponding macro

UINT ListView_GetCallbackMask(HWND hwnd);

The LVM_GETCALLBACKMASK message retrieves the callback mask for a list view control. You can send this message explicitly or by using the ListView_GetCallbackMask macro.

Parameters

hwnd

Handle to the list view control.

Return Value

Returns the callback mask.


LVM_GETCOLUMN [New - Windows NT]
LVM_GETCOLUMN  QuickInfo  Overview  Group

[New - Windows NT]

LVM_GETCOLUMN

wParam = (WPARAM) (int) iCol;

lParam = (LPARAM) (LV_COLUMN FAR *) pcol;

// Corresponding macro

BOOL ListView_GetColumn(HWND hwnd, int iCol,

LV_COLUMN FAR* pcol);

The LVM_GETCOLUMN message retrieves the attributes of a list view control's column. You can send this message explicitly or by using the ListView_GetColumn macro.

Parameters

hwnd

Handle to the list view control.

iCol

Index of the column.

pcol

Pointer to an LV_COLUMN structure that specifies the information to retrieve and receives information about the column. The mask member specifies which column attributes to retrieve.

If the mask member specifies the LVCF_TEXT value, the pszText member must contain the pointer to the buffer that receives the item text and the cchTextMax member must specify the size of the buffer.

Return Value

Returns TRUE if successful or FALSE otherwise.

See Also

LV_COLUMN


LVM_GETCOLUMNWIDTH [New - Windows NT]
LVM_GETCOLUMNWIDTH  QuickInfo  Overview  Group

[New - Windows NT]

LVM_GETCOLUMNWIDTH

wParam = (WPARAM) (int) iCol;

lParam = 0;

// Corresponding macro

int ListView_GetColumnWidth(HWND hwnd, int iCol);

The LVM_GETCOLUMNWIDTH message retrieves the width of a column in report or list view. You can send this message explicitly or by using the ListView_GetColumnWidth macro.

Parameters

hwnd

Handle to the list view control.

iCol

Index of the column. This parameter is ignored in list view.

Return Value

Returns the column width if successful or zero otherwise.


LVM_GETCOUNTPERPAGE [New - Windows NT]
LVM_GETCOUNTPERPAGE  QuickInfo  Overview  Group

[New - Windows NT]

LVM_GETCOUNTPERPAGE

wParam = 0;

lParam = 0;

// Corresponding macro

int ListView_GetCountPerPage(HWND hwnd);

The LVM_GETCOUNTPERPAGE message calculates the number of items that can fit vertically in the visible area of a list view control when in list or report view. Only fully-visible items are counted. You can send this message explicitly, or by using the ListView_GetCountPerPage macro.

Parameters

hwnd

Handle to the list view control.

Return Value

Returns the number of fully-visible items if successful. If the current view is icon or small icon view, the return value is the total number of items in the list view control.


LVM_GETEDITCONTROL [New - Windows NT]
LVM_GETEDITCONTROL  QuickInfo  Overview  Group

[New - Windows NT]

LVM_GETEDITCONTROL

wParam = 0;

lParam = 0;

// Corresponding macro

HWND ListView_GetEditControl(HWND hwnd);

The LVM_GETEDITCONTROL message retrieves the handle to the edit control being used to edit a list view item's text. You can send this message explicitly or by using the ListView_GetEditControl macro.

Parameters

hwnd

Handle to the list view control.

Return Value

Returns the handle to the edit control if successful or NULL otherwise.

Remarks

If no label is being edited, the return value is NULL. The edit control is not created until after the LVN_BEGINLABELEDIT notification message is sent.

When the user completes or cancels editing, the edit control is destroyed and the handle is no longer valid. You can safely subclass the edit control, but you should not destroy it. To cancel editing, you can send the list view control a WM_CANCELMODE message.

The list view item being edited is the currently focused item — that is, the item in the focused state. To find an item based on its state, use the LVM_GETNEXTITEM message.

See Also

LVN_BEGINLABELEDIT, LVM_GETNEXTITEM, WM_CANCELMODE


LVM_GETIMAGELIST [New - Windows NT]
LVM_GETIMAGELIST  QuickInfo  Overview  Group

[New - Windows NT]

LVM_GETIMAGELIST

wParam = (WPARAM) (int) iImageList;

lParam = 0;

// Corresponding macro

HIMAGELIST ListView_GetImageList(HWND hwnd, int iImageList);

The LVM_GETIMAGELIST message retrieves the handle to an image list used for drawing list view items. You can send this message explicitly or by using the ListView_GetImageList macro.

Parameters

hwnd

Handle to the list view control.

iImageList

Image list to retrieve. This parameter can be one of the following values:

Value	Meaning
LVSIL_NORMAL	Image list with large icons
LVSIL_SMALL	Image list with small icons
LVSIL_STATE	Image list with state images
Return Value

Returns the handle of the specified image list if successful or NULL otherwise.


LVM_GETISEARCHSTRING
LVM_GETISEARCHSTRING  Overview  Group

LVM_GETISEARCHSTRING

wParam = 0;

lParam = (LPARAM) (LPSTR) lpsz;

// Corresponding macro

BOOL ListView_GetISearchString(HWND hwnd, LPSTR lpsz);

The LVM_GETISEARCHSTRING message retrieves the incremental search string of a list-view control. You can send this message explicitly or by using the ListView_GetISearchString macro.

Parameters

hwnd

Handle to the list view control.

lpsz

Pointer to a buffer that receives the incremental search string.

Return Value

Returns the number of characters in the incremental search string, or zero if the list-view control is not in incremental search mode.

Remarks

The incremental search string is the character sequence that the user types while the list view has the input focus. Each time the user types a character, the system appends the character to the search string and then searches for a matching item. If the system finds a match, it selects the item and, if necessary, scrolls it into view.

A timeout period is associated with each character that the user types. If the timeout period elapses before the user types another character, the incremental search string is reset.


LVM_GETITEM [New - Windows NT]
LVM_GETITEM  QuickInfo  Overview  Group

[New - Windows NT]

LVM_GETITEM

wParam = 0;

lParam = (LPARAM) (LV_ITEM FAR*) pitem;

// Corresponding macro

BOOL ListView_GetItem(HWND hwnd, LV_ITEM FAR* pitem);

The LVM_GETITEM message retrieves some or all of a list view item's attributes. You can send this message explicitly or by using the ListView_GetItem macro.

Parameters

hwnd

Handle to the list view control.

pitem

Pointer to an LV_ITEM structure that specifies the information to retrieve and receives information about the list view item.

When the message is sent, the iItem and iSubItem members identify the item or subitem to retrieve information about and the mask member specifies which attributes to retrieve. For a list of possible values, see the description of the LV_ITEM structure.

If the mask member specifies the LVIF_TEXT value, the pszText member must contain the pointer to the buffer that receives the item text and the cchTextMax member must specify the size of the buffer.

If the mask member specifies the LVIF_STATE value, the stateMask member specifies which item states are to be returned.

Return Value

Returns TRUE if successful or FALSE otherwise.

See Also

LV_ITEM


LVM_GETITEMCOUNT [New - Windows NT]
LVM_GETITEMCOUNT  QuickInfo  Overview  Group

[New - Windows NT]

LVM_GETITEMCOUNT

wParam = 0;

lParam = 0;

// Corresponding macro

int ListView_GetItemCount(HWND hwnd);

The LVM_GETITEMCOUNT message retrieves the number of items in a list view control. You can send this message explicitly or by using the ListView_GetItemCount macro.

Parameters

hwnd

Handle to the list view control.

Return Value

Returns the number of items.


LVM_GETITEMPOSITION [New - Windows NT]
LVM_GETITEMPOSITION  QuickInfo  Overview  Group

[New - Windows NT]

LVM_GETITEMPOSITION

wParam = (WPARAM) (int) i;

lParam = (LPARAM) (POINT FAR *) ppt;

// Corresponding macro

BOOL ListView_GetItemPosition(HWND hwnd, int i, POINT FAR* ppt);

The LVM_GETITEMPOSITION message retrieves the position of a list view item. You can send this message explicitly or by using the ListView_GetItemPosition macro.

Parameters

hwnd

Handle to the list view control.

i

Index of the list view item.

ppt

Pointer to a POINT structure that receives the position of the item's upper-left corner, in view coordinates.

Return Value

Returns TRUE if successful or FALSE otherwise.

See Also

POINT


LVM_GETITEMRECT [New - Windows NT]
LVM_GETITEMRECT  QuickInfo  Overview  Group

[New - Windows NT]

LVM_GETITEMRECT

wParam = (WPARAM) (int) i;

lParam = (LPARAM) (LPRECT) prc;

// Corresponding macro

BOOL ListView_GetItemRect(HWND hwnd, int i, RECT FAR* prc, int code);

The LVM_GETITEMRECT message retrieves the bounding rectangle for all or part of an item in the current view. You can send this message explicitly or by using the ListView_GetItemRect macro.

Parameters

hwnd

Handle to the list view control.

i

Index of the list view item.

prc

Pointer to a RECT structure that receives the bounding rectangle. When the message is sent, the left member of this structure contains the value of the code parameter.

code

Portion of the list view item for which to retrieve the bounding rectangle. This parameter can be one of the following values:

Value	Meaning
LVIR_BOUNDS	Returns the bounding rectangle of the entire item, including the icon and label.
LVIR_ICON	Returns the bounding rectangle of the icon or small icon.
LVIR_LABEL	Returns the bounding rectangle of the item text.
LVIR_SELECTBOUNDS	Returns the union of the LVIR_ICON and LVIR_LABEL rectangles, but excludes columns in details view.
Return Value

Returns TRUE if successful or FALSE otherwise.

Remarks

This parameter is specified by the left member of the RECT structure pointed to by prc.

See Also

RECT


LVM_GETITEMSPACING [New - Windows NT]
LVM_GETITEMSPACING  QuickInfo  Overview  Group

[New - Windows NT]

LVM_GETITEMSPACING

wParam = (WPARAM) (BOOL) fSmall;

lParam = 0;

// Corresponding macro

DWORD ListView_GetItemSpacing(HWND hwnd, BOOL fSmall);

The LVM_GETITEMSPACING message determines the spacing between items in a list view control. You can send this message explicitly or by using the ListView_GetItemSpacing macro.

Parameters

hwnd

Handle to the list view control.

fSmall

View to retrieve the item spacing for. This parameter is TRUE for small icon view, or FALSE for icon view.

Return Value

Returns the amount of spacing between items.


LVM_GETITEMSTATE [New - Windows NT]
LVM_GETITEMSTATE  QuickInfo  Overview  Group

[New - Windows NT]

LVM_GETITEMSTATE

wParam = (WPARAM) (int) i;

lParam = (LPARAM) (UINT) mask;

// Corresponding macro

UINT WINAPI ListView_GetItemState(HWND hwnd, int i, UINT mask);

The LVM_GETITEMSTATE message retrieves the state of a list view item. You can send this message explicitly or by using the ListView_GetItemState macro.

Parameters

hwnd

Handle to the list view control.

i

Index of the list view item.

mask

Mask that specifies which of the item's state flags to return.

Return Value

Returns the item's state flags.


LVM_GETITEMTEXT [New - Windows NT]
LVM_GETITEMTEXT  QuickInfo  Overview  Group

[New - Windows NT]

LVM_GETITEMTEXT

wParam = (WPARAM) (int) iItem;

lParam = (LPARAM) (LV_ITEM FAR *) pitem;

// Corresponding macro

void WINAPI ListView_GetItemText(HWND hwnd, int iItem,

     int iSubItem, LPSTR pszText, int cchTextMax);

The LVM_GETITEMTEXT message retrieves the text of a list view item or subitem.

Parameters

The message has the following parameters:

hwnd

Handle to the list view control.

iItem

Index of the list view item.

pitem

Pointer to an LV_ITEM structure. The iSubItem member specifies the index of a subitem, or it can be zero to get the item label. The pszText member points to a buffer that receives the text, and the cchTextMax member specifies the size of the buffer.

The macro has the following parameters:

hwnd

Handle to the list view control.

iItem

Index of the list view item.

iSubItem

Index of the subitem, or zero to retrieve the item label.

pszText

Pointer to the buffer that receives the item or subitem text.

cchTextMax

Size of the buffer, in bytes.

Return Value

If you send this message explicitly, it returns the length of the retrieved string.

If you can send this message implicitly by using the ListView_GetItemText macro, there is no return value.

See Also

LV_ITEM


LVM_GETNEXTITEM [New - Windows NT]
LVM_GETNEXTITEM  QuickInfo  Overview  Group

[New - Windows NT]

LVM_GETNEXTITEM

wParam = (WPARAM) (int) iStart;

lParam = MAKELPARAM((UINT) flags, 0);

// Corresponding macro

int ListView_GetNextItem(HWND hwnd, int iStart, UINT flags);

The LVM_GETNEXTITEM message searches for a list view item that has the specified properties and bears the specified relationship to a specified item. You can send this message explicitly or by using the ListView_GetNextItem macro.

Parameters

hwnd

Handle to the list view control.

iStart

Index of the item to begin the searching with, or −1 to find the first item that matches the specified flags. The specified item itself is excluded from the search.

flags

Geometric relation of the requested item to the specified item and, if specified, the state of the requested item.

The geometric relation can be one of the following values:

Value	Meaning
LVNI_ABOVE	Searches for an item that is above the specified item.
LVNI_ALL	Searches for a subsequent item by index (the default value).
LVNI_BELOW	Searches for an item that is below the specified item.
LVNI_TOLEFT	Searches for an item to the left of the specified item.
LVNI_TORIGHT	Searches for an item to the right of the specified item.
The state can be zero, or it can be one or more of the following values:

Value	Meaning
LVNI_CUT	The item has the LVIS_CUT state flag set.
LVNI_DROPHILITED	The item has the LVIS_DROPHILITED state flag set.
LVNI_FOCUSED	The item has the LVIS_FOCUSED state flag set.
LVNI_SELECTED	The item has the LVIS_SELECTED state flag set.
If an item does not have all of the specified state flags set, the search continues with the next item.

Return Value

Returns the index of the next item if successful or −1 otherwise.


LVM_GETORIGIN [New - Windows NT]
LVM_GETORIGIN  QuickInfo  Overview  Group

[New - Windows NT]

LVM_GETORIGIN

wParam = 0;

lParam = (LPARAM) (LPPOINT) lpptOrg;

// Corresponding macro

BOOL ListView_GetOrigin(HWND hwnd, LPPOINT lpptOrg);

The LVM_GETORIGIN message retrieves the current view origin for a list view control. You can send this message explicitly or by using the ListView_GetOrigin macro.

Parameters

hwnd

Handle to the list view control.

lpptOrg

Pointer to a POINT structure that receives the view origin.

Return Value

Returns TRUE if successful or FALSE if the current view is list or report view.

See Also

POINT


LVM_GETSELECTEDCOUNT [New - Windows NT]
LVM_GETSELECTEDCOUNT  QuickInfo  Overview  Group

[New - Windows NT]

LVM_GETSELECTEDCOUNT

wParam = 0;

lParam = 0;

// Corresponding macro

UINT ListView_GetSelectedCount(HWND hwnd);

The LVM_GETSELECTEDCOUNT message determines the number of selected items in a list view control. You can send this message explicitly or by using the ListView_GetSelectedCount macro.

Parameters

hwnd

Handle to the list view control.

Return Value

Returns the number of selected items.


LVM_GETSTRINGWIDTH [New - Windows NT]
LVM_GETSTRINGWIDTH  QuickInfo  Overview  Group

[New - Windows NT]

LVM_GETSTRINGWIDTH

wParam = 0;

lParam = (LPARAM) (LPCSTR) psz;

// Corresponding macro

int ListView_GetStringWidth(HWND hwnd, LPCSTR psz);

The LVM_GETSTRINGWIDTH message determines the width of a specified string, using the specified list view control's current font. You can send this message explicitly or by using the ListView_GetStringWidth macro.

Parameters

hwnd

Handle to the list view control.

psz

Pointer to a null-terminated string.

Return Value

Returns the string width if successful or zero otherwise.


LVM_GETTEXTBKCOLOR [New - Windows NT]
LVM_GETTEXTBKCOLOR  QuickInfo  Overview  Group

[New - Windows NT]

LVM_GETTEXTBKCOLOR

wParam = 0;

lParam = 0;

// Corresponding macro

COLORREF ListView_GetTextBkColor(HWND hwnd);

The LVM_GETTEXTBKCOLOR message retrieves the text background color of a list view control. You can send this message explicitly or by using the ListView_GetTextBkColor macro.

Parameters

hwnd

Handle to the list view control.

Return Value

Returns the background color of the text.


LVM_GETTEXTCOLOR [New - Windows NT]
LVM_GETTEXTCOLOR  QuickInfo  Overview  Group

[New - Windows NT]

LVM_GETTEXTCOLOR

wParam = 0;

lParam = 0;

// Corresponding macro

COLORREF ListView_GetTextColor(HWND hwnd);

The LVM_GETTEXTCOLOR message retrieves the text color of a list view control. You can send this message explicitly or by using the ListView_GetTextColor macro.

Parameters

hwnd

Handle to the list view control.

Return Value

Returns the text color.


LVM_GETTOPINDEX [New - Windows NT]
LVM_GETTOPINDEX  QuickInfo  Overview  Group

[New - Windows NT]

LVM_GETTOPINDEX

wParam = 0;

lParam = 0;

// Corresponding macro

int ListView_GetTopIndex(HWND hwnd);

The LVM_GETTOPINDEX message retrieves the index of the topmost visible item when in list or report view. You can send this message explicitly or by using the ListView_GetTopIndex macro.

Parameters

hwnd

Handle to the list view control.

Return Value

Returns the index of the item if successful or zero if the list view control is in icon or small icon view.


LVM_GETVIEWRECT [New - Windows NT]
LVM_GETVIEWRECT  QuickInfo  Overview  Group

[New - Windows NT]

LVM_GETVIEWRECT

wParam = 0;

lParam = (LPARAM) (RECT FAR *) prc;

// Corresponding macro

BOOL ListView_GetViewRect(HWND hwnd, RECT FAR* prc);

The LVM_GETVIEWRECT message retrieves the bounding rectangle of all items in the list view control. The list view must be in icon or small icon view. You can send this message explicitly or by using the ListView_GetViewRect macro.

Parameters

hwnd

Handle to the list view control.

prc

Pointer to a RECT structure that receives the bounding rectangle. All coordinates are relative to the visible area of the list view control.

Return Value

Returns TRUE if successful or FALSE otherwise.

See Also

RECT


LVM_HITTEST [New - Windows NT]
LVM_HITTEST  QuickInfo  Overview  Group

[New - Windows NT]

LVM_HITTEST

wParam = 0;

lParam = (LPARAM) (LV_HITTESTINFO FAR *) pinfo;

// Corresponding macro

int ListView_HitTest(HWND hwnd, LV_HITTESTINFO FAR* pinfo);

The LVM_HITTEST message determines which list view item, if any, is at a specified position. You can send this message explicitly or by using the ListView_HitTest macro.

Parameters

hwnd

Handle to the list view control.

pinfo

Pointer to an LV_HITTESTINFO structure that contains the position to hit test and receives information about the results of the hit test.

Return Value

Returns the index of the item at the specified position, if any, or −1 otherwise.

See Also

LV_HITTESTINFO


LVM_INSERTCOLUMN [New - Windows NT]
LVM_INSERTCOLUMN  QuickInfo  Overview  Group

[New - Windows NT]

LVM_INSERTCOLUMN

wParam = (WPARAM) (int) iCol;

lParam = (LPARAM) (const LV_COLUMN FAR *) pcol;

// Corresponding macro

int ListView_InsertColumn(HWND hwnd, int iCol,

    const LV_COLUMN FAR* pcol);

The LVM_INSERTCOLUMN message inserts a new column in a list view control. You can send this message explicitly or by using the ListView_InsertColumn macro.

Parameters

hwnd

Handle to the list view control.

iCol

Index of the new column.

pcol

Pointer to an LV_COLUMN structure that contains the attributes of the new column.

Return Value

Returns the index of the new column if successful or −1 otherwise.

See Also

LV_COLUMN


LVM_INSERTITEM [New - Windows NT]
LVM_INSERTITEM  QuickInfo  Overview  Group

[New - Windows NT]

LVM_INSERTITEM

wParam = 0;

lParam = (LPARAM) (const LV_ITEM FAR *) pitem;

// Corresponding macro

int ListView_InsertItem(HWND hwnd, const LV_ITEM FAR* pitem);

The LVM_INSERTITEM message inserts a new item in a list view control. You can send this message explicitly or by using the ListView_InsertItem macro.

Parameters

hwnd

Handle to the list view control.

pitem

Pointer to an LV_ITEM structure that specifies the attributes of the list view item. The iItem member specifies the index of the new item. The iSubItem member must be zero; the macro cannot be used to insert subitems.

Return Value

Returns the index of the new item if successful or −1 otherwise.

See Also

LV_ITEM


LVM_REDRAWITEMS [New - Windows NT]
LVM_REDRAWITEMS  QuickInfo  Overview  Group

[New - Windows NT]

LVM_REDRAWITEMS

wParam = (int) iFirst;  // index of first item to redraw

lParam = (int) iLast;  // index of last item to redraw

// Corresponding macro

BOOL ListView_RedrawItems(HWND hwnd, int iFirst, int iLast);

The LVM_REDRAWITEMS message forces a list view control to redraw a range of items. You can send this message explicitly or by using the ListView_RedrawItems macro.

Parameters

hwnd

Handle to the list view control.

iFirst

Index of the first item to redraw.

iLast

Index of the last item to redraw.

Return Value

Returns TRUE if successful or FALSE otherwise.

Remarks

The specified items are not actually redrawn until the list view window receives a WM_PAINT message to repaint. To repaint immediately, call the UpdateWindow function after using this macro.

See Also

UpdateWindow, WM_PAINT


LVM_SCROLL [New - Windows NT]
LVM_SCROLL  QuickInfo  Overview  Group

[New - Windows NT]

LVM_SCROLL

wParam = (int) dx;  // amount of horizontal scrolling, in pixels or columns

lParam = (int) dy;   // amount of vertical scrolling, in pixels

// Corresponding macro

BOOL ListView_Scroll(HWND hwnd, int dx, int dy);

The LVM_SCROLL message scrolls the content of a list view control. You can send this message explicitly or by using the ListView_Scroll macro.

Parameters

hwnd

Handle to the list view control.

dx

Integer value that specifies the amount of horizontal scrolling.

If the view type of the list view control is icon view, small icon view, or report view, this value specifies the number of pixels to scroll. If the view type of the list view control is list view, this value specifies the number of columns to scroll.

dy

Integer value that specifies the amount of vertical scrolling.

If the view type of the list view control is icon view, small icon view, or list view, this value specifies the number of pixels to scroll. If the view type of the list view control is report view, this value specifies the number of lines to scroll.

Return Value

Returns TRUE if successful or FALSE otherwise.


LVM_SETBKCOLOR [New - Windows NT]
LVM_SETBKCOLOR  QuickInfo  Overview  Group

[New - Windows NT]

LVM_SETBKCOLOR

wParam = 0;

lParam = (LPARAM) (COLORREF) clrBk;

// Corresponding macro

BOOL ListView_SetBkColor(HWND hwnd, COLORREF clrBk);

The LVM_SETBKCOLOR message sets the background color of a list view control. You can send this message explicitly or by using the ListView_SetBkColor macro.

Parameters

hwnd

Handle to the list view control.

clrBk

Background color to set or the CLR_NONE value for no background color. List view controls with background colors redraw themselves significantly faster than those without background colors.

Return Value

Returns TRUE if successful or FALSE otherwise.


LVM_SETCALLBACKMASK [New - Windows NT]
LVM_SETCALLBACKMASK  QuickInfo  Overview  Group

[New - Windows NT]

LVM_SETCALLBACKMASK

wParam = (WPARAM) (UINT) mask;

lParam = 0;

// Corresponding macro

BOOL ListView_SetCallbackMask(HWND hwnd, UINT mask);

The LVM_SETCALLBACKMASK message sets the callback mask for a list view control. You can send this message explicitly or by using the ListView_SetCallbackMask macro.

Parameters

hwnd

Handle to the list view control.

mask

New value of the callback mask.

Return Value

Returns TRUE if successful or FALSE otherwise.


LVM_SETCOLUMN [New - Windows NT]
LVM_SETCOLUMN  QuickInfo  Overview  Group

[New - Windows NT]

LVM_SETCOLUMN

wParam = (WPARAM) (int) iCol;

lParam = (LPARAM) (const LV_COLUMN FAR *) pcol;

// Corresponding macro

BOOL ListView_SetColumn(HWND hwnd, int iCol, LV_COLUMN FAR* pcol);

The LVM_SETCOLUMN message sets the attributes of a list view column. You can send this message explicitly or by using the ListView_SetColumn macro.

Parameters

hwnd

Handle to the list view control.

iCol

Index of the column.

pcol

Pointer to an LV_COLUMN structure that contains the new column attributes. The mask member specifies which column attributes to set.

If the mask member specifies the LVCF_TEXT value, the pszText member is the pointer to a null-terminated string and the cchTextMax member is ignored.

Return Value

Returns TRUE if successful or FALSE otherwise.

See Also

LV_COLUMN


LVM_SETCOLUMNWIDTH [New - Windows NT]
LVM_SETCOLUMNWIDTH  QuickInfo  Overview  Group

[New - Windows NT]

LVM_SETCOLUMNWIDTH

wParam = (WPARAM) (int) iCol;

lParam = MAKELPARAM((int) cx, 0);

// Corresponding macro

BOOL ListView_SetColumnWidth(HWND hwnd, int iCol, int cx);

The LVM_SETCOLUMNWIDTH message changes the width of a column in report or list view. You can send this message explicitly or by using the ListView_SetColumnWidth macro.

Parameters

hwnd

Handle to the list view control.

iCol

Index of the column. In list view, the iCol parameter must be −1.

cx

New width of the column, in list view coordinates, or one of the following values:

Value	Meaning
LVSCW_AUTOSIZE	Automatically sizes the column.
LVSCW_AUTOSIZE_USEHEADER	Automatically sizes the column to fit the header text.


LVM_SETIMAGELIST [New - Windows NT]
LVM_SETIMAGELIST  QuickInfo  Overview  Group

[New - Windows NT]

LVM_SETIMAGELIST

wParam = (WPARAM) (int) iImageList;

lParam = (LPARAM) (HIMAGELIST) himl;

// Corresponding macro

HIMAGELIST ListView_SetImageList(HWND hwnd, HIMAGELIST himl, int iImageList);

The LVM_SETIMAGELIST message assigns an image list to a list view control. You can send this message explicitly or by using the ListView_SetImageList macro.

Parameters

hwnd

Handle to the list view control.

himl

Handle to the image list to assign.

iImageList

Type of image list. This parameter can be one of the following values:

Value	Meaning
LVSIL_NORMAL	Image list with large icons
LVSIL_SMALL	Image list with small icons
LVSIL_STATE	Image list with state images
Return Value

Returns the handle of the image list previously associated with the control if successful; NULL otherwise.


LVM_SETITEM [New - Windows NT]
LVM_SETITEM  QuickInfo  Overview  Group

[New - Windows NT]

LVM_SETITEM

wParam = 0;

lParam = (LPARAM) (const LV_ITEM FAR *) pitem;

// Corresponding macro

BOOL ListView_SetItem(HWND hwnd, const LV_ITEM FAR* pitem);

The LVM_SETITEM message sets some or all of a list view item's attributes. You can send this message explicitly or by using the ListView_SetItem macro.

Parameters

hwnd

Handle to the list view control.

pitem

Pointer to an LV_ITEM structure that contains the new item attributes. The iItem and iSubItem members identify the item or subitem, and the mask member specifies which attributes to set.

If the mask member specifies the LVIF_TEXT value, the pszText member is the pointer to a null-terminated string and the cchTextMax member is ignored.

If the mask member specifies the LVIF_STATE value, the stateMask member specifies which item states to change and the state member contains the values for those states.

Return Value

Returns TRUE if successful or FALSE otherwise.

See Also

LV_ITEM


LVM_SETITEMCOUNT [New - Windows NT]
LVM_SETITEMCOUNT  QuickInfo  Overview  Group

[New - Windows NT]

LVM_SETITEMCOUNT

wParam = (WPARAM) (int) cItems;

lParam = 0;

// Corresponding macro

VOID ListView_SetItemCount(HWND hwnd, int cItems);

The LVM_SETITEMCOUNT message prepares a list view control for adding a large number of items. You can send this message explicitly or by using the ListView_SetItemCount macro.

Parameters

hwnd

Handle to the list view control.

cItems

Number of items that the list view control will ultimately contain.

Return Value

No return value.

Remarks

By sending the LVM_SETITEMCOUNT message before adding a large number of items, you enable a list view control to reallocate its internal data structures only once rather than every time you add an item.


LVM_SETITEMPOSITION [New - Windows NT]
LVM_SETITEMPOSITION  QuickInfo  Overview  Group

[New - Windows NT]

LVM_SETITEMPOSITION

wParam = (LPARAM) (int) i;

lParam = MAKELPARAM((int) x, (int) y);

// Corresponding macro

BOOL ListView_SetItemPosition(HWND hwnd, int i, int x, int y);

The LVM_SETITEMPOSITION message moves an item to a specified position in a list view control, which must be in icon or small icon view. You can send this message explicitly or by using the ListView_SetItemPosition macro.

Parameters

hwnd

Handle to the list view control.

i

Index of the list view item.

x and y

New position of the item's upper-left corner, in view coordinates.

Return Value

Returns TRUE if successful or FALSE otherwise.

Remarks

If the list view control has the LVS_AUTOARRANGE style, the list view control is arranged after the position of the item is set.


LVM_SETITEMPOSITION32 [New - Windows NT]
LVM_SETITEMPOSITION32  QuickInfo  Overview  Group

[New - Windows NT]

LVM_SETITEMPOSITION32

wParam = (WPARAM) (int) iItem;

lParam = (LPARAM) (LPPOINT) lpptNewPos;

// Corresponding macro

void ListView_SetItemPosition32(HWND hwnd, int iItem, int x, int y);

The LVM_SETITEMPOSITION32 message moves an item to a specified position in a list view control, which must be in icon or small icon view. This message differs from the LVM_SETITEMPOSITION message in that it uses 32-bit coordinates.

Parameters

The message has the following parameters:

iItem

Index of the list view item to set the position of.

lpptNewPos

Pointer to a POINT structure that contains the new position of the item, in list view coordinates.

The macro has the following parameters:

hwnd

Handle to the list view control.

iItem

Index of the list view item to set the position of.

x and y

New horizontal and vertical coordinates of the item.

Return Value

No return value.

If you send this message by using the ListView_SetItemPosition32 macro, it has no return value.

See Also

LVM_SETITEMPOSITION, POINT


LVM_SETITEMSTATE [New - Windows NT]
LVM_SETITEMSTATE  QuickInfo  Overview  Group

[New - Windows NT]

LVM_SETITEMSTATE

wParam = (WPARAM) (int) i;

lParam = (LPARAM) (LV_ITEM FAR *) pitem;

// Corresponding macro

BOOL WINAPI ListView_SetItemState(HWND hwnd, int i,

     UINT state, UINT mask);

The LVM_SETITEMSTATE message changes the state of an item in a list view control.

Parameters

The message has the following parameters:

i

Index of the list view item.

pitem

Pointer to an LV_ITEM structure. The stateMask member specifies which state bits to change, and the state member contains the new values for those bits. The other members are ignored.

The macro has the following parameters:

hwnd

Handle to the list view control.

i

Index of the list view item.

state

New state bits for the item.

mask

Mask specifying which of the item's current state bits to change.

Return Value

If you send this message explicitly, it returns TRUE if successful or FALSE otherwise.

If you send this message implicitly by using the ListView_SetItemState macro, there is no return value.

See Also

LV_ITEM


LVM_SETITEMTEXT [New - Windows NT]
LVM_SETITEMTEXT  QuickInfo  Overview  Group

[New - Windows NT]

LVM_SETITEMTEXT

wParam = (WPARAM) (int) i;

lParam = (LPARAM) (LV_ITEM FAR *) pitem;

// Corresponding macro

VOID WINAPI ListView_SetItemText(HWND hwnd, int i,

int iSubItem, LPCSTR pszText);

The LVM_SETITEMTEXT message changes the text of a list view item or subitem.

Parameters

The message has the following parameters:

i

Index of the list view item.

pitem

Pointer to an LV_ITEM structure. The iSubItem member is the index of the subitem, or it can be zero to set the item label. The pszText member is the pointer to a null-terminated string containing the new text; it can also be NULL.

The macro has the following parameters:

hwnd

Handle to the list view control.

i

Index of the list view item.

iSubItem

Index of the subitem or zero to set the item label.

pszText

Pointer to a null-terminated string that contains the new text. This parameter can be NULL.

Return Value

If you send this message explicitly, it returns TRUE if successful or FALSE otherwise.

If you send this message implicitly by using the ListView_SetItemText macro, there is no return value.

See Also

LV_ITEM


LVM_SETTEXTBKCOLOR [New - Windows NT]
LVM_SETTEXTBKCOLOR  QuickInfo  Overview  Group

[New - Windows NT]

LVM_SETTEXTBKCOLOR

wParam = 0;

lParam = (LPARAM) (COLORREF) clrText;

// Corresponding macro

BOOL ListView_SetTextBkColor(HWND hwnd, COLORREF clrText);

The LVM_SETTEXTBKCOLOR message sets the background color of text in a list view control. You can send this message explicitly or by using the ListView_SetTextBkColor macro.

Parameters

hwnd

Handle to the list view control.

clrText

New text color.

Return Value

Returns TRUE if successful or FALSE otherwise.


LVM_SETTEXTCOLOR [New - Windows NT]
LVM_SETTEXTCOLOR  QuickInfo  Overview  Group

[New - Windows NT]

LVM_SETTEXTCOLOR

wParam = 0;

lParam = (LPARAM) (COLORREF) clrText;

// Corresponding macro

BOOL ListView_SetTextColor(HWND hwnd, COLORREF clrText);

The LVM_SETTEXTCOLOR message sets the text color of a list view control. You can send this message explicitly or by using the ListView_SetTextColor macro.

Parameters

hwnd

Handle to the list view control.

clrText

New text color.

Return Value

Returns TRUE if successful or FALSE otherwise.


LVM_SORTITEMS [New - Windows NT]
LVM_SORTITEMS  QuickInfo  Overview  Group

[New - Windows NT]

LVM_SORTITEMS

wParam = (WPARAM) (LPARAM) lParamSort;

lParam = (LPARAM) (PFNLVCOMPARE) pfnCompare;

// Corresponding macro

BOOL ListView_SortItems(HWND hwnd, PFNLVCOMPARE pfnCompare,

LPARAM lParamSort);

The LVM_SORTITEMS message sorts list view items using an application-defined comparison function. The index of each item changes to reflect the new sequence. You can send this message explicitly or by using the ListView_SortItems macro.

Parameters

hwnd

Handle to the list view control.

pfnCompare

Pointer to the application-defined comparison function. The comparison function is called during the sort operation each time the relative order of two list items needs to be compared. For more information, see the following.

lParamSort

Application-defined value that is passed to the comparison function.

Return Value

Returns TRUE if successful or FALSE otherwise.

Remarks

The comparison function has the following form:

int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2,

LPARAM lParamSort);

The comparison function must return a negative value if the first item should precede the second, a positive value if the first item should follow the second, or zero if the two items are equivalent.

The lParam1 and lParam2 parameters specify the item data for the two items being compared. The lParamSort parameter is the same value passed to the LVM_SORTITEMS message.


LVM_UPDATE [New - Windows NT]
LVM_UPDATE  QuickInfo  Overview  Group

[New - Windows NT]

LVM_UPDATE

wParam = (WPARAM) iItem;

lParam = 0;

// Corresponding macro

BOOL ListView_Update(HWND hwnd, int iItem);

The LVM_UPDATE message updates a list view item. If the list view control has the LVS_AUTOARRANGE style, this macro causes the list view control to be arranged. You can send this message explicitly or by using the ListView_Update macro.

Parameters

hwnd

Handle to the list view control.

iItem

Index of the item to update.

Return Value

Returns TRUE if successful or FALSE otherwise.


LVN_BEGINDRAG [New - Windows NT]
LVN_BEGINDRAG  QuickInfo  Overview  Group

[New - Windows NT]

LVN_BEGINDRAG

pnmv = (NM_LISTVIEW FAR *) lParam;

The LVN_BEGINDRAG notification message notifies a list view control's parent window that a drag-and-drop operation involving the left mouse button is being initiated. This notification message is sent in the form of a WM_NOTIFY message.

Parameters

pnmv

Pointer to an NM_LISTVIEW structure. The iItem member identifies the item being dragged, and the other members are zero.

Return Value

No return value.

See Also

NM_LISTVIEW, WM_NOTIFY


LVN_BEGINLABELEDIT [New - Windows NT]
LVN_BEGINLABELEDIT  QuickInfo  Overview  Group

[New - Windows NT]

LVN_BEGINLABELEDIT

pdi = (LV_DISPINFO FAR *) lParam;

The LVN_BEGINLABELEDIT notification message notifies a list view control's parent window about the start of label editing for an item. This notification message is sent in the form of a WM_NOTIFY message.

Parameters

pdi

Pointer to an LV_DISPINFO structure that contains information about the item

Return Value

Returns FALSE to allow label editing or TRUE to prevent it.

See Also

LV_DISPINFO, WM_NOTIFY


LVN_BEGINRDRAG [New - Windows NT]
LVN_BEGINRDRAG  QuickInfo  Overview  Group

[New - Windows NT]

LVN_BEGINRDRAG

pnmv = (NM_LISTVIEW FAR *) lParam;

The LVN_BEGINRDRAG notification message notifies a list view control's parent window that a drag-and-drop operation involving the right mouse button is being initiated. This notification message is sent in the form of a WM_NOTIFY message.

Parameters

pnmv

Pointer to an NM_LISTVIEW structure. The iItem member identifies the item being dragged, and the other members are zero.

Return Value

No return value.

See Also

NM_LISTVIEW, WM_NOTIFY


LVN_COLUMNCLICK [New - Windows NT]
LVN_COLUMNCLICK  QuickInfo  Overview  Group

[New - Windows NT]

LVN_COLUMNCLICK

pnmv = (NM_LISTVIEW FAR *) lParam;

The LVN_COLUMNCLICK notification message notifies a list view control's parent window that a column was clicked. This notification message is sent in the form of a WM_NOTIFY message.

Parameters

pnmv

Pointer to an NM_LISTVIEW structure. The iItem member is  − 1, and the iSubItem member identifies the column. All other members are zero.

Return Value

No return value.

See Also

NM_LISTVIEW, WM_NOTIFY


LVN_DELETEALLITEMS [New - Windows NT]
LVN_DELETEALLITEMS  QuickInfo  Overview  Group

[New - Windows NT]

LVN_DELETEALLITEMS

pnmv = (NM_LISTVIEW FAR *) lParam;

The LVN_DELETEALLITEMS notification message notifies a list view control's parent window that all items in the control were deleted. This notification message is sent in the form of a WM_NOTIFY message.

Parameters

pnmv

Pointer to an NM_LISTVIEW structure. The iItem member is  − 1, and the other members are zero.

Return Value

No return value.

See Also

NM_LISTVIEW, WM_NOTIFY


LVN_DELETEITEM [New - Windows NT]
LVN_DELETEITEM  QuickInfo  Overview  Group

[New - Windows NT]

LVN_DELETEITEM

pnmv = (NM_LISTVIEW FAR *) lParam;

The LVN_DELETEITEM notification message notifies a list view control's parent window that an item was deleted. This notification message is sent in the form of a WM_NOTIFY message.

Parameters

pnmv

Pointer to an NM_LISTVIEW structure. The iItem member identifies the deleted item, and the other members are zero.

Return Value

No return value.

See Also

NM_LISTVIEW, WM_NOTIFY


LVN_ENDLABELEDIT [New - Windows NT]
LVN_ENDLABELEDIT  QuickInfo  Overview  Group

[New - Windows NT]

LVN_ENDLABELEDIT

pdi = (LV_DISPINFO FAR *) lParam;

The LVN_ENDLABELEDIT notification message notifies a list view control's parent window about the end of label editing for an item. This notification message is sent in the form of a WM_NOTIFY message.

Parameters

pdi

Pointer to an LV_DISPINFO structure. The iItem member identifies the item being edited.

Windows 95: You can determine if editing is being canceled by checking the lpszText member; if it is NULL, the user is canceling editing.

Windows NT: If editing is being canceled, the iItem member of LV_DISPINFO may be -1.

Return Value

No return value.

Remarks

The pszText member of the LV_ITEM structure contained within the LV_DISPINFO structure pointed to by pdi contains a valid value when the LVN_ENDLABELEDIT message is sent, regardless of whether the LVIF_TEXT flag is set in the mask member of the LV_ITEM structure. Note that NULL is a valid value for pszText, indicating the cancellation of the label editing operation.

 When the user cancels the editing of an item in the listview (while in report mode, of course), the LVN_ENDLABELEDIT sets the lpszText member to NULL and the iItem member to the identifier for the item that was being edited.

See Also

LV_DISPINFO, LV_ITEM, WM_NOTIFY,


LVN_GETDISPINFO [New - Windows NT]
LVN_GETDISPINFO  QuickInfo  Overview  Group

[New - Windows NT]

LVN_GETDISPINFO

pnmv = (LV_DISPINFO FAR *) lParam;

The LVN_GETDISPINFO notification message is sent to a list view control's parent window. It is a request for the parent window to provide information needed to display or sort a list view item. The LVN_GETDISPINFO notification message is sent in the form of a WM_NOTIFY message.

Parameters

pnmv

Pointer to an LV_DISPINFO structure that specifies the type of information required and that receives the information.

Return Value

No return value.

Remarks

If your message handler sets the LVIF_DI_SETITEM flag of the mask member of the LV_ITEM structure contained within the LV_DISPINFO structure pointed to by pnmv, the operating system stores the requested information, and will not ask for it again.

See Also

LV_DISPINFO, WM_NOTIFY


LVN_INSERTITEM [New - Windows NT]
LVN_INSERTITEM  QuickInfo  Overview  Group

[New - Windows NT]

LVN_INSERTITEM

pnmv = (NM_LISTVIEW FAR *) lParam;

The LVN_INSERTITEM notification message notifies a list view control's parent window that a new item was inserted. This notification message is sent in the form of a WM_NOTIFY message.

Parameters

pnmv

Pointer to an NM_LISTVIEW structure. The iItem member identifies the new item, and the other members are zero.

Return Value

No return value.

See Also

NM_LISTVIEW, WM_NOTIFY


LVN_ITEMCHANGED [New - Windows NT]
LVN_ITEMCHANGED  QuickInfo  Overview  Group

[New - Windows NT]

LVN_ITEMCHANGED

pnmv = (NM_LISTVIEW FAR *) lParam;

The LVN_ITEMCHANGED notification message notifies a list view control's parent window that an item has changed. This notification message is sent in the form of a WM_NOTIFY message.

Parameters

pnmv

Pointer to an NM_LISTVIEW structure that identifies the item and specifies which of its attributes have changed.

Return Value

No return value.

See Also

NM_LISTVIEW, WM_NOTIFY


LVN_ITEMCHANGING [New - Windows NT]
LVN_ITEMCHANGING  QuickInfo  Overview  Group

[New - Windows NT]

LVN_ITEMCHANGING

pnmv = (NM_LISTVIEW FAR *) lParam;

The LVN_ITEMCHANGING notification message notifies a list view control's parent window that an item is changing. This notification message is sent in the form of a WM_NOTIFY message.

Parameters

pnmv

Pointer to an NM_LISTVIEW structure that identifies the item and specifies which of its attributes are changing.

Return Value

Returns TRUE to allow the change or FALSE to prevent the change.

See Also

NM_LISTVIEW, WM_NOTIFY


LVN_KEYDOWN [New - Windows NT]
LVN_KEYDOWN  QuickInfo  Overview  Group

[New - Windows NT]

LVN_KEYDOWN

pnkd = (LV_KEYDOWN FAR *) lParam;

The LVN_KEYDOWN notification message notifies a list view control's parent window that a key has been pressed. This notification message is sent in the form of a WM_NOTIFY message.

Parameters

pnkd

Pointer to an LV_KEYDOWN structure.

Return Value

No return value.

See Also

LV_KEYDOWN, WM_NOTIFY


LVN_PEN [New - Windows 95]
LVN_PEN  QuickInfo  Overview  Group

[New - Windows 95]

LVN_PEN

The LVN_PEN notification message notifies a list view control of a pen event.

Remarks

The LVN_PEN notification message is only implemented on the Windows 95 platform. In addition, the computer must have the Microsoft Windows for Pen Computing (Pen Windows) extensions installed. To determine whether Pen Windows is installed on a system, call the GetSystemMetrics function, with nIndex set to SM_PENWINDOWS.

See Also

GetSystemMetrics


LVN_SETDISPINFO [New - Windows NT]
LVN_SETDISPINFO  QuickInfo  Overview  Group

[New - Windows NT]

LVN_SETDISPINFO

pnmv = (LV_DISPINFO FAR *) lParam;

The LVN_SETDISPINFO notification message notifies a list view control's parent window that it must update the information it maintains for an item. This notification message is sent in the form of a WM_NOTIFY message.

Parameters

pnmv

Pointer to an LV_DISPINFO structure that specifies information for the changed item.

Return Value

No return value.

Remarks

The pszText member of the LV_ITEM structure contained within the LV_DISPINFO structure pointed to by pnmv contains a valid value when the LVN_SETDISPINFO message is sent, regardless of whether the LVIF_TEXT flag is set in the mask member of the LV_ITEM structure.

See Also

LV_DISPINFO, LV_ITEM, WM_NOTIFY


NM_CLICK [New - Windows NT]
NM_CLICK  QuickInfo  Overview  Group

[New - Windows NT]

NM_CLICK

pnmh = (NMHDR FAR *) lParam;

The NM_CLICK notification message notifies the parent window of a control that the user has clicked the left mouse button within the control. NM_CLICK is sent in the form of a WM_NOTIFY message.


NM_DBLCLK [New - Windows NT]
NM_DBLCLK  QuickInfo  Overview  Group

[New - Windows NT]

NM_DBLCLK

pnmh = (NMHDR FAR *) lParam;

The NM_DBLCLK notification message notifies the parent window of a control that the user has double-clicked the left mouse button within the control. NM_DBLCLK is sent in the form of a WM_NOTIFY message.


NM_KILLFOCUS [New - Windows NT]
NM_KILLFOCUS  QuickInfo  Overview  Group

[New - Windows NT]

NM_KILLFOCUS

pnmh = (NMHDR FAR *) lParam;

The NM_KILLFOCUS notification message notifies the parent window of a control that the control has lost the input focus. NM_KILLFOCUS is sent in the form of a WM_NOTIFY message.


NM_OUTOFMEMORY [New - Windows NT]
NM_OUTOFMEMORY  QuickInfo  Overview  Group

[New - Windows NT]

NM_OUTOFMEMORY

pnmh = (NMHDR FAR *) lParam;

The NM_OUTOFMEMORY notification message notifies the parent window of a control that the control could not complete an operation because there was not enough memory available. NM_OUTOFMEMORY is sent in the form of a WM_NOTIFY message.


NM_RCLICK [New - Windows NT]
NM_RCLICK  QuickInfo  Overview  Group

[New - Windows NT]

NM_RCLICK

pnmh = (NMHDR FAR *) lParam;

The NM_RCLICK notification message notifies the parent window of a control that the user has clicked the right mouse button within the control. NM_RCLICK is sent in the form of a WM_NOTIFY message.


NM_RDBLCLK [New - Windows NT]
NM_RDBLCLK  QuickInfo  Overview  Group

[New - Windows NT]

NM_RDBLCLK

pnmh = (NMHDR FAR *) lParam;

The NM_RDBLCLK notification message notifies the parent window of a control that the user has double-clicked the right mouse button within the control. NM_RDBLCLK is sent in the form of a WM_NOTIFY message.


NM_RETURN [New - Windows NT]
NM_RETURN  QuickInfo  Overview  Group

[New - Windows NT]

NM_RETURN

pnmh = (NMHDR FAR *) lParam;

The NM_RETURN notification message notifies the parent window of a control that the control has the input focus and that the user has pressed the ENTER key. NM_RETURN is sent in the form of a WM_NOTIFY message.


NM_SETFOCUS [New - Windows NT]
NM_SETFOCUS  QuickInfo  Overview  Group

[New - Windows NT]

NM_SETFOCUS

pnmh = (NMHDR FAR *) lParam;

The NM_SETFOCUS notification message notifies the parent window of a control that the control has received the input focus. NM_SETFOCUS is sent in the form of a WM_NOTIFY message.


PBM_DELTAPOS [New - Windows 95]
PBM_DELTAPOS  QuickInfo  Overview  Group

[New - Windows 95]

PBM_DELTAPOS

wParam = (WPARAM) nIncrement

lParam = 0;

The PBM_DELTAPOS message advances the current position of a progress bar by a specified increment and redraws the bar to reflect the new position.

Parameters

nIncrement

Amount to advance the position.

Return Value

Returns the previous position.


PBM_SETPOS [New - Windows 95]
PBM_SETPOS  QuickInfo  Overview  Group

[New - Windows 95]

PBM_SETPOS

wParam = (WPARAM) nNewPos;

lParam = 0;

The PBM_SETPOS message sets the current position for a progress bar and redraws the bar to reflect the new position.

Parameters

nNewPos

New position.

Return Value

Returns the previous position.


PBM_SETRANGE [New - Windows 95]
PBM_SETRANGE  QuickInfo  Overview  Group

[New - Windows 95]

PBM_SETRANGE

wParam = 0;

lParam = MAKELPARAM(nMinRange, nMaxRange);

The PBM_SETRANGE message sets the minimum and maximum values for a progress bar and redraws the bar to reflect the new range.

Parameters

nMinRange

Minimum range value. By default, the minimum value is zero.

nMaxRange

Maximum range value. By default, the maximum value is 100.

Return Value

Returns the previous range values if successful, or zero otherwise. The low-order word specifies the previous minimum value, and the high-order word specifies the previous maximum value.


PBM_SETSTEP [New - Windows 95]
PBM_SETSTEP  QuickInfo  Overview  Group

[New - Windows 95]

PBM_SETSTEP

wParam = (WPARAM) nStepInc;

lParam = 0;

The PBM_SETSTEP message specifies the step increment for a progress bar. The step increment is the amount by which the progress bar increases its current position whenever it receives a PBM_STEPIT message. By default, the step increment is set to 10.

Parameters

nStepInc

New step increment.

Return Value

Returns the previous step increment.

See Also

PBM_STEPIT


PBM_STEPIT [New - Windows 95]
PBM_STEPIT  QuickInfo  Overview  Group

[New - Windows 95]

PBM_STEPIT

wParam = 0;

lParam = 0;

The PBM_STEPIT message advances the current position for a progress bar by the step increment and redraws the bar to reflect the new position. An application sets the step increment by sending the PBM_SETSTEP message.

Return Value

Returns the previous position.

Remarks

When the position exceeds the maximum range value, this message resets the current position so that the progress indicator starts over again from the beginning.

See Also

PBM_SETSTEP


PBT_APMBATTERYLOW
PBT_APMBATTERYLOW  QuickInfo

PBT_APMBATTERYLOW

dwData = (DWORD) lParam;

The PBT_APMBATTERYLOW message is sent to notify applications that battery power is low. A window receives this message through the WM_POWERBROADCAST message.

Parameters

dwData

Reserved, must be zero.

Return Value

No return value.

Remarks

This message is broadcast when a system's APM BIOS signals an APM battery low notification. Because some APM BIOS implementations do not provide battery low notifications, this message may never be sent on some machines.

See Also

WM_POWERBROADCAST


PBT_APMOEMEVENT
PBT_APMOEMEVENT  QuickInfo

PBT_APMOEMEVENT

dwEventCode = (DWORD) lParam;

The PBT_APMOEMEVENT message is sent when an APM BIOS signals an APM OEM event. A window receives this message through the WM_POWERBROADCAST message.

Parameters

dwEventCode

OEM-defined event code that was signaled by the system's APM BIOS. OEM event codes are in the range 0200h - 02FFh.

Return Value

No return value.

Remarks

Because not all APM BIOS implementations provide OEM event notifications, this message may never be sent on some machines.

See Also

WM_POWERBROADCAST


PBT_APMPOWERSTATUSCHANGE

[New - Windows 95]

dwData = (DWORD) lParam;

The PBT_APMPOWERSTATUSCHANGE message is sent when a change in the power status of the computer is detected, such as a switch from battery power to A/C or a drop in remaining battery power below a threshold. A window receives this message through the WM_POWERBROADCAST message.

Parameters

dwData

Reserved; must be 0.

Return Value

No return value.

Remarks

An application should process this message by calling the GetSystemPowerStatus function to retrieve the current power status of the computer. In particular, the application should check the ACLineStatus, BatteryFlag, BatteryLifeTime, and BatteryLifePercent members of the SYSTEM_POWER_STATUS structure for any changes. This message can occur when the battery life time drops to less than 5 minutes, or when the percentage of battery life drops below 10 percent.

See Also

GetSystemPowerStatus, SYSTEM_POWER_STATUS, WM_POWERBROADCAST


PBT_APMQUERYSTANDBY [New - Windows 95]
PBT_APMQUERYSTANDBY  QuickInfo  Overview  Group

[New - Windows 95]

Flags = (DWORD) lParam;

The PBT_APMQUERYSTANDBY message is sent to request permission to place the system in standby mode. An installable driver that grants permission should carry out preparations for changing to standby before returning. A driver receives this message through the WM_POWERBROADCAST message.

Parameters

Flags

Action flags. If bit 0 is 1, the installable driver can prompt the user for directions on how to prepare for the change to standby; otherwise, the driver must prepare without user interaction. All other bit values are reserved.

Return Value

Returns TRUE to grant the request to change to standby mode. To deny the request, return BROADCAST_QUERY_DENY.

Remarks

An installable driver should process this message by first determining whether permission to change to standby can be granted. It must not grant permission if doing so would cause a lost of data. The installable driver can prompt the user for directions on how to prepare for the change to standby only if bit 0 in the Flags parameter is set.

This message is not sent to applications.

See Also

WM_POWERBROADCAST


PBT_APMQUERYSTANDBYFAILED [New - Windows 95]
PBT_APMQUERYSTANDBYFAILED  QuickInfo  Overview  Group

[New - Windows 95]

dwData = (DWORD) lParam;

The PBT_APMQUERYSTANDBYFAILED message is sent as a notification that permission to place the computer in standby mode was denied. This message is sent if any installable driver returned FALSE to a previous PBT_APMQUERYSTANDBY message. A driver receives this message through the WM_POWERBROADCAST message.

Parameters

dwData

Reserved; must be 0.

Return Value

No return value.

Remarks

Installable drivers typically respond to this message by resuming normal operation. This message is not sent to applications.

See Also

PBT_APMQUERYSTANDBY, WM_POWERBROADCAST


PBT_APMQUERYSUSPEND [New - Windows 95]
PBT_APMQUERYSUSPEND  QuickInfo  Overview  Group

[New - Windows 95]

Flags = (DWORD) lParam;

The PBT_APMQUERYSUSPEND message is sent to request permission to suspend the computer. An application that grants permission should carry out preparations for the suspension before returning. A window receives this message through the WM_POWERBROADCAST message.

Parameters

Flags

Action flags. If bit 0 is 1, the application can prompt the user for directions on how to prepare for the suspension; otherwise, the application must prepare without user interaction. All other bit values are reserved.

Return Value

Returns TRUE to grant the request to suspend. To deny the question, return BROADCAST_QUERY_DENY.

Remarks

An application should process this message by first determining whether permission to suspend can be granted. It must not grant permission if doing so would cause a loss of data. The application can prompt the user for directions on how to prepare for suspension only if bit 0 in the Flags parameter is set.

See Also

WM_POWERBROADCAST


PBT_APMQUERYSUSPENDFAILED [New - Windows 95]
PBT_APMQUERYSUSPENDFAILED  QuickInfo  Overview  Group

[New - Windows 95]

dwData = (DWORD) lParam;

The PBT_APMQUERYSUSPENDFAILED message is sent as a notification that permission to suspend the computer was denied. This message is sent if any application or driver returned FALSE to a previous PBT_APMQUERYSUSPEND message. A window receives this message through the WM_POWERBROADCAST message.

Parameters

dwData

Reserved; must be 0.

Return Value

No return value.

Remarks

Applications typically respond to this message by resuming normal operation.

See Also

PBT_APMQUERYSUSPEND, WM_POWERBROADCAST


PBT_APMRESUMECRITICAL [New - Windows 95]
PBT_APMRESUMECRITICAL  QuickInfo  Overview  Group

[New - Windows 95]

dwData = (DWORD) lParam;

The PBT_APMRESUMECRITICAL message is sent as a notification that the system has resumed operation after a critical suspension caused by a failing battery. A driver receives this message through the WM_POWERBROADCAST message.

Parameters

dwData

Reserved; must be 0.

Return Value

No return value.

Remarks

Because a critical suspension occurs without prior notification, resources and data previously available to a driver may not be present when the driver receives this message. The driver should attempt to restore its state to the best of its ability. While in a critical suspension, the system maintains the state of the DRAM and local hard disks, but may not maintain net connections. A driver may have to take action with respect to files that were open on the network prior to the critical suspension.

This message is not sent to applications.

See Also

WM_POWERBROADCAST


PBT_APMRESUMESTANDBY [New - Windows 95]
PBT_APMRESUMESTANDBY  QuickInfo  Overview  Group

[New - Windows 95]

dwData = (DWORD) lParam;

The PBT_APMRESUMESTANDBY message is sent as a notification that the system has resumed operation after being placed in standby mode. A driver receives this message through the WM_POWERBROADCAST message.

Parameters

dwData

Reserved; must be 0.

Return Value

No return value.

Remarks

This message is not sent to applications.

See Also

WM_POWERBROADCAST


PBT_APMRESUMESUSPEND [New - Windows 95]
PBT_APMRESUMESUSPEND  QuickInfo  Overview  Group

[New - Windows 95]

dwData = (DWORD) lParam;

The PBT_APMRESUMESUSPEND message is sent as a notification that the system has resumed opration after being suspended. A window receives this message through the WM_POWERBROADCAST message.

Parameters

dwData

Reserved; must be 0.

Return Value

No return value.

Remarks

Applications may receive this message at any time without a preceding PBT_APMSUSPEND message.

See Also

PBT_APMSUSPEND, WM_POWERBROADCAST


PBT_APMSTANDBY [New - Windows 95]
PBT_APMSTANDBY  QuickInfo  Overview  Group

[New - Windows 95]

dwData = (DWORD) lParam;

The PBT_APMSTANDBY message is sent immediately before the system is placed in standby mode. This message is typically sent when all installable drivers have returned TRUE to a previous PBT_APMQUERYSTANDBY message. A driver receives this message through the WM_POWERBROADCAST message. A window receives this message through the WM_POWERBROADCAST message.

Parameters

dwData

Reserved; must be 0.

Return Value

No return value.

Remarks

An installable driver should process this message by completing all tasks necessary to save data. Usually, no special action is required. This message may also be sent, without a prior PBT_APMQUERYSUSPEND message, if an application or device driver uses the SetSystemPowerState function to force suspension.

This message is not sent to applications.

See Also

PBT_APMQUERYSTANDBY, PBT_APMQUERYSUSPEND, SetSystemPowerState, WM_POWERBROADCAST


PBT_APMSUSPEND [New - Windows 95]
PBT_APMSUSPEND  QuickInfo  Overview  Group

[New - Windows 95]

dwData = (DWORD) lParam;

The PBT_APMSUSPEND is sent immediately before the computer is suspended. This message is typically sent when all applications and installable drivers have returned TRUE to a previous PBT_APMQUERYSUSPEND message. A window receives this message through the WM_POWERBROADCAST message.

Parameters

dwData

Reserved; must be 0.

Return Value

No return value.

Remarks

An application should process this message by completing all tasks necessary to save data. This message may also be sent, without a prior PBT_APMQUERYSUSPEND message, if an application or device driver uses the SetSystemPowerState function to force suspension.

See Also

PBT_APMQUERYSUSPEND, SetSystemPowerState, WM_POWERBROADCAST


PSM_ADDPAGE [New - Windows NT]
PSM_ADDPAGE  QuickInfo  Overview  Group

[New - Windows NT]

PSM_ADDPAGE

wParam = 0;

lParam = (LPARAM) (HPROPSHEETPAGE) hpage);

// Corresponding macro

BOOL PropSheet_AddPage(hPropSheetDlg, hpage);

The PSM_ADDPAGE message adds a new page to the end of an existing property sheet.

Parameters

hPropSheetDlg

Handle to the property sheet.

hpage

Handle to the page to add. The page must have been created by a previous call to the CreatePropertySheetPage function.

Return Value

No return value.

Remarks

The property sheet is not resized to fit the new page. The new page should be no larger than the largest page currently in the property sheet.

See Also

CreatePropertySheetPage


PSM_APPLY [New - Windows NT]
PSM_APPLY  QuickInfo  Overview  Group

[New - Windows NT]

PSM_APPLY

wParam = 0;

lParam = 0;

// Corresponding macro

BOOL PropSheet_Apply(hPropSheetDlg);

The PSM_APPLY message simulates the choice of the Apply Now button, indicating that one or more pages have changed and the changes need to be validated and recorded. The property sheet sends the PSN_KILLACTIVE notification message to the current page. If the current page returns FALSE, the property sheet sends the PSN_APPLY notification message to all pages.

Parameters

hPropSheetDlg

Handle to the property sheet.

Return Value

Returns TRUE if all pages successfully applied the changes or FALSE otherwise.

See Also

PSN_APPLY, PSN_KILLACTIVE


PSM_CANCELTOCLOSE [New - Windows NT]
PSM_CANCELTOCLOSE  QuickInfo  Overview  Group

[New - Windows NT]

PSM_CANCELTOCLOSE

wParam = 0;

lParam = 0;

// Corresponding macro

VOID PropSheet_CancelToClose(hPropSheetDlg)

The PSM_CANCELTOCLOSE message disables the Cancel button and changes the text of the OK button to "Close." An application sends this message after applying a change that cannot be canceled.

Parameters

hPropSheetDlg

Handle to the property sheet.

Return Value

No return value.


PSM_CHANGED [New - Windows NT]
PSM_CHANGED  QuickInfo  Overview  Group

[New - Windows NT]

PSM_CHANGED

wParam = (WPARAM) (HWND) hwndPage;

lParam = 0;

// Corresponding macro

BOOL PropSheet_Changed(hPropSheetDlg, hwndPage);

The PSM_CHANGED message informs a property sheet that information in a page has changed. The property sheet enables the Apply Now button.

Parameters

hPropSheetDlg

Handle to the property sheet.

hwndPage

Handle to the page that has changed.

Return Value

No return value.


PSM_GETCURRENTPAGEHWND
PSM_GETCURRENTPAGEHWND  Overview  Group

PSM_GETCURRENTPAGEHWND

wParam = 0;

lParam = 0;

// Corresponding macro

HWND PropSheet_GetCurrentPageHwnd(hDlg);

The PSM_GETCURRENTPAGEHWND message retrieves a handle to the window of the current page of a property sheet.

Parameters

hDlg

Handle to the property sheet.

Return Value

Returns a handle to the window of the current property sheet page.

Remarks

Use the PSM_GETCURRENTPAGEHWND message with modeless property sheets to determine when to destroy the dialog box. When the user selects the OK or Cancel button, PSM_GETCURRENTPAGEHWND returns NULL, and you can then use the DestroyWindow function to destroy the dialog box.

See Also

DestroyWindow, PropertySheet


PSM_GETTABCONTROL [New - Windows NT]
PSM_GETTABCONTROL  QuickInfo  Overview  Group

[New - Windows NT]

PSM_GETTABCONTROL

wParam = 0;

lParam = 0;

// Corresponding macro

HWND PropSheet_GetTabControl(hPropSheetDlg);

The PSM_GETTABCONTROL message retrieves the handle to the tab control of a property sheet.

Parameters

hPropSheetDlg

Handle to the property sheet.

Return Value

Returns the handle to the tab control.


PSM_ISDIALOGMESSAGE
PSM_ISDIALOGMESSAGE  Overview  Group

PSM_ISDIALOGMESSAGE

wParam = 0;

lParam = (LPARAM)pMsg;

// Corresponding macro

BOOL PropSheet_IsDialogMessage(hDlg, pMsg);

The PSM_ISDIALOGMESSAGE message passes a message to a property sheet dialog box and indicates whether the dialog processed the message.

Parameters

hDlg

Handle to the property sheet.

pMsg

Pointer to a MSG structure that contains the message to be checked.

Return Value

If the message has been processed, the return value is TRUE.

If the message has not been processed, the return value is FALSE.

Remarks

Your message loop should use the PSM_ISDIALOGMESSAGE message with modeless property sheets to pass messages to the property sheet dialog box.

If the return value indicates that the message was processed, it must not be passed to the TranslateMessage or DispatchMessage function.

See Also

DispatchMessage, MSG, PropertySheet, TranslateMessage


PSM_PRESSBUTTON [New - Windows NT]
PSM_PRESSBUTTON  QuickInfo  Overview  Group

[New - Windows NT]

PSM_PRESSBUTTON

wParam = (WPARAM) (int) iButton;

lParam = 0;

// Corresponding macro

BOOL PropSheet_PressButton(hPropSheetDlg, iButton);

The PSM_PRESSBUTTON message simulates the choice of a property sheet button.

Parameters

hPropSheetDlg

Handle to the property sheet.

iButton

Index of button to choose. This parameter can be one of the following values:

Value	Meaning
PSBTN_APPLYNOW	Chooses the Apply Now button.
PSBTN_BACK	Chooses the Back button.
PSBTN_CANCEL	Chooses the Cancel button.
PSBTN_FINISH	Chooses the Finish button.
PSBTN_HELP	Chooses the Help button.
PSBTN_NEXT	Chooses the Next button.
PSBTN_OK	Chooses the OK button.
Return Value

No return value.


PSM_QUERYSIBLINGS [New - Windows NT]
PSM_QUERYSIBLINGS  QuickInfo  Overview  Group

[New - Windows NT]

PSM_QUERYSIBLINGS

wParam = (WPARAM) param1;

lParam = (LPARAM) param2;

// Corresponding macro

int PropSheet_QuerySiblings(hPropSheetDlg, param1, param2);

The PSM_QUERYSIBLINGS message forwards the message to each page in the property sheet. If a page returns a nonzero value, the property sheet does not send the message to subsequent pages.

Parameters

hPropSheetDlg

Handle to the property sheet.

param1

First application-defined parameter.

param2

Second application-defined parameter.

Return Value

Returns the nonzero value from a page in the property sheet, or zero if no page returns a nonzero value.


PSM_REBOOTSYSTEM [New - Windows NT]
PSM_REBOOTSYSTEM  QuickInfo  Overview  Group

[New - Windows NT]

PSM_REBOOTSYSTEM

wParam = 0;

lParam = 0;

// Corresponding macro

VOID PropSheet_RebootSystem(hPropSheetDlg);

The PSM_REBOOTSYSTEM message indicates that the system needs to be restarted for the changes to take effect. An application should send this message only in response to the PSN_APPLY or PSN_KILLACTIVE notification message.

Parameters

hPropSheetDlg

Handle to the property sheet.

Return Value

No return value.

Remarks

This message causes the PropertySheet function to return the ID_PSREBOOTSYSTEM value, but only if the user chooses the OK button to close the property sheet. It is the application's responsibility to reboot the system, which can be done by using the ExitWindowsEx function.

This message supersedes all PSM_RESTARTWINDOWS messages that precede or follow it.

See Also

ExitWindowsEx, PropertySheet, PSN_APPLY, PSN_KILLACTIVE, PSM_RESTARTWINDOWS


PSM_REMOVEPAGE [New - Windows NT]
PSM_REMOVEPAGE  QuickInfo  Overview  Group

[New - Windows NT]

PSM_REMOVEPAGE

wParam = (WPARAM) (int) index;

lParam = (LPARAM) (HPROPSHEETPAGE) hpage);

// Corresponding macro

VOID PropSheet_RemovePage(hPropSheetDlg, index, hpage);

The PSM_REMOVEPAGE message removes a page from a property sheet.

Parameters

hPropSheetDlg

Handle to the property sheet.

hpage and index

Handle to the page to remove, and the zero-based index of the page to remove. An application can specify the handle or the index, or both. If both are specified, hpage takes precedence.

Return Value

No return value.


PSM_RESTARTWINDOWS [New - Windows NT]
PSM_RESTARTWINDOWS  QuickInfo  Overview  Group

[New - Windows NT]

PSM_RESTARTWINDOWS

wParam = 0;

lParam = 0;

// Corresponding macro

VOID PropSheet_RestartWindows(hPropSheetDlg);

The PSM_RESTARTWINDOWS message indicates that Windows needs to be restarted for the changes to take effect. An application should send this message only in response to the PSN_APPLY or PSN_KILLACTIVE notification message.

Parameters

hPropSheetDlg

Handle to the property sheet.

Return Value

No return value.

Remarks

This message causes the PropertySheet function to return the ID_PSRESTARTWINDOWS value, but only if the user chooses the OK button to close the property sheet. It is the application's responsibility to restart Windows, which can be done by using the ExitWindowsEx function.

See Also

ExitWindowsEx, PropertySheet, PSN_APPLY, PSN_KILLACTIVE


PSM_SETCURSEL [New - Windows NT]
PSM_SETCURSEL  QuickInfo  Overview  Group

[New - Windows NT]

PSM_SETCURSEL

wParam = (WPARAM) (int) index;

lParam = (LPARAM) (HPROPSHEETPAGE) hpage;

// Corresponding macro

BOOL PropSheet_SetCurSel(hPropSheetDlg, hpage, index);

The PSM_SETCURSEL message activates the given page in a property sheet.

Parameters

hPropSheetDlg

Handle to the property sheet.

hpage and index

Handle to the page to activate, and the zero-based index of the page to activate. An application can specify the handle or the index, or both. If both are specified, hpage takes precedence.

Return Value

Returns TRUE if successful or FALSE otherwise.

Remarks

The window that is losing the activation receives the PSN_KILLACTIVE notification message, and the window that is gaining the activation receives the PSN_SETACTIVE notification message.

See Also

PSN_KILLACTIVE, PSN_SETACTIVE


PSM_SETCURSELID [New - Windows NT]
PSM_SETCURSELID  QuickInfo  Overview  Group

[New - Windows NT]

PSM_SETCURSELID

wParam = 0;

lParam = (LPARAM) (int) id;

// Corresponding macro

BOOL PropSheet_SetCurSelByID(hPropSheetDlg, id);

The PSM_SETCURSELID message activates the given page in a property sheet based on the resource identifier of the page.

Parameters

hPropSheetDlg

Handle to the property sheet.

id

Resource identifier of the page to activate.

Return Value

Returns TRUE if successful or FALSE otherwise.

Remarks

The window that is losing the activation receives the PSN_KILLACTIVE notification message, and the window that is gaining the activation receives the PSN_SETACTIVE notification message.

See Also

PSN_KILLACTIVE, PSN_SETACTIVE


PSM_SETFINISHTEXT [New - Windows NT]
PSM_SETFINISHTEXT  QuickInfo  Overview  Group

[New - Windows NT]

PSM_SETFINISHTEXT

wParam = 0;

lParam = (LPARAM) (LPSTR) lpszText;

// Corresponding macro

VOID PropSheet_SetFinishText(hPropSheetDlg, lpszText);

The PSM_SETFINISHTEXT message sets the text of the Finish button in a wizard property sheet, shows and enables the button, and hides the Next and Back buttons.

Parameters

hPropSheetDlg

Handle to the property sheet.

lpszText

Pointer to the new text for the Finish button.

Return Value

No return value.

Remarks

This message causes the DM_SETDEFID message to be sent to the property sheet dialog box. The wParam parameter specifies the identifier of the Finish button.

See Also

DM_SETDEFID


PSM_SETTITLE [New - Windows NT]
PSM_SETTITLE  QuickInfo  Overview  Group

[New - Windows NT]

PSM_SETTITLE

wParam = (WPARAM) (DWORD) dwStyle

lParam = (LPARAM) (LPCSTR) lpszText;

// Corresponding macro

VOID PropSheet_SetTitle(hPropSheetDlg, dwStyle, lpszText);

The PSM_SETTITLE message sets the title of a property sheet.

Parameters

hPropSheetDlg

Handle to the property sheet.

dwStyle

Flag that indicates whether to include the prefix "Properties for" with the specified title string. If dwStyle is the PSH_PROPTITLE value, the prefix is included. Otherwise, the prefix is not used.

lpszText

Pointer to a buffer that contains the title string. If the high-order word of this parameter is NULL, the property sheet loads the string resource specified in the low-order word.

Return Value

No return value.


PSM_SETWIZBUTTONS [New - Windows NT]
PSM_SETWIZBUTTONS  QuickInfo  Overview  Group

[New - Windows NT]

PSM_SETWIZBUTTONS

wParam = 0;

lParam = (LPARAM) (DWORD) dwFlags;

// Corresponding macro

VOID PropSheet_SetWizButtons(hPropSheetDlg, dwFlags);

The PSM_SETWIZBUTTONS message enables the Back, Next, or Finish button in a wizard property sheet. The PropSheet_SetWizButtons macro posts the PSM_SETWIZBUTTONS message.

Parameters

hPropSheetDlg

Handle to the property sheet.

dwFlags

Buttons to enable. This parameter can be a combination of the following values:

Value	Meaning
PSWIZB_BACK	Back button
PSWIZB_NEXT	Next button
PSWIZB_FINISH	Finish button
Return Value

No return value.


PSM_UNCHANGED [New - Windows NT]
PSM_UNCHANGED  QuickInfo  Overview  Group

[New - Windows NT]

PSM_UNCHANGED

wParam = (WPARAM) (HWND) hwndPage;

lParam = 0;

// Corresponding macro

VOID PropSheet_UnChanged(hPropSheetDlg, hwndPage);

The PSM_UNCHANGED message informs a property sheet that information in a page has reverted to the previously saved state. The property sheet disables the Apply Now button if no other pages have registered changes with the property sheet.

Parameters

hPropSheetDlg

Handle to the property sheet.

hwndPage

Handle to the page that has reverted to the previously saved state.

Return Value

No return value.


PSN_APPLY [New - Windows NT]
PSN_APPLY  QuickInfo  Overview  Group

[New - Windows NT]

PSN_APPLY

lpnmhdr = (NMHDR FAR *) lParam;

The PSN_APPLY notification message indicates that the user chose the OK or Apply Now button and wants all changes to take effect. This notification message is sent in the form of a WM_NOTIFY message.

Parameters

lpnmhdr

Pointer to an NMHDR structure. The hwndFrom member is the handle to the property sheet.

Return Value

Returns the PSNRET_INVALID_NOCHANGEPAGE value to prevent the changes from taking effect and to return the focus to the page, or the PSNRET_NOERROR value to accept the changes and allow the property sheet to be destroyed.

Remarks

To set the return value, the dialog box procedure for the page must use the SetWindowLong function with the DWL_MSGRESULT value, and the dialog box procedure must return TRUE.

A page should not call the EndDialog function when processing this notification message.

The property sheet is destroyed if the user chooses the OK button and the application returns the PSNRET_NOERROR value in response to this notification.

To receive this notification, a page must set the DWL_MSGRESULT value to FALSE in response the PSN_KILLACTIVE notification message.

The PSHNOTIFY structure is supplied with the PSN_APPLY notification message. The lParam member in this structure is TRUE if the user clicked the Ok or Cancel button, and is FALSE if the user clicked the Close button.

See Also

EndDialog, NMHDR, PSN_KILLACTIVE, PSHNOTIFY, SetWindowLong, WM_NOTIFY


PSN_HELP [New - Windows NT]
PSN_HELP  QuickInfo  Overview  Group

[New - Windows NT]

PSN_HELP

lpnmhdr = (NMHDR FAR *) lParam;

The PSN_HELP notification message notifies a page that the user has chosen the Help button. This notification message is sent in the form of a WM_NOTIFY message.

Parameters

lpnmhdr

Pointer to an NMHDR structure. The hwndFrom member is the handle to the property sheet.

Return Value

No return value.

Remarks

An application should display help information for the page.

See Also

NMHDR, WM_NOTIFY


PSN_KILLACTIVE [New - Windows NT]
PSN_KILLACTIVE  QuickInfo  Overview  Group

[New - Windows NT]

PSN_KILLACTIVE

lpnmhdr = (NMHDR FAR *) lParam;

The PSN_KILLACTIVE notification message notifies a page that it is about to lose the activation either because another page is being activated or the user has chosen the OK button. This notification message is sent in the form of a WM_NOTIFY message.

Parameters

lpnmhdr

Pointer to an NMHDR structure. The hwndFrom member is the handle to the property sheet.

Return Value

Returns TRUE to prevent the page from losing the activation or FALSE to allow it.

Remarks

An application should validate the information that the user has typed.

To set the return value, the dialog box procedure for the page must use the SetWindowLong function with the DWL_MSGRESULT value, and the dialog box procedure must return TRUE.

If the dialog box procedure sets DWL_MSGRESULT to TRUE, it should display a message box to explain the problem to the user.

See Also

SetWindowLong, NMHDR, WM_NOTIFY


PSN_QUERYCANCEL [New - Windows NT]
PSN_QUERYCANCEL  QuickInfo  Overview  Group

[New - Windows NT]

PSN_QUERYCANCEL

lpnmhdr = (NMHDR FAR *) lParam;

The PSN_QUERYCANCEL notification message indicates that the user chose the Cancel button. This notification message is sent in the form of a WM_NOTIFY message.

Parameters

lpnmhdr

Pointer to an NMHDR structure. The hwndFrom member is the handle of the property sheet.

Return Value

Returns TRUE to prevent the cancel operation or FALSE to allow it.

Remarks

A property sheet page can use this notification message to ask the user to verify the cancel operation.

See Also

NMHDR, WM_NOTIFY


PSN_RESET [New - Windows NT]
PSN_RESET  QuickInfo  Overview  Group

[New - Windows NT]

PSN_RESET

lpnmhdr = (NMHDR FAR *) lParam;

The PSN_RESET notification message notifies a page that the user has chosen the Cancel button and the property sheet is about to be destroyed. All changes made since the user last chose the Apply Now button are canceled. This notification message is sent in the form of a WM_NOTIFY message.

Parameters

lpnmhdr

Pointer to an NMHDR structure. The hwndFrom member is the handle of the property sheet.

Return Value

No return value.

Remarks

An application can use this notification message as an opportunity to perform cleanup operations.

A page should not call the EndDialog function when processing this notification message.

The PSHNOTIFY structure is supplied with the PSN_RESET notification message. The lParam member in this structure is TRUE if the user clicked the Ok or Cancel button, and is FALSE if the user clicked the Close button.

See Also

EndDialog, NMHDR, PSHNOTIFY, WM_NOTIFY


PSN_SETACTIVE [New - Windows NT]
PSN_SETACTIVE  QuickInfo  Overview  Group

[New - Windows NT]

PSN_SETACTIVE

lpnmhdr = (NMHDR FAR *) lParam;

The PSN_SETACTIVE notification message notifies a page that it is about to be activated. This notification message is sent in the form of a WM_NOTIFY message.

Parameters

lpnmhdr

Pointer to the property sheet.

Return Value

Returns zero to accept the activation or −1 to activate the next or previous page (depending on whether the user chose the Next or Back button). To set the activation to a particular page, return the resource identifier of the page.

Remarks

The PSN_SETACTIVE notification message is sent before the page is visible. An application can use this notification to initialize data in the page.

To set the return value, the dialog box procedure for the page must use the SetWindowLong function with the DWL_MSGRESULT value, and the dialog box procedure must return TRUE.

See Also

NMHDR, SetWindowLong, WM_NOTIFY


PSN_WIZBACK [New - Windows NT]
PSN_WIZBACK  QuickInfo  Overview  Group

[New - Windows NT]

PSN_WIZBACK

lpnmhdr = (NMHDR FAR *) lParam;

The PSN_WIZBACK notification message notifies a page that the user has chosen the Back button in a wizard property sheet. This notification message is sent in the form of a WM_NOTIFY message.

Parameters

lpnmhdr

Pointer to an NMHDR structure. The hwndFrom member is the handle of the property sheet.

Return Value

Returns −1 to prevent the property sheet from advancing to the previous page.

See Also

NMHDR, WM_NOTIFY


PSN_WIZFINISH [New - Windows NT]
PSN_WIZFINISH  QuickInfo  Overview  Group

[New - Windows NT]

PSN_WIZFINISH

lpnmhdr = (NMHDR FAR *) lParam;

The PSN_WIZFINISH notification message notifies a page that the user has chosen the Finish button in a wizard property sheet. This notification message is sent in the form of a WM_NOTIFY message.

Parameters

lpnmhdr

Pointer to an NMHDR structure. The hwndFrom member is the handle to the property sheet.

Return Value

Returns a nonzero value to prevent the property sheet from being destroyed.

See Also

NMHDR, WM_NOTIFY


PSN_WIZNEXT [New - Windows NT]
PSN_WIZNEXT  QuickInfo  Overview  Group

[New - Windows NT]

PSN_WIZNEXT

lpnmhdr = (NMHDR FAR *) lParam;

The PSN_WIZNEXT notification message notifies a page that the user has chosen the Next button in a wizard property sheet. This notification message is sent in the form of a WM_NOTIFY message.

Parameters

lpnmhdr

Pointer to an NMHDR structure. The hwndFrom member is the handle to the property sheet.

Return Value

Returns −1 to prevent the property sheet from advancing to the next page.

See Also

NMHDR, WM_NOTIFY


SB_GETBORDERS [New - Windows NT]
SB_GETBORDERS  QuickInfo  Overview  Group

[New - Windows NT]

SB_GETBORDERS

wParam = 0;

lParam = (LPARAM) (LPINT) aBorders;

The SB_GETBORDERS message retrieves the current widths of the horizontal and vertical borders of a status window.

Parameters

aBorders

Pointer to an integer array that has three elements. The first element receives the width of the horizontal border, the second receives the width of the vertical border, and the third receives the width of the border between rectangles.

Return Value

If the operation succeeds, the return value is TRUE.

If the operation fails, the return value is FALSE.

Remarks

The borders determine the spacing between the outside edge of the window and the rectangles within the window that contain text. The borders also determine the spacing between rectangles.


SB_GETPARTS [New - Windows NT]
SB_GETPARTS  QuickInfo  Overview  Group

[New - Windows NT]

SB_GETPARTS

wParam = (WPARAM) nParts;

lParam = (LPARAM) (LPINT) aRightCoord;

The SB_GETPARTS message retrieves a count of the parts in a status window. The message also retrieves the coordinate of the right edge of the specified number of parts.

Parameters

nParts

Number of parts for which to retrieve coordinates. If this parameter is greater than the number of parts in the window, the message retrieves coordinates for existing parts only.

aRightCoord

Pointer to an integer array that has the same number of elements as parts specified by nParts. Each element in the array receives the client coordinate of the right edge of the corresponding part. If an element is set to − 1, the position of the right edge for that part extends to the right edge of the window. To retrieve the current number of parts, set this parameter to zero.

Return Value

Returns the number of parts in the window if successful or zero otherwise.


SB_GETRECT [New - Windows NT]
SB_GETRECT  QuickInfo  Overview  Group

[New - Windows NT]

SB_GETRECT

wParam = (WPARAM) iPart;

lParam = (LPARAM) (LPRECT) lprc;

The SB_GETRECT message retrieves the bounding rectangle of a part in a status window.

Parameters

iPart

Zero-based index of the part whose bounding rectangle is to be retrieved.

lprc

Pointer to a RECT structure that receives the bounding rectangle.

Return Value

If the operation succeeds, the return value is TRUE.

If the operation fails, the return value is FALSE.

See Also

RECT


SB_GETTEXT [New - Windows NT]
SB_GETTEXT  QuickInfo  Overview  Group

[New - Windows NT]

SB_GETTEXT

wParam = (WPARAM) iPart;

lParam = (LPARAM) (LPSTR) szText;

The SB_GETTEXT message retrieves the text from the specified part of a status window.

Parameters

iPart

Zero-based index of the part from which to retrieve text.

szText

Pointer to the buffer that receives the text. This parameter is a null-terminated string.

Return Value

Returns a 32-bit value that consists of two 16-bit values. The low word specifies the length, in characters, of the text. The high word specifies the type of operation used to draw the text. The type can be one of these values:

Value	Meaning
0	The text is drawn with a border to appear lower than the plane of the window.
SBT_NOBORDERS	The text is drawn without borders.
SBT_POPOUT	The text is drawn with a border to appear higher than the plane of window.
SBT_RTLREADING	Windows 95 only: Displays text using right-to-left reading order on Hebrew or Arabic systems.
If the text has the SBT_OWNERDRAW drawing type, this message returns the 32-bit value associated with the text instead of the length and operation type.


SB_GETTEXTLENGTH [New - Windows NT]
SB_GETTEXTLENGTH  QuickInfo  Overview  Group

[New - Windows NT]

SB_GETTEXTLENGTH

wParam = (WPARAM) iPart;

lParam = 0;

The SB_GETTEXTLENGTH message retrieves the length, in characters, of the text from the specified part of a status window.

Parameters

iPart

Zero-based index of the part from which to retrieve text.

Return Value

Returns a 32-bit value that consists of two 16-bit values. The low word specifies the length, in characters, of the text. The high word specifies the type of operation used to draw the text. The type can be one of these values:

Value	Meaning
0	The text is drawn with a border to appear lower than the plane of the window.
SBT_NOBORDERS	The text is drawn without borders.
SBT_OWNERDRAW	The text is drawn by the parent window.
SBT_POPOUT	The text is drawn with a border to appear higher than the plane of the window.
SBT_RTLREADING	Windows 95 only: Displays text using right-to-left reading order on Hebrew or Arabic systems.


SB_SETMINHEIGHT [New - Windows NT]
SB_SETMINHEIGHT  QuickInfo  Overview  Group

[New - Windows NT]

SB_SETMINHEIGHT

wParam = (WPARAM) minHeight;

lParam = 0;

The SB_SETMINHEIGHT message sets the minimum height of a status window's drawing area.

Parameters

minHeight

Minimum height, in pixels, of the window.

Return Value

No return value.

Remarks

The minimum height is the sum of wParam and twice the width, in pixels, of the vertical border of the status window. An application must send the WM_SIZE message to the status window to redraw the window. The wParam and lParam parameters of the WM_SIZE message should be set to zero.

See Also

WM_SIZE


SB_SETPARTS [New - Windows NT]
SB_SETPARTS  QuickInfo  Overview  Group

[New - Windows NT]

SB_SETPARTS

wParam = (WPARAM) nParts;

lParam = (LPARAM) (LPINT) aWidths;

The SB_SETPARTS message sets the number of parts in a status window and the coordinate of the right edge of each part.

Parameters

nParts

Number of parts to set. The number of parts cannot be greater than 255.

aWidths

Pointer to an integer array that has the same number of elements as parts specified by nParts. Each element in the array specifies the position, in client coordinates, of the right edge of the corresponding part. If an element is  − 1, the position of the right edge for that part extends to the right edge of the window.

Return Value

If the operation succeeds, the return value is TRUE.

If the operation fails, the return value is FALSE.


SB_SETTEXT [New - Windows NT]
SB_SETTEXT  QuickInfo  Overview  Group

[New - Windows NT]

SB_SETTEXT

wParam = (WPARAM) iPart | uType;

lParam = (LPARAM) (LPSTR) szText;

The SB_SETTEXT message sets the text in the specified part of a status window.

Parameters

iPart

Zero-based index of the part to set. If this value is 255, the status window is assumed to be a simple window having only one part.

uType

Type of drawing operation. This parameter can be one of the following values:

Value	Meaning
0	The text is drawn with a border to appear lower than the plane of the window.
SBT_NOBORDERS	The text is drawn without borders.
SBT_OWNERDRAW	The text is drawn by the parent window.
SBT_POPOUT	The text is drawn with a border to appear higher than the plane of the window.
SBT_RTLREADING	Windows 95 only: Displays text using right-to-left reading order on Hebrew or Arabic systems.
szText

Pointer to a null-terminated string that specifies the text to set. If uType is SBT_OWNERDRAW, this parameter represents 32 bits of data. The parent window must interpret the data and draw the text when it receives the WM_DRAWITEM message.

Return Value

If the operation succeeds, the return value is TRUE.

If the operation fails, the return value is FALSE.

Remarks

The message invalidates the portion of the window that has changed, causing it to display the new text when the window next receives the WM_PAINT message.

See Also

WM_DRAWITEM, WM_PAINT


SB_SIMPLE [New - Windows NT]
SB_SIMPLE  QuickInfo  Overview  Group

[New - Windows NT]

SB_SIMPLE

wParam = (WPARAM) (BOOL) fSimple;

lParam = 0;

The SB_SIMPLE message specifies whether a status window displays simple text or displays all window parts set by a previous SB_SETPARTS message.

Parameters

fSimple

Display type flag. If this parameter is TRUE, the window displays simple text. If it is FALSE, it displays multiple parts.

Return Value

Returns FALSE if an error occurs.

Remarks

If the status window is being changed from nonsimple to simple, or vice versa, the window is immediately redrawn.

See Also

SB_SETPARTS


SBM_ENABLE_ARROWS
SBM_ENABLE_ARROWS  QuickInfo  Overview  Group

SBM_ENABLE_ARROWS

wParam = (WPARAM) fuArrowFlags; // scroll-bar arrow flags

lParam = 0;                     // not used; must be zero

An application sends the SBM_ENABLE_ARROWS message to enable or disable one or both arrows of a scroll bar control.

Parameters

fuArrowFlags

Specifies whether the scroll bar arrows are enabled or disabled and indicates which arrows are enabled or disabled. This parameter can be one of the following values:

Value	Meaning
ESB_DISABLE_BOTH	Disables both arrows on a scroll bar.
ESB_DISABLE_DOWN	Disables the down arrow on a vertical scroll bar.
ESB_DISABLE_LTUP	Disables the left arrow on a horizontal scroll bar or the up arrow on a vertical scroll bar.
ESB_DISABLE_LEFT	Disables the left arrow on a horizontal scroll bar.
ESB_DISABLE_RTDN	Disables the right arrow on a horizontal scroll bar or the down arrow on a vertical scroll bar.
ESB_DISABLE_UP	Disables the up arrow on a vertical scroll bar.
ESB_ENABLE_BOTH	Enables both arrows on a scroll bar.
Return Value

If the message succeeds, the return value is TRUE; otherwise, it is FALSE.


SBM_GETPOS
SBM_GETPOS  QuickInfo  Overview  Group

SBM_GETPOS

wParam = 0; // not used; must be zero

lParam = 0; // not used; must be zero

An application sends the SBM_GETPOS message to retrieve the current position of the scroll box of a scroll bar control. The current position is a relative value that depends on the current scrolling range. For example, if the scrolling range is 0 through 100 and the scroll box is in the middle of the bar, the current position is 50.

Parameters

This message has no parameters.

Return Value

If the message succeeds, the return value is the current position of the scroll box in the scroll bar.

See Also

SBM_GETRANGE, SBM_SETPOS, SBM_SETRANGE, SBM_SETRANGEREDRAW


SBM_GETRANGE
SBM_GETRANGE  QuickInfo  Overview  Group

SBM_GETRANGE

wParam = (WPARAM) (LPINT) lpnMinPos; // minimum position

lParam = (LPARAM) (LPINT) lpnMaxPos; // maximum position

An application sends the SBM_GETRANGE message to a scroll bar control to retrieve the minimum and maximum position values for the control.

Parameters

lpnMinPos

Points to a value that receives the minimum scrolling position.

lpnMaxPos

Points to a value that receives the maximum scrolling position.

Return Value

This message does not return a value.

See Also

SBM_GETPOS, SBM_SETPOS, SBM_SETRANGE, SBM_SETRANGEREDRAW


SBM_GETSCROLLINFO [New - Windows NT]
SBM_GETSCROLLINFO  QuickInfo

[New - Windows NT]

SBM_GETSCROLLINFO

wParam = 0;                             // not used, must be zero

lParam = (LPARAM) (LPSCROLLINFO) lpsi;  // scroll bar parameters

An application sends the SBM_GETSCROLLINFO message to retrieve the parameters of a scroll bar.

Parameters

lpsi

Value of lParam. Points to a SCROLLINFO structure whose fMask member, when the message is sent, specifies the scroll bar parameters to retrieve. Before returning, the message copies the specified parameters to the appropriate members of the structure.

The fMask member can be a combination of the following values:

Value	Meaning
SIF_ALL	Combination of SIF_PAGE, SIF_POS, and SIF_RANGE.
SIF_PAGE	Copies the scroll page to the nPage member of the SCROLLINFO structure pointed to by lpsi.
SIF_POS	Copies the scroll position to the nPos member of the SCROLLINFO structure pointed to by lpsi.
SIF_RANGE	Copies the scroll range to the nMin and nMax members of the SCROLLINFO structure pointed to by lpsi.
Return Value

If the message retrieved any values, the return value is TRUE; otherwise, it is FALSE.

See Also

SBM_SETSCROLLINFO, SCROLLINFO


SBM_SETPOS
SBM_SETPOS  QuickInfo  Overview  Group

SBM_SETPOS

wParam = (WPARAM) nPos;           // new position of scroll box

lParam = (LPARAM) (BOOL) fRedraw; // redraw flag

An application sends the SBM_SETPOS message to a scroll bar control to set the position of the scroll box (thumb) and, if requested, redraw the scroll bar to reflect the new position of the scroll box.

Parameters

nPos

Specifies the new position of the scroll box. It must be within the scrolling range.

fRedraw

Specifies whether the scroll bar should be redrawn to reflect the new scroll box position. If this parameter is TRUE, the scroll bar is redrawn. If it is FALSE, the scroll bar is not redrawn.

Return Value

If the position of the scroll box changed, the return value is the previous position of the scroll box; otherwise, it is zero.

Remarks

If the scroll bar control is redrawn by a subsequent call to another function, setting the fRedraw parameter to FALSE is useful.

See Also

SBM_GETPOS, SBM_GETRANGE, SBM_SETRANGE, SBM_SETRANGEREDRAW


SBM_SETRANGE
SBM_SETRANGE  QuickInfo  Overview  Group

SBM_SETRANGE

wParam = (WPARAM) nMinPos; // minimum scrolling position

lParam = (LPARAM) nMaxPos; // maximum scrolling position

An application sends the SBM_SETRANGE message to a scroll bar control to set the minimum and maximum position values for the control.

Parameters

nMinPos

Specifies the minimum scrolling position.

fMaxPos

Specifies the maximum scrolling position.

Return Value

If the position of the scroll box changed, the return value is the previous position of the scroll box; otherwise, it is zero.

Remarks

The default minimum and maximum position values are zero. The difference between the values specified by the nMinPos and nMaxPos parameters must not be greater than the value of MAXLONG.

If the minimum and maximum position values are equal, the scroll bar control is hidden and, in effect, disabled.

See Also

SBM_GETPOS, SBM_GETRANGE, SBM_SETPOS, SBM_SETRANGEREDRAW


SBM_SETRANGEREDRAW
SBM_SETRANGEREDRAW  QuickInfo  Overview  Group

SBM_SETRANGEREDRAW

wParam = (WPARAM) nMinPos; // minimum scrolling position

lParam = (LPARAM) nMaxPos  // maximum scrolling position

An application sends the SBM_SETRANGEREDRAW message to a scroll bar control to set the minimum and maximum position values and to redraw the control.

Parameters

nMinPos

Specifies the minimum scrolling position.

fMaxPos

Specifies the maximum scrolling position.

Return Value

If the position of the scroll box changed, the return value is the previous position of the scroll box; otherwise, it is zero.

Remarks

The default minimum and maximum position values are zero. The difference between the values specified by the nMinPos and nMaxPos parameters must not be greater than the value of MAXLONG.

If the minimum and maximum position values are equal, the scroll bar control is hidden and, in effect, disabled.

See Also

SBM_GETPOS, SBM_GETRANGE, SBM_SETPOS, SBM_SETRANGE


SBM_SETSCROLLINFO [New - Windows NT]
SBM_SETSCROLLINFO  QuickInfo

[New - Windows NT]

SBM_SETSCROLLINFO

wParam = (WPARAM) fRedraw;              // redraw flag

lParam = (LPARAM) (LPSCROLLINFO) lpsi;  // scroll bar parameters

An application sends the SBM_GETSCROLLINFO message to set the parameters of a scroll bar.

Parameters

fRedraw

Value of wParam. Specifies whether the scroll bar is redrawn to reflect the new scroll box position. If this parameter is TRUE, the scroll bar is redrawn. If it is FALSE, the scroll bar is not redrawn.

lpsi

Value of lParam. Points to a SCROLLINFO structure whose fMask member, when the message is sent, specifies the scroll bar parameters to set.

The fMask member can be a combination of the following values:

Value	Meaning
SIF_ALL	Combination of SIF_PAGE, SIF_POS, and SIF_RANGE.
SIF_PAGE	Sets the scroll page to the value specified in the nPage member of the SCROLLINFO structure pointed to by lpsi.
SIF_POS	Sets the scroll position to the value specified in the nPos member of the SCROLLINFO structure pointed to by lpsi.
SIF_RANGE	Sets the scroll range to the value specified in the nMin and nMax members of the SCROLLINFO structure pointed to by lpsi.
Return Value

The return value is the current position of the scroll box.

See Also

SBM_GETSCROLLINFO, SCROLLINFO


SETRGBSTRING
SETRGBSTRING  Overview  Group

msg = uSetRGBMsg;
wParam = 0;
lParam = (COLORREF) rgbColor;

Sent from the hook function to the Color dialog box to set the current color selection.

Parameters

uSetRGBMsg

Message identifier for the Set RGB message. This value is the same as returned by the RegisterWindowMessage function for the SETRGBSTRING string.

rgbColor

Value of the color to set the selection to.

Return Value

No return value.

Remarks

If the color value matches one of the basic colors, the dialog box procedure selects that color. If the value does not match a basic color, the procedure either updates the spectrum and luminosity controls or ignores the message if these controls are not visible.

See Also

RegisterWindowMessage


SHAREVISTRING
SHAREVISTRING  Overview  Group

msg = uShareViolationMsg;
wParam = 0;
lParam = (LPOPENFILENAME) lpofn;

Sent to the hook function of a Open or Save As dialog box when the user has selected the name of a file for which a sharing violation has occurred.

Parameters

uShareViolationMsg

Message identifier for the Share Violation message. This value is the same as returned by the RegisterWindowMessage function for the SHAREVISTRING string.

lpofn

Address of the OPENFILENAME structure that contains the name of the file that caused the sharing violation in the lpstrFile member.

Return Value

Returns one of these values:

OFN_SHAREFALLTHROUGH	Accept the filename.
OFN_SHARENOWARN	Reject the filename but do not warn the user. The application is responsible for displaying a warning message.
OFN_SHAREWARN	Rejects the filename and displays a warning message (the same result as if there were no hook function).
All other values are reserved.

Remarks

If the hook function returns an undefined value, the dialog box responds as if OFN_SHAREWARN was returned.

See Also

OPENFILENAME, RegisterWindowMessage


STM_GETICON
STM_GETICON  QuickInfo  Overview  Group

STM_GETICON

wParam = 0; // not used; must be zero

lParam = 0; // not used; must be zero

An application sends the STM_GETICON message to retrieve the handle of the icon associated with a static control that has the SS_ICON style.

Parameters

This message has no parameters.

Return Value

The return value is the handle of the icon, or NULL if either the static control has no associated icon or if an error occurred.

See Also

STM_SETICON


STM_GETIMAGE [New - Windows NT]
STM_GETIMAGE  QuickInfo

[New - Windows NT]

STM_GETIMAGE

wParam = (WPARAM) fImageType;  // image-type flag

lParam = 0;                    // not used; must be zero

An application sends an STM_GETIMAGE message to retrieve the handle of the image associated with a static control.

Parameters

fImageType

Value of wParam. Specifies the type of image to retrieve. This parameter can be one of the following values:

IMAGE_BITMAP

IMAGE_CURSOR

IMAGE_ENHMETAFILE

IMAGE_ICON

Return Value

The return value is the handle of the image, if any; otherwise, it is NULL.

See Also

STM_SETIMAGE


STM_SETICON
STM_SETICON  QuickInfo  Overview  Group

STM_SETICON

wParam = (WPARAM) (HICON) hicon;    // handle of the icon

lParam = 0;                         // not used; must be zero

An application sends the STM_SETICON message to associate an icon with an icon control.

Parameters

hicon

Value of wParam. Identifies the icon to associate with the icon control.

Return Value

The return value is the handle of the icon previously associated with the icon control, or zero if an error occurs.

See Also

LoadIcon, STM_GETICON


STM_SETIMAGE [New - Windows NT]
STM_SETIMAGE  QuickInfo

[New - Windows NT]

STM_SETIMAGE

wParam = (WPARAM) fImageType;       // image-type flag

lParam = (LPARAM) (HANDLE) hImage;  // handle of the image

An application sends an STM_SETIMAGE message to associate a new image (icon or bitmap) with a static control.

Parameters

fImageType

Value of wParam. Specifies the type if image to associate with the static control. This parameter can be one of the following values:

IMAGE_BITMAP

IMAGE_CURSOR

IMAGE_ENHMETAFILE

IMAGE_ICON

hImage

Value of lParam. Identifies the image to associate with the static control.

Return Value

The return value is the handle of the image previously associated with the static control, if any; otherwise, it is NULL.

See Also

STM_GETIMAGE


STN_CLICKED [New - Windows 95]
STN_CLICKED  QuickInfo

[New - Windows 95]

STN_CLICKED
idStatic = (int) LOWORD(wParam);    // identifier of static control
hwndStatic = (HWND) LOWORD(lParam); // handle of static control

The STN_CLICKED notification message is sent when the user clicks a static control that has the SS_NOTIFY style. The parent window of the control receives this notification message through the WM_COMMAND message.

See Also

STN_DBLCLK, WM_COMMAND


STN_DBLCLK [New - Windows 95]
STN_DBLCLK  QuickInfo

[New - Windows 95]

STN_DBLCLK
idStatic = (int) LOWORD(wParam);    // identifier of static control
hwndStatic = (HWND) LOWORD(lParam); // handle of static control

The STN_DBLCLK notification message is sent when the user double-clicks a static control that has the SS_NOTIFY style. The parent window of the control receives this notification message through the WM_COMMAND message.

See Also

STN_CLICKED, WM_COMMAND


STN_DISABLE [New - Windows 95]
STN_DISABLE  QuickInfo

[New - Windows 95]

STN_DISABLE
idStatic = (int) LOWORD(wParam);    // identifier of static control
hwndStatic = (HWND) LOWORD(lParam); // handle of static control

The STN_DISABLE notification message is sent when a static control is disabled. The static control must have the SS_NOTIFY style to receive this notification message. The parent window of the control receives this notification message through the WM_COMMAND message.

See Also

STN_ENABLE, WM_COMMAND


STN_ENABLE [New - Windows 95]
STN_ENABLE  QuickInfo

[New - Windows 95]

STN_ENABLE
idStatic = (int) LOWORD(wParam);    // identifier of static control
hwndStatic = (HWND) LOWORD(lParam); // handle of static control

The STN_ENABLE notification message is sent when a static control is enabled. The static control must have the SS_NOTIFY style to receive this notification message. The parent window of the control receives this notification message through the WM_COMMAND message.

See Also

STN_DISABLE, WM_COMMAND


TB_ADDBITMAP [New - Windows NT]
TB_ADDBITMAP  QuickInfo  Overview  Group

[New - Windows NT]

TB_ADDBITMAP

wParam = (WPARAM) nButtons;

lParam = (LPARAM) (LPTBADDBITMAP) lptbab;

The TB_ADDBITMAP message adds one or more images to the list of button images available for a toolbar.

Parameters

nButtons

Number of button images in the bitmap.

lptbab

Pointer to a TBADDBITMAP structure that contains the identifier of a bitmap resource and the handle to the module instance with the executable file that contains the bitmap resource.

Return Value

Returns the index of the first new image if successful or  − 1 otherwise.

Remarks

If the toolbar was created by using the CreateWindowEx function, you must send the TB_BUTTONSTRUCTSIZE message to the toolbar before sending TB_ADDBITMAP.

See Also

CreateWindowEx, TBADDBITMAP, TB_BUTTONSTRUCTSIZE


TB_ADDBUTTONS [New - Windows NT]
TB_ADDBUTTONS  QuickInfo  Overview  Group

[New - Windows NT]

TB_ADDBUTTONS

wParam = (WPARAM) (UINT) uNumButtons;

lParam = (LPARAM) (LPTBBUTTON) lpButtons;

The TB_ADDBUTTONS message adds one or more buttons to a toolbar.

Parameters

uNumButtons

Number of buttons to add.

lpButtons

Pointer to an array of TBBUTTON structures that contains information about the buttons to add. There must be the same number of elements in the array as buttons specified by uNumButtons.

Return Value

Returns TRUE if successful or FALSE otherwise.

Remarks

If the toolbar was created by using the CreateWindowEx function, you must send the TB_BUTTONSTRUCTSIZE message to the toolbar before sending TB_ADDBUTTONS.

See Also

CreateWindowEx, TBBUTTON, TB_BUTTONSTRUCTSIZE


TB_ADDSTRING [New - Windows NT]
TB_ADDSTRING  QuickInfo  Overview  Group

[New - Windows NT]

TB_ADDSTRING

wParam = (WPARAM) (HINSTANCE) hinst;

lParam = (LPARAM) MAKELONG(idString, 0);

The TB_ADDSTRING message adds a new string to the list of strings available for a toolbar.

Parameters

hinst

Handle to the module instance with an executable file that contains the string resource. If idString points to one or more strings to add, this parameter is zero.

idString

Resource identifier for the string resource, or the address of a buffer that contains one or more null-terminated strings to add to the list, depending on the value of hinst. The last string must be terminated with two null characters.

Return Value

Returns the index of the first new string if successful or  − 1 otherwise.


TB_AUTOSIZE [New - Windows NT]
TB_AUTOSIZE  QuickInfo  Overview  Group

[New - Windows NT]

TB_AUTOSIZE

wParam = 0;

lParam = 0;

The TB_AUTOSIZE message causes a toolbar to be resized.

Return Value

No return value.

Remarks

An application sends the TB_AUTOSIZE message after causing the size of a toolbar to change either by setting the button or bitmap size or by adding strings for the first time.


TB_BUTTONCOUNT [New - Windows NT]
TB_BUTTONCOUNT  QuickInfo  Overview  Group

[New - Windows NT]

TB_BUTTONCOUNT

wParam = 0;

lParam = 0;

The TB_BUTTONCOUNT message retrieves a count of the buttons currently in the toolbar.

Return Value

Returns the count of the buttons.


TB_BUTTONSTRUCTSIZE [New - Windows NT]
TB_BUTTONSTRUCTSIZE  QuickInfo  Overview  Group

[New - Windows NT]

wParam = (WPARAM) cb;

lParam = 0;

The TB_BUTTONSTRUCTSIZE message specifies the size of the TBBUTTON structure.

Parameters

cb

Size, in bytes, of the TBBUTTON structure.

The system uses the size to determine which version of the common control dynamic-link library (DLL) is being used.

If an application uses the CreateWindowEx function to create the toolbar, the application must send this message to the toolbar before sending the TB_ADDBITMAP or TB_ADDBUTTONS message. The CreateToolBarEx function automatically sends TB_BUTTONSTRUCTSIZE, and the size of the TBBUTTON structure is a parameter of the function.

Return Value

No return value.

See Also

CreateWindowEx, TB_ADDBITMAP, TB_ADDBUTTONS, TBBUTTON


TB_CHANGEBITMAP [New - Windows NT]
TB_CHANGEBITMAP  QuickInfo  Overview  Group

[New - Windows NT]

TB_CHANGEBITMAP

wParam = (WPARAM) idButton;

lParam = (LPARAM) MAKELPARAM(iBitmap, 0);

The TB_CHANGEBITMAP message changes the bitmap for a button in a toolbar.

Parameters

idButton

Command identifier of the button that is to receive a new bitmap.

iBitmap

Zero-based index of an image in the toolbar's image list. The system displays the specified image in the button.

Return Value

Returns TRUE if successful or FALSE otherwise.


TB_CHECKBUTTON [New - Windows NT]
TB_CHECKBUTTON  QuickInfo  Overview  Group

[New - Windows NT]

TB_CHECKBUTTON

wParam = (WPARAM) idButton;

lParam = (LPARAM) MAKELONG(fCheck, 0);

The TB_CHECKBUTTON message checks or unchecks a given button in a toolbar.

Parameters

idButton

Command identifier of the button to check.

fCheck

Check flag. If this parameter TRUE, the check is added. If it is FALSE, the check is removed.

Return Value

Returns TRUE if successful or FALSE otherwise.

Remarks

When a button has been checked, it appears to have been pressed.


TB_COMMANDTOINDEX [New - Windows NT]
TB_COMMANDTOINDEX  QuickInfo  Overview  Group

[New - Windows NT]

TB_COMMANDTOINDEX

wParam = (WPARAM) idButton;

lParam = 0;

The TB_COMMANDTOINDEX message retrieves the zero-based index for the button associated with the specified command identifier.

Parameters

idButton

Command identifier associated with the button.

Return Value

Returns the zero-based index for the button.


TB_CUSTOMIZE [New - Windows NT]
TB_CUSTOMIZE  QuickInfo  Overview  Group

[New - Windows NT]

TB_CUSTOMIZE

wParam = 0;

lParam = 0;

The TB_CUSTOMIZE message displays the Customize Toolbar dialog box.

Return Value

No return value.


TB_DELETEBUTTON [New - Windows NT]
TB_DELETEBUTTON  QuickInfo  Overview  Group

[New - Windows NT]

TB_DELETEBUTTON

wParam = (WPARAM) iButton;

lParam = 0;

The TB_DELETEBUTTON message deletes a button from the toolbar.

Parameters

iButton

Zero-based index of the button to delete.

Return Value

Returns TRUE if successful or FALSE otherwise.


TB_ENABLEBUTTON [New - Windows NT]
TB_ENABLEBUTTON  QuickInfo  Overview  Group

[New - Windows NT]

TB_ENABLEBUTTON

wParam = (WPARAM) idButton;

lParam = (LPARAM) MAKELONG(fEnable, 0);

The TB_ENABLEBUTTON message enables or disables the specified button in a toolbar.

Parameters

idButton

Command identifier of the button to enable or disable.

fEnable

Enable flag. If this parameter is TRUE, the button is enabled. If it is FALSE, the button is disabled.

Return Value

Returns TRUE if successful or FALSE otherwise.

Remarks

When a button has been enabled, it can be pressed and checked.


TB_GETBITMAP [New - Windows NT]
TB_GETBITMAP  QuickInfo  Overview  Group

[New - Windows NT]

TB_GETBITMAP

wParam = (WPARAM) idButton;

lParam = 0;

The TB_GETBITMAP message retrieves the index of the bitmap associated with a button in a toolbar.

Parameters

idButton

Command identifier of the button whose bitmap index is to be retrieved.

Return Value

If successful, the message returns the index of the bitmap. If unsuccessful, it returns zero.


TB_GETBITMAPFLAGS [New - Windows NT]
TB_GETBITMAPFLAGS  QuickInfo  Overview  Group

[New - Windows NT]

TB_GETBITMAPFLAGS

wParam = 0;

lParam = 0;

The TB_GETBITMAPFLAGS message retrieves the bitmap flags.

Return Value

Returns the TBBF_LARGE value if the display can handle large bitmaps (that is, if the width of the display has at least 120 pixels per logical inch). Otherwise, the return value is zero.


TB_GETBUTTON [New - Windows NT]
TB_GETBUTTON  QuickInfo  Overview  Group

[New - Windows NT]

TB_GETBUTTON

wParam = (WPARAM) iButton;

lParam = (LPARAM) (LPTBBUTTON) lpButton;

The TB_GETBUTTON message retrieves information about the specified button in a toolbar.

Parameters

iButton

Zero-based index of the button for which to retrieve information.

lpButton

Pointer to the TBBUTTON structure that receives the button information.

Return Value

Returns TRUE if successful or FALSE otherwise.

See Also

TBBUTTON


TB_GETBUTTONTEXT [New - Windows NT]
TB_GETBUTTONTEXT  QuickInfo  Overview  Group

[New - Windows NT]

TB_GETBUTTONTEXT

wParam = (WPARAM) idButton;

lParam = (LPARAM) (LPSTR) lpszText;

The TB_GETBUTTONTEXT message retrieves the text of a button in a toolbar.

Parameters

idButton

Command identifier of the button whose text is to be retrieved.

lpszText

Pointer to a buffer that receives the button text.

Return Value

Returns the length, in characters, of the string copied to the specified buffer if successful. The length does not include the terminating null character. Otherwise, the return value is  − 1.


TB_GETITEMRECT [New - Windows NT]
TB_GETITEMRECT  QuickInfo  Overview  Group

[New - Windows NT]

wParam = (WPARAM) iButton;

lParam = (LPARAM) (LPRECT) lprc;

The TB_GETITEMRECT message retrieves the bounding rectangle of a button in a toolbar.

Parameters

iButton

Zero-based index of the button for which to retrieve information.

lprc

Pointer to a RECT structure that receives the coordinates of the bounding rectangle.

Return Value

Returns TRUE if successful or FALSE otherwise.

Remarks

This message does not retrieve the bounding rectangle for buttons whose state is set to the TBSTATE_HIDDEN value.

See Also

RECT


TB_GETROWS [New - Windows NT]
TB_GETROWS  QuickInfo  Overview  Group

[New - Windows NT]

TB_GETROWS

wParam = 0;

lParam = 0;

The TB_GETROWS message retrieves the number of rows of buttons in a toolbar with the TBSTYLE_WRAPABLE style.

Return Value

Returns the number of rows.


TB_GETSTATE [New - Windows NT]
TB_GETSTATE  QuickInfo  Overview  Group

[New - Windows NT]

TB_GETSTATE

wParam = (WPARAM) idButton;

lParam = 0;

The TB_GETSTATE message retrieves information about the state of the specified button in a toolbar, such as whether it is enabled, pressed, or checked.

Parameters

idButton

Command identifier of the button for which to retrieve information.

Return Value

Returns the button state information if successful or  − 1 otherwise. The button state information can be a combination of the values listed in Button States.


TB_GETTOOLTIPS [New - Windows NT]
TB_GETTOOLTIPS  QuickInfo  Overview  Group

[New - Windows NT]

TB_GETTOOLTIPS

wParam = 0;

lParam = 0;

The TB_GETTOOLTIPS message retrieves the handle to the tooltip control, if any, associated with the toolbar.

Return Value

Returns the handle to the tooltip control or NULL if the toolbar has no associated tooltip.


TB_HIDEBUTTON [New - Windows NT]
TB_HIDEBUTTON  QuickInfo  Overview  Group

[New - Windows NT]

TB_HIDEBUTTON

wParam = (WPARAM) idButton;

lParam = (LPARAM) MAKELONG(fShow, 0);

The TB_HIDEBUTTON message hides or shows the specified button in a toolbar.

Parameters

idButton

Command identifier of the button to hide or show.

fShow

Show flag. If this parameter is TRUE, the button is hidden. If it is FALSE, the button is shown.

Return Value

Returns TRUE if successful or FALSE otherwise.


TB_INDETERMINATE [New - Windows NT]
TB_INDETERMINATE  QuickInfo  Overview  Group

[New - Windows NT]

TB_INDETERMINATE

wParam = (WPARAM) idButton;

lParam = (LPARAM) MAKELONG(fIndeterminate, 0);

The TB_INDETERMINATE message sets or clears the indeterminate state of the specified button in a toolbar.

Parameters

idButton

Command identifier of the button whose indeterminate state is to be set or cleared.

fIndeterminate

Indeterminate flag. If this parameter is TRUE, the indeterminate state is set. If it is FALSE, the state is cleared.

Return Value

Returns TRUE if successful or FALSE otherwise.


TB_INSERTBUTTON [New - Windows NT]
TB_INSERTBUTTON  QuickInfo  Overview  Group

[New - Windows NT]

TB_INSERTBUTTON

wParam = (WPARAM) iButton;

lParam = (LPARAM) (LPTBBUTTON) lpButton;

The TB_INSERTBUTTON message inserts a button in a toolbar.

Parameters

iButton

Zero-based index of a button. The message inserts the new button to the left of this button.

lpButton

Pointer to a TBBUTTON structure containing information about the button to insert.

Return Value

Returns TRUE if successful or FALSE otherwise.

See Also

TBBUTTON


TB_ISBUTTONCHECKED [New - Windows NT]
TB_ISBUTTONCHECKED  QuickInfo  Overview  Group

[New - Windows NT]

TB_ISBUTTONCHECKED

wParam = (WPARAM) idButton;

lParam = 0;

The TB_ISBUTTONCHECKED message determines whether the specified button in a toolbar is checked.

Parameters

idButton

Command identifier of the button.

Return Value

Returns nonzero if the button is checked or zero otherwise.


TB_ISBUTTONENABLED [New - Windows NT]
TB_ISBUTTONENABLED  QuickInfo  Overview  Group

[New - Windows NT]

TB_ISBUTTONENABLED

wParam = (WPARAM) idButton;

lParam = 0;

The TB_ISBUTTONENABLED message determines whether the specified button in a toolbar is enabled.

Parameters

idButton

Command identifier of the button.

Return Value

Returns nonzero if the button is enabled or zero otherwise.


TB_ISBUTTONHIDDEN [New - Windows NT]
TB_ISBUTTONHIDDEN  QuickInfo  Overview  Group

[New - Windows NT]

TB_ISBUTTONHIDDEN

wParam = (WPARAM) idButton;

lParam = 0;

The TB_ISBUTTONHIDDEN message determines whether the specified button in a toolbar is hidden.

Parameters

idButton

Command identifier of the button.

Return Value

Returns nonzero if the button is hidden or zero otherwise.


TB_ISBUTTONINDETERMINATE [New - Windows NT]
TB_ISBUTTONINDETERMINATE  QuickInfo  Overview  Group

[New - Windows NT]

TB_ISBUTTONINDETERMINATE

wParam = (WPARAM) idButton;

lParam = 0;

The TB_ISBUTTONINDETERMINATE message determines whether the specified button in a toolbar is indeterminate.

Parameters

idButton

Command identifier of the button.

Return Value

Returns nonzero if the button is indeterminate or zero otherwise.


TB_ISBUTTONPRESSED [New - Windows NT]
TB_ISBUTTONPRESSED  QuickInfo  Overview  Group

[New - Windows NT]

TB_ISBUTTONPRESSED

wParam = (WPARAM) idButton;

lParam = 0;

The TB_ISBUTTONPRESSED message determines whether the specified button in a toolbar is pressed.

Parameters

idButton

Command identifier of the button.

Return Value

Returns nonzero if the button is pressed or zero otherwise.


TB_PRESSBUTTON [New - Windows NT]
TB_PRESSBUTTON  QuickInfo  Overview  Group

[New - Windows NT]

TB_PRESSBUTTON

wParam = (WPARAM) idButton;

lParam = (LPARAM) MAKELONG(fPress, 0);

The TB_PRESSBUTTON message presses or releases the specified button in a toolbar.

Parameters

idButton

Command identifier of the button to press or release.

fPress

Press flag. If this parameter is TRUE, the button is pressed. If it is FALSE, the button is released.

Return Value

Returns TRUE if successful or FALSE otherwise.


TB_SAVERESTORE [New - Windows NT]
TB_SAVERESTORE  QuickInfo  Overview  Group

[New - Windows NT]

TB_SAVERESTORE

wParam = (WPARAM) (BOOL) fSave;

lParam = (LPARAM)  (TBSAVEPARAMS *)ptbsp;

The TB_SAVERESTORE message saves or restores the state of the toolbar.

Parameters

fSave

Save or restore flag. If this parameter is TRUE, the information is saved. If it is FALSE, it is restored.

ptbsp

Pointer to a TBSAVEPARAMS structure that specifies the registry key, subkey, and value name for the toolbar state information.

Return Value

No return value.

See Also

TBSAVEPARAMS


TB_SETBITMAPSIZE [New - Windows NT]
TB_SETBITMAPSIZE  QuickInfo  Overview  Group

[New - Windows NT]

TB_SETBITMAPSIZE

wParam = 0;

lParam = (LPARAM) MAKELONG(dxBitmap, dyBitmap)

The TB_SETBITMAPSIZE message sets the size of the bitmapped images to be added to a toolbar.

Parameters

dxBitmap

Width, in pixels, of the bitmapped images.

dyBitmap

Height, in pixels, of the bitmapped images.

Return Value

Returns TRUE if successful or FALSE otherwise.

Remarks

The size can be set only before adding any bitmaps to the toolbar. If an application does not explicitly set the bitmap size, the size defaults to 16 by 15 pixels.


TB_SETBUTTONSIZE [New - Windows NT]
TB_SETBUTTONSIZE  QuickInfo  Overview  Group

[New - Windows NT]

TB_SETBUTTONSIZE

wParam = 0;

lParam = (LPARAM) MAKELONG(dxButton, dyButton)

The TB_SETBUTTONSIZE sets the size of the buttons to be added to a toolbar.

Parameters

dxButton

Width, in pixels, of the buttons.

dyButton

Height, in pixels, of the buttons.

Return Value

Returns TRUE if successful or FALSE otherwise.

Remarks

The size can be set only before adding any buttons to the toolbar. If an application does not explicitly set the button size, the size defaults to 24 by 22 pixels.


TB_SETCMDID [New - Windows NT]
TB_SETCMDID  QuickInfo  Overview  Group

[New - Windows NT]

TB_SETCMDID

wParam = (WPARAM) (UINT) index;

lParam = (WPARAM) (UINT) cmdId;

The TB_SETCMDID message sets the command identifier of a toolbar button.

Parameters

index

Zero-based index of the button whose command identifier is to be set.

cmdId

Command identifier.

Return Value

Returns TRUE if successful or FALSE otherwise.


TB_SETPARENT [New - Windows NT]
TB_SETPARENT  QuickInfo  Overview  Group

[New - Windows NT]

TB_SETPARENT

wParam = (WPARAM) (HWND) hwndParent;

lParam = 0;

The TB_SETPARENT message sets the parent window for a toolbar.

Parameters

hwndParent

Handle to the new parent window.

Return Value

No return value.


TB_SETROWS [New - Windows NT]
TB_SETROWS  QuickInfo  Overview  Group

[New - Windows NT]

TB_SETROWS

wParam = (WPARAM) MAKEWPARAM(cRows, fLarger);

lParam = (LPARAM) (LPRECT) lprc;

The TB_SETROWS message sets the number of rows of buttons in a toolbar.

Parameters

cRows

Number of rows requested. The minimum number of rows is one, and the maximum is equal to the number of buttons in the toolbar.

fLarger

Flag that indicates whether to create more rows than requested when the system cannot create the number of rows specified by cRows. If this parameter is TRUE, the system creates more rows. If it is FALSE, the system creates fewer rows.

lprc

Pointer to a RECT structure that receives the bounding rectangle of the toolbar after the rows are set.

Return Value

No return value.

Remarks

Because the system does not break up button groups when setting the number of rows, the resulting number of rows might differ from the number requested.

See Also

RECT


TB_SETSTATE [New - Windows NT]
TB_SETSTATE  QuickInfo  Overview  Group

[New - Windows NT]

TB_SETSTATE

wParam = (WPARAM) idButton;

lParam = (LPARAM) MAKELONG(fState, 0);

The TB_SETSTATE message sets the state for the specified button in a toolbar.

Parameters

idButton

Command identifier of the button.

fState

State flags. This parameter can be a combination of the values listed in Toolbar Button States.

Return Value

Returns TRUE if successful or FALSE otherwise.


TB_SETTOOLTIPS [New - Windows NT]
TB_SETTOOLTIPS  QuickInfo  Overview  Group

[New - Windows NT]

TB_SETTOOLTIPS

wParam = (WPARAM) (HWND) hwndToolTip;

lParam = 0;

The TB_SETTOOLTIPS message associates a tooltip control with a toolbar.

Parameters

hwndToolTip

Handle to the tooltip control.

Return Value

No return value.

Remarks

Any buttons added to a toolbar before sending the TB_SETTOOLTIPS message are not registered with the tooltip control.


TBM_CLEARSEL [New - Windows NT]
TBM_CLEARSEL  QuickInfo  Overview  Group

[New - Windows NT]

TBM_CLEARSEL

wParam = (WPARAM) (BOOL) fRedraw;

lParam = 0;

The TBM_CLEARSEL message clears the current selection in a trackbar.

Parameters

fRedraw

Redraw flag. If this parameter is TRUE, the trackbar is redrawn after the selection is cleared.

Return Value

No return value.


TBM_CLEARTICS [New - Windows NT]
TBM_CLEARTICS  QuickInfo  Overview  Group

[New - Windows NT]

TBM_CLEARTICS

wParam = (WPARAM) (BOOL) fRedraw;

lParam = 0;

The TBM_CLEARTICS message removes the current tick marks from a trackbar.

Parameters

fRedraw

Redraw flag. If this parameter is TRUE, the trackbar is redrawn after the tick marks are cleared.

Return Value

No return value.


TBM_GETCHANNELRECT [New - Windows NT]
TBM_GETCHANNELRECT  QuickInfo  Overview  Group

[New - Windows NT]

TBM_GETCHANNELRECT
wParam = 0;

lParam = (LPARAM) (LPRECT) lprc;

The TBM_GETCHANNELRECT message retrieves the size and position of the bounding rectangle for a trackbar's channel. (The channel is the area over which the slider moves and which contains the highlight when a range is selected.)

Parameters

lprc

Pointer to a RECT structure that contains the size and position of the channel's bounding rectangle when the function returns.

Return Value

No return value.

See Also

RECT


TBM_GETLINESIZE [New - Windows NT]
TBM_GETLINESIZE  QuickInfo  Overview  Group

[New - Windows NT]

TBM_GETLINESIZE
wParam = 0;

lParam = 0;

The TBM_GETLINESIZE message retrieves the size of the line for a trackbar. The line size affects how much the slider moves for the TB_LINEUP and TB_LINEDOWN notification messages.

Return Value

Returns a 32-bit value that specifies the size of a line for the trackbar.

Remarks

The default setting for the line size is 1.


TBM_GETNUMTICS [New - Windows NT]
TBM_GETNUMTICS  QuickInfo  Overview  Group

[New - Windows NT]

TBM_GETNUMTICS
wParam = 0;

lParam = 0;

The TBM_GETNUMTICS message retrieves the number of tick marks in a trackbar.

Return Value

Returns the number of tick marks.

Remarks

This message returns all of the tick marks, including the first and last tick marks created by the trackbar.


TBM_GETPAGESIZE [New - Windows NT]
TBM_GETPAGESIZE  QuickInfo  Overview  Group

[New - Windows NT]

TBM_GETPAGESIZE
wParam = 0;

lParam = 0;

The TBM_GETPAGESIZE message retrieves the size of the page for a trackbar. The page size affects how much the slider moves for the TB_PAGEUP and TB_PAGEDOWN notification messages.

Return Value

Returns a 32-bit value that specifies the size of a page for the trackbar.


TBM_GETPOS [New - Windows NT]
TBM_GETPOS  QuickInfo  Overview  Group

[New - Windows NT]

TBM_GETPOS

wParam = 0;

lParam = 0;

The TBM_GETPOS message retrieves the current position of the slider in a trackbar.

Return Value

Returns a 32-bit value that specifies the current position.


TBM_GETPTICS [New - Windows NT]
TBM_GETPTICS  QuickInfo  Overview  Group

[New - Windows NT]

TBM_GETPTICS

wParam = 0;

lParam = 0;

The TBM_GETPTICS message retrieves the pointer to the array that contains the positions of tick marks for a trackbar.

Return Value

Returns the pointer to the array.


TBM_GETRANGEMAX [New - Windows NT]
TBM_GETRANGEMAX  QuickInfo  Overview  Group

[New - Windows NT]

TBM_GETRANGEMAX

wParam = 0;

lParam = 0;

The TBM_GETRANGEMAX message retrieves the maximum position for the slider in a trackbar.

Return Value

Returns a 32-bit value that specifies the maximum position.


TBM_GETRANGEMIN [New - Windows NT]
TBM_GETRANGEMIN  QuickInfo  Overview  Group

[New - Windows NT]

TBM_GETRANGEMIN

wParam = 0;

lParam = 0;

The TBM_GETRANGEMIN message retrieves the minimum position for the slider in a trackbar.

Return Value

Returns a 32-bit value that specifies the minimum position.


TBM_GETSELEND [New - Windows NT]
TBM_GETSELEND  QuickInfo  Overview  Group

[New - Windows NT]

TBM_GETSELEND

wParam = 0;

lParam = 0;

The TBM_GETSELEND message retrieves the ending position of the current selection in a trackbar.

Return Value

Returns a 32-bit value that specifies the ending position of the current selection.


TBM_GETSELSTART [New - Windows NT]
TBM_GETSELSTART  QuickInfo  Overview  Group

[New - Windows NT]

TBM_GETSELSTART

wParam = 0;

lParam = 0;

The TBM_GETSELSTART message retrieves the starting position of the current selection in a trackbar.

Return Value

Returns a 32-bit value that specifies the starting position of the current selection.


TBM_GETTHUMBLENGTH [New - Windows NT]
TBM_GETTHUMBLENGTH  QuickInfo  Overview  Group

[New - Windows NT]

TBM_GETTHUMBLENGTH

wParam = 0;

lParam = 0;

The TBM_GETTHUMBLENGTH message retrieves the length of the slider in a trackbar.

Return Value

Returns the length, in pixels, of the slider.


TBM_GETTHUMBRECT [New - Windows NT]
TBM_GETTHUMBRECT  QuickInfo  Overview  Group

[New - Windows NT]

TBM_GETTHUMBRECT

wParam = 0;

lParam = (LPARAM) (LPRECT) lprc;

The TBM_GETTHUMBRECT message retrieves the size and position of the bounding rectangle for the slider in a trackbar.

Parameters

lprc

Pointer to a RECT structure that contains the bounding rectangle for the slider when the function returns.

Return Value

No return value.

See Also

RECT


TBM_GETTIC [New - Windows NT]
TBM_GETTIC  QuickInfo  Overview  Group

[New - Windows NT]

TBM_GETTIC

wParam = (WPARAM) (WORD) iTic;

lParam = 0;

The TBM_GETTIC message retrieves the position of a tick mark in a trackbar.

Parameters

iTic

Zero-based index identifying a tick mark.

Return Value

Returns the position of the specified tick mark or  − 1 if iTic does not specify a valid index.


TBM_GETTICPOS [New - Windows NT]
TBM_GETTICPOS  QuickInfo  Overview  Group

[New - Windows NT]

TBM_GETTICPOS

wParam = (WPARAM) (WORD) iTic;

lParam = 0;

The TBM_GETTICPOS message retrieves the current physical position of a tick mark in a trackbar.

Parameters

iTic

Zero-based index identifying a tick mark.

Return Value

Returns the physical position, in client coordinates, of the specified tick mark or − 1 if iTic does not specify a valid index.


TBM_SETLINESIZE [New - Windows NT]
TBM_SETLINESIZE  QuickInfo  Overview  Group

[New - Windows NT]

TBM_SETLINESIZE
wParam = 0;

lParam = (LONG) lLineSize;

The TBM_SETLINESIZE message sets the size of the line for a trackbar. The line size affects how much the slider moves for the TB_LINEUP and TB_LINEDOWN notification messages.

Parameters

lLineSize

New line size.

Return Value

Returns a 32-bit value that specifies the previous line size.


TBM_SETPAGESIZE [New - Windows NT]
TBM_SETPAGESIZE  QuickInfo  Overview  Group

[New - Windows NT]

TBM_SETPAGESIZE
wParam = 0;

lParam = (LONG) lPageSize;

The TBM_SETPAGESIZE message sets the size of the page for a trackbar. The page size affects how much the slider moves for the TB_PAGEUP and TB_PAGEDOWN notification messages.

Parameters

lPageSize

New page size.

Return Value

Returns a 32-bit value that specifies the previous page size.


TBM_SETPOS [New - Windows NT]
TBM_SETPOS  QuickInfo  Overview  Group

[New - Windows NT]

TBM_SETPOS

wParam = (WPARAM) (BOOL) fPosition;

lParam = (LPARAM) (LONG) lPosition;

The TBM_SETPOS message sets the current position of the slider in a trackbar.

Parameters

fPosition

Position flag. If this parameter is TRUE, the message sets the slider to the position given by lPosition. Otherwise, the message ensures that the current position is within the current minimum and maximum positions, but it does not move the slider.

lPosition

New position of the slider.

Return Value

No return value.


TBM_SETRANGE [New - Windows NT]
TBM_SETRANGE  QuickInfo  Overview  Group

[New - Windows NT]

TBM_SETRANGE

wParam = (WPARAM) (BOOL) fRedraw;

lParam = (LPARAM) MAKELONG(lMinimum, lMaximum);

The TBM_SETRANGE message sets the range (minimum and maximum positions) for the slider in a trackbar.

Parameters

fRedraw

Redraw flag. If this parameter is TRUE, the slider is redrawn after the range is set.

lMinimum

Minimum position for the slider.

lMaximum

Maximum position for the slider.

Return Value

No return value.


TBM_SETRANGEMAX [New - Windows NT]
TBM_SETRANGEMAX  QuickInfo  Overview  Group

[New - Windows NT]

TBM_SETRANGEMAX

wParam = (WPARAM) fRedraw;

lParam = (LPARAM) lMaximum;

The TBM_SETRANGEMAX message sets the maximum position for the slider in a trackbar.

Parameters

fRedraw

Redraw flag. If this parameter is TRUE, the slider is redrawn after the range is set.

lMaximum

Maximum position for the slider.

Return Value

No return value.


TBM_SETRANGEMIN [New - Windows NT]
TBM_SETRANGEMIN  QuickInfo  Overview  Group

[New - Windows NT]

TBM_SETRANGEMIN

wParam = (WPARAM) fRedraw;

lParam = (LPARAM) lMinimum;

The TBM_SETRANGEMIN message sets the minimum position for the slider in a trackbar.

Parameters

fRedraw

Redraw flag. If this parameter is TRUE, the slider is redrawn after the range is set.

lMinimum

Minimum position for the slider.

Return Value

No return value.


TBM_SETSEL [New - Windows NT]
TBM_SETSEL  QuickInfo  Overview  Group

[New - Windows NT]

TBM_SETSEL

wParam = (WPARAM) (BOOL) fRedraw;

lParam = (LPARAM) MAKELONG(lMinimum, lMaximum);

The TBM_SETSEL message sets the starting and ending positions for the current selection in a trackbar.

Parameters

fRedraw

Redraw flag. If this parameter is TRUE, the slider is redrawn after the selection is set.

lMinimum

Starting position for the slider.

lMaximum

Ending position for the slider.

Return Value

No return value.


TBM_SETSELEND [New - Windows NT]
TBM_SETSELEND  QuickInfo  Overview  Group

[New - Windows NT]

TBM_SETSELEND

wParam = (WPARAM) (BOOL) fRedraw;

lParam = (LPARAM) (LONG) lEnd;

The TBM_SETSELEND message sets the ending position of the current selection in a trackbar.

Parameters

fRedraw

Redraw flag. If this parameter is TRUE, the slider is redrawn after the selection is set.

lEnd

Ending position of the selection.

Return Value

No return value.


TBM_SETSELSTART [New - Windows NT]
TBM_SETSELSTART  QuickInfo  Overview  Group

[New - Windows NT]

TBM_SETSELSTART

wParam = (WPARAM) (BOOL) fRedraw;

lParam = (LPARAM) (LONG) lStart;

The TBM_SETSELSTART message sets the starting position of the current selection in a trackbar.

Parameters

fRedraw

Redraw flag. If this parameter is TRUE, the slider is redrawn after the selection is set.

lStart

Starting position of the selection.

Return Value

No return value.


TBM_SETTHUMBLENGTH [New - Windows NT]
TBM_SETTHUMBLENGTH  QuickInfo  Overview  Group

[New - Windows NT]

TBM_SETTHUMBLENGTH

wParam = (WPARAM) (UINT) iLength;

lParam = 0;

The TBM_SETTHUMBLENGTH message sets the length of the slider in a trackbar.

Parameters

iLength

Length, in pixels, of the slider.

Return Value

No return value.


TBM_SETTIC [New - Windows NT]
TBM_SETTIC  QuickInfo  Overview  Group

[New - Windows NT]

TBM_SETTIC

wParam = 0;

lParam = (LPARAM) (LONG) lPosition;

The TBM_SETTIC message sets the position of a tick mark in a trackbar.

Parameters

lPosition

Position of the tick mark. This parameter must specify a positive value.

Return Value

Returns TRUE if the tick mark is set or FALSE otherwise.

Remarks

A trackbar creates its own first and last tick marks. An application should not use this message to set the first and last marks.


TBM_SETTICFREQ [New - Windows NT]
TBM_SETTICFREQ  QuickInfo  Overview  Group

[New - Windows NT]

TBM_SETTICFREQ

wParam = (WPARAM) wFreq;

lParam = (LPARAM) (LONG) lPosition;

The TBM_SETTICFREQ message sets the interval frequency for tick marks in a trackbar. For example, if the frequency is set to two, a tick mark is displayed for every other increment in the trackbar's range. The default setting for the frequency is one; that is, every increment in the range is associated with a tick mark.

Parameters

wFreq

Frequency of the tick marks.

lPosition

Position of the tick mark. This parameter must specify a positive value.

Return Value

No return value.

Remarks

The trackbar must have the TBS_AUTOTICKS style to use this message.


TBN_BEGINADJUST [New - Windows NT]
TBN_BEGINADJUST  QuickInfo  Overview  Group

[New - Windows NT]

TBN_BEGINADJUST

pnmhdr = (NMHDR FAR *) lParam;

The TBN_BEGINADJUST notification message notifies a toolbar's parent window that the user has begun customizing a toolbar. This message is sent in the form of a WM_NOTIFY message.

Parameters

pnmhdr

Pointer to an NMHDR structure that contains information about the notification message.

Return Value

No return value.

See Also

NMHDR, WM_NOTIFY


TBN_BEGINDRAG [New - Windows NT]
TBN_BEGINDRAG  QuickInfo  Overview  Group

[New - Windows NT]

TBN_BEGINDRAG

ptbn = (TBNOTIFY FAR *) lParam;

The TBN_BEGINDRAG notification message notifies a toolbar's parent window that the user has begun dragging a button in a toolbar. This message is sent in the form of a WM_NOTIFY message.

Parameters

ptbn

Pointer to a TBNOTIFY structure. The iItem member contains the zero-based index of the button being dragged.

Return Value

No return value.

See Also

TBNOTIFY, WM_NOTIFY


TBN_CUSTHELP [New - Windows NT]
TBN_CUSTHELP  QuickInfo  Overview  Group

[New - Windows NT]

TBN_CUSTHELP

pnmhdr = (NMHDR FAR *) lParam;

The TBN_CUSTHELP notification message notifies a toolbar's parent window that the user has chosen the Help button in the Customize Toolbar dialog box. This message is sent in the form of a WM_NOTIFY message.

Parameters

pnmhdr

Pointer to an NMHDR structure that contains information about the notification message.

Return Value

No return value.

See Also

NMHDR, WM_NOTIFY


TBN_ENDADJUST [New - Windows NT]
TBN_ENDADJUST  QuickInfo  Overview  Group

[New - Windows NT]

TBN_ENDADJUST

pnmhdr = (NMHDR FAR *) lParam;

The TBN_ENDADJUST notification message notifies a toolbar's parent window that the user has stopped customizing a toolbar. This message is sent in the form of a WM_NOTIFY message.

Parameters

pnmhdr

Pointer to an NMHDR structure that contains information about the notification message.

Return Value

No return value.

See Also

NMHDR, WM_NOTIFY


TBN_ENDDRAG [New - Windows NT]
TBN_ENDDRAG  QuickInfo  Overview  Group

[New - Windows NT]

TBN_ENDDRAG

ptbn = (TBNOTIFY FAR *) lParam;

The TBN_ENDDRAG notification message notifies the toolbar's parent window that the user has stopped dragging a button in a toolbar. This message is sent in the form of a WM_NOTIFY message.

Parameters

ptbn

Pointer to a TBNOTIFY structure. The iItem member contains the zero-based index of the button being dragged.

Return Value

No return value.

See Also

TBNOTIFY, WM_NOTIFY


TBN_GETBUTTONINFO [New - Windows NT]
TBN_GETBUTTONINFO  QuickInfo  Overview  Group

[New - Windows NT]

TBN_GETBUTTONINFO

ptbn = (TBNOTIFY FAR *) lParam;

The TBN_GETBUTTONINFO message retrieves toolbar customization information and notifies the toolbar's parent window of any changes being made to the toolbar. This is sent in the form of a WM_NOTIFY message.

Parameters

ptbn

Pointer to a TBNOTIFY structure. The iItem member specifies a zero-based index that provides a count of the buttons the customize dialog box displays as both available and present on the toolbar.

The pszText member specifies the address of the current button text, and cchText specifies its length in characters. The application should fill the structure with information about the button.

Return Value

Returns TRUE if button information was copied to the specified structure or FALSE otherwise.

Remarks

The toolbar control allocates a buffer, and the receiver (parent window) must copy the text into that buffer. The cchText member contains the length of the buffer allocated by the toolbar when TBN_GETBUTTONINFO is sent to the parent window.

See Also

TBNOTIFY, WM_NOTIFY


TBN_QUERYDELETE [New - Windows NT]
TBN_QUERYDELETE  QuickInfo  Overview  Group

[New - Windows NT]

TBN_QUERYDELETE

ptbn = (TBNOTIFY FAR *) lParam;

The TBN_QUERYDELETE notification message notifies the toolbar's parent window whether a button may be deleted from a toolbar while the user is customizing a toolbar. This message is sent in the form of a WM_NOTIFY message.

Parameters

ptbn

Pointer to a TBNOTIFY structure. The iItem member contains the zero-based index of the button to be deleted.

Return Value

Returns TRUE to allow the button to be deleted or FALSE to prevent the button from being deleted.

See Also

TBNOTIFY, WM_NOTIFY


TBN_QUERYINSERT [New - Windows NT]
TBN_QUERYINSERT  QuickInfo  Overview  Group

[New - Windows NT]

TBN_QUERYINSERT

ptbn = (TBNOTIFY FAR *) lParam;

The TBN_QUERYINSERT notification message notifies the toolbar's parent window whether a button may be inserted to the left of the specified button while the user is customizing a toolbar. This message is sent in the form of a WM_NOTIFY message.

Parameters

ptbn

Pointer to a TBNOTIFY structure. The iItem member contains the zero-based index of the button to be inserted.

Return Value

Returns TRUE to allow a button to inserted in front of the given button or FALSE to prevent the button from being inserted.

See Also

TBNOTIFY, WM_NOTIFY


TBN_RESET [New - Windows NT]
TBN_RESET  QuickInfo  Overview  Group

[New - Windows NT]

TBN_RESET

pnmhdr = (NMHDR FAR *) lParam;

The TBN_RESET notification message notifies the toolbar's parent window that the user has reset the content of the Customize Toolbar dialog box. This message is sent in the form of a WM_NOTIFY message.

Parameters

pnmhdr

Pointer to an NMHDR structure that contains information about the notification message.

Return Value

No return value.

See Also

NMHDR, WM_NOTIFY


TBN_TOOLBARCHANGE [New - Windows NT]
TBN_TOOLBARCHANGE  QuickInfo  Overview  Group

[New - Windows NT]

TBN_TOOLBARCHANGE

pnmhdr = (NMHDR FAR *) lParam;

The TBN_TOOLBARCHANGE notification message notifies the toolbar's parent window that the user has customized a toolbar. This message is sent in the form of a WM_NOTIFY message.

Parameters

pnmhdr

Pointer to an NMHDR structure that contains information about the notification message.

Return Value

No return value.

See Also

NMHDR, WM_NOTIFY


TCM_ADJUSTRECT [New - Windows NT]
TCM_ADJUSTRECT  QuickInfo  Overview  Group

[New - Windows NT]

TCM_ADJUSTRECT

wParam = (WPARAM) (BOOL) fLarger;  // operation to perform

lParam = (LPARAM) (LPRECT) prc;    // pointer to a RECT structure

// Corresponding macro

VOID TabCtrl_AdjustRect(HWND hwnd, BOOL fLarger, RECT FAR* prc);

The TCM_ADJUSTRECT message calculates a tab control's display area given a window rectangle or calculates the window rectangle that would correspond to a specified display area. You can send this message explicitly or by using the TabCtrl_AdjustRect macro.

Parameters

fLarger

Operation to perform. If this parameter is TRUE, prc specifies a display rectangle and receives the corresponding window rectangle. If this parameter is FALSE, prc specifies a window rectangle and receives the corresponding display area.

prc

Pointer to a RECT structure that specifies the given rectangle and receives the calculated rectangle.

hwnd

Handle to the tab control.

Return Value

No return value.

See Also

RECT


TCM_DELETEALLITEMS [New - Windows NT]
TCM_DELETEALLITEMS  QuickInfo  Overview  Group

[New - Windows NT]

TCM_DELETEALLITEMS

wParam = 0;           // not used; must be zero

lParam = 0;           // not used; must be zero

// Corresponding macro

BOOL TabCtrl_DeleteAllItems(HWND hwnd);

The TCM_DELETEALLITEMS message removes all items from a tab control. You can send this message explicitly or by using the TabCtrl_DeleteAllItems macro.

Parameters

hwnd

Handle to the tab control.

Return Value

Returns TRUE if successful or FALSE otherwise.


TCM_DELETEITEM [New - Windows NT]
TCM_DELETEITEM  QuickInfo  Overview  Group

[New - Windows NT]

TCM_DELETEITEM

wParam = (WPARAM) (int) iItem;  // index of the item to delete

lParam = 0;                     // not used; must be zero

// Corresponding macro

BOOL TabCtrl_DeleteItem(HWND hwnd, int iItem);

The TCM_DELETEITEM message removes an item from a tab control. You can send this message explicitly or by using the TabCtrl_DeleteItem macro.

Parameters

iItem

Index of the item to delete.

hwnd

Handle to the tab control.

Return Value

Returns TRUE if successful or FALSE otherwise.


TCM_GETCURFOCUS [New - Windows NT]
TCM_GETCURFOCUS  QuickInfo  Overview  Group

[New - Windows NT]

TCM_GETCURFOCUS

wParam = 0;  // not used; must be zero

lParam = 0;  // not used; must be zero

// Corresponding macro

int TabCtrl_GetCurFocus(HWND hwnd);

The TCM_GETCURFOCUS message returns the index of the item that has the focus in a tab control. You can send this message explicitly or by using the TabCtrl_GetCurFocus macro.

Parameters

hwnd

Handle to the tab control.

Return Value

Returns the index of the tab item that has the focus

Remarks

The item that has the focus may be different than the selected item.


TCM_GETCURSEL [New - Windows NT]
TCM_GETCURSEL  QuickInfo  Overview  Group

[New - Windows NT]

TCM_GETCURSEL

wParam = 0;   // not used; must be zero

lParam = 0;   // not used; must be zero

// Corresponding macro

int TabCtrl_GetCurSel(HWND hwnd);

The TCM_GETCURSEL message determines the currently selected tab in a tab control. You can send this message explicitly or by using the TabCtrl_GetCurSel macro.

Parameters

hwnd

Handle to the tab control.

Return Value

Returns the index of the selected tab if successful or  − 1 if no tab is selected.


TCM_GETIMAGELIST [New - Windows NT]
TCM_GETIMAGELIST  QuickInfo  Overview  Group

[New - Windows NT]

TCM_GETIMAGELIST

wParam = 0;   // not used; must be zero

lParam = 0;   // not used; must be zero

// Corresponding macro

HIMAGELIST TabCtrl_GetImageList(HWND hwnd);

The TCM_GETIMAGELIST message retrieves the image list associated with a tab control. You can send this message explicitly or by using the TabCtrl_GetImageList macro.

Return Value

Returns the handle to the image list if successful or NULL otherwise.


TCM_GETITEM [New - Windows NT]
TCM_GETITEM  QuickInfo  Overview  Group

[New - Windows NT]

TCM_GETITEM

wParam = (WPARAM) (int) iItem;

lParam = (LPARAM) (TC_ITEM FAR *) pitem;

// Corresponding macro

BOOL TabCtrl_GetItem(HWND hwnd, int iItem, TC_ITEM FAR* pitem);

The TCM_GETITEM message retrieves information about a tab in a tab control. You can send this message explicitly or by using the TabCtrl_GetItem macro.

Parameters

iItem

Index of the tab.

pitem

Pointer to a TC_ITEM structure that specifies the information to retrieve and receives information about the tab. When the message is sent, the mask member specifies which attributes to return.

If the mask member specifies the TCIF_TEXT value, the pszText member must contain the address of the buffer that receives the item text and the cchTextMax member must specify the size of the buffer.

hwnd

Handle to the tab control.

Return Value

Returns TRUE if successful or FALSE otherwise.

See Also

TC_ITEM


TCM_GETITEMCOUNT [New - Windows NT]
TCM_GETITEMCOUNT  QuickInfo  Overview  Group

[New - Windows NT]

TCM_GETITEMCOUNT

wParam = 0;   // not used; must be zero

lParam = 0;   // not used; must be zero

// Corresponding macro

int TabCtrl_GetItemCount(HWND hwnd);

The TCM_GETITEMCOUNT message retrieves the number of tabs in the tab control. You can send this message explicitly or by using the TabCtrl_GetItemCount macro.

Parameters

hwnd

Handle to the tab control.

Return Value

Returns the number of items if successful or zero otherwise.


TCM_GETITEMRECT [New - Windows NT]
TCM_GETITEMRECT  QuickInfo  Overview  Group

[New - Windows NT]

TCM_GETITEMRECT

wParam = (WPARAM) (int) iItem;       // index of the tab

lParam = (LPARAM) (RECT FAR *) prc;  // pointer to a structure to receive rectangle of tab

// Corresponding macro

BOOL TabCtrl_GetItemRect(HWND hwnd, int iItem, RECT FAR* prc);

The TCM_GETITEMRECT message retrieves the bounding rectangle for a tab in a tab control. You can send this message explicitly or by using the TabCtrl_GetItemRect macro.

Parameters

iItem

Index of the tab.

prc

Pointer to a RECT structure that receives the bounding rectangle of the tab, in viewport coordinates.

hwnd

Handle to the tab control.

Return Value

Returns TRUE if successful or FALSE otherwise.

See Also

RECT


TCM_GETROWCOUNT [New - Windows NT]
TCM_GETROWCOUNT  QuickInfo  Overview  Group

[New - Windows NT]

TCM_GETROWCOUNT

wParam = 0;   // not used; must be zero

lParam = 0;   // not used; must be zero

// Corresponding macro

int TabCtrl_GetRowCount(HWND hwnd);

The TCM_GETROWCOUNT message retrieves the current number of rows of tabs in a tab control. You can send this message explicitly or by using the TabCtrl_GetRowCount macro.

Parameters

hwnd

Handle to the tab control.

Return Value

Returns the number of rows of tabs.

Remarks

Only tab controls that have the TCS_MULTILINE style can have multiple rows of tabs.


TCM_GETTOOLTIPS [New - Windows NT]
TCM_GETTOOLTIPS  QuickInfo  Overview  Group

[New - Windows NT]

TCM_GETTOOLTIPS

wParam = 0;   // not used; must be zero

lParam = 0;   // not used; must be zero

// Corresponding macro

int TabCtrl_GetToolTips(HWND hwnd);

The TCM_GETTOOLTIPS message retrieves the handle to the tooltip control associated with a tab control. You can send this message explicitly or by using the TabCtrl_GetToolTips macro.

Parameters

hwnd

Handle to the tab control.

Return Value

Returns the handle to the tooltip control if successful or NULL otherwise.

Remarks

A tab control creates a tooltip control if it has the TCS_TOOLTIPS style. You can also assign a tooltip control to a tab control by using the TCM_SETTOOLTIPS message.

See Also

TCM_SETTOOLTIPS


TCM_HITTEST [New - Windows NT]
TCM_HITTEST  QuickInfo  Overview  Group

[New - Windows NT]

TCM_HITTEST

wParam = 0;    // not used; must be zero

lParam = (LPARAM) (TC_HITTESTINFO FAR *) pinfo; \\pointer to struct specifying position to test

// Corresponding macro

int TabCtrl_HitTest(HWND hwnd, TC_HITTESTINFO FAR* pinfo);

The TCM_HITTEST message determines which tab, if any, is at a specified screen position. You can send this message explicitly or by using the TabCtrl_HitTest macro.

Parameters

pinfo

Pointer to a TC_HITTESTINFO structure that specifies the screen position to test.

hwnd

Handle to the tab control.

Return Value

Returns the index of the tab or  − 1 if no tab is at the specified position.

See Also

TC_HITTESTINFO


TCM_INSERTITEM [New - Windows NT]
TCM_INSERTITEM  QuickInfo  Overview  Group

[New - Windows NT]

TCM_INSERTITEM

wParam = (WPARAM) (int) iItem;                 \\index of the new tab

lParam = (LPARAM) (const TC_ITEM FAR*) pitem;  \\pointer to struct specifying tab attributes

// Corresponding macro

int TabCtrl_InsertItem(HWND hwnd, int iItem,

        const TC_ITEM FAR* pitem);

The TCM_INSERTITEM message inserts a new tab in a tab control. You can send this message explicitly or by using the TabCtrl_InsertItem macro.

Parameters

iItem

Index of the new tab.

pitem

Pointer to a TC_ITEM structure that specifies the attributes of the tab.

hwnd

Handle to the tab control.

Return Value

Returns the index of the new tab if successful or  − 1 otherwise.

See Also

TC_ITEM


TCM_REMOVEIMAGE [New - Windows NT]
TCM_REMOVEIMAGE  QuickInfo  Overview  Group

[New - Windows NT]

TCM_REMOVEIMAGE

wParam = (WPARAM) (int) iImage;  // index of the image to remove

lParam = 0;                      // not used; must be zero

// Corresponding macro

void TabCtrl_RemoveImage(HWND hwnd, int iImage);

The TCM_REMOVEIMAGE message removes an image from a tab control's image list. You can send this message explicitly or by using the TabCtrl_RemoveImage macro.

Parameters

iImage

Index of the image to remove.

hwnd

Handle to the tab control.

Return Value

No return value.

Remarks

The tab control updates each tab's image index, so each tab remains associated with the same image it had been.


TCM_SETCURSEL [New - Windows NT]
TCM_SETCURSEL  QuickInfo  Overview  Group

[New - Windows NT]

TCM_SETCURSEL

wParam = (WPARAM) (int) iItem;  // index of the tab to select

lParam = 0;                     // not used; must be zero

// Corresponding macro

int TabCtrl_SetCurSel(HWND hwnd, int iItem);

The TCM_SETCURSEL message selects a tab in a tab control. You can send this message explicitly or by using the TabCtrl_SetCurSel macro.

Parameters

iItem

Index of the tab to select.

hwnd

Handle to the tab control.

Return Value

Returns the index of the previously selected tab if successful or  − 1 otherwise.

Remarks

A tab control does not send a TCN_SELCHANGING or TCN_SELCHANGE notification message when a tab is selected using this message.

See Also

TCN_SELCHANGE, TCN_SELCHANGING


TCM_SETIMAGELIST [New - Windows NT]
TCM_SETIMAGELIST  QuickInfo  Overview  Group

[New - Windows NT]

TCM_SETIMAGELIST

wParam = 0;                           // not used; must be zero

lParam = (LPARAM) (HIMAGELIST) himl;  // handle of image list to assign to tab control

// Corresponding macro

BOOL TabCtrl_SetImageList(HWND hwnd, HIMAGELIST himl);

The TCM_SETIMAGELIST message assigns an image list to a tab control. You can send this message explicitly or by using the TabCtrl_SetImageList macro.

Parameters

himl

Handle of the image list to assign to the tab control.

hwnd

Handle to the tab control.

Return Value

Returns the handle to the previous image list or NULL if there is no previous image list.


TCM_SETITEM [New - Windows NT]
TCM_SETITEM  QuickInfo  Overview  Group

[New - Windows NT]

TCM_SETITEM

wParam = (WPARAM) (int) iItem;            // index of the item

lParam = (LPARAM) (TC_ITEM FAR *) pitem;  // pointer to struct containing item attributes

// Corresponding macro

BOOL TabCtrl_SetItem(HWND hwnd, int iItem, TC_ITEM FAR* pitem);

The TCM_SETITEM message sets some or all of a tab's attributes. You can send this message explicitly or by using the TabCtrl_SetItem macro.

Parameters

iItem

Index of the item.

pitem

Pointer to a TC_ITEM structure that contains the new item attributes. The mask member specifies which attributes to set.

If the mask member specifies the LVIF_TEXT value, the pszText member is the address of a null-terminated string and the cchTextMax member is ignored.

hwnd

Handle to the tab control.

Return Value

Returns TRUE if successful or FALSE otherwise.

See Also

TC_ITEM


TCM_SETITEMEXTRA [New - Windows NT]
TCM_SETITEMEXTRA  QuickInfo  Overview  Group

[New - Windows NT]

TCM_SETITEMEXTRA

wParam = (WPARAM) (int) cb;  // number of extra bytes

lParam = 0;                  // not used; must be zero

// Corresponding macro

BOOL TabCtrl_SetItemExtra(HWND hwnd, int cb);

The TCM_SETITEMEXTRA message sets the number of bytes per tab reserved for application-defined data in a tab control. You can send this message explicitly or by using the TabCtrl_SetItemExtra macro.

Parameters

cb

Number of extra bytes.

hwnd

Handle to the tab control.

Return Value

Returns TRUE if successful or FALSE otherwise.

Remarks

By default, the number of extra bytes is four. An application that changes the number of extra bytes cannot use the TC_ITEM structure to retrieve and set the application-defined data for a tab. Instead, you must define a new structure that consists of the TC_ITEMHEADER structure followed by application-defined members.

An application should only change the number of extra bytes when a tab control does not contain any tabs.

See Also

TC_ITEM, TC_ITEMHEADER


TCM_SETITEMSIZE [New - Windows NT]
TCM_SETITEMSIZE  QuickInfo  Overview  Group

[New - Windows NT]

TCM_SETITEMSIZE

wParam = 0;                   // not used; must be zero

lParam = MAKELPARAM(cx, cy);  // new width and height, in pixels

// Corresponding macro

DWORD TabCtrl_SetItemSize(HWND hwnd, int cx, int cy);

The TCM_SETITEMSIZE message sets the width and height of tabs in a fixed-width or owner-drawn tab control. You can send this message explicitly or by using the TabCtrl_SetItemSize macro.

Parameters

cx and cy

New width and height, in pixels.

hwnd

Handle to the tab control.

Return Value

Returns the old width and height. The width is in the low-order word of the return value, and the height is in the high-order word.


TCM_SETPADDING [New - Windows NT]
TCM_SETPADDING  QuickInfo  Overview  Group

[New - Windows NT]

TCM_SETPADDING

wParam = 0;                   // not used; must be zero

lParam = MAKELPARAM(cx, cy);  // amount of horizontal and vertical padding, in pixels

// Corresponding macro

void TabCtrl_SetPadding(HWND hwnd, int cx, int cy);

The TCM_SETPADDING message sets the amount of space (padding) around each tab's icon and label in a tab control. You can send this message explicitly or by using the TabCtrl_SetPadding macro.

Parameters

cx and cy

Amount of horizontal and vertical padding, in pixels.

hwnd

Handle to the tab control.

Return Value

No return value.


TCM_SETTOOLTIPS [New - Windows NT]
TCM_SETTOOLTIPS  QuickInfo  Overview  Group

[New - Windows NT]

TCM_SETTOOLTIPS

wParam = (WPARAM) (HWND) hwndTT;    \\handle to the tooltip control

lParam = 0;                       // not used; must be zero

// Corresponding macro

void TabCtrl_SetToolTips(HWND hwndTab, HWND hwndTT);

The TCM_SETTOOLTIPS message assigns a tooltip control to a tab control. You can send this message explicitly or by using the TabCtrl_SetToolTips macro.

Parameters

hwndTT

Handle to the tooltip control.

hwndTab

Handle to the tab control.

Return Value

No return value.

Remarks

You can get the tooltip control associated with a tab control by using the TCM_GETTOOLTIPS message.

See Also

TCM_GETTOOLTIPS


TCN_KEYDOWN [New - Windows NT]
TCN_KEYDOWN  QuickInfo  Overview  Group

[New - Windows NT]

TCN_KEYDOWN

pnm = (TC_KEYDOWN FAR *) lParam;

The TCN_KEYDOWN notification message notifies a tab control's parent window that a key has been pressed. This message is sent in the form of a WM_NOTIFY message.

Parameters

pnm

Pointer to a TC_KEYDOWN structure.

Return Value

No return value.

See Also

TC_KEYDOWN, WM_NOTIFY


TCN_SELCHANGE [New - Windows NT]
TCN_SELCHANGE  QuickInfo  Overview  Group

[New - Windows NT]

TCN_SELCHANGE

idTabCtl = (int) LOWORD(wParam);

hwndTabCtl = (HWND) lParam;

The TCN_SELCHANGE notification message notifies a tab control's parent window that the currently selected tab has changed. This message is sent in the form of a WM_NOTIFY message.

Return Value

No return value.

Remarks

To determine the currently selected tab, use the TabCtrl_GetCurSel macro.

See Also

WM_NOTIFY


TCN_SELCHANGING [New - Windows NT]
TCN_SELCHANGING  QuickInfo  Overview  Group

[New - Windows NT]

TCN_SELCHANGE

idTabCtl = (int) LOWORD(wParam);

hwndTabCtl = (HWND) lParam;

The TCN_SELCHANGING notification message notifies a tab control's parent window that the currently selected tab is about to change. This message is sent in the form of a WM_NOTIFY message.

Return Value

Returns TRUE to prevent the selection from changing or FALSE to allow the selection to change.

Remarks

To determine the currently selected tab, use the TabCtrl_GetCurSel macro.

See Also

WM_NOTIFY


TTM_ACTIVATE [New - Windows NT]
TTM_ACTIVATE  QuickInfo  Overview  Group

[New - Windows NT]

TTM_ACTIVATE

wParam = (WPARAM) (BOOL) fActivate;

lParam = 0;

The TTM_ACTIVATE message activates or deactivates a tooltip control.

Parameters

fActivate

Activation flag. If this parameter is TRUE, the tooltip control is activated. If it is FALSE, the tooltip control is deactivated.

Return Value

No return value.


TTM_ADDTOOL [New - Windows NT]
TTM_ADDTOOL  QuickInfo  Overview  Group

[New - Windows NT]

TTM_ADDTOOL

wParam = 0;

lParam = (LPARAM) (LPTOOLINFO) lpti;

The TTM_ADDTOOL message registers a tool with a tooltip control.

Parameters

lpti

Pointer to a TOOLINFO structure containing information that the tooltip control needs to display text for the tool.

Return Value

Returns TRUE if successful or FALSE otherwise.

See Also

TOOLINFO


TTM_DELTOOL [New - Windows NT]
TTM_DELTOOL  QuickInfo  Overview  Group

[New - Windows NT]

TTM_DELTOOL

wParam = 0;

lParam = (LPARAM) (LPTOOLINFO) lpti;

The TTM_DELTOOL message removes a tool from a tooltip control.

Parameters

lpti

Pointer to a TOOLINFO structure. The hwnd and uId members identify the tool to remove, and the cbSize member must specify the size of the structure. All other members are ignored.

Return Value

No return value.

See Also

TOOLINFO


TTM_ENUMTOOLS [New - Windows NT]
TTM_ENUMTOOLS  QuickInfo  Overview  Group

[New - Windows NT]

TTM_ENUMTOOLS

wParam = (WPARAM) (UINT) iTool;

lParam = (LPARAM) (LPTOOLINFO) lpti;

The TTM_ENUMTOOLS message retrieves the information that a tooltip control maintains about the current tool; that is, the tool for which the tooltip is currently displaying text.

Parameters

iTool

Zero-based index of the tool for which to retrieve information.

lpti

Pointer to a TOOLINFO structure that receives information about the tool. Before sending this message, the cbSize member must specify the size of the structure.

Return Value

Returns TRUE if any tools are enumerated or FALSE otherwise.

Remarks

Retrieves the information that a tooltip control maintains about a tool.

See Also

TOOLINFO


TTM_GETCURRENTTOOL [New - Windows NT]
TTM_GETCURRENTTOOL  QuickInfo  Overview  Group

[New - Windows NT]

TTM_GETCURRENTTOOL

wParam = 0;

lParam = (LPARAM) (LPTOOLINFO) lpti;

The TTM_GETCURRENTTOOL message retrieves the text that a tooltip control maintains for a tool.

Parameters

lpti

Pointer to a TOOLINFO structure that receives information about the current tool.

Return Value

Returns TRUE if successful or FALSE otherwise.

See Also

TOOLINFO


TTM_GETTEXT [New - Windows NT]
TTM_GETTEXT  QuickInfo  Overview  Group

[New - Windows NT]

TTM_GETTEXT

wParam = 0;

lParam = (LPARAM) (LPTOOLINFO) lpti;

The TTM_GETTEXT message retrieves a count of the tools maintained by a tooltip control.

Parameters

lpti

Pointer to a TOOLINFO structure. When sending the message, the hwnd and uId members identify a tool. If the tooltip control includes the tool, the lpszText member receives the pointer to the string.

Return Value

No return value.

See Also

TOOLINFO


TTM_GETTOOLCOUNT [New - Windows NT]
TTM_GETTOOLCOUNT  QuickInfo  Overview  Group

[New - Windows NT]

TTM_GETTOOLCOUNT

wParam = 0;

lParam = 0;

The TTM_GETTOOLCOUNT message retrieves the information that a tooltip control maintains about a tool.

Return Value

Returns a count of tools.


TTM_GETTOOLINFO [New - Windows NT]
TTM_GETTOOLINFO  QuickInfo  Overview  Group

[New - Windows NT]

TTM_GETTOOLINFO

wParam = 0;

lParam = (LPARAM) (LPTOOLINFO) lpti;

The TTM_GETTOOLINFO message retrieves the information that a tooltip control maintains about a tool.

Parameters

lpti

Pointer to a TOOLINFO structure. When sending the message, the hwnd and uId members identify a tool, and the cbSize member must specify the size of the structure. If the tooltip control includes the tool, the structure receives information about the tool.

Return Value

Returns TRUE if successful or FALSE otherwise.

See Also

TOOLINFO


TTM_HITTEST [New - Windows NT]
TTM_HITTEST  QuickInfo  Overview  Group

[New - Windows NT]

TTM_HITTEST

wParam = 0;

lParam = (LPARAM) (LPHITTESTINFO) lphti;

The TTM_HITTEST message tests a point to determine whether it is within the bounding rectangle of the specified tool and, if the point is within, retrieves information about the tool.

Parameters

lphti

Pointer to a TTHITTESTINFO structure. When sending the message, the hwnd member must specify the handle of a tool and the pt member must specify the coordinates of a point. If the return value is TRUE, the ti member receives information about the tool that occupies the point.

Return Value

Returns TRUE if the tool occupies the specified point or FALSE otherwise.

See Also

TTHITTESTINFO


TTM_NEWTOOLRECT [New - Windows NT]
TTM_NEWTOOLRECT  QuickInfo  Overview  Group

[New - Windows NT]

TTM_NEWTOOLRECT

wParam = 0;

lParam = (LPARAM) (LPTOOLINFO) lpti;

The TTM_NEWTOOLRECT message sets a new bounding rectangle for a tool.

Parameters

lpti

Pointer to a TOOLINFO structure. The hwnd and uId members identify a tool, and the rect member specifies the new bounding rectangle.

Return Value

No return value.

See Also

TOOLINFO


TTM_RELAYEVENT [New - Windows NT]
TTM_RELAYEVENT  QuickInfo  Overview  Group

[New - Windows NT]

TTM_RELAYEVENT

wParam = 0;

lParam = (LPARAM) (LPMSG) lpmsg;

The TTM_RELAYEVENT message passes a mouse message to a tooltip control for processing.

Parameters

lpmsg

Pointer to an MSG structure that contains the message to relay.

Return Value

No return value.

Remarks

A tooltip control processes only the following messages passed to it by the TTM_RELAYEVENT message.

WM_LBUTTONDOWN	WM_MOUSEMOVE
WM_LBUTTONUP	WM_RBUTTONDOWN
WM_MBUTTONDOWN	WM_RBUTTONUP
WM_MBUTTONUP
All other messages are ignored.

See Also

MSG


TTM_SETDELAYTIME [New - Windows NT]
TTM_SETDELAYTIME  QuickInfo  Overview  Group

[New - Windows NT]

TTM_SETDELAYTIME

wParam = (WPARAM) uFlag;

lParam = (LPARAM) (int) iDelay;

The TTM_SETDELAYTIME message sets the initial, reshow, and autopopup durations for a tooltip control.

Parameters

uFlag

Duration to set. This parameter can be one of the following values:

Value	Meaning
TTDT_AUTOMATIC	Automatically calculates the initial, reshow, and autopopup durations based on the value of iDelay.
TTDT_AUTOPOP	Sets the length of time before the tooltip window is hidden if the cursor remains stationary in the tool's bounding rectangle after the tooltip window has appeared.
TTDT_INITIAL	Sets the length of time that the cursor must remain stationary within the bounding rectangle of a tool before the tooltip window is displayed.
TTDT_RESHOW	Sets the length of the delay before subsequent tooltip windows are displayed when the cursor is moved from one tool to another.
iDelay

New duration, in milliseconds.

Return Value

No return value.


TTM_SETTOOLINFO [New - Windows NT]
TTM_SETTOOLINFO  QuickInfo  Overview  Group

[New - Windows NT]

TTM_SETTOOLINFO

wParam = 0;

lParam = (LPARAM) (LPTOOLINFO) lpti;

The TTM_SETTOOLINFO message sets the information that a tooltip control maintains for a tool.

Parameters

lpti

Pointer to a TOOLINFO structure that specifies the information to set.

Return Value

No return value.

See Also

TOOLINFO


TTM_UPDATETIPTEXT
TTM_UPDATETIPTEXT  QuickInfo  Overview  Group

TTM_UPDATETIPTEXT

wParam = 0;

lParam = (LPARAM) (LPTOOLINFO) lpti;

The TTM_UPDATETIPTEXT message sets the tooltip text for a tool.

Parameters

lpti

Pointer to a TOOLINFO structure. The hinst and lpszText members must specify the instance handle and the pointer to the text. The hwnd and uId members identify the tool to update.

Return Value

No return value.

See Also

TOOLINFO


TTM_WINDOWFROMPOINT
TTM_WINDOWFROMPOINT  QuickInfo  Overview  Group

TTM_WINDOWFROMPOINT

wParam = 0;

lParam = (POINT FAR *) lppt;

The TTM_WINDOWFROMPOINT message allows a subclass procedure to cause a tooltip to display text for a window other than the one beneath the mouse cursor.

Parameters

lppt

Pointer to a POINT structure that defines the point to be checked.

Return Value

The return value is the handle to the window that contains the point, or NULL if no window exists at the specified point.

Remarks

This message is intended to be processed by an application that subclasses a tooltip. It is not intended to be sent by an application. A tooltip sends this message to itself before displaying the text for a window. By changing the coordinates of the point specified by lppt, the subclass procedure can cause the tooltip to display text for a window other than the one beneath the mouse cursor.

See Also

POINT


TTN_NEEDTEXT [New - Windows NT]
TTN_NEEDTEXT  QuickInfo  Overview  Group

[New - Windows NT]

TTN_NEEDTEXT

idTT = (int) wParam;

lpttt = (LPTOOLTIPTEXT) lParam;

The TTN_NEEDTEXT notification message retrieves text for a tool. This notification message is sent in the form of a WM_NOTIFY message.

Parameters

idTT

Identifier of the tooltip control.

lpttt

Pointer to a TOOLTIPTEXT structure. The hdr member identifies the tool for which text is needed. The receiving window can specify the string by taking one of the following actions:

•	Copying the text to the buffer specified by the szText member.

•	Copying the address of the buffer that contains the text to the lpszText member.

•	Copying the identifier of a string resource to the lpszText member and copying the handle of the instance that contains the resource to the hinst member.

Return Value

No return value.

Remarks

This notification message is sent to the window specified in the hwnd member of the TOOLINFO structure for the tool. This notification is sent only if the LPSTR_TEXTCALLBACK value is specified when the tool is added to a tooltip control.

Windows 95 only: When a TTN_NEEDTEXT notification is received, the application can set or clear the TTF_RTLREADING value in the uFlags member of the TOOLTIPTEXT structure pointed to by lpttt as required. This is the only flag that can be changed during the notification callback.

See Also

TOOLINFO, TOOLTIPTEXT, WM_NOTIFY


TTN_POP [New - Windows NT]
TTN_POP  QuickInfo  Overview  Group

[New - Windows NT]

TTN_POP

idTT = (int) wParam;

pnmh = (NMHDR FAR *) lParam;

The TTN_POP notification message notifies the owner window that a tooltip is about to be hidden. This notification message is sent in the form of a WM_NOTIFY message.

Parameters

idTT

Identifier of the tooltip control.

lpttt

Return Value

No return value.

Remarks

Address of an NMHDR structure.

See Also

NMHDR, WM_NOTIFY


TTN_SHOW [New - Windows NT]
TTN_SHOW  QuickInfo  Overview  Group

[New - Windows NT]

TTN_SHOW

idTT = (int) wParam;

pnmh = (NMHDR FAR *) lParam;

The TTN_SHOW notification message notifies the owner window that a tooltip is about to be displayed. This notification message is sent in the form of a WM_NOTIFY message.

Parameters

idTT

Identifier of the tooltip control.

lpttt

Return Value

No return value.

Remarks

Address of an NMHDR structure.

See Also

NMHDR, WM_NOTIFY


TVM_CREATEDRAGIMAGE [New - Windows NT]
TVM_CREATEDRAGIMAGE  QuickInfo  Overview  Group

[New - Windows NT]

TVM_CREATEDRAGIMAGE

wParam = 0;

lParam = (LPARAM) (HTREEITEM) hitem;

// Corresponding macro

HIMAGELIST TreeView_CreateDragImage(hwnd, hitem);

The TVM_CREATEDRAGIMAGE message creates a dragging bitmap for the specified item in a tree-view control, creates an image list for the bitmap, and adds the bitmap to the image list. An application can display the image when dragging the item by using the image list functions. You can send this message explicitly or by using the TreeView_CreateDragImage macro.

Parameters

hwnd

Handle to the tree-view control.

hitem

Handle to the item that receives the new dragging bitmap.

Return Value

Returns the handle of the image list to which the dragging bitmap was added if successful or NULL otherwise.


TVM_DELETEITEM [New - Windows NT]
TVM_DELETEITEM  QuickInfo  Overview  Group

[New - Windows NT]

TVM_DELETEITEM

wParam = 0;

lParam = (LPARAM) (HTREEITEM) hitem;

// Corresponding macro

BOOL TreeView_DeleteItem(hwnd, hitem);

// Related macro

BOOL TreeView_DeleteAllItems(hwnd);

The TVM_DELETEITEM message removes an item from a tree-view control. You can send this message explicitly or by using the TreeView_DeleteItem or TreeView_DeleteAllItems macro.

Parameters

hwnd

Handle to the tree-view control.

hitem

Handle to the item to delete. If hitem is the TVI_ROOT value, all items are deleted from the tree-view control.

Return Value

Returns TRUE if successful or FALSE otherwise.

Remarks

If the item label is being edited, the edit operation is canceled and the parent window receives the TVN_ENDLABELEDIT notification message. The parent window receives a TVN_DELETEITEM notification message when the item is removed.

See Also

TVN_DELETEITEM, TVN_ENDLABELEDIT


TVM_EDITLABEL [New - Windows NT]
TVM_EDITLABEL  QuickInfo  Overview  Group

[New - Windows NT]

TVM_EDITLABEL

wParam = 0;

lParam = (LPARAM) (HTREEITEM) hitem;

// Corresponding macro

HWND TreeView_EditLabel(hwnd, hitem);

The TVM_EDITLABEL message begins in-place editing of the specified item's text, replacing the text of the item with a single-line edit control containing the text. This message implicitly selects and focuses the specified item. You can send this message explicitly or by using the TreeView_EditLabel macro.

Parameters

hwnd

Handle to the tree-view control.

hitem

Handle to the item to edit.

Return Value

Returns the handle to the edit control used to edit the item text if successful or NULL otherwise.

Remarks

This message sends a TVN_BEGINLABELEDIT notification message to the parent of the tree-view control.

When the user completes or cancels editing, the edit control is destroyed and the handle is no longer valid. You can safely subclass the edit control, but do not destroy it.

The control must have the focus before you send this message to the control. Focus can be set using the SetFocus function.

See Also

TVN_BEGINLABELEDIT, SetFocus


TVM_ENDEDITLABELNOW [New - Windows NT]
TVM_ENDEDITLABELNOW  QuickInfo  Overview  Group

[New - Windows NT]

TVM_ENDEDITLABELNOW

wParam = (WPARAM) (BOOL) fCancel;

lParam = 0;

// Corresponding macro

BOOL TreeView_EndEditLabelNow(hwnd, fCancel);

The TVM_ENDEDITLABELNOW message ends the editing of a tree-view item's label.

Parameters

hwnd

Handle to the tree-view control.

fCancel

Variable that indicates whether the editing is canceled without being saved to the label. If this parameter is TRUE, the system cancels editing without saving the changes. Otherwise, the system saves the changes to the label.

Return Value

Returns TRUE if successful or FALSE otherwise.

Remarks

This message causes the TVN_ENDLABELEDIT notification message to be sent to the parent window of the tree-view control.

See Also

TVN_ENDLABELEDIT


TVM_ENSUREVISIBLE [New - Windows NT]
TVM_ENSUREVISIBLE  QuickInfo  Overview  Group

[New - Windows NT]

TVM_ENSUREVISIBLE

wParam = 0;

lParam = (LPARAM) (HTREEITEM) hitem;

// Corresponding macro

BOOL TreeView_EnsureVisible(hwnd, hitem);

The TVM_ENSUREVISIBLE message ensures that a tree-view item is visible, expanding the parent item or scrolling the tree-view control, if necessary. You can send this message explicitly or by using the TreeView_EnsureVisible macro.

Parameters

hwnd

Handle to the tree-view control.

hitem

Handle to the item.

Return Value

Returns TRUE if the system scrolled the items in the tree-view control to ensure that the specified item is visible. Otherwise, the message returns FALSE.

Remarks

If the TVM_ENSUREVISIBLE message expands the parent item, the parent window receives the TVN_ITEMEXPANDING and TVN_ITEMEXPANDED notification messages.

See Also

TVN_ITEMEXPANDED, TVN_ITEMEXPANDING


TVM_EXPAND [New - Windows NT]
TVM_EXPAND  QuickInfo  Overview  Group

[New - Windows NT]

TVM_EXPAND

wParam = (WPARAM) (UINT) flag;

lParam = (LPARAM) (HTREEITEM) hitem;

// Corresponding macro

BOOL TreeView_Expand(hwnd, hitem, flag);

The TVM_EXPAND message expands or collapses the list of child items, if any, associated with the specified parent item. You can send this message explicitly or by using the TreeView_Expand macro.

Parameters

hwnd

Handle to the tree-view control.

hitem

Handle to the parent item to expand or collapse.

flag

Action flag. This parameter can be one of the following values:

Value	Meaning
TVE_COLLAPSE	Collapses the list.
TVE_COLLAPSERESET	Collapses the list and removes the child items. Note that TVE_COLLAPSE must also be specified.
TVE_EXPAND	Expands the list.
TVE_TOGGLE	Collapses the list if it is currently expanded or expands it if it is currently collapsed.
Return Value

Returns TRUE if any change took place or FALSE otherwise.

Remarks

This message does not send the TVN_ITEMEXPANDING and TVN_ITEMEXPANDED notification messages to the parent window.

See Also

TVN_ITEMEXPANDED, TVN_ITEMEXPANDING


TVM_GETCOUNT [New - Windows NT]
TVM_GETCOUNT  QuickInfo  Overview  Group

[New - Windows NT]

TVM_GETCOUNT

wParam = 0;

lParam = 0;

// Corresponding macro

UINT TreeView_GetCount(hwnd);

The TVM_GETCOUNT message retrieves a count of the items in a tree-view control. You can send this message explicitly or by using the TreeView_GetCount macro.

Parameters

hwnd

Handle to the tree-view control.

Return Value

Returns the count of items.


TVM_GETEDITCONTROL [New - Windows NT]
TVM_GETEDITCONTROL  QuickInfo  Overview  Group

[New - Windows NT]

TVM_GETEDITCONTROL

wParam = 0;

lParam = 0;

// Corresponding macro

HWND TreeView_GetEditControl(hwnd);

The TVM_GETEDITCONTROL message retrieves the handle to the edit control being used to edit a tree-view item's text. You can send this message explicitly or by using the TreeView_GetEditControl macro.

Parameters

hwnd

Handle to the tree-view control.

Return Value

Returns the handle to the edit control if successful or NULL otherwise.


TVM_GETIMAGELIST [New - Windows NT]
TVM_GETIMAGELIST  QuickInfo  Overview  Group

[New - Windows NT]

TVM_GETIMAGELIST

wParam = (WPARAM) iImage;

lParam = 0;

// Corresponding macro

HIMAGELIST TreeView_GetImageList(hwnd, iImage);

The TVM_GETIMAGELIST message retrieves the handle to the normal or state image list associated with a tree-view control. You can send this message explicitly or by using the TreeView_GetImageList macro.

Parameters

hwnd

Handle to the image list.

iImage

Type of image list to retrieve. This parameter can be one of the following values:

Value	Meaning
TVSIL_NORMAL	Retrieves the normal image list, which contains the selected and unselected images for the tree-view item.
TVSIL_STATE	Retrieves the state image list, which contains the images for tree-view items that are in a user-defined state.
Return Value

Returns the handle to the image list.


TVM_GETINDENT [New - Windows NT]
TVM_GETINDENT  QuickInfo  Overview  Group

[New - Windows NT]

TV_GETINDENT

wParam = 0;

lParam = 0;

// Corresponding macro

UINT TreeView_GetIndent(hwnd);

The TVM_GETINDENT message retrieves the amount, in pixels, that child items are indented relative to their parent items. You can send this message explicitly or by using the TreeView_GetIndent macro.

Parameters

hwnd

Handle to the tree-view control.

Return Value

Returns the amount of indentation.


TVM_GETISEARCHSTRING [New - Windows NT]
TVM_GETISEARCHSTRING  QuickInfo  Overview  Group

[New - Windows NT]

TVM_GETISEARCHSTRING

wParam = 0;

lParam = (LPARAM) (LPSTR) lpsz;

// Corresponding macro

BOOL TreeView_GetISearchString(hwnd, lpsz);

The TVM_GETISEARCHSTRING message retrieves the incremental search string for a tree-view control. The tree-view control uses the incremental search string to select an item based on characters typed by the user.

Parameters

hwnd

Handle to the tree-view control.

lpsz

Pointer to the buffer that receives the incremental search string.

Return Value

Returns the number of characters in the incremental search string.

If the tree-view control is not in incremental search mode, the return value is zero.


TVM_GETITEM [New - Windows NT]
TVM_GETITEM  QuickInfo  Overview  Group

[New - Windows NT]

TVM_GETITEM

wParam = 0;

lParam = (LPARAM) (TV_ITEM FAR*) pitem;

// Corresponding macro

BOOL TreeView_GetItem(hwnd, pitem);

The TVM_GETITEM message retrieves some or all of a tree-view item's attributes. You can send this message explicitly or by using the TreeView_GetItem macro.

Parameters

hwnd

Handle to the tree-view control.

pitem

Pointer to a TV_ITEM structure that specifies the information to retrieve and receives information about the item. When the message is sent, the hItem member identifies the item to retrieve information about and the mask member specifies the attributes to retrieve.

If mask specifies the TVIF_TEXT value, the pszText member must contain the pointer to the buffer that receives the item text and the cchTextMax member must specify the size of the buffer.

If mask specifies the TVIF_STATE value, the stateMask member indicates which item states are to be returned.

Return Value

Returns TRUE if successful or FALSE otherwise.

See Also

TV_ITEM


TVM_GETITEMRECT [New - Windows NT]
TVM_GETITEMRECT  QuickInfo  Overview  Group

[New - Windows NT]

TVM_GETITEMRECT

wParam = (WPARAM) (BOOL) fItemRect;

lParam = (LPARAM) (RECT FAR*) prc;

// Corresponding macro

BOOL TreeView_GetItemRect(hwnd, hitem, prc, fItemRect);

The TVM_GETITEMRECT message retrieves the bounding rectangle for a tree-view item and indicates whether the item is visible. You can send this message explicitly or by using the TreeView_GetItemRect macro.

Parameters

hwnd and hitem

Handle to the tree-view control, and the handle to the item.

prc

Pointer to a RECT structure that receives the bounding rectangle. The coordinates are relative to the upper-left corner of the tree-view control.

fItemRect

Value specifying the portion of the item for which to retrieve the bounding rectangle. If this parameter is TRUE, the bounding rectangle includes only the text of the item. Otherwise, it includes the entire line that the item occupies in the tree-view control.

Return Value

If the item is visible and retrieves the bounding rectangle, the return value is TRUE. Otherwise, the message returns FALSE and does not retrieve the bounding rectangle.

See Also

RECT


TVM_GETNEXTITEM [New - Windows NT]
TVM_GETNEXTITEM  QuickInfo  Overview  Group

[New - Windows NT]

TVM_GETNEXTITEM

wParam = (WPARAM) (UINT) flag;

lParam = (LPARAM) (HTREEITEM) hitem;

// Corresponding macro

HTREEITEM TreeView_GetNextItem(hwnd, hitem, flag);

// Related macros

HTREEITEM TreeView_GetChild(hwnd, hitem);

HTREEITEM TreeView_GetDropHilite(hwnd);

HTREEITEM TreeView_GetFirstVisible(hwnd);

HTREEITEM TreeView_GetNextSibling(hwnd, hitem);

HTREEITEM TreeView_GetNextVisible(hwnd, hitem);

HTREEITEM TreeView_GetParent(hwnd, hitem);

HTREEITEM TreeView_GetPrevSibling(hwnd, hitem);

HTREEITEM TreeView_GetPrevVisible(hwnd, hitem);

HTREEITEM TreeView_GetRoot(hwnd);

HTREEITEM TreeView_GetSelection(hwnd);

Retrieves the tree-view item that bears the specified relationship to a specified item. You can send this message explicitly, or by using the TreeView_GetNextItem macro or one of the related macros.

Parameters

hwnd and hitem

Handle to the tree-view control, and the handle to an item.

flag

Flag specifying the item to retrieve. This parameter can be one of the following values:

Value	Message
TVGN_CARET	Retrieves the currently selected item.
TVGN_CHILD	Retrieves the first child item. The hitem parameter must be NULL.
TVGN_DROPHILITE	Retrieves the item that is the target of a drag-and-drop operation.
TVGN_FIRSTVISIBLE	Retrieves the first visible item.
TVGN_NEXT	Retrieves the next sibling item.
TVGN_NEXTVISIBLE	Retrieves the next visible item that follows the specified item. The specified item must be visible. Use the TVM_GETITEMRECT message to determine whether an item is visible.
TVGN_PARENT	Retrieves the parent of the specified item.
TVGN_PREVIOUS	Retrieves the previous sibling item.
TVGN_PREVIOUSVISIBLE	Retrieves the first visible item that precedes the specified item. The specified item must be visible. Use the TVM_GETITEMRECT message to determine whether an item is visible.
TVGN_ROOT	Retrieves the topmost or very first item of the tree-view control.
Return Value

Returns the handle to the item if successful or NULL otherwise.

See Also

TVM_GETITEMRECT


TVM_GETVISIBLECOUNT [New - Windows NT]
TVM_GETVISIBLECOUNT  QuickInfo  Overview  Group

[New - Windows NT]

TVM_GETVISIBLECOUNT

wParam = 0;

lParam = 0;

// Corresponding macro

UINT TreeView_GetVisibleCount(hwnd);

The TVM_GETVISIBLECOUNT message obtains the number of items that are fully visible in the client window of a tree-view control. You can send this message explicitly, or by using the TreeView_GetVisibleCount macro.

Parameters

hwnd

Handle to the tree-view control.

Return Value

Returns the number of items that are fully visible in the client window of the tree-view control.

Remarks

Note that the return value is the number of fully-visible items. If you can see all of 20 items, and part of one more item, the return value is 20, not 21.


TVM_HITTEST [New - Windows NT]
TVM_HITTEST  QuickInfo  Overview  Group

[New - Windows NT]

TV_HITTEST

wParam = 0;

lParam = (LPARAM) (LPTV_HITTESTINFO) lpht;

// Corresponding macro

HTREEITEM TreeView_HitTest(hwnd, lpht);

The TVM_HITTEST message determines the location of the specified point relative to the client area of a tree-view control. You can send this message explicitly or by using the TreeView_HitTest macro.

Parameters

hwnd

Handle to the tree-view control.

lpht

Pointer to a TV_HITTESTINFO structure. When the message is sent, the pt member specifies the coordinates of the point to test. When the message returns, the hItem member is the handle to the item at the specified point or NULL if no item occupies the point. Also, when the message returns, the flags member is a hit-test value that indicates the location of the specified point. For a list of hit-test values, see the description of the TV_HITTESTINFO structure.

Return Value

Returns the handle to the tree-view item that occupies the specified point or NULL if no item occupies the point.

See Also

TV_HITTESTINFO


TVM_INSERTITEM [New - Windows NT]
TVM_INSERTITEM  QuickInfo  Overview  Group

[New - Windows NT]

TVM_INSERTITEM

wParam = 0;

lParam = (LPARAM) (LPTV_INSERTSTRUCT) lpis;

// Corresponding macro

HTREEITEM TreeView_InsertItem(hwnd, lpis);

The TVM_INSERTITEM message inserts a new item in a tree-view control. You can send this message explicitly or by using the TreeView_InsertItem macro.

Parameters

hwnd

Handle to the tree-view control.

lpis

Pointer to a TV_INSERTSTRUCT structure that specifies the attributes of the tree-view item.

If the item label is being edited, the edit operation is canceled and the parent window receives the TVN_ENDLABELEDIT notification message.

Return Value

Returns the handle to the new item if successful or NULL otherwise.

See Also

TV_INSERTSTRUCT, TVN_ENDLABELEDIT


TVM_SELECTITEM [New - Windows NT]
TVM_SELECTITEM  QuickInfo  Overview  Group

[New - Windows NT]

TV_SELECTITEM

wParam = (WPARAM) flag;

lParam = (LPARAM) (HTREEITEM) hitem;

// Corresponding macro

BOOL TreeView_Select(hwnd, hitem, flag);

// Related macros

BOOL TreeView_SelectDropTarget(hwnd, hitem);

BOOL TreeView_SelectItem(hwnd, hitem);

BOOL TreeView_SelectSetFirstVisible(hwnd, hitem);

The TVM_SELECTITEM message selects the specified tree-view item, scrolls the item into view, or redraws the item in the style used to indicate the target of a drag-and-drop operation. You can send this message explicitly or by using the TreeView_Select, TreeView_SelectItem, or TreeView_SelectDropTarget macro.

Parameters

hwnd and hitem

Handle to the tree-view control, and the handle to an item. If hitem is NULL, the selection is removed from the currently selected item, if any.

flag

Action flag. This parameter can be one of the following values:

Value	Meaning
TVGN_CARET	Sets the selection to the given item.
TVGN_DROPHILITE	Redraws the given item in the style used to indicate the target of a drag and drop operation.
TVGN_FIRSTVISIBLE	Scrolls the tree view vertically so that the given item is the first visible item.
Return Value

Returns TRUE if successful or FALSE otherwise.

Remarks

If the TVGN_CARET value is specified, the parent window receives the TVN_SELCHANGING and TVN_SELCHANGED notification messages. Also, if the specified item is the child of a collapsed parent item, the parent's list of child items is expanded to reveal the specified item. In this case, the parent window receives the TVN_ITEMEXPANDING and TVN_ITEMEXPANDED notification messages.

Using the TreeView_SelectItem macro is equivalent to sending the TVM_SELECTITEM message with flag set to the TVGN_CARET value. Using the TreeView_SelectDropTarget macro is equivalent to sending the TVM_SELECTITEM message with flag set to the TVGN_DROPHILITE value. Using TreeView_SelectSetFirstVisible is equivalent to sending the TVM_SELECTITEM message with flag set to the TVGN_FIRSTVISIBLE value.

See Also

TVN_ITEMEXPANDED, TVN_ITEMEXPANDING, TVN_SELCHANGED, TVN_SELCHANGING


TVM_SETIMAGELIST [New - Windows NT]
TVM_SETIMAGELIST  QuickInfo  Overview  Group

[New - Windows NT]

TVM_SETIMAGELIST

wParam = (WPARAM) iImage;

lParam = (LPARAM) (HIMAGELIST) himl;

// Corresponding macro

HIMAGELIST TreeView_SetImageList(hwnd, himl, iImage);

The TVM_SETIMAGELIST message sets the normal or state image list for a tree-view control and redraws the control using the new images. You can send this message explicitly or by using the TreeView_SetImageList macro.

Parameters

hwnd and himl

Handle to the tree-view control, and the handle to the image list. If himl is NULL, all images are removed from the tree-view control.

iImage

Type of image list to set. For a list of possible values, see the description of the TVM_GETIMAGELIST message.

Return Value

Returns the handle to the previous image list, if any, or NULL otherwise.

See Also

TVM_GETIMAGELIST


TVM_SETINDENT [New - Windows NT]
TVM_SETINDENT  QuickInfo  Overview  Group

[New - Windows NT]

TVM_SETINDENT

wParam = (WPARAM) indent;

lParam = 0;

// Corresponding macro

BOOL TreeView_SetIndent(hwnd, indent);

The TVM_SETINDENT message sets the width of indentation for a tree-view control and redraws the control to reflect the new width. You can send this message explicitly or by using the TreeView_SetIndent macro.

Parameters

hwnd

Handle to the tree-view control.

indent

Width, in pixels, of the indentation. If this parameter is less than the system-defined minimum width, the new width is set to the system-defined minimum.

Return Value

No return value.


TVM_SETITEM [New - Windows NT]
TVM_SETITEM  QuickInfo  Overview  Group

[New - Windows NT]

TVM_SETITEM

wParam = 0;

lParam = (LPARAM) (const TV_ITEM FAR*) pitem;

// Corresponding macro

BOOL TreeView_SetItem(hwnd, pitem);

The TVM_SETITEM sets some or all of a tree-view item's attributes. You can send this message explicitly or by using the TreeView_SetItem macro.

Parameters

hwnd

Handle to the tree-view control.

pitem

Pointer to a TV_ITEM structure that contains the new item attributes. The hItem member identifies the item, and the mask member specifies which attributes to set.

If mask specifies the TVIF_TEXT value, the pszText member is the pointer to a null-terminated string and the cchTextMax member is ignored.

If mask specifies the TVIF_STATE value, the stateMask member indicates which item states to change and the state member contains the values for those states.

Return Value

Returns zero if successful or  − 1 otherwise.

See Also

TV_ITEM


TVM_SORTCHILDREN [New - Windows NT]
TVM_SORTCHILDREN  QuickInfo  Overview  Group

[New - Windows NT]

TVM_SORTCHILDREN

wParam = 0;  // reserved for future use; must be zero

lParam = (LPARAM) (HTREEITEM) hitem;

// Corresponding macro

BOOL TreeView_SortChildren(hwnd, hitem, fRecurse);

The TVM_SORTCHILDREN message sorts the child items of the specified parent item in a tree-view control. You can send this message explicitly or by using the TreeView_SortChildren macro.

Parameters

hwnd and hitem

Handle to the tree-view control, and the handle to the parent item whose child items are to be sorted.

fRecurse

Reserved for future use. Must be zero.

Return Value

Returns TRUE if successful or FALSE otherwise.


TVM_SORTCHILDRENCB [New - Windows NT]
TVM_SORTCHILDRENCB  QuickInfo  Overview  Group

[New - Windows NT]

TVM_SORTCHILDRENCB

wParam = 0;  // reserved for future use; must be zero

lParam = (LPARAM) (LPTV_SORTCB) psort;

// Corresponding macro

BOOL TreeView_SortChildrenCB(hwnd, psort, fRecurse);

The TVM_SORTCHILDRENCB message sorts tree-view items using an application-defined callback function that compares the items. You can send this message explicitly or by using the TreeView_SortChildrenCB macro.

Parameters

hwnd

Handle to the tree-view control.

psort

Pointer to a TV_SORTCB structure. The lpfnCompare member is the pointer to the application-defined callback function, which is called during the sort operation each time the relative order of two list items needs to be compared. For more information about the callback function, see the description of TV_SORTCB.

fRecurse

Reserved for future use. Must be zero.

Return Value

Returns TRUE if successful or FALSE otherwise.

See Also

TV_SORTCB


TVN_BEGINDRAG [New - Windows NT]
TVN_BEGINDRAG  QuickInfo  Overview  Group

[New - Windows NT]

TVN_BEGINDRAG

pnmtv = (NM_TREEVIEW FAR *) lParam

The TVN_BEGINDRAG notification message notifies a tree-view control's parent window that a drag-and-drop operation involving the left mouse button is being initiated. This notification message is sent in the form of a WM_NOTIFY message.

Parameters

pnmtv

Pointer to an NM_TREEVIEW structure. The itemNew member is a TV_ITEM structure that contains valid information about the item being dragged in the hItem, state, and lParam members. The ptDrag member specifies the current screen coordinates of the mouse.

Return Value

No return value.

Remarks

A tree-view control that has the TVS_DISABLEDRAGDROP style does not send this notification message.

See Also

NM_TREEVIEW, TV_ITEM, WM_NOTIFY


TVN_BEGINLABELEDIT [New - Windows NT]
TVN_BEGINLABELEDIT  QuickInfo  Overview  Group

[New - Windows NT]

TVN_BEGINLABELEDIT

ptvdi = (TV_DISPINFO FAR *) lParam

The TVN_BEGINLABELEDIT notification message notifies a tree-view control's parent window about the start of label editing for an item. This notification message is sent in the form of a WM_NOTIFY message.

Parameters

ptvdi

Pointer to a TV_DISPINFO structure. The item member is a TV_ITEM structure that contains valid information about the item being edited in the hItem, state, lParam, and pszText members.

Return Value

Returns TRUE to cancel label editing.

See Also

TV_DISPINFO, TV_ITEM, WM_NOTIFY


TVN_BEGINRDRAG [New - Windows NT]
TVN_BEGINRDRAG  QuickInfo  Overview  Group

[New - Windows NT]

TVN_BEGINRDRAG

pnmtv = (NM_TREEVIEW FAR *) lParam

The TVN_BEGINRDRAG notification message notifies a tree-view control's parent window about the initiation of a drag-and-drop operation involving the right mouse button. This notification message is sent in the form of a WM_NOTIFY message.

Parameters

pnmtv

Pointer to an NM_TREEVIEW structure. The itemNew member is a TV_ITEM structure that contains valid information in the hItem, state, and lParam members about the item to be dragged. The ptDrag member specifies the current screen coordinates of the mouse.

Return Value

No return value.

See Also

NM_TREEVIEW, TV_ITEM, WM_NOTIFY


TVN_DELETEITEM [New - Windows NT]
TVN_DELETEITEM  QuickInfo  Overview  Group

[New - Windows NT]

TVN_DELETEITEM

pnmtv = (NM_TREEVIEW FAR *) lParam

The TVN_DELETEITEM notification message notifies a tree-view control's parent window that an item has been deleted. This notification message is sent in the form of a WM_NOTIFY message.

Parameters

pnmtv

Pointer to an NM_TREEVIEW structure. The itemOld member is a TV_ITEM structure containing valid information about the item that was deleted in the hItem and lParam members.

Return Value

No return value.

See Also

NM_TREEVIEW, TV_ITEM, WM_NOTIFY


TVN_ENDLABELEDIT [New - Windows NT]
TVN_ENDLABELEDIT  QuickInfo  Overview  Group

[New - Windows NT]

TVN_ENDLABELEDIT

ptvdi = (TV_DISPINFO FAR *) lParam

The TVN_ENDLABELEDIT notification message notifies a tree-view control's parent window about the end of label editing for an item. This notification message is sent in the form of a WM_NOTIFY message.

Parameters

ptvdi

Pointer to a TV_DISPINFOstructure. The item member is a TV_ITEM structure containing valid information about the item that was edited in the hItem, lParam, and pszText members. If label editing was canceled, the pszText member is zero.

Return Value

No return value.

See Also

WM_NOTIFY, TV_DISPINFO, TV_ITEM


TVN_GETDISPINFO [New - Windows NT]
TVN_GETDISPINFO  QuickInfo  Overview  Group

[New - Windows NT]

TVN_GETDISPINFO

ptvdi = (TV_DISPINFO FAR *) lParam

The TVN_GETDISPINFO notification message requests that a tree-view control's parent window provide information needed to display or sort an item. This notification message is sent in the form of a WM_NOTIFY message.

Parameters

ptvdi

Pointer to a TV_DISPINFO structure. The item member is a TV_ITEM structure whose mask, hItem, state, and lParam members specify the type of information required. You must fill the members of the structure with the appropriate information.

Return Value

No return value.

Remarks

See Also

TV_DISPINFO, TV_ITEM, WM_NOTIFY


TVN_ITEMEXPANDED [New - Windows NT]
TVN_ITEMEXPANDED  QuickInfo  Overview  Group

[New - Windows NT]

TVN_ITEMEXPANDED

pnmtv = (NM_TREEVIEW FAR *) lParam

The TVN_ITEMEXPANDED notification message notifies a tree-view control's parent window that a parent item's list of child items has expanded or collapsed. This notification message is sent in the form of a WM_NOTIFY message.

Parameters

pnmtv

Pointer to an NM_TREEVIEW structure. The itemNew member is a TV_ITEM structure that contains valid information about the parent item in the hItem, state, and lParam members. The action member indicates whether the list expanded or collapsed. For a list of possible values, see the description of the TVM_EXPAND message.

Return Value

No return value.

See Also

NM_TREEVIEW, TV_ITEM, TVM_EXPAND, WM_NOTIFY


TVN_ITEMEXPANDING [New - Windows NT]
TVN_ITEMEXPANDING  QuickInfo  Overview  Group

[New - Windows NT]

TVN_ITEMEXPANDING

pnmtv = (NM_TREEVIEW FAR *) lParam

The TVN_ITEMEXPANDING notification message notifies a tree-view control's parent window that a parent item's list of child items is about to expand or collapse. This notification message is sent in the form of a WM_NOTIFY message.

Parameters

pnmtv

Pointer to an NM_TREEVIEW structure. The itemNew member is a TV_ITEM structure that contains valid information about the parent item in the hItem, state, and lParam members. The action member indicates whether the list is to expand or collapse. For a list of possible values, see the description of the TVM_EXPAND message.

Return Value

Returns TRUE to prevent the list from expanding or collapsing.

See Also

NM_TREEVIEW, TV_ITEM, TVM_EXPAND, WM_NOTIFY


TVN_KEYDOWN [New - Windows NT]
TVN_KEYDOWN  QuickInfo  Overview  Group

[New - Windows NT]

TVN_ITEMEXPANDING

ptvkd = (TV_KEYDOWN FAR *) lParam

The TVN_KEYDOWN notification message notifies a tree-view control's parent window that the user pressed a key and the tree-view control has the input focus. This notification message is sent in the form of a WM_NOTIFY message.

Parameters

ptvkd

Pointer to a TV_KEYDOWN structure. The wVKey member specifies the virtual-key code.

Return Value

No return value.

See Also

TV_KEYDOWN, WM_NOTIFY


TVN_SELCHANGED [New - Windows NT]
TVN_SELCHANGED  QuickInfo  Overview  Group

[New - Windows NT]

TVN_SELCHANGED

pnmtv = (NM_TREEVIEW FAR *) lParam

The TVN_SELCHANGED notification message notifies a tree-view control's parent window that the selection has changed from one item to another. This notification message is sent in the form of a WM_NOTIFY message.

Parameters

pnmtv

Pointer to an NM_TREEVIEW structure. The itemOld and itemNew members are TV_ITEM structures that contain information about the previously selected item and the newly selected items in the hItem, state, and lParam members. The stateMask members in the TV_ITEM structures specified by itemOld and itemNew are undefined on input. The action member indicates the type of action that caused the selection to change; it can be one of the following values:

Value	Meaning
TVC_BYKEYBOARD	By a key stroke
TVC_BYMOUSE	By a mouse click
TVC_UNKNOWN	Unknown
Return Value

No return value.

See Also

NM_TREEVIEW, WM_NOTIFY


TVN_SELCHANGING [New - Windows NT]
TVN_SELCHANGING  QuickInfo  Overview  Group

[New - Windows NT]

TVN_SELCHANGING

pnmtv = (NM_TREEVIEW FAR *) lParam

The TVN_SELCHANGING notification message notifies a tree-view control's parent window that the selection is about to change from one item to another. This notification message is sent in the form of a WM_NOTIFY message.

Parameters

pnmtv

Pointer to an NM_TREEVIEW structure. The itemOld and itemNew members contain valid information about the currently selected item and the newly selected item. The action member indicates whether a mouse or keyboard action is causing the selection to change. For a list of possible values, see the description of the TVN_SELCHANGED notification message.

Return Value

Returns TRUE to prevent the selection from changing.

See Also

NM_TREEVIEW, TVN_SELCHANGED, WM_NOTIFY


TVN_SETDISPINFO [New - Windows NT]
TVN_SETDISPINFO  QuickInfo  Overview  Group

[New - Windows NT]

TVN_SETDISPINFO

ptvdi = (TV_DISPINFO FAR *) lParam

The TVN_SETDISPINFO notification message notifies a tree-view control's parent window that it must update the information it maintains about an item. This notification message is sent in the form of a WM_NOTIFY message.

Parameters

ptvdi

Pointer to a TV_DISPINFO structure. The item member is a TV_ITEM structure that contains valid information about the item in the hItem and lParam members.

Return Value

No return value.

Remarks

The system sends this notification message when the user has finished editing the label of an item whose text is set to LPSTR_TEXTCALLBACK. The notification gives the parent window the opportunity to store the new item text.

See Also

TV_DISPINFO, TV_ITEM, WM_NOTIFY


UDM_GETACCEL [New - Windows NT]
UDM_GETACCEL  QuickInfo  Overview  Group

[New - Windows NT]

UDM_GETACCEL

wParam = (WPARAM) cAccels;

lParam = (LPARAM) (LPUDACCEL) paAccels;

The UDM_GETACCEL message retrieves acceleration information for an up-down control.

Parameters

cAccels

Number of elements in the array specified by paAccels.

paAccels

Address of an array of UDACCEL structures that receives acceleration information.

Return Value

The return value is the number of accelerator structures retrieved.

See Also

UDACCEL


UDM_GETBASE [New - Windows NT]
UDM_GETBASE  QuickInfo  Overview  Group

[New - Windows NT]

UDM_GETBASE

wParam = 0;

lParam = 0;

The UDM_GETBASE message retrieves the current radix base (that is, either base 10 or 16) for an up-down control.

Return Value

The return value is the current base value.


UDM_GETBUDDY [New - Windows NT]
UDM_GETBUDDY  QuickInfo  Overview  Group

[New - Windows NT]

UDM_GETBUDDY

wParam = 0;

lParam = 0;

The UDM_GETBUDDY message retrieves the handle of the current buddy window.

Return Value

The return value is the handle of the current buddy window.


UDM_GETPOS [New - Windows NT]
UDM_GETPOS  QuickInfo  Overview  Group

[New - Windows NT]

UDM_GETPOS

wParam = 0;

lParam = 0;

The UDM_GETPOS message retrieves the current position of an up-down control.

Return Value

The return value is the current position in the low-order word. If an error occurred, the high-order word is nonzero.

Remarks

When processing this message, the up-down control updates its current position based on the caption of the buddy window. The up-down control returns an error if there is no buddy window or if the caption specifies an invalid or out-of-range value.


UDM_GETRANGE [New - Windows NT]
UDM_GETRANGE  QuickInfo  Overview  Group

[New - Windows NT]

UDM_GETRANGE

wParam = 0;

lParam = 0;

The UDM_GETRANGE message retrieves the minimum and maximum positions (range) for an up-down control.

Return Value

The return value is a 32-bit value that contains the minimum and maximum positions. The low-order word is the maximum position for the control, and the high-order word is the minimum position.


UDM_SETACCEL [New - Windows NT]
UDM_SETACCEL  QuickInfo  Overview  Group

[New - Windows NT]

UDM_SETACCEL

wParam = (WPARAM) nAccels;

lParam = (LPARAM) (LPUDACCEL) aAccels;

The UDM_SETACCEL message sets the acceleration for an up-down control.

Parameters

nAccels

Number of UDACCEL structures specified by aAccels.

aAccels

Address of an array of UDACCEL structures that contains acceleration information. Elements should be sorted in ascending order based on the nSec member.

Return Value

Returns TRUE if successful or FALSE otherwise.

See Also

UDACCEL


UDM_SETBASE [New - Windows NT]
UDM_SETBASE  QuickInfo  Overview  Group

[New - Windows NT]

UDM_SETBASE

wParam = (WPARAM) nBase;

lParam = 0;

The UDM_SETBASE message sets the radix base for an up-down control. The base value determines whether the buddy window displays numbers in decimal or hexadecimal digits. Hexadecimal numbers are always unsigned, and decimal numbers are signed.

Parameters

nBase

New base value for the control. This parameter can be 10 for decimal or 16 for hexadecimal.

Return Value

The return value is the previous base value. If an invalid base is given, the return value is zero.


UDM_SETBUDDY [New - Windows NT]
UDM_SETBUDDY  QuickInfo  Overview  Group

[New - Windows NT]

UDM_SETBUDDY

wParam = (WPARAM) (HWND) hwndBuddy;

lParam = 0;

The UDM_SETBUDDY message sets the buddy window for an up-down control.

Parameters

hwndBuddy

Handle of the new buddy window.

Return Value

The return value is the handle of the previous buddy window.


UDM_SETPOS [New - Windows NT]
UDM_SETPOS  QuickInfo  Overview  Group

[New - Windows NT]

UDM_SETPOS

wParam = 0;

lParam = (LPARAM) MAKELONG((short) nPos, 0);

The UDM_SETPOS message sets the current position for an up-down control.

Parameters

nPos

New position for the up-down control. This parameter must be in the range specified by the upper and lower limits for the control.

Return Value

The return value is the previous position.


UDM_SETRANGE [New - Windows NT]
UDM_SETRANGE  QuickInfo  Overview  Group

[New - Windows NT]

UDM_SETRANGE

wParam = 0;

lParam = (LPARAM) MAKELONG((short) nUpper, (short) nLower);

The UDM_SETRANGE message sets the minimum and maximum positions (range) for an up-down control.

Parameters

nUpper and nLower

Maximum position and minimum position for the up-down control. Neither position can be greater than the UD_MAXVAL value or less than the UD_MINVAL value. In addition, the difference between the two positions cannot exceed UD_MAXVAL.

Return Value

No return value.

Remarks

The maximum position can be less than the minimum position. Clicking the up arrow moves the current position closer to the maximum position, and clicking the down arrow moves towards the minimum position.


UDN_DELTAPOS [New - Windows NT]
UDN_DELTAPOS  Overview  Group

[New - Windows NT]

UDN_DELTAPOS

pnmud = (NM_UPDOWN FAR *) lParam

The operating system sends the UDN_DELTAPOS notification message to the parent window of an up-down control when the position of the control is about to change. This happens when the user requests a change in the value by pressing the control's up or down arrow. The UDN_DELTAPOS message is sent before the WM_VSCROLL message that actually changes the control's position. This lets you examine, allow, modify, or disallow the change. The UDN_DELTAPOS message is sent in the form of a WM_NOTIFY message.

Parameters

pnmud

Pointer to an NM_UPDOWN structure that contains information about the position change.

The iPos member of this structure contains the current position of the control.

The iDelta member of the structure is a signed integer that contains the proposed change in position. If the user has clicked on the up button, this is a positive value. If the user has clicked on the down button, this is a negative value.

Return Value

Return TRUE in response to this message to prevent the change in the control's position.

Return FALSE to allow the change in the control's position.

See Also

NM_UPDOWN, WM_COMMAND, WM_VSCROLL


WM_ACTIVATE
WM_ACTIVATE  QuickInfo  Overview  Group

WM_ACTIVATE

fActive = LOWORD(wParam);           // activation flag

fMinimized = (BOOL) HIWORD(wParam); // minimized flag

hwnd = (HWND) lParam;               // window handle

The WM_ACTIVATE message is sent when a window is being activated or deactivated. This message is sent first to the window procedure of the top-level window being deactivated; it is then sent to the window procedure of the top-level window being activated.

Parameters

fActive

Value of the low-order word of wParam. Specifies whether the window is being activated or deactivated. This parameter can be one of the following values:

Value	Meaning
WA_ACTIVE	Activated by some method other than a mouse click (for example, by a call to the SetActiveWindow function or by use of the keyboard interface to select the window).
WA_CLICKACTIVE	Activated by a mouse click.
WA_INACTIVE	Deactivated.
fMinimized

Value of the high-order word of wParam. Specifies the minimized state of the window being activated or deactivated. A nonzero value indicates the window is minimized.

hwnd

Value of lParam. Identifies the window being activated or deactivated, depending on the value of the fActive parameter. If the value of fActive is WA_INACTIVE, hwnd is the handle of the window being activated. If the value of fActive is WA_ACTIVE or WA_CLICKACTIVE, hwnd is the handle of the window being deactivated. This handle can be NULL.

Return Value

If an application processes this message, it should return zero.

Default Action

If the window is being activated and is not minimized, the DefWindowProc function sets the keyboard focus to the window.

Remarks

If the window is activated by a mouse click, it also receives a WM_MOUSEACTIVATE message.

See Also

DefWindowProc, SetActiveWindow, WM_MOUSEACTIVATE, WM_NCACTIVATE


WM_ACTIVATEAPP
WM_ACTIVATEAPP  QuickInfo  Overview  Group

WM_ACTIVATEAPP

fActive = (BOOL) wParam;        // activation flag

dwThreadID = (DWORD) lParam:    // thread identifier

The WM_ACTIVATEAPP message is sent when a window belonging to a different application than the active window is about to be activated. The message is sent to the application whose window is being activated and to the application whose window is being deactivated.

Parameters

fActive

Value of wParam. Specifies whether the window is being activated or deactivated. This parameter is TRUE if the window is being activated; it is FALSE if the window is being deactivated.

dwThreadID

Value of lParam. Specifies a thread identifier. If the fActive parameter is TRUE, dwThreadID is the identifier of the thread that owns the window being deactivated. If fActive is FALSE, dwThreadID is the identifier of the thread that owns the window being activated.

Return Value

If an application processes this message, it should return zero.

See Also

WM_ACTIVATE


WM_ASKCBFORMATNAME
WM_ASKCBFORMATNAME  QuickInfo  Overview  Group

WM_ASKCBFORMATNAME

cchName = (DWORD) wParam            // size of buffer

lpszFormatName = (LPTSTR) lParam    // buffer to receive format name

The WM_ASKCBFORMATNAME message is sent to the clipboard owner by a clipboard viewer window to request the name of a CF_OWNERDISPLAY clipboard format.

Parameters

cchName

Value of wParam. Specifies the size, in characters, of the buffer pointed to by the lpszFormatName parameter.

lpszFormatName

Value of lParam. Points to the buffer that is to receive the clipboard format name.

Return Value

If an application processes this message, it should return zero.

Remarks

In response to this message, the clipboard owner should copy the name of the owner-display format to the specified buffer, not exceeding the buffer size specified by the cchName parameter.

A clipboard viewer window sends this message to the clipboard owner to determine the name of the CF_OWNERDISPLAY format — for example, to initialize a menu listing available formats.


WM_CANCELJOURNAL
WM_CANCELJOURNAL  QuickInfo

WM_CANCELJOURNAL

wParam = 0; // not used, must be zero

lParam = 0; // not used, must be zero

The WM_CANCELJOURNAL message is posted to an application when a user cancels the application's journaling activities. The message is posted with a NULL window handle.

Parameters

This message has no parameters.

Return Value

This message does not return a value. It is meant to be processed from within an application's main loop or a GetMessage hook procedure, not from a window procedure.

Remarks

Journal record and playback modes are modes imposed on the system that let an application sequentially record or play back user input. The system enters these modes when an application installs a JournalRecordProc or JournalPlaybackProc hook procedure. When the system is in either of these journaling modes, applications must take turns reading input from the input queue. If any one application stops reading input while the system is in a journaling mode, other applications are forced to wait.

To ensure a robust system, one that cannot be hung up by any one application, Windows NT automatically cancels any journalling activities when a user presses CTRL+ESC, ALT+ESC, or CTRL+ALT+DEL. The system then unhooks any journaling hook procedures, and posts a WM_CANCELJOURNAL message, with a NULL window handle, to the application that set the journaling hook.

Since the WM_CANCELJOURNAL has a NULL window handle, it cannot be dispatched to a window procedure. There are two ways for an application to see a WM_CANCELJOURNAL message: If the application is running in its own main loop, it must catch the message between its call to GetMessage or PeekMessage and its call to DispatchMessage. If the application is not running in its own main loop, it must set a GetMsgProc hook procedure (via a call to SetWindowsHookEx specifying the WH_GETMESSAGE hook type) that watches for the message.

When an application sees a WM_CANCELJOURNAL message, it can assume two things: the user has intentionally cancelled the journal record or playback mode, and the system has already unhooked any journal record or playback hook procedures.

Note that the key combinations mentioned above (CTRL+ESC, ALT+ESC, or CTRL+ALT+DEL) cause the system to cancel journaling. If any one application is hung, they give the user a means of recovery. The VK_CANCEL virtual keycode (usually implemented as the CTRL+BREAK key combination) is what an application that is in journal record mode should watch for as a signal that the user wishes to cancel the journaling activity. The difference is that watching for VK_CANCEL is a suggested behavior for journaling applications, whereas CTRL+ESC, ALT+ESC, or CTRL+ALT+DEL cause the system to cancel journalling regardless of a journalling application's behavior.

See Also

DispatchMessage, GetMessage, JournalPlaybackProc, JournalRecordProc, GetMsgProc, PeekMessage, SetWindowsHookEx


WM_CANCELMODE
WM_CANCELMODE  QuickInfo  Overview  Group

WM_CANCELMODE

The WM_CANCELMODE message is sent to the focus window when a dialog box or message box is displayed; this enables the focus window to cancel modes, such as mouse capture.

Parameters

This message has no parameters.

Return Value

If an application processes this message, it should return zero.

Default Action

The DefWindowProc function cancels internal processing of standard scroll bar input, cancels internal menu processing, and releases the mouse capture.

See Also

DefWindowProc, ReleaseCapture


WM_CAPTURECHANGED [New - Windows 95]
WM_CAPTURECHANGED  QuickInfo  Overview  Group

[New - Windows 95]

WM_CAPTURECHANGED

hwndNewCapture = (HWND) lParam;    // handle of window to gain mouse capture

The WM_CAPTURECHANGED message is sent to the window that is losing the mouse capture.

Parameters

hwndNewCapture

Value of lParam. Identifies the window that is gaining the mouse capture.

Return Value

An application should return zero if it processes this message.

Remarks

A window receives this message even if it calls ReleaseCapture itself. An application should not attempt to set the mouse capture in response to this message.

When it receives this message, a window should redraw itself, if necessary, to reflect the new mouse-capture state.

See Also

ReleaseCapture, SetCapture


WM_CHANGECBCHAIN
WM_CHANGECBCHAIN  QuickInfo  Overview  Group

WM_CHANGECBCHAIN

hwndRemove = (HWND) wParam;     // handle of window being removed

hwndNext = (HWND) lParam;       // handle of next window in chain

The WM_CHANGECBCHAIN message is sent to the first window in the clipboard viewer chain when a window is being removed from the chain.

Parameters

hwndRemove

Value of wParam. Identifies the window being removed from the clipboard viewer chain.

hwndNext

Value of lParam. Identifies the next window in the chain following the window being removed. This parameter is NULL if the window being removed is the last window in the chain.

Return Value

If an application processes this message, it should return zero.

Remarks

Each clipboard viewer window saves the handle of the next window in the clipboard viewer chain. Initially, this handle is the return value of the SetClipboardViewer function.

When a clipboard viewer window receives the WM_CHANGECBCHAIN message, it should call the SendMessage function to pass the message to the next window in the chain, unless the next window is the window being removed. In this case, the clipboard viewer should save the handle specified by hwndNext as the next window in the chain.

See Also

SendMessage, SetClipboardViewer


WM_CHAR
WM_CHAR  QuickInfo  Overview  Group

WM_CHAR

chCharCode = (TCHAR) wParam;    // character code

lKeyData = lParam;              // key data

The WM_CHAR message is posted to the window with the keyboard focus when a WM_KEYDOWN message is translated by the TranslateMessage function. WM_CHAR contains the character code of the key that was pressed.

Parameters

chCharCode

Value of wParam. Specifies the character code of the key.

lKeyData

Value of lParam. Specifies the repeat count, scan code, extended-key flag, context code, previous key-state flag, and transition-state flag, as shown in the following table:

Value	Description
0−15	Specifies the repeat count. The value is the number of times the keystroke is repeated as a result of the user holding down the key.
16−23	Specifies the scan code. The value depends on the original equipment manufacturer (OEM).
24	Specifies whether the key is an extended key, such as the right-hand ALT and CTRL keys that appear on an enhanced 101- or 102-key keyboard. The value is 1 if it is an extended key; otherwise, it is 0.
25−28	Reserved; do not use.
29	Specifies the context code. The value is 1 if the ALT key is held down while the key is pressed; otherwise, the value is 0.
30	Specifies the previous key state. The value is 1 if the key is down before the message is sent, or it is 0 if the key is up.
31	Specifies the transition state. The value is 1 if the key is being released, or it is 0 if the key is being pressed.
Return Value

An application should return zero if it processes this message.

Remarks

Because there is not necessarily a one-to-one correspondence between keys pressed and character messages generated, the information in the high-order word of the lKeyData parameter is generally not useful to applications. The information in the high-order word applies only to the most recent WM_KEYDOWN message that precedes the posting of the WM_CHAR message.

For enhanced 101- and 102-key keyboards, extended keys are the right ALT and the right CTRL keys on the main section of the keyboard; the INS, DEL, HOME, END, PAGE UP, PAGE DOWN and arrow keys in the clusters to the left of the numeric keypad; and the divide (/) and ENTER keys in the numeric keypad. Some other keyboards may support the extended-key bit in the lKeyData parameter.

See Also

TranslateMessage, WM_KEYDOWN


WM_CHARTOITEM
WM_CHARTOITEM  QuickInfo  Overview  Group

WM_CHARTOITEM

nKey = LOWORD(wParam);          // key value

nCaretPos = HIWORD(wParam);     // caret position

hwndListBox = (HWND) lParam;    // handle of list box

The WM_CHARTOITEM message is sent by a list box with the LBS_WANTKEYBOARDINPUT style to its owner in response to a WM_CHAR message.

Parameters

nKey

Value of the low-order word of wParam. Specifies the value of the key the user pressed.

nCaretPos

Value of the high-order word of wParam. Specifies the current position of the caret.

hwndListBox

Value of lParam. Identifies the list box.

Return Value

The return value specifies the action that the application performed in response to the message. A return value of −1 or −2 indicates that the application handled all aspects of selecting the item and requires no further action by the list box. A return value of 0 or greater specifies the zero-based index of an item in the list box and indicates that the list box should perform the default action for the keystroke on the given item.

Default Action

The DefWindowProc function returns −1.

Remarks

Only owner-drawn list boxes that do not have the LBS_HASSTRINGS style can receive this message.

See Also

DefWindowProc, WM_CHAR, WM_VKEYTOITEM


WM_CHILDACTIVATE
WM_CHILDACTIVATE  QuickInfo  Overview  Group

WM_CHILDACTIVATE

The WM_CHILDACTIVATE message is sent to a multiple document interface (MDI) child window when the user clicks the window's title bar or when the window is activated, moved, or sized.

Parameters

This message has no parameters.

Return Value

If an application processes this message, it should return zero.

See Also

MoveWindow, SetWindowPos


WM_CHOOSEFONT_GETLOGFONT
WM_CHOOSEFONT_GETLOGFONT  QuickInfo

WM_CHOOSEFONT_GETLOGFONT

wParam = 0;                // not used, must be zero

lParam = (LPLOGFONT) lplf; // address of struct. with font data

An application sends a WM_CHOOSEFONT_GETLOGFONT message to the Font dialog box created by the ChooseFont function to retrieve the current LOGFONT structure.

Parameters

lplf

Points to a LOGFONT structure that receives information about the current logical font.

Return Value

This message does not return a value.

Remarks

An application uses this message to retrieve the LOGFONT structure while the Font dialog box is open. When the user closes the dialog box, the ChooseFont function receives information about the LOGFONT structure.

See Also

ChooseFont, WM_GETFONT, LOGFONT


WM_CHOOSEFONT_SETFLAGS
WM_CHOOSEFONT_SETFLAGS  Overview  Group

WM_CHOOSEFONT_SETFLAGS

wParam = 0;                   // not used, must be zero

lParam = (LPCHOOSEFONT) lpcf; // address of struct. with flags data

Sent to a Font dialog box (created by the ChooseFont function) to set the display options for the dialog box.

Parameters

lpcf

Address of a CHOOSEFONT structure that contains new settings in the Flags member.

Return Value

No return value.

Remarks

This message is intended to be sent from the hook function for the Font dialog box to set display options while the dialog box is still open. The hook function, if any, is specified by the lpfnHook member of the CHOOSEFONT structure passed to ChooseFont.

See Also

ChooseFont, CHOOSEFONT


WM_CHOOSEFONT_SETLOGFONT
WM_CHOOSEFONT_SETLOGFONT  Overview  Group

WM_CHOOSEFONT_SETLOGFONT

wParam = 0;                // not used, must be zero

lParam = (LPLOGFONT) lplf; // address of struct. with font data

Sent to a Font dialog box (created by the ChooseFont function) to set the current logical font information.

Parameters

lplf

Address of a LOGFONT structure that contains information about the current logical font.

Return Value

No return value.

Remarks

This message is intended to be sent from the hook function for the Font dialog box to set the font attributes while the dialog box is still open. The hook function, if any, is specified by the lpfnHook member of the CHOOSEFONT structure passed to ChooseFont.

See Also

ChooseFont, CHOOSEFONT


WM_CLEAR
WM_CLEAR  QuickInfo

WM_CLEAR

wParam = 0; // not used; must be zero

lParam = 0; // not used; must be zero

An application sends a WM_CLEAR message to an edit control or combo box to delete (clear) the current selection, if any, from the edit control.

Parameters

This message has no parameters.

Return Value

This message does not return a value.

Remarks

The deletion performed by the WM_CLEAR message can be undone by sending the edit control an EM_UNDO message.

To delete the current selection and place the deleted content on the clipboard, use the WM_CUT message.

When sent to a combo box, the WM_CLEAR message is handled by its edit control. This message has no effect when sent to a combo box with the CBS_DROPDOWNLIST style.

See Also

EM_UNDO, WM_COPY, WM_CUT, WM_PASTE


WM_CLOSE
WM_CLOSE  QuickInfo  Overview  Group

WM_CLOSE

The WM_CLOSE message is sent as a signal that a window or an application should terminate.

Parameters

This message has no parameters.

Return Value

If an application processes this message, it should return zero.

Default Action

The DefWindowProc function calls the DestroyWindow function to destroy the window.

Remarks

An application can prompt the user for confirmation, prior to destroying a window, by processing the WM_CLOSE message and calling the DestroyWindow function only if the user confirms the choice.

See Also

DefWindowProc, DestroyWindow


WM_COMMAND
WM_COMMAND  QuickInfo  Overview  Group

WM_COMMAND

wNotifyCode = HIWORD(wParam); // notification code

wID = LOWORD(wParam);         // item, control, or accelerator identifier

hwndCtl = (HWND) lParam;      // handle of control

The WM_COMMAND message is sent when the user selects a command item from a menu, when a control sends a notification message to its parent window, or when an accelerator keystroke is translated.

Parameters

wNotifyCode

Value of the high-order word of wParam. Specifies the notification code if the message is from a control. If the message is from an accelerator, this parameter is 1. If the message is from a menu, this parameter is 0.

wID

Value of the low-order word of wParam. Specifies the identifier of the menu item, control, or accelerator.

hwndCtl

Value of lParam. Identifies the control sending the message if the message is from a control. Otherwise, this parameter is NULL.

Return Value

If an application processes this message, it should return zero.

Remarks

Accelerator keystrokes that select items from the System menu are translated into WM_SYSCOMMAND messages.

If an accelerator keystroke occurs that corresponds to a menu item when the window that owns the menu is minimized, no WM_COMMAND message is sent. However, if an accelerator keystroke occurs that does not match any of the items in the window's menu or in the System menu, a WM_COMMAND message is sent, even if the window is minimized.

If an application enables a menu separator, the system sends a WM_COMMAND message with the low-word of the wParam parameter set to zero when the user selects the separator.

See Also

WM_SYSCOMMAND


WM_COMPACTING
WM_COMPACTING  QuickInfo

WM_COMPACTING

wCompactRatio = wParam; // compacting ratio

The WM_COMPACTING message is sent to all top-level windows when Windows detects more than 12.5 percent of system time over a 30- to 60-second interval is being spent compacting memory. This indicates that system memory is low.

Parameters

wCompactRatio

Value of wParam. Specifies the ratio of central processing unit (CPU) time currently spent by Windows compacting memory to CPU time currently spent by Windows performing other operations. For example, 0x8000 represents 50 percent of CPU time spent compacting memory.

Return Value

If an application processes this message, it should return zero.

Remarks

When an application receives this message, it should free as much memory as possible, taking into account the current level of activity of the application and the total number of applications running with Windows.


WM_COMPAREITEM
WM_COMPAREITEM  QuickInfo  Overview  Group

WM_COMPAREITEM

idCtl = wParam;                       // control identifier

lpcis = (LPCOMPAREITEMSTRUCT) lParam; // structure with items

Windows sends the WM_COMPAREITEM message to determine the relative position of a new item in the sorted list of an owner-drawn combo box or list box. Whenever the application adds a new item, Windows sends this message to the owner of a combo box or list box created with the CBS_SORT or LBS_SORT style.

Parameters

idCtl

Value of wParam. Specifies the identifier of the control that sent the WM_COMPAREITEM message.

lpcis

Value of lParam. Points to a COMPAREITEMSTRUCT structure that contains the identifiers and application-supplied data for two items in the combo or list box.

Return Value

The return value indicates the relative position of the two items. It may be any of the following:

Value	Meaning
−1	Item 1 precedes item 2 in the sorted order.
0	Items 1 and 2 are equivalent in the sorted order.
1	Item 1 follows item 2 in the sorted order.
Remarks

When the owner of an owner-drawn combo box or list box receives this message, the owner returns a value indicating which of the items specified by the COMPAREITEMSTRUCT structure will appear before the other. Typically, Windows sends this message several times until it determines the exact position for the new item.

See Also

COMPAREITEMSTRUCT


WM_CONTEXTMENU [New - Windows NT]
WM_CONTEXTMENU  QuickInfo  Overview  Group

[New - Windows NT]

hwnd = (HWND) wParam;

xPos = LOWORD(lParam);

yPos = HIWORD(lParam);

The WM_CONTEXTMENU message notifies a window that the user clicked the right mouse button (right clicked) in the window.

Parameters

hwnd

Handle to the window in which the user right clicked the mouse. This can be a child window of the window receiving the message. For more information about processing this message, see the Remarks section.

xPos

Horizontal position of the cursor, in screen coordinates, at the time of the mouse click.

yPos

Vertical position of the cursor, in screen coordinates, at the time of the mouse click.

Return Value

No return value.

Remarks

A window can process this message by displaying a context menu using the TrackPopupMenu or TrackPopupMenuEx function.

If a window does not display a context menu it should pass this message to the DefWindowProc function. If a window is a child window, DefWindowProc sends the message to the parent. Otherwise, DefWindowProc displays a default context menu if the specified position is in the window's caption.

DefWindowProc generates the WM_CONTEXTMENU message when it processes the WM_RBUTTONUP or WM_NCRBUTTONUP message.

See Also

DefWindowProc, TrackPopupMenu, TrackPopupMenuEx, WM_NCRBUTTONUP, WM_RBUTTONUP


WM_COPY
WM_COPY  QuickInfo  Overview  Group

WM_COPY

wParam = 0; // not used; must be zero

lParam = 0; // not used; must be zero

An application sends the WM_COPY message to an edit control or combo box to copy the current selection to the clipboard in CF_TEXT format.

Parameters

This message has no parameters.

Return Value

This message does not return a value.

Remarks

When sent to a combo box, the WM_COPY message is handled by its edit control. This message has no effect when sent to a combo box with the CBS_DROPDOWNLIST style.

See Also

WM_CLEAR, WM_CUT, WM_PASTE


WM_COPYDATA
WM_COPYDATA  QuickInfo  Overview  Group

WM_COPYDATA

wParam = (WPARAM) (HWND) hwnd;            // handle of sending window

lParam = (LPARAM) (PCOPYDATASTRUCT) pcds; // pointer to structure with data

The WM_COPYDATA message is sent when an application passes data to another application.

Parameters

hwnd

Identifies the window passing the data.

pcds

Points to a COPYDATASTRUCT structure that contains the data to be passed.

Return Value

If the receiving application processes this message, it should return TRUE; otherwise, it should return FALSE.

Remarks

An application must use the SendMessage function to send this message, not the PostMessage function.

The data being passed must not contain pointers or other references to objects not accessible to the application receiving the data.

While this message is being sent, the referenced data must not be changed by another thread of the sending process.

The receiving application should consider the data read-only. The pcds parameter is valid only during the processing of the message. The receiving application should not free the memory referenced by pcds. If the receiving application must access the data after SendMessage returns, it must copy the data into a local buffer.

See Also

PostMessage, SendMessage, COPYDATASTRUCT


WM_CPL_LAUNCH
WM_CPL_LAUNCH  QuickInfo  Overview  Group

WM_CPL_LAUNCH

hwnd = (HWND) wParam;          // handle of sending window

lpszAppName = (LPSTR) lParam;  // application-name string

An application sends the WM_CPL_LAUNCH message to Windows Control Panel to request that a Control Panel application be started.

Parameters

hwnd

Value of wParam. Specifies the handle of the window sending the message. The WM_CPL_LAUNCHED message is sent to this window.

lpszAppName

Value of lParam. Specifies a far pointer to a string containing the name of the Control Panel application to open.

Return Value

If the application starts, the return value is TRUE; otherwise, it is FALSE.

See Also

WM_CPL_LAUNCHED


WM_CPL_LAUNCHED
WM_CPL_LAUNCHED  QuickInfo  Overview  Group

WM_CPL_LAUNCHED

fAppStarted = (BOOL) wParam;

The WM_CPL_LAUNCHED message is sent when a Control Panel application, started by the WM_CPL_LAUNCH message, has closed. The WM_CPL_LAUNCHED message is sent to the window identified by the wParam parameter of the WM_CPL_LAUNCH message that started the application.

Parameters

fAppStarted

Value of wParam. Specifies whether the application was started. If the application was started, this parameter is TRUE; otherwise, it is FALSE.

Return Value

The value returned by the application is ignored for this message.

See Also

WM_CPL_LAUNCH


WM_CREATE
WM_CREATE  QuickInfo  Overview  Group

WM_CREATE

lpcs = (LPCREATESTRUCT) lParam; // structure with creation data

The WM_CREATE message is sent when an application requests that a window be created by calling the CreateWindowEx or CreateWindow function. The window procedure of the new window receives this message after the window is created, but before the window becomes visible. The message is sent before the CreateWindowEx or CreateWindow function returns.

Parameters

lParam

Value of lParam. Points to a CREATESTRUCT structure that contains information about the window being created. The members of CREATESTRUCT are identical to the parameters of the CreateWindowEx function.

Return Value

If an application processes this message, it should return 0 to continue creation of the window. If the application returns −1, the window is destroyed and the CreateWindowEx or CreateWindow function returns a NULL handle.

See Also

CreateWindow, CreateWindowEx, CREATESTRUCT, WM_NCCREATE


WM_CTLCOLORBTN
WM_CTLCOLORBTN  QuickInfo  Overview  Group

WM_CTLCOLORBTN

hdcButton = (HDC) wParam;   // handle of button display context

hwndButton = (HWND) lParam; // handle of button

The WM_CTLCOLORBTN message is sent to the parent window of a button when the button is about to be drawn. By responding to this message, the parent window can set a button's text and background colors.

Parameters

hdcButton

Value of wParam. Identifies the display context for the button.

hwndButton

Value of lParam. Identifies the button.

Return Value

If an application processes this message, it must return the handle of a brush. Windows uses the brush to paint the background of the button.

Default Action

The DefWindowProc function selects the default system colors for the button.

Remarks

The WM_CTLCOLORBTN message is never sent between threads. It is sent only within one thread.

The text color of a check box or radio button applies to the box or button, its check mark, and the text. The focus rectangle for these buttons remains the system default color (typically black). The text color of a group box applies to the text but not to the line that defines the box. The text color of a push button applies only to its focus rectangle; it does not affect the color of the text.

You cannot use a custom palette to set a button's text or background color. Although the SelectPalette and RealizePalette functions will succeed, they will have no effect on the button.

See Also

DefWindowProc, RealizePalette, SelectPalette, WM_CTLCOLORDLG, WM_CTLCOLOREDIT, WM_CTLCOLORLISTBOX, WM_CTLCOLORMSGBOX, WM_CTLCOLORSCROLLBAR, WM_CTLCOLORSTATIC


WM_CTLCOLORDLG
WM_CTLCOLORDLG  QuickInfo

WM_CTLCOLORDLG

hdcDlg = (HDC) wParam;   // handle of dialog box display context

hwndDlg = (HWND) lParam; // handle of dialog box

The WM_CTLCOLORDLG message is sent to a dialog box before Windows draws the dialog box. By responding to this message, the dialog box can set its text and background colors by using the given display device context handle.

Parameters

hdcDlg

Value of wParam. Identifies the device context for the dialog box.

hwndDlg

Value of lParam. Identifies the dialog box.

Return Value

If an application processes this message, it must return the handle of a brush. Windows uses the brush to paint the background of the dialog box.

Default Action

The DefWindowProc function selects the default system colors for the dialog box.

Remarks

The WM_CTLCOLORDLG message is never sent between threads. It is sent only within one thread.

Note that the WM_CTLCOLORDLG message is sent to the dialog box itself; all of the other WM_CTLCOLOR* messages are sent to the owner of the control.

You cannot use a custom palette to draw a dialog box's text and background colors. Although you could select and realize a custom palette into the dialog box's display context while handling the WM_CTLCOLORDLG message, no message is sent when dialog box drawing is done, and thus you wouldn't know when to restore the display context's previous palette.

You cannot use a custom palette to set a dialog box's text or background color. Although the SelectPalette and RealizePalette functions will succeed, they will have no effect on the dialog box.

See Also

DefWindowProc, RealizePalette, SelectPalette, WM_CTLCOLORBTN, WM_CTLCOLOREDIT, WM_CTLCOLORLISTBOX, WM_CTLCOLORMSGBOX, WM_CTLCOLORSCROLLBAR, WM_CTLCOLORSTATIC


WM_CTLCOLOREDIT
WM_CTLCOLOREDIT  QuickInfo  Overview  Group

WM_CTLCOLOREDIT

hdcEdit = (HDC) wParam;   // handle of display context

hwndEdit = (HWND) lParam; // handle of static control

The WM_CTLCOLOREDIT message is sent to the parent window of an edit control when the control is about to be drawn. By responding to this message, the parent window can use the given device context handle to set the text and background colors of the edit control.

Parameters

hdcEdit

Value of wParam. Identifies the device context for the edit control window.

hwndEdit

Value of lParam. Identifies the edit control.

Return Value

If an application processes this message, it must return the handle of a brush. Windows uses the brush to paint the background of the edit control.

Default Action

The DefWindowProc function selects the default system colors for the edit control.

Remarks

The WM_CTLCOLOREDIT message is never sent between threads, it is only sent within the same thread.

You cannot use a custom palette to set an edit control's text or background color. Although the SelectPalette and RealizePalette functions will succeed, they will have no effect on the edit control.

See Also

DefWindowProc, RealizePalette, SelectPalette, WM_CTLCOLORBTN, WM_CTLCOLORDLG, WM_CTLCOLORLISTBOX, WM_CTLCOLORMSGBOX, WM_CTLCOLORSCROLLBAR, WM_CTLCOLORSTATIC


WM_CTLCOLORLISTBOX
WM_CTLCOLORLISTBOX  QuickInfo

WM_CTLCOLORLISTBOX

hdcLB = (HDC) wParam;   // handle of list box display context

hwndLB = (HWND) lParam; // handle of list box

The WM_CTLCOLORLISTBOX message is sent to the parent window of a list box before Windows draws the list box. By responding to this message, the parent window can set the text and background colors of the list box by using the given display device context handle.

Parameters

hdcLB

Value of wParam. Identifies the device context for the list box.

hwndLB

Value of lParam. Identifies the list box.

Return Value

If an application processes this message, it must return the handle of a brush. Windows uses the brush to paint the background of the list box.

Default Action

The DefWindowProc function selects the default system colors for the list box.

Remarks

The WM_CTLCOLORLISTBOX message is never sent between threads. It is sent only within one thread.

You cannot use a custom palette to set a list box's text or background color. Although the SelectPalette and RealizePalette functions will succeed, they will have no effect on the list box.

See Also

DefWindowProc, RealizePalette, SelectPalette, WM_CTLCOLORBTN, WM_CTLCOLORDLG, WM_CTLCOLOREDIT, WM_CTLCOLORMSGBOX, WM_CTLCOLORSCROLLBAR, WM_CTLCOLORSTATIC


WM_CTLCOLORMSGBOX
WM_CTLCOLORMSGBOX  QuickInfo  Overview  Group

WM_CTLCOLORMSGBOX

hdcMB = (HDC) wParam;   // handle of message box display context

hwndMB = (HWND) lParam; // handle of message box

The WM_CTLCOLORMSGBOX message is sent to the owner window of a message box before Windows draws the message box. By responding to this message, the owner window can set the text and background colors of the message box by using the given display device context handle.

Parameters

hdcMB

Value of wParam. Identifies the device context for the message box.

hwndMB

Value of lParam. Identifies the message box.

Return Value

If an application processes this message, it must return the handle of a brush. Windows uses the brush to paint the background of the message box.

Default Action

The DefWindowProc function selects the default system colors for the message box.

Remarks

The WM_CTLCOLORMSGBOX message is never sent between threads. It is sent only within one thread.

You cannot use a custom palette to set a message box's text or background color. Although the SelectPalette and RealizePalette functions will succeed, they will have no effect on the message box.

See Also

DefWindowProc, RealizePalette, SelectPalette, WM_CTLCOLORBTN, WM_CTLCOLORDLG, WM_CTLCOLOREDIT, WM_CTLCOLORLISTBOX, WM_CTLCOLORSCROLLBAR, WM_CTLCOLORSTATIC


WM_CTLCOLORSCROLLBAR
WM_CTLCOLORSCROLLBAR  QuickInfo  Overview  Group

WM_CTLCOLORSCROLLBAR

hdcSB  = (HDC) wParam;   // handle of scroll-bar display context

hwndSB = (HWND) lParam;  // handle of scroll bar

The WM_CTLCOLORSCROLLBAR message is sent to the parent window of a scroll bar control when the control is about to be drawn. By responding to this message, the parent window can use the given display context handle to set the background color of the scroll bar control.

Parameters

hdcSB

Value of wParam. Identifies the device context for the scroll bar control.

hwndSB

Value of lParam. Identifies the scroll bar.

Return Value

If an application processes this message, it must return the handle of a brush. Windows uses the brush to paint the background of the scroll bar control.

Default Action

The DefWindowProc function selects the default system colors for the scroll bar control.

Remarks

The WM_CTLCOLORSCROLLBAR message is never sent between threads; it is only sent within the same thread.

You cannot use a custom palette to set a scroll bar's text or background color. Although the SelectPalette and RealizePalette functions will succeed, they will have no effect on the scroll bar.

See Also

DefWindowProc, RealizePalette, SelectPalette, WM_CTLCOLORBTN, WM_CTLCOLORDLG, WM_CTLCOLOREDIT, WM_CTLCOLORLISTBOX, WM_CTLCOLORMSGBOX, WM_CTLCOLORSTATIC


WM_CTLCOLORSTATIC
WM_CTLCOLORSTATIC  QuickInfo  Overview  Group

WM_CTLCOLORSTATIC

hdcStatic = (HDC) wParam;   // handle of display context

hwndStatic = (HWND) lParam; // handle of static control

The WM_CTLCOLORSTATIC message is sent to the parent window of a static control when the control is about to be drawn. By responding to this message, the parent window can use the given device context handle to set the text and background colors of the static control.

Parameters

hdcStatic

Value of wParam. Identifies the device context for the static control window.

hwndStatic

Value of lParam. Identifies the static control.

Return Value

If an application processes this message, the return value is the handle of a brush that Windows uses to paint the background of the static control.

Default Action

The DefWindowProc function selects the default system colors for the static control.

Remarks

The WM_CTLCOLORSTATIC message is never sent between threads; it is sent only within the same thread.

You cannot use a custom palette to set a static control's text or background color. Although the SelectPalette and RealizePalette functions will succeed, they will have no effect on the static control.

See Also

DefWindowProc, RealizePalette, SelectPalette, WM_CTLCOLORBTN, WM_CTLCOLORDLG, WM_CTLCOLOREDIT, WM_CTLCOLORLISTBOX, WM_CTLCOLORMSGBOX, WM_CTLCOLORSCROLLBAR


WM_CUT
WM_CUT  QuickInfo  Overview  Group

WM_CUT

wParam = 0; // not used; must be zero

lParam = 0; // not used; must be zero

An application sends a WM_CUT message to an edit control or combo box to delete (cut) the current selection, if any, in the edit control and copy the deleted text to the clipboard in CF_TEXT format.

Parameters

This message has no parameters.

Return Value

This message does not return a value.

Remarks

The deletion performed by the WM_CUT message can be undone by sending the edit control an EM_UNDO message.

To delete the current selection without placing the deleted text on the clipboard, use the WM_CLEAR message.

When sent to a combo box, the WM_CUT message is handled by its edit control. This message has no effect when sent to a combo box with the CBS_DROPDOWNLIST style.

See Also

EM_UNDO, WM_CLEAR, WM_COPY, WM_PASTE


WM_DDE_ACK
WM_DDE_ACK  QuickInfo  Overview  Group

WM_DDE_ACK

// Response to WM_DDE_INITIATE

wParam = (WPARAM) hwnd;          // handle of posting application

lParam = MAKELPARAM(aApp, aTopic) // application and topic atoms

// Response to WM_DDE_EXECUTE

wParam = (WPARAM) hwnd;         // handle of posting application

lParam = (LPARAM) lPackedVal;   // packed status flags and data handle

// Response to all other messages

wParam = (WPARAM) hwnd;         // handle of posting application

lParam = (LPARAM) lPackedVal;   // packed status flags and item

The WM_DDE_ACK message notifies a DDE application of the receipt and processing of a WM_DDE_POKE, WM_DDE_EXECUTE, WM_DDE_DATA, WM_DDE_ADVISE, WM_DDE_UNADVISE, or WM_DDE_INITIATE message, and in some cases, of a WM_DDE_REQUEST message.

Parameters

When responding to WM_DDE_INITIATE:

hwnd

Value of wParam. Identifies the server window posting the message.

aApp

Value of the low-order word of lParam. Contains an atom that identifies the replying application.

aTopic

Value of the high-order word of lParam. Contains an atom that identifies the topic for which a conversation is being established.

When responding to WM_DDE_EXECUTE:

hwnd

Value of wParam. Identifies the server window posting the message.

lPackedVal

Value of lParam. The component parameters that are packed into lPackedVal are extracted by calling the UnpackDDElParam function. The low-order word is wStatus. The high-order word is the same hCommands that was received in the WM_DDE_EXECUTE message.

Parameter	Description
wStatus	Specifies a DDEACK structure containing a series of flags that indicate the status of the response.
hCommands	Identifies a global memory object that contains the command string.
When replying to all other messages:

hwnd

Value of wParam. Identifies the client or server window posting the message.

lPackedVal

Value of lParam. The component parameters that are packed into lPackedVal are extracted by calling the UnpackDDElParam function. The low-order word is wStatus. The high-order word is aItem.

Parameter	Description
wStatus	Specifies a DDEACK structure containing a series of flags that indicate the status of the response.
aItem	Contains a global atom that identifies the name of the data item for which the response is sent.
Remarks

Posting

Except in response to the WM_DDE_INITIATE message, the application posts the WM_DDE_ACK message by calling the PostMessage function, not by calling the SendMessage function. When responding to WM_DDE_INITIATE, the application sends the WM_DDE_ACK message by calling SendMessage. In this case, neither the application-name atom nor the topic-name atom should be NULL (even if the WM_DDE_INITIATE message specified NULL atoms).

When acknowledging any message with an accompanying aItem atom, the application posting WM_DDE_ACK can either reuse the aItem atom that accompanied the original message, or it can delete it and create a new one.

When acknowledging WM_DDE_EXECUTE, the application that posts WM_DDE_ACK should reuse the global memory object identified in the original WM_DDE_EXECUTE message.

All posted WM_DDE_ACK messages must create or reuse the lPackedVal parameter by calling the PackDDElParam function or the ReuseDDElParam function.

If an application has initiated the termination of a conversation by posting WM_DDE_TERMINATE and is awaiting confirmation, the waiting application should not acknowledge (positively or negatively) any subsequent messages sent by the other application. The waiting application should delete any atoms or shared memory objects received in these intervening messages. Memory objects should not be freed if the fRelease flag is set to FALSE in WM_DDE_POKE, and WM_DDE_DATA messages.

Receiving

The application that receives a WM_DDE_ACK message should delete all atoms accompanying the message. If the application receives a WM_DDE_ACK in response to a message with an accompanying hData object, and the object was sent with the fRelease flags set to FALSE, the application is responsible for deleteing the hData object.

If the application receives a negative WM_DDE_ACK message posted in reply to a WM_DDE_ADVISE message, the application should delete the global memory object posted with the original WM_DDE_ADVISE message (in hOptions). If the application receives a negative WM_DDE_ACK message posted in reply to a WM_DDE_DATA, WM_DDE_POKE, or WM_DDE_EXECUTE message, the application should delete the global memory object posted with the original WM_DDE_DATA, WM_DDE_POKE, or WM_DDE_EXECUTE message (in hCommands).

The application that receives a posted WM_DDE_ACK message must free the lPackedVal parameter by using the FreeDDElParam function.

See Also

DDEACK, FreeDDElParam, PackDDElParam, PostMessage, ReuseDDElParam, SendMessage, UnpackDDElParam, WM_DDE_ADVISE, WM_DDE_DATA, WM_DDE_EXECUTE, WM_DDE_INITIATE, WM_DDE_POKE, WM_DDE_REQUEST, WM_DDE_TERMINATE, WM_DDE_UNADVISE


WM_DDE_ADVISE
WM_DDE_ADVISE  QuickInfo  Overview  Group

WM_DDE_ADVISE

wParam = (WPARAM) hwnd;        // handle of posting application

lParam = (LPARAM) lPackedVal;  // packed DDEADVISE and item atom

A DDE client application posts the WM_DDE_ADVISE message to a DDE server application to request the server to supply an update for a data item whenever the item changes.

Parameters

hwnd

Value of wParam. Identifies the client window posting the message.

lPackedVal

Value of lParam. The component parameters packed into lPackedVal are extracted by calling the UnpackDDElParam function. The low-order word is hOptions. The high-order word is aItem.

Parameter	Description
hOptions	Identifies a global memory object containing a DDEADVISE structure that specifies how the data is to be sent.
aItem	Contains an atom that identifies the requested data item.
Remarks

If a client application supports more than one clipboard format for a single topic and item, it can post multiple WM_DDE_ADVISE messages for the topic and item, specifying a different clipboard format with each message. Note that a server can support multiple formats only for hot data links, not warm data links.

Posting

The client application posts the WM_DDE_ADVISE message by calling the PostMessage function, not the SendMessage function.

The client application allocates hOptions by calling the GlobalAlloc function with the GMEM_DDESHARE option. It allocates aItem by calling the GlobalAddAtom function.

The client application must create or reuse the WM_DDE_ADVISE lPackedVal parameter by calling the PackDDElParam function or the ReuseDDElParam function with hOptions supplied as the low-order word and aItem supplied as the high-order word.

If the receiving (server) application responds with a negative WM_DDE_ACK message, the posting (client) application must delete the hOptions object.

The fRelease flag is not used in WM_DDE_ADVISE messages, but their data-freeing behavior is similar to that of WM_DDE_DATA and WM_DDE_POKE messages where fRelease is TRUE.

Receiving

The server application posts the WM_DDE_ACK message to respond positively or negatively. When posting WM_DDE_ACK, the application can reuse the aItem atom or delete it and create a new one. If the WM_DDE_ACK message is positive, the application should delete the hOptions object; otherwise, the application should not delete the object.

The server must create or reuse the WM_DDE_ACK lPackedVal parameter by calling the PackDDElParam function or the ReuseDDElParam function with wStatus supplied as the low-order word and aItem supplied as the high-order word.

See Also

DDEADVISE, FreeDDElParam, GlobalAddAtom, GlobalAlloc, PackDDElParam, PostMessage, ReuseDDElParam, SendMessage, UnpackDDElParam, WM_DDE_ACK, WM_DDE_DATA, WM_DDE_POKE, WM_DDE_REQUEST


WM_DDE_DATA
WM_DDE_DATA  QuickInfo  Overview  Group

WM_DDE_DATA

wParam = (WPARAM) hwnd;         // handle of posting application

lParam = (LPARAM) lPackedVal;   // packed DDEDATA and item atom

A DDE server application posts a WM_DDE_DATA message to a DDE client application to pass a data item to the client or to notify the client of the availability of a data item.

Parameters

hwnd

Value of wParam. Identifies the server window posting the message.

lPackedVal

Value of lParam. The component parameters that are packed into lPackedVal are extracted by calling the UnpackDDElParam function. The low-order word is hData or NULL. The high-order word is aItem.

Parameter	Description
hData	Identifies a global memory object containing a DDEDATA structure with the data and additional information. The handle should be set to NULL if the server is notifying the client that the data-item value has changed during a warm data link. A warm link is established by the client sending a WM_DDE_ADVISE message with the fDeferUpd bit set.
aItem	Contains an atom that identifies the data item for which the data or notification is sent.
Remarks

Posting

The server application posts the WM_DDE_DATA message by calling the PostMessage function, not the SendMessage function.

The server application allocates hData by calling the GlobalAlloc function with the GMEM_DDESHARE option. It allocates aItem by calling the GlobalAddAtom function.

The server must create or reuse the WM_DDE_DATA lPackedVal parameter by calling the PackDDElParam function or the ReuseDDElParam function with hData supplied as the low-order word and aItem supplied as the high-order word.

If the receiving (client) application responds with a negative WM_DDE_ACK message, the posting (server) application must delete the hData object; otherwise, the client must delete the hData object after extracting its contents by calling the UnpackDDElParam function.

If the server application sets the fRelease member of the DDEDATA structure to FALSE, the server is responsible for deleting hData upon receiving either a positive or negative acknowledgement.

The server application should not set both the fAckReq and fRelease members of the DDEDATA structure to FALSE. If both members are set to FALSE, it is impossible for the server to determine when to delete hData.

Receiving

If fAckReq is TRUE, the client application should post the WM_DDE_ACK message to respond positively or negatively. When posting WM_DDE_ACK, the client can either reuse the aItem atom, or it can delete it and create a new one.

The client must create or reuse the WM_DDE_ACK lPackedVal parameter by calling the PackDDElParam function or the ReuseDDElParam function with wStatus supplied as the low-order word and aItem supplied as the high-order word.

If fAckReq is FALSE, the client application should delete the aItem atom.

If the posting (server) application specified hData as NULL, the receiving (client) application can request the server to send the data by posting a WM_DDE_REQUEST message.

After processing a WM_DDE_DATA message in which hData is not NULL, the client should free hData, unless one of the following conditions is true:

•	The fRelease member is FALSE.

•	The fRelease member is TRUE, but the client application responds with a negative WM_DDE_ACK message.

See Also

DDEDATA, FreeDDElParam, GlobalAddAtom, GlobalAlloc, PackDDElParam, PostMessage, ReuseDDElParam, SendMessage, UnpackDDElParam, WM_DDE_ACK, WM_DDE_ADVISE, WM_DDE_POKE, WM_DDE_REQUEST


WM_DDE_EXECUTE
WM_DDE_EXECUTE  QuickInfo  Overview  Group

WM_DDE_EXECUTE

wParam = (WPARAM) hwnd;        // handle of posting application

lParam = (LPARAM) hCommands;   // handle to global object

A DDE client application posts a WM_DDE_EXECUTE message to a DDE server application to send a string to the server to be processed as a series of commands. The server application is expected to post a WM_DDE_ACK message in response.

Parameters

hwnd

Value of wParam. Identifies the client window posting the message.

hCommands

Value of lParam. Contains a global memory object that references an ANSI or Unicode command string, depending on the types of windows involved in the conversation.

Remarks

The command string is a null-terminated string consisting of one or more opcode strings enclosed in single brackets ([ ]).

Each opcode string has the following syntax, where the parameters list is optional:

opcode parameters

The opcode is any application-defined single token. It cannot include spaces, commas, parentheses, brackets, or quotation marks.

The parameters list can contain any application-defined value or values. Multiple parameters are separated by commas, and the entire parameter list is enclosed in parentheses. Parameters cannot include commas or parentheses except inside a quoted string. If a bracket or parenthesis character is to appear in a quoted string, it need not be doubled, as was the case under the old rules.

Following are some valid command strings:

[connect][download(query1,results.txt)][disconnect]

[query("sales per employee for each district")]

[open("sample.xlm")][run("r1c1")]

[quote_case("This is a "" character")]

[bracket_or_paren_case("()s or []s should be no problem.")]

Note that, under the old rules, parentheses and brackets had to be doubled, as follows:

[bracket_or_paren_case("(())s or [[]]s should be no problem.")]

Servers should be able to parse commands in either form.

Unicode execute strings should be used only when both the client and server window handles cause the IsWindowUnicode function to return TRUE.

Posting

The client application posts the WM_DDE_EXECUTE message by calling the PostMessage function, not the SendMessage function.

The client application allocates hCommands by calling the GlobalAlloc function with the GMEM_DDESHARE option.

When processing the WM_DDE_ACK message that the server posts in reply to a WM_DDE_EXECUTE message, the client application must delete the hCommands object sent back in the WM_DDE_ACK message.

Receiving

The server application posts the WM_DDE_ACK message to respond positively or negatively. The server should reuse the hCommands object.

Unless specified otherwise by a sub-protocol, the server should not post the WM_DDE_ACK message until all the actions specified by the execute command string are completed. The one exception to this rule is when the string causes the server to terminate the conversation.

See Also

GlobalAlloc, IsWindowUnicode, PackDDElParam, PostMessage, ReuseDDElParam, SendMessage, UnpackDDElParam, WM_DDE_ACK


WM_DDE_INITIATE
WM_DDE_INITIATE  QuickInfo  Overview  Group

WM_DDE_INITIATE

wParam = (WPARAM) hwnd;             // handle of posting appl.

lParam = MAKELPARAM(aApp, aTopic);  // appl. and topic atoms

A DDE client application sends a WM_DDE_INITIATE message to initiate a conversation with a server application responding to the specified application and topic names. Upon receiving this message, all server applications with names that match the specified application and that support the specified topic are expected to acknowledge it. (For more information, see the WM_DDE_ACK message.)

Parameters

hwnd

Value of wParam. Identifies the client window sending the message.

aApp

Value of the low-order word of lParam. Contains an atom that identifies the application with which a conversation is requested. The application name cannot contain slashes (/) or backslashes (\). These characters are reserved for network implementations. If aApp is NULL, a conversation with all applications is requested.

aTopic

Value of the high-order word of lParam. Contains an atom that identifies the topic for which a conversation is requested. If the topic is NULL, conversations for all available topics are requested.

Remarks

If aApp is NULL, any server application can respond. If aTopic is NULL, any topic is valid. Upon receiving a WM_DDE_INITIATE request with the aTopic parameter set to NULL, a server must send a WM_DDE_ACK message for each of the topics it supports.

Sending

The client application sends WM_DDE_INITIATE by calling the SendMessage function, not the PostMessage function. The client broadcasts the message to all top-level windows by setting the first parameter of SendMessage to −1.

If the client application has already obtained the window handle of the desired server, it can send WM_DDE_INITIATE directly to the server window by passing the server's window handle as the first parameter of SendMessage.

The client application allocates aApp and aTopic by calling GlobalAddAtom.

When SendMessage returns, the client application must delete the aApp and aTopic atoms.

Receiving

To complete the initiation of a conversation, the server application must respond with one or more WM_DDE_ACK messages, where each message is for a separate topic. When sending WM_DDE_ACK message, the server should create new aApp and aTopic atoms; it should not reuse the atoms sent with WM_DDE_INITIATE.

See Also

GlobalAddAtom, GlobalAlloc, PostMessage, SendMessage, WM_DDE_ACK


WM_DDE_POKE
WM_DDE_POKE  QuickInfo  Overview  Group

WM_DDE_POKE

wParam = (WPARAM) hwnd;        // handle of posting application

lParam = (LPARAM) lPackedVal;  // packed DDEPOKE and item atom

A DDE client application posts a WM_DDE_POKE message to a DDE server application. A client uses this message to request the server to accept an unsolicited data item. The server is expected to reply with a WM_DDE_ACK message indicating whether it accepted the data item.

Parameters

hwnd

Value of wParam. Identifies the client window posting the message.

lPackedVal

Value of lParam. The component parameters that are packed into lPackedVal are extracted by calling the UnpackDDElParam function. The low-order word is hData. The high-order word is aItem.

Parameter	Description
hData	Identifies a global memory object containing a DDEPOKE structure with the data and additional information.
aItem	Contains a global atom that identifies the data item for which the data or notification is being sent.
Remarks

Posting

The client application posts the WM_DDE_POKE message by using the PostMessage function.

The client application must allocate memory for the hData object by using the GlobalAlloc function with the GMEM_DDESHARE option. The client application must delete the hData object if either of the following conditions is true:

•	The server application responds with a negative WM_DDE_ACK message.

•	The fRelease member is FALSE, but the server application responds with either a positive or negative WM_DDE_ACK.

The client application must create the aItem atom by using the GlobalAddAtom function.

The client application must create or reuse the WM_DDE_POKE lPackedVal parameter by calling the PackDDElParam function or the ReuseDDElParam function with hData supplied as the low-order word and aItem supplied as the high-order word.

Receiving

The server application should post the WM_DDE_ACK message to respond positively or negatively. When posting WM_DDE_ACK, the server can either reuse the aItem atom, or it can delete it and create a new one.

The server must create or reuse the WM_DDE_ACK lPackedVal parameter by calling the PackDDElParam function or the ReuseDDElParam function with wStatus supplied as the low-order word and aItem supplied as the high-order word.

To free the hData object, the server should call the GlobalFree function. Also, if the data format is either CF_DSPMETAFILEPICT or CF_METAFILEPICT, the server must also call DeleteMetaFile with the embedded metafile handle. These two formats have an extra level of indirection; that is, an application must lock hData to get a pointer to a handle, then lock that handle to get a pointer to a METAFILEPICT structure, and finally call DeleteMetaFile with the handle from the hMF member of the METAFILEPICT structure.

To free the lPackedVal object, the server should call the FreeDDElParam function.

See Also

DDEPOKE, DeleteMetaFile, FreeDDElParam, GlobalAddAtom, GlobalAlloc, GlobalFree, METAFILEPICT, PackDDElParam, PostMessage, ReuseDDElParam, SendMessage, UnpackDDElParam, WM_DDE_ACK


WM_DDE_REQUEST
WM_DDE_REQUEST  QuickInfo  Overview  Group

WM_DDE_REQUEST

wParam = (WPARAM) hwnd;        // handle of posting application

lParam = (LPARAM) lParam;      // holds cfFormat and aItem

A DDE client application posts a WM_DDE_REQUEST message to a DDE server application to request the value of a data item.

Parameters

hwnd

Value of wParam. Identifies the client window sending the message.

lParam

Holds the cfFormat and aItem parameters.

Parameter	Description
cfFormat	This is the LOWORD of lParam. Specifies a standard or registered clipboard format.
aItem	This is the HIWORD of lParam. Contains an atom that identifies the data item requested from the server.
Remarks

Posting

The client application posts the WM_DDE_REQUEST message by calling the PostMessage function, not the SendMessage function.

The client application allocates aItem by calling the GlobalAddAtom function.

Receiving

If the receiving (server) application can satisfy the request, it responds with a WM_DDE_DATA message containing the requested data. Otherwise, it responds with a negative WM_DDE_ACK message.

When responding with either a WM_DDE_DATA or WM_DDE_ACK message, the server application can either reuse the aItem atom or it can delete the atom and create a new one.

See Also

GlobalAddAtom, PackDDElParam, PostMessage, ReuseDDElParam, SendMessage, UnpackDDElParam, WM_DDE_ACK, WM_DDE_DATA


WM_DDE_TERMINATE
WM_DDE_TERMINATE  QuickInfo  Overview  Group

WM_DDE_TERMINATE

wParam = (WPARAM) hwnd; // handle of posting window

lParam = 0;             // not used, must be zero

A DDE application (client or server) posts a WM_DDE_TERMINATE message to terminate a conversation.

Parameters

hwnd

Value of wParam. Identifies the client or server window posting the message.

Remarks

Posting

The client or server application posts the WM_DDE_TERMINATE message by calling the PostMessage function, not the SendMessage function.

While waiting for confirmation of the termination, the posting application should not post any other messages to the receiving application. If the sending application receives messages (other than WM_DDE_TERMINATE) from the receiving application, it should delete any atoms or shared memory objects accompanying the messages, except hData objects associated with WM_DDE_POKE or WM_DDE_DATA messages that do not have the fRelease flag set.

Receiving

The client or server application should respond by posting a WM_DDE_TERMINATE message.

See Also

PostMessage, SendMessage, WM_DDE_DATA, WM_DDE_POKE


WM_DDE_UNADVISE
WM_DDE_UNADVISE  QuickInfo  Overview  Group

WM_DDE_UNADVISE

wParam = (WPARAM) hwnd;        // handle of posting application

lParam = (LPARAM) lParam;      // format and item atom

A DDE client application posts a WM_DDE_UNADVISE message to inform a DDE server application that the specified item or a particular clipboard format for the item should no longer be updated. This terminates the warm or hot data link for the specified item.

Parameters

hwnd

Value of wParam. Identifies the client window sending the message.

lParam

Holds the cfFormat and aItem parameters.

Parameter	Description
cfFormat	This is the LOWORD of lParam. Specifies the clipboard format of the item for which the update request is being retracted. If cfFormat is NULL, all active WM_DDE_ADVISE conversations for the item are to be terminated.
aItem	This is the HIWORD of lParam. Contains a global atom that identifies the item for which the update request is being retracted. When aItem is NULL, all active WM_DDE_ADVISE links associated with the conversation are to be terminated.
Remarks

Posting

The client application posts the WM_DDE_UNADVISE message by calling the PostMessage function, not the SendMessage function.

The client application allocates aItem by calling the GlobalAddAtom function.

Receiving

The server application posts the WM_DDE_ACK message to respond positively or negatively. When posting WM_DDE_ACK, the server can either reuse the aItem atom, or it can delete the atom and create a new one.

See Also

GlobalAddAtom, PackDDElParam, PostMessage, ReuseDDElParam, SendMessage, UnpackDDElParam, WM_DDE_ACK, WM_DDE_ADVISE


WM_DEADCHAR
WM_DEADCHAR  QuickInfo  Overview  Group

WM_DEADCHAR

chCharCode = (TCHAR) wParam;    // character code

lKeyData = lParam;              // key data

The WM_DEADCHAR message is posted to the window with the keyboard focus when a WM_KEYUP message is translated by the TranslateMessage function. WM_DEADCHAR specifies a character code generated by a dead key. A dead key is a key that generates a character, such as the umlaut (double-dot), that is combined with another character to form a composite character. For example, the umlaut-O character (Ö) is generated by typing the dead key for the umlaut character, and then typing the O key.

Parameters

chCharCode

Value of wParam. Specifies the character code generated by the dead key.

lKeyData

Value of lParam. Specifies the repeat count, scan code, extended-key flag, context code, previous key-state flag, and transition-state flag, as shown in the following table:

Value	Description
0−15	Specifies the repeat count. The value is the number of times the keystroke is repeated as a result of the user holding down the key.
16−23	Specifies the scan code. The value depends on the original equipment manufacturer (OEM).
24	Specifies whether the key is an extended key, such as the right-hand ALT and CTRL keys that appear on an enhanced 101- or 102-key keyboard. The value is 1 if it is an extended key; otherwise, it is 0.
25−28	Reserved; do not use.
29	Specifies the context code. The value is 1 if the ALT key is held down while the key is pressed; otherwise, the value is 0.
30	Specifies the previous key state. The value is 1 if the key is down before the message is sent, or it is 0 if the key is up.
31	Specifies the transition state. The value is 1 if the key is being released, or it is 0 if the key is being pressed.
Return Value

An application should return zero if it processes this message.

Remarks

The WM_DEADCHAR message typically is used by applications to give the user feedback about each key pressed. For example, an application can display the accent in the current character position without moving the caret.

Because there is not necessarily a one-to-one correspondence between keys pressed and character messages generated, the information in the high-order word of the lKeyData parameter is generally not useful to applications. The information in the high-order word applies only to the most recent WM_KEYDOWN message that precedes the posting of the WM_DEADCHAR message.

For enhanced 101- and 102-key keyboards, extended keys are the right ALT and the right CTRL keys on the main section of the keyboard; the INS, DEL, HOME, END, PAGE UP, PAGE DOWN and arrow keys in the clusters to the left of the numeric keypad; and the divide (/) and ENTER keys in the numeric keypad. Some other keyboards may support the extended-key bit in the lKeyData parameter.

See Also

TranslateMessage, WM_KEYDOWN, WM_KEYUP, WM_SYSDEADCHAR


WM_DELETEITEM
WM_DELETEITEM  QuickInfo  Overview  Group

WM_DELETEITEM

idCtl = wParam;                      // control identifier

lpdis = (LPDELETEITEMSTRUCT) lParam; // structure with item information

The WM_DELETEITEM message is sent to the owner of a list box or combo box when the list box or combo box is destroyed or when items are removed by the LB_DELETESTRING, LB_RESETCONTENT, CB_DELETESTRING, or CB_RESETCONTENT message. Windows sends a WM_DELETEITEM message for each deleted item.

Windows NT

Windows sends a WM_DELETEITEM message only for items deleted from an owner-drawn list box (with the LBS_OWNERDRAWFIXED or LBS_OWNERDRAWVARIABLE style) or owner-drawn combo box (with the CBS_OWNERDRAWFIXED or CBS_OWNERDRAWVARIABLE style).

Windows 95

Windows sends the WM_DELETEITEM message for any deleted list box or combo box item with non-zero item data.

Parameters

idCtl

Value of wParam. Specifies the identifier of the control that sent the WM_DELETEITEM message.

lpdis

Value of lParam. Points to a DELETEITEMSTRUCT structure that contains information about the item deleted from a list box.

Return Value

An application should return TRUE if it processes this message.

See Also

CB_DELETESTRING, CB_RESETCONTENT, DELETEITEMSTRUCT, LB_DELETESTRING, LB_RESETCONTENT


WM_DESTROY
WM_DESTROY  QuickInfo  Overview  Group

WM_DESTROY

The WM_DESTROY message is sent when a window is being destroyed. It is sent to the window procedure of the window being destroyed after the window is removed from the screen.

This message is sent first to the window being destroyed and then to the child windows (if any) as they are destroyed. During the processing of the message, it can be assumed that all child windows still exist.

Parameters

This message has no parameters.

Return Value

If an application processes this message, it should return zero.

Remarks

If the window being destroyed is part of the clipboard viewer chain (set by calling the SetClipboardViewer function), the window must remove itself from the chain by processing the ChangeClipboardChain function before returning from the WM_DESTROY message.

See Also

ChangeClipboardChain, DestroyWindow, PostQuitMessage, SetClipboardViewer, WM_CLOSE


WM_DESTROYCLIPBOARD
WM_DESTROYCLIPBOARD  QuickInfo  Overview  Group

WM_DESTROYCLIPBOARD

The WM_DESTROYCLIPBOARD message is sent to the clipboard owner when a call to the EmptyClipboard function empties the clipboard.

Parameters

This message has no parameters.

Return Value

If an application processes this message, it should return zero.

See Also

EmptyClipboard


WM_DEVICECHANGE [New - Windows 95]
WM_DEVICECHANGE  QuickInfo  Overview  Group

[New - Windows 95]

Event = (UINT) wParam;
dwData = (DWORD) lParam;

The WM_DEVICECHANGE device message notifies an application or device driver of a change to the hardware configuration of a device or the computer.

Parameters

Event

Event type. Can be one of these values:

Value	Meaning
DBT_DEVICEARRIVAL	A device has been inserted and is now available.
DBT_DEVICEQUERYREMOVE	Permission to remove a device is requested. Any application can deny this request and cancel the removal.
DBT_DEVICEQUERYREMOVEFAILED	Request to remove a device has been canceled.
DBT_DEVICEREMOVEPENDING	Device is about to be removed. Can not be denied.
DBT_DEVICEREMOVECOMPLETE	Device has been removed.
DBT_DEVICETYPESPECIFIC	Device-specific event.
DBT_CONFIGCHANGED	Current configuration has changed.
dwData

Address of a structure that contains event-specific data. Its meaning depends on the given event.

Return Value

Returns TRUE to complete a requested action, FALSE otherwise.

Remarks

For devices that offer software-controllable features, such as ejection and locking, the operating system typically sends a DBT_DEVICEREMOVEPENDING message to let applications and device drivers end their use of the device gracefully.

If the operating system forcefully removes of a device, it may not send a DBT_DEVICEQUERYREMOVE message before doing so.

DBT_CONFIGCHANGED, DBT_DEVICEARRIVAL, DBT_DEVICEQUERYREMOVE, DBT_DEVICEQUERYREMOVEFAILED, DBT_DEVICEREMOVECOMPLETE, DBT_DEVICEREMOVEPENDING, DBT_DEVICETYPESPECIFIC,


WM_DEVMODECHANGE
WM_DEVMODECHANGE  QuickInfo  Overview  Group

WM_DEVMODECHANGE

lpszDev = (LPCTSTR) lParam; // address of device name

The WM_DEVMODECHANGE message is sent to all top-level windows whenever the user changes device-mode settings.

Parameters

lpszDev

Value of lParam. Points to the device name specified in the WIN.INI file.

Return Value

An application should return zero if it processes this message.

Remarks

Windows NT only: Calls to functions that change the WIN.INI file may be mapped to the registry instead. This mapping occurs when WIN.INI and the section being changed are specified in the registry under the following keys:

HKEY_LOCAL_MACHINE\Software\Description\Microsoft\
        Windows NT\CurrentVersion\IniFileMapping

The change in the storage location has no effect on the behavior of this message.

See Also

WM_WININICHANGE


WM_DISPLAYCHANGE [New - Windows 95]
WM_DISPLAYCHANGE  QuickInfo  Overview  Group

[New - Windows 95]

WM_DISPLAYCHANGE

cBitsPerPixel = wParam;

cxScreen = LOWORD(lParam);

cyScreen = HIWORD(lParam);

The WM_DISPLAYCHANGE message is sent to all windows when the display resolution has changed.

Parameters

cBitsPerPixel

Specifies the new image depth of the display in bits per pixel.

cxScreen

Specifies the new horizontal resolution of the screen.

cyScreen

Specifies the new vertical resolution of the screen.

Remarks

In previous versions, this message was sent twice, once in anticipation of a change to the display resolution and once after the display resolution changed. Now it is only sent after the display resolution has changed.


WM_DRAWCLIPBOARD
WM_DRAWCLIPBOARD  QuickInfo  Overview  Group

WM_DRAWCLIPBOARD

The WM_DRAWCLIPBOARD message is sent to the first window in the clipboard viewer chain when the content of the clipboard changes. This enables a clipboard viewer window to display the new content of the clipboard.

Parameters

This message has no parameters.

Remarks

Only clipboard viewer windows receive this message. These are windows that have been added to the clipboard viewer chain by using the SetClipboardViewer function.

Each window that receives the WM_DRAWCLIPBOARD message must call the SendMessage function to pass the message on to the next window in the clipboard viewer chain. The handle of the next window in the chain is returned by SetClipboardViewer, and may change in response to a WM_CHANGECBCHAIN message.

See Also

SendMessage, SetClipboardViewer, WM_CHANGECBCHAIN


WM_DRAWITEM
WM_DRAWITEM  QuickInfo  Overview  Group

WM_DRAWITEM

idCtl = (UINT) wParam;             // control identifier

lpdis = (LPDRAWITEMSTRUCT) lParam; // item-drawing information

The WM_DRAWITEM message is sent to the owner window of an owner-drawn button, combo box, list box, or menu when a visual aspect of the button, combo box, list box, or menu has changed.

Parameters

idCtl

Value of wParam. Specifies the identifier of the control that sent the WM_DRAWITEM message. If the message was sent by a menu, this parameter is zero.

lpdis

Value of lParam. Points to a DRAWITEMSTRUCT structure containing information about the item to be drawn and the type of drawing required.

Return Value

If an application processes this message, it should return TRUE.

Default Action

The DefWindowProc function draws the focus rectangle for an owner-drawn list box item.

Remarks

The itemAction member of the DRAWITEMSTRUCT structure specifies the drawing operation that an application should perform.

Before returning from processing this message, an application should ensure that the device context identified by the hDC member of the DRAWITEMSTRUCT structure is in the default state.

See Also

DefWindowProc, DRAWITEMSTRUCT


WM_DROPFILES
WM_DROPFILES  QuickInfo  Overview  Group

WM_DROPFILES

hDrop = (HANDLE) wParam;  // handle of internal drop structure

The WM_DROPFILES message is sent when the user releases the left mouse button while the cursor is in the window of an application that has registered itself as a recipient of dropped files.

Parameters

hDrop

Value of wParam. Identifies an internal structure describing the dropped files. This handle is used by the DragFinish, DragQueryFile, and DragQueryPoint functions to retrieve information about the dropped files.

Return Value

An application should return zero if it processes this message.

See Also

DragAcceptFiles, DragFinish, DragQueryFile, DragQueryPoint


WM_ENABLE
WM_ENABLE  QuickInfo  Overview  Group

WM_ENABLE

fEnabled = (BOOL) wParam;   // enabled/disabled flag

The WM_ENABLE message is sent when an application changes the enabled state of a window. It is sent to the window whose enabled state is changing. This message is sent before the EnableWindow function returns, but after the enabled state (WS_DISABLED style bit) of the window has changed.

Parameters

fEnabled

Value of wParam. Specifies whether the window has been enabled or disabled. This parameter is TRUE if the window has been enabled or FALSE if the window has been disabled.

Return Value

If an application processes this message, it should return zero.

See Also

EnableWindow


WM_ENDSESSION
WM_ENDSESSION  QuickInfo  Overview  Group

Windows 95:

WM_ENDSESSION

fEndSession = (BOOL) wParam;    // end-session flag

fLogOff = (BOOL) lParam         // logoff flag

Windows NT:

WM_ENDSESSION

fEndSession = (BOOL) wParam;    // end-session flag

The WM_ENDSESSION message is sent to an application after Windows processes the results of the WM_QUERYENDSESSION message. The WM_ENDSESSION message informs the application whether the Windows session is ending.

Parameters

fEndSession

Value of wParam. Specifies whether the session is being ended. If the session is being ended, this parameter is TRUE; otherwise, it is FALSE.

fLogOff

Windows 95 only: Value of lParam. Indicates whether the user is logging off or shutting down the system. This parameter is TRUE if the user is logging off; it is FALSE if the user is shutting down the system.

Return Value

If an application processes this message, it should return zero.

Remarks

If the fEndSession parameter is TRUE, the Windows session can end any time after all applications have returned from processing this message. Therefore, an application should perform all tasks required for termination before returning from this message.

Note that lParam is not used on the Windows NT platform but is used on the Windows 95 platform.

The application need not call the DestroyWindow or PostQuitMessage function when the session is ending.

See Also

DestroyWindow, PostQuitMessage, WM_QUERYENDSESSION


WM_ENTERIDLE
WM_ENTERIDLE  QuickInfo  Overview  Group

WM_ENTERIDLE

fuSource = wParam;    // idle-source flag

hwnd = (HWND) lParam; // handle of dialog box or owner window

The WM_ENTERIDLE message is sent to the owner window of a modal dialog box or menu that is entering an idle state. A modal dialog box or menu enters an idle state when no messages are waiting in its queue after it has processed one or more previous messages.

Parameters

fuSource

Value of wParam. Specifies whether the message is the result of a dialog box or a menu being displayed. This parameter can be one of the following values:

Value	Meaning
MSGF_DIALOGBOX	The system is idle because a dialog box is displayed.
MSGF_MENU	The system is idle because a menu is displayed.
hwnd

Value of lParam. Contains the handle of the dialog box (if fuSource is MSGF_DIALOGBOX) or of the window containing the displayed menu (if fuSource is MSGF_MENU).

Return Value

An application should return zero if it processes this message.

Remarks

The DefWindowProc function returns zero.

See Also

DefWindowProc


WM_ENTERMENULOOP
WM_ENTERMENULOOP  QuickInfo  Overview  Group

WM_ENTERMENULOOP

wParam = (BOOL) fIsTrackPopupMenu  // flags a pop-up menu

lParam = 0 ;                       // not used; must be zero

The WM_ENTERMENULOOP message informs an application's main window procedure that a menu modal loop has been entered.

Parameters

fIsTrackPopupMenu

Specifies whether the menu involved is a pop-up menu. This parameter has a value of TRUE if it is a pop-up, FALSE if it isn't.

Return Value

An application should return zero if it processes this message.

Remarks

The DefWindowProc function returns zero.

See Also

DefWindowProc, WM_EXITMENULOOP


WM_ENTERSIZEMOVE [New - Windows NT]
WM_ENTERSIZEMOVE  QuickInfo

[New - Windows NT]

WM_ENTERSIZEMOVE

wParam = 0;  // not used, must be zero

lParam = 0;  // not used, must be zero

The WM_ENTERSIZEMOVE message is sent once to a window when it enters the moving or sizing mode. The window enters the moving or sizing mode when the user clicks the window's title bar or sizing border, or when the window passes the WM_SYSCOMMAND message to the DefWindowProc function and the wParam parameter of the message specifies the SC_MOVE or SC_SIZE value. Windows sends the WM_ENTERSIZEMOVE message regardless of whether the dragging of full windows is enabled.

Parameters

This message has no parameters.

Return Value

An application should return zero if it processes this message.

See Also

DefWindowProc, WM_EXITSIZEMOVE, WM_SYSCOMMAND


WM_ERASEBKGND
WM_ERASEBKGND  QuickInfo  Overview  Group

WM_ERASEBKGND

hdc = (HDC) wParam; // handle of device context

An application sends the WM_ERASEBKGND message when the window background must be erased (for example, when a window is resized). The message is sent to prepare an invalidated portion of a window for painting.

Parameters

hdc

Value of wParam. Identifies the device context.

Return Value

An application should return nonzero if it erases the background; otherwise, it should return zero.

Remarks

The DefWindowProc function erases the background by using the class background brush specified by the hbrBackground member of the WNDCLASS structure. If hbrBackground is NULL, the application should process the WM_ERASEBKGND message and erase the background.

An application should return nonzero in response to WM_ERASEBKGND if it processes the message and erases the background; this indicates that no further erasing is required. If the application returns zero, the window will remain marked for erasing. (Typically, this indicates that the fErase member of the PAINTSTRUCT structure will be TRUE.)

See Also

BeginPaint, DefWindowProc, PAINTSTRUCT, WM_ICONERASEBKGND, WNDCLASS


WM_EXITMENULOOP
WM_EXITMENULOOP  QuickInfo  Overview  Group

WM_EXITLOOP

wParam = (BOOL) fIsTrackPopupMenu    // flags a pop-up menu

lParam = 0 ;                         // not used; must be zero

The WM_EXITMENULOOP message informs an application's main window procedure that a menu modal loop has been exited.

Parameters

fIsTrackPopupMenu

Specifies whether the menu involved is a pop-up menu. This parameter has a value of TRUE if it is a pop-up, FALSE if it isn't.

Return Value

An application should return zero if it processes this message.

Remarks

The DefWindowProc function returns zero.

See Also

DefWindowProc, WM_ENTERMENULOOP


WM_EXITSIZEMOVE [New - Windows NT]
WM_EXITSIZEMOVE  QuickInfo

[New - Windows NT]

WM_EXITSIZEMOVE

wParam = 0;  // not used; must be zero

lParam = 0;  // not used; must be zero

The WM_EXITSIZEMOVE message is sent once to a window after it has exited the moving or sizing mode.

Parameters

This message has no parameters.

Return Value

An application should return zero if it processes this message.

See Also

WM_ENTERSIZEMOVE


WM_FONTCHANGE
WM_FONTCHANGE  QuickInfo

WM_FONTCHANGE

wParam = 0; // not used, must be zero

lParam = 0; // not used, must be zero

An application sends the WM_FONTCHANGE message to all top-level windows in the system after changing the pool of font resources.

Parameters

This message has no parameters.

Remarks

An application that adds or removes fonts from the system (for example, by using the AddFontResource or RemoveFontResource function) should send this message to all top-level windows.

To send the WM_FONTCHANGE message to all top-level windows, an application can call the SendMessage function with the hwnd parameter set to HWND_BROADCAST.

See Also

AddFontResource, RemoveFontResource, SendMessage


WM_GETDLGCODE
WM_GETDLGCODE  QuickInfo  Overview  Group

WM_GETDLGCODE

The WM_GETDLGCODE message is sent to the dialog box procedure associated with a control. Normally, Windows handles all arrow-key and TAB-key input to the control. By responding to the WM_GETDLGCODE message, an application can take control of a particular type of input and process the input itself.

Parameters

This message has no parameters.

Return Value

The return value is one or more of the following values, indicating which type of input the application processes.

Value	Meaning
DLGC_BUTTON	Button.
DLGC_DEFPUSHBUTTON	Default push button.
DLGC_HASSETSEL	EM_SETSEL messages.
DLGC_RADIOBUTTON	Radio button.
DLGC_STATIC	Static control.
DLGC_UNDEFPUSHBUTTON	Nondefault push button.
DLGC_WANTALLKEYS	All keyboard input.
DLGC_WANTARROWS	Direction keys.
DLGC_WANTCHARS	WM_CHAR messages.
DLGC_WANTMESSAGE	All keyboard input (the application passes this message on to a control).
DLGC_WANTTAB	TAB key.
Default Action

The DefWindowProc function returns zero.

Remarks

Although the DefWindowProc function always returns zero in response to the WM_GETDLGCODE message, the window procedure for the predefined control classes return a code appropriate for each class.

The WM_GETDLGCODE message and the returned values are useful only with user-defined dialog box controls or standard controls modified by subclassing.

See Also

DefWindowProc, EM_SETSEL, WM_CHAR


WM_GETFONT
WM_GETFONT  QuickInfo  Overview  Group

WM_GETFONT

wParam = 0; // not used, must be zero

lParam = 0; // not used, must be zero

An application sends a WM_GETFONT message to a control to retrieve the font with which the control is currently drawing its text.

Parameters

This message has no parameters.

Return Value

The return value is the handle of the font used by the control, or NULL if the control is using the system font.

See Also

WM_SETFONT


WM_GETHOTKEY
WM_GETHOTKEY  QuickInfo

WM_GETHOTKEY

wParam = 0; // not used; must be zero

lParam = 0; // not used; must be zero

An application sends a WM_GETHOTKEY message to determine the hot key associated with a window.

Parameters

This message has no parameters.

Return Value

The return value is the virtual-key code and modifiers for the hot key, or NULL if no hot key is associated with the window. The virtual-key code is in the low byte of the return value and the modifiers are in the high byte. The modifiers can be a combination of the following flags:

Value	Meaning
HOTKEYF_ALT	ALT key
HOTKEYF_CONTROL	CTRL key
HOTKEYF_EXT	Extended key
HOTKEYF_SHIFT	SHIFT key
Remarks

These hot keys are unrelated to the hot keys set by the RegisterHotKey function.

See Also

RegisterHotKey, WM_SETHOTKEY


WM_GETICON [New - Windows 95]
WM_GETICON  QuickInfo

[New - Windows 95]

WM_GETICON

fType = (BOOL) wParam;  // icon-size flag

The WM_GETICON message is sent to a window to retrieve the handle of the big or small icon associated with a window. Windows retrieves the big icon when drawing a minimized window, and retrieves the small icon when drawing a title bar.

Parameters

fType

Value of wParam. Specifies the icon to retrieve. If TRUE, the message retrieves the big icon; if FALSE, it retrieves the small icon.

Return Value

The return value is the handle of the big or small icon, depending on the value of fType. When an application receives this message, it can return the handle of a big or small icon, or pass the message to DefWindowProc.

Default Action

DefWindowProc returns the handle of the big or small icon associated with the window, depending on the value of fType.

Remarks

When an application receives this message, it can return the handle of a big or small icon, or pass the message to DefWindowProc.

See Also

DefWindowProc, WM_SETICON


WM_GETMINMAXINFO
WM_GETMINMAXINFO  QuickInfo  Overview  Group

WM_GETMINMAXINFO

lpmmi = (LPMINMAXINFO) lParam; // address of structure

The WM_GETMINMAXINFO message is sent to a window when the size or position of the window is about to change. An application can use this message to override the window's default maximized size and position, or its default minimum or maximum tracking size.

Parameters

lpmmi

Value of lParam. Points to a MINMAXINFO structure that contains the default maximized position and dimensions, and the default minimum and maximum tracking sizes. An application can override the defaults by setting the members of this structure.

Return Value

If an application processes this message, it should return zero.

Remarks

The maximum tracking size is the largest window size that can be produced by using the borders to size the window. The minimum tracking size is the smallest window size that can be produced by using the borders to size the window.

See Also

MoveWindow, SetWindowPos, MINMAXINFO


WM_GETTEXT
WM_GETTEXT  QuickInfo  Overview  Group

WM_GETTEXT

wParam = (WPARAM) cchTextMax;   // number of characters to copy

lParam = (LPARAM) lpszText;     // address of buffer for text

An application sends a WM_GETTEXT message to copy the text that corresponds to a window into a buffer provided by the caller.

Parameters

cchTextMax

Value of wParam. Specifies the maximum number of characters to be copied, including the terminating null character.

lpszText

Value of lParam. Points to the buffer that is to receive the text.

Return Value

The return value is the number of characters copied.

Default Action

The DefWindowProc function copies the text associated with the window into the specified buffer and returns the number of characters copied.

Remarks

For an edit control, the text to be copied is the content of the edit control. For a combo box, the text is the content of the edit control (or static-text) portion of the combo box. For a button, the text is the button name. For other windows, the text is the window title. To copy the text of an item in a list box, an application can use the LB_GETTEXT message.

When the WM_GETTEXT message is sent to a static control with the SS_ICON style, the handle of the icon will be returned in the first four bytes of the buffer pointed to by lpszText. This is true only if the WM_SETTEXT message has been used to set the icon.

See Also

DefWindowProc, GetWindowText, GetWindowTextLength, LB_GETTEXT, WM_GETTEXTLENGTH, WM_SETTEXT


WM_GETTEXTLENGTH
WM_GETTEXTLENGTH  QuickInfo

WM_GETTEXTLENGTH

wParam = 0; // not used; must be zero

lParam = 0; // not used; must be zero

An application sends a WM_GETTEXTLENGTH message to determine the length, in characters, of the text associated with a window. The length does not include the terminating null character.

Parameters

This message has no parameters.

Return Value

The return value is the length, in characters, of the text.

Default Action

The DefWindowProc function returns the length, in characters, of the text. Under certain conditions, this value may actually be greater than the length of the text. For more information, see the following Remarks section.

Remarks

For an edit control, the text to be copied is the content of the edit control. For a combo box, the text is the content of the edit control (or static-text) portion of the combo box. For a button, the text is the button name. For other windows, the text is the window title. To determine the length of an item in a list box, an application can use the LB_GETTEXTLEN message.

Under certain conditions, the DefWindowProc function returns a value that is larger than the actual length of the text. This occurs with certain mixtures of ANSI and Unicode, and is due to the operating system allowing for the possible existence of DBCS characters within the text. The return value, however, will always be at least as large as the actual length of the text; you can thus always use it to guide buffer allocation. This behavior can occur when an application uses both ANSI functions and common dialogs, which use Unicode.

To obtain the exact length of the text, use the WM_GETTEXT, LB_GETTEXT, or CB_GETLBTEXT messages, or the GetWindowText function.

See Also

CB_GETLBTEXT, DefWindowProc, GetWindowText, GetWindowTextLength, LB_GETTEXT, LB_GETTEXTLEN, WM_GETTEXT


WM_HELP [New - Windows NT]
WM_HELP  QuickInfo  Overview  Group

[New - Windows NT]

WM_HELP

lphi = (LPHELPINFO) lParam;

The WM_HELP message indicates that the user pressed the F1 key. If a menu is active when F1 is pressed, WM_HELP is sent to the window associated with the menu; otherwise, WM_HELP is sent to the window that has the keyboard focus. If no Window has the keyboard focus, WM_HELP is sent to the currently active window.

Parameters

lphi

Pointer to a HELPINFO structure that contains information about the menu item, control, dialog box, or window for which help is requested.

Return Value

Returns TRUE.

Remarks

The DefWindowProc function passes WM_HELP to the parent window of a child window or to the owner of a top-level window.

See Also

DefWindowProc, HELPINFO


WM_HOTKEY
WM_HOTKEY  QuickInfo  Overview  Group

WM_HOTKEY

idHotKey = (int) wParam;              // identifier of hot key

fuModifiers = (UINT) LOWORD(lParam);  // key-modifier flags

uVirtKey = (UINT) HIWORD(lParam);     // virtual-key code

The WM_HOTKEY message is posted when the user presses a hot key registered by the RegisterHotKey function. The message is placed at the top of the message queue associated with the thread that registered the hot key.

Parameters

idHotKey

Value of wParam. Specifies the identifier of the hot key that generated the message. If the message was generated by a system-defined hot key, the idHotKey parameter will be one of the following values:

Value	Meaning
IDHOT_SNAPDESKTOP	The "snap desktop" hot key was pressed.
IDHOT_SNAPWINDOW	The "snap window" hot key was pressed.
fuModifiers

Specifies the keys that were to be pressed in combination with the key specified by the nVirtKey parameter to generate the WM_HOTKEY message. The fuModifiers parameter can be a combination of the following values:

Value	Meaning
MOD_ALT	Either ALT key was held down.
MOD_CONTROL	Either CTRL key was held down.
MOD_SHIFT	Either SHIFT key was held down.
MOD_WIN	Either WINDOWS key was held down. These keys appear only on the Microsoft Ergonomic Keyboard and are labeled with the Microsoft Windows logo.
uVirtKey

Specifies the virtual key code of the hot key.

Remarks

WM_HOTKEY is unrelated to the WM_GETHOTKEY and WM_SETHOTKEY hot keys. The WM_HOTKEY message is sent for generic hot keys while the WM_SET\GETHOTKEY messages relate to window activation hot keys.

See Also

RegisterHotKey, WM_GETHOTKEY, WM_SETHOTKEY


WM_HSCROLL
WM_HSCROLL  QuickInfo  Overview  Group

WM_HSCROLL

nScrollCode = (int) LOWORD(wParam);  // scroll bar value

nPos = (short int) HIWORD(wParam);   // scroll box position

hwndScrollBar = (HWND) lParam;       // handle of scroll bar

The WM_HSCROLL message is sent to a window when a scroll event occurs in the window's standard horizontal scroll bar. This message is also sent to the owner of a horizontal scroll bar control when a scroll event occurs in the control.

Parameters

nScrollCode

Value of the low-order word of wParam. Specifies a scroll bar value that indicates the user's scrolling request. This parameter can be one of the following values:

Value	Meaning
SB_BOTTOM	Scrolls to the lower right.
SB_ENDSCROLL	Ends scroll.
SB_LINELEFT	Scrolls left by one unit.
SB_LINERIGHT	Scrolls right by one unit.
SB_PAGELEFT	Scrolls left by the width of the window.
SB_PAGERIGHT	Scrolls right by the width of the window.
SB_THUMBPOSITION	Scrolls to the absolute position. The current position is specified by the nPos parameter.
SB_THUMBTRACK	Drags scroll box to the specified position. The current position is specified by the nPos parameter.
SB_TOP	Scrolls to the upper left.
nPos

Value of the high-order word of wParam. Specifies the current position of the scroll box if the nScrollCode parameter is SB_THUMBPOSITION or SB_THUMBTRACK; otherwise, nPos is not used.

hwndScrollBar

Value of lParam. Identifies the control if WM_HSCROLL is sent by a scroll bar control. If WM_HSCROLL is sent by a window's standard scroll bar, hwndScrollBar is not used.

Return Value

If an application processes this message, it should return zero.

Remarks

The SB_THUMBTRACK notification message is typically used by applications that provide feedback as the user drags the scroll box.

If an application scrolls the content of the window, it must also reset the position of the scroll box by using the SetScrollPos function.

Note that the WM_HSCROLL message carries only 16 bits of scroll box position data. Thus, applications that rely solely on WM_HSCROLL (and WM_VSCROLL) for scroll position data have a practical maximum position value of 65,535.

However, because the SetScrollPos, SetScrollRange, GetScrollPos, and GetScrollRange functions support 32-bit scroll bar position data, there is a way to circumvent the 16-bit barrier of the WM_HSCROLL and WM_VSCROLL messages. See GetScrollPos for a description of the technique and its limits.

See Also

GetScrollPos, GetScrollRange, SetScrollPos, SetScrollRange, WM_VSCROLL


WM_HSCROLLCLIPBOARD
WM_HSCROLLCLIPBOARD  QuickInfo  Overview  Group

WM_HSCROLLCLIPBOARD

hwndViewer = (HWND) wParam;         // handle of clipboard viewer window

nScrollCode = (int) LOWORD(lParam); // scroll bar code

nPos = (int) HIWORD(lParam);        // scroll box position

The WM_HSCROLLCLIPBOARD message is sent to the clipboard owner by a clipboard viewer window. This occurs when the clipboard contains data in the CF_OWNERDISPLAY format and an event occurs in the clipboard viewer's horizontal scroll bar. The owner should scroll the clipboard image and update the scroll bar values.

Parameters

hwndViewer

Value of wParam. Identifies the clipboard viewer window.

nScrollCode

Value of the low-order word of lParam. Specifies a scroll bar event. This parameter can be one of the following values:

Value	Meaning
SB_BOTTOM	Scroll to lower right.
SB_ENDSCROLL	End scroll.
SB_LINEDOWN	Scroll one line down.
SB_LINEUP	Scroll one line up.
SB_PAGEDOWN	Scroll one page down.
SB_PAGEUP	Scroll one page up.
SB_THUMBPOSITION	Scroll to absolute position. The current position is specified by the nPos parameter.
SB_TOP	Scroll to upper left.
nPos

Value of the high-order word of lParam. Specifies the current position of the scroll box if the nScrollCode parameter is SB_THUMBPOSITION; otherwise, the nPos parameter is not used.

Return Value

If an application processes this message, it should return zero.

Remarks

The clipboard owner can use the ScrollWindow function to scroll the image in the clipboard viewer window and invalidate the appropriate region.

See Also

ScrollWindow


WM_ICONERASEBKGND
WM_ICONERASEBKGND  QuickInfo  Overview  Group

WM_ICONERASEBKGND

hdc = (HDC) wParam; // handle of device context

The WM_ICONERASEBKGND message is sent to a minimized window when the background of the icon must be filled before painting the icon. A window receives this message only if a class icon is defined for the window; otherwise, WM_ERASEBKGND is sent.

Parameters

hdc

Value of wParam. Identifies the device context of the icon.

Return Value

An application should return nonzero if it processes this message.

Remarks

The DefWindowProc function fills the icon background with the class background brush of the parent window.

See Also

DefWindowProc, WM_ERASEBKGND


WM_IME_CHAR [New - Windows 95]
WM_IME_CHAR  QuickInfo  Overview  Group

[New - Windows 95]

chCharCode1 = (TCHAR) wParam;
chCharCode2 = (TCHAR) wParam>>8;
lKeyData = lParam;

The WM_IME_CHAR message is sent to an application when the IME gets a character of the conversion result. Unlike the WM_CHAR message, this message can include double-byte as well as single-byte character values.

Parameters

chCharCode1 and chCharCode2

Single- or double-byte character value.

lKeyData

Repeat count, scan code, extended-key flag, context code, previous key-state flag, and transition-state flag, as shown following:

Bit	Meaning
0 - 15	Repeat count: Since the first byte and second byte is continuous, this is always 1.
16 - 23	Scan Code: Scan code for complete a FE character.
24 - 28	Not used.
29	Context code.
31	Conversion state.
Remarks

If the WM_IME_CHAR message includes a double-byte character, the DefWindowProc function converts this message into two WM_CHAR messages, each containing one byte of the double-byte character.

See Also

DefWindowProc, WM_CHAR


WM_IME_COMPOSITION [New - Windows 95]
WM_IME_COMPOSITION  QuickInfo  Overview  Group

[New - Windows 95]

chDBCS = (WORD) wParam;
fFlags = (BOOL) lParam;

The WM_IME_COMPOSITION message is sent to an application when the IME changes composition status as a result of a key stroke. An application should process this message if it displays composition characters itself. Otherwise, it should send the message to the IME window.

Parameters

chDBCS

DBCS character representing the latest change to the composition string.

fFlags

Change flag, indicating how the composition string or character changed. This parameter can be one or more of the following values:

GCS_COMPSTR	GCS_SETCURSORPOS
GCS_COMPATTR	GCS_RESULTSTR
GCS_COMPCLAUSE	GCS_RESULTCLAUSE
GCS_COMPREADSTR	GCS_RESULTREADSTR
GCS_COMPREADATTR	GCS_RESULTREADCLAUSE
GCS_COMPREADCLAUSE	GCR_ERRORSTR
GCS_TYPINGINFO	GCR_INFOSTR
Return Value

No return value.

Remarks

For more information about these values, see the "IME Composition String Values" table in Input Method Editor Constants.

The fFlags parameter can also be a combination of the following values:

Value	Meaning
CS_INSERTCHAR	Specifies that the given composition character should be inserted at the current insertion point. An application should display the composition character if it processes this message.
CS_NOMOVECARET	Specifies that the application must not move the caret position as a result of processing the message. For example, if an IME specifies a combination of CS_INSERTCHAR and CS_NOMOVECARET, the application should insert the given character at the current caret position but should not move caret to the next position. A subsequent WM_IME_COMPOSITION message with GCS_RESULTSTR will replace this character.
If the application has created an IME window, it should pass this message to that window. The DefWindowProc function processes this message by passing it to the default IME window.The IME window processes this message by updating its appearance based on the change flag given. An application can call ImmGetCompositionString to retrieve the new composition status.

If none of the GCS_ values are set, the message indicates that the current composition has been canceled and applications that draw the composition string should delete the string.

See Also

DefWindowProc, ImmGetCompositionString


WM_IME_COMPOSITIONFULL(preliminary-Windows 95) [New - Windows 95]
WM_IME_COMPOSITIONFULL  QuickInfo  Overview  Group

[New - Windows 95]

The WM_IME_COMPOSITIONFULL message is sent to an application when the IME window finds no space to extend the area for the composition window. The application should use the IMC_SETCOMPOSITIONWINDOW message to specify how to display the window.

Return Value

No return value.

Remarks

The wParam and lParam parameters are not used. The IME window, not the IME, sends this notification message by using the SendMessage message.

See Also

IMC_SETCOMPOSITIONWINDOW, SendMessage


WM_IME_CONTROL [New - Windows 95]
WM_IME_CONTROL  QuickInfo  Overview  Group

[New - Windows 95]

wParam = (WPARAM) (DWORD) dwCommand;
lParam = (LPARAM) (DWORD) dwData;

The WM_IME_CONTROL message directs the IME window to carry out the requested command. An application uses this message to control the IME window created by the application.

Parameters

dwCommand

Command value. This parameter can be one of the following values:

IMC_GETCANDIDATEPOS	IMC_OPENSTATUSWINDOW
IMC_GETCOMPOSITIONFONT	IMC_SETCANDIDATEPOS
IMC_GETCOMPOSITIONWINDOW	IMC_SETCOMPOSITIONFONT
IMC_GETCONVERSIONMODE	IMC_SETCOMPOSITIONWINDOW
IMC_GETOPENSTATUS	IMC_SETCONVERSIONMODE
IMC_GETSENTENCEMODE	IMC_SETOPENSTATUS
IMC_GETSTATUSWINDOWPOS	IMC_SETSENTENCEMODE
IMC_CLOSESTATUSWINDOW	IMC_SETSTATUSWINDOWPOS
For more information about these commands, see the individual descriptions.

dwData

Command-specific value.

Return Value

Returns a command-specific value.

See Also

IMC_CLOSESTATUSWINDOW, IMC_GETCANDIDATEPOS, IMC_GETCOMPOSITIONFONT, IMC_GETCOMPOSITIONWINDOW, IMC_GETCONVERSIONMODE, IMC_GETOPENSTATUS, IMC_GETSENTENCEMODE, IMC_GETSTATUSWINDOWPOS, IMC_OPENSTATUSWINDOW, IMC_SETCANDIDATEPOS, IMC_SETCOMPOSITIONFONT, IMC_SETCOMPOSITIONWINDOW, IMC_SETCONVERSIONMODE, IMC_SETOPENSTATUS, IMC_SETSENTENCEMODE, IMC_SETSTATUSWINDOWPOS


WM_IME_ENDCOMPOSITION(preliminary-Windows 95) [New - Windows 95]
WM_IME_ENDCOMPOSITION  QuickInfo  Overview  Group

[New - Windows 95]

The WM_IME_ENDCOMPOSITION message is sent to an application when the IME ends composition. An application should process this message if it displays composition characters itself.

Return Value

No return value.

Remarks

The wParam and lParam parameters are not used.

If an application has created an IME window, it should pass this message to that window. The DefWindowProc function processes this message by passing it to default IME window.

See Also

DefWindowProc


WM_IME_KEYDOWN
WM_IME_KEYDOWN  QuickInfo

nVirtKey = (int) wParam;    // virtual-key code
lKeyData = lParam;          // key data

The WM_IME_KEYDOWN message is sent to an application by the IME to notify the application of a key press. The parameters and return value for this message are identical to the WM_KEYDOWN message. An application can process this message or pass it to the DefWindowProc function to generate a matching WM_KEYDOWN message. This message is usually generated by the IME to keep message order.

See Also

DefWindowProc


WM_IME_KEYUP
WM_IME_KEYUP  QuickInfo

nVirtKey = (int) wParam;    // virtual-key code
lKeyData = lParam;          // key data

The WM_IME_KEYUP message is sent to an application by the IME to notify the application of a key release. The parameters and return value for this message are identical to the WM_KEYUP message. An application can process this message or pass it to the DefWindowProc function to generate a matching WM_KEYUP message. This message is usually generated by the IME to keep message order.

See Also

DefWindowProc


WM_IME_NOTIFY [New - Windows 95]
WM_IME_NOTIFY  QuickInfo  Overview  Group

[New - Windows 95]

dwCommand = (DWORD) wParam;
dwData = (DWORD) lParam;

The WM_IME_NOTIFY message is sent to an application to notify it of changes to the IME window. An application processes this message if it is responsible for managing the IME window.

Parameters

dwCommand

Command value. This parameter may be one of the following values:

IMN_CHANGECANDIDATE	IMN_SETCANDIDATEPOS
IMN_CLOSECANDIDATE	IMN_SETCOMPOSITIONFONT
IMN_CLOSESTATUSWINDOW	IMN_SETCOMPOSITIONWINDOW
IMN_GUIDELINE	IMN_SETCONVERSIONMODE
IMN_OPENCANDIDATE	IMN_SETOPENSTATUS
IMN_OPENSTATUSWINDOW	IMN_SETSENTENCEMODE
IMN_PRIVATE	IMN_SETSTATUSWINDOWPOS
For more information about these commands, see the corresponding descriptions.

dwData

Command-specific value.

Return Value

Returns a command-specific value.

IMN_CHANGECANDIDATE, IMN_OPENCANDIDATE, IMN_OPENSTATUSWINDOW, IMN_SETCANDIDATEPOS, IMN_SETCOMPOSITIONFONT, IMN_SETCOMPOSITIONWINDOW, IMN_SETCONVERSIONMODE, IMN_SETOPENSTATUS, IMN_SETSENTENCEMODE, IMN_SETSTATUSWINDOWPOS


WM_IME_SELECT [New - Windows 95]
WM_IME_SELECT  QuickInfo  Overview  Group

[New - Windows 95]

fSeleft = (BOOL) wParam;
hKL = (HANDLE) lParam;

The WM_IME_SELECT message is sent to an application when the system is about to change the current IME. An application that has created an IME window should pass this message to that window so that it can retrieve the keyboard layout handle for the newly selected IME.

Parameters

fSelect

Selection flag. If TRUE, the specified IME is selected; if FALSE, the specified IME is no longer selected.

hKL

Handle to the keyboard layout associated with the IME.

Return Value

No return value.

Remarks

The DefWindowProc function processes this message by passing the information to the default IME window.

See Also

DefWindowProc


WM_IME_SETCONTEXT [New - Windows 95]
WM_IME_SETCONTEXT  QuickInfo  Overview  Group

[New - Windows 95]

fSet = (BOOL) wParam;
iShow = (DWORD) lParam;

The WM_IME_SETCONTEXT message is sent to an application when a window of the application is activated. If the application has created an IME window, it should call the ImmIsUIMessage function. Otherwise, it should pass this message to the DefWindowProc function.

Parameters

fSet

Active flag. If TRUE, the input context is active. If FALSE, the context is inactive.

iShow

Show flags. Can be a combination of the following values:

Value	Description
ISC_SHOWUICOMPOSITIONWINDOW	Shows the composition window by UI window.
ISC_SHOWUIGUIDWINDOW	Shows the guide window by UI window
ISC_SHOWUISOFTKBD	Shows the soft keyboard by UI window
ISC_SHOWUICANDIDATEWINDOW	Shows the candidate window of Index 0 by UI window.
ISC_SHOWUICANDIDATEWINDOW << 1	Shows the candidate window of Index 1 by UI window.
ISC_SHOWUICANDIDATEWINDOW << 2	Shows the candidate window of Index 2 by UI window.
ISC_SHOWUICANDIDATEWINDOW << 3	Shows the candidate window of Index 3 by UI window.
If the application draws the composition window, the default IME window does not need to show its composition window. In this case, the application must clear the ISC_SHOWUICOMPOSITIONWINDOW value from the lParam parameter before passing the message to the DefWindowProc or ImmIsUIMessage functions.

Return Value

Returns the value returned by DefWindowProc or ImmIsUIMessage.

See Also

DefWindowProc, ImmIsUIMessage


WM_IME_STARTCOMPOSITION(preliminary-Windows 95) [New - Windows 95]
WM_IME_STARTCOMPOSITION  QuickInfo  Overview  Group

[New - Windows 95]

The WM_IME_STARTCOMPOSITION message is sent immediately before the IME generates composition string as a result of a key stroke. The message is a notification to an IME window to open its composition window. An application should process this message if it displays composition characters itself.

Return Value

No return value.

Remarks

The wParam and lParam parameters are not used.

If an application has created an IME window, it should pass the WM_IME_STARTCOMPOSITION message to that window. The DefWindowProc function processes this message by passing it to the default IME window.

See Also

DefWindowProc


WM_INITDIALOG
WM_INITDIALOG  QuickInfo  Overview  Group

WM_INITDIALOG

hwndFocus = (HWND) wParam; // handle of control to receive focus

lInitParam = lParam;       // initialization parameter

The WM_INITDIALOG message is sent to the dialog box procedure immediately before a dialog box is displayed. Dialog box procedures typically use this message to initialize controls and carry out any other initialization tasks that affect the appearance of the dialog box.

Parameters

hwndFocus

Value of wParam. Identifies the control to receive the default keyboard focus. Windows assigns the default keyboard focus only if the dialog box procedure returns TRUE.

lInitParam

Value of lParam. Specifies additional initialization data. This data is passed to Windows as the lParamInit parameter in a call to the CreateDialogIndirectParam, CreateDialogParam, DialogBoxIndirectParam, or DialogBoxParam function used to create the dialog box. This parameter is zero if any other dialog box creation function is used.

Return Value

The dialog box procedure should return TRUE to direct Windows to set the keyboard focus to the control given by hwndFocus. Otherwise, it should return FALSE to prevent Windows from setting the default keyboard focus.

Remarks

The control to receive the default keyboard focus is always the first control in the dialog box that is visible, not disabled, and that has the WS_TABSTOP style. When the dialog box procedure returns TRUE, Windows checks the control to ensure that the procedure has not disabled it. If it has been disabled, Windows sets the keyboard focus to the next control that is visible, not disabled, and has the WS_TABSTOP.

An application can return FALSE only if it has set the keyboard focus to one of the controls of the dialog box.

See Also

CreateDialogIndirectParam, CreateDialogParam, DialogBoxIndirectParam, DialogBoxParam, SetFocus


WM_INITMENU
WM_INITMENU  QuickInfo  Overview  Group

WM_INITMENU

hmenuInit = (HMENU) wParam; // handle of menu to initialize

The WM_INITMENU message is sent when a menu is about to become active. It occurs when the user clicks an item on the menu bar or presses a menu key. This allows the application to modify the menu before it is displayed.

Parameters

hmenuInit

Value of wParam. Identifies the menu to be initialized.

Return Value

If an application processes this message, it should return zero.

Remarks

A WM_INITMENU message is sent only when a menu is first accessed; only one WM_INITMENU message is generated for each access. For example, moving the mouse across several menu items while holding down the button does not generate new messages. WM_INITMENU does not provide information about menu items.

See Also

WM_INITMENUPOPUP


WM_INITMENUPOPUP
WM_INITMENUPOPUP  QuickInfo  Overview  Group

WM_INITMENUPOPUP

hmenuPopup = (HMENU) wParam;         // handle of pop-up menu

uPos = (UINT) LOWORD(lParam);        // pop-up item position

fSystemMenu = (BOOL) HIWORD(lParam); // System menu flag

The WM_INITMENUPOPUP message is sent when a pop-up menu is about to become active. This allows an application to modify the pop-up menu before it is displayed, without changing the entire menu.

Parameters

hmenuPopup

Value of wParam. Identifies the pop-up menu.

uPos

Value of the low-order word of lParam. Specifies the zero-based relative position of the menu item that invokes the pop-up menu.

fSystemMenu

Value of the high-order word of lParam. Specifies whether the pop-up menu is the System menu. If the pop-up menu is the System menu (also known as Control menu), this parameter is TRUE; otherwise, it is FALSE.

Return Value

If an application processes this message, it should return zero.

See Also

WM_INITMENU


WM_INPUTLANGCHANGE [New - Windows 95]
WM_INPUTLANGCHANGE

[New - Windows 95]

WM_INPUTLANGCHANGE
charset = wParam;
hkl = (HKL) lParam;

The WM_INPUTLANGCHANGE message is sent to the topmost affected window after a task's locale has been changed. It should be used to make any application-specific settings and passed on to the DefWindowProc function to be passed on to any children.

Parameters

charset

Value of wParam. Specifies the character set of the new keyboard layout.

hkl

Value of lParam. Identifies the new keyboard layout.

Return Value

An application should return nonzero if it processes this message.

See Also

DefWindowProc, WM_INPUTLANGCHANGEREQUEST


WM_INPUTLANGCHANGEREQUEST [New - Windows 95]
WM_INPUTLANGCHANGEREQUEST

[New - Windows 95]

WM_INPUTLANGCHANGEREQUEST
fSysCharSet = (BOOL) wParam

hkl = (HKL) lParam;

The WM_INPUTLANGCHANGEREQUEST message is sent when the user chooses an input language, either with an input language change hotkey or from the system languages menu. An application can accept the change by passing the message to the DefWindowProc function or reject the change (and prevent it from taking place) by returning immediately.

Parameters

wParam

This parameter is TRUE if the handle of the keyboard layout can be used with the system character set. For example, in the Russian-language version of Windows 95, this parameter is TRUE for keyboard layout handles for English (US) and Russian, but FALSE for other handles.

hkl

Value of lParam. Identifies the keyboard layout to switch to.

Return Value

The application should return nonzero if it processes this message. It should return zero to reject the change.

See Also

DefWindowProc, WM_INPUTLANGCHANGE


WM_KEYDOWN
WM_KEYDOWN  QuickInfo  Overview  Group

WM_KEYDOWN

nVirtKey = (int) wParam;    // virtual-key code

lKeyData = lParam;          // key data

The WM_KEYDOWN message is posted to the window with the keyboard focus when a nonsystem key is pressed. A nonsystem key is a key that is pressed when the ALT key is not pressed.

Parameters

nVirtKey

Value of wParam. Specifies the virtual-key code of the nonsystem key.

lKeyData

Value of lParam. Specifies the repeat count, scan code, extended-key flag, context code, previous key-state flag, and transition-state flag, as shown in the following table:

Value	Description
0−15	Specifies the repeat count. The value is the number of times the keystroke is repeated as a result of the user holding down the key.
16−23	Specifies the scan code. The value depends on the original equipment manufacturer (OEM).
24	Specifies whether the key is an extended key, such as the right-hand ALT and CTRL keys that appear on an enhanced 101- or 102-key keyboard. The value is 1 if it is an extended key; otherwise, it is 0.
25−28	Reserved; do not use.
29	Specifies the context code. The value is always 0 for a WM_KEYDOWN message.
30	Specifies the previous key state. The value is 1 if the key is down before the message is sent, or it is 0 if the key is up.
31	Specifies the transition state. The value is always 0 for a WM_KEYDOWN message.
Return Value

An application should return zero if it processes this message.

Default Action

If the F10 key is pressed, the DefWindowProc function sets an internal flag. When DefWindowProc receives the WM_KEYUP message, the function checks whether the internal flag is set and, if so, sends a WM_SYSCOMMAND message to the top-level window. The wParam parameter of the message is set to SC_KEYMENU.

Remarks

Because of the autorepeat feature, more than one WM_KEYDOWN message may be posted before a WM_KEYUP message is posted. The previous key state (bit 30) can be used to determine whether the WM_KEYDOWN message indicates the first down transition or a repeated down transition.

For enhanced 101- and 102-key keyboards, extended keys are the right ALT and CTRL keys on the main section of the keyboard; the INS, DEL, HOME, END, PAGE UP, PAGE DOWN and arrow keys in the clusters to the left of the numeric keypad; and the divide (/) and ENTER keys in the numeric keypad. Other keyboards may support the extended-key bit in the lKeyData parameter.

See Also

DefWindowProc, WM_CHAR, WM_KEYUP, WM_SYSCOMMAND


WM_KEYUP
WM_KEYUP  QuickInfo  Overview  Group

WM_KEYUP

nVirtKey = (int) wParam;    // virtual-key code

lKeyData = lParam;          // key data

The WM_KEYUP message is posted to the window with the keyboard focus when a nonsystem key is released. A nonsystem key is a key that is pressed when the ALT key is not pressed, or a keyboard key that is pressed when a window has the keyboard focus.

Parameters

nVirtKey

Value of wParam. Specifies the virtual-key code of the nonsystem key.

lKeyData

Value of lParam. Specifies the repeat count, scan code, extended-key flag, context code, previous key-state flag, and transition-state flag, as shown in the following table:

Value	Description
0−15	Specifies the repeat count. The value is the number of times the keystroke is repeated as a result of the user holding down the key. The repeat count is always one for a WM_KEYUP message.
16−23	Specifies the scan code. The value depends on the original equipment manufacturer (OEM).
24	Specifies whether the key is an extended key, such as the right-hand ALT and CTRL keys that appear on an enhanced 101- or 102-key keyboard. The value is 1 if it is an extended key; otherwise, it is 0.
25−28	Reserved; do not use.
29	Specifies the context code. The value is always 0 for a WM_KEYUP message.
30	Specifies the previous key state. The value is always 1 for a WM_KEYUP message.
31	Specifies the transition state. The value is always 1 for a WM_KEYUP message.
Return Value

An application should return zero if it processes this message.

Default Action

The DefWindowProc function sends a WM_SYSCOMMAND message to the top-level window if the F10 key or the ALT key was released. The wParam parameter of the message is set to SC_KEYMENU.

Remarks

For enhanced 101- and 102-key keyboards, extended keys are the right ALT and CTRL keys on the main section of the keyboard; the INS, DEL, HOME, END, PAGE UP, PAGE DOWN and arrow keys in the clusters to the left of the numeric keypad; and the divide (/) and ENTER keys in the numeric keypad. Other keyboards may support the extended-key bit in the lKeyData parameter.

See Also

DefWindowProc, WM_KEYDOWN, WM_SYSCOMMAND


WM_KILLFOCUS
WM_KILLFOCUS  QuickInfo  Overview  Group

WM_KILLFOCUS

hwndGetFocus = (HWND) wParam; // handle of window receiving focus

The WM_KILLFOCUS message is sent to a window immediately before it loses the keyboard focus.

Parameters

hwndGetFocus

Value of wParam. Identifies the window that receives the keyboard focus (may be NULL).

Return Value

An application should return zero if it processes this message.

Remarks

If an application is displaying a caret, the caret should be destroyed at this point.

See Also

SetFocus, WM_SETFOCUS


WM_LBUTTONDBLCLK
WM_LBUTTONDBLCLK  QuickInfo  Overview  Group

WM_LBUTTONDBLCLK

fwKeys = wParam;        // key flags

xPos = LOWORD(lParam);  // horizontal position of cursor

yPos = HIWORD(lParam);  // vertical position of cursor

The WM_LBUTTONDBLCLK message is posted when the user double-clicks the left mouse button while the cursor is in the client area of a window. If the mouse is not captured, the message is posted to the window beneath the cursor. Otherwise, the message is posted to the window that has captured the mouse.

Parameters

fwKeys

Value of wParam. Indicates whether various virtual keys are down. This parameter can be any combination of the following values:

Value	Description
MK_CONTROL	Set if the CTRL key is down.
MK_LBUTTON	Set if the left mouse button is down.
MK_MBUTTON	Set if the middle mouse button is down.
MK_RBUTTON	Set if the right mouse button is down.
MK_SHIFT	Set if the SHIFT key is down.
xPos

Value of the low-order word of lParam. Specifies the x-coordinate of the cursor. The coordinate is relative to the upper-left corner of the client area.

yPos

Value of the high-order word of lParam. Specifies the y-coordinate of the cursor. The coordinate is relative to the upper-left corner of the client area.

Return Value

If an application processes this message, it should return zero.

Remarks

Only windows that have the CS_DBLCLKS style can receive WM_LBUTTONDBLCLK messages, which Windows generates whenever the user presses, releases, and again presses the left mouse button within the system's double-click time limit. Double-clicking the left mouse button actually generates four messages: WM_LBUTTONDOWN, WM_LBUTTONUP, WM_LBUTTONDBLCLK, and WM_LBUTTONUP again.

An application can use the MAKEPOINTS macro to convert the lParam parameter to a POINTS structure.

See Also

GetCapture, GetDoubleClickTime, MAKEPOINTS, POINTS, SetCapture, SetDoubleClickTime, WM_LBUTTONDOWN, WM_LBUTTONUP


WM_LBUTTONDOWN
WM_LBUTTONDOWN  QuickInfo  Overview  Group

WM_LBUTTONDOWN

fwKeys = wParam;        // key flags

xPos = LOWORD(lParam);  // horizontal position of cursor

yPos = HIWORD(lParam);  // vertical position of cursor

The WM_LBUTTONDOWN message is posted when the user presses the left mouse button while the cursor is in the client area of a window. If the mouse is not captured, the message is posted to the window beneath the cursor. Otherwise, the message is posted to the window that has captured the mouse.

Parameters

fwKeys

Value of wParam. Indicates whether various virtual keys are down. This parameter can be any combination of the following values:

Value	Description
MK_CONTROL	Set if the CTRL key is down.
MK_LBUTTON	Set if the left mouse button is down.
MK_MBUTTON	Set if the middle mouse button is down.
MK_RBUTTON	Set if the right mouse button is down.
MK_SHIFT	Set if the SHIFT key is down.
xPos

Value of the low-order word of lParam. Specifies the x-coordinate of the cursor. The coordinate is relative to the upper-left corner of the client area.

yPos

Value of the high-order word of lParam. Specifies the y-coordinate of the cursor. The coordinate is relative to the upper-left corner of the client area.

Return Value

If an application processes this message, it should return zero.

Remarks

An application can use the MAKEPOINTS macro to convert the lParam parameter to a POINTS structure.

See Also

GetCapture, MAKEPOINTS, POINTS, SetCapture, WM_LBUTTONDBLCLK, WM_LBUTTONUP


WM_LBUTTONUP
WM_LBUTTONUP  QuickInfo  Overview  Group

WM_LBUTTONUP

fwKeys = wParam;        // key flags

xPos = LOWORD(lParam);  // horizontal position of cursor

yPos = HIWORD(lParam);  // vertical position of cursor

The WM_LBUTTONUP message is posted when the user releases the left mouse button while the cursor is in the client area of a window. If the mouse is not captured, the message is posted to the window beneath the cursor. Otherwise, the message is posted to the window that has captured the mouse.

Parameters

fwKeys

Value of wParam. Indicates whether various virtual keys are down. This parameter can be any combination of the following values:

Value	Description
MK_CONTROL	Set if the CTRL key is down.
MK_MBUTTON	Set if the middle mouse button is down.
MK_RBUTTON	Set if the right mouse button is down.
MK_SHIFT	Set if the SHIFT key is down.
xPos

Value of the low-order word of lParam. Specifies the x-coordinate of the cursor. The coordinate is relative to the upper-left corner of the client area.

yPos

Value of the high-order word of lParam. Specifies the y-coordinate of the cursor. The coordinate is relative to the upper-left corner of the client area.

Return Value

If an application processes this message, it should return zero.

Remarks

An application can use the MAKEPOINTS macro to convert the lParam parameter to a POINTS structure.

See Also

GetCapture, MAKEPOINTS, POINTS, SetCapture, WM_LBUTTONDBLCLK, WM_LBUTTONDOWN


WM_MBUTTONDBLCLK
WM_MBUTTONDBLCLK  QuickInfo  Overview  Group

WM_MBUTTONDBLCLK

fwKeys = wParam;        // key flags

xPos = LOWORD(lParam);  // horizontal position of cursor

yPos = HIWORD(lParam);  // vertical position of cursor

The WM_MBUTTONDBLCLK message is posted when the user double-clicks the middle mouse button while the cursor is in the client area of a window. If the mouse is not captured, the message is posted to the window beneath the cursor. Otherwise, the message is posted to the window that has captured the mouse.

Parameters

fwKeys

Value of wParam. Indicates whether various virtual keys are down. This parameter can be any combination of the following values:

Value	Description
MK_CONTROL	Set if the CTRL key is down.
MK_LBUTTON	Set if the left mouse button is down.
MK_MBUTTON	Set if the middle mouse button is down.
MK_RBUTTON	Set if the right mouse button is down.
MK_SHIFT	Set if the SHIFT key is down.
xPos

Value of the low-order word of lParam. Specifies the x-coordinate of the cursor. The coordinate is relative to the upper-left corner of the client area.

yPos

Value of the high-order word of lParam. Specifies the y-coordinate of the cursor. The coordinate is relative to the upper-left corner of the client area.

Return Value

If an application processes this message, it should return zero.

Remarks

Only windows that have the CS_DBLCLKS style can receive WM_MBUTTONDBLCLK messages, which Windows generates whenever the user presses, releases, and again presses the middle mouse button within the system's double-click time limit. Double-clicking the middle mouse button actually generates four messages: WM_MBUTTONDOWN, WM_MBUTTONUP, WM_MBUTTONDBLCLK, and WM_MBUTTONUP again.

An application can use the MAKEPOINTS macro to convert the lParam parameter to a POINTS structure.

See Also

GetCapture, GetDoubleClickTime, MAKEPOINTS, POINTS, SetCapture, SetDoubleClickTime, WM_MBUTTONDOWN, WM_MBUTTONUP


WM_MBUTTONDOWN
WM_MBUTTONDOWN  QuickInfo  Overview  Group

WM_MBUTTONDOWN

fwKeys = wParam;        // key flags

xPos = LOWORD(lParam);  // horizontal position of cursor

yPos = HIWORD(lParam);  // vertical position of cursor

The WM_MBUTTONDOWN message is posted when the user presses the middle mouse button while the cursor is in the client area of a window. If the mouse is not captured, the message is posted to the window beneath the cursor. Otherwise, the message is posted to the window that has captured the mouse.

Parameters

fwKeys

Value of wParam. Indicates whether various virtual keys are down. This parameter can be any combination of the following values:

Value	Description
MK_CONTROL	Set if the CTRL key is down.
MK_LBUTTON	Set if the left mouse button is down.
MK_MBUTTON	Set if the middle mouse button is down.
MK_RBUTTON	Set if the right mouse button is down.
MK_SHIFT	Set if the SHIFT key is down.
xPos

Value of the low-order word of lParam. Specifies the x-coordinate of the cursor. The coordinate is relative to the upper-left corner of the client area.

yPos

Value of the high-order word of lParam. Specifies the y-coordinate of the cursor. The coordinate is relative to the upper-left corner of the client area.

Return Value

If an application processes this message, it should return zero.

Remarks

An application can use the MAKEPOINTS macro to convert the lParam parameter to a POINTS structure.

See Also

GetCapture, MAKEPOINTS, POINTS, SetCapture, WM_MBUTTONDBLCLK, WM_MBUTTONUP


WM_MBUTTONUP
WM_MBUTTONUP  QuickInfo  Overview  Group

WM_MBUTTONUP

fwKeys = wParam;        // key flags

xPos = LOWORD(lParam);  // horizontal position of cursor

yPos = HIWORD(lParam);  // vertical position of cursor

The WM_MBUTTONUP message is posted when the user releases the middle mouse button while the cursor is in the client area of a window. If the mouse is not captured, the message is posted to the window beneath the cursor. Otherwise, the message is posted to the window that has captured the mouse.

Parameters

fwKeys

Value of wParam. Indicates whether various virtual keys are down. This parameter can be any combination of the following values:

Value	Description
MK_CONTROL	Set if the CTRL key is down.
MK_LBUTTON	Set if the left mouse button is down.
MK_RBUTTON	Set if the right mouse button is down.
MK_SHIFT	Set if the SHIFT key is down.
xPos

Value of the low-order word of lParam. Specifies the x-coordinate of the cursor. The coordinate is relative to the upper-left corner of the client area.

yPos

Value of the high-order word of lParam. Specifies the y-coordinate of the cursor. The coordinate is relative to the upper-left corner of the client area.

An application can use the MAKEPOINTS macro to convert the lParam parameter to a POINTS structure.

See Also

GetCapture, MAKEPOINTS, POINTS, SetCapture, WM_MBUTTONDBLCLK, WM_MBUTTONDOWN


WM_MDIACTIVATE
WM_MDIACTIVATE  QuickInfo  Overview  Group

WM_MDIACTIVATE

// Message sent to MDI client

wParam = (WPARAM) (HWND) hwndChildAct; // child to activate

lParam = 0;                            // not used; must be zero

// Message received by MDI child

hwndChildDeact = (HWND) wParam;        // child being deactivated

hwndChildAct = (HWND) lParam;          // child being activated

An application sends the WM_MDIACTIVATE message to a multiple document interface (MDI) client window to instruct the client window to activate a different MDI child window. As the client window processes this message, it sends WM_MDIACTIVATE to the child window being deactivated and to the child window being activated.

Parameters

In messages sent to an MDI client window:

hwndChildAct

Value of wParam. Identifies the MDI child window to be activated.

In messages received by an MDI child window:

hwndChildDeact

Value of wParam. Identifies the MDI child window being deactivated.

hwndChildAct

Value of lParam. Identifies the MDI child window being activated.

Return Value

If an application sends this message to an MDI client window, the return value is zero. An MDI child window should return zero if it processes this message.

Remarks

An MDI child window is activated independently of the MDI frame window. When the frame window becomes active, the child window last activated by using the WM_MDIACTIVATE message receives the WM_NCACTIVATE message to draw an active window frame and title bar; the child window does not receive another WM_MDIACTIVATE message.

See Also

WM_MDIGETACTIVE, WM_MDINEXT, WM_NCACTIVATE


WM_MDICASCADE
WM_MDICASCADE  QuickInfo  Overview  Group

WM_MDICASCADE

wParam = (WPARAM) (UINT) fuCascade;  // cascade flag

lParam = 0;                          // not used; must be zero

An application sends the WM_MDICASCADE message to a multiple document interface (MDI) client window to arrange all its child windows in a cascade format.

Parameters

fuCascade

Value of wParam. Specifies a cascade flag. The only flag currently available, MDITILE_SKIPDISABLED, prevents disabled MDI child windows from being cascaded.

Return Value

If the message succeeds, the return value is TRUE.

If the message fails, the return value is FALSE.

See Also

WM_MDIICONARRANGE, WM_MDITILE


WM_MDICREATE
WM_MDICREATE  QuickInfo  Overview  Group

WM_MDICREATE

wParam = 0;                                     // not used; must be zero

lParam = (LPARAM) (LPMDICREATESTRUCT) lpmdic;   // creation data

An application sends the WM_MDICREATE message to a multiple document interface (MDI) client window to create an MDI child window.

Parameters

lpmdic

Points to an MDICREATESTRUCT structure containing information that Windows uses to create the MDI child window.

Return Value

If the message succeeds, the return value is the handle of the new child window.

If the message fails, the return value is NULL.

Remarks

The MDI child window is created with the style bits WS_CHILD, WS_CLIPSIBLINGS, WS_CLIPCHILDREN, WS_SYSMENU, WS_CAPTION, WS_THICKFRAME, WS_MINIMIZEBOX, and WS_MAXIMIZEBOX, plus additional style bits specified in the MDICREATESTRUCT structure to which the lpmdic parameter points. Windows adds the title of the new child window to the Window menu of the frame window. An application should use this message to create all child windows of the client window.

If an MDI client window receives any message that changes the activation of its child windows while the active child window is maximized, Windows restores the active child window and maximizes the newly activated child window.

When an MDI child window is created, Windows sends the WM_CREATE message to the window. The lParam parameter of the WM_CREATE message contains a pointer to a CREATESTRUCT structure. The lpCreateParams member of this structure contains a pointer to the MDICREATESTRUCT structure passed with the WM_MDICREATE message that created the MDI child window.

An application should not send a second WM_MDICREATE message while a WM_MDICREATE message is still being processed. For example, it should not send a WM_MDICREATE message while an MDI child window is processing its WM_MDICREATE message.

See Also

CreateMDIWindow, CREATESTRUCT, MDICREATESTRUCT, WM_CREATE, WM_MDIDESTROY


WM_MDIDESTROY
WM_MDIDESTROY  QuickInfo  Overview  Group

WM_MDIDESTROY

wParam = (WPARAM) (HWND) hwndChild; // handle of child to close

lParam = 0;                         // not used; must be zero

An application sends the WM_MDIDESTROY message to a multiple document interface (MDI) client window to close an MDI child window.

Parameters

hwndChild

Value of wParam. Identifies the MDI child window to be closed.

Return Value

This message always returns zero.

Remarks

This message removes the title of the MDI child window from the MDI frame window and deactivates the child window. An application should use this message to close all MDI child windows.

If an MDI client window receives a message that changes the activation of its child windows and the active MDI child window is maximized, Windows restores the active child window and maximizes the newly activated child window.

See Also

WM_MDICREATE


WM_MDIGETACTIVE
WM_MDIGETACTIVE  QuickInfo  Overview  Group

WM_MDIGETACTIVE

wParam = 0;                      // not used; must be zero

lParam = (LPBOOL) lpfMaximized;  // optional pointer to maximized state flag

An application sends the WM_MDIGETACTIVE message to a multiple document interface (MDI) client window to retrieve the handle of the active MDI child window.

Parameters

lpfMaximized

Value of lparam. This is an optional pointer to a maximized state flag variable. If lpfMaximized is non-NULL, the BOOL it points to is set to indicate the maximized state of the MDI child window. TRUE indicates that the window is maximized, FALSE indicates that it is not. This is equivalent to the indication supplied by the high-order word of the return value of the WM_MDIGETACTIVE message under Windows version 3.x. If lpfMaximized is NULL, the parameter is ignored.

Return Value

The return value is the handle of the active MDI child window.

Remarks

Note carefully a change in how this message indicates maximization. In Windows version 3.x, the message return value includes a flag indicating whether the MDI child window is maximized. In the Win32 application programming interface (API), the return value does not include this flag. In Win32, the MDI child window's maximized state is indicated by setting a BOOL variable via the optional parameter in lParam, lpfMaximized.


WM_MDIICONARRANGE
WM_MDIICONARRANGE  QuickInfo  Overview  Group

WM_MDIICONARRANGE

wParam = 0; // not used; must be zero

lParam = 0; // not used; must be zero

An application sends the WM_MDIICONARRANGE message to a multiple document interface (MDI) client window to arrange all minimized MDI child windows. It does not affect child windows that are not minimized.

Parameters

This message has no parameters.

See Also

WM_MDICASCADE, WM_MDITILE


WM_MDIMAXIMIZE
WM_MDIMAXIMIZE  QuickInfo  Overview  Group

WM_MDIMAXIMIZE

wParam = (WPARAM) (HWND) hwndMax; // handle of child to maximize

lParam = 0;                       // not used; must be zero

An application sends the WM_MDIMAXIMIZE message to a multiple document interface (MDI) client window to maximize an MDI child window. Windows resizes the child window to make its client area fill the client window. Windows places the child window's System menu icon in the rightmost position of the frame window's menu bar, and places the child window's restore icon in the leftmost position. Windows also appends the title bar text of the child window to that of the frame window.

Parameters

hwndMax

Value of wParam. Identifies the MDI child window to be maximized.

Return Value

The return value is always zero.

Remarks

If an MDI client window receives any message that changes the activation of its child windows while the currently active MDI child window is maximized, Windows restores the active child window and maximizes the newly activated child window.

See Also

WM_MDIRESTORE


WM_MDINEXT
WM_MDINEXT  QuickInfo  Overview  Group

WM_MDINEXT

wParam = (WPARAM) (HWND) hwndChild; // handle of child

lParam = (LPARAM) fNext;            // next or previous child

An application sends the WM_MDINEXT message to a multiple document interface (MDI) client window to activate the next or previous child window.

Parameters

hwndChild

Value of wParam. Identifies the MDI child window. Windows activates the child window that is immediately before or after the given child window, depending on the value of the fNext parameter. If the hwndChild parameter is NULL, Windows activates the child window that is immediately before or after the currently active child window.

fNext

Value of lParam. If this parameter is zero, Windows activates the next MDI child window and places the child window identified by the hwndChild parameter behind all other child windows. If this parameter is nonzero, Windows activates the previous child window, placing it in front of the child window identified by hwndChild.

Return Value

The return value is always zero.

Remarks

If an MDI client window receives any message that changes the activation of its child windows while the active MDI child window is maximized, Windows restores the active child window and maximizes the newly activated child window.

See Also

WM_MDIACTIVATE, WM_MDIGETACTIVE


WM_MDIREFRESHMENU
WM_MDIREFRESHMENU  QuickInfo  Overview  Group

WM_MDIREFRESHMENU

wParam = 0; // not used; must be zero

lParam = 0; // not used; must be zero

An application sends the WM_MDIREFRESHMENU message to a multiple document interface (MDI) client window to refresh the Window menu of the MDI frame window.

Parameters

This message has no parameters.

Return Value

If the message succeeds, the return value is the handle of the frame window menu.

If the message fails, the return value is NULL.

Remarks

After sending this message, an application must call the DrawMenuBar function to update the menu bar.

See Also

DrawMenuBar, WM_MDISETMENU


WM_MDIRESTORE
WM_MDIRESTORE  QuickInfo  Overview  Group

WM_MDIRESTORE

wParam = (WPARAM) (HWND) hwndRes; // handle of child to restore

lParam = 0;                       // not used; must be zero

An application sends the WM_MDIRESTORE message to a multiple document interface (MDI) client window to restore an MDI child window from maximized or minimized size.

Parameters

hwndRes

Value of wParam. Identifies the MDI child window to be restored.

Return Value

The return value is always zero.

See Also

WM_MDIMAXIMIZE


WM_MDISETMENU
WM_MDISETMENU  QuickInfo  Overview  Group

WM_MDISETMENU

wParam = (WPARAM) (HMENU) hmenuFrame;  // handle of frame menu

lParam = (LPARAM) (HMENU) hmenuWindow; // handle of Window menu

An application sends the WM_MDISETMENU message to a multiple document interface (MDI) client window to replace the entire menu of an MDI frame window, to replace the Window menu of the frame window, or both.

Parameters

hmenuFrame

Value of wParam. Identifies the new frame window menu. If this parameter is NULL, the frame window menu is not changed.

hmenuWindow

Value of lParam. Identifies the new Window menu. If this parameter is NULL, the Window menu is not changed.

Return Value

If the message succeeds, the return value is the handle of the old frame window menu.

If the message fails, the return value is zero.

Remarks

After sending this message, an application must call the DrawMenuBar function to update the menu bar.

If this message replaces the Window menu, the MDI child window menu items are removed from the previous Window menu and added to the new Window menu.

If an MDI child window is maximized and this message replaces the MDI frame window menu, the System menu icon and restore icon are removed from the previous frame window menu and added to the new frame window menu.

See Also

DrawMenuBar, WM_MDIREFRESHMENU


WM_MDITILE
WM_MDITILE  QuickInfo  Overview  Group

WM_MDITILE

wParam = (WPARAM) (UINT) fuTile; // tiling flag

lParam = 0;                      // not used; must be zero

An application sends the WM_MDITILE message to a multiple document interface (MDI) client window to arrange all of its MDI child windows in a tile format.

Parameters

fuTile

Specifies a tiling flag. This parameter can be one of the following values:

Value	Meaning
MDITILE_HORIZONTAL	Tiles MDI child windows so that they are wide rather than tall.
MDITILE_SKIPDISABLED	Prevents disabled MDI child windows from being tiled.
MDITILE_VERTICAL	Tiles MDI child windows so that they are tall rather than wide.
Return Value

If the message succeeds, the return value is TRUE.

If the message fails, the return value is FALSE.

See Also

WM_MDICASCADE, WM_MDIICONARRANGE


WM_MEASUREITEM
WM_MEASUREITEM  QuickInfo  Overview  Group

WM_MEASUREITEM

idCtl = (UINT) wParam;                // control identifier

lpmis = (LPMEASUREITEMSTRUCT) lParam; // item-size information

The WM_MEASUREITEM message is sent to the owner window of an owner-drawn button, combo box, list box, list view control, or menu item when the control or menu is created.

Parameters

idCtl

Value of wParam. Contains the value of the CtlID member of the MEASUREITEMSTRUCT structure pointed to by the lpmis parameter. This value identifies the control that sent the WM_MEASUREITEM message.

If the value is zero, the message was sent by a menu. If the value is nonzero, the message was sent by a combo box or by a list box. If the value is nonzero, and the value of the itemID member of the MEASUREITEMSTRUCT pointed to by lpmis is (UINT) −1, the message was sent by a combo edit field.

lpmis

Value of lParam. Points to a MEASUREITEMSTRUCT structure that contains the dimensions of the owner-drawn control or menu item.

Return Value

If an application processes this message, it should return TRUE.

Remarks

When the owner window receives the WM_MEASUREITEM message, the owner fills in the MEASUREITEMSTRUCT structure pointed to by the lParam parameter of the message and returns; this informs Windows of the dimensions of the control. If a list box or combo box is created with the LBS_OWNERDRAWVARIABLE or CBS_OWNERDRAWVARIABLE style, this message is sent to the owner for each item in the control; otherwise, this message is sent once.

Windows sends the WM_MEASUREITEM message to the owner window of combo boxes and list boxes created with the OWNERDRAWFIXED style before sending the WM_INITDIALOG message. As a result, when the owner receives this message, Windows has not yet determined the height and width of the font used in the control; function calls and calculations requiring these values should occur in the main function of the application or library.

See Also

MEASUREITEMSTRUCT, WM_INITDIALOG


WM_MENUCHAR
WM_MENUCHAR  QuickInfo  Overview  Group

WM_MENUCHAR

chUser = (char) LOWORD(wParam); // ASCII character

fuFlag = (UINT) HIWORD(wParam); // menu flag

hmenu = (HMENU) lParam;         // handle of menu

The WM_MENUCHAR message is sent when a menu is active and the user presses a key that does not correspond to any mnemonic or accelerator key. This message is sent to the window that owns the menu.

Parameters

chUser

Value of the low-order word of wParam. Specifies the ASCII character that corresponds to the key the user pressed.

fuFlag

Value of the high-order word of wParam. Specifies the type of the active menu. This parameter can be one of the following values:

Value	Meaning
MF_POPUP	Pop-up menu
MF_SYSMENU	System menu
hmenu

Value of lParam. Identifies the active menu.

Return Value

An application that processes this message should return one of the following values in the high-order word of the return value:

Value	Meaning
0	Informs Windows that it should discard the character the user pressed and create a short beep on the system speaker.
1	Informs Windows that it should close the active menu.
2	Informs Windows that the low-order word of the return value specifies the zero-based relative position of a menu item. This item is selected by Windows.
Remarks

The low-order word is ignored if the high-order word contains 0 or 1. An application should process this message when an accelerator is used to select a menu item that displays a bitmap.


WM_MENUSELECT
WM_MENUSELECT  QuickInfo  Overview  Group

WM_MENUSELECT

uItem = (UINT) LOWORD(wParam);   // menu item or pop-up menu index

fuFlags = (UINT) HIWORD(wParam); // menu flags

hmenu = (HMENU) lParam;          // handle of menu clicked

The WM_MENUSELECT message is sent to a menu's owner window when the user selects a menu item.

Parameters

uItem

Value of the low-order word of wParam. If the selected item is a command item, this parameter contains the identifier of the menu item. If the selected item invokes a pop-up menu, this parameter contains the menu index of the pop-up menu in the main menu, and the hMenu parameter then contains the handle of the main (clicked) menu; use the GetSubMenu function to get the menu handle of the pop-up menu.

fuFlags

Value of the high-order word of wParam. Specifies one or more menu flags. This parameter can be a combination of the following values:

Value	Description
MF_BITMAP	Item displays a bitmap.
MF_CHECKED	Item is checked.
MF_DISABLED	Item is disabled.
MF_GRAYED	Item is grayed.
MF_HILITE	Item is highlighted.
MF_MOUSESELECT	Item is selected with the mouse.
MF_OWNERDRAW	Item is an owner-drawn item.
MF_POPUP	Item invokes a pop-up menu.
MF_SYSMENU	Item is contained in the System menu (also known as Control menu). The hmenu parameter identifies the System menu associated with the message.
hmenu

Value of lParam. Identifies the menu that was clicked.

Return Value

If an application processes this message, it should return zero.

Remarks

If the fuFlags parameter contains 0xFFFF and the hmenu parameter contains NULL, Windows has closed the menu because the user pressed the ESC key or clicked outside the menu.

Do not use the value −1 for fuFlags. That is because fuFlags is specified as (UINT) HIWORD(wParam). If HIWORD(wParam) were 0xFFFF, fuFlags (because of the UINT cast) would be 0x0000FFFF, not −1.

See Also

GetSubMenu


WM_MOUSEACTIVATE
WM_MOUSEACTIVATE  QuickInfo  Overview  Group

WM_MOUSEACTIVATE

hwndTopLevel = (HWND) wParam;       // handle of top-level parent

nHittest = (INT) LOWORD(lParam);    // hit-test value

uMsg =    (UINT) HIWORD(lParam);    // mouse message

The WM_MOUSEACTIVATE message is sent when the cursor is in an inactive window and the user presses a mouse button. The parent window receives this message only if the child window passes it to the DefWindowProc function.

Parameters

hwndTopLevel

Value of wParam. Identifies the top-level parent window of the window being activated.

nHittest

Value of the low-order word of lParam. Specifies the hit-test value returned by the DefWindowProc function as a result of processing the WM_NCHITTEST message. For a list of hit-test values, see WM_NCHITTEST.

uMsg

Value of the high-order word of lParam. Specifies the identifier of the mouse message generated when the user pressed a mouse button. The mouse message is either discarded or posted to the window, depending on the return value.

Return Value

The return value specifies whether the window should be activated and whether the identifier of the mouse message should be discarded. It must be one of the following values:

Value	Meaning
MA_ACTIVATE	Activates the window, and does not discard the mouse message.
MA_ACTIVATEANDEAT	Activates the window, and discards the mouse message.
MA_NOACTIVATE	Does not activate the window, and does not discard the mouse message.
MA_NOACTIVATEANDEAT	Does not activate the window, but discards the mouse message.
Default Action

The DefWindowProc function passes the message to a child window's parent window before any processing occurs. The parent window determines whether to activate the child window. If it activates the child window, the parent window should return TRUE to prevent the system from processing the message further.

See Also

DefWindowProc, WM_NCHITTEST


WM_MOUSEMOVE
WM_MOUSEMOVE  QuickInfo  Overview  Group

WM_MOUSEMOVE

fwKeys = wParam;        // key flags

xPos = LOWORD(lParam);  // horizontal position of cursor

yPos = HIWORD(lParam);  // vertical position of cursor

The WM_MOUSEMOVE message is posted to a window when the cursor moves. If the mouse is not captured, the message is posted to the window that contains the cursor. Otherwise, the message is posted to the window that has captured the mouse.

Parameters

fwKeys

Value of wParam. Indicates whether various virtual keys are down. This parameter can be any combination of the following values:

Value	Description
MK_CONTROL	Set if the CTRL key is down.
MK_LBUTTON	Set if the left mouse button is down.
MK_MBUTTON	Set if the middle mouse button is down.
MK_RBUTTON	Set if the right mouse button is down.
MK_SHIFT	Set if the SHIFT key is down.
xPos

Value of the low-order word of lParam. Specifies the x-coordinate of the cursor. The coordinate is relative to the upper-left corner of the client area.

yPos

Value of the high-order word of lParam. Specifies the y-coordinate of the cursor. The coordinate is relative to the upper-left corner of the client area.

Remarks

The MAKEPOINTS macro can be used to convert the lParam parameter to a POINTS structure.

See Also

GetCapture, MAKEPOINTS, POINTS, SetCapture


WM_MOVE
WM_MOVE  QuickInfo  Overview  Group

WM_MOVE

xPos = (int) LOWORD(lParam);    // horizontal position

yPos = (int) HIWORD(lParam);    // vertical position

The WM_MOVE message is sent after a window has been moved.

Parameters

xPos

Value of the low-order word of lParam. Specifies the x-coordinate of the upper-left corner of the client area of the window.

yPos

Value of the high-order word of lParam. Specifies the y-coordinate of the upper-left corner of the client area of the window.

Return Value

If an application processes this message, it should return zero.

Remarks

The xPos and yPos parameters are given in screen coordinates for overlapped and pop-up windows and in parent-client coordinates for child windows.

An application can use the MAKEPOINTS macro to convert the lParam parameter to a POINTS structure.

See Also

MAKEPOINTS, POINTS


WM_MOVING [New - Windows 95]
WM_MOVING  QuickInfo

[New - Windows 95]

fwSide = wParam;	// edge of window to be moved

lprc = (LPRECT) lParam;	// screen coordinates of drag rectangle

The WM_MOVING message is sent to a window that the user is moving. By processing this message, an application can monitor the size and position of the drag rectangle and, if needed, change its size or position.

Parameters

fwSide

Value of wParam. Indicates which edge of the window is being moved. This parameter can be a combination of the following values:

Value	Meaning
WMSZ_BOTTOM	Bottom edge
WMSZ_BOTTOMLEFT	Bottom-left corner
WMSZ_BOTTOMRIGHT	Bottom-right corner
WMSZ_LEFT	Left edge
WMSZ_RIGHT	Right edge
WMSZ_TOP	Top edge
WMSZ_TOPLEFT	Top-left corner
WMSZ_TOPRIGHT	Top-right corner
lprc

Value of lParam. Address of a RECT structure with the screen coordinates of the drag rectangle. To change the size or position of the drag rectangle, an application must change the members of this structure.

Return Value

An application should return TRUE if it processes this message.

See Also

RECT, WM_MOVE, WM_SIZING


WM_NCACTIVATE
WM_NCACTIVATE  QuickInfo  Overview  Group

WM_NCACTIVATE

fActive = (BOOL) wParam;	// new state of the title bar or icon

The WM_NCACTIVATE message is sent to a window when its nonclient area needs to be changed to indicate an active or inactive state.

Parameters

fActive

Value of wParam. Specifies when a title bar or icon needs to be changed to indicate an active or inactive state. If an active title bar or icon is to be drawn, the fActive parameter is TRUE. It is FALSE for an inactive title bar or icon.

Return Value

When the fActive parameter is FALSE, an application should return TRUE to indicate that Windows should proceed with the default processing, or it should return FALSE to prevent the title bar or icon from being deactivated. When fActive is TRUE, the return value is ignored.

Default Action

The DefWindowProc function draws the title bar or icon title in its active colors when the fActive parameter is TRUE and in its inactive colors when fActive is FALSE.

See Also

DefWindowProc


WM_NCCALCSIZE
WM_NCCALCSIZE  QuickInfo  Overview  Group

WM_NCCALCSIZE

fCalcValidRects = (BOOL) wParam;        // valid area flag

lpncsp = (LPNCCALCSIZE_PARAMS) lParam;  // points to size calculation data

   or

lpncsp = (LPRECT) lParam;               // points to new window coordinates

The WM_NCCALCSIZE message is sent when the size and position of a window's client area must be calculated. By processing this message, an application can control the content of the window's client area when the size or position of the window changes.

Parameters

fCalcValidRects

Value of wParam. A Boolean value that, if TRUE, specifies that the application should indicate which part of the client area contains valid information. The operating system copies the valid information to the specified area within the new client area. Also, if this parameter is TRUE, lParam points to an NCCALCSIZE_PARAMS structure.

If this parameter is FALSE, the application does not need to indicate the valid part of the client area. Also, if this parameter is FALSE, lParam points to a RECT structure.

lpncsp

Value of lParam.

If wParam  is TRUE, lParam points to an NCCALCSIZE_PARAMS structure that contains information an application can use to calculate the new size and position of the client rectangle.

If wParam  is FALSE, lParam points to a RECT structure that contains the new coordinates of the window that has been moved or resized. This is equivalent to rgrc[0] of an NCCALCSIZE_PARAMS structure.

Return Value

If the fCalcValidRects parameter is FALSE, the application should return zero.

If fCalcValidRects is TRUE, the application can return zero or a valid combination of the following values:

Value	Meaning
WVR_ALIGNTOP, WVR_ALIGNLEFT, WVR_ALIGNBOTTOM, WVR_ALIGNRIGHT
	These values, used in combination, specify that the client area of the window is to be preserved and aligned appropriately relative to the new position of the window. For example, to align the client area to the lower-left corner, return the WVR_ALIGNLEFT and WVR_ALIGNTOP values.
WVR_HREDRAW, WVR_VREDRAW
	These values, used in combination with any other values, cause the window to be completely redrawn if the client rectangle changes size horizontally or vertically. These values are similar to the CS_HREDRAW and CS_VREDRAW class styles.
WVR_REDRAW
	This value causes the entire window to be redrawn. It is a combination of WVR_HREDRAW and WVR_VREDRAW values.
WVR_VALIDRECTS
	This value indicates that, upon return from WM_NCCALCSIZE, the rectangles specified by the rgrc[1] and rgrc[2] members of the NCCALCSIZE_PARAMS structure contain valid source and destination area rectangles, respectively. Windows combines these rectangles to calculate the area of the window to be preserved. Windows copies any part of the window image that is within the source rectangle and clips the image to the destination rectangle. Both rectangles are in parent-relative or screen-relative coordinates.
	This return value allows an application to implement more elaborate client-area preservation strategies, such as centering or preserving a subset of the client area.
If fCalcValidRects is TRUE and an application returns zero, the old client area is preserved and is aligned with the upper-left corner of the new client area.

Default Action

The window may be redrawn, depending on whether the CS_HREDRAW or CS_VREDRAW class style is specified. This is the default, backward-compatible processing of this message by the DefWindowProc function (in addition to the usual client rectangle calculation described in the preceding table).

See Also

DefWindowProc, MoveWindow, SetWindowPos, NCCALCSIZE_PARAMS, RECT


WM_NCCREATE
WM_NCCREATE  QuickInfo  Overview  Group

WM_NCCREATE

lpcs = (LPCREATESTRUCT) lParam; // initialization data

The WM_NCCREATE message is sent prior to the WM_CREATE message when a window is first created.

Parameters

lpcs

Value of wParam. Points to the CREATESTRUCT structure for the window.

Return Value

If an application processes this message, it should return TRUE to continue creation of the window. If the application returns FALSE, the CreateWindow or CreateWindowEx function will return a NULL handle.

Default Action

The DefWindowProc function returns TRUE.

See Also

CreateWindow, CreateWindowEx, DefWindowProc, CREATESTRUCT, WM_CREATE


WM_NCDESTROY
WM_NCDESTROY  QuickInfo  Overview  Group

WM_NCDESTROY

The WM_NCDESTROY message informs a window that its nonclient area is being destroyed. The DestroyWindow function sends the WM_NCDESTROY message to the window following the WM_DESTROY message. WM_DESTROY is used to free the allocated memory object associated with the window.

Parameters

This message has no parameters.

Return Value

If an application processes this message, it should return zero.

Remarks

This message frees any memory internally allocated for the window.

See Also

DestroyWindow, WM_DESTROY, WM_NCCREATE


WM_NCHITTEST
WM_NCHITTEST  QuickInfo  Overview  Group

WM_NCHITTEST

xPos = LOWORD(lParam);  // horizontal position of cursor

yPos = HIWORD(lParam);  // vertical position of cursor

The WM_NCHITTEST message is sent to a window when the cursor moves, or when a mouse button is pressed or released. If the mouse is not captured, the message is sent to the window beneath the cursor. Otherwise, the message is posted to the window that has captured the mouse.

Parameters

xPos

Value of the low-order word of lParam. Specifies the x-coordinate of the cursor. The coordinate is relative to the upper-left corner of the screen.

yPos

Value of the high-order word of lParam. Specifies the y-coordinate of the cursor. The coordinate is relative to the upper-left corner of the screen.

Return Value

The return value of the DefWindowProc function is one of the following values, indicating the position of the cursor hot spot:

Value	Location of hot spot
HTBORDER	In the border of a window that does not have a sizing border
HTBOTTOM	In the lower horizontal border of a window
HTBOTTOMLEFT	In the lower-left corner of a window border
HTBOTTOMRIGHT	In the lower-right corner of a window border
HTCAPTION	In a title bar
HTCLIENT	In a client area
HTERROR	On the screen background or on a dividing line between windows (same as HTNOWHERE, except that the DefWindowProc function produces a system beep to indicate an error)
HTGROWBOX	In a size box (same as HTSIZE)
HTHSCROLL	In a horizontal scroll bar
HTLEFT	In the left border of a window
HTMENU	In a menu
HTNOWHERE	On the screen background or on a dividing line between windows
HTREDUCE	In a Minimize button
HTRIGHT	In the right border of a window
HTSIZE	In a size box (same as HTGROWBOX)
HTSYSMENU	In a System menu or in a Close button in a child window
HTTOP	In the upper horizontal border of a window
HTTOPLEFT	In the upper-left corner of a window border
HTTOPRIGHT	In the upper right corner of a window border
HTTRANSPARENT	In a window currently covered by another window
HTVSCROLL	In the vertical scroll bar
HTZOOM	In a Maximize button
Remarks

An application can use the MAKEPOINTS macro to convert the lParam parameter to a POINTS structure.

See Also

DefWindowProc, GetCapture, MAKEPOINTS, POINTS


WM_NCLBUTTONDBLCLK
WM_NCLBUTTONDBLCLK  QuickInfo  Overview  Group

WM_NCLBUTTONDBLCLK

nHittest = (INT) wParam;    // hit-test value

pts = MAKEPOINTS(lParam);   // position of cursor

The WM_NCLBUTTONDBLCLK message is posted when the user double-clicks the left mouse button while the cursor is within the nonclient area of a window. This message is posted to the window that contains the cursor. If a window has captured the mouse, this message is not posted.

Parameters

nHittest

Value of wParam. Specifies the hit-test value returned by the DefWindowProc function as a result of processing the WM_NCHITTEST message. For a list of hit-test values, see WM_NCHITTEST.

pts

Value of lParam. Specifies a POINTS structure that contains the x- and y-coordinates of the cursor. The coordinates are relative to the upper-left corner of the screen.

Return Value

If an application processes this message, it should return zero.

Default Action

The DefWindowProc function tests the given point to find out the location of the cursor and performs the appropriate action. If appropriate, DefWindowProc sends the WM_SYSCOMMAND message to the window.

Remarks

A window need not have the CS_DBLCLKS style to receive WM_NCLBUTTONDBLCLK messages.

Windows generates a WM_NCLBUTTONDBLCLK message when the user presses, releases, and again presses the left mouse button within the system's double-click time limit. Double-clicking the left mouse button actually generates four messages: WM_NCLBUTTONDOWN, WM_NCLBUTTONUP, WM_NCLBUTTONDBLCLK, and WM_NCLBUTTONUP again.

An application can use the MAKEPOINTS macro to convert the lParam parameter to a POINTS structure.

See Also

DefWindowProc, MAKEPOINTS, POINTS, WM_NCHITTEST, WM_NCLBUTTONDOWN, WM_NCLBUTTONUP, WM_SYSCOMMAND


WM_NCLBUTTONDOWN
WM_NCLBUTTONDOWN  QuickInfo  Overview  Group

WM_NCLBUTTONDOWN

nHittest = (INT) wParam;    // hit-test value

pts = MAKEPOINTS(lParam);   // position of cursor

The WM_NCLBUTTONDOWN message is posted when the user presses the left mouse button while the cursor is within the nonclient area of a window. This message is posted to the window that contains the cursor. If a window has captured the mouse, this message is not posted.

Parameters

nHittest

Value of wParam. Specifies the hit-test value returned by the DefWindowProc function as a result of processing the WM_NCHITTEST message. For a list of hit-test values, see WM_NCHITTEST.

pts

Value of lParam. Specifies a POINTS structure that contains the x- and y-coordinates of the cursor. The coordinates are relative to the upper-left corner of the screen.

Return Value

If an application processes this message, it should return zero.

Default Action

The DefWindowProc function tests the given point to find out the location of the cursor and performs the appropriate action. If appropriate, DefWindowProc sends the WM_SYSCOMMAND message to the window.

Remarks

An application can use the MAKEPOINTS macro to convert the lParam parameter to a POINTS structure.

See Also

DefWindowProc, MAKEPOINTS, POINTS, WM_NCHITTEST, WM_NCLBUTTONDBLCLK, WM_NCLBUTTONUP, WM_SYSCOMMAND


WM_NCLBUTTONUP
WM_NCLBUTTONUP  QuickInfo  Overview  Group

WM_NCLBUTTONUP

nHittest = (INT) wParam;    // hit-test value

pts = MAKEPOINTS(lParam);   // mouse-cursor coordinates

The WM_NCLBUTTONUP message is posted when the user releases the left mouse button while the cursor is within the nonclient area of a window. This message is posted to the window that contains the cursor. If a window has captured the mouse, this message is not posted.

Parameters

nHittest

Value of wParam. Specifies the hit-test value returned by the DefWindowProc function as a result of processing the WM_NCHITTEST message. For a list of hit-test values, see WM_NCHITTEST.

pts

Value of lParam. Specifies a POINTS structure that contains the x- and y-coordinates of the cursor. The coordinates are relative to the upper-left corner of the screen.

Return Value

If an application processes this message, it should return zero.

Default Action

The DefWindowProc function tests the given point to find out the location of the cursor and performs the appropriate action. If appropriate, DefWindowProc sends the WM_SYSCOMMAND message to the window.

Remarks

An application can use the MAKEPOINTS macro to convert the lParam parameter to a POINTS structure.

If it is appropriate to do so, the system sends the WM_SYSCOMMAND message to the window.

See Also

DefWindowProc, MAKEPOINTS, POINTS, WM_NCHITTEST, WM_NCLBUTTONDBLCLK, WM_NCLBUTTONDOWN, WM_SYSCOMMAND


WM_NCMBUTTONDBLCLK
WM_NCMBUTTONDBLCLK  QuickInfo  Overview  Group

WM_NCMBUTTONDBLCLK

nHittest = (INT) wParam;    // hit-test value

pts = MAKEPOINTS(lParam);   // position of cursor

The WM_NCMBUTTONDBLCLK message is posted when the user double-clicks the middle mouse button while the cursor is within the nonclient area of a window. This message is posted to the window that contains the cursor. If a window has captured the mouse, this message is not posted.

Parameters

nHittest

Value of wParam. Specifies the hit-test value returned by the DefWindowProc function as a result of processing the WM_NCHITTEST message. For a list of hit-test values, see WM_NCHITTEST.

pts

Value of lParam. Specifies a POINTS structure that contains the x- and y-coordinates of the cursor. The coordinates are relative to the upper-left corner of the screen.

Return Value

If an application processes this message, it should return zero.

Remarks

A window need not have the CS_DBLCLKS style to receive WM_NCMBUTTONDBLCLK messages.

Windows generates a WM_NCMBUTTONDBLCLK message when the user presses, releases, and again presses the middle mouse button within the system's double-click time limit. Double-clicking the middle mouse button actually generates four messages: WM_NCMBUTTONDOWN, WM_NCMBUTTONUP, WM_NCMBUTTONDBLCLK, and WM_NCMBUTTONUP again.

An application can use the MAKEPOINTS macro to convert the lParam parameter to a POINTS structure.

If it is appropriate to do so, the system sends the WM_SYSCOMMAND message to the window.

See Also

DefWindowProc, MAKEPOINTS, POINTS, WM_NCHITTEST, WM_NCMBUTTONDOWN, WM_NCMBUTTONUP, WM_SYSCOMMAND


WM_NCMBUTTONDOWN
WM_NCMBUTTONDOWN  QuickInfo  Overview  Group

WM_NCMBUTTONDOWN

nHittest = (INT) wParam;    // hit-test value

pts = MAKEPOINTS(lParam);   // position of cursor

The WM_NCMBUTTONDOWN message is posted when the user presses the middle mouse button while the cursor is within the nonclient area of a window. This message is posted to the window that contains the cursor. If a window has captured the mouse, this message is not posted.

Parameters

nHittest

Value of wParam. Specifies the hit-test value returned by the DefWindowProc function as a result of processing the WM_NCHITTEST message. For a list of hit-test values, see WM_NCHITTEST.

pts

Value of lParam. Specifies a POINTS structure that contains the x- and y-coordinates of the cursor. The coordinates are relative to the upper-left corner of the screen.

Return Value

If an application processes this message, it should return zero.

Remarks

An application can use the MAKEPOINTS macro to convert the lParam parameter to a POINTS structure.

If it is appropriate to do so, the system sends the WM_SYSCOMMAND message to the window.

See Also

DefWindowProc, MAKEPOINTS, POINTS, WM_NCHITTEST, WM_NCMBUTTONDBLCLK, WM_NCMBUTTONUP, WM_SYSCOMMAND


WM_NCMBUTTONUP
WM_NCMBUTTONUP  QuickInfo  Overview  Group

WM_NCMBUTTONUP

nHittest = (INT) wParam;    // hit-test value

pts = MAKEPOINTS(lParam);   // position of cursor

The WM_NCMBUTTONUP message is posted when the user releases the middle mouse button while the cursor is within the nonclient area of a window. This message is posted to the window that contains the cursor. If a window has captured the mouse, this message is not posted.

Parameters

nHittest

Value of wParam. Specifies the hit-test value returned by the DefWindowProc function as a result of processing the WM_NCHITTEST message. For a list of hit-test values, see WM_NCHITTEST.

pts

Value of lParam. Specifies a POINTS structure that contains the x- and y-coordinates of the cursor. The coordinates are relative to the upper-left corner of the screen.

Return Value

If an application processes this message, it should return zero.

Remarks

An application can use the MAKEPOINTS macro to convert the lParam parameter to a POINTS structure.

If it is appropriate to do so, the system sends the WM_SYSCOMMAND message to the window.

See Also

DefWindowProc, MAKEPOINTS, POINTS, WM_NCHITTEST, WM_NCMBUTTONDBLCLK, WM_NCMBUTTONDOWN, WM_SYSCOMMAND


WM_NCMOUSEMOVE
WM_NCMOUSEMOVE  QuickInfo  Overview  Group

WM_NCMOUSEMOVE

nHittest = (INT) wParam;    // hit-test value

pts = MAKEPOINTS(lParam);   // position of cursor

The WM_NCMOUSEMOVE message is posted to a window when the cursor is moved within the nonclient area of the window. This message is posted to the window that contains the cursor. If a window has captured the mouse, this message is not posted.

Parameters

nHittest

Value of wParam. Specifies the hit-test value returned by the DefWindowProc function as a result of processing the WM_NCHITTEST message. For a list of hit-test values, see WM_NCHITTEST.

pts

Value of lParam. Specifies a POINTS structure that contains the x- and y-coordinates of the cursor. The coordinates are relative to the upper-left corner of the screen.

Return Value

If an application processes this message, it should return zero.

Remarks

If it is appropriate to do so, the system sends the WM_SYSCOMMAND message to the window.

An application can use the MAKEPOINTS macro to convert the lParam parameter to a POINTS structure.

See Also

DefWindowProc, MAKEPOINTS, POINTS, WM_NCHITTEST, WM_SYSCOMMAND


WM_NCPAINT
WM_NCPAINT  QuickInfo  Overview  Group

WM_NCPAINT

hrgn = (HRGN) wParam;   // handle of update region

An application sends the WM_NCPAINT message to a window when its frame must be painted.

Parameters

hrgn

Value of wParam. Identifies the update region of the window. The update region is clipped to the window frame.

Return Value

An application should return zero if it processes this message.

Remarks

The DefWindowProc function paints the window frame.

An application can intercept this message and paint its own custom window frame. The clipping region for a window is always rectangular, even if the shape of the frame is altered.

See Also

DefWindowProc, GetWindowDC, WM_PAINT


WM_NCRBUTTONDBLCLK
WM_NCRBUTTONDBLCLK  QuickInfo  Overview  Group

WM_NCRBUTTONDBLCLK

nHittest = (INT) wParam;    // hit-test value

pts = MAKEPOINTS(lParam);   // position of cursor

The WM_NCRBUTTONDBLCLK message is posted when the user double-clicks the right mouse button while the cursor is within the nonclient area of a window. This message is posted to the window that contains the cursor. If a window has captured the mouse, this message is not posted.

Parameters

nHittest

Value of wParam. Specifies the hit-test value returned by the DefWindowProc function as a result of processing the WM_NCHITTEST message. For a list of hit-test values, see WM_NCHITTEST.

pts

Value of lParam. Specifies a POINTS structure that contains the x- and y-coordinates of the cursor. The coordinates are relative to the upper-left corner of the screen.

Return Value

If an application processes this message, it should return zero.

Remarks

A window need not have the CS_DBLCLKS style to receive WM_NCRBUTTONDBLCLK messages.

Windows generates a WM_NCRBUTTONDBLCLK message when the user presses, releases, and again presses the right mouse button within the system's double-click time limit. Double-clicking the right mouse button actually generates four messages: WM_NCRBUTTONDOWN, WM_NCRBUTTONUP, WM_NCRBUTTONDBLCLK, and WM_NCRBUTTONUP again.

An application can use the MAKEPOINTS macro to convert the lParam parameter to a POINTS structure.

If it is appropriate to do so, the system sends the WM_SYSCOMMAND message to the window.

See Also

DefWindowProc, MAKEPOINTS, POINTS, WM_NCHITTEST, WM_NCRBUTTONDOWN, WM_NCRBUTTONUP, WM_SYSCOMMAND


WM_NCRBUTTONDOWN
WM_NCRBUTTONDOWN  QuickInfo  Overview  Group

WM_NCRBUTTONDOWN

nHittest = (INT) wParam;    // hit-test value

pts = MAKEPOINTS(lParam);   // position of cursor

The WM_NCRBUTTONDOWN message is posted when the user presses the right mouse button while the cursor is within the nonclient area of a window. This message is posted to the window that contains the cursor. If a window has captured the mouse, this message is not posted.

Parameters

nHittest

Value of wParam. Specifies the hit-test value returned by the DefWindowProc function as a result of processing the WM_NCHITTEST message. For a list of hit-test values, see WM_NCHITTEST.

pts

Value of lParam. Specifies a POINTS structure that contains the x- and y-coordinates of the cursor. The coordinates are relative to the upper-left corner of the screen.

Return Value

If an application processes this message, it should return zero.

Remarks

An application can use the MAKEPOINTS macro to convert the lParam parameter to a POINTS structure.

If it is appropriate to do so, the system sends the WM_SYSCOMMAND message to the window.

See Also

DefWindowProc, MAKEPOINTS, POINTS, WM_NCHITTEST, WM_NCRBUTTONDBLCLK, WM_NCRBUTTONUP, WM_SYSCOMMAND


WM_NCRBUTTONUP
WM_NCRBUTTONUP  QuickInfo  Overview  Group

WM_NCRBUTTONUP

nHittest = (INT) wParam;    // hit-test value

pts = MAKEPOINTS(lParam);   // position of cursor

The WM_NCRBUTTONUP message is posted when the user releases the right mouse button while the cursor is within the nonclient area of a window. This message is posted to the window that contains the cursor. If a window has captured the mouse, this message is not posted.

Parameters

nHittest

Value of wParam. Specifies the hit-test value returned by the DefWindowProc function as a result of processing the WM_NCHITTEST message. For a list of hit-test values, see WM_NCHITTEST.

pts

Value of lParam. Specifies a POINTS structure that contains the x- and y-coordinates of the cursor. The coordinates are relative to the upper-left corner of the screen.

Return Value

If an application processes this message, it should return zero.

Remarks

An application can use the MAKEPOINTS macro to convert the lParam parameter to a POINTS structure.

If it is appropriate to do so, the system sends the WM_SYSCOMMAND message to the window.

See Also

DefWindowProc, MAKEPOINTS, POINTS, WM_NCHITTEST, WM_NCRBUTTONDBLCLK, WM_NCRBUTTONDOWN, WM_SYSCOMMAND


WM_NEXTDLGCTL
WM_NEXTDLGCTL  QuickInfo  Overview  Group

WM_NEXTDLGCTL

wCtlFocus = wParam;              // identifies control for focus

fHandle = (BOOL) LOWORD(lParam); // wParam handle flag

The WM_NEXTDLGCTL message is sent to a dialog box procedure to set the keyboard focus to a different control in the dialog box.

Parameters

wCtlFocus

Value of wParam. If the fHandle parameter is TRUE, the wCtlFocus parameter identifies the control that receives the focus. If fHandle is FALSE, wCtlFocus is a flag that indicates whether the next or previous control with the WS_TABSTOP style receives the focus. If wCtlFocus is zero, the next control receives the focus; otherwise, the previous control with the WS_TABSTOP style receives the focus.

fHandle

Value of lParam. Contains a flag that indicates how Windows uses the wCtlFocus parameter. If the fHandle parameter is TRUE, wCtlFocus is a handle associated with the control that receives the focus; otherwise, wCtlFocus is a flag that indicates whether the next or previous control with the WS_TABSTOP style receives the focus.

Return Value

An application should return zero if it processes this message.

Remarks

The effect of this message differs from that of the SetFocus function because WM_NEXTDLGCTL modifies the border around the control.

Do not use the SendMessage function to send a WM_NEXTDLGCTL message if your application will concurrently process other messages that set the focus. Use the PostMessage function instead.

See Also

PostMessage, SendMessage, SetFocus


WM_NOTIFY [New - Windows NT]
WM_NOTIFY  QuickInfo  Overview  Group

[New - Windows NT]

WM_NOTIFY

idCtrl = (int) wParam;

pnmh = (LPNMHDR) lParam;

The WM_NOTIFY message informs the parent window of a control that an event has occurred in the control or that the control requires some kind of information.

Parameters

idCtrl

Identifier of the control sending the message. This identifier is not guaranteed to be unique. An application should use the hwindFrom or idFrom member of the NMHDR structure (passed as the lParam parameter) to identify the control.

pnmh

Pointer to an NMHDR structure that contains the notification code and additional information. For some notification messages, this parameter points to a larger structure that has the NMHDR structure as its first member.

Return Value

The return value is ignored except for notification messages that specify otherwise.

See Also

NMHDR


WM_NOTIFYFORMAT  (preliminary-WindowsNT) [New - Windows NT]
WM_NOTIFYFORMAT  QuickInfo

[New - Windows NT]

hwndFrom = (HWND) wParam;        // handle of the window sending this message

Command =  lParam;               // command value specifying the nature of this message

Common controls, custom controls, and their parent windows use the WM_NOTIFYFORMAT message to determine whether the control should use ANSI or Unicode structures in the WM_NOTIFY notification messages that the control uses to communicate with its parent window. WM_NOTIFYFORMAT messages are sent from a control to its parent window, and from the parent window to the control.

Parameters

hwndFrom

Value of wParam. Handle of the window that is sending the WM_NOTIFYFORMAT message. If Command is NF_QUERY, hwndFrom is the handle of a control. If Command is NF_REQUERY, this is the handle of the parent window of a control.

Command

Value of lParam. A command value that specifies the nature of the WM_NOTIFYFORMAT message. The following values are defined:

Value	Meaning
NF_QUERY	The message is a query to determine whether ANSI or Unicode structures should be used in WM_NOTIFY messages. This command is sent from a control to its parent window. This command is sent during the creation of a control, and in response to an NF_REQUERY command.
NF_REQUERY	The message is a request that a control send an NF_QUERY form of this message to its parent window. This command is sent from a control's parent window to the control. The parent window is asking the control to requery it about the type of structures to use in WM_NOTIFY messages.
Return Value

The return value is one of the following :

Value	Meaning
NFR_ANSI	ANSI structures should be used in WM_NOTIFY messages sent by the control.
NFR_UNICODE	Unicode structures should be used in WM_NOTIFY messages sent by the control.
0	An error occurred.
If Command is NF_REQUERY, the return value is the result of the requery operation.

Remarks

When a common control is created, the control sends a WM_NOTIFYFORMAT message to its parent window to determine the type of structures to use in WM_NOTIFY messages. If the parent window does not handle this message, the DefWindowProc function responds according to the type of the parent window. That is, if the parent window is a Unicode window, DefWindowProc returns NFR_UNICODE, and if the parent window is an ANSI window, DefWindowProc returns NFR_ANSI. If the parent window is a dialog box and does not handle this message, the DefDlgProc function similarly responds according to the type of the dialog box (Unicode or ANSI).

A parent window can change the type of structures a common control uses in WM_NOTIFY messages by setting lParam to NF_REQUERY and sending a WM_NOTIFYFORMAT message to the control. This causes the control to send an NF_QUERY form of the WM_NOTIFYFORMAT message to the parent window.

See Also

DefDlgProc, DefWindowProc, WM_NOTIFY


WM_PAINT
WM_PAINT  QuickInfo  Overview  Group

WM_PAINT

An application sends the WM_PAINT message when Windows or another application makes a request to paint a portion of an application's window. The message is sent when the UpdateWindow or RedrawWindow function is called, or by the DispatchMessage function when the application obtains a WM_PAINT message by using the GetMessage or PeekMessage function.

Parameters

This message has no parameters.

Return Value

An application should return zero if it processes this message.

Remarks

The DefWindowProc function validates the update region. The function may also send the WM_NCPAINT message to the window procedure if the window frame must be painted and send the WM_ERASEBKGND message if the window background must be erased.

The system sends this message when there are no other messages in the application's message queue. DispatchMessage determines where to send the message; GetMessage determines which message to dispatch. GetMessage returns the WM_PAINT message when there are no other messages in the application's message queue, and DispatchMessage sends the message to the appropriate window procedure.

A window may receive internal paint messages as a result of calling RedrawWindow with the RDW_INTERNALPAINT flag set. In this case, the window may not have an update region. An application should call the GetUpdateRect function to determine whether the window has an update region. If GetUpdateRect returns zero, the application should not call the BeginPaint and EndPaint functions.

An application must check for any necessary internal painting by looking at its internal data structures for each WM_PAINT message, because a WM_PAINT message may have been caused by both a non-NULL update region and a call to RedrawWindow with the RDW_INTERNALPAINT flag set.

Windows sends an internal WM_PAINT message only once. After an internal WM_PAINT message is returned from GetMessage or PeekMessage or is sent to a window by UpdateWindow, Windows does not post or send further WM_PAINT messages until the window is invalidated or until RedrawWindow is called again with the RDW_INTERNALPAINT flag set.

See Also

BeginPaint, DefWindowProc, DispatchMessage, EndPaint, GetMessage, GetUpdateRect, PeekMessage, RedrawWindow, UpdateWindow, WM_ERASEBKGND, WM_NCPAINT


WM_PAINTCLIPBOARD
WM_PAINTCLIPBOARD  QuickInfo  Overview  Group

WM_PAINTCLIPBOARD

hwndViewer = (HWND) wParam;     // handle of clipboard viewer window

hglbPs = (HGLOBAL) lParam;      // handle of PAINTSTRUCT object

The WM_PAINTCLIPBOARD message is sent to the clipboard owner by a clipboard viewer window when the clipboard contains data in the CF_OWNERDISPLAY format and the clipboard viewer's client area needs repainting.

Parameters

hwndViewer

Value of wParam. Identifies the clipboard viewer window.

hglbPs

Value of lParam. Identifies a global DDESHARE object that contains a PAINTSTRUCT structure. The structure defines the part of the client area to paint.

Return Value

If an application processes this message, it should return zero.

Remarks

To determine whether the entire client area or just a portion of it needs repainting, the clipboard owner must compare the dimensions of the drawing area given in the rcpaint member of PAINTSTRUCT to the dimensions given in the most recent WM_SIZECLIPBOARD message.

The clipboard owner must use the GlobalLock function to lock the memory that contains the PAINTSTRUCT structure. Before returning, the clipboard owner must unlock that memory by using the GlobalUnlock function.

See Also

GlobalLock, GlobalUnlock, PAINTSTRUCT, WM_SIZECLIPBOARD


WM_PAINTICON
WM_PAINTICON  QuickInfo  Overview  Group

WM_PAINTICON

The WM_PAINTICON message is sent to a minimized window when the icon is to be painted but only if the application is written for Windows 3.x. A window receives this message only if a class icon is defined for the window; otherwise, WM_PAINT is sent instead.

Parameters

This message has no parameters.

Return Value

An application should return zero if it processes this message.

Remarks

The DefWindowProc function draws the class icon. For compatibility with Windows 3.x, wParam is TRUE. However, this value has no significance.

See Also

DefWindowProc, WM_ICONERASEBKGND, WM_PAINT


WM_PALETTECHANGED
WM_PALETTECHANGED  QuickInfo  Overview  Group

WM_PALETTECHANGED

hwndPalChg = (HWND) wParam; // handle of window that changed palette

The WM_PALETTECHANGED message is sent to all top-level and overlapped windows after the window with the keyboard focus has realized its logical palette, thereby changing the system palette. This message enables a window that uses a color palette but does not have the keyboard focus to realize its logical palette and update its client area.

Parameters

hwndPalChg

Value of wParam. Identifies the window that caused the system palette to change.

Remarks

This message must be sent to all top-level and overlapped windows, including the one that changed the system palette. If any child windows use a color palette, this message must be passed on to them as well.

To avoid creating an infinite loop, a window that receives this message must not realize its palette, unless it determines that wParam does not contain its own window handle.

See Also

WM_PALETTEISCHANGING, WM_QUERYNEWPALETTE


WM_PALETTEISCHANGING
WM_PALETTEISCHANGING  QuickInfo  Overview  Group

WM_PALETTEISCHANGING

hwndRealize = (HWND) wParam; // window to realize palette

The WM_PALETTEISCHANGING message informs applications that an application is going to realize its logical palette.

Parameters

hwndRealize

Value of wParam. Identifies the window that is going to realize its logical palette.

Return Value

If an application processes this message, it should return zero.

Remarks

The application changing its palette does not wait for acknowledgment of this message before changing the palette and sending the WM_PALETTECHANGED message. As a result, the palette may already be changed by the time an application receives this message.

If the application either ignores or fails to process this message and a second application realizes its palette while the first is using palette indices, there is a strong possibility that the user will see unexpected colors during subsequent drawing operations.

See Also

WM_PALETTECHANGED, WM_QUERYNEWPALETTE


WM_PARENTNOTIFY
WM_PARENTNOTIFY  QuickInfo  Overview  Group

WM_PARENTNOTIFY

fwEvent = LOWORD(wParam);  // event flags

idChild = HIWORD(wParam);  // identifier of child window

lValue = lParam;           // child handle, or cursor coordinates

The WM_PARENTNOTIFY message is sent to the parent of a child window when the child window is created or destroyed, or when the user clicks a mouse button while the cursor is over the child window. When the child window is being created, the system sends WM_PARENTNOTIFY just before the CreateWindow or CreateWindowEx function that creates the window returns. When the child window is being destroyed, Windows sends the message before any processing to destroy the window takes place.

Parameters

fwEvent

Value of the low-order word of wParam. Specifies the event for which the parent is being notified. This parameter can be one of the following values:

Value	Meaning
WM_CREATE	The child window is being created.
WM_DESTROY	The child window is being destroyed.
WM_LBUTTONDOWN	The user has placed the cursor over the child window and has clicked the left mouse button.
WM_MBUTTONDOWN	The user has placed the cursor over the child window and has clicked the middle mouse button.
WM_RBUTTONDOWN	The user has placed the cursor over the child window and has clicked the right mouse button.
idChild

Value of the high-order word of wParam. If the fwEvent parameter is the WM_CREATE or WM_DESTROY value, idChild specifies the identifier of the child window. Otherwise, idChild is undefined.

lValue

Contains the handle of the child window, if the fwEvent parameter is the WM_CREATE or WM_DESTROY value; otherwise, lValue contains the x- and y-coordinates of the cursor. The x-coordinate is in the low-order word and the y-coordinate is in the high-order word.

Return Value

If an application processes this message, it should return zero.

Remarks

This message is also sent to all ancestor windows of the child window, including the top-level window.

All child windows, except those that have the WS_EX_NOPARENTNOTIFY extended window style, send this message to their parent windows. By default, child windows in a dialog box have the WS_EX_NOPARENTNOTIFY style, unless the CreateWindowEx function is called to create the child window without this style.

See Also

CreateWindow, CreateWindowEx, WM_CREATE, WM_DESTROY, WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_RBUTTONDOWN


WM_PASTE
WM_PASTE  QuickInfo  Overview  Group

WM_PASTE

wParam = 0; // not used; must be zero

lParam = 0; // not used; must be zero

An application sends a WM_PASTE message to an edit control or combo box to copy the current content of the clipboard to the edit control at the current caret position. Data is inserted only if the clipboard contains data in CF_TEXT format.

Parameters

This message has no parameters.

Return Value

This message does not return a value.

Remarks

When sent to a combo box, the WM_PASTE message is handled by its edit control. This message has no effect when sent to a combo box with the CBS_DROPDOWNLIST style.

See Also

WM_CLEAR, WM_COPY, WM_CUT


WM_POWER
WM_POWER  QuickInfo  Overview  Group

WM_POWER

fwPowerEvt = wParam;    // power-event notification message

The WM_POWER message is sent when the system, typically a battery-powered personal computer, is about to enter suspended mode.

Windows 95: For Windows 95 applications, The WM_POWER message is not supported. It is provided to simplify porting of 16-bit Windows-based applications. Win32-based applications for Windows 95 should use the WM_POWERBROADCAST message.

Parameters

fwPowerEvt

Value of wParam. Specifies a power-event notification message. This parameter can be one of the following values:

Value	Meaning
PWR_CRITICALRESUME	Indicates that the system is resuming operation after entering suspended mode without first sending a PWR_SUSPENDREQUEST notification message to the application. An application should perform any necessary recovery actions.
PWR_SUSPENDREQUEST	Indicates that the system is about to enter suspended mode.
PWR_SUSPENDRESUME	Indicates that the system is resuming operation after having entered suspended mode normally — that is, the system sent a PWR_SUSPENDREQUEST notification message to the application before the system was suspended. An application should perform any necessary recovery actions.
Return Value

The value an application returns depends on the value of the wParam parameter. If wParam is PWR_SUSPENDREQUEST, the return value is PWR_FAIL to prevent the system from entering the suspended state; otherwise, it is PWR_OK. If wParam is PWR_SUSPENDRESUME or PWR_CRITICALRESUME, the return value is zero.

Remarks

This message is sent only to an application that is running on a system that conforms to the Advanced Power Management (APM) basic input/output system (BIOS) specification. The message is sent by the power-management driver to each window returned by the EnumWindows function.

The suspended mode is the state in which the greatest amount of power savings occurs, but all operational data and parameters are preserved. Random-access memory (RAM) contents are preserved, but many devices are likely to be turned off.

See Also

EnumWindows, WM_POWERBROADCAST


WM_POWERBROADCAST [New - Windows 95]
WM_POWERBROADCAST  QuickInfo  Overview  Group

[New - Windows 95]

dwPowerEvent = (DWORD) wParam;
dwData = (DWORD) lParam;

The WM_POWERBROADCAST message is sent to an application to notify it of power-management events.

Windows NT: For Windows NT applications, use WM_POWER.

Parameters

dwPowerEvent

Event notification message. This parameter can be one of the following values:

Value	Meaning
PBT_APMBATTERYLOW	Battery power is low.
PBT_APMOEMEVENT	OEM-defined event occurred.
PBT_APMPOWERSTATUSCHANGED	Power status has changed.
PBT_APMQUERYSTANDBY	Request for permission to standby.
PBT_APMQUERYSTANDBYFAILED	Standby request denied.
PBT_APMQUERYSUSPEND	Request for permission to suspend.
PBT_APMQUERYSUSPENDFAILED	Suspension request denied.
PBT_APMRESUMECRITICAL	Operation resuming after critical suspension.
PBT_APMRESUMESTANDBY	Operation resuming after standby.
PBT_APMRESUMESUSPEND	Operation resuming after suspension.
PBT_APMSTANDBY	System is changing to standby.
PBT_APMSUSPEND	System is suspending operation.
dwData

Function-specific data. For most messages, this parameter is reserved and not used.

However, if wParam is one of the resume notifications (PBT_APMRESUME*), the lParam parameter can specify the PBTF_APMRESUMEFROMFAILURE flag. This flag indicates that a suspend or standby operation failed after the PBT_APMSUSPEND or PBT_APMSTANDBY message was sent.

Return Value

Returns TRUE if successful or FALSE otherwise.


WM_PRINT [New - Windows 95]
WM_PRINT  QuickInfo  Overview  Group

[New - Windows 95]

WM_PRINT

hdc = (HDC) wParam;

uFlags = lParam;

The WM_PRINT message is sent to a window to request that it draw itself in the specified device context, most commonly in a printer device context.

Parameters

hdc

Identifies the device context to draw in.

uFlags

Specifies the drawing options. This parameter can be one or more of these flags:

Value	Meaning
PRF_CHECKVISIBLE	Draw the window only if it is visible.
PRF_CHILDREN	Draw all visible children windows.
PRF_CLIENT	Draw the client area of the window.
PRF_ERASEBKGND	Erase the background before drawing the window.
PRF_NONCLIENT	Draw the nonclient area of the window.
PRF_OWNED	Draw all owned windows.
Remarks

The DefWindowProc function processes this message based on which drawing option is specified: if PRF_CHECKVISIBLE is specified and the window is not visible, do nothing, if PRF_NONCLIENT is specified, draw the nonclient area in the given device context, if PRF_ERASEBKGND is specified, send the window a WM_ERASEBKGND message, if PRF_PRINTCLIENT is specified, send the window a WM_PRINTCLIENT message, if PRF_PRINTCHILDREN is set, send each visible child window a WM_PRINT message, if PRF_OWNED is set, send each visible owned window a WM_PRINT message.

See Also

DefWindowProc, WM_ERASEBKGND, WM_PRINTCLIENT


WM_PRINTCLIENT
WM_PRINTCLIENT  QuickInfo  Overview  Group

WM_PRINTCLIENT

hdc = (HDC) wParam;

uFlags = lParam;

The WM_PRINTCLIENT message is sent to a window to request that it draw its client area in the specified device context, most commonly in a printer device context.

Parameters

hdc

Identifies the device context to draw in.

uFlags

Specifies drawing options. This parameter can be one or more of these flags:

Value	Meaning
PRF_CHECKVISIBLE	Draw the window only if it is visible.
PRF_CHILDREN	Draw all visible children windows.
PRF_CLIENT	Draw the client area of the window.
PRF_ERASEBKGND	Erase the background before drawing the window.
PRF_NONCLIENT	Draw the nonclient area of the window.
PRF_OWNED	Draw all owned windows.
Remarks

A window can process this message in much the same manner as WM_PAINT, except that BeginPaint and EndPaint need not be called (a device context is provided), and the window should draw its entire client area rather than just the invalid region.

Windows that can be used anywhere in the system, such as controls, should process this message. It is probably worthwhile for other windows to process this message as well because it is relatively easy to implement.

See Also

BeginPaint, EndPaint, WM_PAINT


WM_PSD_ENVSTAMPRECT
WM_PSD_ENVSTAMPRECT  Overview  Group

WM_PSD_ENVSTAMPRECT

hDC = (WPARAM) (HDC) wParam;             // handle of device context

lprcEnvStamp = (LPARAM) (LPRECT) lParam; // envelope-stamp rectangle

Informs a hook function of the coordinates of the envelope-stamp rectangle in the sample page of the Page Setup dialog box. Before drawing in the envelope-stamp rectangle, the system passes this message to the hook function specified in the lpfnPagePaintHook member of the PAGESETUPDLG structure used to create the dialog box.

Parameters

hDC

Value of wParam. Identifies the device context for the sample page.

lprcMargin

Value of lParam. Points to a RECT structure that contains the coordinates, in pixels, of the envelope-stamp rectangle.

Return Value

A hook procedure should return TRUE to prevent the system from drawing the envelope-stamp rectangle; otherwise, it should return FALSE.

Remarks

A hook procedure receives this message only if the selected paper type is an envelope.

See Also

PAGESETUPDLG, RECT


WM_PSD_FULLPAGERECT
WM_PSD_FULLPAGERECT  Overview  Group

WM_PSD_FULLPAGERECT

hDC = (WPARAM) (HDC) wParam;         // handle of device context

lprcPage = (LPARAM) (LPRECT) lParam; // dimensions of page rectangle

Informs a hook function of the coordinates of the sample page rectangle in the Page Setup dialog box. Before drawing in the sample page rectangle, the system sends this message to the hook function specified in the lpfnPagePaintHook member of the PAGESETUPDLG structure used to create the dialog box.

Parameters

hDC

Value of wParam. Handle of the device context for the sample page.

lprcPage

Value of lParam. Points to a RECT structure that contains the coordinates, in pixels, of the sample page.

Return Value

A hook procedure should return TRUE to prevent the system from drawing in the sample page rectangle; otherwise, it should return FALSE. If it returns TRUE, the hook procedure receives no more messages until the next time the system needs to redraw the sample page.

See Also

PAGESETUPDLG, RECT


WM_PSD_GREEKTEXTRECT
WM_PSD_GREEKTEXTRECT  Overview  Group

WM_PSD_GREEKTEXTRECT

hDC = (WPARAM) (HDC) wParam;              // handle of device context

lprcGreekText = (LPARAM) (LPRECT) lParam; // greek text rectangle

Informs a hook function of the coordinates of the greek-text rectangle in the sample page of the Page Setup dialog box. The system fills the greek-text rectangle with random characters to demonstrate how text is be formatted on a printed page. Before drawing the greek text, the system passes this message to the hook function specified in the lpfnPagePaintHook member of the PAGESETUPDLG structure used to create the dialog box.

Parameters

hDC

Value of wParam. Identifies the device context for the sample page.

lprcMargin

Value of lParam. Points to a RECT structure that contains the coordinates, in pixels, of the greek-text rectangle.

Return Value

A hook function should return TRUE to prevent the system from drawing in the greek-text rectangle; otherwise, it should return FALSE.

See Also

PAGESETUPDLG, RECT


WM_PSD_MARGINRECT
WM_PSD_MARGINRECT  Overview  Group

WM_PSD_MARGINRECT

hDC = (WPARAM) (HDC) wParam;           // handle of device context

lprcMargin = (LPARAM) (LPRECT) lParam; // margin rectangle

Informs a hook function of the coordinates of the margin rectangle in the sample page of the Page Setup dialog box. Before drawing the margin rectangle, the system passes this message to the hook function specified in the lpfnPagePaintHook member of the PAGESETUPDLG structure used to create the dialog box.

Parameters

hDC

Value of wParam. Identifies the device context for the sample page.

lprcMargin

Value of lParam. Points to a RECT structure that contains the coordinates, in pixels, of the margin rectangle.

Return Value

A hook function should return TRUE to prevent the system from drawing the margin rectangle; otherwise, is should return FALSE.

See Also

PAGESETUPDLG, RECT


WM_PSD_MINMARGINRECT
WM_PSD_MINMARGINRECT  Overview  Group

WM_PSD_MINMARGINRECT

hDC = (WPARAM) (HDC) wParam;              // handle of device context

lprcMinMargin = (LPARAM) (LPRECT) lParam; // minimum margin rectangle

Informs a hook function of the coordinates of the minimum margin rectangle of the sample page in the Page Setup dialog box. The system passes this message to the hook function specified in the lpfnPagePaintHook member of the PAGESETUPDLG structure used to create the dialog box.

Parameters

hDC

Value of wParam. Identifies the device context for the sample page.

lprcMinMargin

Value of lParam. Points to a RECT structure that contains the coordinates, in pixels, of the minimum margin rectangle.

Return Value

A hook function should return TRUE to prevent the system from any further drawing in the sample page rectangle; otherwise, it should return FALSE. If it returns TRUE, the hook function receives no more messages until the next time the system needs to redraw the sample page.

See Also

PAGESETUPDLG, RECT


WM_PSD_PAGESETUPDLG
WM_PSD_PAGESETUPDLG  Overview  Group

WM_PSD_PAGESETUPDLG

wPaper = LOWORD(wParam);         // paper-size flag

wFlags = HIWORD(wParam);         // paper-orientation flag

lppsd = (LPPAGESETUPDLG) lParam; // dialog box information

Sent when the system is about to draw the contents of the sample page in the Page Setup dialog box. The system sends this message to the hook function specified in the lpfnPagePaintHook member of the PAGESETUPDLG structure used to create the dialog box. The hook function can use this message to carry out initialization tasks related to drawing the contents of the sample page.

Parameters

wPaper

Value of the low-order word of wParam. Specifies a value that indicates the paper size. This value can be one of the DMPAPER_ values listed in the description of the DEVMODE structure.

wFlags

Value of the high-order word of wParam. Indicates the orientation of the paper or envelope, and whether the printer is a dot matrix or HPPCL (Hewlett Packard Printer Control Language) device. This parameter can be one of the following values:

0x0001	Paper in landscape mode (dot matrix)
0x0003	Paper in landscape mode (HPPCL)
0x0005	Paper in portrait mode (dot matrix)
0x0007	Paper in portrait mode (HPPCL)
0x000b	Envelope in landscape mode (HPPCL)
0x000d	Envelope in portrait mode (dot matrix)
0x0019	Envelope in landscape mode (dot matrix)
0x001f	Envelope in portrait mode (HPPCL)
lppsd

Value of lParam. Points to a PAGESETUPDLG structure that contains information used to initialize the Page Setup dialog box.

Return Value

A hook function should return TRUE to prevent the system from drawing in the sample page rectangle; otherwise, it should return FALSE. If it returns TRUE, the hook function receives no more messages until the next time the system needs to redraw the sample page.

See Also

DEVMODE, PAGESETUPDLG


WM_PSD_YAFULLPAGERECT
WM_PSD_YAFULLPAGERECT  Overview  Group

WM_PSD_YAFULLPAGERECT

hDC = (WPARAM) (HDC) wParam;               // handle of device context

lprcYaFullPage = (LPARAM) (LPRECT) lParam; // dimensions of page rectangle

Informs a hook function of the coordinates of the sample page rectangle in the Page Setup dialog box. The system sends this message to the hook function specified in the lpfnPagePaintHook member of the PAGESETUPDLG structure used to create the dialog box.

Parameters

hDC

Value of wParam. Handle of the device context for the sample page.

lprcPage

Value of lParam. Points to a RECT structure that contains the coordinates, in pixels, of the sample page.

Return Value

A hook function should return TRUE to prevent the system from drawing in the return address rectangle of the sample page. It should return FALSE to allow the system to draw in the return address rectangle. If the paper type is not an envelope, the return value has no effect.

See Also

PAGESETUPDLG, RECT


WM_QUERYDRAGICON
WM_QUERYDRAGICON  QuickInfo

WM_QUERYDRAGICON

The WM_QUERYDRAGICON message is sent to a minimized (iconic) window. The window is about to be dragged by the user but does not have an icon defined for its class. An application can return the handle of an icon or cursor. The system displays this cursor or icon while the user drags the icon.

Parameters

This message has no parameters.

Return Value

An application should return the handle of a cursor or icon that Windows is to display while the user drags the icon. The cursor or icon must be compatible with the display driver's resolution. If the application returns NULL, the system displays the default cursor.

Default Action

The DefWindowProc function returns the handle of the default cursor.

Remarks

When the user drags the icon of a window without a class icon, Windows replaces the icon with a default cursor. If the application requires a different cursor to be displayed during dragging, it must return the handle of the cursor or icon compatible with the display driver's resolution. If an application returns the handle of a color cursor or icon, the system converts the cursor or icon to black and white. The application can call the LoadCursor or LoadIcon function to load a cursor or icon from the resources in its executable (.EXE) file and to retrieve this handle.

See Also

DefWindowProc, LoadCursor, LoadIcon


WM_QUERYENDSESSION
WM_QUERYENDSESSION  QuickInfo  Overview  Group

Windows 95:

WM_QUERYENDSESSION

nSource = (UINT) wParam;    // source of end-session request

fLogOff = (BOOL) lParam    // logoff flag

Windows NT:

WM_QUERYENDSESSION

nSource = (UINT) wParam;    // source of end-session request

The WM_QUERYENDSESSION message is sent when the user chooses to end the Windows session or when an application calls the ExitWindows function. If any application returns zero, the Windows session is not ended. Windows stops sending WM_QUERYENDSESSION messages as soon as one application returns zero.

After processing this message, Windows sends the WM_ENDSESSION message with the wParam parameter set to the results of the WM_QUERYENDSESSION message.

Parameters

nSource

Value of wParam. Specifies the source of the request to end the Windows session. This parameter is zero if the request occurred because the user clicked the Logoff or Shutdown button in the Shut Down Windows dialog box. This parameter is nonzero if the user clicked the End Task button in the Task List dialog box.

fLogOff

Windows 95 only: Value of lParam. Indicates whether the user is logging off or shutting down the system. This parameter is TRUE if the user is logging off; it is FALSE if the user is shutting down the system.

Return Value

If an application can terminate conveniently, it should return TRUE; otherwise, it should return FALSE.

Default Action

The DefWindowProc function returns TRUE.

Remarks

Note that lParam is not used on the Windows NT platform, but is used on the Windows 95 platform.

See Also

DefWindowProc, ExitWindows, WM_ENDSESSION


WM_QUERYNEWPALETTE
WM_QUERYNEWPALETTE  QuickInfo  Overview  Group

WM_QUERYNEWPALETTE

The WM_QUERYNEWPALETTE message informs a window that it is about to receive the keyboard focus, giving the window the opportunity to realize its logical palette when it receives the focus.

Parameters

This message has no parameters.

Return Value

If the window realizes its logical palette, it must return TRUE; otherwise, it must return FALSE.

See Also

WM_PALETTECHANGED, WM_PALETTEISCHANGING


WM_QUERYOPEN
WM_QUERYOPEN  QuickInfo  Overview  Group

WM_QUERYOPEN

The WM_QUERYOPEN message is sent to an icon when the user requests that the window be restored to its previous size and position.

Parameters

This message has no parameters.

Return Value

If the icon can be opened, an application that processes this message should return TRUE; otherwise, it should return FALSE to prevent the icon from being opened.

Default Action

The DefWindowProc function returns TRUE.

Remarks

While processing this message, the application should not perform any action that would cause an activation or focus change (for example, creating a dialog box).

See Also

DefWindowProc


WM_QUEUESYNC
WM_QUEUESYNC  QuickInfo  Overview  Group

WM_QUEUESYNC

wParam = 0; // not used, must be zero

lParam = 0; // not used, must be zero

The WM_QUEUESYNC message is sent by a computer-based training (CBT) application to separate user-input messages from other messages sent through the WH_JOURNALPLAYBACK hook procedure.

Parameters

This message has no parameters.

Return Value

A CBT application should return zero if it processes this message.

Remarks

Whenever a CBT application uses the WH_JOURNALPLAYBACK hook procedure, the first and last messages are WM_QUEUESYNC. This allows the CBT application to intercept and examine user-initiated messages without doing so for events that it sends.

If an application specifies a NULL window handle, the message is posted to the message queue of the active window.


WM_QUIT
WM_QUIT  QuickInfo  Overview  Group

WM_QUIT

nExitCode = (int) wParam;   // exit code

The WM_QUIT message indicates a request to terminate an application and is generated when the application calls the PostQuitMessage function. It causes the GetMessage function to return zero.

Parameters

nExitCode

Value of wParam. Specifies the exit code given in the PostQuitMessage function.

Return Value

This message does not have a return value, because it causes the message loop to terminate before the message is sent to the application's window procedure.

See Also

GetMessage, PostQuitMessage


WM_RASDIALEVENT
WM_RASDIALEVENT  QuickInfo  Overview  Group

WM_RASDIALEVENT

rasconnstate = (RASCONNSTATE) wParam; // connection state about to be entered

dwError = (DWORD) lParam;             // error that may have occurred

The operating system sends a WM_RASDIALEVENT message to a window procedure when a change of state event occurs during a Remote Access Service (RAS) connection process, and a window has been specified to handle notifications of such events by using the notifier parameter of RasDial.

The two message parameters are equivalent to the parameters of the same names that are used with RasDialFunc and RasDialFunc1 callback functions.

Parameters

rasconnstate

Value of wParam. Equivalent to the rasconnstate parameter of the RasDialFunc and RasDialFunc1 callback functions. Specifies a RASCONNSTATE enumerator value that indicates the state the RasDial remote access connection process is about to enter.

dwError

Value of lParam. Equivalent to the dwError parameter of the RasDialFunc and RasDialFunc1 callback functions. A nonzero value indicates the error that has occurred, or zero if no error has occurred.

RasDial sends this message with dwError set to zero upon entry to each connection state. If an error occurs within a state, the message is sent again for the state, this time with a nonzero dwError value.

Return Value

If an application processes this message, it should return TRUE.

See Also

RasDial, RasDialFunc, RasDialFunc1, RASCONNSTATE


WM_RBUTTONDBLCLK
WM_RBUTTONDBLCLK  QuickInfo  Overview  Group

WM_RBUTTONDBLCLK

fwKeys = wParam;        // key flags

xPos = LOWORD(lParam);  // horizontal position of cursor

yPos = HIWORD(lParam);  // vertical position of cursor

The WM_RBUTTONDBLCLK message is posted when the user double-clicks the right mouse button while the cursor is in the client area of a window. If the mouse is not captured, the message is posted to the window beneath the cursor. Otherwise, the message is posted to the window that has captured the mouse.

Parameters

fwKeys

Value of wParam. Indicates whether various virtual keys are down. This parameter can be any combination of the following values:

Value	Description
MK_CONTROL	Set if the CTRL key is down.
MK_LBUTTON	Set if the left mouse button is down.
MK_MBUTTON	Set if the middle mouse button is down.
MK_RBUTTON	Set if the right mouse button is down.
MK_SHIFT	Set if the SHIFT key is down.
xPos

Value of the low-order word of lParam. Specifies the x-coordinate of the cursor. The coordinate is relative to the upper left corner of the client area.

yPos

Value of the high-order word of lParam. Specifies the y-coordinate of the cursor. The coordinate is relative to the upper left corner of the client area.

Return Value

If an application processes this message, it should return zero.

Remarks

Only windows that have the CS_DBLCLKS style can receive WM_RBUTTONDBLCLK messages, which Windows generates whenever the user presses, releases, and again presses the right mouse button within the system's double-click time limit. Double-clicking the right mouse button actually generates four messages: WM_RBUTTONDOWN, WM_RBUTTONUP, WM_RBUTTONDBLCLK, and WM_RBUTTONUP again.

An application can use the MAKEPOINTS macro to convert the lParam parameter to a POINTS structure.

See Also

GetCapture, GetDoubleClickTime, MAKEPOINTS, POINTS, SetCapture, SetDoubleClickTime, WM_RBUTTONDOWN, WM_RBUTTONUP


WM_RBUTTONDOWN
WM_RBUTTONDOWN  QuickInfo  Overview  Group

WM_RBUTTONDOWN

fwKeys = wParam;        // key flags

xPos = LOWORD(lParam);  // horizontal position of cursor

yPos = HIWORD(lParam);  // vertical position of cursor

The WM_RBUTTONDOWN message is posted when the user presses the right mouse button while the cursor is in the client area of a window. If the mouse is not captured, the message is posted to the window beneath the cursor. Otherwise, the message is posted to the window that has captured the mouse.

Parameters

fwKeys

Value of wParam. Indicates whether various virtual keys are down. This parameter can be any combination of the following values:

Value	Description
MK_CONTROL	Set if the CTRL key is down.
MK_LBUTTON	Set if the left mouse button is down.
MK_MBUTTON	Set if the middle mouse button is down.
MK_RBUTTON	Set if the right mouse button is down.
MK_SHIFT	Set if the SHIFT key is down.
xPos

Value of the low-order word of lParam. Specifies the x-coordinate of the cursor. The coordinate is relative to the upper left corner of the client area.

yPos

Value of the high-order word of lParam. Specifies the y-coordinate of the cursor. The coordinate is relative to the upper left corner of the client area.

Return Value

If an application processes this message, it should return zero.

Remarks

An application can use the MAKEPOINTS macro to convert the lParam parameter to a POINTS structure.

See Also

GetCapture, MAKEPOINTS, POINTS, SetCapture, WM_RBUTTONDBLCLK, WM_RBUTTONUP


WM_RBUTTONUP
WM_RBUTTONUP  QuickInfo  Overview  Group

WM_RBUTTONUP

fwKeys = wParam;        // key flags

xPos = LOWORD(lParam);  // horizontal position of cursor

yPos = HIWORD(lParam);  // vertical position of cursor

The WM_RBUTTONUP message is posted when the user releases the right mouse button while the cursor is in the client area of a window. If the mouse is not captured, the message is posted to the window beneath the cursor. Otherwise, the message is posted to the window that has captured the mouse.

Parameters

fwKeys

Value of wParam. Indicates whether various virtual keys are down. This parameter can be any combination of the following values:

Value	Description
MK_CONTROL	Set if the CTRL key is down.
MK_LBUTTON	Set if the left mouse button is down.
MK_MBUTTON	Set if the middle mouse button is down.
MK_SHIFT	Set if the SHIFT key is down.
xPos

Value of the low-order word of lParam. Specifies the x-coordinate of the cursor. The coordinate is relative to the upper left corner of the client area.

yPos

Value of the high-order word of lParam. Specifies the y-coordinate of the cursor. The coordinate is relative to the upper left corner of the client area.

Return Value

If an application processes this message, it should return zero.

Remarks

An application can use the MAKEPOINTS macro to convert the lParam parameter to a POINTS structure.

See Also

GetCapture, MAKEPOINTS, POINTS, SetCapture, WM_RBUTTONDBLCLK, WM_RBUTTONDOWN


WM_RENDERALLFORMATS
WM_RENDERALLFORMATS  QuickInfo  Overview  Group

WM_RENDERALLFORMATS

The WM_RENDERALLFORMATS message is sent to the clipboard owner before it is destroyed, if the clipboard owner has delayed rendering one or more clipboard formats. For the content of the clipboard to remain available to other applications, the clipboard owner must render data in all the formats it is capable of generating, and place the data on the clipboard by calling the SetClipboardData function.

Parameters

This message has no parameters.

Return Value

If an application processes this message, it should return zero.

Remarks

When responding to a WM_RENDERFORMAT or WM_RENDERALLFORMATS message, the clipboard owner must not open the clipboard before calling SetClipboardData.

When the application returns, the system removes any unrendered formats from the list of available clipboard formats. For information about delayed rendering, see SetClipboardData.

See Also

SetClipboardData, WM_RENDERFORMAT


WM_RENDERFORMAT
WM_RENDERFORMAT  QuickInfo  Overview  Group

WM_RENDERFORMAT

uFormat = (UINT) wParam;    // clipboard format

The WM_RENDERFORMAT message is sent to the clipboard owner if it has delayed rendering a specific clipboard format and if an application has requested data in that format. The clipboard owner must render data in the specified format and place it on the clipboard by calling the SetClipboardData function.

Parameters

uFormat

Specifies the clipboard format to be rendered.

Return Value

If an application processes this message, it should return zero.

Remarks

When responding to a WM_RENDERFORMAT or WM_RENDERALLFORMATS message, the clipboard owner must not open the clipboard before calling SetClipboardData.

See Also

SetClipboardData, WM_RENDERALLFORMATS


WM_SETCURSOR
WM_SETCURSOR  QuickInfo  Overview  Group

WM_SETCURSOR

hwnd = (HWND) wParam;       // handle of window with cursor

nHittest = LOWORD(lParam);  // hit-test code

wMouseMsg = HIWORD(lParam); // mouse-message identifier

The WM_SETCURSOR message is sent to a window if the mouse causes the cursor to move within a window and mouse input is not captured.

Parameters

hwnd

Value of wParam. Identifies the window that contains the cursor.

nHittest

Value of the low-order word of lParam. Specifies the hit-test code.

wMouseMsg

Value of the high-order word of lParam. Specifies the identifier of the mouse message.

Default Action

The DefWindowProc function passes the WM_SETCURSOR message to a parent window before processing. If the parent window returns TRUE, further processing is halted. Passing the message to a window's parent window gives the parent window control over the cursor's setting in a child window. The DefWindowProc function also uses this message to set the cursor to an arrow if it is not in the client area, or to the registered class cursor if it is in the client area. If the low-order word of the lParam parameter is HTERROR and the high-order word of lParam specifies that one of the mouse buttons is pressed, DefWindowProc calls the MessageBeep function.

Remarks

The high-order word of lParam is zero when the window enters menu mode.

See Also

DefWindowProc, MessageBeep


WM_SETFOCUS
WM_SETFOCUS  QuickInfo  Overview  Group

WM_SETFOCUS

hwndLoseFocus = (HWND) wParam; // handle of window losing focus

The WM_SETFOCUS message is sent to a window after it has gained the keyboard focus.

Parameters

hwndLoseFocus

Value of wParam. Identifies the window that has lost the keyboard focus (may be NULL).

Return Value

An application should return zero if it processes this message.

Remarks

To display a caret, an application should call the appropriate caret functions when it receives the WM_SETFOCUS message.

See Also

SetFocus, WM_KILLFOCUS


WM_SETFONT
WM_SETFONT  QuickInfo  Overview  Group

WM_SETFONT

wParam = (WPARAM) hfont;            // handle of font

lParam = MAKELPARAM(fRedraw, 0);    // redraw flag

An application sends a WM_SETFONT message to specify the font that a control is to use when drawing text.

Parameters

hfont

Value of wParam. Identifies the font. If this parameter is NULL, the control uses the default system font to draw text.

fRedraw

Value of lParam. Specifies whether the control should be redrawn immediately upon setting the font. Setting the fRedraw parameter to TRUE causes the control to redraw itself.

Return Value

This message does not return a value.

Remarks

The WM_SETFONT message applies to all controls, not just those in dialog boxes.

The best time for the owner of a dialog box control to set the font of the control is when it receives the WM_INITDIALOG message. The application should call the DeleteObject function to delete the font when it is no longer needed; for example, after it destroys the control.

The size of the control does not change as a result of receiving this message. To avoid clipping text that does not fit within the boundaries of the control, the application should correct the size of the control window before it sets the font.

When a dialog box uses the DS_SETFONT style to set the text in its controls, Windows sends the WM_SETFONT message to the dialog box procedure before it creates the controls. An application can create a dialog box that contains the DS_SETFONT style by calling any of the following functions:

•	CreateDialogIndirect

•	CreateDialogIndirectParam

•	DialogBoxIndirect

•	DialogBoxIndirectParam

See Also

CreateDialogIndirect, CreateDialogIndirectParam, DeleteObject, DialogBoxIndirect, DialogBoxIndirectParam, WM_INITDIALOG, DLGTEMPLATE


WM_SETHOTKEY
WM_SETHOTKEY  QuickInfo

WM_SETHOTKEY

wParam = (WPARAM) MAKEWORD(vkey, modifiers)   // virtual-key code and modifiers of hot key

lParam = 0;                                   // not used; must be zero

An application sends a WM_SETHOTKEY message to a window to associate a hot key with the window. When the user presses the hot key, the system activates the window.

Parameters

vkey

Value of wParam. Specifies the virtual-key code and modifiers of the hot key to associate with the window. The virtual-key code is in the low byte of the parameter and the modifier flags are in the high byte. Setting this parameter to NULL removes the hot key associated with a window. The modifier byte can be a combination of the following flags:

Value	Meaning
HOTKEYF_ALT	ALT key
HOTKEYF_CONTROL	CTRL key
HOTKEYF_EXT	Extended key
HOTKEYF_SHIFT	SHIFT key
Return Value

The return value is one of the following:

Value	Meaning
−1	The function is unsuccessful — the hot key is invalid.
..0	The function is unsuccessful — the window is invalid.
..1	The function is successful, and no other window has the same hot key.
..2	The function is successful, but another window already has the same hot key.
Remarks

A hot key cannot be associated with a child window.

VK_ESCAPE, VK_SPACE, and VK_TAB are invalid hot keys.

When the user presses the hot key, the system generates a WM_SYSCOMMAND message with wParam equal to SC_HOTKEY.

A window can only have one hot key. If the window already has a hot key associated with it, the new hot key replaces the old one. If more than one window has the same hot key, the window that is activated by the hot key is random.

These hot keys are unrelated to the hot keys set by RegisterHotKey.

See Also

RegisterHotKey, WM_GETHOTKEY, WM_SYSCOMMAND


WM_SETICON [New - Windows 95]
WM_SETICON  QuickInfo

[New - Windows 95]

WM_SETICON

wParam = (WPARAM) (BOOL) fType;    // icon size (large or small)

lParam = (LPARAM) (HICON) hicon;   // handle of icon

An application sends the WM_SETICON message to associate a new big or small icon with a window. Windows draws the big icon when the window is minimized, and the small icon in the window's title bar.

Parameters

fType

Value of wParam. Specifies the icon being set. If TRUE, the message sets the big icon. If FALSE, the message sets the small icon.

hicon

Value of lParam. Identifies the new big or small icon. If this parameter is NULL, the icon indicated by fType is removed.

Return Value

The return value is the handle of the previous big or small icon, depending on the value of fType. It is NULL if the window previously had no icon of the type indicated by fType.

Default Action

The DefWindowProc function returns the handle of the previous big or small icon associated with the window, depending on the value of fType.

See Also

DefWindowProc, WM_GETICON


WM_SETREDRAW
WM_SETREDRAW  QuickInfo  Overview  Group

WM_SETREDRAW

wParam = (WPARAM) fRedraw;  // state of redraw flag

lParam = 0;                 // not used; must be zero

An application sends the WM_SETREDRAW message to a window to allow changes in that window to be redrawn or to prevent changes in that window from being redrawn.

Parameters

fRedraw

Value of wParam. Specifies the state of the redraw flag. If this parameter is TRUE, the redraw flag is set. If the parameter is FALSE, the flag is cleared.

Return Value

An application should return zero if it processes this message.

Remarks

This message sets or clears the redraw flag. If the redraw flag is cleared, the content of the given window is not updated after each change, and the window is not repainted until the redraw flag is set. For example, an application that must add several items to a list box can clear the redraw flag, add the items, and then set the redraw flag. Finally, the application can call the InvalidateRect function to cause the list box to be repainted.

See Also

InvalidateRect


WM_SETTEXT
WM_SETTEXT  QuickInfo  Overview  Group

WM_SETTEXT

wParam = 0;                     // not used; must be zero

lParam = (LPARAM)(LPCTSTR)lpsz; // address of window-text string

An application sends a WM_SETTEXT message to set the text of a window.

Parameters

lpsz

Value of lParam. Points to a null-terminated string that is the window text.

Return Value

The return value is TRUE if the text is set. It is FALSE (for an edit control), LB_ERRSPACE (for a list box), or CB_ERRSPACE (for a combo box) if insufficient space is available to set the text in the edit control. It is CB_ERR if this message is sent to a combo box without an edit control.

Default Action

The DefWindowProc function sets and displays the window text.

Remarks

For an edit control, the text is the contents of the edit control. For a combo box, the text is the contents of the edit-control portion of the combo box. For a button, the text is the button name. For other windows, the text is the window title.

This message does not change the current selection in the list box of a combo box. An application should use the CB_SELECTSTRING message to select the item in a list box that matches the text in the edit control.

See Also

DefWindowProc, CB_SELECTSTRING, WM_GETTEXT


WM_SETTINGCHANGE [New - Windows 95]
WM_SETTINGCHANGE  QuickInfo

[New - Windows 95]

WM_SETTINGCHANGE

wParam = wFlag;                         // system-wide parameter flag

lParam = (LPARAM) (LPCTSTR) pszMetrics; // metrics name

The WM_SETTINGCHANGE message is sent to all windows when an application changes a systemwide setting by using the SystemParametersInfo function.

Parameters

wFlag

Value of wParam. Specifies the systemwide parameter that has changed. For a list of values, see the SystemParametersInfo function.

pszMetrics

Points to a buffer that contains the string "WindowMetrics" if wFlag specifies any of the following systemwide parameters. This parameter is NULL, otherwise.

SPI_SETANIMATION

SPI_SETNONCLIENTMETRICS

SPI_SETICONMETRICS

SPI_SETMINIMIZEDMETRICS

Return Value

An application should return zero if it processes this message.

Remarks

Windows NT: The WM_SETTINGCHANGE message is implemented on the Windows 95 platform. It is not implemented on the Windows NT platform. The Windows NT message WM_WININICHANGE provides equivalent functionality.

See Also

SystemParametersInfo, WM_WININICHANGE


WM_SHOWWINDOW
WM_SHOWWINDOW  QuickInfo  Overview  Group

WM_SHOWWINDOW

fShow = (BOOL) wParam;      // show/hide flag

fnStatus = (int) lParam;    // status flag

The WM_SHOWWINDOW message is sent to a window when the window is about to be hidden or shown.

Parameters

fShow

Value of wParam. Specifies whether a window is being shown. It is TRUE if the window is being shown or FALSE if the window is being hidden.

fnStatus

Value of lParam. Specifies the status of the window being shown. The fnStatus parameter is zero if the message is sent because of a call to the ShowWindow function; otherwise, fnStatus is one of the following values:

Value	Meaning
SW_OTHERUNZOOM	Window is being uncovered because a maximize window was restored or minimized.
SW_OTHERZOOM	Window is being covered by another window that has been maximized.
SW_PARENTCLOSING	Window's owner window is being minimized.
SW_PARENTOPENING	Window's owner window is being restored.
Return Value

If an application processes this message, it should return zero.

Default Action

The DefWindowProc function hides or shows the window, as specified by the message.

Remarks

If a window has the WS_VISIBLE style when it is created, the window receives this message after it is created, but before it is displayed. A window also receives this message when its visibility state is changed by the ShowWindow or ShowOwnedPopups function.

The WM_SHOWWINDOW message is not sent under the following circumstances:

•	When a top-level, overlapped window is created with the WS_MAXIMIZE or WS_MINIMIZE style.

•	When the SW_SHOWNORMAL flag is specified in the call to the ShowWindow function.

See Also

DefWindowProc, ShowOwnedPopups, ShowWindow


WM_SIZE
WM_SIZE  QuickInfo  Overview  Group

WM_SIZE

fwSizeType = wParam;      // resizing flag

nWidth = LOWORD(lParam);  // width of client area

nHeight = HIWORD(lParam); // height of client area

The WM_SIZE message is sent to a window after its size has changed.

Parameters

fwSizeType

Value of wParam. Specifies the type of resizing requested. This parameter can be one of the following values:

Value	Meaning
SIZE_MAXHIDE	Message is sent to all pop-up windows when some other window is maximized.
SIZE_MAXIMIZED	Window has been maximized.
SIZE_MAXSHOW	Message is sent to all pop-up windows when some other window has been restored to its former size.
SIZE_MINIMIZED	Window has been minimized.
SIZE_RESTORED	Window has been resized, but neither the SIZE_MINIMIZED nor SIZE_MAXIMIZED value applies.
nWidth

Value of the low-order word of lParam. Specifies the new width of the client area.

nHeight

Value of the high-order word of lParam. Specifies the new height of the client area.

Return Value

If an application processes this message, it should return zero.

Remarks

If the SetScrollPos or MoveWindow function is called for a child window as a result of the WM_SIZE message, the bRedraw parameter should be nonzero to cause the window to be repainted.

Although the width and height of a window are 32-bit values, the nWidth and nHeight parameters of the WM_SIZE message contain only the low-order 16 bits.

See Also

MoveWindow, SetScrollPos


WM_SIZECLIPBOARD
WM_SIZECLIPBOARD  QuickInfo  Overview  Group

WM_SIZECLIPBOARD

hwndViewer = (HWND) wParam;  // handle of clipboard viewer window

hglbRc = (HGLOBAL) lParam;   // handle of RECT object

The WM_SIZECLIPBOARD message is sent to the clipboard owner by a clipboard viewer window when the clipboard contains data in the CF_OWNERDISPLAY format and the clipboard viewer's client area has changed size.

Parameters

hwndViewer

Value of wParam. Identifies the clipboard viewer window.

hglbRc

Value of lParam. Identifies a global memory object that contains a RECT structure. The structure specifies the new dimensions of the clipboard viewer's client area.

Remarks

When the clipboard viewer window is about to be destroyed or resized, a WM_SIZECLIPBOARD message is sent with a null rectangle (0, 0, 0, 0) as the new size. This permits the clipboard owner to free its display resources.

The clipboard owner must use the GlobalLock function to lock the memory object that contains RECT. Before returning, the clipboard owner must unlock the object by using the GlobalUnlock function.

See Also

GlobalLock, GlobalUnlock, RECT


WM_SIZING [New - Windows 95]
WM_SIZING  QuickInfo

[New - Windows 95]

fwSide = wParam;         // edge of window being sized

lprc = (LPRECT) lParam;  // screen coordinates of drag rectangle

The WM_SIZING message is sent to a window that the user is resizing. By processing this message, an application can monitor the size and position of the drag rectangle and, if needed, change its size or position.

Parameters

fwSide

Value of wParam. Indicates which edge of the window is being sized. This parameter can be a combination of the following values:

Value	Meaning
WMSZ_BOTTOM	Bottom edge
WMSZ_BOTTOMLEFT	Bottom-left corner
WMSZ_BOTTOMRIGHT	Bottom-right corner
WMSZ_LEFT	Left edge
WMSZ_RIGHT	Right edge
WMSZ_TOP	Top edge
WMSZ_TOPLEFT	Top-left corner
WMSZ_TOPRIGHT	Top-right corner
lprc

Address of a RECT structure with the screen coordinates of the drag rectangle. To change the size or position of the drag rectangle, an application must change the members of this structure.

Return Value

An application should return TRUE if it processes this message.

See Also

RECT, WM_MOVING, WM_SIZE


WM_SPOOLERSTATUS
WM_SPOOLERSTATUS  QuickInfo  Overview  Group

WM_SPOOLERSTATUS

fwJobStatus = wParam;       // job-status flag

cJobsLeft = LOWORD(lParam); // number of jobs remaining

The WM_SPOOLERSTATUS message is sent from Windows Print Manager whenever a job is added to or removed from the Print Manager queue.

Parameters

fwJobStatus

Value of wParam. Specifies the PR_JOBSTATUS flag.

cJobsLeft

Value of the low-order word of lParam. Specifies the number of jobs remaining in the Print Manager queue.

Return Value

An application should return zero if it processes this message.

Remarks

This message is for informational purposes only.


WM_STYLECHANGED [New - Windows NT]
WM_STYLECHANGED  QuickInfo

[New - Windows NT]

WM_STYLECHANGED

wStyleType = wParam;            // extended or nonextended styles

lpss = (LPSTYLESTRUCT) lParam;  // structure containing new styles

The WM_STYLECHANGED message is sent to a window after the SetWindowLong function has changed one or more of the window's styles.

Parameters

wStyleType

Value of wParam. Specifies whether the window's extended or nonextended styles have changed. This parameter can be a combination of the following values:

Value	Meaning
GWL_EXSTYLE	The window's extended styles have changed.
GWL_STYLE	The window's nonextended styles have changed.
lpss

Value of lParam. Points to a STYLESTRUCT structure that contains the new styles for the window. An application can examine the styles, but can not change them.

Return Value

An application should return zero if it processes this message.

See Also

SetWindowLong, STYLESTRUCT, WM_STYLECHANGING


WM_STYLECHANGING [New - Windows NT]
WM_STYLECHANGING  QuickInfo

[New - Windows NT]

WM_STYLECHANGING

wStyleType = wParam;            // extended or nonextended styles

lpss = (LPSTYLESTRUCT) lParam;  // structure containing new styles

The WM_STYLECHANGING message is sent to a window when the SetWindowLong function is about to change one or more of the window's styles.

Parameters

wStyleType

Value of wParam. Specifies whether the window's extended or nonextended styles have changed. This parameter can be a combination of the following values:

Value	Meaning
GWL_EXSTYLE	The window's extended styles are changing.
GWL_STYLE	The window's nonextended styles are changing.
lpss

Value of lParam. Points to a STYLESTRUCT structure that contains the proposed new styles for the window. An application can examine the styles and, if necessary, change them.

Return Value

An application should return zero if it processes this message.

See Also

STYLESTRUCT, WM_STYLECHANGED


WM_SYSCHAR
WM_SYSCHAR  QuickInfo  Overview  Group

WM_SYSCHAR

chCharCode = (TCHAR) wParam;   // character code

lKeyData = lParam;             // key data

The WM_SYSCHAR message is posted to the window with the keyboard focus when a WM_SYSKEYDOWN message is translated by the TranslateMessage function. It specifies the character code of a system character key — that is, a character key that is pressed while the ALT key is down.

Parameters

chCharCode

Value of wParam. Specifies the character code of the System menu key.

lKeyData

Value of lParam. Specifies the repeat count, scan code, extended-key flag, context code, previous key-state flag, and transition-state flag, as shown in the following table:

Value	Meaning
0−15	Specifies the repeat count. The value is the number of times the keystroke is repeated as a result of the user holding down the key.
16−23	Specifies the scan code. The value depends on the original equipment manufacturer (OEM).
24	Specifies whether the key is an extended key, such as the right-hand ALT and CTRL keys that appear on an enhanced 101- or 102-key keyboard. The value is 1 if it is an extended key; otherwise, it is 0.
25−28	Reserved; do not use.
29	Specifies the context code. The value is 1 if the ALT key is held down while the key is pressed; otherwise, the value is 0.
30	Specifies the previous key state. The value is 1 if the key is down before the message is sent, or it is 0 if the key is up.
31	Specifies the transition state. The value is 1 if the key is being released, or it is 0 if the key is being pressed.
Return Value

An application should return zero if it processes this message.

Remarks

When the context code is zero, the message can be passed to the TranslateAccelerator function, which will handle it as though it were a standard key message instead of a system character-key message. This allows accelerator keys to be used with the active window even if the active window does not have the keyboard focus.

For enhanced 101- and 102-key keyboards, extended keys are the right ALT and CTRL keys on the main section of the keyboard; the INS, DEL, HOME, END, PAGE UP, PAGE DOWN and arrow keys in the clusters to the left of the numeric keypad; the PRINT SCRN key; the BREAK key; the NUMLOCK key; and the divide (/) and ENTER keys in the numeric keypad. Other keyboards may support the extended-key bit in the lKeyData parameter.

See Also

TranslateAccelerator, TranslateMessage, WM_SYSKEYDOWN


WM_SYSCOLORCHANGE
WM_SYSCOLORCHANGE  QuickInfo  Overview  Group

WM_SYSCOLORCHANGE

The WM_SYSCOLORCHANGE message is sent to all top-level windows when a change is made to a system color setting.

Parameters

This message has no parameters.

Remarks

Windows sends a WM_PAINT message to any window that is affected by a system color change.

Applications that have brushes using the existing system colors should delete those brushes and recreate them using the new system colors.

Top level windows that use common controls must forward the WM_SYSCOLORCHANGE message to the controls; otherwise, the controls will not be notified of the color change. This ensures that the colors used by your common controls are consistent with those used by other user interface objects. For example, a toolbar control uses the "3D Objects" color to draw its buttons. If the user changes the 3D Objects color but the WM_SYSCOLORCHANGE message is not forwarded to the toolbar, the toolbar buttons will remain in their original color while the color of other buttons in the system changes.

See Also

WM_PAINT


WM_SYSCOMMAND
WM_SYSCOMMAND  QuickInfo  Overview  Group

WM_SYSCOMMAND

uCmdType = wParam;        // type of system command requested

xPos = LOWORD(lParam);    // horizontal postion, in screen coordinates

yPos = HIWORD(lParam);    // vertical postion, in screen coordinates

A window receives this message when the user chooses a command from the System menu (also known as Control menu) or when the user chooses the Maximize button or Minimize button.

Parameters

uCmdType

Specifies the type of system command requested. This can be one of these values:

Value	Meaning
SC_CLOSE	Closes the window.
SC_CONTEXTHELP	Changes the cursor to a question mark with a pointer. If the user then clicks a control in the dialog box, the control receives a WM_HELP message.
SC_DEFAULT	Selects the default item; the user double-clicked the System menu.
SC_HOTKEY	Activates the window associated with the application-specified hot key. The low-order word of lParam identifies the window to activate.
SC_HSCROLL	Scrolls horizontally.
SC_KEYMENU	Retrieves the System menu as a result of a keystroke.
SC_MAXIMIZE (or SC_ZOOM)	Maximizes the window.
SC_MINIMIZE (or SC_ICON)	Minimizes the window.
SC_MONITORPOWER	Windows 95 only: Sets the state of the display. This command supports devices that have power-saving features, such as a battery-powered personal computer.
SC_MOUSEMENU	Retrieves the System menu as a result of a mouse click.
SC_MOVE	Moves the window.
SC_NEXTWINDOW	Moves to the next window.
SC_PREVWINDOW	Moves to the previous window.
SC_RESTORE	Restores the window to its normal position and size.
SC_SCREENSAVE	Executes the screen saver application specified in the [boot] section of the SYSTEM.INI file.
SC_SIZE	Sizes the window.
SC_TASKLIST	Executes or activates Windows Task Manager.
SC_VSCROLL	Scrolls vertically.
xPos

Specifies the horizontal position of the cursor, in screen coordinates, if a System menu command is chosen with the mouse. Otherwise, the xPos parameter is not used.

yPos

Specifies the vertical position of the cursor, in screen coordinates, if a System menu command is chosen with the mouse. This parameter is − 1 if the command is chosen using a system accelerator, or zero if using a mnenomic.

Return Value

An application should return zero if it processes this message.

Remarks

The DefWindowProc function carries out the System menu request for the predefined actions specified in the previous table.

In WM_SYSCOMMAND messages, the four low-order bits of the uCmdType parameter are used internally by Windows. To obtain the correct result when testing the value of uCmdType, an application must combine the value 0xFFF0 with the uCmdType value by using the bitwise AND operator.

The menu items in a System menu can be modified by using the GetSystemMenu, AppendMenu, InsertMenu, ModifyMenu, InsertMenuItem, and SetMenuItem functions. Applications that modify the System menu must process WM_SYSCOMMAND messages.

An application can carry out any system command at any time by passing a WM_SYSCOMMAND message to DefWindowProc. Any WM_SYSCOMMAND messages not handled by the application must be passed to DefWindowProc. Any command values added by an application must be processed by the application and cannot be passed to DefWindowProc.

Accelerator keys that are defined to choose items from the System menu are translated into WM_SYSCOMMAND messages; all other accelerator keystrokes are translated into WM_COMMAND messages.

See Also

AppendMenu, DefWindowProc, GetSystemMenu, InsertMenu, ModifyMenu, WM_COMMAND


WM_SYSDEADCHAR
WM_SYSDEADCHAR  QuickInfo  Overview  Group

WM_SYSDEADCHAR

chCharCode = (TCHAR) wParam;    // character code

lKeyData = lParam;              // key data

The WM_SYSDEADCHAR message is sent to the window with the keyboard focus when a WM_SYSKEYDOWN message is translated by the TranslateMessage function. WM_SYSDEADCHAR specifies the character code of a system dead key — that is, a dead key that is pressed while holding down the ALT key.

Parameters

chCharCode

Value of wParam. Specifies the character code generated by the system dead key — that is, a dead key that is pressed while holding down the ALT key.

lKeyData

Value of lParam. Specifies the repeat count, scan code, extended-key flag, context code, previous key-state flag, and transition-state flag, as shown in the following table:

Value	Description
0−15	Specifies the repeat count. The value is the number of times the keystroke is repeated as a result of the user holding down the key.
16−23	Specifies the scan code. The value depends on the original equipment manufacturer (OEM).
24	Specifies whether the key is an extended key, such as the right-hand ALT and CTRL keys that appear on an enhanced 101- or 102-key keyboard. The value is 1 if it is an extended key; otherwise, it is 0.
25−28	Reserved; do not use.
29	Specifies the context code. The value is 1 if the ALT key is held down while the key is pressed; otherwise, the value is 0.
30	Specifies the previous key state. The value is 1 if the key is down before the message is sent, or it is 0 if the key is up.
31	Specifies the transition state. The value is 1 if the key is being released, or it is 0 if the key is being pressed.
Return Value

An application should return zero if it processes this message.

Remarks

For enhanced 101- and 102-key keyboards, extended keys are the right ALT and CTRL keys on the main section of the keyboard; the INS, DEL, HOME, END, PAGE UP, PAGE DOWN and arrow keys in the clusters to the left of the numeric keypad; and the divide (/) and ENTER keys in the numeric keypad. Other keyboards may support the extended-key bit in the lKeyData parameter.

See Also

TranslateMessage, WM_DEADCHAR, WM_SYSKEYDOWN


WM_SYSKEYDOWN
WM_SYSKEYDOWN  QuickInfo  Overview  Group

WM_SYSKEYDOWN

nVirtKey = (int) wParam;    // virtual-key code

lKeyData = lParam;          // key data

The WM_SYSKEYDOWN message is posted to the window with the keyboard focus when the user holds down the ALT key and then presses another key. It also occurs when no window currently has the keyboard focus; in this case, the WM_SYSKEYDOWN message is sent to the active window. The window that receives the message can distinguish between these two contexts by checking the context code in the lKeyData parameter.

Parameters

nVirtKey

Value of wParam. Specifies the virtual-key code of the key being pressed.

lKeyData

Value of lParam. Specifies the repeat count, scan code, extended-key flag, context code, previous key-state flag, and transition-state flag, as shown in the following table:

Value	Description
0−15	Specifies the repeat count. The value is the number of times the keystroke is repeated as a result of the user holding down the key.
16−23	Specifies the scan code. The value depends on the original equipment manufacturer (OEM).
24	Specifies whether the key is an extended key, such as the right-hand ALT and CTRL keys that appear on an enhanced 101- or 102-key keyboard. The value is 1 if it is an extended key; otherwise, it is 0.
25−28	Reserved; do not use.
29	Specifies the context code. The value is 1 if the ALT key is down while the key is pressed; it is 0 if the WM_SYSKEYDOWN message is posted to the active window because no window has the keyboard focus.
30	Specifies the previous key state. The value is 1 if the key is down before the message is sent, or it is 0 if the key is up.
31	Specifies the transition state. The value is always 0 for a WM_SYSKEYDOWN message.
Return Value

An application should return zero if it processes this message.

Default Action

The DefWindowProc function examines the given key and generates a WM_SYSCOMMAND message if the key is either TAB or ENTER.

Remarks

When the context code is zero, the message can be passed to the TranslateAccelerator function, which will handle it as though it were a normal key message instead of a system character-key message. This allows accelerator keys to be used with the active window even if the active window does not have the keyboard focus.

Because of automatic repeat, more than one WM_SYSKEYDOWN message may occur before a WM_SYSKEYUP message is sent. The previous key state (bit 30) can be used to determine whether the WM_SYSKEYDOWN message indicates the first down transition or a repeated down transition.

For enhanced 101- and 102-key keyboards, enhanced keys are the right ALT and CTRL keys on the main section of the keyboard; the INS, DEL, HOME, END, PAGE UP, PAGE DOWN and arrow keys in the clusters to the left of the numeric keypad; and the divide (/) and ENTER keys in the numeric keypad. Other keyboards may support the extended-key bit in the lParam parameter.

See Also

DefWindowProc, TranslateAccelerator, WM_SYSCOMMAND, WM_SYSKEYUP


WM_SYSKEYUP
WM_SYSKEYUP  QuickInfo  Overview  Group

WM_SYSKEYUP

nVirtKey = (int) wParam;    // virtual-key code

lKeyData = lParam;          // key data

The WM_SYSKEYUP message is posted to the window with the keyboard focus when the user releases a key that was pressed while the ALT key was held down. It also occurs when no window currently has the keyboard focus; in this case, the WM_SYSKEYUP message is sent to the active window. The window that receives the message can distinguish between these two contexts by checking the context code in the lKeyData parameter.

Parameters

nVirtKey

Value of wParam. Specifies the virtual-key code of the key being released.

lKeyData

Value of lParam. Specifies the repeat count, scan code, extended-key flag, context code, previous key-state flag, and transition-state flag, as shown in the following table:

Value	Description
0−15	Specifies the repeat count. The value is the number of times the keystroke is repeated as a result of the user holding down the key. The repeat count is always one for a WM_SYSKEYUP message.
16−23	Specifies the scan code. The value depends on the original equipment manufacturer (OEM).
24	Specifies whether the key is an extended key, such as the right-hand ALT and CTRL keys that appear on an enhanced 101- or 102-key keyboard. The value is 1 if it is an extended key; otherwise, it is 0.
25−28	Reserved; do not use.
29	Specifies the context code. The value is 1 if the ALT key is down while the key is released; it is 0 if the WM_SYSKEYDOWN message is posted to the active window because no window has the keyboard focus.
30	Specifies the previous key state. The value is always 1 for a WM_SYSKEYUP message.
31	Specifies the transition state. The value is always 1 for a WM_SYSKEYUP message.
Return Value

An application should return zero if it processes this message.

Default Action

The DefWindowProc function sends a WM_SYSCOMMAND message to the top-level window if the F10 key or the ALT key was released. The wParam parameter of the message is set to SC_KEYMENU.

Remarks

When the context code is zero, the message can be passed to the TranslateAccelerator function, which will handle it as though it were a normal key message instead of a system character-key message. This allows accelerator keys to be used with the active window even if the active window does not have the keyboard focus.

For enhanced 101- and 102-key keyboards, extended keys are the right ALT and CTRL keys on the main section of the keyboard; the INS, DEL, HOME, END, PAGE UP, PAGE DOWN and arrow keys in the clusters to the left of the numeric keypad; and the divide (/) and ENTER keys in the numeric keypad. Other keyboards may support the extended-key bit in the lKeyData parameter.

For non-U.S. enhanced 102-key keyboards, the right ALT key is handled as a CTRL+ALT key. The following table shows the sequence of messages that result when the user presses and releases this key:

Message	Virtual-key code
WM_KEYDOWN	VK_CONTROL
WM_KEYDOWN	VK_MENU
WM_KEYUP	VK_CONTROL
WM_SYSKEYUP	VK_MENU
See Also

DefWindowProc, TranslateAccelerator, WM_SYSCOMMAND, WM_SYSKEYDOWN


WM_TCARD [New - Windows 95]
WM_TCARD  QuickInfo  Overview  Group

[New - Windows 95]

WM_TCARD

idAction = wParam;

dwActionData = lParam;

The WM_TCARD message is sent to an application that has initiated a training card with Windows Help. The message informs the application when the user clicks an authorable button. An application initiates a training card by specifying the HELP_TCARD command in a call to the WinHelp function.

Parameters

idAction

Value of wParam. Indicates the action the user has taken. This parameter can be one of these values:

Value	Meaning
IDABORT	The user clicked an authorable Abort button.
IDCANCEL	The user clicked an authorable Cancel button.
IDCLOSE	The user closed the training card.
IDHELP	The user clicked an authorable Windows Help button.
IDIGNORE	The user clicked an authorable Ignore button.
IDOK	The user clicked an authorable OK button.
IDNO	The user clicked an authorable No button.
IDRETRY	The user clicked an authorable Retry button.
HELP_TCARD_DATA	The user clicked an authorable button. The lParam parameter contains a long integer specified by the help author.
HELP_TCARD_NEXT	The user clicked an authorable Next button.
HELP_TCARD_OTHER_CALLER	Another application has requested training cards.
IDYES	The user clicked an authorable Yes button.
dwActionData

Value of lParam. If idAction specifies HELP_TCARD_DATA, this parameter is a long integer specified by the help author. Otherwise, this parameter is zero.

Return Value

The return value is ignored; use zero.

See Also

WinHelp


WM_TIMECHANGE
WM_TIMECHANGE  QuickInfo

WM_TIMECHANGE

wParam = 0; // not used, must be zero

lParam = 0; // not used, must be zero

An application sends the WM_TIMECHANGE message to all top-level windows after changing the system time.

Parameters

This message has no parameters.

Return Value

An application should return zero if it processes this message.

Remarks

An application that changes the system time should send this message to all top-level windows. To send the WM_TIMECHANGE message to all top-level windows, an application can use the SendMessage function with the hwnd parameter set to HWND_TOPMOST.

See Also

SendMessage


WM_TIMER
WM_TIMER  QuickInfo

WM_TIMER

wTimerID = wParam;            // timer identifier

tmprc = (TIMERPROC *) lParam; // address of timer callback

The WM_TIMER message is posted to the installing thread's message queue or sent to the appropriate TimerProc callback function after each interval specified in the SetTimer function used to install a timer.

Parameters

wTimerID

Value of wParam. Specifies the timer identifier.

tmprc

Value of lParam. Points to an application-defined callback function that was passed to the SetTimer function when the timer was installed. If the tmprc parameter is not NULL, Windows passes the WM_TIMER message to the specified callback function rather than posting the message to the thread's message queue.

Return Value

An application should return zero if it processes this message.

Remarks

The DispatchMessage function forwards this message when no other messages are in the thread's message queue.

See Also

DispatchMessage, SetTimer, TimerProc


WM_UNDO
WM_UNDO  QuickInfo  Overview  Group

WM_UNDO

wParam = 0; // not used; must be zero

lParam = 0; // not used; must be zero

An application sends a WM_UNDO message to an edit control to undo the last operation. When this message is sent to an edit control, the previously deleted text is restored or the previously added text is deleted.

Parameters

This message has no parameters.

Return Value

If the message succeeds, the return value is TRUE; otherwise, it is FALSE.

See Also

WM_CLEAR, WM_COPY, WM_CUT, WM_PASTE


WM_USER
WM_USER  QuickInfo

WM_USER

The WM_USER constant is used by applications to help define private messages.

Remarks

The WM_USER constant is used to distinguish between message values that are reserved for use by Windows and values that can be used by an application to send messages within a private window class. There are five ranges of message numbers:

Range	Meaning
0 through WM_USER − 1	Messages reserved for use by Windows.
WM_USER through 0x7FFF	Integer messages for use by private window classes.
0x8000 through 0xBFFF	Messages reserved for future use by Windows.
0xC000 through 0xFFFF	String messages for use by applications.
Greater than 0xFFFF	Reserved by Windows for future use.
Message numbers in the first range (0 through WM_USER − 1) are defined by Windows. Values in this range that are not explicitly defined are reserved for future use by Windows.

Message numbers in the second range (WM_USER through 0x7FFF) can be defined and used by an application to send messages within a private window class. These values cannot be used to define messages that are meaningful throughout an application, because some predefined window classes already define values in this range. For example, predefined control classes such as BUTTON, EDIT, LISTBOX, and COMBOBOX may use these values. Messages in this range should not be sent to other applications unless the applications have been designed to exchange messages and to attach the same meaning to the message numbers.

Message numbers in the third range (0x8000 through 0xBFFF) are reserved for future use by Windows.

Message numbers in the fourth range (0xC000 through 0xFFFF) are defined at run time when an application calls the RegisterWindowMessage function to retrieve a message number for a string. All applications that register the same string can use the associated message number for exchanging messages. The actual message number, however, is not a constant and cannot be assumed to be the same between different Windows sessions.

Message numbers in the fifth range (greater than 0xFFFF) are reserved for future use by Windows.

See Also

RegisterWindowMessage


WM_USERCHANGED [New - Windows 95]
WM_USERCHANGED  QuickInfo

[New - Windows 95]

WM_USERCHANGED

wParam = 0;       // not used, must be zero

lParam = 0;       // not used, must be zero

The WM_USERCHANGED message is sent to all windows after the user has logged on or off. When the user logs on or off, the system updates the user-specific settings. The system sends this message immediately after updating the settings.

Return Value

An application should return zero if it processes this message.


WM_VKEYTOITEM
WM_VKEYTOITEM  QuickInfo  Overview  Group

WM_VKEYTOITEM

vkey = LOWORD(wParam);      // virtual-key code

nCaretPos = HIWORD(wParam); // caret position

hwndLB = lParam;            // handle of list box

The WM_VKEYTOITEM message is sent by a list box with the LBS_WANTKEYBOARDINPUT style to its owner in response to a WM_KEYDOWN message.

Parameters

vkey

Value of the low-order word of wParam. Specifies the virtual-key code of the key the user pressed.

nCaretPos

Value of the high-order word of wParam. Specifies the current position of the caret.

hwndLB

Value of lParam. Identifies the list box.

Return Value

The return value specifies the action that the application performed in response to the message. A return value of −2 indicates that the application handled all aspects of selecting the item and requires no further action by the list box. A return value of −1 indicates that the list box should perform the default action in response to the keystroke. A return value of 0 or greater specifies the index of an item in the list box and indicates that the list box should perform the default action for the keystroke on the given item.

Default Action

The DefWindowProc function returns −1.

See Also

DefWindowProc, WM_CHARTOITEM, WM_KEYDOWN


WM_VSCROLL
WM_VSCROLL  QuickInfo  Overview  Group

WM_VSCROLL

nScrollCode = (int) LOWORD(wParam); // scroll bar value

nPos = (short int) HIWORD(wParam);  // scroll box position

hwndScrollBar = (HWND) lParam;      // handle of scroll bar

The WM_VSCROLL message is sent to a window when a scroll event occurs in the window's standard vertical scroll bar. This message is also sent to the owner of a vertical scroll bar control when a scroll event occurs in the control.

Parameters

nScrollCode

Value of the low-order word of wParam. Specifies a scroll bar value that indicates the user's scrolling request. This parameter can be one of the following values:

Value	Meaning
SB_BOTTOM	Scrolls to the lower right.
SB_ENDSCROLL	Ends scroll.
SB_LINEDOWN	Scrolls one line down.
SB_LINEUP	Scrolls one line up.
SB_PAGEDOWN	Scrolls one page down.
SB_PAGEUP	Scrolls one page up.
SB_THUMBPOSITION	Scrolls to the absolute position. The current position is specified by the nPos parameter.
SB_THUMBTRACK	Drags scroll box to the specified position. The current position is specified by the nPos parameter.
SB_TOP	Scrolls to the upper left.
nPos

Value of the high-order word of wParam. Specifies the current position of the scroll box if the nScrollCode parameter is SB_THUMBPOSITION or SB_THUMBTRACK; otherwise, nPos is not used.

hwndScrollBar

Value of lParam. Identifies the control if WM_VSCROLL is sent by a scroll bar control. If WM_VSCROLL is sent by a window's standard scroll bar, hwndScrollBar is not used.

Return Value

If an application processes this message, it should return zero.

Remarks

The SB_THUMBTRACK notification message is typically used by applications that provide feedback as the user drags the scroll box.

If an application scrolls the content of the window, it must also reset the position of the scroll box by using the SetScrollPos function.

Note that the WM_VSCROLL message carries only 16 bits of scroll box position data. Thus, applications that rely solely on WM_VSCROLL (and WM_HSCROLL) for scroll position data have a practical maximum position value of 65,535.

However, because the SetScrollPos, SetScrollRange, GetScrollPos, and GetScrollRange functions support 32-bit scroll bar position data, there is a way to circumvent the 16-bit barrier of the WM_HSCROLL and WM_VSCROLL messages. See GetScrollPos for a description of the technique and its limits.

See Also

GetScrollPos, GetScrollRange, SetScrollPos, SetScrollRange, WM_HSCROLL


WM_VSCROLLCLIPBOARD
WM_VSCROLLCLIPBOARD  QuickInfo  Overview  Group

WM_VSCROLLCLIPBOARD

hwndViewer = (HWND) wParam;         // handle of clipboard viewer window

nScrollCode = (int) LOWORD(lParam); // scroll bar code

nPos = (int) HIWORD(lParam);        // scroll box position

The WM_VSCROLLCLIPBOARD message is sent to the clipboard owner by a clipboard viewer window when the clipboard contains data in the CF_OWNERDISPLAY format and an event occurs in the clipboard viewer's vertical scroll bar. The owner should scroll the clipboard image and update the scroll bar values.

Parameters

hwndViewer

Value of wParam. Identifies the clipboard viewer window.

nScrollCode

Value of the low-order word of lParam. Specifies a scroll bar event. This parameter can be one of the following values:

Value	Meaning
SB_BOTTOM	Scroll to lower right.
SB_ENDSCROLL	End scroll.
SB_LINEDOWN	Scroll one line down.
SB_LINEUP	Scroll one line up.
SB_PAGEDOWN	Scroll one page down.
SB_PAGEUP	Scroll one page up.
SB_THUMBPOSITION	Scroll to absolute position. The current position is specified by the nPos parameter.
SB_TOP	Scroll to upper left.
nPos

Value of the high-order word of lParam. Specifies the current position of the scroll box if the nScrollCode parameter is SB_THUMBPOSITION; otherwise, the nPos parameter is not used.

Return Value

If an application processes this message, it should return zero.

Remarks

The clipboard owner can use the ScrollWindow function to scroll the image in the clipboard viewer window and invalidate the appropriate region.

See Also

ScrollWindow


WM_WINDOWPOSCHANGED
WM_WINDOWPOSCHANGED  QuickInfo  Overview  Group

WM_WINDOWPOSCHANGED

lpwp = (LPWINDOWPOS) lParam; // points to size and position data

The WM_WINDOWPOSCHANGED message is sent to a window whose size, position, or place in the Z order has changed as a result of a call to the SetWindowPos function or another window-management function.

Parameters

lpwp

Value of lParam. Points to a WINDOWPOS structure that contains information about the window's new size and position.

Return Value

If an application processes this message, it should return zero.

Default Action

The DefWindowProc function sends the WM_SIZE and WM_MOVE messages to the window.

Remarks

The WM_SIZE and WM_MOVE messages are not sent if an application handles the WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient to perform any move or size change processing during the WM_WINDOWPOSCHANGED message without calling DefWindowProc.

See Also

DefWindowProc, EndDeferWindowPos, SetWindowPos, WINDOWPOS, WM_MOVE, WM_SIZE, WM_WINDOWPOSCHANGING


WM_WINDOWPOSCHANGING
WM_WINDOWPOSCHANGING  QuickInfo  Overview  Group

WM_WINDOWPOSCHANGING

lpwp = (LPWINDOWPOS) lParam; // points to size and position data

The WM_WINDOWPOSCHANGING message is sent to a window whose size, position, or place in the Z order is about to change as a result of a call to the SetWindowPos function or another window-management function.

Parameters

lpwp

Value of lParam. Points to a WINDOWPOS structure that contains information about the window's new size and position.

Return Value

If an application processes this message, it should return zero.

Default Action

For a window with the WS_OVERLAPPED or WS_THICKFRAME style, the DefWindowProc function sends the WM_GETMINMAXINFO message to the window. This is done to validate the new size and position of the window and to enforce the CS_BYTEALIGNCLIENT and CS_BYTEALIGNWINDOW client styles. By not passing the WM_WINDOWPOSCHANGING message to the DefWindowProc function, an application can override these defaults.

Remarks

While this message is being processed, modifying any of the values in WINDOWPOS affects the window's new size, position, or place in the Z order. An application can prevent changes to the window by setting or clearing the appropriate bits in the flags member of WINDOWPOS.

See Also

DefWindowProc, EndDeferWindowPos, SetWindowPos, WINDOWPOS, WM_GETMINMAXINFO, WM_MOVE, WM_SIZE, WM_WINDOWPOSCHANGED


WM_WININICHANGE
WM_WININICHANGE  QuickInfo

WM_WININICHANGE

wParam = 0;                          // not used, must be zero

lParam = (LPARAM) (LPCTSTR) pszSection; // section-name string

An application sends the WM_WININICHANGE message to all top-level windows after making a change to the WIN.INI file. The SystemParametersInfo function sends the WM_WININICHANGE message after an application uses the function to change a setting in WIN.INI.

Parameters

pszSection

Value of lParam. Points to a string containing the name of the section that has changed. The string does not include the square brackets that enclose the section name.

Return Value

An application should return zero if it processes this message.

Remarks

To send the WM_WININICHANGE message to all top-level windows, an application can use the SendMessage function with the hwnd parameter set to HWND_BROADCAST.

Some applications send this message with lParam set to NULL. If an application receives this message with an lParam value of NULL, it should check all sections in WIN.INI that affect the application.

Calls to functions that change WIN.INI may be mapped to the registry instead. This mapping occurs when WIN.INI and the section being changed are specified in the registry under the following keys:

HKEY_LOCAL_MACHINE\Software\Microsoft\
        Windows NT\CurrentVersion\IniFileMapping

The change in the storage location has no effect on the behavior of this message.

Windows 95: The WM_WININICHANGE message is implemented on the Windows NT platform, but not on the Windows 95 platform. Windows 95 applications should use the WM_SETTINGCHANGE message, which provides equivalent functionality.

See Also

SendMessage, SystemParametersInfo, WM_DEVMODECHANGE, WM_SETTINGCHANGE


Data Types

Various simple data types define the size and meaning of parameters, return values, and members associated with the functions, messages, and structures of Microsoft Windows. The following table contains character, integer, and Boolean types; pointer types; and handles. The character, integer, and Boolean types are common to most C compilers. Many of the pointer-type names begin with a prefix of P or LP. A Windows-based application uses a handle to refer to a resource that has been loaded into memory. Windows provides access to these resources through internally maintained tables that contain individual entries for each handle. Each entry in the handle table contains the address of the resource and a means of identifying the resource type.

Type	Definition
ABORTPROC	Pointer to an application-defined callback function that the operating system calls when a print job is to be cancelled during spooling. See AbortProc for information on functions of this type.
ACMDRIVERENUMCB	Pointer to an application-defined callback function that is used with the acmDriverEnum function. See acmDriverEnumCallback for information on functions of this type.
ACMDRIVERPROC	Pointer to an application-defined callback function that is used with an installable audio compression manager (ACM) driver. See acmDriverProc for information on functions of this type.
ACMFILTERCHOOSEHOOKPROC	Pointer to an application-defined function that hooks the acmFilterChoose dialog box. See acmFilterChooseHookProc for information on functions of this type.
ACMFILTERENUMCB	Pointer to an application-defined callback function that is used with the acmFilterEnum function. See acmFilterEnumCallback for information on functions of this type.
ACMFILTERTAGENUMCB	Pointer to an application-defined callback function that is used with the acmFilterTagEnum function. See acmFilterTagEnumCallback for information on functions of this type.
ACMFORMATCHOOSEHOOKPROC	Pointer to an application-defined function that hooks the acmFormatChoose dialog box. See acmFormatChooseHookProc for information on functions of this type.
ACMFORMATENUMCB	Pointer to an application-defined callback function that is used with the acmFormatEnum function. See acmFormatEnumCallback for information on functions of this type.
ACMFORMATTAGENUMCB	Pointer to an application-defined callback function that is used with the acmFormatTagEnum function. See acmFormatTagEnumCallback for information on functions of this type.
APPLET_PROC	Pointer to a library-defined callback function that is the entry point for a Control Panel application. See CplApplet for information on functions of this type.
ATOM	Atom (a reference to a character string in an atom table).
BOOL	Boolean variable (should be TRUE or FALSE).
BOOLEAN	Boolean variable (should be TRUE or FALSE).
BYTE	Byte (8 bits).
CCHAR	Windows character.
CHAR	Windows character.
COLORREF	Red, green, blue (RGB) color value (32 bits).
CONST	Variable whose value is to remain constant during execution.
CRITICAL_SECTION	Critical-section object.
CTRYID	Country identifier.
DLGPROC	Pointer to an application-defined dialog box callback procedure.
DWORD	Doubleword (32 bits).
DWORDLONG	Double (64 bits).
EDITWORDBREAKPROC	Pointer to an application-defined callback function that the operating system calls when a multiline edit control needs to break a line of text. See EditWordBreakProc for information on functions of this type.
ENHMFENUMPROC	Pointer to an application-defined callback function that enumerates enhanced-metafile records.
ENUMRESLANGPROC	Pointer to an application-defined callback function that enumerates resource languages.
ENUMRESNAMEPROC	Pointer to an application-defined callback function that enumerates resource names.
ENUMRESTYPEPROC	Pointer to an application-defined callback function that enumerates resource types.
FARPROC	Pointer to a callback function.
FLOAT	Floating-point variable.
FONTENUMPROC	Pointer to an application-defined callback function that enumerates fonts.
GLOBALHANDLE	Handle of a global memory block.
GOBJENUMPROC	Pointer to an application-defined callback function that enumerates graphics device interface (GDI) objects.
GRAYSTRINGPROC	Pointer to an application-defined callback function that draws gray text.
HACCEL	Handle of an accelerator table.
HANDLE	Handle of an object.
HBITMAP	Handle of a bitmap.
HBRUSH	Handle of a brush.
HCOLORSPACE	Windows 95 only: Handle of a logical color space.
HCONV	Handle of a dynamic data exchange (DDE) conversation.
HCONVLIST	Handle of a DDE conversation list.
HCURSOR	Handle of a cursor.
HDC	Handle of a device context (DC).
HDDEDATA	Handle of DDE data.
HDWP	Handle of a deferred window position structure.
HENHMETAFILE	Handle of an enhanced metafile.
HFILE	Handle of a file.
HFONT	Handle of a font.
HGDIOBJ	Handle of a GDI object.
HGLOBAL	Handle of a global memory block.
HHOOK	Handle of a hook.
HICON	Handle of an icon.
HIMAGELIST	Handle to an image list.
HINSTANCE	Handle of an instance.
HKEY	Handle of a registry key.
HKL	Windows 95 only: Handle of a keyboard layout.
HLOCAL	Handle of a local memory block.
HMENU	Handle of a menu.
HMETAFILE	Handle of a metafile.
HMODULE	Handle of a module.
HOOKPROC	Pointer to an application-defined hook function.
HPALETTE	Handle of a palette.
HPEN	Handle of a pen.
HRGN	Handle of a region.
HRSRC	Handle of a resource.
HSZ	Handle of a DDE string.
HWINSTA	Handle of a workstation.
HWND	Handle of a window.
INT	Signed integer.
LANGID	Language identifier.
LCID	Locale identifier.
LCSCSTYPE	Color space type.
LCSGAMUTMATCH	Gamut-matching method.
LCTYPE	Locale type.
LINEDDAPROC	Pointer to a callback function that processes line coordinates.
LOCALHANDLE	Handle of a local memory block.
LONG	32-bit signed value.
LONGLONG	Double (64 bits).
LP	Pointer to a null-terminated Unicode™ string.
LPARAM	32-bit message parameter.
LPBOOL	Pointer to a Boolean variable.
LPBYTE	Pointer to a byte.
LPCCH	Pointer to a constant Windows character.
LPCCHOOKPROC	Pointer to an application-defined hook function.
LPCFHOOKPROC	Pointer to an application-defined hook function.
LPCH	Pointer to a Windows character.
LPCOLORREF	Pointer to a COLORREF value.
LPCRITICAL_SECTION	Pointer to a critical-section object.
LPCSTR	Pointer to a constant null-terminated Windows character string.
LPCTSTR	Pointer to a constant null-terminated Unicode or Windows character string.
LPCWCH	Pointer to a constant null-terminated Unicode character.
LPCWSTR	Pointer to a constant null-terminated Unicode character string.
LPDWORD	Pointer to an unsigned doubleword (32 bits).
LPFRHOOKPROC	Pointer to an application-defined hook function.
LPHANDLE	Pointer to a handle.
LPHANDLER_FUNCTION	Pointer to a handler function.
LPINT	Pointer to a signed integer.
LPLONG	Pointer to a signed long (32 bits).
LPOFNHOOKPROC	Pointer to an application-defined hook function.
LPPRINTHOOKPROC	Pointer to an application-defined hook function.
LPSETUPHOOKPROC	Pointer to an application-defined hook function.
LPSTR	Pointer to a null-terminated Windows character string.
LPTCH	Pointer to a Unicode character or a Windows character.
LPTSTR	Pointer to a null-terminated Windows or Unicode character string.
LRESULT	Signed result of message processing.
LPVOID	Pointer to any type.
LPWCH	Pointer to a Unicode character.
LPWORD	Pointer to an unsigned word (16 bits).
LPWSTR	Pointer to a null-terminated Unicode character string.
LUID	Locally unique identifier.
MFENUMPROC	Pointer to an application-defined callback function that enumerates metafile records.
NPSTR	Pointer to a null-terminated Windows character string.
NWPSTR	Pointer to a null-terminated Unicode string.
PBOOL	Pointer to a Boolean variable.
PBOOLEAN	Pointer to a Boolean variable.
PBYTE	Pointer to a byte.
PCCH	Pointer to a constant Windows character.
PCH	Pointer to a Windows character.
PCHAR	Pointer to a Windows character.
PCRITICAL_SECTION	Pointer to a critical-section object.
PCSTR	Pointer to a constant null-terminated Windows character string.
PCWCH	Pointer to a constant Unicode character.
PCWSTR	Pointer to a constant null-terminated Unicode character string.
PDWORD	Pointer to an unsigned doubleword (32 bits).
PFLOAT	Pointer to a floating-point variable.
PFNCALLBACK	Pointer to a callback function.
PHANDLE	Pointer to a handle.
PHANDLER_ROUTINE	Pointer to a handler routine.
PHKEY	Pointer to a registry key.
PINT	Pointer to a signed integer.
PLCID	Pointer to a locale identifier.
PLONG	Pointer to a signed long (32 bits).
PLUID	Pointer to a locally unique identifier (LUID).
PROC	Pointer to a callback function.
PROPENUMPROC	Pointer to an application-defined callback function that enumerates window properties. See PropEnumProc for information on functions of this type.
PROPENUMPROCEX	Pointer to an application-defined callback function that enumerates window properties. See PropEnumProcEx for information on functions of this type.
PSHORT	Pointer to a signed short (16 bits).
PSID	Pointer to a security identifier (SID).
PSTR	Pointer to a null-terminated Windows character string.
PSZ	Pointer to a null-terminated Windows character string.
PTBYTE	Pointer to a Windows or Unicode character.
PTCH	Pointer to a Windows or Unicode character.
PTCHAR	Pointer to a Windows or Unicode character.
PTSTR	Pointer to a null-terminated Windows or Unicode character string.
PUCHAR	Pointer to an unsigned Windows character.
PUINT	Pointer to an unsigned integer.
PULONG	Pointer to an unsigned long (32 bits).
PUSHORT	Pointer to an unsigned short (16 bits).
PVOID	Pointer to any type.
PWCH	Pointer to a Unicode character.
PWCHAR	Pointer to a Unicode character.
PWORD	Pointer to an unsigned word (16 bits).
PWSTR	Pointer to a null-terminated Unicode character string.
REGSAM	Security access mask for registry key.
SC_HANDLE	Handle of a service.
SENDASYNCPROC	Pointer to an application-defined callback function that the operating system calls when the SendMessageCallback function is called. The system passes the message to the callback function after passing the message to the destination window procedure. See SendAsyncProc for information on functions of this type.
SERVICE_STATUS_HANDLE	Handle of a service status value.
SHORT	Short integer.
SPHANDLE	Pointer to a handle.
TBYTE	Windows or Unicode character.
TCHAR	Unicode character or Windows character.
TIMERPROC	Pointer to an application-defined timer callback function.
UCHAR	Unsigned Windows character.
UINT	Unsigned integer.
ULONG	Unsigned long integer (32 bits).
USHORT	Unsigned short integer (16 bits).
VOID	Any type.
WCHAR	Unicode character.
WNDENUMPROC	Pointer to an application-defined callback function that enumerates windows.
WNDPROC	Pointer to an application-defined window procedure.
WORD	Unsigned word (16 bits).
WPARAM	32-bit message parameter.
YIELDPROC	Pointer to a yield callback function.


ABC
ABC  QuickInfo

typedef struct _ABC { // abc

    int     abcA;

    UINT    abcB;

    int     abcC;

} ABC;

The ABC structure contains the width of a character in a TrueType font.

Members

abcA

Specifies the "A" spacing of the character. The "A" spacing is the distance to add to the current position before drawing the character glyph.

abcB

Specifies the "B" spacing of the character. The "B" spacing is the width of the drawn portion of the character glyph.

abcC

Specifies the "C" spacing of the character. The "C" spacing is the distance to add to the current position to provide white space to the right of the character glyph.

Remarks

The total width of a character is the summation of the "A," "B," and "C" spaces. Either the "A" or the "C" space can be negative to indicate underhangs or overhangs.

See Also

GetCharABCWidths


ABCFLOAT
ABCFLOAT  QuickInfo

typedef struct _ABCFLOAT { // abcf

    FLOAT   abcfA;

    FLOAT   abcfB;

    FLOAT   abcfC;

} ABCFLOAT;

The ABCFLOAT structure contains the A, B, and C widths of a font character.

Members

abcfA

Specifies the "A" spacing of the character. The "A" spacing is the distance to add to the current position before drawing the character glyph.

abcfB

Specifies the "B" spacing of the character. The "B" spacing is the width of the drawn portion of the character glyph.

abcfC

Specifies the "C" spacing of the character. The "C" spacing is the distance to add to the current position to provide white space to the right of the character glyph.

Remarks

The A, B, and C widths are measured along the base line of the font.

The character increment (total width) of a character is the sum of the "A," "B," and "C" spaces. Either the "A" or the "C" space can be negative to indicate underhangs or overhangs.

See Also

GetCharABCWidthsFloat


ACCEL
ACCEL  QuickInfo

typedef struct tagACCEL { // accl

    BYTE   fVirt;

    WORD   key;

    WORD   cmd;

} ACCEL;

The ACCEL structure defines an accelerator key used in an accelerator table.

Members

fVirt

Specifies the accelerator flags. This member can be a combination of the following values:

Value	Meaning
FALT	The ALT key must be held down when the accelerator key is pressed.
FCONTROL	The CTRL key must be held down when the accelerator key is pressed.
FNOINVERT	Specifies that no top-level menu item is highlighted when the accelerator is used. If this flag is not specified, a top-level menu item will be highlighted, if possible, when the accelerator is used.
FSHIFT	The SHIFT key must be held down when the accelerator key is pressed.
FVIRTKEY	The key member specifies a virtual-key code. If this flag is not specified, key is assumed to specify an ASCII character code.
key

Specifies the accelerator key. This member can be either a virtual-key code or an ASCII character code.

cmd

Specifies the accelerator identifier. This value is placed in the low-order word of the wParam parameter of the WM_COMMAND or WM_SYSCOMMAND message when the accelerator is pressed.

See Also

WM_COMMAND, WM_SYSCOMMAND


ACCESS_ALLOWED_ACE
ACCESS_ALLOWED_ACE  QuickInfo

typedef struct _ACCESS_ALLOWED_ACE { // aaace

    ACE_HEADER Header;

    ACCESS_MASK Mask;

    DWORD SidStart;

} ACCESS_ALLOWED_ACE;

The ACCESS_ALLOWED_ACE structure defines an access-control entry (ACE) for the discretionary access-control list (ACL) that controls access to an object. An access-allowed ACE allows access to an object for a specific subject identified by a security identifier (SID).

Members

Header

Specifies an ACE_HEADER structure.

Mask

Specifies an ACCESS_MASK structure that specifies the access rights granted by this ACE.

SidStart

Specifies an SID. The access rights specified by the Mask member are granted to any subject possessing an enabled SID matching this field.

Remarks

ACE structures must be aligned on doubleword boundaries. All Windows memory-management functions return doubleword-aligned handles to memory.

See Also

AddAccessAllowedAce, AddAce, GetAce, ACCESS_DENIED_ACE, ACCESS_MASK, ACE_HEADER, ACL, SID, SYSTEM_ALARM_ACE, SYSTEM_AUDIT_ACE


ACCESS_DENIED_ACE
ACCESS_DENIED_ACE  QuickInfo

typedef struct _ACCESS_DENIED_ACE { // adace

    ACE_HEADER  Header;

    ACCESS_MASK Mask;

    DWORD       SidStart;

} ACCESS_DENIED_ACE;

The ACCESS_DENIED_ACE structure defines an access-control entry (ACE) for the discretionary access-control list (ACL) controlling access to an object. An access-denied ACE denies access to an object for a specific subject identified by a security identifier (SID).

Members

Header

Specifies an ACE_HEADER structure.

Mask

Specifies an ACCESS_MASK structure specifying the access rights explicitly denied by this ACE.

SidStart

Specifies an SID. The access rights specified by the Mask member are denied to any subject possessing an enabled SID matching this field.

Remarks

ACE structures must be aligned on doubleword boundaries. All Windows memory-management functions return doubleword-aligned handles to memory.

See Also

AddAccessDeniedAce, ACCESS_ALLOWED_ACE, ACCESS_MASK, ACE_HEADER, ACL, SID, SYSTEM_ALARM_ACE, SYSTEM_AUDIT_ACE


ACCESS_MASK
ACCESS_MASK  QuickInfo

typedef DWORD ACCESS_MASK;

The ACCESS_MASK structure is one doubleword value containing standard, specific, and generic rights. These rights are used in access-control entries (ACEs) and are the primary means of specifying the requested or granted access to an object.

The bits in this value are allocated as follows:

Bits	Meaning
0 through 15	Specific rights. Contains the access mask specific to the object type associated with the mask.
16 through 23	Standard rights. Contains the object's standard access rights and can be a combination of the following predefined flags:
	Bit	Flag	Meaning
	16	DELETE	Delete access
	17	READ_CONTROL	Read access to the owner, group, and discretionary access-control list (ACL) of the security descriptor
	18	WRITE_DAC	Write access to the discretionary access-control list (ACL)
	19	WRITE_OWNER	Write access to owner
	20	SYNCHRONIZE	Windows NT: Synchronize access
Bits	Meaning
24	Access system security (ACCESS_SYSTEM_SECURITY). This flag is not a typical access type. It is used to indicate access to a system ACL. This type of access requires the calling process to have a specific privilege.
25	Maximum allowed (MAXIMUM_ALLOWED)
26 through 27	Reserved
28	Generic all (GENERIC_ALL)
29	Generic execute (GENERIC_EXECUTE)
30	Generic write (GENERIC_WRITE)
31	Generic read (GENERIC_READ)
The following constants represent the specific and standard access rights:

#define SPECIFIC_RIGHTS_ALL           0x0000FFFF

#define STANDARD_RIGHTS_REQUIRED      0x000F0000

#define STANDARD_RIGHTS_ALL           0x001F0000

See Also

GENERIC_MAPPING


ACCESSTIMEOUT
ACCESSTIMEOUT  QuickInfo  Overview  Group

typedef struct tagACCESSTIMEOUT {     // ato

    UINT  cbSize;

    DWORD dwFlags;

    DWORD iTimeOutMSec;

} ACCESSTIMEOUT;

The ACCESSTIMEOUT structure contains information about the time-out period associated with the Win32 accessibility features. The accessibility time-out period is the length of time that must pass without keyboard and mouse input before the operating system automatically turns off accessibility features. The accessibility features affected by the time-out are the FilterKeys features (SlowKeys, BounceKeys, and RepeatKeys), MouseKeys, ToggleKeys, and StickyKeys. The accessibility time-out is designed for computers that are shared by several users so that options selected by one user do not inconvenience a subsequent user.

Windows 95 only: The accessibility time-out affects the High Contrast Mode setting.

Members

cbSize

Specifies the size, in bytes, of this structure.

dwFlags

A set of bit flags that specify properties of the time-out behavior for accessibility features. The following values are defined:

Value	Meaning
ATF_ONOFFFEEDBACK	If this flag is set, the operating system plays a descending siren sound when the time-out period elapses and the accessibility features are turned off.
ATF_AVAILABLE	If this flag is set, you can set a time-out period for accessibility features. An application can retrieve this value, but cannot set it.
ATF_TIMEOUTON	If this flag is set, a time-out period has been set for accessibility features. If this flag is not set, the features will not time out even though a time-out period is specified.
iTimeOutMSec

Specifies the time-out period, in milliseconds.

Remarks

Use an ACCESSTIMEOUT structure when calling the SystemParametersInfo function with the uiAction parameter set to the SPI_GETACCESSTIMEOUT or SPI_SETACCESSTIMEOUT value. When using SPI_GETACCESSTIMEOUT, you must specify the cbSize member of the ACCESSTIMEOUT structure; the SystemParametersInfo function fills in the remaining members. Specify all structure members when using the SPI_SETACCESSTIMEOUT value.

See Also

SystemParametersInfo


ACE
ACE  QuickInfo

An ACE is an access-control entry (ACE) in an access-control list (ACL).

Following are the currently defined ACE types:

ACE type	Structure	ACL Type
Access allowed	ACCESS_ALLOWED_ACE	Discretionary
Access denied	ACCESS_DENIED_ACE	Discretionary
System alarm	SYSTEM_ALARM_ACE	System
System audit	SYSTEM_AUDIT_ACE	System
System-alarm ACEs are not supported in the current version of Windows NT.

Remarks

An ACL contains a list of ACEs. An ACE defines access to an object for a specific user or group or defines the types of access that generate system-administration messages or alarms for a specific user or group. The user or group is identified by a security identifier (SID).

Each ACE starts with an ACE_HEADER structure. The format of the data following the header varies according to the ACE type specified in the header.

See Also

AddAce, ACCESS_ALLOWED_ACE, ACCESS_DENIED_ACE, ACL, SYSTEM_ALARM_ACE, SYSTEM_AUDIT_ACE


ACE_HEADER
ACE_HEADER  QuickInfo

typedef struct _ACE_HEADER { // acehdr

    BYTE AceType;

    BYTE AceFlags;

    WORD AceSize;

} ACE_HEADER;

The ACE_HEADER structure describes the type and size of an access-control entry (ACE).

Members

AceType

Specifies the ACE type. This member can be one of the following values:

Value	ACE type
ACCESS_ALLOWED_ACE_TYPE	Access-allowed (defined by the ACCESS_ALLOWED_ACE structure)
ACCESS_DENIED_ACE_TYPE	Access-denied (defined by the ACCESS_DENIED_ACE structure)
SYSTEM_AUDIT_ACE_TYPE	System-audit (defined by the SYSTEM_AUDIT_ACE structure)
System-alarm ACEs are not supported in the current version of Windows NT. Applications cannot use the SYSTEM_ALARM_ACE_TYPE value or SYSTEM_ALARM_ACE structure.

AceFlags

Specifies a set of ACE type-specific control flags. This member can be a combination of the following values:

Value	Meaning
CONTAINER_INHERIT_ACE
	The ACE is inherited by container objects, such as directories.
INHERIT_ONLY_ACE
	The ACE does not apply to the container object, but to objects contained by it.
NO_PROPAGATE_INHERIT_ACE
	The OBJECT_INHERIT_ACE and CONTAINER_INHERIT_ACE bits are not propagated to an inherited ACE.
OBJECT_INHERIT_ACE
	The ACE is inherited by noncontainer objects, such as files created within the container object to which the ACE is assigned.
FAILED_ACCESS_ACE_FLAG
	Used with system-audit and system-alarm ACEs to indicate a message is generated for failed access attempts.
SUCCESSFUL_ACCESS_ACE_FLAG
	Used with system-audit and system-alarm ACEs to indicate a message is generated for successful access attempts.
AceSize

Specifies the size, in bytes, of the ACE.

Remarks

An ACE defines access to an object for a specific user or group or defines the types of access that generate system-administration messages or alarms for a specific user or group. The user or group is identified by a security identifier (SID).

See Also

ACCESS_ALLOWED_ACE, ACCESS_DENIED_ACE, ACL, SYSTEM_ALARM_ACE, SYSTEM_AUDIT_ACE


ACL
ACL  QuickInfo

typedef struct _ACL { // acl

    BYTE AclRevision;

    BYTE Sbz1;

    WORD AclSize;

    WORD AceCount;

    WORD Sbz2;

} ACL;

The ACL structure is the header of an access-control list (ACL). A complete ACL consists of an ACL structure followed by an ordered list of zero or more access-control entries (ACEs).

Members

AclRevision

Specifies the ACL's revision level. This value should be ACL_REVISION. All ACEs in an ACL must be at the same revision level.

Sbz1

Specifies a zero byte of padding that aligns the AclRevision member on a 16-bit boundary.

AclSize

Specifies the size, in bytes, of the ACL. This value includes both the ACL structure and all the ACEs.

AceCount

Specifies the number of ACEs stored in the ACL.

Sbz2

Specifies two zero bytes of padding that align the ACL structure on a 32-bit boundary.

Remarks

An ACL includes a sequential list of zero or more ACEs. The individual ACEs in an ACL are numbered from 0 to n, where n+1 is the number of ACEs in the ACL. When editing an ACL, an application refers to an ACE within the ACL by its index.

There are two types of ACL: discretionary and system.

A discretionary ACL is controlled by the owner of an object or anyone granted WRITE_DAC access to the object. It specifies the access particular users and groups can have to an object. For example, the owner of a file can use a discretionary ACL to control which users and groups can and cannot have access to the file.

An object may also have system-level security information associated with it, in the form of a system ACL controlled by a system administrator. A system ACL can allow the system administrator to audit any attempts to gain access to an object.

Three ACE structures are currently defined:

ACE structure	Description
ACCESS_ALLOWED_ACE	Grants specified rights to a user or group. This ACE is stored in a discretionary ACL.
ACCESS_DENIED_ACE	Denies specified rights to a user or group. This ACE is stored in a discretionary ACL.
SYSTEM_AUDIT_ACE	Specifies what types of access will cause system-level audits. This ACE is stored in a system ACL.
A fourth ACE structure, SYSTEM_ALARM_ACE, is not currently supported by Windows NT.

The ACL structure is to be treated as though it were opaque and applications are not to attempt to work with its members directly. To ensure that ACLs are semantically correct, applications can use the functions listed in the SeeAlso section to create and manipulate ACLs.

Each ACL and ACE structure begins on a doubleword boundary.

See Also

AddAce, DeleteAce, GetAclInformation, GetSecurityDescriptorDacl, GetSecurityDescriptorSacl, InitializeAcl, IsValidAcl, SetAclInformation, SetSecurityDescriptorDacl, SetSecurityDescriptorSacl


ACL_REVISION_INFORMATION
ACL_REVISION_INFORMATION  QuickInfo

typedef struct _ACL_REVISION_INFORMATION {

    DWORD   AclRevision;

} ACL_REVISION_INFORMATION;

The ACL_REVISION_INFORMATION structure contains revision information about an ACL structure.

Members

AclRevision

Specifies a revision number. The current revision number is ACL_REVISION.

See Also

GetAclInformation, SetAclInformation, ACL, ACL_INFORMATION_CLASS, ACL_SIZE_INFORMATION


ACL_SIZE_INFORMATION
ACL_SIZE_INFORMATION  QuickInfo

typedef struct _ACL_SIZE_INFORMATION {

    DWORD   AceCount;

    DWORD   AclBytesInUse;

    DWORD   AclBytesFree;

} ACL_SIZE_INFORMATION;

The ACL_SIZE_INFORMATION structure contains information about the size of an ACL structure.

Members

AceCount

Specifies the number of access-control entries (ACEs) in the access-control list (ACL).

AclBytesInUse

Specifies the number of bytes in the ACL actually used to store the ACEs and ACL structure. This may be less than the total number of bytes allocated to the ACL.

AclBytesFree

Specifies the number of unused bytes in the ACL.

See Also

GetAclInformation, SetAclInformation, ACL, ACL_INFORMATION_CLASS, ACL_REVISION_INFORMATION


ACTION_HEADER
ACTION_HEADER  QuickInfo

typedef struct _ACTION_HEADER {

    ULONG   transport_id;

    USHORT  action_code;

    USHORT  reserved;

} ACTION_HEADER;

The ACTION_HEADER structure contains information about an action. This action is an extension to the standard transport interface.

Members

transport_id

Specifies the transport provider. This member can be used to check the validity of the request by the transport.

This member is always a four-character string. All strings starting with the letter M are reserved, as shown in the following example:

String	Meaning
M000	All transports
MNBF	NBF
MABF	AsyBEUI
MXNS	XNS
action_code

Specifies the action.

reserved

Reserved.

Remarks

The scope of the action is determined by the ncb_lsn and ncb_num members of the NCB structure, as follows:

	ncb_lsn = 0	ncb_lsn != 0
ncb_num = 0	Action applies to control channel associated with the valid LAN adapter.	Action applies to connection identifier associated with the valid local session number.
ncb_num != 0	Action applies to address associated with the valid LAN adapter.	Illegal combination.
See Also

NCB


ADAPTER_STATUS
ADAPTER_STATUS  QuickInfo

typedef struct _ADAPTER_STATUS { // adptst

    UCHAR   adapter_address[6];

    UCHAR   rev_major;

    UCHAR   reserved0;

    UCHAR   adapter_type;

    UCHAR   rev_minor;

    WORD    duration;

    WORD    frmr_recv;

    WORD    frmr_xmit;

    WORD    iframe_recv_err;

    WORD    xmit_aborts;

    DWORD   xmit_success;

    DWORD   recv_success;

    WORD    iframe_xmit_err;

    WORD    recv_buff_unavail;

    WORD    t1_timeouts;

    WORD    ti_timeouts;

    DWORD   reserved1;

    WORD    free_ncbs;

    WORD    max_cfg_ncbs;

    WORD    max_ncbs;

    WORD    xmit_buf_unavail;

    WORD    max_dgram_size;

    WORD    pending_sess;

    WORD    max_cfg_sess;

    WORD    max_sess;

    WORD    max_sess_pkt_size;

    WORD    name_count;

} ADAPTER_STATUS;

The ADAPTER_STATUS structure contains information about a network adapter. This structure is pointed to by the ncb_buffer member of the NCB structure. ADAPTER_STATUS is followed by as many NAME_BUFFER structures as required to describe the network adapters on the system.

Members

adapter_address

Specifies encoded address of the adapter.

rev_major

Specifies the major software-release level. This value is 3 for IBM NetBIOS 3. x.

reserved0

Reserved. This value is always zero.

adapter_type

Specifies the adapter type. This value is 0xFF for a Token Ring adapter or 0xFE for an Ethernet adapter.

rev_minor

Specifies the minor software-release level. This value is zero for IBM NetBIOS x.0.

duration

Specifies the duration of the reporting period, in minutes.

frmr_recv

Specifies the number of FRMR frames received.

frmr_xmit

Specifies the number of FRMR frames transmitted.

iframe_recv_err

Specifies the number of I frames received in error.

xmit_aborts

Specifies the number of aborted transmissions.

xmit_success

Specifies the number of successfully transmitted packets.

recv_success

Specifies the number of successfully received packets.

iframe_xmit_err

Specifies the number of I frames transmitted in error.

recv_buff_unavail

Specifies the number of times a buffer was not available to service a request from a remote computer.

t1_timeouts

Specifies the number of times that the DLC T1 timer timed out.

ti_timeouts

Specifies the number of times that the ti inactivity timer timed out.The ti timer is used to detect links that have been broken.

reserved1

Reserved. This value is always zero.

free_ncbs

Specifies the current number of free network control blocks.

max_cfg_ncbs

Undefined for IBM NetBIOS 3.0.

max_ncbs

Undefined for IBM NetBIOS 3.0.

xmit_buf_unavail

Undefined for IBM NetBIOS 3.0.

max_dgram_size

Specifies the maximum size of a datagram packet. This value is always at least 512 bytes.

pending_sess

Specifies the number of pending sessions.

max_cfg_sess

Specifies the configured maximum pending sessions.

max_sess

Undefined for IBM NetBIOS 3.0.

max_sess_pkt_size

Specifies the maximum size of a session data packet.

name_count

Specifies the number of names in the local names table.

See Also

NAME_BUFFER, NCB


ADDJOB_INFO_1
ADDJOB_INFO_1  QuickInfo

typedef struct _ADDJOB_INFO_1 { // aji1

    LPTSTR  Path;

    DWORD   JobId;

} ADDJOB_INFO_1;

The ADDJOB_INFO_1 structure identifies a print job as well as the directory and file in which an application can store that job.

Members

Path

Points to a null-terminated string that contains the path and filename that the application can use to store the print job.

JobId

Identifies the print job.

See Also

AddJob


ANIMATIONINFO
ANIMATIONINFO  QuickInfo

typedef struct tagANIMATIONINFO {

    UINT cbSize;

    int  iMinAnimate;

} ANIMATIONINFO, FAR *LPANIMATIONINFO;

The ANIMATIONINFO structure specifies the animation effects associated with user actions. This structure is used with the SystemParametersInfo function when the SPI_GETANIMATION or SPI_SETANIMATION action value is specified.

Members

cbSize

Specifies the size of the structure, in bytes.

iMinAnimate

Indicates that minimize and restore animation is enabled (if the member is a nonzero value) or not enabled (if zero).

See Also

SystemParametersInfo


APPBARDATA
APPBARDATA  QuickInfo

typedef struct _AppBarData { // abd

    DWORD  cbSize;           // sizeof(APPBARDATA)

    HWND   hWnd;             // handle of appbar

    UINT   uCallbackMessage; // see below

    UINT   uEdge;            // see below

    RECT   rc;               // see below

    LPARAM lParam;           // see below

} APPBARDATA, *PAPPBARDATA;

Contains information that the system uses to process appbar messages.

Members

uCallbackMessage

Application-defined message identifier. The application uses the specified identifier for notification messages that it sends to the the appbar identified by the hWnd member. This member is used when sending the ABM_NEW message.

uEdge

Flag that specifies an edge of the screen. This member can be one of the following values:

ABE_BOTTOM	Bottom edge
ABE_LEFT	Left edge
ABE_RIGHT	Right edge
ABE_TOP	Top edge
This member is used when sending the ABM_GETAUTOHIDEBAR, ABM_QUERYPOS, ABM_SETAUTOHIDEBAR, and ABM_SETPOS messages.

rc

RECT structure that contains the bounding rectangle, in screen coordinates, of an appbar or the Windows taskbar. This member is used when sending the ABM_GETTASKBARPOS, ABM_QUERYPOS, and ABM_SETPOS messages.

lParam

Message-dependent value. This member is used with the ABM_SETAUTOHIDEBAR message.

Remarks

This structure is used with the SHAppBarMessage function.

See Also

SHAppBarMessage


BITMAP
BITMAP  QuickInfo

typedef struct tagBITMAP {  // bm

   LONG   bmType;

   LONG   bmWidth;

   LONG   bmHeight;

   LONG   bmWidthBytes;

   WORD   bmPlanes;

   WORD   bmBitsPixel;

   LPVOID bmBits;

} BITMAP;

The BITMAP structure defines the type, width, height, color format, and bit values of a bitmap.

Members

bmType

Specifies the bitmap type. This member must be zero.

bmWidth

Specifies the width, in pixels, of the bitmap. The width must be greater than zero.

bmHeight

Specifies the height, in pixels, of the bitmap. The height must be greater than zero.

bmWidthBytes

Specifies the number of bytes in each scan line. This value must be divisible by 2, because Windows assumes that the bit values of a bitmap form an array that is word aligned.

bmPlanes

Specifies the count of color planes.

bmBitsPixel

Specifies the number of bits required to indicate the color of a pixel.

bmBits

Points to the location of the bit values for the bitmap. The bmBits member must be a long pointer to an array of character (1-byte) values.

Remarks

The bitmap formats currently used are monochrome and color. The monochrome bitmap uses a one-bit, one-plane format. Each scan is a multiple of 32 bits.

Scans are organized as follows for a monochrome bitmap of height n:

    Scan 0

    Scan 1

    .

    .

    .

    Scan n-2

    Scan n-1

The pixels on a monochrome device are either black or white. If the corresponding bit in the bitmap is 1, the pixel is set to the foreground color; if the corresponding bit in the bitmap is zero, the pixel is set to the background color.

All devices that have the RC_BITBLT device capability support bitmaps. For more information, see GetDeviceCaps.

Each device has a unique color format. To transfer a bitmap from one device to another, use the GetDIBits and SetDIBits functions.

See Also

CreateBitmapIndirect, GetObject


BITMAPCOREHEADER
BITMAPCOREHEADER  QuickInfo

typedef struct tagBITMAPCOREHEADER { // bmch

        DWORD   bcSize;

        WORD    bcWidth;

        WORD    bcHeight;

        WORD    bcPlanes;

        WORD    bcBitCount;

} BITMAPCOREHEADER;

The BITMAPCOREHEADER structure contains information about the dimensions and color format of a device-independent bitmap (DIB).

Members

bcSize

Specifies the number of bytes required by the structure.

bcWidth

Specifies the width of the bitmap, in pixels.

bcHeight

Specifies the height of the bitmap, in pixels.

bcPlanes

Specifies the number of planes for the target device. This value must be 1.

bcBitCount

Specifies the number of bits per pixel. This value must be 1, 4, 8, or 24.

Remarks

The BITMAPCOREINFO structure combines the BITMAPCOREHEADER structure and a color table to provide a complete definition of the dimensions and colors of a DIB. For more information about specifying a device-independent bitmap, see BITMAPCOREINFO structure.

An application should use the information stored in the bcSize member to locate the color table in a BITMAPCOREINFO structure, using a method such as the following:

pColor = ((LPBYTE) pBitmapCoreInfo +

        (WORD) (pBitmapCoreInfo -> bcSize))


BITMAPCOREINFO
BITMAPCOREINFO  QuickInfo

typedef struct _BITMAPCOREINFO {    // bmci

        BITMAPCOREHEADER  bmciHeader;

        RGBTRIPLE         bmciColors[1];

} BITMAPCOREINFO;

The BITMAPCOREINFO structure defines the dimensions and color information for a device-independent bitmap (DIB).

Members

bmciHeader

Specifies a BITMAPCOREHEADER structure that contains information about the dimensions and color format of a DIB.

bmciColors

Specifies an array of RGBTRIPLE structures that define the colors in the bitmap.

Remarks

A DIB consists of two parts: a BITMAPCOREINFO structure describing the dimensions and colors of the bitmap, and an array of bytes defining the pixels of the bitmap. The bits in the array are packed together, but each scan line must be padded with zeroes to end on a LONG boundary. The origin of the bitmap is the lower left corner.

The bcBitCount member of the BITMAPCOREHEADER structure determines the number of bits that define each pixel and the maximum number of colors in the bitmap. This member can be one of the following values:

Value	Meaning
1	The bitmap is monochrome, and the bmciColors member contains two entries. Each bit in the bitmap array represents a pixel. If the bit is clear, the pixel is displayed with the color of the first entry in the bmciColors table; if the bit is set, the pixel has the color of the second entry in the table.
4	The bitmap has a maximum of 16 colors, and the bmciColors member contains up to 16 entries. Each pixel in the bitmap is represented by a 4-bit index into the color table. For example, if the first byte in the bitmap is 0x1F, the byte represents two pixels. The first pixel contains the color in the second table entry, and the second pixel contains the color in the sixteenth table entry.
8	The bitmap has a maximum of 256 colors, and the bmciColors member contains up to 256 entries. In this case, each byte in the array represents a single pixel.
24	The bitmap has a maximum of 2 (24)  colors, and the bmciColors member is NULL. Each three-byte triplet in the bitmap array represents the relative intensities of red, green, and blue, respectively, for a pixel.
The colors in the bmciColors table should appear in order of importance.

Alternatively, for functions that use DIBs, the bmciColors member can be an array of 16-bit unsigned integers that specify indices into the currently realized logical palette, instead of explicit RGB values. In this case, an application using the bitmap must call the DIB functions (CreateDIBitmap, CreateDIBPatternBrush, and CreateDIBSection) with the iUsage parameter set to DIB_PAL_COLORS.

Note  The bmciColors member should not contain palette indices if the bitmap is to be stored in a file or transferred to another application. Unless the application has exclusive use and control of the bitmap, the bitmap color table should contain explicit RGB values.

See Also

BITMAPCOREHEADER, CreateDIBitmap, CreateDIBPatternBrush, CreateDIBSection RGBTRIPLE


BITMAPFILEHEADER
BITMAPFILEHEADER  QuickInfo

typedef struct tagBITMAPFILEHEADER { // bmfh

        WORD    bfType;

        DWORD   bfSize;

        WORD    bfReserved1;

        WORD    bfReserved2;

        DWORD   bfOffBits;

} BITMAPFILEHEADER;

The BITMAPFILEHEADER structure contains information about the type, size, and layout of a file that contains a device-independent bitmap (DIB).

Members

bfType

Specifies the file type. It must be BM.

bfSize

Specifies the size, in bytes, of the bitmap file.

bfReserved1

Reserved; must be zero.

bfReserved2

Reserved; must be zero.

bfOffBits

Specifies the offset, in bytes, from the BITMAPFILEHEADER structure to the bitmap bits.

Remarks

A BITMAPINFO or BITMAPCOREINFO structure immediately follows the BITMAPFILEHEADER structure in the DIB file.

See Also

BITMAPCOREINFO, BITMAPINFO


BITMAPINFO
BITMAPINFO  QuickInfo

typedef struct tagBITMAPINFO { // bmi

   BITMAPINFOHEADER bmiHeader;

   RGBQUAD          bmiColors[1];

} BITMAPINFO;

The BITMAPINFO structure defines the dimensions and color information for a Windows device-independent bitmap (DIB).

Members

bmiHeader

Specifies a BITMAPINFOHEADER structure that contains information about the dimensions and color format of a DIB.

bmiColors

Specifies an array of RGBQUAD or doubleword data types that define the colors in the bitmap.

Remarks

A device-independent bitmap consists of two distinct parts: a BITMAPINFO structure describing the dimensions and colors of the bitmap, and an array of bytes defining the pixels of the bitmap. The bits in the array are packed together, but each scan line must be padded with zeroes to end on a LONG data-type boundary. If the height is positive, the bitmap is a bottom-up DIB and its origin is the lower left corner. If the height is negative, the bitmap is a top-down DIB and its origin is the upper left corner.

The biBitCount member of the BITMAPINFOHEADER structure determines the number of bits that define each pixel and the maximum number of colors in the bitmap. This member can be one of the following values:

Value	Meaning
1	The bitmap is monochrome, and the bmiColors member contains two entries. Each bit in the bitmap array represents a pixel. If the bit is clear, the pixel is displayed with the color of the first entry in the bmiColors table; if the bit is set, the pixel has the color of the second entry in the table.
4	The bitmap has a maximum of 16 colors, and the bmiColors member contains up to 16 entries. Each pixel in the bitmap is represented by a 4-bit index into the color table. For example, if the first byte in the bitmap is 0x1F, the byte represents two pixels. The first pixel contains the color in the second table entry, and the second pixel contains the color in the sixteenth table entry.
8	The bitmap has a maximum of 256 colors, and the bmiColors member contains up to 256 entries. In this case, each byte in the array represents a single pixel.
16	The bitmap has a maximum of 2 (16)  colors. If the biCompression member of the BITMAPINFOHEADER is BI_RGB, the bmiColors member is NULL. Each WORD in the bitmap array represents a single pixel. The relative intensities of red, green, and blue are represented with 5 bits for each color component. The value for blue is in the least significant 5 bits, followed by 5 bits each for green and red, respectively. The most significant bit is not used. If the biCompression member of the BITMAPINFOHEADER is BI_BITFIELDS, the bmiColors member contains three DWORD color masks that specify the red, green, and blue components, respectively, of each pixel. Each WORD in the bitmap array represents a single pixel. Windows NT: When the biCompression member is BI_BITFIELDS, bits set in each DWORD mask must be contiguous and should not overlap the bits of another mask. All the bits in the pixel do not have to be used.  Windows 95: When the biCompression member is BI_BITFIELDS, Windows 95 supports only the following 16bpp color masks: A 5-5-5 16-bit image, where the blue mask is 0x001F, the green mask is 0x03E0, and the red mask is 0x7C00; and a 5-6-5 16-bit image, where the blue mask is 0x001F, the green mask is 0x07E0, and the red mask is 0xF800.
24	The bitmap has a maximum of 2 (24)  colors, and the bmiColors member is NULL. Each 3-byte triplet in the bitmap array represents the relative intensities of blue, green, and red, respectively, for a pixel.
32	The bitmap has a maximum of 2 (32)  colors. If the biCompression member of the BITMAPINFOHEADER is BI_RGB, the bmiColors member is NULL. Each DWORD in the bitmap array represents the relative intensities of blue, green, and red, respectively, for a pixel. The high byte in each DWORD is not used. If the biCompression member of the BITMAPINFOHEADER is BI_BITFIELDS, the bmiColors member contains three DWORD color masks that specify the red, green, and blue components, respectively, of each pixel. Each DWORD in the bitmap array represents a single pixel. Windows NT: When the biCompression member is BI_BITFIELDS, bits set in each DWORD mask must be contiguous and should not overlap the bits of another mask. All the bits in the pixel do not have to be used.  Windows 95: When the biCompression member is BI_BITFIELDS, Windows 95 supports only the following 32bpp color mask: The blue mask is 0x000000FF, the green mask is 0x0000FF00, and the red mask is 0x00FF0000.
The biClrUsed member of the BITMAPINFOHEADER structure specifies the number of color indices in the color table that are actually used by the bitmap. If the biClrUsed member is set to zero, the bitmap uses the maximum number of colors corresponding to the value of the biBitCount member.

The colors in the bmiColors table should appear in order of importance.

Alternatively, for functions that use DIBs, the bmiColors member can be an array of 16-bit unsigned integers that specify indices into the currently realized logical palette, instead of explicit RGB values. In this case, an application using the bitmap must call the DIB functions (CreateDIBitmap, CreateDIBPatternBrush, and CreateDIBSection) with the iUsage parameter set to DIB_PAL_COLORS.

If the bitmap is a packed bitmap (a bitmap in which the bitmap array immediately follows the BITMAPINFO header and which is referenced by a single pointer), the biClrUsed member must be set to an even number when using the DIB_PAL_COLORS mode so the DIB bitmap array starts on a doubleword boundary.

Note  The bmiColors member should not contain palette indices if the bitmap is to be stored in a file or transferred to another application. Unless the application has exclusive use and control of the bitmap, the bitmap color table should contain explicit RGB values.

See Also

BITMAPINFOHEADER, CreateDIBitmap, CreateDIBPatternBrush, CreateDIBSection, RGBQUAD


BITMAPINFOHEADER
BITMAPINFOHEADER  QuickInfo

typedef struct tagBITMAPINFOHEADER{ // bmih

   DWORD  biSize;

   LONG   biWidth;

   LONG   biHeight;

   WORD   biPlanes;

   WORD   biBitCount

   DWORD  biCompression;

   DWORD  biSizeImage;

   LONG   biXPelsPerMeter;

   LONG   biYPelsPerMeter;

   DWORD  biClrUsed;

   DWORD  biClrImportant;

} BITMAPINFOHEADER;

The BITMAPINFOHEADER structure contains information about the dimensions and color format of a device-independent bitmap (DIB).

Members

biSize

Specifies the number of bytes required by the structure.

biWidth

Specifies the width of the bitmap, in pixels.

biHeight

Specifies the height of the bitmap, in pixels. If biHeight is positive, the bitmap is a bottom-up DIB and its origin is the lower left corner. If biHeight is negative, the bitmap is a top-down DIB and its origin is the upper left corner.

biPlanes

Specifies the number of planes for the target device. This value must be set to 1.

biBitCount

Specifies the number of bits per pixel. This value must be 1, 4, 8, 16, 24, or 32.

biCompression

Specifies the type of compression for a compressed bottom-up bitmap (top-down DIBs cannot be compressed). It can be one of the following values:

Value	Description
BI_RGB	An uncompressed format.
BI_RLE8	A run-length encoded (RLE) format for bitmaps with 8 bits per pixel. The compression format is a two-byte format consisting of a count byte followed by a byte containing a color index. For more information, see the following Remarks section.
BI_RLE4	An RLE format for bitmaps with 4 bits per pixel. The compression format is a two-byte format consisting of a count byte followed by two word-length color indices. For more information, see the following Remarks section.
BI_BITFIELDS	Specifies that the bitmap is not compressed and that the color table consists of three doubleword color masks that specify the red, green, and blue components, respectively, of each pixel. This is valid when used with 16- and 32-bits-per-pixel bitmaps.
biSizeImage

Specifies the size, in bytes, of the image. This may be set to 0 for BI_RGB bitmaps.

biXPelsPerMeter

Specifies the horizontal resolution, in pixels per meter, of the target device for the bitmap. An application can use this value to select a bitmap from a resource group that best matches the characteristics of the current device.

biYPelsPerMeter

Specifies the vertical resolution, in pixels per meter, of the target device for the bitmap.

biClrUsed

Specifies the number of color indices in the color table that are actually used by the bitmap. If this value is zero, the bitmap uses the maximum number of colors corresponding to the value of the biBitCount member for the compression mode specified by biCompression.

If biClrUsed is nonzero and the biBitCount member is less than 16, the biClrUsed member specifies the actual number of colors the graphics engine or device driver accesses. If biBitCount is 16 or greater, then biClrUsed member specifies the size of the color table used to optimize performance of Windows color palettes. If biBitCount equals 16 or 32, the optimal color palette starts immediately following the three doubleword masks.

If the bitmap is a packed bitmap (a bitmap in which the bitmap array immediately follows the BITMAPINFO header and which is referenced by a single pointer), the biClrUsed member must be either 0 or the actual size of the color table.

biClrImportant

Specifies the number of color indices that are considered important for displaying the bitmap. If this value is zero, all colors are important.

Remarks

The BITMAPINFO structure combines the BITMAPINFOHEADER structure and a color table to provide a complete definition of the dimensions and colors of a DIB. For more information about DIBs, see the description of the BITMAPINFO data structure.

An application should use the information stored in the biSize member to locate the color table in a BITMAPINFO structure, as follows:

pColor = ((LPSTR)pBitmapInfo +

    (WORD)(pBitmapInfo->bmiHeader.biSize));

Windows supports formats for compressing bitmaps that define their colors with eight or four bits per pixel. Compression reduces the disk and memory storage required for the bitmap. The following paragraphs describe these formats.

When the biCompression member is BI_RLE8, the bitmap is compressed by using a run-length encoding (RLE) format for an 8-bit bitmap. This format can be compressed in encoded or absolute modes. Both modes can occur anywhere in the same bitmap.

•	Encoded mode consists of two bytes: the first byte specifies the number of consecutive pixels to be drawn using the color index contained in the second byte. In addition, the first byte of the pair can be set to zero to indicate an escape that denotes an end of line, end of bitmap, or delta. The interpretation of the escape depends on the value of the second byte of the pair, which can be one of the following:

Value	Meaning
0	End of line.
1	End of bitmap.
2	Delta. The two bytes following the escape contain unsigned values indicating the horizontal and vertical offsets of the next pixel from the current position.
•	In absolute mode, the first byte is zero and the second byte is a value in the range 03H through FFH. The second byte represents the number of bytes that follow, each of which contains the color index of a single pixel. When the second byte is 2 or less, the escape has the same meaning as in encoded mode. In absolute mode, each run must be aligned on a word boundary.

The following example shows the hexadecimal values of an 8-bit compressed bitmap.

03 04 05 06 00 03 45 56 67 00 02 78 00 02 05 01

02 78 00 00 09 1E 00 01

This bitmap would expand as follows (two-digit values represent a color index for a single pixel):

04 04 04

06 06 06 06 06

45 56 67

78 78

move current position 5 right and 1 down

78 78

end of line

1E 1E 1E 1E 1E 1E 1E 1E 1E

end of RLE bitmap

When the biCompression member is BI_RLE4, the bitmap is compressed by using a run-length encoding format for a 4-bit bitmap, which also uses encoded and absolute modes:

•	In encoded mode, the first byte of the pair contains the number of pixels to be drawn using the color indices in the second byte. The second byte contains two color indices, one in its high-order four bits and one in its low-order four bits. The first of the pixels is drawn using the color specified by the high-order four bits, the second is drawn using the color in the low-order four bits, the third is drawn using the color in the high-order four bits, and so on, until all the pixels specified by the first byte have been drawn.

•	In absolute mode, the first byte is zero, the second byte contains the number of color indices that follow, and subsequent bytes contain color indices in their high- and low-order four bits, one color index for each pixel. In absolute mode, each run must be aligned on a word boundary. The end-of-line, end-of-bitmap, and delta escapes described for BI_RLE8 also apply to BI_RLE4 compression.

The following example shows the hexadecimal values of a 4-bit compressed bitmap.

03 04 05 06 00 06 45 56 67 00 04 78 00 02 05 01

04 78 00 00 09 1E 00 01

This bitmap would expand as follows (single-digit values represent a color index for a single pixel):

0 4 0

0 6 0 6 0

4 5 5 6 6 7

7 8 7 8

move current position 5 right and 1 down

7 8 7 8

end of line

1 E 1 E 1 E 1 E 1

end of RLE bitmap

If biHeight is negative, indicating a top-down DIB, biCompression must be either BI_RGB or BI_BITFIELDS. Top-down DIBs cannot be compressed.

See Also

BITMAPINFO


BITMAPV4HEADER [New - Windows 95]
BITMAPV4HEADER  QuickInfo  Overview  Group

[New - Windows 95]

typedef struct {
    DWORD        bV4Size;
    LONG         bV4Width;
    LONG         bV4Height;
    WORD         bV4Planes;
    WORD         bV4BitCount;
    DWORD        bV4V4Compression;
    DWORD        bV4SizeImage;
    LONG         bV4XPelsPerMeter;
    LONG         bV4YPelsPerMeter;
    DWORD        bV4ClrUsed;
    DWORD        bV4ClrImportant;
    DWORD        bV4RedMask;
    DWORD        bV4GreenMask;
    DWORD        bV4BlueMask;
    DWORD        bV4AlphaMask;
    DWORD        bV4CSType;
    CIEXYZTRIPLE bV4Endpoints;
    DWORD        bV4GammaRed;
    DWORD        bV4GammaGreen;
    DWORD        bV4GammaBlue;
} BITMAPV4HEADER, FAR *LPBITMAPV4HEADER, *PBITMAPV4HEADER;

The BITMAPV4HEADER structure contains information about a Win32 version 4.0 bitmap.


BLOB
BLOB  QuickInfo  Overview  Group

typedef struct _BLOB {

    ULONG   cbSize;

    BYTE    *pBlobData;

} BLOB;

A BLOB structure contains information about a block of data.

Members

cbSize

Specifies the size in bytes of the block of data pointed to by pBlobData

Addresses

Points to a block of data.

Remarks

The structure name BLOB comes from the acronym BLOB, which stands for "Binary Large OBject".

Note that this structure description says nothing about the nature of the data pointed to by pBlobData.

See Also

SERVICE_INFO


BROWSEINFO
BROWSEINFO  QuickInfo

typedef struct _browseinfo {

    HWND hwndOwner;          // see below

    LPCITEMIDLIST pidlRoot;  // see below

    LPSTR pszDisplayName;    // see below

    LPCSTR lpszTitle;        // see below

    UINT ulFlags;            // see below

    BFFCALLBACK lpfn;        // see below

    LPARAM lParam;           // see below

    int iImage;              // see below

} BROWSEINFO, *PBROWSEINFO, *LPBROWSEINFO;

Contains parameters for the the SHBrowseForFolder function and receives information about the folder selected by the user.

Members

hwndOwner

Handle of the owner window for the dialog box.

pidlRoot

Pointer to an item identifier list (an ITEMIDLIST structure) specifying the location of the "root" folder to browse from. Only the specified folder and its subfolders appear in the dialog box. This member can be NULL, and in that case, the name space root (the desktop folder) is used.

pszDisplayName

Pointer to a buffer that receives the display name of the folder selected by the user. The size of this buffer is assumed to be MAX_PATH bytes.

lpszTitle

Pointer to a null-terminated string that is displayed above the tree view control in the dialog box. This string can be used to specify instructions to the user.

ulFlags

Value specifying the types of folders to be listed in the dialog box as well as other options. This member can include zero or more of the following values:

BIF_BROWSEFORCOMPUTER	Only returns computers. If the user selects anything other than a computer, the OK button is grayed.
BIF_BROWSEFORPRINTER	Only returns printers. If the user selects anything other than a printer, the OK button is grayed.
BIF_DONTGOBELOWDOMAIN	Does not include network folders below the domain level in the tree view control.
BIF_RETURNFSANCESTORS	Only returns file system ancestors. If the user selects anything other than a file system ancestor, the OK button is grayed.
BIF_RETURNONLYFSDIRS	Only returns file system directories. If the user selects folders that are not part of the file system, the OK button is grayed.
BIF_STATUSTEXT	Includes a status area in the dialog box. The callback function can set the status text by sending messages to the dialog box.
lpfn

Address an application-defined function that the dialog box calls when events occur. For more information, see the description of the BrowseCallbackProc function. This member can be NULL.

lParam

Application-defined value that the dialog box passes to the callback function (if one is specified).

iImage

Variable that receives the image associated with the selected folder. The image is specified as an index to the system image list.

See Also

BrowseCallbackProc, ITEMIDLIST, SHBrowseForFolder


BY_HANDLE_FILE_INFORMATION
BY_HANDLE_FILE_INFORMATION  QuickInfo

typedef struct _BY_HANDLE_FILE_INFORMATION { // bhfi

    DWORD    dwFileAttributes;

    FILETIME ftCreationTime;

    FILETIME ftLastAccessTime;

    FILETIME ftLastWriteTime;

    DWORD    dwVolumeSerialNumber;

    DWORD    nFileSizeHigh;

    DWORD    nFileSizeLow;

    DWORD    nNumberOfLinks;

    DWORD    nFileIndexHigh;

    DWORD    nFileIndexLow;

} BY_HANDLE_FILE_INFORMATION;

The BY_HANDLE_FILE_INFORMATION structure contains information retrieved by the GetFileInformationByHandle function.

Members

dwFileAttributes

Specifies file attributes. This member can be one or more of the following values:

Value	Meaning
FILE_ATTRIBUTE_ARCHIVE
	The file is an archive file. Applications use this value to mark files for backup or removal.
FILE_ATTRIBUTE_COMPRESSED
	The file or directory is compressed. For a file, this means that all of the data in the file is compressed. For a directory, this means that compression is the default for newly created files and subdirectories.
FILE_ATTRIBUTE_DIRECTORY
	The file is a directory.
FILE_ATTRIBUTE_HIDDEN
	The file is hidden. It is not included in an ordinary directory listing.
FILE_ATTRIBUTE_NORMAL
	The file has no other attributes. This value is valid only if used alone.
FILE_ATTRIBUTE_READONLY
	The file is read-only. Applications can read the file but cannot write to it or delete it.
FILE_ATTRIBUTE_SYSTEM
	The file is part of the operating system or is used exclusively by it.
FILE_ATTRIBUTE_TEMPORARY
	The file is being used for temporary storage. Applications should write to the file only if absolutely necessary. Most of the file's data remains in memory without being flushed to the media because the file will soon be deleted.
ftCreationTime

Specifies the time the file was created. If the underlying file system does not support this time member, ftCreationTime is zero.

ftLastAccessTime

Specifies the time the file was last accessed. If the underlying file system does not support this time member, ftLastAccessTime is zero.

ftLastWriteTime

Specifies the last time the file was written to.

dwVolumeSerialNumber

Specifies the serial number of the volume that contains the file.

nFileSizeHigh

Specifies the high-order word of the file size.

nFileSizeLow

Specifies the low-order word of the file size.

nNumberOfLinks

Specifies the number of links to this file. For the FAT file system and HPFS, this member is always 1. For NTFS, it may be more than 1.

nFileIndexHigh

Specifies the high-order word of a unique identifier associated with the file.

nFileIndexLow

Specifies the low-order word of a unique identifier associated with the file. This identifier and the volume serial number uniquely identify a file. This number may change when the system is restarted or when the file is opened. After a process opens a file, the identifier is constant until the file is closed. An application can use this identifier and the volume serial number to determine whether two handles refer to the same file.

See Also

GetFileInformationByHandle


CANDIDATEFORM [New - Windows 95]
CANDIDATEFORM  QuickInfo  Overview  Group

[New - Windows 95]

typedef _tagCANDIDATEFORM {
    DWORD  dwIndex;
    DWORD  dwStyle;
    POINT  ptCurrentPos;
    RECT   rcArea;
} CANDIDATEFORM;

The CANDIDATEFORM structure contains position information for the candidate window.

Members

dwIndex

Candidate list identifier. Can be 0 for the first list, 1 for the second, and so on. The maximum index is 31.

dwStyle

Position style. This member can be one of the following values:

CFS_CANDIDATEPOS	Display the upper-left corner of the candidate list window at the position given by ptCurrentPos. The coordinates are relative to the upper-left corner of the window containing the list window, and are subject to adjustment by the system.
CFS_EXCLUDE	Exclude the candidate window from the area given by rcArea. The ptCurrentPos member specifies the coordinates of the current point of interest, typically the caret position.
ptCurrentPos

Coordinates of the upper-left corner of the candidate window or the caret position, depending on the value of dwStyle.

rcArea

Coordinates of the upper-left and lower-right corners of the exclusion area.


CANDIDATELIST [New - Windows 95]
CANDIDATELIST  QuickInfo  Overview  Group

[New - Windows 95]

typedef struct _tagCANDIDATELIST {
    DWORD  dwSize;
    DWORD  dwStyle;
    DWORD  dwCount;
    DWORD  dwSelection;
    DWORD  dwPageStart;
    DWORD  dwPageSize;
    DWORD  dwOffset[];
} CANDIDATELIST;

The CANDIDATELIST structure contains information about a candidate list.

Members

dwSize

Size, in bytes, of the structure, the offset array, and all candidate strings.

dwStyle

Candidate style values. This member can be one or more of the following values:

Value	Meaning
IME_CAND_UNKNOWN	Candidates are in a style other than listed here.
IME_CAND_READ	Candidates are in same reading.
IME_CAND_CODE	Candidates are in a code range.
IME_CAND_MEANING	Candidates are in same meaning.
IME_CAND_RADICAL	Candidates use same radical character.
IME_CAND_STROKES	Candidates are in same number of strokes.
For the IME_CAND_CODE style, the candidate list has a special structure depending on the value of the dwCount member. If dwCount is 1, the dwOffset member contains a single DBCS character rather than an offset, and no candidate string is provided. If the dwCount member is greater than 1, the dwOffset member contains valid offsets, and the candidate strings are text representations of individual DBCS character values in hexadecimal notation.

dwCount

Number of candidate strings.

dwSelection

Index of the selected candidate string.

dwPageStart

Index of the first candidate string in the candidate window. This varies as the user presses the PAGE UP and PAGE DOWN keys.

dwPageSize

Number of candidate strings to be shown in one page in the candidate window. The user can move to the next page by pressing IME-defined keys, such as the PAGE UP or PAGE DOWN key. If this number is zero, an application can define a proper value by itself.

dwOffset

Offset to the start of the first candidate string, relative to the start of this structure. The offsets for subsequent strings immediately follow this member, forming an array of 32-bit offsets.

Remarks

The candidate strings immediately follow the last offset in the dwOffset array.


CBT_CREATEWND
CBT_CREATEWND  QuickInfo

typedef struct tagCBT_CREATEWND { // cbtcw

    LPCREATESTRUCT lpcs;

    HWND           hwndInsertAfter;

} CBT_CREATEWND;

The CBT_CREATEWND structure contains information passed to a WH_CBT hook procedure before a window is created.

Members

lpcs

Points to a CREATESTRUCT structure that contains initialization parameters for the window about to be created.

hwndInsertAfter

Identifies the window whose position in the Z order precedes that of the window being created.

See Also

CBTProc, CREATESTRUCT, SetWindowsHookEx


CBTACTIVATESTRUCT
CBTACTIVATESTRUCT  QuickInfo

typedef struct tagCBTACTIVATESTRUCT { // cas

    BOOL fMouse;

    HWND hWndActive;

} CBTACTIVATESTRUCT;

The CBTACTIVATESTRUCT structure contains information passed to a WH_CBT hook procedure before a window is activated.

Members

fMouse

Specifies whether the window is being activated as a result of a mouse click. This value is TRUE if a mouse click is causing the activation or FALSE if it is not.

hWndActive

Identifies the active window.

See Also

SetWindowsHookEx


CHAR_INFO
CHAR_INFO  QuickInfo  Overview  Group

typedef struct _CHAR_INFO { // chi

    union {                /* Unicode or ANSI character  */

        WCHAR UnicodeChar;

        CHAR AsciiChar;

    } Char;

    WORD Attributes;       // text and background colors

} CHAR_INFO, *PCHAR_INFO;

The CHAR_INFO structure specifies the Unicode or ANSI character and the foreground (text) and background color attributes of a screen buffer character cell. This structure is used by console functions to read from and write to a console screen buffer.

Members

Char

Specifies either the Unicode (wide-character) or ANSI character of a screen buffer character cell, depending on whether the Unicode or ANSI version of the function is used.

Attributes

Specifies the foreground (text) and background colors in which a screen buffer character cell is drawn. This member can be zero, or it can be any combination of the following values:

BACKGROUND_BLUE	FOREGROUND_BLUE
BACKGROUND_GREEN	FOREGROUND_GREEN
BACKGROUND_RED	FOREGROUND_RED
BACKGROUND_INTENSITY	FOREGROUND_INTENSITY
See Also

ReadConsoleOutput, ScrollConsoleScreenBuffer, WriteConsoleOutput


CHARFORMAT [New - Windows NT]
CHARFORMAT  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct _charformat {

    UINT     cbSize;

    _WPAD    _wPad1;

    DWORD    dwMask;

    DWORD    dwEffects;

    LONG     yHeight;

    LONG     yOffset;

    COLORREF crTextColor;

    BYTE     bCharSet;

    BYTE     bPitchAndFamily;

    TCHAR    szFaceName[LF_FACESIZE];

    _WPAD    _wPad2;

} CHARFORMAT;

The CHARFORMAT structure contains information about character formatting in a rich edit control.

Members

cbSize

Size in bytes of this structure. Must be set before passing the structure to the rich edit control.

dwMask

Members containing valid information or attributes to set. This member can be zero or more of the following values:

Value	Meaning
CFM_BOLD	The CFE_BOLD value of the dwEffects member is valid.
CFM_COLOR	The crTextColor member and the CFE_AUTOCOLOR value of the dwEffects member are valid.
CFM_FACE	The szFaceName member is valid.
CFM_ITALIC	The CFE_ITALIC value of the dwEffects member is valid.
CFM_OFFSET	The yOffset member is valid.
CFM_PROTECTED	The CFE_PROTECTED value of the dwEffects member is valid.
CFM_SIZE	The yHeight member is valid.
CFM_STRIKEOUT	The CFE_STRIKEOUT value of the dwEffects member is valid.
CFM_UNDERLINE.	The CFE_UNDERLINE value of the dwEffects member is valid.
dwEffects

Character effects. This member can be a combination of the following values:

Value	Meaning
CFE_AUTOCOLOR	The text color is the return value of GetSysColor (COLOR_WINDOWTEXT).
CFE_BOLD	Characters are bold.
CFE_ITALIC	Characters are italic.
CFE_STRIKEOUT	Characters are struck out.
CFE_UNDERLINE	Characters are underlined.
CFE_PROTECTED	Characters are protected; an attempt to modify them will cause an EN_PROTECTED notification message.
yHeight

Character height.

yOffset

Character offset from the baseline. If this member is positive, the character is a superscript; if it is negative, the character is a subscript.

crTextColor

Text color. This member is ignored if the CFE_AUTOCOLOR character effect is specified.

bCharSet

Character set value. Can be one of the values specified for the lfCharSet member of the LOGFONT structure.

bPitchAndFamily

Font family and pitch. This member is the same as the lfPitchAndFamily member of the LOGFONT structure.

szFaceName

Null-terminated character array specifying the font face name.

Remarks

This structure is used with the EM_GETCHARFORMAT and EM_SETCHARFORMAT messages.

See Also

GetSysColor, EM_GETCHARFORMAT, EM_SETCHARFORMAT, EN_PROTECTED, LOGFONT


CHARRANGE [New - Windows NT]
CHARRANGE  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct _charrange {

    LONG cpMin;

    LONG cpMax;

} CHARRANGE;

The CHARRANGE structure specifies a range of characters in a rich edit control. This structure is used with the EM_EXGETSEL and EM_EXSETSEL messages.

If the cpMin and cpMax members are equal, the range is empty. The range includes everything if cpMin is 0 and cpMax is  − 1.

Members

cpMin

Index of first intercharacter position.

cpMax

Index of last intercharacter position.

EM_EXGETSEL, EM_EXSETSEL


CHARSET
CHARSET  QuickInfo

typedef struct tagCHARSET { // chst

    DWORD aflBlock[3];

    DWORD flLang;

} CHARSET;

The CHARSET structure specifies the Unicode blocks and the character sets supported by a given font.

Members

aflBlock

Specifies which (if any) of the 96 Unicode blocks are supported by a font. If the font contains at least one character in the given block, the corresponding bit is set.

flLang

Identifies the character set supported by the font. This member can be one of the following values:

Value	Meaning
CS_UGL	Supports the Universal Glyph List (UGL) character set.
CS_LATIN	Supports the Latin character set.
CS_GREEK	Supports the Greek character set.
CS_WIN30	Supports the Windows 3.0 character set.
Bits 0 and 31 of flLang are reserved and must be set to zero.


CHARSETINFO [New - Windows 95]
CHARSETINFO  QuickInfo  Overview  Group

[New - Windows 95]

typedef struct {
    UINT ciCharset;
    UINT ciACP;
    FONTSIGNATURE fs;
} CHARSETINFO;

The CHARSETINFO structure contains information about a character set.

Members

ciCharset

Character set value.

ciACP

ANSI code-page value.

fs

A FONTSIGNATURE structure that identifies the Unicode and code-page font signature values. Only one Windows code-page will be set when this structure is set by the function.

See Also

FONTSIGNATURE, TranslateCharsetInfo


CHOOSECOLOR
CHOOSECOLOR  QuickInfo

typedef struct {   // cc

    DWORD        lStructSize;

    HWND         hwndOwner;

    HWND         hInstance;

    COLORREF     rgbResult;

    COLORREF*    lpCustColors;

    DWORD        Flags;

    LPARAM       lCustData;

    LPCCHOOKPROC lpfnHook;

    LPCTSTR      lpTemplateName;

} CHOOSECOLOR;

The CHOOSECOLOR structure contains information the operating system uses to initialize the system-defined Color dialog box. After the user closes the dialog box, the system returns information about the user's selection in this structure.

Members

lStructSize

Specifies the length, in bytes, of the structure.

hwndOwner

Identifies the window that owns the dialog box. This member can be any valid window handle, or it can be NULL if the dialog box has no owner.

hInstance

Identifies a data block that contains the dialog box template specified by the lpTemplateName member. This member is used only if the Flags member specifies the CC_ENABLETEMPLATE flag; otherwise, this member is ignored.

rgbResult

Specifies the color initially selected when the dialog box is created, and contains the user's color selection when the dialog box is closed. When the dialog box is created, the system selects the nearest solid color available if the CC_RGBINIT flag is specified in the Flags member and the value of this member is not among the colors available. If this member is NULL, the color initially selected is black.

lpCustColors

Points to an array of 16 doublewords that contain red, green, blue (RGB) values for the custom color boxes in the dialog box. If the user modifies these colors, the system updates the array with the new RGB values. An application should save these values for future calls to the ChooseColor function.

Flags

Specifies the dialog box initialization flags. This member may be a combination of the following flags:

Flag	Meaning
CC_ENABLEHOOK	Enables the hook function specified in the lpfnHook member.
CC_ENABLETEMPLATE	Causes the system to create the dialog box by using the dialog box template identified by the hInstance and lpTemplateName members.
CC_ENABLETEMPLATEHANDLE	Indicates that the hInstance member identifies a data block containing a pre-loaded dialog box template. The system ignores the lpTemplateName member if this flag is specified.
CC_FULLOPEN	Causes the entire dialog box to appear when the dialog box is created, including the portion that allows the user to create custom colors. If this flag is not specified, the user must choose the Define Custom Color button to see this portion of the dialog box.
CC_PREVENTFULLOPEN	Disables the Define Custom Colors button, preventing the user from creating custom colors.
CC_RGBINIT	Causes the dialog box to use the color specified in the rgbResult member as the initial color selection.
CC_SHOWHELP	Causes the dialog box to show the Help button. The hwndOwner member must not be NULL if this option is specified.
lCustData

Specifies application-defined data the system passes to the hook function identified by the lpfnHook member. The system passes the data in the lParam parameter of the WM_INITDIALOG message.

lpfnHook

Points to a hook function that processes messages intended for the dialog box. An application must specify the CC_ENABLEHOOK flag in the Flags member to enable the function; otherwise, the system ignores this member. The hook function must return FALSE to pass a message to the standard color dialog box procedure or TRUE to discard the message.

lpstrTemplateName

Points to a null-terminated string that names the dialog box template to be substituted for the standard dialog box template. An application can use the MAKEINTRESOURCE macro for numbered dialog box resources. This member is used only if Flags specifies the CC_ENABLETEMPLATE flag; otherwise, this member is ignored.

See Also

ChooseColor, MAKEINTRESOURCE, WM_INITDIALOG


CHOOSEFONT
CHOOSEFONT  QuickInfo

typedef struct {    // cf

    DWORD        lStructSize;

    HWND         hwndOwner;

    HDC          hDC;

    LPLOGFONT    lpLogFont;

    INT          iPointSize;

    DWORD        Flags;

    DWORD        rgbColors;

    LPARAM       lCustData;

    LPCFHOOKPROC lpfnHook;

    LPCTSTR      lpTemplateName;

    HINSTANCE    hInstance;

    LPTSTR       lpszStyle;

    WORD         nFontType;

    WORD         ___MISSING_ALIGNMENT__;

    INT          nSizeMin;

    INT          nSizeMax;

} CHOOSEFONT;

The CHOOSEFONT structure contains information the operating system uses to initialize the system-defined Font dialog box. After the user closes the dialog box, the system returns information about the user's selection in this structure.

Members

lStructSize

Specifies the length, in bytes, of the structure.

hwndOwner

Identifies the window that owns the dialog box. This member can be any valid window handle, or it can be NULL if the dialog box has no owner.

hDC

Identifies the device context (or information context) of the printer whose fonts will be listed in the dialog box. This member is used only if the Flags member specifies the CF_PRINTERFONTS flag; otherwise, this member is ignored.

lpLogFont

Points to a LOGFONT structure. If an application initializes the members of this structure before calling the ChooseFont function and also sets the CF_INITTOLOGFONTSTRUCT flag, ChooseFont initializes the dialog box with a font that is the closest possible match. After the user closes the dialog box, ChooseFont sets the members of the LOGFONT structure based on the user's final selection.

iPointSize

Specifies the size of the selected font, in units of 1/10 of a point. ChooseFont sets this value after the user closes the dialog box.

Flags

Specifies the dialog box initialization flags. This member may be a combination of the following flags:

Flag	Meaning
CF_APPLY	Specifies that ChooseFont should enable the Apply button.
CF_ANSIONLY	Windows 95: This flag is obsolete. To limit font selections to all scripts except those that use the OEM or Symbol character sets, use CF_SCRIPTSONLY. To get the Windows 3.1 CF_ANSIONLY behavior, use CF_SELECTSCRIPT and specify ANSI_CHARSET in the lfCharSet member of the LOGFONT structure pointed to by lpLogFont. Windows NT: Specifies that ChooseFont should allow the selection of all fonts that use the Windows and Unicode character sets. The user will not be able to select fonts that use the OEM or Symbol character sets. This flag is equivalent to the Windows 95 CF_SCRIPTSONLY flag.
CF_BOTH	Causes the dialog box to list the available printer and screen fonts. The hDC member identifies the device context (or information context) associated with the printer.
CF_TTONLY	Specifies that ChooseFont should only enumerate and allow the selection of TrueType fonts.
CF_EFFECTS	Specifies that ChooseFont should enable strikeout, underline, and color effects. If this flag is specified, you can set the rgbColors member of this structure and the lfStrikeOut and lfUnderline members of the LOGFONT structure pointed to by lpLogFont. ChooseFont can then use these members after the user closes the dialog box.
CF_ENABLEHOOK	Enables the hook function specified in the lpfnHook member of this structure.
CF_ENABLETEMPLATE	Indicates that the hInstance member identifies a data block that contains a dialog box template identified by the lpTemplateName member.
CF_ENABLETEMPLATEHANDLE	Indicates that the hInstance member identifies a data block that contains a preloaded dialog box template. The system ignores the lpTemplateName member if this flag is specified.
CF_FIXEDPITCHONLY	Specifies that ChooseFont should select only fixed-pitch fonts.
CF_FORCEFONTEXIST	Specifies that ChooseFont should indicate an error condition if the user attempts to select a font or style that does not exist.
CF_INITTOLOGFONTSTRUCT	Specifies that ChooseFont should use the LOGFONT structure pointed to by the lpLogFont member to initialize the dialog box controls.
CF_LIMITSIZE	Specifies that ChooseFont should select only font sizes within the range specified by the nSizeMin and nSizeMax members.
CF_NOOEMFONTS	See the CF_NOVECTORFONTS description.
CF_NOFACESEL	Specifies that ChooseFont should not make an initial face name selection, because there is no one single face name that applies to the text selection. Set this flag if the text selection contains multiple face names.
CF_NOSCRIPTSEL	Windows 95 only: Specifies that there is no selection in the character set combo box. Applications use this flag to support multiple character set selections. This flag is set on input only. When it is set, the script combo box is disabled and the lfCharSet member of the LOGFONT structure is set to DEFAULT_CHARSET.
CF_NOSTYLESEL	Specifies that ChooseFont should not make an initial style selection, because there is no one single style that applies to the text selection. Set this flag if the text selection contains multiple styles.
CF_NOSIZESEL	Specifies that ChooseFont should not make an initial size selection, because there is no one single size that applies to the text selection. Set this flag if the text selection contains multiple sizes.
CF_NOSIMULATIONS	Specifies that ChooseFont should not allow graphics device interface (GDI) font simulations.
CF_NOVECTORFONTS	Specifies that ChooseFont should not allow vector font selections.
CF_NOVERTFONTS	Windows 95: Causes the Font dialog box to list only horizontally oriented fonts.
CF_PRINTERFONTS	Causes the dialog box to list only the fonts supported by the printer associated with the device context (or information context) identified by the hDC member.
CF_SCALABLEONLY	Specifies that ChooseFont should allow only the selection of scalable fonts. (Scalable fonts include vector fonts, scalable printer fonts, TrueType fonts, and fonts scaled by other technologies.)
CF_SCREENFONTS	Causes the dialog box to list only the screen fonts supported by the system.
CF_SCRIPTSONLY	Windows 95 only: Specifies that ChooseFont should allow selection of fonts for all non-OEM and Symbol character sets, as well as the ANSI character set. This supersedes the CF_ANSIONLY value.
CF_SELECTSCRIPT	Windows 95 only: When specified on input, only fonts with the character set identified in the lfCharSet member of the LOGFONT structure are displayed. The user will not be allowed to change the character set combo box.
CF_SHOWHELP	Causes the dialog box to show the Help button. The hwndOwner member must not be NULL if this option is specified.
CF_USESTYLE	Specifies that lpszStyle member points to a buffer that contains style data that ChooseFont should use to initialize the Font Style selection. When the user closes the dialog box, ChooseFont copies style data for the user's selection to this buffer.
CF_WYSIWYG	Specifies that ChooseFont should allow only the selection of fonts available on both the printer and the display. If this flag is specified, the CF_BOTH and CF_SCALABLEONLY flags should also be specified.
rgbColors

If the CF_EFFECTS flag is specified, this member contains an RGB value that ChooseFont should use to specify the text color. After the user closes the dialog box, this member contains the RGB value of the color the user selected.

lCustData

Specifies application-defined data the application passes to the hook function.

lpfnHook

Points to a hook function that processes messages intended for the dialog box. An application must specify the CF_ENABLEHOOK flag in the Flags member to enable the function; otherwise, the system ignores this member. The hook function must return FALSE to pass a message to the standard dialog box procedure or TRUE to discard the message.

lpTemplateName

Points to a null-terminated string that names the dialog box template to be substituted for the standard dialog box template. An application can use the MAKEINTRESOURCE macro for numbered dialog box resources. This member is used only if Flags specifies the CF_ENABLETEMPLATE flag; otherwise, this member is ignored.

hInstance

Identifies a data block that contains the dialog box template specified by lpstrTemplateName. This member is used only if Flags specifies the CF_ENABLETEMPLATE flag; otherwise, this member is ignored.

lpszStyle

Points to a buffer that contains style data. If the CF_USESTYLE flag is specified, ChooseFont uses the data in this buffer to initialize the style control. When the user closes the dialog box, ChooseFont copies the string in the style control into this buffer.

nFontType

Specifies the type of the selected font. This member may contain one of the following values:

Value	Meaning
BOLD_FONTTYPE	The font weight is bold. This information is duplicated from the lfWeight member of the LOGFONT structure and is equivalent to FW_BOLD.
ITALIC_FONTTYPE	The italic font attribute is set. This information is duplicated from the lfItalic member of the LOGFONT structure.
PRINTER_FONTTYPE	The font is a printer font.
REGULAR_FONTTYPE	The font weight is normal. This information is duplicated from the lfWeight member of the LOGFONT structure and is equivalent to FW_REGULAR.
SCREEN_FONTTYPE	The font is a screen font.
SIMULATED_FONTTYPE	The font is simulated by the graphics device interface (GDI).
nSizeMin

Specifies the minimum point size a user can select. ChooseFont recognizes this member only if the CF_LIMITSIZE flag is specified.

nSizeMax

Specifies the maximum point size a user can select. ChooseFont recognizes this member only if the CF_LIMITSIZE flag is specified.

See Also

ChooseFont, MAKEINTRESOURCE


CIDA
CIDA  QuickInfo

typedef struct _IDA {

    UINT cidl;        // number array elements

    UINT aoffset[1];  // see below

} CIDA, * LPIDA;

This structure corresponds to the CF_IDLIST clipboard format.

Member

aoffset

Array of offsets relative to the beginning of the CIDA structure. The first element is the offset of the ITEMIDLIST structure for a folder (absolute from the root). Subsequent elements are offsets of ITEMIDLIST structures for file objects (relative from the parent folder).

See Also

ITEMIDLIST


CIEXYZ [New - Windows 95]
CIEXYZ  QuickInfo  Overview  Group

[New - Windows 95]

typedef struct tagCIEXYZ
{
    FXPT2DOT30 ciexyzX;

    FXPT2DOT30 ciexyzY;

    FXPT2DOT30 ciexyzZ;

} CIEXYZ;
typedef CIEXYZ FAR* LPCIEXYZ;

The CIEXYZ structure contains the x, y, and z coordinates of a specific color in a specified color space.

Members

ciexyzX

x coordinate in fix point (2.30).

ciexyzY

y coordinate in fix point (2.30).

ciexyzZ

z coordinate in fix point (2.30).


CIEXYZTRIPLE [New - Windows 95]
CIEXYZTRIPLE  QuickInfo  Overview  Group

[New - Windows 95]

typedef struct tagCIEXYZTRIPLE
{
    CIEXYZ  ciexyzRed;

    CIEXYZ  ciexyzGreen;

    CIEXYZ  ciexyzBlue;

} CIEXYZTRIPLE;
typedef CIEXYZTRIPLE FAR* LPCIEXYZTRIPLE;

The CIEXYZTRIPLE structure contains the x, y, and z coordinates of the three colors that correspond to the red, green, and blue endpoints for a specified logical color space.

Members

ciexyzRed;

xyz coordinates of red endpoint.

ciexyzGreen

xyz coordinates of green endpoint.

ciexyzBlue

xyz coordinates of blue endpoint.


CLIENTCREATESTRUCT
CLIENTCREATESTRUCT  QuickInfo

typedef struct tagCLIENTCREATESTRUCT { // ccs

    HANDLE hWindowMenu;

    UINT   idFirstChild;

} CLIENTCREATESTRUCT;

The CLIENTCREATESTRUCT structure contains information about the menu and first multiple document interface (MDI) child window of an MDI client window. An application passes a pointer to this structure as the lpvParam parameter of the CreateWindow function when creating an MDI client window.

Members

hWindowMenu

Identifies the handle of the MDI application's Window menu. An MDI application can retrieve this handle from the menu of the MDI frame window by using the GetSubMenu function.

idFirstChild

Specifies the child window identifier of the first MDI child window created. Windows increments the identifier for each additional MDI child window the application creates, and reassigns identifiers when the application destroys a window to keep the range of identifiers contiguous. These identifiers are used in WM_COMMAND messages sent to the application's MDI frame window when a child window is chosen from the Window menu; they should not conflict with any other command identifiers.

See Also

CreateWindow, GetSubMenu, MDICREATESTRUCT, WM_COMMAND


CMINVOKECOMMANDINFO
CMINVOKECOMMANDINFO  QuickInfo

typedef struct _CMInvokeCommandInfo {

    DWORD cbSize;        // sizeof(CMINVOKECOMMANDINFO)

    DWORD fMask;

    HWND hwnd;

    LPCSTR lpVerb;

    LPCSTR lpParameters;

    LPCSTR lpDirectory;

    int nShow;

    DWORD dwHotKey;

    HANDLE hIcon;

} CMINVOKECOMMANDINFO, *LPCMINVOKECOMMANDINFO;

Contains information about a context menu command.

Members

fMask

Value specifying zero or more of the following flags:

CMIC_MASK_HOTKEY	Specifies that the dwHotKey member is valid.
CMIC_MASK_ICON	Specifies that the hIcon member is valid.
CMIC_MASK_FLAG_NO_UI	Prevents the system from displaying user interface elements (for example, error messages) while carrying out a command.
hwnd

Handle of the window that owned the context menu, such as the desktop, the explorer, or the tray. An extension might specify this handle as the owner window of any message boxes or dialog boxes it displays.

lpVerb

32-bit value containing zero in the high-order word and the menu-identifier offset of the command to carry out in the low-order word. The shell specifies this value (using the MAKEINTRESOURCE macro) when the user chooses a menu command.

If the high-order word is not zero, this member is the address of a null-terminated string specifying the language-independent name of the command to carry out. This member is typically a string when a command is being activated by an application. The system provides predefined constant values for the following command strings:

Value	String
CMDSTR_NEWFOLDER	"NewFolder"
CMDSTR_VIEWDETAIL	"ViewDetails"
CMDSTR_VIEWLIST	"ViewList"
lpParameters

Optional parameters. This member is always NULL for menu items inserted by a shell extension.

lpDirectory

Optional working directory name. This member is always NULL for menu items inserted by a shell extension.

nShow

Flag to pass to the ShowWindow function if the command displays a window or starts an application.

dwHotKey

Optional hot key to assign any application activated by the command. If fMask does not specify CMIC_MASK_HOTKEY, this member is ignored.

hIcon

Icon to use for any application activated by the command. If the fMask member does not specify CMIC_MASK_ICON, this member is ignored.

Remarks

The address of this structure is passed to the IContextMenu::InvokeCommand method.

See Also

IContextMenu::InvokeCommand, MAKEINTRESOURCE, ShowWindow


COLORADJUSTMENT
COLORADJUSTMENT  QuickInfo

typedef struct  tagCOLORADJUSTMENT {    // ca

    WORD  caSize;

    WORD  caFlags;

    WORD  caIlluminantIndex;

    WORD  caRedGamma;

    WORD  caGreenGamma;

    WORD  caBlueGamma;

    WORD  caReferenceBlack;

    WORD  caReferenceWhite;

    SHORT caContrast;

    SHORT caBrightness;

    SHORT caColorfulness;

    SHORT caRedGreenTint;

} COLORADJUSTMENT;

The COLORADJUSTMENT structure defines the color adjustment values used by the StretchBlt and StretchDIBits functions when the stretch mode is HALFTONE.

Members

caSize

Specifies the size, in bytes, of the structure.

caFlags

Specifies how the output image should be prepared. This member may be set to NULL or any combination of the following values:

Value	Meaning
CA_NEGATIVE	Specifies that the negative of the original image should be displayed.
CA_LOG_FILTER	Specifies that a logarithmic function should be applied to the final density of the output colors. This will increase the color contrast when the luminance is low.
caIlluminantIndex

Specifies the type of standard light source under which the image is viewed. This member may be set to one of the following values:

Value	Meaning
ILLUMINANT_DEVICE_DEFAULT	Device's default. Standard used by output devices.
ILLUMINANT_A	Tungsten lamp.
ILLUMINANT_B	Noon sunlight.
ILLUMINANT_C	NTSC daylight.
ILLUMINANT_D50	Normal print.
ILLUMINANT_D55	Bond paper print.
ILLUMINANT_D65	Standard daylight. Standard for CRTs and pictures.
ILLUMINANT_D75	Northern daylight.
ILLUMINANT_F2	Cool white lamp
ILLUMINANT_TUNGSTEN	Same as ILLUMINANT_A.
ILLUMINANT_DAYLIGHT	Same as ILLUMINANT_C.
ILLUMINANT_FLUORESCENT	Same as ILLUMINANT_F2.
ILLUMINANT_NTSC	Same as ILLUMINANT_C.
caRedGamma

Specifies the nth power gamma-correction value for the red primary of the source colors. The value must be in the range from 2500 to 65,000. A value of 10,000 means no gamma-correction.

caGreenGamma

Specifies the nth power gamma-correction value for the green primary of the source colors. The value must be in the range from 2500 to 65,000. A value of 10,000 means no gamma-correction.

caBlueGamma

Specifies the nth power gamma-correction value for the blue primary of the source colors. The value must be in the range from 2500 to 65,000. A value of 10,000 means no gamma-correction.

caReferenceBlack

Specifies the black reference for the source colors. Any colors that are darker than this are treated as black. The value must be in the range from 0 to 4000.

caReferenceWhite

Specifies the white reference for the source colors. Any colors that are lighter than this are treated as white. The value must be in the range from 6000 to 10,000.

caContrast

Specifies the amount of contrast to be applied to the source object. The value must be in the range from  − 100 to 100. A value of 0 means no contrast adjustment.

caBrightness

Specifies the amount of brightness to be applied to the source object. The value must be in the range from  − 100 to 100. A value of 0 means no brightness adjustment.

caColorfulness

Specifies the amount of colorfulness to be applied to the source object. The value must be in the range from  − 100 to 100. A value of 0 means no colorfulness adjustment.

caRedGreenTint

Specifies the amount of red or green tint adjustment to be applied to the source object. The value must be in the range from  − 100 to 100. Positive numbers adjust towards red and negative numbers adjust towards green. Zero means no tint adjustment.

See Also

SetStretchBltMode, StretchBlt, StretchDIBits


COLORMAP [New - Windows NT]
COLORMAP  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct _COLORMAP {

    COLORREF from;

    COLORREF to;

} COLORMAP, FAR* LPCOLORMAP;

The COLORMAP structure contains information used by the CreateMappedBitmap function to map the colors of the bitmap.

Members

from

Color to map from.

to

Color to map to.

See Also

CreateMappedBitmap


COLORREF
COLORREF  QuickInfo

The COLORREF value is a 32-bit value used to specify an RGB color.

Remarks

When specifying an explicit RGB color, the COLORREF value has the following hexadecimal form:

0x00bbggrr

The low-order byte contains a value for the relative intensity of red; the second byte contains a value for green; and the third byte contains a value for blue. The high-order byte must be zero. The maximum value for a single byte is 0xFF.

See Also

GetBValue, GetGValue, GetRValue, RGB


COMMCONFIG [New - Windows 95]
COMMCONFIG  QuickInfo

[New - Windows 95]

typedef struct _COMM_CONFIG {
    DWORD dwSize;
    WORD  wVersion;

    WORD  wReserved;
    DCB   dcb;
    DWORD dwProviderSubType;
    DWORD dwProviderOffset;
    DWORD dwProviderSize;
    WCHAR wcProviderData[1];
} COMMCONFIG, *LPCOMMCONFIG;

The COMMCONFIG structure contains information about the configuration state of a communications device.

Members

dwSize

Specifies the size, in bytes, of the COMMCONFIG structure.

wVersion

Specifies the version number of the COMMCONFIG structure. For
Windows 95 device drivers, this parameter can be 1. The version of the provider-specific structure should be included in the wcProviderData member.

wReserved

Reserved; do not use.

dcb

Specifies a device-control block (DCB) structure for RS-232 serial devices. A DCB structure is always present regardless of the port driver subtype specified in the device's COMMPROP structure.

dwProviderSubType

Identifies the type of communications provider, and thus the format of the provider-specific data. For a list of communications provider types, see the description of the COMMPROP structure.

dwProviderOffset

Specifies the offset, in bytes, of the provider-specific data relative to the beginning of the structure. This member is zero if there is no provider-specific data.

dwProviderSize

Specifies the size, in bytes, of the provider-specific data.

wcProviderData

Contains the provider-specific data, if any. This member may be of any size or may be omitted. Because the COMMCONFIG structure may be expanded in the future, applications should use the dwProviderOffset member to determine the location of this member.

Remarks

If the provider subtype is PST_RS232 or PST_PARALLELPORT the wcProviderData member is omitted. If the provider subtype is PST_MODEM, the wcProviderData member contains a MODEMSETTINGS structure.

See Also

DCB, COMMPROP, GetCommProperties, MODEMSETTINGS


COMMPROP
COMMPROP  QuickInfo

typedef struct _COMMPROP { // cmmp

    WORD  wPacketLength;       // packet size, in bytes

    WORD  wPacketVersion;      // packet version

    DWORD dwServiceMask;       // services implemented

    DWORD dwReserved1;         // reserved

    DWORD dwMaxTxQueue;        // max Tx bufsize, in bytes

    DWORD dwMaxRxQueue;        // max Rx bufsize, in bytes

    DWORD dwMaxBaud;           // max baud rate, in bps

    DWORD dwProvSubType;       // specific provider type

    DWORD dwProvCapabilities;  // capabilities supported

    DWORD dwSettableParams;    // changable parameters

    DWORD dwSettableBaud;      // allowable baud rates

    WORD  wSettableData;       // allowable byte sizes

    WORD  wSettableStopParity; // stop bits/parity allowed

    DWORD dwCurrentTxQueue;    // Tx buffer size, in bytes

    DWORD dwCurrentRxQueue;    // Rx buffer size, in bytes

    DWORD dwProvSpec1;         // provider-specific data

    DWORD dwProvSpec2;         // provider-specific data

    WCHAR wcProvChar[1];       // provider-specific data

} COMMPROP;

The COMMPROP structure is used by the GetCommProperties function to return information about a given communications driver.

Members

wPacketLength

Specifies the size, in bytes, of the entire data packet, regardless of the amount of data requested.

wPacketVersion

Specifies the version of the structure.

dwServiceMask

Specifies a bitmask indicating which services are implemented by this provider. The SP_SERIALCOMM value is always specified for communications providers, including modem providers.

dwReserved1

Reserved; do not use.

dwMaxTxQueue

Specifies the maximum size, in bytes, of the driver's internal output buffer. A value of zero indicates that no maximum value is imposed by the serial provider.

dwMaxRxQueue

Specifies the maximum size, in bytes, of the driver's internal input buffer. A value of zero indicates that no maximum value is imposed by the serial provider.

dwMaxBaud

Specifies the maximum allowable baud rate, in bits per second (bps). This member can be one of the following values:

Value	Meaning
BAUD_075	75 bps
BAUD_110	110 bps
BAUD_134_5	134.5 bps
BAUD_150	150 bps
BAUD_300	300 bps
BAUD_600	600 bps
BAUD_1200	1200 bps
BAUD_1800	1800 bps
BAUD_2400	2400 bps
BAUD_4800	4800 bps
BAUD_7200	7200 bps
BAUD_9600	9600 bps
BAUD_14400	14400 bps
BAUD_19200	19200 bps
BAUD_38400	38400 bps
BAUD_56K	56K bps
BAUD_57600	57600 bps
BAUD_115200	115200 bps
BAUD_128K	128K bps
BAUD_USER	Programmable baud rates available
dwProvSubType

Specifies the specific communications provider type:

Value	Meaning
PST_FAX	FAX device
PST_LAT	LAT protocol
PST_MODEM	Modem device
PST_NETWORK_BRIDGE	Unspecified network bridge
PST_PARALLELPORT	Parallel port
PST_RS232	RS-232 serial port
PST_RS422	RS-422 port
PST_RS423	RS-423 port
PST_RS449	RS-449 port
PST_SCANNER	Scanner device
PST_TCPIP_TELNET	TCP/IP Telnet® protocol
PST_UNSPECIFIED	Unspecified
PST_X25	X.25 standards
dwProvCapabilities

Specifies a bitmask indicating the capabilities offered by the provider. This member can be one of the following values:

Value	Meaning
PCF_16BITMODE	Special 16-bit mode supported
PCF_DTRDSR	DTR (data-terminal-ready)/DSR (data-set-ready) supported
PCF_INTTIMEOUTS	Interval time-outs supported
PCF_PARITY_CHECK	Parity checking supported
PCF_RLSD	RLSD (receive-line-signal-detect) supported
PCF_RTSCTS	RTS (request-to-send)/CTS (clear-to-send) supported
PCF_SETXCHAR	Settable XON/XOFF supported
PCF_SPECIALCHARS	Special character support provided
PCF_TOTALTIMEOUTS	Total (elapsed) time-outs supported
PCF_XONXOFF	XON/XOFF flow control supported
dwSettableParams

Specifies a bitmask indicating the communications parameter that can be changed. This member can be one of the following values:

Value	Meaning
SP_BAUD	Baud rate
SP_DATABITS	Data bits
SP_HANDSHAKING	Handshaking (flow control)
SP_PARITY	Parity
SP_PARITY_CHECK	Parity checking
SP_RLSD	RLSD (receive-line-signal-detect)
SP_STOPBITS	Stop bits
dwSettableBaud

Specifies a bitmask indicating the baud rates that can be used. For values, see the dwMaxBaud member.

wSettableData

Specifies a bitmask indicating the number of data bits that can be set. This member can be one of the following values:

Value	Meaning
DATABITS_5	5 data bits
DATABITS_6	6 data bits
DATABITS_7	7 data bits
DATABITS_8	8 data bits
DATABITS_16	16 data bits
DATABITS_16X	Special wide path through serial hardware lines
wSettableStopParity

Specifies a bitmask indicating the stop bit and parity settings that can be selected. This member can be one of the following values:

Value	Meaning
STOPBITS_10	1 stop bit
STOPBITS_15	1.5 stop bits
STOPBITS_20	2 stop bits
PARITY_NONE	No parity
PARITY_ODD	Odd parity
PARITY_EVEN	Even parity
PARITY_MARK	Mark parity
PARITY_SPACE	Space parity
dwCurrentTxQueue

Specifies the size, in bytes, of the driver's internal output buffer. A value of zero indicates that the value is unavailable.

dwCurrentRxQueue

Specifies the size, in bytes, of the driver's internal input buffer. A value of zero indicates that the value is unavailable.

dwProvSpec1

Specifies provider-specific data. Applications should ignore this member unless they have detailed information about the format of the data required by the provider.

Windows 95 only: Set this member to COMMPROP_INITIALIZED before calling the GetCommProperties function to indicate that the wPacketLength member is already valid.

dwProvSpec2

Specifies provider-specific data. Applications should ignore this member unless they have detailed information about the format of the data required by the provider.

wcProvChar

Specifies provider-specific data. Applications should ignore this member unless they have detailed information about the format of the data required by the provider.

Remarks

The contents of the dwProvSpec1, dwProvSpec2, and wcProvChar members depend on the provider subtype (specified by the dwProvSubType member).

Windows 95 only:

If the provider subtype is PST_MODEM, these members are used as follows:

Value	Meaning
dwProvSpec1	Not used.
dwProvSpec2	Not used.
wcProvChar	Contains a MODEMDEVCAPS structure.
See Also

GetCommProperties


COMMTIMEOUTS
COMMTIMEOUTS  QuickInfo

typedef struct _COMMTIMEOUTS {   // ctmo

    DWORD ReadIntervalTimeout;

    DWORD ReadTotalTimeoutMultiplier;

    DWORD ReadTotalTimeoutConstant;

    DWORD WriteTotalTimeoutMultiplier;

    DWORD WriteTotalTimeoutConstant;

} COMMTIMEOUTS,*LPCOMMTIMEOUTS;

The COMMTIMEOUTS structure is used in the SetCommTimeouts and GetCommTimeouts functions to set and query the time-out parameters for a communications device. The parameters determine the behavior of ReadFile, WriteFile, ReadFileEx, and WriteFileEx operations on the device.

Members

ReadIntervalTimeout

Specifies the maximum time, in milliseconds, allowed to elapse between the arrival of two characters on the communications line. During a ReadFile operation, the time period begins when the first character is received. If the interval between the arrival of any two characters exceeds this amount, the ReadFile operation is completed and any buffered data is returned. A value of zero indicates that interval time-outs are not used.

A value of MAXDWORD, combined with zero values for both the ReadTotalTimeoutConstant and ReadTotalTimeoutMultiplier members, specifies that the read operation is to return immediately with the characters that have already been received, even if no characters have been received.

ReadTotalTimeoutMultiplier

Specifies the multiplier, in milliseconds, used to calculate the total time-out period for read operations. For each read operation, this value is multiplied by the requested number of bytes to be read.

ReadTotalTimeoutConstant

Specifies the constant, in milliseconds, used to calculate the total time-out period for read operations. For each read operation, this value is added to the product of the ReadTotalTimeoutMultiplier member and the requested number of bytes.

A value of zero for both the ReadTotalTimeoutMultiplier and ReadTotalTimeoutConstant members indicates that total time-outs are not used for read operations.

WriteTotalTimeoutMultiplier

Specifies the multiplier, in milliseconds, used to calculate the total time-out period for write operations. For each write operation, this value is multiplied by the number of bytes to be written.

WriteTotalTimeoutConstant

Specifies the constant, in milliseconds, used to calculate the total time-out period for write operations. For each write operation, this value is added to the product of the WriteTotalTimeoutMultiplier member and the number of bytes to be written.

A value of zero for both the WriteTotalTimeoutMultiplier and WriteTotalTimeoutConstant members indicates that total time-outs are not used for write operations.

Remarks

Windows 95: If an application sets the ReadIntervalTimeout and readTotalTimeoutMultiplier members to MAXDWORD and the ReadTotalTimeoutConstant member to a value greater than zero and less than MAXDWORD, one of the following occurs when the readFile function is called:Selecting a button typically causes the following events:

•	If there are any characters in the input buffer, ReadFile returns immediately with the characters in the buffer.

•	If there are no characters in the input buffer, ReadFile waits until a character arrives and then returns immediately.

•	If no character arrives within the time specified by the ReadTotalTimeoutConstant member, ReadFile times out.

See Also

GetCommTimeouts, ReadFile, ReadFileEx, SetCommTimeouts, WriteFile, WriteFileEx


COMPAREITEMSTRUCT
COMPAREITEMSTRUCT  QuickInfo

typedef struct tagCOMPAREITEMSTRUCT { // cis

    UINT  CtlType;

    UINT  CtlID;

    HWND  hwndItem;

    UINT  itemID1;

    DWORD itemData1;

    UINT  itemID2;

    DWORD itemData2;

} COMPAREITEMSTRUCT;

The COMPAREITEMSTRUCT structure supplies the identifiers and application-supplied data for two items in a sorted, owner-drawn list box or combo box.

Whenever an application adds a new item to an owner-drawn list box or combo box created with the CBS_SORT or LBS_SORT style, Windows sends the owner a WM_COMPAREITEM message. The lParam parameter of the message contains a long pointer to a COMPAREITEMSTRUCT structure. Upon receiving the message, the owner compares the two items and returns a value indicating which item sorts before the other.

Members

CtlType

Specifies ODT_LISTBOX (an owner-drawn list box) or ODT_COMBOBOX (an owner-drawn combo box).

CtlID

Specifies the identifier of the list box or combo box.

hwndItem

Identifies the control.

itemID1

Specifies the index of the first item in the list box or combo box being compared.

itemData1

Specifies application-supplied data for the first item being compared. (This value was passed as the lParam parameter of the message that added the item to the list box or combo box.)

itemID2

Specifies the index of the second item in the list box or combo box being compared.

itemData2

Specifies application-supplied data for the second item being compared. This value was passed as the lParam parameter of the message that added the item to the list box or combo box.

See Also

WM_COMPAREITEM


COMPCOLOR
COMPCOLOR  QuickInfo  Overview  Group

typedef struct {
    COLORREF crText;
    COLORREF crBackground;
    DWORD dwEffects;
} COMPCOLOR;

Contains color settings for the composition string.

Members

crText

Color of text.

crBackground

Color of background.

dwEffects

Character effect values as described for the dwEffects member in the CHARFORMAT structure.

See Also

CHARFORMAT


COMPOSITIONFORM [New - Windows 95]
COMPOSITIONFORM  QuickInfo  Overview  Group

[New - Windows 95]

typedef _tagCOMPOSITIONFORM {
    DWORD  dwStyle;
    POINT  ptCurrentPos;
    RECT   rcArea;
} COMPOSITIONFORM;

The COMPOSITIONFORM structure contains position information for the composition window.

Members

dwStyle

Position style. This member can be one of the following values:

Value	Meaning
CFS_DEFAULT	Move the composition window to the default position. The IME window can display the composition window outside the client area, such as in a floating window.
CFS_FORCE_POSITION	Display the upper-left corner of the composition window at exactly the position given by ptCurrentPos. The coordinates are relative to the upper-left corner of the window containing the composition window and are not subject to adjustment by the IME.
CFS_POINT	Display the upper-left corner of the composition window at the position given by ptCurrentPos. The coordinates are relative to the upper-left corner of the window containing the composition window and are subject to adjustment by the IME.
CFS_RECT	Display the composition window at the position given by rcArea. The coordinates are relative to the upper-left of the window containing the composition window.
ptCurrentPos

Coordinates of the upper-left corner of the composition window.

rcArea

Coordinates of the upper-left and lower-right corners of the composition window.

Remarks

Some IME windows adjust the composition window position specified by the system or the application. The CFS_FORCE_POSITION directs the IME window to skip this adjustment.


COMSTAT
COMSTAT  QuickInfo

typedef struct _COMSTAT { // cst

    DWORD fCtsHold : 1;   // Tx waiting for CTS signal

    DWORD fDsrHold : 1;   // Tx waiting for DSR signal

    DWORD fRlsdHold : 1;  // Tx waiting for RLSD signal

    DWORD fXoffHold : 1;  // Tx waiting, XOFF char rec'd

    DWORD fXoffSent : 1;  // Tx waiting, XOFF char sent

    DWORD fEof : 1;       // EOF character sent

    DWORD fTxim : 1;      // character waiting for Tx

    DWORD fReserved : 25; // reserved

    DWORD cbInQue;        // bytes in input buffer

    DWORD cbOutQue;       // bytes in output buffer

} COMSTAT, *LPCOMSTAT;

The COMSTAT structure contains information about a communications device. This structure is filled by the ClearCommError function.

Members

fCtsHold

Specifies whether transmission is waiting for the CTS (clear-to-send) signal to be sent. If this member is TRUE, transmission is waiting.

fDsrHold

Specifies whether transmission is waiting for the DSR (data-set-ready) signal to be sent. If this member is TRUE, transmission is waiting.

fRlsdHold

Specifies whether transmission is waiting for the RLSD (receive-line-signal-detect) signal to be sent. If this member is TRUE, transmission is waiting.

fXoffHold

Specifies whether transmission is waiting because the XOFF character was received. If this member is TRUE, transmission is waiting.

fXoffSent

Specifies whether transmission is waiting because the XOFF character was transmitted. If this member is TRUE, transmission is waiting. Transmission halts when the XOFF character is transmitted to a system that takes the next character as XON, regardless of the actual character.

fEof

Specifies whether the end-of-file (EOF) character has been received. If this member is TRUE, the EOF character has been received.

fTxim

If this member is TRUE, there is a character queued for transmission that has come to the communications device by way of the TransmitCommChar function. The communications device transmits such a character ahead of other characters in the device's output buffer.

fReserved

Reserved; do not use.

cbInQue

Specifies the number of bytes received by the serial provider but not yet read by a ReadFile operation.

cbOutQue

Specifies the number of bytes of user data remaining to be transmitted for all write operations. This value will be zero for a nonoverlapped write.

See Also

ClearCommError, ReadFile, TransmitCommChar


CONSOLE_CURSOR_INFO
CONSOLE_CURSOR_INFO  QuickInfo  Overview  Group

typedef struct _CONSOLE_CURSOR_INFO { // cci

    DWORD  dwSize;

    BOOL   bVisible;

} CONSOLE_CURSOR_INFO, *PCONSOLE_CURSOR_INFO;

The CONSOLE_CURSOR_INFO structure contains information about the console cursor.

Members

dwSize

Specifies a number between 1 and 100, indicating the percentage of the character cell that is filled by the cursor. The cursor appearance varies, ranging from completely filling the cell to showing up as a horizontal line at the bottom of the cell.

bVisible

Specifies the visibility of the cursor. If the cursor is visible, this member is TRUE.

See Also

GetConsoleCursorInfo, SetConsoleCursorInfo


CONSOLE_SCREEN_BUFFER_INFO
CONSOLE_SCREEN_BUFFER_INFO  QuickInfo  Overview  Group

typedef struct _CONSOLE_SCREEN_BUFFER_INFO { // csbi

    COORD      dwSize;

    COORD      dwCursorPosition;

    WORD       wAttributes;

    SMALL_RECT srWindow;

    COORD      dwMaximumWindowSize;

} CONSOLE_SCREEN_BUFFER_INFO ;

The CONSOLE_SCREEN_BUFFER_INFO structure contains information about a console screen buffer.

Members

dwSize

Specifies the size, in character columns and rows, of the screen buffer.

dwCursorPosition

Specifies the column and row coordinates of the cursor in the screen buffer.

wAttributes

Specifies the foreground (text) and background color attributes to be used for characters that are written to a screen buffer by the WriteFile and WriteConsole functions, or echoed to a screen buffer by the ReadFile and ReadConsole functions. The attribute values are some combination of the following values: FOREGROUND_BLUE, FOREGROUND_GREEN, FOREGROUND_RED, FOREGROUND_INTENSITY, BACKGROUND_BLUE, BACKGROUND_GREEN, BACKGROUND_RED, and BACKGROUND_INTENSITY. For example, the following combination of values produces red text on a white background:

FOREGROUND_RED | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE

srWindow

Specifies a SMALL_RECT structure that contains the screen buffer coordinates of the upper-left and lower-right corners of the display window.

dwMaximumWindowSize

Specifies the maximum size of the console window, given the current screen buffer size and font and the screen size.

See Also

GetConsoleScreenBufferInfo, ReadConsole, ReadFile, SMALL_RECT, WriteConsole, WriteFile


CONTEXT
CONTEXT  QuickInfo

A CONTEXT structure contains processor-specific register data. The Windows NT operating system uses CONTEXT structures to perform various internal operations. Currently, there are CONTEXT structures defined for Intel®, MIPS®,  Alpha®, and PowerPC®,processors. Refer to the header file WinNT.h for definitions of these structures.


CONVCONTEXT
CONVCONTEXT  QuickInfo

typedef struct tagCONVCONTEXT {   // cc

    UINT  cb;

    UINT  wFlags;

    UINT  wCountryID;

    int   iCodePage;

    DWORD dwLangID;

    DWORD dwSecurity;

    SECURITY_QUALITY_OF_SERVICE qos;  // client side's quality of service

} CONVCONTEXT;

The CONVCONTEXT structure contains information supplied by a DDE client application. The information is useful for specialized or cross-language DDE conversations.

Members

cb

Specifies the structure's size, in bytes.

wFlags

Specifies conversation context flags. Currently, no flags are defined for this member.

wCountryID

Specifies the country-code identifier for topic-name and item-name strings.

iCodePage

Specifies the code page for topic-name and item-name strings. Non-multilingual clients should set this member to CP_WINANSI. Unicode clients should set this value to CP_WINUNICODE.

dwLangID

Specifies the language identifier for topic-name and item-name strings.

dwSecurity

Specifies a private (application-defined) security code.

qos

Specifies the quality of service a DDE client wants from the system during a given conversation. The quality of service level specified lasts for the duration of the conversation. It cannot be changed once the conversation is started.


CONVINFO
CONVINFO  QuickInfo

typedef struct tagCONVINFO {  // ci

    DWORD       cb;

    DWORD       hUser;

    HCONV       hConvPartner;

    HSZ         hszSvcPartner;

    HSZ         hszServiceReq;

    HSZ         hszTopic;

    HSZ         hszItem;

    UINT        wFmt;

    UINT        wType;

    UINT        wStatus;

    UINT        wConvst;

    UINT        wLastError;

    HCONVLIST   hConvList;

    CONVCONTEXT ConvCtxt;

    HWND        hwnd;

    HWND        hwndPartner;

} CONVINFO;

The CONVINFO structure contains information about a DDE conversation.

Members

cb

Specifies the structure's size, in bytes.

hUser

Identifies application-defined data.

hConvPartner

Identifies the partner application in the DDE conversation. This member is zero if the partner has not registered itself (using the DdeInitialize function) to make DDE Management Library (DDEML) function calls. An application should not pass this member to any DDEML function except DdeQueryConvInfo.

hszSvcPartner

Identifies the service name of the partner application.

hszServiceReq

Identifies the service name of the server application that was requested for connection.

hszTopic

Identifies the name of the requested topic.

hszItem

Identifies the name of the requested item. This member is transaction specific.

wFmt

Specifies the format of the data being exchanged. This member is transaction specific.

wType

Specifies the type of the current transaction. This member is transaction specific; it can be one of the following values:

Value	Meaning
XTYP_ADVDATA	Informs a client that advise data from a server has arrived.
XTYP_ADVREQ	Requests a server to send updated data to the client during an advise loop. This transaction results when the server calls DdePostAdvise.
XTYP_ADVSTART	Requests a server to begin an advise loop with a client.
XTYP_ADVSTOP	Notifies a server that an advise loop is stopping.
XTYP_CONNECT	Requests a server to establish a conversation with a client.
XTYP_CONNECT_CONFIRM	Notifies a server that a conversation with a client has been established.
XTYP_DISCONNECT	Notifies a server that a conversation has terminated.
XTYP_EXECUTE	Requests a server to execute a command sent by a client.
XTYP_MONITOR	Notifies an application registered as APPCMD_MONITOR that DDE data is being transmitted.
XTYP_POKE	Requests a server to accept unsolicited data from a client.
XTYP_REGISTER	Notifies other DDEML applications that a server has registered a service name.
XTYP_REQUEST	Requests a server to send data to a client.
XTYP_UNREGISTER	Notifies other DDEML applications that a server has unregistered a service name.
XTYP_WILDCONNECT	Requests a server to establish multiple conversations with the same client.
XTYP_XACT_COMPLETE	Notifies a client that an asynchronous data transaction has been completed.
wStatus

Specifies the status of the current conversation. This member can be a combination of the following values:

Value	Meaning
ST_ADVISE	One or more links are in progress.
ST_BLOCKED	The conversation is blocked.
ST_BLOCKNEXT	The conversation will block after calling the next callback.
ST_CLIENT	The conversation handle passed to the DdeQueryConvInfo function is a client-side handle. If the handle is zero, the conversation handle passed to the DdeQueryConvInfo function is a server-side handle.
ST_CONNECTED	The conversation is connected.
ST_INLIST	The conversation is a member of a conversation list.
ST_ISLOCAL	Both sides of the conversation are using the DDEML.
ST_ISSELF	Both sides of the conversation are using the same instance of the DDEML.
ST_TERMINATED	The conversation has been terminated by the partner.
wConvst

Specifies the conversation state. This member can be one of the following values:

Value	Meaning
XST_ADVACKRCVD	The advise transaction has just been completed.
XST_ADVDATAACKRCVD	The advise data transaction has just been completed.
XST_ADVDATASENT	Advise data has been sent and is awaiting an acknowledgement.
XST_ADVSENT	An advise transaction is awaiting an acknowledgement.
XST_CONNECTED	The conversation has no active transactions.
XST_DATARCVD	The requested data has just been received.
XST_EXECACKRCVD	An execute transaction has just been completed.
XST_EXECSENT	An execute transaction is awaiting an acknowledgement.
XST_INCOMPLETE	The last transaction failed.
XST_INIT1	Mid-initiate state 1.
XST_INIT2	Mid-initiate state 2.
XST_NULL	Pre-initiate state.
XST_POKEACKRCVD	A poke transaction has just been completed.
XST_POKESENT	A poke transaction is awaiting an acknowledgement.
XST_REQSENT	A request transaction is awaiting an acknowledgement.
XST_UNADVACKRCVD	An unadvise transaction has just been completed.
XST_UNADVSENT	An unadvise transaction is awaiting an acknowledgement.
wLastError

Specifies the error value associated with the last transaction.

hConvList

Identifies the conversation list if the handle of the current conversation is in a conversation list. This member is NULL if the conversation is not in a conversation list.

ConvCtxt

Specifies the conversation context.

hwnd

Identifies the window of the calling application involved in the conversation.

hwndPartner

Identifies the window of the partner application involved in the current conversation.

See Also

CONVCONTEXT, DdeInitialize, DdePostAdvise, DdeQueryConvInfo


COORD
COORD  QuickInfo

typedef struct _COORD { // coord.

    SHORT X;      // horizontal coordinate

    SHORT Y;      // vertical coordinate

} COORD;

The COORD structure defines the coordinates of a character cell in a console screen buffer. The origin of the coordinate system (0,0) is at the top, left cell of the buffer.

Members

X

Horizontal or column value.

Y

Vertical or row value.


COPYDATASTRUCT
COPYDATASTRUCT  QuickInfo

typedef struct tagCOPYDATASTRUCT {  // cds

    DWORD dwData;

    DWORD cbData;

    PVOID lpData;

} COPYDATASTRUCT;

The COPYDATASTRUCT structure contains data to be passed to another application by the WM_COPYDATA message.

Members

dwData

Specifies up to 32 bits of data to be passed to the receiving application.

cbData

Specifies the size, in bytes, of the data pointed to by the lpData member.

lpData

Points to data to be passed to the receiving application. This member can be NULL.

See Also

WM_COPYDATA


CPINFO
CPINFO  QuickInfo

struct _cpinfo {

    UINT MaxCharSize;

    BYTE DefaultChar[MAX_DEFAULTCHAR];

    BYTE LeadByte[MAX_LEADBYTES];

} CPINFO;

The CPINFO structure contains information about a code page.

Members

MaxCharSize

Specifies the maximum length, in bytes, of a character in this code page.

DefaultChar

Specifies the default character used in translations into this code page. This character is used by the WideCharToMultiByte function if an explicit default character is not given.

LeadByte

Specifies a fixed-length array of lead-byte ranges, where the number of lead-byte ranges is variable. If there are no lead bytes in this code page, then every element of the array is NULL. If there are lead bytes in this code page, a starting value and ending value is given for each range. Ranges are inclusive. The maximum number of lead-byte ranges for any code page is 5. The array uses two bytes to describe each range, with a double-byte null terminator after the last range.

Remarks

Lead bytes are unique to double-byte character sets (DBCS). A lead byte is the first byte of a 2-byte character in a DBCS. Lead bytes occupy a specific range of byte values.

See Also

GetCPInfo, WideCharToMultiByte


CPLINFO
CPLINFO  QuickInfo

typedef struct tagCPLINFO { // cpli

    int  idIcon;

    int  idName;

    int  idInfo;

    LONG lData;

} CPLINFO;

The CPLINFO structure contains resource information and a user-defined value for a dialog box supported by a Control Panel application.

Members

idIcon

Specifies the resource identifier of the icon that represents the dialog box.

idName

Specifies the resource identifier of the string containing the short name for the dialog box. This name is intended to be displayed below the icon.

idInfo

Specifies the resource identifier of the string containing the description for the dialog box. The description is the descriptive string that is intended to be displayed when the application icon is selected.

lData

Specifies user-defined data for the dialog box.

See Also

CPL_NEWINQUIRE, NEWCPLINFO


CREATE_PROCESS_DEBUG_INFO
CREATE_PROCESS_DEBUG_INFO  QuickInfo

typedef struct _CREATE_PROCESS_DEBUG_INFO { // cpdi

    HANDLE hFile;

    HANDLE hProcess;

    HANDLE hThread;

    LPVOID lpBaseOfImage;

    DWORD dwDebugInfoFileOffset;

    DWORD nDebugInfoSize;

    LPVOID lpThreadLocalBase;

    LPTHREAD_START_ROUTINE lpStartAddress;

    LPVOID lpImageName;

    WORD fUnicode;

} CREATE_PROCESS_DEBUG_INFO;

The CREATE_PROCESS_DEBUG_INFO structure contains process creation information that can be used by a debugger.

Members

hFile

Identifies an open handle of the process's image file. If this member is NULL, the handle is not valid. Otherwise, the debugger can use the member to read from and write to the image file.

hProcess

Identifies an open handle of the process. If this member is NULL, the handle is not valid. Otherwise, the debugger can use the member to read from and write to the process's memory.

hThread

Identifies an open handle of the initial thread of the process identified by the hProcess member. If hThread is NULL, the handle is not valid. Otherwise, the debugger has THREAD_GET_CONTEXT, THREAD_SET_CONTEXT, and THREAD_SUSPEND_RESUME access to the thread, allowing the debugger to read from and write to the registers of the thread and to control execution of the thread.

lpBaseOfImage

Points to the base address of the executable image that the process is running.

dwDebugInfoFileOffset

Specifies the offset to the debugging information in the file identified by the hFile member. The kernel expects the debugging information to be in Microsoft® CodeView® version 4.0 format. This format is currently a derivative of COFF (Common Object File Format).

nDebugInfoSize

Specifies the size, in bytes, of the debugging information in the file. If this value is zero, there is no debugging information.

lpThreadLocalBase

Points to a block of data. At offset 0x2C into this block is another pointer, called ThreadLocalStoragePointer, that points to an array of per-module thread local storage blocks. This gives a debugger access to per-thread data in the threads of the process being debugged using the same algorithms that a compiler would use.

lpStartAddress

Points to the starting address of the thread. This value may only be an approximation of the thread's starting address, because any application with appropriate access to the thread can change the thread's context by using the SetThreadContext function.

lpImageName

Points to the filename associated with the hFile parameter. This parameter may be NULL, or it may contain the address of a string pointer in the address space of the process being debugged. That address may, in turn, either be NULL or point to the actual filename. If fUnicode is a nonzero value, the name string is Unicode; otherwise, it is ANSI.

This member is strictly optional. Debuggers must be prepared to handle the case where lpImageName is NULL or *lpImageName (in the address space of the process being debugged) is NULL. Specifically, Windows does not provide an image name for a create process event, and will not likely pass an image name for the first DLL event. Windows also does not provide this information in the case of debug events that originate from a call to the DebugActiveProcess function.

fUnicode

Indicates whether a file name specified by the lpImageName member is Unicode or ANSI. A nonzero value indicates Unicode; zero indicates ANSI.

See Also

CREATE_THREAD_DEBUG_INFO, DebugActiveProcess, DEBUG_EVENT, LOAD_DLL_DEBUG_INFO, SetThreadContext


CREATE_THREAD_DEBUG_INFO
CREATE_THREAD_DEBUG_INFO  QuickInfo

typedef struct _CREATE_THREAD_DEBUG_INFO { // ctdi

    HANDLE hThread;

    LPVOID lpThreadLocalBase;

    LPTHREAD_START_ROUTINE lpStartAddress;

} CREATE_THREAD_DEBUG_INFO;

The CREATE_THREAD_DEBUG_INFO structure contains thread-creation information that can be used by a debugger.

Members

hThread

Identifies a handle of the thread whose creation caused the debugging event. If this member is NULL, the handle is not valid. Otherwise, the debugger has THREAD_GET_CONTEXT, THREAD_SET_CONTEXT, and THREAD_SUSPEND_RESUME access to the thread, allowing the debugger to read from and write to the registers of the thread and control execution of the thread.

lpThreadLocalBase

Points to a block of data. At offset 0x2C into this block is another pointer, called ThreadLocalStoragePointer, that points to an array of per-module thread local storage blocks. This gives a debugger access to per-thread data in the threads of the process being debugged using the same algorithms that a compiler would use.

lpStartAddress

Points to the starting address of the thread. This value may only be an approximation of the thread's starting address, because any application with appropriate access to the thread can change the thread's context by using the SetThreadContext function.

See Also

CREATE_PROCESS_DEBUG_INFO, DEBUG_EVENT, LOAD_DLL_DEBUG_INFO, SetThreadContext


CREATESTRUCT
CREATESTRUCT  QuickInfo

typedef struct tagCREATESTRUCT { // cs

    LPVOID    lpCreateParams;

    HINSTANCE hInstance;

    HMENU     hMenu;

    HWND      hwndParent;

    int       cy;

    int       cx;

    int       y;

    int       x;

    LONG      style;

    LPCTSTR   lpszName;

    LPCTSTR   lpszClass;

    DWORD     dwExStyle;

} CREATESTRUCT;

The CREATESTRUCT structure defines the initialization parameters passed to the window procedure of an application.

Members

lpCreateParams

Points to data to be used for creating the window.

Windows NT: This member is the address of a SHORT (16_bit) value that specifies the size, in bytes, of the window creation data. The value is immediately followed by the creation data. For more information, see the following Remarks section.

hInstance

Identifies the module that owns the new window.

hMenu

Identifies the menu to be used by the new window.

hwndParent

Identifies the parent window, if the window is a child window. If the window is owned, this member identifies the owner window. If the window is not a child or owned window, this member is NULL.

cy

Specifies the height of the new window, in pixels.

cx

Specifies the width of the new window, in pixels.

y

Specifies the y-coordinate of the upper left corner of the new window. If the new window is a child window, coordinates are relative to the parent window. Otherwise, the coordinates are relative to the screen origin.

x

Specifies the x-coordinate of the upper left corner of the new window. If the new window is a child window, coordinates are relative to the parent window. Otherwise, the coordinates are relative to the screen origin.

style

Specifies the style for the new window.

lpszName

Points to a null-terminated string that specifies the name of the new window.

lpszClass

Points to a null-terminated string that specifies the class name of the new window.

dwExStyle

Specifies the extended style for the new window.

Remarks

Windows NT: Referring to the lpCreateParams member of the CREATESTRUCT structure, because the pointer may not be DWORD aligned, an application should access the data using a pointer that has been declared using the UNALIGNED type, as shown in the following example:

typedef struct tagMyData {

    . . .;	// define creation data here

} MYDATA;

typedef struct tagMyDlgData {

    SHORT    cbExtra;

    MYDATA  myData;

} MYDLGDATA, UNALIGNED *PMYDLGDATA;

PMYDLGDATA pMyDlgdata =

    (PMYDLGDATA) (((LPCREATESTRUCT) lParam)->lpcreateParams);

See Also

CreateWindow, CreateWindowEx


CSADDR_INFO
CSADDR_INFO  QuickInfo  Overview  Group

typedef struct _CSADDR_INFO {

    SOCKET_ADDRESS  LocalAddr;

    SOCKET_ADDRESS  RemoteAddr;

    INT             iSocketType;

    INT             iProtocol;

} CSADDR_INFO;

The CSADDR_INFO structure contains Windows Sockets address information for a network service or name space provider. The GetAddressByName function obtains Windows Sockets address information using CSADDR_INFO structures.

LocalAddr

Specifies a Windows Sockets local address.

In a client application, pass this address to the bind function to obtain access to a network service.

In a network service, pass this address to the bind function so that the service is bound to the appropriate local address.

RemoteAddr

Specifies a Windows Sockets remote address. There are several uses for this remote address:

•	You can use this remote address to connect to the service via the connect function. This is useful if an application performs send/receive operations that involve connection-oriented protocols.

•	You can use this remote address with the sendto function when you are communicating over a connectionless (datagram) protocol. If you are using a connectionless protocol, such as UDP, sendto is typically the way you pass data to the remote system.

iSocketType

Specifies the type of the Windows socket. The following socket types are defined in WINSOCK.H:

Value	Socket Type
SOCK_STREAM	Stream.This is a protocol that sends data as a stream of bytes, with no message boundaries.
SOCK_DGRAM	Datagram. This is a connectionless protocol. There is no virtual circuit setup. There are typically no reliability guarantees. Services use recvfrom to obtain datagrams. The listen and accept functions do not work with datagrams.
SOCK_RDM	Reliably-Delivered Message. This is a protocol that preserves message boundaries in data.
SOCK_SEQPACKET	Sequenced packet stream. This is a protocol that is essentially the same as SOCK_RDM.
iProtocol

Specifies a value to pass as the protocol parameter to the socket function to open a socket for this service.

See Also

bind, connect, GetAddressByName, recv, send, sendto


CURRENCYFMT
CURRENCYFMT  QuickInfo

typedef struct _currencyfmt {

    UINT      NumDigits;

    UINT      LeadingZero;

    UINT      Grouping;

    LPTSTR    lpDecimalSep;

    LPTSTR    lpThousandSep;

    UINT      NegativeOrder;

    UINT      PositiveOrder;

    LPTSTR    lpCurrencySymbol;
} CURRENCYFMT;

The CURRENCYFMT structure contains information that defines the format of a currency string. The GetCurrencyFormat function uses this information to customize a currency string for a specified locale.

Members

NumDigits

Specifies the number of fractional digits. This is equivalent to the locale information specified by the LCTYPE constant value LOCALE_IDIGITS.

LeadingZero

Specifies whether to use leading zeroes in decimal fields. This is equivalent to the locale information specified by the LCTYPE constant value LOCALE_ILZERO.

Grouping

Specifies the size of each group of digits to the left of the decimal. Values in the range 0 − 9 are valid.

lpDecimalSep

Points to a null-terminated decimal separator string.

lpThousandSep

Points to a null-terminated thousand separator string.

NegativeOrder

Specifies the negative currency mode. This is equivalent to the locale information specified by the LCTYPE constant value LOCALE_INEGCURR.

PositiveOrder

Specifies the positive currency mode. This is equivalent to the locale information specified by the LCTYPE constant value LOCALE_ICURRENCY.

lpCurrencySymbol

Points to a null-terminated currency symbol string.

Remarks

For more information about the LCTYPE constants, see LCTYPE Constants.

See Also

GetCurrencyFormat


CURSORSHAPE
CURSORSHAPE  QuickInfo

typedef struct tagCURSORSHAPE {    // cs

    int     xHotSpot;

    int     yHotSpot;

    int     cx;

    int     cy;

    int     cbWidth;

    BYTE    Planes;

    BYTE    BitsPixel;

} CURSORSHAPE, FAR *LPCURSORSHAPE;

The CURSORSHAPE structure contains information about a cursor.

Members

xHotSpot

Specifies the horizontal position of the hot spot, relative to the upper left corner of the cursor bitmap.

yHotSpot

Specifies the vertical position of the hot spot, relative to the upper left corner of the cursor bitmap.

cx

Specifies the width, in pixels, of the cursor.

cy

Specifies the height, in pixels, of the cursor.

cbWidth

Width, in bytes, of the cursor bitmap.

Planes

Specifies the number of color planes.

BitsPixel

Specifies the number of bits used to indicate the color of a single pixel in the cursor.

Remarks

When an application passes a cursor handle to the LockResource function, the function returns a pointer to a buffer containing information about the cursor. An application can use the CURSORSHAPE structure to access the information.

See Also

LockResource


CWPRETSTRUCT [New - Windows 95]
CWPRETSTRUCT  QuickInfo

[New - Windows 95]

typedef struct tagCWPRETSTRUCT { // cwprs

    LRESULT lResult;

    LPARAM  lParam;

    WPARAM  wParam;

    DWORD   message;

    HWND    hwnd;

} CWPRETSTRUCT;

The CWPRETSTRUCT structure defines the message parameters passed to a WH_CALLWNDPROCRET hook procedure.

Members

lResult

Specifies the return value of the window procedure that processed the message specified by the message value.

lParam

Specifies additional information about the message. The exact meaning depends on the message value.

wParam

Specifies additional information about the message. The exact meaning depends on the message value.

message

Specifies the message.

hwnd

Identifies the window that processed the message specified by the message value.

See Also

CallWndRetProc, SetWindowsHook, SetWindowsHookEx


CWPSTRUCT
CWPSTRUCT  QuickInfo

typedef struct tagCWPSTRUCT { // cwps

    LPARAM  lParam;

    WPARAM  wParam;

    UINT    message;

    HWND    hwnd;

} CWPSTRUCT;

The CWPSTRUCT structure defines the message parameters passed to a WH_CALLWNDPROC hook procedure.

Members

lParam

Specifies additional information about the message. The exact meaning depends on the message value.

wParam

Specifies additional information about the message. The exact meaning depends on the message value.

message

Specifies the message.

hwnd

Identifies the window to receive the message.

See Also

CallWndProc, SetWindowsHook, SetWindowsHookEx


DATATYPES_INFO_1
DATATYPES_INFO_1  QuickInfo  Overview  Group

typedef struct _DATATYPES_INFO_1 {

    LPTSTR pName;

} DATATYPES_INFO_1;

The DATATYPES_INFO_1 structure contains information about the data type used to record a print job.

Members

pName

Points to a null-terminated string that identifies the data type used to record a print job.

See Also

EnumPrintProcessorDataTypes


DCB
DCB  QuickInfo

typedef struct _DCB { // dcb

    DWORD DCBlength;           // sizeof(DCB)

    DWORD BaudRate;            // current baud rate

    DWORD fBinary: 1;          // binary mode, no EOF check

    DWORD fParity: 1;          // enable parity checking

    DWORD fOutxCtsFlow:1;      // CTS output flow control

    DWORD fOutxDsrFlow:1;      // DSR output flow control

    DWORD fDtrControl:2;       // DTR flow control type

    DWORD fDsrSensitivity:1;   // DSR sensitivity

    DWORD fTXContinueOnXoff:1; // XOFF continues Tx

    DWORD fOutX: 1;        // XON/XOFF out flow control

    DWORD fInX: 1;         // XON/XOFF in flow control

    DWORD fErrorChar: 1;   // enable error replacement

    DWORD fNull: 1;        // enable null stripping

    DWORD fRtsControl:2;   // RTS flow control

    DWORD fAbortOnError:1; // abort reads/writes on error

    DWORD fDummy2:17;      // reserved

    WORD wReserved;        // not currently used

    WORD XonLim;           // transmit XON threshold

    WORD XoffLim;          // transmit XOFF threshold

    BYTE ByteSize;         // number of bits/byte, 4-8

    BYTE Parity;           // 0-4=no,odd,even,mark,space

    BYTE StopBits;         // 0,1,2 = 1, 1.5, 2

    char XonChar;          // Tx and Rx XON character

    char XoffChar;         // Tx and Rx XOFF character

    char ErrorChar;        // error replacement character

    char EofChar;          // end of input character

    char EvtChar;          // received event character

    WORD wReserved1;       // reserved; do not use

} DCB;

The DCB structure defines the control setting for a serial communications device.

Members

DCBlength

Specifies the length, in bytes, of the DCB structure.

BaudRate

Specifies the baud rate at which the communications device operates. This member can be an actual baud rate value, or one of the following baud rate indexes:

CBR_110	CBR_19200
CBR_300	CBR_38400
CBR_600	CBR_56000
CBR_1200	CBR_57600
CBR_2400	CBR_115200
CBR_4800	CBR_128000
CBR_9600	CBR_256000
CBR_14400
fBinary

Specifies whether binary mode is enabled. The Win32 API does not support nonbinary mode transfers, so this member should be TRUE. Trying to use FALSE will not work.

Under Windows 3.1, if this member is FALSE, nonbinary mode is enabled, and the character specified by the EofChar member is recognized on input and remembered as the end of data.

fParity

Specifies whether parity checking is enabled. If this member is TRUE, parity checking is performed and errors are reported.

fOutxCtsFlow

Specifies whether the CTS (clear-to-send) signal is monitored for output flow control. If this member is TRUE and CTS is turned off, output is suspended until CTS is sent again.

fOutxDsrFlow

Specifies whether the DSR (data-set-ready) signal is monitored for output flow control. If this member is TRUE and DSR is turned off, output is suspended until DSR is sent again.

fDtrControl

Specifies the DTR (data-terminal-ready) flow control. This member can be one of the following values:

Value	Meaning
DTR_CONTROL_DISABLE	Disables the DTR line when the device is opened and leaves it disabled.
DTR_CONTROL_ENABLE	Enables the DTR line when the device is opened and leaves it on.
DTR_CONTROL_HANDSHAKE	Enables DTR handshaking. If handshaking is enabled, it is an error for the application to adjust the line by using the EscapeCommFunction function.
fDsrSensitivity

Specifies whether the communications driver is sensitive to the state of the DSR signal. If this member is TRUE, the driver ignores any bytes received, unless the DSR modem input line is high.

fTXContinueOnXoff

Specifies whether transmission stops when the input buffer is full and the driver has transmitted the XoffChar character. If this member is TRUE, transmission continues after the input buffer has come within XoffLim bytes of being full and the driver has transmitted the XoffChar character to stop receiving bytes. If this member is FALSE, transmission does not continue until the input buffer is within XonLim bytes of being empty and the driver has transmitted the XonChar character to resume reception.

fOutX

Specifies whether XON/XOFF flow control is used during transmission. If this member is TRUE, transmission stops when the XoffChar character is received and starts again when the XonChar character is received.

fInX

Specifies whether XON/XOFF flow control is used during reception. If this member is TRUE, the XoffChar character is sent when the input buffer comes within XoffLim bytes of being full, and the XonChar character is sent when the input buffer comes within XonLim bytes of being empty.

fErrorChar

Specifies whether bytes received with parity errors are replaced with the character specified by the ErrorChar member. If this member is TRUE and the fParity member is TRUE, replacement occurs.

fNull

Specifies whether null bytes are discarded. If this member is TRUE, null bytes are discarded when received.

fRtsControl

Specifies the RTS (request-to-send) flow control. If this value is zero, the default is RTS_CONTROL_HANDSHAKE. This member can be one of the following values:

Value	Meaning
RTS_CONTROL_DISABLE	Disables the RTS line when the device is opened and leaves it disabled.
RTS_CONTROL_ENABLE	Enables the RTS line when the device is opened and leaves it on.
RTS_CONTROL_HANDSHAKE	Enables RTS handshaking. The driver raises the RTS line when the "type-ahead" (input) buffer is less than one-half full and lowers the RTS line when the buffer is more than three-quarters full. If handshaking is enabled, it is an error for the application to adjust the line by using the EscapeCommFunction function.
RTS_CONTROL_TOGGLE	Specifies that the RTS line will be high if bytes are available for transmission. After all buffered bytes have been sent, the RTS line will be low.
fAbortOnError

Specifies whether read and write operations are terminated if an error occurs. If this member is TRUE, the driver terminates all read and write operations with an error status if an error occurs. The driver will not accept any further communications operations until the application has acknowledged the error by calling the ClearCommError function.

fDummy2

Reserved; do not use.

wReserved

Not used; must be set to zero.

XonLim

Specifies the minimum number of bytes allowed in the input buffer before the XON character is sent.

XoffLim

Specifies the maximum number of bytes allowed in the input buffer before the XOFF character is sent. The maximum number of bytes allowed is calculated by subtracting this value from the size, in bytes, of the input buffer.

ByteSize

Specifies the number of bits in the bytes transmitted and received.

Parity

Specifies the parity scheme to be used. This member can be one of the following values:

Value	Meaning
EVENPARITY	Even
MARKPARITY	Mark
NOPARITY	No parity
ODDPARITY	Odd
StopBits

Specifies the number of stop bits to be used. This member can be one of the following values:

Value	Meaning
ONESTOPBIT	1 stop bit
ONE5STOPBITS	1.5 stop bits
TWOSTOPBITS	2 stop bits
XonChar

Specifies the value of the XON character for both transmission and reception.

XoffChar

Specifies the value of the XOFF character for both transmission and reception.

ErrorChar

Specifies the value of the character used to replace bytes received with a parity error.

EofChar

Specifies the value of the character used to signal the end of data.

EvtChar

Specifies the value of the character used to signal an event.

wReserved1

Reserved; do not use.

Remarks

When a DCB structure is used to configure the 8250, the following restrictions apply to the values specified for the ByteSize and StopBits members:

•	The number of data bits must be 5 to 8 bits.

•	The use of 5 data bits with 2 stop bits is an invalid combination, as is 6, 7, or 8 data bits with 1.5 stop bits.

See Also

BuildCommDCB, ClearCommError, EscapeCommFunction, GetCommState, SetCommState


DDEACK
DDEACK  QuickInfo

typedef struct { // ddeack

    unsigned short bAppReturnCode:8,

    reserved:6,

    fBusy:1,

    fAck:1;

} DDEACK;

The DDEACK structure contains status flags that a DDE application passes to its partner as part of the WM_DDE_ACK message. The flags provide details about the application's response to the messages WM_DDE_DATA, WM_DDE_POKE, WM_DDE_EXECUTE, WM_DDE_ADVISE, WM_DDE_UNADVISE, and WM_DDE_REQUEST.

Members

bAppReturnCode

Specifies an application-defined return code.

fBusy

Indicates whether the application was busy and unable to respond to the partner's message at the time the message was received. A nonzero value indicates the partner was busy and unable to respond. The fBusy member is defined only when the fAck member is zero.

fAck

Indicates whether the application accepted the message from its partner. A nonzero value indicates the partner accepted the message.

See Also

WM_DDE_ACK, WM_DDE_ADVISE, WM_DDE_DATA, WM_DDE_EXECUTE, WM_DDE_REQUEST, WM_DDE_POKE, WM_DDE_UNADVISE


DDEADVISE
DDEADVISE  QuickInfo

typedef struct { // ddeadv

    unsigned short reserved:14,

        fDeferUpd:1,

        fAckReq:1;

    short cfFormat;

} DDEADVISE;

The DDEADVISE structure contains flags that specify how a DDE server application should send data to a client application during an advise loop. A client passes the handle of a DDEADVISE structure to a server as part of a WM_DDE_ADVISE message. This structure supersedes the DDELN structure.

Members

fDeferUpd

Indicates whether the server should defer sending updated data to the client. If this value is nonzero, the server should send a WM_DDE_DATA message with a NULL data handle whenever the data item changes. In response, the client can post a WM_DDE_REQUEST message to the server to get a handle of the updated data.

fAckReq

Indicates whether the server should set the fAckReq flag in the WM_DDE_DATA messages it posts to the client. If this value is nonzero, the server should set the fAckReq bit.

cfFormat

Specifies the client application's preferred data format. The format must be a standard or registered clipboard format. The following standard clipboard formats can be used:

CF_BITMAP
CF_DIB
CF_DIF
CF_ENHMETAFILE
CF_METAFILEPICT
CF_OEMTEXT
CF_PALETTE
CF_PENDATA
CF_RIFF
CF_SYLK
CF_TEXT
CF_TIFF
CF_WAVE
CF_UNICODETEXT

See Also

WM_DDE_ADVISE, WM_DDE_DATA, WM_DDE_UNADVISE


DDEDATA
DDEDATA  QuickInfo

typedef struct { // ddedat

    unsigned short unused:12,

        fResponse:1,

        fRelease:1,

        reserved:1,

        fAckReq:1;

    short cfFormat;

    BYTE  Value[1];

} DDEDATA;

The DDEDATA structure contains the data, and information about the data, sent as part of a WM_DDE_DATA message. This structure supersedes the DDEUP structure.

Members

fResponse

Indicates whether the data was sent in response to a WM_DDE_REQUEST message or a WM_DDE_ADVISE message. If this value is nonzero, the data was sent in response to a WM_DDE_REQUEST message.

fRelease

Indicates whether the application receiving the WM_DDE_POKE message should free the data. If this value is nonzero, the application should free the data.

fAckReq

Indicates whether the application receiving the WM_DDE_DATA message should acknowledge receipt of the data by sending a WM_DDE_ACK message. If this value is nonzero, the application should send the acknowledgment.

cfFormat

Specifies the format of the data. The format should be a standard or registered clipboard format. The following standard clipboard formats can be used:

CF_BITMAP
CF_DIB
CF_DIF
CF_ENHMETAFILE
CF_METAFILEPICT
CF_OEMTEXT
CF_PALETTE
CF_PENDATA
CF_RIFF
CF_SYLK
CF_TEXT
CF_TIFF
CF_WAVE
CF_UNICODETEXT

Value

Contains the data. The length and type of data depend on the cfFormat member.

See Also

DDEUP, WM_DDE_ACK, WM_DDE_ADVISE, WM_DDE_DATA, WM_DDE_POKE, WM_DDE_REQUEST


DDELN
DDELN  QuickInfo

typedef struct { // ddeln

    unsigned short unused:13,

        fRelease:1,

        fDeferUpd:1,

        fAckReq:1;

    short cfFormat;

} DDELN;

The DDELN structure is obsolete. Win32-based applications should use the DDEADVISE structure.

See Also

DDEADVISE, WM_DDE_ADVISE, WM_DDE_UNADVISE


DDEML_MSG_HOOK_DATA
DDEML_MSG_HOOK_DATA  QuickInfo

typedef struct tagDDEML_MSG_HOOK_DATA { // dmhd

    UINT  uiLo;

    UINT  uiHi;

    DWORD cbData;

    DWORD Data[8];

} DDEML_MSG_HOOK_DATA;

The DDEML_MSG_HOOK_DATA structure contains information about a DDE message, and provides read access to the data referenced by the message. This structure is intended to be used by a DDE Management Library (DDEML) monitoring application.

Members

uiLo

Specifies the unpacked low-order word of the lParam parameter associated with the DDE message.

uiHi

Specifies the unpacked high-order word of the lParam parameter associated with the DDE message.

cbData

Specifies the amount, in bytes, of data being passed with the message. This value can be greater than 32.

Data

Contains the first 32 bytes of data being passed with the message
(8 * sizeof(DWORD)).

See Also

MONCBSTRUCT, MONCONVSTRUCT, MONERRSTRUCT, MONHSZSTRUCT, MONLINKSTRUCT, MONMSGSTRUCT


DDEPOKE
DDEPOKE  QuickInfo

typedef struct { // ddepok

    unsigned short unused:13,

        fRelease:1,

        fReserved:2;

    short cfFormat;

    BYTE  Value[1];

} DDEPOKE;

The DDEPOKE structure contains the data, and information about the data, sent as part of a WM_DDE_POKE message. This structure supersedes the DDEUP structure.

Members

fRelease

Indicates whether the application receiving the WM_DDE_POKE message should free the data. If this value is nonzero, the application should free the data.

fReserved

Reserved; do not use.

cfFormat

Specifies the format of the data. The format should be a standard or registered clipboard format. The following standard clipboard formats can be used:

CF_BITMAP
CF_DIB
CF_DIF
CF_ENHMETAFILE
CF_METAFILEPICT
CF_OEMTEXT
CF_PALETTE
CF_PENDATA
CF_RIFF
CF_SYLK
CF_TEXT
CF_TIFF
CF_WAVE
CF_UNICODETEXT

Value

Contains the data. The length and type of data depend on the value of the cfFormat member.

See Also

DDEUP, WM_DDE_POKE


DDEUP
DDEUP  QuickInfo

typedef struct { // ddeup

    unsigned short unused:12,

        fAck:1,

        fRelease:1,

        fReserved:1,

        fAckReq:1;

    short cfFormat;

    BYTE rgb[1];

} DDEUP;

The DDEUP structure is obsolete. Win32-based applications should use the DDEDATA and DDEPOKE structures.

See Also

WM_DDE_DATA, WM_DDE_POKE


DEBUG_EVENT
DEBUG_EVENT  QuickInfo

typedef struct _DEBUG_EVENT { // de

    DWORD dwDebugEventCode;

    DWORD dwProcessId;

    DWORD dwThreadId;

    union {

        EXCEPTION_DEBUG_INFO Exception;

        CREATE_THREAD_DEBUG_INFO CreateThread;

        CREATE_PROCESS_DEBUG_INFO CreateProcessInfo;

        EXIT_THREAD_DEBUG_INFO ExitThread;

        EXIT_PROCESS_DEBUG_INFO ExitProcess;

        LOAD_DLL_DEBUG_INFO LoadDll;

        UNLOAD_DLL_DEBUG_INFO UnloadDll;

        OUTPUT_DEBUG_STRING_INFO DebugString;

        RIP_INFO RipInfo;

    } u;

} DEBUG_EVENT;

The DEBUG_EVENT structure describes a debugging event.

Members

dwDebugEventCode

Specifies a debugging event code that identifies the type of debugging event. This parameter can be one of the following values:

Value	Meaning
EXCEPTION_DEBUG_EVENT
	Reports an exception debugging event. The value of u.Exception specifies an EXCEPTION_DEBUG_INFO structure.
CREATE_THREAD_DEBUG_EVENT
	Reports a create-thread debugging event. The value of u.CreateThread specifies a CREATE_THREAD_DEBUG_INFO str structure.
CREATE_PROCESS_DEBUG_EVENT
	Reports a create-process debugging event. The value of u.CreateProcessInfo specifies a CREATE_PROCESS_DEBUG_INFO str structure.
EXIT_THREAD_DEBUG_EVENT
	Reports an exit-thread debugging event. The value of u.ExitThread specifies an EXIT_THREAD_DEBUG_INFO str structure.
EXIT_PROCESS_DEBUG_EVENT
	Reports an exit-process debugging event. The value of u.ExitProcess specifies an EXIT_PROCESS_DEBUG_INFO str structure.
LOAD_DLL_DEBUG_EVENT
	Reports a load-dynamic-link-library (DLL) debugging event. The value of u.LoadDll specifies a LOAD_DLL_DEBUG_INFO str structure.
UNLOAD_DLL_DEBUG_EVENT
	Reports an unload-DLL debugging event. The value of u.UnloadDll specifies an UNLOAD_DLL_DEBUG_INFO str structure.
OUTPUT_DEBUG_STRING_EVENT
	Reports an output-debugging-string debugging event. The value of u.DebugString specifies an OUTPUT_DEBUG_STRING_INFO str structure.
RIP_EVENT
	Reports a RIP-debugging event (system debugging error). The value of u.RipInfo specifies a RIP_INFO structure.
dwProcessId

Specifies the identifier of the process in which the debugging event occurred. A debugger uses this value to locate the debugger's per-process structure. These values are not necessarily small integers that can be used as table indices.

dwThreadId

Specifies the identifier of the thread in which the debugging event occurred. A debugger uses this value to locate the debugger's per-thread structure. These values are not necessarily small integers that can be used as table indices.

u

Specifies additional information relating to the debugging event. This union takes on the type and value appropriate to the type of debugging event, as described in the dwDebugEventCode member.

Remarks

If the WaitForDebugEvent function succeeds, it fills in the members of a DEBUG_EVENT structure.

See Also

CREATE_PROCESS_DEBUG_INFO, CREATE_THREAD_DEBUG_INFO, EXIT_PROCESS_DEBUG_INFO, EXIT_THREAD_DEBUG_INFO, EXCEPTION_DEBUG_INFO, LOAD_DLL_DEBUG_INFO, OUTPUT_DEBUG_STRING_INFO, UNLOAD_DLL_DEBUG_INFO, WaitForDebugEvent


DEBUGHOOKINFO
DEBUGHOOKINFO  QuickInfo

typedef struct tagDEBUGHOOKINFO { // dh

    DWORD  idThread;

    DWORD  idThreadInstaller;

    LPARAM lParam;

    WPARAM wParam;

    int    code;

} DEBUGHOOKINFO;

The DEBUGHOOKINFO structure contains debugging information.

Members

idThread

Identifies the thread containing the filter function.

idThreadInstaller

Identifies the thread that installed the debugging filter function.

lParam

Specifies the value to be passed to the hook in the lParam parameter of the DebugProc callback function.

wParam

Specifies the value to be passed to the hook in the wParam parameter of the DebugProc callback function.

code

Specifies the value to be passed to the hook in the nCode parameter of the DebugProc callback function.

See Also

DebugProc, SetWindowsHook, SetWindowsHookEx


DELETEITEMSTRUCT
DELETEITEMSTRUCT  QuickInfo

typedef struct tagDELETEITEMSTRUCT { // ditms

    UINT CtlType;

    UINT CtlID;

    UINT itemID;

    HWND hwndItem;

    UINT itemData;

} DELETEITEMSTRUCT;

The DELETEITEMSTRUCT structure describes a deleted list box or combo box item. The lParam parameter of a WM_DELETEITEM message contains a pointer to this structure. When an item is removed from a list box or combo box or when a list box or combo box is destroyed, Windows sends the WM_DELETEITEM message to the owner for each deleted item.

Windows NT

Windows sends a WM_DELETEITEM message only for items deleted from an owner-drawn list box (with the LBS_OWNERDRAWFIXED or LBS_OWNERDRAWVARIABLE style) or owner-drawn combo box (with the CBS_OWNERDRAWFIXED or CBS_OWNERDRAWVARIABLE style).

Windows 95

Windows sends the WM_DELETEITEM message for any deleted list box or combo box item with non-zero item data.

Members

CtlType

Specifies one of the following values to indicate whether the item was deleted from a list box or a combo box:

Value	Meaning
ODT_LISTBOX	A list box.
ODT_COMBOBOX	A combo box.
CtlID

Specifies the identifier of the list box or combo box.

itemID

Specifies index of the item in the list box or combo box being removed.

hwndItem

Identifies the control.

itemData

Specifies application-defined data for the item. This value is passed to the control in the lParam parameter of the message that adds the item to the list box or combo box.

See Also

WM_DELETEITEM


DEV_BROADCAST_HDR [New - Windows 95]
DEV_BROADCAST_HDR  QuickInfo  Overview  Group

[New - Windows 95]

typedef struct _DEV_BROADCAST_HDR {
    ULONG dbch_size;

    ULONG dbch_devicetype;

    ULONG dbch_reserved;

} DEV_BROADCAST_HDR;
typedef DEV_BROADCAST_HDR *PDEV_BROADCAST_HDR;

The DEV_BROADCAST_HDR structure contains information about the device affected by a WM_DEVICECHANGE message.

Members

dbch_size

Size of this structure, in bytes.

dbch_devicetype

Type of device. Can be one of these values:

Value	Meaning
DBT_DEVTYP_OEM	OEM- or IHV-defined device type.
DBT_DEVTYP_VOLUME	Logical volume.
DBT_DEVTYP_PORT	Port device (serial or parallel).
dbch_reserved

Reserved; do not use.

See Also

WM_DEVICECHANGE


DEV_BROADCAST_OEM [New - Windows 95]
DEV_BROADCAST_OEM  QuickInfo  Overview  Group

[New - Windows 95]

typedef struct _DEV_BROADCAST_OEM {
    ULONG dbco_size;

    ULONG dbco_devicetype;

    ULONG dbco_reserved;

    ULONG dbco_identifier;

    ULONG dbco_suppfunc;

} DEV_BROADCAST_OEM;
typedef DEV_BROADCAST_OEM *PDEV_BROADCAST_OEM;

The DEV_BROADCAST_OEM structure contains information about a OEM-defined device type.

Members

dbco_size

Size of this structure, in bytes.

dbco_devicetype

DBT_DEVTYPE_OEM.

dbco_reserved

Reserved; do not use.

dbco_identifier

Globally unique identifier (GUID) for the device. Use the uuidgen utility to create this identifier.

dbco_suppfunc

OEM-specific function value. Possible values depend on the device.


DEV_BROADCAST_PORT [New - Windows 95]
DEV_BROADCAST_PORT  QuickInfo  Overview  Group

[New - Windows 95]

typedef struct _DEV_BROADCAST_PORT {
    ULONG dbcp_size;

    ULONG dbcp_devicetype;

    ULONG dbcp_reserved;

    char dbcp_name[1];

} DEV_BROADCAST_PORT;
typedef DEV_BROADCAST_PORT *PDEV_BROADCAST_PORT;

The DEV_BROADCAST_PORT structure contains information about a modem, serial, or parallel port.

Members

dbcp_size

Size of this structure, in bytes.

dbcp_devicetype

DBT_DEVTYP_VOLUME.

dbcp_reserved

Reserved; do not use.

dbcp_name

Null-terminated string specifying the friendly name of the port or the device connected to the port. Friendly names are intended to help the user quickly and accurately identify the device—for example, "COM1", "Hayes 2400 Smartmodem", and "LPT1" are considered friendly names.


_DEV_BROADCAST_USERDEFINED
_DEV_BROADCAST_USERDEFINED  Overview  Group

struct _DEV_BROADCAST_USERDEFINED {
    struct _DEV_BROADCAST_HDR dbud_dbh;
    char  dbud_szName[1];           // ASCIIZ name
//    BYTE  dbud_rgbUserDefined[];  // Optional user-defined contents
};

The _DEV_BROADCAST_USERDEFINED structure contains the user-defined message and optional data associated with the DBT_USERDEFINED device message.

Members

dbud_dbh

Information about the device affected by a WM_DEVICECHANGE message as specified by the DEV_BROADCAST_HDR structure. Because the _DEV_BROADCAST_USERDEFINED structure is variable length, dbud_dbh.dbch_size must be the size in bytes of the entire structure, including the variable length part.

dbud_szName

A case-sensitive, null-terminated string that names the message. The name must consist of the vendor name, a backslash, followed by arbitrary user-defined null-terminated text. For example:

"WidgetWare\QueryScannerShutdown"

or

"WidgetWare\Video Q39S\AdapterReady"

dbud_rgbUserDefined

Optional user-defined information.

Because this structure contains variable length fields, use this structure tag as a template for creating a pointer to a user-defined structure. Note that the structure must not contain pointers. For example:

#define NAME_LENGTH 32

#define USER_LENGTH 50

typedef struct tagWIDGET_WARE_DEV_BROADCAST_USERDEFINED
{
    struct _DEV_BROADCAST_HDR DBHeader;
    char  szName[NAME_LENGTH]
    BYTE  UserDefined[USER_LENGTH];

} WIDGET_WARE_DEV_BROADCAST_USERDEFINED;

See Also

DBT_USERDEFINED, DEV_BROADCAST_HDR, WM_DEVICECHANGE


DEV_BROADCAST_VOLUME [New - Windows 95]
DEV_BROADCAST_VOLUME  QuickInfo  Overview  Group

[New - Windows 95]

typedef struct _DEV_BROADCAST_VOLUME {
    ULONG dbcv_size;

    ULONG dbcv_devicetype;

    ULONG dbcv_reserved;

    ULONG dbcv_unitmask;

    USHORT dbcv_flags;

} DEV_BROADCAST_VOLUME;
typedef DEV_BROADCAST_VOLUME *PDEV_BROADCAST_VOLUME;

The DEV_BROADCAST_VOLUME structure contains information about a logical volume.

Members

dbcv_size

Size of this structure, in bytes.

dbcv_devicetype

DBT_DEVTYP_VOLUME.

dbcv_reserved

Reserved; do not use.

dbcv_unitmask

Logical unit mask identifying one or more logical units. Each bit in the mask corresponds to one logical drive. Bit 0 represents drive A, bit 1 drive B, and so on.

dbcv_flags

Flags indicating whether drive or media.

Value	Meaning
DBTF_MEDIA	Change affects media in drive. If not set, change affects physical device or drive.
DBTF_NET	Indicated logical volume is a network volume.
Remarks

Although the dbcv_unitmask member may specify more than one volume in any given message, this does not guarantee that only message is generated for a given event. Multiple system components may independently generate messages for logical volumes at the same time.


DEVMODE
DEVMODE  QuickInfo

typedef struct _devicemode {    // dvmd

    BCHAR  dmDeviceName[CCHDEVICENAME];

    WORD   dmSpecVersion;

    WORD   dmDriverVersion;

    WORD   dmSize;

    WORD   dmDriverExtra;

    DWORD  dmFields;

    short  dmOrientation;

    short  dmPaperSize;

    short  dmPaperLength;

    short  dmPaperWidth;

    short  dmScale;

    short  dmCopies;

    short  dmDefaultSource;

    short  dmPrintQuality;

    short  dmColor;

    short  dmDuplex;

    short  dmYResolution;

    short  dmTTOption;

    short  dmCollate;

    BCHAR  dmFormName[CCHFORMNAME];

    WORD  dmLogPixels;

    DWORD  dmBitsPerPel;

    DWORD  dmPelsWidth;

    DWORD  dmPelsHeight;

    DWORD  dmDisplayFlags;

    DWORD  dmDisplayFrequency;

#if(WINVER >= 0x0400)

    DWORD  dmICMMethod;         // Windows 95 only

    DWORD  dmICMIntent;         // Windows 95 only

    DWORD  dmMediaType;         // Windows 95 only

    DWORD  dmDitherType;        // Windows 95 only

    DWORD  dmReserved1;         // Windows 95 only

    DWORD  dmReserved2;         // Windows 95 only

#endif /* WINVER >= 0x0400 */

} DEVMODE;

The DEVMODE data structure contains information about the device initialization and environment of a printer.

Members

dmDeviceName

Specifies the the "friendly" name of the printer; for example, "PCL/HP LaserJet" in the case of PCL/HP LaserJet®. This string is unique among device drivers. Note that this name may be truncated to fit in the dmDeviceName array.

dmSpecVersion

Specifies the version number of the initialization data specification on which the structure is based.

dmDriverVersion

Specifies the printer driver version number assigned by the printer driver developer.

dmSize

Specifies the size, in bytes, of the DEVMODE structure, not including any private driver-specific data that might follow the structure's public members. You can use this member to determine the number of bytes of public data regardless of the version of the DEVMODE structure being used.

dmDriverExtra

Contains the number of bytes of private driver-data that follow this structure. If a device driver does not use device-specific information, set this member to zero.

dmFields

A set of bit flags that specify whether certain members of the DEVMODE structure have been initialized. If a field is initialized, its corresponding bit flag is set, otherwise the bit flag is clear.  A printer driver supports only those DEVMODE structure members that are appropriate for the printer technology.

The following bit flags are defined, and are listed here with the corresponding structure members:

Value	Structure Member
DM_ORIENTATION	dmOrientation
DM_PAPERSIZE	dmPaperSize
DM_PAPERLENGTH	dmPaperLength
DM_PAPERWIDTH	dmPaperWidth
DM_SCALE	dmScale
DM_COPIES	dmCopies
DM_DEFAULTSOURCE	dmDefaultSource
DM_PRINTQUALITY	dmPrintQuality
DM_COLOR	dmColor
DM_DUPLEX	dmDuplex
DM_YRESOLUTION	dmYResolution
DM_TTOPTION	dmTTOption
DM_COLLATE	dmCollate
DM_FORMNAME	dmFormName
DM_LOGPIXELS	dmLogPixels
DM_BITSPERPEL	dmBitsPerPel
DM_PELSWIDTH	dmPelsWidth
DM_PELSHEIGHT	dmPelsHeight
DM_DISPLAYFLAGS	dmDisplayFlags
DM_DISPLAYFREQUENCY	dmDisplayFrequency
DM_ICMMETHOD	Windows 95 only: dmICMMethod
DM_ICMINTENT	Windows 95 only: dmICMIntent
DM_MEDIATYPE	Windows 95 only: dmMediaType
DM_DITHERTYPE	Windows 95 only: dmDitherType
dmOrientation

Selects the orientation of the paper. This member can be either DMORIENT_PORTRAIT (1) or DMORIENT_LANDSCAPE (2).

dmPaperSize

Selects the size of the paper to print on. This member can be set to zero if the length and width of the paper are both set by the dmPaperLength and dmPaperWidth members. Otherwise, the dmPaperSize member can be set to one of the following predefined values:

Value	Meaning
DMPAPER_LETTER	Letter, 8 1/2- by 11-inches
DMPAPER_LEGAL	Legal, 8 1/2- by 14-inches
DMPAPER_A4	A4 Sheet, 210- by 297-millimeters
DMPAPER_CSHEET	C Sheet, 17- by 22-inches
DMPAPER_DSHEET	D Sheet, 22- by 34-inches
DMPAPER_ESHEET	E Sheet, 34- by 44-inches
DMPAPER_LETTERSMALL	Letter Small, 8 1/2- by 11-inches
DMPAPER_TABLOID	Tabloid, 11- by 17-inches
DMPAPER_LEDGER	Ledger, 17- by 11-inches
DMPAPER_STATEMENT	Statement, 5 1/2- by 8 1/2-inches
DMPAPER_EXECUTIVE	Executive, 7 1/4- by 10 1/2-inches
DMPAPER_A3	A3 sheet, 297- by 420-millimeters
DMPAPER_A4SMALL	A4 small sheet, 210- by 297-millimeters
DMPAPER_A5	A5 sheet, 148- by 210-millimeters
DMPAPER_B4	B4 sheet, 250- by 354-millimeters
DMPAPER_B5	B5 sheet, 182- by 257-millimeter paper
DMPAPER_FOLIO	Folio, 8 1/2- by 13-inch paper
DMPAPER_QUARTO	Quarto, 215- by 275-millimeter paper
DMPAPER_10X14	10- by 14-inch sheet
DMPAPER_11X17	11- by 17-inch sheet
DMPAPER_NOTE	Note, 8 1/2- by 11-inches
DMPAPER_ENV_9	#9 Envelope, 3 7/8- by 8 7/8-inches
DMPAPER_ENV_10	#10 Envelope, 4 1/8- by 9 1/2-inches
DMPAPER_ENV_11	#11 Envelope, 4 1/2- by 10 3/8-inches
DMPAPER_ENV_12	#12 Envelope, 4 3/4- by 11-inches
DMPAPER_ENV_14	#14 Envelope, 5- by 11 1/2-inches
DMPAPER_ENV_DL	DL Envelope, 110- by 220-millimeters
DMPAPER_ENV_C5	C5 Envelope, 162- by 229-millimeters
DMPAPER_ENV_C3	C3 Envelope,  324- by 458-millimeters
DMPAPER_ENV_C4	C4 Envelope,  229- by 324-millimeters
DMPAPER_ENV_C6	C6 Envelope,  114- by 162-millimeters
DMPAPER_ENV_C65	C65 Envelope, 114- by 229-millimeters
DMPAPER_ENV_B4	B4 Envelope,  250- by 353-millimeters
DMPAPER_ENV_B5	B5 Envelope,  176- by 250-millimeters
DMPAPER_ENV_B6	B6 Envelope,  176- by 125-millimeters
DMPAPER_ENV_ITALY	Italy Envelope, 110- by 230-millimeters
DMPAPER_ENV_MONARCH	Monarch Envelope, 3 7/8- by 7 1/2-inches
DMPAPER_ENV_PERSONAL	6 3/4 Envelope, 3 5/8- by 6 1/2-inches
DMPAPER_FANFOLD_US	US Std Fanfold, 14 7/8- by 11-inches
DMPAPER_FANFOLD_STD_GERMAN	German Std Fanfold, 8 1/2- by 12-inches
DMPAPER_FANFOLD_LGL_GERMAN	German Legal Fanfold, 8 1/2- by 13-inches
dmPaperLength

Overrides the length of the paper specified by the dmPaperSize member, either for custom paper sizes or for devices such as dot-matrix printers, which can print on a page of arbitrary length. These values, along with all other values in this structure that specify a physical length, are in tenths of a millimeter.

dmPaperWidth

Overrides the width of the paper specified by the dmPaperSize member.

dmScale

Specifies the factor by which the printed output is to be scaled. The apparent page size is scaled from the physical page size by a factor of dmScale/100. For example, a letter-sized page with a dmScale value of 50 would contain as much data as a page of 17- by 22-inches because the output text and graphics would be half their original height and width.

dmCopies

Selects the number of copies printed if the device supports multiple-page copies.

dmDefaultSource

Reserved; must be zero.

dmPrintQuality

Specifies the printer resolution. There are four predefined device-independent values:

DMRES_HIGH
DMRES_MEDIUM
DMRES_LOW
DMRES_DRAFT

If a positive value is given, it specifies the number of dots per inch (DPI) and is therefore device dependent.

dmColor

Switches between color and monochrome on color printers. Following are the possible values:

DMCOLOR_COLOR
DMCOLOR_MONOCHROME

dmDuplex

Selects duplex or double-sided printing for printers capable of duplex printing. Following are the possible values:

DMDUP_SIMPLEX
DMDUP_HORIZONTAL
DMDUP_VERTICAL

dmYResolution

Specifies the y-resolution, in dots per inch, of the printer. If the printer initializes this member, the dmPrintQuality member specifies the x-resolution, in dots per inch, of the printer.

dmTTOption

Specifies how TrueType® fonts should be printed. This member can be one of the following values:

Value	Meaning
DMTT_BITMAP	Prints TrueType fonts as graphics. This is the default action for dot-matrix printers.
DMTT_DOWNLOAD	Downloads TrueType fonts as soft fonts. This is the default action for Hewlett-Packard printers that use Printer Control Language (PCL).
DMTT_SUBDEV	Substitute device fonts for TrueType fonts. This is the default action for PostScript® printers.
dmUnusedPadding

Used to align the structure to a DWORD boundary. This should not be used or referenced. Its name and usage is reserved, and can change in future releases.

dmCollate

Specifies whether collation should be used when printing multiple copies. (This member is ignored unless the printer driver indicates support for collation by setting the dmFields member to DM_COLLATE.) This member can be be one of the following values:

Value	Meaning
DMCOLLATE_TRUE	Collate when printing multiple copies.
DMCOLLATE_FALSE	Do not collate when printing multiple copies.
Using DMCOLLATE_TRUE provides faster, more efficient output for collation, since the data is sent to the device driver just once, no matter how many copies are required. The printer is told to simply print the page again.

dmFormName

Windows NT: Specifies the name of the form to use; for example, "Letter" or "Legal". A complete set of names can be retrieved by using the EnumForms function.

Windows 95: Printer drivers do not use this member.

dmLogPixels

Specifies the number of pixels per logical inch.

dmBitsPerPel

Windows NT: Specifies the color resolution, in bits per pixel, of the display device (for example: 4 bits for 16 colors, 8 bits for 256 colors, or 16 bits for 65536 colors).

Windows 95: Display drivers use this member, for example, in the ChangeDisplaySettings function. Printer drivers do not use this member.

dmPelsWidth

Windows NT: Specifies the width, in pixels, of the visible device surface.

Windows 95: Display drivers use this member, for example, in the ChangeDisplaySettings function. Printer drivers do not use this member.

dmPelsHeight

Windows NT: Specifies the height, in pixels, of the visible device surface.

Windows 95: Display drivers use this member, for example, in the ChangeDisplaySettings function. Printer drivers do not use this member.

dmDisplayFlags

Windows NT: Specifies the device's display mode. This member can be one of the following values:

Value	Meaning
DM_GRAYSCALE	Specifies that the display is a NON-color device. If this flag is not set, color is assumed.
DM_INTERLACED	Specifies that the display mode is interlaced. If the flag is not set, NON-interlaced is assumed.
Windows 95: Display drivers use this member, for example, in the ChangeDisplaySettings function. Printer drivers do not use this member.

dmDisplayFrequency

Windows NT: Specifies the frequency, in hertz (cycles per second), of the display device in a particular mode.

Windows 95: Display drivers use this member, for example, in the ChangeDisplaySettings function. Printer drivers do not use this member.

dmICMMethod

Windows 95

Specifies how ICM is handled. For a non-ICM application, this member determines if ICM is enabled or disabled. For ICM applications, Windows examines this member to determine how to handle ICM support. This member can be one of the following predefined values, or a driver-defined value greater than the value of DMICMMETHOD_USER:

Value	Meaning
DMICMMETHOD_NONE	Windows 95 only: Specifies that ICM is disabled.
DMICMMETHOD_SYSTEM	Windows 95 only: Specifies that ICM is handled by Windows.
DMICMMETHOD_DRIVER	Windows 95 only: Specifies that ICM is handled by the device driver.
DMICMMETHOD_DEVICE	Windows 95 only: Specifies that ICM is handled by the destination device.
The printer driver must provide a user interface for setting this member. Most printer drivers support only the DMICMMETHOD_SYSTEM or DMICMMETHOD_NONE value. Drivers for PostScript printers support all values.

Windows NT

This member is not supported on Windows NT.

dmICMIntent

Windows 95

Specifies which of the three possible color matching methods, or intents, should be used by default. This member is primarily for non-ICM applications. ICM applications can establish intents by using the ICM functions. This member can be one of the following predefined values, or a driver defined value greater than the value of DMICM_USER:

Value	Meaning
DMICM_SATURATE	Windows 95 only: Color matching should optimize for color saturation. This value is the most appropriate choice for business graphs when dithering is not desired.
DMICM_CONTRAST	Windows 95 only: Color matching should optimize for color contrast. This value is the most appropriate choice for scanned or photographic images when dithering is desired.
DMICM_COLORMETRIC	Windows 95 only: Color matching should optimize to match the exact color requested. This value is most appropriate for use with business logos or other images when an exact color match is desired.
Windows NT

This member is not supported on Windows NT.

dmMediaType

Windows 95

Specifies the type of media being printed on. The member can be one of the following predefined values, or a driver-defined value greater than the value of DMMEDIA_USER:

Value	Meaning
DMMEDIA_STANDARD	Windows 95 only: Plain paper.
DMMEDIA_GLOSSY	Windows 95 only: Glossy paper.
DMMEDIA_TRANSPARENCY	Windows 95 only: Transparent film.
Windows NT

This member is not supported on Windows NT.

dmDitherType

Windows 95

Specifies how dithering is to be done. The member can be one of the following predefined values, or a driver-defined value greater than the value of DMDITHER_USER:

Value	Meaning
DMDITHER_NONE	Windows 95 only: No dithering.
DMDITHER_COARSE	Windows 95 only: Dithering with a coarse brush.
DMDITHER_FINE	Windows 95 only: Dithering with a fine brush.
DMDITHER_LINEART	Windows 95 only: Line art dithering, a special dithering method that produces well defined borders between black, white, and gray scalings. It is not suitable for images that include continuous graduations in intensisty and hue such as scanned photographs.
DMDITHER_GRAYSCALE	Windows 95 only: Device does grayscaling.
Windows NT

This member is not supported on Windows NT.

dmReserved1

Windows 95

Not used; must be zero.

Windows NT

This member is not supported on Windows NT.

dmReserved2

Windows 95

Not used; must be zero.

Windows NT

This member is not supported on Windows NT.

Remarks

A device driver's private data follows the public portion of the DEVMODE structure. The size of the public data can vary for different versions of the structure. The dmSize member specifies the number of bytes of public data, and the dmDriverExtra member specifies the number of bytes of private data.

See Also

AdvancedDocumentProperties, CreateDC, CreateIC, DeviceCapabilities, DocumentProperties, OpenPrinter


DEVNAMES
DEVNAMES  QuickInfo

typedef struct tagDEVNAMES { // dvnm

    WORD wDriverOffset;

    WORD wDeviceOffset;

    WORD wOutputOffset;

    WORD wDefault;

    // driver, device, and port name strings follow wDefault

} DEVNAMES;

The DEVNAMES structure contains strings that identify the driver, device, and output port names for a printer. The PrintDlg function uses these strings to initialize members in the system-defined Print dialog box. When the user closes the dialog box, information about the selected printer is returned in this structure.

Members

wDriverOffset

(Input/Output) Specifies the offset in characters from the beginning of this structure to a null-terminated string that contains the filename (without the extension) of the device driver. On input, this string is used to determine the printer to display initially in the dialog box.

wDeviceOffset

(Input/Output) Specifies the offset in characters from the beginning of this structure to the null-terminated string (maximum of 32 bytes including the null) that contains the name of the device. This string must be identical to the dmDeviceName member of the DEVMODE structure.

wOutputOffset

(Input/Output) Specifies the offset in characters from the beginning of this structure to the null-terminated string that contains the device name for the physical output medium (output port).

wDefault

Specifies whether the strings contained in the DEVNAMES structure identify the default printer. This string is used to verify that the default printer has not changed since the last print operation. If any of the strings do not match, a warning message is displayed informing the user that the document may need to be reformatted.

On output, the wDefault member is changed only if the Print Setup dialog box was displayed and the user chose the OK button. The DN_DEFAULTPRN flag is used if the default printer was selected. If a specific printer is selected, the flag is not used. All other flags in this member are reserved for internal use by the Print Dialog box procedure.

See Also

DEVMODE, PrintDlg


DIBSECTION
DIBSECTION  QuickInfo

typedef struct tagDIBSECTION {

    BITMAP              dsBm;

    BITMAPINFOHEADER    dsBmih;

    DWORD               dsBitfields[3];

    HANDLE              dshSection;

    DWORD               dsOffset;

} DIBSECTION;

The DIBSECTION structure contains information about a device-independent bitmap created by calling the CreateDIBSection function. A DIBSECTION structure includes information about the bitmap's dimensions, color format, color masks, optional file mapping object, and optional bit values storage offset. An application can obtain a filled-in DIBSECTION structure for a given device-independent bitmap by calling the GetObject function.

Members

dsBm

A BITMAP data structure that contains information about the device-independent bitmap: its type, its dimensions, its color capacities, and a pointer to its bit values.

dsBmih

A BITMAPINFOHEADER data structure that contains information about the color format of the device-independent bitmap.

dsBitfields

Specifies three DWORD color masks for the device-independent bitmap. This field is only valid when the biBitCount member of the BITMAPINFOHEADER structure has a value greater than 8. Each color mask indicates the bits within a bit value doubleword that are used to encode one of the three color channels (red, green, and blue).

dshSection

Contains a handle to the file mapping object that the CreateDIBSection function used to create the device-independent bitmap. If CreateDIBSection was called with a NULL value for its hSection parameter, causing the operating system to allocate memory for the bitmap, the dshSection member will be NULL.

dsOffset

Specifies the offset to the bitmap's bit values within the file mapping object referenced by dshSection. If dshSection is NULL, the dsOffset value has no meaning.

See Also

BITMAP, BITMAPINFOHEADER, CreateDIBSection, GetDIBColorTable, GetObject


DISK_GEOMETRY
DISK_GEOMETRY  QuickInfo  Overview  Group

typedef struct _DISK_GEOMETRY {

   LARGE_INTEGER  Cylinders;

   MEDIA_TYPE  MediaType;

   DWORD  TracksPerCylinder;

   DWORD  SectorsPerTrack;

   DWORD  BytesPerSector;

} DISK_GEOMETRY ;

The DISK_GEOMETRY structure describes the geometry of disk devices and media.

Members

Cylinders

The number of cylinders.

MediaType

The type of media. See MEDIA_TYPE.

TracksPerCylinder

The number of tracks per cylinder.

SectorsPerTrack

The number of sectors per track.

BytesPerSector

The number of bytes per sector

Remarks

The DeviceIoControl function receives a DISK_GEOMETRY structure in response to an IOCTL_DISK_GET_DRIVE_GEOMETRY device input and output contol (IOCTL) operation. The DeviceIoControl function receives an array of DISK_GEOMETRY structures in response to an IOCTL_DISK_GET_MEDIA_TYPES device I/O operation.

See Also

DeviceIoControl, IOCTL_DISK_GET_DRIVE_GEOMETRY, IOCTL_DISK_GET_MEDIA_TYPES, MEDIA_TYPE


DISK_PERFORMANCE
DISK_PERFORMANCE  QuickInfo  Overview  Group

typedef struct _DISK_PERFORMANCE {

        LARGE_INTEGER BytesRead;

        LARGE_INTEGER BytesWritten;

        LARGE_INTEGER ReadTime;

        LARGE_INTEGER WriteTime;

        DWORD ReadCount;

        DWORD WriteCount;

        DWORD QueueDepth;

} DISK_PERFORMANCE ;

The DISK_PERFORMANCE structure provides disk performance information.

Members

BytesRead

Specifies the number of bytes read.

BytesWritten

Specifies the number of bytes written.

ReadTime

Specifies the time it took to complete the read.

WriteTime

Specifies the time it took to complete the write.

ReadCount

Specifies the number of read operations.

WriteCount

Specifies the number of write operations.

QueueDepth

Specifies the depth of the queue.

Remarks

The DeviceIoControl function receives a DISK_PERFORMANCE structure in response to an IOCTL_DISK_PERFORMANCE device I/O operation.

See Also

DeviceIoControl, IOCTL_DISK_PERFORMANCE


DLGITEMTEMPLATE
DLGITEMTEMPLATE  QuickInfo  Overview  Group

typedef struct { // dlit

    DWORD style;

    DWORD dwExtendedStyle;

    short x;

    short y;

    short cx;

    short cy;

    WORD  id;

} DLGITEMTEMPLATE;

The DLGITEMTEMPLATE structure defines the dimensions and style of a control in a dialog box. One or more of these structures are combined with a DLGTEMPLATE structure to form a dialog box template.

Members

style

Specifies the style of the control. This member can be a combination of window style values (such as WS_BORDER) and one or more of the control style values (such as BS_PUSHBUTTON and ES_LEFT).

dwExtendedStyle

Specifies extended styles for a window. This member is not used to create controls in dialog boxes, but applications that use dialog box templates can use it to create other types of windows.

x

Specifies the x-coordinate, in dialog box units, of the upper-left corner of the control. This coordinate is always relative to the upper-left corner of the dialog box's client area.

y

Specifies the y-coordinate, in dialog box units, of the upper-left corner of the control. This coordinate is always relative to the upper-left corner of the dialog box's client area.

cx

Specifies the width, in dialog box units, of the control.

cy

Specifies the height, in dialog box units, of the control.

id

Specifies the control identifier.

Remarks

In a dialog box template, the DLGITEMTEMPLATE structure is always immediately followed by three variable-length arrays specifying the class, title, and creation data for the control. Each array consists of one or more 16-bit elements.

The class array follows the DLGITEMTEMPLATE structure. When the first element of this array is 0xFFFF, the array has one additional element that specifies an atom value identifying a registered window class. When the first element has any other value, Windows assumes the array is a null-terminated Unicode string that specifies the name of a registered window class. Following are the class atom values for predefined controls:

Value	Meaning
0x0080	Button
0x0081	Edit
0x0082	Static
0x0083	List box
0x0084	Scroll bar
0x0085	Combo box
The title array follows the class array. When the first element is 0xFFFF, the array has one additional element that specifies the identifier of a resource, such as an icon, in an executable file. Resource identifiers are usually given for controls, such as static icon controls, that load and display an icon or other resources rather than text. When the first element is any other value, Windows assumes the array is a null-terminated Unicode string that specifies the initial text for the control.

The creation data array follows the text array. This array can contain any number of elements; the control's window procedure must understand the content and format of the data. Windows passes this data to the control when it calls the CreateWindowEx function.

The x, y, cx, and cy members specify values in dialog box units. You can convert these values to screen units (pixels) by using the MapDialogRect function.

See Also

CreateDialogIndirect, CreateDialogIndirectParam, CreateWindowEx, DialogBoxIndirect, DialogBoxIndirectParam, MapDialogRect


DLGTEMPLATE
DLGTEMPLATE  QuickInfo  Overview  Group

typedef struct { // dltt

    DWORD style;

    DWORD dwExtendedStyle;

    WORD  cdit;

    short x;

    short y;

    short cx;

    short cy;

} DLGTEMPLATE;

The DLGTEMPLATE structure defines the dimensions and style of a dialog box. This structure, always the first in a dialog box template, also specifies the number of controls in the dialog box and therefore specifies the number of subsequent DLGITEMTEMPLATE structures in the template.

Members

style

Specifies the style of the dialog box. This member can be a combination of window style values (such as WS_CAPTION and WS_SYSMENU) and one or more of the following dialog box style values:

Value	Meaning
DS_3DLOOK	Windows 95 only: Gives the dialog box a non-bold font and draws three dimensional borders around control windows in the dialog box.  The DS_3DLOOK style is not required by Win32-based applications that are marked with version number 4.0 or greater; the system automatically applies the three dimensional look to dialog boxes created by these applications.
DS_ABSALIGN	Indicates that the coordinates of the dialog box are screen coordinates. If this style is not specified, Windows assumes they are client coordinates.
DS_CENTER	Windows 95 only: Centers the dialog box in the working area; that is, the area not obscured by the tray.
DS_CENTERMOUSE	Windows 95 only: Centers the mouse cursor in the dialog box.
DS_CONTEXTHELP	Includes a question mark in the title bar of the dialog box. When the user clicks the question mark, the cursor changes to a question mark with a pointer. If the user then clicks a control in the dialog box the control receives a WM_HELP message. The control should pass the message to the dialog procedure, which should call the WinHelp function using the HELP_WM_HELP command. The Help application displays a pop-up window that typically contains help for the control.  Note that DS_CONTEXTHELP is just a placeholder. When the dialog box is created, the system checks for DS_CONTEXTHELP and, if it is there, adds WS_EX_CONTEXTHELP to the extended style of the dialog box.
DS_CONTROL	Creates a dialog gox that works well as a child window of another dialog box, much like a page in a property sheet. This style allows the user to tab among the control windows of a child dialog box, use its accelerator keys, and so on.
DS_FIXEDSYS	Windows 95 only: Use SYSTEM_FIXED_FONT instead of SYSTEM_FONT.
DS_LOCALEDIT	Applies to 16-bit applications only. This style directs edit controls in the dialog box to allocate memory from the application's data segment. Otherwise, edit controls allocate storage from a global memory object.
DS_MODALFRAME	Creates a dialog box with a modal dialog-box frame that can be combined with a title bar and System menu by specifying the WS_CAPTION and WS_SYSMENU styles.
DS_NOFAILCREATE	Windows 95 only: Creates the dialog even if errors occur — for example, if a child window cannot be created or if the system cannot create a special data segment for an edit control.
DS_NOIDLEMSG	Suppresses WM_ENTERIDLE messages that Windows would otherwise send to the owner of the dialog box while the dialog box is displayed.
DS_SETFONT	Indicates that the dialog box template (the DLGTEMPLATE structure) contains two additional members specifying a font name and point size. The corresponding font is used to display text within the dialog box client area and within the dialog box controls. Windows passes the handle of the font to the dialog box and to each control by sending them the WM_SETFONT message.
DS_SETFOREGROUND	This style brings the dialog box to the foreground. Internally, Windows calls the SetForegroundWindow function for the dialog box.
DS_SYSMODAL	Creates a system-modal dialog box. This style causes the dialog box to have the WS_EX_TOPMOST style, but otherwise has no effect on the dialog box or the behavior of other windows in the system when the dialog box is displayed.
dwExtendedStyle

Specifies extended styles for a window. This member is not used to create dialog boxes, but applications that use dialog box templates can use it to create other types of windows.

cdit

Specifies the number of items in the dialog box.

x

Specifies the x-coordinate, in dialog box units, of the upper-left corner of the dialog box.

y

Specifies the y-coordinate, in dialog box units, of the upper-left corner of the dialog box.

cx

Specifies the width, in dialog box units, of the dialog box.

cy

Specifies the height, in dialog box units, of the dialog box.

Remarks

In a dialog box template, the DLGTEMPLATE structure is always immediately followed by three variable-length arrays that specify the menu, class, and title for the dialog box. When the DS_SETFONT style is given, these arrays are also followed by a 16-bit value specifying point size and another variable-length array specifying a typeface name. Each array consists of one or more 16-bit elements.

The menu array follows the DLGTEMPLATE structure. When the first element of this array is 0x0000, the dialog box has no menu and the array has no other elements. When the first element is 0xFFFF, the array has one additional element that specifies the resource identifier for a menu resource in an executable file. If the first element has any other value, Windows assumes the array is a null-terminated Unicode string that specifies the name of the menu resource in an executable file.

The class array follows the menu array. When the first element of the array is 0x0000, Windows uses the predefined dialog box class for the dialog box. When the first element is 0xFFFF, the array has one additional element that specifies the atom value identifying a registered window class. When the first element has any other value, Windows assumes the array is a null-terminated Unicode string that specifies the name of a registered window class.

The title array follows the class array. When the first element of the array is 0x0000, the dialog box has no title. When the first element has any other value, Windows assumes the array is a null-terminated Unicode string that specifies the title.

The 16-bit point size value and the typeface array follow the title array, but only if the style member gives the DS_SETFONT style. The point size value specifies the point size of the font to use for the text in the dialog box and its controls. The typeface array is a null-terminated Unicode string specifying the name of the typeface for the font. When these values are given, Windows creates a font having the given size and typeface (if possible) and sends a WM_SETFONT message to the dialog box procedure and the control window procedures as it creates the dialog box and controls.

Every dialog box template also contains the number of DLGITEMTEMPLATE structures as given by the cdit member. These structures define the dimensions and style of the controls in the dialog box.

The x, y, cx, and cy members specify values in dialog box units. You can convert these values to screen units (pixels) by using the MapDialogRect function.

See Also

CreateDialogIndirect, CreateDialogIndirectParam, DialogBoxIndirect, DialogBoxIndirectParam, MapDialogRect


DOC_INFO_1
DOC_INFO_1  QuickInfo

typedef struct _DOC_INFO_1 { // dci1

    LPTSTR pDocName;

    LPTSTR pOutputFile;

    LPTSTR pDatatype;

} DOC_INFO_1;

The DOC_INFO_1 structure describes a document that will be printed.

Members

pDocName

Points to a null-terminated string that specifies the name of the document.

pOutputFile

Points to a null-terminated string that specifies the name of an output file.

pDatatype

Points to a null-terminated string that identifies the type of data used to record the document.

See Also

StartDocPrinter


DOC_INFO_2 [New - Windows 95]
DOC_INFO_2  QuickInfo

[New - Windows 95]

typedef struct _DOC_INFO_2 { // dci2

    LPTSTR pDocName;

    LPTSTR pOutputFile;

    LPTSTR pDatatype;

    DWORD  dwMode;

    DWORD  JobId;

} DOC_INFO_2;

The DOC_INFO_2 structure describes a document that will be printed.

Members

pDocName

Points to a null-terminated string that specifies the name of the document.

pOutputFile

Points to a null-terminated string that specifies the name of an output file.

pDatatype

Points to a null-terminated string that identifies the type of data used to record the document.

dwMode

Informs the print spooler of the nature of the data to follow. If this value is zero, the print spooler treats the data sent by subsequent calls to WritePrinter as a normal print job (whether or not it is spooled depends on the printer property). If this value is DI_CHANNEL, only a communications channel is opened. In this case, the data passed into subsequent calls to WritePrinter is sent to the printer or subsequent calls to ReadPrinter retrieve data from the printer. This mode remains effective until EndDoc is called.

JobId

Reserved for internal use; should be zero.

See Also

EndDoc, ReadPrinter, StartDocPrinter, WritePrinter


DOCINFO
DOCINFO  QuickInfo

typedef struct {    // di

    int     cbSize;

    LPCTSTR lpszDocName;

    LPCTSTR lpszOutput;

    LPCTSTR lpszDatatype;   // Windows 95 only; ignored on Windows NT

    DWORD   fwType;         // Windows 95 only; ignored on Windows NT

} DOCINFO;

The DOCINFO structure contains the input and output filenames and other information used by the StartDoc function.

Members

cbSize

Specifies the size, in bytes, of the structure.

lpszDocName

Points to a null-terminated string that specifies the name of the document.

lpszOutput

Points to a null-terminated string that specifies the name of an output file. If this pointer is NULL, the output will be sent to the device identified by the device context handle that was passed to the StartDoc function.

lpszDatatype

Windows 95:

Points to a null-terminated string that specifies the type of data used to record the print job.

Windows NT:

This member is ignored.

fwType

Windows 95:

Specifies additional information about the print job. Can be zero or DI_APPBANDING if the application will use banding. For optimal performance during printing, banding applications should specify DI_APPBANDING.

Windows NT:

This member is ignored.

See Also

StartDoc


DRAGLISTINFO [New - Windows NT]
DRAGLISTINFO  QuickInfo  Overview  Group

[New - Windows NT]

Typedef struct {

    UINT uNotification;

    HWND hWnd;

    POINT ptCursor;

} DRAGLISTINFO, FAR *LPDRAGLISTINFO;

The DRAGLISTINFO structure contains information about a drag event. The pointer to DRAGLISTINFO is passed as the lParam parameter of the drag list message.

Members

uNotification

Notification code that specifies the type of drag event. This member can be one of the following values:

Value	Meaning
DL_BEGINDRAG	The user has clicked the left mouse button on a list item.
DL_CANCELDRAG	The user has canceled the drag operation by clicking the right mouse button or pressing the ESC key.
DL_DRAGGING	The user has moved the mouse while dragging an item.
DL_DROPPED	The user has released the left mouse button, completing a drag operation.
hWnd

Handle to drag list box.

ptCursor

POINT structure that contains the current x- and y-coordinates of the mouse cursor.

See also

DL_BEGINDRAG, DL_CANCELDRAG, DL_DRAGGING, DL_DROPPED, POINT


DRAWITEMSTRUCT
DRAWITEMSTRUCT  QuickInfo

typedef struct tagDRAWITEMSTRUCT {  // dis

    UINT  CtlType;

    UINT  CtlID;

    UINT  itemID;

    UINT  itemAction;

    UINT  itemState;

    HWND  hwndItem;

    HDC   hDC;

    RECT  rcItem;

    DWORD itemData;

} DRAWITEMSTRUCT;

The DRAWITEMSTRUCT structure provides information the owner window must have to determine how to paint an owner-drawn control or menu item. The owner window of the owner-drawn control or menu item receives a pointer to this structure as the lParam parameter of the WM_DRAWITEM message.

Members

CtlType

Specifies the control type. This member can be one of the following values:

Value	Meaning
ODT_BUTTON	Owner-drawn button
ODT_COMBOBOX	Owner-drawn combo box
ODT_LISTBOX	Owner-drawn list box
ODT_LISTVIEW	List view control
ODT_MENU	Owner-drawn menu item
ODT_STATIC	Owner-drawn static control
ODT_TAB	Tab control
CtlID

Specifies the identifier of the combo box, list box, button, or static control. This member is not used for a menu item.

itemID

Specifies the menu item identifier for a menu item or the index of the item in a list box or combo box. For an empty list box or combo box, this member can be −1. This allows the application to draw only the focus rectangle at the coordinates specified by the rcItem member even though there are no items in the control. This indicates to the user whether the list box or combo box has the focus. How the bits are set in the itemAction member determines whether the rectangle is to be drawn as though the list box or combo box has the focus.

itemAction

Specifies the drawing action required. This member can be one or more of the following values:

Value	Meaning
ODA_DRAWENTIRE	The entire control needs to be drawn.
ODA_FOCUS	The control has lost or gained the keyboard focus. The itemState member should be checked to determine whether the control has the focus.
ODA_SELECT	The selection status has changed. The itemState member should be checked to determine the new selection state.
itemState

Specifies the visual state of the item after the current drawing action takes place. This member can be a combination of the following values:

Value	Meaning
ODS_CHECKED	The menu item is to be checked. This bit is used only in a menu.
ODS_COMBOBOXEDIT	The drawing takes place in the selection field (edit control) of an ownerdrawn combo box.
ODS_DEFAULT	The item is the default item.
ODS_DISABLED	The item is to be drawn as disabled.
ODS_FOCUS	The item has the keyboard focus.
ODS_GRAYED	The item is to be grayed. This bit is used only in a menu.
ODS_SELECTED	The menu item's status is selected.
hwndItem

Identifies the control for combo boxes, list boxes, buttons, and static controls. For menus, this member identifies the menu containing the item.

hDC

Identifies a device context; this device context must be used when performing drawing operations on the control.

rcItem

Specifies a rectangle that defines the boundaries of the control to be drawn. This rectangle is in the device context specified by the hDC member. Windows automatically clips anything the owner window draws in the device context for combo boxes, list boxes, and buttons, but does not clip menu items. When drawing menu items, the owner window must not draw outside the boundaries of the rectangle defined by the rcItem member.

itemData

Specifies the application-defined 32-bit value associated with the menu item. For a control, this parameter specifies the value last assigned to the list box or combo box by the LB_SETITEMDATA or CB_SETITEMDATA message. If the list box or combo box has the LBS_HASSTRINGS or CBS_HASSTRINGS style, this value is initially zero. Otherwise, this value is initially the value that was passed to the list box or combo box in the lParam parameter of one of the following messages:

CB_ADDSTRING
CB_INSERTSTRING
LB_ADDSTRING
LB_INSERTSTRING

If ctlType is ODT_BUTTON or ODT_STATIC, itemData is zero.

See Also

CB_ADDSTRING, CB_INSERTSTRING, CB_SETITEMDATA, LB_ADDSTRING, LB_INSERTSTRING, SETITEMDATA, WM_DRAWITEM


DRAWTEXTPARAMS [New - Windows 95]
DRAWTEXTPARAMS  QuickInfo

[New - Windows 95]

typedef struct {

    UINT cbSize;

    int  iTabLength;

    int  iLeftMargin;

    int  iRightMargin;

    UINT uiLengthDrawn;

} DRAWTEXTPARAMS, FAR *LPDRAWTEXTPARAMS;

The DRAWTEXTPARAMS structure contains extended formatting options for the DrawTextEx function.

Members

cbSize

Specifies the structure size, in bytes.

iTabLength

Specifies the size of each tab stop, in units equal to the average character width.

iLeftMargin

Specifies the left margin, in units equal to the average character width.

iRightMargin

Specifies the right margin, in units equal to the average character width.

uiLengthDrawn

Receives the number of characters processed by DrawTextEx, including white-space characters. The number can be the length of the string or the index of the first line that falls below the drawing area. Note that DrawTextEx always processes the entire string if the DT_NOCLIP formatting flag is specified.

See Also

DrawTextEx


DRIVE_LAYOUT_INFORMATION
DRIVE_LAYOUT_INFORMATION  QuickInfo  Overview  Group

typedef struct _DRIVE_LAYOUT_INFORMATION {

   DWORD  PartitionCount;

   DWORD  Signature;

   PARTITION_INFORMATION  PartitionEntry[1];

} DRIVE_LAYOUT_INFORMATION;

The DRIVE_LAYOUT_INFORMATION structure provides information about a drive's partitions.

Members

PartitionCount

The number of partitions on the drive.

Signature

A drive signature value.

PartitionEntry

A variable-sized array of PARTITION_INFORMATION structures, one structure for each partition on the drive.

Remarks

The DeviceIoControl function receives a DRIVE_LAYOUT_INFORMATION structure in response to an IOCTL_DISK_GET_DRIVE_LAYOUT device I/O operation. The DeviceIoControl function  uses a DRIVE_LAYOUT_INFORMATION structure as input to an IOCTL_DISK_SET_DRIVE_LAYOUT device I/O operation.

See Also

DeviceIoControl, IOCTL_DISK_GET_DRIVE_LAYOUT, IOCTL_DISK_SET_DRIVE_LAYOUT, PARTITION_INFORMATION


DRIVER_INFO_1
DRIVER_INFO_1  QuickInfo

typedef struct _DRIVER_INFO_1 { // dri1

    LPTSTR pName;

} DRIVER_INFO_1;

The DRIVER_INFO_1 structure identifies a printer driver.

Members

pName

Points to a null-terminated string that specifies the name of a printer driver.

See Also

EnumPrinterDrivers


DRIVER_INFO_2
DRIVER_INFO_2  QuickInfo

typedef struct _DRIVER_INFO_2 { // dri2

    DWORD  cVersion;

    LPTSTR pName;

    LPTSTR pEnvironment;

    LPTSTR pDriverPath;

    LPTSTR pDataFile;

    LPTSTR pConfigFile;

} DRIVER_INFO_2;

The DRIVER_INFO_2 structure identifies a printer driver, the driver version number, the environment for which the driver was written, the name of the file in which the driver is stored, and so on.

Members

cVersion

Specifies a printer-driver version number.

pName

Points to a null-terminated string that specifies the name of the driver (for example, "QMS 810").

pEnvironment

Points to a null-terminated string that specifies the environment for which the driver was written (for example, "Windows NT x86" or "Windows NT R4000").

pDriverPath

Points to null-terminated string that specifies a filename or full path and filename for the file that contains the device driver (for example, "c:\drivers\pscript.dll").

pDataFile

Points to a null-terminated string that specifies a filename or a full path and filename for the file that contains driver data (for example, "c:\drivers\QMS810.PPD").

pConfigFile

Points to a null-terminated string that specifies a filename or a full path and filename for the device-driver's configuration DLL (for example, "c:\drivers\PSCRPTUI.DLL").

See Also

AddPrinterDriver, GetPrinterDriver


DRIVER_INFO_3 [New - Windows 95]
DRIVER_INFO_3  QuickInfo

[New - Windows 95]

typedef struct _DRIVER_INFO_3 { // dri3

    DWORD  cVersion;

    LPTSTR pName;

    LPTSTR pEnvironment;

    LPTSTR pDriverPath;

    LPTSTR pDataFile;

    LPTSTR pConfigFile;

    LPTSTR pHelpFile;

    LPTSTR pDependentFiles;

    LPTSTR pMonitorName;

    LPTSTR pDefaultDataType;

} DRIVER_INFO_3;

The DRIVER_INFO_3 structure contains printer driver information.

Members

cVersion

Specifies a printer-driver version number.

pName

Points to a null-terminated string that specifies the name of the driver (for example, "QMS 810").

pEnvironment

Points to a null-terminated string that specifies the environment for which the driver was written (for example, "Windows x86" or "Windows NT R4000").

pDriverPath

Points to a null-terminated string that specifies a filename or full path and filename for the file that contains the device driver (for example, "C:\DRIVERS\PSCRIPT.DLL").

pDataFile

Points to a null-terminated string that specifies a filename or a full path and filename for the file that contains driver data (for example, "C:\DRIVERS\QMS810.PPD").

pConfigFile

Points to a null-terminated string that specifies a filename or a full path and filename for the device driver's configuration dynamic-link library (for example, "C:\DRIVERS\PSCRPTUI.DLL").

pHelpFile

Points to a null-terminated string that specifies a filename or a full path and filename for the device driver's help file.

pDependentFiles

Points to a null-terminated string that specifies the files the driver is dependent on. Each filename in the string is also terminated with a null (for example, "PSCRIPT.DLL\0QMS810.PPD\0PSCRPTUI.DLL\0PSPCRIPTUI.HLP\0PSTEST.TXT\0\0").

pMonitorName

Points to a null-terminated string that specifies a language monitor (for example, "PJL monitor"). This member can be NULL and should be specified only for printers capable of bidirectional communication.

pDefaultDataType

Points to a null-terminated string that specifies the default data type of the print job (for example, "EMF").

See Also

AddPrinterDriver, EnumPrinterDrivers, GetPrinterDriver


EDITSTREAM [New - Windows NT]
EDITSTREAM  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct _editstream {

    DWORD dwCookie;

    DWORD dwError;

    EDITSTREAMCALLBACK pfnCallback;

} EDITSTREAM;

The EDITSTREAM structure contains information about a data stream used with a rich edit control.

Members

dwCookie

Application-defined value that is passed to the callback function.

dwError

Error encountered while streaming. If there was no error, this member is zero.

pfnCallback

Pointer to an application-defined function that the control calls to transfer data.

This structure is used with the EM_STREAMIN message to read (stream in) data into a rich edit control, replacing its contents. It is used with the EM_STREAMOUT message to write (stream out) the contents of a rich edit control.

The control calls the callback function repeatedly, transferring a portion of the data with each call. The callback function has the following form:

DWORD CALLBACK EditStreamCallback(DWORD dwCookie,

    LPBYTE pbBuff, LONG cb, LONG FAR *pcb);

dwCookie

Value of the dwCookie member of the EDITSTREAM structure.

pbBuff

Pointer to the buffer to read from or write to.

cb

Count of bytes to read or write.

pcb

Pointer to a variable that receives the number of bytes actually read or written.

Return Value

The return value depends on direction. If data is streaming in, the return value is the number of bytes copied to the buffer, or zero if the transfer is complete.

If data is streaming out, the return value is a nonzero value to continue to the transfer operation, or zero to abort it.

See Also

EM_STREAMIN, EM_STREAMOUT


EMR
EMR  QuickInfo  Overview  Group

typedef struct tagEMR
{
    DWORD iType;

    DWORD nSize;
} EMR, *PEMR;

The EMR structure provides the base structure for all enhanced metafile records. An enhanced metafile record contains the parameters for a specific GDI function used to create part of a picture in an enhanced format metafile.

Members

iType

Specifies the record type.

nSize

Size of the record, in bytes. This member must be a multiple of four.


EMRANGLEARC
EMRANGLEARC  QuickInfo  Overview  Group

typedef struct tagEMRANGLEARC
{
    EMR     emr;
    POINTL  ptlCenter;

    DWORD   nRadius;
    FLOAT   eStartAngle;
    FLOAT   eSweepAngle;
} EMRANGLEARC, *PEMRANGLEARC;

The EMRANGLEARC structure contains members for the AngleArc enhanced metafile record.

Members

emr

Base structure for all record types.

ptlCenter

Logical coordinates of circle's center.

nRadius

Circle's radius, in logical units.

eStartAngle

Arc's start angle, in degrees.

eSweepAngle

Arc's sweep angle, in degrees.

See Also

AngleArc


EMRARC, EMRARCTO, EMRCHORD, EMRPIE
EMRARC, EMRARCTO, EMRCHORD, EMRPIE  Overview  Group

typedef struct tagEMRARC
{
    EMR    emr;

    RECTL  rclBox;
    POINTL ptlStart;
    POINTL ptlEnd;
} EMRARC,   *PEMRARC,
  EMRARCTO, *PEMRARCTO,
  EMRCHORD, *PEMRCHORD,
  EMRPIE,   *PEMRPIE;

The EMRARC, EMRARCTO, EMRCHORD, and EMRPIE structures contain members for the Arc, ArcTo, Chord, and Pie enhanced metafile records.

Members

emr

Base structure for all record types.

rclBox

Bounding rectangle.

ptlStart

Coordinates of first radial ending point.

ptlEnd

Coordinates of second radial ending point.

See Also

Arc, ArcTo, Chord, Pie


EMRBITBLT
EMRBITBLT  QuickInfo  Overview  Group

typedef struct tagEMRBITBLT
{
    EMR      emr;

    RECTL    rclBounds;

    LONG     xDest;

    LONG     yDest;

    LONG     cxDest;

    LONG     cyDest;

    DWORD    dwRop;

    LONG     xSrc;

    LONG     ySrc;

    XFORM    xformSrc;

    COLORREF crBkColorSrc;

    DWORD    iUsageSrc;

    DWORD    offBmiSrc;

    DWORD    offBitsSrc;

    DWORD    cbBitsSrc;

} EMRBITBLT, *PEMRBITBLT;

The EMRBITBLT structure contains members for the BitBlt enhanced metafile record. Note that graphics device interface (GDI) converts the device-dependent bitmap into a device-independent bitmap (DIB) before storing it in the metafile record.

Members

emr

Base structure for all record types.

rclBounds

Bounding rectangle, in device units.

xDest

Logical x-coordinate of the upper-left corner of the destination rectangle.

yDest

Logical y-coordinate of the upper-left corner of the destination rectangle.

dwRop

Raster-operation code. These codes define how the color data of the source rectangle is to be combined with the color data of the destination rectangle to achieve the final color.

xSrc

Logical x-coordinate of the upper-left corner of the source rectangle.

ySrc

Logical y-coordinate of the upper-left corner of the source rectangle.

xformSrc

World-space to page-space transformation of the source device context.

crBkColorSrc

Background color (the RGB value) of the source device context.

iUsageSrc

Value of the bmiColors member of the BITMAPINFO structure. The iUsageSrc member can be either the DIB_PAL_COLORS, DIB_PAL_INDICES or DIB_RGB_COLORS value.

offBmiSrc

Offset to source BITMAPINFO structure.

cbBmiSrc

Size of source BITMAPINFO structure.

offBitsSrc

Offset to source bitmap bits.

cbBitsSrc

Size of source bitmap bits.

See Also

BitBlt, BITMAPINFO, RGB


EMRCREATEBRUSHINDIRECT
EMRCREATEBRUSHINDIRECT  QuickInfo  Overview  Group

typedef struct tagEMRCREATEBRUSHINDIRECT
{
    EMR      emr;

    DWORD    ihBrush;

    LOGBRUSH lb;

} EMRCREATEBRUSHINDIRECT, *PEMRCREATEBRUSHINDIRECT;

The EMRCREATEBRUSHINDIRECT structure contains members for the CreateBrushIndirect enhanced metafile record.

Members

emr

Base structure for all record types.

ihBrush

Index of brush in handle table.

lb

LOGBRUSH structure containing information about the brush. The lbStyle member must be either the BS_SOLID, BS_HOLLOW, BS_NULL, or BS_HATCHED value.

CreateBrushIndirect, LOGBRUSH


EMRCREATECOLORSPACE [New - Windows 95]
EMRCREATECOLORSPACE  QuickInfo  Overview  Group

[New - Windows 95]

typedef struct tagEMRCREATECOLORSPACE
{
    EMR           emr;

    DWORD         ihCS;

    LOGCOLORSPACE lcs;

} EMRCREATECOLORSPACE, *PEMRCREATECOLORSPACE;

The EMRCREATECOLORSPACE structure contains members for the CreateColorSpace enhanced metafile record.

Members

emr

Base structure for all record types

ihCS

Index of the color cpace in handle table

lcs

Logical color space

See Also

CreateColorSpace


EMRCREATEDIBPATTERNBRUSHPT
EMRCREATEDIBPATTERNBRUSHPT  QuickInfo  Overview  Group

typedef struct tagEMRCREATEDIBPATTERNBRUSHPT
{
    EMR   emr;

    DWORD ihBrush;

    DWORD iUsage;

    DWORD offBmi;

    DWORD cbBmi;

    DWORD offBits;

    DWORD cbBits;

} EMRCREATEDIBPATTERNBRUSHPT,
PEMRCREATEDIBPATTERNBRUSHPT;

The EMRCREATEDIBPATTERNBRUSHPT structure contains members for the CreateDIBPatternBrushPt enhanced metafile record. The BITMAPINFO structure is followed by the bitmap bits that form a packed device-independent bitmap (DIB).

Members

emr

Base structure for all record types.

ihBrush

Index of brush in handle table.

iUsage

Value specifying whether the bmiColors member of the BITMAPINFO structure was provided and, if so, whether bmiColors contains explicit red, green, blue (RGB) values or indices. The iUsage member must be either the DIB_PAL_COLORS, DIB_PAL_INDICES, or DIB_RGB_COLORS value.

offBmi

Offset to BITMAPINFO structure.

cbBmi

Size of BITMAPINFO structure.

offBits

Offset to bitmap bits.

cbBits

Size of bitmap bits.

See Also

BITMAPINFO, CreateDIBPatternBrushPt, RGB


EMRCREATEMONOBRUSH
EMRCREATEMONOBRUSH  QuickInfo  Overview  Group

typedef struct tagEMRCREATEMONOBRUSH
{
    EMR   emr;

    DWORD ihBrush;

    DWORD iUsage;

    DWORD offBmi;

    DWORD cbBmi;

    DWORD offBits;

    DWORD cbBits;

} EMRCREATEMONOBRUSH, *PEMRCREATEMONOBRUSH;

The EMRCREATEMONOBRUSH structure contains members for the CreatePatternBrush (when passed a monochrome bitmap) or CreateDIBPatternBrush (when passed a monochrome DIB) enhanced metafile records.

Members

emr

Base structure for all record types.

ihBrush

Index of brush in handle table.

iUsage

Value specifying whether the bmiColors member of the BITMAPINFO structure was provided and, if so, whether bmiColors contains explicit red, green, blue (RGB) values or indices. The iUsage member must be either the DIB_PAL_COLORS, DIB_PAL_INDICES, or DIB_RGB_COLORS value.

offBmi

Offset to BITMAPINFO structure.

cbBmi

Size of BITMAPINFO structure.

offBits

Offset to bitmap bits.

cbBits

Size of bitmap bits.

See Also

BITMAPINFO, CreateDIBPatternBrush, CreatePatternBrush, RGB


EMRCREATEPALETTE
EMRCREATEPALETTE  QuickInfo  Overview  Group

typedef struct tagEMRCREATEPALETTE
{
    EMR        emr;

    DWORD      ihPal;

    LOGPALETTE lgpl;

} EMRCREATEPALETTE, *PEMRCREATEPALETTE;

The EMRCREATEPALETTE structure contains members for the CreatePalette enhanced metafile record.

Members

emr

Base structure for all record types.

ihPal

Index of palette in handle table.

lgpl

LOGPALETTE structure that contains information about the palette. Note that peFlags members in the PALETTEENTRY structures do not contain any flags.

See Also

CreatePalette, LOGPALETTE, PALETTEENTRY


EMRCREATEPEN
EMRCREATEPEN  QuickInfo  Overview  Group

typedef struct tagEMRCREATEPEN
{
    EMR    emr;

    DWORD  ihPen;

    LOGPEN lopn;

} EMRCREATEPEN, *PEMRCREATEPEN;

The EMRCREATEPEN structure contains members for the CreatePen enhanced metafile record.

Members

emr

Base structure for all record types

ihPen

Index to pen in handle table

lopn

Logical pen

See Also

CreatePen


EMRELLIPSE, EMRRECTANGLE
EMRELLIPSE, EMRRECTANGLE  Overview  Group

typedef struct tagEMRELLIPSE
{
    EMR   emr;

    RECTL rclBox;

} EMRELLIPSE,  *PEMRELLIPSE,
  EMRRECTANGLE, *PEMRRECTANGLE;

The EMRELLIPSE and EMRRECTANGLE structures contain members for the Ellipse and Rectangle enhanced metafile records.

Members

emr

Base structure for all record types.

rclBox

Bounding rectangle.

See Also

Ellipse, Rectangle


EMREOF
EMREOF  QuickInfo  Overview  Group

typedef struct tagEMREOF
{
    EMR     emr;
    DWORD   nPalEntries;

    DWORD   offPalEntries;

    DWORD   nSizeLast;

} EMREOF, *PEMREOF;

The EMREOF structure contains data for the enhanced metafile record that indicates the end of the metafile.

Members

emr

Base structure for all record types.

nPalEntries

Number of palette entries.

offPalEntires

Offset to palette entries.

nSizeLast

Same size as the nSize member of the EMR structure. This member must be the last doubleword of the record. If palette entries exist, they precede this member.

See Also

EMR


EMREXCLUDECLIPRECT, EMRINTERSECTCLIPRECT
EMREXCLUDECLIPRECT, EMRINTERSECTCLIPRECT  Overview  Group

typedef struct tagEMREXCLUDECLIPRECT
{
    EMR   emr;      // base structure for all record types
    RECTL rclClip;  // clipping rectangle
} EMREXCLUDECLIPRECT,   *PEMREXCLUDECLIPRECT,
  EMRINTERSECTCLIPRECT, *PEMRINTERSECTCLIPRECT;

The EMREXCLUDECLIPRECT and EMRINTERSECTCLIPRECTstructures contain members for the ExcludeClipRect and IntersectClipRect enhanced metafile records.

Members

emr

Base structure for all record types.

rclClip

Clipping rectangle.

ExcludeClipRect, IntersectClipRect


EMREXTCREATEFONTINDIRECTW
EMREXTCREATEFONTINDIRECTW  QuickInfo  Overview  Group

typedef struct tagEMREXTCREATEFONTINDIRECTW
{
    EMR         emr;

    DWORD       ihFont;

    EXTLOGFONTW elfw;

} EMREXTCREATEFONTINDIRECTW,
PEMREXTCREATEFONTINDIRECTW;

The EMREXTCREATEFONTINDIRECTW structure contains members for the CreateFontIndirect enhanced metafile record.

Members

emr

Base structure for all record types.

ihFont

Index to the font in handle table.

elfw

Logical font.

See Also

CreateFontIndirect


EMREXTCREATEPEN
EMREXTCREATEPEN  QuickInfo  Overview  Group

typedef struct tagEMREXTCREATEPEN
{
    EMR       emr;

    DWORD     ihPen;

    DWORD     offBmi;

    DWORD     cbBmi;

    DWORD     offBits;

    DWORD     cbBits;

    EXTLOGPEN elp;

} EMREXTCREATEPEN, *PEMREXTCREATEPEN;

The EMREXTCREATEPEN structure contains members for the ExtCreatePen enhanced metafile record. If the record contains a BITMAPINFO structure, it is followed by the bitmap bits that form a packed device-independent bitmap (DIB).

Members

emr

Base structure for all record types.

ihPen

Index to pen in handle table.

offBmi

Offset to BITMAPINFO structure, if any.

cbBmi

Size of BITMAPINFO structure, if any.

offBits

Offset to brush bitmap bits, if any.

cbBits

Size of brush bitmap bits, if any.

elp

Extended logical pen, including the elpStyleEntry member of the EXTLOGPEN structure.

See Also

BITMAPINFO, ExtCreatePen, EXTLOGPEN


EMREXTFLOODFILL
EMREXTFLOODFILL  QuickInfo  Overview  Group

typedef struct tagEMREXTFLOODFILL
{
    EMR     emr;

    POINTL  ptlStart;

    COLORREF crColor;

    DWORD   iMode;

} EMREXTFLOODFILL, *PEMREXTFLOODFILL;

The EMREXTFLOODFILL structure contains members for the ExtFloodFill enhanced metafile record.

Members

emr

Base structure for all record types.

ptlStart

Coordinates where filling begins.

crColor

Color of fill.

iMode

Type of fill operation to be performed. This member must be either the FLOODFILLBORDER or FLOODFILLSURFACE value.

See Also

ExtFloodFill


EMREXTSELECTCLIPRGN
EMREXTSELECTCLIPRGN  QuickInfo  Overview  Group

typedef struct tagEMREXTSELECTCLIPRGN
{
    EMR   emr;

    DWORD cbRgnData;

    DWORD iMode;

    BYTE  RgnData[1]; //

} EMREXTSELECTCLIPRGN, *PEMREXTSELECTCLIPRGN;

The EMREXTSELECTCLIPRGN structure contains members for the ExtSelectClipRgn enhanced metafile record.

Members

emr

Base structure for all record types.

cbRgnData

Size of region data, in bytes.

iMode

Operation to be performed. This member must be one of the following values: RGN_AND, RGN_COPY, RGN_DIFF, RGN_OR, or RGN_XOR.

See Also

ExtSelectClipRgn


EMREXTTEXTOUTA, EMREXTTEXTOUTW
EMREXTTEXTOUTA, EMREXTTEXTOUTW  Overview  Group

typedef struct tagEMREXTTEXTOUTA
{
    EMR     emr;

    RECTL   rclBounds;

    DWORD   iGraphicsMode;

    FLOAT   exScale;

    FLOAT   eyScale;
    EMRTEXT emrtext;

} EMREXTTEXTOUTA, *PEMREXTTEXTOUTA,
  EMREXTTEXTOUTW, *PEMREXTTEXTOUTW;

The EMREXTTEXTOUTA and EMREXTTEXTOUTW structures contain members for the ExtTextOut, TextOut, or DrawText enhanced metafile records.

Members

emr

Base structure for all record types.

rclBounds

Bounding rectangle, in device units.

iGraphicsMode

Current graphics mode. This member can be either the GM_COMPATIBLE or GM_ADVANCED value.

exScale

X-scaling factor from page units to .01mm units if the graphics mode is the GM_COMPATIBLE value.

eyScale

Y-scaling factor from page units to .01mm units if the graphics mode is the GM_COMPATIBLE value.

emrtext

EMRTEXT structure, which is followed by the string and the intercharacter spacing array.

See Also

DrawText, ExtTextOut, TextOut, EMRTEXT


EMRFILLPATH, EMRSTROKEANDFILLPATH, EMRSTROKEPATH
EMRFILLPATH, EMRSTROKEANDFILLPATH, EMRSTROKEPATH  Overview  Group

typedef struct tagEMRFILLPATH
{
    EMR   emr;

    RECTL rclBounds;

} EMRFILLPATH,          *PEMRFILLPATH,
  EMRSTROKEANDFILLPATH, *PEMRSTROKEANDFILLPATH,
  EMRSTROKEPATH,        *PEMRSTROKEPATH;

The EMRFILLPATH, EMRSTROKEANDFILLPATH, and EMRSTROKEPATH structures contain members for the FillPath, StrokeAndFillPath, and StrokePath enhanced metafile records.

Members

emr

Base structure for all record types.

rclBounds

Bounding rectangle, in device units.

See Also

FillPath, StrokeAndFillPath, StrokePath


EMRFILLRGN
EMRFILLRGN  QuickInfo  Overview  Group

typedef struct tagEMRFILLRGN
{
    EMR   emr;

    RECTL rclBounds;

    DWORD cbRgnData;

    DWORD ihBrush;

    BYTE  RgnData[1];

} EMRFILLRGN, *PEMRFILLRGN;

The EMRFILLRGN structure contains members for the FillRgn enhanced metafile record.

Members

emr

Base structure for all record types.

rclBounds

Bounding rectangle, in device units.

cbRgnData

Size of region data, in bytes.

ihBrush

Index of brush, in handle table.

RgnData

Buffer containing RGNDATA structure.

See Also

FillRgn, RGNDATA


EMRFORMAT
EMRFORMAT  QuickInfo

typedef struct tagEMRFORMAT   {

    DWORD   dSignature;

    DWORD   nVersion;

    DWORD   cbData;

    DWORD   offData;

} EMRFORMAT;

The EMRFORMAT structure contains information that identifies graphics data in an enhanced metafile. A GDICOMMENT_MULTIFORMATS enhanced metafile public comment contains an array of EMRFORMAT structures.

Members

dSignature

Contains a picture format identifier. The following identifier values are defined:

Identifier	Meaning
ENHMETA_SIGNATURE	The picture is in enhanced metafile format.
0x46535045	The picture is in encapsulated PostScript file format.
nVersion

Contains a picture version number. The following version number value is defined:

Version	Meaning
1	This is the version number of a level 1 encapsulated PostScript file.
cbData

Specifies the size, in bytes, of the picture data.

offData

Specifies an offset to the picture data. The offset is figured from the start of the GDICOMMENT_MULTIFORMATS public comment within which this EMRFORMAT structure is embedded. The offset must be a DWORD offset.

Remarks

GdiComment discusses enhanced metafile public comments in general, and the GDICOMMENT_MULTIFORMATS public comment in particular.

See Also

GdiComment


EMRFRAMERGN
EMRFRAMERGN  QuickInfo  Overview  Group

typedef struct tagEMRFRAMERGN
{
    EMR   emr;

    RECTL rclBounds;

    DWORD cbRgnData;

    DWORD ihBrush;

    SIZEL szlStroke;

    BYTE  RgnData[1];

} EMRFRAMERGN, *PEMRFRAMERGN;

The EMRFRAMERGN structure contains members for the FrameRgn enhanced metafile record.

Members

emr

Base structure for all record types.

rclBounds

Bounding rectangle, in device units.

cbRgnData

Size of region data, in bytes.

ihBrush

Index of brush, in handle table.

szlStroke

Width and height of region frame.

RgnData

Buffer containing RGNDATA structure.

See Also

FrameRgn, RGNDATA


EMRGDICOMMENT
EMRGDICOMMENT  QuickInfo  Overview  Group

typedef struct tagEMRGDICOMMENT
{
    EMR   emr;

    DWORD cbData;

    BYTE  Data[1];

} EMRGDICOMMENT, *PEMRGDICOMMENT;

The EMRGDICOMMENT structure contains application-specific data. This enhanced metafile record is only meaningful to applications that know the format of the data and how to utilize it. This record is ignored by graphics device interface (GDI) during playback of the enhanced metafile.

Members

emr

Base structure for all record types.

cbData

Size of data buffer, in bytes.

Data[1]

Application-specific data.


EMRINVERTRGN, EMRPAINTRGN
EMRINVERTRGN, EMRPAINTRGN  Overview  Group

typedef struct tagEMRINVERTRGN
{
    EMR   emr;

    RECTL rclBounds;

    DWORD cbRgnData;

    BYTE  RgnData[1];

} EMRINVERTRGN, *PEMRINVERTRGN,
  EMRPAINTRGN,  *PEMRPAINTRGN;

The EMRINVERTRGN and EMRPAINTRGN structures contain members for the InvertRgn and PaintRgn enhanced metafile records.

Members

emr

Base structure for all record types.

rclBounds

Bounding rectangle, in device units.

cbRgnData

Size of region data, in bytes.

RgnData

Buffer containing RGNDATA structure.

See Also

InvertRgn, PaintRgn


EMRLINETO, EMRMOVETOEX
EMRLINETO, EMRMOVETOEX  Overview  Group

typedef struct tagEMRLINETO
{
    EMR    emr;

    POINTL ptl;

} EMRLINETO,   *PEMRLINETO,
  EMRMOVETOEX, *PEMRMOVETOEX;

The EMRLINETO and EMRMOVETOEX structures contains members for the LineTo and MoveToEx enhanced metafile records.

Members

emr

Base structure for all record types.

ptl

Coordinates of the line's ending point for the LineTo function or coordinates of the new current position for the MoveToEx function.

See Also

LineTo, MoveToEx


EMRMASKBLT
EMRMASKBLT  QuickInfo  Overview  Group

typedef struct tagEMRMASKBLT
{
    EMR     emr;

    RECTL   rclBounds;

    LONG    xDest;

    LONG    yDest;

    LONG    cxDest;

    LONG    cyDest;

    DWORD   dwRop;

    LONG    xSrc;

    LONG    ySrc;

    XFORM   xformSrc;

    COLORREF crBkColorSrc;

    DWORD   iUsageSrc;

    DWORD   offBmiSrc;

    DWORD   cbBmiSrc;

    DWORD   offBitsSrc;

    DWORD   cbBitsSrc;

    LONG    xMask;

    LONG    yMask;

    DWORD   iUsageMask;

    DWORD   offBmiMask;

    DWORD   cbBmiMask;

    DWORD   offBitsMask;

    DWORD   cbBitsMask;

} EMRMASKBLT, *PEMRMASKBLT;

The EMRMASKBLT structure contains members for the MaskBlt enhanced metafile record. Note that graphics device interface (GDI) converts the device-dependent bitmap into a device-independent bitmap (DIB) before storing it in the metafile record.

Members

emr

Base structure for all record types.

rclBounds

Bounding rectangle, in device units.

xDest

Logical x-coordinate of the upper-left corner of the destination rectangle.

yDest

Logical y-coordinate of the upper-left corner of the destination rectangle.

cxDest

Logical width of destination rectangle

cyDest

Logical height of destination rectangle

dwRop

Raster-operation code. These codes define how the color data of the source rectangle is to be combined with the color data of the destination rectangle to achieve the final color.

xSrc

Logical x-coordinate of the upper-left corner of the source rectangle.

ySrc

Logical y-coordinate of the upper-left corner of the source rectangle.

xformSrc

World-space to page-space transformation of the source device context.

crBkColorSrc

Background color (the RGB value) of the source device context.

iUsageSrc

Value of the bmiColors member of the source BITMAPINFO structure. The iUsageSrc member can be either the DIB_PAL_COLORS, DIB_PAL_INDICES, or DIB_RGB_COLORS value.

offBmiSrc

Offset to source BITMAPINFO structure.

cbBmiSrc

Size of source BITMAPINFO structure.

offBitsSrc

Offset to source bitmap bits.

cbBitsSrc

Size of source bitmap bits.

xMask

Horizontal pixel offset into mask bitmap

yMask

Vertical pixel offset into mask bitmap

iUsageMask

Value of the bmiColors member of the mask BITMAPINFO structure.

offBmiMask

Offset to mask BITMAPINFO structure.

cbBmiMask

Size of mask BITMAPINFO structure.

offBitsMask

Offset to mask bitmap bits.

cbBitsMask

Size of mask bitmap bits.

See Also

BITMAPINFO, MaskBlt, RGB


EMRMODIFYWORLDTRANSFORM
EMRMODIFYWORLDTRANSFORM  QuickInfo  Overview  Group

typedef struct tagEMRMODIFYWORLDTRANSFORM
{
    EMR   emr;

    XFORM xform;

    DWORD iMode;

transformation
} EMRMODIFYWORLDTRANSFORM,
PEMRMODIFYWORLDTRANSFORM;

The EMRMODIFYWORLDTRANSFORM structure contains members for the ModifyWorldTransform enhanced metafile record.

Members

emr

Base structure for all record types.

xform

World-space to page-space transformation data.

iMode

Value specifying how the transformation data modifies the current world transformation. This member can be one of the following values: MWT_IDENTITY, MWT_LEFTMULTIPLY, or MWT_RIGHTMULTIPLY.

See Also

ModifyWorldTransform


EMROFFSETCLIPRGN
EMROFFSETCLIPRGN  QuickInfo  Overview  Group

typedef struct tagEMROFFSETCLIPRGN
{
    EMR    emr;

    POINTL ptlOffset;

} EMROFFSETCLIPRGN, *PEMROFFSETCLIPRGN;

The EMROFFSETCLIPRGN structure contains members for the OffsetClipRgn enhanced metafile record.

Members

emr

Base structure for all record types.

ptlOffset

Logical coordinates of offset.

See Also

OffsetClipRgn


EMRPLGBLT
EMRPLGBLT  QuickInfo  Overview  Group

typedef struct tagEMRPLGBLT
{
    EMR      emr;

    RECTL    rclBounds;

    POINTL   aptlDest[3];

    LONG    xSrc;

    LONG    ySrc;

    LONG     cxSrc;

    LONG     cySrc;

    XFORM   xformSrc;

    COLORREF crBkColorSrc;

    DWORD    iUsageSrc;

    DWORD    offBmiSrc;

    DWORD   cbBmiSrc;

    DWORD   offBitsSrc;

    DWORD   cbBitsSrc;

    LONG    xMask;
    LONG    yMask;

    DWORD   iUsageMask;

    DWORD   offBmiMask;

    DWORD   cbBmiMask;
    DWORD   offBitsMask;
    DWORD   cbBitsMask;
} EMRPLGBLT, *PEMRPLGBLT;

The EMRPLGBLT structure contains members for the PlgBlt enhanced metafile record. Note that graphics device interface (GDI) converts the device-dependent bitmap into a device-independent bitmap (DIB) before storing it in the metafile record.

Members

emr

Base structure for all record types.

rclBounds

Bounding rectangle, in device units.

aptlDest

Array of three points in logical space that identify three corners of the destination parallelogram. The upper-left corner of the source rectangle is mapped to the first point in this array, the upper-right corner to the second point in this array, and the lower-left corner to the third point. The lower-right corner of the source rectangle is mapped to the implicit fourth point in the parallelogram.

xSrc

Logical x-coordinate of the upper-left corner of the source rectangle.

ySrc

Logical y-coordinate of the upper-left corner of the source rectangle.

cxSrc

Logical width of source

cySrc

Logical height of source

xformSrc

World-space to page-space transformation of the source device context.

crBkColorSrc

Background color (the RGB value) of the source device context.

iUsageSrc

Value of the bmiColors member of the BITMAPINFO structure. The iUsageSrc member can be either the DIB_PAL_COLORS, DIB_PAL_INDICES, or DIB_RGB_COLORS value.

offBmiSrc

Offset to source BITMAPINFO structure.

cbBmiSrc

Size of source BITMAPINFO structure.

offBitsSrc

Offset to source bitmap bits.

cbBitsSrc

Size of source bitmap bits.

xMask

Horizontal pixel offset into mask bitmap.

yMask

Vertical pixel offset into mask bitmap.

iUsageMask

Value of the bmiColors member of the mask BITMAPINFO structure.

offBmiMask

Offset to mask BITMAPINFO structure.

cbBmiMask

Size of mask BITMAPINFO structure.

offBitsMask

Offset to mask bitmap bits.

cbBitsMask

Size of mask bitmap bits.

See Also

BITMAPINFO, PlgBlt, RGB


EMRPOLYDRAW
EMRPOLYDRAW  QuickInfo  Overview  Group

typedef struct tagEMRPOLYDRAW
{
    EMR    emr;

    RECTL  rclBounds;

    DWORD  cptl;

    POINTL aptl[1];

    BYTE   abTypes[1];

} EMRPOLYDRAW, *PEMRPOLYDRAW;

The EMRPOLYDRAW structure contains members for the PolyDraw enhanced metafile record.

Members

emr

Base structure for all record types.

rclBounds

Bounding rectangle, in device units.

cptl

Number of points.

aptl

Array of 32-bit points.

abTypes

Array of values that specifies how each point in the aptl array is used. This member can be one of the following values: PT_MOVETO, PT_LINETO, or PT_BEZIERTO. The PT_LINETO or PT_BEZIERTO value can be combined with the PT_CLOSEFIGURE value by using the bitwise-xOR operator.

See Also

PolyDraw


EMRPOLYDRAW16
EMRPOLYDRAW16  QuickInfo  Overview  Group

typedef struct tagEMRPOLYDRAW16
{
    EMR    emr;

    RECTL  rclBounds;

    DWORD  cpts;

    POINTS apts[1];

    BYTE   abTypes[1];

} EMRPOLYDRAW16, *PEMRPOLYDRAW16;

The EMRPOLYDRAW16 structure contains members for the PolyDraw enhanced metafile record.

Members

emr

Base structure for all record types.

rclBounds

Bounding rectangle, in device units.

cpts

Number of points.

apts

Array of 16-bit points.

abTypes

Array of values that specifies how each point in the apts array is used. This member can be one of the following values: PT_MOVETO, PT_LINETO, or PT_BEZIERTO. The PT_LINETO or PT_BEZIERTO value can be combined with the PT_CLOSEFIGURE value by using the bitwise-OR operator.

See Also

PolyDraw


EMRPOLYLINE, EMRPOLYBEZIER, EMRPOLYGON, EMRPOLYBEZIERTO, EMRPOLYLINETO  [New - Windows 95]
EMRPOLYLINE, EMRPOLYBEZIER, EMRPOLYGON, EMRPOLYBEZIERTO, EMRPOLYLINETO  Overview  Group

[New - Windows 95]

typedef struct tagEMRPOLYLINE
{
    EMR    emr;
    RECTL  rclBounds;

    DWORD  cptl;

    POINTL aptl[1];

} EMRPOLYLINE,     *PEMRPOLYLINE,
  EMRPOLYBEZIER,   *PEMRPOLYBEZIER,
  EMRPOLYGON,      *PEMRPOLYGON,
  EMRPOLYBEZIERTO, *PEMRPOLYBEZIERTO,
  EMRPOLYLINETO,   *PEMRPOLYLINETO;

The EMRPOLYLINE, EMRPOLYBEZIER, EMRPOLYGON, EMRPOLYBEZIERTO, and EMRPOLYLINETO structures contain members for the Polyline, PolyBezier, Polygon, PolyBezierTo, and PolylineTo enhanced metafile records.

Members

emr

Base structure for all record types.

rclBounds

Bounding rectangle, in device units.

cptl

Number of points array.

aptl

Array of 32-bit points.

See Also

PolyBezier, PolyBezierTo, Polygon, Polyline, PolylineTo


EMRPOLYLINE16, EMRPOLYBEZIER16, EMRPOLYGON16, EMRPOLYBEZIERTO16, EMRPOLYLINETO16
EMRPOLYLINE16, EMRPOLYBEZIER16, EMRPOLYGON16, EMRPOLYBEZIERTO16, EMRPOLYLINETO16  Overview  Group

typedef struct tagEMRPOLYLINE
{
    EMR    emr;

    RECTL  rclBounds;

    DWORD  cpts;

    POINTL apts[1];

} EMRPOLYLINE16,     *PEMRPOLYLINE16,
  EMRPOLYBEZIER16,   *PEMRPOLYBEZIER16,
  EMRPOLYGON16,      *PEMRPOLYGON16,
  EMRPOLYBEZIERTO16, *PEMRPOLYBEZIERTO16,
  EMRPOLYLINETO16,   *PEMRPOLYLINETO16;

The EMRPOLYLINE16, EMRPOLYBEZIER16, EMRPOLYGON16, EMRPOLYBEZIERTO16, and EMRPOLYLINETO16 structures contain members for the Polyline, PolyBezier, Polygon, PolyBezierTo, and PolylineTo enhanced metafile records.

Members

emr

Base structure for all record types.

rclBounds

Bounding rectangle, in device units.

cpts

Number of points in the array.

apts

Array of 16-bit points.

See Also

PolyBezier, PolyBezierTo, Polygon, Polyline, PolylineTo


EMRPOLYPOLYLINE, EMRPOLYPOLYGON
EMRPOLYPOLYLINE, EMRPOLYPOLYGON  Overview  Group

typedef struct tagEMRPOLYPOLYLINE
{
    EMR     emr;

    RECTL   rclBounds;

    DWORD   nPolys;

    DWORD   cptl;

    DWORD   aPolyCounts[1];

    POINTL  aptl[1];

} EMRPOLYPOLYLINE, *PEMRPOLYPOLYLINE,
  EMRPOLYPOLYGON,  *PEMRPOLYPOLYGON;

The EMRPOLYPOLYLINE and EMRPOLYPOLYGON structures contain members for the PolyPolyline and PolyPolygon enhanced metafile records.

Members

emr

Base structure for all record types.

rclBounds

Bounding rectangle, in device units.

nPolys

Number of polys.

cpt1

Total number of points in all polys.

aPolyCounts

Array of point counts for each poly.

aptl

Array of 32-bit points.

See Also

PolyPolyline, PolyPolygon


EMRPOLYPOLYLINE16, EMRPOLYPOLYGON16
EMRPOLYPOLYLINE16, EMRPOLYPOLYGON16  Overview  Group

typedef struct tagEMRPOLYPOLYLINE16
{
    EMR     emr;

    RECTL   rclBounds;
    DWORD   nPolys;

    DWORD   cpts;

    DWORD   aPolyCounts[1];

    POINTS  apts[1];

} EMRPOLYPOLYLINE16, *PEMRPOLYPOLYLINE16,
  EMRPOLYPOLYGON16,  *PEMRPOLYPOLYGON16;

The EMRPOLYPOLYLINE16 and EMRPOLYPOLYGON16 structures contain members for the PolyPolyline and PolyPolygon enhanced metafile records.

Members

emr

Base structure for all record types.

rclBounds

Bounding rectangle, in device units.

nPolys

Number of polys.

cpt1

Total number of points in all polys.

aPolyCounts

Array of point counts for each poly.

aptl

Array of 16-bit points.

See Also

PolyPolyline, PolyPolygon


EMRPOLYTEXTOUTA, EMRPOLYTEXTOUTW
EMRPOLYTEXTOUTA, EMRPOLYTEXTOUTW  Overview  Group

typedef struct tagEMRPOLYTEXTOUTA
{
    EMR     emr;

    RECTL   rclBounds;

    DWORD   iGraphicsMode;

    FLOAT   exScale;

    FLOAT   eyScale;

    LONG    cStrings;

    EMRTEXT aemrtext[1];

} EMRPOLYTEXTOUTA, *PEMRPOLYTEXTOUTA,
  EMRPOLYTEXTOUTW, *PEMRPOLYTEXTOUTW;

The EMRPOLYTEXTOUTA and EMRPOLYTEXTOUTW structures contain members for the PolyTextOut enhanced metafile record.

Members

emr

Base structure for all record types.

rclBounds

Bounding rectangle, in device units.

iGraphicsMode

Current graphics mode. This member can be either the GM_COMPATIBLE or GM_ADVANCED value.

exScale

X-scaling factor from page units to .01mm units if the graphics mode is the GM_COMPATIBLE value.

eyScale

Y-scaling factor from page units to .01mm units if the graphics mode is the GM_COMPATIBLE value.

cStrings

Number of strings.

aemrtext

EMRTEXT structure, which is followed by the string and the intercharacter spacing array.

See Also

EMRTEXT


EMRRESIZEPALETTE
EMRRESIZEPALETTE  QuickInfo  Overview  Group

typedef struct tagEMRRESIZEPALETTE
{
    EMR   emr;

    DWORD ihPal;

    DWORD cEntries;

} EMRRESIZEPALETTE, *PEMRRESIZEPALETTE;

The EMRRESIZEPALETTE structure contains members for the ResizePalette enhanced metafile record.

Members

emr

Base structure for all record types.

ihPal

Index of palette in handle table.

cEntries

Number of entries in palette after resizing.

See Also

ResizePalette


EMRRESTOREDC
EMRRESTOREDC  QuickInfo  Overview  Group

typedef struct tagEMRRESTOREDC
{
    EMR  emr;

    LONG iRelative;

} EMRRESTOREDC, *PEMRRESTOREDC;

The EMRRESTOREDC structure contains members for the RestoreDC enhanced metafile record.

Members

emr

Base structure for all record types.

iRelative

Relative instance to restore.

See Also

RestoreDC


EMRROUNDRECT
EMRROUNDRECT  QuickInfo  Overview  Group

typedef struct tagEMRROUNDRECT
{
    EMR   emr;

    RECTL rclBox;

    SIZEL szlCorner;

} EMRROUNDRECT, *PEMRROUNDRECT;

The EMRROUNDRECT structure contains members for the RoundRect enhanced metafile record.

Members

emr

Base structure for all record types.

szlCorner

Width and height of the ellipse used to draw rounded corners.

See Also

RoundRect


EMRSCALEVIEWPORTEXTEX, EMRSCALEWINDOWEXTEX
EMRSCALEVIEWPORTEXTEX, EMRSCALEWINDOWEXTEX  Overview  Group

typedef struct tagEMRSCALEVIEWPORTEXTEX
{
    EMR  emr;

    LONG xNum;

    LONG xDenom;

    LONG yNum;

    LONG yDenom;

} EMRSCALEVIEWPORTEXTEX, *PEMRSCALEVIEWPORTEXTEX,

  EMRSCALEWINDOWEXTEX,   *PEMRSCALEWINDOWEXTEX;

The EMRSCALEVIEWPORTEXTEX and EMRSCALEWINDOWEXTEX structures contain members for the ScaleViewportExtEx and ScaleWindowExtEx enhanced metafile records.

Members

emr

Base structure for all record types.

xNum

Horizontal multiplicand.

xDenom

Horizontal divisor.

yNum

Vertical multiplicand.

yDenom

Vertical divisor.

See Also

ScaleViewportExtEx, ScaleWindowExtEx


EMRSELECTCOLORSPACE, EMRDELETECOLORSPACE [New - Windows 95]
EMRSELECTCOLORSPACE, EMRDELETECOLORSPACE  Overview  Group

[New - Windows 95]

typedef struct tagEMRSELECTCOLORSPACE

{

    EMR     emr;

    DWORD   ihCS;

} EMRSELECTCOLORSPACE, *PEMRSELECTCOLORSPACE,
  EMRDELETECOLORSPACE, *PEMRDELETECOLORSPACE;

The EMRSELECTCOLORSPACE and EMRDELETECOLORSPACE structures contain members for the SelectColorSpace and DeleteColorSpace enhanced metafile records.

Members

emr

Base structure for all record types.

ihCS

Color space handle index.

See Also

DeleteColorSpace


EMRSELECTOBJECT, EMRDELETEOBJECT
EMRSELECTOBJECT, EMRDELETEOBJECT  Overview  Group

typedef struct tagEMRSELECTOBJECT
{
    EMR   emr;

    DWORD ihObject;
} EMRSELECTOBJECT, *PEMRSELECTOBJECT,
  EMRDELETEOBJECT, *PEMRDELETEOBJECT;

The EMRSELECTOBJECT and EMRDELETEOBJECT structures contain members for the SelectObject and DeleteObject enhanced metafile records.

Members

emr

Base structure for all record types.

ihObject

Index of object in handle table.

See Also

SelectObject, DeleteObject


EMRSELECTPALETTE
EMRSELECTPALETTE  QuickInfo  Overview  Group

typedef struct tagEMRSELECTPALETTE

{
    EMR   emr;

    DWORD ihPal;

} EMRSELECTPALETTE, *PEMRSELECTPALETTE;

The EMRSELECTPALETTE structure contains members for the SelectPalette enhanced metafile record. Note that the bForceBackground parameter in SelectPalette is always recorded as TRUE, which causes the palette to be realized as a background palette.

Members

emr

Base structure for all record types.

ihPal

Index to logical palette in handle table.

See Also

SelectPalette


EMRSETARCDIRECTION
EMRSETARCDIRECTION  QuickInfo  Overview  Group

typedef struct tagEMRSETARCDIRECTION
{
    EMR   emr;

    DWORD iArcDirection;
} EMRSETARCDIRECTION, *PEMRSETARCDIRECTION;

The EMRSETARCDIRECTION structure contains members for the SetArcDirection enhanced metafile record.

Members

emr

Base structure for all record types.

iArcDirection

Arc direction. This member can be either the AD_CLOCKWISE or AD_COUNTERCLOCKWISE value.

See Also

Arc, SetArcDirection


EMRSETBKCOLOR, EMRSETTEXTCOLOR
EMRSETBKCOLOR, EMRSETTEXTCOLOR  Overview  Group

typedef struct tagEMRSETTEXTCOLOR
{
    EMR      emr;

    COLORREF crColor;

} EMRSETBKCOLOR,   *PEMRSETBKCOLOR,
  EMRSETTEXTCOLOR, *PEMRSETTEXTCOLOR;

The EMRSETBKCOLOR and EMRSETTEXTCOLOR structures contain members for the SetBkColor and SetTextColor enhanced metafile records.

Members

emr

Base structure for all record types.

crColor

Color value.

See Also

SetBkColor, SetTextColor


EMRSETCOLORADJUSTMENT
EMRSETCOLORADJUSTMENT  QuickInfo  Overview  Group

typedef struct tagEMRSETCOLORADJUSTMENT
{
    EMR  emr;

    COLORADJUSTMENT ColorAdjustment;

} EMRSETCOLORADJUSTMENT, *PEMRSETCOLORADJUSTMENT;

The EMRSETCOLORADJUSTMENT structure contains members for the SetColorAdjustment enhanced metafile record.

Members

emr

Base structure for all record types.

ColorAdjustment

COLORADJUSTMENT structure.

See Also

SetColorAdjustment


EMRSETDIBITSTODEVICE
EMRSETDIBITSTODEVICE  QuickInfo  Overview  Group

typedef struct tagEMRSETDIBITSTODEVICE
{
    EMR   emr;

    RECTL rclBounds;

    LONG  xDest;

    LONG  yDest;

    LONG  xSrc;

    LONG  ySrc;

    LONG  cxSrc;

    LONG  cySrc;

    DWORD offBmiSrc;

    DWORD cbBmiSrc;

    DWORD offBitsSrc;

    DWORD cbBitsSrc;

    DWORD iUsageSrc;

    DWORD iStartScan;

    DWORD cScans;

} EMRSETDIBITSTODEVICE, *PEMRSETDIBITSTODEVICE;

The EMRSETDIBITSTODEVICE structure contains members for the SetDIBitsToDevice enhanced metafile record.

Members

emr

Base structure for all record types.

rclBounds

Bounding rectangle, in device units.

xDest

Logical x-coordinate of the upper-left corner of the destination rectangle.

yDest

Logical y-coordinate of the upper-left corner of the destination rectangle.

xSrc

Logical x-coordinate of the lower-left corner of the source device-independent bitmap (DIB).

ySrc

Logical y-coordinate of the lower-left corner of the source DIB.

cxSrc

Width of source rectangle.

cyScr

Height of source rectangle.

offBmiSrc

Offset to source BITMAPINFO structure.

cbBmiSrc

Size of source BITMAPINFO structure.

offBitsSrc

Offset to source bitmap bits.

cbBitsSrc

Size of source bitmap bits.

iUsageSrc

Value of the bmiColors member of the BITMAPINFO structure. The iUsageSrc member can be either the DIB_PAL_COLORS, DIB_PAL_INDICES, or DIB_RGB_COLORS value.

iStartScan

First scan line in array.

cScans

Number of scan lines.

See Also

BITMAPINFO, SetDIBitsToDevice


EMRSETMAPPERFLAGS
EMRSETMAPPERFLAGS  QuickInfo  Overview  Group

typedef struct tagEMRSETMAPPERFLAGS
{
    EMR   emr;

    DWORD dwFlags;

} EMRSETMAPPERFLAGS, *PEMRSETMAPPERFLAGS;

The EMRSETMAPPERFLAGS structure contains members for the SetMapperFlags enhanced metafile record.

Members

emr

Base structure for all record types.

dwFlags

Font mapper flag.

See Also

SetMapperFlags


EMRSETMITERLIMIT
EMRSETMITERLIMIT  QuickInfo  Overview  Group

typedef struct tagEMRSETMITERLIMIT
{
    EMR   emr;
    FLOAT eMiterLimit;

} EMRSETMITERLIMIT, *PEMRSETMITERLIMIT;

The EMRSETMITERLIMIT structure contains members for the SetMiterLimit enhanced metafile record.

Members

emr

Base structure for all record types.

eMiterLimit

New miter limit.

See Also

SetMiterLimit


EMRSETPALETTEENTRIES
EMRSETPALETTEENTRIES  QuickInfo  Overview  Group

typedef struct tagEMRSETPALETTEENTRIES
{
    EMR          emr;

    DWORD        ihPal;

    DWORD        iStart;

    DWORD        cEntries;

    PALETTEENTRY aPalEntries[1];

} EMRSETPALETTEENTRIES, *PEMRSETPALETTEENTRIES;

The EMRSETPALETTEENTRIES structure contains members for the SetPaletteEntries enhanced metafile record.

Members

emr

Base structure for all record types.

ihPal

Palette handle index.

iStart

Index of first entry to set.

cEntries

Number of entries.

aPalEntries

Array of PALETTEENTRY structures. Note that peFlags members in the structures do not contain any flags.

See Also

PALETTEENTRY, SetPaletteEntries


EMRSETPIXELV
EMRSETPIXELV  QuickInfo  Overview  Group

typedef struct tagEMRSETPIXELV
{
    EMR     emr;

    POINTL  ptlPixel;

    COLORREF crColor;

} EMRSETPIXELV, *PEMRSETPIXELV;

The EMRSETPIXELV structure contains members for the SetPixelV enhanced metafile record. When an enhanced metafile is created, calls to SetPixel are also recorded in this record.

Members

emr

Base structure for all record types.

ptlPixel

Logical coordinates of pixel.

crColor

Color value.

SetPixelV, SetPixel


EMRSETVIEWPORTEXTEX, EMRSETWINDOWEXTEX
EMRSETVIEWPORTEXTEX, EMRSETWINDOWEXTEX  Overview  Group

typedef struct tagEMRSETVIEWPORTEXTEX
{
    EMR   emr;

    SIZEL szlExtent;

} EMRSETVIEWPORTEXTEX, *PEMRSETVIEWPORTEXTEX,
  EMRSETWINDOWEXTEX,   *PEMRSETWINDOWEXTEX;

The EMRSETVIEWPORTEXTEX and EMRSETWINDOWEXTEX structures contains members for the SetViewportExtEx and SetWindowExtEx enhanced metafile records.

Members

emr

Base structure for all record types.

szlExtent

Horizontal and vertical extents. For SetViewportExtEx, the extents are in device units, and for SetWindowExtEx, the extents are in logical units.

SetViewportExtEx, SetWindowExtEx


EMRSETVIEWPORTORGEX, EMRSETWINDOWORGEX, EMRSETBRUSHORGEX
EMRSETVIEWPORTORGEX, EMRSETWINDOWORGEX, EMRSETBRUSHORGEX  Overview  Group

typedef struct tagEMRSETVIEWPORTORGEX
{
    EMR    emr;

    POINTL ptlOrigin;

} EMRSETVIEWPORTORGEX, *PEMRSETVIEWPORTORGEX,
  EMRSETWINDOWORGEX,   *PEMRSETWINDOWORGEX,
  EMRSETBRUSHORGEX,    *PEMRSETBRUSHORGEX;

The EMRSETVIEWPORTORGEX, EMRSETWINDOWORGEX, and EMRSETBRUSHORGEX structures contain members for the SetViewportOrgEx, SetWindowOrgEx, and SetBrushOrgEx enhanced metafile records.

Members

emr

Base structure for all record types.

ptlOrigin

Coordinate of origin.

See Also

SetBrushOrgEx, SetViewportOrgEx, SetWindowOrgEx


EMRSETWORLDTRANSFORM
EMRSETWORLDTRANSFORM  QuickInfo  Overview  Group

typedef struct tagEMRSETWORLDTRANSFORM
{
    EMR   emr;

    XFORM xform;

} EMRSETWORLDTRANSFORM, *PEMRSETWORLDTRANSFORM;

The EMRSETWORLDTRANSFORM structure contains members for the SetWorldTransform enhanced metafile record.

Members

emr

Base structure for all record types.

xform

World-space to page-space transformation data.

See Also

SetWorldTransform


EMRSTRETCHBLT
EMRSTRETCHBLT  QuickInfo  Overview  Group

typedef struct tagEMRSTRETCHBLT
{
    EMR      emr;

    RECTL    rclBounds;

    LONG     xDest;

    LONG     yDest;

    LONG     cxDest;

    LONG     cyDest;

    DWORD    dwRop;

    LONG     xSrc;

    LONG     ySrc;

    XFORM    xformSrc;

    COLORREF crBkColorSrc;

    DWORD    iUsageSrc;

    DWORD    offBmiSrc;

    DWORD    cbBmiSrc;

    DWORD    offBitsSrc;

    DWORD    cbBitsSrc;

    LONG     cxSrc;

    LONG     cySrc;

} EMRSTRETCHBLT, *PEMRSTRETCHBLT;

The EMRSTRETCHBLT structure contains members for the StretchBlt enhanced metafile record. Note that graphics device interface (GDI) converts the device-dependent bitmap into a device-independent bitmap (DIB) before storing it in the metafile record.

Members

emr

Base structure for all record types.

rclBounds

Bounding rectangle, in device units.

xDest

Logical x-coordinate of the upper-left corner of the destination rectangle.

yDest

Logical y-coordinate of the upper-left corner of the destination rectangle.

cxDest

Logical width of destination rectangle

cyDest

Logical height of destination rectangle

dwRop

Raster-operation code. These codes define how the color data of the source rectangle is to be combined with the color data of the destination rectangle to achieve the final color.

xSrc

Logical x-coordinate of the upper-left corner of the source rectangle.

ySrc

Logical y-coordinate of the upper-left corner of the source rectangle.

xformSrc

World-space to page-space transformation of the source device context.

crBkColorSrc

Background color (the RGB value) of the source device context.

iUsageSrc

Value of the bmiColors member of the BITMAPINFO structure. The iUsageSrc member can be either the DIB_PAL_COLORS, DIB_PAL_INDICES, or DIB_RGB_COLORS value.

offBmiSrc

Offset to source BITMAPINFO structure.

cbBmiSrc

Size of source BITMAPINFO structure.

offBitsSrc

Offset to source bitmap bits.

cbBitsSrc

Size of source bitmap bits.

cxSrc

Width of source rectangle.

cySrc

Height of source rectangle.

See Also

BITMAPINFO, RGB, StretchBlt


EMRSTRETCHDIBITS
EMRSTRETCHDIBITS  QuickInfo  Overview  Group

typedef struct tagEMRSTRETCHDIBITS
{
    EMR   emr;
    RECTL rclBounds;

    LONG  xDest;

    LONG  yDest;

    LONG  xSrc;

    LONG  ySrc;

    LONG  cxSrc;

    LONG  cySrc;
    DWORD offBmiSrc;
    DWORD cbBmiSrc;

    DWORD offBitsSrc;

    DWORD cbBitsSrc;

    DWORD iUsageSrc;

    DWORD dwRop;

    LONG  cxDest;

    LONG  cyDest;

} EMRSTRETCHDIBITS, *PEMRSTRETCHDIBITS;

The EMRSTRETCHDIBITS structure contains members for the StretchDIBits enhanced metafile record.

Members

emr

Base structure for all record types.

rclBounds

Bounding rectangle, in device units.

xDest

Logical x-coordinate of the upper-left corner of the destination rectangle.

yDest

Logical y-coordinate of the upper-left corner of the destination rectangle.

xSrc

Logical x-coordinate of the upper-left corner of the source rectangle.

ySrc

Logical y-coordinate of the upper-left corner of the source rectangle.

cxSrc

Width of source rectangle.

cyScr

Height of source rectangle.

offBmiSrc

Offset to source BITMAPINFO structure.

cbBmiSrc

Size of source BITMAPINFO structure.

offBitsSrc

Offset to source bitmap bits.

cbBitsSrc

Size of source bitmap bits.

iUsageSrc

Value of the bmiColors member of the BITMAPINFO structure. The iUsageSrc member can be either the DIB_PAL_COLORS, DIB_PAL_INDICES, or DIB_RGB_COLORS value.

dwRop

Raster-operation code. These codes define how the color data of the source rectangle is to be combined with the color data of the destination rectangle to achieve the final color.

cxDest

Logical width of destination rectangle

cyDest

Logical height of destination rectangle

See Also

BITMAPINFO, StretchDIBits


EMRTEXT
EMRTEXT  QuickInfo  Overview  Group

typedef struct tagEMRTEXT

{
    POINTL ptlReference;

    DWORD  nChars;

    DWORD  offString;

    DWORD  fOptions;

    RECTL  rcl;

    DWORD  offDx;

} EMRTEXT, *PEMRTEXT;

The EMRTEXT structure contains members for text output.

Members

ptlReference

Logical coordinates of the reference point used to position the string.

nChars

Number of characters in string.

offString

Offset to string.

fOptions

Value specifying how to use the application-defined rectangle. This member can be a combination of the ETO_CLIPPED and ETO_OPAQUE values.

rcl

Optional clipping and/or opaquing rectangle.

offDx

Offset to intercharacter spacing array.

Remarks

The EMRTEXT structure is used as a member in the EMREXTTEXTOUT and EMRPOLYTEXTOUT structures.


Enhanced Metafile Records with No Parameters

typedef struct tagABORTPATH

{

    EMR emr;

} EMRABORTPATH,      *PEMRABORTPATH,
  EMRBEGINPATH,      *PEMRBEGINPATH,
  EMRENDPATH,        *PEMRENDPATH,
  EMRCLOSEFIGURE,    *PEMRCLOSEFIGURE,
  EMRFLATTENPATH,    *PEMRFLATTENPATH,
  EMRWIDENPATH,      *PEMRWIDENPATH,
  EMRSETMETARGN,     *PEMRSETMETARGN,
  EMRSAVEDC,         *PEMRSAVEDC,
  EMRREALIZEPALETTE, *PEMRREALIZEPALETTE;

Contains data for the AbortPath, BeginPath, EndPath, CloseFigure, FlattenPath, WidenPath, SetMetaRgn, SaveDC, and RealizePalette enhanced metafile records.


Enhanced Metafile Records with One Parameter

typedef struct tagEMRSELECTCLIPPATH
{
    EMR   emr;

    DWORD iMode;

} EMRSELECTCLIPPATH,    *PEMRSELECTCLIPPATH,
  EMRSETBKMODE,         *PEMRSETBKMODE,
  EMRSETMAPMODE,        *PEMRSETMAPMODE,
  EMRSETPOLYFILLMODE,   *PEMRSETPOLYFILLMODE,
  EMRSETROP2,           *PEMRSETROP2,
  EMRSETSTRETCHBLTMODE, *PEMRSETSTRETCHBLTMODE,
  EMRSETTEXTALIGN,	      *PEMRSETTEXTALIGN,
  EMRENABLEICM, 	      *PEMRENABLEICM

Contains parameters for the SelectClipPath, SetBkMode, SetPolyFillMode, SetROP2, SetStretchBltMode, SetTextAlign, and EnableICM enhanced metafile records.

Members

emr

Base structure for all record types.

iMode

Value and meaning that varies depending on the function contained in the enhanced metafile record. For a description of this member, see the documentation of the functions contained in this record .

See Also

SelectClipPath, SetBkMode, SetPolyFillMode, SetROP2, SetStretchBltMode, SetTextAlign


ENCORRECTTEXT
ENCORRECTTEXT  QuickInfo

typedef struct _encorrecttext {
    NMHDR nmhdr;     // notification header
    CHARRANGE chrg;  // current selection
    WORD seltyp;     // selection type
} ENCORRECTTEXT;

Contains information about the selected text to be corrected.

Members

seltyp

Value specifying the contents of the new selection. This member is SEL_EMPTY if the selection is empty or one or more of the following values:

Value	Meaning
SEL_TEXT	Text
SEL_OBJECT	At least one OLE object
SEL_MULTICHAR	More than one character of text
SEL_MULTIOBJECT	More than one OLE object


ENDROPFILES [New - Windows NT]
ENDROPFILES  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct _endropfiles {

    NMHDR nmhdr;

    HANDLE hDrop;

    LONG cp;

    BOOL fProtected;

} ENDROPFILES;

The ENDDROPFILES structure contains information associated with an EN_DROPFILES notification message. A rich edit control sends this notification message when it receives a WM_DROPFILES message.

Members

nmhdr

Notification header.

hDrop

Handle to the dropped files list (same as with WM_DROPFILES). This handle is used with the DragFinish, DragQueryFile, and DragQueryPoint functions.

cp

Character position at which the dropped files would be inserted.

fProtected

Boolean value specifying whether the specified character position is protected (TRUE) or not protected (FALSE).

See Also

DragFinish, DragQueryFile, DragQueryPoint, EN_DROPFILES, WM_DROPFILES


ENHMETAHEADER
ENHMETAHEADER  QuickInfo

typedef struct tagENHMETAHEADER { // enmh

    DWORD iType;

    DWORD nSize;

    RECTL rclBounds;

    RECTL rclFrame;

    DWORD dSignature;

    DWORD nVersion;

    DWORD nBytes;

    DWORD nRecords;

    WORD  nHandles;

    WORD  sReserved;

    DWORD nDescription;

    DWORD offDescription;

    DWORD nPalEntries;

    SIZEL szlDevice;

    SIZEL szlMillimeters;

} ENHMETAHEADER;

The ENHMETAHEADER structure contains enhanced-metafile data such as the dimensions of the picture stored in the enhanced metafile, the count of records in the enhanced metafile, the resolution of the device on which the picture was created, and so on.

This structure is always the first record in an enhanced metafile.

Members

iType

Specifies the record type. This member must specify the value assigned to the EMR_HEADER constant.

nSize

Specifies the structure size, in bytes.

rclBounds

Specifies the dimensions, in device units, of the smallest rectangle that can be drawn around the picture stored in the metafile. This rectangle is supplied by graphics device interface (GDI). Its dimensions include the right and bottom edges.

rclFrame

Specifies the dimensions, in .01 millimeter units, of a rectangle that surrounds the picture stored in the metafile. This rectangle must be supplied by the application that creates the metafile. Its dimensions include the right and bottom edges.

dSignature

Specifies a doubleword signature. This member must specify the value assigned to the ENHMETA_SIGNATURE constant.

nVersion

Specifies the metafile version. The current version value is 0x10000.

nBytes

Specifies the size of the enhanced metafile, in bytes.

nRecords

Specifies the number of records in the enhanced metafile.

nHandles

Specifies the number of handles in the enhanced-metafile handle table. (Index zero in this table is reserved.)

sReserved

Reserved; must be zero.

nDescription

Specifies the number of characters in the array that contains the description of the enhanced metafile's contents. This member should be set to zero if the enhanced metafile does not contain a description string.

offDescription

Specifies the offset from the beginning of the ENHMETAHEADER structure to the array that contains the description of the enhanced metafile's contents. This member should be set to zero if the enhanced metafile does not contain a description string.

nPalEntries

Specifies the number of entries in the enhanced metafile's palette.

szlDevice

Specifies the resolution of the reference device, in pixels.

szlMillimeters

Specifies the resolution of the reference device, in millimeters.

See Also

ENHMETARECORD


ENHMETARECORD
ENHMETARECORD  QuickInfo

typedef struct tagENHMETARECORD { // enmr

    DWORD iType;

    DWORD nSize;

    DWORD dParm[1];

} ENHMETARECORD;

The ENHMETARECORD structure contains data that describes a graphics device interface (GDI) function used to create part of a picture in an enhanced-format metafile.

Members

iType

Specifies the record type.

nSize

Specifies the size of the record, in bytes.

dParm

Specifies an array of parameters passed to the GDI function identified by the record.

See Also

ENHMETAHEADER


ENOLEOPFAILED
ENOLEOPFAILED  QuickInfo  Overview  Group

typedef struct {
    NMHDR nmhdr;
    LONG iob;
    LONG lOper;
    HRESULT hr;
} ENOLEOPFAILED;

Contains information about a failed OLE operation.

Members

nmhdr

Notification header.

iob

Object index.

lOper

OLE operation that failed. This can be OLEOP_DOVERB to indicate that IOleObject::DoVerb failed.

hr

Error code returned by the object on the operation.

See Also

EN_OLEOPFAILED, IOleObject::DoVerb


ENPROTECTED [New - Windows NT]
ENPROTECTED  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct _enprotected {

    NMHDR nmhdr;

    _WPAD _wPad1;

    UINT msg;

    _WPAD _wPad2;

    WPARAM wParam;

    LPARAM lParam;

    CHARRANGE chrg;

} ENPROTECTED;

The ENPROTECTED structure contains information associated with an EN_PROTECTED notification message. A rich edit control sends this notification when the user attempts to edit protected text.

Members

nmhdr

Notification header.

msg

Message that triggered the notification.

wParam

wParam parameter of the message.

lParam

lParam parameter of the message.

chrg

Current selection.

See Also

EN_PROTECTED


ENSAVECLIPBOARD
ENSAVECLIPBOARD  QuickInfo  Overview  Group

typedef struct {
    NMHDR nmhdr;
    LONG cObjectCount;
    LONG cch;
} ENSAVECLIPBOARD;

Contains information about objects and text on the clipboard.

Members

nmhdr

Notification header.

cObjectCount

Number of objects on the clipboard.

cch

Number of characters on the clipboard.


ENUM_SERVICE_STATUS
ENUM_SERVICE_STATUS  QuickInfo

typedef struct _ENUM_SERVICE_STATUS { // ess

    LPTSTR lpServiceName;

    LPTSTR lpDisplayName;

    SERVICE_STATUS ServiceStatus;

} ENUM_SERVICE_STATUS, *LPENUM_SERVICE_STATUS;

The ENUM_SERVICE_STATUS structure is used by the EnumDependentServices and EnumServicesStatus functions to return the name of a service in a service control manager database and to return information about that service.

Members

lpServiceName

Points to a null-terminated string that names a service in a service control manager database. The maximum string length is 256 characters. The service control manager database preserves the case of the characters, but service name comparisons are always case insensitive. A slash (/), backslash (\), comma, and space are invalid service name characters.

lpDisplayName

Points to a null-terminated string that is to be used by user interface programs to identify the service. This string has a maximum length of 256 characters. The name is case-preserved in the Service Control Manager. Display name comparisons are always case-insensitive.

ServiceStatus

Specifies a SERVICE_STATUS structure in which status information about the lpServiceName service is returned.

See Also

EnumDependentServices, EnumServicesStatus, SERVICE_STATUS


ENUMLOGFONT
ENUMLOGFONT  QuickInfo

typedef struct tagENUMLOGFONT { // elf

    LOGFONT elfLogFont;

    BCHAR    elfFullName[LF_FULLFACESIZE];

    BCHAR    elfStyle[LF_FACESIZE];

} ENUMLOGFONT;

The ENUMLOGFONT structure defines the attributes of a font, the complete name of a font, and the style of a font.

Members

elfLogFont

Specifies a LOGFONT structure that defines the attributes of a font.

elfFullName

Specifies a unique name for the font. For example, "ABCD Font Company TrueType Bold Italic Sans Serif".

elfStyle

Specifies the style of the font. For example, "Bold Italic".

See Also

EnumFontFamProc, LOGFONT


ENUMLOGFONTEX [New - Windows 95]
ENUMLOGFONTEX  QuickInfo

[New - Windows 95]

typedef struct tagENUMLOGFONTEX {
    LOGFONT  elfLogFont;
    BCHAR  elfFullName[LF_FULLFACESIZE];
    BCHAR  elfStyle[LF_FACESIZE];
    BCHAR  elfScript[LF_FACESIZE];
} ENUMLOGFONTEX;

The ENUMLOGFONTEX structure contains information about an enumerated font.

Members

elfLogFont

Specifies a LOGFONT structure that contains values defining the font attributes.

elfFullName

Specifies a null-terminated string specifying the unique name of the font. For example, "ABC Font Company TrueType Bold Italic Sans Serif".

elfStyle

Specifies a null-terminated string specifying the style of the font. For example, "Bold Italic".

elfScript

Specifies a null-terminated string specifying the script of the font. For example, "Cyrillic".

See Also

EnumFontFamExProc, EnumFontFamiliesEx, LOGFONT


EVENTLOGRECORD
EVENTLOGRECORD  QuickInfo

typedef struct _EVENTLOGRECORD { // evlr

    DWORD  Length;

    DWORD  Reserved;

    DWORD  RecordNumber;

    DWORD  TimeGenerated;

    DWORD  TimeWritten;

    DWORD  EventID;

    WORD   EventType;

    WORD   NumStrings;

    WORD   EventCategory;

    WORD   ReservedFlags;

    DWORD  ClosingRecordNumber;

    DWORD  StringOffset;

    DWORD  UserSidLength;

    DWORD  UserSidOffset;

    DWORD  DataLength;

    DWORD  DataOffset;

    //

    // Then follow:

    //

    // TCHAR SourceName[]

    // TCHAR Computername[]

    // SID   UserSid

    // TCHAR Strings[]

    // BYTE  Data[]

    // CHAR  Pad[]

    // DWORD Length;

    //

} EVENTLOGRECORD;

The EVENTLOGRECORD structure contains information about an event record.

Members

Length

Specifies the length, in bytes, of this event record. Note that this value is stored at both ends of the entry to ease moving forward or backward through the log. The length includes any pad bytes inserted at the end of the record for DWORD alignment.

Reserved

Reserved.

RecordNumber

Contains a record number that can be used with the EVENTLOG_SEEK_READ flag passed in a call to the ReadEventLog function to begin reading at a specified record.

TimeGenerated

The time at which this entry was submitted. This time is measured in the number of seconds elapsed since 00:00:00 January 1, 1970.

TimeWritten

Specifies the time at which this entry was received by the service to be written to the logfile. This time is measured in the number of seconds elapsed since 00:00:00 January 1, 1970.

EventID

Identifies the event. This is specific to the source that generated the event log entry, and is used, together with SourceName, to identify a message in a message file that is presented to the user while viewing the log.

EventType

Specifies the type of event. This member can be one of the following values:

Value	Meaning
EVENTLOG_ERROR_TYPE	Error event
EVENTLOG_WARNING_TYPE	Warning event
EVENTLOG_INFORMATION_TYPE	Information event
EVENTLOG_AUDIT_SUCCESS	Success Audit event
EVENTLOG_AUDIT_FAILURE	Failure Audit event
For more information about event types, see Event Logging.

NumStrings

Specifies the number of strings present in the log (at the position indicated by StringOffset). These strings are merged into the message before it is displayed to the user.

EventCategory

Specifies a subcategory for this event. This subcategory is source specific.

ReservedFlags

Reserved.

ClosingRecordNumber

Reserved.

StringOffset

Specifies the offset of the strings within this event log entry.

UserSidLength

Specifies the length, in bytes, of the UserSid member. This value can be zero if no security identifier was provided.

UserSidOffset

Specifies the offset of the security identifier within this event record.

DataLength

Specifies the length, in bytes, of the event-specific data (at the position indicated by DataOffset).

DataOffset

Specifies the offset of the event-specific information within this log. This information could be something specific (a disk driver might log the number of retries, for example), followed by binary information specific to the event being logged and to the source that generated the entry.

SourceName

Contains the variable-length null-terminated string specifying the name of the source (application, service, driver, subsystem) that generated the entry. This is the name used to retrieve from the registry the name of the file containing the message strings for this source. It is used, together with the event identifier, to get the message string that describes this event.

Computername

Contains the variable-length null-terminated string specifying the name of the computer that generated this event. There may also be some pad bytes after this field to ensure that the UserSid is aligned on a DWORD boundary.

UserSid

Specifies the security identifier of the active user at the time this event was logged. This member may be empty if the UserSidLength member is zero.

The defined members are followed by the replacement strings for the message identified by the event identifier, the binary information, some pad bytes to make sure the full entry is on a DWORD boundary, and finally the length of the log entry again. Because the strings and the binary information can be of any length, no structure members are defined to reference them.

The event identifier together with SourceName and a language identifier identify a message string that describes the event in more detail. The strings are used as replacement strings and are merged into the message string to make a complete message. The message strings are contained in a message file specified in the source entry in the registry.

The binary information is information that is specific to the event. It could be the contents of the processor registers when a device driver got an error, a dump of an invalid packet that was received from the network, a dump of all the structures in a program (when the data area was detected to be corrupt), and so on. This information should be useful to the writer of the device driver or the application in tracking down bugs or unauthorized breaks into the application.

See Also

ReadEventLog


EVENTMSG
EVENTMSG  QuickInfo

typedef struct tagEVENTMSG {    // em

    UINT  message;

    UINT  paramL;

    UINT  paramH;

    DWORD time;

    HWND  hwnd;

} EVENTMSG;

The EVENTMSG structure contains information about a hardware message sent to the system message queue. This structure is used to store message information for the JournalPlaybackProc callback function.

Members

message

Specifies the message.

paramL

Specifies additional information about the message. The exact meaning depends on the message value.

paramH

Specifies additional information about the message. The exact meaning depends on the message value.

time

Specifies the time at which the message was posted.

hwnd

Identifies the window to which the message was posted.

See Also

JournalPlaybackProc, SetWindowsHookEx


EXCEPTION_DEBUG_INFO
EXCEPTION_DEBUG_INFO  QuickInfo

typedef struct _EXCEPTION_DEBUG_INFO { // exdi

    EXCEPTION_RECORD ExceptionRecord;

    DWORD dwFirstChance;

} EXCEPTION_DEBUG_INFO;

The EXCEPTION_DEBUG_INFO structure contains exception information that can be used by a debugger.

Members

ExceptionRecord

Contains an EXCEPTION_RECORD structure with information specific to the exception. This includes the exception code, flags, address, a pointer to a related exception, extra parameters, and so on.

dwFirstChance

Indicates whether the debugger has previously encountered the exception specified by the ExceptionRecord member. If the dwFirstChance member is nonzero, this is the first time the debugger has encountered the exception. Debuggers typically handle breakpoint and single-step exceptions when they are first encountered. If this member is zero, the debugger has previously encountered the exception. This occurs only if, during the search for structured exception handlers, either no handler was found or the exception was continued.

See Also

DEBUG_EVENT, EXCEPTION_RECORD


EXCEPTION_POINTERS
EXCEPTION_POINTERS  QuickInfo

typedef struct _EXCEPTION_POINTERS { // exp

    PEXCEPTION_RECORD ExceptionRecord;

    PCONTEXT ContextRecord;

} EXCEPTION_POINTERS;

The EXCEPTION_POINTERS structure contains an exception record with a machine-independent description of an exception and a context record with a machine-dependent description of the processor context at the time of the exception.

Members

ExceptionRecord

Points to an EXCEPTION_RECORD structure that contains a machine-independent description of the exception.

ContextRecord

Points to a CONTEXT structure that contains a processor-specific description of the state of the processor at the time of the exception.

See Also

GetExceptionInformation, CONTEXT, EXCEPTION_RECORD


EXCEPTION_RECORD
EXCEPTION_RECORD  QuickInfo

typedef struct _EXCEPTION_RECORD { // exr

    DWORD ExceptionCode;

    DWORD ExceptionFlags;

    struct _EXCEPTION_RECORD *ExceptionRecord;

    PVOID ExceptionAddress;

    DWORD NumberParameters;

    DWORD ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];

} EXCEPTION_RECORD;

The EXCEPTION_RECORD structure describes an exception.

Members

ExceptionCode

Specifies the reason the exception occurred. This is the code generated by a hardware exception, or the code specified in the RaiseException function for a software-generated exception. Following are the exception codes likely to occur due to common programming errors:

Value	Meaning
EXCEPTION_ACCESS_VIOLATION
	The thread tried to read from or write to a virtual address for which it does not have the appropriate access.
EXCEPTION_ARRAY_BOUNDS_EXCEEDED
	The thread tried to access an array element that is out of bounds and the underlying hardware supports bounds checking.
EXCEPTION_BREAKPOINT
	A breakpoint was encountered.
EXCEPTION_DATATYPE_MISALIGNMENT
	The thread tried to read or write data that is misaligned on hardware that does not provide alignment. For example, 16-bit values must be aligned on 2-byte boundaries; 32-bit values on 4-byte boundaries, and so on.
EXCEPTION_FLT_DENORMAL_OPERAND
	One of the operands in a floating-point operation is denormal. A denormal value is one that is too small to represent as a standard floating-point value.
EXCEPTION_FLT_DIVIDE_BY_ZERO
	The thread tried to divide a floating-point value by a floating-point divisor of zero.
EXCEPTION_FLT_INEXACT_RESULT
	The result of a floating-point operation cannot be represented exactly as a decimal fraction.
EXCEPTION_FLT_INVALID_OPERATION
	This exception represents any floating-point exception not included in this list.
EXCEPTION_FLT_OVERFLOW
	The exponent of a floating-point operation is greater than the magnitude allowed by the corresponding type.
EXCEPTION_FLT_STACK_CHECK
	The stack overflowed or underflowed as the result of a floating-point operation.
EXCEPTION_FLT_UNDERFLOW
	The exponent of a floating-point operation is less than the magnitude allowed by the corresponding type.
EXCEPTION_ILLEGAL_INSTRUCTION
	The thread tried to execute an invalid instruction.
EXCEPTION_IN_PAGE_ERROR
	The thread tried to access a page that was not present, and the system was unable to load the page. For example, this exception might occur if a network connection is lost while running a program over the network.
EXCEPTION_INT_DIVIDE_BY_ZERO
	The thread tried to divide an integer value by an integer divisor of zero.
EXCEPTION_INT_OVERFLOW
	The result of an integer operation caused a carry out of the most significant bit of the result.
EXCEPTION_INVALID_DISPOSITION
	An exception handler returned an invalid disposition to the exception dispatcher. Programmers using a high-level language such as C should never encounter this exception.
EXCEPTION_NONCONTINUABLE_EXCEPTION
	The thread tried to continue execution after a noncontinuable exception occurred.
EXCEPTION_PRIV_INSTRUCTION
	The thread tried to execute an instruction whose operation is not allowed in the current machine mode.
EXCEPTION_SINGLE_STEP
	A trace trap or other single-instruction mechanism signaled that one instruction has been executed.
EXCEPTION_STACK_OVERFLOW
	The thread used up its stack.
Another exception code is likely to occur when debugging console processes. It does not arise because of a programming error. The DBG_CONTROL_C exception code occurs when CTRL+C is input to a console process that handles CTRL+C signals and is being debugged. This exception code is not meant to be handled by applications. It is raised only for the benefit of the debugger, and is raised only when a debugger is attached to the console process.

ExceptionFlags

Specifies the exception flags. This member can be either zero, indicating a continuable exception, or EXCEPTION_NONCONTINUABLE indicating a noncontinuable exception. Any attempt to continue execution after a noncontinuable exception causes the EXCEPTION_NONCONTINUABLE_EXCEPTION exception.

ExceptionRecord

Points to an associated EXCEPTION_RECORD structure. Exception records can be chained together to provide additional information when nested exceptions occur.

ExceptionAddress

Specifies the address where the exception occurred.

NumberParameters

Specifies the number of parameters associated with the exception. This is the number of defined elements in the ExceptionInformation array.

ExceptionInformation

Specifies an array of additional 32-bit arguments that describe the exception. The RaiseException function can specify this array of arguments. For most exception codes, the array elements are undefined. For the following exception code, the array elements are defined as follows:

Exception code	Array contents
EXCEPTION_ACCESS_VIOLATION
	The first element of the array contains a read-write flag that indicates the type of operation that caused the access violation. If this value is zero, the thread attempted to read the inaccessible data. If this value is 1, the thread attempted to write to an inaccessible address.
	The second array element specifies the virtual address of the inaccessible data.
See Also

EXCEPTION_DEBUG_INFO, EXCEPTION_POINTERS, GetExceptionInformation, RaiseException, UnhandledExceptionFilter


EXIT_PROCESS_DEBUG_INFO
EXIT_PROCESS_DEBUG_INFO  QuickInfo

typedef struct _EXIT_PROCESS_DEBUG_INFO { // epdi

    DWORD dwExitCode;

} EXIT_PROCESS_DEBUG_INFO;

The EXIT_PROCESS_DEBUG_INFO structure contains an exiting process's exit code.

Members

dwExitCode

Specifies the exit code for the process.

See Also

DEBUG_EVENT


EXIT_THREAD_DEBUG_INFO
EXIT_THREAD_DEBUG_INFO  QuickInfo

typedef struct _EXIT_THREAD_DEBUG_INFO { // etdi

    DWORD dwExitCode;

} EXIT_THREAD_DEBUG_INFO;

The EXIT_THREAD_DEBUG_INFO structure contains an exiting thread's exit code.

Members

dwExitCode

Specifies the exit code for the thread.

See Also

DEBUG_EVENT


EXT_BUTTON
EXT_BUTTON  QuickInfo

typedef struct _EXT_BUTTON { /* extbtn */

    WORD idCommand;

    WORD idsHelp;

    WORD fsStyle;

} EXT_BUTTON;

The EXT_BUTTON structure contains information about a button that a File Manager extension dynamic-link library is adding to the toolbar of File Manager.

Members

idCommand

Specifies the command identifier for the button.

idsHelp

Specifies the identifier of the Help string for the button.

fsStyle

Specifies the style of the button.

See Also

FMEVENT_TOOLBARLOAD, FMS_TOOLBARLOAD


EXTLOGFONT
EXTLOGFONT  QuickInfo

typedef struct tagEXTLOGFONT {

    LOGFONT elfLogFont;

    BCHAR    elfFullName[LF_FULLFACESIZE];

    BCHAR    elfStyle[LF_FACESIZE];

    DWORD   elfVersion;

    DWORD   elfStyleSize;

    DWORD   elfMatch;

    DWORD   elfReserved;

    BYTE    elfVendorId[ELF_VENDOR_SIZE];

    DWORD   elfCulture;

    PANOSE  elfPanose;

} EXTLOGFONT;

The EXTLOGFONT structure defines the attributes of a font.

Members

elfLogFont

Specifies some of the attributes of the given font. This member is a LOGFONT structure.

elfFullName

Specifies a unique name for the font (for example, ABCD Font Company TrueType Bold Italic Sans Serif).

elfStyle

Specifies the style of the font (for example, Bold Italic).

elfVersion

Reserved. Must be zero.

elfStyleSize

This member only has meaning for hinted fonts. It specifies the point size at which the font is hinted. If set to zero, which is its default value, the font is hinted at the point size corresponding to the lfHeight member of the LOGFONT structure specified by elfLogFont.

elfMatch

A unique identifier for an enumerated font. This will be filled in by the graphics device interface (GDI) upon font enumeration.

elfReserved

Reserved; must be zero.

elfVendorId

A 4-byte identifier of the font vendor.

elfCulture

Reserved; must be zero.

elfPanose

A PANOSE structure that specifies the shape of the font. If all members of this structure are set to zero, the elfPanose member is ignored by the font mapper.

See Also

LOGFONT, PANOSE


EXTLOGPEN
EXTLOGPEN  QuickInfo

typedef struct tagEXTLOGPEN { // exlp

    UINT     elpPenStyle;

    UINT     elpWidth;

    UINT     elpBrushStyle;

    COLORREF elpColor;

    LONG     elpHatch;

    DWORD    elpNumEntries;

    DWORD    elpStyleEntry[1];

} EXTLOGPEN;

The EXTLOGPEN structure defines the pen style, width, and brush attributes for an extended pen. This structure is used by the GetObject function when it retrieves a description of a pen that was created when an application called the ExtCreatePen function.

Members

elpPenStyle

Specifies a combination of pen type, style, end cap style, and join style. The values from each category can be retrieved by using a bitwise AND with the appropriate mask.

The elpPenStyle member masked with PS_TYPE_MASK has one of the following pen type values:

Value	Meaning
PS_GEOMETRIC	The pen is geometric.
PS_COSMETIC	The pen is cosmetic.
The elpPenStyle member masked with PS_STYLE_MASK has one of the following pen styles values:

Value	Meaning
PS_SOLID	The pen is solid.
PS_DASH	The pen is dashed.
PS_DOT	The pen is dotted.
PS_DASHDOT	The pen has alternating dashes and dots.
PS_DASHDOTDOT	The pen has alternating dashes and double dots.
PS_NULL	The pen is invisible.
PS_USERSTYLE	The pen will use a styling array supplied by the user.
PS_INSIDEFRAME	The pen is solid. When this pen is used in any GDI drawing function that takes a bounding rectangle, the dimensions of the figure are shrunk so that it fits entirely in the bounding rectangle, taking into account the width of the pen. This applies only to PS_GEOMETRIC pens.
The following category applies only to PS_GEOMETRIC pens. The elpPenStyle member masked with PS_ENDCAP_MASK has one of the following end cap values:

Value	Meaning
PS_ENDCAP_ROUND	Line end caps are round.
PS_ENDCAP_SQUARE	Line end caps are square.
PS_ENDCAP_FLAT	Line end caps are flat.
The following category applies only to PS_GEOMETRIC pens. The elpPenStyle member masked with PS_JOIN_STYLE has one of the following join values:

Value	Meaning
PS_JOIN_BEVEL	Line joins are beveled.
PS_JOIN_MITER	Line joins are mitered when they are within the current SetMiterLimit limit. A join is beveled when it would exceed the limit.
PS_JOIN_ROUND	Line joins are round.
elpWidth

Specifies the width of the pen. If the elpPenStyle member specifies geometric lines, this value is the width, in logical units, of the line. Otherwise, the lines are cosmetic and this value is 1.

elpBrushStyle

Specifies the brush style of the pen. The elpBrushStyle member values can be one of the following:

Value	Description
BS_DIBPATTERN	Specifies a pattern brush defined by a device-independent bitmap (DIB) specification. If elpBrushStyle is BS_DIBPATTERN, the elpHatch member contains a handle to a packed DIB.
BS_DIBPATTERNPT	Specifies a pattern brush defined by a device-independent bitmap (DIB) specification. If elpBrushStyle is BS_DIBPATTERNPT, the elpHatch member contains a pointer to a packed DIB.
BS_HATCHED	Specifies a hatched brush.
BS_HOLLOW	Specifies a hollow or NULL brush.
BS_PATTERN	Specifies a pattern brush defined by a memory bitmap.
BS_SOLID	Specifies a solid brush.
elpColor

If elpBrushStyle is BS_SOLID or BS_HATCHED, elpColor specifies the color in which the pen is to be drawn. For BS_HATCHED, the SetBkMode and SetBkColor functions determine the background color.

If elpBrushStyle is BS_HOLLOW or BS_PATTERN, elpColor is ignored.

If elpBrushStyle is BS_DIBPATTERN or BS_DIBPATTERNPT, the low-order word of elpColor specifies whether the bmiColors members of the BITMAPINFO structure contain explicit red, green, blue (RGB) values or indexes into the currently realized logical palette. The elpColor value must be one of the following:

Value	Meaning
DIB_PAL_COLORS	The color table consists of an array of 16-bit indexes into the currently realized logical palette.
DIB_RGB_COLORS	The color table contains literal RGB values.
elpHatch

If elpBrushStyle is BS_PATTERN, elpHatch is a handle to the bitmap that defines the pattern.

If elpBrushStyle is BS_SOLID or BS_HOLLOW, elpHatch is ignored.

If elpBrushStyle is BS_DIBPATTERN, the elpHatch member is a handle to a packed DIB. To obtain this handle, an application calls the GlobalAlloc function to allocate a block of global memory and then fills the memory with the packed DIB. A packed DIB consists of a BITMAPINFO structure immediately followed by the array of bytes that define the pixels of the bitmap.

If elpBrushStyle is BS_DIBPATTERNPT, the elpHatch member is a pointer to a packed DIB.

If elpBrushStyle is BS_HATCHED, the elpHatch member specifies the orientation of the lines used to create the hatch. It can be any one of the following values:

Value	Meaning
HS_BDIAGONAL	45-degree upward hatch (left to right)
HS_CROSS	Horizontal and vertical crosshatch
HS_DIAGCROSS	45-degree crosshatch
HS_FDIAGONAL	45-degree downward hatch (left to right)
HS_HORIZONTAL	Horizontal hatch
HS_VERTICAL	Vertical hatch
elpNumEntries

Specifies the number of entries in the style array in the elpStyleEntry member. This value is zero if elpPenStyle does not specify PS_USERSTYLE.

elpStyleEntry

Specifies a user-supplied style array. The array is specified with a finite length, but it is used as if it repeated indefinitely. The first entry in the array specifies the length of the first dash. The second entry specifies the length of the first gap. Thereafter, lengths of dashes and gaps alternate.

If elpWidth specifies geometric lines, the lengths are in logical units. Otherwise, the lines are cosmetic and lengths are in device units.

See Also

BITMAPINFO, ExtCreatePen, GetObject, GlobalAlloc, SetBkColor, SetBkMode


FILETIME
FILETIME  QuickInfo

typedef struct _FILETIME { // ft

    DWORD dwLowDateTime;

    DWORD dwHighDateTime;

} FILETIME;

The FILETIME structure is a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601.

Members

dwLowDateTime

Specifies the low-order 32 bits of the file time.

dwHighDateTime

Specifies the high-order 32 bits of the file time.

See Also

CompareFileTime, DosDateTimeToFileTime, FileTimeToDosDateTime, FileTimeToLocalFileTime, FileTimeToSystemTime, GetFileTime, LocalFileTimeToFileTime, SetFileTime, SystemTimeToFileTime


FILTERKEYS
FILTERKEYS  QuickInfo  Overview  Group

typedef struct tagFILTERKEYS {     // fk

    UINT  cbSize;

    DWORD dwFlags;

    DWORD iWaitMSec;

    DWORD iDelayMSec;

    DWORD iRepeatMSec;

    DWORD iBounceMSec;

} FILTERKEYS;

The FILTERKEYS structure contains information about the FilterKeys accessibility feature, which allow a user with disabilities to set the keyboard repeat rate (RepeatKeys), acceptance delay (SlowKeys), and bounce rate (BounceKeys).

Members

cbSize

Specifies the structure size, in bytes.

dwFlags

A set of bit flags that specify properties of the FilterKeys feature. The following bit-flag values are defined:

Value	Meaning
FKF_AVAILABLE	The FilterKeys features are available.
FKF_CLICKON	The computer makes a click sound when a key is pressed or accepted, that is, if SlowKeys is on, the acceptance is separated from the press and gets a separate click..
FKF_FILTERKEYSON	The FilterKeys features are on.
FKF_HOTKEYACTIVE	The user can turn the FilterKeys feature on and off by holding down the SHIFT key for eight seconds.
FKF_HOTKEYSOUND	If this flag is set, the computer plays a siren sound when the user turns the FilterKeys feature on or off by using the hot key.
FKF_CONFIRMHOTKEY	Windows 95 only: A confirmation dialog box appears when the the FilterKeys features are activated by using the hot key.
FKF_INDICATOR	Windows 95 only: A visual indicator is displayed when the FilterKeys features are on.
iWaitMSec

Specifies the length of time, in milliseconds, that the user must hold down a key before it is accepted by the computer.

iDelayMSec

Specifies the length of time, in milliseconds, that the user must hold down a key before it begins to repeat.

iRepeatMSec

Specifies the length of time, in milliseconds, between each repetition of the keystroke.

iBounceMSec

Specifies the amount of time, in milliseconds, that must elapse after releasing a key before the computer will accept a subsequent press of the same key.

Remarks

Use a FILTERKEYS structure when calling the SystemParametersInfo function with the wAction parameter set to the SPI_GETFILTERKEYS or SPI_SETFILTERKEYS value. When using SPI_GETFILTERKEYS,you must specify the cbSize member of the FILTERKEYS structure; the SystemParametersInfo function fills the remaining members. Specify all structure members when using the SPI_SETFILTERKEYS value.

Either iDelayMSec or iBounceMSec, or both, must be zero; they cannot both be non-zero at the same time.

If iBounceMSec is non-zero, the BounceKeys feature is on and the SlowKeys feature is off (the iDelayMSec value is ignored). If iBounceMSec is zero, the BounceKeys feature is off.

If iDelayMSec is nonzero and iBounceMSec is zero, the SlowKeys feature is on; otherwise, it is off.

See Also

SystemParametersInfo


FIND_NAME_BUFFER
FIND_NAME_BUFFER  QuickInfo

typedef struct _FIND_NAME_BUFFER { // fnb

    UCHAR length;

    UCHAR access_control;

    UCHAR frame_control;

    UCHAR destination_addr[6];

    UCHAR source_addr[6];

    UCHAR routing_info[18];

} FIND_NAME_BUFFER;

The FIND_NAME_BUFFER structure contains information about a local network session. One or more FIND_NAME_BUFFER structures follows a FIND_NAME_HEADER structure when an application specifies the NCBFINDNAME command in the ncb_command member of the NCB structure.

Members

length

Specifies the length, in bytes, of the FIND_NAME_BUFFER structure. Although this structure always occupies 33 bytes, not all of the structure is necessarily valid.

access_control

Specifies the access control for the LAN header.

frame_control

Specifies the frame control for the LAN header.

destination_addr

Specifies the destination address of the remote node where the name was found.

source_addr

Specifies the source address for the remote node where the name was found.

routing_info

Specifies additional routing information.

See Also

FIND_NAME_HEADER, NCB


FIND_NAME_HEADER
FIND_NAME_HEADER  QuickInfo

typedef struct _FIND_NAME_HEADER { // fnh

    WORD  node_count;

    UCHAR reserved;

    UCHAR unique_group;

} FIND_NAME_HEADER;

The FIND_NAME_HEADER structure contains information about a network name. This structure is followed by as many FIND_NAME_BUFFER structures as are required to describe the name.

Members

node_count

Specifies the number of nodes on which the specified name was found. This structure is followed by the number of FIND_NAME_BUFFER structures specified by the node_count member.

reserved

Reserved.

unique_group

Specifies whether the name is unique. This value is 0 to specify a unique name or 1 to specify a group.

Remarks

The FIND_NAME_HEADER structure is pointed to by the ncb_buffer member of the NCB structure when an application issues an NCBFINDNAME command.

See Also

FIND_NAME_BUFFER, NCB


FINDREPLACE
FINDREPLACE  QuickInfo

typedef struct {    // fr

    DWORD        lStructSize;

    HWND         hwndOwner;

    HINSTANCE    hInstance;

    DWORD        Flags;

    LPTSTR        lpstrFindWhat;

    LPTSTR        lpstrReplaceWith;

    WORD         wFindWhatLen;

    WORD         wReplaceWithLen;

    LPARAM        lCustData;

    LPFRHOOKPROC lpfnHook;

    LPCTSTR       lpTemplateName;

} FINDREPLACE;

The FINDREPLACE structure contains information the operating system uses to initialize the system-defined Find and Replace dialog boxes. After the user closes the dialog box, the system returns information about the user-defined find or replace selections in this structure.

Members

lStructSize

Specifies the length, in bytes, of the structure.

hwndOwner

Identifies the window that owns the dialog box. This member can be any valid window handle, but it must not be NULL.

hInstance

Identifies a data block that contains a dialog box template specified by the lpTemplateName member. This member is used only if the Flags member specifies the FR_ENABLETEMPLATE flag; otherwise, this member is ignored.

Flags

Specifies the dialog box initialization flags. This member may be a combination of the following flags:

Flag	Meaning
FR_DIALOGTERM
	Indicates that the dialog box is closing. The window handle returned by the FindText or ReplaceText function is not valid if this flag is specified.
FR_DOWN
	Determines the direction of searches through a document. If this flag is used, the search direction is down; if the flag is not used, the search direction is up. Initially, this flag specifies the state of the Up and Down controls; after the user closes the dialog box, this flag specifies the user's selection.
FR_ENABLEHOOK
	Enables the hook function specified in the lpfnHook member of this structure. This flag is used only to initialize the dialog box.
FR_ENABLETEMPLATE
	Causes the system to create the dialog box by using the dialog box template identified by the hInstance and lpTemplateName members. This flag is used only to initialize the dialog box.
FR_ENABLETEMPLATEHANDLE
	Indicates that the hInstance member identifies a data block that contains a preloaded dialog box template. The system ignores the lpTemplateName member if this flag is specified.
FR_FINDNEXT
	Indicates that the application should search for the next occurrence of the string specified by the lpstrFindWhat member.
FR_HIDEUPDOWN
	Causes the system to hide the Direction check box and the Up and Down controls.
FR_HIDEMATCHCASE
	Causes the system to hide the Match Case check box.
FR_HIDEWHOLEWORD
	Causes the system to hide the Match Whole Word Only check box.
FR_MATCHCASE
	Indicates case-sensitive searches.
FR_NOMATCHCASE
	Disables the Match Case check box. This flag is used only to initialize the dialog box.
FR_NOUPDOWN
	Disables the direction radio buttons. This flag is used only to initialize the dialog box.
FR_NOWHOLEWORD
	Disables the Whole Word check box. This flag is used only to initialize the dialog box.
FR_REPLACE
	Indicates that the application should replace the current occurrence of the string specified in the lpstrFindWhat member with the string specified in the lpstrReplaceWith member.
FR_REPLACEALL
	Indicates that the application should replace all occurrences of the string specified in the lpstrFindWhat member with the string specified in the lpstrReplaceWith member.
FR_SHOWHELP
	Causes the dialog box to show the Help button. The hwndOwner member must not be NULL if this flag is specified.
FR_WHOLEWORD
	Checks the Whole Word check box. Only whole words matching the search string will be considered.
lpstrFindWhat

Specifies the string to search for. If there is a string specified when the dialog box starts, the dialog box initializes the Find What: text control with this string. If the FR_FINDNEXT flag is specified when the dialog box is opened, the application should search for an occurrence of this string by using the FR_DOWN, FR_WHOLEWORD, and FR_MATCHCASE flags to further define the direction and type of search. The application must allocate a buffer for the string. This buffer should be at least 80 characters long.

lpstrReplaceWith

Specifies the replacement string for replace operations. The FindText function ignores this member.

wFindWhatLen

Specifies the length, in bytes, of the buffer pointed to by the lpstrFindWhat member.

wReplaceWithLen

Specifies the length, in bytes, of the buffer pointed to by the lpstrReplaceWith member.

lCustData

Specifies application-defined data the system passes to the hook function identified by the lpfnHook member. The system passes the data in the lParam parameter of the WM_INITDIALOG message.

lpfnHook

Points to a hook function that processes messages intended for the dialog box. An application must specify the FR_ENABLEHOOK flag in the Flags member to enable the function; otherwise, the system ignores this member. The hook function should return FALSE to pass a message on to the standard dialog box procedure or TRUE to discard the message.

If the hook function returns FALSE in response to the WM_INITDIALOG message, it is responsible for displaying the dialog box, which is done by calling the ShowWindow and UpdateWindow functions. (These calls should be placed after any other paint operations). The following code provides an example:

    // we've returned FALSE in response to WM_INITDIALOG

    // we've performed any other paint operations

    // now we display the dialog box

    ShowWindow(hDlg, SW_SHOWNORMAL);

    UpdateWindow(hDlg);

If the hook function returns FALSE in response to the WM_INITDIALOG message but fails to display the dialog, the dialog box will not be shown.

lpTemplateName

Points to a null-terminated string that names the dialog box template resource to be substituted for the standard dialog box template. An application can use the MAKEINTRESOURCE macro for numbered dialog resources. This member is used only if the Flags member specifies the FR_ENABLETEMPLATE flag; otherwise, this member is ignored.

See Also

FindText, MAKEINTRESOURCE, ReplaceText, ShowWindow, UpdateWindow, WM_INITDIALOG


FINDTEXT [New - Windows NT]
FINDTEXT  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct _findtext {

    CHARRANGE chrg;

    LPSTR lpstrText;

} FINDTEXT;

The FINDTEXT structure contains information about text to search for in a rich edit control. This structure is used with the EM_FINDTEXT message.

Members

chrg

Range to search.

lpstrText

Null-terminated string to find.

See Also

EM_FINDTEXT


FINDTEXTEX
FINDTEXTEX  QuickInfo  Overview  Group

typedef struct _findtextex {
    CHARRANGE chrg;      // range to search
    LPSTR lpstrText;     // null-terminated string to find
    CHARRANGE chrgText;  // range in which text is found
} FINDTEXTEX;

Contains information about text to search for in a rich edit control. This structure is used with the EM_FINDTEXTEX message.


FIXED
FIXED  QuickInfo

typedef struct _FIXED { // fix

    WORD  fract;

    short value;

} FIXED;

The FIXED structure contains the integral and fractional parts of a fixed-point real number.

Members

fract

Specifies the fractional part of the number.

value

Specifies the integer part of the number.

Remarks

The FIXED structure is used to describe the elements of the MAT2 structure.

See Also

MAT2


FMS_GETDRIVEINFO
FMS_GETDRIVEINFO  QuickInfo

typedef struct _FMS_GETDRIVEINFO { /* fmsgdi */

    DWORD dwTotalSpace;

    DWORD dwFreeSpace;

    TCHAR  szPath[260];

    TCHAR  szVolume[14];

    TCHAR  szShare[128];

} FMS_GETDRIVEINFO;

The FMS_GETDRIVEINFO structure contains information about the drive selected in the active File Manager window (the directory window or the Search Results window).

Members

dwTotalSpace

Specifies the total amount of storage space, in bytes, on the disk associated with the drive.

dwFreeSpace

Specifies the amount of free storage space, in bytes, on the disk associated with the drive.

szPath

Specifies the null-terminated path of the current directory.

szVolume

Specifies the null-terminated volume label of the disk associated with the drive.

szShare

Specifies the null-terminated name of the sharepoint (if the drive is being accessed through a network).

See Also

FMExtensionProc, FM_GETDRIVEINFO


FMS_GETFILESEL
FMS_GETFILESEL  QuickInfo

typedef struct _FMS_GETFILESEL { /* fmsgfs */

    FILETIME ftTime;

    DWORD    dwSize;

    BYTE     bAttr;

    TCHAR     szName[260];

} FMS_GETFILESEL;

The FMS_GETFILESEL structure contains information about a selected file in the active File Manager window (the directory window or the Search Results window).

Members

ftTime

Specifies the time and date the file was created.

dwSize

Specifies the size, in bytes, of the file.

bAttr

Specifies the attributes of the file.

szName

Specifies the null-terminated full path and filename of the selected file.

See Also

FMExtensionProc


FMS_LOAD
FMS_LOAD  QuickInfo

typedef struct _FMS_LOAD { /* fmsld */

    DWORD dwSize;

    TCHAR  szMenuName[MENU_TEXT_LEN];

    HMENU hMenu;

    UINT  wMenuDelta;

} FMS_LOAD;

The FMS_LOAD structure contains information that File Manager uses to add a custom menu provided by a File Manager extension DLL. The structure also provides a delta value that the extension DLL can use to manipulate the custom menu after File Manager has loaded the menu.

Members

dwSize

Specifies the length, in bytes, of the structure.

szMenuName

Specifies the null-terminated name for a menu item that appears on the menu bar in File Manager.

hMenu

Identifies the pop-up menu added to the menu bar in File Manager.

wMenuDelta

Specifies the menu-item delta value. To avoid conflicts with its own menu items, File Manager renumbers the menu-item identifiers in the pop-up menu identified by the hMenu member by adding this delta value to each identifier. An extension DLL that must modify a menu item must identify the item by adding the delta value to the menu item's identifier. The value of this member can vary from session to session.

See Also

FMExtensionProc


FMS_TOOLBARLOAD
FMS_TOOLBARLOAD  QuickInfo

typedef struct _FMS_TOOLBARLOAD { /* fmstbl */

    DWORD        dwSize;

    LPEXT_BUTTON lpButtons;

    WORD         cButtons;

    WORD         cBitmaps;

    WORD         idBitmap;

    HBITMAP      hBitmap;

} FMS_TOOLBARLOAD;

The FMS_TOOLBARLOAD structure contains information about custom buttons to be added to the File Manager toolbar. The buttons are provided by a File Manager extension DLL.

Members

dwSize

Specifies the size, in bytes, of the structure. File Manager sets the size before calling the extension and checks the size after the extension procedure returns.

lpButtons

Points to an array of EXT_BUTTON structures that specify the style, command identifier, and Help string identifier for each toolbar button.

cButtons

Specifies the number of EXT_BUTTON structures in the array pointed to by the lpButtons member. This number equals the number of buttons and separators to add to the toolbar.

cBitmaps

Specifies the number of buttons represented by the given bitmap.

idBitmap

Specifies the identifier of a bitmap resource in the executable file for the extension DLL. The bitmap resource contains images for the number of buttons specified by cBitmaps. File Manager loads the bitmap resource, then uses it to display the buttons.

hBitmap

Specifies the handle of a bitmap that the File Manager will use to obtain and display button images if idBitmap is 0.

See Also

FMEVENT_TOOLBARLOAD, EXT_BUTTON


FOCUS_EVENT_RECORD
FOCUS_EVENT_RECORD  QuickInfo  Overview  Group

typedef struct _FOCUS_EVENT_RECORD { // fer

    BOOL bSetFocus;

} FOCUS_EVENT_RECORD;

The FOCUS_EVENT_RECORD structure is used to report focus events in a console INPUT_RECORD structure. These events are used internally and should be ignored.

Members

bSetFocus

Used internally.

See Also

INPUT_RECORD


FONTSIGNATURE [New - Windows 95]
FONTSIGNATURE  QuickInfo  Overview  Group

[New - Windows 95]

typedef struct tagFONTSIGNATURE {
    DWORD  fsUsb[4];
    DWORD  fsCsb[2];
} FONTSIGNATURE;

The FONTSIGNATURE structure contains information identifying the code-pages and Unicode subranges for which a given font provides glyphs.

Members

fsUsb

A 128-bit Unicode subset bitfield (USB) identifying up to 126 Unicode subranges. Each bit, except the two most significant bits, represents a single subrange. The most significant bit is always 1 and identifies the bitfield as a font signature; the second most significant bit is reserved and must be 0. Unicode subranges are numbered in accordance with the ISO 10646 standard.

fsCsb

A 64-bit, code-page bitfield (CPB) that identifies a specific character set or code-page. Windows code-pages are in the lower 32 bits of this bitfield. The high 32 are used for non-Windows code-pages. For more information, see Code-Page Bitfields.

Remarks

GDI relies on Windows code-pages fitting within a 32-bit value. Furthermore, the highest two bits within this value are reserved for GDI internal use and may not be assigned to code-pages.


FORM_INFO_1
FORM_INFO_1  QuickInfo

typedef struct _FORM_INFO_1 { // fi1

    DWORD Flags;

    LPTSTR pName;

    SIZEL  Size;

    RECTL  ImageableArea;

} FORM_INFO_1;

The FORM_INFO_1 structure contains information about a print form. The information includes the print form's origin, its name, its dimensions, and the dimensions of its printable area.

Members

Flags

A set of bit-flags that specify form properties. The following bit-flag is defined:

Value	Meaning
FORM_BUILTIN	If this bit-flag is set, the form is built-in. If this bit-flag is clear, the form is user-defined.
pName

Points to a null-terminated string that specifies the name of the form.

Size

Specifies the width and height, in thousandths of millimeters, of the form.

ImageableArea

Specifies the width and height, in thousandths of millimeters, of the form.

See Also

AddForm, GetForm, SetForm


FORMAT_PARAMETERS
FORMAT_PARAMETERS  QuickInfo  Overview  Group

typedef struct _FORMAT_PARAMETERS{

   MEDIA_TYPE MediaType;

   DWORD StartCylinderNumber;

   DWORD EndCylinderNumber;

   DWORD StartHeadNumber;

   DWORD EndHeadNumber;

} FORMAT_PARAMETERS ;

The FORMAT_PARAMETERS structure provides information used in formatting a contiguous set of disk tracks.

Members

MediaType

Specifies the media type. See MEDIA_TYPE.

StartCylinderNumber

Specifies the cylinder number at which to begin the format.

EndCylinderNumber

Specifies the cylinder number at which to end the format.

StartHeadNumber

Specifies the beginning head location.

EndHeadNumber

Specifies the ending head location.

Remarks

The DeviceIoControl function uses a FORMAT_PARAMETERS structure as input to an IOCTL_DISK_FORMAT_TRACKS device I/O operation.

See Also

DeviceIoControl, IOCTL_DISK_FORMAT_TRACKS, MEDIA_TYPE


FORMATRANGE [New - Windows NT]
FORMATRANGE  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct _formatrange {

    HDC hdc;

    HDC hdcTarget;

    RECT rc;

    RECT rcPage;

    CHARRANGE chrg;

} FORMATRANGE;

The FORMATRANGE structure contains information that a rich edit control uses to format its output for a particular device. This structure is used with the EM_FORMATRANGE message.

Members

hdc

Device to render to.

hdcTarget

Target device to format for.

rc

Area to render to. Units are in TWIPS

rcPage

Entire area of rendering device. Units are in TWIPS

chrg

Range of text to format.

See Also

EM_FORMATRANGE


GCP_RESULTS [New - Windows 95]
GCP_RESULTS  QuickInfo

[New - Windows 95]

typedef struct tagGCP_RESULTS {
    DWORD  lStructSize;
    LPTSTR  lpOutString;
    UINT  *lpOrder;
    INT  *lpDx;
    INT  *lpCaretPos;
    LPTSTR lpClass;
    UINT  *lpGlyphs;
    UINT  nGlyphs;
    UINT  nMaxFit;
} GCP_RESULTS;

The GCP_RESULTS structure contains information about characters in a string. This structure receives the results of the GetCharacterPlacement function. For some languages, the first element in the arrays may contain more, language-dependent information.

Members

lStructSize

Specifies the size, in bytes, of the structure.

lpOutString

Pointer to the buffer that receives the output string or is NULL if the output string is not needed. The output string is a version of the original string that is in the order that will be displayed on a given device. Typically the output string is identical to the original string, but may be different if the string needs reordering and the GCP_REORDER flag is set or if the the original string exceeds the maximum extent and the GCP_MAXEXTENT flag is set.

lpOrder

Address of the array that receives the ordering indices for the characters in the output string or is NULL if the ordering indices are not needed. The original string needs reordering if the GetFontLanguageInfo function returns the GCP_REORDER value. This is typically used when GetFontLanguageInfo returns the GCP_REORDER flag. For example, in Hebrew, in which the text runs from right to left, the lpOrder array gives the exact locations of each element in the original string.

lpDx

Pointer to the array that receives the distances between adjacent character cells or is NULL if these distances are not needed. If glyph rendering is done, the distances are for the glyphs not the characters, so the resulting array can be used with the ExtTextOut function.

The distances in this array are in display order. To find the distance for the ith character in the original string, use the lpOrder array as follows:

width = lpDx[lpOrder[i]];

On input, this member may contain justification weight values if the GCP_JUSTIFYIN value is given with the GetCharacterPlacement function.

lpCaretPos

Pointer to the array that receives the caret position values or is NULL if caret positions are not needed. Each value specifies the caret position immediately before the corresponding character. In some languages the position of the caret for each character may not be immediately to the left of the character. For example, in Hebrew, in which the text runs from right to left, the caret position is to the right of the character. If glyph ordering is done, lpCaretPos matches the original string not the output string. This means that some adjacent values may be the same.

The values in this array are in input order. To find the caret position value for the ith character in the original string, use the array as follows:

position = lpCaretPos[i];

lpClass

Pointer to the array that contains and/or receives character classifications. The values indicate how to lay out characters in the string and are similar (but not identical) to the CT_CTYPE2 values returned by the GetStringTypeEx function. Each element of the array can be set to zero or one of the following values:

Value	Meaning
GCPCLASS_ARABIC	Arabic character.
GCPCLASS_HEBREW	Hebrew character.
GCPCLASS_LATIN	Character from a Latin or other single-byte character set for a left-to-right language.
GCPCLASS_LATINNUMBER	Digit from a Latin or other single-byte character set for a left-to-right language.
GCPCLASS_LOCALNUMBER	Digit from the character set associated with the current font.
In addition, the following can be used when supplying values in the lpClass array with the GCP_CLASSIN flag.

Value	Meaning
GCPCLASS_LATINNUMERICSEPARATOR	Input only. Character used to separate Latin digits, such as acomma or decimal point.
GCPCLASS_LATINNUMERICTERMINATOR	Input only. Character used to terminate Latin digits, such as a plus or minus sign.
GCPCLASS_NEUTRAL	Input only. character has no specific classification.
GCPCLASS_NUMERICSEPARATOR	Input only. Character used to separate digits, such as a comma or decimal point.
For languages that use the GCP_REORDER flag, the following values can also be used with the GCP_CLASSIN flag. Unlike the preceding values, which can be used anywhere in the lpClass array, all of the following values are used only in the first location in the array. All combine with other classifications. Note that GCPCLASS_PREBOUNDLTR and GCPCLASS_PREBOUNDRTL are mutually exclusive, as are GCPCLASSPOSTBOUNDLTR and GCPCLASSPOSTBOUNDRTL.

Value	Meaning
GCPCLASS_PREBOUNDLTR	Set lpClass[0] to GCP_CLASS_PREBOUNDLTR to bind the string to left-to-right reading order before the string.
CGPCLASS_PREBOUNDRTL	Set lpClass[0] to GCP_CLASS_PREBOUNDRTL to bind the string to right-to-left reading order before the string.
GCPCLASS_POSTBOUNDLTR	Set lpClass[0] to GCP_CLASS_POSTBOUNDLTR to bind the string to left-to-right reading order after the string.
GCPCLASS_POSTBOUNDRTL	Set lpClass[0] to GCP_CLASS_POSTBOUNDRTL to bind the string to right-to-left reading order after the string.
To force the layout of a character to be carried out in a specific way, preset the classification for the corresponding array element; the function leaves such preset classifications unchanged and computes classifications only for array elements that have been set to zero. Preset classifications are used only if the GCP_CLASSIN flag is set and the lpclass array is supplied.

If getFontLanguageInfo does not return GCP_REORDER for the current font, only the GCPCLASS_LATIN value is meaningful.

lpGlyphs

Pointer to the array that receives the values identifying the glyphs used for rendering the string or is NULL if glyph rendering is not needed. The number of glyphs in the array may be less than the number of characters in the original string if the string contains ligated glyphs. Also if reordering is required, the order of the glyphs may not be sequential.

This array is useful if more than one operation is being done on a string which has any form of ligation, kerning or order-switching. Using the values in this array for subsequent operations saves the time otherwise required to generate the glyph indices each time.

This array always contains glyph indices and the ETO_GLYPH_INDEX value must always be used when this array is used with the ExtTextOut function.

When GCP_LIGATE is used, you can limit the number of characters that will be ligated together. (In Arabic for example, three-character ligations are common). This is done by setting the maximum required in lpGcpResults->lpGlyphs[0]. If no maximum is required, you should set this field to zero.

For languages such as Arabic, where GetFontLanguageInfo returns the GCP_GLYPHSHAPE flag, the glyphs for a character will be different depending on whether the character is at the beginning, middle, or end of a word. Typically, the first character in the input string will also be the first character in a word, and the last character in the input string will be treated as the last character in a word. However, if the displayed string is a subset of the complete string, such as when displaying a section of scrolled text, this may not be true. In these cases, it is desirable to force the first or last characters to be shaped as not being initial or final forms. To do this, again, the first location in the lpGlyphs array is used by performing an OR operation of the ligation value above with the values GCPGLYPH_LINKBEFORE and/or GCPGLYPH_LINKAFTER. For example, a value of GCPGLYPH_LINKBEFORE | 2 means that two-character ligatures are the maximum required, and the first character in the string should be treated as if it is in the middle of a word.

nGlyphs

On input, this member must be set to the size of the arrays pointed to by the array pointer members. On output, this is set to the number of glyphs filled in, in the output arrays. If glyph substitution is not required (that is, each input character maps to exactly one glyph), this member is the same as it is on input.

nMaxFit

Number of characters that fit within the extents specified by the nMaxExtent parameter of the GetCharacterPlacement function. If the GCP_MAXEXTENT or GCP_JUSTIFY value is set, this value may be less than the number of characters in the original string. This member is set regardless of whether the GCP_MAXEXTENT or GCP_JUSTIFY value is given. Unlike nGlyphs, which specifies the number of output glyphs, nMaxFit refers to the number of characters from the input string. For Latin SBCS languages, this will be the same.

Remarks

Whether the lpGlyphs, lpOutString, or neither is required depends on the results of the GetFontLanguageInfo call.

In the case of a font for a language such as English, in which none of the GCP_DBCS, GCP_REORDER, GCP_GLYPHSHAPE, GCP_LIGATE, GCP_DIACRITIC, or GCP_KASHIDA flags are returned, neither of the arrays is required for proper operation. (Though not required, they can still be used. If the lpOutString array is used, it will be exactly the same as the lpInputString passed to GetCharacterPlacement.) Note, however, that if GCP_MAXEXTENT is used, then lpOutString will contain the truncated string if it is used, NOT an exact copy of the original.

In the case of fonts for languages such as Hebrew, which DO have reordering but do not typically have extra glyph shapes, lpOutString should be used. This will give the string on the screen-readable order. However, the lpGlyphs array is not typically needed. (Hebrew can have extra glyphs, if the font is a TrueType/Open font.)

In the case of languages such as Thai or Arabic, in which GetFontLanguageInfo returns the GCP_GLYPHSHAPE flag, the lpOutString will give the display-readable order of the string passed to GetCharacterPlacement, but the values will still be the unshaped characters. For proper display, the lpGlyphs array must be used.

See Also

ExtTextOut, GetCharacterPlacement, GetFontLanguageInfo


GENERIC_MAPPING
GENERIC_MAPPING  QuickInfo

typedef struct _GENERIC_MAPPING { // gm

    ACCESS_MASK GenericRead;

    ACCESS_MASK GenericWrite;

    ACCESS_MASK GenericExecute;

    ACCESS_MASK GenericAll;

} GENERIC_MAPPING;

The GENERIC_MAPPING structure defines the mapping of generic access rights to specific and standard access rights for an object. When a client application requests generic access to an object, that request is mapped to the access rights defined in this structure.

Members

GenericRead

Specifies an access mask defining read access to an object.

GenericWrite

Specifies an access mask defining write access to an object.

GenericExecute

Specifies an access mask defining execute access to an object.

GenericAll

Specifies an access mask defining all possible types of access to an object.

See Also

AccessCheck, AccessCheckAndAuditAlarm, CreatePrivateObjectSecurity, MapGenericMask, SetPrivateObjectSecurity, ACCESS_MASK


GLYPHMETRICS
GLYPHMETRICS  QuickInfo

typedef struct _GLYPHMETRICS { // glmt

    UINT  gmBlackBoxX;

    UINT  gmBlackBoxY;

    POINT gmptGlyphOrigin;

    short gmCellIncX;

    short gmCellIncY;

} GLYPHMETRICS;

The GLYPHMETRICS structure contains information about the placement and orientation of a glyph in a character cell.

Members

gmBlackBoxX

Specifies the width of the smallest rectangle that completely encloses the glyph (its "black box").

gmBlackBoxY

Specifies the height of the smallest rectangle that completely encloses the glyph (its "black box").

gmptGlyphOrigin

Specifies the x- and y-coordinates of the upper left corner of the smallest rectangle that completely encloses the glyph.

gmCellIncX

Specifies the horizontal distance from the origin of the current character cell to the origin of the next character cell.

gmCellIncY

Specifies the vertical distance from the origin of the current character cell to the origin of the next character cell.

Remarks

Values in the GLYPHMETRICS structure are specified in device units.

See Also

GetGlyphOutline


HANDLETABLE
HANDLETABLE  QuickInfo

typedef struct tagHANDLETABLE { // ht

    HGDIOBJ objectHandle[1];

} HANDLETABLE;

The HANDLETABLE structure is an array of handles, each of which identifies a graphics device interface (GDI) object.

Members

objectHandle

Contains an array of handles.

See Also

EnhMetaFileProc, EnumMetaFileProc


HD_HITTESTINFO [New - Windows NT]
HD_HITTESTINFO  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct _HD_HITTESTINFO {

    POINT pt;

    UINT flags;

    int iItem;

} HD_HITTESTINFO;

The HD_HITTESTINFO structure contains information about a hit test.

Members

pt

Points to test, in client coordinates

flags

Variable that receives information about the results of a hit test. This member can be one or more of the following values:

Value	Meaning
HHT_NOWHERE	The point is inside the bounding rectangle of the header control but is not over a header item.
HHT_ONDIVIDER	The point is on the divider between two header items.
HHT_ONDIVOPEN	The point is on the divider of an item that has a width of zero. Dragging the divider reveals the item instead of resizing the item to the left of the divider.
HHT_ONHEADER	The point is inside the bounding rectangle of the header control.
HHT_TOLEFT	The point is to the left of the bounding rectangle of the header control.
HHT_TORIGHT	The point is to the right of the bounding rectangle of the header control.
Two of these values can be combined, such as when the position is above and to the left of the client area.

iItem

Receives the index of item at point, if any.

Remarks

This structure is used with the HDM_HITTEST message.

See Also

HDM_HITTEST


HD_ITEM [New - Windows NT]
HD_ITEM  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct _HD_ITEM {   hdi

    UINT    mask;

    int     cxy;

    LPTSTR   pszText;

    HBITMAP hbm;

    int     cchTextMax;

    int     fmt;

    LPARAM  lParam;

} HD_ITEM;

The HD_ITEM structure contains information about an item in a header control.

Members

mask

Mask flags that indicate which of the other structure members contain valid data. This member can be a combination of the following values:

Value	Meaning
HDI_BITMAP	The hbm member is valid.
HDI_FORMAT	The fmt member is valid.
HDI_HEIGHT	The cxy member is valid and specifies the height of the item.
HDI_LPARAM	The lParam member is valid.
HDI_TEXT	The pszText and cchTextMax members are valid.
HDI_WIDTH	The cxy member is valid and specifies the width of the item.
cxy

Width or height of item.

pszText

Pointer to item string.

hbm

Handle to item bitmap.

cchTextMax

Length of item string, in characters.

fmt

Format flags. This member can be one of the following values:

Value	Meaning
HDF_CENTER	Centers the contents of the item.
HDF_LEFT	Left aligns the contents of the item.
HDF_RIGHT	Right aligns the contents of the item.
HDF_RTLREADING	Windows 95 only: Displays text using right-to-left reading order on Hebrew or Arabic systems.
The preceding value is combined with one of the following values:

Value	Meaning
HDF_BITMAP	The item displays a bitmap.
HDF_OWNERDRAW	The owner window of the header control draws the item.
HDF_STRING	The item displays a string.
lParam

Application-defined item data.


HD_LAYOUT [New - Windows NT]
HD_LAYOUT  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct _HD_LAYOUT {  // hdl

    RECT FAR* prc;

    WINDOWPOS FAR* pwpos;

} HD_LAYOUT;

The HD_LAYOUT structure contains information used to set the size and position of a header control.

Members

prc

Pointer to a RECT structure that contains the coordinates of a rectangle that the header control is to occupy.

pwpos

Pointer to a WINDOWPOS structure that receives information about the appropriate size and position of the header control.

Remarks

This structure is used with the HDM_LAYOUT message.

See Also

HDM_LAYOUT, RECT, WINDOWPOS


HD_NOTIFY [New - Windows NT]
HD_NOTIFY  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct _HD_NOTIFY {  // hdn

    NMHDR   hdr;

    int     iItem;

    int     iButton;

    HD_ITEM FAR* pitem;

} HD_NOTIFY;

The HD_NOTIFY structure contains information used to process notification messages from a header control.

Members

hdr

Required for all WM_NOTIFY messages.z

iItem

Index of item associated with notification.

iButton

Index of the mouse button involved in generating the notification message. This member can be one of these values:

Value	Meaning
0	Left button
1	Right button
2	Middle button
pitem

Pointer to an HD_ITEM structure that contains information about the header item associated with the notification message.

See Also

HD_ITEM, WM_NOTIFY


HELPINFO
HELPINFO  QuickInfo

typedef  struct  tagHELPINFO {  // hi

    UINT   cbSize;

    int    iContextType

    int    iCtrlId;

    HANDLE hItemHandle;

    DWORD  dwContextId;

    POINT  MousePos;

} HELPINFO, FAR *LPHELPINFO;

The HELPINFO structure contains information about an item for which context-sensitive help has been requested.

cbSize

Specifies the structure size, in bytes.

iContextType

Specifies the type of context for which help is requested. This member can be one of the following values:

Value	Meaning
HELPINFO_MENUITEM	Help requested for a menu item
HELPINFO_WINDOW	Help requested for a control or window
iCtrlId

Specifies the identifier of the window or control if iContextType is HELPINFO_WINDOW. Specifies the identifier of the menu item if iContextType is HELPINFO_MENUITEM.

hItemHandle

Identifies the child window or control if iContextType is HELPINFO_WINDOW. Identifies the associated menu if iContextType is HELPINFO_MENUITEM.

dwContextId

Specifies the help context identifier of the window or control.

MousePos

Specifies a POINT structure that contains the screen coordinates of the mouse cursor. This is useful for providing help based on the position of the mouse cursor.

See Also

POINT


HELPWININFO
HELPWININFO  QuickInfo

typedef struct {    // hwi

    int   wStructSize;

    int   x;

    int   y;

    int   dx;

    int   dy;

    int   wMax;

    TCHAR rgchMember[2];

} HELPWININFO;

The HELPWININFO structure contains the size and position of either a primary or a secondary Help window. An application can set this information by calling the WinHelp function with the HELP_SETWINPOS value.

Members

wStructSize

Specifies the structure size, in bytes.

x

Specifies the x-coordinate of the upper-left corner of the window, in screen coordinates.

y

Specifies the y-coordinate of the upper-left corner of the window, in screen coordinates.

dx

Specifies the window width, in pixels.

dy

Specifies the window height, in pixels.

wMax

Specifies how to show the window. This member must be one of the following values:

Value	Action
SW_HIDE	Hides the window and passes activation to another window.
SW_MINIMIZE	Minimizes the specified window and activates the top-level window in the Z order.
SW_RESTORE	Same as SW_SHOWNORMAL.
SW_SHOW	Activates a window and displays it in its current size and position.
SW_SHOWMAXIMIZED	Activates the window and displays it as a maximized window.
SW_SHOWMINIMIZED	Activates the window and displays it as an icon.
SW_SHOWMINNOACTIVE	Displays the window as an icon. The window that is currently active remains active.
SW_SHOWNA	Displays the window in its current state. The window that is currently active remains active.
SW_SHOWNOACTIVATE	Displays a window in its most recent size and position. The window that is currently active remains active.
SW_SHOWNORMAL	Activates and displays the window. Whether the window is minimized or maximized, Windows restores it to its original size and position.
rgchMember

Specifies the name of the window.

Remarks

Windows Help divides the display into 1024 units in both the x- and y-directions. To create a secondary window that fills the upper-left quadrant of the display, for example, an application would specify zero for the x and y members and 512 for the dx and dy members.

See Also

WinHelp


HIGHCONTRAST [New - Windows 95]
HIGHCONTRAST  QuickInfo  Overview  Group

[New - Windows 95]

typedef struct tagHIGHCONTRAST {     // hc

    UINT cbSize;

    DWORD dwFlags;

    LPTSTR lpszDefaultScheme;

} HIGHCONTRAST, FAR* LPHIGHCONTRAST;

The HIGHCONTRAST structure contains information about the High Contrast Mode accessibility feature, which sets the appearance scheme of the user interface for maximum visibility for a visually-impaired user, and advises applications to comply with this appearance scheme.

Members

cbSize

Specifies the size, in bytes, of this structure.

dwFlags

Specifies a combination of the following values:

Value	Meaning
HCF_AVAILABLE	The High Contrast Mode is available.
HCF_CONFIRMHOTKEY	A confirmation dialog appears when the the High Contrast Mode is activated by using the hot key.
HCF_HIGHCONTRASTON	The High Contrast Mode is on.
HCF_HOTKEYACTIVE	The user can turn the High Contrast Mode on and off by simultaneously pressing the left ALT, left SHIFT, and PRINT SCREEN keys.
HCF_HOTKEYAVAILABLE	The hot key associated with the High Contrast Mode can be enabled. An application can retrieve this value, but cannot set it.
HCF_HOTKEYSOUND	A siren is played when the user turns the High Contrast Mode on or off by using the hot key.
HCF_INDICATOR	A visual indicator is displayed when the High Contrast Mode is on. This value is not currently used and is ignored.
lpszDefaultScheme

Points to a string that contains the name of the default color scheme.

Remarks

An application uses this structure when calling the SystemParametersInfo function with the SPI_GETHIGHCONTRAST or SPI_SETHIGHCONTRAST value. When using SPI_GETHIGHCONTRAST, an application must specify the cbSize member of the HIGHCONTRAST structure; the SystemParametersInfo function fills the remaining members. An application must specify all structure members when using the SPI_SETHIGHCONTRAST value.

See Also

SystemParametersInfo


HSZPAIR
HSZPAIR  QuickInfo

typedef struct tagHSZPAIR {   // hp

    HSZ hszSvc;

    HSZ hszTopic;

} HSZPAIR;

The HSZPAIR structure contains a DDE service name and topic name. A DDE server application can use this structure during an XTYP_WILDCONNECT transaction to enumerate the service-topic pairs that it supports.

Members

hszSvc

Identifies a service name.

hszTopic

Identifies a topic name.


ICONINFO
ICONINFO  QuickInfo

typedef struct _ICONINFO { // ii

   BOOL    fIcon;

   DWORD   xHotspot;

   DWORD   yHotspot;

   HBITMAP hbmMask;

   HBITMAP hbmColor;

} ICONINFO;

The ICONINFO structure contains information about an icon or a cursor.

Members

fIcon

Specifies whether this structure defines an icon or a cursor. A value of TRUE specifies an icon; FALSE specifies a cursor.

xHotspot

Specifies the x-coordinate of a cursor's hot spot. If this structure defines an icon, the hot spot is always in the center of the icon, and this member is ignored.

yHotspot

Specifies the y-coordinate of the cursor's hot spot. If this structure defines an icon, the hot spot is always in the center of the icon, and this member is ignored.

hbmMask

Specifies the icon bitmask bitmap. If this structure defines a black and white icon, this bitmask is formatted so that the upper half is the icon AND bitmask and the lower half is the icon XOR bitmask. Under this condition, the height should be an even multiple of two. If this structure defines a color icon, this mask only defines the AND bitmask of the icon.

hbmColor

Identifies the icon color bitmap. This member can be optional if this structure defines a black and white icon. The AND bitmask of hbmMask is applied with the SRCAND flag to the destination; subsequently, the color bitmap is applied (using XOR) to the destination by using the SRCINVERT flag.

See Also

CreateIconIndirect, GetIconInfo


ICONMETRICS
ICONMETRICS  QuickInfo

typedef struct tagICONMETRICS {

    UINT    cbSize;

    int     iHorzSpacing;

    int     iVertSpacing;

    int     iTitleWrap;

    LOGFONT lfFont;

} ICONMETRICS, FAR *LPICONMETRICS;

The ICONMETRICS structure contains the scalable metrics associated with icons. This structure is used with the SystemParametersInfo function when the SPI_GETICONMETRICS or SPI_SETICONMETRICS action is specified.

Members

cbSize

Specifies the size of the structure, in bytes.

iHorzSpacing and iVertSpacing

Horizontal and vertical space, in pixels, for each arranged icon.

iTitleWrap

Title-wrapping flag. If this member is nonzero, icon titles wrap to a new line. If this member is zero, titles do not wrap.

lfFont

Specifies the font to use for icon titles.

See Also

SystemParametersInfo


IMAGEINFO [New - Windows NT]
IMAGEINFO  QuickInfo  Overview  Group

[New - Windows NT]

The IMAGEINFO structure contains information about an image in an image list. This structure is used with the ImageList_GetImageInfo function.

typedef struct _IMAGEINFO {

    HBITMAP hbmImage;  // bitmap containing the images

    HBITMAP hbmMask;   // handle to a monochrome bitmap

    int     Unused1;   // not used

    int     Unused2;   // not used

    RECT    rcImage;   // bounding rectangle of the image

} IMAGEINFO;

Members

hbmMask

Handle to a monochrome bitmap that contains the masks for the images. If the image list does not contain a mask, this member is NULL.

rcImage

Bounding rectangle of the image within the bitmap specified by hbmImage.


INPUT_RECORD
INPUT_RECORD  QuickInfo  Overview  Group

typedef struct _INPUT_RECORD { // ir

    WORD EventType;

    union {

        KEY_EVENT_RECORD KeyEvent;

        MOUSE_EVENT_RECORD MouseEvent;

        WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent;

        MENU_EVENT_RECORD MenuEvent;

        FOCUS_EVENT_RECORD FocusEvent;

    } Event;

} INPUT_RECORD;

The INPUT_RECORD structure is used to report input events in the console input buffer. These records can be read from the input buffer by using the ReadConsoleInput or PeekConsoleInput function, or written to the input buffer by using the WriteConsoleInput function.

Members

EventType

Identifies the type of input event and the event record stored in the Event member.

This member can have one of the following values:

Value	Meaning
KEY_EVENT
MOUSE_EVENT
WINDOW_BUFFER_SIZE_EVENT
MENU_EVENT
FOCUS_EVENT
Event

Contains a KEY_EVENT_RECORD, MOUSE_EVENT_RECORD, WINDOW_BUFFER_SIZE_RECORD, MENU_EVENT_RECORD, or FOCUS_EVENT_RECORD structure, depending on the event type specified by the EventType member.

See Also

FOCUS_EVENT_RECORD, KEY_EVENT_RECORD, MENU_EVENT_RECORD, MOUSE_EVENT_RECORD, PeekConsoleInput, ReadConsoleInput, WriteConsoleInput


ITEMIDLIST
ITEMIDLIST  QuickInfo

typedef struct _ITEMIDLIST { // idl

    SHITEMID mkid;  // list of item identifers

} ITEMIDLIST, * LPITEMIDLIST;

typedef const ITEMIDLIST * LPCITEMIDLIST;

Contains a list of item identifiers.


JOB_INFO_1
JOB_INFO_1  QuickInfo

typedef struct _JOB_INFO_1 {    // ji1

    DWORD  JobId;

    LPTSTR pPrinterName;

    LPTSTR pMachineName;

    LPTSTR pUserName;

    LPTSTR pDocument;

    LPTSTR pDatatype;

    LPTSTR pStatus;

    DWORD  Status;

    DWORD  Priority;

    DWORD  Position;

    DWORD  TotalPages;

    DWORD  PagesPrinted;

    SYSTEMTIME Submitted;

} JOB_INFO_1;

The JOB_INFO_1 structure specifies print-job information such as the job-identifier value, the name of the printer for which the job is spooled, the name of the machine that created the print job, the name of the user that owns the print job, and so on.

Members

JobId

Specifies a job identifier.

pPrinterName

Points to a null-terminated string that specifies the name of the printer for which the job is spooled.

pMachineName

Points to a null-terminated string that specifies the name of the machine that created the print job.

pUserName

Points to a null-terminated string that specifies the name of the user that owns the print job.

pDocument

Points to a null-terminated string that specifies the name of the print job (for example, "MS-WORD: Review.doc").

pDatatype

Points to a null-terminated string that specifies the type of data used to record the print job.

pStatus

Points to a null-terminated string that specifies the status of the print job. This member should be checked prior to Status and, if pStatus is NULL, the status is defined by the contents of the Status member.

Status

Specifies the job status. This member can be one or more of the following values:

JOB_STATUS_DELETING
JOB_STATUS_ERROR
JOB_STATUS_OFFLINE
JOB_STATUS_PAPEROUT
JOB_STATUS_PAUSED
JOB_STATUS_PRINTED
JOB_STATUS_PRINTING
JOB_STATUS_SPOOLING

Priority

Specifies the job priority. This member can be one of the following values or in the range between 1 through 99 (MIN_PRIORITY through MAX_PRIORITY):

Value	Meaning
MIN_PRIORITY	Minimum priority.
MAX_PRIORITY	Maximum priority.
DEF_PRIORITY	Default priority.

Position

Specifies the job's position in the print queue.

TotalPages

Specifies how many pages the document contains.

PagesPrinted

Specifies the number of pages that have printed.

Submitted

Specifies the time that this document was spooled.

See Also

EnumJobs, GetJob, SetJob


JOB_INFO_2
JOB_INFO_2  QuickInfo

typedef struct _JOB_INFO_2 { // ji2

    DWORD      JobId;

    LPTSTR     pPrinterName;

    LPTSTR     pMachineName;

    LPTSTR     pUserName;

    LPTSTR     pDocument;

    LPTSTR     pNotifyName;

    LPTSTR     pDatatype;

    LPTSTR     pPrintProcessor;

    LPTSTR     pParameters;

    LPTSTR     pDriverName;

    LPDEVMODE  pDevMode;

    LPTSTR     pStatus;

    PSECURITY_DESCRIPTOR pSecurityDescriptor;

    DWORD      Status;

    DWORD      Priority;

    DWORD      Position;

    DWORD      StartTime;

    DWORD      UntilTime;

    DWORD      TotalPages;

    DWORD      Size;

    SYSTEMTIME Submitted;

    DWORD      Time;

    DWORD      PagesPrinted ;

} JOB_INFO_2;

The JOB_INFO_2 structure describes a full set of values associated with a job.

Members

JobId

Specifies a job identifier value.

pPrinterName

Points to a null-terminated string that specifies the name of the printer for which the job is spooled.

pMachineName

Points to a null-terminated string that specifies the name of the machine that created the print job.

pUserName

Points to a null-terminated string that specifies the name of the user who owns the print job.

pDocument

Points to a null-terminated string that specifies the name of the print job (for example, "MS-WORD: Review.doc").

pNotifyName

Points to a null-terminated string that specifies the name of the user who should be notified when the job has been printed or when an error occurs while printing the job.

pDatatype

Points to a null-terminated string that specifies the type of data used to record the print job.

pPrintProcessor

Points to a null-terminated string that specifies the name of the print processor that should be used to print the job.

pParameters

Points to a null-terminated string that specifies print-processor parameters.

pDriverName

Points to a null-terminated string that specifies the name of the printer driver that should be used to process the print job.

pDevMode

Points to a DEVMODE structure that contains device-initialization and environment data for the printer driver.

pStatus

Points to a null-terminated string that specifies the status of the print job. This member should be checked prior to Status and, if pStatus is NULL, the status is defined by the contents of the Status member.

pSecurityDescriptor

The value of this member is NULL. Retrieval and setting of document security descriptors is not supported in this release.

Status

Specifies the job status. This member can be one or more of the following values:

JOB_STATUS_PAUSED
JOB_STATUS_ERROR
JOB_STATUS_DELETING
JOB_STATUS_SPOOLING
JOB_STATUS_PRINTING
JOB_STATUS_OFFLINE
JOB_STATUS_PAPEROUT
JOB_STATUS_PRINTED

Priority

Specifies the job priority. This member can be one of the following values or in the range between 1 through 99 (MIN_PRIORITY through MAX_PRIORITY):

Value	Meaning
MIN_PRIORITY	Minimum priority.
MAX_PRIORITY	Maximum priority.
DEF_PRIORITY	Default priority.
Position

Specifies the job's position in the print queue.

StartTime

Specifies the earliest time that the job can be printed.

UntilTime

Specifies the the latest time that the job can be printed.

TotalPages

Specifies the number of pages required for the job.

Size

Specifies the size, in bytes, of the job.

Submitted

Specifies the time when the job was submitted.

Time

Specifies the total time, in seconds, that has elapsed since the job began printing.

PagesPrinted

Specifies the number of pages that have printed.

See Also

DEVMODE, EnumJobs, GetJob, SetJob


KERNINGPAIR
KERNINGPAIR  QuickInfo

typedef struct tagKERNINGPAIR { // kp

    WORD wFirst;

    WORD wSecond;

    int  iKernAmount;

} KERNINGPAIR;

The KERNINGPAIR structure defines a kerning pair.

Members

wFirst

Specifies the character code for the first character in the kerning pair.

wSecond

Specifies the character code for the second character in the kerning pair.

iKernAmount

Specifies the amount this pair will be kerned if they appear side by side in the same font and size. This value is typically negative, because pair kerning usually results in two characters being set more tightly than normal. The value is given in logical units — that is, it depends on the current mapping mode.

See Also

GetKerningPairs


KEY_EVENT_RECORD
KEY_EVENT_RECORD  QuickInfo

typedef struct _KEY_EVENT_RECORD { // ker

    BOOL bKeyDown;

    WORD wRepeatCount;

    WORD wVirtualKeyCode;

    WORD wVirtualScanCode;

    union {

        WCHAR UnicodeChar;

        CHAR  AsciiChar;

    } uChar;

    DWORD dwControlKeyState;

} KEY_EVENT_RECORD;

The KEY_EVENT_RECORD structure is used to report keyboard input events in a console INPUT_RECORD structure.

Members

bKeyDown

Specifies TRUE if the key is being pressed, FALSE if the key is being released.

wRepeatCount

Specifies a count indicating that a key is being held down. For example, when a key is held down, you might get five events with this member equal to 1, one event with this member equal to 5, or multiple events with this member greater than or equal to 1.

wVirtualKeyCode

Specifies the virtual-key code that identifies the given key in a device-independent manner.

wVirtualScanCode

Specifies the virtual scan code of the given key that represents the device-dependent value generated by the keyboard hardware.

uChar

Specifies the translated Unicode or ASCII character, depending on whether the wide-character (Unicode) or ANSI version of the ReadConsoleInput function was used.

dwControlKeyState

Indicates the state of the control keys. This member can be a combination of the following values:

Value	Meaning
CAPSLOCK_ON	The CAPS LOCK light is on.
ENHANCED_KEY	The key is enhanced.
LEFT_ALT_PRESSED	The left ALT key is pressed.
LEFT_CTRL_PRESSED	The left CTRL key is pressed.
NUMLOCK_ON	The NUM LOCK light is on.
RIGHT_ALT_PRESSED	The right ALT key is pressed.
RIGHT_CTRL_PRESSED	The right CTRL key is pressed.
SCROLLLOCK_ON	The SCROLL LOCK light is on.
SHIFT_PRESSED	The SHIFT key is pressed.
Remarks

Enhanced keys for the IBM® 101- and 102-key keyboards are the INS, DEL, HOME, END, PAGE UP, PAGE DOWN, and direction keys in the clusters to the left of the keypad; and the divide (/) and ENTER keys in the keypad.

Keyboard input events are generated when any key, including control keys, is pressed or released. However, the ALT key when pressed and released without combining with another character, has special meaning to Windows and is not passed through to the application. Also, the CTRL+C key combination is not passed through if the input handle is in processed mode (ENABLE_PROCESSED_INPUT).

See Also

PeekConsoleInput, ReadConsoleInput, WriteConsoleInput, INPUT_RECORD


LANA_ENUM
LANA_ENUM  QuickInfo

typedef struct _LANA_ENUM { // le

    UCHAR length;

    UCHAR lana[MAX_LANA];

} LANA_ENUM;

The LANA_ENUM structure contains the numbers for the current LAN adapters.

Members

length

Specifies the number of valid entries in the array of LAN adapter numbers.

lana

Specifies an array of LAN adapter numbers.

Remarks

The LANA_ENUM structure is pointed to by the ncb_buffer member of the NCB structure when an application issues the NCBENUM command. The NCBENUM command is not part of the IBM NetBIOS 3.0 specification.

See Also

NCB


LARGE_INTEGER
LARGE_INTEGER  QuickInfo

typedef struct _LARGE_INTEGER { // li

    DWORD LowPart;

    LONG  HighPart;

} LARGE_INTEGER;

The LARGE_INTEGER structure is used to represent a 64-bit signed integer value.

Members

LowPart

Specifies the low-order 32 bits.

HighPart

Specifies the high-order 32 bits.

See Also

LUID, ULARGE_INTEGER


LDT_ENTRY
LDT_ENTRY  QuickInfo

typedef struct _LDT_ENTRY { // ldte

    WORD LimitLow;

    WORD BaseLow;

    union {

        struct {

            BYTE BaseMid;

            BYTE Flags1;

            BYTE Flags2;

            BYTE BaseHi;

        } Bytes;

        struct {

            DWORD BaseMid : 8;

            DWORD Type : 5;

            DWORD Dpl : 2;

            DWORD Pres : 1;

            DWORD LimitHi : 4;

            DWORD Sys : 1;

            DWORD Reserved_0 : 1;

            DWORD Default_Big : 1;

            DWORD Granularity : 1;

            DWORD BaseHi : 8;

        } Bits;

    } HighWord;

} LDT_ENTRY, *PLDT_ENTRY;

The LDT_ENTRY structure describes an entry in the descriptor table. This structure is valid only on x86-based systems.

Members

LimitLow

Contains the low 16 bits of the address of the last byte in the segment.

BaseLow

Contains the low 16 bits of the base address of the segment.

HighWord

Contains the high two words of the descriptor. This member may be interpreted as bytes or collections of bits, depending on the level of detail required.

The members of the Bits structure are as follows:

Member	Contents
BaseMid	Middle bits (16−23) of the base address of the segment.
Type	Bitmask that indicates the type of segment. This member can be one of the following values:
Value	Meaning
0	Read-only data segment
1	Read-write data segment
2	Unused segment
3	Read-write expand-down data segment
4	Execute-only code segment
5	Executable-readable code segment
6	Execute-only "conforming" code segment
7	Executable-readable "conforming" code segment
Dpl	Privilege level of the descriptor. This member is an integer value in the range 0 (most privileged) through 3 (least privileged).
Pres	Present flag. This member is 1 if the segment is present in physical memory or 0 if it is not.
LimitHi	High bits (16−19) of the address of the last byte in the segment.
Sys	Space that is available to system programmers. This member might be used for marking segments in some system-specific way.
Reserved_0	Reserved.
Default_Big	Size of segment. If the segment is a data segment, this member contains 1 if the segment is larger than 64 kilobytes (K) or 0 if the segment is smaller than or equal to 64K.
	If the segment is a code segment, this member contains 1 if the segment is a code segment and runs with the default (native mode) instruction set. This member contains 0 if the code segment is an 80286 code segment and runs with 16-bit offsets and the 80286-compatible instruction set.
Granularity	Granularity. This member contains 0 if the segment is byte granular, 1 if the segment is page granular.
BaseHi	High bits (24−31) of the base address of the segment.
The members of the Bytes structure are as follows:

Member	Contents
BaseMid	Middle bits (16−23) of the base address of the segment.
Flags1	Values of the Type, Dpl, and Pres members in the Bits structure.
Flags2	Values of the LimitHi, Sys, Reserved_0, Default_Big, and Granularity members in the Bits structure.
BaseHi	High bits (24−31) of the base address of the segment.
Remarks

The GetThreadSelectorEntry function fills this structure with information from an entry in the descriptor table. You can use this information to convert a segment-relative address to a linear virtual address.

The base address of a segment is the address of offset 0 in the segment. To calculate this value, combine the BaseLow, BaseMid, and BaseHi members.

The limit of a segment is the address of the last byte that can be addressed in the segment. To calculate this value, combine the LimitLow and LimitHi members.

See Also

GetThreadSelectorEntry


LIST_ENTRY
LIST_ENTRY  QuickInfo

typedef struct _LIST_ENTRY { // le

    struct _LIST_ENTRY *Flink;

    struct _LIST_ENTRY *Blink;

} LIST_ENTRY;

The LIST_ENTRY structure is available for any entry in a double-linked list.

Members

Flink

Points to the preceding entry in a double-linked list.

Blink

Points to the next entry in a double-linked list.

Remarks

This structure can be used as the beginning of a double-linked list or as any subsequent entry in the list.


LOAD_DLL_DEBUG_INFO
LOAD_DLL_DEBUG_INFO  QuickInfo

typedef struct _LOAD_DLL_DEBUG_INFO { // lddi

    HANDLE hFile;

    LPVOID lpBaseOfDll;

    DWORD  dwDebugInfoFileOffset;

    DWORD  nDebugInfoSize;

    LPVOID lpImageName;

    WORD fUnicode;

} LOAD_DLL_DEBUG_INFO;

The LOAD_DLL_DEBUG_INFO structure contains information about a dynamic-link library (DLL) that has just been loaded.

Members

hFile

Identifies a handle of the DLL. If this member is NULL, the handle is not valid. Otherwise, the member is opened for reading and read-sharing in the context of the debugger.

lpBaseOfDll

Points to the base address of the DLL in the address space of the process loading the DLL.

dwDebugInfoFileOffset

Specifies the offset to the debugging information in the file identified by the hFile member. The kernel expects the debugging information to be in CodeView 4.0 format. This format is currently a derivative of Common Object File Format (COFF).

nDebugInfoSize

Specifies the size, in bytes, of the debugging information in the file. If this value is zero, there is no debugging information.

lpImageName

Points to the filename associated with hFile. This member may be NULL, or it may contain the address of a string pointer in the address space of the process being debugged. That address may, in turn, either be NULL or point to the actual filename. If fUnicode is a nonzero value, the name string is Unicode; otherwise, it is ANSI.

This member is strictly optional. Debuggers must be prepared to handle the case where lpImageName is NULL or *lpImageName (in the address space of the process being debugged) is NULL. Specifically, this release of Windows NT will never provide an image name for a create process event, and it will not likely pass an image name for the first DLL event. This version of Windows NT will also never provide this information in the case of debugging events that originate from a call to the DebugActiveProcess function.

fUnicode

Indicates whether a filename specified by lpImageName is Unicode or ANSI. A nonzero value for this member indicates Unicode; zero indicates ANSI.

See Also

CREATE_PROCESS_DEBUG_INFO, CREATE_THREAD_DEBUG_INFO, DebugActiveProcess, DEBUG_EVENT


LOCALESIGNATURE [New - Windows 95]
LOCALESIGNATURE  QuickInfo  Overview  Group

[New - Windows 95]

typedef struct tagLOCALESIGNATURE {
    DWORD  lsUsb[4];
    DWORD  lsCsbDefault[2];
    DWORD  lsCsbSupported[2];
} LOCALESIGNATURE;

The LOCALESIGNATURE structure contains extended font-signature information, including two code-page bitfields (CPBs) that define the default and supported character sets and code-pages. This structure is typically used to represent the relationships between font coverage and locales.

Members

lsUsb

A 128-bit Unicode subset bitfield (USB) identifying up to 126 Unicode subranges. Each bit, except the two most significant bits, represents a single subrange. The most significant bit is always 1 and identifies the bitfield as a font signature; the second most significant is reserved and must be 0. Unicode subranges are numbered in accordance with the ISO 10646 standard.

lsCsbDefault

A code-page bitfield that indicates the default OEM and ANSI code-pages for a locale. The code-pages may be identified by separate bits or a single bit representing a common ANSI and OEM code-page. For a list of possible bitfield values, see Code-Page Bitfields.

lsCsbSupported

A code-page bitfield that indicates all the code-pages in which the locale can be supported. For a list of possible bitfield values, see Code-Page Bitfields.


LOCALGROUP_MEMBERS_INFO_0
LOCALGROUP_MEMBERS_INFO_0  QuickInfo

typedef struct _LOCALGROUP_MEMBERS_INFO_0 {

    PSID  lgrmi0_sid;

} LOCALGROUP_MEMBERS_INFO_0;

The LOCALGROUP_MEMBERS_INFO_0 structure is used in the NetLocalGroupAddMembers and NetLocalGroupDelMembers functions to identify a member of a local group.

Members

lgrmi0_sid

Points to the security identifier of the member.

See Also

LOCALGROUP_MEMBERS_INFO_3, NetLocalGroupAddMembers, NetLocalGroupDelMembers


LOCALGROUP_MEMBERS_INFO_3
LOCALGROUP_MEMBERS_INFO_3  QuickInfo

typedef struct _LOCALGROUP_MEMBERS_INFO_3 {

    LPWSTR  lgrmi3_domainandname;

} LOCALGROUP_MEMBERS_INFO_3;

The LOCALGROUP_MEMBERS_INFO_3 structure is used in the NetLocalGroupAddMembers and NetLocalGroupDelMembers functions to identify a member of a local group.

Members

lgrmi3_domainandname

Points to a null-terminated Unicode string containing the name of the member prefixed by the domain name and the "\" separator character.

See Also

LOCALGROUP_MEMBERS_INFO_0, NetLocalGroupAddMembers, NetLocalGroupDelMembers


LOGBRUSH
LOGBRUSH  QuickInfo

typedef struct tagLOGBRUSH { // lb

   UINT     lbStyle;

   COLORREF lbColor;

   LONG     lbHatch;

} LOGBRUSH;

The LOGBRUSH structure defines the style, color, and pattern of a physical brush. It is used by the CreateBrushIndirect and ExtCreatePen functions.

Members

lbStyle

Specifies the brush style. The lbStyle member must be one of the following styles:

Value	Meaning
BS_DIBPATTERN	A pattern brush defined by a device-independent bitmap (DIB) specification. If lbStyle is BS_DIBPATTERN, the lbHatch member contains a handle to a packed DIB. Windows 95 only: Creating brushes from bitmaps or DIBs larger than 8x8 pixels is not supported. If a larger bitmap is given, only a portion of the bitmap is used.
BS_DIBPATTERN8X8	Same as BS_DIBPATTERN.
BS_DIBPATTERNPT	A pattern brush defined by a device-independent bitmap (DIB) specification. If lbStyle is BS_DIBPATTERNPT, the lbHatch member contains a pointer to a packed DIB.
BS_HATCHED	Hatched brush.
BS_HOLLOW	Hollow brush.
BS_NULL	Same as BS_HOLLOW.
BS_PATTERN	Pattern brush defined by a memory bitmap.
BS_PATTERN8X8	Same as BS_PATTERN.
BS_SOLID	Solid brush.
lbColor

Specifies the color in which the brush is to be drawn. If lbStyle is the BS_HOLLOW or BS_PATTERN style, lbColor is ignored.

If lbStyle is BS_DIBPATTERN or BS_DIBPATTERNBT, the low-order word of lbColor specifies whether the bmiColors members of the BITMAPINFO structure contain explicit red, green, blue (RGB) values or indices into the currently realized logical palette. The lbColor member must be one of the following values:

Value	Meaning
DIB_PAL_COLORS	The color table consists of an array of 16-bit indices into the currently realized logical palette.
DIB_RGB_COLORS	The color table contains literal RGB values.
lbHatch

Specifies a hatch style. The meaning depends on the brush style defined by lbStyle.

If lbStyle is BS_DIBPATTERN, the lbHatch member contains a handle to a packed DIB. If lbStyle is BS_DIBPATTERNPT, the lbHatch member contains a pointer to a packed DIB.

If lbStyle is BS_HATCHED, the lbHatch member specifies the orientation of the lines used to create the hatch. It can be one of the following values:

Value	Meaning
HS_BDIAGONAL	A 45-degree upward, left-to-right hatch
HS_CROSS	Horizontal and vertical cross-hatch
HS_DIAGCROSS	45-degree crosshatch
HS_FDIAGONAL	A 45-degree downward, left-to-right hatch
HS_HORIZONTAL	Horizontal hatch
HS_VERTICAL	Vertical hatch
If lbStyle is BS_PATTERN, lbHatch is a handle to the bitmap that defines the pattern. The bitmap cannot be a DIB section bitmap, which is created by the CreateDIBSection function.

If lbStyle is BS_SOLID or BS_HOLLOW, lbHatch is ignored.

Remarks

Although lbColor controls the foreground color of a hatch brush, the SetBkMode and SetBkColor functions control the background color.

See Also

BITMAPINFO, CreateBrushIndirect, CreateDIBSection, ExtCreatePen, SetBkColor, SetBkMode


LOGCOLORSPACE [New - Windows 95]
LOGCOLORSPACE  QuickInfo  Overview  Group

[New - Windows 95]

typedef struct tagLOGCOLORSPACE {
    DWORD         lcsSignature;

    DWORD         lcsVersion;

    DWORD         lcsSize;

    LCSCSTYPE     lcsCSType;

    LCSGAMUTMATCH lcsIntent;

    CIEXYZTRIPLE  lcsEndpoints;
    DWORD         lcsGammaRed;
    DWORD         lcsGammaGreen;

    DWORD         lcsGammaBlue;
    TCHAR         lcsFilename[MAX_PATH];

} LOGCOLORSPACE, *LPLOGCOLORSPACE;

The LOGCOLORSPACE structure contains information that defines a logical color space.

Members

lcsSignature

Color space signature.

lcsVersion

Version number; must be 0x400.

lcsSize

Size of this structure, in bytes.

lcsCSType

Color space type. Can be one of the following values:

Value	Meaning
LCS_DEVICE_RGB	Color values are device RGB values. The values are passed to the device without translation.
LCS_DEVICE_CMYK	Color values are device CMYK values. The values are passed to the device without translation
LCS_CALIBRATED_RGB	Color values are calibrated RGB values. The values are translated using the endpoints specified by the lcsEndpoints member before being passed to the device.
If LCS_CALIBRATED_RGB is not specified, the lcsEndpoints member is ignored.

lcsIntent

The gamut matching method. Can be one of the following values:

Value	Meaning
LCS_GM_BUSINESS	Maintain saturation. Used for business charts and other situations in which undithered colors are required.
LCS_GM_GRAPHICS	Maintain colormetric match. Used for graphic designs and named colors.
LCS_GM_IMAGES	Maintain contrast. Used for photographs and natural images.
lcsEndpoints

Red, green, blue endpoints.

lcsGammaRed

Scale of the red coordinate.

lcsGammaGreen

Scale of the green coordinate.

lcsGammaBlue

Scale of the blue coordinate.

lcsFilename

A null-terminated string that names a color profile file. This member is typically set to zero, but may be used to set the color space to be exactly as specified by the color profile. This is useful for devices that input color values for a specific printer, or when using an installable image color matcher. If a color profile is specified, all other members of this structure should be set to reasonable values, even if the values are not 100 percent accurate.

See Also

RGB, CMYK


LOGFONT
LOGFONT  QuickInfo

typedef struct tagLOGFONT { // lf

   LONG lfHeight;

   LONG lfWidth;

   LONG lfEscapement;

   LONG lfOrientation;

   LONG lfWeight;

   BYTE lfItalic;

   BYTE lfUnderline;

   BYTE lfStrikeOut;

   BYTE lfCharSet;

   BYTE lfOutPrecision;

   BYTE lfClipPrecision;

   BYTE lfQuality;

   BYTE lfPitchAndFamily;

   TCHAR lfFaceName[LF_FACESIZE];

} LOGFONT;

The LOGFONT structure defines the attributes of a font.

Members

lfHeight

Specifies the height, in logical units, of the font's character cell or character. The character height value (also known as the em height) is the character cell height value minus the internal-leading value. The font mapper interprets the value specified in lfHeight in the following manner:

Value	Meaning
> 0	The font mapper transforms this value into device units and matches it against the cell height of the available fonts.
0	The font mapper uses a default height value when it searches for a match.
< 0	The font mapper transforms this value into device units and matches its absolute value against the character height of the available fonts.
For all height comparisons, the font mapper looks for the largest font that does not exceed the requested size.

This mapping occurs when the font is used for the first time.

For the MM_TEXT mapping mode, you can use the following formula to specify a height for a font with a given point size:

lfHeight = -MulDiv(PointSize, GetDeviceCaps(hDC, LOGPIXELSY), 72);

lfWidth

Specifies the average width, in logical units, of characters in the font. If lfWidth is zero, the aspect ratio of the device is matched against the digitization aspect ratio of the available fonts to find the closest match, determined by the absolute value of the difference.

lfEscapement

Specifies the angle, in tenths of degrees, between the escapement vector and the x-axis of the device. The escapement vector is parallel to the base line of a row of text.

Windows NT:

When the graphics mode is set to GM_ADVANCED, you can specify the escapement angle of the string independently of the orientation angle of the string's characters.

When the graphics mode is set to GM_COMPATIBLE, lfEscapement specifies both the escapement and orientation. You should set lfEscapement and lfOrientation to the same value.

Windows 95:

The lfEscapement member specifies both the escapement and orientation. You should set lfEscapement and lfOrientation to the same value.

lfOrientation

Specifies the angle, in tenths of degrees, between each character's base line and the x-axis of the device.

lfWeight

Specifies the weight of the font in the range 0 through 1000. For example, 400 is normal and 700 is bold. If this value is zero, a default weight is used.

The following values are defined for convenience:

Value	Weight
FW_DONTCARE	0
FW_THIN	100
FW_EXTRALIGHT	200
FW_ULTRALIGHT	200
FW_LIGHT	300
FW_NORMAL	400
FW_REGULAR	400
FW_MEDIUM	500
FW_SEMIBOLD	600
FW_DEMIBOLD	600
FW_BOLD	700
FW_EXTRABOLD	800
FW_ULTRABOLD	800
FW_HEAVY	900
FW_BLACK	900
lfItalic

Specifies an italic font if set to TRUE.

lfUnderline

Specifies an underlined font if set to TRUE.

lfStrikeOut

Specifies a strikeout font if set to TRUE.

lfCharSet

Specifies the character set. The following values are predefined:

ANSI_CHARSET
DEFAULT_CHARSET
SYMBOL_CHARSET
SHIFTJIS_CHARSET
GB2312_CHARSET
HANGEUL_CHARSET
CHINESEBIG5_CHARSET
OEM_CHARSET

Windows 95 only:

JOHAB_CHARSET
HEBREW_CHARSET
ARABIC_CHARSET
GREEK_CHARSET
TURKISH_CHARSET
THAI_CHARSET
EASTEUROPE_CHARSET
RUSSIAN_CHARSET
MAC_CHARSET
BALTIC_CHARSET

The OEM_CHARSET value specifies a character set that is operating-system dependent.

You can use the DEFAULT_CHARSET value to allow the name and size of a font to fully describe the logical font. If the specified font name does not exist, a font from any character set can be substituted for the specified font, so you should use DEFAULT_CHARSET sparingly to avoid unexpected results.

Fonts with other character sets may exist in the operating system. If an application uses a font with an unknown character set, it should not attempt to translate or interpret strings that are rendered with that font.

This parameter is important in the font mapping process. To ensure consistent results, specify a specific character set. If you specify a typeface name in the lfFaceName member, make sure that the lfCharSet value matches the character set of the typeface specified in lfFaceName.

lfOutPrecision

Specifies the output precision. The output precision defines how closely the output must match the requested font's height, width, character orientation, escapement, pitch, and font type. It can be one of the following values:

Value	Meaning
OUT_CHARACTER_PRECIS	Not used.
OUT_DEFAULT_PRECIS	Specifies the default font mapper behavior.
OUT_DEVICE_PRECIS	Instructs the font mapper to choose a Device font when the system contains multiple fonts with the same name.
OUT_OUTLINE_PRECIS	Windows NT: This value instructs the font mapper to choose from TrueType and other outline-based fonts. Windows 95: This value is not used.
OUT_RASTER_PRECIS	Instructs the font mapper to choose a raster font when the system contains multiple fonts with the same name.
OUT_STRING_PRECIS	This value is not used by the font mapper, but it is returned when raster fonts are enumerated.
OUT_STROKE_PRECIS	Windows NT: This value is not used by the font mapper, but it is returned when TrueType, other outline-based fonts, and vector fonts are enumerated.  Windows 95: This value is used to map vector fonts, and is returned when TrueType or vector fonts are enumerated.
OUT_TT_ONLY_PRECIS	Instructs the font mapper to choose from only TrueType fonts. If there are no TrueType fonts installed in the system, the font mapper returns to default behavior.
OUT_TT_PRECIS	Instructs the font mapper to choose a TrueType font when the system contains multiple fonts with the same name.
Applications can use the OUT_DEVICE_PRECIS, OUT_RASTER_PRECIS, and OUT_TT_PRECIS values to control how the font mapper chooses a font when the operating system contains more than one font with a given name. For example, if an operating system contains a font named Symbol in raster and TrueType form, specifying OUT_TT_PRECIS forces the font mapper to choose the TrueType version. Specifying OUT_TT_ONLY_PRECIS forces the font mapper to choose a TrueType font, even if it must substitute a TrueType font of another name.

lfClipPrecision

Specifies the clipping precision. The clipping precision defines how to clip characters that are partially outside the clipping region. It can be one or more of the following values:

Value	Meaning
CLIP_DEFAULT_PRECIS	Specifies default clipping behavior.
CLIP_CHARACTER_PRECIS	Not used.
CLIP_STROKE_PRECIS	Not used by the font mapper, but is returned when raster, vector, or TrueType fonts are enumerated. Windows NT: For compatibility, this value is always returned when enumerating fonts.
CLIP_MASK	Not used.
CLIP_EMBEDDED	You must specify this flag to use an embedded read-only font.
CLIP_LH_ANGLES	When this value is used, the rotation for all fonts depends on whether the orientation of the coordinate system is left-handed or right-handed.  If not used, device fonts always rotate counterclockwise, but the rotation of other fonts is dependent on the orientation of the coordinate system. For more information about the orientation of coordinate systems, see the description of the nOrientation parameter
CLIP_TT_ALWAYS	Not used.
lfQuality

Specifies the output quality. The output quality defines how carefully the graphics device interface (GDI) must attempt to match the logical-font attributes to those of an actual physical font. It can be one of the following values:

Value	Meaning
DEFAULT_QUALITY	Appearance of the font does not matter.
DRAFT_QUALITY	Appearance of the font is less important than when PROOF_QUALITY is used. For GDI raster fonts, scaling is enabled, which means that more font sizes are available, but the quality may be lower. Bold, italic, underline, and strikeout fonts are synthesized if necessary.
PROOF_QUALITY	Character quality of the font is more important than exact matching of the logical-font attributes. For GDI raster fonts, scaling is disabled and the font closest in size is chosen. Although the chosen font size may not be mapped exactly when PROOF_QUALITY is used, the quality of the font is high and there is no distortion of appearance. Bold, italic, underline, and strikeout fonts are synthesized if necessary.
lfPitchAndFamily

Specifies the pitch and family of the font. The two low-order bits specify the pitch of the font and can be one of the following values:

DEFAULT_PITCH
FIXED_PITCH
VARIABLE_PITCH

Bits 4 through 7 of the member specify the font family and can be one of the following values:

FF_DECORATIVE
FF_DONTCARE
FF_MODERN
FF_ROMAN
FF_SCRIPT
FF_SWISS

The proper value can be obtained by using the Boolean OR operator to join one pitch constant with one family constant.

Font families describe the look of a font in a general way. They are intended for specifying fonts when the exact typeface desired is not available. The values for font families are as follows:

Value	Meaning
FF_DECORATIVE	Novelty fonts. Old English is an example.
FF_DONTCARE	Don't care or don't know.
FF_MODERN	Fonts with constant stroke width (monospace), with or without serifs. Monospace fonts are usually modern. Pica, Elite, and CourierNew® are examples.
FF_ROMAN	Fonts with variable stroke width (proportional) and with serifs. MS® Serif is an example.
FF_SCRIPT	Fonts designed to look like handwriting. Script and Cursive are examples.
FF_SWISS	Fonts with variable stroke width (proportional) and without serifs. MS® Sans Serif is an example.
lfFaceName

A null-terminated string that specifies the typeface name of the font. The length of this string must not exceed 32 characters, including the null terminator. The EnumFontFamilies function can be used to enumerate the typeface names of all currently available fonts. If lfFaceName is an empty string, GDI uses the first font that matches the other specified attributes.

See Also

CreateFont, CreateFontIndirect, EnumFontFamilies


LOGPALETTE
LOGPALETTE  QuickInfo

typedef struct tagLOGPALETTE { // lgpl

    WORD         palVersion;

    WORD         palNumEntries;

    PALETTEENTRY palPalEntry[1];

} LOGPALETTE;

The LOGPALETTE structure defines a logical color palette.

Members

palVersion

Specifies the Windows version number for the structure (currently 0x300).

palNumEntries

Specifies the number of entries in the logical color palette.

palPalEntry

Specifies an array of PALETTEENTRY structures that define the color and usage of each entry in the logical palette.

Remarks

The colors in the palette-entry table should appear in order of importance because entries earlier in the logical palette are most likely to be placed in the system palette.

See Also

CreatePalette, PALETTEENTRY


LOGPEN
LOGPEN  QuickInfo

typedef struct tagLOGPEN { // lgpn

    UINT     lopnStyle;

    POINT    lopnWidth;

    COLORREF lopnColor;

} LOGPEN;

The LOGPEN structure defines the style, width, and color of a pen. The CreatePenIndirect function uses the LOGPEN structure.

Members

lopnStyle

Specifies the pen style, which can be one of the following values:

Value	Meaning
PS_SOLID	Pen is solid.
PS_DASH	Pen is dashed.
PS_DOT	Pen is dotted.
PS_DASHDOT	Pen has alternating dashes and dots.
PS_DASHDOTDOT	Pen has dashes and double dots.
PS_NULL	Pen is invisible.
PS_INSIDEFRAME	Pen is solid. When this pen is used in any graphics device interface (GDI) drawing function that takes a bounding rectangle, the dimensions of the figure are shrunk so that it fits entirely in the bounding rectangle, taking into account the width of the pen. This applies only to geometric pens.
lopnWidth

Specifies the POINT structure that contains the pen width, in logical units. If the pointer member is NULL, the pen is one pixel wide on raster devices. The y member in the POINT structure for lopnWidth is not used.

lopnColor

Specifies the pen color.

Remarks

If the width of the pen is greater than 1 and the pen style is PS_INSIDEFRAME, the line is drawn inside the frame of all GDI objects except polygons and polylines. If the pen color does not match an available red, green, blue (RGB) value, the pen is drawn with a logical (dithered) color. If the pen width is less than or equal to 1, the PS_INSIDEFRAME style is identical to the PS_SOLID style.

See Also

CreatePenIndirect, POINT, RGB


LUID
LUID  QuickInfo

typedef LARGE_INTEGER LUID

An LUID is a 64-bit value guaranteed to be unique only on the system on which it was generated. The uniqueness of a locally unique identifier (LUID) is guaranteed only until the system is restarted.

An LUID is not for direct manipulation. Applications are to use functions and structures to manipulate LUID values.

See Also

AllocateLocallyUniqueId, LookupPrivilegeName, LookupPrivilegeValue, PrivilegeCheck, LUID_AND_ATTRIBUTES, PRIVILEGE_SET


LUID_AND_ATTRIBUTES
LUID_AND_ATTRIBUTES  QuickInfo

typedef struct _LUID_AND_ATTRIBUTES { // luaa

    LUID  Luid;

    DWORD Attributes;

} LUID_AND_ATTRIBUTES;

The LUID_AND_ATTRIBUTES structure represents a locally unique identifier (LUID) and its attributes.

Members

Luid

Specifies an LUID value.

Attributes

Specifies attributes of the LUID. This value contains up to 32 one-bit flags. Its meaning is dependent on the definition and use of the LUID.

Remarks

An LUID_AND_ATTRIBUTES structure can represent an LUID whose attributes change frequently, such as when it is used to represent privileges in the PRIVILEGE_SET structure. Privileges are represented by LUIDs and have attributes indicating whether they are currently enabled or disabled.

See Also

AllocateLocallyUniqueId, LUID, PRIVILEGE_SET, TOKEN_PRIVILEGES


LV_COLUMN [New - Windows NT]
LV_COLUMN  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct _LV_COLUMN {

    UINT mask;

    int fmt;

    int cx;

    LPTSTR pszText;

    int cchTextMax;

    int iSubItem;

} LV_COLUMN;

The LV_COLUMN structure contains information about a column in report view. This structure is also used to receive information about a column.

Members

mask

Variable specifying which members contain valid information. This member can be zero, or one or more of the following values:

Value	Meaning
LVCF_FMT	The fmt member is valid.
LVCF_SUBITEM	The iSubItem member is valid.
LVCF_TEXT	The pszText member is valid.
LVCF_WIDTH	The cx member is valid.
fmt

Alignment of the column. This member can be one of the following values: LVCFMT_LEFT, LVCFMT_RIGHT, or LVCFMT_CENTER. The first column in a list view control must be left aligned; that is, the LVCFMT_RIGHT must not be specified for the first column.

cx

Width of the column, in pixels.

pszText

Pointer to a null-terminated string that contains the column heading if the structure contains information about a column. If the structure is receiving information about a column, this member specifies the address of the buffer that receives the column heading.

cchTextMax

Size of the buffer pointed to by the pszText member. If the structure is not receiving information about a column, this member is ignored.

iSubItem

Index of subitem associated with column.

Remarks

This structure is used with the LVM_GETCOLUMN, LVM_SETCOLUMN, LVM_INSERTCOLUMN, and LVM_DELETECOLUMN messages.

See Also

LVM_DELETECOLUMN, LVM_GETCOLUMN, LVM_INSERTCOLUMN, LVM_SETCOLUMN


LV_DISPINFO [New - Windows NT]
LV_DISPINFO  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct tagLV_DISPINFO {

    NMHDR   hdr;

    LV_ITEM item;

} LV_DISPINFO;

The LV_DISPINFO structure contains information needed to display an owner-drawn item in a list view control. The LV_DISPINFO structure is used with the LVN_GETDISPINFO and LVN_SETDISPINFO notification messages.

Members

hdr

Required for all WM_NOTIFY messages.

item

LV_ITEM structure that identifies the item or subitem. The structure either contains or receives information about the item. The mask member contains a set of bit flags that specify which item attributes are relevant. You can set one or more of the following bit flags:

Value	Meaning
LVIF_IMAGE	The iImage member specifies, or is to receive, the index of the item's icon in the image list.
LVIF_STATE	The state member specifies, or is to receive, the state of the item.
LVIF_TEXT	The pszText member specifies the new item text or the address of a buffer that is to receive the item text.
If the structure is receiving item text, the pszText and cchTextMax members specify the address and size of a buffer. You can either copy text to the buffer or assign the address of a string to the pszText member. In the latter case, you must not change or delete the string until the corresponding item text is deleted or two additional LVN_GETDISPINFO messages have been sent.

If you are handling the LVN_GETDISPINFO message, you can set the LVIF_DI_SETITEM flag in the mask member. This tells the operating system to store the requested list item information, and not ask for it again.

See Also

LV_ITEM, LVN_GETDISPINFO, LVN_SETDISPINFO, WM_NOTIFY


LV_FINDINFO [New - Windows NT]
LV_FINDINFO  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct _LV_FINDINFO {

    UINT flags;

    LPCTSTR psz;

    LPARAM lParam;

    POINT pt;

    UINT vkDirection;

} LV_FINDINFO;

The LV_FINDINFO structure contains information used to search for a list view item.

Members

flags

Type of search to perform. This member can be one or more of the following values:

Value	Meaning
LVFI_PARAM	Searches based on the lParam member. The lParam member of the matching item's LV_ITEM structure must match the lParam member of this structure. If this value is specified, all other values are ignored.
LVFI_PARTIAL	Matches if the item text begins with the string pointed to by the psz member. This value implies use of LVFI_STRING.
LVFI_STRING	Searches based on the item text. Unless additional values are specified, the item text of the matching item must exactly match the string pointed to by the psz member.
LVFI_WRAP	Continues the search at the beginning if no match is found.
LVFI_NEARESTXY	Finds the item nearest the specified position in the specified direction.
psz

Pointer to a null-terminated string to compare with the item text if flags specifies LVFI_STRING or LVFI_PARTIAL.

lParam

Value to compare with the lParam member of a list view item's LV_ITEM structure if the flags member specifies LVFI_PARAM.

pt

POINT structure that specifies the starting position to search from. This member is used only if LVFI_NEARESTXY is specified.

vkDirection

Direction to search in. This member is used only if LVFI_NEARESTXY is specified. If this member used, it specifies the virtual-key code of an arrow key.

Remarks

The LV_FINDINFO structure is used with the LVM_FINDITEM message.

See Also

LV_ITEM, LVM_FINDITEM, POINT


LV_HITTESTINFO [New - Windows NT]
LV_HITTESTINFO  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct _LV_HITTESTINFO {

    POINT pt;

    UINT flags;

    int iItem;

} LV_HITTESTINFO;

The LV_HITTESTINFO structure contains information about a hit test.

Members

pt

Position to hit test, in client coordinates.

flags

Variable that receives information about the results of a hit test. This member can be one or more of the following values:

Value	Meaning
LVHT_ABOVE	The position is above the client area of the control.
LVHT_BELOW	The position is below the client area of the control.
LVHT_NOWHERE	The position is inside the list view control's client window, but it is not over a list item.
LVHT_ONITEMICON	The position is over a list view item's icon.
LVHT_ONITEMLABEL	The position is over a list view item's text.
LVHT_ONITEMSTATEICON	The position is over the state image of a list view item.
LVHT_TOLEFT	The position is to the left of the list view control's client area.
LVHT_TORIGHT	The position is to the right of the list view control's client area.
You can use LVHT_ABOVE, LVHT_BELOW, LVHT_TOLEFT, and LVHT_TORIGHT to determine whether to scroll the contents of a list view control. Two of these values may be combined — for example, if the position is above and to the left of the client area.

You can test for LVHT_ONITEM to determine whether a specified position is over a list view item. This value is a bitwise-OR operation on LVHT_ONITEMICON, LVHT_ONITEMLABEL, and LVHT_ONITEMSTATEICON.

iItem

Receives the index of the matching item.

Remarks

This structure is used with the LVM_HITTEST message.

See Also

LVM_HITTEST


LV_ITEM [New - Windows NT]
LV_ITEM  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct _LV_ITEM {

    UINT   mask;

    int    iItem;

    int    iSubItem;

    UINT   state;

    UINT   stateMask;

    LPTSTR  pszText;

    int    cchTextMax;

    int    iImage;       // index of the list view item's icon

    LPARAM lParam;       // 32-bit value to associate with item

} LV_ITEM;

The LV_ITEM structure specifies or receives the attributes of a list view item.

Members

mask

A set of bit flags that specify attributes of this data structure or of an operation that is using this structure.

The following bit flags specify the members of the LV_ITEM structure that contain valid data or need to be filled in. One or more of these bit flags may be set:

Value	Meaning
LVIF_TEXT	The pszText member is valid or needs to be filled in.
LVIF_IMAGE	The iImage member is valid or needs to be filled in.
LVIF_PARAM	The lParam member is valid or needs to be filled in.
LVIF_STATE	The state member is valid or needs to be filled in..
The following bit flag is used with the LVN_GETDISPINFO notification message:

Value	Meaning
LVIF_DI_SETITEM	The operating system should store the requested list item information, and not ask for it again.
iItem

Item that this structure refers to.

iSubItem

Subitem that this structure refers to, or zero.

state and statemask

Current state of the item, and the valid states of the item. This member can be any valid combination of state flags.

pszText

Pointer to a null-terminated string that contains the item text if the structure specifies item attributes. If this member is the LPSTR_TEXTCALLBACK value, the item is a callback item. Do not set the pszText member to LPSTR_TEXTCALLBACK if the list view control has LVS_SORTASCENDING or LVS_SORTDESCENDING style.

If the structure is receiving item attributes, this member is the pointer to the buffer that receives the item text.

cchTextMax

Size of the buffer pointed to by the pszText member if the structure is receiving item attributes. If the structure specifies item attributes, this member is ignored.

iImage

Index of the list view item's icon in the icon and small icon image lists. If this member is the I_IMAGECALLBACK value, the item is a callback item.

Remarks

The LV_ITEM structure is used with a number of messages, including LVM_GETITEM, LVM_SETITEM, LVM_INSERTITEM, and LVM_DELETEITEM.

See Also

LVM_DELETEITEM, LVM_GETITEM, LVM_INSERTITEM, LVM_SETITEM


LV_KEYDOWN [New - Windows NT]
LV_KEYDOWN  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct tagLV_KEYDOWN {

    NMHDR hdr;

    WORD wVKey;

    UINT flags;

} LV_KEYDOWN;

The LV_KEYDOWN structure contains information about a keyboard event in a list view control.

Members

hdr

Required for all WM_NOTIFY messages.

wVKey

Virtual-key code.

flags

Always zero.

Remarks

The LV_KEYDOWN structure is used with the LVN_KEYDOWN notification message.

See Also

LVN_KEYDOWN, WM_NOTIFY


MAT2
MAT2  QuickInfo

typedef struct _MAT2 { // mt2

    FIXED eM11;

    FIXED eM12;

    FIXED eM21;

    FIXED eM22;

} MAT2;

The MAT2 structure contains the values for a transformation matrix used by the GetGlyphOutline function.

Members

eM11

Specifies a fixed-point value for the M11 component of a 3 by 3 transformation matrix.

eM12

Specifies a fixed-point value for the M12 component of a 3 by 3 transformation matrix.

eM21

Specifies a fixed-point value for the M21 component of a 3 by 3 transformation matrix.

eM22

Specifies a fixed-point value for the M22 component of a 3 by 3 transformation matrix.

Remarks

The identity matrix produces a transformation in which the transformed graphical object is identical to the source object. In the identity matrix, the value of eM11 is 1, the value of eM12 is zero, the value of eM21 is zero, and the value of eM22 is 1.

See Also

GetGlyphOutline


MDICREATESTRUCT
MDICREATESTRUCT  QuickInfo

typedef struct tagMDICREATESTRUCT { // mdic

    LPCTSTR szClass;

    LPCTSTR szTitle;

    HANDLE  hOwner;

    int     x;

    int     y;

    int     cx;

    int     cy;

    DWORD   style;

    LPARAM  lParam;

} MDICREATESTRUCT;

The MDICREATESTRUCT structure contains information about the class, title, owner, location, and size of a multiple document interface (MDI) child window.

Members

szClass

Points to a null-terminated string specifying the name of the window class of the MDI child window. The class name must have been registered by a previous call to the RegisterClass function.

szTitle

Points to a null-terminated string that represents the title of the MDI child window. Windows displays the title in the child window's title bar.

hOwner

Identifies the instance of the application creating the MDI client window.

x

Specifies the initial horizontal position, in client coordinates, of the MDI child window. If this member is CW_USEDEFAULT, the MDI child window is assigned the default horizontal position.

y

Specifies the initial vertical position, in client coordinates, of the MDI child window. If this member is CW_USEDEFAULT, the MDI child window is assigned the default vertical position.

cx

Specifies the initial width, in device units, of the MDI child window. If this member is CW_USEDEFAULT, the MDI child window is assigned the default width.

cy

Specifies the initial height, in device units, of the MDI child window. If this member is set to CW_USEDEFAULT, the MDI child window is assigned the default height.

style

Specifies the style of the MDI child window. If the MDI client window was created with the MDIS_ALLCHILDSTYLES window style, this member can be any combination of the window styles listed in the description of the CreateWindow function. Otherwise, this member can be one or more of the following values:

Value	Meaning
WS_MINIMIZE	Creates an MDI child window that is initially minimized.
WS_MAXIMIZE	Creates an MDI child window that is initially maximized.
WS_HSCROLL	Creates an MDI child window that has a horizontal scroll bar.
WS_VSCROLL	Creates an MDI child window that has a vertical scroll bar.
lParam

Specifies an application-defined 32-bit value.

Remarks

When the MDI child window is created, Windows sends the WM_CREATE message to the window. The lParam parameter of WM_CREATE contains a pointer to a CREATESTRUCT structure. The lpCreateParams member of this structure contains a pointer to the MDICREATESTRUCT structure passed with the WM_MDICREATE message that created the MDI child window.

See Also

CLIENTCREATESTRUCT, CREATESTRUCT, WM_CREATE


MEASUREITEMSTRUCT
MEASUREITEMSTRUCT  QuickInfo

typedef struct tagMEASUREITEMSTRUCT {   // mis

    UINT  CtlType;      // type of control

    UINT  CtlID;        // combo box, list box, or button identifier

    UINT  itemID;       // menu item, variable-height list box, or combo box identifier

    UINT  itemWidth;    // width of menu item, in pixels

    UINT  itemHeight;   // height of single item in list box menu, in pixels

    DWORD itemData;     // application-defined 32-bit value

} MEASUREITEMSTRUCT;

The MEASUREITEMSTRUCT structure informs Windows of the dimensions of an owner-drawn control or menu item. This allows Windows to process user interaction with the control correctly.

Members

CtlType

Specifies the control type. This member can be one of the following values:

Value	Meaning
ODT_BUTTON	Owner-drawn button
ODT_COMBOBOX	Owner-drawn combo box
ODT_LISTBOX	Owner-drawn list box
ODT_LISTVIEW	Owner-draw listview control
ODT_MENU	Owner-drawn menu
CtlID

Specifies the identifier of the combo box, list box, or button. This member is not used for a menu.

itemID

Specifies the identifier for a menu item or the position of a list box or combo box item. This value is specified for a list box only if it has the LBS_OWNERDRAWVARIABLE style; this value is specified for a combo box only if it has the CBS_OWNERDRAWVARIABLE style.

itemWidth

Specifies the width, in pixels, of a menu item. Before returning from the message, the owner of the owner-drawn menu item must fill this member.

itemHeight

Specifies the height, in pixels, of an individual item in a list box or a menu. Before returning from the message, the owner of the owner-drawn combo box, list box, or menu item must fill out this member.

itemData

Specifies the application-defined 32-bit value associated with the menu item. For a control, this member specifies the value last assigned to the list box or combo box by the LB_SETITEMDATA or CB_SETITEMDATA message. If the list box or combo box has the LB_HASSTRINGS or CB_HASSTRINGS style, this value is initially zero. Otherwise, this value is initially the value passed to the list box or combo box in the lParam parameter of one of the following messages:

CB_ADDSTRING
CB_INSERTSTRING
LB_ADDSTRING
LB_INSERTSTRING

Remarks

The owner window of an owner-drawn control receives a pointer to the MEASUREITEMSTRUCT structure as the lParam parameter of a WM_MEASUREITEM message. The owner-drawn control sends this message to its owner window when the control is created. The owner then fills in the appropriate members in the structure for the control and returns. This structure is common to all owner-drawn controls.

If an application does not fill the appropriate members of MEASUREITEMSTRUCT, the control or menu item may not be drawn properly.

See Also

CB_ADDSTRING, CB_INSERTSTRING, CB_SETITEMDATA, LB_ADDSTRING, LB_INSERTSTRING, LB_SETITEMDATA, WM_MEASUREITEM


MEMORY_BASIC_INFORMATION
MEMORY_BASIC_INFORMATION  QuickInfo

typedef struct _MEMORY_BASIC_INFORMATION { // mbi

    PVOID BaseAddress;            // base address of region

    PVOID AllocationBase;         // allocation base address

    DWORD AllocationProtect;      // initial access protection

    DWORD RegionSize;             // size, in bytes, of region

    DWORD State;                  // committed, reserved, free

    DWORD Protect;                // current access protection

    DWORD Type;                   // type of pages

} MEMORY_BASIC_INFORMATION;

typedef MEMORY_BASIC_INFORMATION *PMEMORY_BASIC_INFORMATION;

The MEMORY_BASIC_INFORMATION structure contains information about a range of pages in the virtual address space of a process. The VirtualQuery and VirtualQueryEx functions use this structure.

Members

BaseAddress

Points to the base address of the region of pages.

AllocationBase

Points to the base address of a range of pages allocated by the VirtualAlloc function. The page pointed to by the BaseAddress member is contained within this allocation range.

AllocationProtect

Specifies the access protection given when the region was initially allocated. One of the following flags can be present, along with the PAGE_GUARD and PAGE_NOCACHE protection modifier flags:

Flag	Meaning
PAGE_READONLY	Enables read access to the committed region of pages. An attempt to write to the committed region results in an access violation. If the system differentiates between read-only access and execute access, an attempt to execute code in the committed region results in an access violation.
PAGE_READWRITE	Enables both read and write access to the committed region of pages.
PAGE_WRITECOPY	Gives copy-on-write access to the committed region of pages.
PAGE_EXECUTE	Enables execute access to the committed region of pages. An attempt to read or write to the committed region results in an access violation.
PAGE_EXECUTE_READ	Enables execute and read access to the committed region of pages. An attempt to write to the committed region results in an access violation.
PAGE_EXECUTE_READWRITE	Enables execute, read, and write access to the committed region of pages.
PAGE_EXECUTE_WRITECOPY	Enables execute, read, and write access to the committed region of pages. The pages are shared read-on-write and copy-on-write.
PAGE_GUARD	Protects the page with the underlying page protection. However, access to the region causes a "guard page entered" condition to be raised in the subject process. This flag is a page protection modifier, only valid when used with one of the page protections other than PAGE_NOACCESS.
PAGE_NOACCESS	Disables all access to the committed region of pages. An attempt to read from, write to, or execute in the committed region results in an access violation exception, called a general protection (GP) fault.
PAGE_NOCACHE	Allows no caching of the committed regions of pages. The hardware attributes for the physical memory should be set to no cache. This is not recommended for general usage. It is useful for device drivers; for example, mapping a video frame buffer with no caching. This flag is a page protection modifier, only valid when used with one of the page protections other than PAGE_NOACCESS.
RegionSize

Specifies the size, in bytes, of the region beginning at the base address in which all pages have identical attributes.

State

Specifies the state of the pages in the region. One of the following states is indicated:

State	Meaning
MEM_COMMIT	Indicates committed pages for which physical storage has been allocated, either in memory or in the paging file on disk.
MEM_FREE	Indicates free pages not accessible to the calling process and available to be allocated. For free pages, the information in the AllocationBase, AllocationProtect, Protect, and Type members is undefined.
MEM_RESERVE	Indicates reserved pages where a range of the process's virtual address space is reserved without allocating any physical storage. For reserved pages, the information in the Protect member is undefined.
Protect

Specifies the access protection of the pages in the region. One of the flags listed for the AllocationProtect member is specified.

Type

Specifies the type of pages in the region. The following types are defined:

Type	Meaning
MEM_IMAGE	Indicates that the memory pages within the region are mapped into the view of an image section.
MEM_MAPPED	Indicates that the memory pages within the region are mapped into the view of a section.
MEM_PRIVATE	Indicates that the memory pages within the region are private (not shared by other processes).
See Also

VirtualAlloc, VirtualQuery, VirtualQueryEx


MEMORYSTATUS
MEMORYSTATUS  QuickInfo

typedef struct _MEMORYSTATUS { // mst

    DWORD dwLength;        // sizeof(MEMORYSTATUS)

    DWORD dwMemoryLoad;    // percent of memory in use

    DWORD dwTotalPhys;     // bytes of physical memory

    DWORD dwAvailPhys;     // free physical memory bytes

    DWORD dwTotalPageFile; // bytes of paging file

    DWORD dwAvailPageFile; // free bytes of paging file

    DWORD dwTotalVirtual;  // user bytes of address space

    DWORD dwAvailVirtual;  // free user bytes

} MEMORYSTATUS, *LPMEMORYSTATUS;

The MEMORYSTATUS structure contains information about current memory availability. The GlobalMemoryStatus function uses this structure.

Members

dwLength

Indicates the size of the structure. The calling process should set this member prior to calling GlobalMemoryStatus.

dwMemoryLoad

Specifies a number between 0 and 100 that gives a general idea of current memory utilization, in which 0 indicates no memory use and 100 indicates full memory use.

dwTotalPhys

Indicates the total number of bytes of physical memory.

dwAvailPhys

Indicates the number of bytes of physical memory available.

dwTotalPageFile

Indicates the total number of bytes that can be stored in the paging file. Note that this number does not represent the actual physical size of the paging file on disk.

dwAvailPageFile

Indicates the number of bytes available in the paging file.

dwTotalVirtual

Indicates the total number of bytes that can be described in the user mode portion of the virtual address space of the calling process.

dwAvailVirtual

Indicates the number of bytes of unreserved and uncommitted memory in the user mode portion of the virtual address space of the calling process.

See Also

GlobalMemoryStatus


MENU_EVENT_RECORD
MENU_EVENT_RECORD  QuickInfo  Overview  Group

typedef struct _MENU_EVENT_RECORD { // mer

    UINT dwCommandId;

} MENU_EVENT_RECORD, *PMENU_EVENT_RECORD;

The MENU_EVENT_RECORD structure reports menu events in a console INPUT_RECORD structure. These events are used internally and should be ignored.

Members

dwCommandId

Used internally.

See Also

INPUT_RECORD


MENUEX_TEMPLATE_HEADER [New - Windows 95]
MENUEX_TEMPLATE_HEADER  QuickInfo  Overview  Group

[New - Windows 95]

typedef struct

    WORD  wVersion;

    WORD  wOffset;

    DWORD dwHelpId;

} MENUEX_TEMPLATE_HEADER;

The MENUEX_TEMPLATE_HEADER structure defines the header for an extended menu template.

Members

wVersion

Template version number. This member must be 1 for extended menu templates.

wOffset

Offset of the first MENUEX_TEMPLATE_ITEM structure, relative to the end of this structure member. If the first item definition immediately follows the dwHelpId member, this member should be 4.

dwHelpId

Help identifier of menu bar

Remarks

An extended menu template consists of a MENUEX_TEMPLATE_HEADER structure followed by one or more contiguous MENUEX_TEMPLATE_ITEM structures. The MENUEX_TEMPLATE_ITEM structures, which are variable in length, are aligned on doubleword boundaries. To create a menu from an extended menu template in memory, use the LoadMenuIndirect function.

The structure definition given here is for explanation only; it is not present in any standard header file.

See Also

LoadMenuIndirect, MENUEX_TEMPLATE_ITEM


MENUEX_TEMPLATE_ITEM [New - Windows 95]
MENUEX_TEMPLATE_ITEM  QuickInfo  Overview  Group

[New - Windows 95]

typedef struct {

    DWORD  dwType;

    DWORD  dwState;

    UINT   uId;

    BYTE   bResInfo;

    WCHAR  szText[1];

    // DWORD dwHelpId;

} MENUEX_TEMPLATE_ITEM;

The MENUEX_TEMPLATE_ITEM structure defines a menu item in an extended menu template.

Members

dwType

Menu item type. This member can be a combination of the type (beginning with MFT) values listed with the MENUITEMINFO structure.

dwState

Menu item state. This member can be a combination of the state (beginning with MFS) values listed with the MENUITEMINFO structure.

uId

Menu item identifier. This is an application-defined 16-bit value that identifies the menu item. In an extended menu resource, pop-up items as well as command items can have identifiers.

bResInfo

Value specifying whether the menu item is the last item in the menu bar or pop-up menu and whether it is a pop-up item. This member can be zero or more of these values:

Value	Meaning
MFR_END	The structure defines the last menu item in the menu bar or pop-up menu.
MFR_POPUP	The structure defines a pop-up item. Subsequent structures define menu items in the corresponding pop-up menu.
szText

Menu item text. This member, which is a null-terminated Unicode string, is aligned on a word boundary. The size of the menu item definition varies depending on the length of this string.

dwHelpId

Help identifier for a pop-up menu. This member, which is included only for pop-up items, is located at the first doubleword boundary following the variable-length szText member.

Remarks

An extended menu template consists of a MENUEX_TEMPLATE_HEADER structure followed by one or more contiguous MENUEX_TEMPLATE_ITEM structures. The MENUEX_TEMPLATE_ITEM structures, which are variable in length, are aligned on doubleword boundaries.

The structure definition given here is for explanation only; it is not present in any standard header file.

See Also

MENUEX_TEMPLATE_HEADER, MENUITEMINFO


MENUITEMINFO [New - Windows 95]
MENUITEMINFO  QuickInfo  Overview  Group

[New - Windows 95]

typedef struct tagMENUITEMINFO {
    UINT    cbSize;

    UINT    fMask;

    UINT    fType;

    UINT    fState;

    UINT    wID;

    HMENU   hSubMenu;

    HBITMAP hbmpChecked;

    HBITMAP hbmpUnchecked;

    DWORD   dwItemData;

    LPTSTR  dwTypeData;

    UINT    cch;

} MENUITEMINFO, FAR *LPMENUITEMINFO;

The MENUITEMINFO structure contains information about a menu item.

Members

cbsize

Size of structure, in bytes.

fMask

Members to retrieve or set. This member can be one or more of these values:

Value	Meaning
MIIM_CHECKMARKS	Retrieves or sets the hbmpChecked and hbmpUnchecked members.
MIIM_DATA	Retrieves or sets the dwItemData member.
MIIM_ID	Retrieves or sets the wID member.
MIIM_STATE	Retrieves or sets the fState member.
MIIM_SUBMENU	Retrieves or sets the hSubMenu member.
MIIM_TYPE	Retrieves or sets the fType and dwTypeData members.
fType

Menu item type. This member can be one or more of these values:

Value	Meaning
MFT_BITMAP	Displays the menu item using a bitmap. The low-order word of the dwTypeData member is the bitmap handle, and the cch member is ignored.
MFT_MENUBARBREAK	Places the menu item on a new line if it is in a menu bar or in a new column if it is in a pop-up menu. A vertical line separates the new column from the old.
MFT_MENUBREAK	Places the menu item on a new line if it is in a menu bar or in a new column if it is in a pop-up menu. The columns are not separated by a vertical line.
MFT_OWNERDRAW	Assigns responsibility for drawing the menu item to the window that owns the menu. The window receives a WM_MEASUREITEM message before the menu is displayed for the first time, and a WM_DRAWITEM message whenever the appearance of the menu item must be updated. If this value is specified, the dwTypeData member contains an application-defined 32-bit value.
MFT_RADIOCHECK	Displays checked menu items using a radio-button mark instead of a check mark if the hbmpChecked member is NULL.
MFT_RIGHTJUSTIFY	Right-justifies the menu item and any subsequent items. This value is valid only if the menu item is in a menu bar.
MFT_SEPARATOR	Specifies that the menu item is a separator. A menu item separator appears as a horizontal dividing line. The dwTypeData and cch members are ignored. This value is valid only if the menu item is in a pop-up menu.
MFT_STRING	Displays the menu item using a text string. The dwTypeData member is the pointer to a null-terminated string, and the cch member is the length of the string.
The MFT_BITMAP, MFT_SEPARATOR, and MFT_STRING values cannot be combined with one another.

fState

Menu item state. This member can be one or more of these values:

Value	Meaning
MFS_CHECKED	Checks the menu item. For more information about checked menu items, see the hbmpChecked member.
MFS_DEFAULT	Specifies that the menu item is the default. A menu can contain only one default menu item, which is displayed in bold.
MFS_DISABLED	Disables the menu item so that it cannot be selected, but does not gray it.
MFS_ENABLED	Enables the menu item so that it can be selected. This is the default state.
MFS_GRAYED	Disables the menu item and grays it so that it cannot be selected.
MFS_HILITE	Highlights the menu item.
MFS_UNCHECKED	Unchecks the menu item. For more information about unchecked menu items, see the hbmpUnchecked member.
MFS_UNHILITE	Removes the highlight from the menu item. This is the default state.
wID

Application-defined 16-bit value that identifies the menu item.

hSubMenu

Handle to the pop-up menu associated with the menu item. If the menu item is not a pop-up item, this member is NULL.

hbmpChecked

Handle to the bitmap to display next to the item if it is checked. If this member is NULL, a default bitmap is used. If the MFT_RADIOCHECK type value is specified, the default bitmap is a bullet. Otherwise, it is a check mark.

hbmpUnchecked

Handle to the bitmap to display next to the item if it is not checked. If this member is NULL, no bitmap is used.

dwItemData

Application-defined value associated with the menu item.

dwTypeData

Content of the menu item. The meaning of this member depends on the menu item type: the MFT_BITMAP, MFT_SEPARATOR, or MFT_STRING values.

cch

Length of the menu item text, when information is received about a menu item of the MFT_STRING type. This value is zero for other menu item types. This member is ignored when the content of a menu item is set.

Remarks

The MENUITEMINFO structure is used with the GetMenuItemInfo, InsertMenuItem, and SetMenuItemInfo functions.

See Also

GetMenuItemInfo, InsertMenuItem, SetMenuItemInfo, WM_DRAWITEM, WM_MEASUREITEM


MENUITEMTEMPLATE
MENUITEMTEMPLATE  QuickInfo

typedef struct {    // mit

    WORD mtOption;       // menu item flags

    WORD mtID;           // menu item identifier (omitted for pop-up items)

    WCHAR mtString[1];   // null-terminated string for menu item

} MENUITEMTEMPLATE;

The MENUITEMTEMPLATE structure defines a menu item in a menu template.

Members

mtOption

Specifies one or more of the following predefined menu options that control the appearance of the menu item:

Value	Meaning
MF_CHECKED	Indicates that the menu item has a check mark next to it.
MF_GRAYED	Indicates that the menu item is initially inactive and drawn with a gray effect.
MF_HELP	Indicates that the menu item has a vertical separator to its left.
MF_MENUBARBREAK	Indicates that the menu item is placed in a new column. The old and new columns are separated by a bar.
MF_MENUBREAK	Indicates that the menu item is placed in a new column.
MF_OWNERDRAW	Indicates that the owner window of the menu is responsible for drawing all visual aspects of the menu item, including highlighted, checked, and inactive states. This option is not valid for an item in a menu bar.
MF_POPUP	Indicates that the item is a pop-up item (a pop-up item invokes a pop-up menu when the user chooses the item).
mtID

Specifies the menu item identifier of a command item; a command item sends a command message to its owner window. The MENUITEMTEMPLATE structure for a pop-up item does not contain the mtID member.

mtString

Specifies the null-terminated string for the menu item.

See Also

LoadMenuIndirect, MENUITEMTEMPLATEHEADER


MENUITEMTEMPLATEHEADER
MENUITEMTEMPLATEHEADER  QuickInfo

typedef struct {          // mith

    WORD versionNumber;   // version number; must be zero

    WORD offset;          // offset first MENUITEMTEMPLATE structure

} MENUITEMTEMPLATEHEADER;

The MENUITEMTEMPLATEHEADER structure defines the header for a menu template. A complete menu template consists of a header and one or more menu item lists.

Members

versionNumber

Specifies the version number. This member must be zero.

offset

Specifies the offset, in bytes, from the end of the header. The menu item list begins at this offset. Usually, this member is zero, and the menu item list follows immediately after the header.

Remarks

One or more MENUITEMTEMPLATE structures are combined to form the menu item list.

See Also

LoadMenuIndirect, MENUITEMTEMPLATE


METAFILEPICT
METAFILEPICT  QuickInfo

typedef struct tagMETAFILEPICT { // mfp

    LONG      mm;

    LONG      xExt;

    LONG      yExt;

    HMETAFILE hMF;

} METAFILEPICT;

The METAFILEPICT structure defines the metafile picture format used for exchanging metafile data through the clipboard.

Members

mm

Specifies the mapping mode in which the picture is drawn.

xExt

Specifies the size of the metafile picture for all modes except the MM_ISOTROPIC and MM_ANISOTROPIC modes. (For more information about these modes, see the yExt member.) The x-extent specifies the width of the rectangle within which the picture is drawn. The coordinates are in units that correspond to the mapping mode.

yExt

Specifies the size of the metafile picture for all modes except the MM_ISOTROPIC and MM_ANISOTROPIC modes. The y-extent specifies the height of the rectangle within which the picture is drawn. The coordinates are in units that correspond to the mapping mode.

For MM_ISOTROPIC and MM_ANISOTROPIC modes, which can be scaled, the xExt and yExt members contain an optional suggested size in MM_HIMETRIC units. For MM_ANISOTROPIC pictures, xExt and yExt can be zero when no suggested size is supplied. For MM_ISOTROPIC pictures, an aspect ratio must be supplied even when no suggested size is given. (If a suggested size is given, the aspect ratio is implied by the size.) To give an aspect ratio without implying a suggested size, set xExt and yExt to negative values whose ratio is the appropriate aspect ratio. The magnitude of the negative xExt and yExt values is ignored; only the ratio is used.

hMF

Identifies a memory metafile.

See Also

SetClipboardData


METAHEADER
METAHEADER  QuickInfo

typedef struct tagMETAHEADER {  // mh

    WORD  mtType;

    WORD  mtHeaderSize;

    WORD  mtVersion;

    DWORD mtSize;

    WORD  mtNoObjects;

    DWORD mtMaxRecord;

    WORD  mtNoParameters;

} METAHEADER;

The METAHEADER structure contains information about a Windows-format metafile.

Members

mtType

Specifies whether the metafile is in memory or recorded in a disk file. This member can be one of the following values:

Value	Meaning
1	Metafile is in memory.
2	Metafile is in a disk file.
mtHeaderSize

Specifies the size, in words, of the metafile header.

mtVersion

Specifies the Windows version number. The version number for metafiles that support device-independent bitmaps (DIBs) is 0x0300. Otherwise, the version number is 0x0100.

mtSize

Specifies the size, in words, of the file.

mtNoObjects

Specifies the maximum number of objects that exist in the metafile at the same time.

mtMaxRecord

Specifies the size, in words, of the largest record in the metafile.

mtNoParameters

Reserved.

See Also

METARECORD


METARECORD
METARECORD  QuickInfo

typedef struct tagMETARECORD {  // mr

    DWORD rdSize;

    WORD  rdFunction;

    WORD  rdParm[1];

} METARECORD;

The METARECORD structure contains a Windows-format metafile record.

Members

rdSize

Specifies the size, in words, of the record.

rdFunction

Specifies the function number.

rdParm

Specifies an array of words containing the function parameters, in reverse of the order they are passed to the function.

See Also

METAHEADER


MINIMIZEDMETRICS
MINIMIZEDMETRICS  QuickInfo

typedef struct tagMINIMIZEDMETRICS {

    UINT    cbSize;

    int     iWidth;

    int     iHorzGap;

    int     iVertGap;

    int     iArrange;

}   MINIMIZEDMETRICS, FAR *LPMINIMIZEDMETRICS;

The MINIMIZEDMETRICS structure contains the scalable metrics associated with minimized windows. This structure is used with the SystemParametersInfo function when the SPI_GETMINIMIZEDMETRICS or SPI_SETMINIMIZEDMETRICS action value is specified.

Members

cbSize

Specifies the size of the structure, in bytes.

iWidth

Specifies the width, in pixels, of minimized windows.

iHorzGap and iVertGap

Specifies the amount of horizontal and vertical space, in pixels, between arranged minimized windows.

iArrange

Specifies the starting position and direction used when arranging minimized windows. The starting position must be one of the following values:

Value	Meaning
ARW_BOTTOMLEFT	Start at the lower-left corner of the work area.
ARW_BOTTOMRIGHT	Start at the lower-right corner of the work area.
ARW_TOPLEFT	Start at the upper-left corner of the work area.
ARW_TOPRIGHT	Start at the upper-right corner of the work area.
The direction must be one of the following values:

Value	Meaning
ARW_LEFT	Arrange left (valid with ARW_BOTTOMRIGHT and ARW_TOPRIGHT only).
ARW_RIGHT	Arrange right (valid with ARW_BOTTOMLEFT and ARW_TOPLEFT only).
ARW_UP	Arrange up (valid with ARW_BOTTOMLEFT and ARW_BOTTOMRIGHT only).
ARW_DOWN	Arrange down (valid with ARW_TOPLEFT and ARW_TOPRIGHT only).
See Also

SystemParametersInfo


MINMAXINFO
MINMAXINFO  QuickInfo

typedef struct tagMINMAXINFO {  // mmi

    POINT ptReserved;

    POINT ptMaxSize;

    POINT ptMaxPosition;

    POINT ptMinTrackSize;

    POINT ptMaxTrackSize;

} MINMAXINFO;

The MINMAXINFO structure contains information about a window's maximized size and position and its minimum and maximum tracking size.

Members

ptReserved

Reserved; do not use.

ptMaxSize

Specifies the maximized width (point.x) and the maximized height (point.y) of the window.

ptMaxPosition

Specifies the position of the left side of the maximized window (point.x) and the position of the top of the maximized window (point.y).

ptMinTrackSize

Specifies the minimum tracking width (point.x) and the minimum tracking height (point.y) of the window.

ptMaxTrackSize

Specifies the maximum tracking width (point.x) and the maximum tracking height (point.y) of the window.

See Also

POINT, WM_GETMINMAXINFO


MODEMDEVCAPS
MODEMDEVCAPS  QuickInfo

typedef struct modemdevcaps_tag {
    DWORD dwActualSize;               // size of returned data, in bytes
    DWORD dwRequiredSize;             // total size of structure
    DWORD dwDevSpecificOffset;        // offset of provider-defined data
    DWORD dwDevSpecificSize;          // size of provider-defined data

    // Product and version identification
    DWORD dwModemProviderVersion;     // provider version number
    DWORD dwModemManufacturerOffset;  // offset of manufacturer name
    DWORD dwModemManufacturerSize;    // length of manufacturer name
    DWORD dwModemModelOffset;         // offset of model name
    DWORD dwModemModelSize;           // length of model name
    DWORD dwModemVersionOffset;       // offset of version name
    DWORD dwModemVersionSize;         // length of version name

    // Local option capabilities
    DWORD dwDialOptions;              // bitmap of supported values
    DWORD dwCallSetupFailTimer;       // maximum in seconds
    DWORD dwInactivityTimeout;        // maximum in tenths of seconds
    DWORD dwSpeakerVolume;            // bitmap of supported values
    DWORD dwSpeakerMode;              // bitmap of supported values
    DWORD dwModemOptions;             // bitmap of supported values
    DWORD dwMaxDTERate;               // maximum value in bit/s
    DWORD dwMaxDCERate;               // maximum value in bit/s

    // Variable portion for strings and provider-specific data
    BYTE abVariablePortion [1];       // variable-length data
} MODEMDEVCAPS, *PMODEMDEVCAPS, *LPMODEMDEVCAPS;

The MODEMDEVCAPS structure contains information about the capabilities of a modem.

Members

dwActualSize

Specifies the size, in bytes, of the data actually returned to the application. This member may be less than the dwRequiredSize member, if an application did not allocate enough space for the variable-length portion of the structure.

dwRequiredSize

Specifies the number of bytes required for the entire MODEMDEVCAPS structure, including the variable-length portion.

dwDevSpecificOffset

Specifies the offset of the provider-defined portion of the structure, in bytes relative to the beginning of the structure.

dwDevSpecificSize

Specifies the size of the provider-defined portion of the structure, in bytes.

dwModemProviderVersion

Specifies the version of the service provider. The format and use of this member depends on the service provider.

dwModemManufacturerOffset

Specifies the offset of a text string that contains the name of the modem manufacturer. The offset is specified in bytes relative to the beginning of the structure.

dwModemManufacturerSize

Specifies the length of the modem manufacturer name, in bytes. The string is not null-terminated.

dwModemModelOffset

Specifies the offset of a text string that contains the model of the modem. The offset is specified in bytes relative to the beginning of the structure.

dwModemModelSize

Specifies the length of the model name, in bytes. The string is not null-terminated.

dwModemVersionOffset

Specifies the offset of a text string that gives the version and revision of the attached modem, if the provider could determine the information. The offset is specified in bytes relative to the beginning of the structure.

dwModemVersionSize

Specifies the length of the modem version string, in bytes. The string is not null-terminated.

dwDialOptions

Specifies dialing options that are supported by the modem device. This member can be zero or more of the following values:

Value	Meaning
DIALOPTION_DIALBILLING	Specifies that the modem supports waiting for billing tone (bong).
DIALOPTION_DIALQUIET	Specifies that the modem supports waiting for quiet.
DIALOPTION_DIALDIALTONE	Specifies that the modem supports waiting for a dial tone.
dwCallSetupFailTimer

Specifies the maximum call setup timeout supported by the modem, in seconds. This is the largest value that can be specified for the corresponding member of the MODEMSETTINGS structure.

dwInactivityTimeout

Specifies the maximum inactivity timeout supported by the modem, in tenths of seconds. This is the largest value that can be specified for the corresponding member of the MODEMSETTINGS structure.

dwSpeakerVolume

Specifies the speaker volume settings supported by the modem. This member can be zero or more of the following values:

Value	Meaning
MDMVOLFLAG_LOW	The modem supports low (MDMVOL_LOW) volume.
MDMVOLFLAG_MEDIUM	The modem supports medium (MDMVOL_MEDIUM) volume.
MDMVOLFLAG_HIGH	The modem supports high (MDMVOL_HIGH) volume.
dwSpeakerMode

Specifies the speaker mode settings supported by the modem. This member can be zero or more of the following values:

Value	Meaning
MDMSPKRFLAG_OFF	The modem supports the MDMSPKR_OFF speaker mode.
MDMSPKRFLAG_DIAL	The modem supports the MDMSPKR_DIAL speaker mode.
MDMSPKRFLAG_ON	The modem supports the MDMSPKR_ON speaker mode.
MDMSPKRFLAG_CALLSETUP	The modem supports the MDMSPKR_CALLSETUP speaker mode.
dwModemOptions

Specifies supported modem options. This member can be zero or more of the following values:

MDM_BLIND_DIAL	MDM_FLOWCONTROL_SOFT
MDM_CCITT_OVERRIDE	MDM_FORCED_EC
MDM_CELLULAR	MDM_SPEED_ADJUST
MDM_COMPRESSION	MDM_TONE_DIAL
MDM_ERROR_CONTROL	MDM_V23_OVERRIDE
MDM_FLOWCONTROL_HARD
When MODEMDEVCAPS is used to set modem options, as part of the MODEMSETTINGS structure, these values are used as follows:

Value	Meaning
MDM_CCITT_OVERRIDE	When set, CCITT modulations are enabled for V.21 and V.22 or V.23. When clear, bell modulations are enabled for 103 and 212A.
MDM_V23_OVERRIDE	When set, CCITT modulations are enabled for V.23. When clear, CCITT modulations are enabled for V.21 and V.22.
For V.23 to be set, both MDM_CCITT_OVERRIDE and MDM_V23_OVERRIDE must be set.

dwMaxDTERate

Maximum DTE rate in bits per second.

dwMaxDCERate

Maximum DCE rate in bits per second.

abVariablePortion

Contains variable-length information, including strings and any provider-defined information.

See Also

MODEMSETTINGS


MODEMSETTINGS
MODEMSETTINGS  QuickInfo

typedef struct modemsettings_tag {
    DWORD dwActualSize;               // size of returned data, in bytes
    DWORD dwRequiredSize;             // total size of structure
    DWORD dwDevSpecificOffset;        // offset of provider-defined data
    DWORD dwDevSpecificSize;          // size of provider-defined data

    // Static local options (read/write)
    DWORD dwCallSetupFailTimer;       // call setup timeout, in seconds
    DWORD dwInactivityTimeout;        // inactivity timeout, in tenths of seconds
    DWORD dwSpeakerVolume;            // speaker volume level
    DWORD dwSpeakerMode;              // speaker mode
    DWORD dwPreferredModemOptions;    // bitmap specifying preferred options

    // negotiated options (read only) for current or last call
    DWORD dwNegotiatedModemOptions;   // bitmap specifying actual options
    DWORD dwNegotiatedDCERate;        // DCE rate, in bits per second

    // Variable portion for proprietary expansion
    BYTE  abVariablePortion[1];       // variable-length data
} MODEMSETTINGS, *PMODEMSETTINGS, *LPMODEMSETTINGS;

The MODEMSETTINGS structure contains information about a modem's configuration.

Members

dwActualSize

Specifies the size, in bytes, of the data actually returned to the application. This member may be less than the dwRequiredSize member if an application did not allocate enough space for the variable-length portion of the structure.

dwRequiredSize

Specifies the number of bytes required for the entire MODEMDEVCAPS structure, including the variable-length portion.

dwDevSpecificOffset

Specifies the offset of the provider-defined portion of the structure, in bytes relative to the beginning of the structure.

dwDevSpecificSize

Specifies the size of the provider-defined portion of the structure, in bytes.

dwCallSetupFailTimer

Specifies the maximum number of seconds the modem should wait, after dialing is completed, for an indication that a modem-to-modem connection has been established. If a connection is not established in this interval, the call is assumed to have failed. This member is equivalent to register S7 in Hayes® compatible modems.

dwInactivityTimeout

Specifies the maximum number of seconds of inactivity allowed after a connection is established. If no data is either transmitted or received for this period of time, the call is automatically terminated. This time-out is used to avoid excessive long distance charges or online service charges if an application unexpectedly locks up or the user leaves.

dwSpeakerVolume

Specifies the volume level of the monitor speaker when the speaker is on. This member can be one of the following values:

Value	Meaning
MDMVOL_LOW	Low volume.
MDMVOL_MEDIUM	Medium volume.
MDMVOL_HIGH	High volume.
The MODEMDEVCAPS structure specifies the speaker volumes a modem supports. Actual volumes are hardware-specific.

dwSpeakerMode

Specifies when the speaker should be on. This member can be one of the following values:

Value	Meaning
MDMSPKR_OFF	The speaker is always off.
MDMSPKR_CALLSETUP	The speaker is on until a connection is established.
MDMSPKR_ON	The speaker is always on.
MDMSPKR_DIAL	The speaker is on until a connection is established, except that it is off while the modem is actually dialing.
dwPreferredModemOptions

Specifies the modem options requested by the application. The local and remote modems negotiate modem options during call setup; this member specifies the initial negotiating position of the local modem.

The dwModemOptions member of the MODEMDEVCAPSstructure specifies the modem options supported by the local modem. For a list of modem options, see the description of the MODEMDEVCAPS structure.

dwNegotiatedModemOptions

Specifies the modem options that are actually in effect. This member is filled in after a connection is established and the local and remote modems negotiate modem options.

The dwModemOptions member of the MODEMDEVCAPS structure specifies the modem options supported by the local modem. For a list of modem options, see the description of the MODEMDEVCAPS structure.

dwNegotiatedDCERate

Specifies the DCE rate that is in effect. This member is filled in after a connection is established and the local and remote modems negotiate modem modulations.

abVariablePortion

Contains provider-defined information, if any.

See Also

MODEMDEVCAPS


MONCBSTRUCT
MONCBSTRUCT  QuickInfo

typedef struct tagMONCBSTRUCT { // mcbst

    UINT   cb;

    DWORD  dwTime;

    HANDLE hTask;

    DWORD  dwRet;

    UINT   wType;

    UINT   wFmt;

    HCONV  hConv;

    HSZ    hsz1;

    HSZ    hsz2;

    HDDEDATA hData;

    DWORD    dwData1;

    DWORD    dwData2;

    CONVCONTEXT cc;

    DWORD  cbData;

    DWORD  Data[8];

} MONCBSTRUCT;

The MONCBSTRUCT structure contains information about the current DDE transaction. A DDE debugging application can use this structure when monitoring transactions that the system passes to the DDE callback functions of other applications.

Members

cb

Specifies the structure's size, in bytes.

dwTime

Specifies the Windows time that the transaction occurred. Windows time is the number of milliseconds that have elapsed since the system was booted.

hTask

Identifies the task (application instance) containing the DDE callback function that received the transaction.

dwRet

Specifies the value returned by the DDE callback function that processed the transaction.

wType

Identifies the transaction type.

wFmt

Specifies the format of the data exchanged (if any) during the transaction.

hConv

Identifies the conversation in which the transaction took place.

hsz1

Identifies a string.

hsz2

Identifies a string.

hData

Identifies the data exchanged (if any) during the transaction.

dwData1

Specifies additional data.

dwData2

Specifies additional data.

cc

Specifies a CONVCONTEXT structure containing language information used to share data in different languages.

cbData

Specifies the amount, in bytes, of data being passed with the transaction. This value may be more than 32 bytes.

Data

Contains the first 32 bytes of data being passed with the transaction
(8 * sizeof(DWORD)).

See Also

CONVCONTEXT, MONERRSTRUCT, MONHSZSTRUCT, MONLINKSTRUCT, MONMSGSTRUCT


MONCONVSTRUCT
MONCONVSTRUCT  QuickInfo

typedef struct tagMONCONVSTRUCT { // mcvst

    UINT   cb;

    BOOL   fConnect;

    DWORD  dwTime;

    HANDLE hTask;

    HSZ    hszSvc;

    HSZ    hszTopic;

    HCONV  hConvClient;

    HCONV  hConvServer;

} MONCONVSTRUCT;

The MONCONVSTRUCT structure contains information about a DDE conversation. A DDE monitoring application can use this structure to obtain information about a conversation that has been established or has terminated.

Members

cb

Specifies the structure's size, in bytes.

fConnect

Indicates whether the conversation is currently established. A value of TRUE indicates the conversation is established; FALSE indicates it is not.

dwTime

Specifies the Windows time at which the conversation was established or terminated. Windows time is the number of milliseconds that have elapsed since the system was booted.

hTask

Identifies a task (application instance) that is a partner in the conversation.

hszSvc

Identifies the service name on which the conversation is established.

hszTopic

Identifies the topic name on which the conversation is established.

hConvClient

Identifies the client conversation.

hConvServer

Identifies the server conversation.

Remarks

Because string handles are local to the process, the hszSvc and hszTopic members are global atoms. Similarly, conversation handles are local to the instance; therefore, the hConvClient and hConvServer members are window handles.

The hConvClient and hConvServer members of the MONCONVSTRUCT structure do not hold the same value as would be seen by the applications engaged in the conversation. Instead, they hold a globally unique pair of values that identify the conversation.

See Also

MONCBSTRUCT, MONERRSTRUCT, MONHSZSTRUCT, MONLINKSTRUCT, MONMSGSTRUCT


MONERRSTRUCT
MONERRSTRUCT  QuickInfo

typedef struct tagMONERRSTRUCT { // mest

    UINT   cb;

    UINT   wLastError;

    DWORD  dwTime;

    HANDLE hTask;

} MONERRSTRUCT;

The MONERRSTRUCT structure contains information about the current DDE error. A DDE monitoring application can use this structure to monitor errors returned by DDE Management Library functions.

Members

cb

Specifies the structure's size, in bytes.

wLastError

Identifies the current error.

dwTime

Specifies the Windows time that the error occurred. Windows time is the number of milliseconds that have elapsed since the system was booted.

hTask

Identifies the task (application instance) that called the DDE function that caused the error.

See Also

MONCBSTRUCT, MONCONVSTRUCT, MONHSZSTRUCT, MONLINKSTRUCT, MONMSGSTRUCT


MONHSZSTRUCT
MONHSZSTRUCT  QuickInfo

typedef struct tagMONHSZSTRUCT { // mhst

    UINT   cb;

    BOOL   fsAction;

    DWORD  dwTime;

    HSZ    hsz;

    HANDLE hTask;

    TCHAR   str[1];

} MONHSZSTRUCT;

The MONHSZSTRUCT structure contains information about a DDE string handle. A DDE monitoring application can use this structure when monitoring the activity of the string manager component of the DDE Management Library.

Members

cb

Specifies the structure's size, in bytes.

fsAction

Specifies the action being performed on the string identified by the hsz member.

Value	Meaning
MH_CLEANUP	An application is freeing its DDE resources, causing the system to delete string handles the application had created. (The application called the DdeUninitialize function.)
MH_CREATE	An application is creating a string handle. (The application called the DdeCreateStringHandle function.)
MH_DELETE	An application is deleting a string handle. (The application called the DdeFreeStringHandle function.)
MH_KEEP	An application is increasing the usage count of a string handle. (The application called the DdeKeepStringHandle function.)
dwTime

Specifies the Windows time when the action specified by the fsAction member takes place. Windows time is the number of milliseconds that have elapsed since the system was booted.

hsz

Identifies the string. Because string handles are local to the process, this member is a global atom.

hTask

Identifies the task (application instance) performing the action on the string handle.

str

Points to the string identified by the hsz member.

See Also

MONCBSTRUCT, MONCONVSTRUCT, MONERRSTRUCT, MONLINKSTRUCT, MONMSGSTRUCT


MONITOR_INFO_1
MONITOR_INFO_1  QuickInfo

typedef struct _MONITOR_INFO_1 { // mi1

    LPTSTR pName;

} MONITOR_INFO_1;

The MONITOR_INFO_1 structure identifies an installed monitor.

Members

pName

Points to a null-terminated string that identifies an installed monitor.

See Also

EnumMonitors, MONITOR_INFO_2


MONITOR_INFO_2
MONITOR_INFO_2  QuickInfo

typedef struct _MONITOR_INFO_2 { // mi2

    LPTSTR pName;

    LPTSTR pEnvironment ;

    LPTSTR pDLLName ;

} MONITOR_INFO_2;

The MONITOR_INFO_2 structure identifies a monitor.

Members

pName

Points to a null-terminated string that is the name of the monitor.

pEnvironment

Points to a null-terminated environment string specifying the environment in which the monitor dynamic-link library (DLL) is designed to run.

pDLLName

Points to a null-terminated string that is the name of the monitor DLL.

See Also

EnumMonitors, MONITOR_INFO_1


MONLINKSTRUCT
MONLINKSTRUCT  QuickInfo

typedef struct tagMONLINKSTRUCT { // mlst

    UINT   cb;

    DWORD  dwTime;

    HANDLE hTask;

    BOOL   fEstablished;

    BOOL   fNoData;

    HSZ    hszSvc;

    HSZ    hszTopic;

    HSZ    hszItem;

    UINT   wFmt;

    BOOL   fServer;

    HCONV  hConvServer;

    HCONV  hConvClient;

} MONLINKSTRUCT;

The MONLINKSTRUCT structure contains information about a DDE advise loop. A DDE monitoring application can use this structure to obtain information about an advise loop that has started or ended.

Members

cb

Specifies the structure's size, in bytes.

dwTime

Specifies the Windows time when the advise loop was started or ended. Windows time is the number of milliseconds that have elapsed since the system was booted.

hTask

Identifies a task (application instance) that is a partner in the advise loop.

fEstablished

Indicates whether an advise loop was successfully established. A value of TRUE indicates an advise loop was established; FALSE indicates it was not.

fNoData

Indicates whether the XTYPF_NODATA flag is set for the advise loop. A value of TRUE indicates the flag is set; FALSE indicates it is not.

hszSvc

Identifies the service name of the server in the advise loop.

hszTopic

Identifies the topic name on which the advise loop is established.

hszItem

Identifies the item name that is the subject of the advise loop.

wFmt

Specifies the format of the data exchanged (if any) during the advise loop.

fServer

Indicates whether the link notification came from the server. A value of TRUE indicates the notification came from the server; FALSE indicates otherwise.

hConvServer

Identifies the server conversation.

hConvClient

Identifies the client conversation.

Remarks

Because string handles are local to the process, the hszSvc, hszTopic, and hszItem members are global atoms.

The hConvClient and hConvServer members of the MONLINKSTRUCT structure do not hold the same value as would be seen by the applications engaged in the conversation. Instead, they hold a globally unique pair of values that identify the conversation.

See Also

MONCBSTRUCT, MONERRSTRUCT, MONHSZSTRUCT, MONMSGSTRUCT


MONMSGSTRUCT
MONMSGSTRUCT  QuickInfo

typedef struct tagMONMSGSTRUCT { // mmst

    UINT   cb;

    HWND   hwndTo;

    DWORD  dwTime;

    HANDLE hTask;

    UINT   wMsg;

    WPARAM wParam;

    LPARAM lParam;

    DDEML_MSG_HOOK_DATA dmhd;

} MONMSGSTRUCT;

The MONMSGSTRUCT structure contains information about a DDE message. A DDE monitoring application can use this structure to obtain information about a DDE message that was sent or posted.

Members

cb

Specifies the structure's size, in bytes.

hwndTo

Identifies the window that receives the DDE message.

dwTime

Specifies the Windows time at which the message was sent or posted. Windows time is the number of milliseconds that have elapsed since the system was booted.

hTask

Identifies the task (application instance) containing the window that receives the DDE message.

wMsg

Specifies the identifier of the DDE message.

wParam

Specifies the wParam parameter of the DDE message.

lParam

Specifies the lParam parameter of the DDE message.

dmhd

Specifies a DDEML_MSG_HOOK_DATA structure that contains additional information about the DDE message.

See Also

DDEML_MSG_HOOK_DATA, MONCBSTRUCT, MONCONVSTRUCT, MONERRSTRUCT, MONHSZSTRUCT, MONLINKSTRUCT


MOUSE_EVENT_RECORD
MOUSE_EVENT_RECORD  QuickInfo

typedef struct _MOUSE_EVENT_RECORD { // mer

    COORD dwMousePosition;

    DWORD dwButtonState;

    DWORD dwControlKeyState;

    DWORD dwEventFlags;

} MOUSE_EVENT_RECORD;

The MOUSE_EVENT_RECORD structure is used in a console INPUT_RECORD structure to report mouse input events.

Members

dwMousePosition

Specifies the location of the cursor in terms of the screen buffer's character-cell coordinates.

dwButtonState

Indicates the status of the mouse buttons. The least significant bit corresponds to the leftmost mouse button. The next least significant bit corresponds to the rightmost mouse button. The next bit indicates the next-to-leftmost mouse button. The bits then correspond left to right to the mouse buttons. A bit is 1 if the button was pressed.

The following constants are defined for the first five mouse buttons:

FROM_LEFT_1ST_BUTTON_PRESSED

RIGHTMOST_BUTTON_PRESSED

FROM_LEFT_2ND_BUTTON_PRESSED

FROM_LEFT_3RD_BUTTON_PRESSED

FROM_LEFT_4TH_BUTTON_PRESSED

dwControlKeyState

Indicates the state of the control keys. This member can be a combination of the following values:

Value	Meaning
RIGHT_ALT_PRESSED	The right ALT key is pressed.
LEFT_ALT_PRESSED	The left ALT key is pressed.
RIGHT_CTRL_PRESSED	The right CTRL key is pressed.
LEFT_CTRL_PRESSED	The left CTRL key is pressed.
CAPSLOCK_ON	The CAPS LOCK light is on.
ENHANCED_KEY	The key is enhanced.
NUMLOCK_ON	The NUM LOCK light is on.
SCROLLLOCK_ON	The SCROLL LOCK light is on.
SHIFT_PRESSED	The SHIFT key is pressed.
dwEventFlags

Indicates the type of mouse event. If this value is zero, it indicates a mouse button being pressed or released. Otherwise, the value is one of the following:

Value	Meaning
DOUBLE_CLICK	The second click (button press) of a double-click occurred. The first click is returned as a regular button-press event.
MOUSE_MOVED	A change in mouse position occurred.
Remarks

Mouse events are placed in the input buffer when the console is in mouse mode (ENABLE_MOUSE_INPUT).

Mouse events are generated whenever the user moves the mouse, or presses or releases one of the mouse buttons. Mouse events are placed in a console's input buffer only when the console group has the keyboard focus and the cursor is within the borders of the console's window.

See Also

INPUT_RECORD, PeekConsoleInput, ReadConsoleInput, WriteConsoleInput


MOUSEHOOKSTRUCT
MOUSEHOOKSTRUCT  QuickInfo

typedef struct tagMOUSEHOOKSTRUCT { // ms

    POINT pt;

    HWND  hwnd;

    UINT  wHitTestCode;

    DWORD dwExtraInfo;

} MOUSEHOOKSTRUCT;

The MOUSEHOOKSTRUCT structure contains information about a mouse event.

Members

pt

Specifies a POINT structure that contains the x- and y-coordinates of the cursor, in screen coordinates.

hwnd

Identifies the window that will receive the mouse message corresponding to the mouse event.

wHitTestCode

Specifies the hit-test value. For a list of hit-test values, see the description of the WM_NCHITTEST message.

dwExtraInfo

Specifies extra information associated with the message.

See Also

GetMessageExtraInfo, POINT, SetWindowsHook, SetWindowsHookEx, WM_NCHITTEST


MOUSEKEYS
MOUSEKEYS  QuickInfo  Overview  Group

typedef struct _MOUSEKEYS {     // mk

    DWORD cbSize;

    DWORD dwFlags;

    DWORD iMaxSpeed;

    DWORD iTimeToMaxSpeed;

    DWORD iCtrlSpeed;

    DWORD dwReserved1;

    DWORD dwReserved2;

} MOUSEKEYS;

The MOUSEKEYS structure contains information about the MouseKeys accessibility feature. When the MouseKeys feature is active, the user can use the numeric keypad to control the mousepointer, and to click, double-click, drag, and drop. By pressing NUMLOCK, the user can toggle the numeric keypad between mouse control mode and normal operation.

Members

cbSize

Specifies the size, in bytes, of this structure.

dwFlags

A set of bit-flags that specify properties of the FilterKeys feature. The following bit-flag values are defined:

Value	Meaning
MKF_AVAILABLE	If this flag is set, the MouseKeys feature is available.
MKF_CONFIRMHOTKEY	Windows 95 only: A confirmation dialog box appears when the MouseKeys feature is activated by using the hot key.
MKF_HOTKEYACTIVE	If this flag is set, the user can turn the MouseKeys feature on and off by using the hot key, which is LEFT ALT+LEFT SHIFT+NUM LOCK.
MKF_HOTKEYSOUND	If this flag is set, the system plays a siren sound when the user turns the MouseKeys feature on or off by using the hot key.
MKF_INDICATOR	Windows 95 only: A visual indicator is displayed when the MouseKeys feature is on.
MKF_MOUSEKEYSON	If this flag is set, the MouseKeys feature is on.
MKF_MODIFIERS	Windows 95 only: The CTRL key increases cursor speed by the value specified by the iCtrlSpeed member, and the SHIFT key causes the cursor to delay briefly after moving a single pixel, allowing fine positioning of the cursor. If this value is not specified, the CTRL and SHIFT keys are ignored while the user moves the mouse cursor using the arrow keys.
MKF_REPLACENUMBERS	Windows 95 only:The numeric keypad moves the mouse when the NUM LOCK key is on. If this flag is not specified, the numeric keypad moves the mouse cursor when the NUM LOCK key is off.
iMaxSpeed

Specifies the maximum speed the mouse cursor attains when an arrow key is held down.

Windows 95: Range checking is not performed.

Windows NT: Valid values are from 10 to 360.

iTimeToMaxSpeed

Specifies the length of time, in milliseconds, that it takes for the mouse cursor to reach maximum speed when an arrow key is held down. Valid values are from 1000 to 5000.

iCtrlSpeed

Windows 95: Specifies the multiplier to apply to the mouse cursor speed when the user holds down the CTRL key while using the arrow keys to move the cursor. this value is ignored if MKF_MODIFIERS is not set.

Windows NT: This member is reserved for future use. It must be set to zero.

dwReserved1

This member is reserved for future use. It must be set to zero.

dwReserved2

This member is reserved for future use. It must be set to zero.

Remarks

An application uses a MOUSEKEYS structure when calling the SystemParametersInfo function with the wAction parameter set to the SPI_GETMOUSEKEYS or SPI_SETMOUSEKEYS value. When using SPI_GETMOUSEKEYS, an application must specify the cbSize member of the MOUSEKEYS structure; the SystemParametersInfo function fills the remaining members. An application must specify all structure members when using the SPI_SETMOUSEKEYS value.

See Also

SystemParametersInfo


MSG
MSG  QuickInfo

typedef struct tagMSG {     // msg

    HWND   hwnd;

    UINT   message;

    WPARAM wParam;

    LPARAM lParam;

    DWORD  time;

    POINT  pt;

} MSG;

The MSG structure contains message information from a thread's message queue.

Members

hwnd

Identifies the window whose window procedure receives the message.

message

Specifies the message number.

wParam

Specifies additional information about the message. The exact meaning depends on the value of the message member.

lParam

Specifies additional information about the message. The exact meaning depends on the value of the message member.

time

Specifies the time at which the message was posted.

pt

Specifies the cursor position, in screen coordinates, when the message was posted.

See Also

GetMessage, PeekMessage


MSGBOXPARAMS [New - Windows 95]
MSGBOXPARAMS  QuickInfo  Overview  Group

[New - Windows 95]

typedef struct {

    UINT      cbSize;

    HWND      hwndOwner;

    HINSTANCE hInstance;

    LPCSTR    lpszText;

    LPCSTR    lpszCaption;

    DWORD     dwStyle;

    LPCSTR    lpszIcon;

    DWORD     dwContextHelpId;

    MSGBOXCALLBACK lpfnMsgBoxCallback;

    DWORD     dwLanguageId;

} MSGBOXPARAMS, *PMSGBOXPARAMS, FAR *LPMSGBOXPARAMS;

The MSGBOXPARAMS structure contains information used to display a message box. The MessageBoxIndirect function uses this structure.

Members

cbSize

Specifies the structure size, in bytes.

hwndOwner

Identifies the owner window; can be NULL.

hInstance

Identifies the instance containing the icon resource identified by the lpszIcon member, and the string resource identified by the lpszText or lpszCaption member.

lpszText

Points to a null-terminated string, or the identifier of a string resource, that contains the message to be displayed.

lpszCaption

Points to a null-terminated string, or the identifier of a string resource, that contains the message box title. If this member is NULL, the default title Error is used.

dwStyle

Specifies the contents and behavior of the message box. Can be one or more of the values specified in the MessageBoxEx function and one of the following values:

Value	Meaning
MB_HELP	Adds a Help button to the message box. Choosing the Help button or pressing F1 generates a Help event.
MB_TOPMOST	Uses the WS_EX_TOPMOST window style.
MB_USERICON	Uses the icon specified by the lpszIcon member.
lpszIcon

Identifies an icon resource. This parameter can be either a null-terminated string or an integer resource identifier passed to the MAKEINTRESOURCE macro. To load a standard icon, the hInstance member should be NULL, and lpszIcon should be one of the values listed with the LoadIcon function. This parameter is ignored if the dwStyle member does not specify the MB_USERICON flag.

dwContextHelpId

Identifies a Help context. If a Help event occurs, this value is specified in the HELPINFO structure that the message box sends to the owner window or callback function.

lpfnMsgBoxCallback

Points to the callback function that processes Help events for the message box. The callback function has the following form:

VOID CALLBACK MsgBoxCallback(LPHELPINFO lpHelpInfo);

If this member is NULL, the message box sends WM_HELP messages to the owner window when help events occur.

dwLanguageId

Specifies the language in which to display the text contained in the predefined push buttons. This value must be in the form returned by the MAKELANGID macro.

See Also

HELPINFO, LoadIcon, MAKEINTRESOURCE, MAKELANGID, MessageBoxEx, MessageBoxIndirect


MSGFILTER [New - Windows NT]
MSGFILTER  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct _msgfilter {

    NMHDR nmhdr;

    UINT msg;

    _WPAD _wPad1;

    WPARAM wParam;

    _WPAD _wPad2;

    LPARAM lParam;

} MSGFILTER;

The MSGFILTER structure contains information about a keyboard or mouse event. A rich edit control sends this structure to its parent window as part of an EN_MSGFILTER notification message, enabling the parent to change the message or prevent it from being processed.

Members

nmhdr

Notification header.

msg

Keyboard or mouse message identifier.

wParam

wParam parameter of the message.

lParam

lParam parameter of the message.

See Also

EN_MSGFILTER


MULTIKEYHELP
MULTIKEYHELP  QuickInfo

typedef struct tagMULTIKEYHELP { // mkh

    DWORD  mkSize;

    TCHAR  mkKeylist;

    TCHAR  szKeyphrase[1];

} MULTIKEYHELP;

The MULTIKEYHELP structure specifies a keyword table and an associated keyword to be used by Windows Help.

Members

mkSize

Specifies the structure size, in bytes.

mkKeylist

Specifies a single character that identifies the keyword table to search.

szKeyphrase

Contains a null-terminated text string that specifies the keyword to locate in the keyword table.

See Also

WinHelp


NAME_BUFFER
NAME_BUFFER  QuickInfo

typedef struct _NAME_BUFFER { // nb

    UCHAR name[NCBNAMSZ];

    UCHAR name_num;

    UCHAR name_flags;

} NAME_BUFFER;

The NAME_BUFFER structure contains information about a local network name. One or more NAME_BUFFER structures follows an ADAPTER_STATUS structure when an application specifies the NCBASTAT command in the ncb_command member of the NCB structure.

Members

name

Specifies the local network name. This value is in the ncb_name member of the NCB structure.

name_num

Specifies the number for the local network name. This value is in the ncb_num member of the NCB structure.

name_flags

Specifies the current state of the name table entry. This member can be one of the following values:

Value	Meaning
REGISTERING	The name specified by the name member is being added to the network.
REGISTERED	The name specified by the name member has been successfully added to the network.
DEREGISTERED	The name specified by the name member has an active session when an NCBDELNAME command is issued. The name will be removed from the name table when the session is closed.
DUPLICATE	A duplicate name was detected during registration.
DUPLICATE_DEREG	A duplicate name was detected with a pending deregistration.
GROUP_NAME	The name specified by the name member was created by using the NCBADDGRNAME command.
UNIQUE_NAME	The name specified by the name member was created by using the NCBADDNAME command.
See Also

ADAPTER_STATUS, NCB


NCB
NCB  QuickInfo

typedef struct _NCB { // ncb

    UCHAR  ncb_command;

    UCHAR  ncb_retcode;

    UCHAR  ncb_lsn;

    UCHAR  ncb_num;

    PUCHAR ncb_buffer;

    WORD   ncb_length;

    UCHAR  ncb_callname[NCBNAMSZ];

    UCHAR  ncb_name[NCBNAMSZ];

    UCHAR  ncb_rto;

    UCHAR  ncb_sto;

    void (*ncb_post) (struct _NCB *);

    UCHAR  ncb_lana_num;

    UCHAR  ncb_cmd_cplt;

    UCHAR  ncb_reserve[10];

    HANDLE ncb_event;

} NCB;

The NCB structure describes a network control block. A pointer to this structure is passed to the Netbios function.

Members

ncb_command

Specifies the command code and a flag that indicates whether the NCB structure is processed asynchronously. The most significant bit contains the flag. If the ASYNCH constant is combined with a command code (by using the OR operator), the NCB structure is processed asynchronously. The following command codes are supported:

Code	Meaning
NCBACTION	Enables extensions to the transport interface. NCBACTION commands are mapped to TdiAction. When this code is specified, the ncb_buffer member points to a buffer to be filled with an ACTION_HEADER structure, which is optionally followed by data. NCBACTION commands cannot be canceled by using NCBCANCEL.
NCBADDGRNAME	Adds a group name to the local name table.
NCBADDNAME	Adds a unique name to the local name table.
NCBASTAT	Retrieves the status of the adapter. When this code is specified, the ncb_buffer member points to a buffer to be filled with an ADAPTER_STATUS structure, followed by an array of NAME_BUFFER structures.
NCBCALL	Opens a session with another name.
NCBCANCEL	Cancels a previous command.
NCBCHAINSEND	Sends the contents of two data buffers to the specified session partner.
NCBCHAINSENDNA	Sends the contents of two data buffers to the specified session partner and does not wait for acknowledgment.
NCBDELNAME	Deletes a name from the local name table.
NCBDGRECV	Receives a datagram from any name.
NCBDGRECVBC	Receives broadcast datagram from any host.
NCBDGSEND	Sends datagram to a specified name.
NCBDGSENDBC	Sends a broadcast datagram to every host on the local area network (LAN).
NCBENUM	Enumerates LAN adapter (LANA) numbers. When this code is specified, the ncb_buffer member points to a buffer to be filled with a LANA_ENUM structure.
NCBFINDNAME	Determines the location of a name on the network. When this code is specified, the ncb_buffer member points to a buffer to be filled with a FIND_NAME_HEADER structure followed by one or more FIND_NAME_BUFFER structures.
NCBHANGUP	Closes a specified session.
NCBLANSTALERT	Notifies the user of LAN failures that last for more than one minute.
NCBLISTEN	Enables a session to be opened with another name.
NCBRECV	Receives data from the specified session partner.
NCBRECVANY	Receives data from any session corresponding to a specified name.
NCBRESET	Resets a LAN adapter. An adapter must be reset before any other NCB command that specifies the same number in the ncb_lana_num member will be accepted.
	The IBM NetBIOS 3.0 specification documents several NCB_RESET NCB's. Win32 implements the NCB.RESET using the dynamic link routine interface. Particular values can be passed in specific bytes of the NCB, more specifically:
	• If ncb_lsn is not 0x00, all resources associated with ncb_lana_num are to be freed.
	• If ncb_lsn is 0x00, all resources associated with ncb_lana_num are to be freed, and new resources are to be allocated. The ncb_callname[0] byte specifies the maximum number of sessions, and the ncb_callname[2] byte specifies the maximum number of names. A nonzero value for the ncb_callname[3] byte requests that the application use NAME_NUMBER_1.
NCBSEND	Sends data to the specified session partner.
NCBSENDNA	Sends data to specified session partner and does not wait for an acknowledgment.
NCBSSTAT	Retrieves the status of the session. When this value is specified, the ncb_buffer member points to a buffer to be filled with a SESSION_HEADER structure, followed by one or more SESSION_BUFFER structures.
NCBTRACE	Activates or deactivates NCB tracing. Support for this command in the system is optional and system-specific.
NCBUNLINK	Unlinks the adapter.
ncb_retcode

Specifies the return code. This value is set to NRC_PENDING while an asynchronous operation is in progress. One of the following return code values can be specified:

Value	Meaning
NRC_GOODRET	The operation succeeded.
NRC_BUFLEN	An illegal buffer length was supplied.
NRC_ILLCMD	An illegal command was supplied.
NRC_CMDTMO	The command was timed out.
NRC_INCOMP	The message was incomplete. The application is to issue another command.
NRC_BADDR	The buffer address was illegal.
NRC_SNUMOUT	The session number was out of range.
NRC_NORES	No resource was available.
NRC_SCLOSED	The session was closed.
NRC_CMDCAN	The command was canceled.
NRC_DUPNAME	A duplicate name existed in the local name table.
NRC_NAMTFUL	The name table was full.
NRC_ACTSES	The command finished; the name has active sessions and is no longer registered.
NRC_LOCTFUL	The local session table was full.
NRC_REMTFUL	The remote session table was full. The request to open a session was rejected.
NRC_ILLNN	An illegal name number was specified.
NRC_NOCALL	The system did not find the name that was called.
NRC_NOWILD	Wildcards are not permitted in the ncb_name member.
NRC_INUSE	The name was already in use on the remote adapter.
NRC_NAMERR	The name was deleted.
NRC_SABORT	The session ended abnormally.
NRC_NAMCONF	A name conflict was detected.
NRC_IFBUSY	The interface was busy.
NRC_TOOMANY	Too many commands were outstanding; the application can retry the command later.
NRC_BRIDGE	The ncb_lana_num member did not specify a valid network number.
NRC_CANOCCR	The command finished while a cancel operation was occurring.
NRC_CANCEL	The NCBCANCEL command was not valid; the command was not canceled.
NRC_DUPENV	The name was defined by another local process.
NRC_ENVNOTDEF	The environment was not defined. A reset command must be issued.
NRC_OSRESNOTAV	Operating system resources were exhausted. The application can retry the command later.
NRC_MAXAPPS	The maximum number of applications was exceeded.
NRC_NOSAPS	No service access points (SAPs) were available for NetBIOS.
NRC_NORESOURCES	The requested resources were not available.
NRC_INVADDRESS	The NCB address was not valid.
	This return code is not part of the IBM NetBIOS 3.0 specification and is not returned in the NCB structure. Instead, it is returned by the Netbios function.
NRC_INVDDID	The NCB DDID was invalid.
NRC_LOCKFAIL	The attempt to lock the user area failed.
NRC_OPENERR	An error occurred during an open operation being performed by the device driver. This return code is not part of the IBM NetBIOS 3.0 specification.
NRC_SYSTEM	A system error occurred.
NRC_PENDING	An asynchronous operation is not yet finished.
ncb_lsn

Specifies the local session number. This number uniquely identifies a session within an environment.

ncb_num

Specifies the number for the local network name. This number is returned by Netbios after a successful NCBADDNAME or NCBADDGRNAME command. This number, not the name, must be used with all datagram commands and for NCBRECVANY commands.

The number for NAME_NUMBER_1 (see NCBRESET) is always 0x01. Netbios assigns values in the range 0x02 to 0xFE for the remaining names.

ncb_buffer

Points to the message buffer.

ncb_length

Specifies the size, in bytes, of the message buffer.

ncb_callname

Specifies the string that contains the remote name. Trailing space characters should be supplied to make the length of the string equal to NCBNAMSZ.

ncb_name

Specifies the string that contains the local name. Trailing space characters should be supplied to make the length of the string equal to NCBNAMSZ.

ncb_rto

Specifies the receive time-out period, in 500-millisecond units, for the session. A value of zero implies no time-out. Specified only for NCBRECV commands.

ncb_sto

Specifies the send time-out period, in 500-millisecond units, for the session. A value of zero implies no time-out. Specified only for NCBSEND and NCBCHAINSEND commands.

ncb_post

Specifies the address of the routine to call when the asynchronous NCB finishes. The completion routine is passed a pointer to the completed network control block.

ncb_lana_num

Specifies the LAN adapter number. This zero-based number corresponds to a particular transport provider using a particular LAN adapter board.

ncb_cmd_cplt

Specifies the command complete flag. This value is the same as the ncb_retcode member.

ncb_reserve

Reserved; must be zero.

ncb_event

Specifies a handle to a Windows event that is set to the signaled state when the asynchronous network control block finishes. The event is signaled if the Netbios function returns a nonzero value.

The ncb_event member must be zero if the ncb_command member does not have the ASYNCH value set or if ncb_post is non zero. Otherwise, NRC_ILLCMD is returned.

The event specified by ncb_event is set to the nonsignaled state by the system when an asynchronous NetBIOS command is accepted, and it is set to the signaled state when the asynchronous NetBIOS command finishes.

Using ncb_event to submit asynchronous requests requires fewer system resources than using ncb_post. Also, when ncb_event is nonzero, the pending request is canceled if the thread terminates before the request is processed. This is not true for requests sent by using ncb_post.

Only manual reset events should be used with Netbios. A given event should not be associated with more than one active asynchronous NetBIOS command.

See Also

ACTION_HEADER, ADAPTER_STATUS, FIND_NAME_BUFFER, FIND_NAME_HEADER, LANA_ENUM, NAME_BUFFER, Netbios, SESSION_BUFFER, SESSION_HEADER,


NCCALCSIZE_PARAMS
NCCALCSIZE_PARAMS  QuickInfo

typedef struct _NCCALCSIZE_PARAMS { // nccp

    RECT        rgrc[3];

    PWINDOWPOS  lppos;

} NCCALCSIZE_PARAMS;

The NCCALCSIZE_PARAMS structure contains information that an application can use while processing the WM_NCCALCSIZE message to calculate the size, position, and valid contents of the client area of a window.

Members

rgrc

Specifies an array of rectangles. The first contains the new coordinates of a window that has been moved or resized. The second contains the coordinates of the window before it was moved or resized. The third contains the coordinates of the window's client area before the window was moved or resized. If the window is a child window, the coordinates are relative to the client area of the parent window. If the window is a top-level window, the coordinates are relative to the screen origin.

lppos

Points to a WINDOWPOS structure that contains the size and position values specified in the operation that moved or resized the window.

See Also

MoveWindow, RECT, SetWindowPos, WINDOWPOS, WM_NCCALCSIZE


NDDESHAREINFO
NDDESHAREINFO  QuickInfo  Overview  Group

typedef struct _NDDESHAREINFO {

    LONG   lRevision;

    LPTSTR lpszShareName;

    LONG   lShareType;

    LPTSTR lpszAppTopicList;

    LONG   fSharedFlag;

    LONG   fService;

    LONG   fStartAppFlag;

    LONG   nCmdShow;

    LONG   qModifyId[2];

    LONG   cNumItems;

    LPTSTR lpszItemList;

}NDDESHAREINFO;

The NDDESHAREINFO structure gets and sets DDE share attributes maintained by the NetDDE Share Database Manager (DSDM). The security descriptor associated with each DDE share is not passed through this structure but is accessed through specific functions. The NetDDE DSDM API accepts this structure for set functions; for get functions, the DSDM returns the structure packed into the supplied buffer along with the data referenced by the members lpszShareName, lpszAppTopicList, and lpszItemList.

Members

lRevision

Specifies the revision level of the NDDESHAREINFO structure. Currently, the revision level is 1.

lpszShareName

Points to a buffer containing a null-terminated string that specifies the name of the share. This string must be no more than MAX_NDDESHARENAME characters long.

lShareType

Specifies the DDE share type(s). A DDE share can assume more than one type. This member can be a combination of the following supported DDE share types:

Share type	Meaning
SHARE_TYPE_OLD	Specifies that the share contains a DDE application/topic pair.
SHARE_TYPE_NEW	Specifies that the share contains an OLE application/topic pair.
SHARE_TYPE_STATIC	Specifies that the share contains a static application/topic pair.
lpszAppTopicList

Points to a buffer containing null-terminated strings for the DDE, OLE, and static application/topic pairs. The buffer should be in the following format:

    <DDE application name>|<DDE topic name>\0

        <OLE application name>|<OLE topic name>\0

        <static application name>|<static topic name>\0\0

fSharedFlag

Specifies whether the share is accessible to remote clients for linking. If this flag is set to FALSE, the DDE share will not allow remote users to communicate through it by using DDE. However, local users can still communicate through the DDE share. Local client links are always implied if the associated DACL grants access.

fService

If this flag is set, the DDE share will not check whether the current user has set it as trusted before before allowing DDE communication through it.

fStartAppFlag

If this flag is set and the share is trusted to start applications, NetDDE will attempt to start the application specified by lpszAppTopicList if it cannot initially start a DDE conversation with the application.

nCmdShow

When NetDDE starts an application to initiate a DDE conversation with it, this value is sent to the application by the nCmdShow parameter of the WinMain function. It defines the preferred mode for the application window to be shown in. This parameter is significant only if fStartAppFlag is active. The logged on user in whose context the application is started can also override this option when promoting the share to trusted status. The default for this field is SW_SHOWMAXIMIZED.

qModifyId

An 8-byte serial number that indicates the modification serial number of the DDE share. Every time the DDE share is modified by a NDdeShareSetInfo or NDdeSetShareSecurity call, these values are changed.

cNumItems

Specifies the number of items listed in lpszItemList. If cNumItems is zero, then lpszItemList is empty, and the share information and associated security descriptor apply to all items serviced by the associated application.

lpszItemList

Points to a buffer containing null-terminated strings that specify the items the client application in a DDE transaction can request or start advise loops on. If no items are listed, the DDE share allows any item to be used. The number of items in the list must match the cNumItems count.

See Also

NDdeSetShareSecurity, NDdeShareSetInfo, WinMain


NETRESOURCE
NETRESOURCE  QuickInfo

typedef struct _NETRESOURCE {  // nr

    DWORD  dwScope;

    DWORD  dwType;

    DWORD  dwDisplayType;

    DWORD  dwUsage;

    LPTSTR lpLocalName;

    LPTSTR lpRemoteName;

    LPTSTR lpComment;

    LPTSTR lpProvider;

} NETRESOURCE;

The NETRESOURCE structure is returned during enumeration of resources on the network and during enumeration of currently connected resources.

Members

dwScope

Specifies the scope of the enumeration. Currently, this member can be one of the following values:

Value	Meaning
RESOURCE_CONNECTED	Currently connected resources (the dwUsage member is undefined).
RESOURCE_GLOBALNET	Resources on the network.
RESOURCE_REMEMBERED	Remembered (persistent) connections (dwUsage is undefined).
dwType

Specifies a bitmask that gives the resource type. Currently, this member can be one of the following values:

Value	Meaning
RESOURCETYPE_ANY	All resources
RESOURCETYPE_DISK	Disk resources
RESOURCETYPE_PRINT	Print resources
dwDisplayType

Specifies how the network object should be displayed in a network browsing user interface. Currently, this member can be the following values:

Value	Meaning
RESOURCEDISPLAYTYPE_DOMAIN
	The object should be displayed as a domain.
RESOURCEDISPLAYTYPE_GENERIC
	The method used to display the object does not matter.
RESOURCEDISPLAYTYPE_SERVER
	The object should be displayed as a server.
RESOURCEDISPLAYTYPE_SHARE
	The object should be displayed as a sharepoint.
dwUsage

Specifies a bitmask that gives the resource usage. This member is defined only if dwScope is RESOURCE_GLOBALNET. Currently, this member can be one of the following values:

Value	Meaning
RESOURCEUSAGE_CONNECTABLE	This is a connectable resource; the name pointed to by the lpRemoteName member can be passed to the WNetAddConnection function to make a network connection.
RESOURCEUSAGE_CONTAINER	This is a container resource; the name pointed to by the lpRemoteName member can be passed to the WNetOpenEnum function to enumerate the resources in the container.
lpLocalName

Points to the name of a local device if the dwScope member is RESOURCE_CONNECTED or RESOURCE_REMEMBERED. This member is NULL if the connection does not use a device. Otherwise, it is undefined.

lpRemoteName

Points to a remote network name if the entry is a network resource.

If the entry is a current or persistent connection, lpRemoteName points to the network name associated with the name pointed to by the lpLocalName member.

lpComment

Points to a provider-supplied comment.

lpProvider

Points to the name of the provider owning this resource. This member can be NULL if the provider name is unknown.

See Also

WNetAddConnection, WNetCloseEnum, WNetEnumResource, WNetOpenEnum


NEWCPLINFO
NEWCPLINFO  QuickInfo

typedef struct tagNEWCPLINFO {  // ncpli

    DWORD dwSize;

    DWORD dwFlags;

    DWORD dwHelpContext;

    LONG  lData;

    HICON hIcon;

    TCHAR  szName[32];

    TCHAR  szInfo[64];

    TCHAR  szHelpFile[128];

} NEWCPLINFO;

The NEWCPLINFO structure contains resource information and a user-defined value for a dialog box supported by a Control Panel application.

Members

dwSize

Specifies the length of the structure, in bytes.

dwFlags

Specifies Control Panel flags.

dwHelpContext

Specifies the context number of a topic in a Help (.HLP) file. This topic is intended to be displayed when the user selects help for the dialog box.

lData

Specifies data defined by the application.

hIcon

Identifies the icon that represents the dialog box. This icon is intended to be displayed by the application that controls the Control Panel application.

szName

Specifies a null-terminated string that contains the dialog box name. The name is intended to be displayed below the icon.

szInfo

Specifies a null-terminated string containing the dialog box description. The description is intended to be displayed when the icon for the dialog box is selected.

szHelpFile

Specifies a null-terminated string that contains the path of the help file, if any, for the application.

See Also

CPLINFO, CPL_NEWINQUIRE


NEWTEXTMETRIC
NEWTEXTMETRIC  QuickInfo

typedef struct tagNEWTEXTMETRIC { // ntm

    LONG   tmHeight;

    LONG   tmAscent;

    LONG   tmDescent;

    LONG   tmInternalLeading;

    LONG   tmExternalLeading;

    LONG   tmAveCharWidth;

    LONG   tmMaxCharWidth;

    LONG   tmWeight;

    LONG   tmOverhang;

    LONG   tmDigitizedAspectX;

    LONG   tmDigitizedAspectY;

    BCHAR  tmFirstChar;

    BCHAR  tmLastChar;

    BCHAR  tmDefaultChar;

    BCHAR  tmBreakChar;

    BYTE   tmItalic;

    BYTE   tmUnderlined;

    BYTE   tmStruckOut;

    BYTE   tmPitchAndFamily;

    BYTE   tmCharSet;

    DWORD  ntmFlags;

    UINT   ntmSizeEM;

    UINT   ntmCellHeight;

    UINT   ntmAvgWidth;

} NEWTEXTMETRIC;

The NEWTEXTMETRIC structure contains data that describes a physical font.

Members

tmHeight

Specifies the height (ascent + descent) of characters.

tmAscent

Specifies the ascent (units above the base line) of characters.

tmDescent

Specifies the descent (units below the base line) of characters.

tmInternalLeading

Specifies the amount of leading (space) inside the bounds set by the tmHeight member. Accent marks and other diacritical characters may occur in this area. The designer may set this member to zero.

tmExternalLeading

Specifies the amount of extra leading (space) that the application adds between rows. Since this area is outside the font, it contains no marks and is not altered by text output calls in either OPAQUE or TRANSPARENT mode. The designer may set this member to zero.

tmAveCharWidth

Specifies the average width of characters in the font (generally defined as the width of the letter x). This value does not include overhang required for bold or italic characters.

tmMaxCharWidth

Specifies the width of the widest character in the font.

tmWeight

Specifies the weight of the font.

tmOverhang

Specifies the extra width per string that may be added to some synthesized fonts. When synthesizing some attributes, such as bold or italic, graphics device interface (GDI) or a device may have to add width to a string on both a per-character and per-string basis. For example, GDI makes a string bold by expanding the spacing of each character and overstriking by an offset value; it italicizes a font by shearing the string. In either case, there is an overhang past the basic string. For bold strings, the overhang is the distance by which the overstrike is offset. For italic strings, the overhang is the amount the top of the font is sheared past the bottom of the font.

The tmOverhang member enables the application to determine how much of the character width returned by a GetTextExtentPoint32 function call on a single character is the actual character width and how much is the per-string extra width. The actual width is the extent minus the overhang.

tmDigitizedAspectX

Specifies the horizontal aspect of the device for which the font was designed.

tmDigitizedAspectY

Specifies the vertical aspect of the device for which the font was designed. The ratio of the tmDigitizedAspectX and tmDigitizedAspectY members is the aspect ratio of the device for which the font was designed.

tmFirstChar

Specifies the value of the first character defined in the font.

tmLastChar

Specifies the value of the last character defined in the font.

tmDefaultChar

Specifies the value of the character to be substituted for characters that are not in the font.

tmBreakChar

Specifies the value of the character to be used to define word breaks for text justification.

tmItalic

Specifies an italic font if it is nonzero.

tmUnderlined

Specifies an underlined font if it is nonzero.

tmStruckOut

Specifies a strikeout font if it is nonzero.

tmPitchAndFamily

Specifies the pitch and family of the selected font. The low-order bit (bit 0) specifies the pitch of the font. If it is 1, the font is variable pitch (or proportional). If it is 0, the font is fixed pitch (or monospace). Bits 1 and 2 specify the font type. If both bits are 0, the font is a raster font; if bit 1 is 1 and bit 2 is 0, the font is a vector font; if bit 1 is 0 and bit 2 is set, or if both bits are 1, the font is some other type. Bit 3 is 1 if the font is a device font; otherwise, it is 0.

The four high-order bits designate the font family. The tmPitchAndFamily member can be combined with the hexadecimal value 0xF0 by using the bitwise AND operator and can then be compared with the font family names for an identical match. For more information about the font families, see the LOGFONT structure.

tmCharSet

Specifies the character set of the font.

ntmFlags

Specifies whether the font is italic, underscored, outlined, bold, and so forth. The following list shows the bits corresponding to each font type:

Bit	Meaning
0	Italic
1	Underscore
2	Negative
3	Outline
4	Strikeout
5	Bold
ntmSizeEM

Specifies the size of the em square for the font. This value is in "notional units" (that is, the units for which the font was designed).

ntmCellHeight

Specifies the height, in notional units, of the font. This value should be compared with the value of the ntmSizeEM member.

ntmAvgWidth

Specifies the average width of characters in the font, in notional units. This value should be compared with the value of the ntmSizeEM member.

Remarks

The last four members of the NEWTEXTMETRIC structure are not included in the TEXTMETRIC structure; in all other respects, the structures are identical.

The sizes in the NEWTEXTMETRIC structure are typically given in logical units; that is, they depend on the current mapping mode of the display context.

See Also

EnumFontFamilies, GetTextExtentPoint32, GetTextMetrics, LOGFONT


NEWTEXTMETRICEX [New - Windows 95]
NEWTEXTMETRICEX  QuickInfo

[New - Windows 95]

typedef struct tagNEWTEXTMETRICEX {
    NEWTEXTMETRIC  ntmentm;
    FONTSIGNATURE  ntmeFontSignature;
} NEWTEXTMETRICEX;

The NEWTEXTMETRICEX structure contains information about a physical font.

Members

ntmentm

Specifies a NEWTEXTMETRIC structure.

ntmeFontSignature

Specifies a FONTSIGNATURE structure indicating the coverage of the font.

See Also

NEWTEXTMETRIC


NM_LISTVIEW [New - Windows NT]
NM_LISTVIEW  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct tagNM_LISTVIEW {

    NMHDR hdr;

    int   iItem;

    int   iSubItem;

    UINT  uNewState;

    UINT  uOldState;

    UINT  uChanged;

    POINT ptAction;

    LPARAM lParam;

} NM_LISTVIEW;

The NM_LISTVIEW structure contains information about a list view notification message.

Members

hdr

Required for all WM_NOTIFY messages.

iItem

List view item, or −1 if not used.

iSubItem

Subitem, or zero if none.

uNewState

New item state. This member is zero for notification messages that do not use it.

uOldState

Old item state. This member is zero for notification messages that do not use it.

uChanged

Item attributes that have changed. This member is zero for notifications that do not use it. Otherwise, it can have the same values as the mask member of the LV_ITEM structure.

ptAction

Location at which the event occurred. This member is valid only for the LVN_BEGINDRAG and LVN_BEGINRDRAG notification messages.

Remarks

The address of the NM_LISTVIEW structure is specified as the lParam parameter of the WM_NOTIFY message for several list view notification messages.

See Also

LV_ITEM, LVN_BEGINDRAG, LVN_BEGINRDRAG, WM_NOTIFY


NM_TREEVIEW [New - Windows NT]
NM_TREEVIEW  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct _NM_TREEVIEW {  nmtv

    NMHDR    hdr;

    UINT     action;        TV_ITEM  itemOld;   // see below

    TV_ITEM  itemNew;

    POINT    ptDrag;

} NM_TREEVIEW;

typedef NM_TREEVIEW FAR *LPNM_TREEVIEW;

The NM_TREEVIEW structure contains information about a tree view notification message.

Members

hdr

Required for all WM_NOTIFY messages.

action

Notification-specific action flag.

itemOld

Address of TV_ITEM structures that contain information about the old item state. This member is zero for notification messages that do not use it.

itemNew

Address of TV_ITEM structures that contain information about the new item state. This member is zero for notification messages that do not use it.

ptDrag

POINT structure that contains the client coordinates of the mouse at the time the event occurred that caused the notification message to be sent.

Remarks

The address of this structure is specified as the lParam parameter of the WM_NOTIFY message for several tree-view notification messages.

See Also

POINT, TV_ITEM, WM_NOTIFY


NM_UPDOWN [New - Windows NT]
NM_UPDOWN  QuickInfo

[New - Windows NT]

typedef struct _NM_UPDOWN {  nmud

    NMHDR    hdr;       // notification message header

    int     iPos;        // current position

    int  iDelta;      // proposed change in position

} NM_UPDOWNW;

The NM_UPDOWN structure contains information about an up-down control notification message.

Members

hdr

Notification message header structure. This is required for all WM_NOTIFY messages.

iPos

Signed integer value that is the current position of the up-down control.

iDelta

Signed integer value that is the proposed change in the position of the up-down control.

Remarks

The address of this structure is specified as the lParam parameter of the WM_NOTIFY message for the UDN_DELTAPOS notification message.

See Also

NMHDR, UDN_DELTAPOS, WM_NOTIFY


NMHDR [New - Windows NT]
NMHDR  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct tagNMHDR {

    HWND hwndFrom;

    UINT idFrom;

    UINT code;

} NMHDR;

The NMHDR structure contains information about a notification message. The pointer to this structure is specified as the lParam member of the WM_NOTIFY message.

Members

hwndFrom

Handle to control sending message

idFrom

Identifier of control sending message

code

Notification code. This member can be a control-specific notification code, or it can be one of the following common notification values:

Value	Meaning
NM_CLICK	The user has clicked the left mouse button within the control.
NM_DBLCLK	The user has double-clicked the left mouse button within the control.
NM_KILLFOCUS	The control has lost the input focus.
NM_OUTOFMEMORY	The control could not complete an operation because there was not enough memory available.
NM_RCLICK	The user has clicked the right mouse button within the control.
NM_RDBLCLK	The user has double-clicked the right mouse button within the control.
NM_RETURN	The control has the input focus, and the user has pressed the ENTER key.
NM_SETFOCUS	The control has received the input focus.


NONCLIENTMETRICS
NONCLIENTMETRICS  QuickInfo

typedef struct tagNONCLIENTMETRICS {

    UINT    cbSize;

    int     iBorderWidth;

    int     iScrollWidth;

    int     iScrollHeight;

    int     iCaptionWidth;

    int     iCaptionHeight;

    LOGFONT lfCaptionFont;

    int     iSmCaptionWidth;

    int     iSmCaptionHeight;

    LOGFONT lfSmCaptionFont;

    int     iMenuWidth;

    int     iMenuHeight;

    LOGFONT lfMenuFont;

    LOGFONT lfStatusFont;

    LOGFONT lfMessageFont;

} NONCLIENTMETRICS, FAR* LPNONCLIENTMETRICS;

The NONCLIENTMETRICS structure contains the scalable metrics associated with the nonclient area of a nonminimized window. This structure is used by the SPI_GETNONCLIENTMETRICS and SPI_SETNONCLIENTMETRICS actions of SystemParametersInfo.

Members

cbSize

Specifies the size of the structure, in bytes.

iBorderWidth

Specifies the thickness, in pixels, of the sizing border.

iScrollWidth

Specifies the width, in pixels, of a standard vertical scroll bar.

iScrollHeight

Specifies the height, in pixels, of a standard horizontal scroll bar.

iCaptionWidth

Specifies the width, in pixels, of caption buttons.

iCaptionHeight

Specifies the height, in pixels, of caption buttons.

lfCaptionFont

Contains information about the caption font.

iSmCaptionWidth

Specifies the width, in pixels, of small caption buttons.

iSmCaptionHeight

Specifies the height, in pixels, of small captions.

iMenuWidth

Specifies the width, in pixels, of menu-bar buttons.

iMenuHeight

Specifies the height, in pixels, of a menu bar.

lfMenuFont

Contains information about the font used in menu bars.

lfStatusFont

Contains information about the font used in status bars.

lfMessageFont

Contains information about the font used in message boxes.

See Also

SystemParametersInfo


NS_SERVICE_INFO
NS_SERVICE_INFO  QuickInfo  Overview  Group

typedef struct _NS_SERVICE_INFO {

    DWORD   dwNameSpace;

    SERVICE_INFO ServiceInfo;

} NS_SERVICE_INFO;

The NS_SERVICE_INFO structure contains information about a network service or a network service type in the context of a specified name space, or a set of default name spaces.

Members

dwNameSpace

Specifies the name space or a set of default name spaces to which this service information applies.

Use one of the following constant values to specify a name space:

Value	Name Space
NS_DEFAULT	A set of default name spaces. The set of default name spaces typically includes all the name spaces installed on the system. System administrators, however, can exclude particular name spaces from the set.
NS_DNS	The Domain Name System used in the Internet to resolve the name of the host.
NS_MS
NS_NDS	The NetWare 4 provider.
NS_NETBT	The NetBIOS over TCP/IP layer. The operating system registers their computer names with NetBIOS. This name space is used to convert a computer name to an IP address that uses this registration.
NS_NIS
NS_SAP	The NetWare Service Advertising Protocol. This can access the Netware bindery, if appropriate. NS_SAP is a dynamic name space that enables the registration of services.
NS_STDA
NS_TCPIP_HOSTS	Lookup value in the <systemroot>\system32\drivers\etc\posts file.
NS_TCPIP_LOCAL	Local TCP/IP name resolution mechanisms, including comparisons against the local host name and lookup value in the cache of host to IP address mappings.
NS_WINS
NS_X500
ServiceInfo

A SERVICE_INFO structure that contains information about a network service or network service type.

See Also

GetService, SetService, SERVICE_INFO


NUMBERFMT
NUMBERFMT  QuickInfo

typedef struct _numberfmt {

    UINT      NumDigits;

    UINT      LeadingZero;

    UINT      Grouping;

    LPTSTR    lpDecimalSep;

    LPTSTR    lpThousandSep;

    UINT      NegativeOrder;

} NUMBERFMT;

The NUMBERFMT structure contains information that defines the format of a number string. The GetNumberFormat function uses this information to customize a number string for a specified locale.

Members

NumDigits

Specifies the number of fractional digits. This is equivalent to the locale information specified by the LCTYPE constant value LOCALE_IDIGITS.

LeadingZero

Specifies whether to use leading zeroes in decimal fields. This is equivalent to the locale information specified by the LCTYPE constant value LOCALE_ILZERO.

Grouping

Specifies the size of each group of digits to the left of the decimal. Values in the range 0 − 9 are valid.

lpDecimalSep

Points to a null-terminated decimal separator string.

lpThousandSep

Points to a null-terminated thousand separator string.

NegativeOrder

Specifies the negative number mode. This is equivalent to the locale information specified by the LCTYPE constant value LOCALE_INEGNUMBER.

Remarks

For more information about the LCTYPE constants, see LCTYPE Constants.

See Also

GetNumberFormat


OFNOTIFY
OFNOTIFY  Overview  Group

typedef struct _OFNOTIFY {  // on

    NMHDR          hdr;

    LPOPENFILENAME lpOFN;

    LPTSTR         pszFile;

} OFNOTIFY, FAR *LPOFNOTIFY;

Contains information about the WM_NOTIFY message sent to a hook function from an Open or Save As dialog box. The address of the OFNOTIFY structure is passed as the lParam parameter of the WM_NOTIFY message.

Members

hdr

Handle to an NMHDR structure. The code member of this structure identifies the notification message being sent and can be one of the CDN_ notification message values.

lpOFN

Handle to an OPENFILENAME structure that contains the initialization parameters for the Open or Save As dialog box.

pszFile

Pointer to the filename for which a sharing violation has occurred. The member is valid only with the CDN_SHAREVIOLATION notification message.

See Also

NMHDR, OPENFILENAME


OFSTRUCT
OFSTRUCT  QuickInfo

typedef struct _OFSTRUCT { // of

    BYTE cBytes;

    BYTE fFixedDisk;

    WORD nErrCode;

    WORD Reserved1;

    WORD Reserved2;

    CHAR szPathName[OFS_MAXPATHNAME];

} OFSTRUCT;

The OFSTRUCT structure contains information about a file that the OpenFile function opened or attempted to open.

Members

cBytes

Specifies the length, in bytes, of the structure.

fFixedDisk

Specifies whether the file is on a hard (fixed) disk. This member is nonzero if the file is on a hard disk.

nErrCode

Specifies the MS-DOS error code if the OpenFile function failed.

Reserved1

Reserved; do not use.

Reserved2

Reserved; do not use.

szPathName

Specifies the path and filename of the file. This string consists of characters from the Windows character set.

See Also

OpenFile


OPENFILENAME
OPENFILENAME  QuickInfo

typedef struct tagOFN { // ofn

    DWORD         lStructSize;

    HWND          hwndOwner;

    HINSTANCE     hInstance;

    LPCTSTR       lpstrFilter;

    LPTSTR        lpstrCustomFilter;

    DWORD         nMaxCustFilter;

    DWORD         nFilterIndex;

    LPTSTR        lpstrFile;

    DWORD         nMaxFile;

    LPTSTR        lpstrFileTitle;

    DWORD         nMaxFileTitle;

    LPCTSTR       lpstrInitialDir;

    LPCTSTR       lpstrTitle;

    DWORD         Flags;

    WORD          nFileOffset;

    WORD          nFileExtension;

    LPCTSTR       lpstrDefExt;

    DWORD         lCustData;

    LPOFNHOOKPROC lpfnHook;

    LPCTSTR       lpTemplateName;

} OPENFILENAME;

The OPENFILENAME structure contains information the operating system uses to initialize the system-defined Open or Save As dialog box. After the user closes the dialog box, the system returns information about the user's selection in this structure.

Members

lStructSize

Specifies the length, in bytes, of the structure.

hwndOwner

Identifies the window that owns the dialog box. This member can be any valid window handle, or it can be NULL if the dialog box has no owner.

hInstance

Identifies a data block that contains a dialog box template specified by the lpTemplateName member (if the Flags member is set to OFN_ENABLETEMPLATE).  Identifies the memory object containing a dialog box template (if Flags is set to OFN_ENABLETEMPLATEHANDLE). If neither OFN_ENABLETEMPLATE nor OFN_ENABLETEMPLATEHANDLE is set, this member is ignored.

lpstrFilter

Points to a buffer containing pairs of null-terminated filter strings. The first string in each pair describes a filter (for example, "Text Files"), and the second specifies the filter pattern (for example, "*.TXT"). Multiple filters can be specified for a single item by separating the filter pattern strings with a semicolon (for example, "*.TXT;*.DOC;*.BAK"). The last string in the buffer must be terminated by two NULL characters. If this member is NULL, the dialog box will not display any filters. The filter strings are assumed to be in the proper order — the operating system does not change the order.

lpstrCustomFilter

Points to a buffer containing a pair of user-defined filter strings. The first string describes the filter, and the second specifies the filter pattern (for example "WinWord, *.docnn"). The buffer is terminated by two NULL characters. The operating system copies the strings to the buffer when the user closes the dialog box. The system uses the strings to initialize the user-defined file filter the next time the dialog box is created. If this member is NULL, the dialog box lists but does not save user-defined filter strings.

Windows 95: If this member is NULL, the member is ignored.

If this member is not NULL, the value of the nMaxCustFilter member is used to determine the length of the corresponding string.

nMaxCustFilter

Specifies the size, in bytes or characters, of the buffer identified by lpstrCustomFilter. This buffer should be at least 40 characters long. This member is ignored if lpstrCustomFilter is NULL or points to a NULL string.

Windows 95: The value of nMaxcustFilter is used whenever lpstrCustomFilter is defined.

nFilterIndex

Specifies an index into the buffer pointed to by lpstrFilter. The system uses the index value to obtain a pair of strings to use as the initial filter description and filter pattern for the dialog box. The first pair of strings has an index value of 1. When the user closes the dialog box, the system copies the index of the selected filter strings into this location. If nFilterIndex is zero, the custom filter is used. If nFilterIndex is zero and lpstrCustomFilter is NULL, the system uses the first filter in the buffer identified by lpstrFilter. If all three members are zero or NULL, the system does not use any filters and does not show any files in the file list control of the dialog box.

lpstrFile

Points to a buffer that contains a filename used to initialize the File Name edit control. The first character of this buffer must be NULL if initialization is not necessary. When the GetOpenFileName or GetSaveFileName function returns, this buffer contains the drive designator, path, filename, and extension of the selected file.

If the buffer is too small, the dialog box procedure copies the required size into this member.

nMaxFile

Windows NT: Specifies the size, in characters, of the buffer pointed to by lpstrFile. The GetOpenFileName and GetSaveFileName functions return FALSE if the buffer is too small to contain the file information. The buffer should be at least 256 characters long. This member is ignored if lpstrFile is NULL.

Windows 95: Specifies the size in bytes or characters of the buffer pointed to by lpstrFile. The buffer should be at least 260 charcters long. this member is ignored if lpstrFile is NULL.

lpstrFileTitle

Points to a buffer that receives the title of the selected file. For Windows versions 3.0 and 3.1, this buffer receives the filename and extension without path information. The application should use this string to display the file title. If this member is NULL, the function does not copy the file title.

nMaxFileTitle

Specifies the maximum length of the string that can be copied into the lpstrFileTitle buffer. This member is ignored if lpstrFileTitle is NULL.

lpstrInitialDir

Points to a string that specifies the initial file directory. If this member is NULL, the system uses the current directory as the initial directory.

lpstrTitle

Points to a string to be placed in the title bar of the dialog box. If this member is NULL, the system uses the default title (that is, "Save As" or "Open").

Flags

Specifies the dialog box creation flags. This member may be a combination of the following flags:

Flag	Meaning
OFN_ALLOWMULTISELECT
	Specifies that the File Name list box allows multiple selections. (If the dialog box is created by using a private template, the definition of the File Name list box must contain the LBS_EXTENDEDSEL value.) Specifies that the File Name list box allows multiple selections.  If the dialog box is created by using a private template, the  definition of the File Name list box must contain the LBS_EXTENDEDSEL value. When this flag is set, the lpstrFile member points to a buffer containing the path to the current directory and all filenames in the selection. The first filename is separated from the path by a space. Each subsequent filename is separated by one space from the preceding filename. Note that for the new Explorer-style dialogs (dialogs that have the OFN_EXPLORER flag set), a single null character, \0, separates the filenames, and two null characters, \0\0, terminate the entire string.
OFN_CREATEPROMPT
	Specifies that the dialog box function should ask whether the user wants to create a file that does not currently exist. (This flag automatically uses the OFN_PATHMUSTEXIST and OFN_FILEMUSTEXIST flags.)
OFN_ENABLEHOOK
	Enables the hook function specified in the lpfnHook member.
OFN_ENABLETEMPLATE
	Causes the operating system to create the dialog box by using the dialog box template identified by hInstance and lpTemplateName.
OFN_ENABLETEMPLATEHANDLE
	Indicates that hInstance identifies a data block that contains a preloaded dialog box template. The operating system ignores lpTemplateName if this flag is specified.
OFN_EXPLORER
	Creates an Open or Save As dialog box that uses user-interface features similar to the Windows Explorer.
OFN_EXTENSIONDIFFERENT
	Specifies that the user typed a filename extension that differs from the extension specified by lpstrDefExt. The function does not use this flag if lpstrDefExt is NULL.
OFN_FILEMUSTEXIST
	Specifies that the user can type only names of existing files in the File Name entry field. If this flag is specified and the user enters an invalid name, the dialog box procedure displays a warning in a message box. If this flag is specified, the OFN_PATHMUSTEXIST flag is also used.
OFN_HIDEREADONLY
	Hides the Read Only check box.
OFN_LONGNAMES
	Causes the Open or Save As dialog box to display long filenames. If this flag is not specified, the dialog box displays filenames in 8.3 format. This value is ignored if OFN_EXPLORER is set.
OFN_NOCHANGEDIR
	Restores the current directory to its original value if the user changed the directory while searching for files.
OFN_NODEREFERENCELINKS
	Directs the dialog box to return the path and filename of the selected shortcut (.LNK) file. If this value is not given, the dialog box returns the path and filename of the file referenced by the shortcut.
OFN_NOLONGNAMES
	Specifies that long filenames are not displayed in the File Name list box. This value is ignored if OFN_EXPLORER is set.
OFN_NONETWORKBUTTON
	Hides and disables the Network button.
OFN_NOREADONLYRETURN
	Specifies that the returned file does not have the Read Only check box checked and is not in a write-protected directory.
OFN_NOTESTFILECREATE
	Specifies that the file is not created before the dialog box is closed. This flag should be specified if the application saves the file on a create-nonmodify network sharepoint. When an application specifies this flag, the library does not check for write protection, a full disk, an open drive door, or network protection. Applications using this flag must perform file operations carefully, because a file cannot be reopened once it is closed.
OFN_NOVALIDATE
	Specifies that the common dialog boxes allow invalid characters in the returned filename. Typically, the calling application uses a hook function that checks the filename by using the FILEOKSTRING message. If the text box in the edit control is empty or contains nothing but spaces, the lists of files and directories are updated. If the text box in the edit control contains anything else, nFileOffset and nFileExtension are set to values generated by parsing the text. No default extension is added to the text, nor is text copied to the buffer specified by lpstrFileTitle.
	If the value specified by nFileOffset is less than zero, the filename is invalid. Otherwise, the filename is valid, and nFileExtension and nFileOffset can be used as if the OFN_NOVALIDATE flag had not been specified.
OFN_OVERWRITEPROMPT
	Causes the Save As dialog box to generate a message box if the selected file already exists. The user must confirm whether to overwrite the file.
OFN_PATHMUSTEXIST
	Specifies that the user can type only valid paths and filenames. If this flag is used and the user types an invalid path and filename in the File Name entry field, the dialog box function displays a warning in a message box.
OFN_READONLY
	Causes the Read Only check box to be checked initially when the dialog box is created. This flag indicates the state of the Read Only check box when the dialog box is closed.
OFN_SHAREAWARE
	Specifies that if a call to the OpenFile function fails because of a network sharing violation, the error is ignored and the dialog box returns the given filename. If this flag is not specified, the registered message for SHAREVISTRING is sent to the hook function with a pointer to a null-terminated string for the path and filename in the lParam parameter.
OFN_SHOWHELP
	Causes the dialog box to show the Help button. The hwndOwner member must not be NULL if this option is specified.
nFileOffset

Specifies a zero-based offset from the beginning of the path to the filename in the string pointed to by lpstrFile. For example, if lpstrFile points to the following string, "c:\dir1\dir2\file.ext", this member contains the value 13.

nFileExtension

Specifies a zero-based offset from the beginning of the path to the filename extension in the string pointed to by lpstrFile. For example, if lpstrFile points to the following string, "c:\dir1\dir2\file.ext", this member contains the value 18. If the user did not type an extension and lpstrDefExt is NULL, this member specifies an offset to the terminating null character. If the user typed "." as the last character in the filename, this member specifies 0.

lpstrDefExt

Points to a buffer that contains the default extension. GetOpenFileName and GetSaveFileName append this extension to the filename if the user fails to type an extension. This string can be any length, but only the first three characters are appended. The string should not contain a period (.). If this member is NULL and the user fails to type an extension, no extension is appended.

lCustData

Specifies application-defined data that the operating system passes to the hook function identified by lpfnHook. The system passes the data in the lParam parameter of the WM_INITDIALOG message.

lpfnHook

Points to a hook function that processes messages intended for the dialog box. An application must specify the OFN_ENABLEHOOK flag in the Flags member to enable the function; otherwise, the operating system ignores this structure member. The hook function should return FALSE to pass a message to the standard dialog box procedure or TRUE to discard the message.

If the hook function processes WM_CTLCOLOR* messages (such as WM_CTLCOLORDLG), the function must return a valid brush handle for painting the background of the dialog box or the corresponding control.

lpTemplateName

Points to a null-terminated string that names the dialog box template to be substituted for the standard dialog box template. An application can use the MAKEINTRESOURCE macro for numbered dialog box resources. This member is only used if Flags specifies the OFN_ENABLETEMPLATE flag; otherwise, this member is ignored.

See Also

GetOpenFileName, GetSaveFileName


OSVERSIONINFO
OSVERSIONINFO  QuickInfo

typedef struct _OSVERSIONINFO{

    DWORD dwOSVersionInfoSize;

    DWORD dwMajorVersion;

    DWORD dwMinorVersion;

    DWORD dwBuildNumber;

    DWORD dwPlatformId;

    TCHAR szCSDVersion[ 128 ];

} OSVERSIONINFO;

The OSVERSIONINFO data structure contains operating system version information. The information includes major and minor version numbers, a build number, a platform identifier, and descriptive text about the operating system. This structure is used with the GetVersionEx function.

Members

dwOSVersionInfoSize

Specifies the size, in bytes, of this data structure. Set this member to sizeof(OSVERSIONINFO) before calling the GetVersionEx function.

dwMajorVersion

Identifies the major version number of the operating system. For example, the major version number of the Daytona release of Windows NT is 3.

dwMinorVersion

Identifies the minor version number of the operating system. For example, the minor version number of the Daytona release of Windows NT is 5.

dwBuildNumber

Identifies the build number of the operating system in the low-order word. (The high-order word contains the major and minor version numbers.)

dwPlatformId

Identifies the platform supported by the operating system.

This member can have one of the following values:

Value	Platform
VER_PLATFORM_WIN32s	Win32s on Windows 3.1
VER_PLATFORM_WIN32_WINDOWS	Win32 on Windows 95
VER_PLATFORM_WIN32_NT	Windows NT
szCSDVersion

Contains a zero-terminated string that provides arbitrary additional information about the operating system.

See Also

GetVersionEx


OUTLINETEXTMETRIC
OUTLINETEXTMETRIC  QuickInfo

typedef struct _OUTLINETEXTMETRIC { // otm

    UINT   otmSize;

    TEXTMETRIC otmTextMetrics;

    BYTE   otmFiller;

    PANOSE otmPanoseNumber;

    UINT   otmfsSelection;

    UINT   otmfsType;

    int    otmsCharSlopeRise;

    int    otmsCharSlopeRun;

    int    otmItalicAngle;

    UINT   otmEMSquare;

    int    otmAscent;

    int    otmDescent;

    UINT   otmLineGap;

    UINT   otmsCapEmHeight;

    UINT   otmsXHeight;

    RECT   otmrcFontBox;

    int    otmMacAscent;

    int    otmMacDescent;

    UINT   otmMacLineGap;

    UINT   otmusMinimumPPEM;

    POINT  otmptSubscriptSize;

    POINT  otmptSubscriptOffset;

    POINT  otmptSuperscriptSize;

    POINT  otmptSuperscriptOffset;

    UINT   otmsStrikeoutSize;

    int    otmsStrikeoutPosition;

    int    otmsUnderscoreSize;

    int    otmsUnderscorePosition;

    PSTR   otmpFamilyName;

    PSTR   otmpFaceName;

    PSTR   otmpStyleName;

    PSTR   otmpFullName;

} OUTLINETEXTMETRIC;

The OUTLINETEXTMETRIC structure contains metrics describing a TrueType font.

Members

otmSize

Specifies the size, in bytes, of the OUTLINETEXTMETRIC structure.

otmTextMetrics

Specifies a TEXTMETRIC structure containing further information about the font.

otmFiller

Specifies a value that causes the structure to be byte aligned.

otmPanoseNumber

Specifies the PANOSE number for this font.

otmfsSelection

Specifies the nature of the font pattern. This member can be a combination of the following bits:

Bit	Meaning
0	Italic
1	Underscore
2	Negative
3	Outline
4	Strikeout
5	Bold
otmfsType

Specifies whether the font is licensed. Licensed fonts must not be modified or exchanged. If bit 1 is set, the font may not be embedded in a document. If bit 1 is clear, the font can be embedded. If bit 2 is set, the embedding is read-only.

otmsCharSlopeRise

Specifies the slope of the cursor. This value is 1 if the slope is vertical. Applications can use this value and the value of the otmsCharSlopeRun member to create an italic cursor that has the same slope as the main italic angle (specified by the otmItalicAngle member).

otmsCharSlopeRun

Specifies the slope of the cursor. This value is zero if the slope is vertical. Applications can use this value and the value of the otmsCharSlopeRise member to create an italic cursor that has the same slope as the main italic angle (specified by the otmItalicAngle member).

otmItalicAngle

Specifies the main italic angle of the font, in tenths of a degree counterclockwise from vertical. Regular (roman) fonts have a value of zero. Italic fonts typically have a negative italic angle (that is, they lean to the right).

otmEMSquare

Specifies the number of logical units defining the x- or y-dimension of the em square for this font. (The number of units in the x- and y-directions are always the same for an em square.)

otmAscent

Specifies the maximum distance characters in this font extend above the base line. This is the typographic ascent for the font.

otmDescent

Specifies the maximum distance characters in this font extend below the base line. This is the typographic descent for the font.

otmLineGap

Specifies typographic line spacing.

otmsCapEmHeight

Not supported.

otmsXHeight

Not supported.

otmrcFontBox

Specifies the bounding box for the font.

otmMacAscent

Specifies the maximum distance characters in this font extend above the base line for the Macintosh® computer.

otmMacDescent

Specifies the maximum distance characters in this font extend below the base line for the Macintosh® computer.

otmMacLineGap

Specifies line-spacing information for the Macintosh® computer.

otmusMinimumPPEM

Specifies the smallest recommended size for this font, in pixels per em-square.

otmptSubscriptSize

Specifies the recommended horizontal and vertical size for subscripts in this font.

otmptSubscriptOffset

Specifies the recommended horizontal and vertical offset for subscripts in this font. The subscript offset is measured from the character origin to the origin of the subscript character.

otmptSuperscriptSize

Specifies the recommended horizontal and vertical size for superscripts in this font.

otmptSuperscriptOffset

Specifies the recommended horizontal and vertical offset for superscripts in this font. The superscript offset is measured from the character base line to the base line of the superscript character.

otmsStrikeoutSize

Specifies the width of the strikeout stroke for this font. Typically, this is the width of the em dash for the font.

otmsStrikeoutPosition

Specifies the position of the strikeout stroke relative to the base line for this font. Positive values are above the base line and negative values are below.

otmsUnderscoreSize

Specifies the thickness of the underscore character for this font.

otmsUnderscorePosition

Specifies the position of the underscore character for this font.

otmpFamilyName

Specifies the offset from the beginning of the structure to a string specifying the family name for the font.

otmpFaceName

Specifies the offset from the beginning of the structure to a string specifying the typeface name for the font. (This typeface name corresponds to the name specified in the LOGFONT structure.)

otmpStyleName

Specifies the offset from the beginning of the structure to a string specifying the style name for the font.

otmpFullName

Specifies the offset from the beginning of the structure to a string specifying the full name for the font. This name is unique for the font and often contains a version number or other identifying information.

Remarks

The sizes returned in OUTLINETEXTMETRIC are given in logical units; that is, they depend on the current mapping mode of the specified display context.

See Also

GetOutlineTextMetrics, LOGFONT, TEXTMETRIC


OUTPUT_DEBUG_STRING_INFO
OUTPUT_DEBUG_STRING_INFO  QuickInfo

typedef struct _OUTPUT_DEBUG_STRING_INFO { // odsi

    LPSTR lpDebugStringData;

    WORD  fUnicode;

    WORD  nDebugStringLength;

} OUTPUT_DEBUG_STRING_INFO;

The OUTPUT_DEBUG_STRING_INFO structure contains the address, format, and length, in bytes, of a debugging string.

Members

lpDebugStringData

Points to the address of the debugging string in the calling process's address space. The debugger can use the ReadProcessMemory function to retrieve the value of the string.

fUnicode

Specifies the format of the debugging string. If this member is zero, the debugging string is 8-bit ASCII; if it is nonzero, the string is 16-bit Unicode™.

nDebugStringLength

Specifies the length, in bytes, of the debugging string. The length includes the string's terminating null character.

See Also

DEBUG_EVENT, ReadProcessMemory


OVERLAPPED
OVERLAPPED  QuickInfo

typedef struct _OVERLAPPED { // o

    DWORD  Internal;

    DWORD  InternalHigh;

    DWORD  Offset;

    DWORD  OffsetHigh;

    HANDLE hEvent;

} OVERLAPPED;

The OVERLAPPED structure contains information used in asynchronous input and output (I/O).

Members

Internal

Reserved for operating system use. This member, which specifies a system-dependent status, is valid when the GetOverlappedResult function returns without setting the extended error information to ERROR_IO_PENDING.

InternalHigh

Reserved for operating system use. This member, which specifies the length of the data transferred, is valid when the GetOverlappedResult function returns TRUE.

Offset

Specifies a file position at which to start the transfer. The file position is a byte offset from the start of the file. The calling process sets this member before calling the ReadFile or WriteFile function. This member is ignored when reading from or writing to named pipes and communications devices.

OffsetHigh

Specifies the high word of the byte offset at which to start the transfer. This member is ignored when reading from or writing to named pipes and communications devices.

hEvent

Identifies an event set to the signaled state when the transfer has been completed. The calling process sets this member before calling the ReadFile, WriteFile, ConnectNamedPipe, or TransactNamedPipe function.

See Also

ConnectNamedPipe, CreateFile, GetOverlappedResult, ReadFile, ReadFileEx, TransactNamedPipe, WriteFile, WriteFileEx


PAGESETUPDLG
PAGESETUPDLG  Overview  Group

typedef struct tagPSD {  // psd

    DWORD           lStructSize;

    HWND            hwndOwner;

    HGLOBAL         hDevMode;

    HGLOBAL         hDevNames;

    DWORD           Flags;

    POINT           ptPaperSize;

    RECT            rtMinMargin;

    RECT            rtMargin;

    HINSTANCE       hInstance;

    LPARAM          lCustData;

    LPPAGESETUPHOOK lpfnPageSetupHook;

    LPPAGEPAINTHOOK lpfnPagePaintHook;

    LPCTSTR         lpPageSetupTemplateName;

    HGLOBAL         hPageSetupTemplate;

} PAGESETUPDLG, * LPPAGESETUPDLG;

Contains information to initialize the Page Setup dialog box. After the user closes the dialog box, the structure receives information about the user-defined page parameters in this structure. This structure is used with the PageSetupDlg function.

Members

lStructSize

Size, in bytes, of this structure.

hwndOwner

Handle to the window that owns the Setup dialog box. If this parameter is NULL, the dialog box has no owner.

hDevMode

Handle to a global memory object that contains a DEVMODE structure. On input, if a handle is given, the values in the corresponding DEVMODE structure are used to initialize the controls in the dialog box. On output, this member is set to a global memory handle for a DEVMODE structure that contains values specifying the user's selections or to NULL if the user's selections are not available.

hDevNames

Handle to a global memory object that contains a DEVNAMES structure. This structure contains three strings that specify the driver name, the printer name, and the output port name. On input, if a handle is given, the strings in the corresponding DEVNAMES structure are used to initialize controls in the dialog box. On output, this member is set to the global memory handle for a DEVNAMES structure that contains strings specifying the user's selections or to NULL if the user's selections are not available.

Flags

Initialization flags. Can be a combination of the following values:

PSD_DEFAULTMINMARGINS
	Sets the minimum allowable widths for the page margins to be the same as the printer's minimums. This flag is ignored if the PSD_MARGINS and PSD_MINMARGINS flags are also specified.
PSD_DISABLEMARGINS
	Disables the margin controls, preventing the user from setting the margins.
PSD_DISABLEORIENTATION
	Disables the orientation controls, preventing the user from setting the page orientation.
PSD_DISABLEPAGEPAINTING
	Prevents the system from displaying the sample page.
PSD_DISABLEPAPER
	Disables the paper controls, preventing the user from setting page parameters such as the paper size and source.
PSD_DISABLEPRINTER
	Disables the Printer button, preventing the user from invoking a dialog box that contains additional printer setup information.
PSD_ENABLEPAGEPAINTHOOK
	Enables the hook function specified in the lpfnPagePaintHook member. This flag overrides the PSD_DISABLEPAGEPAINTING flag.
PSD_ENABLEPAGESETUPHOOK
	Enables the hook function specified in the lpfnPageSetupHook member.
PSD_ENABLEPAGESETUPTEMPLATE
	Causes the system to create the Page Setup dialog box by using the dialog template identified by the hInstance and lpPageSetupTemplateName members.
PSD_ENABLEPAGESETUPTEMPLATEHANDLE
	Indicates that the hPageSetupTemplate member identifies a data block that contains a preloaded dialog box template. The system ignores the lpPageSetupTemplateName member if this flag is specified.
PSD_INHUNDREDTHSOFMILLIMETERS
	Causes the system to use hundredths of millimeters as the unit of measure for the margins.
PSD_INTHOUSANDTHSOFINCHES
	Causes the system to use thousandths of inches as the unit of measure for the margins.
PSD_INWININIINTLMEASURE
	Not implemented.
PSD_MARGINS
	Causes the system to use the values specified in the rtMargin member as the initial widths for the left, top, right, and bottom margins. If PSD_MARGINS is not specified, the system sets the initial widths to one inch for all margins.
PSD_MINMARGINS
	Causes the system to use the values specified in the rtMinMargin member as the minimum allowable widths for the left, top, right, and bottom margins. The system prevents the user from entering a width that is less than the specified minimum. If PSD_MINMARGINS is not specified, the system sets the minimum allowable widths to those allowed by the printer.
PSD_NOWARNING
	Prevents the system from displaying a warning message when there is no default printer.
PSD_RETURNDEFAULT
	Causes PageSetupDlg to return DEVMODE and DEVNAMES structures that are initialized for the system default printer, without displaying a dialog box. It is assumed that both hDevNames and hDevMode are NULL; otherwise, the function returns an error.
PSD_SHOWHELP
	Causes the dialog box to show the help button. Because the system sends a message to the owner window when the user presses the Help button, the hwndOwner member must not be NULL if PSD_SHOWHELP is specified.
ptPaperSize

Dimensions of the paper selected by the user.

rtMinMargin

Minimum allowable widths for the left, top, right, and bottom margins. These values must be less than the values specified in the rtMargin member. This system ignores this member if the PSD_MARGINS and PSD_MINMARGINS flags are not specified.

rtMargin

Initial widths for the left, top, right, and bottom margins. When the PageSetupDlg function returns, this member contains the margins widths selected by the user. This system ignores this member if the PSD_MARGINS flag is not specified.

hInstance

Handle to the application or module instance that contains the dialog box template specified in the lpPageSetupTemplateName member. This member is used only if the Flags member includes the PSD_ENABLEPAGESETUPTEMPLATE flag; otherwise, this member is ignored.

lCustData

Application-defined data that the system passes to the hook function pointed to by the lpfnPageSetupHook member. The system passes the data in the lParam parameter of the WM_INITDIALOG message.

lpfnPageSetupHook

Pointer to a hook function that processes messages intended for the dialog box. An application must specify the PSD_ENABLEPAGESETUPHOOK flag in the Flags member to enable the function; otherwise, the system ignores this member. The hook function should return FALSE to pass a message on to the standard dialog box procedure or TRUE to discard the message. If the hook function processes the WM_CTLCOLORDLG message, the function must return a valid brush handle for painting the background of the dialog box.

If the hook function returns FALSE in response to the WM_INITDIALOG message, the function is responsible for calling the ShowWindow and UpdateWindow functions to display the dialog box any painting operations are complete.

lpfnPagePaintHook

Pointer to a hook function that receives WM_PSD_* messages from the dialog box whenever the sample page is redrawn. By processing the messages, the hook function can customize the appearance of the sample page.

lpPageSetupTemplateName

Pointer to a null-terminated string that names the dialog box template resource to substitute for the standard dialog box template. An application can use the MAKEINTRESOURCE macro for numbered dialog box resources. This member is used only if the Flags member specifies the PSD_ENABLEPAGESETUPTEMPLATE flag; otherwise, this member is ignored.

hPageSetupTemplate

Identifies a data block that contains a preloaded dialog box template. This member is used only if the Flags member specifies the PSD_ENABLEPAGESETUPTEMPLATEHANDLE flag; otherwise, this member is ignored.

Remarks

If the PSD_INHUNDREDTHSOFMILLIMETERS and PSD_INTHOUSANDTHSOFINCHES flags are not specified, the system queries the LOCALE_IMEASURE value of the default user locale to determine the unit of measure (either hundredths of millimeters or thousandths of inches) for the margin widths.

If both hDevNames and hDevMode have valid handles and the printer name specified by the wDeviceOffset member of the DEVNAMES structure is not the same as the name specified by the dmDeviceName member of the DEVMODE structure, the system uses the name specified by wDeviceOffset by default.

See Also

DEVMODE, DEVNAMES, MAKEINTRESOURCE, PageSetupDlg, ShowWindow, UpdateWindow, WM_CTLCOLORDLG, WM_INITDIALOG


PAINTSTRUCT
PAINTSTRUCT  QuickInfo

typedef struct tagPAINTSTRUCT { // ps

    HDC  hdc;

    BOOL fErase;

    RECT rcPaint;

    BOOL fRestore;

    BOOL fIncUpdate;

    BYTE rgbReserved[32];

} PAINTSTRUCT;

The PAINTSTRUCT structure contains information for an application. This information can be used to paint the client area of a window owned by that application.

Members

hdc

Identifies the display DC to be used for painting.

fErase

Specifies whether the background must be erased. This value is nonzero if the application should erase the background. The application is responsible for erasing the background if a window class is created without a background brush. For more information, see the description of the hbrBackground member of the WNDCLASS structure.

rcPaint

Specifies a RECT structure that specifies the upper left and lower right corners of the rectangle in which the painting is requested.

fRestore

Reserved; used internally by Windows.

fIncUpdate

Reserved; used internally by Windows.

rgbReserved

Reserved; used internally by Windows.

See Also

BeginPaint, RECT, WNDCLASS


PALETTEENTRY
PALETTEENTRY  QuickInfo

typedef struct tagPALETTEENTRY { // pe

    BYTE peRed;

    BYTE peGreen;

    BYTE peBlue;

    BYTE peFlags;

} PALETTEENTRY;

The PALETTEENTRY structure specifies the color and usage of an entry in a logical color palette. A logical palette is defined by a LOGPALETTE structure.

Members

peRed

Specifies a red intensity value for the palette entry.

peGreen

Specifies a green intensity value for the palette entry.

peBlue

Specifies a blue intensity value for the palette entry.

peFlags

Specifies how the palette entry is to be used. The peFlags member may be set to NULL or one of the following values:

Value	Meaning
PC_EXPLICIT	Specifies that the low-order word of the logical palette entry designates a hardware palette index. This flag allows the application to show the contents of the display device palette.
PC_NOCOLLAPSE	Specifies that the color be placed in an unused entry in the system palette instead of being matched to an existing color in the system palette. If there are no unused entries in the system palette, the color is matched normally. Once this color is in the system palette, colors in other logical palettes can be matched to this color.
PC_RESERVED	Specifies that the logical palette entry be used for palette animation. This flag prevents other windows from matching colors to the palette entry since the color frequently changes. If an unused system-palette entry is available, the color is placed in that entry. Otherwise, the color is not available for animation.
See Also

LOGPALETTE


PANOSE
PANOSE  QuickInfo

typedef struct tagPANOSE { // pnse

    BYTE bFamilyType;

    BYTE bSerifStyle;

    BYTE bWeight;

    BYTE bProportion;

    BYTE bContrast;

    BYTE bStrokeVariation;

    BYTE bArmStyle;

    BYTE bLetterform;

    BYTE bMidline;

    BYTE bXHeight;

} PANOSE

The PANOSE structure describes the PANOSE font-classification values for a TrueType font. These characteristics are then used to associate the font with other fonts of similar appearance but different names.

Members

bFamilyType

For Latin fonts, bFamilyType can have one of the following values:

Value	Meaning
PAN_ANY	Any
PAN_NO_FIT	No fit
PAN_FAMILY_TEXT_DISPLAY	Text and display
PAN_FAMILY_SCRIPT	Script
PAN_FAMILY_DECORATIVE	Decorative
PAN_FAMILY_PICTORIAL	Pictorial
bSerifStyle

Specifies the serif style. For Latin fonts, bSerifStyle can have one of the following values:

Value	Meaning
PAN_ANY	Any
PAN_NO_FIT	No fit
PAN_SERIF_COVE	Cove
PAN_SERIF_OBTUSE_COVE	Obtuse cove
PAN_SERIF_SQUARE_COVE	Square cove
PAN_SERIF_OBTUSE_SQUARE_COVE	Obtuse square cove
PAN_SERIF_SQUARE	Square
PAN_SERIF_THIN	Thin
PAN_SERIF_BONE	Bone
PAN_SERIF_EXAGGERATED	Exaggerated
PAN_SERIF_TRIANGLE	Triangle
PAN_SERIF_NORMAL_SANS	Normal sans serif
PAN_SERIF_OBTUSE_SANS	Obtuse sans serif
PAN_SERIF_PERP_SANS	Perp sans serif
PAN_SERIF_FLARED	Flared
PAN_SERIF_ROUNDED	Rounded
bWeight

For Latin fonts, bWeight can have one of the following values:

Value	Meaning
PAN_ANY	Any
PAN_NO_FIT	No fit
PAN_WEIGHT_VERY_LIGHT	Very light
PAN_WEIGHT_LIGHT	Light
PAN_WEIGHT_THIN	Thin
PAN_WEIGHT_BOOK	Book
PAN_WEIGHT_MEDIUM	Medium
PAN_WEIGHT_DEMI	Demibold
PAN_WEIGHT_BOLD	Bold
PAN_WEIGHT_HEAVY	Heavy
PAN_WEIGHT_BLACK	Black
PAN_WEIGHT_NORD	Nord
bProportion

For Latin fonts, bProportion can have one of the following values:

Value	Meaning
PAN_ANY	Any
PAN_NO_FIT	No fit
PAN_PROP_OLD_STYLE	Old style
PAN_PROP_MODERN	Modern
PAN_PROP_EVEN_WIDTH	Even width
PAN_PROP_EXPANDED	Expanded
PAN_PROP_CONDENSED	Condensed
PAN_PROP_VERY_EXPANDED	Very expanded
PAN_PROP_VERY_CONDENSED	Very condensed
PAN_PROP_MONOSPACED	Monospaced
bContrast

For Latin fonts, bContrast can have one of the following values:

Value	Meaning
PAN_ANY	Any
PAN_NO_FIT	No fit
PAN_CONTRAST_NONE	None
PAN_CONTRAST_VERY_LOW	Very low
PAN_CONTRAST_LOW	Low
PAN_CONTRAST_MEDIUM_LOW	Medium low
PAN_CONTRAST_MEDIUM	Medium
PAN_CONTRAST_MEDIUM_HIGH	Medium high
PAN_CONTRAST_HIGH	High
PAN_CONTRAST_VERY_HIGH	Very high
bStrokeVariation

For Latin fonts, bStrokeVariation can have one of the following values:

Value	Meaning
PAN_ANY	Any
PAN_NO_FIT	No fit
PAN_STROKE_GRADUAL_DIAG	Gradual/diagonal
PAN_STROKE_GRADUAL_TRAN	Gradual/transitional
PAN_STROKE_GRADUAL_VERT	Gradual/vertical
PAN_STROKE_GRADUAL_HORZ	Gradual/horizontal
PAN_STROKE_RAPID_VERT	Rapid/vertical
PAN_STROKE_RAPID_HORZ	Rapid/horizontal
PAN_STROKE_INSTANT_VERT	Instant/vertical
bArmStyle

For Latin fonts, bArmStyle can have one of the following values:

Value	Meaning
PAN_ANY	Any
PAN_NO_FIT	No fit
PAN_STRAIGHT_ARMS_HORZ	Straight arms/horizontal
PAN_STRAIGHT_ARMS_WEDGE	Straight arms/wedge
PAN_STRAIGHT_ARMS_VERT	Straight arms/vertical
PAN_STRAIGHT_ARMS_SINGLE_SERIF	Straight arms/single-serif
PAN_STRAIGHT_ARMS_DOUBLE_SERIF	Straight arms/double-serif
PAN_BENT_ARMS_HORZ	Non-straight arms/horizontal
PAN_BENT_ARMS_WEDGE	Non-straight arms/wedge
PAN_BENT_ARMS_VERT	Non-straight arms/vertical
PAN_BENT_ARMS_SINGLE_SERIF	Non-straight arms/single-serif
PAN_BENT_ARMS_DOUBLE_SERIF	Non-straight arms/double-serif
bLetterform

For Latin fonts, bLetterform can have one of the following values:

Value	Meaning
PAN_ANY	Any
PAN_NO_FIT	No fit
PAN_LETT_NORMAL_CONTACT	Normal/contact
PAN_LETT_NORMAL_WEIGHTED	Normal/weighted
PAN_LETT_NORMAL_BOXED	Normal/boxed
PAN_LETT_NORMAL_FLATTENED	Normal/flattened
PAN_LETT_NORMAL_ROUNDED	Normal/rounded
PAN_LETT_NORMAL_OFF_CENTER	Normal/off center
PAN_LETT_NORMAL_SQUARE	Normal/square
PAN_LETT_OBLIQUE_CONTACT	Oblique/contact
PAN_LETT_OBLIQUE_WEIGHTED	Oblique/weighted
PAN_LETT_OBLIQUE_BOXED	Oblique/boxed
PAN_LETT_OBLIQUE_FLATTENED	Oblique/flattened
PAN_LETT_OBLIQUE_ROUNDED	Oblique/rounded
PAN_LETT_OBLIQUE_OFF_CENTER	Oblique/off center
PAN_LETT_OBLIQUE_SQUARE	Oblique/square
bMidline

For Latin fonts, bMidline can have one of the following values:

Value	Meaning
PAN_ANY	Any
PAN_NO_FIT	No fit
PAN_MIDLINE_STANDARD_TRIMMED	Standard/trimmed
PAN_MIDLINE_STANDARD_POINTED	Standard/pointed
PAN_MIDLINE_STANDARD_SERIFED	Standard/serifed
PAN_MIDLINE_HIGH_TRIMMED	High/trimmed
PAN_MIDLINE_HIGH_POINTED	High/pointed
PAN_MIDLINE_HIGH_SERIFED	High/serifed
PAN_MIDLINE_CONSTANT_TRIMMED	Constant/trimmed
PAN_MIDLINE_CONSTANT_POINTED	Constant/pointed
PAN_MIDLINE_CONSTANT_SERIFED	Constant/serifed
PAN_MIDLINE_LOW_TRIMMED	Low/trimmed
PAN_MIDLINE_LOW_POINTED	Low/pointed
PAN_MIDLINE_LOW_SERIFED	Low/serifed
bXHeight

For Latin fonts, bXHeight can have one of the following values:

Value	Meaning
PAN_ANY	Any
PAN_NO_FIT	No fit
PAN_XHEIGHT_CONSTANT_SMALL	Constant/small
PAN_XHEIGHT_CONSTANT_STD	Constant/standard
PAN_XHEIGHT_CONSTANT_LARGE	Constant/large
PAN_XHEIGHT_DUCKING_SMALL	Ducking/small
PAN_XHEIGHT_DUCKING_STD	Ducking/standard
PAN_XHEIGHT_DUCKING_LARGE	Ducking/large


PARAFORMAT [New - Windows NT]
PARAFORMAT  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct _paraformat {

    UINT cbSize;

    _WPAD _wPad1;

    DWORD dwMask;

    WORD  wNumbering;

    WORD  wReserved;

    LONG  dxStartIndent;

    LONG  dxRightIndent;

    LONG  dxOffset;

    WORD  wAlignment;

    SHORT cTabCount;

    LONG  rgxTabs[MAX_TAB_STOPS];

} PARAFORMAT;

The PARAFORMAT structure contains information about paragraph formatting attributes in a rich edit control. This structure is used with the EM_GETPARAFORMAT and EM_SETPARAFORMAT messages.

Members

cbSize

Size in bytes of this structure. Must be filled before passing to the rich edit control.

dwMask

Members containing valid information or attributes to set. This parameter can be zero or more of these values:

Value	Meaning
PFM_ALIGNMENT	The wAlignment member is valid.
PFM_NUMBERING	The wNumbering member is valid.
PFM_OFFSET	The dxOffset member is valid.
PFM_OFFSETINDENT	The dxStartIndent member is valid and specifies a relative value.
PFM_RIGHTINDENT	The dxRightIndent member is valid.
PFM_STARTINDENT	The dxStartIndent member is valid.
PFM_TABSTOPS	The cTabStobs and rgxTabStops members are valid.
If both PFM_STARTINDENT and PFM_OFFSETINDENT are specified, PFM_STARTINDENT takes precedence.

wNumbering

Value specifying numbering options. This member can be zero or PFN_BULLET.

dxStartIndent

Indentation of the first line in the paragraph. If the paragraph formatting is being set and PFM_OFFSETINDENT is specified, this member is treated as a relative value that is added to the starting indentation of each affected paragraph.

dxRightIndent

Size of the right indentation, relative to the right margin.

dxOffset

Indentation of the second line and subsequent lines, relative to the starting indentation. The first line is indented if this member is negative, or outdented is this member is positive.

wAlignment

Value specifying the paragraph alignment. This member can be one of the following values:

Value	Meaning
PFA_LEFT	Paragraphs are aligned with the left margin.
PFA_RIGHT	Paragraphs are aligned with the right margin.
PFA_CENTER	Paragraphs are centered.
cTabCount

Number of tab stops.

rgxTabs

Array of absolute tab stop positions.

See Also

EM_GETPARAFORMAT, EM_SETPARAFORMAT


PARTITION_INFORMATION
PARTITION_INFORMATION  QuickInfo  Overview  Group

typedef struct _PARTITION_INFORMATION {

    BYTE PartitionType;

    BOOLEAN BootIndicator;

    BOOLEAN RecognizedPartition;

    BOOLEAN RewritePartition;

    LARGE_INTEGER StartingOffset;

    LARGE_INTEGER PartitionLength;

    LARGE_INTEGER HiddenSectors;

} PARTITION_INFORMATION ;

The PARTITION_INFORMATION structure provides information about a disk partition.

Members

PartitionType

Specifies the type of partition. This member can be one of the following values:

Value	Meaning
PARTITION_ENTRY_UNUSED	Entry unused.
PARTITION_FAT_12	Specifies a partition with 12-bit FAT entries.
PARTITION_XENIX_1	Specifies a Xenix type 1 partition.
PARTITION_XENIX_2	Specifies a Xenix type 2 partition.
PARTITION_FAT_16	Specifies a partition with 16-bit FAT entries.
PARTITION_EXTENDED	Specifies an extended partition entry.
PARTITION_HUGE	Specifies an MS-DOS V4 huge partition.
PARTITION_IFS	Specifies an IFS partition.
PARTITION_UNIX	Specifies a Unix partition.
VALID_NTFT	Specifies an NTFT partition.
BootIndicator

The boot sector of the disk.

RecognizedPartition

The partition is recognized.

RewritePartition

The rewrite partition.

StartingOffset

The starting offset.

PartitionLength

The partition length.

HiddenSectors

The number of hidden sectors.

Remarks

The DeviceIoControl function receives a PARTITION_INFORMATION structure in response to an IOCTL_DISK_GET_PARTITION_INFO or IOCTL_DISK_GET_DRIVE_LAYOUT device input and output control (IOCTL) operation. The DeviceIoControl function uses a PARTITION_INFORMATION structure as input to an IOCTL_DISK_SET_DRIVE_LAYOUT device IOCTL operation.

See Also

DeviceIoControl, IOCTL_DISK_GET_DRIVE_LAYOUT, IOCTL_DISK_GET_PARTITION_INFO, IOCTL_DISK_SET_DRIVE_LAYOUT


PERF_COUNTER_BLOCK
PERF_COUNTER_BLOCK  QuickInfo

typedef struct _PERF_COUNTER_BLOCK { // pcd

    DWORD ByteLength;

} PERF_COUNTER_BLOCK;

The PERF_COUNTER_BLOCK structure contains the length, in bytes, of the performance-counter data. This structure is followed by data for the number of counters specified in the PERF_OBJECT_TYPE structure.

Members

ByteLength

Specifies the length, in bytes, of this structure, including the counters that follow.

Remarks

This structure is part of the performance data provided by the RegQueryValueEx function when the HKEY_PERFORMANCE_DATA key is used.

See Also

PERF_OBJECT_TYPE, RegQueryValueEx


PERF_COUNTER_DEFINITION
PERF_COUNTER_DEFINITION  QuickInfo

typedef struct _PERF_COUNTER_DEFINITION { // pcd

    DWORD  ByteLength;

    DWORD  CounterNameTitleIndex;

    LPWSTR CounterNameTitle;

    DWORD  CounterHelpTitleIndex;

    LPWSTR CounterHelpTitle;

    DWORD  DefaultScale;

    DWORD  DetailLevel;

    DWORD  CounterType;

    DWORD  CounterSize;

    DWORD  CounterOffset;

} PERF_COUNTER_DEFINITION;

The PERF_COUNTER_DEFINITION structure describes a performance counter. The Unicode names in this structure must appear in a message file.

Members

ByteLength

Contains the length, in bytes, of this structure.

CounterNameTitleIndex

Contains the index of the counter name in the title database of the registry.

CounterNameTitle

Points to the name of the counter. This member contains NULL, initially, but it can contain a pointer to the actual string once the string is located.

CounterHelpTitleIndex

Contains the index to the counter's Help title in the title database of the registry.

CounterHelpTitle

Points to the title of Help. This member contains NULL, initially, but it can contain a pointer to the actual string once the string is located.

DefaultScale

Specifies the power of 10 by which to scale a chart line, assuming the vertical axis is 100. If this value is zero, the scale value is 1; if this value is 1, the scale value is 10; if this value is −1, the scale value is .10; and so on.

DetailLevel

Specifies the level of detail for the counter. Applications use this value to control display complexity. This member can be one of the following values:

Value	Meaning
PERF_DETAIL_NOVICE	The data can be understood by the uninformed user.
PERF_DETAIL_ADVANCED	The data is designed for the advanced user.
PERF_DETAIL_EXPERT	The data is designed for the expert user.
PERF_DETAIL_WIZARD	The data is designed for the system designer.
CounterType

Specifies the type of counter. This member is some combination of the following values.

These values indicate the counter's data size:

Value	Meaning
PERF_SIZE_DWORD	The counter data is a doubleword.
PERF_SIZE_LARGE	The counter data is a large integer.
PERF_SIZE_ZERO	The counter data is a zero-length field.
PERF_SIZE_VARIABLE_LEN	The size of the counter data is in the CounterSize member.
These values indicate the additional contents of this member:

Value	Meaning
PERF_TYPE_NUMBER	The counter data is a number value but not a counter.
PERF_TYPE_COUNTER	The counter data is an increasing numeric value.
PERF_TYPE_TEXT	The counter data is a text field.
PERF_TYPE_ZERO	The counter data is always zero.
If PERF_TYPE_NUMBER is specified, one of these values is also specified to indicate the format of the number:

Value	Meaning
PERF_NUMBER_HEX	The counter data should be displayed as a hexadecimal value.
PERF_NUMBER_DECIMAL	The counter data should be displayed as a decimal value.
PERF_NUMBER_DEC_1000	The counter data should be divided by 1000 and displayed as a decimal value.
If PERF_TYPE_COUNTER is specified, one of these values is also specified to indicate the type of counter:

Value	Meaning
PERF_COUNTER_VALUE	The counter value is valid without additional calculation; that is, it should be displayed as is.
PERF_COUNTER_RATE	The counter value should be divided by the elapsed time.
PERF_COUNTER_FRACTION	The counter value should be divided by the base value indicated by the next counter if it is of type PERF_COUNTER_BASE or by the value of the counter subtype.
PERF_COUNTER_BASE	The counter value is the base value to use in fractions.
PERF_COUNTER_ELAPSED	The counter value is a start time to be subtracted from the current time.
PERF_COUNTER_QUEUELEN	The performance application should use the Queuelen counter — that is, the Queue Length Space-Time Product formula. The next counter is the number currently in the queue. Multiply it by the current time (units specified by this counter's subtype). Add the product to the original value of the counter. To obtain the average queue length, divide the result of the addition by the delta time.
PERF_COUNTER_HISTOGRAM	The counter value begins or ends a histogram.
If PERF_TYPE_COUNTER is specified, one of these values is also specified to indicate the subtype of counter:

Value	Meaning
PERF_TIMER_TICK	The frequency of the high-resolution performance counter should be used as the base.
PERF_TIMER_100NS	The time base units of the 100-nanosecond timer should be used as the base.
PERF_OBJECT_TIMER	The object-timer frequency should be used as the base unit. This value is system-defined in this counter's PERF_OBJECT_TYPE definition.
If PERF_TYPE_TEXT is specified, one of these values is also specified to indicate the type of text:

Value	Meaning
PERF_TEXT_UNICODE	The counter data contains Unicode text.
PERF_TEXT_ASCII	The counter data contains ASCII text.
These values indicate how to use the counter data in a calculation:

Value	Meaning
PERF_DELTA_COUNTER	The difference between the previous counter value and the current counter value is computed before proceeding.
PERF_DELTA_BASE	The difference between the previous base value and the current base value is computed before proceeding.
PERF_INVERSE_COUNTER	After other calculations, the counter should be inverted before displaying or converting to a percentage.
PERF_MULTI_COUNTER	This value is a sum of counters from several sources, the number of which is indicated by the next counter.
These values indicate the display suffix of the counter data:

Value	Meaning
PERF_DISPLAY_NO_SUFFIX	There is no display suffix.
PERF_DISPLAY_PER_SEC	The display suffix is '/sec'.
PERF_DISPLAY_PERCENT	The display suffix is '%'.
PERF_DISPLAY_SECONDS	The display suffix is 'secs'.
PERF_DISPLAY_NOSHOW	The counter value should not be displayed.
CounterSize

Specifies the counter size, in bytes.

CounterOffset

Specifies the offset from the start of the PERF_COUNTER_BLOCK structure to the first byte of this counter.

Remarks

This structure is part of the performance data provided by the RegQueryValueEx function when the HKEY_PERFORMANCE_DATA key is used.

See Also

RegQueryValueEx


PERF_DATA_BLOCK
PERF_DATA_BLOCK  QuickInfo

typedef struct _PERF_DATA_BLOCK { // pdb

    WCHAR         Signature[4];

    DWORD         LittleEndian;

    DWORD         Version;

    DWORD         Revision;

    DWORD         TotalByteLength;

    DWORD         HeaderLength;

    DWORD         NumObjectTypes;

    DWORD         DefaultObject;

    SYSTEMTIME    SystemTime;

    LARGE_INTEGER PerfTime;

    LARGE_INTEGER PerfFreq;

    LARGE_INTEGER PerfTime100nSec;

    DWORD         SystemNameLength;

    DWORD         SystemNameOffset;

} PERF_DATA_BLOCK;

The PERF_DATA_BLOCK structure describes the performance data provided by RegQueryValueEx function. The data starts with a PERF_DATA_BLOCK structure and is followed by a PERF_OBJECT_TYPE structure and other object-specific data for each type of object monitored.

Members

Signature

Contains the Unicode string PERF.

LittleEndian

Contains zero if the processor is big endian and one if it is little endian.

Version

Contains the version of the performance (PERF_) structures. This member is greater than or equal to one.

Revision

Contains the revision of the performance (PERF_) structures. This member is greater than or equal to zero.

TotalByteLength

Contains the total length, in bytes, of the performance data.

HeaderLength

Contains the length, in bytes, of this structure.

NumObjectTypes

Contains the number of object types being monitored.

DefaultObject

Contains the object title index of the default object whose performance data is to be displayed. This member can be −1 to indicate that no data is to be displayed.

SystemTime

Contains the time when the system is monitored. This member is in Coordinated Universal Time (UTC) format.

PerfTime

Contains the performance-counter value, in counts, for the system being monitored.

PerfFreq

Contains the performance-counter frequency, in counts per second, for the system being monitored.

PerfTime100nSec

Contains the performance-counter value, in 100 nanosecond units, for the system being monitored.

SystemNameLength

Contains the length, in bytes, of the system name.

SystemNameOffset

Contains the offset from the beginning of this structure to the name of the system being monitored.

See Also

PERF_OBJECT_TYPE, RegQueryValueEx


PERF_INSTANCE_DEFINITION
PERF_INSTANCE_DEFINITION  QuickInfo

typedef struct _PERF_INSTANCE_DEFINITION { // pid

    DWORD ByteLength;

    DWORD ParentObjectTitleIndex;

    DWORD ParentObjectInstance;

    DWORD UniqueID;

    DWORD NameOffset;

    DWORD NameLength;

} PERF_INSTANCE_DEFINITION;

The PERF_INSTANCE_DEFINITION structure contains the instance-specific information for a block of performance data. There is one PERF_INSTANCE_DEFINITION structure for each instance specified in the PERF_DATA_BLOCK structure.

Members

ByteLength

Specifies the length, in bytes, of this structure, including the subsequent name.

ParentObjectTitleIndex

Specifies the index of the name of the "parent" object in the title database. For example, if the object is a thread, the parent object type is a process, or if the object is a logical drive, the parent is a physical drive.

ParentObjectInstance

Specifies the index to an instance of the parent object type that is the parent of this instance. This member may be zero or greater.

UniqueID

Specifies the unique identifier used instead of the instance name. This member is PERF_NO_UNIQUE_ID if there is no such identifier.

NameOffset

Specifies the offset from the beginning of this structure to the Unicode name of this instance.

NameLength

Specifies the length, in bytes, of the instance name. This member is zero if the instance does not have a name.

See Also

PERF_DATA_BLOCK


PERF_OBJECT_TYPE
PERF_OBJECT_TYPE  QuickInfo

typedef struct _PERF_OBJECT_TYPE {  // pot

    DWORD  TotalByteLength;

    DWORD  DefinitionLength;

    DWORD  HeaderLength;

    DWORD  ObjectNameTitleIndex;

    LPWSTR ObjectNameTitle;

    DWORD  ObjectHelpTitleIndex;

    LPWSTR ObjectHelpTitle;

    DWORD  DetailLevel;

    DWORD  NumCounters;

    DWORD  DefaultCounter;

    DWORD  NumInstances;

    DWORD  CodePage;

    LARGE_INTEGER PerfTime;

    LARGE_INTEGER PerfFreq;

} PERF_OBJECT_TYPE;

The PERF_OBJECT_TYPE structure describes object-specific performance information. This structure is followed by a list of PERF_COUNTER_DEFINITION structures, one for each counter defined for the type of object.

Members

TotalByteLength

Contains the length, in bytes, of the object-specific data. This value includes this structure, the PERF_COUNTER_DEFINITION structures, and the PERF_INSTANCE_DEFINITION and PERF_COUNTER_BLOCK structures for each instance. This member specifies the offset from the beginning of this structure to the next PERF_OBJECT_TYPE structure if one exists.

DefinitionLength

Contains the length, in bytes, of the object-specific data. This value includes this structure and the PERF_COUNTER_DEFINITION structures for this object. This member is the offset from the beginning of the PERF_OBJECT_TYPE structure to the first PERF_INSTANCE_DEFINITION structure or to the PERF_COUNTER_DEFINITION structures if there is no instance data.

HeaderLength

Contains the length, in bytes, of this structure. This member is the offset to the first PERF_COUNTER_DEFINITION structure for this object.

ObjectNameTitleIndex

Contains the index to the object's name in the title database.

ObjectNameTitle

Points to the name of the object. This member initially contains NULL, but it can contain a pointer to the actual string once the string is located.

ObjectHelpTitleIndex

Contains the index to the object's Help title in the title database.

ObjectHelpTitle

Points to the title of Help. This member initially contains NULL, but it can contain a pointer to the actual string once the string is located.

DetailLevel

Specifies the level of detail. Applications use this value to control display complexity. This value is the minimum detail level of all the counters for a given object. This member can be one of the following values:

Detail level	Meaning
PERF_DETAIL_NOVICE	No technical ability is required to understand the counter data.
PERF_DETAIL_ADVANCED	The counter data is provided for advanced users.
PERF_DETAIL_EXPERT	The counter data is provided for expert users.
PERF_DETAIL_WIZARD	The counter data is provided for system designers.
NumCounters

Specifies the number of counters in each counter block. There is one counter block per instance.

DefaultCounter

Specifies the default counter whose information is to be displayed when this object is selected. This member is typically greater than or equal to zero. However, this member may be −1 to indicate that there is no default.

NumInstances

Specifies the number of object instances for which counters are being provided.

CodePage

Specifies the code page. This member is zero if the instance strings are in Unicode. Otherwise, this member is the code-page identifier of the instance names.

PerfTime

Specifies the current value, in counts, of the high-resolution performance counter.

PerfFreq

Specifies the current frequency, in counts per second, of the high-resolution performance counter.

Remarks

If there is only one instance of the object type, the counter definitions are followed by a single PERF_COUNTER_BLOCK structure. This structure is followed by data for each counter. (The PERF_COUNTER_BLOCK structure contains the total length of the structure and the counter data that follows it.)

If there is more than one instance of the object type, the list of counter definitions is followed by a PERF_INSTANCE_DEFINITION structure and a PERF_COUNTER_BLOCK structure for each instance. The PERF_INSTANCE_DEFINITION structure includes the name, the identifier, and the name of the parent of the instance.

Following the counter data, there is a PERF_INSTANCE_DEFINITION structure and a PERF_COUNTER_BLOCK structure for each instance specified in the PERF_DATA_BLOCK structure that begins the performance-data area.

See Also

PERF_COUNTER_BLOCK, PERF_COUNTER_DEFINITION, PERF_INSTANCE_DEFINITION


POINT
POINT  QuickInfo

typedef struct tagPOINT { // pt

    LONG x;

    LONG y;

} POINT;

The POINT structure defines the x- and y- coordinates of a point.

Members

x

Specifies the x-coordinate of the point.

y

Specifies the y-coordinate of the point.

See Also

ChildWindowFromPoint, GetBrushOrgEx, PtInRect, SetBrushOrgEx, WindowFromPoint


POINTFX
POINTFX  QuickInfo

typedef struct tagPOINTFX { // ptfx

    FIXED x;

    FIXED y;

} POINTFX;

The POINTFX structure contains the coordinates of points that describe the outline of a character in a TrueType font.

Members

x

Specifies the x-component of a point on the outline of a TrueType character.

y

Specifies the y-component of a point on the outline of a TrueType character.

Remarks

The POINTFX structure is a member of the TTPOLYCURVE and TTPOLYGONHEADER structures. Values in the POINTFX structure are specified in device units.

See Also

FIXED, TTPOLYCURVE, TTPOLYGONHEADER


POINTL
POINTL  QuickInfo

typedef struct _POINTL { // ptl

    LONG x;

    LONG y;

} POINTL;

The POINTL structure contains the coordinates of a point.

Members

x

Specifies the horizontal (x) coordinate of the point.

y

Specifies the vertical (y) coordinate of the point.


POINTS
POINTS  QuickInfo

typedef struct tagPOINTS { // pts

    SHORT x;

    SHORT y;

} POINTS;

The POINTS structure defines the coordinates of a point.

Members

x

Specifies the x-coordinate of the point.

y

Specifies the y-coordinate of the point.

See Also

ChildWindowFromPoint, PtInRect, WindowFromPoint, POINT


POLYTEXT
POLYTEXT  QuickInfo

typedef struct _POLYTEXT { // ptxt

    int     x;

    int     y;

    UINT    n;

    LPCTSTR lpstr;

    UINT    uiFlags;

    RECT    rcl;

    int     *pdx;

} POLYTEXT;

The POLYTEXT structure describes how the PolyTextOut function should draw a string of text.

Members

x

Specifies the horizontal reference point for the string. The string is aligned to this point using the current text-alignment mode.

y

Specifies the vertical reference point for the string. The string is aligned to this point using the current text-alignment mode.

n

Specifies the number of characters in the string.

uiFlags

Specifies whether the string is to be opaque or clipped and whether the string is accompanied by an array of character-width values. This member can be one or more of the following values:

Value	Meaning
ETO_OPAQUE	The rectangles given for each string is to be opaqued with the current background color.
ETO_CLIPPED	Each string is to be clipped to its given rectangle.
lpstr

Points to a string of text to be drawn by the PolyTextOut function.

rcl

Specifies a rectangle structure that contains the dimensions of the opaquing or clipping rectangle. This member is ignored if neither of the ETO_OPAQUE nor the ETO_CLIPPED value is specified for the uiFlags member.

pdx

Specifies in an array the width value for each character in the string.

See Also

PolyTextOut


PORT_INFO_1
PORT_INFO_1  QuickInfo

typedef struct _PORT_INFO_1 { // pi1

    LPTSTR pName;

} PORT_INFO_1;

The PORT_INFO_1 structure identifies a supported printer port.

Members

pName

Points to a null-terminated string that identifies a supported printer port (for example, "LPT1:").

See Also

EnumPorts


PORT_INFO_2 [New - Windows 95]
PORT_INFO_2  QuickInfo

[New - Windows 95]

typedef struct _PORT_INFO_2 { // pi2

    LPSTR pPortName;

    LPSTR pMonitorName

    LPSTR pDescription;

    DWORD fPortType;

    DWORD Reserved;

} PORT_INFO_2;

The PORT_INFO_2 structure identifies a supported printer port.

Members

pPortName

Points to a null-terminated string that identifies a supported printer port (for example, "LPT1:").

pMonitorName

Points to a null-terminated string that identifies an installed monitor (for example, "PJL monitor").

pDescription

Points to a null-terminated string that describes the port in more detail (for example, if pPortName is "LPT1:", pDescription is "printer port").

fPortType

Identifies the type of port. Can be one of these values:

PORT_TYPE_WRITE

PORT_TYPE_READ

PORT_TYPE_REDIRECTED

PORT_TYPE_NET_ATTACHED

Reserved

Reserved; must be zero.

Remarks

Use the PORT_INFO_2 structure when calling EnumPorts if there are multiple monitors installed that support the same ports.

See Also

EnumPorts


PREVENT_MEDIA_REMOVAL
PREVENT_MEDIA_REMOVAL  QuickInfo  Overview  Group

typedef struct _PREVENT_MEDIA_REMOVAL{

   BOOLEAN PreventMediaRemoval;

} PREVENT_MEDIA_REMOVAL ;

The PREVENT_MEDIA_REMOVAL structure provides removable media locking data.

Members

PreventMediaRemoval

Specifies whether the media is to be locked (if TRUE) or not (if FALSE).

Remarks

The DeviceIoControl function uses a PREVENT_MEDIA_REMOVAL structure as input to an IOCTL_DISK_MEDIA_REMOVAL device input and output operation.

See Also

DeviceIoControl, IOCTL_DISK_MEDIA_REMOVAL


PRINTDLG
PRINTDLG  QuickInfo

typedef struct tagPD {  // pd

    DWORD     lStructSize;

    HWND      hwndOwner;

    HANDLE    hDevMode;

    HANDLE    hDevNames;

    HDC       hDC;

    DWORD     Flags;

    WORD      nFromPage;

    WORD      nToPage;

    WORD      nMinPage;

    WORD      nMaxPage;

    WORD      nCopies;

    HINSTANCE hInstance;

    DWORD     lCustData;

    LPPRINTHOOKPROC lpfnPrintHook;

    LPSETUPHOOKPROC lpfnSetupHook;

    LPCTSTR    lpPrintTemplateName;

    LPCTSTR    lpSetupTemplateName;

    HANDLE    hPrintTemplate;

    HANDLE    hSetupTemplate;

} PRINTDLG;

The PRINTDLG structure contains information the system uses to initialize the system-defined Print dialog boxes. After the user closes the dialog box, the system returns information about the user-defined print selections in this structure.

Members

lStructSize

Specifies the structure size, in bytes.

hwndOwner

Identifies the window that owns the dialog box. This member can be any valid window handle, or it can be NULL if the dialog box has no owner.

hDevMode

Identifies a movable global memory object that contains a DEVMODE structure. Before a call to the PrintDlg function, the structure members may contain data used to initialize the dialog controls. When PrintDlg returns, the structure members specify the state of the dialog box controls.

If the application uses the structure to initialize the dialog box controls, it must allocate space for and create the DEVMODE structure. (The application should allocate a movable block of memory.)

If the application does not use the structure to initialize the dialog box controls, hDevMode may be NULL. In this case, PrintDlg allocates memory for the structure, initializes its members, and returns a handle that identifies it.

If the device driver for the specified printer does not support extended device modes, hDevMode is NULL when PrintDlg returns.

If the device name (specified by the dmDeviceName member of the DEVMODE structure) does not appear in the [devices] section of WIN.INI, PrintDlg returns an error.

Because this structure is a movable global memory object, the value of hDevMode may change during the execution of PrintDlg.

For a discussion of how the system resolves a possible data collision between values specified by the hDevMode and hDevNames members, see the Remarks section later in this topic.

hDevNames

Identifies a movable global memory object that contains a DEVNAMES structure. This structure contains three strings that specify the driver name, the printer name, and the output port name. Before the call to PrintDlg, the structure members contain strings used to initialize dialog box controls. When PrintDlg returns, the structure members contain the strings typed by the user. The calling application uses these strings to create a device context or an information context.

If the application uses the structure to initialize the dialog box controls, it must allocate space for and create the DEVNAMES structure. (The application should allocate a movable block of global memory.)

If the application does not use the structure to initialize the dialog box controls, hDevNames may be NULL. In this case, PrintDlg allocates memory for the structure, initializes its members (by using the printer name specified in the DEVMODE structure), and returns a handle that identifies it. PrintDlg uses the first port name that appears in the [devices] section of WIN.INI when it initializes the members in the DEVNAMES structure. For example, the function uses "LPT1:" as the port name if the following string appears in the [devices] section:

PCL / HP LaserJet=HPPCL,LPT1:,LPT2:

If both hDevMode and hDevNames are NULL, PrintDlg initializes hDevNames using the current default printer.

Because this structure is a movable global memory object, the value of hDevNames may change during the execution of PrintDlg.

For a discussion of how the system resolves a possible data collision between values specified by hDevNames and hDevMode, see the Remarks section later in this topic.

hDC

Identifies a device context or an information context, depending on whether the Flags member specifies the PD_RETURNDC or PC_RETURNIC flag. If neither flag is specified, the value of this member is undefined. If both flags are specified, PD_RETURNDC has priority.

Flags

Specifies the dialog box initialization flags. This member may be a combination of the following flags:

Flag	Meaning
PD_ALLPAGES
	Indicates that the All radio button was selected when the user closed the dialog box. (This flag is used as a placeholder to indicate that the PD_PAGENUMS and PD_SELECTION flags are not specified. This flag can be set on input and on output.)
PD_COLLATE
	Places a checkmark in the Collate check box when set on input. When the PrintDlg function returns, this value indicates that the user selected the Collate option and the printer driver does not support collation. In this case, the application must provide collation. If PrintDlg sets the PD_COLLATE value on return, the print driver does not support collation and dmCollate in the DEVMODE structure is undefined.
PD_DISABLEPRINTTOFILE
	Disables the Print to File check box.
PD_ENABLEPRINTHOOK
	Enables the hook function specified in lpfnPrintHook.
PD_ENABLEPRINTTEMPLATE
	Causes the system to create the dialog box by using the dialog box template identified by hInstance and lpPrintTemplateName.
PD_ENABLEPRINTTEMPLATEHANDLE
	Indicates that hInstance identifies a data block that contains a preloaded dialog box template. The system ignores lpPrintTemplateName if this flag is specified.
PD_ENABLESETUPHOOK
	Enables the hook function specified in lpfnSetupHook.
PD_ENABLESETUPTEMPLATE
	Causes the operating system to create the dialog box by using the dialog template box identified by hInstance and lpSetupTemplateName.
PD_ENABLESETUPTEMPLATEHANDLE
	Indicates that hInstance identifies a data block that contains a preloaded dialog box template. The system ignores lpSetupTemplateName if this flag is specified.
PD_HIDEPRINTTOFILE
	Hides and disables the Print to File check box.
PD_NOPAGENUMS
	Disables the Pages radio button and the associated edit control.
PD_NOSELECTION
	Disables the Selection radio button.
PD_NOWARNING
	Prevents the warning message from being displayed when there is no default printer.
PD_PAGENUMS
	Causes the Pages radio button to be in the selected state when the dialog box is created. When PrintDlg returns, this flag is specified if the Pages radio button is in the selected state.
PD_PRINTSETUP
	Causes the system to display the Print Setup dialog box rather than the Print dialog box.
PD_PRINTTOFILE
	Causes the Print to File check box to be in the checked state when the dialog box is created. When PrintDlg returns, the pOutput member of the DEVNAMES structure points to the "FILE:" string.
PD_RETURNDC
	Causes PrintDlg to return a device context matching the selections the user made in the dialog box. The device context is returned in hDC.
PD_RETURNDEFAULT
	Causes PrintDlg to return DEVMODE and DEVNAMES structures that are initialized for the system default printer without displaying a dialog box. It is assumed that both hDevNames and hDevMode are NULL; otherwise, the function returns an error. If the system default printer is supported by an old printer driver (earlier than Windows version 3.0), only hDevNames is returned; hDevMode is NULL.
PD_RETURNIC
	Similar to the PD_RETURNDC flag except that this flag returns an information context rather than a device context. If neither PD_RETURNDC nor PD_RETURNIC is specified, hDC is undefined on output.
PD_SELECTION
	Causes the Selection radio button to be in the selected state when the dialog box is created. When PrintDlg returns, this flag is specified if the Selection radio button is in the selected state. If neither PD_PAGENUMS nor PD_SELECTION is specified, the All radio button is in the selected state.
PD_SHOWHELP
	Causes the dialog box to show the Help button. The hwndOwner member must not be NULL if this flag is specified.
PD_USEDEVMODECOPIES
	Same as PD_USEDEVMODECOPIESANDCOLLATE
PD_USEDEVMODECOPIESANDCOLLATE
	Disables the Copies edit control if the printer driver does not support multiple copies, and disables the Collate checkbox if the printer driver does not support collation. If this flag is not specified, PrintDlg stores the user selections for the Copies and Collate options in the dmCopies and dmCollate members of the DEVMODE structure.
	If this flag isn't set, the copies and collate information is returned in the DEVMODE structure if the driver supports multiple copies and collation. If the driver doesn't support multiple copies and collation, the information is returned in the PRINTDLG structure. this means that an application only has to look at nCopies and PD_COLLATE to determine how many copies it needs to render and whether it needs to print them collated.
nFromPage

Specifies the initial value for the starting page edit control. When the PrintDlg function returns, this member specifies the page at which to begin printing. This value is valid only if the PD_PAGENUMS flag is specified.

nToPage

Specifies the initial value for the ending page edit control. When the PrintDlg function returns, this member specifies the last page to print. This value is valid only if the PD_PAGENUMS flag is specified.

nMinPage

Specifies the minimum value for the range of pages specified in the From and To page edit controls.

nMaxPage

Specifies the maximum value for the range of pages specified in the From and To page edit controls.

nCopies

Contains the initial number of copies for the Copies edit control if hDevMode is NULL; otherwise, the dmCopies member of the DEVMODE structure contains the initial value. When PrintDlg returns, this member contains the actual number of copies to print. If the printer driver does not support multiple copies, this value may be greater than one and the application must print all requested copies. If the PD_USEDEVMODECOPIESANDCOLLATE value is set in the Flags member, nCopies is always set to 1 on return and the dmCopies member in the DEVMODE receives the actual number of copies to print.

hInstance

Identifies a data block that contains the preloaded dialog box template specified by lpPrintTemplateName or lpSetupTemplateName. This member is used only if Flags specifies the PD_ENABLEPRINTTEMPLATE or PD_ENABLESETUPTEMPLATE flag; otherwise, this member is ignored.

lCustData

Specifies application-defined data that the operating system passes to the hook function pointed to by lpfnHook. The system passes the data in the lParam parameter of the WM_INITDIALOG message.

lpfnPrintHook

Points to the exported function that hooks dialog messages if the application alters the Print dialog box. This member is ignored unless the Flags member specifies the PD_ENABLEPRINTHOOK flag.

lpfnSetupHook

Points to the exported function that hooks dialog messages if the application alters the Print Setup dialog box. This member is ignored unless the Flags member specifies the PD_ENABLESETUPHOOK flag.

lpPrintTemplateName

Specifies the name of the Print dialog box template identified by hInstance.

lpSetupTemplateName

Specifies the name of the Print Setup dialog box identified by hInstance.

hPrintTemplate

Identifies the global memory object that contains the preloaded dialog box template to be used instead of the default Print Dialog box.

hSetupTemplate

Identifies the global memory object that contains the preloaded dialog box template to be used instead of the default Setup dialog box.

Remarks

There might be data collision between the values specified by hDevNames and hDevMode because the wDeviceOffset member of the DEVNAMES structure is supposed to be identical to the dmDeviceName member of the DEVMODE structure. If it is not, the system resolves the data collision by using the value of wDeviceOffset.

If the user checks the Collate check box in the common Print dialog box, but the printer driver does not support collation, the Flags member of the printdlg structure returned by PrintDlg includes the PD_COLLATE flag. In addition, the dmCollate member of the DEVMODE structure identified by the hDevMode member is set to COLLATE_TRUE. If the PD_COLLATE flag is set, the application must simulate collation.

If the PD_USEDEVMODECOPIESANDCOLLATE flag is set, the Collate check box is grayed out if the printer driver does not support collation. This ensures that the user can only select one copy, and nCopies will be one. If the driver does support multiple copies, dmCopies will contain the number of copies, and nCopies will be one.

On entry to PrintDlg, the nCopies member of the PRINTDLG structure specifies the number of copies if PD_USEDEVMODECOPIESANDCOLLATE is not set. On exit from PrintDlg, nCopies contains the number of copies if the printer driver does not support multiple copies. Otherwise it is set to one. If nCopies is greater than one on exit from PrintDlg, the application must print multiple copies of the document.

See Also

CreateDC, CreateIC, PrintDlg, DEVMODE, DEVNAMES, WM_INITDIALOG


PRINTER_DEFAULTS
PRINTER_DEFAULTS  QuickInfo

typedef struct _PRINTER_DEFAULTS {  // pd

    LPTSTR      pDatatype;

    LPDEVMODE   pDevMode;

    ACCESS_MASK DesiredAccess;

} PRINTER_DEFAULTS;

The PRINTER_DEFAULTS structure specifies the default data type, environment, initialization data, and access rights for a printer.

Members

pDatatype

Points to a null-terminated string that specifies the default data type for a printer.

pDevMode

Points to a DEVMODE structure that identifies the default environment and initialization data for a printer.

DesiredAccess

Specifies desired access rights for a printer. The OpenPrinter function uses this member to set access rights to the printer. These rights can affect the operation of the SetPrinter and DeletePrinter functions.

This member can be set to PRINTER_ACCESS_ADMINISTER, PRINTER_ACCESS_USE, or any generic security value (for example, WRITE_DACL). If an application wishes to open a printer to perform administrative tasks, such as the SetPrinter function, it must open the printer with PRINTER_ACCESS_ADMINISTER access.

See Also

DeletePrinter, DEVMODE, OpenPrinter, SetPrinter


PRINTER_INFO_1
PRINTER_INFO_1  QuickInfo

typedef struct _PRINTER_INFO_1 { // pri1

    DWORD  Flags;

    LPTSTR pDescription;

    LPTSTR pName;

    LPTSTR pComment;

} PRINTER_INFO_1;

The PRINTER_INFO_1 structure specifies general printer information.

Members

Flags

Specifies information about the returned data. Following are the values for this member

Value	Meaning
PRINTER_ENUM_EXPAND	A print provider can set this flag as a hint to a calling application to enumerate this object further if default expansion is enabled. For example, when domains are enumerated, a print provider might indicate the user's domain by setting this flag.
PRINTER_ENUM_CONTAINER	If this flag is set, the printer object may contain enumerable objects. For example, the object may be a print server that contains printers.
PRINTER_ENUM_ICON1	Indicates that, where appropriate, an application should display an icon identifying the object as a top-level network name, such as Microsoft Windows Network.
PRINTER_ENUM_ICON2	Indicates that, where appropriate, an application should display an icon that identifies the object as a network domain.
PRINTER_ENUM_ICON3	Indicates that, where appropriate, an application should display an icon that identifies the object as a print server.
PRINTER_ENUM_ICON4	Reserved for future use.
PRINTER_ENUM_ICON5	Reserved for future use.
PRINTER_ENUM_ICON6	Reserved for future use.
PRINTER_ENUM_ICON7	Reserved for future use.
PRINTER_ENUM_ICON8	Indicates that, where appropriate, an application should display an icon that identifies the object as a printer.
pDescription

Windows NT: Points to a null-terminated string that describes the contents of the structure.

Windows 95: Points to a null-terminated string that describes the printer. The string contains the pPrinterName, pDriverName, and pComment members of the PRINTER_INFO_2 structure concatenated and separated by commas.

pName

Windows NT: Points to a null-terminated string that names the contents of the structure.

Windows 95: Points to a null-terminated string that specifies the name of the printer.

pComment

Windows NT: Points to a null-terminated string that contains additional data describing the structure.

Windows 95: Points to a null-terminated string that provides a brief description of the printer.

See Also

GetPrinter, EnumPrinters, PRINTER_INFO_2, PRINTER_INFO_3, PRINTER_INFO_4


PRINTER_INFO_2
PRINTER_INFO_2  QuickInfo

typedef struct _PRINTER_INFO_2 { // pri2

    LPTSTR    pServerName;

    LPTSTR    pPrinterName;

    LPTSTR    pShareName;

    LPTSTR    pPortName;

    LPTSTR    pDriverName;

    LPTSTR    pComment;

    LPTSTR    pLocation;

    LPDEVMODE pDevMode;

    LPTSTR    pSepFile;

    LPTSTR    pPrintProcessor;

    LPTSTR    pDatatype;

    LPTSTR    pParameters;

    PSECURITY_DESCRIPTOR pSecurityDescriptor;

    DWORD     Attributes;

    DWORD     Priority;

    DWORD     DefaultPriority;

    DWORD     StartTime;

    DWORD     UntilTime;

    DWORD     Status;

    DWORD     cJobs;

    DWORD     AveragePPM;

} PRINTER_INFO_2;

The PRINTER_INFO_2 structure specifies detailed printer information.

Members

pServerName

Points to a null-terminated string identifying the server that controls the printer. If this string is NULL, the printer is controlled locally.

pPrinterName

Points to a null-terminated string that specifies the name of the printer.

pShareName

Points to a null-terminated string that identifies the sharepoint for the printer. (This string is used only if the PRINTER_ATTRIBUTE_SHARED constant was set for the Attributes member.)

pPortName

Points to a null-terminated string that identifies the port(s) used to transmit data to the printer. If a printer is connected to more than one port, the names of each port must be separated by commas (for example, "LPT1:,LPT2:,LPT3:").

pDriverName

Points to a null-terminated string that specifies the name of the printer driver.

pComment

Points to a null-terminated string that provides a brief description of the printer.

pLocation

Points to a null-terminated string that specifies the physical location of the printer (for example, "Bldg. 38, Room 1164").

pDevMode

Points to a DEVMODE structure that defines default printer data such as the paper orientation and the resolution.

pSepFile

Points to a null-terminated string that specifies the name of the file used to create the separator page. This page is used to separate print jobs sent to the printer.

pPrintProcessor

Points to a null-terminated string that specifies the name of the print processor used by the printer.

pDatatype

Points to a null-terminated string that specifies the data type used to record the print job.

pParameters

Points to a null-terminated string that specifies the default print-processor parameters.

pSecurityDescriptor

Points to a SECURITY_DESCRIPTOR structure for the printer. This member may be NULL.

Attributes

Specifies the printer attributes. This member can be one of the following values:

PRINTER_ATTRIBUTE_DEFAULT
PRINTER_ATTRIBUTE_DIRECT
PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST
PRINTER_ATTRIBUTE_ENABLE_BIDI (Windows 95 only)
PRINTER_ATTRIBUTE_ENABLE_DEVQ
PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS
PRINTER_ATTRIBUTE_QUEUED
PRINTER_ATTRIBUTE_SHARED
PRINTER_ATTRIBUTE_WORK_OFFLINE (Windows 95 only)

Priority

Specifies a priority value that the spooler uses to route print jobs.

DefaultPriority

Specifies the default priority value assigned to each print job.

StartTime

Specifies the earliest time at which the printer will print a job. (This value is specified in minutes elapsed since 12:00 A.M.)

UntilTime

Specifies the latest time at which the printer will print a job. (This value is specified in minutes elapsed since 12:00 A.M.)

Status

Specifies the printer status. This member can be one of the following values:

Windows NT:

PRINTER_STATUS_PAUSED
PRINTER_STATUS_PENDING_DELETION

Windows 95:

PRINTER_STATUS_BUSY
PRINTER_STATUS_DOOR_OPEN
PRINTER_STATUS_ERROR
PRINTER_STATUS_INITIALIZING
PRINTER_STATUS_IO_ACTIVE
PRINTER_STATUS_MANUAL_FEED
PRINTER_STATUS_NO_TONER
PRINTER_STATUS_NOT_AVAILABLE
PRINTER_STATUS_OFFLINE
PRINTER_STATUS_OUT_OF_MEMORY
PRINTER_STATUS_OUTPUT_BIN_FULL
PRINTER_STATUS_PAGE_PUNT
PRINTER_STATUS_PAPER_JAM
PRINTER_STATUS_PAPER_OUT
PRINTER_STATUS_PAPER_PROBLEM
PRINTER_STATUS_PAUSED
PRINTER_STATUS_PENDING_DELETION
PRINTER_STATUS_PRINTING
PRINTER_STATUS_PROCESSING
PRINTER_STATUS_TONER_LOW
PRINTER_STATUS_UNAVAILABLE
PRINTER_STATUS_USER_INTERVENTION
PRINTER_STATUS_WAITING
PRINTER_STATUS_WARMING_UP

cJobs

Specifies the number of print jobs that have been queued for the printer.

AveragePPM

Specifies the average number of pages per minute that have been printed on the printer.

Remarks

Windows 95: The PRINTER_STATUS_PAGE_PUNT value specifies that the page is being "punted" (that is, not printed) because it is too complex for the printer to print.

See Also

DEVMODE, EnumPrinters, PRINTER_INFO_1, PRINTER_INFO_3, PRINTER_INFO_4, SECURITY_DESCRIPTOR


PRINTER_INFO_3
PRINTER_INFO_3  QuickInfo

typedef struct _PRINTER_INFO_3 { // pri3

    PSECURITY_DESCRIPTOR pSecurityDescriptor;

} PRINTER_INFO_3;

The PRINTER_INFO_3 structure specifies printer security information.

Members

pSecurityDescriptor

Points to a SECURITY_DESCRIPTOR structure that specifies a printer's security information.

Remarks

The PRINTER_INFO_3 structure lets an application get and set a printer's security descriptor. The caller may do so even if it lacks specific printer permissions, as long as it has the standard rights described in SetPrinter and GetPrinter. Thus, an application may temporarily deny all access to a printer, while allowing the owner of the printer to have access to the printer's discretionary ACL.

See Also

SetPrinter, GetPrinter, PRINTER_INFO_1, PRINTER_INFO_2, PRINTER_INFO_4, SECURITY_DESCRIPTOR


PRINTER_INFO_4
PRINTER_INFO_4  QuickInfo

typedef struct _PRINTER_INFO_4 { // pri4

    LPTSTR  pPrinterName;

    LPTSTR  pServerName;

    DWORD  Attributes;

} PRINTER_INFO_4;

The PRINTER_INFO_4 structure specifies general printer information.

The structure can be used to retrieve minimal printer information on a call to EnumPrinters. Such a call is a fast and easy way to retrieve the names and attributes of all locally installed printers on a system and all remote printer connections that a user has established.

Members

pPrinterName

Points to a null-terminated string that specifies the name of the printer (local or remote).

pServerName

Points to a null-terminated string that is the name of the server.

Attributes

Specifies information about the returned data.

Value	Meaning
PRINTER_ATTRIBUTE_LOCAL	The printer is a local printer.
PRINTER_ATTRIBUTE_NETWORK	The printer is a remote printer.
Remarks

The PRINTER_INFO_4 structure provides an easy and extremely fast way to retrieve the names of the printers installed on a local machine, as well as the remote connections that a user has established. When EnumPrinters is called with a PRINTER_INFO_4 data structure, that function queries the registry for the specified information, then returns immediately. This differs from the behavior of EnumPrinters when called with other levels of PRINTER_INFO_xxx data structures. In particular, when EnumPrinters is called with a level 2 (PRINTER_INFO_2) data structure, it performs an OpenPrinter call on each remote connection. If a remote connection is down, if the remote server no longer exists, or if the remote printer no longer exists, the function must wait for RPC to time out and consequently fail the OpenPrinter call. This can take a while. Passing a PRINTER_INFO_4 structure lets an application retrieve a bare minimium of required information; if more detailed information is desired, a subsequent EnumPrinter level 2 call can be made.

See Also

GetPrinter, EnumPrinters, OpenPrinter, PRINTER_INFO_1, PRINTER_INFO_2, PRINTER_INFO_3


PRINTER_INFO_5 [New - Windows 95]
PRINTER_INFO_5  QuickInfo

[New - Windows 95]

typedef struct _PRINTER_INFO_5 { // pri5

    LPTSTR    pPrinterName;

    LPTSTR    pPortName;

    DWORD     Attributes;

    DWORD     DeviceNotSelectedTimeout;

    DWORD     TransmissionRetryTimeout;

} PRINTER_INFO_5;

The PRINTER_INFO_5 structure specifies detailed printer information.

Members

pPrinterName

Points to a null-terminated string that specifies the name of the printer.

pPortName

Points to a null-terminated string that identifies the port(s) used to transmit data to the printer. If a printer is connected to more than one port, the names of each port must be separated by commas (for example, "LPT1:,LPT2:,LPT3:").

Attributes

Specifies the printer attributes. This member can be one of the following values:

PRINTER_ATTRIBUTE_QUEUED
PRINTER_ATTRIBUTE_DIRECT
PRINTER_ATTRIBUTE_DEFAULT
PRINTER_ATTRIBUTE_SHARED
PRINTER_ATTRIBUTE_WORK_OFFLINE

DeviceNotSelectedTimeout

Specifies the maximum time, in milliseconds, allowed to elapse between attempts to select a device.

TransmissionRetryTimeout

Specifies the maximum time, in milliseconds, allowed to elapse between transmission retries.

See Also

EnumPrinters, GetPrinter, SetPrinter, PRINTER_INFO_1, PRINTER_INFO_2, PRINTER_INFO_3, PRINTER_INFO_4


PRINTER_NOTIFY_INFO
PRINTER_NOTIFY_INFO  QuickInfo  Overview  Group

typedef struct _PRINTER_NOTIFY_INFO {

    DWORD  Version;

    DWORD  Flags;

    DWORD  Count;

    PRINTER_NOTIFY_INFO_DATA  aData[1];

} PRINTER_NOTIFY_INFO;

The PRINTER_NOTIFY_INFO structure contains printer information returned by the FindNextPrinterChangeNotification function. The function returns this information after a wait operation on a printer change notification object has been satisfied.

Members

Version

Specifies the version of this structure. Set this member to 2.

Flags

Contains a bit flag to indicate the state of the notification structure. If the PRINTER_NOTIFY_INFO_DISCARDED bit is set, it indicates that some notifications had to be discarded.

Count

Specifies the number of PRINTER_NOTIFY_INFO_DATA elements in the aData array.

aData

An array of PRINTER_NOTIFY_INFO_DATA structures. Each element of the array identifies a single job or printer information field, and provides the current data for that field.

Remarks

If the Flags member has the PRINTER_NOTIFY_INFO_DISCARDED bit set, this indicates that an overflow or error occured, and notifications may have been lost. In this case, you must call FindNextPrinterChangeNotification and specify the PRINTER_NOTIFY_OPTIONS_REFRESH flag to retrieve all current information. Until you request this refresh operation, the system will not send additional notifications for this change notification object.

See Also

FindNextPrinterChangeNotification, PRINTER_NOTIFY_INFO_DATA


PRINTER_NOTIFY_INFO_DATA
PRINTER_NOTIFY_INFO_DATA  QuickInfo  Overview  Group

typedef struct _PRINTER_NOTIFY_INFO_DATA {

    WORD   Type;

    WORD   Field;

    DWORD  Reserved;

    DWORD  Id;

    union {

        DWORD  adwData[2];

        struct {

            DWORD  cbBuf;

            LPVOID pBuf;

        } Data;

    } NotifyData;

} PRINTER_NOTIFY_INFO_DATA;

The PRINTER_NOTIFY_INFO_DATA structure identifies a job or printer information field and provides the current data for that field.

The FindNextPrinterChangeNotification function returns a PRINTER_NOTIFY_INFO structure, which contains an array of PRINTER_NOTIFY_INFO_DATA structures.

Members

Type

Indicates the type of information provided. This member can be one of the following values:

Value	Meaning
PRINTER_NOTIFY_TYPE	Indicates that the Field member specifies a PRINTER_NOTIFY_FIELD_* constant.
JOB_NOTIFY_TYPE	Indicates that the Field member specifies a JOB_NOTIFY_FIELD_* constant.
Field

Indicates the field that changed. For a list of possible values, see the following Remarks section.

Reserved

Reserved.

Id

Indicates the job identifier if the Type member specifies JOB_NOTIFY_TYPE. If the Type member specfies PRINTER_NOTIFY_TYPE, this member is undefined.

NotifyData

A union of data information based on the Type and Field members. For a description of the type of data associated with each field, see the following Remarks section.

The NotifyData union can be one of the following members:

Member	Meaning
adwData	An array of two DWORD values. For information fields that use only a single DWORD, the data is in adwData[0]
Data	The following members are contained in the Data structure:
Member	Meaning
cbBuf	Indicates the size, in bytes, of the buffer pointed to by pBuf.
pBuf	Points to a buffer that contains the field's current data.
Remarks

If the Type member specifies PRINTER_NOTIFY_TYPE, the Field member can be one of the following values:

Field	Type of data
PRINTER_NOTIFY_FIELD_PRINTER_NAME
	pBuf points to a null-terminated string containing the name of the printer.
PRINTER_NOTIFY_FIELD_SHARE_NAME
	pBuf points to a null-terminated string that identifies the sharepoint for the printer.
PRINTER_NOTIFY_FIELD_DRIVER_NAME
	pBuf points to a null-terminated string containing the name of the printer's driver.
PRINTER_NOTIFY_FIELD_COMMENT
	pBuf points to a null-terminated string containing the new comment string, which is typically a brief description of the printer.
PRINTER_NOTIFY_FIELD_LOCATION
	pBuf points to a null-terminated string containing the new physical location of the printer (for example, "Bldg. 38, Room 1164").
PRINTER_NOTIFY_FIELD_DEVMODE
	pBuf points to a DEVMODE structure that defines default printer data such as the paper orientation and the resolution.
PRINTER_NOTIFY_FIELD_SEPFILE
	pBuf points to a null-terminated string that specifies the name of the file used to create the separator page. This page is used to separate print jobs sent to the printer.
PRINTER_NOTIFY_FIELD_PRINT_PROCESSOR
	pBuf points to a null-terminated string that specifies the name of the print processor used by the printer.
PRINTER_NOTIFY_FIELD_PARAMETERS
	pBuf points to a null-terminated string that specifies the default print-processor parameters.
PRINTER_NOTIFY_FIELD_DATATYPE
	pBuf points to a null-terminated string that specifies the data type used to record the print job.
PRINTER_NOTIFY_FIELD_SECURITY_DESCRIPTOR
	pBuf points to a SECURITY_DESCRIPTOR structure for the printer. The pointer may be NULL if there is no security descriptor.
PRINTER_NOTIFY_FIELD_ATTRIBUTES
	adwData[0] specifies the printer attributes, which can be one of the following values:  PRINTER_ATTRIBUTE_QUEUED PRINTER_ATTRIBUTE_DIRECT PRINTER_ATTRIBUTE_DEFAULT PRINTER_ATTRIBUTE_SHARED
PRINTER_NOTIFY_FIELD_PRIORITY
	adwData[0] specifies a priority value that the spooler uses to route print jobs.
PRINTER_NOTIFY_FIELD_DEFAULT_PRIORITY
	adwData[0] specifies the default priority value assigned to each print job.
PRINTER_NOTIFY_FIELD_START_TIME
	adwData[0] specifies the earliest time at which the printer will print a job. (This value is specified in minutes elapsed since 12:00 A.M.)
PRINTER_NOTIFY_FIELD_UNTIL_TIME
	adwData[0] specifies the latest time at which the printer will print a job. (This value is specified in minutes elapsed since 12:00 A.M.)
PRINTER_NOTIFY_FIELD_STATUS
	adwData[0] specifies the printer status. For a list of possible values, see the PRINTER_INFO_2 structure.
PRINTER_NOTIFY_FIELD_CJOBS
	adwData[0] specifies the number of print jobs that have been queued for the printer.
PRINTER_NOTIFY_FIELD_AVERAGE_PPM
	adwData[0] specifies the average number of pages per minute that have been printed on the printer.

If the Type member specifies JOB_NOTIFY_TYPE, the Field member can be one of the following values:

Field	Type of data
JOB_NOTIFY_FIELD_PRINTER_NAME
	pBuf points to a null-terminated string containing the name of the printer for which the job is spooled.
JOB_NOTIFY_FIELD_MACHINE_NAME
	pBuf points to a null-terminated string that specifies the name of the machine that created the print job.
JOB_NOTIFY_FIELD_PORT_NAME
	pBuf points to a null-terminated string that identifies the port(s) used to transmit data to the printer. If a printer is connected to more than one port, the names of the ports are separated by commas (for example, "LPT1:,LPT2:,LPT3:").
JOB_NOTIFY_FIELD_USER_NAME
	pBuf points to a null-terminated string that specifies the name of the user who sent the print job.
JOB_NOTIFY_FIELD_NOTIFY_NAME
	pBuf points to a null-terminated string that specifies the name of the user who should be notified when the job has been printed or when an error occurs while printing the job.
JOB_NOTIFY_FIELD_DATATYPE
	pBuf points to a null-terminated string that specifies the type of data used to record the print job.
JOB_NOTIFY_FIELD_PRINT_PROCESSOR
	pBuf points to a null-terminated string that specifies the name of the print processor to be used to print the job.
JOB_NOTIFY_FIELD_PARAMETERS
	pBuf points to a null-terminated string that specifies print-processor parameters.
JOB_NOTIFY_FIELD_DRIVER_NAME
	pBuf points to a null-terminated string that specifies the name of the printer driver that should be used to process the print job.
JOB_NOTIFY_FIELD_DEVMODE
	pBuf points to a DEVMODE structure that contains device-initialization and environment data for the printer driver.
JOB_NOTIFY_FIELD_STATUS
	adwData[0] specifies the job status. For a list of possible values, see the JOB_INFO_2 structure.
JOB_NOTIFY_FIELD_STATUS_STRING
	pBuf points to a null-terminated string that specifies the status of the print job.
JOB_NOTIFY_FIELD_DOCUMENT
	pBuf points to a null-terminated string that specifies the name of the print job (for example, "MS-WORD: Review.doc").
JOB_NOTIFY_FIELD_PRIORITY
	adwData[0] specifies the job priority.
JOB_NOTIFY_FIELD_POSITION
	adwData[0] specifies the job's position in the print queue.
JOB_NOTIFY_FIELD_SUBMITTED
	pBuf points to a SYSTEMTIME structure that specifies the time when the job was submitted.
JOB_NOTIFY_FIELD_START_TIME
	adwData[0] specifies the earliest time that the job can be printed. (This value is specified in minutes elapsed since 12:00 A.M.)
JOB_NOTIFY_FIELD_UNTIL_TIME
	adwData[0] specifies the the latest time that the job can be printed. (This value is specified in minutes elapsed since 12:00 A.M.)
JOB_NOTIFY_FIELD_TIME
	adwData[0] specifies the total time, in seconds, that has elapsed since the job began printing.
JOB_NOTIFY_FIELD_TOTAL_PAGES
	adwData[0] specifies the size, in pages, of the job.
JOB_NOTIFY_FIELD_PAGES_PRINTED
	adwData[0] specifies the number of pages that have printed.
JOB_NOTIFY_FIELD_TOTAL_BYTES
	adwData[0] specifies the size, in bytes, of the job.
JOB_NOTIFY_FIELD_BYTES_PRINTED
	adwData[0] specifies the number of bytes that have been printed on this job. For this field, the change notification object is signaled when bytes are sent to the printer.
See Also

DEVMODE, FindNextPrinterChangeNotification, JOB_INFO_2, PRINTER_INFO_2, PRINTER_NOTIFY_INFO, SECURITY_DESCRIPTOR, SYSTEMTIME


PRINTER_NOTIFY_OPTIONS
PRINTER_NOTIFY_OPTIONS  QuickInfo  Overview  Group

typedef struct _PRINTER_NOTIFY_OPTIONS {

    DWORD  Version;

    DWORD  Flags;

    DWORD  Count;

    PPRINTER_NOTIFY_OPTIONS_TYPE  pTypes;

} PRINTER_NOTIFY_OPTIONS;

The PRINTER_NOTIFY_OPTIONS structure specifies options for a change notification object that monitors a printer or print server.

Members

Version

Specifies the version of this structure. Set this member to 2.

Flags

Contains a bit flag. If you set the PRINTER_NOTIFY_OPTIONS_REFRESH flag in a call to the FindNextPrinterChangeNotification function, the function provides current data for all monitored printer information fields. The FindFirstPrinterChangeNotification function ignores the Flags member.

Count

Specifies the number of elements in the pTypes array.

pTypes

Points to an array of PRINTER_NOTIFY_OPTIONS_TYPE structures. Use one element of this array to specify the printer information fields to monitor, and one element to specify the job information fields to monitor. You can monitor either printer information, job information, or both.

Remarks

Use this structure with the FindFirstPrinterChangeNotification function to specify the set of printer or job information fields to monitor for change.

Use this structure with the FindNextPrinterChangeNotification function to request the current data for all monitored printer and job information fields. In this case, the Flags member specifies the PRINTER_NOTIFY_OPTIONS_REFRESH flag, and the function ignores the other structure members.

See Also

FindFirstPrinterChangeNotification, FindNextPrinterChangeNotification, PRINTER_NOTIFY_OPTIONS_TYPE


PRINTER_NOTIFY_OPTIONS_TYPE
PRINTER_NOTIFY_OPTIONS_TYPE  QuickInfo  Overview  Group

typedef struct _PRINTER_NOTIFY_OPTIONS_TYPE {

    WORD   Type;

    WORD   Reserved0;

    DWORD  Reserved1;

    DWORD  Reserved2;

    DWORD  Count;

    PWORD  pFields;

} PRINTER_NOTIFY_OPTIONS_TYPE;

The PRINTER_NOTIFY_OPTIONS_TYPE structure specifies the set of printer or job information fields to be monitored by a printer change notification object.

A call to the FindFirstPrinterChangeNotification function specifies a PRINTER_NOTIFY_OPTIONS structure, which contains an array of PRINTER_NOTIFY_OPTIONS_TYPE structures.

Members

Type

Specifies the type to watch. This member can be one of the following values:

Value	Meaning
PRINTER_NOTIFY_TYPE	Indicates that the fields specified in the pFields array are PRINTER_NOTIFY_FIELD_* constants.
JOB_NOTIFY_TYPE	Indicates that the fields specified in the pFields array are JOB_NOTIFY_FIELD_* constants.
Reserved0

Reserved.

Reserved1

Reserved.

Reserved2

Reserved.

Count

Specifies the number of elements in the pFields array.

pFields

Points to an array of 16-bit values. Each element of the array specifies a job or printer information field of interest. For a list of supported printer and job information fields, see the PRINTER_NOTIFY_INFO_DATA structure.

See Also

FindFirstPrinterChangeNotification, PRINTER_NOTIFY_INFO_DATA, PRINTER_NOTIFY_OPTIONS


PRINTPROCESSOR_INFO_1
PRINTPROCESSOR_INFO_1  QuickInfo

typedef struct _PRINTPROCESSOR_INFO_1 { // ppi1

    LPTSTR pName;

} PRINTPROCESSOR_INFO_1;

The PRINTPROCESSOR_INFO_1 structure specifies the name of an installed print processor.

Members

pName

Points to a null-terminated string that specifies the name of an installed print processor.

See Also

EnumPrintProcessors


PRIVILEGE_SET
PRIVILEGE_SET  QuickInfo

typedef struct _PRIVILEGE_SET { // ps

    DWORD PrivilegeCount;

    DWORD Control;

    LUID_AND_ATTRIBUTES Privilege[ANYSIZE_ARRAY];

} PRIVILEGE_SET;

The PRIVILEGE_SET structure specifies a set of privileges. It is also used to indicate which, if any, privileges are held by a user or group requesting access to an object.

Members

PrivilegeCount

Specifies the number of privileges in the privilege set.

Control

Specifies a control flag related to the privileges. The PRIVILEGE_SET_ALL_NECESSARY control flag is currently defined. It indicates that all of the specified privileges must be held by the process requesting access. If this flag is not set, the presence of any privileges in the user's access token grants the access.

Privilege

Specifies an array of LUID_AND_ATTRIBUTES structures describing the set's privileges. The following attributes are defined for privileges:

Attribute	Description
SE_PRIVILEGE_ENABLED_BY_DEFAULT
	The privilege is enabled by default.
SE_PRIVILEGE_ENABLED
	The privilege is enabled.
SE_PRIVILEGE_USED_FOR_ACCESS
	The privilege was used to gain access to an object or service. This flag is used to identify the relevant privileges in a set passed by a client application that may contain unnecessary privileges.
Remarks

A privilege is used to control access to an object or service more strictly than is typical with discretionary access control. A system manager uses privileges to control which users are able to manipulate system resources. An application uses privileges when it changes a system-wide resource, such as when it changes the system time or shuts down the system.

See Also

PrivilegeCheck, LUID, LUID_AND_ATTRIBUTES


PROCESS_HEAP_ENTRY
PROCESS_HEAP_ENTRY  QuickInfo

typedef struct _PROCESS_HEAP_ENTRY {

    PVOID lpData;

    DWORD cbData;

    BYTE cbOverhead;

    BYTE iRegionIndex;

    WORD wFlags;

    union {

        struct {

            HANDLE hMem;

            DWORD dwReserved[ 3 ];

        } Block;

        struct {

            DWORD dwCommittedSize;

            DWORD dwUnCommittedSize;

            LPVOID lpFirstBlock;

            LPVOID lpLastBlock;

        } Region;

    };

} PROCESS_HEAP_ENTRY;

The PROCESS_HEAP_ENTRY structure contains information about a heap element. The HeapWalk function uses a PROCESS_HEAP_ENTRY structure to enumerate the elements of a heap.

Members

lpData

Points to the data portion of the heap element.

To initiate a HeapWalk heap enumeration, set lpData to NULL.

If the PROCESS_HEAP_REGION bit flag is set in the wFlags member, lpData points to the first virtual address used by the region.

If the PROCESS_HEAP_UNCOMMITTED_RANGE bit flag is set in wFlags, lpData points to the beginning of the range of uncommitted memory.

cbData

Specifies the size, in bytes, of the data portion of the heap element.

If the PROCESS_HEAP_REGION bit flag is set in wFlags, cbData specifies the total size, in bytes, of the address space that is reserved for this region.

If the PROCESS_HEAP_UNCOMMITTED_RANGE bit flag is set in wFlags, cbData specifies the size, in bytes, of the range of uncommitted memory.

cbOverhead

Specifies the size, in bytes, of the data used by the system to maintain information about the heap element. These overhead bytes are in addition to the cbData bytes of the data portion of the heap element.

If the PROCESS_HEAP_REGION bit flag is set in wFlags, cbOverhead specifies the size, in bytes, of the heap control structures that describe the region.

If the PROCESS_HEAP_UNCOMMITTED_RANGE bit flag is set in wFlags, cbOverhead specifies the size, in bytes, of the control structures that describe this uncommitted range.

iRegionIndex

Identifies the heap region that contains the heap element. A heap consists of one or more regions of virtual memory, each with a unique region index.

In the first heap entry returned for most heap regions, HeapWalk sets the PROCESS_HEAP_REGION flag in the wFlags member. When this flag is set, the members of the Region structure contain additional information about the region.

The HeapAlloc function sometimes uses the VirtualAlloc function to allocate large blocks from a growable heap. The heap manager treats such a large block allocation as a separate region with a unique region index. HeapWalk does not set the PROCESS_HEAP_REGION flag in the heap entry returned for a large block region, so the members of the Region structure are not valid. You can use the VirtualQuery function to get additional information about a large block region.

wFlags

A set of bit flags that specify properties of the heap element. Some of these flags affect the meaning of other members of this PROCESS_HEAP_ENTRY data structure. The following bit-flag constants are defined:

Value	Meaning
PROCESS_HEAP_REGION	If this flag is set, the heap element is located at the beginning of a region of contiguous virtual memory in use by the heap.  If this flag is set, the lpData member of the structure points to the first virtual address used by the region; the cbData member specifies the total size, in bytes, of the address space that is reserved for this region; and the cbOverhead member specifies the size, in bytes, of the heap control structures that describe the region. If this flag is set, the Region structure becomes valid. The dwCommittedSize, dwUnCommittedSize, lpFirstBlock, and lpLastBlock members of the structure contain additional information about the region.
PROCESS_HEAP_UNCOMMITTED_RANGE	If this flag is set, the heap element is located in a range of uncommitted memory within the heap region.  If this flag is set, the lpData member points to the beginning of the range of uncommitted memory; the cbData member specifies the size, in bytes, of the range of uncommitted memory; and the cbOverhead member specifies the size, in bytes, of the control structures that describe this uncommitted range.
PROCESS_HEAP_ENTRY_BUSY	If this flag is set, the heap element is an allocated block.  If both this flag and the PROCESS_HEAP_ENTRY_MOVEABLE flag are set, the Block structure becomes valid. The hMem member of the Block structure contains a handle to the allocated, moveable memory block.
PROCESS_HEAP_ENTRY_MOVEABLE	This flag is only valid if the PROCESS_HEAP_ENTRY_BUSY flag is set, indicating that the heap element is an allocated block. If this flag is valid and set, the block was allocated with the LMEM_MOVEABLE or GMEM_MOVEABLE flag, and the Block structure becomes valid. The hMem member of the Block structure contains a handle to the allocated, moveable memory block.
PROCESS_HEAP_ENTRY_DDESHARE	This flag is only valid if the PROCESS_HEAP_ENTRY_BUSY flag is set, indicating that the heap element is an allocated block. If this flag is valid and set, the block was allocated with the GMEM_DDESHARE flag. For a discussion of the GMEM_DDESHARE flag, see GlobalAlloc .
Block

This structure is valid only if both the PROCESS_HEAP_ENTRY_BUSY and PROCESS_HEAP_ENTRY_MOVEABLE flags in wFlags are set.

The members of the Block structure are as follows:

Member	Description
hMem	Contains a handle to the allocated, moveable memory block.
dwReserved	Reserved; not used.
Region

This structure is valid only if the PROCESS_HEAP_REGION flag is set in the wFlags member.

The members of the Region structure are as follows:

Member	Description
dwCommittedSize	Specifies the number of bytes in the heap region that are currently committed as free memory blocks, busy memory blocks, or heap control structures. This is an optional field that is set to zero if the number of committed bytes is not available.
dwUnCommittedSize	Specifies the number of bytes in the heap region that are currently uncommitted. This is an optional field that is set to zero if the number of uncommitted bytes is not available.
lpFirstBlock	Pointer to the first valid memory block in this heap region.
lpLastBlock	Pointer to the first invalid memory block in thisheap region.
See Also

GlobalAlloc, HeapAlloc, HeapWalk, VirtualAlloc, VirtualQuery


PROCESS_INFORMATION
PROCESS_INFORMATION  QuickInfo

typedef struct _PROCESS_INFORMATION { // pi

    HANDLE hProcess;

    HANDLE hThread;

    DWORD dwProcessId;

    DWORD dwThreadId;

} PROCESS_INFORMATION;

The PROCESS_INFORMATION structure is filled in by the CreateProcess function with information about a newly created process and its primary thread.

Members

hProcess

Returns a handle to the newly created process. The handle is used to specify the process in all functions that perform operations on the process object.

hThread

Returns a handle to the primary thread of the newly created process. The handle is used to specify the thread in all functions that perform operations on the thread object.

dwProcessId

Returns a global process identifier that can be used to identify a process. The value is valid from the time the process is created until the time the process is terminated.

dwThreadId

Returns a global thread identifiers that can be used to identify a thread. The value is valid from the time the thread is created until the time the thread is terminated.

See Also

CreateProcess


PROPSHEETHEADER [New - Windows NT]
PROPSHEETHEADER  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct _PROPSHEETHEADER { // psh

    DWORD      dwSize;

    DWORD      dwFlags;

    HWND       hwndParent;

    HINSTANCE  hInstance;

    union {

        HICON  hIcon;

        LPCTSTR pszIcon;

    };

    LPCTSTR     pszCaption;

    UINT       nPages

    union {

        UINT  nStartPage

        LPCTSTR pStartPage;

    };

    union {

        LPCPROPSHEETPAGE    ppsp;

        HPROPSHEETPAGE FAR *phpage;

    };

    PFNPROPSHEETCALLBACK pfnCallback;

} PROPSHEETHEADER, FAR *LPPROPSHEETHEADER;

typedef const PROPSHEETHEADER FAR *LPCPROPSHEETHEADER;

The PROPSHEETHEADER structure defines the frame and pages of a property sheet.

Members

dwSize

Size, in bytes, of this structure.

dwFlags

Array of flags that indicate which other members to use and which to ignore. This member can be a combination of the following values:

Value	Meaning
PSH_DEFAULT	Uses the default meaning for all structure members.
PSH_HASHELP	Displays the property sheet Help button. The Help button is enabled only when the PSP_HASHELP flag is set in the PROPSHEETPAGE structure for the active page.  If any of the initial property sheet pages sets the PSP_HASHELP flag, the Help button is automatically displayed regardless of the PSH_HASHELP flag. However, PSH_HASHELP is useful when none of the initial pages set PSP_HASHELP, but pages added later might.
PSH_MODELESS	Causes the PropertySheet function to create the property sheet as a modeless dialog instead of the default modal behavior. When this flag is set, PropertySheet returns immediately after the dialog is created and the return value from PropertySheet is the window handle of the property sheet dialog.
PSH_MULTILINETABS	Allows multiple rows of tabbed pages.
PSH_NOAPPLYNOW	Removes the Apply Now button.
PSH_PROPSHEETPAGE	Uses ppsp and ignores phpage when creating the pages for the property sheet.
PSH_PROPTITLE	Includes "Properties for" with the string specified by pszCaption in the title bar of the property sheet.
PSH_USECALLBACK	Calls the function specified by pfnCallback when initializing the property sheet defined by this structure.
PSH_USEHICON	Uses hIcon as the small icon in the title bar of the property sheet dialog box.
PSH_USEICONID	Uses pszIcon as the name of the icon resource to load and use as the small icon in the title bar of the property sheet dialog box.
PSH_USEPSTARTPAGE	Uses pStartPage and ignores nStartPage when displaying the initial page of the property sheet.
PSH_WIZARD	Creates a wizard property sheet.
PSH_RTLREADING	Windows 95 only: Displays the title of the property sheet dialog using right-to-left reading order on Hebrew or Arabic systems.
hwndParent

Handle of the owner window.

hInstance

Handle of the instance from which to load the icon or title string resource. If pszIcon or pszCaption identifies a resource to load, this member must be specified.

hIcon

Handle of the icon to use as the small icon in the title bar of the property sheet dialog box. If dwFlags does not include the PSH_USEHICON value, this member is ignored.

pszIcon

Icon resource to use as the small icon in the title bar of the property sheet dialog box. This member can specify either the identifier of the icon resource or the pointer to the string that specifies the name of the icon resource. If dwFlags does not include the PSH_USEICONID value, this member is ignored.

pszCaption

Title of the property sheet dialog box. This member can specify either the identifier of a string resource or the pointer to a string that specifies the title. If dwFlags includes the PSH_PROPTITLE value, the string, "Properties for" is used with the title.

nPages

Number of elements in phpage array.

nStartPage

Zero-based index of the initial page that appears when the property sheet dialog box is created.

pStartPage

Name of the initial page that appears when the property sheet dialog box is created. This member can specify either the identifier of a string resource or the pointer to a string that specifies the name.

ppsp

Pointer to an array of PROPSHEETPAGE structures that define the pages in the property sheet. If dwFlags does not include the PSH_PROPSHEETPAGE value, this member is ignored.

phpage

Pointer to an array that contains handles of property sheet pages. Each handle must have been created by a previous call to the CreatePropertySheetPage function. If dwFlags includes the PSH_PROPSHEETPAGE value, this member is ignored.

pfnCallback

Pointer to an application-defined callback function that is called when the property sheet is initialized. For more information about the callback function, see the description of the PropSheetProc function. If dwFlags does not include the PSP_USECALLBACK value, this member is ignored.

See Also

CreatePropertySheetPage, PropertySheet, PROPSHEETPAGE, PropSheetProc


PROPSHEETPAGE [New - Windows NT]
PROPSHEETPAGE  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct _PROPSHEETPAGE { // psp

    DWORD     dwSize;

    DWORD     dwFlags;

    HINSTANCE hInstance;

    union {

        LPCTSTR        pszTemplate;

        LPCDLGTEMPLATE pResource;

    };

    union {

        HICON  hIcon;

        LPCTSTR pszIcon;

    };

    LPCTSTR pszTitle;

    DLGPROC pfnDlgProc;

    LPARAM  lParam;

    LPFNPSPCALLBACK pfnCallback;

    UINT FAR * pcRefParent;

} PROPSHEETPAGE, FAR *LPPROPSHEETPAGE;

typedef const PROPSHEETPAGE FAR *LPCPROPSHEETPAGE;

The PROPSHEETPAGE structure defines a page in a property sheet.

Members

dwSize

Size, in bytes, of the structure. The size includes any extra application-defined data at the end of the structure.

dwFlags

Array of flags that indicate which other structure members to use and which to ignore. This member can be a combination of the following values:

Value	Meaning
PSP_DEFAULT	Uses the default meaning for all structure members.
PSP_DLGINDIRECT	Uses pResource instead of pszTemplate. That is, the template for the property sheet dialog box is supplied in memory, not loaded from a resource.
PSP_HASHELP	Enables the property sheet Help button when this page is active.
PSP_USECALLBACK	Calls the function specified by pfnCallback when creating or destroying the property sheet page defined by this structure.
PSP_USEHICON	Uses hIcon as the small icon on the tab for the page.
PSP_USEICONID	Uses pszIcon as the name of the icon resource to load and use as the small icon on the tab for the page.
PSP_USEREFPARENT	Maintains the reference count specified by pcRefParent for the lifetime of the property sheet page created from this structure.
PSP_USETITLE	Uses pszTitle as the title of the property sheet dialog box instead of the title stored in the dialog box template.
PSP_RTLREADING	Windows 95 only: When this page is active, displays the text of pszTitle using right-to-left reading order on Hebrew or Arabic systems.
hInstance

Handle to the instance from which to load the dialog box template, icon, or title string resource.

pszTemplate

Dialog box template to use to create the page. This member can specify either the resource identifier of the template or the address of a string that specifies the name of the template. If dwFlags includes the PSP_DLGINDIRECT value, this member is ignored.

pResource

Pointer to a dialog box template in memory. If dwFlags does not include the PSP_DLGINDIRECT value, this member is ignored.

hIcon

Handle to the icon to use as the small icon in the tab for the page. If dwFlags does not include the PSP_USEHICON value, this member is ignored.

pszIcon

Icon resource to use as the small icon in the tab for the page. This member can specify either the identifier of the icon resource or the pointer to the string that specifies the name of the icon resource. If dwFlags does not include the PSP_USEICONID value, this member is ignored.

pszTitle

Title of the property sheet dialog box. This title overrides the title specified in the dialog box template. This member can specify either the identifier of a string resource or the pointer to a string that specifies the title. If dwFlags does not include the PSP_USETITLE value, this member is ignored.

pfnDlgProc

Pointer to the dialog box procedure for the page. The dialog box procedure must not call the EndDialog function.

lParam

Application-defined data.

pfnCallback

Pointer to an application-defined callback function that is called when the page is created and when it is about to be destroyed. For more information about the callback function, see PropSheetPageProc. If dwFlags does not include the PSP_USECALLBACK value, this member is ignored.

pcRefParent

Pointer to the reference count value. If dwFlags does not include the PSP_USERREFPARENT value, this member is ignored.

Remarks

When the PropertySheet function creates the page, the dialog box procedure for the page receives a WM_INITDIALOG message. The lParam parameter of this message points to the PROPSHEETPAGE structure used to create the page.

See Also

EndDialog, PropSheetPageProc, PropertySheet, WM_INITDIALOG


PROTOCOL_INFO
PROTOCOL_INFO  QuickInfo  Overview  Group

typedef  struct _PROTOCOL_INFO {

    DWORD  dwServiceFlags;

    INT  iAddressFamily;

    INT  iMaxSockAddr;

    INT  iMinSockAddr;

    INT  iSocketType;

    INT  iProtocol;

    DWORD  dwMessageSize;

    LPTSTR  lpProtocol;

} PROTOCOL_INFO;

The PROTOCOL_INFO structure contains information about a protocol.

Members

dwServiceFlags

A set of bit flags that specify the services provided by the protocol. One or more of the following bit flags may be set:

Value	Meaning
XP_CONNECTIONLESS	If this flag is set, the protocol providesconnectionless (datagram) service. If this flag is clear, the protocol provides connection-oriented data transfer.
XP_GUARANTEED_DELIVERY	If this flag is set, the protocol guarantees that all data sent will reach the intended destination. If this flag is clear, there is no such guarantee.
XP_GUARANTEED_ORDER	If this flag is set, the protocol guarantees that data will arrive in the order in which it was sent. Note that this characteristic does not guarantee delivery of the data, but guarantees only its order. If this flag is clear, the order of data sent is not guaranteed.
XP_MESSAGE_ORIENTED	If this flag is set, the protocol is message-oriented. A message-oriented protocol honors message boundaries. If this flag is clear, the protocol is stream-oriented, and the concept of message boundaries is irrelevant.
XP_PSEUDO_STREAM	If this flag is set, the protocol is a message-oriented protocol that ignores message boundaries for all receive operations.  This optional capability is useful when you do not want the protocol to frame messages. An application that requires stream-oriented characteristics can open a socket with type SOCK_STREAM for transport protocols that support this functionality, regardless of the value of iSocketType.
XP_GRACEFUL_CLOSE	If this flag is set, the protocol supports two-phase close operations, also known as "graceful" close operations. If this flag is clear, the protocol supports only abortive close operations.
XP_EXPEDITED_DATA	If this flag is set, the protocol supports expedited data, also known as "urgent data."
XP_CONNECT_DATA	If this flag is set, the protocol supports connect data.
XP_DISCONNECT_DATA	If this flag is set, the protocol supports disconnect data.
XP_SUPPORTS_BROADCAST	If this flag is set, the protocol supports a broadcast mechanism.
XP_SUPPORTS_MULTICAST	If this flag is set, the protocol supports a multicast mechanism.
XP_BANDWIDTH_ALLOCATION	If this flag is set, the protocol supports a mechanism for allocating a guaranteed bandwidth to an application.
XP_FRAGMENTATION	If this flag isset, the protocol supports message fragmentation; physical network MTU is hidden from applications.
XP_ENCRYPTS	If this flag is set, the protocol supports data encryption.
iAddressFamily

Specifies the value to pass as the af parameter when you call the socket function to open a socket for the protocol. This address family value uniquely defines the structure of Protocol addresses, also known as SOCKADDRs, used by the protocol.

iMaxSockAddr

Specifies the maximum length of a socket address supported by the protocol.

iMinSockAddr

Specifies the minimum length of a socket address supported by the protocol.

iSocketType

Specifies the value to pass as the type parameter when you call the socket function to open a socket for the protocol.

Note that if XP_PSEUDO_STREAM is set in dwServiceFlags, the application can specify SOCK_STREAM as the type parameter to socket, regardless of the value of iSocketType.

iProtocol

Specifies the value to pass as the protocol parameter when you call the socket function to open a socket for the protocol.

dwMessageSize

Specifies the maximum message size supported by the protocol. This is the maximum size of a message that can be sent from or received by the host. For protocols that do not support message framing, the actual maximum size of a message that can be sent to a given address may be less than this value.

The following special message size values are defined:

Value	Meaning
0	The protocol is stream-oriented; the concept of message size is not relevant.
0xFFFFFFFF	The protocol is message-oriented, but there is no maximum message size.
lpProtocol

Points to a zero-terminated string that supplies a name for the protocol; for example, "SPX2."

See Also

EnumProtocols, socket


PROVIDOR_INFO_1
PROVIDOR_INFO_1  QuickInfo

typedef struct _PROVIDOR_INFO_1 { // pi1

    LPTSTR pName;

    LPTSTR pEnvironment ;

    LPTSTR pDLLName ;

} PROVIDOR_INFO_1;

The PROVIDOR_INFO_1 structure identifies a print provider.

Members

pName

Points to a null-terminated string that is the name of the print provider.

pEnvironment

Points to a null-terminated environment string specifying the environment the provider dynamic-link library (DLL) is designed to run in.

pDLLName

Points to a null-terminated string that is the name of the provider DLL.

See Also

MONITOR_INFO_2


PSHNOTIFY
PSHNOTIFY  QuickInfo

typedef struct _PSHNOTIFY {
    NMHDR hdr;

    LPARAM lParam;

} PSHNOTIFY, FAR *LPPSHNOTIFY;

PSHNOTIFY contains information for the PSN_APPLY and PSN_RESET notification messages.

Members

hdr

Notification header.

lParam

Close flag. TRUE if the OK or Cancel button is used to close the property sheet. FALSE if the Close button used.

See Also

PSN_APPLY, PSN_RESET


PUNCTUATION
PUNCTUATION  QuickInfo  Overview  Group

typedef struct _punctuation {
    UINT   iSize;          // size of table; see below
    LPSTR  szPunctuation;  // punctuation; see below
} PUNCTUATION;

Contains information about the punctuation used in a rich edit control.

Members

iSize

Size in bytes of buffer pointed to by the szPunctuation member.

szPunctuation

Address of the buffer containing the punctuation characters.


QUERY_SERVICE_CONFIG
QUERY_SERVICE_CONFIG  QuickInfo

typedef struct _QUERY_SERVICE_CONFIG { // qsc

    DWORD dwServiceType;

    DWORD dwStartType;

    DWORD dwErrorControl;

    LPTSTR lpBinaryPathName;

    LPTSTR lpLoadOrderGroup;

    DWORD dwTagId;

    LPTSTR lpDependencies;

    LPTSTR lpServiceStartName;

    LPTSTR lpDisplayName;

} QUERY_SERVICE_CONFIG, LPQUERY_SERVICE_CONFIG;

The QUERY_SERVICE_CONFIG structure is used by the QueryServiceConfig function to return configuration information about an installed service.

Members

dwServiceType

The value returned includes one of the following service type flags to indicate the type of service. In addition, for a SERVICE_WIN32 service, the SERVICE_INTERACTIVE_PROCESS flag might be set, indicating that the service process can interact with the desktop.

Value	Meaning
SERVICE_WIN32_OWN_PROCESS	A service type flag that indicates a Win32 service that runs in its own process.
SERVICE_WIN32_SHARE_PROCESS	A service type flag that indicates a Win32 service that shares a process with other services.
SERVICE_KERNEL_DRIVER	A service type flag that indicates a Windows NT device driver.
SERVICE_FILE_SYSTEM_DRIVER	A service type flag that indicates a Windows NT file system driver.
SERVICE_INTERACTIVE_PROCESS	A flag that indicates a Win32 service process that can interact with the desktop.
dwStartType

Specifies when to start the service. One of the following values is specified:

Value	Meaning
SERVICE_BOOT_START	Specifies a device driver started by the operating system loader. This value is valid only if the service type is SERVICE_KERNEL_DRIVER or SERVICE_FILE_SYSTEM_DRIVER.
SERVICE_SYSTEM_START	Specifies a device driver started by the IoInitSystem function. This value is valid only if the service type is SERVICE_KERNEL_DRIVER or SERVICE_FILE_SYSTEM_DRIVER.
SERVICE_AUTO_START	Specifies a device driver or Win32 service started by the service control manager automatically during system startup.
SERVICE_DEMAND_START	Specifies a device driver or Win32 service started by the service control manager when a process calls the StartService function.
SERVICE_DISABLED	Specifies a device driver or Win32 service that can no longer be started.
dwErrorControl

Specifies the severity of the error if this service fails to start during startup, and determines the action taken by the startup program if failure occurs. One of the following values can be specified:

Value	Meaning
SERVICE_ERROR_IGNORE
	The startup (boot) program logs the error but continues the startup operation.
SERVICE_ERROR_NORMAL
	The startup program logs the error and displays a message box pop-up but continues the startup operation.
SERVICE_ERROR_SEVERE
	The startup program logs the error. If the last-known good configuration is being started, the startup operation continues. Otherwise, the system is restarted with the last-known-good configuration.
SERVICE_ERROR_CRITICAL
	The startup program logs the error, if possible. If the last-known good configuration is being started, the startup operation fails. Otherwise, the system is restarted with the last-known good configuration.
lpBinaryPathName

Points to a null-terminated string that contains the fully qualified path to the service binary file.

lpLoadOrderGroup

Points to a null-terminated string that names the load ordering group of which this service is a member. If the pointer is NULL or if it points to an empty string, the service does not belong to a group. The registry has a list of load ordering groups located at:

HKEY_LOCAL_MACHINE\System
\CurrentControlSet\Control\ServiceGroupOrder.

The startup program uses this list to load groups of services in a specified order with respect to the other groups in the list. You can place a service in a group so that another service can depend on the group.

The order in which a service starts is determined by the following criteria:

1.	The order of groups in the registry's load-ordering group list. Services in groups in the load-ordering group list are started first, followed by services in groups not in the load-ordering group list and then services that do not belong to a group.

2.	The service's dependencies listed in the lpszDependencies parameter and the dependencies of other services dependent on the service.

dwTagId

Specifies a unique tag value for this service in the group specified by the lpLoadOrderGroup parameter. A value of zero indicates that the service has not been assigned a tag. You can use a tag for ordering service startup within a load order group by specifying a tag order vector in the registry located at:

HKEY_LOCAL_MACHINE\System\CurrentControlSet
\Control\GroupOrderList

Tags are only evaluated for SERVICE_KERNEL_DRIVER and SERVICE_FILE_SYSTEM_DRIVER type services that have SERVICE_BOOT_START or SERVICE_SYSTEM_START start types.

lpDependencies

Points to an array of null-separated names of services or load ordering groups that must start before this service. The array is doubly null-terminated. If the pointer is NULL or if it points to an empty string, the service has no dependencies. If a group name is specified, it must be prefixed by the SC_GROUP_IDENTIFIER (defined in the WINSVC.H file) character to differentiate it from a service name, because services and service groups share the same name space. Dependency on a service means that this service can only run if the service it depends on is running. Dependency on a group means that this service can run if at least one member of the group is running after an attempt to start all members of the group.

lpServiceStartName

Points to a null-terminated string. If the service type is SERVICE_WIN32_OWN_PROCESS or SERVICE_WIN32_SHARE_PROCESS, this name is the account name in the form of "DomainName\Username", which the service process will be logged on as when it runs. If the account belongs to the built-in domain, ".\Username" can be specified. If NULL is specified, the service will be logged on as the LocalSystem account.

If the service type is SERVICE_KERNEL_DRIVER or SERVICE_FILE_SYSTEM_DRIVER, this name is the Windows NT driver object name (that is, \FileSystem\Rdr or \Driver\Xns) which the input and output (I/O) system uses to load the device driver. If NULL is specified, the driver is run with a default object name created by the I/O system based on the service name.

lpDisplayName

Points to a null-terminated string that is to be used by user interface programs to identify the service. This string has a maximum length of 256 characters. The name is case-preserved in the service control manager. Display name comparisons are always case-insensitive.

Remarks

The configuration information for a service is initially specified when the service is created by a call to the CreateService function. The information can be modified by calling the ChangeServiceConfig function.

See Also

ChangeServiceConfig, CreateService, QueryServiceConfig, StartService


QUERY_SERVICE_LOCK_STATUS
QUERY_SERVICE_LOCK_STATUS  QuickInfo

typedef struct _QUERY_SERVICE_LOCK_STATUS { // qsls

    DWORD fIsLocked;

    LPTSTR lpLockOwner;

    DWORD dwLockDuration;

} QUERY_SERVICE_LOCK_STATUS, * LPQUERY_SERVICE_LOCK_STATUS ;

The QUERY_SERVICE_LOCK_STATUS structure is used by the QueryServiceLockStatus function to return information about the lock status of a service control manager database.

Members

fIsLocked

Specifies whether the database is locked. If this member is nonzero, the database is locked. If it is zero, the database is unlocked.

lpLockOwner

Points to a null-terminated string containing the name of the user who acquired the lock.

dwLockDuration

Specifies the time, in seconds, since the lock was first acquired.

See Also

QueryServiceLockStatus


RASAMB
RASAMB  QuickInfo  Overview  Group

typedef  struct  _RASAMB {

    DWORD    dwSize;

    DWORD    dwError;

    TCHAR    szNetBiosError[ NETBIOS_NAME_LEN + 1 ];

     BYTE     bLana;

} RASAMB;

The RASAMB structure contains the result of a remote access server (RAS) Authentication Message Block (AMB) projection operation.

The RasGetProjectionInfo function returns a RASAMB data structure when its rasprojection parameter has the value RASP_Amb.

Members

dwSize

Specifies the size of the structure, in bytes. Before calling the RasGetProjectionInfo function, set this member to sizeof(RASAMB). The function can then determine the version of the RASAMB data structure that the caller of RasGetProjectionInfo is expecting. This allows backward compatibility for compiled applications if there are future enhancements to the data structure.

dwError

Contains the result of the PPP control protocol negotiation. A value of zero indicates success. A nonzero value indicates failure, and is the actual fatal error that occurred during the control protocol negotiation, the error that prevented the projection from completing successfully.

szNetBiosError

If dwError has the value ERROR_NAME_EXISTS_ON_NET, the szNetBiosError field contains a zero-terminated string that is the NetBIOS name that caused the conflict. For other values of dwError, this field contains the null string.

bLana

Identifies the NetBIOS network adapter identifier, or LANA, on which the remote access connection was established. This member contains the value 0xFF if a connection was not established.

Remarks

The AMB protocol is used with servers that were released before PPP was adopted as the primary framing protocol; for example, Windows NT 3.1 and OS/2 1.3 RAS servers.

See Also

RasGetProjectionInfo, RASPROJECTION


RASCONN
RASCONN  QuickInfo  Overview  Group

typedef struct _RASCONN {

    DWORD     dwSize;

    HRASCONN  hrasconn;

    TCHAR     szEntryName[RAS_MaxEntryName + 1];

#if (WINVER >= 0x400)

    CHAR      szDeviceType[ RAS_MaxDeviceType + 1 ];

    CHAR      szDeviceName[ RAS_MaxDeviceName + 1 ];

#endif

} RASCONN ;

The RASCONN structure provides information about a remote access connection. The RasEnumConnections function returns an array of RASCONN structures.

Members

dwSize

Specifies the size, in bytes, of the RASCONN structure.

hrasconn

Specifies the remote access connection. This handle is used in other remote access API calls.

szEntryName

A string that specifies the phonebook entry used to establish the remote access connection. If the connection was established using an empty entry name, this string consists of a "." followed by the connection phone number.

szDeviceType

A null-terminated string that contains the device type through which the connection is made.

Windows NT: This member is defined only if you build with the WINVER constant defined as 0x400 or greater. By default, the SDK for Windows NT 3.51 defines WINVER as less than 0x400.

szDeviceName

A null-terminated string that contains the device name through which the connection is made.

Windows NT: This member is defined only if you build with the WINVER constant defined as 0x400 or greater.

See Also

RasEnumConnections, RasGetConnectStatus


RASCONNSTATUS
RASCONNSTATUS  QuickInfo  Overview  Group

typedef struct _RASCONNSTATUS {

    DWORD         dwSize;

    RASCONNSTATE  rasconnstate;

    DWORD         dwError;

    TCHAR         szDeviceType[RAS_MaxDeviceType + 1];

    TCHAR         szDeviceName[RAS_MaxDeviceName + 1];

} RASCONNSTATUS;

A RASCONNSTATUS structure describes the current status of a remote access connection. It is returned by the RasGetConnectStatus function.

Members

dwSize

Specifies the structure size, in bytes.

rasconnstate

Specifies a RASCONNSTATE enumerator value that indicates the current state of the RasDial connection process; that is, the piece of the RasDial process that is currently executing.

Two state values are especially significant:

State	Meaning
RASCS_Connected	Indicates that the connection has completed successfully.
RASCS_Disconnected	Indicates that the connection has failed.
dwError

If nonzero, indicates the reason for failure. The value is one of the error values from the RAS header file or one of ERROR_NOT_ENOUGH_MEMORY or ERROR_INVALID_HANDLE.

szDeviceType

A string that specifies the type of the current device, if available. For example, common device types supported by RAS remote access service are "modem",  "pad", "switch", "isdn", or "null".

szDeviceName

A string that specifies the name of the current device, if available. This would be the name of the modem — for example, "Hayes Smartmodem 2400"; the name of the PAD, for example "US Sprint"; or the name of a switch device, for example "Racal-Guardata".

See Also

RasGetConnectStatus, RasDial, RASCONNSTATE


RASDIALEXTENSIONS
RASDIALEXTENSIONS  QuickInfo  Overview  Group

typedef  struct  _RASDIALEXTENSIONS {

    DWORD    dwSize;

    DWORD    dwfOptions;

    HWND    hwndParent;

    DWORD    reserved;

} RASDIALEXTENSIONS;

The RASDIALEXTENSIONS structure contains information about extended features of the RasDial function. You can enable one or more of these extensions by passing a pointer to a RASDIALEXTENSIONS structure when you call RasDial. If you do not pass a pointer to a RASDIALEXTENSIONS structure to RasDial, RasDial uses the default settings that are noted following.

Members

dwSize

Specifies the size of this structure, in bytes. Set this member to sizeof(RASDIALEXTENSIONS). This indicates the version of the structure.

dwfOptions

A set of bit flags that specify RasDial extensions. The following bit flags are defined; you must set all undefined bits to zero:

Value	Description
RDEOPT_UsePrefixSuffix	If this bit flag is one, RasDial uses the prefix and suffix that is in the RAS phonebook. If this bit flag is zero, RasDial ignores the prefix and suffix that is in the RAS phonebook. If no phonebook entry name is specified in the call to RasDial, the actual value of this bit flag is ignored, and it is assumed to be zero.
RDEOPT_PausedStates	If this bit flag is one, RasDial accepts paused states. Examples of paused states are terminal mode, retry logon, change password, and set callback number. If this bit flag is zero, RasDial reports a fatal error if it enters a paused state.
RDEOPT_IgnoreModemSpeaker	If this bit flag is one, RasDial ignores the modem speaker setting that is in the RAS phonebook, and uses the setting specified by the RDEOPT_SetModemSpeaker bit flag. If this bit flag is zero, RasDial uses the modem speaker setting that is in the RAS phonebook, and ignores the setting specified by the RDEOPT_SetModemSpeaker bit flag. If no phonebook entry name is specified in the call to RasDial, the choice is between using a default setting or the setting specified by the RDEOPT_SetModemSpeaker bit flag. The default setting is used if RDEOPT_IgnoreModemSpeaker is zero. The setting specified by RDEOPT_SetModemSpeaker is used if RDEOPT_IgnoreModemSpeaker is one.
RDEOPT_SetModemSpeaker	If this bit flag is one, and RDEOPT_IgnoreModemSpeaker is one, RasDial sets the modem speaker on.  If this bit flag is zero, and RDEOPT_IgnoreModemSpeaker is one, RasDial sets the modem speaker off. If RDEOPT_IgnoreModemSpeaker is zero, RasDial ignores the value of RDEOPT_SetModemSpeaker, and sets the modem speaker based on the RAS phonebook setting or the default setting.
RDEOPT_IgnoreSoftwareCompression	If this bit flag is one, RasDial ignores the software compression setting that is in the RAS phonebook, and uses the setting specified by the RDEOPT_SetSoftwareCompression bit flag. If this bit flag is zero, RasDial uses the software compression setting that is in the RAS phonebook, and ignores the setting specified by the RDEOPT_SetSoftwareCompression bit flag. If no phonebook entry name is specified in the call to RasDial, the choice is between using a default setting or the setting specified by the RDEOPT_SetSoftwareCompression bit flag. The default setting is used if RDEOPT_IgnoreSoftwareCompression is zero. The setting specified by RDEOPT_SetSoftwareCompression is used if RDEOPT_IgnoreSoftwareCompression is one.
RDEOPT_SetSoftwareCompression	If this bit flag is one, and RDEOPT_IgnoreSoftwareCompression is one, RasDial uses software compression.  If this bit flag is zero, and RDEOPT_IgnoreSoftwareCompression is one, RasDial does not use software compression. If RDEOPT_IgnoreSoftwareCompression is zero, RasDial ignores the value of RDEOPT_SetSoftwareCompression, and sets the software compression state based on the RAS phonebook setting or the default setting.
The default value for each of these bit flags is zero.

hwndParent

Handle to a parent window that a security DLL can use for dialog box creation and centering.

Note that this is not the window that receives RasDial progress notifications.

This member is optional; it is not required when no security DLL is defined.

The default value for this member is NULL.

reserved

This member is reserved for future use. It must be set to zero.

See Also

RasDial


RASDIALPARAMS
RASDIALPARAMS  QuickInfo  Overview  Group

typedef struct _RASDIALPARAMS {

   DWORD  dwSize;

   TCHAR  szEntryName[RAS_MaxEntryName + 1];

   TCHAR  szPhoneNumber[RAS_MaxPhoneNumber + 1];

   TCHAR  szCallbackNumber[RAS_MaxCallbackNumber + 1];

   TCHAR  szUserName[UNLEN + 1];

   TCHAR  szPassword[PWLEN + 1];

   TCHAR  szDomain[DNLEN + 1] ;

} RASDIALPARAMS;

The RASDIALPARAMS structure contains parameters used by RasDial to establish a remote access connection.

Members

dwSize

Specifies the structure size, in bytes.

szEntryName

Specifies a string containing the phonebook entry to use to establish the connection. An empty string ("") specifies a simple modem connection on the first available modem port, in which case a non-empty szPhoneNumber must be provided.

szPhoneNumber

Specifies a string containing an overriding phone number. An empty string ("") indicates that the phonebook entry's phone number should be used. If szEntryName is "", szPhoneNumber cannot be "".

szCallbackNumber

Specifies a string containing a callback phone number. An empty string ("") indicates that callback should not be used. This string is ignored unless the user has "Set By Caller" callback permission on the RAS server. An asterisk indicates that the number stored in the phonebook should be used for callback.

szUserName

Specifies a string containing the user's user name. This string is used to authenticate the user's access to the remote access server.

szPassword

Specifies a string containing the user's password. This string is used to authenticate the user's access to the remote access server.

szDomain

Specifies a string containing the domain on which authentication is to occur. An empty string ("") specifies the domain in which the remote access server is a member. An asterisk specifies the domain stored in the phonebook for the entry.

Remarks

The szUserName and szPassword strings are used to authenticate the user's access to the remote access server.

Windows NT

RAS does not actually log the user onto the network. The user does this in the usual manner, for example, by logging on with cached credentials prior to making the connection or by using CTRL+ALT+DEL, after the RAS connection is established.

If both the szUserName and the szPassword members are empty strings (""), RAS uses the user name and password of the currently logged-on user for authentication.

Windows 95

RAS uses the szUserName and szPassword strings to log the user onto the network.

Windows 95 cannot get the password of the currently logged-on user, so if both the szUserName and the szPassword members are empty strings (""), RAS leaves the user name and password empty during authentication.

See Also

RasDial


RASENTRYNAME
RASENTRYNAME  QuickInfo  Overview  Group

typedef struct _RASENTRYNAME {

    DWORD  dwSize;

    TCHAR  szEntryName[RAS_MaxEntryName + 1];

}RASENTRYNAME;

The RASENTRYNAME structure contains an entry name from a remote access phonebook. The RasEnumEntries function returns an array of these structures.

Members

dwSize

Specifies the structure size, in bytes.

szEntryName

Specifies a string containing the name of a remote access phonebook entry.

See Also

RasEnumEntries


RASPPPIP
RASPPPIP  QuickInfo  Overview  Group

typedef  struct  _RASPPPIP {

    DWORD    dwSize;

    DWORD    dwError;

    TCHAR    szIpAddress[ RAS_MaxIpAddress + 1 ];

} RASPPPIP;

The RASPPPIP structure contains the result of a PPP Internet Protocol (IP) projection operation.

The RasGetProjectionInfo function returns a RASPPPIP data structure when its rasprojection parameter has the value RASP_PppIp.

Members

dwSize

Specifies the size of the structure, in bytes. Before calling the RasGetProjectionInfo function, set this member to indicate the version of the RASPPPIP structure that you are using. For information about earlier versions of this structure, see the following Remarks section.

dwError

Contains the result of the PPP control protocol negotiation. A value of zero indicates success. A nonzero value indicates failure, and is the actual fatal error that occurred during the control protocol negotiation, the error that prevented the projection from completing successfully.

szIpAddress

Contains a zero-terminated string that is the client's IP address on the RAS connection. This address string has the form a.b.c.d; for example, "11.101.237.71".

szServerIpAddress

Contains a null-terminated string that is the IP address of the remote PPP peer (that is, the server's IP address). This string is in "a.b.c.d" form. PPP does not require that servers provide this address, but Windows NT servers will consistently return the address anyway. Other PPP vendors may not provide the address. If the address is not available, this member returns an empty string, "".

Remarks

The szServerIpAddress member was added to the RASPPPIP structure beginning with Windows NT 3.51 and the initial release of Windows 95. Beginning with these systems, RasGetProjectionInfo will support both the current form of the structure and the old form without the szServerIpAddress member. Use the dwSize member to indicate which version you are using.

For earlier versions of Windows NT, RasGetProjectionInfo will return ERROR_INVALID_SIZE if dwSize specifies the current structure size. To retrieve PPP IP information from older systems, dwSize must specify the size of the old structure without the szServerIpAddress member.

See Also

RasGetProjectionInfo, RASPROJECTION


RASPPPIPX
RASPPPIPX  QuickInfo  Overview  Group

typedef  struct  _RASPPPIPX {

    DWORD    dwSize;

    DWORD    dwError;

    TCHAR    szIpxAddress[ RAS_MaxIpxAddress + 1 ];

} RASPPPIPX;

The RASPPPIPX structure contains the result of a PPP Internetwork Packet Exchange (IPX) projection operation.

The RasGetProjectionInfo function returns a RASPPPIPX data structure when its rasprojection parameter has the value RASP_PppIpx.

Members

dwSize

Specifies the size of the structure, in bytes. Before calling the RasGetProjectionInfo function, set this member to sizeof(RASPPPIPX). The function can then determine the version of the RASPPPIPX data structure that the caller of RasGetProjectionInfo is expecting. This allows backwards compatibility for compiled applications if there are future enhancements to the data structure.

dwError

Contains the result of the PPP control protocol negotiation. A value of zero indicates success. A nonzero value indicates failure, and is the actual fatal error that occurred during the control protocol negotiation, the error that prevented the projection from completing successfully.

szIpxAddress

Contains a zero-terminated string that is the client's IPX address on the RAS connection. This address string has the form net.node; for example, "1234ABCD.12AB34CD56EF".

See Also

RasGetProjectionInfo, RASPROJECTION


RASPPPNBF
RASPPPNBF  QuickInfo  Overview  Group

typedef  struct  _RASPPPNBF {

    DWORD    dwSize;

    DWORD    dwError;

    DWORD    dwNetBiosError;

    TCHAR    szNetBiosError[ NETBIOS_NAME_LEN + 1 ];

    TCHAR    szWorkstationName[ NETBIOS_NAME_LEN + 1 ];

    BYTE     bLana;

} RASPPPNBF;

The RASPPPNBF structure contains the result of a PPP NetBEUI Framer (NBF) projection operation.

The RasGetProjectionInfo function returns a RASPPPNBF data structure when its rasprojection parameter has the value RASP_PppNbf.

Members

dwSize

Specifies the size of the structure, in bytes. Before calling the RasGetProjectionInfo function, set this member to sizeof(RASPPPNBF). The function can then determine the version of the RASPPPNBF data structure that the caller of RasGetProjectionInfo is expecting. This allows backwards compatibility for compiled applications if there are future enhancements to the data structure.

dwError

Contains the result of the PPP control protocol negotiation. A value of zero indicates success. A nonzero value indicates failure, and is the actual fatal error that occurred during the control protocol negotiation, the error that prevented the projection from completing successfully.

dwNetBiosError

If dwError has the value ERROR_SERVER_NOT_RESPONDING or ERROR_NETBIOS_ERROR, the dwNetBiosError field contains the NetBIOS error that occurred. For other values of dwError, this field contains zero.

szNetBiosError

If dwError has the value ERROR_NAME_EXISTS_ON_NET, the szNetBiosError field contains a zero-terminated string that is the NetBIOS name that caused the conflict. For other values of dwError, this field contains the null string.

szWorkStationName

Contains a zero-terminated string that is the local workstation's computer name. This unique computer name is the closest NetBIOS equivalent to a client's NetBEUI address on a remote access connection.

bLana

Identifies the NetBIOS network adapter identifier, or LANA, on which the remote access connection was established. This member contains the value 0xFF if a connection was not established.

See Also

RasGetProjectionInfo, RASPROJECTION


RASTERIZER_STATUS
RASTERIZER_STATUS  QuickInfo

typedef struct _RASTERIZER_STATUS {    // rs

    short nSize;

    short wFlags;

    short nLanguageID;

} RASTERIZER_STATUS;

The RASTERIZER_STATUS structure contains information about whether TrueType is installed. This structure is filled when an application calls the GetRasterizerCaps function.

Members

nSize

Specifies the size, in bytes, of the RASTERIZER_STATUS structure.

wFlags

Specifies whether at least one TrueType font is installed and whether TrueType is enabled. This value is TT_AVAILABLE, TT_ENABLED, or both if TrueType is on the system.

nLanguageID

Specifies the language in the system's SETUP.INF file.

See Also

GetRasterizerCaps


REASSIGN_BLOCKS
REASSIGN_BLOCKS  QuickInfo  Overview  Group

typedef struct _REASSIGN_BLOCKS {

    WORD   Reserved;

    WORD   Count;

    DWORD BlockNumber[1];

} REASSIGN_BLOCKS ;

The REASSIGN_BLOCKS structure provides disk-block reassignment data. It is a variable-length structure whose last member is an array of block numbers to be reassigned.

Members

Reserved

This member is reserved. Do not use it. Set it to zero.

Count

Specifies the number of blocks to be reassigned. This is the number of elements that are in the BlockNumber member array.

BlockNumber

An array of Count block numbers, one for each block to be reassigned.

Remarks

The DeviceIoControl function uses a REASSIGN_BLOCKS structure as input to an IOCTL_DISK_REASSIGN_BLOCKS device input and output control operation.

See Also

DeviceIoControl, IOCTL_DISK_REASSIGN_BLOCKS


RECT
RECT  QuickInfo

typedef struct _RECT {    // rc

    LONG left;

    LONG top;

    LONG right;

    LONG bottom;

} RECT;

The RECT structure defines the coordinates of the upper-left and lower-right corners of a rectangle.

Members

left

Specifies the x-coordinate of the upper-left corner of the rectangle.

top

Specifies the y-coordinate of the upper-left corner of the rectangle.

right

Specifies the x-coordinate of the lower-right corner of the rectangle.

bottom

Specifies the y-coordinate of the lower-right corner of the rectangle.

Remarks

When RECT is passed to the FillRect function, the rectangle is filled up to, but not including, the right column and bottom row of pixels. This structure is identical to the RECTL structure.

See Also

FillRect, RECTL, SMALL_RECT


RECTL
RECTL  QuickInfo

typedef struct _RECTL { // rcl

    LONG left;

    LONG top;

    LONG right;

    LONG bottom;

} RECTL;

The RECTL structure defines the coordinates of the upper-left and lower-right corners of a rectangle.

Members

left

Specifies the x-coordinate of the upper-left corner of the rectangle.

top

Specifies the y-coordinate of the upper-left corner of the rectangle.

right

Specifies the x-coordinate of the lower-right corner of the rectangle.

bottom

Specifies the y-coordinate of the lower-right corner of the rectangle.

Remarks

When RECTL is passed to the FillRect function, the rectangle is filled up to, but not including, the right column and bottom row of pixels. This structure is identical to the RECT structure.

See Also

FillRect, RECT, SMALL_RECT


REGISTERWORD
REGISTERWORD  QuickInfo

typedef struct tagREGISTERWORD {

    LPTSTR  lpReading;

    LPTSTR  lpWord;

} REGISTERWORD;

The REGISTERWORD structure contains reading information or a word to register. You can pass this structure to the ImmConfigureIME function to have the information or word appear as an initial value in the configuration dialog box of the input method editor.

Members

lpReading

Pointer to the reading information for the word to register. If the reading information is not needed, it can be NULL.

lpWord

Pointer to the word to register. If a word is not needed, it can be NULL.

See Also

ImmConfigureIME


REMOTE_NAME_INFO
REMOTE_NAME_INFO  QuickInfo

typedef struct _REMOTE_NAME_INFO { /* rni */

    LPTSTR  lpUniversalName;

    LPTSTR  lpConnectionName;

    LPTSTR  lpRemainingPath;

} REMOTE_NAME_INFO;

The REMOTE_NAME_INFO data structure contains path and name information about a network resource. The structure contains a member that points to a Universal Naming Convention (UNC) name string for the resource, and two members that point to additional network connection information strings.

Members

lpUniversalName

Points to a zero-terminated UNC name string.

lpConnectionName

Points to a zero-terminated string that is the name of a network connection.

lpRemainingPath

Points to a zero-terminated UNC name string.

Remarks

The REMOTE_NAME_INFO data structure contains a pointer to a Universal Naming Convention (UNC) name string. UNC names look like this:

\\servername\sharename\path\file

You can pass the REMOTE_NAME_INFO structure's lpConnectionName member to the WNetAddConnection2 function as the lpRemoteName member of the NETRESOURCE structure pointed to by lpNetResource. This lets you connect a local device to a network resource. You can then append the string pointed to by the lpRemainingPath member to the local device string, and pass the resulting string to Win32 functions that use a drive-based path.

See Also

WNetAddConnection2, UNIVERSAL_NAME_INFO


REOBJECT
REOBJECT  QuickInfo  Overview  Group

typedef struct _reobject {
    DWORD  cbStruct;           // size of structure in bytes
    LONG   cp;                 // character position of object
    CLSID  clsid;              // class ID of object
    LPOLEOBJECT      poleobj;  // OLE object interface
    LPSTORAGE        pstg;     // associated storage interface
    LPOLECLIENTSITE  polesite; // associated client site interface
    SIZEL  sizel;              // size of object (may be 0,0)
    DWORD  dvaspect;           // display aspect to use
    DWORD  dwFlags;            // object status flags
    DWORD  dwUser;             // user-defined value
} REOBJECT;

The REOBJECT structure contains information about an object.

Members

cbStruct

Size, in bytes, of this structure.

cp

Character position of the object.

clsid

Class identifier of the object.

poleobj

Points to an instance of the IOleObject interface for the object.

pstg

Points to an instance of the IStorage interface. This is the storage object associated with the object.

polesite

Points to an instance of the IOleClientSite interface. This is the object's client site in the rich edit control. This address must have been obtained from the IRichEditOle::GetClientSite method.

sizel

SIZEL structure specifying the size of the object. A 0,0 on insert indicates that an object is free to determine its size until the modify flag is turned off.

dvAspect

Display aspect to use.

dwFlags

Object status flags. Can be a combination of the following values:

Value	Meaning
REO_BELOWBASELINE	Object sits below the baseline of the surrounding text; the default is to sit on the baseline.
REO_DONTUSEPALETTE	Prevents creation and realization of a half-tone palette before rendering the object. Applies to 32-bit platforms only.
REO_DYNAMICSIZE	Object always determines its extents and may change despite the modify flag being turned off.
REO_GETMETAFILE	The rich edit control retrieved the metafile from the object to correctly determine the object's extents. This flag can be read but not set.
REO_HILITED	Object is currently highlighted to indicate selection. Occurs when focus is in the control and REO_SELECTED is set. This flag can be read but not set.
REO_INPLACEACTIVE	Object is currently in place active. This flag can be read but not set.
REO_INVERTEDSELECT	Object is to be drawn entirely inverted when selected; the default is to be drawn with a border.
REO_LINK	Object is a link. This flag can be read but not set.
REO_LINKAVAILABLE	Object is a link and is believed to be available. This flag can be read but not set.
REO_OPEN	Object is currently open in its server. This flag can be read but not set.
REO_RESIZABLE	Object may be resized.
REO_SELECTED	Object is currently selected in the rich edit control. This flag can be read but not set.
REO_STATIC	Object is a static object. This flag can be read but not set.
dwUser

Reserved for user-defined values.

See Also

IOleClientSite, IOleObject, IRichEditOle::GetClientSite, IStorage


REPASTESPECIAL
REPASTESPECIAL  QuickInfo  Overview  Group

typedef struct _repastespecial {
    DWORD  dwAspect;  // display aspect for object
    DWORD  dwParam;   // aspect data
} REPASTESPECIAL;

Contains information identifying whether the display aspect of a pasted object should be based on the content of the object or the icon that represent the object.

Members

dwAspect

Display aspect. Can be DVASPECT_CONTENT if the aspect of the pasted object is based on the content of the object, or DVASPECT_ICON if the aspect is based on the icon view of the object.

dwParam

Aspect data. If dwAspect is DVASPECT_ICON, this member contains the handle to the metafile with the icon view of the object.


REQRESIZE [New - Windows NT]
REQRESIZE  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct _reqresize {

    NMHDR nmhdr;

    RECT rc;

} REQRESIZE;

The REQRESIZE structure contains the requested size of a rich edit control. A rich edit control sends this structure to its parent window as part of an EN_REQUESTRESIZE notification message.

Members

nmhdr

Notification header.

rc

Requested new size.

See Also

EN_REQUESTRESIZE


RGBQUAD
RGBQUAD  QuickInfo

typedef struct tagRGBQUAD { // rgbq

    BYTE    rgbBlue;

    BYTE    rgbGreen;

    BYTE    rgbRed;

    BYTE    rgbReserved;

} RGBQUAD;

The RGBQUAD structure describes a color consisting of relative intensities of red, green, and blue.

Members

rgbBlue

Specifies the intensity of blue in the color.

rgbGreen

Specifies the intensity of green in the color.

rgbRed

Specifies the intensity of red in the color.

rgbReserved

Reserved; must be zero.

Remarks

The bmiColors member of the BITMAPINFO structure consists of an array of RGBQUAD structures.

See Also

BITMAPINFO, CreateDIBitmap, CreateDIBSection, GetDIBits, SetDIBits, SetDIBitsToDevice, StretchDIBits


RGBTRIPLE
RGBTRIPLE  QuickInfo

typedef struct tagRGBTRIPLE { // rgbt

    BYTE rgbtBlue;

    BYTE rgbtGreen;

    BYTE rgbtRed;

} RGBTRIPLE;

The RGBTRIPLE structure describes a color consisting of relative intensities of red, green, and blue. The bmciColors member of the BITMAPCOREINFO structure consists of an array of RGBTRIPLE structures.

Members

rgbtBlue

Specifies the intensity of blue in the color.

rgbtGreen

Specifies the intensity of green in the color.

rgbtRed

Specifies the intensity of red in the color.

See Also

BITMAPCOREINFO


RGNDATA
RGNDATA  QuickInfo

typedef struct _RGNDATA { // rgnd

    RGNDATAHEADER rdh;

    char          Buffer[1];

} RGNDATA;

The RGNDATA structure contains a header and an array of rectangles that compose a region. The rectangles are sorted top to bottom, left to right. They do not overlap.

Members

rdh

Specifies a RGNDATAHEADER structure. The members of this structure specify the type of region (whether it is rectangular or trapezoidal), the number of rectangles that make up the region, the size of the buffer that contains the rectangle structures, and so on.

Buffer

Specifies an arbitrary-size buffer that contains the RECT structures that make up the region.

See Also

RECT, RGNDATAHEADER


RGNDATAHEADER
RGNDATAHEADER  QuickInfo

typedef struct _RGNDATAHEADER { // rgndh

    DWORD dwSize;

    DWORD iType;

    DWORD nCount;

    DWORD nRgnSize;

    RECT  rcBound;

} RGNDATAHEADER;

The RGNDATAHEADER structure describes the data returned by the GetRegionData function.

Members

dwSize

Specifies the size, in bytes, of the header.

iType

Specifies the type of region. This value must be RDH_RECTANGLES.

nCount

Specifies the number of rectangles that make up the region.

nRgnSize

Specifies the size of the buffer required to receive the RECT structure that specifies the coordinates of the rectangles that make up the region. If the size is not known, this member can be zero.

rcBound

Specifies a bounding rectangle for the region.

See Also

GetRegionData, RECT, RGNDATA


RIP_INFO
RIP_INFO  QuickInfo

typedef struct _RIP_INFO { /* ri */

    DWORD  dwError;

    DWORD  dwType;

} RIP_INFO;

The RIP_INFO structure contains the error and address, format, and length, in bytes, of a debugging string.

dwError

Specifies the error that caused the RIP debug event. For more information about exception handling, see Errors.

dwType

Specifies additional information about the type of error that caused the RIP debug event. This may be one of the following values:

Value	Meaning
SLE_ERROR	Indicates that invalid data was passed to the function that failed. This caused the application to fail.
SLE_MINORERROR	Indicates that invalid data was passed to the function, but the error probably will not cause the application to fail.
SLE_WARNING	Indicates that potentially invalid data was passed to the function, but the function completed processing.
0	Indicates that only dwError was set.
See Also

DEBUG_EVENT


SCROLLINFO
SCROLLINFO  QuickInfo

typedef struct tagSCROLLINFO {  // si

    UINT cbSize;

    UINT fMask;

    int  nMin;

    int  nMax;

    UINT nPage;

    int  nPos;

    int  nTrackPos;

}   SCROLLINFO;

typedef SCROLLINFO FAR *LPSCROLLINFO;

The SCROLLINFO structure contains scroll bar parameters to be set by the SetScrollInfo function (or SBM_SETSCROLLINFO message), or retrieved by the GetScrollInfo function (or SBM_GETSCROLLINFO message).

cbSize

Specifies the size, in bytes, of this structure.

fMask

Specifies the scroll bar parameters to set or retrieve. This member can be a combination of the following values:

Value	Meaning
SIF_ALL	Combination of SIF_PAGE, SIF_POS, and SIF_RANGE.
SIF_DISABLENOSCROLL	This value is used only when setting a scroll bar's parameters. If the scroll bar's new parameters make the scroll bar unnecessary, disable the scroll bar instead of removing it.
SIF_PAGE	The nPage member contains the page size for a proportional scroll bar.
SIF_POS	The nPos parameter contains the scroll box position.
SIF_RANGE	The nMin and nMax members contain the minimum and maximum values for the scrolling range.
nMin

Specifies the minimum scrolling position.

nMax

Specifies the maximum scrolling position.

nPage

Specifies the page size. A scroll bar uses this value to determine the appropriate size of the proportional scroll box.

nPos

Specifies the position of the scroll box.

nTrackPos

Specifies the immediate position of a scroll box that the user is dragging. An application can retrieve this value while processing the SB_THUMBTRACK notification message. An application cannot set the immediate scroll position; the SetScrollInfo function ignores this member.

See Also

SBM_GETSCROLLINFO, SBM_SETSCROLLINFO, GetScrollInfo, SetScrollInfo


SECURITY_ATTRIBUTES
SECURITY_ATTRIBUTES  QuickInfo

typedef struct _SECURITY_ATTRIBUTES { // sa

    DWORD  nLength;

    LPVOID lpSecurityDescriptor;

    BOOL   bInheritHandle;

} SECURITY_ATTRIBUTES;

The SECURITY_ATTRIBUTES structure contains the security descriptor for an object and specifies whether the handle retrieved by specifying this structure is inheritable.

Members

nLength

Specifies the length, in bytes, of this structure. This value is to be set to the size of the SECURITY_ATTRIBUTES structure.

lpSecurityDescriptor

Points to a security descriptor for the object that controls the sharing of it. If NULL is specified for this member, the object may be assigned the default security descriptor of the calling process.

bInheritHandle

Specifies whether the returned handle is inherited when a new process is created. If this member is TRUE, the new process inherits the handle.

Remarks

A pointer to a SECURITY_ATTRIBUTES structure is used as a parameter in most kernel and window-management functions in the Win32 API that return a handle of an object.

See Also

SECURITY_DESCRIPTOR


SECURITY_DESCRIPTOR
SECURITY_DESCRIPTOR  QuickInfo

typedef PVOID PSECURITY_DESCRIPTOR;

The SECURITY_DESCRIPTOR structure contains the security information associated with an object. Applications use this structure to set and query an object's security status.

Applications are not to modify the SECURITY_DESCRIPTOR structure directly. For creating and manipulating a security descriptor, use the functions listed in the See Also section.

Remarks

A security descriptor includes information that specifies the following components of an object's security:

•	An owner (SID)

•	A primary group (SID)

•	A discretionary ACL

•	A system ACL

•	Qualifiers for the preceding items

Security descriptors use access-control lists (ACLs) and security identifiers (SIDs) to specify the information in this list.

A security descriptor can be in absolute or self-relative form. In self-relative form, all members of the structure are located contiguously in memory. In absolute form, the structure only contains pointers to the members.

See Also

GetSecurityDescriptorControl, GetSecurityDescriptorDacl, GetSecurityDescriptorGroup, GetSecurityDescriptorLength, GetSecurityDescriptorOwner, GetSecurityDescriptorSacl, InitializeSecurityDescriptor, IsValidSecurityDescriptor, SetSecurityDescriptorDacl, SetSecurityDescriptorGroup, SetSecurityDescriptorOwner, SetSecurityDescriptorSacl


SECURITY_DESCRIPTOR_CONTROL
SECURITY_DESCRIPTOR_CONTROL  QuickInfo

typedef WORD SECURITY_DESCRIPTOR_CONTROL;

The SECURITY_DESCRIPTOR_CONTROL structure contains a set of bit flags that qualify the meaning of a security descriptor or its individual members.

Each security descriptor has an associated SECURITY_DESCRIPTOR_CONTROL structure. Applications can use the Win32 API functions to set and retrieve a security descriptor's SECURITY_DESCRIPTOR_CONTROL values. These functions are listed in the See Also section.

The following constants are defined for setting and retrieving SECURITY_DESCRIPTOR_CONTROL bit flags:

Value	Meaning
SE_OWNER_DEFAULTED	Instead of the original provider of the security descriptor, a default mechanism provided the security descriptor's owner security identifier (SID). This can affect the treatment of the SID with respect to inheritance of an owner. This flag is ignored if the owner member is NULL. The SetSecurityDescriptorOwner function sets this flag.
SE_GROUP_DEFAULTED	Instead of the the original provider of the security descriptor, a default mechanism provided the security descriptor's group SID. This can affect the treatment of the SID with respect to inheritance of a primary group. This flag is ignored if the group member is NULL. The SetSecurityDescriptorGroup function sets this flag.
SE_DACL_PRESENT	The security descriptor contains a discretionary access-control list (ACL). If this flag is set and the discretionary ACL is NULL, an empty ACL is being explicitly specified. An empty ACL has a size but no access-control entries (ACEs). A NULL ACL has no pointer to an ACL. This flag allows functions to determine whether a security descriptor points to a NULL ACL or no ACL at all. The SetSecurityDescriptorDacl function sets this flag.
SE_DACL_DEFAULTED	Instead of the the original provider of the security descriptor, a default mechanism provided the discretionary ACL. This can affect the treatment of the ACL with respect to inheritance of an ACL. If the SE_DACL_PRESENT flag is not set, this flag is ignored. The SetSecurityDescriptorDacl function sets this flag.
SE_SACL_PRESENT	The security descriptor contains a system ACL. If this flag is set and the Sacl member is NULL, an empty ACL is being explicitly specified. This flag allows functions to determine whether a security descriptor points to a NULL ACL or no ACL at all. The SetSecurityDescriptorSacl function sets this flag.
SE_SACL_DEFAULTED	Instead of the the original provider of the security descriptor, a default mechanism provided the ACL. This can affect the treatment of the ACL with respect to inheritance of an ACL. If the SE_SACL_PRESENT flag is not set, this flag is ignored. The SetSecurityDescriptorSacl function sets this flag.
SE_SELF_RELATIVE	The security descriptor is in self-relative form and all members of the security descriptor are contiguous in memory. All pointer members are expressed as offsets from the beginning of the security descriptor. This form is useful for treating security descriptors as opaque structures for transmission in a communications protocol or for storage on secondary media.
See Also

GetSecurityDescriptorControl, GetSecurityDescriptorDacl, GetSecurityDescriptorGroup, GetSecurityDescriptorOwner, GetSecurityDescriptorSacl, SetSecurityDescriptorDacl, SetSecurityDescriptorGroup, SetSecurityDescriptorOwner, SetSecurityDescriptorSacl


SECURITY_INFORMATION
SECURITY_INFORMATION  QuickInfo

typedef DWORD SECURITY_INFORMATION;

The SECURITY_INFORMATION structure identifies the object-related security information being set or queried. This security information includes:

•	The owner of an object

•	The primary group of an object

•	The discretionary access-control list (ACL) of an object

•	The system ACL of an object

Each item of security information is designated by a bit flag. The following values specify the bits:

Value	Meaning
OWNER_SECURITY_INFORMATION	Indicates the owner identifier of the object is being referenced.
GROUP_SECURITY_INFORMATION	Indicates the primary group identifier of the object is being referenced.
DACL_SECURITY_INFORMATION	Indicates the discretionary ACL of the object is being referenced.
SACL_SECURITY_INFORMATION	Indicates the system ACL of the object is being referenced.
See Also

GetFileSecurity, GetKernelObjectSecurity, GetPrivateObjectSecurity, GetUserObjectSecurity, SetFileSecurity, SetKernelObjectSecurity, SetPrivateObjectSecurity, SetUserObjectSecurity


SECURITY_QUALITY_OF_SERVICE
SECURITY_QUALITY_OF_SERVICE  QuickInfo

typedef struct _SECURITY_QUALITY_OF_SERVICE { // sqos

    DWORD Length;

    SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;

    SECURITY_CONTEXT_TRACKING_MODE ContextTrackingMode;

    BOOLEAN EffectiveOnly;

} SECURITY_QUALITY_OF_SERVICE;

The SECURITY_QUALITY_OF_SERVICE data structure contains information used to support client impersonation. A client can specify this information when it connects to a server; the information determines whether or not the server may impersonate the client, and if so, to what extent.

Members

Length

Specifies the size, in bytes, of this structure.

ImpersonationLevel

Specifies what the server may be told about the client, and how the server may represent, or impersonate, the client. Security impersonation levels govern the degree to which a server process can act on behalf of a client process. This member is a SECURITY_IMPERSONATION_LEVEL enumeration type value.

ContextTracking Mode

Specifies whether the server is to be given a snapshot of the client's security context (called static tracking), or is to be continually updated to track changes to the client's security context (called dynamic tracking). The value SECURITY_STATIC_TRACKING specifies static tracking, and the value SECURITY_DYNAMIC_TRACKING specifies dynamic tracking. Not all communications mechanisms support dynamic tracking; those that do not will default to static tracking.

Effective Only

Specifies whether or not the server may enable or disable privileges and groups that the client's security context may include.

See Also

SECURITY_IMPERSONATION_LEVEL


SELCHANGE [New - Windows NT]
SELCHANGE  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct _selchange {

    NMHDR nmhdr;

    CHARRANGE chrg;

    WORD seltyp;

} SELCHANGE;

The SELCHANGE stucture contains information associated with an EN_SELCHANGE notification message. A rich edit control sends this notification to its parent window when the current selection changes.

Members

nmhdr

Notification header.

chrg

New selection range.

seltyp

Value specifying the contents of the new selection. This member is SEL_EMPTY if the selection is empty or one or more of the following values:

Value	Contents of the selection
SEL_TEXT	Text
SEL_OBJECT	At least one OLE object
SEL_MULTICHAR	More than one character of text
SEL_MULTIOBJECT	More than one OLE object
See Also

EN_SELCHANGE


SERIALKEYS [New - Windows NT]
SERIALKEYS  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct tagSERIALKEYS {     // sk

    DWORD cbSize;

    DWORD dwFlags;

    LPSTR lpszActivePort;

    LPSTR lpszPort;

    DWORD iBaudRate;

    DWORD iPortState;

} SERIALKEYS, FAR* LPSERIALKEYS;

The SERIALKEYS structure contains information about the SerialKeys accessibility feature, which interprets data from a communication aid attached to a serial port as commands causing the system to simulate keyboard and mouse input.

Members

cbSize

Specifies the structure size, in bytes.

dwFlags

Specifies a combination of the following values:

Value	Meaning
SERKF_ACTIVE	The SerialKeys feature is currently receiving input on the serial port specified by lpszPort.
SERKF_AVAILABLE	The SerialKeys feature is available.
SERKF_INDICATOR	A visual indicator is displayed when the SerialKeys feature is on. This value is not currently used and is ignored.
SERKF_SERIALKEYSON	The SerialKeys feature is on.
lpszActivePort

Points to a string that contains the name of the serial port that receives input from the communication aid when the SerialKeys feature is on. If no port is being used, this member is NULL. If this member is "Auto", the system watches all unused serial ports for input from communication aids.

lpszPort

Reserved; must be NULL.

iBaudRate

Specifies the baud rate setting for the serial port specified by the lpszActivePort member. This member should be set to one of the CBR_ values defined in the Windows header files. If lpszActivePort is NULL, this member is zero.

iPortState

Specifies the state of the port specified by the lpszActivePort member. If lpszActivePort is NULL, iPortState is zero; otherwise, it is one of the following values:

Value	Meaning
0	All input on this port is ignored by the SerialKeys feature.
1	Input on this port is watched for SerialKeys activation sequences when no other application has the port open.
2	All input on this port is treated as SerialKeys commands.
Remarks

An application uses this structure when calling the SystemParametersInfo function with the SPI_GETSERIALKEYS or SPI_SETSERIALKEYS value. When using SPI_GETSERIALKEYS, an application must specify the cbSize, lpszActivePort, and lpszPort members of the SERIALKEYS structure; the SystemParametersInfo function fills the remaining members. An application must specify all structure members when using the SPI_SETSERIALKEYS value.

See Also

SystemParametersInfo


SERVICE_ADDRESS [New - Windows NT]
SERVICE_ADDRESS  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct _SERVICE_ADDRESS {

    DWORD   dwAddressType;

    DWORD   dwAddressFlags;

    DWORD   dwAddressLength;

    DWORD   dwPrincipalLength;

    BYTE   *lpAddress;

    BYTE   *lpPrincipal;

} SERVICE_ADDRESS;

The SERVICE_ADDRESS structure contains address information for a service. The structure can accomodate many types of interprocess communications (IPC) mechanisms and their address forms, including remote procedure calls (RPCs), named pipes, and sockets.

Members

dwAddressType

Specifies the address family that the socket address pointed to by lpAddress belongs to.

dwAddressFlags

A set of bit flags that specify properties of the address. The following bit flags are defined:

Value	Meaning
SERVICE_ADDRESS_FLAG_RPC_CN	If this bit flag is set, the service supports connection-oriented RPC over this transport protocol.
SERVICE_ADDRESS_FLAG_RPC_DG	If this bit flag is set, the service supports datagram-oriented RPC over this transport protocol.
SERVICE_ADDRESS_FLAG_RPC_NB	If this bit flag is set, the service supports NetBIOS RPC over this transport protocol.
dwAddressLength

Specifies the size, in bytes, of the address.

dwPrincipalLength

This member is reserved for future use. It must be zero.

lpAddress

Points to a socket address of the appropriate type.

lpPrincipal

This member is reserved for future use. It must be NULL.

See Also

SERVICE_ADDRESSES, SERVICE_INFO


SERVICE_ADDRESSES [New - Windows NT]
SERVICE_ADDRESSES  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct _SERVICE_ADDRESSES {

    DWORD   dwAddressCount;

    SERVICE_ADDRESS   Addresses[1];

} SERVICE_ADDRESSES;

The SERVICE_ADDRESSES structure contains an array of SERVICE_ADDRESS data structures.

Members

dwAddressCount

Specifies the number of SERVICE_ADDRESS structures in the Addresses array.

Addresses

An array of SERVICE_ADDRESS data structures. Each SERVICE_ADDRESS structure contains information about a network service address.

See Also

SERVICE_ADDRESS, SERVICE_INFO


SERVICE_INFO [New - Windows NT]
SERVICE_INFO  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct _SERVICE_INFO {

    LPGUID   lpServiceType;

    LPTSTR   lpServiceName;

    LPTSTR   lpComment;

    LPTSTR   lpLocale;

    DWORD    dwDisplayHint;

    DWORD    dwVersion;

    DWORD    dwTime;

    LPTSTR   lpMachineName;

    LPSERVICE_ADDRESSES lpServiceAddress;

    BLOB ServiceSpecificInfo;

} SERVICE_INFO;

The SERVICE_INFO structure contains information about a network service or a network service type.

Members

lpServiceType

Points to a GUID that is the type of the network service.

lpServiceName

Points to a zero-terminated string that is the name of the network service.

If you are calling the SetService function with the dwNameSpace parameter set to NS_DEFAULT, the network service name must be a common name A common name is what the network service is commonly known as. An example of a common name for a network service is "My SQL Server".

If you are calling the SetService function with the dwNameSpace parameter set to a specific service name, the network service name can be a common name or a distinguished name. A distinguished name distinguishes the service to a unique location with a directory service. An example of a distinguished name for a network service is "MS\\SYS\\NT\\DEV\\My SQL Server". The

lpComment

Points to a zero-terminated string that is a comment or description for the network service. For example, "Used for development upgrades."

lpLocale

Points to a zero-terminated string that contains locale information.

dwDisplayHint

Specifies a hint as to how to display the network service in a network browsing user interface. This can be one of the following values:

Value	Meaning
RESOURCEDISPLAYTYPE_DOMAIN	Display the network service as a domain.
RESOURCEDISPLAYTYPE_FILE	Display the network service as a file.
RESOURCEDISPLAYTYPE_GENERIC	The method used to display the object does not matter.
RESOURCEDISPLAYTYPE_GROUP	Display the network service as a group.
RESOURCEDISPLAYTYPE_SERVER	Display the network service as a server.
RESOURCEDISPLAYTYPE_SHARE	Display the network service as a sharepoint.
RESOURCEDISPLAYTYPE_TREE	Display the network service as a tree.
dwVersion

Specifies version information for the network service. The high word of this value specifies a major version number. The low word of this value specifies a minor version number.

dwTime

This member is reserved for future use. It must be set to zero.

lpMachineName

Points to a zero-terminated string that is the name of the computer on which the network service is running.

lpServiceAddress

Points to a SERVICE_ADDRESSES structure that contains an array of SERVICE_ADDRESS structures. Each SERVICE_ADDRESS structure contains information about a network service address.

A network service can call the getsockname function to determine the local address of the system.

ServiceSpecificInfo

A BLOB structure that specifies service-defined information.

Note that, in general, the data pointed to by the BLOB structure's pBlobData member must not contain any pointers. That is because only the network service knows the format of the data; copying the data without such knowledge would lead to pointer invalidation. If the data pointed to by pBlobData contains variable-sized elements, offsets from pBlobData can be used to indicate the location of those elements. There is one exception to this general rule: when pBlobData points to a SERVICE_TYPE_INFO_ABS structure. This is possible because both the SERVICE_TYPE_INFO_ABS structure, and any SERVICE_TYPE_VALUE_ABS structures it contains are predefined, and thus their formats are known to the operating system.

See Also

BLOB, GetService, NS_SERVICE_INFO, SetService, SERVICE_ADDRESS, SERVICE_ADDRESSES, SERVICE_TYPE_INFO_ABS, SERVICE_TYPE_VALUE_ABS


SERVICE_STATUS
SERVICE_STATUS  QuickInfo

typedef struct _SERVICE_STATUS { // ss

    DWORD dwServiceType;

    DWORD dwCurrentState;

    DWORD dwControlsAccepted;

    DWORD dwWin32ExitCode;

    DWORD dwServiceSpecificExitCode;

    DWORD dwCheckPoint;

    DWORD dwWaitHint;

} SERVICE_STATUS, *LPSERVICE_STATUS;

The SERVICE_STATUS structure contains information about a service. The ControlService, EnumDependentServices, EnumServicesStatus, and QueryServiceStatus functions use this structure to return information about a service. A service uses this structure in the SetServiceStatus function to report its current status to the service control manager.

Members

dwServiceType

The value returned includes one of the following service type flags to indicate the type of service. In addition, for a SERVICE_WIN32 service, the SERVICE_INTERACTIVE_PROCESS flag might be set, indicating that the service process can interact with the desktop.

Value	Meaning
SERVICE_WIN32_OWN_PROCESS	A service type flag that indicates a Win32 service that runs in its own process.
SERVICE_WIN32_SHARE_PROCESS	A service type flag that indicates a Win32 service that shares a process with other services.
SERVICE_KERNEL_DRIVER	A service type flag that indicates a Windows NT device driver.
SERVICE_FILE_SYSTEM_DRIVER	A service type flag that indicates a Windows NT file system driver.
SERVICE_INTERACTIVE_PROCESS	A flag that indicates a Win32 service process that can interact with the desktop.
dwCurrentState

Indicates the current state of the service. One of the following values is specified:

Value	Meaning
SERVICE_STOPPED	The service is not running.
SERVICE_START_PENDING	The service is starting.
SERVICE_STOP_PENDING	The service is stopping.
SERVICE_RUNNING	The service is running.
SERVICE_CONTINUE_PENDING	The service continue is pending.
SERVICE_PAUSE_PENDING	The service pause is pending.
SERVICE_PAUSED	The service is paused.
dwControlsAccepted

Specifies the control codes that the service will accept and process. A user interface process can control a service by specifying a control command in the ControlService function. By default, all services accept the SERVICE_CONTROL_INTERROGATE value. Any or all of the following flags can be specified to enable the other control codes.

Value	Meaning
SERVICE_ACCEPT_STOP
	The service can be stopped. This enables the SERVICE_CONTROL_STOP value.
SERVICE_ACCEPT_PAUSE_CONTINUE
	The service can be paused and continued. This enables the SERVICE_CONTROL_PAUSE and SERVICE_CONTROL_CONTINUE values.
SERVICE_ACCEPT_SHUTDOWN
	The service is notified when system shutdown occurs. This enables the system to send a SERVICE_CONTROL_SHUTDOWN value to the service. The ControlService function cannot send this control code.
dwWin32ExitCode

Specifies a Win32 error code that the service uses to report an error that occurs when it is starting or stopping. To return an error code specific to the service, the service must set this value to ERROR_SERVICE_SPECIFIC_ERROR to indicate that the dwServiceSpecificExitCode member contains the error code. The service should set this value to NO_ERROR when it is running and on normal termination.

dwServiceSpecificExitCode

Specifies a service specific error code that the service returns when an error occurs while the service is starting or stopping. This value is ignored unless the dwWin32ExitCode member is set to ERROR_SERVICE_SPECIFIC_ERROR.

dwCheckPoint

Specifies a value that the service increments periodically to report its progress during a lengthy start, stop, or continue operation. For example, the service should increment this value as it completes each step of its initialization when it is starting up. The user interface program that invoked the operation on the service uses this value to track the progress of the service during a lengthy operation. This value is not valid and should be zero when the service does not have a start, stop, or continue operation pending.

dwWaitHint

Specifies an estimate of the amount of time, in milliseconds, that the service expects a pending start, stop, or continue operation to take before the service makes its next call to the SetServiceStatus function with either an incremented dwCheckPoint value or a change in dwCurrentState. If the amount of time specified by dwWaitHint passes, and dwCheckPoint has not been incremented, or dwCurrentState has not changed, the service control manager or service control program can assume that an error has occurred.

See Also

ControlService, EnumDependentServices, EnumServicesStatus, QueryServiceStatus, SetServiceStatus


SERVICE_TABLE_ENTRY [New - Windows NT]
SERVICE_TABLE_ENTRY  QuickInfo

[New - Windows NT]

typedef struct _SERVICE_TABLE_ENTRY { // ste

    LPTSTR lpServiceName;

    LPSERVICE_MAIN_FUNCTION lpServiceProc;

} SERVICE_TABLE_ENTRY, *LPSERVICE_TABLE_ENTRY;

The SERVICE_TABLE_ENTRY structure is used by the StartServiceCtrlDispatcher function to specify the ServiceMain function for a Win32 service that can run in the calling process.

Members

lpServiceName

Points to a null-terminated string that names a service that can run in this service process. This string is ignored if the service is installed in the service control manager database as a SERVICE_WIN32_OWN_PROCESS service type. For a SERVICE_WIN32_SHARE_PROCESS service process, this string names the service that uses the ServiceMain function pointed to by the lpServiceProc member.

lpServiceProc

Points to a ServiceMain function.

See Also

ServiceMain, StartServiceCtrlDispatcher


SERVICE_TYPE_INFO_ABS [New - Windows NT]
SERVICE_TYPE_INFO_ABS  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct _SERVICE_TYPE_INFO_ABS {

    LPTSTR                  lpTypeName;

    DWORD                   dwValueCount;

    SERVICE_TYPE_VALUE_ABS  Values[1];

} SERVICE_TYPE_INFO_ABS

The SERVICE_TYPE_INFO_ABS structure contains information about a network service type. You use a SERVICE_TYPE_INFO_ABS structure to add a network service type to a name space.

Members

lpTypeName

Points to a zero-terminated string that is the name of the network service type.  This name is the same in all name spaces, and is used by the GetTypeByName and GetNameByType functions.

dwValueCount

Specifies the number of SERVICE_TYPE_VALUE_ABS structures in the Values member array that follows dwValueCount.

Values[1]

An array of SERVICE_TYPE_VALUE_ABS structures.

Each of these structures contains information about a service type value that the operating system or network service may need when an instance of this network service type is registered with a name space.

The information in these structures may be specific to a name-space. For example, if a network service uses the SAP name space, but does not have a GUID that contains the SAP identifier (SAPID), it defines the SAPID in a SERVICE_TYPE_VALUE_ABS structure.

Remarks

When you use the SetService function to add a network service type to a name space, the SERVICE_TYPE_INFO_ABS structure is passed as the ServiceSpecificInfo BLOB member of a SERVICE_INFO structure. Although the ServiceSpecificInfo member generally should not contain pointers, an exception is made in the case of the SERVICE_TYPE_INFO_ABS and SERVICE_TYPE_VALUE_ABS structures.

See Also

SetService, SERVICE_INFO, SERVICE_TYPE_VALUE_ABS


SERVICE_TYPE_VALUE_ABS [New - Windows NT]
SERVICE_TYPE_VALUE_ABS  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct _SERVICE_TYPE_VALUE_ABS {

    DWORD   dwNameSpace;

    DWORD   dwValueType;

    DWORD   dwValueSize;

    LPTSTR  lpValueName;

    PVOID   lpValue;

} SERVICE_TYPE_VALUE_ABS

The SERVICE_TYPE_VALUE_ABS structure contains information about a network-service type value. This information may be specific to a name space.

Members

dwNameSpace

Specifies the name space, or a set of default name spaces, for which the network service type value is intended . Name-space providers will look only at values intended for their name space.

Use one of the following constants to specify a name space:

Value	Name Space
NS_DEFAULT	A set of default name spaces. The function queries each name space within this set. The set of default name spaces typically includes all the name spaces installed on the system. System administrators, however, can exclude particular name spaces from the set. NS_DEFAULT is the value that most applications should use for dwNameSpace.
NS_DNS	The Domain Name System used in the Internet for host name resolution.
NS_NETBT	The NetBIOS over TCP/IP layer. All Windows NT systems register their computer names with NetBIOS. This name space is used to convert a computer name to an IP address that uses this registration. Note that NS_NETBT may access a WINS server to perform the resolution.
NS_SAP	The Netware Service Advertising Protocol. This may access the Netware bindery if appropriate. NS_SAP is a dynamic name space that allows registration of services.
NS_TCPIP_HOSTS	Lookup value in the <systemroot>\system32\drivers\etc\hosts file.
NS_TCPIP_LOCAL	Local TCP/IP name resolution mechanisms, including comparisons against the local host name and looks up host names and IP addresses in cache of host to IP address mappings.
dwValueType

Specifies the type of the value data. You can specify one of the following types:

Value	Meaning
REG_BINARY	Binary data in any form.
REG_DWORD	A 32-bit number.
REG_MULTI_SZ	An array of null-terminated strings, terminated by two null characters.
REG_SZ	A null-terminated string.
dwValueSize

Specifies the size, in bytes, of the value data. In the case of REG_SZ and REG_MULTI_SZ string data, the terminating characters are counted as part of the size.

lpValueName

Points to a zero-terminated string that is the name of the value. This name is specific to a name space.

Several commonly used value name strings are associated with defined constants. These name strings include the following:

Constant	Name String
SERVICE_TYPE_VALUE_SAPID	"SapId"
SERVICE_TYPE_VALUE_CONN	"ConnectionOriented"
SERVICE_TYPE_VALUE_TCPPORT	"TcpPort"
SERVICE_TYPE_VALUE_UDPPORT	"UdpPort"
lpValue

Points to the value data.

Remarks

When you use the SetService function to add a network service type to a name space, a SERVICE_TYPE_INFO_ABS structure is passed as the ServiceSpecificInfo BLOB member of a SERVICE_INFO structure. Although the ServiceSpecificInfo member generally should not contain pointers, an exception is made in the case of the SERVICE_TYPE_INFO_ABS and SERVICE_TYPE_VALUE_ABS structures.

See Also

SetService, SERVICE_INFO, SERVICE_TYPE_INFO_ABS


SESSION_BUFFER
SESSION_BUFFER  QuickInfo

typedef struct _SESSION_BUFFER { // sb

    UCHAR lsn;

    UCHAR state;

    UCHAR local_name[NCBNAMSZ];

    UCHAR remote_name[NCBNAMSZ];

    UCHAR rcvs_outstanding;

    UCHAR sends_outstanding;

} SESSION_BUFFER;

The SESSION_BUFFER structure contains information about a local network session. One or more SESSION_BUFFER structures follows a SESSION_HEADER structure when an application specifies the NCBSSTAT command in the ncb_command member of the NCB structure.

Members

lsn

Specifies the local session number.

state

Specifies the state of the session. This member can be one of the following values:

Value	Meaning
LISTEN_OUTSTANDING	The session is waiting for a call from a remote computer.
CALL_PENDING	The session is attempting to connect to a remote computer.
SESSION_ESTABLISHED	The session connected and is able to transfer data.
HANGUP_PENDING	The session is being deleted due to a command by the local user.
HANGUP_COMPLETE	The session was deleted due to a command by the local user.
SESSION_ABORTED	The session was abandoned due to a network or user problem.
local_name

Specifies the 16-byte NetBIOS name on the local computer used for this session.

remote_name

Specifies the 16-byte NetBIOS name on the remote computer used for this session.

rcvs_outstanding

Specifies the number of pending NCBRECV commands.

sends_outstanding

Specifies the number of pending NCBSEND and NCBCHAINSEND commands.

See Also

NCB, SESSION_HEADER


SESSION_HEADER
SESSION_HEADER  QuickInfo

typedef struct _SESSION_HEADER { // sh

    UCHAR sess_name;

    UCHAR num_sess;

    UCHAR rcv_dg_outstanding;

    UCHAR rcv_any_outstanding;

} SESSION_HEADER;

The SESSION_HEADER structure contains information about a network session. This structure is pointed to by the ncb_buffer member of the NCB structure. SESSION_HEADER is followed by as many SESSION_BUFFER structures as are required to describe the current network sessions.

Members

sess_name

Specifies the name number of the session. This value corresponds to the ncb_num member of the NCB structure.

num_sess

Specifies the number of sessions that have the name specified by the sess_name member.

rcv_dg_outstanding

Specifies the number of outstanding NCBDGRECV and NCBDGRECVBC commands.

rcv_any_outstanding

Specifies the number of outstanding NCBRECVANY commands.

See Also

NCB, SESSION_BUFFER


SET_PARTITION_INFORMATION [New - Windows NT]
SET_PARTITION_INFORMATION  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct _SET_PARTITION_INFORMATION {

   BYTE PartitionType;

} SET_PARTITION_INFORMATION ;

The SET_PARTITION_INFORMATION structure provides information used to set a disk partition's type.

Members

PartitionType

Specifies the type of partition. This member can be one of the following values:

Value	Meaning
PARTITION_ENTRY_UNUSED	Entry unused.
PARTITION_FAT_12	Specifies a partition with 12-bit FAT entries.
PARTITION_XENIX_1	Specifies a Xenix type 1 partition.
PARTITION_XENIX_2	Specifies a Xenix type 2 partition.
PARTITION_FAT_16	Specifies a partition with 16-bit FAT entries.
PARTITION_EXTENDED	Specifies an extended partition entry.
PARTITION_HUGE	Specifies an MS-DOS V4 huge partition.
PARTITION_IFS	Specifies an IFS partition.
PARTITION_UNIX	Specifies a Unix partition.
VALID_NTFT	Specifies an NTFT partition.
Remarks

The DeviceIoControl function uses a SET_PARTITION_INFORMATION structure as input to an IOCTL_DISK_SET_PARTITION_INFO device input and output control operation.

See Also

DeviceIoControl, IOCTL_DISK_GET_PARTITION_INFO, IOCTL_DISK_SET_PARTITION_INFO, PARTITION_INFORMATION


SHCONTF [New - Windows 95]
SHCONTF  QuickInfo

[New - Windows 95]

typedef enum tagSHCONTF {

    SHCONTF_FOLDERS = 32,         // for shell browser

    SHCONTF_NONFOLDERS = 64,      // for default view

    SHCONTF_INCLUDEHIDDEN = 128,  // for hidden or system objects

} SHCONTF;

Specifies an enumerated type that defines flags used with the IShellFolder::EnumObjects method.

See Also

IShellFolder::EnumObjects


SHELLEXECUTEINFO
SHELLEXECUTEINFO  Overview  Group

typedef struct _SHELLEXECUTEINFO {   // sei

    DWORD     cbSize;

    ULONG     fMask;

    HWND      hwnd;

    LPCSTR    lpVerb;

    LPCSTR    lpFile;

    LPCSTR    lpParameters;

    LPCSTR    lpDirectory;

    int       nShow;

    HINSTANCE hInstApp;

    // Optional members

    LPVOID lpIDList;

    LPCSTR lpClass;

    HKEY   hkeyClass;

    DWORD  dwHotKey;

    HANDLE hIcon;

    HANDLE hProcess;

} SHELLEXECUTEINFO, FAR *LPSHELLEXECUTEINFO;

The SHELLEXECUTEINFO structure contains information used by the ShellExecuteEx function.

Members

cbSize

Specifies the size, in bytes, of the structure.

fMask

This is an array of flags that indicate the content and validity of the other structure members. You can specify a combination of the following values:

Value	Meaning
SEE_MASK_CLASSKEY	Use class key given by the hkeyClass member.
SEE_MASK_CLASSNAME	Use the class name given by the lpClass member.
SEE_MASK_CONNECTNETDRV	The lpFile member is a Universal Naming Convention (UNC) path of a file on a network. Validate the share and connect to a drive letter.
SEE_MASK_DOENVSUBST	Expand any environment variables specified in the string given by the lpDirectory or lpFile member.
SEE_MASK_FLAG_DDEWAIT	Wait for the DDE conversation to terminate before returning, if the ShellExecuteEx function causes a DDE conversation to start.
SEE_MASK_FLAG_NO_UI	Do not display an error message box if an error occurs.
SEE_MASK_HOTKEY	Use the hot key given by the dwHotKey member.
SEE_MASK_ICON	Use the icon given by the hIcon member.
SEE_MASK_IDLIST	Use the item identifier list given by the lpIDList member.
SEE_MASK_INVOKEIDLIST	Use the item identifier list given by the lpIDList member to invoke an application. If this member is NULL, the function creates an item identifier list and invokes the application. SEE_MASK_INVOKEIDLIST overrides SEE_MASK_IDLIST.
SEE_MASK_NOCLOSEPROCESS	Leave the process running after the ShellExecuteEx function exits. The hProcess member receives the handle of the process.
hwnd

Handle to the parent window for any message boxes that the system may produce while executing this function (for example, for error reporting).

lpVerb

Pointer to a string specifying the name of a verb. The verb specifies an action for the application to perform. This member defaults to "Open" if no verb is specified.

lpFile

Pointer to a list of null-terminated strings that specify the names of the files to open or print. The function can open an executable file or a document file. The function can print a document file. If the path is not included with a name, the current directory is assumed.

lpParameters

Pointer to a null-terminated string containing the application parameters. The parameters must be separated by spaces. To include double quotation marks, you must enclose the marks in double quotation marks, as in the following example:

sei.lpParameters = "An example: \"\"\"quoted text\"\"\"";

In this case, the application receives three parameters: An, example:, and "quoted text".

If lpFile specifies a document file, lpParameters should be NULL.

lpDirectory

Pointer to a null-terminated string that specifies the name of the working directory. If this member is not specified, the current directory is used as the working directory.

nShow

Show flags. Can be one of the SW_ values described for the ShowWindow function. If lpFile specifies an executable file, nShow specifies how the application is to be shown when it is opened. If lpFile specifies a document file, nShow should be zero.

hInstApp

Handle to the instance of the application that was started or an error value if the application could not be started. (This handle could also be the handle of a dynamic data exchange [DDE] server application.) This member is set on return. Error values can be one of the following:

Value	Meaning
SE_ERR_FNF	File not found
SE_ERR_PNF	Path not found
SE_ERR_ACCESSDENIED	Access denied
SE_ERR_OOM	Out of memory
SE_ERR_DLLNOTFOUND	Dynamic-link library not found
SE_ERR_SHARE	Cannot share open file
SE_ERR_ASSOCINCOMPLETE	File association information not complete
SE_ERR_DDETIMEOUT	DDE operation timed out
SE_ERR_DDEFAIL	DDE operation failed
SE_ERR_DDEBUSY	DDE operation busy
SE_ERR_NOASSOC	File association not available
lpIDList

Pointer to an ITEMIDLIST structure that contains an item identifier list that uniquely identifies the file to execute. Ignored if fMask is not set to SEE_MASK_IDLIST.

lpClass

Pointer to a null-terminated string specifying the name of a file class or a globally unique identifier (GUID). Ignored if fMask is not set to SEE_MASK_CLASSNAME.

hkeyClass

Handle to the registry key for the file class. Ignored if fMask is not set to SEE_MASK_CLASSKEY.

dwHotKey

Hot key to associate with the application. The low-order word is the virtual-key code, and the high-order word is a modifier flag (HOTKEYF_). For a list of modifier flags, see the description of the WM_SETHOTKEY message. Ignored if fMask is not set to SEE_MASK_HOTKEY.

hIcon

Handle to the icon for the file class. Ignored if fMask is not set to SEE_MASK_ICON.

hProcess

Handle to the newly started application. This member is set on return and is always NULL if fMask is not set to SEE_MASK_NOCLOSEPROCESS.

See Also

ITEMIDLIST, ShellExecuteEx, ShowWindow, WM_SETHOTKEY


SHFILEINFO [New - Windows 95]
SHFILEINFO  QuickInfo

[New - Windows 95]

typedef struct _SHFILEINFO { // shfi

    HICON hIcon;

    int   iIcon;

    DWORD dwAttributes;

    char  szDisplayName[MAX_PATH];

    char  szTypeName[80];

} SHFILEINFO;

Contains information about a file object.

Members

hIcon

Handle of the icon that represents the file.

iIcon

Index of the icon image within the system image list.

dwAttributes

Array of flags that indicates the attributes of the file object. For information about the flags, see the description of the IShellFolder::GetAttributesOf method.

szDisplayName

String that contains the name of the file as it appears in the Windows shell, or path and filename of the file that contains the icon representing the file.

szTypeName

String that describes the type of the file.

Remarks

This structure is used with the SHGetFileInfo function.

See Also

IShellFolder::GetAttributesOf, SHGetFileInfo


SHFILEOPSTRUCT [New - Windows 95]
SHFILEOPSTRUCT  QuickInfo

[New - Windows 95]

typedef struct _SHFILEOPSTRUCT { // shfos

    HWND         hwnd;

    UINT         wFunc;

    LPCSTR       pFrom;

    LPCSTR       pTo;

    FILEOP_FLAGS fFlags;

    BOOL         fAnyOperationsAborted;

    LPVOID       hNameMappings;

    LPCSTR       lpszProgressTitle;

} SHFILEOPSTRUCT, FAR *LPSHFILEOPSTRUCT;

Contains information that the SHFileOperation function uses to perform file operations.

Members

hwnd

Handle of the dialog box to use to display information about the status of the operation. If fFlags includes the FOF_CREATEPROGRESSDLG value, this parameter is the handle of the parent window for the progress dialog box created by the system.

wFunc

Operation to perform. This member can be one of the following values:

FO_COPY	Copies the files specified by pFrom to the location specified by pTo.
FO_DELETE	Deletes the files specified by pFrom (pTo is ignored).
FO_MOVE	Moves the files specified by pFrom to the location specified by pTo.
FO_RENAME	Renames the files specified by pFrom.
pFrom

Pointer to a string that contains the names of the source files.

pTo

Pointer to a string that specifies the destination for the moved, copied, or renamed file.

fFlags

Flags that control the file operation. This member can be a combination of the following values:

FOF_ALLOWUNDO	Preserves undo information, if possible.
FOF_CONFIRMMOUSE	Not implemented.
FOF_FILESONLY	Performs the operation only on files if a wildcard filename (*.*) is specified.
FOF_MULTIDESTFILES	Indicates that the pTo member specifies multiple destination files (one for each source file) rather than one directory where all source files are to be deposited.
FOF_NOCONFIRMATION	Responds with "yes to all" for any dialog box that is displayed.
FOF_NOCONFIRMMKDIR	Does not confirm the creation of a new directory if the operation requires one to be created.
FOF_RENAMEONCOLLISION	Gives the file being operated on a new name (such as "Copy #1 of...") in a move, copy, or rename operation if a file of the target name already exists.
FOF_SILENT	Does not display a progress dialog box.
FOF_SIMPLEPROGRESS	Displays a progress dialog box, but does not show the filenames.
FOF_WANTMAPPINGHANDLE	Fills in the hNameMappings member. The handle must be freed by using the SHFreeNameMappings function.
fAnyOperationsAborted

Value that receives TRUE if the user aborted any file operations before they were completed or FALSE otherwise.

hNameMappings

Handle of a filename mapping object that contains an array of SHNAMEMAPPING structures. Each structure contains the old and new path names for each file that was moved, copied, or renamed. This member is used only if fFlags includes FOF_WANTMAPPINGHANDLE.

lpszProgressTitle

Pointer to a string to use as the title for a progress dialog box. This member is used only if fFlags includes FOF_SIMPLEPROGRESS.

Remarks

If pFrom or pTo are unqualified names, the current directories are taken from the global current drive and directory settings as managed by the GetCurrentDirectory and SetCurrentDirectory functions.

The SHGetNameMappingPtr macro retrieves a pointer to the filename mapping object returned in the hNameMappings member. The SHGetNameMappingCount macro retrieves the number of SHNAMEMAPPING structures in the object.

See Also

GetCurrentDirectory, SetCurrentDirectory, SHFileOperation, SHFreeNameMappings, SHGetNameMappingPtr, SHGetNameMappingCount, SHNAMEMAPPING


SHGNO [New - Windows 95]
SHGNO  QuickInfo

[New - Windows 95]

typedef enum tagSHGDN {

    SHGDN_NORMAL = 0,

    SHGDN_INFOLDER = 1,

    SHGDN_FORPARSING = 0x8000,

} SHGNO;

Specifies an enumerated type that defines flags used with the IShellFolder::GetDisplayNameOf and IShellFolder::SetNameOf methods.

Members

SHGDN_NORMAL

Default display name that is suitable for a file object displayed by itself, as shown in the following examples.

File system path	Corresponding display name
C:\WINDOWS\FILE.TXT	file
\\COMPUTER\SHARE	share on computer
C:\ (where drive C has the volume name My Drive)	My Drive (C)
SHGDN_INFOLDER

Display name that is suitable for a file object displayed within its respective folder, as shown in the following examples.

File system path	Corresponding display name
C:\WINDOWS\FILE.TXT	file
\\COMP\SHARE	user
C:\ (where drive C has the volume name My Drive)	My Drive (C)
SHGDN_FORPARSING

Display name that can be passed to the ParseDisplayName method of the parent folder's IShellFolder object.

File system path	Corresponding display name
C:\WINDOWS\FILE.TXT	C:\WINDOWS\FILE.TXT
\\COMP\SHARE	\\COMP\SHARE
C:\ (where drive C has the volume name My Drive)	C:\
See Also

IShellFolder::GetDisplayNameOf, IShellFolder::SetNameOf, ParseDisplayName


SHITEMID [New - Windows 95]
SHITEMID  QuickInfo

[New - Windows 95]

typedef struct _SHITEMID {       // mkid

    USHORT cb;       // size of identifier, including cb itself

    BYTE   abID[1];  // variable length item identifier

} SHITEMID, * LPSHITEMID;

typedef const SHITEMID  * LPCSHITEMID;

Defines an item identifier.


SHNAMEMAPPING [New - Windows 95]
SHNAMEMAPPING  QuickInfo

[New - Windows 95]

typedef struct _SHNAMEMAPPING { // shnm

    LPSTR pszOldPath; // address of old path name

    LPSTR pszNewPath; // pointer to new path name

    int   cchOldPath; // number of characters in old path name

    int   cchNewPath; // number of characters in new path name

} SHNAMEMAPPING, FAR *LPSHNAMEMAPPING;

Contains the old and new path names for each file that was moved, copied, or renamed by the SHFileOperation function.

See Also

SHFileOperation


SID
SID  QuickInfo

typedef PVOID PSID;

The SID structure is a variable-length structure used to uniquely identify users or groups. SID stands for security identifier.

Applications are not to modify the SID structure directly. To create and manipulate a security identifier, use the functions listed in the See Also section.

See Also

AllocateAndInitializeSid, CopySid, EqualSid, FreeSid, GetLengthSid, GetSidIdentifierAuthority, GetSidLengthRequired, GetSidSubAuthority, GetSidSubAuthorityCount, InitializeSid, IsValidSid, LookupAccountName, LookupAccountSid


SID_AND_ATTRIBUTES
SID_AND_ATTRIBUTES  QuickInfo

typedef struct _SID_AND_ATTRIBUTES { // saa

    PSID  Sid;

    DWORD Attributes;

} SID_AND_ATTRIBUTES ;

The SID_AND_ATTRIBUTES structure represents a security identifier (SID) and its attributes. SIDs are used to uniquely identify users or groups.

Members

Sid

Points to a SID structure.

Attributes

Specifies attributes of the SID. This value contains up to 32 one-bit flags. Its meaning depends on the definition and use of the SID.

Remarks

A group is represented by a SID. SIDs have attributes that indicate whether they are currently enabled, disabled, or mandatory, and how they are used. A SID_AND_ATTRIBUTES structure can represent a SID whose attributes change frequently. For example, it is used to represent groups in the TOKEN_GROUPS structure.

See Also

SID, TOKEN_GROUPS, TOKEN_USER


SID_IDENTIFIER_AUTHORITY
SID_IDENTIFIER_AUTHORITY  QuickInfo

typedef struct _SID_IDENTIFIER_AUTHORITY { // sia

    BYTE Value[6];

} SID_IDENTIFIER_AUTHORITY ;

The SID_IDENTIFIER_AUTHORITY structure represents the top-level authority of a security identifier (SID).

Members

Value

An array of six bytes specifying a SID's top-level authority.

Remarks

The identifier authority value identifies the agency that issued the SID. Some identifier authorities are predefined:

Identifier authority	Value
SECURITY_NULL_SID_AUTHORITY	0
SECURITY_WORLD_SID_AUTHORITY	1
SECURITY_LOCAL_SID_AUTHORITY	2
SECURITY_CREATOR_SID_AUTHORITY	3
SECURITY_NT_AUTHORITY	5
A SID must contain a top-level authority and at least one relative identifier (RID) value.

See Also

AllocateAndInitializeSid, GetSidIdentifierAuthority, InitializeSid, SID


SINGLE_LIST_ENTRY
SINGLE_LIST_ENTRY  QuickInfo

typedef struct _SINGLE_LIST_ENTRY { // sle

    struct _SINGLE_LIST_ENTRY *Next;

} SINGLE_LIST_ENTRY;

The SINGLE_LIST_ENTRY structure is available for any entry in a single-linked list.

Members

Next

Points to the next entry in a single-linked list.

Remarks

This structure can be used as the beginning of a single-linked list or as any subsequent entry in the list.


SIZE
SIZE  QuickInfo

typedef struct tagSIZE { // siz

    LONG cx;

    LONG cy;

} SIZE;

The SIZE structure specifies the width and height of a rectangle.

Members

cx

Specifies the rectangle's width.

cy

Specifies the rectangle's height.

Remarks

The rectangle dimensions stored in this structure may correspond to viewport extents, window extents, text extents, bitmap dimensions, or the aspect-ratio filter for some extended functions.

See Also

GetAspectRatioFilterEx, GetBitmapDimensionEx, GetTextExtentPoint32, GetViewportExtEx, GetWindowExtEx, ScaleViewportExtEx, ScaleWindowExtEx, SetBitmapDimensionEx, SetViewportExtEx, SetWindowExtEx


SMALL_RECT
SMALL_RECT  QuickInfo

typedef struct _SMALL_RECT { // srct

    SHORT Left;

    SHORT Top;

    SHORT Right;

    SHORT Bottom;

} SMALL_RECT;

The SMALL_RECT structure defines the coordinates of the upper left and lower right corners of a rectangle.

Members

Left

Specifies the x-coordinate of the upper left corner of the rectangle.

Top

Specifies the y-coordinate of the upper left corner of the rectangle.

Right

Specifies the x-coordinate of the lower right corner of the rectangle.

Bottom

Specifies the y-coordinate of the lower right corner of the rectangle.

Remarks

This structure is used by console functions to specify rectangular areas of console screen buffers, where the coordinates specify the rows and columns of screen-buffer character cells.

See Also

RECT, RECTL


SOUNDSENTRY
SOUNDSENTRY  QuickInfo  Overview  Group

typedef struct tagSOUNDSENTRY {     // ss

    UINT cbSize;

    DWORD dwFlags;

    DWORD iFSTextEffect;

    DWORD iFSTextEffectMSec;

    DWORD iFSTextEffectColorBits;

    DWORD iFSGrafEffect;

    DWORD iFSGrafEffectMSec;

    DWORD iFSGrafEffectColor;

    DWORD iWindowsEffect;

    DWORD iWindowsEffectMSec;

    LPTSTR lpszWindowsEffectDLL;

    DWORD iWindowsEffectOrdinal;

} SOUNDSENTRY, *LPSOUNDSENTRY;

The SOUNDSENTRY structure contains information about the SoundSentry accessibility feature. When the SoundSentry feature is on, the computer displays a visual indication only when a sound is generated.

Windows 95: The visual indication is displayed when a sound is generated through the computer's internal speaker.

Windows NT The visual indication is displayed when a sound is generated through either the multimedia sound services or through the computer's speaker.

Members

cbSize

Specifies the size, in bytes, of this structure.

dwFlags

A set of bit flags that specify properties of the SoundSentry feature. The following bit-flag values are defined:

Value	Meaning
SSF_AVAILABLE	If this flag is set, the SoundSentry feature is available.
SSF_SOUNDSENTRYON	If this flag is set, the SoundSentry feature is on.
iFSTextEffect

Windows 95: Specifies the visual signal to present when a text-mode application generates a sound while running in a full-screen virtual machine. This member can be one of the following values:

Value	Meaning
SSTF_BORDER	Flash the screen border (that is, the overscan area), which is unavailable on some displays.
SSTF_CHARS	Flash characters in the corner of the screen.
SSTF_DISPLAY	Flash the entire display.
SSTF_NONE	No visual signal.

Windows NT: This member is reserved for future use. It must be set to zero.

iFSTextEffectMSec

Windows 95: Specifies the duration, in milliseconds, of the visual signal that is displayed when a full-screen, text-mode application generates a sound.

Wndows NT: This member is reserved for future use. It must be set to zero.

iFSTextEffectColorBits

Windows 95: Specifies the RGB value of the color to be used when displaying the visual signal shown when a full-screen, text-mode application generates a sound.

Windows NT: This member is reserved for future use. It must be set to zero.

iFSGrafEffect

Windows 95: Specifies the visual signal to present when a graphics-mode application generates a sound while running in a full-screen virtual machine. This member can be one of the following values:

Value	Meaning
SSGF_DISPLAY	No visual signal.
SSGF_NONE	Flash the entire display.

Windows NT: This member is reserved for future use. It must be set to zero.

iFSGrafEffectMSec

Windows 95: Specifies the duration, in milliseconds, of the visual signal that is displayed when a full-screen, graphics-mode application generates a sound.

Windows NT: This member is reserved for future use. It must be set to zero.

iFSGrafEffectColor

Windows 95: Specifies the RGB value of the color to be used when displaying the visual signal shown when a full-screen, graphics-mode application generates a sound.

Windows NT: This member is reserved for future use. It must be set to zero.

iWindowsEffect

Specifies the visual signal to display when a sound is generated by a Windows-based application or an MS-DOS application running in a window. This member can be one of the following values:

Value	Meaning
SSWF_CUSTOM	Windows 95 only: Call the SoundSentryProc routine exported by the DLL specified by the iFSWindowsEffectDLL member.
SSWF_DISPLAY	Flash the entire display.
SSWF_NONE	No visual signal.
SSWF_TITLE	Flash the title bar of the active window.
SSWF_WINDOW	Flash the active window.
iWindowsEffectMSec

Windows 95: Specifies the duration, in milliseconds, of the visual signal that is displayed when a Windows-based application (or a non-Windows-based application running in a window) generates a sound.

Windows NT: This member is reserved for future use. It must be set to zero.

lpszWindowsEffectDLL

Windows 95: Points to the buffer that contains the name of the DLL that contains a SoundSentryProc callback function. The length of the name must not exceed the value of MAX_PATH. This member is NULL if no DLL is used. When retrieving information about the SoundSentry feature, the size of the buffer must be equal to, or larger than, the value of MAX_PATH.

Windows NT: This member is reserved for future use. It must be set to NULL.

iWindowsEffectOrdinal

This member is reserved for future use on both platforms. It must be set to zero.

Remarks

An application uses a SOUNDSENTRY structure when calling the SystemParametersInfo function with the wAction parameter set to SPI_GETSOUNDSENTRY or SPI_SETSOUNDSENTRY. When using SPI_GETSOUNDSENTRY, an application must specify the cbSize member of the SOUNDSENTRY structure; the SystemParametersInfo function fills the remaining members. An application must specify the cbSize, dwFlags, and iWindowsEffect members when using the SPI_SETSOUNDSENTRY value.

See Also

SoundSentryProc, SystemParametersInfo


STARTUPINFO
STARTUPINFO  QuickInfo

typedef struct _STARTUPINFO { // si

    DWORD   cb;

    LPTSTR  lpReserved;

    LPTSTR  lpDesktop;

    LPTSTR  lpTitle;

    DWORD   dwX;

    DWORD   dwY;

    DWORD   dwXSize;

    DWORD   dwYSize;

    DWORD   dwXCountChars;

    DWORD   dwYCountChars;

    DWORD   dwFillAttribute;

    DWORD   dwFlags;

    WORD    wShowWindow;

    WORD    cbReserved2;

    LPBYTE  lpReserved2;

    HANDLE  hStdInput;

    HANDLE  hStdOutput;

    HANDLE  hStdError;

} STARTUPINFO, *LPSTARTUPINFO;

The STARTUPINFO structure is used with the CreateProcess function to specify main window properties if a new window is created for the new process. For graphical user interface (GUI) processes, this information affects the first window created by the CreateWindow function. For console processes, this information affects the console window if a new console is created for the process. A process can use the GetStartupInfo function to retrieve the STARTUPINFO structure specified when the process was created.

Members

cb

Specifies the size, in bytes, of the structure.

lpReserved

Reserved. Set this member to NULL before passing the structure to CreateProcess.

lpDesktop

Windows 95: Ignore this member.

Windows NT: Points to a zero-terminated string that specifies either the name of the desktop only or the name of both the window station and desktop for this process. A backslash in the string pointed to by lpDesktop indicates that the string includes both desktop and window station names. Otherwise, the lpDesktop string is interpreted as a desktop name. If lpDesktop is NULL, the new process inherits the window station and desktop of its parent process.

lpTitle

For console processes, this is the title displayed in the title bar if a new console window is created. If NULL, the name of the executable file is used as the window title instead. This parameter must be NULL for GUI or console processes that do not create a new console window.

dwX, dwY

Ignored unless dwFlags specifies STARTF_USEPOSITION. Specifies the x and y offsets, in pixels, of the upper left corner of a window if a new window is created. The offsets are from the upper left corner of the screen. For GUI processes, the specified position is used the first time the new process calls CreateWindow to create an overlapped window if the x parameter of CreateWindow is CW_USEDEFAULT.

dwXSize, dwYSize

Ignored unless dwFlags specifies STARTF_USESIZE. Specifies the width (dwXSize) and height (dwYSize), in pixels, of the window if a new window is created. For GUI processes, this is used only the first time the new process calls CreateWindow to create an overlapped window if the nWidth parameter of CreateWindow is CW_USEDEFAULT.

dwXCountChars, dwYCountChars

Ignored unless dwFlags specifies STARTF_USECOUNTCHARS. For console processes, if a new console window is created, dwXCountChars specifies the screen buffer width in character columns, and dwYCountChars specifies the screen buffer height in character rows. These values are ignored in GUI processes.

dwFillAttribute

Ignored unless dwFlags specifies STARTF_USEFILLATTRIBUTE. For console processes, specifies the initial text and background colors if a new console window is created. These values are ignored in GUI processes.

dwFlags

This is a bit field that determines whether certain STARTUPINFO members are used when the process creates a window. Any combination of the following values can be specified:

Value	Meaning
STARTF_USESHOWWINDOW	If this value is not specified, the wShowWindow member is ignored.
STARTF_USEPOSITION	If this value is not specified, the dwX and dwY members are ignored.
STARTF_USESIZE	If this value is not specified, the dwXSize and dwYSize members are ignored.
STARTF_USECOUNTCHARS	If this value is not specified, the dwXCountChars and dwYCountChars members are ignored.
STARTF_USEFILLATTRIBUTE	If this value is not specified, the dwFillAttribute member is ignored.
STARTF_FORCEONFEEDBACK	If this value is specified, the cursor is in feedback mode for two seconds after CreateProcess is called. If during those two seconds the process makes the first GUI call, the system gives five more seconds to the process. If during those five seconds the process shows a window, the system gives five more seconds to the process to finish drawing the window.
	The system turns the feedback cursor off after the first call to GetMessage, regardless of whether the process is drawing.
	For more information on feedback, see the following Remarks section.
STARTF_FORCEOFFFEEDBACK	If specified, the feedback cursor is forced off while the process is starting. The normal cursor is displayed. For more information on feedback, see the following Remarks section.
STARTF_SCREENSAVER	If specified, the system will treat the application as a screen saver:
	• The system allows the application to initialize at the foreground priority of the priority class passed to the CreateProcess function. For more information on process priorities, see Scheduling Priorities .
	• When the application checks for input using the GetMessage or PeekMessage function for the first time, the system changes it to the idle priority class. That lets background applications get priority over it.
	• When the user moves the mouse or presses a key, the system gives the application the foreground priority of the priority class originally passed to the CreateProcess function.
	Creating a screen saver with NORMAL_PRIORITY_CLASS lets the screen saver initialize and terminate over other normal priority applications.
STARTF_USESTDHANDLES	If this value is specified, sets the standard input of the process, standard output, and standard error handles to the handles specified in the hStdInput, hStdOutput, and hStdError members of the STARTUPINFO structure. The CreateProcess function's fInheritHandles parameter must be set to TRUE for this to work properly.
	If this value is not specified, the hStdInput, hStdOutput, and hStdError members of the STARTUPINFO structure are ignored.
wShowWindow

Ignored unless dwFlags specifies STARTF_USESHOWWINDOW. For GUI processes, wShowWindow specifies the default value the first time ShowWindow is called, if the nCmdShow parameter of ShowWindow is SW_SHOWDEFAULT. The wshowWindow member can be any of the SW_ constants defined in WINUSER.H.

In earlier versions of Windows, the WinMain function had an nCmdShow parameter that applications were encouraged to pass to the CreateWindow or ShowWindow function. The nCmdShow parameter is no longer available through WinMain. Now applications are encouraged to use SW_SHOWDEFAULT as the default ShowWindow command, in which case, ShowWindow uses the wShowWindow member of the STARTUPINFO structure of the process.

cbReserved2

Reserved; must be zero.

lpReserved2

Reserved; must be NULL.

hStdInput

Ignored unless dwFlags specifies STARTF_USESTDHANDLES. Specifies a handle that will be used as the standard input handle of the process if STARTF_USESTDHANDLES is specified.

hStdOutput

Ignored unless dwFlags specifies STARTF_USESTDHANDLES. Specifies a handle that will be used as the standard output handle of the process if STARTF_USESTDHANDLES is specified.

hStdError

Ignored unless dwFlags specifies STARTF_USESTDHANDLES. Specifies a handle that will be used as the standard error handle of the process if STARTF_USESTDHANDLES is specified.

Remarks

If a GUI process is being started and neither STARTF_FORCEONFEEDBACK or STARTF_FORCEOFFFEEDBACK is specified, the process feedback cursor is used. A GUI process is one whose subsystem is specified as "windows."

See Also

CreateProcess, CreateWindow, GetMessage, GetStartupInfo, PeekMessage, ShowWindow, WinMain


STICKYKEYS
STICKYKEYS  QuickInfo  Overview  Group

typedef struct tagSTICKYKEYS {     // sk

    DWORD cbSize;

    DWORD dwFlags;

} STICKYKEYS, *LPSTICKYKEYS;

The STICKYKEYS structure contains information about the StickyKeys accessibility feature. When the StickyKeys feature is on, the user can press a modifier key (SHIFT, CTRL, or ALT) and then another key in sequence rather than at the same time, to enter shifted (modified) characters and other key combinations.

Members

cbSize

Specifies the size, in bytes, of this structure.

dwFlags

A set of bit-flags that specify properties of the StickyKeys feature. The following bit-flag values are defined:

Value	Meaning
SKF_AUDIBLEFEEDBACK	If this flag is set, the system plays a sound when the user latches, locks, or releases modifier keys using the StickyKeys feature.
SKF_AVAILABLE	If this flag is set, the StickyKeys feature is available.
SKF_CONFIRMHOTKEY	Windows 95 only: A confirmation dialog appears when the StickyKeys feature is activated by using the hot key.
SKF_HOTKEYACTIVE	If this flag is set, the user can turn the StickyKeys feature on and off by pressing the SHIFT key five times.
SKF_HOTKEYSOUND	If this flag is set, the system plays a siren sound when the user turns the StickyKeys feature on or off by using the hot key.
SKF_INDICATOR	Windows 95 only: A visual indicator should be displayed when the StickyKeys feature is on.
SKF_STICKYKEYSON	If this flag is set, the StickyKeys feature is on.
SKF_TRISTATE	If this flag is set, pressing a modifier key twice in a row locks down the key until the user presses it a third time.
SKF_TWOKEYSOFF	If this flag is set, releasing a modifier key that has been pressed in combination with any other key turns off the StickyKeys feature.
Remarks

An application uses a STICKYKEYS structure when calling the SystemParametersInfo function with the wAction parameter set to SPI_GETSTICKYKEYS or SPI_SETSTICKYKEYS. When using SPI_GETSTICKYKEYS, an application must specify the cbSize member of the STICKYKEYS structure; the SystemParametersInfo function fills the remaining members. You must specify all structure members when using the SPI_SETSTICKYKEYS value.

See Also

SystemParametersInfo


STRRET
STRRET  QuickInfo

typedef struct _STRRET { // str

    UINT uType;

    union

    {

        LPWSTR pOleStr;        // pointer to OLE string to free

        UINT   uOffset;        // offset into item identifier list

        char   cStr[MAX_PATH]; // buffer to receive the display name

    } DUMMYUNIONNAME;

} STRRET, *LPSTRRET;

Contains strings returned from IShellFolder methods, such as GetDisplayNameOf.

Member

uType

Value that specifies the desired format of the string. This member can be one of the following values:

STRRET_CSTR	The string is returned in cStr.
STRRET_OFFSET	The string is located at uOffset bytes from the beginning of the item identifier list.
STRRET_WSTR	The string is at the address pointed to by pOleStr.
Remarks

The system may or may not provide the display name in the desired format. When IShellFolder::GetDisplayNameOf returns, the uType member indicates the format.

See Also

IShellFolder::GetDisplayNameOf


String
String  QuickInfo

String {

    WCHAR  szKey[];

    BYTE   Padding[];

    String Value[];

} String;

The String structure depicts the organization of data in a file-version resource. This structure is not a true C data structure because it contains variable-length members. This structure was created solely to depict the organization of data in a version resource and does not appear in any of the header files shipped with the Microsoft® Win32® Software Development Kit (SDK).

The String structure contains a string that describes a specific aspect of a file.

Members

szKey

Specifies an arbitrary 7-bit ASCII English string. The szKey member can be one of the following values:

String	Description
Comments	Value contains any additional information that should be displayed for diagnostic purposes. This string is optional and can be of an arbitrary length.
CompanyName	Value identifies the company that produced the file. For example, "Microsoft Corporation" or "Standard Microsystems Corporation, Inc." This string is required.
FileDescription	Value describes the file in such a way that it can be presented to users. This string may be presented in a list box when the user is choosing files to install. For example, "Keyboard driver for AT-style keyboards" or "Microsoft Word for Windows". This string is required.
FileVersion	Value identifies the version of this file. For example, Value could be "3.00A" or "5.00.RC2". This string is required.
InternalName	Value identifies the file's internal name, if one exists. For example, this string would contain the module name for Windows dynamic-link libraries (DLLs), a virtual device name for Windows virtual devices, or a device name for MS-DOS device drivers. This string is required.
LegalCopyright	Value describes all copyright notices, trademarks, and registered trademarks that apply to the file. This should include the full text of all notices, legal symbols, copyright dates, trademark numbers, and so on. This string is optional. In English, this string should be in the format "Copyright Microsoft Corp. 1990−1994".
LegalTrademarks	Value describes all trademarks and registered trademarks that apply to the file. This should include the full text of all notices, legal symbols, trademark numbers, and so on. This string is optional. In English, this string should be in the format "Windows is a trademark of Microsoft Corporation".
OriginalFilename	Value identifies the original name of the file, not including a path. This enables an application to determine whether a file has been renamed by a user. This name may not be MS-DOS 8.3-format if the file is specific to a non-FAT file system. This string is required.
PrivateBuild	Value describes by whom, where, and why this private version of the file was built. This string should only be present if the VS_FF_PRIVATEBUILD flag is set in the dwFileFlags member of the VS_FIXEDFILEINFO structure. For example, Value could be "Built by OSCAR on \OSCAR2".
ProductName	Value identifies the name of the product with which this file is distributed. For example, this string could be "Microsoft Windows". This string is required.
ProductVersion	Value identifies the version of the product with which this file is distributed. For example, Value could be "3.00A" or "5.00.RC2". This string is required.
SpecialBuild	Value describes how this version of the file differs from the normal version. This entry should only be present if the VS_FF_SPECIALBUILD flag is set in the dwFileFlags member of the VS_FIXEDFILEINFO structure. For example, Value could be "Private build for Olivetti solving mouse problems on M250 and M250E computers".
Padding

Contains as many zero bytes as necessary to align the Value member on a 32-bit boundary.

Value

Specifies a zero-terminated string formatted in the language and code page indicated by the current StringTable structure. See the szKey description for more information.

Remarks

A String structure may have an szKey value of, for example, "CompanyName" and a Value of "Microsoft Corporation". Another String structure with the same szKey value could contain a Value of "Microsoft GmbH". This might occur if the second String structure were associated with a StringTable structure whose szKey value is 04070000 — that is, German/ASCII.

See Also

StringTable, VS_FIXEDFILEINFO, VS_VERSION_INFO


StringFileInfo
StringFileInfo  QuickInfo

StringFileInfo {

    WCHAR       szKey[];

    BYTE        Padding[];

    StringTable Children[];

};

The StringFileInfo structure depicts the organization of data in a file-version resource. This structure is not a true C data structure because it contains variable-length members. This structure was created solely to depict the organization of data in a version resource and does not appear in any of the header files shipped with the Microsoft Win32 Software Development Kit (SDK).

The StringFileInfo structure contains version information that must be displayed in a particular language and code page. A code page is an ordered character set.

Members

szKey

Contains "StringFileInfo".

Padding

Contains as many zero bytes as necessary to align the Children member on a 32-bit boundary.

Children

Specifies a list of one or more Children structures. Each StringTable structure's szKey member indicates the appropriate language and code-page formatting.

Remarks

The Children member of the VS_VERSION_INFO structure may contain zero or more StringFileInfo structures.

See Also

StringTable, VS_VERSION_INFO


StringTable
StringTable  QuickInfo

StringTable {

    WCHAR  szKey[];

    BYTE   Padding[];

    String Children[];

};

The StringTable structure depicts the organization of data in a file-version resource. This structure is not a true C data structure because it contains variable-length members. This structure was created solely to depict the organization of data in a version resource and does not appear in any of the header files shipped with the Microsoft Win32 Software Development Kit (SDK).

The StringTable structure contains language and code-page formatting information for the strings specified by the Children member. A code page is an ordered character set.

An executable file or dynamic-link library (DLL) that supports multiple languages should have a version resource for each language, rather than a single version resource that contains strings in several languages.

Members

szKey

Specifies an 8-digit hexadecimal number stored as a string. The four most significant digits represent the language identifier, and the four least significant digits represent the code page for which the data is formatted.

Each Microsoft Standard Language identifier contains two parts: the low-order 10 bits specify the major language, and the high-order 6 bits specify the sublanguage. The following language identifiers are valid:

Identifier	Language
0x0401	Arabic
0x0402	Bulgarian
0x0403	Catalan
0x0404	Traditional Chinese
0x0804	Simplified Chinese
0x0405	Czech
0x0406	Danish
0x0407	German
0x0807	Swiss German
0x0408	Greek
0x0409	U.S. English
0x0809	U.K. English
0x040A	Castilian Spanish
0x080A	Mexican Spanish
0x040B	Finnish
0x040C	French
0x080C	Belgian French
0x0C0C	Canadian French
0x100C	Swiss French
0x040D	Hebrew
0x040E	Hungarian
0x040F	Icelandic
0x0410	Italian
0x0810	Swiss Italian
0x0411	Japanese
0x0412	Korean
0x0413	Dutch
0x0813	Belgian Dutch
0x0414	Norwegian — Bokmål
0x0814	Norwegian — Nynorsk
0x0415	Polish
0x0416	Brazilian Portuguese
0x0816	Portuguese
0x0417	Rhaeto-Romanic
0x0418	Romanian
0x0419	Russian
0x041A	Croato-Serbian (Latin)
0x081A	Serbo-Croatian (Cyrillic)
0x041B	Slovak
0x041C	Albanian
0x041D	Swedish
0x041E	Thai
0x041F	Turkish
0x0420	Urdu
0x0421	Bahasa
The code-page value can be one of the following or any IBM-registered code page:

Code page	Description
0	7-bit ASCII
932	Windows, Japan (Shift — JIS X-0208)
949	Windows, Korea (Shift — KSC 5601)
950	Windows, Taiwan (GB5)
1200	Unicode
1250	Windows, Latin-2 (Eastern European)
1251	Windows, Cyrillic
1252	Windows, Multilingual (ANSI)
1253	Windows, Greek
1254	Windows, Turkish
1255	Windows, Hebrew
1256	Windows, Arabic
Files designed for the English version of Windows would normally be marked with a code-page value of 1252.

Padding

Contains as many zero bytes as necessary to align the Children member on a 32-bit boundary.

Children

Specifies a list of zero or more String structures.

Remarks

The Children member of the StringFileInfo structure contains at least one StringTable structure with an szKey value of "04090000". This value indicates that the language is U.S. English and the code page is generic 7-bit ASCII.

See Also

Strings, StringFileInfo, VS_VERSION_INFO


STYLEBUF [New - Windows 95]
STYLEBUF  QuickInfo  Overview  Group

[New - Windows 95]

typedef struct _tagSTYLEBUF {
    DWORD  dwStyle;
    CHAR  szDescription[32];
} STYLEBUF;

The STYLEBUF structure contains the identifier and name of a style.

Members

dwStyle

Style of the register string. Can be IME_REGWORD_STYLE_EUDC to indicate a string in the EUDC range.

szDescription

Description of the style.


STYLESTRUCT
STYLESTRUCT  QuickInfo

typedef struct tagSTYLESTRUCT {  // ss

    DWORD styleOld;

    DWORD styleNew;

} STYLESTRUCT, * LPSTYLESTRUCT;

The STYLESTRUCT structure contains the window styles for a window.

Members

style

Specifies an array of window style or extended-style flags.

See Also

WM_STYLECHANGED, WM_STYLECHANGING


SYSTEM_ALARM_ACE
SYSTEM_ALARM_ACE  QuickInfo

Reserved for future use.


SYSTEM_AUDIT_ACE
SYSTEM_AUDIT_ACE  QuickInfo

typedef struct _SYSTEM_AUDIT_ACE { // sada

    ACE_HEADER  Header;

    ACCESS_MASK Mask;

    DWORD       SidStart;

} SYSTEM_AUDIT_ACE;

The SYSTEM_AUDIT_ACE structure defines an access-control entry (ACE) for the system access-control list (ACL) specifying what types of access cause system-level notifications. A system-audit ACE causes an audit message to be logged when a specified user or group attempts to gain access to an object. The user or group is identified by a security identifier (SID).

Members

Header

Specifies an ACE_HEADER structure.

Mask

Specifies an ACCESS_MASK structure that gives the access rights causing audit messages to be generated. The SUCCESSFUL_ACCESS_ACE_FLAG and FAILED_ACCESS_ACE_FLAG flags in the AceFlags member of the ACE_HEADER structure indicate whether messages are generated for successful access attempts, unsuccessful access attempts, or both.

SidStart

Specifies a SID. An access attempt of a kind specified by the Mask member by any user or group whose SID matches the SidStart member causes the system to generate an audit message. If an application does not specify a SID for this member, audit messages are generated for the specified access rights for all users and groups.

Remarks

Audit messages are stored in an event log that can be manipulated by using the Win32 API event-logging functions or by using Windows NT Event Viewer (EVENTVWR.EXE).

ACE structures should be aligned on doubleword boundaries. All Windows memory-management functions return doubleword-aligned handles to memory.

See Also

ACCESS_ALLOWED_ACE, ACCESS_DENIED_ACE, ACCESS_MASK, ACE_HEADER, ACL, SYSTEM_ALARM_ACE


SYSTEM_INFO
SYSTEM_INFO  QuickInfo

typedef struct _SYSTEM_INFO { // sinf

    union {

        DWORD  dwOemId;

        struct {

            WORD wProcessorArchitecture;

            WORD wReserved;

        };

    };

    DWORD  dwPageSize;

    LPVOID lpMinimumApplicationAddress;

    LPVOID lpMaximumApplicationAddress;

    DWORD  dwActiveProcessorMask;

    DWORD  dwNumberOfProcessors;

    DWORD  dwProcessorType;

    DWORD  dwAllocationGranularity;

    WORD  wProcessorLevel;

    WORD  wProcessorRevision;

} SYSTEM_INFO;

The SYSTEM_INFO structure contains information about the current computer system. This includes the processor type, page size, original equipment manufacturer (OEM) identifier, and other such information.

Members

dwOemId

Windows 95: The system always sets this parameter to zero, the value defined for PROCESSOR_ARCHITECTURE_INTEL.

Windows NT: On Windows NT, use wProcessorArchitecture.

wProcessorArchitecture

Specifies the system's processor architecture. This value can be one of the following:

Platform	Value
Windows 95	PROCESSOR_ARCHITECTURE_INTEL
Windows NT	PROCESSOR_ARCHITECTURE_INTEL PROCESSOR_ARCHITECTURE_MIPS PROCESSOR_ARCHITECTURE_ALPHA PROCESSOR_ARCHITECTURE_PPC
wReserved

Reserved for future use.

dwPageSize

Returns the page size and specifies the granularity of page protection and commitment.

lpMinimumApplicationAddress

Returns the lowest memory address accessible to applications and dynamic-link libraries (DLLs).

lpMaximumApplicationAddress

Returns the highest memory address accessible to applications and DLLs.

dwActiveProcessorMask

Returns a mask representing the set of processors configured into the system. Bit 0 is processor 0; bit 31 is processor 31.

dwNumberOfProcessors

Returns the number of processors in the system.

dwProcessorType

No longer relevant but is retained for compatibility with Windows 95 and previous versions of Windows NT. It can be one of the following values:

Platform	Value
Windows 95	PROCESSOR_INTEL_386 PROCESSOR_INTEL_486 PROCESSOR_INTEL_PENTIUM
Windows NT	PROCESSOR_INTEL_386 PROCESSOR_INTEL_486 PROCESSOR_INTEL_PENTIUM PROCESSOR_MIPS_R4000 PROCESSOR_ALPHA_21046
dwAllocationGranularity

Returns the allocation granularity in which memory will be allocated on. This value was hard coded as 64K in the past, but other hardware architectures may require different values.

wProcessorLevel

Specifies the system's architecture-dependent processor level. This parameter can be one of the following:

Processor Architecture	Value
PROCESSOR_ARCHITECTURE_INTEL	3 - 80386 4 - 80486 5 - Pentium
PROCESSOR_ARCHITECTURE_MIPS	00xx - Where xx is an 8-bit implementation number (bits 8-15 of the PRid register. 0004 - R4000
PROCESSOR_ARCHITECTURE_ALPHA	xxxx where xxxx is a 16-bit processor version number (the low-order 16 bits of a version number from the firmware. 21064 - 21064 21066 - 21066 21164 - 21164
PROCESSOR_ARCHITECTURE_PPC	xxxx - where xxxx is a 16-bit processor version number (the high-order 16 bits of the Processor Version Register. 1  -  601 3  -  603 4  -  604 6  -  603+ 9  -  604+ 20 - 620
wProcessorRevision

Specifies an architecture-dependent processor revision. The following shows how appropriate revision values for each type of processor architecture are assembled.

Processor Architecture	Value
PROCESSOR_ARCHITECTURE_INTEL	Intel 80386 or 80486: xxyy - where xx + 'A' is the stepping level and yy is the stepping, so 0300 is a D0 chip. Intel Pentium or Cyrex/NextGen 486: xxyy - where xx is the model number and yy is the stepping, so 0201 is Model 2, Stepping 1.
PROCESSOR_ARCHITECTURE_MIPS	00xx is the 8-bit revision number of the processor (the low-order 8 bits of the PRId register).
PROCESSOR_ARCHITECTURE_ALPHA	xxxx where xxxx is a 16-bit processor revision number (the low-order 16 bits of the processor revision number from the firmware). It is displayed as:  Model 'A'+xx, Pass yy
PROCESSOR_ARCHITECTURE_PPC	xxyy - where xxyy is a 16-bit processor revision number (the low-order 16 bits of the Processor Version Register). it is displayed as a fixed point number xx.yy.
See Also

GetSystemInfo, MapViewOfFile, MapViewOfFileEx


SYSTEM_POWER_STATUS [New - Windows 95]
SYSTEM_POWER_STATUS  QuickInfo  Overview  Group

[New - Windows 95]

typedef struct _SYSTEM_POWER_STATUS {
    BYTE ACLineStatus;
    BYTE  BatteryFlag;
    BYTE  BatteryLifePercent;
    BYTE  Reserved1;
    DWORD  BatteryLifeTime;
    DWORD  BatteryFullLifeTime;
} SYSTEM_POWER_STATUS;
typedef struct SYSTEM_POWER_STATUS *LPSYSTEM_POWER_STATUS;

The SYSTEM_POWER_STATUS structure contains information about the power status of the system.

Members

ACLineStatus

AC power status. This parameter can be one of the following values:

Value	Meaning
0	Offline
1	Online
255	Unknown status.
All other values are reserved.

BatteryFlag

Battery charge status. This parameter can be a combination of the following values:

Value	Meaning
1	High
2	Low
4	Critical
8	Charging
128	No system battery
255	Unknown status
All other values are reserved.

BatteryLifePercent

Percentage of full battery charge remaining. This member can be a value in the range 0 to 100, or 255 if status is unknown. All other values are reserved.

Reserved1

Reserved; must be zero.

BatteryLifeTime

Number of seconds of battery life remaining, or 0xFFFFFFFF if remaining seconds are unknown.

BatteryFullLifeTime

Number of seconds of battery life when at full charge, or 0xFFFFFFFF if full lifetime is unknown.

Remarks

Windows 95 is only capable of estimating BatteryFullTime based on calculations on BatteryLifeTime and BatteryLifePercent. Without smart battery subsystems, this value may not be accurate enough to be useful.


SYSTEMTIME
SYSTEMTIME  QuickInfo

typedef struct _SYSTEMTIME {  // st

    WORD wYear;

    WORD wMonth;

    WORD wDayOfWeek;

    WORD wDay;

    WORD wHour;

    WORD wMinute;

    WORD wSecond;

    WORD wMilliseconds;

} SYSTEMTIME;

The SYSTEMTIME structure represents a date and time using individual members for the month, day, year, weekday, hour, minute, second, and millisecond.

Members

wYear

Specifies the current year.

wMonth

Specifies the current month; January = 1, February = 2, and so on.

wDayOfWeek

Specifies the current day of the week; Sunday = 0, Monday = 1, and so on.

wDay

Specifies the current day of the month.

wHour

Specifies the current hour.

wMinute

Specifies the current minute.

wSecond

Specifies the current second.

wMilliseconds

Specifies the current millisecond.

See Also

GetLocalTime, GetSystemTime, SetLocalTime, SetSystemTime, FILETIME


TAPE_ERASE
TAPE_ERASE  QuickInfo

typedef struct _TAPE_ERASE { // ter

    ULONG Type;

} TAPE_ERASE;

The TAPE_ERASE structure describes the partition to be erased.

Members

Type

Specifies how to erase the tape. This member must have one of the following values:

Value	Description
TAPE_ERASE_LONG	Erases the entire partition.
TAPE_ERASE_SHORT	Erases only the partition's header block.


TAPE_GET_DRIVE_PARAMETERS
TAPE_GET_DRIVE_PARAMETERS  QuickInfo

typedef struct _TAPE_GET_DRIVE_PARAMETERS { // tgdp

    BOOLEAN ECC;

    BOOLEAN Compression;

    BOOLEAN DataPadding;

    BOOLEAN ReportSetmarks;

    ULONG   DefaultBlockSize;

    ULONG   MaximumBlockSize;

    ULONG   MinimumBlockSize;

    ULONG   MaximumPartitionCount;

    ULONG   FeaturesLow;

    ULONG   FeaturesHigh;

    ULONG   EOTWarningZoneSize;

} TAPE_GET_DRIVE_PARAMETERS;

The TAPE_GET_DRIVE_PARAMETERS structure describes the tape drive.

Members

ECC

Specifies whether the device supports hardware error correction. This member is TRUE if hardware error correction is supported.

Compression

Specifies whether hardware data compression is enabled or disabled. This member is TRUE if hardware data compression is enabled.

DataPadding

Specifies whether data padding is enabled or disabled. Data padding keeps the tape streaming at a constant speed. This member is TRUE if data padding is enabled.

ReportSetmarks

Specifies whether setmark reporting is enabled or disabled. This member is TRUE if setmark reporting is enabled.

DefaultBlockSize

Specifies the device's default fixed block size.

MaximumBlockSize

Specifies the device's maximum block size.

MinimumBlockSize

Specifies the device's minimum block size.

MaximumPartitionCount

Specifies the maximum number of partitions that can be created on the device.

FeaturesLow

Specifies the low-order 32 bits of the device features flag. This member can be one or more of following values:

Value	Meaning
TAPE_DRIVE_COMPRESSION	The device supports hardware data compression.
TAPE_DRIVE_ECC	The device supports hardware error correction.
TAPE_DRIVE_ERASE_BOP_ONLY	The device performs the erase operation from the beginning-of-partition marker only.
TAPE_DRIVE_ERASE_LONG	The device performs a long erase operation.
TAPE_DRIVE_ERASE_IMMEDIATE	The device performs an immediate erase operation —  that is, it returns when the erase operation begins.
TAPE_DRIVE_ERASE_SHORT	The device performs a short erase operation.
TAPE_DRIVE_FIXED	The device creates fixed data partitions.
TAPE_DRIVE_FIXED_BLOCK	The device supports fixed-length block mode.
TAPE_DRIVE_INITIATOR	The device creates initiator-defined partitions.
TAPE_DRIVE_PADDING	The device supports data padding.
TAPE_DRIVE_GET_ABSOLUTE_BLK	The device provides the current device-specific block address.
TAPE_DRIVE_GET_LOGICAL_BLK	The device provides the current logical block address (and logical tape partition).
TAPE_DRIVE_REPORT_SMKS	The device supports setmark reporting.
TAPE_DRIVE_SELECT	The device creates select data partitions.
TAPE_DRIVE_SET_EOT_WT_SIZE	The device supports setting the end-of-medium warning size.
TAPE_DRIVE_TAPE_CAPACITY	The device returns the maximum capacity of the tape.
TAPE_DRIVE_TAPE_REMAINING	The device returns the remaining capacity of the tape.
TAPE_DRIVE_VARIABLE_BLOCK	The device supports variable-length block mode.
TAPE_DRIVE_WRITE_PROTECT	The device returns an error if the tape is write-enabled or write-protected.
FeaturesHigh

Contains the high-order 32 bits of the device features flag. This member can be one or more of the following values:

Value	Meaning
TAPE_DRIVE_ABS_BLK_IMMED	The device moves the tape to a device-specific block address and returns as soon as the move begins.
TAPE_DRIVE_ABSOLUTE_BLK	The device moves the tape to a device specific block address.
TAPE_DRIVE_END_OF_DATA	The device moves the tape to the end-of-data marker in a partition.
TAPE_DRIVE_FILEMARKS	The device moves the tape forward (or backward) a specified number of filemarks.
TAPE_DRIVE_LOAD_UNLOAD	The device enables and disables the device for further operations.
TAPE_DRIVE_LOAD_UNLOAD_IMMED	The device supports immediate load and unload operations.
TAPE_DRIVE_LOCK_UNLOCK	The device enables and disables the tape ejection mechanism.
TAPE_DRIVE_LOCK_UNLK_IMMED	The device supports immediate lock and unlock operations.
TAPE_DRIVE_LOG_BLK_IMMED	The device moves the tape to a logical block address in a partition and returns as soon as the move begins.
TAPE_DRIVE_LOGICAL_BLK	The device moves the tape to a logical block address in a partition.
TAPE_DRIVE_RELATIVE_BLKS	The device moves the tape forward (or backward) a specified number of blocks.
TAPE_DRIVE_REVERSE_POSITION	The device moves the tape backward over blocks, filemarks, or setmarks.
TAPE_DRIVE_REWIND_IMMEDIATE	The device supports immediate rewind operation.
TAPE_DRIVE_SEQUENTIAL_FMKS	The device moves the tape forward (or backward) to the first occurrence of a specified number of consecutive filemarks.
TAPE_DRIVE_SEQUENTIAL_SMKS	The device moves the tape forward (or backward) to the first occurrence of a specified number of consecutive setmarks.
TAPE_DRIVE_SET_BLOCK_SIZE	The device supports setting the size of a fixed-length logical block or setting the variable-length block mode.
TAPE_DRIVE_SET_COMPRESSION	The device enables and disables hardware data compression.
TAPE_DRIVE_SET_ECC	The device enables and disables hardware error correction.
TAPE_DRIVE_SET_PADDING	The device enables and disables data padding.
TAPE_DRIVE_SET_REPORT_SMKS	The device enables and disables the reporting of setmarks.
TAPE_DRIVE_SETMARKS	The device moves the tape forward (or reverse) a specified number of setmarks.
TAPE_DRIVE_SPACE_IMMEDIATE	The device supports immediate spacing.
TAPE_DRIVE_TENSION	The device supports tape tensioning.
TAPE_DRIVE_TENSION_IMMED	The device supports immediate tape tensioning.
TAPE_DRIVE_WRITE_FILEMARKS	The device writes filemarks.
TAPE_DRIVE_WRITE_LONG_FMKS	The device writes long filemarks.
TAPE_DRIVE_WRITE_MARK_IMMED	The device supports immediate writing of short and long filemarks.
TAPE_DRIVE_WRITE_SETMARKS	The device writes setmarks.
TAPE_DRIVE_WRITE_SHORT_FMKS	The device writes short filemarks.
EOTWarningZoneSize

Indicates the number of bytes between the end-of-tape warning and the physical end of the tape.


TAPE_GET_MEDIA_PARAMETERS
TAPE_GET_MEDIA_PARAMETERS  QuickInfo

typedef struct _TAPE_GET_MEDIA_PARAMETERS {  // tgmp

    LARGE_INTEGER   Capacity;

    LARGE_INTEGER   Remaining;

    DWORD   BlockSize;

    DWORD   PartitionCount;

    BOOLEAN WriteProtected;

} TAPE_GET_MEDIA_PARAMETERS;

The TAPE_GET_MEDIA_PARAMETERS structure describes the tape in the tape drive.

Members

Capacity

Specifies the total number of bytes on the current tape partition.

Remaining

Specifies the number of bytes between the current position and the end of the current tape partition.

BlockSize

Specifies the number of bytes per block.

PartitionCount

Specifies the number of partitions on the tape.

WriteProtected

Specifies whether the tape is write-protected. If this member is TRUE, the tape is write-protected.

Remarks

The GetTapeParameters function fills the Remaining and Capacity members with estimates of the tape remaining in the current tape partition and the total capacity of the current tape partition.

See Also

GetTapeParameters


TAPE_GET_POSITION
TAPE_GET_POSITION  QuickInfo

typedef struct _TAPE_GET_POSITION { // tgpos

    ULONG Type;

    ULONG Partition;

    ULONG OffsetLow;

    ULONG OffsetHigh;

} TAPE_GET_POSITION;

The TAPE_GET_POSITION structure describes the position of the tape.

Members

Type

Specifies the type of position. This member must be one of the following values:

Value	Description
TAPE_ABSOLUTE_POSITION	The position specified by the OffsetLow and OffsetHigh members is an absolute number of blocks from the beginning of the partition specified by the Partition member.
TAPE_LOGICAL_POSITION	The position specified by OffsetLow and OffsetHigh is relative to the current position in the partition specified by Partition.
Partition

Specifies the partition to position within. If this member is zero, the current partition is assumed.

OffsetLow

Specifies the low-order 32 bits of the block address.

OffsetHigh

Specifies the high-order 32 bits of the block address. If the high-order 32 bits are not required, this member should be zero.


TAPE_PREPARE
TAPE_PREPARE  QuickInfo

typedef struct _TAPE_PREPARE { // tp

    ULONG Operation;

} TAPE_PREPARE;

The TAPE_PREPARE structure describes how to prepare the tape.

Members

Operation

Specifies how to prepare the tape. This member must be one of the following values:

Value	Description
TAPE_LOCK	Locks the tape ejection mechanism so that the tape is not ejected accidentally during a tape operation.
TAPE_TENSION	Moves to the end of the tape and rewinds to the beginning of the tape. This value is ignored if the tape device does not support tensioning.
TAPE_UNLOAD	Rewinds and unloads the tape.
TAPE_UNLOCK	Unlocks the tape ejection mechanism.


TAPE_SET_DRIVE_PARAMETERS
TAPE_SET_DRIVE_PARAMETERS  QuickInfo

typedef struct _TAPE_SET_DRIVE_PARAMETERS {  // tsdp

    BOOLEAN ECC;

    BOOLEAN Compression;

    BOOLEAN DataPadding;

    BOOLEAN ReportSetmarks;

    ULONG   EOTWarningZoneSize;

} TAPE_SET_DRIVE_PARAMETERS;

The TAPE_SET_DRIVE_PARAMETERS structure describes the tape drive.

Members

ECC

Specifies whether the device supports hardware error correction. This member is TRUE if hardware error correction is supported.

Compression

Specifies whether hardware data compression is enabled or disabled. This member is TRUE if hardware data compression is enabled.

DataPadding

Specifies whether data padding is enabled or disabled. Data padding keeps the tape streaming at a constant speed. This member is TRUE if data padding is enabled.

ReportSetmarks

Specifies whether setmark reporting is enabled or disabled. This member is TRUE if setmarks are enabled.

EOTWarningZoneSize

Specifies the number of bytes between the end-of-tape warning and the physical end of the tape.


TAPE_SET_MEDIA_PARAMETERS
TAPE_SET_MEDIA_PARAMETERS  QuickInfo

typedef struct _TAPE_SET_MEDIA_PARAMETERS { // tsmp

    ULONG BlockSize;

} TAPE_SET_MEDIA_PARAMETERS;

The TAPE_SET_MEDIA_PARAMETERS structure describes the tape in the tape drive.

Members

BlockSize

Specifies the number of bytes per block. Maximum and minimum block sizes can be obtained by calling the GetTapeParameters function.

Remarks

There is no longer a requirement that block sizes be powers of 2.

See Also

GetTapeParameters, SetTapeParameters


TAPE_SET_POSITION
TAPE_SET_POSITION  QuickInfo

typedef struct _TAPE_SET_POSITION { // tspos

    ULONG Method;

    ULONG Partition;

    ULONG OffsetLow;

    ULONG OffsetHigh;

} TAPE_SET_POSITION;

The TAPE_SET_POSITION structure describes how and where to position the tape.

Members

Method

Specifies the type of positioning. This member must be one of the following values:

Value	Description
TAPE_ABSOLUTE_BLOCK	Moves the tape to the device-specific block address specified by the OffsetLow and OffsetHigh members. The Partition member is ignored.
TAPE_LOGICAL_BLOCK	Moves the tape to the block address specified by OffsetLow and OffsetHigh in the partition specified by Partition.
TAPE_REWIND	Moves the tape to the beginning of the current partition. The Partition, OffsetLow, and OffsetHigh members are ignored.
TAPE_SPACE_END_OF_DATA	Moves the tape to the end of the data on the partition specified by Partition.
TAPE_SPACE_FILEMARKS	Moves the tape forward (or backward) the number of filemarks specified by OffsetLow and OffsetHigh in the current partition. The Partition member is ignored.
TAPE_SPACE_RELATIVE_BLOCKS	Moves the tape forward (or backward) the number of blocks specified by OffsetLow and OffsetHigh in the current partition. The Partition member is ignored.
TAPE_SPACE_SEQUENTIAL_FMKS	Moves the tape forward (or backward) to the first occurrence of n filemarks in the current partition, where n is the number specified by OffsetLow and OffsetHigh. The Partition parameter is ignored.
TAPE_SPACE_SEQUENTIAL_SMKS	Moves the tape forward (or backward) to the first occurrence of n setmarks in the current partition, where n is the number specified by OffsetLow and OffsetHigh. The Partition member is ignored.
TAPE_SPACE_SETMARKS	Moves the tape forward (or backward) the number of setmarks specified by OffsetLow and OffsetHigh in the current partition. The Partition member is ignored.
Partition

Specifies the partition to position within. If this member is zero, the current partition is assumed.

OffsetLow

Specifies the low-order 32 bits of the block address or count for the position operation specified by the Method member.

OffsetHigh

Specifies the high-order 32 bits of the block address or count for the position operation specified by the Method member. If the high-order 32 bits are not required, this member should be zero.

Remarks

If the positioning is relative, a positive offset moves the tape forward (toward the end of the tape) and a negative offset moves the tape backward (toward the beginning of the tape).


TAPE_WRITE_MARKS
TAPE_WRITE_MARKS  QuickInfo

typedef struct _TAPE_WRITE_MARKS { // twm

    ULONG Type;

    ULONG Count;

} TAPE_WRITE_MARKS;

The TAPE_WRITE_MARKS structure describes the type and number of tapemarks to write.

Members

Type

Specifies the type of tapemark to write. This member can be one of the following values:

Value	Description
TAPE_LONG_FILEMARKS	Writes long filemarks.
TAPE_SEQUENTIAL_FILEMARKS	Writes sequential filemarks.
TAPE_SETMARKS	Writes setmarks.
TAPE_SHORT_FILEMARKS	Writes short filemarks.
Count

Specifies the number of tapemarks to write.


TBADDBITMAP [New - Windows NT]
TBADDBITMAP  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct {  // tbab

    HINSTANCE hInst;

    UINT nID;

} TBADDBITMAP, *LPTBADDBITMAP;

The TBADDBITMAP structure adds a bitmap that contains button images to a toolbar.

Members

hInst

Handle to the module instance with the executable file that contains a bitmap resource. You can add the system-defined button bitmaps to the list by specifying HINST_COMMCTRL as the hInst member and one of the following values as the nID member:

Value	Meaning
IDB_STD_LARGE_COLOR	Adds large, color standard bitmaps.
IDB_STD_SMALL_COLOR	Adds small, color standard bitmaps.
IDB_VIEW_LARGE_COLOR	Adds large, color view bitmaps.
IDB_VIEW_SMALL_COLOR	Adds small, color view bitmaps.
For more information about the system-defined standard and view bitmaps, see the following Remarks section.

nID

Resource identifier of the bitmap resource that contains the button images. If hInst is NULL, this parameter must be the handle to a bitmap that contains the button images.

Remarks

The Windows header files provide the following values that you use as indexes to the standard and view bitmaps.

STD_COPY	STD_PASTE
STD_CUT	STD_PRINT
STD_DELETE	STD_PRINTPRE
STD_FILENEW	STD_PROPERTIES
STD_FILEOPEN	STD_REDOW
STD_FILESAVE	STD_REPLACE
STD_FIND	STD_UNDO
STD_HELP
VIEW_LARGEICONS	VIEW_SORTNAME
VIEW_SMALLICONS	VIEW_SORTSIZE
VIEW_LIST	VIEW_SORTDATE
VIEW_DETAILS	VIEW_SORTTYPE
The TBADDBITMAP structure is used with the TB_ADDBITMAP message.

See Also

TB_ADDBITMAP


TBBUTTON [New - Windows NT]
TBBUTTON  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct _TBBUTTON { \\ tbb

    int iBitmap;

    int idCommand;

    BYTE fsState;

    BYTE fsStyle;

    DWORD dwData;

    int iString;

} TBBUTTON, NEAR* PTBBUTTON, FAR* LPTBBUTTON;

typedef const TBBUTTON FAR* LPCTBBUTTON;

The TBBUTTON structure contains information about a button in a toolbar.

Members

iBitmap

Zero-based index of button image.

idCommand

Command identifier associated with the button. This identifier is used in a WM_COMMAND message when the button is chosen. If the fsStyle member is the TBSTYLE_SEP value, this member must be zero.

fsState

Button state flags. This member can be a combination of the values listed in Toolbar Button States.

fsStyle

Button style. This member can be a combination of values listed in Toolbar Button Styles

dwData

Application-defined value.

iString

Zero-based index of button string.

See Also

WM_COMMAND


TBNOTIFY [New - Windows NT]
TBNOTIFY  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct { \\ tbn

    NMHDR hdr;

    int iItem;

    TBBUTTON tbButton;

    int cchText;

    LPTSTR pszText;

} TBNOTIFY, FAR* LPTBNOTIFY;

The TBNOTIFY structure contains information used to process notification messages from a toolbar.

Members

hdr

Required for all WM_NOTIFY messages.

iItem

Index of the button associated with notification.

tbButton

Address of a TBBUTTON structure that contains information about the toolbar button associated with the notification.

cchText

Count of characters in the button text.

pszText

Address of the button text.

See Also

TBBUTTON, WM_NOTIFY


TBSAVEPARAMS [New - Windows NT]
TBSAVEPARAMS  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct { \\ tbsr

    HKEY hkr;

    LPCTSTR pszSubKey;

    LPCTSTR pszValueName;

} TBSAVEPARAMS;

The TBSAVEPARAMS function specifies the location in the registry where the TB_SAVERESTORE message stores and retrieves information about the state of a toolbar.

Members

hkr

Handle to the registry key.

pszSubKey

Subkey name.

pszValueName

Value name.

See Also

TB_SAVERESTORE


TC_HITTESTINFO [New - Windows NT]
TC_HITTESTINFO  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct _TC_HITTESTINFO {

    POINT pt;     // position to hit test, in client coordinates

    UINT  flags;  // variable to receive hit test results

} TC_HITTESTINFO;

The TC_HITTESTINFO structure contains information about a hit test.

Members

pt

Position to hit test, in client coordinates.

flags

Variable that receives the results of a hit test. The tab control sets this member to one of the following values:

Value	Meaning
TCHT_NOWHERE	The position is not over a tab.
TCHT_ONITEM	The position is over a tab, but not over its icon or its text. For owner-drawn tab controls, this value is specified if the position is anywhere over a tab.
TCHT_ONITEMICON	The position is over a tab's icon.
TCHT_ONITEMLABEL	The position is over a tab's text.
TCHT_ONITEM is a bitwise OR operation on TCHT_ONITEMICON and TCHT_ONITEMLABEL.

Remarks

This structure is used with the TCM_HITTEST message.

See Also

TCM_HITTEST


TC_ITEM [New - Windows NT]
TC_ITEM  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct _TC_ITEM {

    UINT mask;         // value specifying which members to retrieve or set

    UINT lpReserved1;  // reserved; do not use

    UINT lpReserved2;  // reserved; do not use

    LPSTR pszText;     // pointer to string containing tab text

    int cchTextMax;    // size of buffer pointed to by the pszText member

    int iImage;        // index to tab control's image

    LPARAM lParam;     // application-defined data associated with tab

} TC_ITEM;

The TC_ITEM structure specifies or receives the attributes of a tab.

Members

mask

Value specifying which members to retrieve or set. This member can be TCIF_ALL (meaning all members), or zero or more of the following values:

Value	Meaning
TCIF_TEXT	The pszText member is valid.
TCIF_IMAGE	The iImage member is valid.
TCIF_PARAM	The lParam member is valid.
TCIF_RTLREADING	Windows 95 only: Displays the text of pszText using right-to-left reading order on Hebrew or Arabic systems.
lpReserved1

Reserved; do not use.

lpReserved2

Reserved; do not use.

pszText

Pointer to a null-terminated string that contains the tab text if the structure contains information about a tab. If the structure is receiving information, this member specifies the address of the buffer that receives the tab text.

cchTextMax

Size of the buffer pointed to by the pszText member. If the structure is not receiving information, this member is ignored.

iImage

Index into the tab control's image list or  − 1 if there is no image for the tab.

lParam

Application-defined data associated with the tab. If there are more or less than 4 bytes of application-defined data per tab, an application must define a structure and use it instead of the TC_ITEM structure. The first member of the application-defined structure must be a TC_ITEMHEADER structure.

This structure is used with the TCM_INSERTITEM, TCM_GETITEM, and TCM_SETITEM messages.

See Also

TCM_GETITEM, TCM_INSERTITEM, TC_ITEMHEADER, TCM_SETITEM


TC_ITEMHEADER [New - Windows NT]
TC_ITEMHEADER  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct _TC_ITEMHEADER {

    UINT mask;         // value specifying which members to retrieve or set

    UINT lpReserved1;  // reserved; do not use

    UINT lpReserved2;  // reserved; do not use

    LPSTR pszText;     // pointer to string containing tab text

    int cchTextMax;    // size of buffer pointed to by the pszText member

    int iImage;        // index to tab control's image

} TC_ITEMHEADER;

The TC_ITEMHEADER structure specifies or receives the attributes of a tab. This structure is the same as the TC_ITEM structure, that it does not include an lParam member for application-defined data.

Members

mask

Value specifying which members to retrieve or set. This member can be TCIF_ALL (meaning all members), or zero or more of the following values:

Value	Meaning
TCIF_TEXT	The pszText member is valid.
TCIF_IMAGE	The iImage member is valid.
TCIF_PARAM	The lParam member is valid.
TCIF_RTLREADING	Windows 95 only: Displays the text of pszText using right-to-left reading order on Hebrew or Arabic systems.
lpReserved1

Reserved; do not use.

lpReserved2

Reserved; do not use.

pszText

Pointer to a null-terminated string that contains the tab text if the structure contains information about a tab. If the structure is receiving information, this member specifies the address of the buffer that receives the tab text.

cchTextMax

Size of the buffer pointed to by the pszText member. If the structure is not receiving information, this member is ignored.

iImage

Index into the tab control's image list or  − 1 if there is no image for the tab.

Remarks

An application cannot use the TC_ITEM structure to retrieve or set the application-defined data for tabs in a tab control with more or less than four extra bytes per tab. Instead, you should define a structure that consists of the TC_ITEMHEADER structure followed by application-defined data.

To set the number of extra bytes per tab, use the TCM_SETITEMEXTRA message.

See Also

TC_ITEM, TCM_SETITEMEXTRA


TC_KEYDOWN [New - Windows NT]
TC_KEYDOWN  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct _TC_KEYDOWN {

    NMHDR hdr;    // notification header

    WORD wVKey;   // virtual-key code

    UINT flags;
} TC_KEYDOWN;

The TC_KEYDOWN structure contains information about a key press in a tab control. This structure is used with the TCN_KEYDOWN notification message.

Members

hdr

Notification header

wVKey

Virtual key code.

flags

Same as the lParam parameter of the WM_KEYDOWN message.

See Also

TCN_KEYDOWN, WM_KEYDOWN


TEXTMETRIC
TEXTMETRIC  QuickInfo

typedef struct tagTEXTMETRIC { // tm

    LONG tmHeight;

    LONG tmAscent;

    LONG tmDescent;

    LONG tmInternalLeading;

    LONG tmExternalLeading;

    LONG tmAveCharWidth;

    LONG tmMaxCharWidth;

    LONG tmWeight;

    LONG tmOverhang;

    LONG tmDigitizedAspectX;

    LONG tmDigitizedAspectY;

    BCHAR tmFirstChar;

    BCHAR tmLastChar;

    BCHAR tmDefaultChar;

    BCHAR tmBreakChar;

    BYTE tmItalic;

    BYTE tmUnderlined;

    BYTE tmStruckOut;

    BYTE tmPitchAndFamily;

    BYTE tmCharSet;

} TEXTMETRIC;

The TEXTMETRIC structure contains basic information about a physical font. All sizes are given in logical units; that is, they depend on the current mapping mode of the display context.

Members

tmHeight

Specifies the height (ascent + descent) of characters.

tmAscent

Specifies the ascent (units above the base line) of characters.

tmDescent

Specifies the descent (units below the base line) of characters.

tmInternalLeading

Specifies the amount of leading (space) inside the bounds set by the tmHeight member. Accent marks and other diacritical characters may occur in this area. The designer may set this member to zero.

tmExternalLeading

Specifies the amount of extra leading (space) that the application adds between rows. Since this area is outside the font, it contains no marks and is not altered by text output calls in either OPAQUE or TRANSPARENT mode. The designer may set this member to zero.

tmAveCharWidth

Specifies the average width of characters in the font (generally defined as the width of the letter x). This value does not include the overhang required for bold or italic characters.

tmMaxCharWidth

Specifies the width of the widest character in the font.

tmWeight

Specifies the weight of the font.

tmOverhang

Specifies the extra width per string that may be added to some synthesized fonts. When synthesizing some attributes, such as bold or italic, graphics device interface (GDI) or a device may have to add width to a string on both a per-character and per-string basis. For example, GDI makes a string bold by expanding the spacing of each character and overstriking by an offset value; it italicizes a font by shearing the string. In either case, there is an overhang past the basic string. For bold strings, the overhang is the distance by which the overstrike is offset. For italic strings, the overhang is the amount the top of the font is sheared past the bottom of the font.

The tmOverhang member enables the application to determine how much of the character width returned by a GetTextExtentPoint32 function call on a single character is the actual character width and how much is the per-string extra width. The actual width is the extent minus the overhang.

tmDigitizedAspectX

Specifies the horizontal aspect of the device for which the font was designed.

tmDigitizedAspectY

Specifies the vertical aspect of the device for which the font was designed. The ratio of the tmDigitizedAspectX and tmDigitizedAspectY members is the aspect ratio of the device for which the font was designed.

tmFirstChar

Specifies the value of the first character defined in the font.

tmLastChar

Specifies the value of the last character defined in the font.

tmDefaultChar

Specifies the value of the character to be substituted for characters not in the font.

tmBreakChar

Specifies the value of the character that will be used to define word breaks for text justification.

tmItalic

Specifies an italic font if it is nonzero.

tmUnderlined

Specifies an underlined font if it is nonzero.

tmStruckOut

Specifies a strikeout font if it is nonzero.

tmPitchAndFamily

Specifies information about the pitch, the technology, and the family of a physical font.

The four low-order bits of this member specify information about the pitch and the technology of the font. A constant is defined for each of the four bits:

Constant	Meaning
TMPF_FIXED_PITCH	If this bit is set the font is a variable pitch font. If this bit is clear the font is a fixed pitch font. Note very carefully that those meanings are the opposite of what the constant name implies.
TMPF_VECTOR	If this bit is set the font is a vector font.
TMPF_TRUETYPE	If this bit is set the font is a TrueType font.
TMPF_DEVICE	If this bit is set the font is a device font.
An application should carefully test for qualities encoded in these low-order bits, making no arbitrary assumptions. For example, besides having their own bits set, TrueType and PostScript fonts set the TMPF_VECTOR bit. A monospace bitmap font has all of these low-order bits clear; a proportional bitmap font sets the TMPF_FIXED_PITCH bit. A Postscript printer device font sets the TMPF_DEVICE, TMPF_VECTOR, and TMPF_FIXED_PITCH bits.

The four high-order bits of tmPitchAndFamily designate the font's font family. An application can use the value 0xF0 and the bitwise AND operator to mask out the four low-order bits of tmPitchAndFamily, thus obtaining a value that can be directly compared with font family names to find an identical match. For information about font families, see the description of the LOGFONT structure.

tmCharSet

Specifies the character set of the font.

See Also

GetTextMetrics, GetTextExtentPoint32, LOGFONT


TEXTRANGE [New - Windows NT]
TEXTRANGE  QuickInfo  Overview  Group

[New - Windows NT]

pedef struct _textrange {

    CHARRANGE chrg;

    LPSTR lpstrText;

} TEXTRANGE;

The TEXTRANGE structure receives a range of text from a rich edit control. This structure is filled in by the EM_GETTEXTRANGE message. The buffer pointed to by the lpstrText member must be large enough to receive all characters and the teminating null character.

Members

chrg

Range of characters to get.

lpstrText

Pointer to buffer to receive the text.

See Also

EM_GETTEXTRANGE


TIME_ZONE_INFORMATION
TIME_ZONE_INFORMATION  QuickInfo

typedef struct _TIME_ZONE_INFORMATION { // tzi

    LONG       Bias;

    WCHAR      StandardName[ 32 ];

    SYSTEMTIME StandardDate;

    LONG       StandardBias;

    WCHAR      DaylightName[ 32 ];

    SYSTEMTIME DaylightDate;

    LONG       DaylightBias;

} TIME_ZONE_INFORMATION;

The TIME_ZONE_INFORMATION structure specifies information specific to the time zone.

Members

Bias

Specifies the current bias, in minutes, for local time translation on this computer. The bias is the difference, in minutes, between Coordinated Universal Time (UTC) and local time. All translations between UTC and local time are based on the following formula:

UTC = local time + bias

This member is required.

StandardName

Specifies a null-terminated string associated with standard time on this operating system. For example, this parameter could contain "EST" to indicate Eastern Standard Time. This string is not used by the operating system, so anything stored there by using the SetTimeZoneInformation function is returned unchanged by the GetTimeZoneInformation function. This string can be empty.

StandardDate

Specifies a SYSTEMTIME structure that contains a date and UTC when the transition from daylight time to standard time occurs on this operating system. If this date is not specified, the wMonth member in the SYSTEMTIME structure must be zero. If this date is specified, the DaylightDate value in the TIME_ZONE_INFORMATION structure must also be specified. Local time translations done during the standard-time range are relative to the supplied StandardBias value.

This member supports two date formats. Absolute format specifies an exact date and time when standard time begins. In this form, the wYear, wMonth, wDay, wHour, wMinute, wSecond, and wMilliseconds members of the SYSTEMTIME structure are used to specify an exact date.

Day-in-month format is specified by setting the wYear member to zero, setting the wDayOfWeek member to an appropriate weekday, and using a wDay value in the range 1 through 5 to select the correct day in the month. Using this notation, the first Sunday in April can be specified, as can the last Thursday in October (5 is equal to "the last").

StandardBias

Specifies a bias value to be used during local time translations that occur during standard time. This member is ignored if a value for the StandardDate member is not supplied.

This value is added to the value of the Bias member to form the bias used during standard time. In most time zones, the value of this member is zero.

DaylightName

Specifies a null-terminated string associated with daylight time on this operating system. For example, this parameter could contain "PDT" to indicate Pacific Daylight Time. This string is not used by the operating system, so anything stored there by using the SetTimeZoneInformation function is returned unchanged by the GetTimeZoneInformation function. This string can be empty.

DaylightDate

Specifies a SYSTEMTIME structure that contains a date and UTC when the transition from standard time to daylight time occurs on this operating system. If this date is not specified, the wMonth member in the SYSTEMTIME structure must be zero. If this date is specified, the StandardDate value in the TIME_ZONE_INFORMATION structure must also be specified. Local time translations during the daylight-time range are relative to the supplied DaylightBias value. This member supports the absolute and day-in-month time formats described for the StandardDate member.

DaylightBias

Specifies a bias value to be used during local time translations that occur during daylight time. This member is ignored if a value for the DaylightDate member is not supplied.

This value is added to the value of the Bias member to form the bias used during daylight time. In most time zones, the value of this member is  − 60.

See Also

GetTimeZoneInformation, SetTimeZoneInformation, SYSTEMTIME


TOGGLEKEYS
TOGGLEKEYS  QuickInfo  Overview  Group

typedef struct tagTOGGLEKEYS {     // tk

    DWORD cbSize;

    DWORD dwFlags;

} TOGGLEKEYS;

The TOGGLEKEYS structure contains information about the ToggleKeys accessibility feature. When the ToggleKeys feature is on, the computer emits a high-pitched tone whenever the user turns on the CAPS LOCK, NUM LOCK, or SCROLL LOCK key, and a low-pitched tone whenever the user turns off one of those keys.

Members

cbSize

Specifies the size, in bytes, of this structure.

dwFlags

A set of bit flags that specify properties of the ToggleKeys feature. The following bit flag values are defined:

Value	Meaning
TKF_AVAILABLE	If this flag is set, the ToggleKeys feature is available.
TKD_CONFIRMHOTKEY	Windows 95 only: A confirmation dialog box appears when the Togglekeys feature is activated by using the hot key.
TKF_HOTKEYACTIVE	If this flag is set, the user can turn the ToggleKeys feature on and off by holding down the NUM LOCK key for eight seconds.
TKF_HOTKEYSOUND	If this flag is set, the system plays a siren sound when the user turns the ToggleKeys feature on or off by using the hot key.
TKF_TOGGLEKEYSON	If this flag is set, the ToggleKeys feature is on.
Remarks

An application uses a TOGGLEKEYS structure when calling the SystemParametersInfo function with the wAction parameter set to SPI_GETTOGGLEKEYS or SPI_SETTOGGLEKEYS. When using SPI_GETTOGGLEKEYS, an application must specify the cbSize member of the TOGGLEKEYS structure; the SystemParametersInfo function fills the remaining members. An application must specify all structure members when using the SETTOGGLEKEYS value.

See Also

SystemParametersInfo


TOKEN_CONTROL
TOKEN_CONTROL  QuickInfo

typedef struct _TOKEN_CONTROL { // tc

    LUID TokenId;

    LUID AuthenticationId;

    LUID ModifiedId;

    TOKEN_SOURCE TokenSource;

} TOKEN_CONTROL ;

The TOKEN_CONTROL structure contains information that identifies an access token.

Members

TokenId

Specifies a locally unique identifier (LUID) identifying this instance of the token object.

AuthenticationId

Specifies an LUID assigned to the session this token represents. There can be many tokens representing a single logon session.

ModifiedId

Specifies an LUID that changes each time the token is modified. An application can use this value as a test of whether a security context has changed since it was last used.

TokenSource

Specifies a TOKEN_SOURCE structure identifying the agency that issued the token. This information is used in audit logging.

See Also

LUID, TOKEN_DEFAULT_DACL, TOKEN_GROUPS, TOKEN_INFORMATION_CLASS, TOKEN_OWNER, TOKEN_PRIMARY_GROUP, TOKEN_PRIVILEGES, TOKEN_SOURCE, TOKEN_STATISTICS, TOKEN_TYPE, TOKEN_USER


TOKEN_DEFAULT_DACL
TOKEN_DEFAULT_DACL  QuickInfo

typedef struct _TOKEN_DEFAULT_DACL {  // tdd

    PACL DefaultDacl;

} TOKEN_DEFAULT_DACL;

The TOKEN_DEFAULT_DACL structure specifies a discretionary access-control list (ACL).

Members

DefaultDacl

Points to an ACL structure assigned by default to any objects created by the user represented by the access token.

Remarks

The GetTokenInformation function retrieves the default discretionary ACL for an access token, in the form of a TOKEN_DEFAULT_DACL structure. This structure is also used with the SetTokenInformation function to set the default discretionary ACL.

See Also

ACL, GetTokenInformation, SetTokenInformation, TOKEN_CONTROL, TOKEN_GROUPS, TOKEN_INFORMATION_CLASS, TOKEN_OWNER, TOKEN_PRIMARY_GROUP, TOKEN_PRIVILEGES, TOKEN_SOURCE, TOKEN_STATISTICS, TOKEN_TYPE, TOKEN_USER


TOKEN_GROUPS
TOKEN_GROUPS  QuickInfo

typedef struct _TOKEN_GROUPS { // tg

    DWORD GroupCount;

    SID_AND_ATTRIBUTES Groups[ANYSIZE_ARRAY];

} TOKEN_GROUPS;

The TOKEN_GROUPS structure contains information about a set of groups in an access token.

Members

GroupCount

Specifies the number of groups in the access token.

Groups

Specifies an array of SID_AND_ATTRIBUTES structures containing a token's group security identifiers (SIDs) and corresponding attributes.

The following attributes can be used with this parameter:

Value	Meaning
SE_GROUP_MANDATORY	The group cannot be disabled.
SE_GROUP_ENABLED_BY_DEFAULT	The group is enabled by default.
SE_GROUP_ENABLED	The group is enabled.
SE_GROUP_OWNER	The user is the owner of the group or the SID can be assigned as the owner of the token or objects.
SE_GROUP_LOGON_ID	The group is a logon identifier.
See Also

AdjustTokenGroups, SID_AND_ATTRIBUTES, TOKEN_CONTROL, TOKEN_DEFAULT_DACL, TOKEN_INFORMATION_CLASS, TOKEN_OWNER, TOKEN_PRIMARY_GROUP, TOKEN_PRIVILEGES, TOKEN_SOURCE, TOKEN_STATISTICS, TOKEN_TYPE, TOKEN_USER


TOKEN_OWNER
TOKEN_OWNER  QuickInfo

typedef struct _TOKEN_OWNER { // to

    PSID Owner;

} TOKEN_OWNER;

The TOKEN_OWNER structure contains the default owner SID that will be applied to newly created objects.

Members

Owner

Points to a SID structure representing a user who will become the owner of any objects created by a process using this access token. The security identifier (SID) must be one of the user or group SIDs already in the token.

See Also

GetTokenInformation, SetTokenInformation, SID, TOKEN_CONTROL, TOKEN_DEFAULT_DACL, TOKEN_GROUPS, TOKEN_INFORMATION_CLASS, TOKEN_PRIMARY_GROUP, TOKEN_PRIVILEGES, TOKEN_SOURCE, TOKEN_STATISTICS, TOKEN_TYPE, TOKEN_USER


TOKEN_PRIMARY_GROUP
TOKEN_PRIMARY_GROUP  QuickInfo

typedef struct _TOKEN_PRIMARY_GROUP { // tpg

    PSID PrimaryGroup;

} TOKEN_PRIMARY_GROUP;

The TOKEN_PRIMARY_GROUP structure specifies a group security identifier (SID) for an access token.

Members

PrimaryGroup

Points to a SID structure representing a group that will become the primary group of any objects created by a process using this access token. The security identifier (SID) must be one of the group SIDs already in the token.

See Also

GetTokenInformation, SetTokenInformation, SID, TOKEN_CONTROL, TOKEN_DEFAULT_DACL, TOKEN_GROUPS, TOKEN_INFORMATION_CLASS, TOKEN_OWNER, TOKEN_PRIVILEGES, TOKEN_SOURCE, TOKEN_STATISTICS, TOKEN_TYPE, TOKEN_USER


TOKEN_PRIVILEGES
TOKEN_PRIVILEGES  QuickInfo

typedef struct _TOKEN_PRIVILEGES { // tp

    DWORD PrivilegeCount;

    LUID_AND_ATTRIBUTES Privileges[ANYSIZE_ARRAY];

} TOKEN_PRIVILEGES;

The TOKEN_PRIVILEGES structure contains information about the set of privileges for an access token.

Members

PrivilegeCount

Specifies the number of privileges in the token.

Privileges

Specifies an array of LUID_AND_ATTRIBUTES structures describing the token's privileges.

The following attributes can be used with this parameter:

Attribute	Description
SE_PRIVILEGE_ENABLED_BY_DEFAULT
	The privilege is enabled by default.
SE_PRIVILEGE_ENABLED
	The privilege is enabled.
SE_PRIVILEGE_USED_FOR_ACCESS
	The privilege was used to gain access to an object or service. This flag is used to identify the relevant privileges in a set passed by a client application that may contain unnecessary privileges.
See Also

AdjustTokenPrivileges, GetTokenInformation, PrivilegeCheck, PrivilegedServiceAuditAlarm, SetTokenInformation, LUID_AND_ATTRIBUTES, PRIVILEGE_SET, TOKEN_CONTROL, TOKEN_DEFAULT_DACL, TOKEN_GROUPS, TOKEN_INFORMATION_CLASS, TOKEN_OWNER, TOKEN_PRIMARY_GROUP, TOKEN_SOURCE, TOKEN_STATISTICS, TOKEN_TYPE, TOKEN_USER


TOKEN_SOURCE
TOKEN_SOURCE  QuickInfo

typedef struct _TOKEN_SOURCE { // ts

    CHAR SourceName[8];

    LUID SourceIdentifier;

} TOKEN_SOURCE;

The TOKEN_SOURCE structure identifies the source of an access token.

Members

SourceName

Specifies an eight-byte character string used to identify the source of an access token. This is used to distinguish between such sources as Session Manager, LAN Manager, and RPC Server. A string, rather than a constant, is used to identify the source so users and developers can make extensions to the system, such as by adding other networks, that act as the source of access tokens.

SourceIdentifier

Specifies a locally unique identifier (LUID) provided by the source component named by the SourceName member. This value aids the source component in relating context blocks, such as session-control structures, to the token. This value is typically, but not necessarily, an LUID.

See Also

GetTokenInformation, LUID, TOKEN_CONTROL, TOKEN_DEFAULT_DACL, TOKEN_GROUPS, TOKEN_INFORMATION_CLASS, TOKEN_OWNER, TOKEN_PRIMARY_GROUP, TOKEN_PRIVILEGES, TOKEN_STATISTICS, TOKEN_TYPE, TOKEN_USER


TOKEN_STATISTICS
TOKEN_STATISTICS  QuickInfo

typedef struct _TOKEN_STATISTICS { // tst

    LUID  TokenId;

    LUID  AuthenticationId;

    LARGE_INTEGER ExpirationTime;

    TOKEN_TYPE    TokenType;

    SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;

    DWORD DynamicCharged;

    DWORD DynamicAvailable;

    DWORD GroupCount;

    DWORD PrivilegeCount;

    LUID  ModifiedId;

} TOKEN_STATISTICS;

The TOKEN_STATISTICS structure contains information about an access token. An application can retrieve this information by calling the GetTokenInformation function.

Members

TokenId

Specifies a locally unique identifier (LUID) that identifies this instance of the token object.

AuthenticationId

Specifies an LUID assigned to the session this token represents. There can be many tokens representing a single logon session.

ExpirationTime

Specifies the time at which this token expires. Expiration times for access tokens are not supported in the current version of Windows NT.

TokenType

Specifies a TOKEN_TYPE enumerated type indicating whether the token is a primary or impersonation token.

ImpersonationLevel

Specifies a SECURITY_IMPERSONATION_LEVEL enumerated type indicating the impersonation level of the token. This member is valid only if the TokenType is TokenImpersonation.

DynamicCharged

Specifies the amount, in bytes, of memory allocated for storing default protection and a primary group identifier.

DynamicAvailable

Specifies the portion of memory allocated for storing default protection and a primary group identifier not already in use. This value is returned as a count of free bytes.

GroupCount

Specifies the number of supplemental group security identifiers (SIDs) included in the token.

PrivilegeCount

Specifies the number of privileges included in the token.

ModifiedId

Specifies an LUID that changes each time the token is modified. An application can use this value as a test of whether a security context has changed since it was last used.

See Also

GetTokenInformation, LUID, SECURITY_IMPERSONATION_LEVEL, TOKEN_CONTROL, TOKEN_DEFAULT_DACL, TOKEN_GROUPS, TOKEN_INFORMATION_CLASS, TOKEN_OWNER, TOKEN_PRIMARY_GROUP, TOKEN_PRIVILEGES, TOKEN_SOURCE, TOKEN_TYPE, TOKEN_USER


TOKEN_USER
TOKEN_USER  QuickInfo

typedef struct _TOKEN_USER { // tu

    SID_AND_ATTRIBUTES User;

} TOKEN_USER;

The TOKEN_USER structure identifies the user associated with an access token.

Members

User

Specifies an SID_AND_ATTRIBUTES structure representing the user associated with the access token. There are currently no attributes defined for user security identifiers (SIDs).

See Also

GetTokenInformation, SID_AND_ATTRIBUTES, TOKEN_CONTROL, TOKEN_DEFAULT_DACL, TOKEN_GROUPS, TOKEN_INFORMATION_CLASS, TOKEN_OWNER, TOKEN_PRIMARY_GROUP, TOKEN_PRIVILEGES, TOKEN_SOURCE, TOKEN_STATISTICS, TOKEN_TYPE


TOOLINFO [New - Windows NT]
TOOLINFO  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct {  // ti

    UINT      cbSize;

    UINT      uFlags;

    HWND      hwnd;

    UINT      uId;

    RECT      rect;

    HINSTANCE hinst;

    LPTSTR     lpszText;

} TOOLINFO, NEAR *PTOOLINFO, FAR *LPTOOLINFO;

The TOOLINFO structure contains information about a tool in a tooltip control.

Members

cbSize

Size, in bytes, of the TOOLINFO structure. This member must be specified.

uFlags

A set of bit flags. This member can be a combination of the following values:

Value	Meaning
TTF_IDISHWND	Indicates that the uId member is the window handle to the tool. If this flag is not set, uId is the identifier of the tool.
TTF_CENTERTIP	Centers the tooltip window below the tool specified by the uId member.
TTF_RTLREADING	Windows 95 only: Displays text using right-to-left reading order on Hebrew or Arabic systems.
TTF_SUBCLASS	Indicates that the tooltip control should subclass the tool's window to intercept messages, such as WM_MOUSEMOVE. If not set, you need to use the TTM_RELAYEVENT message to forward messages to the tooltip control. For a list of messages that a tooltip control processes, see TTM_RELAYEVENT.
hwnd

Handle to the window that contains the tool. If lpszText includes the LPSTR_TEXTCALLBACK value, this member identifies the window that receives TTN_NEEDTEXT notification messages.

uId

Application-defined identifier of the tool. If uFlags includes the TTF_IDISHWND value, uId must specify the window handle to the tool.

rect

Coordinates of the bounding rectangle of the tool. The coordinates are relative to the upper-left corner of the client area of the window identified by hwnd. If uFlags includes the TTF_IDISHWND value, this member is ignored.

hinst

Handle to the instance that contains the string resource for the tool. If lpszText specifies the identifier of a string resource, this member is used.

lpszText

Pointer to the buffer that contains the text for the tool, or identifier of the string resource that contains the text. If this member is set to the LPSTR_TEXTCALLBACK value, the control sends the TTN_NEEDTEXT notification message to the owner window to retrieve the text.

See Also

TTN_NEEDTEXT


TOOLTIPTEXT [New - Windows NT]
TOOLTIPTEXT  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct { // ttt

    NMHDR     hdr;

    LPTSTR    lpszText;

    char      szText[80];

    HINSTANCE hinst;

    UINT      uFlags;

} TOOLTIPTEXT, FAR *LPTOOLTIPTEXT;

The TOOLTIPTEXT structure identifies a tool for which text is to be displayed and receives the text for the tool.

Members

hdr

Required for all WM_NOTIFY messages.

lpszText

Pointer to a string that contains or receives the text for a tool. If hinst specifies an instance handle, this member must be the identifier of a string resource.

szText

Buffer that receives the tooltip text. An application can copy the text to this buffer as an alternative to specifying a string address or string resource.

hinst

Handle to the instance that contains a string resource to be used as the tooltip text. If lpszText is the pointer to the tooltip text, this member is NULL.

uFlags

Flag that indicates how to interpret the idFrom member of the NMHDR structure that is included in the structure. If this member is the TTF_IDISHWND value, idFrom is the handle of the tool. Otherwise, idFrom is the identifier of the tool.

Windows 95 only: If this member is the TTF_RTLREADING value, then text on Hebrew or Arabic systems is displayed using right-to-left reading order.

Remarks

This structure is used with the TTN_NEEDTEXT notification message.

See Also

NMHDR, TTN_NEEDTEXT, WM_NOTIFY


TPMPARAMS [New - Windows 95]
TPMPARAMS  QuickInfo  Overview  Group

[New - Windows 95]

typedef struct tagTPMPARAMS {

    UINT cbSize;

    RECT rcExclude;

} TPMPARAMS, FAR *LPTPMPARAMS;

The TPMPARAMS structure contains extended parameters for the TrackPopupMenuEx function.

Members

cbsize

Size of structure, in bytes.

rcExclude

Rectangle to exclude when positioning the window, in screen coordinates.

See Also

TrackPopupMenuEx, Rectangle


TRANSMIT_FILE_BUFFERS [New - Windows NT]
TRANSMIT_FILE_BUFFERS  QuickInfo

[New - Windows NT]

typedef struct _TRANSMIT_FILE_BUFFERS {

    PVOID Head;

    DWORD HeadLength;

    PVOID Tail;

    DWORD TailLength;

} TRANSMIT_FILE_BUFFERS;

The TRANSMIT_FILE_BUFFERS structure specifies data to be transmitted before and after file data during a TransmitFile function file transfer operation.

Members

Head

Pointer to a buffer that contains data to be transmitted before the file data is transmitted.

HeadLength

Specifies the number of bytes of data in the buffer pointed to by the Head member that are to be transmitted.

Tail

Pointer to a buffer that contains data to be transmitted after the file data is transmitted.

TailLength

Specifies the number of bytes of data in the buffer pointed to by the Tail member that are to be transmitted.

See Also

TransmitFile


TTHITTESTINFO [New - Windows NT]
TTHITTESTINFO  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct _TT_HITTESTINFO { // tthti

    HWND hwnd;

    POINT pt;

    TOOLINFO ti;

} TTHITTESTINFO, FAR * LPHITTESTINFO;

The TTHITTESTINFO structure contains information that a tooltip control uses to determine whether a point is in the bounding rectangle of the specified tool. If the point is in the rectangle, the structure receives information about the tool.

Members

hwnd

Handle to the tool or window with the specified tool.

pt

Client coordinates of the point to test.

ti

Receives information about the specified tool.

Remarks

This structure is used with the TTM_HITTEST message.

See Also

TTM_HITTEST


TTPOLYCURVE
TTPOLYCURVE  QuickInfo

typedef struct tagTTPOLYCURVE { // ttpc

    WORD    wType;

    WORD    cpfx;

    POINTFX apfx[1];

} TTPOLYCURVE, FAR* LPTTPOLYCURVE;

The TTPOLYCURVE structure contains information about a curve in the outline of a TrueType character.

Members

wType

Specifies the type of curve described by the structure. This member can be one of the following values:

Value	Meaning
TT_PRIM_LINE	Curve is a polyline.
TT_PRIM_QSPLINE	Curve is a Bézier spline.
cpfx

Specifies the number of POINTFX structures in the array.

apfx

Specifies an array of POINTFX structures that define the polyline or Bézier spline.

Remarks

When an application calls the GetGlyphOutline function, a glyph outline for a TrueType character is returned in a TTPOLYGONHEADER structure, followed by as many TTPOLYCURVE structures as are required to describe the glyph. All points are returned as POINTFX structures and represent absolute positions, not relative moves. The starting point given by the pfxStart member of the TTPOLYGONHEADER structure is the point at which the outline for a contour begins. The TTPOLYCURVE structures that follow can be either polyline records or spline records.

Polyline records are a series of points; lines drawn between the points describe the outline of the character. Spline records represent the quadratic curves (that is, quadratic b-splines) used by TrueType.

See Also

GetGlyphOutline, POINTFX, TTPOLYGONHEADER


TTPOLYGONHEADER
TTPOLYGONHEADER  QuickInfo

typedef struct _TTPOLYGONHEADER { // ttph

    DWORD   cb;

    DWORD   dwType;

    POINTFX pfxStart;

} TTPOLYGONHEADER, FAR* LPTTPOLYGONHEADER;

The TTPOLYGONHEADER structure specifies the starting position and type of a contour in a TrueType character outline.

Members

cb

Specifies the number of bytes required by the TTPOLYGONHEADER structure and TTPOLYCURVE structure or structures required to describe the contour of the character.

dwType

Specifies the type of character outline returned. Currently, this value must be TT_POLYGON_TYPE.

pfxStart

Specifies the starting point of the contour in the character outline.

Remarks

Each TTPOLYGONHEADER structure is followed by one or more TTPOLYCURVE structures.

See Also

POINTFX, TTPOLYCURVE


TV_DISPINFO [New - Windows NT]
TV_DISPINFO  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct _TV_DISPINFO {  tvdi

    NMHDR   hdr;

    TV_ITEM item;

} TV_DISPINFO;

The TV_DISPINFO structure retrieves and sets information about a tree-view item.

Members

hdr

Required for all WM_NOTIFY messages.

item

TV_ITEM structure that identifies and contains information about the tree-view item. The mask member specifies which information is being set or retrieved; it can be one or more of the following values:

Value	Meaning
TVIF_CHILDREN	The iChildren member specifies, or is to receive, the number of child items associated with the item.
TVIF_IMAGE	The iImage member specifies, or is to receive, the index of the item's icon in the image list.
TVIF_SELECTEDIMAGE	The iSelectedImage member specifies, or is to receive, the index of the item's icon in the image list.
TVIF_TEXT	The pszText member specifies the new item text or the pointer to a buffer that is to receive the item text.
If the structure is receiving item text, you typically copy the text to the buffer pointed to by the pszText member of the TV_ITEM structure. However, you can return a string in the pszText member instead. If you do so, you cannot change or delete the string until the corresponding item text is deleted or until two additional TVN_GETDISPINFO notification messages have been sent.

Remarks

A tree-view control sends a notification message to retrieve or set an item's text if the pszText member of the item's TV_ITEM structure is the LPSTR_TEXTCALLBACK value. A tree-view control sends a notification message to retrieve or set an item's icon or small icon if the iImage or iSelectedImage member of the TV_ITEM structure is the I_IMAGECALLBACK value. A tree-view control sends a notification message to retrieve or set an item's state flags if the corresponding bits are set in the control's state callback mask.

The notification mesages are sent only if the parent window is responsible for maintaining certain information. The TV_ITEM structure is used with the TVN_GETDISPINFO and TVN_SETDISPINFO notification messages.

See Also

TV_ITEM, TVN_GETDISPINFO, TVN_SETDISPINFO


TV_HITTESTINFO [New - Windows NT]
TV_HITTESTINFO  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct _TVHITTESTINFO {  tvhtst

    POINT     pt;

    UINT      flags;

    HTREEITEM hItem;

} TV_HITTESTINFO, FAR *LPTV_HITTESTINFO;

The TV_HITTESTINFO structure contains information used to determine the location of a point relative to a tree-view control.

Members

pt

Client coordinates of point to test.

flags

Variable that receives information about the results of a hit test. This member can be one or more of the following values:

Value	Meaning
TVHT_ABOVE	Above the client area
TVHT_BELOW	Below the client area
TVHT_NOWHERE	In the client area, but below the last item
TVHT_ONITEM	On the bitmap or label associated with an item
TVHT_ONITEMBUTTON	On the button associated with an item
TVHT_ONITEMICON	On the bitmap associated with an item
TVHT_ONITEMINDENT	In the indentation associated with an item
TVHT_ONITEMLABEL	On the label (string) associated with an item
TVHT_ONITEMRIGHT	In the area to the right of an item
TVHT_ONITEMSTATEICON	On the state icon for a tree-view item that is in a user-defined state
TVHT_TOLEFT	To the right of the client area
TVHT_TORIGHT	To the left of the client area
hItem

Handle to the item that occupies the point.

Remarks

This structure is used with the TVM_HITTEST message.

See Also

TVM_HITTEST


TV_INSERTSTRUCT [New - Windows NT]
TV_INSERTSTRUCT  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct _TV_INSERTSTRUCT {  tvins

    HTREEITEM hParent;

    HTREEITEM hInsertAfter;

    TV_ITEM   item;

} TV_INSERTSTRUCT, FAR *LPTV_INSERTSTRUCT;

The TV_INSERTSTRUCT structure contains information used to add a new item to a tree-view control.

Members

hParent

Handle to the parent item. If this member is the TVI_ROOT value or NULL, the item is inserted at the root of the tree-view control.

hInsertAfter

Handle to the item after which the new item is to be inserted or one of the following values:

Value	Meaning
TVI_FIRST	Inserts the item at the beginning of the list.
TVI_LAST	Inserts the item at the end of the list.
TVI_SORT	Inserts the item into the list in alphabetical order.
item

Information about the item to add.

Remarks

This structure is used with the TVM_INSERTITEM message.

See Also

TVM_INSERTITEM


TV_ITEM [New - Windows NT]
TV_ITEM  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct _TV_ITEM {  tvi

    UINT       mask;

    HTREEITEM  hItem;

    UINT       state;

    UINT       stateMask;

    LPSTR      pszText;

    int        cchTextMax;

    int        iImage;

    int        iSelectedImage;

    int        cChildren;

    LPARAM     lParam;

} TV_ITEM, FAR *LPTV_ITEM;

The TV_ITEM structure specifies or receives attributes of a tree-view item.

Members

mask

Array of flags that indicate which of the other structure members contain valid data or which are to be filled in. This member can be a combination of the following values:

Value	Meaning
TVIF_CHILDREN	The cChildren member is valid.
TVIF_IMAGE	The iImage member is valid.
TVIF_PARAM	The lParam member is valid.
TVIF_SELECTEDIMAGE	The iSelectedImage member is valid.
TVIF_STATE	The state and stateMask members are valid.
TVIF_TEXT	The pszText and cchTextMax members are valid.
hItem

Item to which this structure refers.

state and stateMask

Variables specifying the current state of the item and the valid states of the item. This member can be any valid combination of state values. For a list of item states, see Tree-View Control Constants.

pszText

Pointer to a null-terminated string that contains the item text if the structure specifies item attributes. If this member is the LPSTR_TEXTCALLBACK value, the parent window is responsible for storing the name. In this case, the tree-view control sends the parent window a TVN_GETDISPINFO notification message when it needs the item text for displaying, sorting, or editing and a TVN_SETDISPINFO notification message when the item text changes.

If the structure is receiving item attributes, this member is the pointer to the buffer that receives the item text.

cchTextMax

Size of the buffer pointed to by the pszText member if the structure is receiving item attributes. If the structure specifies item attributes, this member is ignored.

iImage and iSelectedImage

Indices of the icon image and the selected icon image within the image list. If either member is the I_IMAGECALLBACK value, the parent window is responsible for storing the corresponding images. In this case, the tree-view control sends the parent a TVN_GETDISPINFO notification message when it needs to display the images and a TVN_SETDISPINFO notification message when the images change.

cChildren

Flag indicating whether the item has associated child items. It is one if the item has one or more child items; otherwise, it is zero. If this member is the I_CHILDRENCALLBACK value, the parent window is responsible for drawing the child items. In this case, the tree-view control sends the parent a TVN_GETDISPINFO notification message when it needs to display the child items and a TVN_SETDISPINFO notification message when the attributes of a child item change.

lParam

32-bit value to associate with the item.

Remarks

This structure is used with the TVM_GETITEM, TVM_SETITEM, and TVM_INSERTITEM messages. It is also included with many of the notification messages. When the structure is used to retrieve item information, only the structure members indicated by mask contain valid data. All other members are invalid.

See Also

TVN_GETDISPINFO, TVM_GETITEM, TVM_INSERTITEM, TVN_SETDISPINFO, TVM_SETITEM


TV_KEYDOWN [New - Windows NT]
TV_KEYDOWN  QuickInfo  Overview  Group

[New - Windows NT]

pedef struct _TV_KEYDOWN { tvkd

    NMHDR hdr;

    WORD  wVKey;

    UINT  flags;

} TV_KEYDOWN;

The TV_KEYDOWN structure contains information about a keyboard event in a tree-view control.

Members

hdr

Required for all WM_NOTIFY messages.

sVKey

Virtual key code.

flags

Always zero.

Remarks

This structure is used with the TVN_KEYDOWN notification message.

See Also

TVN_KEYDOWN


TV_SORTCB [New - Windows NT]
TV_SORTCB  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct _TV_SORTCB { tvscb

    HTREEITEM    hParent;

    PFNTVCOMPARE lpfnCompare;

    LPARAM       lParam;

} TV_SORTCB, FAR *LPTV_SORTCB;

The TV_SORTCB structure contains information used to sort child items in a tree-view control.

Members

lpfnCompare

Pointer to an application-defined callback function, which is called during a sort operation each time the relative order of two list items needs to be compared. The callback function has the following form:

int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2,

LPARAM lParamSort);

The callback function must return a negative value if the first item should precede the second, a positive value if the first item should follow the second, or zero if the two items are equivalent.

The lParam1 and lParam2 parameters correspond to the lParam member of the TV_ITEM structure for the two items being compared. The lParamSort parameter corresponds to the lParam member of the TV_SORTCB structure that was passed with the TVM_SORTCHILDRENCB message.

hParent

Handle to the parent item.

lParam

Application-defined 32-bit value.

Remarks

This structure is used with the TVM_SORTCHILDRENCB message.

See Also

TV_ITEM, TVM_SORTCHILDRENCB


UDACCEL [New - Windows NT]
UDACCEL  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct {

    UINT nSec;

    UINT nInc;

} UDACCEL;

The UDACCEL structure contains acceleration information for an up-down control.

Members

nSec

Amount of elapsed time, in seconds, before the position change increment specified by nInc is used.

nInc

Position change increment to use after the time specified by nSec elapses.


ULARGE_INTEGER
ULARGE_INTEGER  QuickInfo

typedef struct _ULARGE_INTEGER { // uli

    DWORD LowPart;

    DWORD HighPart;

} ULARGE_INTEGER;

The ULARGE_INTEGER structure is used to specify a 64-bit unsigned integer value.

Members

LowPart

Specifies the low-order 32 bits.

HighPart

Specifies the high-order 32 bits.

See Also

LARGE_INTEGER


UNIVERSAL_NAME_INFO
UNIVERSAL_NAME_INFO  QuickInfo

typedef struct _UNIVERSAL_NAME_INFO { /* uni */

    LPTSTR  lpUniversalName;

} UNIVERSAL_NAME_INFO;

The UNIVERSAL_NAME_INFO structure contains a pointer to a Universal Naming Convention (UNC) name string.

Members

lpUniversalName

Points to a zero-terminated UNC name string.

Remarks

A universal form of a path identifies a network resource in an unambiguous, computer-independent manner. The path can then be passed to processes on other computers, allowing those processes to obtain access to the network resource.

Universal Naming Convention (UNC) names look like this:

\\servername\sharename\path\file

See Also

WNetGetUniversalName, REMOTE_NAME_INFO


UNLOAD_DLL_DEBUG_INFO
UNLOAD_DLL_DEBUG_INFO  QuickInfo

typedef struct _UNLOAD_DLL_DEBUG_INFO { // uddi

    LPVOID lpBaseOfDll;

} UNLOAD_DLL_DEBUG_INFO;

The UNLOAD_DLL_DEBUG_INFO structure contains information about a dynamic-link library (DLL) that has just been unloaded.

Members

lpBaseOfDll

Points to the base address of the DLL in the address space of the process unloading the DLL.

See Also

DEBUG_EVENT


USEROBJECTFLAGS [New - Windows NT]
USEROBJECTFLAGS  QuickInfo  Overview  Group

[New - Windows NT]

typedef struct tagUSEROBJECTFLAGS {

    BOOL fInherit;

    BOOL fReserved;

    DWORD dwFlags;

} USEROBJECTFLAGS;

The USEROBJECTFLAGS structure contains information about a window station or desktop handle.

Members

fInherit

Specifies whether the handle is inherited when a new process is created. If this member is TRUE, new processes will inherit the handle.

fReserved

Reserved for future use. This member must be FALSE.

dwFlags

For window stations, this member can contain the following window station attribute flag:

Value	Description
WSF_VISIBLE	Window station has visible display surfaces.
For desktops, the dwFlags member can contain the following desktop control flag:

Value	Description
DF_ALLOWOTHERACCOUNTHOOK	Allows processes running in other accounts on the desktop to set hooks in this process.
See Also

CreateDesktop, GetUserObjectInformation, OpenDesktop, OpenInputDesktop,SetUserObjectInformation


Var
Var  QuickInfo

Var {

    WCHAR szKey[];

    BYTE  Padding[];

    Var   Value[];

};

The Var structure depicts the organization of data in a file-version resource. This structure is not a true C data structure because it contains variable-length members. This structure was created solely to depict the organization of data in a version resource and does not appear in any of the header files shipped with the Microsoft Win32 Software Development Kit (SDK).

The Var structure contains version information not dependent on a particular language and code page.

Members

szKey

Specifies an arbitrary 7-bit ASCII English string. The szKey member can be the following value:

Value	Meaning
Translation	Value contains an array of doubleword values indicating the language and code-page combinations supported by this file. The high-order word of each doubleword contains a Microsoft language identifier and the low-order word contains the IBM® code-page number. Either high-order or low-order word may be zero, indicating that the file is language or code-page independent. If this block is omitted, the file will be interpreted as language and code-page independent.
Padding

Contains as many zero bytes as necessary to align the Value member on a 32-bit boundary.

Value

Specifies a list of zero or more Var structures.

Remarks

The Children member of the VS_VERSION_INFO structure may contain zero or more Var structures.

See Also

VarFileInfo, VS_VERSION_INFO


VarFileInfo
VarFileInfo  QuickInfo

VarFileInfo {

    WCHAR szKey[];

    BYTE  Padding[];

    Var   Children[];

};

The VarFileInfo structure depicts the organization of data in a file-version resource. This structure is not a true C data structure because it contains variable-length members. This structure was created solely to depict the organization of data in a version resource and does not appear in any of the header files shipped with the Microsoft Win32 Software Development Kit (SDK).

The VarFileInfo structure contains version information not dependent on a particular language and code page.

Members

szKey

Contains "VarFileInfo".

Padding

Contains as many zero bytes as necessary to align the Children member on a 32-bit boundary.

Children

Specifies a list of zero or more Var structures.

Remarks

The Children member of the VS_VERSION_INFO structure may contain zero or more VarFileInfo structures.

See Also

Var, VS_VERSION_INFO


VERIFY_INFORMATION
VERIFY_INFORMATION  QuickInfo  Overview  Group

typedef struct _VERIFY_INFORMATION {

   LARGE_INTEGER  StartingOffset;

   DWORD  Length;

} VERIFY_INFORMATION ;

The VERIFY_INFORMATION structure provides information used to logically format a disk extent.

Members

StartingOffset

Specifies the starting offset of the disk extent.

Length

Length, in bytes, of the disk extent.

Remarks

The DeviceIoControl function uses a VERIFY_INFORMATION structure as input to an IOCTL_DISK_VERIFY device I/O operation.

See Also

DeviceIoControl, IOCTL_DISK_VERIFY


VS_FIXEDFILEINFO
VS_FIXEDFILEINFO  QuickInfo

typedef struct _VS_FIXEDFILEINFO {  // vsffi

    DWORD dwSignature;

    DWORD dwStrucVersion;

    DWORD dwFileVersionMS;

    DWORD dwFileVersionLS;

    DWORD dwProductVersionMS;

    DWORD dwProductVersionLS;

    DWORD dwFileFlagsMask;

    DWORD dwFileFlags;

    DWORD dwFileOS;

    DWORD dwFileType;

    DWORD dwFileSubtype;

    DWORD dwFileDateMS;

    DWORD dwFileDateLS;

} VS_FIXEDFILEINFO;

The VS_FIXEDFILEINFO structure contains version information about a file. This information is language and code-page independent.

Members

dwSignature

Contains the value 0xFEEFO4BD. This is used with the szKey member of VS_VERSION_INFO data when searching a file for the VS_FIXEDFILEINFO structure.

dwStrucVersion

Specifies the binary version number of this structure. The high-order word of this member contains the major version number, and the low-order word contains the minor version number. This value must be greater than 0x00000029.

dwFileVersionMS

Specifies the most significant 32 bits of the file's binary version number. This member is used with dwFileVersionLS to form a 64-bit value used for numeric comparisons.

dwFileVersionLS

Specifies the least significant 32 bits of the file's binary version number. This member is used with dwFileVersionMS to form a 64-bit value used for numeric comparisons.

dwProductVersionMS

Specifies the most significant 32 bits of the binary version number of the product with which this file was distributed. This member is used with dwProductVersionLS to form a 64-bit value used for numeric comparisons.

dwProductVersionLS

Specifies the least significant 32 bits of the binary version number of the product with which this file was distributed. This member is used with dwProductVersionMS to form a 64-bit value used for numeric comparisons.

dwFileFlagsMask

Contains a bitmask that specifies the valid bits in dwFileFlags. A bit is valid only if it was defined when the file was created.

dwFileFlags

Contains a bitmask that specifies the Boolean attributes of the file. This member can include one or more of the following values:

Flag	Description
VS_FF_DEBUG	The file contains debugging information or is compiled with debugging features enabled.
VS_FF_INFOINFERRED	The file's version structure was created dynamically; therefore, some of the members in this structure may be empty or incorrect. This flag should never be set in a file's VS_VERSION_INFO data.
VS_FF_PATCHED	The file has been modified and is not identical to the original shipping file of the same version number.
VS_FF_PRERELEASE	The file is a development version, not a commercially released product.
VS_FF_PRIVATEBUILD	The file was not built using standard release procedures. If this flag is set, the StringFileInfo structure should contain a PrivateBuild entry.
VS_FF_SPECIALBUILD	The file was built by the original company using standard release procedures but is a variation of the normal file of the same version number. If this flag is set, the StringFileInfo structure should contain a SpecialBuild entry.
dwFileOS

Specifies the operating system for which this file was designed. This member can be one of the following values:

Flag	Description
VOS_UNKNOWN	The operating system for which the file was designed is unknown to Windows.
VOS_DOS	The file was designed for MS-DOS.
VOS_OS216	The file was designed for 16-bit OS/2.
VOS_OS232	The file was designed for 32-bit OS/2.
VOS_NT	The file was designed for Windows NT.
VOS_WINDOWS16	The file was designed for 16-bit Windows.
VOS_PM16	The file was designed for 16-bit Presentation Manager.
VOS_PM32	The file was designed for 32-bit Presentation Manager.
VOS_WINDOWS32	The file was designed for the Win32 API.
An application can combine these values to indicate that the file was designed for one operating system running on another. The following dwFileOS values are examples of this, but are not a complete list:

Flag	Description
VOS_DOS_WINDOWS16	The file was designed for 16-bit Windows running on MS-DOS.
VOS_DOS_WINDOWS32	The file was designed for the Win32 API running on MS-DOS.
VOS_OS216_PM16	The file was designed for 16-bit Presentation Manager running on 16-bit OS/2.
VOS_OS232_PM32	The file was designed for 32-bit Presentation Manager running on 32-bit OS/2.
VOS_NT_WINDOWS32	The file was designed for the Win32 API running on Windows NT.
dwFileType

Specifies the general type of file. This member can be one of the following values:

Flag	Description
VFT_UNKNOWN	The file type is unknown to Windows.
VFT_APP	The file contains an application.
VFT_DLL	The file contains a dynamic-link library (DLL).
VFT_DRV	The file contains a device driver. If dwFileType is VFT_DRV, dwFileSubtype contains a more specific description of the driver.
VFT_FONT	The file contains a font. If dwFileType is VFT_FONT, dwFileSubtype contains a more specific description of the font file.
VFT_VXD	The file contains a virtual device.
VFT_STATIC_LIB	The file contains a static-link library.
All other values are reserved for future use by Microsoft.

dwFileSubtype

Specifies the function of the file. The possible values depend on the value of dwFileType. For all values of dwFileType not described in the following list, dwFileSubtype is zero.

If dwFileType is VFT_DRV, dwFileSubtype can be one of the following values:

Flag	Description
VFT2_UNKNOWN	The driver type is unknown by Windows.
VFT2_DRV_PRINTER	The file contains a printer driver.
VFT2_DRV_KEYBOARD	The file contains a keyboard driver.
VFT2_DRV_LANGUAGE	The file contains a language driver.
VFT2_DRV_DISPLAY	The file contains a display driver.
VFT2_DRV_MOUSE	The file contains a mouse driver.
VFT2_DRV_NETWORK	The file contains a network driver.
VFT2_DRV_SYSTEM	The file contains a system driver.
VFT2_DRV_INSTALLABLE	The file contains an installable driver.
VFT2_DRV_SOUND	The file contains a sound driver.
If dwFileType is VFT_FONT, dwFileSubtype can be one of the following values:

Flag	Description
VFT2_UNKNOWN	The font type is unknown by Windows.
VFT2_FONT_RASTER	The file contains a raster font.
VFT2_FONT_VECTOR	The file contains a vector font.
VFT2_FONT_TRUETYPE	The file contains a TrueType font.
If dwFileType is VFT_VXD, dwFileSubtype contains the virtual device identifier included in the virtual device control block.

All dwFileSubtype values not listed here are reserved for future use by Microsoft.

dwFileDateMS

Specifies the most significant 32 bits of the file's 64-bit binary creation date and time stamp.

dwFileDateLS

Specifies the least significant 32 bits of the file's 64-bit binary creation date and time stamp.

Remarks

The Value member of the VS_VERSION_INFO data is a VS_FIXEDFILEINFO structure.

See Also

StringFileInfo, VS_VERSION_INFO


VS_VERSION_INFO
VS_VERSION_INFO  QuickInfo

VS_VERSION_INFO {

    WORD  wLength;

    WORD  wValueLength;

    WORD  bText;

    WCHAR szKey[];

    BYTE  Padding1[];

    VS_FIXEDFILEINFO Value;

    BYTE  Padding2[];

    BYTE  Children[];

};

The VS_VERSION_INFO structure depicts the organization of data in a file-version resource. This structure is not a true C data structure because it contains variable-length members. This structure was created solely to depict the organization of data in a version resource and does not appear in any of the header files shipped with the Microsoft Win32 Software Development Kit (SDK).

Members

wLength

Specifies the length of the VS_VERSION_INFO structure. This length does not include any padding that aligns the subsequent version structure on a 32-bit boundary.

wValueLength

Specifies the length of the Value member. This value is zero if there is no Value member associated with the current version structure.

bText

Specifies the type of data in the version resource. This member is 1 if the version resource contains text data and 0 if the version resource contains binary data.

szKey

Contains "VS_VERSION_INFO".

Padding1

Contains as many zero bytes as necessary to align the Value member on a 32-bit boundary.

Value

Contains a VS_FIXEDFILEINFO structure that specifies arbitrary data associated with this structure. The wValueLength member specifies the length of this member; if wValueLength is zero, this member does not exist.

Padding2

Contains as many zero bytes as necessary to align the Children member on a 32-bit boundary. These bytes are not included in wValueLength.

Children

Specifies a list of zero or more StringFileInfo or VarFileInfo structures (or both) that are children of the current version structure.

Remarks

The VS_VERSION_INFO structure is the root structure that contains all other file information structures.

See Also

StringFileInfo, VarFileInfo, VS_FIXEDFILEINFO


WIN32_FIND_DATA
WIN32_FIND_DATA  QuickInfo

typedef struct _WIN32_FIND_DATA { // wfd

    DWORD dwFileAttributes;

    FILETIME ftCreationTime;

    FILETIME ftLastAccessTime;

    FILETIME ftLastWriteTime;

    DWORD    nFileSizeHigh;

    DWORD    nFileSizeLow;

    DWORD    dwReserved0;

    DWORD    dwReserved1;

    TCHAR    cFileName[ MAX_PATH ];

    TCHAR    cAlternateFileName[ 14 ];

} WIN32_FIND_DATA;

The WIN32_FIND_DATA structure describes a file found by the FindFirstFile or FindNextFile function.

Members

dwFileAttributes

Specifies the file attributes of the file found. This member can be one or more of the following values:

Value	Meaning
FILE_ATTRIBUTE_ARCHIVE
	The file is an archive file. Applications use this value to mark files for backup or removal.
FILE_ATTRIBUTE_COMPRESSED
	The file or directory is compressed. For a file, this means that all of the data in the file is compressed. For a directory, this means that compression is the default for newly created files and subdirectories.
FILE_ATTRIBUTE_DIRECTORY
	The file is a directory.
FILE_ATTRIBUTE_HIDDEN
	The file is hidden. It is not included in an ordinary directory listing.
FILE_ATTRIBUTE_NORMAL
	The file has no other attributes set. This value is valid only if used alone.
FILE_ATTRIBUTE_READONLY
	The file is read-only. Applications can read the file but cannot write to it or delete it.
FILE_ATTRIBUTE_SYSTEM
	The file is part of the operating system or is used exclusively by it.
FILE_ATTRIBUTE_TEMPORARY
	The file is being used for temporary storage. Applications should write to the file only if absolutely necessary. Most of the file's data remains in memory without being flushed to the media because the file will soon be deleted.
ftCreationTime

Specifies a FILETIME structure containing the time the file was created. FindFirstFile and FindNextFile report file times in Coordinated Universal Time (UTC) format. These functions set the FILETIME members to zero if the file system containing the file does not support this time member. You can use the FileTimeToLocalFileTime function to convert from UTC to local time, and then use the FileTimeToSystemTime function to convert the local time to a SYSTEMTIME structure containing individual members for the month, day, year, weekday, hour, minute, second, and millisecond.

ftLastAccessTime

Specifies a FILETIME structure containing the time that the file was last accessed. The time is in UTC format; the FILETIME members are zero if the file system does not support this time member.

ftLastWriteTime

Specifies a FILETIME structure containing the time that the file was last written to. The time is in UTC format; the FILETIME members are zero if the file system does not support this time member.

nFileSizeHigh

Specifies the high-order DWORD value of the file size, in bytes. This value is zero unless the file size is greater than MAXDWORD. The size of the file is equal to (nFileSizeHigh * MAXDWORD) + nFileSizeLow.

nFileSizeLow

Specifies the low-order DWORD value of the file size, in bytes.

dwReserved0

Reserved for future use.

dwReserved1

Reserved for future use.

cFileName

A null-terminated string that is the name of the file.

cAlternateFileName

A null-terminated string that is an alternative name for the file. This name is in the classic 8.3 (filename.ext) filename format.

Remarks

If a file has a long filename, the complete name appears in the cFileName field, and the 8.3 format truncated version of the name appears in the cAlternateFileName field.

See Also

FindFirstFile, FindNextFile, FILETIME, FileTimeToLocalFileTime, FileTimeToSystemTime


WIN32_STREAM_ID
WIN32_STREAM_ID  QuickInfo

struct WIN32_STREAM_ID {

    DWORD dwStreamId;

    DWORD dwStreamAttributes;

    LARGE_INTEGER Size;

    DWORD dwStreamNameSize;

    WCHAR  cStreamName[ ] ;

}

Members

dwStreamId

Specifies the type of data. This member can be one of the following values:

Value	Meaning
BACKUP_DATA	Standard data
BACKUP_EA_DATA	Extended attribute data
BACKUP_SECURITY_DATA	Windows NT security descriptor data
BACKUP_ALTERNATE_DATA	Alternative data streams
BACKUP_LINK	Hard link information
dwStreamAttributes

Specifies the attributes of data to facilitate cross-operating system transfer. This member must be one or more of the following values:

Value	Description
STREAM_MODIFIED_WHEN_READ	Attribute set if the stream contains data that is modified when read. Allows the backup application to know that verification of data will fail.
STREAM_CONTAINS_SECURITY	Stream contains security data (general attributes). Allows the stream to be ignored on cross-operations restore.
Size

Specifies the size, in bytes, of data. Note that this is a 64-bit value.

dwStreamNameSize

Specifies the length of the name of the alternative data stream.

cStreamName

Specifies the name of the alternative data stream, in Unicode™.

See Also

BackupRead, BackupSeek, BackupWrite


WINDOW_BUFFER_SIZE_RECORD
WINDOW_BUFFER_SIZE_RECORD  QuickInfo  Overview  Group

typedef struct _WINDOW_BUFFER_SIZE_RECORD { // wbsr

    COORD dwSize;

} WINDOW_BUFFER_SIZE_RECORD;

The WINDOW_BUFFER_SIZE_RECORD structure is used in a console INPUT_RECORD structure to report changes in the size of the screen buffer.

Members

dwSize

Specifies the new size of the screen buffer, in character cell columns and rows.

Remarks

Buffer size events are placed in the input buffer when the console is in window-aware mode (ENABLE_WINDOW_INPUT).

See Also

INPUT_RECORD, ReadConsoleInput


WINDOWPLACEMENT
WINDOWPLACEMENT  QuickInfo

typedef struct _WINDOWPLACEMENT {     // wndpl

    UINT  length;

    UINT  flags;

    UINT  showCmd;

    POINT ptMinPosition;

    POINT ptMaxPosition;

    RECT  rcNormalPosition;

} WINDOWPLACEMENT;

The WINDOWPLACEMENT structure contains information about the placement of a window on the screen.

Members

length

Specifies the length, in bytes, of the structure. Before calling the GetWindowPlacement or SetWindowPlacement functions, set this member to sizeof(WINDOWPLACEMENT).

Windows 95 only: GetWindowPlacement and SetWindowPlacement fail if this member is not set correctly.

flags

Specifies flags that control the position of the minimized window and the method by which the window is restored. This member can be one or both of the following values:

Value	Meaning
WPF_RESTORETOMAXIMIZED
	Specifies that the restored window will be maximized, regardless of whether it was maximized before it was minimized. This setting is only valid the next time the window is restored. It does not change the default restoration behavior. This flag is only valid when the SW_SHOWMINIMIZED value is specified for the showCmd member.
WPF_SETMINPOSITION
	Specifies that the coordinates of the minimized window may be specified. This flag must be specified if the coordinates are set in the ptMinPosition member.
showCmd

Specifies the current show state of the window. This member can be one of the following values:

Value	Meaning
SW_HIDE	Hides the window and activates another window.
SW_MINIMIZE	Minimizes the specified window and activates the top-level window in the system's list.
SW_RESTORE	Activates and displays a window. If the window is minimized or maximized, Windows restores it to its original size and position (same as SW_SHOWNORMAL).
SW_SHOW	Activates a window and displays it in its current size and position.
SW_SHOWMAXIMIZED	Activates a window and displays it as a maximized window.
SW_SHOWMINIMIZED	Activates a window and displays it as an icon.
SW_SHOWMINNOACTIVE	Displays a window as an icon. The active window remains active.
SW_SHOWNA	Displays a window in its current state. The active window remains active.
SW_SHOWNOACTIVATE	Displays a window in its most recent size and position. The active window remains active.
SW_SHOWNORMAL	Activates and displays a window. If the window is minimized or maximized, Windows restores it to its original size and position (same as SW_RESTORE).
ptMinPosition

Specifies the coordinates of the window's upper-left corner when the window is minimized.

ptMaxPosition

Specifies the coordinates of the window's upper-left corner when the window is maximized.

rcNormalPosition

Specifies the window's coordinates when the window is in the restored position.

See Also

ShowWindow, POINT, RECT


WINDOWPOS
WINDOWPOS  QuickInfo

typedef struct _WINDOWPOS { // wp

    HWND hwnd;

    HWND hwndInsertAfter;

    int  x;

    int  y;

    int  cx;

    int  cy;

    UINT flags;

} WINDOWPOS;

The WINDOWPOS structure contains information about the size and position of a window.

Members

hwnd

Identifies the window.

hwndInsertAfter

Specifies the position of the window in Z order (front-to-back position). This member can be the handle of the window behind which this window is placed, or can be one of the special values listed with the SetWindowPos function.

x

Specifies the position of the left edge of the window.

y

Specifies the position of the top edge of the window.

cx

Specifies the window width, in pixels.

cy

Specifies the window height, in pixels.

flags

Specifies the window position. This member can be one of the following values:

Value	Meaning
SWP_DRAWFRAME	Draws a frame (defined in the window's class description) around the window. The window receives a WM_NCCALCSIZE message.
SWP_HIDEWINDOW	Hides the window.
SWP_NOACTIVATE	Does not activate the window.
SWP_NOCOPYBITS	Discards the entire contents of the client area. If this flag is not specified, the valid contents of the client area are saved and copied back into the client area after the window has been sized or repositioned.
SWP_NOMOVE	Retains the current position (ignores the x and y parameters).
SWP_NOOWNERZORDER	Does not change the owner window's position in the Z order.
SWP_NOSIZE	Retains the current size (ignores the cx and cy parameters).
SWP_NOREDRAW	Does not redraw changes.
SWP_NOREPOSITION	Same as the SWP_NOOWNERZORDER flag.
SWP_NOZORDER	Retains the current Z order (ignores the hwndInsertAfter member).
SWP_SHOWWINDOW	Displays the window.
See Also

EndDeferWindowPos, SetWindowPos, WM_NCCALCSIZE


WNDCLASS
WNDCLASS  QuickInfo

typedef struct _WNDCLASS {    // wc

    UINT    style;

    WNDPROC lpfnWndProc;

    int     cbClsExtra;

    int     cbWndExtra;

    HANDLE  hInstance;

    HICON   hIcon;

    HCURSOR hCursor;

    HBRUSH  hbrBackground;

    LPCTSTR lpszMenuName;

    LPCTSTR lpszClassName;

} WNDCLASS;

The WNDCLASS structure contains the window class attributes that are registered by the RegisterClass function.

Members

style

Specifies the class style(s). Styles can be combined by using the bitwise OR (|) operator. This member can be any combination of the following values:

Value	Action
CS_BYTEALIGNCLIENT	Aligns the window's client area on the byte boundary (in the x direction) to enhance performance during drawing operations. This style affects the width of the window and its horizontal position on the display.
CS_BYTEALIGNWINDOW	Aligns a window on a byte boundary (in the x direction) to enhance performance during operations that involve moving or sizing the window. This style affects the width of the window and its horizontal position on the display.
CS_CLASSDC	Allocates one device context to be shared by all windows in the class. Because window classes are process specific, it is possible for multiple threads of a multithreaded application to create a window of the same class. It is also possible for the threads to attempt to use the device context simultaneously. When this happens, the operating system allows only one of the threads to successfully finish its drawing operation.
CS_DBLCLKS	Sends double-click messages to the window procedure when the user double-clicks the mouse while the cursor is within a window belonging to the class.
CS_GLOBALCLASS	Allows an application to create a window of the class regardless of the value of the hInstance parameter passed to the CreateWindow or CreateWindowEx function. If you do not specify this style, the hInstance parameter passed to the CreateWindow (or CreateWindowEx) function must be the same as the hInstance parameter passed to the RegisterClass function.
	You can create a global class by creating the window class in a dynamic-link library (DLL) and listing the name of the DLL in the registry under the following keys:
	HKEY_LOCAL_MACHINE\Software \Microsoft\Windows NT\ CurrentVersion\Windows\APPINIT_DLLS
	Whenever a process starts, the operating system loads the specified DLLs in the context of the newly started process before calling the main function in that process. The DLL must register the class during its initialization procedure and must specify the CS_GLOBALCLASS style.
CS_HREDRAW	Redraws the entire window if a movement or size adjustment changes the width of the client area.
CS_NOCLOSE	Disables the Close command on the System menu.
CS_OWNDC	Allocates a unique device context for each window in the class.
CS_PARENTDC	Specifies that child windows inherit their parent window's device context. Specifying CS_PARENTDC enhances an application's performance. When an application calls the GetDC function, passing the handle of a window that belongs to a class with the CS_PARENTDC style, the operating system searches for a device context that has been precalculated for the window's parent window. If all child windows of a particular parent window specify this style, the system need not recalculate a device context for any of the child windows.
CS_SAVEBITS	Saves, as a bitmap, the portion of the screen image obscured by a window. Windows uses the saved bitmap to re-create the screen image when the window is removed. Windows displays the bitmap at its original location and does not send WM_PAINT messages to windows obscured by the window if the memory used by the bitmap has not been discarded and if other screen actions have not invalidated the stored image. This style is useful for small windows (for example, menus or dialog boxes) that are displayed briefly and then removed before other screen activity takes place. This style increases the time required to display the window, because the operating system must first allocate memory to store the bitmap.
CS_VREDRAW	Redraws the entire window if a movement or size adjustment changes the height of the client area.
lpfnWndProc

Points to the window procedure. For more information, see WindowProc.

cbClsExtra

Specifies the number of extra bytes to allocate following the window-class structure. The operating system initializes the bytes to zero.

cbWndExtra

Specifies the number of extra bytes to allocate following the window instance. The operating system initializes the bytes to zero. If an application uses the WNDCLASS structure to register a dialog box created by using the CLASS directive in the resource file, it must set this member to DLGWINDOWEXTRA.

hInstance

Identifies the instance that the window procedure of this class is within.

hIcon

Identifies the class icon. This member must be a handle of an icon resource. If this member is NULL, an application must draw an icon whenever the user minimizes the application's window.

hCursor

Identifies the class cursor. This member must be a handle of a cursor resource. If this member is NULL, an application must explicitly set the cursor shape whenever the mouse moves into the application's window.

hbrBackground

Identifies the class background brush. This member can be a handle to the physical brush to be used for painting the background, or it can be a color value. A color value must be one of the following standard system colors (the value 1 must be added to the chosen color). If a color value is given, you must convert it to one of the following HBRUSH types:

COLOR_ACTIVEBORDER
COLOR_ACTIVECAPTION
COLOR_APPWORKSPACE
COLOR_BACKGROUND
COLOR_BTNFACE
COLOR_BTNSHADOW
COLOR_BTNTEXT
COLOR_CAPTIONTEXT
COLOR_GRAYTEXT
COLOR_HIGHLIGHT
COLOR_HIGHLIGHTTEXT
COLOR_INACTIVEBORDER
COLOR_INACTIVECAPTION
COLOR_MENU
COLOR_MENUTEXT
COLOR_SCROLLBAR
COLOR_WINDOW
COLOR_WINDOWFRAME
COLOR_WINDOWTEXT

The operating system automatically deletes class background brushes when the class is freed. An application should not delete these brushes, because a class may be used by multiple instances of an application.

When this member is NULL, an application must paint its own background whenever it is requested to paint in its client area. To determine whether the background must be painted, an application can either process the WM_ERASEBKGND message or test the fErase member of the PAINTSTRUCT structure filled by the BeginPaint function.

lpszMenuName

Points to a null-terminated character string that specifies the resource name of the class menu, as the name appears in the resource file. If you use an integer to identify the menu, use the MAKEINTRESOURCE macro. If this member is NULL, windows belonging to this class have no default menu.

lpszClassName

Points to a null-terminated string or is an atom. If this parameter is an atom, it must be a global atom created by a previous call to the GlobalAddAtom function. The atom, a 16-bit value, must be in the low-order word of lpszClassName; the high-order word must be zero.

If lpszClassName is a string, it specifies the window class name.

See Also

BeginPaint, CreateWindow, CreateWindowEx, GetDC, GlobalAddAtom, MAKEINTRESOURCE, PAINTSTRUCT, RegisterClass, WindowProc, WM_PAINT


WNDCLASSEX
WNDCLASSEX  QuickInfo

typedef struct _WNDCLASSEX {    // wc

    UINT    cbSize;

    UINT    style;

    WNDPROC lpfnWndProc;

    int     cbClsExtra;

    int     cbWndExtra;

    HANDLE  hInstance;

    HICON   hIcon;

    HCURSOR hCursor;

    HBRUSH  hbrBackground;

    LPCTSTR lpszMenuName;

    LPCTSTR lpszClassName;

    HICON   hIconSm;

} WNDCLASSEX;

The WNDCLASSEX structure contains window class information. It is used with the the RegisterClassEx and GetClassInfoEx functions.

The WNDCLASSEX structure is similar to the WNDCLASS structure. There are two differences. WNDCLASSEX includes the cbSize member, which specifies the size of the structure, and the hIconSm member, which contains a handle to a small icon associated with the window class.

Windows NT: The hIconSm member is not used. Set it to NULL before calling RegisterClassEx. It will be NULL when GetClassInfoEx returns.

Members

cbSize

Specifies the size, in bytes, of this structure. Set this member to sizeof(WINDOWCLASSEX). Be sure to set this member before calling the GetClassInfoEx function.

style

Specifies the class style(s). Styles can be combined by using the bitwise OR (|) operator. This member can be any combination of the following values:

Value	Action
CS_BYTEALIGNCLIENT	Aligns the window's client area on the byte boundary (in the x direction) to enhance performance during drawing operations. This style affects the width of the window and its horizontal position on the display.
CS_BYTEALIGNWINDOW	Aligns a window on a byte boundary (in the x direction) to enhance performance during operations that involve moving or sizing the window. This style affects the width of the window and its horizontal position on the display.
CS_CLASSDC	Allocates one device context to be shared by all windows in the class. Because window classes are process specific, it is possible for multiple threads of a multithreaded application to create a window of the same class. It is also possible for the threads to attempt to use the device context simultaneously. When this happens, the operating system allows only one of the threads to successfully finish its drawing operation.
CS_DBLCLKS	Sends double-click messages to the window procedure when the user double-clicks the mouse while the cursor is within a window belonging to the class.
CS_GLOBALCLASS	Allows an application to create a window of the class regardless of the value of the hInstance parameter passed to the CreateWindow or CreateWindowEx function. If you do not specify this style, the hInstance parameter passed to the CreateWindow (or CreateWindowEx) function must be the same as the hInstance parameter passed to the RegisterClass function.
	You can create a global class by creating the window class in a dynamic-link library (DLL) and listing the name of the DLL in the registry under the following keys:
	HKEY_LOCAL_MACHINE\Software \Microsoft\Windows NT\ CurrentVersion\Windows\APPINIT_DLLS
	Whenever a process starts, the operating system loads the specified DLLs in the context of the newly started process before calling the main function in that process. The DLL must register the class during its initialization procedure and must specify the CS_GLOBALCLASS style.
CS_HREDRAW	Redraws the entire window if a movement or size adjustment changes the width of the client area.
CS_NOCLOSE	Disables the Close command on the System menu.
CS_OWNDC	Allocates a unique device context for each window in the class.
CS_PARENTDC	Specifies that child windows inherit their parent window's device context. Specifying CS_PARENTDC enhances an application's performance. When an application calls the GetDC function, passing the handle of a window that belongs to a class with the CS_PARENTDC style, the operating system searches for a device context that has been precalculated for the window's parent window. If all child windows of a particular parent window specify this style, the system need not recalculate a device context for any of the child windows.
CS_SAVEBITS	Saves, as a bitmap, the portion of the screen image obscured by a window. Windows uses the saved bitmap to re-create the screen image when the window is removed. Windows displays the bitmap at its original location and does not send WM_PAINT messages to windows obscured by the window if the memory used by the bitmap has not been discarded and if other screen actions have not invalidated the stored image. This style is useful for small windows (for example, menus or dialog boxes) that are displayed briefly and then removed before other screen activity takes place. This style increases the time required to display the window, because the operating system must first allocate memory to store the bitmap.
CS_VREDRAW	Redraws the entire window if a movement or size adjustment changes the height of the client area.
lpfnWndProc

Points to the window procedure. For more information, see WindowProc.

cbClsExtra

Specifies the number of extra bytes to allocate following the window-class structure. The operating system initializes the bytes to zero.

cbWndExtra

Specifies the number of extra bytes to allocate following the window instance. The operating system initializes the bytes to zero. If an application uses the WNDCLASS structure to register a dialog box created by using the CLASS directive in the resource file, it must set this member to DLGWINDOWEXTRA.

hInstance

Identifies the instance that the window procedure of this class is within.

hIcon

Identifies the class icon. This member must be a handle of an icon resource. If this member is NULL, an application must draw an icon whenever the user minimizes the application's window.

hCursor

Identifies the class cursor. This member must be a handle of a cursor resource. If this member is NULL, an application must explicitly set the cursor shape whenever the mouse moves into the application's window.

hbrBackground

Identifies the class background brush. This member can be a handle to the physical brush to be used for painting the background, or it can be a color value. A color value must be one of the following standard system colors (the value 1 must be added to the chosen color). If a color value is given, you must convert it to one of the following HBRUSH types:

COLOR_ACTIVEBORDER
COLOR_ACTIVECAPTION
COLOR_APPWORKSPACE
COLOR_BACKGROUND
COLOR_BTNFACE
COLOR_BTNSHADOW
COLOR_BTNTEXT
COLOR_CAPTIONTEXT
COLOR_GRAYTEXT
COLOR_HIGHLIGHT
COLOR_HIGHLIGHTTEXT
COLOR_INACTIVEBORDER
COLOR_INACTIVECAPTION
COLOR_MENU
COLOR_MENUTEXT
COLOR_SCROLLBAR
COLOR_WINDOW
COLOR_WINDOWFRAME
COLOR_WINDOWTEXT

The operating system automatically deletes class background brushes when the class is freed. An application should not delete these brushes, because a class may be used by multiple instances of an application.

When this member is NULL, an application must paint its own background whenever it is requested to paint in its client area. To determine whether the background must be painted, an application can either process the WM_ERASEBKGND message or test the fErase member of the PAINTSTRUCT structure filled by the BeginPaint function.

lpszMenuName

Points to a null-terminated character string that specifies the resource name of the class menu, as the name appears in the resource file. If you use an integer to identify the menu, use the MAKEINTRESOURCE macro. If this member is NULL, windows belonging to this class have no default menu.

lpszClassName

Points to a null-terminated string or is an atom. If this parameter is an atom, it must be a global atom created by a previous call to the GlobalAddAtom function. The atom, a 16-bit value, must be in the low-order word of lpszClassName; the high-order word must be zero.

If lpszClassName is a string, it specifies the window class name.

hIconSm

Windows 95: Handle to a small icon that is associated with the window class.

Windows NT: This member is not used. Set it to NULL before calling RegisterClassEx. It will be NULL when GetClassInfoEx returns.

See Also

GetClassInfoEx, RegisterClassEx, WNDCLASS


XFORM
XFORM  QuickInfo

typedef struct  _XFORM {  // xfrm

    FLOAT eM11;

    FLOAT eM12;

    FLOAT eM21;

    FLOAT eM22;

    FLOAT eDx;

    FLOAT eDy;

} XFORM;

The XFORM structure specifies a world-space to page-space transformation.

Members

eM11

Specifies the following:

Operation	Meaning
Scaling	Horizontal scaling component
Rotation	Cosine of rotation angle
Reflection	Horizontal component
eM12

Specifies the following:

Operation	Meaning
Shear	Horizontal proportionality constant
Rotation	Sine of the rotation angle
eM21

Specifies the following:

Operation	Meaning
Shear	Vertical proportionality constant
Rotation	Negative sine of the rotation angle
eM22

Specifies the following:

Operation	Meaning
Scaling	Vertical scaling component
Rotation	Cosine of rotation angle
Reflection	Vertical reflection component
eDx

Specifies the horizontal translation component.

eDy

Specifies the vertical translation component.

Remarks

The following list describes how the members are used for each operation:

Operation	eM11	eM12	eM21	eM22
Rotation	Cosine	Sine	Negative sine	Cosine
Scaling	Horizontal scaling component	Nothing	Nothing	Vertical Scaling Component
Shear	Nothing	Horizontal Proportionality Constant	Vertical Proportionality Constant	Nothing
Reflection	Horizontal Reflection Component	Nothing	Nothing	Vertical Reflection Component
See Also

ExtCreateRegion, GetWorldTransform, ModifyWorldTransform, PlayEnhMetaFile, SetWorldTransform


ACL_INFORMATION_CLASS
ACL_INFORMATION_CLASS  QuickInfo

typedef enum _ACL_INFORMATION_CLASS { // aclic

    AclRevisionInformation = 1,    // ACL revision information

    AclSizeInformation             // ACL size information

} ACL_INFORMATION_CLASS;

The ACL_INFORMATION_CLASS enumeration type contains values that specify the type of information being assigned to or retrieved from an access-control list (ACL).

See Also

ACL, ACL_REVISION_INFORMATION, ACL_SIZE_INFORMATION, GetAclInformation, SetAclInformation


MEDIA_TYPE
MEDIA_TYPE  QuickInfo

typedef enum _MEDIA_TYPE {

    Unknown,                // Format is unknown

    F5_1Pt2_512,            // 5.25", 1.2MB,  512 bytes/sector

    F3_1Pt44_512,           // 3.5",  1.44MB, 512 bytes/sector

    F3_2Pt88_512,           // 3.5",  2.88MB, 512 bytes/sector

    F3_20Pt8_512,           // 3.5",  20.8MB, 512 bytes/sector

    F3_720_512,             // 3.5",  720KB,  512 bytes/sector

    F5_360_512,             // 5.25", 360KB,  512 bytes/sector

    F5_320_512,             // 5.25", 320KB,  512 bytes/sector

    F5_320_1024,            // 5.25", 320KB,  1024 bytes/sector

    F5_180_512,             // 5.25", 180KB,  512 bytes/sector

    F5_160_512,             // 5.25", 160KB,  512 bytes/sector

    RemovableMedia,         // Removable media other than floppy

    FixedMedia              // Fixed hard disk media

} MEDIA_TYPE;

The MEDIA_TYPE enumeration type contains values that specify various forms of device media. The comments above explain the enumerators.

Remarks

The MediaType member of the DISK_GEOMETRY data structure is of type MEDIA_TYPE. The DeviceIoControl function receives a DISK_GEOMETRY structure in response to an IOCTL_DISK_GET_DRIVE_GEOMETRY device I/O operation. The DeviceIoControl function receives an array of DISK_GEOMETRY structures in response to an IOCTL_DISK_GET_MEDIA_TYPES device I/O operation.

See Also

DeviceIoControl, DISK_GEOMETRY, IOCTL_DISK_GET_DRIVE_GEOMETRY, IOCTL_DISK_GET_MEDIA_TYPES


RASCONNSTATE
RASCONNSTATE  QuickInfo

typedef enum _RASCONNSTATE {

    RASCS_OpenPort = 0,

    RASCS_PortOpened,

    RASCS_ConnectDevice,

    RASCS_DeviceConnected,

    RASCS_AllDevicesConnected,

    RASCS_Authenticate,

    RASCS_AuthNotify,

    RASCS_AuthRetry,

    RASCS_AuthCallback,

    RASCS_AuthChangePassword,

    RASCS_AuthProject,

    RASCS_AuthLinkSpeed,

    RASCS_AuthAck,

    RASCS_ReAuthenticate,

    RASCS_Authenticated,

    RASCS_PrepareForCallback,

    RASCS_WaitForModemReset,

    RASCS_WaitForCallback,
    RASCS_Projected,

#if (WINVER >= 0x400)

    RASCS_StartAuthentication,    // Windows 95 only

    RASCS_CallbackComplete,       // Windows 95 only

    RASCS_LogonNetwork,           // Windows 95 only

#endif

    RASCS_Interactive = RASCS_PAUSED,

    RASCS_RetryAuthentication,

    RASCS_CallbackSetByCaller,

    RASCS_PasswordExpired,

    RASCS_Connected = RASCS_DONE,

    RASCS_Disconnected

} RASCONNSTATE ;

The RASCONNSTATE enumeration type contains values that specify the states that may occur when connecting by using the RasDial function.

A RASCONNSTATE enumerator value is returned as part of a RASCONNSTATUS structure, which is retrieved by calls to the RasGetConnectStatus function.

The enumerator values are listed here in the general order in which the connection states occur. However, you should not write code that depends on the order or occurrence of particular RASCONNSTATE connection states, because this may vary between platforms.

Enumerator	Meaning
RASCS_OpenPort	The communication port is about to be opened.
RASCS_PortOpened	The communication port has been opened successfully.
RASCS_ConnectDevice	A device is about to be connected. RasGetConnectStatus can be called to determine the name and type of the device being connected.
RASCS_DeviceConnected	A device has connected successfully. RasGetConnectStatus can be called to determine the name and type of the device being connected.
	For a simple modem connection, RASCS_ConnectDevice and RASCS_DeviceConnected will be called only once. For a dial-up X.25 PAD connection, the pair will be called first for the modem, then for the PAD. If a preconnect switch is configured, the pair will be called for the switch before any other devices connect. Likewise, the pair will be called for a postconnect switch after any other devices connect. Windows 95: Note that Windows 95 does not currently support multi-stage connections such as the X.25 PAD connection described above.
RASCS_AllDevicesConnected	All devices in the device chain have successfully connected. At this point, the physical link is established.
RASCS_Authenticate	The authentication process is starting. Remote access does not allow the remote client to generate any traffic on the LAN until authentication has been successfully completed.  Remote access authentication on a Windows NT or Windows 95 server consists of: • Validating the username/password on the specified domain.  • Projecting the client onto the LAN. This means that the remote access server does what is necessary to send and receive data on the LAN on behalf of the client. For example, the remote access server might need to add a NetBIOS name that corresponds to the client's computer name.  • Callback processing in which the client hangs up and the server calls back. (The user needs special permissions on the remote access server for this.)  • Calculating the link speed. This is necessary to correctly set transport timeouts to match the relatively slow speed of the remote link.
RASCS_AuthNotify	An authentication event has occurred. If dwError is zero, this event will be immediately followed by one of the more specific authentication states following. If dwError is nonzero, authentication has failed, and the error value indicates why.
RASCS_AuthRetry	The client has requested another validation attempt with a new username/password/domain. This state does not occur in Windows NT version 3.1.
RASCS_AuthCallback	The remote access server has requested a callback number. This occurs only if the user has "Set By Caller" callback privilege on the server.
RASCS_AuthChangePassword	The client has requested to change the password on the account. This state does not occur in Windows NT version 3.1.
RASCS_AuthProject	The projection phase is starting.
RASCS_AuthLinkSpeed	The link-speed calculation phase is starting.
RASCS_AuthAck	An authentication request is being acknowledged.
RASCS_ReAuthenticate	Reauthentication (after callback) is starting.
RASCS_Authenticated	The client has successfully completed authentication.
RASCS_PrepareForCallback	The line is about to disconnect in preparation for callback.
RASCS_WaitForModemReset	The client is delaying in order to give the modem time to reset itself in preparation for callback.
RASCS_WaitForCallback	The client is waiting for an incoming call from the remote access server.
RASCS_Projected	This state occurs after the RASCS_AuthProject state. It indicates that projection result information is available. You can access the projection result information by calling RasGetProjectionInfo.
RASCS_StartAuthentication	Windows 95 only: Indicates that user authentication is being initiated or retried.
RASCS_CallbackComplete	Windows 95 only: Indicates that the client has been called back and is about to resume authentication.
RASCS_LogonNetwork	Windows 95 only: Indicates that the client is logging on to the network.
RASCS_Interactive	This state corresponds to the terminal state supported by RASPHONE.EXE. This state does not occur in Windows NT version 3.1.
RASCS_RetryAuthentication	This state corresponds to the retry authentication state supported by RASPHONE.EXE. This state does not occur in Windows NT version 3.1.
RASCS_CallbackSetByCaller	This state corresponds to the Callback state supported by RASPHONE.EXE. This state does not occur in Windows NT version 3.1.
RASCS_PasswordExpired	This state corresponds to the change password state supported by RASPHONE.EXE. This state does not occur in Windows NT version 3.1.
RASCS_Connected	Successful connection.
RASCS_Disconnected	Disconnection or failed connection.
Remarks

The connection process states are divided into three classes: running states, paused states, and terminal states.

An application can easily determine the class of a specific state by performing Boolean bit operations with the RASCS_PAUSED and RASCS_DONE bitmasks. Here are some examples:

fDoneState = (state & RASCS_DONE);

fPausedState = (state & RASCS_PAUSED);

fRunState = !(fDoneState || fPausedState);

See Also

RasDial, RasGetConnectStatus, RasGetProjectionInfo, RASCONNSTATUS


RASPROJECTION
RASPROJECTION  QuickInfo  Overview  Group

typedef enum _RASPROJECTION {

    RASP_Amb = 0x10000,

    RASP_PppNbf = 0x803F,

    RASP_PppIpx = 0x802B,

    RASP_PppIp = 0x8021

} RASPROJECTION ;

The RASPROJECTION enumeration type defines values that specify a particular authentication protocol or Point-to-Point Protocol control protocol (PPP). An application passes a value of this type to the RasGetProjectionInfo function to specify the protocol of interest.

Each of the RASPROJECTION enumerators has a corresponding data structure; the RasGetProjectionInfo function returns the specified information in a structure of that type.

Value	Meaning
RASP_Amb	Specifies the Authentication Message Block (AMB) authentication protocol. AMB is a NetBIOS-based protocol used to authenticate with downlevel remote access servers ( all those prior to Windows NT 3.5). The corresponding data structure is a RASAMB.
RASP_PppNbf	Specifies the NetBEUI Framer (NBF) protocol. NBFCP is a PPP network control protocol used to negotiate the parameters necessary to ship NetBEUI packets on a WAN link. The corresponding data structure is a RASPPPNBF.
RASP_PppIpx	Specifies the Internetwork Packet Exchange (IPX) control protocol. IPXCP is a PPP network control protocol used to negotiate the parameters necessary to ship IPX packets on a WAN link. The corresponding data structure is a RASPPPIPX.
RASP_PppIp	Specifies the Internet Protocol (IP) control protocol. IPCP is a PPP network control protocol used to negotiate the parameters necessary to ship IP packets on a WAN link.  The corresponding data structure is a RASPPPIP.
See Also

RasGetProjectionInfo, RASAMB, RASPPPIP, RASPPPIPX, RASPPPNBF


SECURITY_IMPERSONATION_LEVEL
SECURITY_IMPERSONATION_LEVEL  QuickInfo

typedef enum _SECURITY_IMPERSONATION_LEVEL { // sil

    SecurityAnonymous,

    SecurityIdentification,

    SecurityImpersonation,

    SecurityDelegation

} SECURITY_IMPERSONATION_LEVEL;

The SECURITY_IMPERSONATION_LEVEL enumeration type contains values that specify security impersonation levels. Security impersonation levels govern the degree to which a server process can act on behalf of a client process.

Value	Meaning
SecurityAnonymous	The server process cannot obtain identification information about the client and it cannot impersonate the client. It is defined with no value given, and thus, by ANSI C rules, defaults to a value of 0.
SecurityIdentification	The server process can obtain information about the client, such as security identifiers and privileges, but it cannot use kernel functions. This is useful for servers that export their own objects — for example, tables and views exported by a database product. Using the retrieved client-security information, the server can make access-validation decisions without being able to utilize other services using the client's security context.
SecurityImpersonation	The server process can impersonate the client's security context on its local system. The server cannot impersonate the client on remote systems.
SecurityDelegation	This impersonation level is not supported in the current version of Windows NT.
Remarks

Impersonation is the ability of a process to take on the security attributes of another process.

See Also

CreatePrivateObjectSecurity, DuplicateToken, GetTokenInformation, ImpersonateSelf, OpenThreadToken


SID_NAME_USE
SID_NAME_USE  QuickInfo

typedef enum _SID_NAME_USE {

    SidTypeUser = 1,

    SidTypeGroup,

    SidTypeDomain,

    SidTypeAlias,

    SidTypeWellKnownGroup,

    SidTypeDeletedAccount,

    SidTypeInvalid,

    SidTypeUnknown

} SID_NAME_USE;

The SID_NAME_USE enumeration type contains values that specify the type of a security identifier (SID).

Value	Meaning
SidTypeUser	Indicates a user SID.
SidTypeGroup	Indicates a group SID.
SidTypeDomain	Indicates a domain SID.
SidTypeAlias	Indicates an alias SID.
SidTypeWellKnownGroup	Indicates an SID for a well-known group.
SidTypeDeletedAccount	Indicates an SID for a deleted account.
SidTypeInvalid	Indicates an invalid SID.
SidTypeUnknown	Indicates an unknown SID type.
See Also

LookupAccountName, LookupAccountSid


TOKEN_INFORMATION_CLASS
TOKEN_INFORMATION_CLASS  QuickInfo

typedef enum _TOKEN_INFORMATION_CLASS { // tic

    TokenUser = 1,

    TokenGroups,

    TokenPrivileges,

    TokenOwner,

    TokenPrimaryGroup,

    TokenDefaultDacl,

    TokenSource,

    TokenType,

    TokenImpersonationLevel,

    TokenStatistics

} TOKEN_INFORMATION_CLASS;

The TOKEN_INFORMATION_CLASS enumeration type contains values that specify the type of information being assigned to or retrieved from an access token.

See Also

GetTokenInformation, SetTokenInformation, TOKEN_CONTROL, TOKEN_DEFAULT_DACL, TOKEN_GROUPS, TOKEN_OWNER, TOKEN_PRIMARY_GROUP, TOKEN_PRIVILEGES, TOKEN_SOURCE, TOKEN_STATISTICS, TOKEN_TYPE, TOKEN_USER


TOKEN_TYPE
TOKEN_TYPE  QuickInfo

typedef enum tagTOKEN_TYPE { // tt

    TokenPrimary = 1,

    TokenImpersonation

} TOKEN_TYPE;

The TOKEN_TYPE enumeration type contains values that differentiate between a primary token and an impersonation token.

See Also

GetTokenInformation, TOKEN_CONTROL, TOKEN_DEFAULT_DACL, TOKEN_GROUPS, TOKEN_INFORMATION_CLASS, TOKEN_OWNER, TOKEN_PRIMARY_GROUP, TOKEN_PRIVILEGES, TOKEN_SOURCE, TOKEN_STATISTICS, TOKEN_USER


Animate_Create [New - Windows NT]
Animate_Create  QuickInfo  Overview  Group

[New - Windows NT]

The Animate_Create macro creates an animation control. Animate_Create calls the CreateWindow function.

HWND Animate_Create(

HWND  hwndP,
UINT  id,
DWORD  dwStyle,
HINSTANCE  hInstance
);
Parameters

hwndP

Handle to the parent window.

id

Child window identifier of the animation control.

dwStyle

Window styles. For a list of the animation-control style values, see Animation Control Styles.

hInstance

Handle to the instance of the module that is creating the animation control.

Return Value

Returns the handle to the animation control.

Remarks

The Animate_Create macro sets the width and height of the animation control to zero if the ACS_CENTER style is specified. If the ACS_CENTER style is not specified, Animate_Create sets the width and height based on the dimensions of a frame in the AVI clip.

See Also

CreateWindow


CMYK [New - Windows 95]
CMYK  QuickInfo  Overview  Group

[New - Windows 95]

The CMYK macro creates a CMYK color value by combining the specified cyan, magenta, yellow, and black values.

COLORREF CMYK(

c,
m,
y,
k
);
See Also

GetCValue, GetMValue, GetKValue, GetYValue


FORWARD_WM_NOTIFY [New - Windows NT]
FORWARD_WM_NOTIFY  QuickInfo  Overview  Group

[New - Windows NT]

The FORWARD_WM_NOTIFY macro sends or posts the WM_NOTIFY message.

VOID FORWARD_WM_NOTIFY(

hwnd,
idFrom,
pnmhdr,
fn
);
Parameters

hwnd

Handle to the window that receives the WM_NOTIFY message.

idFrom

Identifier of the control sending the message.

pnmhdr

Pointer to an NMHDR structure that contains the notification code and additional information. For some notification messages, this parameter points to a larger structure that has the NMHDR structure as its first member.

fn

Function that sends or posts the WM_NOTIFY message. This parameter can be either the SendMessage or PostMessage function.

Return Value

Returns a value whose meaning depends on the fn parameter.

Remarks

The FORWARD_WM_NOTIFY macro is defined as follows:

#define FORWARD_WM_NOTIFY(hwnd, idFrom, pnmhdr, fn) \

    (void)(fn)((hwnd), WM_NOTIFY, (WPARAM)(int)(id), \

    (LPARAM)(NMHDR FAR*)(pnmhdr))

See Also

NMHDR, PostMessage, SendMessage, WM_NOTIFY


GetBValue
GetBValue  QuickInfo

The GetBValue macro retrieves an intensity value for the blue component of a 32-bit red, green, blue (RGB) value.

BYTE GetBValue(

WORD  rgb	// 32-bit RGB value
);
Parameters

rgb

Specifies an RGB color value.

Return Value

The return value is the intensity of the blue component of the specified RGB color.

Remarks

The intensity value is in the range 0 through 255.

The GetBValue macro is defined as follows:

#define GetBValue(rgb)   ((BYTE) ((rgb) >> 16))

See Also

GetGValue, GetRValue, PALETTEINDEX, PALETTERGB, RGB


GetCValue [New - Windows 95]
GetCValue  QuickInfo  Overview  Group

[New - Windows 95]

The GetCValue macro retrieves the cyan color value from a CMYK color value.

BYTE GetCValue(

cmyk
);
See Also

CMYK, GetKValue, GetMValue, GetYValue


GetGValue
GetGValue  QuickInfo

The GetGValue macro retrieves an intensity value for the green component of a 32-bit red, green, blue (RGB) value.

BYTE GetGValue(

DWORD  rgb	// 32-bit RGB value
);
Parameters

rgb

Specifies an RGB color value.

Return Value

The return value is the intensity of the green component of the specified RGB color.

Remarks

The intensity value is in the range 0 through 255.

The GetGValue macro is defined as follows:

#define GetGValue(rgb)   ((BYTE) (((WORD) (rgb)) >> 8))

See Also

GetBValue, GetRValue, PALETTEINDEX, PALETTERGB, RGB


GetKValue [New - Windows 95]
GetKValue  QuickInfo  Overview  Group

[New - Windows 95]

The GetKValue macro retrieves the black color value from a CMYK color value.

BYTE GetKValue(

cmyk
);
See Also

CMYK, GetCValue, GetMValue, GetYValue


GetMValue [New - Windows 95]
GetMValue  QuickInfo  Overview  Group

[New - Windows 95]

The GetMValue macro retrieves the magenta color value from a CMYK color value.

BYTE GetMValue(

cmyk
);
See Also

CMYK, GetCValue, GetKValue, GetYValue


GetRValue
GetRValue  QuickInfo

The GetRValue macro retrieves an intensity value for the red component of a 32-bit red, green, blue (RGB) value.

BYTE GetRValue(

DWORD  rgb	// 32-bit RGB value
);
Parameters

rgb

Specifies an RGB color value.

Return Value

The return value is the intensity of the red component of the specified RGB color.

Remarks

The intensity value is in the range 0 through 255.

The GetRValue macro is defined as follows:

#define GetRValue(rgb)   ((BYTE) (rgb))

See Also

GetBValue, GetGValue, PALETTEINDEX, PALETTERGB, RGB


GetYValue [New - Windows 95]
GetYValue  QuickInfo  Overview  Group

[New - Windows 95]

The GetYValue macro retrieves the yellow color value from a CMYK color value.

BYTE GetYValue(

cmyk
);
See Also

CMYK, GetCValue, GetMValue, GetKValue,


HANDLE_WM_NOTIFY [New - Windows NT]
HANDLE_WM_NOTIFY  QuickInfo  Overview  Group

[New - Windows NT]

The HANDLE_WM_NOTIFY macro calls a function that processes the WM_NOTIFY message.

HANDLE_WM_NOTIFY(

hwnd,
wParam,
lParam,
fn
);
Parameters

hwnd

Handle to the window that received WM_NOTIFY.

wParam

First parameter of WM_NOTIFY.

lParam

Second parameter of WM_NOTIFY.

fn

Function that is to process WM_NOTIFY.

Return Value

Returns a value whose meaning depends on the fn parameter.

Remarks

The HANDLE_WM_NOTIFY macro is defined as follows:

#define HANDLE_WM_NOTIFY(hwnd, wParam, lParam, fn) \

    (fn)((hwnd), (int)(wParam), (NMHDR FAR*)(lParam))

See Also

WM_NOTIFY


HIBYTE
HIBYTE  QuickInfo

The HIBYTE macro retrieves the high-order byte from the given 16-bit value.

BYTE HIBYTE(

WORD  wValue	// value from which high-order byte is retrieved
);
Parameters

wValue

Specifies the value to be converted.

Return Value

The return value is the high-order byte of the specified value.

Remarks

The HIBYTE macro is defined as follows:

#define HIBYTE(w)   ((BYTE) (((WORD) (w) >> 8) & 0xFF))

See Also

HIWORD, LOBYTE


HIWORD
HIWORD  QuickInfo

The HIWORD macro retrieves the high-order word from the given 32-bit value.

WORD HIWORD(

DWORD  dwValue	// value from which high-order word is retrieved
);
Parameters

dwValue

Specifies the value to be converted.

Return Value

The return value is the high-order word of the specified value.

Remarks

The HIWORD macro is defined as follows:

#define HIWORD(l)   ((WORD) (((DWORD) (l) >> 16) & 0xFFFF))

See Also

HIBYTE, LOWORD


INDEXTOOVERLAYMASK [New - Windows NT]
INDEXTOOVERLAYMASK  QuickInfo  Overview  Group

[New - Windows NT]

The INDEXTOOVERLAYMASK macro prepares the index of an overlay mask so that the ImageList_Draw function can use it.

UINT INDEXTOOVERLAYMASK(

UINT  iOverlay	//
);
Parameters

iOverlay

Index of an overlay mask.

Remarks

The INDEXTOOVERLAYMASK macro is defined as follows:

#define INDEXTOOVERLAYMASK(i) ((i) << 8)


INDEXTOSTATEIMAGEMASK [New - Windows NT]
INDEXTOSTATEIMAGEMASK  QuickInfo  Overview  Group

[New - Windows NT]

The INDEXTOSTATEIMAGEMASK macro prepares the index of a state image so that a tree-view control or list-view control can use the index to retrieve the state image for an item.

UINT INDEXTOSTATEIMAGEMASK(

UINT  i
);
Parameters

i

Index of a state image.

Remarks

The INDEXTOSTATEIMAGEMASK macro is defined as follows:

#define INDEXTOSTATEIMAGEMASK(i) ((i) << 12)


LANGIDFROMLCID
LANGIDFROMLCID  QuickInfo  Overview  Group

The LANGIDFROMLCID macro retrieves a language identifier from a locale identifier.

WORD LANGIDFROMLCID(

LCID  lcid	// locale identifier
);
Parameters

lcid

Specifies the locale identifier. This parameter may have been created by using the MAKELCID macro.

Return Value

The return value is a language identifier.

Remarks

The LANGIDFROMLCID macro is defined as follows:

#define LANGIDFROMLCID(lcid)   ((WORD) (lcid))

See Also

MAKELANGID, MAKELCID, PRIMARYLANGID, SUBLANGID


LOBYTE
LOBYTE  QuickInfo

The LOBYTE macro retrieves the low-order byte from the given 16-bit value.

BYTE LOBYTE(

WORD  wValue	// value from which low-order byte is retrieved
);
Parameters

wValue

Specifies the value to be converted.

Return Value

The return value is the low-order byte of the specified value.

Remarks

The LOBYTE macro is defined as follows:

#define LOBYTE(w)   ((BYTE) (w))

See Also

HIBYTE, LOWORD


LOWORD
LOWORD  QuickInfo

The LOWORD macro retrieves the low-order word from the given 32-bit value.

WORD LOWORD(

DWORD  dwValue	// value from which low-order word is retrieved
);
Parameters

dwValue

Specifies the value to be converted.

Return Value

The return value is the low-order word of the specified value.

Remarks

The LOWORD macro is defined as follows:

#define LOWORD(l)   ((WORD) (l))

See Also

HIWORD, LOBYTE


MAKEINTATOM
MAKEINTATOM  QuickInfo

The MAKEINTATOM macro creates an integer atom that represents a character string of decimal digits.

Integer atoms created by this macro can be added to an atom table by using the AddAtom or GlobalAddAtom function.

LPTSTR MAKEINTATOM(

WORD  wInteger	// integer to make into atom
);
Parameters

wInteger

Specifies the numeric value to be made into an integer atom.

Return Value

The return value is a pointer to the atom created for the given integer.

Remarks

Although the return value of the MAKEINTATOM macro is cast as an LPTSTR value, it cannot be used as a string pointer except when it is passed to atom-management functions that require an LPTSTR argument.

The DeleteAtom and GlobalDeleteAtom functions always succeed for integer atoms, even though they do nothing. The string returned by the GetAtomName and GlobalGetAtomName functions for an integer atom is a null-terminated string in which the first character is a pound sign (#) and the remaining characters are the decimal digits used in the MAKEINTATOM macro.

The MAKEINTATOM macro is defined as follows:

#define MAKEINTATOM(i)   (LPTSTR) ((DWORD) ((WORD) (i)))

See Also

AddAtom, DeleteAtom, GetAtomName, GlobalAddAtom, GlobalDeleteAtom, GlobalGetAtomName


MAKEINTRESOURCE
MAKEINTRESOURCE  QuickInfo

The MAKEINTRESOURCE macro converts an integer value to a resource type compatible with Win32 resource-management functions. This macro is used in place of a string containing the name of the resource.

LPTSTR MAKEINTRESOURCE(

WORD  wInteger	// integer to convert
);
Parameters

wInteger

Specifies the integer value to be converted.

Return Value

The return value is the specified value in the low-order word and zero in the high-order word.

Remarks

The return value should be passed only to the Win32 resource-management functions, as the lpType parameter.

The MAKEINTRESOURCE macro is defined as follows:

#define MAKEINTRESOURCE(i)  (LPTSTR) ((DWORD) ((WORD) (i)))


MAKELANGID
MAKELANGID  QuickInfo  Overview  Group

The MAKELANGID macro creates a language identifier from a primary language identifier and a sublanguage identifier.

WORD MAKELANGID(

USHORT  usPrimaryLanguage,	// primary language identifier
USHORT  usSubLanguage	// sublanguage identifier
);
Parameters

usPrimaryLanguage

Specifies the primary language identifier. This parameter can be one of the following values:

LANG_BULGARIAN	LANG_JAPANESE
LANG_CHINESE	LANG_KOREAN
LANG_CROATIAN	LANG_NEUTRAL
LANG_CZECH	LANG_NORWEGIAN
LANG_DANISH	LANG_POLISH
LANG_DUTCH	LANG_PORTUGUESE
LANG_ENGLISH	LANG_ROMANIAN
LANG_FINNISH	LANG_RUSSIAN
LANG_FRENCH	LANG_SLOVAK
LANG_GERMAN	LANG_SLOVENIAN
LANG_GREEK	LANG_SPANISH
LANG_HUNGARIAN	LANG_SWEDISH
LANG_ICELANDIC	LANG_TURKISH
LANG_ITALIAN
Windows 95: In addition to the preceding, Windows 95 also defines the following values:

LANG_AFRIKAANS	LANG_HEBREW
LANG_ALBANIAN	LANG_INDONESIAN
LANG_ARABIC	LANG_LATVIAN
LANG_BASQUE	LANG_LITHUANIAN
LANG_BYELORUSSIAN	LANG_SORBIAN
LANG_CATALAN	LANG_THAI
LANG_ESTONIAN	LANG_UKRANIAN
For a user-defined language, usPrimaryLanguage can be a value in the range 0x0200 to 0x03FF. All other values are reserved for system use.

usSubLanguage

Specifies the sublanguage identifier. This parameter can be one of the following values:

SUBLANG_CHINESE_SIMPLIFIED	SUBLANG_FRENCH_SWISS
SUBLANG_CHINESE_TRADITIONAL	SUBLANG_GERMAN
SUBLANG_CHINESE_HONGKONG	SUBLANG_GERMAN_AUSTRIAN
SUBLANG_CHINESE_SINGAPORE	SUBLANG_GERMAN_SWISS
SUBLANG_DEFAULT	SUBLANG_ITALIAN
SUBLANG_DUTCH	SUBLANG_ITALIAN_SWISS
SUBLANG_DUTCH_BELGIAN	SUBLANG_NEUTRAL
SUBLANG_ENGLISH_AUS	SUBLANG_NORWEGIAN_BOKMAL
SUBLANG_ENGLISH_CAN	SUBLANG_NORWEGIAN_NYNORSK
SUBLANG_ENGLISH_EIRE	SUBLANG_PORTUGUESE
SUBLANG_ENGLISH_NZ	SUBLANG_PORTUGUESE_ BRAZILIAN
SUBLANG_ENGLISH_UK	SUBLANG_SPANISH
SUBLANG_ENGLISH_US	SUBLANG_SPANISH_MEXICAN
SUBLANG_FRENCH	SUBLANG_SPANISH_MODERN
SUBLANG_FRENCH_BELGIAN	SUBLANG_SYS_DEFAULT
SUBLANG_FRENCH_CANADIAN
For a user-defined sublanguage, usSubLanguage can be a value in the range 0x20 to 0x3F. All other values are reserved for system use.

Return Value

The return value is a language identifier that can be used with the FindResourceEx and EnumResLangProc functions.

Remarks

The following three combinations of usPrimaryLanguage and usSubLanguage have special meaning:

Primary language ID	Sublanguage ID	Meaning
LANG_NEUTRAL	SUBLANG_NEUTRAL	Language neutral
LANG_NEUTRAL	SUBLANG_DEFAULT	User default language
LANG_NEUTRAL	SUBLANG_SYS_DEFAULT	System default language
The MAKELANGID macro is defined as follows:

#define MAKELANGID(p, s) ((((WORD) (s)) << 10) | (WORD) (p))

See Also

EnumResLangProc, FindResourceEx, LANGIDFROMLCID, MAKELCID, PRIMARYLANGID, SUBLANGID


MAKELCID
MAKELCID  QuickInfo  Overview  Group

The MAKELCID macro creates a locale identifier from a language identifier.

DWORD MAKELCID(

WORD  wLanguageID,	// language identifier
WORD  wSortID	// sorting identifier
);
Parameters

wLanguageID

Specifies the language identifier. This parameter is a combination of a primary language identifier and a sublanguage identifier and is usually created by using the MAKELANGID macro.

wSortID

Specifies the sort identifier. Use the value SORT_DEFAULT for this parameter.

Return Value

The return value is a locale identifier.

Remarks

The MAKELCID macro is defined as follows:

#define MAKELCID(lgid, srtid)  \

    ((DWORD)((((DWORD)((WORD  )(srtid))) << 16) |  \

            ((DWORD)((WORD  )(lgid)))))

See Also

LANGIDFROMLCID, MAKELANGID, SORTIDFROMLCID


MAKELONG
MAKELONG  QuickInfo

The MAKELONG macro creates an unsigned 32-bit value by concatenating two given 16-bit values.

DWORD MAKELONG(

WORD  wLow,	// low-order word of long value
WORD  wHigh	// high-order word of long value
);
Parameters

wLow

Specifies the low-order word of the new long value.

wHigh

Specifies the high-order word of the new long value.

Return Value

The return value is an unsigned 32-bit value.

Remarks

The MAKELONG macro is defined as follows:

#define MAKELONG(a, b) \

    ((LONG) (((WORD) (a)) | ((DWORD) ((WORD) (b))) << 16))


MAKELPARAM
MAKELPARAM  QuickInfo

The MAKELPARAM macro creates an unsigned 32-bit value for use as an lParam parameter in a message. The macro concatenates two given 16-bit values.

LPARAM MAKELPARAM(

WORD  wLow,	// low-order word
WORD  wHigh	// high-order word
);
Parameters

wLow

Specifies the low-order word of the new long value.

wHigh

Specifies the high-order word of the new long value.

Return Value

The return value is an unsigned 32-bit value.

Remarks

The MAKELPARAM macro is defined as follows:

#define MAKELPARAM(l, h)   ((LPARAM) MAKELONG(l, h))

See Also

MAKELONG, MAKELRESULT, MAKEWPARAM


MAKELRESULT
MAKELRESULT  QuickInfo

The MAKELRESULT macro creates an unsigned 32-bit value for use as a return value from a window procedure. The macro concatenates two given 16-bit values.

LRESULT MAKELRESULT(

WORD  wLow,	// low-order word
WORD  wHigh	// high-order word
);
Parameters

wLow

Specifies the low-order word of the new long value.

wHigh

Specifies the high-order word of the new long value.

Return Value

The return value is an unsigned 32-bit value.

Remarks

The MAKELRESULT macro is defined as follows:

#define MAKELRESULT(l, h)   ((LRESULT) MAKELONG(l, h))

See Also

MAKELONG, MAKELPARAM, MAKEWPARAM


MAKEPOINTS
MAKEPOINTS  QuickInfo

The MAKEPOINTS macro converts a value that contains the x- and y-coordinates of a point into a POINTS structure.

POINTS MAKEPOINTS(

DWORD  dwValue	// coordinates of a point
);
Parameters

dwValue

Specifies the coordinates of a point. The x-coordinate is in the low-order word, and the y-coordinate is in the high-order word.

Return Value

The return value is a pointer to a POINTS structure.

Remarks

The MAKEPOINTS macro is defined as follows:

#define MAKEPOINTS(l)   (*((POINTS FAR *) & (l)))

See Also

GetMessagePos


MAKEROP4
MAKEROP4  QuickInfo

The MAKEROP4 macro creates a quaternary raster operation code for use with the MaskBlt function. The macro takes two ternary raster operation codes as input, one for the foreground and one for the background, and packs their Boolean operation indexes into the high-order word of a 32-bit value. The low-order word of this value will be ignored.

DWORD MAKEROP4(

DWORD  fore,	// foreground ternary raster operation code
DWORD  back	// background ternary raster operation code
);
Parameters

fore

Specifies a foreground ternary raster operation code.

back

Specifies a background ternary raster operation code

Return Value

The return value is a DWORD quaternary raster operation code for use with the MaskBlt function.

Remarks

The MAKEROP4 macro is defined as follows:

#define MAKEROP4(fore,back)

          (DWORD)((((back) << 8) & 0xFF000000) | (fore))

See Also

MaskBlt


MAKEWORD
MAKEWORD  QuickInfo

The MAKEWORD macro creates an unsigned 16-bit integer by concatenating two given unsigned character values.

WORD MAKEWORD(

BYTE  bLow,	// low-order byte of short value
BYTE  bHigh	// high-order byte of short value
);
Parameters

bLow

Specifies the low-order byte of the new short value.

bHigh

Specifies the high-order byte of the new short value.

Return Value

The return value is an unsigned 16-bit integer value.

Remarks

The MAKEWORD macro is defined as follows:

#define MAKEWORD(a, b) \

    ((WORD) (((BYTE) (a)) | ((WORD) ((BYTE) (b))) << 8))


MAKEWPARAM
MAKEWPARAM  QuickInfo

The MAKEWPARAM macro creates an unsigned 32-bit value for use as a wParam parameter in a message. The macro concatenates two given 16-bit values.

LPARAM MAKEWPARAM(

WORD  wLow,	// low-order word
WORD  wHigh	// high-order word
);
Parameters

wLow

Specifies the low-order word of the new long value.

wHigh

Specifies the high-order word of the new long value.

Return Value

The return value is an unsigned 32-bit value.

Remarks

The MAKEWPARAM macro is defined as follows:

#define MAKEWPARAM(l, h)   ((LPARAM) MAKELONG(l, h))

See Also

MAKELONG, MAKELPARAM, MAKELRESULT


max
max  QuickInfo

The max macro compares two values and returns the larger one. The data type can be any numeric data type, signed or unsigned. The data type of the arguments and the return value is the same.

max(

value1,	// low-order word
value2	// high-order word
);
Parameters

value1

Specifies the first of two values.

value2

Specifies the second of two values.

Return Value

The return value is the greater of the two specified values.

Remarks

The max macro is defined as follows:

#define max(a, b)  (((a) > (b)) ? (a) : (b))

See Also

min


min
min  QuickInfo

The min macro compares two values and returns the smaller one. The data type can be any numeric data type, signed or unsigned. The data type of the arguments and the return value is the same.

min(

value1,
value2
);
Parameters

value1

Specifies the first of two values.

value2

Specifies the second of two values.

Return Value

The return value is the smaller of the two specified values.

Remarks

The min macro is defined as follows:

#define min(a, b)  (((a) < (b)) ? (a) : (b))

See Also

max


PALETTEINDEX
PALETTEINDEX  QuickInfo

The PALETTEINDEX macro accepts an index to a logical-color palette entry and returns a palette-entry specifier consisting of a 32-bit COLORREF value that specifies the color associated with the given index. An application using a logical color palette can pass this specifier, instead of an explicit red, green, blue (RGB) value, to GDI functions that expect a color. This allows the function to use the color in the specified palette entry.

COLORREF PALETTEINDEX(

WORD  wPaletteIndex	// index to palette entry
);
Parameters

wPaletteIndex

Specifies an index to the palette entry containing the color to be used for a graphics operation.

Return Value

The return value is a logical-palette index specifier.

Remarks

The PALETTEINDEX macro is defined as follows:

#define PALETTEINDEX(i) /

    ((COLORREF) (0x01000000 | (DWORD) (WORD) (i)))

See Also

PALETTERGB, RGB


PALETTERGB
PALETTERGB  QuickInfo

The PALETTERGB macro accepts three values that represent the relative intensities of red, green, and blue and returns a palette-relative red, green, blue (RGB) specifier consisting of 2 in the high-order byte and an RGB value in the three low-order bytes. An application using a color palette can pass this specifier, instead of an explicit RGB value, to functions that expect a color.

COLORREF PALETTERGB(

BYTE  bRed,	// red component of palette-relative RGB
BYTE  bGreen,	// green component of palette-relative RGB
BYTE  bBlue	// blue component of palette-relative RGB
);
Parameters

bRed

Specifies the intensity of the red color field.

bGreen

Specifies the intensity of the green color field.

bBlue

Specifies the intensity of the blue color field.

Return Value

The return value is a palette-relative RGB specifier. For output devices that support logical palettes, Windows matches a palette-relative RGB value to the nearest color in the logical palette of the device context as though the application had specified an index to that palette entry. If an output device does not support a system palette, Windows uses the palette-relative RGB as though it were a conventional RGB doubleword returned by the RGB macro.

Remarks

The PALETTERGB macro is defined as follows:

#define PALETTERGB(r, g, b)  (0x02000000 | RGB(r, g, b))

See Also

PALETTEINDEX, RGB


POINTSTOPOINT
POINTSTOPOINT  QuickInfo

The POINTSTOPOINT macro copies the contents of a POINTS structure into a POINT structure.

POINTSTOPOINT(

POINT  pt,	// POINT structure
POINTS  pts	// POINTS structure
);
Parameters

pt

Specifies the POINT structure to receive the contents of the POINTS structure.

pts

Specifies the POINTS structure to copy.

Remarks

The POINTSTOPOINT macro is defined as follows:

#define POINTSTOPOINT(pt, pts) {(pt).x = (SHORT) LOWORD(pts); \

                               (pt).y = (SHORT) HIWORD(pts);}

See Also

MAKEPOINTS, POINTTOPOINTS


POINTTOPOINTS
POINTTOPOINTS  QuickInfo

The POINTTOPOINTS macro converts a POINT structure to a POINTS structure.

POINTS POINTTOPOINTS(

POINT  pt	// coordinates of a point
);
Parameters

pt

Specifies the POINT structure to convert.

Return Value

The return value is a POINTS structure.

Remarks

The POINTTOPOINTS macro is defined as follows:

#define POINTTOPOINTS(pt) \

    (MAKELONG((short) ((pt).x), (short) ((pt).y)))

See Also

MAKEPOINTS, POINTSTOPOINT


PRIMARYLANGID
PRIMARYLANGID  QuickInfo

The PRIMARYLANGID macro extracts a primary language identifier from a language identifier.

WORD PRIMARYLANGID(

WORD  lgid	// language identifier
);
Parameters

lgid

Specifies the language identifier. This value is a combination of a primary language identifier and a sublanguage identifier and is usually created by using the MAKELANGID macro.

Return Value

The return value is a primary language identifier. The following primary language identifiers are defined:

LANG_BULGARIAN	LANG_JAPANESE
LANG_CHINESE	LANG_KOREAN
LANG_CROATIAN	LANG_NEUTRAL
LANG_CZECH	LANG_NORWEGIAN
LANG_DANISH	LANG_POLISH
LANG_DUTCH	LANG_PORTUGUESE
LANG_ENGLISH	LANG_ROMANIAN
LANG_FINNISH	LANG_RUSSIAN
LANG_FRENCH	LANG_SLOVAK
LANG_GERMAN	LANG_SLOVENIAN
LANG_GREEK	LANG_SPANISH
LANG_HUNGARIAN	LANG_SWEDISH
LANG_ICELANDIC	LANG_TURKISH
LANG_ITALIAN
Remarks

The PRIMARYLANGID macro is defined as follows:

#define PRIMARYLANGID(lgid)    ((WORD  )(lgid) & 0x3ff)

See Also

LANGIDFROMLCID, MAKELANGID, SUBLANGID


RGB
RGB  QuickInfo

The RGB macro selects a red, green, blue (RGB) color based on the arguments supplied and the color capabilities of the output device.

COLORREF RGB(

BYTE  bRed,	// red component of color
BYTE  bGreen,	// green component of color
BYTE  bBlue	// blue component of color
);
Parameters

cRed

Specifies the intensity of the red color.

cGreen

Specifies the intensity of the green color.

cBlue

Specifies the intensity of the blue color.

Return Value

The return value is the resultant RGB color.

Remarks

The intensity for each argument is in the range 0 through 255. If all three intensities are zero, the result is black. If all three intensities are 255, the result is white.

For information about using color values in a color palette, see the descriptions of the PALETTEINDEX and PALETTERGB macros.

The RGB macro is defined as follows:

#define RGB(r, g ,b)  ((DWORD) (((BYTE) (r) | \

    ((WORD) (g) << 8)) | \

    (((DWORD) (BYTE) (b)) << 16)))

See Also

PALETTEINDEX, PALETTERGB


SORTIDFROMLCID
SORTIDFROMLCID  QuickInfo

The SORTIDFROMLCID macro retrieves a sort identifier from a locale identifier.

WORD SORTIDFROMLCID(

LCID  lcid	// locale identifier
);
Parameters

lcid

Specifies the locale identifier. This parameter may have been created by using the MAKELCID macro.

Return Value

The return value is a sort identifier.

Remarks

The SORTIDFROMLCID macro is defined as follows:

#define SORTIDFROMLCID(lcid) \

          ((WORD  )((((DWORD)(lcid)) & NLS_VALID_LOCALE_MASK) >> 16))

The following sort identifiers are defined:

Value	Meaning
SORT_DEFAULT	Specifies the default sort.
SORT_JAPANESE_XJIS	Specifies Japanese XJIS order.
SORT_JAPANESE_UNICODE	Specifies Japanese Unicode order.
SORT_CHINESE_BIG5	Specifies Chinese BIG5 order.
SORT_CHINESE_UNICODE	Specifies Chinese Unicode order.
SORT_KOREAN_KSC	Specifies Korean KSC order.
SORT_KOREAN_UNICODE	Specifies Korean Unicode order.
See Also

MAKELANGID, MAKELCID, PRIMARYLANGID, SUBLANGID


SUBLANGID
SUBLANGID  QuickInfo

The SUBLANGID macro extracts a sublanguage identifier from a language identifier.

WORD SUBLANGID(

WORD  lgid	// language identifier
);
Parameters

lgid

Specifies the language identifier. This value is a combination of a primary language identifier and a sublanguage identifier and is usually created by using the MAKELANGID macro.

Return Value

The return value is a sublanguage identifier. The following sublanguage identifiers are defined:

SUBLANG_CHINESE_HONGKONG	SUBLANG_FRENCH_SWISS
SUBLANG_CHINESE_SIMPLIFIED	SUBLANG_GERMAN
SUBLANG_CHINESE_SINGAPORE	SUBLANG_GERMAN_AUSTRIAN
SUBLANG_CHINESE_TRADITIONAL	SUBLANG_GERMAN_SWISS
SUBLANG_DEFAULT	SUBLANG_ITALIAN
SUBLANG_DUTCH	SUBLANG_ITALIAN_SWISS
SUBLANG_DUTCH_BELGIAN	SUBLANG_NEUTRAL
SUBLANG_ENGLISH_AUS	SUBLANG_NORWEGIAN_BOKMAL
SUBLANG_ENGLISH_CAN	SUBLANG_NORWEGIAN_NYNORSK
SUBLANG_ENGLISH_EIRE	SUBLANG_PORTUGUESE
SUBLANG_ENGLISH_NZ	SUBLANG_PORTUGUESE_BRAZILIAN
SUBLANG_ENGLISH_UK	SUBLANG_SPANISH
SUBLANG_ENGLISH_US	SUBLANG_SPANISH_MEXICAN
SUBLANG_FRENCH	SUBLANG_SPANISH_MODERN
SUBLANG_FRENCH_BELGIAN	SUBLANG_SYS_DEFAULT
SUBLANG_FRENCH_CANADIAN
Remarks

The SUBLANGID macro is defined as follows:

#define SUBLANGID(lgid)        ((WORD  )(lgid) >> 10)

See Also

LANGIDFROMLCID, MAKELANGID, PRIMARYLANGID


TEXT Macro
TEXT  QuickInfo

The TEXT macro identifies a string as Unicode when the UNICODE compile flag is used or as an ANSI string when Unicode is not defined.

TEXT(

LPTSTR  string	// address of ANSI or Unicode string
);
Parameters

string

Specifies the string to be interpreted as either Unicode or ANSI.

Remarks

The TEXT macro is defined as follows:

#define TEXT(quote) L##quote


XTYP_ADVDATA
XTYP_ADVDATA  QuickInfo

XTYP_ADVDATA

A dynamic data exchange (DDE) client callback function receives the XTYP_ADVDATA transaction after establishing an advise loop with a server. This transaction informs the client that the value of the data item has changed.

Parameters

uFmt

Specifies the format atom of the data sent from the server.

hconv

Identifies the conversation.

hsz1

Identifies the topic name.

hsz2

Identifies the item name.

hdata

Identifies the data associated with the topic name and item name pair. This parameter is NULL if the client specified the XTYPF_NODATA flag when it requested the advise loop.

dwData1

Not used.

dwData2

Not used.

Return Value

A DDE callback function should return DDE_FACK if it processes this transaction, DDE_FBUSY if it is too busy to process this transaction, or DDE_FNOTPROCESSED if it rejects this transaction.

Remarks

An application must not free the data handle obtained during this transaction. An application must, however, copy the data associated with the data handle if the application must process the data after the callback function returns. An application can use the DdeGetData function to copy the data.

See Also

DdeClientTransaction, DdeGetData, DdePostAdvise


XTYP_ADVREQ
XTYP_ADVREQ  QuickInfo

XTYP_ADVREQ

The system sends the XTYP_ADVREQ transaction to a server after the server calls the DdePostAdvise function. This transaction informs the server that an advise transaction is outstanding on the specified topic name and item name pair and that data corresponding to the topic name and item name pair has changed.

Parameters

uFmt

Specifies the format in which the data should be submitted to the client.

hconv

Identifies the conversation.

hsz1

Identifies the topic name.

hsz2

Identifies the item name that has changed.

hdata

Not used.

dwData1

Specifies the count, in the low-order word, of XTYP_ADVREQ transactions that remain to be processed on the same topic, item, and format name set within the context of the current call to the DdePostAdvise function. The count is zero if the current XTYP_ADVREQ transaction is the last one. A server can use this count to determine whether to create an HDATA_APPOWNED data handle for the advise data.

The low-order word is set to CADV_LATEACK if the Dynamic Data Exchange Management Library (DDEML) issued the XTYP_ADVREQ transaction because of a late-arriving DDE_ACK message from a client being outrun by the server.

The high-order word is not used.

dwData2

Not used.

Return Value

The server should first call the DdeCreateDataHandle function to create a data handle that identifies the changed data and then return the handle. The server should return NULL if it is unable to complete the transaction.

Remarks

A server cannot block this transaction type; the CBR_BLOCK return code is ignored.

See Also

DdeCreateDataHandle, DdeInitialize, DdePostAdvise


XTYP_ADVSTART
XTYP_ADVSTART  QuickInfo

XTYP_ADVSTART

A dynamic data exchange (DDE) server callback function receives the XTYP_ADVSTART transaction when a client specifies XTYP_ADVSTART as the uType parameter of the DdeClientTransaction function. A client uses this transaction to establish an advise loop with a server.

Parameters

uFmt

Specifies the data format requested by the client.

hconv

Identifies the conversation.

hsz1

Identifies the topic name.

hsz2

Identifies the item name.

hdata

Not used.

dwData1

Not used.

dwData2

Not used.

Return Value

A server callback function should return TRUE to allow an advise loop on the specified topic name and item name pair, or FALSE to deny the advise loop. If the callback function returns TRUE, any subsequent calls to the DdePostAdvise function by the server on the same topic name and item name pair causes the system to send XTYP_ADVREQ transactions to the server.

Remarks

If a client requests an advise loop on a topic name, item name, and data format for an advise loop that is already established, the Dynamic Data Exchange Management Library (DDEML) does not create a duplicate advise loop but instead alters the advise loop flags (XTYPF_ACKREQ and XTYPF_NODATA) to match the latest request.

This transaction is filtered if the server application specified the CBF_FAIL_ADVISES flag in the DdeInitialize function.

See Also

DdeClientTransaction, DdeInitialize, DdePostAdvise


XTYP_ADVSTOP
XTYP_ADVSTOP  QuickInfo

XTYP_ADVSTOP

A dynamic data exchange (DDE) server callback function receives the XTYP_ADVSTOP transaction when a client specifies XTYP_ADVSTOP in the DdeClientTransaction function. A client uses this transaction to end an advise loop with a server.

Parameters

uFmt

Specifies the data format associated with the advise loop being ended.

hconv

Identifies the conversation.

hsz1

Identifies the topic name.

hsz2

Identifies the item name.

hdata

Not used.

dwData1

Not used.

dwData2

Not used.

Remarks

This transaction is filtered if the server application specified the CBF_FAIL_ADVISES flag in the DdeInitialize function.

See Also

DdeClientTransaction, DdeInitialize, DdePostAdvise


XTYP_CONNECT
XTYP_CONNECT  QuickInfo

XTYP_CONNECT

A dynamic data exchange (DDE) server callback function receives the XTYP_CONNECT transaction when a client specifies a service name that the server supports and a topic name that is not NULL in a call to the DdeConnect function.

Parameters

uFmt

Not used.

hconv

Not used.

hsz1

Identifies the topic name.

hsz2

Identifies the service name.

hdata

Not used.

dwData1

Points to a CONVCONTEXT structure that contains context information for the conversation. If the client is not a Dynamic Data Exchange Management Library (DDEML) application, this parameter is 0.

dwData2

Specifies whether the client is the same application instance as the server. If the parameter is 1, the client is the same instance. If the parameter is 0, the client is a different instance.

Return Value

A server callback function should return TRUE to allow the client to establish a conversation on the specified service name and topic name pair, or the function should return FALSE to deny the conversation. If the callback function returns TRUE and a conversation is successfully established, the system passes the conversation handle to the server by issuing an XTYP_CONNECT_CONFIRM transaction to the server's callback function (unless the server specified the CBF_SKIP_CONNECT_CONFIRMS flag in the DdeInitialize function).

Remarks

This transaction is filtered if the server application specified the CBF_FAIL_CONNECTIONS flag in the DdeInitialize function.

A server cannot block this transaction type; the CBR_BLOCK return code is ignored.

See Also

CONVCONTEXT, DdeConnect, DdeInitialize


XTYP_CONNECT_CONFIRM
XTYP_CONNECT_CONFIRM  QuickInfo

XTYP_CONNECT_CONFIRM

A dynamic data exchange (DDE) server callback function receives the XTYP_CONNECT_CONFIRM transaction to confirm that a conversation has been established with a client and to provide the server with the conversation handle. The system sends this transaction as a result of a previous XTYP_CONNECT or XTYP_WILDCONNECT transaction.

Parameters

uFmt

Not used.

hconv

Identifies the new conversation.

hsz1

Identifies the topic name on which the conversation has been established.

hsz2

Identifies the service name on which the conversation has been established.

hdata

Not used.

dwData1

Not used.

dwData2

Specifies whether the client is the same application instance as the server. If the parameter is 1, the client is the same instance. If the parameter is 0, the client is a different instance.

Remarks

This transaction is filtered if the server application specified the CBF_SKIP_CONNECT_CONFIRMS flag in the DdeInitialize function.

A server cannot block this transaction type; the CBR_BLOCK return code is ignored.

See Also

DdeConnect, DdeConnectList, DdeInitialize


XTYP_DISCONNECT
XTYP_DISCONNECT  QuickInfo

XTYP_DISCONNECT

An application's dynamic data exchange (DDE) callback function receives the XTYP_DISCONNECT transaction when the application's partner in a conversation uses the DdeDisconnect function to terminate the conversation.

Parameters

uFmt

Not used.

hconv

Identifies that the conversation was terminated.

hsz1

Not used.

hsz2

Not used.

hdata

Not used.

dwData1

Not used.

dwData2

Specifies whether the partners in the conversation are the same application instance. If this parameter is 1, the partners are the same instance. If this parameter is 0, the partners are different instances.

Remarks

This transaction is filtered if the application specified the CBF_SKIP_DISCONNECTS flag in the DdeInitialize function.

The application can obtain the status of the terminated conversation by calling the DdeQueryConvInfo function while processing this transaction. The conversation handle becomes invalid after the callback function returns.

An application cannot block this transaction type; the CBR_BLOCK return code is ignored.

See Also

DdeDisconnect, DdeInitialize, DdeQueryConvInfo


XTYP_ERROR
XTYP_ERROR  QuickInfo

XTYP_ERROR

A dynamic data exchange (DDE) callback function receives the XTYP_ERROR transaction when a critical error occurs.

Parameters

uFmt

Not used.

hconv

Identifies the conversation associated with the error. This parameter is NULL if the error is not associated with a conversation.

hsz1

Not used.

hsz2

Not used.

hdata

Not used.

dwData1

Specifies the error code in the low-order word. Currently, only the following error code is supported:

Error Code	Description
DMLERR_LOW_MEMORY	Memory is low; advise, poke, or execute data may be lost, or the system may fail.
dwData2

Not used.

Remarks

An application cannot block this transaction type; the CBR_BLOCK return code is ignored. The DDEML attempts to free memory by removing noncritical resources. An application that has blocked conversations should unblock them.


XTYP_EXECUTE
XTYP_EXECUTE  QuickInfo

XTYP_EXECUTE

A dynamic data exchange (DDE) server callback function receives the XTYP_EXECUTE transaction when a client specifies XTYP_EXECUTE in the DdeClientTransaction function. A client uses this transaction to send a command string to the server.

Parameters

uFmt

Not used.

hconv

Identifies the conversation.

hsz1

Identifies the topic name.

hsz2

Not used.

hdata

Identifies the command string.

dwData1

Not used.

dwData2

Not used.

Return Value

A server callback function should return DDE_FACK if it processes this transaction, DDE_FBUSY if it is too busy to process this transaction, or DDE_FNOTPROCESSED if it rejects this transaction.

Remarks

This transaction is filtered if the server application specified the CBF_FAIL_EXECUTES flag in the DdeInitialize function.

An application must free the data handle obtained during this transaction. An application must, however, copy the command string associated with the data handle if the application must process the string after the callback function returns. An application can use the DdeGetData function to copy the data.

Because most client applications expect a server application to perform an XTYP_EXECUTE transaction synchonrously, a server should attempt to perform all processing of the XTYP_EXECUTE transaction either from within the DDE callback function or by returning the CBR_BLOCK return code. If the hdata parameter is a command that instructs the server to terminate, the server should do so after processing the XTYP_EXECUTE transaction.

See Also

DdeClientTransaction, DdeGetData, DdeInitialize


XTYP_MONITOR
XTYP_MONITOR  QuickInfo

XTYP_MONITOR

The dynamic data exchange (DDE) callback function of a DDE debugging application receives the XTYP_MONITOR transaction whenever a DDE event occurs in the system. To receive this transaction, an application must specify the APPCLASS_MONITOR flag when it calls the DdeInitialize function.

Parameters

uFmt

Not used.

hconv

Not used.

hsz1

Not used.

hsz2

Not used.

hdata

Identifies a DDE object that contains information about the DDE event. The application should use the DdeAccessData function to obtain a pointer to the object.

dwData1

Not used.

dwData2

Identifies the DDE event. This parameter may be one of the following values:

Value	Meaning
MF_CALLBACKS	The system sent a transaction to a DDE callback function. The DDE object contains a MONCBSTRUCT structure that provides information about the transaction.
MF_CONV	A DDE conversation was established or terminated. The DDE object contains a MONCONVSTRUCT structure that provides information about the conversation.
MF_ERRORS	A DDE error occurred. The DDE object contains a MONERRSTRUCT structure that provides information about the error.
MF_HSZ_INFO	A DDE application created, freed, or incremented the usage count of a string handle, or a string handle was freed as a result of a call to the DdeUninitialize function. The DDE object contains a MONHSZSTRUCT structure that provides information about the string handle.
MF_LINKS	A DDE application started or stopped an advise loop. The DDE object contains a MONLINKSTRUCT structure that provides information about the advise loop.
MF_POSTMSGS	The system or an application posted a DDE message. The DDE object contains a MONMSGSTRUCT structure that provides information about the message.
MF_SENDMSGS	The system or an application sent a DDE message. The DDE object contains a MONMSGSTRUCT structure that provides information about the message.
Return Value

If the callback function processes this transaction, it should return 0.

See Also

DdeAccessData, DdeInitialize, DdeUninitialize, MONCBSTRUCT, MONCONVSTRUCT, MONERRSTRUCT, MONHSZSTRUCT, MONLINKSTRUCT, MONMSGSTRUCT


XTYP_POKE
XTYP_POKE  QuickInfo

XTYP_POKE

A dynamic data exchange (DDE) server callback function receives the XTYP_POKE transaction when a client specifies XTYP_POKE in DdeClientTransaction function. A client uses this transaction to send unsolicited data to the server.

Parameters

uFmt

Specifies the format of the data sent from the server.

hconv

Identifies the conversation.

hsz1

Identifies the topic name.

hsz2

Identifies the item name.

hdata

Identifies the data that the client is sending to the server.

dwData1

Not used.

dwData2

Not used.

Return Value

A server callback function should return the DDE_FACK flag if it processes this transaction, the DDE_FBUSY flag if it is too busy to process this transaction, or the DDE_FNOTPROCESSED flag if it rejects this transaction.

Remarks

This transaction is filtered if the server application specified the CBF_FAIL_POKES flag in the DdeInitialize function.

See Also

DdeClientTransaction, DdeInitialize


XTYP_REGISTER
XTYP_REGISTER  QuickInfo

XTYP_REGISTER

A dynamic data exchange (DDE) callback function receives the XTYP_REGISTER transaction type whenever a Dynamic Data Exchange Library (DDEML) server application uses the DdeNameService function to register a service name, or whenever a non-DDEML application that supports the System topic is started.

Parameters

uFmt

Not used.

hconv

Not used.

hsz1

Identifies the base service name being registered.

hsz2

Identifies the instance-specific service name being registered.

hdata

Not used.

dwData1

Not used.

dwData2

Not used.

Remarks

This transaction is filtered if the application specified the CBF_SKIP_REGISTRATIONS flag in the DdeInitialize function.

A application cannot block this transaction type; the CBR_BLOCK return code is ignored.

An application should use the hsz1 parameter to add the service name to the list of servers available to the user. An application should use the hsz2 parameter to identify which application instance has started.

See Also

DdeInitialize, DdeNameService


XTYP_REQUEST
XTYP_REQUEST  QuickInfo

XTYP_REQUEST

A dynamic data exchange (DDE) server callback function receives the XTYP_REQUEST transaction when a client specifies XTYP_REQUEST in the DdeClientTransaction function. A client uses this transaction to request data from a server.

Parameters

uFmt

Specifies the format in which the server should submit data to the client.

hconv

Identifies the conversation.

hsz1

Identifies the topic name.

hsz2

Identifies the item name.

hdata

Not used.

dwData1

Not used.

dwData2

Not used.

Return Value

The server should call the DdeCreateDataHandle function to create a data handle that identifies the data and then return the handle. The server should return NULL if it is unable to complete the transaction. If the server returns NULL, the client will receive a DDE_FNOTPROCESSED flag.

Remarks

This transaction is filtered if the server application specified the CBF_FAIL_REQUESTS flag in the DdeInitialize function.

If responding to this transaction requires lengthy processing, the server can return the CBR_BLOCK return code to suspend future transactions on the current conversation and then process the transaction asynchronously. When the server has finished and the data is ready to pass to the client, the server can call the DdeEnableCallback function to resume the conversation.

See Also

DdeClientTransaction, DdeCreateDataHandle, DdeEnableCallback, DdeInitialize


XTYP_UNREGISTER
XTYP_UNREGISTER  QuickInfo

XTYP_UNREGISTER

A dynamic data exchange (DDE) callback function receives the XTYP_UNREGISTER transaction whenever a Dynamic Data Exchange Management Library (DDEML) server application uses the DdeNameService function to unregister a service name, or whenever a non-DDEML application that supports the System topic is terminated.

Parameters

uFmt

Not used.

hconv

Not used.

hsz1

Identifies the base service name being unregistered.

hsz2

Identifies the instance-specific service name being unregistered.

hdata

Not used.

dwData1

Not used.

dwData2

Not used.

Remarks

This transaction is filtered if the application specified the CBF_SKIP_REGISTRATIONS flag in the DdeInitialize function.

A application cannot block this transaction type; the CBR_BLOCK return code is ignored.

An application should use the hsz1 parameter to remove the service name from the list of servers available to the user. An application should use the hsz2 parameter to identify which application instance has terminated.

See Also

DdeInitialize, DdeNameService


XTYP_WILDCONNECT
XTYP_WILDCONNECT  QuickInfo

XTYP_WILDCONNECT

A dynamic data exchange (DDE) server callback function receives the XTYP_WILDCONNECT transaction when a client specifies a NULL service name, a NULL topic name, or both in a call to the DdeConnect or DdeConnectList function. This transaction allows a client to establish a conversation on each of the server's service name and topic name pairs that match the specified service name and topic name.

Parameters

uFmt

Not used.

hconv

Not used.

hsz1

Identifies the topic name. If this parameter is NULL, the client is requesting a conversation on all topic names that the server supports.

hsz2

Identifies the service name. If this parameter is NULL, the client is requesting a conversation on all service names that the server supports.

hdata

Not used.

dwData1

Points to a CONVCONTEXT structure that contains context information for the conversation. If the client is not a Dynamic Data Exchange Management Library (DDEML) application, this parameter is set to 0.

dwData2

Specifies whether the client is the same application instance as the server. If the parameter is 1, the client is same instance. If the parameter is 0, the client is a different instance.

Return Value

The server should return a data handle that identifies an array of HSZPAIR structures. The array should contain one structure for each service-name and topic-name pair that matches the service-name and topic-name pair requested by the client. The array must be terminated by a NULL string handle. The system sends the XTYP_CONNECT_CONFIRM transaction to the server to confirm each conversation and to pass the conversation handles to the server. The server will not receive these confirmations if it specified the CBF_SKIP_CONNECT_CONFIRMS flag in the DdeInitialize function.

The server should return NULL to refuse the XTYP_WILDCONNECT transaction.

Remarks

This transaction is filtered if the server application specified the CBF_FAIL_CONNECTIONS flag in the DdeInitialize function.

A server cannot block this transaction type; the CBR_BLOCK return code is ignored.

See Also

CONVCONTEXT, DdeConnect, DdeInitialize, HSZPAIR


XTYP_XACT_COMPLETE
XTYP_XACT_COMPLETE  QuickInfo

XTYP_XACT_COMPLETE

A dynamic data exchange (DDE) client callback function receives the XTYP_XACT_COMPLETE transaction when an asynchronous transaction, initiated by a call to the DdeClientTransaction function, has completed.

Parameters

uFmt

Specifies the format of the data associated with the completed transaction (if applicable) or NULL if no data was exchanged during the transaction.

hconv

Identifies the conversation.

hsz1

Identifies the topic name involved in the completed transaction.

hsz2

Identifies the item name involved in the completed transaction.

hdata

Identifies the data involved in the completed transaction, if applicable. If the transaction was successful but involved no data, this parameter is TRUE. This parameter is NULL if the transaction was unsuccessful.

dwData1

Specifies the transaction identifier of the completed transaction.

dwData2

Specifies any applicable DDE_ status flags in the low word. This parameter provides support for applications dependent on DDE_APPSTATUS bits. It is recommended that applications no longer use these bits — future versions of the Dynamic Data Exchange Management Library (DDEML) may not support them.

Remarks

An application must not free the data handle obtained during this transaction. An application must, however, copy the data associated with the data handle if the application must process the data after the callback function returns. An application can use the DdeGetData function to copy the data.

See Also

DdeClientTransaction, DdeGetData


Virtual-Key Codes

The following table shows the symbolic constant names, hexadecimal values, and keyboard equivalents for the virtual-key codes used by the Microsoft Windows operating system. The codes are listed in numeric order.

Symbolic constant name	Value (hexadecimal)	Mouse or keyboard equivalent
VK_LBUTTON	01	Left mouse button
VK_RBUTTON	02	Right mouse button
VK_CANCEL	03	Control-break processing
VK_MBUTTON	04	Middle mouse button (three-button mouse)
—	05−07	Undefined
VK_BACK	08	BACKSPACE key
VK_TAB	09	TAB key
—	0A−0B	Undefined
VK_CLEAR	0C	CLEAR key
VK_RETURN	0D	ENTER key
—	0E−0F	Undefined
VK_SHIFT	10	SHIFT key
VK_CONTROL	11	CTRL key
VK_MENU	12	ALT key
VK_PAUSE	13	PAUSE key
VK_CAPITAL	14	CAPS LOCK key
—	15−19	Reserved for Kanji systems
—	1A	Undefined
VK_ESCAPE	1B	ESC key
—	1C−1F	Reserved for Kanji systems
VK_SPACE	20	SPACEBAR
VK_PRIOR	21	PAGE UP key
VK_NEXT	22	PAGE DOWN key
VK_END	23	END key
VK_HOME	24	HOME key
VK_LEFT	25	LEFT ARROW key
VK_UP	26	UP ARROW key
VK_RIGHT	27	RIGHT ARROW key
VK_DOWN	28	DOWN ARROW key
VK_SELECT	29	SELECT key
—	2A	Original equipment manufacturer (OEM) specific
VK_EXECUTE	2B	EXECUTE key
VK_SNAPSHOT	2C	PRINT SCREEN key for Windows 3.0 and later
VK_INSERT	2D	INS key
VK_DELETE	2E	DEL key
VK_HELP	2F	HELP key
VK_0	30	0 key
VK_1	31	1 key
VK_2	32	2 key
VK_3	33	3 key
VK_4	34	4 key
VK_5	35	5 key
VK_6	36	6 key
VK_7	37	7 key
VK_8	38	8 key
VK_9	39	9 key
—	3A−40	Undefined
VK_A	41	A key
VK_B	42	B key
VK_C	43	C key
VK_D	44	D key
VK_E	45	E key
VK_F	46	F key
VK_G	47	G key
VK_H	48	H key
VK_I	49	I key
VK_J	4A	J key
VK_K	4B	K key
VK_L	4C	L key
VK_M	4D	M key
VK_N	4E	N key
VK_O	4F	O key
VK_P	50	P key
VK_Q	51	Q key
VK_R	52	R key
VK_S	53	S key
VK_T	54	T key
VK_U	55	U key
VK_V	56	V key
VK_W	57	W key
VK_X	58	X key
VK_Y	59	Y key
VK_Z	5A	Z key
—	5B−5F	Undefined
VK_NUMPAD0	60	Numeric keypad 0 key
VK_NUMPAD1	61	Numeric keypad 1 key
VK_NUMPAD2	62	Numeric keypad 2 key
VK_NUMPAD3	63	Numeric keypad 3 key
VK_NUMPAD4	64	Numeric keypad 4 key
VK_NUMPAD5	65	Numeric keypad 5 key
VK_NUMPAD6	66	Numeric keypad 6 key
VK_NUMPAD7	67	Numeric keypad 7 key
VK_NUMPAD8	68	Numeric keypad 8 key
VK_NUMPAD9	69	Numeric keypad 9 key
VK_MULTIPLY	6A	Multiply key
VK_ADD	6B	Add key
VK_SEPARATOR	6C	Separator key
VK_SUBTRACT	6D	Subtract key
VK_DECIMAL	6E	Decimal key
VK_DIVIDE	6F	Divide key
VK_F1	70	F1 key
VK_F2	71	F2 key
VK_F3	72	F3 key
VK_F4	73	F4 key
VK_F5	74	F5 key
VK_F6	75	F6 key
VK_F7	76	F7 key
VK_F8	77	F8 key
VK_F9	78	F9 key
VK_F10	79	F10 key
VK_F11	7A	F11 key
VK_F12	7B	F12 key
VK_F13	7C	F13 key
VK_F14	7D	F14 key
VK_F15	7E	F15 key
VK_F16	7F	F16 key
VK_F17	80H	F17 key
VK_F18	81H	F18 key
VK_F19	82H	F19 key
VK_F20	83H	F20 key
VK_F21	84H	F21 key
VK_F22	85H	F22 key
VK_F23	86H	F23 key
VK_F24	87H	F24 key
—	88−8F	Unassigned
VK_NUMLOCK	90	NUM LOCK key
VK_SCROLL	91	SCROLL LOCK key
—	92−B9	Unassigned
—	BA−C0	OEM specific
—	C1−DA	Unassigned
—	DB−E4	OEM specific
—	E5	Unassigned
—	E6	OEM specific
—	E7−E8	Unassigned
—	E9−F5	OEM specific
—	F6−FE	Unassigned


Locale Identifiers

This appendix contains detailed information about national language support in Microsoft® Windows®. The information presented here pertains to locale identifiers, LCTYPE constants, country codes, and language identifiers.

A locale identifier (LCID) is a DWORD value containing the language identifier in the lower word and a reserved value in the upper word. The identifier supplied in an LCID is a standard international numeric abbreviation. This LCID has the components necessary to uniquely identify one of the installed system-defined locales.

Applications can use the MAKELCID macro to create LCID values.

There are two predefined LCID values: LOCALE_SYSTEM_DEFAULT is the system default locale, and LOCALE_USER_DEFAULT is the current user's locale.


LCTYPE Constants

An LCTYPE constant is a constant that specifies a particular piece of locale information.

The values in the following list correspond to the names of these values in the configuration registry, under both the user's preferences (as values in the registry key HKEY_CURRENT_USER\Control Panel\International) and the system's installed languages (as files pointed to by registry keys, one key per language installed, under HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\NLS). All values are null-terminated Unicode™ strings. If no maximum length is indicated, the strings may vary in length.

Constant	Description
LOCALE_ILANGUAGE	Language identifier indicating the language. The maximum number of characters allowed for this string is 5.
LOCALE_SLANGUAGE	Full localized name of the language.
LOCALE_SENGLANGUAGE	Full English name of the language from the International Organization for Standardization (ISO) Standard 639. This is always restricted to characters mappable into the ASCII 127-character subset.
LOCALE_SABBREVLANGNAME	Abbreviated name of the language, created by taking the 2-letter language abbreviation from the ISO Standard 639 and adding a third letter, as appropriate, to indicate the sublanguage.
LOCALE_SNATIVELANGNAME	Native name of the language.
LOCALE_ICOUNTRY	Country code, based on international phone codes, also referred to as IBM country codes. The maximum number of characters allowed for this string is 6.
LOCALE_SCOUNTRY	Full localized name of the country.
LOCALE_SENGCOUNTRY	Full English name of the country. This is always restricted to characters mappable into the ASCII 127-character subset.
LOCALE_SABBREVCTRYNAME	Abbreviated name of the country from the ISO Standard 3166.
LOCALE_SNATIVECTRYNAME	Native name of the country.
LOCALE_IDEFAULTLANGUAGE	Language identifier for the principal language spoken in this locale. This is provided so that partially specified locales can be completed with default values. The maximum number of characters allowed for this string is 5.
LOCALE_IDEFAULTCOUNTRY	Country code for the principal country in this locale. This is provided so that partially specified locales can be completed with default values. The maximum number of characters allowed for this string is 6.
LOCALE_IDEFAULTCODEPAGE	Original equipment manufacturer (OEM) code page associated with the country. The maximum number of characters allowed for this string is 6.
LOCALE_SLIST	Character(s) used to separate list items. For example, a comma is used in many locales.
LOCALE_IMEASURE	System of measurement. This value is 0 if the metric system (Systéme International d'Unités, or S.I.) is used and 1 if the U.S. system is used. The maximum number of characters allowed for this string is 2.
LOCALE_SDECIMAL	Character(s) used as the decimal separator.
LOCALE_STHOUSAND	Character(s) used to separate groups of digits to the left of the decimal.
LOCALE_SGROUPING	Sizes for each group of digits to the left of the decimal. An explicit size is needed for each group; sizes are separated by semicolons. If the last value is zero, the preceding value is repeated. To group thousands, specify 3;0, for example.
LOCALE_IDIGITS	Number of fractional digits. The maximum number of characters allowed for this string is 3.
LOCALE_ILZERO	Specifier for leading zeros in decimal fields. The maximum number of characters allowed for this string is 2. The specifier can be one of the following values:
Value	Meaning
0	No leading zeros
1	Leading zeros
LOCALE_SNATIVEDIGITS	Native equivalents to ASCII 0 through 9.
LOCALE_SCURRENCY	String used as the local monetary symbol.
LOCALE_SINTLSYMBOL	Three characters of the international monetary symbol specified in ISO 4217, "Codes for the Representation of Currencies and Funds," followed by the character separating this string from the amount.
LOCALE_SMONDECIMALSEP	Character(s) used as the monetary decimal separator.
LOCALE_SMONTHOUSANDSEP	Character(s) used as the monetary separator between groups of digits to the left of the decimal.
LOCALE_SMONGROUPING	Sizes for each group of monetary digits to the left of the decimal. An explicit size is needed for each group; sizes are separated by semicolons. If the last value is zero, the preceding value is repeated. To group thousands, specify 3;0, for example.
LOCALE_ICURRDIGITS	Number of fractional digits for the local monetary format. The maximum number of characters allowed for this string is 3.
LOCALE_IINTLCURRDIGITS	Number of fractional digits for the international monetary format. The maximum number of characters allowed for this string is 3.
LOCALE_ICURRENCY	Positive currency mode. The maximum number of characters allowed for this string is 2. The mode can be one of the following values:
Value	Meaning
0	Prefix, no separation
1	Suffix, no separation
2	Prefix, 1-char. separation
3	Suffix, 1-char. separation
LOCALE_INEGCURR	Negative currency mode. The maximum number of characters allowed for this string is 3. The mode can be one of the following values:
Value	Example
0	($1.1)
1	−$1.1
2	$−1.1
3	$1.1−
4	(1.1$)
5	−1.1$
6	1.1−$
7	1.1$−
8	−1.1 $ (space before $)
9	−$ 1.1 (space after $)
10	1.1 $− (space before $)
11	$ 1.1− (space after $)
12	$ −1.1 (space after $)
13	1.1− $ (space before $)
14	($ 1.1) (space after $)
15	(1.1 $) (space before $)
LOCALE_SDATE	Character(s) for the date separator.
LOCALE_STIME	Character(s) for the time separator.
LOCALE_STIMEFORMAT	Time formatting strings for this locale.
LOCALE_SSHORTDATE	Short date formatting string for this locale.
LOCALE_SLONGDATE	Long date formatting string for this locale.
LOCALE_IDATE	Short date format-ordering specifier. The maximum number of characters allowed for this string is 2. The specifier can be one of the following values:
Value	Meaning
0	Month-Day-Year
1	Day-Month-Year
2	Year-Month-Day
LOCALE_ILDATE	Long date format-ordering specifier. The maximum number of characters allowed for this string is 2. The specifier can be one of the following values:
Value	Meaning
0	Month-Day-Year
1	Day-Month-Year
2	Year-Month-Day
LOCALE_ITIME	Time format specifier. The maximum number of characters allowed for this string is 2. The specifier can be one of the following values:
Value	Meaning
0	AM / PM 12-hour format
1	24-hour format
LOCALE_ICENTURY	Specifier for full 4-digit century. The maximum number of characters allowed for this string is 2. The specifier can be one of the following values:
Value	Meaning
0	Abbreviated 2-digit century
1	Full 4-digit century
LOCALE_ITLZERO	Specifier for leading zeros in time fields. The maximum number of characters allowed for this string is 2. The specifier can be one of the following values:
Value	Meaning
0	No leading zeros for hours
1	Leading zeros for hours
LOCALE_IDAYLZERO	Specifier for leading zeros in day fields. The maximum number of characters allowed for this string is 2. The specifier can be one of the following values:
Value	Meaning
0	No leading zeros for days
1	Leading zeros for days
LOCALE_IMONLZERO	Specifier for leading zeros in month fields. The maximum number of characters allowed for this string is 2. The specifier can be one of the following values:
Value	Meaning
0	No leading zeros for months
1	Leading zeros for months
LOCALE_S1159	String for the AM designator.
LOCALE_S2359	String for the PM designator.
LOCALE_SDAYNAME1	Native long name for Monday.
LOCALE_SDAYNAME2	Native long name for Tuesday.
LOCALE_SDAYNAME3	Native long name for Wednesday.
LOCALE_SDAYNAME4	Native long name for Thursday.
LOCALE_SDAYNAME5	Native long name for Friday.
LOCALE_SDAYNAME6	Native long name for Saturday.
LOCALE_SDAYNAME7	Native long name for Sunday.
LOCALE_SABBREVDAYNAME1	Native abbreviated name for Monday.
LOCALE_SABBREVDAYNAME2	Native abbreviated name for Tuesday.
LOCALE_SABBREVDAYNAME3	Native abbreviated name for Wednesday.
LOCALE_SABBREVDAYNAME4	Native abbreviated name for Thursday.
LOCALE_SABBREVDAYNAME5	Native abbreviated name for Friday.
LOCALE_SABBREVDAYNAME6	Native abbreviated name for Saturday.
LOCALE_SABBREVDAYNAME7	Native abbreviated name for Sunday.
LOCALE_SMONTHNAME1	Native long name for January.
LOCALE_SMONTHNAME2	Native long name for February.
LOCALE_SMONTHNAME3	Native long name for March.
LOCALE_SMONTHNAME4	Native long name for April.
LOCALE_SMONTHNAME5	Native long name for May.
LOCALE_SMONTHNAME6	Native long name for June.
LOCALE_SMONTHNAME7	Native long name for July.
LOCALE_SMONTHNAME8	Native long name for August.
LOCALE_SMONTHNAME9	Native long name for September.
LOCALE_SMONTHNAME10	Native long name for October.
LOCALE_SMONTHNAME11	Native long name for November.
LOCALE_SMONTHNAME12	Native long name for December.
LOCALE_SABBREVMONTHNAME1	Native abbreviated name for January.
LOCALE_SABBREVMONTHNAME2	Native abbreviated name for February.
LOCALE_SABBREVMONTHNAME3	Native abbreviated name for March.
LOCALE_SABBREVMONTHNAME4	Native abbreviated name for April.
LOCALE_SABBREVMONTHNAME5	Native abbreviated name for May.
LOCALE_SABBREVMONTHNAME6	Native abbreviated name for June.
LOCALE_SABBREVMONTHNAME7	Native abbreviated name for July.
LOCALE_SABBREVMONTHNAME8	Native abbreviated name for August.
LOCALE_SABBREVMONTHNAME9	Native abbreviated name for September.
LOCALE_SABBREVMONTHNAME10	Native abbreviated name for October.
LOCALE_SABBREVMONTHNAME11	Native abbreviated name for November.
LOCALE_SABBREVMONTHNAME12	Native abbreviated name for December.
LOCALE_SPOSITIVESIGN	String value for the positive sign.
LOCALE_SNEGATIVESIGN	String value for the negative sign.
LOCALE_IPOSSIGNPOSN	Formatting index for positive values. The maximum number of characters allowed for this string is 2. The index can be one of the following values:
Value	Meaning
0	Parentheses surround the amount and the monetary symbol.
1	The sign string precedes the amount and the monetary symbol.
2	The sign string succeeds the amount and the monetary symbol.
3	The sign string immediately precedes the monetary symbol.
4	The sign string immediately succeeds the monetary symbol.
LOCALE_INEGSIGNPOSN	Formatting index for negative values. This index uses the same values as LOCALE_IPOSSIGNPOSN. The maximum number of characters allowed for this string is 2.
LOCALE_IPOSSYMPRECEDES	Position of monetary symbol in a positive monetary value. This value is 1 if the monetary symbol precedes the positive amount, 0 if it follows it. The maximum number of characters allowed for this string is 2.
LOCALE_IPOSSEPBYSPACE	Separation of monetary symbol in a positive monetary value. This value is 1 if the monetary symbol is separated by a space from a positive amount, 0 if it is not. The maximum number of characters allowed for this string is 2.
LOCALE_INEGSYMPRECEDES	Position of monetary symbol in a negative monetary value. This value is 1 if the monetary symbol precedes the negative amount, 0 if it follows it. The maximum number of characters allowed for this string is 2.
LOCALE_INEGSEPBYSPACE	Separation of monetary symbol in a negative monetary value. This value is 1 if the monetary symbol is separated by a space from the negative amount, 0 if it is not. The maximum number of characters allowed for this string is 2.
LOCALE_NOUSEROVERRIDE	This constant may be OR'ed with any other LCTYPE constant in a call to the GetLocaleInfo function. This always causes the function to bypass any user overrides, and return the system default value for the other LCTYPE specified in the function call, based on the given LCID.


Language Identifiers and Locales

Applications can use the MAKELANGID macro to create a language identifier.

The first release of Windows NT supports 35 sublanguages/locales.

The following 28 sublanguages/locales use the Latin 1 script:

Latin 1 Script

Identifier	Language	Sublanguage/Locale	Language Code
0x0406	Danish	Danish	DAN
0x0413	Dutch	Dutch (Standard)	NLD
0x0813	Dutch	Belgian (Flemish)	NLB
0x0409	English	American	ENU
0x0809	English	British	ENG
0x0c09	English	Australian	ENA
0x1009	English	Canadian	ENC
0x1409	English	New Zealand	ENZ
0x1809	English	Ireland	ENI
0x040b	Finnish	Finnish	FIN
0x040c	French	French (Standard)	FRA
0x080c	French	Belgian	FRB
0x0c0c	French	Canadian	FRC
0x100c	French	Swiss	FRS
0x0407	German	German (Standard)	DEU
0x0807	German	Swiss	DES
0x0c07	German	Austrian	DEA
0x040f	Icelandic	Icelandic	ISL
0x0410	Italian	Italian (Standard)	ITA
0x0810	Italian	Swiss	ITS
0x0414	Norwegian	Norwegian (Bokmal)	NOR
0x0814	Norwegian	Norwegian (Nynorsk)	NON
0x0416	Portuguese	Portuguese (Brazilian)	PTB
0x0816	Portuguese	Portuguese (Standard)	PTG
0x041D	Swedish	Swedish	SVE
0x040a	Spanish	Spanish (Standard/Traditional)	ESP
0x080a	Spanish	Mexican	ESM
0x0c0a	Spanish	Spanish (Modern)	ESN
The following 5 sublanguages/locales use the Latin 2 script:

Latin 2 Script

Identifier	Sublanguage/Locale	Language Code
0x041f	Turkish	TRK
0x0415	Polish	PLK
0x0405	Czech	CSY
0x041b	Slovak	SKY
0x040e	Hungarian	HUN
The following sublanguage/locale uses the Cyrillic script:

Cyrillic Script

Identifier	Sublanguage/Locale	Language Code
0x0419	Russian	RUS
The following sublanguage/locale uses an other script:

Other Script

Identifier	Sublanguage/Locale	Language Code
0x0408	Greek	ELL
The following special identifiers are also defined:

Special Identifiers

Identifier	Sublanguage/Locale
0x0000	Language-Neutral
0x0400	Process Default Language


MCI Command String Syntax Summary

This section summarizes MCI commands and their options, by device type. For the conventions used in the command tables, see About the Command Tables.


Introduction

This topic provides a summary of the syntax of the MCI command strings.

To view a command table, click on one of the following:

•	System command set

•	Required command set

•	Basic command set

•	Animation commands

•	Audio CD command set

•	MIDI sequencer commands

•	Videodisc command set

•	Video overlay command set

•	Waveform audio command set


About the Command Tables

Each command table has a Command column and an Arguments column. The Command column contains the MCI commands available for a device type. The Arguments column contains the options available for each MCI command. For example, the following table contains the MCI commands all devices support.

Command	Arguments
capability device_name	{can eject
	| can play | can record | can save | compound device | device type | has audio | has video | uses files}
close device_name
info device_name	[product]
open device_name	[alias device_alias]
	[shareable]
	[type device_type]
status device_name	[mode | ready]
Each command also has a notify and wait flag that does not appear in the tables. These flags can be added to any command.

The following conventions are used in the previous example and for the other MCI command tables.

Type style	Used for
Bold	A specific term intended to be used literally. When used in the command column, it represents the MCI string command. When used in the arguments column, it represents a flag. For example, the capability command and the can play flag must be typed as shown.
Italics	Placeholders for information you must provide. The MCI command or flag associated with the information must precede it. For example, to use the alias words for the device_name with the capability command, type "capability words can play."
|	Divider for mutually exclusive arguments. When multiple arguments are separated by this symbol, only one of them can be used for each command. For example, the items in the list can eject, can play, can record, can save, compound device, device type, has audio, has video, uses files are mutually exclusive and you must select only one to use with the capability command. (Do not type the | with the argument.)
{}	Required argument. You must include an argument enclosed by braces. For example, you must use one of the arguments can eject, can play, can record, can save, compound device, device type, has audio, has video, uses files with the capability command. (Do not type the braces with the argument.)
[ ]	Optional argument. For example, the alias, type and shareable flags are optional for the open command. You can use any combination of these flags. You can also use optional arguments with a required argument. (Do not type the brackets with the argument.)


System Command Set

The following table summarizes the MCI system commands. These commands are interpreted directly by MCI. System commands also support notify and wait as optional flags. You can add either or both of these flags to any system command.

Command	Arguments
break device_name	{off | on virtual key code}
sound sound_name
sysinfo device_name	{installname
	| name index | name index open | quantity | quantity open}


Required Command Set

The following table lists the commands recognized by all devices. Extended commands can add other options to these commands. Required commands also support notify and wait as optional flags. You can add either or both of these flags to any required command.

Command	Arguments
capability device_name	{can eject
	| can play | can record | can save | compound device | device type | has audio | has video | uses files}
close device_name
info device_name	[product]
open device_name	[alias device_alias]
	[shareable]
	[type device_type]
status device_name	[mode | ready]


Basic Command Set

In addition to supporting the commands described previously, each device supports a set of commands specific to its device type. Although these commands are optional for a device, if a command is used it must support the options listed in this table as a minimum set of capabilities. Basic commands also support notify and wait as optional flags. You can add either or both of these flags to any basic command.

Command	Arguments
load device_name	{file_name}
pause device_name
play device_name	[from position]
	[to position]
	[insert | overwrite]
resume device_name
save device_name	[file_name]
seek device_name	{to position | to start | to end}
set device_name	[audio all off
	| audio all on | audio left off | audio left on | audio right off | audio right on | video off | video on]
	[door closed | door open]
	[time format milliseconds | time format ms]
status device_name	{current track
	| length | length track track_number | mode | number of tracks | position | position track track_number | ready | start position | time format}
stop device name


Animation Commands

Animation devices support the following set of commands. These devices also supporty notify and wait as optional flags. You can add either or both of these flags to any animation command.

Command	Arguments
capability device_name	{can eject
	| can play | can record | can reverse | can save | can stretch | compound device | device type | fast play rate | has audio | has video | normal play rate | slow play rate | uses files | uses palettes | windows}
close device_name
info device_name	[file | product | window text]
open device_name	[alias device_alias]
	[nostatic]
	[parent hwnd]
	[shareable]
	[style child
	| style overlapped | style popup]
	[type device_type]
pause device_name
play device_name	[fast | slow | speed fps]
	[from position]
	[to position | reverse]
	[scan]
put device_name	{destination
	| destination at destination_rectangle | source | source at source_rectangle}
realize device_name	{background | normal}
resume device_name
seek device_name	[to position | to start | to end]
set device_name	[audio all off
	| audio all on | audio left off | audio left on | audio right off | audio right on | video off | video on]
	[time format milliseconds
	| time format ms | time format frames]
status device_name	{current track
	| forward | length | length track track_number | media present | mode | number of tracks | palette handle | position | position track track_number | ready | speed | start position | stretch | time format | window handle}
step device_name	[by frames]
stop device_name
update device_name	[at update_rect]
	[hdc hdc]
where device_name	{destination | source}
window device_name	[handle window_handle | handle default]
	[stretch | fixed]
	[state hide
	| state iconic | state maximized | state minimize | state minimized | state no action | state no active | state normal | state show]
	[text caption_text]


Audio CD Command Set

Audio CD devices support the following core set of commands. Audio CD devices also support notify and wait as option flags. You can add either or both of these flags to any audio CD command.

Command	Arguments
capability device_name	{can eject
	| can play | can record | can save | compound device | device type | has audio | has video | uses files}
close device_name	[product]
info device_name
open device_name	[alias device_name]
	[shareable]
pause device_name
play device_name	[from position]
	[to position]
resume device_name
seek device_name	[to position to start | to end]
set device_name	[audio all off
	| audio all on | audio left off | audio left on | audio right off | audio right on | video off | video on]
	[door closed | door open]
	[time format milliseconds
	| time format ms | time format msf | time format tmsf]
status device_name	{current track
	| length | length track track_number | media present | mode | number of tracks | position | position track track_number | ready | start position | time format}
stop device_name


MIDI Sequencer Commands

The MIDI sequencer supports the following set of commands. MIDI sequencers also support notify and wait as optional flags. You can add either or both of these flags to any MIDI sequencer command.

Command	Arguments
capability device_name	{can eject
	| can play | can record | can save | compound device | device type | has audio | has video | uses files}
close device_name
info device_name	[file | product]
open device_name	[alias device_alias]
	[shareable]
	[type device_type]
pause device_name
play device_name	[from position]
	[to position]
record device_name	[from position]
	[to position]
	[insert | overwrite]
save device_name	[file_name]
seek device_name	[to position | to start | to end]
set device_name	[audio all off
	| audio all on | audio left off | audio left on | audio right off | audio right on | video off | video on]
	[master MIDI
	| master none | master SMPTE]
	[offset hmsf_value]
	[port port_number
	| port mapper | port none]
	[slave file
	| slave MIDI | slave none | slave SMPTE]
	[tempo tempo_value]
	[time format milliseconds
	| time format ms | time format smpte 24 | time format smpte 25 | time format smpte 30 | time format smpte 30 drop | time format song pointer]
status device_name	{current track
	| division type | length | length track track_number | master | media present | mode | number of tracks | offset | port | position | position track track_number | ready | slave | start position | tempo | time format}
stop device_name


Videodisc Commands

Videodisc players support the following set of commands. Videodisc devices also support notify and wait as optional flags. You can add either or both of these flags to any videodisc command.

Command	Arguments
capability device_name	{can eject
	| can play | can record | can reverse | can save | compound device | device type | fast play rate | has audio | has video | normal play rate | slow play rate | uses files}
	[CAV | CLV]
close device_name
escape device_name	{command_string}
info device_name	[product]
open device_name	[alias device_alias]
	[shareable]
pause device_name
play device_name	[fast | slow | speed fps]
	[from position]
	[scan]
	[to position | reverse]
resume device_name
seek device_name	[reverse | to position | to start | to end]
set device_name	[audio all off
	| audio all on | audio left off | audio left on | audio right off | audio right on | video off | video on]
	[door closed | door open]
	[time format milliseconds
	| time format ms | time format frames | time format hms | time format track]
spin device_name	[down | up]
status device_name	{current track
	| disc size | forward | length | length track track_number | media present | media type | mode | number of tracks | position | position track track_number | ready | side | speed | start position | time format}
step device_name	[by] position
	[reverse]
stop device_name


Video Overlay Command Set

Video overlay devices support the following set of commands. Video overlay devices also support notify and wait as optional flags. You can add either or both of these flags to any video overlay command.

Command	Arguments
capability device_name	{can eject
	| can freeze | can play | can record | can save | can stretch | compound device | device type | has audio | has video | uses files | windows}
close device_name
freeze device_name	[at rectangle]
info device_name	[product | file | window text]
load device_name	[file_name]
	at  buffer_rectangle
open device_name	[alias device_alias]
	[parent hwnd]
	[shareable]
	[style style_type
	| style child | style overlapped | style popup]
	[type device_type]
put device_name	{destination | at destination_rectangle
	| frame | frame at frame_rectangle | source | source at source_rectangle | video | video at video_rectangle}
save device_name	[file_name]
	at buffer_rectangle
set device_name	[audio all off
	| audio all on | audio left off | audio left on | audio right off | audio right on | video off | video on]
	[time format milliseconds
	| time format ms]
status device_name	{current track
	| length | length track track_number | media present | mode | number of tracks | position | position track track_number | ready | start position | stretch | time format | window handle}
unfreeze device_name	[at freeze_rectangle]
where device_name	{destination | frame | source | video}
window device_name	[handle window_handle | handle default]
	| [stretch | fixed]
	[state hide
	| state iconic | state maximized | state minimized | state no action | state no activate | state normal | state show]
	[text caption_text]


Waveform Audio Command Set

Wave audio devices support the following set of commands. Wave audio devices also support notify and wait as optional flags. You can add either or both of these flags to any wave audio command.

Command	Arguments
capability device_name	{can eject
	| can play | can record | can save | compound device | device type | has audio | has video | inputs | outputs | uses files}
close device_name
cue device_name	[input | output]
delete device_name	[from position]
	[to position]
info device_name	[file
	| input | output | product]
open device_name	[alias device_alias]
	[buffer buffer_size]
	[shareable]
	[type device_type]
pause device_name
play device_name	[from position]
	[to position]
record device_name	[from position]
	[to position]
	[insert | overwrite]
resume device_name
save device_name	[file_name]
seek device_name	[to position | to start | to end]
set device_name	[alignment block_alignment]
	[any input]
	[any output]
	[audio all off
	| audio all on | audio left off | audio left on | audio right off | audio right on | video off | video on]
	[bitspersample bit_count]
	[bytespersec byte_rate]
	[channels channel_count]
	[format tag tag | format tag pcm]
	[input device_number]
	[output device_number]
	[samplespersec sample_rate]
	[timeformat milliseconds
	| time format ms | time format bytes | time format samples]
status device_name	{alignment
	| bitspersample | bytespersec | channels | current track | format tag | input | length | length track track_number | level | media present | mode | number of tracks | output | position | position track track_number | ready | samplespersec | start position | time format}
stop device_name


Raster Operation Codes

Raster-operation codes define how the graphics device interface (GDI) combines the bits from the selected pen with the bits in the destination bitmap. This appendix lists and describes the binary and ternary raster operations used by GDI.


About Raster Operation Codes

This appendix lists and describes the binary and ternary raster operations used by graphics device interface (GDI). A binary raster operation involves two operands: a pen and a destination bitmap. A ternary raster operation involves three operands: a source bitmap, a brush, and a destination bitmap. Both binary and ternary raster operations use Boolean operators.


Binary Raster Operations

This section lists the binary raster-operation codes used by the GetROP2 and SetROP2 functions. Raster-operation codes define how GDI combines the bits from the selected pen with the bits in the destination bitmap.

Each raster-operation code represents a Boolean operation in which the values of the pixels in the selected pen and the destination bitmap are combined. Following are the two operands used in these operations:

Operand	Meaning
P	Selected pen
D	Destination bitmap
The Boolean operators used in these operations follow:

Operator	Meaning
a	Bitwise AND
n	Bitwise NOT (inverse)
o	Bitwise OR
x	Bitwise exclusive OR (XOR)
All Boolean operations are presented in reverse Polish notation. For example, the following operation replaces the values of the pixels in the destination bitmap with a combination of the pixel values of the pen and the selected brush:

DPo

Each raster-operation code is a 32-bit integer whose high-order word is a Boolean operation index and whose low-order word is the operation code. The 16-bit operation index is a zero-extended 8-bit value that represents all possible outcomes resulting from the Boolean operation on two parameters (in this case, the pen and destination values). For example, the operation indexes for the DPo and DPan operations are shown in the following list:

P	D	DPo	DPan
0	0	0	1
0	1	1	1
1	0	1	1
1	1	1	0
The following list outlines the drawing modes and the Boolean operations that they represent:

Raster operation	Boolean operation
R2_BLACK	0
R2_COPYPEN	P
R2_MASKNOTPEN	DPna
R2_MASKPEN	DPa
R2_MASKPENNOT	PDna
R2_MERGENOTPEN	DPno
R2_MERGEPEN	DPo
R2_MERGEPENNOT	PDno
R2_NOP	D
R2_NOT	Dn
R2_NOTCOPYPEN	Pn
R2_NOTMASKPEN	DPan
R2_NOTMERGEPEN	DPon
R2_NOTXORPEN	DPxn
R2_WHITE	1
R2_XORPEN	DPx
For a monochrome device, GDI maps the value zero to black and the value 1 to white. If an application attempts to draw with a black pen on a white destination by using the available binary raster operations, the following results occur:

Raster operation	Result
R2_BLACK	Visible black line
R2_COPYPEN	Visible black line
R2_MASKNOTPEN	No visible line
R2_MASKPEN	Visible black line
R2_MASKPENNOT	Visible black line
R2_MERGENOTPEN	No visible line
R2_MERGEPEN	Visible black line
R2_MERGEPENNOT	Visible black line
R2_NOP	No visible line
R2_NOT	Visible black line
R2_NOTCOPYPEN	No visible line
R2_NOTMASKPEN	No visible line
R2_NOTMERGEPEN	Visible black line
R2_NOTXORPEN	Visible black line
R2_WHITE	No visible line
R2_XORPEN	No visible line
For a color device, GDI uses RGB values to represent the colors of the pen and the destination. An RGB color value is a long integer that contains a red, a green, and a blue color field, each specifying the intensity of the given color. Intensities range from 0 through 255. The values are packed in the three low-order bytes of the long integer. The color of a pen is always a solid color, but the color of the destination may be a mixture of any two or three colors. If an application attempts to draw with a white pen on a blue destination by using the available binary raster operations, the following results occur:

Raster operation	Result
R2_BLACK	Visible black line
R2_COPYPEN	Visible white line
R2_MASKNOTPEN	Visible black line
R2_MASKPEN	Invisible blue line
R2_MASKPENNOT	Visible red/green line
R2_MERGENOTPEN	Invisible blue line
R2_MERGEPEN	Visible white line
R2_MERGEPENNOT	Visible white line
R2_NOP	Invisible blue line
R2_NOT	Visible red/green line
R2_NOTCOPYPEN	Visible black line
R2_NOTMASKPEN	Visible red/green line
R2_NOTMERGEPEN	Visible black line
R2_NOTXORPEN	Invisible blue line
R2_WHITE	Visible white line
R2_XORPEN	Visible red/green line


Ternary Raster Operations

This section lists the ternary raster-operation codes used by the BitBlt, PatBlt, and StretchBlt functions. Ternary raster-operation codes define how GDI combines the bits in a source bitmap with the bits in the destination bitmap.

Each raster-operation code represents a Boolean operation in which the values of the pixels in the source, the selected brush, and the destination are combined. Following are the three operands used in these operations:

Operand	Meaning
D	Destination bitmap
P	Selected brush (also called pattern)
S	Source bitmap
Boolean operators used in these operations follow:

Operator	Meaning
a	Bitwise AND
n	Bitwise NOT (inverse)
o	Bitwise OR
x	Bitwise exclusive OR (XOR)
All Boolean operations are presented in reverse Polish notation. For example, the following operation replaces the values of the pixels in the destination bitmap with a combination of the pixel values of the source and brush:

PSo

The following operation combines the values of the pixels in the source and brush with the pixel values of the destination bitmap (there are alternative spellings of the same function, so although a particular spelling may not be in the list, an equivalent form would be):

DPSoo

Each raster-operation code is a 32-bit integer whose high-order word is a Boolean operation index and whose low-order word is the operation code. The 16-bit operation index is a zero-extended, 8-bit value that represents the result of the Boolean operation on predefined brush, source, and destination values. For example, the operation indexes for the PSo and DPSoo operations are shown in the following list:

P	S	D	PSo	DPSoo
0	0	0	0	0
0	0	1	0	1
0	1	0	1	1
0	1	1	1	1
1	0	0	1	1
1	0	1	1	1
1	1	0	1	1
1	1	1	1	1
Operation index:			00FCh	00FEh
In this case, PSo has the operation index 00FC (read from the bottom up); DPSoo has the operation index 00FE. These values define the location of the corresponding raster-operation codes, as shown in Table A.1, "Raster-Operation Codes." The PSo operation is in line 252 (00FCh) of the table; DPSoo is in line 254 (00FEh).

The most commonly used raster operations have been given special names in the Windows include file, WINDOWS.H. You should use these names whenever possible in your applications.

When the source and destination bitmaps are monochrome, a bit value of zero represents a black pixel and a bit value of 1 represents a white pixel. When the source and the destination bitmaps are color, those colors are represented with RGB values. For more information about RGB values, see RGB

Raster-Operation Codes

Boolean function (hexadecimal)	Raster operation (hexadecimal)	Boolean function in reverse Polish	Common name
00	00000042	0	BLACKNESS
01	00010289	DPSoon	−
02	00020C89	DPSona	−
03	000300AA	PSon	−
04	00040C88	SDPona	−
05	000500A9	DPon	−
06	00060865	PDSxnon	−
07	000702C5	PDSaon	−
08	00080F08	SDPnaa	−
09	00090245	PDSxon	−
0A	000A0329	DPna	−
0B	000B0B2A	PSDnaon	−
0C	000C0324	SPna	−
0D	000D0B25	PDSnaon	−
0E	000E08A5	PDSonon	−
0F	000F0001	Pn	−
10	00100C85	PDSona	−
11	001100A6	DSon	NOTSRCERASE
12	00120868	SDPxnon	−
13	001302C8	SDPaon	−
14	00140869	DPSxnon	−
15	001502C9	DPSaon	−
16	00165CCA	PSDPSanaxx	−
17	00171D54	SSPxDSxaxn	−
18	00180D59	SPxPDxa	−
19	00191CC8	SDPSanaxn	−
1A	001A06C5	PDSPaox	−
1B	001B0768	SDPSxaxn	−
1C	001C06CA	PSDPaox	−
1D	001D0766	DSPDxaxn	−
1E	001E01A5	PDSox	−
1F	001F0385	PDSoan	−
20	00200F09	DPSnaa	−
21	00210248	SDPxon	−
22	00220326	DSna	−
23	00230B24	SPDnaon	−
24	00240D55	SPxDSxa	−
25	00251CC5	PDSPanaxn	−
26	002606C8	SDPSaox	−
27	00271868	SDPSxnox	−
28	00280369	DPSxa	−
29	002916CA	PSDPSaoxxn	−
2A	002A0CC9	DPSana	−
2B	002B1D58	SSPxPDxaxn	−
2C	002C0784	SPDSoax	−
2D	002D060A	PSDnox	−
2E	002E064A	PSDPxox	−
2F	002F0E2A	PSDnoan	−
30	0030032A	PSna	−
31	00310B28	SDPnaon	−
32	00320688	SDPSoox	−
33	00330008	Sn	NOTSRCCOPY
34	003406C4	SPDSaox	−
35	00351864	SPDSxnox	−
36	003601A8	SDPox	−
37	00370388	SDPoan	−
38	0038078A	PSDPoax	−
39	00390604	SPDnox	−
3A	003A0644	SPDSxox	−
3B	003B0E24	SPDnoan	−
3C	003C004A	PSx	−
3D	003D18A4	SPDSonox	−
3E	003E1B24	SPDSnaox	−
3F	003F00EA	PSan	−
40	00400F0A	PSDnaa	−
41	00410249	DPSxon	−
42	00420D5D	SDxPDxa	−
43	00431CC4	SPDSanaxn	−
44	00440328	SDna	SRCERASE
45	00450B29	DPSnaon	−
46	004606C6	DSPDaox	−
47	0047076A	PSDPxaxn	−
48	00480368	SDPxa	−
49	004916C5	PDSPDaoxxn	−
4A	004A0789	DPSDoax	−
4B	004B0605	PDSnox	−
4C	004C0CC8	SDPana	−
4D	004D1954	SSPxDSxoxn	−
4E	004E0645	PDSPxox	−
4F	004F0E25	PDSnoan	−
50	00500325	PDna	−
51	00510B26	DSPnaon	−
52	005206C9	DPSDaox	−
53	00530764	SPDSxaxn	−
54	005408A9	DPSonon	−
55	00550009	Dn	DSTINVERT
56	005601A9	DPSox	−
57	00570389	DPSoan	−
58	00580785	PDSPoax	−
59	00590609	DPSnox	−
5A	005A0049	DPx	PATINVERT
5B	005B18A9	DPSDonox	−
5C	005C0649	DPSDxox	−
5D	005D0E29	DPSnoan	−
5E	005E1B29	DPSDnaox	−
5F	005F00E9	DPan	−
60	00600365	PDSxa	−
61	006116C6	DSPDSaoxxn	−
62	00620786	DSPDoax	−
63	00630608	SDPnox	−
64	00640788	SDPSoax	−
65	00650606	DSPnox	−
66	00660046	DSx	SRCINVERT
67	006718A8	SDPSonox	−
68	006858A6	DSPDSonoxxn	−
69	00690145	PDSxxn	−
6A	006A01E9	DPSax	−
6B	006B178A	PSDPSoaxxn	−
6C	006C01E8	SDPax	−
6D	006D1785	PDSPDoaxxn	−
6E	006E1E28	SDPSnoax	−
6F	006F0C65	PDSxnan	−
70	00700CC5	PDSana	−
71	00711D5C	SSDxPDxaxn	−
72	00720648	SDPSxox	−
73	00730E28	SDPnoan	−
74	00740646	DSPDxox	−
75	00750E26	DSPnoan	−
76	00761B28	SDPSnaox	−
77	007700E6	DSan	−
78	007801E5	PDSax	−
79	00791786	DSPDSoaxxn	−
7A	007A1E29	DPSDnoax	−
7B	007B0C68	SDPxnan	−
7C	007C1E24	SPDSnoax	−
7D	007D0C69	DPSxnan	−
7E	007E0955	SPxDSxo	−
7F	007F03C9	DPSaan	−
80	008003E9	DPSaa	−
81	00810975	SPxDSxon	−
82	00820C49	DPSxna	−
83	00831E04	SPDSnoaxn	−
84	00840C48	SDPxna	−
85	00851E05	PDSPnoaxn	−
86	008617A6	DSPDSoaxx	−
87	008701C5	PDSaxn	−
88	008800C6	DSa	SRCAND
89	00891B08	SDPSnaoxn	−
8A	008A0E06	DSPnoa	−
8B	008B0666	DSPDxoxn	−
8C	008C0E08	SDPnoa	−
8D	008D0668	SDPSxoxn	−
8E	008E1D7C	SSDxPDxax	−
8F	008F0CE5	PDSanan	−
90	00900C45	PDSxna	−
91	00911E08	SDPSnoaxn	−
92	009217A9	DPSDPoaxx	−
93	009301C4	SPDaxn	−
94	009417AA	PSDPSoaxx	−
95	009501C9	DPSaxn	−
96	00960169	DPSxx	−
97	0097588A	PSDPSonoxx	−
98	00981888	SDPSonoxn	−
99	00990066	DSxn	−
9A	009A0709	DPSnax	−
9B	009B07A8	SDPSoaxn	−
9C	009C0704	SPDnax	−
9D	009D07A6	DSPDoaxn	−
9E	009E16E6	DSPDSaoxx	−
9F	009F0345	PDSxan	−
A0	00A000C9	DPa	−
A1	00A11B05	PDSPnaoxn	−
A2	00A20E09	DPSnoa	−
A3	00A30669	DPSDxoxn	−
A4	00A41885	PDSPonoxn	−
A5	00A50065	PDxn	−
A6	00A60706	DSPnax	−
A7	00A707A5	PDSPoaxn	−
A8	00A803A9	DPSoa	−
A9	00A90189	DPSoxn	−
AA	00AA0029	D	−
AB	00AB0889	DPSono	−
AC	00AC0744	SPDSxax	−
AD	00AD06E9	DPSDaoxn	−
AE	00AE0B06	DSPnao	−
AF	00AF0229	DPno	−
B0	00B00E05	PDSnoa	−
B1	00B10665	PDSPxoxn	−
B2	00B21974	SSPxDSxox	−
B3	00B30CE8	SDPanan	−
B4	00B4070A	PSDnax	−
B5	00B507A9	DPSDoaxn	−
B6	00B616E9	DPSDPaoxx	−
B7	00B70348	SDPxan	−
B8	00B8074A	PSDPxax	−
B9	00B906E6	DSPDaoxn	−
BA	00BA0B09	DPSnao	−
BB	00BB0226	DSno	MERGEPAINT
BC	00BC1CE4	SPDSanax	−
BD	00BD0D7D	SDxPDxan	−
BE	00BE0269	DPSxo	−
BF	00BF08C9	DPSano	−
C0	00C000CA	PSa	MERGECOPY
C1	00C11B04	SPDSnaoxn	−
C2	00C21884	SPDSonoxn	−
C3	00C3006A	PSxn	−
C4	00C40E04	SPDnoa	−
C5	00C50664	SPDSxoxn	−
C6	00C60708	SDPnax	−
C7	00C707AA	PSDPoaxn	−
C8	00C803A8	SDPoa	−
C9	00C90184	SPDoxn	−
CA	00CA0749	DPSDxax	−
CB	00CB06E4	SPDSaoxn	−
CC	00CC0020	S	SRCCOPY
CD	00CD0888	SDPono	−
CE	00CE0B08	SDPnao	−
CF	00CF0224	SPno	−
D0	00D00E0A	PSDnoa	−
D1	00D1066A	PSDPxoxn	−
D2	00D20705	PDSnax	−
D3	00D307A4	SPDSoaxn	−
D4	00D41D78	SSPxPDxax	−
D5	00D50CE9	DPSanan	−
D6	00D616EA	PSDPSaoxx	−
D7	00D70349	DPSxan	−
D8	00D80745	PDSPxax	−
D9	00D906E8	SDPSaoxn	−
DA	00DA1CE9	DPSDanax	−
DB	00DB0D75	SPxDSxan	−
DC	00DC0B04	SPDnao	−
DD	00DD0228	SDno	−
DE	00DE0268	SDPxo	−
DF	00DF08C8	SDPano	−
E0	00E003A5	PDSoa	−
E1	00E10185	PDSoxn	−
E2	00E20746	DSPDxax	−
E3	00E306EA	PSDPaoxn	−
E4	00E40748	SDPSxax	−
E5	00E506E5	PDSPaoxn	−
E6	00E61CE8	SDPSanax	−
E7	00E70D79	SPxPDxan	−
E8	00E81D74	SSPxDSxax	−
E9	00E95CE6	DSPDSanaxxn	−
EA	00EA02E9	DPSao	−
EB	00EB0849	DPSxno	−
EC	00EC02E8	SDPao	−
ED	00ED0848	SDPxno	−
EE	00EE0086	DSo	SRCPAINT
EF	00EF0A08	SDPnoo	−
F0	00F00021	P	PATCOPY
F1	00F10885	PDSono	−
F2	00F20B05	PDSnao	−
F3	00F3022A	PSno	−
F4	00F40B0A	PSDnao	−
F5	00F50225	PDno	−
F6	00F60265	PDSxo	−
F7	00F708C5	PDSano	−
F8	00F802E5	PDSao	−
F9	00F90845	PDSxno	−
FA	00FA0089	DPo	−
FB	00FB0A09	DPSnoo	PATPAINT
FC	00FC008A	PSo	−
FD	00FD0A0A	PSDnoo	−
FE	00FE02A9	DPSoo	−
FF	00FF0062	1	WHITENESS


Error Codes

Alphabetic listing

Numerical listing


Alphabetical List of Error Codes

EPT_S_CANT_CREATE

The endpoint mapper database could not be created.

EPT_S_CANT_PERFORM_OP

The operation cannot be performed.

EPT_S_INVALID_ENTRY

The entry is invalid.

EPT_S_NOT_REGISTERED

There are no more endpoints available from the endpoint mapper.

ERROR_ACCESS_DENIED

Access is denied.

ERROR_ACCOUNT_DISABLED

The referenced account is currently disabled and cannot be logged on to.

ERROR_ACCOUNT_EXPIRED

The user's account has expired.

ERROR_ACCOUNT_RESTRICTION

Indicates a referenced user name and authentication information are valid, but some user account restriction has prevented successful authentication (such as time-of-day restrictions).

ERROR_ADAP_HDW_ERR

A network adapter hardware error occurred.

ERROR_ALIAS_EXISTS

The specified alias already exists.

ERROR_ALLOTTED_SPACE_EXCEEDED

When a block of memory is allotted for future updates, such as the memory allocated to hold discretionary access control and primary group information, successive updates may exceed the amount of memory originally allotted. Since quota may already have been charged to several processes that have handles of the object, it is not reasonable to alter the size of the allocated memory. Instead, a request that requires more memory than has been allotted must fail and the ERROR_ALLOTTED_SPACE_EXCEEDED error returned.

ERROR_ALREADY_ASSIGNED

The local device name is already in use.

ERROR_ALREADY_EXISTS

Attempt to create file that already exists.

ERROR_ALREADY_RUNNING_LKG

The system is currently running with the last-known-good configuration.

ERROR_ARENA_TRASHED

The storage control blocks were destroyed.

ERROR_ARITHMETIC_OVERFLOW

Arithmetic result exceeded 32-bits.

ERROR_ATOMIC_LOCKS_NOT_SUPPORTED

The file system does not support atomic changing of the lock type.

ERROR_AUTODATASEG_EXCEEDS_64k

The operating system cannot run this application program.

ERROR_BAD_ARGUMENTS

The argument string passed to DosExecPgm is incorrect.

ERROR_BAD_COMMAND

The device does not recognize the command.

ERROR_BAD_DESCRIPTOR_FORMAT

Indicates a security descriptor is not in the required format (absolute or self-relative).

ERROR_BAD_DEV_TYPE

The network resource type is incorrect.

ERROR_BAD_DEVICE

The specified device name is invalid.

ERROR_BAD_DRIVER_LEVEL

The system does not support the requested command.

ERROR_BAD_ENVIRONMENT

The environment is incorrect.

ERROR_BAD_EXE_FORMAT

%1 is not a valid Windows-based application.

ERROR_BAD_FORMAT

An attempt was made to load a program with an incorrect format.

ERROR_BAD_IMPERSONATION_LEVEL

A specified impersonation level is invalid. Also used to indicate a required impersonation level was not provided.

ERROR_BAD_INHERITANCE_ACL

Indicates that an attempt to build either an inherited ACL or ACE did not succeed. One of the more probable causes is the replacement of a CreatorId with an SID that didn't fit into the ACE or ACL.

ERROR_BAD_LENGTH

The program issued a command but the command length is incorrect.

ERROR_BAD_LOGON_SESSION_STATE

The logon session is not in a state consistent with the requested operation.

ERROR_BAD_NET_NAME

The network name cannot be found.

ERROR_BAD_NET_RESP

The specified server cannot perform the requested operation.

ERROR_BAD_NETPATH

The network path was not found.

ERROR_BAD_PATHNAME

The specified path name is invalid.

ERROR_BAD_PIPE

The pipe state is invalid.

ERROR_BAD_PROFILE

The network connection profile is damaged.

ERROR_BAD_PROVIDER

The specified network provider name is invalid.

ERROR_BAD_REM_ADAP

The remote adapter is not compatible.

ERROR_BAD_THREADID_ADDR

The address for the thread ID is incorrect.

ERROR_BAD_TOKEN_TYPE

The type of token object is inappropriate for its attempted use.

ERROR_BAD_UNIT

The system cannot find the specified device.

ERROR_BAD_USERNAME

The specified user name is invalid.

ERROR_BAD_VALIDATION_CLASS

The requested validation information class is invalid.

ERROR_BADDB

The configuration registry database is damaged.

ERROR_BADKEY

The configuration registry key is invalid.

ERROR_BEGINNING_OF_MEDIA

The beginning of the tape or partition was encountered.

ERROR_BOOT_ALREADY_ACCEPTED

The current boot has already been accepted for use as the last-known-good control set.

ERROR_BROKEN_PIPE

The pipe was ended.

ERROR_BUFFER_OVERFLOW

The file name is too long.

ERROR_BUS_RESET

The I/O bus was reset.

ERROR_BUSY

The requested resource is in use.

ERROR_BUSY_DRIVE

The system cannot perform a JOIN or SUBST at this time.

ERROR_CALL_NOT_IMPLEMENTED

The Application Program Interface (API) entered will only work in Windows/NT mode.

ERROR_CAN_NOT_COMPLETE

Cannot complete function for some reason.

ERROR_CANCEL_VIOLATION

A lock request was not outstanding for the supplied cancel region.

ERROR_CANNOT_COPY

The Copy API cannot be used.

ERROR_CANNOT_FIND_WND_CLASS

Cannot find window class.

ERROR_CANNOT_IMPERSONATE

Indicates that an attempt was made to impersonate via a named pipe was not yet read from.

ERROR_CANNOT_MAKE

The directory or file cannot be created.

ERROR_CANNOT_OPEN_PROFILE

Unable to open the network connection profile.

ERROR_CANT_ACCESS_DOMAIN_INFO

Indicates a domain controller could not be contacted or that objects within the domain are protected and necessary information could not be retrieved.

ERROR_CANT_DISABLE_MANDATORY

A mandatory group cannot be disabled.

ERROR_CANT_OPEN_ANONYMOUS

An attempt was made to open an anonymous level token. Anonymous tokens cannot be opened.

ERROR_CANTOPEN

The configuration registry key cannot be opened.

ERROR_CANTREAD

The configuration registry key cannot be read.

ERROR_CANTWRITE

The configuration registry key cannot be written.

ERROR_CHILD_MUST_BE_VOLATILE

An attempt was made to create a stable subkey under a volatile parent key.

ERROR_CHILD_NOT_COMPLETE

The %1 application cannot be run in Windows mode.

ERROR_CHILD_WINDOW_MENU

Child windows can't have menus.

ERROR_CIRCULAR_DEPENDENCY

Circular service dependency was specified.

ERROR_CLASS_ALREADY_EXISTS

Class already exists.

ERROR_CLASS_DOES_NOT_EXIST

Class does not exist.

ERROR_CLASS_HAS_WINDOWS

Class still has open windows.

ERROR_CLIPBOARD_NOT_OPEN

Thread doesn't have clipboard open.

ERROR_CONNECTION_UNAVAIL

The device is not currently connected but is a remembered connection.

ERROR_CONTROL_ID_NOT_FOUND

Control ID not found.

ERROR_COUNTER_TIMEOUT

A serial I/O operation completed because the time-out period expired. (The IOCTL_SERIAL_XOFF_COUNTER did not reach zero.)

ERROR_CRC

Data error (cyclic redundancy check).

ERROR_CURRENT_DIRECTORY

The directory cannot be removed.

ERROR_DATABASE_DOES_NOT_EXIST

The database specified does not exist.

ERROR_DC_NOT_FOUND

Invalid HDC passed to ReleaseDC.

ERROR_DEPENDENT_SERVICES_RUNNING

A stop control has been sent to a service which other running services are dependent on.

ERROR_DESTROY_OBJECT_OF_OTHER_THREAD

Cannot destroy object created by another thread.

ERROR_DEV_NOT_EXIST

The specified network resource is no longer available.

ERROR_DEVICE_ALREADY_REMEMBERED

An attempt was made to remember a device that was previously remembered.

ERROR_DEVICE_IN_USE

The device is in use by an active process and cannot be disconnected.

ERROR_DEVICE_NOT_PARTITIONED

Tape partition information could not be found when loading a tape.

ERROR_DIR_NOT_EMPTY

The directory is not empty.

ERROR_DIR_NOT_ROOT

The directory is not a subdirectory of the root directory.

ERROR_DIRECT_ACCESS_HANDLE

Attempt to use a file handle to an open disk partition for an operation other than raw disk I/O.

ERROR_DIRECTORY

The directory name is invalid.

ERROR_DISCARDED

The segment is already discarded and cannot be locked.

ERROR_DISK_CHANGE

Program stopped because alternate disk was not inserted.

ERROR_DISK_CORRUPT

The disk structure is damaged and nonreadable.

ERROR_DISK_FULL

There is not enough space on the disk.

ERROR_DISK_OPERATION_FAILED

While accessing the hard disk, a disk operation failed even after retries.

ERROR_DISK_RECALIBRATE_FAILED

While accessing the hard disk, a recalibrate operation failed, even after retries.

ERROR_DISK_RESET_FAILED

While accessing the hard disk, a disk controller reset was needed, but even that failed.

ERROR_DLL_INIT_FAILED

A DLL initialization routine failed.

ERROR_DOMAIN_EXISTS

The specified domain already exists.

ERROR_DOMAIN_LIMIT_EXCEEDED

An attempt to exceed the limit on the number of domains per server for this release.

ERROR_DOMAIN_TRUST_INCONSISTENT

The name or security ID (SID) of the domain specified is inconsistent with the trust information for that domain.

ERROR_DRIVE_LOCKED

The disk is in use or locked by another process.

ERROR_DUP_DOMAINNAME

The workgroup or domain name is already in use by another computer on the network.

ERROR_DUP_NAME

A duplicate name exists on the network.

ERROR_DUPLICATE_SERVICE_NAME

The name is already in use as either a service name or a service display name.

ERROR_DYNLINK_FROM_INVALID_RING

The operating system cannot run this application program.

ERROR_EA_ACCESS_DENIED

Access to the EA is denied.

ERROR_EA_FILE_CORRUPT

The EA file on the mounted file system is damaged.

ERROR_EA_LIST_INCONSISTENT

The EAs are inconsistent.

ERROR_EA_TABLE_FULL

The EA table in the EA file on the mounted file system is full.

ERROR_EAS_DIDNT_FIT

The EAs did not fit in the buffer.

ERROR_EAS_NOT_SUPPORTED

The mounted file system does not support extended attributes.

ERROR_END_OF_MEDIA

End of tape mark was reached during an operation.

ERROR_ENVVAR_NOT_FOUND

The system could not find the environment option entered.

ERROR_EOM_OVERFLOW

Physical end of tape encountered.

ERROR_EVENTLOG_CANT_START

No event log file could be opened, so the event logging service did not start.

ERROR_EVENTLOG_FILE_CHANGED

The event log file has changed between reads.

ERROR_EVENTLOG_FILE_CORRUPT

One of the Eventlog logfiles is damaged.

ERROR_EXCEPTION_IN_SERVICE

An exception occurred in the service when handling the control request.

ERROR_EXCL_SEM_ALREADY_OWNED

The exclusive semaphore is owned by another process.

ERROR_EXE_MARKED_INVALID

The operating system cannot run %1.

ERROR_EXTENDED_ERROR

An extended error has occurred.

ERROR_FAIL_I24

Fail on INT 24.

ERROR_FAILED_SERVICE_CONTROLLER_CONNECT

The service process could not connect to the service controller.

ERROR_FILE_CORRUPT

The file or directory is damaged and nonreadable.

ERROR_FILE_EXISTS

The file exists.

ERROR_FILE_INVALID

The volume for a file was externally altered and the opened file is no longer valid.

ERROR_FILE_NOT_FOUND

The system cannot find the file specified.

ERROR_FILEMARK_DETECTED

A tape access reached a filemark.

ERROR_FILENAME_EXCED_RANGE

The file name or extension is too long.

ERROR_FLOPPY_BAD_REGISTERS

The floppy disk controller returned inconsistent results in its registers.

ERROR_FLOPPY_ID_MARK_NOT_FOUND

No ID address mark was found on the floppy disk.

ERROR_FLOPPY_WRONG_CYLINDER

Mismatch between the floppy disk sector ID field and the floppy disk controller track address.

ERROR_FLOPPY_UNKNOWN_ERROR

The floppy disk controller reported an error that is not recognized by the floppy disk driver.

ERROR_FULLSCREEN_MODE

The requested operation cannot be performed in full-screen mode.

ERROR_GEN_FAILURE

A device attached to the system is not functioning.

ERROR_GENERIC_NOT_MAPPED

Indicates generic access types were contained in an access mask that should already be mapped to non-generic access types.

ERROR_GLOBAL_ONLY_HOOK

This hook can only be set globally.

ERROR_GROUP_EXISTS

The specified group already exists.

ERROR_HANDLE_DISK_FULL

The disk is full.

ERROR_HANDLE_EOF

Reached End Of File.

ERROR_HOOK_NEEDS_HMOD

Cannot set non-local hook without an module handle.

ERROR_HOOK_NOT_INSTALLED

Hook is not installed.

ERROR_HOTKEY_ALREADY_REGISTERED

Hotkey is already registered.

ERROR_HOTKEY_NOT_REGISTERED

Hotkey is not registered.

ERROR_HWNDS_HAVE_DIFFERENT_PARENT

All DeferWindowPos HWNDs must have same parent.

ERROR_ILL_FORMED_PASSWORD

When trying to update a password, this return status indicates the value provided for the new password contains values not allowed in passwords.

ERROR_INFLOOP_IN_RELOC_CHAIN

The operating system cannot run %1.

ERROR_INSUFFICIENT_BUFFER

The data area passed to a system call is too small.

ERROR_INTERNAL_DB_CORRUPTION

This error indicates the requested operation cannot be completed due to a catastrophic media failure or on-disk data structure corruption.

ERROR_INTERNAL_DB_ERROR

The Local Security Authority (LSA) database contains in internal inconsistency.

ERROR_INTERNAL_ERROR

This error indicates the SAM server has encounterred an internal consistency error in its database. This catastrophic failure prevents further operation of SAM.

ERROR_INVALID_ACCEL_HANDLE

Invalid accelerator-table handle.

ERROR_INVALID_ACCESS

The access code is invalid.

ERROR_INVALID_ACCOUNT_NAME

The name provided is not a properly formed account name.

ERROR_INVALID_ACL

Indicates the ACL structure is not valid.

ERROR_INVALID_ADDRESS

Attempt to access invalid address.

ERROR_INVALID_AT_INTERRUPT_TIME

Cannot request exclusive semaphores at interrupt time.

ERROR_INVALID_BLOCK

The storage control block address is invalid.

ERROR_INVALID_BLOCK_LENGTH

When accessing a new tape of a multivolume partition, the current block size is incorrect.

ERROR_INVALID_CATEGORY

The IOCTL call made by the application program is incorrect.

ERROR_INVALID_COMBOBOX_MESSAGE

Invalid Message, combo box doesn't have an edit control.

ERROR_INVALID_COMPUTERNAME

The format of the specified computer name is invalid.

ERROR_INVALID_CURSOR_HANDLE

The cursor handle is invalid.

ERROR_INVALID_DATA

The data is invalid.

ERROR_INVALID_DATATYPE

The specified datatype is invalid.

ERROR_INVALID_DOMAINNAME

The format of the specified domain name is invalid.

ERROR_INVALID_DOMAIN_ROLE

Indicates the requested operation cannot be completed with the domain in its present role.

ERROR_INVALID_DOMAIN_STATE

Indicates the domain is in the wrong state to perform the desired operation.

ERROR_INVALID_DRIVE

The system cannot find the specified drive.

ERROR_INVALID_DWP_HANDLE

The DeferWindowPos handle is invalid.

ERROR_INVALID_EA_HANDLE

The specified EA handle is invalid.

ERROR_INVALID_EA_NAME

The specified EA name is invalid.

ERROR_INVALID_EDIT_HEIGHT

Height must be less than 256.

ERROR_INVALID_ENVIRONMENT

The Environment specified is invalid.

ERROR_INVALID_EVENT_COUNT

The number of specified semaphore events is incorrect.

ERROR_INVALID_EVENTNAME

The format of the specified event name is invalid.

ERROR_INVALID_EXE_SIGNATURE

%1 cannot be run in Windows/NT mode.

ERROR_INVALID_FILTER_PROC

The filter proc is invalid.

ERROR_INVALID_FLAG_NUMBER

The flag passed is incorrect.

ERROR_INVALID_FLAGS

The flags are invalid.

ERROR_INVALID_FUNCTION

The function is incorrect.

ERROR_INVALID_GROUP_ATTRIBUTES

The specified attributes are invalid, or incompatible with the attributes for the group as a whole.

ERROR_INVALID_GROUPNAME

The format of the specified group name is invalid.

ERROR_INVALID_GW_COMMAND

The GW_* command is invalid.

ERROR_INVALID_HANDLE

The internal file identifier is incorrect.

ERROR_INVALID_HOOK_FILTER

The hook filter type is invalid.

ERROR_INVALID_HOOK_HANDLE

The hook handle is invalid.

ERROR_INVALID_ICON_HANDLE

The icon handle is invalid.

ERROR_INVALID_ID_AUTHORITY

The value provided is an invalid value for an identifier authority.

ERROR_INVALID_INDEX

The index is invalid.

ERROR_INVALID_LB_MESSAGE

The message for single-selection list box is invalid.

ERROR_INVALID_LEVEL

The system call level is incorrect.

ERROR_INVALID_LIST_FORMAT

The list is not correct.

ERROR_INVALID_LOGON_HOURS

The user account has time restrictions and cannot be logged onto at this time.

ERROR_INVALID_LOGON_TYPE

Indicates an invalid value has been provided for LogonType has been requested.

ERROR_INVALID_MEMBER

A new member could not be added to an alias because the member has the wrong account type.

ERROR_INVALID_MENU_HANDLE

The menu handle is invalid.

ERROR_INVALID_MESSAGE

Window can't handle sent message.

ERROR_INVALID_MESSAGEDEST

The format of the specified message destination is invalid.

ERROR_INVALID_MESSAGENAME

The format of the specified message name is invalid.

ERROR_INVALID_MINALLOCSIZE

The operating system cannot run %1.

ERROR_INVALID_MODULETYPE

The operating system cannot run %1.

ERROR_INVALID_MSGBOX_STYLE

The message box style is invalid.

ERROR_INVALID_NAME

The file name, directory name, or volume label is syntactically incorrect.

ERROR_INVALID_NETNAME

The format of the specified network name is invalid.

ERROR_INVALID_ORDINAL

The operating system cannot run %1.

ERROR_INVALID_OWNER

Indicates a particular Security ID cannot be assigned as the owner of an object.

ERROR_INVALID_PARAMETER

The parameter is incorrect.

ERROR_INVALID_PASSWORD

The specified network password is incorrect.

ERROR_INVALID_PASSWORDNAME

The format of the specified password is invalid.

ERROR_INVALID_PRIMARY_GROUP

Indicates a particular Security ID cannot be assigned as the primary group of an object.

ERROR_INVALID_PRINTER_COMMAND

The printer command is invalid.

ERROR_INVALID_PRINTER_NAME

The printer name is invalid.

ERROR_INVALID_PRIORITY

The specified priority is invalid.

ERROR_INVALID_SCROLLBAR_RANGE

Scrollbar range greater than 0x7FFF.

ERROR_INVALID_SECURITY_DESCR

Indicates the SECURITY_DESCRIPTOR structure is invalid.

ERROR_INVALID_SEGDPL

The operating system cannot run %1.

ERROR_INVALID_SEGMENT_NUMBER

The system detected a segment number that is incorrect.

ERROR_INVALID_SEPARATOR_FILE

The specified separator file is invalid.

ERROR_INVALID_SERVER_STATE

Indicates the Sam Server was in the wrong state to perform the desired operation.

ERROR_INVALID_SERVICE_ACCOUNT

The account name is invalid or does not exist.

ERROR_INVALID_SERVICE_CONTROL

The requested control is not valid for this service

ERROR_INVALID_SERVICE_LOCK

The specified service database lock is invalid.

ERROR_INVALID_SERVICENAME

The format of the specified service name is invalid.

ERROR_INVALID_SHARENAME

The format of the specified share name is invalid.

ERROR_INVALID_SHOWWIN_COMMAND

The ShowWindow command is invalid.

ERROR_INVALID_SID

Indicates the SID structure is invalid.

ERROR_INVALID_SIGNAL_NUMBER

The signal being posted is incorrect.

ERROR_INVALID_SPI_VALUE

The SPI_* parameter is invalid.

ERROR_INVALID_STACKSEG

The operating system cannot run %1.

ERROR_INVALID_STARTING_CODESEG

The operating system cannot run %1.

ERROR_INVALID_SUB_AUTHORITY

Indicates the sub-authority value is invalid for the particular use.

ERROR_INVALID_TARGET_HANDLE

The target internal file identifier is incorrect.

ERROR_INVALID_THREAD_ID

The thread ID is invalid.

ERROR_INVALID_USER_BUFFER

The supplied user buffer is invalid for the requested operation.

ERROR_INVALID_VERIFY_SWITCH

The verify-on-write switch parameter value is incorrect.

ERROR_INVALID_WINDOW_HANDLE

The window handle invalid.

ERROR_INVALID_WORKSTATION

The user account is restricted and cannot be used to log on from the source workstation.

ERROR_IO_DEVICE

The request could not be performed because of an I/O device error.

ERROR_IO_INCOMPLETE

Overlapped IO event not in signaled state.

ERROR_IO_PENDING

Overlapped IO operation in progress.

ERROR_IOPL_NOT_ENABLED

The operating system is not presently configured to run this application.

ERROR_IRQ_BUSY

Unable to open a device that was sharing an interrupt request (IRQ) with other devices. At least one other device that uses that IRQ was already opened.

ERROR_IS_JOIN_PATH

Not enough resources are available to process this command.

ERROR_IS_JOIN_TARGET

A JOIN or SUBST command cannot be used for a drive that contains previously joined drives.

ERROR_IS_JOINED

An attempt was made to use a JOIN or SUBST command on a drive that is already joined.

ERROR_IS_SUBST_PATH

The path specified is being used in a substitute.

ERROR_IS_SUBST_TARGET

An attempt was made to join or substitute a drive for which a directory on the drive is the target of a previous substitute.

ERROR_IS_SUBSTED

An attempt was made to use a JOIN or SUBST command on a drive already substituted.

ERROR_ITERATED_DATA_EXCEEDS_64k

The operating system cannot run %1.

ERROR_JOIN_TO_JOIN

The system tried to join a drive to a directory on a joined drive.

ERROR_JOIN_TO_SUBST

The system tried to join a drive to a directory on a substituted drive.

ERROR_JOURNAL_HOOK_SET

The journal hook is already installed.

ERROR_KEY_DELETED

Illegal operation attempted on a registry key that has been marked for deletion.

ERROR_KEY_HAS_CHILDREN

An attempt was made to create a symbolic link in a registry key that already has subkeys or values.

ERROR_LABEL_TOO_LONG

The volume label entered exceeds the 11 character limit. The first 11 characters were written to disk. Any characters that exceeded the 11 character limit were automatically deleted.

ERROR_LAST_ADMIN

Indicates the requested operation would disable or delete the last remaining administration account. This is not allowed to prevent creating a situation where the system will not be administrable.

ERROR_LB_WITHOUT_TABSTOPS

This list box doesn't support tab stops.

ERROR_LISTBOX_ID_NOT_FOUND

List box ID not found.

ERROR_LM_CROSS_ENCRYPTION_REQUIRED

An attempt was made to change a user password in the security account manager without providing the required LM cross-encrypted password.

ERROR_LOCAL_USER_SESSION_KEY

A user session key was requested for a local RPC connection. The session key returned is a constant value and not unique to this connection.

ERROR_LOCK_FAILED

Attempt to lock a region of a file failed.

ERROR_LOCK_VIOLATION

The process cannot access the file because another process has locked a portion of the file.

ERROR_LOCKED

The segment is locked and cannot be reallocated.

ERROR_LOG_FILE_FULL

The event log file is full.

ERROR_LOGON_FAILURE

The attempted logon is invalid. This is due to either a bad user name or authentication information.

ERROR_LOGON_NOT_GRANTED

A requested type of logon, such as Interactive, Network, or Service, is not granted by the target system's local security policy. The system administrator can grant the required form of logon.

ERROR_LOGON_SESSION_COLLISION

The logon session ID is already in use.

ERROR_LOGON_SESSION_EXISTS

An attempt was made to start a new session manager or LSA logon session with an ID already in use.

ERROR_LOGON_TYPE_NOT_GRANTED

A user has requested a type of logon, such as interactive or network, that was not granted. An administrator has control over who may logon interactively and through the network.

ERROR_LUIDS_EXHAUSTED

Indicates there are no more LUID to allocate.

ERROR_MAX_THRDS_REACHED

No more threads can be created in the system.

ERROR_MEDIA_CHANGED

Media in drive may have changed.

ERROR_MEMBER_IN_ALIAS

The specified account name is not a member of the alias.

ERROR_MEMBER_IN_GROUP

The specified user account is already in the specified group account. Also used to indicate a group can not be deleted because it contains a member.

ERROR_MEMBER_NOT_IN_ALIAS

The specified account name is not a member of the alias.

ERROR_MEMBER_NOT_IN_GROUP

The specified user account is not a member of the specified group account.

ERROR_MEMBERS_PRIMARY_GROUP

Indicates a member cannot be removed from a group because the group is currently the member's primary group.

ERROR_META_EXPANSION_TOO_LONG

The global filename characters * or ? are entered incorrectly, or too many global filename characters are specified.

ERROR_MOD_NOT_FOUND

The specified module cannot be found.

ERROR_MORE_DATA

More data is available.

ERROR_MORE_WRITES

A serial I/O operation was completed by another write to the serial port. (The IOCTL_SERIAL_XOFF_COUNTER reached zero.)

ERROR_MR_MID_NOT_FOUND

The system cannot find message for message number 0x%1 in message file for %2.

ERROR_NEGATIVE_SEEK

An attempt was made to move the file pointer before the beginning of the file.

ERROR_NESTING_NOT_ALLOWED

Can't nest calls to LoadModule.

ERROR_NETLOGON_NOT_STARTED

An attempt was made to logon, but the network logon service was not started.

ERROR_NET_WRITE_FAULT

A write fault occurred on the network.

ERROR_NETNAME_DELETED

The specified network name is no longer available.

ERROR_NETWORK_ACCESS_DENIED

Network access is denied.

ERROR_NETWORK_BUSY

The network is busy.

ERROR_NO_BROWSER_SERVERS_FOUND

The list of servers for this workgroup is not currently available

ERROR_NO_DATA

Pipe close in progress.

ERROR_NO_DATA_DETECTED

During a tape access, the end of the data marker was reached.

ERROR_NO_IMPERSONATION_TOKEN

An attempt was made to operate on an impersonation token by a thread was not currently impersonating a client.

ERROR_NO_INHERITANCE

Indicates an ACL contains no inheritable components.

ERROR_NO_LOG_SPACE

System could not allocate required space in a registry log.

ERROR_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT

The account used is an interdomain trust account. Use your normal user account or remote user account to access this server.

ERROR_NOLOGON_SERVER_TRUST_ACCOUNT

The account used is an server trust account. Use your normal user account or remote user account to access this server.

ERROR_NO_LOGON_SERVERS

There are currently no logon servers available to service the logon request.

ERROR_NOLOGON_WORKSTATION_TRUST_ACCOUNT

The account used is a workstation trust account. Use your normal user account or remote user account to access this server.

ERROR_NO_MEDIA_IN_DRIVE

Tape query failed because of no media in drive.

ERROR_NO_MORE_FILES

There are no more files.

ERROR_NO_MORE_ITEMS

No more data is available.

ERROR_NO_MORE_SEARCH_HANDLES

No more internal file identifiers available.

ERROR_NO_NET_OR_BAD_PATH

No network provider accepted the given network path.

ERROR_NO_NETWORK

The network is not present or not started.

ERROR_NO_PROC_SLOTS

The system cannot start another process at this time.

ERROR_NO_QUOTAS_FOR_ACCOUNT

No system quota limits are specifically set for this account.

ERROR_NO_SCROLLBARS

Window does not have scroll bars.

ERROR_NO_SECURITY_ON_OBJECT

Indicates an attempt was made to operate on the security of an object that does not have security associated with it.

ERROR_NO_SHUTDOWN_IN_PROGRESS

An attempt to abort the shutdown of the system failed because no shutdown was in progress.

ERROR_NO_SIGNAL_SENT

No process in the command subtree has a signal handler.

ERROR_NO_SPOOL_SPACE

Space to store the file waiting to be printed is not available on the server.

ERROR_NO_SUCH_ALIAS

The specified alias does not exist.

ERROR_NO_SUCH_DOMAIN

The specified domain does not exist.

ERROR_NO_SUCH_GROUP

The specified group does not exist.

ERROR_NO_SUCH_LOGON_SESSION

A specified logon session does not exist. It may already have been terminated.

ERROR_NO_SUCH_MEMBER

A new member cannot be added to an alias because the member does not exist.

ERROR_NO_SUCH_PACKAGE

A specified authentication package is unknown.

ERROR_NO_SUCH_PRIVILEGE

A specified privilege does not exist.

ERROR_NO_SUCH_USER

The specified user does not exist.

ERROR_NO_SYSTEM_MENU

Window does not have system menu.

ERROR_NO_TOKEN

An attempt was made to reference a token that does not exist.

ERROR_NO_TRUST_LSA_SECRET

The workstation does not have a trust secret.

ERROR_NO_TRUST_SAM_ACCOUNT

The domain controller does not have an account for this workstation.

ERROR_NO_UNICODE_TRANSLATION

No mapping for the Unicode character exists in the target multi-byte code page.

ERROR_NO_USER_SESSION_KEY

There is no user session key for the specified logon session.

ERROR_NO_VOLUME_LABEL

The disk has no volume label.

ERROR_NO_WILDCARD_CHARACTERS

No wildcard characters found.

ERROR_NOACCESS

Invalid access to memory location.

ERROR_NON_MDICHILD_WINDOW

DefMDIChildProc called with a non-MDI child window.

ERROR_NONE_MAPPED

None of the information to be mapped has been translated.

ERROR_NOT_ALL_ASSIGNED

Indicates not all privileges referenced are assigned to the caller. This allows, for example, all privileges to be disabled without having to know exactly which privileges are assigned.

ERROR_NOT_CHILD_WINDOW

Window is not a child window.

ERROR_NOT_CONNECTED

This network connection does not exist.

ERROR_NOT_CONTAINER

Cannot enumerate a non-container.

ERROR_NOT_DOS_DISK

The specified disk cannot be accessed.

ERROR_NOT_ENOUGH_MEMORY

Not enough storage is available to process this command.

ERROR_NOT_ENOUGH_SERVER_MEMORY

Not enough server storage is available to process this command.

ERROR_NOT_JOINED

The system attempted to delete the JOIN of a drive not previously joined.

ERROR_NOT_LOCKED

The segment is already unlocked.

ERROR_NOT_LOGON_PROCESS

The requested action is restricted for use by logon processes only. The calling process has not registered as a logon process.

ERROR_NOT_OWNER

Attempt to release mutex not owned by caller.

ERROR_NOT_READY

The drive is not ready.

ERROR_NOT_REGISTRY_FILE

The system attempted to load or restore a file into the registry, and the specified file is not in the format of a registry file.

ERROR_NOT_SAME_DEVICE

The system cannot move the file to a different disk drive.

ERROR_NOT_SUBSTED

The system attempted to delete the substitution of a drive not previously substituted.

ERROR_NOT_SUPPORTED

The network request is not supported.

ERROR_NOTIFY_ENUM_DIR

This indicates that a notify change request is being completed and the information is not being returned in the caller's buffer. The caller now needs to enumerate the files to find the changes.

ERROR_NT_CROSS_ENCRYPTION_REQUIRED

An attempt was made to change a user password in the security account manager without providing the necessary NT cross-encrypted password.

ERROR_NULL_LM_PASSWORD

The Windows NT password is too complex to be converted to a Windows-networking password. The Windows-networking password returned is a NULL string.

ERROR_OPEN_FAILED

The system cannot open the specified device or file.

ERROR_OPEN_FILES

There are open files or requests pending on this connection.

ERROR_OPERATION_ABORTED

The I/O operation was aborted due to either thread exit or application request.

ERROR_OUT_OF_PAPER

The printer is out of paper.

ERROR_OUT_OF_STRUCTURES

Storage to process this request is not available.

ERROR_OUTOFMEMORY

Not enough storage is available to complete this operation.

ERROR_PARTITION_FAILURE

Tape could not be partitioned.

ERROR_PASSWORD_EXPIRED

The user account's password has expired.

ERROR_PASSWORD_RESTRICTION

When trying to update a password, this status indicates that some password update rule was violated. For example, the password may not meet length criteria.

ERROR_PATH_BUSY

The specified path cannot be used at this time.

ERROR_PATH_NOT_FOUND

The system cannot find the specified path.

ERROR_PIPE_BUSY

All pipe instances busy.

ERROR_PIPE_CONNECTED

There is a process on other end of the pipe.

ERROR_PIPE_LISTENING

Waiting for a process to open the other end of the pipe.

ERROR_PIPE_NOT_CONNECTED

No process on other end of pipe.

ERROR_POPUP_ALREADY_ACTIVE

Pop-up menu already active.

ERROR_POSSIBLE_DEADLOCK

A potential deadlock condition has been detected.

ERROR_PRINT_CANCELLED

File waiting to be printed was deleted.

ERROR_PRINTER_ALREADY_EXISTS

The printer already exists.

ERROR_PRINTER_DRIVER_ALREADY_INSTALLED

The specified printer driver is already installed.

ERROR_PRINTQ_FULL

The printer queue is full.

ERROR_PRIVATE_DIALOG_INDEX

Using private DIALOG window words.

ERROR_PRIVILEGE_NOT_HELD

A required privilege is not held by the client.

ERROR_PROC_NOT_FOUND

The specified procedure could not be found.

ERROR_PROCESS_ABORTED

The process terminated unexpectedly.

ERROR_READ_FAULT

The system cannot read from the specified device.

ERROR_REDIR_PAUSED

The specified printer or disk device has been paused.

ERROR_REDIRECTOR_HAS_OPEN_HANDLES

The redirector is in use and cannot be unloaded.

ERROR_REGISTRY_CORRUPT

The registry is damaged. The structure of one of the files that contains registry data is damaged, or the system's in memory image of the file is damaged, or the file could not be recovered because its alternate copy or log was absent or damaged.

ERROR_REGISTRY_IO_FAILED

The registry initiated an I/O operation that had an unrecoverable failure. The registry could not read in, or write out, or flush, one of the files that contain the system's image of the registry.

ERROR_REGISTRY_RECOVERED

One of the files containing the system's registry data had to be recovered by use of a log or alternate copy. The recovery succeeded.

ERROR_RELOC_CHAIN_XEEDS_SEGLIM

The operating system cannot run %1.

ERROR_REM_NOT_LIST

The remote computer is not available.

ERROR_REMOTE_SESSION_LIMIT_EXCEEDED

An attempt was made to establish a session to a LAN Manager server, but there are already too many sessions established to that server.

ERROR_REQ_NOT_ACCEP

The network request was not accepted.

ERROR_NOT_ENOUGH_QUOTA

Not enough quota is available to process this command.

ERROR_RESOURCE_DATA_NOT_FOUND

The specified image file did not contain a resource section.

ERROR_RESOURCE_LANG_NOT_FOUND

The specified resource language ID cannot be found in the image file.

ERROR_RESOURCE_NAME_NOT_FOUND

The specified resource name can not be found in the image file.

ERROR_RESOURCE_TYPE_NOT_FOUND

The specified resource type can not be found in the image file.

ERROR_REVISION_MISMATCH

Indicates two revision levels are incompatible.

ERROR_RING2_STACK_IN_USE

The ring 2 stack is in use.

ERROR_RING2SEG_MUST_BE_MOVABLE

The code segment cannot be greater than or equal to 64KB.

ERROR_RXACT_COMMIT_FAILURE

Indicates an error occurred during a registry transaction commit. The database has been left in an unknown state. The state of the registry transaction is left as COMMITTING. This status value is returned by the runtime library (RTL) registry transaction package (RXact).

ERROR_RXACT_INVALID_STATE

Indicates that the transaction state of a registry sub-tree is incompatible with the requested operation. For example, a request has been made to start a new transaction with one already in progress, or a request to apply a transaction when one is not currently in progress. This status value is returned by the runtime library (RTL) registry transaction package (RXact).

ERROR_SAME_DRIVE

The system cannot join or substitute a drive to or for a directory on the same drive.

ERROR_SCREEN_ALREADY_LOCKED

Screen already locked.

ERROR_SECRET_TOO_LONG

The length of a secret exceeds the maximum length allowed. The length and number of secrets is limited to satisfy the United States State Department export restrictions.

ERROR_SECTOR_NOT_FOUND

The drive cannot find the requested sector.

ERROR_SEEK

The drive cannot locate a specific area or track on the disk.

ERROR_SEEK_ON_DEVICE

The file pointer cannot be set on the specified device or file.

ERROR_SEM_IS_SET

The semaphore is set and cannot be closed.

ERROR_SEM_NOT_FOUND

The specified system semaphore name was not found.

ERROR_SEM_OWNER_DIED

The previous ownership of this semaphore has ended.

ERROR_SEM_TIMEOUT

The semaphore timeout period has expired.

ERROR_SEM_USER_LIMIT

Insert the disk for drive 1.

ERROR_SERIAL_NO_DEVICE

No serial device was successfully initialized. The serial driver will unload.

ERROR_SERVER_DISABLED

The GUID allocation server is already disabled at the moment.

ERROR_SERVER_HAS_OPEN_HANDLES

The server is in use and cannot be unloaded.

ERROR_SERVER_NOT_DISABLED

The GUID allocation server is already enabled at the moment.

ERROR_SERVICE_ALREADY_RUNNING

An instance of the service is already running.

ERROR_SERVICE_CANNOT_ACCEPT_CTRL

The service cannot accept control messages at this time.

ERROR_SERVICE_DATABASE_LOCKED

The service database is locked.

ERROR_SERVICE_DEPENDENCY_DELETED

The dependency service does not exist or has been marked for deletion.

ERROR_SERVICE_DEPENDENCY_FAIL

The dependency service or group failed to start.

ERROR_SERVICE_DISABLED

The specified service is disabled and cannot be started.

ERROR_SERVICE_DOES_NOT_EXIST

The specified service does not exist as an installed service.

ERROR_SERVICE_EXISTS

The specified service already exists.

ERROR_SERVICE_LOGON_FAILED

The service did not start due to a logon failure.

ERROR_SERVICE_MARKED_FOR_DELETE

The specified service has been marked for deletion.

ERROR_SERVICE_NEVER_STARTED

No attempts to start the service have been made since the last boot.

ERROR_SERVICE_NO_THREAD

A thread could not be created for the service.

ERROR_SERVICE_NOT_ACTIVE

The service has not been started.

ERROR_SERVICE_REQUEST_TIMEOUT

The service did not respond to the start or control request in a timely fashion.

ERROR_SERVICE_SPECIFIC_ERROR

The service has returned a service-specific error code.

ERROR_SERVICE_START_HANG

After starting, the service hung in a start-pending state.

ERROR_SESSION_CREDENTIAL_CONFLICT

The credentials supplied conflict with an existing set of credentials.

ERROR_SETCOUNT_ON_BAD_LB

LB_SETCOUNT sent to non-lazy list box.

ERROR_SETMARK_DETECTED

A tape access reached a setmark.

ERROR_SHARING_BUFFER_EXCEEDED

Too many files opened for sharing.

ERROR_SHARING_PAUSED

The remote server is paused or is in the process of being started.

ERROR_SHARING_VIOLATION

The process cannot access the file because it is being used by another process.

ERROR_SHUTDOWN_IN_PROGRESS

A system shutdown is in progress.

ERROR_SIGNAL_PENDING

A signal is already pending.

ERROR_SIGNAL_REFUSED

The recipient process has refused the signal.

ERROR_SOME_NOT_MAPPED

Some of the information to be mapped has not been translated.

ERROR_SPECIAL_ACCOUNT

Indicates an operation was attempted on a built-in (special) SAM account that is incompatible with built-in accounts. For example, built-in accounts cannot be renamed or deleted.

ERROR_SPECIAL_GROUP

The requested operation cannot be performed on the specified group because it is a built-in special group.

ERROR_SPECIAL_USER

The requested operation cannot be performed on the specified user because it is a built-in special user.

ERROR_STACK_OVERFLOW

Recursion too deep, stack overflowed.

ERROR_SUBST_TO_JOIN

The system attempted to SUBST a drive to a directory on a joined drive.

ERROR_SUBST_TO_SUBST

The system attempted to substitute a drive to a directory on a substituted drive.

ERROR_SUCCESS

The operation was successfully completed.

ERROR_SWAPERROR

Error accessing paging file.

ERROR_SYSTEM_TRACE

System trace information not specified in your CONFIG.SYS file, or tracing is not allowed.

ERROR_THREAD_1_INACTIVE

The signal handler cannot be set.

ERROR_TLW_WITH_WSCHILD

CreateWindow failed, creating top-level window with WS_CHILD style.

ERROR_TOKEN_ALREADY_IN_USE

An attempt was made to establish a token for use as a primary token but the token is already in use. A token can only be the primary token of one process at a time.

ERROR_TOO_MANY_CMDS

The network BIOS command limit has been reached.

ERROR_TOO_MANY_CONTEXT_IDS

During a logon attempt, the user's security context accumulated too many security IDs. Remove the user from some groups or aliases to reduce the number of security ids to incorporate into the security context.

ERROR_TOO_MANY_LUIDS_REQUESTED

The number of LUID requested cannot be allocated with a single allocation.

ERROR_TOO_MANY_MODULES

Too many dynamic link modules are attached to this program or dynamic link module.

ERROR_TOO_MANY_MUXWAITERS

Too many semaphores are already set.

ERROR_TOO_MANY_NAMES

The name limit for the local computer network adapter card exceeded.

ERROR_TOO_MANY_OPEN_FILES

The system cannot open the file.

ERROR_TOO_MANY_POSTS

Too many posts made to a semaphore.

ERROR_TOO_MANY_SECRETS

The maximum number of secrets that can be stored in a single system was exceeded. The length and number of secrets is limited to satisfy the United States State Department export restrictions.

ERROR_TOO_MANY_SEM_REQUESTS

The semaphore cannot be set again.

ERROR_TOO_MANY_SEMAPHORES

Cannot create another system semaphore.

ERROR_TOO_MANY_SESS

The network BIOS session limit exceeded.

ERROR_TOO_MANY_SIDS

Too many SIDs specified.

ERROR_TOO_MANY_TCBS

Cannot create another thread.

ERROR_TRUST_FAILURE

The network logon failed.

ERROR_TRUSTED_DOMAIN_FAILURE

The trust relationship between the primary domain and the trusted domain failed.

ERROR_TRUSTED_RELATIONSHIP_FAILURE

The trust relationship between this workstation and the primary domain failed.

ERROR_UNABLE_TO_LOCK_MEDIA

Attempt to lock the eject media mechanism failed.

ERROR_UNABLE_TO_UNLOAD_MEDIA

Unload media failed.

ERROR_UNEXP_NET_ERR

An unexpected network error occurred.

ERROR_UNKNOWN_PORT

The specified port is unknown.

ERROR_UNKNOWN_PRINTPROCESSOR

The print processor is unknown.

ERROR_UNKNOWN_PRINTER_DRIVER

The printer driver is unknown.

ERROR_UNKNOWN_REVISION

Indicates an encountered or specified revision number is not one known by the service. The service may not be aware of a more recent revision.

ERROR_UNRECOGNIZED_MEDIA

The disk media is not recognized. It may not be formatted.

ERROR_UNRECOGNIZED_VOLUME

The volume does not contain a recognized file system. Make sure that all required file system drivers are loaded and the volume is not damaged.

ERROR_USER_EXISTS

The specified user already exists.

ERROR_VC_DISCONNECTED

The session was canceled.

ERROR_WAIT_NO_CHILDREN

There are no child processes to wait for.

ERROR_WINDOW_NOT_COMBOBOX

The window is not a combo box.

ERROR_WINDOW_NOT_DIALOG

The window is not a valid dialog window.

ERROR_WINDOW_OF_OTHER_THREAD

Invalid window, belongs to other thread.

ERROR_WRITE_FAULT

The system cannot write to the specified device.

ERROR_WRITE_PROTECT

The media is write protected.

ERROR_WRONG_DISK

The wrong disk is in the drive. Insert %2 (Volume Serial Number: %3) into drive %1.

ERROR_WRONG_PASSWORD

When trying to update a password, this return status indicates the value provided as the current password is incorrect.

LZERROR_BADINHANDLE

Invalid input handle.

LZERROR_BADOUTHANDLE

Invalid output handle.

LZERROR_BADVALUE

Input parameter out of acceptable range.

LZERROR_GLOBALLOC

Insufficient memory for LZFile structure.

LZERROR_GLOBLOCK

Bad global handle.

LZERROR_READ

Corrupt compressed file format.

LZERROR_WRITE

Out of space for output file.

LZERROR_UNKNOWNALG

Compression algorithm not recognized.

NO_ERROR

No error.

RPC_S_ADDRESS_ERROR

An addressing error occurred in the server.

RPC_S_ALREADY_LISTENING

The server is already listening.

RPC_S_ALREADY_REGISTERED

The object UUID already registered.

RPC_S_BINDING_HAS_NO_AUTH

The binding does not contain any authentication information.

RPC_S_CALL_FAILED

The remote procedure call failed.

RPC_S_CALL_FAILED_DNE

The remote procedure call failed and did not execute.

RPC_S_CALL_IN_PROGRESS

A remote procedure call is already in progress for this thread.

RPC_S_CANNOT_SUPPORT

The requested operation is not supported.

RPC_S_CANT_CREATE_ENDPOINT

The endpoint cannot be created.

RPC_S_DUPLICATE_ENDPOINT

The endpoint is a duplicate.

RPC_S_ENTRY_ALREADY_EXISTS

The entry already exists.

RPC_S_ENTRY_NOT_FOUND

The entry is not found.

RPC_S_FP_DIV_ZERO

A floating point operation at the server caused a divide by zero.

RPC_S_FP_OVERFLOW

A floating point overflow occurred at the server.

RPC_S_FP_UNDERFLOW

A floating point underflow occurred at the server.

RPC_S_GROUP_MEMBER_NOT_FOUND

The group member was not found.

RPC_S_INCOMPLETE_NAME

The entry name is incomplete.

RPC_S_INTERFACE_NOT_FOUND

The interface was not found.

RPC_S_INTERNAL_ERROR

An internal error occurred in RPC.

RPC_S_INVALID_AUTH_IDENTITY

The security context is invalid.

RPC_S_INVALID_BINDING

The binding handle is invalid.

RPC_S_INVALID_BOUND

The array bounds are invalid.

RPC_S_INVALID_ENDPOINT_FORMAT

The endpoint format is invalid.

RPC_S_INVALID_NAME_SYNTAX

The name syntax is invalid.

RPC_S_INVALID_NET_ADDR

The network address is invalid.

RPC_S_INVALID_NETWORK_OPTIONS

The network options are invalid.

RPC_S_INVALID_OBJECT

The object universal unique identifier (UUID) is the nil UUID.

RPC_S_INVALID_RPC_PROTSEQ

The RPC protocol sequence is invalid.

RPC_S_INVALID_STRING_BINDING

The string binding is invalid.

RPC_S_INVALID_STRING_UUID

The string UUID is invalid.

RPC_S_INVALID_TAG

The tag is invalid.

RPC_S_INVALID_TIMEOUT

The timeout value is invalid.

RPC_S_INVALID_VERS_OPTION

The version option is invalid.

RPC_S_MAX_CALLS_TOO_SMALL

The maximum number of calls is too small.

RPC_S_NAME_SERVICE_UNAVAILABLE

The name service is unavailable.

RPC_S_NO_BINDINGS

There are no bindings.

RPC_S_NO_CALL_ACTIVE

There is not a remote procedure call active in this thread.

RPC_S_NO_CONTEXT_AVAILABLE

No security context is available to allow impersonation.

RPC_S_NO_ENDPOINT_FOUND

No endpoint was found.

RPC_S_NO_ENTRY_NAME

The binding does not contain an entry name.

RPC_S_NO_MORE_BINDINGS

There are no more bindings.

RPC_S_NO_MORE_MEMBERS

There are no more members.

RPC_S_NO_PROTSEQS

There are no protocol sequences.

RPC_S_NO_PROTSEQS_REGISTERED

No protocol sequences were registered.

RPC_S_NOT_LISTENING

The server is not listening.

RPC_S_OBJECT_NOT_FOUND

The object UUID was not found.

RPC_S_OUT_OF_RESOURCES

Not enough resources are available to complete this operation.

RPC_S_PROCNUM_OUT_OF_RANGE

The procedure number is out of range.

RPC_S_PROTOCOL_ERROR

An RPC protocol error occurred.

RPC_S_PROTSEQ_NOT_FOUND

The RPC protocol sequence was not found.

RPC_S_PROTSEQ_NOT_SUPPORTED

The RPC protocol sequence is not supported.

RPC_S_SERVER_OUT_OF_MEMORY

The server has insufficient memory to complete this operation.

RPC_S_SERVER_TOO_BUSY

The server is too busy to complete this operation.

RPC_S_SERVER_UNAVAILABLE

The server is unavailable.

RPC_S_STRING_TOO_LONG

The string is too long.

RPC_S_TYPE_ALREADY_REGISTERED

The type UUID is already registered.

RPC_S_UNKNOWN_AUTHN_LEVEL

The authentication level is unknown.

RPC_S_UNKNOWN_AUTHN_SERVICE

The authentication service is unknown.

RPC_S_UNKNOWN_AUTHN_TYPE

The authentication type is unknown.

RPC_S_UNKNOWN_AUTHZ_SERVICE

The authorization service is unknown.

RPC_S_UNKNOWN_IF

The interface is unknown.

RPC_S_UNKNOWN_MGR_TYPE

The manager type is unknown.

RPC_S_UNSUPPORTED_NAME_SYNTAX

The name syntax is not supported.

RPC_S_UNSUPPORTED_TRANS_SYN

The transfer syntax is not supported by the server.

RPC_S_UNSUPPORTED_TYPE

The type UUID is not supported.

RPC_S_UUID_NO_ADDRESS

No network address is available to use to construct a UUID.

RPC_S_WRONG_KIND_OF_BINDING

The binding handle is the incorrect type.

RPC_S_ZERO_DIVIDE

The server attempted an integer divide by zero.

RPC_X_BAD_STUB_DATA

The stub received bad data.

RPC_X_BYTE_COUNT_TOO_SMALL

The byte count is too small.

RPC_X_ENUM_VALUE_OUT_OF_RANGE

The enumeration value is out of range.

RPC_X_NO_MORE_ENTRIES

The list of servers available for auto_handle binding was exhausted.

RPC_X_NULL_REF_POINTER

A null reference pointer was passed to the stub.

RPC_X_SS_CANNOT_GET_CALL_HANDLE

The stub is unable to get the call handle.

RPC_X_SS_CHAR_TRANS_OPEN_FAIL

The file designated by DCERPCCHARTRANS cannot be opened.

RPC_X_SS_CHAR_TRANS_SHORT_FILE

The file containing the character translation table has fewer than 512 bytes.

RPC_X_SS_CONTEXT_DAMAGED

The context handle changed during a call.

RPC_X_SS_CONTEXT_MISMATCH

The context handle does not match any known context handles.

RPC_X_SS_HANDLES_MISMATCH

The binding handles passed to a remote procedure call do not match.

RPC_X_SS_IN_NULL_CONTEXT

A null context handle is passed as an [in] parameter.


Numerical List of Error Codes

-8        LZERROR_UNKNOWNALG

-7        LZERROR_BADVALUE

-6        LZERROR_GLOBLOCK

-5        LZERROR_GLOBALLOC

-4        LZERROR_WRITE

-3        LZERROR_READ

-2        LZERROR_BADOUTHANDLE

-1        LZERROR_BADINHANDLE

0L        NO_ERROR

0L        ERROR_SUCCESS

1L        ERROR_INVALID_FUNCTION

2L        ERROR_FILE_NOT_FOUND

3L        ERROR_PATH_NOT_FOUND

4L        ERROR_TOO_MANY_OPEN_FILES

5L        ERROR_ACCESS_DENIED

6L        ERROR_INVALID_HANDLE

7L        ERROR_ARENA_TRASHED

8L        ERROR_NOT_ENOUGH_MEMORY

9L        ERROR_INVALID_BLOCK

10L       ROR_BAD_ENVIRONMENT

11L       ROR_BAD_FORMAT

12L       ROR_INVALID_ACCESS

13L       ROR_INVALID_DATA

14L       ROR_OUTOFMEMORY

15L       ROR_INVALID_DRIVE

16L       ROR_CURRENT_DIRECTORY

17L       ROR_NOT_SAME_DEVICE

18L       ROR_NO_MORE_FILES

19L       ROR_WRITE_PROTECT

20L       ROR_BAD_UNIT

21L       ROR_NOT_READY

22L       ROR_BAD_COMMAND

23L       ROR_CRC

24L       ROR_BAD_LENGTH

25L       ROR_SEEK

26L       ROR_NOT_DOS_DISK

27L       ROR_SECTOR_NOT_FOUND

28L       ROR_OUT_OF_PAPER

29L       ROR_WRITE_FAULT

30L       ROR_READ_FAULT

31L       ROR_GEN_FAILURE

32L       ROR_SHARING_VIOLATION

33L       ROR_LOCK_VIOLATION

34L       ROR_WRONG_DISK

36L       ROR_SHARING_BUFFER_EXCEEDED

38L       ROR_HANDLE_EOF

39L       ROR_HANDLE_DISK_FULL

50L       ROR_NOT_SUPPORTED

51L       ROR_REM_NOT_LIST

52L       ROR_DUP_NAME

53L       ROR_BAD_NETPATH

54L       ROR_NETWORK_BUSY

55L       ROR_DEV_NOT_EXIST

56L       ROR_TOO_MANY_CMDS

57L       ROR_ADAP_HDW_ERR

58L       ROR_BAD_NET_RESP

59L       ROR_UNEXP_NET_ERR

60L       ROR_BAD_REM_ADAP

61L       ROR_PRINTQ_FULL

62L       ROR_NO_SPOOL_SPACE

63L       ROR_PRINT_CANCELLED

64L       ROR_NETNAME_DELETED

65L       ROR_NETWORK_ACCESS_DENIED

66L       ROR_BAD_DEV_TYPE

67L       ROR_BAD_NET_NAME

68L       ROR_TOO_MANY_NAMES

69L       ROR_TOO_MANY_SESS

70L       ROR_SHARING_PAUSED

71L       ROR_REQ_NOT_ACCEP

72L       ROR_REDIR_PAUSED

80L       ROR_FILE_EXISTS

82L       ROR_CANNOT_MAKE

83L       ROR_FAIL_I24

84L       ROR_OUT_OF_STRUCTURES

85L       ROR_ALREADY_ASSIGNED

86L       ROR_INVALID_PASSWORD

87L       ROR_INVALID_PARAMETER

88L       ROR_NET_WRITE_FAULT

89L       ROR_NO_PROC_SLOTS

100L      RROR_TOO_MANY_SEMAPHORES

101L      RROR_EXCL_SEM_ALREADY_OWNED

102L      RROR_SEM_IS_SET

103L      RROR_TOO_MANY_SEM_REQUESTS

104L      RROR_INVALID_AT_INTERRUPT_TIME

105L      RROR_SEM_OWNER_DIED

106L      RROR_SEM_USER_LIMIT

107L      RROR_DISK_CHANGE

108L      RROR_DRIVE_LOCKED

109L      RROR_BROKEN_PIPE

110L      RROR_OPEN_FAILED

111L      RROR_BUFFER_OVERFLOW

112L      RROR_DISK_FULL

113L      RROR_NO_MORE_SEARCH_HANDLES

114L      RROR_INVALID_TARGET_HANDLE

117L      RROR_INVALID_CATEGORY

118L      RROR_INVALID_VERIFY_SWITCH

119L      RROR_BAD_DRIVER_LEVEL

120L      RROR_CALL_NOT_IMPLEMENTED

121L      RROR_SEM_TIMEOUT

122L      RROR_INSUFFICIENT_BUFFER

123L      RROR_INVALID_NAME

124L      RROR_INVALID_LEVEL

125L      RROR_NO_VOLUME_LABEL

126L      RROR_MOD_NOT_FOUND

127L      RROR_PROC_NOT_FOUND

128L      RROR_WAIT_NO_CHILDREN

129L      RROR_CHILD_NOT_COMPLETE

130L      RROR_DIRECT_ACCESS_HANDLE

131L      RROR_NEGATIVE_SEEK

132L      RROR_SEEK_ON_DEVICE

133L      RROR_IS_JOIN_TARGET

134L      RROR_IS_JOINED

135L      RROR_IS_SUBSTED

136L      RROR_NOT_JOINED

137L      RROR_NOT_SUBSTED

138L      RROR_JOIN_TO_JOIN

139L      RROR_SUBST_TO_SUBST

140L      RROR_JOIN_TO_SUBST

141L      RROR_SUBST_TO_JOIN

142L      RROR_BUSY_DRIVE

143L      RROR_SAME_DRIVE

144L      RROR_DIR_NOT_ROOT

145L      RROR_DIR_NOT_EMPTY

146L      RROR_IS_SUBST_PATH

147L      RROR_IS_JOIN_PATH

148L      RROR_PATH_BUSY

149L      RROR_IS_SUBST_TARGET

150L      RROR_SYSTEM_TRACE

151L      RROR_INVALID_EVENT_COUNT

152L      RROR_TOO_MANY_MUXWAITERS

153L      RROR_INVALID_LIST_FORMAT

154L      RROR_LABEL_TOO_LONG

155L      RROR_TOO_MANY_TCBS

156L      RROR_SIGNAL_REFUSED

157L      RROR_DISCARDED

158L      RROR_NOT_LOCKED

159L      RROR_BAD_THREADID_ADDR

160L      RROR_BAD_ARGUMENTS

161L      RROR_BAD_PATHNAME

162L      RROR_SIGNAL_PENDING

164L      RROR_MAX_THRDS_REACHED

167L      RROR_LOCK_FAILED

170L      RROR_BUSY

173L      RROR_CANCEL_VIOLATION

174L      RROR_ATOMIC_LOCKS_NOT_SUPPORTED

180L      RROR_INVALID_SEGMENT_NUMBER

182L      RROR_INVALID_ORDINAL

183L      RROR_ALREADY_EXISTS

186L      RROR_INVALID_FLAG_NUMBER

187L      RROR_SEM_NOT_FOUND

188L      RROR_INVALID_STARTING_CODESEG

189L      RROR_INVALID_STACKSEG

190L      RROR_INVALID_MODULETYPE

191L      RROR_INVALID_EXE_SIGNATURE

192L      RROR_EXE_MARKED_INVALID

193L      RROR_BAD_EXE_FORMAT

194L      RROR_ITERATED_DATA_EXCEEDS_64k

195L      RROR_INVALID_MINALLOCSIZE

196L      RROR_DYNLINK_FROM_INVALID_RING

197L      RROR_IOPL_NOT_ENABLED

198L      RROR_INVALID_SEGDPL

199L      RROR_AUTODATASEG_EXCEEDS_64k

200L      RROR_RING2SEG_MUST_BE_MOVABLE

201L      RROR_RELOC_CHAIN_XEEDS_SEGLIM

202L      RROR_INFLOOP_IN_RELOC_CHAIN

203L      RROR_ENVVAR_NOT_FOUND

205L      RROR_NO_SIGNAL_SENT

206L      RROR_FILENAME_EXCED_RANGE

207L      RROR_RING2_STACK_IN_USE

208L      RROR_META_EXPANSION_TOO_LONG

209L      RROR_INVALID_SIGNAL_NUMBER

210L      RROR_THREAD_1_INACTIVE

212L      RROR_LOCKED

214L      RROR_TOO_MANY_MODULES

215L      RROR_NESTING_NOT_ALLOWED

230L      RROR_BAD_PIPE

231L      RROR_PIPE_BUSY

232L      RROR_NO_DATA

233L      RROR_PIPE_NOT_CONNECTED

234L      RROR_MORE_DATA

240L      RROR_VC_DISCONNECTED

254L      RROR_INVALID_EA_NAME

255L      RROR_EA_LIST_INCONSISTENT

259L      RROR_NO_MORE_ITEMS

266L      RROR_CANNOT_COPY

267L      RROR_DIRECTORY

275L      RROR_EAS_DIDNT_FIT

276L      RROR_EA_FILE_CORRUPT

277L      RROR_EA_TABLE_FULL

278L      RROR_INVALID_EA_HANDLE

282L      RROR_EAS_NOT_SUPPORTED

288L      RROR_NOT_OWNER

298L      RROR_TOO_MANY_POSTS

317L      RROR_MR_MID_NOT_FOUND

487L      RROR_INVALID_ADDRESS

534L      RROR_ARITHMETIC_OVERFLOW

535L      RROR_PIPE_CONNECTED

536L      RROR_PIPE_LISTENING

994L      RROR_EA_ACCESS_DENIED

995L      RROR_OPERATION_ABORTED

996L      RROR_IO_INCOMPLETE

997L      RROR_IO_PENDING

998L      RROR_NOACCESS

999L      RROR_SWAPERROR

1001L     ERROR_STACK_OVERFLOW

1002L     ERROR_INVALID_MESSAGE

1003L     ERROR_CAN_NOT_COMPLETE

1004L     ERROR_INVALID_FLAGS

1005L     ERROR_UNRECOGNIZED_VOLUME

1006L     ERROR_FILE_INVALID

1007L     ERROR_FULLSCREEN_MODE

1008L     ERROR_NO_TOKEN

1009L     ERROR_BADDB

1010L     ERROR_BADKEY

1011L     ERROR_CANTOPEN

1012L     ERROR_CANTREAD

1013L     ERROR_CANTWRITE

1014L     ERROR_REGISTRY_RECOVERED

1015L     ERROR_REGISTRY_CORRUPT

1016L     ERROR_REGISTRY_IO_FAILED

1017L     ERROR_NOT_REGISTRY_FILE

1018L     ERROR_KEY_DELETED

1019L     ERROR_NO_LOG_SPACE

1020L     ERROR_KEY_HAS_CHILDREN

1021L     ERROR_CHILD_MUST_BE_VOLATILE

1022L     ERROR_NOTIFY_ENUM_DIR

1051L     ERROR_DEPENDENT_SERVICES_RUNNING

1052L     ERROR_INVALID_SERVICE_CONTROL

1053L     ERROR_SERVICE_REQUEST_TIMEOUT

1054L     ERROR_SERVICE_NO_THREAD

1055L     ERROR_SERVICE_DATABASE_LOCKED

1056L     ERROR_SERVICE_ALREADY_RUNNING

1057L     ERROR_INVALID_SERVICE_ACCOUNT

1058L     ERROR_SERVICE_DISABLED

1059L     ERROR_CIRCULAR_DEPENDENCY

1060L     ERROR_SERVICE_DOES_NOT_EXIST

1061L     ERROR_SERVICE_CANNOT_ACCEPT_CTRL

1062L     ERROR_SERVICE_NOT_ACTIVE

1063L     ERROR_FAILED_SERVICE_CONTROLLER_CONNECT

1064L     ERROR_EXCEPTION_IN_SERVICE

1065L     ERROR_DATABASE_DOES_NOT_EXIST

1066L     ERROR_SERVICE_SPECIFIC_ERROR

1067L     ERROR_PROCESS_ABORTED

1068L     ERROR_SERVICE_DEPENDENCY_FAIL

1069L     ERROR_SERVICE_LOGON_FAILED

1070L     ERROR_SERVICE_START_HANG

1071L     ERROR_INVALID_SERVICE_LOCK

1072L     ERROR_SERVICE_MARKED_FOR_DELETE

1073L     ERROR_SERVICE_EXISTS

1074L     ERROR_ALREADY_RUNNING_LKG

1075L     ERROR_SERVICE_DEPENDENCY_DELETED

1076L     ERROR_BOOT_ALREADY_ACCEPTED

1077L     ERROR_SERVICE_NEVER_STARTED

1078L     ERROR_DUPLICATE_SERVICE_NAME

1100L     ERROR_END_OF_MEDIA

1101L     ERROR_FILEMARK_DETECTED

1102L     ERROR_BEGINNING_OF_MEDIA

1103L     ERROR_SETMARK_DETECTED

1104L     ERROR_NO_DATA_DETECTED

1105L     ERROR_PARTITION_FAILURE

1106L     ERROR_INVALID_BLOCK_LENGTH

1107L     ERROR_DEVICE_NOT_PARTITIONED

1108L     ERROR_UNABLE_TO_LOCK_MEDIA

1109L     ERROR_UNABLE_TO_UNLOAD_MEDIA

1110L     ERROR_MEDIA_CHANGED

1111L     ERROR_BUS_RESET

1112L     ERROR_NO_MEDIA_IN_DRIVE

1113L     ERROR_NO_UNICODE_TRANSLATION

1114L     ERROR_DLL_INIT_FAILED

1115L     ERROR_SHUTDOWN_IN_PROGRESS

1116L     ERROR_NO_SHUTDOWN_IN_PROGRESS

1117L     ERROR_IO_DEVICE

1118L     ERROR_SERIAL_NO_DEVICE

1119L     ERROR_IRQ_BUSY

1120L     ERROR_MORE_WRITES

1121L     ERROR_COUNTER_TIMEOUT

1122L     ERROR_FLOPPY_ID_MARK_NOT_FOUND

1123L     ERROR_FLOPPY_WRONG_CYLINDER

1124L     ERROR_FLOPPY_UNKNOWN_ERROR

1125L     ERROR_FLOPPY_BAD_REGISTERS

1126L     ERROR_DISK_RECALIBRATE_FAILED

1127L     ERROR_DISK_OPERATION_FAILED

1128L     ERROR_DISK_RESET_FAILED

1129L     ERROR_EOM_OVERFLOW

1130L     ERROR_NOT_ENOUGH_SERVER_MEMORY

1131L     ERROR_POSSIBLE_DEADLOCK

1200L     ERROR_BAD_DEVICE

1201L     ERROR_CONNECTION_UNAVAIL

1202L     ERROR_DEVICE_ALREADY_REMEMBERED

1203L     ERROR_NO_NET_OR_BAD_PATH

1204L     ERROR_BAD_PROVIDER

1205L     ERROR_CANNOT_OPEN_PROFILE

1206L     ERROR_BAD_PROFILE

1207L     ERROR_NOT_CONTAINER

1208L     ERROR_EXTENDED_ERROR

1209L     ERROR_INVALID_GROUPNAME

1210L     ERROR_INVALID_COMPUTERNAME

1211L     ERROR_INVALID_EVENTNAME

1212L     ERROR_INVALID_DOMAINNAME

1213L     ERROR_INVALID_SERVICENAME

1214L     ERROR_INVALID_NETNAME

1215L     ERROR_INVALID_SHARENAME

1216L     ERROR_INVALID_PASSWORDNAME

1217L     ERROR_INVALID_MESSAGENAME

1218L     ERROR_INVALID_MESSAGEDEST

1219L     ERROR_SESSION_CREDENTIAL_CONFLICT

1220L     ERROR_REMOTE_SESSION_LIMIT_EXCEEDED

1221L     ERROR_DUP_DOMAINNAME

1300L     ERROR_NOT_ALL_ASSIGNED

1301L     ERROR_SOME_NOT_MAPPED

1302L     ERROR_NO_QUOTAS_FOR_ACCOUNT

1303L     ERROR_LOCAL_USER_SESSION_KEY

1304L     ERROR_NULL_LM_PASSWORD

1305L     ERROR_UNKNOWN_REVISION

1306L     ERROR_REVISION_MISMATCH

1307L     ERROR_INVALID_OWNER

1308L     ERROR_INVALID_PRIMARY_GROUP

1309L     ERROR_NO_IMPERSONATION_TOKEN

1310L     ERROR_CANT_DISABLE_MANDATORY

1311L     ERROR_NO_LOGON_SERVERS

1312L     ERROR_NO_SUCH_LOGON_SESSION

1313L     ERROR_NO_SUCH_PRIVILEGE

1314L     ERROR_PRIVILEGE_NOT_HELD

1315L     ERROR_INVALID_ACCOUNT_NAME

1316L     ERROR_USER_EXISTS

1317L     ERROR_NO_SUCH_USER

1318L     ERROR_GROUP_EXISTS

1319L     ERROR_NO_SUCH_GROUP

1320L     ERROR_MEMBER_IN_GROUP

1321L     ERROR_MEMBER_NOT_IN_GROUP

1322L     ERROR_LAST_ADMIN

1323L     ERROR_WRONG_PASSWORD

1324L     ERROR_ILL_FORMED_PASSWORD

1325L     ERROR_PASSWORD_RESTRICTION

1326L     ERROR_LOGON_FAILURE

1327L     ERROR_ACCOUNT_RESTRICTION

1328L     ERROR_INVALID_LOGON_HOURS

1329L     ERROR_INVALID_WORKSTATION

1330L     ERROR_PASSWORD_EXPIRED

1331L     ERROR_ACCOUNT_DISABLED

1332L     ERROR_NONE_MAPPED

1333L     ERROR_TOO_MANY_LUIDS_REQUESTED

1334L     ERROR_LUIDS_EXHAUSTED

1335L     ERROR_INVALID_SUB_AUTHORITY

1336L     ERROR_INVALID_ACL

1337L     ERROR_INVALID_SID

1338L     ERROR_INVALID_SECURITY_DESCR

1340L     ERROR_BAD_INHERITANCE_ACL

1341L     ERROR_SERVER_DISABLED

1342L     ERROR_SERVER_NOT_DISABLED

1343L     ERROR_INVALID_ID_AUTHORITY

1344L     ERROR_ALLOTTED_SPACE_EXCEEDED

1345L     ERROR_INVALID_GROUP_ATTRIBUTES

1346L     ERROR_BAD_IMPERSONATION_LEVEL

1347L     ERROR_CANT_OPEN_ANONYMOUS

1348L     ERROR_BAD_VALIDATION_CLASS

1349L     ERROR_BAD_TOKEN_TYPE

1350L     ERROR_NO_SECURITY_ON_OBJECT

1351L     ERROR_CANT_ACCESS_DOMAIN_INFO

1352L     ERROR_INVALID_SERVER_STATE

1353L     ERROR_INVALID_DOMAIN_STATE

1354L     ERROR_INVALID_DOMAIN_ROLE

1355L     ERROR_NO_SUCH_DOMAIN

1356L     ERROR_DOMAIN_EXISTS

1357L     ERROR_DOMAIN_LIMIT_EXCEEDED

1358L     ERROR_INTERNAL_DB_CORRUPTION

1359L     ERROR_INTERNAL_ERROR

1360L     ERROR_GENERIC_NOT_MAPPED

1361L     ERROR_BAD_DESCRIPTOR_FORMAT

1362L     ERROR_NOT_LOGON_PROCESS

1363L     ERROR_LOGON_SESSION_EXISTS

1364L     ERROR_NO_SUCH_PACKAGE

1365L     ERROR_BAD_LOGON_SESSION_STATE

1366L     ERROR_LOGON_SESSION_COLLISION

1367L     ERROR_INVALID_LOGON_TYPE

1368L     ERROR_CANNOT_IMPERSONATE

1369L     ERROR_RXACT_INVALID_STATE

1370L     ERROR_RXACT_COMMIT_FAILURE

1371L     ERROR_SPECIAL_ACCOUNT

1372L     ERROR_SPECIAL_GROUP

1373L     ERROR_SPECIAL_USER

1374L     ERROR_MEMBERS_PRIMARY_GROUP

1375L     ERROR_TOKEN_ALREADY_IN_USE

1376L     ERROR_NO_SUCH_ALIAS

1377L     ERROR_MEMBER_NOT_IN_ALIAS

1378L     ERROR_MEMBER_IN_ALIAS

1379L     ERROR_ALIAS_EXISTS

1380L     ERROR_LOGON_NOT_GRANTED

1381L     ERROR_TOO_MANY_SECRETS

1382L     ERROR_SECRET_TOO_LONG

1383L     ERROR_INTERNAL_DB_ERROR

1384L     ERROR_TOO_MANY_CONTEXT_IDS

1385L     ERROR_LOGON_TYPE_NOT_GRANTED

1386L     ERROR_NT_CROSS_ENCRYPTION_REQUIRED

1387L     ERROR_NO_SUCH_MEMBER

1388L     ERROR_INVALID_MEMBER

1389L     ERROR_TOO_MANY_SIDS

1390L     ERROR_LM_CROSS_ENCRYPTION_REQUIRED

1391L     ERROR_NO_INHERITANCE

1392L     ERROR_FILE_CORRUPT

1393L     ERROR_DISK_CORRUPT

1394L     ERROR_NO_USER_SESSION_KEY

1400L     ERROR_INVALID_WINDOW_HANDLE

1401L     ERROR_INVALID_MENU_HANDLE

1402L     ERROR_INVALID_CURSOR_HANDLE

1403L     ERROR_INVALID_ACCEL_HANDLE

1404L     ERROR_INVALID_HOOK_HANDLE

1405L     ERROR_INVALID_DWP_HANDLE

1406L     ERROR_TLW_WITH_WSCHILD

1407L     ERROR_CANNOT_FIND_WND_CLASS

1408L     ERROR_WINDOW_OF_OTHER_THREAD

1409L     ERROR_HOTKEY_ALREADY_REGISTERED

1410L     ERROR_CLASS_ALREADY_EXISTS

1411L     ERROR_CLASS_DOES_NOT_EXIST

1412L     ERROR_CLASS_HAS_WINDOWS

1413L     ERROR_INVALID_INDEX

1414L     ERROR_INVALID_ICON_HANDLE

1415L     ERROR_PRIVATE_DIALOG_INDEX

1416L     ERROR_LISTBOX_ID_NOT_FOUND

1417L     ERROR_NO_WILDCARD_CHARACTERS

1418L     ERROR_CLIPBOARD_NOT_OPEN

1419L     ERROR_HOTKEY_NOT_REGISTERED

1420L     ERROR_WINDOW_NOT_DIALOG

1421L     ERROR_CONTROL_ID_NOT_FOUND

1422L     ERROR_INVALID_COMBOBOX_MESSAGE

1423L     ERROR_WINDOW_NOT_COMBOBOX

1424L     ERROR_INVALID_EDIT_HEIGHT

1425L     ERROR_DC_NOT_FOUND

1426L     ERROR_INVALID_HOOK_FILTER

1427L     ERROR_INVALID_FILTER_PROC

1428L     ERROR_HOOK_NEEDS_HMOD

1429L     ERROR_GLOBAL_ONLY_HOOK

1430L     ERROR_JOURNAL_HOOK_SET

1431L     ERROR_HOOK_NOT_INSTALLED

1432L     ERROR_INVALID_LB_MESSAGE

1433L     ERROR_SETCOUNT_ON_BAD_LB

1434L     ERROR_LB_WITHOUT_TABSTOPS

1435L     ERROR_DESTROY_OBJECT_OF_OTHER_THREAD

1436L     ERROR_CHILD_WINDOW_MENU

1437L     ERROR_NO_SYSTEM_MENU

1438L     ERROR_INVALID_MSGBOX_STYLE

1439L     ERROR_INVALID_SPI_VALUE

1440L     ERROR_SCREEN_ALREADY_LOCKED

1441L     ERROR_HWNDS_HAVE_DIFFERENT_PARENT

1442L     ERROR_NOT_CHILD_WINDOW

1443L     ERROR_INVALID_GW_COMMAND

1444L     ERROR_INVALID_THREAD_ID

1445L     ERROR_NON_MDICHILD_WINDOW

1446L     ERROR_POPUP_ALREADY_ACTIVE

1447L     ERROR_NO_SCROLLBARS

1448L     ERROR_INVALID_SCROLLBAR_RANGE

1449L     ERROR_INVALID_SHOWWIN_COMMAND

1500L     ERROR_EVENTLOG_FILE_CORRUPT

1501L     ERROR_EVENTLOG_CANT_START

1502L     ERROR_LOG_FILE_FULL

1503L     ERROR_EVENTLOG_FILE_CHANGED

1700L     RPC_S_INVALID_STRING_BINDING

1701L     RPC_S_WRONG_KIND_OF_BINDING

1702L     RPC_S_INVALID_BINDING

1703L     RPC_S_PROTSEQ_NOT_SUPPORTED

1704L     RPC_S_INVALID_RPC_PROTSEQ

1705L     RPC_S_INVALID_STRING_UUID

1706L     RPC_S_INVALID_ENDPOINT_FORMAT

1707L     RPC_S_INVALID_NET_ADDR

1708L     RPC_S_NO_ENDPOINT_FOUND

1709L     RPC_S_INVALID_TIMEOUT

1710L     RPC_S_OBJECT_NOT_FOUND

1711L     RPC_S_ALREADY_REGISTERED

1712L     RPC_S_TYPE_ALREADY_REGISTERED

1713L     RPC_S_ALREADY_LISTENING

1714L     RPC_S_NO_PROTSEQS_REGISTERED

1715L     RPC_S_NOT_LISTENING

1716L     RPC_S_UNKNOWN_MGR_TYPE

1717L     RPC_S_UNKNOWN_IF

1718L     RPC_S_NO_BINDINGS

1719L     RPC_S_NO_PROTSEQS

1720L     RPC_S_CANT_CREATE_ENDPOINT

1721L     RPC_S_OUT_OF_RESOURCES

1722L     RPC_S_SERVER_UNAVAILABLE

1723L     RPC_S_SERVER_TOO_BUSY

1724L     RPC_S_INVALID_NETWORK_OPTIONS

1725L     RPC_S_NO_CALL_ACTIVE

1726L     RPC_S_CALL_FAILED

1727L     RPC_S_CALL_FAILED_DNE

1728L     RPC_S_PROTOCOL_ERROR

1730L     RPC_S_UNSUPPORTED_TRANS_SYN

1731L     RPC_S_SERVER_OUT_OF_MEMORY

1732L     RPC_S_UNSUPPORTED_TYPE

1733L     RPC_S_INVALID_TAG

1734L     RPC_S_INVALID_BOUND

1735L     RPC_S_NO_ENTRY_NAME

1736L     RPC_S_INVALID_NAME_SYNTAX

1737L     RPC_S_UNSUPPORTED_NAME_SYNTAX

1739L     RPC_S_UUID_NO_ADDRESS

1740L     RPC_S_DUPLICATE_ENDPOINT

1741L     RPC_S_UNKNOWN_AUTHN_TYPE

1742L     RPC_S_MAX_CALLS_TOO_SMALL

1743L     RPC_S_STRING_TOO_LONG

1744L     RPC_S_PROTSEQ_NOT_FOUND

1745L     RPC_S_PROCNUM_OUT_OF_RANGE

1746L     RPC_S_BINDING_HAS_NO_AUTH

1747L     RPC_S_UNKNOWN_AUTHN_SERVICE

1748L     RPC_S_UNKNOWN_AUTHN_LEVEL

1749L     RPC_S_INVALID_AUTH_IDENTITY

1750L     RPC_S_UNKNOWN_AUTHZ_SERVICE

1751L     EPT_S_INVALID_ENTRY

1752L     EPT_S_CANT_PERFORM_OP

1753L     EPT_S_NOT_REGISTERED

1755L     RPC_S_INCOMPLETE_NAME

1756L     RPC_S_INVALID_VERS_OPTION

1757L     RPC_S_NO_MORE_MEMBERS

1759L     RPC_S_INTERFACE_NOT_FOUND

1760L     RPC_S_ENTRY_ALREADY_EXISTS

1761L     RPC_S_ENTRY_NOT_FOUND

1762L     RPC_S_NAME_SERVICE_UNAVAILABLE

1764L     RPC_S_CANNOT_SUPPORT

1765L     RPC_S_NO_CONTEXT_AVAILABLE

1766L     RPC_S_INTERNAL_ERROR

1767L     RPC_S_ZERO_DIVIDE

1768L     RPC_S_ADDRESS_ERROR

1769L     RPC_S_FP_DIV_ZERO

1770L     RPC_S_FP_UNDERFLOW

1771L     RPC_S_FP_OVERFLOW

1772L     RPC_X_NO_MORE_ENTRIES

1773L     RPC_X_SS_CHAR_TRANS_OPEN_FAIL

1774L     RPC_X_SS_CHAR_TRANS_SHORT_FILE

1775L     RPC_X_SS_IN_NULL_CONTEXT

1776L     RPC_X_SS_CONTEXT_MISMATCH

1777L     RPC_X_SS_CONTEXT_DAMAGED

1778L     RPC_X_SS_HANDLES_MISMATCH

1779L     RPC_X_SS_CANNOT_GET_CALL_HANDLE

1780L     RPC_X_NULL_REF_POINTER

1781L     RPC_X_ENUM_VALUE_OUT_OF_RANGE

1782L     RPC_X_BYTE_COUNT_TOO_SMALL

1783L     RPC_X_BAD_STUB_DATA

1784L     ERROR_INVALID_USER_BUFFER

1785L     ERROR_UNRECOGNIZED_MEDIA

1786L     ERROR_NO_TRUST_LSA_SECRET

1787L     ERROR_NO_TRUST_SAM_ACCOUNT

1788L     ERROR_TRUSTED_DOMAIN_FAILURE

1789L     ERROR_TRUSTED_RELATIONSHIP_FAILURE

1790L     ERROR_TRUST_FAILURE

1791L     RPC_S_CALL_IN_PROGRESS

1792L     ERROR_NETLOGON_NOT_STARTED

1793L     ERROR_ACCOUNT_EXPIRED

1794L     ERROR_REDIRECTOR_HAS_OPEN_HANDLES

1795L     ERROR_PRINTER_DRIVER_ALREADY_INSTALLED

1796L     ERROR_UNKNOWN_PORT

1797L     ERROR_UNKNOWN_PRINTER_DRIVER

1798L     ERROR_UNKNOWN_PRINTPROCESSOR

1799L     ERROR_INVALID_SEPARATOR_FILE

1800L     ERROR_INVALID_PRIORITY

1801L     ERROR_INVALID_PRINTER_NAME

1802L     ERROR_PRINTER_ALREADY_EXISTS

1803L     ERROR_INVALID_PRINTER_COMMAND

1804L     ERROR_INVALID_DATATYPE

1805L     ERROR_INVALID_ENVIRONMENT

1806L     RPC_S_NO_MORE_BINDINGS

1807L     ERROR_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT

1808L     ERROR_NOLOGON_WORKSTATION_TRUST_ACCOUNT

1809L     ERROR_NOLOGON_SERVER_TRUST_ACCOUNT

1810L     ERROR_DOMAIN_TRUST_INCONSISTENT

1811L     ERROR_SERVER_HAS_OPEN_HANDLES

1812L     ERROR_RESOURCE_DATA_NOT_FOUND

1813L     ERROR_RESOURCE_TYPE_NOT_FOUND

1814L     ERROR_RESOURCE_NAME_NOT_FOUND

1815L     ERROR_RESOURCE_LANG_NOT_FOUND

1816L     ERROR_NOT_ENOUGH_QUOTA

1898L     RPC_S_GROUP_MEMBER_NOT_FOUND

1899L     EPT_S_CANT_CREATE

1900L     RPC_S_INVALID_OBJECT

2138L     ERROR_NO_NETWORK

2202L     ERROR_BAD_USERNAME

2250L     ERROR_NOT_CONNECTED

2401L     ERROR_OPEN_FILES

2404L     ERROR_DEVICE_IN_USE

6118L     ERROR_NO_BROWSER_SERVERS_FOUND


 Win32 Glossary


 A

ABC width

The amount of spacing required for a single glyph in a font. "A" spacing is added to the current position before drawing the glyph. "B" spacing is the width of the black part of the glyph. "C" spacing is added to the current position to account for the white space to the right of the glyph. The total advanced width is given by A+B+C. See also glyph.

absolute security descriptor

A security descriptor structure that contains pointers to the security information associated with an object. See also security descriptor, self-relative security descriptor.

accelerator table

An array of ACCEL data structures, each of which defines a keyboard accelerator. See also keyboard accelerator.

access-control entry (ACE)

An entry in an access-control list (ACL). An access-control entry contains a security identifier and may also contain a set of access rights. Access-control entries are used to grant or deny access to a user or group and to audit the access attempts of a user or group. See also access-control list (ACL), security identifier (SID).

access-control list (ACL)

A list of security protections that applies to an object. (An object can be a file, process, event, or anything else having a security descriptor.) An entry in an access-control list (ACL) is an access-control entry (ACE). There are two types of access-control list: discretionary and system. See also access-control entry (ACE), discretionary access-control list (DACL), security descriptor, system access-control list (SACL).

access mask

A 32-bit value that specifies the rights that are granted or denied in an access-control entry (ACE). An access mask is also used to request access rights when an object is opened. See also access-control entry (ACE).

access time

The last time a file was written to, read from, or run, if the file is executable.

access token

A group of security attributes permanently attached to a process when a user logs on to the operating system. An access token contains privileges and security identifiers for a user, global group, or local group. The privileges regulate the use of some system services and the security identifiers regulate access to objects that are protected by access-control lists (ACLs). There are two kinds of access token: primary and impersonation. See also impersonation token, primary token, privilege, process, security identifier (SID).

ACE

See access-control entry (ACE).

ACL

See access-control list (ACL).

active screen buffer

The screen buffer that is currently displayed in a console's window.

active window

A top-level window of the application with which the user is working. Windows identifies the active window by positioning it at the top of the Z order and highlighting its title bar and border. See also window.

Adaptive Differential Pulse Code Modulation (ADPCM)

An audio-compression technique.

additive color technology

The color technology, used by video displays, that is based on the three primary colors red, green, and blue (RGB). Other colors (except black) are a combination of two or more of the primaries in varying amounts. Black is defined as the absence of the primaries.

ADPCM

See Adaptive Differential Pulse Code Modulation (ADPCM).

alertable wait

(1) A wait operation initiated when a thread calls either the WaitForSingleObjectEx, WaitForMultipleObjectsEx, or SleepEx function with the function's fAlertable flag set to TRUE. In an alertable wait, the wait function returns when a ReadFileEx or WriteFileEx function completion routine is queued for execution.

(2) A wait function operation in which the function can return when the specified conditions are satisfied, or when the system queues a completion routine for execution by the waiting thread. See also completion routine, wait function.

animation

The display of a series of graphic images that simulates motion. Animation can be frame based or cast based.

anonymous pipe

An unnamed, one-way pipe that transfers data between a parent and child process, or between two child processes of the same parent process. An anonymous pipe is created by the CreatePipe function that returns two handles (one to the read end and one to the write end of the pipe). The creating parent process controls whether these handles are inherited by its child processes. See also child process, handle, parent process, pipe.

application-defined control

A control belonging to a window class supplied by an application.

application-defined resource

A resource whose format is defined and recognized by a specific application. See also custom resource.

association

The process of matching a filename extension with a specific application. When an extension and an application have been associated, applications can use the association to find and start other applications or to open and print files.

asynchronous input and output (I/O)

A type of I/O in which some file I/O functions return immediately, even though an I/O request is still pending. This enables an application to continue with other processing and wait for the I/O to finish at a later time. See also overlapped input and output (I/O).

asynchronous task handle

The handle returned by the WSAAsyncGetXByY routines. This handle is used to identify the outstanding operation and allow the application to cancel it if needed.

atom

An integer that identifies a character string in an atom table.

atom name

The character string identified by an atom.

atom table

A table, defined by the operating system, that stores character strings and their associated atoms. A global atom table is available to all applications. A local atom table can be used only by the application that created it.

attribute

A characteristic of a file. The six Windows file attributes indicate whether a file is read only, hidden, system, archived, a directory, or normal. See also directory.

auto-reset event object

See event object.

auxiliary audio device

Audio devices whose output is mixed with the Musical Instrument Digital Interface (MIDI) and waveform output devices in a multimedia computer. An example of an auxiliary audio device is the compact disc audio output from a CD-drive.


 B

background window

Any window created by a thread other than the foreground thread.

base character

A character followed by a nonspacing character; typically, this is a letter that receives an accent mark. For example, in the character è, an accented e, the e is the base character. See also nonspacing character.

base class

The window class an application uses as the starting point when creating a superclass. See also superclass.

base line

An imaginary line where the capital letters for a given font rest. See also font.

base priority

A thread priority value that provides the basis for calculating the thread's dynamic priority. This value is set to one of the five levels within the priority class of the thread's process. The scheduler can temporarily boost the priority of a thread, but it cannot reduce it below this base. See also dynamic priority, priority class, process, thread.

beginning-of-medium marker

The position on a tape where you can begin recording data.

beginning-of-partition marker

The position in a partition where you can begin recording data. If there is only one partition, this position is usually equivalent to the beginning-of-medium marker.

Bezier spline

An irregular curve defined by four points: two endpoints and two control points. The endpoints determine where the curve begins and ends. The control points determine the shape of the curve; however, unlike the endpoints, the control points do not intersect the curve.

bit count

The number of bits of data in a color plane that represent a single pixel. See also pixel.

bitmap

An array of bits that contains data that describes the colors found in a rectangular region on the screen (or the rectangular region found on a page of printer paper). See also rectangular region.

bitmapped image

A rectangular image on a video display (or page of printer paper) represented by the color data in a bitmap.

blink time

The elapsed time, in milliseconds, required to invert the caret display. This value is half of the flash time. See also caret, flash time.

blocking input and output (I/O)

A wait mode for I/O operations on a named pipe where functions wait for a process on the other end of the pipe to perform an action. In nonblocking wait mode, the functions return if their operations are not finished immediately. See also named pipe, pipe, process.

bottom-up DIB

A device-independent bitmap (DIB) whose origin lies at the bottom-left corner. See also top-down DIB.

bounding rectangle

A Windows or graphics device interface (GDI) object. In the case of some GDI objects, the dimensions of this rectangle are inclusive-exclusive when no world transformation has been set, and inclusive-inclusive when a world transformation has been set.

break key

In Media Control Interface (MCI), a keystroke that interrupts a wait operation. By default, MCI defines this key as ^CTRL+BREAK^. An application can redefine this key by using the MCI_BREAK command message.

breakpoint

A location in a process where execution is stopped to allow the developer to examine the process's code, variables, and register values, and, as necessary, make changes, continue execution, or terminate execution.

brush

A bitmap that is used to fill the interior of closed shapes, polygons, ellipses, and paths. See also bitmap, ellipse, path, polygon.

brush origin

A coordinate that specifies the location of one of the pixels in a brush's bitmap. Windows maps this pixel to the upper left corner of the window that contains the object to be painted. See also bitmap, pixel, window.

button

An element in the Windows user interface that enables a user to provide input to an application. Buttons are typically used in dialog boxes.

byte-order mark

A special Unicode character (0xFEFF) that is placed at the beginning of Unicode text files to indicate that the text is in Unicode format.

byte reversed

A Unicode file in which the most significant byte is first (as on Motorola architectures).

byte type pipe

A named pipe where data is written as a stream of bytes. See also named pipe.


 C

caret

A flashing line, block, or bitmap that marks the location of the insertion point in a window's client area. See also bitmap.

CD-ROM extended architecture (CD-XA)

An extension of the CD-ROM standard that provides for storage of compressed audio data along with other data on a CD-ROM disc. This standard also defines the way data is read from a disc. Audio signals are combined with text and graphic data on a single track so they can be read at virtually the same time.

channel

A method, provided by Musical Instrument Digital Interface (MIDI), for sending messages to an individual device within a MIDI setup. There are 16 MIDI channel numbers. Devices in a MIDI setup can be directed to respond only to messages marked with a channel number specific to the device.

channel map

A channel map, provided by the MIDI Mapper, that can redirect Musical Instrument Digital Interface (MIDI) messages from one channel to another. See also MIDI Mapper, Musical Instrument Digital Interface (MIDI).

character code

A numeric value that represents a particular character in a set, such as the ASCII character set. See also code page.

character set

A mapping of characters to their identifying numeric values. See also multibyte character set, single-byte character set, Unicode.

character-mode application

An application that does not provide its own graphical user interface (GUI). The Win32 API provides consoles for managing input and output (I/O) for character-mode applications. See also console.

check box

A square box operated by the user to choose from a set of related but independent options. A checked check box contains an X. Repeatedly checking a check box toggles it from state to state. A standard check box has two states: checked and unchecked. A three-state check box has an additional state: disabled (grayed). In versions of standard and three-state check boxes, Windows is responsible for changing the state of the check box.

child process

A process (child) initiated by another process (the parent). The child process can operate independently from the parent process. Further, the parent process can suspend or terminate without affecting the child process. See also parent process.

child window

A window that has the WS_CHILD style. A child window always appears within the client area of its parent window.

child-window identifier

An application-defined value assigned to a child window. An application that creates multiple child windows of the same class uses the identifiers to distinguish among the child windows.

chord

A region bounded by the intersection of an ellipse and a secant. In Windows, a chord is outlined by using the current pen and filled by using the current brush. See also ellipse, secant.

chunk

The basic building block of a Resource Interchange File Format (RIFF) file, consisting of an identifier (called a chunk identifier), a chunk-size variable, and a chunk data area of variable size.

class cursor

The default cursor for a window class. The class cursor is specified by the hCursor member of a WNDCLASS structure. See also cursor.

class icon

The default icon for a window class. The class icon is identified by the hIcon member of a WNDCLASS structure. See also icon.

class menu

The default menu for a window class. All windows of a given class use the same menu unless the application specifies a different menu when creating a window of that class. See also menu, window.

click

To press and release a mouse button.

client area

The part of a window where the application displays output such as text or graphics.

client coordinates

Coordinates relative to the upper left corner of a window's client area.

clip path

One or more irregular shapes in a window's client area where clipped output appears. The edges of a clip path can be straight lines, Bezier curves, or combinations of the two. See also irregular shape.

clipboard

A set of functions and messages used to transfer information between applications or within an application.

clipboard format

The format of data on the clipboard. A window can copy information to the clipboard using multiple clipboard formats. A clipboard format is identified by a unique unsigned integer value. See also clipboard, window.

clipboard owner

The window associated with the information on the clipboard. It is possible for there to be no clipboard owner. See also clipboard, window.

clipboard viewer

A window that displays the contents of the clipboard. See also clipboard, window.

clipping

The process of limiting output to part of the client area in a window. See also window.

clipping region

A polygon or ellipse in a window's client area where clipped output appears. See also ellipse, polygon.

CMY format

See cyan, magenta, yellow (CMY) format.

code page

A mapping of characters to 256 8-bit character codes. See also character code.

coherent

A description of file views that contain identical data at a given time. File views are coherent if they are derived from the same file-mapping object.

Color common dialog box

A common dialog box that displays available colors and controls that let the user define a custom color. See also common dialog box.

color palette

An array containing the RGB (red, green, blue) values identifying the colors that can currently be displayed or drawn on the output device. Color palettes are used by devices that are capable of generating many colors but can only display or draw a subset of these at any given time.

color plane

An array of bits that represents the red, green, blue, or intensity components for the pixels in a bitmapped image. See also bitmapped image, pixel.

command item

A menu item that, when chosen, sends a command message to the window procedure of the window that owns the menu. See also menu item, window.

command message

In Media Control Interface (MCI), a symbolic constant that represents a unique command for an MCI device. Command messages have associated data structures that provide information a device requires to carry out a request.

command string

In Media Control Interface (MCI), a null-terminated character string that represents a command for an MCI device. The text string contains all the information that an MCI device needs to carry out a request. MCI parses the text string and translates it into an equivalent command message and data structure that it then sends to an MCI device driver.

comment

A string of text inserted between records in a metafile. See also metafile.

committed page

A page of memory in a process's virtual address space for which physical storage has been allocated. The storage is either in RAM or on disk.

common dialog box

A dialog box that an application displays by calling a single function rather than by creating a dialog box procedure and a resource file containing the dialog box template. See also resource file.

common display context

The default display context assigned to a window that does not specify CS_OWNDC or CS_CLASSDC as the window's class style. See also display context, window.

communications resource

A physical or logical device that provides a single bidirectional, asynchronous data stream. Serial ports, parallel ports, fax machines, and modems are examples of communications resources. For each communications resource, there is a service provider, consisting of a library or driver, that enables applications to access the resource.

compact disc − digital audio (CD-DA)

An optical data-storage format that provides for the storage of up to 73 minutes of high-quality digital-audio data on a compact disc. Also known as Red Book audio.

compact disc − read-only memory (CD-ROM)

An optical data-storage technology that allows large quantities of data to be stored on a compact disc.

compatible device context (DC)

A virtual-device context that provides a means of storing an image that was created on a physical screen. (Compatible DCs are sometimes referred to as "memory" DCs.) See also device context.

completion routine

A function specified in a call to either the ReadFileEx or WriteFileEx function. A completion routine is queued for execution when the read or write operation is finished. The completion routine is not executed until the thread that called the ReadFileEx and WriteFileEx function enters an alertable wait. See also alertable wait.

composite character

An accented character represented by two character values, one for the base character and another for the nonspacing accent character. See also base character, nonspacing character, precomposed character.

compound device

A Media Control Interface (MCI) device that requires a device element, usually a data file. An example of a compound device is the MCI waveform audio driver. See also device element.

compound file

A number of individual files bound together in one physical file. Each individual file in a compound file can be accessed as if it were a single physical file.

console

An interface that provides input and output to character-mode applications. See also character-mode application.

console modes

Settings associated with a console that determine the behavior of some of its input and output operations.

console process

A character-mode process whose entry point is the main function. A console process uses the console functions or the file input and output (I/O) functions for I/O, while a graphical user interface (GUI) process uses the USER/graphic device interface (GDI) functions. See also process.

console window

A window managed by the system that a console uses to receive input and display output.

container

A network resource that contains other network resources. The contained resources can be such objects as servers or printers, or containers that can also contain further objects and containers. See also sharepoint.

context record

A record of the machine state created when an exception occurs. The context record is saved in a CONTEXT structure.

control

A child window used in conjunction with another window to carry out simple input and output (I/O) tasks.

control change

See MIDI control-change message.

control identifier

A number that an application uses to uniquely identify a control.

control message

A message sent to a control to request information or perform an action.

control set

A set of configurable options for a computer. See also profile.

control style

A value, similar to a window style, that specifies the appearance and behavior of a control. The window procedure for the control uses the style to determine how to draw the control and process input.

coordinate space

A planar space based on the Cartesian coordinate system. This system requires two axes that are perpendicular and equal in length. There are four coordinate spaces in Windows: world, page, device, and physical device (client area, or desktop, or page of printer paper).

Coordinated Universal Time

The standard international time used internally by Windows NT.

cosmetic pen

A pen with dimensions specified in device units. See also pen.

counter

A general term referring to an incrementing variable.

critical section

An object used to synchronize the threads of a single process. Only one thread at a time can own a critical-section object.

current directory

The directory at the end of the active path. This is the directory where the active application started, unless explicitly changed. See also directory.

current position

The starting point for any line-drawing or curve-drawing operations.

current selection

The portion of a document the user has marked in preparation for carrying out a command.

cursor

A small bitmap whose location on the screen is controlled by a pointing device, such as a mouse, pen, or trackball. See also bitmap.

cursor handle

A unique value of the HCURSOR type that identifies a cursor.

custom cursor

A cursor designed for use in a specific application.

custom icon

An icon designed for use in a specific application. See also icon.

custom resource

See application-defined resource.

cyan, magenta, yellow (CMY) format

A color format that identifies a given color with a cyan, magenta, yellow (CMY) format triplet. This format is used by printers and other ink-based devices.


 D

DACL

See discretionary access-control list.

DBCS

See double-byte character set.

DC

See device context.

DDE

See dynamic data exchange.

DDE client application

An application that requests a conversation with a dynamic data exchange (DDE) server application, and receives data from the server during the conversation. See also DDE server application.

DDE conversation

The interaction between a dynamic data exchange (DDE) client and a DDE server application.

DDE server application

An application that provides data to a dynamic data exchange (DDE) client application during a DDE conversation. See also DDE client application, DDE conversation.

DDE transaction

An exchange of messages or data between a dynamic data exchange (DDE) client application and a DDE server application. See also DDE client application.

dead key

A key used with another key to create an accented character. A dead key, when pressed, produces no visible character but indicates that the accent mark it represents is to be combined with the character produced by the next letter key pressed. See also key.

deadlock

A bug where the execution of thread A is blocked indefinitely waiting for thread B to perform some action, while thread B is blocked waiting for thread A. For example, two threads on opposite ends of a named pipe can become deadlocked if each thread waits to read data written by the other thread. A single thread can also deadlock itself. See also named pipe, thread.

debugger

An application that enables a developer to observe and correct programming errors by stepping through an application program, examining data, and checking conditions.

debugging

The process of observing and correcting logical and syntactical errors in an application.

debugging event

An event that occurs in a process being debugged that causes the kernel to notify the debugger. Also, the notification the kernel sends to the debugger. See also debugger, process.

default color palette

An array of RGB values identifying the colors that can be used with a device context by default. Windows associates the default color palette with a context whenever an application creates a context for a device that supports color palettes. The default color palette ensures that colors are available for use by an application without requiring additional action by the application.

default window procedure

A system-defined function that provides default processing for messages an application-defined window procedure does not process. See also window procedure.

desktop wallpaper

The pattern created by the bitmap that the desktop window uses to paint the background of the screen.

desktop window

A system-defined window that paints the background of the screen and serves as the base for all windows displayed by all Windows applications.

detached process

A console process that does not have access to the console of its parent process. Typically, a detached process runs in the background, but it can use the AllocConsole function to create a new console if it needs to print a message to the screen or get input from the user. See also console process, parent process.

device capabilities

The curve-, line-, polygon-, raster-, and text-drawing capabilities of a display or printer.

device context

A data structure defining the graphic objects, their associated attributes, and the graphic modes affecting output on a device. See also graphic modes, graphic objects.

device coordinate space

One of four coordinate spaces used for all graphic device interface (GDI) drawing operations.

device-dependent bitmap

An array of bits that can only be used with a particular display or printer.

device element

Data required for operation of Media Control Interface (MCI) compound devices. The device element is generally an input or output data file.

device-independent bitmap (DIB)

An array of bits combined with several structures that specify the width and height of the bitmapped image (in pixels), the color format of the device where the image was created, and the resolution of the device used to create that image. See also bitmapped image, pixel.

device type

A class of Media Control Interface (MCI) devices that respond to a common set of commands.

DIB palette

The logical color palette created when a device-independent bitmap (DIB) was created. See also color palette.

DIB pattern-brush

A logical brush created from a device-independent bitmap (DIB). See also device-independent bitmap (DIB), logical brush.

digital differential analyzer (DDA)

An algorithm that determines which pixels on a video display (or dots on a printed page) are part of a line or curve. See also pixel.

directory

An organizational construct supported by most disk-based operating systems. Rather than listing all the files on a volume at once, users can create multiple directories to contain groups of files. Directories can also contain other directories.

disabled window

A window that cannot receive input from keyboard, mouse, or other input device.

discretionary access-control list (DACL)

An access-control list that is controlled by the owner of an object and that specifies the access particular users or groups can have to the object. See also access-control list (ACL), system access-control list.

disk drive

A physical device that reads from or writes to disks. Disk drives are referenced by letters, typically A for the first floppy-disk drive, B for the second floppy-disk, C for the first fixed-disk drive, D for the second fixed-disk drive, and so on. Each drive on an operating system is assigned a unique letter to distinguish it from other drives.

display context

A special device context that treats each window like a separate screen surface. See also device context, window.

display driver

A Windows dynamic-link library (DLL) that contains functions that process input from the graphics engine and convert that input into device-specific commands. These commands are processed by the display adapter. See also dynamic-link library (DLL).

display element

The parts of a window and the Windows display that appear on the system display screen.

division type

The technique used to represent the time between Musical Instruments Digital Interface (MIDI) events in a MIDI sequencer.

DLL

See dynamic-link library (DLL).

domain

A group of workstations and servers that share a single group name.

double-byte character set (DBCS)

A mapping of characters to their identifying numeric values, in which each value is 2 bytes wide. Double-byte character sets are sometimes used for languages that have more than 256 characters. For example, a double-byte character set is used to encode Japanese (Kanji) characters. See also multibyte character set.

double-click

To press and release a mouse button twice in quick succession.

drag

To move the mouse while holding down a mouse button.

drag-drop

To select one or more files in File Manager, drag them to an open application, and drop them there.

driver service

A service that follows the device driver protocols for Windows NT rather than using the Service Control Manager interface.

drop-down combo box

A combo box, created by using the CBS_DROPDOWN style, containing a drop-down list and a selection field that can be edited by the user.

drop-down list

A list in a combo box that is visible only when it is opened by the user. Combo boxes with the CBS_DROPDOWN and CBS_DROPDOWNLIST styles contain drop-down lists.

drop-down list box

A combo box, created by using the CBS_DROPDOWNLIST style, containing a drop-down list and a selection field that cannot be edited by the user. A drop-down list box can be used in place of a list box when screen space is tight.

dynamic data exchange (DDE)

A form of interprocess communications that uses shared memory to exchange data between applications. Applications can use DDE for one-time data transfers and for ongoing exchanges in applications that send updates to one another as new data becomes available.

dynamic-link library (DLL)

A .DLL file that contains one or more functions compiled, linked, and stored separately from the processes that use them. The operating system maps the DLLs into the process's address space when the process is starting up or while it is running. The process then executes functions in the DLL. See also process.

dynamic priority

A thread priority value used by the scheduler in making scheduling decisions. The value for each thread can never be lower than the thread's base priority, but it can be raised and then lowered to enhance responsiveness to input or other significant events. See also base priority, thread.


 E

early-warning position

A physical mark or device-computed position immediately before the end-of-partition marker.

edit control

An element of the Windows user interface that allows the user to enter and edit text. Edit controls are typically used in dialog boxes.

ellipse

A closed curve defined by two fixed points such that the sum of the distances from any point on the curve to the two fixed points is constant.

elliptical region

A region with the shape of an ellipse. See also ellipse, region.

embedded font

A TrueType font stored as part of a document. (By storing a font in a document, the document's author is guaranteed that the original appearance and format of the document remain intact.) See also TrueType font.

end cap

A geometric pen attribute that specifies the shape of the pen. There are three types of end caps: flat, round, and square.

end-of-medium marker

The last position on a tape where you can record data.

end-of-partition marker

The last position on a partition where you can record data.

end-of-tape marker

Same as end-of-medium marker.

enhanced metafile

One of two metafile formats. This format, used in applications written to run with the Win32 application programming interface (API), consists of a header, a table of handles to graphics device interface (GDI) objects, a private palette, and an array of metafile records. See also handle.

environment variable

A symbolic variable that represents some element of the operating system, such as a path, a filename, or other literal data. For example, the environment variable PATH represents the directories to search for executable files. See also directory, path.

erase gap

An area of erased tape or a pattern that the device does not recognize as a marker or as user data; it is used to locate a filemark to be overwritten.

escapement

An angle defined by the escapement vector and the x-axis of a device. The base line of a string of text is parallel to the escapement vector. See also x-axis.

event object

An interprocess synchronization object whose state is explicitly set to signaled by the SetEvent or PulseEvent function. A manual-reset event object's state must be explicitly reset to the nonsignaled state by the ResetEvent function. A wait function resets an auto-reset event object's state to nonsignaled before returning. See also synchronization object, wait function.

exception

An event that occurs during the execution of a program and that requires the execution of software outside the normal flow of control.

exception record

A record of an exception. The exception record is saved in an EXCEPTION_RECORD structure.


 F

family name

One of two attributes used to organize TrueType fonts. Family names include Courier New, Arial, and Times New Roman. (The other attribute used to organize TrueType fonts is the style name.) See also TrueType font.

FAT

See file allocation table (FAT).

file

A named, ordered collection of information, such as a program, a set of data used by a program, or a user-created document. A file is the basic unit of storage that enables a computer to distinguish one set of information from another.

file allocation table (FAT)

A table that contains the status of various segments of disk space used for file storage. Also, the file system that maintains the table.

file element

A complete file contained in a Resource Interchange File Format (RIFF) compound file.

file handle

A unique identifier that Windows assigns to a file when the file is opened or created. A file handle is valid until the file is closed.

file-mapping object

An object whose handle can be used to create a view to a file or piece of memory. The CreateFileMapping function creates file-mapping objects. See also handle.

file pointer

A pointer to the next byte to be read or written in a file.

file system

A part of the operating system that enables you to store, access, and organize files on storage devices, such as hard or floppy disks or tape drives. File allocation table (FAT), high-performance file system (HPFS), and New Technology file system (NTFS) are examples of file systems.

file time

A 64-bit value representing the number of 100-nanosecond intervals that have elapsed since January 1, 1601.

file view

A copy of a file or piece of memory that appears in a process's virtual address space. The MapViewOfFile function creates a file view in the process's address space and returns a pointer to the file view.

filemark

A special recorded element that contains no user data and is used to provide a segmentation scheme. A normal filemark does not contain an erase gap.

filled path

A path that is filled by using the brush currently selected into an application's device context. See also device context, path.

filter expression

An expression that is part of a frame-based exception handler. When an exception occurs during the execution of the guarded body of code in a frame-based exception handler, the system evaluates the filter expression to determine whether the exception handler code is to be executed. See also frame-based exception handler, guarded body of code.

filter function

A function called by a filter expression in a frame-based exception handler. See also frame-based exception handler.

Find common dialog box

A common dialog box that displays an edit control in which the user can type a string that the application should search. See also common dialog box.

first-chance notification

The first time the kernel notifies the debugger of an exception. See also debugger.

flash time

The elapsed time, in milliseconds, required to display, invert, and restore the caret display. This value is twice as much as the blink time. See also blink time, caret.

flattened path

A path altered by converting each curve (in the path) into a series of line segments. See also path.

floating pop-up menu

A pop-up menu that is not attached to a menu bar. See also pop-up menu.

FM synthesizer

See frequency modulation (FM) synthesizer.

font

(1) A collection of characters and symbols that share a common design.

(2) A drawing object used to write text on a display surface.

Font common dialog box

A common dialog box that displays lists of fonts and point sizes that correspond to available fonts. See also common dialog box.

font mapper

An algorithm that Windows uses to determine which available font most closely matches a requested font. See also font.

font table

An array that identifies each of the fonts whose resources have been loaded. Only fonts whose resources have been loaded can be used for text output. See also font.

foreground window

The window with which the user is currently working. The system assigns a slightly higher priority to the thread that created the foreground window than it does to other threads.

form type

A four-character code (FOURCC) identifying the type of data contained in a Resource Interchange File Format (RIFF) chunk. For example, a RIFF chunk with a form type of WAVE contains waveform audio data.

FOURCC (Four-Character Code)

A code used to identify Resource Interchange File Format (RIFF) chunks. A FOURCC is a 32-bit quantity represented as a sequence of one to four ASCII alphanumeric characters, padded on the right with blank characters.

frame-based exception handler

A mechanism used by a developer to deal with the possibility that an exception may occur in a certain sequence of code. A frame-based exception handler consists of a guarded body of code, a filter expression, and an exception handler. See also filter expression, guarded body of code.

free page

A page of memory in a process's virtual address space that is available to be reserved or committed. A process cannot access a free page. See also committed page, reserved page.

frequency

With respect to the high-resolution performance counter, the number of counts per second. This value is processor dependent.

frequency modulation (FM) synthesizer

A synthesizer that creates sounds by combining the output of digital oscillators using a frequency modulation technique.


 G

General MIDI

A synthesizer specification created by the MIDI Manufacturers Association (MMA) defining a common configuration and set of capabilities for consumer Musical Instrument Digital Interface (MIDI) synthesizers.

geometric pen

A pen with dimensions that are specified in world units. A geometric pen may possess attributes usually associated with a brush, such as pattern and hatch. See also brush, geometric pen, pen.

global atom

An atom stored in the global atom table. The value of a global atom is unique among all others in the operating system. See also atom.

global atom table

See atom table.

global subclassing

A type of subclassing in which an application replaces the window-procedure address stored in the WNDCLASS structure of a window class with the address of a subclass procedure. All subsequent windows created with the class use the subclass procedure rather than the original window procedure. See also subclassing, window, window procedure.

glyph

The bitmap, collection of points, or collection of graphic commands that define a single character or symbol in a font. See also bitmap, font.

graceful disconnect

In a graceful disconnect, all the data sent by both sides are delivered and there is full acknowledgment of the session termination by both sides. This contrasts with an abortive disconnect, in which one side unilaterally terminates the connection, disregarding any queued data. As a result, in an abortive disconnect there may be data loss.

graphic modes

A set of modes that define how the Win32 API draws output with the objects found in a device context. See also device context.

graphic objects

The pen, brush, bitmap, palette, region, and path associated with a device context. See also bitmap, brush, device context, palette, path, region.

graphical user interface (GUI) process

A process whose entry point is the WinMain function. A GUI process uses the USER/graphics device interface (GDI) functions for input and output (I/O), while a console process uses the console functions or the file I/O functions. See also console process.

graphics device interface

A dynamic-link library that processes graphics function calls from a Windows-based application and passes those calls to the appropriate device driver. See also dynamic-link library (DLL).

group box

A rectangle used to group related controls (usually check boxes or radio buttons). Because its sole purpose is to organize other controls, a group box cannot be selected. See also check box, radio button.

guarded body of code

A set of one or more statements for which an exception or termination handler provides protection.

GUI process

See graphical user interface (GUI) process.


 H

handle

A variable that identifies an object; an indirect reference to an operating system resource.

hatched brush

A logical brush created from one of twenty predefined bitmaps. See also bitmap, logical brush.

hidden window

A window that does not have the WS_VISIBLE style. A hidden window does not appear on the screen. As a result, it cannot receive user input or display output, although it can receive input from Windows and other applications.

high-performance file system (HPFS)

A file system that supports extended attributes and long, mixed-case filenames, and improves operating system performance by implementing several levels of caching. Windows NT cannot manipulate the extended attributes of a file created on HPFS.

high-resolution performance counter

Hardware that provides high-resolution timing useful in improving the performance of applications.

hit testing

(1) The process of detecting user input by using the position of the mouse cursor hot spot. See also hot spot.

(2) A procedure for determining the current cursor position related to a given region. See also region.

hive

A discrete body of registry information, typically rooted at the top of the registry hierarchy. Each hive is usually supported by a single file of registry data.

HLS format

A color format that identifies a given color with a HLS (hue, luminosity, and saturation) triplet.

HMS time format

A time format used by Media Control Interface (MCI) to express time in hours, minutes, and seconds. The HMS time format is used primarily by videodisc devices.

hollow brush

See null brush.

hook

A point in the Windows message-handling mechanism where an application can install a subroutine to monitor messages.

hook chain

A list of pointers to the hook procedures associated with a hook. When a message occurs that is monitored by the hook, Windows calls the first hook procedure in the chain.

hook procedure

An application-defined callback function whose address has been installed in a hook chain.

hot key

A key combination that generates a WM_HOTKEY message.

hot spot

The pixel in a cursor that marks the exact screen location affected by a mouse action, such as a button click. Mouse messages include the coordinates of the hot spot. See also cursor, pixel.

HPFS

See high-performance file system (HPFS).


 I

icon

A small bitmap that usually represents a minimized application. Icons may also serve as symbols in warning messages or other windows. See also bitmap.

icon handle

A unique value of the HICON type that identifies an icon. See also icon.

iconic

Minimized. If an icon represents a minimized application, the application's window is said to be iconic. See also icon, window.

ideographic

A single character that represents a word, object or a phrase — for example, a single character that means "month." This term would apply to the Han script.

IMA

See Interactive Multimedia Association (IMA) and International MIDI Association (IMA).

image

A rectangular region on a video display that contains a graphical representation of an object. See also rectangular region.

impersonation token

An access token that has been created to capture the security information of a client process, allowing a server to "impersonate" the client process in security operations. See also access token, primary token.

import library

A .LIB file that contains information about one or more dynamic-link libraries (DLLs), but does not contain the DLL's executable code. The linker uses an import library when building an executable module of a process, to provide the information needed to resolve the external references to DLL functions. See also dynamic-link library, process.

information context

A device context used strictly for data retrieval; it cannot be used for any drawing operations. See also device context.

input buffer

A buffer containing a queue of input records with information about keyboard, mouse, and window-sizing events for a console. See also console.

input event

An event--such as a keystroke, mouse movement, or mouse-button click--that causes a console to place an INPUT_RECORD structure in its input buffer. A console process can get information about an input event by reading from the console's input buffer.

instance

An instantiation of a particular object type in a class, such as a specific process or thread. All instances of a given type have identical performance counters.

instance subclassing

A type of subclassing where an application replaces the window-procedure address of a single instance of a window with the address of a subclass procedure. See also subclassing, window.

integer atom

An atom that identifies an integer value. See also atom.

Interactive Multimedia Association (IMA)

A professional trade association of companies, institutions, and individuals involved in producing and using interactive multimedia technology.

International MIDI Association (IMA)

The nonprofit organization that circulates information about the Musical Instrument Digital Interface (MIDI) specification.

irregular curve

A curve that does not fit the perimeter of a conic section.

irregular shape

A shape composed of curves and straight line segments.

item name

A string that identifies a unit of data a server can pass to a client during a transaction.


 J

join style

A geometric pen attribute that specifies how the ends of connected lines are joined. See also geometric pen.


 K

key

An entry (or node) in the registry. A key may have one or more values, subkeys, or both. With the exception of four predefined keys, all keys are subkeys of other keys. See also registry, subkey.

keyboard accelerator

A keystroke or combination of keystrokes that sends a command message to the specified application window.

keyboard focus

A property of the window currently receiving keyboard input. Only one window at a time can have the keyboard focus. See also window.


 L

language identifier

A 16-bit value that identifies a language and, where appropriate, the variant of the language being used. A language identifier is a combination of a primary language identifier and a sublanguage identifier. For example, if the primary language identifier specifies English, the sublanguage identifier might specify Australian English.

last-chance notification

The last time the kernel notifies the debugger of an exception. If the debugger does not handle an exception after last-chance notification, the kernel terminates the process being debugged. See also debugger, process.

last-error code

A per-thread value set by Win32 functions when an error occurs. The last-error code can be retrieved by using the GetLastError function.

LCID

See locale identifier.

line

A set of highlighted pixels on a video display (or a series of dots on a printed page) that is defined by two points: a starting point and an ending point. See also pixel.

line and curve attributes

The width, color, style, and (in the case of lines or curves drawn with a geometric pen) end cap, join style, and transformation of a line or curve. See also end cap, geometric pen, join style, transformation.

list box

A control window that contains a list of items that can be selected by the user.

LIST chunk

A Resource Interchange File Format (RIFF) chunk with a chunk identifier of LIST. LIST chunks contain a series of subchunks.

list type

A four-character code (FOURCC) identifying the type of data contained in a Resource Interchange File Format (RIFF) chunk with a chunk identifier of LIST. For example, a LIST chunk with a list type of INFO contains a list of information about a file, such as the creation date and author.

load-time linking

Dynamic linking that occurs when a program (either an application or another dynamic-link library [DLL]) makes an explicit call to a DLL function. This requires that the executable module of the program be built by linking with the DLL's import library. When the program is executed, the operating system uses the information provided by the import library to locate the executable module of the DLL, which is mapped into the address space of the process. See also import library, process.

local atom

An atom stored in an application's atom table. The value of a local atom is unique within the application but may not be unique throughout the operating system. See also atom, atom table.

local atom table

See atom table.

locale identifier (LCID)

A DWORD value containing the language identifer in the lower word and a reserved value in the upper word. The identifier supplied in an LCID is a standard international numeric abbreviation. This LCID has the components necessary to uniquely identify one of the installed system-defined locales.

locally unique identifier (LUID)

A 64-bit value guaranteed to be unique on the operating system that generated it (until the system is restarted).

logfile

A configuration registry key that specifies the filename of an event log. Logfiles are subkeys of the EventLog registration key. See also key, subkey.

logging off

The action of stopping all processes running in the security context of the process that called the Exit function.

logical brush

A description of a bitmap. A logical brush can be selected into a device context. See also bitmap, device context.

logical coordinate space

Another name for the world or page coordinate space. If an application has set a world-space to page-space transformation, the logical space is the world space; otherwise, the logical space is the page space.

logical palette

An array of colors, or "color palette," that an application creates and associates with a device context and uses for graphics output. See also device context.

logical volume

See partition.

long filemark

A filemark that contains a long erase gap that enables an application to position the tape at the beginning of the filemark and to overwrite the filemark and the erase gap. See also erase gap.

LUID

See locally unique identifier.


 M

mailslot

A pseudofile used for one-way interprocess communications.

mailslot client

A process that writes a message to a mailslot.

mailslot server

A process that creates and owns a mailslot and can read messages from it. See also process.

main window

The window that serves as the primary interface between the user and an application.

manual-reset event object

See event object.

mapping

A representation of the elements (or points) from a source coordinate space on a target coordinate space.

mapping mode

An algorithm that specifies the size of the units used for any drawing operations associated with a particular device context.

matrix

An n-dimensional array that is used to specify a transformation. Transformations in a two-dimensional space require either a two-dimensional or a three-dimensional array.

maximize box

A window component that, when clicked, causes Windows to enlarge the window to the size of the screen.

maximized window

A window that has the WS_MAXIMIZE style. A maximized top level window fills the screen; a maximized child window fills the client area of its parent window.

maximum tracking size

The largest window size the user can produce by dragging the sizing border.

MCI

See Media Control Interface.

MDI client window

See multiple document interface client window.

MDI frame window

See multiple document interface frame window.

Media Control Interface (MCI)

High-level control software that provides a device-independent interface to multimedia devices and media files. MCI includes a command-message interface and a command-string interface.

memory device context (DC)

See compatible device context (DC).

menu

A list of items that represent an application's commands. A menu item can be either a string or a bitmap. See also bitmap, menu item.

menu bar

The topmost menu in a hierarchy of menus. A menu bar typically contains one or more menu items that the user can select to display pop-up menus. See also menu, menu item, pop-up menu.

menu handle

A unique value of the type HMENU used to identify a menu. See also menu.

menu item

A string or bitmap displayed in a menu. Choosing a menu item either sends a command message or activates a pop-up menu. See also bitmap, pop-up menu.

message

A data packet used for communicating information or a request. Messages can be passed between the operating system and an application, different applications, threads within an application, and windows within an application. See also thread, window.

message loop

A program loop that retrieves messages from a thread's message queue and dispatches them to the appropriate window procedures. See also message queue.

message parameters

A pair of 32-bit values that contains information a window procedure uses while processing a message.

message queue

An operating system-defined memory object that holds an ordered list of messages awaiting processing. The system message queue holds mouse and keyboard input waiting to be passed to a thread's message queue. A thread's message queue holds messages waiting to be retrieved by a thread's message loop. See also message loop.

message-type pipe

A named pipe where data is written as a stream of messages. See also named pipe.

metafile

A collection of structures that stores a picture in a device-independent format. (There are two metafile formats: the enhanced format and the Windows format.)

metafile bits

The binary representation of a metafile. The bits include the header, an optional palette, an optional text description of the metafile contents, and the metafile records. See also metafile record, palette.

metafile device context (DC)

A device context that is used for metafile operations. See also device context.

metafile handle table

An array of handles that identify pens, brushes, fonts, and other objects used to create the picture stored in the metafile. See also brush, font, handle, metafile, pen.

metafile header

A structure that specifies the size of the picture stored in the metafile, the size of the metafile (in bytes), the number of entries in the metafile palette, the number of records in the metafile, a pointer to the metafile description (if one exists), and a pointer to the metafile palette (if one exists). See also metafile, metafile palette, palette.

metafile palette

An array of red, green, blue (RGB) values that represent the colors used to create the picture stored in a metafile. See also metafile.

metafile record

A variable-length structure. In most cases, this structure represents a call made to a graphics device interface (GDI) function to create part of the picture stored in the metafile. See also metafile.

MIDI

See Musical Instrument Digital Interface.

MIDI control-change message

A Musical Instrument Digital Interface (MIDI) message sent to a synthesizer to change different synthesizer control settings. An example of a control-change message is the volume controller message, which changes the volume of a specific MIDI channel.

MIDI Manufacturers Association (MMA)

A collective organization composed of Musical Instrument Digital Interface (MIDI) instrument manufacturers and MIDI software companies. The MMA works with the MIDI Standard Committee to maintain the MIDI specification.

MIDI Mapper

Windows systems software that modifies Musical Instrument Digital Interface (MIDI) output messages and redirects them to a MIDI output device using values stored in a MIDI setup map. The MIDI Mapper can change the destination channel and output device for a message, as well as modify program-change messages, volume values, and key values.

MIDI mapping

The process of translating and redirecting Musical Instrument Digital Interface (MIDI) messages according to data defined in a MIDI map setup.

MIDI program-change message

A Musical Instrument Digital Interface (MIDI) message sent to a synthesizer to change the patch on a specific MIDI channel.

MIDI sequence

Musical Instrument Digital Interface (MIDI) data that can be played by a MIDI sequencer.

MIDI sequencer

A program that creates or plays songs stored as Musical Instrument Digital Interface (MIDI) files. When a sequencer plays MIDI files, it sends MIDI data from the file to a MIDI synthesizer, which produces the sounds. Windows provides a MIDI sequencer, accessible through media control interface (MCI), that plays MIDI files. See also Media Control Interface (MCI).

MIDI setup map

A complete set of data for the Musical Instrument Digital Interface (MIDI) Mapper to use when redirecting MIDI messages. Only one setup map can be in effect at a given time, but the user can have several setup maps available and can choose between them by using the MIDI Mapper Control Panel option.

minimize box

A window component that, when clicked, causes Windows to reduce the window to the size of an icon.

minimized window

A window that has the WS_MINIMIZE style. A minimized window is the same size as an icon. Windows displays a minimized top-level window at the bottom of the screen; Windows displays a minimized child window at the bottom of its parent window's client area.

minimum tracking size

The smallest window size the user can produce by dragging the window's sizing border.

MMA

See MIDI Manufacturers Association.

module-definition file

A text file (.DEF) that contains one or more statements describing various attributes of an executable module. A dynamic-link library (DLL) must have a .DEF file to specify the DLL's name and a list of its exported functions. See also dynamic-link library (DLL).

mouse capture

The act of channeling mouse input to a specific window without regard to the position of the mouse-cursor hot spot. See also hot spot, window.

MS-DOS date

A date in the format used by MS-DOS. The date is a packed 16-bit value in which bits in the value represent the day, month, and year.

MS-DOS time

A time in the format used by MS-DOS. The time is a packed 16-bit value in which bits in the value represent the hour, minute, and second.

MSF time format

A time format used by Media Control Interface (MCI) to express time in minutes, seconds, and frames. The number of frames in a second depends on the type of device being used; compact disc audio devices use 75 frames per second. The MSF time format is used primarily by compact disc audio devices.

multibyte character set

A character set in which each character is identified by using more than one byte--for example, a double-byte character set (DBCS). Although Unicode characters are 2 bytes wide, the Unicode character set is not referred to by this term. See also double-byte character set (DBCS), single-byte character set, Unicode.

multiple document interface (MDI) client window

A window that belongs to the MDICLIENT window class. An MDI client window serves as the background for MDI child windows, and it provides support for creating and manipulating child windows. See also window.

multiple document interface (MDI) frame window

The main window of a multiple document interface (MDI) application. See also window.

multiple-selection list box

A list box in which more than one item can be selected at the same time.

Musical Instrument Digital Interface (MIDI)

A standard protocol for communication between musical instruments and computers.

mutex object

An interprocess synchronization object whose state is signaled when it is not owned by any thread, and nonsignaled when it is owned. Only one thread at a time can own a mutex. See also nonsignaled, signaled, synchronization object.


 N

named pipe

A one-way or two-way pipe used for communications between a server process and one or more client processes. A server process specifies a name when it creates one or more instances of a named pipe. Each instance of the pipe can be connected to a client process that uses the pipe name to open a handle to the other end of the pipe. See also handle, pipe.

network provider

The supplier of a complete implementation of a networking system: for example, Microsoft Server or Novell Netware.

network root

The topmost container resource in a network hierarchy. The network root can contain the network providers on a system.

New Technology File System (NTFS)

A file system that supports object-oriented applications by treating all files as objects with user-defined and system-defined attributes. NTFS provides all the capabilities of the file allocation table (FAT) and high-performance (HPFS) file systems without many of their limitations.

nonclient area

The parts of a window that are not a part of the client area. A window's nonclient area consists of the border, menu bar, title bar, scroll bar, System menu, Minimize button, and Maximize button. See also menu bar, scroll bar, window.

nonqueued message

A message sent directly to a window procedure.

nonsignaled

The state of an object used for synchronization in one of the wait functions is either signaled or nonsignaled. A nonsignaled state can prevent the wait function from returning. See also signaled, wait function.

nonspacing character

A character that prints over the preceding character--typically, an accent mark. See also base character.

normal filemark

A filemark that does not contain an erase gap. See also erase gap.

notification message

A message a control sends to its parent window when events, such as input from the user, occur.

NTFS

See New Technology File System (NTFS).

null brush

A logical brush created from a bitmap that matches the current window background colors. (A null brush is identical to a hollow brush.) See also bitmap, hollow brush, logical brush.


 O

object

(1) An internal structure that represents a system resource, such as a file, a thread, or a graphic image. See also thread.

(2) A network resource that does not contain any further network resources. It is not necessarily possible to connect to an object.

object type

A measurable entity, such as a processor, disk, or thread.

Open common dialog box

A common dialog box that displays a list of filenames matching any specified extensions, directories, or drives. By selecting one of the listed filenames, the user indicates the file an application should open. See also common dialog box, directory.

overlapped input and output (I/O)

See asynchronous input and output (I/O).

overlapped window

A style of window meant to serve as an application's main window.

owned window

A window that has an owner. Being owned affects the window's position in the Z order and its visibility and can determine when the window is destroyed.

owner window

A window that affects aspects of another window's appearance and behavior.

owner-drawn button

A button with the style BS_OWNERDRAW. Unlike all other button types, an owner-drawn button has no predefined appearance or behavior. Also, the application, not Windows, is responsible for painting it. See also button.

owner-drawn control

A predefined control that sends messages to its parent window when it must be drawn.

owner-drawn item

A menu item whose appearance is controlled by a menu's owner window rather than by Windows. See also menu item, window.


 P

page

A unit of memory that is used by the system in managing memory. The size of a page is computer dependent and can be determined by using the GetSystemInfo function. The system manages memory by assigning pages of memory to specific processes, moving pages to and from a paging file on disk to keep the most recently used pages in physical memory (RAM), and maintaining a page map for each process that keeps track of the current physical location of each committed page in a process's virtual address space. See also committed page, page map.

page coordinate space

The coordinate space in which all graphics device interface (GDI) drawing operations begin if an application has not set the world-space to page-space transformation.

page map

An internal data structure maintained by the system for each process that maps the pages of a process's virtual address space with the corresponding pages of physical storage. See also page.

paging file

A disk file that the system uses to increase the amount of physical storage.

palette

An array of colors currently available on a device.

palette animation

A method of updating the colors in the logical palette.

PANOSE numbers

Special values specified by an application to select a particular font.

parent process

A process (parent) that initiates and controls another process (child) in a multitasking environment. The parent process defines the environment for the child process. The parent process can suspend or complete its own processing while the child process continues its operation. See also child process.

parent window

A window that has one or more child windows.

partition

A logically distinct portion of memory or a storage device that the system references as though it were a physically separate unit. The partition is referenced as a separate volume. For example, a single fixed disk may be divided into two partitions, referred to as C and D, even though they exist on the same physical volume.

parts per quarter note (PPQN)

A time format used for Musical Instrument Digital Interface (MIDI) sequences. PPQN is the most common time format used with standard MIDI files.

patch

A particular setup of a Musical Instrument Digital Interface (MIDI) synthesizer that results in a particular sound, usually a sound simulating a specific musical instrument. Patches are also called programs. A MIDI program-change message changes the patch setting in a synthesizer. Patch also refers to the connection or connections between MIDI devices. See also Musical Instrument Digital Interface (MIDI).

patch caching

A technique that enables some internal Musical Instrument Digital Interface (MIDI) synthesizer device drivers to preload their patch data, reducing the delay between the moment the synthesizer receives a MIDI program-change message and the moment it plays a note using the new patch. Patch caching also ensures that required patches are available (the synthesizer might load only a subset of its patches). See also Musical Instrument Digital Interface (MIDI), patch.

path

(1) A string that describes the location of a file or directory on a volume relative to the current directory or the root directory.

(2) One or more figures that are filled, outlined, or filled and outlined. See also directory, volume.

path bracket

One or more graphics device interface (GDI) functions embedded between a BeginPath and an EndPath function. (The BeginPath function defines the start of the bracket; the EndPath function defines the end.)

pattern brush

A logical brush created from an application-defined bitmap. See also bitmap, logical brush.

pen

A drawing tool used to draw lines and curves.

pen style

One of the cosmetic and geometric pen attributes that define the appearance of lines drawn with the pen. There are eight possible styles: solid, dashed, dotted, dashed and dotted, dash followed by two dots, invisible, inside frame, and user defined. See also cosmetic pen, geometric pen, pen.

pen type

An attribute that determines whether the pen's dimensions are specified in world units or device units.

performance monitoring

The process of determining the system resources an application consumes, such as processor time and memory.

persistent connection

A network connection that Windows restores automatically when the user logs on.

physical brush

A bitmap that Windows uses to paint the interior of filled shapes. A physical brush is a device driver's approximation of a logical brush. See also bitmap, logical brush.

physical device

The fourth and final coordinate space for most graphics device interface (GDI) drawing operations. (The points in this coordinate space may correspond to the desktop, a client area, or a page of printer paper.)

physical palette

See system palette.

picture frame

A rectangle defining the width and height of the picture stored in a metafile. (The dimensions of this rectangle are always specified in .01-mm units.) See also metafile.

pie

A region bounded by the intersection of an ellipse and two radials. In Windows, a pie is outlined by using the current pen and filled by using the current brush. See also ellipse, radial.

pipe

A communication conduit with two ends. A process with a handle to one end can communicate through a pipe with a process having a handle to the other end. Pipes can be one way (where one end is read only and the other end is write only) or two way (where both ends of the pipe can be used for reading or writing). The Win32 application programming interface (API) provides both anonymous (unnamed) pipes and named pipes. See also anonymous pipe, handle, named pipe, process.

pipe instance

A separate conduit for named pipe communications between a client and a server process. A named pipe can have multiple instances, where all instances share the same pipe name but each instance has its own buffers and handles. See also handle, named pipe.

pitch scale factor

In waveform audio, the amount by which a waveform audio driver scales the pitch. A scale factor of two results in a one-octave increase in pitch. Pitch scaling requires specialized hardware. The playback rate and sample rate are not changed.

pixel

The smallest definable unit on a video display. (A pixel's size is a function of video-display technology.)

playback rate scale factor

In waveform audio, the amount by which the waveform audio driver scales the playback rate. Playback scaling is accomplished through software; the sample rate is not changed, but the driver interpolates by skipping or synthesizing samples. For example, if the playback rate is changed by a factor of two, the driver skips every other sample.

playing a metafile

The process of converting the records in a metafile into the respective device commands and drawing the corresponding picture on the device. See also metafile.

Point-to-Point Protocol (PPP)

The Point-to-Point Protocol, or PPP, is an industry-standard suite of control protocols that allow multiple network protocols to be carried on a point-to-point link. Windows NT supports IP, IPX, and NBF connections using PPP. This allows the use of applications that write to a network-specific interface, connections to third-party PPP servers, and remote access to the Internet.

polygon

A closed figure with straight sides. In Windows, a polygon is outlined by using the current pen and filled by using the current brush. See also brush, pen.

polygon fill mode

An algorithm that determines the parts of a region that can be filled, painted, inverted, or clipped. See also region.

polygonal region

A region with the shape of a polygon. See also polygon, region.

polyphony

The maximum number of notes that a Musical Instrument Digital Interface (MIDI) output device can play simultaneously.

pop-up item

A menu item that, when chosen, displays a pop-up menu. See also menu item, pop-up menu.

pop-up menu

A menu that is hidden until the user performs an action that causes Windows to display the menu. See also menu.

pop-up window

A special type of overlapped window typically used for dialog boxes, message boxes, and other temporary windows that appear outside an application's main window.

PPP

See Point-to-Point Protocol.

PPQN

See parts per quarter note.

precomposed character

An accented character represented by a single character value. See also base character, composite character, nonspacing character.

predefined control

A control belonging to a window class supplied by Windows.

preimaging

The process of building a movie frame in a memory buffer before it is displayed.

primary domain

The domain used by the local computer as its usual and default network environment. See also domain.

primary language identifier

An 8-bit value identifying the primary language in a language identifier. See also language identifier, sublanguage identifier.

primary thread

The initial thread of a process. Also called the main thread or thread 1. When the main or WinMain function of a primary thread returns, the ExitProcess function is called implicitly, terminating all other threads of the process. A primary thread does not differ from other threads with respect to signals because all signals are delivered to the thread that caused them. See also process, thread.

primary token

An access token that is typically created only by the Windows NT™ executive layer. It may be assigned to a process to represent the default security information for that process. See also access token, impersonation token.

Print common dialog box

A common dialog box that displays information about the installed printer and its configuration. By altering and selecting controls in this dialog box, the user specifies how output should be printed and starts the printing process. See also common dialog box.

Print-setup common dialog box

A common dialog box that displays the current printer configuration and provides options for setting the paper orientation, size, and source. See also common dialog box.

priority class

A process priority category (high, normal, or idle) used to determine the scheduling priorities of a process's threads. Each priority class has five levels. See also thread.

private memory

Pages of a process's memory that cannot be accessed by other processes. All memory objects allocated by the GlobalAlloc, LocalAlloc, VirtualAlloc, and HeapAlloc functions are in private pages.

privilege

A locally unique identifier used to regulate the use of some system services. See also locally unique identifier (LUID).

process

An executing application that consists of a private virtual address space, code, data, and other operating system resources, such as files, pipes, and synchronization objects that are visible to the process. A process also contains one or more threads that run in the context of the process. See also pipe, process, thread.

profile

A set of configurable options for a user. See also control set.

push button

A rounded rectangle used by the user to start or cancel an operation by clicking the rectangle, which "pushes" the button. A default push button is "pushed" when the user presses the ENTER key. See also button.


 Q

queued message

A message in a message queue. See also message queue.


 R

race condition

A bug in a multithreaded process where the code of thread A relies on thread B to complete some action, but where there is no synchronization between the two threads. The process works if thread B wins the race by completing its action before thread A needs it, but the process fails if thread A wins the race. See also process, thread.

radial

A line drawn from the center of an ellipse to a point on the ellipse. See also ellipse.

radio button

A round button operated by the user to choose from a set of related but mutually exclusive options. The check mark for a radio button is a black dot. A radio button can assume two states: checked (dot) or unchecked (no dot). In automatic radio buttons, Windows is responsible for changing the state of the radio button.

raster device

A device that creates text and graphics output by highlighting rows and columns of pixels (in the case of video displays) or rows and columns of dots (in the case of printers). See also pixel.

rasterizer

A Windows dynamic-link library that converts the graphics commands and hints for TrueType glyphs into actual bitmaps that are drawn on a video display or page of paper. See also bitmap, glyph, dynamic-link library (DLL).

rectangular region

A region with the shape of a rectangle. See also region.

Red Book audio

See compact disc − digital audio (CD-DA).

red, green, blue (RGB) format

A color format that identifies a given color with a red, green, blue (RGB) triplet. This format is used by video displays.

reference count

The number of times a string has been added to or deleted from an atom table. The AddAtom or GlobalAddAtom function increments the count; the DeleteAtom or GlobalDeleteAtom function decrements the count. See also atom table.

reference device

The device where the original picture was created.

reference device context (DC)

The device context associated with the reference device.

reflection

A transformation that creates a mirror image of an object.

region

A rectangle, polygon, ellipse (or a combination of two or more of these shapes) used by Windows-based applications to define a part of the client area to be painted, inverted, filled with output, framed, or used for hit testing. See also ellipse, hit testing, polygon.

region operation

A procedure such as inverting, painting, clipping, or hit testing. See also clipping, hit testing.

registered clipboard format

A clipboard format registered by an application, as opposed to a standard clipboard format.

registry

The database in which configuration information is registered. This database takes the place of most configuration and initialization files for Windows and new Windows-based applications.

regular curve

A curve that defines the perimeter of a conic section.

relative identifier (RID)

The portion of a security identifier (SID) that identifies a user or group in relation to the authority that issued the SID. See also security identifier (SID).

render

To make data available in a specific clipboard format. See also clipboard format.

Replace common dialog box

A common dialog box that displays two edit controls where the user can type strings: The first string identifies a word or value that the application should replace, and the second string identifies the replacement word or value. See also common dialog box, edit control.

reserved page

A page of memory in a process's virtual address space that has been set aside for future use. The page is not accessible and has no physical storage associated with it. A reserve page reserves a range of virtual addresses that cannot be used subsequently by other allocation operations.

resolution

(1) For joysticks, the minimum and maximum intervals between joystick messages sent for a captured joystick.

(2) For timers, the accuracy of the timer event. A resolution value of zero means that the event must occur at the exact time requested; a resolution value of ten means that the event must occur within ten milliseconds of the requested time.

resource

Binary data the resource compiler or developer adds to an application's executable file. Windows resources include icons, cursors, menus, dialog boxes, bitmaps, fonts, keyboard-accelerator tables, message-table entries, string-table entries, version data, and user-defined data.

resource compiler

An application that creates a binary resource file based on the resource-definition file. The resource compiler can also append binary resource data to an executable file and create a resource table in the executable file's header. See also resource table.

resource-definition file

A text file containing descriptions of an application's resources. The resource compiler creates a binary resource file based on the contents of the resource-definition file. Resource-definition files usually have a .RC extension.

resource file

A binary file created by the resource compiler that contains an application's resource data. Resource files usually have a .RES extension. See also resource compiler.

Resource Interchange File Format (RIFF)

A tagged-file specification used to define standard formats for multimedia files. Tagged-file structure helps prevent compatibility problems that often occur when file-format definitions change over time. Because each piece of data in the file is identified by a standard header, an application that does not recognize a given data element can skip over the unknown information. See also tagged file format.

resource object

An object file that consists of the resource file and the resource table. The linker links the resource object to the executable file. See also resource file.

resource table

Data the resource compiler adds to the header of an application's executable file. This data includes the location, name, type, language, and so on, of each resource in the executable file. See also resource compiler.

restore box

A bitmap that, when clicked, restores the window to its previous size and position.

restored window

A window that does not have the WS_MAXIMIZE or WS_MINIMIZE style.

RGB format

See red, green, blue (RGB) format.

RID

See relative identifier (RID).

RIFF

See Resource Interchange File Format (RIFF).

RIFF chunk

A chunk with chunk identifier Resource Interchange File Format (RIFF) that includes an identifying code and zero or more subchunks, the contents of which depend on the form type.

RIFF file

A file whose format complies with one of the published Resource Interchange File Format (RIFF) forms. Examples of RIFF files include WAVE files for waveform audio data, RMID files for Musical Instrument Digital Interface (MIDI) sequences, and RDIB files for device-independent bitmaps.

RIFF form

A file-format specification based on the Resource Interchange File Format (RIFF) standard.

root directory

The topmost directory on a volume. Files and directories on a volume are organized in a tree structure whose entry point is the root directory. The root directory is referenced in a path by a single backslash (\\) or a leading backslash in a longer path (\\MYDIR\\MYFILE.TXT). See also directory, path, volume.

rotation

A transformation that rotates an object with respect to the coordinate-space origin.

run-time linking

Dynamic linking that occurs when the LoadLibrary and GetProcAddress functions are used to get the starting address of a dynamic-link library (DLL) function.


 S

SACL

See system access control list.

sample

A discrete piece of waveform data represented by a single numerical value. Sampling is the process of converting analog data to digital data by taking samples of the analog waveform at regular intervals.

sampling rate

The rate at which a waveform audio driver performs audio-to-digital or digital-to-audio conversion. For compact disc − digital audio (CD-DA), the sampling rate is 44.1 kHz. See also compact disc − digital audio

Save As common dialog box

A common dialog box that displays a list of filenames matching any specified extensions, directories, or drives. By selecting one of the listed filenames, the user indicates what file an application should save. See also common dialog box.

scalable font

A TrueType font. See also TrueType font.

scaling

A transformation that alters the apparent size of an object.

scan code

A device-dependent value that identifies a physical key on the keyboard. Each key on a keyboard generates two unique scan codes--one when the user presses the key and the other when the user releases the key.

scan line

A single row of adjacent pixels on a video display. See also pixel.

scheduler

The component of the operating system that determines which of the competing threads receives the next slice of the processor's time. See also thread.

screen buffer

A two-dimensional array of character and color data for output in a console window. A screen buffer can be accessed for reading and writing whether it is active or inactive. Its character data can be either a Unicode™ or ANSI value. See also console window.

screen coordinates

Coordinates relative to the upper left corner of the screen.

scroll bar

An element of the Windows user interface that converts mouse or keyboard input into values that a window procedure can use to shift the contents of a window's client area either horizontally or vertically. See also window procedure.

scroll bar control

A predefined control window that belongs to the SCROLLBAR window class. See also window.

scroll box

A movable area in a scroll bar that indicates the position of the information currently displayed in the associated window. The position of the scroll box is relative to the total amount of information available for display. See also scroll bar.

scrolling

The process of shifting a data object in a window's client area in order to see parts of the object that extend beyond the border of the client area.

scrolling range

The minimum and maximum values that a scroll bar can report. See also scroll bar.

secant

A line drawn through two points on an ellipse. See also ellipse.

security descriptor

A structure that contains the security information associated with an object. An absolute security descriptor contains pointers to the information, and a self-relative security descriptor stores the structure and associated information contiguously in memory. See also absolute security descriptor, self-relative security descriptor.

security domain

A collection of nodes in a security database that share a common set of user and group accounts.

security identifier (SID)

A structure of variable length that uniquely identifies a user or group on all Windows NT™ implementations.

seek

(1) With file input and output (I/O), to change the current position in the file. (The current position is the location where the next read or write operation will take place.)

(2) With a media device (such as a hard disk), to position the medium so a certain sector can be accessed. The seek operation involves a physical movement of the device, so the time it takes can often be perceived by the user.

selection field

The portion of a combo box that displays the currently selected item. Selecting an item in the list causes that item to appear in the selection field. In simple and drop-down combo boxes, the selection field is an edit control and can be used to enter input not in the list.

self-relative security descriptor

See security descriptor.

semaphore object

An interprocess synchronization object that maintains a count between zero and some maximum value. The object's state is signaled when its count is greater than zero and nonsignaled when its count is zero. See also synchronization object.

sequence

See MIDI sequence.

sequencer

See MIDI sequencer.

service

An executable object that is installed in a registry database maintained by the Service Control Manager. The executable file associated with a service can be started at boot time by a boot program or by the system, or it can be started on demand by the Service Control Manager. The two types of service are Win32 service and driver service. See also driver service, Win32 service.

service control manager

A Windows NT system process that provides a unified and secure means of controlling Win32 and driver services. Each computer that is running Windows NT has a service control manager process that is started during system startup.

service name

A string that a server application responds to when a client attempts to establish a conversation with the server.

setmark

A special recorded element that contains no user data and is used to provide a segmentation scheme hierarchically superior to filemarks. Setmarks typically provide faster positioning on high-capacity tapes.

share mode

A condition that indicates whether a file is to be shared for reading, writing, both, or neither.

shared memory

Memory that two or more processes can read from and write to. If the file-mapping object that references the shared memory has a name, the memory is referred to as "named shared memory."

sharepoint

A network resource that remote applications can address specifically and use across a network--for example, a printer or a shared directory. See also container.

shearing

A transformation that alters the apparent length and orientation of vertical or horizontal lines in an object.

shell

An application that enables users to group, start, and otherwise control other applications.

short filemark

A filemark that contains a short erase gap that cannot be overwritten unless the write operation is performed from the beginning of the partition or from an earlier long filemark.

show state

The collective qualities of a window at a given time (whether active or visible; minimized; maximized; or restored).

shut down

To stop all processes, flush all file-system buffers to disk, and bring the system to a condition in which it is safe to turn off the computer.

sibling window

A child window that has the same parent window as one or more other child windows.

SID

See security identifier (SID).

signaled

The state of an object used for synchronization in one of the wait functions. A signaled state can enable the wait function to return. See also nonsignaled, wait function.

signature

A 4-byte value that identifies an enhanced metafile. See also enhanced metafile.

simple combo box

A combo box in which the list box is visible at all times.

simple device

A media control interface (MCI) device that does not require a device element (data file) for playback. The MCI compact disc audio driver is an example of a simple device.

simple list

A list in a combo box that is always visible. Combo boxes with the CBS_SIMPLE style contain simple lists.

single-byte character set

to their identifying numeric values, in which each value is one byte wide. The ANSI and original equipment manufacturer (OEM) character sets are single-byte character sets. See also character set, multibyte character set, Unicode.

single-selection list box

A list box in which only one item can be selected at a time.

sizing border A type of window border that enables the user to size the window by clicking and dragging the border.

SMPTE

See Society of Motion Picture and Television Engineers.

SMPTE division type

One of four SMPTE timing formats. SMPTE time is expressed in hours, minutes, seconds, and frames. The SMPTE division type specifies the frames-per-second value corresponding to a given SMPTE time. For example, a SMPTE time of one hour, 30 minutes, 24 seconds, and 15 frames is useful only if the frames-per-second value, or SMPTE division type, is known.

SMPTE offset

A Musical Instrument Digital Interface (MIDI) event that designates the SMPTE time at which playback of a MIDI file is to start. SMPTE offsets are used only with MIDI files using SMPTE division type.

SMPTE time

A standard representation of time developed for the video and film industries. SMPTE time is used with Musical Instrument Digital Interface (MIDI) audio because many people use MIDI to score films and video. SMPTE time is an absolute time format expressed in hours, minutes, seconds, and frames. Standard SMPTE division types are 24, 25, and 30 frames per second.

Society of Motion Picture and Television Engineers (SMPTE)

An association of engineers involved in movie, television, and video production. SMPTE also refers to SMPTE time, the timing standard that this group adopted.

solid brush

A logical brush created from a bitmap that contains pixels of the same color. See also bitmap, logical brush, pixel.

source

A configuration registry key that specifies message-file names for replacement strings in events logged by an application, service, or group of applications. Sources are subkeys of logfile keys. See also key, logfile, subkey.

square-wave synthesizer

A synthesizer that produces sound by adding square waves of various frequencies. A square wave is a rectangular waveform.

standard cursors

The default cursors that Windows automatically displays when users move windows or icons, resize windows, or wait. Standard cursors include an arrow, hourglass, crosshair, and I-beam. Standard cursors are also known as system cursors. See also cursor, icon, window.

standard icons

The default icons that Windows displays in system message boxes. Standard icons include, among other bitmaps, a stop sign and a circled exclamation point. See also icon.

standard resource

A resource whose format is defined and recognized by Windows. Standard resources include icons, cursors, menus, dialog boxes, bitmaps, fonts, keyboard accelerator tables, message-table entries, string-table entries, and version data.

standard scroll bar

A scroll bar created as part of the nonclient area of an overlapped, pop-up, or child window. See also scroll bar.

standard VGA

A video adapter that supports a resolution of 640 by 480 pixels and 16 simultaneous colors. See also pixel.

static control

An element of the Windows user interface used to display text and graphics that require no response from the user. Static controls are typically used in dialog boxes.

stock brush

One of seven logical brushes maintained by Windows. See also logical brush.

stock pen

A cosmetic pen created and maintained by the window manager. There are three kinds of stock pens: black, white, and invisible. See also cosmetic pen.

streaming

The process of transferring information from a storage device, such as a hard disk or CD-ROM, to a device driver.

string atom

An atom that identifies a character string in an atom table. See also atom, atom table.

string handle

A doubleword value, assigned by the operating system, that identifies a string passed between a dynamic data exchange (DDE) client and a DDE server. See also dynamic data exchange (DDE).

stroked path

A path that is outlined by using the pen that is currently selected into an application's device context. See also device context, path, pen.

structured exception handling

A mechanism for handling hardware- and software-generated exceptions. Structured exception handling gives developers complete control over the handling of exceptions, provides support for debuggers, and is usable across all programming languages and computers.

style names

One of two attributes used to organize TrueType® fonts. Style names include extra-bold, bold, and italic. (The other attribute used to organize TrueType fonts is the family name.) See also TrueType font.

subclass procedure

An application-defined window procedure that replaces a window's original window procedure when the window is subclassed. See also subclassing, window procedure.

subclassing

A technique that allows an application to intercept and process messages sent or posted to a particular window before the window has a chance to process them. See also subclass procedure.

subdirectory

A directory within another directory. See also directory.

subkey

An entry (or node) in the registry subordinate to a given key. With the exception of four predefined keys, all keys are subkeys of other keys. See also key, registry.

sublanguage identifier

An 8-bit value identifying the variant of a language in a language identifier. See also language identifier, primary language identifier.

subtractive color technology

The color technology, used by ink-based printers, that is based on the three primary colors cyan, yellow, and magenta. Other colors (except white) are obtained by combining two or more of the primaries in varying amounts. White is defined as the absence of the primaries. Black is defined as the presence of all the primaries.

super VGA

A video adapter that supports resolutions higher than 640-by-480 pixels or more than 16 simultaneous colors (or both).

superclass procedure

An application-defined window procedure that replaces the window procedure for a window of a particular window class when the class is superclassed. See also superclassing, window procedure.

superclassing

A technique that allows an application to create a new window class that has the basic functionality of the existing class, but with enhancements provided by the application. See also superclass procedure.

syllabary

A single character that represents what we would call a syllable, using consonant/vowel combinations as their linguistically-discrete units — for example, the sound created by "ta." This term would apply to Kana (Katakana and Hiragana) and Hangul scripts. Linguists use the word "syllabary" to define a system of phonemic (linguistically-distinct) syllabic units used in a language.

synchronization object

An object whose handle can be specified in one of the wait functions to coordinate the execution of multiple threads. Synchronization objects include change notification, console input, event, mutex, process, thread, and semaphore objects. See also object, wait function.

system access-control list (SACL)

An access-control list (ACL) that is controlled by a system administrator and used to control the generation of audit messages. See also access-control list (ACL), discretionary access-control list (DACL).

system directory

The directory that contains Windows libraries, drivers, and font files. See also directory.

system-exclusive data

In Musical Instrument Digital Interface (MIDI), messages understood only by MIDI devices from a specific manufacturer. MIDI device manufacturers can use system-exclusive data to define custom messages that can be exchanged between their MIDI devices. (The standard MIDI specification defines only a framework for system-exclusive messages.) See also Musical Instrument Digital Interface.

System menu

A pop-up menu, defined mainly by the operating system, that typically contains commands used to set a window's size or position, close a window or application, or activate a different application. See also pop-up menu.

system metric

A dimension of a Windows display element, such as the border width, scroll bar arrow height, icon height, and so on. System metrics may also describe other aspects of the operating system, such as whether a mouse is installed, whether the current version of Windows supports double-byte characters, and so on. See also scroll bar.

system paging file

The storage file that the kernel uses to hold pages of memory swapped out of RAM.

system palette

An array that identifies all of the colors that can be displayed simultaneously on a device. For most displays, this array is a subset of all possible colors that can appear on the display.

system time

The "real-time" clock format. System time uses a structure containing individual members for the date and time.


 T

tagged file format

A file format in which data is tagged using standard headers that identify information type and length. See also Resource Interchange File Format (RIFF).

tape drive

A device that reads from and writes to a tape.

tape volume

A recording medium and its physical carrier.

tempo

The speed at which a Musical Instrument Digital Interface (MIDI) file is played. Tempo is measured in beats per minute (BPM); typical MIDI tempo is 120 BPM. See also Musical Instrument Digital Interface.

tension

To move the tape to the end-of-medium marker and back to the beginning-of-medium marker in one command.

termination handler

A mechanism by which a developer ensures that a block of termination code is executed. A termination handler consists of a guarded body of code and a termination block. See also guarded body of code.

thread

The basic entity to which the operating system allocates CPU time. A thread can execute any part of the application's code, including a part currently being executed by another thread. All threads of a process share the virtual address space, global variables, and operating system resources of the process. See also process.

thread affinity mask

A bit vector in which each bit represents the processors that a thread is allowed to run on.

thread local storage

A storage method in which an index can be used by multiple threads of the same process to store and retrieve a different value for each thread. See also thread.

threshold

For the joystick interface, the amount, in device units, that the stick coordinates must change before the application is notified of the movement. A high threshold reduces the number of joystick messages sent to an application, but it also reduces the sensitivity of the joystick.

time-out value

The interval, in milliseconds, measured by a timer.

timer

An internal routine that causes the system to send a WM_TIMER message whenever a specified interval elapses.

time slice

A unit of processor time (in clock ticks) allocated to a thread. See also thread.

time stamp

A tag that enables a Musical Instrument Digital Interface (MIDI) sequencer to replay recorded MIDI data at the proper moment. See also Musical Instrument Digital Interface.

title bar

A window component that displays an application-defined line of text. Typically, the text identifies the application or indicates the purpose of the window.

TLS

See thread local storage.

TMSF time format

A time format used by Media Control Interface (MCI) to express time in tracks, minutes, seconds, and frames. The number of frames in a second depends on the type of device being used; compact disc audio devices use 75 frames per second. The TMSF time format is used primarily by compact disc audio devices. See also Media Control Interface (MCI).

token

See access token.

top-down DIB

A device-independent bitmap (DIB) whose origin lies at the top-left corner. See also bottom-up DIB.

top-level window

A window that has no parent window.

topic name

A string that identifies the type of data requested by a dynamic data exchange (DDE) client application.

topmost window

A window with the WS_EX_TOPMOST style. A topmost window overlaps all other non-topmost windows.

track

A sequence of sound on a compact disc − digital audio (CD-DA) disc. With a Musical Instrument Digital Interface (MIDI) file, information can be separated into tracks, defined by the creator of the file. MIDI file tracks can correspond to MIDI channels, or they can correspond to parts of a song (such as melody or chorus); a CD-DA track usually corresponds to a song. See also compact disc − digital audio.

transaction filter

A flag that prevents the Data Exchange Management Library (DDEML) from passing an unwanted type of transaction to an application's dynamic data exchange (DDE) callback function. See also dynamic data exchange (DDE).

transformation

An algorithm that alters ("transforms") the size, orientation, and shape of objects.

translation

A transformation that shifts an object farther from or closer to the coordinate-space origin.

TrueType font

A font whose glyphs are stored as a collection of line and curve commands plus a collection of hints. Windows uses the line and curve commands to define the outline of the glyph's bitmap. Windows uses the hints to adjust the length of the lines and shapes of the curves. These hints and the respective adjustments are based on the amount of scaling used to reduce or increase the size of the bitmap. See also bitmap, font, glyph.

try block

A guarded body of code in a try-except frame-based exception handler or try-finally termination handler. See also frame-based exception handler, guarded body of code, termination handler.


 U

Unicode

A 16-bit character set capable of encoding all known characters and used as a worldwide character-encoding standard. Windows uses Unicode exclusively at the system level.

universal well-known security identifier (SID)

An SID that is meaningful on all secure systems using the security model implemented in Windows NT™.

user-defined pen

A cosmetic or geometric pen that uses a unique series of dashes, dots, or dashes and dots defined by the user. See also cosmetic pen, geometric pen.

UTC

See Coordinated Universal Time.


 V

value

Data associated with a key. A key may have zero or more values. Each value has three parts: a name, a type, and data. See also key.

vector device

A device that creates text and graphics output by drawing lines.

viewport

A rectangle in device space that is used to specify a transformation between page and device space. The viewport extents are always measured in pixels for a video display or dots for printers.

viewport extent

The width or height of the viewport.

viewport origin

The corner of the viewport from which the extents are measured. (The viewport-origin coordinates are specified with respect to the device-space origin.)

virtual-key code

A device-independent value that identifies the purpose of a keystroke as interpreted by the Windows keyboard device driver.

visible region

The part of the client area that is visible to the user.

visible window

A window that has the WS_VISIBLE style. A visible window is displayed on the screen and can receive user input.

volatile key

A key that is valid only until the next time the operating system is started. See also key.

volume

A storage medium, such as a disk or tape, that is formatted to contain files and directories. A volume is accessed through a disk drive. In a path, a volume is referenced by the letter of the disk drive that accesses the volume. For example, a fixed disk may be referred to as C. A single volume may be divided into more than one logical volume, also called a partition. Each partition is referenced by a unique volume identifier.

volume scalar

A component of a Musical Instrument Digital Interface (MIDI) Mapper patch map that adjusts the volume of a patch on a synthesizer. For example, if the bass patch on a synthesizer is too loud relative to the piano patch, the volume scalar can reduce the volume for the bass or increase the volume for the piano. (Applications playing waveform audio can also adjust the output volume.) See also MIDI Mapper, patch.


 W

wait function

A function that blocks the execution of the calling thread until a specified set of conditions has been satisfied.

waiting thread

A thread whose execution is blocked while waiting for a wait function to return. See also wait function.

WAVE file

A Microsoft standard file format for storing waveform audio data. WAVE files have a .WAV filename extension.

waveform audio

A technique of recreating an audio waveform from digital samples of the waveform.

wide character

A synonym for a Unicode™ character; Unicode characters are 2 bytes wide.

widened path

A modified path. See also path.

wildcard characters

Characters that represent one or more characters in a filename. The Windows wildcard characters are the question mark (?) and the asterisk (*). The question mark matches any single character; the asterisk matches any combination of characters. For example, if a directory contains files with the names BAT, B12, BOAT, and CAT, the pattern b\* matches the names BAT, B12, and BOAT. The pattern b?t matches only the name BAT.

Win32 service

A service that conforms to the interface rules of the Service Control Manger. This enables the Service Control Manager to start the service at system startup or on demand and enables communication between the service and service control programs. A Win32 service can execute in its own process, or it can share a process with other Win32 services.

window

A rectangle in page space that is used to specify a transformation between page and device space.

window extent

The width or height of the window.

window handle

A 32-bit value, assigned by Windows, that uniquely identifies a window.

window name

A text string that identifies a window for the user.

window origin

(1) The upper left corner of a window's client area.

(2) The corner of the window from which the extents are measured. (The window-origin coordinates are specified with respect to the page-space origin.)

window procedure

A function, called by the operating system, that controls the appearance and behavior of its associated windows. The procedure receives and processes all messages to these windows.

window style

A named constant that defines an aspect of the window's appearance and behavior not specified by the window's class.

window text

See window name.

Windows directory

The directory that contains Windows-based applications, initialization files, and Help files. See also directory.

Windows metafile

One of two metafile formats. This format, used for applications written to run with Windows version 3.x, consists of a header and an array of metafile records. See also metafile record.

Windows time

The number of milliseconds since Windows started running. This time is recorded as a 32-bit value, so it overflows to zero every 49.7 days.

world coordinate space

The coordinate space in which all graphics device interface (GDI) drawing operations begin if an application has set the world-space to page-space transformation.

world space

The coordinate space in which all graphics device interface (GDI) drawing operations begin if an application has set the world-space to page-space transformation. Applications use world space to rotate shear, or reflect graphics output. World space measures 2^(32) units high by 2^(32) units wide, and is one of four coordinate spaces used in the Win32 API. See also device coordinate space, page coordinate space, and physical device.


 X

x-axis

The axis that normally extends horizontally across a coordinate space.


 Y

y-axis

The axis that normally extends vertically across a coordinate space.


 Z

Z order

A stack of overlapping windows. Each window has a unique position in the Z order.


16-Bit App WNetGetCaps Call Return Value on Win32

PSS ID Number: Q120359

Authored 08-Sep-1994	Last modified 10-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.5, 3.51,

   and 4.0

16-bit Windows-based applications often call WNetGetCaps() to determine the

capabilities of the installed network. When a Windows-based application

running on Windows NT calls WNetGetCaps(), the return value is 0x8004,

which corresponds to WNNC_NET_Multinet | WNNC_SUBNET_WinWorkgroups.

However, the Windows NT Windows on Windows (WOW) layer and Windows 95 do

not support the Windows for Workgroups Multinet (MNet) APIs, so a call to

one of these APIs returns a failed Dynalink error.

The return value of WNetGetCaps() may not seem technically correct for

Windows for Workgroups. It was designed to be compatible with all existing

16-bit Windows-based applications.

If you need to determine whether a 16-bit Windows-based application is

running on Windows NT or MS-DOS/Windows version 3.1, use GetWinFlags().

GetWinFlags() returns a WF_WINNT flag if the application is running under

WOW on Windows NT.

GetWinFlags() is an existing function that was modified in WOW to add the

following flag:

   #define WF_WINNT         0x4000

Additional reference words: 3.50 4.00

KBCategory: kbprg

KBSubcategory: SubSys


32-Bit Scroll Ranges

PSS ID Number: Q104311

Authored 13-Sep-1993	Last modified 16-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.1 and 3.5

You can use 32-bit scroll ranges by calling GetScrollPos(); however, you

cannot get 32-bit positions for notifications sent while thumb tracking,

that is, via the SB_THUMBPOSITION message. This is because thumb position

information is not queryable via an application programming interface

(API). You only can obtain the 32-bit scroll information only before or

after the scroll has taken place.

The scroll bar APIs allow setting a scroll range up to 0x7FFFFFFF via

SetScrollRange(), and setting a scroll position within that range using

SetScrollPos(). If the WM_HSCROLL or WM_VSCROLL message is processed, the

information returned for scroll bar position, nPos, is only a 16-bit value.

To obtain the 32-bit information, the GetScrollPos() API must be used.

Additional reference words: 3.10 3.50 scrollbar

KBCategory: kbprg

KBSubcategory: UsrCtl


Accessing Parent Window's Menu from Child Window w/ focus

PSS ID Number: Q92527

Authored 09-Nov-1992	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.1 and 3.0

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

In an MDI-like application, the user must be allowed to pull down menus in

the parent window by using menu mnemonics even though the child window or

one of its children may have the focus. This can be done by creating child

windows without a system menu or by processing the WM_MENUCHAR and

WM_SYSCOMMAND/SC_KEYMENU messages to programatically pull down the parent's

menu.

MORE INFORMATION

If a child window with a system menu has the focus and the user attempts to

access the parent's menu with the keyboard using the menu mnemonic

(ALT+mnemonic character), Windows will beep and the parent's menu will not

be pulled down. This problem occurs because the parent window does not have

the focus and because the window with the focus does not have a menu

corresponding to the mnemonic. (Child windows cannot have menus other than

the system menu.)

If the child window with the focus does not have a system menu, Windows

assumes that the menu mnemonic is for the nearest ancestor with a system

menu and passes the message to that parent. Consequently, it is possible to

use menu mnemonics to pull down a parent's menu if the descendant windows

do not have system menus.

If the child window with the focus has a system menu, Windows will beep if

a menu mnemonic corresponding to a parent menu is typed. This can be

prevented and the parent menu can be dropped down using the following code

in the window procedure of the child window:

 case WM_MENUCHAR:

    PostMessage(hwndWindowWithMenu, WM_SYSCOMMAND, SC_KEYMENU, wParam);

    return(MAKELRESULT(0, 1));

WM_MENUCHAR is sent to the child window when the user presses a key

sequence that does not match any of the predefined mnemonics in the current

menu. wParam contains the mnemonic character. The child window posts a

WM_SYSCOMMAND/SC_KEYMENU message to the parent whose menu is to be dropped

down, with lParam set to the character that corresponds to the menu

mnemonic.

The above code can also be used if the child window with the focus does not

have a system menu but an intermediate child window with a system menu

exists between the child with the focus and the ancestor whose menu is to

be dropped. In this case, the code would be placed in the intermediate

window's window procedure.

Additional reference words: 3.10 3.00 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrMen


Accessing the Application Desktop from a Service

PSS ID Number: Q115825

Authored 05-Jun-1994	Last modified 13-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.5 and 3.51

SUMMARY

Under Windows NT, version 3.1, if you want a service to have access to the

application desktop, you must run the service in the LocalSystem account. A

service process running in the LocalSystem account (or a process started

from such a service) can display message boxes, windows, and dialog boxes.

Processes that are running in the LocalSystem account are not terminated by

the system during logoff. A number of changes were made to Windows NT,

version 3.5, that affect the way Windows NT interacts with these services.

In addition, Windows NT 3.51 has a richer set of desktop APIs.

NOTE: Running interactive services under the system account is a VERY

dangerous practice. This is especially true of the command processor and

batch files. A user who wants to control the system can just hit CTRL+C

to get an interactive system command prompt.

MORE INFORMATION

The following are new features of Windows NT, version 3.5, that affect

services:

 - The account of the logged in user is the only account granted access to

   the application desktop. The LocalSystem no longer has access.

   Therefore, it is possible to get access to the desktop by impersonating

   the user before making any USER or GDI calls.

 - Console and GUI applications started from a service process during a

   particular logon session are run on an invisible window station and

   desktop that are unique to that session. The window station and desktop

   are created automatically when the first application in the session

   starts; they are destroyed when the last application exits. There is no

   way to make these invisible desktops visible.

 - If you want a service to interact with the logged-on user, specify the

   SERVICE_INTERACTIVE_PROCESS flag in the call to CreateService(). For

   example:

      schService = CreateService(

         schSCManager,

         serviceName,

         serviceName,

         SERVICE_ALL_ACCESS,

         SERVICE_INTERACTIVE_PROCESS | SERVICE_WIN32_OWN_PROCESS,

         SERVICE_DEMAND_START,

         SERVICE_ERROR_NORMAL,

         lpszBinaryPathName,

         NULL,

         NULL,

         NULL,

         NULL,

         NULL );

 - If you use CreateProcess() to launch your process and you want your

   service to log onto the users desktop, assign the lpdesktop parameter of

   the STARTUPINFO struct with "WinSta0\\Default".

 - Services that simply need a visible user notification can do this by

   calling MessageBox() with the MB_SERVICE_NOTIFICATION flag. Using the

   MB_DEFAULT_DESKTOP_ONLY flag works as well, but only if the user's

   desktop is active. If the workstation is locked or a screen saver is

   running, the call will fail.

   NOTE: If you are writing code for an application that can be run as

   either a service or an executable, you can't use MB_SERVICE_NOTIFICATION

   as well as a non-NULL hwndOwner.

 - Any output done to a window is not displayed or made available to  the

   application in any way. Attempts to read bits from the display results

   in a failure.

 - GUI services do not receive WM_QUERYENDSESSION/WM_ENDSESSION messages

   at logoff and shutdown; instead, they receive CTRL_LOGOFF_EVENT

   and CTRL_SHUTDOWN_EVENT events. These services are not terminated by the

   system at logoff.

Additional reference words: 3.50

KBCategory: kbprg

KBSubcategory: BseService


Accessing the Event Logs

PSS ID Number: Q108230

Authored 07-Dec-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

SUMMARY

Event logs are used to store significant events, such as warnings, errors,

or information. There are five operations that can be performed on event

logs through the event logging application programming interface (API):

backup, clear, query, read, and write.

The default event logs are the Application event log, the Security event

log, and the System event log. Access to these event logs is determined by

which account the application is running under.

MORE INFORMATION

The following table shows which accounts are granted access to which logs

and what type of access is granted under Windows NT 3.1:

   Log           Account     Access Granted

   -------------------------------------------

   Application   LocalSys    read write clear

                 Admins      read write clear

                 ServerOp    read write clear

                 World       read write

   Security      LocalSys    read write clear

                 Admins      read       clear

   System        LocalSys    read write clear

                 Admins      read       clear

                 ServerOp    read       clear

                 World       read

   -------------------------------------------

   Table 1 - access granted in Windows NT 3.1

The Local System account (LocalSys) is a special account that may be used

by Windows NT services. The Administrator account (Admins) consists of the

administrators for the system. The Server Operator account (ServerOp)

consists of the administrators of the domain server. The World account

includes all users on all systems.

Changes made were for Windows NT 3.5:

   Log           Account     Access Granted

   -------------------------------------------

   Application   LocalSys    read write clear

                 Admins      read write clear

                 ServerOp    read write clear

                 World       read write

   Security      LocalSys    read write clear

                 Admins      read       clear

                 World       read       clear *

   System        LocalSys    read write clear

                 Admins      read write clear **

                 ServerOp    read       clear

                 World       read

   -------------------------------------------

   Table 2 - access granted under Windows NT 3.5

    * Users that have been granted manage auditing and security log rights

      can read and clear the Security log.

   ** Admins can write to the System log.

The following table shows which types of access are required for the

corresponding event logging API:

   Event Logging API         Access Required

   -------------------------------------------

   OpenEventLog()            read

   OpenBackupEventLog()      read

   RegisterEventSource()     write

   ClearEventLog()           clear

   -------------------------------------------

   Table 3 - access required for event logging APIs

As an example, OpenEventLog() requires read access (see Table 2). A member

of the ServerOp account can call OpenEventLog() for the Application event

log and the System event log, because ServerOp has read access for both of

these logs (see Table 1). However, a member of the ServerOp account cannot

call OpenEventLog() for the Security log, because it does not have read

access for this log (see Table 1).

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseMisc


Accessing the Macintosh Resource Fork

PSS ID Number: Q106663

Authored 11-Nov-1993	Last modified 02-Mar-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

Resource forks are implemented as NTFS streams named AFP_Resource. There is

no structure to the fork; it is exactly whatever the Macintosh writes to

it. The resource fork can be written to using standard Win32 application

programming interfaces (APIs). Refer to the forks as

<FileName>:AFP_Resource.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseMisc


Accurately Showing on the Screen What Will Print

PSS ID Number: Q75469

Authored 21-Aug-1991	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

Many applications have an option where the screen display is set to

closely correspond to the printed output. This article discusses some

of the issues involved in implementing this feature.

MORE INFORMATION

If a screen font is available that exactly matches (or at least very

closely corresponds to) the chosen printer font, then the process is

very straightforward and consists of seven steps:

1. Retrieve a device context (DC) or an information context (IC) for

   the printer.

2. Call EnumFontFamilies() to obtain a LOGFONT structure for the chosen

   printer font. The nFontType parameter to the EnumFontFamilies() callback

   function specifies if a given font is a device font.

3. Get a DC for the screen.

4. Convert the lfHeight and lfWidth members of the LOGFONT structure

   from printer resolution units to screen resolution units. If a

   mapping mode other than MM_TEXT is used, round-off error may occur.

5. Call CreateFontIndirect() with the LOGFONT structure.

6. Call SelectObject(). GDI will select the appropriate screen font to

   match the printer font.

7. Release the printer device context or information context and the

   screen device context.

If a screen font that corresponds to the selected printer font is not

available, the process is more difficult. It is possible to modify the

character placement on the screen to match the printer font to show

justification, line breaks, and page layout. However, visual

similarity between the printer fonts and screen fonts depends on a

number of factors, including the number and variety of screen fonts

available, the selected printer font, and how the printer driver

describes the font. For example, if the printer has a serifed Roman-

style font, one of the GDI serifed Roman-style fonts will appear to be

very similar to the printer font. However, if the printer has a

decorative Old English-style font, no corresponding screen font will

typically be available. The closest available match would not be very

similar.

To have a screen font that matches the character placement of a

printer font, do the following:

1. Perform the seven steps above to retrieve an appropriate screen

   font.

2. Get the character width from the TEXTMETRIC structure returned by

   the EnumFonts function in step 2 above. Use this information to

   calculate the page position of each character to be printed in the

   printer font.

3. Allocate a block of memory and specify the spacing between

   characters. Make sure that this information is in screen resolution

   units.

4. Specify the address of the memory block as the lpDx parameter to

   ExtTextOut(). GDI will space the characters as listed in the array.

Additional reference words: 3.00 3.10 3.50 4.00 95 WYSIWYG

KBCategory: kbprg

KBSubcategory: GdiPrn


Action of Static Text Controls with Mnemonics

PSS ID Number: Q65883

Authored 26-Sep-1990	Last modified 18-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.1 and 3.0

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

The text of a static control may contain a mnemonic, which is a

character with which the user can access the control. A mnemonic is

indicated to the user by underlining the character in the text of the

control, and is created by preceding the desired character with an

ampersand (&).

Mnemonic characters are used in conjunction with the ALT key to allow

quick access to a control with the keyboard. When the user enters the

key combination of the ALT key and the mnemonic character, Windows

sets the input focus to the corresponding control and performs the

same action as when the mouse is clicked on that control. Push

buttons, option buttons, and check boxes all behave in this manner.

Because static text controls do not accept the focus, the behavior of

a mnemonic in a static text control is different. When the user enters

the mnemonic of a static text control, the focus is set to the next

enabled nonstatic control. A static text control with a mnemonic is

primarily used to label an edit control or list box. When the user

enters the mnemonic, the corresponding control gains the focus.

In this context, the order in which windows are created is important.

In a dialog box template, the control defined on the line following

the static text control is considered to be "next."

When the user enters the mnemonic of a static text control and the

next control is either another static text control or a disabled

control, Windows searches for a control that is nonstatic and enabled.

In some cases, it may be preferable to disable the mnemonic of a

static text control when the control it labels is also disabled. For

more information, please query in the Microsoft Knowledge Base on the

following word:

   mnemonic

MORE INFORMATION

The dialog box described by the following dialog box template might be

displayed by an application when the user chooses Open from the File

menu:

IDD_FILEOPEN DIALOG LOADONCALL MOVEABLE DISCARDABLE 9, 22, 178, 112

CAPTION "File Open..."

STYLE WS_CAPTION | DS_MODALFRAME | WS_SYSMENU | WS_VISIBLE | WS_POPUP

BEGIN

   CONTROL "File&name:", ID_NULL, "static",

           SS_LEFT | WS_GROUP | WS_CHILD, 5, 5, 33, 8

   CONTROL "", ID_NAMEEDIT, "edit",

           ES_LEFT | ES_AUTOHSCROLL | WS_BORDER | WS_TABSTOP

           | WS_CHILD | ES_OEMCONVERT, 40, 4, 90, 12

   CONTROL "Directory:", ID_NULL, "static", SS_LEFT | WS_CHILD,

           5, 20, 35, 8

   CONTROL "", ID_PATH, "static", SS_LEFT | WS_CHILD, 40, 20, 91, 8

   CONTROL "&Files:", ID_NULL, "static", SS_LEFT | WS_GROUP

           | WS_CHILD, 5, 33, 21, 8

   CONTROL "", ID_FILELIST, "listbox", LBS_NOTIFY | LBS_SORT

           | LBS_STANDARD | LBS_HASSTRINGS | WS_BORDER | WS_VSCROLL

           | WS_TABSTOP | WS_CHILD, 5, 43, 66, 65

   CONTROL "&Directories:", ID_NULL, "static", SS_LEFT | WS_GROUP

           | WS_CHILD, 75, 33, 49, 8

   CONTROL "", ID_DIRLIST, "listbox", LBS_NOTIFY | LBS_SORT

           | LBS_STANDARD | LBS_HASSTRINGS | WS_BORDER | WS_VSCROLL

           | WS_TABSTOP | WS_CHILD, 75, 43, 65, 65

   CONTROL "OK", IDOK, "button", BS_DEFPUSHBUTTON | WS_TABSTOP

           | WS_CHILD, 139, 4, 35, 14

   CONTROL "Cancel", IDCANCEL, "button", BS_PUSHBUTTON | WS_TABSTOP

           | WS_CHILD, 139, 23, 35, 14

END

In this dialog box, one static text control, with identifier ID_PATH,

is used to display the current path. The other four static text

controls label other controls, as follows:

   "File&name"         labels the ID_NAMEEDIT edit control

   "Directory"         labels the ID_PATH static control display

   "&Files"            labels the ID_FILELIST list box

   "&Directories"      labels the ID_DIRLIST list box

When the user enters the key combination ALT+N, Windows sets the focus

to the edit control identified in the dialog template as ID_NAMEEDIT,

because it is the next enabled nonstatic control. If that edit control

was disabled by the EnableWindow function, pressing ALT+N would move

the focus to the next enabled nonstatic control. This control would be

the list box identified as ID_FILELIST.

Note that the static control "Directory" has no mnemonic; therefore,

keyboard input does not affect it.

When the user enters ALT+F, the focus moves to the ID_FILELIST list

box, if it is enabled. In the same manner, ALT+D moves the focus to

the ID_DIRLIST list box.

If ID_DIRBOX is disabled, ALT+D moves the focus to the OK button, the

next enabled nonstatic control. Windows treats this as if the user

pressed and released the mouse button over the OK button. For more

information on how to prevent this behavior, query the Microsoft

Knowledge Base on the following word:

   mnemonic

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95 radio shortcut

KBCategory: kbprg

KBSubcategory: UsrCtl


Add-On Allows SystemParameterInfo() to Get/Set System

PSS ID Number: Q125695

Authored 01-Feb-1995	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

The SystemParameterInfo() API provides functionality to set and get many

Windows System Parameters based on the action flag if Windows extension #1

is installed. Here are some examples:

 - The Full Window Drag system parameter can be retrieved or set by using

   SPI_GETDRAGFULLWINDOWS/SPI_SETDRAGFULLWINDOWS as the action flag in the

   SystemParameterInfo() API. When full drag windows is enabled, users can

   move entire windows instead of just moving the outline. This makes it

   easier to see how a window looks while being resized. This feature is

   not available with Windows, so calling SystemParameterInfo using the

   SPI_GETDRAGFULLWINDOWS or SPI_SETDRAGFULLWINDOWS flag will always fail.

   However, this feature will be available if an add-on product, Windows

   extension #1, is installed.

 - The Font Smoothing setting can be retrieved or set by using

   SPI_GETFONTSMOOTHING or SPI_SETFONTSMOOTHING as the action flag

   in the SystemParameterInfo() API. Enabling this system setting tells

   Windows to draw smooth characters using font anti-aliasing. This feature

   is not available with Windows. Thus the call to SystemParameterInfo with

   the SPI_GETFONTSMOOTHING or SPI_SETFONTSMOOTHING flag will always fail.

   However, this Font Smoothing feature will be available if an add-on

   product, Windows extension #1, is installed.

 - SystemParameterInfo(SPI_GETWINDOWSEXTENSION, 1,  0,  0) returns true if

   Windows extension #1 is installed otherwise false. The Second parameter

   denotes Windows extension #1.

Additional reference words: 4.00 95

KBCategory: kbprg

KBSubcategory: UsrWnd


Adding a Custom Template to a Common Dialog Box

PSS ID Number: Q86720

Authored 15-Jul-1992	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK, version 3.5

SUMMARY

Many applications developed for the Microsoft Windows environment using

dialog boxes from the common dialogs library (COMMDLG.DLL) require custom

dialog templates. An application generally uses a custom dialog box

template to add controls to a standard common dialog box. The text below

discusses the steps required to implement a custom dialog box template with

a common dialog box.

A custom dialog box template is most often used in conjunction with a hook

function. For details on using a hook function with one of the common

dialog boxes, query on the following words in the Microsoft Knowledge Base:

   steps adding hook function

MORE INFORMATION

CDDEMO, one of the advanced sample applications provided with version 3.1

of the Microsoft Windows Software Development Kit (SDK), demonstrates

adding a hook function to the File Open dialog box. The five steps required

to modify the CDDEMO application to use a custom dialog box template in its

File Open dialog box are as follows:

 1. Edit the FILEOPEN.DLG template in the Windows SDK advanced sample

    applications directory (by default, C:\WINDEV\SAMPLES\COMMDLG). All

    existing controls must remain in the dialog template; add

    additional controls, if desired. To demonstrate the process, make a

    copy of the FILEOPEN.DLG template and include it in the CDDEMO.RC

    file. Modify the title of the "Cancel" button to "CANCEL." Renaming

    the button minimizes the potential for error while demonstrating

    that the application loaded the custom dialog box template.

 2. In the application, modify the Flags member of the OPENFILENAME

    data structure to include the OFN_ENABLETEMPLATE initialization

    flag.

 3. Specify MAKEINTRESOURCE(FILEOPENORD) as the value of the

    lpTemplateName member of the OPENFILENAME data structure.

 4. Specify ghInst as the value of the hInstance member of the

    OPENFILENAME data structure.

 5. Use the #include directive to include DLGS.H in the CDDEMO.RC file.

If an application adds a hook function to a common dialog box, the hook

receives all messages addressed to the dialog box. With the exception of

the WM_INITDIALOG message, the hook function receives messages before its

associated common dialog box does. If the hook function processes a message

completely, it returns TRUE. If the common dialog box must provide default

processing for a message, the hook function returns FALSE.

In the hook function, the application should process messages for any new

controls added through the custom dialog box template. If the standard

common dialog box template contains a control that is unnecessary in a

particular application, hide the control when the hook function processes

the WM_INITDIALOG message. Use the ShowWindow() API to hide a control; do

not delete any controls from the common dialog box template. To indicate

that the common dialog boxes DLL does not function properly if any controls

are missing, the debug version of Windows displays FatalExit 0x0007.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: UsrCmnDlg


Adding a Hook Function to a Common Dialog Box

PSS ID Number: Q86721

Authored 15-Jul-1992	Last modified 12-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

Many applications developed for the Microsoft Windows environment using

dialog boxes from the common dialogs library (COMMDLG.DLL) require hook

functions. A hook function for one of the common dialog boxes is similar to

a subclass procedure for a standard Window control, such as an edit

control. Through a hook function, an application can process all messages

addressed to the dialog box. The text below discusses the steps required to

implement a hook function with a common dialog box.

A hook function is most often used in conjunction with a custom dialog

template. For details using a custom dialog template with one of the

common dialog boxes, query on the following words in the Microsoft

Knowledge Base:

   steps add custom template

MORE INFORMATION

The hook function receives all messages addressed to a common dialog box.

With the exception of the WM_INITDIALOG message, the hook function receives

messages before its associated common dialog box does. If the hook function

processes a message completely, it returns TRUE. If the common dialog box

must provide default processing for a message, the hook function returns

FALSE.

CDDEMO, one of the advanced sample applications provided with version 3.1

of the Microsoft Windows Software Development Kit (SDK), demonstrates

adding a hook function to the File Open dialog box. The eight steps

involved in this process are as follows:

 1. Add the standard common dialog box to the application without the

    hook function.

 2. In the application's module definition (DEF) file, list the hook

    procedure name (for example, MyHookProc) in the EXPORTS section.

 3. Define a FARPROC variable (for example, lpfnHookProc)

 4. In the application, before completing the OPENFILENAME data

    structure, call the MakeProcInstance function to create a procedure

    instance address for the hook procedure.

 5. Set the lpfnHook member of the OPENFILENAME data structure to the

    procedure address of the hook function.

 6. Specify OFN_ENABLEHOOK as one of the initialization flags in the

    Flags member of the OPENFILENAME structure.

 7. Code the hook function to process messages as required. A sample

    hook function follows below.

 8. After the user dismisses the common dialog box, call the

    FreeProcInstance function to free the procedure instance address.

The following code is a sample hook function:

   BOOL FAR PASCAL MyHookProc(HWND hDlg, unsigned message,

                              WORD wParam, LONG lParam)

   {

      switch (message)

      {

         case WM_INITDIALOG:

            OutputDebugString("Hello hook function!");

            return TRUE;

         case WM_COMMAND:

            switch(wParam)

            {

               case IDD_MYNEWCONTROL:

               // Perform appropriate processing here...

                  return TRUE;

               default:

                  break;

            }

            break;

         default:

            break;

      }

      return FALSE;

   }

Additional reference words: 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrCmnDlg


Adding Categories for Events

PSS ID Number: Q115947

Authored 07-Jun-1994	Last modified 03-Mar-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   versions 3.1, 3.5, and 3.51

SUMMARY

The ReportEvent() API accepts a category ID as one of the arguments. The

"Microsoft Win32 Programmer's Reference" states that you can add your own

categories for events. This article shows you how to add categories that

will be recognized by the Event Viewer; however, the article assumes that

you already know how to create a message file and add an event source to

the registry. For information about basic event logging, please see the

logging sample in the Q_A\SAMPLES\logging directory on the "Win32 SDK" CD.

NOTE: The logging example that comes with Visual C++ 2.0 does not bind the

MESSAGES.RC to the MESSAGES.DLL unlike the logging example that accompanies

the Win32 SDK or NSDN Level 2. Binding MESSAGES.RC to the MESSAGES.DLL can

be accomplished by adding MESSAGES.RC to MESSAGES.MAK.

NOTE: If you notice that there are some entries that have a .DLL name and a

driver name while you are attempting to read messages from the event log,

this means that the event message source has more than one message file.

This means you need to parse the string and load each message file.

MORE INFORMATION

Just like events, category IDs are simply IDs in message file resources.

However, in order to use categories, the following two requirements must be

met:

 - The category IDs must be sequentially numbered, starting with a

   message ID of 1.

 - The event source entry in the registry must specify the category

   message file and the number of categories in the message file.

The first requirement is simply a matter of setting the MessageID entries

in the message file for the categories. If all of your categories are

listed at the top of the message file, you can assign the ID of 1 to the

first message. Each message after that automatically gets the next ID value

unless you specify otherwise in the MessageID entry.

The category entries in the registry are made by adding values to your

event key. Normally, your event log application key already contains

EventMessageFile and TypesSupported entries. You should add the following

two entries:

 - CategoryMessageFile

 - CategoryCount

The CategoryMessageFile entry is of type REG_EXPAND_SZ. It should be set to

the full path to the message file that contains the categories.

The CategoryCount entry is a REG_DWORD type. You should set this entry to

the number of categories in the message file specified in

CategoryMessageFile.

REFERENCES

"Microsoft Win32 Programmer's Reference," Microsoft Corporation.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseMisc


Adding Custom Error Strings to an MCI Device Driver

PSS ID Number: Q76411

Authored 23-Sep-1991	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

In the Microsoft Windows graphical environment, an application can use

mciGetErrorString() to obtain the string associated with an error code

returned from a media control interface (MCI) device driver.

An MCI driver can use a STRINGTABLE resource to store its error strings.

The identifier constant for each string should correspond to the error

value returned by the DriverProc function. This value must be greater than

or equal to the constant MCIERR_CUSTOM_DRIVER_BASE to avoid confusion with

the predefined MCI error codes.

MORE INFORMATION

For example, the Pioneer LaserDisc device driver, MCIPIONR.DRV, included

with the Microsoft Device Development Kit (DDK) for Windows 3.1, contains

the following declarations in its header file, MCIPIONR.H:

#define MCIERR_PIONEER_ILLEGAL_FOR_CLV  (MCIERR_CUSTOM_DRIVER_BASE)

#define MCIERR_PIONEER_NOT_SPINNING     (MCIERR_CUSTOM_DRIVER_BASE+1)

#define MCIERR_PIONEER_NO_CHAPTERS      (MCIERR_CUSTOM_DRIVER_BASE+2)

#define MCIERR_PIONEER_NO_TIMERS        (MCIERR_CUSTOM_DRIVER_BASE+3)

Its resource file, MCIPIONR.RC, contains the following STRINGTABLE

definition:

STRINGTABLE

BEGIN

  MCIERR_PIONEER_ILLEGAL_FOR_CLV, "Illegal operation for CLV type disc."

  MCIERR_PIONEER_NOT_SPINNING, "The disc must be spun up to perform this \

operation."

  MCIERR_PIONEER_NO_CHAPTERS, "Chapters are not supported for this disc."

  MCIERR_PIONEER_NO_TIMERS, "All timers are in use. Cannot enable \

notification."

END

When mciGetErrorString() receives a value greater than or equal to

MCIERR_CUSTOM_DRIVER_BASE, it looks in the driver's resource table for a

string with the corresponding identifier.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbmm kbprg

KBSubcategory: MMMisc


Adding Point Sizes to the ChooseFont() Common Dialog Box

PSS ID Number: Q99668

Authored 03-Jun-1993	Last modified 12-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

When a TrueType font (or any other scalable font) is selected in the

ChooseFont() common dialog box, a list of reasonable point sizes is

displayed for selection. In some cases it is necessary to change this

list to allow fewer or more selections.

The initial list of point sizes is hard-coded into COMMDLG.DLL but can

be changed programmatically using a common dialog box hook function.

MORE INFORMATION

Most scalable fonts can be created at nearly any point size. Some

TrueType fonts can be sized from 4 points to 999 points. A complete

list of available point sizes for a font of this type would contain

about 1000 elements, which can be prohibitively long and

time-consuming to construct.

The ChooseFont() common dialog box attempts to limit the selection by

listing only a few of the available point sizes in the size selection

combo box.

In certain cases, it may be desirable to offer more point-size

selections in this dialog box. In this case, a common dialog box hook

procedure can be used to insert point sizes when a specific font is

selected.

The following steps describe a technique that will allow new point

sizes to be added to the size selection combo box. Pay special

attention to step number 4:

1. In your common dialog box hook procedure, look for WM_COMMAND

   messages with wParam equal to the font name combo box (which is

   "cmb1" for Windows version 3.1).

2. When you get this message(s), check for the font name you are

   looking for (for example, you can compare the current selection to

   "Courier New"). If it's not the font you want, return.

3. If this is the font you want, post yourself a user-defined

   message. In response to this message, add the new point size to the

   Point Size combo box (which is "cmb3" for Windows 3.1). It's a good

   idea to double-check here that the point size you are adding isn't

   already in the combo box (so you don't get duplicates).

4. Once you add the new point size, set the item data for the new

   item equal to the point size you are adding. For example, if you

   are adding the string "15" to the combo box, you need to set the

   item data of this new item to 15.

The following code fragment demonstrates the above steps:

// Common Dialog ChooseFont() hook procedure.

UINT CALLBACK __export FontHook(HWND hwnd, UINT wm, WPARAM wParam,

LPARAM lParam)

{

   char szBuf[150];

   DWORD dwIndex;

   switch(wm)

   {

      case WM_COMMAND:

      // See if the notification is for the "Font name" combo box.

         if (wParam == cmb1)

         {

            switch (HIWORD(lParam))

            {

               case CBN_SETFOCUS:

               case CBN_KILLFOCUS:

                  break;

               default:

               // Check to see if it's the font we're looking for.

                  dwIndex = SendDlgItemMessage(hwnd, cmb1, CB_GETCURSEL,

                                               0, 0);

                  if (dwIndex != CB_ERR)

                     SendDlgItemMessage(hwnd, cmb1, CB_GETLBTEXT, (WPARAM)

                                        dwIndex, (LPARAM) ((LPSTR) szBuf));

               // Compare list box contents to the font we are looking for.

               // In this case, it's "Courier New".

                  if (strcmp(szBuf, "Courier New") == 0)

                  // It's the font we want. Post ourselves a message.

                     PostMessage(hwnd, WM_ADDNEWPOINTSIZES, 0, 0L);

            }

         }

      break;

      case WM_ADDNEWPOINTSIZES:

      // First look to see if we've already added point sizes to this

      // combo box.

         if (SendDlgItemMessage(hwnd, cmb3, CB_FINDSTRING, -1,

                               (LPARAM)(LPCSTR)"6") == CB_ERR)

         {

         // Not found, add new point size.

            dwIndex = SendDlgItemMessage(hwnd, cmb3, CB_INSERTSTRING,

                                         0, (LPARAM)(LPSTR)"6");

         // Also set the item data equal to the point size.

            SendDlgItemMessage(hwnd, cmb3, CB_SETITEMDATA,

                               (WPARAM)dwIndex, 6);

         }

         return TRUE; // Don't pass this message on.

   }

   return FALSE;

}

Additional reference words: 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrCmnDlg


Adding to or Removing Windows from the Task List

PSS ID Number: Q99800

Authored 08-Jun-1993	Last modified 18-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.1 and 3.5

There are no functions included in the Windows Software Development

Kit (SDK) to add or remove windows from the task list. All top-level

windows (that is, windows without parents) that are visible will

automatically appear in the task list. A window can be removed from

the task list by making it hidden. Call ShowWindow() with the SW_HIDE

parameter to hide the window. To make it visible again, call

ShowWindow() with the appropriate parameter such as SW_SHOW or

SW_SHOWNORMAL.

Additional reference words: 3.00 3.10 3.50 tasklist

KBCategory: kbprg

KBSubcategory: UsrMisc


Additional Information for WIN32_FIND_DATA

PSS ID Number: Q120697

Authored 18-Sep-1994	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

This article contains additional information about the WIN32_FIND_DATA

members.

The WIN32_FIND_DATA structure contains three members that store the

creation, last access, and last write time of a file. The time format

for these three members (ftCreationTime, ftLastAccessTime, and

ftLastWriteTime) are expressed in the Universal Time Convention (UTC).

These three data members can be converted from UTC time to local time by

calling the FileTimeToLocalFileTime api.

The WIN32_FIND_DATA structure contains two members that store the file

size: nFileSizeHigh and nFileSizeLow. They are described as being the high

and low order words of the size, but they are actually DWORDs. Therefore,

nFileSizeHigh will be zero unless the file size is greater than 0xffffffff

(4.2 Gig).

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: BseMisc


Additional Remote Debugging Requirement

PSS ID Number: Q106066

Authored 31-Oct-1993	Last modified 26-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

The printed and online documentation for remote debugging with WinDbgRm

fail to mention one requirement. The binaries must be in the same drive and

directory on both the target machine and the development machine.

WinDbg also expects to find the source files in the same directory in which

the the binary file was built, but will browse for the source if it is not

found in this location. WinDbg will automatically locate the source if the

files are specified to the compiler with fully qualified paths.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbtool

KBSubcategory: TlsWindbg


Administrator Access to Files

PSS ID Number: Q102099

Authored 28-Jul-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

A user that is a member of the Administrator group is not automatically

granted access to any file on the local machine. For an administrator to

access a file, permission must be specifically granted (as for any user) in

the file's discretionary access control list (DACL).

If an administrator wants to access a file that he or she is not granted

access to, the administrator must first take ownership of that file. Once

ownership is taken, the administrator will have full access to the file. It

is important to note that administrator cannot give ownership back to the

original owner. If this were so, the administrator could take ownership of

a file, examine it, and then assign it back to the original owner without

that owner's knowledge.

NOTE: Because administrators have backup privileges, an administrator could

back up a file (or entire volume) and restore it onto another system. The

administrator could then take ownership of a file on this new system

without the owner's knowledge. Please keep this in mind when thinking about

file security.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseSecurity


Advanced Graphics Settings Slider under Windows 95

PSS ID Number: Q127066

Authored 12-Mar-1995	Last modified 25-May-1995

---

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

---

The following table shows exactly what the Advanced Graphics Settings

Slider control does:

Slider     Hardware    Memory         Accelerated

Control    Cursor      Mapped I/O     Functions

-------------------------------------------------------

None       No          No             Safe mode level 2

Basic      No          No             Safe mode level 1

Most       No          Yes            All

Full       Yes         Yes            All

NOTES:

 - The hardware cursor adjusts the SWCursor switch in SYSTEM.INI [display]

   section. It applies only to S3 and WD drivers.

 - The Memory Mapped I/O adjusts the MMIO switch in SYSTEM.INI [display]

   section. It applies only to the S3 driver.

 - Accelerated Functions adjusts the SafeMode switch in WIN.INI [Windows]

   section. It applies to all DIB engine minidrivers. Level 1 allows basic,

   safe acceleration, such as srcCopy bitblt, patblt, and so on. Level 2

   completely bypasses the driver for all operations (except cursor).

Additional reference words: 4.00 95  Video SYSTEM Applet

KBCategory: kbprg

KBSubcategory: UsrCtl


Advantages of Device-Dependent Bitmaps

PSS ID Number: Q94918

Authored 25-Jan-1993	Last modified 16-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

A DDB (device-dependent bitmap) is much faster than a DIB (device

independent-bitmap) to BitBlt(). For this reason, it is often a good

strategy under Win32 (as well as under Windows 3.1) to create a DDB from a

DIB when caching or calling *Blt() functions.

The slight drawback of memory overhead for the DDB is handled well by

Win32. Under Windows 3.1, the DDB memory could be marked as discardable.

Under Win32, the memory will be paged out if system resources become tight

(at least until the next repaint); if the memory is marked as

PAGE_READONLY, it can be efficiently reused, [see VirtualProtect() in the

Win32 application programming interface (API) Help file].

However, saving the DDB to disk as a mechanism for transfer to other

applications or for later display (another invocation) is not recommended.

This is because DDBs are driver and driver version dependent. DDBs do not

have header information, which is needed for proper translation if passed

to another driver or, potentially, to a later version of the driver for the

same card.

MORE INFORMATION

Windows 95 and Windows NT 3.5 and later support DIBSections. DIBSections

are the fastest and easiest to manipulate, giving the speed of DDBs with

direct access to the DIB bits. NOTE: Win32s does not support DIBSections.

Additional reference words: 3.10 3.50 4.00

KBCategory: kbprg

KBSubcategory: GdiBmp


Allocating and Using Class and Window Extra Bytes

PSS ID Number: Q34611

Authored 22-Aug-1988	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

The WNDCLASS structure contains two fields, cbClsExtra and cbWndExtra,

which can be used to specify a number of additional bytes of memory to

be allocated to the class structure itself or to each window created

using that class.

MORE INFORMATION

Every application that uses class extra bytes and window extra bytes

must specify the appropriate number of bytes before the window class

is registered. If no bytes are specified, an attempt to store

information in extra bytes will cause the application to write into

some random portion of Windows memory, causing data corruption.

Windows version 3.1 will FatalExit if extra bytes are used improperly.

If an application does not use class extra bytes or window extra

bytes, it is important that the cbClsExtra and cbWndExtra fields be

set to zero.

Class and window extra bytes are a scarce resource. If more than 4

extra bytes are required, use the GlobalAlloc fucntion to allocate a

block of memory and store the handle in class or window extra bytes.

Class Extra Bytes

-----------------

For example, setting the value of the cbClsExtra field to 4 will cause

4 extra bytes to be added to the end of the class structure when the

class is registered. This memory is accessible by all windows of that

class. The number of additional bytes allocated to a window's class

can be retrieved through the following call to the GetClassWord

function:

   nClassExtraBytes = GetClassWord(hWnd, GCW_CBCLSEXTRA);

The additional memory can be accessed one word at a time by specifying

an offset, in BYTES (starting at 0), as the nIndex parameter in calls

to the GetClassWord function. These values can be set using the

SetClassWord function.

The GetClassLong and SetClassLong functions perform in a similar

manner and get or set four bytes of memory respectively:

   nClassExtraBytes = GetClassLong(hWnd, GCL_CBCLSEXTRA);

NOTE: A Win32-based application should use GetClassLong and SetClassLong,

because the GCW_ indices are obsolete under Win32.

Window Extra Bytes

------------------

Assigning a value to cbWndExtra will cause additional memory to be

allocated for each window of the class. If, for example, cbWndExtra is

set to 4, every window created using that class will have 4 extra

bytes allocated for it. This memory is accessible only by using the

GetWindowWord and GetWindowLong functions, and specifying a handle

to the window. These values can be set by calling the SetClassWord

or SetClassLong functions. As with the class structures, the offset

is always specified in bytes.

An example of using window extra bytes would be a text editor that has

a variable number of files open at once. The file handle and other

file-specific variables can be stored in the window extra bytes of the

corresponding text window. This eliminates the requirement to always

consume memory for the maximum number of handles or to search a data

structure each time a window is opened or closed.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: UsrWndw


AllocConsole() Necessary to Get Valid Handles

PSS ID Number: Q89750

Authored 29-Sep-1992	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

If a graphical user interface (GUI) application redirects a standard

handle, such as stderr or stdout, and then spawns a child process, the

output of the child process will not be seen unless the AllocConsole()

application programming interface (API) is called before the standard

handle is redirected.

If an application spawns a child process without calling AllocConsole()

first, the child's console window will appear on the screen and the GUI

application will not be able to control this window (for example, it cannot

minimize the child window). In addition, users can terminate the child

process by choosing Close from the console window's Control (system) menu.

This causes users to think that only the window is closed, when in

actuality, the entire application is terminated. This can cause the user to

lose data in the console window.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseCon


Allowing Only One Application Instance on Win32s

PSS ID Number: Q124134

Authored 19-Dec-1994	Last modified 21-Feb-1995

The information in this article applies to:

 - Microsoft Win32s, versions 1.1, 1.15, 1.15a, and 1.2

SUMMARY

The entry point for both Windows-based and Win32-based applications is:

   int WinMain( hInstance, hPrevInstance, lpszCmdLine, nCmdShow )

   HINSTANCE hInstance;        /* Handle of current instance  */

   HINSTANCE hPrevInstance;    /* Handle of previous instance */

   LPSTR lpszCmdLine;          /* Address of command line     */

   int nCmdShow;               /* Show state of window        */

You can allow only one instance of your Windows-based application to run

at a time by using hPrevInstance to determine if there is already an

existing application instance; then exit the process if there is one. If

there is no previous instance, hPrevInstance is NULL.

However, in a Win32-based application, hPrevInstance is always NULL.

Therefore, you cannot determine if another instance of your application

has been started simply by examining hPrevInstance. This article gives you

a method you can use.

MORE INFORMATION

Use one of the following four methods to determine if there is an existing

application instance on Win32s:

 - Synchronize with a named object, such as a file mapping.

   -or-

 - Synchronize with a global atom.

   -or-

 - Synchronize with a private message.

   -or-

 - Use FindWindow() to check for the application.

Using a File Mapping

--------------------

Using a file mapping works well on any Win32 platform. The global atom is a

cheaper resource, whereas a file mapping will cost a page of memory. A

private message is good if you want to inform the first instance that the

user attempted to start a second instance, and then let it handle the

request -- post a message, become the active application, and so on.

NOTE: You need to clean up before terminating the second instance.

FindWindow() doesn't require cleanup, but this method will not work as

reliably in a preemptive multitasking environment, such as Windows NT,

because you can get in a race condition.

The following code fragment demonstrates how a file mapping can be used

to allow only one instance of a Win32-based application. This code should

avoid any race conditions. Place this code at the beginning of WinMain().

The code creates a file mapping named MyTestMap using CreateFileMapping().

If MyTestMap already exists, then you know that there is already a running

instance of this application. A similar technique would be used with a

global atom.

Sample Code

-----------

   HANDLE hMapping;

   hMapping = CreateFileMapping( (HANDLE) 0xffffffff,

                                 NULL,

                                 PAGE_READONLY,

                                 0,

                                 32,

                                 "MyTestMap" );

   if( hMapping )

   {

      if( GetLastError() == ERROR_ALREADY_EXISTS )

      {

      //

      // Display something that tells the user

      // the app is already running.

      //

         MessageBox( NULL, "Application is running.", "Test", MB_OK );

         ExitProcess(1);

      }

   }

   else

   {

   //

   // Some other error; handle error.

   //

      MessageBox( NULL, "Error creating mapping", "Test", MB_OK );

      ExitProcess(1);

   }

Additional reference words: 1.10 1.20

KBCategory: kbprg kbcode

KBSubcategory: W32s


Alternative to PtInRegion() for Hit-Testing

PSS ID Number: Q121960

Authored 24-Oct-1994	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.1, 3.5, 3.51, and 4.0

SUMMARY

It may be useful to perform hit-testing on an object that is defined by a

polygon. To accomplish this, you could call CreatePolygonRgn() to create a

region from the polygon, and then call PtInRegion() to determine if the

point falls within the region. However, this method can be expensive both

in terms of GDI resources, and in terms of speed. If a polygon is complex,

CreatePolygonRgn() will often fail due to lack of memory in Windows because

regions are in GDI's heap.

The code below provides a better method. Use it to determine if a point

lies within a polygon. It is fast and does not use regions. The trick lies

in determining the number of times an imaginary line drawn from the point

you want to test crosses edges of your polygon. If the line crosses edges

an even number of times, the point is outside the polygon. If it crosses an

odd number of times it is inside. The line is drawn horizontally from the

point to the right.

MORE INFORMATION

WARNING: ANY USE BY YOU OF THE CODE PROVIDED IN THIS ARTICLE IS AT YOUR OWN

RISK. Microsoft provides this code "as is" without warranty of any kind,

either express or implied, including but not limited to the implied

warranties of merchantability and/or fitness for a particular purpose. The

references below do not constitute a recommendation. You are encouraged to

examine any resource to determine whether or not it meets your needs. These

books are not recommended over any others.

The following code is based on an algorithm presented in "Algorithms" by

Robert Sedgewick, Addison-Wesley, 1988, 2nd ed. ISBN 0201066734. The

algorithm is on p.354, in the section "Inclusion in a Polygon" in the

chapter "Elementary Geometric Methods." It is also discussed in "Computer

Graphics" by Foley, van Dam, Feiner and Hughes, Addison-Wesley, 1990, 2nd

ed. ISBN 0201121107, chapter 2, section 1, p.34.

Sample Code

-----------

#include "windows.h"

#include "limits.h"

BOOL G_PtInPolygon(POINT *rgpts, WORD wnumpts, POINT ptTest,

                   RECT *prbound) ;

BOOL G_PtInPolyRect(POINT *rgpts, WORD wnumpts, POINT ptTest,

                    RECT *prbound) ;

BOOL Intersect(POINT p1, POINT p2, POINT p3, POINT p4) ;

int  CCW(POINT p0, POINT p1, POINT p2) ;

/*************************************************************************

 * FUNCTION:   G_PtInPolygon

 *

 * PURPOSE

 * This routine determines if the point passed is in the polygon. It uses

 * the classical polygon hit-testing algorithm: a horizontal ray starting

 * at the point is extended infinitely rightwards and the number of

 * polygon edges that intersect the ray are counted. If the number is odd,

 * the point is inside the polygon.

 *

 * RETURN VALUE

 * (BOOL) TRUE if the point is inside the polygon, FALSE if not.

 *************************************************************************/

BOOL G_PtInPolygon(POINT *rgpts, WORD wnumpts, POINT ptTest,

                   RECT *prbound)

{

   RECT   r ;

   POINT  *ppt ;

   WORD   i ;

   POINT  pt1, pt2 ;

   WORD   wnumintsct = 0 ;

   if (!G_PtInPolyRect(rgpts,wnumpts,ptTest,prbound))

      return FALSE ;

   pt1 = pt2 = ptTest ;

   pt2.x = r.right + 50 ;

   // Now go through each of the lines in the polygon and see if it

   // intersects

   for (i = 0, ppt = rgpts ; i < wnumpts-1 ; i++, ppt++)

   {

      if (Intersect(ptTest, pt2, *ppt, *(ppt+1)))

         wnumintsct++ ;

   }

   // And the last line

   if (Intersect(ptTest, pt2, *ppt, *rgpts))

      wnumintsct++ ;

   return (wnumintsct&1) ;

}

/*************************************************************************

 * FUNCTION:   G_PtInPolyRect

 *

 * PURPOSE

 * This routine determines if a point is within the smallest rectangle

 * that encloses a polygon.

 *

 * RETURN VALUE

 * (BOOL) TRUE or FALSE depending on whether the point is in the rect or

 * not.

 *************************************************************************/

BOOL  G_PtInPolyRect(POINT *rgpts, WORD wnumpts, POINT ptTest,

                     RECT *prbound)

{

   RECT r ;

   // If a bounding rect has not been passed in, calculate it

   if (prbound)

      r = *prbound ;

   else

   {

      int   xmin, xmax, ymin, ymax ;

      POINT *ppt ;

      WORD  i ;

      xmin = ymin = INT_MAX ;

      xmax = ymax = -INT_MAX ;

      for (i=0, ppt = rgpts ; i < wnumpts ; i++, ppt++)

      {

         if (ppt->x < xmin)

            xmin = ppt->x ;

         if (ppt->x > xmax)

            xmax = ppt->x ;

         if (ppt->y < ymin)

            ymin = ppt->y ;

         if (ppt->y > ymax)

            ymax = ppt->y ;

      }

      SetRect(&r, xmin, ymin, xmax, ymax) ;

   }

   return (PtInRect(&r,ptTest)) ;

}

/*************************************************************************

 * FUNCTION:   Intersect

 *

 * PURPOSE

 * Given two line segments, determine if they intersect.

 *

 * RETURN VALUE

 * TRUE if they intersect, FALSE if not.

 *************************************************************************/

BOOL Intersect(POINT p1, POINT p2, POINT p3, POINT p4)

{

   return ((( CCW(p1, p2, p3) * CCW(p1, p2, p4)) <= 0)

        && (( CCW(p3, p4, p1) * CCW(p3, p4, p2)  <= 0) )) ;

}

/*************************************************************************

 * FUNCTION:   CCW (CounterClockWise)

 *

 * PURPOSE

 * Determines, given three points, if when travelling from the first to

 * the second to the third, we travel in a counterclockwise direction.

 *

 * RETURN VALUE

 * (int) 1 if the movement is in a counterclockwise direction, -1 if

 * not.

 *************************************************************************/

int CCW(POINT p0, POINT p1, POINT p2)

{

   LONG dx1, dx2 ;

   LONG dy1, dy2 ;

   dx1 = p1.x - p0.x ; dx2 = p2.x - p0.x ;

   dy1 = p1.y - p0.y ; dy2 = p2.y - p0.y ;

   /* This is basically a slope comparison: we don't do divisions because

    * of divide by zero possibilities with pure horizontal and pure

    * vertical lines.

    */

   return ((dx1 * dy2 > dy1 * dx2) ? 1 : -1) ;

}

/*************************************************

 * The above code might be tested as follows:

 *************************************************/

void PASCAL TestProc( HWND hWnd )

{

    POINT rgpts[] = {0,0, 10,0, 10,10, 5,15, 0,10};

    WORD wnumpts = 5;

    POINT ptTest = {3,10};

    RECT prbound = {0, 0, 20, 20};

    BOOL bInside;

    bInside = G_PtInPolygon(rgpts, wnumpts, ptTest, &prbound);

    if (bInside)

       MessageBox(hWnd, "Point is inside!", "Test", MB_OK );

    else

       MessageBox(hWnd, "Point is outside!", "Test", MB_OK );

}

/* code ends */

Additional reference words: 3.00 3.10 3.50 4.00 95  hittest hit-test fails

KBCategory: kbprg kbcode

KBSubcategory: GdiMisc


Alternatives to Using GetProcAddress() With LoadLibrary()

PSS ID Number: Q92862

Authored 16-Nov-1992	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

When loading a DLL with LoadLibrary(), an alternative to calling

GetProcAddress() for each of your DLL entry points is to have the DLL

initialization function initialize a global structure or array containing

the addresses of these DLL entry points, then call a DLL function from your

executable which will return the address of this structure or array to your

executable. You can then call your DLL functions via the function pointers

in this structure or array.

MORE INFORMATION

The best place to initialize this structure or array of function pointers

would be in the DLL_PROCESS_ATTACH code of your DLL's main entry point. The

structure or array containing these function pointers must be declared as

either a global variable or as dynamically allocated memory (malloc(),

GlobalAlloc(), etc.) in your DLL in order for the executable to be able to

address this memory properly.

It is also possible, though not as clean, to export the global structure or

array of function pointers so that your executable can use the structure or

array by name directly in your executable. For more information on how to

declare and export global data in a Win32 DLL, please see the following

article(s) in the Microsoft Knowledge Base:

   ARTICLE-ID: Q90530

   TITLE     : Exporting Data From a DLL

Be careful not to call these DLL functions via the function pointers after

the DLL is unloaded via FreeLibrary(). After FreeLibrary() is called, these

function pointer addresses are invalid and calling them will result in an

access violation.

This technique of returning pointers to DLL entry points is a supported

technique and will work on all hardware platforms that Windows NT supports.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: BseDll


An Efficient Animation Algorithm

PSS ID Number: Q75431

Authored 20-Aug-1991	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

An application that shows an animated image cannot rely solely on Windows

graphical device interface (GDI) functions because they will be too slow.

Instead, the application must create its own set of bitmaps. This article

discusses the process required and provides tips to improve performance and

memory use.

This information applies to any type of animation or fast drawing, from

painting the game pieces in Reversi to updating the time each second in

Clock.

MORE INFORMATION

There are three major steps to this process:

1. Allocate the bitmap.

It is preferable to allocate a single bitmap to store all the different

"cels"--the components of the animated scene. The contents of the bitmap

should be arranged in a column that is wide enough to hold a single cel;

the height is determined by the number of cels. To improve memory usage,

the bitmap should be discardable.

For example, given the definitions of the three constants below, the

following code allocates the correct size bitmap:

   X_SIZE = width of the cel

   Y_SIZE = height of the cel

   NUM_CELS = number of cels in the animated sequence

   HBITMAP hbm;

   hbm = CreateDiscardableBitmap(hDC, X_SIZE, NUM_CELS * Y_SIZE);

   if (!hbm)

       {

       // error - could not allocate bitmap

       }

2. Prepare the bitmaps.

To draw into the bitmap, it must be selected into a display context (DC).

Allocate a (temporary) compatible DC for this purpose:

   if (hTmpDC = CreateCompatibleDC(hDC))

       {

       HBITMAP hOldBm;

       hOldBm = SelectObject(hTmpDC, hbm);

       // and so forth

       }

In many cases, all cels will share the same background. Rather than drawing

this background several times onto the bitmap, draw it once onto the first

cel and copy it to the other cels, as the following code demonstrates:

   // GDI calls to draw to hbm from (0, 0) to (X_SIZE, Y_SIZE)

   for (i = 1; i < NUM_CELS; i++)  // Perform the copy

       BitBlt(hTmpDC, 0, i * Y_SIZE, X_SIZE, Y_SIZE, hTmpDC, 0, 0,

                 SRCCOPY);

After the background is copied, draw the foreground on each cel, using

regular GDI calls (in TRANSPARENT drawing mode). The coordinates for cel

"i" in bitmap hbm are:

   x_pos: 0 to (X_SIZE - 1)

   y_pos: (i * Y_SIZE) to (((i + 1) * Y_SIZE) - 1)

If the cels in the bitmap contain sequential images, animating to the

screen is simplified.

To finish this step, release the temporary DC.

   SelectObject(hTmpDC, hOldBm);

   DeleteDC(hTmpDC);

3. Animate.

A temporary, off-screen DC is required to allow the application to select

the bitmap. Note that selecting the object may fail if the bitmap has been

discarded. If this has occurred, another bitmap must be allocated (if

memory allows) and the bitmap must be initialized (as outlined in step 2,

above).

   if ((hTmpDC = CreateCompatibleDC(hDC)) != NULL)

       {

       HBITMAP hOldBm;

       if (!(hOldBm = SelectObject(hTmpDC, hbm))

           // must re-allocate bitmap. Note that this MAY FAIL!!!

At this point, call the BitBlt() function to copy the various stages of the

animation sequence to the screen. If the cels in the bitmap contain

sequential images, a simple loop will do the job nicely, as the following

code demonstrates:

       for (i = 0; i < NUM_CELS; i++)

           {

           BitBlt (hDC, x_pos, y_pos, X_SIZE, Y_SIZE, hTmpDC, 0,

                        i * Y_SIZE, SRCCOPY);

           // Some form of delay goes here. A real-time wait, based on

           // clock ticks, is recommended.

           }

When the drawing is done, delete the temporary DC:

   SelectObject(hTmpDC, hOldBm);

   DeleteDC(hTmpDC);

It is important to cancel the selection of the bitmap between passes

through the for loop. This allows the bitmap to be discarded if the system

runs low on memory.

Additional reference words: 3.00 3.10 3.50 4.00 95 animation

KBCategory: kbprg

KBSubcategory: GdiBmp


Application Can Allocate Memory with DdeCreateDataHandle

PSS ID Number: Q85680

Authored 17-Jun-1992	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

An application can use the DdeCreateDataHandle function to create a

handle to a block of data. The application can use the handle to pass

the data to another application in a dynamic data exchange (DDE)

conversation using the Dynamic Data Exchange Management Libraries

(DDEML). All DDEML functions refer to blocks of memory using data

handles.

An application can allocate memory and manually create a data handle

associated with the memory (using method 1 below), or automatically by

using the DdeCreateDataHandle function (method 2 below).

Method 1

--------

1. Obtain a block of memory using the GlobalAlloc or LocalAlloc

   function or by declaring a variable in your application.

2. Fill the block of memory with the desired data.

3. Call the DdeCreateDataHandle function to create a data handle

   associated with the block of memory.

Method 2

--------

1. Call the DdeCreateDataHandle function with the lpvSrcBuf parameter

   set to NULL, the cbInitData parameter set to zero, and the

   offSrcBuf parameter set to the number of bytes of memory required.

2. To retrieve a handle to the memory block, specify the data handle

   returned by DdeCreateDataHandle as the hData parameter of the

   DdeAccessData function. This operation is similar to calling the

   GlobalLock function on a handle returned from GlobalAlloc.

3. Use the pointer to fill the memory block with data.

4. Call DdeUnaccessData to unaccess the object. This operation is

   similar to calling the GlobalUnlock function on a handle returned

   from GlobalAlloc.

The following code fragment demonstrates method 2:

   // Retrieve the length of the data to be stored

   cbLen = lstrlen("This is a test") + 1;

   // Create the data handle and allocate the memory

   hData = DdeCreateDataHandle(idInst, NULL, 0, cbLen,

                               hszItem, wFmt, 0);

   // Access the data handle

   lpstrData = (LPSTR)DdeAccessData(hData, NULL);

   // Fill the block of memory

   lstrcpy(lpstrData, "This is a test");

   // Unaccess the data handle

   DdeUnaccessData(hData);

When an application obtains a data handle from DdeCreateDataHandle,

the application should next call DdeAccessData with the handle. If a

data handle is first specified as a parameter to a DDEML function

other than DdeAccessData, when the application later calls

DdeAccessData, the application receives only read access to the

associated memory block.

Additional reference words: 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrDde


Application Exception Error Codes

PSS ID Number: Q101774

Authored 21-Jul-1993	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

Many exception errors are not processed by applications. The most common

exception error is EXCEPTION_ACCESS_VIOLATION (c0000005). It occurs when a

pointer is dereferenced and the pointer points to inaccessible memory or a

write operation is attempted on read-only memory. If an application does

not trap an exception, the Win32 module, UnhandledExceptionFilter, will do

one of the following: display a message box, invoke Dr. Watson, or attach

your application to a debugger.

The following are standard exception errors:

   EXCEPTION_ACCESS_VIOLATION

   EXCEPTION_ARRAY_BOUNDS_EXCEEDED

   EXCEPTION_BREAKPOINT

   EXCEPTION_DATATYPE_MISALIGNMENT

   EXCEPTION_FLT_DENORMAL_OPERAND

   EXCEPTION_FLT_DIVIDE_BY_ZERO

   EXCEPTION_FLT_INEXACT_RESULT

   EXCEPTION_FLT_INVALID_OPERATION

   EXCEPTION_FLT_OVERFLOW

   EXCEPTION_FLT_STACK_CHECK

   EXCEPTION_FLT_UNDERFLOW

   EXCEPTION_ILLEGAL_INSTRUCTION

   EXCEPTION_IN_PAGE_ERROR

   EXCEPTION_INT_DIVIDE_BY_ZERO

   EXCEPTION_INT_OVERFLOW

   EXCEPTION_INVALID_DISPOSITION

   EXCEPTION_NONCONTINUABLE_EXCEPTION

   EXCEPTION_PRIV_INSTRUCTION

   EXCEPTION_SINGLE_STEP

   EXCEPTION_STACK_OVERFLOW

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: BseExcept


Application Version Marking in Windows 95

PSS ID Number: Q125705

Authored 01-Feb-1995	Last modified 16-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

SUMMARY

Applications designed for Windows 95, whether 16- or 32-bit, should be

marked for Windows version 4.0 so they receive the full benefit of new user

interface features in Windows 95. Applications marked as being designed for

earlier versions of Windows will display behavior consistent with the

Windows version 3.1 user interface, which is not always identical to

Windows 95 behavior.

Executables marked for Windows version 4.0 will load on Windows 95, Windows

NT version 3.5, Win32s version 1.15, and later versions, but not on earlier

versions.

NOTE: This article deals solely with marking executable files as compatible

with a particular Windows version. This is different from the version

resources (VS_VERSION_INFO) that may be contained in an executable.

MORE INFORMATION

The Microsoft Visual C++ version 2.1 linker defaults to marking executables

for Windows version 4.0 while the version 2.0 linker defaults to 3.1. To

override the default, the Microsoft Visual C++ linkers accept the following

syntax for the /SUBSYSTEM option:

   /SUBSYSTEM:WINDOWS,4.0

In the development environment, you can change the /SUBSYSTEM option by

going to the Project menu, selecting Settings, selecting either Win32 Debug

or Win32 Release, choosing the Link tab, and editing the Project Options.

You may need to perform a full link for this to take effect, but subsequent

incremental linking with this switch will work correctly.

To mark a 16-bit executable as Windows version 4.0 compatible, use the

16-bit resource compiler (RC.EXE) from the Windows 95 SDK to bind the

resources into the executable file. By default, this version of RC marks

the executable for version 4.0, but this can be overridden by using

the -30 or -31 switch.

An application will display several behavioral differences depending on

which Windows version the application is compatible with:

1. All standard control windows owned by a version 4.0 application are

   drawn with a chiseled 3D look. The same effect can be obtained for

   dialogs owned by a version 3.1 application by using the DS_3DLOOK dialog

   style. (This style is ignored on other Windows platforms.)

2. Thunks created using the Windows 95 SDK Thunk Compiler will not work

   unless the 16-bit thunk DLL is marked for version 4.0.

3. Windows version 3.1 allowed 16-bit applications to share GDI resources

   such as font or bitmap handles. For backwards compatibility, Windows 95

   does not clean up objects left undeleted by a 16-bit version 3.x

   application when that application terminates because these objects may

   be in use by another application. Instead, such objects remain valid as

   long as there are any 16-bit applications running. When all 16-bit

   applications are closed, these objects are freed.

   On the other hand, is is assumed that 16-bit version 4.0 applications

   follow the Windows 95 guidelines, and do not share objects. Thus, all

   objects owned by a 16-bit version 4.0-based application are freed when

   the application terminates.

   Win32-based applications cannot freely share GDI objects, so all owned

   objects are freed when a Win32-based application terminates regardless

   of the version of the application.

4. New window messages, such as WM_STYLECHANGED, are only sent to windows

   owned by a version 4.0 application.

5. Printer DCs are reset during StartPage() in applications marked with

   version 4.0

Additional reference words: 4.00

KBCategory: kbprg

KBSubcategory: UsrMisc


Assigning Mnemonics to Owner-Draw Push Buttons

PSS ID Number: Q67716

Authored 12-Dec-1990	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.1, 3.5, 3.51, and 4.0

An application that uses owner-draw push buttons is always responsible for

the appearance of the buttons. It might seem that in doing so, the ability

to assign a mnemonic character to an owner-draw button is lost because text

containing the mnemonic may not be displayed.

Fortunately, this is not the case. If an owner-draw button should be

activated by ALT+X, place "&X" into the button text. NOTE: You have to use

DrawText() to get the & character to underline the next character. Using

TextOut() will not cause the & character to underline the next character in

the string.

When the ALT key is pressed in combination with any character, Windows

examines the text of each control to determine which control, if any, uses

that particular mnemonic. With an owner-draw button, the text exists, but

may not necessarily be used to paint the button.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: UsrCtl


Associating Data with a List Box Entry

PSS ID Number: Q74345

Authored 16-Jul-1991	Last modified 23-Jun-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

In the Microsoft Windows graphical environment, an application can use the

LB_SETITEMDATA and LB_GETITEMDATA messages to associate additional

information with each entry in a list box. These messages enable an

application to associate an arbitrary LONG value with each entry and to

retrieve that value. This article documents how an application uses these

messages.

MORE INFORMATION

In this example, the application will associate a 64-byte block of data

with each list box entry. This is accomplished by allocating a global

memory block and using the LB_SETITEMDATA message to associate the handle

of the memory block with the appropriate list box item.

During list box initialization, the following code is executed for each

list box item:

   if ((hLBData = GlobalAlloc(GMEM_MOVEABLE, 64)))

      {

      if ((lpLBData = GlobalLock(hLBData)))

         {

         // Store data in 64-byte block.

         GlobalUnlock(hLBData);

         }

      }

// NOTE: The MAKELONG is not needed on 32-bit platforms.

   SendMessage(hListBox, LB_SETITEMDATA, nIndex, MAKELONG(hLBData, 0));

To retrieve the information associated with a list box entry, the following

code can be used:

// NOTE: The return from LB_GETITEMDATA is a long on 32-bit platforms.

   if ((hLBData = LOWORD(SendMessage(hListBox, LB_GETITEMDATA,

             nIndex, 0L))))

      {

      if ((lpLBData = GlobalLock(hLBData)))

         {

         // Access or manipulate the data or both.

         GlobalUnlock(hLBData);

         }

      }

Before the application terminates, it must free the memory associated with

each list box item. The following code frees the memory associated with one

list box item:

   if ((hLBData = LOWORD(SendMessage(hListBox, LB_GETITEMDATA,

         nIndex, 0L))))

      GlobalFree(hLBData);

These techniques can be used to associated data with an entry in a combo

box by substituting the CB_SETITEMDATA and CB_GETITEMDATA messages.

Additional reference words: 3.00 3.10 3.50 4.00 95 combobox listbox

KBCategory: kbprg

KBSubcategory: UsrCtl


Authoring Windows Help Files for Performance

PSS ID Number: Q74937

Authored 05-Aug-1991	Last modified 24-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

The Windows Help Compiler allows an application developer to create

hypertext documentation, richly annotated with color and graphics.

This article discusses methods to author help files to achieve maximum

performance when the file is used. These comments apply to Windows

Help versions 3.06 and later.

This information is subject to change in future versions of the Help

Compiler and of the Help application as new technology is incorporated

into these products.

There are four major suggestions:

1. Use OPTCDROM=1 for all files destined for CD-ROM (compact-disk

   read-only memory), and potentially on files where up to an

   additional 10K of size is not significant.

2. Use bitmaps placed with data for small bitmaps that are referenced

   only once or infrequently in the help file.

3. Use bitmaps not placed with data for large bitmaps, all bitmaps

   referenced frequently, or bitmaps referenced by two or more topics

   that generally will be viewed in succession.

4. Use segmented hypergraphics to generate graphics with multiple hot

   spots, rather than several bitmaps positioned next to each other.

Coincidentally, suggestions 2, 3, and 4 are also generally space-saving

techniques as well.

MORE INFORMATION

1. Use OPTCDROM=1 for files destined for CD-ROM.

   When OPTCDROM is placed in the [OPTIONS] section of the .HPJ file,

   the topic information in the help file is aligned on 2K boundaries.

   This option is aimed at maximizing performance on CD-ROM drives,

   where reading aligned information can be significantly faster.

   Estimates indicate that sequential reads from CD-ROM can be up to

   twice as fast when aligned. While reads are not always sequential,

   a high percentage can be, depending on how the help file is

   authored. Minor improvements have also been noted on magnetic

   media.

   This option can cause up to 10K of additional file space to be

   used.

2. Store small bitmaps with data.

   Placing bitmaps with data keeps the graphical and textual

   information in the same location in the help file. This avoids

   reading from different locations on disk to display a topic. Seeks

   to different locations are exceptionally time consuming on CD-ROM,

   and can be time consuming on magnetic media. Bitmaps with data also

   help maximize the effects of the OPTCDROM option.

   Up to 12K of compressed topic text is buffered in memory. Since

   bitmaps are kept with the topic text, they take advantage of this

   buffering. Thus, topics under 12K in compressed size generally do

   not need to be reread when the window is resized or redrawn.

   Note that large bitmaps kept with data may cause performance to

   become worse. Topics may be laid out twice as part of scroll bar

   removal. Topics over 12K in size will be read, laid out, and then

   reread as they are laid out a second time before display. Bitmaps

   are often the cause of exceeding the 12K size. Bitmaps NOT kept

   with data are buffered elsewhere (see #3 below), and if the

   remaining textual data is less than 12K, the topic will be read

   from disk only once.

   Bitmaps with data cost space only when the same bitmap is used more

   than once in the help file. If a bitmap is used frequently, not

   placing it "with data" may be more appropriate, unless the

   performance benefit is determined to outweigh the size hit.

3. Store large and frequently accessed bitmaps separately.

   The 50 most recently accessed bitmaps not stored with data are

   cached in memory. This means that the bitmap may have to be read

   from disk only once if two successively displayed help topics

   reference it. Unlike bitmaps stored with data, these cached bitmaps

   only have to be reread if they are bumped out of the cache by the

   subsequent display of 50 more bitmaps, or by low memory conditions.

   Cached bitmaps not stored with data cost some speed when they are

   typically displayed by the user only once in a session. Since they

   are stored in a different portion of the help file from the topic

   text, an additional seek is required to locate them. This cost, if

   incurred, is generally negligible on disk, and high on CD-ROM.

   Note, however, that this cost MAY be less than the cost of reading

   the topic twice, if the topic is laid out twice as a result of not

   needing scroll bars, and is larger than 12K.

4. Use segmented hypergraphics.

   Segmented hypergraphics is the term used to describe the ability to

   take a single bitmap, and define several regions that are hot

   spots. Hot spots can overlap, and can each perform different

   actions.

   The primary benefit of using segmented hypergraphics is that a

   single bitmap can be used. Previous techniques utilizing several

   bitmaps carefully placed in the topic text to generate a single

   image have the drawback of requiring several bitmap-locating

   operations at display time, which can translate to several disk

   seeks and reads. On CD-ROM, especially, this can be quite

   significant.

   The only cost involved in using segmented hypergraphics is that the

   segmented hypergraphics editor must be used to define the hot spots

   within the bitmaps.

In summary, there are a few simple authoring techniques that can

improve performance of help files. While especially significant for

CD-ROM hosted help files, they are of benefit to disk-based help files.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbtool

KBSubcategory: TlsHlp


Availability of Microsoft Network SDKs

PSS ID Number: Q115604

Authored 31-May-1994	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK), version 3.1

 - Microsoft Win32 SDK, versions 3.1, 3.5, 3.51, and 4.0

 - Windows for Workgroups SDK, version 3.11

 - Microsoft LAN Manager SDK

SUMMARY

The following SDKs are available for programmers writing network

applications on Microsoft platforms:

Microsoft Windows for Workgroups SDK

------------------------------------

This is available on the April 1994 (and later) Microsoft Developer Network

(MSDN) Level 2 CDs.

The SDK, documentation, debug kernel, and other files for network

programmers on Windows for Workgroups, version 3.11 are available on the

April 1994 MSDN. This SDK includes APIs for the network extensions to

Windows for Workgroups, version 3.11.

Microsoft LAN Manager SDK

-------------------------

This is available on CompuServe:

   Forum: msnet

   Section: 3 (LM on OS/2)

The libraries in this section contain the SDK.

The SDK for LAN Manager programming on MS-DOS, Windows, and OS/2 is

available on CompuServe.

The documentation is available in two books:

 - "Microsoft LAN Manager, A Programmer's Guide," Ralph Ryan, Microsoft

   Press, ISBN 1-55615-166-7.

 - "Microsoft LAN Manager Programmer's Reference," Microsoft Corporation,

   Microsoft Press, ISBN 1-55615-313-9.

This SDK includes APIs for writing distributed applications and

administration programs for Microsoft LAN Manager.

LAN Manager APIs for Windows NT

-------------------------------

The file DOC\SDK\MISC\LMAPI.HLP on the CD describes the ported LAN Manager

APIs APIs. Windows NT supports 32-bit equivalents of most of the LAN

Manager APIs.

The LAN Manager APIs are included in the header file LMACCESS.H and in the

import library NETAPI32.LIB. These APIs are described in the Win32 API help

file.

Windows Sockets APIs

--------------------

The Windows Sockets APIs are available through the SDKs. The file

WINSOCK.HLP gives the details.

The files needed to support Windows Sockets APIs (conforming to the Windows

Sockets specifications) for Microsoft LAN Manager may be obtained in the

following locations:

 - CompuServe (lib 10 in the MSNETWORKS forum, titled LMSOCK.ZIP).

   -or-

 - Internet (FTP.MICROSOFT.COM, ADVSYS\LANMAN\SUP-ED\WINSOCK).

The Windows Sockets specifications, libraries, header files and samples may

also be obtained from the Internet location mentioned above, in the

ADVSYS\WINSOCK directory.

Microsoft Remote Procedure Call (RPC)

-------------------------------------

The support for RPC is included in the Win32 SDKs. The Win32 API help file

includes the RPC APIs. The RPC.HLP file gives the details of RPC support.

RPC support files for MS-DOS and Microsoft Windows may be obtained from the

Win32SDK CD-ROM. The directory MSTOOLS\RPC_DOS has the required files.

NOTE: Microsoft also provides other kinds of network APIs. For example, the

NetBIOSCall() API provides a mechanism to write NetBIOS applications on

Microsoft Windows; on Windows NT this is accomplished with the Netbios()

API. Information on these other APIs may be obtained from the Windows and

Win32 SDK documentation.

Additional reference words: 3.10 3.50 4.00 95  3.11 msdnl2

KBCategory: kbref

KBSubcategory: NtwkMisc


Avoid Calling SendMessage() Inside a Hook Filter Function

PSS ID Number: Q74857

Authored 31-Jul-1991	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

A hook filter function should not call SendMessage() to pass intertask

messages because this behavior can create a deadlock condition in

Windows. If a hook filter function is called as a result of an

intertask SendMessage(), and if the hook function then yields control

with an intertask SendMessage(), a message deadlock condition may

occur. For this reason, hook filters should use PostMessage() rather

than SendMessage() to pass messages to other applications.

NOTE: A hook filter can use SendMessage() to pass a message to the

current task because this will not yield the control.

Section 1.1.5 of the "Microsoft Windows Software Development Kit Reference

Volume 1" from the Windows SDK version 3.0 documentation has more

information on message deadlocks.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrHks


Background, Foreground, and System Palette Management

PSS ID Number: Q72386

Authored 23-May-1991	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

On a device that supports the Microsoft Windows palette management APIs, an

application can create a logical palette, select the palette into a device

context (DC), and realize the palette. Realizing a logical palette maps its

colors to the system (hardware) color palette. The GetDeviceCaps() API is

available to inform an application whether the device is capable of

supporting palette management functions and, if so, the size of its system

palette. This article discusses the different types of logical palettes and

the effect of each on the system palette when a logical palette is

realized.

MORE INFORMATION

When a logical palette is selected into a DC, it can be selected as either

a foreground or a background palette. Setting the bForceBackground

parameter of the SelectPalette() API to TRUE selects the palette as a

background palette. If this parameter is FALSE, the palette can be selected

as a foreground palette. A palette will be selected as a foreground palette

only if the DC into which the palette is selected is one of the five cached

DCs managed by the GetDC() API and the DC is retrieved on behalf of the

active window. If the DC is returned by CreateDC() or CreateCompatibleDC()

or if the window is not the active window, the palette will be forced

into the background.

The status as a foreground or a background palette affects how the colors

in the logical palette are mapped into the system palette when the logical

palette is realized.

When a foreground palette is realized, every entry in the system palette

that can be modified by an application is accessible to the logical

palette. Logical palette entries are mapped into the system palette

starting at the first available entry. Because a logical palette entry that

exactly matches a reserved system palette entry is mapped to that system

entry, it does not consume a separate palette slot. If the logical palette

has more entries than available slots in the system palette, the available

slots are filled, in order, from the logical palette. The remaining logical

palette entries are mapped to the closest colors already present in the

system palette. There is one exception to this rule: if a logical palette

entry is marked with the PC_RESERVED flag, no colors will be mapped to that

entry. If all available system palette entries are reserved, additional

colors will not be mapped to any entry and will be displayed as black on

the screen.

A palette entry marked as PC_NOCOLLAPSE will always take a separate slot if

available, just as for PC_RESERVED. Unlike a PC_RESERVED color, if no slots

are available, it will map to the nearest color, and other colors may map

onto it.

The first available entry in the system palette is the first palette entry

not marked as used. For example, assume a device with 256 palette entries,

20 of which are reserved for the system. An application realizes a palette

of 36 colors on this device; therefore, the first 36 entries are marked

used. Another application realizes a 100-entry palette; therefore, the next

100 entries are marked used. If a third application receives the input

focus and realizes a foreground palette with 236 entries, Windows maps the

first 100 colors into the remainder of the system palette. Each of the

remaining 136 colors of the logical palette is mapped into the closest

color available in the system palette.

When a background palette is realized, any empty positions in the system

palette are filled. Any colors that remain are mapped to the closest color

in the system palette. A background palette entry cannot overlay a

foreground entry in the system palette; however, a foreground palette entry

can overlay a background entry in the system palette.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: GdiPal


Background Colors Affect BitBlt() from Mono to Color

PSS ID Number: Q41464

Authored 22-Feb-1989	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

When using BitBlt() to convert a monochrome bitmap to a color bitmap, GDI

transforms all white bits (1) to the background color of the destination

device context (DC). GDI transforms all black bits (0) to the text (or

foreground) color of the destination DC.

When using BitBlt() to convert a color bitmap to a monochrome bitmap, GDI

sets to white (1) all pixels that match the background color of the source

DC. All other bits are set to black (0).

These features are mentioned in the BitBlt() documentation.

manual.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: GdiBmp


BeginPaint() Invalid Rectangle in Client Coordinates

PSS ID Number: Q19963

Authored 17-Dec-1987	Last modified 23-Jun-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.1, 3.5, 3.51, and 4.0

The BeginPaint() function returns a pointer to a PAINTSTRUCT data structure

through its second parameter. The rcPaint field of this structure specifies

the update rectangle in client-area coordinates (relative to the upper-left

corner of the window client area).

This update rectangle also serves as the clipping area for painting in

the window, unless the invalid area of the window is expanded using the

InvalidateRect() function.

Additional reference words: 3.00 3.10 3.5 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrPnt


Binary and Source Compatibility Under Windows NT

PSS ID Number: Q93213

Authored 01-Dec-1992	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

SUMMARY

There are currently three hardware platforms for which Win32-based

applications can be written; they are Intel (x86), MIPS, and DEC Alpha.

Binary compatibility across these hardware platforms is not a viable

alternative. Therefore, Windows NT offers source compatibility. This means

that developers may create versions of their Win32 applications for each

CPU by recompiling.

For example, suppose that you have written a Win32-based application in C

and have used a 32-bit compiler that targets the Intel platform. In order

to produce a Win32-based application that runs on DEC Alpha, you would

purchase a 32-bit compiler that targets Alpha and recompile your code.

MORE INFORMATION

It is important not to confuse source compatibility across hardware

platforms with binary compatibility across application execution

environments. Windows NT and Win32s do support binary compatibility between

different application execution environments. For example, the typical

16-bit Windows-based application can be run without modification on any

Windows NT machine. On the MIPS and Alpha platforms, this is achieved

through emulation. In addition, it is possible to design an x86 Win32-based

application so that it runs on Windows 3.1. This is achieved through

Win32s.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: SubSys


Binary Compatibility Basics

PSS ID Number: Q95162

Authored 02-Feb-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

SUMMARY

Because of differing instruction sets between processors, object code is

not binary-compatible across platforms. To enable object code compiled for

processor X to run on processor Y, a virtual machine must be created on

processor Y to emulate processor X's instructions, which results in a

considerable performance hit. For this reason, Windows NT offers a strong

source compatibility, which makes it a relatively simple matter to compile

the same code into native object code for each platform.

The Hardware Abstraction Layer (HAL), smooths over differences between

hardware implementations. All access to the hardware from the operating

system (OS) goes through the HAL, which makes changing of both the hardware

and the OS itself much simpler. The HAL, however, does not emulate the

instruction set of the platform; a common misconception.

MORE INFORMATION

Source code is compiled into executable or object code for the instruction

set of a specific processor or family (x86, 680x0, R3000/4000, and so

forth). This code runs natively only on that type of processor. Remember,

this reduces to 1's and 0's, hence binary, so even if two processors have a

large overlap in the available instructions (and they do; MOVs, XORs, or

whatever at the assembly language level), what is actually executed is not

even relatively "high level" human-readable assembly code but merely a

series of bytes that by convention/definition only are assigned the

meanings that are human-readable at the assembly language level.

For example, probably every microprocessor has an OR instruction. On the

Intel x86, the OR instruction may be represented in the instruction stream

by the bytes "09 [effective address]" (see page 456 of Microsoft's

80386/80486 Programming Guide, 2nd Ed.). On the R4000, however, it's nearly

guaranteed to be something different.

Thus, if you want to run an executable compiled for Intel on a MIPS chip,

you must run a program that behaves as an Intel instruction interpreter

(similar to a Basic interpreter, but much more complex). Such a program is

called an emulator, and will scan through the Intel object code and then in

turn execute equivalent commands in MIPS form on the processor. But the

emulator must do much more than that; it must also create a "virtual

machine," a complete software execution environment that behaves similar to

the original hardware/software environment that the executable was

originally compiled for.

Note that even in an ideal case, every processor X instruction requires

about 5-20 instructions on processor Y. The object code interpreter must

examine the next instruction/byte, compare its value to known instruction

values via some kind of table (depending on the implementation), and then

execute the equivalent native instruction. There is room for optimization

but it will never be very fast (relative to native code).

Therefore, run non-native object code only if you absolutely must. Below is

a binary compatibility table for Windows NT:

   System         Binary-Compatible on NT?

   ------        ------------------------

   Win16 apps     Yes (via Insignia's x86 emulation code)

   Win32 apps     No  (must re-compile)

   POSIX apps     No  (POSIX is a source-code standard)(1)

   OS/2 1.x apps  No  (Don't run on non-x86 machines at all)(2)

Notes: (1) POSIX 1003.1 is a C-language source-level standard for basic

operating system services. POSIX applications don't need to be binary-

compatible even on the same instruction set! That is, a POSIX application

compiled and linked for SCO on x86 will NOT run on x86 Windows NT POSIX or

x86 Sun/Interactive POSIX. (2) OS/2 1.x support is technically feasible but

would have required more work on the non-Intel platforms, and was not

considered a high priority.

The Hardware Abstraction Layer (HAL)

------------------------------------

A common misconception is that the HAL should allow binary compatibility.

The Windows NT HAL has absolutely nothing to do with the issue discussed

above; that is, running code complied for processor X on processor Y. Nor

is the HAL akin to a "virtual machine" implementation; it does not simulate

anything. Rather, the HAL is simply an example of a good modular software

design that deals with the issue of differences in hardware design between

machines with the same instruction set (or between instruction sets).

The HAL provides a set of services to the rest of the Windows NT executive

that abstracts and "hides" the differences between low- level hardware-

software interfaces, such as with DMA controllers, programmable interrupt

controllers, clocks and timers, and so forth. In a typical pre-Windows NT

operating system, there is lots of code embedded throughout the operating

system (particularly in device drivers) that is specifically tied to

particular implementations of hardware services (a particular PIC, a

particular DMA chip, and so forth). If one of these hardware pieces is

changed, lots of code scattered throughout the system will break. As a

result, the hardware never changed and a typical 486/66 machine today uses

the same low-function hardware devices that appear in the IBM AT 286 (if

not the IBM PC itself).

In Windows NT, any other part of the OS (including the kernel and all

device drivers) that needs to deal with those low-level devices now uses

HAL services, and is therefore isolated from changes in the hardware. If

you change those hardware pieces you only need to change the HAL. This

results in at least the following two advantages:

 - A cleaner, easier to write and debug design for the OS and device

   drivers.

 - The real possibility for innovation and change in the underlying

   hardware.

But the HAL does not provide an abstract instruction set, or the services

necessary for running object code from processor X on processor Y. It is

possible to write an such as OS if you are willing to take the huge

performance hit, but Windows NT isn't it. And because a well-designed OS

such as Windows NT can provide a very complete level of source-code

compatibility across instruction sets, and therefore a relatively painless

way of getting native-code versions of Win32-based applications, probably

no one will be willing to take that performance hit in a mainstream

operating system, no matter how fast the hardware.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: SubSys


Broadcasting Messages Using PostMessage() & SendMessage()

PSS ID Number: Q64296

Authored 28-Jul-1990	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

When SendMessage() is used to send a broadcast message (hwnd = 0xFFFF or

hwnd = -1), the message is sent to all top-level windows. A message

broadcast by PostMessage() is only sent to top-level windows that are

visible, enabled, and have no owner.

You might observe the effect of the difference when, for example, the top-

level window of your application calls DialogBox() to present a modal

dialog box. While the modal dialog box exists, its owner (your top-level

window) will be disabled. Messages broadcast using PostMessage() will not

reach the top-level window because the window is disabled, and will not

reach the dialog box because the dialog box has an owner. Messages

broadcast using SendMessage() will reach both the top-level window and the

dialog.

In Windows 3.1, PostMessage() will broadcast to invisible and disabled

windows just like SendMessage() already does.

Both PostMessage() and SendMessage() actually broadcast using the same

broadcast procedure. This procedure does some additional screening to make

sure that pop-up menus, the task manager window, and icon title windows are

insulated from broadcast messages.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrMsg


BUG: Bad Characters in 32-bit App on Win32s on Russian

PSS ID Number: Q126865

Authored 06-Mar-1995	Last modified 24-Mar-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.5

 - Microsoft Win32s versions 1.2 and 1.25

SYMPTOMS

When compiling, linking, and running a Russian application which was built

using Microsoft Visual C++ version 2 under on Windows NT version 3.5 the

application runs correctly. If this application is run on Russian Windows

version 3.1 with the Win32s libraries version 1.2 or 1.25 installed, some

parts of the user interface appear as meaningless set of characters.

CAUSE

The strings in the resources are stored in UNICODE format. Yet you must

pass all strings to Windows 3.1 in ANSI format. The drawing of the

resources is done by Windows 3.1. Win32s simply reads the 32-bit resources,

converts them to the 16-bit format equivalent, and passes the resources to

Windows 3.1. One stage of the conversion is to convert the UNICODE strings

into ANSI strings. This conversion for the Russian language is broken.

STATUS

Microsoft has confirmed this to be a problem in the product(s) listed at

the beginning of this article. This bug will be fixed in the next release

of Win32s.

Additional reference words: Cyrillic Russia 2.00 garbage corruption

KBCategory: kbbuglist

KBSubcategory: WIntlDev W32s


BUG: Console Applications Do Not Receive Signals on Windows

PSS ID Number: Q130717

Authored 25-May-1995	Last modified 30-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) version 4.0

SYMPTOMS

Console applications call SetConsoleCtrlHandler() to install or remove

application-defined callback functions to handle signals. On Windows 95,

the signal handler function only gets called for the CTRL_C_EVENT and

CTRL_BREAK_EVENT signals; the signal handler function is never called for

the CTRL_SHUTDOWN_EVENT, CTRL_LOGOFF_EVENT, and CTRL_CLOSE_EVENT signals.

CAUSE

Windows 95 sends CTRL_C_EVENT and CTRL_BREAK_EVENT signals to console

applications that have installed signal handers, but does not send

CTRL_SHUTDOWN_EVENT, CTRL_LOGOFF_EVENT, or CTRL_CLOSE_EVENT signals.

STATUS

Microsoft has confirmed this to be a bug in the Microsoft products listed

at the beginning of this article. We are researching this problem and will

post new information here in the Microsoft Knowledge Base as it becomes

available.

Additional reference words: Win95 4.00 console event signal

KBCategory: kbprg kbbuglist

KBSubcategory: BseCon


BUG: CreateDC Does Not Thunk DEVMODE Structure Correctly

PSS ID Number: Q128701

Authored 06-Apr-1995	Last modified 07-Apr-1995

The information in this article applies to:

 - Microsoft Win32s, versions 1.2 and 1.25

SYMPTOMS

Under Win32s version 1.2 and 1.25, when a Win32-based application displays

a printer setup dialog box that calls PrintDlg with the PD_PRINTSETUP flag

and the printing orientation is changed from Portrait to Landscape, the

DEVMODE structure obtained from the PrintDlg call to CreateDC is passed and

creates a printer DC. If the printer driver is a postscript driver,

anything printed using this DC is still in Portrait mode.

CAUSE

The thunking layer for CreateDC does not thunk the DEVMODE structure for

the postcript driver correctly.

RESOLUTION

To work around the problem, avoid calling CreateDC with a DEVMODE

structure. Instead, directly create the pinter DC by calling PrintDlg with

the PD_RETURNDC flag. Then change the printing orientation from within the

print dialog box.

STATUS

Microsoft has confirmed this to be a bug in the Microsoft products listed

at the beginning of this article. We are reasearching this problem and will

post new information here in the Microsoft Knowledge Base as it becomes

available.

Additional reference words: 1.20 1.25 3.10 3.50

KBCategory: kbprg kbbuglist

KBSubcategory: GdiPrn


BUG: ESC/ENTER Keys Don't Work When Editing Labels in

PSS ID Number: Q130691

Authored 24-May-1995	Last modified 23-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.51 and 4.0

 - Microsoft Win32s version 1.3

SYMPTOMS

When editing labels in a TreeView control, you should be able to press the

ESC key to cancel the changes or press the ENTER key to accept the changes.

However, when the TreeView control is contained in a dialog box,

IsDialogMessage processes the ESC and ENTER keystrokes and does not pass

them on to the edit control created by the TreeView control, so the

keystrokes have no effect.

CAUSE

The TreeView control creates and subclasses the edit control used for

in-place editing. The subclass procedure does not process the WM_GETDLGCODE

and WM_CHAR messages for the edit control properly.

RESOLUTION

To work around the problem, subclass the edit control and return

DLGC_WANTALLKEYS in response to the WM_GETDLGCODE message. Then process the

WM_CHAR messages for VK_ESCAPE and VK_RETURN.

To subclass the edit control, obtain the handle to the edit control by

using the TVM_GETEDITCONTROL message in response to the TVN_BEGINLABELEDIT

notification. Remove the subclassing when the TVN_ENDLABELEDIT notification

is received.

In response to the WM_CHAR|VK_ESCAPE message, have the application send

the TVM_ENDEDITLABELNOW with fCancel = TRUE message to cancel the edit. In

response to the WM_CHAR|VK_ENTER message, have the application send the

TVM_ENDEDITLABELNOW with fCancel = FALSE message to accept the edit.

All other WM_CHAR messages should be passed on to the default edit control

window procedure.

STATUS

Microsoft has confirmed this to be a bug in the Microsoft products listed

at the beginning of this article. We are researching this problem and will

post new information here in the Microsoft Knowledge Base as it becomes

available.

Additional reference words: 1.30 4.00 95

KBCategory: kbprg kbui kbbuglist

KBSubcategory: UsrCtl W32s


BUG: FindFirstFile() Does Not Handle Wildcard (?) Correctly

PSS ID Number: Q130860

Authored 30-May-1995	Last modified 12-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), version 4.0

SYMPTOMS

In Windows 95, the FindFirstFile() function interprets a wildcard (?) as

"any character" instead of "zero or one character," its true meaning. This

incorrect interpretation causes some searches to return invalid results.

For example, if the files, TEMP.TXT and TEMPTEMP.TXT, are in the same

directory, the following code finds the TEMPTEMP.TXT file, but not the

TEMP.TXT file:

   HANDLE hFind;

   WIN32_FIND_DATA findData = {0};

   hFind = FindFirstFile ("TEM?????.???", &findData);

   if (hFind == INVALID_HANDLE_VALUE)

      MessageBox (hwnd, "FindFirstFile() failed.", NULL, MB_OK);

   else

   {

      do

      {

         MessageBox (hwnd, findData.cFileName, "File found", MB_OK);

      }

      while (FindNextFile(hFind, &findData));

      CloseHandle (hFind);

   }

Windows NT correctly finds both the TEMP.TXT and TEMPTEMP.TXT files.

WORKAROUND

To work around this problem, choose an alternative wildcard search and

apply further processing to eliminate files that are found by the

alternative search, but do not match the original search. For example, the

code above could be changed to search for TEM*.* instead of TEM?????.???.

Then you could make an additional test for filenames that are up to 8

characters in length, followed by a ".", followed by up to 3 more

characters (8.3).

STATUS

Microsoft has confirmed this to be a bug in the Microsoft products

listed at the beginning of this article. We are researching this bug

and will post new information here in the Microsoft Knowledge Base

as it becomes available.

Additional reference words: win95 4.00 regular expression wild

KBCategory: kbprg kbbuglist

KBSubcategory:


BUG: GetKerningPairs Sometimes Fails on Win32s Version 1.2

PSS ID Number: Q125872

Authored 07-Feb-1995	Last modified 13-Jun-1995

The information in this article applies to:

 - Microsoft Win32s versions 1.2 and 1.25a

SYMPTOMS

GetKerningPairs will sometimes fail on Win32s version 1.2 causing the

32-bit application to exit mysteriously. The problem may only occur once in

a while with many successful runs interrupted by a single unsuccessful run.

CAUSE

The thunking layer for GetKerningPairs contains a bug in the code that

allocates a temporary buffer passed to the 16-bit version of

GetKerningPairs. The errant code executes whenever the number of kerning

pairs requested is equal to or less than 128. Requesting GetKerningPairs to

return 129 or more kerning pairs forces the thunking layer to use an

alternative buffer allocation method.

RESOLUTION

To work around the problem, ensure that the number of kerning pairs

requested from GetKerningPairs is greater than 128.

Typically, kerning pairs are retrieved with two calls to GetKerningPairs.

The first call retrieves the number of kerning pairs available. A buffer is

allocated based on the number of pairs returned. Then the second call to

GetKerningPairs retrieves the kerning pairs into the buffer.

To avoid the bug in GetKerningPairs, follow these steps:

1. Retrieve the number of kerning pairs available from GetKerningPairs.

2. Check that this value is greater than 128. If it is less than or

   equal to 128, reset the variable to an arbitrary value greater than

   128 -- like 129.

3. Use the new value to allocate the buffer of KERNINGPAIRS and pass

   this new value with the buffer to the second GetKerningPairs call.

STATUS

Microsoft has confirmed this to be a bug in the Microsoft products listed

at the beginning of this article. We are researching this problem and will

post new information here in the Microsoft Knowledge Base as it becomes

available.

Additional reference words: 1.20 font kerning

KBCategory: kbprg kbbuglist

KBSubcategory: GdiFnt


BUG: MDI Child Window's "Minimize" System Menu Disabled

PSS ID Number: Q110795

Authored 28-Jan-1994	Last modified 10-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

 - Microsoft Win32 SDK, version 3.1

SYMPTOMS

After creating a new multiple document interface (MDI) child window in an

MDI application, the child window's Minimize System menu option will be

disabled after the following actions:

1. The MDI child window is created and in the topmost z-order.

2. The user accesses the MDI child window's System menu through the

   shortcut keys: ALT+SPACE, RIGHT ARROW.

These actions will cause the child window's System menu to appear with the

Minimize menu option disabled. This behavior can be demonstrated with File

Manager. From File Manager's Window menu, choose New Window. Next, press

ALT+SPACE and then press the RIGHT ARROW key to bring up the new window's

System menu. The Minimize option will be disabled.

NOTE: The Minimize menu item is not disabled if the System menu is accessed

through the ALT+"-" (minus) shortcut key or the mouse. Also, the Minimize

menu item is not disabled if the window is moved.

RESOLUTION

This problem may be avoided if the MDI parent calls GetSystemMenu() after

creating the MDI child window. If the parent calls GetSystemMenu

(hwndMDIChild, TRUE) for the MDI child window, the System menu is reset to

the Windows default state, thus eliminating the problem.

STATUS

Microsoft has confirmed this to be a bug in Windows version 3.1 and

Windows NT version 3.1. We are researching this problem and will post new

information here in the Microsoft Knowledge Base as it becomes available.

MORE INFORMATION

Although MDI is supported, it is discouraged. New users find it complicated

to understand, so Microsoft is encouraging ISVs to use SDI or greatly

simplify their interfaces to act like an SDI (there are some advantages to

coding using MDI).

Additional reference words: buglist3.10 3.10

KBCategory: kbprg kbbuglist

KBSubcategory: UsrMdi


BUG: Menu Bar Covered By Main Window Client Area

PSS ID Number: Q109539

Authored 04-Jan-1994	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

 - Microsoft Win32 SDK, version 3.1

SYMPTOMS

In an application, the lower half of the menu bar is covered by the client

area of the main window.

CAUSE

This problem can be caused by a command with a null menu string or

separator at the end of the menu bar. For example, if the following menus

are used in a window, they will display the problem:

   PROBLEMMENU MENU DISCARDABLE

   BEGIN

      POPUP "&Popup 1"

         BEGIN

            MENUITEM "&Menu Item 1", 1

         END

      MENUITEM "", 2

   END

-or-

   PROBLEMMENU MENU DISCARDABLE

   BEGIN

      POPUP "&Popup 1"

         BEGIN

            MENUITEM "&Menu Item 1", 1

         END

      MENUITEM SEPARATOR

   END

RESOLUTION

To work around this problem, remove the command with a null menu string or

separator at the end of the menu bar.

STATUS

Microsoft has confirmed this to be a bug in the Microsoft products listed

at the beginning of this article. We are researching this bug and will post

new information here in the Microsoft Knowledge Base as it becomes

available.

Additional reference words: utoff overlayed view toolbar

KBCategory: kbprg kbbuglist

KBSubcategory: UsrMen


BUG: Pressing SHIFT+ESC Doesn't Generate WM_CHAR on Windows

PSS ID Number: Q129861

Authored 08-May-1995	Last modified 08-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) version 4.0

SYMPTOMS

Pressing SHIFT+ESC in an application running under Windows 95 doesn't

generate a WM_CHAR message even though it does generates a WM_CHAR

message for applications running under Windows version 3.x and Windows NT.

CAUSE

The key table that TranslateMessage on Windows 95 uses to generate the

WM_CHAR messages doesn't include the SHIFT+ESC key combination.

RESOLUTION

If you need to use this key combination, use the WM_KEYDOWN or WM_KEYUP

messages.

STATUS

Microsoft has confirmed this to be a bug in the Microsoft products

listed at the beginning of this article. We are researching this problem

and will post new information here in the Microsoft Knowledge Base as it

becomes available. This bug is scheduled to be corrected in a future

version of Windows 95.

Additional reference words: 4.00

KBCategory: kbui kbbuglist

KBSubcategory: UsrInp


BUG: Race Between 2 Threads Sharing a Socket Causes Problem

PSS ID Number: Q126346

Authored 21-Feb-1995	Last modified 01-May-1995

The information in this article applies to:

 - Microsoft Win32 Device Development Kit (DDK) for Windows NT

   version 3.5

SYMPTOMS

Packets between the TCP, UDP, and IP layers are lost.

CAUSE

There appears to be a problem with a race condition between two threads

that share a socket where one is closing a socket while the other tries to

call recvfrom() on the same socket. This causes problems the next time a

socket is bound to the same UDP port.

RESOLUTION

The vendor should implement a workaround within the application so that

this race condition does not occur.

STATUS

Microsoft has confirmed this to be a problem in the Microsoft products

listed at the beginning of this article. We are researching this problem

and will post new information here in the Microsoft Knowledge Base as it

becomes available.

MORE INFORMATION

This Sockets/UDP problem was discovered while testing the TX1000 NCPI

driver for Windows NT. Here are some notes showing what appears to be

happening:

Thread 1                        Thread 2

--------                        ---------

Create DGRAM socket x

Bind socket x to:

        IPADDR = ANY

        PORT = 1571

Create thread 2 ----------------->

                                RecvFrom on socket x

                                ...

                                Packet received on x (recvfrom completes)

                <---------------signal main thread

Process rec'd packet            wait for main thread to consume buffer

Signal buffer available--------->

                                RecvFrom on socket x

                                ...  { repeats many times }

Normal Shutdown Sequence (on Last Packet)

-----------------------------------------

                                Packet received on x (recvfrom completes)

                <---------------signal main thread

Process rec'd packet            wait for main thread to consume buffer

Signal buffer available--------->

Application done                (1) RecvFrom on socket x

(2) close socket x

                                (3) RecvFrom fails with expected error

                                Thread terminates

Usually, events occur in sequence (1, 2, then 3). In this normal case, the

socket is cleared correctly, and everything works the next time the

application runs.

Shutdown Sequence that Causes Problems (on Last Packet)

-------------------------------------------------------

                                Packet received on x (recvfrom completes)

                <---------------signal main thread

Process rec'd packet            wait for main thread to consume buffer

Signal buffer available--------->

Application done

(1) close socket x              (2) RecvFrom on socket x

                                (3) RecvFrom fails with expected error

                                Thread terminates

In this case, the sequence is slightly different. The closesocket()

function from main thread starts, but does not complete, before thread 2

runs. While thread 1 is suspended awaiting completion of closesocket(),

thread 2 runs and posts next recvfrom() on same socket. The closesocket()

function completes successfully, and recvfrom() fails as in normal case.

But the next time the application runs and binds to the same UDP port, the

following occurs:

 - All socket calls (bind(), recvfrom()) are successful

 - All incoming packets to that UDP port are discarded before reaching the

   application -- recvfrom() never completes. The following command shows

   that the "receive errors" count has been incremented once for each

   incoming packet that was lost:

   netstat -s -p udp

The conclusion is that in this case the socket was not cleaned up properly

due to the race condition between the closesocket() and the recvfrom()

functions.

Additional reference words: 3.50

KBCategory: kbprg

KBSubcategory: NtwkWinsock


BUG: SetWindowPlacement and ptMin.x or ptMax.x = -1

PSS ID Number: Q110793

Authored 28-Jan-1994	Last modified 13-Jun-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK, versions 3.1, 3.5, 3.51, 4.0

SYMPTOMS

Passing an X coordinate value of -1 to SetWindowPlacement causes the

parameter to be ignored. If ptMinPosition.x is set to -1,

SetWindowPlacement won't reset the minimized window coordinate; this is

also true for ptMaxPosition.x. This was undocumented in the Windows 3.1 SDK

documentation.

CAUSE

This problem is caused by the use of -1 as a special value. A value of -1

in the X coordinate causes the API (application programming interface) to

use the window's current coordinate for the specified parameter.

RESOLUTION

Microsoft has confirmed this to be a bug in the products list above.

This behavior may be a problem for application developers because they may

want to set the maximized or minimized horizontal coordinate of a window to

-1. To avoid this problem, the developer should trap values of -1, and use

a value of -2 or 0 (zero) as appropriate.

Additional reference words: 3.10 3.50 3.51 4.00 95

KBCategory: kbprg kbbuglist

KBSubcategory: UsrWndw


BUG: SNMP Service Produces Bad "Error on getproc(InitEx) 127"

PSS ID Number: Q130699

Authored 25-May-1995	Last modified 30-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

SYMPTOMS

When the SNMP service is started with debug level 2 or greater, it returns

this error message:

   error on getproc(InitEx) 127

RESOLUTION

This error message should be ignored.

STATUS

Microsoft has confirmed this to be a bug in the Microsoft products listed

at the beginning of this article. We are reasearching this problem and will

post new information here in the Microsoft Knowledge Base as it becomes

available.

MORE INFORMATION

How to Start the SNMP Service

-----------------------------

The SNMP service can be started from either the control panel or from

a console window.

Type "net help start snmp" in a console box to see how to configure error

logging of the SNMP agent.

The syntax of the command is:

   net start snmp [/logtype: type] [/loglevel: level]

where:

 - /LOGTYPE: type determines where the log will be created. The possible

   values are 2 for file, 4 for eventlog, and 6 for both. The default is 4.

   The file option creates a file under \WINNT\SYSTEM32 called SNMPDBG.LOG.

 - /LOGLEVEL: level determines the debug level. The higher the number, the

   more the detail obtained. The default is 1 (minimum), and the range is

   from 1 to 20.

Here is an example:

   net start snmp /logtype:6 /loglevel:10

This starts the SNMP service with loglevel 10, and logs events in the

eventlog as well as in SNMPDBG.LOG.

The SNMP service can also be started from a console window without typing

"net start." This makes all error messages go to the console window and can

be used to help in debugging when writing SNMP applications. For example,

the following starts the SNMP service:

   cmd-prompt> snmp

Additional reference words: 3.10 3.50

KBCategory: kbnetwork kbbuglist

KBSubcategory: NtwkSnmp


BUG: Using WM_SETREDRAW w/ TreeView Control Gives Odd Results

PSS ID Number: Q130611

Authored 23-May-1995	Last modified 23-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.51 and 4.0

SYMPTOMS

If a program uses the WM_SETREDRAW message to turn off updating of a

TreeView control before adding items, the TreeView control can behave

strangely.

For example, if the item being added to the control uses the TVI_FIRST

style to insert it to the top of the tree and the top of the tree is

scrolled above the top of the visible window, it may be impossible to bring

the item into view.

Another possible symptom is that the TreeView control doesn't repaint

itself at all. These problems occur only if the program has used the

WM_SETREDRAW message to turn off updating the TreeView control.

RESOLUTION

Don't use the WM_SETREDRAW message with the TreeView control while adding

items to the control.

STATUS

Microsoft has confirmed this to be a bug in the Microsoft products listed

at the beginning of this article. We are researching this problem and will

post new information here in the Microsoft Knowledge Base as it becomes

available.

Additional reference words: 4.00 95

KBCategory: kbprg kbbuglist

KBSubcategory: UsrCtl


BUG: Win32 SDK Ver. 3.5 Bug List for Win32 SDK and Win32 API

PSS ID Number: Q121907

Authored 23-Oct-1994	Last modified 03-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), version 3.5

SUMMARY

The following is a list of bugs in the Win32 SDK and Win32 API (version

3.5) that were known at the time of its release. The list is divided

into four sections: Base, GDI, Networking, and User.

MORE INFORMATION

Base

----

 - SetLastErrorEx() does not raise a RIP_INFO debug event.

 - Overlapped I/O does not work on CD-ROM drives.

 - CDECL should be defined to __cdecl in WINDEF.H.

 - EVENTLOGRECORD strings are incorrectly given as type WCHAR in winnt.h.

   The online help correctly gives the strings as type TCHAR.

 - SetComputerName(""); sets computer name to an empty string at reboot,

   which the logon service cannot handle. The Network applet does not

   allow this computer name. Your code should check for this case as well.

 - Registry allows remote access to certain performance data, but not

   local access.

 - RegCreateKeyEx() puts the class string in all created subkeys.

 - Call FileTimeToLocalFileTime() with a structure containing 0, then pass

   the result to FileTimeToSystemTime(). FileTimeToSystemTime() returns a

   bad value in SystemTime.wHour.

 - DLL does not receive DLL_PROCESS_DETACH if last thread in process calls

   ExitThread().

GDI

---

 - Return values for certain GetBitmapBits() calls are not the same on

   Windows and Windows NT.

 - Return values for certain StretchBlt() calls are not the same on

   Windows and Windows NT.

 - When a transparent window is present and full drag is enabled, the

   display is not refreshed correctly when a window is dragged.

 - GetCharABCWidths() returns twice the width for character 0x92 that

   GetTextExtentPoint() returns using Arial font.

 - Use a True Type font off the network, produce a few glyphs, and kill

   the network connection. You get an in page memory exception if you

   try to use the font with different (not cached) glyphs. Restore the

   network connection and try to use the font. The font was tagged as

   invalid, so all subsequent TextOut() calls fail.

 - CreateDC() returns ERROR_MOD_NOT_FOUND instead of ERROR_ACCESS_DENIED

   for a printer with no access rights. The problem is that GDI does not

   check for ERROR_ACCESS_DENIED when the open printer fails; GDI directly

   tries to do a LoadLibrary() on the pszDevice.

 - EndDoc() reports success when given an information context (IC).

 - AbortDoc() reports success when given an information context (IC).

 - glGet() doesn't generate GL_INVALID_OPERATION error code when it is

   called within glBegin()/glEnd().

Networking

----------

 - For MS-DOS clients, NetAccessGetInfo() returns code 53.

   (ERROR_BAD_NETPATH) for the local server.

 - For MS-DOS clients, NetServerEnum2() with a bad domain should return

   error 2320, but it returns Windows NT error code 6118.

 - For MS-DOS clients, NetShareGetInfo() level 2 fails with error 87.

 - For MS-DOS clients, NetShareGetInfo() level 3 returns NERR_Success,

   but level 3 is not a valid level.

 - NetWkstaGetInfo() returns a platform id of PLATFORM_ID_OS2 for a

   downlevel Windows for Workgroups machine.

 - NetUserAdd() remoted from a 16-bit application to a server with a

   long name fails with error 59 (unexpected network error).

 - NetServiceEnum() resumehandle and prefMaxLen fields are ignored.

 - NetGetDCName() with domain name of "." or "?" returns error 2102

   (NERR_NetNotStarted), not 2453 (NERR_DCNotFound).

 - NetUseEnum() with a preferred buffer size less than 40 bytes returns

   ERROR_MORE_DATA, rather than NERR_BufTooSmall.

 - NetServerEnum() with a zero length buffer returns ERROR_MORE_DATA,

   rather than NERR_BufTooSmall.

 - NetScheduleJobEnum() with a small preferred buffer size returns

   ERROR_MORE_DATA, rather than NERR_BufTooSmall.

 - NetStatisticsGet() remoted to a downlevel OS/2 server does not

   work for the service "LanmanWorkstation".

 - NetAccessEnum() with NULL base path causes an access violation.

 - NetUserModalsGet() level 2 returns error 87 (ERROR_INVALID_PARAMETER).

 - Network API doc errors: NetUserModals() supports a level 3 structure in

   Windows NT 3.5, NetGroupSetUsers() also supports level 1,

   NetAccessCheck() is in docs but not the header files, and the

   NetAuditClear()/NetAuditRead() service parameter should be marked as a

   reserved field that must be NULL.

 - NetConfigGet() and NetConfigGetAll() return error 2146 when remoted to

   Windows NT. This API should only work from Windows NT to a downlevel

   machine. It should return ERROR_NOT_SUPPORTED or NERR_InvalidApi is

   remoted to Windows NT.

 - NetWkstaUserSetInfo() level 0 returns error 124 (invalid level).

 - NetReplImportDirUnlock() returns error 87 (NERR_Invalid_Parameter) if

   the directory is not locked.

 - NetReplExportDirEnum() ignores suggested buffer size.

 - NetUseEnum() level 2 remoted to an OS/2 machine returns error 50

   (ERROR_NOT_SUPPORTED), not error 124 (ERROR_INVALID_LEVEL).

 - NetConfigSet() returns success when remoted to Windows NT.

 - NetWkstaUserSetInfo() called with an incorrect level returns error 87

   (INVALID_PARAMETER), rather than error 124 (ERROR_INVALID_LEVEL).

 - NetMessageNameEnum() with a zero length buffer returns NERR_Success,

   rather than NERR_BufTooSmall.

User

----

 - DDESPY frees locked global objects when filtering out WM_DDE_INITIATE

   messages.

 - GetTabbedTextExtent(), TabbedTextOut(), TextOut(), and DrawText() GP

   fault with bad string length values.

 - Journal Recording causes improper icon title painting.

 - With a WH_MSGFILTER installed, MSGF_NEXTWINDOW is not sent when the

   user Alt-Tabs to the next window.

 - Active Screen Saver doesn't allow WH_JOURNALPLAYBACK hook.

 - 122-key kbd: WSCtrl, Jump, Finish keys are VK_NONAME.

 - Using of NumLock key for PF1 in terminal emulation programs does not

   work.

 - Calling GetKeyState()/GetKeyboardState() from a thread that is not

   reading from an input queue causes a QEVENT_UPDATEKEYSTATE to be posted

   to the queue, but it is never removed. If the input queue is being

   read, the key state is one update event out of date.

 - System hang during journalling if a hung application exists and many

   system events are posted to the hung application.

 - Windows NT does not wait for all applications to return their response

   from WM_QUERYENDSESSION before starting to destroy an application. This

   can cause data loss in OLE.

 - WM_GETMINMAXINFO not used when window has WS_CAPTION and WS_THICKFRAME.

 - Edit control clips italic text.

 - Hotkeys are not checked during journal playback.

 - OLE 2.01 server creates a window and uses SetParent() on the window of

   the container. When the container is resized to a smaller window than

   the server, the container can no longer be resized with the mouse over

   the server window. This is a side effect of calling SetParent() on a

   window that does not have style WS_CHILD.

 - GetSystemMetrics() does not check parameter to see if it is within

   range and returns garbage for out of range values.

 - Windows applications with focus can be overlapped.

 - In large font video mode, AdjustWindowRect() returns bad width if the

   window does not have a menu and a bad height if the window has a menu.

 - Prototypes for SetSystemCursor() and LoadCursorFromFile() are missing

   from WINUSER.H.

Additional reference words: 3.50 buglist3.50

KBCategory: kbprg kbnetwork kbbuglist

KBSubcategory: BseMisc GdiMisc NtwkMisc UsrMisc


BUG: Win32 SDK Version 3.5 Bug List - OLE

PSS ID Number: Q122679

Authored 09-Nov-1994	Last modified 10-Nov-1994

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), version 3.5

SUMMARY

The following lists the bugs in the Win32 SDK and OLE API that were known

when the SDK was released.

MORE INFORMATION

 - Packager will report that there is not enough memory when you try to

   package a file which is in use.

 - VB can't activate Word object if Word is running in separate VDM.

 - MFC 2.5 OLE 2.0 Automation Server fails initialization.

 - If a client thread terminates without calling CoUnitialize(), its

   servers in the same process are not released.

 - OLE 2.0 hides application aborts. The server does not receive the

   exception.

 - CoCreateInstance() returns REGDB_E_CLASSNOTREG when the object create

   fails, instead of the return code from DllGetClassObject() from the

   inproc server DLL.

 - OLE objects inherit only "system" environment variables, not "user"

   environment variables.

 - Users can log on and start an ole app before the OLE service is

   autostarted.

 - Passing CoMarshalInterface() a NULL pUnk (pointer to IUnknown)

   causes an access violation.

 - CoGetClassObject() returns E_OUTOFMEMORY when DllGetClassObject()

   fails.

 - If an OLE Server which dies after registering its class, the container

   will stall waiting for CoGetClassObject() to succeed.

 - Class cache never shrinks - all classes are treated as InUse.

 - Default handler causes RPC_E_FAULT exceptions during OnClose.

 - ::SetColorScheme() does not validate lpLogPal.

 - Messages for server ownerdraw menuitems on menu bar go to the

   container.

 - The server is started if you "Insert" a "Link from File" choosing

   icon format.

 - IsLinkUpToDate() returns S_FALSE after object creation. This can cause

   containers to run the server twice during creation of the object.

 - Setting the link source with IOL::SetSourceMoniker() does not update

   the presentation cache, even though it does run the server app.

 - AddRef() does not marshall count back properly for return value.

 - BindToStorage() on non-existent file returns MK_E_INVALIDEXTEN.

 - IOleCache::Cache() fails for ICON aspect unless metafile format is

   used.

 - IOleCache2::DiscardCache() does not persist uncaches.

 - If an enhanced metafile node exists and IOleCache::Cache is used to

   cache multiple NULL FORMATETCs, a node is added.

 - IViewObject::GetColorSet() after flushing cache should return

   OLE_E_BLANK, but signals Win32 error 0x8007000e.

 - OleDuplicateMedium() does not GlobalUnlock() source METAFILEPICT in

   the error case.

 - Iconic aspect has incorrect colors when played in metafile.

 - OLE Cache has a limit of 100 nodes, but accepts more and never

   returns from the call.

 - GetColorSet() for WMF should return LOGPALLETE, which is the union

   of colors used in the contained CreatePalette() calls. GetColorSet()

   only returns the first colorset found in this case.

Additional reference words: 3.50

KBCategory: kbprg kbbuglist

KBSubcategory: LeTwoMisc


BUG: Win32 SDK Version 3.5 Bug List - WinDbg Debugger

PSS ID Number: Q122681

Authored 09-Nov-1994	Last modified 29-Nov-1994

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), version 3.5

SUMMARY

The following is a list of bugs in the WinDbg debugger that were known

at the time of the release of the Win32 SDK version 3.5.

MORE INFORMATION

 - Enter rgbGlobal, s in watch window (note: rgbGlobal is defined as a

   character array). The variable is displayed as a character string and

   an array that can be expanded. When expanding the array, the value of

   each element is "CAN0026: Error: bad format string."

 - REP and REPE are the same prefix codes. REPE is to be used for string

   comparisons and REP for all other instructions. WinDbg always uses REP.

 - Type information defined in a DLL is not available when the current

   context is another DLL or an EXE.

 - Breakpoint message classes do not match class list in SPY.

 - C++ expresssion evaluator doesn't handle default function arguments.

   This is because the compiler does not include them in the debug

   information.

 - Locals window updates on radix change.

 - Evaluation of a function with breakpoints returns an incomplete result.

 - The Memory Window can't be scrolled up before the starting address.

 - Locals window collapses expanded structures on change of scope, such

   as stepping into a block (not a new function).

 - The value of array members cannot be changed.

 - The expression evaluator does not handle casting from a class to a

   primitive data type.

 - Remove Last in Quickwatch only works once when multiple items are added

   to the watch list in a single quickwatch session.

 - The return value type is not reported for ?<FuncName>.

 - Function evaluation reports "Error: function requires implicit

   conversion" for a function taking a structure (not a pointer to

   a structure).

 - Watch window shift-key selection is not consistent: sometimes all

   characters from the beginning of the expression to the caret position

   are selected, sometimes 2 characters are selected.

 - User DLLs dialog silently discards edits after picking a DLL and

   changing the radio button from suppress to load.

 - Information windows don't maintain color after structure expansion.

 - WinDbg disassembles F2 66 F0 F0 AF as "repne lock lock sca" not

   "repne lock lock scasw".

 - Breakpoints may not work correctly in multithreaded apps in areas not

   protected by critical sections.

 - Choosing Stop Debugging and Restart causes memory leak (100K per

   iteration).

 - Combo box in dialog for browsing symbol files is too narrow to show

   the *.dbg.

 - Debug.Watch does not set default watch expression to the selection

   made in the source window.

 - If you set a conditional breakpoint, you step over it with an F10, and

   the condition is not currently satisfied, the program will run to

   completion, rather than stepping.

 - Long expression (?arg00+arg01+...+arg31) causes debuggee to run to

   termination.

 - ?<function returning near pointer> displays segment.

 - Windbg hangs if exited during aedebug start.

 - A vararg function evaluation fails on Mips and Alpha.

 - Private members may not be evaluatable.

 - First Command Window prompt after connecting to target machine for

   kernel debugging is ">", not "KDx86>", "KDMIPS>", or "KDALPHA>".

 - Context expression evaluation of item up the callstack cannot be

   evaluated and causes CXX0036: Error: bad context {...} specification.

 - Alpha: Disassembly of RS, RC, RPCC, FETCH, and FETCH_M instructions

   displays no operand.

 - Help file says "u" command is for unfreezing a thread. The "u" command

   is for unassemble; it is the "z" command that is used for unfreezing a

   thread.

 - Automatic forward searching not done by breakpoint dialog. Otherwise,

   when setting a breakpoint on a line that does not contain executable

   code, the breakpoint is set on the next executable line.

 - Automatic forward searching not done when modules are loaded. Otherwise,

   when setting a breakpoint on a line that does not contain executable

   code, the breakpoint is set on the next executable line.

 - OK button not always active on Set Process dialog.

 - Alpha: Large enumerated value not displayed correctly (16-bits instead

   of 32-bits).

 - The Delete button in User DLLs dialog is always active.

 - ?Spinlock::Spinlock should display the prototype for the function, but

   it causes CXX0046: Error: argument list required for member function.

 - Flat callstack displayed debugging 16-bit Windows-based application.

 - File menu Save_All is not enabled consistently on all platforms.

 - Page up/down goes farther than scroll thumb in the Memory Window.

 - Page up/down doesn't move scroll thumb in Memory Window.

 - Disassembler option "Display Symbols" ignored on Alpha.

 - Ppcodes always displayed in lower case in MIPS disasembly, even if

   "Uppercase symbols and opcodes" is checked.

 - Create several workspaces for a single program, choose Delete from the

   Program menu, and select several of the workspaces. WinDbg locks up

   when you select OK.

 - Deleting the last debugger DLL causes an access violation.

 - Bad caret movement when editing Memory Window with ASCII format.

 - Calls window not updated if the current thread is changed with the

   Set Thread dialog. The Calls window is updated if the Command window is

   used to set the current thread.

 - Thread-specific translations of segment registers is not done. The

   segment register is translated using thread 0's descriptor table.

 - When stepping over a function which contains a breakpoint, execution

   halts, but there is no message indicating that a breakpoint was hit.

 - Value of "this" pointer is incorrect in a virtual function in a derived

   class.

 - Based pointers in flat segments are displayed as a 16-bit value, not a

   32-bit value. In addition, nothing happens when you click the expansion

   button.

 - WINDBG won't set a breakpoint on code placed in memory and then

   executed.

 - Windbg does not know about all exceptions that can occur while

   debugging 16-bit code.

 - Alpha: CVTxx instructions disassembled with 3 operands, instead of

   only 2 operands. The first operand is wrong, the second operand would be

   the correct first operand, and the third operand would be the correct

   second operand.

 - !help <str> reports that there is no help available.

 - Set a breakpoint on a function call which spans multiple source lines,

   but don't set the breakpoint on the last line. Save the information and

   leave the debugger. When you restart WinDbg with the saved information,

   WinDbg cannot resolve the breakpoint.

 - Alpha: Cannot step through call through a function pointer.

 - Commands sxeld and sxdld cause the debugger to stop when a DLL is

   loaded.

 - If there are no symbols loaded, double-clicking a symbol in the call

   stack produces a disassembly window with a starting address of 0.

 - The following context operators cause "CXX0036: Error: bad context {...}

   specification":

      ?{,functest.c,functest.exe}count

      ?{,functest.c,}count

   The following context operators cause "CXX0017: Error: symbol not

   found":

      ?{,,functest.exe}count

      ?{,,}count

 - When the current instruction is "cmp dword ptr [esp+18],01", the

   register window shows a calculation based on [esp], rather than

   [esp+18].

 - WinDbg displays only the first letter of a 'const WCHAR *const'

   variable. Casting the variable to a WCHAR * in the Watch window

   works around the problem.

 - Run windbg -g cmd.exe and invoke a batch file that repeatedly invokes

   another command; WinDbg will leak memory.

 - x86: f2a6 is disassembled as "repnee cmpsb", not "repne cmpsb",

   f2a7 is disassembled as "repnee cmpsb", not "repne cmpsd",

   f2ae is disassembled as "repnee scasb", not "repne scasb",

   f2af is disassembled as "repnee scasd", not "repne scasd",

   f0a6 is disassembled as "locke cmpsb", not "lock cmpsb",

   f0af is disassembled as "locke scasd", not "lock scasd",

   f32ea6 is disassembled as "rep cmpsb", not "repe cmpsb",

   f326a7 is disassembled as "rep cmpsd", not "repe cmpsd",

   f32ea7 is disassembled as "rep cmpsd", not "repe cmpsd",

   f366a7 is disassembled as "rep cmpsw", not "repe cmpsw",

   f36665a7 is disassembled as "rep cmpsw", not "repe cmpsw",

   f326ae is disassembled as "rep scasb", not "repe scasb",

   f365af is disassembled as "rep scasd", not "repe scasd",

   f33eaf is disassembled as "rep scasd", not "repe scasd",

   f3f0af is disassembled as "rep locke scasw", not "repe lock scasw",

   f366af is disassembled as "rep scasw", not "repe scasw",

   f36636af is disassembled as "rep scasw", not "repe scasw".

 - dc doesn't accept the '&' prefix for an address specifier.

 - CXX0004: Error: syntax error on reference to float array. For

   example, the error is produced by "g .115;?Pf[8], where Pf is

   declared float Pf[11].

 - If you have a DLL built with multiple files with the same name (that

   live in different source directories), you cannot set a break point in

   2nd file with same name.

 - Error "CXX0034: Error: types incompatable with operator" accessing

   members, member functions, and overloaded operators of base classes

   and virtual base classes or a derived class.

 - Alpha: WinDbg doesn't display floating part of a float constant.

 - Crash dumps fail because of bad symbol lookup. This breaks !process

   when kernel debugging as well.

Additional reference words: 3.50

KBCategory: kbtool kbbuglist

KBSubcategory: TlsWindbg


BUG: Win32 Ver 3.5 SDK Bug List at Release - Subsystems & WOW

PSS ID Number: Q122048

Authored 25-Oct-1994	Last modified 29-Nov-1994

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), version 3.5

SUMMARY

The following is a list of the bugs in the Win32 version 3.5 SDK that were

known when Win32 version 3.5 was released. The list is divided into three

sections: OS/2 Subsystem, POSIX Subsystem, and Windows on Win32 (WOW).

MORE INFORMATION

OS/2 Subsystem

--------------

 - Extended characters in editors don't work with right-hand Alt key.

 - DosRmDir() returns ERROR_PATH_NOT_FOUND, not ERROR_FILE_NOT_FOUND, if

   passed the name of a directory that does not exist.

 - CTRL-X doesn't show with OS/2 Epsilon, although it is received by the

   application.

 - DosSelectDisk() returns error if disk not ready, but not under OS/2.

 - DosFindFirst() doesn't find config.sys in the registry.

 - Ctrl-C doesn't centre text in Word 5.5 for OS/2.

 - Ctrl-C will not cancel Fortran 5.1 setup.

 - DosQApptype() returns ERROR_INVALID_EXE_SIGNATURE (191) if pszFileName

   does not use the correct .EXE format, but OS/2 returns

   ERROR_BAD_EXE_FORMAT (193).

 - DosMove() returns error 80 if the target file exists, but OS/2 returns

   error 5.

 - DosSetFileMode() returns error 0x02 if the file does not exist, but

   OS/2 returns error 0xCE.

 - OS/2 subsystem doesn't load REXXINIT.DLL on startup, as OS/2 does,

   so OS/2 applications using REXX will fail on the first attempt.

 - Flags3 field not preserved between DosDevIOCtl/ASYNC_SETDCB and

   DosDevIOCtl/ASYNC_GETDCB. Flags3 is always returned with a value of 3.

 - Many vio functions return the wrong error code.

 - Epsilon not jumping back after matching braces.

 - NetHandleGetInfo() returns error 87 at level 2 or level 3.

 - DosCreateThread() corrupts 11 words of temporary (under OS/2, only

   2 words are corrupted).

 - UUPC OS/2 1.x application tries to open and write to the com port. CTS

   and DTR come up, but RTS never does.

 - SQL 4.2 setup fails to configure sort order.

 - DosKillProcess() of ancestor with DKP_PROCESSTREE succeeds, but OS/2

   returns ERROR_NOT_DESCENDANT.

 - DosCWait() with DCWA_PROCESSTREE returns when the process terminates,

   not when the tree terminates.

 - OS/2 CMD.EXE hangs after running Epsilon or PWB.

 - Signals not held while resizing data segments with DosReallocSeg().

POSIX Subsystem

---------------

 - printf() doesn't check to see if writing fails on the first character;

   it tries to write the second character instead of returning an error.

Windows on Win32 (WOW)

----------------------

 - GlobalSize() of handle returned by GetMetaFile() may not match.

 - Invalid TEMP environment variable causes problems, whereas Windows 3.1

   will use the root if the TEMP environment variable is invalid.

 - GetExitCodeProcess() does not return exit codes for WOW applications.

 - Floating point exceptions are not reported to the debugger.

 - Segment Load Failure in KRNL386 after using WINDISK.EXE.

 - Locking at negative offset fails on WOW with EACCES, but works under

   Windows.

 - WIN16 emulator incorrectly handles FBSTP instruction on MIPS, Alpha,

   and x86 with no math coprocessor.

 - WOW passes wrong size buffer to spooler when 16-bit application passes

   wrong size structure to WOW.

 - WOW uses Windows 3.0 devmode structure, not 3.1 devmode structure,

   which has two extra fields.

 - Fast Alt+Tab between WOW apps selects the File menu from one of the

   applications.

 - WM_MENUSELECT wParam and lParam are lost in PostMessage().

 - EndDeferWindowPos() returns 0 for success, but returns nonzero for

   success under Windows.

Additional reference words: 3.50 buglist3.50

KBCategory: kbprg kbbuglist

KBSubcategory: SubSys


BUG: Win32s 1.2 Bug List (at the Time of its Release)

PSS ID Number: Q121906

Authored 23-Oct-1994	Last modified 15-Jun-1995

The information in this article applies to:

 - Microsoft Win32s version 1.2

The following is a list of the known bugs in Win32s version 1.2 at the

time of its release.

 - EM_GETWORDBREAKPROC return code is incorrect.

 - Int 3 cannot be trapped via Structured Exception Handling (SEH) on

   Win32s.

 - GlobalAlloc(GMEM_FIXED) from 32-bit .EXE locks memory pages. It is

   more efficient to use GlobalAlloc(GMEM_MOVEABLE) and call GlobalFix()

   if necessary.

 - WinHlp32.exe will not run.

 - C Run-time functions getdcwd()/getcwd() do not work.

 - PlayMetaFileRecord()/EnumMetaFile() contain incorrect lpHTable.

 - Print setup common dialog does not work as expected (the dialog does

   not appear in some situations).

 - Size of memory mapped files is rounded to a whole number of pages,

   meaning that the size is a multiple of 4096 bytes.

 - Functions chdrive() and SetCurrentDirectory() fail on PCNFS network

   drives.

 - Calling CreateWindowEx() with a 32-bit menu handle causes int 3.

 - GetExitCodeProcess() does not return exit codes for Win16 applications.

 - FindFirstFile()/FindNextFile() return local time, not Universal

   Coordinated Time (UTC) time. This behavior matches Windows 3.1, but not

   Windows NT.

 - Memory passed to Netbios() must be allocated with GlobalAlloc().

 - biSizeImage field of BITMAPINFOHEADER is zero

 - CreateFile() on certain invalid long filenames closes Windows.

 - Only the first CBT hook gets messages.

 - GlobalUnlock() sets an error of ERROR_INVALID_PARAMETER.

 - CreateFile() with share options of 0 does not lock file.

 - lstrcmp()/lstrcmpi() do not use the collate table correctly.

 - FreeLibrary() in DLL_PROCESS_DETACH crashes system.

 - LockResource() does not return NULL if hResource is invalid.

 - sndPlaySound() may cause a crash or may work poorly.

 - GetVolumeInformation() fails for Universal Naming Convention (UNC)

   root path.

 - Stubbed API GetFileAttributesW() does not return -1 on error.

 - Code page CP_MACCP not supported.

 - Invalid LCIDs are not recognized.

 - CreateFile() fails to open an existing file in share mode.

 - CreateDirectory()/RemoveDirectory() handle errors differently on

   Windows NT and Win32s.

 - SetCurrentDirctory() returns different error codes than on Windows NT.

 - FindText() leaks memory.

 - FindText() may cause GP fault.

 - Not all 32-bit DLLs have correct version numbers.

 - WINMM16.DLL has no version information.

 - RegEnumValue() and other Registry functions return ERROR_SUCCESS even

   though they are not implemented. Win32s implements only the registry

   functions supported by Windows.

 - COMPOBJ.DLL calls FreeLibrary() on w32sys.dll, leaving the FP exception

   vector invalid. Causes crash, often out to MS-DOS. A binary patch for

   COMPBOJ.DLL is available in the Microsoft OLE 2.02 appnote WW1116.

 - CreatePolyPolygonRgn() is not closing the polygons.

 - SetDIBits() with DIB_PAL_INDICES is not supported (this behavior matches

   Windows 3.1, but not Windows NT).

 - Progman gets restored when debugger app exits.

 - Cannot do ReadProcessMemory (RPM) on memory that has a hardware break

   point set on it.

 - Pointer to common dialog structures (lParam) becomes invalid.

 - ResumeThread() while debugging writes to debuggee stack.

 - Fault in initialization if app has more than 128K bytes of local data.

   This is because the application stack is limited to 128K.

 - Using CVW debugger, exception will terminate the app being debugged.

 - RealizePalette() error on Windows NT is -1, but is not defined under

   Win32s.

 - Using StartDoc() does not produce document from printer.

 - Can't open file using full path with different drive in common dialog.

 - GetFileInformationByHandle() doesn't return correct file attribute.

 - GlobalReAlloc(x,y,GMEM_MOVEABLE) returns wrong handle type.

 - Thread Local Storage (TLS) data not initialized to zero in TlsAlloc().

 - spawnl() does not pass parameters to an MS-DOS application.

 - Incorrect context at EXIT_PROCESS_DEBUG_EVENT.

 - Win32s doesn't support language files other than default (l_intl.nls).

 - SetLocaleInfoW()/SetLocaleInfoA() not implemented.

 - GetScrollPos() fails if scroll pos is 0.

 - SetScrollPos() fails if last scroll pos is 0.

 - FreeLibrary() may crash when using universal thunks.

 - Win32s does not support forwarded exports.

 - GetCurrentDirectory() returns wrong directory after calling

   GetOpenFileName(). The workaround is to call SetCurrentDirectory(".")

   right after returning from the call to GetOpenFileName().

 - Changing system locale in Win32s will not have an effect until Win32s

   is loaded again, unlike on Windows NT.

 - Module management APIs missing ANSI to OEM translation.

 - LoadString() leaks memory if the string is a null string.

Additional reference words: 1.20

KBCategory: kbprg kbbuglist

KBSubcategory: W32s


BUG: Win32s 1.25a Bug List

PSS ID Number: Q130138

Authored 11-May-1995	Last modified 12-May-1995

The information in this article applies to:

 - Microsoft Win32s, version 1.25a

The following is a list of the known bugs in Win32s version 1.25 at the

time of its release.

 - Incorrect context at EXIT_PROCESS_DEBUG_EVENT.

 - Progman gets restored when debugger app exits.

 - Using StartDoc() does not produce document from printer.

 - EM_GETWORDBREAKPROC return code is incorrect.

 - Int 3 cannot be trapped via Structured Exception Handling (SEH) on

   Win32s.

 - Win32s does not open all files in RAW mode, as Windows NT does.

 - Cannot do ReadProcessMemory (RPM) on memory that has a hardware

   breakpoint set on it.

 - C run-time functions getdcwd()/getcwd() do not work.

 - GetFullPathName() returns the root directory for any drive that is not

   the current drive.

 - PlayMetaFileRecord()/EnumMetaFile() contains incorrect lpHTable.

 - Size of memory mapped files is rounded to a whole number of pages,

   meaning that the size is a multiple of 4096 bytes.

 - Functions chdrive() and SetCurrentDirectory() fail on PCNFS network

   drives.

 - GetExitCodeProcess() does not return exit codes for 16-bit Windows-based

   applications.

 - Memory passed to Netbios() must be allocated with GlobalAlloc().

 - biSizeImage field of BITMAPINFOHEADER is zero.

 - CreateFile() on certain invalid long filesnames closes Windows.

 - Only the first CBT hook gets messages.

 - Most registry functions return the Windows 3.1 return codes, not the

   Windows NT return codes.

 - GlobalReAlloc(x,y,GMEM_MOVEABLE) returns wrong handle type.

 - GetVolumeInformation() fails for Universal Naming Convention (UNC)

   root path.

 - ResumeThread while debugging writes to debuggee stack.

 - GetShortPathName() doesn't fail with a bad path, as it does on

   Windows NT.

 - CreateDirectory()/RemoveDirectory() handle errors differently than on

   Windows NT.

 - SetCurrentDirctory() returns different error codes than on Windows NT.

 - FindText() leaks memory.

 - Win32s doesn't support language files other than default (l_intl.nls).

 - spawnl does not pass parameters to an MS-DOS-based application.

 - Win32s does not support forwarded exports.

 - GetDlgItemInt() only translates numbers <= 32767 (a 16-bit integer).

 - Changing system locale in Win32s will not have an effect until Win32s

   is loaded again, unlike on Windows NT.

 - Module Management APIs missing ANSI to OEM translation.

 - When WS_TABSTOP is passed to CreateWindow(), this forces a

   WS_MAXIMIZEBOX.

 - Stubbed API FindFirstFileW() does not return -1 to indicate failure.

 - SearchPath() and OpenFile() don't work properly with OEM chars in the

   filename.

 - GetSystemInfo() doesn't set correct ProcessorType for the Pentium.

 - FormatMessage() doesn't set last error.

 - FormatMessage() fails with LANG_NEUTRAL | SUBLANG_DEFAULT, but works

   with LANG_ENGLISH | SUBLANG_ENGLISH_US.

 - After calling CreateFile() on a write-protected floppy GetLastError()

   returns 2, instead of 19, as it should.

 - VirtualProtect() with anything other than PAGE_NOACCESS, PAGE_READ, OR

   PAGE_READWRITE yields unpredictable page protections.

 - COMPAREITEMSTRUCT, DELETEITEMSTRUCT, DRAWITEMSTRUCT, AND

   MEASUREITEMSTRUCT incorrectly sign-extend fields.

 - GetWindowTextLength() & GetWindowText() incorrectly sign-extend the

   return value.

 - MoveFile() fails on Windows for Workgroups when the source is remote and

   the destination is local.

Additional reference words: 1.25 1.25a

KBCategory: kbprg kbbuglist

KBSubcategory: W32s


BUG: WNetGetUniversalName Fails Under Windows 95

PSS ID Number: Q131416

Authored 11-Jun-1995	Last modified 12-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) version 4.0

SYMPTOMS

The WNetGetUniversalName function takes a drive-based path for a network

resource and obtains a data structure that contains a more universal form

of the name. This function always fails with error 1200 when called from a

32-bit application running under Windows 95.

WORKAROUND

The functionality provided by WNetGetUniversalName can be implemented using

the Win32 network enumeration functions WNetOpenEnum and WNetEnumResource.

Here is an example of how to use these functions to implement similiar

functionality:

#include <windows.h>

#include <stdio.h>

// Function Name:  GetUniversalName

//

// Parameters:     szUniv  - contains the UNC equivalent of szDrive

//                           upon completion

//

//                 szDrive - contains a drive based path

//

// Return value:   TRUE if successful, otherwise FALSE

//

// Comments:       This function assumes that szDrive contains a

//                 valid drive based path.

//

//                 For simplicity, this code assumes szUniv points

//                 to a buffer large enough to accomodate the UNC

//                 equivalent of szDrive.

BOOL GetUniversalName( char szUniv[], char szDrive[] )

{

   // get the local drive letter

   char chLocal = toupper( szDrive[0] );

   // cursory validation

   if ( chLocal < 'A' || chLocal > 'Z' )

      return FALSE;

   if ( szDrive[1] != ':' || szDrive[2] != '\\' )

      return FALSE;

   HANDLE hEnum;

   DWORD dwResult = WNetOpenEnum( RESOURCE_CONNECTED, RESOURCETYPE_DISK,

                                  0, NULL, &hEnum );

   if ( dwResult != NO_ERROR )

      return FALSE;

   // request all available entries

   const int    c_cEntries   = 0xFFFFFFFF;

   // start with a reasonable buffer size

   DWORD        cbBuffer     = 50 * sizeof( NETRESOURCE );

   NETRESOURCE *pNetResource = (NETRESOURCE*) malloc( cbBuffer );

   BOOL fResult = FALSE;

   while ( TRUE )

   {

      DWORD dwSize   = cbBuffer,

            cEntries = c_cEntries;

      dwResult = WNetEnumResource( hEnum, &cEntries, pNetResource,

                                   &dwSize );

      if ( dwResult == ERROR_MORE_DATA )

      {

         // the buffer was too small, enlarge

         cbBuffer = dwSize;

         pNetResource = (NETRESOURCE*) realloc( pNetResource, cbBuffer );

         continue;

      }

      if ( dwResult != NO_ERROR )

         goto done;

      // search for the specified drive letter

      for ( int i = 0; i < (int) cEntries; i++ )

         if ( pNetResource[i].lpLocalName &&

              chLocal == toupper(pNetResource[i].lpLocalName[0]) )

         {

            // match

            fResult = TRUE;

            // build a UNC name

            strcpy( szUniv, pNetResource[i].lpRemoteName );

            strcat( szUniv, szDrive + 2 );

            _strupr( szUniv );

            goto done;

         }

   }

done:

   // cleanup

   WNetCloseEnum( hEnum );

   free( pNetResource );

   return fResult;

}

STATUS

Microsoft has confirmed this to be a bug in the Microsoft products listed

at the beginning of this article. We are researching this problem and will

post new information here in the Microsoft Knowledge Base as it becomes

available.

Additional reference words: 4.00 Win95

KBCategory: kbnetwork kbbuglist kbcode

KBSubcategory: NtwkWinnet


Button and Static Control Styles Are Not Inclusive

PSS ID Number: Q74297

Authored 15-Jul-1991	Last modified 16-May-1995

-

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK), versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

-

The class-specific window styles for button controls (BS_*) are mutually

exclusive, as are the class-specific window styles for static controls

(SS_*). In other words, they cannot be OR'd together as can most styles for

edit controls, list boxes, and combo boxes.

For example, the following style is invalid:

   BS_OWNERDRAW | BS_AUTORADIOBUTTON

A button control is either owner-draw or it is not. In the same

manner, the following style is also invalid:

   SS_LEFT | SS_GRAYFRAME

WINDOWS.H defines button and static styles sequentially (1, 2, 3...),

instead of as individual bits (1, 2, 4...) as other control's styles are

defined. If sequential styles are OR'd together, the resulting style may be

completely different from that intended.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: UsrCtl


Calculating String Length in Registry

PSS ID Number: Q94920

Authored 25-Jan-1993	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

When writing a string to the registry, you must specify the length of the

string, including the terminating null character (\0). A common error is to

use strlen() to determine the length of the string, but to forget that

strlen() returns only the number of characters in the string, not including

the null terminator.

Therefore, the length of the string should be calculated as:

   strlen( string ) + 1

Note that a REG_MULTI_SZ string, which contains multiple null-terminated

strings, ends with two (2) null characters, which must be factored into the

length of the string. For example, a REG_MULTI_SZ string might resemble the

following in memory:

   string1\0string2\0string3\0laststring\0\0

When calculating the length of a REG_MULTI_SZ string, add the length of

each of the component strings, as above, and add one for the final

terminating null.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: BseMisc


Calculating Text Extents of Bold and Italic Text

PSS ID Number: Q74298

Authored 15-Jul-1991	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

GetTextExtent() can be used to calculate the extent of a string. The value

returned may need to be adjusted, depending upon the style of the font.

When an italic or bold font is requested and none are available, the

graphics device interface (GDI) may simulate those styles using an existing

raster or vector font.

MORE INFORMATION

GDI-simulated bold and italic fonts both include overhangs. The

overhang is specified in a TEXTMETRIC structure obtained by calling

the GetTextMetrics function. The proper method for calculating the

extent of a line of italic or bold text is shown below:

   dwExtent = GetTextExtent(hDC, lpString, nCount);

   GetTextMetrics(hDC, &tm);

   xExtent = LOWORD(dwExtent) - tm.tmOverhang;

Listed below are examples of italic text alignment. If the next

character is not italic, the overhang should not be subtracted

from the extent returned from the GetTextExtent function. The

overhang needs to be subtracted only when the next character has the

same style.

                                        GetTextExtent yields

                                        this as the extent:

                                              ||

       /   /                                  \/

      /   /           /   / /   /         /   /|   |

     /---/           /   / /   /         /   / |   |

    /   /           /---/ /---/         /---/  |---|

   /   /           /   / /   /         /   /   |   |

       -----      /   / /   /         /   /    |   |

         ^            /\                      /\

      Overhang        ||                      ||

               Because the next        Start the nonitalic H

               character is italic,    here because it does not

               start the next          slant and would partially

               character within the    overwrite the previous

               overhang of the         italic character.

               current character

The overhang for bold characters synthesized by GDI is generally 1

because GDI synthesizes bold fonts by outputting the text twice,

offsetting the second output by one pixel, effectively increasing the

width of each character by one pixel. Calculating the extent of the

bold text is similar to the method for italic text. The

GetTextExtent function always returns the extent of the text plus 1

for bold text. Thus by subtracting the tmOverhang(1), the proper

extent is achieved.

        ||   ||

        ||   ||

        ||===||

        ||   ||

        ||   ||

              ---<= This line represents the "extra" overhang of 1.

                /\

                ||

             GetTextExtent yields

             this as the extent of the

             bold H.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: GdiFnt


Calculating The Logical Height and Point Size of a Font

PSS ID Number: Q74299

Authored 15-Jul-1991	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

To create a font in the Microsoft Windows graphical environment given only

the required point size, an application must calculate the logical height

of the font because the CreateFont() and CreateFontIndirect() functions use

logical units to specify height.

To describe a font to the user, an application can calculate a font's point

size, given its height. This article provides the formulas required to

perform these calculations for the MM_TEXT mapping mode. You will have to

derive a new equation to calculate the font size in another mapping mode.

MORE INFORMATION

To calculate the logical height, use the following formula:

                                Point Size * LOGPIXELSY

   height = Internal Leading + -------------------------

                                           72

LOGPIXELSY is the number of pixels contained in a logical inch on the

device. This value is obtained by calling the GetDeviceCaps() function with

the LOGPIXELSY index. The value 72 is significant because one inch contains

72 points.

The problem with this calculation is that there is no method to determine

the internal leading for the font because it has not yet been created. To

work around this difficulty, use the following variation of the formula:

            -(Point Size * LOGPIXELSY)

   height = --------------------------

                         72

This formula may also be written as follows:

   plf->lfHeight = -MulDiv (nPtSize, GetDeviceCaps (hdc, LOGPIXELSY), 72);

When an application calls the CreateFont() or CreateFontIndirect()

functions and specifies a negative value for the height parameter, the font

mapper provides the closest match for the character height rather than the

cell height. The difference between the cell height and the character

height is the internal leading, as demonstrated by the following diagram:

   ----------  <------------------------------

   |        |           |- Internal Leading  |

   | |   |  |  <---------                    |

   | |   |  |        |                       |- Cell Height

   | |---|  |        |- Character Height     |

   | |   |  |        |                       |

   | |   |  |        |                       |

   ----------  <------------------------------

The following formula computes the point size of a font:

                (Height - Internal Leading) * 72

   Point Size = --------------------------------

                           LOGPIXELSY

The Height and Internal Leading values are obtained from the

TEXTMETRIC data structure. The LOGPIXELSY value is obtained from the

GetDeviceCaps function as outlined above.

Round the calculated point size to the nearest integer. The Windows

MulDiv() function rounds its result and is an excellent choice to

perform the above calculation.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: GdiFnt


Calculating the Point Size of a Font

PSS ID Number: Q74300

Authored 15-Jul-1991	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

The generic formula listed below can be used to compute the point size of a

font in the MM_TEXT mapping mode. Any other mapping mode will require a

different equation, because the Height will be in a different unit.

MORE INFORMATION

                     (Height - Internal Leading) * 72

   Point Size  =    ---------------------------------

                               LOGPIXELSY

   Height - Cell height obtained from the TEXTMETRIC structure.

   Internal Leading - Internal leading obtained from TEXTMETRIC

                      structure.

   72 - One point is 1/72 of an inch.

   LOGPIXELSY - Number of pixels contained in a logical inch on the

                device. This value can be obtained by calling the

                GetDeviceCaps() function and specifying the LOGPIXELSY

                index.

The value returned from this calculation should be rounded to the nearest

integer. The Windows MulDiv() function rounds its result and is an

excellent choice for performing the above calculation.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: GdiFnt


Calculating the TrueType Checksum

PSS ID Number: Q102354

Authored 03-Aug-1993	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

To calculate a TrueType checksum:

1. Sum all the ULONGS in the .TTF file, except the checkSumAdjust

   field (which contains the calculated checksum). Note that TrueType

   files are big-endian, while Windows and Windows NT are little-endian,

   so the bytes must be swapped before they are summed.

2. Subtract the result from the magic number 0xb1b0afba.

MORE INFORMATION

Example

-------

1. Open the SYMBOL.TTF distributed with Windows NT. It is 64492 bytes

   long.

2. Step through the 16123 ULONGS, summing each one, except for the

   checkSumAdjust field for the file (which in this case is

   0xa7a81151).

3. Subtract the result from 0xb1b0afba. The result is 0xa7a81151.

The TrueType font file specification is available from several sources,

including the Microsoft Software Library (query on the word

TTSPEC1).

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: GdiFnt


Call the Windows Help Search Dialog Box from Application

PSS ID Number: Q86268

Authored 01-Jul-1992	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK), version 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

In the Microsoft Windows environment, an application can invoke the Search

dialog box of the Windows Help application independent of the main help

window. For example, many applications have an item like "Search for Help

on" in their Help menus.

An application can invoke the Search dialog box via the WinHelp

function by specifying HELP_PARTIALKEY as the value for the fuCommand

parameter and by specifying a pointer to an empty string for the

dwData parameter. The following code demonstrates how to call the

Windows Help Search dialog box from an application:

LPSTR lpszDummy,

      lpszHelpFile;

// Allocate memory for strings

lpszDummy = malloc(5);

lpszHelpFile = malloc(MAX_PATH);

// Initialize an empty string

lstrcpy(lpszDummy, "");

// Initialize the help filename

lstrcpy(lpszHelpFile, "c:\\windows\\myhelp.hlp");

// Call WinHelp function

WinHelp(hWnd, lpszHelpFile, HELP_PARTIALKEY, (DWORD)lpszDummy);

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: UsrDlgs


Calling 16-bit Code from Win32-based Apps in Windows 95

PSS ID Number: Q125715

Authored 02-Feb-1995	Last modified 01-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

SUMMARY

As a developer, you may need to access the functionality provided by a 16-

bit DLL from your Win32-based applications. This is true particularly when

you do not have the source code for the DLL so that you can port it to

Win32. This article discusses the mechanism by which Win32-based DLLs can

call Windows-based DLLs. The mechanism is called a thunk and the method

implemented under Windows 95 is called a flat thunk.

The three major steps in writing the thunk code are:

1. Creating the Thunk Script

2. Building the Win32-based DLL

3. Building the Windows-based DLL

MORE INFORMATION

The recommended way to design a thunk call is to isolate all thunk

specific code in DLLs (a 16-bit DLL and a 32-bit DLL, to provide both sides

of the thunk). That way, you can install certain DLLs on one platform and

replace them on another platform, for portability.

Designing a new flat thunk involves creating a thunk script (.THK file).

This script is compiled with the Thunk Compiler into an assembly file. This

file is assembled using two different flags: -DIS_32 and -DIS_16. This

allows you to create both the 16-bit and 32-bit object modules. These

object modules are linked in the Windows-based and Win32-based DLLs,

respectively. The following diagram summarizes the files involves in

building the DLLs.

                         +------------+

                         | 32to16.THK |

                         +------------+

                               |

                         +------------+

                         | 32to16.ASM |

                         +------------+

                            /       \

                  +-----------+ +-----------+

                  | 32THK.OBJ | | 16THK.OBJ |

                  +-----------+ +-----------+

                        /                 \

        +-------+    +-------+             +-------+

        | APP32 | -> | DLL32 | -- THUNK -- | DLL16 |

        +-------+    +-------+             +-------+

Creating the Thunk Script

-------------------------

You need to create a script that will be used by the thunk compiler to

create a thunk. A thunk script contains the function prototype and a

specification for the input and output values. You need to include the

following statement to create a 32-bit to 16-bit thunk call:

   enablemapdirect3216 = true

The following is an example of a simple thunk script for a function that

has no input and output:

   enablemapdirect3216 = true

   void MyThunk16()

   {

   }

The following is an example of script that takes two parameters and

returns a value. The second parameter is an output parameter and

contains a pointer that is passed back to the Win32-based DLL.

   enablemapdirect3216 = true

   typedef int   BOOL;

   typedef char *LPSTR;

   BOOL MyThunk32(LPSTR lpstrInput, LPSTR lpstrOutput)

   {

      lpstrOutput = output;

   }

The statement "lpstrOutput = output" tells the script compiler that the

16-bit code will return an address that needs to be converted from a

selector:offset pointer to a flat memory pointer.

The following thunk script uses more complex parameter types, such as

structures. This example also shows how to specify input and output

parameters.

   enablemapdirect3216 = true

   typedef int BOOL;

   typedef unsigned int UINT;

   typedef char *LPSTR;

   typedef struct tagPOINT {

      INT  x;

      INT  y;

   } POINT;

   typedef POINT *LPPOINT;

   typedef struct tagCIRCLE {

      POINT center;

      INT   radius;

   } CIRCLE;

   typedef CIRCLE *LPCIRCLE

   void MyThunk32( LPCIRCLE lpCircleInOut)

   {

      lpCircleInOut = InOut;

   }

The statement "lpCircleInOut = InOut" tells the script compiler that

this pointer is going to be used for input and output. This means that

conversion from a flat memory pointer to a 16-bit selector:offset and

vice-versa needs to be accomplished.

The thunk compiler usage is as follows:

   thunk.exe /options <inputfile> -o <outputfile>

The following command line shows how to create a 16-bit thunk code.

   thunk -t thk 32to16.thk -o 32to16.asm

The "-t thk" option tells the thunk compiler to prefix the thunk

functions in the assembly language file with "thk_." This will create an

assembly language file.

Building the Win32-based DLL (DLL32)

------------------------------------

1. In the DllEntryPoint function (DllMain if you're using the Microsoft

   C Run-time libraries) in your Win32-based DLL, you must make a call

   to the imported function thk_ThunkConnect32, as shown here:

      BOOL WINAPI DllMain(HINSTANCE hDLLInst,

                          DWORD  fdwReason,

                          LPVOID lpvReserved)

      {

         if (!thk_ThunkConnect32("DLL16.DLL",

                                 "DLL32.DLL",

                                 hDLLInst,

                                 fdwReason))

         {

            return FALSE;

         }

         switch (fdwReason)

         {

            case DLL_PROCESS_ATTACH:

               break;

            case DLL_PROCESS_DETACH:

               break;

            case DLL_THREAD_ATTACH:

               break;

            case DLL_THREAD_DETACH:

               break;

         }

         return TRUE;

      }

2. Include the following lines in the EXPORT section of the module

   definition (DEF) file for DLL32.

      thk_ThunkData32

3. Export the function that you are thunking to.

4. Assemble the assembly language file produced by the thunk compiler as a

   32-bit object module. The following line shows an example:

      ml /DIS_32 /c /W3 /nologo /coff /Fo thk32.obj 32to16.asm

5. Link this object module as part of the Win32-based DLL (DLL32).

Building the Windows-based DLL (DLL16)

--------------------------------------

1. The Windows-based DLL must export a function named "DllEntryPoint". This

   function must make a call to an imported function thk__ThunkConnect16.

      BOOL FAR PASCAL __export DllEntryPoint(DWORD dwReason,

                                             WORD  hInst,

                                             WORD  wDS,

                                             WORD  wHeapSize,

                                             DWORD dwReserved1,

                                             WORD  wReserved 2)

      {

         if (!thk_ThunkConnect16("DLL16.DLL",

                                 "DLL32.DLL",

                                 hInst,

                                 dwReason))

         {

            return FALSE;

         }

         return TRUE;

      }

2. Include the following lines in the IMPORTS section of the module

   definition (DEF) file for DLL16:

      C16ThkSL01      = KERNEL.631

      ThunkConnect16  = KERNEL.651

3. Include the following lines in the EXPORTS section of the module

   definition (DEF) file for DLL16. The THK_THUNKDATA16 is defined in the

   object file that is assembled from the output of the thunk compiler.

      THK_THUNKDATA16 @1  RESIDENTNAME

      DllEntryPoint   @2  RESIDENTNAME

4. Once you have done that you need to assemble the assembly language

   file produced by the thunk compiler as a 16-bit object module. The

   following line shows an example:

      ml /DIS_16 /c /W3 /nologo /Fo thk16.obj 16to32.asm

5. Link this object module as part of the 16-bit DLL (DLL16) object file.

6. Mark the Windows-based DLL as version 4.0. To do this you can use the

   resource compiler (RC.EXE). The following line shows the syntax:

      rc -40 <DLL file>

   This -40 option is available in the resource compiler that is provided

   with the Windows 95 SDK and later SDKs.

Additional reference words: 4.00 95 flat thunk win16

KBCategory: kbprg

KBSubcategory: SubSys BseMisc


Calling 32-bit Code from 16-bit Apps in Windows 95

PSS ID Number: Q125718

Authored 02-Feb-1995	Last modified 01-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

SUMMARY

It is often desirable to port 16-bit Windows-based applications to Win32 a

little at a time, rather than all at once. For example, you may want to

port Windows-based DLLs to Win32, but still be able to call them from 16-

bit code. This article discusses the mechanism by which Windows-based DLLs

can call Win32-based DLLs. The mechanism is called a thunk and the method

implemented under Windows 95 is called a flat thunk.

The three major steps in writing the thunk code are:

1. Creating the Thunk Script

2. Building the Windows-based DLL

3. Building the Win32-based DLL

MORE INFORMATION

The recommended way to design a thunk call is to isolate all thunk

specific code in DLLs (a 16-bit DLL and a 32-bit DLL, to provide both sides

of the thunk). That way, you can install certain DLLs on one platform and

replace them on another platform, for portability.

Designing a new flat thunk involves creating a thunk script (.THK file).

This script is compiled with the Thunk Compiler into an assembly file. This

file is assembled using two different flags: -DIS_32 and -DIS_16. This

allows you to create both the 16-bit and 32-bit object modules. These

object modules are linked in the Windows-based and Win32-based DLLs,

respectively. The following diagram summarizes the files involves in

building the DLLs.

                       +------------+

                       | 16to32.THK |

                       +------------+

                             |

                       +------------+

                       | 16to32.ASM |

                       +------------+

                        /          \

                +-----------+ +-----------+

                | 16THK.OBJ | | 32THK.OBJ |

                +-----------+ +-----------+

                       /                 \

      +-------+    +-------+             +-------+

      | APP16 | -> | DLL16 | -- THUNK -- | DLL32 |

      +-------+    +-------+             +-------+

Creating the Thunk Script

-------------------------

You need to create a script that will be used by the thunk compiler to

create a thunk. A thunk script contains the function prototype and a

specification for the input and output values. You need to include the

following statement to create a 16-bit to 32-bit thunk call:

   enablemapdirect1632 = true

By default, the Win32-based DLL is loaded only on the first encounter of a

16->32 thunk. Because late binding is used, 16-bit code must not depend on

any action taken by the initialization of the Win32-based DLL. Also a

loading failure of the Win32-based DLL will not be detected until the first

16->32 thunk has been called. To disable late binding of the Win32-based

DLL add the following line in your thunk script:

   preload32=true;

The following is an example of a simple thunk script for a function that

has no input and output:

   enablemapdirect1632 = true

   void MyThunk32()

   {

   }

The following is an example of script that takes two parameters and

returns a value. The second parameter is an output parameter and

contains a pointer that is passed back to the Windows-based DLL.

   enablemapdirect1632 = true

   typedef int   BOOL;

   typedef char *LPSTR;

   BOOL MyThunk32(LPSTR lpstrInput, LPSTR lpstrOutput)

   {

      lpstrOutput = output;

   }

The statement "lpstrOutput = output" tells the script compiler that

the 32-bit code will return an address that needs to be converted from

flat memory pointer to a selector:offset pointer.

The following thunk script uses more complex parameter types, such as

structures. This example also shows how to specify input and output

parameters.

   enablemapdirect1632 = true

   typedef int BOOL;

   typedef unsigned int UINT;

   typedef char *LPSTR;

   typedef struct tagPOINT {

      INT x;

      INT y;

   } POINT;

   typedef POINT *LPPOINT;

   typedef struct tagCIRCLE {

      POINT center;

      INT   radius;

   } CIRCLE;

   typedef CIRCLE *LPCIRCLE

   void MyThunk32( LPCIRCLE lpCircleInOut)

   {

      lpCircleInOut = InOut;

   }

The statement "lpCircleInOut = InOut" tells the script compiler that

this pointer is going to be used for input and output. This means that

conversion from a 16-bit selector:offset to a flat memory pointer and

vice-versa needs to be accomplished.

The thunk compiler usage is as follows:

   thunk.exe /options <inputfile> -o <outputfile>

The following line shows how to create a 16-bit thunk code.

   thunk -t thk 16to32.thk -o 16to32.asm

The "-t thk" option tells the thunk compiler to prefix the thunk

functions in the assembly language file with "thk_". This will create

an assembly language file.

Building the Windows-based DLL (DLL16)

--------------------------------------

1. The Windows-based DLL must export a function named "DllEntryPoint". This

   function must make a call to an imported function thk__ThunkConnect16.

      BOOL FAR PASCAL __export DllEntryPoint(DWORD dwReason,

                                             WORD  hInst,

                                             WORD  wDS,

                                             WORD  wHeapSize,

                                             DWORD dwReserved1,

                                             WORD  wReserved 2)

      {

         if (!thk_ThunkConnect16("DLL16.DLL",

                                 "DLL32.DLL",

                                 hInst,

                                 dwReason))

         {

            return FALSE;

         }

         return TRUE;

      }

2. Include the following lines in the IMPORTS section of the module

   definition (DEF) file for DLL16.

      C16ThkSL01      = KERNEL.631

      ThunkConnect16  = KERNEL.651

3. Include the following lines in the EXPORTS section of the module

   definition (DEF) file for DLL16. The THK_THUNKDATA16 is defined in the

   object file that is assembled from the output of the thunk compiler.

      THK_THUNKDATA16 @1  RESIDENTNAME

      DllEntryPoint   @2  RESIDENTNAME

4. Once you have done that you need to assemble the assembly language

   file produced by the thunk compiler as a 16-bit object module. The

   following line shows an example:

      ml /DIS_16 /c /W3 /nologo /Fo thk16.obj 16to32.asm

5. Link this object module as part of the 16-bit DLL (DLL16) object file.

6. Mark the Windows-based DLL as version 4.0. To do this you can use the

   resource compiler (RC.EXE). The following line shows the syntax:

      rc -40 <DLL file>

   This -40 option is available in the resource compiler that is provided

   with the Windows 95 SDK and later SDKs.

Building the Win32-based DLL (DLL32)

------------------------------------

1. In the DllEntryPoint function (DllMain if you're using the Microsoft

   C Run-time libraries) in your Win32-based DLL, you must make a call

   to the imported function thk_ThunkConnect32, as shown here:

      BOOL WINAPI DllMain(HINSTANCE hDLLInst,

                          DWORD fdwReason,

                          LPVOID lpvReserved)

      {

         if (!thk_ThunkConnect32("DLL16.DLL",

                                 "DLL32.DLL",

                                 hDLLInst,

                                 fdwReason))

         {

            return FALSE;

         }

         switch (fdwReason)

         {

            case DLL_PROCESS_ATTACH:

               break;

            case DLL_PROCESS_DETACH:

               break;

            case DLL_THREAD_ATTACH:

               break;

            case DLL_THREAD_DETACH:

               break;

         }

         return TRUE;

      }

2. Include the following lines into the EXPORT section of the module

   definition (DEF) file for DLL32:

      thk_ThunkData32

3. Export the function that you are thunking to.

4. Assemble the assembly language file produced by the thunk compiler as a

   32-bit object module. The following line shows an example:

      ml /DIS_32 /c /W3 /nologo /coff /Fo thk32.obj 16to32.asm

5. Link this object module as part of the Win32-based DLL (Win32).

Additional reference words: 4.00 95 flat thunk win16

KBCategory: kbprg

KBSubcategory: SubSys BseMisc


Calling a New 32-bit API from a 16-bit Application

PSS ID Number: Q125674

Authored 01-Feb-1995	Last modified 06-Apr-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

SUMMARY

Windows 95 supports a new set of APIs for 32-bit applications. These APIs

are exported by USER32, GDI32, KERNEL32, and so on. In Windows 95, some of

these new APIs are also exported by the 16-bit counterpart DLLs in the

system such as USER16, GDI16, and so on. But 16-bit applications running on

Windows 95 should not call these new APIs from the 16-bit system DLLs

because these calls are not unsupported and might be removed from the

16-bit system DLLs in the future.

MORE INFORMATION

APIs such as WindowFromDC(), SetWindowRgn(), SetForeGroundWindow(), and so

on for 16-bit USER window management and PolyBezier(), PolyBezierTo(), and

so on for 16-bit GDI graphics management are exported from the 16-bit

system DLLs.

Even though these APIs are intended for 32-bit applications, the 16-bit

system DLLs export some of them. 16-bit Windows 95 Applications should not

call them. They are not supported and the APIs will not work as intended.

If Windows 95 Applications need to use these APIs, port the 16-bit

application to 32-bit. This is the best solution and is the one that

Microsoft recommends. One addtional solution is to write a 32-bit DLL that

actually calls the 32-bit API; then the 16-bit application can thunk into

this 32-bit DLL. However, Microsoft strongly discourages developers from

having applications thunk into sytem DLLs (16- or 32-bit).

Additional reference words: 4.00

KBCategory: kbprg

KBSubcategory: UsrMisc


Calling a Win32 DLL from a Win16 App on Win32s

PSS ID Number: Q97785

Authored 21-Apr-1993	Last modified 22-Mar-1995

The information in this article applies to:

 - Microsoft Win32s versions 1.1 and 1.2

SUMMARY

A Windows version 3.1 application can call a Win32 dynamic-link library

(DLL) under Win32s using Universal Thunks.

The following are required components (in addition to the Windows 3.1

application and the Win32 DLL):

 - A 16-bit DLL that provides the same entry points as the Win32 DLL.

   This serves as the 16-bit end for the Universal Thunk. The

   programmer must also include code that will detect whether the

   32-bit side is loaded.

 - A Win32 DLL that sets up the Universal Thunk. This serves as the

   32-bit end of the Universal Thunk. This DLL is supported only under

   Win32s.

 - A Win32 EXE that loads the 32-bit DLL described above.

NOTE: Universal Thunks were designed to work with a Win32-based application

calling a 16-bit DLL. The method described here has limitations. Because

the application is 16-bit, no 32-bit context is created, so certain calls

will not work from the Win32 DLL. For example, the first time you call

malloc() or new() from a DLL entrypoint called by the 16-bit application,

the system will hang. This is because MSVCRT20.DLL is using TLS to store C

Run-time state information and there is no TLS set up.

MORE INFORMATION

The following diagram illustrates how the pieces fit together:

                      -----------     -----------     ---------

                     | Win32 EXE |-->| Win32 DLL |<->|  Win32  |

    32-bit           |   (stub)  |   |    (UT)   |   |   DLL   |

                      -----------     -----------     ---------

                              /|\      /|\

              -----------------|--------|-------------------------

                               |       \|/

                ---------     ------------

               | Win 3.1 |<->| 16-bit DLL |

    16-bit     |   app.  |   |   (UT)     |

                ---------     ------------

The load order is as follows: The Windows 3.1 application loads the 16-bit

DLL. The 16-bit DLL checks to see whether the 32-bit side has been

initialized. If it has not been initialized, then the DLL spawns the 32-bit

EXE (stub), which then loads the 32-bit DLL that sets up the Universal

Thunks with the 16-bit DLL. Once all of the components are loaded and

initialized, when the Windows 3.x application calls an entry point in the

16-bit DLL, the 16-bit DLL uses the 32-bit Universal Thunk callback to pass

the data over to the 32-bit side. Once the call has been received on the

32-bit side, the proper Win32 DLL entry point can be called.

Note that the components labeled Win32 DLL (UT) and Win32 DLL in the

diagram above can be contained in the same Win32 DLL. Remember that the

code in the Win32 DLL (UT) portion isn't supported under Windows NT, so

this code must be special-cased if the DLLs are combined.

For more information, please see the "Win32s Programmer's Reference."

For a sample program, see the following file on CompuServe, in the

MSWIN32 forum:

   LIB 14 !dir /des /long /lib:all rev*.*

   [76150,2543]    Lib:14

   REVUT./Bin      Bytes:   8848, Count:  205, 10-Jan-94   Last:29-Jul-94

      Title   : Revut

      Keywords: UT UNIVERSAL THUNK WIN32S 32-BIT DLL 16-BIT APP

      16-bit app calling a 32 bit dll under win32s (reverse UT)

Additional reference words: 1.10 1.20 reverse universal thunk

KBCategory: kbprg

KBSubcategory: W32s


Calling a Win32 DLL from a Win16 Application Under WOW

PSS ID Number: Q104009

Authored 02-Sep-1993	Last modified 20-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

SUMMARY

Under Windows NT, it is possible to call routines in a Win32 dynamic-link

library (DLL) from a 16-bit Windows application using an interface called

Windows on Win32 (WOW) Generic Thunking. This is not to be confused with

Win32s Universal Thunks, which provides this functionality under Windows

3.1.

NOTE: Windows 95 also supports Generic Thunks.

WOW presents a few new 16-bit application programming interfaces (APIs)

that allow you to load the Win32 DLL, get the address of the DLL routine,

call the routine (passing it up to thirty-two 32-bit arguments), convert

16:16 (WOW) addresses to 0:32 addresses (useful if you need to build up a

32-bit structure that contains pointers and pass a pointer to it), and free

the Win32 DLL.

The Generic Thunks specification is included on the Win32 SDK CD in

\DOC\SDK\MISC\GENTHUNK.TXT. However, the 3.1 version of this document does

not include correct information for all of the function prototypes. The 3.5

version of the document has been corrected and it includes information on

new APIs introduced in 3.5 for thunking.

The following prototypes should be used:

   DWORD FAR PASCAL LoadLibraryEx32W( LPCSTR, DWORD, DWORD );

   DWORD FAR PASCAL GetProcAddress32W( DWORD, LPCSTR );

   DWORD FAR PASCAL CallProc32W( DWORD, ..., LPVOID, DWORD, DWORD );

   DWORD FAR PASCAL GetVDMPointer32W( LPVOID, UINT );

   BOOL FAR PASCAL FreeLibrary32W( DWORD );

Note that although these functions are called in 16-bit code, they need to

be provided with 32-bit handles, and they return 32-bit handles.

In addition, be sure that your DLL routines are declared with the _stdcall

convention; otherwise, you will get an access violation.

CallProc32W() is a Pascal function which was designed to take a variable

number of arguments, a Proc address, a mask, and the number of parameters.

The mask is used to specific which arguments should be treated as being

passed by value and which parameters should be translated from 16:16

pointers to flat pointers. Note that the low-order bit of the mask

represents the last parameter, the next lowest bit represents the next to

the last parameter, and so forth.

NOTE: It is a good idea to test the Win32 DLL by calling it from a Win32-

based application before attemting to call it from a 16-bit Windows-based

application, because the debugging support is superior in the 32-bit

environment.

MORE INFORMATION

Sample

------

The following code fragments can be used as a basis for Generic Thunks.

Assume that the 16-bit Windows-based application is named app16, that the

Win32 DLL is named dll32, and that the following are declared:

   typedef void (FAR PASCAL *MYPROC)(LPSTR);

   DWORD ghLib;

   MYPROC hProc;

   char FAR *TestString = "Hello there";

The DLL routine is defined in dll32.c as follows:

   void WINAPI MyPrint( LPTSTR lpString, HANDLE hWnd )

   {

      ...

   }

Attempt to load the library in the app16 WinMain():

   if( NULL == (ghLib = LoadLibraryEx32W( "dll32.dll", NULL, 0 )) ) {

      MessageBox( NULL, "Cannot load DLL32", "App16", MB_OK );

      return 0;

   }

Attempt to get the address of MyPrint():

   if( NULL == (hProc = (MYPROC)GetProcAddress32W( ghLib, "MyPrint" ))) {

      MessageBox( hWnd, "Cannot call DLL function", "App16", MB_OK );

      ...

   }

Call MyPrint() and pass it TestString and hWnd as arguments:

   CallProc32W( (DWORD) TestString, (DWORD) hWnd|0xffff0000, hProc, 2, 2 );

The hWnd is OR'd with 0xffff0000, because this is the way to convert a 16-

bit window handle to a 32-bit window handle in Windows NT. If you wanted to

convert a 32-bit window handle to a 16-bit window handle, you would simply

truncate the upper word. Note that this only works for windows handles, not

for other types of handles. In Windows NT 3.5, you should use the following

functions exported by WOW32.DLL: WOWHandle32() and WOWHandle16(), rather

than relying on this relationship. These functions (and many others) are

discussed in \DOC\SDK\MISC\GENTHUNK.TXT.

A mask of 2 (0x10) is given because we want to pass TestString by reference

(WOW translates the pointer) and we want to pass the handle by value.

Free the library right before exiting WinMain():

   FreeLibrary32W( ghLib );

NOTE: When linking the Windows-based application, you need to put the

following statements in the .DEF file, indicating that the functions will

be imported from the WOW kernel:

   IMPORTS

      kernel.LoadLibraryEx32W

      kernel.FreeLibrary32W

      kernel.GetProcAddress32W

      kernel.GetVDMPointer32W

      kernel.CallProc32W

The complete sample is also available in the Microsoft Software Library.

Download GTHUNKS.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for GTHUNKS.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download GTHUNKS.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \softlib\mslfiles directory

      Get GTHUNKS.EXE

Faults

------

On MIPS systems, an alignment fault will occur when a Win32-based

application deferences a pointer to unaligned data that was passed by a 16-

bit Windows application. As a workaround, declare the parameter with the

UNALIGNED keyword. For example,

   void func( DWORD *var );

becomes

   void func( DWORD unaligned *var);

An application can use SetErrorMode() to specify SEM_NOALIGMENTFAULTEXCEPT

flag. If this is done, the system will automatically fix up alignment

faults and make them invisible to the application.

The default value of this error mode is OFF for MIPS, and ON for ALPHA. So

on MIPS platforms, an app MUST call SetErrorMode() and specify

SEM_NOALIGMENTFAULTEXCEPT if it wants the system to automatically fix

alignment faults. This call does not have to be made on ALPHA platforms.

This flag has no effect on x86 systems. Note that the fix above is

preferable.

Additional reference words: 3.10 3.50 4.00 softlib GTHUNKS.EXE

KBCategory: kbprg kbfile

KBSubcategory: SubSys


Calling a Win32 DLL from an OS/2 Application

PSS ID Number: Q119217

Authored 10-Aug-1994	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   version 3.5

SUMMARY

The OS/2 subsystem provides a general mechanism that allows 16-bit OS/2 and

PM applications to load and call a Win32 DLL. This feature is useful if you

would like to call one of the Win32 APIs without having to spawn a Win32

application to do so; it is also useful if you are porting your OS/2

application to Win32 in stages. A small set of APIs (described in the "MORE

INFORMATION" section, below) provides this functionality to your

application.

To take full advantage of this feature, write a small Win32 DLL to provide

the thunk. The OS/2 application calls the thunk DLL, which in turn calls

the real Win32 API, using the parameters that were passed from the OS/2

application. You could call the Win32 DLL directly, but the OS/2 subsystem

thunking mechanism has only one generic pointer parameter. Most Win32 APIs

require different numbers or types of parameters, so the thunking layer is

required to retrieve the parameters from the parameter pointer. The

parameter pointer typically points to a structure that contains the actual

parameters.

You will also need to modify your OS/2 application to call the thunking

APIs described below.

MORE INFORMATION

The following are the header file, descriptions, and import statements for

the 16-bit APIs that are used by the OS/2 application to load and call the

thunk DLL. The APIs are defined in the same manner as the OS/2 APIs.

Header File

-----------

   extern USHORT pascal far

   Dos32LoadModule(PSZ DllName, PULONG pDllHandle);

   extern USHORT pascal far

   Dos32GetProcAddr(ULONG Handle, PSZ pszProcName, PULONG pWin32Thunk);

   extern USHORT pascal far

   Dos32Dispatch(ULONG Win32Thunk, PVOID pArguments, PULONG pRetCode);

   extern USHORT pascal far

   Dos32FreeModule(ULONG DllHandle);

   extern USHORT pascal far

   FarPtr2FlatPtr(ULONG FarPtr, PULONG pFlarPtr);

   extern USHORT pascal far

   FlatPtr2FarPtr(ULONG FlatPtr, PULONG pFarPtr);

API Descriptions

----------------

   Dos32LoadModule

   ---------------

   USHORT pascal far Dos32LoadModule (

      PSZ    DLLName,

      PULONG pDllHandle );

   Purpose:

   Load the Win32 thunk DLL that will intermediate between the OS/2

   application and the Win32 APIs.

   Parameters:

   DLLName    - Name of the thunk DLL.

   pDllHandle - Receives the module handle of the DLL. Used as an

                argument to Dos32GetProcAddr.

   Return:

   If NO_ERROR is returned, the value pointed to by pDllHandle is used for

   other WIN32 thunk APIs as described below. It is invalid for usage with

   regular OS/2 APIs.

   If ERROR_MOD_NOT_FOUND is returned, the value pointed to by pDLLHandle

   is undefined.

   Dos32GetProcAddr

   ----------------

   USHORT pascal far Dos32GetProcAddr (

      ULONG  DllHandle,

      PSZ    pszProcName,

      PULONG pWin32Thunk );

   Purpose:

   Get a flat pointer to a routine in the Win32 thunk DLL previously opened

   by Dos32LoadModule.

   Parameters:

   DllHandle   - Handle obtained through Dos32LoadModule.

   pszProcName - Name of the API to be called.

   pWin32Thunk - Receives pointer to the thunk routine.

   Return:

   If NO_ERROR is returned, then pszProcName is exported by the thunk DLL.

   If ERROR_PROC_NOT_FOUND or ERROR_INVALID_HANDLE is returned, then the

   value pointed to by pWin32Thunk is undefined.

   Dos32Dispatch

   -------------

   USHORT pascal far Dos32Dispatch (

      ULONG  Win32Thunk,

      PVOID  pArguments,

      PULONG pRetCode );

   Purpose:

   Call the thunk routine through the pointer obtained through

   Dos32GetProcAddr.

   Parameters:

   Win32Thunk - Thunk routine obtained through Dos32GetProcAddr.

   pArguments - Argument for thunk routine.

   pRetCode   - Error code returned from the thunk routine.

   The structure pointed to by pArguments is application specific and

   the value is not modified to the OS/2 subsystem.

   On the Win32 side (in the thunk DLL), the thunk looks like:

      ULONG MyFunc (

         PVOID pFlatArg );

   The OS/2 subsystem does translate pArguments from a 16:16 pointer to

   a flat pointer (pFlatArg). To translate pointers inside the structure,

   use FarPtr2FlatPtr.

   Return:

   If NO_ERROR is returned, then pFlatArg is a valid pointer.

   Dos32FreeModule

   ---------------

   USHORT pascal far Dos32FreeModule (

      ULONG DllHandle );

   Purpose:

   Unload the Win32 thunk DLL that is intermediating between the OS/2

   application and the Win32 APIs.

   Parameter:

   DllHandle - Handle obtained through Dos32LoadModule.

   Return:

   If NO_ERROR is returned, then DllHandle corresponds to a Win32 DLL

   previously loaded by Dos32LoadModule. After the call, DllHandle is no

   longer valid. Otherwise, ERROR_INVALID_HANDLE is returned.

   FarPtr2FlatPtr

   --------------

   USHORT pascal far FarPtr2FlatPtr (

      ULONG  FarPtr,

      PULONG pFlatPtr );

   Purpose:

   Translates a segmented far pointer to a flat pointer.

   Parameters:

   FarPtr   - Segmented far pointer.

   pFlatPtr - Points to flat pointer.

   Return:

   If NO_ERROR is returned, FarPtr is a valid 16:16 pointer and pFlatPtr

   contains a valid flat pointer to be used by Win32 code. Otherwise,

   ERROR_INVALID_PARAMETER is returned and pFlatPtr is undefined.

   FlatPtr2FarPtr

   --------------

   USHORT pascal far FlatPtr2FarPtr (

      ULONG  FlatPtr,

      PULONG pFarPtr );

   Purpose:

   Translates a flat pointer to a segmented far pointer.

   Parameters:

   FlatPtr - Flat pointer.

   pFarPtr - Points to a segmented far pointer.

   Return:

   If NO_ERROR is returned, the flat pointer maps to a valid segmented

   pointer in the 16-bit application's context and pFarPtr contains a valid

   segmented pointer to be used by 16-bit OS/2 code. Otherwise,

   ERROR_INVALID_PARAMETER is returned and pFarPtr is undefined.

IMPORTS Section for the Module Definition File

----------------------------------------------

   IMPORTS

      DOSCALLS.DOS32LOADMODULE

      DOSCALLS.DOS32GETPROCADDR

      DOSCALLS.DOS32DISPATCH

      DOSCALLS.DOS32FREEMODULE

      DOSCALLS.FARPTR2FLATPTR

      DOSCALLS.FLATPTR2FARPTR

Additional reference words: 3.50 OS2

KBCategory: kbprg

KBSubcategory: SubSys


Calling CRT Output Routines from a GUI Application

PSS ID Number: Q105305

Authored 17-Oct-1993	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

To use C Run-time output routines, such as printf(), from a GUI

application, it is necessary to create a console. The Win32 application

programming interface (API) AllocConsole() creates the console. The CRT

routine setvbuf() removes buffering so that output is visible immediately.

This method works if the GUI application is run from the command line or

from File Manager. However, this method does not work if the application is

started from the Program Manager or via the "start" command. The following

code shows how to work around this problem:

   int hCrt;

   FILE *hf;

   AllocConsole();

   hCrt = _open_osfhandle(

             (long) GetStdHandle(STD_OUTPUT_HANDLE),

             _O_TEXT

          );

   hf = _fdopen( hCrt, "w" );

   *stdout = *hf;

   i = setvbuf( stdout, NULL, _IONBF, 0 );

This code opens up a new low-level CRT handle to the correct console output

handle, associates a new stream with that low-level handle, and replaces

stdout with that new stream. This process takes care of functions that use

stdout, such as printf(), puts(), and so forth. Use the same procedure for

stdin and stderr.

Note that this code does not correct problems with handles 0, 1, and 2. In

fact, due to other complications, it is not possible to correct this, and

therefore it is necessary to use stream I/O instead of low-level I/O.

MORE INFORMATION

When a GUI application is started with the "start" command, the three

standard OS handles STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, and

STD_ERROR_HANDLE are all "zeroed out" by the console initialization

routines. These three handles are replaced by valid values when the GUI

application calls AllocConsole(). Therefore, once this is done, calling

GetStdHandle() will always return valid handle values. The problem is that

the CRT has already completed initialization before your application gets a

chance to call AllocConsole(); the three low I/O handles 0, 1, and 2 have

already been set up to use the original zeroed out OS handles, so all CRT

I/O is sent to invalid OS handles and CRT output does not appear in the

console. Use the workaround described above to eliminate this problem.

In the case of starting the GUI application from the command line without

the "start" command, the standard OS handles are NOT correctly zeroed out,

but are incorrectly inherited from CMD.EXE. When the application's CRT

initializes, the three low I/O handles 0, 1, and 2 are initialized to use

the three handle numbers that the application inherits from CMD.EXE. When

the application calls AllocConsole(), the console initialization routines

attempt to replace what the console initialization believes to be invalid

standard OS handle values with valid handle values from the new console. By

coincidence, because the console initialization routines tend to give out

the same three values for the standard OS handles, the console

initilization will replace the standard OS handle values with the same

values that were there before--the ones inherited from CMD.EXE. Therefore,

CRT I/O works in this case.

It is important to realize that the ability to use CRT routines from a GUI

application run from the command line was not by design so this may not

work in future versions of Windows NT or Windows. In a future version, you

may need the workaround not just for applications started on the command

line with "start <application name>", but also for applications started on

the command line with "application name".

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: BseMisc


Calling DdePostAdvise() from XTYP_ADVREQ

PSS ID Number: Q102571

Authored 04-Aug-1993	Last modified 18-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

The documentation for DdePostAdvise() in the Windows 3.1 Software

Development Kit "Programmer's Reference, Volume 2: Functions" states

the following in the Comments section:

   If a server calls DdePostAdvise() with a topic/item/format name set

   that includes the set currently being handled in an XTYP_ADVREQ

   callback, a stack overflow may result.

MORE INFORMATION

This is merely a warning against calling DdePostAdvise() from within a

DDE callback function's XTYP_ADVREQ transaction, because it may result

in a stack overflow.

Like window procedures, DDE callbacks must be coded with care to avoid

infinite recursion (eventually resulting in a stack overflow). Because

DdePostAdvise() causes DDEML to send an XTYP_ADVREQ transaction to the

calling application's DDE callback function, calling DdePostAdvise()

on the same topic/item/format name set as the one currently being

handled results in an infinite loop.

An analogous piece of code that has become a classic problem in

Windows programming involves calling UpdateWindow() in a WM_PAINT

case:

   case WM_PAINT:

       InvalidateRect (hWnd, NULL, TRUE);

       UpdateWindow (hWnd);

Calling UpdateWindow() as in the code above causes a WM_PAINT message

to be sent to a window procedure, and thus results in the same type of

infinite recursion that occurs when calling DdePostAdvise() from an

XTYP_ADVREQ transaction.

An example of a situation that would lend itself to this scenario

would be one where data needs to be updated as a result of a previous

data change. There are two ways to work around the stack overflow

problem in this case:

 - Post a user-defined message and handle the data change

   asynchronously. For example,

      // in DdeCallback:

      case XTYP_ADVREQ:

                if ((!DdeCmpStringHandles (hsz1, ghszTopic)) &&

                    (!DdeCmpStringHandles (hsz2, ghszItem)) &&

                    (fmt == CF_SOMEFORMAT))

                  {

                        HDDEDATA  hData;

                        hData = DdeCreateDataHandle ();

                        PostMessage (hWnd, WM_DATACHANGED,hData,);

                        return (hData);

                  }

                  break;

       // in MainWndProc():

       case WM_DATACHANGED:

               DdePostAdvise (idInst, ghszTopic, ghszItem);

                 :

 - Return CBR_BLOCK from the XTYP_ADVREQ and let DDEML suspend further

   transactions on that conversation, while the server prepares data

   asynchronously.

More information on how returning CBR_BLOCK allows an application to

process data "asynchronously" may be derived from Section 5.8.6 of the

Windows 3.1 Software Development Kit (SDK) "Programmer's Reference,

Volume 1: Overview," or by querying on the following words in the

Microsoft Knowledge Base:

   DDEML and CBR_BLOCK

Additional reference words: 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrDde


Calling LoadLibrary() on a 16-bit DLL

PSS ID Number: Q123731

Authored 07-Dec-1994	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32s versions 1.15a and 1.2

SUMMARY

In Win32-based applications, LoadLibrary() returns an HINSTANCE and

GetLastError() is used to determine the error. If HINSTANCE is NULL, the

DLL was not successfully loaded. If the HINSTANCE is not null, the DLL was

loaded and the usage count was incremented; however, you may still see that

the last error was set if the DLL is a 16-bit DLL.

NOTE: At this point, the DLL is loaded and the usage count is incremented.

Call FreeLibrary() to unload the DLL.

MORE INFORMATION

In order to see all possible error returns, you'll need to call

SetLastError(0) before calling LoadLibrary(). If HINSTANCE is not NULL and

GetLastError() is ERROR_BAD_EXE_FORMAT, the DLL is a 16-bit DLL. You can

access the DLL resources and/or printer APIs from your Win32-based

application.

To call routines in the 16-bit DLL, you should load and call the DLL via

the Universal Thunk. This increments the usage count again. Later, you can

use FreeLibrary() to free the DLL from the 16-bit code, but this won't

unload the DLL from memory unless you already called FreeLibrary() from the

32-bit code. This is because the usage count is not zero. We recommend you

call FreeLibrary() from the 32-bit code after the DLL is loaded by the

16-bit code, so the DLL isn't unloaded and then reloaded.

REFERENCES

For more information on how to get resources from a 16-bit DLL, please see

the following article in the Microsoft Knowledge Base:

   ARTICLE-ID: Q105761

   TITLE     : Getting Resources from 16-bit DLLs Under Win32s

For more information on Universal Thunk, please see Chapter 4 of the Win32s

Programmer's Reference.

Additional reference words: 1.20

KBCategory: kbprg

KBSubcategory: W32s


Cancelling Overlapped I/O

PSS ID Number: Q90368

Authored 13-Oct-1992	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

There is no routine in the Win32 API to cancel an asynchronous request once

it has been issued. When a thread does an overlapped I/O (that is, a

write), the system starts up another thread to do the I/O and leaves your

thread free to do other work. Once it is started, there is no way to stop

it.

If it necessary to interrupt the I/O, you can either

 - Split the writes into batches and check for interruptions. For example,

   you could break a 20 megabyte (MB) write into 20, 1 MB writes.

   -or-

 - Create another thread yourself to handle the I/O. Terminating the thread

   will cancel the I/O. You should have a thread in the process explicitly

   close the handle to the device.

   -or-

 - Close the handle to the device with the pending I/O. The close has the

    net effect of cancelling the I/O.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: BseFileio


Cancelling WaitCommEvent() with SetCommMask()

PSS ID Number: Q105302

Authored 17-Oct-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

If a serial port is in nonoverlapped mode (without FILE_FLAG_OVERLAPPED)

and SetCommMask() is called, the call does not return until any pending

WaitCommEvent() calls return. This apparently contradicts the following

statement from the SetCommMask() Help

   If SetCommMask() is called for a communications resource while a wait

   is pending for that resource, WaitCommEvent() returns an error.

and the following statement from the WaitCommEvent() Help:

   If a process attempts to change the device handle's event mask by

   using the SetCommMask() function while a WaitCommEvent() operation

   is in progress, WaitCommEvent() returns immediately.

However, this is the expected behavior. If you open a serial port in the

nonoverlapped mode, then you can do only one thing at a time with the

serial port. SetCommMask() must block while the WaitCommEvent() call is

blocking.

If the serial port was opened with FILE_FLAG_OVERLAPPED, WaitCommEvent()

will return after SetCommEvent() has been called.

Additional reference words: 3.10 com1 com2

KBCategory: kbprg

KBSubcategory: BseCommapi


Cannot Load <exe> Because NTVDM Is Already Running

PSS ID Number: Q103863

Authored 01-Sep-1993	Last modified 23-Feb-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   versions 3.1 and 3.5

WinDbg can debug 16-bit Windows-based applications running on Windows NT,

under the Win16 VDM (virtual MS-DOS machine), NTVDM. By default, each

16-bit Windows-based application run as a thread in NTVDM. On Windows NT

3.5, each application can be run in a separate address space.

If NTVDM is running when the debugger tries to start the application, you

get the following error message:

   Cannot load <exe> because NTVDM is already running

Under Windows NT 3.5, to work around this problem, go to the WinDbg Options

menu, choose Debug, and check Separate WOW VDM, to allow the debuggee to be

run in a different address space.

Alternatively, you could terminate NTVDM. On Windows NT 3.1, your only

choice is to terminate NTVDM, because separate address spaces for 16-bit

Windows-based application are not supported.

To terminate NTVDM, run PView, select NTVDM, and choose "Kill Process."

Note that there may be two NTVDM processes. The one that you want to

terminate has one thread for each Windows-based application (plus a few

more).

The Windows NT WinLogon is set up to automatically start WoWExec, which

automatically starts the Win16 VDM. This behavior can be changed by

removing WoWExec from:

   HKEY_LOCAL_MACHINE\

             Software\

            Microsoft\

           Windows NT\

       CurrentVersion\

             Winlogon\

                Shell

Additional reference words: 3.10 3.50

KBCategory: kbtool

KBSubcategory: TlsWindbg


Captions for Dialog List Boxes

PSS ID Number: Q24646

Authored 16-Dec-1987	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.1, 3.5, 3.51, and 4.0

SUMMARY

To place text into the caption bar specified for a list box, use the

SetWindowText() function. First, use GetDlgItem() to get the handle of

the list box, then call SetWindowText() to set the list box caption.

MORE INFORMATION

The following code fragment illustrates the necessary steps. Note: The

list box includes the WS_CAPTION window style.

   ...

   BOOL FAR PASCAL TemplateDlg(hWndDlg, message, wParam, lParam)

   ...

       switch (message)

        {

       case WM_INITDIALOG:

           ...

           /* The following line sets the Listbox caption */

           SetWindowText( GetDlgItem(hWndDlg, IDDLISTBOX),

                          (LPSTR)"Caption");

           for (i = 0; i < CSTR; i++) {

               LoadString(hInstTemplate, IDSSTR1+i, (LPSTR)szWaters, 12);

               SendDlgItemMessage(hWndDlg, IDDLISTBOX, LB_ADDSTRING, 0,

                   (LONG)(LPSTR)szWaters);

               }

           SendDlgItemMessage(hWndDlg, IDDLISTBOX, LB_SETCURSEL, iSel, 0L);

           ...

           return TRUE;

       case WM_COMMAND:

   ...

Additional reference words: 3.00 3.10 3.50 4.00 95  listbox

KBCategory: kbprg

KBSubcategory: UsrCtl


Caret Position & Line Numbers in Multiline Edit Controls

PSS ID Number: Q68572

Authored 22-Jan-1991	Last modified 27-Jun-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.1 and 3.0

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

This article explains how to determine the position (row and column) of the

caret and the line number of the first visible line of text in a multiline

edit control.

MORE INFORMATION

Edit controls process several messages that return information relevant to

the position of the caret within the control. These messages help an

application determine the line number of the caret relative to the number

of lines of text in the control.

Once the line number is known, the application can compute the caret's

character position within that line and the line number of the first

visible line of text in the control.

An edit control must be subclassed in order to track the caret position

because the position changes with mouse clicks and keystrokes. The subclass

procedure must process the WM_KEYDOWN and WM_LBUTTONDOWN messages, and

compute the caret position upon receipt of each message.

The remainder of this article describes three procedures:

 - Finding the line number of the caret position

 - Finding the column number of the caret position

 - Finding the line number of the first visible line

Note that you may replace any mention of the SendMessage API in this

article with the SendDlgItemMessage function. Also note that the term

return value refers to the value returned by the SendMessage or the

SendDlgItemMessage function.

Finding the Line Number of the Caret Position

---------------------------------------------

Perform the following two steps:

1. Send the EM_GETSEL message to the edit control. The high-order word

   of the return value is the character position of the caret relative

   to the first character in the control.

2. Send the EM_LINEFROMCHAR message to the edit control and specify the

   value returned from step 1 as wParam. Add 1 to the return value to

   get the line number of the caret position because Windows numbers

   the lines starting at zero.

Finding the Column Number of the Caret Position

-----------------------------------------------

Perform the following three steps:

1. Send the EM_GETSEL message to the edit control. The high-order word

   of the return value is the character position of the caret relative

   to the first character in the control.

2. Send the EM_LINEINDEX message with wParam set to -1. The value

   returned is the count of characters that precede the first

   character in the line containing the caret.

3. Subtract the value returned in step 2 from the value in step 1 and

   add 1 because Windows numbers the columns starting at zero. This

   result is the column number of the caret position.

Finding the Line Number of the First Visible Line

-------------------------------------------------

Windows 3.1 and later define the EM_GETFIRSTVISIBLELINE message, which an

application can send to a single line or a multiline edit control. For

single line edit controls, this value returned for the message is the

offset of the first visible character. For multiline edit controls,

the value returned is the number of the first visible line.

Under Windows 95, it would be more efficient to use a combination of

GetCaretPos() and EM_CHARFROMPOS.

If an application must be compatible with Windows 3.0, it can perform

the following 10-step procedure:

1. Follow steps 1 and 2 of "Finding the Line Number of the Caret

   Position," presented above, and save the line number.

2. Call the GetCaretPos function to fill a POINT structure with the

   caret's coordinates relative to the client area of the edit

   control. (The client area is inside the border.)

3. Call the GetDC function using the handle to the edit control to

   retrieve a handle to a device context for the edit control. Store

   this handle in a variable named hDC.

4. Send the WM_GETFONT message to the edit control. The return value

   is a handle to the font used by the edit control. If the value

   returned is NULL, proceed to step 6 because the control is using

   the system default font.

5. Call the SelectObject function to select the font used by the edit

   control into hDC. Do not call the SelectObject function if

   WM_GETFONT returned NULL in step 4. Save the value returned by

   SelectObject in the hOldFont variable.

6. Call the GetTextMetrics function with hDC to fill a TEXTMETRIC

   data structure with information about the font used by the edit

   control (the font which is selected into hDC). The field of

   interest is tmHeight.

7. While the vertical coordinate of the caret is greater than the

   value of tmHeight, subtract tmHeight from the vertical coordinate

   and subtract 1 from the line number of the caret from step 1.

8. Repeat step 7 until the vertical coordinate of the caret is less

   than or equal to tmHeight.

9. Call SelectObject to select hOldFont back into hDC. Then call

   ReleaseDC to return the display context to the system.

10. The value remaining in the line number variable is the line number

   of the first visible line in the edit control.

Additional reference words: 3.00 3.10 3.50 4.00 95 caretpos

KBCategory: kbprg

KBSubcategory: UsrCrt


Case Sensitivity in Atoms

PSS ID Number: Q38901

Authored 07-Dec-1988	Last modified 12-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

If the same string is added to an atom table twice, but a different case is

used, the string is only stored once; only the first one is present.

The "Microsoft Windows 2.0 Software Development Kit Update" for versions

2.03 and 2.1 states that atoms are case insensitive.

This means that when the AddAtom() function is used, the case is ignored

when atoms are compared. Therefore, if AddAtom("DIR") is called, and then

AddAtom("dir"), the single atom "DIR" (with a reference count of 2) will

result. If AddAtom("dir") is called first, the single atom "dir" will

result.

Similarly, the other atom-handling functions are case insensitive. For

example, calling FindAtom("dIr") will find the atom "dir", "DIR", or "Dir",

and so on.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrDde


Cases Where "Normal" Window Position, Size Not Available

PSS ID Number: Q68583

Authored 22-Jan-1991	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.1 and 3.0

 - Microsoft Win32 SDK, versions 3.1, 3.5, 3.51, and 4.0

SUMMARY

In Windows version 3.0, the "normal" size and position of a window is

not available when that window is maximized (zoomed) or minimized

(represented as an icon). In Windows version 3.1, two new functions

named GeWindowPlacement and SetWindowPlacement have been added

which provide access to normal position information.

MORE INFORMATION

The remainder of this article provides two possible ways to work

around this limitation in Windows version 3.0:

1. If the normal size is needed only as the application is shut down,

   restore the window and retrieve its position before closing the

   application. The following call can be used to restore the window

   whose window handle is hWnd:

      SendMessage(hWnd, WM_SYSCOMMAND, SC_RESTORE, 0L);

   The GetWindowRect or GetClientRect functions can then be used

   to obtain the window's position.

2. If the normal size is needed at all times, keep track of the

   position every time the window receives a WM_MOVE message. If the

   IsIconic and IsZoomed functions both return FALSE, assume the

   window is normal and update the position values. Otherwise, do not

   change the saved position information.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrWndw


Centering a Dialog Box on the Screen

PSS ID Number: Q74798

Authored 30-Jul-1991	Last modified 23-Jun-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.1 and 3.0

 - Microsoft Win32 SDK, version 3.5 and 3.51

When an application developed for the Microsoft Windows graphical

environment displays a dialog box, centering the dialog box on the

screen is sometimes desirable. However, on systems with high-

resolution displays, the application displaying the dialog box may be

nowhere near the center of the screen. In these cases, it is

preferable to place the dialog near the application requesting input.

To center a dialog box on the screen before it is visible, add the

following lines to the processing of the WM_INITDIALOG message:

    {

    RECT rc;

    GetWindowRect(hDlg, &rc);

    SetWindowPos(hDlg, NULL,

       ((GetSystemMetrics(SM_CXSCREEN) - (rc.right - rc.left)) / 2),

       ((GetSystemMetrics(SM_CYSCREEN) - (rc.bottom - rc.top)) / 2),

       0, 0, SWP_NOSIZE | SWP_NOACTIVATE);

    }

This code centers the dialog horizontally and vertically.

Under Windows 95, you should use the new style DS_CENTER to get the same

effect.

Additional reference words: 3.00 3.10 3.50

KBCategory: kbprg

KBSubcategory: UsrDlgs


Chaining Parent PSP Environment Variables

PSS ID Number: Q96209

Authored 10-Mar-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

SUMMARY

Some MS-DOS-based applications change the environment variables of their

parent application by chaining through the program segment prefix (PSP).

With Windows NT, this functionality doesn't work if the parent is a

Win32-based application.

MORE INFORMATION

When an MS-DOS-based application is started from a single command shell

(SCS), the application inherits a new copy of the environment variables.

Any attempts by the MS-DOS-based application to modify its parent's

environment variables will not work. When the MS-DOS-based application

exits, the SCS will be "restored" to its original state. If another

MS-DOS-based application is started, the second application will receive

the same environment that the first MS-DOS-based application received.

If an MS-DOS-based application (B) is spawned by another MS-DOS-based

application (A), any modifications to application A's environment variables

will be reflected when application B exits.

For more information on how environment variables are set, please see the

following article(s) in the Microsoft Knowledge Base:

   ARTICLE-ID: Q96268

   TITLE     : How Environment Variables Are Set in Windows NT

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: BseMisc


Changes to the MSTest WFndWndC()

PSS ID Number: Q108227

Authored 07-Dec-1993	Last modified 06-Jun-1995

The information in this article applies to:

 - Microsoft Win32 SDK, versions 3.1 and 3.5

A change made to MS-TEST WFndWnd() and WFndWndC() may cause them not to

work as they did previously. Specifically, treatment of the first parameter

of WFndWnd() and WFndWndC() has changed.

Previously, "" and NULL resulted in the caption of the window being

ignored. Now, "" means the window must have an empty caption and NULL means

to ignore the caption altogether.

Additional reference words: 3.10 3.50

KBCategory: kbtool

KBSubcategory: TlsMisc


Changing a List Box from Single-Column to Multicolumn

PSS ID Number: Q68580

Authored 22-Jan-1991	Last modified 16-May-1995

-

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK), versions 3.0 and 3.1

 - Microsoft Win32, SDK versions 3.5, 3.51, and 4.0

-

SUMMARY

A list box cannot be changed from single column to multicolumn by

altering the list box's style bits "on the fly."

The effect of switching a single-column list box to multicolumn can be

achieved by creating one single column and one multicolumn list box.

Initially, hide the multicolumn list box. To switch the list boxes,

hide the single-column list box and show the multicolumn list box.

MORE INFORMATION

In general, programmatically changing the style bits of a window

usually leads to unstable results. The method of switching between two

windows (hiding one and showing the other) can safely switch window

styles.

Additional reference words: 3.00 3.10 3.50 4.00 95 listbox

KBCategory: kbprg

KBSubcategory: UsrCtl


Changing How Pop-Up Menus Respond to Mouse Actions

PSS ID Number: Q65256

Authored 28-Aug-1990	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.1 and 3.0

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

The TrackPopupMenu function allows an application to receive input

from a menu that is displayed anywhere within the application's client

area. This article demonstrates how to change the menu's default

behavior for mouse selections.

MORE INFORMATION

The default action for floating pop-up menus maintained with

TrackPopupMenu is as follows:

1. If the menu is displayed in response to a keystroke, the pop-up

   menu is visible until the user selects a menu item or presses ESC.

2. If the menu is displayed in response to a WM_*BUTTONUP message, it

   acts as if it were displayed in response to a keystroke.

NOTE: In the context of this article, the * in the WM_*BUTTONUP and

WM_*BUTTONDOWN messages can be L (left mouse button), M (middle mouse

button), or R (right mouse button).

An application can change the behavior of a floating pop-up menu

displayed in response to a WM_*BUTTONDOWN message to keep it visible

after the mouse button is released. However, when an application uses

the techniques described below, it changes the menu's user interface.

Specifically, to change menu selections with the mouse, the user must

first release the mouse button and then press it again. Dragging the

mouse between items with the button down, without releasing the button

at least once, will not change the selection.

To cause a floating pop-up menu to remain visible after it is

displayed in response to a WM_*BUTTONDOWN message, follow these four

steps:

1. In the application, allocate a 256 byte buffer to hold the key

   state.

2. Call the GetKeyboardState function with a far pointer to the buffer

   to retrieve the keyboard state.

3. Set the keyboard state for the VK_*BUTTON index in the keyboard

   state array to 0.

4. Call SetKeyboardState with a far pointer to the buffer to register

   the change with Windows.

The keyboard state array is 256 bytes. Each byte represents the state

of a particular virtual key. The value 0 indicates that the key is up,

and the value 1 indicates that the key is down. The array is indexed

by the VK_ values listed in Appendix A of the "Microsoft Windows

Software Development Kit Reference Volume 2" for version 3.0.

The code fragment below changes the state of the VK_LBUTTON to 0 (up)

during the processing of a WM_LBUTTONDOWN message. This causes

TrackPopupMenu to act as if the menu were displayed as the result of a

WM_LBUTTONUP message or of a keystroke. Therefore, the menu remains

visible even after the mouse button is released and the WM_LBUTTONUP

message is received. Items on this menu can be selected with the mouse

or the keyboard.

   switch (iMessage)

      {

   case WM_LBUTTONDOWN:

      static BYTE rgbKeyState[256];

      GetKeyboardState(rgbKeyState);

      rgbKeyState[VK_LBUTTON] = 0;      // 0==UP, 1==DOWN

      SetKeyboardState(rgbKeyState);

      // Create the pop-up menu and call TrackPopupMenu.

      break;

      }

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrMen


Changing Hypertext Jump Color in Windows Help

PSS ID Number: Q75111

Authored 12-Aug-1991	Last modified 24-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.1 and 3.0

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

The author of a file to be used with Windows Help can alter the

default color of hypertext jump strings. This specification overrides

both the default behavior of showing these strings as underlined green

text and any color preference listed in the WIN.INI file. This article

explains the steps required to make this type of modification.

MORE INFORMATION

This feature must be used with care. There are situations when the

user may require a jump color other than the default. The profile

strings in the WIN.INI file provide an opportunity to specify a color

value appropriate for the particular situation. For more information

on these settings, query on the following words:

   prod(winsdk) and jumpcolor

To specify the color of a context jump when the RTF Help text is

created using Microsoft Word for Windows, follow the six steps listed

below. This procedure is a modification of the steps listed on page

17-11 of the "Microsoft Windows Software Development Kit Tools"

manual.

1. Place the cursor at the point in the text where the jump term will

   be entered.

2. Choose Character from the Format menu and specify the double-

   underline attribute and the desired text color. Word for Windows

   provides 6 colors, along with auto, black, and white.

3. Type the jump word or words.

4. Choose Character from the Format menu. Turn off the double-

   underline attribute and choose the default text color and hidden

   text.

5. Type a percent sign (%), followed by the context string assigned to

   the topic. For example, JumpText%ContextString, where JumpText is

   given the desired color and %ContextString is hidden text.

6. Choose Character from the Format menu. Turn off hidden text.

After all topics have been created, save the file as RTF (rich text

format) and build the .HLP file. For more information on this process,

refer to Chapters 15 through 19 of the "Windows Software Development

Kit (SDK) Tools" manual.

It is also possible to modify the six color values that Word for

Windows provides as defaults. This can be done by modifying the color

table in the RTF header. To do this, load the RTF file into Word for

Windows, however, do not convert the file from RTF. For more

information on the RTF color table, refer to page 389 of the

"Microsoft Word for Windows Technical Reference" (Microsoft Press).

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbtool

KBSubcategory: TlsHlp


Changing Print Settings Mid-Job

PSS ID Number: Q85679

Authored 17-Jun-1992	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK), version 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

In Windows 3.1 and later, print settings can be changed on a page-by-page

basis through the ResetDC() API.

MORE INFORMATION

An application can pass a new DEVMODE structure (containing new print

settings) to ResetDC() between pages to change the print settings. For

example, this function makes it possible to change the paper bin or paper

orientation for each page in a print job. Note that ResetDC() cannot be

used to change the driver name, device name, or the output port.

Before calling ResetDC(), the application must ensure that all objects

(other than stock objects) that were previously selected into the

printer device context are selected out.

Additional reference words: 3.10 3.50 4.00 95  dmOrientation

dmDefaultSource

dmPaperSize hDC WM_DEVMODECHANGE ExtDeviceMode

KBCategory: kbprg

KBSubcategory: GdiPrn


Changing the Controls in a Common Dialog Box

PSS ID Number: Q82299

Authored 30-Mar-1992	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK, version 3.5

One reason to incorporate the common dialogs library routines into an

application is the ability to use the basic functionality of one or more of

the common dialogs and tailor it to the needs of a particular application.

All of the predefined controls must be present for the Common Dialogs

DLL (COMMDLG.DLL) to properly interact with a dialog box. Each predefined

control in the dialog box must retain its control ID value. For these

reasons, an application cannot delete unnecessary controls from a dialog

box.

To prevent the user from interacting with a given control, move the control

off screen by specifying very large coordinate values [for example, (4000,

4000)]. The application must also disable the control to prevent it from

receiving the focus when the user uses the TAB key to cycle through the

controls. Failing to disable the control can create "mystery" tab stops

where the input focus disappears.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: UsrCmnDlg


Changing the Font Used by Dialog Controls in Windows

PSS ID Number: Q74737

Authored 29-Jul-1991	Last modified 23-Jun-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.1, 3.5, 3.51, and 4.0

In Windows 3.x, there are two ways to specify the font used by dialog

controls:

1. The FONT statement can be used in the dialog template to specify

   the font used by ALL the controls in the dialog box.

   -or-

2. The WM_SETFONT message can be sent to one or more dialog controls

   during the processing of the WM_INITDIALOG message.

If a font is specified in the dialog template, the controls will use a

bold version of that font. The following code demonstrates how to

change the font used by dialog box controls to a nonbold font using

WM_SETFONT. The font should be deleted with DeleteObject() when the

dialog box is closed.

HWND hDlg;

HFONT hDlgFont;

LOGFONT lFont;

case WM_INITDIALOG:

    /* Get dialog font and create non-bold version */

    hDlgFont = NULL;

    if ((hDlgFont = (HFONT)SendMessage(hDlg, WM_GETFONT, 0, 0L))

             != NULL)

       {

       if (GetObject(hDlgFont, sizeof(LOGFONT), (LPSTR)&lFont)

                 != NULL)

          {

          lFont.lfWeight = FW_NORMAL;

          if ((hDlgFont = CreateFontIndirect(&lFont)) != NULL)

             {

             SendDlgItemMessage(hDlg, CTR1, WM_SETFONT, hDlgFont, 0L);

             // Send WM_SETFONT message to desired controls

             }

          }

       }

    else  // user did not specify a font in the dialog template

       {  // must simulate system font

       lFont.lfHeight = 13;

       lFont.lfWidth = 0;

       lFont.lfEscapement = 0;

       lFont.lfOrientation = 0;

       lFont.lfWeight = 200; // non-bold font weight

       lFont.lfItalic = 0;

       lFont.lfUnderline = 0;

       lFont.lfStrikeOut = 0;

       lFont.lfCharSet = ANSI_CHARSET;

       lFont.lfOutPrecision = OUT_DEFAULT_PRECIS;

       lFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;

       lFont.lfQuality = DEFAULT_QUALITY;

       lFont.lfPitchAndFamily = VARIABLE_PITCH | FF_SWISS;

       lFont.lfFaceName[0] = NULL;

       hDlgFont = CreateFontIndirect(&lFont);

       SendDlgItemMessage(hDlg, CTR1, WM_SETFONT, hDlgFont,

          (DWORD)TRUE);

       // Send WM_SETFONT message to desired controls

       }

   return TRUE;

   break;

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: UsrDlgs


Changing/Setting the Default Push Button in a Dialog Box

PSS ID Number: Q67655

Authored 08-Dec-1990	Last modified 18-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.1, 3.5, 3.51, and 4.0

SUMMARY

The default push button in a dialog box is defined to be the button that is

pressed when the user chooses the ENTER key, provided that the input focus

is not on another button in the dialog box. The default push button is

visually distinguished from other buttons by a thick dark border. This

article describes how to change the default push button.

MORE INFORMATION

To change the default push button, perform the following three steps:

1. Send the BM_SETSTYLE message to the current default push button to

   change its border to that of a regular push button.

2. Send a DM_SETDEFID message to the dialog box to change the ID of the

   default push button.

3. Send the BM_SETSTYLE message to the new default push button to

   change its border to that of a default push button.

The following is sample code that performs the three steps:

Sample Code

-----------

   // Reset the current default push button to a regular button.

   SendDlgItemMessage(hDlg, <ID of current default push button>,

         BM_SETSTYLE, BS_PUSHBUTTON, (LONG)TRUE);

   // Update the default push button's control ID.

   SendMessage(hDlg, DM_SETDEFID, <ID of new default push button>,

         0L);

   // Set the new style.

   SendDlgItemMessage(hDlg, <ID of new default push button>,

         BM_SETSTYLE, BS_DEFPUSHBUTTON, (LONG)TRUE);

NOTE: For Win32, the (LONG) casts should be changed to (LPARAM).

Note, however, that ANY push button that has the input focus will have a

dark border. A default push button will retain this dark border even when

the input focus is transferred to another control in the dialog box,

provided the new control is not another push button.

For example, if the input focus is on an edit control, check box, radio

button, or any control other than a push button, and the ENTER key is

pressed, Windows sends a WM_COMMAND message to the dialog box procedure

with the wParam set to the control ID of the default push button.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrCtl


Character Sets Supported by Hangeul (Korean) Windows Versions

PSS ID Number: Q130055

Authored 10-May-1995	Last modified 16-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 4.0

 - Microsoft Win32 Software Development Kit (SDK) version 3.5

 - Microsoft Win32s version 1.2

SUMMARY

Hangeul (Korean) Windows version 3.1 supports the Wansung code set only.

However Hangeul Windows 95 will support the XWansung code set.

MORE INFORMATION

Two different Hangeul character standards exist in Korea. One is Wansung,

and the other is Johap. The Korean government issued a Korean standard code

set (KSC5601-1987), which is Wansung code set. Hangeul Windows version 3.1

supports this character set only.

Later, the Korean government amended and added to the standard and issued a

new one (KSC5601-1992), which contains both Wansung and Johap code sets.

Hangeul Windows version 3.1 and Hangeul Windows 95 will not support the

KSC5601-1992 standard. Instead, Hangeul Windows 95 will support the

XWansung (Microsoft Extended Wansung) standard, which is an extended

version of the KSC5601-1987 standard.

The XWansung Code system contains some Johab characters (not all the Johap

codes). Johab characters were added into the vacant Range of old Wansung

Code of Hangeul Windows version 3.1. Here are the details on the XWansung

code set:

Number of characters:

     Exisitng Wansung    = 8,836

     Additional Assigned = 8,822 (Johab)

     Additional Reserved = 4,770

     ------------------------------

     Total characters    = 22,428

Leading byte range:    0x81-0xFE

Trailing byte range:   0x41-5A,0x61-0x7A,0x81-0xFE

Additional reference words: 1.20 3.10 4.00 3.50 Hangul Chohap kbinf

KBCategory: kbother

KBSubcategory: wintldev


Checking for Administrators Group

PSS ID Number: Q111542

Authored 14-Feb-1994	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

SUMMARY

It is often useful to know if the account under which your application is

running is a member of the "Administrators" group. The sample code below

demonstrates a method of making this determination:

Sample Code

-----------

BOOL IsAdmin(void)

{

   HANDLE hProcess, hAccessToken;

   UCHAR InfoBuffer[1024];

   PTOKEN_GROUPS ptgGroups = (PTOKEN_GROUPS)InfoBuffer;

   DWORD dwInfoBufferSize;

   SID_NAME_USE snuInfo;

   UCHAR szAccountName[256], szDomainName[256];

   DWORD dwAccountNameSize, dwDomainNameSize;

   UINT x;

   hProcess = GetCurrentProcess();

   if(!OpenProcessToken(hProcess,TOKEN_READ,&hAccessToken))

      return(FALSE);

   if(!GetTokenInformation(hAccessToken,TokenGroups,InfoBuffer,

     1024, &dwInfoBufferSize)) return(FALSE);

   for(x=0;x<ptgGroups->GroupCount;x++)

   {

      dwAccountNameSize = 256;

      dwDomainNameSize = 256;

      LookupAccountSid(NULL, ptgGroups->Groups[x].Sid,

      szAccountName, &dwAccountNameSize,

      szDomainName, &dwDomainNameSize, &snuInfo);

      if(!strcmp(szAccountName,"Administrators") &&

      !strcmp(szDomainName,"BUILTIN"))

      return(TRUE);

  }

  return(FALSE);

}

MORE INFORMATION

The sample code above begins by obtaining a handle to the access token via

the OpenProcessToken() API (application programming interface). The

GetTokenInformation() API is then called to obtain the TOKEN_GROUPS

structure for the access token. The sample then looks up the name of each

group via the LookupAccountSid() API and compares it to Administrators. If

a group with an account name Administrators and domain name "BUILTIN" is

found, then the sample returns TRUE indicating the user is a member of the

Administrators group.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseSecurity


Choosing the Debugger That the System Will Spawn

PSS ID Number: Q103861

Authored 01-Sep-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   versions 3.1 and 3.5

SUMMARY

With Windows NT version 3.1, it is possible to have the system spawn a

debugger whenever an application faults. The capability is controlled

by the following Registry key:

   HKEY_LOCAL_MACHINE\

             SOFTWARE\

            Microsoft\

           Windows NT\

       CurrentVersion\

              AeDebug

This key contains the following values:

   Auto

   Debugger

If the value of Auto is set to "0" (zero), then the system will

generate a pop-up window, and if the user chooses Cancel, spawn the

debugger that is specified in the Debugger value. If the value of Auto

is set to "1", then the system will automatically spawn the debugger

that is specified in the Debugger value.

After installing Windows NT 3.1, the Debugger value is set to DRWTSN32

-p %ld -e %ld -g and the Auto value is set to 1.

If the Win32 SDK is installed, then the Debugger value is changed to

<MSTOOLS>\BIN\WINDBG -p %ld -e %ld and the Auto value is set to 0.

MORE INFORMATION

The DRWTSN32 debugger is a post-mortem debugger similar in functionality to

the Windows 3.1 Dr. Watson program. DRWTSN32 generates a log file

containing fault information about the offending application. The following

data is generated in the DRWTSN32.LOG file:

 - Exception information (exception number and name)

 - System information (machine name, user name, OS version, and so forth

 - Task list

 - State dump for each thread (register dump, disassembly, stack walk,

   symbol table)

A record of each application error is recorded in the application event

log. The application error data for each crash is stored in a log file

named DRWTSN32.LOG, which by default is placed in your Windows directory.

Additional reference words: 3.10 3.50

KBCategory: kbtool

KBSubcategory: TlsMisc


Clarification of COMMPROP dwMax?xQueue Members

PSS ID Number: Q94950

Authored 26-Jan-1993	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

The entry for the COMMPROP structure in the Win32 Programmer's Reference

states that for the dwMaxTxQueue and dwMaxRxQueue members, "a value of 0

means that this field is not used".

MORE INFORMATION

This statement means that the provider does not restrict you to maximum Rx

and Tx queue values, and these members [returned by GetCommProperties()]

should not be used to determine the size of your transmit and receive

buffers when calling SetupComm().

Based on the memory present in the system, the Windows NT serial driver

determines a default Rx queue size (currently 128 bytes on low memory

systems and 4K on high memory systems). The current Rx and Tx queue sizes

are located in the dwCurrentTxQueue and dwCurrentRxQueue members.

SetupComm() allows you to change these default queue sizes. However, you

should not assume that the given serial driver will allocate any memory.

The queue size allocated is stored in the dwCurrentRxQueue member of the

COMMPROP structure. You may use this information to set the XonLim and

XoffLim members of the device control block (DCB) structure.

The Microsoft-supplied serial driver attempts to allocate at least the

amount requested for the RXQUEUE and, failing this, the request will also

fail. The driver never attempts to allocate memory for the TXQUEUE.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: BseCommapi


Clarification of SearchPath() Return Value

PSS ID Number: Q115826

Authored 05-Jun-1994	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   version 3.1

SUMMARY

The entry for "SearchPath()" in the "Win32 Programmer's Reference" says

that the return value will be one of the following:

 - The length (in characters) of the string copied to the buffer.

   -or-

 - 0 if the function fails [see "GetLastError()" in the "Win32 Programmer's

   Reference" for more information].

If the specified file is not found, then the return value is 0, but

the value retrieved by GetLastError() is not changed.

In order to distinguish the "file not found" condition from another

error (out of memory, invalid parameter, and so forth), call

SetLastError() with a value of NO_ERROR before calling SearchPath().

MORE INFORMATION

This behavior is by design. The recommended way to check the return

status for SearchPath() is:

   return value >  buffer length    buffer too small

   return value =  0                file not found or another error

   return value <= buffer length    file found

Handle the case where the return value is 0 as follows:

   TCHAR  szFilename[] = "MyFile.Txt";

   TCHAR  szPathname[MAX_PATH];

   LPTSTR lpszFilename;

   SetLastError( NO_ERROR );

   if( !SearchPath( NULL, szFilename, NULL, MAX_PATH, szPathname,

                    &lpszFilename ) )

   {

      if( GetLastError() == NO_ERROR )

         Display( "File not found." );

      else

         Display( "SearchPath failed!" );

   }

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: BseFileio


Clarification of the "Country" Setting

PSS ID Number: Q102765

Authored 10-Aug-1993	Last modified 05-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

Under Windows NT, the "Country" choice affects currency, date/time and

number format, and so forth. The "Language" choice affects sorting, names

of the days of the weeks and months, and so forth. These settings allow the

user to choose the appropriate language and country format. For example, if

you are British and living in the U.S., you can pick a locale of English

(British) at setup time, then use Control Panel later to change your

country to U.S. so that currency is in dollars instead of pounds.

In Windows 95, there is not both a Country and a Language choice. You are

asked for a single Regional Setting.

Additional reference words: 3.10 3.50 4.00

KBCategory: kbprg

KBSubcategory: UsrNls WintlDev


Clearing a Message Box

PSS ID Number: Q74444

Authored 18-Jul-1991	Last modified 18-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

During the processing of the MessageBox() function, Windows creates a

bitmap to save the part of the screen covered by the message box. Normally,

before the MessageBox() function returns, Windows repaints the portion of

the screen covered by the message box using the bitmap. In this scenario,

when the user clicks on a button to dismiss the message box, the message

box disappears immediately.

It is important to note that under low memory conditions, Windows will

discard the bitmap. If the bitmap is discarded and a significant amount of

processing takes place between the MessageBox() call and painting the

application's window, the vestigial image of the message box will remain on

the screen during the processing. If the user clicks on this image with the

mouse, the underlying window will receive the mouse messages. This can

cause unexpected (and possibly undesirable) effects.

To address this problem, call UpdateWindow() immediately after

MessageBox(). The parameter to UpdateWindow() should be the parent window

of the message box (or of the application's main window if the message box

has no parent). This will cause the application to paint the affected

window if the bitmap has been discarded. The message box will disappear

immediately under all circumstances.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrDlgs


Client Service For Novell Netware Doesn't Support Named Pipes

PSS ID Number: Q129317

Authored 24-Apr-1995	Last modified 04-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

The Windows NT Client Service for Novell NetWare does not support named

pipes. Consequently, 16-bit Novell NetWare client applications running on

Windows NT cannot connect to Novell NetWare named pipe server applications.

There are currently no plans to add named pipe support to the Windows NT

Client Service for Novell NetWare.

For more information on Novell NetWare named pipes, consult the following

Novell documentation:

 - NetWare Client for OS/2 User's Guide

 - NetWare Client for MS-DOS and Microsoft Windows User's Guide

Additional reference words: 3.10 3.50

KBCategory: kbnetwork

KBSubcategory: NtwkMisc


Clipboard Memory Sharing in Windows

PSS ID Number: Q11654

Authored 26-Oct-1987	Last modified 12-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

The following are questions and answers on the topic of Clipboard memory

sharing:

Q. Does the Clipboard UNLOCK before freeing the handle when I tell it to

   SetClipboardData()?

A. Yes, the Clipboard UNLOCKs before freeing the handle when you

   SetClipboardData().

Q. Does the Clipboard actually copy my global storage to another

   block, or does it just retain the value of my handle for

   referencing my block?

A. The Clipboard is sharable; it retains the value of the handle.

Q. Does GetClipboardData() remove the data from the Clipboard, or

   does it allow me to reference the data without removing it from

   the Clipboard?

A. The data handle returned by GetClipboardData() is controlled by

   the Clipboard, not by the application. The application should

   copy the data immediately, instead of relying on the data handle

   for long-term use. The application should not free the data

   handle or leave it locked. To remove data from the Clipboard,

   call SetClipboardData().

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrClp


ClipCursor() Requires WINSTA_WRITEATTRIBUTES

PSS ID Number: Q106384

Authored 07-Nov-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

SUMMARY

The documentation for ClipCursor() states that the calling process must

have WINSTA_WRITEATTRIBUTES access to the window station. However, this

permission does not have to be enabled programmatically because the system

always grants the Local Login SID (the interactive user)

WINSTA_WRITEATTRIBUTES access, regardless of the permission groups to which

the user belongs.

MORE INFORMATION

The following code shows how to confine the cursor to the application

window during WM_ACTIVATE processing. Note that the clip cursor region must

be restored to its previous state each time the application deactivates.

Sample Code

-----------

   static RECT rcOldClip;

    .

    .

    .

      case WM_ACTIVATE:{

         short fActive = LOWORD( wParam );

         if( fActive ){

            RECT rcNewClip;

            /* Record the area in which the cursor can move. */

            GetClipCursor( &rcOldClip );

            /* Get the dimensions of the application's client area. */

            GetClientRect( hWnd, &rcNewClip);

            /* Convert to screen coordinates. */

            MapWindowPoints( hWnd, NULL, (LPPOINT)&rcNewClip, 2 );

            /* Confine the cursor to the application's window. */

            ClipCursor( &rcNewClip );

        }

        else{

            /* Restore the cursor to its previous area. */

            ClipCursor( &rcOldClip );

        }

        break;

    }

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: GdiCurico


Combo Box w/Edit Control & Owner-Draw Style Incompatible

PSS ID Number: Q82078

Authored 25-Mar-1992	Last modified 16-May-1995

-

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK), versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

-

SUMMARY

The owner-draw combo box styles (CBS_OWNERDRAWFIXED and

CBS_OWNERDRAWVARIABLE) are incompatible with the combo box styles that

contain an edit control (combo box styles CBS_SIMPLE and

CBS_DROPDOWN). A combo box with either the CBS_SIMPLE or CBS_DROPDOWN

style displays the currently selected item in its associated edit

control. When an owner-draw style is specified for the combo box style

CBS_SIMPLE or CBS_DROPDOWN, the current selection may not be

displayed. Using the SetWindowText function to display the current

selection in response to a CBN_SELCHANGE message may not be effective.

MORE INFORMATION

An owner-draw combo box can contain bitmaps or other graphic elements

in its list box. Therefore, to correctly display the current

selection, it is necessary to display a bitmap or other graphic

element in the edit control. Because edit controls are not designed to

display graphics, there is no natural method to display the current

selection in an owner-draw combo box with an edit control.

The combo box style CBS_DROPDOWNLIST, which has a static text area

instead of an edit control, can display any item, including graphics.

Use this style combo box with the owner-draw styles.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: UsrCtl


COMCTL32 APIs Unsupported in the Win32 SDK

PSS ID Number: Q105300

Authored 17-Oct-1993	Last modified 05-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.1 and 3.5

 - Microsoft Win32s version 1.2

The library COMCTL32.LIB was included in the Win32 SDK because the PERFMON

sample makes use of it. The library is part of the Windows for Workgroups

(WFW) COMMCTRL.LIB. However, Microsoft does not officially support

COMCTL32.LIB or recommend the use of these application programming

interfaces (APIs), and therefore they have not been documented in the SDK.

Microsoft does not recommend using these APIs, because Microsoft is

providing the new controls in Windows 95, Windows NT 3.51, and Win32s 1.3.

If you must absolutely use COMCTL32 with earlier versions, the

documentation can be found in the WFW SDK. Be aware that these APIs are

unsupported, and code that you write will not work on Windows 95 and

Windows NT 3.51.

Additional reference words: 1.20 3.10 3.50

KBCategory: kbprg

KBSubcategory: UsrCtl W32s


Common Dialog Boxes and the WM_INITDIALOG Message

PSS ID Number: Q74610

Authored 24-Jul-1991	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK, version 3.5

SUMMARY

An application using the common dialog box library (COMMDLG.DLL) can

override any information initialized in the DLL by handling the

WM_INITDIALOG message in its dialog hook function. If the application is

using a private dialog template, it should also initialize all private

dialog items while handling this message.

After processing the WM_INITDIALOG message, the hook function should

return FALSE if it has set the focus to a dialog control, and return

TRUE if Windows should set the focus.

MORE INFORMATION

For example, consider an application that is using the Open File common

dialog box (via GetOpenFileName()) but does not want the Drives combo box

to appear in the dialog box. Since all dialog items in the standard dialog

template must be included in the application's private dialog template, the

application will need to include code to disable and hide the Drives combo

box and the corresponding "Drives:" static text control. This code would be

implemented in the WM_INITDIALOG case of the dialog hook function, as

follows:

   case WM_INITDIALOG:

      hWnd = GetDlgItem( hDlg, cmb2 );  // Get Drives combo box handle

      EnableWindow( hWnd, FALSE );      // No longer receives input,

                                        // no longer a tabstop

      SetWindowPos( hWnd, NULL, 0, 0, 0, 0, SWP_HIDEWINDOW );

      hWnd = GetDlgItem( hDlg, stc4 );  // Get "Drives:" static control

      EnableWindow( hWnd, FALSE );      // no longer an accelerator

      SetWindowPos( hWnd, NULL, 0, 0, 0, 0, SWP_HIDEWINDOW);

   // Initialize private dialog items here...

      return( TRUE );                   // Let Windows set the focus

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: UsrCmnDlg


Common File Mapping Problems and Platform Differences

PSS ID Number: Q125713

Authored 02-Feb-1995	Last modified 27-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.5, 3.51,

   and 4.0

 - Microsoft Win32s, version 1.3

SUMMARY

This article addresses some common problems encountered when using file

mapping. It also points out some platform differences in the file mapping

implementation.

This article does not describe the procedures for performing file mapping.

For information on using file mapping, please see the File Mapping

overview in the Microsoft Win32 Programmer's Reference. Also see the

descriptions for CreateFileMapping(), OpenFileMapping(), MapViewOfFile(),

MapViewOfFileEx(), UnmapViewOfFile(), and FlushViewOfFile().

MORE INFORMATION

Name Space Conflicts

--------------------

The names of event, semaphore, mutex, and file-mapping objects share

the same name space, so it is not possible to have two different object

types with the same name. It is an error to attempt to create or open an

object of one type using a name that is already being used by an object of

another type.

CreateFileMapping() and OpenFileMapping() will fail if they specify an

object name that is in use by an object of another type. In both cases,

GetLastError() will return ERROR_INVALID_HANDLE (6).

To avoid conflicts between object types, one solution is to include

the object type in the name. For example, use "EV_myapp_block_ready" for an

event object name and "FM_myapp_missile_data" for a file mapping object

name.

Necessity of Unmapping All Views of a Mapped File

-------------------------------------------------

Windows maintains an internal handle to a file mapping object for each

view of that object, whether created by MapViewOfFile() or

MapViewOfFileEx(). This internal handle is kept in addition to the handle

returned by CreateFileMapping(). The internal handle is not closed until

the view associated with the handle is unmapped by calling

UnmapViewOfFile(). To completely close a file mapping object requires that

all handles for the object, including internal handles, be closed. Thus, to

close a file mapping object, all views of that object must be unmapped, and

the handle returned by CreateFileMapping() must be closed.

Extant unmapped views of a file mapping object will NOT cause a

CloseHandle() on the object's handle to fail. In other words, when your

handle to the object is closed successfully, it is not necessarily true

that all views have been unmapped, so the file mapping object has not

necessarily been freed.

Failure to properly unmap all views of the object and to close the handle

to the object will cause leaks in the application's paged pool,

nonpaged pool, virtual bytes, and also in the system wide committed bytes.

Restrictions on the Size of File Mapping Objects

------------------------------------------------

The size of a file mapping object backed by the system paging file is

limited to available system virtual memory (meaning the amount of memory

that could be committed with a call to VirtualAlloc()).

On Windows NT, the size of a file mapping object backed by a named disk

file is limited by available disk space. The size of a mapped view of

an object is limited to the largest contiguous block of unreserved

virtual memory in the process performing the mapping (at most, 2GB minus

the virtual memory already reserved by the process).

On Win32s, the size of a file mapping object backed by a named disk

file is limited to available system virtual memory, due to the virtual

memory management implementation of Win32s. Win32s allocates regular

virtual memory for the memory mapped section even though it does not

need swap space, and the amount of VM set by Windows is too small to use

for mapping large files. As with Windows NT, available disk space will

also impose a limitation.

On Windows 95, the size of a file mapping object backed by a named disk

file is limited to available disk space. The size of a mapped view of

an object is limited to the largest contiguous block of unreserved

virtual memory in the shared virtual arena. This block will be at most

1GB, minus any memory in use by other components of Windows 95 which use

the shared virtual arena (such as 16-bit Windows-based applications). Each

mapped view will use memory from this arena, so this limit applies to the

total size of all non-overlapping mapped views for all applications running

on the system.

Mapped File May Not be Automatically Grown

------------------------------------------

If the size specified for a file mapping object backed by a named disk

file in a call to CreateFileMapping() is larger than the size of the

file used to back the mapping, the file will normally be grown to the

specified size by the CreateFileMapping() call.

On Windows NT only, if PAGE_WRITECOPY is specified for the fdwProtect

parameter, the file will not automatically be grown. This will cause

CreateFileMapping() to fail, and GetLastError() will return

ERROR_NOT_ENOUGH_MEMORY (8). To set the size of the file before calling

CreateFileMapping(), use SetFilePointer() and SetEndOfFile().

MapViewOfFileEx() and Valid Range of lpvBase

--------------------------------------------

On Windows NT, views of file mapping objects are mapped in the address

range of 0-2 GB. Passing an address outside of this range as the

lpvBase parameter to MapViewOfFileEx() will cause it to fail, and

GetLastError() will return ERROR_INVALID_PARAMETER (87).

On Windows 95, views of file mapping objects are mapped in the address

range of 2-3 GB (the shared virtual arena). Passing an address outside of

this range will cause MapViewOfFileEx() to fail, and GetLastError() will

return ERROR_INVALID_ADDRESS (487). Note that future updates to Windows 95

may change the mapping range to 0-2 GB, as on Windows NT.

MapViewOfFileEx() and Allocation Status of lpvBase

--------------------------------------------------

If an address is specified for the lpvBase parameter of MapViewOfFileEx(),

and there is not a block of unreserved virtual address space at that

address large enough to satisfy the number of bytes specified in the

cbMap parameter, then MapViewOfFileEx() will fail, and GetLastError() will

return ERROR_NOT_ENOUGH_MEMORY (8). This does not mean that the system is

low on memory or that the process cannot allocate more memory. It simply

means that the virtual address range requested has already been reserved

in that process.

Prior to calling MapViewOfFileEx(), VirtualQuery() can be used to determine

an appropriate range of unreserved virtual address space.

MapViewOfFileEx() and Granularity of lpvBase

--------------------------------------------

For the lpvBase parameter specified in a call to MapViewOfFileEx(), you

should use an integral multiple of the system's allocation granularity. On

Windows NT, not specifying such a value will cause MapViewOfFileEx() to

fail, and GetLastError() to return ERROR_MAPPED_ALIGNMENT (1132). On

Windows 95, the address is rounded down to the nearest integral multiple of

the system's allocation granularity.

To determine the system's allocation granularity, call GetSystemInfo().

Addresses of Mapped Views

-------------------------

When mapping a view of a file (or shared memory), it is possible to either

let the operating system determine the address of the view, or to specify

an address as the lpvBase parameter of the MapViewOfFileEx() function. If

the file mapping is going to be shared among multiple processes, then

the recommended method is to use MapViewOfFile() and let the operating

system select the mapping address for you. There are good reasons for doing

so:

 - On Windows NT, views are mapped independently into each process's

   address space. While it may be convenient to try to map the view at

   the same address in each process, the specified virtual address range

   may not be free in all of the processes involved. Therefore, the mapping

   could fail in one (or more) of the processes trying to share the

   file mapping.

 - On Windows 95, file mapping objects exist in the 2-3 GB address range

   (the shared virtual arena). Therefore, once the initial address for the

   view is determined, additional views of the mapping will be mapped to

   the same address in each process anyway, and there is no benefit in

   trying to force the initial mapping to a specific address. For the

   second and subsequent views of a mapping object, if the address

   specified for lpvBase does not match the actual address where Windows 95

   has mapped the view, then MapViewOfFileEx() fails, and GetLastError()

   returns ERROR_INVALID_ADDRESS (487). Additionally, when attempting to

   map the first view at a pre-determined address, that address may already

   be in use by other components of Windows 95 which use the shared virtual

   arena. Note that future updates to Windows 95 may change the mapping

   range to 0-2 GB, as on Windows NT.

If it is absolutely necessary to create the mappings at the same address

in multiple processes under Windows NT, here are two possible approaches:

1. Pick an appropriate address and manage the virtual address space so that

   this address is left available. This means basing your DLLs, allocating

   memory at specific locations, and using a tool such as Process Walker to

   observe the virtual address space pattern. As soon as possible in the

   execution of the application, either reserve the desired address space

   or perform the mapping. One good place to do this is in the

   PROCESS_ATTACH handling in a DLL, because it is called before the

   executable itself is started. NOTE: There is still no guarantee that

   some DLL will not have already loaded at the address in question. If not

   all involved processes can map at the predetermined address, they can

   either fail or try a new address.

   -or-

2. Have all processes involved negotiate an appropriate address. The

   processes can all use the VirtualQuery() function to scan their

   address spaces until a common address is found in each process

   that has a large enough unreserved block. This requires that all

   processes involved map the address at the same time. A process that

   starts after the address has been determined must map at that address,

   and fail if it cannot do so. Alternatively, the negotiation process

   could be repeated, with each process remapping at the new address. Then,

   all pointers into the mapping must be readjusted.

The second method is far more likely to succeed. It can also be combined

with the first to make it more likely that an appropriate address will be

found quickly.

When views are mapped to different addresses under Windows NT, the

difficulty that arises is storing pointers to the mapping within the

mapping itself. This is because a pointer in one process does not point

to the same location within the mapping in another process. To overcome

this problem, store offsets rather than pointers in the mapping, and

calculate actual addresses in each process by adding the base address of

the mapping to the offset. It is also possible to used based pointers and

thus perform the base + offset conversion implicitly. A short SDK sample

called BPOINTER demonstrates this technique.

Additional Platform Differences

-------------------------------

Additional limitations when performing file mapping under Windows 95:

1. The dwOffsetHigh parameters of MapViewOfFile() and MapViewOfFileEx() are

   not used, and should be zero. Windows 95 uses a 32-bit file system.

2. The dwMaximumSizeHigh parameter of CreateFileMapping() is not used,

   and should be zero. Again, this is due to the 32-bit file system.

3. The SEC_IMAGE and SEC_NOCACHE flags for the fdwProtect parameter of

   CreateFileMapping() are not supported.

4. If the FILE_MAP_COPY flag is used to map a view of a file mapping

   object, the object must have been created using PAGE_WRITECOPY

   protection. Additionally, the object must be backed by a named

   file rather than the system paging file (in other words, a valid file

   handle, not (HANDLE)0xFFFFFFFF, must be specified for the hFile

   parameter of CreateFileMapping()). Failure to do either of these

   causes MapViewOfFile() to fail, and GetLastError() to return

   ERROR_INVALID_PARAMETER (87).

5. If two or more processes map a PAGE_WRITECOPY view of the same file

   mapping object (by using a named object, for example), they are able

   to see changes made to the view by the other process(es). The actual

   disk file is not modified, however. Under Windows NT, if one process

   writes to the view, it receives its own copy of the modified pages and

   will not affect the pages in the other process(es) or the disk file.

Additional reference words: 1.30 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: BseMm


Complete Enumeration of System Fonts

PSS ID Number: Q99672

Authored 03-Jun-1993	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK), version 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

Complete enumeration of system fonts is a two-phase process.

Applications should first call EnumFontfamilies with NULL as the

family name to enumerate all the font face names in the system.

Applications should then take each face name and call EnumFontFamilies

again to obtain the style names (for TrueType fonts only) or the

supported point sizes (for raster fonts only). The style names are not

supported for the raster and vector fonts. Because TrueType and vector

fonts are continuously scalable, their point sizes are not enumerated.

MORE INFORMATION

The following steps detail the enumeration:

1. Call EnumFontFamilies with NULL as the family name (lpszFamily) to list

   one font from each available font family.

2. In the EnumFontFamProc callback function, look at the nFontType

   parameter.

3. If nFontType has the TRUETYPE_FONTTYPE flag set, then call

   EnumFontFamilies with the family name set to the font's type face

   name (lfFaceName of the ENUMLOGFONT structure). The callback

   function is called once for each style name. This enumeration is

   useful if the application is interested in finding a TrueType font

   with a specific style name (such as "Outline"). Because a TrueType

   font is continuously scalable, it is not necessary to enumerate a

   given font for point sizes. An application may use any desired

   point size. If the application is listing the enumerated TrueType

   fonts, it can simply choose some representative point sizes in a

   given range. The point sizes recommended by "The Windows Interface:

   An Application Design Guide" (page 159, Section 8.4.1.4) are 8, 9,

   10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28, 36, 48, and 72. All

   TrueType fonts are available on both displays and printers, so an

   application can be sure that the font appears the same on the

   display and the printer.

4. If nFontType has the RASTER_FONTTYPE flag set, then call

   EnumFontFamilies with the family name set to the font's type face

   name. The callback function is called once for each available point

   size. Raster fonts can be scaled only in multiples of the available

   point sizes. Because scaled raster fonts are usually not appealing

   to the user, applications may choose to limit themselves to the

   available sizes. Because Microsoft Windows version 3.1 does not

   define style names for raster fonts, there is no need to enumerate

   for style names.

   If the nFontType also has the DEVICE_FONTTYPE flag set, then the

   current font is a raster font available to the printer driver for

   use with the printer. The printer may have these fonts in hardware

   or be capable of downloading them when necessary. Applications that

   use such fonts should be aware that similar raster fonts may not be

   available on the display device. The converse is also true. If the

   DEVICE_FONTTYPE flag is not set, then applications should be aware

   that a similar font may not be available on the printer. Fonts

   generated by font packages such as Adobe Type Manager (ATM) are

   listed as device fonts.

5. If nFontType has neither the TRUETYPE_FONTTYPE nor the

   RASTER_FONTTYPE flags set, then the enumerated font is a vector

   font. Vector fonts are also continuously scalable so they do not

   have to be enumerated for point sizes. Because Windows 3.1 does not

   support style names for vector fonts, there is no need to enumerate

   them for style names. Vector fonts are generally used by devices

   such as plotters that cannot support raster fonts. These fonts

   generally have a poor appearance on raster devices, so many

   applications avoid them.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: GdiFnt


Computing the Size of a New ACL

PSS ID Number: Q102103

Authored 28-Jul-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

SUMMARY

When adding an access-allowed access control entry (ACE) to a discretionary

access control list (DACL), it is useful to know the exact size needed for

the new DACL. This is particularly useful when creating a new DACL and

copying over the existing ACEs. The below code computes the size needed for

a DACL if an access-allowed ACE is added:

   ACL_SIZE_INFORMATION AclInfo;

   GetAclInformation(pACL,&AclInfo,sizeof(ACL_SIZE_INFORMATION),

                     AclSizeInformation))

   dwNewACLSize = AclInfo.AclBytesInUse +

                  sizeof(ACCESS_ALLOWED_ACE) +

                  GetLengthSid(UserSID) - sizeof(DWORD);

MORE INFORMATION

The call to GetAclInformation() takes a pointer to an ACL. This point is

supplied by your program and should point to the DACL you want to add an

access-allowed ACE to. The GetAclInformation() call fills out a

ACL_SIZE_INFORMATION structure, which provides size information on the ACL.

The second statement computes what the new size of the ACL will be if an

access-allowed ACE is added. This is accomplished by adding the current

bytes being used to the size of an ACCESS_ALLOWED_ACE. We then add the size

of the security identifier (SID) (provided by your application) that is to

used in the AddAccessAllowedAce() API call. Subtracting out the size of a

DWORD is the final adjustment needed to obtain the exact size. This adjust

is to compensate for a place holder member in the ACCESS_ALLOWED_ACE

structure which is used in variable length ACEs.

When adding an ACE to an existing ACL, often there is not enough free space

in the ACL to accommodate the additional ACE. In this situation, it is

necessary to allocate a new ACL and copy over the existing ACEs and then

add the access-allowed ACE. The above code can be used to determine the

amount of memory to allocate for the new ACL.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseSecurity


Conditionally Activating a Button in Windows Help

PSS ID Number: Q76534

Authored 26-Sep-1991	Last modified 24-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

An application can add buttons to the Windows Help engine button

bar. There may be times when the button should be activated or

deactivated based on an external condition.

For example, if an application adds a tutorial button to the bar and

the user has not chosen to install the tutorial, the button should be

dimmed to indicate that the tutorial is not available.

MORE INFORMATION

The following code fragment demonstrates activating and deactivating

buttons using the macro facility:

char szMacro[255];

    .

    .

    .

/* Bring up the Help engine with the HLP file   */

/* This code fragment assumes that a button has */

/* been defined with an ID of TUTORIAL_BUTTON   */

WinHelp (hWnd, lpHelpFile, HELP_CONTENTS, 0L)

if (fTutorial)

/* If the tutorial is installed, the macro should enable the button */

    lstrcpy(szMacro,"EnableButton('TUTORIAL_BUTTON')");

else

/* If the tutorial is not installed, the macro should disable the

   button */

    lstrcpy(szMacro,"DisableButton('TUTORIAL_BUTTON')");

/* Run the appropriate macro */

WinHelp (hWnd, lpHelpFile, HELP_COMMAND, (LONG)szMacro);

Additional reference words: 3.10 3.50 4.00 95 grayed out disabled

unavailable

KBCategory: kbtool

KBSubcategory: TlsHlp


Considerations for CreateCursor() and CreateIcon()

PSS ID Number: Q73667

Authored 02-Jul-1991	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

An application can use the CreateCursor() and CreateIcon() APIs

to create icons and cursors on the fly. The application determines

the shape at run time.

When the shape of the icons and the cursors is known in advance, an

application should use LoadIcon() and LoadCursor().

An application that uses CreateIcon() must call DestroyIcon() to free the

memory used by the icon when it is no longer needed. An application that

uses CreateCursor() must call DestroyCursor() to release the memory used by

the cursor when it is no longer needed.

An application can call DestroyIcon() and DestroyCursor() only when the

icon or the cursor is not in use. For example, if the cursor created by

CreateCursor() has been specified in a SetCursor call, it must not be

destroyed until it has been released by another SetCursor() call.

An application can only use DestroyIcon() and DestroyCursor() to destroy

icons and cursors created by CreateIcon() and CreateCursor(). It should not

try to destroy icons and cursors loaded with LoadIcon() and LoadCursor().

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: GdiCurico


Consoles Do Not Support ANSI Escape Sequences

PSS ID Number: Q84240

Authored 05-May-1992	Last modified 18-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

Windows NT does not support ANSI escape sequences. There is some

functionality that this affects (for example, changing the color of the

prompt). This also affects a very limited number TTY-type programs that

rely on the console for escape support to be provided.

This feature is is under review and is being considered for future

releases.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseCon


Controlling the Caret Color

PSS ID Number: Q84054

Authored 29-Apr-1992	Last modified 12-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.1 and 3.0

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

When an application creates a custom caret using a bitmap, it is

possible to specify white or black for the caret color. In the case of

Windows running on a monochrome display, the application can cause the

caret to be the color of the display (white, green, amber, and so

forth, as appropriate). However, because the caret color is determined

by Windows at run time based on the hardware installed, the

application cannot guarantee what color will be used under all

circumstances. This article provides information about using color in

a custom caret.

MORE INFORMATION

To create a caret, first create a bitmap with the desired pattern. To

display the caret, Windows exclusive-ORs (XORs) and takes the opposite

of the result (the NOT of the result) of the bitmap with the

background of the client window. Therefore, to create a white caret,

create a bitmap that when XOR'd with the window background will have

an opposite value that will create a white color. It is when the caret

blinks that Windows uses the reverse of the bitmap XOR'd with the

background to draw the caret; this creates the white blink seen on the

screen.

The bitmap for the caret cannot use a color palette. Windows does not

use the color values from the palette in its calculations but the

indices into the palette. While it is possible to use palette indices

successfully, perfect symmetry of the colors in the palette is

required. This is unlikely. For each color in the palette, its exact

opposite color must be in the palette, in the exactly opposite index

position.

However, when the application creates bitmaps itself, it has complete

control over the bits. Therefore, the application can create the

perfect counterpart that corresponds to the window background color.

If the application uses this information to create the caret bitmap,

when Windows creates the caret, it can choose the closest color

available in the system palette.

Therefore, to create a white caret (or a black one, if the screen has

too many light elements), the task is straightforward. Windows always

reserves a few colors in the system palette and makes them available

to all applications. On a color display, these colors include black

and white. On a monochrome display, these colors are whatever the

monochrome color elements are.

Because black and white (or the monochrome screen colors) are always

available, the application simply creates a bitmap that, when XOR'd

with the screen background color, produces black or white.

The technique involves one main principle: background XOR background =

FALSE. Anything XOR'd with itself returns FALSE, which in bitmap terms

maps to the color black.

The process of creating a caret from the background color involves the

four steps discussed below:

1. Create a pattern brush the same as the window background

2. Select the pattern brush into a memory display context (DC)

3. Use the PATCOPY option of the PatBlt function to copy the brush

   pattern into the caret bitmap.

4. Specify the caret bitmap in a call to the CreateCaret function.

When this caret is XOR'd with the background, black will result. When

the caret blinks, and is therefore displayed, Windows computes the

opposite of the caret and XOR's this value into the background. This

yields NOT(background XOR background) = NOT(FALSE) = TRUE which

corresponds to WHITE.  The first background represents the caret

bitmap and the second is the current background color of the window.

Note that half the time the custom bitmap is displayed (when the caret

"blinks") the other half of the time the background is displayed,

(between "blinks").

If the background color is light gray or lighter [RGB values

(128, 128, 128) through (255, 255, 255)], then a black caret is

usually desired. The process of creating a black caret is just as

straightforward. Modify step 1 of the process given above to

substitute the inverse of the background for the background bitmap.

When the caret blinks, it will show black. The equation that

corresponds to this case is NOT(inverse of background XOR background)

= NOT(TRUE) = FALSE which corresponds to BLACK.

To change the caret color to something other than black or white

requires considerably more work, with much less reliable results

because the application must solve the following equation:

   NOT(caret XOR background) = desired_color on the

                               "blink" of the caret.

where the value for the caret color must be determined given the

desired color. A series of raster operations is required to solve this

type of equation. (For more information on raster operations, see

chapter 11 of the "Microsoft Windows [3.0] Software Development Kit

Reference, Volume 2" or pages 573-585 of the "Microsoft Windows [3.1]

Software Development Kit Programmer's Reference, Volume 3: Messages,

Structures, and Macros.")

Even after solving this equation, the color actually displayed is

controlled by Windows and the colors in the current system palette.

With colors other than black or white, an exact match for the desired

color may not be available. In that case, Windows will provide the

closest match possible. Because the palette is a dynamic entity and

can be modified at will, it is impossible to guarantee a particular

result color in all cases. The colors black and white should be safe

most of the time because it is quite unusual for an application to

modify the reserved system colors. Even when an application does

change the system palette, it most likely retains a true black and a

true white.

As long as a black and white remain in the palette (which is usually

the case), this algorithm will provide a white or black caret.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrCrt


Converting a Linear Address to a Flat Offset on Win32s

PSS ID Number: Q115080

Authored 18-May-1994	Last modified 05-Jan-1995

The information in this article applies to:

  - Microsoft Win32s, versions 1.1, 1.15, and 1.2

SUMMARY

Win32s flat code and data selectors are not zero-based. Linear addresses

retrieved through a VxD can be used in a Win32-based application running

under Win32s, after one small change is made.

In addition, there are two Universal Thunk APIs that are used to convert

segmented addresses to flat addresses and vice versa.

MORE INFORMATION

Linear Address to Flat Address

------------------------------

Win32s does not base linear addresses at 0, so that exceptions will be

generated when null pointers are dereferenced. Therefore, an access

violation occurs when:

1. a 16-bit DLL calls a VxD to retrieve a linear address (the VxD got

   the address by translating a physical address to a linear address)

   through DPMI function 0800h (map physical to linear).

2. the 16-bit DLL returns the address to a Win32-based application through

   the Universal Thunk.

3. the Win32-based application uses this linear address.

In order to convert a linear address (based at 0) to a flat offset, add

the base to the linear address. To do this, get the offset through

GetThreadSelectorEntry() with the DS or CS and then subtract that base from

the linear address that was returned by the VxD.

Segmented Address to Flat Address

---------------------------------

The following Win32s Universal Thunk APIs are used for address

translation:

 - UTSelectorOffsetToLinear (segmented address to flat address)

 - UTLinearToSelectorOffset (flat address to segmented address)

NOTE: In the nested function call

   UTLinearToSelectorOffset( UTSelectorOffsetToLinear( x ) );

where x is a segmented address, you may not necessarily get the original

value of x back. It is by design that the sel:off pair may be different.

If the memory was allocated by a 16-bit application, Win32s does not

have x in its LinearAddress->selector translation tables. Therefore,

when UTLinearToSelectorOffset() is called, new selectors are created.

Additional reference words: 1.10 1.20 gpf gp-fault

KBCategory: kbprg

KBSubcategory: W32s


Converting Colors Between RGB and HLS (HBS)

PSS ID Number: Q29240

Authored 26-Apr-1988	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

The code fragment below converts colors between RGB (Red, Green,

Blue) and HLS/HBS (Hue, Lightness, Saturation/Hue, Brightness,

Saturation).

MORE INFORMATION

/* Color Conversion Routines --

RGBtoHLS() takes a DWORD RGB value, translates it to HLS, and

stores the results in the global vars H, L, and S. HLStoRGB takes the

current values of H, L, and S and returns the equivalent value in an

RGB DWORD. The vars H, L, and S are only written to by:

   1. RGBtoHLS (initialization)

   2. The scroll bar handlers

A point of reference for the algorithms is Foley and Van Dam,

"Fundamentals of Interactive Computer Graphics," Pages 618-19. Their

algorithm is in floating point. CHART implements a less general

(hardwired ranges) integral algorithm.

There are potential round-off errors throughout this sample.

((0.5 + x)/y) without floating point is phrased ((x + (y/2))/y),

yielding a very small round-off error. This makes many of the

following divisions look strange.

*/

#define  HLSMAX   RANGE /* H,L, and S vary over 0-HLSMAX */

#define  RGBMAX   255   /* R,G, and B vary over 0-RGBMAX */

                        /* HLSMAX BEST IF DIVISIBLE BY 6 */

                        /* RGBMAX, HLSMAX must each fit in a byte. */

/* Hue is undefined if Saturation is 0 (grey-scale) */

/* This value determines where the Hue scrollbar is */

/* initially set for achromatic colors */

#define UNDEFINED (HLSMAX*2/3)

void  RGBtoHLS(lRGBColor)

DWORD lRGBColor;

{

   WORD R,G,B;          /* input RGB values */

   BYTE cMax,cMin;      /* max and min RGB values */

   WORD  Rdelta,Gdelta,Bdelta; /* intermediate value: % of spread from max

*/

   /* get R, G, and B out of DWORD */

   R = GetRValue(lRGBColor);

   G = GetGValue(lRGBColor);

   B = GetBValue(lRGBColor);

   /* calculate lightness */

   cMax = max( max(R,G), B);

   cMin = min( min(R,G), B);

   L = ( ((cMax+cMin)*HLSMAX) + RGBMAX )/(2*RGBMAX);

   if (cMax == cMin) {           /* r=g=b --> achromatic case */

      S = 0;                     /* saturation */

      H = UNDEFINED;             /* hue */

   }

   else {                        /* chromatic case */

      /* saturation */

      if (L <= (HLSMAX/2))

         S = ( ((cMax-cMin)*HLSMAX) + ((cMax+cMin)/2) ) / (cMax+cMin);

      else

         S = ( ((cMax-cMin)*HLSMAX) + ((2*RGBMAX-cMax-cMin)/2) )

            / (2*RGBMAX-cMax-cMin);

      /* hue */

      Rdelta = ( ((cMax-R)*(HLSMAX/6)) + ((cMax-cMin)/2) ) / (cMax-cMin);

      Gdelta = ( ((cMax-G)*(HLSMAX/6)) + ((cMax-cMin)/2) ) / (cMax-cMin);

      Bdelta = ( ((cMax-B)*(HLSMAX/6)) + ((cMax-cMin)/2) ) / (cMax-cMin);

      if (R == cMax)

         H = Bdelta - Gdelta;

      else if (G == cMax)

         H = (HLSMAX/3) + Rdelta - Bdelta;

      else /* B == cMax */

         H = ((2*HLSMAX)/3) + Gdelta - Rdelta;

      if (H < 0)

         H += HLSMAX;

      if (H > HLSMAX)

         H -= HLSMAX;

   }

}

/* utility routine for HLStoRGB */

WORD HueToRGB(n1,n2,hue)

WORD n1;

WORD n2;

WORD hue;

{

   /* range check: note values passed add/subtract thirds of range */

   if (hue < 0)

      hue += HLSMAX;

   if (hue > HLSMAX)

      hue -= HLSMAX;

   /* return r,g, or b value from this tridrant */

   if (hue < (HLSMAX/6))

      return ( n1 + (((n2-n1)*hue+(HLSMAX/12))/(HLSMAX/6)) );

   if (hue < (HLSMAX/2))

      return ( n2 );

   if (hue < ((HLSMAX*2)/3))

      return ( n1 + (((n2-n1)*(((HLSMAX*2)/3)-hue)+(HLSMAX/12))/(HLSMAX/6))

);

   else

      return ( n1 );

}

DWORD HLStoRGB(hue,lum,sat)

WORD hue;

WORD lum;

WORD sat;

{

   WORD R,G,B;                /* RGB component values */

   WORD  Magic1,Magic2;       /* calculated magic numbers (really!) */

   if (sat == 0) {            /* achromatic case */

      R=G=B=(lum*RGBMAX)/HLSMAX;

      if (hue != UNDEFINED) {

         /* ERROR */

      }

   }

   else  {                    /* chromatic case */

      /* set up magic numbers */

      if (lum <= (HLSMAX/2))

         Magic2 = (lum*(HLSMAX + sat) + (HLSMAX/2))/HLSMAX;

      else

         Magic2 = lum + sat - ((lum*sat) + (HLSMAX/2))/HLSMAX;

      Magic1 = 2*lum-Magic2;

      /* get RGB, change units from HLSMAX to RGBMAX */

      R = (HueToRGB(Magic1,Magic2,hue+(HLSMAX/3))*RGBMAX +

(HLSMAX/2))/HLSMAX;

      G = (HueToRGB(Magic1,Magic2,hue)*RGBMAX + (HLSMAX/2)) / HLSMAX;

      B = (HueToRGB(Magic1,Magic2,hue-(HLSMAX/3))*RGBMAX +

(HLSMAX/2))/HLSMAX;

   }

   return(RGB(R,G,B));

}

Additional reference words: 3.00 3.10 3.50 4.00 95  color RGB HLS HBS

KBCategory: kbprg

KBSubcategory: GdiPal


Copy on Write Page Protection for Windows NT

PSS ID Number: Q103858

Authored 01-Sep-1993	Last modified 18-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   versions 3.1, 3.5, and 3.51

SUMMARY

The Windows NT's Copy on Write page protection is a concept that allows

multiple applications to map their virtual address spaces to share the same

physical pages, until an application needs to modify the page and have its

own instance copy. This is part of a technique called Lazy Evaluation,

which allows the system to not waste time by committing resources, time, or

execution until/unless absolutely necessary. Copy on Write allows the

virtual memory manager to save memory and execution time.

MORE INFORMATION

Copy on Write works as follows: In generic terms, an application can load

something into its virtual memory (for example, a code section or DLL

code). Virtual memory is mapped to physical memory. Another process may

want to load the same thing into its virtual memory. As long as neither

process writes to this memory, they can map to, and share, the same

physical pages.

If either process needs to write to this memory, because the memory is

marked as Copy on Write, the physical page frame will be copied somewhere

else in physical memory. Fixups are made for the virtual memory mapping of

the writing process. Both applications now have their own instance of the

memory contents. In short, applications can share the same physical memory

with Copy on Write, until one of the applications has to modify the

contents. At that point, a new copy of the contents is made, and the

writing process has its own copy.

It should be emphasized that this is not to say that applications are

sharing memory in the sense that one application can write to it and

another can read what the first one wrote; as long as applications are only

going to read a piece of memory (for example, a code section), then the

physical pages supporting that memory for the applications can be shared.

Once the application needs to write to the memory (for example, in the form

of a fixup), then that application must have a new physical page so that

the modifications are not seen by other processes. The processes are no

longer sharing the same physical pages.

Applications

------------

When multiple instances of the same Windows-based application load, you may

notice that most, if not all, of their instance handles (hInstance) have

the same value. In fact, almost all of the windows on the desktop have this

value, which represents the base address where the application loaded in

virtual memory.

Each of the instances of the same application running has its own protected

virtual address space to run in. If each of these applications can load

into its default base address, each will map to, and be able to share, the

same physical pages in memory. Using Copy on Write, the system will allow

these applications to share the same physical pages until one of the

applications modifies a page. Then a copy is made in physical memory, and

that process's virtual memory is fixed up to use the new physical page. If

for some reason one of these instances cannot load in the desired base

address, it will get its own physical pages. See the section on DLLs below

for more explanation.

DLLs

----

Dynamic-link libraries (DLLs) are created with a default base address to

load at. Assuming that multiple applications call the DLL, they will all

try to load it within their own address space at that default virtual

address. If they are all successful, they can all map that virtual address

space to share the same physical pages.

However, if for some reason the DLL cannot be loaded within the process's

address space at the default address, it will load the DLL elsewhere. The

DLL must be copied into another physical address frame. The reason is that

fixups for jump instructions in a DLL are written as specific locations

within the DLL's pages. If the DLL can be loaded at the same base address

for each process, the second to the nth process does not have to write that

memory location for the jump. If a process cannot load the DLL at the

specified base address, the locations written in the DLL's jumps will be

different for this process. This forces the fixup to write a new location

into the jump, and the Copy on Write will automatically force a new

physical page.

Note that all references to data must be fixed up too. If this causes

virtual memory of the code section to be updated, then the process will

again go through the Copy on Write process. For example, if there are a

great many places in the code section that make reference into data in a

DLL, if the DLL cannot be loaded at its default location, the locations in

the code section data in the DLL are referenced will have to be modified.

If this is one of multiple instances of a process, these fixups must go

through the copy on write process, and the virtual memory pages of the

process's code section will not be able to map and share the same physical

pages as the other instances. If there are a lot of references to the data

in the DLL by the code section, this can essentially cause the entire code

section to be copied to new physical pages.

POSIX

-----

In POSIX, there is a fork() instruction that basically creates two copies

of the same program. It is an expensive process for the system to copy the

address space of one process into another. Instead, under Windows NT, the

system simply marks the parent's pages with Copy on Write. This way new

physical frames are copied only if and when they are needed (have been

modified). The system does not waste time or memory if all of the address

space doesn't need to be copied. (For more information, see "Inside Windows

NT" by Microsoft Press).

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseMm


Copying Compressed Files

PSS ID Number: Q130331

Authored 17-May-1995	Last modified 18-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.5 and 3.51

SUMMARY

It is not possible to copy NTFS compressed files without uncompressing

them. This functionality is not available in Windows NT versions 3.5 and

3.51; however, this feature may be included in a future version of Windows

NT.

Compressed files are expanded via memory-mapped files. This minimizes the

performance hit of expanding the file.

MORE INFORMATION

One of the new features found in Windows NT 3.51 is file compression.

Files or directories can be compressed or decompressed by calling

DeviceIoControl() with one of the following compression flags:

   FSCTL_SET_COMPRESSION : Sets the compression state of a file or

                           directory.

   FSCTL_GET_COMPRESSION : Obtains the compression state of a file

                           or directory.

Two additional FSCTL codes are documented in the Win32 SDK as "not

implemented in this release." They are FSCTL_READ_COMPRESSION and

FSCTL_WRITE_COMPRESSION. These additional FSCTL codes will be part of

the functionality that will allow you to read and write files on an

NTFS compressed drive without having to decompress them first. Again,

this functionality may be included in a future release of Windows NT.

Additional reference words: 3.50 NTFS File Compression

KBCategory: kbprg kbusage

KBSubcategory: BseFileIo


Correct Use of Try/Finally

PSS ID Number: Q83670

Authored 19-Apr-1992	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

Try/finally, used correctly, helps to provide a robust application.

However, if used incorrectly it can cause unnecessary overhead. any

flow of control out of the try body of try/finally is an abnormal

termination that can cause hundreds of instructions to be executed on

an x86 system, and thousands on a MIPS machine, even if control leaves

the try body via a control statement on the very last statement of the

try body. The language definition states that control must leave the

try body sequentially for normal termination to occur (that is,

execution falls through the bottom of the try body).

The following sample demonstrates an incorrect use of try/finally:

/* Incorrect use of try/finally */

VOID

function (

   DWORD ... P1,

      .

   DWORD ... Pn

   )

{

   try {

       if (...) {

           .

           .

           return;

       }

           .

           .

   } finally {

      .

      .

   }

   return;

}

The overhead can be avoided in the above example by moving the return

AFTER the end of the finally clause. The following provides more

detail on the correct use of try/finally.

MORE INFORMATION

Execution of a termination handler due to abnormal termination of a

try body is expensive. Abnormal termination occurs when control leaves

a try body in any way other than by falling through the bottom.

Intentionally branching out of a try body is still an abnormal

termination.

In the above example, abnormal termination of the try body occurs if

the return in the middle of the try body is executed. If the predicate

of the if is false, then extremely efficient execution of the finally

clause occurs because this is not abnormal termination and the finally

clause is called directly by inline code.

When abnormal termination occurs hundreds to thousands of instructions

are executed because an unwind must be executed, which must search

backward through frames to determine if any termination handlers

should be called. On an x86 system, this executes the C run-time

handler and examines the handler list. On a MIPS machine, this also

causes the function table to be searched and the prologue of each

intervening function to be executed backwards interpretively.

You should always avoid the execution of a termination handler as a

result of the abnormal termination of a try body by a return, or other

direct flow of control out of the try body. Abnormal termination

occurs whenever control leaves the try body other than by falling

through the bottom. This can occur because of a return, goto,

continue, or break. It can also occur because of an exception, which

presumably cannot be avoided.

In the above example, abnormal termination in the nonexception case

can be eliminated easily as follows:

/* Correct use of try/finally */

VOID

function (

   DWORD ... P1,

      .

      .

   DWORD ... Pn

   )

{

   try {

       if (...) {

           .

           .

       } else {

           .

           .

       }

   } finally {

      .

      .

   }

   return;

}

Now both clauses of the if fall through to the termination handler in

all but exceptional cases and execute the termination handler in the

most efficient way. This also has the same logical execution as the

previous sample.

In summary, the correct use of try/finally is a powerful method to

help you write robust applications. Care should be taken to ensure the

correct use of try/finally.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: BseExcept


CPU Quota Limits Not Enforced

PSS ID Number: Q100329

Authored 20-Jun-1993	Last modified 03-Mar-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   versions 3.1, 3.5, and 3.51

SUMMARY

On page 88 of "Inside Windows NT," Table 4-1 indicates that a process

object contains a quota limit for the maximum amount of processor time that

the process can use.

This limit is not enforced in Windows NT versions 3.1 or 3.5x.

MORE INFORMATION

The key to understanding Windows NT thread scheduling and resultant

application behavior is knowing the central algorithm used. This algorithm

is very simple, and is the same one a number of other operating systems

use. It is "run the highest priority thread ready." A list of ready

threads or processes exists; it is often called the "dispatch queue" or

"eligible queue." The queue entries are in order based on their individual

priority. A hardware-driven real-time clock or interval timer will

periodically interrupt, passing control to a device driver that calls the

process or thread scheduler. The thread scheduler will take the highest

priority entry from the queue and dispatch it to run.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseProcThrd


CreateFile() Using CONOUT$ or CONIN$

PSS ID Number: Q90088

Authored 08-Oct-1992	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

If you attempt to open a console input or output handle by calling the

CreateFile() function with the special CONIN$ or CONOUT$ filenames, this

call will return INVALID_HANDLE_VALUE if you do not use the proper sharing

attributes for the fdwShareMode parameter in your CreateFile() call. Be

sure to use FILE_SHARE_READ when opening "CONIN$" and FILE_SHARE_WRITE when

opening "CONOUT$".

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: BseFileio


CreateFileMapping() SEC_* Flags

PSS ID Number: Q108231

Authored 07-Dec-1993	Last modified 05-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

The definition of CreateFileMapping() is as follows:

   HANDLE CreateFileMapping(hFile, lpsa, fdwProtect, dwMaximumSizeHigh,

      dwMaximumSizeLow, lpszMapName)

   HANDLE hFile;

   LPSECURITY_ATTRIBUTES lpsa;

   DWORD fdwProtect;

   DWORD dwMaximumSizeHigh;

   DWORD dwMaximumSizeLow;

   LPCTSTR lpszMapName;

The following flags are four possible values for the parameter fdwProtect:

   SEC_COMMIT

      All pages of a section are to be set to the commit state.

   SEC_IMAGE

      The file specified for a section's file mapping is an executable

      image file.

   SEC_NOCACHE

      All pages of a section are to be set as noncacheable.

   SEC_RESERVE

      All pages of a section are to be set to the reserved state.

If none of these flags are specified, SEC_COMMIT is the default. This

behaves the same way as MEM_COMMIT in VirtualAlloc().

MORE INFORMATION

Windows NT

----------

The SEC_RESERVE flag is intended for file mappings that are backed by the

paging file, and therefore use SEC_RESERVE only when hFile is -1. The pages

are reserved just as they are when the MEM_RESERVE flag is used in

VirtualAlloc(). The pages can be committed by subsequently using the

VirtualAlloc() application programming interface (API), specifying

MEM_COMMIT. Once committed, these pages cannot be decommitted.

The SEC_NOCACHE flag is intended for architectures that require various

locking structures to be located in memory that is not ever fetched into

the CPU cache. On x86 and MIPS machines, use of this flag just slows down

the performance because the hardware keeps the cache coherent. Certain

device drivers may require noncached data so that programs can write

through to the physical memory. SEC_NOCACHE requires that either

SEC_RESERVE or SEC_COMMIT be used in addition to SEC_NOCACHE.

The SEC_IMAGE flag indicates that the file handle points to an executable

file, and it should be loaded as such. The mapping information and file

protection are taken from the image file, and therefore no other options

are allowed when SEC_IMAGE is used.

Windows 95

----------

Under Windows NT, the Win32 loader simply sits on top of the memory mapped

file subsystem, and so when the loader needs to load a PE executable, it

simply calls down into the existing memory mapped file code. Therefore, it

is extremely easy for to support SEC_IMAGE in CreateFileMapping() under

Windows NT.

In Windows 95, the loader is more complex and the memory mapped files are

simple and only support the bare minimum of functionality to make the

existing MapViewOfFile() work. Therefore, Windows 95 does not support

SEC_IMAGE. There is support for SEC_NOCACHE, SEC_RESERVE and SEC_COMMIT.

Additional reference words: 3.10 3.50 4.00

KBCategory: kbprg

KBSubcategory: BseMm


Creating a Font for Use with the Console

PSS ID Number: Q105299

Authored 17-Oct-1993	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.1 and 3.5

It is possible to use FontEdit to create a font that can be used by the

console. The following must be true:

 - The face name must be System, Terminal, or Courier

 - The font size must be different from any of the other console fonts

 - The font must be fixed pitch

 - The font must not be italic

In addition, in the U.S. market, the font should support codepage 437.

Install the font from the Control Panel. After rebooting, the font will be

available to the console.

An EnumFonts() call is made by the console during its initialization to

determine what fonts are available. The console saves a set of one-to-one

mappings between the font sizes listed and a set of LOGFONTs. The console

never has direct knowledge of what file is used.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: GdiFnt


Creating a Hidden MDI Child Window

PSS ID Number: Q70080

Authored 09-Mar-1991	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

Whenever Windows creates a new multiple-document interface (MDI) child

window in response to a WM_MDICREATE message, it makes that child window

visible.

The information below describes how to create a hidden MDI child window

without causing an unattractive "flash" on the screen as the window is

created visible and then hidden.

MORE INFORMATION

A code fragment such as the following can be used to create an

invisible MDI child:

MDICREATESTRUCT mcs;            // structure to pass with WM_MDICREATE

HWND            hWndMDIClient;  // the MDI client window

HWND            hwnd;           // temporary window handle

      ...

// assume that we have already filled out the MDICREATESTRUCT...

// turn off redrawing in the MDI client window

SendMessage(hwndMDIClient, WM_SETREDRAW, FALSE, 0L);

/*

 * Create the MDI child. It will be created visible, but will not

 * be seen because redrawing to the MDI client has been disabled

*/

hwnd = (WORD)SendMessage(hwndMDIClient,

                         WM_MDICREATE,

                         0,

                         (LONG)(LPMDICREATESTRUCT)&mcs);

// hide the child

ShowWindow(hwnd, SW_HIDE);

// turn redrawing in the MDI client back on,

// and force an immediate update

SendMessage(hwndMDIClient, WM_SETREDRAW, TRUE, 0L);

InvalidateRect( hwndMDIClient, NULL, TRUE );

UpdateWindow( hwndMDIClient );

      ...

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrMdi


Creating a List Box That Does Not Sort

PSS ID Number: Q68116

Authored 08-Jan-1991	Last modified 16-May-1995

-

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK), versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

-

A Windows list box with the LBS_STANDARD style will sort the list of items

into alphabetical order before displaying them in the control.

To create a list box that will not sort, you must remove the LBS_SORT bit

from the window style. The following style specification removes this bit:

   (LBS_STANDARD | LBS_HASSTRINGS) & ~LBS_SORT

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: UsrCtl


Creating a List Box with No Vertical Scroll Bar

PSS ID Number: Q68115

Authored 08-Jan-1991	Last modified 16-May-1995

--

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK), versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

--

A Windows list box with the LBS_STANDARD style will display a vertical

scroll bar if there are more items in the list than can be displayed in the

client area of the list box.

To create a list box that will not use a vertical scroll bar, you must

remove the WS_VSCROLL bit from the window style. The following style

specification removes this bit:

   (LBS_STANDARD | LBS_HASSTRINGS) & ~WS_VSCROLL

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: UsrCtl


Creating a List Box Without a Scroll Bar

PSS ID Number: Q11365

Authored 01-Dec-1987	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows versions

   3.1 and 3.0

 - Microsoft Win32 SDK, versions 3.1, 3.5, 3.51, and 4.0

When LBS_STANDARD is used as follows

   LBS_NOTIFY | LBS_SORT | WS_BORDER | LBS_STANDARD

the following results (as defined in WINDOWS.H):

   LBS_STANDARD = #00A00003;

                 /* LBS_NOTIFY | LBS_SORT | WS_VSCROLL | WS_BORDER */

To create a dialog box that contains a list box without the vertical scroll

bar, use NOT WS_VSCROLL as the style for creating a list box control

without a vertical scroll bar, as follows:

   (LBS_STANDARD & ~WS_VSCROLL)  // NOT WS_VSCROLL

Additional reference words: 3.00 3.10 3.50 4.00 95 listbox

KBCategory: kbprg

KBSubcategory: UsrCtl


Creating a Logical Font with a Nonzero lfOrientation

PSS ID Number: Q104010

Authored 02-Sep-1993	Last modified 24-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   and 3.51

SUMMARY

To create a font that writes in a direction other than left to right, an

application should specify a nonzero lfEscapement in the LOGFONT structure

that is passed to CreateFontIndirect(). This method works under Windows NT

regardless of the graphics mode of the device context.

To create a font where the characters themselves are rotated, the

application should specify a nonzero lfOrientation in the LOGFONT structure

that is passed to CreateFontIndirect(). However, this setting is ignored in

Windows NT unless the graphics mode is set to GM_ADVANCED.

Therefore, to successfully create a logical font with a nonzero

lfOrientation, use

   SetGraphicsMode( hDC, GM_ADVANCED )

to set the graphics mode of the device context to GM_ADVANCED.

MORE INFORMATION

The TTFONTS sample program is a good way to quickly and easily see the

effects of the lfEscapement and lfOrientation fields. However, TTFONTS does

not set the graphics mode of its test window HDC to GM_ADVANCED. As a

result, the lfOrientation field apparently is ignored. It is easy to modify

the DISPLAY.C module of TTFONTS in order to set the graphics mode of the

window HDC to GM_ADVANCED.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: GdiFnt


Creating a Multiple Line Message Box

PSS ID Number: Q67210

Authored 27-Nov-1990	Last modified 18-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

Message boxes are used to provide information to the user of an

application. Error messages and warnings are also provided through message

boxes. This article provides details on using message boxes in

applications.

MORE INFORMATION

Message boxes are modal windows. When an application displays an

application modal message box, which is the default message box type, the

user cannot interact with any part of that application until the message

box has been dismissed. However, the user may use the mouse or keyboard to

activate another application and interact with it while the message box is

displayed. Certain critical errors that may affect all of Windows are

displayed in system modal message boxes. Windows will not perform any

operations until the error condition is acknowledged and the system modal

message box is dismissed.

There are times where it is necessary to display a long message in a

message box. Windows does this when you start an MS-DOS-based application

that uses graphics from inside an MS-DOS window. To break a message into

many lines, insert a newline character into the message text. Here is a

sample MessageBox() call:

   MessageBox(hWnd, "This is line 1.\nThis is line 2.", "App",

       MB_OK | MB_ICONQUESTION);

If the text of a message is too long for a single line, Windows will

break the text into multiple lines.

System modal message boxes treat the newline character as any other. A

newline character is displayed as a black block in the text. Because system

modal message boxes are designed to work at all times, even under extremely

low memory conditions, it does not provide the ability to display more than

one line of text.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrDlgs


Creating a Nonblinking Caret

PSS ID Number: Q74607

Authored 24-Jul-1991	Last modified 12-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK)versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

The Microsoft Windows graphical environment is designed to provide a

blinking caret. However, using a timer and the SetCaretBlinkTime()

function, an application can "trick" the caret into not blinking.

MORE INFORMATION

Although Windows is designed to blink the caret at a specified interval, a

timer function and SetCaretBlinkTime() can be used to prevent Windows from

turning the caret off by following these three steps:

1. Call SetCaretBlinkTime(10000), which instructs Windows to blink the

   caret every 10,000 milliseconds (10 seconds). This results in a

   "round-trip" time of 20 seconds to go from OFF to ON and back to

   OFF (or vice versa).

2. Create a timer, using SetTimer(), specifying a timer procedure and a

   5,000 millisecond interval between timer ticks.

3. In the timer procedure, call SetCaretBlinkTime(10000). This resets

   the timer in Windows that controls the caret blink.

When an application implements this procedure, Windows never removes the

caret from the screen, and the caret does not blink.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrCrt


Creating a World SID

PSS ID Number: Q111543

Authored 14-Feb-1994	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

The sample code below demonstrates how to create a World Security

Identifier (SID). The World SID (S-1-1-0) is a group that includes all

users. To determine if a SID (perhaps in an Access Control Entry) is the

World SID, you must first create a World SID to compare it to. Once you

have created a World SID, you can use the EqualSid() API (application

programming interface) to determine equality.

Sample Code

-----------

PSID psidWorldSid;

SID_IDENTIFIER_AUTHORITY siaWorldSidAuthority =

     SECURITY_WORLD_SID_AUTHORITY;

psidWorldSid = (PSID)LocalAlloc(LPTR,GetSidLengthRequired( 1 ));

InitializeSid( psidWorldSid, &siaWorldSidAuthority, 1);

*(GetSidSubAuthority( psidWorldSid, 0)) = SECURITY_WORLD_RID;

Additional reference words: 3.10 and 3.50

KBCategory: kbprg

KBSubcategory: BseSecurity


Creating Access Control Lists for Directories

PSS ID Number: Q115948

Authored 07-Jun-1994	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   versions 3.1 and 3.5

SUMMARY

The discretionary access control list (DACL) for a directory usually

differs from that of a file. When assigning security to a directory, you

are often specifying both the security for the directory and the security

for any contained files and directories.

A directory's ACL will normally contain at least two access control

entries (ACE):

 - An ACE for the directory itself and any subdirectories.

 - An ACE for any files in the directory.

If an ACE is to apply to object in the directory (subdirectories and

files), the ACE is marked as an OBJECT_INHERIT_ACE and/or a

CONTAINER_INHERIT_ACE. (In this article, a container means a directory.)

For example, when you use File Manager to set the security on a directory

to "Change (RWXD)(RWXD)," the directory's DACL contains the following two

ACEs:

   ACE1 (applies to files in the directory)

      ACE flags:   INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE

      Access Mask: DELETE | GENERIC_READ | GENERIC_WRITE |

                   GENERIC_EXECUTE

   ACE2 (applies to the directory and subdirectories)

      ACE flags:   CONTAINER_INHERIT_ACE

      Access Mask: DELETE | FILE_GENERIC_READ | FILE_GENERIC_WRITE |

                   FILE_GENERIC_EXECUTE

MORE INFORMATION

The ACE flags are part of the ACE header. The structure of an ACE header

can be found in the online help by searching on "ACE_HEADER".

In the above example, ACE1 applies only to contained files through the

INHERIT_ONLY_ACE flag. If INHERIT_ONLY_ACE is not specified in an ACE, the

ACE applies only to the current container.

NOTE: Adding one of these ACEs to a directory does not change the security

for any contained files or directories. The ACEs are only copied to files

and directories created after the ACEs have been added to the directory.

When adding your own security to files, it is easy to create a

combination that File Manager does not recognize as a "standard"

setting. This is shown in file manager as "special" security.

If you want to match the DACLs you create to those used by File Manager,

you can set the security of a file or directory in File Manager and then

check the DACLs and ACEs. A tool for this is provided as a sample called

"Check_SD" in the Win32 SDK. Check_SD can be found in the

Q_A\SAMPLES\CHECK_SD directory on the Win32 SDK CD.

REFERENCES

 - "Microsoft Win32 Programmer's Reference," Microsoft Corporation.

 - "Microsoft Win32 SDK API Reference help file," Microsoft Corporation.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseSecurity


Creating and Using a Custom Caret

PSS ID Number: Q74514

Authored 22-Jul-1991	Last modified 12-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

In the Microsoft Windows graphical environment, creating a custom

caret is simple. Windows has a series of caret control, creation, and

deletion functions specifically designed to make manipulating the

caret easy.

MORE INFORMATION

The caret is a shared system resource. Unlike brushes, pens, device

contexts and such, but like the cursor, only one caret is available

under Windows. Also, like the cursor, an application can define a

custom shape for the caret.

The CreateCaret() function creates a custom caret. Its syntax is as

follows:

   void CreateCaret(HWND hWnd, HBITMAP hBitmap,

                    int nWidth, int nHeight);

The caret shape can be a line, a block, or a bitmap specified as the

hBitmap parameter. If the hBitmap parameter contains a valid handle [a

bitmap handle returned from the CreateBitmap(), CreateDIBitmap(), or

LoadBitmap() function], CreateCaret() ignores the values of its nWidth

and nHeight parameters and uses the dimensions of the bitmap. If

hBitmap is NULL, the caret is a solid block; if hBitmap is one, the

caret is a gray block. The nWidth and nHeight parameters specify the

caret size in logical units. If either nWidth or nHeight is zero, the

caret width or height is set to the window-border width or height.

If an application uses a bitmap for the caret shape, the caret can be

in color; unlike the cursor, the caret is not restricted to

monochrome.

CreateCaret() automatically destroys the previous caret shape, if any,

regardless of which window owns the caret. The new caret is initially

hidden; call the ShowCaret() function to display the caret.

Because the caret is a shared resource, a window should create a caret

only when it has the input focus or is active. It should destroy the

caret before it loses the input focus or becomes inactive. Only the

window that owns the caret should move it, show it, hide it, or modify

it in any way.

Other functions related to the caret are the following:

 - SetCaretPos()

   This function moves the caret to the specified position (in logical

   coordinates).

 - GetCaretPos()

   This function retrieves the caret's current position (in screen

   coordinates).

 - ShowCaret()

   This function shows the caret on the display at the caret's current

   position. When shown, the caret flashes automatically. If the caret

   is not owned by the window specified in the call, the caret is not

   shown.

 - HideCaret()

   This function hides the caret by removing it from the display

   screen. HideCaret() hides the caret only if the window handle

   specified in the call is the window that owns the caret. Hiding the

   caret does not destroy it.

   NOTE: Hiding the caret is cumulative; ShowCaret() must be called once

   for every call to HideCaret(). For example, if HideCaret() is called

   five times, ShowCaret() must be called five times for the caret

   to be shown.

 - DestroyCaret()

   This function removes the caret from the screen, frees the caret

   from the current owner-window, and destroys the current shape of

   the caret. It destroys the caret only if the current task owns the

   caret. This call should be used in conjunction with CreateCaret().

   DestroyCaret() does not free or destroy a bitmap used to define the

   caret shape.

 - SetCaretBlinkTime()

   This function sets the caret blink rate. After the blink rate is

   set, it remains the same until the same window changes it again,

   another window changes it, another application changes it, or

   Windows is rebooted.

 - GetCaretBlinkTime()

   This function returns the current caret blink rate.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrCrt


Creating Autosized Tables with Windows Help

PSS ID Number: Q81233

Authored 01-Mar-1992	Last modified 24-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK, versions 3.5 and 3.51

SUMMARY

A Windows Help file can contain a table to present information in a

consistent manner. Help 3.1 supports "autosized" tables where the

relative widths of the columns remain the same, even as the absolute

size of the table changes. The absolute size is determined by the size

of the Windows Help window.

MORE INFORMATION

To create an autosized table in the RTF file, create a centered table.

Create the text for the table using the minimum possible width for

each column. If the Help window is larger, the columns will be wider

and Help will compute where the text wraps based on the available

width. If the user sizes the Help window smaller than the table's

authored size, Help will display a horizontal scroll bar.

In Word for Windows version 1.1, use the Table command on the Format

menu to create a centered table. In Word for Windows 2.0, create a

table, then choose Row Height from the Table menu and choose the

Center button in the Alignment group.

Additional reference words: 3.10 3.50

KBCategory: kbtool

KBSubcategory: TlsHlp


Creating Instance Data in a Win32s DLL

PSS ID Number: Q109620

Authored 05-Jan-1994	Last modified 24-Feb-1995

The information in this article applies to:

 - Microsoft Win32s versions 1.0, 1.1, and 1.2

SUMMARY

The Win32 dynamic-link libraries (DLLs) that are running on Win32s use

shared data by default. This means that any global data in the DLL is

shared by all processes that use the DLL. Thread local storage (TLS) can be

used to create instance data; that is, data in the DLL that is specific to

each process.

The Win32s "Programmer's Reference" mentions that TLS can be used to create

instance data, but provides no details. The sample code below shows the

source for a DLL that uses instance data on both Win32 and Win32s. The

sample code was built using Microsoft Visual C++, 32-bit edition.

If you use a development environment that does not have similar support for

TLS, you should still be able to use the API (application programming

interface) calls. The API calls for TLS are TlsAlloc, TlsGetValue,

TlsSetValue, and TlsFree.

MORE INFORMATION

One reason for wanting to create instance data on Win32s is to create a DLL

that behaves identically on Win32s and Win32 (although it introduces extra

overhead on Windows NT and Windows 95). Another way to create a DLL that

behaves identically on Win32s and Win32 is to share all of the data in

the Win32-based DLL. For additional information, please see the following

article(s) in the Microsoft Knowledge Base:

   ARTICLE-ID: Q109619

   TITLE     : Sharing All Data in a DLL

Sample Code

-----------

/* Compile options used: /LD /MD

*/

int __declspec(thread) nVar = 0;    // Variables should be initialized

int __declspec(dllexport) GetVar()

{

    return nVar;

}

void __declspec(dllexport) SetVar(int nNew)

{

    nVar = nNew;

}

Additional reference words: 1.00 1.10 1.20

KBCategory: kbprg

KBSubcategory: W32s


Creating Lines with a Nonstandard Pattern

PSS ID Number: Q34614

Authored 22-Aug-1988	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

The Microsoft Windows graphical environment provides six predefined

pens for drawing dotted, dashed, and solid lines. However, an

application cannot draw fine gray lines, such as those on a Microsoft

Excel spreadsheet, with these pens. This article describes how to

create such lines.

MORE INFORMATION

An application can use the LineDDA function to produce any type of

patterned line. Based on the endpoints of a line, LineDDA calculates

each point on the line and calls an application-defined callback

function for each point. The callback function is free to use the

calculated points in any manner desired. An application can draw a

gray line similar to those used in Excel by calling the the SetPixel

function in the callback function to draw every other point.

For example, the following code calculates all points on the line from

coordinates (30, 40) to (100, 100). Then it calls the function pointed

to by the lpfnLineProc variable with the points and the handle to a

device context (hDC) as parameters:

   LineDDA(30, 40, 100, 100, lpfnLineProc, (LPSTR)hDC);

For more information on this function, see pages 4-272 and 4-273 of

the "Microsoft Windows Software Development Kit Reference, Volume 1"

for Windows 3.0 or pages 568 and 569 of the "Microsoft Windows

Software Development Kit: Programmer's Reference, Volume 2: Functions"

for Windows 3.1. Charles Petzold's book "Programming Windows 3"

(Microsoft Press, 1990) demonstrates using the LineDDA function in a

programming example on pages 593 through 598.

The following code fragment draws 50 random Excel-style lines. Note

that the LineProc function must be listed as an EXPORT in the module

definition (DEF) file:

   case WM_PAINT:

      {

      HDC hDC;

      int nIndex;

      PAINTSTRUCT ps;

      hDC = BeginPaint(hWnd, &ps);

      for (nIndex = 0; nIndex < 50; nIndex++)

         LineDDA(rand() / 110, rand() / 110, rand() / 110,

                 rand() / 110, lpfnLineProc, (LPSTR)hDC);

      EndPaint(hWnd, &ps);

      break;

      }

void FAR PASCAL LineProc(x, y, lpData)

short x, y;

LPSTR lpData;

{

   static short nTemp = 0;

   if (nTemp == 1)

      SetPixel((HDC)lpData, x, y, 0L);

   nTemp = (nTemp + 1) % 2;

}

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: GdiDrw


Creating Windows in a Multithreaded Application

PSS ID Number: Q90975

Authored 26-Oct-1992	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

In a multithreaded application, any thread can call the CreateWindow() API

to create a window. There are no restrictions on which thread(s) can create

windows.

It is important to note that the message loop and window procedure for the

window must be in the thread that created the window. If a different thread

creates the window, the window won't get messages from DispatchMessage(),

but will get messages from other sources. Therefore, the window will appear

but won't show activation or repaint, cannot be moved, won't receive mouse

messages, and so on.

MORE INFORMATION

Normally, windows created in different threads process input independently

of each other. The windows have their own input states and the threads are

not synchronized with eachother in regards to input processing.

In order to have threads to share input state, have one thread call

AttachThreadInput() to have its input processing attached to another

thread. What this means is that these two threads will use a Windows 3.1

style system queue. The threads will still have separate input, but they

will take turns reading out of the same queue.

Creating a window can force an implicit AttachThreadInput(), when a parent

window is created in one thread and the child window is being created in

another thread. When windows are created (or set) in separate threads with

a parent-child relationship, the input queues are attached.

Additional reference words: 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrWndw


Creating/Managing User Accounts Programmatically

PSS ID Number: Q119671

Authored 20-Aug-1994	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   versions 3.1 and 3.5

SUMMARY

Windows NT and the Windows NT Advanced Server use the same APIs that

Microsoft LAN Manager uses to create and maintain user- and group-account

information. For example, to create a new global group, use NetGroupAdd().

To create a new user, use NetUserAdd(). To add the user to the global

group, use NetGroupAddUser(). Local groups are created by using

NetLocalGroupAdd() and members are added to local groups by using

NetLocalGroupAddMember().

MORE INFORMATION

The APIs NetGroupAdd(), NetUserAdd(), NetGroupAddUser(),

NetLocalGroupAdd(), and NetLocalGroupAddMember() require access at the

administrator or accounts-operator level to run successfully. Windows NT

includes the following built-in groups:

 - Administrators

 - Power Users

 - Users

 - Guests

Members of the Administrators group can fully administer user accounts;

only Administrators can assign user rights and access privileges for

resources. Members of the Power Users group can create accounts only in the

Power Users, Users, and Guests groups; they can also maintain and delete

the accounts they create. However, a Power User can neither change nor

delete an account in these groups if the account was created by someone

else. A member of the Users group can create, maintain, and delete accounts

in local groups that he or she has created. Guests can neither create nor

delete accounts.

REFERENCES

In the Win32 SDK, version 3.1, the documentation for the ported LAN Manager

APIs is available in the file LMAPI.HLP on the SDK CD. In the installed

Win32 SDK, version 3.5, the ported LAN Manager APIs are documented in the

Help file "Win32 API Reference".

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: NtwkLmapi


Critical Sections Versus Mutexes

PSS ID Number: Q105678

Authored 22-Oct-1993	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

Critical sections and mutexes provide synchronization that is very similar,

except that critical sections can be used only by the threads of a single

process. There are two areas to consider when choosing which method to use

within a single process:

1. Speed. The Synchronization overview says the following about

   critical sections:

      ... critical section objects provide a slightly faster, more

      efficient mechanism for mutual-exclusion synchronization.

   Critical sections use a processor-specific test and set instruction

   to determine mutual exclusion.

2. Deadlock. The Synchronization overview says the following about

   mutexes:

      If a thread terminates without releasing its ownership of a

      mutex object, the mutex is considered to be abandoned. A waiting

      thread can acquire ownership of an abandoned mutex, but the wait

      function's return value indicates that the mutex is abandoned.

   WaitForSingleObject() will return WAIT_ABANDONED for a mutex that

   has been abandoned. However, the resource that the mutex is

   protecting is left in an unknown state.

   There is no way to tell whether a critical section has been

   abandoned.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: BseSync


CS_SAVEBITS Class Style Bit

PSS ID Number: Q31073

Authored 01-Jun-1988	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

If the CS_SAVEBITS style is included when registering a pop-up window, a

bitmap copy of the screen image that the window will obscure is saved in

memory when the window is displayed.

The bitmap is redisplayed at its original location and no WM_PAINT messages

are sent to the obscured windows if the following is true when the window

is removed from the display:

 - The memory used by the saved bitmap has not been discarded.

 - Other screen actions have not invalidated the image that has been

   stored.

As a general rule, this bit should not be set if the window will cover

more than half the screen; a lot of memory is required to store color

bitmaps.

The window will take longer to be displayed because memory needs to be

allocated. The bitmap also needs to be copied over each time the

window is shown.

Use should be restricted to small windows that come up and are then

removed before much other screen activity takes place. Any memory

calls that will discard all discardable memory, and any actions that

take place "under" the window, will invalidate the bitmap.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrPnt


CTRL+C Exception Handling Under WinDbg

PSS ID Number: Q97858

Authored 22-Apr-1993	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

An exception is raised for CTRL+C only if the process is being debugged.

The purpose is to make it convenient for the debugger to catch CTRL+C in

console applications. For the purposes of this article, the debugger is

assumed to be WinDbg.

MORE INFORMATION

When the console server detects a CTRL+C, it uses CreateRemoteThread() to

create a thread in the client process to handle the event. This new thread

then raises an exception IF AND ONLY IF the process is being debugged. At

this point, the debugger either handles the exception or it continues the

exception unhandled.

The "gh" command marks the exception as having been handled and continues

the execution. The application does not notice the CTRL+C, with one

exception: CTRL+C causes alertable waits to terminate. This is most

noticable when executing:

   while( (c = getchar()) != EOF )  - or -  while( gets(s) )

It is not possible to get the debugger to stop the wait from terminating.

The "gn" command marks an exception as unhandled and continues the

execution. The handler list for the application is searched, as documented

for SetConsoleCtrlHandler(). The handler is executed in the thread created

by the console server.

After the exception is handled, the thread created to handle the event

terminates. The debugger will not continue to execute the application if Go

On Thread Termination is not enabled (from the Options menu, choose Debug,

and select the Go On Thread Termination check box). The thread and process

status indicate that the application is stopped at a debug event. As soon

as the debugger is given a go command, the dead thread disappears and the

application continues execution.

There are three cases where CTRL+C doesn't cause the program to stop

executing (instead it causes a "page down"):

1. When CTRL+C is already being handled.

2. When the debugger is in the foreground and a source window has the

   focus (both must be true).

3. When the CTRL+C exception is disabled (through the Debugger

   Exceptions dialog box).

This follows the convention of the WordStar/Turbo C/Turbo Pascal editor

commands.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbtool

KBSubcategory: TlsWindbg


CTYPE Macros Function Incorrectly

PSS ID Number: Q94323

Authored 04-Jan-1993	Last modified 26-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

When an application that is linked to CRTDLL.LIB is compiled without

defining _MT and _DLL, the CTYPE.H family of macros will not operate

correctly.

To define _MT and _DLL on the CL command line, just add the following to

the command line:

   -D_MT -D_DLL

By adding these defines, the CTYPE macros will be properly initialized.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbtool

KBSubcategory: TlsMisc


Custom Controls Must Use CS_DBLCLKS with Dialog Editor

PSS ID Number: Q71223

Authored 10-Apr-1991	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.1, 3.5, 3.51, and 4.0

SUMMARY

For a custom control to function properly with the Dialog Editor, the

custom control window class must include the CS_DBLCLKS style.

If the custom control does not have the CS_DBLCLKS style, double-

clicking the control in the Dialog Editor does not cause the custom

control function to display its style dialog box. However, the

control's style dialog box is still accessible from the Styles command

on the Edit menu.

MORE INFORMATION

The Dialog Editor subclasses each control it creates and processes

WM_LBUTTONDBLCLK messages. In response to this message, the custom

control is asked to display its style dialog box.

If the custom control window class does not have the CS_DBLCLKS style,

Windows does not send any WM_LBUTTONDBLCLK messages to the control. As

a result, the Dialog Editor does not call the style dialog box

function for the custom control and no dialog box appears.

NOTE: This article does not apply to the resource editor included with the

Visual C++ development environment.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: UsrCtl


Customizing a Pop-Up Menu

PSS ID Number: Q12118

Authored 23-Oct-1987	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

The following are three methods to customize a pop-up menu:

1. Use the word SEPARATOR in a pop-up menu, to produce a horizontal

   bar.

2. Use the word MENUBREAK, to start the menus on another column.

3. Place the vertical bar symbol in the menu string to display a

   vertical bar on the menu.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrMen


Customizing the FileOpen Common Dialog in Windows 95

PSS ID Number: Q125706

Authored 01-Feb-1995	Last modified 06-Apr-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

SUMMARY

In Windows version 3.x, customizing the FileOpen common dialog meant

providing a special hook function, and in most cases, a custom dialog box

template. This custom dialog box template is created by modifying the

standard FileOpen dialog box template used by COMMDLG, which was actually

made available as part of the Windows versopm 3.1 SDK.

In Windows 95, the new dialog box templates will no longer be made

available for modification. Instead, an application should provide a dialog

template that includes only the items to be added to the standard dialog

box. COMMDLG will then create this dialog as a child of the standard dialog

box. Because it is a child, it must have the WS_CHILD style set.

Note that the Windows version 3.1 method of customizing common dialogs by

modifying the dialog templates will still work for 16-bit applications.

MORE INFORMATION

Follow these steps to customize the FileOpen common dialog in Windows 95:

1. Create a dialog box template that will have all the controls you

   want to add to the FileOpen common dialog. Be sure to specify the

   styles:

      WS_CHILD | WS_VISIBLE | DS_3DLOOK | DS_CONTROL | WS_CLIPSIBLINGS

   WS_CHILD is specified because without it, the call to GetOpenFileName()

   fails. COMMDLG creates the dialog specified as a child of the standard

   FileOpen common dialog box. As a result, the hDlg passed to the

   application's hook function will be the child of the standard

   FileOpen dialog box. To get a handle to the standard dialog box from

   the hook function, call GetParent (hDlg).

   WS_CLIPSIBLINGS is specified so that overlapping controls paint

   properly.

   DS_3DLOOK is a new style for Windows 95 that gives the dialog box

   a nonbold font, and gives all the controls the 3D look.

   DS_CONTROL is another new style that among other things allows the

   user to tab between the controls of a dialog box to the controls

   of a child dialog box. As mentioned above, the dialog template will

   be created as a child of the standard FileOpen common dialog box,

   so specifying this style will allow tabbing from the application-defined

   controls to the standard controls.

2. Include a static control in your dialog template, specifying a control

   ID of stc32. This control will serve as a placeholder for the standard

   controls.

   If there is no stc32 control specified, COMMDLG places all the new

   controls defined in your dialog template below the standard controls and

   looks at the size of the static control to attempt to fit all the

   standard controls in it. If it is not big enough, COMMDLG resizes this

   stc32 control to make room for the standard controls, and then

   repositions the new controls with respect to the resized stc32 control.

   Be sure to use the #include directive to include DLGS.H in your .RC

   file, as stc32 is defined in <dlgs.h>.

3. Initialize the Flags member of the OPENFILENAME structure to include the

   following flags:

      OFN_EXPLORER | OFN_ENABLETEMPLATE | OFN_ENABLEHOOK

   OFN_ENABLETEMPLATEHANDLE may be used instead of OFN_ENABLETEMPLATE if

   you want to specify a handle to a memory block containing a preloaded

   dialog box template.

4. If the OFN_ENABLETEMPLATE flag is set, specify the name of your

   application-defined template in the lpTemplateName field of the

   OPENFILENAME structure, and specify your application's instance handle

   in the hInstance field.

   If the OFN_ENABLETEMPLATEHANDLE flag is set, specify the handle to the

   memory block containing your dialog box template in the hInstance field

   of the OPENFILENAME structure.

5. Specify the address of a dialog box procedure associated with your

   dialog box in the lpfnHook field of the OPENFILENAME structure.

6. Process appropriate notifications and messages as a result of adding

   new controls.

REFERENCES

Much of the information contained in this article is derived from the

MSDN Technical Article entitled "Using the Common Dialogs Under Windows

95." Please refer to that article for more information.

Additional reference words: 4.00

KBCategory: kbprg

KBSubcategory: UsrCmnDlg


Dangers of Uninitialized Data Structures

PSS ID Number: Q74277

Authored 15-Jul-1991	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

In general, all fields in structures passed to functions in the

Microsoft Windows graphical environment should be initialized. If a

field is not initialized, it may contain random data, which can cause

unexpected behavior.

For example, before an application registers a window class, it must

initialize the cbClsExtra and cbWndExtra fields of the WNDCLASS data

structure. Windows allocates cbClsExtra bytes for the class, and

cbWndExtra bytes for each window created using the class. If these

fields contain large random values, the application may run out of

memory quickly.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: UsrWndw


DDE Error Message: Application Using DDE Did Not Respond

PSS ID Number: Q94955

Authored 26-Jan-1993	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

 - Microsoft Win32 SDK, version 4.0

SUMMARY

DDEML displays a dialog box with the following error message when a

terminate deadlock occurs, often caused by a DDE application not

terminating correctly:

   Application using DDE did not respond to the System's Exit command

MORE INFORMATION

A terminate deadlock situation occurs when DDEML times out while

waiting for a responding terminate.

This message box appears when a DDEML application calls

DdeUninitialize() with conversations still active. DdeUninitialize()

posts WM_DDE_TERMINATE messages for each open conversation, and waits

for a corresponding WM_DDE_TERMINATE for a set period of time. This

time is actually set in the [DDEML] section of the WIN.INI file

   [DDEML]

   ShutdownTimeout= ?

   ShutdownRetryTimeout=?

where both are defined as integers defaulting to 30000 milliseconds.

These WIN.INI entries were purposely not documented to discourage

people from setting them to some other value.

If DDEML does not receive a response within the set period of time, it

brings up the message box to allow the user to choose to either quit,

wait longer, or wait indefinitely. This was done to work around a

problem in Windows 3.0 where the system locks up if an application

attempts to post a message to a non-existent window, and to allow the

user to save his work.

Additional reference words: 3.10 3.00 4.00 95

KBCategory: kbprg

KBSubcategory: UsrDde


DdeInitialize(), DdeNameService(), APPCMD_FILTERINITS

PSS ID Number: Q108925

Authored 20-Dec-1993	Last modified 18-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

DdeInitialize() and DdeNameService() work as complimentary functions during

initialization of a server application. When called for the first time to

initialize a server application, DdeInitialize() will cause DDEML to append

the APPCMD_FILTERINITS flag to the third parameter of the function call by

default. Once this flag is set, client applications will not be able to

connect to the server until it is reset. This flag is reset when the

function DdeNameService() is called to register the service name with

DDEML. Also, if the server wishes to remain anonymous, then DdeInitialize()

must be called the second time to specifically turn off the

APPCMD_FILTERINITS flag.

MORE INFORMATION

The DdeInitialize() function registers an application with DDEML. This

function must be called by both the client and the server applications

before calling any other DDEML function.

When the server application calls DdeInitialize() for the first time, DDEML

appends the APPCMD_FILTERINITS flag to the third parameter of the function

call, regardless of whether the application specifies this flag. This flag

when used, will prevent DDEML from sending the XTYP_CONNECT and

XTYP_WILDCONNECT transactions to the server application until the server

has created its string handles and performed other application-specific

initialization. The server application then calls DdeNameService() to

register its service name with DDEML so that other client or server

applications are notified of its existence. Calling DdeNameService() after

the server has gone through the process of initialization turns off the

APPCMD_FILTERINITS flag.

Some DDEML server applications might not want to register their names with

DDEML because of various reasons (for example, the server application is a

custom server application that wants to service particular clients, and

thus wishes to remain anonymous to the rest of the system).

In special cases like this, an application may choose not to call the

DdeNameService() function, because this function broadcasts the name of the

server to all DDEML applications on the system. Not calling the

DdeNameService() function, however, causes the APPCMD_FILTERINIT flag not

to be reset properly, thus keeping the server from getting any XTYP_CONNECT

or XTYP_WILDCONNECT transactions even from its clients.

One other way to reset this flag is to call DdeInitialize() a second time,

without specifying the APPCMD_FILTERINITS flag.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrDde


DDEML Application-Instance IDs Are Thread Local

PSS ID Number: Q94091

Authored 23-Dec-1992	Last modified 01-Mar-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1 and 3.5

When using the DDEML (Dynamic Data Exchange Management Library) libraries

from a spawned thread, the application-instance ID that is returned in the

lpidInst parameter of DdeInitialize is thread local.

Therefore, the application-instance ID cannot be used by any other thread

that is spawned by the process, nor can it be inherited from the parent.

To use the DDEML libraries within a thread, it is necessary to make both

the DdeInitialize call and to use the DdeUninitialize call from within the

thread; otherwise, there is no way to terminate the DDEML session.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: UsrDde


Dealing w/ Lengthy Processing in Service Control Handler

PSS ID Number: Q120557

Authored 14-Sep-1994	Last modified 13-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.1, 3.5,

   and 3.51

The service control handler function must return within 30 seconds. If it

does not, the Service Control Manager will return the following error:

"Error 2186 - The service is not responding to the control function".

If a service needs to do lengthy processing when the service is in the

service control handler, it should create a secondary thread to perform the

lengthy processing and then return. This prevents the service from tying up

the service control handler thread.

If you are processing a SERVICE_CONTROL_STOP, you may wish to register a

status of SERVICE_STOP_PENDING. The dwWaitHint should be at least 30

seconds. You can make the control panel applet wait for a long time if you

send multiple SERVICE_STOP_PENDING states which update the dwCheckPoint and

use a long dwWaitHint.

The system shutting down is another event that limits the service control

handler. The dwCtrlCode parameter for the service control handler returns

SERVICE_CONTROL_SHUTDOWN. A service then has approximately 20 seconds to

perform cleanup tasks. If the tasks are not done, the system shuts down

regardless if the service shutdown is complete. If the user has selected

"restart", all processes will halt quickly. If instead the system is left

in the "shutdown" state, the service processes continue to run.

If you need a longer time to shut down or earlier notification, consider

using SetConsoleCtrlHandler() or SetProcessShutdownParameters() instead of

using SERVICE_CONTROL_SHUTDOWN. This is the same mechanism that the Service

Controller uses to get its notification.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseService


Debugging a Service with WinDbg

PSS ID Number: Q98890

Authored 18-May-1993	Last modified 27-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

The following steps illustrate how to debug a service under Windows NT

using WinDbg, which ships with the Win32 Software Development Kit (SDK).

For illustration purposes, this procedure uses the SERVICE sample, which is

built with debugging information by default. This sample is located in:

   Win32 SDK 3.1:

      MSTOOLS\SAMPLES\SERVICE

   Win32 SDK 3.5:

      MSTOOLS\SAMPLES\WIN32\SERVICE

   Win32 SDK 3.51 and 4.0:

      MSTOOLS\SAMPLES\WIN32\WINNT\SERVICE

MORE INFORMATION

 1. Build the sample.

 2. Install the Simple service with the following command:

       Win32 SDK 3.1:

          instsrv simple <drive>:\mstools\samples\service\simple.exe

       Win32 SDK 3.5 and later:

          simple - install

    Upon success, you will receive the message "CreateService Success".

 3. Use the Control Panel's Services application to start the Simple

    service. With the Win32 SDK 3.5, you can also use

       sc start simpleservice

    The SC.EXE is located in MSTOOLS\BIN.

 4. Use PView to get the process ID (PID) for the Simple service. For

    instance, if PView shows the process as simple(0xD5), then the PID

    is 0xD5.

 5. If using SDK versions 3.1 or 3.5, convert the PID from hexadecimal to

    decimal. For example, 0xD5 is 213 in decimal. Later versions of WinDbg

    use hexadecimal PIDs.

 6. At a command prompt, go to the directory containing the sample and type

       start windbg

    to start WinDbg in its own command shell.

 7. In WinDbg, choose Open from the File menu and open the source file

    (SIMPLE.C).

 8. Set breakpoints at (for example) lines 326, 335, 337, 344, and 353.

    The lines will not change color at this point, but the breakpoints

    are successfully set.

 9. Open a command window in WinDbg and type

       .attach <PID>

    Note that the lines where breakpoints are set will have changed

    colors.

10. Type "g" (a go command) in the WinDbg command window to restart

    after the thread that WinDbg uses to do the .attach terminates.

11. At the command prompt, start the client by typing

       Win32 SDK 3.1:

          client \\.\pipe\simple boo

       Win32 SDK 3.5 and later:

          client [-pipe <pipename>] [-string <string>]

12. Press F5 (a go command) to debug the service. The breakpoint hit

    will be on line 335. Press F5 again to go to the next breakpoint.

    Keep pressing F5 until line 326 waits again for a client to

    connect. Try connecting another client and repeat the same steps.

Exiting WinDbg will kill the service, which must be restarted manually

with the Control Panel.

Services must log on as LocalSystem for this to work correctly; otherwise,

you will not have permission to debug the service.

The manual translation of the PID from hexadecimal to decimal will not

be needed in the future once the .attach command is modified so that

it accepts hexadecimal.

NOTE: Under Windows NT 3.5 and later, because services do not have access

to the user's desktop by default, one additional step must be taken to

debug services with Windbg. In order to debug services, the user must check

the startup option "Allow Service to interact with Desktop" in the Services

control panel applet. You can do the same thing programmatically by setting

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\<DisplayName>\Type to

0x110.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbtool

KBSubcategory: TlsWindbg


Debugging a System-Wide Hook

PSS ID Number: Q102428

Authored 03-Aug-1993	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

Debugging a system-wide hook such as a journal hook must be done with the

extreme caution. When an application installs such a hook, it effectively

takes control of user input. In effect, this disables the interface with

the debugger. For example, after installing a journal record hook, you must

unhook the record hook when you want to allow the debugger to regain

control.

It is not possible to use an interactive debugger to debug an actively

installed journal hook using a single machine. It is possible to use a

remote debugger, because one interface can be blocked (or recording) while

the other one does the debugging.

MORE INFORMATION

System-wide input hook procedures can be thought of as being in three

possible states:

   unhooked (not installed)

   suspended

   hooked (installed)

In the unhooked state, the procedure imposes no control over user input. In

the hooked state, all user input specifically defined to be handled by this

hook passes through this procedure. In the suspended state, all user input

specifically defined to be handled by this hook is completely blocked.

In the case of a journal record hook, the suspended state can be achieved

when a breakpoint is reached within the hook procedure. When this happens,

all user input (system wide, that is) in the form of mouse and keyboard

input is blocked, and thus you cannot interact with the debugger or any

other application as you normally would. Fortunately, when the user presses

the CTRL+ESC or the CTRL+ALT+DEL key combinations, all system-wide hooks

are automatically unhooked, returning the system to the unhooked state.

Once this has occurred, it is likely that the application with the journal

hook is now in a undefined state (because it had the hook pulled out from

underneath it, so to speak). Fortunately, the system will send all

applications the WM_CANCELJOURNAL message to indicate that it has removed

the hook. A well behaved application can intercept this message and adjust

its state accordingly.

Additional reference words: 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrHks


Debugging Applications Under Win32s

PSS ID Number: Q102430

Authored 03-Aug-1993	Last modified 04-May-1995

The information in this article applies to:

 - Microsoft Win32s versions 1.0, 1.1, and 1.2

SUMMARY

To start debugging a Win32-based application, make sure that it runs

correctly under Windows NT. Use either WinDbg or NTSD to track down any

problems.

Then, install the debugging libraries for Windows 3.1 and the debug version

of Win32s. Hook the machine to another machine running a terminal emulator

and watch for any warnings that are issued. Be sure to select the

Win32sDebug flags carefully--selecting too many will generate more

information than you may care to see; selecting too few may cause you to

miss important information and warnings.

If you need to debug on Win32s, there are currently two options:

 - Use wdeb386 (note that this method is very tricky).

 - Use remote WinDbg (WDBG32S.EXE) if you are not familiar with using a

   kernel debugger. This method requires two machines: a Win32s

   machine to run the application and the remote debugger and a Windows NT

   machine to run WinDbg.

If you have Microsoft Visual C++ 32-bit Edition version 1.0, CodeView for

Win32s is an additional option. CodeView for Win32s is a user-level

debugger; remote debugging is not necessary, and therefore CodeView for

Win32s does not require a second machine. CVW32S does not come with Visual

C++ 2.0 and later. You can still use CVW32S.EXE with later versions of

Visual C++, if you link with /PDB:none and /INCREMENTAL:no and if you do

not use new features such as templates or C++ exception handling.

MORE INFORMATION

When performing remote debugging, make sure that the cable is set up

exactly as specified in the Win32s Programmer's Reference. The remote

WinDbg does not support software flow control, so it is very important that

the hardware flow control is set up properly. If it is not set up

correctly, you will have problems as the buffers overflow.

WinDbg supports XON/XOFF (software) flow control, which means that the

standard 3-wire cable can now be used, although the default is still

hardware handshaking (5-wire cable). To enable XON/XOFF, you must specify

the XON flag in the serial transport parameters on both WinDbg and

remote WinDbg.

To enable XON/XOFF in the remote WinDbg:

1. Select Options to bring up the Transport dynamic-link library (DLL)

   dialog box.

2. Select the serial transport and make any needed modifications to

   the communications port or baud rate parameters.

3. Place the XON flag at the end of the Parameters box. For example,

   "COM1:19200 XON". Note that the space is needed.

To enable XON/XOFF on WinDbg:

1. Select Options/Debug DLLs.

2. Select the proper serial transport layer.

3. Choose the Change button.

4. Add XON to the end of the Parameters line: "COM1:19200 XON".

It is very important that both sides of the debugger use the same protocol.

If they do not, both debuggers will probably hang. Also, the remote

debugging environment requires that binaries be located on the same

drive/directory on both the development and target systems. For example, if

WIN32APP.EXE is built from sources in a C:\DEV\WIN32APP directory, the

binary should be located in this directory on both systems. If you build

your source files by specifying fully qualified paths for the compiler, the

compiler will place this information with the debug records which will

allow WinDbg to automatically locate the appropriate source files.

For additional information on remote debugging, please see the "Win32s

Programmer's Reference" which is included with the Win32 SDK.

Additional reference words: 1.00 1.10 1.20

KBCategory: kbprg

KBSubcategory: W32s


Debugging Console Apps Using Redirection

PSS ID Number: Q102351

Authored 03-Aug-1993	Last modified 26-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

To redirect the standard input (STDIN) for a console application named

APP.EXE from a file named INPUT.TXT, the following syntax is used:

   app < input.txt

However, the following syntax will not work when attempting to debug

this application using WinDbg with STDIN redirected:

   windbg app < input.txt

To debug the application as desired, use

   windbg cmd /c "app < input.txt"

MORE INFORMATION

This will allow WinDbg to debug whatever goes on in the cmd window. A

dialog box will be displayed that says "No symbolic Info for Debuggee."

This message refers to CMD.EXE; dismiss this dialog box. When the child

process (APP.EXE) is started, the command window will read "Stopped at

program entry point." To continue, type "g" at the command window. Note

that APP.EXE will begin executing, then you can open the source file and

set breakpoints.

This technique is also useful when debugging an application that behaves

differently when run with a debugger than it does when it is run in the

command window.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbtool

KBSubcategory: TlsWindbg


Debugging DLLs Using WinDbg

PSS ID Number: Q97908

Authored 25-Apr-1993	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

This article describes the process of debugging dynamic-link libraries

(DLLs) under WinDbg. As a further example, debugging File Manager

extensions under Windows NT is discussed in the "More Information" section

in this article.

MORE INFORMATION

The application and the DLL must be built with certain compiler and linker

switches so that debugging information is included. These switches can be

found in the $(cdebug) and $(ldebug) macros, respectively, which are

defined in NTWIN32.MAK.

NOTE: It is important to disable optimization with -Od or locals will not

be available in the locals window and line numbers may not match the

source.

The application is loaded into WinDbg either by specifying "windbg

<filename>" on the command prompt or by starting WinDbg from the program

group and specifying <filename> in the Program Open dialog box (from the

Program menu, choose Open). Note that <filename> is the name of the

application, not the DLL. It is not necessary to specify the name of the

DLL to be debugged.

The DLL is loaded either when execution of the application begins or

dynamically through a call to LoadLibrary(). In the first case, simply

press F8 to begin execution. All DLLs and symbolic information are loaded.

To trace through the DLL code, breakpoints can be set in the DLL using a

variety of methods:

 - From the Debug menu, choose Breakpoints. The dialog box is Program Open.

   -or-

 - Open the source file and use F9 or the "hand" button on the toolbar.

   -or-

 - Go to the Command window and type:

       bp[#] <Options>

   <Options>:

      addr          break at address

      @line         break at line

In the case that the DLL is dynamically loaded, pressing F8 causes all

other DLLs and symbolic information to load. The same methods described

above can be used to set breakpoints; however, the user will get a dialog

box indicating that the breakpoint was not instantiated. After the call to

LoadLibrary() has been executed, all breakpoints are instantiated (it is

possible to note the color change if the DLL source window is open) and

will behave as expected.

To set a breakpoint in a DLL that is not loaded, specify the context when

setting the breakpoint. The syntax for a context specifier is:

   {proc, module, exe}addr

   -or-

   {proc, module, exe}@line

Example: {func, module.c, app.exe}0x50987. The first two parameters are

optional, so {,,app.exe}0x50987 or {,,app.exe}func could be used instead.

For example, assume that we are trying to debug a File Manager extension

under Windows NT that has been built with full debugging information. The

procedure to debug the extension is as follows:

1. Open a Command window.

2. Start WinDbg WINFILE.

3. Set a breakpoint on FmExtensionProc().

4. At the Command window, type "g" and press ENTER. The debugger will

   continue executing the program form the point where it stopped

   (which could be from the beginning, at the breakpoint, and so on).

WinDbg will start WINFILE and when FmExtensionProc() is executed, WinDbg

will break into the WINFILE process.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbtool

KBSubcategory: TlsWindbg


Debugging OLE 2.0 Applications Under Win32s

PSS ID Number: Q123812

Authored 11-Dec-1994	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32s version 1.2

SUMMARY

The following are available to help you debug your OLE 2.0 applications

under Win32s:

 - Debug versions of the OLE DLLs, included with Win32s. (See the Win32s

   Programmer's Reference for more information on the debug DLLs.)

 - Failure/trace messages.

 - The OLE SDK for Win32s, version 1.2, included on the Microsoft Developer

   Network (MSDN) CD.

For information on a utility that will convert OLE error codes into

error message, please see the following article in the Microsoft Knowledge

Base:

   ARTICLE-ID: Q122957

   TITLE     : SAMPLE: DECODE32: OLE Error Code Decoder Tool

MORE INFORMATION

The debug version of OLE can send diagnostic information to the debug

terminal. To enable this feature, include the following lines in the

SYSTEM.INI:

   [Win32sDbg]

   ole20str=xxxxx

   ole20str16=yyy

Use ole20str for 32-bit OLE and ole20str16 for 16-bit OLE. Set them to a

combination of the following letters (case sensitive):

   f - Failure message, kind of asserts.

   v - Verbose. General purpose messages.

   1 - Trace special translation activity for 32/16 interoperability.

   i - Trace initialization of OLE.

   t - Trace termination and cleanup of OLE.

The following tools are contained in the OLE SDK for Win32s, version 1.2:

 - DFVIEW - Show the content of storage files.

 - LRPCSPY - Monitor LRPC messages sent by 16-bit OLE applications (does

   not require Win32s).

 - RPCSPY32 - Monitor LRPC messages from both 16-bit and 32-bit OLE

   applications.

 - DOBJVIEW and DOBJVW32 - View objects placed on the clipboard as well as

   objects transferred by drag and drop.

 - IROTVIEW and IROTVW32 - Display the contents of the OLE running object

   table (ROT).

 - OLE2VIEW and OLE2VW32 - Identify objects, interfaces, inproc and local

   servers, registration database entries, and so on.

Additional reference words: 1.20

KBCategory: kbole kbprg

KBSubcategory: W32s


Debugging the Win32 Subsystem

PSS ID Number: Q105677

Authored 22-Oct-1993	Last modified 23-Feb-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

The instructions on page 1-18 of Part II of the Win32 "Programmer's Guide"

included with the Win32 Device Driver Kit (DDK) says to use NTSD -d -p -1

to attach to the Win32 subsystem process and enable debugging of its user-

mode drivers. This results in the error:

   NTSD: cannot debug PID -1

   error = 5

To enable this procedure to work properly, change the GlobalFlag value

under:

   HKEY_LOCAL_MACHINE\

               SYSTEM\

    CurrentControlSet\

              Control\

      Session Manager

Remove the flag 0x00080000 from 0x211a0000 to make it 0x21120000. The

0x00080000 flag disables the ability to debug CSRSS.EXE (the client

server run time subsystem), which is specified by the "-p -1"

parameter.

It is also possible to debug CSRSS using "WinDbgRm -c -p-1" instead of

NTSD. Make sure that WinDbgRm defaults to debugging using TLPIPE.DLL

as its transport layer, then run "windbgrm -c -p-1" on the debuggee.

On the debugger machine, make sure that CSRSS.EXE and any dynamic-link

libraries (DLLs) that you are debugging in association with it are in

the same directory, and run WinDbg. To set the transport DLL, choose

Debug from the Options menu, choose Transport DLLs, and set the

transport DLL to TLPIPE. Set the host name entries to be the machine

name of the debuggee.

Additional reference words: 3.10 3.50

KBCategory: kbtool

KBSubcategory: TlsMisc


Debugging Universal Thunks

PSS ID Number: Q105756

Authored 24-Oct-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32s versions 1.0, 1.1, and 1.2

The general recommendation for an application targeted for Win32s is to

debug it under Windows NT, then make sure that the application works under

Win32s. However, Universal Thunks are not supported on Windows NT, so it is

not possible to debug Win32-based applications that use the Universal Thunk

in this manner.

To debug across the Universal Thunk, you can use WDEB386, which is

available with the Windows 3.1 Software Development Kit (SDK). If you are

not familiar with WDEB386, you may find it simpler to use other methods. In

that case, be sure to install the debug version of Windows 3.1 and the

debug version of Win32s and enable suitable notifications for Win32s

(unimplemented functions and messages, verbose, and so forth). You may find

OutputDebugString() useful for displaying extra information.

For more information on WDEB386, please see the Knowledge Base article

"Tips On Installing WDEB386." For information on installing the debug

version of Windows, please see your Windows SDK documentation.

Additional reference words: 1.00 1.10 1.20

KBCategory: kbprg

KBSubcategory: W32s


Default Attributes for Console Windows

PSS ID Number: Q90837

Authored 22-Oct-1992	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

SUMMARY

Console attributes (screen fonts, screen colors, insert/overstrike, etc.)

are stored by console title within each user's profile. When a profile for

a new window is not found, the .DEFAULT configuration is used.

MORE INFORMATION

You can change the start font, screen colors, pop up colors, and

insert/overstrike defaults using REGEDT32. Under the key HKEY_USERS, there

is a .DEFAULT along with an entry for each user who has an account on that

machine. Select DEFAULT\Console\Configuration. Use Edit.AddValue to add

FontSize as a REG_DWORD to change the default font, Add ScreenColors and

PopupColors as REG_DWORDs to change those defaults. To reset the console to

be in insert mode rather than overstrike mode, add InsertMode as REG_SZ and

set it to ON.

To get the right settings for the font size and colors you should first set

your MS-DOS Prompt window font size and colors. Look up Console\MS-DOS

Prompt\Configuration under your account and write down the values for the

keys you need to add. Then go back to DEFAULT\Console\Configuration and add

those values.

The DEFAULT configuration is read when the user chooses the Command

prompt. However, if the user chooses to run a command shell via the

File Manager (selecting CMD.EXE and choosing Run from the File menu),

the DEFAULT configuration will not be read out of the registry.

-----------------------------------------------------------------------

WARNING:

RegEdit is a very powerful utility that facilitates directly changing

the Registry Database. Using RegEdit incorrectly can cause serious

problems, including hard disk corruption. It may be necessary to

reinstall the software to correct some problems. Microsoft does not

support changes made with RegEdit. Use this tool at your own risk.

-----------------------------------------------------------------------

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseCon


Default Edit Control Entry Validation Done by Windows

PSS ID Number: Q74266

Authored 15-Jul-1991	Last modified 16-May-1995

-

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK), versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

-

Under the Microsoft Windows graphical environment, multiline and

single-line edit controls do not accept characters with virtual key

code values less than 0x20. The two exceptions are the TAB and ENTER

keys; users can enter these characters only in a multiline edit

control.

If an application creates an edit control with the ES_LOWERCASE or

ES_UPPERCASE style, text entry is converted into the specified case.

If an application creates an edit control with the ES_OEMCONVERT

style, the text is converted from the ANSI character set to the OEM

character set and then back to ANSI for display in the control.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: UsrCtl


Default Stack in Win32-Based Applications

PSS ID Number: Q97786

Authored 21-Apr-1993	Last modified 06-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.1 and 3.5

SUMMARY

By default, space is reserved for applications in the following manner:

   1 megabyte (MB) reserved (total virtual address space for the stack)

   1 page committed (total physical memory allocated when stack is

                     created)

   Note: The -stack linker option can be used to modify both of these

         values.

The default stack size is taken from the process default reserve stack

size.

The operating system will grow the stack as needed by committing 1 page

blocks (4K on an x86 machine) out of the reserved stack memory. Once all of

the reserved memory has been committed, Windows NT will attempt to continue

to grow the stack into the memory adjacent to the memory reserved for the

stack, as shown in the following example on an x86 machine:

   |<--- Total 1 MB for stack --->|<--- Adjacent memory --->|

   --------------------------------------------------------

   |       |                      |                         |

   |  4K   |   1020K  ...         |       ...               |

   |       |                      |                         |

   --------------------------------------------------------

However, once the stack grows to the point that the adjacent area is not

free (and this may happen as soon as the reserved 1 MB has been committed),

the stack cannot grow any farther. Therefore, it is very risky to rely on

this memory being free. Applications should take care to reserve all the

memory that will be needed by increasing the amount of memory reserved for

the stack.

In other cases, it may be desirable to reduce the amount of memory reserved

for the stack.

The /STACK option in the linker and the STACKSIZE statement in the DEF file

can be used to change both the amount of reserved memory and the amount of

committed memory. The syntax for each method is shown below:

   /STACK:[reserve][,commit]

   STACKSIZE [reserve][,commit]

MORE INFORMATION

Each new thread gets its own stack space of committed and reserved memory.

CreateThread() has a stacksize parameter, which is the commit size. If a

new size is not specified in the CreateThread() call, the new thread

takes on the same stack size as the thread that created it, whether that be

the default value, a value defined in the DEF file, or by the linker

switch. If the commit size specified is larger than the default process

stack size, the stack size is set to the commit size. When specifying a

stack size of 0, the commit size is taken from the process default commit.

The system handles committing more reserved stack space when needed, but

cannot reserve or commit more than the total amount initially reserved (or

committed if no additional is reserved). Remember that the only resource

consumed by reserving space is addresses in your process. No memory or

pagefile space is allocated. When the memory is actually committed, both

memory and pagefile resources are allocated. There is no harm in reserving

a large area if it might be needed.

As always, automatic variables are placed on the stack. All other static

data is located in the process address space. Because they are static, they

do not need to be managed like heap memory.

Note that under Win32s 1.2 and earlier, stacks are limited to a maximum of

128K (this limit has been increased with Win32s 1.25a). The same stack is

used on the 16-bit side of a Universal Thunk (UT). A 16:16 pointer is

created and it points to the top of the 32-bit stack. The selector base is

set in such a way that the 16-bit code is allocated at least an 8K stack.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseMm


Default/Private Dialog Classes, Procedures, DefDlgProc

PSS ID Number: Q68566

Authored 22-Jan-1991	Last modified 18-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

The information below explains the differences between default and

private dialog classes, their associated dialog procedures, and using

the DefDlgProc() function.

This information is organized as a comparison between private and

default dialog classes, covering class registration, dialog templates,

dialog creation, and message processing.

Note that the source to the DefDlgProc() function is provided with the

Windows Software Development Kit (SDK) version 3.0. The code is

supplied on the Sample Source 2 disk in the DEFDLG.C file. By default,

DEFDLG.C is placed into the \SAMPLES\DEFPROCS directory if the SDK

installation program copies the sample source code.

There are many functions and macros used in DefDlgProc() that are

internal to Windows and cannot be used by applications. No additional

information is available on these functions and macros.

MORE INFORMATION

All dialog classes are window classes, just as all dialog boxes are

windows. All dialog classes must declare at least DLGWINDOWEXTRA in

the cbWndExtra field of the WNDCLASS structure before the dialog class

is registered. The Windows Dialog Manager uses this area to store

special information for dialog boxes.

The default dialog class is registered by Windows at startup. The

window procedure for this class is known as DefDlgProc(), which is

located in Windows's USER module. DefDlgProc() calls the application-

provided dialog function, which returns TRUE if it processes a message

completely or FALSE if DefDlgProc should process the message further.

If an application registers a private dialog class, it provides a

window procedure for the dialog box. The window procedure is the same

as that for any other application window and returns a LONG value.

Messages that are not processed by this window function are passed to

DefDlgProc().

Dialog Class Registration

-------------------------

Windows registers the default dialog class, which is represented by

the value 0x8002. Windows uses this class when an application creates

a dialog box using the DialogBox() or CreateDialog() functions, but

specifies no class in the dialog resource template.

To use a private dialog class, the application must specify the fields

of a WNDCLASS structure and call RegisterClass(). This is the same

procedure that Windows uses to register the default dialog class.

In either case, the value in the cbWndExtra field of the WNDCLASS

structure must contain a value of at least DLGWINDOWEXTRA. These bytes

are used as storage space for dialog-box specific information, such as

which control has the focus and which button is the default.

When a dialog class is registered, the lpfnWndProc field of the

WNDCLASS structure must contain a function pointer. For the default

dialog class, this field points to DefDlgProc(). For a private class,

the field points to application-supplied procedure that returns a LONG

(as does a normal window procedure) and passes all unprocessed

messages to DefDlgProc().

Dialog Templates

----------------

Resource scripts are almost identical whether used with a default or a

private dialog class. Dialog boxes using a private class must use the

CLASS statement in the dialog template. The name given in the CLASS

statement must match the name of class that exists (is registered)

when the dialog box is created.

Dialog Creation and the lpfnDlgFunc Parameter

---------------------------------------------

Applications create dialog boxes using the function DialogBox(),

CreateDialog(), or one of the variant functions such as

DialogBoxIndirect(). The complete list of functions is found on page 1-

43 of the "Microsoft Windows Software Development Kit Reference Volume

1."

All dialog box creation calls take a parameter called lpfnDlgFunc,

which can either be NULL or the procedure instance address of the

dialog box function returned from MakeProcInstance(). When the

application specifies a private dialog class and sets lpfnDlgFunc to a

procedure instance address, the application processes each message for

the dialog box twice. The message processing proceeds as follows:

1. Windows calls the dialog class procedure to process the message. To

   process a message in the default manner, this procedure calls

   DefDlgProc().

2. DefDlgProc() calls the procedure specified in the dialog box creation

   call.

The procedure specified in lpfnDlgFunc must be designed very

carefully. When it processes a message, it returns TRUE or FALSE and

does not call DefDlgProc(). These requirements are the same as for any

other dialog procedure.

Using a dialog procedure in conjunction with a private dialog class

can be very useful. Processing for the private dialog class can be

generic and apply to a number of dialog boxes. Code in the dialog

procedure is specific to the particular instance of the private dialog

class.

Dialog Message Processing

-------------------------

In dialog boxes with the default class, the application provides a

callback dialog function that returns TRUE or FALSE, depending on

whether or not the message was processed. As mentioned above,

DefDlgProc(), which is the window procedure for the default dialog

class, calls the application's dialog function and uses the return

value to determine whether it should continue processing the message.

In dialog boxes of a private class, Windows sends all messages to the

application-provided window procedure. The procedure either processes

the message like any other window procedure or passes it to

DefDlgProc(). DefDlgProc() processes dialog-specific functions and passes

any other messages to DefWindowProc() for processing.

Some messages are sent only to the application-supplied procedure

specified in the call to CreateDialog() or DialogBox(). Two examples of

functions that Windows does not send to the private dialog class

function are WM_INITDIALOG and WM_SETFONT.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrDlgs


Defining Private Messages for Application Use

PSS ID Number: Q86835

Authored 19-Jul-1992	Last modified 23-Jun-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.1 and 3.0

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

In the Microsoft Windows environment, an application can define a private

message for its own use without calling the RegisterWindowMessage API.

Message numbers between 0x8000 and 0xBFFF are reserved for this purpose.

For Windows NT and Windows 95, the system defines a new message WM_APP

(value 0x8000). Applications can make use of the range WM_APP through

0xBFFF for private messages without conflict. The only requirement is that

the .EXE file must be marked version 4.0 (use the linker switch

/subsystem:windows,4.0). Windows NT 3.5 and 3.51 and Windows 95 will run

applications marked version 4.0.

MORE INFORMATION

The documentation for the WM_USER message lists four ranges of message

numbers as follows:

   Message Number           Description

   --------------           -----------

   0 through WM_USER-1      Messages reserved for use by Windows.

   WM_USER through 0x7FFF   Integer messages for use by private window

                            classes.

   0x8000 through 0xBFFF    Messages reserved for use by Windows.

   0xC000 through 0xFFFF    String messages for use by applications.

   Greater than 0xFFFF      Reserved by Windows for future use.

When an application subclasses a predefined Windows control or

provides a special message in its dialog box procedure, it cannot use

a WM_USER+x message to define a new message because the predefined

controls use some WM_USER+x messages internally. It was necessary to

use the RegisterWindowMessage function to retrieve a unique message

number between 0xC000 and 0xFFFF.

To avoid this inconvenience, messages between 0x8000 and 0xBFFF were

redefined to make them available to an application. Messages in this

range do not conflict with any other messages in the system.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: UsrMsg


Definition of a Protected Server

PSS ID Number: Q102447

Authored 03-Aug-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

SUMMARY

The Win32 application programming interface (API) reference briefly

discusses creating a "protected server" that assigns security to private

objects. This article explains the concept of a protected server" and its

relationship to private objects.

MORE INFORMATION

A protected server is an application that provides services to clients.

These services could be as simple as saving and retrieving information from

a database while issuing security checks to verify that the client has

proper access.

A private object is an application-defined data structure that both the

client and server recognize. Private objects are not registered with nor

recognized by the Windows NT operating system; they are entirely

application-defined.

It is not uncommon for security to be assigned to private objects in a

protected server's database. For example, when a client asks the server to

create a new object in the database, the server could use the

CreatePrivateObjectSecurity() Win32 API to create a security descriptor

(SD) for the new private object. The server would then store the SD with

the private object in the database. It is important to note that there is

nothing in the SD that associates it with the private object. Instead, it

is up to the protected server to maintain that association in the private

object or in the database. It is likely that the private object and the

associated SD would be stored together in a single database record.

A protected server application is responsible for checking a client's

access before providing information. For example, when a client asks the

server to retrieve some data, the server would go out and locate the record

(which would contain the private object and SD) and bring a copy of the SD

into memory. It would then call the AccessCheck() Win32 API passing the SD,

the clients access token, and the desired access mask. AccessCheck() will

check the client's access against the object's SD to determine if access is

permitted. Depending on the result of AccessCheck(), the protected server

would either provide the requested information or deny access.

In conclusion, a protected server is a application that performs operations

on private objects that are entirely user defined. The protected server is

responsible for associating security descriptors to those objects and must

take the steps necessary to verify a client's access.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseSecurity


Detecting Closure of Command Window from a Console App

PSS ID Number: Q102429

Authored 03-Aug-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

Win32 console applications run in a command window. For the console

application to detect when the console is closing, register a console

control handler and look for the following values in your case statement:

   CTRL_CLOSE_EVENT     User closes the console

   CTRL_LOGOFF_EVENT    User logs off

   CTRL_SHUTDOWN_EVENT  User shuts down the system

For an example, see the CONSOLE sample. For more information, see the entry

for SetConsoleCtrlhandler() in the Win32 application programming interface

(API) reference.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseCon


Detecting Data on the Communications Port

PSS ID Number: Q118625

Authored 25-Jul-1994	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

To detect whether there is any data available on the communications (COM)

port without calling ReadFile(), use the ClearCommError() API. The field

COMSTAT.CbInQue contains the number of bytes not yet read by a call to

ReadFile().

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: BseCommapi


Detecting Keystrokes While a Menu Is Pulled Down

PSS ID Number: Q35930

Authored 29-Sep-1988	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

In the Windows environment, there are two methods that an application

can use to receive notification that a key is pressed while a menu is

dropped down:

 - The easier method is to process the WM_MENUCHAR message that is sent

   to an application when the user presses a key that does not correspond

   to any of the accelerator keys defined for the current menu.

 - The other method is to use a message filter hook specified with the

   SetWindowsHook function. The hook function can process a message

   before it is dispatched to a dialog box, message box, or menu.

The hook functions and the WM_MENUCHAR message are documented in the

Microsoft Windows SDK "Reference: Volume 1" for version 3.0 and in

"Programmer's Reference, Volume 3: Messages, Structures, and Macros" for

version 3.1.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrInp


Detecting Logoff from a Service

PSS ID Number: Q104122

Authored 07-Sep-1993	Last modified 21-Feb-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.1 and 3.5

Sometimes it is handy for a service to know whether or not a user is logged

on to the system. For example, suppose that there are circumstances under

which the service displays a dialog box and waits for the user to respond.

If this is done while the user is logged off, the service is blocked until

the user logs on again.

Unfortunately, there is no direct way for a service to detect whether or

not a user is logged on. There is, however, an indirect method. If you

supply MB_DEFAULT_DESKTOP_ONLY as one of the flags in the fuStyle parameter

of MessageBox(), the function will fail if no one is logged on or if a

screen saver is running.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseService


Detecting the Presence of NetBIOS in Win32s

PSS ID Number: Q110844

Authored 31-Jan-1994	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32s versions 1.1 and 1.2

The way to determine whether NetBIOS is present from a Win32 application

running on Win32s is to issue an invalid NetBIOS command (such as 0xB2) and

check that the return code is 0x3 (Illegal command).

Additional reference words: 1.10 1.20

KBCategory: kbprg

KBSubcategory: W32s


Detecting Windows NT from an MS-DOS-Based Application

PSS ID Number: Q100290

Authored 17-Jun-1993	Last modified 06-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1 and 3.5

SUMMARY

There are calls that MS-DOS-based applications can make that are not

supported under Windows NT. For example, calling Interrupt 25h to read the

disk is not supported under Windows NT. Therefore, in some cases MS-DOS-

based applications will need to know whether or not they are running under

Windows NT.

Interrupt 21h, function 3306h can be used by MS-DOS-based applications to

detect whether or not they are running under Windows NT. On return,

registers BL and BH will contain the operating system major and minor

numbers, respectively. If your application is running under Windows NT, the

return will be:

   BL = 5

   BH = 50

MORE INFORMATION

Note that it is important to check both BL and BH, because MS-DOS 5.0 will

also return a 5 in BL.

The following code demonstrates how to detect the operating system version

from an MS-DOS-based application:

Sample Code

-----------

#include <stdio.h>

#include <stdlib.h>

#include <io.h>

void main()

{

   unsigned char cbh = 0;

   unsigned char cbl = 0;

   _asm {

      mov ax, 3306h

      int 21h

      mov cbh, bh

      mov cbl, bl

   }

   printf( "After int 21h\n" );

   printf( "%u, %u (bh, bl)\n", cbh, cbl );

}

Additional reference words: 3.10 3.50 determine

KBCategory: kbprg

KBSubcategory: SubSys


Detecting x86 Floating Point Coprocessor in Win32

PSS ID Number: Q124207

Authored 21-Dec-1994	Last modified 18-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

In Windows NT (x86) and Windows 95, floating point is emulated by the

operating system, in the event that a numeric coprocessor is not present.

This allows Win32-based applications to be compiled with floating point

instructions present, which will be trapped by the operating system at

runtime in the event that a coprocessor is not present. This behavior is

transparent to the application, so it is difficult to detect.

In some cases, it is useful to execute code based on the presence of a

numeric coprocessor, so this article explains how to do it.

MORE INFORMATION

One approach you can use to detect whether a coprocessor is present is to

read the CR0 (System Control Register). This is not possible from Ring 3

application code under Windows NT, so a different approach is outlined

below.

To determine whether a coprocessor is present on a computer using the x86

platform running Windows NT, you need to determine if the registry entry

HKEY_LOCAL_MACHINE\\HARDWARE\\DESCRIPTION\\System\\FloatingPointProcessor

is present. If this key is present, a numeric coprocessor is present.

On the MIPS and Alpha platforms, this registry key is not present because

floating point support is built-in. The following function indicates

whether a numeric coprocessor is present on Windows NT. If the function

returns TRUE, a coprocessor is present. If the function returns FALSE, and

GetLastError() indicates ERROR_RESOURCE_DATA_NOT_FOUND, a coprocessor is

not present.  Otherwise, an error occured while attempting to detect for a

coprocessor. Some error checking is omitted, for brevity.

BOOL IsCoProcessorPresent(void)

{

    #define MY_ERROR_WRONG_OS 0x20000000

    HKEY hKey;

    SYSTEM_INFO SystemInfo;

    // return FALSE if we are not running under Windows NT

    // this should be expanded to cover alternative Win32 platforms

    if(!(GetVersion() & 0x7FFFFFFF))

    {

        SetLastError(MY_ERROR_WRONG_OS);

        return(FALSE);

    }

    // we return TRUE if we're not running on x86

    // other CPUs have built in floating-point, with no registry entry

    GetSystemInfo(&SystemInfo);

    if((SystemInfo.dwProcessorType != PROCESSOR_INTEL_386) &&

       (SystemInfo.dwProcessorType != PROCESSOR_INTEL_486) &&

       (SystemInfo.dwProcessorType != PROCESSOR_INTEL_PENTIUM))

    {

        return(TRUE);

    }

    if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,

"HARDWARE\\DESCRIPTION\\System\\FloatingPointProcessor",

                    0,

                    KEY_EXECUTE,

                    &hKey) != ERROR_SUCCESS)

    {

        // GetLastError() will indicate ERROR_RESOURCE_DATA_NOT_FOUND

        // if we can't find the key.  This indicates no coprocessor present

        return(FALSE);

    }

    RegCloseKey(hKey);

    return(TRUE);

}

Additional reference words: 3.10 3.50 4.00

KBCategory: kbprg kbcode

KBSubcategory: BseFltpt


Determining Available RGB Values of an Output Device

PSS ID Number: Q27225

Authored 03-Mar-1988	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

The best way to determine the colors supported by a device is to

enumerate the solid pens from a device context (DC) associated with

that device. The EnumObjects function enumerates the pens supported by

a specified device and calls a callback function for each pen. To do

so, EnumObjects requires three parameters: a device context associated

with the desired device as the hDC parameter, OBJ_PEN as the value of

the nOjbectType parameter, and the procedure-instance address of a

callback function as the lpObjectFunc parameter.

MORE INFORMATION

The first parameter for the callback function, lpLogObject, points to

a LOGPEN data structure that describes each enumerated pen. When the

lopnStyle field of the LOGPEN structure contains the PS_SOLID value,

the application can retrieve and store the value of the lopnColor

field.

NOTE: For true color devices (devices that support more than 8 bits-

per-pixel of color resolution), Windows enumerates only a subset of

the supported pens. These devices support almost any color.

The following code demonstrates the process described above:

int cMaxRGB, nCnt, nSolid; // Global variables for system RGB colors

void GetColorList(HWND hWnd)

{

   HDC hdc;

   FARPROC lpProcCallback;

   HANDLE hmem;

   BYTE FAR *lpmem;

   nCnt = nSolid = 0;

   hdc = GetDC(hWnd);

   cMaxRGB = GetDeviceCaps(hdc, NUMCOLORS);

   if (cMaxRGB >= 0x7FFF)

      return; // All colors available. Enumeration not required.

   lpProcCallback = MakeProcInstance(Callback, hInst);

   // Allocate space for color table

   hmem = GlobalAlloc(GHND, sizeof(COLORREF) * cMaxRGB);

   lpmem = GlobalLock(hmem);

   EnumObjects(hdc, OBJ_PEN, lpProcCallback, lpmem);

   FreeProcInstance(lpProcCallback);

   // Use the color table stored in the first nSolid entries of a

   // COLORREF array stored in lpmem.

   GlobalUnlock(hmem);

   GlobalFree(hmem);

   ReleaseDC(hWnd, hdc);

   return;

}

The source for the enumeration callback function is below. The

callback function must be listed in the EXPORTS section of the module

definition (DEF) file.

int FAR PASCAL Callback(LPLOGPEN lpLogPen, LPSTR lpData)

{

   nCnt++;

   if (lpLogPen->lopnStyle == PS_SOLID) // solid pen

      {

      COLORREF FAR *lpDest = (COLORREF FAR *)lpData + nSolid++;

      *lpDest = lpLogPen->lopnColor; // remember the solid color

      }

   if (nCnt >= cMaxRGB)

      return 0;

   return 1;

}

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: GdiPal


Determining Selected Items in a Multiselection List Box

PSS ID Number: Q71759

Authored 01-May-1991	Last modified 16-May-1995

-

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK), versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

-

To obtain the indexes of all the selected items in a multiselection list

box, the LB_GETSELITEMS message should be sent to the list box.

The message LB_GETCURSEL cannot be used for this purpose because it is

designed for use in single-selection list boxes.

Another approach is to send one LB_GETSEL message for every item of the

multiselection list box to get its selection state. If the item is

selected, LB_GETSEL returns a positive number. The indexes can be built

into an array of selected items.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: UsrCtl


Determining System Version from a Win32-based Application

PSS ID Number: Q92395

Authored 04-Nov-1992	Last modified 12-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.1, 3.5,

   3.51, and 4.0

 - Microsoft Win32s, versions 1.2, 1.25a, and 1.3

SUMMARY

In order to create a Win32-based application that takes advantage of the

features of each platform, it is necessary to determine the operating

system on which the application is currently running.

You can use GetVersion() or GetVersionEx() to determine what operating

system and version your application is running under. NOTE: GetVersion() is

supported on Windows 3.1, but GetVersionEx() is new to the Win32 API. A

Win32-based application might be running under MS-DOS/Windows using the

Win32s extension, Windows NT Workstation, Windows NT Server, or Windows 95.

MORE INFORMATION

According to the documentation, the return value of GetVersion() is a DWORD

that specifies the major and minor version numbers. GetVersionEx() uses

members of the OSVERSIONINFO structure (dwMajorVersion and dwMinorVersion).

The following table shows the return values from GetVersion() under various

environments:

+------------------------------------------------------------------+

|  Environment    |  LOWORD                | HIWORD                |

+==================================================================+

|  Win32s on      |  Windows version 3.1   | RESERVED *            |

|  Windows 3.1    |                        |                       |

+------------------------------------------------------------------+

|  Windows NT 3.x |  Windows version       | RESERVED **           |

|                 |                        |                       |

+------------------------------------------------------------------+

|  Windows 95     |  Windows version 4.0   | RESERVED ***          |

|                 |                        |                       |

+------------------------------------------------------------------+

  * The highest bit is 1. The remaining bits specify build number.

    Note that the version of MS-DOS cannot be determined as it can under

    Windows 3.x.

 ** The highest bit is 0. The remaining bits specify build number.

*** The highest bit is 1. The remaining bits are reserved.

The following sample code can be used to test the values returned by

GetVersion().

Sample Code 1

-------------

#include <windows.h>

void main()

{

   DWORD dwVersion;

   char szVersion[80];

   dwVersion = GetVersion();

   if (dwVersion < 0x80000000) {

   // Windows NT

       wsprintf (szVersion, "Microsoft Windows NT %u.%u (Build: %u)",

                (DWORD)(LOBYTE(LOWORD(dwVersion))),

                (DWORD)(HIBYTE(LOWORD(dwVersion))),

                (DWORD)(HIWORD(dwVersion)));

   }

   else if (LOBYTE(LOWORD(dwVersion))<4) {

   // Win32s

       wsprintf (szVersion, "Microsoft Win32s %u.%u (Build: %u)",

                (DWORD)(LOBYTE(LOWORD(dwVersion))),

                (DWORD)(HIBYTE(LOWORD(dwVersion))),

                (DWORD)(HIWORD(dwVersion) & ~0x8000));

   } else {

   // Windows 95

       wsprintf (szVersion, "Microsoft Windows 95 %u.%u (Build: %u)",

                (DWORD)(LOBYTE(LOWORD(dwVersion))),

                (DWORD)(HIBYTE(LOWORD(dwVersion))),

                (DWORD)(HIWORD(dwVersion) & ~0x8000));

   }

   MessageBox( NULL, szVersion, "Version Check", MB_OK );

}

The following sample code can be used to test the values returned by

GetVersionEx(). NOTE: The actual build number is derived by masking

dwBuildNumber with 0xFFFF.

Sample Code 2

-------------

{

   OSVERSIONINFO osvi;

   char  szVersion [80];

   memset(&osvi, 0, sizeof(OSVERSIONINFO));

   osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);

   GetVersionEx (&osvi);

   if (osvi.dwPlatformId == VER_PLATFORM_WIN32s)

      wsprintf (szVersion, "Microsoft Win32s %d.%d (Build %d)",

                osvi.dwMajorVersion,

                osvi.dwMinorVersion,

                osvi.dwBuildNumber & 0xFFFF);

   else if (osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)

      wsprintf (szVersion, "Microsoft Windows 95 %d.%d (Build %d)",

                osvi.dwMajorVersion,

                osvi.dwMinorVersion,

                osvi.dwBuildNumber & 0xFFFF);

   else if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)

      wsprintf (szVersion, "Microsoft Windows NT %d.%d (Build %d)",

                osvi.dwMajorVersion,

                osvi.dwMinorVersion,

                osvi.dwBuildNumber & 0xFFFF);

   MessageBox( NULL, szVersion, "Version Check", MB_OK );

}

In order to distinguish between Windows NT Workstation and Windows NT

Server, use the registry API to query the following:

   \HKEY_LOCAL_MACHINE\SYSTEM

   \CurrentControlSet

   \Control

   \ProductOptions

The result will be one of the following:

   WINNT      Windows NT Workstation is running.

   SERVERNT   Windows NT Server (3.5 or later) is running.

   LANMANNT   Windows NT Advanced Server (3.1) is running.

Additional reference words: 1.20 1.30 3.10 3.50 4.00 detect

KBCategory: kbprg

KBSubcategory: BseMisc


Determining the Maximum Allowed Access for an Object

PSS ID Number: Q115945

Authored 07-Jun-1994	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   versions 3.1 and 3.5

SUMMARY

The AccessCheck() API call can be used to determine the maximum access to

an object allowed for a subject. (In this article, a subject means a

program running in a specific user's security context.) When using

AccessCheck() for this purpose, perform the following steps:

1. Obtain a security descriptor that has owner, group, and DACL

   information.

2. If you are not impersonating a client, obtain an impersonation token by

   calling ImpersonateSelf. This token is passed as the client token in the

   AccessCheck() call.

3. Create a generic mapping structure. The contents of this structure will

   vary depending on the object being used.

4. Call AccessCheck() and request "MAXIMUM_ALLOWED" as the desired access.

If the AccessCheck() call succeeds after the above steps have been

completed, the dwGrantedAccess parameter to AccessCheck() contains a

mask of the object-specific rights that are granted by the security

descriptor.

MORE INFORMATION

In most situations, you should not use this method of access determination.

If you need access to an object to perform a task, simply try to open the

object using the required access.

The AccessCheck() API is mainly intended for use with private objects

created by an application. However, it can be used with predefined objects.

The generic mapping values and specific rights for many of the predefined

objects (files and so forth) may be found in WINNT.H.

REFERENCES

Please see the Security Overview in the "Win32 Programmer's Reference" and

the "Win32 SDK API Reference" for more information.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseSecurity


Determining the Network Protocol Used By Named Pipes

PSS ID Number: Q126766

Authored 01-Mar-1995	Last modified 03-Mar-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), version 3.5

This article discusses how to determine or set the network protocol used by

named pipes.

Named pipes are implemented using the server message block (SMB) redirector

and server. As such, they can use whatever protocols are bound into the

server and the client.

Both the redirector and the server maintain independent lists of transports

that they are active on. The redirector contacts the remote server. The

redirector will use the highest priority transport that both the client and

the server support.

The priority for the transports is set using the Network control panel

applet. Go into the Bindings button, select Workstation, and use the up and

down buttons to rearrange the order that the redirector will use while

trying to connect to the remote server.

Additional reference words: 3.50

KBCategory: kbprg

KBSubcategory: BseIpc


Determining the Number of Visible Items in a List Box

PSS ID Number: Q78952

Authored 05-Dec-1991	Last modified 16-May-1995

-

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK), versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

-

SUMMARY

To determine the number of items that are currently visible in a list

box, an application must consider the following cases:

1. There are many items in the list box (some items are not visible).

2. There are few items in the list box (the bottom area of the list

   box is empty).

3. The heights of the items may vary (an owner-draw list box or use of

   a font other than the system default).

MORE INFORMATION

The following code segment can be used to determine the number of

items visible in a list box:

Sample Code

-----------

int ntop, nCount, nRectheight, nVisibleItems;

RECT rc;

ntop = SendMessage(hwndList, LB_GETTOPINDEX, 0, 0);

                               // Top item index.

nCount = SendMessage(hwndList, LB_GETCOUNT, 0, 0);

                               // Number of total items.

GetClientRect(hwndList, &rc);

                               // Get list box rectangle.

nRectheight = rc.bottom - rc.top;

                               // Compute list box height.

nVisibleItems = 0;             // Initialize counter.

while ((nRectheight > 0) && (ntop < nCount))

                        // Loop until the bottom of the list box

                        // or the last item has been reached.

   {

   SendMessage(hwndList, LB_GETITEMRECT, ntop, (DWORD)(&itemrect));

                               // Get current line's rectangle.

   nRectheight = nRectheight - (itemrect.bottom - itemrect.top);

                               // Subtract current line height.

   nVisibleItems++;            // Increase item count.

   ntop++;                     // Move to the next line.

   }

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: UsrCtl


Determining the Topmost Pop-Up Window

PSS ID Number: Q66943

Authored 14-Nov-1990	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

When an application has many pop-up child windows (with a common parent

window), the GetNextWindow() function can be used when one pop-up window is

closed to determine the next topmost pop-up window that remains.

The following code fragment shows a window procedure for simple pop-up

windows (modified from the PARTY program in Petzold's "Programming

Windows"). In the WM_CLOSE case, the handle received by the pop-up window

procedure is the handle of the pop-up to be closed. This sample activates

the topmost pop-up window that remains by giving it the focus.

long FAR PASCAL PopupWndProc (hWnd, iMessage, wParam, lParam)

     HWND     hWnd;

     unsigned iMessage;

     WORD     wParam;

     LONG     lParam;

     {

     HWND     hWndPopup;

     switch (iMessage)

        {

        case WM_CLOSE:

            hWndPopup = GetNextWindow(hWnd, GW_HWNDNEXT);

            if (hWndPopup)

                SetFocus(hWndPopup);

            break;

        }

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

     }

NOTE: In Windows 3.1, two messages are sent to an application when its Z-

order is changing: WM_WINDOWPOSCHANGING and WM_WINDOWPOSCHANGED. When a

window is closed (as in the example shown above) these two message will be

sent to all window procedures.

For additional information on changing the Z-order of an MDI window, query

on the following words in the Microsoft Knowledge Base:

   WM_WINDOWPOSCHANGED and MDICREATESTRUCT and WS_EX_TOPMOST

Additional reference word: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrWndw


Determining the Visible Area of a Multiline Edit Control

PSS ID Number: Q88387

Authored 24-Aug-1992	Last modified 27-Jun-1995

-

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK), versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

-

SUMMARY

The multiline edit control provided with Microsoft Windows versions

3.0 and 3.1 does not provide a mechanism that allows an application to

determine the currently visible lines of text. This article outlines

an algorithm to provide that functionality.

MORE INFORMATION

The general idea is to determine the first and last visible lines and

obtain the text of those lines from the edit control. The following

steps detail this process:

1. A Windows-3.1-based application can use the newly available

   message, EM_GETFIRSTVISIBLELINE, to determine the topmost visible

   line.

   A Windows-3.0-based application can use a technique described in the

   following Microsoft Knowledge Base article to determine the line

   number of the first visible line:

      ARTICLE-ID: Q68572

      TITLE     : Caret Position & Line Numbers in Multiline Edit Controls

2. Obtain the edit control's formatting rectangle using EM_GETRECT.

   Determine the rectangle's height using this formula:

      nFmtRectHeight = rect.bottom - rect.top;

3. Obtain the line spacing of the font used by the edit control to

   display the text. Use the WM_GETFONT message to determine the font

   used by the edit control. Select this font into a display context

   and use the GetTextMetrics function. The tmHeight field of the

   resulting TEXTMETRIC structure is the line spacing.

4. Divide the formatting rectangle's height (step 2) with the line

   spacing (step 3) to determine the number of lines. Compute the line

   number of the last visible line based on the first visible line

   (step 1) and the number of visible lines.

5. Use EM_GETLINE for each line number from the first visible line to

   the last visible line to determine the visible lines of text.

   Remember that the last visible line may not necessarily be at the

   bottom of the edit control (the control may only be half full). To

   detect this case, use EM_GETLINECOUNT to know the last line and

   compare its number with the last visible line. If the last line

   number is less than the last visible line, your application should

   use EM_GETLINE only on lines between the first and the last line.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: UsrCtl


Determining Visible Window Area When Windows Overlap

PSS ID Number: Q75236

Authored 15-Aug-1991	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

There is no Windows API that reports the portion of an application's

window that is not obscured by other windows. To determine which areas

of the window are covered, it is necessary to walk through the window

list managed by Windows.

Each window that precedes the application's window is "above" that

window on the screen. Using the IntersectRect() function, check the

rectangle of the window with any windows above to see if they

intersect. Any window that is above the application's window and

intersects its window rectangle obscures part of the application's

window. By accumulating the positions of all windows that overlap the

application's window, it is possible to determine which areas of the

window are covered and which are not.

MORE INFORMATION

The following sample code demonstrates this procedure:

  GetWindowRect(hWnd, &rMyRect);    /*  Get the window dimensions

                                     *  for the current window.

                                     */

      /*  Start from the current window and use the GetWindow()

       *  function to move through the previous window handles.

       */

  for (hPrevWnd = hWnd;

      (hNextWnd = GetWindow(hPrevWnd, GW_HWNDPREV)) != NULL;

       hPrevWnd = hNextWnd)

    {

      /*  Get the window rectangle dimensions of the window that

       *  is higher Z-Order than the application's window.

       */

    GetWindowRect(hNextWnd, &rOtherRect);

      /*  Check to see if this window is visible and if intersects

       *  with the rectangle of the application's window. If it does,

       *  call MessageBeep(). This intersection is an area of this

       *  application's window that is not visible.

       */

    if (IsWindowVisible(hNextWnd) &&

           IntersectRect(&rDestRect, &rMyRect, &rOtherRect))

      {

      MessageBeep(0);

      }

    }

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrWndw


Determining Whether a WOW App is Running in Enhanced Mode

PSS ID Number: Q101893

Authored 26-Jul-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

SUMMARY

Windows NT and Windows NT Advanced Server will run a Windows 3.1

application in 386 enhanced mode on X86 machines (standard mode on RISC

machines). The proper way to determine whether a Windows 3.1 application is

in enhanced mode is to call GetWinFlags() and do a bit test for

WF_ENHANCED. This method is described on pages 486-487 in the Windows 3.1

Software Development Kit (SDK) "Programmer's Reference, Volume 2:

Functions."

MORE INFORMATION

Calling Interrupt 2F with AX=1600h

----------------------------------

This method, which is described in the Windows 3.1 Device Development Kit

(DDK) checks to see whether a 386 memory manager is running. If Windows 3.1

is running in enhanced mode, it returns AL = 3 and 2 for standard mode.

Windows NT's WOW (Windows 16 on Windows NT) returns AL=0, which means

enhanced mode Windows is not running.

DWORD GetWinFlags()

-------------------

The GetWinFlags() function retrieves the current Windows system and

memory configuration.

The configuration returned by GetWinFlags() can be a combination of the

following values:

   Value          Meaning

   ----------------------------------------------------------------

   WF_80x87       System contains an Intel math coprocessor.

   WF_CPU286      System CPU is an 80286.

   WF_CPU386      System CPU is an 80386.

   WF_CPU486      System CPU is an i486.

   WF_ENHANCED    Windows is running in 386-enhanced mode. The WF_PMODE

                  flag is always set when WF_ENHANCED is set.

   WF_PAGING      Windows is running on a system with paged memory.

   WF_PMODE       Windows is running in protected mode. In Windows 3.1,

                  this flag is always set.

   WF_STANDARD    Windows is running in standard mode. The WF_PMODE

                  flag is always set when WF_STANDARD is set.

   WF_WIN286      Same as WF_STANDARD.

   WF_WIN386      Same as WF_ENHANCED.

NOTE: When running in Windows NT, WF_WINNT will also be returned to tell

the 16-bit Windows-based application that you are running in Windows NT.

Example:

The following example uses the GetWinFlags() function to display

information about the current Windows system configuration:

Sample Code

-----------

int len;

char szBuf[80];

DWORD dwFlags;

dwFlags = GetWinFlags();

len = sprintf(szBuf, "system %s a coprocessor",

    (dwFlags & WF_80x87) ? "contains" : "does not contain");

TextOut(hdc, 10, 15, szBuf, len);

len = sprintf(szBuf, "processor is an %s",

    (dwFlags & WF_CPU286) ? "80286" :

    (dwFlags & WF_CPU386) ? "80386" :

    (dwFlags & WF_CPU486) ? "i486" : "unknown");

TextOut(hdc, 10, 30, szBuf, len);

len = sprintf(szBuf, "running in %s mode",

    (dwFlags & WF_ENHANCED) ? "enhanced" : "standard");

TextOut(hdc, 10, 45, szBuf, len);

len = sprintf(szBuf, "%s WLO",

    (dwFlags & WF_WLO) ? "using" : "not using");

TextOut(hdc, 10, 60, szBuf, len);

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: SubSys


Determining Whether an Application is Console or GUI

PSS ID Number: Q90493

Authored 15-Oct-1992	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

In order to determine whether an application is console or GUI, you must

parse the EXEheader. The header contains a field called 'Subsystem'. This

field determines both the subsystem the application is to run under and the

type of interface it requires. The values consist of:

   IMAGE_SUBSYSTEM_NATIVE               1

   IMAGE_SUBSYSTEM_WINDOWS_GUI          2

   IMAGE_SUBSYSTEM_WINDOWS_CUI          3

   IMAGE_SUBSYSTEM_OS2_CUI              5

   IMAGE_SUBSYSTEM_POSIX_CUI            7

MORE INFORMATION

Sample Code

-----------

#include <windows.h>

#include <winnt.h>

VOID  main(int, char **);

DWORD AbsoluteSeek(HANDLE, DWORD);

VOID  ReadBytes(HANDLE, LPVOID, DWORD);

VOID  WriteBytes(HANDLE, LPVOID, DWORD);

VOID  CopySection(HANDLE, HANDLE, DWORD);

#define XFER_BUFFER_SIZE 2048

VOID

main(int argc, char *argv[])

{

    HANDLE hImage;

    DWORD  bytes;

    DWORD  iSection;

    DWORD  SectionOffset;

    DWORD  CoffHeaderOffset;

    DWORD  MoreDosHeader[16];

    ULONG  ntSignature;

    IMAGE_DOS_HEADER      image_dos_header;

    IMAGE_FILE_HEADER     image_file_header;

    IMAGE_OPTIONAL_HEADER image_optional_header;

    IMAGE_SECTION_HEADER  image_section_header;

    if (argc != 2)

    {

        printf("USAGE: %s program_file_name\n", argv[1]);

        exit(1);

    }

    /*

     *  Open the reference file.

     */

    hImage = CreateFile(argv[1],

                        GENERIC_READ,

                        FILE_SHARE_READ,

                        NULL,

                        OPEN_EXISTING,

                        FILE_ATTRIBUTE_NORMAL,

                        NULL);

    if (INVALID_HANDLE_VALUE == hImage)

    {

        printf("Could not open %s, error %lu\n", argv[1], GetLastError());

        exit(1);

    }

    /*

     *  Read the MS-DOS image header.

     */

    ReadBytes(hImage,

              &image_dos_header,

              sizeof(IMAGE_DOS_HEADER));

    if (IMAGE_DOS_SIGNATURE != image_dos_header.e_magic)

    {

        printf("Sorry, I do not understand this file.\n");

        exit(1);

    }

    /*

     *  Read more MS-DOS header.       */

    ReadBytes(hImage,

              MoreDosHeader,

              sizeof(MoreDosHeader));

    /*

     *  Get actual COFF header.

     */

    CoffHeaderOffset = AbsoluteSeek(hImage, image_dos_header.e_lfanew) +

                       sizeof(ULONG);

    ReadBytes (hImage, &ntSignature, sizeof(ULONG));

    if (IMAGE_NT_SIGNATURE != ntSignature)

    {

     printf("Missing NT signature. Unknown file type.\n");

     exit(1);

    }

    SectionOffset = CoffHeaderOffset + IMAGE_SIZEOF_FILE_HEADER +

                    IMAGE_SIZEOF_NT_OPTIONAL_HEADER;

    ReadBytes(hImage,

              &image_file_header,

              IMAGE_SIZEOF_FILE_HEADER);

    /*

     *  Read optional header.

     */

    ReadBytes(hImage,

              &image_optional_header,

              IMAGE_SIZEOF_NT_OPTIONAL_HEADER);

    switch (image_optional_header.Subsystem)

    {

    case IMAGE_SUBSYSTEM_UNKNOWN:

        printf("Type is unknown.\n");

        break;

    case IMAGE_SUBSYSTEM_NATIVE:

        printf("Type is native.\n");

        break;

    case IMAGE_SUBSYSTEM_WINDOWS_GUI:

        printf("Type is Windows GUI.\n");

        break;

    case IMAGE_SUBSYSTEM_WINDOWS_CUI:

        printf("Type is Windows CUI.\n");

        break;

    case IMAGE_SUBSYSTEM_OS2_CUI:

        printf("Type is OS/2 CUI.\n");

        break;

    case IMAGE_SUBSYSTEM_POSIX_CUI:

        printf("Type is POSIX CUI.\n");

        break;

    default:

        printf("Unknown type %u.\n", image_optional_header.Subsystem);

        break;

    }

}

DWORD

AbsoluteSeek(HANDLE hFile,

             DWORD  offset)

{

    DWORD newOffset;

    if ((newOffset = SetFilePointer(hFile,

                                    offset,

                                    NULL,

                                    FILE_BEGIN)) == 0xFFFFFFFF)

    {

        printf("SetFilePointer failed, error %lu.\n", GetLastError());

        exit(1);

    }

    return newOffset;

}

VOID

ReadBytes(HANDLE hFile,

          LPVOID buffer,

          DWORD  size)

{

    DWORD bytes;

    if (!ReadFile(hFile,

                  buffer,

                  size,

                  &bytes,

                  NULL))

    {

        printf("ReadFile failed, error %lu.\n", GetLastError());

        exit(1);

    }

    else if (size != bytes)

    {

        printf("Read the wrong number of bytes, expected %lu, got %lu.\n",

               size, bytes);

        exit(1);

    }

}

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: BseMisc


Determining Whether App Is Running as Service or .EXE

PSS ID Number: Q94994

Authored 28-Jan-1993	Last modified 13-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.1 and 3.5

SUMMARY

When debugging Windows NT services, it may be necessary for the service

application to be run interactively.

In this case, the application may determine whether it is being run as a

service or as an executable (interactively) by checking GetLastError()

after the call to StartServiceCtrlDispatcher() in the application's startup

code.

If the application is being run as an executable, the call to

GetLastError() will return with the following:

   ERROR_FAILED_SERVICE_CONTROLLER_CONNECT

An alternative method is to check the return value from GetConsoleMode().

For example:

   ret = GetConsoleMode (GetStdHandle (STD_OUTPUT_HANDLE), &mode);

Although the std handles may exist, they almost certainly will not be

console handles unless there is a console attached. GetConsoleMode() will

fail (with ERROR_INVALID_HANDLE) for non-console handles.

Sample Code

-----------

// Call StartServiceCtrlDispatcher() to set up the control

// interface. The API won't return until all services have been

// terminated. At that point, we just exit. See the

// StartServiceCtrlDispatcher() entry in Windows Help.

if (!StartServiceCtrlDispatcherW(ElfSvcDispatchTable) &&

   GetLastError() == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) {

   // Set a flag indicating you're running as an .EXE, not a service.

}

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseService


Determining Whether the User is an Administrator

PSS ID Number: Q118626

Authored 25-Jul-1994	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

To determine whether or not a user is an administrator, you need to examine

the user's access token with GetTokenInformation(). The access token

represents the user's privileges and the groups to which the user belongs.

When a user starts an application, the access token associated with that

process is the user's access token. To get the process token (and therefore

the user's token), use OpenProcessToken().

The sample code below uses the APIs mentioned in the previous paragraph to

test whether or not the current user is an administrator on the local

machine:

Sample code

-----------

   /* BOOL IsAdmin(void)

      returns TRUE if user is an admin

              FALSE if user is not an admin

   */

   BOOL IsAdmin(void)

   {

      HANDLE hProcess, hAccessToken;

      UCHAR InfoBuffer[1024];

      PTOKEN_GROUPS ptgGroups = (PTOKEN_GROUPS)InfoBuffer;

      DWORD dwInfoBufferSize;

      PSID psidAdministrators;

      SID_IDENTIFIER_AUTHORITY siaNtAuthority = SECURITY_NT_AUTHORITY;

      UINT x;

      hProcess = GetCurrentProcess();

      if(!OpenProcessToken(hProcess,TOKEN_READ,&hAccessToken))

         return(FALSE);

      if(!GetTokenInformation(hAccessToken,TokenGroups,InfoBuffer,

         1024, &dwInfoBufferSize)) return(FALSE);

      AllocateAndInitializeSid(&siaNtAuthority, 2,

         SECURITY_BUILTIN_DOMAIN_RID,

         DOMAIN_ALIAS_RID_ADMINS,

         0, 0, 0, 0, 0, 0,

         &psidAdministrators);

      for(x=0;x<ptgGroups->GroupCount;x++)

      {

         if( EqualSid(psidAdministrators, ptgGroups->Groups[x].Sid) )

         {

            FreeSid(&psidAdministrators);

            return( TRUE );

         }

      }

      FreeSid(&psidAdministrators);

      return(FALSE);

   }

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseSecurity


Development Tools Do Not Accept Unicode Text

PSS ID Number: Q106065

Authored 31-Oct-1993	Last modified 24-Mar-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.1 and 3.5

SUMMARY

Neither the Win32 SDK tools or Visual C++ (VC++) 32-bit Edition tools

support Unicode text. In fact, the C/C++ Language specification says that

the source files are to be written in 7-bit ANSI.

MORE INFORMATION

For example, language-specific resources cannot be specified in Unicode in

the .RC file because RC does not accept the Unicode text. Although the

message compiler has flags for Unicode, the flags are not implemented.

To convert to and from Unicode text, use the UCONVERT utility included in

your MSTOOLS\BIN directory. The source for UCONVERT in the 3.1 SDK is in

MSTOOLS\SAMPLES\SDKTOOLS\UCONVERT. The source for UCONVERT in the 3.5 SDK

is in MSTOOLS\SAMPLES\SDKTOOLS\WINNT\UCONVERT.

The long term solution that Microsoft is working on are Resource

Localization Tools and other methods that will allow the user to localize

the strings in a GUI editor, running on the target machine.

Note that it is possible to specify Unicode escapes in L-quoted strings.

The following is quoted from "Common Statement Parameters" in RC.HLP:

   By default, the characters listed between the double quotation

   marks are ANSI characters and escape sequences are interpreted as

   byte escape sequences. If the string is preceded by the L prefix,

   the string is a wide-character string and escape sequences are

   interpreted as two-byte escape sequences that specify Unicode

   characters. If a double quotation mark is required in the text, you

   must include the double quotation mark twice or use the \" escape

   sequence.

Another alternative is to use user-defined resources and include a binary

(Unicode) file.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: WIntlDev


DEVMODE and dmSpecVersion

PSS ID Number: Q96282

Authored 14-Mar-1993	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

The dmSpecVersion field of the DEVMODE structure is intended for printer

driver use only; no application programs should test this field. The

purpose of this field is for new printer drivers to be able to recognize

and handle DEVMODE structures created according to previous DEVMODE

structure specification.

MORE INFORMATION

The DEVMODE structure is used for printer and (occasionally) display

drivers when initializing. This structure is tied to the driver--not the

operating system. The dmSpecVersion field does not allow an application to

determine which platform (Windows version 3.1, Windows on Windows, Win32)

the application is running in.

When an application fills a DEVMODE structure, it should set the

dmSpecVersion field to DM_SPECVERSION. This identifies the version of the

DEVMODE structure the application is generating.

If the application is querying to understand an unknown device, then

special attention should be paid to the dmFields, dmSize, and dmDriverExtra

fields. These fields are a reliable means of understanding what fields in

the DEVMODE structure are readable.

The DEVMODE structure consists of public and private parts. The

dmSpecVersion field applies to the public part. Any previously defined

fields are not altered when the DEVMODE specification is updated--more

fields are merely added to the end of the structure. This can mean fields

used in the previous specification are ignored in a later specification.

This functionality is managed by one bitfield describing what fields a

driver actually uses. The new drivers just switch off the obsolete fields.

Applications using DEVMODE should always use the dmSize and dmDriverExtra

fields for allocating/storing/manipulating the structure. These fields

define the sizes of the public and private parts of the structure,

respectively.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: GdiPrn


Dialog Box Frame Styles

PSS ID Number: Q74334

Authored 16-Jul-1991	Last modified 18-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

Dialog boxes can have either the WS_DLGFRAME or the WS_BORDER style. If a

dialog box is created with both of these styles, it will have a caption bar

instead of the expected frame and border. This is because WS_BORDER |

WS_DLGFRAME is equal to WS_CAPTION.

To create a dialog box with a modal dialog frame and a caption, use

DS_MODALFRAME combined with WS_CAPTION.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrDlgs


DIB_PAL_INDICES and CBM_CREATEDIB Not Supported in Win32s

PSS ID Number: Q108497

Authored 13-Dec-1993	Last modified 05-May-1995

The information in this article applies to:

 - Microsoft Win32s versions 1.0, 1.1, and 1.2

 - Microsoft Win32 SDK (Windows 95 only)

The Windows NT implementation of the Win32 application programming

interface (API) includes two new flags, DIB_PAL_INDICES and CBM_CREATEDIB,

that can be used with various device-independent bitmap (DIB) APIs. These

flags are not supported by Windows 3.1, Win32s, or Windows 95.

DIB_PAL_INDICES

---------------

In Windows NT, the DIB_PAL_INDICES flag can be used with the following

APIs:

   CreateDIBitmap()

   CreateDIBPatternBrush()

   CreateDIBPatternBrushPt()

   SetDIBits()

   GetDIBits()

   SetDIBitsToDevice()

   StretchDIBits()

When the dwUsage parameter is DIB_PAL_INDICES, the associated DIB does not

have a color table. In this case, the bitmap bits are indices into the

device palette.

Applications written to run on Windows 3.1 or Win32s should use

DIB_PAL_COLORS or DIB_RGB_COLORS instead of DIB_PAL_INDICES.

Windows 95 does not support DIB_PAL_INDICES.

CBM_CREATEDIB

-------------

In Windows 3.1, CreateDIBitmap() creates a device-dependent bitmap (DDB)

from a DIB definition and optionally initializes the DDB. In Windows NT,

the CBM_CREATEDIB flag can be used with CreateDIBitmap() to create a new

DIB instead of a DDB.

This functionality is not present in Windows 3.1 or Win32s.

Windows 95 does not support CBM_CREATEDIB. Equivalent functionality is

provided in Windows 95 by CreateDIBSection().

Additional reference words: 1.00 1.10 1.20 4.00

KBCategory: kbprg

KBSubcategory: GdiBmp W32s


Differences Between hInstance on Win 3.1 and Windows NT

PSS ID Number: Q103644

Authored 26-Aug-1993	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.1, 3.5,

   3.51, 4.0

SUMMARY

In Microsoft Windows version 3.1, an instance handle can be used to

uniquely identify the instance of an application because instance handles

are unique within the scope of an address space. Because each instance of

an application runs in its own address space on Windows NT, instance

handles cannot be used to uniquely identify an instance of an application

running on the system. This article explains why, and some alternative

calls that might assist in uniquely identifying an application instance on

Windows NT.

MORE INFORMATION

Although the concepts for an instance handle are similar on Windows NT and

Windows 3.1, the results you see regarding them might be very different

from what you expect.

With Windows 3.1, when you start several instances of the same application,

they all share the same address space. You have multiple instances of the

same code segment; however, each of these instances has a unique data

segment associated with it. Using an instance handle (hInstance) is a way

to uniquely identify these different instances and data segments in the

address space.

Instance handles are unique to the address space. On Windows NT, when

looking at the value of the instance handle, or the value returned from

GetWindowLong(hWnd, GWL_HINSTANCE), a developer coming from a Windows 3.1

background might be surprised to see that most of the windows on the

desktop return the same value. This is because the return value is the

hInstance for the instance of the application, which is running it its own

address space. (An interesting side note: The hInstance value is the base

address where the application's module was able to load; either the default

address or the fixed up address.)

On Windows NT, running several instances of the same application causes the

instances to start and run in their own separate address space. To

emphasize the difference: multiple instances of the same application on

Windows 3.1 run in the same address space; in Windows NT, each instance has

its own, separate address space. Using an instance handle to uniquely

identify an application instance, as is possible on Windows 3.1, does not

apply in Windows NT. (Another interesting side note: Remember that even if

there are multiple instances of an application, if they are able to load at

their default virtual address spaces, the virtual address pages of the

different applications' executable code will map to the same physical

memory pages.)

In Windows NT, instance handles are not unique in the global scope of the

system; however, window handles, thread IDs, and process IDs are. Here are

some calls that may assist in alternative methods to uniquely identify

instance of applications on Windows NT:

 - GetWindowThreadProcessID() retrieves the identifier of the thread

   that created the given window and, optionally, the identifier of

   the process that created the window.

 - OpenProcess() returns a handle to a process specified by a process

   ID.

 - GetCurrentProcessID() returns the calling process's ID.

 - EnumThreadWindows() returns all of the windows associated with a

   thread.

 - The FindWindow() function retrieves the handle of the top-level

   window specified by class name and window name.

 - To enumerate all of the processes on the system, you can query the

   Registry using RegQueryValueEx() with key HKEY_PERFORMANCE_DATA,

   and the Registry database index associated with the database string

   "Process".

For further details on using these calls, please see the Win32 SDK help

file.

Additional reference words: 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrMisc


Differences Between the Win32 3.1 SDK and VCNT 1.0

PSS ID Number: Q105679

Authored 22-Oct-1993	Last modified 18-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) version 3.1

 - Microsoft Visual C++ 32-bit Edition, version 1.0

SUMMARY

The following is a list of items included in the retail Win32 SDK that are

not included in the 32-bit Edition of Visual C++ (Intel only):

MORE INFORMATION

Tools

-----

   WinDbg/WinDbgRM

   Process Walker

   Working Set Tuner (WST)

   WinObj

   Setup Toolkit

   Microsoft Test

   Software Compatibility Test (SCT)

   API Profilers: CAP and WAP

   Symedit

   masm386

   Font Editor

Documentation

-------------

   LM API Reference (LMAPI.HLP)

   SNMP Programmer's Reference (SNMP.TXT)

   Generic Thunks (GENTHUNK.TXT)

   File Formats (CUSTCNTL.TXT, ENHMETA.TXT, PE.TXT, RESFMT.TXT)

Samples

-------

   BNDBUF                         MFEDIT

   BOB (named EXITWIN in VC++)    MIDIMON

   CDTEST                         MINREC

   CPL                            MSGTABLE

   DYNDLG                         NTFONTS

   GUIGREP                        NTSD

   LARGEINT                       PDC

   LOGGING                        RESDLL

   LOWPASS                        REVERSE

   MANDEL                         SCRNSAVE

   MAPI                           SEMAPHOR

   MAZELORD                       SPINCUBE

   MCITEST                        WINNET

Other

-----

   Device Driver Kit (DDK) headers and libraries

   Checked build of Windows NT

   RPC Toolkit

   POSIX headers and libraries

   Microsoft Foundation Classes (MFC) 1.0

The following is a list of items included in the 32-bit Edition of

Visual C++ that are not included in the retail Win32 SDK (Intel only):

Tools

-----

   Visual Workbench/AppStudio/Wizards

   bscmake

   Pharlap TNT DOS-Extender

   Spy++

   Source Profiler

   CodeView for Win32S

Samples

-------

   BOUNCE

   CVTMAKE

   EXITWIN (named BOB in the SDK)

Other

-----

   MFC 2.0

The preliminary Win32 SDK contained the compiler tools, while the

retail Win32 SDK does not. In addition, the preliminary Win32 DDK was

available separately, while the retail DDK is bundled with the retail

SDK.

The Win32 SDK has a separate "Win32s Programmer's Reference," while

VC++ has the same chapters as part of the "Programming Techniques"

manual.

There are tools whose names have changed and tools that are no longer

needed. The SDK linker is LINK32, the VC++ linker is LINK. The SDK

librarian is LIB32, the VC++ librarian is LIB. CVTRES existed in the

SDK to convert the .RES file produced by RC so that it could be used

by the linker, while VC++ has this functionality built into its

linker. These changes may affect your makefiles.

For more information on switching from the Win32 SDK to 32-bit VC++,

see the VC++ file MIGRATE.HLP.

Additional reference words: 3.10

KBCategory: kbtool

KBSubcategory: TlsMisc


Differences Between the Win32 3.5 SDK and Visual C++ 2.0

PSS ID Number: Q125474

Authored 29-Jan-1995	Last modified 30-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), version 3.5

 - Microsoft Visual C++ 32-bit Edition, version 2.0

SUMMARY

Microsoft Visual C++ version 2.0 contains the compiler tools, headers, and

libraries necessary to develop Win32-based applications. In addition, it

has an integrated development environment (Microsoft Foundation Classes

(MFC) version 3.0) and Wizards to make programming easier. However, there

is still a separate Win32 SDK available through MSDN Level II.

This article lists the things that are included in the Win32 SDK that

are not included in Visual C++ version 2.0.

MORE INFORMATION

The following is a list of items included in the retail Win32 SDK that are

not included in Visual C++ version 2.0 (Intel only):

Tools

-----

WinDbg/WinDbgRM

Process Walker

Working Set Tuner

Software Compatibility Test

Microsoft Test

API Profilers

POSIX headers and libraries

Help Indexing

masm386

Toolkits

--------

RPC Toolkit (and samples)

Setup Toolkit

Documentation

-------------

SNMP Programmer's Reference (PROGREF.RTF)

Generic Thunks (GENTHUNK.TXT)

Multicast Extensions to Windows Sockets for Win32

Windows Sockets for Appletalk

File Formats (CUSTCNTL.TXT, ENHMETA.HLP, PE.TXT, RESFMT.TXT)

Writing Great 32-bit Applications for Windows

POSIX Conformance Document

Microsoft Windows NT Version 3.5 Hardware Compatibility List

Additional Samples

------------------

Win32:                            Multimedia:

   BNDBUF          NTSD           AVIEDI32           MIXAPP

   CDTEST          RASBERRY       AVIVIEW            MOVPLAY

   CPL             REBOOT         CAPTEST            MPLAY

   DYNDLG          RNR            DSEQFILE           PALMAP

   GLOBCHAT        SD_FLPPY       ICMAPP             REVERSE

   INTEROP         SERVENUM       ICMWALK            TEXTOUT

   IOCOMP          SIMPLEX        LANGPLAY           WAVEFILE

   IPXCHAT         SNMP           MCIPLAY            WRITEAVI

   LARGEINT        SOCKETS        MCIPUZZL

   MANDEL          SPINCUBE

   MSGTABLE        WDBGEXTS

   NETDDE

SDK Tools:

   ANIEDIT         RSHELL

   FONTEDIT        TLIST

   IMAGE           UCONVERT

   IMAGEDIT        WALKER

   NETWATCH        WINAT

   REMOTE

Additional reference words: 2.00 3.50

KBCategory: kbtool

KBSubcategory: TlsMisc


Differentiating Between the Two ENTER Keys

PSS ID Number: Q77550

Authored 20-Oct-1991	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.1 and 3.0

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

An application may find it useful to differentiate between the user

pressing the ENTER key on the standard keyboard and the ENTER key on

the numeric keypad. Either action creates a WM_KEYDOWN message and a

WM_KEYUP message with wParam set to the virtual key code VK_RETURN.

When the application passes these messages to TranslateMessage, the

application receives a WM_CHAR message with wParam set to the

corresponding ASCII code 13.

To differentiate between the two ENTER keys, test bit 24 of lParam

sent with the three messages listed above. Bit 24 is set to 1 if the

key is an extended key; otherwise, bit 24 is set to 0 (zero). The

contents of lParam for these messages is documented in the "Microsoft

Windows Software Development Kit Reference Volume 1" for version 3.0

of the SDK and in the SDK Reference Volume 3, "Messages, Structures,

and Macros."

Because the keys in the numeric keypad (along with the function keys)

are extended keys, pressing ENTER on the numeric keypad results in bit

24 of lParam being set, while pressing the ENTER key on the standard

keyboard results in bit 24 clear.

The following code sample demonstrates differentiating between these

two ENTER keys:

   case WM_KEYDOWN:

      if (wParam == VK_RETURN)    // ENTER pressed

         if (lParam & 0x1000000L) // Test bit 24 of lParam

            {

            // ENTER on numeric keypad

            }

         else

            {

            // ENTER on the standard keyboard

            }

      break;

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg kbcode

KBSubcategory: UsrInp


Direct Drive Access Under Win32

PSS ID Number: Q100027

Authored 14-Jun-1993	Last modified 21-Feb-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   versions 3.1 and 3.5

SUMMARY

To open a physical hard drive for direct disk access (raw I/O) in a

Win32-based application, use a device name of the form

   \\.\PhysicalDriveN

where N is 0, 1, 2, and so forth, representing each of the physical drives

in the system.

To open a logical drive, direct access is of the form

   \\.\X:

where X: is a hard-drive partition letter, floppy disk drive, or CD-ROM

drive.

MORE INFORMATION

You can open a physical or logical drive using the CreateFile() application

programming interface (API) with these device names provided that you have

the appropriate access rights to the drive (that is, you must be an

administrator). You must use both the CreateFile() FILE_SHARE_READ and

FILE_SHARE_WRITE flags to gain access to the drive.

Once the logical or physical drive has been opened, you can then perform

direct I/O to the data on the entire drive. When performing direct disk

I/O, you must seek, read, and write in multiples of sector sizes of the

device and on sector boundaries. Call DeviceIoControl() using

IOCTL_DISK_GET_DRIVE_GEOMETRY to get the bytes per sector, number of

sectors, sectors per track, and so forth, so that you can compute the size

of the buffer that you will need.

Note that a Win32-based application cannot open a file by using internal

Windows NT object names; for example, attempting to open a CD-ROM drive by

opening

   \Device\CdRom0

does not work because this is not a valid Win32 device name. An application

can use the QueryDosDevice() API to get a list of all valid Win32 device

names and see the mapping between a particular Win32 device name and an

internal Windows NT object name. An application running at a sufficient

privilege level can define, redefine, or delete Win32 device mappings by

calling the DefineDosDevice() API.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseFileio


Disabling the Mnemonic on a Disabled Static Text Control

PSS ID Number: Q66946

Authored 14-Nov-1990	Last modified 18-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

Disabling a static text control that contains a mnemonic does not prevent

the control from responding to that key. For more information on static

text controls with mnemonics, query in this Knowledge Base on the word

"mnemonic".

To keep a static text control from processing mnemonics, it must be

subclassed. When the control is disabled, WM_GETTEXT messages must be

intercepted and the subclass procedure should return an empty string in

response to the message.

MORE INFORMATION

When a static text control with a mnemonic is disabled using

EnableWindow(), it turns gray but it does not stop responding to the

mnemonic. This can cause problems because Windows processes the

mnemonic by setting the focus to the next nonstatic, enabled control.

It is necessary to resort to subclassing to prevent the static control

from processing the mnemonic. The subclass procedure should process

the WM_GETTEXT message as follows:

    ...

    // Windows asks the control, hChild, for its text.

    case WM_GETTEXT:

        if (!IsWindowEnabled(hChild))

            {

            *(LPSTR)(lParam) = 0;    // A null terminated empty string

            return 0L;

            }

        break;

    ....

When the ALT key is held down and a key is pressed, Windows scans the text

of each control to see if the key corresponds to a mnemonic. A WM_GETTEXT

message is sent to each control. Normally, the control processes this

message by returning its text. By returning an empty string in response to

this message, Windows does not find the mnemonic.

Because the mnemonic must work when the control is enabled, the

IsWindowEnabled() function is used to determine the state of the control.

If it is enabled, default processing occurs. Otherwise, the control is

disabled and no text is returned, effectively disabling the mnemonic.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrCtl


Displaying on the Screen What Will Print

PSS ID Number: Q22553

Authored 09-Oct-1987	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

It is possible for an application to closely simulate on the screen

how an block of text will appear when printed. This article provides

some references and techniques to accomplish this goal.

NOTE: WYSIWYG functionality can be attained in Windows 3.1 by using

TrueType fonts. The following information should be used with non-TrueType

fonts.

MORE INFORMATION

To create a what-you-see-is-what-you-get (WYSIWYG) screen image, the

application must combine the services of the Windows graphics device

interface (GDI), the printer, the display, and fonts. The following

three references provide information that may be helpful:

1. "Pocket Pal -- A Graphic Arts Production Handbook" from

   International Paper Company; discusses issues related to type and

   typesetting.

2. "Bookmaking" by Marsha Lee; discusses issues related specifically

   to making books.

3. "Phototypesetting, A Design Manual" by James Craig.

These books contain information about type, fonts, and stringing

characters together to make text. The following are three points to

remember:

1. Printer manufacturers produce excellent fonts on their printers.

   Use printer fonts as much as possible.

2. GDI must provide some fonts for use with font-deficient display

   drivers.

3. Displays (even high-end ones) have much lower resolution than

   printers.

The best displays attached to microcomputers are approximately 120

dots-per-inch (dpi), while the typical laser printer is 300 dpi. To

produce the same size image (for example, a 9-point capital A), the

printer will illuminate/paint more of its pixels than will the screen.

In particular, the printer will more closely match the requested size

than the display. This leads to integer round-off errors.

Most graphics output devices are raster devices. Due to integer

round-off errors associated with sampling the ideal "A" for different

device resolutions, the origin of characters and words and the ends of

lines on the display will seldom be the same as on a printer. For

example, using a 75-dpi display and 300-dpi printer, the display might

choose a 6 pixel-width for the character "A", while the printer might

choose a 25 or 23 pixel-width for that same character. This mismatch

necessitates adjusting the text on the display to match the output on

the printer.

GDI provides various approaches to find the information needed to

perform the adjustments. The following applications perform this task

with increasing sophistication:

1. Windows Notepad application (does a less-than-ideal job)

2. Windows Write application (does better; however, the point at which

   various screen lines word wrap with different fonts is jagged)

3. Word for Windows (does an excellent job of handling text)

The first two applications are included with the Windows operating

environment.

When Windows starts up, GDI asks each device whether it can support

any fonts. For devices that provide some intrinsic (driver-based)

fonts, GDI enumerates the available fonts and creates a table that

describes them. When an application requests a font from GDI (using

the CreateFont and SelectObject functions), GDI selects the font in

its table that most closely matches the requested font. If no device

font matches well, GDI will attempt to use one of its own fonts.

Ideally, the requested font will be available for all devices. More

realistically, GDI provides a similar font, within the limits of the

device capabilities.

The best way to imitate the appearance of printer fonts on a display

is to assume that the printer has more fonts and greater resolution

than the display. The following nine steps describe one way to

implement a WYSIWYG display:

1. Open a device context (DC) and enumerate the fonts available on the

   printer. Use information from the GetDeviceCaps function with the

   TEXTCAPS parameter to determine how the device can alter the

   appearance of the fonts it provides. Together, the EnumFonts and

   GetDeviceCaps functions will allow the application to determine

   which fonts the device and GDI can provide. The text capabilities

   of the device serve as a filter in the enumeration process.

2. Provide a user interface in the application to allow the user to

   choose one of the fonts (this will result in "printer-centered

   WYSIWYG"). If appropriate, provide a method to choose between sizes

   and other attributes (bold, italic, and so forth). Fonts are most

   commonly selected by point size. One point equals 1/72 of an inch.

   Enumerating fonts returns LOGFONT and TEXTMETRIC structures. The

   quantities in these structures are in logical units that depend on

   the current mapping mode. Assuming that MM_TEXT (the default

   mapping mode) is selected, one logical unit equals one device unit

   (pixel, or pel). Font height and internal leading define the point

   size of the font as follows:

                   72 * (tmHeight - tmInternalLeading)

      point_size = -----------------------------------

                      GetDeviceCaps(hDC, LOGPIXELSY)

3. Create a LOGFONT structure for the selected font. To ensure

   successful selection of that font into the printer DC, the

   lfHeight, lfWeight, and lfFacename fields must be specified. Weight

   and face name can be copied directly from the LOGFONT structure

   that was returned during the enumeration. The height should be

   computed using the following formula:

      lfHeight = -(point_size * GetDeviceCaps(hDC, LOGPIXELSY) / 72)

   In normal situations, set lfWidth to zero.

4. Once a font has been chosen, select it into the printer DC. Use

   GetTextMetrics and GetTextFace to verify the selection. If the

   steps above are followed, the process should fail only when very

   little memory is available in the system.

5. Create a device context for the display. Use the equation listed in

   step 2 above to compute the logical height for the font to be

   selected into the screen DC. Use CreateFont and SelectObject to

   select this logical font into the display DC, and use

   GetTextMetrics and GetTextFace to retrieve a TEXTMETRIC data

   structure and the face name for the selected font.

6. The font selected for the display is generally not the same as the

   font selected for the printer. To achieve WYSIWYG and the highest

   possible quality of the printed output, it is best to perform all

   page layout computations based on the metrics obtained from the

   printer DC, and force the output on the screen to match the printer

   output as closely as possible. This process generally causes some

   degradation of quality. It is assumed in the remainder of this

   discussion that text quality is most important.

7. Check whether either device supports the GDI escape codes that

   enhance the usability of fonts. One escape code, for example,

   returns the width table for proportionally spaced fonts. These

   escapes are listed in chapter 12 of the "Microsoft Windows Software

   Development Kit Reference, Volume 2." Use the escape code

   QUERYESCSUPPORT to discover whether a device supports a particular

   escape code. The width tables provide data to determine the

   physical extent of character strings to be sent to the printer and

   how to match that extent on the display.

8. If the devices do not support those GDI escapes, select the desired

   font into a printer DC and use the GetTextExtent function to get

   the extent a string will occupy when printed.

9. With the methods outlined in steps 7 and 8, the dimensions of any

   string can be computed for the printer device. This information is

   used to compute page breaks and line breaks. Once the placement and

   extent of a string of text have been determined on the printed

   page, it is possible to create a scaled image on the screen. There

   are three methods of forcing a match between printer and screen:

   a. Take no special action. Put the text on the screen based on

      screen DC text metrics. With this method, only minimal matching

      is obtained.

   b. Use either the GetTextExtent function or the combination of the

      GetCharWidths, SetTextJustification, and SetTextCharacterExtra

      functions to create the same line breaks and justification on

      the screen as on the printed page. This method uses white space

      (usually the space character) to stretch or shrink a string of

      text (action of SetTextJustification) and adds a constant value

      to the width of every character in the font (action of

      SetTextCharExtra). This method achieves reasonable WYSIWYG.

   c. Use the ExtTextOut function and pass a width array to achieve

      the exact placement of each and every character in the string.

      This method provides the highest degree of WYSIWYG; however, it

      also requires character placement algorithms that do not degrade

      the speed of text output too much.

The following functions related to this article are documented in

chapter 4 of the "Microsoft Windows Software Development Kit

Reference, Volume 1:"

   CreateFont

   CreateFontIndirect

   EnumFonts

   Escape

   GetCharWidths

   GetDeviceCaps

   GetTextExtent

   GetTextFace

   GetTextMetrics

   SelectObject

   SetMappingMode

   SetViewportExtent

   SetViewportOrigin

   SetWindowExtent

   SetWindowOrigin

The LOGFONT and TEXTMETRIC data structures are documented in Chapter 7

of the SDK reference, volume 2.

The following device escape functions are documented in Chapter 12 of

the SDK reference, volume 2:

   ENABLEPAIRKERNING

   ENABLERELATIVEWIDTHS

   EXTTEXTOUT

   GETEXTENDEDTEXTMETRICS

   GETEXTENTTABLE

   GETPAIRKERNTABLE

   GETTRACKKERNTABLE

   QUERYESCSUPPORT

   SETKERNTRACK

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: GdiPrn


Distinguishing Between Keyboard ENTER and Keypad ENTER

PSS ID Number: Q96242

Authored 11-Mar-1993	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

It is possible using ReadConsoleInput() or PeekConsole() to distinguish

between the ENTER key on the main keyboard and the ENTER key on the numeric

keypad. The KEY_EVENT_RECORD structure in the INPUT_RECORD structure must

be used to distinguish between the two keys.

MORE INFORMATION

The following illustrates what the KEY_EVENT_RECORD structure is filled

with after a keyboard ENTER key versus a numeric keypad ENTER key is

pressed.

Keyboard ENTER Key

------------------

   KeyEvent.wRepeatCount     = 1

   KeyEvent.wVirtualKeyCode  = 13

   KeyEvent.wVirtualScanCode = 28

   KeyEvent.dwControlKeyState= 00000000

Numeric Keypad ENTER Key

------------------------

   KeyEvent.wRepeatCount     = 1

   KeyEvent.wVirtualKeyCode  = 13

   KeyEvent.wVirtualScanCode = 28

   KeyEvent.dwControlKeyState= 00000100

In the case of the numeric keypad ENTER key, in dwControlKeyState, the

ENHANCED_KEY bit is set.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: BseCon


DLC Information on LLC_DIR_SET_MULTICAST_ADDRESS Command

PSS ID Number: Q129022

Authored 17-Apr-1995	Last modified 18-Apr-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

SUMMARY

The DLC programming interface for Windows NT supports Ethernet multicast

addressing via the LLC_DIR_SET_MULTICAST_ADDRESS command. This command must

be successfully issued before Ethernet multicasts can be received. This

article shows by example how to use the command.

MORE INFORMATION

The following function demonstrates the command.

Sample Code

-----------

BOOL DlcSetMulticastAddress( BYTE bAdapter, BYTE *pbResult, BYTE *pbAddress

)

{

    LLC_CCB Ccb;

    Ccb.uchAdapterNumber  = bAdapter;

    Ccb.uchDlcCommand     = LLC_DIR_SET_MULTICAST_ADDRESS;

    // note:  Dlc expects Ethernet addresses to be specified in the

    //        non-canonical form.  In other words, reverse the bits

    //        before passing an Ethernet address.

    //

    //        Also, the first byte of the canonical form of an

    //        Ethernet multicast address must be 0x01.

    Ccb.u.pParameterTable = (PLLC_PARMS) pbAddress;

    if(!DlcSyncCall( &Ccb ))

        return FALSE;

    else

    {

        *pbResult = Ccb.uchDlcStatus;

        return TRUE;

    }

}

// AcsLan wrapper function used by DlcSetMulticastAddress

BOOL DlcSyncCall( PLLC_CCB pCcb )

{

   BOOL  fResult = FALSE;

   DWORD dwResult;

   pCcb->hCompletionEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

   if (!pCcb->hCompletionEvent)

      return FALSE;

   int iStatus = (int) AcsLan( pCcb, NULL );

   if ( iStatus != ACSLAN_STATUS_COMMAND_ACCEPTED )

      goto done;

   dwResult = WaitForSingleObject( pCcb->hCompletionEvent, INFINITE );

   if ( dwResult == WAIT_OBJECT_0 )

      fResult = TRUE;

done:

   CloseHandle( pCcb->hCompletionEvent );

   return fResult;

}

Additional reference words: 3.10 3.50

KBCategory: kbnetwork kbprg kbcode

KBSubcategory: NtwkMisc


DlgDirList on Novell Drive Doesn't Show Double Dots [..]

PSS ID Number: Q99339

Authored 26-May-1993	Last modified 23-Jun-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

The Microsoft Windows application programming interface (API) function

DlgDirList() can be used to add directories, drives, and/or files to a

list box. On a Novell network with the default login script, the

Windows API may not add the string "[..]" used to represent the parent

directory to the list box. This is due to Novell implementation, and

is not a bug in the Windows API. To make the entry appear, add the

following line to the Novell login script (usually called SHELL.CFG

located in the root directory of the boot drive)

   SHOW DOTS = ON

MORE INFORMATION

A Novell NetWare file server does not include the directory entries

dot (.) and double dot (..) as MS-DOS does. However, the NetWare shell

(version 3.01 or later) can emulate these entries when applications

attempt to list the files in a directory. Turning on Show Dots causes

problems with earlier versions of some 286-based NetWare utilities,

such as BINDFIX.EXE and MAKEUSER.EXE. Make sure you upgrade these

utilities if you upgrade your NetWare shell. For more information,

contact your Novell dealer.

NOTE: With Novell NetWare version 3.1.1, the line SHOW DOTS=ON/OFF can

be added to the NET.CFG file for the same effect.

The same behavior is shown with the API DlgDirListComboBox, and the

messages LB_DIR and CB_DIR.

Additional reference words: 3.10 3.50 3.51 4.00 95 listbox

KBCategory: kbprg

KBSubcategory: UsrCtl


Do Not Call the Display Driver Directly

PSS ID Number: Q77402

Authored 15-Oct-1991	Last modified 10-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK (Windows 95 only)

SUMMARY

In general, a Windows-based application cannot call the Windows display

driver directly to perform graphics primitives. This article details

the reasons this restriction is in place.

MORE INFORMATION

The Windows display driver communicates with the Graphics Device

Interface (GDI) to perform primitive graphics operations. The

parameters of the entry points (or exported functions) in the display

driver are set up according to the standard interface between GDI and

the display driver. The parameters passed by GDI to the display driver

are only meaningful to GDI and to the display driver. A Windows-based

application has no way to obtain these parameters. For example, the

parameter most-commonly passed by GDI to the display driver is a

pointer to a structure called PDEVICE. Memory for this structure is

allocated by GDI, and its contents are specified by the display driver

during the driver's initialization. The pointer to the PDEVICE

structure is private to GDI; furthermore, the structure of PDEVICE

varies among display drivers.

To give another example, when a primitive is to be done to a memory

bitmap, instead of passing a pointer to PDEVICE, GDI passes to the

display driver a pointer to a structure; the structure is usually

referred to as a physical bitmap. Note that this physical bitmap

structure is also called "BITMAP"; do not confuse it with the BITMAP

structure defined in the Windows Software Development Kit. Again, this

physical bitmap structure is not designed to be used by a Windows-based

application. Although the information described in this structure is

somewhat related to the bitmap that the application uses, the pointer

to the physical bitmap structure is private to GDI and cannot be

obtained by the application.

Additional reference words: 3.00 3.10

KBCategory: kbprg

KBSubcategory: GdiMisc


Do Not Forward DDEML Messages from a Hook Procedure

PSS ID Number: Q89828

Authored 30-Sep-1992	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

If an application for Windows uses the Dynamic Data Exchange

Management Library (DDEML) in addition to a message hook [for example,

by calling SetWindowsHook() or SetWindowsHookEx()], it is possible

that your hook procedure will receive messages that are intended for

the DDEML libraries.

For the DDEML libraries to work properly, you must make sure that your

hook function does not forward on any messages that are intended for

the DDEML libraries.

MORE INFORMATION

If your hook procedure receives a code of type MSGF_DDEMGR, you should

return FALSE instead of calling the CallNextHookEx() function.

The way to handle this situation is to use the following code:

   if (MSGF_DDEMGR == code)

      return FALSE;

   else

   {

   ...

   }

In cases where the callback function processes the message, it should

return TRUE.

Note, however, how the message filter function is called from within

DDEML:

   while (TimeOutHasntExpired) {

       GetMesage (&msg, (HWND)NULL, 0, 0);

       if ( !CallMsgFilter (&msg, MSGF_DDEMGR))

            DispatchMessage (&msg);

    }

Given this, a callback function that just returns would cause the

CallMsgFilter() call above to return TRUE, and never dispatch the

message. This inevitably causes an infinite loop in the application,

because GetMessage() ends up retrieving the same message over and

over, without dispatching it to the appropriate window for processing.

Therefore, a callback function that processes the message may not just

return TRUE, but should also translate and dispatch messages

appropriately.

The Windows 3.1 SDK's DDEMLCL sample demonstrates how to do this

correctly in its MessageFilterProc() found in DDEMLCL.C:

   if (nCode == MSGF_DDEMGR) {

   /*

   * If a keyboard message is for MDI, let MDI client take care of it.

   * Otherwise, check to see if it is a normal accelerator key.

   * Otherwise, just handle the message as usual.

   */

       if ( !TranslateMDISysAccel (hWndMDIClient, lpmsg) &&

             !TranslateAccelerator (hWndFrame, hAccel, lpmsg))  {

             TranslateMessage (lpmsg);

             DispatchMessage (lpmsg);

         }

        return 1;

    }

For more information about message hooks and DDEML, please see the

above mentioned functions in the Windows SDK manual or the online help

facility.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrDde


DOCERR: AddPort, ConfigurePort, DeletePort Fail Remotely

PSS ID Number: Q131223

Authored 06-Jun-1995	Last modified 23-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.5, 3.51,

   and 4.0

SYMPTOMS

Using AddPort, ConfigurePort, or DeletePort with the Universal Naming

Convention (UNC) name of a remote server as the first parameter results in

a return value of FALSE. This indicates that a failure has occurred. The

error returned by GetLastError is ERROR_NOT_SUPPORTED. If the first

parameter is the UNC name of the local machine or NULL, the functions

succeed.

CAUSE

Calls to remote servers via AddPort, ConfigurePort and DeletePort are not

supported. The documentation gives the impression that the UNC name for a

remote server is permissible as the first parameter.

RESOLUTION

Use the UNC name to the local server or NULL as the first parameter.

MORE INFORMATION

These functions display a dialog associated with the hWnd that is supplied

in the second parameter. Because the call displays a dialog box and

requires a handle to a window in the second parameter, it is only supported

locally.

Additional reference words: 3.50 4.00 95

KBCategory: kbprg kbdocerr

KBSubcategory: GdiPrn


DOCERR: BUFFER.CREATE Command Not Documented

PSS ID Number: Q123462

Authored 01-Dec-1994	Last modified 24-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), version 3.5

SUMMARY

This article documents the BUFFER.CREATE command. This is a command that

Microsoft added, so it is not documented in IBM LAN Technical Reference.

MORE INFORMATION

The AcsLan function topic in the Win32 Help file indicates that there are

some differences between Windows NT DLC and the CCB2 interface documented

in the IBM LAN Technical Reference. The most notable is that the buffer

pool must be specified on an open adapter instance basis, not per SAP.

After an adapter has been opened by using the DIR.OPEN.ADAPTER command, a

buffer pool must be given to the DLC driver by using BUFFER.CREATE.

The IBM LAN Technical Reference manual has no reference to BUFFER.CREATE.

However, the DLCAPI.H file contains the following structure with no other

information explaining how to use it:

typedef struct {

    HANDLE hBufferPool;                // handle of new buffer pool

    PVOID pBuffer;                     // any buffer in memory

    ULONG cbBufferSize;                // buffer size in bytes

    ULONG cbMinimumSizeThreshold;      // minimum locked size

} LLC_BUFFER_CREATE_PARMS, *PLLC_BUFFER_CREATE_PARMS;

Unlike DLC as described in IBM LAN Technical Reference, Windows NT DLC does

not support a buffer pool per SAP, but rather a buffer pool per process.

All buffers given to the application are allocated from the same pool. (You

can also allocate send buffers from the buffer pool, but this is not the

case in general.)

The application gives the buffer pool to DLC by using the BUFFER.CREATE

request. The parameters are:

 - hBufferPool: the returned handle of the buffer pool. Supposedly, DLC can

   share buffer pools between processes but it doesn't, so it's useless.

 - pBuffer: the pointer to application allocated buffer pool. This can be

   allocated by any scheme you wish and can be any size.

 - cbBufferSize: the size of pBuffer.

 - cbMinimumSizeThreshold: the minimum locked size.

Because the buffer is passed on kernel mode, it must be mapped into system

space. It is divided into pages and further subdivided into 256-byte

segments (unknown to the application). DLC tries to return as many

contiguous segments as it can, but you may end up with a fragmented buffer,

containing a relatively long chain of small segments. To your advantage,

the largest DLC receive frame is usually around 4K.

DLC aligns the buffer to a page boundary, discarding any partial page

buffer after the last page. This is not a problem unless you allocate a

buffer less than a page, or one that is not page-aligned. In these cases,

you are in danger of not having a buffer.

Because the buffer must be mapped to system space, DLC needs to lock the

buffers into memory when receiving or sending from the buffers. To increase

performance, DLC tries to keep a certain amount of buffer locked at all

times. It will lock successive pages as the need arises. (In Windows NT,

the smallest lockable region is a page.) You can control the initial locked

area by setting the cbMinimumSizeThreshold value. If DLC does indeed lock

your pages in excess of cbMinimumSizeThreshold, it will try to unlock them

as they are freed up.

Additional reference words: 3.50

KBCategory: kbprg kbdocerr

KBSubcategory: NtwkMisc


DOCERR: CloseClipboard() Suggests Calling DuplicateHandle()

PSS ID Number: Q103240

Authored 19-Aug-1993	Last modified 12-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.1, 3.5,

   3.51, and 4.0

The documentation for CloseClipboard() suggests using DuplicateHandle() on

a clipboard object before closing the clipboard, in order to use that

object after the clipboard is closed. Doing so results in a return of

ERROR_INVALID_HANDLE.

The Win32 SDK 3.1 documentation is in error. DuplicateHandle() is specified

to work only on console input, console output, events, files, file

mappings, mutexes, pipes, processes, semaphores, and thread handles.

The Win32 SDK 3.5 documentation has been corrected.

Additional reference words: 3.10 3.50 3.51 4.00 95

KBCategory: kbprg kbdocerr

KBSubcategory: UsrClp


DOCERR: CreateFile() and Mailslots

PSS ID Number: Q131493

Authored 12-Jun-1995	Last modified 22-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) version 3.5

SUMMARY

The documentation for CreateFile() API gives incorrect possible return

values while opening a client end of a mailslot. The documentation states:

    If CreateFile opens the client end of a mailslot, the function always

    returns a valid handle, even if the mailslot does not exist.

    In other words, there is no relationship between opening the client

    end and opening the server end of the mailslot.

Actually, CreateFile() returns INVALID_HANDLE_VALUE for a mailslot if the

mailslot client is being created using the "\\." notation to communicate

with a mailslot server on the local system when the server is not up and

running.

MORE INFORMATION

The following code always returns INVALID_HANDLE_VALUE for a handle value

from CreateFile() while opening the client end of the mailslot if the

mailslot server is not up and running to read mailslot messages:

    CreateFile("\\\\.\\mailslot\\testslot",

               GENERIC_WRITE,

               FILE_SHARE_READ,

               NULL,

               OPEN_EXISTING,

               FILE_ATTRIBUTE_NORMAL,

               NULL);

GetLastError() in this case returns Error 2: "The system cannot find the

specified file."

This is an expected behavior. Windows NT implementation of local mailslots

does not allow you to open the mailslot if the receiver has not created the

server end with CreateMailslot() API.

Additional reference words: 3.50

KBCategory: kbprg kbnetwork kbdocerr

KBSubcategory: BseIpc


DOCERR: CS_PARENTDC Class Style Description Incorrect

PSS ID Number: Q111005

Authored 03-Feb-1994	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.1, 3.5, 3.51, and 4.0

SUMMARY

The documentation relating to the CS_PARENTDC window class style in the

Windows SDK versions 3.0 and 3.1 states that CS_PARENTDC "Gives the display

context of the parent window to the window class." The documentation for

the Win32 SDK contains a similar statement. These statements are incorrect.

MORE INFORMATION

A window with the CS_PARENTDC style bit will receive a regular device

context (DC) from the system's cache of device contexts. CS_PARENTDC merely

sets the clipping rectangle of the child to that of the parent so that the

child can draw on the parent. It does not give the child the parent's DC or

DC settings.

CS_PARENTDC is used with all of Windows's standard controls such as edit

controls and list boxes because it can help improve performance when

drawing, especially in a dialog box. For example, dialog box units are not

exact and if a child is drawing in a very small space it might accidentally

draw outside its own border. This style provides a little room for error

and prevents the child from being clipped unexpectedly.

Additional reference words: 3.00 3.10 3.50 4.00 95  WNDCLASS RegisterClass

KBCategory: kbprg kbdocerr

KBSubcategory: UsrCls


DOCERR: DdeCreateDataHandle Documentation Errors

PSS ID Number: Q109131

Authored 22-Dec-1993	Last modified 10-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

 - Microsoft Win32 SDK, version 3.1

The documentation for the cbInitData and offSrcBuf parameters to the

DdeCreateDataHandle function are incorrect. Here is the description given

for these two parameters in the current documentation:

   cbInitData     Specifies the amount, in bytes, of memory to allocate for

                  the global memory object. If this parameter is zero, the

                  lpvSrcBuf parameter is ignored.

   offSrcBuf      Specifies an offset, in bytes, from the beginning of the

                  buffer pointed to by the lpvSrcBuf parameter. The data

                  beginning at this offset is copied from the buffer to the

                  global memory object.

These parameters should be documented as follows:

   cbInitData     Specifies the amount, in bytes, of memory to copy from

                  the source buffer specified by lpvSrcBuf.

   offTargetBuf   Specifies an offset, in bytes, from the beginning of the

                  global memory object* allocated by DdeCreateDataHandle.

                  Data from the source buffer is copied to the global

                  memory object, beginning at this offset.

                  *The size of the global memory object allocated by

                  DdeCreateDataHandle is equal to the sum of cbInitData and

                  offTargetBuf.

Additional reference words: 3.10

KBCategory: kbprg kbdocerr

KBSubcategory: UsrDde


DOCERR: DdeCreateStringHandle() lpszString param

PSS ID Number: Q102570

Authored 04-Aug-1993	Last modified 18-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.10

 - Microsoft Win32 SDK versions 3.1, 3.5, 3.51, and 4.0

SUMMARY

The documentation for the DdeCreateStringHandle() function in the

Windows 3.1 Software Development Kit (SDK) "Programmer's Reference,

Volume 2: Functions" incorrectly states that the lpszString parameter

may point to a buffer of a null-terminated string of any length, when

the string is actually limited to 255 characters.

DDEML string-management functions are internally implemented using

global atom functions. DdeCreateStringHandle() in particular,

internally calls GlobalAddAtom(), and therefore inherits the same

limitation as atoms to a maximum of 255 characters in length.

MORE INFORMATION

DDEML applications use string handles extensively to carry out DDE

tasks. To obtain a string handle for a string, an application calls

DdeCreateStringHandle(). This function registers the string with the

system by adding the string to the global atom table, and returns a

unique value identifying the string.

The global atom table table in Windows can maintain strings that are

less than or equal to 255 characters in length. Any attempt to add a

string of greater length to this global atom table will fail. Hence, a

call to DdeCreateStringHandle() fails for strings over 255 characters

long.

This limitation is by design. DDEML applications that use the

DdeCreateStringHandle() function should conform to the 255-character

limit.

This limitation has been preserved on the Windows NT version of DDEML

for compatibility reasons.

Additional reference words: 3.10 3.50 3.51 4.00 95

KBCategory: kbprg kbdocerr

KBSubcategory: UsrDde


DOCERR: DeviceIoControl Requires OVERLAPPED Struct w/ Async.

PSS ID Number: Q126282

Authored 19-Feb-1995	Last modified 22-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1 and 3.5

The documentation for DeviceIoControl is incomplete. It should warn you

that unexpected behavior may occur when both the following are true:

 - A DeviceIoControl request is followed by another DeviceIoControl request

   on the same handle.

 - There was no OVERLAPPED structure passed into DeviceIoControl after the

   handle to the device or file was opened with FILE_FLAG_OVERLAPPED.

The following is a list of some of the unexpected behavior that may occur:

 - Requests complete before expected.

 - There's undefined data in the returned buffers.

 - Unknown error codes are returned.

 - IRPs are held in a driver while the DeviceIoControl call has already

   returned.

When a handle is requested to a driver or file with FILE_FLAG_OVERLAPPED

specified, the executive prepares itself for all requests on that handle to

be asynchronous. Usually, when the request is sent down with an OVERLAPPED

structure, an event is placed in that OVERLAPPED structure. This event is

then stored in the FILE_OBJECT in kernel mode to use later to signal the

user-mode application when that IRP has been completed. If an event is not

specified, the value will be 0 in the FILE_OBJECT, when a second request is

sent down before the first request completes (and completes), the IO

manager will not have separate signals for the completion of the requests.

Therefore, the request will appear to be completed, while in reality the

IRP has not been completed by the underlying driver.

Please see the current documentation of GetOverlappedResult for more

information on the behavior of the executive when no OVERLAPPED structure

is specified when the handle to the driver or file was opened with

FILE_FLAG_OVERLAPPED.

Additional reference words: 3.10 3.50 FILE_FLAG_OVERLAPPED DDK EVENT

KBCategory: kbprg kbdocerr

KBSubcategory: BseFileio


DOCERR: DEVMODE dmPaperSize Member Documentation Error

PSS ID Number: Q108924

Authored 20-Dec-1993	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

The dmPaperSize member of the DEVMODE structure is documented incorrectly.

The documentation states that the dmPaperSize member may be set to zero if

the length and width of the paper are specified by the dmPaperLength and

dmPaperWidth members, respectively. However, the correct value to use for

user-defined paper sizes is DMPAPER_USER.

DMPAPER_USER is correctly listed in the Microsoft Windows 3.1 SDK

documentation as meaning a user-defined paper size, but is completely

omitted from the Microsoft Windows 3.0 SDK documentation.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg kbdocerr

KBSubcategory: GdiPrn


DOCERR: DragQueryFile() Return Code Can Be Misleading

PSS ID Number: Q115081

Authored 18-May-1994	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.1, 3.5,

   3.51, 4.0

SYMPTOMS

The documentation for DragQueryFile() in the "Win32 Programmer's

Reference" indicates that the return value is "the count of the

characters copied" or "the required size, in characters, of the buffer".

However, the actual return values do not include the trailing null

character in this count.

RESOLUTION

The correct description for the return value is "the length of the string

returned, not including the terminating null character" or "the length of

the string that would be returned, not including the terminating null

character".

The Win32 SDK 3.5 documentation has been corrected.

Additional reference words: 3.10 3.50 3.51 4.00 95

KBCategory: kbref kbdocerr

KBSubcategory: UsrDnd


DOCERR: EofChar Field of DCB Structure Is Not Supported

PSS ID Number: Q115083

Authored 18-May-1994	Last modified 28-Nov-1994

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   versions 3.1 and 3.5

SYMPTOMS

The documentation for the device control block (DCB) structure says that

the EofChar field specifies the value of the character used to signal

the end of the data over the communications resource. However, this

setting seems to have no effect.

RESOLUTION

DCB.EofChar is not currently supported in Windows NT.

MORE INFORMATION

When DCB.EofChar is supported, you should call ClearCommError() after

every read to see whether COMSTAT.fEof is set. When COMSTAT.fEof is set,

this means that DCB.EofChar has been received.

Additional reference words: 3.10 3.50

KBCategory: kbref kbdocerr

KBSubcategory: BseCommapi


DOCERR: Error 87 When NetMessageBufferSend Attempts Broadcast

PSS ID Number: Q129289

Authored 24-Apr-1995	Last modified 08-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.5

SUMMARY

The documentation incorrectly states that applications may use

NetMessageBufferSend() to send broadcast messages on the network. This API

does not support broadcasts. If an application calls the

NetMessageBufferSend() API with the second parameter set to "L"*"", the API

fails with error 87 (Invalid Parameter). The "*" parameter is used to

broadcast a message to all the machines on the network.

MORE INFORMATION

Programmers can specify the domain name as the second parameter to send

broadcasts on a particular domain. For example:

   NetMessageBufferSend(NULL, // Run command on local machine.

              L"MYDOMAIN*",   // Domain name.

              L"MYNAME",      // Sender of message.

              buffer,         // Buffer to send.

              buflen);        // Size of buffer.

If broadcasts are necessary, use the NetServerEnum() or WNetOpenEnum() API

in conjunction with the WNetEnumResource() API to list domains, and use the

NetMessageBufferSend() API to send a message on each domain as shown above.

REFERENCES

"Message APIs" help file in the Windows Networking API Definitions

section of the online "Win32 SDK Programmer's Reference."

Additional reference words: 3.50

KBCategory: kbnetwork kbdocerr

KBSubcategory: NtwkLmapi


DOCERR: Errors in Win32s Compatibility

PSS ID Number: Q113679

Authored 11-Apr-1994	Last modified 20-Jun-1995

The information in this article applies to:

 - Microsoft Win32s versions 1.2 and 1.25a

SUMMARY

The following Win32 APIs are not listed in the Win32 Programmer's Reference

as being supported under Win32s. This is incorrect. These Win32 APIs are

supported under Win32s:

   FlushInstructionCache

   GetFileInformationByHandle

   MoveMemory

   TlsAlloc

   RegCreateKeyEx

   RegOpenKeyEx

   RegSetValueEx

   WNetAddConnection

   WNetGetConnection

In addition, all of the BS_ button styles are marked as not supported under

Win32s. However, Win32s supports all of the button styles that Windows 3.1

supports.

MORE INFORMATION

The following Win32 APIs and CRT (C Run-time) routines are supported under

Win32s, with the restrictions noted.

Function                        Associated Restriction

===

CreateFile                      FILE_FLAG_NO_BUFFERING,

                                FILE_FLAG_WRITE_THROUGH,

                                FILE_FLAG_OVERLAPPED, FILE_DELETE_ON_CLOSE,

                                and the security flags are not supported.

                                Passing dwShareMode=0 opens the file in

                                compatibility mode, not in exclusive mode.

---------------------------------------------------------------------------

CreateFileMapping               SEC_COMMIT is supported, but not

                                SEC_IMAGE, SEC_NOCACHE or SEC_RESERVE.

                                The size of named shared memory is limited

                                by Windows memory.

---------------------------------------------------------------------------

CreateDIBitmap                  DIB_PAL_INDICES

CreateDIBPatternBrush           DIB_PAL_PHYSINDICES

CreateDIBPatternBrushPt         DIB_PAL_LOGINDICES   are not supported.

GetDIBits

SetDIBits

SetDIBitsToDevice

StretchDIBits

---------------------------------------------------------------------------

CreatePolyPolygonRgn            The polygon must be closed.

---------------------------------------------------------------------------

CreateProcess                   Handle inheritance is not supported.

                                Only creation flags supported are

                                DEBUG_PROCESS and DEBUG_ONLY_THIS_PROCESS.

                                The only priority supported is

                                NORMAL_PRIORITY_CLASS. The security

                                attributes are ignored.

---------------------------------------------------------------------------

GetFileInformationByHandle      ftCreationTime, ftLastAccessTime,

                                dwVolumeSerialNumber, nFileIndexHigh, and

                                nFileIndexLow are all 0.

---------------------------------------------------------------------------

GetFileTime                     Only lpLastWriteTime is supported.

SetFileTime

---------------------------------------------------------------------------

GetPrivateProfileString         lpszSection parameter cannot be NULL.

GetProfileString

---------------------------------------------------------------------------

GetSystemMetrics                SM_CMOUSEBUTTONS is not supported.

---------------------------------------------------------------------------

GetSystemPaletteEntries         The fourth parameter cannot be NULL.

---------------------------------------------------------------------------

GetVolumeInformation            Volume ID is not supported.

---------------------------------------------------------------------------

OpenProcess                     Settings for fdwAccess and fInherit are

                                ignored. In the implementation,

                                fdwAccess=PROCESS_ALL_ACCESS and

                                fInherit=TRUE.

---------------------------------------------------------------------------

PeekMessage                     hWnd cannot be -1.

---------------------------------------------------------------------------

PlaySound                       SND_ALIAS, SND_FILENAME, and

                                SND_NOWAIT are not supported.

---------------------------------------------------------------------------

RegSetValueEx                   Only supports the REG_SZ entries.

---------------------------------------------------------------------------

SetClipboardData                Use only a global handle.

---------------------------------------------------------------------------

SetWindowsHookEx                dwThreadId parameter is ignored.

---------------------------------------------------------------------------

signal                          SIGBREAK is not supported.

---------------------------------------------------------------------------

spawn                           P_WAIT is not supported.

---------------------------------------------------------------------------

WaitForDebugEvent               Any dwTimeOut other than 0 is treated as

                                INFINITE.

---------------------------------------------------------------------------

WNetAddConnection               Password cannot be NULL, but can be "".

===

Additional reference words: 1.20

KBCategory: kbref kbdocerr

KBSubcategory: W32s


DOCERR: GetWindowPlacement Function Always Returns an Error

PSS ID Number: Q89569

Authored 27-Sep-1992	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SYMPTOMS

When an application developed for the Microsoft Windows graphical

environment uses the GetWindowPlacement() function to retrieve the

show state and position information for a window, the function

always returns FALSE, indicating an error.

CAUSE

The length member of the specified WINDOWPLACEMENT data structure

is not initialized.

RESOLUTION

Initialize the length member and call the GetWindowPlacement()

function as follows:

   BOOL             bResult;

   WINDOWPLACEMENT  lpWndPl;

   lpWndPl.length = sizeof(WINDOWPLACEMENT);

   bResult = GetWindowPlacement(hWnd, &lpWndPl);

MORE INFORMATION

The need to initialize the length member of the WINDOWPLACEMENT

structure is documented on page 422 of the Microsoft Windows Software

Development Kit (SDK) "Programmer's Reference, Volume 3: Messages,

Structures, and Macros" manual for version 3.1. This information is

not listed in the documentation for the GetWindowPlacement() function on

page 479 of the "Programmer's Reference, Volume 2: Functions" manual.

Additional reference words: 3.10 3.50 3.51 4.00 95

KBCategory: kbprg kbdocerr

KBSubcategory: UsrWndw


DOCERR: GLYPHMETRICS Is in Device Units Not Logical Units

PSS ID Number: Q126141

Authored 15-Feb-1995	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK), version 3.1

 - Microsoft Win32s version 1.2

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

The units of the values in the GLYPHMETRICS structure are documented in the

"Win32 Programmer's Reference vol. 5" page 425 and the "Windows 3.1 SDK

Programmer's Reference vol. 3" page 297 as being in logical units. This is

incorrect. The values in the GLYPHMETRICS structure returned by the

GetGlyphOutline function call are in device units, not in logical units.

Additional reference words: 1.20 3.10 3.50 4.00 95

KBCategory: kbprg kbdocerr

KBSubcategory: GdiFnt


DOCERR: Important Information on RPC 1.0 Missing from the

PSS ID Number: Q129142

Authored 18-Apr-1995	Last modified 19-Apr-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows for

   Workgroups version 3.11

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

SUMMARY

This article documents important information about Microsoft RPC version

1.0 that is not included in the Microsoft RPC programming documentation or

in Help. This information is identical to the information contained in the

file RPCREAD.ME included with the Win32 SDK for Windows NT version 3.1.

MORE INFORMATION

Introduction

------------

Microsoft RPC version 1.0 is a toolkit for developing network-aware

distributed applications in C/C++. The RPC toolkit includes:

 - MIDL compilers for Microsoft Windows NT and Microsoft Windows 3.x.

 - C/C++ language header files (.H) and run-time libraries (.LIB and .DLL)

   for Microsoft Windows NT, Microsoft Windows 3.x, and MS-DOS.

 - Sample programs for Microsoft Windows NT, Microsoft Windows 3.x,

   Microsoft Windows for Workgroups, and MS-DOS.

 - RPC reference Help files, Windows Write files, and PostScript files.

The Win32 SDK contains the Microsoft Windows NT and Microsoft Windows 3.x

versions of the RPC SDK.

Installation

------------

The Microsoft Win32 SDK installs the components of the Microsoft RPC

toolkit as part of its standard installation. No additional installation is

required.

To develop client-side distributed applications for MS-DOS, Microsoft

Windows 3.x, and Windows for Workgroups version 3.1, you must install the

Microsoft Windows 3.x/MS-DOS version of the RPC toolkit. Cross-compilation

of Windows version 3.x and MS-DOS clients with Microsoft Windows NT

requires a 16-bit C compiler in the Microsoft Windows NT environment. This

development environment is not installed during RPC SDK setup. The

Microsoft RPC toolkit for MS-DOS and Microsoft Windows 3.x requires:

 - A 16-bit compiler such as Microsoft Visual C++ Development System

   for Windows or the Microsoft C/C++ 7.0 compiler.

 - One of the following:

    - Microsoft Windows for Workgroups version 3.1 (or later) with named

      pipes, NetBIOS, or TCP/IP.

      -or-

    - Microsoft LAN Manager version 2.1 (or later) with named pipes,

      NetBIOS, or TCP/IP.

      -or-

    - DEC PATHWORKS 4.0 (or later) with NetBIOS, TCP/IP, or DECNet.

      -or-

    - Novell Netware 3.x with SPX.

      -or-

    - Other networking software compatible with the Windows Sockets API

      standard.

To install the Microsoft Windows 3.x/MS-DOS version of the RPC toolkit, run

the Setup program in the directory MSTOOLS\RPC_DOS. To start the Setup

program, choose the Run command from the File menu in the Microsoft Windows

3.x Program Manager.

When you install the RPC toolkit in a directory different from the

directory you used for Microsoft C/C++ version 7.0, you must set the

environment variables INCLUDE, LIB, and PATH to point to the directories

that contain the RPC header files, libraries, and DLLs and binaries,

respectively. You cannot install the RPC toolkit in the same directory as

the Visual C++ compiler binaries because of name conflicts.

RPC Documentation

-----------------

The following Microsoft RPC version 1.0 reference materials are available

in Windows Write format and in PostScript file format:

Microsoft RPC Programmer's Guide and Reference:

 - Part I: Programmer's Guide

 - Part II: MIDL Language Reference

 - Part III: Run-Time API Reference

 - Part IV: Installing RPC

 - Part V: Appendixes

Use the PostScript files to print individual chapters of the documentation

on your PostScript printer.

The following run-time and MIDL reference Help file is available on line:

   RPC.HLP   WinHelp MIDL and run-time API reference

RPC sample-program source files are available in the directory

MSTOOLS\SAMPLES\RPC. MS-DOS and Microsoft Windows 3.x versions of some

samples are available when you install the Windows 3.x/MS-DOS version of

the RPC toolkit. The file MSTOOLS\SAMPLES\RPC\README.TXT describes the

available samples.

Release Notes for MIDL compiler

-------------------------------

1.0 The following release notes relate to the MIDL compiler and to building

distributed applications.

1.1 Packing and Alignment Considerations

----------------------------------------

You must use the same packing and alignment settings (/Zp switch) for both

the C compiler and the MIDL compiler. Using different packing levels for

the two compilers causes undefined results. Specify the /Zp switch to

verify that the correct packing and alignment settings are used on both

compilers.

This release of the MIDL compiler does not support the switches /Zp1 and

/Zp2 in the MIPS environment, although the compiler does not prevent the

use of /Zp1 and /Zp2.

Use /Zp1 or /Zp2 for 16-bit client platforms. Objects of types with natural

alignment greater than 2 that are allocated on the stack as local variables

in the client application are not necessarily allocated on 4- and 8-byte

boundaries by the C compiler. Because the C compiler does not guarantee

alignment on the stack, marshalling from and unmarshalling into such

objects may cause problems.

Generic stubs (/env generic) must be specified with /Zp1 or /Zp2 in 16-bit

client environments. Generic stubs specified with /Zp1 or /Zp2 cannot be

used in the MIPS environment. MIDL uses /Zp4 by default for generic stubs.

1.2 C Stub Source Code Causes Compilation Warnings

--------------------------------------------------

The stub files generated by the MIDL compiler may generate warnings when

they are compiled at compiler warning-level 3 and higher. These warnings

can generally be safely ignored.

When your C compiler does not use the same default character sign as the

MIDL compiler, use the MIDL compiler switch /char to generate explicit

declarations in the header file. For more information, see the Microsoft

RPC programming documentation.

1.3 Use Six-Character Filenames on the FAT File System

------------------------------------------------------

Because RPC version 1.0 appends _C, _X, and similar extensions to

filenames, limit your filenames to six characters or less. Filenames that

total more than eight characters are too long for some file systems and can

fail.

1.4 Specifying Local and UUID Attributes

----------------------------------------

If the base IDL file contains no procedures, you don't have to specify

local or UUID attributes.

1.5 MIDL Extra Server Files in the Windows 3.x/MS-DOS Environment

-----------------------------------------------------------------

MIDL does not produce server files in the Windows 3.x/MS-DOS environment.

For this reason, if you specify the /env switch as /env dos or /env win16,

server stubs are not produced. To produce server stubs, specify that the

/env switch is either /env win32 or /env generic.

1.6 Working with Visual C++ on 16-Bit Machines

----------------------------------------------

Do not install the 16-bit RPC toolkit in the same directory as Visual C++.

MIDL requires the Microsoft C 7.0 front end for C preprocessing. The

installer will install the Microsoft C 7.0 front end if needed. Use the

/cpp_cmd switch to make sure MIDL is using the right C compiler.

1.7 Memory Leak Possible with Multiple Context Handles

-------------------------------------------------------

Memory can leak when data argument(s) precede context-handle argument(s)

and the call is directed by another handle. The leak happens on the server

side if the data requires memory allocation and if the context handle that

is used (as opposed to initialized) is invalid. The stub raises an

exception as it is supposed to, but it doesn't do the clean up.

1.8 Use Zero or Positive Values for the size_is and length_is Variables

-----------------------------------------------------------------------

You must use a zero or a positive value for the size_is and length_is

variables. A negative value for the size_is or length_is variable causes an

exception.

1.9 RPC Cannot Pass More than 63K Worth of Data on 16-Bit Platforms

--------------------------------------------------------------------

An MS-DOS or Windows 3.x system cannot pass more than 63K worth of data in

a single remote procedure call. Trying to pass more than 63K worth of data

results in undefined behavior.

1.10 Windows 3.x Applications Using the [callback] Attribute

-------------------------------------------------------------

If you use the [callback] attribute for a procedure specified in the IDL

file and if your application runs with Windows 3.x, you must compile all

stubs with the /GA C-compiler switch. Note that the /GA switch should not

be used for Windows callback functions (as opposed to RPC callback

functions) that are called in the context of another process.

1.11 Building RPC Samples with Visual C++ for Microsoft Windows NT

------------------------------------------------------------------

You can build RPC applications with the Visual C++ SDK for Microsoft

Windows NT using the RPC*.H files distributed with that SDK. To build RPC

samples with Visual C++ for Windows NT, add the following definition to

RPC.H (this applies to Intel processors only):

     #define     _CRTAPI1    _cdecl

Release Notes for RPC Run-Time/Transport Libraries & Windows NT Services

------------------------------------------------------------------------

2.0 The following release notes are related to the RPC run-time libraries,

transport libraries, and Windows NT services provided with Microsoft RPC

version 1.0.

2.1 RpcServerUseAllProtseqs Requires a Null Security Descriptor

---------------------------------------------------------------

The RpcServerUseAllProtseqs security-descriptor parameter must be set to

NULL in this release of Microsoft RPC version 1.0. The null parameter

allows everyone access.

2.2 Named-Pipes Security Descriptor

-----------------------------------

Named pipes (ncacn_np) allows everyone access when a null security

descriptor is supplied. This accessibility is independent of whether or not

the account used to start the server has a default ACL.

2.3 Multiple Networks

---------------------

The Microsoft Locator does not work with a router.

2.4 RpcNsBindingExport IP Addresses

-----------------------------------

If a server has two IP addresses and as a result is on two subnets,

RpcNsBindingExport adds only one of the two addresses to the name service.

For this reason, clients on one of the two networks cannot import a valid

handle to that server. Clients that already know the server address will

work using either well-known or dynamic endpoints.

2.5 SPX Transport Limitations

-----------------------------

The MS-DOS SPX transport does not function in a Windows DOS box or Windows

NT DOS box. The Windows SPX transport does not function in Windows standard

mode or in emulation mode with Windows NT.

2.6 All Machines Must Use the Same SPX Packet Size

--------------------------------------------------

To use the ncacn_spx protocol sequence (RPC over SPX), both the client and

the server must use the same maximum IPX packet size. Otherwise,

multipacket RPC calls will fail with RPC_S_CALL_FAILED. To adjust the

packet size on a machine running MS-DOS, Windows 3.x, or Windows for

Workgroups, add the following line to your NET.CFG or SHELL.CFG file:

   IPX PACKET SIZE LIMIT=xxxx

Here xxxx is the packet size in bytes.

Consult your Novell documentation for more information. Note that some

older drivers do not support setting IPX PACKET SIZE LIMIT.

To adjust the maximum packet size on machines running Windows NT, use

REGEDT32.EXE to set HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\

Services\NWLINKIPX\NetConfig\Driver01\MaxPktSize to the proper value.

Consult the Windows NT Resource Kit for more information on the registry.

2.7 Windows 3.x Applications Using TCP/IP Must Call RpcWinSetYieldInfo

----------------------------------------------------------------------

Applications based on Windows 3.x that use TCP/IP (ncacn_ip_tcp) must call

the RpcWinSetYieldInfo routine. Applications making RPC calls that don't

call RpcWinSetYieldInfo will always hit an exception. The exception occurs

because Windows Sockets API standard requires that applications yield while

using the network.

2.8 When Writing MS-DOS Applications, Avoid Calling _exit Directly

------------------------------------------------------------------

Always write your RPC applications for MS-DOS to call the complete

C-library termination function exit or _cexit rather than the quick

C-library termination function _exit or _c_exit because the

quick-termination functions do not call the atexit function. The MS-DOS

RPC run-time libraries use the atexit function to clean up system

resources. When you call the _exit or _c_exit function, the atexit function

is not invoked and resources are not freed correctly.

Release Notes for Installation & Configuration Issues for This Release

----------------------------------------------------------------------

3.0 The following release notes are related to installation and

configuration issues for this release:

3.1 Using Microsoft RPC with Microsoft Windows for Workgroups

-------------------------------------------------------------

To successfully run Microsoft RPC distributed applications with Microsoft

Windows for Workgroups version 3.1, you must use the Windows for Workgroups

network services. Stop all real-mode network services before starting

Windows for Workgroups. At the MS-DOS prompt, enter:

   net stop workstation /y

   win

3.2 Creating Installation Disks for Your Distributed Application

----------------------------------------------------------------

After you have developed your distributed application using Microsoft RPC,

you should provide a way for your users to install your application.

To enable your users to install your application, perform the following

steps when installing RPC:

1. Copy your executable files.

2. Copy Microsoft RPC run-time and transport DLLs.

3. Set Microsoft RPC-related registry entries as needed.

To provide an installation tool for your users, use the Microsoft Setup

Toolkit for Windows. Microsoft Setup provides important version-control

features that prevent users from overwriting newer versions of the RPC run-

time libraries with older, incompatible versions.

You can also use the template batch files provided with Microsoft RPC for

MS-DOS and Windows 3.x to help your users install your distributed

applications. The files DRUNDISK.BAT and WRUNDISK.BAT copy the Microsoft

RPC Setup program and associated files and direct the Microsoft RPC Setup

program to install all needed RPC system files. You must customize the .INF

file for your application. For more information about changing the .INF

file, see the documentation for the Microsoft Setup Toolkit for Windows.

If you use another installation method, you should implement some form of

version control. Version-control methods ensure that you do not distribute

incompatible versions of the RPC run-time and transport libraries that can

cause software errors in your application and other applications.

Some files include an embedded version-control number for use by the Setup

Toolkit for Windows. These files are noted in the lists below.

The following Microsoft Windows 3.x RPC files should be installed in the

system directory or in a directory specified by the LIBPATH environment

variable:

DNETAPI.DLL    Non-Microsoft environments for DEC PATHWORKS

               interoperability with Microsoft LAN Manager

NETAPI.DLL     Microsoft LAN Manager transport DLL; has version number

               for use with Microsoft Setup

RPCNS1.DLL     Microsoft RPC name-service provider

RPCRT1.DLL     Microsoft RPC client run-time library

RPC16C1.DLL    RPC transport DLL for client-side named pipes

RPC16C3.DLL    RPC transport DLL for client-side WinSock TCP/IP

RPC16C3X.DLL   RPC transport DLL for client-side WSOCKETS.DLL TCP/IP

RPC16C4.DLL    RPC transport DLL for client-side DECnet

RPC16C5.DLL    RPC transport DLL for client-side NetBIOS

RPC16C6.DLL    RPC transport DLL for client-side SPX

The following MS-DOS RPC files should be installed in a directory that is

specified by the PATH environment variable:

RPCNS.RPC      Microsoft RPC name-service provider

RPCNSLM.RPC    Microsoft RPC name-service provider LAN Manager support

RPCNSMGM.RPC   Microsoft RPC name-service provider support module

RPC16C1.RPC    RPC transport DLL for client-side named pipes

RPC16C3.RPC    RPC transport DLL for client-side TCP/IP

RPC16C4.RPC    RPC transport DLL for client-side DECnet

RPC16C5.RPC    RPC transport DLL for client-side NetBIOS

RPC16C6.RPC    RPC transport DLL for client-side SPX

You need not install the Microsoft Windows NT versions of the Microsoft RPC

run-time libraries and transports. Microsoft Windows NT computers support

Microsoft RPC version 1.0. If you want to run Microsoft Windows 3.x or

MS-DOS RPC applications with Microsoft Windows NT, install the above RPC

DLLs on the system.

Setting RPC Registry Entries

----------------------------

Your installation procedure should set any registry entries your

application needs. Registry entries are used by the RPC run-time libraries

and the RPC name-service provider to obtain information about the transport

an application intends to use.

By default, MS-DOS and Windows 3.x registry entries are present in the file

RPGREG.DAT in the root directory of the boot drive. You can use a different

file by setting the value of the environment variable RPC_REG_DATA_FILE to

the path and filename of the alternate file.

The RPC Setup program for MS-DOS and Microsoft Windows 3.x creates the

registry file RPCREG.DAT. If you write your own installation program, you

must create RPCREG.DAT and set appropriate entries for the name-service and

NetBIOS transports supported in that environment.

If the Microsoft Locator is the name-service provider:

   \Root\Software\Microsoft\Rpc\NameService\Protocol=ncacn_np

   \Root\Software\Microsoft\Rpc\NameService\NetworkAddress=\\.

   \Root\Software\Microsoft\Rpc\NameService\Endpoint=\pipe\locator

   \Root\Software\Microsoft\Rpc\NameService\DefaultSyntax=3

If CDS is the name-service provider via NSID:

   \Root\Software\Microsoft\Rpc\NameService\Protocol=ncacn_ip_tcp

   \Root\Software\Microsoft\Rpc\NameService\NetworkAddress=NSID host name

   \Root\Software\Microsoft\Rpc\NameService\Endpoint=

   \Root\Software\Microsoft\Rpc\NameService\DefaultSyntax=3

The NetBIOS transport entries have the following form:

   \Root\Software\Microsoft\Rpc\NetBios\ncacn_nb_<A><B>=<C>

Where:

   <A> is the NetBIOS sub-protocol sequence (nb, ipx, or tcp).

   <B> is a unique digit for each protocol sequence.

   <C> is the lana number.

For example, if you have two net cards in a system, running NetBEUI on both

and TCP/IP on one, and the lana numbers on the system are configured as

NetBEUI on card0 is 0, TCP/IP on card0 is 1, and NetBEUI on card1 is 2,

then the RPC NetBIOS registry entries are:

   \Root\Software\Microsoft\Rpc\NetBios\ncacn_nb_nb0=0

   \Root\Software\Microsoft\Rpc\NetBios\ncacn_nb_nb1=2

   \Root\Software\Microsoft\Rpc\NetBios\ncacn_nb_tcp0=1

For more information about the strings generated in the file RPCREG.DAT,

run Microsoft RPC Setup and inspect the strings.

REFERENCES

RPCREAD.ME in \MSTOOLS\SAMPLES\RPC in Win32SDK for Windows NT version 3.1

on MSDN.

Additional reference words: 6.20 3.10

KBCategory: kbnetwork kbref kbtshoot kbdocerr

KBSubcategory: NtwkRpc


DOCERR: Important Information on RPC 2.0 Missing from the

PSS ID Number: Q129143

Authored 18-Apr-1995	Last modified 19-Apr-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows for

   Workgroups version 3.11

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.5

SUMMARY

This article contains important information not included in the Microsoft

RPC programming documentation or in Help about Microsoft RPC version 2.0.

This information is identical to the information provided in the RPCREAD.ME

file in the Win32 SDK (MSTOOLS\SAMPLES\RPC\) for Windows NT version 3.5.

Microsoft RPC is a toolkit for developing distributed applications in

C/C++. The toolkit includes:

 - MIDL compiler for Microsoft Windows NT.

 - C/C++ language header files and run-time libraries for Windows NT,

   Microsoft Windows versions 3.x, and MS-DOS.

 - Sample programs for Windows NT, Windows versions 3.x, and MS-DOS.

MORE INFORMATION

This article is organized into the following sections:

 - Installation

 - Documentation

 - Before Using RPC

 - MIDL Issues

 - Run-Time API Issues

Installation

------------

The Windows NT SDK provides the components of the RPC toolkit as part of

its standard installation. No additional installation is required. To

produce MS-DOS and Windows 3.x RPC clients, install version 1.50 of the

Microsoft Visual C/C++ development environment, and then install the MS-

DOS/Win16 RPC tookit from disk. To install the MS-DOS/Windows 3.x version

of the RPC toolkit, use the Setup program in the MSTOOLS\RPC_DOS\DISK1

directory.

Because the 16-bit MIDL compiler is no longer supported, you must develop

applications using the 32-bit MIDL compiler. However, to write MS-DOS or

Windows 3.x applications without a 32-bit C/C++ compiler capable of

targeting MS-DOS, you must compile the IDL file with a 32-bit MIDL compiler

on Windows NT. Then, compile the application and stubs using your C/C++

compiler. To write MS-DOS or Windows 3.x applications using a 32-bit C/C++

compiler that is capable of targeting MS-DOS, compile both the IDL file and

C/C++ files on Windows NT.

Documentation

-------------

The RPC Programmer's Guide and Reference is available in Help and includes

conceptual material, MIDL language and command-line references, and

run-time API references.

Because many new features have been included in this version of Microsoft

RPC, see the New in this Version of RPC help topic.

RPC sample program source files are available in the directory

MSTOOLS\SAMPLES\RPC. The MSTOOLS\SAMPLES\RPC\README.TXT file describes each

sample.

Before Using RPC

----------------

Read the following section on MIDL and run-time API issues before

attempting to use this version of RPC. These sections contain important

information that is not documented in Help.

MIDL Issues

-----------

The 16-bit MIDL compiler for MS-DOS or Windows 3.x is no longer supported.

Use the 32-bit MIDL compiler switch /env with either the DOS or WIN16

option.

Note the following when using this version of the MIDL compiler:

 - When compiling the generated stubs, warnings about different levels of

   pointer indirection or different const specifications are benign.

 - When using the DOS or WIN option of the -env switch, the compiler will

   not set the correct packing level to 2. In this case, you must

   explicitly specify the correct packing level by using the /Zp or /pack

   switch.

 - For Alpha platforms, procedure serialization stubs must be compiled on

   the C compiler by using the -Od switch. The procedure encoding/decoding

   stubs on the Alpha platform should not be compiled as optimized (for

   example, using the -Ox switch). This affects the stubs on the Alpha

   platform only if the serializing procedure uses one of the following

   attributes on top-level parameters:

    - array or ptr attributes, such as size_is or length_is.

    - The switch_is union attribute.

 - A structure whose only member is a conformant string results in an MIDL

   compiler assert.

 - In the osf mode of the compiler, the default allocate and free routines

   map to NdrRpcSmClientAllocate and NdrRpcSmClientFree. The signatures for

   these routines are in RPCNDR.H

Run-Time API Issues

-------------------

When using the ncacn_spx and ncadg_ipx transports, the server name is

exactly the same as the Windows NT server name. However, because the names

are distributed using Novell protocols, they must conform to the Novell

naming conventions. If a server name is not a valid Novell name, servers

will not be able to create endpoints with the ncacn_spx or ncadg_ipx

transports. The following is a partial list of characters prohibited in

Novell server names:

   "  *  +  .  /  :  ;  <  =  >  ?  [  ]  \  |

When using ncadg_ipx on Windows 3.x or MS-DOS platforms, use the Windows NT

3.1 model of server naming. That is, a tilde, followed by the servers eight-

digit network number, followed by its twelve-digit Ethernet address.

The ncacn_spx transport is not supported by the version of NWLink supplied

with MS Client 3.0; however, ncadg_ipx is supported.

Backslashes are now optional in the host name for ncacn_np, for consistency

with the other transports.

The datagram protocols (ncadg_ipx, ncadg_ip_udp) have the following

limitations:

 - They do not support callbacks. Any functions using the callback

   attribute will fail.

 - They do not support the RPC security API (RpcBindingSetAuthInfo,

   RpcImpersonateClient, and so on).

Only the ncacn_spx and ncacn_ip_tcp protocols support cancels. For all

other protocols, the cancel routines will return RPC_S_OK, but there will

be no effect. Specifically:

 - RpcCancelThread will alert the specified thread, but will not interrupt

   a pending RPC.

 - RpcTestCancel will return RPC_S_OK if the current thread has been

   alerted.

 - RpcMgmtSetCancelTimeout has no visible effect.

RpcTestCancel, RpcMgmtSetCancelTimeout, and RpcCancelThread are only

supported on Windows NT platforms; all other platforms return

RPC_S_CANNOT_SUPPORT.

The function RpcBindingSetAuthInfo does not accept the value

RPC_C_AUTHN_DEFAULT.

To use the RpcBindingSetAuthInfo routine and, in particular, when using

MS-DOS authentication in this version of RPC, note this information:

 - The constant RPC_C_AUTHN_WINNT has been defined in the header RPCDCE.H.

   This constant should be passed as the AuthnSvc parameter to use the

   Windows NT LAN Manager Security Support Provider (NTLMSSP) service.

 - When using the RPC_C_AUTHN_WINNT authentication service, the

   AuthIdentity parameter should be a pointer to a SEC_WINNT_AUTH_IDENTITY

   structure, defined in RPCDCE.H. This structure contains strings for the

   user's domain, username, and password. You can pass a NULL pointer to

   use the information for the currently logged-in user.

For MS-DOS, you cannot pass NULL because there is no way for RPC to

determine the current user's logon information. However, either a structure

or NULL is acceptable for Windows versions 3.x and Windows NT.

When using authenticated RPC on a system composed of Novell NetWare and

Windows version 3.x (not Windows for Workgroups), you must run the optional

NETBIOS.EXE program before starting Windows.

The 16-bit SDK cannot be installed on a Windows NT computer unless the

current user is an administrator.

Supported Platforms for Runtime APIs

------------------------------------

The following function is supported only by 16-bit Windows 3.x platforms:

RpcWinSetYieldInfo

The following functions are supported only by 32-bit Windows NT platforms:

DceErrorInqTest

RpcBindingInqAuthClient

RpcBindingServerFromClient

RpcCancelThread

RpcEpRegister

RpcEpUnregister

RpcIfIdVectorFree

RpcImpersonateClient

RpcNetworkInqProtseqs

RpcObjectInqType

RpcObjectSetInqFn

RpcObjectSetType

RpcProtseqVectorFree

RpcRevertToSelf

RpcServerInqBindings

RpcServerInqIf

RpcServerListen

RpcServerRegisterAuthInfo

RpcServerRegisterIf

RpcServerUnregisterIf

RpcServerUse*Protseq*

RpcMgmtInqIfIds

RpcMgmtInqStats

RpcMgmtIsServerListening

RpcMgmtInqServerPrincName

RpcMgmtSetAuthorizationFn

RpcMgmtSetCancelTimeout

RpcMgmtSetServerStackSize

RpcMgmtStatsVectorFree

RpcMgmtStopServerListening

RpcMgmtWaitServerListen

RpcMgmtEnableIdleCleanup

RpcMgmtEpElt*

RpcMgmtEpUnregister

RpcNsBindingExport

RpcNsBindingUnexport

RpcTestCancel

All other runtime functions are supported on Windows NT, Windows 3.x, and

MS-DOS platforms.

REFERENCES

RPCREAD.ME in \MSTOOLS\SAMPLES\RPC in Win32SDK for Windows NT 3.5 on MSDN.

Additional reference words: 6.20 3.50

KBCategory: kbnetwork kbtshoot kbref kbdocerr

KBSubcategory: NtwkRpc


DOCERR: Media Player Command-Line Switches

PSS ID Number: Q126869

Authored 06-Mar-1995	Last modified 15-May-1995

The information in this article applies to:

 - Microsoft Windows operating system versions 3.1, 3.11

 - Microsoft Windows for Workgroups versions 3.1, 3.11

 - Microsoft Windows NT versions 3.5, 3.51

 - Microsoft Windows Software Development Kit (SDK), version 3.1

 - Microsoft Win32 SDK, versions 3.5 and 3.51

Media Player (both the 16-bit MPLAYER.EXE and the 32-bit MPLAY32.EXE)

supports the following command-line syntax:

   MPLAYER /play /close /embedding file

All of the command-line switches and the file name are optional. Their

meanings are as follows:

   /play       Play file right away.

   /close      Close after playing (only valid with /play).

   /embedding  Run as an OLE server.

   file        The file or device to open.

This information was inadvertently omitted from the Windows documentation.

In Windows 95 and Windows NT 3.5 and higher, the Media Player also supports

the following switch:

   /open       Open the file if specified; otherwise, show the File Open

               dialog.

In addition, the following switches can be used to ensure that the

specified file is of a particular type:

   /VFW        The file must be a Video for Windows (.AVI) file.

   /MID        The file must be a MIDI (.MID) file.

   /WAV        The file must be a Wave Audio (.WAV) file.

Additional reference words: 3.10 3.50 4.00 undocumented win31 wfw wfwg

KBCategory: kbdocerr kbmm

KBSubcategory: MMMisc


DOCERR: TabbedTextOut Tab Positions Really in Logical Units

PSS ID Number: Q113253

Authored 29-Mar-1994	Last modified 22-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.1 and 3.5

Both the printed and electronic documentation from the Windows 3.0 and 3.1

SDKs, as well as the Win32 SDK, state that the tab positions parameter of

TabbedTextOut() is in device units. This is incorrect. The tab position

array is in logical units. The Windows 3.0 and 3.1 SDKs refer to the tab

position array as lpnTabPositions, while the Win32 SDK calls it

lpnTabStopPositions.

The use of logical units can be seen by using a mapping mode other than the

default MM_TEXT. The output of tabs using TabbedTextOut() reflects the

mapping mode.

Additional reference words: 3.00 3.10 3.50 docerr

KBCategory: kbprg kbdocerr

KBSubcategory: GdiDrw


Drawing a Rubber Rectangle

PSS ID Number: Q114471

Authored 04-May-1994	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK), version 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

Most drawing software uses what is termed a "rubber rectangle". This term

is used to describe the situation where

1. the left mouse button is held down, defining one corner of the

   rectangle

2. the mouse is dragged and released at the point defining the opposite

   corner of the rectangle

3. the rectangle is drawn while the mouse is being dragged, so that it

   looks like the rectangle is being stretched and contracted, like a

   rubber band

MORE INFORMATION

The key to making this work is in the following call, which should be

made in the WM_LBUTTONDOWN case:

   SetROP2( hDC, R2_NOT )

On each WM_MOUSEMOVE message, the rectangle is redrawn in its previous

position. Because of the ROP code, the rectangle appears to be erased. The

new position for the rectangle is calculated and then the rectangle is

drawn.

Note that Windows will only let you draw in the invalid area of the window

if you use a DC returned from BeginPaint(). If you want to use the DC

returned from BeginPaint(), you must first call InvalidateRect() to specify

the region to be updated.

With the DC returned from GetWindowDC(), Windows will restrict your drawing

to the client and non-client areas. With the hDC returned from CreateDC(),

you can write on the entire display, so you must be careful.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: GdiDrw


Drawing Outside a Window's Client Area

PSS ID Number: Q33096

Authored 18-Jul-1988	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

When an application uses the BeginPaint or GetDC function to obtain a

device context (DC) for its client window and draws into this DC,

Windows clips the output to the edge of the client window. While this

is usually the desired effect, there are circumstances where an

application draws outside the client area of its window.

MORE INFORMATION

The GetWindowDC function provides a DC that allows an application to

draw anywhere within its window, including the nonclient area.

In the Windows environment, the display is a scarce resource that is

shared by all applications running in the system. Most of the time, an

application should restrict its output to the area of the screen it

has been assigned by the user. However, an application can use the

CreateDC function to obtain a DC for the entire display, as follows:

   hDC = CreateDC("DISPLAY", NULL, NULL, NULL);

Device contexts are another scarce resource in the Windows

environment. When an application creates a DC in response to a

WM_PAINT message, it must call the DeleteDC function to free the DC

before it completes processing of the message.

Painting in the nonclient area of a window is not recommended. If an

application changes the nonclient area of its window, the user can

become confused because the familiar Windows controls change

appearance or are not available. An application should not corrupt

other windows on the display.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: GdiDc


DSKLAYT2 Does Not Preserve Tree Structure of Source Files

PSS ID Number: Q87947

Authored 12-Aug-1992	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.5

 - Microsoft Win32 SDK, versions 3.1, 3.5, 3.51, and 4.0

The DSKLAYT2 utility in the Microsoft Setup Toolkit for Windows creates

disk images using the files specified in the .LYT file produced by the

DSKLAYT utility. The created disk images are flat; all files are placed in

the root directory. DSKLAYT2 does not preserve the tree structure of the

source files.

Having flat directories on the setup disks is a limitation of only the

DSKLAYT2 utility. _MSTEST.EXE, the setup driver spawned by SETUP.EXE,

supports a tree structure on the setup disks. Once DSKLAYT2 creates disk

images, manually create subdirectories on each disk. Then move files from

the root directory of the disk to the appropriate position in the tree

structure. (Do not move files between disks.) Make corresponding changes to

the .INF file. In the file description line of each moved file, change the

filename to indicate the file's new location in the tree structure.

Additional reference words: 3.10 3.50 4.00 95  MSSetup tool kit

KBCategory: kbtool

KBSubcategory: TlsMss


Dsklayt2 Does Not Support Duplicate Filenames

PSS ID Number: Q87906

Authored 11-Aug-1992	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

The Dsklayt2 utility in the Microsoft Setup Toolkit for Windows does

not support duplicate filenames in the source tree. If two or more

files have the same name, Dsklayt2 may place more than one of these

files into the root directory of the same setup disk. If this happens,

Dsklayt2 generates a warning message when it creates a disk image for

the disk that warns that the first file is overwritten.

If two or more files in the source tree for an application share the

same name, rename all but one of the files before running the Dsklayt

utility. Use the Rename Copied File option in the Dsklayt utility to

have the filenames changed back to their original names when SETUP.EXE

or _MSTEST.EXE copies the files from the setup disk to the destination

disk.

When Dsklayt2 creates a compressed file, it adds an underscore (_) to

the end of the file extension, replacing the third character if

necessary. Therefore, Dsklayt2 does not support compressed files if

the names of the uncompressed files differ only in the third character

of the file extension.

Additional reference words: 3.10 3.50 4.00 95 MSSetup tool kit

KBCategory: kbtool

KBSubcategory: TlsMss


Dynamic Loading of Win32 DLLs

PSS ID Number: Q90745

Authored 21-Oct-1992	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

When using LoadLibrary() under Win16 or OS/2, the Dynamic Link Library

(DLL) is loaded only once. Therefore, the DLL has the same address in all

processes. Dynamic loading of DLLs is different under Windows NT.

A DLL is loaded separately for each process because each application has

its own address space, unlike Win16 and OS/2. Pages must be mapped into the

address space of a process. Therefore, it is possible that the DLL is

loaded at different addresses in different processes. The memory manager

optimizes the loading of DLLs so that if two processes share the same pages

from the same image, they will share the same physical memory.

Each DLL has a preferred base address, specified at link time. If the

address space from the base address to the base address plus image size is

unavailable, then the DLL is loaded elsewhere and fixups will be applied.

There is no way to specify a load address at load time.

To summarize, at load time the system:

1. Examines the image and determines its preferred base address and

   required size.

2. Finds the address space required and maps the image, copy-on-write,

   from the file.

3. Applies internal fixups if the image isn't at its preferred base.

4. Fixes up all dynamic link imports by placing the correct address for

   each imported function in the appropriate entry of the Import Address

   Table. This table is contiguous with 32-bit addresses, so 1024 imports

   require dirtying only one page.

MORE INFORMATION

The pages containing code are shared, using a copy-on-write scheme. The

term copy-on-write means that the pages are read-only; however, when a

process writes the page, instead of an access violation, the memory manager

makes a private copy of the page and allows the write to proceed. For

example, if two processes start from the same .EXE, both initially have all

pages mapped from the .EXE copy-on-write. As the two processes proceed to

modify pages, they get their own copies of the modified pages. The memory

manager is free to optimize unmodified pages and actually map the same

physical memory into the address space of both processes. Modified pages

are swapped to/from the page file instead of the .EXE file.

There are two kinds of fixups. One is the address of an imported function.

All these fixups are localized in what the Portable Executable (PE)

specification calls the Import Address Table (IAT). This is an array of 32-

bit function pointers, one for each imported API. The IAT is located on its

own page(s), because it is always modified. Calling an imported function is

actually an indirect call through the appropriate entry in this array. In

case that the image is loaded at the preferred address, the only fixups

needed are for imports.

Note that there is an optimization whereby each import library exports a 32-

bit number for each API along with any name and ordinal. This serves as a

"hint" to speed the fixups performed at load time. If the hints in the

program and the DLL do not match, the loader uses a binary search by name.

The other kind of fixup is needed for references to the image's own code or

data when the image can't be loaded at its preferred address. When a page

must be taken out of memory, the system checks to see whether the page has

been modified. If it has not, then the page is still mapped copy-on-write

against the EXE and can be discarded from memory. Otherwise, it must be

written to the page file before it can be removed from memory, so that the

page file is used as the backing store (where the page is recovered from)

rather than the executable image file.

NOTES

The DLL's entry point does not get called for a second LoadLibrary() call

in a process (that is, no second DLL_PROCESS_ATTACH entry). There is one

call to DllEntry/DLL_THREAD_ATTACH per thread no matter the number of times

a thread calls LoadLibrary(). The same goes for FreeLibrary(), but the

DLL_PROCESS_DETACH happens only on the last call (that is, reference count

back to zero for the process).

Global instance data for the DLL is on a per process basis (only one set

per unique process). If it is necessary to ensure that global instance data

is unique for each LoadLibrary() performed in a single process, consider

thread local storage (TLS) as an alternative. This requires multiple

threads of execution, but TLS allows unique data for each ThreadID. There

is very little overhead on the DLL's part; just create a global TLS index

during process initialization. During thread initialization, allocate

memory (via HeapAlloc(), GlobalAlloc(), LocalAlloc(), malloc(), and so on)

and store a pointer to the memory using the global TLS index value in the

function TlsSetValue. Win32 internally stores each thread's pointer by TLS

index and ThreadID to achieve the thread specific storage.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: BseDll


Efficiency of Using SendMessage Versus SendDlgItemMessage

PSS ID Number: Q66944

Authored 14-Nov-1990	Last modified 18-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.1 and 3.0

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

The SendDlgItemMessage function is equivalent to obtaining the

handle of a dialog control using the GetDlgItem function and then

calling the SendMessage function with that handle. The

SendDlgItemMessage function therefore takes slightly longer to

execute than the SendMessage function for the same message, because

an extra call to the GetDlgItem function is required each time the

SendDlgItemMessage function is called.

The GetDlgItem function searches through all controls in a given

dialog box to find one that matches the given ID value. If there are

many controls in a dialog box, the GetDlgItem function can be quite

slow.

If an application needs to send more than one message to a dialog

control at one time, it is more efficient to call the GetDlgItem

function once, using the returned handle in subsequent SendMessage

calls. This saves Windows from searching through all the controls

each time a message is sent. The SendMessage function should also be

used when your application retains handles to controls that receive

messages.

However, if your application needs to send one message to many

controls, such as sending WM_SETFONT messages to all the controls in a

dialog, then the SendDlgItemMessage function will save code in the

application because a call to the GetDlgItem function is not made for

each control.

Note that if the message sent to a control may result in a lengthy

operation (such as sending the LB_DIR message to a list box), then the

overhead in the GetDlgItem call is negligible. Either the

SendDlgItemMessage or SendMessage can be used, whichever is more

convenient.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95  dlgitem

KBCategory: kbprg

KBSubcategory: UsrDlgs


EM_SETHANDLE and EM_GETHANDLE Messages Not Supported

PSS ID Number: Q130759

Authored 25-May-1995	Last modified 22-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) version 4.0

SUMMARY

The EM_GETHANDLE and EM_SETHANDLE messages are not supported for edit

contols that are created as controls of a 32-bit application under Windows

95. This is due to the way USER is designed under Windows 95. 16-bit

applications work the same way they did under Windows version 3.1. That is,

they can use the EM_GET/SETHANDLE messages. Also Win32-based applications

running under Windows NT will be able to use these messages.

MORE INFORMATION

The EM_GETHANDLE and EM_SETHANDLE messages are used to retrieve and set the

handle of the memory currently allocated for a multiline edit control's

text. USER under Windows 95 is a mixture of 16- and 32-bit code, so edit

controls created inside a 32-bit application cannot use these messages to

retrieve or set the handles. Trying to do so causes the application to

cause a general protection (GP) fault and thereby be terminated by the

System.

One workaround that involves a little code modification is to use the

GetWindowTextLengt(), GetWindowText(), and SetWindowText() APIs to retrieve

and set the text in a edit control.

NOTE: USER is almost completely 16-bit, so 32-bit applications thunk down

to the 16-bit USER. Also note that the EM_GETHANDLE and EM_SETHANDLE

messages cannot be used with Win32s-based applications either.

Additional reference words: 4.00 user controls GPF

KBCategory: kbprg

KBSubcategory: UsrCtl


Enumerating Network Connections

PSS ID Number: Q119216

Authored 10-Aug-1994	Last modified 26-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

From the MS-DOS prompt, you can enumerate the network connections (drives)

by using the following command:

   net use

Programmatically, you would call WNetOpenEnum() to start the enumeration of

connected resources and WNetEnumResources() to continue the enumeration.

MORE INFORMATION

The following sample code enumerates the network connections:

Sample Code

-----------

   #include <windows.h>

   #include <stdio.h>

   void main()

   {

      DWORD dwResult;

      HANDLE hEnum;

      DWORD cbBuffer = 16384;

      DWORD cEntries = 0xFFFFFFFF;

      LPNETRESOURCE lpnrDrv;

      DWORD i;

      dwResult = WNetOpenEnum( RESOURCE_CONNECTED,

                               RESOURCETYPE_ANY,

                               0,

                               NULL,

                               &hEnum );

      if (dwResult != NO_ERROR)

      {

         printf( "\nCannot enumerate network drives.\n" );

         return;

      }

      printf( "\nNetwork drives:\n\n" );

      do

      {

         lpnrDrv = (LPNETRESOURCE) GlobalAlloc( GPTR, cbBuffer );

         dwResult = WNetEnumResource( hEnum, &cEntries, lpnrDrv, &cbBuffer

   );

         if (dwResult == NO_ERROR)

         {

            for( i = 0; i < cEntries; i++ )

            {

               if( lpnrDrv[i].lpLocalName != NULL )

               {

                  printf( "%s\t%s\n", lpnrDrv[i].lpLocalName,

                                      lpnrDrv[i].lpRemoteName );

               }

            }

         }

         else if( dwResult != ERROR_NO_MORE_ITEMS )

         {

            printf( "Cannot complete network drive enumeration" );

            GlobalFree( (HGLOBAL) lpnrDrv );

            break;

         }

         GlobalFree( (HGLOBAL) lpnrDrv );

      }

      while( dwResult != ERROR_NO_MORE_ITEMS );

      WNetCloseEnum(hEnum);

   }

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: NtwkWinnet


ERROR_BUS_RESET May Be Benign

PSS ID Number: Q111837

Authored 20-Feb-1994	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

SUMMARY

Tape API (application programming interface) functions may return an error

code of ERROR_BUS_RESET when operating on SCSI tape devices. In many cases,

you can ignore this error value and retry the operation. However, this

error is fatal if received during a series of write operations because a

tape drive cannot recover from a bus reset and continue writing.

MORE INFORMATION

When Windows NT boots up it resets the SCSI bus. This bus reset is reported

by the tape drive in response to the first operation after the reset.

The code fragment shown below in the Sample Code section could be used to

check for ERROR_BUS_RESET and clear it. The same technique could be used

for other informational errors, such as ERROR_MEDIA_CHANGED, that may not

be relevant at application startup.

Sample Code

-----------

/*

** This is a code fragment only and will not compile and run as is.

*/

   ...

   do {

      dwError = GetTapeStatus(hTape);

   } while (dwError == ERROR_BUS_RESET);

   ...

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseFileio


Establishing Advise Loop on Same topic!item!format! Name

PSS ID Number: Q95983

Authored 03-Mar-1993	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

Sometimes more than one DDEML client application might establish an

advise loop with a server on the same topic!item!format name set. This

article discusses the complexities involved in such a transaction.

MORE INFORMATION

A client application sends an XTYP_ADVSTART to DDEML when it needs

periodic updates on a particular data item from a server, typically

when that particular data item's value changes.

The server application calls DdePostAdvise whenever the value of the

requested data item changes. This results in an XTYP_ADVREQ

transaction being sent to the server's DDEML callback function, where

the server returns a handle to the changed data.

The client then receives the updated data item during the XTYP_ADVDATA

transaction in the case of a hot advise loop. In a warm advise loop,

the XTYP_ADVDATA transaction that the client receives in its callback

does not contain data; it has to specifically request data with an

XTYP_REQUEST transaction.

When more than one client application requests an advise loop on the

same topic!item!format name set, DDEML maintains a list of these

client applications so that it knows that on one call to

DdePostAdvise(), it should send the changed hData to all the

requesting applications in its list.

The server's callback receives an XTYP_ADVREQ transaction as a result

of DdePostAdvise() with the LOWORD (dwData1) containing a count of the

number of ADVREQ transactions remaining to be processed on the same

topic!item!format name set.

This count allows the server application to create its hData as

HDATA_APPOWNED, whereby it could create a data handle just once and

pass the same handle on to its other pending requests on the same

topic!item!format name set. Finally, when the count is down to zero,

DdeFreeDataHandle() can then be called on this hData.

Note that a server needs to call DdePostAdvise() only once regardless

of how many pending advise requests it has on the same

topic!item!format name set. This one call to DdePostAdvise() causes

DDEML to send the appropriate number of XTYP_ADVREQ transactions to

the server's callback.

All these can be easily illustrated using the Windows version 3.1 Software

Development Kit (SDK) DDEML CLIENT and SERVER samples in this manner:

1. Start the SERVER application.

2. a. Start the CLIENT application.

   b. Establish a connection with the SERVER.

   c. Start an advise loop on the item "Rand".

3. a. Start another instance of the client application.

   b. Establish a connection with the SERVER.

   c. Start an advise loop on the item Rand.

4. Bring up DDESPY.

5. Go back to the SERVER and choose ChangeData from the Options menu and

   watch both CLIENT applications update their data.

Results (from DDESPY main window):

1. Two XTYP_ADVREQs (because you have two pending ADVREQs on the same

   test!Rand pair.

2. Changed Rand data is then sent to the first CLIENT in the advise list.

3. The first CLIENT in the advise list receives the data via XTYP_ADVDATA.

4. Changed "Rand" data is sent to the second CLIENT in the advise list.

5. The second CLIENT in the advise list receives its XTYP_ADVDATA.

One caveat to this scenario is when an advise loop is invoked with the

XTYPF_ACKREQ flag set (that is, the client establishes an

XTYP_ADVSTART transaction or'ed with the XTYPF_ACKREQ flag). In this

case, the server does not send the next data item until an ACK is

received from the client for the first data item. During a particular

call to DdePostAdvise(), the server might not necessarily receive

XTYP_ADVREQ in its callback for all active links, and the

LOWORD(dwData1) might not necessarily reach 0 (zero). When the

DDE_FACK from the client finally arrives, DDEML then sends the server

an XTYP_ADVREQ with LOWORD(dwData1) set to CADV_LATEACK, identifying

the late-arriving ACK appropriately.

Advise links of this kind (with XTYPF_ACKREQ flag set) are best suited

to situations where the server sends information faster than a client

can process it--setting the XTYPF_ACKREQ bit ensures that the server

never outruns the client. However, setting this flag also sets a

drawback in circumstances where data transitions may be lost. Thus, in

Windows NT or in similar situations where server outrun is highly

unlikely, it is recommended that the XTYPF_ACKREQ bit not be used to

prevent such data transition loss.

Note that in this delayed ACK update scenario, the count received in

the LOWORD (dwData1) may not be relied upon for creating APPOWNED data

handles as discussed in the earlier paragraphs; where an hData is

created once, and when the count is down to zero, DdeFreeDataHandle()

is called on this hData.

This does not, however, imply that the efficiency provided by APPOWNED

data handles may not be used at all. In this case, a server could

create an APPOWNED data handle once--usually on the first XTYP_ADVREQ

it receives--and associate that handle with a topic!item!format name

set. It could then return this data handle for all subsequent requests

it receives on this topic!item!format set. Each time data changes

thereafter, the server should destroy the old data handle and not

re-render the data [that is, call DdeCreateDataHandle()] until another

request comes through.

This might be better explained as follows:

      case XTYP_ADVREQ:

           if (ThisIsForTheTopicItemFormatSpecified)

           {

               if (bFirstTimeRequested)

                  {

                      bFirstTimeRequested = FALSE;

                      hData = DdeCreateDataHandle();

                   }

                return hData;

            }

            break;

     // and then whenever data changes for this topic!item!format

         if (hData)

           {

             DdeFreeDataHandle (hData);

             bFirstTimeRequested = TRUE;

            }

         DdePostAdvise();         // specify topic!item!format here.

                                  // This causes DDEML to send an

XTYP_ADVREQ

                                  // which is handled above.

For Microsoft Windows version 3.1 DDEML, the only way for a server

application to distinguish which client's advise request is currently

being responded to is through the XTYP_ADVREQ's hConv parameter. The

hConvPartner field of the CONVINFO structure may be used to

distinguish between clients.

Additional reference words: 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrDde


Examining the dwOemId Value

PSS ID Number: Q101190

Authored 07-Jul-1993	Last modified 22-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

The Win32 application programming interface (API) GetSystemInfo() fills in

the members of a SYSTEM_INFO structure. The dwOemId member represents a

computer identifier that is specific to a particular OEM (original

equipment manufacturer). Windows NT versions 3.1 - 3.51 and Windows 95

always place a zero in the dwOemId member. In later releases, this behavior

will change to include different OEM IDs.

Additional reference words: 3.10 3.50 4.00

KBCategory: kbprg

KBSubcategory: BseMisc


Explanation of the NEWCPLINFO Structure

PSS ID Number: Q103315

Authored 22-Aug-1993	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

The following is an explanation of the NEWCPLINFO structure:

dwSize: Specifies the length of the structure, in bytes. Set this to

sizeof(NEWCPLINFO).

dwFlags: Specifies Control Panel flags. This is field is currently

unused. Set this field to NULL.

dwHelpContext: Specifies the context number for the topic in the help

project (.HPJ) file that displays when the user selects help for the

application. If dwData is non-NULL, Windows Help will be invoked with

the HELP_CONTEXT fuCommand with dwHelpContext as dwData. If

dwHelpContext is NULL, Windows Help is invoked with the HELP_INDEX

fuCommand.

lData: Specifies data defined by the application. This is passed back

to the application in the CPL_DBLCLK, CPL_SELECT, and CPL_STOP

messages via lParam2.

hIcon: Identifies an icon resource for the application icon. This icon

is displayed in the Control Panel window.

szName: Specifies a null-terminated string that contains the

application name. The name is the short string displayed below the

application icon in the Control Panel window. The name is also

displayed in the Settings menu of Control Panel.

szInfo: Specifies a null-terminated string containing the application

description. The description is displayed at the bottom of the Control

Panel window when the application icon is selected.

szHelpFile: Specifies a null-terminated string that contains the path

of the help file, if any, for the application. If this field is

unused, set it to NULL. The Control Panel will invoke a default

Windows Help file when this field is NULL.

Additional reference words: 3.10 3.50 3.51 4.00 95  cpl control panel

extension

KBCategory: kbprg

KBSubcategory: UsrExt


Exporting Callback Functions

PSS ID Number: Q83706

Authored 19-Apr-1992	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

It is not necessary for Win32-based applications to export callback

functions. Windows versions 3.1 and earlier (Win16) need callback functions

primarily for fixing references to global data and ensuring that EMS memory

is not paged out. Neither of these situations applies to the Windows NT

operating system.

MORE INFORMATION

Exports are necessary for any function that must be located at either

 - Run time via GetProcAddress()(dynamic linking)

   -or-

 - Load time via an import library (static linking)

Both of these linking methods require that the name or ordinal number of

the export be known and that their names (or ordinal numbers) be present in

the executable's exported entry table. This enables Windows to determine

the addresses at run time.

Static linking is done by the loader, which performs this lookup for all of

the imported entry points that an executable needs (normally by ordinal

number). In dynamic linking, the system scans by ordinal number or by name

through the DLL (Dynamic Link Library) exports table.

In Win16, exported entries are automatically fixed by the linker to adjust

to the appropriate data segment. Exporting entries on Win32 just adds them

to the module's exported names and ordinal numbers table; the linker does

not need to "fix" them. For code compatibility with Win16, you may want to

continue to use MakeProcInstance() and export all callbacks. This macro

does nothing on Windows NT.

In short,

                    On Windows                       Win32

                    ---------------------------      -----------------

   Callbacks        Export or use MakeProcInstance   Use address of fn

   GetProcAddress   Must export                      Must export

   Static linking   Must export                      Must export

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: BseDll


Exporting Data from a DLL or an Application

PSS ID Number: Q90530

Authored 18-Oct-1992	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1, 3.5, 3.51, and 4.0

SUMMARY

It is possible for a Win32-based application to be able to address DLL

global variables directly by name from within the executable. This is done

by exporting global data names in a way that is similar to the way you

export a DLL function name. Use the following steps to declare and utilize

exported global data.

1. Define the global variables in the DLL code. For example:

      int i = 1;

      int *j = 2;

      char *sz = "WBGLMCMTP";

2. Export the variables in the module-definition (DEF) file. With the 3.1

   SDK linker, use of the CONSTANT keyword is required, as shown below:

   EXPORTS

      i  CONSTANT

      j  CONSTANT

      sz CONSTANT

   With the 3.5 SDK linker or the Visual C++ linker, use of the DATA

   keyword is required, as shown below

   EXPORTS

      i  DATA

      j  DATA

      sz DATA

   Otherwise, you will receive the warning

      warning LNK4087: CONSTANT keyword is obsolete; use DATA

   Alternately, with Visual C++, you can export the variables with:

      _declspec( dllexport ) int i;

      _declspec( dllexport ) int *j;

      _declspec( dllexport ) char *sz;

3. If you are using the 3.1 SDK, declare the variables in the modules that

   will use them (note that they must be declared as pointers because a

   pointer to the variable is exported, not the variable itself):

      extern int *i;

      extern int **j;

      extern char **sz;

   If you are using the 3.5 SDK or Visual C++ and are using DATA, declare

   the variables with _declspec( dllimport ) to avoid having to manually

   perform the extra level of indirection:

      _declspec( dllimport ) int i;

      _declspec( dllimport ) int *j;

      _declspec( dllimport ) char *sz;

4. If you did not use _declspec( dllimport ) in step 3, use the values by

   dereferencing the pointers declared:

      printf( "%d", *i );

      printf( "%d", **j );

      printf( "%s", *sz );

   It may simplify things to use #defines instead; then the variables can

   be used exactly as defined in the DLL:

      #define i *i

      #define j *j

      #define sz *sz

      extern int i;

      extern int *j;

      extern char *sz;

      printf( "%d", i );

      printf( "%d", *j );

      printf( "%s", sz );

MORE INFORMATION

NOTE: This technique can also be used to export a global variable from an

application so that it can be used in a DLL.

REFERENCE

For more information on the use of EXPORTS and CONSTANT in the Module

Definition File (DEF) file for the 3.1 SDK, see Chapter 4 of the Win32 SDK

"Tools" manual.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: BseDll


Extending Standard Windows Controls Through Superclassing

PSS ID Number: Q76947

Authored 03-Oct-1991	Last modified 16-May-1995

-

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK), versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

-

SUMMARY

A Windows-based application can extend the behavior of a standard Windows

control by using the technique of superclassing. An application can

superclass a standard Windows control by retrieving its window class

information, modifying the fields of the WNDCLASS structure, and

registering a new class. For example, to associate status information with

each button control in an application, the buttons can be superclassed to

provide a number of window extra bytes.

This article describes a technique to access the WNDCLASS structure

associated with the standard "button" class.

MORE INFORMATION

The following five steps are necessary to register a new class that

uses some information from the standard windows "button" class:

1. Call GetClassInfo() to fill the WNDCLASS structure.

2. Save the cbWndExtra value in a global variable.

3. Add the desired number of bytes to the existing cbWndExtra value.

4. Change the lpszClassName field.

5. Call RegisterClass() to register the new class.

The first step will fill the WNDCLASS structure with the data that was used

when the class was originally registered. In this example, the second step

is necessary so that when the "new" extra bytes are accessed, the original

extra bytes are not destroyed. Please note that it is NOT safe to assume

that the original cbWndExtra value was zero. When accessing the "new" extra

bytes, it is necessary to use the original value of cbWndExtra as the base

for any new data stored in the extra bytes. The third step allocates the

new extra bytes. The fourth step specifies the new name of the class to be

registered, and the final step actually registers the new class.

Any new class created in this manner MUST have a unique class name.

Typically, this name would be similar but not identical to the original

class. For example, to superclass a button, an appropriate class name might

be "superbutton." There is no conflict with class names used by other

applications as long as the CS_GLOBALCLASS class style is not specified.

The standard Windows "button" class remains unchanged and can still be used

by the application as normal. In addition, once a new class has been

registered, any number of controls can be created and destroyed with no

extra coding effort. The superclass is simply another class in the pool of

classes that can be used when creating a window.

The sample code below demonstrates this procedure:

BOOL DefineSuperButtonClass(void)

{

#define MYEXTRABYTES 8

   HWND     hButton;

   WNDCLASS wc;

   GetClassInfo(NULL, "button", (LPWNDCLASS)&wc);

   iStdButtonWndExtra = wc.cbWndExtra;   // Save this in a global

   wc.cbWndExtra += MYEXTRABYTES;

   lstrcpy((LPSTR)wc.lpszClassName, (LPSTR)"superbutton");

   return(RegisterClass((LPWNDCLASS)&wc));

}

It is important to note that the lpszClassName, lpszMenuName, and hInstance

fields in the WNDCLASS structure are NOT returned by the GetClassInfo()

function. Please refer to page 4-153 of the "Microsoft Windows Software

Development Kit Reference Volume 1" for more information. Also, each time a

new class is registered, scarce system resources are used. If it is

necessary to alter many different standard classes, the GetProp(),

SetProp(), and RemoveProp() functions should be used as an alternative

approach to associating extra information with standard Windows controls.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: UsrCtl


Extracting the SID from an ACE

PSS ID Number: Q102101

Authored 28-Jul-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

SUMMARY

To access the security identifier (SID) contained in an access control

entry (ACE), the following syntax can be used:

   PSID pSID;

   if((((PACE_HEADER)pTempAce)->AceType) == ACCESS_ALLOWED_ACE_TYPE)

   {

      pSID=(PSID)&((PACCESS_ALLOWED_ACE)pTempAce)->SidStart;

   }

MORE INFORMATION

The "if" statement checks the type of ACE, which is one of the following

values:

   ACCESS_ALLOWED_ACE_TYPE

   ACCESS_DENIED_ACE_TYPE

   SYSTEM_AUDIT_ACE_TYPE

The conditional statement casts pTempAce (the pointer to the ACE) to a

PACCESS_ALLOWED_ACE structure. The address of the SidStart member is then

cast to a PSID and assigned to the pSID variable. pSID can now be used with

any Win32 Security application programming interface (API) that takes a

PSID as a parameter.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseSecurity


File Manager Passes Short Filename as Parameter

PSS ID Number: Q98575

Authored 09-May-1993	Last modified 18-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), version 3.1 and 3.5

When starting an application from File Manager by double-clicking a

document associated with the application, if the document resides on an

NTFS partition and has a long (non-8.3 form) filename, File Manager will

pass the short version of the filename (also known as the MS-DOS alias or

8.3 name) to the associated application if the application is an MS-DOS or

16-bit Windows-based application. This is done for compatibility reasons;

applications not aware of long filenames (16-bit Windows-based

applications) can still function correctly. 32-bit Windows-based

applications will be passed the long file name.

This can create confusion, however, if the application displays the name of

the file the application was started with; the short name is displayed even

though the long name was double-clicked.

You can avoid possible confusion by always expanding any filenames passed

to an application via the command line. Do this by calling the

FindFirstFile() application programming interface (API) on these filenames.

FindFirstFile() will always return the file system's version of the

filename in the WIN32_FIND_DATA.cFileName structure member, which the

application can then use in all further references to the file without any

problems.

Additional reference words: 3.10 file name 3.50

KBCategory: kbprg

KBSubcategory: BseFileio


FILE_FLAG_WRITE_THROUGH and FILE_FLAG_NO_BUFFERING

PSS ID Number: Q99794

Authored 08-Jun-1993	Last modified 25-May-1995

The information in this article applies to:

   - Microsoft Win32 Software Development Kit (SDK), versions 3.1 and

     3.5

SUMMARY

The FILE_FLAG_WRITE_THROUGH flag for CreateFile() causes any writes made to

that handle to be written directly to the file without being buffered. The

data is cached (stored in the disk cache); however, it is still written

directly to the file. This method allows a read operation on that data to

satisfy the read request from cached data (if it's still there), rather

than having to do a file read to get the data. The write call doesn't

return until the data is written to the file. This applies to remote writes

as well--the network redirector passes the FILE_FLAG_WRITE_THROUGH flag to

the server so that the server knows not to satisfy the write request until

the data is written to the file.

The FILE_FLAG_NO_BUFFERING takes this concept one step further and

eliminates all read-ahead file buffering and disk caching as well, so that

all reads are guaranteed to come from the file and not from any system

buffer or disk cache. When using FILE_FLAG_NO_BUFFERING, disk reads and

writes must be done on sector boundaries, and buffer addresses must be

aligned on disk sector boundaries in memory.

These restrictions are necessary because the buffer that you pass to the

read or write API is used directly for I/O at the device level; at that

level, your buffer addresses and sector sizes must satisfy any processor

and media alignment restrictions of the hardware you are running on.

MORE INFORMATION

This code fragment demonstrates how to sector-align data in a buffer and

pass it to CreateFile():

  char buf[2 * SECTOR_SIZE - 1], *p;

  p = (char *) ((DWORD) (buf + SECTOR_SIZE - 1) & ~(SECTOR_SIZE - 1));

  h = CreateFile(argv[1], GENERIC_READ | GENERIC_WRITE,

      FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS,

      FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL);

  WriteFile(h, p, SECTOR_SIZE, &dwWritten, NULL);

The pointer p is sector-aligned and points within the buffer.

If you have a situation where you want to flush all open files on the

current logical drive, this can be done by:

   hFile = CreateFile("\\\\.\\c:", ....);

   FlushFileBuffers(hFile);

This method causes all buffered write data for all open files on the C:

partition to be flushed and written to the disk. Note that any buffering

done by anything other than the system is not affected by this flush; any

possible file buffering that the C Run-time is doing on files opened with C

Run-time routines is unaffected.

When opening a remote file over the network, the server always caches and

ignores the no buffering flag specified by the client. This is by design.

The redirector and server cannot properly implement the full semantics of

FILE_FLAG_NO_BUFFERING over the network. In particular, the requirement for

sector-sized, sector-aligned I/O cannot be met. Therefore, when a Win32-

based application asks for FILE_FLAG_NO_BUFFERING, the redirector and

server treat this as a request for FILE_FLAG_WRITE_THROUGH. The file is not

cached at the client, writes go directly to the server and to the disk on

the server, and the read/write sizes on the network are exactly what the

application asks for. However, the file is cached on the server.

Not caching the client can have a different effect, depending on the type

of I/O. You eliminate the cache hits or read ahead, but you also may reduce

the size of transmits and receives. In general, for sequential I/O, it is a

good idea to cache on the client. For small, random access I/O, it is often

best not to cache.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: BseFileio


FILE_READ_EA and FILE_WRITE_EA Specific Types

PSS ID Number: Q102104

Authored 28-Jul-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

The FILE_READ_EA and FILE_WRITE_EA specific types provide access to read

and write a file's extended attributes. Specific access types are

represented as bits in the access mask and are specific to the object type

associated with the mask.

Please note that these specific types are used in the definition of

constants such as FILE_GENERIC_READ, and are not intended to be generally

used when specifying access (generic access types are much more

appropriate).

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: BseFileio


Filenames Ending with Space or Period Not Supported

PSS ID Number: Q115827

Authored 05-Jun-1994	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

CreateFile() removes trailing spaces and periods from file and directory

names. This is done for compatibility with the FAT and HPFS file systems.

Problems can arise when a Macintosh client creates a file on a Windows NT

server. The code to remove trailing spaces and periods is not carried out

and the Macintosh user gets the correctly punctuated filename. The Win32

APIs FindFirstFile() and FindNextFile() return a filename that ends in a

space or in a period; however, there is no way to create or open the file

using the Win32 API.

Applications such as File Manager and Backup check to see whether the

filename ends with a space or period. If the filename does end in a space

or a period, then File Manager and Backup use the alternative name found in

WIN32_FIND_DATA.cAlternateFileName to create and open the file. Therefore,

the full filename is lost.

Additional reference words: 3.10 3.50 4.00 95  winfile ntbackup

KBCategory: kbprg

KBSubcategory: BseFileio


FileTimeToLocalFileTime() Adjusts for Daylight Saving Time

PSS ID Number: Q128126

Authored 27-Mar-1995	Last modified 27-Mar-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), version 3.5

SUMMARY

Under NTFS, the API GetFileTime() returns the create time, last access

time, and last write time for the specified file. The times returned in the

FILETIME structures are in Universal Coordinated Time (UTC). This is also

the time that NTFS uses. You can use FileTimeToLocalFileTime() to convert a

file time to a local time. However, if you automatically adjust for

Daylight Saving Time, FileTimeToLocalFileTime() will adjust for Daylight

Saving Time based on whether the current date should be adjusted for

Daylight Saving Time, not based on whether the date represented by the

FILETIME structure should be adjusted.

The behavior in this situation is different under FAT, but may be changed

to match the behavior under NTFS in a future version of Windows NT.

MORE INFORMATION

The result of this behavior, which is by design, is that reported file

times under NTFS may change with the start and end of Daylight Saving Time.

For example, suppose that the file TEST.C has a last write FILETIME

representing Jan 1, 1995 9:00pm (UTC), it is not Daylight Saving Time,

and you are in the Pacific time zone. Both the DIR command and the

following sample code report the file time as 1:00pm (LocalTime = UTC - 8).

Sample Code 1

-------------

   #include <windows.h>

   void main()

   {

      HANDLE hFile;

      FILETIME ftCreate, ftLastAccess, ftLastWrite, ftLocal;

      SYSTEMTIME st;

      char buf[80];

   // Open the file.

      hFile = CreateFile( "test.c",

                          GENERIC_READ,

                          0,

                          NULL,

                          OPEN_EXISTING,

                          FILE_ATTRIBUTE_NORMAL,

                          NULL );

   // Get the file time (in UTC) and convert to local time.

      GetFileTime( hFile, &ftCreate, &ftLastAccess, &ftLastWrite );

      FileTimeToLocalFileTime( &ftLastWrite, &ftLocal );

   // Display the time, as a test.

      FileTimeToSystemTime( &ftLocal, &st );

      GetTimeFormat( LOCALE_USER_DEFAULT, 0, &st, NULL, buf, sizeof(buf) );

      MessageBox( NULL, buf, " FILE TIME", MB_OK );

   }

Now, set the date to 7/1/95 and enable Automatically Adjust for Daylight

Saving Time. The DIR command and the sample code above will report the

file time as 2:00pm, because FileTimeToLocalFileTime() has adjusted for

Daylight Saving Time (LocalTime = UTC - 7).

The following sample code will correctly report the file time of TEST.C

with the date set to 7/1/95 under NTFS. The FILETIME structure is

converted to a SYSTEMTIME structure with FileTimeToSystemTime(). Then the

time is converted using SystemTimeToTzSpecificLocalTime(). If you need to

convert back to a FILETIME structure, use SystemTimeToFileTime() after the

conversion to local time.

Sample Code 2

-------------

   #include <windows.h>

   void main()

   {

      HANDLE hFile;

      FILETIME ftCreate, ftLastAccess, ftLastWrite;

      SYSTEMTIME stUTC, st;

      char buf[80];

   // Open the file.

      hFile = CreateFile( "test.c",

                          GENERIC_READ,

                          0,

                          NULL,

                          OPEN_EXISTING,

                          FILE_ATTRIBUTE_NORMAL,

                          NULL );

   // Get the file time (in UTC) and convert to local time.

      GetFileTime( hFile, &ftCreate, &ftLastAccess, &ftLastWrite );

      FileTimeToSystemTime( &ftLastWrite, &stUTC );

      SystemTimeToTzSpecificLocalTime( NULL, &stUTC, &st);

   // Display the time, as a test.

      GetTimeFormat( LOCALE_USER_DEFAULT, 0, &st, NULL, buf, sizeof(buf) );

      MessageBox( NULL, buf, "FILE TIME", MB_OK );

   }

The FAT file system stores local time, not UTC. GetFileTime() gets cached

UTC times from FAT. In this sample, the time stored is 1pm and the cached

time is 9pm. When it becomes Daylight Saving Time, sample codes 1 and 2

will demonstrate the same behavior that they do under NTFS, because 9pm is

still used. However, when you restart the machine, the new cached time will

be 8pm (UTC = LocalTime + 7). The call to FileTimeToLocalFileTime() cancels

the adjustment made by GetFileTime() (LocalTime = UTC - 7). Therefore,

sample code 1 will report the correct time under FAT, but sample code 2

will not.

On the other hand, FindFirstFile() on FAT always reads the time from the

file (stored as local time) and converts it into UTC, adjusting for DST

based on the current date. So if FindFirstFile() is called, the date is

changed to a different DST season, and then FindFirstFile() is called

again, the UTC returned by the two calls will be different.

Additional reference words: 3.50

KBCategory: kbprg kbcode

KBSubcategory: BseMisc


First and Second Chance Exception Handling

PSS ID Number: Q105675

Authored 22-Oct-1993	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

Structured exception handling (SEH) takes a little getting used to,

particularly when debugging. It is common practice to use SEH as a

signaling mechanism. Some application programming interfaces (APIs)

register an exception handler in anticipation of a failure condition that

is expected to occur in a lower layer. When the exception occurs, the

handler may correct or ignore the condition rather than allowing a failure

to propagate up through intervening layers. This is very handy in complex

environments such as networks where partial failures are expected and it is

not desirable to fail an entire operation simply because one of several

optional parts failed. In this case, the exception can be handled so that

the application is not aware that an exception has occurred.

However, if the application is being debugged, it is important to realize

that the debugger will see all exceptions before the program does. This is

the distinction between the first and second chance exception. The debugger

gets the "first chance," hence the name. If the debugger continues the

exception unhandled, the program will see the exception as usual. If the

program does not handle the exception, the debugger will see it again (the

"second chance"). In this latter case, the program normally would have

crashed had the debugger not been present.

If you do not want to see the first chance exception in the debugger, then

disable the feature. Otherwise, during execution, when the debugger gets

the first chance, continue the exception unhandled and allow the program to

handle the exception as usual. Check the documentation for the debugger

that you are using for descriptions of the commands to be used.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: BseExcept


FIX: AllocConsole() Does Not Set Error Code on Failure

PSS ID Number: Q105564

Authored 20-Oct-1993	Last modified 19-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

SYMPTOMS

The documentation for AllocConsole() states the following:

   If the function succeeds, the return value is TRUE; otherwise, it

   is FALSE. To get extended error information, use the GetLastError()

   function.

Upon failure, AllocConsole() does not set the error code.

STATUS

Microsoft has confirmed this to be a bug in Windows NT 3.1. This problem

was corrected in Windows NT 3.5.

MORE INFORMATION

The following sample code demonstrates the problem:

#include <stdio.h>

#include <windows.h>

void main()

{

   BOOL bSuccess;

/* Comment out the following line and GetLastError() will   */

/* return 999; otherwise, GetLastError() returns 1812.      */

   FreeConsole();

   SetLastError( 999 );

   bSuccess = AllocConsole();

   if( !bSuccess )

      puts( "AllocConsole failed" );

   printf( "The last error is: %d\n", GetLastError() );

   getchar();

}

Additional reference words: 3.10

KBCategory: kbprg kbfixlist kbbuglist

KBSubcategory: BseCon


FIX: APIs Do Incorrect Comparisons

PSS ID Number: Q105804

Authored 25-Oct-1993	Last modified 28-Nov-1994

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

SYMPTOMS

The functions getservbyport() and getprotobynumber() do an incorrect

comparison when two port APIs take a parameter as an integer then do

comparisons of the integer against an unsigned short that is incorrectly

sign-extended. If a port or protocol number greater than 127 is passed into

these routines, they will not return any information.

STATUS

Microsoft has confirmed this to be a problem in Windows NT and Windows NT

Advanced Server version 3.1. This problem was corrected in the latest U.S.

Service Pack for Windows NT and Windows NT Advanced Server version 3.1. For

information on obtaining the Service Pack, query on the following word in

the Microsoft Knowledge Base (without the spaces):

   S E R V P A C K

Additional reference words: 3.10 buglist3.10 fixlist3.10.001

KBCategory: kbprg kbbuglist kbfixlist

KBSubCategory: NtwkWinsock


FIX: Cannot Compile from Win32 SDK M Editor (MEP.EXE)

PSS ID Number: Q98918

Authored 18-May-1993	Last modified 18-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

SYMPTOMS

The Win32 Software Development Kit (SDK) M Editor compile function uses the

correct extmake line and spawns the compiler correctly, but does not

produce the desired result. The terminating beep is issued, but no messages

appear in the <compile> pseudo file and no object file is produced.

STATUS

Microsoft has confirmed this to be a problem in the products listed at the

beginning of this article. This problem was corrected in the Win32 SDK

version 3.5.

MORE INFORMAION

The method typically used to invoke the compiler from the M Editor is

1. Include the following text switch in the TOOLS.INI

      extmake:<ext> <command>

   where <ext> is the file extension and <command> is the command to be

   carried out when compiling a file of this type. For example:

      extmake:c cl /DWIN32 %s

   NOTE: %s is the current file.

2. To invoke the switch, use Arg Compile (ALT+A CTRL+F3)

Additional reference words: 3.10 mep

KBCategory: kbtool kbprb

KBSubcategory: TlsMep


FIX: GetPrivateProfileSection() Can Read Only 32K Sections

PSS ID Number: Q105681

Authored 22-Oct-1993	Last modified 28-Mar-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

SYMPTOMS

The documentation for GetProfileSection(), GetProfileString(),

GetPrivateProfileSection(), GetPrivateProfileString(), and

GetPrivateProfileSection() indicate that the application programming

interface (API) can read all the keys and values of a section, regardless

of size. However, these functions only seem to handle sections that are

smaller than 32K, even though the size of the buffer is a DWORD.

CAUSE

The code is casting this value to a signed short, and therefore you are

having problems with sections that are greater than 32K in size.

STATUS

Microsoft has confirmed this to be a problem in Windows NT 3.1. This

problem was corrected in Windows NT 3.5.

Additional reference words: 3.10

KBCategory: kbprg kbfixlist kbbuglist

KBSubcategory: BseMisc


FIX: Global Constructors Not Called in Alpha DLLs

PSS ID Number: Q98732

Authored 12-May-1993	Last modified 29-Nov-1994

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

SYMPTOMS

C++ constructors on global variables are not invoked when a dynamic link

library (DLL) is loaded on the Alpha AXP platform.

STATUS

Microsoft has confirmed this to be a problem in Windows NT and Windows NT

Advanced Server version 3.1. This problem was corrected in the latest U.S.

Service Pack for Windows NT and Windows NT Advanced Server version 3.1. For

information on obtaining the Service Pack, query on the following word in

the Microsoft Knowledge Base (without the spaces):

   S E R V P A C K

Additional reference words: 3.10 buglist3.10 fixlist3.10.003

KBCategory: kbtool kbfixlist kbbuglist

KBSubCategory: TlsMisc


FIX: High CPU Usage When SNMP Retrieves Performance Counters

PSS ID Number: Q130563

Authored 23-May-1995	Last modified 06-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) version 3.5

SYMPTOMS

When an SNMP extension agent tries to retrieve performance counters, CPU

utilization jumps to 100 percent.

STATUS

Microsoft has confirmed this to be a bug in the Microsoft products listed

at the beginning of this article. This problem was corrected in Windows NT

version 3.51.

MORE INFORMATION

If an SNMP extension agent tries to retrieve performance counters as in the

following example, the CPU utilization is observed to jump to 100 percent

and stay there until the SNMP service is stopped.

   RegOpenKeyEx(...);

   .

   .

   RegQueryValueEx(HKEY_PERFORMANCE_DATA,

   ...)

To see this, use the Performance Monitor tool in the Administrative Tools

program group.

The same problem can occur when an application is trying to retrieve TCP/IP

performance counters and the Internet MIB II agent is being used to

retrieve the counters.

REFERENCES

For more information, please see the Windows NT 3.5 Resource Kit Vol IV.

Additional reference words: 3.50

KBCategory: kbnetwork kbfixlist kbbuglist

KBSubcategory: NtwkSnmp


FIX: Internal Error from NetUserEnum()

PSS ID Number: Q108055

Authored 02-Dec-1993	Last modified 29-Nov-1994

--

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

--

SYMPTOMS

If you make a NetUserEnum() call from a down-level computer remoted to a

Windows NT machine, the error return is:

   2140 (NERR_InternalError).

This happens only if the down-level computer remotes the API to the Windows

NT computer and provides a buffer size that is greater than zero but less

than the size of one element of the data structure.

STATUS

Microsoft has confirmed this to be a problem in Windows NT and Windows NT

Advanced Server version 3.1. This problem was corrected in the latest U.S.

Service Pack for Windows NT and Windows NT Advanced Server version 3.1. For

information on obtaining the Service Pack, query on the following word in

the Microsoft Knowledge Base (without the spaces):

   S E R V P A C K

Additional reference words: 3.10 buglist3.10 fixlist3.10.003

KBCategory: kbtool kbbuglist kbfixlist

KBSubCategory: TlsLmapi


FIX: Low Memory Condition Cause APIs to Return Random Values

PSS ID Number: Q105575

Authored 20-Oct-1993	Last modified 29-Nov-1994

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

SYMPTOMS

Low memory on a Windows NT computer can cause USER APIs to return random

values. For example, CreateWindowEx() returns a bad value, and

SetWindowLong() and GetWindowLong() do not receive the correct value.

STATUS

Microsoft has confirmed this to be a problem in Windows NT and Windows NT

Advanced Server version 3.1. This problem was corrected in the latest U.S.

Service Pack for Windows NT and Windows NT Advanced Server version 3.1. For

information on obtaining the Service Pack, query on the following word in

the Microsoft Knowledge Base (without the spaces):

   S E R V P A C K

Additional reference words: 3.10 buglist3.10 fixlist3.10.001

KBCategory: kbprg kbbuglist kbfixlist

KBSubCategory: UsrMisc


FIX: MFC-Based App Cannot Run Under International Win32s

PSS ID Number: Q125457

Authored 29-Jan-1995	Last modified 11-Apr-1995

The information in this article applies to:

 - Microsoft Win32s version 1.2

SYMPTOMS

When activating a Microsoft Foundations Classes (MFC)-based application

built with Visual C++ version 2.0 under Win32s version 1.2, if the language

setting in Windows or Windows for Workgroups Control panel is set to

anything other than English, German, or French, the following error occurs:

   Win32s - Error: Initialization of a dynamic link library failed.

   The process is terminating abnormally.

This error has also been reported with non-MFC-based applications as well.

CAUSE

CRT startup code causes an unhandled exception in the Win32s DLL

(W32SCOMB.DLL).

RESOLUTION

For an international version of Windows 3.1 or Windows for Workgroups, if

the country and language settings are changed to United States and

English(American), 32-bit MFC-based applications are able to run.

STATUS

Microsoft has confirmed this to be a bug in Win32s version 1.2. This

problem has been corrected in Win32s version 1.25.

Additional reference words: 1.20 w32scomb

KBCategory: kbinterop kbfixlist kbbuglist

KBSubcategory: W32s WIntlDev


FIX: MIDL 2.0 Does Not Handle VAX Floating Point Numbers

PSS ID Number: Q129064

Authored 18-Apr-1995	Last modified 06-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) version 3.5

SYMPTOMS

RPC applications (client and server) built using MIDL 2.0 (shipped with

Windows NT version 3.5) may get spurious characters or report memory

violations when dealing with VAX floating point numbers.

RESOLUTION

There are two possible resolutions to this problem:

 - Use MIDL 1.0 (shipped with Windows NT version 3.1) to build RPC client

   and server applications.

   -or-

 - On the VAX side, use a compiler switch to make sure the application

   represents its floating point numbers in IEEE format.

STATUS

Microsoft has confirmed this to be a bug in the Microsoft products listed

at the beginning of this article. This problem was corrected in Windows NT

version 3.51.

MORE INFORMATION

Note that Microsoft RPC is binary compatible with DCE RPC. There are four

types of representations for floating point numbers: IEEE, VAX, IBM, and

CRAY. An application built using MIDL 1.0 can recognize IEEE and VAX

representations but not IBM and CRAY. Applications built using MIDL 2.0 can

recognize only IEEE representaion as mentioned above. Both, MIDL 1.0 and

2.0, use IEEE representations to send data.

Additional reference words: 3.50

KBCategory: kbnetwork kbfixlist kbbuglist

KBSubcategory: NtwkRpc


FIX: MIPS Compiler Assertion with C version 8.0

PSS ID Number: Q102764

Authored 10-Aug-1993	Last modified 29-Nov-1994

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

SYMPTOMS

You may get the following assertion from the C version 8.0 compiler on

Windows NT under MIPS:

   Microsoft (R) C Centaur Optimizing Compiler Version 8.00.081

   Copyright (c) Microsoft Corp 1984-1992. All rights reserved.

   t516a.cxx

   Assertion failed: prld->symbol->symbolnumber >= 0, file

   E:\src\centaur\drop81\msas\as1coff.c, line 459

   abnormal program termination

CAUSE

You can get an assertion running C 8.0 on Windows NT MIPS if you did not

compile with /Zi or /Z7 or if your external declarations are not at file

scope level (that is, declare them as global).

RESOLUTION

The easiest workaround is to recompile with /Zi or /Z7. Another workaround

is to move all extern declarations to file scope level.

STATUS

There is a fix for this but the problem wasn't deemed critical enough to

change right before the Windows NT 3.1 release. This problem was corrected

in the Win32 SDK, version 3.5.

Additional reference words: 3.10

KBCategory: kbtool kbfixlist kbbuglist

KBSubcategory: TlsMisc


FIX: NDISCloseFile() Does Not Free Image Buffer

PSS ID Number: Q105785

Authored 24-Oct-1993	Last modified 28-Nov-1994

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

SYMPTOMS

The NDISCloseFile() function does not free the buffer that it allocates to

hold the image that was read in.

STATUS

Microsoft has confirmed this to be a problem in Windows NT and Windows NT

Advanced Server version 3.1. This problem was corrected in the latest U.S.

Service Pack for Windows NT and Windows NT Advanced Server version 3.1. For

information on obtaining the Service Pack, query on the following word in

the Microsoft Knowledge Base (without the spaces):

   S E R V P A C K

Additional reference words: 3.10 buglist3.10 fixlist3.10.001

KBCategory: kbprg kbbuglist kbfixlist

KBSubCategory: NtwkMisc


FIX: Owner Drawn Items on the Menu Bar Hang Windows NT

PSS ID Number: Q126720

Authored 28-Feb-1995	Last modified 03-Mar-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.5

SYMPTOMS

Windows NT supports owner drawn items on the menu bar. However, Windows NT

may stop responding (hang) if multiple windows of same class are created

with the owner drawn menu bar.

STATUS

Microsoft has confirmed this to be a bug in Windows NT version 3.50. This

problems was corrected in Windows NT version 3.51.

MORE INFORMATION

Steps to Reproduce Problem

--------------------------

1. Assign a menu to a window class via RegisterClass().

2. Modify the menu bar to be owner draw in WM_CREATE.

3. Create multiple windows of the same window class.

Windows NT may stop responding, in which case, you must turn off the

computer.

Additional reference words: 3.50

KBCategory: kbprg kbfixlist kbbuglist

KBSubcategory: UsrMen UsrOwn


FIX: POSIX Does Not Distinguish stdout & stderr

PSS ID Number: Q92769

Authored 15-Nov-1992	Last modified 29-Nov-1994

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

SYMPTOMS

Programs under POSIX do not distinguish between stdout and stderr. This

causes a variety of symptoms, such as fprints to stdout and stderr ending

up in the same place.

CAUSE

When output is destined for the terminal (or a pipe to a windows

application), the output becomes generic output instead of being destined

for a specific file descriptor, and so forth.

STATUS

Microsoft has confirmed this to be a problem in Windows NT, version 3.1.

This problem was corrected in Windows NT, version 3.5.

MORE INFORMATION

The following sample code can be used to demonstrate the problem.

Sample code

-----------

#include <stdio.h>

void main( )

{

   freopen( "freopen.out", "w", stdout );

   fprintf( stdout, "Hey there.\n" );

   fprintf( stderr, "Hey! Not me too!\n" );

}

Additional reference words: 3.10  buglist3.10 fixlist3.50

KBCategory: kbprg kbbuglist kbfixlist

KBSubcategory: SubSystem


FIX: Redirecting Output to an MS-DOS-Based Application

PSS ID Number: Q105303

Authored 17-Oct-1993	Last modified 28-Nov-1994

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

SYMPTOMS

The following method is used to redirect output to a child process when it

is started from a GUI application:

1. Declare STARTUPINFO si.

   a. Set the hStdIn, hStdOut, and/or hStdErr field as desired.

   b. Set the dwFlags field to STARTF_USESTDHANDLES.

2. In CreateProcess(), set inherit handles to TRUE.

NOTE: This method does not work when starting MS-DOS-based applications.

RESOLUTION

As a workaround, use AllocConsole(), then the following method:

1. Use SetStdHandle() to set the desired handles to be inherited.

   -or-

   Use DuplicateHandle() to change the inheritance property of handles

   that should not be inherited.

3. In CreateProcess(), set inherit handles to TRUE.

This method creates a blank console window; however, this is necessary

because the method doesn't work otherwise.

STATUS

Microsoft has confirmed this to be a bug in Windows NT 3.1. This problem

was corrected in Windows NT 3.5.

MORE INFORMATION

Note that if you are opening a handle that will be inherited by the

child, set SECURITY_ATTRIBUTES.bInheritHandle = TRUE in the call to

CreateFile(), CreatePipe(), and so forth.

For an example of both methods of redirection, see the INHERIT SDK

sample.

Additional reference words: 3.10 buglist3.10 fixlist3.50

KBCategory: kbprg kbfixlist kbbuglist

KBSubcategory: BseProcThrd


FIX: SetCaret API May Not Work Correctly in Win32-Based Apps

PSS ID Number: Q105733

Authored 24-Oct-1993	Last modified 28-Nov-1994

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

SYMPTOMS

The SetCaret() API does not work correctly in multithreaded Win32-based

applications. Code with the following logic fails:

Thread 1: Creates a window and starts another thread.

Thread 2: Uses an API to synchronize the two threads' "Input State,"

attempts to write to the window of Thread 1, and then tries to set the

caret through SetCaret().

STATUS

Microsoft has confirmed this to be a problem in Windows NT and Windows NT

Advanced Server version 3.1. This problem was corrected in the latest U.S.

Service Pack for Windows NT and Windows NT Advanced Server version 3.1. For

information on obtaining the Service Pack, query on the following word in

the Microsoft Knowledge Base (without the spaces):

   S E R V P A C K

Additional reference words: 3.10 buglist3.10 fixlist3.10.001

KBCategory: kbprg kbbuglist kbfixlist

KBSubCategory: GdiCurico


FIX: Setsockopt() for Winsock over Appletalk Returns Error

PSS ID Number: Q129062

Authored 18-Apr-1995	Last modified 06-Jun-1995

The information in this article applies to

 - Microsoft Win32 Software Development Kit (SDK) version 3.5

SYMPTOMS

After you open a socket of type SOCK_STREAM by using the ATPROTO_ADSP

protocol, and bind to a dynamic socket, the setsockopt() function fails

under these conditions:

 - The setsockopt() function uses the zone name returned by getsockopt()

   (also found by looking at the control panel network entry) with the

   SO_LOOKUP_MYZONE option.

 - The zone name is supplied to setsockopt() with the SO_REGISTER_NAME

   option.

Error code 10022 (WSAINVAL :Invalid Argument) is returned on calling

GetLastError().

RESOLUTION

Instead of passing the string returned by getsockopt() for the zone name,

use the character "*" for the ZoneName member of the WSH_REGISTER_NAME

struct. For example, use this:

   WSH_REGISTER_NAME regName;

   ........

   strcpy( regName.ZoneName, "*");

instead of this:

   strcpy( regName.ZoneName, "BLDG/1");

STATUS

Microsoft has confirmed this to be a bug in the Microsoft products listed

at the beginning of this article. This problem was corrected in Windows NT

3.51.

REFERENCES

Windows Sockets for Appletalk (SFMWSHAT.WRI version 1.2).

Additional reference words: 3.50

KBCategory: kbnetwork kbfixlist kbbuglist

KBSubcategory: NtwkWinsock


FIX: SNMP Sample Generates an Application Error

PSS ID Number: Q124961

Authored 17-Jan-1995	Last modified 07-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) version 3.5

SYMPTOMS

The Win32 SDK for Windows NT 3.5 contains a SNMP sample called SNMPUTIL

(\MSTOOLS\SAMPLES\WIN32\SNMP\SNMPUTIL). Building this sample generates an

executable file that causes an access violation. The message box displayed

resembles the following:

                     snmputil.exe - Application Error

   -----------------------------------------------------------------

   The instruction at <address> referenced memory at <address>.  The

   memory could not be "read".

CAUSE

One part of the SNMP run times uses the C run-time routines provided by

CRTDLL.DLL. The other part of the SNMP run times uses the C run-time

routines that the application uses. Because many people are using Visual

C++ to build the samples, the run time routines used are in MSVCRT20.DLL.

The access violation occurs when memory allocated using one run time

version are freed using a different copy of the run time library.

RESOLUTION

One possible solution is to build the sample application using the

CRTDLL.DLL version of the run time library. If you are using the makefile

supplied with the Win32 SDK, one way to accomplish this is to:

1. Copy NTWIN32.MAK from your include directory to the working directory

   for the sample.

2. Change all references to MSVCRT.LIB in NTWIN32.MAK to CRTDLL.LIB.

If you are using a Visual C++ make file, you can:

1. Select the "Ignore All Default Libraries" check box in the Linker

   Project Settings property page.

2. Add CRTDLL.LIB to the "Object/Library Modules" section in the Linker

   Project Settings property page.

NOTE: CRTDLL.LIB does not ship with Visual C++. You can get the CRTDLL.LIB

file from the Win32 SDK in the \MSTOOLS\LIB\CRT\<PLATFORM> directory, where

<PLATFORM> would be replaced with the type of machine you are using (I386,

alpha, and so forth).

If you are using MFC 3.0, you will not be able to use CRTDLL.DLL because

MFC 3.0 uses some functions that are not supplied in CRTDLL.DLL.

STATUS

Microsoft has confirmed that this is a problem in the Microsoft products

listed at the beginning of this article. This problem was corrected in the

Win32 SDK version 3.51.

Additional reference words: 3.50

KBCategory: kbprg kbnetwork kbfixlist kbbuglist

KBSubcategory: NtwkSnmp


FIX: StreBlt Sample Causes Windows NT to Stop Responding

PSS ID Number: Q104834

Authored 29-Sep-1993	Last modified 28-Nov-1994

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

SYMPTOMS

When you run the STREBLT sample, Windows NT may stop responding (hang).

STATUS

This problem was corrected in Windows NT 3.5.

MORE INFORMATION

Steps to Reproduce Problem

--------------------------

1. Build the StreBlt sample using the supplied makefile.

2. The sample displays a dialog box for the main window. There are

   three drop-down list controls titled StretchBltMode, Pattern, and

   Standard ROPs. Select the following in these drop-down lists:

      StretchBltMode    BLACKONWHITE

      Pattern           NULL_BRUSH

      Standard ROPs     PATPAINT

At this point, Windows NT stops responding.

Additional reference words: 3.10

KBCategory: kbprg kbfixlist kbbuglist

KBSubCategory: GdiBmp


FIX: SVCGUID.H Has Wrong UDP Port for SNMP Traps

PSS ID Number: Q129061

Authored 18-Apr-1995	Last modified 06-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) version 3.5

SYMPTOMS

The file SVCGUID.H used by the Registration and Name Resolution (RnR) APIs

has the UDP trap port for SNMP set to 167:

   #define SVCID_SNMP_TRAP_UDP                   SVCID_UDP(167)

RESOLUTION

The correct port number for SNMP traps is 162. However, please note that

this entry is not looked at by the SNMP service for Windows NT. Hence, it

cannot cause traps to be sent to the wrong port. SVCGUID.H is used only by

Registration and Name Resolution (RnR) APIs.

STATUS

Microsoft has confirmed this to be a bug in the Microsoft products listed

at the beginning of this article. This problem was corrected in Windows NT

3.51.

Additional reference words: 3.50

KBCategory: kbnetwork kbfixlist kbbuglist

KBSubcategory: NtwkWinsock


FIX: VirtualLock() on File-Mapped Pages Hangs Computer

PSS ID Number: Q107642

Authored 23-Nov-1993	Last modified 28-Nov-1994

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

SYMPTOMS

Your computer may stop responding (hang) if you use the VirtualLock()

application programming interface (API) command to lock a file-mapped

page.

STATUS

Microsoft has confirmed this to be a problem in Windows NT and

Windows NT Advanced Server version 3.1. This problem was corrected in

the latest U.S. Service Pack for Windows NT and Windows NT Advanced

Server version 3.1. For information on obtaining the Service Pack,

query on the following word in the Microsoft Knowledge Base (without

the spaces):

   S E R V P A C K

Additional reference words: 3.10 buglist3.10 fixlist3.10.003

KBCategory: kbprg kbfixlist kbbuglist

KBSubCategory: BseMm


FIX: Win32s 1.25a Fix List

PSS ID Number: Q130139

Authored 11-May-1995	Last modified 12-May-1995

The information in this article applies to:

 - Microsoft Win32s, version 1.25a

The following is a list of the known bugs in Win32s version 1.2 that

were fixed in Win32s version 1.25.

 - GlobalAlloc(GMEM_FIXED) from 32-bit .EXE locks memory pages. It is

   more efficient to use GlobalAlloc(GMEM_MOVEABLE) and call GlobalFix()

   if necessary.

 - WINMM16.DLL has no version information.

 - CreateFileMapping() with SEC_NOCOMMIT returns ERROR_INVALID_PARAMETER.

 - PolyPolygon() does not close the polygons.

 - OpenFile() only searches the current directory when only a filename is

   given, not the application directory, the system directory, the windows

   directory, or the directories listed on the path.

 - GetFileInformationByHandle() doesn't return the correct file attribute.

 - GlobalUnlock() sets an error of ERROR_INVALID_PARAMETER.

 - lstrcmp()/lstrcmpi() do not use the collate table correctly.

 - FreeLibrary() in DLL_PROCESS_DETACH crashes the system.

 - FindResource(), LoadResource(), GetProcAddress(), GetModuleFileName(),

   EnumResourceNames(), and other APIs, fail with a NULL hInstance.

 - sndPlaySound() with SND_ASYNC | SND_MEMORY may cause a crash or may work

   poorly.

 - Thread Local Storage (TLS) data is not initialized to 0 in TlsAlloc().

 - The pointer received in the lParam of WM_INITDIALOG in the common dialog

   hook function becomes invalid in the following messages if the pointer

   is "remembered" in a static variable.

 - Stubbed API GetFileAttributesW() does not return -1 on error.

 - Code page CP_MACCP not supported.

 - Invalid LCIDs are not recognized.

 - CreateFile() fails to open an existing file in share mode.

 - GetLocaleInfo() for locale returns system defaults from WIN.INI.

 - GetVolumeInformation() fails with ERROR_INVALID_NAME for volumes

   without a label.

 - VirtualProtect() may miss the last page in an address range.

 - GetLocaleInfo() returns incorrect information for most non-US locales.

 - ANSI/OEM conversions always use code page 437.

 - GetProcAddress() for printer driver APIs is case sensitive.

 - The LanMan APIs are unsupported, but they return 0, which indicates

   that the API was successful. They should return NERR_InvalidAPI (2142).

 - CreateFileW() returns 0 instead of -1 (HFILE_ERROR).

 - lstrcpyn() copies n bytes from source to destination, then appends a

   NULL terminator, instead of copying n-1 bytes and appending the NULL

   terminator.

 - GetDriveType() doesn't report detecting a CD-ROM or a RAM DISK.

 - CRTDLL calls TlsFree() upon each process detach, not just the last.

 - If a DllEntryPoint calls FreeLibrary() when using universal thunks,

   the system can crash.

 - Not all 32-bit DLLs have correct version numbers.

 - GetCurrentDirectory() returns the wrong directory after calling

   GetOpenFileName(). The workaround is to call SetCurrentDirectory(".")

   right after returning from the call to GetOpenFileName().

 - RegEnumValue() and other Registry functions return ERROR_SUCCESS even

   though they are not implemented. Win32s implements only the registry

   functions supported by Windows.

 - AreFileApisANSI()/SetFileApisToANSI()/SetFileApisToOEM() are not

   exported. AreFileApisANSI() should always return TRUE, SetFileApiToOEM()

   should always fail, and SetFileApiToANSI() should always succeed.

 - SetLocaleInfoW()/SetLocateInfoA() are not implemented.

 - GetScrollPos() sets the last error if the scroll position is 0.

 - SetScrollPos() sets the last error if the last scroll position is 0.

 - LoadString() leaks memory if the string is a null string.

 - GetFileVersionInfoSize() fails if the resource section is small and

   close to the end of the file.

 - MoveFile() doesn't call SetLastError() on failure or sets a different

   error than on Windows NT.

 - SetCurrentDirectory() does not work on a CD-ROM drive.

 - GetFileVersionInfoSize() fails if the 2nd parameter is NULL.

 - WSOCK32.DLL is missing exported stubs for unimplemented APIs.

 - Win32s fails to load 64x64 monochrome (black and white) icons.

 - CreateFile() fails when called with a filename with an international

   character.

 - GetCurrentDirectory() returns an OEM string.

 - PrintDlg() causes GP fault if hDevMode!=NULL and another printer is

   selected that uses a larger DevMode buffer.

 - Unicode resources are not properly converted to 8-bit characters.

 - CreateDC() returns an incorrect DEVMODE. This can cause a variety of

   symptoms, like the inability to do a Landscape Print Preview from an

   MFC application or the displayed paper width and height not changing,

   even when you change the paper size.

 - OpenFile() fails on filenames with OEM characters in the name.

 - GetDriveType() fails on a Stacker 3.1 drive.

 - SetCurrentDirectory() fails on Novell client machines.

 - GetProp() returns 0 in the second instance of an app in certain cases.

 - fopen(fn, "w") fails on second call.

 - TLS indices allocated by a module are released when that module is

   freed.

 - CreateWindow() handles STARTUPINFO incorrectly if the application starts

   minimized.

 - CreateFile() creates files with incorrect attributes.

 - Resource sections are now read/write to emulate the behavior of Windows

   NT and Windows 95.

 - Removed the 128K stack limitation.

 - CompareStringW() sometimes uses incorrect locale, primarily Swedish and

   other Scandinavian locales.

 - Added dummy _iob to CRTDLL for applications that reference standard

   handles.

 - Added support for OPENCHANNEL, CLOSECHANNEL, SEXGDIXFORM, and

   DOWNLOADHEADER escapes.

Additional reference words: 1.25 1.25a

KBCategory: kbprg kbfixlist kbbuglist

KBSubcategory: W32s


FIX: WinDbg FIND Dialog Box Slows Down the System

PSS ID Number: Q105586

Authored 20-Oct-1993	Last modified 29-Nov-1994

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

SYMPTOMS

Leaving the WinDbg FIND dialog box displayed after searching for some

string causes the CPU to go to 100 percent busy, making the system very

slow.

RESOLUTION

Choosing Cancel in the FIND dialog box allows the system to return to

normal.

STATUS

Microsoft has confirmed this to be a problem in WinDbg. This problem was

corrected in the Win32 SDK, version 3.5.

Additional reference words: 3.10 buglist3.10 fixlist3.50

KBCategory: kbtool kbbuglist kbfixlist

KBSubcategory: TlsWindbg


FIX: Winsock Over Appletalk (DDP) Leaks Memory

PSS ID Number: Q131159

Authored 05-Jun-1995	Last modified 07-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.5

SYMPTOMS

A memory leak occurs when you open a socket with address family

AF_APPLETALK, type SOCK_DGRAM, and protocol ATPROTO_BASE + x (where x is a

user-defined number except the ones that are reserved - please refer to the

SDK header file ATALKWSH.H); then once a server is located to send data to,

you send data to it.

Observing with PerfMon, you can see that non-paged memory use keeps on

increasing. It does not decrease even after the application is stopped. If

the application is allowed to continue for a long time, the results are

unpredictable and it is neccessary to restart the computer.

STATUS

Microsoft has confirmed this to be a bug in the Microsoft products listed

at the beginning of this article. This bug was corrected in Windows NT

version 3.51.

Additional reference words: 3.50 3.51

KBCategory: kbnetwork kbfixlist kbbuglist

KBSubcategory: NtwkWinsock


FixBrushOrgEx() and Brush Origins under Win32s

PSS ID Number: Q124191

Authored 21-Dec-1994	Last modified 05-May-1995

The information in this article applies to:

 - Microsoft Win32s versions 1.15, 1.15a, and 1.2

FixBrushOrgEx() is not implemented in the Win32 API, but it is provided for

compatibility with Win32s. If called, the function does nothing, and

returns FALSE.

A brush's origin relates to the origin of the window being painted. If you

move a window, the brush origin needs to be updated or else newly painted

patterns won't line up with the old patterns. On Windows version 3.1, the

system does not automatically update the brush origin when it is selected

into a device context (DC), so applications have to call SetBrushOrg(). On

Windows NT, the system automatically fixes brush origins when necessary.

Win32s uses FixBrushOrgEx() to hide this difference in system behavior. On

Win32s, FixBrushOrgEx() calls SetBrushOrgEx(). A Win32-based application

can check the platform and call SetBrushOrgEx() only if it is Win32s, or it

could simply always call FixBrushOrgEx() wherever a Windows-based

application would call SetBrushOrg() for brush origin tracking.

Additional reference words: 1.20

KBCategory: kbprg

KBSubcategory: W32s


FlushViewOfFile() on Remote Files

PSS ID Number: Q95043

Authored 31-Jan-1993	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

When flushing a memory-mapped file over a network, FlushViewOfFile()

guarantees that the data has been written from the workstation, but not

that the data resides on the remote disk.

This is because the server may be caching the data on the remote end.

Therefore, FlushViewOfFile() may return before the data has been physically

written to disk.

However, if the file was created via CreateFile() with the flag

FILE_FLAG_WRITE_THROUGH, the remote file system will not perform lazy

writes on the file, and FlushViewOfFile() will return when the actual

physical write is complete.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: BseFileio


Format for LANGUAGE Statement in .RES Files

PSS ID Number: Q89822

Authored 30-Sep-1992	Last modified 23-Jun-1995

The information in this article applies to:

- Microsoft Win32 SDK, versions 3.1, 3.5, 3.51, and 4.0

SUMMARY

The syntax for the LANGUAGE statement in the resource script file is given

as follows on page 289 of the Win32 SDK "Tools User's Guide" manual:

   LANGUAGE major, minor

   major

      Language identifier. Must be one of the constants from WINNLS.H

   minor

      Sublanguage identifier. Must be one of the constants from WINNLS.H

For example, suppose that you want to set the language for the resources in

a file to French. For the major parameter, you would choose the following

constant from the list of language identifiers

   #define LANG_FRENCH                  0x0c

and you would have the choice of any of the sublanguages that begin with

SUBLANG_FRENCH in the list of sublanguage identifiers. They are:

   #define SUBLANG_FRENCH               0x01

   #define SUBLANG_FRENCH_BELGIAN       0x02

   #define SUBLANG_FRENCH_CANADIAN      0x03

   #define SUBLANG_FRENCH_SWISS         0x04

RC.EXE does not directly place these constants in the .RES file. It uses

the macro MAKELANGID to turn the parameters into a WORD that corresponds to

a language ID.

NOTE: The following three combinations have special meaning:

Primary language ID   Sublanguage ID       Meaning

---------------------------------------------------------------------

LANG_NEUTRAL          SUBLANG_NEUTRAL      Language neutral

LANG_NEUTRAL          SUBLANG_DEFAULT      User default language

LANG_NEUTRAL          SUBLANG_SYS_DEFAULT  System default language

MORE INFORMATION

The following information is taken from the WINNLS.H file.

   A language ID is a 16-bit value that is the combination of a

   primary language ID and a secondary language ID.  The bits are

   allocated as follows:

      +-----------------------+-------------------------+

      |      Sublanguage ID   |   Primary Language ID   |

      +-----------------------+-------------------------+

       15                   10 9                       0   bit

   Language ID creation/extraction macros:

      MAKELANGID    - Construct language ID from primary language ID and

                      sublanguage ID.

      PRIMARYLANGID - Extract primary language ID from a language ID.

      SUBLANGID     - Extract sublanguage ID from a language ID.

The macros are defined as follows

   #define MAKELANGID(p, s)       ((((USHORT)(s)) << 10) | (USHORT)(p))

   #define PRIMARYLANGID(lgid)    ((USHORT)(lgid) & 0x3ff)

   #define SUBLANGID(lgid)        ((USHORT)(lgid) >> 10)

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbtool

KBSubcategory: TlsRc


FormatMessage() Converts GetLastError() Codes

PSS ID Number: Q94999

Authored 28-Jan-1993	Last modified 06-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

The FormatMessage() application programming interface (API) allows you

to convert error codes returned by GetLastError() into error strings,

using FORMAT_MESSAGE_FROM_SYSTEM in the dwFlags parameter.

MORE INFORMATION

The following code fragment demonstrates how to get the system message

string:

LPVOID lpMessageBuffer;

FormatMessage(

  FORMAT_MESSAGE_ALLOCATE_BUFFER |

  FORMAT_MESSAGE_FROM_SYSTEM,

  NULL,

  GetLastError(),

  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), //The user default language

  (LPTSTR) &lpMessageBuffer,

  0,

  NULL );

//... now display this string

// Free the buffer allocated by the system

LocalFree( lpMessageBuffer );

REFERENCES

For more information on language identifiers, please see the topic

MAKELANGID in the Win32 Programmer's Reference.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: BseMisc


Fractional Point Sizes Not Supported in ChooseFont()

PSS ID Number: Q77843

Authored 28-Oct-1991	Last modified 12-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

The ChooseFont() common dialog box library routine does not support

fractional point sizes. When a fractional point size is entered, it is

rounded to the nearest integral point size.

Rounding point sizes affects certain printers that support fractional font

sizes. For example, one particular HP LaserJet font cartridge contains an

8.5-point font. The ChooseFont() dialog box displays this font as an 8-

point font.

Additional reference words: 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrCmnDlg


Freeing Memory for Transactions in a DDEML Client App

PSS ID Number: Q83912

Authored 23-Apr-1992	Last modified 12-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

A Dynamic Data Exchange Management Library (DDEML) client application

can request data from a server both synchronously and asynchronously

by calling the DdeClientTransaction function.

To make a synchronous request, the client application specifies

XTYP_REQUEST as the value for the uType parameter to

DdeClientTransaction, and any reasonable value for the uTimeout

parameter.

To make an asynchronous request, the client application specifies

XTYP_REQUEST as the value for the uType parameter to

DdeClientTransaction, and TIMEOUT_ASYNC as the value for the uTimeout

parameter.

The client can also establish an advise loop with a server application

by specifying XTYP_ADVSTART as the value for the uType parameter. In

an advise loop, the client application's callback function receives an

XTYP_ADVDATA transaction each time the specified data item changes in

the server application. (NOTE: This article discusses only hot advise

loops in which changed data is communicated to the application. No

data is transferred for a warm advise loop, only a notification that

the data changed.)

The client application must free the data handle it receives from a

synchronous transaction; however, the client application should not

free the data handle it receives from an asynchronous transaction or

from an advise loop.

MORE INFORMATION

If the client application initiates a synchronous transaction, the

DdeClientTransaction function returns a handle to the requested data.

If the client application initiates an asynchronous transaction, the

DdeClientTransaction function returns either TRUE or FALSE. When the

data becomes available, the DDEML sends the client application an

XTYP_XACT_COMPLETE notification accompanied by a handle to the

requested data. In an active advise loop, the DDEML sends the client

application an XTYP_ADVDATA notification accompanied by a handle to

the updated data.

In the synchronous case, the client application must call

DdeFreeDataHandle before it terminates to free a data handle (and the

associated memory) that it received as the return value from

DdeClientTransaction. If the DDEML server specified HDATA_APPOWNED

when it created the data handle, then the data is invalidated when the

client calls DdeFreeDataHandle; the server must call DdeFreeDataHandle

before terminating to free the associated memory.

In the asynchronous case, the DDEML sends the client application's

callback function an XTYP_XACT_COMPLETE notification when the server

has completed the transaction. A handle to the requested data

accompanies the notification as the hData parameter to the callback

function. This handle is valid until control returns from the client

application's callback function. Once the client application's

callback function returns control, the DDEML may free the data handle

and the client application must not assume that the data handle

received in the callback function remains valid. This fact has two

implications, as follows:

 - The client application cannot call DdeFreeDataHandle on the data

   handle it receives with an XTYP_XACT_COMPLETE transaction. If the

   client invalidates the data handle by freeing it in the client's

   callback function, and the DDEML later attempts to free the handle,

   a Fatal Exit will result.

 - The client application must make a local copy of the data it

   receives with the XTYP_XACT_COMPLETE transaction to use that data

   after the callback function returns.

In an advise loop, the client application should not free the data

handle that it receives as the hData parameter to the callback

function. The DDEML frees the data handle when the client application

returns from its callback function. If the client calls

DdeFreeDataHandle on the data handle, the DDEML will cause a Fatal

Exit when it attempts to free the same data handle.

These rules apply to all data handles, whether or not the server

application specified the HDATA_APPOWNED flag when it created the

handle.

Additional reference words: 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrDde


Freeing Memory in a DDEML Server Application

PSS ID Number: Q83413

Authored 12-Apr-1992	Last modified 12-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

SUMMARY

A Dynamic Data Exchange Management Library (DDEML) server application

calls the DdeCreateDataHandle function to allocate a block of memory

for data it will send to a client application. DdeCreateDataHandle

returns a handle to a block of memory that can be passed between

applications.

The server application owns every data handle it creates. However, it

is not necessary to call DdeFreeDataHandle under every circumstance.

This article details the circumstances under which the server

application must call DdeFreeDataHandle and when the DDEML will

automatically free a data handle.

MORE INFORMATION

If the server application specifies the HDATA_APPOWNED flag in the

afCmd parameter to DdeCreateDataHandle, it must explicitly call

DdeFreeDataHandle to free the memory handle. Using HDATA_APPOWNED data

handles is convenient when data, such as system topic information, is

likely to be passed to a client application more than once, because the

server calls DdeCreateDataHandle only once, regardless of the number

of times the data handle is passed to a client application.

When it closes down, a server application must call DdeFreeDataHandle

for each data handle that it has not passed to a client application.

When the server creates a handle without specifying HDATA_APPOWNED,

and passes the handle to a client application in an asynchronous

transaction, the DDEML frees the data handle when the client returns

from its callback function. Therefore, the server is not required to

free the data handle it passes to a client because the DDEML frees the

handle. However, if the data handle is never sent to a client

application, the server must call DdeFreeDataHandle to free the

handle. It is the client application's responsibility to call

DdeFreeDataHandle for any data provided by a server in a synchronous

transaction.

Additional reference words: 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrDde


Freeing PackDDElParam() Memory

PSS ID Number: Q94149

Authored 28-Dec-1992	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.1, 3.5,

   3.51, and 4.0

When posting DDE messages via PostMessage(), an application first calls

PackDDElParam() and sends its return value (a pointer cast to LPARAM) as

the lParam in PostMessage().

Normally the receiving application is responsible for freeing the structure

[via FreeDDElParam()]. However, if the call to PostMessage() fails, the

posting application must free the packed data. This is also the method used

by 16-bit Windows.

Additional reference words: 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrDde


Gaining Access to ACLs

PSS ID Number: Q102098

Authored 28-Jul-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

To gain access to a security access control list (SACL), a process must

have the SE_SECURITY_NAME privilege. When requesting access, the calling

process must request ACCESS_SYSTEM_SECURITY in the desired access mask.

There is not a privilege that controls read or write access to a

discretionary access control list (DACL). Instead, access to read and write

an object's DACL is granted by the READ_CONTROL and WRITE_DAC access

rights, respectively. These rights must be specifically granted to the user

(or group containing the user) for DACL read or write access to be granted.

If the owner of an object requests READ_CONTROL or WRITE_DAC, the access

will always be granted.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseSecurity


GDI Objects and Windows 95 Heaps

PSS ID Number: Q125699

Authored 01-Feb-1995	Last modified 06-Apr-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

Under Windows version 3.1, GDI allocates all resources from a single 64K

heap. This limit has caused many applications to run out of GDI resources,

especially when using objects that can really take up a lot of the heap,

like elliptical regions. This caused GDI resources to be dangerously low

when executing several applications at once.

Windows 95 has now introduced a combination of a 16-bit heap and an

additional 32-bit heap. The 16-bit heap is still limited to 64K but the

32-bit heap can grow as large as available memory.

As in Windows version 3.1, the 16-bit GDI.EXE of Windows 95 continues to

have a 16-bit DGROUP segment with a local heap within it, and most logical

objects are still stored in this local heap. The data structures that

describe brushes, bitmap headers, and pens, for example, stay in the 16-bit

heap. All physical objects, like fonts and bitmaps, are now stored in the

32-bit heap. GDI regions have also been moved to the 32-bit heap. Moving

these GDI resources to the 32-bit heap takes the pressure off of the 64K

16-bit heap.

Regions can take up a large amount of resources and were the main source of

problems with GDI memory in Windows version 3.1. This will not be a

limitation in Windows 95 because regions are stored in the 32-bit heap.

Applications will be able to use much more complex regions, and regions

will be more useful now that they are not limited to a local 64K heap.

Windows 95, like Windows NT, will free all GDI resources owned by a 32-bit

process when that process terminates. Windows 95 will also clean up any GDI

resources of 16-bit processes marked as a 4.0 application. Because GDI

objects were sharable between applications in Windows version 3.1, Windows

95 will not immediately clean up GDI resources for 16-bit applications

marked with a version less than 4.0. However, when all 16-bit applications

have finished running, all GDI resources allocated by previous 16-bit

applications will be cleaned up.

Additional reference words: 4.00 Heaps

KBCategory: kbprg

KBSubcategory: GdiGeneral


General Overview of Win32s

PSS ID Number: Q83520

Authored 14-Apr-1992	Last modified 30-Mar-1995

The information in this article applies to:

 - Microsoft Win32s versions 1.1 and 1.2

SUMMARY

The following is intended as a general introduction to Win32s. More

information can be found in the "Win32s Programmer's Reference" and by

querying for Knowledge Base articles on "Win32s".

MORE INFORMATION

General Overview

----------------

The Win32 API consists of the Window 3.1 (Win16) API, with types stretched

to 32 bits, plus the addition of APIs which offer new functionality, like

threads, security, services, and virtual memory. Applications developed

using the Win32 API are called "Win32-based applications".

Win32s is a set of DLLs and a VxD which allow Win32-based applications to

run on top of Windows or Windows for Workgroups version 3.1. Win32s

supports a subset of the Win32 API, some directly (like memory management)

and some through thunks to the 16-bit systems (particularly GDI and User).

Win32s contains function stubs for the APIs that are not supported, which

return ERROR_NOT_IMPLEMENTED. Win32s also includes 4 new APIs which support

the Universal Thunk (UT). For details on which API are supported under

Win32s, refer to the individual API entries in the help file "Win32 API

Reference." Among the new features gained from Win32 are structured

exception handling (SEH), FP emulation, memory-mapped files, named shared

memory, and sparse memory.

Win32-based applications running on Windows 3.1 will generally be faster

than their Win16 equivalents on Windows 3.1, particularly if they are

memory or floating-point intensive. The actual speed improvement varies

with each application, because it depends on how often you cross the thunk

layer. Each call which uses a thunk is no more than 10 percent slower than

a direct call.

Binary Compatibility

--------------------

Win32s offers binary compatibility for Win32-based applications on Windows

3.1 and Windows NT.

When you call a Win32 API, two options should be allowed:

 - Option A: Your code should allow for a successful return from the

   function call.

 - Option B: Your code should allow for an unsuccessful return from

   the function call.

For example, if the application is running under Windows 3.1 and a call is

made to one of the supported APIs, then the call returns successfully and

option A is executed. If the call is made while running under Windows NT,

the call again returns successfully and option A should be executed.

However, if running under Windows 3.1 and a Win32 API function is called

that is unsupported, then an error code is returned and option B should be

executed.

If, for example, option A were using a CreateThread() call, then option B

would be alternative code, which would handle the task using a single-

thread solution.

Programming Issues

------------------

Win32-based applications cannot use MS-DOS and BIOS interrupts; therefore,

the Win32s VxD has Win32 entries for each Interrupt 21 and the BIOS calls.

The Win32s DLLs may thunk to Win16 when a Win32 application makes a call.

The 32-bit parameters are copied from the 32-bit stack to a 16-bit stack

and the 16-bit entry point is called. The Win32 application has a 128K

stack. When switching to the 16-bit side via UT, the same stack is used,

and a 16:16 stack pointer is created which points to the top of the stack.

The selector base is set so that there is at least an 8K stack for the

16-bit code.

There are other semantic difference between Windows 3.1 and Win32. Windows

3.1 will run applications for Win32 nonpreemptively in a single, shared

address space, while Windows NT runs them preemptively in separate address

spaces. It is therefore important that you test your Win32-based

application on both Windows 3.1 and Windows NT.

If you need to call routines that reside in a 16-bit DLL or Windows from

32-bit code, you can do this using the Win32s Universal Thunk or other

client-server techniques. For a description of UT, please see the

"Win32s Programmer's Reference" and the sample UTSAMPLE.

DDE, OLE, WM_COPYDATA, the clipboard, metafiles, and bitmaps can be used

between 16-bit Windows-based and Win32-based applications on both Windows

3.1 and Windows NT. RPC is not supported from Win32-based applications.

Additional reference words: 1.10 1.20

KBCategory: kbprg

KBSubcategory: W32s


GetClientRect() Coordinates Are Not Inclusive

PSS ID Number: Q43596

Authored 21-Apr-1989	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.1 and 3.0

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

The coordinates returned by GetClientRect() are not inclusive. For

example, to draw a border around the edge of the client area, draw it

from the coordinates (Rectangle.left, Rectangle.top) to

(Rectangle.right-1, Rectangle.bottom-1).

Addtional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrPnt


GetCommandLine() Under Win32s

PSS ID Number: Q102762

Authored 10-Aug-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32s versions 1.0, 1.1, and 1.2

Under Win32s, GetCommandLine() includes the full drive/path of the

executable, while under Windows NT GetCommandLine() does not include the

full path.

When programs are run from the Program Manager or the File Manager on

Windows 3.1, they are spawned using the full path. As a result, argv[0]

will have the complete path. When a Win32s application is spawned by a 16-

bit application, Windows detects that the application is a Win32s

application. The full path is passed to Win32s regardless of whether or not

WinExec() was invoked with the full path. As a result, 32-bit applications

receive the full path.

When a Win32-based application is spawned from another Win32-based

application, the 32-bit kernel passes the information as given by the

parent process [that is, if a Win32-based application is started via

CreateProcess() from another Win32-based application, argv[0] will contain

the path that the spawning application passed in].

Additional reference words: 1.00 1.10 1.20

KBCategory: kbprg

KBSubcategory: W32s


GetCurrentTime and GetTickCount Functions Identical

PSS ID Number: Q45702

Authored 13-Jun-1989	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.1 and 3.0

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

The GetCurrentTime() and GetTickCount() functions are identical. Each

returns the number of milliseconds (+/- 55 milliseconds) since the user

started Windows, and the return value of each function is declared to be a

DWORD.

The following code demonstrates these two functions:

   DWORD dwCurrTime;

   DWORD dwTickCount;

   char szCurrTime[50];

   dwCurrTime = GetCurrentTime ();

   dwTickCount = GetTickCount ();

   sprintf (szCurrTime, "Current time = %lu\nTick count = %lu",

            dwCurrTime, dwTickCount);

   MessageBox (hWnd, szCurrTime, "Times", MB_OK);

NOTE: GetCurrentTime() and GetTickCount() return an unsigned double word

(32-bit DWORD) which gives a maximum count of 4,294,967,296 ticks. This

number will yield a maximum count of 49.71 days which the system keeps

track of running time.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrTim


GetDeviceCaps(hDC, RASTERCAPS) Description

PSS ID Number: Q75912

Authored 09-Sep-1991	Last modified 25-May-1995

---

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

---

SUMMARY

GetDeviceCaps(hDC, RASTERCAPS) returns the raster capabilities bit

field in the GDIINFO structure, which indicates the raster

capabilities of the device. The RASTERCAPS index of the

GetDeviceCaps() function is documented in the "Microsoft Windows

Software Development Kit Reference Volume 1" on page 4-168. The flags

available include: RC_BANDING, RC_BITBLT, RC_BITMAP64, RC_DI_BITMAP,

RC_DIBTODEV, RC_GDI20_OUTPUT, RC_PALETTE, RC_SCALING, RC_STRETCHBLT,

and RC_STRETCHDIB. The GDIINFO structure itself is documented in the

"Microsoft Windows Device Development Kit Device Driver Adaptation

Guide."

An application should use GetDeviceCaps() to query the printer driver

for device capabilities. For example, before printing a bitmap larger

than 64K, the application should query the driver using

GetDeviceCaps() with the index RASTERCAPS and the flag RC_BITMAP64. If

the application fails to test for the capability and prints a bitmap

larger than 64K, unexpected printer output may occur if the driver

does not support bitmaps larger than 64K.

In particular, if the driver does not support a capability, GDI will

attempt to simulate it using a more fundamental capability of the

driver. However, the resulting GDI simulation is usually slower, is of

lower quality, or differs in some way from a device driver

implementation of the capability.

                                              Differences in

                     GDI Call to Invoke   Functionality Resulting

Field   Capability      Capability or      from Supporting or not

Name    or Function        Function        Supporting Capability

------|-------------|--------------------|----------------------------

  0   | BitBlt      |                    | ?

------|-------------|--------------------|----------------------------

  1   | Requires    |                    | ?

      | banding     |                    |

------|-------------|--------------------|----------------------------

  2   | Requires    |                    | ?

      | scaling     |                    |

------|-------------|--------------------|----------------------------

  3   | Supports    |                    | ?

      | >64K bitmaps|                    |

------|-------------|--------------------|----------------------------

  4   | Supports    | ExtTextOut         | GDI will call StrBlt() once

      | ExtTextOut, |                    | for each character to

      | FastBorder, |                    | simulate the ExtTextOut()

      | GetCharWidth|                    | function's ability to

      |             |                    | position proportionally-

      |             |                    | spaced characters. This can

      |             |                    | be very slow. GDI simulates

      |             |                    | bold text by overstriking

      |             |                    | one or more times. This

      |             |                    | fails on laser printers.

      |             |                    | Laser printer drivers that

      |             |                    | support ExtTextOut() offset

      |             |                    | the text before overstriking.

      |             |                    |

      |             | FastBorder         |

      |             |                    |

      |             | GetCharWidth       | Returns 0 if driver does

      |             |                    | not support GetCharWidth;

      |             |                    | otherwise, it calls

      |             |                    | ExtTextOut() or StrBlt()

      |             |                    | with count = -1 to obtain

      |             |                    | the width of each

      |             |                    | individual character.

------|-------------|--------------------|----------------------------

  5   | Has state   |                    |

      | block       |                    |

------|-------------|--------------------|----------------------------

  6   | Saves       |                    |

      | bitmaps in  |                    |

      | shadow      |                    |

      | memory      |                    |

------|-------------|--------------------|----------------------------

  7   | RC_DI_BITMAP| Supports Get and   | If GDI is called upon to

      |             | Set DIBs and RLEs  | copy a RLE bitmap that

      |             |                    | contains a transparent

      |             |                    | window (region not defined

      |             |                    | by the bitmap), the window

      |             |                    | will be filled by the

      |             |                    | current background color.

      |             |                    |

      |             |                    | The destination for any GDI

      |             |                    | DIB operation is a

      |             |                    | monochrome bitmap.

      |             |                    |

      |             |                    | Unidrv offers a variety of

      |             |                    | halftone dithering

      |             |                    | techniques to simulate a

      |             |                    | range of intensities on

      |             |                    | black and white and color

      |             |                    | printers. GDI does not.

      |             |                    | Unidrv offers intensity

      |             |                    | adjustment to darken and

      |             |                    | lighten halftone output.

      |             |                    | Unidrv does not support RLE

      |             |                    | DIBs at present.

------|-------------|--------------------|----------------------------

  8   | RC_PALETTE  | Performs color     |

      |             | palette management |

------|-------------|--------------------|----------------------------

  9   | RC_DIBTODEV | Supports           | See comments above for

      |             | SetDIBitsToDevice  | RC_DI_BITMAP

------|-------------|--------------------|----------------------------

 10   | RC_BIGFONTS | Supports Windows   | This flag specifies the

      |             | 3.0 FONTINFO       | format of the FONTINFO

      |             | structure format   | structure passed between

      |             |                    | GDI's SelectObject() call

      |             |                    | and the driver's

      |             |                    | RealizeFont() function. If

      |             |                    | a bit is set, the Windows

      |             |                    | 3.0 format is used.

      |             |                    | Otherwise, the Windows 2.0

      |             |                    | font file format is used.

------|-------------|--------------------|----------------------------

 11   |RC_STRETCHBLT| Supports StretchBlt|

------|-------------|--------------------|----------------------------

 12   | RC_FLOODFILL| Supports flood fill|

------|-------------|--------------------|----------------------------

 13   |RC_STRETCHDIB| Supports           | See comments above for

      |             | StretchDIBits      | RC_DI_BITMAP. Additionally,

      |             |                    | Unidrv has these limits on

      |             |                    | the degree of stretching

      |             |                    | and shrinking supported:

      |             |                    |

      |             |                    | The X and Y axes may be

      |             |                    | scaled independently.

      |             |                    |

      |             |                    | The maximum scale-up factor

      |             |                    | is 256.

      |             |                    |

      |             |                    | The maximum product of the

      |             |                    | X and Y scale-down factors

      |             |                    | is 256.

      |             |                    |

      |             |                    | Therefore, if both axes are

      |             |                    | scaled down equally, the

      |             |                    | maximum scale-down factor

      |             |                    | for each axis is 16.

------|-------------|--------------------|----------------------------

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: GdiDc


GetGlyphOutline() Native Buffer Format

PSS ID Number: Q87115

Authored 22-Jul-1992	Last modified 25-May-1995

---

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

---

SUMMARY

The GetGlyphOutline function provides a method for an application to

retrieve the lowest-level information about a glyph in the TrueType

environment. This article describes the format of the data the

GetGlyphOutline function returns.

MORE INFORMATION

A glyph outline is a series of contours that describe the glyph. Each

contour is defined by a TTPOLYGONHEADER data structure, which is

followed by as many TTPOLYCURVE data structures as are required to

describe the contour.

Each position is described by a POINTFX data structure, which

represents an absolute position, not a relative position. The starting

and ending point for the glyph is given by the pfxStart member of the

TTPOLYGONHEADER data structure.

The TTPOLYCURVE data structures fall into two types: a TT_PRIM_LINE

record or a TT_PRIM_QSPLINE record. A TT_PRIM_LINE record is a series

of points; lines drawn between the points describe the outline of the

glyph. A TT_PRIM_QSPLINE record is a series of points defining the

quadratic splines (q-splines) required to describe the outline of the

character.

In TrueType, a q-spline is defined by three points (A, B, and C),

where points A and C are on the curve and point B is off the curve.

The equation for each q-spline is as follows (xA represents the

x-coordinate of point A, yA represents the y-coordinate of point A,

and so on)

   x(t) = (xA-2xB+xC)*t^2 + (2xB-2xA)*t + xA

   y(t) = (yA-2yB+yC)*t^2 + (2yB-2yA)*t + yA

where t varies from 0.0 to 1.0.

The format of a TT_PRIM_QSPLINE record is as follows:

 - Point A on the q-spline is the current position (either pfxStart in

   the TTPOLYGONHEADER, the starting point for the TTPOLYCURVE, or the

   ending point of the previous TTPOLYCURVE).

 - Point B is the current point in the record.

 - Point C is as follows:

    - If the record has two or more points following point B, point C

      is the midpoint between point B and the next point in the

      record.

    - Otherwise, point C is the point following point B.

The following code presents the algorithm used to process a

TT_PRIM_QSPLINE record. While this code demonstrates how to extract

q-splines from a TT_PRIM_QSPLINE record, it is not appropriate for use

in an application.

pfxA = pfxStart;                // Starting point for this polygon

for (u = 0; u < cpfx - 1; u++)  // Walk through points in spline

   {

   pfxB = apfx[u];              // B is always the current point

   if (u < cpfx - 2)            // If not on last spline, compute C

      {

      pfxC.x = (pfxB.x + apfx[u+1].x) / 2;  // x midpoint

      pfxC.y = (pfxB.y + apfx[u+1].y) / 2;  // y midpoint

      }

   else                         // Else, next point is C

      pfxC = apfx[u+1];

                                // Draw q-spline

   DrawQSpline(hdc, pfxA, pfxB, pfxC);

   pfxA = pfxC;                 // Update current point

   }

The algorithm above manipulates points directly, using floating-point

operators. However, points in q-spline records are stored in a FIXED

data type. The following code demonstrates how to manipulate FIXED

data items:

FIXED fx;

long *pl = (long *)&fx;

// Perform all arithmetic on *pl rather than on fx

*pl = *pl / 2;

The following function converts a floating-point number into the FIXED

representation:

FIXED FixedFromDouble(double d)

{

   long l;

   l = (long) (d * 65536L);

   return *(FIXED *)&l;

}

In a production application, rather than writing a DrawQSpline

function to draw each q-spline individually, it is more efficient to

calculate points on the q-spline and store them in an array of POINT

data structures. When the calculations for a glyph are complete, pass

the POINT array to the PolyPolygon function to draw and fill the

glyph.

The following example presents the data returned by the

GetGlyphOutline for the lowercase "j" glyph in the 24-point Arial font

of the 8514/a (Small Fonts) video driver:

GetGlyphOutline GGO_NATIVE 'j'

  dwrc            = 208      // Total native buffer size in bytes

  gmBlackBoxX, Y  = 6, 29    // Dimensions of black part of glyph

  gmptGlyphOrigin = -1, 23   // Lower-left corner of glyph

  gmCellIncX, Y   = 7, 0     // Vector to next glyph origin

TTPOLYGONHEADER #1           // Contour for dot on "j"

  cb       = 44              // Total size of dot polygon

  dwType   = 24              // TT_POLYGON_TYPE

  pfxStart = 2.000, 20.000   // Start at lower-left corner of dot

  TTPOLYCURVE #1

    wType  = TT_PRIM_LINE

    cpfx   = 3

    pfx[0] = 2.000, 23.000

    pfx[1] = 5.000, 23.000

    pfx[2] = 5.000, 20.000   // Automatically close to pfxStart

TTPOLYGONHEADER #2   // Contour for body of "j"

  cb       = 164     // Total size is 164 bytes

  dwType   = 24      // TT_POLYGON_TYPE

  pfxStart = -1.469, -5.641

  TTPOLYCURVE #1     // Finish flat bottom end of "j"

    wType  = TT_PRIM_LINE

    cpfx   = 1

    pfx[0] = -0.828, -2.813

  TTPOLYCURVE #2    // Make hook in "j" with spline

                    // Point A in spline is end of TTPOLYCURVE #1

    wType  = TT_PRIM_QSPLINE

    cpfx   = 2               // two points in spline -> one curve

    pfx[0] = -0.047, -3.000  // This is point B in spline

    pfx[1] = 0.406, -3.000   // Last point is always point C

  TTPOLYCURVE #3    // Finish hook in "j"

                    // Point A in spline is end of TTPOLYCURVE #2

    wType  = TT_PRIM_QSPLINE

    cpfx   = 3               // Three points -> two splines

    pfx[0] = 1.219, -3.000   // Point B for first spline

                             // Point C is (pfx[0] + pfx[1]) / 2

    pfx[1] = 2.000, -1.906   // Point B for second spline

    pfx[2] = 2.000, 0.281    // Point C for second spline

  TTPOLYCURVE #4    // Majority of "j" outlined by this polyline

    wType  = TT_PRIM_LINE

    cpfx   = 3

    pfx[0] = 2.000, 17.000

    pfx[1] = 5.000, 17.000

    pfx[2] = 5.000, -0.250

  TTPOLYCURVE #5    // start of bottom of hook

    wType  = TT_PRIM_QSPLINE

    cpfx   = 2               // One spline in this polycurve

    pfx[0] = 5.000, -3.266   // Point B for spline

    pfx[1] = 4.188, -4.453   // Point C for spline

  TTPOLYCURVE #6    // Middle of bottom of hook

    wType  = TT_PRIM_QSPLINE

    cpfx   = 2               // One spline in this polycurve

    pfx[0] = 3.156, -6.000   // B for spline

    pfx[1] = 0.766, -6.000   // C for spline

  TTPOLYCURVE #7    // Finish bottom of hook and glyph

    wType  = TT_PRIM_QSPLINE

    cpfx   = 2               // One spline in this polycurve

    pfx[0] = -0.391, -6.000  // B for spline

    pfx[1] = -1.469, -5.641  // C for spline

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: GdiTt


GetInputState Is Faster Than GetMessage or PeekMessage

PSS ID Number: Q35605

Authored 16-Sep-1988	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

This article describes a method to quickly determine whether an

application for the Microsoft Windows graphical environment has any

keyboard or mouse messages in its queue without calling the GetMessage

or PeekMessage functions.

NOTE: In Win32, GetInputState is thread-local only.

MORE INFORMATION

The GetInputState function returns this information more quickly than

GetMessage or PeekMessage. GetInputState returns TRUE (nonzero) if

either a keyboard or mouse message is in the application's input

queue. If the application must distinguish between a mouse and a

keyboard message, GetInputState returns the value 2 for a keyboard and

the value 1024 for a mouse message.

Because difficulties may arise if the application loses the input

focus, use GetInputState only in tight loop conditions where execution

speed is critical.

In Win32, message queues are not global as they are in 16-bit Windows. The

message queues are local to the thread. When you call GetInputState, you

are checking to see if there are mouse or keyboard messages for the calling

thread only. If a window created by another thread in the application has

the keyboard input waiting, GetInputState will not be able to check for

those messages.

Additional reference words: 3.00 3.10 3.50 4.00 95  yield

KBCategory: kbprg

KBSubcategory: UsrMsg


GetLastError() May Differ Between Windows 95 and Windows NT

PSS ID Number: Q127991

Authored 22-Mar-1995	Last modified 06-Apr-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

The extended error codes returned by the GetLastError() API are not

guaranteed to be the same under Windows 95 and Windows NT. This difference

applies to extended error codes generated by calls to GDI, Window

Management, and System Services APIs.

The set of potential error codes returned by any particular Win32 API

depends on many underlying components, including system kernel-mode

components and loaded drivers. The extended error codes are not a part of

the Win32 specification. Therefore, they can change as operating system and

driver code is changed.

It is impossible to get the error codes for each API in synch across

operating system and platforms. Windows NT and Windows 95 have different

code bases. Third-party drivers return error codes that are mapped to Win32

error codes. In addition, it would be difficult to accurately maintain

error code information in the Win32 Programmer's Reference. Therefore, this

information is not included in the documentation.

In general, you should not rely on GetLastError() returning the same values

under Windows 95 and Windows NT. Sometimes, an API will fail and

GetLastError() will return 0 (ERROR_SUCCESS) under Windows 95. This is

because some of the APIs do not set error codes under Windows 95.

Additional reference words: 4.00

KBCategory: kbprg

KBSubcategory: BseMisc UsrMisc GdiMisc


GetSystemMetrics(SM_CMOUSEBUTTONS) Fails Under Win32s

PSS ID Number: Q124836

Authored 12-Jan-1995	Last modified 24-Feb-1995

The information in this article applies to:

 - Microsoft Win32s versions 1.15, 1.15a, and 1.20

Under Win32s, the Win32 API GetSystemMetrics() is implemented as a direct

thunk to Windows version 3.1. Therefore, the call will return whatever

Windows version 3.1 would return for a similar call to the Windows API

GetSystemMetrics().

GetSystemMetrics() returns zero for all unrecognized parameters. Under

Windows, this includes the new flag SM_CMOUSEBUTTONS, which was introduced

in the Win32 API. Therefore, avoid using the SM_CMOUSEBUTTONS flag when

your Win32-based application is running under Win32s.

Additional reference words: 1.20

KBCategory: kbprg

KBSubcategory: W32s


Getting a Dialog to Use an Icon When Minimized

PSS ID Number: Q114612

Authored 08-May-1994	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

The standard Windows dialog box does not have an icon when it is minimized.

A dialog box can be made to use an icon by replacing the standard dialog

box class with a private dialog box class.

MORE INFORMATION

The standard dialog box class specifies NULL as the value of the hIcon

field of its WNDCLASS structure. So no icon is drawn when the standard

dialog box is minimized.

An icon can be specified by getting the dialog to use a private class as

follows:

1. Register a private class.

      WNDCLASS wc;

      wc.style = CS_DBLCLKS | CS_SAVEBITS | CS_BYTEALIGNWINDOW;

      wc.lpfnWndProc = DefDlgProc;

      wc.cbClsExtra = 0;

      wc.cbWndExtra = DLGWINDOWEXTRA;

      wc.hInstance = hinst;

      wc.hIcon = LoadIcon(hinst, "DialogIcon");

      wc.hCursor = LoadCursor(NULL, IDC_ARROW);

      wc.hbrBackground = COLOR_WINDOW + 1;

      wc.lpszMenuName = NULL;

      wc.lpszClassName = "MyDlgClass";

      RegisterClass(&wc);

   NOTE: The default dialog window procedure, DefDlgProc(), is used as the

   window procedure of the class. This causes windows of this class to

   behave as standard dialogs. The cbWndExtra field has to be assigned to

   DLGWINDOWEXTRA - the dialog box stores its internal state information in

   these extra window bytes. The icon to be used when the dialog box is

   minimized is assigned to the hIncon field.

2. Get the dialog box to use the private class.

   Use the CLASS statement in the dialog box template to get the dialog box

   to use the private class:

      IDD_MYDIALOG DIALOG 0, 0, 186, 92

      CLASS "MyDlgClass"

      :

3. Create the dialog box using DialogBox() or CreateDialog().

      DialogBox (hinst,

                 MAKEINTRESOURCE (IDD_MYDIALOG),

                 NULL,

                (DLGPROC)MyDlgFunc);

   MyDlgFunc() is the dialog function implemented by the application. When

   the dialog box is minimized, it will use the icon specified in the

   private class.

Additional reference words: 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrDlgs


Getting and Using a Handle to a Directory

PSS ID Number: Q105306

Authored 17-Oct-1993	Last modified 05-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   versions 3.1 and 3.5

SUMMARY

CreateDirectory() can be used to open a new directory. An existing

directory can be opened by calling CreateFile(). To open an existing

directory with CreateFile(), it is necessary to specify the flag

FILE_FLAG_BACKUP_SEMANTICS. The following code shows how this can be done:

   HANDLE hFile;

   hFile = CreateFile( "c:\\mstools",

              GENERIC_READ | GENERIC_WRITE,

              FILE_SHARE_READ | FILE_SHARE_WRITE,

              NULL,

              OPEN_EXISTING,

              FILE_FLAG_BACKUP_SEMANTICS,

              NULL

           );

   if( hFile == INVALID_HANDLE_VALUE )

      MessageBox( NULL, "CreateFile() failed", NULL, MB_OK );

The handle obtained can be used to obtain information about the directory

or to set information about the directory. For example:

   BY_HANDLE_FILE_INFORMATION fiBuf;

   FILETIME ftBuf;

   SYSTEMTIME stBuf;

   char msg[40];

   GetFileInformationByHandle( hFile, &fiBuf );

   FileTimeToLocalFileTime( &fiBuf.ftLastWriteTime, &ftBuf );

   FileTimeToSystemTime( &ftBuf, &stBuf );

   wsprintf( msg, "Last write time is %d:%d  %d/%d/%d",

      stBuf.wHour,stBuf.wMinute,stBuf.wMonth,stBuf.wDay,stBuf.wYear );

   MessageBox( NULL, msg, NULL, MB_OK );

MORE INFORMATION

Opening directories with CreateFile is not supported on Windows 95.

This code does not work on Win32s, because MS-DOS does not support opening

a directory. If you are looking for the creation time of a directory, use

FindFirstFile(), because it works on all platforms.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseFileio


Getting Floppy Drive Information

PSS ID Number: Q115828

Authored 05-Jun-1994	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   versions 3.1 and 3.5

SUMMARY

To get the media type(s) supported by a floppy drive, it is necessary to

call CreateFile() to get a handle to the drive and then DeviceIoControl()

to get the information. However, if there is no floppy disk in the floppy

drive, the following message box may appear when CreateFile() is called for

drive A (\\.\a:):

   There is no disk in the drive. Please insert a disk into drive A:

When calling CreateFile(), be sure to use 0 for the access mode and

FILE_SHARE_READ for the share mode so that the user will not be prompted to

insert a floppy disk:

   CreateFile(

      szFileName,

      0,

      FILE_SHARE_READ,

      NULL,

      OPEN_ALWAYS,

      0,

      NULL

   );

Another way to avoid the message box prompt is to put

   SetErrorMode( SEM_FAILCRITICALERRORS );

before the call to CreateFile().

MORE INFORMATION

The following sample code is based on the code in the FLOPPY SDK sample,

but it simply displays the media type(s) supported by floppy drive A. The

code demonstrates one way to retrieve the supported media without requiring

you to insert a floppy disk in the drive.

Sample Code

-----------

#include <windows.h>

#include <stdio.h>

#include <winioctl.h>

DISK_GEOMETRY SupportedGeometry[20];

DWORD SupportedGeometryCount;

VOID

GetSupportedGeometrys( HANDLE hDisk )

{

   DWORD ReturnedByteCount;

   if( DeviceIoControl(

          hDisk,

          IOCTL_DISK_GET_MEDIA_TYPES,

          NULL,

          0,

          SupportedGeometry,

          sizeof(SupportedGeometry),

          &ReturnedByteCount,

          NULL

      ))

      SupportedGeometryCount = ReturnedByteCount /  sizeof(DISK_GEOMETRY);

   else SupportedGeometryCount = 0;

}

VOID

PrintGeometry( PDISK_GEOMETRY lpGeometry )

{

   LPSTR MediaType;

   switch ( lpGeometry->MediaType ) {

      case F5_1Pt2_512:

         MediaType = "5.25, 1.2MB,  512 bytes/sector";

         break;

      case F3_1Pt44_512:

         MediaType = "3.5,  1.44MB, 512 bytes/sector";

         break;

      case F3_2Pt88_512:

         MediaType = "3.5,  2.88MB, 512 bytes/sector";

         break;

      case F3_20Pt8_512:

         MediaType = "3.5,  20.8MB, 512   bytes/sector";

         break;

      case F3_720_512:

         MediaType = "3.5,  720KB,  512 bytes/sector";

         break;

      case F5_360_512:

         MediaType = "5.25, 360KB,  512 bytes/sector";

         break;

      case F5_320_512:

         MediaType = "5.25, 320KB,  512 bytes/sector";

         break;

      case F5_320_1024:

         MediaType = "5.25, 320KB,  1024 bytes/sector";

         break;

      case F5_180_512:

         MediaType = "5.25, 180KB,  512 bytes/sector";

         break;

      case F5_160_512:

         MediaType = "5.25, 160KB,  512  bytes/sector";

         break;

      case RemovableMedia:

         MediaType = "Removable media other than floppy";

         break;

      case FixedMedia:

         MediaType = "Fixed hard disk media";

         break;

      default:

         MediaType = "Unknown";

         break;

   }

   printf("    Media Type %s\n", MediaType );

   printf("    Cylinders %d, Tracks/Cylinder %d, Sectors/Track %d\n",

          lpGeometry->Cylinders.LowPart, lpGeometry->TracksPerCylinder,

          lpGeometry->SectorsPerTrack

         );

}

void main( int argc, char *argv[], char *envp[] )

{

   HANDLE hDrive;

   UINT i;

   hDrive = CreateFile(

                   "\\\\.\\a:",

                   0,

                   FILE_SHARE_READ,

                   NULL,

                   OPEN_ALWAYS,

                   0,

                   NULL

                   );

   if ( hDrive == INVALID_HANDLE_VALUE )

   {

      printf( "Open failed: %d\n", GetLastError() );

      ExitProcess(1);

   }

   GetSupportedGeometrys( hDrive );

   printf( "\nDrive A supports the following disk geometries\n" );

   for( i=0; i<SupportedGeometryCount; i++ )

   {

       printf("\n");

       PrintGeometry( &SupportedGeometry[i] );

   }

   printf("\n");

}

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseMisc


Getting Real Handle to Thread/Process Requires Two Calls

PSS ID Number: Q90470

Authored 15-Oct-1992	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

The API GetCurrentThread() returns a pseudo-handle rather than the real

handle to the thread. To get the real handle to the thread, you need to use

DuplicateHandle() using the pseudo-handle that is returned from

GetCurrentThread(). In addition, to get the real handle to a process, you

need to call DuplicateHandle() after calling GetCurrentProcess().

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: BseProcThrd


Getting Resources from 16-Bit DLLs Under Win32s

PSS ID Number: Q105761

Authored 24-Oct-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32s versions 1.0, 1.1, and 1.2

A Win32-based application running under Win32s can load a 16-bit dynamic-

link library (DLL) using LoadLibrary() and free it with FreeLibrary(). This

behavior is allowed primarily so that GetProcAddress() can be called for

printer driver application programming interfaces (APIs).

Calling FindResource() with the handle that LoadLibrary() returns to the

DLL that it just loaded results in an access violation. However, the

Win32-based application can use the following APIs with this handle

   LoadBitmap

   LoadCursor

   LoadIcon

because this results in USER.EXE (16-bit) making calls to KERNEL.EXE.

If you go through a Universal Thunk to get raw resource data from the

16-bit DLL, it is necessary to convert the resource to 32-bit format,

because the resource format is different from the 16-bit format. The 32-bit

format is described in the Software Development Kit (SDK) file

DOC\SDK\FILEFRMT\RESFMT.TXT.

To determine whether a DLL is a 32-bit or 16-bit DLL, check the DLL header.

The DWORD at offset 0x3C indicates where to look for the PE signature.

Compare the 4 bytes there to 0x00004550 to determine whether this is a

Win32 DLL.

Additional reference words: 1.00 1.10 1.20

KBCategory: kbprg

KBSubcategory: W32s


Getting the Filename Given a Window Handle

PSS ID Number: Q119163

Authored 09-Aug-1994	Last modified 21-Feb-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   versions 3.1 and 3.5

SUMMARY

To find the filename of the program that created a given window under

Windows, you would use GetWindowLong(hWnd, GWL_HINSTANCE) to find the

module handle and then GetModuleFileName() to find the filename. This

method cannot be used under Windows NT because instance handles are not

global, but are unique to the address space in which the application is

running.

If the application that created the window is a Windows-based application,

the name returned is "ntvdm". To get the actual filename, you need to spawn

a Win16 application that will call GetModuleFileName() and pass the

filename back to your application using some form of interprocess

communication (IPC).

MORE INFORMATION

To find the filename of an application once you have its window handle,

first use GetWindowThreadProcessId() to find the process ID (PID) of the

process that created the window. Using the PID, query the registry for the

performance data associated with the process. To do this, you have to

enumerate all processes in the system, comparing each PID to the PID of the

process that you are looking for, until the data for that process is found.

(This data includes the name of the process.)

The following sample code demonstrates how to find the filename of the

Program Manager, PROGMAN.EXE, after obtaining its window handle:

Sample Code

-----------

   #include <windows.h>

   #include <stdio.h>

   #include <string.h>

   #define Key "SOFTWARE\\Microsoft\\Windows

   NT\\CurrentVersion\\Perflib\\009"

   void GetIndex( char *, char * );

   void DisplayFilename( DWORD );

   /********************************************************************\

   * Function: void main( )                                             *

   *                                                                    *

   * Purpose : Application entry point                                  *

   *                                                                    *

   void main( )

   {

      HWND                      hWnd;

      DWORD                     dwActiveProcessId;

      // Get window handle of Program Manager's main window.

      hWnd = FindWindow( "Progman", NULL );

      // Get PID of Program Manager.

      GetWindowThreadProcessId( hWnd, &dwActiveProcessId );

      // Display name of Program Manager's executable file.

      printf( "Searching for filename of Program Manager...\n" );

      DisplayFilename( dwActiveProcessId );

   }

   /********************************************************************\

   * Function: void DisplayFilename( DWORD )                            *

   *                                                                    *

   * Purpose : Display executable filename of the process whose PID     *

   *           is passed in as a parameter.                             *

   *                                                                    *

   * Comment : The information is retrieved from the performance        *

   *           data in the registry.                                    *

   *                                                                    *

   void DisplayFilename( DWORD dwProcessId )

   {

      DWORD                     CurrentProcessId;

      BOOL                      bContinue = TRUE;

      char                      szIndex[256] = "";

      DWORD                     dwBytes = 12000;

      DWORD                     dwProcessIdOffset;

      int                       i;

      PPERF_DATA_BLOCK          pdb;

      PPERF_OBJECT_TYPE         pot;

      PPERF_INSTANCE_DEFINITION pid;

      PPERF_COUNTER_BLOCK       pcb;

      PPERF_COUNTER_DEFINITION  pcd;

      // Get the index for the PROCESS object.

      GetIndex( "Process", szIndex );

      // Get memory for PPERF_DATA_BLOCK.

      pdb = (PPERF_DATA_BLOCK) HeapAlloc( GetProcessHeap(),

                                          HEAP_ZERO_MEMORY,

                                          dwBytes);

      // Get performance data.

      while( RegQueryValueEx(HKEY_PERFORMANCE_DATA, (LPTSTR)szIndex, NULL,

                             NULL, (LPBYTE)pdb, &dwBytes) ==

   ERROR_MORE_DATA )

      {

         // Increase memory.

         dwBytes += 1000;

         // Allocated memory is too small; reallocate new memory.

         pdb = (PPERF_DATA_BLOCK) HeapReAlloc( GetProcessHeap(),

                                               HEAP_ZERO_MEMORY,

                                               (LPVOID)pdb,

                                               dwBytes);

      }

      // Get PERF_OBJECT_TYPE.

      pot = (PPERF_OBJECT_TYPE)((PBYTE)pdb + pdb->HeaderLength);

      // Get the first counter definition.

      pcd = (PPERF_COUNTER_DEFINITION)((PBYTE)pot + pot->HeaderLength);

      // Get index value for ID_PROCESS.

      szIndex[0] = '\0';

      GetIndex( "ID Process", szIndex );

      for( i=0; i< (int)pot->NumCounters; i++ )

      {

         if (pcd->CounterNameTitleIndex == (DWORD)atoi(szIndex))

         {

            dwProcessIdOffset = pcd->CounterOffset;

            break;

         }

         pcd = ((PPERF_COUNTER_DEFINITION)((PBYTE)pcd + pcd->ByteLength));

      }

      // Get the first instance of the object.

      pid = (PPERF_INSTANCE_DEFINITION)((PBYTE)pot + pot-

   >DefinitionLength);

      // Get the name of the first process.

      pcb = (PPERF_COUNTER_BLOCK) ((PBYTE)pid + pid->ByteLength );

      CurrentProcessId = *((DWORD *) ((PBYTE)pcb + dwProcessIdOffset));

      // Find the process object for PID passed in, then print its

      // filename.

      for( i = 1; i < pot->NumInstances && bContinue; i++ )

      {

         if( CurrentProcessId == dwProcessId )

         {

            printf( "The filename is %ls.exe.\n",

                    (char *) ((PBYTE)pid + pid->NameOffset) );

            bContinue = FALSE;

         }

         else

         {

            pid = (PPERF_INSTANCE_DEFINITION) ((PBYTE)pcb + pcb-

   >ByteLength);

            pcb = (PPERF_COUNTER_BLOCK) ((PBYTE)pid + pid->ByteLength);

            CurrentProcessId = *((DWORD *)((PBYTE)pcb +

   dwProcessIdOffset));

         }

      }

      if( bContinue == TRUE )

         printf( "Not found.\b" );

      // Free the allocated memory.

      if( !HeapFree(GetProcessHeap(), 0, (LPVOID)pdb) )

         printf( "HeapFree failed in main.\n" );

      // Close handle to the key.

      RegCloseKey( HKEY_PERFORMANCE_DATA );

   }

   /********************************************************************\

   * Function: void GetIndex( char *, char * )                          *

   *                                                                    *

   * Purpose : Get the index for the given counter                      *

   *                                                                    *

   * Comment : The index is returned in the parameter szIndex           *

   *                                                                    *

   void GetIndex( char *pszCounter, char *szIndex )

   {

      char*  pszBuffer;

      char*  pszTemp;

      char   szObject[256] = "";

      DWORD  dwBytes;

      HANDLE hKeyIndex;

      int    i = 0;

      int    j = 0;

      // Open the key.

      RegOpenKeyEx( HKEY_LOCAL_MACHINE,

                    Key,

                    0, KEY_READ,

                    &hKeyIndex );

      // Get the size of the counter.

      RegQueryValueEx( hKeyIndex,

                       "Counters",

                       NULL, NULL, NULL,

                       &dwBytes );

      // Allocate memory for the buffer.

      pszBuffer = (char *) HeapAlloc( GetProcessHeap(),

                                      HEAP_ZERO_MEMORY,

                                      dwBytes );

      // Get the titles and counters.

      RegQueryValueEx( hKeyIndex,

                       "Counters",

                       NULL, NULL,

                       (LPBYTE)pszBuffer,

                       &dwBytes );

      // Find the index value for PROCESS.

      pszTemp = pszBuffer;

      while( i != (int)dwBytes )

      {

         while (*(pszTemp+i) != '\0')

         {

            szIndex[j] = *(pszTemp+i);

            i++;

            j++;

         }

         szIndex[j] = '\0';

         i++;

         j = 0;

         while (*(pszTemp+i) != '\0')

         {

            szObject[j] = *(pszTemp+i);

            i++;

            j++;

         }

         szObject[j] = '\0';

         i++;

         j = 0;

         if( *(pszTemp+i) == '\0' )

            i++;

         if( strcmp(szObject, pszCounter) == 0 )

            break;

      }

      // Deallocate the memory.

      HeapFree( GetProcessHeap(), 0, (LPVOID)pszBuffer );

      // Close the key.

      RegCloseKey( hKeyIndex );

   }

REFERENCES

For more information on working with the performance data, please see one

or all of the following references:

 - The "Win32 Programmer's Reference."

 - The "Windows NT Resource Kit," volume 3.

 - The source code for PView that is included in the Win32 SDK.

 - The "Windows/MS-DOS Developer's Journal," April 1994.

Additional reference words: 3.10 3.50 file name

KBCategory: kbprg

KBSubcategory: BseMisc


Getting the MAC Address for an Ethernet Adapter

PSS ID Number: Q118623

Authored 25-Jul-1994	Last modified 26-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

To get the Media Access Control (MAC) address for an ethernet adapter

programmatically, you can use NetBIOS if your card is bound to NetBIOS. Use

the Netbios() NCBASTAT command and provide a "*" as the name in the

NCB.ncb_CallName field. This is demonstrated in the sample code below.

With the NetBEUI and IPX transports, the same information can be obtained

at a command prompt by using:

   net config workstation

The ID given is the MAC address.

Sample Code

-----------

   #include <windows.h>

   #include <wincon.h>

   #include <stdlib.h>

   #include <stdio.h>

   #include <time.h>

   typedef struct _ASTAT_

   {

      ADAPTER_STATUS adapt;

      NAME_BUFFER    NameBuff [30];

   }ASTAT, * PASTAT;

   ASTAT Adapter;

   void main (void)

   {

      NCB Ncb;

      UCHAR uRetCode;

      char NetName[50];

      memset( &Ncb, 0, sizeof(Ncb) );

      Ncb.ncb_command = NCBRESET;

      Ncb.ncb_lana_num = 0;

      uRetCode = Netbios( &Ncb );

      printf( "The NCBRESET return code is: 0x%x \n", uRetCode );

      memset( &Ncb, 0, sizeof (Ncb) );

      Ncb.ncb_command = NCBASTAT;

      Ncb.ncb_lana_num = 0;

      strcpy( Ncb.ncb_callname,  "*               " );

      Ncb.ncb_buffer = (char *) &Adapter;

      Ncb.ncb_length = sizeof(Adapter);

      uRetCode = Netbios( &Ncb );

      printf( "The NCBASTAT return code is: 0x%x \n", uRetCode );

      if ( uRetCode == 0 )

      {

         printf( "The Ethernet Number is: %02x%02x%02x%02x%02x%02x\n",

                  Adapter.adapt.adapter_address[0],

                  Adapter.adapt.adapter_address[1],

                  Adapter.adapt.adapter_address[2],

                  Adapter.adapt.adapter_address[3],

                  Adapter.adapt.adapter_address[4],

                  Adapter.adapt.adapter_address[5] );

      }

   }

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: NtwkNetbios


Getting the Net Time on a Domain

PSS ID Number: Q98722

Authored 12-May-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

SUMMARY

When trying to execute

   net time /domain:egdomain /set

you may get a message saying the account is not known or the password is

invalid. This can happen if you are logged on using an account whose name

is spelled "Administrator", but the account is a different Administrator

account than the one on the domain controller. For example, if you are

logged on as EGMACHINE\Administrator, and attempt

   net time /domain:egdomain /set

you will get an error message because EGMACHINE\Administrator is not the

same account as EGDOMAIN\Administrator.

The solution is to log off EGMACHINE, log back on as EGMACHINE\PowerUsr1,

then execute the command. Note that a privilege is needed to set the time

on a machine. In the previous example, the account, EGMACHINE\PowerUsr1,

was used to remind us that power users have the needed privilege.

MORE INFORMATION

When running Windows NT while logged on to a domain, doing a NET TIME

without the /DOMAIN parameter, as mentioned above, probably will not yield

the desired results. However, because you are logged on to a domain, you

can do

   net time /domain /set

and a domain controller from the domain you are logged on to will be used.

In other words, if you are logged on to a domain, the /DOMAIN parameter is

necessary, but the actual domain name can optionally be left to default to

the domain you're currently participating in. If your machine is joined to

the a domain, that domain will be the default domain for NET TIME /DOMAIN.

If you are trying to get the time from EGDOMAIN and have done a prior

   net use \\egdomain\ipc$ /user:username

where username can be either a legitimate user name or domain name\user

name pair, or anything that will use the guest access), then the net time

will use the existing connection to the IPC$ share, using the different

user name.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseSecurity


Getting the WinMain() lpCmdLine in Unicode

PSS ID Number: Q90912

Authored 26-Oct-1992	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

The prototype for WinMain() is as follows:

   int PASCAL WinMain(

          HANDLE hInstance,

          HANDLE hPrevInstance,

          LPSTR lpCmdLine,

          int nCmdShow );

The third parameter is an LPSTR, which specifies an ANSI string. WinMain()

cannot be defined to accept Unicode input because there is no way for the

system to know whether or not the application wants Unicode at the time

WinMain() is called; the system knows once the application has registered a

window class.

To get the arguments in Unicode, use GetCommandLine().

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: UsrNls


GetWindowRect() Returns TRUE with Desktop Window Handle

PSS ID Number: Q129598

Authored 30-Apr-1995	Last modified 01-May-1995

The information in this article applies to:

 - Microsoft Win32s, version 1.2

Under Windows NT and Windows 95, GetWindowRect() returns FALSE (to indicate

failure) if the desktop window handle is used. Under Win32s,

GetWindowRect() returns TRUE if the desktop window handle is used, however,

the RECT structure is not correctly filled in.

On Win32s, GetWindowRect() returns TRUE unconditionally because the 16-bit

Windows GetWindowRect() has no return value. Therefore, before calling

GetWindowRect() on Win32s, you should first check that the window handle is

not the desktop window handle.

Additional reference words: 1.20 GetDesktopWindow HWND_DESKTOP

KBCategory: kbprg

KBSubcategory: W32s


Global Classes in Win32

PSS ID Number: Q80382

Authored 28-Jan-1992	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

Under 16-bit Windows, when an application wants to check whether or not a

window class has been previously registered in the system, it typically

checks hPrevInstance. Under 32-bit Windows and Windows NT,

hPreviousInstance is always FALSE, because a class definition is not

available outside the process context of the process that registers it.

Thus, code that checks hPreviousInstance will always register the window

class.

MORE INFORMATION

Under 32-bit Windows and Windows NT, a style of CS_GLOBALCLASS indicates

that the class is available to every DLL in the process, not every

application and DLL in the system, as it does in Windows 3.1.

To have a class registered for every process in the system, it is necessary

to:

1. Register the class in a DLL.

2. Use a style of CS_GLOBALCLASS.

3. List the DLL in the following registry key.

   HKEY_LOCAL_MACHINE\S OFTWARE\

      Microsoft\

      Windows NT\

      CurrentVersion\

      Windows\

      AppInit_DLLs

   This will force the DLL to be loaded into every process in the system,

   thereby registering the class in each and every process.

For more information, please see "Window Classes in Win32," which is

available on the MSDN CD, starting April 1994.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: UsrCls


Global Quota for Registry Data

PSS ID Number: Q94993

Authored 28-Jan-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

SUMMARY

Window NT includes a "global quota" on the amount of memory that may be

allocated in the registry. This prevents a broken or malicious application

from effectively crashing the system by filling paged pool with registry

data; however, it does NOT prevent such an application from using up all

available registry space. Similar to the file systems, the registry does

not support per process/user quotas.

MORE INFORMATION

The total amount of memory that may be consumed by registry data (the

hives) is limited by the registry size limit (RSL). The RSL works as a

"global quota" for registry space, both in the paged pool and on disk.

By default, the RSL is 25 percent of the size of the paged pool (the paged

pool is the memory that may be swapped to disk; all user memory is part of

the paged pool). Changing the size of the paged pool also affects the size

of the RSL. See

   HKEY_LOCAL_MACHINE\System\

      CurrentControlSet\

      Control\

      SessionManager\

      MemoryManagement\

      PagedPoolSize

in the registry.

The RSL may also be manually set. The value in bytes may be specified

by setting the value entry for the key

   HKEY_LOCAL_MACHINE\System\

      CurrentControlSet\

      Control\

      RegistrySizeLimit.

This key must have a type of REG_DWORD and a data length of 4 bytes, or it

will be ignored.

If the value entry RegistrySizeLimit is less than 4 megabytes (MB), it will

be forced up to 4 MB. If it is greater than about 80 percent of the size of

the paged pool, it will be set down to 80 percent of the size of the paged

pool. (It is assumed that paged pool is always larger than 5 MB.)

The system must be rebooted for changes in the RSL to take effect.

To ensure that the user can always at least boot and edit the registry if

they somehow set the RSL wrong, the quota is not enforced until after the

first successful loading of a hive (that is, loading of a user profile.)

Note that the RSL sets a maximum, not an allocation (unlike some other such

limits in the system). Setting a large RSL does NOT cause the system to set

aside that much space unless it is actually needed by the registry. It also

does NOT guarantee that that much space will be available for use in the

registry.

Setting the value entry RegistrySizeLimit to 0xffffffff effectively sets

RSL to be as large as paged pool allows (80 percent of paged pool size).

In the initial release of Windows NT, the paged pool defaults to 32 MB, so

the default RSL is 8 MB (enough to support approximately 5000 users). The

paged pool can be set to a maximum of 128 MB, so the RSL can be no larger

than about 102 MB, supporting about 80,000 users (surpassing the realistic

limitations of other parts of the system).

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: BseMisc


Graphics as Jumps in Windows Help Files

PSS ID Number: Q67884

Authored 28-Dec-1990	Last modified 24-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

One of the things that reduces the training required to learn Windows is

the presence of consistent graphical help. You can create Help files that

use graphic images as context jumps or as glossary pop-ups.

MORE INFORMATION

To use a graphic as a context jump, perform the following steps:

1. Create the graphic in your favorite graphics editor. The typical

   Windows developer has at least two tools available for this

   purpose:

   a. Windows Paintbrush, included with the retail release of Windows

   b. SDKPaint, provided with the Windows SDK

   A Note to Paintbrush Users

   --------------------------

   When an image is saved from Paintbrush, by default, the entire

   "canvas" is saved to disk, not just the image created. To work

   around this potential problem, after the image is complete, use the

   square outline tool (at the upper right of the tool bar) to select

   the image. If the image is not square, select the smallest bounding

   rectangle, leaving a border if desired. From the Edit menu, choose

   Copy To, and fill in the name of the file in which to save the

   selection.

2. Edit the file that contains the Help text. This is often called the

   .RTF file.

3. Place the cursor where the graphic should occur and turn on the

   strikethrough character format feature of the text editor. Word

   for Windows users should use double underline character formatting

   instead.

4. Insert one of the following text strings:

      {bmc <filename>}

      -or-

      {bml <filename>}

      -or-

      {bmr <filename>}

   This text should be struck through (or double underlined).

5. Turn off the strikethrough (or double underline) character format

   and turn on hidden text character formatting.

6. Type the context string for the jump destination.

7. Turn off hidden text character formatting.

8. Save the .RTF file.

9. Edit the .HPJ file. There must be a [BITMAPS] section in this file,

   and that section must include the name of the bitmap used above.

When the Help file is built, clicking the graphic with the mouse will

cause Help to change to the specified context.

If the graphic has a name or other short text description, we

recommend that the text also be coded as a context jump. This way, the

user can click on either the graphic or the text to perform the jump.

The text also provides a means for users without a mouse to perform

the jump.

More information on Windows Help files is in Chapters 15 through 19 of

the "Microsoft Windows Software Development Kit Tools" manual. Chapter

17 discusses context jumps, glossary pop-ups, and inserting graphics

into the Help file by reference.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbtool

KBSubcategory: TlsHlp


Graying the Text of a Button or Static Text Control

PSS ID Number: Q39480

Authored 17-Dec-1988	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

 - Microsoft Win32 SDK, versions 3.1, 3.5, and 3.51

A control is a child window that is responsible for processing

keyboard, mouse, focus, and activation messages, among others. A

control paints itself and processes text strings. The color of the

text in a button or static text control is automatically changed to

gray when the control is disabled with the EnableWindow function.

However, If an application subclasses a control to process WM_PAINT

messages for the control, the application can use the GrayString

function to change the text color.

Additional reference words: 3.00 3.10 3.50 4.00 95  grey

KBCategory: kbprg

KBSubcategory: UsrCtl


Handling COMMDLG File Open Network Button Under Win32s

PSS ID Number: Q117825

Authored 10-Jul-1994	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32s versions 1.1, 1.15, and 1.2

When you run a Win32-based application under Win32s on top of Windows 3.1

without a network, the File Open common dialog box still has a Network

button.

Under Windows NT, the File Open common dialog box that appears when you

call GetOpenFileName() has a Network button only when a network is present.

The API (application programming interface) will either use the Network

button in the dialog box template if it exists or dynamically add the

button if it is not in the template and there is a network present. If

there is no network present but the template contains a Network button, the

button will be hidden.

The dialog box template that is included with the Windows Software

Development Kit (SDK) does not have a Network button because Windows does

not include a network. When the 16-bit Windows-based application is

executed under Windows for Workgroups or under Windows NT, the Network

button is dynamically added, because these operating systems have built-in

networking.

The template that is included with the Win32 SDK has a Network button. If

the Win32-based application is run under a non-networked Windows 3.1, the

Network button is shown; however it is nonfunctional because there is no

network. This happens because the COMMDLG.DLL that provides Windows 3.1

with the common dialog boxes does not recognize networks. Therefore,

GetOpenFileName() does not remove the Network button from the template if

there is no network.

One solution is to leave the button in the template, determine when you are

running under Win32s, and include OFN_NONETWORKBUTTON in the OPENFILENAME

structure when Win32s is present but there is no network present. Define a

hook function that during WM_INITDIALOG checks the Flags field of the

OPENFILENAME struct that lParam is pointing to. If OFN_NONETWORKBUTTON is

used, call ShowWindow(GetDlgItem(hWnd, psh14), SW_HIDE).

Alternatively, if your application will most likely run on networked

Windows 3.1 machines, you can install the COMMDLG.DLL that ships with

Windows for Workgroups 3.11 on all machines, because it is a

redistributable dynamic-link library (DLL). This DLL checks to see if a

network is present and removes the Network button for you if it is not.

Additional reference words: 1.10 1.15 1.20

KBCategory: kbprg

KBSubcategory: W32s


Handling WM_CANCELMODE in a Custom Control

PSS ID Number: Q74548

Authored 23-Jul-1991	Last modified 23-Jun-1995

-

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK), versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

-

SUMMARY

In the Microsoft Windows graphical environment, the WM_CANCELMODE

message informs a window that it should cancel any internal state.

This message is sent to the window with the focus when a dialog box or

a message box is displayed, giving the window the opportunity to

cancel states such as mouse capture.

When a control has the focus, it receives a WM_CANCELMODE message when

the EnableWindow function disables the control or when a dialog box or

a message box is displayed. When a control receives this message, it

should cancel modes, such as mouse capture, and delete any timers it

has created. A control must cancel these modes because an application

may use a notification from the control to display a dialog box or a

message box.

The DefWindowProc function processes WM_CANCELMODE by calling the

ReleaseCapture function, which cancels the mouse capture for whatever

window has the capture. The DefWindowProc function does not cancel any

other modes.

MORE INFORMATION

For example, consider a miniature scroll bar custom control that, when

it receives a mouse click, sets the mouse capture, creates a timer to

provide for repeated scrolling, and sends a WM_VSCROLL message to its

parent application. The timer is used to send WM_VSCROLL messages

periodically to the parent when the mouse button is held down and the

mouse is over the control.

If the application displays a dialog box in response to the WM_VSCROLL

message, the control receives a WM_CANCELMODE message, at which time

it should kill its timer and release the mouse capture. If the

WM_CANCELMODE message is simply passed to the DefWindowProc function,

only the mouse capture is released; the timer remains active. When the

dialog box is closed, the control immediately sends the parent another

WM_VSCROLL message, causing it to display the dialog box again.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: UsrCtl


Height and Width Limitations with Windows SDK Font Editor

PSS ID Number: Q69081

Authored 06-Feb-1991	Last modified 24-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

The Microsoft Windows Font Editor (FONTEDIT.EXE) does not allow creation of

fonts in which the height or width of the font is greater than 64 pixels.

This corresponds to a font-file size of approximately 115K.

This is a limitation of the Font Editor, and not of the fonts themselves.

There is no limit to the size of the font file in the font format. Font

files created in the Windows version 2.0 font format cannot be larger than

64K.

The Font Editor displays a message box containing one of these two errors

if the entered Font Size Character Pixel Width or Character Pixel Height is

larger than 64:

   Fixed/maximum width must be a number from 1-64

   Font height must be a number from 1-64 pixels

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbtool

KBSubcategory: TlsFnt


Help Fonts Must Use ANSI Character Set

PSS ID Number: Q92422

Authored 05-Nov-1992	Last modified 24-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

When creating a help file, it is often necessary to access special

characters available in certain fonts. However, when the Windows

Help engine tries to display the special character, it may not appear

correctly.

MORE INFORMATION

Fonts used to create RTF source files for the Windows Help engine must

use the ANSI character set. Fonts that use character sets other than

ANSI may not display properly in the Help engine. The only exception

to this is the Symbol font, which is also supported in Windows Help

version 3.1.

To determine whether a particular font uses the ANSI character set,

run the FONTEST sample included with the Windows Software Development

Kit (SDK). From the Font menu, choose the Choose Font option. In the

Font dialog box, select the font for which you would like to determine

the character set. If the font is an ANSI font, then the tmCharSet

value displayed in the main window will be zero.

Additional reference words: 3.10 3.50 4.00 95 HC HCP

KBCategory: kbtool

KBSubcategory: TlsHlp


Help Universal Localization Kit (HULK) Is Available

PSS ID Number: Q129452

Authored 26-Apr-1995	Last modified 29-Apr-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

 - Microsoft Win32 Software Development Kit (SDK) version 3.5

 - Microsoft Win32s version 1.2

Microsoft HULK (Help Universal Localization Kit) is a collection of

editing, testing, and building tools for Microsoft Windows-based Help,

integrated into an easy-to-use environment. It is designed to make

localizing Windows Help projects as smooth as possible, especially if this

work is being done by external vendors.

HULK is available on MSDN (Microsoft Developer Network) Development

Library, under "Unsupported Tools and Utilities." It is provided "as is"

and is not supported by Microsoft.

Additional reference words: kbinf hc.exe hcp.exe

KBCategory: kbtool

KBSubcategory: wintldev


Hooking Console Applications and the Desktop

PSS ID Number: Q108232

Authored 07-Dec-1993	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

Under Windows NT, system hooks are limited in two situations: hooking

console windows and hooking the desktop.

Because of the current design of the console and the fact that its user

interface runs in the Win32 server, Windows NT does not support hook calls

in the context of console applications. Thus, if application A sets a

system-wide input hook and text is typed in a console window, application

A's input hook will not be called. The same is true for every type of

Windows hook except for journal record and journal playback hooks.

Hooking a console application will be enabled in Windows NT 3.51.

MORE INFORMATION

Windows NT supports journaling by forcing the console input thread to

communicate with the application that set the hook. In the case of a

console, the call to the hook functions are run in the context of the

application that installed the hook. This forces Windows NT to

synchronously talk to this process in order for it to work; if this process

is busy or blocked (as it is when it is sitting at a breakpoint), the

console thread is hung.

If console applications were typical Win32-based applications, then this

would not be a problem. A design change such as this would require that

each console take an extra thread just to process input. This was not

acceptable to the designers, and therefore console applications are not

implemented in the same way that other Win32-based applications are

implemented.

Similarly, if Windows NT allowed other hooks to freely hook any process,

then these processes could enter a hanging state as well. The reason that

journaling is allowed to hook consoles is that journaling already requires

synchronization between all processes in the system, and a mechanism to

disengage the journaling process (via the CTRL+ESC, ALT+ESC and

CTRL+ALT+DEL keystroke combinations) is provided to prevent hanging the

system message queue.

For similar reasons, 16-bit Windows-based applications cannot hook

Win32-based applications under Windows NT.

The issues above apply equally well to hooking the desktop. If an

application were allowed to hook the desktop, it could potentially hang it.

This is completely unacceptable and violates one of the design principles

of Windows NT: no application should be allowed to bring down the system or

hang the user interface.

Additional reference words: 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrHks


Host Name May Map to Multiple IP Addresses

PSS ID Number: Q110703

Authored 27-Jan-1994	Last modified 26-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

The sockets function gethostname() returns a string that identifies the

name of the local host. Each host has only one "official" name,

regardless of how many IP addresses it has, but there may be several

"aliases" for the host.

In TCP/IP, there is not a one-to-one mapping between host name and IP

address. The mapping is one-to-many: one host name can have multiple IP

addresses.

The sockets function getsockname() returns the sockaddr that the socket

is bound to.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: NtwkWinsock


Hot Versus Warm Links in a DDEML Server Application

PSS ID Number: Q108927

Authored 20-Dec-1993	Last modified 18-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

In message-based dynamic-data exchange (DDE), a server application can

readily distinguish between a hot and a warm link as soon as it receives a

request for an advise loop, via the WM_DDE_ADVISE message. This allows the

server to send the appropriate value in the data handle (for example, a

NULL or a valid data handle) to the client application whenever data

changes. In DDEML, there is no way to distinguish between these two links

when the server receives a request for an advise transaction.

MORE INFORMATION

Two applications engaged in a DDE conversation may establish one or more

links (or advise loops) so that the server application sends periodic

updates about the linked item/s to the client, typically when that

particular data item's value changes.

In a hot advise loop, the server immediately sends a data handle to the

changed data item value. In a warm advise loop, however, the server just

notifies the client that the data item value has changed, but does not send

the data handle until the client explicitly requests it.

In message-based DDE, a client requests the server for an update on an item

by posting the WM_DDE_ADVISE message to the server application. Upon

receipt of this message, the server application is able to distinguish

between a request for a hot advise loop and a warm advise loop via the

fDeferUpd bit of the DDEADVISE structure it received in the low-order word

of lParam.

A nonzero fDeferUpd value tells the server that it is a WARM advise loop.

This instructs the server to send a WM_DDE_DATA message with a NULL data

handle whenever the data item changes, and wait for the client to post a

WM_DDE_REQUEST before it sends the handle to the updated data.

A zero fDeferUpd value, however, indicates a HOT advise loop, which then

tells the server to send a WM_DDE_DATA message with the valid data handle

to the changed data item.

In DDEML, a client requests the server for a hot advise loop via the

XTYP_ADVSTART transaction type in a call to the DdeClientTransaction()

function. To request a warm advise loop, the client specifies an

XTYP_ADVSTART transaction or'ed with the XTYPF_NODATA flag. In both cases,

the DDEML passes the same XTYP_ADVSTART to the server callback function,

with no particular flags set, leaving the server with no means to

distinguish between a hot or warm advise request.

Note that DDEML internally remembers the type of advise loop established.

Once an advise loop is established, the server application calls the

DdePostAdvise() function whenever the value of the data item changes. In a

hot advise loop, this causes the DDEML to send the server an XTYP_ADVREQ

transaction to its callback function, where the server then returns a data

handle to the changed data item. The DDEML then sends the XTYP_ADVDATA

transaction to the client's callback function with the data handle.

In a warm advise loop, an XTYP_ADVREQ transaction is not sent to the

server's callback function when the data item changes on a call to

DdePostAdvise(). DDEML takes care of sending the XTYP_ADVDATA transaction

directly to the client's callback function, with the data handle set to

NULL. The server application does not send the handle to the changed data

item until the client issues an XTYP_REQUEST transaction to obtain this

data handle.

Because the type of advise loop (hot versus warm) is not known to the

server application, a good rule of thumb in writing server applications

that support advise loops is to return a data handle in response to both

the XTYP_ADVREQ and the XTYP_REQUEST transactions. This guarantees that a

data handle is returned for both hot and warm advise loops.

Additional reference words: 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrDde


How CREATOR_OWNER and CREATOR_GROUP Affect Security

PSS ID Number: Q126629

Authored 27-Feb-1995	Last modified 07-Mar-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), version 3.5

SUMMARY

This article discusses the CREATOR_OWNER and CREATOR_GROUP security

identifiers (SID) and how they affect security.

MORE INFORMATION

When logged on, each user is represented by a token object. This token

contains all the SIDs comprising your security context. Tokens identify

one of those SIDs as a default owner for any new objects the user creates,

such as files, processes, events, and so forth. Typically, this is the

user's account (<domain>\<username>). For an administrator however, the

default owner is set to be the local group "Administrators," rather than

the individual's user account.

Each token also identifies a primary group for the user. This group does

not necessarily have to be one the user is a member of (although it is by

default) and it does not determine the objects a user has access to (that

is, it isn't used in access validation decisions). However, by default it

is assigned as the primary group of any objects the user creates. For the

most part, the primary group is required simply for POSIX compatibility,

but the primary group does play a role in object creation.

When a new object is created, the security system has the task of

assigning protection to the new object. The system follows this process:

1. Assign the new object any protection explicitly passed in by the

   object creator.

2. Otherwise, assign the new object any inheritable protection from the

   container the object is created in.

3. Otherwise, assign the new object any protection explicitly passed in by

   the object creator, but marked as "default."

4. Otherwise, if the caller's token has a default DACL, that will be

   assigned to the new object.

5. Otherwise, no protection is assigned to the new object.

In step 2, if the parent container has inheritable access-control entries

(ACE), those are used to generate protection for the new object. In this

case, each ACE is evaluated to see if it should be copied to the new

object's protection. Usually, when an ACE is copied, the SID within that

ACE is copied as is. The two exceptions to this rule are when CREATOR_OWNER

and CREATOR_GROUP are encountered. In this case, the SID is replaced with

the caller's default owner SID or primary group SID.

By default, users logging on to Windows NT are given a primary group of

"Domain Users" (when logging on to a Windows NT Server) or the group called

"None" (when logging onto a Windows NT Workstation system). Therefore, when

you create an object in a container that has an inheritable ACE with the

CREATOR_GROUP SID, you will likely end up with an ACE granting Domain Users

some access. This may not be what you intended.

Additional reference words: 3.50

KBCategory: kbprg

KBSubcategory: BseSecurity


How Database WinSock APIs Are Implemented in Windows NT 3.5

PSS ID Number: Q130024

Authored 09-May-1995	Last modified 16-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

   versions 3.5 and 3.51

SUMMARY

This article describes the ways in which various WinSock database APIs are

implemented through the Windows NT versions 3.5 and 3.51 implementation of

the WinSock DLL. The article covers the following WinSock database APIs:

gethostbyname(), gethostbyaddr(), getprotobyname(), getprotobynumber(),

getservbyname(), and getservebynumber().

MORE INFORMATION

Following are the steps taken by each API. In a case where more than one

step may be taken to resolve the requested information, the process is not

carried to the next step if the information is resolved in the current

step.

gethostbyname():

1. Check the HOSTS file at %SystemRoot%\System32\DRIVERS\ETC.

2. Do a DNS query if the DNS server is configured for name resolution.

3. Query one or more WINS servers.

gethostbyaddr():

1. Check the HOSTENT cache.

2. Check the HOSTS file at %SystemRoot%\System32\DRIVERS\ETC.

3. Do a DNS query if the DNS server is configured for name resolution.

4. Do an additional NetBIOS remote adapter status to an IP address for its

   NetBIOS name table. This step is specific only to the Windows NT version

   3.51 implementation.

getprotobyname() and getprotobynumber():

1. Check the PROTOCOL file at %SystemRoot%\System32\DRIVERS\ETC.

getservbyname() and getservebynumber():

1. Check the SERVICES files at %SystemRoot%\System32\DRIVERS\ETC.

Additional reference words: 3.50 3.51

KBCategory: kbprg kbnetwork

KBSubcategory: NtwkWinsock


How HEAPSIZE/STACKSIZE Commit > Reserve Affects Execution

PSS ID Number: Q89296

Authored 16-Sep-1992	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

The syntax for the module-definition statements HEAPSIZE and STACKSIZE is

as follows

   HEAPSIZE  [reserve] [,commit]

   STACKSIZE [reserve] [,commit]

The remarks for HEAPSIZE and STACKSIZE on page 62 of the "Tools User's

Guide" manual that comes with the Win32 SDK state the following:

   When commit is less than reserve, memory demands are reduced but

   execution time is slower.

By default, commit is less than reserve.

The reason that execution time is slower (and it is actually only

fractionally slower), is that the system sets up guard pages and could have

to process guard page faults.

MORE INFORMATION

If the committed memory is less than the reserved memory, the system sets

up guard page(s) around the heap or stack. When the heap or stack grows big

enough, the guard pages start accessing outside the committed area. This

causes a guard page fault, which tells the system to map in another page.

The application continues to run as if you had originally had the new page

committed.

If the committed memory is greater than the reserve, no guard pages are

created and the program faults if it goes outside the committed memory

area.

Experimenting with the commit versus reserve numbers may result in a

combination that would produce noticeable results, but for most

applications, this difference is probably not noticeable. The potential

benefits do not warrant significant experimentation.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: BseMisc


How Keyboard Data Gets Translated

PSS ID Number: Q104316

Authored 13-Sep-1993	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

Keyboard input is acquired by the keyboard driver, which in turn produces a

scan code. This scan code is passed on to the locale-specific Win32

subsystem keyboard driver. This locale-specific driver then converts the

scan code to a virtual key and a Unicode character. The Win32 subsystem

then passes on this information to the application.

All messages in the Win32 application programming interface (API) that

present textual information to a window procedure depend upon how the

window registered its class. For example, if RegisterClassW() was called,

then Unicode is presented; if RegisterClassA() was called, then ANSI is

presented. The conversion of the text is handled by the Window Manager.

This allows an ANSI application to send textual information to a Unicode

application.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: UsrInp


How POSIX Applications are Recognized

PSS ID Number: Q101770

Authored 21-Jul-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

The presence of the IMAGE_SUBSYSTEM_POSIX_CUI flag in the Subsystem

field of the image's optional header means that the application is a

32-bit POSIX application.

Additional reference words: 3.10

KBCategory: kbprg

KBSubCategory: SubSys


How to Add an Access-Allowed ACE to a File

PSS ID Number: Q102102

Authored 28-Jul-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

SUMMARY

This article explains the process of adding an access-allowed (or

access-denied) access control entry (ACE) to a file.

Adding an access-allowed ACE to a file's access control list (ACL) provides

a means of granting or denying (using an access-denied ACE) access to the

file to a particular user or group. In most cases, the file's ACL will not

have enough free space to add an additional ACE, and therefore it is

usually necessary to create a new ACL and copy the file's existing ACEs

over to it. Once the ACEs are copied over and the access-allowed ACE is

also added, the new ACL can be applied to the file's security descriptor

(SD). This process is explained in detail in the section below. Sample code

is provided at the end of this article.

MORE INFORMATION

At the end of this article is sample code that defines a function named

AddAccessRights(), which adds an access-allowed ACE to the specified file

allowing the specified access. Steps 1-17 in the comments of the sample

code are discussed in detail below:

 1. GetUserName() is called to retrieve the name of the currently

    logged in user. The user name is stored in plszUserName[] array.

 2. LookupAccountName() is called to obtain the SID of the user

    returned by GetUserName() in step 1. The resulting SID is stored

    in the UserSID variable and will be used later in the

    AddAccessAllowedACE() application programming interface (API)

    call. The LookupAccountName() API is also providing the user's

    domain in the plszDomain[] array. Please note that

    LookupAccountName() returns the SID of the first user or group

    that matches the name in plszUserName.

 3. GetFileSecurity() is used here to obtain a copy of the file's

    security descriptor (SD). The file's SD is placed into the ucSDbuf

    variable, which is declared a size of

    65536+SECURITY_DESCRIPTOR_MIN_LENGTH for simplicity. This value

    represents the maximum size of an SD, which ensures the SD will be

    of sufficient size.

 4. Here we initialize the new security descriptor (NewSD variable) by

    calling the InitializeSecurityDescriptor() API. Because the

    SetFileSecurity() API requires that the security item being set is

    contained in a SD, we create and initialize NewSD.

 5. Here GetSecurityDescriptorDacl() retrieves a pointer to the

    discretionary access control list (DACL) in the SD. The pointer is

    stored in the pACL variable.

 6. GetAclInformation() is called here to obtain size information on

    the file's DACL in the form of a ACL_SIZE_INFORMATION structure.

    This information is used when computing the size of the new DACL

    and when copying ACEs.

 7. This statement computes the exact number of bytes to allocate for

    the new DACL. The AclBytesInUse member represents the number of

    bytes being used in the file's DACL. We add this number to the

    size of an ACCESS_ALLOWED_ACE and the size of the user's SID.

    Subtracting the size of a DWORD is an adjustment required to

    obtain the exact number of bytes necessary.

 8. Here we allocate memory for the new ACL that will ultimately

    contain the file's existing ACEs plus the access-allowed ACE.

 9. In addition to allocating the memory, it is important to

    initialize the ACL structure as we do here.

10. Here we check the bDaclPresent flag returned by

    GetSecurityDescriptorDacl() to see if a DACL was present in the

    file's SD. If a DACL was not present, then we skip the code that

    copies the file's ACEs to the new DACL.

11. After verifying that there is at least one ACE in the file's DACL

    (by checking the AceCount member), we begin the loop to copy the

    individual ACEs to the new DACL.

12. Here we get a pointer to an ACE in the file's DACL by using the

    GetAce() API.

13. Now we add the ACE to the new DACL. It is important to note that

    we pass MAXDWORD for the dwStartingAceIndex parameter of AddAce()

    to ensure the ACE is added to the end of the DACL. The statement

    ((PACE_HEADER)pTempAce)->AceSize provides the size of the ACE.

14. Now that we have copied all the file's original ACEs over to our

    new DACL, we add the access-allowed ACE. The dwAccessMask variable

    will contain the access mask being granted. GENERIC_READ is an

    example of an access mask.

15. Because the SetFileSecurity() API can set a variety of security

    information, it takes a pointer to a security descriptor. For this

    reason, it is necessary to attach our new DACL to a temporary SD.

    This is done by using the SetSecurityDescriptorDacl() API.

16. Now that we have a SD containing the new DACL for the file, we set

    the DACL to the file's SD by calling SetFileSecurity(). The

    DACL_SECURITY_INFORMATION parameter indicates that we want the

    DACL in the provided SD applied to the file's SD. Please note that

    only the file's DACL is set, the other security information in the

    file's SD remains unchanged.

17. Here we free the memory that was allocated for the new DACL.

The below sample demonstrates the basic steps required to add an access-

allowed ACE to a file's DACL. Please note that this same process can be

used to add an access-denied ACE to a file's DACL. Because the access-

denied ACE should appear before access-allowed ACEs, it is suggested that

the call to AddAccessDeniedAce() precede the code that copies the existing

ACEs to the new DACL.

Sample Code

-----------

#define SD_SIZE (65536 + SECURITY_DESCRIPTOR_MIN_LENGTH)

BOOL AddAccessRights(CHAR *pFileName, DWORD dwAcessMask)

{

   // SID variables

   UCHAR          psnuType[2048];

   UCHAR          lpszDomain[2048];

   DWORD          dwDomainLength = 250;

   UCHAR          UserSID[1024];

   DWORD          dwSIDBufSize=1024;

   // User name variables

   UCHAR          lpszUserName[250];

   DWORD          dwUserNameLength = 250;

   // File SD variables

   UCHAR          ucSDbuf[SD_SIZE];

   PSECURITY_DESCRIPTOR pFileSD=(PSECURITY_DESCRIPTOR)ucSDbuf;

   DWORD          dwSDLengthNeeded;

   // ACL variables

   PACL           pACL;

   BOOL           bDaclPresent;

   BOOL           bDaclDefaulted;

   ACL_SIZE_INFORMATION AclInfo;

   // New ACL variables

   PACL           pNewACL;

   DWORD          dwNewACLSize;

   // New SD variables

   UCHAR                NewSD[SECURITY_DESCRIPTOR_MIN_LENGTH];

   PSECURITY_DESCRIPTOR psdNewSD=(PSECURITY_DESCRIPTOR)NewSD;

   // Temporary ACE

   PVOID          pTempAce;

   UINT           CurrentAceIndex;

   // STEP 1: Get the logged on user name

   if(!GetUserName(lpszUserName,&dwUserNameLength))

   {

      printf("Error %d:GetUserName\n",GetLastError());

      return(FALSE);

   }

   // STEP 2: Get SID for current user

   if (!LookupAccountName((LPSTR) NULL,

       lpszUserName,

       UserSID,

       &dwSIDBufSize,

       lpszDomain,

       &dwDomainLength,

       (PSID_NAME_USE)psnuType))

   {

      printf("Error %d:LookupAccountName\n",GetLastError());

      return(FALSE);

   }

   // STEP 3: Get security descriptor (SD) for file

   if(!GetFileSecurity(pFileName,

                 (SECURITY_INFORMATION)(DACL_SECURITY_INFORMATION),

                 pFileSD,

                 SD_SIZE,

                 (LPDWORD)&dwSDLengthNeeded))

   {

      printf("Error %d:GetFileSecurity\n",GetLastError());

      return(FALSE);

   }

   // STEP 4: Initialize new SD

   if(!InitializeSecurityDescriptor(psdNewSD,SECURITY_DESCRIPTOR_REVISION))

   {

      printf("Error %d:InitializeSecurityDescriptor\n",GetLastError());

      return(FALSE);

   }

   // STEP 5: Get DACL from SD

   if (!GetSecurityDescriptorDacl(pFileSD,

                    &bDaclPresent,

                    &pACL,

                    &bDaclDefaulted))

   {

      printf("Error %d:GetSecurityDescriptorDacl\n",GetLastError());

      return(FALSE);

   }

   // STEP 6: Get file ACL size information

   if(!GetAclInformation(pACL,&AclInfo,sizeof(ACL_SIZE_INFORMATION),

      AclSizeInformation))

   {

      printf("Error %d:GetAclInformation\n",GetLastError());

      return(FALSE);

   }

   // STEP 7: Compute size needed for the new ACL

   dwNewACLSize = AclInfo.AclBytesInUse +

                  sizeof(ACCESS_ALLOWED_ACE) +

                  GetLengthSid(UserSID) - sizeof(DWORD);

   // STEP 8: Allocate memory for new ACL

   pNewACL = (PACL)LocalAlloc(LPTR, dwNewACLSize);

   // STEP 9: Initialize the new ACL

   if(!InitializeAcl(pNewACL, dwNewACLSize, ACL_REVISION2))

   {

      printf("Error %d:InitializeAcl\n",GetLastError());

      LocalFree((HLOCAL) pNewACL);

      return(FALSE);

   }

   // STEP 10: If DACL is present, copy it to a new DACL

   if(bDaclPresent)  // only copy if DACL was present

   {

      // STEP 11: Copy the file's ACEs to our new ACL

      if(AclInfo.AceCount)

      {

         for(CurrentAceIndex = 0; CurrentAceIndex < AclInfo.AceCount;

            CurrentAceIndex++)

         {

            // STEP 12: Get an ACE

            if(!GetAce(pACL,CurrentAceIndex,&pTempAce))

            {

              printf("Error %d: GetAce\n",GetLastError());

              LocalFree((HLOCAL) pNewACL);

              return(FALSE);

            }

             // STEP 13: Add the ACE to the new ACL

            if(!AddAce(pNewACL, ACL_REVISION, MAXDWORD, pTempAce,

               ((PACE_HEADER)pTempAce)->AceSize))

            {

               printf("Error %d:AddAce\n",GetLastError());

               LocalFree((HLOCAL) pNewACL);

               return(FALSE);

            }

          }

      }

   }

   // STEP 14: Add the access-allowed ACE to the new DACL

   if(!AddAccessAllowedAce(pNewACL,ACL_REVISION2,dwAcessMask, &UserSID))

   {

      printf("Error %d:AddAccessAllowedAce",GetLastError());

      LocalFree((HLOCAL) pNewACL);

      return(FALSE);

   }

   // STEP 15: Set our new DACL to the file SD

   if (!SetSecurityDescriptorDacl(psdNewSD,

                     TRUE,

                     pNewACL,

                     FALSE))

   {

      printf("Error %d:SetSecurityDescriptorDacl",GetLastError());

      LocalFree((HLOCAL) pNewACL);

      return(FALSE);

   }

   // STEP 16: Set the SD to the File

   if (!SetFileSecurity(pFileName, DACL_SECURITY_INFORMATION,psdNewSD))

   {

      printf("Error %d:SetFileSecurity\n",GetLastError());

      LocalFree((HLOCAL) pNewACL);

      return(FALSE);

   }

   // STEP 17: Free the memory allocated for the new ACL

   LocalFree((HLOCAL) pNewACL);

   return(TRUE);

}

NOTE: Security descriptors have two possible formats: self-relative and

absolute. GetFileSecurity() returns an SD in self-relative format, but

SetFileSecurity() expects and absolute SD. This is one reason that the code

must create a new SD and copy the information, instead of simply modifying

the SD from GetFileSecurity() and passing it to SetFileSecurity(). It is

possible to call MakeAbsoluteSD() to do the conversion, but there may not

be enough room in the current ACL anyway, as mentioned above.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseSecurity


How to Add an SNMP Extension Agent to the NT Registry

PSS ID Number: Q128729

Authored 06-Apr-1995	Last modified 11-Apr-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.5

SUMMARY

After developing a new extension agent DLL, you must configure the registry

so that the SNMP extension agent is loaded when the SNMP service is

started. This article shows you how.

MORE INFORMATION

You can use REGEDT32.EXE to configure the registry, or you can have your

SNMP extension agent installation program configure the registry using the

Win32 registry APIs.

To configure an SNMP extension agent in the registry, follow these steps:

1. Walk down:

      HKEY_LOCAL_MACHINE\

         SYSTEM\

         CurrentControlSet\

         Services\

         SNMP\

         Parameter\

         ExtensionAgents

   You'll notice at least one entry like this:

      1:REG_SZ:SOFTWARE\Microsoft\LANManagerMIB2Agent\CurrentVersion

   Add an entry for the new extension agent. For the SNMP Toaster sample

   in the SDK, the entry is:

      3:REG_SZ:SOFTWARE\CompanyName\toaster\CurrentVersion

   This entry provides a pointer to another registery entry (see step 2)

   that contains the physical path where the extension agent DLL can be

   found. Note that "CompanyName" and "toaster" strings can be any other

   meaningful strings that will be used in Step 2.

2. Go to:

      HKEY_LOCAL_MACHINE\SOFTWARE

   Create keys that correspond to the new entry in step 1:

      CompanyName\toaster\CurrentVersion

3. Assign the path of the extension agent DLL as the value to the

   CurrentVersion key in step 2. For the SNMP toaster sample agent

   DLL, the entry is:

      Pathname:REG_SZ:D:\mstools\samples\snmp\testdll\testdl.dll

4. Note that names and values in the NT registry are case sensitive.

5. Restart the SNMP service from the control panel. The new extension

   agent DLL will be loaded. Event Viewer in the administrative tools can

   be used to view errors encountered during the startup process of the

   SNMP service and extension agents.

REFERENCES

SNMP.TXT in the \BIN directory of the Win32 SDK.

Windows NT Resource Guide, Chapters 10-14.

Additional reference words: 3.50

KBCategory: kbprg

KBSubcategory: NtwkSnmp


How to Add Windows 95 Controls to Visual C++ 2.0 Dialog

PSS ID Number: Q125686

Authored 01-Feb-1995	Last modified 10-Apr-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

 - Microsoft Visual C++ version 2.0

SUMMARY

When using Visual C++ version 2.0 on Windows 95, the Windows 95 common

controls do not appear by default on the control palette in the Visual C++

Dialog Editor. Many of these controls may be added, however, by adding an

entry into the registry.

MORE INFORMATION

To add buttons in the Dialog Editor's control palette for TreeView,

ListView, HotKey, Trackbar, Progress, and UpDown controls:

1. Run REGEDIT from the start menu.

2. Select:

   HKEY_CURRENT_USER\Software\Microsoft\Visual C++ 2.0 Dialog Editor

3. Select the New, Binary Value option from the Edit Menu.

4. Rename the new entry "ChicagoControls" without the quotation marks.

5. Select Modify from the edit menu to change the value of ChicagoControls

   to 01 00 00 00. The editor will add the spaces between each pair of

   digits.

6. Exit REGEDIT.

7. Restart Visual C++ version 2.0.

Additional reference words: 2.00 4.00

KBCategory: kbprg

KBSubcategory: UsrCtl


How to Assign Privileges to Accounts for API Calls

PSS ID Number: Q131144

Authored 04-Jun-1995	Last modified 07-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) version 3.51

SUMMARY

Some new security API calls were added to Win32 in Windows NT version 3.51.

Two of these new calls, LogonUser() and CreateProcessAsUser(), require that

the calling process have certain privileges. If the calling process is a

service running in the Local System account, it will already have these

privileges. Otherwise, the required privileges can be added to an account

by using the "User Rights Policy" dialog box. Run the User Manager and

choose User Rights from the Policies menu to see the dialog box.

NOTE: You must select the "Show Advanced User Rights" check box to see

the privileges mentioned in this article.

MORE INFORMATION

The Win32 API reference documents the required privileges, but it gives

their internal string names instead of the display names. The "User Rights

Policy" dialog box displays the privileges using the display names.

The following table shows the display names associated with the internal

string names:

   Privilege          Display Name

   ------------------------------------------------------

   SeTcbPrivilege     Act as part of the operating system

   SeAssignPrimary    Replace a process level token

   SeIncreaseQuota    Increase quotas

Additional reference words:

KBCategory: kbprg

KBSubcategory: BseSecurity


How to Back Up the Windows NT Registry

PSS ID Number: Q128731

Authored 06-Apr-1995	Last modified 23-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.5

SUMMARY

This article shows by example how to back up portions of the Windows NT

registry to be restored later.

MORE INFORMATION

This is normally accomplished by enabling the SeBackupPrivilege and calling

RegSaveKey. The operation can fail with ERROR_ACCESS_DENIED if the caller

does not have access to portions of the key, such as the registry key

HKEY_LOCAL_MACHINE\SECURITY.

If you do not have access to the key, but have backup privilege, pass the

REG_OPTION_BACKUP_RESTORE flag to RegCreateKeyEx in the dwOptions

parameter. This has an effect similar to FILE_FLAG_BACKUP_SEMANTICS with

CreateFile, allowing you to open the key for backup. The resultant key

handle can be used in a subsequent call to RegSaveKey.

To back up the registry from the root, it is necessary to enumerate the

subkeys from the root, opening each subkey with RegCreateKeyEx and saving

the subkey with RegSaveKey.

Sample Code

-----------

The following sample source code saves the HKEY_LOCAL_MACHINE registry

key, with each subkey saved to a filename matching the subkey name.

The folloing function performs the save operation:

LONG SaveRegistrySubKey(

    HKEY hKey,              // handle of key to save

    LPTSTR szSubKey,        // pointer to subkey name to save

    LPTSTR szSaveFileName   // pointer to save path/filename

    )

If the function succeeds, the return value is ERROR_SUCCESS.

If the function fails, the return value is an error value.

/* Save HKEY_LOCAL_MACHINE registry key, each subkey saved to a file of

 * name subkey

 *

 * this allows us to get around security restrictions which prevent

 * the use of RegSaveKey() on the root key

 *

 * the use of REG_OPTION_BACKUP_RESTORE is not documented in the Win32

 * documentation at this time.  The documentation will be changed to

 * reflect this flag.  This flag is contained in the WINNT.H header file.

 *

 * the optional target machine name is specified in argv[1]

 *

 * v1.21

 * Scott Field (sfield) 01-Apr-1995

 */

#define RTN_OK 0

#define RTN_USAGE 1

#define RTN_ERROR 13

#include <windows.h>

#include <stdio.h>

#include <stdlib.h>

LONG SaveRegistrySubKey(HKEY hKey, LPTSTR szSubKey, LPTSTR szSaveFileName);

void PERR(LPTSTR szAPI, DWORD dwLastError);

int main(int argc, char *argv[])

{

   TOKEN_PRIVILEGES tp;

   HANDLE hToken;

   LUID luid;

   LONG rc;     // contains error value returned by Regxxx()

   HKEY hKey;   // handle to key we are interested in

   LPTSTR MachineName=NULL; // pointer to machine name

   DWORD dwSubKeyIndex=0;   // index into key

   char szSubKey[_MAX_FNAME]; // this should be dynamic.

                            // _MAX_FNAME is good because this

                            // is what we happen to save the

                            // subkey as

   DWORD dwSubKeyLength=_MAX_FNAME; // length of SubKey buffer

/*

    if (argc != 2) // usage

    {

        fprintf(stderr,"Usage: %s [<MachineName>]\n", argv[0]);

        return RTN_USAGE;

    }

 */

    // set MachineName == argv[1], if appropriate

    if (argc == 2) MachineName=argv[1];

    //

    // enable backup privilege

    //

    if(!OpenProcessToken(GetCurrentProcess(),

                        TOKEN_ADJUST_PRIVILEGES,

                        &hToken ))

    {

        PERR("OpenProcessToken", GetLastError() );

        return RTN_ERROR;

    }

    if(!LookupPrivilegeValue(MachineName, SE_BACKUP_NAME, &luid))

    {

        PERR("LookupPrivilegeValue", GetLastError() );

        return RTN_ERROR;

    }

    tp.PrivilegeCount           = 1;

    tp.Privileges[0].Luid       = luid;

    tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

    AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES),

                                NULL, NULL );

    if (GetLastError() != ERROR_SUCCESS)

    {

        PERR("AdjustTokenPrivileges", GetLastError() );

        return RTN_ERROR;

    }

    // only connect if a machine name specified

    if (MachineName != NULL)

    {

        if((rc=RegConnectRegistry(MachineName,

                                  HKEY_LOCAL_MACHINE,

                                  &hKey)) != ERROR_SUCCESS)

        {

            PERR("RegConnectRegistry", rc);

            return RTN_ERROR;

        }

    }

    else hKey=HKEY_LOCAL_MACHINE;

    while((rc=RegEnumKeyEx(

                        hKey,

                        dwSubKeyIndex,

                        szSubKey,

                        &dwSubKeyLength,

                        NULL,

                        NULL,

                        NULL,

                        NULL)

                        ) != ERROR_NO_MORE_ITEMS) { // are we done?

    if(rc == ERROR_SUCCESS)

   {

        LONG lRetVal; // return value from SaveRegistrySubKey

#ifdef DEBUG

        fprintf(stdout,"Saving %s\n", szSubKey);

#endif

        // save registry subkey szSubKey to filename szSubKey

        if( (lRetVal=SaveRegistrySubKey(hKey, szSubKey, szSubKey)

            ) != ERROR_SUCCESS)

        {

            PERR("SaveRegistrySubKey", lRetVal);

        }

        // increment index into the key

       dwSubKeyIndex++;

       // reset buffer size

        dwSubKeyLength=_MAX_FNAME;

        // Continue the festivities

        continue;

    }

    else

   {

       //

       // note: we need to watch for ERROR_MORE_DATA

       // this indicates we need a bigger szSubKey buffer

       //

        PERR("RegEnumKeyEx", rc);

        return RTN_ERROR;

   }

    } // RegEnumKeyEx

    // close registry key we have been working with

    RegCloseKey(hKey);

    // Revoke all privileges this process holds (including backup)

    AdjustTokenPrivileges( hToken, TRUE, NULL, 0, NULL, NULL);

    // close handle to process token

    CloseHandle(hToken);

    return RTN_OK;

}

LONG SaveRegistrySubKey(

    HKEY hKey,              // handle of key to save

    LPTSTR szSubKey,        // pointer to subkey name to save

    LPTSTR szSaveFileName   // pointer to save path/filename

    )

{

    HKEY hKeyToSave;    // Handle of subkey to save

    LONG rc;            // result code from RegXxx

    DWORD dwDisposition;

    if((rc=RegCreateKeyEx(hKey,

                          szSubKey, // Name of subkey to open

                          0,

                          NULL,

                          REG_OPTION_BACKUP_RESTORE, // in winnt.h

                          KEY_QUERY_VALUE, // minimal access

                          NULL,

                          &hKeyToSave,

                          &dwDisposition)

                          ) == ERROR_SUCCESS)

    {

        // Save registry subkey.  If the registry is remote, files will

        // be saved on the remote machine

        rc=RegSaveKey(hKeyToSave, szSaveFileName, NULL);

        // close registry key we just tried to save

        RegCloseKey(hKeyToSave);

    }

    // return the last registry result code

    return rc;

}

void PERR(

    LPTSTR szAPI,       // pointer to failed API name

    DWORD dwLastError   // last error value associated with API

    )

{

    LPTSTR MessageBuffer;

    DWORD dwBufferLength;

    //

    // TODO get this fprintf out of here!

    //

    fprintf(stderr,"%s error! (rc=%lu)\n", szAPI, dwLastError);

    if(dwBufferLength=FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |

                                    FORMAT_MESSAGE_FROM_SYSTEM,

                                    NULL,

                                    dwLastError,

                                    LANG_NEUTRAL,

                                    (LPTSTR) &MessageBuffer,

                                    0,

                                    NULL))

    {

        DWORD dwBytesWritten;

        //

        // Output message string on stderr

        //

        WriteFile(GetStdHandle(STD_ERROR_HANDLE),

                  MessageBuffer,

                  dwBufferLength,

                  &dwBytesWritten,

                  NULL);

        //

        // free the buffer allocated by the system

        //

        LocalFree(MessageBuffer);

    }

}

Additional reference words: 3.50

KBCategory: kbprg kbcode

KBSubcategory: BseMisc BseSecurity CodeSam


How to Broadcast Messages Using NetMessageBufferSend()

PSS ID Number: Q131458

Authored 12-Jun-1995	Last modified 15-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.5, 3.51

The NetMessageBufferSend() API can be used to broadcast a message. To

broadcast a copy a of a particular message to all workstations running

messanger service in a particular domain, the LPWSTR msgname parameter

needs to be specified as "DOMAINNAME*" - where DOMAINNAME is the name of

the domain to which a message is to be sent. In this case, you can use the

following piece of code to call this API:

   #define UNICODE

   #define MESGLEN 50

   WCHAR awcToName[] = TEXT("DomainName*");

   WCHAR awcFromName[] = Text("MyComputer");

   WCHAR awcMesgBuffer[MESGLEN] = Text("This ia Test Message");

   NET_API_STATUS nasStatus;

   nasStatus = NetMessageBufferSend(NULL,

                                    awcToName,

                                    awcFromName,

                                    awcMesgBuffer,

                                    MESGLEN);

Additional reference words: 3.50 3.51 LanMan

KBCategory: kbprg kbnetwork

KBSubcategory: NtwkMisc


How to Build a Japanese NT 3.50 Application on US NT 3.50

PSS ID Number: Q126744

Authored 01-Mar-1995	Last modified 24-Mar-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) version 3.5

 - Microsoft Visual C++, 32-bit Edition, version 2.0

 - Microsoft Windows NT version 3.5

Use the following steps to build a Japanese application on U.S. Windows NT

version 3.5 using the English 32-bit Edition of Visual C++ version 2.0:

1. Copy c_932.nls from your Japanese Windows NT version 3.5 CD or disks.

2. Add c_932.nls to your English Windows NT version 3.5 system directory

   (for example, WINNT35\SYSTEM32.

3. Using REGEDT32.EXE, search for "codepage" in the HKEY_LOCAL_MACHINE

   registry and add this value:

   932 : REG_SZ : c_932.nls

4. Add the "/C932" switch to the RC compiler option in the Project setting

   in the Microsoft Visual C++ IDE (Intergrated Development Environment).

Take similar steps if you want to use U.S. Windows NT version 3.5 as the

development environment and build an application that requires a codepage

that is not present on U.S. Windows NT version 3.5.

Additional reference words: 3.50 msvcj setlocale language

KBCategory: kbprg

KBSubcategory: WIntlDev


How to Calculate Dialog Base Units with Non-System-Based Font

PSS ID Number: Q125681

Authored 01-Feb-1995	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

SUMMARY

This article shows how to calculate the dialog base unit in Windows for

the dialog box using a font other than System Font. You can use this

calculation to build dialog templates in memory or calculate dialog

dimensions.

MORE INFORMATION

Each dialog box template contains measurements that specify the position,

width, and height of the dialog box and the controls it contains. These

measurements are device independent, so an application can use a single

template to create the same dialog box for all types of display devices.

This ensures that a dialog box will have the same proportions and

appearance on all screens despite differing resolutions and aspect ratios

between screens.

Further, dialog box measurements are given in dialog base units. One

horizontal base unit is equal to one-fourth of the average character width

for the system font. One vertical base unit is equal to one-eighth of the

average character height for the system font. An application can retrieve

the number of pixels per base unit for the current display by using the

GetDialogBaseUnits function. The low-order word of the return value, from

the GetDialogBaseUnits function, contains the horizontal base units

and the high-order word of the return value, from the GetDialogBaseUnits

function, contains the vertical base units.

Using this information, you can compute the dialog base units for a dialog

using font other than system font:

   horz pixels == (horz dialog units * average char width  of font) / 4

   vert pixels == (vert dialog units * average char height of font) / 8

As the font of a dialog changes, the actual size and position of a

control also changes.

 - Four pixels is half the average character width of the system font.

 - Eight pixels is half the average character height of the system font.

Here's another version of the same formulas:

horz pixels == 2 * horz dialog units * (average char width  of dialog font

                        / average char width of system font)

vert pixels == 2 * vert dialog units * (average char height of dialog font

                        / average char height of system font)

One dialog base unit is equivalent to the number of pixels per dialog unit

which gives:

1 horz dialog base unit == (2 * average char width  dialog font /

                                average char width  system font) pixels

1 vert dialog base unit == (2 * average char height dialog font /

                                average char height system font) pixels

Average character width and height of a font can be computed as follows:

hFontOld = SelectObject(hdc,hFont);

GetTextMetrics(hdc,&tm);

GetTextExtentPoint32(hdc,"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrst"

            "uvwxyz",52,&size);

avgWidth = (size.cx/26+1)/2;

avgHeight = (WORD)tm.tmHeight;

Additional reference words: 4.00 95

KBCategory: kbprg

KBSubcategory: UsrDlg


How to Calculate the Height of Edit Control to Resize It

PSS ID Number: Q124315

Authored 28-Dec-1994	Last modified 24-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK), version 3.1

 - Microsoft Win32 Software Development Kit (SDK), versions 3.5 and 3.51

SUMMARY

When a program changes the font of an edit control, it must calculate the

new height of the control so that text is displayed correctly. When an edit

control contains a border, the control automatically adds white space

around the text so the text won't interfere with the border.

This article shows by example how a program can modify the height of an

edit control so that text displayed in the control looks right after the

program changes the font.

MORE INFORMATION

The height of the control on creation is calculated as the height of the

control's font plus half of the smaller of the height of the control's font

or the height of the system font. You can use a function similar to the one

below to calculate the new height of an edit control when the font in the

control is changed.

Sample Code

-----------

void ResizeEdit(HWND hwndEdit, HFONT hNewFont)

{

   HFONT       hSysFont,

               hOldFont;

   HDC         hdc;

   TEXTMETRIC  tmNew,

               tmSys;

   RECT        rc;

   int         nTemp;

   //get the DC for the edit control

   hdc = GetDC(hwndEdit);

   //get the metrics for the system font

   hSysFont = GetStockObject(SYSTEM_FONT);

   hOldFont = SelectObject(hdc, hSysFont);

   GetTextMetrics(hdc, &tmSys);

   //get the metrics for the new font

   SelectObject(hdc, hNewFont);

   GetTextMetrics(hdc, &tmNew);

   //select the original font back into the DC and release the DC

   SelectObject(hdc, hOldFont);

   DeleteObject(hSysFont);

   ReleaseDC(hwndEdit, hdc);

   //calculate the new height for the edit control

   nTemp = tmNew.tmHeight + (min(tmNew.tmHeight, tmSys.tmHeight)/2);

   //re-size the edit control

   GetWindowRect(hwndEdit, &rc);

   MapWindowPoints(HWND_DESKTOP, GetParent(hwndEdit), (LPPOINT)&rc, 2);

   MoveWindow( hwndEdit,

               rc.left,

               rc.top,

               rc.right - rc.left,

               nTemp,

               TRUE);

}

Additional reference words: 3.10 3.50 win16sdk

KBCategory: kbprg kbcode

KBSubcategory: UsrCtl


How to Change Hard Error Popup Handling in Windows NT

PSS ID Number: Q128642

Authored 05-Apr-1995	Last modified 06-Apr-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.5

 - Microsoft Windows NT version 3.5

SUMMARY

In an unattended environment, you may want to automatically dispatch hard

error popups that require user intervention. This article gives you the

code you need to change the hard error popup mode.

MORE INFORMATION

Windows NT allows the user to change the handling of hard error popups that

result from application and system errors. Such errors include no disk in

the drive and general protection (GP) faults.

Normally, these events cause a hard error popup to be displayed, which

requires user intervention to dispatch. This behavior can be modified so

that such errors are logged to the Windows NT event log. When the error is

logged to the event log, no user intervention is necessary, and the system

provides a default handler for the hard error. The user can examine the

event log to determine the cause of the hard error.

Registry Entry

--------------

The following registry entry controls the hard error popup handling in

Windows NT:

HKEY_LOCAL_MACHINE\

 SYSTEM\

 CurrentControlSet\

 Control\

 Windows\

 ErrorMode

Valid Modes

-----------

The following are valid values for ErrorMode:

 - Mode 0

   This is the default operating mode that serializes the errors and waits

   for a response.

 - Mode 1

   If the error does not come from the system, this is the normal operating

   mode. If the error comes from the system, this logs the error to the

   event log and returns OK to the hard error. No intervention is required

   and the popup is not seen.

 - Mode 2

   This always logs the error to the event log and returns OK to the hard

   error. Popups are not seen.

In all modes, system-originated hard errors are logged to the system log.

To run an unattended server, use mode 2.

Sample Code to Change Hard Error Popup Mode

-------------------------------------------

The following function changes the hard error popup mode. If the function

succeeds, the return value is TRUE. If the function fails, the return value

is FALSE.

BOOL SetGlobalErrorMode(

    DWORD dwErrorMode   // specifies new ErrorMode value

    )

{

    HKEY hKey;

    LONG lRetCode;

    // make sure the value passed isn't out-of-bounds

    if (dwErrorMode > 2) return FALSE;

    if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,

                    "SYSTEM\\CurrentControlSet\\Control\\Windows",

                    0,

                    KEY_SET_VALUE,

                    &hKey) != ERROR_SUCCESS) return FALSE;

    lRetCode=RegSetValueEx(hKey,

                            "ErrorMode",

                            0,

                            REG_DWORD,

                            (CONST BYTE *) &dwErrorMode,

                            sizeof(DWORD) );

    RegCloseKey(hKey);

    if (lRetCode != ERROR_SUCCESS) return FALSE;

    return TRUE;

}

Sample Code to Obtain Hard Error Popup Mode

-------------------------------------------

The following function obtains the hard error popup mode. If the function

succeeds, the return value is TRUE. If the function fails, the return value

is FALSE. If the function succeeds, dwErrorMode contains the error popup

mode. Otherwise, dwErrorMode is undefined.

BOOL GetGlobalErrorMode(

    LPDWORD dwErrorMode // Pointer to a DWORD to place popup mode

    )

{

    HKEY hKey;

    LONG lRetCode;

    DWORD cbData=sizeof(DWORD);

    if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,

                    "SYSTEM\\CurrentControlSet\\Control\\Windows",

                    0,

                    KEY_QUERY_VALUE,

                    &hKey) != ERROR_SUCCESS) return FALSE;

    lRetCode=RegQueryValueEx(hKey,

                            "ErrorMode",

                            0,

                            NULL,

                            (LPBYTE) dwErrorMode,

                            &cbData );

    RegCloseKey(hKey);

    if (lRetCode != ERROR_SUCCESS) return FALSE;

    return TRUE;

}

Additional reference words: 3.50

KBCategory: kbprg kbcode

KBSubcategory: BseErrdebug BseMisc CodeSam


How to Change Small Icon for FileOpen and Other Common

PSS ID Number: Q130758

Authored 25-May-1995	Last modified 22-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) version 4.0

SUMMARY

Applications that need to display icons on the caption bars of File Open

and other Common Dialogs can do so by installing a hook function and

sending the WM_SETICON message from within the hook function to the common

dialog to change its small icon. Note that OFN_ENABLEHOOK flag (or relavant

flags for other common dialogs) has to be set for your hook function to be

called.

MORE INFORMATION

Under Windows 95, every popup or overlapped window can have two icons

associated with it, a large icon used when the window is minimized and a

small icon used for displaying the system menu icon.

Common Dialogs under Windows 95 do not display a small icon on their

caption bars by default. If you want the application to display its own

icon for the system menu, have the application install a hook funtion for

that common dialog and send the WM_SETICON message when the hook callback

function is called with the WM_INITDIALOG message.

The WM_SETICON message is sent to change or set the small and large icons

of a window. In this case, because you are setting the small icon, wParam

must be set to FALSE.

Code Sample

-----------

The following code shows how to do this for a File Open Common Dialog:

 // Fill in the OPENFILENAME structure to support

 // a hook and  a template (optional).

 OpenFileName.lStructSize       = sizeof(OPENFILENAME);

 OpenFileName.hwndOwner      = hWnd;

 OpenFileName.hInstance         = g_hInst;

   ...

   ...

   ...

   ...

 OpenFileName.lpfnHook          = ComDlg32HkProc;

 OpenFileName.lpTemplateName  = NULL;

 OpenFileName.Flags               = OFN_SHOWHELP |

                 OFN_EXPLORER | OFN_ENABLE_HOOK;

Note that the lpTemplateName parameter is set to NULL. To just install a

hook, one does not need a custom template. The hook function will get

called if it is sepcified in the structure.

Below is the Comdlg32HkgProc hook callback funtion that chages the small

icon. This code below is for the open or save as dialog boxes only.

BOOL CALLBACK ComDlg32HkProc(HWND hDlg,

                             UINT uMsg,

                             WPARAM wParam,

                             LPARAM lPar

{

   HWND hWndParent;

   HICON  hIcon;

   switch (uMsg)

   {

      case WM_INITDIALOG:

         hWndParent = GetParent(hDlg);

         hIcon = LoadIcon(g_hInst, "CustomIcon");

         SendMessage(hWndParent,

                     WM_SETICON,

                    (WPARAM)(BOOL)FALSE,

                    (LPARAM)(HICON)hIcon);

        return TRUE;

        break;

      default:

        break;

    }

NOTE: This code calls GetParent() to get the actual window handle of the

common dialog box. This is done for the FileOpen and SaveAs dialog boxes

only. These dialogs, when created with the OFN_EXPLORER look with a hook

and a template (optional), create a seperate dialog to hold all the

controls. This is the dialog handle that is passed in the hook function.

The parent of this dialog is the main common dialog window, whose caption

icon must be modified. The FileOpen and SaveAs dialog boxes with the old

style (no OFN_EXPLORER) need not call GetParent().

All other common dialogs, such as ChooseColor and ChooseFont, behave as the

the Windows version 3.1 common dialogs behaved, so the code listed in this

article does not need to call GetParent(). It can just send the WM_SETICON

message to the hDlg that is passed to the hook function.

Additional reference words: 4.00 user common dialog

KBCategory: kbprg kbcode

KBSubcategory: UsrCmnDlg


How to Change the International Settings Programmatically

PSS ID Number: Q126625

Authored 27-Feb-1995	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.5, 3.51,

   4.0

The International control panel icon allows you to choose international

settings for the time, date, keyboard, and so forth. You can change

these settings from your application code by calling SetLocaleInfo(). Be

sure to broadcast a WM_WININICHANGE message using PostMessage() so that all

applications are notified of the change.

The Win32 API allows you to display the time and date in the correct

international format. Use GetDateFormat() and GetTimeFormat() to get the

date and time in the format specified by the user.

Additional reference words: 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrLoc WintlDev


How to Compile Large Chinese or Korean Help Files

PSS ID Number: Q123331

Authored 29-Nov-1994	Last modified 10-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

 - Microsoft Win32 SDK version 3.5

The Extended Help Compiler is not available in Traditional/Simplified

Chinese Windows version 3.1 SDK extension or in the Korean Windows version

3.1 SDK extension. Therefore, large help files in Chinese or Korean cannot

be compiled under Windows version 3.1 using the extended help compiler.

However, large Chinese or Korean help files can be compiled under Windows

NT, by using Chinese or Korean Help Compiler (HC31.EXE). Make sure the

directory containing the appropriate HC31.EXE is in the path.

If the .HPJ file contains Compress=YES, change it to compress=MEDIUM or to

compress=FALSE.

The resulting .HLP files cannot be displayed correctly under Windows NT. If

you try it, you'll see random symbols in place of the Chinese or Korean

characters. To examine the result of the compilation, exit from Windows NT,

and start Chinese or Korean Windows. Then display the help files.

Additional reference words: fesdk hcp

KBCategory: kbprg kbtool

KBSubcategory: WIntlDev


How to Convert a Binary SID to Textual Form

PSS ID Number: Q131320

Authored 07-Jun-1995	Last modified 23-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

SUMMARY

It may be useful to convert a binary SID (security identifier) to a

readable, textual form, for display or manipulation purposes.

One example of an application that makes use of SIDs in textual form is the

Windows NT Event Viewer. If the Event Viewer cannot look up the name

associated with the SID of a logged event, the Event Viewer displays a

textual representation of the SID.

Windows NT also makes use of textual SIDs when loading user configuration

hives into the HKEY_USERS registry key.

Applications that obtain domain and user names can display the textual SID

representation when the Win32 API LookupAccountSid fails to obtain domain

and user information. Such a failure can occur if the network is down, or

the target machine is unavailable.

Sample Code

-----------

The following sample code displays the textual representation of the SID

associated with the current user. This source code converts a SID using the

same algorithm that the Windows NT operating system components use.

/*++

A standardized shorthand notation for SIDs makes it simpler to

visualize their components:

   S-R-I-S-S...

In the notation shown above:

   S identifies the series of digits as an SID.

   R is the revision level.

   I is the identifier-authority value.

   S is subauthority value(s).

A SID could be written in this notation as follows:

   S-1-5-32-544

In this example, the SID has a revision level of 1, an identifier-authority

value of 5, first subauthority value of 32, second subauthority value of

544. (Note that the above SID represents the local Administrators group.)

The GetTextualSid function converts a binary SID to a textual string.

The resulting string will take one of two forms. If the IdentifierAuthority

value is not greater than 2^32, then the SID will be in the form:

S-1-5-21-2127521184-1604012920-1887927527-19009

  ^ ^ ^^ ^^^^^^^^^^ ^^^^^^^^^^ ^^^^^^^^^^ ^^^^^

  | | |      |          |          |        |

  +-+-+------+----------+----------+--------+--- Decimal

Otherwise, the SID will take the form:

S-1-0x206C277C6666-21-2127521184-1604012920-1887927527-19009

  ^ ^^^^^^^^^^^^^^ ^^ ^^^^^^^^^^ ^^^^^^^^^^ ^^^^^^^^^^ ^^^^^

  |       |        |      |          |          |        |

  |   Hexadecimal  |      |          |          |        |

  +----------------+------+----------+----------+--------+--- Decimal

If the function succeeds, the return value is TRUE. If the function fails,

the return value is FALSE. To get extended error information, call the

Win32 API GetLastError().

--*/

#define RTN_OK 0

#define RTN_ERROR 13

#include <windows.h>

#include <stdio.h>

BOOL GetTextualSid(

    PSID pSid,          // binary SID

    LPSTR TextualSID,   // buffer for textual representation of SID

    LPDWORD dwBufferLen // required/provided TextualSid buffersize

    );

int main(void)

{

    #define MY_BUFSIZE 256 // all allocations should be dynamic

    HANDLE hToken;

    TOKEN_USER ptgUser[MY_BUFSIZE];

    DWORD cbBuffer=MY_BUFSIZE;

    char szTextualSid[MY_BUFSIZE];

    DWORD cbSid=MY_BUFSIZE;

    BOOL bSuccess;

    //

    // obtain current process token

    //

    if(!OpenProcessToken(

                GetCurrentProcess(), // target current process

                TOKEN_QUERY,         // TOKEN_QUERY access

                &hToken              // resultant hToken

                ))

    {

        fprintf(stderr, "OpenProcessToken error! (rc=%lu)\n",

            GetLastError() );

        return RTN_ERROR;

    }

    //

    // obtain user identified by current process's access token

    //

    bSuccess=GetTokenInformation(

                hToken,    // identifies access token

                TokenUser, // TokenUser info type

                ptgUser,   // retrieved info buffer

                cbBuffer,  // size of buffer passed-in

                &cbBuffer  // required buffer size

                );

    // close token handle. Do this even if error above

    CloseHandle(hToken);

    if(!bSuccess)

    {

        fprintf(stderr, "GetTokenInformation error! (rc=%lu)\n",

            GetLastError() );

        return RTN_ERROR;

    }

    //

    // obtain the textual representaion of the SID

    //

    if(!GetTextualSid(

                ptgUser->User.Sid, // user binary SID

                szTextualSid,      // buffer for TextualSid

                &cbSid             // size/required buffer

                ))

    {

        fprintf(stderr, "GetTextualSid error! (rc=%lu)\n",

            GetLastError() );

        return RTN_ERROR;

    }

    // display the TextualSid representation

    fprintf(stdout,"%s\n", szTextualSid);

    return RTN_OK;

}

BOOL GetTextualSid(

    PSID pSid,          // binary SID

    LPSTR TextualSID,   // buffer for textual representaion of SID

    LPDWORD dwBufferLen // required/provided TextualSid buffersize

    )

{

    PSID_IDENTIFIER_AUTHORITY psia;

    DWORD dwSubAuthorities;

    DWORD dwSidRev=SID_REVISION;

    DWORD dwCounter;

    DWORD dwSidSize;

    //

    // test if SID passed in is valid

    //

    if(!IsValidSid(pSid)) return FALSE;

    // obtain SidIdentifierAuthority

    psia=GetSidIdentifierAuthority(pSid);

    // obtain sidsubauthority count

    dwSubAuthorities=*GetSidSubAuthorityCount(pSid);

    //

    // compute buffer length

    // S-SID_REVISION- + identifierauthority- + subauthorities- + NULL

    //

    dwSidSize = 15 + 12 + (12 * dwSubAuthorities) + 1;

    //

    // check provided buffer length.

    // If not large enough, indicate proper size and setlasterror

    //

    if (*dwBufferLen < dwSidSize)

    {

        *dwBufferLen = dwSidSize;

        SetLastError(ERROR_INSUFFICIENT_BUFFER);

        return FALSE;

    }

    //

    // prepare S-SID_REVISION-

    //

    wsprintf(TextualSID, "S-%lu-", dwSidRev );

    //

    // prepare SidIdentifierAuthority

    //

    if ( (psia->Value[0] != 0) || (psia->Value[1] != 0) )

    {

        wsprintf(TextualSID + lstrlen(TextualSID),

                    "0x%02hx%02hx%02hx%02hx%02hx%02hx",

                    (USHORT)psia->Value[0],

                    (USHORT)psia->Value[1],

                    (USHORT)psia->Value[2],

                    (USHORT)psia->Value[3],

                    (USHORT)psia->Value[4],

                    (USHORT)psia->Value[5]);

    }

    else

    {

        wsprintf(TextualSID + lstrlen(TextualSID), "%lu",

                    (ULONG)(psia->Value[5]      )   +

                    (ULONG)(psia->Value[4] <<  8)   +

                    (ULONG)(psia->Value[3] << 16)   +

                    (ULONG)(psia->Value[2] << 24)   );

    }

    //

    // loop through SidSubAuthorities

    //

    for (dwCounter=0 ; dwCounter < dwSubAuthorities ; dwCounter++)

    {

        wsprintf(TextualSID + lstrlen(TextualSID), "-%lu",

                    *GetSidSubAuthority(pSid, dwCounter) );

    }

    return TRUE;

}

Additional reference words: Convert LookupAccountSid SID String

KBCategory: kbprg

KBSubcategory: BseSecurity BseMisc CodeSam


How to Create 3D Controls in Client Area of Non-Dialog Window

PSS ID Number: Q130763

Authored 25-May-1995	Last modified 23-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) version 4.0

SUMMARY

An application that uses standard Windows controls (edit boxes, list boxes,

and so on) as part of a dialog box with the DS_3DLOOK style set, have the

3D look by default. But if an application creates child controls as part of

the main window's client area, these controls do not have the 3D look by

default. Applications should add the WS_EX_CLIENTEDGE style to the list of

styles while creating the child controls to get the new 3D look.

MORE INFORMATION

WS_EX_CLIENTEDGE is the new extended style that gives controls (or any

window for that matter) the new 3D look. When controls are created as part

of a dialog box by using a dialog template based in the resource file,

Windows adds the WS_EX_CLIENTEDGE style to the list of styles.

Some applications use controls as child windows in the client area of the

main window. If the WS_EX_CLIENTEDGE style is not specified, these controls

have the Windows version 3.11 user interface (2D look).

Use CreateWindowEx() to create controls in the client area of a non-dialog

window, and make sure you OR in the WS_EX_CLIENTEDGE style. If your

application is using Microsoft Foundation Classes (MFC) version 3.x, you

can override the CreateEx() member function of the CEdit, CList, or any

other standard control class.

Additional reference words: 4.00 95 user

KBCategory: kbprg kbui

KBSubcategory: UsrCtl


How to Create a Topmost Window

PSS ID Number: Q81137

Authored 26-Feb-1992	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

Windows 3.1 introduces the concept of a topmost window that stays

above all the non-topmost windows even when the window is not the

active window.

There are two ways to add the topmost attribute to a window:

1. Use CreateWindowEx to create a new window. Specify WS_EX_TOPMOST as

   the value for the dwExStyle parameter.

2. Call SetWindowPos, specifying an existing non-topmost window and

   HWND_TOPMOST as the value for the hwndInsertAfter parameter.

SetWindowPos can also be used to remove the topmost attribute from a

window. To do so, specify HWND_NOTOPMOST or HWND_BOTTOM as the value

for the hwndInsertAfter parameter.

Additional reference words: 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrWndw


How to Create Inheritable Win32 Handles in Windows 95

PSS ID Number: Q118605

Authored 25-Jul-1994	Last modified 06-Apr-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK)

SUMMARY

Sometimes it is convenient for you to create an object such as a semaphore

or file and then allow a child process to inherit the object's handle. This

provides a means for two or more related processes to easily share an

object.

Although Windows 95 does not have a security system such as the one in

Microsoft Windows NT, Win32 API functions that create objects still use the

SECURITY_ATTRIBUTES structure to determine whether the handle to the newly

created object can be inherited. This article shows how to initialize a

SECURITY_ATTRIBUTES structure to control whether an object handle can be

inherited.

MORE INFORMATION

Win32 API functions that create objects require a SECURITY_ATTRIBUTES

parameter to give a newly created object access-control information and to

determine whether the handle to the object can be inherited.

The SECURITY_ATTRIBUTES structure contains the following members:

    Type      Name

    ----      ----

    DWORD     nLength;

    LPVOID    lpSecurityDescriptor;

    BOOL      bInheritHandle;

Secure Win32 operating systems such as Microsoft Windows NT use the

lpSecurityDescriptor member to enforce how and by which processes an object

is accessed. Because Windows 95 does not have a security system, it ignores

lpSecurityDescriptor. Like Microsoft Windows NT, Windows 95 uses the

bInheritHandle member to determine whether an object's handle can be

inherited by child processes.

To initialize a SECURITY_ATTRIBUTES structure so that a handle can be

inherited, set bInheritHandle to TRUE. The following code snippet shows how

to create a mutex with an inheritable handle:

      // Set the length of the structure, allow the handle to be

      // inherited, and use the default security descriptor (which

      // Windows 95 will ignore, but Windows NT will use.) Then create

      // a named, initially unowned mutex whose handle can be

      // inherited.

   SECURITY_ATTRIBUTES sa;

   HANDLE              hMutex1;

   sa.nLength              = sizeof(sa);

   sa.bInheritHandle       = TRUE;

   sa.lpSecurityDescriptor = NULL;

   hMutex1 = CreateMutex(&sa, FALSE, "MUTEX1");

To prevent the handle from being inherited, set bInheritHandle to FALSE.

The following code example demonstrates creating a mutex with a

noninheritable handle:

      // Set the length of the structure, do not allow the handle

      // to be inherited, and use the default security descriptor

      // (which Windows 95 will ignore, but Windows NT will use).

      // Create a named, initially unowned mutex whose handle cannot

      // be inherited.

   SECURITY_ATTRIBUTES sa;

   HANDLE              hMutex1;

   sa.nLength              = sizeof(sa);

   sa.bInheritHandle       = FALSE;

   sa.lpSecurityDescriptor = NULL;

   hMutex1 = CreateMutex(&sa, FALSE, "MUTEX1");

You can also prevent a handle to an object from being inherited by

specifying NULL in the call to Win32 object creation API function instead

of specifying a pointer to a SECURITY_ATTRIBUTES structure. This is

equivalent to setting bInheritHandle to FALSE and lpSecurityDescriptor to

NULL. For example:

      // Use NULL instead of pointer to SECURITY_ATTRIBUTES

      // structure to create a named, initially unowned

      // mutex whose handle cannot be inherited. A NULL security

      // descriptor will be used by Windows NT, but ignored by

      // Windows 95.

   HANDLE hMutex1;

   hMutex1 = CreateMutex(NULL, FALSE, "MUTEX1");

Cross-Platform Compatibility Information

----------------------------------------

Keep in mind that while Windows 95 does not have a security system, Windows

NT does. Windows 95 ignores the lpSecurityDescriptor member of the

SECURITY_ATTRIBUTES, but Windows NT uses it. If access to the object needs

to be controlled in a specific way on Windows NT, then the

lpSecurityDescriptor should be initialized by calling the Win32 security

API functions.

Additional reference words: 4.00

KBCategory: kbprg

KBSubcategory: BseSecurity


How to Create Non-rectangular Windows

PSS ID Number: Q125669

Authored 01-Feb-1995	Last modified 06-Apr-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

SUMMARY

Windows 95 and Windows NT version 3.51 provide a new API called

SetWindowRgn() that makes it easy for applications to create irregularly

shaped windows.

MORE INFORMATION

In previous versions of Windows and Windows NT, it was possible to create

only rectangular windows. To simulate a non-rectangular window required a

lot of work on the application developer's part. Besides handling all

drawing for the window, the application was required to perform hit-testing

and force underlying windows to repaint as necessary to refresh the

"transparent" portions of the window.

Windows 95 and Windows NT version 3.51 greatly simplify this by providing

the SetWindowRgn function. An application can now create a region with any

desired shape and use SetWindowRgn to set this as the clipping region

for the window. Subsequent painting and mouse messages are limited to this

region, and Windows automatically updates underlying windows that show

through the non-rectangular window. The application need only paint the

window as desired.

For more information on using SetWindowRgn, see the Win32 API

documentation.

Additional reference words: 4.00

KBCategory: kbprg

KBSubcategory: UsrMisc


How to Delete Keys from the Windows NT Registry

PSS ID Number: Q127990

Authored 22-Mar-1995	Last modified 23-Mar-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), version 3.5

There are two ways to delete registry keys: use REGEDT32.EXE or call

RegDeleteKey() from your application.

The documentation for RegDeleteKey() points out that the specified key to

be deleted must not have subkeys. If the key to be deleted does have

subkeys, RegDeleteKey() will fail with access denied. This happens despite

the fact that the machine account has delete privileges and the registry

handle passed to RegDeleteKey() was opened with delete access. The

additional requirement is that the key must have no subkeys.

This limitation does not exist in 16-bit Windows. The difference exists in

Windows NT because of atomicity and security considerations that 16-bit

Windows does not have.

You can select a key with subkeys and delete it with REGEDT32. This is

because REGEDT32 recursively deletes the subkeys for you, making multiple

call to RegDeleteKey(). You should use recursive subkey deletion in your

application as well, if you need to delete keys that have subkeys.

Additional reference words: 3.50

KBCategory: kbprg

KBSubcategory: BseMisc


How to Design Multithreaded Applications to Avoid Deadlock

PSS ID Number: Q126768

Authored 01-Mar-1995	Last modified 25-May-1995

--

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.5, 3.51, and

   4.0

--

SUMMARY

Debugging a multithreaded application that deadlocks is challenging because

the debugger cannot identify for you which thread owns which resource. You

would have to track this information in your code. Because it is difficult

to debug a deadlock situation, it is important to design your application

to avoid deadlock.

This article is a brief introduction to a very complex topic. There are

references at the bottom of this article for additional information.

The key point to keep in mind when designing a multithreaded program is

that resources must always be requested in the same order.

MORE INFORMATION

The Win32 API provides WaitForSingleObject() and WaitForMultipleObjects()

for requesting resources with handles. You would use a different method to

request other resources, depending on the resource type.

Many deadlocks occur because resources are not requested in the same order

by the application threads. For example:

 - Thread 1 holds resource A and wants resource B.

 - Thread 2 holds resoruce B and wants resource A.

Both threads block forever, resulting in deadlock. There are many other

possible scenarios.

To avoid this problem, identify all of your application's critical

resources and order them from least precious to most precious. Design your

code such that if a thread needs several resources, it requests them in

order, starting with the least precious resource. Resources should be freed

in the reverse order and as soon as it is possible. This is not a

requirement to avoid deadlock, but it is good practice.

In the example given above, suppose that resource B is more precious than

resource A. Here's how the code would resolve the situation:

 - Thread 2 already holds B, but because it wants A, it releases

   B and waits for A.

 - Thread 1 grabs B, then begins the task. It releases A when possible.

 - Thread 2 grabs A and waits for B.

 - Thread 1 finishes the task, then releases B.

 - Thread 2 grabs B, finishes the task, then releases A, then releases B.

The reason you should request the least precious resource first is that it

doesn't matter as much if you hold it longer while waiting to acquire all

the resources that you need. If the resource is precious, you want to hold

it for the smallest amount of time possible, so other threads can use it.

REFERENCES

MSDN Development Library, "Detecting Deadlocks in Multithreaded Win32

Applications", by Ruediger Asche.

For more information, refer to a good book on operating system design.

Additional reference words: 3.50 4.00 95  race condition

KBCategory: kbprg

KBSubcategory: BseProcThrd


How to Detect All Program Terminations

PSS ID Number: Q125689

Authored 01-Feb-1995	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

SUMMARY

The processes for detecting program terminations in fall into two

categories:

 - Win32 processes use WaitForSingleObject() or WaitForMultipleObjects()

   to wait for other Win32 processes, Windows 16-bit processes, and

   MS-DOS-based applications to terminate.

 - Windows 16-bit processes, on the other hand, must use the TOOLHELP

   NotifyRegister() function. The 16-bit processes can be notified when

   other 16-bit processes and MS-DOS-based applications exit, but have the

   limitation of not being notified of Win32 process activity.

MORE INFORMATION

Win32 processes can use WaitForSingleObject() or WaitForMultipleObjects()

to wait for a spawned process. By using CreateProcess() to launch a Win32

process, 16-bit process, or MS-DOS-based application, you can fill in a

PROCESS_INFORMATION structure. The hProcess field of this structure can be

used to wait until the spawned process terminates. For example, the

following code spawns a process and waits for its termination:

   STARTUPINFO StartupInfo = {0};

   StartupInfo.cb = sizeof(STARTUPINFO);

   if (CreateProcess(NULL, szCommandLine, NULL, NULL, FALSE,

                     0, NULL, NULL, &StartupInfo, &ProcessInfo))

   {

       WaitForSingleObject(ProcessInfo.hProcess, INFINITE);

       /* Process has terminated */

       ...

   }

   else

   {

       /* Process could not be started */

       ...

   }

If necessary, you can put this code into a separate thread to allow the

initial thread to continue to execute.

This synchronization method is not available to 16-bit processes. Instead,

they must use the TOOLHELP NotifyRegister function to register a callback

function to be called when a program terminates. This method will detect

the termination of 16-bit processes and MS-DOS-based applications, but not

Win32 processes.

The following code shows how to register a callback function with

NotifyRegister():

   FARPROC lpfnCallback;

   lpfnCallback = MakeProcInstance(NotifyRegisterCallback, ghInst);

   if (!NotifyRegister(NULL, (LPFNNOTIFYCALLBACK)lpfnCallback,

                       NF_NORMAL))

   {

      MessageBox(NULL, "NotifyRegister Failed", "Error", MB_OK);

      FreeProcInstance(lpfnCallback);

   }

The next section of code demonstrates the implementation of the callback

function:

   BOOL FAR PASCAL __export NotifyRegisterCallback (WORD wID,

                                                    DWORD dwData)

   {

      HTASK hTask;  // task that called the notification callback

      TASKENTRY te;

      // Check for task exiting

      switch (wID)

      {

         case NFY_EXITTASK:

            // Obtain info about the task that is terminating

            hTask = GetCurrentTask();

            te.dwSize = sizeof(TASKENTRY);

            TaskFindHandle(&te, hTask);

            // Check if the task that is terminating is our child task.

            // Also check if the hInstance of the task that is

            // terminating is the same as the hInstance of the task

            // that was WinExec'd by us earlier in the program.

            if (te.hTaskParent == ghtaskParent &&

                te.hInst == ghInstChild)

                PostMessage(ghwnd, WM_USER+509, (WORD)te.hInst, dwData);

            break;

         default:

            break;

      }

      // Pass notification to other callback functions

      return FALSE;

   }

The NotifyRegisterCallback() API is called by the 16-bit TOOLHELP DLL in

the context of the process that is causing the event. Problems arising

because of reentrancy and notification chaining makes the callback function

subject to certain restrictions. For example, operations that cause

TOOLHELP events cannot be done in the callback function. (See the TOOLHELP

NotifyRegister function documentation in your Software Development Kit for

events that cause TOOLHELP callbacks.)

There is no way a 16-bit process can be notified when a Win32 process

exits. However, a 16-bit process can use TaskFirst() and TaskNext() to

periodically walk the task list to determine if a Win32 process is still

executing. This technique also works for 16-bit processes and MS-DOS-based

applications. For example, the following code shows how to check for the

existence of a process:

   BOOL StillExecuting(HINSTANCE hAppInstance)

   {

      TASKENTRY  te = {0};

      te.dwSize = sizeof(te);

      if (TaskFirst(&te))

          do

          {

             if (te.hInstance == hAppInstance)

                return TRUE;      // process found

          } while (TaskNext(&te));

      // process not found

      return FALSE;

   }

Refer to the TermWait sample for complete details on how to use

NotifyRegister and implement a callback function. For additional

information, please search in the Microsoft Knowledge Base using this word:

   TERMWAIT

Additional reference words: 4.00 95  end exit notification notify spawn

terminate termination

KBCategory: kbprg kbcode

KBSubcategory: BseProcThrd


How to Detect Slow CPU & Unaccelerated Video Under Windows 95

PSS ID Number: Q131259

Authored 07-Jun-1995	Last modified 22-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) version 4.0

Under Windows 95, use GetSystemMetrics(SM_SLOWMACHINE) to check for low-end

computers. It returns a nonzero value if the computer has a 386 CPU, is low

on memory, or has a slow display card.

The return values (bit flags) are:

   0x0001      - CPU is a 386

   0x0002      - low memory machine (less than 5 megabytes)

The following is notable for video:

   0x0004      - slow (nonaccerated) display card

Additional reference words: 4.00 win95 system display slow machine

KBCategory: kbprg

KBSubcategory: UsrSys


How to Determine If a Device Is Palette Capable

PSS ID Number: Q72387

Authored 23-May-1991	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

On a device that supports the Windows palette management function, an

application can create a logical palette, select the palette into a

device context (DC), and realize the palette, which maps its colors

into the system (hardware) palette. The GetDeviceCaps() API informs

an application whether a given device is capable of performing palette

manipulation and, if so, the size of the palette. This article

discusses the GetDeviceCaps() API and how it is used.

MORE INFORMATION

To determine whether a device can perform palette operations, call the

GetDeviceCaps() API with the RASTERCAPS parameter. If the RC_PALETTE bit of

the return is set, the device supports the palette management functions.

To determine how many colors in the system palette are available for the

application to use, the following parameters can be used in a

GetDeviceCaps() call:

   Parameter      Description

   ---------      -----------

   SIZEPALETTE    Total number of entries in the system palette

   NUMRESERVED    Number of reserved (static) colors in the system

                  palette

This functionality is demonstrated in the MyPal sample code that is

included on the Windows version 3.x Software Development Kit (SDK)

Source Code 2 disk. For a demonstration, start MyPal and click the

right mouse button.

The reserved colors are entries in the system palette that are used by

Windows and cannot be changed by an application [except by using

SetSystemPaletteUse(), which is not recommended]. The reserved colors are

used for the following purposes:

   Active border

   Active caption

   Background color MDI applications

   Desktop background color

   Push button faces

   Push button edges

   Push button text

   Caption text

   Disabled (gray) text

   Highlight color in controls (to highlight items in the control)

   Highlight text color

   Inactive border

   Inactive caption

   Inactive caption text (new to Windows version 3.1)

   Menu background

   Menu text

   Scroll-bar gray area

   Window background

   Window frame

   Window text

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: GdiPal


How to Determine the Japanese OEM Windows Version

PSS ID Number: Q130054

Authored 10-May-1995	Last modified 16-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

 - Microsoft Win32 Software Development Kit (SDK) version 3.5

 - Microsoft Win32s version 1.2

SUMMARY

Because of the variety of computer manufacturers (NEC, Fujitsu, IBMJ, and

so on) in Japan, sometimes Windows-based applications need to know which

OEM (original equipment manufacturer) manufactured the computer that is

running the application. This article explains how.

MORE INFORMATION

There is no documented way to detect the manufacturer of the computer that

is currently running an application. However, a Windows-based application

can detect the type of OEM Windows by using the return value of the

GetKeyboardType() function.

If an application uses the GetKeyboardType API, it can get OEM ID by

specifying "1" (keyboard subtype) as argument of the function. Each OEM ID

is listed here:

   OEM Windows       OEM ID

   ------------------------------

   Microsoft         00H (DOS/V)

   all AX            01H

   EPSON             04H

   Fujitsu           05H

   IBMJ              07H

   Matsushita        0AH

   NEC               0DH

   Toshiba           12H

Application programs can use these OEM IDs to distinguish the type of OEM

Windows. Note, however, that this method is not documented, so Microsoft

may not support it in the future version of Windows.

As a rule, application developers should write hardware-independent code,

especially when making Windows-based applications. If they need to make a

hardware-dependent application, they must prepare the separated program

file for each different hardware architecture.

Additional reference words: 3.10 1.20 3.50 1.20 kbinf

KBCategory: kbhw

KBSubcategory: wintldev


How to Determine the Type of Handle Retrieved from

PSS ID Number: Q126258

Authored 16-Feb-1995	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

OpenPrinter returns a valid handle when a printer name or a server name is

passed to it. Sometimes it may be necessary to determine if the returned

handle is a handle to a printer because some Win32 spooler functions only

accept printer handles and will fail on server handles. The following code

determines if a handle is a printer handle:

BOOL IsPrinterHandle( HANDLE hPrinter)

{

    DWORD       cbNeeded;

    DWORD       Error;

    BOOL        bRet = FALSE;

    LPPRINTER_INFO_2 pPrinter;

    DWORD       cbBuf;

    HANDLE      hMem = NULL;

    if( !GetPrinter(hPrinter, 2, (LPBYTE)NULL, cbBuf, &cbNeeded ))

    {

        Error = GetLastError( );

        if( Error == ERROR_INSUFFICIENT_BUFFER )

        {

            hMem = GlobalAlloc(GHND, cbNeeded);

            if (!hMem) return bRet;

            pPrinter = (LPPRINTER_INFO_2)GlobalLock(hMem);

            cbBuf = cbNeeded;

            if(GetPrinter(hPrinter, 2, (LPBYTE)pPrinter, cbBuf, &cbNeeded))

            {

                bRet = TRUE;

                GlobalUnlock(hMem);

                GlobalFree(hMem);

            }

            else SetLastError( ERROR_INVALID_PRINTER_NAME );

        }

        else if( Error == ERROR_INVALID_HANDLE )

        {

            SetLastError( ERROR_INVALID_PRINTER_NAME );

        }

    }

    return bRet;

}

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg kbcode

KBSubcategory: GdiPrn


How to Determine Which Version of Win32s Is Installed

PSS ID Number: Q121091

Authored 26-Sep-1994	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32s, versions 1.1, 1.15, and 1.2

SUMMARY

The "Win32s Programmer's Reference" describes how to use the

GetWin32sInfo() function in a program to determine which version of Win32s

is installed. This article explains how to determine which version of

Win32s is installed interactively.

MORE INFORMATION

Use one of the following two methods to determine interactively which

version of Win32s is installed:

1. Check the WIN32S.INI file in your Windows system directory. The Version

   entry contains the major version and the build number (m.mm.bbb.b). This

   entry should be modified by any Win32-based application which installs a

   later version of Win32s on your Windows machine.

   NOTE: Because it is up to the application vendor to set this value

   when installing Win32s, the value may not be accurate. Microsoft

   strongly urges all independent software vendors (ISVs) to modify the

   WIN32S.INI file so that this information is available to customers.

   -or-

2. If Win32s is installed on top of Windows for Workgroups, select the

   WIN32S16.DLL file from the Windows system directory in File Manager.

   Then from the File menu, choose Properties. The Version line contains

   the major version and the build number.

Version Information

-------------------

Win32s version 1.1.88 was distributed as Win32s version 1.1 and Win32s

version 1.1.89 was distributed as Win32s version 1.1a.

Win32s version 1.15.103 was distributed as Win32s version 1.15 and Win32s

version 1.15.111 was distributed as Win32s version 1.15a.

Win32s version 1.2.123 was distributed as Win32s version 1.2.

Additional reference words: 1.10 1.15 1.20

KBCategory: kbenv

KBSubCategory: W32s


How to Disable the Screen Saver Programmatically

PSS ID Number: Q126627

Authored 27-Feb-1995	Last modified 24-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.5 and 3.51

SUMMARY

Under Windows NT, you can disable the screen saver from your application

code. To detect if the screen saver is enabled, use this:

   SystemParametersInfo( SPI_GETSCREENSAVEACTIVE,

                         0,

                         pvParam,

                         0

                       );

On return, the parameter pvParam will point to TRUE if the screen saver

setting is enabled in the System control panel applet and FALSE if the

screen saver setting is not enabled.

To disable the screen saver setting, call SystemParametersInfo() with this:

   SystemParametersInfo( SPI_SETSCREENSAVEACTIVE,

                         FALSE,

                         0,

                         SPIF_SENDWININICHANGE

                       );

MORE INFORMATION

When the screen saver is activated by the system, it is run on a desktop

other than the user's desktop (similar to the login desktop displayed when

no one is logged in). Therefore, you cannot use FindWindow() to determine

if the screen saver is currently active.

Here are two methods that you can use to detect if the screen saver is

currently running:

1. Get the name of the current screen saver from the registry, parse the PE

   header of the screen saver binary to get the process name, then check

   for an active process with that name in the performance registry.

   -or-

2. Write a screen saver that would be spawned by the system and would in

   turn spawn the "real" screen saver. The first screen saver could notify

   your application when the screen saver has been activated or

   deactivated.

Additional reference words: 3.50

KBCategory: kbprg

KBSubcategory: GdiScrsav


How to Display Debugging Messages in Windows 95

PSS ID Number: Q125868

Authored 07-Feb-1995	Last modified 06-Apr-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

SUMMARY

In Windows 95, 16-bit and 32-bit Windows-based applications may use

OutputDebugString() to display debug messages. Furthermore, the 16-bit and

32-bit system DLLs may also display debug messages. This article describes

how to view these messages during application developement.

MORE INFORMATION

It is possible to use the 16-bit DBWIN application to display debug

messages from 16-bit Windows-based applications and from the debugging

versions of system DLLs (such as GDI.EXE, USER.EXE, and KRNL386.EXE). To

receive debug messages via DBWIN, you must install the Windows 95 SDK debug

components.

To receive messages from 32-bit Windows-based applications under Windows

95, you must debug the application with a Win32 debugger such as WinDbg, or

install WDEB386 as a .VxD or in the AUTOEXEC.BAT file. To receive messages

from the debugging versions of the 32-bit system DLLs (KERNEL32.DLL,

USER32.DLL, and GDI32.DLL), you must install the Windows 95 SDK debugging

components, in conjunction with WDEB386.

You can use WDEB386 to display debug messages from both 16-bit and 32-bit

Windows-based applications and from the debugging versions of system

components. Because WDEB386 works over a serial communications port, it is

necessary to use a serial terminal or second computer to operate it. For

more information about configuring and using WDEB386, please search for

articles in the Microsoft Knowledge Base by using this word:

   WDEB386

Alternative system level debuggers, which provide functionality

similiar to WDEB386, may in the future be provided by third-party vendors.

Also, you can write 32-bit application-level debuggers that display debug

messages from the debuggee by handling the DEBUG_EVENT structure member

OUTPUT_DEBUG_STRING_EVENT.

Additional reference words: 3.95 4.00

KBCategory: kbprg

KBSubcategory: BseErrdebug


How to Display Old-Style FileOpen Common Dialog in Windows 95

PSS ID Number: Q131282

Authored 07-Jun-1995	Last modified 10-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) version 4.0

SUMMARY

If you want an application to revert back to the old-style FileOpen or

SaveAs common dialog box, you must either provide a dialog template or a

hook function in addition to not specifying the OFN_EXPLORER flag.

MORE INFORMATION

Windows 95 provides a new flag for the File Open or Save As common dialog

box called OFN_EXPLORER. When set, this flag ensures that the File Open

dialog box displays a user interface that is similar to the Windows

Explorer (or so-called Explorer-style dialog box).

You may want your application to revert to the old Windows version 3.1

style dialog box. For example, you might want to maintain a user interface

consistent with the Windows NT user interface. Windows NT version 3.51

currently does not support the new Explorer-style File Open common dialog

box. The next version of Windows NT, however, should implement this new

feature.)

To display the old-style common dialog box:

 - Don't specify the OFN_EXPLORER value in the OPENFILENAME structure's

   Flags member.

 - Provide a dialog template or a hook. If the application does not have

   either one, a simple hook that always returns FALSE should suffice.

NOTE: When you specify a hook function for the old-style common dialog box

in Windows 95, the hDlg received in the hookProc is the actual handle to

the dialog containing the standard controls. This is not true, however, for

the new Explorer-style common dialog hookProc where the hDlg received is

the handle to a child of the dialog box containing the standard controls.

Therefore, to get a handle to the actual File Open or Save As dialog box,

an application should call GetParent() on the hDlg passed to the hook

procedure.

Additional reference words: 4.00 subdialog

KBCategory: kbprg kbui

KBSubcategory: UsrCmnDlg


How to Draw a Custom Window Caption

PSS ID Number: Q99046

Authored 20-May-1993	Last modified 20-Jun-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

Microsoft Windows draws captions in the caption bar (or title bar) for all

eligible windows in the system. Applications need to specify only the

WS_CAPTION style to take advantage of this facility. The current version of

Microsoft Windows, however, imposes three significant restrictions on the

captions. An application that does not want to be tied by any of these

restrictions may want to draw its own caption. This article lists the

restrictions and the steps required to draw a window caption.

These restrictions also apply to Windows NT, but there are a few

differences for Windows 95.

It is important to note that an application should not draw its own caption

unless it has very good reasons to do so. A window caption is a user

interface object, and rendering it in ways different from other windows in

the system may obstruct the user's conceptual grasp of the Microsoft

Windows user interface.

MORE INFORMATION

Windows and Windows NT

----------------------

The three important restrictions imposed by Microsoft Windows version 3.1

and Microsoft Windows NT on the caption for a window are:

- It consists of text only; graphics are not allowed.

- All text is centered and drawn with the system font.

- The length of the displayed caption is limited to 78 characters

  even when there is space on the caption bar to accommodate extra

  characters.

An application can essentially render its own caption consisting of any

graphic and text with the standard graphics and text primitives by painting

on the nonclient area of the window. The application should draw in

response to the WM_NCPAINT, WM_NCACTIVATE, WM_SETTEXT, and WM_SYSCOMMAND

messages. When processing these messages, an application should first pass

on the message to DefWindowProc() for default processing, then render its

caption before returning from the message. This ensures that Microsoft

Windows can properly draw the nonclient area. Because drawing the caption

is part of DefWindowProc()'s nonclient area processing, an application

should specify an empty window title to avoid any Windows-initiated drawing

in the caption bar. The following steps indicate the computations needed to

determine the caption drawing area:

1. Get the current window's rectangle using GetWindowRect(). This

   includes client plus nonclient areas and is in screen coordinates.

2. Get a device context (DC) to the window using GetWindowDC().

3. Compute the origin and dimensions of the caption bar. One needs to

   account for the window decorations (frame, border) and window

   bitmaps (min/max/system boxes). Remember that different window

   styles will result in different decorations and a different number of

   min/max/system boxes. Use GetSystemMetrics() to compute the

   dimensions of the frame, border, and the system bitmap dimensions.

4. Render the caption within the boundaries of the rectangle computed

   in step 3. Remember that the user can change the caption bar color

   any time by using the Control Panel. Some components of the caption,

   particularly text backgrounds, may need to be changed based on the

   current caption bar color. Use GetSysColor to determine the current

   color.

The following code sample draws a left-justified caption for a window

(the code sample applies only to the case where the window is active):

Sample Code

-----------

   case WM_NCACTIVATE:

      if ((BOOL)wParam == FALSE)

      {

         DefWindowProc( hWnd, message, wParam, lParam );

      // Add code here to draw caption when window is inactive.

         return TRUE;

      }

      // Fall through if wParam == TRUE, i.e., window is active.

      case WM_NCPAINT:

      // Let Windows do what it usually does. Let the window caption

      // be empty to avoid any Windows-initiated caption bar drawing

         DefWindowProc( hWnd, message, wParam, lParam );

         hDC = GetWindowDC( hWnd );

         GetWindowRect( hWnd, (LPRECT)&rc2 );

      // Compute the caption bar's origin. This window has a system box

      // a minimize box, a maximize box, and has a resizeable frame

         x = GetSystemMetrics( SM_CXSIZE ) +

             GetSystemMetrics( SM_CXBORDER ) +

             GetSystemMetrics( SM_CXFRAME );

         y = GetSystemMetrics( SM_CYFRAME );

         rc1.left = x;

         rc1.top = y;

      // 2*x gives twice the bitmap+border+frame size. Since there are

      // only two bitmaps, two borders, and one frame at the end of the

      // caption bar, subtract a frame to account for this.

         rc1.right = rc2.right - rc2.left - 2*x -

                     GetSystemMetrics( SM_CXFRAME );

         rc1.bottom = GetSystemMetrics( SM_CYSIZE );

      // Render the caption. Use the active caption color as the text

      // background.

         SetBkColor( hDC, GetSysColor(COLOR_ACTIVECAPTION) );

         DrawText( hDC, (LPSTR)"Left Justified Caption", -1,

                 (LPRECT)&rc1, DT_LEFT );

        ReleaseDC( hWnd, hDC );

        break;

Windows 95

----------

On Windows 95, the text is not centered and the user can choose the Font.

In addition, your application might want to monitor the WM_WININICHANGED

message, because the user can change titlebar widths, and so forth,

dynamically. When this happens, the application should take the new system

metrics into account, and force a window redraw.

Additional reference words: 3.00 3.10 3.50 4.00 minimum maximum

KbCategory: kbprg kbcode

KbSubCategory: UsrPnt


How to Draw a Gradient Background

PSS ID Number: Q128637

Authored 05-Apr-1995	Last modified 23-May-1995

-

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK), versions 3.0 and 3.1

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

-

SUMMARY

This article provides source code for drawing a gradient background pattern

similar to the one used in Microsoft Setup applications. The code will

compile and run on Windows version 3.1, Win32s, and Windows 95.

MORE INFORMATION

WARNING: ANY USE BY YOU OF THE CODE PROVIDED IN THIS ARTICLE IS AT YOUR

OWN RISK. Microsoft provides this code "as is" without warranty of any

kind, either express or implied, including but not limited to the implied

warranties of merchantability and/or fitness for a particular purpose.

/*************************************************************

*                                                            *

*  DrawBackgroundPattern()                                   *

*                                                            *

*  Purpose: This function draws a gradient pattern that      *

*           transitions between blue and black. This is      *

*           similar to the background used in Microsoft      *

*           setup programs.                                  *

*                                                            *

*************************************************************/

void DrawBackgroundPattern(HWND hWnd)

{

  HDC hDC = GetDC(hWnd);  // Get the DC for the window

  RECT rectFill;          // Rectangle for filling band

  RECT rectClient;        // Rectangle for entire client area

  float fStep;            // How large is each band?

  HBRUSH hBrush;

  int iOnBand;  // Loop index

  // How large is the area you need to fill?

  GetClientRect(hWnd, &rectClient);

  // Determine how large each band should be in order to cover the

  // client with 256 bands (one for every color intensity level)

  fStep = (float)rectClient.bottom / 256.0f;

  // Start filling bands

  for (iOnBand = 0; iOnBand < 256; iOnBand++) {

    // Set the location of the current band

    SetRect(&rectFill,

            0,                           // Upper left X

            (int)(iOnBand * fStep),      // Upper left Y

            rectClient.right+1,          // Lower right X

            (int)((iOnBand+1) * fStep)); // Lower right Y

    // Create a brush with the appropriate color for this band

    hBrush = CreateSolidBrush(RGB(0, 0, (255 - iOnBand)));

    // Fill the rectangle

    FillRect(hDC, &rectFill, hBrush);

    // Get rid of the brush you created

    DeleteObject(hBrush);

  };

  // Give back the DC

  ReleaseDC(hWnd, hDC);

}

Additional reference words: 3.00 3.10 3.50 4.00 GRADIENT BACKGROUND DITHER

KBCategory: kbprg kbcode

KBSubcategory: GdiMisc


How to Examine the Use of Process Memory Under Win32s

PSS ID Number: Q129599

Authored 30-Apr-1995	Last modified 01-May-1995

The information in this article applies to:

 - Microsoft Win32s, version 1.2

SUMMARY

Under Windows, tools like HeapWalk and PWalk can be used to examine memory

use of 16-bit code. However, these tools cannot be used to look at memory

use of 32-bit code. This article discusses how to look at process memory

use under Win32s.

MORE INFORMATION

If you run the debug version of Win32s and kernel debugger WDEB386, you can

break into the debugger at any point by pressing CTRL+C and using debug

information from the Win32s VxD. Use the command .w32s to get the list of

information types available.

   #.w32s

   W32S debug routines:

   A - General Info

   B - Print Free LS ranges

   C - Print RRD & Section lists

   D - Print Modules list

   E - Toggle SwapOut trace

   F - Toggle PageFault trace

   G - count present alias pages

   H - List RRD Commit List

   I - Toggle Virtual Alloc/Free trace

   J - Toggle Mapped Section trace

   K - List Locked Pages

   [ESC] Exit W32S Debug Routines

Option C gives you information about the sparse memory usage.

The memory for .EXE and .DLL files is allocated in the sparse memory.

Here's an example printout using option C:

RRD List:

Index      Start      Size       Owner      #Commits   CommSize   #PresPg

00000000   87AA0000   0000E000   00000000   - VIEW -   - VIEW -   - VIEW -

00000001   87A90000   00001000   00001F37   00000001   00001000   00000001

00000002   87A50000   00040000   00000000   00000000   00000000   00000000

00000003   87A40000   00002000   00000000   - VIEW -   - VIEW -   - VIEW -

00000004   87A30000   00009000   00000000   - VIEW -   - VIEW -   - VIEW -

00000005   87A20000   00002000   00000000   - VIEW -   - VIEW -   - VIEW -

00000006   87A10000   00002000   00000000   - VIEW -   - VIEW -   - VIEW -

00000007   87910000   00100000   00001F37   00000001   00001000   00000001

00000008   878F0000   00020000   00001F37   00000001   00020000   00000002

00000009   878C0000   00021000   00001F37   00000001   00021000   00000001

0000000A   878B0000   00005000   00000000   00000001   00005000   00000005

0000000B   87860000   00043000   00000000   00000001   00043000   00000031

0000000C   87830000   0002D000   00000000   00000001   0002D000   0000000C

0000000D   87810000   00011000   00000000   00000001   00011000   0000000E

0000000E   80869000   00001000   00001F37   00000001   00001000   00000000

0000000F   87800000   00002000   00001F37   00000001   00002000   00000001

00000010   80635000   00001000   00001F37   00000001   00001000   00000000

                      ========                         ========   ========

Total                 00229000                         000CD000   00000056

Sections List:

SecIndex   hFile      SecSize    #Ref       #Views     CommSize   #PresPg

00000001   00000004   00002000   00000000   00000001   00002000   00000001

00000002   00000005   00002000   00000000   00000001   00002000   00000001

00000003   00000006   00009000   00000000   00000001   00009000   00000003

00000004   00000007   00002000   00000000   00000001   00002000   00000001

00000005   00000008   0000E000   00000000   00000001   0000E000   00000001

                      ========                         ========   ========

Total                 0001D000                         0001D000   00000007

G. Total                                               000EA000   0000005D

The Size column contains the reserved size and the CommSize column contains

the committed size. The addresses are zero-based (ring 0), not based on

0xffff0000 (ring 3). Therefore, you must add 0x10000 to the addresses you

see in the list in order to get the ring 3 addresses.

Option D gives you the list of modules and where they reside in memory.

These addresses are zero-based addresses as well, as is any information

that you get from the VxD.

Another way to get information indicating where things are placed in memory

is to set the verbose loader flag (0x20) in the Win32sDebug variable in the

[386Enh] section of the SYSTEM.INI file.

NOTE: Do not add the 0x, just write Win32sDebug=20. The loader then will

print in the debug terminal information about each loaded module. For

example:

Open file D:\WIN32APP\FREECELL\FREECELL.EXE in mode 0xa0

LELDR: allocating 0x11000

LELDR: Module D:\WIN32APP\FREECELL\FREECELL.EXE [1] loaded at 0x87820000

LELDR: obj  1 loaded @ 0x87821000, 0x   5c00 bytes   .text,flags=0x60000020

LELDR: obj  2 loaded @ 0x87827000, 0x      0 bytes    .bss,flags=0xc0000080

LELDR: obj  3 loaded @ 0x87828000, 0x    200 bytes  .rdata,flags=0x40000040

LELDR: obj  4 loaded @ 0x87829000, 0x    a00 bytes   .data,flags=0xc0000040

LELDR: obj  5 loaded @ 0x8782a000, 0x   2400 bytes   .rsrc,flags=0x40000040

LELDR: obj  6 loaded @ 0x8782d000, 0x    200 bytes    .CRT,flags=0xc0000040

LELDR: obj  7 loaded @ 0x8782e000, 0x    a00 bytes  .idata,flags=0x40000040

LELDR: obj  8 loaded @ 0x8782f000, 0x   1e00 bytes  .reloc,flags=0x42000040

File D:\WIN32APP\FREECELL\FREECELL.EXE is closed

The addresses here are ring 3 addresses.

REFERENCES

Please see the "Win32s Programmer's Reference" included in the Win32 SDK

for more information about the debugging features. This information is not

included in the version of the Win32s documentation distributed with Visual

C++.

Additional reference words: 1.20

KBCategory: kbprg

KBSubcategory: W32s


How to Find Out Which Listview Column Was Right-Clicked

PSS ID Number: Q125694

Authored 01-Feb-1995	Last modified 06-Apr-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

SUMMARY

You can use the technique described in this article to find out which

column was clicked after right-clicking the listview column header.

MORE INFORMATION

LVN_COLUMNCLICK notifies a listview's parent window when a column is

clicked using the left mouse button, but no such notification occurs when a

column is clicked with the right mouse button.

Windows 95 sends an NM_RCLICK notification to the listview's parent window

when a column is clicked with the right mouse button, but the message sent

does not contain any information as to which column was clicked, especially

if the window is sized so that the listview is scrolled to the right.

The correct way to determine which column was clicked with the right mouse

button, regardless of whether the listview is scrolled, is to send the

header control an HDM_HITTEST message, which returns the index of the

column that was clicked in the iItem member of the HD_HITTESTINFO struct.

In sending this message, make sure the point passed in the HD_HITTESTINFO

structure is relative to the header control's client coordinates. Do not

pass it a point relative to the listview's client coordinates; if you do,

it will return an incorrect column index value.

The header control in this case turns out to be a child of the listview

control of LVS_REPORT style.

The following code demonstrates this method. Note that while the code

processes the NM_RCLICK notification on a WM_NOTIFY message, you also

process the WM_CONTEXTMENU message, which is also received as a

notification when the user clicks the right mouse button.

case WM_NOTIFY:

{

    if ((((LPNMHDR)lparam)->code == NM_RCLICK))

    {

       HWND hChildWnd;

       POINT pointScreen, pointLVClient, pointHeader;

       DWORD dwpos;

       dwPos = GetMessagePos();

       pointScreen.x = LOWORD (dwPos);

       pointScreen.y = HIWORD (dwPos);

       pointLVClient = pointScreen;

       // Convert the point from screen to client coordinates,

       // relative to the listview

       ScreenToClient (ghwndLV, &pointLVClient);

       // Because the header turns out to be a child of the

       // listview control, we obtain its handle here.

       hChildWnd = ChildWindowFromPoint (ghwndLV, pointLVClient);

       // NULL hChildWnd means R-CLICKED outside the listview.

       // hChildWnd == ghwndLV means listview got clicked: NOT the

       // header.

       if ((hChildWnd) && (hChildWnd != ghwndLV))

       {

          char szClass [50];

          // Verify that this window handle is indeed the header

          // control's by checking its classname.

          GetClassName (hChildWnd, szClass, 50);

          if (!lstrcmp (szClass, "SysHeader32"))

          {

             HD_HITTESTINFO hdhti;

        char szBuffer [80];

             // Transform to client coordinates

             // relative to HEADER control, NOT the listview!

             // Otherwise, incorrect column number is returned.

             pointHeader = pointScreen;

             ScreenToClient (hChildWnd, &pointHeader);

             hdhti.pt = pointHeader;

             SendMessage (hChildWnd,

                          HDM_HITTEST,

                          (WPARAM)0,

                          (LPARAM) (HD_HITTESTINFO FAR *)&hdhti);

            wsprintf (szBuffer, "Column %d got clicked.\r\n", hdhti.iItem);

            MessageBox (NULL, szBuffer, "Test", MB_OK);

          }

       }

    }

    return 0L;

}

Additional reference words: 4.00

KBCategory: kbprg kbcode

KBSubcategory: UsrCtl


How to Find the Version Number of Win32s

PSS ID Number: Q125014

Authored 19-Jan-1995	Last modified 20-Jan-1995

--

The information in this articles applies to:

 - Microsoft Win32s, versions 1.0, 1.1, and 1.2

--

SUMMARY

This article describes how to obtain the version number information for

Win32s installed on a Windows 3.1 machine from one of the following places:

 - From an end user perspective, on either Windows for Workgroups 3.11 or

   Windows NT 3.5

 - A 16-bit application running on Windows 3.1

 - A 32-bit application running on Windows 3.1

The following section describes in more details how to obtain this

information in all the above situations.

MORE INFORMATION

From an End User Perspective

----------------------------

Because Win32s does not have a user interface, there is no obvious way to

get the version number information for Win32s that is installed on Windows

3.1. However, end users have the following two options:

 - Read the <windir>\SYSTEM\WIN32S.INI file, which has an entry for version

   information. Because this .INI file can be updated by the Setup program

   of any Win32s application, this information is not completely reliable.

 - From File Manager on Windows for Workgroups 3.11 or Windows NT 3.5,

   select the WIN32S16.DLL and choose Properties from the File menu. This

   method yields a dialog box with version information on Win32s. Remember

   that WIN32S16.DLL is a 16-bit DLL; however, File Manager on Windows NT

   3.5 can still read this version resource information.

From a 16-Bit Application

-------------------------

To get version number information for Win32s from a 16-bit application, use

the Win32s specific function, GetWin32sInfo(), which is documented in the

Win32s Programmer's Reference. This function is exported by the 16-bit

W32SYS.DLL file in Win32s 1.1 and later. The GetWin32sInfo() function fills

a specified structure with the information from Win32s VxD. Usually a 16-

bit Windows setup program should use this function to determine if Win32s

is already installed before continuing installation. Note that a 16-bit

program must use LoadLibrary and GetProcAddress to call the function

because the function did not exist in Win32s version 1.0.

The following example on using GetWin32sInfo() is extracted from the Win32s

Programmer's Reference:

// Example of a 16-bit application that indicates whether Win32s is

// installed, and the version number if Win32s is loaded and VxD is

// functional.

BOOL FAR PASCAL IsWin32sLoaded(LPSTR szVersion)

{

    BOOL              fWin32sLoaded = FALSE;

    FARPROC           pfnInfo;

    HANDLE            hWin32sys;

    WIN32SINFO        Info;

    hWin32sys = LoadLibrary("W32SYS.DLL");

    if (hWin32sys > HINSTANCE_ERROR) {

        pfnInfo = GetProcAddress(hWin32sys, "GETWIN32SINFO");

        if (pfnInfo) {

            // Win32s version 1.1 is installed

            if (!(*pfnInfo)((LPWIN32SINFO) &Info)) {

                fWin32sLoaded = TRUE;

                wsprintf(szVersion, "%d.%d.%d.0",

                         Info.bMajor, Info.bMinor, Info.wBuildNumber);

            } else

                fWin32sLoaded = FALSE;    // Win32s VxD not loaded.

        } else {

            // Win32s version 1.0 is installed.

            fWin32sLoaded = TRUE;

            lstrcpy( szVersion, "1.0.0.0" );

        }

        FreeLibrary( hWin32sys );

    } else                                // Win32s not installed.

        fWin32sLoaded = FALSE;

    return fWin32sLoaded;

}

From a 32-Bit Application

-------------------------

To determine if Win32s is installed, use the function GetVersion(); to then

get the version of Win32s use the function, GetVersionEx(). This function

fills a specified structure with version information of Win32s on Windows

3.1. The following is an example illustrating the use of this function:

// Example of a 32-bit code that determines the operating system installed

// and the version number on all platforms: Windows NT, Windows 95, Win32s.

typedef BOOL (*LPFNGETVERSIONEX) (LPOSVERSIONINFO);

BOOL IsWin32sLoaded(char *szVersion)

{

  BOOL              fWin32sLoaded = FALSE;

  DWORD             dwGetVer;

  HMODULE           hKernel32;

  OSVERSIONINFO     ver;

  LPFNGETVERSIONEX    lpfnGetVersionEx;

  // First, check if Win32s is installed

  dwGetVer = GetVersion();

  if (!(dwGetVer & 0x80000000))

  {

     //  Windows NT is loaded

     // Note, GetVersion will also return version number on Windows NT

     return;

  }

  else if (LOBYTE(LOWORD(dwVersion))< 4)

  {

    // Win32s is loaded

    fWin32sLoaded = TRUE;

  }

  else {

     // Windows 95 is loaded

     // Note, GetVersion will also return version number on Windows 95

     return;

  }

  // Now, let's find the version number of Win32s

    hKernel32 = GetModuleHandle("Kernel32");

    if (hKernel32)

    {

        lpfnGetVersionEx = (LPFNGETVERSIONEX)GetProcAddress(hKernel32,

"GetVersionExA");

        if (lpfnGetVersionEx)

   {

           // Win32s version 1.15 or later is installed

           ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);

           if (!(*lpfnGetVersionEx)((LPOSVERSIONINFO) &ver))

             DisplayError("GetVersionEx");

           else

             wsprintf(szVersion, "%d.%d.%d - %s", ver.dwMajorVersion,

ver.dwMinorVersion,

                      ver.dwBuildNumber, PlatformName(ver.dwPlatformId));

   }

   else

   {

// This failure could mean several things

// 1. On an NT system, it indicates NT version 3.1 because GetVersionEx()

//    is only implemented on NT 3.5.

// 2. On Windows 3.1 system, it means either Win32s version 1.1 or 1.0 is

//    installed. You can distinguish between 1.1 and 1.0 in two ways:

// a. Get version info from WIN32S16.DLL like File Manager on NT does.

// b. Thunk to 16-bit side and call GetWin32sInfo.

   }

    }

 return (fWin32sLoaded);

}

NOTE: In general, 32-bit applications that use Win32s should always ship

with the latest version of Win32s. Therefore the detection code above can

be greatly simplified if determination of previous versions of Win32s is

not needed.

Additional reference words: 3.10 win32s w32s win32 wfw

KBCategory: kbenv

KBSubcategory: W32s


How to Gracefully Fail at Service Start

PSS ID Number: Q115829

Authored 05-Jun-1994	Last modified 03-Mar-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   versions 3.1, 3.5, and 3.51

SUMMARY

If an error occurs while your service is running or initializing

(SERVICE_START_PENDING) and you need to stop the service process, do the

following:

1. Clean up any resources that are being used (threads, memory, and so

   forth). You should start sending a SERVICE_STOP_PENDING status if the

   clean up process is lengthy. Be sure to update the Service Control

   Manager as demonstrated in the Win32 SDK SERVICE sample.

2. Send out a SERVICE_STOPPED status from the last thread to terminate

   before it calls ExitThread().

3. Set SERVICE_STATUS.dwWin32ExitCode and/or

   SERVICE_STATUS.dwServiceSpecificExitCode to values that indicate why the

   service is stopping. If you return a value for the

   dwServiceSpecificErrorCode field, then the dwWin32ExitCode field should

   be set to ERROR_SERVICE_SPECIFIC_ERROR.

   The reason for setting these values is that if a service fails its

   operation, but returns an exit code of 0, the following error message is

   returned by default:

      Error 2140: An internal Windows NT error occurred

MORE INFORMATION

When the last service in the process has terminated (you may have multiple

services in the service process), the StartServiceCtrlDispatcher() call

in the main thread returns. The main routine should call ExitProcess()

because all of the services have terminated.

REFERENCES

There is a termination sample in the "Win32 Programmer's Reference," in the

"Services" overview section (58.2.2), "Writing a ServiceMain Function."

This is a simple situation where the service process only consists of one

thread. This thread returns when it is ready to terminate, instead of

calling ExitThread().

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseService


How to Handle FNERR_BUFFERTOOSMALL in Windows 95

PSS ID Number: Q131462

Authored 12-Jun-1995	Last modified 15-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) version 4.0

SUMMARY

When an application uses the Open File common dialog with the

OFN_ALLOWMULTISELECT flag, there is a danger that the buffer passed to the

common dialog in the OPENFILENAME.lpstrFile field will be too small. In

this situation, GetOpenFileName() will return an error value and

CommDlgExtendedError() will return FNERR_BUFFERTOOSMALL.

To work around this problem, watch for the Open or OK button to be pressed

in the dialog hook; then reallocate the buffer if necessary.

This technique works on Windows version 3.1, Windows NT, and Windows 95,

but the implementation details are different when dealing with Windows 95

Explorer-type dialog boxes versus traditional Open and Save common dialog

boxes. This article explains how to do it in Windows 95.

MORE INFORMATION

With the introduction of the new common dialogs for Windows 95, a new way

of handling the FNERR_BUFFERTOOSMALL error was developed. It is still

necessary to watch for the Open button to be pressed and reallocate the

buffer if needed, but the way to watch for the OK is much different.

When you install a hook on the Open File common dialog in Windows 95 using

the OPENFILENAME.lpfnHook member, the dialog you are hooking is a child of

the main Open File dialog. Therefore, to intercept the OK button, you need

to subclass the parent dialog. To do this, you can install the hook

procedure and watch for the CDN_INITDONE notification. The Open File dialog

will send this as part of a WM_NOTIFY message when the initialization for

the dialog is complete. For example:

LRESULT CALLBACK DialogHook(HWND hwnd, UINT uMsg, WPARAM wParam,

                            LPARAM lParam)

{

    static HWND hwndParentDialog;

    LPOFNOTIFY lpofn;

    switch (uMsg)

    {

        case WM_INITDIALOG:

            // You need to use a copy of the OPENFILENAME struct used to

            // create this dialog. You can store a pointer to the

            // OPENFILENAME struct in the ofn.lCustData so you can retrieve

            // it here in the lParam. Once you have it, you need to hang on

            // to it. Using window properties provides a good thread safe

            // solution to using a global variable.

            SetProp(hwnd, "OFN", lParam);

            return (0);

        case WM_NOTIFY:

            // The OFNOTIFY struct is passed in the lParam of this message.

            lpofn = (LPOFNOTIFY) lParam;

            switch (lpofn->hdr.code)

            {

                CDN_INITDONE:

                    // Subclass the parent dialog to watch for the OK

                    // button.

                    hwndParentDialog = GetParent(hwnd);

                    g_lpfnDialogProc =

                            (FARPROC) SetWindowLong(hwndParentDialog,

                                                    DWL_DLGPROC,

                                                    OpenFileSubclassProc);

                    break;

            }

            return (0);

        case WM_DESTROY:

            // Need to clean up the subclassing we did on the dialog.

            SetWindowLong(hwndParentDialog, DWL_DLGPROC, g_lpfnDialogProc);

            // Also need to free the property with the OPENFILENAME struct

            RemoveProp(hwnd, "OFN");

            return (0);

    }

    return (0);

}

Once the parent dialog is subclassed, the program can watch for the actual

Open button. When the program gets the Open button command, it needs to

check to see if the buffer originally allocated is large enough to handle

all the files selected. The CommDlg_OpenSave_GetFilePath() API will return

the length needed. Here is an example of the subclass procedure:

LRESULT CALLBACK OpenFileSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam,

                                      LPARAM lParam)

{

    LPTSTR lpsz;

    WORD   cbLength;

    switch (uMsg)

    {

        case WM_COMMAND:

            switch (LOWORD(wParam))

            {

                case IDOK:

                    // Need to verify the original buffer size is large

                    // enough to handle the files selected. The

                    // CommDlg_OpenSave_GetFilePath() API will return the

                    // length needed for this buffer.

                    cbLength = CommDlg_OpenSave_GetFilePath(hwnd, NULL, 0);

                    // OFN_BUFFER_SIZE is the size of the buffer originally

                    // used in the OPENFILENAME.lpszFile member.

                    if (OFN_BUFFER_SIZE < cbLength)

                    {

                        // The buffer is too small, so allocate a

                        // new buffer.

                        lpsz = (LPTSTR) HeapAlloc(GetProcessHeap(),

                                                  HEAP_ZERO_MEMORY,

                                                  cbLength);

                        if (lpsz)

                        {

                            // The OFN struct is stored in a property of

                            // the dialog window.

                            lpofn = (LPOPENFILENAME) GetProp(hwnd, "OFN");

                            lpofn->lpstrFile = lpsz;

                            lpofn->nMaxFile  = cbLength;

                        }

                    }

                    // Now let the dialog handle the message normally.

                    break;

            }

            break;

    }

    return (CallWindowProc(g_lpfnDialogProc, hwnd, uMsg, wParam, lParam));

}

The dialog should now return without error. Be aware that the buffer

allocated in the subclass procedure needs to be freed once the dialog

returns.

Finally, this technique only works for 32-bit applications that are using

the Explorer-type common dialogs. For 32-bit applications that don't use

the OFN_EXPLORER flag, Windows 95 thunks to the 16-bit common dialog and

the hook function only gets a copy of the OPENFILENAME structure.

Additional reference words: 4.00

KBCategory: kbui kbprg kbcode

KBSubcategory: UsrCmnDlg


How to Ignore WM_MOUSEACTIVATE Message for an MDI Window

PSS ID Number: Q62068

Authored 18-May-1990	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

In order to make an MDI window to become active and have the caret be in

the same position as when the window was last active you need to process

the WM_MOUSEACTIVATE message and return MA_ACTIVATEANDEAT for the first

time. Therefore, you need to set a Boolean flag in the WM_MDIACTIVATE

message so that the return is set only once. The sample code below can be

used to modify the MULTIPAD sample application. Also, the following is

documentation on MA_ACTIVATE* messages, taken from the Windows 3.0 final

SDK README.WRI file:

   WM_MOUSEACTIVATE

   Return Value    The return value specifies whether the window

                   should be activated and whether the mouse event

                   should be discarded. It must be one of the

                   following values:

                   Value                   Meaning

                   -----                   -------

                   MA_ACTIVATE             Activate the window.

                   MA_NOACTIVATE           Do not activate the window.

                   MA_ACTIVATEANDEAT       Activate the window and

                                           discard the mouse event.

SAMPLE CODE

-----------

/* --- multipad.c  MPMDIWndProc section --- */

 case WM_MOUSEACTIVATE:   // added

     if (bEatMessage) {

        bEatMessage = FALSE;

        return (LONG)MA_ACTIVATEANDEAT ;

     }

     /* else break */

     break;

 case WM_MDIACTIVATE:

     /* If we're activating this child, remember it */

     if (wParam){

       hwndActive     = hwnd;

       hwndActiveEdit = (HWND)GetWindowWord (hwnd, GWW_HWNDEDIT);

       bEatMessage = TRUE;      // added

     }

     else{

           hwndActive     = NULL;

           hwndActiveEdit = NULL;

     }

     break;

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrMdi


How to Implement Context-Sensitive Help in Windows 95 Dialogs

PSS ID Number: Q125670

Authored 01-Feb-1995	Last modified 06-Apr-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

SUMMARY

In Windows versions 3.x, applications implement context-sensitive help for

dialog boxes by installing either a message filter hook, or a task-specific

keyboard hook that monitors the WM_KEYDOWN message and responds to F1 key

presses.

Windows 95 makes it easier because it provides a new WM_HELP message that

gets sent each time the user presses the F1 key, giving the application

a chance to bring up help information on the control that has the keyboard

focus or on the dialog box itself. This new WM_HELP message is not limited

to dialog boxes alone, as it gets sent to any window that has keyboard

focus or to the currently active window.

MORE INFORMATION

Windows 95 also provides a new dialog style, DS_CONTEXTHELP that adds a

question mark button to the dialog box's caption bar. This button, when

clicked, changes the cursor to a question mark with a pointer. When the

user clicks any control in the dialog box, Windows 95 sends a WM_HELP

message for that control. The dialog procedure should process the WM_HELP

message as follows:

   // Define an array of dword pairs,

   // where the first of each pair is the control ID,

   // and the second is the context ID for a help topic,

   // which is used in the help file.

   static const DWORD aMenuHelpIDs[] =

   {

      edt1, IDH_EDT1 ,

      lst1, IDH_LST1 ,

      lst2, IDH_LST2 ,

      0,    0

   };

   case WM_HELP:

   {

      LPHELPINFO lphi;

      lphi = (LPHELPINFO)lparam;

      if (lphi->iContextType == HELPINFO_WINDOW)   // must be for a control

      {

         WinHelp (lphi->hItemHandle,

                  "GEN32.HLP",

                  HELP_WM_HELP,

                  (DWORD)(LPVOID)aMenuHelpIDs);

      }

      return TRUE;

   }

Calling WinHelp() with the HELP_WM_HELP parameter as demonstrated above

displays the help topic in a pop-up window.

In addition to the WM_HELP message, Windows 95 provides a new

WM_CONTEXTMENU message that gets sent each time the user right-clicks a

window. Typically this message is processed by displaying a context menu

using the TrackPopupMenu() function. However, this message can be processed

to bring up help information by calling the WinHelp() function to display

the help topic in a pop-up window, as in this example:

   case WM_CONTEXTMENU:

   {

      WinHelp ((HWND)wparam,

               "GEN32.HLP",

                HELP_CONTEXTMENU,

               (DWORD)(LPVOID)aSampleMenuHelpIDs);

      return TRUE;

   }

NOTE: Look at the third parameter (HELP_CONTEXTMENU) passed to WinHelp()

this time. This causes a pop-up menu to come up that displays "What's

This?" text. It then displays the help topic in a pop-up window when the

menu item is selected.

Additional reference words: 4.00

KBCategory: kbprg kbcode

KBSubcategory: UsrDlgs


How to Increase Windows NT System and Desktop Heap Sizes

PSS ID Number: Q125752

Authored 05-Feb-1995	Last modified 06-Feb-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) version 3.5

SUMMARY

Sometimes, it may be necessary to increase the amount of memory that

Windows NT will make available for the system and desktop heaps. This can

be accomplished by editing an entry in the registration database. System

heap items are things like desktops and one-time-allocated items like

system metrics. The items that come out of the desktop heap are items such

as windows, menus, hook structures, queues, and some thread information.

MORE INFORMATION

The entry to be edited is under:

HKEY_LOCAL_MACHINE\

   System\

   CurrentControlSet\

   Control\

   Session Manager\

   SubSystems\

   Windows

Under this entry, you will find a string similar to the following (the

slash (/) is a line continuation charater):

%SystemRoot%\system32\csrss.exe /

   ObjectDirectory=\Windows /

   SharedSection=1024,512 /

   Windows=On /

   SubSystemType=Windows /

   ServerDll=basesrv,1 /

   ServerDll=winsrv:GdiServerDllInitialization,4 /

   ServerDll=winsrv:UserServerDllInitialization,3 /

   ServerDll=winsrv:ConServerDllInitialization,2 /

   ProfileControl=Off /

   MaxRequestThreads=16

By changing the SharedSection values, you can affect the heap sizes. The

first number (1024 as shown above) is the maximum size of the system wide

heap in kilobytes. The second number (512 as shown above) is the maximum

size of the per desktop heap in kilobytes. A desktop value of 512K can

support approximately 2,500 windows.

The memory you allocate needs to be backed up by paging space. It should

not have much effect on performance if you create the same number of items

with different heap sizes. The main effect is overhead in heap management

and initialization.

Additional reference words: 3.50

KBCategory: kbprg

KBSubcategory: UsrWndw


How to Keep a Window Iconic

PSS ID Number: Q66244

Authored 16-Oct-1990	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

Normally, when an application's main window is being represented by an

icon ("iconic"), you can restore it to an open window by

double-clicking the icon or by choosing the Restore option from the

System menu.

Opening the window can be prevented by placing code into the

application that processes the WM_QUERYOPEN message by returning

FALSE.

If it is necessary to perform processing before the iconic window is

opened, the processing should be done in response to the WM_QUERYOPEN

message. After processing is complete the program can return TRUE and

the window will be opened.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrWndw


How to Keep an MDI Window Always on Top

PSS ID Number: Q108315

Authored 08-Dec-1993	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

When creating a multiple document interface (MDI) window, there are no

styles available to have the new window stay on top of the other MDI

windows. Alternatively, two methods are available to achieve this

functionality:

 - Process the WM_WINDOWPOSCHANGED message and call SetWindowPos() to

   change the Z-order of the window.

 - Install a timer for the MDI windows and reset the Z-order of the window

   when processing the WM_TIMER message.

MORE INFORMATION

MDICREATESTRUCT has the field "style", which can be set with the styles for

the new MDI window. Extended styles, such as WS_EX_TOPMOST, are not

available in MDI windows. This field of MDICREATESTRUCT is passed to

CreateWindowEx() in the dwStyle parameter. The dwExStyle field is set to

0L. The two methods shown below cannot be used at the same time in the same

application.

Method 1: Process the WM_WINDOWPOSCHANGED message and call SetWindowPos()

to change the Z-order of the window.

Sample Code

-----------

LRESULT CALLBACK MdiWndProc (HWND hWnd, UINT message, WPARAM wParam,

                    LPARAM lParam)

{

    static HWND hWndAlwaysOnTop = 0;

    switch (message)

     {

     case WM_CREATE :

         if (!hWndAlwaysOnTop)

          {

          SetWindowText (hWnd, "Always On Top Window");

          hWndAlwaysOnTop = hWnd;

          }

            break;

     case WM_WINDOWPOSCHANGED :

         if (hWndAlwaysOnTop)

          {

          WINDOWPOS FAR* pWP = (WINDOWPOS FAR*)lParam;

          if (pWP->hwnd != hWndAlwaysOnTop)

              SetWindowPos (hWndAlwaysOnTop, HWND_TOP, 0, 0, 0, 0,

                      SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);

          }

         break;

     //

     // Other Messages to process here.

     //

     case WM_CLOSE :

         if (hWndAlwaysOnTop == hWnd)

          hWndAlwaysOnTop = NULL;

     default :

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

     }

    return 0L;

}

Method 2: Install a timer for the MDI windows and reset the Z-order of

the window when processing the WM_TIMER message.

Sample Code

-----------

LRESULT CALLBACK MdiWndProc (HWND hWnd, UINT message, WPARAM wParam,

                    LPARAM lParam)

{

    static HWND hWndAlwaysOnTop = 0;

    switch (message)

     {

     case WM_CREATE :

         SetTimer (hWnd, 1, 200, NULL);

         if (!hWndAlwaysOnTop)

          {

          SetWindowText (hWnd, "Always On Top Window");

          hWndAlwaysOnTop = hWnd;

          }

            break;

     case WM_TIMER :

         if (hWndAlwaysOnTop)

          {

          SetWindowPos (hWndAlwaysOnTop, HWND_TOP, 0, 0, 0, 0,

                     SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);

          }

         break;

     case WM_DESTROY:

         KillTimer (hWnd, 1) ;

         break;

     //

     // Other Messages to process here.

     //

     case WM_CLOSE :

         if (hWndAlwaysOnTop == hWnd)

          hWndAlwaysOnTop = NULL;

     default :

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

     }

    return 0L;

}

For additional information on changing the Z-order of child pop-up windows,

please see the following article(s) in the Microsoft Knowledge Base:

   ARTICLE-ID: Q66943

   TITLE     : Determining the Topmost Pop-Up Window

Additional reference words: 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrWndw


How to Look Up a User's Full Name

PSS ID Number: Q119670

Authored 20-Aug-1994	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   versions 3.1 and 3.5

SUMMARY

Windows NT workstations can be organized into a domain, which is a

collection of computers on a Windows NT Advanced Server network. The domain

administrator maintains centralized user and group account information.

MORE INFORMATION

To find the full name of a user if you have the user name and domain name:

1. Convert the user name and domain name to Unicode, if they are not

   already Unicode strings. This is a requirement of the ported LAN

   Manager APIs that are used in the following steps.

2. Look up the name of the domain controller (DC) for the domain name

   by calling NetServerEnum().

3. Look up the user name by calling NetUserGetInfo()

4. Convert the full user name to ANSI, unless the program is expecting

   to work with Unicode strings.

The sample code below is a function that takes a user name and a domain

name as the first two arguments and returns the user's full name in the

third argument.

For information on how to get the current user and domain, please see the

following article in the Microsoft Knowledge Base:

ARTICLE-ID: Q111544

TITLE     : Looking Up the Current User and Domain

Sample Code

-----------

   #include <windows.h>

   #include <lm.h>

   #include <stdio.h>

   /********************************************************************\

   * Function: GetFullName( char *UserName, char *Domain, char *dest ); *

   *                                                                    *

   * Parameters:                                                        *

   *    UserName: the user name                                         *

   *    Domain  : the domain to which the user belongs                  *

   *    dest    : receives the user's full name                         *

   *                                                                    *

   BOOL GetFullName(char *UserName, char *Domain, char *dest)

   {

      WCHAR  wszUserName[256];           // Unicode user name

      WCHAR  wszDomain[256];

      LPBYTE ComputerName;

      struct _SERVER_INFO_100 *si100;   // Server structure

      struct _USER_INFO_2 *ui;          // User structure

      // Convert ASCII user name and domain to Unicode.

      MultiByteToWideChar( CP_ACP, 0, UserName,

         strlen(UserName)+1, wszUserName, sizeof(wszUserName) );

      MultiByteToWideChar( CP_ACP, 0, Domain,

         strlen(Domain)+1, wszDomain, sizeof(wszDomain) );

      // Get the computer name of a DC for the specified domain.

      NetGetDCName( NULL, wszDomain, &ComputerName );

      // Look up the user on the DC.

      if(NetUserGetInfo( (LPWSTR) ComputerName,

         (LPWSTR) &wszUserName, 2, (LPBYTE *) &ui))

      {

         printf( "Error getting user information.\n" );

         return( FALSE );

      }

      // Convert the Unicode full name to ASCII.

      WideCharToMultiByte( CP_ACP, 0, ui->usri2_full_name,

         -1, dest, 256, NULL, NULL );

      return( TRUE );

   }

Additional reference words: 3.10 3.50

KBCategory: kbnetwork kbprg

KBSubcategory: NtwkLmapi


How to Make an Application Display Real Units of Measurement

PSS ID Number: Q127152

Authored 13-Mar-1995	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

Sometimes you need an application to display things in terms of a real unit

of measurement such as an inch or millimeter. When dealing with a printer,

resolution is usually given in dots per inch (DPI), which makes it easy to

convert pixels to real inches. However, on a video display, resolution is

given only in pixels. A given video mode will be some X pixels wide with no

information as to the real dimensions of the display area.

Because there is no way to programmatically determine the real dimensions

of the viewable area on a video display, it is impossible for a program to

determine real output dimensions. Two manual methods for determining real

output dimensions are given in this article.

MORE INFORMATION

When output is destined for a printer, the application can call

GetDeviceCaps() using LOGPIXELSX and LOGPIXELSY to determine dots per real

inch. However, for a video display, LOGPIXELSX and LOGPIXELSY are defined

by the video driver and may vary wildly. These numbers define a logical

inch, which is almost never equal to a real inch.

Applications that need to output real sizes to the video display can use

one of the following two methods for determining output size:

1. The application can ask the user what size monitor is attached. Using

   this value, an application can approximate the actual viewable area, and

   given the resolution of the output (GetDeviceCaps, HORZRES, VERTRES),

   the application can approximate real inches. This solution gives only an

   approximation of a real inch. Several factors can introduce errors into

   this approximation including the size adjustments on digital monitors.

2. The application can ask the user to hold a measuring device to the

   screen and measure a given line. This is the only way to guarantee that

   output on a video display is exactly the expected size, and

   recalibration would be necessary after any adjustment to the monitor.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbgraphic

KBSubcategory: GdiDisplay


How to Minimize Memory Allocations for New TreeView Control

PSS ID Number: Q130697

Authored 25-May-1995	Last modified 30-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

   versions 3.51 and 4.0

SUMMARY

You can use the new TreeView Common Control to display a hierarchical list

of items. This new control is available for Win32-based applications

running under Windows NT or Windows 95. Applications typically use this

control to display a list of items like directories or files on a given

drive. Each node in a TreeView control allocates about 40 bytes. If the

TreeView control displays a lot of items, applications can easily consume

large amounts of memory, which slows down other applications.

Below are some techniques applications can use to minimize memory

allocations for TreeView controls.

MORE INFORMATION

TreeView controls maintain internal data structures for every node added to

the control. This data structure along with image lists associated with

items and text strings for items can drain the physical memory available on

the system.

Applications that need to display thousands of items or nodes in the

TreeView control can be more proficient about memory allocations by doing

the following:

1. When inserting an item into a TreeView control, ensure that the pszText

   member of the TV_ITEM is not the actual string that needs to be

   displayed, but is the value LPSTR_TEXTCALLBACK. If a string pointer is

   passed, the control stores that string internally by allocating memory

   for it. When this flag is specified, the parent window of the control is

   responsible for storing the name (string). The string in most cases can

   be generated dynamically. In this case, the TreeView control sends the

   parent window a TVN_GETDISPINFO notification message when it needs the

   item text for displaying, sorting, or editing and sends a

   TVN_SETDISPINFO notification message when the item text changes.

2. Fill the TreeView nodes on demand. One way to really minimize memory

   usage in a TreeView control is to fill in only the visible nodes. The

   TV_ITEM struct's cChildren member can be put to good use for this

   purpose. This is used as a flag to indicate whether the item has

   associated child items. It is 1 if the item has one or more child items;

   otherwise, it is 0 (zero). When inserting visible items into the

   TreeView control, set this cChildren member to 1 if that node will have

   child items under it. Do not insert the child items. When the user

   clicks the node, the application receives a TVN_ITEMEXPANDING with

   NM_TREEVIEW.action set to TVE_EXPAND. Insert the child items at that

   point. Then when the user clicks the same node again (to collapse the

   node), the applciation receives a TVN_ITEMEXPANDED with

   NM_TREEVIEW.action set to TVE_COLLAPSE. At that time, collapse the node

   and all its child items by calling TreeView_Expand (hWndTrevview, hItem,

   TVE_COLLAPSE|TVE_COLLAPSERESET). This frees up the memory used up by all

   the children or child items.

3. If the application uses different icons for each child item in the

   TreeView control, specify the I_IMAGECALLBACK value for the iImage and

   iSeletedImage members of the TV_ITEM Structure. This way, the control

   doesn't have to store these images for every child item - thereby

   reducing the memory requirements for the control as a whole.

Additional reference words: 4.00 usage user styles

KBCategory: kbprg

KBSubcategory: TreeView


How to Modify Executable Code in Memory

PSS ID Number: Q127904

Authored 21-Mar-1995	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), version 3.5, 3.51,

   and 4.0

Follow the steps in this article to create self-modifying code; that is, to

modify code pages while they are in memory and execute them there.

NOTE: Self-modifying code is not advised, but there are cases where you may

wish to use it.

Step-by-Step Example

--------------------

1. Call VirtualProtect() on the code pages you want to modify, with the

   PAGE_WRITECOPY protection.

2. Modify the code pages.

3. Call VirtualProtect() on the modified code pages, with the PAGE_EXECUTE

   protection.

4. Call FlushInstructionCache().

All four steps are required. The reason for calling FlushInstructionCache()

is to make sure that your changes are executed. As processors get faster,

the instruction caches on the chips get larger. This allows more out of

order prefetching to be done. If you modify your code, but do not call

FlushInstructionCache(), the previous instructions may already be in the

cache and your changes will not be executed.

Additional reference words: 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: BseMm


How to Modify the Width of the Drop Down List in a Combo Box

PSS ID Number: Q131845

Authored 21-Jun-1995	Last modified 23-Jun-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32s version 1.2

 - Microsoft Win32 Software Development KIT (SDK) versions 3.5 and 4.0

SUMMARY

The Windows combo box contains a list box (of the ComboLBox class) within

it. In the standard combo box, this list box has exactly the same width as

the combo box. However, you can make the width of the list box wider or

narrower than the width of the combo box. You may have seen combo box lists

like this in Microsoft Word and Microsoft Excel. This article shows by

example how to subclass a standard combo box class to achieve this

functionality.

MORE INFORMATION

The combo box in Windows is actually a combination of two or more controls;

that's why it's called a "combo" box. For more information about the parts

of a combo box and how they relate to each other, please see the following

article in the Microsoft Knowledge Base:

   ARTICLE-ID: Q65881

   TITLE     : The Parts of a Windows Combo Box and How They Relate

To make the combo box list wider or narrower, you need the handle of the

list box control within the combo box. This task is difficult because the

list box is actually a child of the desktop window (for CBS_DROPDOWN and

CBS_DROPDOWNLIST styles). If it were a child of the ComboBox control,

dropping down the list box would clip it to the parent, and it wouldn't

display.

A combo box receives WM_CTLCOLOR messages for its component controls when

they need to be painted. This allows the combo box to specify a color for

these controls. The HIWORD of the lParam in this message is the type of the

control. In case of the combo box, Windows sends it a WM_CTLCOLOR message

with the HIWORD set to CTLCOLOR_LISTBOX when the list box control needs to

be painted. The LOWORD of the lParam contains the handle of the list box

control.

In 32-bit Windows, the WM_CTLCOLOR message has been replaced with multiple

messages, one for each type of control (WM_CTLCOLORBTN). For more

information about this, please see the following article in the Microsoft

Knowledge Base:

   ARTICLE-ID: Q81707

   TITLE     : WM_CTLCOLOR Processing for Combo Boxes of All Styles

Once you obtain the handle to the list box control window, you can resize

the control by using the MoveWindow API.

The following code sample demonstrates how to do this. This sample assumes

that you have placed the combo box control in a dialog box.

Sample Code

-----------

// Global declarations.

LRESULT CALLBACK NewComboProc (HWND hWnd,   UINT message,   WPARAM

   wParam, LPARAM lParam ); // prototype for the combo box subclass proc

HANDLE hInst;                     // Current app instance

BOOL bFirst;                      // a flag

// Dialog procedure for the dialog containing the combo box.

BOOL __export CALLBACK DialogProc(HWND hDlg, UINT message, WPARAM wParam,

            LPARAM lParam)

{

    FARPROC lpfnNewComboProc;

    switch (message)

    {

    case WM_INITDIALOG:

   bFirst = TRUE;       // set flag here - see below for usage

   // subclass the combo box

   lpfnOldComboProc = (FARPROC ) SetWindowLong (

               GetDlgItem ( hDlg, IDC_COMBO1 ),

               GWL_WNDPROC,

               (LONG)NewComboProc );

   break;

     case WM_DESTROY:

   (FARPROC ) SetWindowLong (    GetDlgItem ( hDlg, IDC_COMBO1 ),

               GWL_WNDPROC,

               (LONG)lpfnOldComboProc );

   break;

     default:

        break;

     }

     return FALSE;

} // end dialog proc

// Combobox subclass proc.

LRESULT CALLBACK NewComboProc (HWND hWnd,   UINT message,   WPARAM

            wParam, LPARAM lParam );

{

   static HWND hwndList;

   static RECT rectList;

#ifdef WIN16

   if (  WM_CTLCOLOR  == message)  // combo controls are to be painted.

#else

   if ( WM_CTLCOLORLISTBOX == message ) // 32 bits has new message.

#endif

   {

      // is this message for the list box control in the combo?

#ifdef WIN16

      if ( CTLCOLOR_LISTBOX==HIWORD (lParam )   ) // need only for 16 bits

      {

#endif

         // Do only the very first time, get the list

         // box handle and the list box rectangle.

         // Note the use of GetWindowRect, as the parent

         // of the list box is the desktop window

         if ( bFirst )

         {

#ifdef WIN16

            hwndList = LOWORD (lParam );

#else

            hwndList = (HWND) lParam ;     // HWND is 32 bits

#endif

            GetWindowRect ( hwndList, &rectList );

                       bFirst = FALSE;

         }

         // Resize listbox window cx by 50 ( use your size here )

         MoveWindow ( hwndList, rectList.left, rectList.top,

         ( rectList.right - rectList.left + 50 ),

         rectList.bottom - rectList.top, TRUE );

#ifdef WIN16

      }

#endif

   }

   // Call original combo box procedure to handle other combo messages.

   return CallWindowProc ( lpfnOldComboProc, hWnd, message,

wParam, lParam  );

}

Additional reference words: 1.20 3.10 3.50 4.00 95

KBCategory: kbprg kbui kbcode

KBSubcategory: usrctl


How to Obtain a Handle to Any Process with SeDebugPrivilege

PSS ID Number: Q131065

Authored 02-Jun-1995	Last modified 06-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   versions 3.1, 3.5, and 3.51

SUMMARY

In Windows NT, you can retrieve a handle to any process in the system by

enabling the SeDebugPrivilege in the calling process. The calling process

can then call the OpenProcess() Win32 API to obtain a handle with

PROCESS_ALL_ACCESS.

MORE INFORMATION

This functionality is provided for system-level debugging purposes. For

debugging non-system processes, it is not necessary to grant or enable this

privilege.

This privilege allows the caller all access to the process, including the

ability to call TerminateProcess(), CreateRemoteThread(),

and other potentially dangerous Win32 APIs on the target process.

Take great care when granting SeDebugPrivilege to users or groups.

Sample Code

-----------

The following source code illustrates how to obtain SeDebugPrivilege

in order to get a handle to a process with PROCESS_ALL_ACCESS. The

sample code then calls TerminateProcess on the resultant process

handle.

/*++

The SeDebugPrivilege allows you to open any process for debugging purposes.

After enabling the privilege, you can open a target process by using

OpenProcess() with PROCESS_ALL_ACCESS.

By default, this privilege is granted only to SYSTEM and the local

Administrators group.

User Manager | Policies | User Rights | Show Advanced User Rights | Debug

Programs can be used to grant or revoke this privilege to arbitrary users

or groups.

WARNING: This privilege allows all access to a process. A malevolent user

could open a system process, create a remote thread in the system process,

and execute code in the system security context. Great care must be used

when giving out this privilege

--*/

#define RTN_OK 0

#define RTN_USAGE 1

#define RTN_ERROR 13

#include <windows.h>

#include <stdio.h>

BOOL SetPrivilege(

    HANDLE hToken,          // token handle

    LPCTSTR Privilege,      // Privilege to enable/disable

    BOOL bEnablePrivilege   // TRUE to enable.  FALSE to disable

    );

void DisplayError(LPTSTR szAPI);

int main(int argc, char *argv[])

{

    HANDLE hProcess;

    HANDLE hToken;

    int dwRetVal=RTN_OK; // assume success from main()

    // show correct usage for kill

    if (argc != 2)

    {

        fprintf(stderr,"Usage: %s [ProcessId]\n", argv[0]);

        return RTN_USAGE;

    }

    if(!OpenProcessToken(

            GetCurrentProcess(),

            TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,

            &hToken

            )) return RTN_ERROR;

    // enable SeDebugPrivilege

    if(!SetPrivilege(hToken, SE_DEBUG_NAME, TRUE))

    {

        DisplayError("SetPrivilege");

        // close token handle

        CloseHandle(hToken);

        // indicate failure

        return RTN_ERROR;

    }

   // open the process

    if((hProcess = OpenProcess(

            PROCESS_ALL_ACCESS,

            FALSE,

            atoi(argv[1]) // PID from commandline

            )) == NULL)

    {

        DisplayError("OpenProcess");

        return RTN_ERROR;

    }

    // disable SeDebugPrivilege

    SetPrivilege(hToken, SE_DEBUG_NAME, FALSE);

    if(!TerminateProcess(hProcess, 0xffffffff))

    {

        DisplayError("TerminateProcess");

        dwRetVal=RTN_ERROR;

    }

    // close handles

    CloseHandle(hToken);

    CloseHandle(hProcess);

    return dwRetVal;

}

BOOL SetPrivilege(

    HANDLE hToken,          // token handle

    LPCTSTR Privilege,      // Privilege to enable/disable

    BOOL bEnablePrivilege   // TRUE to enable.  FALSE to disable

    )

{

    TOKEN_PRIVILEGES tp;

    LUID luid;

    TOKEN_PRIVILEGES tpPrevious;

    DWORD cbPrevious=sizeof(TOKEN_PRIVILEGES);

    if(!LookupPrivilegeValue( NULL, Privilege, &luid )) return FALSE;

    //

    // first pass.  get current privilege setting

    //

    tp.PrivilegeCount           = 1;

    tp.Privileges[0].Luid       = luid;

    tp.Privileges[0].Attributes = 0;

    AdjustTokenPrivileges(

            hToken,

            FALSE,

            &tp,

            sizeof(TOKEN_PRIVILEGES),

            &tpPrevious,

            &cbPrevious

            );

    if (GetLastError() != ERROR_SUCCESS) return FALSE;

    //

    // second pass.  set privilege based on previous setting

    //

    tpPrevious.PrivilegeCount       = 1;

    tpPrevious.Privileges[0].Luid   = luid;

    if(bEnablePrivilege) {

        tpPrevious.Privileges[0].Attributes |= (SE_PRIVILEGE_ENABLED);

    }

    else {

        tpPrevious.Privileges[0].Attributes ^= (SE_PRIVILEGE_ENABLED &

            tpPrevious.Privileges[0].Attributes);

    }

    AdjustTokenPrivileges(

            hToken,

            FALSE,

            &tpPrevious,

            cbPrevious,

            NULL,

            NULL

            );

    if (GetLastError() != ERROR_SUCCESS) return FALSE;

    return TRUE;

}

void DisplayError(

    LPTSTR szAPI    // pointer to failed API name

    )

{

    LPTSTR MessageBuffer;

    DWORD dwBufferLength;

    fprintf(stderr,"%s() error!\n", szAPI);

    if(dwBufferLength=FormatMessage(

                FORMAT_MESSAGE_ALLOCATE_BUFFER |

                FORMAT_MESSAGE_FROM_SYSTEM,

                NULL,

                GetLastError(),

                GetSystemDefaultLangID(),

                (LPTSTR) &MessageBuffer,

                0,

                NULL

                ))

    {

        DWORD dwBytesWritten;

        //

        // Output message string on stderr

        //

        WriteFile(

                GetStdHandle(STD_ERROR_HANDLE),

                MessageBuffer,

                dwBufferLength,

                &dwBytesWritten,

                NULL

                );

        //

        // free the buffer allocated by the system

        //

        LocalFree(MessageBuffer);

    }

}

Additional reference words: 3.10 3.50 3.51 OpenProcess TerminateProcess

KBCategory: kbprg kbcode

KBSubcategory: BseSecurity BseMisc CodeSam


How to Obtain Filename and Path from a Shell Link or Shortcut

PSS ID Number: Q130698

Authored 25-May-1995	Last modified 30-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

   versions 3.51 and 4.0

SUMMARY

The new shell link under Windows 95 (also available for Windows NT after

Windows 95 ships) provides applications and users a way to create shortcuts

or links to objects in the shells namespace. Some applications need to get

the filename and path, given a link or shortcut. The IShellLink OLE

Interface implemented by the shell can be used to obtain this information,

among other things.

MORE INFORMATION

A shell link allows the user or an application to access an oject from

anywhere in the namespace. Links or shortcuts to objects are stored as

binary files. These files contain information such as the path to the

object, working directory, the path of the icon used to display the object,

the description string, and so on.

Given a link or shortcut, applications can use the IShellLink interface and

its functions to obtain all the pertinent information about that object.

The IShellLink interface supports fucntions such as GetPath(),

GetDescription(), Resolve(), GetWorkingDirectory(), and so on.

Code Sample

-----------

The following code shows how to obtain the filename or path and description

of a given link file.

// GetLinkInfo() fills the filename and path buffer

// with relevant information

// hWnd         - calling app's window handle.

//

// lpszLinkName - name of the link file passed into the function.

//

// lpszPath     - the buffer that will receive the filepath name.

//

HRESULT GetLinkInfo( HWND hWnd,

           LPCTSTR lpszLinkName,

           LPSTR lpszPath,

                  LPSTR szDescription)

{

   HRESULT hres;

   IShellLink *psl;

   WIN32_FIND_DATA wfd;

// Assume Failure to start with:

   *lpszPath = 0;

   *lpszDescription = 0;

// Call CoCreateInstance to obtain the IShellLink

// Interface pointer. This call fails if

// CoInitialize is not called, so it is assumed that

// CoInitialize has been called.

   hres = CoCreateInstance( CLSID_ShellLink,

               NULL,

               CLSCTX_INPROC_SERVER,

                            IID_IShellLink,

                                  (LPVOID *)&psl );

   if ( SUCCEEDED( hres ) )

   {

      IPersistFile *ppf;

      bRetVal = TRUE;

// The IShellLink Interface supports the IPersistFile

// interface. Get an interface pointer to it.

      hres = psl->lpVtbl->QueryInterface(psl,

                 IID_IPersistFile,

                 (LPVOID *)&ppf );

      if ( SUCCEEDED( hres ) )

      {

         WORD wsz[MAX_PATH];

//Convert the given link name string to wide character string.

         MultiByteToWideChar( CP_ACP, 0,

                  lpszLinkName,

                  -1, wsz, MAX_PATH );

//Load the file.

         hres = ppf->lpVtbl->Load(ppf, wsz, STGM_READ );

         if ( SUCCEEDED( hres ) )

         {

// Resolve the link by calling the Resolve() interface function.

            hres = psl->lpVtbl->Resolve(psl,  hWnd,

                    SLR_ANY_MATCH |

                    SLR_NO_UI);

            if ( SUCCEEDED( hres ) )

            {

               hres = psl->lpVtbl->GetPath( psl,    lpszPath,

                  MAX_PATH,

                       (WIN32_FIND_DATA*)&wfd,

                                             SLGP_SHORTPATH );

        if(!SUCCEEDED(hres))

      return FALSE;

               hres = psl->lpVtbl->Get(Description(psl,

                    lpszDescription,

                       MAX_PATH );

        if(!SUCCEEDED(hres))

      return FALSE;

            }

         }

         ppf->lpVtbl->Release();

      }

      psl->lpVtbl->Release();

   }

   return hres;

}

Ensure that the interface pointers are released when the application is

finished using them. For a list of other functions that the IShellLink

Interface supports, please see the documentation on the IShellLink

interface.

NOTE: If applications use C++ instead of C, the interface pointer (psl,

ppf) and the lpVtbl variables are implicit.

Additional reference words: 4.00

KBCategory: kbprg kbcode kbole

KBSubcategory: IShellLink


How to Obtain Fonts, ToolTips, and Other Non-Client Metrics

PSS ID Number: Q130764

Authored 25-May-1995	Last modified 22-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) version 4.0

SUMMARY

The SystemParametersInfo() API under Windows 95 has been expanded to

include a new set of FLAGS to set or get system-wide parameters. One such

flag is the SPI_GET/SETNONCLIENTMETRICS flag and the NONCLIENTMETRICS

structure. This flag and the related structure when used with the

SystemsParametersInfo() API can provide applications with a plethora of

information on the non-client metrics system wide.

MORE INFORMATION

Windows 95 provides users with the ability to change the fonts used

(displayed) by menus and message boxes and change the height of caption

bars of windows by simply changing the settings in the Appearance property

sheet. They need only right click the desktop to bring up the Display

properties dialog box; then they can choose the Appearance page. This was

not possible under Windows version 3.1.

Windows 95 applications can programatically change these features with the

help of the SystemParametersInfo() function and the NONCLIENTMETRICS

structure. Windows 95 applications should not randomly change these system

settings unless absolutely necessary because system-wide changes occur.

To obtain the fonts used by message boxes, menus, status bars, and

captions, applications can call SystemParametersInfo() with the

SPI_GETNONCLIENTMETRICS flag, passing the address of the NONCLIENTMETRICS

structure as the third parameter. The system then fills this structure with

all sorts of information. The lfMessageFont, lfMenuFont, lfStatusFont

members of the NONCLIENTMETRICS structure have the font information.

Similarly, applications can change the font used by menus, message boxes,

status bars, and captions by calling SystemParametersInfo() with the

SPI_SETNONCLIENTMETRICS flag. When this flag is spcified, a

NONCLIENTMETRICS structure is filled with the appropriate values if its

address is passed in as the third parameter. Once again, the changes made

this way are reflected system wide, so application designers should use

this flag sparingly.

Additional reference words: 4.00 user controls styles

KBCategory: kbprg

KBSubcategory: UsrSys


How to Obtain Icon Information from an .EXE in Windows 95

PSS ID Number: Q131500

Authored 12-Jun-1995	Last modified 15-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) version 4.0

SUMMARY

SHGetFileInfo is a new API that Windows 95 provides to allow an application

to extract icon information from a particular file. With the introduction

of large (32x32) and small (16x16) icons in Windows 95, SHGetFileInfo

provides this information as well by filling in the appropriate members of

the SHFILEINFO structure.

MORE INFORMATION

In Windows version 3.1, an application can use the ExtractIcon() to

retrieve the handle of an icon associated with a specified executable file,

dynamic link library, or icon file.

Windows 95 provides a new function, SHGetFileInfo(), which, among other

things, provides this icon information when using the SHGFI_ICON flag. When

the function returns, the handle to the icon is returned in the hIcon

member of the SHFILEINFO structure, and the index of the icon within the

system image list is returned in the iIcon member of the same structure.

The code below demonstrates how to retrieve the Gen32 sample's icon and

associates that icon with a dialog box's button:

   HICON  hGen32Icon;

   SHFILEINFO  shfi;

   if (SHGetFileInfo ((LPCSTR)"C:\\MySamplesDir\\Gen32\\Gen32.Exe",

                        0,

                        &shfi,

                        sizeof (SHFILEINFO),

                        SHGFI_ICON))

   {

      hGen32Icon = shfi.hIcon;

      // Note that this button has been defined in the .RC file

      // to be of BS_ICON style

      SendDlgItemMessage (hDlg,

                          IDC_BUTTON,

                          BM_SETIMAGE,

                          (WPARAM)IMAGE_ICON,

                          (LPARAM)(HICON)hGen32Icon);

   }

   else

   {

   // SHGetFileInfo failed...

   }

Windows 95 also introduces the concept of large and small icons associated

with applications where the large icon is displayed when the application

is minimized and the small icon is displayed in the upper-left corner of

the application. This small icon, when clicked, drops down the

application's system menu.

SHGetFileInfo() provides the file's large and small icon information as

well, using the SHGFI_LARGEICON and SHGFI_SMALLICON flags respectively.

SHGFI_LARGEICON returns the handle of the system image list containing the

large icon images, whereas SHGFI_SMALLICON returns that of the system image

list containing the small icon images. These flags, when OR'ed with the

SHGFI_SYSICONINDEX flag, return the icon index within the appropriate

system image list in the iIcon member of the SHFILEINFO struct.

The code sample below demonstrates how to retrieve the small icon

associated with the same GEN32 sample.

   HICON  hGen32Icon;

   HIMAGELIST hSysImageList;

   SHFILEINFO  shfi;

   hSysImageList = SHGetFileInfo

((LPCSTR)"C:\\MySamplesDir\\Gen32\\Gen32.Exe",

                                   0,

                                   &shfi,

                                   sizeof (SHFILEINFO),

                                   SHGFI_SYSICONINDEX | SHGFI_SMALLICON);

   if (hSysImageList)

   {

   hGen32Icon = ImageList_GetIcon (hSysImageList,

                                        shfi.iIcon,

                                        ILD_NORMAL);

   }

   else

   {

   // SHGetFileInfo failed...

   }

Before closing, the application must call DestroyIcon() to free system

resources associated with the icon returned by ImageList_GetIcon().

NOTE: The SHGetFileInfo() API will be supported in the next release of

Windows NT that supports the new shell interface very similar to Windows

95. This API is not supported in Windows NT version 3.51.

Additional reference words: DLL EXE ICO 32 x 32 16 x 16

KBCategory: kbprg kbcode

KBSubcategory: UsrRsc


How To Open Volumes Under Windows 95

PSS ID Number: Q125712

Authored 02-Feb-1995	Last modified 06-Apr-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

SUMMARY

Windows 95 does not support opening disk drives or disk partitions with

CreateFile(), as Windows NT does. Windows 95 also does not support the

DeviceIoControl() IOCTL APIs, as Windows NT does. Instead, low-level disk

access in Windows 95 can be achieved through DeviceIoControl() calls to the

VWIN32 VxD.

MORE INFORMATION

Windows NT supports obtaining a handle to a disk drive or disk partition

by using CreateFile() and specifying the name of the drive or partition

as the filename (e.g. "\\.\PHYSICALDRIVE0" or "\\.\C:"). This handle can

then be used in the DeviceIoControl() Win32 API.

Windows 95 differs in the following ways:

1. Obtaining a disk drive or disk partition handle is not supported.

   The call to CreateFile() will fail, and GetLastError() will return

   error code 2, ERROR_FILE_NOT_FOUND.

2. The DeviceIoControl IOCTL functions (such as IOCTL_DISK_FORMAT_TRACKS)

   are not supported. These IOCTLs require the handle to a disk drive or

   disk partition and thus can't be used.

3. DeviceIoControl() is called using a handle to a VxD rather than a

   handle to a disk drive or disk partition. Obtain a handle to

   VWIN32.VXD by using CreateFile( "\\\\.\\VWIN32", ... ). Use this

   handle in calls to DeviceIoControl() to perform volume locking

   (Int 21h Function 440Dh, Subfunctions 4Ah and 4Bh), and then to

   perform BIOS calls (Int 13h), Absolute Disk Reads/Writes (Int 25h

   and 26h), or MS-DOS IOCTL functions (Int 21h Function 440Dh).

REFERENCES

The chapter "Device I/O Control in Windows 95" describes the procedures for

using DeviceIoControl() in Windows 95, and contains a description of the MS-

DOS IOCTL functions supported by the VWIN32 VxD.

For information on using CreateFile() to obtain disk drive or disk

partition handles under Windows NT, see the description for CreateFile()

in the Microsoft Windows Programmer's Reference, Volume 3.

For a complete list of IOCTLs, see the description of the DeviceIoControl()

function in the Microsoft Windows Programmer's Reference, Volume 3.

Additional reference words: 4.00

KBCategory: kbprg

KBSubcategory: BseFileio


How to Overlay Images Using Image List Controls

PSS ID Number: Q125629

Authored 01-Feb-1995	Last modified 06-Apr-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

SUMMARY

One of the more interesting controls Windows 95 provides as part of its

new common controls is the image list. Image lists provide an easy way

to manage a group of bitmaps and draw them on the screen, without having

to worry about calling CreateCompatibleDC(), SelectObject(), BitBlt(),

StretchBlt(), and so on.

One interesting feature that image lists provide through the

ImageList_Draw() API is the ability to overlay images -- that is, to draw

an image transparently over another image. Calling ImageList_Draw() with

the last parameter set to an index to an overlay mask instructs the image

list to draw an image, and draw the overlay mask on top of it.

MORE INFORMATION

To overlay images correctly using image lists, follow these steps:

1. Create a bitmap that will have the images you want to draw as well as

   the overlay images you want drawn on top of these images.

   For example, say you have a bitmap of four 16x16 images:

    - a green circle.

    - a red circle.

    - a panda.

    - a frog.

2. Create an image list out of the bitmap you've created in step 1 by using

   ImageList_LoadImage() as shown here:

   hImageList = ImageList_LoadImage (hInst,

                                     "MyBitmap",

                                     16,

                                     4,

                                     RGB (255,0,0),

                                     IMAGE_BITMAP,

                                     0);

3. Decide which images you want to specify as overlay masks, and tag them

   as such by using the ImageList_SetOverlayImage() function. The following

   code specifies the panda and the frog (with 0-based index, this comes

   out to image 2 and 3) as overlay masks 1 and 2.

   NOTE: You can only specify up to four overlay masks per image list.

   ImageList_SetOverlayImage (hImageList,

                              2,         // 0-based index to image list

                              1);        // 1-based index to overlay mask.

   ImageList_SetOverlayImage (hImageList,

                              3,       // 0-based index to image list

                              2);      // 1-based index to overlay mask.

4. Draw the image. The following code draws the green circle (or image 0 in

   the example image list). Then it draws the panda (overlay image 1 in the

   example) on top of it.

   ImageList_Draw (hImageList,

                   0,     // 0-based index to imageList of image to draw

                   hDC,   // handle to a DC

                   16, 16 // (x,y) location to draw

                   INDEXTOOVERLAYMASK (1));   // Overlay image #1

Additional reference words: 4.00

KBCategory: kbprg

KBSubcategory: UsrCtl


How to Override Full Drag

PSS ID Number: Q121541

Authored 09-Oct-1994	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.5, 3.51,

   and 4.0

Windows NT version 3.5 introduces full drag, which allows you to see the

entire window moving or resizing instead of seeing just an outline of the

window moving or resizing. You can enable full drag by running the Desktop

Control Panel applet and selecting the Full Drag checkbox.

When you resize a window with full drag enabled, the application will

receive numerous messages indicating that the window is resizing. (You can

verify this with Spy.) If this has undesirable effects on your application,

you will need to override the full drag feature in your application.

When the moving or resizing starts, the application receives this message:

   WM_ENTERSIZEMOVE (0231)

When the moving or resizing finishes, the application receives this

message:

   WM_EXITSIZEMOVE (0232)

The above messages act as a notification that the window is entering and

exiting a sizing or moving operation. If you want, you can use these

notifications to set a flag to prevent the program from handling a WM_PAINT

message during the move or size operation to override full drag.

Additional reference words:  3.50 3.51 4.00 95

KBCategory: kbprg kbtool

KBSubcategory: UsrWndw


How to Pass Large Memory Block Through Win32s Universal Thunk

PSS ID Number: Q126708

Authored 28-Feb-1995	Last modified 03-Mar-1995

The information in this article applies to:

 - Microsoft Win32s version 1.2

SUMMARY

You can pass a memory address to a thunk routine. The pointer address is

translated via the universal thunk (UT). However, the translated pointer

is only guaranteed for 32K. This article describes ways to pass a larger

memory block through the universal thunk.

MORE INFORMATION

GlobalAlloc()

-------------

You can call GlobalAlloc() to allocate a larger memory block on the 32-bit

side of the thunk, copy the data into this memory block, send the handle

to the 16-bit side, and lock the handle on the 16-bit side with

GlobalLock().

VirtualAlloc()

--------------

If you allocate the memory using VirtualAlloc(), it will be aligned on a

64K boundary, so that you can address the entire memory block. HeapAlloc()

allocates large memory blocks using VirtualAlloc() as well. NOTE: You

are still limited to 64K of memory, due to the selector tiling.

Allocate a selector

-------------------

To use this method, get the 32-bit offset used by the Win32-based

application and the selector base for the data selector returned by

GetThreadSelectorEntry(), then calculate the linear address of the memory

block. With this linear address, you can use AllocSelector(),

SetSelectorBase(), and SetSelectorLimit() to access the memory block from

the 16-bit side of the thunk.

NOTE: Sparse memory will cause problems in the general case. Make sure that

the memory range has been not only reserved, but also committed.

Additional reference words: 1.20

KBCategory: kbprg

KBSubcategory: W32s


How To Pass Numbers to a Named Range in Excel through DDE

PSS ID Number: Q45714

Authored 14-Jun-1989	Last modified 12-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

To send an array to Excel via DDE, you must send the array in TEXT,

CSV, or BIFF clipboard format.

For example, if you want to send three numbers for one ROW in CSV

format, use 1,2,3 (where each number is separated by a comma). If you

want to place three numbers in one COLUMN in CSV format, place the

CR/LF (Od 0a) (carriage return/line feed) characters after each number

in the set.

If you would like to send the numbers via the TEXT format separated into

columns, place the CR/LF characters between each number in the set. To

organize the numbers into one row, place a TAB (09) character between

each number.

In order to send an array of data into a named range, use the following

steps:

1. Highlight the appropriate cells in Excel

2. Set up your typical hot link from Excel, for example:

   =Service|Topic!Item

3. Instead of hitting Enter after typing the above, hit Ctrl+Shift+Enter.

   This will cause your data to come in as an array, rather than as a

   single item.

   NOTE: To do the reverse of this, that is, for a client application to

   POKE data to Excel, the client will have to specify an item name of say,

   "R1C1:R1C2" to poke an array of data to the range R1C1..R1C2.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrDde


How to Perform Auto Repeat as Media Player Does

PSS ID Number: Q124185

Authored 21-Dec-1994	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

 - Microsoft Win32 SDK, versions 3.1, 3.5, 3.51, and 4.0

 - Microsoft Video for Windows Development Kit (DK) version 1.1

The Media Player (MPLAYER.EXE) included with Microsoft Windows and

Microsoft Windows NT (MPLAY32.EXE) provides an auto-repeat option that

automatically repeats the playback of a multimedia file. You can

incorporate this functionality into your application on Digital Video

devices by using an extension to the standard Media Control Interface (MCI)

commands as follows:

 - When calling the mciSendString() function, add the word "repeat" to the

   play command, as in this example:

      mciSendString("play mov notify repeat", NULL, 0, hWnd);

 - When calling the mciSendCommand() function, set the play flag

   MCI_DGV_PLAY_REPEAT. For example, to add auto repeat functionality to

   the MOVPLAY sample included with the Video for Windows DK, add the

   following line to the playMovie() function in MOVPLAY1.C, right before

   the mciSendCommand() function call:

      dwFlags |= MCI_DGV_PLAY_REPEAT;

"Digital Video Command Set for the Media Control Interface" documents the

Digital Video MCI extensions. It is available on the Microsoft Developer

Network (MSDN) CD. Look for it in the Specifications section of the CD

contents, under "Digital Video MCI Specification." You can also search the

CD using the word MCI_DGV_PLAY_REPEAT for more information about that flag.

Additional reference words: 3.10 3.50 4.00 95  Video for Windows MCIAVI

MCI_PLAY AVI loop continuous play

KBCategory: kbmm kbprg kbdocerr

KBSubcategory: MMVideo


How to Port a 16-bit DLL to a Win32 DLL

PSS ID Number: Q125688

Authored 01-Feb-1995	Last modified 06-Apr-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

SUMMARY

There are several significant differences between Win16 DLLs and Win32

DLLs. These differences require more than just a simple recompilation to

turn your Win16 DLL into a Win32 DLL. In this article we will show you how

to port your Win16 DLL to a Win32 DLL.

MORE INFORMATION

The first major difference is that the Win32 DLL entry point is called with

every process attach and detach. Secondly, you must account for the fact

that processes can be multithreaded and as such your DLL entry point will

be called with thread attach and detach messages. You need to ensure that

your DLL is "thread-safe" by using multithreaded libraries and mutual

exclusion for functions in your DLL that would otherwise cause data

corruption when preempted and reentered. This requires that you use Win32

synchronization methods to guard critical resources. Finally, each Win32

process gets its own copy of the Win32 DLL's data.

Step One for Porting Your DLL

-----------------------------

The first step in porting a DLL from 16-bit Windows to 32-bit Windows is

moving code from your LibMain (or LibEntry) and _WEP (or WEP) to the new

DLL initialization function. The new DLL initialization function is called

DllMain. You might code your DllMain like this:

BOOL WINAPI DllMain (HANDLE hModule, DWORD fdwReason, LPVOID lpReserved)

{

   switch (fdwReason)

   {

      case DLL_PROCESS_ATTACH:

         /* Code from LibMain inserted here.  Return TRUE to keep the

            DLL loaded or return FALSE to fail loading the DLL.

            You may have to modify the code in your original LibMain to

            account for the fact that it may be called more than once.

            You will get one DLL_PROCESS_ATTACH for each process that

            loads the DLL. This is different from LibMain which gets

            called only once when the DLL is loaded. The only time this

            is critical is when you are using shared data sections.

            If you are using shared data sections for statically

            allocated data, you will need to be careful to initialize it

            only once. Check your code carefully.

            Certain one-time initializations may now need to be done for

            each process that attaches. You may also not need code from

            your original LibMain because the operating system may now

            be doing it for you.

         */

         break;

      case DLL_THREAD_ATTACH:

         /* Called each time a thread is created in a process that has

            already loaded (attached to) this DLL. Does not get called

            for each thread that exists in the process before it loaded

            the DLL.

            Do thread-specific initialization here.

         */

         break;

      case DLL_THREAD_DETACH:

         /* Same as above, but called when a thread in the process

            exits.

            Do thread-specific cleanup here.

         */

         break;

      case DLL_PROCESS_DETACH:

         /* Code from _WEP inserted here.  This code may (like the

            LibMain) not be necessary.  Check to make certain that the

            operating system is not doing it for you.

         */

         break;

   }

   /* The return value is only used for DLL_PROCESS_ATTACH; all other

      conditions are ignored.  */

   return TRUE;   // successful DLL_PROCESS_ATTACH

}

DllMain Called with Flags

-------------------------

There are several conditions where DllMain is called with the

DLL_PROCESS_ATTACH, DLL_PROCESS_DETACH, DLL_THREAD_ATTACH, or

DLL_THREAD_DETACH flags.

The DLL_PROCESS_ATTACH flag is sent when a DLL is loaded into the address

space of a process. This occurs in both situations where the DLL is loaded

with LoadLibrary, or implicitly during application load. When the DLL is

implicitly loaded, DllMain is executed with DLL_PROCESS_ATTACH before the

processes enter WinMain. When the DLL is explicitly loaded, DllMain is

executed with DLL_PROCESS_ATTACH before LoadLibrary returns.

The DLL_PROCESS_DETACH flag is sent when a process cleanly unloads the DLL

from its address space. This occurs during a call to FreeLibrary, or if the

DLL is implicitly loaded, a clean process exit. When a DLL is detaching

from a process, the individual threads of the process do not call the

DLL_THREAD_DETACH flag.

The DLL_THREAD_ATTACH flag is sent when a new thread is being created in a

process already attached to the DLL. Threads in existence before the

process attached to a DLL will not send the DLL_THREAD_ATTACH flag. The

first thread to attach to the DLL does not send the DLL_THREAD_ATTACH flag;

it sends the DLL_PROCESS_ATTACH flag instead.

The DLL_THREAD_DETACH flag is sent when a thread is exiting cleanly. There

is a situation when DllMain may be called when the thread did not first

send the DLL_THREAD_ATTACH flag. This can happen if there are other threads

still running and the original thread exits cleanly. The thread originally

called DllMain with the DLL_PROCESS_ATTACH flag and later calls DllMain

with the DLL_THREAD_DETACH flag. You may also have DllMain being called

with DLL_THREAD_DETACH if a thread exits but was running in the process

before the call to LoadLibrary.

Situations Where DllMain is Not Called or Is Bypassed

-----------------------------------------------------

DllMain may not be called at all in dire situations where a thread or

process was killed by a call to TerminateThread or TerminateProcess. These

functions bypass calling DllMain. They are recommended only as a last

resort. Data owned by the thread or process is at risk of loss because the

process or thread could not shut itself down properly.

DllMain may be bypassed intentionally by a process if it calls

DisableThreadLibraryCalls. This function (available with Windows 95 and

Windows NT versions 3.5 and later) disables all DLL_THREAD_ATTACH and

DLL_THREAD_DETACH notifications for a DLL. This enables a process to reduce

its code size and working set. For more information on this function, see

the SDK documentation on DisableThreadLibraryCalls.

Step Two for Porting Your DLL

-----------------------------

The second step of porting your DLL involves changing functions that were

declared with __export and included in the module definition (.DEF) file

EXPORTS section. The proper export declaration for the Microsoft Visual C++

32-bit compiler and linker is __declspec(dllexport). This declaration

should be used when prototyping and declaring functions. You do not have to

explicitly declare an exported function in the DEF file for the proper LIB

and EXP files to be created; __declspec(dllexport) will do this for you.

Here's an example of an exported function:

// prototype in DLL is necessary

__declspec(dllexport) DWORD WINAPI DLLFunc1(LPSTR);

// function

__declspec(dllexport) DWORD WINAPI DLLFunc1(LPSTR lpszIn)

{

   DWORD dwRes;

   /* DLL function logic */

   return dwRes;

}

To include the function in an application, prototype the above function in

the application with the __declspec(dllimport) modifier.

__declspec(dllimport) is not necessary, but does improve the speed of your

code that implements the function call. Here's an example:

   __declspec(dllimport) DWORD WINAPI DLLFunc1(LPSTR);

Then, link the DLL's import library (.LIB) file with the application

makefile or project.

Some sections of your DEF file will be ignored by the 32-bit linker because

of architectural differences between Win16 and Win32. You may still use the

EXPORTS section of your DEF if you wish to include ordinals for exported

functions, or to rename exported functions. See your linker documentation

for more information about what is acceptable in a DEF file for a Win32

DLL. Users of other 32-bit compilers and linkers will have to refer to

their documentation for more information on exporting functions.

Applications that link to your DLL may be multithreaded. This possibility

means that you should always build your Win32 DLL as multithreaded to

support preemption and reentrancy. If you use runtime library functions in

your DLL, they may be preempted and reentered. That would cause problems

for a normal runtime library. If you use C runtime or some other runtime

library, you should use a multithreaded version of the runtime library.

Microsoft Visual C++ users should link with the /MT option and include

LIBCMT.LIB. This will include the multithreaded C runtime library.

Optionally, you can select the Multithreaded Run-time Library option in the

project settings in the Visual Workbench. If you are using another runtime

library and cannot get a multithreaded version of the library, you must

protect calls to the library from reentrancy using a mutex or critical

section synchronization object. Information later in this article discusses

this issue.

Other Design Issues You Should Consider

---------------------------------------

One of the most significant changes to DLLs in 32-bit Windows operating

systems is that each process executes in its own private address space.

This means that a DLL cannot directly share dynamically-allocated memory

between processes. Addresses are 32-bit offsets in a process's address

space. Passing them between processes is possible, but won't work as in

Win16 because each process has its own address space. In another process,

this pointer may address unknown data, or invalid memory space.

"DS != SS" issues common to 16-bit DLLs no longer apply. A Win32 process

executes in its own private address space and there is no segmentation of

this address space. In a Win32 DLL, all functions are called using the

calling thread's stack and all pointers are 32-bit linear addresses. In a

Win32 process or DLL, a FAR pointer is the same as a near pointer. In other

words, a pointer is just a pointer.

If you must share data, you can specify certain global variables to be

shared among processes by using a shared data section in the DLL. For more

information on shared data sections, please search the Microsoft Knowledge

Base using the following words:

   #pragma data_seg

or:

   sections share dll

You can also use a file-mapping object to share memory by sharing the

system page file. This will allow two different processes to share dynamic

memory. For more information on file mapping objects, please search the

Microsoft Knowledge Base using these words:

   shared memory

Another significant change in the behavior of Win32 DLLs from Win16 DLLs is

the inclusion of synchronization. The Win32 API provides synchronization

objects that allow the programmer to implement correct synchronization. You

should be aware that your 32-bit DLL may be preempted and called again from

a different thread in the process. For example, if a thread executing a DLL

function accesses global data and is preempted and another function

modifies the same data, the original thread will resume but will be using

modified data. You'll need to use synchronization objects to resolve this

situation.

Your Win32 DLL may also be preempted by a thread in a different process.

This situation becomes important if the functions use shared data sections

or file mappings. You will need to examine the functions in a DLL to

determine if this will cause problems. If so, you will have to control

access to data or sections of code that are sensitive to this problem.

Mutexes and critical sections are well suited for DLL synchronization. For

more information on synchronization, please search the Microsoft Knowledge

Base using these words:

   synchronization objects

For additional information, please search the Microsoft Knowledge Base

using these words:

   Win32 DLL

Additional reference words: 4.00 LibEntry LibMain Port WEP _WEP Win32

KBCategory: kbprg

KBSubcategory: BseDll


How to Program Keyboard Interface for Owner-Draw Menus

PSS ID Number: Q121623

Authored 12-Oct-1994	Last modified 15-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

You can implement the keyboard interface for owner-draw menus, which allow

a user to access a menu by typing a menu mnemonic, by processing the

WM_MENUCHAR message.

MORE INFORMATION

Menus other than owner-draw menus can specify a menu mnemonic by inserting

an underscore next to a character in the menu string so that the user can

select the menu by typing ALT+<menu mnemonic character>. But in owner-draw

menus, you cannot specify a menu mnemonic in this manner. Instead, you must

process the WM_MENUCHAR message to provide owner-draw menus with menu

mnemnoics.

WM_MENUCHAR is sent when the user types a menu mnemonic that does not

match any of the predefined mnemonics of the current menu. wParam

specifies the ASCII character that corresponds to the key the user

pressed together with the ALT key. The low-order word of lParam

specifies the type of the selected menu and contains:

 - MF_POPUP if the cuurent menu is a popup menu.

 - MF_SYSMENU if the menu is the system menu.

The high-order word of lParam contains the menu handle of the current menu.

The window with the owner-draw menus can process WM_MENUCHAR as follows:

   case WM_MENUCHAR:

      nIndex = Determine index of menu item to be selected from

               character that was typed and handle of the current

               menu.

      return MAKELRESULT(nIndex, 2);

The 2 in the high-order word of the return value informs Windows that

the low-order word of the return value contains the zero-based index

of the menu item to be selected by Windows.

Windows 95 defines four new constants that correspond to the possible

return values from the WM_MENUCHAR message:

Constant    Value   Meaning

---------------------------

MNC_IGNORE  0       Informs Windows that it should discard the character

                    the user pressed and create a short beep on the system

                    speaker.

MNC_CLOSE   1       Informs Windows that it should close the active menu.

MNC_EXECUTE 2       Informs Windows that it should choose the item

                    specified in the low-order word of the return value.

                    The owner window receives a WM_COMMAND message.

MNC_SELECT  3       Informs Windows that it should select the item

                    specified in the low-order word of the return value.

Additional reference words: 3.10 3.50 4.00

KBCategory: kbprg kbui

KBSubcategory: UsrMen


How to Remove Win32s

PSS ID Number: Q120486

Authored 12-Sep-1994	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32s versions 1.0, 1.1, 1.15, and 1.2

SUMMARY

To remove Win32s:

1. Remove the following line from the [386Enh] section in the

   SYSTEM.INI file:

      device=<WINDOWS>\<SYSTEM>\win32s\w32s.386

   where <WINDOWS> and <SYSTEM> are where the Windows and System

   directories are, respectively.

2. Modify the following line from the [BOOT] section in the

   SYSTEM.INI file:

      drivers=mmsystem.dll winmm16.dll

   to the following (remove winmm16.dll):

      drivers=mmsystem.dll

3. Delete the following files from the <WINDOWS>\<SYSTEM> subdirectory or

   from the SYSTEM directory in network installations:

      W32SYS.DLL

      WIN32S16.DLL

      WIN32S.INI

4. Delete all the files in the <WINDOWS>\<SYSTEM>\WIN32S subdirectory

   or the <SYSTEM>\WIN32S subdirectory in network installations.

   Then delete subdirectory itself.

5. Restart Windows.

NOTE: <WINDOWS> refers to the windows installation directory. On a

networked Windows installation, the system directory may be located on a

remote share. If you are only removing Win32s from your machine, then you

do not need to remove the shared files (in <SYSTEM> and <SYSTEM>\WIN32S).

Before removing these files from the network share, make sure that all

users that use Win32s have removed the references to Win32s from the

SYSTEM.INI file.

MORE INFORMATION

This information can be found in the Win32s Programmer's Reference

help file.

Additional reference words: 1.00 1.10 1.15 1.20

KBCategory: kbsetup kbprg

KBSubcategory: W32s


How to Right-Justify Menu Items in Windows 95

PSS ID Number: Q125675

Authored 01-Feb-1995	Last modified 06-Apr-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

SUMMARY

In Windows 95, right-justify (right-align) a menu item by using the

MFT_RIGHTJUSTIFY type in MENUITEMINFOSTRUCTURE.

MORE INFORMATION

There is a new menu type in Windows 95, MFT_RIGHTJUSTIFY type, which you

can use to right justify a menu item. The Windows version 3.1 method of

prefixing the string with "\a" or "\b" will no longer work.

To right justify a menu item in Windows 95:

1. Get the menu handle of the original menu.

2. Get the original menu item information stored in the MENUITEMINFO

   structure.

3. Change the menu item type to include MFT_RIGHTJUSTIFY by or'ing

   the original value with MFT_RIGHTJUSTIFY.

4. Set the new menu item information.

For example, to create a right-justified menu item, add the following code

to WM_CREATE:

   HMENU hMenu;

   MENUITEMINFO  mii;

   char szBuffer [80];

   hMenu = GetMenu (hwnd);

   // Get the original value of mii.fType first

   // and OR that with MFT_RIGHTJUSTIFY

   mii.cbSize = sizeof (MENUITEMINFO);

   mii.fMask = MIIM_TYPE;

   mii.dwTypeData= szBuffer;

   mii.cch   = sizeof (szBuffer);

   GetMenuItemInfo(hMenu, 1, TRUE, &mii);

   // OR in MFT_RIGHTJUSTIFY type

   mii.fMask = MIIM_TYPE;

   mii.fType  = mii.fType | MFT_RIGHTJUSTIFY;

   // Right justify the specified item and all those following it

   SetMenuItemInfo(hMenu, 1, TRUE,   &mii);

   return 0;

REFERENCES

For additional information on right justifying menus in Windows 3.1,

please see the following article in the Microsoft Knowledge Base:

ARTICLE-ID: Q67063

TITLE     : Inserting Right Justified Text in a Menu in Windows

Additional reference words: 4.00 alignment align

KBCategory: kbprg

KBSubcategory: UsrMen


How to Search for Win32 Articles by KB Subcategory

PSS ID Number: Q115696

Authored 01-Jun-1994	Last modified 21-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   versions 3.1 and 3.5

SUMMARY

The Microsoft Knowledge Base (KB) is categorized by using keywords. This

article lists the category and subcategory keywords specific to articles in

the Microsoft Win32 Software Development Kit (SDK) for Windows NT

Collection.

MORE INFORMATION

Microsoft Win32 SDK KBSubcategory Major and Minor Keywords

----------------------------------------------------------

Each KB article in the Win32 SDK collection may contain one or more product-

specific subcategory keywords (called KBSubcategory keywords) that places

the article in an appropriate Win32 SDK category. Each KBSubcategory word

is composed of the concatenation of a major topic keyword and a minor topic

keyword. For example, you can find all the BASE DLL articles by using

BseDll as the keyword when you query the Microsoft Knowledge Base.

Use the asterisk (*) wildcard to find articles that fall into the general

categories or into an intermediate subcategory. For example, to find all

the articles that apply to GDI issues, query on Gdi*. An article usually

has only one subcategory keyword, but it may have more.

Here are the topics and the corresponding KBSubcategory keywords. The minor

topics are in the indented list under each major topic.

Major Topic

      Minor Topic                  KBSubcategory Keyword

---------------------------------------------------------------------------

BASE (Bse)

      Comm APIs                    BseCommapi

      Console                      BseCon

      DLLs                         BseDll

      Error Debug                  BseErrdebug

      Exception Handling           BseExcept

      File I/O                     BseFileio

      Floating Point               BseFltpt

      IPC                          BseIpc

      Base Misc                    BseMisc

      Memory Management            BseMm

      Procedure Threads            BseProcThrd

      Security                     BseSecurity

      Service                      BseService

      Syncronization               BseSync

GDI (Gdi)

      Bitmaps                      GdiBmp

      Cursors/Icons                GdiCurico

      DCs                          GdiDc

      Display                      GdiDisplay

      Drawing                      GdiDrw

      Fonts                        GdiFnt

      Metafiles                    GdiMeta

      GDI Misc                     GdiMisc

      OpenGL                       GdiOpenGL

      Palettes/Colors              GdiPal

      Brushes/Pens                 GdiPnbr

      Printing                     GdiPrn

      Screen Saver                 GdiScrsav

      TrueType                     GdiTt

MULTIMEDIA

      CD-ROM                       MMCDROM

      MM File I/O Services         MMIO

      Joystick                     MMJoy

      MediaView                    MMMediaView

      Midi                         MMMidi

      Sound Card Mixer Control     MMMixer

      Multimedia Timers            MMTimer

      Video for Windows (VFW)      MMVideo

      Waveform Audio               MMWave

      Miscellaneous                MMMisc

MISC

      International Issues         WIntlDev

      Setup/Install                Setins

      Subsystems                   SubSys

NETWORKING (Ntwk)

      Networking Misc              NtwkMisc

      LAN Manager APIs             NtwkLmapi

      NetBIOS                      NtwkNetbios

      RAS APIs                     NtwkRAS

      RPC                          NtwkRpc

      SNMP                         NtwkSnmp

      TC/PIP                       NtwkTcpip

      WNet APIs                    NtwkWinnet

      Windows Sockets              NtwkWinsock

PEN                                Wpen*

      Video Drivers                WpenVideoDrv

      Pen Drivers                  WpenTbltDrv

      OAK                          WpenOemOak

      Recognizer                   WpenRcgnzr

      Dictionary                   WpenDict

      Visual Basic                 WpenVB

      Training                     WpenTrain

      RC                           WpenRc

      RCRESULT                     WpenRcResult

      SYG                          WpenSyg

      SYV                          WpenSyv

      SYC                          WpenSyc

      SYE                          WpenSye

      Ink                          WpenInk

      Setup                        WpenSetup

      Pen applets                  WpenApps

      control panel apps           WpenCpl

      PEN UI                       WpenPenUI

      Gestures                     WpenGestures

      Keyboard                     WpenKeyboard

      Pen Misc                     WpenMisc

TAPI

      Telephony API                Tapi

TOOLS (Tls)

      Dialog Editor                TlsDlg

      Font Editor                  TlsFnt

      Headers                      TlsHdr

      Help Compiler                TlsHlp

      Image Editor                 TlsImg

      MEP                          TlsMep

      Misc                         TlsMisc

      MS Setup                     TlsMss

      Porting Tool                 TlsPort

      Profiler                     TlsPrf

      Resource Compiler            TlsRc

      Spy                          TlsSpy

      WinDbg                       TlsWindbg

USER (Usr)

      Clipboard                    UsrClp

      Classes                      UsrCls

      Common Dialogs               UsrCmnDlg

      Controls                     UsrCtl

      DDE                          UsrDde

      Dialog/Message Boxes         UsrDlgs

      Drag & Drop                  UsrDnd

      Extension Libraries          UsrExt

      Hooks                        UsrHks

      Input-Mouse/Keyboard         UsrInp

      Localization/Intntl.         UsrLoc

      MDI                          UsrMdi

      Menus/Accelerators           UsrMen

      User Misc                    UsrMisc

      Network DDE                  UsrNetDde

      NLS                          UsrNls

      Owner Draw                   UsrOwn

      Resources                    UsrRes

      New Shell issues             UsrShell

      Strict                       UsrStrict

      Window Manager               UsrWndw

WIN32S

      Win32s                       W32s

Product-Specific Keywords

-------------------------

You can use the KBSubcategory keywords to organize Win32 SDK articles or to

search for specific groups of Win32 SDK articles. For information about

KBSubcategory keywords for other Microsoft developer products, please query

the Microsoft Knowledge Base using these keywords:

   dskbguide and kbkeyword

KB-Wide Keywords

----------------

Each article in the Win32 SDK collection also contains at least one

generic, KB-wide category keyword (called a KBCategory keyword). The

KBCategory keywords are standard throughout the Microsoft Knowledge Base,

appearing in all KB articles, regardless of product. You can use the

KBCategory keywords to organize all KB articles or to search for articles

across several Microsoft products. For more information about these

KBCategory keywords, please see the following article in the Microsoft

Knowledge Base:

   ARTICLE-ID: Q94671

   TITLE     : Categories and Keywords for All Knowledge Base Articles

Additional reference words: 3.10 3.50 kbkeyword kbsubcats dskbguide

KBCategory: kbref

KBSubcatgory:


How to Select a Listview Item Programmatically in Windows 95

PSS ID Number: Q131284

Authored 07-Jun-1995	Last modified 10-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.51, 4.0

 - Microsoft Win32s version 1.3

SUMMARY

Selecting a listview item in Windows 95 is not as easy as selecting a list

box item was in Windows version 3.1. To select a list box item in Windows

version 3.1, an application sends an LB_SETCURSEL or LB_SETSEL to a single-

or multiple-selection list box respectively. To select a listview item in

Windows 95, an application sends an LVM_SETITEMSTATE message or calls the

ListView_SetItemState() macro.

MORE INFORMATION

An application can force a selection of a listview item. You might want the

application to do this when a user clicks a column other than the first

column of a listview of multiple subitems or columns.

Currently, a listview item is selected only when the user clicks the first

column of that item. However, you many want the application to select the

item regardless of which column in the listview is clicked.

Windows 95 does not provide a separate message or function to set the

current selection in a listview. Instead, it defines item states or LVIS_*

values that determine the listview item's appearance and functionality.

LVIS_FOCUSED and LVIS_SELECTED in particular are the states that determine

a listview item's selection state.

To select a listview item programmatically, an application sets the

listview item's state as follows:

   ListView_SetItemState (hWndListView,         // handle to listview

                          iWhichItem,         // index to listview item

                          LVIS_FOCUSED | LVIS_SELECTED, // item state

                          0x000F);                      // mask

Note that the last parameter passed to this macro is a mask specifying

which bits are about to change. LVIS_FOCUSED and LVIS_SELECTED are defined

in <commctrl.h> as 0x0001 and 0x0002 respectively, so you need to set the

last four bits of the mask.

The same principle applies to selecting a treeview item programmatically.

The only difference is that an application sends a TVM_SETITEM message or

calls the TreeView_SetItem() macro.

Because listviews allow multiple selection by default, you can program an

application to select multiple items by simulating a CTRL keydown (or SHIFT

keydown event) prior to setting the item state. For example, the following

code simulates the pressing of the CTRL key:

   BYTE  pbKeyState [256];

   GetKeyboardState ((LPBYTE)&pbKeyState);

   pbKeyState[VK_CONTROL] |= 0x80;

   SetKeyboardState ((LPBYTE)&pbKeyState);

Note that if an application simulates a keypress, it must also be

responsible for releasing it by resetting the appropriate bit. For example,

the following code simulates the release of a CTRL key:

   BYTE  pbKeyState [256];

   GetKeyboardState ((LPBYTE)&pbKeyState);

   pbKeyState[VK_CONTROL] = 0;

   SetKeyboardState ((LPBYTE)&pbKeyState);

Similarly, retrieving the currently selected item in a listview control

in Windows 95 is not as easy as sending an LB_GETCURSEL message to a

listbox control was in Windows version 3.1.

For listviews, call the ListView_GetNextItem() function with the

LVNI_SELECTED flag specified:

   iCurSel = ListView_GetNextItem (ghwndLV, -1, LVNI_SELECTED);

For treeviews, retrieve the currently selected item by calling the

TreeView_GetNextItem() function  with the TVGN_CARET flag

specified or by calling the TreeView_GetSelection() macro directly:

   iCurSel = TreeView_GetNextItem (ghwndTV, NULL, TVGN_CARET);

      or

   iCurSel = TreeView_GetSelection (ghwndTV);

Additional reference words: 4.00 1.30

KBCategory: kbprg kbcode

KBSubcategory: UsrCtl


How to Set Foreground/Background Responsiveness in Code

PSS ID Number: Q125660

Authored 01-Feb-1995	Last modified 03-Feb-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) version 3.5

SUMMARY

In Windows NT version 3.5, you can set foreground/background responsiveness

by using the System Control Panel in Program Manager. Chose Tasking, then

select one of the following through the dialog that is displayed:

 - Best Foreground Application Response Time.

 - Foreground Application More Responsive than Background.

 - Foreground and Background Applications Equally Responsive.

This article describes how to achieve the same thing by using code in a

program. It also explains how to override this setting by using code in a

program.

MORE INFORMATION

You can use the Registry APIs to set foreground/background responsiveness.

The following registry key allows you to specify the priority to give to

the application running in the foreground:

   HKEY_LOCAL_MACHINE\SYSTEM

      CurrentControlSet\

      Control\

      PriorityControl\

      Win32PrioritySeparation

The following values are supported:

   Value    Meaning

   ----------------

   0        Foreground and background applications equally responsive

   1        Foreground application more responsive than background

   2        Best foreground application response time

These values correspond to the choices offered in the Tasking dialog

described in the "Summary" section of this article.

To override the setting from your application, use SetPriorityClass() to

change your application's priority class and SetThreadPriority() to set

the priority for a given thread.

NOTE: The thread priority together with the priority class for the process

determine the thread's base priority.

Additional reference words: 3.50

KBCategory: kbprg

KBSubcategory: BseProcThrd


How to Set the Current Normal Vector in an OpenGL Application

PSS ID Number: Q131130

Authored 04-Jun-1995	Last modified 07-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.5

SUMMARY

In a Microsoft Win32 OpenGL application, it is common practice to construct

objects with the glBegin function followed by several calls to glVertex.

For example, to create a flat polygon in three-dimensional space, you could

write this code:

   glBegin(GL_POLYGON);

   glVertex3f(.....);

   glVertex3f(.....);

   glVertex3f(.....);

   .  .  .

   .  .  .

   glEnd();

Now, if you want to implement a light source or multiple light sources in

your OpenGL application, it is important that you include a call to the

glNormal function between the calls to glBegin and glEnd so that the normal

vector can be used by OpenGL when calculating the color to use when filling

the polygon.

You can perform a vector cross product on two vectors to obtain a third

vector that is perpendicular to the plane containing the two vectors. Using

a vector cross product, you can calculate the vector normal to the polygon

and use that value in your call to glNormal.

MORE INFORMATION

Using cross product math on two vectors of a polygon, you can obtain a

vector that is perpendicular to the polygon. Two sides of a polygon

describe two vectors in the plane of the polygon. With those two vectors,

you can calculate a vector that is perpendicular to the polygon. The length

of the normal vector calculated will not be unit length, and the normal

vector needs to be unit length. Therefore, you need to call

glEnable(GL_NORMALIZE) when you initialize your OpenGL application, so that

normal vectors specified with glNormal are scaled to unit length after

transformation.

Code Sample

-----------

You can use the following function to calculate a normal vector for a

polygon. You need to give it three points of the polygon and the points

should be given in clock-wise order when you are facing the front of the

polygon:

//***********************************************************************

// Function: CalculateVectorNormal

//

// Purpose: Given three points of a 3D plane, this function calculates

//          the normal vector of that plane.

//

// Parameters:

//     fVert1[]   == array for 1st point (3 elements are x, y, and z).

//     fVert2[]   == array for 2nd point (3 elements are x, y, and z).

//     fVert3[]   == array for 3rd point (3 elements are x, y, and z).

//

// Returns:

//     fNormalX   == X vector for the normal vector

//     fNormalY   == Y vector for the normal vector

//     fNormalZ   == Z vector for the normal vector

//

// Comments:

//

// History:  Date       Author        Reason

//           3/22/95     GGB           Created

//*************************************************************************

GLvoid CalculateVectorNormal(GLfloat fVert1[], GLfloat fVert2[],

                             GLfloat fVert3[], GLfloat *fNormalX,

                             GLfloat *fNormalY, GLfloat *fNormalZ)

    {

    GLfloat Qx, Qy, Qz, Px, Py, Pz;

    Qx = fVert2[0]-fVert1[0];

    Qy = fVert2[1]-fVert1[1];

    Qz = fVert2[2]-fVert1[2];

    Px = fVert3[0]-fVert1[0];

    Py = fVert3[1]-fVert1[1];

    Pz = fVert3[2]-fVert1[2];

    *fNormalX = Py*Qz - Pz*Qy;

    *fNormalY = Pz*Qx - Px*Qz;

    *fNormalZ = Px*Qy - Py*Qx;

}

Code to Call and Use the CalculateVectorNormal Function

-------------------------------------------------------

Here is an example of how you might call and use the function:

   glBegin(GL_POLYGON);

   glVertex3fv(fVert1);

   glVertex3fv(fVert2);

   glVertex3fv(fVert3);

   glVertex3fv(fVert4);

   // Calculate the vector normal coming out of the 3D polygon.

   CalculateVectorNormal(fVert1, fVert2, fVert3, &fNormalX,

                         &fNormalY, &fNormalZ);

   // Set the normal vector for the polygon

   glNormal3f(fNormalX, fNormalY, fNormalZ);

   glEnd();

Additional reference words: 3.50 graphics

KBCategory: kbprg kbcode

KBSubcategory: GdiOpenGL


How to Set Up and Run the RNR Sample Included in the Win32

PSS ID Number: Q131505

Authored 13-Jun-1995	Last modified 14-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.5, 3.51

SUMMARY

This article explains how to set up and operate the Service Registration

and Resolution (RNR) sample over the TCP and SPX network protocols. The RNR

sample comes with the Microsoft Win32 (SDK) versions 3.5 and 3.51. It

illustrates the use of the service registration and resolution APIs.

MORE INFORMATION

How to Set Up the RNR Sample

----------------------------

Run rnrsetup /ADD on each client and on the server to call the SetService

API with SERVICE_ADD_TYPE. This call stores the service name type, its

associated GUID, and relevant addressing information for the specified name

spaces in the registry path:

   \HKEY_LOCAL_MACHINE

     \CurrentControlSet

       \Control

         \ServiceProvider

           \ServiceTypes

This information is then retrieved by GetTypeByName() and

GetAddressByName() calls respectively to identify the server's address.

How to Operate the RNR Sample

-----------------------------

1. Start rnrsrv on one machine. After setting listening ports on the

   available protocols, the RNR server executes the SetService() call with

   the SERVICE_REGISTER flag to register the network service with the

   specified name spaces. For example, it enables advertising the

   EchoExample service name on the SAP protocol.

2. On the other machine, start rnrclnt using the following syntax:

   rnrclnt /?

   Usage: rnrclnt [/name:SVCNAME] [/type:TYPENAME] [/size:N]

             [/count:N]  [/rcvbuf:N] [/sndbuf:N]

    - TYPENAME is initially passed to GetTypeByName() call to return

      the GUID value. The GUID value and SVCNAME is then passed to

      GetAddressByName() to return the address of the server that

      the client can connect to. TYPENAME is defined as EchoExample

      for the RNR sample.

    - SVCNAME specifies which EchoExample server to connect to. If

      SVCNAME is specified as the server name in the Internet domain,

      the TCP protocol will be used. If SVCNAME is specified as

      EchoServer (the RNR service name advertised on SAP), the SPX

      protocol will be used.

    - The other parameters to the rnrclnt have appropriate default

      values and are self explanatory.

Additional reference words: 3.50 3.51

KBCategory: kbprg kbnetwork

KBSubcategory: NtwkWinsock


How to Shade Images to Look Like Windows 95 Active Icon

PSS ID Number: Q128786

Authored 10-Apr-1995	Last modified 23-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.5 and 4.0

SUMMARY

This article shows by example how to display an image or an icon in a

shaded state, as Windows 95 does for the active icon.

MORE INFORMATION

Step-by-Step Procedure

----------------------

To obtain the shaded look for your image or icon, follow these six steps:

1. Create a compatible DC and bitmap.

2. Create a monochrome pattern brush with every other pixel on.

3. Fill the memory image with the pattern.

4. BitBlt the source image over the pattern using SRCAND so that only the

   'on' destination pixels are transferred.

5. Color the destination with the pattern, using the highlight color for

   the 'off' pixels and using black for the 'on' pixels.

6. Copy the filtered original from the memory DC to the destination using

   SRCPAINT so that only the 'on' pixels are transferred.

This results in the destination having the original image with every other

pixel colored with the highlight color.

Sample Code

-----------

The following function implements these six steps to shade a rectangular

area on a device context:

// ShadeRect

// hDC    : the DC on which the area is to be shaded

// lpRect : the coordinates within which to shade

BOOL ShadeRect( HDC hDC, LPRECT lpRect )

{

   COLORREF  crHighlightColor, crOldBkColor, crOldTextColor;

   HBRUSH    hBrush, hOldBrush;

   HBITMAP   hBitmap, hBrushBitmap, hOldMemBitmap;

   int       OldBkMode, nWidth, nHeight;

   HDC       hMemDC;

   RECT      rcRect = { 0, 0, 0, 0};

   // The bitmap bits are for a monochrome "every-other-pixel"

   //     bitmap (for a pattern brush)

   WORD      Bits[8] = { 0x0055, 0x00aa, 0x0055, 0x00aa,

                         0x0055, 0x00aa, 0x0055, 0x00aa };

   // The Width and Height of the target area

   nWidth = lpRect->right - lpRect->left + 1;

   nHeight = lpRect->bottom - lpRect->top + 1;

   // Need a pattern bitmap

   hBrushBitmap = CreateBitmap( 8, 8, 1, 1, &Bits );

   // Need to store the original image

   hBitmap = CreateCompatibleBitmap( hDC, nWidth, nHeight );

   // Need a memory DC to work in

   hMemDC = CreateCompatibleDC( hDC );

   // Create the pattern brush

   hBrush = CreatePatternBrush( hBrushBitmap );

   // Has anything failed so far? If so, abort!

   if( (hBrushBitmap==NULL) || (hBitmap==NULL) ||

       (hMemDC==NULL) || (hBrush==NULL) )

   {

      if( hBrushBitmap != NULL ) DeleteObject(hBrushBitmap);

      if( hBitmap != NULL ) DeleteObject( hBitmap );

      if( hMemDC != NULL ) DeleteDC( hMemDC );

      if( hBrush != NULL ) DeleteObject( hBrush );

      return FALSE;

   }

   // Select the bitmap into the memory DC

   hOldMemBitmap = SelectObject( hMemDC, hBitmap );

   // How wide/tall is the original?

   rcRect.right = nWidth;

   rcRect.bottom = nHeight;

   // Lay down the pattern in the memory DC

   FillRect( hMemDC, &rcRect, hBrush );

   // Fill in the non-color pixels with the original image

   BitBlt( hMemDC, 0, 0, nWidth, nHeight, hDC,

   lpRect->left, lpRect->top, SRCAND );

   // For the "Shutdown" look, use black or gray here instead

   crHighlightColor = GetSysColor( COLOR_HIGHLIGHT );

   // Set the color scheme

   crOldTextColor = SetTextColor( hDC, crHighlightColor );

   crOldBkColor = SetBkColor( hDC, RGB(0,0,0) );

   SetBkMode( hDC, OPAQUE );

   // Select the pattern brush

   hOldBrush = SelectObject( hDC, hBrush );

   // Fill in the color pixels, and set the others to black

   FillRect( hDC, lpRect, hBrush );

   // Fill in the black ones with the original image

   BitBlt( hDC, lpRect->left, lpRect->top, nWidth, nHeight,

           hMemDC, 0, 0, SRCPAINT );

   // Restore target DC settings

   SetBkMode( hDC, OldBkMode );

   SetBkColor( hDC, crOldBkColor );

   SetTextColor( hDC, crOldTextColor );

   // Clean up

   SelectObject( hMemDC, hOldMemBitmap );

   DeleteObject( hBitmap );

   DeleteDC( hMemDC );

   DeleteObject( hBrushBitmap );

   SelectObject( hDC, hOldBrush );

   DeleteObject( hBrush );

   return TRUE;

}

Additional reference words: 3.50 4.00 hatch darken shadow

KBCategory: kbgraphic kbcode

KBSubcategory: GdiMisc


How to Share Data Between Different Mappings of a DLL

PSS ID Number: Q125677

Authored 01-Feb-1995	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

SUMMARY

Under certain circumstances, 32-bit DLLs might have to share data with

other 32-bit DLLs loaded by a different application or with different

mappings of the same DLL. Because 32-bit DLLs are mapped into the the

calling process's address space, which is private, sharing data with other

DLLs mapped into the address spaces of different applications involves

creating shared data section(s) or using memory mapped files. This article

discusses the former -- creating shared data sections by using the #pragma

statement. Typically, system-wide hooks installed in a DLL need to share

some common data among different mappings.

MORE INFORMATION

Each Win32-based application runs in its own private address space. If a 32-

bit application installs a system-wide hook with the hook callback function

in a DLL, this DLL is mapped into the address space of every application

for which the hook event occured.

Every application that the DLL gets mapped into, gets its own set of

variables (data). Often there will be a scenario where hook callback

functions mapped into different application or process address spaces need

to share some data variables -- such as HHOOK or a Window Handle -- among

all mappings of the DLL.

Because each application's address space is private, DLLs with hook

callback functions mapped into one application's address spaces cannot

share data (variables) with other hook callback functions mapped into a

different application's address space unless a shared data SECTION exists

in the DLL.

Every 32-bit DLL (or EXE) is composed of a collection of sections. Each

section name begins with a period. The section of interest in this article

is the data section. These sections can have one of the following

attributes: READ, WRITE, SHARED, and EXECUTE.

DLLs that need to share data among different mappings can use the #pragma

pre-processor command in the DLL source file to create a shared data

section that contains the data to be shared.

The following sample code shows by example how to define a named-data

section (.sdata) in a DLL.

Sample Code

-----------

#pragma data_seg(".sdata")

int iSharedVar = 0;

#pragma data_seg()

The first line directs the compiler to place all the data declared in this

section into the .sdata data segment. Therefore, the iSharedVar variable is

stored in the MYSEC segment. By default, data is not shared. Note that you

must initialize all data in the named section. The data_seg pragma applies

only to initialized data. The third line, #pragma data_seg(), resets

allocation to the default data section.

If one application makes any changes to variables in the shared data

section, all mappings of this DLL will reflect the same changes, so you

need to be carefule when dealing with shared data in applications or DLLs.

You must also tell the linker that the variables in the section you defined

are to be shared by modifying your .DEF file to include a SECTIONS section

or by specifying /SECTION:.sdata, RWS in your link line. Here's an example

SECTIONS section:

   SECTIONS

   .sdata   READ WRITE SHARED

In the case of a typical hook DLL, the HHOOK, HINSTDLL, and other variables

can go into the shared data section.

Additional reference words: 4.00 95

KBCategory: kbprg

KBSubcategory: BseMisc


How to Simulate Changing the Font in a Message Box

PSS ID Number: Q68586

Authored 22-Jan-1991	Last modified 16-May-1995

-

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK), versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

-

SUMMARY

To simulate changing the font in a message box, create a dialog box that

uses the desired font. Specify the style and contents of the dialog box to

reflect the style of the desired message box. The application can also draw

a system icon in the dialog box.

MORE INFORMATION

The message box is a unique object in Windows. Its handle is not available

to an application; therefore, it cannot be modified. An application can

simulate a message box with a different font by creating a dialog box that

looks like a message box.

To change the font in a dialog box, use the optional statement FONT in the

dialog statement of the resource script (.RC) file. For example, resource

file statements for a dialog box displaying an error in Courier point size

12 would be as follows:

   FontError DIALOG  45, 17, 143, 46

   CAPTION "Font Error"

   FONT 12, "Courier"

   STYLE WS_CAPTION | WS_SYSMENU | DS_MODALFRAME

   BEGIN

       CTEXT "Please select the right font", -1, 0, 7, 143, 9

       DEFPUSHBUTTON "OK"  IDOK,   56, 25,  32, 14, WS_GROUP

   END

To center the dialog box in the screen, use GetWindowRect() to retrieve the

dimensions of the screen and MoveWindow() to place the dialog box

appropriately. The following code demonstrates this procedure:

   case WM_INITDIALOG:

       GetWindowRect(hDlg, &rc);

       x = GetSystemMetrics(SM_CXSCREEN);

       y = GetSystemMetrics(SM_CYSCREEN);

       MoveWindow (hDlg,

          (x - (rc.right - rc.left)) >> 1,  /* x position */

          (y - (rc.bottom - rc.top)) >> 1,  /* y position */

          rc.right - rc.left,               /* x size */

          rc.bottom - rc.top,               /* y size */

          TRUE);                            /* paint the window */

       return TRUE;

To display a system icon in the dialog box, call the DrawIcon() function

during the processing of a WM_PAINT message. After drawing the desired

icon, the dialog procedure passes control back to the dialog manager by

returning FALSE. The code to paint the exclamation point icon (used in

warning messages) is as follows:

   case WM_PAINT:

       hIcon = LoadIcon(NULL, IDI_EXCLAMATION);

       hDC = GetDC(hDlg);

       DrawIcon(hDC, 20, 40, hIcon);

       ReleaseDC(hDlg, hDC);

       return FALSE;

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: UsrCtl


How to Spawn a Console App and Redirect Standard Handles

PSS ID Number: Q126628

Authored 27-Feb-1995	Last modified 22-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.5, 3.51,

   and 4.0

This article discusses spawning a console application with CreateProcess()

and redirecting its output. The standard handles are controlled with the

STARTUPINFO fields hStdInput, hStdOutput, and hStdError.

In Windows NT version 3.1, if a windowed application spawned a console

application, you could:

 - Redirect none of its standard handles (don't use STARTF_USESTDHANDLES).

   -or-

 - Redirect all of its standard handles (use STARTF_USESTDHANDLES).

For example, if you redirected hStdInput and hStdOutput, but left hStdError

as 0 or INVALID_HANDLE_VALUE, the console application would fail if it

tried to write to stderr. This is not a problem for a console application

spawning another console application.

In Windows NT version 3.5 and later and in Windows 95, if you set any of

these fields to INVALID_HANDLE_VALUE, Windows NT will assign the default

value to that handle in the console application, rather than leaving it an

invalid value. Therefore, if you set STARTF_USESTDHANDLES, but fail to set

one of the handle fields, this will not cause a problem for the console

application. You can now redirect standard input, but not standard output,

and so forth.

Additional reference words: 3.50 4.00

KBCategory: kbprg

KBSubcategory: BseProcThrd


How to Specify a Full Path in the ExecProgram Macro

PSS ID Number: Q86477

Authored 07-Jul-1992	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

 - Microsoft Win32 SDK, versions 3.51 and 4.0

SUMMARY

Windows help files (.HLP files) can be written such that selecting a

designated topic executes a Windows-based application. This is done with

the ExecProgram() macro. If the desired application does not reside in the

same directory as the .HLP file, a full path to the .EXE must be

specified. An invalid path produces an error.

SYMPTOMS

Attempting to execute an application with an invalid path causes

Windows to display the following Help message box:

   Unable to Run Specified File.

CAUSE

A common mistake is to incorrectly specify the subdirectory

delimiters in the path description. This is not a problem with the

Windows Help Compiler.

MORE INFORMATION

The Windows Help Compiler can recognize escape sequences expressed

using the backslash (\) character. When using the ExecProgram() macro,

four backslashes (\\\\) separate each directory in a full path

description:

   ExecProgram( "c:\\\\winapps\\\\excel\\\\excel", 0 )

With HC31.EXE version 3.10.505 and HCW.EXE version 4.0, you would use only

two backslashes:

   ExecProgram( "c:\\winapps\\excel\\excel", 0 )

Additional reference words: 3.00 3.10 4.00 95

KBCategory: kbtool

KBSubcategory: TlsHlp


How to Specify Filenames/Paths in Viewer/WinHelp Commands

PSS ID Number: Q120251

Authored 07-Sep-1994	Last modified 23-Jun-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

Both WinHelp and Viewer have commands such as JumpId() that take a filename

as a parameter. Depending on the circumstances under which such commands

are called, the number of backslashes (\) included in the filename as part

of the path may have to be doubled for the command to work correctly. For

example, if JumpId() is called from a HotSpot, you need to use two

backslashes to separate the subdirectory names as in this example:

   JumpId("C:\\MYAPP\\HLPFILE\\MYHLP.HLP","topicx")

But if JumpId() is used as the command associated with a menu item, you

need to use four backslashes to separate the subdirectory names within the

JumpId command, which is itself part of an InsertItem() command. For

example:

   InsertItem("MNU_FILE","my_id","Jump",

      "JumpId('C:\\\\MYAPP\\\\HLPFILE\\\\MY HLP.HLP','topicx')",0)

To avoid having to modify the filename parameter depending on how the

function is called, Microsoft recommends that you use a single forward

slash (/) to separate subdirectory names within the filename. For example:

   JumpId("C:/MYAPP/HLPFILE/MYHLP.HLP","topicx")

A single forward slash will work regardless of how the command is called.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbtool

KBSubcategory: TlsHlp


How to Specify Shared and Nonshared Data in a DLL

PSS ID Number: Q89817

Authored 30-Sep-1992	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

To have both shared and nonshared data in a dynamic-link library (DLL)

which is built with a 32-bit Microsoft C compiler, you need to use the

#pragma data_seg directive to set up a new named section. You then must

specify the correct sharing attributes for this new named data section in

your .DEF file.

The system will try to load the shared memory block created by #pragma

data_seg at the same address in each process. However, if the block cannot

be loaded into the same memory address, the system allocates a new block of

memory for that process and the memory is not shared. No run time warnings

are given when this happens. Using memory-mapped files backed by pagefile

(named shared memory) is a safer option than using #pragma data_seg,

because the APIs will return an error when the mapping fails.

MORE INFORMATION

Below is a sample of how to define a named data section in your DLL. The

first line directs the compiler to include all the data declared in this

section in the .MYSEC data segment. This means that the iSharedVar variable

would be considered part of the .MYSEC data segment. By default, data will

be nonshared.

Note that you must initialize all data in your named section. The data_seg

pragma only applies to initialized data.

The third line, "#pragma data_seg()", directs the compiler to reset

allocation to the default data section.

   #pragma data_seg(".MYSEC")

   int iSharedVar = 0;

   #pragma data_seg()

Below is a sample of the .DEF file that supports the shared and nonshared

segments. This definition will set the default section .MYSEC to be shared.

The default data section is by default non-shared, so any data not in

section .MYSEC will be non-shared.

   LIBRARY MyDll

   SECTIONS

     .MYSEC READ WRITE SHARED

   EXPORTS

    ...

NOTE: All section names must begin with a period character ('.') and

must not be longer than 8 characters, including the period character.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: BseDll


How to Start an Application at Boot Time Under Windows 95

PSS ID Number: Q125714

Authored 02-Feb-1995	Last modified 06-Apr-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

SUMMARY

Windows NT supports a Win32-based application type known as a Service. A

Service may be started at boot time, automatically, by a user with the

Service Control Manager facility or by Win32-based applications that use

the service-related Win32 APIs. The Service Control subsystem and the

associated Win32 APIs are not supported in Windows 95. In place of

services, Windows 95 has two registry keys that will allow users to run

applications before a user logs in when the system first starts up.

MORE INFORMATION

Microsoft recognizes the value that Services and the Service Control

manager have, therefore, we have implemented a smaller version of the

Service Control Manager so that applications can run before a user logs in.

This is known as MPREXE.EXE. At boot time, MPREXE checks two new registry

keys: "RunServices" and "RunServicesOnce".

   HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion

      RunServices  [key]

         bubba95=service.exe /params [string value]

      ...

      RunServicesOnce  [key]

      ...

The value names are arbitrary. The value data is the command line passed to

CreateProcess(). Values under the key RunServicesOnce are deleted after the

application is launched. Because these applications are started before the

user logs onto the system, the user has not been validated and the

applications cannot assume that they have particular networking permissions

enabled. Window 95, unlike Windows NT, only has one security context for

the entire system. Therefore, don't assume that any application that MPREXE

starts has access to a particular network resource because a particular

user has access to this network resource.

Applications started by the RunServices and RunServicesOnce keys will be

closed when the user selects "Close all programs and log on as a different

user" from the Shutdown dialog on the Start Menu. To keep itself from being

closed in this manner, a Win32-based application needs to call

RegisterServiceProcess(). A Win32-based application may also call

RegisterServiceProcess to keep other processes from closing when the user

logs out.

RegisterServiceProcess is implemented only in Windows 95, and is documented

in the online help (WIN32.HLP).

Additional reference words: 3.95 4.00

KBCategory: kbprg

KBSubcategory: BseService


How to Stop a Journal Playback

PSS ID Number: Q98486

Authored 05-May-1993	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0, 3.1,

   and 4.0

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

To stop a "journal playback" when a specified key is pressed, the

filter function must determine whether the key was pressed and then

call the UnhookWindowsHookEx function to remove the WH_JOURNALPLAYBACK

hook.

MORE INFORMATION

To determine the state of a specified key, the filter function must

call the GetAsyncKeyState function when the nCode parameter equals

HC_SKIP. The HC_SKIP hook code notifies the WH_JOURNALPLAYBACK filter

function that Windows is done processing the current event.

The GetAsyncKeyState function determines whether a key is up or down

at the time the function is called, and whether the key was pressed

after a previous call to the GetAsyncKeyState function. If the most

significant bit of the return value is set, the key is down; if the

least significant bit is set, the key was pressed after a preceding

GetAsyncKeyState call.

If the filter function calls the GetAsyncKeyState function after the

specified key was pressed and released, then the most significant bit

will not be set to reflect a key-down. Thus, a test to check whether

the specified key is down fails. Therefore, the least significant bit

of the return value must be checked to determine whether the specified

key was pressed after a preceding call to GetAsyncKeyState function.

Using this technique of checking the least significant bit requires a

call to the GetAsyncKeyState function before setting the

WH_JOURNALPLAYBACK hook. For example:

// When setting the journal playback hook.

   .

   .

   .

   // Reset the lease significant bit.

   GetAsyncKeyState( VK_CANCEL );

   // Set a system-wide journal playback hook.

   g_hJP = SetWindowsHookEx( WH_JOURNALPLAYBACK,

            FilterFunc,

            g_hInstDLLModule,

            NULL );

   .

   .

   .

// Inside the filter function

   .

   .

   .

   if ( nCode == HC_SKIP )

       if ( GetAsyncKeyState( VK_CANCEL) )

           UnhookWindowsHookEx( g_hJP );

   .

   .

   .

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrHks


How to Subclass a Window in Windows 95

PSS ID Number: Q125680

Authored 01-Feb-1995	Last modified 10-Apr-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

SUMMARY

While subclassing windows within the same application in Windows 95 is

unchanged from Windows version 3.1, subclassing windows belonging to other

applications is somewhat more complicated in Windows 95. This article

explains the process.

MORE INFORMATION

For a 16-bit application, subclassing methods are the same as they were in

Windows version 3.1. However, Windows 95 performs some behind-the-scenes

magic to make it possible for a 16-bit window to subclass a 32-bit window.

Usually, a subclass consists of saving one window procedure and

substituting another in its place. However, this could present a problem

when a 16-bit application tries to call a 32-bit window procedure. Windows

95 works around this potential problem by providing 32-bit windows with a

16-bit window procedure. All 32-bit windows will have the same selector for

their wndProcs that references code in KRNL386.EXE where the 16-bit

wndProcs for all 32-bit windows are stored. Eventually, each of these

16-bit wndProcs will jump to the real 32-bit window procedure.

Subclassing windows belonging to another process, either 16-bit or 32-bit,

from a 32-bit process or application works as it does in Windows NT. The

difficulty is that each 32-bit process has its own private address space.

Hence, a window procedure's address in one process is not valid in another.

To get a window procedure from one process into another, you need to inject

the subclass procedure code into the other process's address space. There

are a number of ways to do this.

Three Ways to Inject Code Into Another Process's Address Space

--------------------------------------------------------------

You can use the registry, hooks, or remote threads and the

WriteProcessMemory() API to inject code into another process's address

space.

If you use the registry, the code that needs to be injected should reside

in a DLL. By either running REGEDIT.EXE or using the registry APIs, add the

\HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\AppInit_DLLs key to the

registry if it does not exist. Set its value to a string containing the

DLL's pathname. This key may contain more than one DLL pathname separated

by single spaces. This has the effect, once the machine is restarted, of

loading the library with DLL_PROCESS_ATTACH into every process at its

creation time. While this method is very easy, it also has several

disadvantages. For example, the computer must be restarted before it takes

effect, and the DLL will last the lifetime of the process.

You can also use hooks to inject code into another process's address space.

When a window hooks another thread belonging to a different process, the

system maps the DLL containing the hook procedure into the address space of

the hooked thread. Windows will map the entire DLL, not just the hook

procedure. So to subclass a window in another process, install a

WH_GETMESSAGE hook or another such hook on the thread that owns the window

to be subclassed. In the DLL that contains the hook procedure, include the

subclass window procedure. In the hook procedure, call SetWindowLong() to

enact the subclass. It is important to leave the hook in place until the

subclass is no longer needed, so the DLL remains in the target window's

address space. When the subclass is removed, the hook would be unhooked,

thus unmapping the DLL.

A third way to inject a DLL into another address space involves the use of

remote threads and the WriteProcessMemory() API. It is more flexible and

significantly more complicated than the previously mentioned methods, and

is described in the following reference.

REFERENCES

"Load Your 32-bit DLL into Another Process's Address Space Using

INJLIB" by Jeffrey Richter, MSJ May 1994.

Additional reference words: 4.00

KBCategory: kbprg

KBSubcategory: UsrWndw


How to Support Language Independent Strings in Event Logging

PSS ID Number: Q125661

Authored 01-Feb-1995	Last modified 07-Mar-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

   versions 3.1 and 3.5

SUMMARY

Insertion strings in the event log entries are language-independent.

Instead of using string literals as the insertion string, use "%%n" as the

insertion string.

MORE INFORMATION

When the event viewer sees "%%n", it looks up the ParameterMessageFile

value in the registry, under the source of the event, as in this example:

   HKEY_LOCAL_MACHINE\SYSTEM\

      CurrentControlSet\

      Services\

      EventLog\

      Security\

      ...

   -or-

   HKEY_LOCAL_MACHINE\SYSTEM\

      CurrentControlSet\

      Services\

      EventLog\

      System\

      Service Control Manager

It then calls the LoadLibrary() function of the ParameterMessageFile. Then

it calls FormatMessage() using "n" as the ID.

For example, suppose an event log entry has the source "Service Control

Manager" and the description is "Failed to start the service due

to the following error: %%245."

In the registry, you find:

   HKEY_LOCAL_MACHINE\SYSTEM\

      CurrentControlSet\

      Services\

      EventLog\

      System\

      Service Control Manager

         EventMessageFile...

         ParameterMessageFile REG_SZ  kernel32.dll

         TypesSupported...

         ...

Therefore, you need to follow these steps:

1. Use LoadLibrary() with KERNEL32.DLL.

2. Call FormatMessage() using the module handle obtained in step 1 and a

   string ID of 245.

3. Replace %%245 in the description with the string obtained in step 2.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseMisc


How to Toggle the NUM LOCK, CAPS LOCK, and SCROLL LOCK Keys

PSS ID Number: Q127190

Authored 14-Mar-1995	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.5, 3.51,

   and 4.0

SUMMARY

The documentation for SetKeyboardState() correctly says that you cannot

use this API to toggle the NUM LOCK, CAPS LOCK, and SCROLL LOCK keys.

You can use keybd_event() to toggle the NUM LOCK, CAPS LOCK, and SCROLL

LOCK keys.

MORE INFORMATION

The following sample program turns the NUM LOCK light on if it is off. The

SetNumLock function defined here simulates pressing the NUM LOCK key, using

keybd_event() with a virtual key of VK_NUMLOCK. It takes a boolean value

that indicates whether the light should be turned off (FALSE) or on (TRUE).

The same technique can be used for the CAPS LOCK key (VK_CAPITAL) and the

SCROLL LOCK key (VK_SCROLL).

Sample Code

-----------

/* Compile options needed:

*/

#include <windows.h>

void SetNumLock( BOOL bState )

{

   BYTE keyState[256];

   GetKeyboardState((LPBYTE)&keyState);

   if( (bState && !(keyState[VK_NUMLOCK] & 1)) ||

       (!bState && (keyState[VK_NUMLOCK] & 1)) )

   {

   // Simulate a key press

      keybd_event( VK_NUMLOCK,

                   0x45,

                   KEYEVENTF_EXTENDEDKEY | 0,

                   0 );

   // Simulate a key release

      keybd_event( VK_NUMLOCK,

                   0x45,

                   KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP,

                   0);

   }

}

void main()

{

   SetNumLock( TRUE );

}

Additional reference words: 3.50 4.00 95

KBCategory: kbprg kbcode

KBSubcategory: UsrInp


How to Update the List of Files in the Common Dialogs

PSS ID Number: Q109696

Authored 06-Jan-1994	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK, version 3.5

SUMMARY

Sometimes it is necessary to update the list of files, without terminating

the dialog box, when using the File Open or Save As common dialog box. This

can be done by simulating a double-click on the list box of directories.

Although the message can be posted from any application, a hook procedure

should be used to post the message to the dialog box window.

MORE INFORMATION

The common dialog box functions that update the list of files and

directories are internal to the common dialog boxes and are not accessible

by applications using the common dialog box routines. The functions are

invoked and the list boxes are updated only when the user double-clicks a

list box.

Sample Code

-----------

The following code uses the Cancel button of the common dialog boxes to

update the list boxes:

BOOL CALLBACK __export FileOpenHook (HWND hDlg, UINT message,

                         WPARAM wParam, LPARAM lParam)

{

   switch (message)

   {

      case WM_COMMAND:

         switch(wParam)

         {

         // This simulates a double-click on the list of directories,

         // effectively forcing the common dialogs to re-read the current

         // directory of files and to refresh the list of files.

            case IDCANCEL :

               PostMessage( hDlg, WM_COMMAND, lst2,

                            MAKELPARAM(GetDlgItem(hDlg, lst2), LBN_DBLCLK);

               return TRUE;

         }

      break;

   }

   return FALSE;

}

If the application targets Win32, the notification message to the list box

is sent differently; here is the PostMessage for Win32 applications:

PostMessage (hDlg, WM_COMMAND, MAKEWPARAM (lst2,LBN_DBLCLK),

          (LPARAM)GetDlgItem (hDlg, lst2));

Applications using the IDs of the common dialog box's controls must include

the DLGS.H file.

The templates for the common dialog boxes are in the \SAMPLES\COMMDLG

directory or in the \INCLUDE directory of the Windows SDK installation.

Additional reference words: 3.10 3.50 refresh redraw

KBCategory: kbprg

KBSubcategory: UsrCmnDlg


How to Use a DIB Stored as a Windows Resource

PSS ID Number: Q67883

Authored 28-Dec-1990	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

Device-independent bitmaps (DIBs) are a very useful tool for displaying

graphic information in a variety of device environments. With the

appropriate device drivers, Windows can display a DIB with varying results

on any video display or on a graphics printer.

This article discusses the differences between two methods that can be

used to access a DIB from a resource.

MORE INFORMATION

Bitmaps retrieved from resources are very similar to those stored in

.BMP files on disk. The header information is the same for each type of

bitmap. However, depending upon the method used to retrieve the bitmap

from the resource, the bitmap may be a device-independent bitmap (DIB)

or a device-dependent bitmap (DDB).

When the LoadBitmap() function is used to obtain a bitmap from a

resource, the bitmap is converted to a DDB. Typically, the DDB will be

selected into a memory device context (DC) and blt'ed to the screen

for display.

NOTE: If a 256-color bitmap with a palette is loaded from a resource, some

colors will be lost. To display a bitmap with a palette correctly, the

palette must be selected into the destination DC before the image is

transferred to the DC. LoadBitmap() cannot return the palette associated

with the bitmap; therefore, this information is lost. Instead, the colors

in the bitmap are mapped to colors available in the default system palette,

and a bitmap with the system default color depth is returned.

For example, if LoadBitmap() loads a 256-color image into an application

running on a VGA display, the 256 colors used in the bitmap will be mapped

to the 16 available colors, and a 4 bits-per-pixel bitmap will be returned.

When the display is a 256-color 8514 unit, the same action will map the 256

bitmap colors into the 20 reserved system colors, and an 8 bits-per-pixel

bitmap will be returned.

If, instead of calling LoadBitmap(), the application calls FindResource()

(with RT_BITMAP type), LoadResource(), and LockResource(), a pointer to a

packed DIB will be the result. A packed DIB is a BITMAPINFO structure

followed by an array of bytes containing the bitmap bits.

NOTE: If the resource was originally stored as a DDB, the bitmap returned

will be in the DDB format. In other words, no conversion is done.

The BITMAPINFO structure is a BITMAPINFOHEADER structure and an array of

RGBQUADs that define the colors used in the DIB. The pointer to the packed

DIB may be used in the same manner as a bitmap read from disk.

NOTE: The BITMAPFILEHEADER structure is NOT present in the packed DIB;

however, it is present in a DIB read from disk.

REFERENCES

For sample code demonstrating how to use FindResource() with RT_BITMAP,

LoadResource(), and LockResource(), please see the following article in the

Microsoft Knowledge Base:

   ARTICLE-ID: Q124947

   TITLE     : Retrieving Palette Information from a Bitmap Resource

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: GdiBmp


How to Use a Program to Calculate Print Margins

PSS ID Number: Q122037

Authored 25-Oct-1994	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.1, 3.5, 3.51, and 4.0

SUMMARY

The Windows Software Development Kit (SDK) does not provide a function to

calculate printer margins directly. An application can calculate this

information using a combination of printer escapes and calls to the

GetDeviceCaps() function in Windows or by using GetDeviceCaps() in Windows

NT. This article discusses those functions and provides code fragments as

illustrations.

MORE INFORMATION

An application can determine printer margins as follows:

1. Calculate the left and top margins

   a. Determine the upper left corner of the printable area by using the

      GETPRINTINGOFFSET printer escape in Windows or by calling

      GetDeviceCaps() with the PHYSICALOFFSETX and PHYSICALOFFSETY

      indices in Windows NT. For example:

      // Init our pt struct in case escape not supported

      pt.x = 0; pt.y = 0;

      // In Windows NT, the following 2 calls replace GETPRINTINGOFFSET:

      // pt.x = GetDeviceCaps(hPrnDC, PHYSICALOFFSETX);

      // pt.y = GetDeviceCaps(hPrnDC, PHYSICALOFFSETY);

      // In Windows, use GETPRINTINGOFFSET to fill the POINT struct

      // Drivers are not required to support the GETPRINTINGOFFSET escape,

      // so call the QUERYESCSUPPORT printer escape to make sure

      // it is supported.

      Escape (hPrnDC, GETPRINTINGOFFSET, NULL, NULL, (LPPOINT) &pt);

   b. Determine the number of pixels required to yield the desired margin

      (x and y offsets) by calling GetDeviceCaps() using the LOGPIXELSX and

      LOGPIXELSY flags.

      // Figure out how much you need to offset output. Note the

      // use of the "max" macro. It is possible that you are asking for

      // margins that are not possible on this printer. For example, the HP

      // LaserJet has a 0.25" unprintable area so we cannot get margins of

      // 0.1".

      xOffset = max (0, GetDeviceCaps (hPrnDC, LOGPIXELSX) *

                        nInchesWeWant - pt.x);

      yOffset = max (0, GetDeviceCaps (hPrnDC, LOGPIXELSY) *

                        nInchesWeWant - pt.y);

   // When doing all the output, you can either offset it by the above

   // values or call SetViewportOrg() to set the point (0,0) at

   // the margin offset you calculated.

   SetViewportOrg (hPrnDC, xOffset, yOffset);

   ... all other output here ...

2. calculate the bottom and right margins

   a. Obtain the total size of the physical page (including printable and

      unprintable areas) by using the GETPHYSPAGESIZE printer escape in

      Windows or by calling GetDeviceCaps() with the PHYSICALWIDTH and

      PHYSICALHEIGHT indices in Windows NT.

   b. Determine the number of pixels required to yield the desired right

      and bottom margins by calling GetDeviceCaps using the LOGPIXELSX and

      LOGPIXELSY flags.

   c. Calculate the size of the printable area with GetDeviceCaps() using

      the HORZRES and VERTRES flags.

   The following code fragment illustrates steps 2a through 2c:

   // In Windows NT, the following 2 calls replace GETPHYSPAGESIZE

   // pt.x = GetDeviceCaps(hPrnDC, PHYSICALWIDTH);

   // pt.y = GetDeviceCaps(hPrnDC, PHYSICALHEIGHT);

   // In Windows, use GETPHYSPAGESIZE to fill the POINT struct

   // Drivers are not required to support the GETPHYSPAGESIZE escape,

   // so call the QUERYESCSUPPORT printer escape to make sure

   // it is supported.

   Escape (hPrnDC, GETPHYSPAGESIZE, NULL, NULL, (LPPOINT) &pt);

   xOffsetOfRightMargin = xOffset +

                          GetDeviceCaps (hPrnDC, HORZRES) -

                          pt.x -

                          GetDeviceCaps (hPrnDC, LOGPIXELSX) *

                          wInchesWeWant;

   yOffsetOfBottomMargin = yOffset +

                           GetDeviceCaps (hPrnDC, VERTRES) -

                           pt.y -

                           GetDeviceCaps (hPrnDC, LOGPIXELSY) *

                           wInchesWeWant;

NOTE: Now, you can clip all output to the rectangle bounded by xOffset,

yOffset, xOffsetOfRightMargin, and yOffsetOfBottomMargin.

For further information about margins, query in the Microsoft Knowledge

Base by using these words:

   GETPHYSPAGESIZE and GETPRINTINGOFFSET and GetDeviceCaps

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprint kbprg kbcode

KBSubcategory: GdiPrn


How to Use CTL3D Under the Windows 95 Operating System

PSS ID Number: Q130693

Authored 24-May-1995	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) version 4.0

SUMMARY

When an application that uses CTL3D is run under Windows 95, CTL3D disables

itself if any dialog box has the DS_3DLOOK style. By default, all

applications based on Windows version 4.0 get the DS_3DLOOK style for all

dialog boxes. This article explains how this affects the way dialog boxes

and controls are displayed under the Windows 95 operating system.

MORE INFORMATION

When CTL3D is disabled, Windows 95 draws dialog boxes and controls using

its own 3D drawing properties. Windows 95 does not draw the static

rectangles and frames in 3D as CTL3D does. For more information about how

these frames and rectangles are drawn under Windows 95, please see the

following article in the Microsoft Knowledge Base:

ARTICLE-ID: Q125684

TITLE     : How to Use SS_GRAYRECT SS_BLACKRECT SS_WHITERECT in Windows 95

There are two new static control styles (SS_SUNKEN and SS_ETCHEDFRAME) in

Windows 95 that simulate two of the static panels used in CTL3D. SS_SUNKEN

creates a sunken panel, and SS_ETCHEDFRAME creates a panel with a dipped

edge. There is no static style for creating a raised panel, but you can use

the DrawEdge API to draw a raised panel.

There are also two new static control styles that you can use to create 3D

lines. SS_ETCHEDHORZ creates a dipped horizontal line, and SS_ETCHEDVERT

creates a dipped vertical line.

An application should check the platform version at run time by using the

GetVersion or GetVersionEx function, and then implement appropriate 3D

effects. If the major version is less than 4, the application can use the

CTL3D functions, messages, and controls. If the major version is 4 or

greater, the application should not implement CTL3D; it should create the

proper Windows 95 style controls (or use DrawEdge to draw its 3D panels) to

achieve the desired effects.

Additional reference words: 4.00

KBCategory: kbprg kbui

KBSubcategory: UsrCtl


How to Use DWL_MSGRESULT in Property Sheets & Wizard Controls

PSS ID Number: Q130762

Authored 25-May-1995	Last modified 22-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) version 4.0

SUMMARY

Each page in a property sheet or wizard control is an application-defined

modeless dialog box that manages the control windows used to view and edit

the properties of an item. Applications provide the dialog box template

used to create each page as well as the dialog box procedure.

A property sheet or wizard control sends notification messages to the

dialog box procedure for a page when the page is gaining or losing the

focus and when the user chooses the OK, Cancel, or other buttons. The

notifications are sent in the form of WM_NOTIFY messages. The dialog box

procedure(s) for the correspoding page(s) should use the SetWindowLong()

function to set the DWL_MSGRESULT value of the page dialog box to specify

the return value from the dialog box procedure to prevent or accecpt the

change. After doing so, the dialog box procedure must return TRUE in

response to processing the WM_NOTIFY message. If it does not return TRUE,

the return value set in the DWL_MSGRESULT index using the SetWindowLong()

function is ignored by the property sheet or wizard control.

MORE INFORMATION

Dialog box procedures return a BOOL value (TRUE or FALSE). This return

value indicates to the caller of the dialog box function that the dialog

box function either handled the message that it received or did not handle

it. When the dialog box function returns FALSE, it is indicating that it

did not handle the message it received. When the dialog box handles the

message and generates a return value, it typically sets the DWL_MSGRESULT

index of the dialog box with the return value.

The dialog box function of the property sheet or wizard page handles

messages (WM_NOTIFY) sent by the property sheet or wizard control. The

property sheet or wizard control determines whether the page that received

the message processed the message or not by checking the retrun value from

the call to SendMessage(). If the return value is FALSE, the control goes

ahead and does what needs to be done by default. But if the return value is

TRUE, the control checks for the return value by looking at the value

stored in the DWL_MSGRESULT index of that page.

For example, the dialog box function of a property page might trap the

PSN_SETACTIVE notification to prevent it from being activated under certain

circumstances. In this case, the page dialog box function uses the

SetWindowLong() function to set the DWL_MSGRESULT value to -1. If the

dialog box does not return TRUE after setting the DWL_MSGRESULT, the

property sheet control that sent the message completely ignores the return

value because it assumes there is no return value.

Additional reference words: 4.00 common controls user Windows 95

KBCategory: kbprg

KBSubcategory: UsrCtl


How to use ExitExecRestart to Install System Files

PSS ID Number: Q114606

Authored 08-May-1994	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK, version 3.5

SUMMARY

Some installation procedures require the installation of files (such as

CTL3D.DLL, COMMDLG.DLL, and fonts) that may be in use by Windows at the

time the setup program is run. Windows is likely to have these files open,

so they cannot be installed without causing sharing violations. The Setup

Toolkit provides features to exit Windows, install these files, and then

restart Windows when complete.

MORE INFORMATION

The Setup Toolkit accomplishes the installation of system files as

follows:

1. Before the Setup Toolkit copies a system file, it checks to see if the

   file is currently open. If it is, it copies the file to the destination

   directory, but under a different file name. It then adds this file to

   the "restart list".

2. When CopyFilesInCopyList() is complete, the Setup Toolkit checks the

   "restart list" and generates a .BAT file (named _MSSETUP.BAT) in the

   "restart directory". This .BAT file contains commands which delete the

   system files which were open (in step #1) and rename the new versions to

   their correct names.

3. Windows is exited, the .BAT file executed, then Windows restarted.

4. The .BAT file is then deleted.

   NOTE: The "restart directory" is not deleted. Hence, you should use your

   application's installation directory as your restart directory.

Hence, to install system files, perform the following steps:

1. Mark the system files as "system" in the DSKLAYT program. This is

   accomplished by highlighting all the system files (clicking with the

   CTRL key down) and placing a check in the "System File" check box under

   "File Attributes".

2. Before calling CopyFilesInCopyList() specify the name of your "restart

   directory". Assuming the target directory for your application is stored

   in DEST$ (as in the samples), use the following line:

      SetRestartDir DEST$

   The specified directory does not need to exist. It will be created

   if necessary.

3. After your installation is complete, execute the following code before

   exiting your setup script. Normally this code will be placed at the

   end of the Install subroutine.

      if RestartListEmpty ()=0 then

          '' The following two lines must go on one line.

          MessageBox hwndFrame (), "Windows will now be exited and

          restarted.", "Sample Setup Script", MB_OK+MB_ICONINFORMATION

      eer:

          i%=ExitExecRestart ()

          '' The following three lines must go on one line.

          MessageBox hwndFrame (), "Windows cannot be restared because

          MS-DOS-based applications are active. Close all MS-DOS-based

          applications, and then click OK.", "Sample Setup Script",

          MB_OK+MB_ICONSTOP

          goto eer

      end if

   NOTE: In order to use the MessageBox() function you must add the

   following lines at the beginning of your setup script:

      const MB_ICONINFORMATION = 64

      '' The following two lines must go on one line.

      declare sub MessageBox lib "user.exe" (hwnd%, message$,

      title$, options%)

4. Add the file _MSSETUP.EXE to your source directory and lay it out on

   Disk #1 in DSKLAYT.

5. Add a reference to _MSSETUP.EXE to the [files] section of your .LST

   file. For example,

    if you marked _MSSETUP.EXE to be compressed,

    [files]

        _mssetup.ex_ = _mssetup.exe

    if you did not mark it as compressed,

    [files]

        _mssetup.exe = _mssetup.exe

NOTES:

1. If ExitExecRestart () is successful, your script will be exited. That

   is, ExitExecRestart () will not return. If it does return, an error

   has occurred.

2. This functionality is not available under Windows 3.0. If the user runs

   the above setup script on Windows 3.0, they will receive the message

   that MS-DOS-based applications are running and they will not be able to

   complete the setup. If this is a concern, check the version of Windows

   before executing the above code.

3. If _MSSETUP.EXE is not in your .LST file or not laid out in DSKLAYT,

   you will receive an "assertion failure" message when calling

   ExitExecRestart ().

Additional reference words: 3.10 3.50 setup toolkit mssetup

KBCategory: kbtool kbsetup kbprg kbcode

KBSubcategory: TlsMss


How to Use Hangeul (Korean) Windows Input Method Editor (IME)

PSS ID Number: Q130053

Authored 10-May-1995	Last modified 16-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

 - Microsoft Win32 Software Development Kit (SDK) version 3.5

 - Microsoft Win32s version 1.2

SUMMARY

Hangeul (Korean) Windows supports the KSC5601-1987 code set, which consists

of several thousands Hangeul characters. The Hangeul Windows IME (Input

Method Editor) allows the user to enter Hangeul Jamos (24 basic components

of Hangeul characters), compose the final characters, and send them to

applications.

MORE INFORMATION

When running Hangeul Windows, you will see a small window with three

buttons in the lower-left corner:

 - The left button toggles between the Roman "A" character and the Korean

   character that is pronounced "GA," which Windows uses to symbolize

   Korean characters.

 - The center button is a graphic of a half box or full box, which selects

   SBCS or DBCS storage (or display) of Roman (but not Hangeul) characters.

   Hangeul characters always take up a double-byte space, unlike some

   Japanese characters (katakana).

 - The right button is the "Hangeul to Hanja" converter.

You can type in English by having the Roman toggle selected. To try typing

Hangeul, the main thing to remember is that there is no apparent logical

connection between the US 101 keyboard and what the you end up typing.

To type like a pro, you need Korean keycaps, a cheat sheet, or a lot of

memory in your brain.

For example, to type the word "Hangeul" type these characters:

   GKS   RMF

(Please ignore the spaces between the two characters.) Notice how each

group of three keyboard characters assemble a single Hangeul character.

Hangeul is often made up of three components (called "Jamos"), but

characters can actually be composed of from two to several Jamos.

Here is how to type "Seoul, Korea."  Seoul is pronounced locally "sa-ul,"

so try typing these characters:

   TJ DNF ZH FL DK

(Please ignore the spaces between the characters.) The word "Korea" is not

a Korean name; it is the English equivalent, just as Japan is really

Nippon. The word "Korea" in Korean is "Han-guk," so "Seoul, Hanguk" would

be:

   TJD NF    GKS RNR

The reason to try "Hanguk" instead of "Korea" is that Hanguk can also be

spelled with Chinese characters. Put the mouse pointer (cursor) on the left

edge of "Han" and click the "Hangeul to Hanja" button. A list box appears.

Select choice #1 by typing 1 or by selecting it with the mouse. Do the same

for the next character, again selecting choice #1. Then it will display

in Hanja.

Most Korean text is in Hangeul not Hanja, notice the 3.1-H readme is all

Hangeul. Hanja is still used in Korea - sometimes.

Additional reference words: 1.20 3.10 3.50 Hangul kbinf

KBCategory: kbother

KBSubcategory: wintldev


How to Use LVIF_DI_SETITEM on an LVN_GETDISPINFO Notification

PSS ID Number: Q131285

Authored 07-Jun-1995	Last modified 10-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.51, 4.0

 - Microsoft Win32s version 1.3

SUMMARY

Windows 95 provides two flags, LVIF_DI_SETITEM and TVIF_DI_SETITEM, for the

listview and treeview controls respectively. When set, these flags instruct

Windows to start storing information for that particular item previously

set as a callback item.

MORE INFORMATION

Windows 95 introduces the concept of callback items for the new listview

and treeview common controls. A callback item is a listview or treeview

item for which the application, not the control, stores the text, icon, or

any appropriate information about the item. If the application already

maintains this information anyway, setting up callback items could decrease

the memory requirements of the control. Callback items are just as useful

for items that display constantly changing information. Setting these items

up as callback items allows the application to display the most current

values appropriate for that item.

Take for example a SPY application that displays information in a

hierarchical form (or a treeview) about the window being browsed or spied

on. One of the things it displays is the window rectangle, or the

dimensions of the window.

Because the user could resize this window at any time, this particular item

is a good candidate for a callback item because it displays constantly

changing information.

The application defines a callback item by specifying LPSTR_TEXTCALLBACK

for the pszText member of the TV_ITEM structure. Whenever the item needs to

be displayed, Windows requests the callback information by sending the

treeview's parent a TVN_GETDISPINFO notification in the form of a WM_NOTIFY

message. The parent window then fills the pszText member of the TV_ITEM

structure as the following sample code demonstrates:

   LRESULT MsgNotify(HWND   hwnd,

                     UINT   uMessage,

                     WPARAM wparam,

                     LPARAM lparam)

   {

       TV_DISPINFO *ptvdi = (TV_DISPINFO *)lparam;

       switch (ptvdi->hdr.code)

       {

          case TVN_GETDISPINFO:

            if (ptvdi.mask & TVIF_TEXT)

            {

               RECT  rect;

               char  szBuf [30];

               GetWindowRect (hWndToBrowse, &rect);

               // where FormatRectText formats the rect information

               // in a nice <WindowRect: (x,y):cx,cy> format

               // and stores it in szBuf.

               FormatRectText (&rect, szBuf, sizeof (szBuf));

               lstrcpy (ptvdi.pszText, szBuf);

            }

            :

           default: break;

        }

   return 0;

   }

At a certain point, the application may determine during run time, that the

window dimensions will no longer change. At this point, there may be no

reason for this particular treeview item to remain as a callback item. This

time, you need to process the TVN_GETDISPINFO message in a slightly

different manner, specifying the TVIF_DI_SETITEM flag as demonstrated in

the following code:

   case TVN_GETDISPINFO:

      if (ptvdi.mask & TVIF_TEXT)

      {

         RECT  rect;

         char  szBuf [30];

         GetWindowRect (hWndToBrowse, &rect);

        // where FormatRectText formats the rect information

        // in a nice <WindowRect: (x,y):cx,cy> format

        // and stores it in szBuf.

         FormatRectText (&rect, szBuf, sizeof (szBuf));

         lstrcpy (ptvdi.pszText, szBuf);

         plvdi->item.mask = plvdi->item.mask | TVIF_DI_SETITEM;

      }

By ORing the mask with TVIF_DI_SETITEM, you instruct Windows to start

storing text information for the particular treeview item. At that point,

the application stops receiving a TVN_GETDISPINFO notification whenever the

item needs to be redrawn. This works almost as well as calling

TreeView_SetItem() on the item and replacing pszText's value with

LPSTR_TEXTCALLBACK to the appropriate string.

The same holds true for listview controls when the mask is ORed with the

LVIF_DI_SETITEM flag. However, note that setting the LVIF_DI_SETITEM flag

for listviews works only for the first column of text (iSubItem ==0).

If an application specifies LPSTR_TEXTCALLBACK therefore for a column

other than 0 in report view, LVIF_DI_SETITEM does not store the text

information for that listview item column.

For more information on other members of the LV_ITEM and TV_ITEM structures

that can be set up for callback, refer to the documentation on LV_DISPINFO

and TV_DISPINFO structures.

Additional reference words: 4.00 1.30 I_IMAGECALLBACK win95

I_CHILDRENCALLBACK

KBCategory: kbprg kbcode

KBSubcategory: UsrCtl


How to Use PeekMessage() Correctly in Windows

PSS ID Number: Q74042

Authored 11-Jul-1991	Last modified 23-Jun-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

 - Microsoft Win32 SDK versions 3.1, 3.5, 3.51, and 4.0

SUMMARY

In the Windows environment, many applications use a PeekMessage() loop to

perform background processing. Such applications must allow the Windows

system to enter an idle state when their background processing is complete.

Otherwise, system performance, "idle-time" system processes such as paging

optimizations, and power management on battery-powered systems will be

adversely affected.

While an application is in a PeekMessage() loop, the Windows system cannot

go idle. Therefore, an application should not remain in a PeekMessage()

loop after its background processing has completed.

NOTE: The PeekMessage method described in this article is only needed if

your application is a 32-bit application for Windows and is, for some

reason, unable to create threads and perform background processing.

MORE INFORMATION

Many Windows-based applications use PeekMessage() to retrieve messages

while they are in the middle of a long process, such as printing,

repaginating, or recalculating, that must be done "in the background."

PeekMessage() is used in these situations because, unlike GetMessage(), it

does not wait for a message to be placed in the queue before it returns.

An application should not call PeekMessage() unless it has background

processing to do between the calls to PeekMessage(). When an application is

waiting for an input event, it should call GetMessage() or WaitMessage().

Remaining in a PeekMessage() loop when there is no background work

causes system performance problems. A program in a PeekMessage() loop

continues to be rescheduled by the Windows scheduler, consuming CPU

time and taking time away from other processes.

In enhanced mode, the virtual machine (VM) in which Windows is running

will not appear to be idle as long as an application is calling the

PeekMessage function. Therefore, the Windows VM will continue to

receive a considerable fraction of CPU time.

Many power management methods employed on laptop and notebook computers are

based on the system going idle when there is no processing to do. An

application that remains in a PeekMessage() loop will make the system

appear busy to power management software, resulting in excessive power

consumption and shortening the time that the user can run the system.

In the future, the Windows system will make more and more use of idle

time to do background processing, which is designed to optimize system

performance. Applications that do not allow the system to go idle will

adversely affect the performance of these techniques.

All these problems can be avoided by calling the PeekMessage() function

only when there is background work to do, and calling GetMessage() or

WaitMessage() when there is no background work to do.

For example, consider the following PeekMessage() loop. If there is no

background processing to do, this loop will continue to run without

waiting for messages, preventing the system from going idle and

causing the negative effects described above.

   // This PeekMessage loop will NOT let the system go idle.

   for( ;; )

   {

      while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))

      {

         if (msg.message == WM_QUIT)

            return TRUE;

         TranslateMessage(&msg);

         DispatchMessage(&msg);

      }

      BackgroundProcessing();

    }

This loop can be rewritten in two ways, as shown below. Both of the

following PeekMessage() loops have two desirable properties:

 - They process all input messages before performing background

   processing, providing good response to user input.

 - The application "idles" (waits for an input message) when no

   background processing needs to be done.

Improved PeekMessage Loop 1

---------------------------

   // Improved PeekMessage() loop

   for(;;)

   {

      while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))

      {

         if (msg.message == WM_QUIT)

            return TRUE;

         TranslateMessage(&msg);

         DispatchMessage(&msg);

      }

      if (IfBackgroundProcessingRequired())

         BackgroundProcessing();

      else

         WaitMessage(); // Will not return until a message is posted.

   }

Improved PeekMessage Loop 2

---------------------------

   // Another improved PeekMessage() loop

   for (;;)

   {

      for (;;)

      {

         if (IfBackgroundProcessingRequired())

         {

            if (!PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))

               break;

         }

         else

            GetMessage(&msg, NULL, 0, 0, 0);

         if (msg.message == WM_QUIT)

            return TRUE;

         TranslateMessage(&msg);

         DispatchMessage(&msg);

      }

      BackgroundProcessing();

   }

Note that calls to functions such as IsDialogMessage() and

TranslateAccelerator() can be added to these loops as appropriate.

There is one case in which the loops above need additional support: if

the application waits for input from a device (for example, a fax

board) that does not send standard Windows messages. For the reasons

outlined above, a Windows-based application should not use a PeekMessage()

loop to continuously poll the device. Rather, implement an interrupt

service routine (ISR) in a dynamic-link library (DLL). When the ISR is

called, the DLL can use the PostMessage function to inform the

application that the device requires service. DLL functions can safely

call the PostMessage() function because the PostMessage() function

is reentrant.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: UsrMsg


How to Use RPC Under Win32s

PSS ID Number: Q127903

Authored 21-Mar-1995	Last modified 06-Jun-1995

The information in this article applies to:

 - Microsoft Win32s, versions 1.2 and 1.25a

Win32s does not thunk Remote Procedure Call (RPC) calls. Therefore, if you

have a Win32-based application that uses RPC and you want it to run on

Win32s, you will need to write a thunking layer for your application to

thunk the 32-bit calls to the 16-bit RPC implementation.

One issue to keep in mind when writing the thunking layer is how to handle

stub code. It is convenient to direct the MIDL compiler to produce 16-bit

stub code for the application. The stub code can be built as a 16-bit DLL,

which can be called from the Win32-based application via the Universal

Thunk. This eliminates the need to write a thunking layer for the RPC

run-time functions that appear in 32-bit client stub code.

One limitation is that RPC servers are not supported with the 16-bit RPC,

only clients. Microsoft's 32-bit RPC implements servers by spawning threads

for each call, and threads are not supported under Win32s. There may be

other vendors who supply a 16-bit RPC that supports servers.

Additional reference words: 1.20

KBCategory: kbprg

KBSubcategory: W32s


How to Use SS_GRAYRECT SS_BLACKRECT SS_WHITERECT in Windows

PSS ID Number: Q125684

Authored 01-Feb-1995	Last modified 06-Apr-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

SUMMARY

The colors used in the gray, white, and black rectangle static controls has

changed in Windows 95. In previous versions of Windows, these colors were

based on the system colors for windows. In Windows 95, these colors are

based on the colors for 3D objects.

MORE INFORMATION

In Windows 95, the definitions for white, gray, and black rectangle static

controls are as follows:

 - SS_WHITERECT: Specifies a rectangle filled with the highlight color for

   three-dimensional display elements (for edges facing the light source).

   This is the same color retrieved by using GetSysColor() with

   COLOR_3DHILIGHT.

 - SS_GRAYRECT: Specifies a rectangle filled with the shadow color for

   three-dimensional display elements (for edges facing away from the light

   source). This is the same color retrieved by using GetSysColor() with

   COLOR_3DSHADOW.

 - SS_BLACKRECT: Specifies a rectangle filled with the Shadow color for

   three-dimensional display elements (for edges facing away from the light

   source). This is the same color retrieved by using GetSysColor() with

   COLOR_3DDKSHADOW. This is not the same color as COLOR_3DSHADOW. There

   are two shadow colors used on 3D objects.

In previous versions of Windows, the definitions for white, gray, and

black rectangle static controls were as follows:

 - SS_WHITERECT: Specifies a rectangle filled with the color used to fill

   window backgrounds. This color is white in the default Windows color

   scheme. This is the same color retrieved by using GetSysColor() with

   COLOR_WINDOW.

 - SS_GRAYRECT: Specifies a rectangle filled with the color used to fill

   the screen background. This color is gray in the default Windows color

   scheme. This is the same color retrieved by using GetSysColor() with

   COLOR_BACKGROUND.

 - SS_BLACKRECT: Specifies a rectangle filled with the color used to draw

   window frames. This color is black in the default Windows color scheme.

   This is the same color retrieved by using GetSysColor() with

   COLOR_WINDOWFRAME.

Additional reference words: 4.00

KBCategory: kbprg

KBSubcategory: UsrCtl


How to Use the Small Icon in Windows 95

PSS ID Number: Q125682

Authored 01-Feb-1995	Last modified 06-Apr-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

SUMMARY

In Windows 95, each application is associated with two icons: a small icon

(16x16) and a large icon (32x32). The small icon is displayed in the

upper-left hand corner of the application and on the taskbar.

MORE INFORMATION

Large and small icons are associated with an application by using the

RegisterClassEx() function. This function takes a pointer to a WNDCLASSEX

structure. The WNDCLASSEX structure is similar to the WNDCLASS structure

except for the addition of the hIconSm parameter, which is used for the

handle to the small icon. If no small icon is associated with an

application, Windows 95 will use a 16x16 representation of the large icon.

NOTE: RegisterClassEx() is not currently implemented in Windows NT where it

returns NULL.

The LoadIcon() function loads the large icon member of an icon resource.

To load the small icon, use the new LoadImage() function as follows:

LoadImage(  hInstance,

            MAKEINTRESOURCE(<icon identifier>),

            IMAGE_ICON,

            16,

            16,

            0);

The small icon currently associated with the application will be displayed

in the upper-left corner of the application's main window and on the task

bar. Both the large and the small icon association can be changed at

runtime by using the WM_SETICON message.

By default, the start menu will display the first icon defined in an

application's resources. This can be changed through the start menu

property sheets.

Explorer displays the first defined icon in an application's resources

unless the application adds an entry to the registry under the program

information called DefaultIcon or defines an icon handler shell extension

for the file type. Refer to the Shell Extension documentation for more

information on shell extensions.

Additional reference words: 4.00

KBCategory: kbprg

KBSubcategory: UsrWndw


How to Use WinSock to Enumerate Addresses

PSS ID Number: Q129315

Authored 24-Apr-1995	Last modified 04-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.5 and 3.51

SUMMARY

The gethostbyname() and gethostname() WinSock database APIs can be used to

list IP addresses for a multihomed host. However, these functions work only

for IP addresses. This article shows by example how to give addresses for

other address families. Two different methods are given.

MORE INFORMATION

Method One Code Sample

----------------------

AF_IPX:

This function can be used to give an IPX address:

   #include <winsock.h>

   #include <wsipx.h>

   #include <wsnwlink.h>

   #include <stdlib.h>

   // Note:  In the interest of clarity, the following code does not check

   //        return values or handle error conditions.

   void IPXEnum()

   {

      int            cAdapters,

                     cbOpt  = sizeof( cAdapters ),

                     cbAddr = sizeof( SOCKADDR_IPX );

      SOCKET         s;

      SOCKADDR_IPX   Addr;

      // Create IPX socket.

      s = socket( AF_IPX, SOCK_DGRAM, NSPROTO_IPX );

      // Socket must be bound prior to calling IPX_MAX_ADAPTER_NUM

      memset( &Addr, 0, sizeof( Addr ));

      Addr.sa_family = AF_IPX;

      bind( s, (SOCKADDR*) &Addr, cbAddr);

      // Get the number of adapters => cAdapters.

      getsockopt( (SOCKET) s, NSPROTO_IPX, IPX_MAX_ADAPTER_NUM,

                  (char *) &cAdapters, &cbOpt );

      // At this point cAdapters is the number of installed adapters.

      while ( cAdapters > 0 )

      {

         IPX_ADDRESS_DATA  IpxData;

         memset( &IpxData, 0, sizeof(IpxData));

         // Specify which adapter to check.

         IpxData.adapternum = cAdapters - 1;

         cbOpt = sizeof( IpxData );

         // Get information for the current adapter.

         getsockopt( s, NSPROTO_IPX, IPX_ADDRESS,

                     (char*) &IpxData, &cbOpt );

         // IpxData contains the address for the current adapter.

         cAdapters--;

      }

   }

AF_NETBIOS:

This function uses the EnumProtocols() function to give lana numbers

for the available NetBIOS transports. NOTE: This doesn't work under Windows

NT 3.5 because of a bug in EnumProtocols(), but it does work under Windows

NT 3.51.

   void NBEnum()

   {

      DWORD          cb = 0;

      PROTOCOL_INFO *pPI;

      BOOL           pfLanas[100];

      int            iRes,

                     nLanas = sizeof(pfLanas) / sizeof(BOOL);

      // Specify NULL for lpiProtocols to enumerate all protocols.

      // First, determine the output buffer size.

      iRes = EnumProtocols( NULL, NULL, &cb );

      // Verify the expected error was received.

      assert( iRes == -1 && GetLastError() == ERROR_INSUFFICIENT_BUFFER );

      if (!cb)

      {

         fprintf( stderr, "No available NetBIOS transports.\n");

         break;

      }

      // Allocate a buffer of the specified size.

      pPI = (PROTOCOL_INFO*) malloc( cb );

      // Enumerate all protocols.

      iRes = EnumProtocols( NULL, pPI, &cb );

      // EnumProtocols() lists each lana number twice, once for

      // SOCK_DGRAM and once for SOCK_SEQPACKET. Set a flag in pfLanas

      // so unique lanas can be identified.

      memset( pfLanas, 0, sizeof( pfLanas ));

      while (iRes > 0)

         // Scan protocols looking for AF_NETBIOS.

         if ( pPI[--iRes].iAddressFamily == AF_NETBIOS )

            // found one

            pfLanas[ pPI[iRes].iProtocol ] = TRUE;

      fprintf( stderr, "Available NetBIOS lana numbers: " );

      while( nLanas-- )

         if ( pfLanas[nLanas] )

            fprintf( stderr, "%d ", nLanas );

      free( pPI );

   }

AF_APPLETALK:

Address enumeration is not meaningful for AF_APPLETALK. On a multihomed

host with routing disabled, only the default adapter is used. If routing is

enabled, a single AppleTalk address is used for all installed network

adapters.

Method Two: Code Sample

-----------------------

Listed below is an example of how to use the WinSock database APIs to

give IP addresses:

   void EnumIP()

   {

      char     szHostname[100];

      HOSTENT *pHostEnt;

      int      nAdapter = 0;

      gethostname( szHostname, sizeof( szHostname ));

      pHostEnt = gethostbyname( szHostname );

      while ( pHostEnt->h_addr_list[nAdapter] )

      {

         // pHostEnt->h_addr_list[nAdapter] is the current address in host

         //  order.

         nAdapter++;

      }

   }

Additional reference words: 3.50

KBCategory: kbnetwork kbcode

KBSubcategory: NtwkWinsock


How Win32-Based Applications Are Loaded Under Windows

PSS ID Number: Q110845

Authored 31-Jan-1994	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32s versions 1.0, 1.1, and 1.2

SUMMARY

Microsoft Win32s is an operating system extension that allows Win32-based

applications to be run on Windows 3.1. Win32s consists of a VxD and a set

of dynamic-link libraries (DLLs).

It is possible to distinguish whether an executable was built for Win32 or

Win16. Win32 executables use the Portable Executable (PE) format, while

Win16 executables use the New Executable (NE) format.

The Windows 3.1 loader was designed to be aware that Win32-based

applications would potentially be loaded. When the user starts a

Win32-based application, the Windows 3.1 loader tries to load the

Win32-based application via WinExec(). WinExec() calls LoadModule(), which

will fail with an error indicating that it was passed an .EXE with the PE

format. At this point, WinExec() calls a special function to start up

Win32s. This function loads W32SYS.DLL (16-bit DLL) via LoadModule(). If

W32SYS determines that the EXE is indeed a valid PE file, it calls

LoadModule() on WIN32S.EXE (16-bit EXE) (it is similar to WinOldApp for MS-

DOS-based programs running in Windows). WIN32S.EXE contains the task

database, PSP, task queue, and module database. WIN32S.EXE calls its only

function to load the Win32s 16-bit translator DLL, W32S16.DLL, which does

work as a translator between the Win32-based application and the 16-bit

world that it is running in.

MORE INFORMATION

Win32-based applications are loaded in the upper 2 gigabytes (GB) of the 4

GB address space under Win32s, whereas Windows NT loads them in the lower 2

GBs. This is because W32S.386, a VxD, allocates the memory, and VxDs get

memory in the 2 GB to 4 GB range. The first 64K and the last 64K cannot be

read or written to (similar to a null page on other architectures).

On Windows 3.1, all applications, even the Win32-based applications, share

the same address space, unlike Windows NT where each Win32-based

application gets its own address space. Each Windows-based application may

be given its own address space, starting with Windows NT 3.5.

Additional reference words: 1.00 1.10 1.20 G byte

KBCategory: kbprg

KBSubcategory: W32s


How Windows NT Handles Floating-Point Calculations

PSS ID Number: Q102555

Authored 04-Aug-1993	Last modified 21-Feb-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

SUMMARY

Each thread in a Win32-based application has its own general register set

(provided by the kernel) and its own floating-point state. However, the

floating-point support available in a specific instance depends on the

subsystem or component in question.

Below is a list of various components and environments and what type of

floating-point support is present for them.

MORE INFORMATION

Win32

-----

Floating-point support is available to any thread running in the Win32 or

POSIX subsystem.

This is true even on x86 machines that do not have floating-point hardware.

The floating-point instructions are emulated automatically for the thread.

This feature allows people writing code in higher level languages, such as

C, to assume floating-point support. The compiler generates the appropriate

floating-point machine code. In addition, some standard floating-point

functions allow applications to use floating-point exceptions in a portable

manner. [For more information, see the header file FPIEE.H and the filter

function fpieee_flt().]

POSIX

-----

Again, POSIX applications can be created with the assumption of available

floating-point support.

Note that the POSIX standard does not define a way to enable floating-point

exceptions, so POSIX applications that do so must rely on some system-

specific features. Under Windows NT, a POSIX application can enable

floating exceptions by using _controlfp(). Floating-point exceptions can

then be caught by SIGFPE, or, if the application needs to do more than

simply catch the exception, by fpieee_flt().

MS-DOS/WOW: x86

---------------

MS-DOS-based and Windows-based applications are run directly by the

processor in virtual-86 mode. An MS-DOS/WOW application has access to the

floating-point hardware just as it would appear in MS-DOS. (If no floating-

point hardware is present, no emulation is provided for the application.)

MS-DOS/WOW: Non-x86

-------------------

When run on a RISC-based computer, or other non-x86 machine using the

Windows/NT 80286 emulation code, the 80287 floating-point instructions are

directly emulated. The MS-DOS/WOW application behaves as if an 80287

processor were present.

OS/2 (Supported Only on x86 Versions of Windows NT)

---------------------------------------------------

Floating-point support in this subsystem matches that of OS/2: if there's

no floating-point hardware installed, the OS/2 application is expected to

provide its own emulation.

Device Drivers: x86

-------------------

On x86 platforms, a driver cannot use the coprocessor. Moreover, using any

floating-point instruction (including fnsave or fwait) in the driver could

cause either corruption of the user's numeric state or a bug check.

Device Drivers: MIPS/Alpha

--------------------------

For non-ISR time (that is, execution that does not occur during the

interrupt service routine [ISR]), floating-point support can be assumed. At

ISR time, floating-point support is available so long as the driver

registered the ISR with IoConnectInterrupt and passed FloatingSave as TRUE.

This causes the system to save and restore the volatile floating-point

registers around the associated ISR.

Note that these functions on RISC-based computers use floating-point:

RtlFillMemory(), RtlZeroMemory(), RtlCopyMemory(), RtlMoveMemory(). If an

ISR calls any of these functions, it must connect to the interrupt with

FloatingSave=TRUE on a MIPS.

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: BseMisc


Icons for Console Applications

PSS ID Number: Q91150

Authored 29-Oct-1992	Last modified 18-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

Under OS/2, when adding an application named CONAPP.EXE to a program group,

the system uses the file CONAPP.ICO (if it exists ) as the icon. This does

not happen automatically under Windows NT and Windows 95; the item will

have a generic icon.

To specify the icon that appears in the program group, use the following

steps:

1. Create a resource file containing an ICON statement:

      ConApp ICON ConApp.ICO

2. Compile the resource using RC:

      rc -r $(rcvars) -fo conapp.res conapp.rc

3. Add the .rc file to the link command line

MORE INFORMATION

If the application is started by clicking its icon in Program Manager, the

icon that appears when the application is minimized will be that icon,

whether it is a generic icon or an icon imbedded in the executable file.

If the application is started from the MS-DOS prompt or the File menu, then

the icon that appears when the application is minimized will be the icon

that is used for the MS-DOS prompt.

Additional reference words: 3.10 3.50 4.00

KBCategory: kbprg

KBSubcategory: BseCon


Ideas to Remember as You Convert from ASCII or ANSI to

PSS ID Number: Q130052

Authored 10-May-1995	Last modified 16-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) version 3.5

 - Microsoft Win32s version 1.2

SUMMARY

Because the industry is moving to Windows NT, and Windows NT supports

Unicode, many independent software vendors (ISVs) want to know how to

convert existing ASCII (or ANSI) help and resource files into Unicode. This

article gives you some notes on the subject.

MORE INFORMATION

When converting ASCII to Unicode, remember that the entire ASCII characters

map perfectly to the first characters in Unicode. You need only add a

second null bit and a 0x00 in the high byte.

When converting ANSI to Unicode, UCONVERT.EXE sources in the Win32 SDK and

the good illustration of win32 MultiBytetoWideChar conversion API are

helpful sources to consult.

When converting a Help file, you face the challenge presented by the fact

that the old ANSI RTF format is clueless about wide characters. Also, you

need an RTF format for each specific country. For example, you'll need one

specific to Japan, another separate RTF format for Korea, and so on. In

addition, you might want to consider converting to the newer, much more

powerful Help file formats supported in the Windows 95 Help file system;

this may be an easier solution.

Help files in Windows NT versions 3.1 and 3.5 use the same Help file format

as Windows version 3.1 does. But newer operating systems such as Windows 95

contains a new help file compiler, engine, and format. One reason that

Microsoft made this change was to improve international support.

One final idea you might want to consider is to develop your own converter

by using the MutltiByteToWideChar() API. In fact, this may be the best

approach, because application developers know exactly what kind of user

interface they want to implement.

Additional reference words: 1.20 3.50 kbinf

KBCategory: kbother

KBSubcategory: wintldev


Identifying a Previous Instance of an Application

PSS ID Number: Q106385

Authored 07-Nov-1993	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.1, 3.5

   3.51, and 4.0

SUMMARY

The entry point of both Windows and Windows NT applications is documented

to be:

   int WinMain( hInstance, hPrevInstance, lpszCmdLine, nCmdShow )

   HINSTANCE hInstance;        /* Handle of current instance  */

   HINSTANCE hPrevInstance;    /* Handle of previous instance */

   LPSTR lpszCmdLine;          /* Address of command line     */

   int nCmdShow;               /* Show state of window            */

However, under Windows NT, hPrevInstance is documented to always be NULL.

The reason is that each application runs in its own address space and may

have the same ID as another application.

To determine whether another instance of the application is running, use a

named mutex. If opening the mutex fails, then there are no other instances

of the application running. FindWindow() can be used with the class and

window name. However, note that a second instance of the application could

be started, and could execute the FindWindow() call before the first

instance has created its window. Use a named object to ensure that this

does not happen.

MORE INFORMATION

The fact that hPrevInstance is set to NULL simplifies porting Win16

applications. Most 16-bit Windows-based applications contain the following

logic:

   if( !hPrevInstance )

      if( !InitApplication(hInstance) )

         return FALSE;

Under Windows, window classes only are registered by the first instance of

an application. Consequently, if hPrevInstance is not NULL, then the window

classes have already been registered and InitApplication() is not called.

Under Windows NT, because hPrevInstance is always NULL, InitApplication()

is always called, and each instance of an application will correctly

register its window classes.

Additional reference words: 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrMisc


Identifying the Versions of International Windows

PSS ID Number: Q130062

Authored 10-May-1995	Last modified 16-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

 - Microsoft Win32 Software Development Kit (SDK) version 3.5

 - Microsoft Win32s version 1.2

SUMMARY

This article suggests three ways to check for the language used in an

international version of a Windows-based application.

MORE INFORMATION

Option One: Least Coding and Least Accurate

-------------------------------------------

Check the "sCountry" entry under the [intl] section of the WIN.INI file by

using the GetProfileString API. It is likely that this will match the

Windows language version. For example, German Windows will probably have

"Deutchland" and English Windows will probably have "United States" or

"United Kingdom." However, because the user can change this setting by

using the Control Panel, it is not always accurate.

Option Two: Most Coding and Most Accurate

-----------------------------------------

Check the "deflang" entry under the [data] section of the SETUP.INF file.

This is a three-letter language code that SETUP.EXE uses.  The setting will

be one of these:

  English=ENU or ENG

  Spanish=ESP

  German=DEU

  French=FRA or FRC (French Canadian)

  Italian=ITA

The problem with this method is getting at the "deflang" entry in  the

SETUP.INF file. The applications should parse SETUP.INF. It's not that

difficult, but it does involve extra coding.

Option Three: Let the User Choose

---------------------------------

Suggest to the user what the application found, and let the user make final

decision. Here's the algorithm:

   if Windows Version < 3.1

           Look at Win.ini, Setup.inf files

           Suggest a good guess and let the user choose;

           Register a profile string for your app;

   else

           Use version stamping;

For Windows version 3.1, the way to identify the character set is to use

the version stamping API. The translation value from the GetFileVersionInfo

when performed on GDI or SHELL.DLL is the only way in version 3.1 to find

out the character set of the system. Please refer to the SDK documentation

for more details on this API. Look for both GetFileVersionInfo and

VERSIONINFO.

The VERSIONINFO statement creates a version-information resource. The

resource contains information about the file such as its version number,

its intended operating system, and its original filename. One of the

parameters is langID, which specifies the language identifiers.

On Windows NT, look for the version resource information in one of the

system DLLs, such as KERNEL32.DLL. Look at result returned by

GetFileVersionInfo and its associated structures and references in the

Win32 API help file or documentation. This should be correct on Windows NT

version 3.5.

Additional reference words: 1.20 3.10 3.50 kbinf

KBCategory: kbother

KBSubcategory: wintldev


IME (Input Method Editor) Usage in Windows 95

PSS ID Number: Q118496

Authored 20-Jul-1994	Last modified 06-Apr-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Japanese

   Windows 95

SUMMARY

IMEs (Input Method Editors) are dynamic-link libraries that allow users to

type complex ideographic characters using a standard keyboard. IMEs are

available in Asian versions of the Microsoft Windows operating system, and

help minimize the effort needed by users to enter text containing

characters from Unicode and double-byte character sets (DBCS). IMEs relieve

users of the need to remember all possible character values. Instead, IMEs

monitor the user's keystrokes, anticipate the character the user may want,

and present a list of candidate characters from which to choose.

MORE INFORMATION

Asian versions of Windows 3.1 and Windows NT each have a separate IME

application programming interface (API). However, these APIs have been

merged into a single API for Windows 95.

Applications for Far East versions of Windows 95 can choose from three

levels of IME support:

1. IME-unaware: Merely retrieves double-byte characters through two WM_CHAR

   messages.

2. IME-aware: Takes control of the IME module's default user interface and

   properly handles Kanji strings passed to it by the IME.

3. Fully IME-aware: Controls the entire process of composing characters,

   including the display of intermediate keystrokes, and can customize the

   IME user interface.

IME, by default, provides an IME window through which users enter

keystrokes and view and select candidate characters. Applications developed

for the WIN32 APIs can use the Input Method Manager(IMM) functions and

messages to create and manage their own IME windows, providing a custom

interface while using the conversion capabilities of the IME.

Additional reference words: 4.00 international IME IMM

KBCategory: kbother

KBSubcategory: WIntlDev


Impersonation Provided by ImpersonateNamedPipeClient()

PSS ID Number: Q101378

Authored 12-Jul-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   version 3.1

SUMMARY

The following information is from the Win32 application programming

interface (API) "Programmer's Reference" in the section regarding

ImpersonateNamedPipeClient():

   BOOL ImpersonateNamedPipeClient(HANDLE hNamedPipe)

   The ImpersonateNamedPipeClient function impersonates a named-pipe

   client application.

The level of impersonation can be specified by the client when the named

pipe is opened. If the client does not explicitly specify a level, then the

default is SecurityImpersonation.

MORE INFORMATION

Suppose there are three threads (A, B, and C) where:

   A calls B

   B calls C

   B does a SecurityImpersonation of A

If A and B both specify dynamic tracking, then C can see the context of A

when it makes a call on the pipe, as long as B impersonates A. Otherwise, C

will see the context of A only if B was impersonating A when the pipe

between B and C was connected.

Note that dynamic tracking is not supported between machines.

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: BseSecurity


Implementing a "Kill" Operation in Windows NT

PSS ID Number: Q90749

Authored 21-Oct-1992	Last modified 02-Mar-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

SUMMARY

The following sample demonstrates how to implement a "kill" operation, such

as a UNIX ps/kill, under Windows NT. Note that PView will give you the PID

you need.

The code sample makes use of the Win32 API TerminateProcess(). While

TerminateProcess() does clean up the objects owned by the process, it does

not notify any DLLs hooked to the process. Therefore, one can easily leave

the DLL in an unstable state.

In general, the Task List is a much cleaner method of killing processes.

MORE INFORMATION

The following sample shows how to "kill" a process, given its process ID

(PID).

Sample Code

-----------

#include <windows.h>

#include <stdio.h>

void ErrorOut(char errstring[30])

/*

Purpose: Print out an meaningful error code by means of

         GetLastError and printf.

Inputs:  errstring - the action that failed, passed by the

                     calling proc.

Returns: none

Calls:   GetLastError

*/

{

   DWORD Error;

   Error= GetLastError();

   printf("Error on %s = %d\n", errstring, Error);

}

void main(int argc, char *argv[])

{

   HANDLE hProcess;

   DWORD ProcId;

   BOOL TermSucc;

   if (argc == 2)

   {

      sscanf(agrv[1],"%x", &ProcId);

      hProcess= OpenProcess(PROCESS_ALL_ACCESS, TRUE, ProcId);

      if (hProcess == NULL)

         ErrorOut("OpenProcess");

      TermSucc= TerminateProcess(hProcess, 0);

      if (TermSucc == FALSE)

         ErrorOut("TerminateProcess");

      else

         printf("Process# %.0lx terminated successfully!\n", ProcId);

   }

   else

   {

      printf("\nKills an active Process\n");

      printf("Usage: killproc ProcessID\n");

   }

}

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: BseProcThrd


Implementing a Line-Based Interface for Edit Controls

PSS ID Number: Q92626

Authored 11-Nov-1992	Last modified 12-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK, versions 3.50, 3.51, and 4.0

SUMMARY

In specific situations, it may be desirable to make multiline edit controls

behave similar to list boxes, such that entries can be selected and

manipulated on a per-line basis. This article describes how to implement

the line-based interface.

MORE INFORMATION

A multiline edit control must be subclassed to achieve the desired

behavior. The subclass function is outlined below.

Most of the work necessary to implement a line-based interface is done by

the predefined window function of the edit control class. With the return

value from the EM_LINEINDEX message, the offset of the line under the caret

can be determined; with the length of that line retrieved via the

EM_LINELENGTH message, the EM_SETSEL message can be used to highlight the

current line.

There are two problems with this approach:

 - The first problem is that the EM_LINEINDEX message, when sent to the

   control with wParam=-1, returns the line index of the caret, which is

   not necessarily the same as the current mouse position. Thus, upon

   receiving the WM_LBUTTONDOWN message, the subclass function should first

   call the old window function, which will set the caret to the character

   under the current mouse position, then compute the beginning and ending

   offsets of the corresponding line, and eventually set the selection to

   that line.

 - The other problem is that the WM_MOUSEMOVE message should be ignored by

   the subclassing function because otherwise the built-in selection

   mechanism will change the selection when the mouse is being dragged with

   the left mouse button pressed, thus defeating the purpose.

Following is the subclassing function that follows from this discussion:

WNDPROC EditSubClassProc(HWND hWnd,

               UINT wMsg,

               WPARAM wParam,

               LPARAM lParam)

{ int iLineBeg, iLineEnd;

  long lSelection;

  switch (wMsg)

  { case WM_MOUSEMOVE:

     break;                       /* Swallow mouse move messages.  */

    case WM_LBUTTONDOWN:          /* First pass on, then process.  */

     CallWindowProc((FARPROC)lpfnOldEditFn,hWnd,wMsg,wParam,lParam);

     iLineBeg = SendMessage(hWnd,EM_LINEINDEX,-1,0);

     iLineEnd=iLineBeg+SendMessage(hWnd,EM_LINELENGTH,iLineBeg,0);

#ifndef WIN32

     SendMessage(hWnd,EM_SETSEL,0,MAKELPARAM(iLeneBeg,iLineEnd));

#else

     SendMessage(hWnd,EM_SETSEL,iLineBeg,iLine)  /* Win 32 rearranges

                      parameters.  */

#endif

     break;

    case WM_LBUTTONDBLCLK:

     lSelection = SendMessage(hWnd,EM_GETSEL,0,0);

     /* Now we have the indices to the beginning and end of the line in

        the LOWORD and HIWORD of lSelection, respectively.

        Do something with it... */

     break;

    default:

return(CallWindowProc((FARPROC)lpfnOldEditFn,hWnd,wMsg,wParam,lParam));

};

return(0);

}

Additional reference words: 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrCtl


Importance of Calling DefHookProc()

PSS ID Number: Q74547

Authored 23-Jul-1991	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

When an application installs a hook using SetWindowsHook(), Windows adds

the hook's callback filter function to the hook chain. It is the

responsibility of each callback function to call the next function in the

chain. DefHookProc() is used to call the next function in the hook chain

for Windows 3.0. DefHookProc() is retained in Windows 3.1 for backwards

compatibility. For Windows 3.1, you should use CallNextHookEx() to call

the next function in the hook chain.

For Win32, mouse and keyboard hooks can suppress messages by return value

and do not have to call CallNextHookEx(), unless they want to pass the

message on. Other hooks, like WH_CALLWNDPROC, don't need to call

CallNextHookEx(), because it will be called by the system. However, all

hooks should call CallNextHookEx() immediately if nCode<0.

MORE INFORMATION

Windows 3.0

-----------

If a callback function does not call DefHookProc(), none of the filter

functions that were installed before the current filter will be called.

Windows will try to process the message and this could hang the system.

Only a keyboard hook (WH_KEYBOARD) can suppress a keyboard event by not

calling DefHookProc() and returning a 1. When the system gets a value of 1

from a keyboard hook callback function, it discards the message.

Windows 3.1

-----------

In Windows 3.1, the WH_MOUSE hook will work like the WH_KEYBOARD hook in

that the mouse event can be suppressed by returning 1 instead of calling

DefHookProc().

Furthermore, when the hook callback function receives a negative value for

the nCode parameter, it should pass the message and the parameters to

DefHookProc() without further processing. When nCode is negative, Windows

is in the process of removing a hook callback function from the hook chain.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: UsrHks


Improve System Performance by Using Proper Working Set Size

PSS ID Number: Q126767

Authored 01-Mar-1995	Last modified 03-Mar-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), version 3.5

SUMMARY

While increasing your working set size and locking pages in physical memory

can reduce paging for your application, it can adversely affect the system

performance. When making decisions for your application, it is important to

consider the whole system, and then test your application under a heavily

loaded system, such as the users of your application might have.

MORE INFORMATION

The Win32 SDK provides a tool called the working set tuner (WST.EXE). The

working set tuner decreases the working set size, which decreases memory

demand. However, you can also choose to set the process working set minimum

and maximum using SetProcessWorkingSetSize() and/or lock pages into memory

with VirtualLock(). These APIs should be used with care. Suppose you have a

16-megabyte system and you set your minimum to four megabytes. In effect,

this takes away four megabytes from the system. Other applications may be

unable to get their minimum working set. You or other applications may be

unable to create processes or threads or perform other operations that

require non-paged pool. This can have an extremely negative impact on the

overall system.

Reducing memory consumption is always a beneficial goal. If you call

SetProcessWorkingSetSize(0xffffffff, 0xffffffff), this tells the system

that your working set can be released. This does not change the current

sizing of the working set, it just allows the memory to be used by other

applications. It is a good idea to do this when your application goes into

a wait state. When you call SetProcessWorkingSet(0, 0), your working set is

reset to the default values. In addition, if you call VirtualUnlock() on a

range that was not locked, it is used as a hint that those pages can be

removed from the working set.

Additional reference words: 3.50

KBCategory: kprg

KBSubcategory: BseMm


Improving the Performance of MCI Wave Playback

PSS ID Number: Q77700

Authored 23-Oct-1991	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Software Development Kit (SDK) for Windows version 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

This article discusses two methods to improve playback performance for

a series of MCI wave files in an application developed for the

Microsoft Windows environment.

MORE INFORMATION

The following code fragment demonstrates opening the device and wave

file at the same time. This method does not give the best performance.

   mciopen.lpstrDeviceType = (LPSTR)"waveaudio";

   mciopen.lpstrElementName = (LPSTR)lpWavefile;

   // The following two fields must be initialized or the debugging

   // version of MMSYSTEM will cause an unrecoverable application

   // error (UAE).

   mciopen.lpstrDeviceType = "\0";

   mciopen.lpstrAlias = "\0";

   dwFlags = MCI_OPEN_TYPE | MCI_OPEN_ELEMENT;

   dwRes = mciSendCommand(0, MCI_OPEN, dwFlags,

                            (DWORD)(LPSTR)&mciopen);

To improve performance, open the device separately from the wave file

(element) and leave the device open until the last element in the

series has been played. Alternately, open and close elements but leave

the global (waveaudio) device open during the entire process. The

following code fragment demonstrates this process:

   // Open the waveaudio driver separate from the element.

   mciopen.lpstrDeviceType = (LPSTR)MCI_DEVTYPE_WAVEFORM_AUDIO;

   dwFlags = MCI_OPEN_TYPE;

   dwRes = mciSendCommand(0, MCI_OPEN, dwFlags,

                            (DWORD)(LPSTR)&mciopen);

The following code fragment demonstrates using the global device ID to

open the wave file separately:

   dwFlags = MCI_OPEN_ELEMENT;

   mciopen.lpstrElementName = (LPSTR)lpWaveName;

   dwRes = mciSendCommand(wGlobalDeviceID, MCI_OPEN, dwFlags,

                           (DWORD)(LPSTR)&mciopen);

This allows the application to open and play wave files without

incurring the performance penalty involved with opening the device.

Another method to speed loading a wave file is to use the fully

qualified path. For example, rather than specifying LASER.WAV, specify

C:\MMWIN\MMDATA\LASER.WAV. If this is done, MCI is not required to

search the directories in the MS-DOS PATH environment variable for the

wave file.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbmm kbprg

KBSubcategory: MMWave


Increased Performance Using FILE_FLAG_SEQUENTIAL_SCAN

PSS ID Number: Q98756

Authored 13-May-1993	Last modified 20-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

There is a flag for CreateFile() called FILE_FLAG_SEQUENTIAL_SCAN which

will direct the Cache Manager to access the file sequentially.

Anyone reading potentially large files with sequential access can specify

this flag for increased performance. This flag is useful if you are reading

files that are "mostly" sequential, but you occasionally skip over small

ranges of bytes.

MORE INFORMATION

The effect on the Cache Manager of this flag is two-fold:

 - There is a minor savings because the Cache Manager dispenses with

   keeping a history of reads on the file, and tries to maintain a

   high-water mark on read ahead, which is always a certain delta from

   the most recent read.

 - More importantly, the Cache Manager reads further ahead for

   sequential access files--currently about three times more than

   files that are currently detected for sequential access.

If the caller makes multiple passes through a file, there are no negative

effects of specifying the sequential flag, because the Cache Manager will

still disable read ahead for as long as the application is getting hits on

the file (such as on the second or subsequent pass).

If you are working on an application where your ability to sequentially

read file data is key to performance, you may want to consider adding the

sequential flag to your create file call. This is especially true of

applications that use this flag to read from a CD-ROM.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: BseFileio


Initializing Menus Dynamically

PSS ID Number: Q75630

Authored 26-Aug-1991	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

Many commercial applications developed for Windows allow the user to

customize the menus of the application. This ability introduces some

complexity when the application must disable particular menu items at

certain times. This article provides a method to perform this task.

Windows sends a WM_INITMENUPOPUP message just before a pop-up menu is

displayed. The parameters to this message provide the handle to the menu

and the index of the pop-up menu on the main menu.

To process this message properly, each menu item must have a unique

identifier. When the application starts up, it creates a mapping array that

lists the items on each menu. When the WM_INITMENUPOPUP message is

received, the application checks the conditions necessary for each menu

item to be disabled or checked and modifies the menu appropriately.

The application must maintain the mapping array when the user modifies the

menus in any way.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrMen


Installing the Win32s NLS Files

PSS ID Number: Q124136

Authored 19-Dec-1994	Last modified 25-Apr-1995

The information in this article applies to:

 - Microsoft Win32s version 1.2

SUMMARY

The help file for Win32s version 1.2 states that the following NLS files

need to be installed in the <windows>\SYSTEM\WIN32S directory when you

install Win32s version 1.2 with your application. However, if your

Win32-based application is only targeting U.S. Windows, you do not need to

install all these files.

   .NLS files:

   CTYPE.NLS                             P_850.NLS

   LOCALE.NLS                            P_852.NLS

   L_INTL.NLS                            P_855.NLS

   P_037.NLS                             P_857.NLS

   P_10000.NLS                           P_860.NLS

   P_10001.NLS                           P_861.NLS

   P_10006.NLS                           P_863.NLS

   P_10007.NLS                           P_865.NLS

   P_10029.NLS                           P_866.NLS

   P_10081.NLS                           P_869.NLS

   P_1026.NLS                            P_875.NLS

   P_1050.NLS                            P_932.NLS

   P_1051.NLS                            P_936.NLS

   P_1252.NLS                            P_949.NLS

   P_1053.NLS                            P_950.NLS

   P_1054.NLS                            SORTKEY.NLS

   P_437.NLS                             SORTTBLS.NLS

   P_500.NLS                             UNICODE.NLS

   P_737.NLS

MORE INFORMATION

Use the following guidelines when shipping a Win32-based application that

targets Win32s:

Ship National Language Support (.NLS) files corresponding to the market of

the Win32-based application. For a Win32-based application released for an

international market, ship all the .NLS files found in MSTOOLS\WIN32S\NLS.

For a Win32-based application released for use only in the United States,

ship P_437.NLS, P_850.NLS, and P_1252.NLS.

NOTE: When installing Win32s, be sure to remove the obsolete files. These

are tagged in WIN32S\SETUP\W32S.LYT with Win32sSystemObsoleteFiles.

Additional reference words: 1.20

KBCategory: kbusage kbpolicy kbdocerr

KBSubcategory: W32s


Instance-Specific String Handles (HSZs) in DDEML

PSS ID Number: Q94953

Authored 26-Jan-1993	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

Instance-specific string handles in DDEML may be used in DdeConnect()

or DdeConnectList() in order to connect to a particular instance of a

server. These string handles are received by a DDEML callback as the

HSZ2 parameter to the XTYP_REGISTER/XTYP_UNREGISTER transactions

whenever a server application registers or unregisters the service

name it supports.

This article explains how instance-specific HSZs are internally

implemented in the Windows 3.1 DDEML; however, this is for purposes of

illustration only because the implementation may change in future versions

of DDEML, particularly in Win32. However, the behavior will be the same.

MORE INFORMATION

Currently, instance-specific string handles contain two pieces of

information: the original service name string plus the handle to a

hidden window created by DDEML, which is associated with that string.

These two pieces of information are then merged [that is, MAKELONG

(SvcNameAtom, hWnd)] into an HSZ.

It is important to underscore what the documents on

DdeCreateStringHandle() say in reference to instance-specific HSZs

(see the Comments section of the Windows 3.1 Software Development Kit

(SDK) "Programmer's Reference, Volume 2: Functions," page 169):

   An instance-specific string handle is not mappable from string

   handle to string to string handle again. The DdeQueryString()

   function creates a string from a string handle and then

   DdeCreateStringHandle() creates a string handle from that string,

   but the two handles are not the same.

This might be better explained as follows:

1. Server registers itself:

      0x0000C18F = DdeCreateStringHandle (,"SERVER",);

      DdeNameService (,0x0000C18F,,);

2. Callbacks receive two HSZs in XTYP_REGISTER:

      HSZ1 = 0x0000C18F  (normal HSZ)

      HSZ2 = 0x56F8C18F  (instance-specific HSZ)

3. Client does a DdeQueryString() on the HSZ2 returned above, and

   creates a string handle with the string returned.

      DdeQueryString (,0x56F8C18F, myLpstr,,,);

            // where myLpstr returned = "SERVER:(56F8)"

      0x0000C193= DdeCreateStringHandle (,myLpstr,);

   Note how instance-specific 0x56F8C18F passed in to DdeQueryString()

   is not the same as the HSZ returned (0x0000C193) from the

   DdeCreateStringHandle() on the same string; whereas regular string

   handles (that is, non-instance-specific HSZs) would have mapped to

   the same string handle.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: UsrDde


Intergraph's NFS causes WinSock APIs to return error 10093

PSS ID Number: Q127015

Authored 08-Mar-1995	Last modified 13-Mar-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.5

SYMPTOMS

The presence of Intergraph's NFS (Network File System) may cause Windows

Sockets applications to function incorrectly. Specifically, if the 'Choose

File' common dialog is displayed in a Windows Sockets application,

subsequent Windows Sockets API calls may return error 10093,

WSAENOTINITIALIZED.

STATUS

This problem has been corrected in an updated version of PC-NFS, version

2.0.8.0. The update is available from Intergraph's FTP server or bulletin

board (IBBS): (205) 730-7248. For more information, please call Intergraph

technical support at (800) 633-7248.

MORE INFORMATION

Steps to Reproduce Problem

--------------------------

1. Call WSAStartup(...).

2. Call any WinSock API function to verify that WSOCK32.DLL is initialized.

3. Call GetOpenFileName to display the 'Open File' common dialog.

4. Call any WinSock API function. If Intergraph's NFS implementation is

   installed, you may receive error 10093.

Additional reference words: 3.50 Windows Sockets

bug CFileDialog

KBCategory: kbprg

KBSubcategory: NtwkWinsock


International Versions of Windows 95

PSS ID Number: Q118495

Authored 20-Jul-1994	Last modified 06-Apr-1995

The information in this article applies to:

 -  Microsoft Win32 Software Development Kit (SDK)

SUMMARY

Microsoft Windows version 3.1 is available in 27 different language

versions. Windows 95 will also be released in 27 different language

versions, with possibly more versions following later.

MORE INFORMATION

There are three categories of the Windows 95 platform:

1. Western and Eastern European languages, plus Indonesian, which are

   based on single-byte character sets (SBCSs) and are written from left to

   right:

      English

      German

      French

      Spanish

      Swedish

      Dutch

      Italian

      Norwegian

      Danish

      Finnish

      Portuguese-Brazil

      Portuguese-Portugal

      Russian

      Czech

      Polish

      Hungarian

      Turkish

      Greek

      Basque

      Catalan

      Indonesian

2. Middle East languages, plus Thai, which are based on SBCSs from both

   right to left and left to right:

      Arabic

      Hebrew

      Thai

3. Far East languages, which are based on double-byte character

   sets (DBCSs) and are written from both left to right and, in certain

   types of applications, from top to bottom:

      Japanese

      Korean

      Simplified Chinese

      Traditional Chinese

Additional reference words: 4.00 versions international

KBCategory: kbother

KBSubcategory: WIntlDev


Interpreting Executable Base Addresses

PSS ID Number: Q101187

Authored 07-Jul-1993	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

LINK.EXE and DUMPBIN.EXE (from Visual C++ 32-bit edition) can be used to

dump the portable executable (PE) header of an executable file. Below is a

fragment of a dump:

   7300 address of entry point

   7000 base of code

   B000 base of data

        ----- new -----

   10000 image base

The "image base" value of 10000 is the address where the program begins in

memory. The value associated with "base of code," "base of data," and

"address of entry point" are all offsets from the image base.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbtool

KBSubcategory: TlsMisc


Interprocess Communication on Windows NT, Windows 95, &

PSS ID Number: Q95900

Authored 01-Mar-1993	Last modified 22-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

The following are some of the standard mechanisms available for

interprocess communication (IPC): NetBIOS, mailslots, windows sockets

(winsock), named pipes, anonymous pipes, semaphores, shared memory, and

shared files. Other IPC mechanisms available on Microsoft systems include

DDE, OLE, memory-mapped files, Windows messages, Windows atoms, the

registration database, and the clipboard.

MORE INFORMATION

The table below denotes what platforms and subsystems provide which IPC

mechanisms (this does not imply that all the mechanisms will interoperate

between different subsystems):

Interprocess Communication Mechanisms

-------------------------------------

   IPC Mechanism  WinNT  Win95  Win32s(1)  Win16(2)  MS-DOS(2)  POSIX  OS/2

   -------------  -----  -----  ---------  --------  ---------  -----  ----

             DDE  YES    YES    YES        YES        NO         NO     NO

             OLE  YES     NO    YES        YES        NO         NO     NO

         OLE 2.0  YES    YES     NO        YES        NO         NO     NO

         NetBIOS  YES    YES    YES        YES       YES         NO    YES

     Named pipes  YES    YES(3) YES(3)     YES(3)    YES(3)     YES(4) YES

 Windows sockets  YES(5) YES    YES        YES(5)     NO         NO(6)  NO

       Mailslots  YES    YES    YES(3)      NO        NO         NO    YES

      Semaphores  YES    YES     NO         NO        NO        YES    YES

             RPC  YES    YES(7) YES(8)     YES       YES         NO     NO

 Mem-Mapped File  YES    YES    YES         NO        NO         NO     NO

     WM_COPYDATA  YES    YES    YES(9)     YES        NO         NO     NO

(1) Win32s an extension to Windows 3.1, which allows Win32-based

    applications to run under Windows 3.1. Win32s supports all the Win32

    APIs, but only a subset provides functionality under Windows 3.1. Those

    APIs that are not functional return ERROR_CALL_NOT_IMPLEMENTED.

(2) This is technically not a subsystem.

(3) Cannot be created on Win16, Windows 95 and MS-DOS workstations, but can

    be opened.

(4) The POSIX subsystem supports FIFO queues, which do not interoperate

    with Microsoft's implementation of named pipes.

(5) Via the Windows sockets API.

(6) Currently BSD-style sockets are under consideration for the POSIX

    subsystem.

(7) Windows 95 supports the RPC 1 protocol only. The NetBios protocol is

    not supported. Namedpipe servers are not supported.

(8) Win32s version 1.1 provides network support through Universal Thunks.

(9) Under Win32s, WM_COPYDATA does not actually copy the data -- it

    only translates the pointers to the data. If the receiving application

    changes the buffer, then the data is changed for both applications.

Additional reference words: 3.10 3.50 4.00

KBCategory: kbprg

KBSubcategory: BseIpc


Interrupting Threads in Critical Sections

PSS ID Number: Q101193

Authored 07-Jul-1993	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

If a thread enters a critical section and then terminates abnormally, the

critical section object will not be released. Many components of the C

Run-time library are not reentrant and use a resource locking scheme to

maintain coherency in the multithreaded environment. Thus, a thread that

has entered a C Run-time function, such as printf(), could deadlock all

access (within that process) to printf() if it terminates abnormally.

This situation could arise if a thread is terminated with TerminateThread()

while it holds a resource lock. If this occurs, any thread that tries to

acquire that resource lock will become deadlocked.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: BseMisc


Inverting Color Inverts Palette Index, Not RGB Value

PSS ID Number: Q71227

Authored 10-Apr-1991	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

Performing any bitwise logical operator on a color, such as inversion,

does not modify the color's RGB value; it instead changes the index

into the system palette. This applies also to the ROP codes associated

with the blt functions (BitBlt, StretchBlt, and PatBlt) and in

the SetRop2 function. For display devices with hardware palettes

[generally, devices with fewer than 24 bits-per-pixel (BPP)], this can

produce unexpected or undesirable results.

MORE INFORMATION

Suppose the system palette contained the following colors:

                                   Entry #

   Color      0      1      2      3      4      5      6      7

   -----

   Red   =    0   0x80      0      0   0x80   0x80      0   0x80

   Green =    0      0   0x80      0   0x80      0   0x80   0x80

   Blue  =    0      0      0   0x80      0   0x80   0x80   0x80

                                   Entry #

   Color      8      9      A      B      C      D      E      F

   -----

   Red   = 0xC0   0xFF      0      0   0xFF   0xFF      0   0xFF

   Green = 0xC0      0   0xFF      0   0xFF      0   0xFF   0xFF

   Blue  = 0xC0      0      0   0xFF      0   0xFF   0xFF   0xFF

The inversion of colors would look like this:

(Half = half intensity, Full = full intensity)

   Color          Index      Inverse Color   Index

   -----          -----      -------------   -----

   Black              0      White               F

   Half Red           1      Full Cyan           E

   Half Green         2      Full Magenta        D

   Half Blue          3      Full Yellow         C

   Half Yellow        4      Full Blue           B

   Half Magenta       5      Full Green          A

   Half Cyan          6      Full Red            9

   Dark Gray          7      Light Gray          8

This obviously is not the desired effect. Inverting a full-intensity

color such as red will not invert to full-intensity cyan; instead, it

is inverted to half-intensity cyan.

This is also true for any logical operations performed on the bits of

a bitmap, pen, or flood fill through ROP codes. All operations are

done on the index of the color and not its RGB value.

Note that when using custom palettes on a palette capable device, the

application does not have control over the precise mapping between

logical palette indexes and system palette indexes. The results of

bitwise logical operations are unpredictable in such a case.

The only way for an application to precisely control color mixing is

to perform the operation on RGB values, then translate the RGB result

back into the most appropriate palette index.

For example, one way to do this is to mix colors in a 24 BPP

device-independent bitmap (DIB), then set the DIB bits into the device

context (DC) again when finished. Another method is to query the RGB

color of pixels to modify, do the mixing, and then use the SetPixel

function to apply the change to the DC.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: GdiPal


Joliet Specification for CD-ROM

PSS ID Number: Q125630

Authored 01-Feb-1995	Last modified 06-Apr-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

Content authors who are developing Windows 95 applications on CD-ROM should

develop their titles according to the Joliet specification in order to

incorporate Unicode file names and take full advantage of Windows 95 long

file name support.

The Joliet specification complies with the ISO 9660:1988 standard. It is

designed to resolve some of its restrictions and ambiguities including:

 - Character Set limitations.

 - File Name Length limitations.

 - Directory Tree Depth limitations.

 - Directory Name Format limitations.

 - Unicode Character ambiguities.

Because the Joliet specification is ISO 9660 compliant, CD-ROM disks

recorded according to the Joliet specification may continue to interchange

data with non-Joliet systems. The designs for the System Use Sharing

Protocol, Rock Ridge extensions for POSIX semantics, CD-XA System Use Area

Semantics, and Apple's Finder Flags and Resource Forks all port in a

straightforward manner to the Joliet specification. These protocols are not

an integral part of the Joliet specification, however.

Support for Joliet is included in Windows 95 and will also be included in a

future version of Windows NT. To obtain a copy of the Joliet specification,

send email to mmdinfo@microsoft.com.

Additional reference words: 4.00 CD CD-ROM XA SUSP ROCKRIDGE LFN

KBCategory: kbprg

KBSubcategory: SubSys


Journal Hooks and Compatibility

PSS ID Number: Q106717

Authored 14-Nov-1993	Last modified 03-Mar-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

SUMMARY

Journal hooks are used to record and play back events, such as keyboard and

mouse events. Journal hooks are system-wide hooks that take control of all

user input, and therefore should be used as little as possible.

MORE INFORMATION

Note that Windows NT does not ship with a Recorder application, as Windows

3.1 does. Therefore, it may be desirable to create an application that can

play back macros recorded under Windows 3.1. However, there are a number of

different problems with the Windows NT implementation of journaling that

make it difficult to use macros recorded under Windows 3.1.

The EVENTMSG structures recorded under Windows 3.1 that hold keystrokes do

not play back under Windows NT. They must be modified, because the journal

playback hook parses a scan code out of the EVENTMSG structure differently

than the Windows 3.1 journal record hook put it in the structure. Under

Windows 3.1, paramH specifies the repeat count. Under Windows NT, there is

no way to specify a repeat count; it is always assumed to be 1.

For more information on hooks, please see the Hooks Overview in Volume 1 of

the Win32 "Programmer's Reference" and the article "Win32 Hooks" included

in the MSDN CD #5.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: UsrHks


Jumping to a Keyword in the Middle of a Help Topic

PSS ID Number: Q94611

Authored 11-Jan-1993	Last modified 23-Jun-1995

---

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

---

SUMMARY

The following information was extracted from the Windows Help Authoring

Guide available on the Microsoft Developer's Network CD-ROM:

   Placing Keywords in the Topic

   When the user goes to a topic by choosing a keyword from the Search

   dialog box, Help displays the selected topic in the main window,

   starting from the beginning of the topic. If the information related to

   the keyword is located in the middle or toward the end of the topic, the

   user may not be able to see the relevant information without scrolling

   the topic. This result may not be what you want.

   If you want users to be able to go directly to relevant information

   within a topic (and see it without scrolling), you can place additional

   keywords with the information you want users to find. Keywords placed

   within a topic function as spot references (similar to context-string

   spot references) because they index specific locations, or "spots,"

   within the topic. To access the spot-referenced material, users choose

   the keyword from the Search dialog box.

   In the Search dialog box, all keywords appear the same. The user cannot

   tell the difference between keywords placed at the beginning of the

   topic and those placed elsewhere in the topic. However, when the user

   goes to the topic, Windows Help uses the location of the keyword

   footnote as a reference point. If the keyword footnote is located in the

   middle of the topic, Help displays the topic as if the middle location

   were the "top" of the topic.

   NOTE:

   Because you cannot insert a title footnote in the middle of a topic, any

   keywords that you place in the middle of the topic use the main topic

   title in the Search dialog box.

   To define a keyword in the middle of the topic:

   1. Place the insertion point where you want to define the keyword. A

      keyword inserted anywhere except the beginning of the topic is

      treated as a spot reference.

   2. From the Insert menu, choose Footnote. The Footnote dialog box

      appears.

   3. Type an uppercase K as the custom footnote mark, and then choose OK.

      A superscript K appears in the text window, and the insertion point

      moves to the footnote window.

   4. Type the keyword(s) to the right of the K in the footnote window. Use

      only a single space between the K and the first keyword. Separate

      multiple keywords with a semicolon (;).

Additional reference words: 3.10 3.50 4.00 95 winhelp hc

KBCategory: kbprg

KBSubcategory: TlsHlp


LB_GETCARETINDEX Returns 0 for Zero Entries in List Box

PSS ID Number: Q97922

Authored 25-Apr-1993	Last modified 12-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.1, 3.5,

   and 4.0

To determine whether a multiple selection list box is empty or has no items

to select, two messages are required. First, call LB_GETCOUNT to determine

whether or not the list box is empty. If the list box is not empty, then

use LB_GETCARETINDEX to determine the position of the caret.

If you want a list box to contain selections that remain after the focus

goes elsewhere, Microsoft recommends using visible check marks next to the

items in the list box. This method provides better visual feedback to the

user than a selection bar.

Additional reference words: 3.50 3.51 4.00 95 listbox

KBCategory: kbprg

KBSubcategory: UsrCtl


Length of STRINGTABLE Resources

PSS ID Number: Q20011

Authored 17-Dec-1987	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

In order to find the length of a string in the STRINGTABLE you need to

do a FindResource() and then a SizeofResource() to find the total size

in bytes of the current block of 16 strings. Remember that

STRINGTABLEs are stored specially; to FindResource() you will ask for

RT_STRING as the Type, and the (string number / 16) + 1 as the name.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrRsc


Limit on the Number of Bytes Written Asynchronously

PSS ID Number: Q98893

Authored 18-May-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

SUMMARY

There is a limit to the number of bytes that can be written with

WriteFile() using asynchronous I/O (FILE_FLAG_OVERLAPPED specified). This

limit depends on the size of your system.

Asynchronous (overlapped) I/O consumes system resources for a long time.

For example, the memory used is locked in the process working set until the

I/O completes. To limit the amount of system resources used asynchronously

by an application, the system charges asynchronous I/O to the working set

of the process requesting the I/O.

While the working set size is dynamically raised and lowered based on the

load, there are minimum and maximum values. These values are based on

system size: consider up to 12 megabytes (MB) a small system, between 12 MB

and 19 MB a medium system, and greater than 19 MB a large system. Each

process is guaranteed a minimum working set for performance reasons; about

120K for small systems, 160K for large systems, and 245K for large systems.

When system resources are heavily taxed, a process is confined to its

maximum working set. Asynchronous I/Os may never cause you to exceed your

maximum working set, because once you are allowed to initiate an

asynchronous I/O, the page cannot be taken away if memory becomes tight.

The maximum working set sizes are about 300K for a small system, 716K for a

medium system, and 1.5 MB for a large system.

MORE INFORMATION

The following code can be used to experiment with the maximum number of

bytes that can be written using asynchronous I/O. Simply change the line to

vary the number of bytes that the code attempts to write:

   #define NBR_BYTE 700000

Sample Code

-----------

#include <stdio.h>

#include <stdlib.h>

#include <malloc.h>

#include <assert.h>

#include <windows.h>

#define NBR_BYTE 700000

int main(void)

{

   char        *c;

   HANDLE      hFile;

   DWORD       byteWrite;

   OVERLAPPED  overLap;

   DWORD       err;

   BOOL        result;

   c = malloc( NBR_BYTE );

   assert( c != NULL );

   overLap.hEvent = CreateEvent( NULL, FALSE, FALSE, "event1" );

   assert( overLap.hEvent );

   hFile = CreateFile( "test", GENERIC_WRITE, 0,  NULL, OPEN_ALWAYS,

                       FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED |

                       FILE_FLAG_WRITE_THROUGH,

                       NULL);

   if( hFile == INVALID_HANDLE_VALUE )

   {

      free( c );

      printf( "error opening file\n" );

      exit( 0 );

   }

   overLap.Offset     = 0;

   overLap.OffsetHigh = 0;

   result = WriteFile( hFile, c, NBR_BYTE, &byteWrite, &overLap );

   if( result == FALSE )

   {

      err = GetLastError( );

      if( err != ERROR_IO_PENDING )

      {

         free( c );

         printf( "Error: %d\n", GetLastError() );

         exit( 0 );

      }

   }

   free( c );

   return 0;

}

Additional reference words: 3.10 asynch

KBCategory: kbprg

KBSubcategory: BseFileio


Limitations of Overlapped I/O in Windows 95

PSS ID Number: Q125717

Authored 02-Feb-1995	Last modified 06-Apr-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

SUMMARY

Windows 95 does not support overlapped operations on files, disk, pipes, or

mail slots, but does support overlapped operations on serial and parallel

communication ports. Non-overlapped file write operations are similar to

overlapped file writes, because Windows 95 uses a lazy-write disk cache.

Overlapped I/O can be implemented in a Win32-based application by creating

multiple threads to handle I/O.

MORE INFORMATION

Asynchronous I/O on files, disk, pipes and mail slots is not implemented in

Windows 95. If a Win32-based application running on Windows 95 attempts to

perform asynchronous file I/O (such as ReadFile() with any value other than

NULL in the lpOverlapped field) on any of these objects, the ReadFile()  or

WriteFile fails and GetLastError() returns ERROR_INVALID_PARAMETER (87).

Overlapped I/O to serial and parallel communication ports is fully

supported in Windows 95. To implement overlapped I/O, call CreateFile()

with the FILE_FLAG_OVERLAPPED flag set in the flags attribute.

Overlapped I/O on disk and files was not implemented in Windows 95, because

the added performance benefits (which would only affect a certain class of

I/O-intensive applications) were not judged to be worth the extra cost.

The system uses a lazy-write disk cache algorithm which automatically

provides many of the benefits of overlapped writes. When a process writes

data to a file, the data is written to the cache and then the write

immediately returns to the calling process. Then, at some later time, the

cache manager writes the data to disk. This is similar to behavior that is

achieved with overlapped I/O. In the case of disk/file reads, many

applications that need to read data do so because it is needed for further

processing. Some applications benefit greatly by prefetching data from

files while doing other work.

Although Windows 95 does not implement overlapped I/O, it is possible for

Win32-based applications on Windows 95 to create additional threads for

implementing an effect similar to overlapped file I/O. One way to implement

this effect is to communicate with an I/O thread using a request packet

mechanism. The thread can queue request packets from other threads and

service them as it is able, signalling the other threads on the completion

of each request with an event. Even though the application may be "waiting"

on some I/O activity, it can still be responsive to the user since the

main, or user interface, thread is not blocking on I/O requests. However,

the use of multiple threads will increase the amount of time spent in the

kernel, which leads to inefficiencies, as compared with an operating system

that supports overlapped I/O.

NOTE: Windows NT has a lazy-write disk cache as well. It has been found

that a write-back cache is not as good as overlapped I/O, particularly when

the data is much larger than the file cache or noncached I/O. One of the

biggest benefits of overlapped I/O is that it allows you to quickly get

lots of outstanding I/O posted to the disk controller, thereby keeping the

disks busy with tagged command queueing in the controller. Using multiple

threads is a reasonable substitute, but I/O may be serialized in the

filesystem.

Additional reference words: 4.00 95 asynchronous overlapped

KBCategory:  kbprg

KBSubcategory: BseFileio


Limitations of WINOLDAP's Terminal Fonts

PSS ID Number: Q117742

Authored 06-Jul-1994	Last modified 18-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   version 3.1

 - Microsoft Win32 SDK, version 3.1

SUMMARY

The MS-DOS prompt window (WINOLDAP) uses a set of private "Terminal" fonts.

Applications developed for the Windows Graphical Environment should not

rely on these fonts.

MORE INFORMATION

WINOLDAP uses Terminal-like fonts to present its output in the Enhanced

mode. The font resources are loaded when WINOLDAP is launched and are

removed when it terminates. To verify this, run a ChooseFont common dialog

box (such as the one in FONTEST sample in the SAMPLES directory of the

Windows 3.1 SDK) when WINOLDAP is not running. Launch WINOLDAP and notice

that "Terminal" fonts are added to the list of fonts in the common dialog

box.

Developers whose applications benefit from Terminal-like fonts may try to

use Terminal fonts out of convenience. However, it is important to realize

that these fonts (DOSAPP.FON, EGA40WOA.FON, EGA80WOA.FON, CGA40WOA.FON, AND

CGA80WOA.FON) are unlike the standard fonts in that they are shipped for

use by WINOLDAP. The standard Windows fonts are guaranteed to be available

in future versions of Windows; such guarantees do not apply to the Terminal

fonts. The Terminal fonts have actually been altered from version 3.0 to

version 3.1 of Microsoft Windows. A simple resolution to this lack of

guarantee is to ship the fonts along with the application. These fonts,

however, may not be shipped freely with third-party applications without

permission from Microsoft.

The paragraph above may lead you to believe that applications running

exclusively under Microsoft Windows version 3.1 can rely on the Terminal

fonts for the applications' displays because all Windows-based

applications, by default, have the above fonts installed. However, a bug in

WINOLDAP denies applications that benefit: When the last WINOLDAP session

exits, it removes the DOSAPP.FON module twice. Any application with the

DOSAPP.FON module loaded then loses the fonts without prior notice.

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: GdiFnt


Limiting the Number of Entries in a List Box

PSS ID Number: Q78241

Authored 10-Nov-1991	Last modified 16-May-1995

-

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK), versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

-

SUMMARY

Although there is no single message that restricts the number of

entries (lines) allowed in a list box, the limit can be imposed

through the use of subclassing.

MORE INFORMATION

The following code fragment is an excerpt from a subclassing function

that can be used to restrict the number of entries in a list box to no

more than the constant MAXENTRIES where the lpfnOldLBFn variable

points to the original list box window procedure:

long FAR PASCAL SubClassFn(hWnd, message, wParam, lParam)

HWND hWnd;

unsigned message;

WORD wParam;

LONG lParam;

{

   int iCount;

   switch (message)

      {

   case LB_ADDSTRING:

   case LB_INSERTSTRING:

      iCount = SendMessage(hWnd, LB_GETCOUNT, 0, 0L);

      if (iCount > MAXENTRIES)

         { /* Insert action here to inform user of limit violation */

         break;

         }

      /* fall through if less entries than maximum */

   default:

      return CallWindowProc(lpfnOldLBProc, hWnd, message, wParam,

            lParam);

      }

}

Additional reference words: 3.00 3.10 3.50 4.00 95 list box

KBCategory: kbprg

KBSubcategory: UsrCtl


Limits on Overlapped Pipe Operations

PSS ID Number: Q115522

Authored 29-May-1994	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   versions 3.1 and 3.5

SUMMARY

The Windows NT version 3.1 redirector allows only 17 outstanding overlapped

pipe operations at any given time. The Windows NT 3.5 redirector does

not have this restriction on overlapped pipe writes. However, the Windows

NT 3.5 redirector allows only 17 outstanding overlapped pipe reads at any

given time.

If the client uses overlapped I/O through the redirector, it is possible

for the client to become deadlocked. You may need to increase the number of

threads that the redirector uses for I/O; the same thing is true for the

server. If your application is doing a lot of I/O, you can avoid this

deadlock by creating extra threads and having them use non-overlapped I/O.

MORE INFORMATION

Increasing the workstation services MaxThreads parameter increases the

number of kernel threads that the redirector will create, thus allowing

more operations to be outstanding at any given time.

This parameter is located in:

   HKEY_LOCAL_MACHINE\SYSTEM\

      CurrentControlSet\

      Services\

      LanmanWorkstation\

      Parameters\

      MaxThreads

The parameter can be set from 0 to 255 (the default is 17).

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseFileio


Line Continuation and Carriage Returns in String Tables

PSS ID Number: Q44385

Authored 12-May-1989	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit for Windows

   versions 3.1 and 3.0

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

The RC compiler does not offer a line-continuation symbol for strings in

string tables.

To force a carriage return into a long line of text, use one of the methods

described below.

One method is to force the carriage return using \012\015. The following

example demonstrates the use of \012\015 and should be considered to be on

one continuous line:

   STRINGTABLE

   BEGIN

   IDSLONGSTRING, "This is a long line of text so I would like \012\015

   to force a carriage return."

   END

For more information on this method, query in the Microsoft Knowledge

Base on the following words:

   STRINGTABLE WinLoadString

Another method of forcing a carriage return is to press ENTER and

continue the line on the next line. The following example will force

a carriage return after the word "like."

   STRINGTABLE

   BEGIN

   IDSLONGSTRING, "This is a long line of text so I would like

   to force a carriage return"

   END

If you try to use the \n or other \ characters, the RC compiler will ignore

them.

NOTE: There is a 255-character limit (per string) in a string table. For

more information on this limit, please query on the following words in the

Microsoft Knowledge Base:

   STRINGTABLE length 255

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbtool

KBSubcategory: TlsRc


List All NetBIOS Names on a Lana

PSS ID Number: Q124960

Authored 17-Jan-1995	Last modified 23-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.1 and 3.5

SUMMARY

You can get a list of NetBIOS names for a lana by using the Adapter Status

NetBIOS request and using the "*" character as the call name. However, on

Windows NT, this method lists only the names added by the current process.

If you want to list all of the NetBIOS names on the lana, use a unique

local name as the call name. This method causes the Adapter Status to be

treated as a remote call, which will disable the "filtering" of names added

by other processes. The sample code below demonstrates this technique.

SAMPLE CODE

-----------

/* The following makefile may be used to build this sample:

 !include <ntwin32.mak>

 PROJ = test.exe

 DEPS = test.obj

 LIBS_EXT = netapi32.lib

 .c.obj:

   $(cc) /YX $(cdebug) $(cflags) $(cvars) $<

 $(PROJ) : $(DEPS)

   $(link) @<<

 $**

 -out:$@

 $(conlibs)

 $(conlflags)

 $(ldebug)

 $(LIBS_EXT)

 <<

*/

#include <windows.h>

#include <stdio.h>

#include <string.h>

/*

 * LANANUM and LOCALNAME should be set as appropriate for

 * your system

 */

#define LANANUM     0

#define LOCALNAME   "MAKEUNIQUE"

#define NBCheck(x)  if (NRC_GOODRET != x.ncb_retcode) { \

                        printf("Line %d: Got 0x%x from NetBios()\n", \

                               __LINE__, x.ncb_retcode); \

                    }

void MakeNetbiosName (char *achDest, LPCSTR szSrc);

BOOL NBAddName (int nLana, LPCSTR szName);

BOOL NBReset (int nLana, int nSessions, int nNames);

BOOL NBListNames (int nLana, LPCSTR szName);

BOOL NBAdapterStatus (int nLana, PVOID pBuffer, int cbBuffer,

                      LPCSTR szName);

void

main ()

{

    if (!NBReset (LANANUM, 20, 30))

        return;

    if (!NBAddName (LANANUM, LOCALNAME))

        return;

    if (!NBListNames (LANANUM, LOCALNAME))

        return;

    printf ("Succeeded.\n");

}

BOOL

NBReset (int nLana, int nSessions, int nNames)

{

    NCB ncb;

    memset (&ncb, 0, sizeof (ncb));

    ncb.ncb_command = NCBRESET;

    ncb.ncb_lsn = 0;            /* Allocate new lana_num resources */

    ncb.ncb_lana_num = nLana;

    ncb.ncb_callname[0] = nSessions;  /* max sessions */

    ncb.ncb_callname[2] = nNames;  /* max names */

    Netbios (&ncb);

    NBCheck (ncb);

    return (NRC_GOODRET == ncb.ncb_retcode);

}

BOOL

NBAddName (int nLana, LPCSTR szName)

{

    NCB ncb;

    memset (&ncb, 0, sizeof (ncb));

    ncb.ncb_command = NCBADDNAME;

    ncb.ncb_lana_num = nLana;

    MakeNetbiosName (ncb.ncb_name, szName);

    Netbios (&ncb);

    NBCheck (ncb);

    return (NRC_GOODRET == ncb.ncb_retcode);

}

/*

 * MakeNetbiosName - Builds a name padded with spaces up to

 * the length of a NetBIOS name (NCBNAMSZ).

 */

void

MakeNetbiosName (char *achDest, LPCSTR szSrc)

{

    int cchSrc;

    cchSrc = lstrlen (szSrc);

    if (cchSrc > NCBNAMSZ)

        cchSrc = NCBNAMSZ;

    memset (achDest, ' ', NCBNAMSZ);

    memcpy (achDest, szSrc, cchSrc);

}

BOOL

NBListNames (int nLana, LPCSTR szName)

{

    int cbBuffer;

    ADAPTER_STATUS *pStatus;

    NAME_BUFFER *pNames;

    int i;

    // Allocate the largest buffer we might need

    cbBuffer = sizeof (ADAPTER_STATUS) + 255 * sizeof (NAME_BUFFER);

    pStatus = (ADAPTER_STATUS *) HeapAlloc (GetProcessHeap (), 0,

                                            cbBuffer);

    if (NULL == pStatus)

        return FALSE;

    if (!NBAdapterStatus (nLana, (PVOID) pStatus, cbBuffer, szName))

    {

        HeapFree (GetProcessHeap (), 0, pStatus);

        return FALSE;

    }

    // The list of names immediately follows the adapter status

    // structure.

    pNames = (NAME_BUFFER *) (pStatus + 1);

    for (i = 0; i < pStatus->name_count; i++)

        printf ("\t%.*s\n", NCBNAMSZ, pNames[i].name);

    HeapFree (GetProcessHeap (), 0, pStatus);

    return TRUE;

}

BOOL

NBAdapterStatus (int nLana, PVOID pBuffer, int cbBuffer, LPCSTR szName)

{

    NCB ncb;

    memset (&ncb, 0, sizeof (ncb));

    ncb.ncb_command = NCBASTAT;

    ncb.ncb_lana_num = nLana;

    ncb.ncb_buffer = (PUCHAR) pBuffer;

    ncb.ncb_length = cbBuffer;

    MakeNetbiosName (ncb.ncb_callname, szName);

    Netbios (&ncb);

    NBCheck (ncb);

    return (NRC_GOODRET == ncb.ncb_retcode);

}

Additional reference words: 3.10 3.50

KBCategory: kbprg  kbnetwork

KBSubcategory: NtwkNetios


List of Articles for Win32 SDK Base Programming Issues

PSS ID Number: Q89989

Authored 17-Jan-1994	Last modified 25-May-1995

The information in this article applies to:

 - FastTips for the Microsoft Win32 Software Development Kit (SDK),

   versions 3.1 and 3.5

INSTRUCTIONS

Microsoft FastTips is available 24 hours a day, 7 days a week, from a

touch-tone telephone. To order items from this catalog, first select the

items you want to receive, noting the five- to six-digit number of the Item

ID shown below for each item, and then:

- Dial the toll-free FastTips number (800) 936-4300.

- When prompted, select the Win32 Software Development Kit.

- Press one (1) on your phone keypad to select Express Order Service.

- When prompted, select the delivery method, fax.

- When prompted, enter your three-digit area code and seven-digit fax

  number on your phone keypad.

- When prompted, enter the number of the Item ID and press #, for up

  to five items.

When finished, simply hang up. If you have problems receiving a fax, please

call (206) 635-3105.

ARTICLE LISTING

ITEM ID  ARTICLE TITLE                                               PAGES

--------------------------------------------------------------------------

Q 83298  Objects Inherited Through a CreateProcess Call             1

Q 83670  Correct Use of Try/Finally                                 2

Q 83706  Exporting Callback Functions                               1

Q 84240  Consoles Do Not Support ANSI Escape Sequences              1

Q 84244  Processes Maintain Only One Current Directory              1

Q 89296  How HEAPSIZE/STACKSIZE Commit > Reserve Affects Execution  1

Q 89373  Replacing the Windows NT Task Manager                      1

Q 89750  AllocConsole() Necessary to Get Valid Handles              1

Q 89817  How to Specify Shared and Nonshared Data in a DLL          1

Q 90083  Windows NT Servers in Locked Closets                       2

Q 90088  CreateFile() Using CONOUT$ or CONIN$                       1

Q 90368  Cancelling Overlapped I/O                                  1

Q 90470  Getting Real Handle to Thread/Process Requires Two Calls   1

Q 90530  Exporting Data from a DLL or an Application                2

Q 90745  Dynamic Loading of DLLs Under Windows NT                   2

Q 90749  Implementing a "Kill" Operation in Windows NT              2

Q 90837  Default Attributes for Console Windows                     1

Q 90910  Win32 Priority Class Mechanism and the START Command       1

Q 91146  PRB: SEH with Abort() in the try Body                           1

Q 91147  PRB: SEH with return in the finally Body Preempts Unwind        2

Q 91148  Initiating an Unwind in an Exception Handler               2

Q 91149  Using volatile to Prevent Optimization of try/except       1

Q 91150  Icons for Console Applications                             1

Q 91194  Memory Handle Allocation                                   1

Q 91698  Sharing Win32 Services                                     1

Q 92395  Determining Whether Windows NT Is Running                  2

Q 92761  Process Will Not Terminate Unless System Is In User-mode   1

Q 92764  Non-Addressable Range in Address Space                     1

Q 92862  Alternatives to Using GetProcAddress() With LoadLibrary()  1

Q 94239  Secure Erasure Under Windows NT                            1

Q 94561  WM_COMMNOTIFY is Obsolete for Win32-Based Applications     1

Q 94804  Thread Local Storage Overview                              2

Q 94839  Precautions When Passing Security Attributes               1

Q 94840  Physical Memory Limits Number of Processes/Threads         1

Q 94920  Calculating String Length in Registry                      1

Q 94947  PAGE_READONLY May Be Used as Discardable Memory            1

Q 94950  Clarification of COMMPROP dwMax?xQueue Members             1

Q 94990  OpenComm() and Related Flags Obsolete Under Win32          1

Q 94993  Global Quota for Registry Data                             2

Q 94994  Determining Whether App Is Running as Service or .EXE      1

Q 94996  VirtualLock() Only Locks Pages into Working Set            1

Q 94997  Reducing the Count on a Semaphore Object                   1

Q 94998  Trapping Floating-Point Exceptions Under Windows NT        1

Q 94999  FormatMessage() Converts GetLastError() Codes              1

Q 95043  FlushViewOfFile() on Remote Files                          1

Q 95804  Win32 Software Development Kit Buglist                     1

Q 95900  Interprocess Communication Under Windows NT and on Win32s  1

Q 96005  Validating User Accounts (Impersonation)                   1

Q 96209  Chaining Parent PSP Environment Variables                  1

Q 96242  Distinguishing Between Keyboard ENTER and Keypad ENTER     1

Q 96374  Win32 .DEF File Usage in Applications and DLLs             1

Q 96418  Priority Inversion and Windows NT Scheduler                2

Q 96780  Security and Screen Savers                                 1

Q 97786  Default Stack in Win32-Based Applications                  2

Q 97926  The Use of the SetLastErrorEx() API                        1

Q 98216  Windows NT Virtual Memory Manager Uses FIFO                1

Q 98575  File Manager Passes Short Filename as Parameter            1

Q 98722  Getting the Net Time on a Domain                           1

Q 98756  Increased Performance Using FILE_FLAG_SEQUENTIAL_SCAN      1

Q 98838  Win32 Graphical Setup Over Network Drives                  1

Q 98840  Noncontinuable Exceptions                                  1

Q 98891  Validating User Account Passwords Under Windows NT         1

Q 98892  PRB: Unexpected Result of SetFilePointer() with Devices         2

Q 98893  Limit on the Number of Bytes Written Asynchronously        2

Q 98952  Setting File Permissions                                   1

Q 99026  Possible Serial Baud Rates on Various Machines             1

Q 99114  Using GMEM_DDESHARE in Win32 Programming                   1

Q 99115  Preventing the Console from Disappearing                   1

Q 99173  Types of File I/O Under Win32                              2

Q 99261  Performing a Clear Screen (CLS) in a Console Application   1

Q 99456  Win32 Equivalents for C Run-Time Functions                 6

Q 99794  FILE_FLAG_WRITE_THROUGH and FILE_FLAG_NO_BUFFERING         1

Q 99795  PRB: SetConsoleOutputCP() Not Functional                        1

Q 100027 Direct Drive Access Under Win32                            1

Q 100291 Restriction on Named-Pipe Names                            1

Q 100328 Replacing the Shell (Program Manager)                      2

Q 100329 CPU Quota Limits Not Enforced                              1

Q 101186 Time Stamps Under the FAT File System                      1

Q 101190 Examining the dwOemId Value                                1

Q 101193 Interrupting Threads in Critical Sections                  1

Q 101378 Impersonation Provided by ImpersonateNamedPipeClient()     1

Q 102098 Gaining Access to ACLs                                     1

Q 102099 Administrator Access to Files                              1

Q 102100 Passing Security Information to SetFileSecurity()          1

Q 102101 Extracting the SID from an ACE                             1

Q 102102 How to Add an Access-Allowed ACE to a File                 5

Q 102103 Computing the Size of a New ACL                            1

Q 102104 FILE_READ_EA and FILE_WRITE_EA Specific Types              1

Q 102105 System GENERIC_MAPPING Structures                          1

Q 102128 Why LoadLibraryEx() Returns an HINSTANCE                   1

Q 102352 Passing a Pointer to a Member Function to the Win32 API    2

Q 102429 Detecting Closure of Command Window from a Console App     1

Q 102447 Definition of a Protected Server                           1

Q 102555 How Windows NT Handles Floating-Point Calculations         2

Q 102798 Security Attributes on Named Pipes                         2

Q 103193 Managing Heap Memory in Win32                              1

Q 103237 Using Temporary File Can Improve Application Performance   1

Q 103858 Copy on Write Page Protection for Windows NT               2

Q 103862 Symbolic Information for System DLLs                       1

Q 104122 Detecting Logoff from a Service                            1

Q 104136 Mapping .INI File Entries to the Registry                  1

Q 104378 PRB: Win32 SDK and VC++ NT Help Files Are Incompatible          1

Q 105299 Creating a Font for Use with the Console                   1

Q 105302 Cancelling WaitCommEvent() with SetCommMask()              1

Q 105303 FIX: Redirecting Output to an MS-DOS-Based Application          1

Q 105304 SetErrorMode() Is Inherited                                1

Q 105305 Calling CRT Output Routines from a GUI Application         2

Q 105306 Getting and Using a Handle to a Directory                  1

Q 105531 Named Pipe Buffer Size                                     1

Q 105532 The Use of PAGE_WRITECOPY                                  1

Q 105533 BUG: Problems with Local/Global Memory Management APIs          1

Q 105564 BUG: AllocConsole() Does Not Set Error Code on Failure          1

Q 105674 Setting the Console Configuration                          1

Q 105675 First and Second Chance Exception Handling                 1

Q 105678 Critical Sections Versus Mutexes                           1

Q 105681 BUG: GetPrivateProfileSection() Can Read Only 32K Sections      1

Q 105763 Using NTFS Alternate Data Streams                          2

Q 106383 RegSaveKey() Requires SeBackupPrivilege                    1

Q 106387 Sharing Objects with a Service                             1

Q 106663 Accessing the Macintosh Resource Fork                      1

Q 106715 Troubleshooting Win32s 1.1 Installation Problems           3

Q 107642 FIX: VirtualLock() on File-Mapped Pages Hangs Computer          1

Q 107728 Retrieving Counter Data From the Registry                  3

Q 108228 Replace IsTask() with GetExitCodeProcess()                 1

Q 108230 Accessing the Event Logs                                   2

Q 108231 CreateFileMapping() SEC_* Flags                            1

Q 108402 DOCERR: WM_COPYDATA Is Also Supported on Win32s                 1

Q 108448 Use LoadLibrary() on .EXE Files Only for Resources         1

Q 108449 Working Set Size, Nonpaged Pool, and VirtualLock()         3

Q 109619 Sharing All Data in a DLL                                  2

Q 110148 PRB: ERROR_INVALID_PARAMETER from WriteFile() or ReadFile()     1

Q 110853 PRB: Can't Increase Process Priority                            1

Q 111541 New Owner in Take-Ownership Operation                      1

Q 111542 Checking for Administrators Group                          2

Q 111543 Creating a World SID                                       1

Q 111544 Looking Up the Current User and Domain                     1

Q 111545 Security Context of Child Processes                        1

Q 111546 Taking Ownership of Registry Keys                          1

Q 111559 PRB: GetExitCodeProcess Always Returns 0 for 16-Bit Processes   1

Q 111837 ERROR_BUS_RESET May Be Benign                              1

Q 111838 Possible Cause for ERROR_INVALID_FUNCTION                  1

Q 115083 DOCERR: EofChar Field of DCB Structure Is Not Supported         1

Q 115231 Retrieving Time-Zone Information                           1

Q 115232 Timer Resolution in Windows NT                             1

Q 115236 Long Filenames on Windows NT FAT Partitions                2

Q 115522 Limits on Overlapped Pipe Operations                       1

Q 115825 Accessing the Application Desktop from a Service           1

Q 115826 Clarification of SearchPath() Return Value                 1

Q 115827 Filenames Ending with Space or Period Not Supported        1

Q 115828 Getting Floppy Drive Information                           3

Q 115829 How to Gracefully Fail at Service Start                    1

Q 115831 Specifying Serial Ports Larger than COM9                   1

Q 115848 Services and Redirected Drives                             1

Q 115945 Determining the Maximum Allowed Access for an Object       1

Q 115946 PRB: AccessCheck() Returns ERROR_INVALID_SECURITY_DESCR         1

Q 115947 Adding Categories for Events                               1

Q 115948 Creating Access Control Lists for Directories              2

Q 117223 BUG: Byte-Range File Locking Deadlock Condition                 2

Q 117261 PRB: RegCreateKeyEx() Gives Error 161 Under Windows NT 3.5      2

Q 117330 PRB: Error "Invalid DLL Entrypoint" when Loading a DLL          2

Q 117867 Detecting Parallel Out-of-Paper Status                     1

Q 117872 Windows NT 3.5 Hives Not Compatible with Windows NT 3.1    1

Q 117892 Memory Requirements for a Win32 App vs. the Win16 Version  1

Q 118625 Detecting Data on the Communications Port                  1

Q 118626 Determining Whether the User is an Administrator           2

Q 118816 PRB: LoadLibrary() Fails with _declspec(thread)                 1

Q 119163 Getting the Filename Given a Window Handle                 5

Q 119218 PRB: Named Pipe Write() Limited to 64K                          1

Q 119219 PRB: GetVolumeInformation() Fails with UNC Name                 1

Q 119220 ReadFile() at EOF Changed in Windows NT 3.5                1

Q 119669 Listing Account Privileges                                 2

Q 120556 PRB: Starting a Service Returns "Logon Failure" Error           1

Q 120557 Dealing w/ Lengthy Processing in Service Control Handler   1

Q 120697 Time Format for WIN32_FIND_DATA                            1

End of listing.

Additional reference words: DSKBGuide 3.10 3.50 4.00 95

KBCategory: kbref kbtlc

KBSubcategory: BseMisc


List of Articles for Win32 SDK GDI Programming Issues

PSS ID Number: Q80828

Authored 13-Feb-1992	Last modified 05-May-1995

The information in this article applies to:

 - FastTips for the Microsoft Win32 Software Development Kit (SDK)

   for Windows NT version 3.1

INSTRUCTIONS

Microsoft FastTips is available 24 hours a day, 7 days a week, from a

touch-tone telephone. To order items from this catalog, first select the

items you want to receive, noting the five- to six-digit number of the Item

ID shown below for each item, and then:

- Dial the toll-free FastTips number (800) 936-4300.

- When prompted, select the Win32 Software Development Kit.

- Press one (1) on your phone keypad to select Express Order Service.

- When prompted, select the delivery method, fax.

- When prompted, enter your three-digit area code and seven-digit fax

  number on your phone keypad.

- When prompted, enter the number of the Item ID and press #, for up

  to five items.

When finished, simply hang up. If you have problems receiving a fax, please

call (206) 635-3105.

ARTICLE LISTING

ITEM ID  ARTICLE TITLE                                               PAGES

--------------------------------------------------------------------------

Q 85844  PRB: Saving/Loading Bitmaps in .DIB Format on MIPS              1

Q 85846  Using GetDIBits() for Retrieving Bitmap Information        1

Q 89375  Transparent Blts in Windows NT                             2

Q 90085  PSTR's in OUTLINETEXTMETRIC Structure                      1

Q 91072  PRB: IsGdiObject() Is Not a Part of the Win32 API               1

Q 92514  Use of DocumentProperties() vs. ExtDeviceMode()            1

Q 94236  Using Device Contexts Across Threads                       1

Q 94326  16 and 32 Bits-Per-Pel Bitmap Formats                      2

Q 94918  Advantages of Device-Dependent Bitmaps                     1

Q 95804  Win32 Software Development Kit Buglist                     1

Q 96282  DEVMODE and dmSpecVersion                                  1

Q 100487 Use 16-Bit .FON Files for Cross-Platform Compatibility     1

Q 102353 Tracking Brush Origins in Windows NT                       1

Q 102354 Calculating the TrueType Checksum                          1

Q 104010 Creating a Logical Font with a Nonzero lfOrientation       1

Q 104834 FIX: StreBlt Sample Causes Windows NT to Stop Responding        1

Q 105733 FIX: SetCaret API May Not Work Correctly in Win32-Based Apps    1

Q 106384 ClipCursor() Requires WINSTA_WRITEATTRIBUTES               1

Q 108234 DOCERR: LoadCursorFromFile() and SetSystemCursor() Are Missing  2

Q 108929 Querying Device Support for MaskBlt                        1

Q 110702 DOCERR: DeviceCapabilitiesEx Not Implemented in Windows NT 3.1  1

Q 115762 Printing Offset, Page Size, and Scaling with Win32         1

Q 118622 Using the Document Properties Dialog Box                   2

Q 119164 Use of Polygon() Versus PolyPolygon()                      1

Q 122564 Prototypes for SetSystemCursor() & LoadCursorFromFile()    1

End of listing.

Additional reference words: DSKBGuide 3.10

KBCategory: kbref kbtlc

KBSubcategory: GdiMisc


List of Articles for Win32 SDK Networking Issues

PSS ID Number: Q81246

Authored 17-Jan-1994	Last modified 05-Jan-1995

The information in this article applies to:

 - FastTips for the Microsoft Win32 Software Development Kit (SDK)

   for Windows NT versions 3.1 and 3.5

INSTRUCTIONS

Microsoft FastTips is available 24 hours a day, 7 days a week, from a

touch-tone telephone. To order items from this catalog, first select the

items you want to receive, noting the five- to six-digit number of the Item

ID shown below for each item, and then:

- Dial the toll-free FastTips number (800) 936-4300.

- When prompted, select the Win32 Software Development Kit.

- Press one (1) on your phone keypad to select Express Order Service.

- When prompted, select the delivery method, fax.

- When prompted, enter your three-digit area code and seven-digit fax

  number on your phone keypad.

- When prompted, enter the number of the Item ID and press #, for up

  to five items.

When finished, simply hang up. If you have problems receiving a fax, please

call (206) 635-3105.

ARTICLE LISTING

ITEM ID  ARTICLE TITLE                                               PAGES

--------------------------------------------------------------------------

Q 92515  Distributed Computing Environment (DCE) Compliance         1

Q 94088  PRB: WSAAsyncSelect() Notifications Stop Coming                 1

Q 95804  Win32 Software Development Kit Buglist                     1

Q 95866  Writing a Telnet Client                                    1

Q 95944  NetBIOS Name Table and NCBRESET                            2

Q 96781  Using RPC Callback Functions                               2

Q 100009 RPC Can Use Multiple Protocols                             1

Q 101268 Tuning Sessions, Names, and NCBs for NetBIOS Applications  1

Q 101377 Supported Versions of Windows Sockets                      1

Q 102381 Location of WNet* API Functions                            1

Q 104315 PRB: RPC Installation Problem                                   1

Q 104318 RpcNsxxx() APIs Not Supported by Windows NT Locator        1

Q 104536 Using ReadFile() and WriteFile() on Socket Descriptors     1

Q 105785 FIX: NDISCloseFile() Does Not Free Image Buffer                 1

Q 105804 FIX: APIs Do Incorrect Comparisons                              1

Q 110703 Host Name May Map to Multiple IP Addresses                 1

Q 110775 PRB: Winsock select() Returns WSAENOTSOCK                       1

Q 110776 Windows NT Support for the MS-DOS LAN Manager APIs         1

Q 115830 MIDL 1.0 and MIDL 2.0 Full Pointers Do Not Interoperate    1

Q 118623 Getting the MAC Address for an Ethernet Adapter            2

Q 119216 Enumerating Network Connections                            2

Q 119670 How to Look Up a User's Full Name                          2

End of listing.

Additional reference words: DSKBGuide 3.10 3.50

KBCategory: kbref kbtlc

KBSubcategory: NtwkMisc


List of Articles for Win32 SDK Tools

PSS ID Number: Q89345

Authored 17-Jan-1994	Last modified 26-May-1995

The information in this article applies to:

 - FastTips for the Microsoft Win32 Software Development Kit (SDK)

   for Windows NT versions 3.1 and 3.5

INSTRUCTIONS

Microsoft FastTips is available 24 hours a day, 7 days a week, from a

touch-tone telephone. To order items from this catalog, first select the

items you want to receive, noting the five- to six-digit number of the Item

ID shown below for each item, and then:

- Dial the toll-free FastTips number (800) 936-4300.

- When prompted, select the Win32 Software Development Kit.

- Press one (1) on your phone keypad to select Express Order Service.

- When prompted, select the delivery method, fax.

- When prompted, enter your three-digit area code and seven-digit fax

  number on your phone keypad.

- When prompted, enter the number of the Item ID and press #, for up

  to five items.

When finished, simply hang up. If you have problems receiving a fax, please

call (206) 635-3105.

ARTICLE LISTING

ITEM ID  ARTICLE TITLE                                               PAGES

--------------------------------------------------------------------------

Q 83300  Using a Mouse with MEP Under Windows NT                    1

Q 84081  RCDATA Begins on 32-Bit Boundary in Windows NT             1

Q 89822  Format for LANGUAGE Statement in .RES Files                2

Q 90384  PRB: Selecting Overlapping Controls in Dialog Editor            1

Q 91697  Use of DLGINCLUDE in Resource Files                        1

Q 94248  Using the C Run Time                                       4

Q 94323  CTYPE Macros Function Incorrectly                          1

Q 94924  Postmortem Debugging Under Windows NT                      1

Q 97765  Size Comparison of 32-Bit and 16-Bit x86 Applications      1

Q 97858  CTRL+C Exception Handling Under WinDbg                     1

Q 97908  Debugging DLLs Using WinDbg                                2

Q 97924  Language ID Needed for RC.EXE                              1

Q 98288  Watching Local Variables That Are Also Globally Declared   1

Q 98732  FIX: Global Constructors Not Called in Alpha DLLs               1

Q 98888  PRB: MS-SETUP Uses \SYSTEM Rather Than \SYSTEM32                1

Q 98890  Debugging a Service with WinDbg                            2

Q 98918  PRB: Cannot Compile from Win32 SDK M Editor (MEP.EXE)           1

Q 99053  Source-level Debugging Under NTSD                          1

Q 99516  Compile Errors Caused by Missing Option -D_X86_            1

Q 99952  PRB: Debugging the Open Common Dialog Box in WinDbg             1

Q 99953  WinDbg Message "Breakpoint Not Instantiated"               1

Q 100289 Enabling Disk Performance Counters                         1

Q 100292 PRB: Data Section Names Limited to Eight Characters             1

Q 100642 Setting Dynamic Breakpoints in WinDbg                      2

Q 100957 PRB: Debugging an Application Driven by MS-TEST                 1

Q 101187 Interpreting Executable Base Addresses                     1

Q 102351 Debugging Console Apps Using Redirection                   1

Q 102764 FIX: MIPS Compiler Assertion with C version 8.0                 1

Q 103861 Choosing the Debugger That the System Will Spawn           1

Q 103863 Cannot Load <exe> Because NTVDM Is Already Running         1

Q 105583 Viewing Globals Out of Context in WinDbg                   1

Q 105584 PRB: RC Does Not Support __DATE__ or __TIME__                   1

Q 105585 PRB: Unable to Freeze One Thread in WinDbg                      1

Q 105586 FIX: WinDbg FIND Dialog Box Slows Down the System               1

Q 105677 Debugging the Win32 Subsystem                              1

Q 105679 Differences Between the Win32 SDK and 32-Bit VC++          2

Q 105764 Listing the Named Shared Objects                           1

Q 106064 PRB: RW1016 Error Due to Unexpected End of File (EOF)           1

Q 106066 Additional Remote Debugging Requirement                    1

Q 106382 PRB: Problems with the Microsoft Setup Toolkit                  2

Q 108055 FIX: Internal Error from NetUserEnum()                          1

Q 108227 Changes to the MSTest WFndWndC()                           1

Q 114610 PRB: "Out of Memory Error" in the Win32 SDK Setup Sample        1

Q 115234 Win32 SDK 3.5 LINK32.EXE Calls CVTRES.EXE                  1

Q 118890 Using the Call-Attributed Profiler (CAP)                   2

End of listing.

Additional reference words: DSKBGuide 3.10 3.50

KBCategory: kbref kbtlc

KBSubcategory: TlsMisc


List of Articles for Win32 SDK User Programming Issues

PSS ID Number: Q89372

Authored 17-Jan-1994	Last modified 13-Jun-1995

The information in this article applies to:

 - FastTips for the Microsoft Win32 Software Development Kit (SDK)

   versions 3.1, 3.5, 3.51, 4.0

INSTRUCTIONS

Microsoft FastTips is available 24 hours a day, 7 days a week, from a

touch-tone telephone. To order items from this catalog, first select the

items you want to receive, noting the five- to six-digit number of the Item

ID shown below for each item, and then:

- Dial the toll-free FastTips number (800) 936-4300.

- When prompted, select the Win32 Software Development Kit.

- Press one (1) on your phone keypad to select Express Order Service.

- When prompted, select the delivery method, fax.

- When prompted, enter your three-digit area code and seven-digit fax

  number on your phone keypad.

- When prompted, enter the number of the Item ID and press #, for up

  to five items.

When finished, simply hang up. If you have problems receiving a fax, please

call (206) 635-3105.

ARTICLE LISTING

ITEM ID  ARTICLE TITLE                                               PAGES

--------------------------------------------------------------------------

Q 80382  Global Classes in Win32                                    1

Q 89295  Unicode Conversion to Integers                             1

Q 89712  Multiline Edit Control Limits in Windows NT                1

Q 89865  Tips for Writing Multiple-Language Scripts                 1

Q 89866  Writing Multiple-Language Resources                        1

Q 90912  Getting the WinMain() lpCmdLine in Unicode                 1

Q 90975  Creating Windows in a Multithreaded Application            1

Q 92505  Multiple Desktops Under Windows NT                         1

Q 94091  DDEML Application-Instance IDs Are Thread Local            1

Q 94149  Freeing PackDDElParam() Memory                             1

Q 94917  Uniqueness Values in User and GDI Handles                  1

Q 95000  SendMessage() in a Multithreaded Environment               1

Q 95804  Win32 Software Development Kit Buglist                     1

Q 96006  Window Message Priorities                                  1

Q 97920  NULL is a Valid Return From SetWindowsHook()               1

Q 97922  LB_GETCARETINDEX Returns 0 for Zero Entries in List Box    1

Q 97925  SetActiveWindow() and SetForegroundWindow() Clarification  1

Q 99359  UNICODE and _UNICODE Needed to Compile for Unicode         1

Q 99360  Memory Handles and Icons                                   1

Q 99392  Using SetThreadLocale() for Language Resources             1

Q 100486 PRB: AttachThreadInput() Resets Keyboard State                  1

Q 100488 System Versus User Locale Identifiers                      1

Q 102428 Debugging a System-Wide Hook                               1

Q 102446 DOCERR: WM_ENTERIDLE Documentation Is Misleading                1

Q 102482 SetTimer() Should Not Be Used in Console Applications      1

Q 102485 The SBS_SIZEBOX Style                                      1

Q 102765 Clarification of the "Country" Setting                     1

Q 103240 DOCERR: CloseClipboard() Suggests Calling DuplicateHandle()     1

Q 103644 Differences Between hInstance on Win 3.1 and Windows NT    2

Q 103977 Unicode Implementation in Windows NT 3.1                   1

Q 104011 Propagating Environment Variables to the System            1

Q 104311 32-Bit Scroll Ranges                                       1

Q 104316 How Keyboard Data Gets Translated                          1

Q 105300 COMCTL32 APIs Unsupported in the Win32 SDK                 1

Q 105446 Win32 Shell Dynamic Data Exchange (DDE) Interface          2

Q 105530 Win32 Drag and Drop Server                                 1

Q 105575 FIX: Low Memory Condition Cause APIs to Return Random Values    1

Q 106065 Development Tools Do Not Accept Unicode Text               1

Q 106385 Identifying a Previous Instance of an Application          1

Q 106386 Retrieving DIBs from the Clipboard                         1

Q 106716 Using SendMessageTimeout() in a Multithreaded Application  2

Q 106717 Journal Hooks and Compatibility                            1

Q 108232 Hooking Console Applications and the Desktop               1

Q 108233 PRB: GetOpenFileName() and Spaces in Long Filenames             1

Q 108450 MultiByteToWideChar() Codepages CP_ACP/CP_OEMCP            1

Q 110704 Replacing Windows NT Control Panel's Mouse Applet          1

Q 115081 DOCERR: DragQueryFile() Return Code Can Be Misleading           1

Q 118624 Using GetForegroundWindow() When Desktop Is Not Active     1

End of listing.

Additional reference words: DSKBGuide 3.10 3.50 3.51 4.00 95

KBCategory: kbref kbtlc

KBSubcategory: UsrMisc


List of Articles for Win32s Programming Issues

PSS ID Number: Q93064

Authored 17-Jan-1994	Last modified 21-Feb-1995

The information in this article applies to:

 - FastTips for Microsoft Win32s version 1.1

INSTRUCTIONS

Microsoft FastTips is available 24 hours a day, 7 days a week, from a

touch-tone telephone. To order items from this catalog, first select the

items you want to receive, noting the five- to six-digit number of the Item

ID shown below for each item, and then:

- Dial the toll-free FastTips number (800) 936-4300.

- When prompted, select the Win32 Software Development Kit.

- Press one (1) on your phone keypad to select Express Order Service.

- When prompted, select the delivery method, fax.

- When prompted, enter your three-digit area code and seven-digit fax

  number on your phone keypad.

- When prompted, enter the number of the Item ID and press #, for up

  to five items.

When finished, simply hang up. If you have problems receiving a fax, please

call (206) 635-3105.

ARTICLE LISTING

ITEM ID  ARTICLE TITLE                                               PAGES

--------------------------------------------------------------------------

Q 83520  General Overview of Win32s                                 2

Q 93639  PRB: Win32s GetVolumeInformation() Returns 0x12345678           1

Q 97785  Calling a Win32 DLL from a Win16 App on Win32s             2

Q 97918  Win32s Message Queue Checking                              1

Q 98286  PRB: _getdcwd() Returns the Root Directory Under Win32s         2

Q 98723  FIX: GetVersion() Returns Invalid Value Under Win32s            1

Q 100713 Support for Sleep() on Win32s                              1

Q 100833 Win32s Translated Pointers Guaranteed for 32K              1

Q 102430 Debugging Applications Under Win32s                        2

Q 102762 GetCommandLine() Under Win32s                              1

Q 104314 Win32s NetBIOS Programming Considerations                  1

Q 105170 SAMPLE: Win32s Universal Thunks                                 1

Q 105680 Win32s Cannot Support _environ in DLLs                     1

Q 105756 Debugging Universal Thunks                                 1

Q 105757 Using Windows Sockets Under Win32s and WOW                 1

Q 105758 Win32s and Windows NT Timer Differences                    1

Q 105759 Using Serial Communications Under Win32s                   1

Q 105760 Using VxDs and Software Interrupts Under Win32s            1

Q 105761 Getting Resources from 16-Bit DLLs Under Win32s            1

Q 105762 Sharing Memory Between 32-Bit and 16-Bit Code on Win32s    1

Q 106715 Troubleshooting Win32s Installation Problems               3

Q 108403 FIX: Opening Named Pipes on Win32s                              2

Q 108497 DIB_PAL_INDICES and CBM_CREATEDIB Not Supported in Win32s  1

Q 108722 PRB: "Routine Not Found" Errors in Windows Help                 1

Q 109620 Creating Instance Data in a Win32s DLL                     1

Q 110705 BUG: Problems with Win32s CreateFileMapping()                   2

Q 110844 Detecting the Presence of NetBIOS in Win32s                1

Q 110845 How Win32-Based Applications Are Loaded Under Windows      1

Q 113739 BUG: Win32s 1.1 Bug List                                        3

Q 114340 Win32s 1.1 Limitations                                     7

Q 115080 Converting a Linear Address to a Flat Offset on Win32s     1

Q 115082 PRB: Page Fault in WIN32S16.DLL Under Win32s                    1

Q 115084 Win32s Device-Independent Bitmap Limit                     1

Q 117153 PRB: Display Problems with Win32s and the S3 Driver             1

Q 117825 Handling COMMDLG File Open Network Button Under Win32s     1

Q 117864 PRB: GP Fault Caused by GROWSTUB in POINTER.DLL                 1

Q 117893 PRB: Result of localtime() Differs on Win32s and Windows NT     1

Q 120486 How to Remove Win32s                                       1

Q 121091 How to Determine Which Version of Win32s Is Installed      1

Q 121092 PRB: Local Reboot (CTRL+ALT+DEL) Doesn't Work Under Win32s      1

Q 121093 Points to Remember When Writing a Debugger for Win32s      7

Q 121094 PRB: Controls Do Not Receive Expected Messages                  2

Q 121095 PRB: GPF When Spawn Windows-Based App w/ WinExec() in Win32s    1

Q 122235 Microsoft Win32s Upgrade                                   2

End of listing.

Additional reference words: 1.10 dskbguide

KBCategory: kbref kbtlc

KBSubcategory: W32s


Listing Account Privileges

PSS ID Number: Q119669

Authored 20-Aug-1994	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   versions 3.1 and 3.5

SUMMARY

When a user starts a process, that process takes on the security attributes

of the user. The security attributes inherited from the user include

privileges, which control access to system services.

MORE INFORMATION

To list the privileges belonging to a process (and thus to the current

user), perform the following steps:

1. Call GetCurrentProcess() to obtain a handle to the current process.

2. Call GetProcessToken() to obtain the process' access token.

3. Call GetTokenInformation() to obtain the list of privileges (among

   other information).

4. Step through the list of privileges, using LookupPrivilegeName() and

   LookupPrivilegeDisplayName() to obtain the names for the program to

   display.

The following sample code lists the displayable privilege names and the

privilege names as defined in the WINNT.H header file:

Sample Code

-----------

   #include <windows.h>

   #include <stdio.h>

   void main()

   {

      HANDLE hProcess, hAccessToken;

      UCHAR InfoBuffer[1000];

      PTOKEN_PRIVILEGES ptgPrivileges = (PTOKEN_PRIVILEGES)InfoBuffer;

      DWORD dwInfoBufferSize;

      DWORD dwPrivilegeNameSize;

      DWORD dwDisplayNameSize;

      UCHAR ucPrivilegeName[500];

      UCHAR ucDisplayName[500];

      DWORD dwLangId;

      UINT x;

      hProcess = GetCurrentProcess();

      OpenProcessToken( hProcess, TOKEN_READ, &hAccessToken );

      GetTokenInformation( hAccessToken, TokenPrivileges, InfoBuffer,

         sizeof(InfoBuffer), &dwInfoBufferSize);

      printf( "Account privileges: \n\n" );

      for( x=0; x<ptgPrivileges->PrivilegeCount; x++ )

      {

         dwPrivilegeNameSize = sizeof( ucPrivilegeName );

         dwDisplayNameSize = sizeof( ucDisplayName );

         LookupPrivilegeName( NULL, &ptgPrivileges->Privileges[x].Luid,

            ucPrivilegeName, &dwPrivilegeNameSize );

         LookupPrivilegeDisplayName( NULL, ucPrivilegeName,

            ucDisplayName, &dwDisplayNameSize, &dwLangId );

         printf( "%40s (%s)\n", ucDisplayName, ucPrivilegeName );

      }

   }

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseSecurity


Listing the Named Shared Objects

PSS ID Number: Q105764

Authored 24-Oct-1993	Last modified 23-Feb-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

Included with the Win32 SDK is an object viewer utility called WinObj that

be used to list named objects, devices, dynamic-link libraries (DLLs), and

so forth. To find objects such as pipes, memory, and semaphores, start

WinObj and select the folder BaseNamedObjects.

Additional reference words: 3.10 3.50

KBCategory: kbtool

KBSubcategory: TlsMisc


Localizing the Setup Toolkit for Foreign Markets

PSS ID Number: Q92523

Authored 09-Nov-1992	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK, version 3.5

SUMMARY

There are no localized versions of the Setup Toolkit .DLLs available.

However, the resource files for these .DLLs are provided with the

Windows 3.1 Software Development Kit (SDK). They can be found in the

INTLDLL subdirectory in the MSSETUP directory created by the SDK

Setup.

The strings in the STRINGTABLES in these .RC files can be translated.

The localized .RC files can then be bound to the .DLLs using the

resource compiler.

Additional reference words: 3.10 3.50 MSSETUP tool kit

KBCategory: kbtool

KBSubcategory: TlsMss


Location of the Cursor in a List Box

PSS ID Number: Q29961

Authored 09-May-1988	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.1, 3.5, 3.51, and 4.0

There is no way to determine which item in the list box has the cursor

when the LBN_DBLCLK message is received. You must keep track of which

item has the cursor as it moves among the items. When you receive the

double-click message, you will know which box has the cursor.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: UsrCtl


Location of WNet* API Functions

PSS ID Number: Q102381

Authored 03-Aug-1993	Last modified 26-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

The WNet* API routines are implemented in MPR.DLL. When linking an

application that uses these routines, link with the import library MPR.LIB.

For a list of which APIs can be resolved with which import libraries, see

the file WIN32API.CSV, which is included in the Win32 SDK and the Visual

C++ 32-bit edition.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubCategory: NtwkWinnet


Long Filenames on Windows NT FAT Partitions

PSS ID Number: Q115236

Authored 22-May-1994	Last modified 21-Feb-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   version 3.5

SUMMARY

Windows NT, version 3.5, introduces the ability to create or open files

with long filenames (LFN) on Windows NT file allocation table (FAT)

partitions.

UNICODE is stored on disk, so that the original name is always preserved

for extended characters regardless of which code page happens to be active

when reading from or writing to the disk.

The legal character set is that of the Windows NT file system (NTFS)

(except for the ":" for opening NTFS alternative file streams), so you can

copy arbitrary files between NTFS and FAT without losing any of the

filename information.

MORE INFORMATION

The LFNs are not available from the MS-DOS DIR command, but they are

available from the Windows NT DIR command. When you create an LFN on a

Windows NT FAT partition, an accompanying short name is created just as

on an NTFS partition. You can access the file or directory with either

the long names or the short names under Windows NT.

For example, use the Microsoft Editor (MEP) to create a file named as

follows on a FAT partition under Windows NT:

   longfilename.fat

This is exactly how the filename appears when you run the DIR command from

the Windows NT command prompt. However, when you boot the machine into MS-

DOS and run the DIR command, the filename appears as follows:

   longfi~1.fat

NOTE: NTFS partitions are not available under MS-DOS, so you cannot

perform this experiment using an NTFS partition.

The same result can also be achieved programmatically. Build and run the

following sample code on Windows NT:

Sample Code

-----------

   #include <windows.h>

   void main( )

   {

      WIN32_FIND_DATA fd;

      char buf[80];

      FindFirstFile( "long*", &fd );

      wsprintf( buf, "File name is %s", fd.cFileName );

      MessageBox( NULL, buf, "Test", MB_OK );

      wsprintf( buf, "Alternate file name is %s", fd.cAlternateFileName );

      MessageBox( NULL, buf, "Test", MB_OK );

   }

The first message box will read:

   File name is longfilename.fat

The second message box will read:

   Alternate file name is longfi~1.fat

Additional reference words: 3.50

KBCategory: kbprg

KBSubcategory: BseFileio


Looking Up the Current User and Domain

PSS ID Number: Q111544

Authored 14-Feb-1994	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

SUMMARY

Program Manager displays the logged in user account and domain name in its

windows title. This information can be retrieved programmatically by

extracting the user SID from the current access token and then looking up

the account and domain name via the LookupAccountSid() Win32 API. Below is

sample code demonstrating this technique:

Sample Code

-----------

void ShowUserDomain(void)

{

     HANDLE hProcess, hAccessToken;

       UCHAR InfoBuffer[1000],szAccountName[200], szDomainName[200];

       PTOKEN_USER pTokenUser = (PTOKEN_USER)InfoBuffer;

       DWORD dwInfoBufferSize,dwAccountSize = 200, dwDomainSize = 200;

       SID_NAME_USE snu;

       hProcess = GetCurrentProcess();

       OpenProcessToken(hProcess,TOKEN_READ,&hAccessToken);

       GetTokenInformation(hAccessToken,TokenUser,InfoBuffer,

            1000, &dwInfoBufferSize);

       LookupAccountSid(NULL, pTokenUser->User.Sid, szAccountName,

            &dwAccountSize,szDomainName, &dwDomainSize, &snu);

    printf("%s\\%s\n",szDomainName,szAccountName);

}

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseSecurity


MAKEINTATOM() Does Not Return a Valid LPSTR

PSS ID Number: Q61980

Authored 17-May-1990	Last modified 12-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.1, 3.5, 3.51, and 4.0

SUMMARY

The LPSTR returned from MAKEINTATOM() cannot be treated as a

general-purpose string pointer. Instead, either use it with the Atom

family or convert it into a valid string before passing it off as one.

MORE INFORMATION

The MAKEINTATOM() macro is documented on Page 370 of the "Microsoft

Windows Software Development Kit Programmer's Reference" versions 2.x

as returning a value of type LPSTR. This is correct, but misleading.

The LPSTR value returned is a "fabricated" LPSTR and cannot be

considered a general-purpose string pointer. Consider the definition

of the MAKEINTATOM macro:

   #define MAKEINTATOM(i)  (LPSTR) ((DWORD)((WORD)(i)))

This tells the compiler to "take the integer value 'i', think of it as

a WORD, zero-extend this into a DWORD, then think of this as a LPSTR."

Thus, MAKEINTATOM(1Ah) returns 001Ah. This obviously is not the same

as "1A", which would be ASCII(1)+ASCII(A)+0.

The reason this psuedo-LPSTR works with AddAtom(), for example, is

that AddAtom() looks to see if the HIWORD of the LPSTR parameter is

0 (zero). If so, AddAtom() knows that the LOWORD contains an actual

integer value and it simply grabs that.

The following code samples show how problems can occur with these

psuedo-LPSTRs returned from MAKEINTATOM.

Incorrect

---------

ATOM AddIntAtom(int iAtom)

{

    LPSTR   szAtom;

    MessageBox(hWnd,

               (szAtom=MAKEINTATOM(iAtom)),

               "Adding Atom",

               MB_OK);

    return (AddAtom(szAtom));

}

The above code fragment will create and return a valid atom, but the

message box will display an erroneous value.

Correct

-------

ATOM AddIntAtom(int iAtom)

{

    LPSTR   szAtom;

    char    szBuf[10];

    szAtom=MAKEINTATOM(iAtom);

    sprintf(szBuf, "%d", LOWORD(szAtom));   /* Here's the trick */

    MessageBox(hWnd,

               szBuf,

               "Adding Atom",

               MB_OK);

    return (AddAtom(szAtom));

}

In the above example, we converted the integer value contained in the

LOWORD of szAtom into a character string, then used this new character

string in the MessageBox() call.

Although these code fragments illustrate the limitations of a

MAKEINTATOM LPSTR, they are not very realistic because you really

should use GetAtomName() to get the character string of an atom. If

you have not yet created an atom out of an integer value, you could

just format the integer into character string directly, as follows:

   sprintf (szBuf, "%d", iAtom);

   MessageBox (hWnd, szBuf,....);

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrDde


Making a List Box Item Unavailable for Selection

PSS ID Number: Q74792

Authored 30-Jul-1991	Last modified 16-May-1995

-

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK), versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

-

SUMMARY

In the Microsoft Windows graphical environment, an application can use

a list box to enumerate options. However, there are circumstances in

which one or more options may not be appropriate. The application can

change the appearance of items in a list box and prevent the user from

selecting one of these items by using the techniques discussed below.

MORE INFORMATION

Changing the Appearance of a List Box Item

------------------------------------------

To dim (gray) a particular item in a list box, use an owner-draw list

box as follows:

1. Create a list box that has the LBS_OWNERDRAW and LBS_HASSTRINGS

   styles.

2. Use the following code to process the WM_MEASUREITEM message:

   case WM_MEASUREITEM:

      ((MEASUREITEMSTRUCT FAR *)(lParam))->itemHeight = wItemHeight;

      break;

   wItemHeight is the height of a character in the list box font.

3. Use the following code to process the WM_DRAWITEM message:

   #define PHDC (pDIS->hDC)

   #define PRC  (pDIS->rcItem)

   DRAWITEMSTRUCT FAR *pDIS;

      ...

   case WM_DRAWITEM:

      pDIS = (DRAWITEMSTRUCT FAR *)lParam;

      /* Draw the focus rectangle for an empty list box or an

         empty combo box to indicate that the control has the

         focus

       */

      if ((int)(pDIS->itemID) < 0)

      {

         switch(pDIS->CtlType)

         {

            case ODT_LISTBOX:

               if ((pDIS->itemAction) & (ODA_FOCUS))

                  DrawFocusRect (PHDC, &PRC);

               break;

            case ODT_COMBOBOX:

               if ((pDIS->itemState) & (ODS_FOCUS))

                  DrawFocusRect (PHDC, &PRC);

               break;

         }

         return TRUE;

      }

      /* Get the string */

      switch(pDIS->CtlType)

      {

         case ODT_LISTBOX:

            SendMessage ( pDIS->hwndItem,

                          LB_GETTEXT,

                          pDIS->itemID,

                          (LPARAM)(LPSTR)szBuf);

            break;

         case ODT_COMBOBOX:

            SendMessage ( pDIS->hwndItem,

                          CB_GETLBTEXT,

                          pDIS->itemID,

                          (LPARAM)(LPSTR)szBuf);

            break;

      }

      if (*szBuf == '!')   // This string is disabled

      {

         hbrGray = CreateSolidBrush (GetSysColor

                                       (COLOR_GRAYTEXT));

         GrayString ( PHDC,

                      hbrGray,

                      NULL,

                      (LPARAM)(LPSTR)(szBuf + 1),

                      0,

                      PRC.left,

                      PRC.top,

                      0,

                      0);

         DeleteObject (hbrGray);

         /* SPECIAL CASE - Need to draw the focus rectangle if

            there is no current selection in the list box, the

            1st item in the list box is disabled, and the 1st

            item has gained or lost the focus

          */

         if (pDIS->CtlType == ODT_LISTBOX)

         {

            if (SendMessage ( pDIS->hwndItem,

                              LB_GETCURSEL,

                              0,

                              0L) == LB_ERR)

               if ( (pDIS->itemID == 0) &&

                    ((pDIS->itemAction) & (ODA_FOCUS)))

                  DrawFocusRect (PHDC, &PRC);

         }

      }

      else  // This string is enabled

      {

         if ((pDIS->itemState) & (ODS_SELECTED))

         {

            /* Set background and text colors for selected

               item */

            crBack = GetSysColor (COLOR_HIGHLIGHT);

            crText = GetSysColor (COLOR_HIGHLIGHTTEXT);

         }

         else

         {

            /* Set background and text colors for unselected

               item */

            crBack = GetSysColor (COLOR_WINDOW);

            crText = GetSysColor (COLOR_WINDOWTEXT);

         }

         // Fill item rectangle with background color

         hbrBack = CreateSolidBrush (crBack);

         FillRect (PHDC, &PRC, hbrBack);

         DeleteObject (hbrBack);

         // Set current background and text colors

         SetBkColor (PHDC, crBack);

         SetTextColor (PHDC, crText);

         // TextOut uses current background and text colors

         TextOut ( PHDC,

                   PRC.left,

                   PRC.top,

                   szBuf,

                   lstrlen(szBuf));

         /* If enabled item has the input focus, call

            DrawFocusRect to set or clear the focus

            rectangle */

         if ((pDIS->itemState) & (ODS_FOCUS))

            DrawFocusRect (PHDC, &PRC);

      }

      return TRUE;

Strings that start with "!" are displayed dimmed. The exclamation mark

character is not displayed.

Preventing Selection

--------------------

To prevent a dimmed string from being selected, create the list box

with the LBS_NOTIFY style. Then use the following code in the list

box's parent window procedure to process the LBN_SELCHANGE

notification:

  case WM_COMMAND:

    switch (wParam)

      {

       ...

      case IDD_LISTBOX:

        if (LBN_SELCHANGE == HIWORD(lParam))

          {

          idx = (int)SendDlgItemMessage(hDlg, wParam,

                        LB_GETCURSEL, 0, 0L);

          SendDlgItemMessage(hDlg, wParam, LB_GETTEXT, idx,

                        (LONG)(LPSTR)szBuf);

          if ('!' == *szBuf)

            {

            // Calculate an alternate index here

            // (not shown in this example).

            // Then set the index.

            SendDlgItemMessage(hDlg, wParam, LB_SETCURSEL, idx, 0L);

            }

          }

        break;

       ...

      }

   break;

When the user attempts to select a dimmed item, the alternate index

calculation moves the selection to an available item.

Additional reference words: 3.00 3.10 3.50 4.00 95 listbox

KBCategory: kbprg

KBSubcategory: UsrCtl


Managing Per-Window Accelerator Tables

PSS ID Number: Q82171

Authored 29-Mar-1992	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

In the Windows environment, an application can have several windows,

each with its own accelerator table. This article describes a simple

technique requiring very little code that an application can use to

translate and dispatch accelerator key strokes to several windows. The

technique employs two global variables, ghActiveWindow and

ghActiveAccelTable, to track the currently active window and its

accelerator table, respectively. These two variables, which are used

in the TranslateAccelerator function in the application's main message

loop, achieve the desired result.

MORE INFORMATION

The key to implementing this technique is to know which window is

currently active and which accelerator table, if any, is associated

with the active window. To track this information, process the

WM_ACTIVATE message that Windows sends each time an application gains

or loses activation. When a window loses activation, set the two

global variables to NULL to indicate that the window and its

accelerator table are no longer active. When a window that has an

accelerator table gains activation, set the global variables

appropriately to indicate that the accelerator table is active. The

following code illustrates how to process the WM_ACTIVATE message:

case WM_ACTIVATE:

   if (wParam == 0)  // indicates loss of activation

   {

      ghActiveWindow = ghActiveAccelTable = NULL;

   }

   else              // indicates gain of activation

   {

      ghActiveWindow = <this window>;

      ghActiveAccelTable = <this window's accelerator table>;

   }

   break;

The application's main message loop resembles the following:

while (GetMessage(&msg,     // message structure

                  NULL,     // handle of window receiving the msg

                  NULL,     // lowest message to examine

                  NULL))    // highest message to examine

{

   if (!TranslateAccelerator(ghActiveWindow, // active window

                             ghActiveAccelTable, // active accelerator

                             &msg))

   {

      TranslateMessage(&msg); // Translates virtual key codes

      DispatchMessage(&msg);  // Dispatches message to

                              //   window procedure

   }

}

Under Windows version 3.1, the WM_ACTIVATE message with the wParam set

to WA_INACTIVE indicates loss of activation.

Under Win32, the low-order word of wParam set to WA_INACTIVE indicates

deactivation.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: UsrMen


Mapping .INI File Entries to the Registry

PSS ID Number: Q104136

Authored 08-Sep-1993	Last modified 20-Apr-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   versions 3.1 and 3.5

Under Windows NT, .INI file variables are mapped into the Registry as

defined in the

   \HKEY_LOCAL_MACHINE

      \Software\Microsoft\WindowsNT\CurrentVersion\IniFileMapping

mapping key. The Win32 Profile application programming interface (API)

functions look for a mapping by looking up the filename extension portion

of the profile file. If a match is found, then the search continues under

that node for the specified application name. If a match is found, then the

search continues for the variable name. If the variable name is not found,

the value of the (NULL) variable name is a string that points to a node in

the Registry, whose value keys are the variable names. If a specific

mapping is found for the variable name, then its value points to the

Registry value that contains the variable value.

The Profile API calls go to the Windows server to look for an actual .INI

file, and read and write its contents, only if no mapping for either the

application name or filename is found. If there is a mapping for the

filename but not the application name, and there is a (NULL) application

name, the value of the (NULL) variable will be used as the location in the

Registry of the variable, after appending the application name to it.

In the string that points to a Registry node, there are several

prefixes that change the behavior of the .INI file mapping:

   ! - This character forces all writes to go both to the Registry and

       to the .INI file on disk.

   # - This character causes the Registry value to be set to the value

       in the Windows 3.1 .INI file when a new user logs in for the

       first time after setup.

   @ - This character prevents any reads from going to the .INI file

       on disk if the requested data is not found in the Registry.

   USR: - This prefix stands for HKEY_CURRENT_USER, and the text after

          the prefix is relative to that key.

   SYS: - This prefix stands for HKEY_LOCAL_MACHINE\Software, and the

          text after the prefix is relative to that key.

Additional reference words: 3.10 3.50 inifilemapping

KBCategory: kbprg

KBSubcategory: BseMisc


Mapping Modes and Round-Off Errors

PSS ID Number: Q89215

Authored 14-Sep-1992	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

Mapping modes, window extents/origins, and viewport extents/origins

allow for very powerful coordinate manipulation, such as  scaling or

moving objects. However, you should be aware that there are cases when

using mapping modes other than MM_TEXT results in improper painting

due to round-off errors.

Round-off errors occur when one logical unit does not equal one device

unit, and an application requests the graphics device interface (GDI)

to perform an action that would result in a nonintegral number of

pixels needing to be drawn, scrolled, blt'd, and so on.

Round-off errors can manifest themselves in many ways, including

unpainted portions of a client area when scrolling, gaps between

objects that shouldn't have gaps (or vice versa), objects that shrink

or grow one pixel depending on where they are on the screen, objects

of unexpected sizes, and so on.

MORE INFORMATION

To better understand round-off errors, consider the following code:

  SetMapMode (hDC, MM_ANISOTROPIC);

  SetWindowExt (hDC, 2, 2);

  SetViewportExt (hDC, 3, 3);

  PatBlt (hDC, 0, 0, 5, 2, BLACKNESS);

This code tells the GDI to treat two logical units (the coordinates

used by most GDI functions), in both the vertical and horizontal

direction, as being equal to three device units (pixels). It then asks

the GDI to draw what amounts to a black rectangle five logical units

wide by three logical units tall starting at the logical point (0,0).

The GDI would translate this request into a request to draw a

rectangle 7.5 (5 * 3/2 = 7.5) pixels wide by 3 (2 * 3/2 = 3) pixels

tall. However, display cards cannot draw half a pixel, so the GDI

would either have to round the width up to 8 or truncate it to 7. If

an application relied on one behavior or the other, improper painting

could occur.

Note that using mapping modes, window origins/extents, and viewport

origins/extents does not mean that an application will have round-off

errors. The occurrence of round-off errors depends on what these

features are used for, the structure of the application, and other

factors. Many applications take advantage of mapping modes, window

origins/extents, and viewport origins/extents without ever

encountering adverse round-off errors.

If an application exhibits round-off errors, there are a number of ways

to prevent them, some which are described below.

Method 1

--------

Only use MM_TEXT mapping mode, where one logical unit always equals

one device unit. However, the application must do all its own scaling

and moving of objects. The benefit of this approach is that the

application has strict control over how objects are scaled and moved;

you can look at your code to see the algebra that leads to round-off

errors, and counter these errors appropriately. The drawback to this

approach is that it makes the code more complicated and harder to read

than it might be if the SetMapMode, SetWindowOrg, SetWindowExt,

SetViewportOrg, and SetViewportExt functions were used.

Method 2

--------

Mix MM_TEXT mapping mode with the mapping mode required. Sometimes

applications only have round-off problems with certain types of

objects. For example, in a graphing program, the application might

want to set a certain mapping mode to draw a bar graph; this mapping

mode might cause the fonts that the application draws to be of the

wrong size.

To work around problems like this, mix MM_TEXT mapping mode with your

mapping mode of choice. You could use MM_TEXT when dealing with

objects that need exact sizes or placement and the other mapping mode

for other drawing.

The benefits and drawbacks of this method are almost the same as those

for method 1. However, with method 2, applications can take advantage

of mapping modes for some of the scaling and moving of objects.

Method 3

--------

If window/viewport origins/extents are set at compile time, be sure to

only do operations that would result in no round-off errors. For

example, take the fraction WindowExt over ViewportExt, and reduce this

fraction. Then only do operations that involve multiples of the

reduced WindowExt values. For example, given the following

    WindowExt   = ( 6, 27)

    ViewportExt = (50, 39)

turn this into a fraction and reduce it. It yields:

    in x direction:   6/50 = (2 * 3) / (2 * 5 * 5)  = 3/25

    in y direction:  27/39 = (3 * 3 * 3) / (3 * 13) = 9/13

Therefore, anything done in the x direction could be done using a

multiple of three logical units; anything done in the y direction

could be done using a multiple of nine logical units. For example, if

the application wanted to scroll the window horizontally, it could

scroll 3, 6, 9, 12, and so on logical units without having to deal

with rounding errors. By using these values, the application will

never have round-off errors.

One benefit of this method is that an application can take advantage

of window origins/extents and viewport origins/extents. A disadvantage

is that the application is limited to a certain set of origins/extents

(that is, those built into the application at compile time).

Method 4

--------

Applications can perform method 3 on-the-fly. This allows the

application to deal with arbitrary window origins/extents and viewport

origins/extents. To determine the minimum number of logical units an

application could use given arbitrary extent values, the following

code might prove useful (the code shown is for determining the value

to use in the horizontal direction):

int GetMinWinXFactor (HDC hDC)

{

   int nMinX, xWinExt, xViewExt, nGCD;

   xWinExt  = LOWORD (GetWindowExt (hDC));

   xViewExt = LOWORD (GetViewportExt (hDC));

   while ((nGCD = GreatestCommonDivisor (xWinExt, xViewExt)) != 1)

      {

      xWinExt  /= nGCD;

      xViewExt /= nGCD;

      }

   return xWinExt;

}

int GreatestCommonDivisor (int i, int j)

{

   while (i != j)

      if (i > j)

         i -= j;

      else

         j -= i;

   return i;

}

The return value from the GetMinWinXFactor function above can then be

used just like in method 3 (that is, the application can do all output

based on multiples of this value).

Final Notes

-----------

The discussion above did not take into account the window origin,

which can contribute to round-off errors. How origins and extents

affect the coordinates that GDI uses is summed up in "Programmer's

Reference.

Developers using mapping modes are encouraged to study the equations

presented in the programmer's reference. The GDI uses these equations when

converting between logical and device units. When round-off errors occur in

an application, it is always a good idea to run the numbers through these

equations to try to determine the cause of the errors.

Additional reference words: 3.00 3.10 3.50 4.00 95  rounding

KBCategory: kbprg

KBSubcategory: GdiDc


Maximum Brush Size

PSS ID Number: Q12071

Authored 01-Dec-1987	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, version 4.0

The maximum size of a brush is determined by the OEM driver. In

theory, any brush size can be created. However, the brushes are

realized by the OEM driver. The only requirement the driver must

satisfy is that it must be able to handle 8 x 8 brushes.

If the driver realizes variable sizes, passing any bitmap is

acceptable. The driver decides what to do with brushes larger than

8 x 8.

Currently, sample drivers use the top left 8 x 8 piece of the pattern;

however, if the OEM wants to use the whole pattern, that also is

proper. The limit of the current device drivers is 8 x 8 because of a

performance trade-off.

The amount of pattern realized is a display driver-dependent issue.

Additional reference words: 3.00 3.10 4.00 95

KBCategory: kbprg

KBSubcategory: GdiPnbr


Memory Handle Allocation

PSS ID Number: Q91194

Authored 29-Oct-1992	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

This article discusses the limitations that exist when allocating memory

handles.

The minimum block you can reserve with each call to VirtualAlloc() is 64K.

It is a good idea to confirm this number by checking the allocation

granularity returned by GetSystemInfo().

With HeapAlloc(), there is no limit to the number of handles that can be

allocated. GlobalAlloc() and LocalAlloc() (combined) are limited to 65536

total handles for GMEM_MOVEABLE and LMEM_MOVEABLE memory per process. Note

that this limitation does not apply to GMEM_FIXED or LMEM_FIXED memory.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: BseMm


Memory Handles and Icons

PSS ID Number: Q99360

Authored 26-May-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   version 3.1

SUMMARY

Memory handles are not globally sharable among processes. Handles for

icons, cursors, windows, and so forth, are not global handles but are

handles into an index into the server-side handle table (the handle is

actually an index into the server-side's handle table). Thus, some objects

can be shared between processes -- but probably shouldn't be, for

concurrency reasons.

GDI-related objects, however, are stored in a client-side handle table,

which is translated to a handle value in a server-side table on every

client-server transition. Thus, there are some objects that can be shared

(USER-related objects) and some that can't be shared (BASE/KERNEL and GDI).

MORE INFORMATION

There are three types of handles in the system:

 - Handles to objects that the executive (object manager) knows

   about. These are assigned on a per-process basis but each access to

   these objects goes through the executive.

 - Handles that are maintained by the Win32 subsystem server (USER

   objects, including icons and cursors) and are therefore sharable.

   Please note that the allowed behavior of shared USER objects is

   subject to change in future releases of Windows NT. Thus, care

   should be taken when using these handles.

 - Handles that are maintained by the Win32 subsystem client, and

   therefore are valid only in the context of the process that created

   it (GDI objects). These handles differ from the first type of

   handles listed in that you cannot call handle manipulation

   functions, such as DuplicateHandle() an WaitForSingleObject(), or

   use the security facilities on these objects.

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: UsrMisc


Memory Requirements for a Win32 App vs. the Win16 Version

PSS ID Number: Q117892

Authored 13-Jul-1994	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5

   3.51, and 4.0

 - Microsoft Win32s, versions 1.1, 1.15, and 1.2

SUMMARY

A Win32 port of a Windows-based application generally requires more virtual

memory than the original Windows-based application. However, it is possible

for the Win32 version of the application to have a smaller working set. The

working set is the certain number of pages that the virtual memory manager

must keep in memory for a process to execute efficiently. If you lower the

working set of an application, it will use less RAM.

MORE INFORMATION

It can appear that the Win32-based version of an application running on

Win32s requires more RAM than the Windows-based version of the application

running on the same machine. This is because segments of a Windows-based

application are loaded only as they are referenced, while the address space

is reserved for the Win32-based application and its DLLs (dynamic-link

libraries) at program load. Therefore, the memory count that is displayed

by many "About" boxes is misleading: for the Windows-based application, the

free memory reported is reduced by the number of segments actually loaded;

for the Win32-based application, the free memory reported is reduced by the

total address space required. However, this free memory represents only the

virtual address space that all applications share, not the amount of RAM

actually used.

You can use WMem to determine the address space used, the number of

physical pages of RAM used, and to get an estimate of the working set. On a

machine that has enough RAM to load the whole application without swapping,

run only Program Manager and WMem. Use SHIFT+double-click in WMem and write

down the available physical memory. Activate the application and use

SHIFT+double-click again. The difference between the available physical

memory before and after activating the application is a rough estimate of

the working set. Test your application further and see how the working set

changes during execution.

The working set of a Win32-based application can be decreased 30 percent or

more with the use of the Working Set Tuner, included in the Win32 SDK.

However, a Win32-based application may fail to load on Win32s even if its

working set is significantly smaller than the free RAM (for example, 100K

working set versus 1 megabyte free RAM). The entire application, DLLs

included, must be mapped into the virtual address space.

The virtual memory size is set by the system at boot time, based on several

factors. RAM is one factor, free disk space is another. The system must be

able to allocate enough space for the swap file on disk. Windows, by

default, allows the size of the swap file to be a maximum of 4 times larger

than available RAM. This constant (4) can be modified by setting

PageOverCommit in the 386enh section of the SYSTEM.INI file. Valid settings

are between 1 and 20. Setting PageOverCommit to a value larger than 4 will

result in less efficient usage of resources and slower execution, but it

will allow you to run applications that otherwise are not able to run.

Additional reference words: 1.10 1.20 3.10 3.50 4.00 95  ProgMan

KBCategory: kbprg

KBSubcategory: BseMm


Menu Operations When MDI Child Maximized

PSS ID Number: Q71836

Authored 04-May-1991	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

Pop-up menus added to an MDI application's menu using InsertMenu() with

MF_BYPOSITION will be inserted one position further left than expected if

the active MDI child window is maximized. This behavior occurs because the

system menu of the active MDI child is inserted into the first position of

the MDI frame window's menu bar.

To avoid this problem, if the active child is maximized when a new pop-up

is inserted by position, add 1 (one) to the position value that would

otherwise have been used. To determine that the currently active child

window is maximized, send a WM_MDIGETACTIVE message to the MDI client

window. In 16-bit Windows, if the high word of the return value from this

message contains 1, the active child window is maximized. In Win32, you

need to pass a pointer to a BOOL in the lParam. If the child window is

maximized, then Windows will set the BOOL pointed to by the lParam to TRUE.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: UsrMdi


Message Retrieval in a DLL

PSS ID Number: Q96479

Authored 18-Mar-1993	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.1 and 3.0

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

When a function in a dynamic-link library (DLL) retrieves messages on

behalf of a calling application, the following must be addressed:

 - The application and the DLL may be re-entered.

 - The application can terminate while in the DLL's message retrieval

   loop.

 - The DLL must allow the application to preprocess any messages that

   may be retrieved.

MORE INFORMATION

The following concerns arise when a function in a DLL retrieves

messages by calling GetMessage or PeekMessage:

 - When the DLL function retrieves, translates, and dispatches

   messages, the calling application and the DLL function may be re-

   entered. This is because message retrieval can cause the calling

   application to respond to user input while waiting for the DLL

   function to return. The DLL function can return a reentrancy error

   code if this happens. To prevent reentrancy, disable windows and

   menu-items, or use a filter in the GetMessage or PeekMessage call

   to retrieve specific messages.

 - The application can terminate while execution is in the DLL

   function's message retrieval loop. The WM_QUIT message retrieved by

   the DLL must be re-posted and the DLL function must return to the

   calling application. This allows the calling application's message

   retrieval loop to retrieve WM_QUIT and terminate.

 - When the DLL retrieves messages, it must allow the calling

   application to preprocess the messages (to call

   TranslateAccelerator, IsDialogMessage, and so forth) if required.

   This is be done by using CallMsgFilter to call any WH_MSGFILTER

   hook that the application may have installed.

The following code shows a message retrieval loop in a DLL function

that waits for a PM_COMPLETE message to signal the end of processing:

while (notDone)

{

   GetMessage(&msg, NULL, 0, 0);

   // PM_COMPLETE is a WM_USER message that is posted when

   // the DLL function has completed.

   if (msg.message == PM_COMPLETE)

   {

      Clean up and set result variables;

      return COMPLETED_CODE;

   }

   else if (msg.message == WM_QUIT)  // If application has terminated...

   {

      // Repost WM_QUIT message and return so that calling

      // application's message retrieval loop can exit.

      PostQuitMessage(msg.wParam);

      return APP_QUIT_CODE;

   }

   // The calling application can install a WH_MSGFILTER hook and

   // preprocess messages when the nCode parameter of the hook

   // callback function is MSGF_MYHOOK. This allows the calling

   // application to call TranslateAccelerator, IsDialogMessage, etc.

   if (!CallMsgFilter(&msg, MSGF_MYHOOK))

   {

      TranslateMessage(&msg);

      DispatchMessage(&msg);

   }

   :

   :

}

Define MSGF_HOOK to a value greater than or equal to MSGF_USER defined

in WINDOWS.H to prevent collision with values used by Windows.

Preprocessing Messages in the Calling Application

-------------------------------------------------

The calling application can install a WH_MSGFILTER hook to preprocess

messages retrieved by the DLL. It is not required for the calling

application to install such a hook if it does not want to preprocess

messages.

   lpfnMsgFilterProc = MakeProcInstance((FARPROC)MsgFilterHookFunc,

                                          ghInst);

   hookprocOld = SetWindowsHook(WH_MSGFILTER, lpfnMsgFilterProc);

   // Call the function in the DLL.

   DLLfunction();

   UnhookWindowsHook(WH_MSGFILTER, lpfnMsgFilterProc);

   FreeProcInstance(lpfnMsgFilterProc);

MsgFilterHookFunc is the hook callback function:

LRESULT CALLBACK MsgFilterHookFunc(int nCode, WPARAM wParam,

                                   LPARAM lParam)

{

   if (nCode < 0)

      return DefHookProc(nCode, wParam, lParam, &hookprocOld);

   // If CallMsgFilter is being called by the DLL.

   if (nCode == MSGF_MYHOOK)

   {

      Preprocess message (call TranslateAccelerator,

          IsDialogMessage etc.);

      return 0L if the DLL is to call TranslateMessage and

          DispatchMessage. Return 1L if TranslateMessage and

          DispatchMessage are not to be called.

   }

   else return 0L;

}

Additional reference words: 3.10 3.50 3.51 4.00 95  yield

KBCategory: kbprg

KBSubcategory: UsrMsg


Method for Sending Text to the Clipboard

PSS ID Number: Q35100

Authored 01-Sep-1988	Last modified 12-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

Sending text to the Clipboard is usually a cumbersome process of

allocating and locking global memory, copying the text to that memory,

and sending the Clipboard the memory handle. This method involves many

pointers and handles and makes the entire process difficult to use and

understand.

Clipboard I/O is easily accomplished with an edit control. If a

portion of text is highlighted, an application can send the edit

control a WM_COPY or WM_CUT message to copy or cut the selected text

to the Clipboard. In the same manner, text can be pasted from the

Clipboard by sending a WM_PASTE message to an edit control.

The following example demonstrates how to use an edit control

transparently within an application to simplify sending and retrieving

text from the Clipboard. Note that this code will not be as fast as

setting or getting the Clipboard data explicitly, but it is easier

from a programming standpoint, especially if the text to be sent is

already in an edit control. Note also that the presence of the edit

window will occupy some additional memory.

MORE INFORMATION

For simplified Clipboard I/O, do the following:

1. Declare a global HWND, hEdit, which will be the handle to the edit

   control.

2. In WinMain, use CreateWindow() to create a child window edit

   control. Use the style WS_CHILD, and give the control dimensions

   large enough to hold the most text that may be sent to or received

   from the Clipboard. CreateWindow() returns the handle to the edit

   control that should be saved in hEdit.

3. When a Cut or Copy command is invoked, use SetWindowText() to place

   the desired string in the edit control, then use SendMessage() to

   select the text and copy or cut it to the Clipboard.

4. When a Paste command is invoked, use SetWindowText() to clear the

   edit control, then use SendMessage() to paste text from the

   Clipboard. Finally, use GetWindowText() to copy the text in the

   edit control to a string buffer.

The actual coding for this procedure is as follows:

    .

    .

    .

    #define ID_ED    100

    HWND       hEdit;

    .

    .

    .

    /* In WinMain: hWnd is assumed to be the handle of the parent window,

*/

    /* hInstance is the instance handle of the parent.

*/

    /* The "EDIT" class name is required for this method to work. ID_ED

*/

    /* is an ID number for the control, used by Get/SetDlgItemText.

*/

    hEdit=CreateWindow("EDIT",

                       NULL,

                       WS_CHILD | BS_LEFTTEXT,

                       10, 15, 270, 10,

                       hWnd,

                       ID_ED,

                       hInstance,

                       NULL);

    .

    .

    .

    /* In the procedure receiving CUT, COPY, and PASTE commands:         */

    /* Note that the COPY and CUT cases perform the same actions, only   */

    /* the CUT case clears out the edit control.                         */

    /* Get the string length */

    short    nNumChars=strlen(szText);

    case CUT:

        /* First, set the text of the edit control to the desired string */

        SetWindowText(hEdit, szText);

        /* Send a message to the edit control to select the string */

        SendMessage(hEdit, EM_SETSEL, 0, MAKELONG(0, nNumChars));

        /* Cut the selected text to the clipboard */

        SendMessage(hEdit, WM_CUT, 0, 0L);

        break;

    case COPY:

        /* First, set the text of the edit control to the desired string */

        SetWindowText(hEdit, szText);

        /* Send a message to the edit control to select the string */

        SendMessage(hEdit, EM_SETSEL, 0, MAKELONG(0, nNumChars));

        /* Copy the text to the clipboard */

        SendMessage(hEdit, WM_COPY, 0, 0L);

        break;

    case IDM_PASTE:

        /* Check if there is text available */

        if (IsClipboardFormatAvailable(CF_TEXT))

            {

            /* Clear the edit control */

            SetWindowText(hEdit, "\0");

            /* Paste the text in the clipboard to the edit control */

            SendMessage(hEdit, WM_PASTE, 0, 0L);

            /* Get the test from the edit control into a string.    */

            /* nNumChars represents the number of characters to get */

            /* from the edit control.                               */

            GetWindowText(hEdit, szText, nNumChars);

            }

        else

            MessageBeep(0); /* Beep on illegal request */

        break;

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrClp


Microsoft Win32s Upgrade

PSS ID Number: Q122235

Authored 01-Nov-1994	Last modified 20-Jun-1995

The information in this article applies to:

 - Microsoft Win32s, version 1.25a

SUMMARY

Microsoft Win32s version 1.25a, the latest version of the software that

allows you to run Win32-based applications on Windows version 3.1 or

Windows for Workgroups versions 3.1 and later, is now available as a

Microsoft Application Note.

The Application Note number is PW1118, and the title is "Microsoft

Win32s Upgrade." It includes these files:

 - W32S125.EXE, which is version 1.25a of Win32s.

 - LICENSE.TXT, which has legal information regarding redistribution of

   Win32s files [please consult the Win32s "Programmer's Reference," which

   is part of the Microsoft Win32 Software Development Kit (SDK), for

   further information].

 - README.TXT, which is the text of the Application Note.

The "Microsoft Win32s Upgrade" does not include OLE support. For OLE

support for Win32-based applications under Win32s, obtain the OLE 2.02

appnote, number WW1116. For more information, please see the following

article in the Microsoft Knowledge Base:

   ARTICLE-ID: Q123087

   TITLE     : WW1116: OLE Version 2.02

The Win32s upgrade is intended as an end-user upgrade and is not intended

for further redistribution.

MORE INFORMATION

To obtain this Application Note (number PW1118) and the files

included with it, download PW1118.EXE, a self-extracting file,

from the Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for PW1118.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download PW1118.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get PW1118.EXE

If you are unable to access the sources listed above, you can have this

Application Note mailed to you by calling Microsoft Product Support

Services Monday through Friday, 6:00 A.M. to 6:00 P.M. Pacific time. If

you are outside the United States, contact the Microsoft subsidiary for

your area. To locate your subsidiary, please call Microsoft International

Customer Service at (206) 936-8661.

Additional reference words: 1.25a

KBCategory: kbsetup kbappnote kbfile

KBSubcategory: W32s


MIDL 1.0 and MIDL 2.0 Full Pointers Do Not Interoperate

PSS ID Number: Q115830

Authored 05-Jun-1994	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   version 3.5

Microsoft Remote Procedure Call (RPC), version 1.0, has minimal support for

full pointers, so the version of the MIDL compiler with Microsoft RPC

version 1.0 (MIDL 1.0) treats full pointers (specified with the ptr

attribute) as unique pointers (specified with the unique attribute).

The MIDL compiler with Microsoft RPC, version 2.0 (MIDL 2.0), supports full

pointers. Because of the way Microsoft RPC, version 1.0, handles the on-

wire representation of pointers, applications compiled using MIDL 2.0 full

pointers cannot operate interactively with applications compiled using MIDL

1.0 full pointers.

The workaround is to recompile the MIDL 2.0 application to use unique

pointers.

Additional reference words: 3.50

KBCategory: kbprg

KBSubcategory: NtwkRpc


Mirroring Main Menu with TrackPopupMenu()

PSS ID Number: Q99806

Authored 08-Jun-1993	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

A developer may want to use TrackPopupMenu() to display the same menu

that is used by the main window. TrackPopupMenu() takes a pop-up menu,

while GetMenu() and LoadMenu() both return handles to top level menus,

and therefore you cannot use the menus returned from these functions

with TrackPopupMenu(). To "mirror" the main menu, you must create

pop-up menus with the same strings, style, and IDs as the main menu.

To do this, use the following Windows APIs:

   GetMenu()

   CreatePopupMenu()

   GetMenuState()

   GetMenuString()

   GetSubMenu()

   AppendMenu()

MORE INFORMATION

The following code displays the same menu as the main window when the

right mouse button is clicked:

// In the main window procedure...

    case WM_RBUTTONDOWN:

    {

           HMENU hMenu;            // The handle to the main menu.

           int nMenu;              // The index of the menu item.

           POINT pt;             // The point to display the track menu.

           HMENU hMenuOurs;        // The pop-up menu that we are creating.

           UINT nID;             // The ID of the menu.

           UINT uMenuState;        // The menu state.

           HMENU hSubMenu;        // A submenu.

           char szBuf[128];        // A buffer to store the menu string.

// Get the main menu.

           hMenu = GetMenu(hWnd);

           nMenu = 0;

// Create a pop-up menu.

           hMenuOurs = CreatePopupMenu();

// Get menu state will return the style of the menu

// in the lobyte of the unsigned int. Return value

// of -1 indicates the menu does not exist, and we

// have finished creating our pop up.

           while ((uMenuState =

              GetMenuState(hMenu,nMenu,MF_BYPOSITION)) != -1)

           {

                if (uMenuState != -1)

                {

// Get the menu string.

              GetMenuString(hMenu,nMenu, szBuf,128,MF_BYPOSITION);

                    if (LOBYTE(uMenuState) & MF_POPUP) // It's a pop-up

menu.

                    {

                        hSubMenu = GetSubMenu(hMenu,nMenu);

                           AppendMenu(hMenuOurs,

                    LOBYTE(uMenuState),hSubMenu,szBuf);

                    }

                    else  // Is a menu item, get the ID.

                    {

                        nID = GetMenuItemID(hMenu,nMenu);

                        AppendMenu(hMenuOurs,LOBYTE(uMenuState),nID,szBuf);

                    }

                    nMenu++;  // Get the next item.

                }

        }

        pt = MAKEPOINT(lParam);

// TrackPopupMenu expects screen coordinates.

        ClientToScreen(hWnd,&pt);

           TrackPopupMenu(hMenuOurs,

          TPM_LEFTALIGN|TPM_RIGHTBUTTON,

          pt.x,pt.y,0,hWnd,NULL);

// Because we are using parts of the main menu in our

// pop-up menu, we can't just delete the pop-up menu, because

// that would also delete the main menu. So we must

// go through the pop-up menu and remove all the items.

        while (RemoveMenu(hMenuOurs,0,MF_BYPOSITION))

            ;

// Destroy the pop-up menu.

        DestroyMenu(hMenuOurs);

    }

    break;

If the menu is never dynamically modified, then the menu hMenuOurs

could be made static and created inside the WM_CREATE message, and

destroyed in the WM_DESTROY message.

To see how this function works, paste this code into the MENU sample

application shipped with both Microsoft Visual C/C++ and Microsoft

C/C++ version 7.0 in the file MENU.C in the MenuWndProc() function.

Additional reference words: 3.10 3.50 3.51 4.00 95  popup

KBCategory: kbprg

KBSubcategory: UsrMen


Missing Japanese Win32s-J Version 1.25 Files

PSS ID Number: Q130844

Authored 30-May-1995	Last modified 20-Jun-1995

The information in this article applies to:

 - Microsoft Japanese Win32s-J version 1.25

SUMMARY

The files missing from the Japanese Win32s version 1.25 release included in

MSDN (Microsoft Developers Network) Development Platform April '95 (CD 1)

are now available.

Download WIN32SJ.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for WIN32SJ.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download WIN32SJ.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the SOFTLIB\MSLFILES directory

      Get WIN32SJ.EXE

MORE INFORMATION

The following files are missing from the MSDN Win32s-J v1.25 NODEBUG

directory:

ole2conv.dll

ole2conv.sym

ole2disp.dll

ole2disp.sym

ole2nls.dll

ole2nls.sym

ole2prox.dll

ole2prox.sym

ole2thk.dll

ole32.dll

oleaut32.dll

oleaut32.sym

olecli.dll

olecli32.dll

olecli32.sym

olesvr32.dll

olesvr32.sym

sck16thk.dll

shell32.dll

shell32.sym

stdole.tlb

stdole32.tlb

storage.dll

typelib.dll

typelib.sym

version.dll

version.sym

w32s.386

w32scomb.dll

w32scomb.sym

w32skrnl.dll

w32sys.dll

win32s.exe

win32s16.dll

winmm.dll

winmm16.dll

winspool.drv

winspool.sym

wsock32.dll

wsock32.sym

All of these files are included in the self-extracting file (WIN32SJ.EXE)

available from the MSL.

Additional reference words: 1.25 3.10 kbinf kbmsdn

KBCategory: kbother kbfile

KBSubcategory: wintldev


Mixer Manager Incorporated into NT 3.5 SDK and DDK

PSS ID Number: Q124504

Authored 03-Jan-1995	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.5, 3.51,

   and 4.0

 - Microsoft Win32 Device Development Kit (DDK) version 3.5

In Windows version 3.1, the Mixer Manager Application Programming Interface

(API) and Mixer Manager Service Provider Interface (SPI) are provided by

the Windows Sound System Version 2.0 Driver Development Kit (DDK). The

Windows Sound System Version 2.0 DDK supports 16-bit application and driver

development for digital audio mixers.

Starting with Windows NT version 3.5, the Mixer Manager API has been

incorporated into the Win32 SDK, and the Mixer Manager SPI has been

incorporated into the Win32 DDK. As a result, there is no 32-bit version of

the Windows Sound System Version 2.0 DDK; all of its functions have been

incorporated into the Win32 SDK and DDK.

Additional reference words: 3.50 4.00 95  WSS DDK Mixer Manager

KBCategory: kbmm

KBSubcategory: MMMixer


MoveFileEx Not Supported in Windows 95 But Functionality Is

PSS ID Number: Q129532

Authored 27-Apr-1995	Last modified 07-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) version 4.0

SUMMARY

Win32 applications running on Windows NT use MoveFileEx() with the

DELAY_UNTIL_REBOOT flag to move, replace, or delete the files currently

being used. Examples of such files include device drivers and setup

programs. To replace a file that is in use, you would do something like

this:

   MoveFileEx(szDstFile, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);

   MoveFileEx(szSrcFile, szDstFile, MOVEFILE_DELAY_UNTIL_REBOOT);

Windows 95 does not implement MoveFileEx() but does provide an alternate

way for all Win32-, Win16-, and MS-DOS-based applications to move, replace,

or delete files that are currently in use. To replace a file that is in

use, you would do something like this:

   GetWindowsDirectory(szTmpName, cchpFullPathBuf);

   lstrcat(szTmpName, "\\WININIT.INI");

   WritePrivateProfileString("Rename", "NUL", szDstFile, szTmpName);

   WritePrivateProfileString("Rename", szDstFile, szSrcFile, szTmpname);

MORE INFORMATION

Although Windows 95 does not implement MoveFileEx(), it provides similar

functionality to the DELAY_UNTIL_REBOOT flag through the [rename] section

of WININIT.INI. If WININIT.INI is present in the Windows directory,

WININIT.EXE processes it when the system boots. Once WININIT.INI has been

processed, WININIT.EXE renames it to WININIT.BAK.

The syntax of the [rename] section is:

   DestinationFileName=SourceFileName

NOTE: The source and destination filenames in WININIT.INI must be 8.3 file

names. Long filenames are not processed.

The [rename] section can have multiple lines with one file per line. To

delete a file, specify NUL as the DestinationFileName.

NOTE: DestinationFileName and SourceFileName cannot be long filenames,

because WININIT.INI is processed before the protected mode disk system is

loaded, and long filenames are only available when the protected mode disk

system is running.

Here are some example entries:

   [rename]

   NUL=C:\TEMP.TXT

   C:\NEW_DIR\EXISTING.TXT=C:\EXISTING.TXT

   C:\NEW_DIR\NEWNAME.TXT=C:\OLDNAME.TXT

   C:\EXISTING.TXT=C:\TEMP\NEWFILE.TXT

The first line causes TEMP.TXT to be deleted. The second line causes

EXISTING.TXT to be moved to a new directory. The third line causes

OLDNAME.TXT to be moved and renamed. The fourth line causes an existing

file to be overwritten by NEWFILE.TXT.

Applications should not use WritePrivateProfileString() to write entries to

the [rename] section because there can be multiple lines with the same

DestinationFileName, especially if DestinationFileName is "NUL." Instead,

they should add entries by parsing WININIT.INI and appending them to the

end of the [rename] section.

Applications that use WININIT.INI should check for its existence in the

Windows directory. If WININIT.INI is present, then another application has

written to it since the system was last restarted. Therefore, the

application should open it, and add entries to the [rename] section. If

WININIT.INI isn't present, the application should create it and add to the

[rename] section. Doing so ensures that entries from other applications

won't be deleted accidentally by your application.

NOTE: WININIT.INI is not processed until Windows 95 is restarted.

Additional reference words: 4.00

KBCategory: kbprg

KBSubcategory: BseFileio


MS Setup Disklay2 Utility Calls COMPRESS.EXE Internally

PSS ID Number: Q103071

Authored 16-Aug-1993	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

 - Microsoft Win32 SDK, versions 3.1, 3.5, 3.51, and 4.0

The Disklay2 utility that comes with the Microsoft Setup Toolkit calls the

COMPRESS.EXE application internally to compress files. If this utility

cannot be found during the execution of Disklay2, the infamous "Bad Command

or Filename" error results. The screen dump of the results of Disklay2's

progress will contain this error message. The solution is to ensure

COMPRESS.EXE is available in the path.

COMPRESS.EXE is a component of the Windows Software Development Kit (SDK).

Additional reference words: 3.10 3.50 4.00 95  mssetup tool kit

KBCategory: kbtool

KBSubcategory: TlsMss


MultiByteToWideChar() Codepages CP_ACP/CP_OEMCP

PSS ID Number: Q108450

Authored 12-Dec-1993	Last modified 24-Mar-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

SUMMARY

MultiByteToWideChar() maps a character string to a wide-character string.

The declaration of this application programming interface (API) is as

follows:

   int MultiByteToWideChar(uCodePage, dwFlags, lpMultiByteStr,

      cchMultiByte, lpWideCharStr, cchWideChar)

   UINT uCodePage;         /* codepage                        */

   DWORD dwFlags;          /* character-type options           */

   LPCSTR lpMultiByteStr;  /* address of string to map         */

   int cchMultiByte;       /* number of characters in string   */

   LPWSTR lpWideCharStr;   /* address of wide-character buffer */

   int cchWideChar;        /* size of wide-character buffer    */

The first parameter, uCodePage, specifies the codepage to be used when

performing the conversion. This discussion applies to the first parameter

of WideCharToMultiByte() as well. The codepage can be any valid codepage

number. It is a good idea to check this number with IsValidCodepage(), even

though MultiByteToWideChar() returns an error if an invalid codepage is

used. The codepage may also be one of the following values:

   CP_ACP       ANSI codepage

   CP_OEMCP     OEM (original equipment manufacturer) codepage

CP_ACP instructs the API to use the currently set default Windows ANSI

codepage. CP_OEMCP instructs the API to use the currently set default OEM

codepage.

If Win32 ANSI APIs are used to get filenames from a Windows NT system, use

CP_ACP when converting the string. Windows NT retrieves the name from the

physical device and translates the OEM name into Unicode. The Unicode name

is translated into ANSI if an ANSI API is called, then it can be translated

back into Unicode with MultiByteToWideChar().

If filenames are being retrieved from a file that is OEM encoded, use

CP_OEMCP instead.

MORE INFORMATION

When an application calls an ANSI function, the FAT/HPFS file systems will

call AnsiToOem(); however, if an ANSI character does not exist in an OEM

codepage, the filename will not be representable. In these cases,

SetFileApisToOEM() should be called to prevent this problem by setting a

group of the Win32 APIs to use the OEM codepage instead of the ANSI

codepage.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: WIntlDev


Multicolumn List Boxes in Microsoft Windows

PSS ID Number: Q64504

Authored 06-Aug-1990	Last modified 18-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.1 and 3.0

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

In the Microsoft Windows environment, a multicolumn list box is

designed to contain homogeneous data. For example, all the data might

be "first names." These first names could logically fall into the same

column or be in multiple columns. This feature was added to Windows at

version 3.0 to enable a list box to be shorter vertically by splitting

the data into two or three columns.

MORE INFORMATION

To create a multicolumn list box, specify the LBS_MULTICOLUMN style

when creating the list box. Then the application calls the SendMessage

function to send an LB_SETCOLUMNWIDTH message to the list box to set

the column width.

When an application sends an LB_SETCOLUMNWIDTH message to a

multicolumn list box, Windows does not update the horizontal scroll

bar until the a string is added to or deleted from the list box. An

application can work around this situation by performing the following

six steps when the column width changes:

1. Send the LB_SETCOLUMNWIDTH message to the list box.

2. Send a WM_SETREDRAW message to the list box to turn off redraw.

3. Add a string to the list box.

4. Delete the string from the list box.

5. Send a WM_SETREDRAW message to the list box to turn on redraw.

6. Call the InvalidateRect function to invalidate the list box.

In response, Windows paints the list box and updates the scroll bar.

Windows automatically manages the list box, including horizontal and

vertical scrolling and distributing the entries into columns. The

distribution is dependent on the dimensions of the list box. Windows

fills Column 1 first, then Column 2, and so on. For example, if an

application has a list box containing 13 ordered items and vertical

space for 5 items, items 1-5 would be in the first column, items 5-10

in the second, and 11-13 in the last column, and item order would be

maintained.

A multicolumn list box cannot have variable column widths.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrCtl


Multiline Edit Control Does Not Show First Line

PSS ID Number: Q66668

Authored 01-Nov-1990	Last modified 18-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.10 3.5, 3.51, and 4.0

When a multiline edit control is created that is less than one system

character in height, the text in the edit control will not be displayed and

subsequent attempts to enter text will cause the edit control to beep. This

functionality is an invalid multiline edit control under Microsoft Windows

versions 3.0 and later, even though this construct does work in Windows

versions 2.x.

The multiline edit control also checks to see if the next line of text is

displayable. If the next line of text is not displayable, it will beep to

let you know that you have reached the limit of the edit control.

There is a similar situation with a control that overlaps another control

in a dialog box. This construct is also considered invalid; thus, the

second control will not be displayed.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrCtl


Multiline Edit Control Limits in Windows NT

PSS ID Number: Q89712

Authored 28-Sep-1992	Last modified 12-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)versions 3.1, 3.5,

   3.51, and 4.0

The default maximum size for a multiline edit (MLE) control in both Windows

and Windows NT is 30,000 characters. The EM_LIMITTEXT message allows an

application to increase this value. Setting "cchmax" to 0 is a portable

method of increasing this limit to the maximum in both Windows and Windows

NT. When cchmax is set to 0, the maximum size for an MLE is 4GB-1 (4

gigabytes minus 1).

Additional reference words: 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrCtl


Multiline Edit Control Wraps Text Different than DrawText

PSS ID Number: Q67722

Authored 12-Dec-1990	Last modified 23-Jun-1995

-

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK), versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

-

SUMMARY

Multiline edit controls will not wrap text in the same manner as the

DrawText() function. This can be a problem when an application

displays text that has been in an edit control because the text may

wrap in a different location.

It is possible to obtain the text from the edit control and display it

statically in a window with the same line breaks. To do this, the

application must retrieve each line of text separately. This can be

accomplished by sending the EM_GETLINE message to the control and

displaying the retrieved text with the TextOut() function.

MORE INFORMATION

The following is a brief code fragment that demonstrates how to obtain

the text of a multiline edit control line by line:

   ... /* other code */

   char  buf[80];         // Buffer for line storage

   HDC   hDC;             // Temporary display context

   HFONT hFont;           // Temporary font storage

   int   iNumEditLines;   // How much text

   TEXTMETRIC tm;         // Text metrics

   // Get number of lines in the edit control

   iNumEditLines = SendMessage(hEditCtl, EM_GETLINECOUNT, 0, 0L);

   hDC = GetDC(hWnd);

   // Get font currently selected into the control

   hFont = SendMessage(hEditCtl, WM_GETFONT, 0, 0L);

   // If it is not the system font, then select it into DC

   if (hFont)

      SelectObject(hDC, hFont);

   GetTextMetrics(hDC, &tm);

   iLine = 0;

   while (iNumEditLines--)

      {

      // First word of buffer contains max number of characters

      // to be copied

      buf[0] = 80;

      // Get the current line of text

      nCount = SendMessage(hEditCtl, EM_GETLINE, iLine, (LONG)buf);

      TextOut(hDC, x, y, buf, nCount);  // Output text to device

      y += tm.tmHeight;

      iLine++;

      }

   ReleaseDC(hWnd, hDC);

   ... /* other code */

The execution time of this code could be reduced by using the

ExtTextOut() function instead of TextOut().

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: UsrCtl


Multimedia API Parameter Changes in the Win32 API

PSS ID Number: Q125864

Authored 07-Feb-1995	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

SUMMARY

This article discusses the following topics concerning multimedia APIs in

the Win32 SDK:

 - Some Windows version 3.1 APIs that require a device ID will also accept

   a properly cast device handle in the Win32 API if the caller is a 32-bit

   application.

 - Some Windows version 3.1 APIs that require a device handle will also

   accept a properly cast device ID in the Win32 API if the caller is a

   32-bit application.

 - An explanation of the difference between using a device ID and using a

   device handle in conjunction with the above functions is given.

 - A list of related APIs that are now obsolete but are provided for

   backwards compatibility with Windows version 3.1 is given.

MORE INFORMATION

Functions That Accept A Device Handle

-------------------------------------

Several MIDI and wave audio APIs have been revised in Win32 to

provide greater flexibility to application developers. The following

APIs require the calling application to provide a device ID for the

target device under Windows 3.1, but under Win32 the APIs also

accept a properly cast device handle if the caller is a 32-bit

application:

   midiInGetDevCaps

   midiOutGetDevCaps

   waveInGetDevCaps

   waveOutGetDevCaps

Functions That Accept A Device ID

---------------------------------

Conversely, the following APIs require the calling application to

provide a device handle under Windows 3.1, but under Win32 the APIs

also accept a properly cast device ID if the caller is a 32-bit

application:

   midiOutGetVolume

   midiOutSetVolume

   waveOutGetVolume

   waveOutSetVolume

Device ID vs. Device Handle

---------------------------

A device ID has a one-to-one correspondence with the physical device

it references and is determined by querying for the number of

devices of a given type in the system and selecting the desired

device. A device handle refers to a specific instance of a device,

of which there may be more than one, and is obtained by opening a

device. A device instance may be thought of as a logical copy of

a physical device.

If a 32-bit application is querying a device's capabilities using

one of the xxxGetDevCaps APIs listed above, the distinction between

whether a device ID or device handle is used in the function call

is unimportant because all instances of a device have the same

capabilities. The result of one of these function calls will be the

same whether or not a device ID or device handle was used.

However, if a 32-bit application uses one of the xxxVolume APIs listed

above to get or set the output volume of a device, the distinction

between using a device ID or device handle becomes important. If a

device ID is used in a call to these xxxVolume APIs, then the result

of the call and/or information returned applies to all instances of

the device. If a device handle is used in a call to the xxxVolume

APIs, then the result of the call and/or information returned by the

call applies only to the instance of the device referenced by the

device handle.

The revised versions of the above APIs are available to 32-bit

applications only. For backwards compatibility reasons, 16-bit

applications are subject to the API design of Windows 3.1.

Obsolete APIs

-------------

In addition to the above changes, the following related APIs are now

obsolete, but are included in Win32 for backwards compatibility

purposes:

   midiInGetID

   midiOutGetID

   waveInGetID

   waveOutGetID

For further information about all the above APIs and how to use

device IDs and device handles, please consult the Win32

Multimedia Programmer's Reference.

Additional reference words: 4.00 95

KBCategory: kbmm

KBSubcategory: MmMisc


Multimedia Group System and API Design Guidelines

PSS ID Number: Q67692

Authored 11-Dec-1990	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

The Microsoft Multimedia Systems Group is doing a large amount of

system design and implementation. This article comments on the areas of

system design.

MORE INFORMATION

Definitions

-----------

   Term      Definition

   ----      ----------

   Module    A module provides a set of functions and the interface to

             access those functions. The interface is called the API.

   Client    A client uses a module. A client might be an application

             or a dynamic-link library (DLL).

   Prefix    The initialization portion of the module that must be

             called before any of the other functions can be accessed.

   Postfix   The closing portion of the module that must be called

             after the client has finished using the functions of the

             module.

   Channel   A channel is created by calling a module's prefix

             function. It is used by the rest of the functions of the

             module (including the postfix function).

             Two notes about a channel:

             1. A module can allocate resources to a channel. For

                example, a handle to a window is a channel, which has

                memory, a window procedure, and many other resources

                associated with it.

             2. The channel uniquely identifies the user of the

                interface to the module. This allows the module to

                perform functions uniquely on each open channel. For

                example, each file handle represents a different file

                that has been opened. Each file handle may have

                different attributes (read, write, read/write, binary,

                and so forth).

Separate Driver Interface from Module Interface

-----------------------------------------------

Separating the application from the hardware is one of the major tasks

of system software. Layers within the operating system are separated

from the hardware through the use of drivers. The system interface to

the application should hide the mechanisms of the drivers as much as

possible. This allows changing the mechanics of a driver in a later

version of the system software. This also preserves the formality of

the interface; applications are prevented from directly accessing the

hardware.

Each application should also be separated from the drivers within the

system. The driver API should not depend on where the driver is

located, what it is named, or what form it takes (DLL, VxD, and so

forth).

A driver should shield the application writer from its internal

workings to enforce the principle of information hiding. If too much

information is available, the application writer may choose to

directly access the hardware, which jeopardizes the separation of

functionality provided by the driver mechanism and system API.

Every Module Should Have an Initialization Function

----------------------------------------------------

Requiring the application to call a prefix function before using a

system module and a postfix function after using a system module

provides three major benefits, as follows:

1. Later versions of the driver can easily virtualize resources

   because the driver defies a channel for all communication. The

   driver can maintain separate resources for each communication

   channel, which is required for virtualization.

   Note that the complete virtualization does not need to be done in

   the first implementation of the module. As long as the interface

   requires the prefix and postfix calls, subsequent prefix calls can

   fail with an appropriate error message. Future versions of the

   system can properly handle multiple requests for the system

   resource.

2. The system module can allocate resources when the channel is

   allocated (when the prefix function is called), rather than when

   the system is initialized. Modules that are not called consume no

   resources. Resource allocation for all modules is postponed as long

   as possible.

3. The system can resolve conflicts between clients through the

   identification provided by the channels.

Interface Naming

----------------

During the process of designing a new module, use the interface naming

conventions from an existing module with similar functionality. For

example, an interface that deals with files would have a prefix

interface containing the word "open," and a postfix interface

containing the word "close." Extend naming conventions to similar

functional areas. A stream interface would also have an "open" and a

"close" function.

If the module has new functionality, then the functions can have

unique names, such as the MIDI driver's midiOutStop function. If the

module is similar to but not the same as another module, then use the

function name to distinguish between modules. For example, the

CreateWindow and CreateWindowEx functions in Windows create windows

but CreateWindowEx also allows an application to specify other

attributes.

The goal is to provide programmers familiar with existing modules a

basis by which to quickly learn the new interface.

Prefix function names with the module name (abbreviated, if

necessary). This allows the documentation to sort function names

alphabetically, while keeping related functions together. More

importantly, it allows easy identification of the module to which a

function belongs.

Definition Naming

-----------------

Prefix the names of constants and data structures with the module name

(abbreviated, if necessary). For example, STRM_SEEK is a constant in

the STRM group. This allows easy identification of the module to which

a definition or data structure belongs.

As another example, MIDIOUTCAPS is the Device Capabilities structure

for the MIDI output module. Using the naming convention developed here

and symmetry (discussed in depth in the second part of this article),

the MIDI Input module Device Capabilities structure should be called

MIDIINCAPS.

Use additional prefixes as appropriate to identify the use of the

definition. For example, MOERR_NODRIVER is a definition in the MIDI

Output module to describe an error, that of no driver present.

Registering Drivers with Module

-------------------------------

Most of the systems designed by the Multimedia group allow device

drivers to be installed by the original equipment manufacturer (OEM)

or even by the end user (given an appropriate setup program). There

are two main ways for these drivers to communicate with the main

module.

The first is to place an entry in the SYSTEM.INI file. When the parent

module loads, it loads the child driver and initiates communication

with the child.

The other method is for the child driver to call the parent to

register itself as a client. This second method presumes that there is

a suitable method available to load the child. Windows provides such a

mechanism.

Requiring a driver to register itself with the handler module provides

four benefits:

1. Drivers can be installed by adding them to the "modules to load"

   list. This is much easier than creating a line for the SYSTEM.INI

   file.

2. The handler module is more general because it does not assume the

   presence of certain drivers. This enhances system portability and

   reduces interdependencies between drivers and handlers. This

   advantage also applies to drivers loaded by a parent process.

3. A driver can pass information about itself, such as its name and

   entry points, to its parent during registration. This further

   separates the parent module from the driver. As long as the format

   of the interface data is fixed, independent changes may be made to

   both parent and driver.

4. Run-time installation of drivers is possible. The inherent nature

   of registration makes installing new drivers while the system is

   running much easier. This also simplifies implementing

   virtualization.

Symmetry of Function Names

--------------------------

 - Every Open function should have a Close function and every Get

   function a Put function.

 - Related functions in separate areas should work the same way. For

   example, if the MIDI output has an Open, the MIDI input should also

   have an Open. Additionally, the return values and parameters should

   be as similar as possible. This eases the programmer's task of

   learning the new APIs. This applies even if the current

   implementation doesn't use API symmetry. See "Designing for

   Implementation in Steps," below.

Symmetry in Naming Conventions

------------------------------

 - Name defined constants and types for related areas should all be

   named using the same conventions. For example, LPMIDICALLBACK and

   LPWAVECALLBACK.

 - If a naming convention already exists for a function type, adhere

   to it. Example: use SEEK and TELL functions to move within a file

   system.

 - If any part of an existing convention is used, little deviation

   from it is allowed. For example, a combination of SEEK and GET

   functions to move within a file system would not be the product of

   good design because it confuses an existing convention.

 - If a convention does not already exist, create a new naming

   convention to avoid confusing things. Example: KNOCK and ANSWER.

Design for Implementation in Steps

----------------------------------

Most implementations of any size must be done in incremental steps of

functionality. More and more features are added to the modules until

the entire design is completely implemented. For large or complex

modules, this process may occur over several years. However, the

original design must anticipate the complete, final functionality, not

just the short-term goals. For example, even if allowing multiple

users of a module will not be implemented in the first phase, this

capability should be designed into the API. That way, the impact on

users of the module will be minimal once implementation is complete.

Avoid placing arbitrary limits on functionality due to details of the

current implementation. For example, even if only one user can have a

resource allocated today, this may not always be true. Specifically,

the Open function should return a handle to the resource that is then

passed to functions that manipulate the resource. In the future, when

multiple users of the resource is implemented, it will not be

necessary to change other functions or applications.

In a message-based system, functions should return a "message not

recognized" code for unexpected messages that is distinct from the "an

error occurred" code. Then, when a future version of the driver

contains extended functionality, an application can determine if the

installed version of the driver supports the new features. If not, the

application can take appropriate alternative action.

A project designed to be built in phases has well defined progress

milestones. This makes it much easier to track progress while the

module is under construction.

Building a module in phases also makes it easier to verify that the

module is built correctly. Testing receives increments of

functionality instead of the entire product toward the end of the

development cycle.

Error Reporting

---------------

An function call can fail for many reasons. It is best if the call can

return the specific cause of the error in addition to noting that the

call failed. Functions that return a handle, structure, or other data

cause particular problems because there is a limited set of values

that are always invalid.

Three approaches to error reporting are:

1. Ignore it (not recommended).

2. Provide a separate "what was that error?" call. This is more

   complicated than it sounds because, in a multitasking system, there

   can be multiple users of the module at the same "time." This makes

   determining what was the last error for a particular application

   difficult.

3. Return the handle or structure in a parameter and return the error

   code as the function return. This seems to be the best option, and

   is the approach used by OS/2.

Now that the error code is available, what should be done with it? To

allow for internationalization and for additional error codes, the

application should not associate the error code with a message.

Instead, provide a function in each API that returns the text message

for a specified error code. This function might be named

GetTextErrorInformation, for example.

Client-Supplied Buffers

-----------------------

It is desirable for the client application to provide all buffers that

it will access. If a system module allocates and maintains buffers,

many implementation problems can arise when a buffer is made visible

to the client application. Three advantages of client-supplied buffers

are:

1. If the system software runs at a different privilege level or on a

   different CPU, or is otherwise separate from the client

   application, the system software can easily access the buffer.

   However, at the client's lower privilege level, or if the client

   and operating system are on different CPUs, it may be extremely

   difficult (if not impossible) to make a system-supplied buffer

   available to the client.

2. When the application supplies the buffers, the application has

   complete control over how much memory the system module uses.

3. The application is responsible for reporting an out-of-memory

   error. This removes an error condition from the system call.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbmm kbprg

KBSubcategory: MMMisc


Multiple Columns of Text in Windows Help Files

PSS ID Number: Q67895

Authored 28-Dec-1990	Last modified 24-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

Microsoft Windows Help version 3.0 will support multiple columns of

information in Help files. Unfortunately, the Table features of Word for

Windows are not supported in Help version 3.0. In Windows Help version 3.1,

however, Word for Windows tables are supported. Below is an outline of the

supported techniques for creating multiple columns in Help files.

MORE INFORMATION

The best results can be achieved with Help version 3.0 if the text is

organized such that one column has the bulk of the text to be

presented and the other columns have relatively little text. The text

might resemble the following:

   column1column1  column2  column3column3column3column3column3column3col

                            column3column3column3...

As the size of the Help window is decreased, the text in the third

column will wrap to remain displayed for as long as possible. To

achieve this effect, format the text as paragraphs with an "outdent,"

or negative indent, as shown in the following example:

   First line               Left margin and tab stop

   v                        v

   column1column1  column2  column3column3column3column3column3column3col

                            column3column3column3...

A typical format for paragraphs of this type is:

   Left Margin 2.5"

   First Line -2.5"

It is also necessary to define a tab stop at 2.5 inches.

Having two columns of text in the outdent is merely an example. You

can define as many or as few columns in that space as necessary.

If two columns with similar amounts of text in each are required, you

can use the side-by-side paragraph formatting of Word for the

Macintosh or Word for MS-DOS. Only two paragraphs side-by-side are

supported by the Help compiler.

If neither of the tools mentioned above is available, or if more

complicated tables are required, you can format the tables manually.

Define appropriate tab stops and use them to align the columns of

text. Format each physical line in the table as a separate paragraph.

Select the entire table and format the paragraphs as "Keep Together."

In the context of a Help system, this paragraph format disables word

wrap.

The following is an example of a more complex table. In this example,

(P*) is the paragraph mark at the end of a line:

   column1column1   column2column2  column3column3column3column3colu(P*)

   column1column1   column2coul     column3column3column3column3colu(P*)

   column1column1                   column3column3column3column3(P*)

   column1column1(P*)

   newcol1newcol1   newcol2newcol2  newcol3newcol3newcol3newcol3...(P*)

As the size of the Help window is reduced, the text will not wrap.

Instead, you must use the horizontal scroll bar at the bottom of the

window to view the remainder of the table.

Support for Word for Windows tables was added in Windows Help version 3.1.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbtool

KBSubcategory: TlsHlp


Multiple Desktops Under Windows NT

PSS ID Number: Q92505

Authored 08-Nov-1992	Last modified 23-Feb-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.51, 3.5, and 3.1

Windows NT does not support sharing the same desktop between two monitors

on the same machine. An independent software vendor (ISV) that wants this

capability must write a display device driver that behaves similar to a

normal driver with a single monitor, but actually controls two monitors.

Support for multiple desktops is exposed and supported in Windows NT

version 3.51.

Additional reference words: 3.10 3.50

KBCategory: kbother kbui

KBSubcategory: UsrMisc


Multiple References to the Same Resource

PSS ID Number: Q83808

Authored 20-Apr-1992	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

Windows supports multiple references to a given resource. For example,

suppose that an application has two top-level menus that each contain the

same submenu. (An application can use the AppendMenu or SetMenu functions

to add a submenu to another menu at run time.)

Normally, destroying a menu destroys all of its submenus. In the case

above, however, when one menu is destroyed, the other menu has a lock on

the common submenu. Therefore, the common submenu remains in memory and is

not destroyed. The handle to the submenu remains valid until all references

to the submenu are removed. The submenu either remains in memory or is

discarded, while its handle remains valid.

MORE INFORMATION

Windows maintains a lock count for each resource, including menus. When the

lock count falls to zero, Windows can free (destroy) the object. Each time

an application loads a resource, its lock count is incremented. If a

resource is loaded more than once, only one copy is created; subsequent

loads only increment the lock count. Each call to free a resource

decrements its lock count.

When the LoadResource function determines if a resource has already been

loaded, it also determines if the resource has been discarded. If so,

LoadResource loads the resource again. The resource is not necessarily

present in memory at all times. However, if the lock count is not zero and

the resource is discarded, Windows will automatically reload the resource.

All resources are discardable and will be discarded if required to free

memory.

Therefore, in the example above, the application's call to the DestroyMenu

function calls FreeResource, which checks the lock count. This process is

analogous to LoadMenu, which calls LoadResource.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrRsc


Multiprotocol Support for Windows Sockets

PSS ID Number: Q125704

Authored 01-Feb-1995	Last modified 06-Apr-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

SUMMARY

The Windows Sockets (WinSock) API is based on the Berkeley Sockets

progamming model, the standard interface for TCP/IP network programming on

Windows. However, the WinSock implementations for Windows NT and Windows 95

include support for additional network transports. Here are the network

transports supported by Microsoft WinSock implementations, listed by

platform. For convenience, the headers and libraries required for

application development are also listed.

Platform      Transport                Header*                  Lib

--------------------------------------------------------------------------

Windows NT    TCP/IP                   WINSOCK.H               WSOCK32.LIB

              IPX/SPX                  WSIPX.H, WSNWLINK.H     ""

              NetBEUI (via NetBIOS)    WSNETBS.H               ""

              Appletalk                ATALKWSH.H              ""

              ISO/TP4                  WSHISOTP.H              ""

Windows 95    TCP/IP                   WINSOCK.H               ""

              IPX/SPX                  WSIPX.H, WSNWLINK.H     ""

Windows for

Workgroups

version 3.11  TCP/IP                   WINSOCK.H               WINSOCK.LIB

* WINSOCK.H is required for all platforms and transports, in addition to

  other header files.

MORE INFORMATION

The Windows Sockets API provides a uniform interface to multiple network

transports and shields the programmer from most transport level

ideosyncracies. However, WinSock does not eliminate the need to learn the

basics of the transport protocol used. In particular, the programmer should

be familiar with the following aspects of any transport protocol used with

Windows Sockets:

1. Addressing.

   Each transport uses different address format. For example, the IP

   socket address structures looks like this:

   /*

    * Socket address, internet style.

    */

   struct sockaddr_in

   {

      short   sin_family;

      u_short sin_port;

      struct  in_addr sin_addr;

      char    sin_zero[8];

   };

   struct in_addr

   {

      union

      {

         struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;

         struct { u_short s_w1,s_w2; } S_un_w;

         u_long S_addr;

      } S_un;

   }

   In contrast, the IPX address structure looks like this:

   typedef struct sockaddr_ipx

   {

      short sa_family;

      char  sa_netnum[4];

      char  sa_nodenum[6];

      unsigned short sa_socket;

   } SOCKADDR_IPX;

2. Connection-Oriented vs. Connectionless Transport.

   In a connection-oriented transport protocol such as TCP or SPX,

   applications are required to establish a virtual circuit before data

   transfer can take place. The following sequences of WinSock functions

   are required at minimum to establish a virtual circuit:

   Server     Client

   ------------------

   socket     socket

   bind       connect

   listen

   accept

   After the virtual circuit is established, the send() and recv()

   functions are used to transfer data.

   In a connectionless transport, a virtual circuit is not established.

   Both the client and server exchange data by binding a socket and

   calling sendto() or recvfrom().

3. Virtual circuit termination semantics.

4. Message Oriented vs. Stream-Oriented.

   See the Win32 SDK online documentation for information on these topics.

5. Expedited data delivery.

   This is data that has been earmarked by the application as urgent data,

   and will be sent by the transport as quickly as possible. Not all

   transports support this feature. The Windows Sockets API provides the

   ability to request expedited data delivery via the MSG_OOB flag in the

   send() function.

6. Broadcasts.

   Here is an extract from the Win32 SDK online documentation:

   "Most connectionless transport protocols support broadcasts in the

   same fashion, in which any bound socket can send a broadcast if the

   SO_BROADCAST option is set, and broadcasts sent to the appropriate

   local endpoint are received without any additional work on the part

   of the application. NetBIOS transport protocols, however, handle

   broadcasts somewhat differently. In order to receive broadcasts, an

   application must bind to the NetBIOS broadcast address, which is an

   asterisk ("*") followed by 15 blank spaces (ASCII character 0x20).

   This means two things: A socket must be specially bound to receive

   broadcasts, and applications cannot depend on receiving broadcasts

   intended only for a specific application, since all NetBIOS broadcasts

   are delivered to this address. In other protocols such as

   UDP/IP and IPX, broadcasts are delivered to a socket only if the

   broadcast was sent to the same port to which the socket was bound."

For more information on any of the above topics, please see the Win32 SDK

online documentation.

Additional reference words: 4.00

KBCategory: kbnetwork

KBSubcategory: NtwkWinsock


Mutex Wait Is FIFO But Can Be Interrupted

PSS ID Number: Q125657

Authored 01-Feb-1995	Last modified 03-Feb-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

   versions 3.1 and 3.5

SUMMARY

A mutex is a synchronization object that is signalled when it is not owned

by any thread. Only one thread at a time can own a mutex. Other threads

requesting the mutex will have to wait until the mutex is signalled. This

article discusses the order in which threads acquire the mutex.

MORE INFORMATION

Threads that are blocked on a mutex are handled in a first in, first out

(FIFO) order. Therefore, the first to wait on the mutex will be the first

to receive the mutex, regardless of thread priority.

It is important to remember that Windows NT can interrupt the wait and that

this will change the order in which threads are queued. A kernel-mode

asynchronous procedure call (APC) can interrupt a user-mode thread's

execution at any time. Once the normal execution of the thread resumes, the

thread will again wait on the mutex; however, the thread is placed at the

end of the wait queue. For example, each time you enter the debugger (hit a

breakpoint, execute OutputDebugString(), and so on), all application

threads are suspended. Suspending a thread causes the thread to run a piece

of code in kernel mode. When you continue from the debugger, the threads

are resumed, causing them to resume their wait for the mutex, but possibly

in a different order than before. In this case, it does not look like the

mutex is acquired in FIFO order. Some threads may be unable to acquire the

mutex when the application in run under the debugger.

NOTE: This implementation detail is subject to change. Windows 95 and other

platforms that support the Win32 API may adopt different strategies.

Most programs do not usually need to make any assumption about this

behavior. The only class of applications that should be sensitive to mutex

claim and release throughput are realtime-class applications. If throughput

is of importance to a program, critical sections should be used wherever

possible.

Additional reference words: 3.10 3.50 windbg ntsd

KBCategory: kbprg

KBSubcategory: BseSync


Named Pipe Buffer Size

PSS ID Number: Q105531

Authored 20-Oct-1993	Last modified 03-Mar-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1, 3.5, and 3.51

The documentation for CreateNamedPipe() indicates that

   The input and output buffer sizes are advisory. The actual buffer

   size reserved for each end of the named pipe is either the system

   default, the system minimum or maximum, or the specified size

   rounded up to the next allocation boundary.

The buffer size specified should be a reasonable size so that your process

will not run out of nonpaged pool, but it should also be large enough to

accommodate typical requests.

Every time a named pipe is created, the system creates the inbound and/or

outbound buffers using nonpaged pool, which is the physical memory used by

the kernel. The number of pipe instances (as well as objects such as

threads and processes) that you can create is limited by the available

nonpaged pool. Each read or write request requires space in the buffer for

the read or write data, plus additional space for the internal data

structures.

Whenever a pipe write operation occurs, the system first tries to charge

the memory against the pipe write quota. If the remaining pipe write quota

is enough to fulfill the request, the write completes immediately.

If the remaining pipe write quota is too small to fulfill the request, the

system will try to expand the buffers to accommodate the data using

nonpaged pool reserved for the process. The write will block until the data

is read from the pipe so that the additional buffer quota can be released.

Therefore, if your specified buffer size is too small, the system will grow

the buffer as needed, but the downside is that the operation will block. If

the operation is overlapped, a system thread is blocked; otherwise, the

application thread is blocked.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseIpc


Named Pipes Under WOW

PSS ID Number: Q94948

Authored 26-Jan-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

A 16-bit Windows-based application under Windows on Win32 (WOW) may use a

named pipe that was created previously by a Win32-based application;

however, REDIR.EXE must be included in the AUTOEXEC.BAT file for this to

work properly.

Note that for local named pipes, networking doesn't need to be enabled.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: SubSys


Nesting Quotation Marks Inside Windows Help Macros

PSS ID Number: Q77748

Authored 24-Oct-1991	Last modified 24-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

In Windows Help macros, strings may be delimited in two ways. The

string can be opened and closed by double quotation marks or the

string can be opened by a single opening quotation mark and closed by

a single closing quotation mark.

Any quoted strings contained in a string delimited with double

quotation marks must be enclosed in opening and closing single

quotation marks.

The single opening quotation mark is different from the single closing

quotation mark. The single opening quotation mark (`) is paired with

the tilde (~) above the TAB key on extended keyboards; the single

closing quotation mark (') is the same as the apostrophe. For example,

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

is illegal because the string "clock" uses double quotation marks

within the double quotation marks used for the ExecProgram macro. The

following example corrects the error by enclosing "clock" in single

quotation marks:

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

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbtool

KBSubcategory: TlsHlp


NetBIOS Name Table and NCBRESET

PSS ID Number: Q95944

Authored 02-Mar-1993	Last modified 23-Feb-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

SUMMARY

The Windows NT NetBIOS implementation conforms to the IBM NetBIOS 3.0

specifications, with several enhancements discussed in this article.

MORE INFORMATION

Name Table

----------

Under Windows NT, the name table is maintained on a per-process basis,

which means that names added by one process are not visible by a different

process. This also means that for two processes to establish a session,

both processes must register two different NetBIOS names. However, sessions

can be established by two threads in the same process using the same

NetBIOS name.

NCBRESET

--------

The IBM NetBIOS 3.0 specifications defines four basic NetBIOS environments

under the NCBRESET command. Win32 follows the OS/2 Dynamic Link Routine

(DLR) environment. This means that the first NCB issued by an application

must be a NCBRESET, with the exception of NCBENUM. The Windows NT

implementation differs from the IBM NetBIOS 3.0 specifications in the

NCB_CALLNAME field.

In the "IBM Local Area Network Technical Reference," under the section on

NetBIOS 3.0, the NCB_CALLNAME field is defined as the following:

   REQ_SESSIONS at NCB_CALLNAME+0 (1-byte field)

   The number of sessions requested by the application program.

   If zero, the default of 16 is used.

   REQ_COMMANDS at NCB_CALLNAME+1 (1-byte field)

   The number of commands requested by the application program.

   If zero, the default of 16 is used.

   REQ_NAMES at NCB_CALLNAME+2 (1-byte field)

   The number of names requested by the application program. This

   does not include a reservation for NAME_NUMBER_1.

   If zero, the default of 8 is used.

   REQ_NAME_ONE at NCB_CALLNAME+3 (1-byte field)

   A request to reserve NAME_NUMBER_1 for this application program.

   If 0, NAME_NUMBER_1 is not requested.

   If not 0, NAME_NUMBER_1 is desired to be reserved for this

   application.

Under the Windows NT implementation, the REQ_COMMANDS (NCB_CALLNAME+1)

field is ignored. Instead, an application is bound by the amount of memory

the process can allocate.

For more information on the differences between the Windows NT

implementation and the IBM NetBIOS 3.0 specifications, see "The NetBIOS

Function" in the "Win32 API Reference" Help file.

For more information on version 3.0 of NetBIOS, contact IBM and order the

"IBM Local Area Network Technical Reference."

Additional reference words: 3.00 3.10 3.50 NCBRESET

KBCategory: kbprg

KBSubcategory: NtwkNetbios


Network DDE For 16-bit Windows-based Apps Under Windows NT

PSS ID Number: Q127861

Authored 19-Mar-1995	Last modified 26-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), version 3.5

Network Dynamic Data Exchange (NetDDE) has limited support for 16-bit

Windows application running under Windows NT. You can use DDE across the

network, however, the NDde APIs are not supported.

The NDde APIs, such as NDdeShareAdd(), are used to create and manage the

NetDDE shares, not for the actual communication. Therefore, for 16-bit

applications to use NetDDE under Windows NT, you will need to use Generic

Thunks to thunk to the 32-bit NDde APIs to create and trust the share. Once

that is done, you can communicate using DDE or DDEML.

NOTE: You must be an administrator to add a DDE share.

Additional reference words: 3.50

KBCategory: kbprg

KBSubcategory: SubSys UsrNetDde


New Dialog Styles in Windows 95

PSS ID Number: Q125678

Authored 01-Feb-1995	Last modified 06-Apr-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

SUMMARY

Windows 95 provides a few new dialog styles -- all listed in this article.

All Windows version 3.1 dialog styles are still usable in Windows 95.

However, DS_LOCALEDIT cannot be used in Win32-based applications because it

does not apply. Although not documented, DS_ABSALIGN and DS_SETFONT exist

in Windows version 3.1. They are documented in Windows 95.

MORE INFORMATION

Here is a list of the new dialog styles:

DS_3DLOOK          Gives the dialog box a nonbold font and draws

                   three-dimensional borders around control windows

                   in the dialog box.

DS_CENTER          Centers the dialog box in the working area -- the

                   area not obscured by the tray.

DS_CENTERMOUSE     Centers the mouse cursor in the dialog box.

DS_CONTEXTHELP     Includes a question mark in the title bar of the

                   dialog box. When the user clicks the question mark,

                   the cursor changes to a question mark with a

                   pointer. If the user then clicks a control in the

                   dialog box, the control receives a WM_HELP message.

                   The control should pass the message to the dialog

                   procedure, which should call the WinHelp function

                   using the HELP_WM_HELP command. The Help

                   application displays a pop-up window that

                   typically contains help for the control. Note that

                   DS_CONTEXTHELP is just a placeholder. When the dialog

                   box is created, the system checks for DS_CONTEXTHELP

                   and, if it is there, adds WS_EX_CONTEXTHELP to the

                   extended style of the dialog box.

DS_CONTROL         Creates a dialog box that works well as a child

                   window of another dialog box, much like a page in

                   a property sheet. This style allows the user to

                   tab among the control windows of a child dialog

                   box, use its accelerator keys, and so on.

DS_FIXEDSYS        Uses SYSTEM_FIXED_FONT instead of SYSTEM_FONT.

DS_NOFAILCREATE    Creates the dialog even if errors occur -- for

                   example, if a child window cannot be created

                   or if the system cannot create a special data

                   segment for an edit control.

DS_SETFOREGROUND   Brings the dialog box to the foreground.

                   Internally, Windows calls the SetForegroundWindow

                   function for the dialog box.

Additional reference words: 4.00 DLGTEMPLATE kbinf

KBCategory: kbui kbprg

KBSubcategory: UsrDlgs


New Owner in Take-Ownership Operation

PSS ID Number: Q111541

Authored 14-Feb-1994	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

SUMMARY

When ownership of a file is taken, the user performing the operation

becomes the new owner. The exception to this rule is when the user is a

member of the "Administrators" group. In this situation, the ownership of

the file is assigned to the Administrators group.

The reasoning for this behavior is that the administrators on a particular

system work together. When one administrator takes ownership of a file, the

others should also receive access.

MORE INFORMATION

When a take-ownership operation is performed, the system assigns the new

owner SID based on the TOKEN_OWNER field of the user's access token.

When a user logs on to a Windows NT system, the logon process builds an

access token to represent the user. Normally the TOKEN_OWNER field in the

access token is set equal to TOKEN_USER (the user's SID). However, when the

user is a member of the Administrators group, the system sets the

TOKEN_OWNER field to the Administrators SID.

Although Windows NT does not provide a user interface for changing the

TOKEN_OWNER field in the user's access token, it is possible to

programatically change this value via the SetTokenInformation() Win32 API

(application programming interface).

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseSecurity


New User Heap Limits Under Windows 95

PSS ID Number: Q125676

Authored 01-Feb-1995	Last modified 06-Apr-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

SUMMARY

In Windows version 3.1, window and menu data is maintained in two 16-bit

heaps. This limits window and menu data to 64k each. Windows 95 uses

32-bit heaps for window and menu data, thus greatly expanding the

limits placed on the number of items contained in these heaps.

MORE INFORMATION

Windows version 3.1 user and menu heaps are each limited to 64K of data.

As a result, the number of window and menus in a system are each

constrained to around 200. In Windows 95, the number of Windows and Menus

that may exist in the system goes up to 32K each. This is possible because

the Windows 95 user and menu heaps are each two megabytes in size.

The first 64K of the user heap looks exactly as it did in Windows version

3.1, except for the absense of WND structures. The Windows 95 WND

structures populate the heap space above 64K, thus increasing the number of

WND structures the heap can hold. This new arrangement also has the

positive effect of freeing up space in the lower 64K space, making more

space for class structures and other items that reside in the user heap.

For the menu heap, there is nothing special about the low 64K, menus and

their data may appear anywhere in the two-megabyte heap.

Additional reference words: 4.00

KBCategory: kbusage

KBSubcategory: UsrMisc


New Window Styles in Windows 95

PSS ID Number: Q125679

Authored 01-Feb-1995	Last modified 06-Apr-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

SUMMARY

Windows 95 provides a number of new window styles that help make the user

interface more attractive and intuitive. These new styles are listed in

this article. Most of the new styles are extended styles, which are

specified with the CreateWindowsEx() function. All Windows version 3.1

window styles are still usable in Windows 95.

MORE INFORMATION

Here are the new styles:

WS_EX_ABSPOSITION       Specifies that a window has an absolute position.

WS_EX_CLIENTEDGE        Specifies that a window has a 3D look -- that is

                        a border with a sunken edge.

WS_EX_CONTEXTHELP       Includes a question mark in the title bar of the

                        window. When the user clicks the question mark,

                        the cursor changes to a question mark with a

                        pointer. If the user then clicks a child window,

                        the child receives a WM_HELP message.

WS_EX_CONTROLPARENT     Allows the user to navigate among the child windows

                        of the window by using the TAB key.

WS_EX_LEFT              Gives window generic left-aligned properties.

                        This is the default.

WS_EX_LEFTSCROLLBAR     Places vertical scroll bar to the left of the

                        client area.

WS_EX_LTRREADING        Displays the window text using left-to-right

                        reading order properties. This is the default.

WS_EX_MDICHILD          Creates an MDI child window.

WS_EX_OVERLAPPEDWINDOW  Combines the WS_EX_CLIENTEDGE and WS_EX_WINDOWEDGE

                        styles.

WS_EX_PALETTEWINDOW     Combines the WS_EX_WINDOWEDGE, WS_EX_SMCAPTION,

                        and WS_EX_TOPMOST styles.

WS_EX_RIGHT             Gives window generic right-aligned properties.

                        This depends on the window class.

WS_EX_RIGHTSCROLLBAR    Places vertical scroll bar (if present) to the

                        right of the client area. This is the default.

WS_EX_RTLREADING        Displays the window text using right-to-left

                        reading order properties.

WS_EX_SMCAPTION         Creates a window that has a small title bar.

WS_EX_STATICEDGE        Creates a window with a three-dimensional border

                        style intended to be used for items that do not

                        accept user input.

WS_EX_TOOLWINDOW        Creates a tool window, which is a window intended

                        to be used as a floating toolbar. A tool window has

                        a title bar that is shorter than a normal title

                        bar, and the window title is drawn using a smaller

                        font. A tool window does not appear in the task bar

                        or in the window that appears when the user presses

                        ALT+TAB.

WS_EX_WINDOWEDGE        Specifies that a window has a border with a raised

                        edge.

Additional reference words: 4.00 CreateWindowEx kbinf

KBCategory: kbui kbprg

KBSubcategory: UsrWndw


New Windows 95 Styles Make Attaching Bitmap to Button Easier

PSS ID Number: Q125673

Authored 01-Feb-1995	Last modified 06-Apr-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

SUMMARY

In Windows 95, there are two new button styles (BS_BITMAP and BS_ICON).

Using these styles makes attaching a bitmap or an icon to a button in

Windows 95 easier than it was in Windows version 3.1.

MORE INFORMATION

In Windows version 3.1 you create the button by using the CreateWindow()

function with the BS_OWNERDRAW style to attach a bitmap or an icon to a

button. Each time the parent window receives the WM_DRAWITEM message the

bitmap or the icon must be loaded and drawn on the button.

In Windows 95 you can create a button with style BS_BITMAP to display a

bitmap instead of text on the button. After you create the button by using

CreateWindow() function, assign the bitmap to the button by sending a

WM_SETIMAGE message to the button with the wparam as IMAGE_BITMAP and

lparam as a handle to the bitmap. Windows displays the specified bitmap on

the button. The attached bitmap should not be deleted until the button uses

it.

SAMPLE CODE

hwndButton = CreateWindow(

              "BUTTON",   // predefined class

              "OK",       // button text

              WS_VISIBLE| WS_CHILD | BS_DEFPUSHBUTTON |BS_BITMAP, //styles

              // Size and position values are given explicitly, because

              // the CW_USEDEFAULT constant gives zero values for buttons.

              5, // starting x position

              5, // starting y position

              30,// button width

              18, // button  height

              hWnd,// parent window

              NULL,// No menu

              (HINSTANCE) GetWindowLong(hWnd,

                          GWL_HINSTANCE), NULL); // pointer not needed

// load the bitmap, NOTE: delete it only when it's no longer being used.

hBitmap   = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_BITMAP1));

// associate the bitmap with the button.

SendMessage(hwndButton,BM_SETIMAGE,(WPARAM)IMAGE_BITMAP,

           (LPARAM)(HANDLE)hBitmap);

In Windows 95, you can also create a button with style BS_ICON to display a

icon instead of text on the button. After creating the button by using

CreateWindow() function, assign the icon to the button by sending a

WM_SETIMAGE message to the button with the wparam as IMAGE_ICON and the

lparam as the handle to the icon. Windows displays the specified icon on

the button.

NOTE: The system handles cleanup of icons or cursors loaded from resources.

Therefore, the icon should not be deleted unless the icon was created at

run time by using CreateIcon() function.

SAMPLE CODE

hwndButton = CreateWindow(

                 "BUTTON",   // predefined class

                 "OK",       // button text

                 WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON|BS_ICON,//styles

              // Size and position values are given explicitly, because

              // the CW_USEDEFAULT constant gives zero values for buttons.

                  5, // starting x position

                  5, // starting y position

                 30, // button width

                 18, // button height

                 hWnd,   // parent window

                 NULL,   // No menu

                 (HINSTANCE) GetWindowLong(hWnd,GWL_HINSTANCE),

                 NULL);      // pointer not needed

// load the icon, NOTE: you should delete it after assigning it.

hIcon = LoadIcon(hInst,MAKEINTRESOURCE(IDI_ICON1));

// associate the icon with the button.

SendMessage(hwndButton,BM_SETIMAGE,(WPARAM)IMAGE_ICON,

           (LPARAM)(HANDLE)hIcon);

If a bitmap or icon is not specified via the BM_SETIMAGE message and the

BS_BITMAP or BS_ICON style is specified, a blank button with no text is

displayed.

Additional reference words: 4.00

KBCategory: kbprg

KBSubcategory: UsrWnd


No Subsystem Developer Kit or Support for Such a Kit

PSS ID Number: Q89987

Authored 06-Oct-1992	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

There is not a kit available for developers to write subsystems, nor are

there plans to provide such a kit. Furthermore, there is no documentation

or support available to develop a subsystem for Windows NT.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: SubSys


Non-Addressable Range in Address Space

PSS ID Number: Q92764

Authored 15-Nov-1992	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

SUMMARY

In Windows NT, each process has its own private address space. The process

can use up to 2 gigabytes of virtual memory. This 2Gb is not necessarily

contiguous. The system uses the other 2Gb.

The user-mode addresses extend from 0x00010000 to 0x7FFF0000. The

following ranges are reserved as non-address space to ensure that the

process does not walk on system-owned memory

   0x00000000 to 0x0000FFFF    (first 64K of virtual space)

   0x7FFF0000 to 0x7FFFFFFF    (last 64K of user virtual space)

These are effectively PAGE_NOACCESS ranges.

Additionally, Win32 DLLs will reserve other specific address ranges. For

more information, see the file COFFBASE.TXT that comes with the DDK.

MORE INFORMATION

This range is not guaranteed to serve this purpose in the future. There

could be good reasons in a future implementation to use these addresses.

Code that is going to depend on this non-address range should verify its

validity at run time with something like

   BOOL IsFirst64kInvalid(void)

   {

      BOOL bFirst64kInvalid = FALSE;

      try {

         *(char *)0x0000FFFF;

      }

      except (EXCEPTION_EXECUTE_HANDLER) {

         if (EXCEPTION_ACCESS_VIOLATION == GetExceptionCode())

            bFirst64kInvalid = TRUE;

      }

      return bFirst64kInvalid;

   }

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseMm


Noncontinuable Exceptions

PSS ID Number: Q98840

Authored 13-May-1993	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

An exception is noncontinuable if the event isn't continuable in the

hardware, or if continuation makes no sense. For example, if the caller's

stack is corrupted while trying to post an exception, continuing from the

bad stack exception would not be useful.

The noncontinuable exception does not terminate the application, and

therefore an application that can succeed in catching the exception and

running after a noncontinuable exception is free to do so. However, a

noncontinuable exception typically arises as a result of a corrupted stack

or other serious problem, making it very difficult to recover from the

exception.

Additional reference words: 3.10 3.50 4.00 95  non-continuable

KBCategory: kbprg

KBSubcategory: BseExcept


Nonzero Return from SendMsg() with HWND_BROADCAST

PSS ID Number: Q102588

Authored 04-Aug-1993	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

The SendMessage() function calls the window procedure for the

specified window and does not return until that window has processed

the message and returned a value. Applications can send messages to

all top-level windows in the system by specifying HWND_BROADCAST as

the first parameter to the SendMessage() function. In doing so,

however, applications lose access to the return values resulting from

the SendMessage() call to each of the top-level windows.

MORE INFORMATION

When a call to SendMessage() is made, the value returned by the window

procedure that processed the message is the same value returned from

the SendMessage() call.

Among other things, SendMessage() determines whether the first

parameter is HWND_BROADCAST (defined as -1 in WINDOWS.H). If

HWND_BROADCAST is the first parameter, SendMessage enumerates all

top-level windows in the system and sends the message to all these

windows. Because this one call to SendMessage() internally translates

to a number of SendMessage() calls to the top-level windows, and

because SendMessage() can return only one value, Windows ignores the

individual return values from each of the top-level window procedures,

and just returns a nonzero value to the application that broadcast the

message. Thus, applications that want to broadcast a message to all

top-level windows, and at the same time expect a return value from

each SendMessage() call, should not specify HWND_BROADCAST as the

first parameter.

There are a couple of ways to access the correct return value from

messages sent to more than one window at a time:

 - If the broadcasted message is a user-defined message, and only a few

   other applications respond to this message, then those applications

   that trap the broadcasted message must return the result by sending

   back another message to the application that broadcast the message.

   The return value can be encoded into the message's lParam.

 - If the application does not have control over which application(s)

   will respond to the message, and it still expects a return value,

   then the application must enumerate all the windows in the system

   using EnumWindows() function, and send the message separately to

   each window it obtained in the enumeration callback function.

Additional reference words: 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrMsg


Objects Inherited Through a CreateProcess Call

PSS ID Number: Q83298

Authored 08-Apr-1992	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

The objects inherited by a process started by a call to CreateProcess() are

those objects that you can get a handle to and on which you can use the

CloseHandle() function. These objects include the following:

   Processes

   Events

   Semaphores

   Mutexes

   Files (including file mappings)

   Standard input, output, or error devices

However, the new process will only inherit objects that were marked

inheritable by the old process.

These are duplicate handles. Each process maintains memory for its own

handle table. If one of the processes modifies its handle (for example,

closes it or changes the mode for the console handle), other processes will

not be affected.

Processes will also inherit environment variables, the current directory,

and priority class.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: BseProcThrd


Obsolete Macro functions in Japanese Windows Version 3.1

PSS ID Number: Q130059

Authored 10-May-1995	Last modified 16-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

 - Microsoft Win32 Software Development Kit (SDK) version 3.5

 - Microsoft Win32s version 1.2

SUMMARY

Some of the Japanese Windows version 3.1 functions are no longer supported

in the Japanese version of Windows NT. These Macro functions are obsolete

in the current C++ compiler.

MORE INFORMATION

The macro functions of Japanese Windows version 3.10 are no longer

supported and are obsolete in current C++ compiler. They were remapped to

other generic MBCS functions. Use the following as workaround functions.

Include them in the current header file. T _ismbb* entries correspond to

the replaced Windows version 3.1 macro.

#include <mbctype.h>

#define iskana       _ismbbkana

#define iskpun       _ismbbkpunct

#define iskmoji     _ismbbkalpha

#define isalkana    _ismbbalpha

#define ispnkana    _ismbbpunct

#define isalnmkana  _ismbbalnum

#define isprkana    _ismbbprint

#define isgrkana    _ismbbgraph

#define iskanji     _ismbblead

#define iskanji2    _ismbbtrail

Additional reference words: 3.10 1.20 3.50 kbinf

KBCategory: kbother

KBSubcategory: wintldev


Obtaining a Console Window Handle (HWND)

PSS ID Number: Q124103

Authored 19-Dec-1994	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

It may be useful to manipulate a window associated with a console

application. The Win32 API provides no direct method for obtaining the

window handle associated with a console application. However, you can

obtain the window handle by calling FindWindow(). This function retrieves a

window handle based on a class name or window name.

Call GetConsoleTitle() to determine the current console title. Then supply

the current console title to FindWindow().

MORE INFORMATION

Because multiple windows may have the same title, you should change the

current console window title to a unique title. This will help prevent the

wrong window handle from being returned. Use SetConsoleTitle() to change

the current console window title. Here is the process:

1. Call GetConsoleTitle() to save the current console window title.

2. Call SetConsoleTitle() to change the console title to a unique title.

3. Call Sleep(40) to ensure the window title was updated.

4. Call FindWindow(NULL, uniquetitle), to obtain the HWND

   this call returns the HWND -- or NULL if the operation failed.

5. Call SetConsoleTitle() with the value retrieved from step 1, to

   restore the original window title.

You should test the resulting HWND. For example, you can test to see if the

returned HWND corresponds with the current process by calling

GetWindowText() on the HWND and comparing the result with

GetConsoleTitle().

The resulting HWND is not guaranteed to be suitable for all window handle

operations.

Sample Code

-----------

The following function retrieves the current console application window

handle (HWND). If the function succeeds, the return value is the handle of

the console window. If the function fails, the return value is NULL. Some

error checking is omitted, for brevity.

HWND GetConsoleHwnd(void)

{

    #define MY_BUFSIZE 1024 // buffer size for console window titles

    HWND hwndFound;         // this is what is returned to the caller

    char pszNewWindowTitle[MY_BUFSIZE]; // contains fabricated WindowTitle

    char pszOldWindowTitle[MY_BUFSIZE]; // contains original WindowTitle

    // fetch current window title

    GetConsoleTitle(pszOldWindowTitle, MY_BUFSIZE);

    // format a "unique" NewWindowTitle

    wsprintf(pszNewWindowTitle,"%d/%d",

                GetTickCount(),

                GetCurrentProcessId());

    // change current window title

    SetConsoleTitle(pszNewWindowTitle);

    // ensure window title has been updated

    Sleep(40);

    // look for NewWindowTitle

    hwndFound=FindWindow(NULL, pszNewWindowTitle);

    // restore original window title

    SetConsoleTitle(pszOldWindowTitle);

    return(hwndFound);

}

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg kbcode

KBSubcategory: BseCon UsrWndw


Obtaining Public Domain Information About Windows Sockets

PSS ID Number: Q115045

Authored 18-May-1994	Last modified 26-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

 - Microsoft Windows SDK for Windows, version 3.1

SUMMARY

Anyone with FTP access to the Internet can obtain a vast amount of

information pertinent to the Windows Sockets API. The information is

available through anonymous FTP to sunsite.unc.edu in the /pub/micro/pc-

stuff/ms-windows/winsock directory. In the winsock directory, there is a

wealth of technical information, including specifications, applications,

DLLs for testing, and developers' guides not only from Microsoft, but also

from other vendors of Windows Sockets.

The following list gives a brief overview of the information contained in

the directory. This information can also be obtained from the READ.ME file

in the location mentioned above.

FAQ

---

A list of frequently asked questions, with companion answers. Please send

additional questions or answers to towfiq@Microdyne.COM.

apps/

----

Applications that have been written to run on top of the Windows Sockets

DLL. See the file READ.ME in the winsock directory for a description of

each application.

./incoming/

-----------

A directory where submissions to the archive (such as sample programs)

should be placed.

packages/

---------

The winsock directory contains different vendors' WINSOCK.DLLs for testing

purposes as well as Windows Sockets development packages. See the file

READ.ME in this directory for a description of each package.

press-releases/

---------------

Some of the press releases about the Windows Sockets.

winsock-archive/

----------------

An archive of the winsock@Sunsite.UNC.Edu mailing list. (Send subscription

requests to listserv@SunSite.UNC.Edu.)

wsguide.doc

-----------

The "Windows Sockets Guide," by Martin Hall, JSB (martinh@jsbus.com) in

Microsoft Word for Windows format.

wsguide.ps

----------

The "Windows Sockets Guide," by Martin Hall, JSB (martinh@jsbus.com) in

PostScript format. In the subdirectories winsock-1.0 and winsock-1.1, you

can find the specification in many different formats.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbref

KBSubCategory: NtwkMisc


Open File Dialog Box -- Pros and Cons

PSS ID Number: Q74612

Authored 24-Jul-1991	Last modified 12-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

Applications can call the common dialog library (COMMDLG.DLL) function

GetOpenFileName() to retrieve the name of a file that the user wants to

manipulate. Using this DLL provides a common interface for opening files

across applications and also eliminates dialog-box message processing

within the application's code. However, the application must initialize a

structure specific to the dialog box. This article discusses the benefits

and costs of using the Open File common dialog, via GetOpenFileName().

MORE INFORMATION

When an application uses the Open File dialog box provided by the common

dialog DLL, the primary benefit to that application's users will be a

familiar interface. Once they learn how to open a file in one application

that uses the DLL, they will know how to open a file in all applications

that use it.

Features of the Open File dialog include:

 - A list box of files, filtered by extension, in the current directory

 - A list box of directories from root of current drive to current

   directory, plus subdirectories

 - A combo box of file types to list in filename list box

 - A combo box of drives available, distinguished by drive type

 - An optional "Read Only" check box

 - An optional "Help" button

 - An optional application hook function to modify standard behavior

 - An optional dialog template to add private application features

For the application's programming staff, the benefits of using the Open

File common dialog will include:

 - No dialog-box message processing necessary to implement the Open

   File dialog box

 - Drive and directory listings are constructed by the DLL, not by

   the application

 - A full pathname for the file to be opened is passed back to the

   application, and this name can be passed directly to the OpenFile

   function

 - Offsets into the full pathname are also returned, giving the

   application access to the filename (sans pathname) and the file

   extension without the need for parsing

 - The application can pass in its own dialog box template, in which

   case the DLL will use that template instead of the standard template

 - The application can provide a dialog hook function to extend the

   interface of the DLL or to change how events are handled

 - The application can choose to have a single filename or multiple

   filenames returned from the dialog box

The cost for the programming staff could be in adapting previously written

application code to handle the common dialog interface. While making this

change is straightforward, it does require coding time. If the application

only needs a filename with no path, the Open File common dialog is probably

not appropriate.

For more information on using the Open File common dialog, query on

GetOpenFileName().

Additional reference words: 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrCmnDlg


OpenComm() and Related Flags Obsolete Under Win32

PSS ID Number: Q94990

Authored 28-Jan-1993	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

OpenComm(), a Windows 3.1 application programming interface (API), is

obsolete under Windows NT and is not in the Win32 API. Note that the flags,

IE_BADID, IE_BAUDRATE, IE_BYTESIZE, IE_DEFAULT, IE_HARDWARE, IE_MEMORY,

IE_NOPEN, and IE_OPEN are obsolete, but are still in the header files.

OpenComm() is provided for 16-bit Windows-based applications running under

Windows on Win32 (WOW).

MORE INFORMATION

Under Win32, CreateFile() is used to create a handle to a communications

resource (for example, COM1). The fdwShareMode parameter must be 0

(exclusive access), the fdwCreate parameter must be OPEN_EXISTING, and the

hTemplate parameter must be NULL. Read, write, or read/write access can be

specified and the handle can be opened for overlapped I/O.

ReadFile() and WriteFile() are used for communciations I/O. The TTY sample

program shipped with the Win32 Software Development Kit (SDK) demonstrates

how to do serial I/O in a Win32-based application.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: BseCommapi


Overlapping Controls Are Not Supported by Windows

PSS ID Number: Q79981

Authored 14-Jan-1992	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

Child window controls should not be overlapped in applications for the

Windows operating system. When one control overlaps another control,

or another child window, the borders shared by the controls may not be

drawn properly. Overlapping controls may confuse the user of the

application because clicking the mouse in the common area may not

activate the control that the user intended to activate. This behavior

is a consequence of the way that Windows is designed.

MORE INFORMATION

The following example illustrates the painting problems caused by the

ambiguity of overlapping borders. Consider three edit controls, called

A, B and C, which overlap each other, and an enclosing child window D:

     ____________________________________________

     | | A          | B          | C          | |

     | ---------------------------------------- |

     |                 D                        |

     --------------------------------------------

Assume that control B has the focus. If this set of controls is

covered by another window, which is subsequently moved away, Windows

will send a series of client and nonclient messages to each of the

controls and to the enclosing child window. The result of these

messages may appear as the illustration below, where the portion of

window B's border that overlapped with part of window D's border is

missing:

     _______________             ________________

     | | A          | B          | C          | |

     | ---------------------------------------- |

     |                 D                        |

     --------------------------------------------

Repainting problems related to overlapping controls may vary depending

on the version of Windows used.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95  CS_PARENTDC

WS_CLIPCHILDREN

WS_CLIPSIBLINGS WM_NCPAINT WM_PAINT

KBCategory: kbprg

KBSubcategory: UsrDlgs


Overview of the Windows 95 Virtual Address Space Layout

PSS ID Number: Q125691

Authored 01-Feb-1995	Last modified 06-Apr-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

SUMMARY

The virtual memory management mechanism in Microsoft Windows 95 makes it

possible to execute Win32-based, 16-bit-based, and MS-DOS-based

applications simultaneously. To accomplish this, the virtual memory manager

uses a virtual address space layout that is considerably different from

that used by Microsoft Windows version 3.x and that is slightly different

from that used by Microsoft Windows NT. Although the differences from

Windows NT are slight, they are important.

The memory manager in Windows 95 uses paging and 32-bit linear addressing

to provide a full 32-bit virtual address space that has a maximum size of

four gigabytes (GB). This four-GB address space is partitioned by the

memory manager into four major sections, known as arenas, that are used for

different types of applications and parts of the system. The first arena,

from zero to four megabytes (MB) exists for compatibility with applications

based on Windows version 3.1x and MS-DOS. The next arena, from four MB to

two GB, is the private address space for each Win32 process. The third

arena, from two to three GB, is a shared address space that contains memory

mapped files and the 16-bit components. Finally, the fourth arena, from

three to four GB, is reserved for the system's use.

MORE INFORMATION

The following diagram shows the overall virtual address space layout used

in Windows 95. The Compatibility Arena holds the current virtual machine

and other software. Each Win32 process gets its own private address space

in which to execute. The Private Arena contains the currently executing

Win32 process's private address space. All 16-bit-based applications and

DLLs, including the 16-bit Windows system components, reside in the Shared

Arena. Finally, the Reserved System Arena is used to store all ring-0 code

such as the virtual machine manager and virtual device drivers. It is not

accessible by either 16-bit-based or Win32-based applications.

        +---------------------------------+ 4 Gigabytes

        |                                 |

        |      Reserved System Arena      |

        |    (Holds ring-0 components)    |

        |                                 |

        |---------------------------------| 3 Gigabytes

        |                                 |

        |          Shared Arena           |

        |                                 |

        |                                 |

        |---------------------------------| 2 Gigabytes

        |                                 |

        |         Private Arena           |

        |    (Holds address space of      |

        |      currently executing        |

        |         Win32 process)          |

        |                                 |

        +---------------------------------+ 4 Megabytes

        |           16-bit/MS-DOS         |

        |        Compatibility Arena      |

        +---------------------------------+ 0 Gigabytes

Each arena has a specific purpose and is described in detail below.

16-bit/MS-DOS Compatibility Arena

---------------------------------

The first four megabytes of the system's address space is reserved by the

system and is accessible to 16-bit and MS-DOS software for compatibility.

The current virtual machine occupies the lowest megabyte of this area. The

remaining three megabytes are mostly empty space but may contain MS-DOS

device drivers and Terminate & Stay Resident (TSR) programs.

The 16-bt/MS-DOS Compatibility Arena is not accessible to Win32 processes

for reading or writing. This means Win32 processes may may not allocate

memory, load DLLs, or be loaded below the four megabyte (MB) address.

Private Arena

-------------

The private arena holds the private address space of the currently

executing Win32 process. Because every Win32 process gets its own address

space, the contents of this arena will depend upon which process is

currently executing. The memory manager maps the pages of a process's

private address space so that other processes cannot access it and corrupt

the process. The process's code, data, and dynamically-allocated memory all

exist in the private address space.

With the exception of the system's shared DLLs (USER32.DLL, GDI32.DLL, and

KERNEL32.DLL), all DLLs loaded by the process are mapped into the process's

private address space. Windows extension DLLs such as SHELL32.DLL,

COMCTL32.DLL, and COMDLG32.DLL are not system shared DLLs and are mapped

into the process's private address space.

Because console applications are Win32-based applications without graphical

user interfaces, they too get their own private address spaces, as do Win32

graphical user interface (GUI) applications.

The minimum load address for a Win32 process in Windows 95 is four MB

because the first four megabytes are reserved for the Compatibility Arena.

Shared Arena

------------

The shared arena is unique to Windows 95. This arena contains components

that must be mapped into every process's address space. All of the pages in

this arena are mapped identically in every process.

The 16-bit global heap, which contains all 16-bit-based applications, DLLs,

and 16-bit system DLLs, resides in the shared arena. The Win32 shared

system DLLs (USER32.DLL, GDI32.DLL, and KERNEL32.DLL) are also located in

the shared arena.

Unlike the Reserved System Arena, the shared arena is readable and writable

by Win32 and 16-bit processes alike. This doesn't mean they are free to get

memory directly from this address space. All 16-bit-based applications and

DLLs actually are located in the 16-bit global heap, so they allocate

memory from the 16-bit global heap; when this heap needs to be grown,

KRNL386.EXE gets the memory from the shared arena.

Win32 processes may not allocate memory directly from the shared arena, but

they always use it for mapping views of file mappings. Unlike Windows NT,

where views of file mappings always are placed in the private address

space, Windows 95 holds views of file mappings in the shared arena.

The DOS Protected Mode Interface (DPMI) server's memory pool is located in

the Shared Arena. Thus, calls to the DPMI server to allocate memory will

result in memory that is globally accessible.

Sometimes, a virtual device driver (VxD) may need to map a buffer passed to

it by a Win32 process into globally accessible memory so that the buffer

can be accessed even if the process isn't in context. By calling

_LinPageLock virtual machine manager service with the PAGEMAPGLOBAL flag, a

VxD can obtain a linear address in the shared arena that corresponds to the

buffer passed to it by the Win32 process.

Reserved System Arena

---------------------

The reserved system contains the code and data of all ring-0 components

such as the virtual machine manager, DOS extender, DPMI server, and virtual

device drivers. This arena is used exclusively by ring-0 components and not

addressable by ring 3 code, such as MS-DOS-based, 16-bit-based, and

Win32-based applications and DLLs.

Additional reference words: 4.00 layout memory virtual

KBCategory: kbprg

KBSubcategory: BseMm


Owner-Draw Buttons with Bitmaps on Non-Standard Displays

PSS ID Number: Q67715

Authored 12-Dec-1990	Last modified 23-Jun-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.1, 3.5, 3.51, and 4.0

SUMMARY

If an application contains an owner-draw button that paints itself with a

bitmap, the application's resources must contain a set of bitmaps

appropriate to each display type on which the application might run.

If the application's resources do not contain bitmaps suitable for the

display on which the application is running, the application can use the

default 3-D button appearance by changing the button style to BS_PUSHBUTTON

from BS_OWNERDRAW.

Under Windows 95, there is a new style BS_BITMAP which applications might

find easier to use.

Changing the style of a button is possible in Windows version 3.0; however,

this technique is not guaranteed to be supported in future releases of

Windows.

MORE INFORMATION

An owner-draw button can use bitmaps to paint itself. When an application

contains this type of owner-draw button, it must also contain a set of

bitmaps appropriate for each display type on which the application might

run. Each set of bitmaps has a normal "up" bitmap and a depressed "down"

bitmap to implement the 3-D effects. The most common standard Windows

display types are: CGA, EGA, VGA, 8514/a, and Hercules Monochrome. The

dimensions and aspect ratio of the display affect the appearance of the

bitmap. For example, a monochrome bitmap designed for VGA will display

correctly on an 8514/a and any other display with a 1:1 aspect ratio.

If an application determines that it does not contain an appropriate set of

bitmaps for the current display type, then it should change the button

style from BS_OWNERDRAW to BS_PUSHBUTTON. After the style has been changed

and the button has been redrawn, the button will appear as a normal 3-D

push button.

The following code fragment demonstrates how to change the style of a

push button from owner-draw to normal:

    ...

    /*

     * hWndButton is assumed to be the handle to the button.

     * Note that lParam has a nonzero value, which forces the button

     * to be redrawn. This assures that the normal button appearance

     * will show after this message is sent.

     */

    SendMessage(hWndButton, BM_SETSTYLE, BS_PUSHBUTTON, 1L);

    ...

Additional reference words: 3.00 3.10 4.00 95

KBCategory: kbprg

KBSubcategory: UsrCtl


Owner-Draw: Overview and Sources of Information

PSS ID Number: Q64327

Authored 31-Jul-1990	Last modified 16-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.1, 3.5, 3.51, and 4.0

SUMMARY

Owner-draw controls are a new feature of Windows version 3.0. Because your

application does all the drawing of the contents of the controls, you can

customize them any way you like. Owner-draw controls are similar to

predefined controls in that Windows will handle the control's functionality

and mouse and keyboard input processing. However, you are responsible for

drawing the owner-draw control in its normal, selected, and focus states.

You can create owner-draw controls from the menu, button, and list-box

classes. You can create owner-draw combo boxes, but they must have the

CBS_DROPDOWNLIST style (equates to a static text item and a list box). The

elements of an owner-draw control can be composed of strings, bitmaps,

lines, rectangles, and other drawing functions in any combination, in your

choice of colors.

MORE INFORMATION

The Windows SDK sample application MENU demonstrates owner-draw menu items.

The SDK sample application OWNCOMBO is a fairly large example of owner-draw

and predefined list boxes and combo boxes.

The Microsoft Software Library contains simplified examples of an owner-

draw push button, owner-draw list boxes, and an owner-draw drop-down list

style combo box. Each of these examples includes descriptive text in a

related Knowledge Base article. For additional information, please see the

following article(s) in the Microsoft Knowledge Base:

   ARTICLE-ID: Q64326

   TITLE     : Owner-Draw: Handling WM_DRAWITEM for Drawing Controls

   -or-

   ARTICLE-ID: Q64328

   TITLE     : Owner-Draw: 3-D Push Button made from Bitmaps with Text

   -or-

   ARTICLE-ID: Q65792

   TITLE     : Owner-Draw Example: Right - and Decimal Alignment

To respond to a WM_MEASUREITEM message, you MUST specify the height of the

appropriate item in your control. Optionally, you can specify the item's

width as well.

If you want to do something special when a string is deleted from a list

box, you should process WM_DELETEITEM messages. Windows's default action is

to erase the deleted string and to redraw the list box.

If you want to have control over the sorting for the order of items in a

list box or combo box that does not have the *_HASSTRINGS style, you should

specify the appropriate *_SORT style and process WM_COMPAREITEM messages.

If the *_SORT and *_HASSTRINGS styles are present, Windows will

automatically do the sorting without sending WM_COMPAREITEM messages. If

*_SORT is not specified, WM_COMPAREITEM messages will not be generated and

items will be displayed in the list box in the order in which they were

inserted.

The heart of owner-draw controls is the response to WM_DRAWITEM messages.

During this processing is when you draw an entire button or each individual

item in a menu, list box, or combo box. Because Windows does not interfere

in the drawing of owner-draw controls, your application must draw the

specified control item. The display of the control must indicate the state

of the control. Common states are as follows:

1. Focus state (has the focus or not)

2. Selection state (selection or not)

3. Emphasis state (active, grayed, or disabled) (less common to

   process)

See the article titled "Owner-Draw: Handling WM_DRAWITEM for Drawing

Controls" for information about drawing controls in their various

states. Familiarity with the WM_DRAWITEM message and the various

control states is extremely helpful before trying to follow the code

examples.

Under Windows 95 and Windows 3.51, the BS_BITMAP style allows buttons to

display bitmaps without using owner-draw.

Additional reference words: 3.00 3.10 3.50 4.00 owndraw od owner draw

KBCategory: kbprg

KBSubcategory: UsrCtl


Owners Have Special Access to Their Objects

PSS ID Number: Q130543

Authored 22-May-1995	Last modified 23-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5

   and 3.51

The Windows NT operating system allows the owner of an object to determine

what types of access are granted or denied for a given user. This is

referred to as Discretionary Access Control (DAC). In addition to granting

the generic read and write types of access, the owner of an object can also

grant other users the right to modify the access allowed to the object.

The access right to view the access allowed on an object is called

READ_CONTROL. This is often granted as part of a generic right. The access

right that allows someone to change the access for an object is called

WRITE_DAC.

The owner of an object can always request WRITE_DAC and READ_CONTROL access

to the object. This prevents a situation where the owner of an object can

not manipulate the object. This also allows owners of objects to restrict

their own access to the object (to guard against accidents) without having

to explicitly grant READ_CONTROL and WRITE_DAC access to their accounts.

Additional reference words: 3.10 3.50 AccessCheck

KBCategory: kbprg

KBSubcategory: BseSecurity


PAGE_READONLY May Be Used as Discardable Memory

PSS ID Number: Q94947

Authored 26-Jan-1993	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

Virtual memory pages marked as PAGE_READONLY under Win32 may be used the

way discardable segments of memory are used in Windows 3.1. These virtual

memory pages are by default not "dirty," so the system may use them

(zeroing them first if necessary) without having to first write their

contents to disk.

From a system resource perspective, PAGE_READONLY is treated similar to

discardable memory under Windows 3.1 when the system needs to free up

resources. From a programming standpoint, the system automatically re-reads

the memory when the data is next accessed (for example, we attempt to

access our page when it has been "discarded," a page fault is generated,

and the system reads it back in). Memory-mapped files are convenient for

setting up this type of behavior.

If a PAGE_READONLY memory page becomes dirty [by changing the protection

via VirtualProtect() to PAGE_READWRITE, changing the data, and restoring

PAGE_READONLY], the page will be written to disk before the system uses it.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: BseMm


Panning and Scrolling in Windows

PSS ID Number: Q11619

Authored 02-Nov-1987	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

When using bitmaps, the mapping mode is ignored and physical units (in

other words, MM_TEXT pixels) are used. It is not necessary to use the

extent/origin routines to keep track of the logical origin.

If scrolling is desired and if there are no child windows in the

client area, it is best to BitBlt the client area to scroll it, and

PatBlt the uncovered area with the default brush.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrPnt


Passing a Pointer to a Member Function to the Win32 API

PSS ID Number: Q102352

Authored 03-Aug-1993	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

Many of the Win32 application programming interfaces (APIs) call for a

callback routine. One example is the lpStartAddr argument of

CreateThread():

   HANDLE CreateThread(lpsa, cbStack, lpStartAddr, lpvThreadParm,

      fdwCreate, lpIDThread)

   LPSECURITY_ATTRIBUTES lpsa;    /* Address of thread security attrs */

   DWORD cbStack;                    /* Initial thread stack size*/

   LPTHREAD_START_ROUTINE lpStartAddr; /* Address of thread function */

   LPVOID lpvThreadParm;       /* Argument for new thread*/

   DWORD fdwCreate;               /* Creation flags*/

   LPDWORD lpIDThread;               /* Address of returned thread ID */

When attempting to use a member function as the thread function, the

following error is generated:

   error C2643: illegal cast from pointer to member

The problem is that the function expects a C-style callback, not a pointer

to a member function. A major difference is that member functions are

called with a hidden argument called the "this" pointer. In addition, the

format of the pointer isn't simply the address of the first machine

instruction, as a C pointer is. This is particularly true for virtual

functions.

If you want to use a member function as a callback, you can use a static

member function. Static member functions do not receive the "this" pointer

and their addresses correspond to an instruction to execute.

Static member functions can only access static data, and therefore to

access nonstatic class members, the function needs an object or a pointer

to an object. One solution is to pass in the "this" pointer as an argument

to the member function.

MORE INFORMATION

This situation occurs with callback functions of other types as well, such

as:

   DLGPROC                  GRAYSTRINGPROC

   EDITWORDBREAKPROC        LINEDDAPROC

   ENHMFENUMPROC            MFENUMPROC

   ENUMRESLANGPROC          PROPENUMPROC

   ENUMRESNAMEPROC          PROPENUMPROCEX

   ENUMRESTYPEPROC          TIMERPROC

   FONTENUMPROC             WNDENUMPROC

   GOBJENUMPROC

For more information on C++ callbacks, please see the May 1993 issue of the

"Windows Tech Journal."

The following sample demonstrates how to use a static member function as a

thread function, and pass in the "this" pointer as an argument.

Sample Code

-----------

#include <windows.h>

class A

{

public:

   int x;

   int y;

   A() { x = 0; y = 0; }

   static StartRoutine( A * );   // Compiles clean, includes "this" pointer

};

void main( )

{

   A a;

   DWORD dwThreadID;

   CreateThread( NULL,

      0,

      (LPTHREAD_START_ROUTINE)(a.StartRoutine),

      &a,                        // Pass "this" pointer to static member fn

      0,

      &dwThreadID

   );

}

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: BseMisc


Passing Security Information to SetFileSecurity()

PSS ID Number: Q102100

Authored 28-Jul-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

The SetFileSecurity() Win32 application programming interface (API) takes a

pointer to a Security Descriptor. This is because SetFileSecurity() can set

any of the following security information for a file:

   The owner identifier of the file

   The primary group identifier of the file

   The discretionary access-control list (DACL) of the file

   The system access-control list (SACL) of the file

When you pass the SD and SECURITY_INFORMATION structure to

SetFileSecurity(), the SECURITY_INFORMATION structure identifies which

security information is to be set. The SECURITY_INFORMATION structure is a

DWORD that can be one of the following values:

   OWNER_SECURITY_INFORMATION

   GROUP_SECURITY_INFORMATION

   DACL_SECURITY_INFORMATION

   SACL_SECURITY_INFORMATION

Each of these values represents one of the security items listed above. The

SD that is passed to SetFileSecurity() is simply a container for the

security information being set for the specified file. SetFileSecurity()

examines the value in the SECURITY_INFORMATION structure, extracts the

appropriate information from the provided SD, and applies it to the

specified file's SD.

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: BseSecurity


PEN2CTL.VBX Custom Controls for Windows 95 Pen Services

PSS ID Number: Q130654

Authored 24-May-1995	Last modified 20-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) Version 4.0

SUMMARY

The PEN2CTL.VBX provides three pen edit custom controls to allow for quick

development of pen-aware applications using Microsoft Windows 95 Pen

Services. The application designer may substitute these custom controls for

the standard input controls available in Visual Basic.

MORE INFORMATION

The PEN2CTL.VBX ships with version 4.0 of the Win32 SDK and is available in

the Microsoft Software. It is installed along with the Pen 2.0 Samples

Library.

To get PEN2CTL.VBX along with the PENVBX.HLP Help file and the sample

application files discussed in this article, download PEN2CTL.EXE, a self-

extracting file, from the Microsoft Software Library (MSL) on the following

services:

 - CompuServe

      GO MSL

      Search for PEN2CTL.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download PEN2CTL.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the SOFTLIB\MSLFILES directory

      Get PEN2CTL.EXE

The PEN2CTL.EXE self-extracting file contains:

 - PENVBX.HLP, a help file that fully explains all the technical issues and

   describes how to interact with these pen-aware custom controls.

 - Several files that comprise a sample Pen application that demonstrates

   how to use all the major features of the PEN2CTL.VBX.

 - PEN2CTL.VBX, which is freely redistibutable and implements the three

   pen-aware custom edit controls: HEdit, BEdit, and lEdit.

    - HEdit is the handwriting edit control. It accepts free-form input.

      This control is similar to the standard Visual Basic text box except

      data can be entered using a pen in addition to the normal keyboard

      input method.

    - BEdit is the boxed edit control. It expands the properties of the

      handwriting edit control. It allows for additional manipulation of

      the writing area and provides the application with comb or box guides

      that accept pen input. Each segment or box accepts only a single

      character of input. This increases the accuracy of the recognition

      and in most cases is preferable to the handwriting edit control. The

      BEdit control also has the ability to provide a list of alternate

      words from which you may choose.

    - lEdit is the pen ink edit control. It is similar to a picture box

      control in that it allows you to draw, erase, move, resize,

      manipulate, and format pen strokes (called ink) on the control. It

      also allows you to set background pictures and grid lines as well as

      create bitmaps of the background and/or ink.

While there are many similarities between the controls provided by the Pen

1.0 VBX (PENCNTRL.VBX) and those provided by PEN2CTL.VBX, there are also

many differences. Those familiar with the Pen 1.0 VBX should refamiliarize

themselves with PEN2CTL.VBX and its changes.

NOTE: Neither VBX is compatible with the other but both implement some of

the same custom controls, so developers should make sure the correct VBX is

installed in their development environment and is distributed with their

application.

Additional reference words: 4.00 2.00

KBCategory: kbprg kbfile

KBSubcategory: WpenMisc WpenVB


Performing a Clear Screen (CLS) in a Console Application

PSS ID Number: Q99261

Authored 26-May-1993	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

There is no Win32 application programming interface (API) that will clear

the screen in a console application. However, it is fairly easy to write a

function that will programmatically clear the screen.

MORE INFORMATION

The following function clears the screen:

void cls( HANDLE hConsole )

{

   COORD coordScreen = { 0, 0 };    /* here's where we'll home the

                                       cursor */

   BOOL bSuccess;

   DWORD cCharsWritten;

   CONSOLE_SCREEN_BUFFER_INFO csbi; /* to get buffer info */

   DWORD dwConSize;                 /* number of character cells in

                                       the current buffer */

   /* get the number of character cells in the current buffer */

   bSuccess = GetConsoleScreenBufferInfo( hConsole, &csbi );

   PERR( bSuccess, "GetConsoleScreenBufferInfo" );

   dwConSize = csbi.dwSize.X * csbi.dwSize.Y;

   /* fill the entire screen with blanks */

   bSuccess = FillConsoleOutputCharacter( hConsole, (TCHAR) ' ',

      dwConSize, coordScreen, &cCharsWritten );

   PERR( bSuccess, "FillConsoleOutputCharacter" );

   /* get the current text attribute */

   bSuccess = GetConsoleScreenBufferInfo( hConsole, &csbi );

   PERR( bSuccess, "ConsoleScreenBufferInfo" );

   /* now set the buffer's attributes accordingly */

   bSuccess = FillConsoleOutputAttribute( hConsole, csbi.wAttributes,

      dwConSize, coordScreen, &cCharsWritten );

   PERR( bSuccess, "FillConsoleOutputAttribute" );

   /* put the cursor at (0, 0) */

   bSuccess = SetConsoleCursorPosition( hConsole, coordScreen );

   PERR( bSuccess, "SetConsoleCursorPosition" );

   return;

}

Additional reference words: 3.10 3.50 4.00 95  clearscreen

KBCategory: kbprg

KBSubcategory: BseCon


Performing a Synchronous Spawn Under Win32s

PSS ID Number: Q125212

Authored 22-Jan-1995	Last modified 04-May-1995

The information in this article applies to:

 - Microsoft Win32s, version 1.2

SUMMARY

Under Windows NT, you can synchronously spawn an application (that

is, spawn an application and wait until the spawned application is

terminated before continuing). To do so, call CreateProcess() to start the

application, and pass the handle returned to WaitForSingleObject() to

wait for the application to terminate. This is shown in the sample code

in the "More Information" section in this article.

However, this method does not work under Win32s. Under Win32s,

CreateProcess() does not return the process handle for 16-bit

Windows-based applications, only for Win32-based application. Even if it

did, the method described in the proceeding paragraph would not work under

Win32s because WaitForSingleObject() returns TRUE immediately under Win32s.

In fact, there is no 32-bit only solution for this issue. The 32-bit

WinExec() does not return an instance handle as the 16-bit WinExec() does.

In addition, you cannot use GetExitCodeProcess() to find the exit status

of 16-bit Windows-based applications in order to loop on their status. It

is a limitation that GetExitCodeProcess() returns zero for 16-bit

Windows-based applications on both Windows NT and Win32s.

The solution is to create a thunk to the 16-bit side and from the 16-bit

side, solve the problem as you would normally solve it from a Windows-based

application. Namely, start the application with WinExec() and use one of

the Toolhelp APIs in a test loop to determine when the application is

terminated. Alternatively, you can use EnumWindows() to determine when the

application is terminated. The sample code below uses the Toolhelp APIs.

MORE INFORMATION

Sample code to perform a synchronous spawn is given below. The code

is divided into three source files:

 - The main application.

 - The 32-bit side of the thunk.

 - The 16-bit side of the thunk.

You can use the thunking code as is, calling SynchSpawn() in your own

application as demonstrated in the main application below. For information

on Universal thunks (including which header files and libraries to use),

please see the "Win32s Programmer's Reference."

In all three modules, use the following header file SPAWN.H:

/*** Function Prototypes ****/

DWORD APIENTRY SynchSpawn( LPCSTR lpszCmdLine, UINT nCmdShow );

/*** Constants for Dispatcher ***/

#define SYNCHSPAWN     1

Main Application

----------------

This application attempts to synchronously spawn NOTEPAD under Windows NT

and Win32s. NOTE: Under Win32s, NOTEPAD is a 16-bit application.

GetVersion() is used to detect the platform. Under Windows NT,

CreateProcess() and WaitForSingleObject() perform the spawn. Under Win32s,

the thunked routine SynchSpawn() is called.

/*** Main application code ***/

#include <windows.h>

#include "spawn.h"

void main()

{

   DWORD dwVersion;

   STARTUPINFO si = {0};

   PROCESS_INFORMATION pi = {0};

   dwVersion = GetVersion();

   if( !(dwVersion & 0x80000000) )  // Windows NT

   {

      si.cb = sizeof(STARTUPINFO);

      si.lpReserved = NULL;

      si.lpReserved2 = NULL;

      si.cbReserved2 = 0;

      si.lpDesktop = NULL;

      si.dwFlags = 0;

      CreateProcess( NULL,

                     "notepad",

                     NULL,

                     NULL,

                     TRUE,

                     NORMAL_PRIORITY_CLASS,

                     NULL,

                     NULL,

                     &si,

                     &pi );

      WaitForSingleObject( pi.hProcess, INFINITE );

   }

   else if( LOBYTE(LOWORD(dwVersion)) < 4 )  // Win32s

   {

      SynchSpawn( "notepad.exe", SW_SHOWNORMAL );

   }

   MessageBox( NULL, "Return from SynchSpawn", " ", MB_OK );

}

32-bit Side of Thunk

--------------------

This DLL provides the 32-bit side of the thunk. If the DLL is loaded

under Win32s, it initializes the thunk in its DllMain() by calling

UTRegister(). The entry point SynchSpawn() packages up the arguments

and calls the 16-bit side through the thunk.

/*** Code for 32-bit side of thunk ***/

#define W32SUT_32    // Needed for w32sut.h in 32-bit code

#include <windows.h>

#include "w32sut.h"

#include "spawn.h"

typedef BOOL (WINAPI * PUTREGISTER) ( HANDLE     hModule,

                  LPCSTR     lpsz16BitDLL,

                  LPCSTR     lpszInitName,

                  LPCSTR     lpszProcName,

                  UT32PROC * ppfn32Thunk,

                  FARPROC    pfnUT32Callback,

                  LPVOID     lpBuff

                );

typedef VOID (WINAPI * PUTUNREGISTER) (HANDLE hModule);

typedef DWORD (APIENTRY *PUT32CBPROC) (LPVOID lpBuff, DWORD dwUserDefined);

UT32PROC      pfnUTProc = NULL;

PUTREGISTER   pUTRegister = NULL;

PUTUNREGISTER pUTUnRegister = NULL;

PUT32CBPROC   pfnUT32CBProc = NULL;

int           cProcessesAttached = 0;

BOOL          fWin32s = FALSE;

HANDLE        hKernel32 = 0;

/********************************************************************\

* Function: BOOL APIENTRY DllMain(HANDLE, DWORD, LPVOID)             *

*                                                                    *

*  Purpose: DLL entry point. Establishes thunk.                      *

BOOL APIENTRY DllMain(HANDLE hInst, DWORD fdwReason, LPVOID lpReserved)

{

   DWORD dwVersion;

   if ( fdwReason == DLL_PROCESS_ATTACH )

   {

    /*

     * Registration of UT need to be done only once for first

     * attaching process.  At that time set the fWin32s flag

     * to indicate if the DLL is executing under Win32s or not.

     */

      if( cProcessesAttached++ )

      {

         return(TRUE);         // Not the first initialization.

      }

      // Find out if we're running on Win32s

      dwVersion = GetVersion();

      fWin32s = (BOOL) (!(dwVersion < 0x80000000))

                        && (LOBYTE(LOWORD(dwVersion)) < 4);

      if( !fWin32s )

         return(TRUE);         // Win32s - no further initialization needed

      hKernel32 = LoadLibrary( "Kernel32.Dll" ); // Get Kernel32.Dll handle

      pUTRegister = (PUTREGISTER) GetProcAddress( hKernel32, "UTRegister"

);

      if( !pUTRegister )

         return(FALSE);        // Error- Win32s, but can't find UTRegister

      pUTUnRegister = (PUTUNREGISTER) GetProcAddress(hKernel32,

                                                     "UTUnRegister");

      if( !pUTUnRegister )

         return(FALSE);        // Error- Win32s, but can't find

UTUnRegister

      return (*pUTRegister)( hInst,           // Spawn32.DLL module handle

                             "SPAWN16.DLL",   // 16-bit thunk dll

                             "UTInit",        // init routine

              "UTProc",        // 16-bit dispatch routine

                             &pfnUTProc,      // Receives thunk address

                             pfnUT32CBProc,   // callback function

                             NULL );          // no shared memroy

   }

   if((fdwReason==DLL_PROCESS_DETACH)&&(0==--cProcessesAttached)&&fWin32s)

   {

      (*pUTUnRegister)( hInst );

      FreeLibrary( hKernel32 );

   }

} // DllMain()

/********************************************************************\

* Function: DWORD APIENTRY SynchSpawn(LPTSTR, UINT)                  *

*                                                                    *

* Purpose: Thunk to 16-bit code                                      *

DWORD APIENTRY SynchSpawn( LPCSTR lpszCmdLine, UINT nCmdShow )

{

   DWORD Args[2];

   PVOID Translist[2];

   Args[0] = (DWORD) lpszCmdLine;

   Args[1] = (DWORD) nCmdShow;

   Translist[0] = &Args[0];

   Translist[1] = NULL;

   return( (* pfnUTProc)( Args, SYNCHSPAWN, Translist) );

}

16-bit Side of Thunk

--------------------

This DLL provides the 16-bit side of the thunk. The LibMain() and WEP()

of this 16-bit DLL perform no special initialization. The UTInit()

function is called during thunk initialization; it stores the callback

procedure address in a global variable. The UTProc() function is called

with a code that indicates which thunk was called as its second

parameter. In this example, the only thunk provided is for SynchSpawn().

The synchronous spawn is performed in the SYNCHSPAWN case of the switch

statement in the UTProc().

NOTE: UTInit() and UTProc() must be exported. This can be done in the

module definition (.DEF) file.

/* Code for 16-bit side of thunk.                              */

/* Requires linking with TOOLHELP.LIB, for ModuleFindHandle(). */

#ifndef APIENTRY

#define APIENTRY

#endif

#define W32SUT_16     // Needed for w32sut.h in 16-bit code

#include <windows.h>

#include <toolhelp.h>

#include <malloc.h>

#include "w32sut.h"

#include "spawn.h"

UT16CBPROC glpfnUT16CallBack;

/********************************************************************\

* Function: LRESULT CALLBACK LibMain(HANDLE, WORD, WORD, LPSTR)      *

*                                                                    *

*  Purpose: DLL entry point                                          *

int FAR PASCAL LibMain( HANDLE hLibInst, WORD wDataSeg,

         WORD cbHeapSize, LPSTR lpszCmdLine)

{

   return (1);

} // LibMain()

/********************************************************************\

* Function: DWORD FAR PASCAL UTInit(UT16CBPROC, LPVOID)              *

*                                                                    *

*  Purpose: Universal Thunk initialization procedure                 *

DWORD FAR PASCAL UTInit( UT16CBPROC lpfnUT16CallBack, LPVOID lpBuf )

{

   glpfnUT16CallBack = lpfnUT16CallBack;

   return(1);   // Return Success

} // UTInit()

/********************************************************************\

* Function: DWORD FAR PASCAL UTProc(LPVOID, DWORD)                   *

*                                                                    *

*  Purpose: Dispatch routine called by 32-bit UT DLL                 *

DWORD FAR PASCAL UTProc( LPVOID lpBuf, DWORD dwFunc)

{

   switch (dwFunc)

   {

      case SYNCHSPAWN:

      {

          HMODULE hMod;

          MODULEENTRY FAR *me;

          UINT hInst;

          LPCSTR lpszCmdLine;

          UINT nCmdShow;

          MSG msg;

          BOOL again=TRUE;

          /* Retrieve the command line arguments stored in buffer */

          lpszCmdLine = (LPSTR) ((LPDWORD)lpBuf)[0];

          nCmdShow = (UINT) ((LPDWORD)lpBuf)[1];

          /* Start the application with WinExec() */

          hInst = WinExec( lpszCmdLine, nCmdShow );

          if( hInst < 32 )

             return 0;

          /* Loop until the application is terminated. The Toolhelp API

           * ModuleFindHandle() returns NULL when the application is

           * terminated. NOTE: PeekMessage() is used to yield the

           * processor; otherwise, nothing else could execute on the

           * system.

           * /

          hMod = GetModuleHandle( lpszCmdLine );

          me = (MODULEENTRY FAR *) _fcalloc( 1, sizeof(MODULEENTRY) );

          me->dwSize = sizeof( MODULEENTRY );

          while( NULL != ModuleFindHandle( me, hMod ) && again )

          {

             while( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) && again )

             {

                if(msg.message == WM_QUIT)

                {

                   PostQuitMessage(msg.wParam);

                   again=FALSE;

                }

                TranslateMessage(&msg);

                DispatchMessage(&msg);

             }

          }

          return 1;

      }

   } // switch (dwFunc)

   return( (DWORD)-1L ); // We should never get here.

} // UTProc()

/********************************************************************\

* Function: int FAR PASCAL _WEP(int)                                 *

*                                                                    *

*  Purpose: Windows exit procedure                                   *

int FAR PASCAL _WEP( int bSystemExit )

{

   return (1);

} // WEP()

Additional reference words: 1.20 win16

KBCategory: kbprg kbcode

KBSubcategory: W32s


PHONECAPS for Phones That Don't Report Button States

PSS ID Number: Q108308

Authored 08-Dec-1993	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Telephony Software Development Kit (SDK) version

   1.0 for Windows version 3.1

 - Microsoft Win32 SDK, version 4.0

A Windows Telephony application can call phoneGetDevCaps to inquire about a

phone's telephony capabilities. The resulting function in the TAPI

(Telephony application programming interface) service provider is

TSPI_phoneGetDevCaps. If the phone device does not report button states, it

is acceptable for the service provider to set the dwButtonModeSize/Offset

fields in the PHONECAPS structure to 0 (zero). Alternatively, the provider

could describe the button(s) as PHONEBUTTONMODE_DUMMY.

As a clarification, setting the dwButtonModeSize to 0 or describing the

buttons as PHONEBUTTON_DUMMY does not prohibit the service provider from

setting and using the dwButtonFunctionsSize and dwButtonFunctionsOffset

members of the PHONECAPS structure.

Additional reference words: 1.00 3.10 4.00 95

KBCategory: kbprg

KBSubcategory: MsgTapi


Physical Memory Limits Number of Processes/Threads

PSS ID Number: Q94840

Authored 19-Jan-1993	Last modified 14-Mar-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

Each time Windows NT creates an object, such as a process or a thread, it

must allocate a certain amount of physical memory (nonpaged pool) for its

support. The amount of memory that is needed for support of a process

object is significantly higher than the memory requirement for support of a

thread object. The amount of memory that is required for a thread object

on a RISC machine is higher than the memory requirement for a thread on an

x86 machine, due to the greater number and size of registers on the RISC

machines.

Due to the physical memory requirement of processes and threads, programs

that use the CreateProcess() and CreateThread() APIs should be careful to

check their return codes to detect out-of-memory conditions.

On Windows NT 3.5, each time a process is created it reserves the minimum

working set of memory. On a 32 MB system, the default minimum working set

is 200 KB. Therefore, on a 32 MB system, you can create ~100 processes. You

can lower your minimum working set to 80 KB (the lowest allowed) with the

following call:

   SetProcessWorkingSetSize( (HANDLE)(-1), 20*4096, 100*4096 );

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseProcThrd


Placing a Caret After Edit-Control Text

PSS ID Number: Q12190

Authored 16-Oct-1987	Last modified 25-May-1995

-

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK), versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.1, 3.5, 3.51, and 4.0

-

The EM_SETSEL message can be used to place a selected range of text in

a Windows edit control. If the starting and ending positions of the

range are set to the same position, no selection is made and a caret

can be placed at that position. To place a caret at the end of the

text in a Windows edit control and set the focus to the edit control,

do the following:

   hEdit = GetDlgItem( hDlg, ID_EDIT );    // Get handle to control

   SetFocus( hEdit );

   SendMessage( hEdit, EM_SETSEL, 0, MAKELONG(0xffff,0xffff) );

It is also possible to force the caret to a desired position within

the edit control. The following code fragment shows how to place the

caret just to the right of the Nth character:

   hEdit = GetDlgItem( hDlg, ID_EDIT );    // Get handle to control

   SetFocus( hEdit );

   SendMessage( hEdit, EM_SETSEL, 0, MAKELONG(N,N) );

                                        // N is the character position

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: UsrCtl


Placing Captions on Control Windows

PSS ID Number: Q77750

Authored 24-Oct-1991	Last modified 16-May-1995

-

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK), versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

-

The SetWindowText() function can be used to place text into the caption bar

specified for a control window. The control must have the WS_CAPTION style

for the caption to be visible.

This technique does not work with edit controls because the SetWindowText()

function specifies the contents of the edit control, not its caption.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: UsrCtl


Placing Double Quotation Mark Symbol in a Resource String

PSS ID Number: Q47674

Authored 03-Aug-1989	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

To specify a set of double quotation marks within a string in an

application's resource (RC) file, use two double quotation mark characters

in succession, as in the following example:

Specify the following string in the RC file:

   "The letter ""Q"" is quoted."

The following string will appear in the compiled resource (RES) file:

   The letter "Q" is quoted.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrRsc


Placing Text in an Edit Control

PSS ID Number: Q32785

Authored 11-Jul-1988	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.1, 3.5, 3.51, and 4.0

Text is placed into an edit control by calling SetDlgItemText() or by

sending the WM_SETTEXT message to the edit control window, with lParam

being a pointer to a null-terminated string. This message can be sent in

two ways:

1. SendMessage(hwndEditControl, WM_SETTEXT, ...

2. SendDlgItemMessage(hwndParent, ID_EDITCTL, WM_SETTEXT...

   NOTE: hwndParent is the window handle of the parent, which may be a

   dialog or window. ID_EDITCTL is the ID of the edit control.

Text is retrieved from an edit control by calling GetDlgItemText() or

by sending the WM_GETTEXT message to the edit control window, with

wParam being the maximum number of bytes to copy and lParam being a

far pointer to a buffer to receive the text. This message can be sent

in two ways:

1. SendMessage(hwndEditControl, WM_GETTEXT, ...

2. SendDlgItemMessage(hwndParent, ID_EDITCTL, WM_GETTEXT...

   NOTE: hwndParent is the window handle of the parent, which may be

   a dialog or window. ID_EDITCTL is the ID of the edit control.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: UsrCtl


Points to Remember When Writing a Debugger for Win32s

PSS ID Number: Q121093

Authored 26-Sep-1994	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32s, versions 1.1, 1.15, and 1.2

SUMMARY

This article is intended for developers of debugging tools for the Win32s

environment. It covers the issues that should be to taken into

consideration while writing debugging tools for the Win32s environment.

Overall, the code of a debugger for the Win32s environment is similar to

the code of a debugger for the Windows NT environment. There are special

points that must be considered before and while writing debugging tools for

the Win32s environment. They are:

 - Using the WaitForDebugEvent() API Function

 - Debugging Shared Code

 - Getting and Setting Thread Context

 - Tracing Through Mixed 16- and 32-bit Code

 - Using Asynchronous Stops

 - Identifying System DLLs

 - Understanding Linear and Virtual Addresses

 - Reading and Writing Process Memory

 - Accessing the Thread Local Storage (TLS)

Each of these is discussed in detail in the More Information section below.

MORE INFORMATION

The following information is specific to writing a debugger for the Win32s

environment.

Using the WaitForDebugEvent() API Function

-------------------------------------------

The WaitForDebugEvent() API function waits for a debugging event to occur

in a process being debugged. Use it to trap debugging events.

Because of the non-preemptive nature of Windows version 3.1, it is not

possible to guarantee the timeout functionality. For this reason, the

dwTimeout parameter was implemented differently in Win32s. In Win32s, if

dwTimeout is zero, the WaitForDebugEvent() function behaves as documented

in the "Win32 Programmer's Reference." Otherwise, the function waits

indefinitely, until a debug event occurs or until a message is received for

that process.

Make sure the function returns if a message is received, so that the

calling process can respond to messages. If WaitForDebugEvent() returns

because a debug event has occurred, the return value is TRUE. Otherwise,

the return value is FALSE. In Win32, a FALSE return value means failure.

Have the calling process use SetLastError() to set the error value to 0

before calling WaitForDebugEvent(). Then if the return value is FALSE and

error value returned by GetLastError() is still zero, it means a message

arrived.

The following code fragment demonstrates the use of WaitForDebugEvent() in

the message loop:

   while( GetMessage(&msg, NULL, NULL, NULL) )

   {

      TranslateMessage(&msg); /* Translate virtual key codes */

      DispatchMessage(&msg);  /* Dispatch message to window */

      SetLastError( 0 );      /* Set error code to zero  */

      if( WaitForDebugEvent(&DebugEvent, INFINITE) )

      {

      /* Process the debug event */

         ProcessDebugEvents( &DebugEvent );

      }

      else

      {

         if( GetLastError() != 0 )

         {

         /* Handle error condition. */

         }

      }

   }

Debugging Shared Code

---------------------

Under Win32s, all processes run in a single address space. For that reason,

if a debugger sets a breakpoint in shared code, all processes will

encounter this breakpoint, even those that are not being debugged. For

these processes, the debugger should restore the code, let the process

execute the restored instruction, and then reset the breakpoint. The

problem is that in order to do these operations, the debugger needs a

handle to the process thread.

The debugger does not have a handle for the process thread of a process it

did not create. To get the handle, Win32s supports a new function,

OpenThread(), which is not a part of the Win32 API.

   HANDLE OpenThread(dwThreadId);

   DWORD dwThreadId;  /* The thread ID */

   Parameter description:

      dwThreadId - Specifies the thread identifier of the thread to open.

   Returns:

      If the function succeeds, the return value is an open handle of the

      specified thread; otherwise, it is NULL. To get extended error

      information, use the GetLastError() API.

   Comments:

      The handle returned by OpenThread() can be used in any function that

      requires a handle to a thread.

OpenThread() is exported by KERNEL32.DLL, but is not included in any of the

SDK import libraries.

To create an import library on a Windows NT development machine:

1. Place the following contents into a file named W32SOPTH.C:

   #include <windows.h>

   HANDLE WINAPI OpenThread(DWORD dwThreadId)

   {

      return (HANDLE)NULL;

   }

2. Place the following contents into a file named W32SOPTH.DEF:

   LIBRARY kernel32

   DESCRIPTION 'Win32s OpenThread library'

   EXPORTS

      OpenThread

3. Place the following contents into a file named MAKEFILE:

   w32sopth.lib: w32sopth.obj

      lib -out:w32sopth.lib -machine:i386 -def:w32sopth.def w32sopth.obj

   w32sopth.obj: w32sopth.c

      cl /c w32sopth.c

4. Run the NMAKE utility from the directory that contains the files

   created in steps 1-3. This creates the W32SOPTH.LIB file.

The debugger should perform the following test: in the DEBUG_INFO structure

returned by WaitForDebugEvent(), there is a thread ID. The debugger should

check to see if this ID is one of the debugged processes. If it is not, the

debugger should call OpenThread() with the given thread ID as the parameter

and receive a handle to the thread. Using this handle, the debugger should

call GetThreadContext(), identify the breakpoint, restore the code, set the

single step bit of EFlag, and resume the process by calling

ContinueDebugEvent(). Then control returns to the debugger. The debugger

restores the breakpoint. After dealing with the non-debugged process, the

debugger must close the thread handle obtained from OpenThread() by using

CloseHandle().

The following code fragment demonstrates how a debugger can handle

breakpoints in the context of a non-debugged process:

   LPDEBUG_EVENT lpEvent;  /* Pointer to the debug event structure */

   HANDLE hProc;           /* Handle to process */

   HANDLE hThread;         /* Handle to thread */

   CONTEXT Context;        /* Context structure */;

   BYTE bOrgByte;          /* Original byte in the place of BP */

   DWORD cWritten;         /* Number of bytes written to memory */

   static DWORD dwBPLoc;   /* Breakpoint location */

   /*

    * Other debugger functions:

    *

    * LookupThreadHandle -

    *    Receives a thread ID and returns a handle to the thread, if

    *    the thread created by the debugger, else returns NULL.

    */

   HANDLE LookupThreadHandle(DWORD);

   /*

    * LookupOriginalBPByte -

    *    Receives an address of a breakpoint and returns the original

    *    contents of the memory in the place of the breakpoint.

    *    The memory contents is returned in the byte buffer passed as

    *    a parameter.

    * Return value - If the breakpoint was set by the debugger the

    *   return value is TRUE, else FALSE.

    */

   BOOL LookupOriginalBPByte( LPVOID, LPBYTE );

   /* Handle debug events according to event types */

   switch( lpEvent->dwDebugEventCode )

   {

   /* ... */

      case EXCEPTION_DEBUG_EVENT:

      /* Handle exception debug events according to exception type */

         switch( lpEvent->u.Exception.ExceptionRecord.ExceptionCode )

         {

         /* ... */

         case EXCEPTION_BREAKPOINT:

            /* Breakpoint exception */

            /* Look for the thread handle in the debugger tables */

               hThread = LookupThreadHandle( lpEvent->dwThreadId );

               if( hThread == NULL )

               {

               /* Not a debuggee */

               /* Get process and thread handles */

                  hProc = OpenProcess( 0, FALSE, lpEvent->dwProcessId );

                  hThread = OpenThread( lpEvent->dwThreadId );

               /* Get the full context of the processor */

                  Context.ContextFlags = CONTEXT_FULL;

                  GetThreadContext( hThread, &Context );

               /* We get the exception after executing the INT 3 */

                  dwBPLoc = --Context.Eip;

               /* Restore the original byte in memory in the */

               /* place of the breakpoint */

                  if( !LookupOriginalBPByte((LPVOID)dwBPLoc, &bOrgByte) )

                  {

                  /* Handle unfamiliar breakpoint */

                  }

                  else

                  {

                  /* Restore memory contents */

                     WriteProcessMemory( hProc, (LPVOID)dwBPLoc,

                     &bOrgByte, 1, &cWritten );

                  /* Set the Single Step bit in EFlags */

                     Context.EFlags |= 0x0100;

                     SetThreadContext( hThread, &Context );

                  }

               /* Free Handles */

                  CloseHandle( hProc );

                  CloseHandle( hThread );

               /* Resume the interrupted process */

                  ContinueDebugEvent( lpEvent->dwProcessId,

                                      lpEvent->dwThreadId, DBG_CONTINUE );

               }

               else

               {

               /* Handle debuggee breakpoint. */

               }

               break;

            case STATUS_SINGLE_STEP:

               hThread = LookupThreadHandle( lpEvent->dwThreadId );

               if( hThread == NULL )

               {

               /* Not a debuggee, just executed the original instruction */

               /* and returned to the debugger. */

               /* Get process handle */

                  hProc = OpenProcess( 0, FALSE, lpEvent->dwThreadId );

               /* Restore the INT 3 instruction in the place of the BP */

                  bOrgByte = 0xCC;

                  WriteProcessMemory( hProc, (LPVOID)dwBPLoc,

                  &bOrgByte, 1, &cWritten );

               /* Free Handle */

                  CloseHandle( hProc );

               /* Resume the process */

                  ContinueDebugEvent( lpEvent->dwProcessId,

                                      lpEvent->dwThreadId, DBG_CONTINUE );

               }

               else

               {

               /* Handle debuggee single-step. */

               }

               break;

         /* .... */

      }

   /* .... */

   }

This sample code does not contain code to handle error checking and return

values from APIs. The assumption is that a non-debugged process generates a

single step exception only when it is executing the instruction in the

place of the breakpoint. The code for handling the single step exception

does not handle debug registers.

Getting and Setting Thread Context

----------------------------------

Because of architectural differences between Windows NT and Win32s, there

is a difference in the way GetThreadContext() and SetThreadContext() work

in Win32s. These functions return successfully only if they are called

after returning from WaitForDebugEvent() with the EXCEPTION_DEBUG_EVENT

value in the dwDebugEventCode field of the DEBUG_INFO structure and before

calling ContinueDebugEvent(). At any other point, these APIs fail and

GetLastError() returns ERROR_CAN_NOT_COMPLETE.

Tracing Through Mixed 16- and 32-bit Code

-----------------------------------------

Occasionally, Win32-based applications switch to 16-bit mode and then go

back to 32-bit mode. For example, part of the Windows API is implemented in

Win32s by using thunks to connect to Windows version 3.1. That means that

in order to call the API, Win32s switches to 16-bit mode, calls the

corresponding API on the Windows version 3.1 side, and then returns to 32-

bit mode.

Most debuggers do not allow tracing through 16-bit code. So when the code

is about to switch to 16-bit mode, the debugger should trace over this

code. To do so, Win32s supplies the DbgBackTo32 label. All calls to 16-bit

code return through this address. The DbgBackTo32 label is exported by

W32SKRNL.DLL. At this label, there is a RET instruction. After executing

this RET instruction and immediately another following RET instruction,

Win32s resumes execution at the application code, at the instruction

following the call to the thunked function. So if the debugger determines

that the next call is into a thunk function, it can set a breakpoint at

DbgBackTo32 and trace over this call.

Using Asynchronous Stops

------------------------

The asynchronous stop key combination was set to CTRL+ALT+F11 in Win32s.

It allows a 16-bit debugger to run at the same time as a 32-bit debugger.

Each debugger can synchronously stop the other.

If the user presses CTRL+ALT+F11 when the executing code is 16-bit code,

execution will not be interrupted until it returns to 32-bit code. This

way, the debugger does not have to handle 16-bit code. If the user presses

CTRL+ALT+F11 when the executing code is 32-bit code, execution is

interrupted immediately.

Execution is interrupted by generating a single step exception. To handle

the case where the user presses CTRL+ALT+F11 while 16-bit code is

executing, the address of the exception is at a special Win32s label

(W32S_BackTo32). This label is exported by W32SKRNL.DLL and is located a

few instructions before DbgBackTo32. For more information on this see the

"Tracing Through Mixed 16- and 32-bit Code" above.

The code at W32S_BackTo32 is system code and usually debuggers should not

allow tracing through system code. But between W32S_BackTo32 and

DbgBackTo32, the debugger may allow tracing through this specific code and

also through the two following RET instructions. This will bring the user

to the point in the application at which CTRL+ALT+F11 was pressed.

Identifying System DLLs

-----------------------

When tracing through application code, it is not desirable to trace into

system DLL code. The main reason for this is that in many cases the code

goes to 16-bit code. To enable the debugger to distinguish between system

and user DLLs, all Win32s system DLLs contain an extra exported symbol

called WIN32SYSDLL. The address of this symbol is meaningless. The

existence of such a symbol indicates that this is a system DLL.

Understanding Linear and Virtual Addresses

------------------------------------------

Win32s uses flat memory address space as does Windows NT, but unlike

Windows NT, the base of the code and data segments is not at zero. You must

consider this when dealing with linear addresses -- such as hardware debug

registers when setting a hardware breakpoint. When setting a hardware

breakpoint, you need to add the base of the selector to the virtual address

of the breakpoint and set the debug register with this value. If you do not

do so, the code will run on Windows NT but not on Win32s.

The debugger needs to get the base address of the selectors by using the

GetThreadSelectorEntry() function.

Similarly, when the hardware breakpoint is encountered, you must subtract

the selector base address from the contents of the debug register in order

to read the process memory at the breakpoint location.

Reading and Writing Process Memory

----------------------------------

When reading from or writing to process memory, all hardware breakpoints

must be disabled. If you do not do so, accessing the memory locations

pointed to by the debug registers will trigger the hardware breakpoints.

The following code demonstrates how a debugger can read process memory at

the location of a read memory hardware breakpoint:

   CONTEXT Context;

   LDT_ENTRY SelEntry;

   DWORD dwDsBase;

   DWORD DR7;

   BYTE Buffer[4];

   /* Get Context */

   Context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;

   GetThreadContext( hThread, &Context );

   /* Calculate the base address of DS */

   GetThreadSelectorEntry(hThread, Context.SegDs, &SelEntry);

   dwDsBase = ( SelEntry.HighWord.Bits.BaseHi << 24) |

                (SelEntry.HighWord.Bits.BaseMid << 16) |

                SelEntry.BaseLow;

   /*

    * Disable all hardware breakpoints before reading the process

    * memory. Not doing so will lead to nested breapoints.

    */

   DR7 = Context.Dr7;

   Context.Dr7 &= ~0x3FF;

   SetThreadContext( hThread, &Context );

   /* Read DWORD at the location of DR0 */

   ReadProcessMemory( hProcess,

                      (LPVOID)((DWORD)Context.Dr0-dwDsBase),

                      Buffer, sizeof(Buffer), NULL);

   /* Restore hardware breakpoints */

   Context.Dr7 = DR7;

   SetThreadContext( hThread, &Context );

Accessing the Thread Local Storage (TLS)

-----------------------------------------

The lpThreadLocalBase field of the CREATE_PROCESS_DEBUG_INFO structure in

Windows NT specifies the base address of a per-thread data block. At offset

0x2C within this block, there exists a pointer to an array of LPVOIDs.

There is one LPVOID for each DLL/EXE loaded at process initialization, and

that LPVOID points to Thread Local Storage (TLS). This gives a debugger

access to per-thread data in its debuggee's threads using the same

algorithms that a compiler would use.

On the other hand, in Win32s, lpThreadLocalBase contains a pointer directly

to the array of LPVOIDs, not the pointer to the per-thread data block.

Additional reference words: 1.10 1.15 1.20

KBCategory: kbprg kbcode

KBSubCategory: W32s


Possible Cause for ERROR_INVALID_FUNCTION

PSS ID Number: Q111838

Authored 20-Feb-1994	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

SUMMARY

The Win32 Tape API (application programming interface) functions may return

an error code of ERROR_INVALID_FUNCTION if the operation being attempted is

not supported by the tape device.

MORE INFORMATION

You can determine what operations are valid for a tape device by calling

GetTapeParameters() to get the tape drive parameters. See the code fragment

in the Sample Code section of this article for an example of how to call

GetTapeParameters() for this information.

Once you have the TAPE_GET_DRIVE_PARAMETERS structure, you can check for a

specific operation in the FeaturesLow and FeaturesHigh members of the

TAPE_GET_DRIVE_PARAMETERS structure. This is also demonstrated in the

Sample Code section.

Sample Code

-----------

/*

** This is a code fragment only and will not compile and run as is.

*/

DWORD dwRes, dwSize;

TAPE_GET_DRIVE_PARAMETERS parmDrive;

...

dwSize = sizeof(parmDrive);

dwRes = GetTapeParameters(hTape, GET_TAPE_DRIVE_INFORMATION,

                &dwSize, &parmDrive);

if (dwRes != NO_ERROR) {

    /* place error handling code here */

    exit(-1);

}

if (parmDrive.FeaturesLow & TAPE_DRIVE_ERASE_LONG)

    printf("Device supports the long erase technique.\n");

...

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseFileio


Possible Serial Baud Rates on Various Machines

PSS ID Number: Q99026

Authored 19-May-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   versions 3.1 and 3.5

SUMMARY

Computers running Windows NT may be unable to set the same serial baud

rates due to differences in serial port hardware on various platforms and

machines. These differences may be important to note when writing a serial

communications application that runs on different Windows NT platforms.

The simplest way to determine what baud rates are available on a particular

serial port is to call the GetCommProperties() application programming

interface (API) and examine the COMMPROP.dwSettableBaud bitmask to

determine what baud rates are supported on that serial port.

MORE INFORMATION

Some baud rates may be available on one machine and not on another because

of differences in the serial port hardware used on the two machines. Most

Intel 80x86 machines use a standard 1.8432 megahertz (MHz) clock speed on

serial port hardware, and therefore most Intel machines can set the same

baud rates. However, on other platforms, such as MIPS, there is no standard

serial port clock speed. MIPS serial ports are known to exist with 1.8432

MHz, 3.072 MHz, 4.2336 MHz, and 8.0 MHz serial port clock chips. Future NT

implementations on other platforms may have different serial port clock

speeds as well.

Furthermore, certain requested baud rates are special-cased in the Windows

NT serial driver so that they will work. The following are these special

cases:

   MHz     Requested Baud    Divisor   Resulting Baud Rate (+/- 1)

  ---------------------------------------------------------------

   1.8432      56000            2              57600

   3.072       14400           13              14769

   4.2336       9600           28               9450

   4.2336      14400           18              14700

   4.2336      19200           14              18900

   4.2336      38400            7              37800

   4.2336      56000            5              52920

   8.0         14400           35              14286

   8.0         56000            9              55556

The actual baud rate can be calculated by dividing the divisor multiplied

by 16 into the clock rate. For example, for a 1.8432 MHz clock and a

divisor of 2, the baud rate would be:

   1843200 Hz / (2 * 16) = 57600

For all other cases, as long as the requested baud rate is within 1 percent

of the nearest baud rate that can be found with an integer divisor, the

baud rate request will succeed.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseCommapi


Posting Frequent Messages Within an Application

PSS ID Number: Q40669

Authored 26-Jan-1989	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

The object-oriented nature of Windows programming can create a situation in

which an application posts a message to itself. When such an application is

designed, care must be taken to avoid posting messages so frequently that

system messages to the application are not processed. This article

discusses two methods of using the PeekMessage() function to combat this

situation.

MORE INFORMATION

In the first method, a PeekMessage() loop is used to check for system

messages to the application. If none are pending, the SendMessage()

function is used from within the PeekMessage() loop to send a message to

the appropriate window. The following code demonstrates this technique:

while (fProcessing)

     {

     if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))

          {

          if (msg.message == WM_QUIT)

               break;

          /* process system messages */

          }

     else

          {

          /* perform other processing */

          ...

          /* send WM_USER message to window procedure */

          SendMessage(hWnd, WM_USER, wParam, lParam);

          }

     }

In the second method, two PeekMessage() loops are used, one to look for

system messages and one to look for application messages. PostMessage() can

be used from anywhere in the application to send the messages to the

appropriate window. The following code demonstrates this technique:

while (fProcessing)

     {

     if (PeekMessage(&msg, NULL, 0, WM_USER-1, PM_REMOVE))

          {

          if (msg.message == WM_QUIT)

               break;

          /* process system messages */

          }

     else if (PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_REMOVE))

          /* process application messages */

     }

An application should use a PeekMessage() loop for as little time as

possible. To be compatible with battery-powered computers and to optimize

system performance, every Windows-based application should inform Windows

that it is idle as soon and as often as possible. An application is idle

when the GetMessage() or WaitMessage() function is called and no messages

are waiting in the application's message queue.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrMsg


PRB: "Out of Memory Error" in the Win32 SDK Setup Sample

PSS ID Number: Q114610

Authored 08-May-1994	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SYMPTOMS

When a dialog box is shown using UIStartDlg() or a billboard is switched

during the file copy operation, you may receive an "out of memory" error.

The error will also occur in any setup program based on a modified version

of the SDK sample.

CAUSE

The dialog box and billboard templates are stored as resources in

MSCUISTF.DLL. This DLL (Dynamic Link Library) is not loaded at the

beginning of the setup program but is rather loaded and unloaded [using

LoadLibrary() and FreeLibrary()] around each call to UIStratDlg() and when

billboards are switched. Hence, each time a dialog or billboard is

displayed, floppy disk #1 has the potential of being accessed. If disks

have been swapped due to the installation process such that disk #1 is no

longer in the drive, you will receive an out of memory error when

LoadLibrary() is called on MSCUISTF.DLL.

RESOLUTION

To solve the problem, call LoadLibrary() at the beginning of WinMain() and

call FreeLibrary() and the end of WinMain(). This way the DLL is always in

use and will never be unloaded until the setup is done.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbtool kbprb

KBSubcategory: TlsMss


PRB: "Routine Not Found" Errors in Windows Help

PSS ID Number: Q108722

Authored 16-Dec-1993	Last modified 28-Nov-1994

The information in this article applies to:

 - Microsoft Win32s versions 1.0, 1.1, and 1.2

SYMPTOMS

When Freecell is running on Win32s, you may get some errors when you try to

use Freecell Help. This has nothing to do with whether or not Win32s is

installed correctly.

When you first open Help in Freecell running on Win32s, you will get a

message box that says, "Routine Not Found."  You will get that same

message box when you choose the Find button.

When you choose any term in Freecell Help that has a dotted underline (a

pop-up hot key), a window pops up but then quickly disappears. You will

then get a message box that reads, "Help Topic Does Not Exist."

CAUSE

FREECELL.HLP was meant to be used with WINHLP32.EXE. FREECELL.HLP uses the

advanced features of WINHLP32.EXE for full-text searching. WINHELP.EXE,

which runs on Windows 3.1, does not support full-text searching.

WINHLP32.EXE does not run on Win32s or Windows 3.1. As a result, everytime

FREECELL.HLP tries to bind the Find button to the full-text searching

functions, it fails, and WinHelp pops up an error message box.

RESOLUTION

You can still read the information in the help file. Although you cannot

use the Find button to do full-text searches, you can use the Search

button to do keyword searches. WINHLP32.EXE will not work on a MS-DOS +

Windows + Win32s operating system. If you need to read the pop-up

definitions or use the Find button, you can do so if you run Freecell Help

on the Windows NT operating system.

Additional reference words: 1.00 1.10 1.20

KBCategory: kbprg kbprb

KBSubcategory: W32s


PRB: _getdcwd() Returns the Root Directory Under Win32s

PSS ID Number: Q98286

Authored 02-May-1993	Last modified 28-Nov-1994

The information in this article applies to:

 - Microsoft Win32s versions 1.1 and 1.2

SYMPTOMS

In the following code segment, _getdcwd() always returns the root:

   _getdcwd( 3, cBuf, MAX_PATH );

   MessageBox( hWnd, cBuf, "Drive 3 <C drive>", MB_OK );

Also, in the following code segment, _chdrive() and _getcwd() always return

the root:

   _chdrive( 3 );

   _getcwd( cBuf, MAX_PATH );

   MessageBox( hWnd, cbuf, "Drive 3 <C drive>", MB_OK );

CAUSE

When a Win32-based application starts on Win32s, the root is set as the

current directory for any drive except the default drive.

RESOLUTION

The following code fragments work as expected under Win32s:

   _getdcwd( 0, cBuf, MAX_PATH );

   MessageBox( hWnd, cBuf, "Drive 0 <default drive>", MB_OK );

   -or-

   GetCurrentDirectory( sizeof (cBuf), cBuf );

   MessageBox( hWnd, cBuf, "SCD", MB_OK );

MORE INFORMATION

Windows NT uses the current directory of a process as the initial current

directory for the current drive of a child process. So for example, if the

current directory in the command prompt (CMD.EXE) is C:\WINNT then the

current directory of the child process will be C:\WINNT.

However, on Win32s, the current directory for any drive except the default

drive is set to the root and not the current directory of the parent

process. A Win32-based application running on Win32s calling _chdrive() or

SetCurrentDirectory() to change the drive GetCurrentDirectory or _getcwd()

will then return the root. The _getdcwd() function is a composite of

changing drives, getting the current directory of that drive, and change

back to the original drive. Therefore, _getdcwd() will always return the

root on Win32s.

Running the following sample to display the current directory of drives C

and D under Windows NT properly displays the full path of the drive.

Running the sample under Win32s always displays the root ("C:\", "D:\").

Sample Code

-----------

#include <direct.h>

...

   status =  _getdcwd(3, szPath, MAX_PATH);    // drive 3 == C:

   if( status != NULL )

   {

      MessageBox( hWnd, szPath, "Current working directory on C:", MB_OK );

   }

   status =  _getdcwd( 4, szPath, MAX_PATH );  // drive 4 == D:

   if( status != NULL )

   {

      MessageBox( hWnd, szPath, "Current working directory on D:", MB_OK );

   }

...

Additional reference words: 1.10 1.20

KBCategory: kbprg kbprb

KBSubcategory: W32s


PRB: Access Denied When Opening a Named Pipe from a Service

PSS ID Number: Q126645

Authored 27-Feb-1995	Last modified 06-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.5 and 3.51

SYMPTOMS

If a service running in the Local System account attempts to open a named

pipe on a computer running Windows NT version 3.5, the operation may fail

with an Access Denied error (error 5). This can happen even if the pipe was

created with a NULL DACL.

NOTE: For more information about placing a NULL DACL on a named pipe,

please see the following article in the Microsoft Knowledge Base:

   ARTICLE-ID: Q102798

   TITLE     : Security Attributes on Named Pipes

CAUSE

In Windows NT version 3.1, a process running in the Local System account

could connect to a resource using a Null Session. For security reasons, use

of the Null Session is restricted by default on Windows NT version 3.5.

RESOLUTION

You can allow access to a named pipe using the Null Session by adding

the pipe name to the following registry entry on the machine that

creates the named pipe:

   \HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\LanmanServer\

      Parameters\NullSessionPipes

The pipe name added to this entry is the name after the last backslash

in the string used to open the pipe. For example, if you use the following

string to open the pipe:

   \\hardknox\pipe\mypipe

you would add mypipe to the NullSessionPipes entry on the computer named

hardknox.

You must either reboot or restart (stop and then start) the Server service

for changes in this entry to take effect. Also, the named pipe will still

need to have a NULL DACL.

In Windows NT 3.51, by customer request, it is no longer necessary to

reboot. Once a named pipe is added to the key listed above, null-session

connections to that pipe will immediately be accessible.

This new functionality allows programs to permit null session access

to named pipes that do not have names known prior to booting the

system.

MORE INFORMATION

Usually, when a session is established between a computer supplying a

resource (server) and a computer that wants to use the resource (client),

the client is identified and credentials are verified. When a Null Session

is used, there is no validation of the client; everyone is allowed access.

If you allow a pipe to be used by a Null Session, you should either:

 - Verify that the data supplied by the pipe is truly public.

    -or-

 - Use an alternative method for verifying clients.

REFERENCES

The "Windows NT Registry Entries" help file in the Windows NT version 3.5

Resource Kit.

Additional reference words: 3.50

KBCategory: kbprg kbprb

KBSubcategory: BseSecurity


PRB: AccessCheck() Returns ERROR_INVALID_SECURITY_DESCR

PSS ID Number: Q115946

Authored 07-Jun-1994	Last modified 28-Nov-1994

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   versions 3.1 and 3.5

SYMPTOMS

In certain cases, the AccessCheck() API fails and GetLastError() returns

the message "ERROR_INVALID_SECURITY_DESCR". This error message indicates

that the security descriptor passed to AccessCheck() was in an invalid

format.

CAUSE

This is expected behavior for the AccessCheck() function. AccessCheck()

was designed for use by programs that create and maintain their own

security descriptors. These security descriptors would always have the

owner, DACL, and group information.

RESOLUTION

If the security descriptor is indeed valid, you can eliminate the error

by ensuring that the security descriptor has been opened for access to

the following types of security information:

     OWNER_SECURITY_INFORMATION

     GROUP_SECURITY_INFORMATION

     DACL_SECURITY_INFORMATION

You can double check the validity of the security descriptor by calling

the IsValidSecurityDescriptor() API.

Additional reference words: 3.10 3.50

KBCategory: kbprg kbprb

KBSubcategory: BseSecurity


PRB: After CreateService() with UNC Name, Service Start Fails

PSS ID Number: Q127862

Authored 19-Mar-1995	Last modified 04-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), version 3.5

SYMPTOMS

When giving a Universal Naming Convention (UNC) name to CreateService(),

the call succeeds, but service start fails with ERROR_ACCESSS_DENIED (5).

The access denied message is given, even though the service runs under an

account that has logon as service rights and has full access to the service

image path.

CAUSE

The service control manager calls CreateProcess() to start the service and

the service controller runs in the LocalSystem security context. When you

call CreateProcess() with a UNC name from a process running in the

LocalSystem context, you get ERROR_ACCESS_DENIED. This is because

LocalSystem has restricted (less than guest) access to remote machines. A

null session is set up for LocalSystem remote access, which has reduced

rights (less in Windows NT version 3.5 than in Windows NT version 3.1).

RESOLUTION

There are two possible solutions:

 - When specifying the fully qualified path to the service binary file,

   do not use a UNC name. It may be desirable to copy the service binary

   file to the local machine. This has the added benefit that the service

   will no longer be dependent on network operations.

   -or-

 - If the service binary is on \\MACHINEA\SHARENAME, add SHARENAME to

   HKEY_LOCAL_MACHINE\SYSTEM\

      CurrentControlSet\

      Services\

      LanmanServer\

      Parameters\

      NullSessionShares

   on MACHINEA. This will let requests to access this share from null

   sessions succeed.

   WARNING: This will allow everyone access to the share. If you want to

   maintain security for the share, create an account with the access

   required.

Additional reference words: 3.50

KBCategory: kbprg kbprb

KBSubcategory: BseService


PRB: Applications Cannot Change the Desktop Bitmap

PSS ID Number: Q74366

Authored 16-Jul-1991	Last modified 13-Jun-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SYMPTOMS

The desktop bitmap is not updated when an application updates the Wallpaper

entry of the [Desktop] section of WIN.INI and then sends a WM_WININICHANGE

message to the desktop window.

RESOLUTION

By design, there is no supported method for an application to dynamically

change the desktop bitmap under Windows 3.0 and 3.1.

MORE INFORMATION

Please note that an application could accidentally (or maliciously)

reference a desktop bitmap in a format that would GP fault the system. For

additional information, please see the following article(s) in the

Microsoft Knowledge Base:

   ARTICLE-ID: Q69292

   TITLE     : PRB: Video Driver GP Faults When Handling Large Bitmaps

Because the entry in WIN.INI has changed, this means that Windows will GP

fault every time the user tries to start it in the future, making Windows

no longer available.

In Windows 3.1, the application can call

   SystemParametersInfo(SPI_SETDESKWALLPAPER,....)

which has safety checks built in.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95  WM_WININICHANGE

KBCategory: kbprg kbprb

KBSubCategory: UsrIni


PRB: Area Around Text and Remainder of Window Different

PSS ID Number: Q22242

Authored 17-Dec-1987	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SYMPTOMS

When text is painted into a window, an area around the text is a

different color than the remainder of the window.

CAUSE

The area around the text is painted with a solid color while the

remainder of the window is painted using a dithered color.

RESOLUTION

To make the area around the text and the remainder of the window

have the same color, perform one of the following two steps:

 - Use a solid color for the window background, and use the same

   color for the text background. To ensure that a color is a solid

   color, use the GetNearestColor function. This function returns

   the nearest solid color available to represent the specified

   color.

   -or-

 - Call the SetBkMode function to specify TRANSPARENT mode for the

   text. Doing so prevents Windows from painting the area behind

   the text. The window background color shows through instead.

MORE INFORMATION

By default, when an application paints text into its window, Windows

fills the area around the character with the current background color.

Windows always uses a solid color for this purpose.

When an application registers a window class, it specifies a handle to

a brush that Windows uses to paint the window background. On some

output devices, brushes can create dithered colors. On one of these

devices, the area behind painted text might have a different color

than the remainder of the window.

The following code specifies the window background color:

   #define ELANGREEN  0x003FFF00

   pTemplateClass->hbrBackground = CreateSolidBrush((DWORD)ELANGREEN);

The following code specifies the color used to paint around text and

draws some text into a device context:

   #define SZ -1

   SetBkColor(hDC, (DWORD)ELANGREEN);

   DrawText(hDC, (LPSTR)"text", SZ, (LPRECT)&Rect, DT_BOTTOM);

The color used to paint the area around the text has a yellow cast,

which gives it a slightly different appearance than the window

background color.

A brush may be able to represent a wider color range than the solid

colors because a brush covers an area while a solid color may be used

to paint nominal-width lines (for example, lines that are one device

unit wide) that must be the same color at all locations and angles.

Therefore, the device-driver writer has the option of providing

dithered colors for brushes, but has no such freedom when it comes to

the solid colors for drawing lines.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg kbprb

KBSubcategory: GdiDrw


PRB: AttachThreadInput() Resets Keyboard State

PSS ID Number: Q100486

Authored 22-Jun-1993	Last modified 29-Nov-1994

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   version 3.1

SYMPTOMS

Start with a program that calls AttachThreadInput() to a thread in another

process. Call GetKeyboardState() to get the current key. Call

SetKeyboardState() to set the keystate. This call returns TRUE, indicating

success, but the keystate is not successfully set.

If the thread is in the same process, calling SetKeyboardState() works as

expected.

CAUSE

When attaching to another thread, a temporary message queue is created.

This queue contains a copy of the keystate information from the queue to

which you are attaching. When the keystate is set, the temporary queue

keystate is updated and the application programming interface (API)

succeeds. However, when the detach occurs, the keystate change information

is lost and reverts to what it was before the attach.

RESOLUTION

To work around the problem, either:

 - Stay attached

   -or-

 - Use hooks

STATUS

This problem will not be resolved in the release of Windows NT version 3.1;

however, a resolution is being considered for a future release.

Additional reference words: 3.10

KBCategory: kbprg kbprb

KBSubcategory: UsrMisc


PRB: Average & Maximum Char Widths Different for TT Fixed

PSS ID Number: Q92410

Authored 05-Nov-1992	Last modified 25-May-1995

---

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

---

SYMPTOMS

The tmAveCharWidth and tmMaxCharWidth fields of the TEXTMETRIC

structure are not equal for a fixed-pitch TrueType (TT) font such

as Courier New.

RESOLUTION

This is by TrueType design. The tmMaxCharWidth denotes the maximum

possible ink width of the font rather than maximum cell width of

the font.

MORE INFORMATION

TrueType fonts use ABC character spacing. The "A" width is the

distance that is added to the current position before placing the

TrueType glyph. The "B" width is the width of the black part (ink

width) of the TT glyph. The "C" width is the distance from the end of

the "B" width to the beginning of the next character. Advanced width

(cell width) is equal to A+B+C.

The physical TT fonts that are passed to drivers have just the "B"

part of the characters, so all fonts at the level of the driver appear

to be proportional width fonts. The tmMaxCharWidth is the least width

in which the "B" part of all characters will fit. The tmAveCharWidth

is the average advance width (A+B+C). For a fixed-pitch TT font such

as Courier New, the A+B+C width is the same for all characters;

however, the maximum width as defined above can be different.

tmMaxCharWidth is greater than tmAveCharWidth only if A+C is negative.

This is possible for a fixed-pitch font.

Please see section 18.2.4.1 of the Windows 3.1 SDK "Guide to

Programming" for more information about ABC character spacing.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg kbprb

KBSubcategory: GdiTt


PRB: Building SDK SNMP Samples Results in Unresolved

PSS ID Number: Q129240

Authored 23-Apr-1995	Last modified 24-Apr-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.5

SYMPTOMS

Building the SNMP samples in the Win32 SDK for Windows NT version 3.5

(TESTDLL.DLL or SNMPUTIL.EXE) using Visual C++ version 2.0 results in the

the linker complaining of unresolved externals _mb_cur_max_dll and

_pctype_dll.

CAUSE

The application was built to use the C run-time in a DLL. In the Win32 SDK,

the import library is CRTDLL.LIB, and in Visual C++, the import library is

MSVCRT.LIB. The "___mb_cur_max_dll" and "__pctype_dll" symbols are defined

in the CRTDLL.LIB file, but not in the MSVCRT.LIB file.

For more information, please see the following article in the Microsoft

Knowledge Base:

   ARTICLE-ID: Q119503

   TITLE     : PRB: Unresolved ___mb_cur_max_dll and __pctype_dll

RESOLUTION

Choose Settings from the Project menu. Then select C/C++, and go to the

Code Generation category. For the run-time library listed, use

Multithreaded using DLL.

Additional reference words: 3.50

KBCategory: kbnetwork kberrmsg kbprb

KBSubcategory: NtwkSnmp


PRB: Byte-Range File Locking Deadlock Condition

PSS ID Number: Q117223

Authored 22-Jun-1994	Last modified 19-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1 and 3.5

SYMPTOMS

It is possible for a thread in a multithreaded Win32-based application to

block while doing a LockFile() or LockFileEx() API call, even when the area

of memory the thread has requested is not locked by another thread.

NOTE: If performance-monitoring tools (such as PERFMON) are used to examine

the status of existing threads and the Thread State indicates that the

thread is waiting and the Thread Wait Reason shows that it is the executive

that the thread is waiting on, this is probably not an indication that a

deadlock has occurred, because threads are often in this state for other

reasons. Also, if the Thread State indicates that the thread is not

waiting, then a deadlock has probably not occurred.

CAUSE

There is a small window of time during which a multithreaded application is

vulnerable to this condition. Specifically, if one thread (call it Thread1)

is in the process of unlocking a currently locked byte range within a file

while a second thread (Thread2) is in the process of obtaining a lock on

that same byte range using the same file handle and without specifying the

flag LOCKFILE_FAIL_IMMEDIATELY, Thread1 can block, waiting for the region

to become available. Ordinarily, when unlocking takes place, blocked

threads are released; but in this critical window of time, it is possible

for Thread2 to unlock the byte range without Thread1 being released. Thus,

Thread1 never resumes operation despite the fact that there is no apparent

fault in the logic of the program.

RESOLUTION

The deadlock condition described above can only come about if multiple

threads are concurrently doing synchronous I/O using the same file handle.

To avoid the problem, you have three options:

 - Each thread can obtain its own handle to the file either through the use

   of the DuplicateHandle() API or through multiple calls to the

   CreateFile() API.

   -or-

 - The threads can perform asynchronous I/O. This also requires the

   application developer to provide some form of explicit synchronization

   to coordinate access to the file by the threads.

   -or-

 - The threads can specify LOCKFILE_FAIL_IMMEDIATELY and then loop until a

   retry succeeds if the lock request fails. This option is the least

   desirable because it incurs significant CPU use overhead.

REFERENCES

For more information about threads, files, and file handles, see the

following sections in the "Win32 SDK Programmer's Reference," volume 2,

part 3, "System Services":

 - Chapter 43.1.6, "Synchronizing Execution of Multiple Threads"

 - Chapter 45.2.2, "Reading, Writing, and Locking Files"

 - Chapter 48.3, "Kernel Objects"

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubCategory: BseMisc


PRB: C2371 BSTR Redefinition When VFW.H Included in MFC App

PSS ID Number: Q129953

Authored 08-May-1995	Last modified 16-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), version 3.5

 - Microsoft Visual C++, 32-bit Edition, versions 2.0 and 2.1

SYMPTOMS

The following error message occurs when compiling an application with

Microsoft Visual C++, version 2.0 or 2.1, which uses the Microsoft Video

for Windows header file, VFW.H, and the Microsoft Foundation Classes (MFC):

   c:\msvc20\include\oleauto.h(214) : error C2371: 'BSTR' : redefinition;

   different basic types

This error message does not occur when using Microsoft Visual C++ version

1.5 for Windows with the Microsoft Video for Windows 1.1 DK installed while

running under Microsoft Windows operating system

version 3.1.

RESOLUTION

If the application does not require binary string (BSTR) support you can

eliminate this error message by defining "_AFX_NO_BSTR_SUPPORT" before the

MFC include files. For example, place the code below at the beginning of

the STDAFX.H file:

   #define _AFX_NO_BSTR_SUPPORT

If the application does require BSTR support, then you can eliminate this

error message by including the code below before including the VFW.H file:

   #define OLE2ANSI

MORE INFORMATION

This error message occurs by design. MFC versions 3.0 and 3.1 require

either that "OLE2ANSI" is defined when including the object linking and

embedding (OLE) headers or that "_AFX_NO_BSTR_SUPPORT" is defined. You

cannot use both ANSI-BSTRs (which is the default) and Unicode-BSTRs; you

must use one or the other.

The AFX.H file defines the BSTR type in order to allow CStrings to support

BSTRs. The VFW.H file unconditionally includes the OLE2.H file, which

eventually includes the OLEAUTO.H file, which also defines the BSTR type.

"_AFX_NO_BSTR_SUPPORT" disables CString support for BSTRs.

Steps to Reproduce Problem

--------------------------

1. Generate a default application with AppWizard.

2. Add the statement "#include vfw.h" to the end of the STDAFX.H file.

3. Compile the application.

The VFW.H file is included with the Microsoft Visual C++, 32-bit Edition,

and the Microsoft Win32 SDK for Windows NT.

Additional reference words: 3.10 3.50 2.00 2.10 CString port porting VfWDK

KBCategory: kbmm kbprb kberrmsg

KBSubcategory: MMVIDEO


PRB: Calling LoadMenuIndirect() with Invalid Data Hangs

PSS ID Number: Q131281

Authored 07-Jun-1995	Last modified 10-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) version 4.0

SYMPTOMS

Under Windows 95 if you call LoadMenuIndirect() with invalid data, the

system hangs (stops responding).

CAUSE

Invalid data anywhere in the array of MENUITEMTEMPLATE structures passed to

the LoadMenuIndirect() function may cause this problem. An example of this

might be an extra NULL byte after a MENUITEMTEMPLATE structure.

Under Windows NT version 3.5, passing the same invalid data in the

MENUITEMTEMPLATE structure causes LoadMenuIndirect() to return NULL, with

GetLastError() reporting an ERROR_INVALID_DATA value.

STATUS

This behavior is by design.

Additional reference words: 4.00 freeze lock up Menus

KBCategory: kbprg kbprb

KBSubcategory: UsrMen


PRB: Can't Disable CTRL+ESC and ALT+TAB Under Windows NT

PSS ID Number: Q125614

Authored 31-Jan-1995	Last modified 11-Apr-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) version 3.5

SYMPTOMS

CTRL+ESC and ALT+TAB task switching cannot be disabled by an application

running under Windows NT.

Capturing WM_SYSCOMMAND messages and not sending them on for processing by

DefWindowProc() allowed task switching to be disabled in Windows version

3.1, but it doesn't work under Windows NT.

CAUSE

A primary reason for this change is to avoid dependence on an application

for processing of these key combinations. This way a hung application can

be switched away from by using either CTRL+ESC or ALT+TAB.

RESOLUTION

CTRL+ESC may disabled on a system-wide basis by replacing the NT Task

Manager. This is not recommended.

ALT+TAB and ALT+ESC may be disabled while a particular application is

running if that application registers hotkeys for those combinations with

Register HotKey().

STATUS

This behavior is by design.

REFERENCES

The first reference below describes the steps that must be taken to replace

TASKMAN.EXE. The two additional references provide more information on the

Windows NT Task Manager and its relationship to the Program Manager.

ARTICLE-ID:Q89373

TITLE     :Replacing the Windows NT Task Manager

ARTICLE-ID:Q100328

TITLE     :Replacing the Shell (Program Manager)

ARTICLE-ID:Q101659

TITLE     :How Windows NT, 16-Bit Windows 3.1 Task Managers Differ

Additional reference words: 3.50

KBCategory: kbusage kbprb

KBSubcategory: UsrMisc


PRB: Can't Increase Process Priority

PSS ID Number: Q110853

Authored 31-Jan-1994	Last modified 02-Mar-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

SYMPTOMS

--------

An attempt to increase process priority to the real-time priority

REALTIME_PRIORITY_CLASS may not set the PriorityClass to the expected

level.

CAUSE

-----

Only accounts with the "Increase Scheduling Priority" permission can

increase the priority to real-time. Only Administrators and "Power Users"

have this permission by default.

RESOLUTION

----------

Either run the program from an Administrator or Power User account, or

grant the Increase Scheduling Priority permission to any user group that

must run the program.

STATUS

------

This behavior is by design.

MORE INFORMATION

The Increase Scheduling Priority permission can be granted to a user or

group through the User Manager. To do this:

1. Open the Administrative Tools group in Program Manager.

2. Run the User Manager application.

3. Choose User Rights from the Policies menu.

4. Select the Show Advanced User Rights check box.

5. Select Increase Scheduling Priority from the drop-down list box.

6. Choose the Add button to add users or groups to the list of entities

   that have this right.

Note that the call to SetPriorityClass() may return success even though the

priority was not set to REALTIME_PRIORITY_CLASS, because if you don't have

the Increase Scheduling Priority permission, a request for

REALTIME_PRIORITY_CLASS is interpreted as a request for the highest

priority class allowed in the current account. If it is important to know

the actual priority class that was set, use the GetPriorityClass()

function.

Additional reference words: 3.10 3.50

KBCategory: kbprg kbprb

KBSubcategory: BseProcThrd


PRB: Can't Remove Minimize or Maximize Button from Caption

PSS ID Number: Q130760

Authored 25-May-1995	Last modified 22-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) version 4.0

SYMPTOMS

Under Windows 95, applications cannot create an overlapped or a popup

window that contains only the Minimize or the Maximize button.

CAUSE

This is by design. Windows can have both buttons or none depending on the

styles specified while creating the window, but specifying just one style

(either the WS_MAXIMZIEBOX or WS_MINIMIZEBOX) creates both buttons on the

caption, with the other one disabled.

STATUS

This behavior is by design.

MORE INFORMATION

Under Windows version 3.1 or Window NT, applications could remove either

the Maximize or Minimize buttons on the caption bar. (This was usually done

when the appliction removed a corresponding menu item from the system menu

of a window.)

Applications running under Windows 95 that try to remove one of the buttons

(not both), will not succeed. The system displays both buttons and disable

the one whose style was not specified during creation. This is by design,

and there is no way to work around it, unless the application draws its own

caption bar.

Applications that removed the maximize or minimize menu items under Windows

version 3.1, should just gray them out (disable them) under Windows 95 to

maintain a uniform user interface.

Under Windows 95, applications can create a window (overlapped or popup)

with just the Close button (the X button) by creating the window without

specifying the WS_MAXIMIZEBOX or WS_MINIMIZEBOX styles. Calling

SetWindowLong(GWL_STYLE) to change or remove the minimize of the maxmize

buttons dynamically still displays both buttons with one of them disabled.

Additional reference words: 4.00 user

KBCategory: kbprg kbui kbprb

KBSubcategory: UsrWndw


PRB: Can't Use TAB to Move from Standard Controls to Custom

PSS ID Number: Q131283

Authored 07-Jun-1995	Last modified 10-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) version 4.0

SYMPTOMS

As you attempt to customize the new Explorer-style File Open or Save As

common dialog, pressing the TAB key fails to move the focus from the

standard dialog's controls to the new controls specified in the custom

template.

CAUSE

The custom dialog box template failed to specify the DS_CONTROL style.

RESOLUTION

When creating a custom dialog box template to be used with the new FileOpen

or Save As common dialog, you must specify the DS_CONTROL style.

STATUS

This behavior is by design.

MORE INFORMATION

With the new way of customizing the File Open or Save As common dialog in

Windows 95, you can customize applications to provide a custom dialog box

template that adds controls to the default Open or Save As dialog box. This

custom dialog box is created as a child of the default dialog box and thus

requires a WS_CHILD style.

DS_CONTROL is a new style provided in Windows 95. It makes a modal dialog

created as a child of another dialog interact well with its parent dialog.

This style ensures that the user can move between the controls of the

parent dialog and the child dialog - or in this case between the standard

Open or Save As common dialog and the custom dialog provided by the

application.

NOTE: This article does not apply to Windows NT. This information applies

only to the new way of customizing the Explorer-style File Open or Save As

common dialog in Windows 95.

Additional reference words: 4.00

KBCategory: kbprg kbprb

KBSubcategory: UsrCmnDlg


PRB: Cannot Alter Messages with WH_KEYBOARD Hook

PSS ID Number: Q33690

Authored 29-Jul-1988	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SYMPTOMS

After creating a program that uses the WH_KEYBOARD hook function to

intercept a user's keystrokes and changing the wParam value before passing

the hook code on to DefHookProc(), whichever application currently has the

focus still receives the original character typed in rather than the

translated character.

CAUSE

Keyboard messages cannot be altered with the WH_KEYBOARD hook. All that can

be done is to "swallow" the message (return TRUE) or have the message

passed on (FALSE). In a keyboard hook function, when you return

DefHookProc(), you are passing the event to the next hook procedure in the

potential hook chain, and giving it a chance to look at the event to decide

whether or not to discard it. You are not passing the message to the system

as if you had called DefWindowProc() from a Window procedure.

RESOLUTION

NOTE: In the discussion below, ignore the references to the WH_CALLWNDPROC

hook for Win32-based applications. Win32 does not allow an application to

change the message in a CallWndProc, as 16-bit Windows does.

To change the value of wParam (and hence the character message that is

received by the window with the focus), you must install the WM_GETMESSAGE

and WH_CALLWNDPROC hooks. The WH_GETMESSAGE hook traps all messages

retrieved via GetMessage() or PeekMessage(). This is the way actual

keyboard events are received: the message is placed in the queue by Windows

and the application retrieves it via GetMessage() or PeekMessage().

However, because applications can send keyboard messages with

SendMessage(), it is best to also install the WH_CALLWNDPROC hook. This

hook traps messages sent to a window via SendMessage().

These hooks pass you the address of the message structure so you can change

it. In Windows 3.0, when you return DefHookProc() within a WH_GETMESSAGE or

WH_CALLWNDPROC hook procedure, you are passing the address of the

(potentially altered) contents of the message structure on to the next hook

function in the chain. In Windows 3.1, you should use the CallNextHookEx()

function to pass the hook information to the next hook function. If you

alter the wParam before passing on the message, this will change the

character message eventually received by the application with the focus.

NOTE: For Windows 3.0, keep in mind that the hook callback procedure must

be placed in a DLL with fixed code so that it will be below the EMS line

and thus will always be present. If the hook callback procedure is not in a

fixed code segment, it could be banked out when it is called, and this

would crash the system. System-wide hooks in Windows 3.1, however, must

still reside in a DLL.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg kbprb

KBSubcategory: UsrHks


PRB: CBS_SIMPLE ComboBox Repainting Problem

PSS ID Number: Q128110

Authored 27-Mar-1995	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK version 3.5

 - Microsoft Win32s version 1.2

SYMPTOMS

When a CBS_SIMPLE combo box has a WS_CLIPCHILDREN parent, the area below

the edit control and left to the list box is not repainted correctly. This

problem exists for 16-bit as well as 32-bit applications.

RESOLUTION

To work around this problem, subclass the combo box, calculate the blank

area, and then repaint to the desired color.

The following ComboBox subclass procedure is written for a 16-bit

application, but you can use the same idea in 32-bit applications.

Sample Code

-----------

LRESULT CALLBACK NewComboProc(

      HWND hWnd,

      UINT uMessage,

      WPARAM uParam,

      LPARAM lParam)

{

HDC myDC;

HPEN   hPen, hOldPen;

HBRUSH hBrush;

HBRUSH hOldBrush;

COLORREF myColor=RGB(255,255,255); //It can be any color. Here

               //the area is painted white.

HWND hEdit, hList;

RECT comboRect, editRect, listRect;

char   *wndClassName="Edit";

if (uMessage == WM_PAINT)

  {

  CallWindowProc(lpfnOldComboProc, hWnd, uMessage, uParam,

                 lParam);

  myDC = GetDC(hWnd);

  hBrush = CreateSolidBrush(myColor);

  hPen   = CreatePen (PS_SOLID, 1, myColor);

  hOldBrush = SelectObject(myDC, hBrush) ;

  hOldPen   = SelectObject(myDC, hPen);

  //This code obtains the handle to the edit control of the

  //combobox.

  hEdit = GetWindow(hWnd, GW_CHILD);

  GetClassName (hEdit, wndClassName, 10);

  if (!lstrcmp (wndClassName, "Edit"))

    hList=GetWindow(hEdit, GW_HWNDNEXT);

  else

    {

    hList=hEdit;

    hEdit=GetWindow(hList, GW_HWNDNEXT);

    }

  //The dimensions of the Edit Control, ListBox control and

  //the Combobox are  calculated and then used

  //as the base dimensions for the Rectangle() routine.

  GetClientRect (hWnd, &comboRect);

  GetClientRect (hEdit, &editRect);

  GetClientRect (hList, &listRect);

  Rectangle (myDC,

             comboRect.left,

             editRect.bottom,

             comboRect.right-listRect.right,

             comboRect.bottom);

  //Also paint the gap, if any exists, between the bottom

  //of the listbox and the bottom of the ComboBox rectangle.

  Rectangle (myDC,

             comboRect.right-listRect.right,

        editRect.bottom +

             listRect.bottom,

        comboRect.right,

        comboRect.bottom);

  DeleteObject(SelectObject(myDC, hOldBrush)) ;

  DeleteObject(SelectObject(myDC, hOldPen)) ;

  ReleaseDC(hWnd, myDC);

  return TRUE;

  }

return CallWindowProc(lpfnOldComboProc, hWnd, uMessage, uParam,

 lParam);

}

STATUS

This behavior is by design.

MORE INFORMAITON

Steps to Reproduce Behavior

---------------------------

To reproduce this behavior, use AppStudio to create a dialog with the

WS_CLIPCHILDREN style, put a CBS_SIMPLE combobox in the dialog, and click

the test button so you can test the dialog. Then move something on top of

the dialog, and move the object on top of the combobox away. You can then

see that area to the left of the listbox is not repainted correctly.

Additional reference words: 3.10 3.50 1.20

KBCategory: kbprg kbcode kbprb

KBSubcategory: UsrCtl


PRB: CBT_CREATEWND Struct Returns Invalid Class Name

PSS ID Number: Q106079

Authored 31-Oct-1993	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

The CBT_CREATEWND structure contains information passed to a WH_CBT

hook callback function before a window is created in the system. The

lpszClass field of this CBT_CREATEWND structure may return an invalid

class name, particularly for windows created internally by the system.

SYMPTOMS

The code to get to the window class name via the CBT_CREATEWND

structure in a CBT callback function may look like the following:

   int FAR PASCAL CBTProc (int nCode, WPARAM wParam, LPARAM lParam)

    {

         LPCBT_CREATEWND  CreateWndParam;

           if (nCode >= 0)

           {

                switch (nCode)

                {

                   case HCBT_CREATWND:

                        CreateWndParam = (LPCBT_CREATEWND)lParam;

                        OutputDebugString ("ClassName = ");

                        OutputDebugString (lParam->lpcs->lpszClass);

                        OutputDebugString ("\r\n");

                        break;

                     :

                     :

                }

           }

           return (int)CallNextHookEx (hHook, nCode, wParam, lParam);

    }

However, this code may or may not output the correct class name,

depending on what the call to CreateWindow() (for the window about to

be created) looks like.

RESOLUTION

Windows provides the GetClassName() function to allow applications to

retrieve a window's class name. This function takes the handle to the

window as a parameter, as well as a buffer to receive the

null-terminated class name string. This function is a more reliable

and a more recommended means to obtain window class name information

than the CBT callback function's CBT_CREATEWND structure.

MORE INFORMATION

Whenever a window is about to be created, Windows checks to see if a

WH_CBT hook is installed anywhere in the system. If it finds one, it

calls the CBTProc() callback function with hook code set to

HCBT_CREATEWND, and with the lParam parameter containing a long

pointer to a CBT_CREATEWND structure.

The CBT_CREATEWND structure is defined in WINDOWS.H as follows

   typedef struct tagCBT_CREATEWND {

       CREATESTRUCT FAR* lpcs;

       HWND hwndInsertAfter;

   } CBT_CREATEWND;

with the CREATESTRUCT structure defined in the same file as:

   typedef struct tagCREATESTRUCT {

      void FAR* lpCreateParams;

         :

      LPCSTR  lpszClass;    // Null-terminated string specifying window

                            // class name

      DWORD  dwExStyle;

   } CREATESTRUCT;

When Windows internally creates windows (such as predefined controls

in a dialog box, for example), it uses atoms for lpszClass instead of

the actual string to minimize overhead. This makes it a little less

straightforward (sometimes impossible) to get to the actual class name

directly from the lpszClass field of the CREATESTRUCT structure.

To cite one particular example, when an application is minimized in

Windows, Windows calls CreateWindow() for the icon title, specifying a

class name of

   (LPSTR)MAKEINTATOM (ICONTITLECLASS == 0x8004)

where MAKEINTATOM() is defined in WINDOWS.H as:

   #define MAKEINTATOM (i)    ((LPCSTR) MAKELP (NULL, i))

Given this, to get to the actual class name, GetAtomName() must be

called in this manner:

   char szBuf [10];

   GetAtomName (LOWORD (lpszClass), szBuf, 10);

   OutputDebugString (szBuf);

This outputs a class name of #32772 for the IconTitleClass.

For predefined controls, such as "static", "button", and so forth, in

a dialog box, the Dialog Manager calls CreateWindow() on each control,

similarly using atoms for lpszClass. The Dialog Manager, however,

creates these atoms in a local atom table in USER's default data

segment (DS), thus making it impossible for other applications to get

to these class names.

[Note the difference between local and global atom tables, where

global atom tables are stored in a shared DS, and are therefore

accessible to all applications, while local atom tables are stored in

USER's default DS. DDE uses global atom tables so that Excel, for

example, can use GlobalAddAtom() to add a string to the atom table,

and another program could use GlobalGetAtomName() to obtain the

character string for that atom.]

More information on atoms can be found by searching on the following

word in the Microsoft Knowledge Base:

   atoms

More Information can also be found in the Windows version 3.1 online

Help file under the heading Function Groups, under the Atom Functions

subheading.

Additional reference words: 3.10 3.50 3.51 4.00 95

KBCategory: kbprg kbprb kbcode

KBSubcategory: UsrHks


PRB: CFileDialog::DoModal() Does Not Display FileOpen Dialog

PSS ID Number: Q131225

Authored 06-Jun-1995	Last modified 07-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) version 4.0

SYMPTOMS

Calling CFileDialog::DoModal() returns without displaying the FileOpen

common dialog.

CAUSE

The CFileDialog class will automatically use the new Explorer-style

FileOpen common dialog under Windows 95. This can break existing code which

customizes these dialogs with custom templates, because the mechanism has

changed in Windows 95.

NOTE: This does not apply to Windows NT 3.51, as this version of Windows NT

will not display the new Explorer-style dialog.

RESOLUTION

An application that depends on the old behavior of customizing the File

Open common dialogs will need to reset the OFN_EXPLORER bit in the Flags

member of the OPENFILENAME structure before calling CFileDialog::DoModal.

MORE INFORMATION

The DIRPKR sample in particular, exhibits the symptoms described above, and

will need to be modified to display the dialog box correctly in Windows 95.

It works as is under Windows NT 3.51.

Sample Code

-----------

    CMyFileDlg  cfdlg(FALSE, NULL, NULL, OFN_SHOWHELP | OFN_HIDEREADONLY |

                      OFN_OVERWRITEPROMPT | OFN_ENABLETEMPLATE,

                      NULL, m_pMainWnd);

    cfdlg.m_ofn.hInstance      = AfxGetInstanceHandle();

    cfdlg.m_ofn.lpTemplateName = MAKEINTRESOURCE(FILEOPENORD);

    cfdlg.m_ofn.Flags         &= ~OFN_EXPLORER;

    if (IDOK==cfdlg.DoModal())

    {

      :

      :

    }

REFERENCES

This information was derived from Visual C++ 2.1 Technical Note 52:

"Writing Windows 95 Applications with MFC 3.1"

Additional reference words: 2.10 4.00

KBCategory: kbprg

KBSubcategory: UsrCmnDlg


PRB: COMM (TTY) Sample Does Not Work on Windows 95

PSS ID Number: Q128787

Authored 10-Apr-1995	Last modified 11-Apr-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) version 4.0

SYMPTOMS

The Win32 COMM (old TTY) sample that ships with Visual C++ version 2.x and

the Windows 95 SDK (pre-release) does not work correctly under Windows 95

M8 builds and later. The problem involves assigning values to the Offset

member of the OVERLAPPED structure which is one of the arguments to the

WriteFile function call.

The observed behavior is that the COMM sample writes only one byte to the

serial port. No other data is transmitted after the first byte.

CAUSE

The documentation for the OVERLAPPED structure explicitly states that the

Offset and OffsetHigh members must be set to 0 when reading from or writing

to a named pipe or communications device. This was not done in the sample.

RESOLUTION

1. Delete the following line from the WriteCommByte() function in the

   sample:

   WRITE_OS( npTTYInfo ).Offset += dwBytesWritten ;

2. Add the following lines to the CreateTTYInfo() function:

   WRITE_OS( npTTYInfo ).Offset = 0 ;

   WRITE_OS( npTTYInfo ).OffsetHigh = 0 ;

STATUS

This is a problem with the sample, not with Windows 95. Windows 95

correctly implements WriteFile() and use of the OVERLAPPED structure.

Additional reference words: 4.00

KBCategory: kbprg kbprb

KBSubcategory: BseComm


PRB: Controls Do Not Receive Expected Messages

PSS ID Number: Q121094

Authored 26-Sep-1994	Last modified 28-Nov-1994

The information in this article applies to:

 - Microsoft Win32s, versions 1.1, 1.15, and 1.2

SYMPTOMS

A Win32-based application works as expected under Windows NT, but under

Win32s, control messages are not received by the application as expected.

Here are some possible scenarios symptomatic of this problem:

 - Sending LB_GETSELITEMS to a superclassed list box does not work.

 - The custom control procedure does not receive messages such as

   CB_ADDSTRING, CB_INSERTSTRING, or CB_SHOWDROPDOWN.

 - The wrong control message is received.

CAUSE

This is a Win32s limitation. When a Win32-based application sends a

message, Win32s processes the message and passes it to Windows. Windows is

responsible for delivering the message. Win32s truncates wParam from a

DWORD to a WORD. Most messages do not use the high word of wParam, however,

if you do use the high word of wParam, be aware that it will be lost under

Win32s.

In the course of processing known messages (messages that are not user-

defined), Win32s translates any pointers in lParam. In addition, if a

message is new to Win32, the corresponding Windows message is used instead.

For example, the Windows WM_CTLCOLOR was replaced in Win32 with

WM_CTLCOLORBTN, WM_CTRLCOLORDLG, WM_CTLCOLOREDIT, and so on. Therefore, if

a Win32-based application uses WM_CTRLCOLORBTN, Win32s passes WM_CTLCOLOR

to Windows with a type of CTLCOLOR_BTN.

Control messages are not unique on Windows version 3.1 as they are on

Windows NT. Control messages on Windows have values above WM_USER, however,

messages for one control may share the same number as a message of another

control. For example, both CB_ADDSTRING and LB_DELETESTRING are defined as

WM_USER+3. Therefore, when Win32s receives the WM_USER+3 message, it needs

to determine the correct control message. Win32s looks at the window class

of the window that will receive the message and maps the message

accordingly. If the window class is not a recognized control class, as in

the case of a superclassed control, the message is not mapped, which

results in unexpected behavior.

RESOLUTION

In order to get the desired behavior under Win32s, make the custom control

use a recognized control class (such as "combobox") and subclass the window

procedure instead of superclassing. If you need to subclass before the

WM_CREATE/WM_NCCREATE messages, use a CBT hook. You will not be able to

change the class icon and cursor, but the messages will be handled

correctly.

If you need to use a custom control, create and use user-defined messages

instead of the control messages.

STATUS

This behavior is by design.

Additional reference words: 1.10 1.15 1.20

KBCategory: kbprg kbprb

KBSubCategory: W32s


PRB: Corruption of the Perflib Registry Values

PSS ID Number: Q128404

Authored 02-Apr-1995	Last modified 11-Apr-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   version 3.5

SYMPTOMS

The Performance Monitoring tool can be affected by a corruption problem in

the Perflib key. The following symptoms are evidence of this corruption

problem:

 - The explain text is not displayed.

   -or-

 - The objects and counters are not displayed.

   -or-

 - The explain text, objects, and counters are not displayed.

CAUSE

When an .INI file, which contains an extra language entry not associated

with any specific objects and counters, is passed as a parameter to

LODCTR.EXE, the values of 'Last Counter' and 'Last Help' are set to zero.

This in turn causes the Performance Monitoring tool to fail.

The following is an example of a problem-causing .INI file:

     [info]

     drivername=SampPerf

     symbolfile=sampperf.h

     [languages]

     009=English

     011=OtherLanguage  <-- problem area

     [text]

     SampObj_009_Name=SampPerf

     SampObj_009_Help=A sample performance object.

     Count_1_009_Name=Tests/sec

     Count_1_009_Help=The number of tests completed.

A further complication arises when a user attempts to rectify the situation

by executing UNLODCTR.EXE. At this point, because Last Counter and Last

Help are set to zero, UNLODCTR.EXE only resets '\009\HELP' and

'\009\COUNTER' to NULL.

RESOLUTION

To resolve this corruption problem, you must restore the Registry to its

former state by using one of the following five methods:

 - Backup and restore the local copy of the Registry by using Windows NT

   Backup.

   -or-

 - Copy and restore the data located in the %WINNT%\SYSTEM32\CONFIG

   directory. This can be done only if Windows NT was installed on a FAT

   partition.

   -or-

 - Save and restore the SOFTWARE registry hive.

   -or-

 - Save and restore the Registry values First Counter, First Help, Last

   Counter, and Last Help.

   -or-

 - Save and restore the Registry by using REGBACK.EXE and REGREST.EXE. Both

   programs are available with the Windows NT Resource Kit (RESKIT).

If the user ran UNLODCTR.EXE to attempt to fix the problem, you will also

need to restore \009\HELP and \009\COUNTER, which you can do by simply

rebooting the computer running Windows NT.

WARNING: The Registry is a vital part of Windows NT; improper modification

of its keys and values can cause Windows NT to malfunction.

Additional reference words: 3.50

KBCategory: kbprg kbprb

KBSubcategory: BseMisc


PRB: CreateEllipticRgn() and Ellipse() Shapes Not Identical

PSS ID Number: Q83807

Authored 20-Apr-1992	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SYMPTOMS

When CreateEllipticRgn() is used to create a region in the shape of an

ellipse and Ellipse() is called with the same parameters to draw an ellipse

on the screen, the calculated region does not match the drawn ellipse

identically.

CAUSE

Ellipse() includes the lower-right point of the bounding rectangle in its

calculations, while the CreateEllipticRgn function excludes the lower-right

point.

RESOLUTION

To draw a filled ellipse on the screen that matches an elliptic region,

create the region with CreateEllipticRgn() and call FillRgn() to fill the

region with the currently selected brush.

MORE INFORMATION

The region created by the CreateEllipticRgn() is slightly smaller than

the elliptical area created by Ellipse(). Unfortunately, decreasing the

width and height of the bounding rectangle by 1 pixel does not solve

the problem. Although changing the parameters of the Ellipse() API

in this way produces a smaller ellipse, the new ellipse does not match

the region created with CreateEllipticRgn().

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg kbprb

KBSubcategory: GdiDrw


PRB: CreateFile Fails on Win32s w/ UNC Name of Local Machine

PSS ID Number: Q129543

Authored 27-Apr-1995	Last modified 29-Apr-1995

The information in this article applies to:

 - Microsoft Win32s version 1.2

SYMPTOMS

CreateFile() fails on Win32s if the file name is a UNC name that refers to

the local machine.

CAUSE

This is a limitation of Windows for Workgroups version 3.11. The same

problem occurs with 16-bit Windows-based applications using OpenFile().

RESOLUTION

Do not use a UNC name to open a file on the local machine.

STATUS

This behavior is by design.

MORE INFORMATION

There is a similar limitation with Windows version 3.1 and LAN Manager. If

you create a network drive and try to open a file on the same network share

using a UNC name, it will fail. This also happens with 16-bit

Windows-based applications.

Additional reference words: 1.20

KBCategory: kbprg kbprb

KBSubcategory: W32s


PRB: CreateFile() Does Not Handle OEM Chars as Expected

PSS ID Number: Q129544

Authored 27-Apr-1995	Last modified 06-Jun-1995

The information in this article applies to:

 - Microsoft Win32s, versions 1.2 and 1.25a

SYMPTOMS

When CreateFile() is passed a filename string that contains an OEM

character, the name of the file created is not as expected. In particular,

a file created with CreateFile() cannot be opened with OpenFile() when

OpenFile() is passed the same filename string.

For example, suppose that the ANSI filename string contains a lower-case e

accent character (0x0e9). The file created by CreateFile() contains an

upper-case E and the file created by OpenFile() contains an upper-case E

accent character.

CAUSE

CreateFile() is implemented with calls to MS-DOS. MS-DOS converts the given

file names to upper-case letters. OpenFile() is implemented with a thunk to

the 16-bit Windows OpenFile(). OpenFile() converts the file name to

upper-case before calling MS-DOS. The conversion that the 16-bit OpenFile()

is doing is different from the conversion performed by MS-DOS for the OEM

characters. The result is that different filenames are created for the same

string passed to CreateFile() and OpenFile() if the name contains OEM

characters.

RESOLUTION

To make the file name created by CreateFile() consistent with the file name

created by OpenFile(), call AnsiUpper() on the file name string before

calling CreateFile().

STATUS

This behavior is by design. This will not be changed in Win32s now, because

it may break existing Win32-based applications.

MORE INFORMATION

The 16-bit OpenFile() will fail to find an existing file if the file

contains OEM characters but not an explicit full path. This also occurs

with the 32-bit OpenFile(), because it is thunked to the 16-bit OpenFile().

SearchFile() will also fail to find files if the file name contains OEM

characters or if the search path (lpszpath != NULL) contains OEM

characters.

NOTE: In 16-bit Windows and Win32s 1.2 and earlier, OpenFile() returns the

filename in OEM characters. However, the Win32 API documentation states

that OpenFile() should return an ANSI string. Starting with the next

version of Win32s, OpenFile() will return an ANSI string, as it does under

Windows NT.

Additional reference words: 1.20

KBCategory: kbprg kbprb

KBSubcategory: W32s


PRB: CreateProcess() of Windows-Based Application Fails

PSS ID Number: Q127860

Authored 19-Mar-1995	Last modified 21-Mar-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), version 3.5

SYMPTOMS

When you spawn a 16-bit Windows-based application using CreateProcess()

where neither lpApplicationName and lpCommandLine are NULL, WOW gives a

popup saying:

   Cannot find file (or one of its components). Check to ensure the path

   and filename are correct and that all required libraries are available.

CAUSE

NTVDM expects the first token in the command line (lpCommandLine) to be the

program name, although the Win32 subsystem does not. The current design

will not be changed.

RESOLUTION

Make lpApplicationName NULL and put the full command line in lpCommandLine.

STATUS

This behavior is by design.

MORE INFORMATION

The documentation for CreateProcess() states:

   If the process to be created is an MS-DOS-based or Windows-based

   application, lpCommandLine should be a full command line in which

   the first element is the application name.

In this case (lpApplicationName is not NULL), lpCommandLine not only

should be a full command line, but it must be a full command line.

Additional reference words: 3.50

KBCategory: kbprg kbprb

KBSubcategory: BseProcThrd


PRB: Data Section Names Limited to Eight Characters

PSS ID Number: Q100292

Authored 17-Jun-1993	Last modified 18-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   versions 3.1 and 3.5

SYMPTOMS

Data sections can be named by using #pragma data_seg. This method is

commonly used so that the named data sections can be shared using the

SECTIONS statement in the DEF file. However, if the length of the name

specified in the pragma exceeds eight characters, then the section is not

properly shared.

CAUSE

The linker does not support sections with longer names. The longer names

require use of the COFF strings table, so the rewrite is not trivial.

MORE INFORMATION

Note that in addition, the first character of a section name must be a

period. Therefore, the section name, as specified in both the pragma and

the DEF file, can be a maximum of a period followed by seven characters.

For more information on the shared named-data section, please see the

following article in the Microsoft Knowledge Base:

   ARTICLE-ID: Q89817

   TITLE     : How to Specify Shared and Nonshared Data in a DLL

Additional reference words: 3.10 3.50

KBCategory: kbtool kbprb

KBSubcategory: TlsMisc


PRB: DDEML Fails to Call TranslateMessage() in its Modal Loop

PSS ID Number: Q102576

Authored 04-Aug-1993	Last modified 18-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

During a synchronous transaction, DDEML causes the client to enter a

modal loop until the transaction is processed. While DDEML dispatches

messages appropriately, it fails to call TranslateMessage() while

inside this modal loop. This problem does not apply to asynchronous

transactions, where no such modal loop is entered.

SYMPTOMS

A common symptom of this problem is seen as the client processes user

input while inside DDEML's modal loop in a synchronous transaction.

WM_KEYDOWN and WM_KEYUP messages are received, with no corresponding

WM_CHAR message for the typed character.

CAUSE

No WM_CHAR message is received because the WM_KEYDOWN message is never

translated. For this to take place, a call to TranslateMessage() must

be made inside the modal loop.

RESOLUTION

This limitation is by design. DDEML applications can work around this

limitation by installing a WH_MSGFILTER hook, watching out for code ==

MSGF_DDEMGR.

The WH_MSGFILTER hook allows an application to filter messages while

the system enters a modal loop, such as when a modal dialog box (code

similarly, when DDEML enters a modal loop in a synchronous transaction

(code == MSGF_DDEMGR).

The Windows 3.1 Software Development Kit (SDK) DDEML\CLIENT sample

demonstrates how to do this in DDEML.C's MyMsgFilterProc() function:

/**********************************************************************

 *

 *  FUNCTION: MyMsgFilterProc

 *

 *  PURPOSE:  This filter proc gets called for each message we handle.

 *            This allows our application to properly dispatch messages

 *            that we might not otherwise see because of DDEMLs modal

 *            loop that is used while processing synchronous transactions.

 *

***********************************************************************/

   DWORD FAR PASCAL MyMsgFilterProc( int nCode, WORD wParam,

                DWORD lParam)

   {

       wParam; // not used

    #define lpmsg ((LPMSG)lParam)

    if (nCode == MSGF_DDEMGR) {

           /* If a keyboard message is for the MDI, let the MDI client

            * take care of it. Otherwise, check to see if it's a normal

            * accelerator key. Otherwise, just handle the message as usual.

            */

           if ( !TranslateMDISysAccel (hwndMDIClient, lpmsg) &&

                !TranslateAccelerator (hwndFrame, hAccel, lpmsg)){

               TranslateMessage (lpmsg);

               DispatchMessage (lpmsg);

           }

           return(1);

       }

       return(0);

   #undef lpmsg

   }

Additional reference words: 3.10 3.50 3.51 4.00 95

KBCategory: kbprg kbprb kbcode

KBSubcategory: UsrDde


PRB: DDEML with Excel Error: Remote Data Not Accessible

PSS ID Number: Q95982

Authored 03-Mar-1993	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SYMPTOMS

When data is linked between a Microsoft Excel spreadsheet and a DDEML

server application, with both applications open, the following error

message may appear:

   Remote data not accessible; start application <SERVER FILENAME>.EXE?

CAUSE

Excel broadcasts an initiate to all windows, for every service/topic name

pair it finds, in an attempt to initiate a conversation with the server

application. (This can be easily verified by running DDESPY and watching

Excel broadcast its initiates.) If Excel can't get a response, or gets a

NACK (negative ACK), Excel attempts to EXEC() a new instance of the server

application.

RESOLUTION

A DDEML server application should return TRUE, in response to the

XTYP_CONNECT transaction it receives, for every service/topic name pair it

supports. Refer to page 518 of the Microsoft Windows Software Development

Kit (SDK) version 3.1 "Programmer's Reference, Volume 3: Messages,

Structures, and Functions" for more information on the XTYP_CONNECT

transaction.

MORE INFORMATION

The DDEML server application responds to Excel's initiate by sending the

XTYP_CONNECT transaction to the DDE callback function of each server

application, passing the service and topic names to the server.

If the server application fails to return TRUE to the service/topic name it

supports, Excel concludes that it is trying to initiate a DDE link to an

application that is not available, and brings up the message box above,

thus giving the user an option to start the application.

Additional reference words:  3.50 3.51 4.00 95

KBCategory: kbprg kbprb

KBSubcategory: UsrDde


PRB: DDESpy Track Conversations Strings Window Empty

PSS ID Number: Q88197

Authored 19-Aug-1992	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SYMPTOMS

In the DDESpy application, provided with version 3.1 of the

Microsoft Windows Software Development Kit (SDK), DDE messages

appear in the main window, while the Track Conversation Strings

window remains empty.

CAUSE

Either the DDESpy application was started after the client and

server applications, or neither application uses functions in the

Dynamic Data Exchange Management Library (DDEML) to conduct DDE.

RESOLUTION

Start the DDESpy application before starting the client and server

applications. Make sure that the client or the server (or both)

uses the DDEML.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbtool kbprg kbprb

KBSubcategory: TlsSpy


PRB: Debugging an Application Driven by MS-TEST

PSS ID Number: Q100957

Authored 01-Jul-1993	Last modified 26-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SYMPTOMS

When an application driven by MS-TEST is being debugged by WinDbg or NTSD

(for example, after an exception has occurred), both the application and

the debugger hang.

CAUSE

The debugger is hooked and ends up hanging.

RESOLUTION

It is not possible to use NTSD or WinDbg to debug an application that is

driven by MS-TEST. Use Dr. Watson (drwtsn32) instead. Note that you must

turn off Visual Notification.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbtool kbprb

KBSubcategory: TlsWindbg


PRB: Debugging the Open Common Dialog Box in WinDbg

PSS ID Number: Q99952

Authored 10-Jun-1993	Last modified 26-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SYMPTOMS

When debugging an application that uses the Open common dialog box (created

by the GetOpenFileName() function) in WinDbg, the program stops and the

following information is displayed in the Command window:

   Thread Terminate: Process=0, Thread=2, Exit Code=1

CAUSE

The Open common dialog box causes a thread to be created. At this point in

the debugging, that thread has terminated. By default, WinDbg halts

whenever a thread terminates.

RESOLUTION

Execute the go command (type "g" at the command prompt). Execution will

continue.

MORE INFORMATION

To prevent WinDbg from halting when a thread is terminated, select Debug

from the Options menu and check "Go on thread terminate."

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbtool kbprb

KBSubcategory: TlsWindbg


PRB: Description for Event ID Could Not Be Found

PSS ID Number: Q129003

Authored 17-Apr-1995	Last modified 18-Apr-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.5

 - Microsoft Visual C++, 32-bit Edition, version 2.0

SYMPTOMS

After building and executing the Win32 LOGGING sample that accompanies

Visual C++ version 2.0 and the Microsoft Developer's Network Library CD,

you find that the descriptions for the logged events contain the following:

   The Description for Event ID (#) in Source (application name) could not

   be found. It contains the following string(s):

CAUSE

The resource file containing the descritions that correspond to the Event

IDs are not bound to the MESSAGES.DLL.

RESOLUTION

Add the MESSAGES.RC file to the Visual C++ version 2.0 project:

1. Run MAKEMC.BAT first. MAKEMC.BAT creates the MSG00001.BIN, MESSAGES.RC,

   and MESSAGES.H files.

2. Open Visual C++ version 2.0 and add MESSAGES.RC to the MESSAGES project

   (MESSAGES.MAK).

3. Rebuild both the MESSAGES and the LOG projects.

NOTE: If you ran the sample a couple of times from different places, you

may need to delete the LOG registry key if it contains an incorrect

location for the MESSAGES.DLL file.

Additional reference words: 3.50 3.51 Event Logging Log MSDN

KBCategory: kbprg kbprb

KBSubcategory: BseMisc


PRB: Device and TrueType Fonts Rotate Inconsistently

PSS ID Number: Q82932

Authored 01-Apr-1992	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SYMPTOMS

In an application for the Microsoft Windows graphical environment

that uses a mapping mode other than MM_TEXT and a text alignment

other than the default (TA_LEFT, TA_TOP), device fonts and TrueType

fonts rotate in the opposite directions. Device fonts may exhibit

other unusual behaviors. Differences in rotated text may appear on

the screen or in printed output.

RESOLUTION

To create a font that rotates based on the coordinate system in

which the font is used, the application must set the CLIP_LH_ANGLES

(0x10) bit in the lfClipPrecision field of the LOGFONT data

structure. This technique is backward-compatible with Windows 3.0

because the CLIP_LH_ANGLES bit is ignored in version 3.0.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg kbprb

KBSubcategory: GdiTt


PRB: Dialog Box and Parent Window Disabled

PSS ID Number: Q11337

Authored 01-Dec-1987	Last modified 18-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.1 and 3.0

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SYMPTOMS

When an application uses one of the DialogBox family of functions

to create a modal dialog box, both the parent window and the dialog

box are disabled (unable to accept keyboard or mouse input).

CAUSE

In the application's resource file, the dialog box resource has the

WS_CHILD style.

RESOLUTION

To avoid this problem, use the WS_POPUP style instead of the

WS_CHILD style.

MORE INFORMATION

When an application creates a modal dialog box using one of the

DialogBox family of functions, Windows disables the dialog box's

parent window. If the parent window has any child windows, the child

windows are also disabled.

An application can use the WS_CHILD style for dialog boxes created by

one of the CreateDialog family of functions. However, problems and

inconsistencies arise if the application uses the IsDialogMessage

function to process dialog box input for either the parent or the

child.

Additional reference words: 3.00 3.10  3.50 3.51 4.00 95

CreateDialogIndirect CreateDialogIndirectParam CreateDialogParam

DialogBoxIndirect DialogBoxIndirectParam DialogBoxParam

KBCategory: kbprg kbprb

KBSubcategory: UsrDlgs


PRB: Dialog Editor Does Not Modify RC File Dialog Box

PSS ID Number: Q32019

Authored 22-Jun-1988	Last modified 22-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

 - Microsoft Win32 SDK, versions 3.1 and 3.5

SYMPTOMS

If the Windows Dialog Editor (DIALOG.EXE) is used to edit a dialog

box, when the associated application is built, the previous version

of the dialog box is used.

CAUSE

The dialog resource used by the program is stored in the

application's resource file (which has the extension RC). The

Dialog Editor stores the updated dialog box resource in a file with

the .DLG extension.

RESOLUTION

Modify the resource file to use the RCINCLUDE statement to include

the updated dialog box resource, as follows:

   RCINCLUDE DIALOG.DLG

MORE INFORMATION

Suppose an application is written that uses a dialog box. The

developer creates a dialog box template manually in the application's

resource file. After building the application, the developer decides

to modify the dialog box using the Dialog Editor.

When the Dialog Editor edits an existing dialog box, it reads the

application's compiled resources stored in a compiled resource file

(with the extension .RES). However, when the developer saves any

changes, the Dialog Editor creates a file with the .DLG extension.

When the application is built for a second time, the Resource Compiler

uses the original definition for the dialog box stored in the resource

file. The resolution provided above avoids this problem because the

Resource Compiler always includes the latest version of the dialog box

template.

For more information about this topic, please see the following article in

the Microsoft Knowledge Base:

   ARTICLE-ID: Q40958

   TITLE     : PRB: DIALOG.EXE Reads Compiled .RES Files, Not .DLG Files

Additional reference words: 3.00 3.10 3.50

KBCategory: kbtool kbprg kbprb

KBSubcategory: TlsDlg


PRB: Dialog Editor Does Not Retain Unsupported Styles

PSS ID Number: Q74264

Authored 15-Jul-1991	Last modified 24-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit for Windows

   versions 3.1 and 3.0

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SYMPTOMS

The Windows Dialog Editor does not retain control/dialog styles that it

does not support.

RESOLUTION

The styles in question must be manually added to the dialog script before

using the resource compiler to compile the resource script.

MORE INFORMATION

Any style that cannot be explicitly set in the Dialog Editor Styles dialog

box will not be present in the script file generated by the the Dialog

Editor. For example, the edit control style, ES_OEMCONVERT is not available

in the Dialog Editor Styles dialog box. If this style is manually added to

the dialog script, compiled, and then loaded into the Dialog Editor, the

ES_OEMCONVERT style will be removed.

Any styles that are not supported by the Dialog Editor must be manually

added to the dialog script. To modify the dialog script, use a text editor

to combine the desired styles using the bitwise OR operator("|"). This

modified script should then be included into the application's resource

script. If the application's .RES file is later loaded into the Dialog

Editor, the unsupported styles will be removed and will need to be added

again as described above.

The following is a list of styles that are known not to be supported by the

Dialog Editor:

Style

-----

CBS_OEMCONVERT

ES_OEMCONVERT

SBS_BOTTOMALIGN

SBS_LEFTALIGN

SBS_RIGHTALIGN

SBS_SIZEBOX

SBS_SIZEBOXBOTTOMRIGHTALIGN

SBS_SIZEBOXTOPLEFTALIGN

SBS_TOPALIGN

SS_LEFTNOWORDWRAP

SS_NOPREFIX

SS_USERITEM

In addition to the above control styles, any menu definitions added to

the dialog script via the MENU resource statement will be deleted by

the Dialog Editor.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbtool kbprb

KBSubcategory: TlsDlg


PRB: DIALOG.EXE Reads Compiled .RES Files, Not .DLG Files

PSS ID Number: Q40958

Authored 07-Feb-1989	Last modified 22-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

 - Microsoft Win32 SDK, versions 3.1 and 3.5

SYMPTOMS

Create a dialog box using DIALOG.EXE, the Dialog Editor. From

MS-DOS, change an attribute (for example, position of control) of

the dialog box by modifying the .DLG file produced by DIALOG.EXE.

Invoke DIALOG.EXE again, the changes that were made are not

evident.

CAUSE

The Dialog Editor produces .DLG and .RES files for the dialog box

created. When using the Dialog Editor to modify an existing dialog

box, the Dialog Editor will look at the .RES file for information

about the makeup of the dialog box. The .DLG file is completely

ignored at this point. This is why the Dialog Editor does not

recognize any .DLG changes.

RESOLUTION

For the modifications to be recognized, the Resource Compiler (RC)

must be used with the -r switch to compile the .DLG file. The new

.RES file can then be loaded into the Dialog Editor and the changes

will be recognized.

Additional reference words: 3.00 3.10 3.50

KBCategory: kbtool kbprg kbprb

KBSubcategory: TlsDlg


PRB: DialogBox() Call w/ Desktop Window Handle Disables Mouse

PSS ID Number: Q129597

Authored 30-Apr-1995	Last modified 01-May-1995

The information in this article applies to:

 - Microsoft Win32s, version 1.2

SYMPTOMS

Under Windows NT and Windows 95, you can call DialogBox() using the return

from GetDesktopWindow() as the parent window handle. However, doing the

same thing under Win32s will disable the mouse. Clicking any mouse button

results in a beep, and you must reboot the computer to enable the mouse

again.

CAUSE

This is a bug in Windows, not Win32s. The same thing occurs from a 16-bit

Windows-based application. Internally, Windows disables the parent window

by calling EnableWindow(hwndParent, FALSE). If the handle is the desktop

window handle, the desktop window is disabled. This disables the mouse as

well, due to the bug in the Windows code.

RESOLUTION

Do not call DialogBox() with the desktop window handle as the parent window

handle.

Additional reference words: 1.20 HWND_DESKTOP

KBCategory: kprg kbprb

KBSubcategory: W32s


PRB: Display Problems with Win32s and the S3 Driver

PSS ID Number: Q117153

Authored 21-Jun-1994	Last modified 04-Apr-1995

The information in this article applies to:

 - Microsoft Win32s versions 1.1, 1.15, and 1.2

SYMPTOMS

Applications running on Windows 3.1 exhibit no problems when using an S3

driver, with a resolution of 1024x768 and 256 colors. However, the display

is corrupted when Win32-based applications, such as FreeCell, run on Win32s

in the same configuration.

CAUSE

This is a known problem with the S3 driver.

A general protection (GP) fault occurs when the display driver is

performing a bit-block transfer (BitBlt). This happens whether or not

Win32s is running. However, when Win32s is not running, Windows recovers

from the faults. When a Win32-based application is running, Win32s catches

all exceptions and transfers control to the nearest try/except frame. As a

result, the BitBlt is interrupted.

RESOLUTION

Certain S3 drivers which exhibit these problems can be made to work with

Win32s by making the following edit to your SYSTEM.INI file before running

any Win32-based applications:

In the SYSTEM.INI file, you will find an entry in the [display] section

   aperture-base=100

Change this entry to

   aperture-base=0

Restart Windows and the display problems will no longer occur.

If this does not help, obtain the latest S3 drivers. It is reported that S3

driver version 1.3 does not have this problem.

Additional reference words: 1.10 1.20

KBCategory: kbprg kbprb

KBSubcategory: W32s


PRB: DLL Load Fails Under Win32s When Apps Share a DLL

PSS ID Number: Q131224

Authored 06-Jun-1995	Last modified 07-Jun-1995

The information in this article applies to:

 - Microsoft Win32s versions 1.2 and 1.25a

SYMPTOMS

LoadLibrary fails under Win32s in the following situation:

1. App1 is executed and loads MYDLL.DLL.

2. App2 is executed and loads MYDLL.DLL as well.

3. App1 is terminated and unloads MYDLL.DLL.

App2 can GP fault when MYDLL.DLL is accessed. In addition, if App1 is

restarted and attempts to load MYDLL.DLL, the call to LoadLibrary fails and

GetLastError reports ERROR_DLL_INIT_FAILED.

This problem does not occur under Windows NT or Windows 95.

CAUSE

By default, Visual C++ create a DLL that statically links to the C Run-time

(CRT). This version of the CRT is not compatible with Win32s. Problems

occur when global data for the CRT is initialized, because of the shared

address space under Windows.

The static CRT library uses global variables to manage memory allocations.

In the scenario above, App2 can fault when allocating memory, if the global

variables used to access memory refer to memory that was allocated App1

which has since terminated, because the allocated memory was returned to

the heap.

RESOLUTION

Use the /MD (Multithreaded using CRT in a DLL) option when compiling the

DLL and add the MSVCRT.LIB import library to the library list. Include the

Win32s version of MSVCRT20.DLL which is included in Visual C++ 2.x (it is

redistributable) in your project. Then the DLL will use the DLL version of

the CRT libraries that is compatible with Win32s and the problem will not

occur.

MORE INFORMATION

When a DLL that uses the CRT is loaded into memory, all global variables

for the DLL and for the CRT libraries are initialized. Under Windows NT and

Windows 95, the application is given its own copy of the global data for

the DLL. When other applications use the same DLL, they each receive their

own copy of the global variables as well. This eliminates conflicts,

because the data is not shared.

Under Win32s, DLLs are loaded into the same shared memory space and all

global variables for a DLL are shared. This means that the CRT global data

is also shared. The version of MSVCRT20.DLL that targets Win32s was written

to take this into account and avoid conflicts.

The Windows NT/Windows 95 version of MSVCRT20.DLL can be found in the

MSVC20\REDIST directory of the CD. The Win32s version can be found in the

WIN32S\REDIST directory.

Additional reference words: 1.20 2.00

KBCategory: kbprg kbprb

KBSubcategory: W32s


PRB: Dotted Line Displays as Solid Line

PSS ID Number: Q24179

Authored 16-Dec-1987	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SYMPTOMS

When an application creates a dotted line using a dotted pen and

the R2_NOT mode, a solid line is drawn on the screen.

CAUSE

The background mode is OPAQUE. This is the default background mode.

In this mode, the line is painted with the background color first,

followed by the pen.

RESOLUTION

Use the SetBkMode() function to set the mode to TRANSPARENT. In

this mode, only the pen is used; the background is not disturbed.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg kbprb

KBSubcategory: GdiPnbr


PRB: Double Quotes Not in Help Files Compiled From Word 6 RTF

PSS ID Number: Q114604

Authored 08-May-1994	Last modified 23-Jun-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SYMPTOMS

When using the Microsoft Windows Help Compiler (any version) to compile a

.RTF file generated by Microsoft Word for Windows version 6.0, any double

quotation marks (") in the text may not show up in the compiled help file.

CAUSE

Microsoft Word for Windows 6.0 automatically replaces double quotation

marks with "smart quotes". This causes your .RTF file to contain

the \ldblquote and \rdblquote tokens rather than the double quotation mark

characters. The Help Compiler does not recognize these tokens and therefore

ignores them.

RESOLUTION

1. Replace existing \ldblquote and \rdblquote tokens with quotation mark

   characters by loading your .RTF file into a text editor (such as

   notepad) and performing a search and replace. That is, search for

   \ldblquote and replace with the quote character (") (without the

   parenthesis).

2. Stop Word for Windows from replacing quotation mark characters in the

   future by unchecking the "Replace Simple Quotes with Smart Quotes" check

   box under both of the following dialog boxes:

   a. Choose Options from the Tools menu, then choose Auto Format.

   b. Choose Auto Correct from the Tools menu.

Additional reference words: 3.10 3.50 4.00 95 WINHELP HC HC31 HC30 HCP

KBCategory: kbtool kbprg kbprb

KBSubcategory: TlsHlp


PRB: DSKLAYT2 May Create Too Many Files on a Disk Image

PSS ID Number: Q114605

Authored 08-May-1994	Last modified 22-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

 - Microsoft Win32 SDK, version 3.1

SYMPTOMS

The DSKLAYT2 program may create a disk image with more than 224 files

on a single disk when many small files are part of your product. When

trying to copy this image to a floppy disk, MS-DOS gives an error

message indicating it cannot create all of the files.

CAUSE

MS-DOS allows aproximantly 224 files to be placed in the root directory

of a floppy disk. Therefore, if DSKLAYT2 creates a disk image with more

than 224 files, MS-DOS will generate an error message when trying to

copy this disk image to an actual floppy disk. DSKLAYT2, however, will

not provide any warnings about the potential problem.

RESOLUTION

The MS-DOS 224-file limit only applies to the root directory of the

floppy disk, and therefore the solution involves creating a subdirectory

on the floppy disk and copying some of the files to the subdirectory.

The .INF file must also be modified to reflect the new locations of

the files.

Perform the following steps:

1. Create your disk images as normal.

2. When copying the problem disk image to a floppy disk, create a

   subdirectory on the floppy disk to receive most of the files. For

   example, suppose your target disk is in drive A:. Use

      md a:\files

   to create the subdirectory. Then, when copying the image files to the

   floppy disk, be sure to copy all the Setup Toolkit files (for example,

   SETUP.EXE, _MSTEST.EXE, SETUPAPI.INC, and so forth) to the root

   directory of the floppy disk and all the other files to the "files"

   subdirectory.

3. Modify the .INF file and place the new copy in the root of disk 1. Your

   .INF file must be modified to reference the new subdirectory as follows:

      Before

      [Files]

          1, myfile1.exe,,,,1992-01-30,,,,,,,ROOT,,,13833,,6,,,

      After

      [Files]

          1, files\myfile1.exe,,,,1992-01-30,,,,,,,ROOT,,,13833,,6,,,

   This modification is easy using the global search and replace

   capabilities of a good editor. For example, if disk 2 is the problem

   disk, search for all occurrences of "2, " and replace them

   with "2, files\".

4. Change the "STF_ROOT" line in the [Default File Settings] section of

   your .INF to read:

      "STF_ROOT" = "YES"

   If your .LST file specifies a compressed .INF file, you must use

   COMPRESS.EXE to compress your modified .INF file before copying it to

   disk 1.

Additional reference words: 3.10 MSSETUP

KBCategory: kbtool kbprg kbprb

KBSubcategory: TlsMss


PRB: Editing Labels in a TreeView Gives WM_COMMAND|IDOK

PSS ID Number: Q130692

Authored 24-May-1995	Last modified 23-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.51, 4.0

 - Microsoft Win32s version 1.3

SYMPTOMS

WM_COMMAND|IDOK errors are received while editing labels in a TreeView

control.

CAUSE

While editing labels in a TreeView control, the edit control created by the

TreeView control can, and usually does, have an identifier of 1. This

identifier is the same as IDOK. This can cause the parent window or dialog

box to receive WM_COMMAND messages with an identifier of 1. Then the

TreeView control passes on the EN_UPDATE and EN_CHANGE notifications from

the edit control to the TreeView's parent.

This was a design decision made to meet system requirements and cannot be

changed. If the parent window is going to perform some action in response

to a command with an identifier of 1, this problem can occur. This problem

is especially significant in dialog boxes that use the standard IDOK for a

command button control.

RESOLUTION

Avoid using command and control identifiers with an identifier of 1 (IDOK).

To be safe, the application should not use any identifiers less than 100

when used in conjunction with a TreeView control.

Another way to avoid this problem is to check the notification codes in the

WM_COMMAND messages. Then respond only to the proper notification codes

such as BN_CLICKED.

STATUS

This behavior is by design.

Additional reference words: 1.30 4.00 95

KBCategory: kbprg kbui kbprb

KBSubcategory: UsrCtl W32s


PRB: EndPage() Returns -1 When Banding

PSS ID Number: Q118873

Authored 01-Aug-1994	Last modified 22-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK), version 3.1

 - Microsoft Win32 SDK, versions 3.1, 3.5, 3.51, and 4.0

SYMPTOMS

When an application that implements banding calls EndPage(), EndPage()

returns SP_ERROR (-1).

CAUSE

EndPage() returns -1 if there has been no corresponding call to

StartPage(). Windows keeps track of whether StartPage() has been called by

maintaining an internal flag that is set when StartPage() is called and

then is cleared when EndPage() is called.

This flag is also cleared when the NEXTBAND escape is called and there are

no more bands on the page to be printed. At this point, Windows clears the

internal flag and tells the device that a page has been finished. Because

the internal flag has been cleared, a subsequent call to EndPage()

returns -1.

RESOLUTION

Though EndPage() returns -1 when it is called from printing code that

implements banding, it does no harm. An application can safely call

StartPage() and EndPage() when banding and ignore the -1 error returned

from EndPage().

NOTE: It is not recommended that a Win32-based application use banding.

Windows NT, spools in a journal file and Windows 95 spools in an enhanced

metafile, so all GDI calls are supported without banding.

Additional reference words: 3.10 3.50 4.00 NEWFRAME

KBCategory: kbprg kbprb

KBSubcategory: GdiPrn


PRB: Error 1 (NRC_BUFLEN) During NetBIOS Send Call

PSS ID Number: Q124879

Authored 15-Jan-1995	Last modified 26-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SYMPTOMS

When making a NetBIOS Send call, the call with fail with error code 1

(NRC_BUFLEN). This error code indicates that the buffer length is

invalid.

CAUSE

NRC_BUFLEN will be returned if the buffer length specified in the

NetBIOS Control Block (NCB) is incorrect. Less obvious is the fact that

this error will also be returned if the buffer pointed to by the NCB is

protected from write operations.

RESOLUTION

Although the NetBIOS code does not write to the buffer supplied in the NCB,

write access is required. You can solve the problem by changing the

protection on your buffer to include write access.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbnetwork kbprg kberrmsg

KBSubcategory: NtwkNetbios


PRB: Error Message Box Returned When DLL Load Fails

PSS ID Number: Q117330

Authored 26-Jun-1994	Last modified 22-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.5, 3.51,

   and 4.0

SYMPTOMS

Under Windows NT, when you load a DLL, a message box titled "Invalid DLL

Entrypoint" is displayed and has the following text:

   The dynamic link library <name> is not written correctly.

   The stack pointer has been left in an inconsistent state.

   The entry point should be declared as WINAPI or STDCALL.

   Select YES to fail the DLL load. Select NO to continue

   execution. Selecting NO may cause the application to operate

   incorrectly.

Under Windows 95, the message box is titled "Error starting program" and

the text is:

   The <dll file name> file cannot start. Check the file to

   determine the problem.

The user is not given a choice to continue, only an OK button. Pressing the

OK button fails program load.

CAUSE

The system expects DLL entrypoints to use the _stdcall convention. If you

use the _cdecl convention, the stack is not properly restored and

subsequent calls into the DLL can cause a general protection fault (GPF).

This error message is new to Windows NT, version 3.5. Under Windows NT,

version 3.1, the DLL is loaded without an error message, but the

application usually causes a GPF when calling a DLL routine.

RESOLUTION

Correct the prototype of your entrypoint. For example, if your entrypoint

is as follows:

   BOOL DllMain( HANDLE hDLL, DWORD dwReason, LPVOID lpReserved)

change it to the following:

   BOOL WINAPI DllMain( HANDLE hDLL, DWORD dwReason, LPVOID lpReserved)

Then, link with the following linker option to specify the entry point if

you are using the C run-time:

   -entry:_DllMainCRTStartup$(DLLENTRY)

MORE INFORMATION

If you are using the Microsoft C run-time, you need to use the entry point

given in the RESOLUTION section in order to properly initialize the C run-

time. For additional information, please see the following article in the

Microsoft Knowledge Base:

   ARTICLE-ID: Q94248

   TITLE     : Using the C Run Time

REFERENCES

For more information on the DLL entrypoint, please search on the topic

"DllEntryPoint" (without the quotes) in the Win32 API help file.

Additional reference words: 3.50 4.00 libmain

KBCategory: kbprg kbprb

KBSubcategory: BseDll


PRB: Error on Win32s: R6016 - not enough space for thread

PSS ID Number: Q126709

Authored 28-Feb-1995	Last modified 03-Mar-1995

The information in this article applies to:

 - Microsoft Win32s, versions 1.2 and 1.25

SYMPTOMS

Spawning and closing an application repeatedly succeeds around 60 times,

then the spawn fails with this error:

   R6016 - not enough space for thread data

CAUSE

The thread local storage (TLS) is not freed by the system.

The failure occurs only if there is another Win32-based application active

while you are doing the spawns. The message itself is not generated by

Win32s. It is generated by the Microsoft C Run-time (CRT) libraries

LIBC.LIB and LIBCMT.LIB.

RESOLUTION

In Win32s version 1.25, TLS indices are freed during module cleanup. The

TLS index is owned by the application's main module, so that it is freed

when the application terminates. This solves the problem for LIBC and

LIBCMT.

There is a similar problem with MSVCRT20.DLL. This DLL version of the CRT

allocates a new TLS index each time a process attaches to it. MSVCRT20

doesn't free the TLS indices when unloading. The system should free them.

If only one application uses MSVCRT20 at a time, then the application can

be spawned successfully up to about 60 times on Win32s version 1.20. On

Win32s version 1.25, there is no limitation.

If there is already an active application that uses MSVCRT20, it is not

possible to spawn and close a second application that uses MSVCRT20 more

than about 60 times under Win32s version 1.25. This is because MSVCRT20

allocates a TLS index each time a process attaches to it. Win32s will free

all of the TLS indices only when MSVCRT20 is unloaded.

MORE INFORMATION

On Win32s, TLS allocation should be done once and not per process. Each

process can use the index to store per-process data, just as a thread

uses a TLS index on Windows NT. This is easy to do, because DLL data is

shared between all processes under Win32s.

The following example demonstrates how to do the TLS allocation once on

Win32s:

   BOOL APIENTRY DllMain(HINSTANCE hinstDll, DWORD fdwReason,

           LPVOID lpvReserved)

   {

       static BOOL fFirstProcess = TRUE;

       BOOL fWin32s = FALSE;

       DWORD dwVersion = GetVersion();

       static DWORD dwIndex;

       if ( !(dwVersion & 0x80000000) && LOBYTE(LOWORD(dwVersion))<4 )

           fWin32s = TRUE;

       if (dwReason == DLL_PROCESS_ATTACH) {

           if (fFirstProcess || !fWin32s) {

               dwIndex = TlsAlloc();

            }

            fFirstProcess = FALSE;

       }

       .

       .

       .

   }

Additional reference words: 1.20

KBCategory: kbprg kbcode kbprb

KBSubcategory: W32s


PRB: Error with GetOpenFileName() and OFN_ALLOWMULTISELECT

PSS ID Number: Q99338

Authored 26-May-1993	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK, version 3.5

SYMPTOMS

Assume that the GetOpenFileName() function is called with the Flags

parameter set to OFN_ALLOWMULTISELECT (allow for multiple selections

in the list box) and OFN_NOVALIDATE (allow for invalid characters in

the filename), the lpstrFile parameter points to a 2K buffer, and the

corresponding nMaxFile is set appropriately to 2048.

When the GetOpenFileName() function call returns, the complete

selection in the list box is not copied to the lpstrFile buffer, but

the string in the buffer is truncated.

CAUSE

This is a problem with the GetOpenFileName() function in the current

version of COMMDLG.DLL in that the OFN_NOVALIDATE flag cannot be used

when multiple selections are allowed.

RESOLUTION

The following are two suggested solutions to this problem:

One solution for this problem is to not use the OFN_NOVALIDATE flag

with the OFN_ALLOWMULTISELECT flag. That is, if only the

OFN_ALLOWMULTISELECT flag is used, then multiple selections will be

copied properly to the text buffer. Note that there is a buffer size

limit of 2K bytes for the lpstrFile buffer, and characters are

truncated after 2K bytes when the OFN_ALLOWMULTISELECT flag is used.

There is another solution, if both the OFN_ALLOWMULTISELECT and

OFN_NOVALIDATE flags must be used simultaneously with

GetOpenFileName(). Note that the entire string is always copied into

the edit control even though the text gets truncated during the

process of copying the text to the lpstrFile buffer. Therefore, one

could write a hook procedure and read the entire string from the edit

control and use it appropriately instead of using the lpstrFile

buffer.

Additional reference words: 3.10 3.50

KBCategory: kbprg kbprb

KBSubcategory: UsrCmnDlg


PRB: ERROR_INVALID_PARAMETER from WriteFile() or ReadFile()

PSS ID Number: Q110148

Authored 13-Jan-1994	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SYMPTOMS

The WriteFile() or ReadFile() function call may fail with the error

ERROR_INVALID_PARAMETER if you are operating on a named pipe and using

overlapped I/O.

CAUSE

A possible cause for the failure is that the Offset and OffsetHigh members

of the OVERLAPPED structure are not set to zero.

RESOLUTION

Set the Offset and OffsetHigh members of your OVERLAPPED structure to zero.

STATUS

This behavior is by design. The online help for both WriteFile() and

ReadFile() state that the Offset and OffsetHigh members of the OVERLAPPED

structure must be set to zero or the functions will fail.

MORE INFORMATION

In many cases the function calls may succeed if you do not explicitly set

OVERLAPPED.Offset and OVERLAPPED.OffsetHigh to zero. However, this is

usually either because the OVERLAPPED structure is static or global and

therefore is initialized to zero, or the OVERLAPPED structure is automatic

(local) and the contents of that location on the stack are already zero.

You should explicitly set the OVERLAPPED.Offset and OVERLAPPED.OffsetHigh

structure members to zero.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg kbprb

KBSubcategory: BseFileio


PRB: Errors When Windbg Switches Not Set for Visual C++ App

PSS ID Number: Q131111

Authored 04-Jun-1995	Last modified 22-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.5

SYMPTOMS

If two switches are not set correctly, Windbg gives the following error

message when the module is loaded:

   (symbol format not supported)

In addition, Windbg gives the following error message for any breakpoints

set in the module:

   Unresolved Breakpoint

CAUSE

For Windbg to understand the symbolic format generated from Microsoft

Visual C++ version 2.0, two linker switches have to be set correctly:

 - /DEBUG is set in the Project Settings dialog box, under the Link tab.

   Choose the Debug category. Then select the Generate Debug Info check

   box, and choose Microsoft Format.

 - /PDB:none is set in the Project Settings dialog box, under the Link tab.

   Choose the Customize category. Then clear the Use Program Database check

   box.

STATUS

This behavior is by design.

Additional reference words: 3.50

KBCategory: kbtool kbprb

KBSubcategory: TlsWindbg


PRB: Excel's =REQUEST() from DDEML Application Returns #N/A

PSS ID Number: Q107980

Authored 01-Dec-1993	Last modified 18-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SYMPTOMS

When executing the =REQUEST() macro to request data from a DDEML server

application, Excel returns a value of "#N/A", although the server

application returned a valid data handle from the request.

CAUSE

When Excel executes a =REQUEST, it requests data in the most efficient

format available. Verifying through DDESPY when Excel executes the =REQUEST

macro, one can see that Excel sends out a request for data for each format,

in this order:

   XLTable  (Excel fast table format)

   BIFF4    (Excel 4.0 file format)

   BIFF3    (Excel 3.0 file format)

   SYLK     (Symbolic Link)

   WK1      (Lotus 1-2-3 release 2 format)

   CSV      (comma-delimited text)

   TEXT     (CF_TEXT)

   RTF      (rich text format)

   DIF      (data interchange format)

Knowing what formats it can handle best, Excel requests data in the most

efficient format first, and so on, until it finds one that the server

application supports. At this point, Excel stops sending further requests.

In response to a request, a DDEML server application that supports only one

format (for example, the CF_TEXT format) may return a data handle in

CF_TEXT format, regardless of the format being requested. When Excel sends

its first request for data in XLTable format, this server application

returns a data handle in CF_TEXT format, as demonstrated in the code below:

   case XTYP_REQUEST:

      if ((ghConv == hConv) &&

           (!DdeCmpStringHandles (hsz1, hszTopicName)) &&

           (!DdeCmpStringHandles (hsz2, hszItemName)))  {

              lstrcpy (szBuffer, "The Simpsons");

              return (DdeCreateDataHandle (idInst,

                                 szBuffer,

                                 lstrlen (szBuffer)+1,

                                 0L,

                                 hszItemName,

                                 CF_TEXT,

                                 0);

      }

      return (HDDEDATA)NULL;

Because Excel expected to receive data in the format it had requested (that

is, XLTable format), and instead received date in CF_TEXT format, Excel

returns #N/A, not knowing how to handle the data it received.

RESOLUTION

In response to a request, a DDEML server application should return a valid

data handle only for the format it supports. When processing an

XTYP_REQUEST transaction, the server application should first check whether

the data being requested is in its supported format; if so, the server

application should return an appropriate data handle. Otherwise, the server

application should return NULL.

The code above can be modified as follows to check for this condition:

   case XTYP_REQUEST:

      if ((ghConv == hConv) &&

           (!DdeCmpStringHandles (hsz1, hszTopicName)) &&

           (!DdeCmpStringHandles (hsz2, hszItemName)) &&

           (wFmt == CF_TEXT))  {     // Add this to the if clause

                                     // to check if data is being requested

                                       // in one of its supported formats.

                lstrcpy (szBuffer, "Fred Flintstone");

                return (DdeCreateDataHandle (idInst,

                                   szBuffer,

                                   lstrlen (szBuffer)+1,

                                   0L,

                                   hszItemName,

                                   CF_TEXT,

                                   0);

        }

        return (HDDEDATA)NULL;

Additional reference words: 3.10 3.50 3.51 4.00 95

KBCategory: kbprg kbprb kbcode

KBSubcategory: UsrDde


PRB: ExitProgman DDE Service Does Not Work If PROGMAN Is

PSS ID Number: Q69899

Authored 06-Mar-1991	Last modified 12-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SYMPTOMS

Calling the ExitProgman() function documented in the Microsoft Windows SDK

version 3.0 "Guide to Programming," section 22.4.4 (pages 22-19 through 22-

22) fails under certain circumstances.

CAUSE

Calling this function will fail if the Program Manager is the Windows

shell.

RESOLUTION

This behavior is by design. The Windows 3.1 documentation states:

   If Program Manager was started from another application, the ExitProgman

   command instructs Program Manager to exit and, optionally, save its

   groups information.

For another application to start Program Manager, the Program Manager

cannot be the shell.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg kbprb

KBSubcategory: UsrDde


PRB: FindText, ReplaceText Hook Function

PSS ID Number: Q96135

Authored 09-Mar-1993	Last modified 12-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SYMPTOMS

When adding a hook function to the FindText and/or ReplaceText common

dialog box, the dialog box is not shown. However, the hook function is

receiving messages and the dialog box window does exist.

CAUSE

The hook function is returning FALSE after processing the WM_INITDIALOG

message.

RESOLUTION

After processing the WM_INITDIALOG message in the hook function, return

TRUE. If your hook function is setting the focus to a specific control, and

therefore should return FALSE, add the following code:

   case WM_INITDIALOG:

      ...WM_INITDIALOG code...

      SetFocus(hCtrl);

      ShowWindow(hDlg, SW_NORMAL);

      UpdateWindow(hDlg);

      return(FALSE);

This code ensures that the dialog box is visible.

Additional reference words: 3.10 3.50 3.51 4.00 95

KBCategory: kbprg kbprb kbcode

KBSubcategory: UsrCmnDlg


PRB: GetExitCodeProcess() Always Returns 0 for 16-Bit

PSS ID Number: Q111559

Authored 14-Feb-1994	Last modified 27-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

 - Microsoft Win32s versions 1.1, 1.15, and 1.2

SYMPTOMS

--------

GetExitCodeProcess() always returns a status of 0 (zero) when the handle

for a 16-bit process is passed. This applies to both Windows NT and Win32s.

STATUS

------

This behavior is by design in the Microsoft products listed at the

beginning of this article. Microsoft may add functionality in future

versions that support exit codes from 16-bit processes.

Additional reference words: 3.10 3.50 1.10 1.20

KBCategory: kbprg kbprb

KBSubcategory: BseMisc W32s


PRB: GetLogicalDrives() Indicates that Drive B: Is Present

PSS ID Number: Q126626

Authored 27-Feb-1995	Last modified 28-Feb-1995

The information in this article applies to:

 - Microsoft Win32s, versions 1.2 and 1.25

SYMPTOMS

GetLogicalDrives() returns a bitmask that indicates that drive B is an

available drive present on the system, even though there is no physical

drive B.

CAUSE

Drive B is a ghosted drive, so you can use it even if it does not exist.

This is useful for performing a diskcopy.

RESOLUTION

Use GetDriveType() to determine whether drive B: is present as a physical

device.

STATUS

This behavior is by design.

Additional reference words: 1.20 1.25

KBCategory: kbprg kbprb

KBSubcategory: W32s


PRB: GetOpenFileName() and Spaces in Long Filenames

PSS ID Number: Q108233

Authored 07-Dec-1993	Last modified 29-Nov-1994

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

SYMPTOMS

GetOpenFileName() is the application programming interface (API) for the

open file common dialog box. This API displays the long filenames (LFNs) on

NTFS and HPFS.

When using the OFN_ALLOWMULTISELECT flag with the GetOpenFileName() API,

the dialog box automatically presents the 8.3 names for all LFNs that

contain embedded spaces.

CAUSE

The original design of GetOpenFileName() uses a filename list that is

space-delimited when the OFN_ALLOWMULTISELECT flag is specified. Thus,

there is no programmatic way to determine which string tokens are complete

filenames or fragments of a complete name with spaces.

STATUS

This behavior is by design. Microsoft is considering changing this behavior

in a future release of Windows NT.

MORE INFORMATION

Historically, FAT filenames that contained embedded spaces were branded as

"illegal," even though the specifications of the FAT file system do not

impose such a restriction. For example, many of the MS-DOS command-line

utilities do no allow the user to specify filenames with embedded spaces,

because of difficulties that would be introduced in parsing the command

line. Under Windows NT, the command utilities have been enhanced to support

such names if they are in quotation marks.

Additional reference words: 3.10 3.50

KBCategory: kbprg kbprb

KBSubcategory: UsrCmnDlg


PRB: Getsockopt() Returns IP Address 0.0.0.0 for UDP

PSS ID Number: Q129065

Authored 18-Apr-1995	Last modified 19-Apr-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.11 and 4.0

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

SYMPTOMS

By following the steps listed below, you might think you should get back

the interface address over which the connection was made. However, it

actually returns the address 0.0.0.0.

1. Open a UDP socket.

2. Bind it to INADDR_ANY.

3. Call connect() to make a UDP connection.

4. Call getsockname() on your socket.

However, if it was a TCP socket, you would get back the IP address of the

interface.

CAUSE

UDP

---

This is the behaviour expected from some flavors of UNIX, notably those

derived from BSD. When an application calls connect() on a UDP socket that

is bound to INADDR_ANY, the operating system associates the remote address

with the local socket. This saves the programmer from having to specify the

remote IP address in each sendto() or recvfrom(). Instead they may use

send() and recv(). Note that this is just a convenience provided by the

operating system; there is no network traffic associated with this call. At

this point, the underlying IP software determines the interface over which

packets will be sent. As described earlier, under BSD UNIX, calling

getsockname() will return the IP address of the interface to the

application.

This however, is not expected behaviour under Windows NT, Windows 95, or

Microsoft TCP IP/32 for Windows for Workgroups version 3.11. Calling

getsockname() will return the IP address 0.0.0.0 (INADDR_ANY). Applications

should not assume that they can get the IP address of the interface.

TCP

---

The behaviour is different if it was a TCP socket. In this case, calling

getsockname() on a connected socket that was bound to INADDR_ANY will

return the IP address of the interface over which the connection was made.

The state of the connection can also be observed by typing 'netstat' at a

command prompt.

NOTE: To enumerate all the IP addresses on an IP host, the

application should call gethostname(), call gethostbyname(), and then

iterate through the h_addr_list[] member of the hostent struct returned by

gethostbyname() as in this example:

   char     Hostname[100];

   HOSTENT *pHostEnt;

   int      nAdapter = 0;

   gethostname( Hostname, sizeof( Hostname ));

   pHostEnt = gethostbyname( Hostname );

   while ( pHostEnt->h_addr_list[nAdapter] )

   {

      // pHostEnt->h_addr_list[nAdapter] -the current address in host order

      nAdapter++;

   }

STATUS

This behavior is by design.

Additional reference words: 3.11 4.00 3.10 3.50 3.51

KBCategory: kbnetwork kbprb

KBSubcategory: NtwkWinsock


PRB: GetVolumeInformation() Fails with UNC Name

PSS ID Number: Q119219

Authored 10-Aug-1994	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SYMPTOMS

GetVolumeInformation() fails and GetLastError() returns 123

(ERROR_INVALID_NAME) if a UNC name is used. The UNC name has the form

\\<SERVER>\<SHARE>.

RESOLUTION

GetVolumeInformation() requires an extra backslash with UNC names, so that

the name has the form \\<SERVER>\<SHARE>\.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg kbprb

KBSubcategory: BseMisc


PRB: GlobalAlloc() Pagelocks Blocks on Win32s

PSS ID Number: Q114611

Authored 08-May-1994	Last modified 21-Dec-1994

The information in this article applies to:

 - Microsoft Win32s, versions 1.1, 1.15, and 1.2

SYMPTOMS

If a Win32-based application running in Win32s uses GlobalAlloc() to

allocate memory from the global heap with GMEM_FIXED, with GPTR, with

GMEM_ZEROINIT, or without specifying GMEM_MOVEABLE the memory allocated

will be fixed and page-locked.

CAUSE

When a Win32 application running under Win32s on Windows 3.1 calls

GlobalAlloc() the call is translated via a thunk supplied by Win32s in a 16-

bit DLL. The 16-bit DLL then calls the Windows 3.1 function GlobalAlloc().

When GlobalAlloc() is called from a DLL in Windows 3.1 the allocated memory

will be fixed and page-locked unless GMEM_MOVEABLE is specified.

RESOLUTION

The GlobalAlloc() flags should always include GMEM_MOVEABLE if memory does

not need to be fixed and page-locked. This is expected behavior for Windows

3.1.

MORE INFORMATION

A Windows-based application will not fix or page-lock memory even when

specifically using the GMEM_FIXED flag. This behavior is unique to Windows

version 3.1; using GlobalAlloc() with GMEM_FIXED to allocate fixed and page-

locked memory must be done in a DLL.

In Windows 3.1, the GMEM_FIXED flag is defined as 0x0000. Using

GMEM_ZEROINIT without GMEM_MOVEABLE will command GlobalAlloc() to allocate

using GMEM_FIXED by default. Since Win32s passes all GlobalAlloc() calls to

the Windows 3.1 GlobalAlloc() by a DLL, GlobalAlloc() called from either a

Win32 application or a Win32 DLL will allocate the block fixed and page-

locked unless the GMEM_MOVEABLE flag is specified.

The following code illustrates this case:

   {

   HGLOBAL hMem;

   // allocate a block from the global heap

   hMem = GlobalAlloc(GMEM_ZEROINIT, 512);

     .

     .

     .

   }

Although this source code is compatible between applications for Windows

3.1 and applications for Windows NT running on Win32s, the result is

different. A 16-bit application running on Windows 3.1 will allocate the

memory as moveable and zero the contents. A Win32 application running on

Win32s will allocate the memory as fixed and page-locked and zero the

contents.

REFERENCES

Appendix B, titled "System Limits", of the "Win32s Programmer's Reference

Manual" briefly mentions on page 56 not to use GMEM_FIXED in GlobalAlloc()

called by 32-bit applications.

Additional reference words: 1.10 1.20 3.10

KBCategory: kbprg kbprb

KBSubcategory: W32s


PRB: GP Fault Caused by GROWSTUB in POINTER.DLL

PSS ID Number: Q117864

Authored 11-Jul-1994	Last modified 16-Dec-1994

The information in this article applies to:

 - Microsoft Win32s versions 1.1, 1.15, and 1.2

SYMPTOMS

As soon as your Win32-based application starts, there is a GP fault caused

by GROWSTUB in POINTER.DLL.

CAUSE

This problem is caused by a bug in GROWSTUB, which is part of the Microsoft

Mouse driver version 9.01.

RESOLUTION

Microsoft Mouse driver version 9.01b corrects this problem. Driver 9.01b is

available via part number: 135-099-351 "Intellepoint Mouse Driver

2.0(dual)". This driver does not introduce new functionality, therefore,

you need only upgrade if you have run into this problem.

For more information, please see the following article in the Microsoft

Knowledge Base:

   ARTICLE-ID: Q119775

   TITLE     : HD1061: POINTER.DLL Corrects GP Fault with Win32 Apps

You can also avoid the problem by removing POINTER.EXE from the load= line

in your WIN.INI file.

Additional reference words: 1.10

KBCategory: kbprg kbprb

KBSubcategory: W32s


PRB: GP Fault in DDEML from XTYP_EXECUTE Timeout Value

PSS ID Number: Q83999

Authored 27-Apr-1992	Last modified 12-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SYMPTOMS

A general protection (GP) fault occurs in DDEML When the following occurs:

1. A DDEML (Dynamic Data Exchange Server Library) server

   application requires more time to process a XTYP_EXECUTE

   transaction than the timeout value specified by a DDEML client

   application

2. The server application creates windows as part of its processing

3. The client application abandons the transaction because the

   transaction timed out

CAUSE

The server application receives a window handle with the same value

as the hidden window created to control the transaction.

RESOLUTION

Specify a timeout value in the client application longer than the

time required by the server application to complete the task.

MORE INFORMATION

To use DDEML, an application (either a client or a server) registers a

callback function with the library. The DDEML calls the callback

function for any DDE activity. A DDE transaction is similar to a

message; it contains a named constant, accompanied by other

parameters.

A client application issues a XTYP_EXECUTE transaction to instruct the

server application to execute a command. When a client calls the

DdeClientTransaction function to issue a transaction, it can specify a

timeout value, which is the amount of time (in seconds) the client is

willing to wait while the server processes the transaction. If the

server fails to execute the command within the specified timeout

value, the DDEML sends a message to the client that the transaction

timed out. Upon receipt of this message, the client can inform the

user, reissue the command, abandon the transaction, or take other

appropriate actions.

If a client application specifies a short timeout period (one second,

for example) and the server requires fifteen seconds to execute a

command, the client will receive notification that the transaction

timed out. If the client terminates the transaction, which is an

appropriate action, the DDEML will GP fault.

When the client sends an XTYP_EXECUTE transaction, the DDEML creates a

hidden window for the conversation. If the client calls the

DdeAbandonTransaction function to terminate the transaction, the DDEML

destroys the associated hidden window.

At the same time, the server application processes the execute

transaction, which might involve creating one or more windows. If the

server creates a window immediately after the DDEML destroys a window,

the server receives a window handle with the same value as that of the

destroyed window. After the server completes processing the execute

transaction, it returns control to the DDEML.

Normally, the DDEML determines that the callback function is returning

to a conversation that has been terminated. It calls the IsWindow

function with the window handle for the transaction's hidden window to

ensure that the handle remains valid.

Because the window handle has been allocated to the server

application, the IsWindow test succeeds. However, this handle no

longer corresponds to the transaction's hidden window. Therefore, when

the DDEML attempts to retrieve the pointer kept in the hidden window's

window extra bytes, the pointer is not available. When the DDEML uses

the contents of this memory, a GP fault is likely to result.

The current way to work around this problem is to specify a timeout

value in the client application that is longer than the time required

by the server to complete its processing.

Additional reference words: 3.10 3.50 3.51 4.00 95

KBCategory: kbprg kbprb

KBSubcategory: UsrDde


PRB: GPF When Spawn Windows-Based App w/ WinExec() in Win32s

PSS ID Number: Q121095

Authored 26-Sep-1994	Last modified 28-Nov-1994

The information in this article applies to:

 - Microsoft Win32s, versions 1.1, 1.15, and 1.2

SYMPTOMS

Win32-based applications running under Win32s can spawn both Windows-based

and Win32-based applications by using either WinExec() or CreateProcess().

However, there is a case where spawning a Windows-based application with

WinExec() does not work as expected and may cause a general protection (GP)

fault.

CAUSE

There is a bug in the C start-up code that comes with Microsoft C version

6.0. If you spawn an application built with Microsoft C version 6.0 by

calling LoadModule() with an explicit environment, the application does not

run correctly. This is true whether the application was spawned from a

Win32-based application or a Windows-based application. Win32s calls

LoadModule() with an explicit environment when you spawn a Windows-based

application with WinExec(). As a result, under Win32s version 1.1 and 1.15,

WinExec() will report success, but the Windows-based application built with

Microsoft C version 6.0 may cause a GP fault.

RESOLUTION

The best solution is to rebuild the application with another compiler

package. However, because a number of Windows accessories (such as Notepad

and Write) were built with Microsoft C version 6.0 and you cannot modify

these applications, changes were introduced into Win32s version 1.2 to help

you work around this problem. These changes are detailed in the More

Information section below.

NOTE: Win32s uses a different mechanism to spawn Win32-based applications,

so the problems discussed in this article do not occur when spawning Win32-

based applications with WinExec().

MORE INFORMATION

In Win32s version 1.2, WinExec() does not pass the environment to the

spawned application (child). The child receives the standard global

environment strings. This allows the application to run, but the child does

not receive the modified environment from the parent. This seemed to be a

reasonable compromise, because most applications do not change the

environment for the child. If an application must modify the child's

environment, it can spawn the application using CreateProcess() and specify

an explicit environment. However, if the child was built using Microsoft C

version 6.0, it may cause a GP fault. In addition, if the parent exits, the

child's environment becomes invalid. These three problems are not specific

to Win32s and will happen with Windows-based applications as well.

Additional reference words: 1.00 1.15 1.20 GPF

KBCategory: kbprg kbprb

KBSubCategory: W32s


PRB: Inadequate Buffer Length Causes Strange Problems in

PSS ID Number: Q107387

Authored 18-Nov-1993	Last modified 18-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK versions 3.1, 3.5, 3.51, and 4.0

SYMPTOMS

Specifying an inadequate buffer length for an XTYP_POKE or an

XTYP_EXECUTE command causes strange problems in DDEML.

Problems can range from a general protection (GP) fault or Exception

13, to DDEML timeout errors (such as DMLERR_EXECACKTIMEOUT or

DMLERR_POKEACKTIMEOUT) or a DDEML transaction failure (or

DMLERR_NOTPROCESSED). Sometimes, the application may seem to work for

the most part, and then occasionally crash.

Data can be passed to the server application via XTYP_POKE or

XTYP_EXECUTE in two ways:

 - Directly, as a pointer to the data or command string, as in the

   sample code below:

   char lpszString [80];

   lstrcpy (lpszString, "[FileOpen(""C:\README.DOC"")]");

   DdeClientTransaction (lpszString,             // string buffer

                         lstrlen (lpszString)+1, // string buffer length

                         hConv,

                         hszItem,

                         CF_TEXT,

                         XTYP_POKE,

                         1000,

                         NULL);

  -or-

 - By creating a data handle, and passing that on to the

   DdeClientTransaction() call:

   char lpszString [80];

   HDDEDATA hData;

   lstrcpy (lpszString, "[FileOpen(""C:\README.DOC"")]");

   hData = DdeCreateDataHandle (idInst,

                                lpszString,

                                lstrlen (lpszString)+1,

                                0,

                                NULL,

                                CF_TEXT,

                                0);

   if (!hData)

      DdeClientTransaction (hData,     // string buffer

                            -1,        // indicates hData is a data handle

                            hConv,

                            hszItem,

                            CF_TEXT,

                            XTYP_POKE,

                            1000,

                            NULL);

CAUSE

Because data is most commonly passed between applications in CF_TEXT

format, a common problem with the string buffer length is setting it

to lstrlen (lpszString), where lpszString is the buffer containing the

string the client needs to pass to the server. Because the lstrlen()

function does not include the terminating null character, this can

cause the system to append garbage characters to the end of the

string, thus sending an invalid string to the server application.

RESOLUTION

When passing strings between two applications, the string buffer

length should be set to lstrlen (lpszString) +1, to include the

terminating null character ('\0').

Using DDESPY, it is easy to track down this problem, because one can

follow the string being passed from the client to the server

application. Garbage characters incorrectly being appended to the

string usually indicate a problem with specifying an inadequate string

buffer length.

Additional reference words: 3.10 3.50 3.51 4.00 95  gpf gp-fault

KBCategory: kbprg kbprb kbcode

KBSubcategory: UsrDde


PRB: Inconsistencies in GDI APIs Between Win32s and Windows

PSS ID Number: Q123421

Authored 01-Dec-1994	Last modified 01-Dec-1994

The information in this article applies to:

 - Microsoft Win32s version 1.2

SYMPTOMS

The StretchBlt() and StretchDIBits()/SetDIBits() GDI APIs do not behave

consistently under Win32s and Windows NT.

StretchBlt()

------------

If the source width and height specified in the call to StretchBlt() are

greater than the actual bitmap width and height, StretchBlt() fails. The

same call to StretchBlt() succeeds under Windows NT.

StretchDIBits()/SetDIBits()

---------------------------

If the memory pointed to by the lpBits parameter is read-only, the call to

StretchDIBits()/SetDIBits() fails.

NOTE: When a Win32-based application uses the memory returned from

LockResource() as a parameter to SetDIBits(), by default, it's using

read-only memory, because the resource section is defined by default as

read-only.

CAUSE

These problems are due to bugs in Windows. In the case of StretchDIBits()

and SetDIBits(), Windows mistakenly verifies that the buffer is writable.

This problem does not show up in a 16-bit Windows-based application running

under Windows because resources are loaded into read/write (global) memory.

RESOLUTION

In Win32s version 1.25, Win32s will always make the resource section

read/write, regardless of what is specified in the section attributes. This

will work around the problem. In the meantime, use the following

resolutions:

StretchBlt()

------------

To work around the problem, specify the proper width and height for the

source bitmap.

StretchDIBits()/SetDIBits()

---------------------------

To work around the problem, do one of the following:

 - Copy the memory to a temporary read/write buffer.

   -or-

 - Use the linker switch /SECTION:.rsrc,rw to make the resource section

   read/write. Windows NT will allocate separate resource sections for

   each copy of the application.

Additional reference words: 1.20

KBCategory: kbprg kbprb

KBSubcategory: W32s


PRB: Inter-thread SetWindowText() Fails to Update Window Text

PSS ID Number: Q125687

Authored 01-Feb-1995	Last modified 06-Apr-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

SYMPTOMS

Calling SetWindowText() to set a static control text from a thread other

than the one that created the control fails to display the new text

in Windows 95.

CAUSE

When SetWindowText() is called from another thread, instead of sending a

WM_SETTEXT message to the appropriate window procedure, only

DefWindowProc() is called, so the edit and static controls do not paint the

control appropriately because the appropriate code is never executed, so

the text on the screen is never updated. In other words, calling

SetWindowText() updates the buffer internally, but the change is not

reflected on the screen.

RESOLUTION

One obvious workaround is to refrain from calling SetWindowText() from

another thread, if possible.

If design considerations don't allow doing this, use one of these

workarounds:

 - Send a WM_SETTEXT message directly to the window or control.

   -or-

 - Call InvalidateRect() immediately after the SetWindowText(). This works

   because DefWindowProc() updates the buffer where the text is stored.

STATUS

This inter-thread SetWindowText() behavior is by design in Windows version

3.x. It was maintained in Windows 95 for backward compatibility purposes.

Applications written for Windows version 3.x can expect their inter-thread

SetWindowText() calls to behave as they did in Windows version 3.x.

MORE INFORMATION

Calling SetWindowText() from another thread in Windows NT displays the

window text correctly, so it works differently from Windows 95.

Additional reference words: 4.00

KBCategory: kbprg kbprb

KBSubcategory: UsrWndw


PRB: IsCharAlpha Return Value Different Between Versions

PSS ID Number: Q84843

Authored 21-May-1992	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.1 and 3.0

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SYMPTOMS

Under Windows version 3.1, the IsCharAlpha function returns TRUE

for the character values 8Ah, 8Ch, 9Ah, 9Ch, 9Fh, and DFh. Under

Windows version 3.0, the function returns FALSE for these character

values.

CAUSE

These characters represent alphabetic characters that were added to

the Windows character set in Windows 3.1.

RESOLUTION

Applications that use the IsCharAlpha function should behave

properly with the newly-defined characters. No changes should be

required.

MORE INFORMATION

Appendix C.1, page 596, of the "Microsoft Windows Software Development

Kit: Programmer's Reference, Volume 3: Messages, Structures, and

Macros" lists the Windows character set.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg kbprb

KBSubcategory: UsrLoc


PRB: IsGdiObject() Is Not a Part of the Win32 API

PSS ID Number: Q91072

Authored 27-Oct-1992	Last modified 05-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SYMPTOMS

There is no IsGdiObject() function in the Win32 API.

CAUSE

The function was added to the Windows 3.1 API because passing a handle

to a non-GDI object to a GDI function causes a GP fault under Windows

3.0. Windows NT and Windows 95 detect whether the APIs are passed an

inappropriate handle, so the function can return an error.

RESOLUTION

IsGdiObject() is not needed on Windows NT or Windows 95.

Additional reference words: 3.10 3.50

KBCategory: kbprg kbprb

KBSubcategory: GdiMisc


PRB: JournalPlayback Hook Can Cause Windows NT to Hang

PSS ID Number: Q124835

Authored 12-Jan-1995	Last modified 13-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

SYMPTOMS

Incorrect use of the delay return value from a journal playback hook can

cause Windows NT to hang temporarily.

CAUSE

The menu loop in Windows NT calls PeekMessage() with the PM_NOREMOVE flag,

does some processing, and then removes the message from the queue. This

sequence is repeated until the menu goes away. When JournalPlayback is

occurring, the PeekMessage( PM_NOREMOVE ) results in a callback to the

application's JournalPlaybackProc with an HC_ACTION code. The subsequent

PeekMessage( PM_REMOVE ) also calls the JournalPlaybackProc with an

HC_ACTION code. If the peek is successful, it is followed by an HC_SKIP

callback.

In order to have playback from a journal playback hook occur at a certain

rate, Microsoft designed it so that the value returned by the

JournalPlaybackProc can be non-zero. This value represents the number of

clock-ticks the system should wait before processing the event. What the

documentation doesn't make clear is that when the delay has expired,

another callback to the JournalPlaybackProc is made to obtain the same

event again; the event provided with the previous non-zero delay is not

used at all. All subsequent HC_ACTION calls that request the same event

should be returned with a zero delay value. Only after an HC_SKIP callback

has been made, may an HC_ACTION callback return a non-zero delay value

again. Some applications do not do this correctly, and simply alternate

between returning a delay and returning a non-delay.

This alternating delay/no delay method made the Windows NT menu loop hang

because the PeekMessage( PM_NOREMOVE ) would get an input event (with no

delay), then the PeekMessage( PM_REMOVE ) would get a non-zero return

value from the JournalPlaybackProc. This represents no message -- so

instead of issuing an HC_SKIP callback to the JournalPlaybackProc to

advance to the next event, the Windows NT menu loop code simply looped back

to the PeekMessage( PM_NOREMOVE ) getting stuck in an infinite loop.

RESOLUTION

To work around this problem, make sure the JournalPlaybackProc correctly

returns the delay only for the first request for an event.

Neither Windows version 3.1 nor Windows 95 have this problem.

STATUS

This behavior is by design.

MORE INFORMATION

The following sample code demonstrates correct and incorrect methods of

handling delays in a journal playback hook.

Sample Code

-----------

LRESULT CALLBACK JournalPlaybackProc(

    int nCode,

    WPARAM wParam,

    LPARAM lParam)

{

    static BOOL     fDelay;

    static EVENTMSG event;

    static LRESULT  ticks_delay;

    BOOL            fCallNextHook = FALSE;

    LRESULT         lResult = 0;

    switch( nCode )

    {

        case HC_SKIP:

            fDelay = TRUE;      // <<<< CORRECT PLACE TO RESET fDelay

            // Get the next event from the list.  If the routine returns

            // FALSE, then we are done - release the hook.

            if( !GetNextEvent( &event, &ticks_delay ))

                SetJournalHook( FALSE, NULL );

            break;

        case HC_GETNEXT:

        {

            // Structure information returned from previous GetNextEvent

            // call

            LPEVENTMSG lpEvent = (LPEVENTMSG) lParam;

            // Set the event

            *lpEvent = event;

            if( fDelay )

            {

                // Toggle pause variable so that the next call won't

                // pause.  Return the pause length specified by ticks_delay

                // since this is the first time the event has been

                // requested.

                fDelay = FALSE; // <<<< CORRECT PLACE TO CLEAR fDelay

                return( ticks_delay );

            }

            break;

        }

        case HC_SYSMODALOFF:

            // System modal dialog is going away - something really got

            // hosed.  Windows took care of removing our JournalPlayback

            // hook, so no need to call SetJournalHook( FALSE ).

            fCallNextHook = TRUE;

            break;

        case HC_SYSMODALON:

        default:

            // Something is is not right here, let the next hook handle

            // it.

            fCallNextHook = TRUE;

            break;

    }

    // If the event wasn't processed by our code, call next hook

    if( fCallNextHook )

        lResult = CallNextHookEx( s_journalHook, nCode, wParam, lParam );

    // fDelay = TRUE;           // <<<< WRONG PLACE TO RESET bDelay !!!

    return lResult;

}

Additional reference words: 3.10 3.50

KBCategory: kbprg kbprb

KBSubcategory: UsrHks


PRB: Large DIBs May Not Display Under Win32s

PSS ID Number: Q126575

Authored 26-Feb-1995	Last modified 27-Feb-1995

The information in this article applies to:

 - Microsoft Win32s versions 1.10, 1.15, or 1.20

SYMPTOMS

DIB functions fail when using large DIBs under Win32s.

CAUSE

There is a two-megabyte limit on the size of the area of a DIB that can be

blitted using blting functions under Win32s. In versions of Win32s up to

1.2, Microsoft set this size to accommodate DIB blts of 1024*768*24 bits-

per-pixel. In version 1.25, the maximum size of the blitted area will be

enlarged to accommodate 1280*1024*24 bits-per-pixel.

The following functions are affected:

  SetDIBits

  SetDIBitsToDevice

  CreateDIBitmap

  StretchDIBits

WORKAROUND

To work around the problem, break down large blts into bands that are

smaller than two megabytes. Please keep in mind that the biSizeImage field

of the BITMAPINFOHEADER used with the blting functions will need to be set

to a value smaller than the DIB size limit.

The following code demonstrates a simple implementation of StretchDIBits()

that can be used with large DIBs under Win32s.

/* Macro to determine the bytes in a DWORD aligned DIB scanline */

#define BYTESPERLINE(Width, BPP) ((WORD)((((DWORD)(Width) *

(DWORD)(BPP) + 31) >> 5)) << 2)

int NewStretchDIBits(

    HDC  hdc,     // handle of device context

    int  XDest,     // x-coordinate of upper-left corner of dest. rect.

    int  YDest,     // y-coordinate of upper-left corner of dest. rect.

    int  nDestWidth,  // width of destination rectangle

    int  nDestHeight, // height of destination rectangle

    int  XSrc,     // x-coordinate of upper-left corner of source rect.

    int  YSrc,     // y-coordinate of upper-left corner of source rect.

    int  nSrcWidth,   // width of source rectangle

    int  nSrcHeight,  // height of source rectangle

    VOID  *lpBits,    // address of bitmap bits

    BITMAPINFO *lpBitsInfo,   // address of bitmap data

    UINT  iUsage,  // usage

    DWORD  dwRop   // raster operation code

   )

{

    BITMAPINFOHEADER  bmiTemp;

    float fDestYDelta;

    LPBYTE lpNewBits;

    int i;

    // Check for NULL pointers and return error

    if (lpBits == NULL) return 0;

    if (lpBitsInfo == NULL) return 0;

    // Get increment value for Y axis of destination

    fDestYDelta = (float)nDestHeight / (float)nSrcHeight;

    // Make backup copy of BITMAPINFOHEADER

    bmiTemp = lpBitsInfo->bmiHeader;

   // Adjust image sizes for one scan line

    lpBitsInfo->bmiHeader.biSizeImage =

                       BYTESPERLINE(lpBitsInfo->bmiHeader.biWidth,

                                    lpBitsInfo->bmiHeader.biBitCount);

    lpBitsInfo->bmiHeader.biHeight = 1;

    // Initialize pointer to the image data

    lpNewBits = (LPBYTE)lpBits;

    // Do the stretching

    for (i = 0; i < nSrcHeight; i++)

   if (!StretchDIBits(hdc,

          XDest, YDest + (int)floor(fDestYDelta * (nSrcHeight - (i+1))),

          nDestWidth, (int)ceil(fDestYDelta),

          XSrc, 0,

          nSrcWidth, 1,

          lpNewBits, lpBitsInfo,

          iUsage, SRCCOPY))

        break; // Error!

   else

     // Increment image pointer by one scan line

     lpNewBits += lpBitsInfo->bmiHeader.biSizeImage;

    // Restore BITMAPINFOHEADER

    lpBitsInfo->bmiHeader = bmiTemp;

    return(i);

}

STATUS

This behavior is by design.

Additional reference words: 1.15 1.20 1.10

KBCategory: kbprg kbprb kbcode

KBSubcategory: W32s


PRB: LB_DIR with Long Filenames Returns LB_ERR in Windows 95

PSS ID Number: Q131286

Authored 07-Jun-1995	Last modified 10-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) version 3.51, 4.0

 - Microsoft Win32s version 1.3

SYMPTOMS

Sending an LB_DIR message to a list box that specifies a long filename in

the lParam returns LB_ERR in Windows 95 but works fine in Windows NT

version 3.51.

CAUSE

The implementation of list boxes in Windows 95 thunks down to 16-bit

USER.EXE, and the LB_DIR command has not been enhanced to support long

filenames.

RESOLUTION

Convert the long filename to its short form before passing it as the lParam

to LB_DIR by using GetShortPathName(). Similarly, when calling DlgDirList()

to fill a list box with filenames, make sure the lpPathSpec parameter

refers to the short name of the file.

Sample Code

-----------

char  szLong [256], szShort [256];

DWORD dwResult;

LONG  lResult;

lstrcpy (szLong, "C:\\This Is A Test Subdirectory");

dwResult = GetShortPathName (szLong, szShort, 256);

if (!dwResult)

   dwResult = GetLastError ();

lstrcat (szShort, "\lResult = SendDlgItemMessage (hdlg,

                              IDC_LIST1,

                              LB_DIR,

                              (WPARAM)(DDL_READWRITE),

          (LPARAM)(LPSTR)szShort);

if (LB_ERR == lResult)

   // an error occurred

NOTE: If a file with a long filename exists under the subdirectory

specified, Windows 95 displays the short name in the list box, whereas

Windows NT displays the long name.

STATUS

This behavior is by design.

MORE INFORMATION

This is not a problem under Windows NT because it always supported long

filenames.

You can have an application check the system version and decide at run time

if it should call GetShortPathName before passing the filename as lParam to

the LB_DIR message. Windows NT will, however, take a short name and fill

the list box with the filenames.

Additional reference words: 4.00 1.30 LongFileName LFN DlgDirList CB_DIR

DlgDirListComboBox

KBCategory: kbprg kbcode kbpb

KBSubcategory: UsrCtl


PRB: Listview Comes Up with No Images

PSS ID Number: Q125628

Authored 01-Feb-1995	Last modified 06-Apr-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

 - The Microsoft Foundation Classes (MFC), included with:

   Microsoft Visual C++, 32-bit Edition, version 2.1

SYMPTOMS

A list view is displayed with text and column headings, but the icons

are not displayed.

CAUSE

The CImageList used to store the images for the list view is no longer in

scope.

RESOLUTION

This can occur, for example, if you create a CImageList on the stack and

create your listview, but at the point the listview is displayed, the

image list has been destroyed. The ImageList functions will still return

success, but no images will be displayed.

To avoid the problem, make sure your image list stays in scope.

STATUS

This behavior is by design.

Additional reference words: 4.00 Windows 95

KBCategory: kbprg

KBSubcategory: UsrCtl


PRB: LoadCursor() Fails on IDC_SIZE/IDC_ICON

PSS ID Number: Q131280

Authored 07-Jun-1995	Last modified 10-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) version 4.0

SYMPTOMS

LoadCursor() returns NULL when passed IDC_SIZE or IDC_ICON for a second

parameter.

CAUSE

IDC_SIZE and IDC_ICON are obsolete. They are available only for backward

compatibility. Applications marked as a version 4.0 application are not

able to load these cursors under Windows 95.

STATUS

This behavior is by design.

Additional reference words: 4.00

KBCategory: kbprg kbprb

KBSubcategory: UsrRsc


PRB: LoadLibrary() Fails with _declspec(thread)

PSS ID Number: Q118816

Authored 31-Jul-1994	Last modified 22-Jun-1995

The information in this article applies to:

 - Microsoft Software Development Kit (SDK) versions 3.1, 3.5, 3.51,

   and 4.0

 - Microsoft Win32s versions 1.1, 1.15, 1.2, and 1.25a

SYMPTOMS

Your dynamic-link library (DLL) uses __declspec(thread) to allocate thread

local storage (TLS). There are no problems running an application that is

statically linked with the DLL's import library. However, when an

application uses LoadLibrary() to load the DLL instead of using the import

library, LoadLibrary() fails on Win32s with "error 87: invalid parameter".

LoadLibrary() succeeds under Windows NT in this situation; however, the

application cannot successfully call functions in the DLL.

CAUSE

This is a limitation of LoadLibrary() and __declspec(). The global variable

space for a thread is allocated at run time. The size is based on a

calculation of the requirements of the application plus the requirements of

all of the DLLs that are statically linked. When you use LoadLibrary(),

there is no way to extend this space to allow for the thread local

variables declared with __declspec(thread). This can cause a protection

fault either when the DLL is dynamically loaded or code references the

data.

RESOLUTION

DLLs that use __declspec(thread) should not be loaded with LoadLibrary().

Use the TLS APIs, such as TlsAlloc(), in your DLL to allocate TLS if the

DLL might be loaded with LoadLibrary(). If you continue to use _declspec(),

warn users of the DLL that they should not load the DLL with LoadLibrary().

Additional reference words: 1.10 1.20 3.10 3.50 4.00 95

KBCategory: kbprg kbprb

KBSubcategory: BseDll


PRB: Local Reboot (CTRL+ALT+DEL) Doesn't Work Under Win32s

PSS ID Number: Q121092

Authored 26-Sep-1994	Last modified 28-Nov-1994

The information in this article applies to:

 - Microsoft Win32s, versions 1.1, 1.15, and 1.2

SYMPTOMS

The Windows local reboot feature (CTRL+ALT+DEL) should terminate a hung

application. However, if the application is a Win32-based application,

using CTRL+ALT+DEL exits Windows.

CAUSE

This is a limitation of Win32s. When the VxD that handles hung applications

tries to access the application stack, it uses ss:sp, instead of ss:esp, as

if the application were a 16-bit application. This causes the VxD to crash,

and when the VxD crashes, the whole system terminates.

STATUS

This behavior is by design.

Additional reference words: 1.10 1.15 1.20

KBCategory: kbenv kbprb

KBSubCategory: W32s


PRB: MDI Program Menu Items Changed Unexpectedly

PSS ID Number: Q74789

Authored 30-Jul-1991	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.1 and 3.0

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SYMPTOMS

In an application for the Microsoft Windows graphical environment

developed using the Windows multiple document interface (MDI), when

the Window menu changes to indicate the addition of MDI child

windows, another menu of the application is also changed.

For example, if the menu resembles the following before any windows

are opened

   FILE            WINDOW

      Load            Cascade

      Save            Tile

      Save As...      Arrange Icons

      Exit

the menu might resemble the following after the first window is

opened:

   FILE            WINDOW

      Load            Cascade

      1: MENU.TXT     Tile

      Save As...      Arrange Icons

      Exit            -------------

                      1: MENU.TXT

CAUSE

One or more menu items have menu-item identifiers that are greater

than or equal to the value of the idFirstChild member of the

CLIENTCREATESTRUCT data structure used to create the MDI client

window.

RESOLUTION

Change the value of the idFirstChild member to be larger than any

menu item identifiers.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg kbprb

KBSubcategory: UsrMdi


PRB: Messages Sent to Mailslot Are Duplicated

PSS ID Number: Q127905

Authored 21-Mar-1995	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.5, 3.51,

   and 4.0

SYMPTOMS

One application creates a mailslot using CreateMailSlot() and reads from it

using ReadFile(). A second application opens the mailslot using

CreateFile() and writes to it using WriteFile(). The second application

writes one message to the mailslot, but the first application receives

three duplicates of the message.

CAUSE

This is expected behavior if you have three network transports loaded.

There is no way to know which transport should be used to deliver to a

given mailslot on a remote machine, so all transports are used.

RESOLUTION

Send a unique ID at the beginning of each message. The listening end can

detect duplicates and delete them. If you have multiple clients sending

messages, their messages may be interleaved in the mailslot. You may need

to track which client sent which message last, in order to successfully

detect duplicates.

STATUS

This behavior is by design.

Additional reference words: 3.50 4.00 95

KBCategory: kbprg kbprb

KBSubcategory: BseIpc


PRB: Most Common Cause of SetPixelFormat() Failure

PSS ID Number: Q126019

Authored 12-Feb-1995	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.5, 3.51,

   and 4.0

SYMPTOMS

SetPixelFormat() will fail with incorrect class or window styles.

CAUSE

Win32-based applications that use Microsoft's implementation of OpenGL to

render onto a window must include WS_CLIPCHILDREN and WS_CLIPSIBLINGS

window styles for that window.

RESOLUTION

Include WS_CLIPCHILDREN and WS_CLIPSIBLINGS window styles when in a Win32-

based application, you use Microsoft's implementation of OpenGL to render

onto a window.

Additionally, the window class attribute should not include the CS_PARENTDC

style. The two window styles can be added to the dwStyles parameter of

CreateWindow() or CreateWindowEX() call. If MFC is used, override

PreCreateWindow() to add the flags. For example:

    BOOL CMyView::PreCreateWindow(CREATESTRUCT& cs)

    {

        cs.style |= (WS_CLIPCHILDREN | WS_CLIPSIBLINGS);

        return CView::PreCreateWindow(cs);

    }

For more information, please refer to "comments" section of the online

documentation on SetPixelFormat.

STATUS

This behavior is by design.

Additional reference words: 3.50 4.00 95

KBCategory: kbgraphic kbprb

KBSubcategory: GdiOpenGL


PRB: Moving or Resizing the Parent of an Open Combo Box

PSS ID Number: Q76365

Authored 23-Sep-1991	Last modified 16-May-1995

-

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK), versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

-

SYMPTOMS

When the user resizes or moves the parent window of an open drop-

down combo box, the list box portion of the combo box does not move.

CAUSE

The list box portion of the combo box does not receive a move

message. Therefore, it remains on the screen at its original

position.

RESOLUTION

Close the drop down list before the combo box is moved. To perform

this task, during the processing of the WM_PAINT message, send the

combo box a CB_SHOWDROPDOWN message with the wParam set to FALSE.

Additional reference words: 3.00 3.10 3.50 4.00 95 combobox

KBCategory: kbprg kbprb

KBSubcategory: UsrCtl


PRB: MS-SETUP Uses \SYSTEM Rather Than \SYSTEM32

PSS ID Number: Q98888

Authored 18-May-1993	Last modified 29-Nov-1994

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

SYMPTOMS

Call GetWindowsSysDir() in the SETUP.MST file of a 16-bit setup

application. The return value is C:\WINNT\SYSTEM\ instead of

C:\WINNT\SYSTEM32\. Note that this doesn't happen with the 32-bit Setup

Toolkit.

CAUSE

Windows on Win32 (WOW) returns the SYSTEM directory, not the SYSTEM32

directory, to 16-bit applications such as MS-SETUP. This is done for

compatibility reasons.

RESOLUTION

Determine whether the setup code is being run under WOW or Windows version

3.1 by checking the WF_WINNT bit (0x4000) in the return from GetWinFlags().

Choose either the return from GetWindowsSysDir() or <winows dir>\system32

as appropriate.

MORE INFORMATION

Note that there are additional considerations for network installs for

Win32s, because the SYSTEM directory may not be a branch off of the Windows

directory.

Additional reference words: 3.10 3.50

KBCategory: kbtool kbprb

KBSubcategory: TlsMss


PRB: Named Pipe Write() Limited to 64K

PSS ID Number: Q119218

Authored 10-Aug-1994	Last modified 28-Nov-1994

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   versions 3.1 and 3.5

SYMPTOMS

WriteFile() returns FALSE and GetLastError() returns ERROR_MORE_DATA

when WriteFile() writes to a message-mode named pipe using a buffer greater

than 64K.

CAUSE

There is a 64K limit on named pipe writes.

RESOLUTION

The error is different from ERROR_MORE_DATA on the reader side, where bytes

have already been read and the operation should be retried for the

remaining message. The real error is STATUS_BUFFER_OVERFLOW. No data is

transmitted; therefore, the write operation must be retried using a smaller

buffer.

Additional reference words: 3.10 3.50

KBCategory: kbprg kbprb

KBSubcategory: BseIpc


PRB: NetBIOS Command NCBSEND Gets Return Code Error 0x3C

PSS ID Number: Q123457

Authored 01-Dec-1994	Last modified 03-Mar-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   versions 3.1 and 3.5

SYMPTOMS

While opening sessions, you start to get error 0x3C (lock of user area

failed) in the NcbSend command call.

CAUSE

An application in Windows NT uses the NcbListen command to accept NetBIOS

calls. After a call is received, the application uses the NcbSend command

to send data back.

If the computer running Windows NT has 32 megabytes of main memory, an

application can request a large number (for example, 128) of sessions, by

using the NcbReset command, without difficulty.

However, with only 16 megabytes of main memory, an application can request

only a moderate number (for example, 80) of sessions. If more sessions are

opened they start to get error 0x3C (lock of user area failed) in the

NcbSend command call. The error persists until some of the sessions that

are currently open are closed, at which time NcbSend will get a good return

status.

STATUS

This behavior is by design. The system stops the process from using so many

resources that it jeopardizes the performance of other applications and/or

the system itself.

Additional reference words: 3.10 3.50

KBCategory: kbprg kbenv kbprb

KBSubcategory: NtwkNetbios


PRB: Netbios RESET Cannot Be Called with Pending Commands

PSS ID Number: Q125659

Authored 01-Feb-1995	Last modified 07-Mar-1995

The information in this article applies to:

 - Microsoft Win32s, versions 1.2 and 1.25

SYMPTOMS

A Win32-based application cannot call the Netbios RESET command as long

as there are asynchronous commands still pending.

CAUSE

This behavior is by design in Win32s.

RESOLUTION

The application should cancel all pending commands, and wait for the post

routines of all the pending commands to be called. After that, the

application can issue a Netbios RESET command.

STATUS

This behavior is by design but may be designed differently in a future

version of Win32s.

Additional reference words: 1.20 1.25

KBCategory: kbprg

KBSubcategory: W32s


PRB: NetDDE Fails to Connect Under Windows 95

PSS ID Number: Q131025

Authored 02-Jun-1995	Last modified 06-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) version 4.0

SYMPTOMS

An application using Network Dynamic Data Exchange (NetDDE) fails to

connect to another DDE application on another computer.

CAUSE

One of the reasons could be that NETDDE.EXE (a system component) is not

running.

Network Dynamic Data Exchange (NetDDE) allows two DDE applications to

communicate with each other over the network. In Windows for Workgroups,

the NETDDE.EXE (a system component) was loaded by default. However under

Window 95, NETDDE.EXE is not loaded by default.

RESOLUTION

An application using the netDDE services should check if the netDDE system

component is loade. if NETDDE.EXE isn't running, the application should run

it.

Sample Code

-----------

The following sample code checks to see if NETDDE.EXE is loaded and tries

to load it if necessary. The sample code works for both 32-bit and 16-bit

applications.

BOOL IsNetDdeActive()

{

HWND  hwndNetDDE;

// find a netDDE window

hwndNetDDE = FindWindow("NetDDEMainWdw", NULL);

// if exists then NETDDE.EXE is running

if(NULL == hwndNetDDE)

   {

   UINT  uReturn;

   // otherwise launch the NETDDE.EXE with show no active

   uReturn = WinExec("NETDDE.EXE", SW_SHOWNA);

   // if unsucessful return FALSE.

   if(uReturn <= 31)

      return FALSE;

   }

// NetDDE is running

return TRUE;

}

STATUS

This behavior is by design.

Additional reference words: 4.00

KBCategory: kbprg kbnetwork kbcode kbinterop

KBSubcategory: Usrdde


PRB: Number Causes Help Compiler Invalid Context ID Error

PSS ID Number: Q85490

Authored 10-Jun-1992	Last modified 24-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SYMPTOMS

When the Windows Help Compiler compiles a help project file, the

following error message appears:

   Error P1083: Invalid context identification number

CAUSE

The representation of the context identification number begins with

a zero and contains the digit 8 or 9.

RESOLUTION

Remove the leading zeros from the number.

MORE INFORMATION

The Windows Help Compiler parses a number that has a leading zero as

an octal number. C compilers also interpret numbers in this manner.

Only the digits 0 through 7 are legal in an octal number.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbtool kbprg kbprb

KBSubcategory: TlsHlp


PRB: Oracle7 for Win32s Hangs When Initialize Database

PSS ID Number: Q127760

Authored 15-Mar-1995	Last modified 20-Jun-1995

The information in this article applies to:

 - Microsoft Win32s versions 1.00, 1.10, 1.15, 1.20, and 1.25a

SYMPTOMS

There is a known problem with using Oracle7 for Win32s with the Windows

Sound System version 2.0. The problem occurs when starting up a database in

the Database Manager. Oracle7 may hang during this process. The machine

will need to be rebooted.

CAUSE

The SNDEVNTS.DRV file is causing the problem by performing stack checking

on the application stacks of Oracle7. The stack checking is corrupting the

application stack of Oracle7 causing the application to hang.

RESOLUTION

Download SEVNT022.EXE, a self extracting file from the Microsoft Software

Library (MSL) available on the following services:

 - CompuServe

      GO MSL

      Search for SEVNT022.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download SEVNT022.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the SOFTLIB\MSLFILES directory

      Get SEVNT022.EXE

Follow the installation directions contained in the README.TXT file.

Additional reference words: 1.00 1.10 1.20 SNDEVNTS.DRV

KBCategory: kb3rdparty kbfile kbprb

KBSubcategory: W32s


PRB: Page Fault in WIN32S16.DLL Under Win32s

PSS ID Number: Q115082

Authored 18-May-1994	Last modified 21-Feb-1995

The information in this article applies to:

 - Microsoft Win32s, versions 1.1 and 1.15

SYMPTOMS

Start two instances of the Win32 application under Win32s. Close one

instance, then close the other instance. A page fault is generated in

WIN32S16.DLL. Under Win32s, version 1.1, a dialog box appears. Under

Win32s, version 1.15, the error only appears in the output from the debug

version of Win32s.

CAUSE

This problem can be caused by using the static C run-time (CRT) libraries

or using MSVCRT10.DLL. Note that even if the application does not make any

CRT calls, one of its DLLs may call the CRT initialization and cleanup

code. The CRT code makes the following sequence of API calls:

   DeleteCriticalSection

   DeleteCriticalSection

   DeleteCriticalSection

   TlsFree

   VirtualFree

   VirtualFree

   VirtualFree

When the second application instance terminates, it faults before it makes

the call to TlsFree(). The CRT has two blocks, one that contains strings

from the environment and one that contains pointers to the first blocks.

These are allocated by the first process that attach to the DLL. Other

processes that attach do not allocate these blocks. When processes are

terminated, these two blocks are freed. However, this succeeds only when

the process that owns the memory frees them. Any other process that tries

to access these blocks will fail.

RESOLUTION

Because there is no instance data by default under Win32s, DLLs should use

the CRT in a DLL instead of linking to the CRT statically. MSVCRT10.DLL

(which comes with Visual C++) is not compatible with Win32s because

MSVCRT10.DLL falsely assumes that Win32s implements instance data, which is

only available on Windows NT. Therefore, until an updated MSVCRT.LIB file

is released, use CRTDLL.LIB (which comes with the Win32 SDK) because Win32s

has its own CRTDLL.DLL file that was specifically designed for this use.

Microsoft Visual C++ 2.0 contains two versions of MSVCRT20.DLL: one version

is intended for use on Windows NT, the other is intended for use on Win32s.

To avoid this problem, use and ship the Win32s version of MSVCRT20.DLL in

your application.

MORE INFORMATION

The real problem is that memory is allocated for several applications. The

allocation is done by the first application. When this application

terminates, it takes with it all of its memory. This means that each time

the remaining applications try to access this memory, an error occurs.

Symptoms include data corruption, hanging, or the WIN32S16.DLL page fault

mentioned above.

Additional reference words: 1.10 1.15

KBCategory: kbprg kbprb

KBSubcategory: W32s


PRB: PaintRgn() Fills Incorrectly with Hatched Brushes

PSS ID Number: Q82169

Authored 29-Mar-1992	Last modified 25-May-1995

---

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

 - Microsoft Win32 SDK, version 4.0

---

SYMPTOMS

When the TRANSPARENT background mode and a mapping mode other than

MM_TEXT are selected and an application calls the PaintRgn() API

to fill a complex region with a hatched brush, a disconnected

pattern results.

CAUSE

The Windows Graphics Device Interface (GDI) draws a complex region

by filling the individual rectangles that make up the region. The

code to compute the position of each rectangle on the screen fails

when the screen coordinates are not in units of pixels. The error

is visible when a hatched brush style is used in TRANSPARENT mode.

RESOLUTION

When a hatched brush and TRANSPARENT background mode are required,

use the MM_TEXT mapping mode.

Additional reference words: 3.10 4.00 95

KBCategory: kbprg kbprb

KBSubcategory: GdiDrw


PRB: Poor TCP/IP Performance When Doing Small Sends

PSS ID Number: Q126716

Authored 28-Feb-1995	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SYMPTOMS

When doing multiple sends of less than the Maximum Transmission Unit

(MTU), you may see poor performance.  On an Ethernet network, the MTU

for TCP/IP is 1460 bytes.

CAUSE

When an application does two sends of less than a transport MTU, the

second send is delayed until an ACK is received from the remote host.

The delay occurs in case the application does another small send. TCP

can then coalesce the two small sends into one larger packet.  This

concept of collecting small sends into larger packets is called Nagling.

RESOLUTION

There are a number of ways to avoid Nagling in an application. Here are

two. The second is more complex but gives a better performance benefit:

 - Set the TCP_NODELAY socket option for the socket. This tells TCP/IP to

   send always, regardless of packet size. This will result in sub-optimal

   use of the physical network, but it will avoid the delay of waiting for

   an ACK.

 - Send larger blocks of data. The send() API call, when you include the

   overhead of the other network components involved, costs a couple of

   thousand instructions. One large send() call will be more efficient than

   two smaller send() calls, even if you need to do some buffer copies.

   Sending larger data blocks will also result in more efficient use of the

   physical network because packets will typically be larger and less

   numerous. This option is much better than the first (enabling

   TCP_NODELAY) and should be used if at all possible.

On Windows NT 3.51, if you are sending files, you should use the new

TransmitFile() API. This call reads the file data directly from the file

system cache and sends it out over the wire. The TransmitFile() call can

also take a data block that will be sent ahead of the file, if desired.

REFERENCES

More information about Nagling and the Nagle algorithm can be found in RFC

1122.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg kbnetwork kbprb

KBSubcategory: NtwkWinsock


PRB: Pressing the ENTER Key in an MDI Application

PSS ID Number: Q99799

Authored 08-Jun-1993	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SYMPTOMS

In a standard Microsoft Windows version 3.1 multiple document

interface (MDI) application, when a minimized MDI child is active and

the user presses the ENTER key, the child is not restored.

This is inconsistent with other MDI applications, such as File Manager

and Program Manager. An MDI child in one of these applications is

restored when it is the active MDI child and the ENTER key is pressed.

When a normal Windows-based application is minimized and the user presses

ENTER, that application is restored to a normal state.

RESOLUTION

One quick workaround to this problem is to create an accelerator for

the ENTER key and restore the minimized MDI child when the key is

pressed.

MORE INFORMATION

It may be desirable to implement the same restore feature that File

Manager and Program Manager have implemented in order to enable the

user to restore an MDI child by pressing the ENTER key. If this

feature is implemented, then the MDI application can be consistent

with other popular applications such as File Manager, Microsoft Excel,

and Microsoft Word.

To achieve this effect in an MDI application, create an accelerator in

the accelerator table of the resource file for the application. This

can be done as follows:

MdiAccelTable ACCELERATORS

     {

     .  .  .

     .  .  .

     VK_RETURN, IDM_RESTORE, VIRTKEY

     }

After this accelerator has been installed in the MDI application, each

time the ENTER key is pressed by the user, an IDM_RESTORE command will

be sent to the MDI frame window's window procedure through a

WM_COMMAND message. When the MDI frame receieves this message, its

window procedure should retrieve a handle to the active MDI child and

determine if it is minimized. If it is minimized, then it can restore

the MDI child by sending the MDI client a WM_MDIRESTORE message. This

can all be done with the following code:

        case IDM_RESTORE:

           {

           HWND hwndActive;

           hwndActive = SendMessage(hwndClient,WM_MDIGETACTIVE,0,0L);

           if (IsIconic(hwndActive))

              SendMessage(hwndClient,WM_MDIRESTORE,hwndActive,0L);

           break;

           }

Additional reference words: 3.10 3.50 3.51 4.00 95

KBCategory: kbprg kbprb kbcode

KBSubcategory: UsrMdi


PRB: Printer Font too Small with ChooseFont() Common Dialog

PSS ID Number: Q89544

Authored 24-Sep-1992	Last modified 12-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SYMPTOMS

In an application for the Microsoft Windows graphical environment, the user

selects a printer font through the ChooseFont() common dialog box function.

When the application calls the CreateFontIndirect() to create the selected

font, even though the style and face name are correct, the point size is

much too small.

CAUSE

The LOGFONT structure returned to the application is based on screen

metrics--even when the user selects a printer font. Because the resolution

(dots per inch) on a printer is generally much greater than that of the

screen, the resulting printer font is smaller than desired.

RESOLUTION

Modify the lfHeight member of the LOGFONT data structure according to the

printer metrics.

MORE INFORMATION

The following code demonstrates how to modify the lfHeight member. The

lpcf variable contains a pointer to the CHOOSEFONT data structure. The

hDC member of the CHOOSEFONT data structure is a handle to the printer

device context.

   if (ChooseFont(lpcf))

   {

      if (lpcf->nFontType & PRINTER_FONT)

      {

         iLogPixelsy = GetDeviceCaps(lpcf->hDC, LOGPIXELSY);

         lpcf->lpLogFont->lfHeight =

             MulDiv(-iLogPixelsy, (lpcf->iPointSize / 10), 72);

         hPrinterFont =

             CreateFontIndirect((LPLOGFONT)(lpcf->lpLogFont));

      }

      else

      {

         // Create screen font

      }

   }

   else

   {

      // Process common dialog box error

   }

Additional reference words: 3.10 3.50 3.51 4.00 95

KBCategory: kbprg kbprb kbcode

KBSubcategory: UsrCmnDlg


PRB: Private Button Class Can't Get BM_SETSTYLE in Windows 95

PSS ID Number: Q130951

Authored 31-May-1995	Last modified 02-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) version 4.0

SYMPTOMS

When an application creates a new button class, the new buttons do not

receive BM_SETSTYLE messages under Windows 95.

CAUSE

In previous versions of Windows, the new button had only to return

DLGC_BUTTON in response to the WM_GETDLGCODE message. This was all that was

required to identify the window as a "button."

However, in Windows 95, returning DLGC_BUTTON to WM_GETDLGCODE is no longer

sufficient to identify the window as a "button." The dialog manager code in

Windows 95 is implemented in 16 bits. When a message is dispatched to a

32-bit window, the system automatically generates a thunk. Because the

system does not know that the new class is actually a "button," it does not

automatically perform the thunk - so the BM_SETSTYLE messages are not sent.

RESOLUTION

To tell the system to treat the window as a "button," the window must call

one of the following APIs at least once:

IsDlgButtonChecked

CheckRadioButton

CheckDlgButton

The preferable method for doing this is to call IsDlgButtonChecked during

the WM_CREATE message. Once this is done, the window will receive all

standard button messages.

STATUS

This behavior is by design.

Additional reference words: 4.00

KBCategory: kbprg kbui kbprb

KBSubcategory: UsrCtl


PRB: Problems with the Microsoft Setup Toolkit

PSS ID Number: Q106382

Authored 07-Nov-1993	Last modified 29-Nov-1994

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

SYMPTOMS

1. When the /zi option is used with the Win32 DSKLAYT2.EXE to provide

   compression, it causes an access violation.

2. The Win32 Setup Toolkit does not contain a setup bootstrapper to

   copy the needed setup files to a temp drive and run the Setup

   program. Setup runs from floppy disks.

3. Install programs for applications that may run on Win32s must be

   created with the 16-bit version of the Setup Toolkit if the

   installation program will install Win32s. However, the 16-bit

   DSKLAY2.EXE cannot read the version information in a Win32 binary.

4. The Win32 DSKLAYT.EXE only shows 8.3 names in the list box.

5. The Setup program reports "out of memory" during installation, but there

   seems to be plenty of memory.

6. Installation fails from a CD-ROM. If the same files are copied from the

   CD to the hard disk, installation succeeds.

7. Setup programs created with the 32-bit setup toolkit will not run under

   Win32s.

RESOLUTIONS

1. The fix for this problem is available in the Alpha SDK Update and later.

   Note that COMPRESS.EXE has been updated to use a better compression

   algorithm, and therefore /zi is no longer recommended for best

   compression. The option has been kept for compatibility reasons.

2. The bootstrapper is not necessary in a 32-bit environment. It is

   required for Windows because it is not possible to remove the

   floppy disk of a currently running Win16 application (the resources

   could not all be preloaded and locked). If you want to use a

   bootstrapper for compatibility, a 32-bit version is available on

   CompuServe.

3. If a Win32s installation is provided on a separate disk, the

   install program can be developed with the Win32 Setup Toolkit.

4. The program is actually a 16-bit program, and therefore it can

   display only the 8.3 name. Use 8.3 names for the source names and

   specify that the files be renamed (using the long names) when they

   are installed.

5. This error can be caused when a DLL on disk 1 is needed when

   when a different disk is currently inserted. To work around this

   problem, use LoadLibrary() to load the DLL.

6. This problem was corrected in the Win32 3.5 SDK.

7. This problem was corrected in the Win32 3.5 SDK.

Additional reference words: 3.10 3.50

KBCategory: kbtool kbprb

KBSubcategory: TlsMss


PRB: Processing the WM_QUERYOPEN Message in an MDI

PSS ID Number: Q99411

Authored 27-May-1993	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SYMPTOMS

When a multiple document interface (MDI) child window processes the

WM_QUERYOPEN message to prevent the child from being restored out of a

minimized state, the system menu and restore button are not removed

from the menu bar when a maximized MDI child loses the focus or is

closed.

This problem occurs only when the maximized MDI child loses the focus

or is closed and the focus is given to an MDI child that returns 0

(zero) on the WM_QUERYOPEN message.

CAUSE

When an MDI child is maximized, the system menu and restore button are

added to the frame menu as bitmap menu items. When a maximized MDI

child is destroyed or another MDI child is given the focus, the MDI

child given the focus afterwards is maximized to replace the old MDI

child. Windows cannot maximize an MDI child when it is processing the

WM_QUERYOPEN message, and therefore the child is not maximized.

Unfortunately, the system menu and restore button bitmaps are not

removed from the menu bar.

RESOLUTION

To prevent this problem, restore the maximized MDI child before giving

the focus to another child.

MORE INFORMATION

It may sometimes be desirable to prevent an MDI child from being

restored during part or all of its life. This can be done by trapping

the WM_QUERYOPEN message by placing the following code in the window

procedure of the MDI child:

   case WM_QUERYOPEN:

      return 0;

Unfortunately, this causes the added restore and system menu bitmaps

to remain on the menu bar when a maximized MDI child loses the focus

or is closed and the focus is given to a child processing this

message. The following code can be used to restore a maximized MDI

child when it loses the focus:

     case WM_MDIACTIVATE:

        if ((wParam == FALSE) && (IsZoomed(hwnd)))

           SendMessage(hwndMDIClient, WM_MDIRESTORE, hwnd, 0L);

        return DefMDIChildProc (hwnd, msg, wParam, lParam);

Additional reference words: 3.10 3.50 3.51 4.00 95

KBCategory: kbprg kbprb kbcode

KBSubcategory: UsrMdi


PRB: Property Sheet w/ Multiline Edit Control Ignores ESC Key

PSS ID Number: Q130765

Authored 25-May-1995	Last modified 22-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) version 4.0

SYMPTOMS

Pressing the ESC key when the focus is on a Multiline Edit control that is

a child of a property sheet page, does not dismiss the property sheet

control as expected.

CAUSE

When the ESC key is pressed while focus is on a Mutiline Edit control, the

IDCANCEL notification (sent with a WM_COMMAND message) is sent to the

property sheet dialog proc whose template contains the Multiline Edit

control. Property sheet dialog procs do not process this message, so it is

not forwarded to the property sheet control.

RESOLUTION

Trap the IDCANCEL notification that is sent along with the WM_COMMAND

message in the property sheet dialog proc that contains the multiline edit

control. Then forward the message to the property sheet control. (The

property sheet control is the parent of all the property sheet page

dialogs.) The following code shows how to do this:

Code Sample

-----------

//

//  FUNCTION: SheetDialogProc(HWND, UINT, WPARAM, LPARAM)

//

//  PURPOSE:  Processes messages for a page in the PPT sheet control.

//

//  PARAMETERS:

//    hdlg - window handle of the property sheet

//    wMessage - type of message

//    wparam - message-specific information

//    lparam - message-specific information

//

//  RETURN VALUE:

//    TRUE -  message handled

//    FALSE - message not handled

//

LRESULT CALLBACK SheetDialogProc(HWND hdlg,

                      UINT uMessage,

                     WPARAM wparam,

                     LPARAM lparam)

{

    LPNMHDR lpnmhdr;

    HWND    hwndPropSheet;

    switch (uMessage)

    {

   case WM_INITDIALOG:

      // Do whatever initializations you have here.

      return TRUE;

   case WM_NOTIFY:

      // more code here ...

      break;

    case WM_COMMAND:

       switch(LOWORD(wparam))

      {

         case IDCANCEL:

         // Forward this message to the parent window

         // so that the PPT sheet is dismissed

            SendMessage(GetParent(hdlg),

                          uMessage,

                          wparam,

                          lparam);

         beak;

         default:

         break;

      }

      break;

   }

NOTE: This solution also works with wizard controls. This behavior is seen

under both Windows NT and Windows 95; the solution in this article works

for both platforms.

Additional reference words: 4.00 user styles

KBCategory: kbprg kbprb kbcode

KBSubcategory: UsrCtl


PRB: Quotation Marks Missing from Compiled Help File

PSS ID Number: Q110540

Authored 24-Jan-1994	Last modified 06-Jun-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SYMPTOMS

After upgrading from Word for Windows 2.x to Word for Windows 6.x and

rebuilding a Windows Help file with HCP.EXE or HC31.EXE, all of the

quotation marks are missing from the Help file.

CAUSE

Word 6.x uses a special .RTF keyword to represent the quotation mark

character, and the Help compiler does not understand the new .RTF keyword

so it drops the character. The same problem occurs for the curly double

quotation mark, single quotation mark, en dash (char 150), em dash (char

151), and the bullet character (char 149).

RESOLUTION

You can prevent this problem by turning off the "Smart Quotes" option in

Word for Windows. The following three steps accomplish this:

1. Choose Options from Tools menu.

2. Select the AutoFormat tab.

3. In the Replace group box, clear the "Straight Quotes with Smart Quotes"

   check box, and choose OK.

If you wish to include smark quotes, bullets, em-dashes, and en-dashes in a

Help file, you can open the file as text only and replace the RTF keywords

with their ANSI hexidecimal equivalents, which are recognized by the help

compiler.

   Find String       Replace String

   -----------       --------------

   \emdash           \'97"

   \endash           \'96"

   \bullet           \'95"

   \rdblquote        \'94"

   \ldblquote        \'93"

   \rquote           \'92"

   \lquote           \'91"

Make sure that there is a blank character included at the end of the Find

String, but not in the Replace String.

This replacement must be made every time you edit and convert the text from

document to RTF format.

Additional reference words: 3.10 3.50 4.00

KBCategory: kbtool kbprg kbprb

KBSubcategory: TlsHlp


PRB: RegCreateKeyEx() Gives Error 161 Under Windows NT 3.5

PSS ID Number: Q117261

Authored 23-Jun-1994	Last modified 28-Nov-1994

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.5

SYMPTOMS

A call to RegCreateKeyEx() is successful under Windows NT version 3.1, but

the call fails with error 161 (ERROR_BAD_PATHNAME) under Windows NT version

3.5.

The sample code below demonstrates this problem.

CAUSE

This is by design. Windows NT version 3.1 allows the subkey to begin with a

backslash ("\"), however Windows NT version 3.5 does not. The subkey is

given as the second parameter to RegCreateKeyEx().

RESOLUTION

Remove the backslash from the beginning of the subkey name.

MORE INFORMATION

In the sample code below, RegCreateKeyEx() fails with error 161 while the

string defined by SUBKEY_FORMAT_STRING begins with a backslash, but

succeeds if the initial backslash is removed.

Sample Code

-----------

   #include <windows.h>

   #include <stdio.h>

   #define SUBKEY_FORMAT_STRING \

   "\\SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\%s"

   void main(int argc, char *argv[])

   {

      DWORD dwErrorCode;

      char lpszSubKey[MAX_PATH];

      HKEY hKey;

      DWORD dwDisposition;

      sprintf( lpszSubKey, SUBKEY_FORMAT_STRING, argv[1] );

      printf( "Trying to open: %s\n", lpszSubKey );

      dwErrorCode = RegCreateKeyEx(HKEY_LOCAL_MACHINE,

                                   lpszSubKey,

                                   0,

                                   "",

                                   REG_OPTION_NON_VOLATILE,

                                   KEY_ALL_ACCESS,

                                   NULL, //Security

                                   &hKey,

                                   &dwDisposition );

      if (dwErrorCode != ERROR_SUCCESS)

         printf( "Code = %d.\n", dwErrorCode );

      RegCloseKey(hKey);

   }

NOTE: Double backslashes ("\\") are required in strings in C code to

represent a single backslash, since a backslash ordinarily indicates the

beginning of an escape sequence.

Additional reference words: 3.50

KBCategory: kbprg kbprb

KBSubcategory: BseMisc


PRB: RegisterClass()/ClassEx() Fails If cbWndExtra > 40 Bytes

PSS ID Number: Q131288

Authored 07-Jun-1995	Last modified 10-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) version 4.0

SYMPTOMS

Under Windows 95, a call to RegisterClass() or RegisterClassEx() returns

NULL if a value greater than 40 is specified for the cbWndExtra or

cbClsExtra members of the WNDCLASS or WNDCLASSEX structure.

CAUSE

Windows 95 checks to see if cbWndExtra or cbClsExtra is greater than 40. If

so, it outputs these debug messages and returns NULL to indicate failure:

   RegisterClassEx: Unusually large cbClsExtra (>40)

   RegisterClassEx: Unusually large cbWndExtra (>40)

RESOLUTION

If more than 40 bytes are needed to store window-specific or class-specific

information, an application should allocate memory. Then set the cbWndExtra

or cbClsExtra to 4 bytes, and pass the pointer to the allocated memory by

using SetClassLong() as follows:

   SetClassLong (hWnd, GCL_CBCLSEXTRA, lpMemoryAllocated);

   SetClassLong (hWnd, GCL_CBWNDEXTRA, lpMemoryAllocated);

The pointer can then be retrieved when needed by using GetClassLong() as

follows:

   lpMemoryAllocated = GetClassLong (hWnd, GCL_CBCLSEXTRA);

   lpMemoryAllocated = GetClassLong (hWnd, GCL_CBWNDEXTRA);

STATUS

This behavior is by design. However, as of version 3.51, Windows NT does

not have this 40-byte limitation.

Additional reference words: 4.00

KBCategory: kbprg kbprb

KBSubcategory: UsrCls


PRB: Result of localtime() Differs on Win32s and Windows NT

PSS ID Number: Q117893

Authored 13-Jul-1994	Last modified 12-Jan-1995

The information in this article applies to:

 - Microsoft Win32s versions 1.1, 1.15, and 1.2

SYMPTOMS

Under Windows NT, localtime( time() ) returns the correct local time.

However, under Win32s, the local time returned is not correct if the TZ

environment variable is set. For example, suppose that you are in the

Pacific time zone (GMT-08:00) and have set tz=pst8pdt. The time returned

under Win32s is off by 8 hours.

CAUSE

This is by design.

The localtime() function depends on time zone information, which is not

available in Win32s. This is the reason that the Win32 API GetLocalTime()

is not supported under Win32s. The C Run-time functions, like localtime(),

use the tz environment variable for time zone information.

The time() function returns the current local time under Win32s, then the

call to localtime() adjusts the time by the offset of your time zone from

GMT, which it finds by reading the tz environment variable.

Under Windows NT, time() and GetSystemTime() return GMT, therefore

localtime( time() ) is the current local time.

RESOLUTION

To get the current local time under both Win32s and Windows NT, use the

following code to clear the tz environment variable and get the time:

   _putenv( "TZ=" );

   _tzset();

   localtime( time() );

Note that _putenv() affects only the tz environment variable for the

application. All other applications use the global environment settings and

make their own modifications.

Additional reference words: 1.10 1.20

KBCategory: kbprg kbprb

KBSubcategory: W32s


PRB: RichEdit Control Hides Mouse Pointer (Cursor)

PSS ID Number: Q131381

Authored 11-Jun-1995	Last modified 23-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.51, 4.0

 - Microsoft Win32s version 1.3

SYMPTOMS

When the mouse pointer (cursor) is over a RichEdit control and the user

starts typing in the control, the RichEdit control hides the pointer.

CAUSE

When the user is typing in a RichEdit control, the control automatically

hides the mouse pointer if it is is over the control. The control does this

intentionally so the cursor does not obscure the text in the control. When

the mouse is moved again, the pointer re-appears.

STATUS

This behavior is by design.

Additional reference words: 4.00 95 1.30

KBCategory: kbprg kbui kbprb

KBSubcategory: UsrCtl


PRB: RoundRect() and Ellipse() Don't Match Same Shaped

PSS ID Number: Q119455

Authored 16-Aug-1994	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   version 3.1

 - Microsoft Win32 SDK, versions 3.1, 3.5, 3.51, and 4.0

SYMPTOMS

When CreateRoundRectrRgn() is used to create a region with the shape of a

rectangle that has rounded corners and RoundRect() is called with the same

parameters to draw the same rectangle that has rounded corners, the

calculated region does not match the drawn rectangle. The same can be said

of the ellipses created by CreateEllipticRgn() and Ellipse().

CAUSE

This behavior is because of the design on Windows. The mismatch between

fills and frames is because of the way that the boundaries and fills must

be specified in order to get polygons to fit together properly. Windows NT

duplicates this behavior for compatibility.

RESOLUTION

Perform the fill first, then draw the frame. Some of the frame pixels will

overwrite fill pixels and some will not; however, there will be no gap

between the frame and the fill, and the fill will not extend past the

frame. Use CreateRoundRectRgn() or CreateEllipticRgn() for the fill and

RoundRect() or Ellipse, respectively, for the frame. Use the same

parameters for both the region API and the filled-shape API.

NOTE: If you use a NULL pen when drawing the filled shape, the pixels will

match those drawn by creating a region through the corresponding region API

and then calling FillRgn() with the same parameters. It draws the frame

with the pen from the filled-shape API that causes the discrepancy.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg kbprb

KBSubcategory: GdiDrw


PRB: RPC Installation Problem

PSS ID Number: Q104315

Authored 13-Sep-1993	Last modified 28-Nov-1994

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

SYMPTOMS

There is a problem with the Remote Procedure Call (RPC) service

installation. Setup searches the Windows directory for WINSOCK.DLL. If the

file is found, Setup installs RPC16C3.DLL.

This is a problem if you are dual booting a machine between Windows 3.1 and

Windows NT because Windows 3.1 uses an older TCP/IP interface, which is

called RPC16C3X.DLL on the distribution disks. When you run Windows NT, you

will want to use the newer TCP/IP interface, called RPC16C3.DLL.

WORKAROUND

If you are dual booting and using RPC, a workaround to this problem is to

rename your WINSOCK.DLL file to something else, such as WINSOCK.XXX. This

will cause Setup to copy the correct version of the TCP/IP dynamic-link

library (DLL).

Additional reference words: 3.10

KBCategory: kbprg kbprb

KBSubcategory: NtwkRpc


PRB: RW1004 Error Due to Unexpected End of File (EOF)

PSS ID Number: Q106064

Authored 31-Oct-1993	Last modified 23-Jun-1995

The information in this article applies to:

- Microsoft Win32 SDK, versions 3.1, 3.5, 3.51, and 4.0

SYMPTOMS

The resource compiler generates the following errors when the .RC file

includes a .H file whose last line is a define (that is, there was no

final carriage return at the end of the #define statement):

   fatal error RC1004: unexpected EOF

CAUSE

The resource compiler preprocessor follows C syntax. A newline character is

required on a #define statement.

RESOLUTION

Add a carriage return following the #define.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbtool kbprb

KBSubcategory: TlsRc


PRB: Saving/Loading Bitmaps in .DIB Format on MIPS

PSS ID Number: Q85844

Authored 22-Jun-1992	Last modified 24-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   and 3.51

SYMPTOMS

In Win32, saving or loading a bitmap in .DIB file format is basically the

same as in Win16. However, care must be taken in DWORD alignment,

especially on the MIPS platform.

An exception occurs when loading or saving a bitmap on the MIPS platform.

In NTSD, the following error message is received:

   data mis-alignment

CAUSE

A non-DWORD aligned actual parameter was passed to a function such as

GetDIBits().

The .DIB file format contains the BITMAPFILEHEADER followed immediately by

the BITMAPINFOHEADER. Notice that the BITMAPFILEHEADER is not DWORD

aligned. Thus, the structure that follows it, the BITMAPINFOHEADER, is not

on a DWORD boundary. If a pointer to this DWORD misaligned structure is

passed to the sixth argument of GetDIBits(), an exception will occur.

RESOLUTION

To resolve this problem, copy the data in the structure over to a DWORD-

aligned memory and pass the pointer to the latter structure to the function

instead. See the sample code LOADBMP.C for detail.

MORE INFORMATION

The is a sample to illustrates this process. Refer to the LOADBMP.C file in

the MANDEL sample that comes with the Win32 SDK.

Additional reference words: 3.10 3.50

KBCategory: kbprg kbprb

KBSubcategory: GdiBmp


PRB: Search Button Disabled in Windows Help

PSS ID Number: Q71761

Authored 01-May-1991	Last modified 24-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.1, 3.5, 3.51, and 4.0

SYMPTOMS

When a help file is loaded into the Windows Help program, the Search button

is disabled.

CAUSE

There are two likely causes:

   1. The help file defines no keywords for searching.

   2. The keywords are defined using a lowercase "k" footnote.

RESOLUTION

For cause 1, if searching is desired, define some keywords in the file. For

cause 2, modify the RTF text to use an uppercase "K" for keyword footnotes.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbtool kbprg kbprb

KBSubcategory: TlsHlp


PRB: SEH with Abort() in the try Body

PSS ID Number: Q91146

Authored 29-Oct-1992	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SYMPTOMS

When using Structured Exception Handling, if the try body calls abort(),

the finally body is not executed.

CAUSE

The finally body is not executed because the abort() never returns. It

calls ExitProcess(), which terminates the process.

RESOLUTION

This behavior is by design.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg kbprb

KBSubcategory: BseExcept


PRB: SEH with return in the finally Body Preempts Unwind

PSS ID Number: Q91147

Authored 29-Oct-1992	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51 and 4.0

SYMPTOMS

When using Structured Exception Handling (SEH), returning out of a finally

body results in a return from the containing procedure scope. For example,

in the following code fragment, the return in the finally block results in

a return from func():

   int func()

   {

       int status = 0;

       __try {

          ...

          status = test();

          ...

       }

       __finally {

          if (status != 0) {

             status = FAILURE;

             return status;

          }

       }

       return status;

   }

CAUSE

A return from within a __finally is equivalent to a goto to the closing

brace in the enclosing function [for example, func()]. This is allowed,

but has consequences that should normally be avoided.

Exception handling has two stages. First, the exception stack is walked,

looking for an accepting __except. When an accepting handler has been

found, all __finallys between the top-of-exception-stack and the target

__except will be called. During this "unwind", the __finallys are

assumed to each execute and then return to their caller (the system

unwind code).

A return in a finally abnormally aborts this unwinding. Instead of

returning to the system unwinder, the __finally returns to the enclosing

function's caller [for example, func()'s parent]. The accepting __except

filter may set some status or perform an allocation in anticipation of

the __except handler being entered. In this case, the intervening

__finally with the return will stop the unwind, and the __except handler

is never entered.

RESOLUTION

This is by design. It makes it possible for a finally handler to stop an

unwind and return a status. This is what is referred to as a collided

unwind.

Abnormal termination from try/except or try/finally blocks is not

generally recommended because it is a performance hit.

The example can be rewritten so that the unwind chain is not aborted:

   int func()

   {

      int status = 0;

      __try {

         ...

         status = test();

         ...

      }

      __except(status != 0) {

          /* null */

      }

      if (status != 0)

         status = FAILURE;

      return status;

   }

This does not have identical semantics because the exception filters

higher up the exception stack will not be executed. However, ensuring

that both phases of exception handling progress to the same depth is a

more robust solution.

MORE INFORMATION

Normally this behavior is transparent to any higher-level exception

handling code. If, however, a filter function, as a side effect, stores

information that it expects to process in an exception handler, then it may

or may not be transparent. Storing such information in a filter function

should be avoided because it is always possible that the exception handler

will not be executed because the unwind is preempted. In the absence of

storing such side effects, it will be transparent that an exception

occurred and an attempted unwind occurred if one of the descendent

functions has a try/finally block with an finally clause that preempts the

unwind.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg kbprb

KBSubcategory: BseExcept


PRB: SelectClipRgn() Cannot Grow Clip Region in WM_PAINT

PSS ID Number: Q118472

Authored 19-Jul-1994	Last modified 23-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK), version 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SYMPTOMS

Setting a smaller clipping region in WM_PAINT by using SelectClipRgn()

works fine; however, setting a larger clipping region seems to have no

effect. GetClipBox() can be used to verify this after calling

SelectClipRgn().

CAUSE

When you call SelectClipRgn() within a BeginPaint()/EndPaint() block in an

application's WM_PAINT case, the maximum size to which you can set your

clipping region is the size of the update region of your paint structure.

This is because the resulting clip region is the intersection of the update

region and the region specified in the call to SelectClipRgn(). In other

words, you can use SelectClipRgn() to shrink your update region, but not to

grow it. This behavior is by design.

RESOLUTION

Invalidate the clipping region area you want before calling BeginPaint().

For example:

case WM_PAINT:

   InvalidateRect(hWnd, ....); // Invalidate the size you'll want

                               // for the clip region.

   BeginPaint()

   SelectClipRgn();

   ... paint away ...

   EndPaint();

   break;

Something similar could be done in the Microsoft Foundation Classes (MFC),

such as:

void CMyView::OnPaint()

{

   InvalidateRect(...); // Invalidate the size you'll want.

   CPaintDC dc(this);   // CPaintDC wraps BeginPaint()/EndPaint().

   // Do drawing here...

}

MORE INFORMATION

This is addressed in the documentation for the Windows NT SDK version 3.1

[Section 20.1.5, "Window Regions" in Chapter 20, "Painting and Drawing" in

the "Microsoft Win32 Programmer's Reference, Volume 1" or in the Win32 API

Reference online help (search on "Window Regions")] which states:

   In addition to the update region, every window has a visible region that

   defines the window portion visible to the user. The system changes the

   visible region for the window whenever the window changes size or

   whenever another window is moved such that it obscures or exposes a

   portion of the window. Applications cannot change the visible region

   directly, but Windows automatically uses the visible region to create

   the clipping region for any display DC retrieved for the window.

   The clipping region determines where the system permits drawing. When

   the application retrieves a display DC using the BeginPaint, GetDC, or

   GetDCEx function, the system sets the clipping region for the DC to the

   intersection of the visible region and the update region. Applications

   can change the clipping region by using functions such as SelectClipPath

   and SelectClipRgn, to further limit drawing to a particular portion of

   the update area.

Additional reference words: 3.10 3.50 4.00 SelectClipRegion big small large

KBCategory: kbprg kbprb

KBSubcategory: GdiMisc


PRB: Selecting Overlapping Controls in Dialog Editor

PSS ID Number: Q90384

Authored 13-Oct-1992	Last modified 24-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.1, 3.5,

   3.51, and 4.0

SYMPTOMS

Create a dialog box using the Dialog Editor. Place a button onto the dialog

box. Create a frame and place it so that it encompasses the button. It is

not possible to select that button with the mouse. However, if the frame is

created before the button and then moved or placed over the button, then it

is possible to select either the frame or the button.

CAUSE

This behavior is by design. When controls are overlapped, the control that

is selected when the mouse is clicked is the one that comes last in

Z-order.

As a special case, it is possible to select a control placed "underneath" a

group box.

RESOLUTION

From the Arrange menu, choose Order/Group. This will bring up a dialog box.

Change the Z-order of the button to be after that of the frame. The Z-order

may also be changed by manually editing the resource file. The controls

that are further down in the file will be "on top."

NOTE: If the frame is selected and is on top of the button, pressing

SHIFT+TAB selects the previous control, which will be the button. This does

not allow the position of the control to be changed with the mouse;

however, it does allow the text and size to be changed.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbtool kbprb

KBSubcategory: TlsDlg


PRB: SelectObject() Fails After ImageList_GetImageInfo()

PSS ID Number: Q131279

Authored 07-Jun-1995	Last modified 10-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) version 4.0

SYMPTOMS

When you try to select the hBitmap returned by ImageList_GetImageInfo()

into a device context, the call to SelectObject() fails and returns NULL.

CAUSE

Under the debug version of Windows 95, attempting to select the hBitmap

returned by ImageList_GetImageInfo() into a DC causes the GDI to output

the message "Bitmap already selected."

Image lists maintain memory DCs with the image and mask bitmaps already

selected. This is done to prevent applications from modifying the images

contained in the image list that are currently being used by the system.

Because a bitmap cannot be selected into more than one DC at a time,

applications that call SelectObject() on the same bitmap fail.

RESOLUTION

An application can work around this in Windows 95 by calling CopyImage() on

the hBitmap, as demonstrated in the following sample code. This API is new

for Windows 95. Remember to delete the hBitmap copy when using this

function.

Sample Code

-----------

HDC        hDC;

HBITMAP    hBitmap, hOldBitmap;

IMAGEINFO  imageInfo;

ImageList_GetImageInfo (hImgList, iWhichImage, &imageInfo);

hBitmap = CopyImage (imageInfo.hbmImage,

                     IMAGE_BITMAP, 0, 0, LR_COPYRETURNORG);

hOldBitmap = SelectObject(hDC, hBitmap);

  :

  :

// Delete hBitmap when you finish using it.

DeleteObject (SelectObject (hDC, hOldBitmap));

STATUS

This behavior is by design.

Additional reference words: 4.00 unusable hDC Image Lists beta

KBCategory: kbprg kbgraphic kbprb kbcode

KBSubcategory: UsrCtl


PRB: SetConsoleOutputCP() Not Functional

PSS ID Number: Q99795

Authored 08-Jun-1993	Last modified 03-Mar-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   versions 3.1 and 3.5

SYMPTOMS

SetConsoleOutputCP() apparently has no effect. The correct codepage is

returned from a call to GetConsoleOutputCP, but the displaying of the text

remains unchanged.

CAUSE

SetConsoleOutputCP() was designed to change the mapping of the 256 8-bit

character values into the glyph set of a fixed-pitch Unicode font, rather

than loading a separate, non-Unicode font for each call to

SetConsoleOutputCP(). Unfortunately, a fixed-pitch Unicode font was not

available by release time, so you can't view the effects of the

SetConsoleOutputCP() application programming interface (API) because the

currently available console fonts are not Unicode fonts.

STATUS

This behavior is by design in Windows NT versions 3.1 and 3.5.

Additional reference words: 3.10 3.50

KBCategory: kbprg kbprb

KBSubcategory: BseCon


PRB: SetCurrentDirectory Fails on a CD-ROM Drive on Win32s

PSS ID Number: Q125013

Authored 19-Jan-1995	Last modified 20-Jan-1995

--

The information in this articles applies to:

 - Microsoft Win32s, versions 1.0, 1.1, and 1.2

--

SYMPTOMS

In the following code, assuming that drive E corresponds to a CD-ROM drive,

SetCurrentDirectory() always fails to set the current directory to the root

directory on the CD-ROM drive. Instead the current directory remains

unchanged:

   char szCurDir[256];

   SetCurrentDirectory("E:\\");

   GetCurrentDirectory(sizeof(szCurDir),szCurDir);

   MessageBox(NULL, szCurDir, "SCD", MB_OK);

CAUSE

SetCurrentDirectory() calls the MS-DOS Interrupt 21h, function 0x4300 to

get the file attributes of the specified drive to check whether the

specified parameter is a directory. This MS-DOS call always fails if you

try to get the attributes of the root directory on a CD-ROM drive, and

therefore SetCurrentDirectory() also fails on the root directory of a CD-

ROM drive.

STATUS

Microsoft is aware of this problem with SetCurrentDirectory() in Win32s. We

are researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

RESOLUTION

As a workaround for the problem with SetCurrentDirectory(), thunk to the 16-

bit environment and utilize MS-DOS functions from a 16-bit DLL. For

example, you can use Interrupt 21h, function 0x0E (Set Default Drive)

followed by Interrupt 21h, function 0x3Bh (Change Current Directory).

MORE INFORMATION

Note that SetCurrentDirectory() fails only on the root directory of a CD-

ROM drive. If you pass any directory path other than the root directory to

SetCurrentDirectory(), it will work properly.

This is a problem with MS-DOS and can be reproduced from an MS-DOS

application in Windows version 3.1.

Additional reference words: 1.00 1.10 1.20 win32s

KBCategory: kbprg kbprb

KBSubcategory: W32s


PRB: Setup Toolkit File Copy Progress Gauge not Updated

PSS ID Number: Q114609

Authored 08-May-1994	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

 - Microsoft Win32 SDK, versions 3.1, 3.5, 3.51, and 4.0

SYMPTOMS

The following may be noticed during the execution of a setup program

created with the Setup Toolkit:

1. The copy progress bar appears frozen even though the user may be

   prompted to change disks.

2. The filename shown at the top of the copy progress dialog box does

   not change for long periods of time.

CAUSE

The "gas gauge" copy progress dialog box (or Copy Gauge dialog box

described on pages 106-107 of the "Setup Toolkit for Windows" manual) is

updated only when files are actually being copied to the hard disk. The

Setup Toolkit does not update the copy progress dialog box when it checks

the version of an existing file. This version check can take a significant

amount of time under certain circumstances. A version check is only

performed if "Check For Version" is marked in the DSKLAYT program AND the

file has a version information resource.

RESOLUTION

There is no way to change this behavior. The dialog box is managed by

CopyFilesInCopyList(). The only way to avoid this behavior is to avoid

marking files with "Check For Version" in DSKLAYT.

MORE INFORMATION

Under certain circumstances, a file may need to be copied to the temporary

directory before its version can be checked. This occurs when the version

information in the .INF file matches the version information (exactly) in

the file already residing on the hard drive. In this case, the file will be

copied from the Setup disks to a temporary location (decompressed if

necessary), and other version information will be verified. This can be a

time-consuming process and the copy progress dialog box will not be updated

while this is occurring.

Additional reference words: 3.10 3.50 4.00 95  MSSETUP CopyFilesInCopyList

KBCategory: kbtool kbprg kbprb

KBSubcategory: TlsMss


PRB: SetWindowsHookEx() Fails to Install Task-Specific Filter

PSS ID Number: Q92659

Authored 12-Nov-1992	Last modified 13-Jun-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SYMPTOMS

In Windows version 3.1, the SetWindowsHookEx() function fails when

it is called to install a task-specific filter (hook) that resides

in a DLL.

CAUSE

According to the documentation, the third parameter to the

SetWindowsHookEx() function must be the instance handle of the

application or the DLL that contains the filter function. However,

because of a problem in Windows 3.1, the SetWindowsHookEx() function

fails when it is called to install a task-specific filter using the

DLL's instance handle.

Note that such a problem does not exist when the SetWindowsHookEx()

function is called to install a system-wide filter in a DLL. The DLL's

instance handle is accepted as a valid parameter. The first argument

passed to the LibMain function of a DLL contains its instance handle.

RESOLUTION

To install a task-specific filter that resides in a DLL, pass the module

handle of the DLL as the third parameter to the SetWindowsHookEx()

function. The module handle can be retrieved using the GetModuleHandle()

function. For example, to install a task-specific keyboard filter, the

code might resemble the following:

g_hHook = SetWindowsHookEx( WH_KEYBOARD,

                   HookCallbackProc,

                   GetModuleHandle( "HOOK.DLL" ),

                   hTargetTask );

This resolution is compatible with future versions of Windows.

Additional reference words: 3.10 3.50 3.51 4.00 95  hook not allowed

KBCategory: kbprg kbprb kbcode

KBSubcategory: UsrHks


PRB: ShellExecute() Succeeds But App Window Doesn't Appear

PSS ID Number: Q124133

Authored 19-Dec-1994	Last modified 21-Dec-1994

The information in this article applies to:

 - Microsoft Win32s, versions 1.15, 1.15a, and 1.2

SYMPTOMS

The following call to ShellExecute() succeeds and the file association

is set in File Manager, but the application does not appear to execute

(the window is not shown):

   hShell = ShellExecute( hWnd,

                          NULL,

                          lpszFile,

                          NULL,

                          lpszDir,

                          SW_SHOWDEFAULT );

CAUSE

ShellExecute() is directly thunked to 16-bit Windows. Windows-based

applications do not support the SW_SHOWDEFAULT flag.

RESOLUTION

Under Win32s, use SW_NORMAL instead of SW_SHOWDEFAULT when using

ShellExecute() with a 16-bit Windows-based application. You can use

SW_SHOWDEFAULT if the application specified is a Win32-based application.

STATUS

This behavior is by design.

Additional reference words: 1.20

KBCategory: kbprg kbprb

KBSubcategory: W32s


PRB: SNMP Extension Agent Gives Exception on Windows NT 3.51

PSS ID Number: Q130562

Authored 23-May-1995	Last modified 24-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.5 and 3.51

SYMPTOMS

An SNMP extension agent built using Windows NT version 3.5 SDK headers and

libraries generates an exception when run under Windows NT version 3.51.

For example, the SDK toaster sample (\MSTOOLS\SAMPLES\WIN32\SNMP\TESTDLL)

works under Windows NT version 3.5 but generates an exception under Windows

NT version 3.51.

CAUSE

The SNMP.LIB SDK library has changed between the release of Windows NT

version 3.5 and the release of Windows NT version 3.51. Memory is now

allocated dynamically with the Win32 API GlobalAlloc() rather than the

c-runtime malloc(). See the SNMP.H SDK header file for details.

An SNMP application that is allocating (or freeing) memory that is passed

to a function in SNMP.LIB should use SNMP_malloc() (or SNMP_free()). The

sample code for the extension DLL provided with the Windows NT version 3.51

beta SDK incorrectly uses malloc().

RESOLUTION

Rebuild the extension agent with the Win32 SDK headers and libraries for

Windows NT version 3.51. Please make sure that the Win32 SDK headers and

libraries are used before Visual C++ headers and libraries.

Also, to allocate and free any memory, use the SNMP_malloc() and

SNMP_free() macros. Both are defined in SNMP.H.

NOTE: If you are using a beta version of Windows NT version 3.51, please

change all references to malloc() and free() in the samples to

SNMP_malloc() and SNMP_free(). This is a known problem with the testdll

sample (MSTOOLS\SAMPLES\WIN32\WINNT\SNMP\TESTDLL).

STATUS

This behavior is by design.

REFERENCES

For more information, please see the following article in the Microsoft

Knowledge Base:

   ARTICLE-ID: Q124961

   TITLE     : BUG: SNMP Sample Generates an Application Error

Additional reference words: 3.50

KBCategory: kbnetwork kbprb

KBSubcategory: NtwkSnmp


PRB: SnmpMgrGetTrap() Fails

PSS ID Number: Q130564

Authored 23-May-1995	Last modified 24-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.5

SYMPTOMS

If an SNMP manager application calls SnmpMgrGetTrap() to recieve traps and

there are traps available, it returns FALSE. If the application calls

GetLastError(), the error code returned is 42 (SNMP_MGMTAPI_TRAP_ERRORS).

RESOLUTION

The SNMP Manager API SnmpMgrGetTrapListen() must be called before calling

SnmpMgrGetTrap(). The event handle returned by SnmpMgrGetTrapListen() can

then be ignored to poll for traps.

STATUS

This behavior is by design.

REFERENCES

For more information, please see the Microsoft Windows NT SNMP Programmer's

Reference (PROGREF.RTF).

Additional reference words: 3.50

KBCategory: kbnetwork kbprb

KBSubcategory: NtwkSnmp


PRB: SnmpMgrStrToOid Assumes Oid Is in Mgmt Subtree

PSS ID Number: Q129063

Authored 18-Apr-1995	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

SYMPTOMS

When using the SNMP Manager API SnmpMgrStrToOid() and passing it a valid

Oid, the application is unable to get the requested variables.

CAUSE

The SNMP Manager API SnmpMgrStrToOid assumes that the Oid that is supplied

to it is under the internet MIB of the mgmt subtree (1.3.6.1.2.1.x).

RESOLUTION

To get variables that are not under the mgmt subtree, the Oid must be

preceeded by a period (.). For example, say an application is trying to get

the system group and the Oid passed to SnmpMgrStrToOid is this:

   1.3.6.1.2.1.1

Then the application will try to get the following, which does not exist:

   iso.org.dod.internet.mgmt.1.1.3.6.1.2.1.1

The correct way to get the system group is to pass this:

   .1.3.6.1.2.1.1

STATUS

This behavior is by design.

REFERENCES

Microsoft Windows/NT SNMP Programmer's Reference (PROGREF.RTF).

Additional reference words: 3.10 3.50

KBCategory: kbnetwork kbprb kbdocerr

KBSubcategory: NtwkSnmp


PRB: Special Characters Missing from Compiled Help File

PSS ID Number: Q86719

Authored 15-Jul-1992	Last modified 24-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SYMPTOMS

In version 2.0 of Microsoft Word for Windows, the RTF (rich-text format)

source file for a Microsoft Windows Help file contains curly (smart) single

or double quotation marks, bullets, or em or en dash characters. However,

even though the specified font contains these special characters, they are

missing when the compiled file is viewed in Help.

CAUSE

Word for Windows stores special RTF tokens for these characters, which the

Microsoft Windows Help Compiler cannot process.

RESOLUTION

In order to avoid these problems do one of the following:

   Format the character to use the Symbol font (without using

   Insert.Symbol).

   -or-

   Select the desired font (not Symbol) and choose the Symbol option from

   the Insert menu. Then choose Normal Text in the Symbols From list box.

   This will format the special character in the desired font.

   -or-

   Use a bitmap to represent the character or symbol. Use the "bmc"

   statement to include the bitmap into the text as a character. For more

   information on the bmc statement, see page 29 of the "Programming Tools"

   manual provided with version 3.1 of the Microsoft Windows SDK.

Additional reference words: 3.10 3.50 4.00 95 HC HC30.EXE HC31.EXE HCP.EXE

KBCategory: kbtool kbprg kbprb

KBSubcategory: TlsHlp


PRB: Spy Repeatedly Lists a Single Message

PSS ID Number: Q74278

Authored 15-Jul-1991	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SYMPTOMS

SPY sometimes reports messages as having been sent twice. Messages

from DDE conversations, especially the WM_DDE_DATA, WM_DDE_ACK, and

WM_DDE_POKE messages, are the most often duplicated. This behavior

can be seen by choosing All Windows from Spy's Windows menu,

selecting DDE messages in Spy's Options dialog, and then running

two applications that communicate using DDE.

CAUSE

Spy displays a message each time it is retrieved. If an application

retrieves a message once by calling PeekMessage() with PM_NOREMOVE,

and then again with GetMessage(), Spy will report it twice. Spy

cannot determine that the message was already retrieved by the

application. Since the application is using the message twice, the

message should indeed be shown twice. This is a useful feature for

determining how an application is handling the DDE messages sent to

it.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbtool kbprg kbprb

KBSubcategory: TlsSpy


PRB: Starting a Service Returns "Logon Failure" Error

PSS ID Number: Q120556

Authored 14-Sep-1994	Last modified 28-Nov-1994

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

SYMPTOMS

Starting a service from either the service control manager or from the

StartService API may return error 1069, "ERROR_SERVICE_LOGON_FAILED."

CAUSE

This error occurs if the service was started from an account that does not

have the "Log on a service" privilege.

RESOLUTION

An account can be granted the "Log on a service right" through the User

Manager Application. From the Policies menu, choose User Rights. In the

User Rights Dialog Box, select the "Show Advanced User Rights" check box.

Choose "Log on a service," in the "Right" scroll box. Then choose the Add

button to grant your account the "Log on a service" privilege.

Additional reference words: 3.10 3.50

KBCategory: kbprg kbprb

KBSubcategory: BseService


PRB: Successful LoadResource of Metafile Yields Random Data

PSS ID Number: Q86429

Authored 06-Jul-1992	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.1 and 3.0

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SYMPTOMS

When an application for the Microsoft Windows graphical environment

calls the LoadResource() function to load a metafile from the

application's resources, locks the metafile with the LockResource()

function, and uses the metafile, the application receives random

data even though the LoadResource() and LockResource() functions

indicate successful completion.

CAUSE

The application loaded the metafile previously and when the

application freed the metafile, it used the DeleteMetaFile() function

to invalidate the metafile handle.

RESOLUTION

Modify the code that unloads the metafile from memory to call the

FreeResource() function.

MORE INFORMATION

The LoadResource() and FreeResource() functions change the lock count

for a memory block that contains the resource. If the application

calls DeleteMetaFile(), Windows does not change the lock count. When

the application subsequently calls LoadResource() for the metafile,

Windows does not load the metafile because the lock count indicates

that it remains in memory. However, the returned memory handle points

to the random contents of that memory block.

For more information on the resource lock count, query in the

Microsoft Knowledge Base on the following words:

   multiple and references and LoadResource

Most of the time, an application uses the DeleteMetaFile() function to

remove a metafile from memory. This function is appropriate for

metafiles created with the CopyMetaFile() or CreateMetaFile()

functions, or metafiles loaded from disk with the GetMetaFile()

function. However, DeleteMetaFile() does not decrement the lock count

of a metafile loaded as a resource.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95  EnumMetaFile

GetMetaFile GetMetaFileBits PlayMetaFile PlayMetaFileRecord SetMetaFileBits

SetMetaFileBitsBetter

KBCategory: kbprg kbprb

KBSubcategory: UsrRsc


PRB: TAB Key, Mnemonics with FindText and ReplaceText Dialogs

PSS ID Number: Q96134

Authored 09-Mar-1993	Last modified 12-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SYMPTOMS

When implementing the FindText and/or ReplaceText common dialog box, the

dialog box is displayed but the TAB key and mnemonics do not work properly.

CAUSE

The FindText and ReplaceText common dialog boxes are modeless dialog boxes.

Therefore, a call to IsDialogMessage must be made in the application's main

message loop in order for the TAB key and mnemonics to work properly.

RESOLUTION

This problem can be corrected by adding a call to IsDialogMessage() in the

application's main message loop.

MORE INFORMATION

A typical message loop might resemble the following

   while (GetMessage(&msg,NULL,NULL,NULL))

     {

        if ( ghFFRDlg==NULL || !IsDialogMessage(ghFFRDlg, &msg) )

           {

              TranslateMessage(&msg);

              DispatchMessage(&msg);

           }

     }

where ghFFRDlg is a global window handle for the currently active modeless

common dialog box.

Additional reference words: 3.10 3.50 3.51 4.00 95

KBCategory: kbprg kbprb

KBSubcategory: UsrCmnDlg


PRB: TrackPopupMenu() on LoadMenuIndirect() Menu Causes UAE

PSS ID Number: Q75254

Authored 15-Aug-1991	Last modified 16-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SYMPTOMS

When LoadMenuIndirect() is used to create a menu from a menu template and

the menu handle is passed to TrackPopupMenu(), Windows reports an

unrecoverable application error (UAE). Windows NT and Windows 95 display

the floating pop-up menu as a vertical bar.

CAUSE

The menu handle returned from LoadMenuIndirect() does not point to a menu

with the MF_POPUP bit set.

RESOLUTION

The following code fragment demonstrates the correct procedure to "wrap"

the menu created by LoadMenuIndirect() inside another menu. This procedure

sets the MF_POPUP bit properly.

   hMenu1 = LoadMenuIndirect(lpMenuTemplate);

   hMenuDummy = CreateMenu();

   InsertMenu(hMenuDummy, 0, MF_POPUP, hMenu1, NULL);

   hMenuToUse = GetSubMenu(hMenuDummy, 0);

Use hMenuToUse when TrackPopupMenu() is called. The values of hMenu1 and

hMenuToUse should be the same.

When the menu is no longer required, call DestroyMenu() to remove

hMenuDummy. This call will also destroy hMenu1 and free the resources it

used.

Additional reference words: 3.00 3.10 3.50 4.00 gpf

KBCategory: kbprg kbprb kbcode

KBSubcategory: UsrMen


PRB: Unable to Choose Kanji Font Using CreateFontIndirect

PSS ID Number: Q119914

Authored 29-Aug-1994	Last modified 06-Apr-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Japanese

   Windows 95

SYMPTOMS

You have difficulty getting the Japanese font handle in Microsoft Win32

Software Development Kit (SDK) for Japanese Windows 95. If you use

CreateFontIndirect() to create the font handle, only the English font is

selected. You are unable to select Kanji (the main system

of writing in Japan) fonts such as MS Mincho and MS Gothic.

CAUSE

The lfCharSet field in the LOGFONT structure is not set to

"SHIFTJIS_CHARSET".

RESOLUTION

Specify SHIFTJIS_CHARSET as the value for lfCharSet field.

MORE INFORMATION

In Windows 95, Japanese fonts cannot be selected without the lfCharSet

field being set to SHIFTJIS_CHARSET. This standard was not enforced in

Japanese Windows NT and Japanese Windows 3.1, So an application with

lfCharSet set to a value other than SHIFTJIS_CHARSET might be able to

select Japanese fonts under Japanese Windows NT and Japanese Windows

version 3.1 using CreateFontIndirect(), but not under Japanese Windows 95.

ShiftJIS is a double-byte character set (DBCS) unique to the Japanese

version of Windows NT, Windows 95, and Windows version 3.1. It requires

a specialized font, keyboard input, and DBCS string-handling support.

Additional reference words: 4.00 kbprb

KBCategory: kbprg kbprb

KBSubcategory: GdiFnt WIntlDev


PRB: Unexpected Result of SetFilePointer() with Devices

PSS ID Number: Q98892

Authored 18-May-1993	Last modified 28-Nov-1994

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

SYMPTOMS

Open a floppy drive with CreateFile():

   h = CreateFile( "\\\\.\\a:", ... );

Use SetFilePointer() to advance the file pointer associated with the file

handle returned from CreateFile():

   SetFilePointer( h,    // file handle

                   5,    // distance (in bytes) to move file pointer

                NULL,    // optional high 32-bits of distance

          FILE_BEGIN     // specifies the starting point

   );

If the offset is not a multiple of the sector size of the floppy drive, the

function will return success; however, the pointer will not be exactly

where requested. The pointer value is rounded down to the beginning of the

sector that the pointer value is in.

CAUSE

The behavior of this application programming interface (API) is by design

for the following reasons:

 - The I/O system is unaware of device particulars such as sector

   size; any offset is valid.

 - SetFilePointer() is very frequently used. Because speed is an

   important goal for Windows NT, time is not spent on querying

   device particulars and detecting such errors.

 - The logic to handle this situation is built into the file system,

   which actually performs the rounding, and therefore there was no

   need to put this into the code for SetFilePointer().

RESOLUTION

When using SetFilePointer() with a handle that represents a floppy drive,

the offset must be a multiple of the sector size for the floppy drive in

order for the function to perform as expected.

MORE INFORMATION

Think of a file pointer as merely a stored value, which is where the next

read or write will take place. In fact, it is possible to override this

value on either the read or write itself, using certain APIs, by supplying

a different location. The new pointer location is remembered after the

operation. Therefore, the operation of "setting a file pointer" merely

means to go store a large integer in a cell in the system's data

structures, for possible use in the next file operation. In the case of a

handle to a device, the file pointer must be on a sector boundary.

In a similar way, ReadFile() only reads amounts that are multiples of the

sector size if it is passed a handle that represents a floppy drive.

Additional reference words: 3.10

KBCategory: kbprg kbprb

KBSubcategory: BseFileio


PRB: Unicode ChooseColor() Help Button May Crash Common

PSS ID Number: Q102026

Authored 27-Jul-1993	Last modified 24-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   versions 3.1, 3.5, and 3.51

SYMPTOMS

A Unicode compiled program, or a program that explicitly calls the

ChooseColorW() function, may suffer an access violation in the common

dialog boxes if the Help button in the ChooseColor() dialog box is chosen.

CAUSE

This problem may not be 100-percent reproducible. Because of the way that

the program loader loads code into memory, a certain address referenced by

the common dialog box Help button logic may or may not be valid depending

on what other applications have been run, what application is calling

ChooseColorW(), and the order in which these programs are run.

WORKAROUND

The following are suggested workarounds:

 - Try running an ANSI-compiled application that uses the common

   dialog boxes, and open one of the common dialog boxes before you run

   the application having this problem.

 - A workaround for new applications developers is to call

   ChooseColorW() with a hook function (see the Windows Software

   Development Kit documentation for more information on common dialog

   box hook functions), handle the Help button logic, and return TRUE

   from the hook function to bypass the standard common dialog box

   push-button code.

Additional reference words: 3.10 3.50

KBCategory: kbprg kbprb

KBSubCategory: UsrCmnDlg


PRB: UnrealizeObject() Causes Unexpected Palette Behavior

PSS ID Number: Q86800

Authored 16-Jul-1992	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SYMPTOMS

In an application for the Microsoft Windows graphical environment,

when a logical palette (HPALETTE) is used with a device-dependent

bitmap (DDB) and the application realizes the palette, the DDB is

painted in incorrect colors.

CAUSE

The UnrealizeObject function was previously called to unrealize the

palette.

RESOLUTION

Modify the code to remove the call to UnrealizeObject()/

MORE INFORMATION

Because the colors of a DDB are stored using indices into the system

palette rather than explicit RGB colors, proper DDB rendering depends

on the colors of the system palette being set properly. An application

sets up the system palette to display a DDB by realizing a logical

palette. The realization process changes the colors in the system

palette and creates a mapping between entries in the logical palette

and entries in the system palette.

When an application first renders a logical palette with RealizePalette(),

Windows sets an internal flag to indicate that the palette has been

realized and stores the current mapping from logical palette entries to

physical palette entries. When an application realizes the palette again

(for example, after another application modifies the palette), Windows

restores the effected entries of the system palette to the state they had

when the logical palette was realized for the first time.

This mechanism allows a bitmap first realized with a specific palette

to display correctly when the same palette is realized subsequently.

If the application calls UnrealizePalette() on a logical palette,

Windows discards the stored state information for the palette. If the

application realizes the palette subsequently, its colors may map into

new locations in the system palette. Because the bitmap contains

indices into the old system palette, it may display incorrectly.

To address this situation, do not call UnrealizeObject() on a palette if

the application has a DDB that depends on that palette.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg kbprb

KBSubcategory: GdiPal


PRB: Vertical Scroll Bars Missing from Windows Help

PSS ID Number: Q77841

Authored 28-Oct-1991	Last modified 24-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SYMPTOMS

The vertical scroll bars do not appear in Windows Help when the

window is sized smaller than the amount of text being displayed.

CAUSE

The displayed topic is formatted as a nonscrolling region.

RESOLUTION

Select the topic in the RTF editor and turn off the "Keep Paragraph

with Next" formatting. This format is used by the Help Compiler to

delimit the nonscrolling regions.

MORE INFORMATION

To remedy the situation in Microsoft Word for Windows, perform the

following three steps:

1. Highlight the entire topic.

2. From the Format menu, choose Paragraph.

3. In the Format Paragraph dialog box, cancel the "With Next" check box.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbtool kbprg kbprb

KBSubcategory: TlsHlp


PRB: Video for Windows Skips AVI Frames

PSS ID Number: Q122775

Authored 13-Nov-1994	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SYMPTOMS

When Video For Windows is playing an AVI file, the processing power of the

computer system and the data rate of the AVI stream determine whether

frames will be skipped during playback. If the data rate exceeds the

ability of Video For Windows to render all the AVI frames in time, Video

For Windows will first try to catch up by decompressing delta frames but

not drawing them. If Video For Windows still can't catch up, it will

eventually skip all the way to the next key frame before it renders a new

frame.

STATUS

This behavior of Video for Windows is by design and cannot be controlled by

the application being affected.

Additional reference words: 3.10 3.50 4.00 95  VfW AVI

KBCategory: kbmm kbprb

KBSubcategory: MMVideo


PRB: Win32-Based Screen Saver Shows File Name in Control

PSS ID Number: Q126239

Authored 16-Feb-1995	Last modified 22-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1 and 3.5

SYMPTOMS

After writing a Win32-based screen saver, if the IDS_DESCRIPTION string is

missing from the string table, the file name of the screen saver module is

displayed in the desktop control panel applet. This happens even if the

DESCRIPTION entry is specified in the .DEF file of the module.

CAUSE

Each Windows screen saver has a name, which is a string packed into the

screen saver module by the linker. This name is displayed in the screen

saver name drop down list box under the desktop applet in the control

panel. The user can select different screen savers for the desktop through

this list box.

Under 16-bit Windows, the name of a screen saver is specified by the

DESCRIPTION entry in the .DEF file. Under Windows NT, this is no longer

true. Instead, a special entry in the string table is used to specify the

name of a screen saver. This string must have IDS_DESCRIPTION as its

string ID. IDS_DESCRIPTION is defined in SCRNSAVE.H.

If the DESCRIPTION entry is missing from the .DEF file for a 16-bit screen

saver, or the IDS_DESCRIPTION is missing from the string table for a 32-bit

screen saver, Windows NT displays the file name of the screen saver module

in the drop down list box in the Desktop control panel applet.

RESOLUTION

Place the DESCRIPTION entry in .DEF file for a 16-bit screen saver, or

place the IDS_DESCRIPTION in the string table for a 32-bit screen saver.

STATUS

This behavior is by design.

REFERENCES

Chapter 14, "Screen Saver Library," Microsoft Windows Software Development

Kit, version 3.1, Programmer's Reference, Volume 1: Overview.

Chapter 79, "Screen Saver Library," Microsoft Win32 Programmer's Reference,

Volume 2: System Services, Multimedia, Extensions, and Application Notes.

Additional reference words: 3.10 3.50

KBCategory: kbprg kbprb

KBSubcategory: GdiScrsav


PRB: Win32s GetVolumeInformation() Returns 0x12345678 or 0

PSS ID Number: Q93639

Authored 17-Dec-1992	Last modified 07-Dec-1994

The information in this article applies to:

 - Microsoft Win32s version 1.0, 1.1, 1.15, and 1.2

SYMPTOMS

In Win32s version 1.0 and 1.1, GetVolumeInformation() always returns a

volume ID of 0x12345678. In Win32s version 1.15 and later, the return is 0.

STATUS

This is a known limitation of Win32s and is by design.

Additional reference words: 1.00 1.10 1.20

KBCategory: kbprg kbprb

KBSubcategory: W32s


PRB: Windows REQUEST Function Not Working With Excel

PSS ID Number: Q26234

Authored 18-Dec-1987	Last modified 12-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SYMPTOMS

The REQUEST function does not work correctly with Excel. The

request message is received, however, Excel does not process the

WM_DDE_DATA message that is sent back.

RESOLUTION

The fResponse bit must also be set in the WM_DDE_DATA message (bit

12). This bit tells Excel that the data message is in reply to a

REQUEST function and not an ADVISE function. If

"lpddeup->fResponse=1" is added, the REQUEST function should work

correctly.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg kbprb

KBSubcategory: UsrDde


PRB: WinExec() Fails Due to Memory Not Deallocated

PSS ID Number: Q126710

Authored 28-Feb-1995	Last modified 03-Mar-1995

The information in this article applies to:

 - Microsoft Win32s, versions 1.15, 1.2, and 1.25

SYMPTOMS

Under Win32s version 1.15, when a Win32-based application spawns a 16-bit

application several times using WinExec(), after a few successful spawns,

WinExec() fails.

Each time WinExec() is called to start a 16-bit application, Win32s

allocates a fixed and pagelocked block. The owner of this block is the

Win32-based application. The memory is not deallocated when the 16-bit

application is terminated, only when the 32-bit application is

terminated.

CAUSE

This is actually a bug in Windows version 3.1. The 32-bit WinExec() calls

the 16-bit LoadModule(). Win32s passes the environment of the calling

process to LoadModule(). Then the Windows 3.1 LoadModule() allocates a

buffer for the environment, copies this environment to the buffer, and

passes this buffer to the child process. The problem is that the owner of

the new allocated buffer is the parent, so the memory is freed when the

parent exits. There is no code for otherwise freeing the memory. This bug

also affects 16-bit Windows-based applications if LoadModule() is called

with an environment selector that is not NULL.

In a related problem, when the parent terminates, the child's environment

becomes invalid. This may cause a general protection (GP) fault.

RESOLUTION

To work around the problem, you can call the Windows version 3.1 WinExec()

through the Universal Thunk. However, the parent will not be able to modify

the child's environment.

In Win32s version 1.2x, this problem exists only if you start 16-bit

application using CreateProcess() or LoadModule() and pass it explicit

environment strings. In this case, you will encounter the Windows version

3.1 bug. If you do not pass an explicit environment, the environment passed

to the 16-bit application is NULL. This resolves the problems mentioned in

the Symtpoms and Cause sections of this article.

MORE INFORMATION

With the changes in Win32s version 1.2x, if the calling application

modifies the environment, the child process will not get the modified

environment of the parent. It will get the global MS-DOS environment. This

is also true for WinExec().

If you need to pass a modified environment, call LoadModule() or

CreateProcess() with the environment set to what GetEnvironmentStrings()

returns. Be aware that this will cause a memory leak. In addition, if the

parent terminates before the child, the child's environment will become

invalid.

Additional reference words: 1.20 GPF

KBCategory: kbprg kbprb

KBSubcategory: W32s


PRB: WINS.MIB & DHCP.MIB Files Missing from Win32 SDK 3.5

PSS ID Number: Q121625

Authored 12-Oct-1994	Last modified 20-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.5

SYMPTOMS

Two Simple Network Management Protocol (SNMP) files (WINS.MIB and DHCP.MIB)

are missing from the currently released version of the Win32 SDK for

Windows NT version 3.5.

The files are two Management Information Base (MIB) files for WINS and DHCP

SNMP usage. The two files (WINS.MIB and DHCP.MIB) are used in the

generation of a MIB.BIN file for use with the NT SNMP Extendible Agent

Management API.

RESOLUTION

Only developers working on SNMP programming using the SNMP Extendible Agent

Management API will need these two .MIB files. To get the two .MIB files:

Download NEWMIB.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for NEWMIB.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download NEWMIB.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the SOFTLIB\MSLFILES directory

      Get NEWMIB.EXE

The two missing .MIB files will be included with the next release of the

Win32 SDK for Windows NT version 3.5.

All licensing and redistribution agreements from the Win32 SDK for Windows

NT version 3.5 also apply to these .MIB files. Please consider the two .MIB

files part of the Win32 SDK. Please see your licensing agreement for the

Win32 SDK for more details.

Additional reference words: 3.50 softlib

KBCategory: kbprg kbfile kbprb

KBSubcategory: NtwkSnmp


PRB: WSAAsyncSelect() Notifications Stop Coming

PSS ID Number: Q94088

Authored 23-Dec-1992	Last modified 26-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SYMPTOMS

I have set a WSAAsyncSelect() call to notify me of read (FD_READ) and

disconnection (FD_CLOSE). When a read call is posted on my message

queue, I continually read from the socket until there are no more

characters waiting. After each read, I use a select() call to determine

if more data needs to be read. However, after a while, the notifications

stop coming. Why is this?

CAUSE

The message queue must be cleared of extraneous notification messages

for each read notification message.

RESOLUTION

Call WSAAsyncSelect( sockt, hWnd, 0, 0) to clear the message queue for

each read notification.

MORE INFORMATION

Sample Code

-----------

WSA_READCLOSE:

  if (WSAGETSELECTEVENT( lParam ) == FD_READ) {

    FD_ZERO( &readfds );

    FD_SET( sockt, &readfds);

    timeout.tv_sec = 0;

    timeout.tv_usec = 0;

    /* Clear the queue of any extraneous notification messages. */

    WSAAsyncSelect( sockt, hWnd, 0, 0);

    while (select(0, &readfds, NULL, NULL, &timeout) != 0) {

      recv(sockt, &ch, 1, 0);

      }

    /* Reset the message notification. */

    WSAAsyncSelect( sockt, hWnd, WSA_READCLOSE, FD_READ | FD_CLOSE);

    }

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg kbprb

KBSubcategory: NtwkWinsock


PRB: WSAStartup() May Return WSAVERNOTSUPPORTED on Second

PSS ID Number: Q130942

Authored 30-May-1995	Last modified 23-Jun-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

 - Microsoft Win32 Software Development Kit (SDK) versions 3.1,

   3.5, 3.51, and 4.0

SYMPTOMS

If two sections of code within the same process call WSAStartup(), the

second call to WSAStartup() fails and returns error WSAVERNOTSUPPORTED

unless the second call specifies the version negotiated in the first call.

This happens even if the requested version would normally be accepted.

Often the extra calls to WSAStartup() come from one or more DLLs loaded by

the process.

RESOLUTION

If multiple calls are made to WSAStartup(), the second call must request

the same version negotiated in the first call.

MORE INFORMATION

Some specific examples may help. Currently, if the version of Winsock

requested is 1.1 or greater, the negotiated version will be 1.1. If a

version less than 1.1 is requested, the call fails and returns the

WSAVERNOTSUPPORTED error.

Example One

-----------

First call : 1.1 requested

Second call: 1.1 requested

Result     : Success

Example Two

-----------

First call : 2.0 requested

Second call: 1.1 requested

Result     : Success

Example Three

-------------

First call : 2.0 requested

Second call: 2.0 requested

Result     : WSAVERNOTSUPPORTED

Example Four

------------

First call : 1.1 requested

Second call: 2.0 requested

Result     : WSAVERNOTSUPPORTED

Additional reference words: 3.50 4.00 95 3.10

KBCategory: kbprg kbprb

KBSubcategory: NtwkWinsock


PRB:Scroll Bar Continues Scrolling After Mouse Button

PSS ID Number: Q102552

Authored 04-Aug-1993	Last modified 12-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0, 3.1,

   and 4.0

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SYMPTOMS

The scroll bar continuously scrolls even after the left mouse button

is released. The type of scroll bar is irrelevant to this problem,

that is, the same problem occurs regardless of whether the scroll bar

is part of the window or is a scroll bar control.

CAUSE

This problem occurs usually when a message retrieval loop is executed

as the result of actions taken for scrolling upon receiving one of the

scroll bar notification messages.

When scrolling, an internal message retrieval loop is started in

Windows. The task of this message loop is to keep track of scrolling

and to send the appropriate scroll bar notification messages,

WM_HSCROLL and WM_VSCROLL. Scrolling is terminated once WM_LBUTTONUP

is received. If another message loop is started during scrolling, the

WM_LBUTTONUP is retrieved by that message loop, and because an

application does not have access to the scroll bar's internal message

retrieval loop, WM_LBUTTONUP cannot be dispatched correctly.

Therefore, the WM_LBUTTONUP is never received by the internal message

retriever, and scrolling is never ended.

The application that is scrolling does not have to retrieve messages

explicitly to cause this problem. Calling any of the following

functions or processing any message that has a message retrieval loop,

while scrolling, can cause the WM_LBUTTONUP to be lost. The functions

listed below fall into this category:

   DialogBox()

   DialogBoxIndirect()

   DialogBoxIndirectParam()

   DialogBoxParam()

   GetMessage()

   MessageBox()

   PeekMessage()

RESOLUTION

While Scrolling, the WM_LBUTTONUP message should not be retrieved from

the queue by any message retrieval loop other than the scroll bar's

internal one.

An application may come across this problem as follows:

 - An application implements a message retrieval loop to implement

   background processing, for example, background processing while

   performing a time consuming paint.

 - An application implements a message retrieval loop to implement

   communication with another application or DLL. For example, in

   order to scroll, the application needs to receive data from

   elsewhere.

Possible Workarounds

--------------------

Two possible workarounds are listed below. The first workaround is

used by many exiting applications and by Windows; however, under rare

circumstances the first workaround may not be a feasible one. In this

case, the second workaround may be used. However, if possible, please

try to avoid implementing message retrieval completely while

scrolling.

 - Use timer-message-based processing. Break down the complicated

   processing into smaller tasks and keep track of where each task

   starts and ends, then perform each task based on a timer message.

   When all components of the processing are complete, kill the timer.

   See below for an example of this workaround.

 - Implement a message retrieval loop, but make sure WM_LBUTTONUP is

   not retrieved by it. This can be accomplished by using filters. See

   below for some examples of this workaround.

Example Demonstrating Workaround 1

----------------------------------

An application has a complex paint procedure. Calling ScrollWindow(), to

scroll, generates paint messages. Background processing takes place

while painting.

1. When receiving the WM_PAINT message do the following:

   a. Call BeginPaint().

   b. Copy the invalidated rect to a global rect variable (for

      example, grcPaint) to be used in step 2. The global rect

      grcPaint would be a union of the previously obtained rect

      (grcPaint) and the new invalidated rect (ps.rcPaint). The code

      for this will resemble the following:

         RECT grcPaint;    // Should be initialized before getting the

                           // first paint message.

            :

            :

         UnionRect(&grcPaint, &ps.rcPaint,&grcPaint);

   c. Call ValidateRect() with ps.rcPaint.

   d. Call EndPaint().

   e. Set a Timer.

   This way, no more WM_PAINT messages are generated, because there

   are no invalid regions, and a timer is set up, which will generate

   WM_TIMER messages.

2. Upon receiving a WM_TIMER message, check the global rect variable;

   if it is not empty, take a section and paint it. Then adjust the

   global rect variable so it no longer includes the painted region.

3. Once the global rect variable is empty then kill the timer.

Example Demonstrating Workaround 2

----------------------------------

An application needs to obtain some data through DDE or some other

mechanism from another application, which is then displayed in the

window. In order to scroll, the application needs to request and then

obtain the data from a server application.

There are three different filters that can be used to set up a

PeekMessage() and get the information. The filters can be set up by

using the uFilterFirst and uFilterLast parameters of PeekMessage().

uFilterFirst specifies the fist message in the range to be checked and

uFilterLast specifies the last message in the range to be checked. For

more information on PeekMessage() and its parameters, see the Windows

SDK "Programmer's Reference, Volume 2: Functions" for version 3.1 and

"Reference, Volume 1" for version 3.0.

1. Check and retrieve only the related message(s) for obtaining the

   needed data.

2. Check for WM_LBUTTONUP without removing it form the queue; if it is

   in the queue, break. Otherwise, retrieve and dispatch all messages.

3. Retrieve all messages less than WM_LBUTTONUP and greater than

   WM_LBUTTONUP, but do not retrieve WM_LBUTTONUP.

MORE INFORMATION

Steps to Reproduce Behavior

---------------------------

The following is the sequence of events leading to the loss of

the WM_LBUTTONUP message:

1. Click the scroll bar using the mouse.

2. Step 1 generates a WM_NCLBUTTONDOWN message.

3. Step 2 causes a Windows internal message loop to be started. This

   message loop looks for scroll-bar-related messages. The purpose of

   this message loop is to generate appropriate WM_HSCROLL or

   WM_VSCROLL messages. The message loop and scrolling terminates once

   WM_LBUTTONUP is received.

4. When receiving the WM_HSCROLL or WM_VSCROLL message, the application

   either gets into a message retrieval loop directly or calls functions

   which result in retrieval of messages.

5. WM_LBUTTONUP is removed from the queue by the message loop

   mentioned in step 4. WM_LBUTTONUP is then dispatched.

6. As result of step 5 WM_LBUTTONUP message is dispatched elsewhere

   and the internal message retrieval loop, mentioned in step 3 never

   receives it. The message loop in step 3 is looking for the

   WM_LBUTTONUP to stop scrolling. Because it is not received, the

   scroll bar continues scrolling.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95 scrollbar stuck

KBCategory: kbprg kbprb

KBSubcategory: UsrCtl


PRB:Unselecting Edit Control Text at Dialog Box

PSS ID Number: Q96674

Authored 24-Mar-1993	Last modified 23-Jun-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK, versions 3.50, 3.51, and 4.0

SYMPTOMS

To remove the highlight (selection) from an edit control text, an EM_SETSEL

message must be sent to the control. However, while processing the

WM_INITDIALOG message of a dialog box, sending an EM_SETSEL fails to remove

the highlight from (unselect) the edit control text.

CAUSE

While processing the WM_INITDIALOG message, sending the EM_SETSEL message

fails to remove the highlight from the edit control. This happens because

the edit control has not yet been drawn. Because it's not drawn and there

is no selection information available to the edit control's procedure, the

EM_SETSEL message is ignored. In other words, the SendMessage() function

passes the EM_SETSEL message too early to the edit control for it to become

effective.

RESOLUTION

There are two solutions to the above problem.

Solution 1

----------

Use SetFocus() to set the input focus on the edit control. Use

PostMessage() to post the EM_SETSEL message to the edit control rather than

using SendMessage() and return FALSE from the WM_INITDIALOG handler.

Solution 2

----------

When a newly created dialog box is displayed with focus on an edit control,

the default text of the edit control is shown highlighted. In some cases,

the text highlighting is undesirable because accidentally pressing a

character key removes the original text from the edit control. Therefore,

the workaround is to unselect the text by sending an EM_SETSEL message to

the edit control at the dialog box initialization.

Delay the EM_SETSEL message until the focus is set to the edit control.

That is, while processing the first EN_SETFOCUS notification message, an

EM_SETSEL message must be sent to the edit control to remove the highlight

from its text. For example:

   static  BOOL    bFirstTime;   // We want to unselect only once.

   switch ( message )

   {

       case WM_INITDIALOG:

           bFirstTime = TRUE;

           return TRUE;

       case WM_COMMAND:

           switch ( wParam )

           {

               case IDC_EDIT:

                   // If this is the first time, then unselect.

                   if ( HIWORD( lParam ) == EN_SETFOCUS &&

                       bFirstTime )

                   {

                      SendMessage(GetDlgItem( hwndDialog, IDC_EDIT ),

                                  EM_SETSEL, 0,

                      MAKELPARAM( -1, -1 ));

                      bFirstTime = FALSE;

                   }

                   break;

           .

           .

           .

           }  // switch ( wParam )

      .

      .

      .

   } // switch ( message )

Additional reference words: 3.10 3.50 3.51 4.00 95

KBCategory: kbprg kbprb

KBSubcategory: UsrCtl


Precautions When Passing Security Attributes

PSS ID Number: Q94839

Authored 19-Jan-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

SUMMARY

All Win32 APIs that allow security to be specified take a parameter of type

LPSECURITY_ATTRIBUTES as the means to attach the security descriptor.

However, it is a common error to pass a PSECURITY_DESCRIPTOR type to such

functions instead. Because PSECURITY_DESCRIPTOR is of type LPVOID (for

opaque data-type reasons), by C Language definition, it is implicitly

converted to the correct type. Therefore, the compiler does not generate

any warnings; however, unexpected run-time errors will result.

MORE INFORMATION

Below is a correct example of creating a named pipe with a security

descriptor attached.

Sample Code

-----------

   saSecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);

   saSecurityAttributes.lpSecurityDescriptor = psdAbsoluteSD;

   saSecurityAttributes.bInheritHandle = FALSE;

   hPipe = CreateNamedPipe(TEST_PIPE_NAME,

                           PIPE_ACCESS_DUPLEX,

   (PIPE_TYPE_BYTE|PIPE_READMODE_BYTE|PIPE_WAIT),

                           100,  // maximum instances

                           0,    // output buffer, sized as needed

                           0,    // input buffer, sized as needed

                           100,  // timeout in milliseconds

   (LPSECURITY_ATTRIBUTES)&saSecurityAttributes);

   if( INVALID_HANDLE_VALUE == hPipe )

   { // handle error

   }

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseSecurity


Preventing Screen Flash During List Box Multiple Update

PSS ID Number: Q66479

Authored 26-Oct-1990	Last modified 18-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.1 3.5, 3.51, and 4.0

SUMMARY

The WM_SETREDRAW message can be used to set and clear the redraw flag for a

window. Before an application adds many items to a list box, this message

can be used to turn the redraw flag off, which prevents the list box from

being painted after each addition. Properly using the WM_SETREDRAW message

keeps the list box from flashing after each addition.

MORE INFORMATION

The following four steps outline ways to use the WM_SETREDRAW message to

facilitate making a number of changes to the contents of a list box in a

visually pleasing manner:

1. Clear the redraw flag by sending the list box a WM_SETREDRAW

   message with wParam set to FALSE. This prevents the list box from

   being painted after each change.

2. Send appropriate messages to make any desired changes to the

   contents of the list box.

3. Set the redraw flag by sending the list box a WM_SETREDRAW message

   with wParam set to TRUE. The list box does not update its display

   in response to this message.

4. Call InvalidateRect(), which instructs the list box to update its

   display. Set the third parameter to TRUE to erase the background in

   the list box. If this is not done, if a short list box item is

   drawn over a long item, part of the long item will remain visible.

The following code fragment illustrates the process described above:

   /* Step 1: Clear the redraw flag. */

   SendMessage(hWndList, WM_SETREDRAW, FALSE, 0L);

   /* Step 2: Add the strings. */

   for (i = 0; i < n; i++)

      SendMessage(hWndList, LB_ADDSTRING, ...);

   /* Step 3: Set the redraw flag. */

   SendMessage(hWndList, WM_SETREDRAW, TRUE, 0L);

   /* Step 4: Invalidate the list box window to force repaint. */

   InvalidateRect(hWndList, NULL, TRUE);

Additional reference words: 3.00 3.10  3.50 3.51 4.00 95 flash flicker

KBCategory: kbprg

KBSubcategory: UsrCtl


Preventing the Console from Disappearing

PSS ID Number: Q99115

Authored 23-May-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   versions 3.1 and 3.5

SUMMARY

When a console application is started from the File Manager, from the

Program Manager, or by typing "start <progname>" from the command prompt,

it executes in its own console. This console disappears as soon as the

application terminates, and therefore the user can't read anything written

to the screen between the last pause and program exit. To resolve this

problem, the programmer should pause the application before termination to

allow the user to read all of the information on the screen.

It is not likely that the programmer will want to introduce this pause if

the application is started directly from the command prompt, because in

this situation it won't make much sense to the user. However, there is no

API (application programming interface) that directly determines whether or

not the application shares a console with CMD.EXE. There is a method that

can be used to determine this information in most cases. When the

application first starts up, call GetConsoleScreenBufferInfo(). If the

cursor position is (0, 0), then the application has its own console, which

will disappear when the application terminates. Otherwise, the application

is operating within a console belonging to another program, typically

CMD.EXE.

NOTE: This method will not work if the user combines a clear screen (CLS)

and execution of the application into one step ([C:\] CLS & <progname>),

because the cursor position will be (0, 0), but the application is using

the console, which belongs to CMD.EXE.

MORE INFORMATION

To start a console application with its own console that will not disappear

when the application is terminated, use CMD /K. For example, use

   start CMD /K <progname>

Note that it is possible to programmatically force an application to always

have its own console by immediately doing a FreeConsole() and an

AllocConsole(). The disadvantage is that the C run-time handles are no

longer valid. Use CreateFile( "CONIN$", ... ) with lpsa->bInherit=TRUE, in

combination with _open_osfhandle() and dup2() to close the current handles

(stdin, stdout, stderr) and associate handles that will be inherited.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseCon


Preventing Word Wrap in Microsoft Windows Help Files

PSS ID Number: Q88142

Authored 18-Aug-1992	Last modified 24-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

By default, the Microsoft Windows Help application wraps lines of text

to reflect the size of its window. However, there are situations (such

as a table of information) in which wrapping text is undesirable. The

information below presents two methods of preventing a section of text

from changing when the Help application window changes sizes. These

techniques apply to version 2.0 of the Microsoft Word for Windows-based

application.

MORE INFORMATION

Method 1

--------

This method, which is compatible with versions 3.0 and 3.1 of the

Microsoft Windows Help Compiler, involves two steps:

1. Place either a hard or a soft carriage return at the end of each

   line.

2. Format the section with the "keep lines together" paragraph

   attribute. From the Format menu, choose Paragraph, and select the

   Keep Lines Together check box in the Paragraph dialog box.

Method 2

--------

This method, which is compatible only with version 3.1 of the Help

Compiler, is to create a one row, one column table in Word for

Windows. Set the width of the table as desired and allow the text to

wrap within the table normally. Windows Help will duplicate the word

breaks in the table provided that the font used to author the table is

selected by the Help engine when displaying the table. If Help uses a

different font, the text may wrap differently, even though the table

keeps the specified width.

Note

----

When you use either of these methods, if the Windows Help window is

not large enough to display the entire width of a topic, Help displays

a horizontal scroll bar rather than wrapping the text to make it

visible.

Additional reference words: 3.00 3.10 3.50 4.00 95 HLP word wrap wordwrap

engine HC31 HC31.EXE HCP HCP.EXE

KBCategory: kbtool

KBSubcategory: TlsHlp


Primitives Supported by Paths Under Windows 95

PSS ID Number: Q125697

Authored 01-Feb-1995	Last modified 06-Apr-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

Windows 95 supports the full set of Win32 path APIs. However, only a

limited set of primitives can be used to build a path. Windows 95 supports

the following primitives to build paths:

ExtTextOut

LineTo

MoveToEx

PolyBezier

PolyBezierTo

Polygon

Polyline

PolylineTo

PolyPolygon

PolyPolyline

TextOut

All other Win32 primitives will be ignored if used in a path. As with other

Win32 primitives in Windows 95, paths are not mapped pixel-by-pixel to

Windows NT; they support only 16-bit coordinates.

Additional reference words: 4.00 GDI

KBCategory: kbprg

KBSubcategory: GdiMisc


Printer Escapes Under Windows 95

PSS ID Number: Q125692

Authored 01-Feb-1995	Last modified 06-Apr-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

SUMMARY

Printer escapes are used to access special printer device features and have

been used widely in Windows version 3.x. With Windows 95, Microsoft is

encouraging application developers to move away from these escapes by

providing GDI functionality to replace them.

For example, a Win32-based application should not call the NEXTBAND and

BANDINFO escapes. Banding is no longer needed in Windows 95. Most of these

escapes, however, are still provided for 16-bit-based applications for

backwards compatibility. The only recommended escapes for 32-bit,

Windows 95-based applications are the QUERYESCSUPPORT and PASSTHROUGH

escapes.

MORE INFORMATION

Applications written for Windows version 3.x can use the QUERYESCSUPPORT

and the PASSTHROUGH escapes, as well as the following 10 escapes. It is

important to note that these escapes are only supported for backwards

compatibility. All new Windows 95-based applications should use Win32 API

that replaces these escapes:

   ABORTDOC

   ENDDOC

   GETPHYSPAGESIZE

   GETPRINTINGOFFSET

   GETSCALINGFACTOR

   NEWFRAME

   NEXTBAND

   SETABORTPROC

   SETCOPYCOUNT

   STARTDOC

The following functions should always be used in place of a printer escape:

   Function       Printer Escape Replaced

   ----------------------------------------

   AbortDoc       ABORTDOC

   EndDoc         ENDDOC

   EndPage        NEWFRAME

   SetAbortProc   SETABORTPROC

   StartDoc       STARTDOC

Windows 95 provides six new indexes for the GetDeviceCaps function that

replace some additional printer escapes:

   Index for GetDeviceCaps   Printer Escape Replaced

   --------------------------------------------------------

   PHYSICALWIDTH             GETPHYSPAGESIZE

   PHYSICALHEIGHT            GETPHYSPAGESIZE

   PHYSICALOFFSETX           GETPRINTINGOFFSET

   PHYSICALOFFSETY           GETPRINTINGOFFSET

   SCALINGFACTORX            GETSCALINGFACTOR

   SCALINGFACTORY            GETSCALINGFACTOR

Although a lot of the escapes have been replaced with Win32 GDI equivalent

APIs, not all device-dependent escapes have been replaced. It is up to

the printer driver manufacturer to decide whether or not its Windows

95-based driver will contain device-specific escapes that were present in

its Windows version 3.x driver. An example of a device-specific escape

would be the Windows version 3.x PostScript driver's POSTSCRIPT_IGNORE

escape. Before calling any of these escapes, an application must first call

the QUERESCSUPPORT escape to find out if the escape is supported or not.

Additional reference words: 4.00

KBCategory: kbprint

KBSubcategory: GdiPrnMisc


Printing in Windows Without Form Feeds

PSS ID Number: Q11915

Authored 26-Oct-1987	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

A Windows-based application cannot print directly to a printer without

issuing a form feed. In 16-bit Windows, the NEWFRAME escape is required to

start the print spooler. This escape, in turn, sends a form feed to the

printer. Without the NEWFRAME escape, the spooler never runs, and nothing

is output to the printer. Win32-based applications should use EndPage(),

which replaces the NEWFRAME escape.

MORE INFORMATION

It is possible to drive the spooler directly by using the spooler

functions documented in the Windows Device Development Kit (DDK). This

allows the printer driver to be bypassed. However, by doing this, the

ability to use GDI output functions and Windows's device-independent

capabilities will be lost.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: GdiPrn


Printing Monochrome and Color Bitmaps from Windows

PSS ID Number: Q64520

Authored 06-Aug-1990	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

The format of a display bitmap determines the procedure that an

application uses to print it. The two display bitmap formats available

under Windows are device-dependent bitmaps (DDBs) and device-

independent bitmaps (DIBs). DIBs and DIB functions should be used for

printing color bitmaps.

MORE INFORMATION

An application can use the BitBlt() or StretchBlt() function to print

or display a monochrome bitmap. Both printer drivers and display

drivers can process monochrome DDBs. However, an application must

account for the difference in resolution between a typical display and

a typical laser printer. The StretchBlt() function enables an

application to appropriately change the size of a monochrome bitmap.

When the display bitmap is a color DDB, printing is more difficult

because the display DDB format may not match the printer DDB format.

Because Windows supports a wide variety of devices, this situation is

quite common. When the formats DDB differ, the application must

convert the display DDB into a print DDB or a DIB.

DIBs are designed to ease the process of transferring images between

devices. When an application uses a DIB, the GDI or the output driver

performs any conversions required for the device. The ShowDIB sample

application, provided in the Windows SDK and the Win32 SDK, demonstrates

converting a DDB to a DIB and other common manipulations. The file DIB.C is

of particular interest. It contains the functions that perform the

manipulations. This code can be incorporated into other applications.

For more information, please see the Windows SDK 3.1 DIBView sample or the

Win32 SDK WinCap32 sample.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: GdiPrn


Printing Offset, Page Size, and Scaling with Win32

PSS ID Number: Q115762

Authored 02-Jun-1994	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

The Win32 documentation for the Escape() function says that the

GETPHYSPAGESIZE, GETPRINTINGOFFSET, and GETSCALINGFACTOR escapes are

obsolete, but it fails to mention the recommended way to get this

information.

The information retrieved by all three escapes can now be retrieved by

calling GetDeviceCaps() with the appropriate index:

 - For the GETPHYSPAGESIZE escape, the indexes to be used with

   GetDeviceCaps() are PHYSICALWIDTH and PHYSICALHEIGHT.

 - For GETPRINTINGOFFSET, the indexes are PHYSICALOFFSETX and

   PHYSICALOFFSETY.

 - For GETSCALINGFACTOR, the indexes are SCALINGFACTORX and SCALINGFACTORY.

All six new indexes are defined in the file WINGDI.H, though they are

missing from the GetDeviceCaps() documentation.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: GdiPrn


Priority Inversion and Windows NT Scheduler

PSS ID Number: Q96418

Authored 16-Mar-1993	Last modified 13-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.1 and 3.5

SUMMARY

The kernel schedules a thread with the real-time process priority class

ahead of every thread with another priority class (nearly all user-mode

threads). Windows NT does not alter the priority of real-time threads. The

system trusts that the programmer will avoid priority inversion. The

remainder of this article talks about the scheduling of threads that are

not real-time priority class and how the system solves the problem of

priority inversion.

Threads are scheduled according to their priority. When the kernel is

choosing which thread will execute on a processor, the highest dynamic

(variable) priority thread is picked. Priority inversion occurs when two

(or more) threads with different priorities are in contention to be

scheduled. Consider a simple case with three threads: Thread 1 is high

priority and becomes ready to be scheduled, while thread 2, a low-priority

thread, is executing in a critical section. Thread 1, the high-priority

thread, begins waiting for a shared resource from thread 2. A third thread

has medium priority. The third thread receives all the processor time,

because the high-priority thread (thread 1) is busy waiting for shared

resources from the low-priority thread (thread 2). Thread 2 won't leave the

critical section, because it isn't the highest priority thread and won't be

scheduled.

The Windows NT scheduler solves this problem by randomly boosting the

priority of threads that are ready to run (in this case the low priority

lock-holders). The low priority threads run long enough to let go of their

lock (exit the critical section), and the high- priority thread gets the

lock back. If the low-priority thread doesn't get enough CPU time to free

its lock the first time, it will get another chance on the next scheduling

round.

Priority inversion is handled differently in Windows 95. If a high priority

thread is dependent on a low priority thread which will not be allowed to

run because a medium priority thread is getting all of the CPU time, the

system recognizes that the high priority thread is dependent on the low

priority thread and will boost the low priority thread's priority up to the

priority of the high priority thread. This will allow the formerly low

priority thread to run and unblock the high priority thread that was

waiting on it.

MORE INFORMATION

Each Process has a base priority. Each thread has a base priority that is a

function of its process base priority. A thread's base priority is settable

to:

 - 1 or 2 points above the process base

 - equal to the process base

 - 1 or 2 points below the process base

Priority setting is exposed through the Win32 API. In addition to a base

priority, all threads have a dynamic priority. The dynamic priority is

never less than the base priority. The system raises and lowers the dynamic

priority of a thread as needed.

All scheduling is done strictly by priority. The scheduler chooses the

highest priority thread which is ready to run. On a multi-processor (MP)

system, the highest N runnable threads run (where N is the number of

processors). The thread priority used to make these decisions is the

dynamic priority of the thread.

When a thread is scheduled, it is given a quantum of time in which to run.

The quantum is in units of clock ticks. The system currently uses 2 units

of quantum (10ms on r4000 and 15ms on x86).

When a thread is caught running during the clock interrupt, its quantum is

decremented by one. If the quantum goes to zero and the thread's dynamic

priority is not at the base priority, the thread's dynamic priority is

decremented by one and the thread's quantum is replenished. If a priority

change occurs, then the scheduler locates the highest priority thread which

is ready to run. Otherwise, the thread is placed at the end of the run

queue for it's priority allowing threads of equal priority to be "round

robin" scheduled. The above is a description of what is usually called

priority decay, or quantum and priority decay.

When a thread voluntarily waits (an an event, for I/O, etc), the system

will usually raise the thread's dynamic priority when it resumes.

Internally, each wait type has an associated priority boost. For example, a

wait associated with disk I/O has a one point dynamic boost. A wait

associated with a keyboard I/O has a 5 point dynamic boost. In most cases,

this boost will raise the priority of the thread such that it can be

scheduled very soon afterwards, if not immediately.

There are other circumstances under which priority will be raised. For

example, whenever a window receives input (timer messages, mouse move

messages, etc), an appropriate boost is given to all threads within the

process that owns the window. This is the boost that allows a thread to

reshape the mouse pointer when the mouse moves over a window.

By default, the foreground application has a base process priority that is

one point higher than the background application. This allows the

foreground process to be even more responsive. This can be changed by

bringing up the System applet, selecting the Tasking button, and choosing a

different option.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseProcThrd


Process Will Not Terminate Unless System Is In User-mode

PSS ID Number: Q92761

Authored 15-Nov-1992	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

Under Windows NT, a process will not be terminated unless the system is

in user-mode. Suppose that TerminateProcess() is called while a device

driver or filesystem code is being executed. The system will wait until

the threads are running user code before marking the process for

termination. On system exit, processes that were the target of a

TerminateProcess() will be killed.

This may affect drivers. If a driver is waiting for an object or

multiple objects in WaitMode or UserMode, its wait may complete

unsuccessfully due to a termination request. Any code that does a

UserMode wait or an Alertable wait must check the return status of the

wait call. If the wait fails with STATUS_USER_APC or STATUS_ALERTED,

this is not an error. The driver should cleanup and return to user-mode.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseProcThrd


Process WM_GETMINMAXINFO to Constrain Window Size

PSS ID Number: Q67166

Authored 22-Nov-1990	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.1 and 3.0

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

Microsoft Windows sends a WM_GETMINMAXINFO message to a window to

determine the maximized size or position for the window, and the

maximum or minimum tracking size for the window. An application can

change these parameters by processing the WM_GETMINMAXINFO message.

Each window type has an absolute minimum size. If an application

changes any of the values associated with WM_GETMINMAXINFO to a value

smaller than the minimum, Windows will override the values specified

by the application and use the minimum size. This minimum window size

restriction has been removed from Windows version 3.1.

Note that Windows can send a WM_GETMINMAXINFO message to a window

prior to sending a WM_CREATE message. Therefore, any processing for

the WM_GETMINMAXINFO message must be independent of processing done

for the WM_CREATE message.

MORE INFORMATION

An application can use the WM_GETMINMAXINFO message to constrain the

size of a window. For example, the application can prevent the user

from changing a window's width while allowing the user to affect its

height, or vice versa. The following code demonstrates fixing the

width:

  int width;

  LPPOINT lppt;

  RECT rect;

  case WM_GETMINMAXINFO:

      lppt = (LPPOINT)lParam;   // lParam points to array of POINTs

      GetWindowRect(hWnd, &rect);   // Get current window size

      width = rect.right - rect.left + 1;

      lppt[3].x = width   // Set minimum width to current width

      lppt[4].x = width   // Set maximum width to current width

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

The modifications required to fix the height are quite

straightforward.

For more information on the array of POINT structures that accompanies

the WM_GETMINMAXINFO message, please refer to the "Microsoft Windows

Software Development Kit Reference."

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrWndw


Processes Maintain Only One Current Directory

PSS ID Number: Q84244

Authored 05-May-1992	Last modified 21-Feb-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

SUMMARY

Processes under Windows NT maintain only one current directory. Under

MS-DOS or OS/2, a process will maintain a current directory for each drive.

MORE INFORMATION

For example, if you do the following

1. Set the current drive to be drive C and set the current directory

   to be \MAINC\MAINSUBC.

2. Change the current drive to be drive D and set the current

   directory to be \MAIND\MAINSUBD.

when you reset the current drive to drive C, the current directory will be

the original directory: \MAINC\MAINSUBC.

MS-DOS and OS/2 use a current directory structure (CDS) to maintain this

information. The memory for this structure is allocated at boot time, and

is set by the LASTDRIVE= line in the CONFIG.SYS file. For example, if you

set LASTDRIVE=Z, you will have 26 entries in the CDS and will be able to

track 26 current directories.

Windows NT by default allows a process to track only one current directory-

-the one for the current drive--because the underlying operating system

does not use drive letters; it always uses fully-qualified names such as:

   \Device\HardDisk0\Partition1\autoexec.bat

The Win32 subsystem maintains drive letters by setting up symbolic links

such as:

   \DosDevices\C: == \Device\HardDisk0\Paritition1

   \DosDevices\D: == \Device\HardDisk0\Paritition2

   \DosDevices\E: == \Device\HardDisk1\Paritition1

(Partitions are 1-based while hard disks are 0-based because Partition0

refers to the entire physical device, which is the "file" that FDISK opens

to do its work.) Therefore, when you do SetCurrentDirectory("c:\tmp\sub"),

the Win32 subsystem translates that to "\DosDevices\c:\tmp\sub", "...".

As far as Windows NT is concerned, there are no "drives," there is one

object namespace.

CMD.EXE maintains a private current directory for each drive it has touched

and uses environment variables to associate a current directory with each

drive. These environment variables have the form "=<drive>:".

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseFileio


Processing CBN_SELCHANGE Notification Message

PSS ID Number: Q66365

Authored 23-Oct-1990	Last modified 18-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.1, 3.5, 3.51, and 4.0

SUMMARY

When a combo box receives a CBN_SELCHANGE notification message,

GetDlgItemText() will give the text of the previous selection and not

the text of the new selection.

To get the text of the new selection, send the CB_GETCURSEL message to

retrieve the index of the new selection and then send a CB_GETLBTEXT

message to obtain the text of that item.

MORE INFORMATION

When an application receives the CBN_SELCHANGE notification message,

the edit/static portion of the combo box has not been updated. To

obtain the new selection, send a CB_GETLBTEXT message to the combo box

control. This message places the text of the new selection in a

specified buffer. The following is a brief code fragment:

   ...  /* other code */

   case CBN_SELCHANGE:

      hCombo = LOWORD(lParam);  /* Get combo box window handle */

    /* Get index of current selection and then the text of that selection

*/

      index = SendMessage(hCombo, CB_GETCURSEL, (WORD)0, 0L);

      SendMessage(hCombo, CB_GETLBTEXT, (WORD)index, (LONG)buffer);

      break;

   ...  /* other code */

NOTE: For Win32 applications, change the WORD and LONG casts to WPARAM and

LPARAM, respectively.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95 combobox

KBCategory: kbprg

KBSubcategory: UsrCtl


Processing WM_PALETTECHANGED and WM_QUERYNEWPALETTE

PSS ID Number: Q77702

Authored 23-Oct-1991	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

An application that manipulates the system palette should process the

WM_PALETTECHANGED and WM_QUERYNEWPALETTE messages to maintain its

appearance during system palette and input focus changes.

MORE INFORMATION

The WM_PALETTECHANGED message informs all windows that the window with

input focus has realized its logical palette, thereby changing the

system palette. This message allows a window without input focus that

uses a color palette to realize its logical palettes and update its

client area.

This message is sent to all windows, including the one that changed

the system palette and caused this message to be sent. The wParam of

this message contains the handle of the window that caused the system

palette to change. To avoid an infinite loop, care must be taken to

check that the wParam of this message does not match the window's

handle. The following sample code demonstrates how to process

WM_PALETTECHANGED:

    case WM_PALETTECHANGED:

        {

        HDC hDC;           // Handle to device context

        HPALETTE hOldPal;  // Handle to previous logical palette

        // If this application did not change the palette, select

        // and realize this application's palette

        if (wParam != hWnd)

           {

           // Need the window's DC for SelectPalette/RealizePalette

           hDC = GetDC(hWnd);

           // Select and realize hPalette

           hOldPal = SelectPalette(hDC, hPalette, FALSE);

           RealizePalette(hDC);

           // When updating the colors for an inactive window,

           // UpdateColors can be called because it is faster than

           // redrawing the client area (even though the results are

           // not as good)

           UpdateColors(hDC);

           // Clean up

           if (hOldPal)

              SelectPalette(hDC, hOldPal, FALSE);

           ReleaseDC(hWnd, hDC);

           }

        }

        break;

NOTE: The WM_PALETTECHANGED message is sent to all top-level and

overlapped windows; therefore, if any child window uses a color

palette, this message must be passed on to it.

The WM_QUERYNEWPALETTE message informs a window that it is about to

receive input focus. In response, the window receiving focus should

realize its palette as a foreground palette and update its client

area. If the window realizes its palette, it should return TRUE;

otherwise, it should return FALSE. The following sample code

demonstrates processing WM_QUERYNEWPALETTE:

    case WM_QUERYNEWPALETTE:

        {

        HDC hDC;           // Handle to device context

        HPALETTE hOldPal;  // Handle to previous logical palette

        // Need the window's DC for SelectPalette/RealizePalette

        hDC = GetDC(hWnd);

        // Select and realize hPalette

        hOldPal = SelectPalette(hDC, hPalette, FALSE);

        RealizePalette(hDC);

        // Redraw the entire client area

        InvalidateRect(hWnd, NULL, TRUE);

        UpdateWindow(hWnd);

        // Clean up

        if (hOldPal)

           SelectPalette(hDC, hOldPal, FALSE);

        ReleaseDC(hWnd, hDC);

        // Message processed, return TRUE

        return TRUE;

        }

NOTE: The WM_QUERYNEWPALETTE message is sent to all top-level and

overlapped windows; therefore, if any child window uses a color

palette, this message must be passed on to it.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: GdiPal


Programatically Appending Text to an Edit Control

PSS ID Number: Q109550

Authored 04-Jan-1994	Last modified 12-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

Windows-based applications often use edit controls to display text. These

applications sometimes need to append text to the end of an edit control

instead of replacing the existing text. There are several ways to do this

in Windows:

 - Use the EM_SETEL and EM_REPLACESEL messages.

  -or-

 - Use the EM_SETSEL message with the clipboard functions to append text to

   the edit control's buffer.

MORE INFORMATION

The EM_SETSEL message can be used to place a selected range of text in a

Windows edit control. If the starting and ending positions of the range are

set to the same position, no selection is made and a caret can be placed at

that position. To place a caret at the end of the text in a Windows edit

control and set the focus to the edit control, do the following:

   HWND hEdit = GetDlgItem (hDlg, ID_EDIT);

   int ndx = GetWindowTextLength (hEdit);

   SetFocus (hEdit);

   SendMessage (hEdit, EM_SETSEL, 0, MAKELONG (ndx, ndx));

Once the caret is placed at end in the edit control, the EM_REPLACESEL

message can be use to append text to the edit control. An application sends

an EM_REPLACESEL message to replace the current selection in an edit

control with the text specified by the lpszReplace (lParam) parameter.

Because there is no current selection, the replacement text is inserted at

the current cursor location. This example sets the selection to the end of

the edit control and inserts the text in the buffer:

   SendMessage (hEdit, EM_SETSEL,     0, MAKELONG (ndx, ndx));

   SendMessage (hEdit, EM_REPLACESEL, 0, (LPARAM) ((LPSTR) szBuffer));

One other way of inserting text into an edit control is to use the Windows

clipboard. If the application has the clipboard open or finds it convenient

to open the clipboard, and copies the text into the clipboard, then it can

send the WM_PASTE message to the edit control to append text.

Before sending the WM_PASTE message, the caret must be placed at the end of

the edit control text using the EM_SETSEL message. Below is pseudo code

that shows how to implement this method:

   OpenClipBoard () ;

   EmptyClipBoard() ;

   SetClipBoardData() ;

   SendMessage (hEdit, EM_SETSEL,  0, MAKELONG (ndx, ndx));

   SendMessage (hEdit, WM_PASTE,   0, 0L);

This pseudo code appends text to the end of the edit control. Note that the

data in the clipboard must be in CF_TEXT format.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrCtl


Propagating Environment Variables to the System

PSS ID Number: Q104011

Authored 02-Sep-1993	Last modified 27-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

User environment variables can be modified using the System control panel

application or by editing the following Registry key:

   HKEY_CURRENT_USER \

         Environment

System environment variables can be modified using the System control panel

application (in Windows NT 3.5 and later) or by editing the following

Registry key:

   HKEY_LOCAL_MACHINE \

               SYSTEM \

    CurrentControlSet \

              Control \

      Session Manager \

          Environment

Note, however, that modifications to the environment variables do not

result in immediate change. For example, if you start another Command

Prompt after making the changes, the environment variables will reflect the

previous (not the current) values. The changes do not take effect until you

log off and then log back on.

To effect these changes without having to log off, broadcast a

WM_WININICHANGE message to all windows in the system, so that any

interested applications (such as Program Manager, Task Manager, Control

Panel, and so forth) can perform an update.

MORE INFORMATION

For example, on Windows NT, the following code fragment should propagate

the changes to the environment variables used in the Command Prompt:

   SendMessage( FindWindow( "Progman", NULL ), WM_WININICHANGE,

     0L, (LPARAM) "Environment" );

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: UsrMisc


Prototypes for SetSystemCursor() & LoadCursorFromFile()

PSS ID Number: Q122564

Authored 08-Nov-1994	Last modified 24-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.5

SUMMARY

The function prototypes for SetSystemCursor() and LoadCursorFromFile()

were inadvertently omitted from the Win32 SDK header files. These APIs

are resolved by linking for USER32.LIB.

Additionally, the use of the OCR_* constants as described in the online

help for LoadCursorFromFile() is not currently implemented. However,

this functionality is available through LoadCursor().

MORE INFORMATION

The correct function prototypes are given below. NOTE: These prototypes

were included correctly in the Win32 SDK 3.51/4.0 documentation.

To use these functions, add the prototypes to a file in your project after

including WINDOWS.H.

#ifdef __cplusplus

extern "C" {

#endif /* __cplusplus */

/* SetSystemCursor prototype */

WINUSERAPI BOOL WINAPI SetSystemCursor (HCURSOR hcur, DWORD id);

/* LoadCursorFromFile prototypes - UNICODE aware */

WINUSERAPI HCURSOR WINAPI LoadCursorFromFileA (LPCSTR lpFileName);

WINUSERAPI HCURSOR WINAPI LoadCursorFromFileW (LPCWSTR lpFileName);

#ifdef UNICODE

#define LoadCursorFromFile  LoadCursorFromFileW

#else

#define LoadCursorFromFile  LoadCursorFromFileA

#endif // !UNICODE

#ifdef __cplusplus

}

#endif  /* __cplusplus */

Additional reference words: 3.50

KBCategory: kbprg kbdocerr

KBSubcategory: GdiCurico


Providing a Custom Wordbreak Function in Edit Controls

PSS ID Number: Q109551

Authored 04-Jan-1994	Last modified 13-Jun-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

An application sends the EM_SETWORDBREAKPROC message to an edit control to

replace the default wordwrap function with an application-defined wordwrap

function. The default wordwrap function breaks a line in a multiline edit

control (MLE) at a space character. If an application needs to change this

functionality (that is, to break at some character other than a space),

then the application must provide its own wordwrap (wordbreak) function.

MORE INFORMATION

A wordwrap function scans a text buffer (which contains text to be sent to

the display), looking for the first word that does not fit on the current

display line. The wordwrap function places this word at the beginning of

the next line on the display.

A wordwrap function defines the point at which Windows should break a line

of text for multiline edit controls, usually at a space character that

separates two words. This can be changed so that the line in an MLE can be

broken at any character. For more information on the EM_SETWORDBREAKPROC

message, please refer to the Windows 3.1 SDK "Programmer's Reference,

Volume 3: Messages, Structures, and Macros" manual.

Below is sample code that demonstrates how to break a line in a multiline

edit control at the "~" (tilde) character (for example) instead of the

regular space (" ") character.

The sample code assumes that the edit control is a multiline edit control

and that it is a child control in a dialog box.

Sample Code

-----------

//Prototype the application-defined wordbreakproc.

int CALLBACK WordBreakProc(LPSTR, int, int, int) ;

//Install wordbreakproc in the WM_INITDIALOG case.

  case WM_INITDIALOG:

    lpWrdBrkProc = MakeProcInstance(WordBreakProc, hInst);

    //Send the EM_SETWORDBREAKPROC message to the edit control

    //to install the new wordbreak procedure.

     SendDlgItemMessage(hDlg, ID_EDIT, EM_SETWORDBREAKPROC, 0,

                        (LPARAM)(EDITWORDBREAKPROC)lpWrdBrkProc) ;

     return (TRUE);

int FAR PASCAL WordBreakProc(LPSTR lpszEditText, int ichCurrent,

                             int cchEditText, int wActionCode)

{

   char FAR *lpCurrentChar;

   int  nIndex;

   int  nLastAction;

   switch (wActionCode) {

     case WB_ISDELIMITER:

     // Windows sends this code so that the wordbreak function can

     // check to see if the current character is the delimiter.

     // If so, return TRUE. This will cause a line break at the ~

     // character.

      if ( lpszEditText[ichCurrent] == '~' )

         return TRUE;

      else

         return FALSE;

      break;

     // Because we have replaced the default wordbreak procedure, our

     // wordbreak procedure must provide the other standard features in

     // edit controls.

     case WB_LEFT:

     // Windows sends this code when the user enters CTRL+LEFT ARROW.

     // The wordbreak function should scan the text buffer for the

     // beginning of the word from the current position and move the

     // caret to the beginning of the word.

         {

            BOOL bCharFound = FALSE;

            lpCurrentChar = lpszEditText + ichCurrent;

            nIndex = ichCurrent;

            while (nIndex > 0  &&

                  (*(lpCurrentChar-1) != '~' &&

                   *(lpCurrentChar-1) != 0x0A) ||

                  !bCharFound )

            {

               lpCurrentChar = AnsiPrev(lpszEditText ,lpCurrentChar);

               nIndex--;

               if (*(lpCurrentChar) != '~' &&  *(lpCurrentChar) != 0x0A )

                  // We have found the last char in the word. Continue

                  // looking backwards till we find the first char of

                  // the word.

                 {

                   bCharFound = TRUE;

                   // We will consider a CR the start of a word.

                   if (*(lpCurrentChar) == 0x0D)

                       break;

                 }

            }

            return nIndex;

         }

      break;

     case WB_RIGHT:

     //Windows sends this code when the user enters CTRL+RIGHT ARROW.

     //The wordbreak function should scan the text buffer for the

     //beginning of the word from the current position and move the

     //caret to the end of the word.

      for (lpCurrentChar = lpszEditText+ichCurrent, nIndex = ichCurrent;

           nIndex < cchEditText;

           nIndex++, lpCurrentChar=AnsiNext(lpCurrentChar))

       if ( *lpCurrentChar == '~' ) {

      lpCurrentChar=AnsiNext(lpCurrentChar);

         nIndex++;

         while ( *lpCurrentChar == '~' ) {

           lpCurrentChar=AnsiNext(lpCurrentChar);

           nIndex++;

          }

         return nIndex;

       }

       return cchEditText;

       break;

  }

}

The wordwrap (wordbreak) function above needs to be exported in the .DEF

file of the application. The function can be modified and customized

according to the application's needs.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95 multi-line

KBCategory: kbprg

KBSubcategory: UsrCtl


PSTR's in OUTLINETEXTMETRIC Structure

PSS ID Number: Q90085

Authored 08-Oct-1992	Last modified 05-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

The OUTLINETEXTMETRIC structure ends with four fields of type PSTR. The

four fields in question are not actually absolute pointers. They are

offsets from the beginning of the OUTLINETEXTMETRIC structure to the

strings in question, as the documentation indicates:

   otmpFamilyName

      Specifies the offset from the beginning of the structure to a

      string specifying the family name for the font.

   otmpFaceName

      Specifies the offset from the beginning of the structure to a

      string specifying the face name for the font. (This face name

      corresponds to the name specified in the LOGFONT structure.)

   otmpStyleName

      Specifies the offset from the beginning of the structure to a

      string specifying the style name for the font.

   otmpFullName

      Specifies the offset from the beginning of the structure to a

      string specifying the full name for the font. This name is

      unique for the font and often contains a version number or

      other identifying information.

The only difference between this structure in Windows 3.1 and Windows NT is

that the strings may be stored in either Unicode or ASCII under Windows NT.

Additional reference words: 3.10 3.50 4.00

KBCategory: kbprg

KBSubcategory: GdiMisc


Querying and Modifying the States of System Menu Items

PSS ID Number: Q83453

Authored 13-Apr-1992	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.1 and 3.0

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

An application should query or set states of the Restore, Move, Size,

Minimize, and Maximize items on the system menu during the processing

of a WM_INITMENU or a WM_INITMENUPOPUP message.

MORE INFORMATION

Windows changes the state of the Restore, Move, Size, Minimize, and

Maximize items on the system menu just before it draws the menu on the

screen and sends the WM_INITMENU and WM_INITMENUPOPUP messages.

Windows sets the states of these menu items according to the state of

the window just before the menu is displayed. For example, if the

window is minimized when its system menu is pulled down, the Minimize

menu item is unavailable (grayed). If an overlapped window is

maximized when its system menu is pulled down, the Move, Size, and

Maximize items are unavailable.

If an application queries or sets the state of any of these system

menu items, the query or change should occur during the processing of

the WM_INITMENU or WM_INITMENUPOPUP message. If any menu item state is

queried before one of these messages is processed, it could reflect a

previous state of the window. If any state is set before one of these

messages is processed, Windows will reset the menu items to correspond

to the state of the window just prior to sending these messages.

Windows does not change the state of the Close menu item. Its state

can be changed or queried at any time.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrMen


Querying Device Support for MaskBlt

PSS ID Number: Q108929

Authored 20-Dec-1993	Last modified 24-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   and 3.51

The Win32 documentation for MaskBlt() states:

   Not all devices support the MaskBlt function. An application should call

   the GetDeviceCaps function to determine whether a device supports this

   function.

To query support for MaskBlt(), an application should query the device for

BitBlt support by passing RC_BITBLT constant to GetDeviceCaps().

MaskBlt() implements transparent blts in Windows NT. For more information,

please see the following article in the Microsoft Knowledge Base:

   ARTICLE-ID: Q89375

   TITLE     : Transparent Blts in Windows NT

GDI implements this application programming interface (API) by calling

BitBlt(). Because BitBlt() is implemented at the driver level, applications

that calls MaskBlt() should check for BitBlt() support on the device.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: GdiBmp


Raster and Stroke Fonts; GDI and Device Fonts

PSS ID Number: Q77126

Authored 08-Oct-1991	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

NOTE: The information contained in this article does not address TrueType

fonts. For information on TrueType fonts, please see chapter 18 of "Guide

to Programming" for the Windows SDK version 3.1.

In Windows version 3.0, there are two different ways that the graphical

device interface (GDI) can generate characters for a font. For a raster

font, GDI displays the font by copying bitmaps to the output device. For a

stroke font, GDI displays the font by drawing lines between a series of

points that describe each character. Each font is owned by either GDI or by

a specific device. Type and ownership information can be determined by

enumerating the fonts. This article discusses the two font types and two

font ownership types.

MORE INFORMATION

A raster font stores its characters as a series of bitmaps; a stroke font

stores its characters as a set of vector operations that describe the

characters. When a character from a raster font is drawn, the bitmap is

copied onto the device. When a character from a stroke font is displayed,

the lines are drawn connecting the points that describe the character.

Examples of raster fonts provided with Windows are Courier and Helv;

examples of stroke fonts are Script and Roman.

Raster fonts are only available in specific sizes. Some devices can scale

installed raster fonts to integer multiples of their size. Use the

GetDeviceCaps() function to determine whether the device has this

capability. The Windows GDI will scale its raster fonts as required

regardless of the device capability. Stroke fonts can be scaled to any size

and can also be rotated.

GDI fonts are owned by the GDI; they are available to all devices. Device

fonts are fonts that are owned by a particular device; they are available

only on that device.

By enumerating the fonts, an application can determine which ones are

raster or stroke fonts, and which are GDI or device fonts. The callback

function used with EnumFonts() has the parameter nFontType. As stated on

page 4-118 of the "Microsoft Windows Software Development Kit Reference

Volume 1," the bitwise AND (&) operator can be used with the constants

RASTER_FONTTYPE and DEVICE_FONTTYPE to determine the font type. If the

RASTER_FONTTYPE bit is set, the font is a raster font; otherwise, it is a

stroke font. If the DEVICE_FONTTYPE bit is set, the font is owned by the

device that corresponds to the display context handle (HDC) used in the

EnumFont() call; otherwise it is a GDI font.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: GdiFnt


RCDATA Begins on 32-Bit Boundary in Win32

PSS ID Number: Q84081

Authored 29-Apr-1992	Last modified 23-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

RCDATA is guaranteed to begin on a DWORD boundary. However, the strings and

the integers specified in the statement are not aligned by the Resource

Compiler (RC)

   RCDATA statement:

   resname RCDATA

   BEGIN

       0,0,

   END

The definition of RCDATA is not changed. The strings and integers

specified in the statement, 0 in this case, are not aligned on the

DWORD boundary. However, the beginning of the data is DWORD-aligned.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbtool

KBSubcategory: TlsRc


ReadFile() at EOF Changed in Windows NT 3.5

PSS ID Number: Q119220

Authored 10-Aug-1994	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.5

The documentation for ReadFile() states that:

   If the function succeeds, the return value is TRUE. If the return value

   is TRUE and the number of bytes read is zero, the file pointer was

   beyond the current end of file at the time of the read operation.

   If the function fails, the return value is FALSE. To get extended error

   information, call GetLastError().

Under Windows NT 3.1, when you read at the end of the file (EOF),

ReadFile() returns TRUE and reports that 0 (zero) bytes were read. However,

if you are using asynchronous I/O and EOF is reached, GetOverlappedResult()

will hang because there is no outstanding I/O. ReadFileEx() properly

handles EOF by failing and setting the error code to ERROR_HANDLE_EOF.

Under Windows NT 3.5, ReadFile() returns FALSE and GetLastError() returns

error 38 (ERROR_HANDLE_EOF) for asynchronous I/O. This change in behavior

was made to avoid the problem described above. The behavior for synchronous

I/O has not changed under Windows NT 3.5.

Additional reference words: 3.50

KBCategory: kbprg

KBSubcategory: BseFileio


Reasons for Failure of Clipboard Functions

PSS ID Number: Q92530

Authored 09-Nov-1992	Last modified 13-Jun-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.1 and 3.0

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

The following clipboard functions:

   OpenClipboard()

   CloseClipboard()

   EmptyClipboard()

   GetClipboardData()

   SetClipboardData()

   EnumClipboardFormats()

   SetClipboardViewer()

   ChangeClipboardChain()

   GetOpenClipboardWindow()

   GetClipboardOwner()

can fail for several reasons. Different functions return different

values to indicate failure. Read the documentation for information

about each function. This article combines the causes of failure for

all functions and provides a resolution or explanation. In the More

Information section, a list of affected functions follows each cause.

The causes are:

1. The clipboard is not opened by any application.

2. The current application does not have the clipboard open.

3. The current application does not own the clipboard.

4. User's data segment is full.

5. Insufficient global memory.

6. The specified clipboard format is not supported.

7. The application that set the clipboard data placed a corrupt or invalid

   metafile in the clipboard.

8. An application is attempting to open an already open clipboard. The

   debug mode of Windows 3.1 will send the "Clipboard already open"

   message.

9. The application that opened the clipboard used NULL as the window

   handle.

MORE INFORMATION

Cause 1: The clipboard is not opened by any application.

Resolution 1: Open the clipboard using OpenClipboard(). If a DLL needs

to open the clipboard, it may pass hwnd = NULL to OpenClipboard().

Explanation 1: An application cannot copy data (using

SetClipboardData()) when no application has the clipboard currently

open.

Affected Functions: SetClipboardData().

Cause 2: The current application does not have the clipboard open.

Resolution 2: Open the clipboard using OpenClipboard(). If a DLL needs

to open the clipboard, it may pass hwnd = NULL to OpenClipboard().

Explanation 2: An application cannot empty or close the clipboard without

first opening it.

Affected Functions: EmptyClipboard(), CloseClipboard().

Cause 3: The current application does not own the clipboard.

Resolution 3: Open the clipboard and get ownership by emptying it.

Explanation 3: An application cannot enumerate the clipboard formats

without owning it.

Affected Functions: EnumClipboardFormats().

Cause 4: User's data segment is full.

Explanation 4: There should be space available in User's data segment to

store internal data structures when SetClipboardData() is called.

Affected Function: SetClipboardData().

Cause 5: Insufficient global memory.

Explanation 5: If the clipboard has data in either the CF_TEXT or

CF_OEMTEXT format and if GetClipboardData() requests text in the

unavailable format, then Windows will perform the conversion. The

converted text must be stored in global memory.

Affected Function: GetClipboardData().

Cause 6: The specified clipboard format is not supported.

Resolution 6: Use IsClipboardFormatAvailable() to check whether the

specified format is available on the clipboard.

Affected Function: GetClipboardData().

Cause 7: The application that set the clipboard data placed a corrupt or

invalid metafile in the clipboard.

Resolution 7: There are no functions to tell whether a given metafile is

corrupt or invalid. Try playing the metafile and see if the metafile plays

as expected.

Affected Function: SetClipboardData().

Cause 8: Application is attempting to open an already open clipboard. The

debug mode of Windows 3.1 will send the "Clipboard already open" message.

Explanation 8: The clipboard must be closed by the application that opened

it, before other applications can open it.

Affected Functions: OpenClipboard().

Cause 9: The application that opened the clipboard used NULL as the window

handle.

Explanation 9: An application can call OpenClipboard(NULL) to

successfully open a clipboard. The side effects are that subsequent

calls to GetClipboardOwner() and GetOpenClipboardWindow() return NULL.

An application can also call SetClipboardViewer(NULL) successfully.

However, there is no reason why this should be allowed, and it is

currently reported as a bug. The side effects are that subsequent

calls to GetClipboardViewer() and ChangeClipboardChain() return NULL.

NULL from these functions does not necessarily imply that they failed.

Affected Functions: GetClipboardOwner(), GetOpenClipboardWindow(),

GetClipboardViewer(), ChangeClipboardChain().

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

GetClipboardFormatName

RegisterClipboardFormat

KBCategory: kbprg

KBSubcategory: UsrClp


Reasons for Failure of Menu Functions

PSS ID Number: Q89739

Authored 29-Sep-1992	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.1 and 3.0

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

The Menu functions (AppendMenu(), CheckMenuItem(), CreateMenu(),

CreatePopupMenu(), DeleteMenu(), DestroyMenu(), GetMenu(),

GetMenuItemID(), GetMenuString(), GetSubMenu(), GetSystemMenu(),

HiliteMenuItem(), InsertMenu(), LoadMenuIndirect(), ModifyMenu(),

RemoveMenu(), SetMenu(), SetMenuItemBitmaps(), and TrackPopupMenu())

can fail for several reasons. Different functions return different

values to indicate failure. Read the documentation for information

about each function. This article combines the causes of failure for

all functions and provides a resolution or explanation. A list of

affected functions follows each cause. The causes are:

1. Invalid hWnd parameter.

2. Invalid hMenu parameter.

3. The menu item is not found.

4. No space left in User's heap to hold a string or to hold an

internal data structure for owner draw menu items or to create a menu

or to create a window for TrackPopupMenu().

5. There are no items in the menu.

6. The menu resource could not be found (FindResource()) or loaded

(LoadResource()) or locked (LockResource()) in memory.

7. TrackPopupMenu() is called while another popup menu is being tracked

in the system.

8. The hMenu that has been passed to TrackPopupMenu() has been deleted.

9. MENUITEMTEMPLATEHEADER's versionNumber field is non-zero.

MORE INFORMATION

Cause 1: Invalid hWnd parameter.

Resolution 1: Validate the hWnd parameter using IsWindow(). Make sure

that hWnd is not a child window.

NOTE: Resolution 1 does not apply to TrackPoupuMenu().

Explanation 1: In Windows, menus are always associated with a window.

Child windows cannot have menu bars.

Affected Functions: All functions that take hWnd as a parameter except for

TrackPoupuMenu().

Cause 2: Invalid hMenu parameter.

Resolution 2: Validate hMenu with IsMenu().

Affected Functions: All functions that take hMenu as a parameter.

Cause 3: The menu item is not found.

Resolution 3: If the menu item is referred to BY_POSITION, make sure

that the index is lesser than the number of items. If the menu item is

referred to BY_COMMAND, an application has to devise its own method of

validating it.

Explanation 3: Menu items are numbered consecutively starting from 0.

Remember that separator items are also counted.

Affected Functions: All functions that refer to a menu item.

Cause 4: No space left in User's heap to hold a string or to hold an

internal data structure for owner draw menu items or to create a menu.

Resolution 4: Remember to delete all menus and other objects that have

been created by the application when they are not needed any more.

If you suspect that objects left undeleted by other applications are

wasting valuable system resources, restart Windows.

Explanation 4: In Windows 3.0, menus and menu items were allocated

space from User's heap. In Windows 3.1, they are allocated space from

a separate heap. This heap is for the exclusive use of menus and menu

items.

Affected Functions: AppendMenu(), Insertmenu(), ModifyMenu(),

CreateMenu(), CreatePopupMenu(), LoadMenu(), LoadMenuIndirect(),

TrackPopupMenu(), GetSystemMenu() (when fRevert = FALSE).

Cause 5: There are no items in the menu.

Resolution 5: Use GetMenuItemCount() to make sure the menu is not empty.

Explanation 5: Nothing to be deleted or removed.

Affected Functions : RemoveMenu(), DeleteMenu().

Cause 6: The menu resource could not be found (FindResource()) or loaded

(LoadResource()) or locked (LockResource()) in memory.

Resolution 6: Ensure that the menu resource exists and that the hInst

parameter refers to the correct hInstance. Try increasing the number

of file handles using SetHandleCount() and increasing available global

memory by closing some applications. For more information about the

causes of failure of resource functions, query this Knowledge Base on

the following keywords:

   failure and LoadResource and FindResource and LockResource.

Explanation 6: Finding, loading, and locking a resource involves use

of file handles, global memory, and the hInstance that has the menu

resource.

Affected Functions: LoadMenu(), LoadMenuIndirect()

Cause 7. TrackPopupMenu() is called while another popup menu is being

tracked in the system.

Explanation 7: Only one popup menu can be tracked in the system at

any given time.

Affected Function: TrackPopupMenu()

Cause 8. The hMenu that has been passed to TrackPopupMenu() has been

deleted. The debug mode of Windows 3.1 sends the following message :

"Menu destroyed unexpectedly by WM_INITMENUPOPUP"

Explanation 8: Windows sends a WM_INITMENUPOPUP to the application

and expects the menu to not be destroyed.

Affected Function: TrackPopupMenu()

Cause 9. MENUITEMTEMPLATEHEADER 's versionNumber field is non-zero.

Explanation 9: In Windows 3.0 and 3.1, this field should always be 0.

Affected Function: LoadMenuIndirect()

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrMen


Reasons Why RegisterClass() and CreateWindow() Fail

PSS ID Number: Q65257

Authored 28-Aug-1990	Last modified 10-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

The RegisterClass() and CreateWindow() functions fail when the system

resources are used up. The percentage of free system resources

reflects the amount of available space in the USER and GDI heaps

within Windows. The smaller amount of free space is reported in the

Program Manager's About box because if either heap fills up, functions

fail.

Under Windows NT, the USER and GDI heap resources are practically

unlimited. Under Windows 95, the USER and GDI heap resources are greater

than Windows 3.1, but not as great as under Windows NT.

MORE INFORMATION

If the amount of free system resources remains low after the

application is exited, it is more likely that the GDI heap is filling.

The main reason for the GDI heap filling is that GDI objects that are

created by the application are not deleted or destroyed when they are

no longer needed, or when the program terminates. Windows does not

delete GDI objects (pens, brushes, fonts, regions, and bitmaps) when

the program exits. Objects must be properly deleted or destroyed.

NOTE: Win32-based applications cannot cause the USER or GDI heaps to

overflow when they terminate, because the system will release the resources

to maximize available resources.

The following are two situations that can cause the USER heap to get

full:

1. Memory is allocated for "extra bytes" associated with window

   classes and windows themselves. Make sure that the cbClsExtra and

   cbWndExtra fields in the WNDCLASS structure are set to 0 (zero),

   unless they really are being used.

2. Menus are stored in the USER heap. If menus are added but are not

   destroyed when they are no longer needed, or when the application

   terminates, system resources will go down.

CreateWindow() will also fail under the following conditions:

1. Windows cannot find the window procedure listed in the

   CreateWindow() call. Avoid this by ensuring that each window

   procedure is listed in the EXPORTS section of the program's DEF

   file.

2. CreateWindow() cannot find the specified window class.

3. The hwndparent is incorrect (make sure to use debug Windows to see

   the RIPs).

4. CreateWindow() cannot allocate memory for internal structures in

   USER heap.

5. The application returns 0 (zero) to the WM_NCCREATE message.

6. The application returns -1 to the WM_CREATE message.

Additional reference words: 3.00 3.10 3.50 4.00

KBCategory: kbprg

KBSubcategory: UsrWndw


Reducing the Count on a Semaphore Object

PSS ID Number: Q94997

Authored 28-Jan-1993	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

ReleaseSemaphore(), which increments the count of a given semaphore object

by a specified amount, will not take a negative value.

If, for some reason, you want to reduce the number of available semaphore

"slots" to temporarily restrict or reduce access, you may loop calling

WaitForSingleObject() with a zero timeout, counting the number of times it

succeeds. When you no longer need to hold the semaphore slots, call

ReleaseSemaphore() with the number of slots counted.

Note that this method does not prevent other threads from taking a

semaphore slot when your thread is looping.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: BseMisc


Registering Multiple RPC Server Interfaces

PSS ID Number: Q129975

Authored 09-May-1995	Last modified 23-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   version 3.5

When registering multiple server interfaces from multiple threads or from

a single thread under the same process, the RpcServerListen() function

should be called only once.

An application process may register two completely separate Remote

Procedure Call (RPC) server interfaces from two separate threads or from a

single thread. However, when doing so, the RpcServerListen() function

should be called only once from any thread.

RPC APIs are called on a per process basis. From the perspective of RPC run

times, a process can register multiple interfaces using one or more

protocol sequences, but must call the RpcServerListen() function only once

from any one thread. Calling the RpcServerListen() function more than once

results in the run time generating an exception called

RPC_S_ALREADY_LISTENING.

Additional reference words: 3.50

KBCategory: kbprg kbnetwork

KBSubcategory: NtwkRpc


RegSaveKey() Requires SeBackupPrivilege

PSS ID Number: Q106383

Authored 07-Nov-1993	Last modified 20-Mar-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

SUMMARY

The description for RegSaveKey() states the following:

   The caller of this function must possess the SeBackupPrivilege

   security privilege.

This means that the application must explicitly open a security token and

enable the SeBackupPrivilege. By granting a particular user the right to

back up files, you give that user the right only to gain access to the

security token (that is, the token is not automatically created for the

user but the right to create such a token is given). You must add

additional code to open the token and enable the privilege.

MORE INFORMATION

The following code demonstrates how to enable SeBackupPrivilege:

   static HANDLE           hToken;

   static TOKEN_PRIVILEGES tp;

   static LUID             luid;

   // Enable backup privilege.

   OpenProcessToken( GetCurrentProcess(),

      TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken ) ;

   LookupPrivilegeValue( NULL, "SeBackupPrivilege", &luid );

   tp.PrivilegeCount           = 1;

   tp.Privileges[0].Luid       = luid;

   tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

   AdjustTokenPrivileges( hToken, FALSE, &tp,

      sizeof(TOKEN_PRIVILEGES), NULL, NULL );

   // Insert your code here to save the registry keys/subkeys.

   // Disable backup privilege.

   AdjustTokenPrivileges( hToken, TRUE, &tp, sizeof(TOKEN_PRIVILEGES),

      NULL, NULL );

Note that you cannot create a process token; you must open the existing

process token and adjust its privileges.

The DDEML Clock sample has similar code sample at the end of the CLOCK.C

file where it obtains the SeSystemTimePrivilege so that it can set the

system time.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseMisc


Removing Focus from a Control When Mouse Released Outside

PSS ID Number: Q66947

Authored 14-Nov-1990	Last modified 18-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.1, 3.5, 3.51, and 4.0

SUMMARY

Under normal circumstances, when you move the mouse cursor into the client

area of a child-window control, click it, and then release the mouse

button, the child window sends a WM_COMMAND message to its parent and

retains the focus.

If you move the mouse into the client area of the child-window control,

press the mouse button, move the mouse cursor out of the client area of the

control, and then release the mouse button, the control does not send a

WM_COMMAND message. However, the control retains the focus.

If you do not want the control to retain the focus, you can remove it by

performing the following steps:

1. Define a static Boolean flag in the parent window function.

2. When a WM_PARENTNOTIFY message is received, set the flag to TRUE.

   This indicates that the mouse button has been pressed while the

   mouse cursor is in the client area of the control.

3. If a WM_COMMAND message is received, reset the flag to FALSE and

   perform normal processing.

4. Otherwise, if a WM_MOUSEMOVE message is received, the mouse button

   was released after the mouse cursor was moved outside the control.

   Reset the flag to FALSE, and use SetFocus() to move the focus to

   the desired window.

MORE INFORMATION

When the mouse cursor is in the client area of a control and you press the

mouse button, the parent window will receive a WM_PARENTNOTIFY message and

a WM_MOUSEACTIVATE message. A Boolean (BOOL) flag should be set when the

message is processed to indicate that this occurred.

The parent window will receive other messages, including a number of

WM_CTLCOLOR messages, when the mouse is moved around with the mouse button

down. When the mouse button is released, the parent window receives only

one of two messages:

1. WM_COMMAND: The mouse button was released over the control.

2. WM_MOUSEMOVE: The mouse button was released outside the control.

Note that these are not the only messages received when the button is

released, but these two are mutually exclusive.

In response to either message, the following steps must take place:

1. Reset the flag indicating a mouse press.

2. Call SetFocus() or send a WM_KILLFOCUS to the control in question

   to move the focus as desired.

If WM_KILLFOCUS is used, the ID of the control or its handle must be known.

SetFocus(NULL) or SetFocus(hWndParent) removes the focus from the control

but does not set the focus to any other control in the window.

In a dialog box, SetFocus(NULL) MUST be used. SetFocus(hDlg) does not

remove the focus from the button.

The following code sample is taken from the dialog box procedure of a

dialog that has a single OK button. If the mouse button is pressed while

the mouse cursor is over the button, the mouse is moved outside the button,

and then the mouse button is released, the focus is removed from the OK

button.

BOOL FAR PASCAL AboutProc(HWND hDlg, unsigned iMessage,

                          WORD wParam, LONG lParam)

    {

    static BOOL fMousePress;

    switch (iMessage)

        {

        case WM_INITDIALOG:

            fMousePress = FALSE;

            return TRUE;

        case WM_PARENTNOTIFY:  // or WM_MOUSEACTIVATE

            fMousePress = TRUE;

            break;

        case WM_MOUSEMOVE:

            if (fMousePress)

                SetFocus(NULL);

            fMousePress = FALSE;

            break;

        // Only command is the OK button.

        case WM_COMMAND:

            if (wParam == IDOK)

                EndDialog(hDlg, TRUE);

            break;

        }

    return FALSE;

    }

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg kbcode

KBSubcategory: UsrCtl


Replace IsTask() with GetExitCodeProcess()

PSS ID Number: Q108228

Authored 07-Dec-1993	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

In Windows 3.1, the application programming interface (API) IsTask() can be

used to determine whether a process is still running or whether it has

terminated. As the help file indicates, this function is obsolete in the

Win32 API.

To get this functionality through the Win32 API, use the API

GetExitCodeProcess(). This function takes the handle as the first parameter

and returns the exit code or STILL_ACTIVE in the second parameter:

   BOOL GetExitCodeProcess(hProcess, lpdwExitCode)

   HANDLE hProcess;

   LPDWORD lpdwExitCode;

As an alternative, you can also use WaitForSingleObject(). Pass the process

handle as the first parameter and a timeout value for the second parameter:

   DWORD WaitForSingleObject(hObject, dwTimeout)

   HANDLE hObject;

   DWORD dwTimeout;

The process handle is signaled when the process terminates. Pass in 0

(zero) for the timeout if you would like to poll or start another thread to

wait with an INFINITE timeout value.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: BseProcThrd


Replacing the Shell (Program Manager)

PSS ID Number: Q100328

Authored 20-Jun-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   versions 3.1 and 3.5

SUMMARY

To replace the current shell, change the following registry key:

   HKEY_LOCAL_MACHINE\

      SOFTWARE\

      Microsoft\

      Windows NT\

      CurrentVersion\

      Winlogon\

      Shell

Note that Program Manager combines the functionality of Program Manager and

Task Manager (the Task Manager installed is not actually run). Therefore,

you must take this into account. In Windows NT 3.1, if the new shell does

not replace the Task Manager functionality, the replacement string should

contain both the new shell name and TASKMAN.EXE, separated by commas. In

Windows NT 3.5, the new shell should either spawn TASKMAN.EXE or your own

task manager, specified in

   HKEY_LOCAL_MACHINE\

      SOFTWARE\

      Microsoft\

      Windows NT\

      CurrentVersion\

      Winlogon\

      Taskman

The value does not exist by default, it must be added. The value type is

REG_SZ.

To update the string that is retrieved when you call

GetPrivateProfileString(), change the string in the following registry key:

   HKEY_LOCAL_MACHINE\

      SOFTWARE\

      MICROSOFT\

      Windows NT\

      Current Version\

      WOW\

      Boot\

      Shell

The duplicate entry is for compatibility with Windows 3.1.

MORE INFORMATION

WritePrivateProfileString() changes the following registry key:

   HKEY_LOCAL_MACHINE\

      SOFTWARE\

      Microsoft\

      Windows NT\

      CurrentVersion\

      WOW\

      Boot\

      Shell

It does not have the desired effect of actually changing the Shell.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseMisc


Replacing the Windows NT Task Manager

PSS ID Number: Q89373

Authored 21-Sep-1992	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

SUMMARY

Under Windows 3.1, the Task Manager is an easily replaceable program.

However, under the Win32 subsystem of Windows NT, it is very difficult to

replace the Task Manager, due to special programming considerations. In

general, it is not recommended that users attempt this.

MORE INFORMATION

Special requirements for the Task Manager make it very different from the

Windows 3.1 Task Manager. The EndTask button handling is done through

internal application programming interface (API) functions. These API

functions are not documented. The situation is the same for handling

foreground management, hung applications, and priority issues (to make sure

that the Task Manager will come up as fast as possible). In addition, the

Windows NT Task Manager uses shortcut ("hot") keys.

In Windows NT 3.1, the Task List has been incorporated into the Program

Manager. To remove the Task List, you must also remove the Program Manager.

The full functionality of the Task List (as found in TASKMAN.EXE) is now

folded into the Program Manager (PROGMAN.EXE). If you completely delete the

TASKMAN.EXE file from your system and from the registry location

   HKEY_LOCAL_MACHINE\

      SOFTWARE\

      Microsoft\

      Windows NT\

      CurrentVersion\

      WinLogon\

      Shell

you will still be able to invoke the Task List because it is built into the

Program Manager.

In Windows NT 3.5, Program Manager checks the registry for a Taskman entry.

If the Taskman entry is found, Program Manager will launch the application,

instead of using its built-in Taskman. The registry entry is:

   HKEY_LOCAL_MACHINE\

      SOFTWARE\

      Microsoft\

      Windows NT\

      CurrentVersion\

      Winlogon\

      Taskman

This entry does not not exist by default. You will have to create this

value, with type REG_SZ.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseMisc


Replacing Windows NT Control Panel's Mouse Applet

PSS ID Number: Q110704

Authored 27-Jan-1994	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

The Control Panel includes a Mouse applet as a standard applet that is

shipped with the system. In Windows 3.1, this applet can be overridden by

an ISV/OEM's mouse driver or module. Windows 3.1 accomplished this by the

Control Panel doing a GetModuleHandle() call on "Mouse". If MOUSE.DLL or

MOUSE.EXE was already loaded in the system, Control Panel would look for

the entry point "CPlApplet". If found, Control Panel would send the

following messages:

   CPL_NEWINQUIRE

   -or-

   CPL_INQUIRE (the former is preferred)

This would return the icon and strings to replace the mouse icon already in

Control Panel.

In Windows NT, because of the separation of Kernel drivers from

applications by the client-server interface, the GetModuleHandle() call

does not work. Consequently, the same functionality must be achieved in a

slightly different way. The Control Panel calls LoadLibrary( "Mouse" ) to

look for a MOUSE.DLL or a MOUSE.EXE. If this call fails, no other checks

are made.

If LoadLibrary() succeeds, the Control Panel looks for the "CPlApplet"

entry point, sends a CPL_INIT message, and then sends a CPL_NEWINQUIRE. If

CPL_NEWINQUIRE fails, a CPL_INQUIRE is sent; however, it is preferable to

have the applet implement the newer CPL_NEWINQUIRE message. The string

information returned by the CPL_NEWINQUIRE message can be in either UNICODE

or ANSI (UNICODE is preferred) as long as the dwSize field is set

correctly. See the CPL.H public header file for these messages and

structures (for example CPLINFOW or CPLINFOA, where CPLINFOW is the

default).

When the User double-clicks the Mouse applet icon, the MOUSE.DLL or

MOUSE.EXE will receive a CPL_DBLCLK message from the CPlApplet interface.

This routine must return TRUE to the Control Panel if the routine runs its

own dialog. If FALSE is returned, the internal Mouse Dialog box will be

presented to the User.

The Control Panel will send the CPL_EXIT message to the Mouse applet when

it wants to unload the module or terminate. The applet must use this

message to perform tasks such as calling UnRegisterWindowClass(), freeing

memory, and unloading DLLs.

NOTE: It is not possible to replace any of the other standard Windows NT

3.1 Control Panel applets. As of Windows NT 3.5, it is also possible to

replace the Keyboard applet in the same manner.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: UsrMisc


Resource Sections are Read-only

PSS ID Number: Q126630

Authored 27-Feb-1995	Last modified 06-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.5, 3.51,

   and 4.0

 - Microsoft Win32s versions 1.2

SUMMARY

Resource sections are read-only by default under Windows NT and Win32s.

However, under Windows NT, the resource section may appear to be

read/write. If an application tries to write to the resource section, an

exception occurs. Windows NT handles the exception by duplicating the page

and making it read/write. Therefore, under Windows NT it is possible to

write to the resource section, even though its section attribute is

read-only.

In Win32s version 1.2, the resource section is read-only and you cannot

write to it. To work around this, link with /SECTION:.rsrc,rw to make the

resource section read/write. Or copy the resource to your own buffer and

work with it from there. You cannot modify the protection of the resource

section because the memory is owned by the system.

In Win32s version 1.25a and later, the resource section is read/write,

regardless of what is specified in the section attributes.

Windows 95 has a handler similar to the one used in Windows NT.

MORE INFORMATION

Under Windows NT, the default top level handler detects writes to

resources and will make the resource writable. If you are running outside

of a debugger and you have no exception handler, your resource writes will

silently work. If you are running under the debugger, your resource write

will look like an access violation:

   First-Chance Exception in msin32.exe: 0xC0000005: Access Violation

This allows you to "fix" your resource writes. If you have the debugger

pass on the exception to your application and you have no handler, the

default handler will make your resource writable.

The disadvantage of setting the attribute of the resource section to

read/write is that Windows NT and Windows 95 will use a separate copy of

the resource section for each process that uses this section, instead of

one copy for all processes.

Additional reference words: 1.20 3.50 4.00 LoadResource LockResource

KBCategory: kbprg

KBSubcategory: UsrRes W32s


Restriction on Named-Pipe Names

PSS ID Number: Q100291

Authored 17-Jun-1993	Last modified 03-Mar-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   versions 3.1, 3.5, and 3.51

Named pipes are implemented in Windows NT using the same approach used for

file systems. Within Windows NT, named pipes are represented as file

objects.

During the design phase, one idea for the implementation was to allow

subdirectories of named pipes. For example, a developer could create a

named pipe subdirectory called \MYPIPES. It would then be possible to

create and use pipes called \MYPIPES\PIPE1 and \MYPIPES\PIPE2, but it would

not be possible to use \MYPIPES as a pipe.

In the end, this idea was not implemented, so subdirectories are not

supported. This does have some effect on the named-pipe names that are

allowed. If a pipe named \MYPIPES is created, it is not possible to

subsequently create a pipe named \MYPIPES\PIPE1, because \MYPIPES is

already a pipe name and cannot be used as a subdirectory. It is possible to

create a pipe named \MYPIPES\PIPE1, but only if there is no pipe named

\MYPIPES. The error recieved is ERROR_INVALID_NAME (123).

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseIpc


Results of GetFileInformationByHandle() Under Win32s

PSS ID Number: Q123813

Authored 11-Dec-1994	Last modified 23-Jun-1995

The information in this article applies to:

 - Microsoft Win32s versions 1.2 and 1.25a

The GetFileInformationByHandle() function returns information about the

given file in a structure of type BY_HANDLE_FILE_INFORMATION.

The following are the BY_HANDLE_FILE_INFORMATION structure fields and

the values they contain under Win32s:

   dwFileAttributes - Always 0 in version 1.2 (A bug that has been fixed.)

   ftCreationTime - Always 0. (An MS-DOS file system limitation.)

   ftLastAccessTime  - Always 0. (An MS-DOS file system limitation.)

   ftLastWriteTime - Correct value.

   dwVolumeSerialNumber - Always 0. (A Win32s limitation.)

   nFileSizeHigh - Correct value.

   nFileSizeLow - Correct value.

   nNumberOfLinks - Always 1.

   nFileIndexHigh - Always 0. (A Win32s limitation.)

   nFileIndexLow - Always 0. (A Win32s limitation.)

Additional reference words: 1.20

KBCategory: kbprg

KBSubcategory: W32s


Retrieving Counter Data From the Registry

PSS ID Number: Q107728

Authored 24-Nov-1993	Last modified 06-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   and 3.51

SUMMARY

The performance data begins with a structure of type PERF_DATA_BLOCK and is

followed by PERF_DATA_BLOCK.NumObjectTypes data blocks. Each data block

begins with a structure of type PERF_OBJECT_TYPE, followed by

PERF_OBJECT_TYPE.NumCounters structures of type PERF_COUNTER_DEFINITION.

Next, there are PERF_OBJECT_TYPE.NumInstances structures of type

PERF_INSTANCE DEFINITION, each directly followed by an instance name, a

structure of type PERF_COUNTER_BLOCK and PERF_OBJECT_TYPE.NumCounters

counters. All of these data types are described in WINPERF.H.

MORE INFORMATION

The following steps are used to retrieve all of the counter information

from the registry:

1. Allocate a buffer to obtain the performance data. Call

   RegQueryValueEx() to obtain the data. If the call returns

   ERROR_MORE_DATA, then the buffer size was not big enough. Increase the

   size of the buffer and try again. Repeat until the call is successful.

      PPERF_DATA_BLOCK PerfData = NULL;

      PerfData = (PPERF_DATA_BLOCK) malloc( BufferSize );

      while( RegQueryValueEx( HKEY_PERFORMANCE_DATA,

                                    "Global",

                                        NULL,

                                        NULL,

                                    PerfData,

                                     &dwSize ) == ERROR_MORE_DATA )

      {

         BufferSize += 1024;

         PerfData = (PPERF_DATA_BLOCK) realloc( PerfData, BufferSize );

         if( PerfData == NULL )

            break;

      }

2. Get the first object:

      PPERF_OBJECT_TYPE PerfObj;

      PerfObj = (PPERF_OBJECT_TYPE) ((PBYTE)PerfData +

                                      PerfData->HeaderLength);

3. Get the first instance:

      PPERF_INSTANCE_DEFINITION PerfInst;

      PerfInst = (PPERF_INSTANCE_DEFINITION) ((PBYTE)PerfObj +

                                               PerfObj->DefinitionLength);

4. Get the first counter:

      PPERF_COUNTER_DEFINITION PerfCntr;

      PerfCntr = (PPERF_COUNTER_DEFINITION) ((PBYTE)PerfObj +

                                                 PerfObj->HeaderLength);

5. Get the counter data:

      PPERF_COUNTER_BLOCK PtrToCntr;

      PVOID CntrData;

      if( PerfInst != NULL )

         PtrToCntr = (PPERF_COUNTER_BLOCK) ((PBYTE)PerfInst +

                                             PerfInst.ByteLength );

      else PtrToCntr = (PPERF_COUNTER_BLOCK) ((PBYTE)PerfObj +

                                             PerfObj.DefinitionLength );

      PVOID CntrData = (PVOID)((PBYTE)PtrToCntr + PerfCntr.CounterOffset);

6. Get the next counter, repeat steps 5 and 6 until all NumCounters

   counters are retrieved:

      PerfCntr = (PPERF_COUNTER_DEFINITION) ((PBYTE)PerfCntr +

                                              PerfCntr->ByteLength);

7. After all the counters are retrieved for the instance, get the next

   instance, repeat steps 4-6 until all NumInstances instances are

   retrieved:

      PPERF_COUNTER_BLOCK PtrToCntr;

      PPERF_INSTANCE_DEFINITION PerfInst;

      PtrToCntr = (PPERF_COUNTER_BLOCK) ((PBYTE) PerfInst +

                                          PerfInst->ByteLength);

      PerfInst = (PPERF_INSTANCE_DEFINITION) ((PBYTE) PtrToCntr +

                                          PtrToCntr->ByteLength);

8. After all instances of the object type are retrieved, move to the next

   object type, repeat steps 3-7 until all NumObjectTypes object types are

   handled:

      PerfObj = (PPERF_OBJECT_TYPE)((PBYTES)PerfObj +

                                     PerfObj.TotalByteLength);

Note that the instance names are retrieved in a fashion that is similar to

retrieving the data.

The steps above showed how to obtain all of the counters. You can retrieve

only the counters that pertain to a particular object by using the titles

database. The information is stored in the registry in the format index,

name, index, name, and so forth.

To retrieve the titles database and store it in TitlesDatabase:

1. Open the key:

      RegOpenKeyEx( HKEY_LOCAL_MACHINE,

         "Software\\Microsoft\\Windows NT\\CurrentVersion\\Perflib\\009",

                0,

         KEY_READ,

            &Hkey);

   Note that 009 is a language ID, so this value will be different on a

   non-English version of the operating system.

2. Query the information from the key:

      RegQueryInfoKey(

                   Hkey,

         (LPTSTR) Class,

             &ClassSize,

                   NULL,

                &Subkey,

              MaxSubKey,

              &MaxClass,

                &Values,

               &MaxName,

               &MaxData,

               &SecDesc,

          &LastWriteTime );

3. Allocate a buffer to store the information:

      TitlesDataBase = (PSTR) malloc( (MaxData+1) * sizeof(TCHAR) )

4. Retrieve the data:

      RegQueryValueEx(     Hkey,

            (LPTSTR) "Counters",

                           NULL,

                           NULL,

        (LPBYTE) TitlesDataBase,

                       &MaxData );

Once you have the database, it is possible to write code that will go

through all objects, searching by index (field ObjectNameTitleIndex) or by

type (field ObjectNameTitle - which is initially NULL).

Or, you could obtain only the performance data for specified objects by

changing the call to ReqQueryValueEx() in step 1 of the SUMMARY section

above to:

   RegQueryValueEx( HKEY_PERFORMANCE_DATA,

                           Indices,

                              NULL,

                              NULL,

                          PerfData,

                           &dwSize );

Note that the only difference here is that instead of specifying "Global"

as the second parameter, you specify a string that represents the decimal

value(s) for the object(s) of interest that are obtained from the titles

database.

The PVIEWER and PERFMON samples in the MSTOOLS\SAMPLES\SDKTOOLS directory

contain complete sample code that deals with performance data. The

"Performance Overview" and Volume 3 of the Windows NT Resource Kit also

contain information about performance monitoring.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseMisc


Retrieving DIBs from the Clipboard

PSS ID Number: Q106386

Authored 07-Nov-1993	Last modified 12-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

Retrieving a DIB (device-independent bitmap) from the clipboard can take

significantly more time than retrieving a bitmap from the clipboard. The

difference stems from the fact that a bitmap is a GDI object and a DIB is a

global memory object.

MORE INFORMATION

When SetClipBoardData() is passed a global memory handle, as it is when it

is passed a handle to a DIB, all the data gets copied into the Win32 server

and put into a sharable section of memory. When the DIB is retrieved with

GetClipBoardData(), the shared memory is mapped into the application's

virtual address space and the memory handle is cached. Any subsequent calls

to GetClipBoardData() return quickly, because the memory does not have to

be remapped.

In contrast, when retrieving a bitmap with GetClipBoardData(), only a

handle is created, because a bitmap is a GDI object.

When CloseClipboard() is called, all of the cached handles to shared memory

and GDI objects are deleted.

Rather than reopening the clipboard, it is a good idea to keep a local copy

of anything retrieved from the clipboard if the item will be used again

after the clipboard has been closed. In general, data should be retrieved

from the clipboard only when the application is doing a paste or if the

application is a clipboard viewer processing a WM_DRAWCLIPBOARD message.

The data for a GDI object exists on the server side. In other words,

bitmaps and DDBs (device-dependent bitmaps) exist in the Win32 subsystem

address space. Only the handles of GDI objects are private to an

application. Therefore, to make a bitmap or a DDB accessible to another

application, only a call to DuplicateHandle() is needed.

Note that even though it is faster to retrieve a DDB from the clipboard, it

is still recommended to put a DIB on the clipboard rather than a DDB.

Additional reference words: 3.10 3.50 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrClp


Retrieving Font Styles Using EnumFontFamilies()

PSS ID Number: Q84131

Authored 29-Apr-1992	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK), version 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

Windows version 3.1 introduces the concept of a font style. In

previous versions of Windows, a font could have the bold, italic,

underline, and strikeout properties, which were supported by

respective members in the LOGFONT and TEXTMETRIC structures. Windows

3.1 also supports these properties, as well as a style name for

TrueType fonts. The article describes how to obtain the font style

name during font enumeration, using the EnumFontFamilies function. For

more information about obtaining style information without enumerating

the fonts, query on the following words in the Microsoft Knowledge

Base:

   prod(winsdk) and getoutlinetextmetrics

MORE INFORMATION

In Windows 3.1, "style" refers to the weight and slant of a font.

Windows supports a wide range of weights in the lfWeight member of the

LOGFONT structure. (Two examples of weights are FW_BOLD, which is

defined as 700, and FW_THIN, which is defined as 100). Very few

applications, however, use any weights other than FW_BOLD and

FW_DONTCARE (defined as 0).

Windows 3.1 builds on the support presently in Windows for these

variations in weight and slant. Style names are NOT used in the

LOGFONT structure except when the fonts are enumerated with

EnumFontFamilies.

The ChooseFont dialog box in the common dialog boxes dynamic-link

library (COMMDLG.DLL) demonstrates how style names are used. The

ChooseFont dialog box has two list boxes: Font and Font Style. The

Font list box lists the face names for all fonts installed and the

Font Style list box lists the font styles for the currently selected

face. For example, if any non-TrueType font (such as MS Sans Serif) is

selected, the following styles appear in the Font Style list box:

   Regular

   Bold

   Italic

   Bold Italic

TrueType fonts may have these or more elaborate styles. For example,

the "Lucida Sans" face includes the following style names:

   Regular

   Italic

   Demibold Roman

   Demibold Italic

In the case of Lucida Sans with the style of Demibold Roman or

Demibold Italic, the lfWeight value is 600 (FW_DEMIBOLD).

In Windows 3.1, the EnumFontFamilies function can be used to obtain

the style name of a font during font enumeration. The EnumFontFamilies

function works in a manner very similar to the Windows 3.0 EnumFonts

function.

EnumFontFamilies is prototyped as:

   int EnumFontFamilies(HDC hdc, LPCSTR lpszFamily,

                        FONTENUMPROC lpfnEnumProc, LPARAM lpData)

The lpszFamily parameter points to a null-terminated string that

specifies the family name (or typeface name) of the desired fonts. If

this parameter is NULL, EnumFontFamilies selects and enumerates one

font of each available font family. For example, to enumerate all

fonts in the "Arial" family, lpszFamily points to a string buffer

containing "Arial."

The following table illustrates the meanings of the terms, "typeface

name," "font name," and "font style:"

   Typeface Name  Font Name                    Font Style

   -------------  ---------                    ----------

   Arial          Arial                        Regular

                  Arial Bold                   Bold

                  Arial Italic                 Italic

                  Arial Bold Italic            Bold Italic

   Courier New    Courier New                  Regular

                  Courier New Bold             Bold

                  Courier New Italic           Italic

                  Courier New Bold Italic      Bold Italic

   Lucida Sans    Lucida Sans                  Regular

                  Lucida Sans Italic           Italic

                  Lucida Sans Demibold Roman   Demibold Roman

                  Lucida Sans Demibold Italic  Demibold Italic

   MS Sans Serif  MS Sans Serif                Regular

                  MS Sans Serif                Bold

                  MS Sans Serif                Italic

                  MS Sans Serif                Bold Italic

The first three typefaces in the above table are TrueType faces, the

remaining typeface is MS Sans Serif. The typeface name is also

sometimes referred to as the family name.

When dealing with non-TrueType fonts, typeface name and font name are

the same. However, it is important to recognize the distinction when

dealing with a TrueType font.

For example, CreateFont takes a pointer to a string containing the

typeface name of the font to create. It is not valid to use Arial Bold

as this string because Arial is a TrueType font and Arial Bold is a

font name, not a typeface name.

If EnumFontFamilies is called with the lpszFamily parameter pointing

to a valid TrueType typeface name, the callback function, which is

specified in fntenmprc, will be called once for each font name for

that typeface name. For example, if EnumFontFamilies is called with

lpszFamily pointing to Lucida Sans, the callback function will be

called four times; once for each font name.

If the lpszFamily parameter points to the typeface name of a non-

TrueType font, such as MS Sans Serif, the callback will be called once

for each face size supported by the font. The number of face sizes

supported by the font can vary from font to font and from device to

device. Note that the callback is called for different sizes, not for

different styles. This behavior is identical to that found using the

EnumFonts function.

Remember that, because TrueType fonts are continuously scalable, there

is no reason for the callback function to be called for each size. If

the callback function was called for each size that a TrueType font

supported, the callback function would be called an infinite number of

times!

The EnumFontFamilies callback function is prototyped as follows:

int CALLBACK EnumFontFamProc(LPNEWLOGFONT lpnlf,

                             LPNEWTEXTMETRIC lpntm,

                             int FontType, LPARAM lpData)

The lpnlf parameter points to a LOGFONT structure that contains

information about the logical attributes of the font. If the typeface

being enumerated is a TrueType font [(nFontType | TRUETYPE_FONTTYPE)

is TRUE], this LOGFONT structure will have two additional members

appended to the end of the structure, as follows:

   char   lfFullName[LF_FACESIZE*2];

   char   lfStyleName[LF_FACESIZE];

It is important to remember that these two additional fields are used

*only* during enumeration with EnumFontFamilies and nowhere else in

Windows. The documentation for the EnumFontFamilies function on pages

266-268 of the "Microsoft Windows Software Development Kit:

Programmer's Reference, Volume 2: Functions" manual refers to the

NEWLOGFONT structure which contains the additional members listed

above. However, the NEWLOGFONT structure is not defined in the

WINDOWS.H header file. To address this situation, use the ENUMLOGFONT

structure which is defined in the WINDOWS.H file but is not listed in

the Windows SDK documentation.

To retrieve the style name and full name of a font without using

enumeration, use the GetOutlineTextMetrics function.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: GdiTt


Retrieving Handles to Menus and Submenus

PSS ID Number: Q67688

Authored 11-Dec-1990	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

To change the contents of a menu, you must have its handle. The handle

of the menu associated with a given window is available through the

GetMenu() function.

To obtain a reference to a particular text item in the menu, use the

GetMenuString() function. The definition for this function is

   GetMenuString(hMenu, wIDItem, lpString, nMaxCount, wFlag)

where

   hMenu     = The menu handle

   wIDItem   = The ID of the item or the zero-based offset of the

               item within the menu

   lpString  = The buffer that is to receive the text

   nMaxCount = The length of the buffer

   wFlag     = MF_BYCOMMAND or MF_BYPOSITION

If a menu item has a mnemonic, the text will contain an ampersand (&)

character preceding the mnemonic character.

To obtain the handle to a submenu of the menu bar, use the

GetSubMenu() function. The second parameter, nPos, is the zero-based

offset from the beginning of the menu.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrMen


Retrieving Palette Information from a Bitmap Resource

PSS ID Number: Q124947

Authored 17-Jan-1995	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

You may sometime need to create a logical palette from a bitmap resource in

order to display the bitmap with the maximum number of available colors.

For example, on an 8 bit-per-pixel display, a logical palette is necessary

to draw a 256-color bitmap on a device context for that display. The

LoadBitmap function does not return or take a palette as one of its

parameters; thus, for example, there is no way to incorporate a palette

with a 256-color bitmap loaded with LoadBitmap. Therefore, an application

must load the resource as a device-independent bitmap (DIB), rather than a

device-dependent bitmap (DDB), in order to retrieve the bitmap's color

information. An application can use the FindResource, LoadResource, and

LockResource functions to do this.

MORE INFORMATION

A bitmap (.BMP file) is stored in an application's resources as a (DIB),

along with a color table if one exists. When a DIB is loaded from an

application's resources with the LoadBitmap function, a DDB is returned.

This DDB is a bitmap compatible with the screen. Routines such as

CreateDIBitmap and SetDIBits that convert DIBs to DDBs take a handle to a

device context as their first parameter. This tells the routine what kind

of DDB to create. If this device context currently has a palette selected

into it, then CreateDIBitmap or SetDIBits can use this palette to create

the DDB. Without a palette, the routines are restricted to system colors

when matching the DIB's colors to the DDB's colors. For example, on an 8

bit-per-pixel display, the resulting DDB can have only up to 20 different

colors. With a logical palette, the resulting bitmap could have had up to

256 different colors.

If the bitmap is loaded as a DIB from the resource, then an application can

query the DIB's color table and create a logical palette for the DIB. Then,

it can call either CreateDIBitmap or SetDIBits, along with a device context

with that palette selected, to obtain a DDB compatible with that palette.

To load a bitmap from a resource as a DIB, you can use the FindResource

function with the RT_BITMAP flag set and then use the LoadResource function

to load it. You can lock the resource with the LockResource function.

The following code demonstrates how to use the above technique to load a

DIB from an application's resources, create a palette for it, and then

create a DDB out of it. The LoadResourceBitmap function below can be used

in place of the LoadBitmap function. The only additional parameter needed

is the address of a logical palette handle. The palette handle referenced

will contain a handle to a logical palette after the function is called.

HBITMAP LoadResourceBitmap(HINSTANCE hInstance, LPSTR lpString,

HPALETTE FAR* lphPalette)

{

    HRSRC  hRsrc;

    HGLOBAL hGlobal;

    HBITMAP hBitmapFinal = NULL;

    LPBITMAPINFOHEADER  lpbi;

    HDC hdc;

    int iNumColors;

    if (hRsrc = FindResource(hInstance, lpString, RT_BITMAP))

       {

       hGlobal = LoadResource(hInstance, hRsrc);

       lpbi = (LPBITMAPINFOHEADER)LockResource(hGlobal);

       hdc = GetDC(NULL);

       *lphPalette =  CreateDIBPalette ((LPBITMAPINFO)lpbi, &iNumColors);

       if (*lphPalette)

          {

          SelectPalette(hdc,*lphPalette,FALSE);

          RealizePalette(hdc);

          }

       hBitmapFinal = CreateDIBitmap(hdc,

                   (LPBITMAPINFOHEADER)lpbi,

                   (LONG)CBM_INIT,

                   (LPSTR)lpbi + lpbi->biSize + iNumColors *

sizeof(RGBQUAD),

                   (LPBITMAPINFO)lpbi,

                   DIB_RGB_COLORS );

       ReleaseDC(NULL,hdc);

       UnlockResource(hGlobal);

       FreeResource(hGlobal);

       }

    return (hBitmapFinal);

}

HPALETTE CreateDIBPalette (LPBITMAPINFO lpbmi, LPINT lpiNumColors)

{

   LPBITMAPINFOHEADER  lpbi;

   LPLOGPALETTE     lpPal;

   HANDLE           hLogPal;

   HPALETTE         hPal = NULL;

   int              i;

   lpbi = (LPBITMAPINFOHEADER)lpbmi;

   if (lpbi->biBitCount <= 8)

       *lpiNumColors = (1 << lpbi->biBitCount);

   else

       *lpiNumColors = 0;  // No palette needed for 24 BPP DIB

   if (*lpiNumColors)

      {

      hLogPal = GlobalAlloc (GHND, sizeof (LOGPALETTE) +

                             sizeof (PALETTEENTRY) * (*lpiNumColors));

      lpPal = (LPLOGPALETTE) GlobalLock (hLogPal);

      lpPal->palVersion    = 0x300;

      lpPal->palNumEntries = *lpiNumColors;

      for (i = 0;  i < *lpiNumColors;  i++)

         {

         lpPal->palPalEntry[i].peRed   = lpbmi->bmiColors[i].rgbRed;

         lpPal->palPalEntry[i].peGreen = lpbmi->bmiColors[i].rgbGreen;

         lpPal->palPalEntry[i].peBlue  = lpbmi->bmiColors[i].rgbBlue;

         lpPal->palPalEntry[i].peFlags = 0;

         }

      hPal = CreatePalette (lpPal);

      GlobalUnlock (hLogPal);

      GlobalFree   (hLogPal);

   }

   return hPal;

}

Here is an example of how you might use the above function to load a bitmap

from a resource and display it using a logical palette:

   {

   HBITMAP hBitmap,hOldBitmap;

   HPALETTE hPalette;

   HDC hMemDC, hdc;

   BITMAP bm;

   hBitmap = LoadResourceBitmap(hInst,"test", &hPalette);

   GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&bm);

   hdc = GetDC(hWnd);

   hMemDC = CreateCompatibleDC(hdc);

   SelectPalette(hdc,hPalette,FALSE);

   RealizePalette(hdc);

   SelectPalette(hMemDC,hPalette,FALSE);

   RealizePalette(hMemDC);

   hOldBitmap = SelectObject(hMemDC,hBitmap);

   BitBlt(hdc,0,0,bm.bmWidth,bm.bmHeight,hMemDC,0,0,SRCCOPY);

   DeleteObject(SelectObject(hMemDC,hOldBitmap));

   DeleteDC(hMemDC);

   ReleaseDC(hWnd,hdc);

   DeleteObject(hPalette);

   }

REFERENCES

For more information on DIB-related functions, please review the Microsoft

Windows SDK sample DIBVIEW.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: GdiBmp GdiBmpFormat


Retrieving the Style String for a TrueType Font

PSS ID Number: Q84132

Authored 29-Apr-1992	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

Windows version 3.1 introduces the concept of a font style. In

previous versions of Windows, a font could have bold, italic,

underline, and strikeout properties, which were supported by

corresponding members of the LOGFONT and TEXTMETRIC structures.

Windows 3.1 continues to support these properties, however, it also

supports the concept of a style name for TrueType fonts.

Windows use of style names can be demonstrated by the ChooseFont

dialog box in the common dialog boxes dynamic-link library

(COMMDLG.DLL). The ChooseFont dialog box contains two list boxes named

Font and Font Style. The Font list box contains a list of all face

names and the Font Style list box contains a list of font styles for

the currently selected face. For example, if any non-TrueType font

(such as MS Sans Serif) is selected, the following styles will appear

in the style list box:

   Regular

   Bold

   Italic

   Bold Italic

TrueType fonts may have these or more elaborate styles. For example,

the "Lucida Sans" face includes the following style names:

   Regular

   Italic

   Demibold Roman

   Demibold Italic

MORE INFORMATION

As part of the TrueType support, the GetOutlineTextMetrics function can be

used to retrieve metric information for TrueType fonts, including the style

name.

GetOutlineTextMetrics is prototyped as follows:

   DWORD GetOutlineTextMetrics(HDC hdc, UINT cbData,

                               LPOUTLINETEXTMETRIC lpotm);

The hdc parameter identifies the device context. GetOutlineTextMetrics

retrieves the metric information for the font currently selected into

the specified device context. For GetOutlineTextMetrics to succeed,

the font must be a TrueType font. The sample code given below shows

how to synthesize the style name for a non-TrueType font.

The cbData parameter specifies the size, in bytes, of the buffer in

which information is returned.

The lpotm parameter points to an OUTLINETEXTMETRIC structure. If this

parameter is NULL, the function returns the size of the buffer

required for the retrieved metric information.

The OUTLINETEXTMETRIC structure contains most of the font metric

information provided with the TrueType format. The relative parts of

the structure are listed below:

     typedef struct tagOUTLINETEXTMETRIC {

       .

       .

       .

         PSTR    otmpFamilyName;

         PSTR    otmpFaceName;

         PSTR    otmpStyleName;

         PSTR    otmpFullName;

     } OUTLINETEXTMETRIC;

While these four members of the OUTLINETEXTMETRIC structure are

defined as near pointers to strings (PSTR), they are actually offsets

into the structure from the beginning of the structure. Because the

length of these strings is not defined, an application must allocate

space for them above and beyond the space allocated for the

OUTLINETEXTMETRIC structure itself. The sample code below demonstrates

this. It also demonstrates using GetOutlineTextMetrics in an

application that will also work with Windows 3.0.

  #include <windows.h>

  #include <windowsx.h>

  .

  .

  .

  HFONT                hFont;

  LPOUTLINETEXTMETRIC  potm;

  TEXTMETRIC           tm;

  int                  cbBuffer;

  hFont = CreateFont( ..... );

  hFont = SelectObject(hDC, hFont);

  /*

   * Call the GetTextMetrics function to determine whether or not the

   * font is a TrueType font.

   */

  GetTextMetrics(hDC, &tm);

  /*

  * GetOutlineTextMetrics is a function implemented in Windows 3.1

  * and later. Assume fWin30 was determined by calling GetVersion.

  */

  if (!fWin30 && tm.tmPitchAndFamily & TMPF_TRUETYPE)

  {

     WORD (WINAPI *lpfnGOTM)(HDC, UINT, LPOUTLINETEXTMETRIC);

     /*

      * GetOutlineTextMetrics is exported from

      * GDI.EXE at ordinal #308

      */

     lpfnGOTM = GetProcAddress(GetModuleHandle("GDI"),

                               MAKEINTRESOURCE(308));

     /*

      * Call GOTM with NULL to retrieve the size of the buffer.

      */

     cbBuffer = (*lpfnGOTM)(hDC, NULL, NULL);

     if (cbBuffer == 0)

     {

       /* GetOutlineTextMetrics failed! */

       hFont = SelectObject(hDC, hFont);

       DeleteObject(hFont);

       return FALSE;

     }

     /*

      * Allocate the memory for the OUTLINETEXTMETRIC structure plus

      * the strings.

      */

     potm = (LPOUTLINETEXTMETRIC)GlobalAllocPtr(GHND, cbBuffer);

     if (potm)

     {

       potm->otmSize = cbBuffer;

       /*

        * Call GOTM with the pointer to the buffer. It will

        * fill in the buffer.

        */

       if (!(*lpfnGOTM)(hDC, cbBuffer, potm))

       {

          /* GetOutlineTextMetrics failed! */

          hFont = SelectObject(hDC, hFont);

          DeleteObject(hFont);

          return FALSE;

       }

       /*

        * Do something useful with the string buffers. NOTE: To access

        * the string buffers, the otmp???Name members are used as

        * OFFSETS into the buffer. They *ARE NOT* pointers themselves.

        */

       OutputDebugString((LPSTR)potm + (UINT)potm->otmpFamilyName);

       OutputDebugString((LPSTR)potm + (UINT)potm->otmpFaceName);

       OutputDebugString((LPSTR)potm + (UINT)potm->otmpStyleName);

       OutputDebugString((LPSTR)potm + (UINT)potm->otmpFullName);

       /* Don't forget to free the memory! */

       GlobalFreePtr(potm);

     }

     else

     {

       /* GlobalAllocPtr failed */

       hFont = SelectObject(hDC, hFont);

       DeleteObject(hFont);

       return FALSE;

     }

  }

  else

  {

     /*

      * It was not a TrueType font, or Windows 3.0 is running.

      */

     LOGFONT lf;

     char    szStyle[LF_FACESIZE];

     LPSTR   p;

     GetObject(hFont, sizeof(LOGFONT), &lf);

     /*

      * Fabricate a style string. Important note! The strings

      * "Italic", "Bold", and "Regular" are only valid in English. On

      * versions of Windows localized for other countries, these

      * strings will differ.

      */

     szStyle[0] = '\0';

     if (lf.lfWeight >= FW_BOLD)

       lstrcpy(szStyle, "Bold ");

     /*

      * If it's "Bold Italic," concatenate.

      */

      p = szStyle + lstrlen(szStyle);

      if (lf.lfItalic)

        lstrcpy(p, "Italic");

      if (!lstrlen(szStyle))

        lstrcpy(szStyle, "Regular");

     /*

      * szStyle now holds what is equivalent to the otmpStyleName

      * member.

      */

     OutputDebugString(szStyle);

  }

  hFont = SelectObject(hDC, hFont);

  DeleteObject(hFont);

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: GdiTt


Retrieving the Text Color from the Font Common Dialog Box

PSS ID Number: Q86331

Authored 02-Jul-1992	Last modified 12-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

The common dialog box library (COMMDLG.DLL) provides the ChooseFont()

routine that provides a common interface (Font dialog box) to specify the

attributes for a font in an application. When the user chooses the Apply

button in the Font dialog box, the application can format selected text

using the specified font. This button is also useful in an application that

allows the user to select more than one font simultaneously.

The Font dialog box provides a common method to specify a number of font

attributes, including color. An application can send the CB_GETITEMDATA

message to the Color combo box to retrieve the currently selected color.

This article discusses the procedure required to obtain all the information

about the currently specified font.

MORE INFORMATION

The Font dialog box includes an Apply button if the application includes

the CF_APPLY value in the specification for the Flags member of the

CHOOSEFONT data structure. The dialog box includes the Color combo box if

the CF_EFFECTS value is also specified. The remainder of this article

assumes that the application has specified both of these values.

To properly process input from the Apply button, an application must

install a hook function. For more information on installing a hook

function from an application, query on the following words in the

Microsoft Knowledge Base:

   steps adding hook function

The following code illustrates one method to process input from the Apply

button:

   case WM_COMMAND:

      switch (wParam)

      {

         case psh3:  // The Apply button

         // Retrieve the font information...

            SendMessage(hDlg, WM_CHOOSEFONT_GETLOGFONT, 0,

                       (LONG)(LPLOGFONT)&lfLogFont);

         // Perform any required processing

         // (create the specified font, for example)

         // Retrieve color information...

            iIndex = (int)SendDlgItemMessage(hDlg, cmb4,

                                          CB_GETCURSEL, 0, 0L);

            if (iIndex != CB_ERR)

            {

               dwRGB = SendDlgItemMessage(hDlg, cmb4, CB_GETITEMDATA,

                                       (WORD)iIndex, 0L);

               wRed = GetRValue(dwRGB);

               wGreen = GetGValue(dwRGB);

               wBlue = GetBValue(dwRGB);

               wsprintf(szBuffer, "RGB Value is %u %u %u\r\n", wRed,

                        wGreen, wBlue);

               OutputDebugString(szBuffer);

            }

            break;

         default:

            break;

      }

      break;

The color information is not required to create the font; however, this

information is required to accurately display the font according to the

user's specification.

In an application that does not use the Apply button, the rgbColors member

of the CHOOSEFONT data structure contains the selected color. In this case,

no special processing to retrieve the color is required.

Additional reference words: 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrCmnDlg


Retrieving Time-Zone Information

PSS ID Number: Q115231

Authored 22-May-1994	Last modified 18-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.5,

   3.51, and 4.0

In Windows NT, version 3.1, the time-zone strings are compiled into a

resource that is linked into the CONTROL.EXE file. For Windows NT, version

3.5 and later and Windows 95, the time-zone strings have been moved into

the registry.

In Windows NT, the time-zone strings are located in the key:

   HKEY_LOCAL_MACHINE\SOFTWARE\

      Microsoft\

      Windows NT\

      CurrentVersion\

      Time Zones.

In Windows 95, the time-zone strings are located in the key:

   HKEY_LOCAL_MACHINE\SOFTWARE\

      Microsoft\

      Windows\

      CurrentVersion\

      Time Zones.

For each time zone, the registry key TZI is formatted as follows:

   LONG       Bias;

   LONG       StandardBias;

   LONG       DaylightBias;

   SYSTEMTIME StandardDate;

   SYSTEMTIME DaylightDate;

You can use this information to fill out a TIME_ZONE_INFORMATION structure,

which is used when calling SetTimeZoneInformation().

Additional reference words: 3.50 4.00

KBCategory: kbprg

KBSubcategory: BseMisc


Returning CBR_BLOCK from DDEML Transactions

PSS ID Number: Q102584

Authored 04-Aug-1993	Last modified 18-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

DDEML servers are applications that provide data to client

applications. For some servers, this data gathering may be a lengthy

process, as when gathering data from sources such as serial ports or a

network. DDEML allows a server application to process data

asynchronously in these situations by returning CBR_BLOCK from the DDE

callback function.

MORE INFORMATION

In DDEML-based applications, while transactions can be either

synchronous or asynchronous, only DDEML client applications may choose

to establish either type of transaction when requesting data from a

server application. DDEML server applications do not distinguish

between synchronous and asynchronous transactions.

Asynchronous transactions can be very useful when client applications

know that the partner server application will take some time to gather

data. This type of transaction frees up the client to do other things

while waiting for a notification from the server of data availability.

Server applications have no way of determining whether the client

application has requested data synchronously or asynchronously.

Request transactions on the server's side are always synchronous. When

a client requests data, the server's callback receives an XTYP_REQUEST

transaction, where the expected return value is a data handle. If the

server application has to wait for data from a serial port, for

example, access to the CPU by other applications will be delayed,

thereby freezing the system until data arrives.

There are a couple of ways one can enable the server to gather data in

an asynchronous manner, thereby allowing it to yield to other

applications on the system while it gathers data. One method is to

use CBR_BLOCK; another is to change the request transaction to a

one-time ADVISE loop.

Method 1

--------

Given that DDEML callbacks are not re-entrant, and that DDEML expects

a data handle as a return value from the XTYP_REQUEST transaction (and

transactions of XCLASS_DATA class), the server application can block

the callback momentarily. It can do this by returning a CBR_BLOCK

value after posting itself a user-defined message.

This way, the server application can gather data in the background

while DDEML queues up any further transactions. The server can start

gathering data when its window procedure gets the user defined message

that was posted by its DDE callback function.

When a server application returns CBR_BLOCK for a request transaction,

DDEML disables the server's callback function. It also queues

transactions that are sent by DDEML after its callback has been

disabled. This feature gives the server an opportunity to gather data

while allowing other applications to run in the system.

As soon as data becomes available, then the server application can

call DdeEnableCallBack() to re-enable the server callback function.

Once the callback is re-enabled, DDEML will resend the same request

transaction to the server's callback and this time, because data is

ready, the server application can return the appropriate data handle

to the client.

Transactions that were queued up because of an earlier block are sent

to the server's callback function in the order they were received by

DDEML.

The pseudo code to implement method 1 might resemble the following:

BOOL gbGatheringData = TRUE;   // Defined GLOBAlly.

HDDEDATA ghData = NULL;

HDDEDATA CALLBACK DdeServerCallBack(...)

   {

       switch(txnType)

       {

       case XTYP_REQUEST:

          // If the server takes a long time to gather data...

          // for this topic/item pair, then

          // post a user-defined message to the server app's wndproc

       // and return CBR_BLOCK... DDEML will block the callback

       // and queue transactions.

       if(bGatheringData) {

         PostMessage(hSrvWnd, WM_GATHERDATA, .....) ;

         return CBR_BLOCK;

       }

       else              // Data is ready, send back handle.

         return ghData;

       default:

         return DDE_FNOTPROCESSED;

      }

    }

LRESULT CALLBACK SrvWndProc(...)

  {

    switch (wMessage)

       {

          case WM_GATHERDATA:

             while (bGatheringData)

               {

                  // Gather data here while yielding to others

                  // at the same time!

      if(!PeekMessage(..))

        bGatheringData = GoGetDataFromSource (&ghData);

                  else {

                    TranslateMessage() ;

                    DispatchMessage ();

                  }

                }

          DdeEnableCallback (idInst, ghConv, EC_ENABLEALL);

             break ;

          default:

            return DefWndProc();

         }

     }

Method 2

---------

Advise transactions in DDEML (or DDE) are just a continuous request

link. Changing the transaction from a REQUEST to a "one time only"

ADVISE loop on the client side allows the server to gather data

asynchronously.

The client application can start an ADVISE transaction from its side

and when the server receives a XTYP_ADVSTART transaction, return TRUE

so that an ADVISE link is established. Once the link is established,

the server can start gathering data, and as soon as it becomes

available, notify the client of its availability.

This can be done by calling DdePostAdvise(). The server can use

PeekMessage() to gather data if the data gathering process is a

lengthy one, so that other applications on the system will get a

chance to run. Once the client receives the data from the server in

its callback (in its XTYP_ADVDATA transaction), it can disconnect the

the ADVISE link from the server by specifying an XTYP_ADVSTOP

transaction.

Additional reference words: 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrDde


Rich Edit Control Does Not Support Unicode

PSS ID Number: Q128558

Authored 03-Apr-1995	Last modified 04-Apr-1995

The information in this article applies to:

 - Microsoft Win32 Software Development KIT (SDK) for Windows NT

   version 3.51 and Windows 95

The Rich Edit control included with Windows 95 and Windows NT version 3.51

does not support Unicode.

For a Unicode application to use the Rich Edit control, it must convert any

strings passed to the control to ASCII text. This includes strings used in

the FINDTEXT structure and the TEXTRANGE structure.

Additional reference words: 3.50 4.00

KBCategory: kbprg

KBSubcategory: UsrCtl


Rotating a Bitmap by 90 Degrees

PSS ID Number: Q77127

Authored 08-Oct-1991	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.0 and 3.1

 - Microsoft Win32 SDK, version 4.0

SUMMARY

There are no Windows functions that directly rotate bitmaps. All techniques

for rotating bitmaps in Windows involve copying the rows from a source

bitmap into the columns of a destination bitmap. The following contains

code for rotating a bitmap using GetPixel() and SetPixel(), and contains an

outline of code for rotating device independent bitmaps (DIB).

MORE INFORMATION

A device dependent bitmap (DDB) can be rotated using the GetPixel() and

SetPixel() functions. To rotate the bitmap, use the following code:

HBITMAP Rotate90(HDC hDC, HBITMAP hSourceBitmap)

{

  HBITMAP hOldSourceBitmap, hOldDestBitmap, hDestBitmap;

  HDC hMemSrc, hMemDest;

  int height, width;

  int i, j;

  BITMAP iSrcBitmap;

  // Step 1: Create a memory DC for the source and destination bitmaps

  //         compatible with the device used.

  hMemSrc = CreateCompatibleDC(hDC);

  hMemDest= CreateCompatibleDC(hDC);

  // Step 2: Get the height and width of the source bitmap.

  GetObject(hSourceBitmap, sizeof(BITMAP), (LPSTR)&SrcBitmap);

  width = SrcBitmap.bmWidth;

  height = SrcBitmap.bmHeight;

  // Step 3: Select the source bitmap into the source DC. Create a

  //         destination bitmap, and select it into the destination DC.

  hOldSourceBitmap = SelectObject(hMemSrc, hSourceBitmap);

  hDestBitmap = CreateBitmap(height, width, SrcBitmap.bmPlanes,

                    SrcBitmap.bmBitsPixel, NULL);

  if (!hDestBitmap)

    return(hDestBitmap);

  hOldDestBitmap = SelectObject(hMemDest, hDestBitmap);

  // Step 4: Copy the pixels from the source to the destination.

  for (i = 0; i < width; ++i)

      for (j = 0; j < height; ++j)

          SetPixel(hMemDest, j, width - 1 - i,

                                            GetPixel(hMemSrc, i, j));

  // Step 5: Destroy the DCs.

  SelectObject(hMemSrc, hOldSourceBitmap);

  SelectObject(hMemDest, hOldDestBitmap);

  DeleteDC(hMemDest);

  DeleteDC(hMemSrc);

  // Step 6: Return the rotated bitmap.

  return(hDestBitmap);

}

If the bitmap is larger, using GetPixel() and SetPixel() may be too slow.

If this is the case, there are two options:

1. If the contents of the bitmap do not change, create two versions of

   the bitmap, the normal version and one that is rotated by 90

   degrees. Load the appropriate bitmap as required.

-or-

2. Find some way to manipulate the bits of the bitmap that is faster

   than using SetPixel() and GetPixel(). The best way to do this is to

   convert the bitmap to a device independent bitmap. The following

   four steps detail how to create the DIB and to perform the

   rotation:

   a. Use GetDIBits() to convert the bitmap to a device independent

      format. It is necessary to create a BITMAPINFO structure

      appropriate for the bitmap. This will write the bitmap as a

      series of scanlines. Each scanline is padded so that it is DWORD

      aligned.

   b. Allocate memory for the destination bitmap. This bitmap requires

      as many scanlines as the width of the source bitmap. Each

      scanline is as many pixels wide as the height of the source

      bitmap. Also, the scanlines must be DWORD aligned.

   c. For each scanline in the source bitmap, copy the pixels to the

      appropriate column in the destination bitmap. NOTE: The format

      for each scanline depends upon the number of bits per pixel. See

      the BITMAPINFO documentation for a description of the possible

      formats.

   d. Use SetDIBits() to copy the device independent bits into a

      device dependent bitmap. Another BITMAPINFO structure,

      appropriate for the destination device is required for this

      step.

The four steps of this method require much more work than is required

if GetPixel() and SetPixel() are used; however, this method may be

faster because it directly manipulates the bits in the bitmap.

Additional reference words: 3.00 3.10 4.00 95

KBCategory: kbprg

KBSubcategory: GdiBmp


RPC CALLBACK Attribute and Unsupported Protocol Sequences

PSS ID Number: Q131495

Authored 12-Jun-1995	Last modified 15-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) version 3.5

SUMMARY

The CALLBACK attribute of RPC does not support connection-less protocol

sequences.

MORE INFORMATION

If an RPC interface has a procedure with the CALLBACK attribute, it can

only make use of connection-oriented protocol sequences. The following

protocol sequences are not supported:

 - ncadg_ip_udp

 - ncadg_ipx

If an RPC client tries to call a remote procedure that in turn calls a

procedure back on client, the client will be able make the initial call,

but when the server tries to call the procedure on client, the RPC run time

generates exception 1726: The remote procedure call failed.

Additional reference words: 3.50

KBCategory: kbprg kbnetwork

KBSubcategory: NtwkRpc


RPC Can Use Multiple Protocols

PSS ID Number: Q100009

Authored 14-Jun-1993	Last modified 26-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.1, 3.5,

   and 4.0

Microsoft Remote Procedure Call (RPC) does not rely on a single protocol.

An RPC server can be written to use all available protocols on the server,

and a client can be written in the same manner. Thus, the server or client

does not have to know which protocols it supports explicitly.

RPC protocols supported by Windows 3.1 and 3.5 are:

   ncacn_ip_tcp   (TCP/IP)

   ncacn_nb_nb    (NetBIOS over NetBEUI)

   ncacn_nb_tcp   (NetBIOS over TCP)

   ncacn_np       (Named Pipes)

   ncalrpc        (LPC)

RPC protocols supported by Windows 3.5 only are:

   ncadg_ipx      (Datagram - IPX)

   ncacn_spx      (SPX)

   ncadg_ip_udp   (Datagram - UDP)

   ncacn_nb_ipx   (Netbios over IPX)

RPC protocols supports by Windows 95 are:

   ncacan_ip_tcp

   ncacn_nb_nb

   ncacn_np

   ncacn_spx

   ncalrpc

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: NtwkRpc


RpcNsxxx() APIs Not Supported by Windows NT Locator

PSS ID Number: Q104318

Authored 13-Sep-1993	Last modified 23-Feb-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

The RpsNSxxx group and profile name service application programming

interfaces (APIs), such as RpcNsProfileEltAdd(), are supported by our RPC

run time; however, they are not supported by the Windows NT Locator, which

is the default RPC name service provider. If you attempt to make a call to

one of these APIs, an error 1764, "request not supported," will be

returned. Because the RpcNSxxx APIs are supported in the run time, name

service providers other than the Locator, such as the DCE CDS, can be

accessed.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: NtwkRpc


Running a Windows-Based Application in its Own VDM

PSS ID Number: Q115235

Authored 22-May-1994	Last modified 04-Apr-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   version 3.5

SUMMARY

The Windows NT, version 3.1, Windows on Win32 (WOW) supports running all

16-bit Windows-based applications in one virtual machine (VM). These

applications share an address space, just as they do on Windows. The

Windows NT, version 3.5, WOW supports running a Windows-based application

in its own VM, which gives the application its own address space.

In order to programmatically start a Windows-based application in its own

VM, start the application with CreateProcess() and then specify the flag

CREATE_SEPARATE_WOW_VDM.

To specify a Win16 application started from the command prompt to run in

its own address space, use the following syntax:

   start /SEPARATE <filename>

To specify a Windows-based application started from the Program Manager to

run in its own address space, check the following item in the Program Item

Properties for the application or in the Run dialog box, which can be

selected from the Program Manager's File menu:

   Run in Separate Memory Space

NOTE: This option is not the default, nor is there any way to make it

the default.

MORE INFORMATION

Allowing a Windows-based application to run in a separate address space

provides for more robust operation, because the application is isolated

from other Windows-based applications. However, the downside is twofold:

 - WOW VMs require approximately 2500K of private memory on x86 machines.

 - There is no shared memory between WOW VMs. Therefore, Windows-based

   applications that rely on shared memory cannot be run in separate

   VMs. As an alternative, use DDE or OLE, because they can be used by

   an application in one VM to communicate with an application in

   another VM.

Additional reference words: 3.50

KBCategory: kbprg

KBSubcategory: Subsys


Running Bound Applications Under Windows NT

PSS ID Number: Q90913

Authored 26-Oct-1992	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

SUMMARY

Bound applications are designed and built so they can be run under either

OS/2 or MS-DOS. The OS/2 subsystem is not available on MIPS; therefore,

bound applications will not run as OS/2 applications on MIPS.

When a bound application is run under Windows NT on an 80x86 system, the

application will automatically run under the OS/2 subsystem if it is

available.

MORE INFORMATION

The OS/2 subsystem is available by default on an 80x86 system. To

force bound applications to run as an MS-DOS-based application, you can

disable the OS/2 subsystem, but this is not recommended. Instead use

the FORCEDOS facility. Type "FORCEDOS /?" at the command line to get

help on FORCEDOS. It is not advised that you disable the OS/2

subsystem unless there is a very specific need that FORCEDOS does not

address.

To disable the OS/2 subsystem using RegEdit:

   Go to HKEY_LOCAL_MACHINE

   Go to SYSTEM

   Go to Current Control Set

   Go to Control

   Go to Session Manager

   Go to SubSystems

   Modify 'Optional: REG_MULTI_SZ OS/2 Posix'. Specifically, remove OS/2

   and reboot.

Once this is done, bound applications will run as MS-DOS-based

applications. Running an OS/2 application results in the following message:

   Cannot connect to OS/2 subsystem

WARNING: REGEDT32 is a very powerful utility that facilitates directly

changing the Registry database. Using REGEDT32 incorrectly can cause

serious problems, including hard disk corruption. It may be necessary to

reinstall the software to correct some problems. Microsoft does not support

changes made with REGEDT32. Use this tool AT YOUR OWN RISK.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: SubSys


RW2002 Error "Cannot Reuse String Constants" in RC.EXE

PSS ID Number: Q21569

Authored 31-Oct-1988	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.1, 3.5, 3.51, and 4.0

SUMMARY

The error "Cannot Reuse String Constants" will be returned by the Resource

Compiler if you have used the same ID value to define two different string

constants.

For example, the following error is returned when compiling the resource

file:

   Cannot Reuse String Constants

The file MY.RC may contain the following lines:

MORE INFORMATION

The following sample code can be used to demonstrate the problem.

Sample Code

-----------

   StringTable

   begin

      1, "one"

      2, "two"

      3, "three"

      1, "four"

   end

Note that "one" and "four" have the same value. This error may be less

noticeable if you are using both decimal and hexadecimal notation in

your RC file. In the following example, 0x010 and 16 have the same

value and generate the error:

    0x010, "hex 10"

    10, "ten"

    11, "eleven"

    15, "fifteen"

    16, "sixteen"

Additional reference words: 3.00 3.10 3.50 4.00 95 RW2002 RC2151

KBCategory: kbtool

KBSubcategory: TlsRc


SAMPLE: 16 and 32 Bits-Per-Pel Bitmap Formats

PSS ID Number: Q94326

Authored 04-Jan-1993	Last modified 21-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

Windows NT supports the same bitmap formats as Microsoft Windows version

3.1, but includes two new formats: 16 and 32 bits-per-pel.

SEEDIB.EXE is a file in the Microsoft Software Library that contains the

source code to an application that demonstrates how to load, display, and

save 1, 4, 8, 16, 24, and 32-bits-per-pixel DIB formats. In addition, it

demonstrates a simple method of creating an optimized palette for

displaying DIBSs with more than 8-bits-per-pixel on 8-bits-per-pixel

devices.

NOTE: In order to minimize color loss, SeeDIB uses CreateDIBSection() to

do conversions between uncompressed DIBs which have more than 8-bits-per-

pixel. This function is not available on Windows NT 3.1.

You can download SEEDIB.EXE from the Microsoft Software Library (MSL) on

the following services:

 - CompuServe

      GO MSL

      Search for SEEDIB.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download SEEDIB.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get SEEDIB.EXE

MORE INFORMATION

For DIBs (device independent bitmaps), the 16 and 32-bit formats contain

three DWORD masks in the bmiColors member of the BITMAPINFO structure.

These masks specify which bits in the pel correspond to which color.

The three masks must have contiguous bits, and their order is assumed to be

R, G, B (high bits to low bits). The order of the three masks in the color

table must also be first red, then green, then blue (RGB). In this manner,

the programmer can specify a mask indicating how many shades of each RGB

color will be available for bitmaps created with CreateDIBitmap(). For

16-bits-per-pixel DIBs, CreateDIBitmap() defaults to the RGB555 format. For

32-bits-per-pixel DIBs, CreateDIBitmap() defaults to an RGB888 format.

NOTE: The DIB engine in Windows 95 supports only RGB555 and RGB565 for

16-bit DIBs and only RGB888 for 32-bit DIBs.

Example

-------

The RGB555 format masks would look like:

   0x00007C00  red   (0000 0000 0000 0000 0111 1100 0000 0000)

   0x000003E0  green (0000 0000 0000 0000 0000 0011 1110 0000)

   0x0000001F  blue  (0000 0000 0000 0000 0000 0000 0001 1111)

NOTE: For 16 bits-per-pel, the upper half of the DWORDs are always zeroed.

The RGB888 format masks would look like:

   0x00FF0000  red   (0000 0000 1111 1111 0000 0000 0000 0000)

   0x0000FF00  green (0000 0000 0000 0000 1111 1111 0000 0000)

   0x000000FF  blue  (0000 0000 0000 0000 0000 0000 1111 1111)

Usage

-----

When using 16 and 32-bit formats, there are also certain fields of the

BITMAPINFOHEADER structure that must be set to the correct values:

1. The biCompression member must be set to either BI_RGB or BI_BITFIELDS.

   Using BI-RGB indicates that no bit masks are included in the color table

   and that the default (RGB555 for 16bpp and RGB888 for 32bpp) format is

   implied. Using BI_BITFIELDS indicates that there are masks (bit fields)

   specified in the color table.

2. As with 24-bits-per-pixel formats, the biClrUsed member specifies the

   size of the color table used to optimize performance of Windows color

   palettes. If the biCompression is set to BI_BITFIELDS, then the optimal

   color palette starts immediately following the three DWORD masks. Note

   that an optimal color palette is optional and many applications will

   ignore it.

A technical note related to this subject from the Microsoft Multimedia

group is also available. It can be obtained from CompuServe in the WINEXT

and WINSDK forums. The filename is VFW.ZIP. In addition, the technote is

available by calling Microsoft Developer Services at (800) 227-4679,

extension 11771. The technical note is part of the Video for Windows

technical notes and describes how to create a display driver that supports

these new DIB formats, which are used by Video for Windows. The technical

note also includes definitions of installable image codecs.

Windows 95

----------

In Windows 95, if the BI_BITFIELDS flag is set, then a color mask must be

specified and it must be one of the following:

Resolution  Bits per color  Color Mask

16bpp       5,5,5           0x00007c00 0x000003e0 0x0000001f

16bpp       5,6,5           0x0000f800 0x000007e0 0x0000001f

32bpp       8,8,8           0x00ff0000 0x0000ff00 0x000000ff

User-defined color masks are not available in Windows 95.

Additional reference words: 3.10 3.50 4.00 bpp bmp

KBCategory: kbprg kbfile

KBSubcategory: GdiBmp


SAMPLE: Adding TrueType, Raster, or Vector Fonts to System

PSS ID Number: Q130459

Authored 21-May-1995	Last modified 20-Jun-1995

--

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK), versions 3.1 and 3.11

 - Microsoft Win32 SDK, versions 3.1, 3.5, 3.51, and 4.0

--

FONTINST is a sample application in the Microsoft Software Library that

demonstrates how to programmatically add a TrueType, raster, or vector font

to the system.

When working with a TrueType font file (.TTF file), FONTINST creates a .FOT

file and moves the specified .TTF file to the Windows system directory. For

a raster or vector font file (.FON file), FONTINST moves the .FON file to

the Windows system directory. After the font file has been moved to the

system directory, FONTINST adds the font to the system by using the

AddFontResource() API. Then it adds font information to the [fonts]

section of the WIN.INI file so that the font is automatically loaded every

time Windows starts. For example, the following line is added to the

WIN.INI file when FONTINST adds the ARIAL.TTF file to the system:

   Arial (TrueType)=ARIAL.FOT

FONTINST also demonstrates how to retrieve the facename of a font given a

.TTF or .FON file. In the case of a TrueType font, FONTINST opens up the

file and reads the naming table of the .TTF file. FONTINST also shows how

to read the FONTINFO structure (as described on pages 49-50 of the

"Microsoft Windows Software Development Kit: Programmer's Reference, Volume

4: Resources") of a .FON file. The facename of a font in a .FON file can

also be found in this manner.

After a font is installed by FONTINST, information about the font is

displayed in the window. Information such as the TEXTMETRIC structure and

font type, as well as sample font text, is displayed. Information added

to the WIN.INI file is also displayed in this window.

Download FONTINST.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for FONTINST.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download FONTINST.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get FONTINST.EXE

Additional reference words: 3.10 3.50 4.00 95 softlib

KBCategory: kbprg kbfile

KBSubcategory: GdiFnt GdiFntCreate


SAMPLE: AngleArc in Windows 3.1, Win32s, and Windows 95

PSS ID Number: Q125693

Authored 01-Feb-1995	Last modified 06-Apr-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

 - Microsoft Win32 SDK

 - Microsoft Win32s, version 1.3

SUMMARY

In Windows version 3.1, Win32s, and Windows 95, you may find it useful to

get the functionality provided by the Win32 API AngleArc(). AngleArc() is

only supported on Windows NT.

MORE INFORMATION

The AngleArc() function draws a line segment and an arc. The line segment

is drawn from the current position to the beginning of the arc. The arc is

drawn along the perimeter of a circle with the given radius and center. The

length of the arc is defined by the given start and sweep angles. The

starting point of the sweep is determined by measuring counterclockwise

from the x-axis of the circle by the number of degrees in the start angle.

The ending point is similarly located by measuring counterclockwise from

the starting point by the number of degrees in the sweep angle.

The code below provides two possible ways of getting functionality similar

to that of the AngleArc() function. While both of these methods will work

on any Windows platform, the second (AngleArc2) will be substantially

faster due to the fact that it uses the Arc() function to draw the sweep

rather than calculating each of the segments on the perimeter of the arc.

NOTE: One limitation of the second method is that if the sweep angle is

greater than 360 degrees, the arc will not be swept multiple times. In most

cases this will not be a problem but in certain cases (constructing paths,

for example) this can be a problem.

SAMPLE CODE #1

BOOL AngleArc1(HDC hdc, int X, int Y, DWORD dwRadius,

               float fStartDegrees, float fSweepDegrees)

{

  float fCurrentAngle;         // Current angle in radians

  float fStepAngle = 0.03f;  // The sweep increment value in radians

  float fStartRadians;       // Start angle in radians

  float fEndRadians;         // End angle in radians

  int ix, iy;                // Current point on arc

  float fTwoPi = 2.0f * 3.141592f;

  /* Get the starting and ending angle in radians */

  if (fSweepDegrees > 0.0f) {

    fStartRadians = ((fStartDegrees / 360.0f) * fTwoPi);

    fEndRadians = (((fStartDegrees + fSweepDegrees) / 360.0f) *

           fTwoPi);

  } else {

    fStartRadians = (((fStartDegrees + fSweepDegrees)  / 360.0f) *

          fTwoPi);

    fEndRadians =  ((fStartDegrees / 360.0f) * fTwoPi);

  }

  /* Calculate the starting point for the sweep via */

  /* polar -> cartesian conversion */

  ix = X + (int)((float)dwRadius * (float)cos(fStartRadians));

  iy = Y - (int)((float)dwRadius * (float)sin(fStartRadians));

  /* Draw a line to the starting point */

  LineTo(hdc, ix, iy);

  /* Calculate and draw the sweep */

  for (fCurrentAngle = fStartRadians;

       fCurrentAngle <= fEndRadians;

       fCurrentAngle += fStepAngle) {

    /* Calculate the current point in the sweep via */

    /* polar -> cartesian conversion */

    ix = X + (int)((float)dwRadius * (float)cos(fCurrentAngle));

    iy = Y - (int)((float)dwRadius * (float)sin(fCurrentAngle));

    /* Draw a line segment to current point */

    LineTo(hdc, ix, iy);

  }

  return TRUE;

}

SAMPLE CODE #2

BOOL AngleArc2(HDC hdc, int X, int Y, DWORD dwRadius,

               float fStartDegrees, float fSweepDegrees)

{

  int iXStart, iYStart;  // End point of starting radial line

  int iXEnd, iYEnd;        // End point of ending radial line

  float fStartRadians;   // Start angle in radians

  float fEndRadians;     // End angle in radians

  BOOL bResult;            // Function result

  float fTwoPi = 2.0f * 3.141592f;

  /* Get the starting and ending angle in radians */

  if (fSweepDegrees > 0.0f) {

    fStartRadians = ((fStartDegrees / 360.0f) * fTwoPi);

    fEndRadians = (((fStartDegrees + fSweepDegrees) / 360.0f) *

          fTwoPi);

  } else {

    fStartRadians = (((fStartDegrees + fSweepDegrees)  / 360.0f) *

          fTwoPi);

    fEndRadians =  ((fStartDegrees / 360.0f) * fTwoPi);

  }

  /* Calculate a point on the starting radial line via */

  /* polar -> cartesian conversion */

  iXStart = X + (int)((float)dwRadius * (float)cos(fStartRadians));

  iYStart = Y - (int)((float)dwRadius * (float)sin(fStartRadians));

  /* Calculate a point on the ending radial line via */

  /* polar -> cartesian conversion */

  iXEnd = X + (int)((float)dwRadius * (float)cos(fEndRadians));

  iYEnd = Y - (int)((float)dwRadius * (float)sin(fEndRadians));

  /* Draw a line to the starting point */

  LineTo(hdc, iXStart, iYStart);

  /* Draw the arc */

  bResult = Arc(hdc, X - dwRadius, Y - dwRadius,

                     X + dwRadius, Y + dwRadius,

                     iXStart, iYStart,

                     iXEnd, iYEnd);

  /* Move to the ending point - Arc() wont do this and ArcTo() */

  /* wont work on Win32s or Win16 */

  MoveToEx(hdc, iXEnd, iYEnd, NULL);

  return bResult;

}

Additional reference words: 1.30 3.10 4.00

KBCategory: kbprg kbcode

KBSubcategory: GdiMisc


SAMPLE: Changing Text Alignment in an Edit Control Dynamiclly

PSS ID Number: Q66942

Authored 14-Nov-1990	Last modified 22-Jun-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.1, 3.5, 3.51, and 4.0

SUMMARY

A Microsoft Windows edit control aligns its contents to the left or right

margins, or centers its contents, depending on the window style of the

control. The control styles ES_LEFT, ES_CENTER, and ES_RIGHT specify left-,

center-, and right-alignment, respectively.

Only multiline edit controls can be right-aligned or centered. Single-line

edit controls are always left-aligned, regardless of the control style

given.

Windows does not support altering the alignment style of a multiline edit

control after it has been created. However, there are two methods that you

can use to cause a multiline edit control in a dialog box to appear to

change alignment. Note that in each of these methods, the dialog box that

contains the control must be created with the DS_LOCALEDIT style.

MORE INFORMATION

The first method applies to all platforms. The second method does not apply

to Windows 95. Under Windows 95, EM_SETHANDlE and EM_GETHANDLE are not

supported. For more information, please see the following articles in the

Microsoft Knowledge Base:

   ARTICLE-ID: Q130759

   TITLE     : EM_SETHANDLE and EM_GETHANDLE Messages Not Supported

Method 1

--------

Create three controls: one left-aligned, one centered, and one right-

aligned. Each has the same dimensions and position in the dialog box, but

only one is initially made visible.

When the alignment is to change, call ShowWindow() to hide the visible

control and to make one of the other controls visible.

To keep the text identical in all three controls, use the EM_GETHANDLE and

EM_SETHANDLE messages to share the same memory among all three controls.

Method 2

--------

Initially create a single control. When the text alignment is to change,

retrieve location, size, and style bits for the existing edit control.

Create a new control with the same size and in the same location, but

change the style bits to reflect the new alignment.

Send the EM_GETHANDLE to each control to retrieve a handle to the memory

that stores the contents. Send an EM_SETHANDLE to each control to exchange

the memory used by each. Finally, destroy the original control.

There is a sample application named EDALIGN in the Microsoft Software

Library that demonstrates each of these methods. Note, however, that this

sample is a Windows 3.1 sample only.

Download EDALIGN.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for EDALIGN.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download EDALIGN.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get EDALIGN.EXE

Additional reference words: 3.00 3.10 3.50 4.00 95 EDALIGN.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrCtl


SAMPLE: Customizing the TOOLBAR Control

PSS ID Number: Q125683

Authored 01-Feb-1995	Last modified 20-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

SUMMARY

The sample BARSDI demonstrates how to provide Customization features for

the Toolbar Common Control. The Toolbar Common Control under Windows 95

provides Customization features that are useful when the user needs to

change the toolbar control's buttons dynamically (add, delete, interchange,

etc. buttons).

Download BARSDI.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for BARSDI.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download BARSDI.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the SOFTLIB\MSLFILES directory

      Get BARSDI.EXE

MORE INFORMATION

There are two ways the user can cusotmize the toolbar.

First, the user can use the Drag Drop Customization process to delete or

change the position of buttons on the toolbar. This method does not allow

the user to add buttons to the toolbar dynamically.

The second method involves displaying the Customize dialog box through

which the user can add, remove, interchange buttons on the toolbar.

To provide Customization, the toolbar control has to be created with the

CCS_ADJUSTABLE style, and the parent of the toolbar control has to process

a series of TBN_XXXX notifications. The BARSDI sample implements both

methods of Customization.

Method 1: Drag Drop Customization

---------------------------------

This method of toolbar customization allows the user to reposition

or delete buttons on the toolbar. The user initiates this operation

by holding down the SHIFT key and begins dragging a button. The toolbar

control handles all of the drag operations automatically, including

the cursor changes.

To delete a button, the user has to release the drag operation outside

the Toolbar control. The Toolbar control sends the TBN_QUERYDELETE

message to its parent window. The parent window can return TRUE to

allow the button to be deleted and FALSE to prevent the button from

being deleted.

If the application wants to do custom dragging, it has to process

the TBN_BEGINDRAG and TBN_ENDDRAG notifications itself and perform

the drag/drop process, which involves more coding.

Method 2: Customization Dialog Box

----------------------------------

This method of customization allows users to add buttons to the toolbar

dynmacally in addition to deleting and rearranging buttons on the toolbar.

For example, if the toolbar has N total buttons, and displays only 10 of

those buttons initially, the bitmap that was used to create the toolbar,

should contian all N buttons (where N > 10).

There are two ways in which the Toolbar control dislpays the customize

dialog box. The user can bring up the Customization dialog box by

double-clicking the left mouse button on the toolbar control or the

application can send the TB_CUSTOMIZE message to the toolbar control.

The Customize dialog box displayed by the Toolbar control has two list

boxes. One, on the left contains the list of N-10 Buttons that were not

displayed on the initial toolbar, and the one on the right will have the

currently displayed buttons on the toolbar. The toolbar control provides

the add, remove and other features in the Customize dialog box.

Here is a code sample that shows how the Customization feature is

implemented:

SAMPLE CODE

// The initial set of toolbar buttons.

TBBUTTON tbButton[] =

{

    {0,   IDM_FILENEW,     TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0},

    {1,   IDM_FILEOPEN,    TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0},

    {2,   IDM_FILESAVE,    TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0},

    {3,   IDM_EDITCUT,     TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0},

    {0,   0,               TBSTATE_ENABLED, TBSTYLE_SEP,    0, 0},

    {4,   IDM_EDITCOPY,    TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0},

    {5,   IDM_EDITPASTE,   TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0},

    {6,   IDM_FILEPRINT,   TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0},

    {0,   0,               TBSTATE_ENABLED, TBSTYLE_SEP,    0, 0},

    {7,   IDM_ABOUT,       TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0},

};

// Buttons that can be added at a later stage.

TBBUTTON tbButtonNew[] =

{

    { 8,  IDM_ERASE,       TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0},

    { 9,  IDM_PEN,         TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0},

    {10,  IDM_SELECT,      TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0},

    {11,  IDM_BRUSH,       TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0},

    {12,  IDM_AIRBRUSH,    TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0},

    {13,  IDM_FILL,        TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0},

    {14,  IDM_LINE,        TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0},

    {15,  IDM_EYEDROP,     TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0},

    {16,  IDM_ZOOM,        TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0},

    {17,  IDM_RECT,        TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0},

    {18,  IDM_FRAME,       TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0},

    {19,  IDM_OVAL,        TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0},

};

// The bitmap that is used to create the toolbar should have all

// tbButtonNew + tbButton buttons = 20 in this case.

// Use tbButtons array to create the initial toolbar control.

// Once the user starts to customize the toolbar, process the WM_NOTIFY

// message and the following notifications.

// The toolbar control sends a WM_NOTIFY message to the parent window

// during each process of the customization.

LRESULT OnMsgNotify(HWND hwnd, UINT uMessage, WPARAM wparam, LPARAM lparam)

{

    LPNMHDR         lpnmhdr;

    lpnmhdr =       (LPNMHDR)lparam;

// process the QUERYINSERT And QUERYDELETE notifications

// to allow the drag/drop operation to succeeed.

    if (lpnmhdr->code == TBN_QUERYINSERT)

        return TRUE;

    else if (lpnmhdr->code == TBN_QUERYDELETE)

        return TRUE;

    else if (lpnmhdr->code == TBN_GETBUTTONINFO)

// The user has brought up the customization dialog box,

// so provide the the control will button information to

// fill the listbox on the left side.

    {

        LPTBNOTIFY lpTbNotify = (LPTBNOTIFY)lparam;

        char  szBuffer [20];

        if (lpTbNotify->iItem < 12) // 20 == the total number of buttons

        {                           // tbButton and tbButtonNew

                                    // Since initially we displayed

                                    // 8 buttons

                   // send back information about the rest of

                   // 12 buttons that can be added the toolbar.

            lpTbNotify->tbButton = tbButtonNew[lpTbNotify->iItem];

            LoadString(hInst,

                       NEWBUTTONIDS + lpTbNotify->iItem, // string

                                                         //ID == command ID

                       szBuffer,

                       sizeof(szBuffer));

            lstrcpy (lpTbNotify->pszText, szBuffer);

            lpTbNotify->cchText = sizeof (szBuffer);

            return TRUE;

        }

        else

        return 0;

    }

}

Additional reference words: 4.00 BARSDI

KBCategory: kbprg kbcode kbfile

KBSubcategory: UsrCtl


SAMPLE: Drawing Three-Dimensional Text in OpenGL Applications

PSS ID Number: Q131024

Authored 02-Jun-1995	Last modified 20-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) version 3.51

SUMMARY

GDI operations, such as TextOut, can be performed on an OpenGL window only

if the window is single-buffered. The Windows NT implementation of OpenGL

does not support GDI graphics in a double-buffered window. Therefore, you

can not use GDI functions to draw text in a double-buffered window, for

example. To draw text in a double-buffered window, an application can use

the wglUseFontBitmaps and wglUseFontOutlines functions to create display

lists for characters in a font and then draw the characters in the font

with the glCallLists function.

The wglUseFontOutlines function is new to Windows NT 3.51 and can be used

to draw 3-D characters of TrueType fonts. These characters can be rotated,

scaled, transformed, and viewed like any other OpenGL 3-D image. This

function is designed to work with TrueType fonts.

The GLFONT sample shows how to use the wglUseFontOutlines function to

create display lists for characters in a TrueType font and how to draw,

scale, and rotate the glyphs in the font by using glCallLists to draw

the characters and other OpenGL functions to rotate and scale them. You

will need the Win32 SDK for Windows NT 3.51 to compile this sample and to

incorporate wglUseFontOutlines in your own application. You will need

Windows NT 3.51 to execute the application.

Download GLFONT.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for GLFONT.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download GLFONT.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the SOFTLIB\MSLFILES directory

      Get GLFONT.EXE

MORE INFORMATION

To specify which TrueType font you want wglUseFontOutlines to create

display lists for, you must first create the desired logical font with

CreateFont or CreateFontIndirect. Then, you must select the HFONT created

into a screen device context (HDC) with SelectObject and send the HDC to

the wglUseFontOutlines function. Each characer is mapped in the "x" and

"y" directions in the display lists and you specify the depth in the

negative "z" direction in the "extrusion" parameter of wglUseFontOutlines.

You can also specify whether you want the 3-D glyphs to be created with

line segments or polygons. To instruct wglUseFontOutlines to create the

3-D glyphs with lines segments, specify WGL_FONT_LINES in the "format"

parameter and to create them with polygons, you need to specify

WGL_FONT_POLYGONS.

Here is an example of how one could create a set of display lists to draw

the characters of the "Arial" TrueType font as a set of polygons:

     LOGFONT     lf;

     HFONT       hFont, hOldFont;

     GLYPHMETRICSFLOAT agmf[256];

     // An hDC and an hRC have already been created.

     wglMakeCurrent( hDC, hRC );

     // Let's create a TrueType font to display.

     memset(&lf,0,sizeof(LOGFONT));

     lf.lfHeight               =   -20 ;

     lf.lfWeight               =   FW_NORMAL ;

     lf.lfCharSet              =   ANSI_CHARSET ;

     lf.lfOutPrecision         =   OUT_DEFAULT_PRECIS ;

     lf.lfClipPrecision        =   CLIP_DEFAULT_PRECIS ;

     lf.lfQuality              =   DEFAULT_QUALITY ;

     lf.lfPitchAndFamily       =   FF_DONTCARE|DEFAULT_PITCH;

     lstrcpy (lf.lfFaceName, "Arial") ;

     hFont = CreateFontIndirect(&lf);

     hOldFont = SelectObject(hDC,hFont);

     // Create a set of display lists based on the TT font we selected

     if (!(wglUseFontOutlines(hDC, 0, 255, GLF_START_LIST, 0.0f, 0.15f,

        WGL_FONT_POLYGONS, agmf)))

          MessageBox(hWnd,"wglUseFontOutlines failed!","GLFont",MB_OK);

     DeleteObject(SelectObject(hDC,hOldFont));

     .  .  .  .

     .  .  .  .

     .  .  .  .

     .  .  .  .

To display these 3-D characters in a string, use the following code:

   // Display string with display lists created by wglUseFontOutlines()

   glListBase(GLF_START_LIST); // indicate start of display lists

   // Draw the characters

   glCallLists(6, GL_UNSIGNED_BYTE, "OpenGL");

Additional reference words: graphics

KBCategory: kbprg kbcode kbfile

KBSubcategory: GdiOpenGL


SAMPLE: Drawing to a Memory Bitmap for Faster Performance

PSS ID Number: Q130805

Authored 28-May-1995	Last modified 23-Jun-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

 - Microsoft Win32 Software Development Kit (SDK) versions 3.5, 4.0

 - Microsoft Win32s version 1.2

An application whose client area is a complex image can realize a

performance benefit from drawing to a memory bitmap. The complex, time

consuming drawing code need only be performed once - to initialize the

offscreen bitmap. During the handling of the WM_PAINT message, the only

work that needs to be done is a simple BitBlt from the memory bitmap to the

screen.

Sample code demonstrating this technique is available in the Microsoft

Software Library. The MemDC sample code draws a complex pattern on its

client area. A menu option toggle allows the user to see the speed

difference between using and not using the offscreen bitmap.

Download MEMDC.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for MEMDC.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download MEMDC.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get MEMDC.EXE

Additional reference words: 1.20 3.10 3.50 4.00 95 device context memory DC

speed fast buffer

KBCategory: kbgraphic kbfile

KBSubcategory: GdiDc


SAMPLE: Fade a Bitmap Using Palette Animation

PSS ID Number: Q130804

Authored 28-May-1995	Last modified 23-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.5, 3.51,

   and 4.0

SUMMARY

PALFADE is a sample application available in the Microsoft Software

Library. It demonstrates:

 - How to use the AnimatePalette function to fade a bitmap to black.

 - How to use the DIBAPI32.DLL library that can be built by the WINCAP32

   sample that ships with the Microsoft Win32 SDK.

To perform palette animation, the sample creates a logical palette for a

device-independent bitmap (DIB) with the PC_RESERVED flag set for each

palette entry. PALFADE loads, displays, and animates both Windows-style and

OS/2-style DIB files.

Download PALFADE.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for PALFADE.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download PALFADE.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the SOFTLIB\MSLFILES directory

      Get PALFADE.EXE

MORE INFORMATION

Before performing palette animation on a logical palette entry, ensure that

the palette entry has the PC_RESERVED flag set. To fade a bitmap drawn on a

device context with a PC_RESERVED palette selected, you can lower the RGB

values for each color in the palette in a loop until all colors are black.

The default system palette contains 20 static colors. These static colors

take up the first ten and last ten colors of the system palette; these

palette entries are not available for animation. If you try to fade a

bitmap that has 256 unique colors by creating a 256-color palette with each

palette entry set to PC_RESERVED, you are not guaranteed that every logical

palette entry will map to an entry in the system palette that is available

for palette animation.

One solution to this is to create a logical palette that contains only 236

colors. The PALFADE sample demonstrates one way to create an optimal

palette of 236 colors given a device-independent bitmap with 256 colors in

its color table.

Given a 256-color DIB, PALFADE traverses through every bit in the bitmap to

find the least-used 20 colors in the color table. Then it creates a logical

palette out of the 236 most-used colors. This ensures that all entries in

the logical palette will animate.

This sample uses many of the DIB support functions included with the

DIBAPI32.DLL library. It does not use the LoadDIB() function, because it

was not written to handle OS/2-style DIB files. Instead, PALFADE implements

the DIB-loading routines found in the Win32 SDK SHOWDIB sample.

NOTE: DIBAPI32.DLL is included with this sample.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg kbfile kbgraphic

KBSubcategory: GdiPal


SAMPLE: FASTBLT Implements Smooth Movement of a Bitmap

PSS ID Number: Q40959

Authored 07-Feb-1989	Last modified 20-Jun-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

There is a sample application called FASTBLT in the Microsoft Software

Library that demonstrates how to implement the smooth movement of a bitmap

around the screen. Basically, it sets up a pair of BitBlt() calls: one that

erases the image and another that redisplays the image. The necessary ROP

codes for BitBlt() that should be used are SRCCOPY and SRCINVERT.

Download FASTBLT.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for FASTBLT.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download FASTBLT.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get FASTBLT.EXE

Additional reference words: 3.00 3.10 3.50 4.00 95  softlib FASTBLT.EXE

KBCategory: kbprg kbfile

KBSubcategory: GdiBmp


SAMPLE: Highlighting an Entire Row in a ListView Control

PSS ID Number: Q131788

Authored 20-Jun-1995	Last modified 23-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.51, 4.0

 - Microsoft Win32s version 1.3

SUMMARY

One of the limitations of the ListView common control is that when the

control is in report view, the control only highlights the first column

when a row is selected. To work around this limitation, you can create the

ListView as an owner draw control (using the LVS_OWNERDRAWFIXED style) and

perform all the painting yourself.

The ODLISTVW sample demonstrates how to create an owner draw ListView

control that highlights an entire row.

Download ODLISTVW.EXE, a self-extracting file, from the Microsoft

Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for ODLISTVW.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download ODLISTVW.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the SOFTLIB\MSLFILES directory

      Get ODLISTVW.EXE

MORE INFORMATION

One of the supported styles for the ListView control is LVS_OWNERDRAWFIXED,

which allows the program to perform all the drawing of items in the

ListView control. Whenever the ListView control needs to have a portion of

the control repainted, it calculates which items are in that area and sends

a WM_DRAWITEM message to its parent for each item. If any part of an item

needs to be redrawn, the ListView sends the WM_DRAWITEM with the update

rectangle set to the entire item.

The ListView control handles owner drawn items differently from other owner

drawn controls. Previous owner drawn controls use the DRAWITEMSTRUCT's

itemAction field to let the parent know if it needs to draw the item,

change the selected state, or change the focus state. The ListView control

always sends the WM_DRAWITEM message with the itemAction set to

ODA_DRAWENTIRE. The parent needs to check the itemState to see if the focus

or selection needs to be updated.

Additional reference words: 1.30 4.00 95 3.51

KBCategory: kbui kbprg kbfile

KBSubcategory: UsrCtl


SAMPLE: How to Simulate Multiple-Selection TreeView Control

PSS ID Number: Q125587

Authored 31-Jan-1995	Last modified 20-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

SUMMARY

The TVWSTATE sample demonstrates how to simulate a multiple-selection

TreeView control. The Windows 95 TreeView control does not support multiple

selection. If you want a multiple-selection TreeView, you can use state

images to simulate it in your application.

The TVWSTATE sample accomplishes this by using a checkbox type of state

image to indicate that the item is selected or cleared (de-selected). These

checkboxes will retain their state even if the TreeView loses focus.

Download TVWSTATE.EXE, a self-extracting file, from the Microsoft

Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for TVWSTATE.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download TVWSTATE.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the SOFTLIB\MSLFILES directory

      Get TVWSTATE.EXE

MORE INFORMATION

The multiple-selection TreeView control simulation is implemented by

setting the state image list of the TreeView control to an image list that

contains the checked and unchecked checkbox bitmaps. This image list is set

by using the TVM_SETIMAGELIST message with lParam == TVSIL_STATE (see

InitImageList in TVWSTATE.C). A TreeView control can have two image lists,

a normal image list and a state image list. In the TreeView, the display

order from left to right is: the expansion button, the state image (if

present), the normal image (if present), and then the item text.

When processing the WM_NOTIFY message where (LPNMHDR)lParam->code ==

NM_CLICK (see MsgNotifyTreeView in TVWSTATE.C), the code checks to see if

the user clicked the left mouse button in the checkbox. If this is the

case, the state image index of the item is retrieved, the index is toggled

between the checked and unchecked image list items, and then the new index

is saved.

The state image index identifies which member of the state image list

should be displayed. The state image index is stored in bits 12-16 of the

item state value. Either TVIS_STATEIMAGEMASK or TVIS_USERMASK can be used

to mask off the lower bits. To access just the state image index, use a

statement similar to this:

   StateIndex = tvi.state & TVIS_STATEIMAGEMASK;

The INDEXTOSTATEIMAGEMASK macro offsets a value to the correct bits for the

state image index. This is accomplished by shifting the given value left 12

places. If the desired state image index is 1, the state can be set using a

statement similar to this:

   tvi.state = INDEXTOSTATEIMAGEMASK(1);

This sample can also be modified to implement selection methods similar to

those of an extended-selection listbox where the user uses the SHIFT key to

select a range of items and/or the CTRL key to select or clear individual

items.

Additional reference words: 3.51 4.00

KBCategory: kbprg kbcode kbfile

KBSubcategory: UsrCtl


SAMPLE: How to Use File Associations

PSS ID Number: Q122787

Authored 13-Nov-1994	Last modified 20-Jun-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK), version 3.1

 - Microsoft Win32 SDK, versions 3.1 and 3.5

SUMMARY

Windows provides file associations so that an application can register the

type of documents it supports. The benefit of doing this is that it allows

the user to double-click or select a document in File Manager to edit or

print it. File association is also supported by the ShellExecute() API.

File associations also allow the user to open multiple documents with a

single instance of the application via the File Manager.

ShellExecute() has even more benefit in Windows 95.

The sample FILEASSO.EXE demonstrates how to use file associations. Download

FILEASSO.EXE, a self-extracting file, from the Microsoft Software Library

(MSL) on the following services:

 - CompuServe

      GO MSL

      Search for FILEASSO.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download FILEASSO.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the SOFTLIB\MSLFILES directory

      Get FILEASSO.EXE

MORE INFORMATION

The following information applies to both File Open and File Print. For

ease of reading, this article will discuss File Open to explain how File

Associations work.

When the user double-clicks a document, the File Manager calls

ShellExecute() with filename. ShellExecute() checks the Registration

Database for an entry that associates that file extension with a particular

application. If an entry exists and does not specify DDE commands, then

ShellExecute() launches the application as specified in the registry. If

the registry specifies to use DDE commands, ShellExecute() attempts to

establish a DDE conversation with that application using the application

topic. If an application responds to the DDE connections, ShellExecute()

sends a DDE Execute command, as specified in the registry. It is up to the

application to define the specifics on this conversation, particularly the

service and topic name to connect to, and also the correct DDE execute

command syntax to use. However, if attempts to establish the conversation

fail, ShellExecute() launches the application specified in the regiistry

and tries to establish the DDE connection again.

There is one more option available when the application is not running,

which seems to be appropriate for File Print. In this option,

ShellExecute() sends a different Execute statement, the application needs

to Open and Print the document. When the Printing is done, it exits.

There are two steps for an application to open multiple documents through

single application instance via File association. As an example, assume

MyApp is the application and AssocSupport is the topic. Most applications

use MyApp as their application name and System as the topic.

1. When the application starts, register a DDE Server with the

   application name and topic (for example MyApp, and AssocSupport).

   The application also has to support DDE Execute Statements. The

   execute statement could be any format; at minimum, it should be:

      <Action> <fileName> <options>

   Here <Action> is anything specifying unique identification of the

   action, such as Open or Print. The <fileName> is the file that should be

   operated on. Finally, <options> can be any options that need to be

   passed on.

   A typical Execute Statement follows this format:

      [<Action>(<FileName>)]

   For example, Microsoft Word uses:

      [Open("%1")]

   The Application has to support the required functionality for executed

   statements.

2. File association can be done in Windows NT via File Manager or regedit.

Using the File Manager to Set File Associations

-----------------------------------------------

When associating a file type using the File Manager, choose Associate from

the File menu. The Associate dialog presents the list of existing file

associations. This dialog allows you to add a new file type (or file

association), modify an existing file type, or delete an existing file

type. The New File Type button allows the user to add an association for a

new file extension. Here are the steps:

1. Add a File type name. For example, name it "Microsoft Word 6.0

   Document."

2. Choose an action (Open or Print). For example, select the Uses DDE

   check box.

3. Add the directory path and application name. For example, enter

   WINWORD as the application.

4. Select the option Uses DDE.

5. Set the Application as the DDE Server Name.

6. Set the Topic as the DDE Server. For example enter System as the

   Topic.

7. Set the DDE Message <Action> <fileName> <options> to be the same as

   your application's Execute Statement. However the <fileName> and

   <options> should be replaced by whatever the command line arguments

   are. For example use:

      DDE Message : [FileOpen("%1")]

Using Regedit in Windows NT to Set File Associations

----------------------------------------------------

NOTE: Regedit is available only in Windows NT, not in Windows version 3.1.

The user can also associate files with an application by using regedit.

From the Edit menu, choose Add File Type or Modify File Type (to modify an

existing file type). A dialog similar to File Manager Associate dialog

appears. Follow the same steps as described for File Manager. In Windows

version 3.1, once you have defined a File Type via this method, go to the

File Manager associate dialog and attach the file type to the extension.

Using a Program to Set File Assoications

----------------------------------------

You can also set the associations programmatically. This is useful when

setting up your application on other machines. You would provide this

functionality through your installation program. The first way to do this

(the simplier method) is to use regedit to merge the changes from a file.

The syntax for this is:

   regedit <filename>.reg

An example of a <filename>.reg is:

   REGEDIT

   HKEY_CLASSES_ROOT\.riy = FMA000_File_assoc

   HKEY_CLASSES_ROOT\FMA000_File_assoc = File_assoc

   HKEY_CLASSES_ROOT\FMA000_File_assoc\shell\open\command = fileasso.EXE

   HKEY_CLASSES_ROOT\FMA000_File_assoc\shell\open\ddeexec = [Open(%1)]

   HKEY_CLASSES_ROOT\FMA000_File_assoc\shell\open\ddeexec\application

= Myserver

   HKEY_CLASSES_ROOT\FMA000_File_assoc\shell\open\ddeexec\topic = system

   HKEY_CLASSES_ROOT\FMA000_File_assoc\shell\print\command = fileasso.EXE

   HKEY_CLASSES_ROOT\FMA000_File_assoc\shell\print\ddeexec = [Open(%1)]

HKEY_CLASSES_ROOT\FMA000_File_assoc\shell\print\ddeexec\application =

MYServer

   HKEY_CLASSES_ROOT\FMA000_File_assoc\shell\print\ddeexec\topic = System

   HKEY_CLASSES_ROOT\FMA000_File_assoc\shell\print\ddeexec\ifexec =

[Test(%1)

]

In the program, you can also add keys to the registry by using the registry

APIs. The developer needs to add the following keys to the registration

database:

   // Your extensions.

   HKEY_CLASSES_ROOT\.riy = FMA000_File_assoc

   //File type name.

   HKEY_CLASSES_ROOT\FMA000_File_assoc = File_assoc

   // Command to execute when application is not running or dde is not

   // present and Open command is issued.

   HKEY_CLASSES_ROOT\FMA000_File_assoc\shell\open\command = fileasso.EXE

   // DDE execute statement for Open.

   HKEY_CLASSES_ROOT\FMA000_File_assoc\shell\open\ddeexec = [Open(%1)]

   // The server name your application responds to.

   HKEY_CLASSES_ROOT\FMA000_File_assoc\shell\open\ddeexec\application =

   Myserver

   // Topic name your application responds to.

   HKEY_CLASSES_ROOT\FMA000_File_assoc\shell\open\ddeexec\topic = system

   // Command to execute when application is not running or dde is not

   // present and print command is issued.

   HKEY_CLASSES_ROOT\FMA000_File_assoc\shell\print\command = fileasso.EXE

   // DDE execute statement for Print.

   HKEY_CLASSES_ROOT\FMA000_File_assoc\shell\print\ddeexec = [Open(%1)]

   // The server name your application responds to.

   HKEY_CLASSES_ROOT\FMA000_File_assoc\shell\print\ddeexec\application =

   MYServer

   // Topic name your application responds to.

   HKEY_CLASSES_ROOT\FMA000_File assoc\shell\print\ddeexec\topic = System

   // DDE execute statement for print if the application is not already

   // running. This gives the options for a an application to Run, Print

   // and Exit.

   HKEY_CLASSES_ROOT\FMA000_File assoc\shell\print\ddeexec\ifexec =

   [Test(%1)]

REFERENCES

Windows SDK Programmers Reference, Volume 1, chapter 7, Shell Library or

Books Online.

Window 3.1 SDK Help file, Registration Database, Shell Library Functions.

Win32 Programmers Reference, Volume 2, chapter 52, Registry and

Initialization Files or Books Online.

Win32 SDK Help file Registry and Initialization

File Manager Help File.

REGEDIT.HLP

REGEDT32.HLP

Additional reference words: 3.10 3.50

KBCategory: kbprg kbfile

KBSubcategory: UsrMisc


SAMPLE: How to Use Paths to Create Text Effects

PSS ID Number: Q128091

Authored 26-Mar-1995	Last modified 20-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

This article defines the term "path" for the purposes of this article, and

it explains how you can get sample code (provided in TEXTFX.EXE, a self-

extracting file) that shows by example how to use paths to draw text at

varying angles, orientations, and sizes. In addition, the sample code gives

useful routines for displaying path data.

Download TEXTFX.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for TEXTFX.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download TEXTFX.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get TEXTFX.EXE

MORE INFORMATION

A path is one or more figures (or shapes) that are filled, outlined, or

both filled and outlined. Computer-aided design (CAD) applications use

paths to create unique clipping regions, to draw outlines of irregular

shapes, and to fill the interiors of irregular shapes.

A path is associated with a Device Context (DC) but unlike other objects

associated with a DC, such as pens and brushes, a path has no default

object.

To create a path, you first call BeginPath(). Then use the drawing

functions in the table below to add to the path. Any drawing done using

these functions is recorded as part of the path. When you finish building

the path, call EndPath(). The new path can then be converted to a region by

using PathToRegion(), selected as a clipping region for a device context by

using SelectClipPath(), and rendered by using StrokePath() or FillPath().

In addition, as this sample illustrates, the path can be retrieved by using

GetPath() and manipulated programmatically.

Functions supported in paths:

   AngleArc      LineTo         Polyline

   Arc           MoveToEx       PolylineTo

   ArcTo         Pie            PolyPolygon

   Chord         PolyBezier     PolyPolyline

   CloseFigure   PolyBezierTo   Rectangle

   Ellipse       PolyDraw       RoundRect

   ExtTextOut    Polygon        TextOut

Functions not supported under Windows 95:

AngleArc

ArcTo

PolyDraw

Functions not supported in a path under Windows 95:

Arc

Chord

Ellipse

Pie

Rectangle

RoundRect

MORE INFORMATION

The following path functions are used in the TextFX sample:

   BeginPath

   EndPath

   GetPath

   FillPath

   StrokePath

To use TextFX, run it, and then draw two lines into the client area (they

don't have to be straight). The first line appears as blue and the second

appears as red. These lines serve as guides for how the text will be

rendered. After completing the second line, the text "This is a test" will

be drawn so that it appears between the two guide lines.

To remap the text so that it appears between the two lines, TextFX first

breaks down the guide lines (which are composed of line segments) into

distinct adjacent points. The result is that the x,y position of each point

in the lines is adjacent to its neighboring points x,y position.

Next, the text "This is a test" is drawn into a device context as a path.

The points that make up the lines and curves in this path are then

retrieved from the device context by using the GetPath() function.

To reposition the points in the path data, the code must establish a

relationship between the relative position of the points in the original

text and the position defined by the guide lines. To establish this

relationship, the code calculates the x and y positions of each point in

the path data relative to the overall extent of the text string. The

relative x position is used to calculate a corresponding point on each of

the two the guide lines, while the relative y value is used as a weight to

determine how far along on a line between the two guide line points the

remapped position should be.

For example, if the point in the upper left corner of the "T" in the string

"This is a test" is 2% of the total x extent of the string and 10% of the

total y extent, then TextFX would find the point in each guide line that

corresponds to 2% of the total number of points in that guide line. Then

TextFX would reposition the point in the path data representing the upper

left corner of the "T" so that it would be 10% of the way along an

imaginary line extending from the point on the top guide line to the point

on the bottom guide line.

Two different methods can be selected for drawing the remapped data, one

draws just the outline of the characters, while the other fills in the

characters.

To draw the outline of the characters, TextFX converts the remapped data

back into a path and uses StrokePath() to display the outlines. To do the

conversion, TextFX begins a new path, and then loops through the remapped

data and uses the vertex types returned from GetPath() to determine how to

draw the points. After drawing all the data, TextFX ends the path and calls

StrokePath().

To draw the solid characters, instead of using StrokePath(), TextFX uses

FillPath(). However, in order to get the interior areas of characters like

"O", "A", "D", and so on, TextFX sets the ROP2 code to R2_MERGEPENNOT

before calling FillPath(). This is done so that characters like "O" that

consist of two separate polygons (one representing the outer perimeter and

one representing the inner perimeter) will not be drawn as a solid blob. By

drawing the polygons with the R2_MERGEPENNOT code, the code ensures that

the second polygon will cancel the effects of the first in the area of the

inner polygon.

REFERENCES

For additional information on paths, please see the PATHS sample included

with the Win32 SDK.

Additional reference words: 3.10 3.50 4.00 stones effects effect font fx

KBCategory: kbprg kbfile kbcode

KBSubcategory: GdiDrw


SAMPLE: Implementing Multiple Threads in an OpenGL

PSS ID Number: Q128122

Authored 27-Mar-1995	Last modified 20-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

It is possible to create multiple threads in an OpenGL application and have

each thread call OpenGL functions to draw an image. You might want to do

this when multiple objects need to be drawn at the same time or when you

want to have certain threads perform the rendering of specific types of

objects.

This article explains how to obtain GLTHREAD, a sample that demonstrates

how to implement multiple threads in an OpenGL application. The main

process default thread creates two threads that each draw a

three-dimensional wave on the main window. The first thread draws a wave on

the left side of the screen. The second thread draws a wave on the right

side of the screen. Both objects are drawn simultaneously, demonstrating

OpenGL's ability to handle multiple threads.

How to Get the GLTHREAD Sample

------------------------------

Download GLTHREAD.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for GLTHREAD.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download GLTHREAD.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get GLTHREAD.EXE

MORE INFORMATION

When implementing multiple threads in any type of application, it is

important to have adequate communication between threads. In OpenGL, it is

important for two threads to know what the other thread is doing. For

example, it is common practice to clear the display window before drawing

an OpenGL scene. If both threads are called to draw portions of a scene and

they both try to call glClear before drawing, one thread's object may get

erased by another thread's call to glClear.

The GLTHREAD sample assigns the glClear function to a single thread, and

ensures that the other thread does not perform any drawing until glClear

has been called. When a menu command message is sent to the main window,

the application calls CreateThread twice to create two threads. Each thread

calls GetDC(hwndMain) to obtain its own device context to the main window.

Then, each thread calls GLTHREAD's bSetupPixelFormat function to set up the

pixel format and calls wglCreateContext to create a new OpenGL Rendering

Context. Now, each thread has its own Rendering Context and both can call

wglMakeCurrent to make its new OpenGL rendering context its (the calling

thread's) current rendering context.

All subsequent OpenGL calls made by the thread are drawn on the device

identified by the HDC returned from each thread's call to GetDC(). Now,

because only one thread should call glClear, GLTHREAD has thread number one

call it. The second thread is created "suspended" so it does nothing until

a call to ResumeThread is made. After thread one has called glClear, it

enables thread two to resume by calling ResumeThread with a handle to the

second thread.

The procedure in the main thread that created the two other threads waits

until both threads are finished before returning from the processing of the

menu command message that is sent when the user selects the "Draw Waves"

menu selection from the "Test Threads" menu. It will use the

WaitForMultipleObjects function to do this.

Additional reference words: 3.10 3.50 4.00 95  GDI GRAPHICS THREADS

KBCategory: kbprg kbgraphic kbfile kbcode

KBSubcategory: codesam GdiDrwOpenGL


SAMPLE: MFCOGL a Generic MFC OpenGL Code Sample

PSS ID Number: Q127071

Authored 12-Mar-1995	Last modified 20-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.5, 3.51,

   and 4.0

 - The Microsoft Foundation Classes (MFC) included with:

    - Microsoft Visual C++ 32-bit Edition, versions 2.0 and 2.1

SUMMARY

Microsoft Windows NT's OpenGL can be used with the Microsoft Foundation

Class (MFC) library. This article gives you the steps to follow to enable

MFC applications to use OpenGL.

The companion sample (MFCOGL) is a generic sample that demonstrates using

OpenGL with MFC. Download MFCOGL.EXE, a self-extracting file, from the

Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for MFCOGL.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download MFCOGL.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the SOFTLIB\MSLFILES directory

      Get MFCOGL.EXE

MORE INFORMATION

Step-by-Step Example to Use OpenGL in MFC Application

-----------------------------------------------------

1. Include the necessary header files to use OpenGL including:

    - "gl\gl.h" for all core OpenGL library fuctions. These functions

      have the "gl" prefix such as glBegin().

    - "gl\glu.h" for all OpenGL utility library functions. These

      functions have the "glu" prefix such as gluLookAt().

    - "gl\glaux.h" for all Windows NT OpenGL auxilary library functions.

      These functions have the "aux" prefix such as auxSphere().

   You don't need to add a header file for functions with the "wgl" prefix.

2. Add necessary library modules to the link project settings. These

   library modules include OPENGL32.LIB, GLU32.LIB, and GLAUX.LIB.

3. Add implementations for OnPaletteChanged() and OnQueryNewPalette() in

   CMainFrame class for palette-aware applications.

   void CMainFrame::OnPaletteChanged(CWnd* pFocusWnd)

   {

       CFrameWnd::OnPaletteChanged(pFocusWnd);

       if (pFocusWnd != this)

           OnQueryNewPalette();

   }

   BOOL CMainFrame::OnQueryNewPalette()

   {

       WORD   i;

       CPalette   *pOldPal;

       CMfcOglView *pView = (CMfcOglView *)GetActiveView();

       CClientDC   dc(pView);

       pOldPal = dc.SelectPalette(&pView->m_cPalette, FALSE);

       i = dc.RealizePalette();

       dc.SelectPalette(pOldPal, FALSE);

       if (i > 0)

           InvalidateRect(NULL);

       return CFrameWnd::OnQueryNewPalette();

   }

4. Use the one or more of the following classes derived from CWnd,

   including view classes, that will use OpenGL for rendering onto:

    - Implement PreCreateWindow() and add WS_CLIPSIBLINGS and

      WS_CLIPCHILDREN to the windows styles:

      BOOL CMfcOglView::PreCreateWindow(CREATESTRUCT& cs)

      {

          cs.style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN;

          return CView::PreCreateWindow(cs);

      }

    - Implement OnCreate() to initialize a rendering context and make

      it current. Also, initialize any OpenGL states here:

      int CMfcOglView::OnCreate(LPCREATESTRUCT lpCreateStruct)

      {

          if (CView::OnCreate(lpCreateStruct) == -1)

              return -1;

          Init(); // initialize OpenGL

          return 0;

      }

    - Implement OnSize() if the window is sizeable:

      void CMfcOglView::OnSize(UINT nType, int cx, int cy)

      {

          CView::OnSize(nType, cx, cy);

          if (cy > 0)

          {

              glViewport(0, 0, cx, cy);

              if ((m_oldRect.right > cx) || (m_oldRect.bottom > cy))

                  RedrawWindow();

              m_oldRect.right = cx;

              m_oldRect.bottom = cy;

              glMatrixMode(GL_PROJECTION);

              glLoadIdentity();

              gluPerspective(45.0f, (GLdouble)cx / cy, 3.0f, 7.0f);

              glMatrixMode(GL_MODELVIEW);

          }

      }

    - Implement OpenGL rendering code. This can be done in OnDraw() or

      other application-specific places such as OnTimer().

    - Implement clean-up code, which is typically done in OnDestroy():

      void CMfcOglView::OnDestroy()

      {

          HGLRC   hrc;

          if (m_nTimerID)

              KillTimer(m_nTimerID);

          hrc = ::wglGetCurrentContext();

          ::wglMakeCurrent(NULL,  NULL);

          if (hrc)

              ::wglDeleteContext(hrc);

          CPalette    palDefault;

          // Select our palette out of the dc

          palDefault.CreateStockObject(DEFAULT_PALETTE);

          m_pDC->SelectPalette(&palDefault, FALSE);

          if (m_pDC)

              delete m_pDC;

          CView::OnDestroy();

      }

Additional reference words: 3.50 3.51 2.00 2.10 3.00 3.10 4.00 95 graphics

KBCategory: kbprg kbcode kbfile

KBSubcategory: GdiOpenGL


SAMPLE: RASberry - an RAS API Demonstration

PSS ID Number: Q118983

Authored 03-Aug-1994	Last modified 20-Jun-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   version 3.1

 - Microsoft Win32 SDK, versions 3.1, 3.5, 3.51, and 4.0

SUMMARY

RASberry is a sample application that demonstrates the Remote Access

Service (RAS) API. RASberry allows the user to enumerate current RAS

connections, display the status of a selected connection, dial entries from

the default phone book, and hang up an active connection. The sample may be

built for both Windows version 3.1 and Win32 environments.

RASBRY.EXE can be downloaded as a self-extracting file from the Microsoft

Software Library (MSL) on the following services:

 - CompuServe

      GO MSL and download RASBRY.EXE

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download RASBRY.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get RASBRY.EXE

MORE INFORMATION

The RAS APIs used in this sample are:

 - RasDial

 - RasEnumConnections

 - RasEnumEntries

 - RasGetConnectStatus

 - RasGetErrorString

 - RasHangUp

The RAS SDK for Win32 is included as part of the Win32 SDK.

The RAS SDK for Windows version 3.1 (which contains additional files that

can be used with the Windows version 3.1 SDK for RAS development) is

available on the Microsoft Developer's Network Level 2 CD set, beginning

with the April 1994 edition.

Additional reference words: 3.10 3.50 4.00 95 softlib

KBCategory: kbnetwork kbprg kbfile

KBSubcategory: NtwkRAS


SAMPLE: RESIZE App Shows How to Resize a Window in Jumps

PSS ID Number: Q123605

Authored 05-Dec-1994	Last modified 20-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

SUMMARY

Sometimes it's useful to have a window that can only be certain sizes. For

example, Microsoft Word and Microsoft Visual C++ have toolbars that are

resizable only to particular sizes that best fit the controls in the

toolbar. When you do this, it's a good idea to give the user visual cues

about the available window sizes. The RESIZE sample code shows by example

how to modify the way Windows resizes a window so that when a user uses the

mouse to resize the window the border jumps automatically to the next

available size.

To obtain the RESIZE sample code, download RESIZE.EXE, a self-extracting

file, from the Microsoft Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for RESIZE.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download RESIZE.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the SOFTLIB\MSLFILES directory

      Get RESIZE.EXE

MORE INFORMATION

When a user clicks the resizing border of a window, Windows enters a

PeekMessage loop to capture all the mouse messages that occur until the

left mouse button is released. While inside this loop, every time the mouse

moves it moves the rectangle that shows the new window size to provide a

visual cue to the user as to what the new window size will be.

The RESIZE sample code modifies the resizing operation by entering it's own

message loop to capture the mouse messages until the left button is

released. Instead of updating the rectangle every time a mouse move is

received, the RESIZE code checks to see if the current mouse position would

make the window size one of the possible window width and height sizes as

defined by the application. By doing this, the RESIZE application provides

more accurate visual cues about what the resizing operation will do.

The resizing operation is triggered by the WM_NCLBUTTONDOWN message both

for Windows and the RESIZE application. When this message is received, a

message loop is entered to filter out all the mouse messages except for

two, WM_MOUSEMOVE and WM_LBUTTONUP. When the WM_MOUSEMOVE message is

received, the RESIZE application checks to see if the current mouse

position would make the window larger or smaller. If the window would be

smaller, the resizing rectangle is moved to the next smaller dimension

defined by the application. If the window would be larger, the program

checks to see if the new size would be large enough for the next possible

dimension and updates the rectangle accordingly. When the WM_LBUTTONUP

message is received, the resizing operation is completed by updating the

window size to the current position defined by the mouse and the rectangle

is removed.

The RESIZE application also takes advantage of some of the flexibility

provided by processing the WM_NCHITTEST message. Windows sends this message

to an application with a mouse position and expects the application to

describe which part of the window that mouse position covers. Frequently,

applications pass this message on to DefWindowProc() and let the default

calculations take care of telling the system what the mouse is on top of.

The RESIZE application allows DefWindowProc() to process the message, but

then checks to see if the mouse is over one of the resizing corners or in

the client area. To simplify the resizing operation, RESIZE doesn't let the

user resize from a window corner, so the application overrides the

HTBOTTOMLEFT, HTBOTTOMRIGHT, HTTOPLEFT, and HTTOPRIGHT hit test codes and

returns HTBOTTOM or HTTOP. By doing this, the mouse cursor accurately

reflects the direction of the resize. When the HTCLIENT hit test code is

returned, RESIZE changes this to HTCAPTION to allow the window to be moved

even though it doesn't have a title bar.

Although this technique will work in Windows 95, it is not necessary.

Windows 95 provides a new message WM_SIZING that will enable the program to

do exactly the same thing without processing the WM_NCxxx messages or

entering a PeekMessage() loop.

Additional reference words: 3.10 3.50 4.00

KBCategory: kbprg kbui kbcode kbfile

KBSubcategory: UsrWndw


SAMPLE: SCLBLDLG - Demonstrates Scaleable Controls in Dialog

PSS ID Number: Q112639

Authored 15-Mar-1994	Last modified 20-Jun-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK, versions 3.1, 3.5, 3.51, 4.0

SUMMARY

In certain circumstances it is desirable to dynamically scale the controls

in a dialog box to the size of the dialog box window. SCLBLDLG.EXE is a

file in the Microsoft Software Library that contains sample code

implementing scaleable controls in a dialog box.

SCLBLDLG can be downloaded as a self-extracting file from the Microsoft

Software Library (MSL) on the following services:

 - CompuServe

      GO MSL and download SCLBLDLG.EXE

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download SCLBLDLG.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get SCLBLDLG.EXE

MORE INFORMATION

To accomplish scaleable controls in a dialog box, the following messages

are processed:

   WM_INITDIALOG - To store original dimensions of the dialog box and all

   its controls, together with the font the dialog box uses. The original

   dimensions are stored using SetProp() in this sample. The font handle is

   stored in a static variable to be used with in WM_SIZE.

   WM_SIZE - To calculate the scaling factor, and then scale up or down the

   font and all the controls in the dialog box.

   WM_GETMINMAXINFO - To set the minimum size of the dialog box so the

   controls are not truncated.

   WM_COMMAND - To clean up when closing the dialog box. RemoveProp() is

   called to remove the stored dimensions from the property list of the

   dialog box window and all its child control windows.

NOTE: Special processing is required for calculating the dimensions of

CBS_DROPDOWN and CBS_DROPDOWNLIST style combo boxes. GetWindowRect()

returns the dimensions of the edit portion of the combo box, excluding the

drop-down list. To get the correct height for such combo boxes, the value

returned by CB_GETDROPPEDCONTROLRECT is used instead of GetWindowRect().

Additional reference words: 3.10 3.50 3.51 4.00 95  proportional sizing

softlib

KBCategory: kbprg kbfile

KBSubcategory: UsrDlgs


SAMPLE: ServerEnumDialog DLL

PSS ID Number: Q118327

Authored 14-Jul-1994	Last modified 20-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

SUMMARY

SERVENUM is a dynamic-link library (DLL) that implements a multithreaded

dialog box, allowing a user to browse the network for servers. The dialog

box is instantiated by calling the ServerEnumDialog application programming

interface (API) implemented in the SERVENUM.DLL.

Download SRVENM.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL and download SRVENM.EXE

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download SRVENM.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \softlib\mslfiles directory

      Get SRVENM.EXE

MORE INFORMATION

The Win32 application programming interface (API) implements several WNet

dialog boxes that allow users to connect to and browse network resources.

However, an API allowing a user to browse the network for servers is

currently not implemented.

Because such a dialog box is often useful in network programs, the SERVENUM

sample implements such a dialog box within a DLL. The sample also includes

a simple Windows program that calls the ServerEnumDialog API implemented in

SERVENUM.DLL of the sample. For redistribution issues of the DLL, please

see the README.TXT file included with the sample.

This sample demonstrates the following Win32 programming issues:

   DLLs

   thread local storage

   multithreading and thread synchronization

   owner-draw list boxes

   Unicode

   WNet APIs

API Interface

-------------

ServerEnumDialog(

   HWND hwnd,              // Handle of calling window

   LPWSTR lpszServer,      // Buffer to store chosen server name

   LPDWORD lpcchServer,    // Pointer to size of buffer in bytes

   FARPROC lpfnHelpProc    // User-defined help procedure

   )

Purpose:

   Display a dialog box that allows a user to select a computer on the

   network. The user may also type in a string. The result is not

   guaranteed to be a valid computer name.

Parameters:

   hwnd - Handle of calling window

   lpszServer - Buffer to store resultant server name in. This should be of

                length MAX_COMPUTERNAME_LENGTH+3

   lpcchServer - Pointer to size of lpszServer, including the NULL

                 terminating character. The resultant length of the string

                 is stored here. If ERROR_MORE_DATA is return, the value is

                 the required size of the buffer.

   lpfnHelpProc - Pointer to user-defined help procedure. The procedure

                  should be prototyped as int HelpProc( VOID );

 Return Value:

   ERROR_SUCCESS - User selected or typed in a server name

   ERROR_CANCELLED - Dialog box was canceled

   ERROR_NOT_ENOUGH_MEMORY - Unable to initialize dialog box

   ERROR_MORE_DATA - lpszServer not large enough

Additional reference words: 3.10 WNetServerBrowseDialog softlib SRVENM.EXE

KBCategory: kbprg kbfile

KBSubcategory: NtwkWinnet


SAMPLE: Setting Tab Stops in a Windows List Box

PSS ID Number: Q66652

Authored 01-Nov-1990	Last modified 20-Jun-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.1, 3.5, 3.51, and 4.0

SUMMARY

Tab stops can be used in a list box to align columns of information. This

article describes how to set tab stops in a list box and provides a code

example that demonstrates the process.

MORE INFORMATION

To set tab stops in a list box, perform the following three steps:

1. Specify the LBS_USETABSTOPS style when creating the list box.

2. Assign the desired tab stops to an integer array.

   a. The tab stop values must be in increasing order -- back tab

      stops are not allowed. The tabs work the same as typewriter

      tabs: once a tab stop is overrun, a tab character will move

      the cursor to the next tab stop. If the tab stop list is

      overrun (that is, the current position is greater than the last

      tab stop value), the default tab of eight characters is used.

   b. The tab stops should be specified in dialog units. On the

      average, each character is about four horizontal dialog units in

      width.

   c. It is possible to hide columns of text from the user by

      specifying tab stops beyond the right side of the list box. This

      can be a useful way to hide information used for the

      application's internal processing.

3. Send an LB_SETTABSTOPS message to the list box to set the tab

   stops. For example, in Windows 3.1:

      SendMessage(GetDlgItem(hDlg, IDD_LISTBOX),

                  LB_SETTABSTOPS,

                  TOTAL_TABS,

                  (LONG)(LPSTR)TabStopList);

   a. If wParam is set to 0 (zero) and lParam to NULL, the tab stops are

      set to two dialog units by default.

   b. SendMessage() will return TRUE if all of the tab stops are set

      successfully; otherwise, SendMessage() returns FALSE.

Example

-------

Below is an example of the process. Tab stops are set at character

positions 16, 32, 58, and 84.

   int     TabStopList[TOTAL_TABS]; /*  Array to store tabs */

   TabStopList[0] = 16 * 4;          /* 16 spaces */

   TabStopList[1] = 32 * 4;          /* 32 spaces */

   TabStopList[2] = 58 * 4;          /* 58 spaces */

   TabStopList[3] = 84 * 4;          /* 84 spaces */

   SendMessage(GetDlgItem(hDlg, IDD_LISTBOX),

               LB_SETTABSTOPS,

               TOTAL_TABS,

               (LONG)(LPSTR)TabStopList);

NOTE: For Win32, use LPARAM instead of LONG.

If the desired unit of measure is character position, then specifying

tab positions in dialog units is recommended. Dialog units are

independent of the current font; they are loosely based on the average

width of the system font. Each character takes approximately four

dialog units.

NOTE: Under Windows 95, dialog base units for dialogs based on non-system

fonts are calculated in a different way than under Windows 3.1. For more

information, please see the following article in the Microsoft Knowledge

Base:

   ARTICLE-ID: Q125681

   TITLE     : How to Calculate Dialog Base Units with Non-system-based

               Font

For more control over the exact placement of a tab stop, the desired

position should be converted to a pixel offset and this offset should

be converted into dialog units. The following formula will take a

pixel position and convert it into the first tab stop position before

(or at) the desired pixel position:

   TabStopList[n] = 4 * DesiredPixelPosition /

                     LOWORD(GetDialogBaseUnits());

There is a sample application named TABSTOPS in the Microsoft Software

Library that demonstrates how tab stops are set and used in a list

box.

Download TABSTOPS.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for TABSTOPS.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download TABSTOPS.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get TABSTOPS.EXE

Additional reference words: 3.00 3.10 3.50 4.00 softlib

KBCategory: kbprg kbfile

KBSubcategory: UsrCtl


SAMPLE: Simulating Palette Animation on Non-Palette Displays

PSS ID Number: Q130476

Authored 21-May-1995	Last modified 20-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   version 3.5

SUMMARY

LAVALAMP is a sample application in the Microsoft Software Library that

demonstrates how to simulate the effects of the AnimatePalette() function

on devices that may not support palettes. This program also demonstrates

how to create and manipulate dibsections. The following dibsection

functions are used in LAVALAMP:

   CreateDIBSection()

   GetDIBColorTable()

   SetDIBColorTable()

Download LAVALAMP.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for LAVALAMP.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download LAVALAMP.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get LAVALAMP.EXE

MORE INFORMATION

When running in display modes that are not palette-based, many of the

effects that can be performed easily with palette animation need to be

reprogrammed. A simple method of simulating palette animation can be

achieved by "animating" a device-independent bitmap's (DIBs) color table

and redisplaying the DIB with the new colors. To demonstrate this

technique, LAVALAMP creates an 8-bits-per-pixel (bpp) dibsection. Then it

shifts each of the RGBQUAD data structures in the color table by one

position to the left, and recycles the first entry in the color table to

the last position. After each modification to the color

table, the DIB is redisplayed.

Because the entire DIB must be redisplayed after each modification to the

color table, this technique is not recommended for large bitmaps.

Additional reference words: 3.50 technote BMP softlib

KBCategory: kbprg kbfile

KBSubcategory: GdiBmp GdiPal


SAMPLE: Using Blinking Text in an Application

PSS ID Number: Q11787

Authored 17-Dec-1987	Last modified 20-Jun-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

It is possible to create blinking text in a Windows-based application.

Because there are no character attributes similar to the normal MS-DOS text

environment, the application must repeatedly paint the screen to implement

the flash. This article, and an accompanying file in the Microsoft Software

Library, demonstrate how this is done.

MORE INFORMATION

A timer is used to determine the rate at which the text flashes. Timer

messages are processed by inverting the appropriate area in the window

using the DSTINVERT action of the PatBlt function. The second time that the

PatBlt function is called, the text returns to its original state.

Alternatively, the PATINVERT action of the PatBlt function may be used. To

use this method, an appropriate brush must be selected into the display

context as the current pattern. This method requires more work, however, it

is more flexible.

The rate at which the text blinks can be set to match the cursor blink time

set in the Control Panel. To do this, the following code should be run when

the application starts and in response to WM_WININICHANGE messages:

   nRate = GetProfileInt(

     (LPSTR)"windows",         /* heading in [] */

     (LPSTR)"CursorBlinkRate", /* string to match */

      550);                    /* default value */

Be sure to delete the timer when the application terminates.

There is a sample program in the Microsoft Software Library named BLINK

that uses this technique to demonstrate blinking text.

Download BLINK.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for BLINK.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download BLINK.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get BLINK.EXE

Additional reference words: 3.00 3.10 3.50 4.00 95  softlib BLINK.EXE

KBCategory: kbprg kbfile

KBSubcategory: UsrPnt


SAMPLE: Win16 App (WOW & Win32s) Calling Win32 DLL Code

PSS ID Number: Q114341

Authored 01-May-1994	Last modified 10-Apr-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.5

SUMMARY

The INTEROP sample demonstrates two general methods for calling routines in

a Win32 DLL from a Windows-based application: thunks and SendMessage().

There are two different thunking methods, one for each platform: Generic

Thunks on Windows NT and Universal Thunks on Win32s. The message used is

WM_COPYDATA, a new message introduced by Windows NT and Win32s. All three

methods provide a way to call functions and pass data across the 16-32

boundary, translating any pointers in the process. The advantages of

WM_COPYDATA over thunks are that it is fast the exact same code runs on

either platform (the thunk used will depend on the platform). The

disadvantage of WM_COPYDATA is that a method must be devised to get a

function return value (other than true or false) back to the calling

application.

NOTE: Universal Thunks were designed to work with a Win32-based application

calling a 16-bit DLL. The method described here has limitations. Because

the application is 16-bit, no 32-bit context is created, so certain calls

will not work from the Win32 DLL.

The sample consists of the following source files:

   APP16.C    -  Win16 Application

   DLL16.C    -  16-bit side of Universal Thunk/Generic Thunk

   STUB32.C   -  32-bit stub that loads the 32-bit DLLs on Win32s

   UTDLL32.C  -  32-bit side of the Universal Thunk

   DISP32.C   -  Dispatch calls sent through WM_COPYDATA

   DLL32.C    -  Win32 DLL

This sample is included with the Microsoft Win32 SDK. It is located in

SCT\SAMPLES\INTEROP. NOTE: There is also an RPC sample named INTEROP, but

it is in a different directory.

MORE INFORMATION

Generic Thunk

-------------

Under Windows NT, it is possible to call routines in a Win32 DLL from a

Windows-based application using an interface called Generic Thunks. The SDK

file DOC\SDK\MISC\GENTHUNK.TXT describes the interface.

Here is a picture of the way the pieces fit together in INTEROP:

                             dll32

                           ---------

                          |  Win32  |

    32-bit                |   DLL   |

                           ---------

                              /|\

             ------------------|-------

                               |

                ---------     ------------

               | Win 3.1 |<->| 16-bit DLL |

    16-bit     |   app.  |   |   (GT)     |

                ---------     ------------

                  app16           dll16

DLL16 is loaded when APP16 is loaded. If it detects that WOW is present,

then it loads DLL32.

WOW presents a few new 16-bit application programming interfaces (APIs)

that allow you to load the Win32 DLL, get the address of the DLL routine,

call the routine (passing it up to thirty-two 32-bit arguments), convert

16:16 (WOW) addresses to 0:32 addresses (useful if you need to build up a

32-bit structure that contains pointers and pass a pointer to it), and free

the Win32 DLL. These functions are:

   DWORD FAR PASCAL LoadLibraryEx32W( LPCSTR, DWORD, DWORD );

   DWORD FAR PASCAL GetProcAddress32W( DWORD, LPCSTR );

   DWORD FAR PASCAL CallProc32W( DWORD, ..., LPVOID, DWORD, DWORD );

   DWORD FAR PASCAL GetVDMPointer32W( LPVOID, UINT );

   BOOL FAR PASCAL FreeLibrary32W( DWORD );

When linking the Win16 application, you need to put the following

statements in the .DEF file, indicating that the functions will be imported

from the WOW kernel:

   IMPORTS

      kernel.LoadLibraryEx32W

      kernel.FreeLibrary32W

      kernel.GetProcAddress32W

      kernel.GetVDMPointer32W

      kernel.CallProc32W

Note that although these functions are called in 16-bit code, they need to

be provided with 32-bit handles, and they return 32-bit handles.

In addition, be sure that your Win32 DLL entry points are declared with the

_stdcall convention; otherwise, you will get an access violation.

Universal Thunk

---------------

Under Win32s, it is possible to call routines in a Win32 DLL from a Win16

application using an interface called Universal Thunks. The interface is

described in the Win32s Programmer's Reference. The sample UTSAMPLE, shows

the opposite (and more typical) case, a Win32 application calling 16-bit

routines.

Here is a picture of the way the pieces fit together in INTEROP:

                         stub           utdll32         dll32

                      -----------     -----------     ---------

                     |   Win32   |-->| Win32 DLL |<->|  Win32  |

    32-bit           |    EXE    |   |    (UT)   |   |   DLL   |

                      -----------     -----------     ---------

                              /|\      /|\

             ------------------|--------|-------------------------

                               |       \|/

                ---------     ------------

               | Win 3.1 |<->| 16-bit DLL |

    16-bit     |   app.  |   |   (UT)     |

                ---------     ------------

                  app16           dll16

The load order is as follows: The Windows 3.1 application loads the 16-bit

DLL. The 16-bit DLL checks to see whether the 32-bit side has been

initialized. If it has not been initialized, then the DLL spawns the 32-bit

.EXE (stub), which then loads the 32-bit DLL that sets up the Universal

Thunks with the 16-bit DLL. Once all of the components are loaded and

initialized, when the Windows 3.x application calls an entry point in the

16-bit DLL, the 16-bit DLL uses the 32-bit Universal Thunk callback to pass

the data over to the 32-bit side. Once the call has been received on the 32-

bit side, the proper Win32 DLL entry point can be called.

WM_COPYDATA

-----------

The wParam and lParam for this message are as follows:

   wParam = (WPARAM) (HWND) hwndFrom;   /* handle of sending window */

   lParam = (LPARAM) (PCOPYDATASTRUCT) pcds;

Where hwndFrom is the handle of the sending window and COPYDATASTRUCT is

defined as follows:

   typedef struct tagCOPYDATASTRUCT {

       DWORD dwData;

       DWORD cbData;

       PVOID lpData;

   } COPYDATASTRUCT;

The INTEROP sample uses dwData as a function code, indicating which Win32

DLL entry point should be calling and lpData to contain a pointer to the

data structure to be passed to the function.

Here is a picture of the way the pieces fit together in INTEROP:

                         disp           dll32

                      -----------     ---------

                     |   Win32   |-->|  Win32  |

    32-bit           |    EXE    |   |   DLL   |

                      -----------     ---------

                              /|\

             ------------------|----------------------------------

                               |

                ---------     ------------

               | Win 3.1 |<->| 16-bit DLL |

    16-bit     |   app.  |   |  (THUNK)   |

                ---------     ------------

                  app16           dll16

DLL16 is loaded when APP16 is loaded. DISP is spawned to handle WM_COPYDATA

messages, regardless of platform. DISP dispatches the calls to DLL32,

marshalling the arguments.

Additional reference words: 3.50

KBCategory: kbref

KBSubcategory: SubSys


Secure Erasure Under Windows NT

PSS ID Number: Q94239

Authored 30-Dec-1992	Last modified 03-Mar-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1, 3.5, and 3.51

SUMMARY

File systems under Windows NT currently have virtual secure erasure (when a

file is deleted, the data is no longer accessible through the operating

system). Although the bits could still be on disk, Windows NT will not

allow access to them.

MORE INFORMATION

The NTFS file system does this by keeping a high-water mark, for each file,

of bytes written to the file. Everything below the line is real data,

anything above the line is (on disk) random garbage that used to be free

space, but any attempt to read past this high-water mark returns all zeros.

Other reusable objects are also protected. For example, all the memory

pages in a process's address space are zeroed when they are touched (unlike

the file system, a process may directly access its pages, and thus the

pages must be actually zeroed rather than virtually zeroed).

Note that file system security assumes physical security; in other words,

if a person has physical access to a machine and can boot an alternative

operating system and/or add custom device drivers and programs, he/she can

always get direct access to the bits on disk.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseSecurity


Security and Screen Savers

PSS ID Number: Q96780

Authored 25-Mar-1993	Last modified 06-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.1, 3.5,

   and 3.51

SUMMARY

Screen savers are user-mode applications that execute in a different

desktop (see the note at the end of the article). Therefore, a screen saver

cannot enumerate windows of user-mode applications. This design prevents

unauthorized users from viewing the contents of applications displayed on

the screen. For secure screen savers (those that ask for a password), this

adds a further layer of protection.

Screen savers also execute in the security context of the logged-on user. A

screen saver may call ExitWindowsEx(), to log off from or shut down the

system, or any other application programming interface (API) that the

logged-on user has permission to perform.

MORE INFORMATION

A sample screen saver SCRNSAVE is distributed on the Win32 SDK CD.

NOTE: A desktop is a virtual screen. Windows NT 3.5 and earlier have three

desktops--the main desktop, the WinLogon desktop, and a desktop for screen

savers. Windows NT 3.51 and later support and document creating multiple

desktops.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseSecurity


Security Attributes on Named Pipes

PSS ID Number: Q102798

Authored 10-Aug-1993	Last modified 21-Feb-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

SUMMARY

The March beta release of the Windows NT (and earlier) did not require

security attributes on pipes. It was valid at that time to enter NULL for

the last parameter of the Win32-based application programming interface

(API) CreateNamedPipe(). This is no longer the case.

MORE INFORMATION

Windows NT 3.1 and later require security attributes for pipes. Please note

that setting the security attributes parameter to NULL does not indicate

that you want a NULL security descriptor (SD), rather it indicates that you

want to inherit the security descriptor of the current access token. This

generally means that any client wanting to connect to your pipe server must

have the same security attributes as the user that started the server. For

example, if the user who started the server was the administrator of the

machine, then any client who wants to connect must also be an administrator

to that machine.

Below is an code sample that demonstrates creating a named pipe with a NULL

security descriptor.

   HANDLE               hPipe;    // Pipe handle.

   SECURITY_ATTRIBUTES  sa;       // Security attributes.

   PSECURITY_DESCRIPTOR pSD;      // Pointer to SD.

   // Allocate memory for the security descriptor.

   pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR,

                                SECURITY_DESCRIPTOR_MIN_LENGTH);

   // Initialize the new security descriptor.

   InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION);

   // Add a NULL descriptor ACL to the security descriptor.

   SetSecurityDescriptorDacl(pSD, TRUE, (PACL) NULL, FALSE);

   sa.nLength = sizeof(sa);

   sa.lpSecurityDescriptor = pSD;

   sa.bInheritHandle = TRUE;

   // Create a local named pipe with a NULL security descriptor.

   hPipe = CreateNamedPipe(

         "\\\\.\\PIPE\\test",    // Pipe name = 'test'.

         PIPE_ACCESS_DUPLEX      // 2-way pipe.

         | FILE_FLAG_OVERLAPPED, // Use overlapped structure.

         PIPE_WAIT               // Wait on messages.

         | PIPE_READMODE_MESSAGE // Specify message mode pipe.

         | PIPE_TYPE_MESSAGE,

         MAX_PIPE_INSTANCES,     // Maximum instance limit.

         OUT_BUF_SIZE,           // Buffer sizes.

         IN_BUF_SIZE,

         TIME_OUT,               // Specify time out.

         &sa);                   // Security attributes.

It is important to note that by specifying TRUE for the fDaclPresent

parameter and NULL for pAcl parameter of the SetSecurityDescriptorDacl()

API, a NULL access control list (ACL) is being explicitly specified.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseIpc


Security Context of Child Processes

PSS ID Number: Q111545

Authored 14-Feb-1994	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

When a process is created with the CreateProcess() API, it operates under

the same security context as the parent. The child process inherits the

parent's security context, which are defined by the parent's access token.

Even if a thread in the parent process impersonates a client and then

creates a new process, the new process still runs under the parent's

original security context and not the under the impersonation token.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseSecurity


Semicolons Cannot Separate Macros in .HPJ File

PSS ID Number: Q83020

Authored 02-Apr-1992	Last modified 24-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

The author of a Help system can combine individual macro commands into

a macro string, which the Microsoft Help Compiler processes as a unit.

When the macro string is part of an RTF text file, the individual

macros in the string are separated from each other with a semicolon

character (;). The Help system runs the individual macros of a macro

string sequentially.

The author can define a macro string that is run when the user loads a

Help file. This macro string is placed into the [CONFIG] section of

the Help project (.HPJ) file. However, in the .HPJ file, the

individual macros of the string are separated from each other with a

colon character (:) because the semicolon character indicates the

beginning of a comment.

MORE INFORMATION

In the following sample [CONFIG] section, a macro adds two buttons to

the Help window's button bar. The first button is labeled "Other",

which when chosen brings up the About Help dialog box. The second

button is labeled "Test". When chosen, it disables the "Other" button

and jumps to the topic represented by "context_string." To create the

"Test" button, two macros are concatenated to form the macro parameter

in the CreateButton call.

[CONFIG]

; This first button is added so that the demonstration macro is

; complete. This macro just creates a button. Choosing the button

; brings up the About Help dialog box.

CreateButton("other_button","&Other","About()")

; This macro also creates a button. Choosing the button disables

; "other_button", created above, and jumps to the topic represented by

; "topic_string."

;

; Note that the two macros in the CreateButton macro are separated by

; a colon, not a semicolon.

;

; NOTE: The following macro should appear on a single line.

CreateButton("test_button","&Test","DisableButton(`Other_Button'):

JumpId(`testhelp.hlp',`context_string')")

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbtool

KBSubcategory: TlsHlp


SendMessage() in a Multithreaded Environment

PSS ID Number: Q95000

Authored 28-Jan-1993	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

When thread X calls SendMessage() to send a message to a window created by

thread Y, it must wait until thread Y calls PeekMessage(), GetMessage(), or

WaitMessage() before the SendMessage() call can continue. This process

prevents synchronization problems.

MORE INFORMATION

Because of the multithreaded environment of Windows NT, SendMessage() does

not behave in the same manner as it does under Windows 3.1. Under Windows

3.1, SendMessage() simply calls the window procedure given to it. In

Windows 3.1, if you use the SendMessage() function to send a message to a

window of another task, the system will perform a task switch to the target

window (change to the stack of the target Windows-based application), let

the target window process the message [when it calls GetMessage() or

PeekMessage()], and then switch back to the original message.

Under Windows NT, however, only the thread that created a window may

process the window's messages. Therefore, if thread X sends a message [via

SendMessage()] to a window that was created by thread Y, thread X must wait

for thread Y to be in a receiving state, and handle the message for it.

Thread Y is only in a receiving state when it calls PeekMessage(),

GetMessage(), or WaitMessage(), because synchronization problems may occur

if a thread is interrupted while processing other messages. While in a

receiving state, thread Y may process messages sent to its windows via

SendMessage() (in this case, by thread X).

Note that PeekMessage() and GetMessage() look in thread Y's message queue

for messages. Because SendMessage() does not post any messages,

PeekMessage() and GetMessage() will not see any indication of the

SendMessage() call. The two functions merely serve as a point in time at

which SendMessage() (thread X) may "interrupt," and have thread Y process

its message next. Then PeekMessage() or GetMessage() continues normal

operation under thread Y.

Because of this behavior, if thread X sends a message to thread Y, and

thread Y is locked in a tight loop, thread X is now locked as well. This

may be prevented by using SendNotifyMessage(), which behaves as

SendMessage() does above, but returns immediately. This may be an advantage

if it is not important that the sent message be completed before thread Y

continues. Note, however, that because SendNotifyMessage() is asynchronous,

thread X should not pass pointers to any of its local variables when making

the call, because they may be gone by the time thread Y attempts to look at

them. This would result in a general protection violation (GP fault) when

thread Y accesses the pointer.

Additional reference words: 3.10 3.50 3.51 4.00 95 GP-fault

KBCategory: kbprg

KBSubcategory: UsrMisc


Services and Redirected Drives

PSS ID Number: Q115848

Authored 06-Jun-1994	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   versions 3.1 and 3.5

SUMMARY

When writing a service, do not use WNetAddConnection() to redirect drives

to remote shares, because the redirector does not allow the logged-on user

to see the server or enumerate the drive. Instead, use universal naming

convention (UNC) names whenever possible to redirect drives to remote

shares.

MORE INFORMATION

WNetAddConnection() creates a global symbolic link describing the drive.

Therefore, the user can change to the drive at the command prompt. However,

WNetOpenEnum(), WNetEnumResource, and the "net use" command fail to list

the drive connection that was created by the service. This happens because

the logged-on user does not have an active session to the remote

connection, so the redirector will not let the user see the remote server.

The File Manager calls GetDriveType() on each drive and puts up an icon

for each drive found. The File Manager creates an icon for redirected

drives created from a service because there is a global symbolic link to

that drive. However, the share name is not available. In addition, the

logged-on user cannot use File Manager to disconnect the drive because the

drive was created by the service, not the logged-on user.

If the service process is running in the Local System account, then only

that process or another process running in the Local System account can

call WNetCancelConnection() to disconnect the drive.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseService


SetActiveWindow() and SetForegroundWindow() Clarification

PSS ID Number: Q97925

Authored 25-Apr-1993	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.1, 3.5,

   3.51, and 4.0

By default, each thread has an independent input state (its own active

window, its own focus window, and so forth). SetActiveWindow() always

logically sets a thread's active window state. To force a window to the

foreground, however, use SetForegroundWindow(). SetForegroundWindow()

activates a window and forces the window into the foreground.

SetActiveWindow() always activates, but it brings the active window into

the foreground only if the thread is the foreground thread.

NOTE: If the target window was not created by the calling thread, the

active window status of the calling thread is set to NULL, and the active

window status of the thread that created the target window is set to the

target window.

Applications can call AttachThreadInput() to allow a set of threads to

share the same input state. By sharing input state, the threads share their

concept of the active window. By doing this, one thread can always activate

another thread's window. This function is also useful for sharing focus

state, mouse capture state, keyboard state, and window Z-order state among

windows created by different threads whose input state is shared.

Additional reference words: 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrWndw


SetBkColor() Does Not Support Dithered Colors

PSS ID Number: Q69885

Authored 06-Mar-1991	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

The syntax for the SetBkColor function is documented in the Microsoft

Windows Software Development Kit (SDK) as follows:

   DWORD SetBkColor(HDC hDC, COLORREF crColor);

SetBkColor sets the current background color of the specified device

context (DC) to the color that the crColor parameter references, or to

the nearest physical color if the device cannot represent the RGB

color value that the crColor parameter specifies. In other words,

SetBkColor cannot be used to set the background to a dithered color

and defaults to the physical color that is closest to the requested

crColor value.

MORE INFORMATION

This behavior can cause unexpected results for an application that

changes the background color of a control to a color that cannot be

represented by a color provided by the display device.

Specifically, when an application specifies a dithered color for the

background of an edit control, and specifies the same color for the

text background, Windows paints the control in two distinct colors.

For example, using the standard VGA display driver, the following

call, in which COLOR_INACTIVEBORDER is a green/gray specified by

RGB(64, 128, 128), sets the background color to gray (RGB(128, 128,

128)) rather than the dithered green/gray that is desired:

   SetBkColor(wParam, GetSysColor(COLOR_INACTIVEBORDER));

To illustrate, if the application uses the function call while

processing the WM_CTLCOLOR message to change the color of an edit

control, the window background is painted green/gray, and the text

background defaults to the nearest physical color, which is gray. This

produces a gray rectangle inside a green/gray rectangle rather than

the desired green/gray for the entire edit control.

This behavior can also occur with other controls such as option

buttons and list boxes. However, an application can avoid this problem

by using the SetBkMode function to set the background mode to

TRANSPARENT. This allows the dithered brush pattern to show through

beneath the text to achieve the desired results. That solution is not

practical with a multiline edit control because if text is inserted,

and the background mode has been set to TRANSPARENT, the text that is

pushed to the right by the inserted text leaves its image behind. The

result is text superimposed on top of other text, which quickly

becomes unreadable.

To partially work around this situation for a multiline edit control,

use the GetNearestColor function to determine the nearest physical

color to the desired color, as in the code fragment below. In this

case, the entire edit control is gray:

   case WM_CREATE:

      {

      HDC hDC;

      hDC = GetDC(hWnd);

      hGrayBrush = CreateSolidBrush(GetNearestColor(hDC,

            RGB(64, 128, 128)));

      ReleaseDC(hWnd, hDC);

      hWndEdit = CreateWindow( ... ES_MULTILINE ... );

      }

      break;

   case WM_CTLCOLOR:

      if (HIWORD(lParam) == CTLCOLOR_EDIT)

         {

         // The following call creates the nearest physical

         // color; therefore, it will be the same as the

         // hGrayBrush created above.

         SetBkColor(wParam, RGB(64, 128, 128));

         SetTextColor(wParam, RGB(255, 0, 0)); // red text

         return (DWORD)hGrayBrush;

         }

      else

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

      break;

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: GdiDrw


SetClipboardData() and CF_PRIVATEFIRST

PSS ID Number: Q24252

Authored 16-Dec-1987	Last modified 12-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.1, 3.5, 3.51, and 4.0

SUMMARY

The documentation for SetClipboardData() states that CF_PRIVATEFIRST can be

used to put private data formats on the clipboard. It also states that data

of this format is not automatically deleted. However, that is apparently

not true. That is, the data is removed automatically when the clipboard is

emptied (sending a WM_DESTROYCLIPBOARD message) and the new item is set

into the clipboard. The old item is shown; however, the handle now is

invalid because GlobalFree() is called on it.

MORE INFORMATION

GlobalFree() was not called on this handle. If you try to use the other

handle to this memory, you will find that the one you initially received

from GlobalAlloc() is still valid. Only the clipboard handle has been

invalidated by the call to EmptyClipboard().

The documentation states that "Data handles associated (with

CF_PRIVATEFIRST) will not be freed automatically." This statement refers to

the memory associated with that data handle. When SetClipboardData() is

called under standard data types, it frees the block of memory identified

by hMem. This is not the case for CF_PRIVATEFIRST. Applications that post

CF_PRIVATEFIRST items on the clipboard are responsible for the memory block

containing those items.

This is not intended to imply that items placed on the clipboard will

remain on the clipboard if they are CF_PRIVATEFIRST. When a call is made to

EmptyClipboard(), all objects will be removed.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrClp


SetErrorMode() Is Inherited

PSS ID Number: Q105304

Authored 17-Oct-1993	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

An application can use SetErrorMode() to control whether the operating

system handles serious errors or whether the application itself will handle

the errors.

NOTE: The error mode will be inherited by any child process. However, the

child process may not be prepared to handle the error return codes. As a

result, the application may die during a critical error without the usual

error message popups occurring.

This behavior is by design.

One solution is to call SetErrorMode() before and after the call to

CreateProcess() in order to control the error mode that is passed to the

child. Be aware that this process must be synchronized in a multithreaded

application.

There is another solution available in Windows NT 3.5 and later.

CreateProcess() has a new flag CREATE_DEFAULT_ERROR_MODE that can be used

to control the error mode of the child process.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: BseExcept


SetParent and Control Notifications

PSS ID Number: Q104069

Authored 05-Sep-1993	Last modified 12-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

An edit, list box, or combo box control sends notifications to the

original parent window even after SetParent has been used to change

the control's parent. A button control sends notifications to the new

parent after SetParent has been used to change its parent.

Edit, list box, and combo box controls keep a private copy of the

window handle of the parent at the time of creation. This handle is

not changed when SetParent is used to change the control's parent.

Consequently, the notifications (EN_*, LBN_*, and CBN_* notifications)

go to the original parent.

Note that WM_PARENTNOTIFY messages go to the new parent and

GetParent() returns the new parent. If it is required that

notifications go to the new parent window, code must be added to the

old parent's window procedure to pass on the notifications to the new

parent.

For example:

case WM_COMMAND:

  hwndCtl = LOWORD(lParam);

  // If notification is from a control and the control is no longer this

  //   window's child, pass it on to the new parent.

  if (hwndCtl && !IsChild(hWnd, hwndCtl))

      SendMessage(GetParent(hwndCtl), WM_COMMAND, wParam,  lParam);

  else Do normal processing;

Button controls send notifications to the new parent after SetParent

has been used to change the parent.

Additional reference words: 3.10 3.50 3.51 4.00 95 listbox combobox

KBCategory: kbprg

KBSubcategory: UsrCtl


SetTimer() Should Not Be Used in Console Applications

PSS ID Number: Q102482

Authored 03-Aug-1993	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

SetTimer() was not designed to be used with a console application because

it requires a message loop to dispatch the timer signal to the timer

procedure. In a console application, this behavior can be easily emulated

with a thread that is set to wait on an event.

MORE INFORMATION

In Windows NT 3.1, SetTimer() can work within a console application, but it

requires a thread in a loop calling GetMessage() and DispatchMessage().

For example,

   while (1)

   {

      GetMessage();

      DispatchMessage();

   }

Because this requires a thread looping, there is no real advantage to

adding a timer to a console application over using a thread waiting on an

event.

Another option is to use a multimedia timer, which does not require a

message loop and has a higher resolution. In Windows NT 3.5, the resolution

can be set to 1 msec using timeBeginPeriod(). See the help for

timeSetEvent() and the Multimedia overview. Any application using

Multimedia calls must include MMSYSTEM.H, and must link with WINMM.LIB.

Additional reference words: 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrMisc


Setting Dynamic Breakpoints in WinDbg

PSS ID Number: Q100642

Authored 24-Jun-1993	Last modified 26-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

The WinDbg breakpoint command contains a metacircular interpreter; that is,

you can execute commands dynamically once a breakpoint is hit. This allows

you to perform complex operations, including breaking when an automatic

variable has changed, as described below.

The command interpreter of WinDbg allows any valid C expression to serve as

a break condition. For example, to break whenever a static variable has

changed, use the following expression in the Expression field of the

breakpoint dialog box:

   &<variablename>

In addition, the length should be specified as 4 (the size of a DWORD) in

the length field.

This technique does not work for automatic variables because the address of

an automatic variable may change depending on the value that the stack

pointer has upon entering the function that defines the automatic variable.

This is one case where the breakpoint needs to be redefined dynamically.

For this purpose, a breakpoint can be enabled at function start and

disabled at function exit, so that the address of the variable is

recomputed.

MORE INFORMATION

Suppose that the name of the function is "subroutine" and the local

variable name is "i". The following steps will be used:

1. Start the program and step into the function that defines the

   automatic variable with the commands:

      g subroutine

      p

      bp500 ={subroutine}&i /r4 /C"?i"

   The breakpoint number is chosen to be large so that the breakpoint

   will be well out of range of other breakpoints. Note that /r4

   indicates a length of 4 because i is an integer. Make this number

   larger for other data types. The command "?i" prints out the value

   of i.

2. Next, disable this first breakpoint with the command

      bd500

   because the address of i may change. The breakpoint will be enabled

   when in the scope of function subroutine.

3. The second breakpoint definition is set at the entry point of the

   function:

      bp .<FirstLine> /C"be 500;g"

   This is where the breakpoint is enabled. Note that <FirstLine> is

   the line number of the first statement in the function subroutine.

4. The last breakpoint is set at the end of the function

      bp .<LastLine> /C"bd 500;g"

   and will disable the breakpoint again. Note that <LastLine> is the

   line number of the last statement in the function subroutine.

   Note that if the function has more than one exit point, multiple

   breakpoints may have to be defined.

Program execution stops when breakpoint #500 is hit (for example, the value

of i changes), but execution will continue after the other two breakpoints

because they contain go ("g") commands.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbtool

KBSubcategory: TlsWindbg


Setting File Permissions

PSS ID Number: Q98952

Authored 18-May-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

In Windows NT, local access controls can be set on just NTFS partitions,

not FAT or HPFS partitions or floppies. Read/execute-only permissions

should work properly on a CD-ROM.

The exception is that ACLs (access control lists) can be set on shares,

regardless of the file system, to control access to all the files within

that share. For example, you can give read access to everyone, but give

full access just to members of a certain group or to certain individuals.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseSecurity


Setting the Console Configuration

PSS ID Number: Q105674

Authored 22-Oct-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

To create a command prompt with custom features such as

   Settings

   Fonts

   Screen Size and Position

   Screen Colors

create a new entry in the Program Manager for CMD.EXE (suppose that the

description is CUSTOM), choose these items from the CMD system menu, and

select Save Configuration in each dialog box. The settings are saved in the

registry under

   HKEY_CURRENT_USER\

             Console\

             custom

and are used when starting the CUSTOM command prompt from the Program

Manager or when specifying:

   start "custom"

This behavior is really a convenient side effect of

   start <string>

which sets the title in the window title bar. When you create a new console

window with the START command, the system looks in the registry and tries

to match the title with one of the configurations stored there. If it

cannot find it, it defaults to the values stored in:

   HKEY_CURRENT_USER\

             Console\

       Configuration

This functionality can be duplicated in your own applications using the

registry application programming interface (API).

For more information, please see the "Registry and Initialization Files"

overview and the REGISTRY sample.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseMisc


Setup Toolkit .INF File Format and Disk Labels

PSS ID Number: Q88141

Authored 18-Aug-1992	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

 - Microsoft Win32 SDK, version 3.5

In the Microsoft Setup Toolkit for Windows, the Source Media Descriptions

section of the .INF file contains one line for each of the disks you use to

install your application. Each of these lines consists of four quoted

strings, separated by commas. The second quoted string is the disk label,

which you create using the disk-layout utilities. This disk label has

nothing to do with the MS-DOS disk label. The disk label in the .INF file

comes from the Disk Labels command on the Options menu in DSKLAYT.EXE and

is arbitrarily chosen by the developer during the disk-layout process.

The Setup Toolkit only uses this disk label to prompt the user for disks.

The Setup Toolkit uses the tag filename in the Source Media Descriptions

section to determine if the proper disk has been placed in the drive.

Additional reference words: 3.00 3.10 3.50 MSSetup tool kit

KBCategory: kbtool

KBSubcategory: TlsMss


SHARE.EXE Functionality Built into Windows NT

PSS ID Number: Q101191

Authored 07-Jul-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   versions 3.1 and 3.5

SUMMARY

The functionality of the MS-DOS SHARE.EXE utility is built into the Windows

NT kernel. Any application or application programming interface (API) that

relies on the SHARE.EXE functionality is automatically supported. This

functionality cannot be disabled.

MORE INFORMATION

If you run the MS-DOS version of SHARE.EXE, you will receive a message

stating that SHARE is already installed. The Windows NT MS-DOS emulation

hooks Interrupt 2Fh function 10H and always returns a status indicating

that SHARE is installed.

If you run an MS-DOS-based application and it complains that SHARE.EXE is

not installed, the application may be searching the AUTOEXEC.BAT file for a

"share" string rather than using the proper Interrupt 2Fh interface.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: SubSys


Sharing All Data in a DLL

PSS ID Number: Q109619

Authored 05-Jan-1994	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

Win32 dynamic-link libraries (DLLs) use instance data by default. This

means that each application that uses a DLL gets its own copy of the DLL's

data. However, it is possible to share the DLL data among all applications

that use the DLL.

If you only need to share some of the DLL data, we recommend creating a

new section and sharing it instead. For additional information, please see

the following article(s) in the Microsoft Knowledge Base:

   ARTICLE-ID: Q89817

   TITLE     : How to Specify Shared and Nonshared Data in a DLL

If you want to share *all* of the DLL static data, it is important to

do two things:

 - First, the DLL must use the DLL version of the C Run-time (for example

   CRTDLL.LIB or MSVCRT.LIB). Please see your product documentation for

   more information about using the C Run-time in a DLL.

 - Second, you will need to specify that both .data and .bss are shared.

   Often, this is done in the "SECTIONS" portion of the .DEF file. For

   example:

      SECTIONS

         .bss  READ WRITE SHARED

         .data READ WRITE SHARED

   If you are using Visual C++ 32-bit Edition, you will have to specify

   this using the -section switch on the linker. For example:

      link -section:.data,rws -section:.bss,rws

Only static data will be shared. Memory allocated dynamically with calls to

APIs/functions such as GlobalAlloc() or malloc() will still be specific to

the calling process.

The system will try to load the shared memory block at the same address in

each process. However, if the block cannot be loaded into the same memory

address, the system allocates a new block of memory for that process and

the memory is not shared. No run time warnings are given when this happens,

therefore, named shared memory is generally a safer option.

MORE INFORMATION

The C Run-time uses global variables. If the CRT is statically linked to

the DLL, these variables will be shared among all clients of the DLL and

will most likely cause an exception c0000005.

The reason you need to specify both .data and .bss as shared is because

they each hold different types of data. The .data section holds initialized

data and the .bss section holds the uninitialized data.

One reason for sharing all data in a DLL is to have consistent behavior in

the DLL between Win32 (running on Windows NT) and Win32s (running on

Windows 3.1). When running on Win32s, a 32-bit DLL shares its data among

all of the processes that use the DLL.

Note that it is not necessary to share all data to behave identically

between Win32 and Win32s. The DLL can use thread local storage (TLS) on

Win32s to store variables as instance data. For additional information,

please see the following article(s) in the Microsoft Knowledge Base:

   ARTICLE-ID: Q109620

   TITLE     : Creating Instance Data in a Win32s DLL

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: BseDll


Sharing Memory Between 32-Bit and 16-Bit Code on Win32s

PSS ID Number: Q105762

Authored 24-Oct-1993	Last modified 23-Feb-1995

The information in this article applies to:

 - Microsoft Win32s versions 1.0, 1.1, and 1.2

SUMMARY

This article discusses many of the issues involved in sharing memory across

the process boundary under Win32s.

MORE INFORMATION

Memory allocated by a Win32-based application using GlobalAlloc() can be

shared with a 16-bit Windows-based application on Win32s. If the memory is

allocated with GMEM_MOVEABLE, then GlobalAlloc() returns a handle and not a

pointer. The 16-bit Windows-based application can use the low word of this

handle. The high word is all zeros. Make sure to lock the handle using

GlobalLock() in the 16-bit Windows-based application to get a pointer.

NOTE: GlobalAlloc (GMEM_FIXED...) is not the same as

GlobalFix(GlobalAlloc(GMEM_MOVEABLE...)). GMEM_FIXED will allocate locked

pages, which is most often not what you want.

Memory allocated by a 16-bit Windows-based application via GlobalAlloc()

must be fixed via GlobalFix() and translated before it can be passed to a

Win32-based application. Whenever a Windows object is passed to a

Win32-based application by its 32-bit address, the memory must be fixed,

because the address is computed from the selector base only once. If

Windows moves the memory, the linear address used by the Win32-based

application will no longer be valid.

If you are using the Universal Thunk, you can also pass a buffer from a

Win32-based application to a 16-bit dynamic-link library (DLL) in the

UTRegister() call. The address is translated for you. Another alternative

is the translation list passed to the callable stubs. Addresses passed in

the translation list will be translated during the thunking process. For

more information on the Universal Thunk, please see the "Win32 Programmer's

Reference."

NOTE: The ability to share global memory handles under Win32s is a result

of the implementation of Windows 3.1, in which all applications run in the

same address space. This is not true of existing Win32 platforms and will

not be true of future Win32 platforms.

Allocating memory with GlobalAlloc() gets you tiled selectors. However, you

can only tile 255 selectors at a time and there is an overall limit of 8192

selectors in the system. If you allocate memory using new, malloc(),

HeapAlloc(), LocalAlloc() or VirtualAlloc, your allocated memory does not

automatically get you tiled selectors. However, because you don't

automatically get tiled selectors, whenever you pass memory to 16-bit code,

selectors must be synthesized for you. There's currently a limit of 256

selectors that Win32s maintains for select synthesis. Also note that each

block of memory that you pass is limited to 32K in size due to the way that

Win32s tiles selectors.

Additional reference words: 1.00 1.10 1.20

KBCategory: kbprg

KBSubcategory: W32s


Sharing Objects with a Service

PSS ID Number: Q106387

Authored 07-Nov-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

SUMMARY

To share objects (file mapping, synchronization, and so forth) created

by a service, you must place a null DACL (discretionary access-control

list) in the security descriptor field when the object is created.

This grants everyone access to the object.

MORE INFORMATION

This null DACL is not the same as a NULL, which is used to specify the

default security descriptor. For example, the following code can be used to

create a mutex with a null DACL:

   PSECURITY_DESCRIPTOR    pSD;

   SECURITY_ATTRIBUTES     sa;

   pSD = (PSECURITY_DESCRIPTOR) LocalAlloc( LPTR,

                  SECURITY_DESCRIPTOR_MIN_LENGTH);

   if (pSD == NULL)

   {

      Error(...);

   }

   if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION))

   {

      Error(...);

   }

   // Add a NULL DACL to the security descriptor..

   if (!SetSecurityDescriptorDacl(pSD, TRUE, (PACL) NULL, FALSE))

   {

      Error(...);

   }

   sa.nLength = sizeof(sa);

   sa.lpSecurityDescriptor = pSD;

   sa.bInheritHandle = TRUE;

   mutex = CreateMutex( &sa, FALSE, "SOMENAME" );

If you are creating one of these objects in an application and the object

will be shared with a service, you could also use a null DACL to grant

everyone access. As an alternative, you could add an access-control entry

(ACE) to the DACL that grants access to the user account that the service

is running under. This would restrict access to the object to the service.

For a more detailed example, please see the SERVICES sample.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseSecurity


Sharing Win32 Services

PSS ID Number: Q91698

Authored 02-Nov-1992	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

Win32 services are discussed in the overview for the Service Control

Manager. The documentation says that:

   A Win32 service runs in a Win32 process which it may or may not share

   with other Win32 services.

Whether or not a service has its own process is determined by which of

these service types is specified in the call to CreateService() to add the

service to the Service Control Manager Database.

SERVICE_WIN32_OWN_PROCESS

   This service type indicates that only one service can run in the

   process. This allows an application to spawn multiple copies of a

   service under different names, each of which gets its own process. This

   is the most common type of service.

SERVICE_WIN32_SHARE_PROCESS

   This service type indicates that more than one service can be run in a

   single process. When the second service is started, it is started as a

   thread in the existing process. A new process is not created. An example

   of this is the LAN Manage Workstation and the LAN Manager Server. Note

   that the service must be started in the system account, which is

   .\System. The name must be NULL.

The service type for each service is stored in the registry. The values are

as follows:

   SERVICE_WIN32_OWN_PROCESS    0x10

   SERVICE_WIN32_SHARE_PROCESS  0x20.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseService


Showing the Beginning of an Edit Control after EM_SETSEL

PSS ID Number: Q64758

Authored 09-Aug-1990	Last modified 12-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

In a single-line edit control created with the ES_AUTOHSCROLL style,

when the EM_SETSEL message is used to select the entire contents of

the control, the text in the control is scrolled to the left and the

caret is placed at the end of the text. This occurs when the control

contains more text than can be displayed at one time. The order of the

starting and ending positions specified in the lParam of the EM_SETSEL

message makes no difference.

If your application needs to have the entire contents selected and the

beginning of the string in view, create the edit control using the

ES_MULTILINE style. The order of the starting and ending positions in

the EM_SETSEL message is respected by multiline edit controls.

MORE INFORMATION

Consider the following example, which sets and then selects the text

in a single-line edit control created with the ES_AUTOHSCROLL style:

   //hEdit and szText defined elsewhere

   SetWindowText(hEdit, szText);

   SendMessage(hEdit, EM_SETSEL, 0, MAKELONG(0x7FFF, 0));

According to the documentation for the EM_SETSEL message, the

low-order word of lParam specifies the starting position of the

selection and the high-order word specifies the ending position.

However, a single-line edit control ignores this ordering and always

selects the text from the lower position to the higher position.

If the content of the edit control is longer than the control can

display, the text is scrolled to the end of the selection, and the

caret is positioned there. In some situations, it is necessary to show

the beginning of the text after the selection is made with EM_SETSEL.

In Windows 3.00, there is no documented method to accomplish this

positioning using a single-line edit control.

A multiline edit control, sized to display only one line and created

without the ES_AUTOVSCROLL style, will appear to the user as a

single-line control. However, this control will respect the order of

the start and end positions in the EM_SETSEL message.

In the sample code above, a multiline edit control will select the

text from the specified starting position to the specified ending

position, regardless of which position is higher. In this example, the

text is scrolled to the beginning and the caret is placed there. The

beginning of the selected text is visible in the control.

NOTE: A multiline edit control uses up slightly more memory in the

USER heap than a single-line edit control.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrCtl


Simulating CreatePatternBrush() on a High-Res Printer

PSS ID Number: Q74793

Authored 30-Jul-1991	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, version 4.0

SUMMARY

When a pattern brush is used to fill an area of the page on the printer,

the printer's high resolution will cause a fine pattern to lose definition

and appear as a shade of gray.

Brushes that are created with the CreatePatternBrush() function are 8

pixels by 8 pixels (8 x 8 pixels) in size. On a 300 dots-per-inch (dpi)

laser printer, the pattern will be 0.027 inches wide.

To create a pattern that gives similar effects on the screen as on the

printer, it is necessary to compare the screen resolution to the printer

resolution, and to compensate for the differences.

For example, if the video display is 100 dpi (typical of a VGA), and the

printer is 300 dpi (a typical laser printer), the bit must be three times

larger in each direction. The following compares a screen bitmap and a

printer bitmap:

   10101010          111000111000111000111000

   01010101          111000111000111000111000

   10101010          111000111000111000111000

   01010101          000111000111000111000111

   10101010          000111000111000111000111     and so forth

   01010101          000111000111000111000111

   10101010          111000111000111000111000

   01010101          111000111000111000111000

                     111000111000111000111000

    Video            000111000111000111000111

                     000111000111000111000111

                     000111000111000111000111

                     111000111000111000111000

                     111000111000111000111000

                     111000111000111000111000

                     000111000111000111000111

                     000111000111000111000111

                     000111000111000111000111

                     111000111000111000111000

                     111000111000111000111000

                     111000111000111000111000

                              Printer

However, since the pattern brush is always 8 x 8 pixels, a different

approach must be used when printing:

1. Use the StretchBlt() function to create, from the video bitmap, the

   24 x 24 pixel bitmap for the printer.

2. Manually "tile" this bitmap into the region to be painted.

Additional reference words: 3.00 3.10 4.00 95

KBCategory: kbprg

KBSubcategory: GdiPrn


Size Comparison of 32-Bit and 16-Bit x86 Applications

PSS ID Number: Q97765

Authored 20-Apr-1993	Last modified 26-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

It is expected that a 32-bit version of an x86 application (console or GUI)

will be larger than the 16-bit version. Much of this difference is due to

the flat memory-model addressing of Windows NT. For each instruction, note

that the opcodes have not changed in size, but the addresses have been

widened to 32 bits.

In addition, the EXE format under Windows NT (the PE format) is optimized

for paging; EXEs are demand-loaded and totally mappable. This leads to some

internal fragmentation because protection boundaries must fall on sector

boundaries within the EXE file.

The MIPS (or any RISC) version of a Win32-based application typically will

be larger and require more memory than its x86 counterpart.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbtool

KBSubcategory: TlsMisc


SizeofResource() Rounds to Alignment Size

PSS ID Number: Q57808

Authored 17-Jan-1990	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SizeofResource() returns the resource size rounded up to the alignment

size. Therefore, if you have your own resource types, you cannot use

SizeofResource() to get the actual resource byte count.

It has been suggested that this be changed to reflect the actual

number of bytes in the resource so that applications can use

SizeofResource() to determine the size of each resource. This

suggestion is under review and will be considered for inclusion in a

future release of the Windows Software Development Kit (SDK).

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrRsc


SNMP Agent Breaks Up Variable Bindings List

PSS ID Number: Q127870

Authored 21-Mar-1995	Last modified 26-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

When the SNMP agent receives a request for mutiple variables in a single

packet, then for each entry in the variable bindings list, the agent

queries the required sub-agent (in this case the .DLL acting as the agent)

and packs up the results in a response variable bindings list and returns

it in a single packet.

For example, say the varibles requested are:

   ip.ipInReceives            (Internet MIB II )

   tcp.tcpMaxConn            (Internet MIB II )

   .iso.org.dod.internet.private.enterprises.lanmanager.lanmgr-2.common.

   comVersionMaj            (LanManager MIB II)

   icmp.icmpOutErrors         (Internet MIB II )

In this case, the agent queries the INETMIB2.DLL file twice, the LMMIB2.DLL

once, and the INETMIB2.DLL once. Then it packs the results in a response

packet and sends it to the requesting manager. There is no "snapshot" of

the MIB.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: NtwkSnmp


Sockets Applications on Microsoft Windows Platforms

PSS ID Number: Q124876

Authored 15-Jan-1995	Last modified 20-Jun-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

 - Microsoft Win32 SDK, versions 3.1, 3.5, 3.51, and 4.0

 - Microsoft Win32s version 1.2

SUMMARY

This article documents the resources necessary to do Winsock development on

the different Microsoft Windows platforms. The key components necessary for

Winsock programming are:

 - TCP/IP networking support

 - A Windows Sockets include file

 - A Windows Wockets import library

 - The Windows Sockets Architecture specification.

NOTE: Some implementations of Windows Sockets may support additional

protocols, and TCP/IP will not be strictly necessary. See the documentation

from your vendor for more information.

MORE INFORMATION

Where you get the necessary components for Winsock programming depends on

what platform you are using.

Microsoft Windows NT Versions 3.1 and 3.5 and Windows 95

--------------------------------------------------------

Header filename:     WINSOCK.H

Import library name: WSOCK32.LIB

If you are using Microsoft Windows NT version 3.1 or 3.5, the TCP/IP

protocol is provided as a component of the operating system. Please see

your operating system documentation for more information about installing

TCP/IP support for Microsoft Windows NT.

The Winsock header file, import library, and specification are all supplied

as part of the Win32 SDK. If you do not have the Win32 SDK, it can be

purchased as part of the Microsoft Developer Network Level 2 subscription.

The header file and import library are also supplied with the 32-bit

editions of Visual C++. Visual C++ does not include the Windows Sockets

specification.

Microsoft Windows for Workgroups Version 3.11

---------------------------------------------

Header filename:     WINSOCK.H

Import library name: WINSOCK.LIB

Windows for Workgroups does not include support for the TCP/IP protocol.

However, Microsoft does provide a TCP/IP protocol for Windows for

Workgroups free of charge. To learn how to obtain the TCP/IP package for

Windows for Workgroups, please see the following article in the

Microsoft Knowledge Base:

   ARTICLE-ID: Q111682

   TITLE     : WFWG 3.11: How to Obtain Microsoft DLC and Microsoft TCP/IP

The Winsock include file, import library, and specification are available

from the Microsoft Software library. Download WSA16.EXE, a self-extracting

file, from the Microsoft Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for WSA16.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download WSA16.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the /softlib/mslfiles directory

      get WSA16.EXE

The header file and library for Winsock programming are not included with

Visual C++ for Windows.

Microsoft Windows Versions 3.0, 3.1, and 3.11

---------------------------------------------

Header filename:     Probably WINSOCK.H (determined by vendor)

Import library name: Probably WINSOCK.LIB (determined by vendor)

TCP/IP support on these versions of Microsoft Windows will have to come

from the underlying network. Your network vendor can tell you what TCP/IP

support is available.

Depending on your network and the TCP/IP implementation, you may also need

to get the Winsock header and library files from your vendor. However,

while not guaranteed, the files supplied in WSA16.EXE (see above) may work

on your implementation.

Microsoft Win32s Version 1.2

----------------------------

Header filename:     WINSOCK.H

Import library name: WSOCK32.LIB

A Winsock application running on Win32s will use the networking support of

the underlying system. See the appropriate section above for information

about TCP/IP support on the host platform.

The header file, import library, and specification will be part of the

Win32 SDK from which the Win32s application was created. See the section on

Windows NT above for more information.

Additional reference words: 3.10 3.50 4.00 1.20 tcpip

KBCategory: kbprg kbfile kbnetwork

KBSubcategory: NtwkWinsock W32s


Some Basic Concepts of a Message-Passing Architecture

PSS ID Number: Q74476

Authored 21-Jul-1991	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

The following is excerpted from an article in the April 1991 issue of

Software Design (Japan).

MORE INFORMATION

Asynchronous message-passing means that Windows will send an application

messages to act on and that these messages may come in any order. At

present, all messages are sent to specific windows. Every window has a

function that Windows calls to send that window a message. This function

processes the message and returns to Windows. When the function returns to

Windows, Windows may then send messages to other windows in the same

program, other programs, or to the same window again.

Because most of these messages are generated by user actions (picking an

item in a menu, moving a window, and so forth), the specific messages a

window receives will differ each time the program is run. This is what

makes the messages asynchronous.

This message passing is what makes Windows programming difficult for many

programmers. The programmer is no longer writing a program in which he or

she controls the flow from beginning to end. Rather, a Windows program is

written as a large number of objects, each one designed to handle a

specific message from Windows.

Understanding message passing is critical and because it leads to so much

confusion, the concept will be explained in greater detail in this article.

If message passing is understood, the remainder of Windows can be learned

fairly easily. However, it is very unlikely that a Windows program or other

graphical user interface (GUI) program can be successfully developed

without a thorough understanding of message passing.

In a message-passing system, the focus changes from being proactive (the

programmer controls the program flow) to being reactive (Windows controls

the program flow). [Or as it has been put by some Macintosh programmers,

"Don't call us, we'll call you."] For example, consider the situation where

a user chooses an action from a menu in a program. In a proactive program,

the program reads the keyboard, determines that the key(s) pressed are

meant to run the action, and calls the function that performs that action.

In a reactive system, the program is sent a message indicating that the

user chose that item from a menu. When the program receives the message, it

calls the function that performs the action. When this function is done,

control returns to the system. Although the reactive approach is

substantially different from the proactive approach, it is also simpler.

In Windows, every window (including dialog boxes) has a "response function"

registered to it. When Windows sends a message to a window, it calls the

response function for that window and passes it the message. All messages

from Windows are passed to window response functions; there is no other way

for Windows to send a message to a program. Therefore, all messages are for

a specific window or group of windows.

However, there are four considerations involved with this method:

1. Messages are sent in two distinct ways. The first method consists

   of messages that are posted to a first-in, first-out queue

   (PostMessage). The second method consists of messages that are sent

   (SendMessage). Posted messages, aside from PAINT messages, are

   serialized, meaning that messages cannot be posted anywhere except

   to the end of the queue, and the application is sent messages only

   from the beginning of the queue. Posted PAINT messages are an

   exception. They are added together and sent only when there is

   nothing else in the queue. This is done to reduce the number of

   times a window has to paint itself.

   Messages that are sent are passed to the application immediately,

   and the send function does not return until the message is

   processed. However, when a message is posted, an indeterminate

   number of messages and amount of time will pass before the message

   is actually sent to a window and acted on. Also, when a message is

   sent, an message posted earlier may not yet have been acted on.

2. Sending messages or calling functions (which may, as part of their

   actions, also send messages), can lead to additional messages being

   generated. The most dangerous situation is where the action for a

   message generates the same message again. If, while processing a

   message, an application sends the same message to itself, the

   application will run out of stack space quite quickly. If an

   application POSTS the same message to itself, the application will

   not run out of stack but it will generate an unending stream of

   messages.

3. If, while processing a message, an application calls a function

   that sends a message, the application will process the second

   message in the middle of processing the first message. Therefore,

   each window response function MUST be fully re-entrant. It is even

   possible for a function to be re-entered to process the same

   message as the message currently being processed. For this reason,

   using global or static variables in a response function is very

   dangerous.

   Also, if the application uses properties, scratch files and/or

   other data storage mechanisms, extreme caution is required.

   Consider the situation where one message reads in data from a file,

   then a second message reads in the same data, makes changes to that

   data, and writes it back to the file. If the first message makes

   additional changes to the data and writes its new data back to the

   file, the changes caused by the second message are completely lost.

   With files, each application must implement its own sharing

   mechanism. For properties, allocated memory and other memory

   storage, there is a simple solution: lock the item and use the

   pointer returned. Because only one lock is allowed, this prevents

   contention. Never copy the data into a scratch buffer to copy back

   later.

4. Because messages come in due to user interaction, the application

   cannot be written to assume that when a particular message is

   received that another message has already been processed and

   performed its functions. While, for a given action, a specific

   sequence of messages may occur, in the interest of remaining

   completely compatible with potential changes in future versions of

   Windows, it is recommended that no message ordering dependencies be

   introduced unless absolutely necessary. The best example of this is

   that the first message a window gets when it is being created is

   not WM_CREATE, rather it is WM_GETMINMAXINFO. When one message must

   logically follow a second (such as WM_CREATE always preceding

   WM_DESTROY), then it is fine to depend on the specific ordering of

   those two messages.

The asynchronous, reactive nature of Windows programming can cause

confusion. Because the program has no control over the order that

messages arrive, the response to ANY specific message CANNOT depend on

other messages having been processed or NOT been processed.

To confuse matters even further, an application may be in the middle

of processing one message when it calls a Windows function that sends

the application another message. When processing this second message,

some dependent processing may be only half finished. If an application

will check and only do some processing if another message has not

already performed it, the application must be prepared for the case

where another message has begun the processing, but has not completed

it.

Further, when an application sets up a modal dialog box, the

DialogBox() function will not return until after the dialog box is

dismissed and processing completed. Therefore, after calling the

dialog box function, all combinations of user-generated messages may

be received before the function returns.

NOTE: 16-bit Windows is non-preemptively multitasks its Windows tasks.

Therefore, an application generally does not need to be designed to process

a user-originated message in the middle of processing another message.

However, when an application calls a Windows function, the application may

then get a set of specific messages sent to it by Windows before the called

function returns.

32-bit Windows 95 and Windows NT are preemptive multitasking systems. Each

thread has its own input queue. It is a good idea to create a separate

thread of execution for the user interface so that it is responsive to user

input.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: UsrMsg


Some CTRL Accelerator Keys Conflict with Edit Controls

PSS ID Number: Q67293

Authored 29-Nov-1990	Last modified 13-Jun-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

Some keys produce the same ASCII values as CTRL+key combinations.

These keys conflict with edit controls if one of the CTRL+key

combinations is used as a keyboard accelerator.

The following table lists some of the conflicting keys.

   ASCII Value  Key Combination  Equivalent  Windows Virtual Key

   -----------  ---------------  ----------  -------------------

   0x08         CTRL+H           BACKSPACE   VK_BACK

   0x09         CTRL+I           TAB         VK_TAB

   0x0D         CTRL+M           RETURN      VK_RETURN

For example, consider the following scenario:

1. CTRL+H has been assigned as an accelerator keystroke to invoke Help

2. An edit control has the focus

3. BACKSPACE is pressed to erase the previous character in the edit

   control

This results in Help being invoked because pressing BACKSPACE is

equivalent to pressing CTRL+H. The edit control does not receive the

BACKSPACE key press that it requires because TranslateAccelerator()

encounters the 0x08 ASCII value and invokes the action assigned to

that accelerator. This limitation is caused by the use of the ASCII

key code for accelerators instead of the system-dependent virtual key

code.

MORE INFORMATION

When messages for the edit control are processed in a message loop

that translates accelerators, this translation conflict will occur.

Child windows and modeless dialog boxes are the most common situations

where this happens.

The affected keystrokes are translated during the processing of the

WM_KEYDOWN message for the letter. For example, when the user types

CTRL+H, a WM_KEYDOWN is processed for the CTRL key, then another

WM_KEYDOWN is processed for the letter "H". In response to this

message, TranslateAccelerator() posts a WM_COMMAND message to the

owner of the CTRL+H accelerator. Similarly, when the user presses the

BACKSPACE key, a WM_KEYDOWN is generated with VK_BACK as the key code.

Because the ASCII value of BACKSPACE is the same as that for CTRL+H,

TranslateAccelerator() treats them as the same character. Either

sequence will cause a WM_COMMAND message to be sent to the owner of

the CTRL+H accelerator, which deprives the child window with the input

focus of the BACKSPACE key message.

Because this conflict is inherent to ASCII, the safest way to avoid

the difficulty is to avoid using the conflicting sequences as

accelerators. Any other ways around the problem may be version

dependent rather than a permanent fix.

A second way around the situation is to subclass each edit control

that is affected. In the subclass procedure, watch for the desired key

sequence(s). The following code sample demonstrates this procedure:

/* This code subclasses a child window edit control to allow it to

 * process the RETURN and BACKSPACE keys without interfering with the

 * parent window's reception of WM_COMMAND messages for its CTRL+H

 * and CTRL+M accelerator keys.

 */

/* forward declaration */

long FAR PASCAL NewEditProc(HWND, unsigned, WORD, LONG);

/* required global variables */

FARPROC lpfnOldEditProc;

HWND    hWndOwner;

/* edit control creation in MainWndProc */

TEXTMETRIC tm;

HDC hDC;

HWND hWndEdit;

FARPROC lpProcEdit;

...

 case WM_CREATE:

    hDC = GetDC(hWnd);

    GetTextMetrics(hDC, &tm);

    ReleaseDC(hWnd, hDC);

    hWndEdit = CreateWindow("Edit", NULL,

        WS_CHILD | WS_VISIBLE | ES_LEFT | WS_BORDER,

        50, 50, 50 * tm.tmAveCharWidth, 1.5 * tm.tmHeight,

        hWnd, 1, hInst, NULL);

    lpfnOldEditProc = (FARPROC) GetWindowLong (hWndEdit, GWL_WNDPROC);

    lpProcEdit = MakeProcInstance ((FARPROC) NewEditProc, hInst);

    SetWindowLong(hWndEdit, GWL_WNDPROC, (LONG) lpProcEdit);

    break;

...

/* subclass procedure */

long FAR PASCAL NewEditProc(HWND hWndEditCtrl, unsigned iMessage,

                            WORD wParam, LONG lParam )

{

  MSG  msg;

  switch (iMessage)

    {

  case WM_KEYDOWN:

    switch (wParam)

        {

    case VK_BACK:

        // This assumes that the next message in the queue will be a

        // WM_COMMAND for the window which owns the accelerators. If

        // this edit control were in a modeless dialog box, hWndOwner

        // should be set to NULL. It may also be NULL in this case.

        PeekMessage(&msg, hWndOwner, 0, 0, PM_REMOVE);

        // Since TranslateAccelerator() processed this message as an

        // accelerator, a WM_CHAR message must be supplied manually to

        // the edit control.

        SendMessage(hWndEditCtrl, WM_CHAR, wParam, MAKELONG(1, 14));

        return 0L;

    case VK_RETURN:

        // Same procedures here.

        PeekMessage(&msg, hWndOwner, 0, 0, PM_REMOVE);

        SendMessage(hWndEditCtrl, WM_CHAR, wParam, MAKELONG(1, 28));

        return 0L;

        }

        break;

    }

    return CallWindowProc(lpfnOldEditProc, hWndEditCtrl, iMessage,

                          wParam, lParam);

}

NOTE: Be sure to export the subclass function in the DEF file.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg kbcode

KBSubcategory: UsrCtl


Some Subsystems Persevere Through Logons

PSS ID Number: Q94995

Authored 28-Jan-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

Subsystems such as the Local Security Authority (LSA), the spooler, the

Win32 server, and the OS/2 subsystem do not terminate when the user logs

off, and then restart at next logon.

Windows on Win32 (WOW) is not a true subsystem; rather, it is a user-mode

program. When you run an MS-DOS program, the console you run it from has a

virtual DOS machine (VDM) attached to it until the console exits (which it

is forced to do at logoff). When you run the first Win16 program, the WOW

VDM is started and continues to run until the user logs off.

Additional reference words: 3.10 and 3.50

KBCategory: kbprg

KBSubcategory: Subsys


Source-level Debugging Under NTSD

PSS ID Number: Q99053

Authored 20-May-1993	Last modified 05-Jan-1995

The information in this article applies to:

   - Microsoft Win32 Software Development Kit (SDK) for Windows NT

     versions 3.1 and 3.5

The following are the steps used for source-level debugging under NTSD:

1. Compile using -Zi and -Od.

2. Link using debug:full and debugtype:coff.

3. Load the program into the debugger.

4. Use s+ to change to source mode.

   -or-

   Use s& to change to mixed mode.

For a console application, type "g main" to get to the program start. For a

GUI application, type "g WinMain" to get to the program start.

Type "v .<number>" to list source lines starting at <number>. For example,

type the following

   v .20

to see all lines starting at line 20.

Additional reference words: 3.10 3.50

KBCategory: kbtool

KBSubcategory: TlsMisc


Specifying Filenames Under the POSIX Subsystem

PSS ID Number: Q99361

Authored 26-May-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   versions 3.1 and 3.5

When specifying filenames under POSIX, use the format

   //C/subdir/executable.exe

to specify C:\SUBDIR\EXECUTABLE.EXE. If you fail to use this format, you

will receive ENAMETOOLONG as the errno.

NOTE: The filenames are case-sensitive.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: Subsys


Specifying Serial Ports Larger than COM9

PSS ID Number: Q115831

Authored 05-Jun-1994	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

CreateFile() can be used to get a handle to a serial port. The "Win32

Programmer's Reference" entry for "CreateFile()" mentions that the share

mode must be 0, the create parameter must be OPEN_EXISTING, and the

template must be NULL.

CreateFile() is successful when you use "COM1" through "COM9" for the name

of the file; however, the message "INVALID_HANDLE_VALUE" is returned if you

use "COM10" or greater.

If the name of the port is \\.\COM10, the correct way to specify the serial

port in a call to CreateFile() is as follows:

   CreateFile(

      "\\\\.\\COM10",     // address of name of the communications device

      fdwAccess,          // access (read-write) mode

      0,                  // share mode

      NULL,               // address of security descriptor

      OPEN_EXISTING,      // how to create

      0,                  // file attributes

      NULL                // handle of file with attributes to copy

   );

NOTES: This syntax also works for ports COM1 through COM9. Certain boards

will let you choose the port names yourself. This syntax works for those

names as well.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: BseCommapi


Specifying Time to Display and Remove a Dialog Box

PSS ID Number: Q74888

Authored 01-Aug-1991	Last modified 18-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

It is possible to modify the timing of the display of a dialog box.

For example, an application has its copyright message in a dialog box

that does not have any push buttons. This dialog box is designed to be

displayed for five seconds and then to disappear. This article

discusses a method to implement this functionality.

MORE INFORMATION

Windows draws the dialog box on the screen during the processing of a

WM_PAINT message. Because all other messages (except for WM_TIMER

messages) are processed before WM_PAINT messages, there may be some

delay before the dialog box is painted. This delay may be avoided by

placing the following code in the processing of the WM_INITDIALOG message:

   ShowWindow(hDlg);

   UpdateWindow(hDlg);

This code causes Windows to send a WM_PAINT message to the dialog box,

bypassing the other messages that may be in the application's queue.

To keep the dialog box on the screen for a particular period of time,

a timer should be created during the processing of the WM_INITDIALOG

message. When the WM_TIMER message is received, call EndDialog() to

close the dialog box.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrDlgs


Specifying Windows "Bounding Box" Coordinates

PSS ID Number: Q27585

Authored 07-Mar-1988	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

GDI functions, such as Rectangle, Ellipse, RoundRect, Chord, and Pie, have

parameters that specify the coordinates of a "bounding box" into which the

figure is drawn. Windows draws the figure up to, but not including, the

right and bottom coordinates.

MORE INFORMATION

Suppose the following call is made:

   Rectangle(hDC, 1, 1, 5, 3)

Assuming that the device context is using the MM_TEXT mapping mode (in

which case logical units map directly to physical pixels), the

resulting rectangle will be 4 pixels wide and 2 pixels tall. The

following diagram shows which pixels are affected:

            ---0-----1-----2-----3-----4-----5-----6-

            |     |     |     |     |     |     |

            0     |     |     |     |     |     |

            |-----|-----|-----|-----|-----|-----|----

            |     |     |     |     |     |     |

            1     |  X  |  X  |  X  |  X  |     |

            |-----|-----|-----|-----|-----|-----|----

            |     |     |     |     |     |     |

            2     |  X  |  X  |  X  |  X  |     |

            |-----|-----|-----|-----|-----|-----|----

            |     |     |     |     |     |     |

            3     |     |     |     |     |     |

            |-----|-----|-----|-----|-----|-----|----

            |     |     |     |     |     |     |

            4     |     |     |     |     |     |

It may be helpful to think of the display as a grid, with each pixel

contained in a grid cell. The X1, Y1, X2, and Y2 parameters to the

Rectangle function specify an imaginary "bounding box" drawn on the

grid. The rectangle is drawn within the bounding box.

The height, width, and area of the resulting rectangle have the

following useful properties:

   Height = X2 - X1

   Width  = Y2 - Y1

   Area   = Height * Width

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: GdiDrw


Starting and Terminating Windows-Based Applications

PSS ID Number: Q105676

Authored 22-Oct-1993	Last modified 04-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

A 16-bit Windows-based application running under Windows NT version 3.1 is

running as a thread in a single virtual MS-DOS machine (VDM). These threads

are nonpreemptively scheduled. A 16-bit Windows-based application shares an

address space and an input queue with other 16-bit Windows-based

applications. Objects created by a thread (application) are owned by the

thread (application). This environment is called WOW (Windows on Win32).

Windows NT version 3.5 introduces support for multiple WOWs, so each 16-bit

Windows-based application can be run in its own address space. For

additional information, please see the following article in the Microsoft

Knowledge Base:

   ARTICLE-ID: Q115235

   TITLE     : Running a Windows-Based Application in its Own VDM

When a 16-bit Windows-based application is started by using

CreateProcess(), the process handle and the thread handle contained in the

PROCESS_INFORMATION structure are pseudo-handles. The only application

programming interfaces (APIs) that can use the process handle are

WaitForSingleObject(), WaitForMultipleObjects(), and WaitForInputIdle().

NOTE: When you call CreateProcess() with CREATE_SEPARATE_WOW_VDM, the

handles returned in the hProcess and hThread fields of the

PROCESS_INFORMATION structure are valid handles. The hProcess handle is the

handle to the new WOW process, but the hThread handle is the handle to the

WOWEXEC thread, and not the thread of the application that you spawned. You

can wait on either of these handles and you will be released when the

Windows-based application terminates, because the separate VDM goes away

when the last application in it terminates. Be aware that if your Windows-

based application spawns another Windows-based application and terminates,

the VDM stays around, because the application is run in the same VDM as the

application that spawned it.

A common question is "How can I terminate a 16-bit process from a 32-bit

process?" However, as implied above, PROCESS_INFORMATION.hProcess cannot be

used in TerminateProcess() and PROCESS_INFORMATION.dwThreadId cannot be

used in PostThreadMessage().

One way to terminate an individual 16-bit Windows-based application is to

enumerate the desktop windows using EnumWindows(), determine which is the

correct window, obtain the thread ID with GetWindowThreadProcessId(), and

post a WM_QUIT message via PostThreadMessage() to terminate the

application.

Another way to terminate an individual 16-bit Windows-based application is

to use the TOOLHELP APIs. Use TaskFirst() and TaskNext() to enumerate the

tasks, determine which is the correct task, and call TerminateApp() to kill

the application. The Windows SDK sample THSAMPLE demonstrates how this can

be done.

Additional reference words: 3.10 3.50 win16

KBCategory: kbprg

KBSubcategory: SubSys


StartPage/EndPage Resets Printer DC Attributes in Windows 95

PSS ID Number: Q125696

Authored 01-Feb-1995	Last modified 06-Apr-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

When you print under Windows version 3.x, the printer device context

attributes, including things like mapping modes, current pen, current

brush, and so on, are reset to their defaults for the device when the end

of a page is reached. The escapes NEWFRAME and NEXTBAND and the API EndPage

all cause the printer device context to be reset.

When you print under Windows NT version 3.x, the printer device context

attributes are not reset during a print job.

When you print under Windows 95, the point at which the printer device

context is reset to the default attributes depends on what version the

executable was marked as. For executables marked as 3.x, the printer

device context will be reset when EndPage is called. For executables

marked as 4.0, the printer device context will be reset when StartPage

is called. This applies to both 16-bit-based and Win32-based executables

running under Windows 95.

A 16-bit-based executable's version can be set by using the Resource

compiler's /xx switch where xx is 30, 31, or 40. A Win32-based executable's

version can be set by using the /SUBSYSTEM:windows,x.x linker switch.

Additional reference words: 4.00

KBCategory: kbprg

KBSubcategory: GdiPrn


Stroke Fonts Marked as OEM Character Set Are ANSI

PSS ID Number: Q72020

Authored 10-May-1991	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

There are three stroke (or vector) fonts packaged with Windows versions 3.0

and 3.1 and Windows NT: Roman, Script, and Modern. These fonts are marked

as belonging to the OEM character set when, in fact, they belong to the

ANSI character set. NOTE: Windows 95 provides only the Modern vector font.

The Roman and Script fonts are included in the True Type fonts shipped with

the system.

The OEM character set is the character set used by the hardware device on

which Windows is running (for example, the IBM PC). The IBM PC OEM

character set and ANSI character set are listed in "Microsoft Windows

Software Development Kit Reference Volume 2" for the Windows SDK version

3.0 and in "Programmer's Reference, Volume 3: Messages, Structures, and

Macros" for the Windows SDK version 3.1.

The fonts were marked in this manner for two reasons. First, in previous

versions of Windows, the stroke fonts did include non-ANSI characters.

Second, mismarking the character set ensures proper font mapping. The

character-set attribute of a font is assigned a very high penalty weight in

the font mapping scheme. If stroke fonts were not marked as using the OEM

character set, a stroke font might be chosen by the font mapper [during a

SelectObject() call] instead of a raster font when a requested raster font

size is not available. This behavior occurs because most raster fonts

belong to the ANSI character set, character size has much lower penalty

weight than character set, and stroke fonts can be scaled to any desired

size. Some raster fonts can be scaled; however, they can be scaled only to

specific sizes.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: GdiFnt


Support for Sleep() on Win32s

PSS ID Number: Q100713

Authored 27-Jun-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32s versions 1.0, 1.1, and 1.2

The Win32 application programming interface (API) documentation indicates

that Sleep() is supported on Win32s. It is important to note, however, that

the behavior of Sleep() on Win32s is not the same as it is under Windows

NT.

Under Win32s, Sleep() calls Yield(). The Windows version 3.1 Yield()

function yields only if the message queue is empty; therefore, Sleep()

cannot be relied on to do anything. Use a PeekMessage() loop to do idle

time processing.

Additional reference words: 1.00 1.10 1.20

KBCategory: kbprg

KBSubcategory: W32s


Switching Between Single and Multiple List Boxes

PSS ID Number: Q57959

Authored 23-Jan-1990	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

After creating a list box with the CreateWindow() API, changing the

list box from a single selection to a multiple selection can be

accomplished in the following way:

Create two hidden list boxes in the .RC file, and during the

WM_INITDIALOG routine, display one of the boxes. Change between the

two by making one hidden and the other one visible using the

ShowWindow function.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: UsrCtl


Symbolic Information for System DLLs

PSS ID Number: Q103862

Authored 01-Sep-1993	Last modified 06-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   and 3.51

SUMMARY

The debugging information for the system dynamic-link libraries (DLLs)

is contained separately in files with a .DBG extension. The Win32 SDK

setup, SETUPSDK, will install the following .DBG files by default in

<SYSTEMROOT>\SYMBOLS\DLL:

   ADVAPI32.DBG           OLECLI32.DBG

   COMDLG32.DBG           OLESVR32.DBG

   CRTDLL.DBG             RASAPI32.DBG

   DLCAPI.DBG             RPCNS4.DBG

   GDI32.DBG              RPCRT4.DBG

   INETMIB1.DBG           SHELL32.DBG

   KERNEL32.DBG           USER32.DBG

   LMMIB2.DBG             VDMDBG.DBG

   LZ32.DBG               VERSION.DBG

   MGMTAPI.DBG            WIN32SPL.DBG

   MPR.DBG                WINMM.DBG

   NDDEAPI.DBG            WINSTRM.DBG

   NETAPI32.DBG           WSOCK32.DBG

   NTDLL.DBG

For Windows NT version 3.5, the additional .DBG files are:

   GLU32.DBG

   MSACM32.DBG

   OLEAUT32.DBG

   OPENGL32.DBG

For Windows NT versions 3.51, the additional .DBG files are:

   COMCTL32.DBG

   DHCPMIB.DBG

   OLE32.DBG

   OLEDLG.DBG

   RICHED32.DBG

   WINSMIB.DBG

Note that these files are not installed by the alternative Win32 SDK

install method, MANUAL.BAT. Therefore, WinDbg will warn that symbol

information cannot be found for each of the system DLLs called by the

debuggee.

These .DBG files can be manually installed by copying them from the

SDK CD. For x86, they are located in \SUPPORT\DEBUG\I386\SYMBOLS\DLL.

For MIPS, they are located in \SUPPORT\DEBUG\MIPS\SYMBOLS\DLL. Note

that there are more than 200 .DBG files in each of these directories.

MORE INFORMATION

In Windows NT 3.1, there are also debugging versions of the system DLLs

that can be installed by using SWITCH.BAT, which is located on the CD in

\SUPPORT\DEBUGDLL. Refer to page 11 of the "Getting Started" manual

and the batch file itself for more information.

Additional reference words: 3.10 3.50

KBCategory: kbsetup

KBSubcategory: Setins


System GENERIC_MAPPING Structures

PSS ID Number: Q102105

Authored 28-Jul-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1

There is not a Win32 application programming interface (API) to retrieve

the GENERIC_MAPPING structures for Windows NT objects. The MapGenericMask()

Win32 API is intended to use GENERIC_MAPPING structures associated with

private objects created by the application.

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: BseSecurity


System Versus User Locale Identifiers

PSS ID Number: Q100488

Authored 22-Jun-1993	Last modified 24-Mar-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   versions 3.1 and 3.5

In Windows NT version 3.1, the following pairs of application programming

interfaces (APIs) have the same functionality:

   GetSystemDefaultLCID()   and GetUserDefaultLCID()

   GetSystemDefaultLangID() and GetUserDefaultLangID()

The user LangID and LCID are always set to the system value. In future

versions of Windows NT, it will be possible to set the LangID and the LCID

on a per-user basis.

Note that it is possible to set the LCID on a per-thread basis [that is,

SetThreadLocale()] in Windows NT 3.1.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: UsrLoc WintlDev


Taking Ownership of Registry Keys

PSS ID Number: Q111546

Authored 14-Feb-1994	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

SUMMARY

To take ownership of a registry key it is necessary to have a handle to the

key. A handle to the key can be obtained by opening the key with a registry

API (application programming interface) such as RegOpenKeyEx(). If the user

does not have access to the registry key, the open operation will fail and

this will in turn prevent ownership being taken (because a handle to the

key is required to change the key's security).

The solution to this problem is to first enable the TakeOwnership privilege

and then to open the registry key with WRITE_OWNER access as shown below:

   RegOpenKeyEx(HKEY_CLASSES_ROOT,"Testkey",0,WRITE_OWNER,&hKey);

This function call will provide a handle to the registry, which can be used

in the following call to take ownership:

   RegSetKeySecurity(hKey,OWNER_SECURITY_INFORMATION, &SecurityDescriptor);

Please note that you will need to initialize the security descriptor being

passed to RegSetKeySecurity() and set the owner field to the new owner SID.

Taking ownership of a registry key is not a common operation. It is

typically an operation that an administrator would use as a last resort to

gain access to a registry key.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseSecurity


Text Alignment in Single Line Edit Controls

PSS ID Number: Q108940

Authored 20-Dec-1993	Last modified 12-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0

   and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

Text in single line edit controls cannot be centered or right-aligned

(right-justified). Text in single line edit controls is left-aligned (left-

justified) by default. This is by product design, and therefore specifying

the ES_RIGHT or ES_CENTER style while creating the single line edit control

does not have any effect on the text alignment.

Windows does not allow text to be centered or right-aligned in a single

line edit control. However, an easy way to work around this problem is to

create a multiline edit control that is the same size as a single line edit

control.

Text in a multiline edit control can be centered or right/left aligned.

Note that the multiline edit control should be created without the

WS_VSCROLL or ES_AUTOVSCROLL style.

While single line edit controls may support text alignment in a future

release of Windows, Windows 3.x applications must use multiline edit

controls to achieve the same effect.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrCtl


The Clipboard and the WM_RENDERFORMAT Message

PSS ID Number: Q31668

Authored 15-Jun-1988	Last modified 12-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.1, 3.5, 3.51, and 4.0

The clipboard sends a WM_RENDERFORMAT message to an application to request

that application format the data last copied to the clipboard in the

specified format, and then pass a handle to the formatted data to the

clipboard.

If an application cannot supply the requested data, it should return a NULL

handle. Because most applications provide access to the actual data (not

rendered) through the CF_TEXT format, applications that use the clipboard

can get the applicable data when rendering fails.

If the application cannot render the data because the system is out of

memory, the application can call GlobalCompact(-1) to discard and compress

memory, then try the memory allocation request again.

If this fails to provide enough memory, the application can render the data

into a file. However, applications that use this technique must cooperate

in order to know that the information is in a file, the name of the file,

and the format of the data.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrClp


The Parts of a Windows Combo Box and How They Relate

PSS ID Number: Q65881

Authored 26-Sep-1990	Last modified 18-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.1, 3.5, 3.51, and 4.0

SUMMARY

A Windows combo box is a compound structure composed of individual windows.

Three types of windows can be created as part of a combo box:

 - A combo box itself, of window class "ComboBox"

 - An edit control, of window class "Edit"

 - A list box, of window class "ComboLBox"

The relationship among these three windows varies depending upon the

different combo box styles.

MORE INFORMATION

For combo boxes created with the CBS_SIMPLE styles, the ComboBox window is

the parent of the edit control and the list box that is always displayed on

the screen. When GetWindowRect() is called for a combo box of this style,

the rectangle returned contains the edit control and the list box.

Combo boxes created with the CBS_DROPDOWNLIST style have no edit control.

The region of the combo box that displays the current selection is in the

ComboBox window itself. When GetWindowRect() is called for a combo box of

this style, the rectangle returned does not include the list box.

For combo boxes created with the CBS_DROPDOWN style, three windows are

created. The combo box edit control is a child of the ComboBox window. When

GetWindowRect() is called for a combo box of this style, the rectangle

returned does not include the list box.

However, the ComboLBox (list box) window for combo boxes that have the

CBS_DROPDOWN or CBS_DROPDOWNLIST style is not a child of the ComboBox

window. Instead, each ComboLBox window is a child of the desktop window.

This is required so that, when the drop-down list box is dropped, it can

extend outside the application window or dialog box. Otherwise, the list

box would be clipped at the window or dialog box border.

Because the ComboLBox window is not a child of the ComboBox window, there

is no simple method to get the handle of one window, given the other. For

example, given a handle to the ComboBox, the handle to any associated drop-

down list box is not readily available. The ComboLBox is a private class

registered by USER that is a list box with the class style CS_SAVEBITS.

Additional reference words: control focus release 3.00 3.10 3.50 3.51 4.00

95

KBCategory: kbprg

KBSubcategory: UsrCtl


The SBS_SIZEBOX Style

PSS ID Number: Q102485

Authored 03-Aug-1993	Last modified 09-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

A size box is a small rectangle the user can expand to change the size of

the window. When you want a size box, you create a SCROLLBAR window with

the SBS_SIZEBOX flag. This action creates a size box with the height,

width, and position that you specified in the call to CreateWindow. If you

specify SBS_SIZEBOXBOTTOMRIGHTALIGN, the box will be aligned in the lower

right of the rectangle you specified when creating the window. If you

specify SBS_SIZEBOXTOPLEFTALIGN, the box will be aligned in the upper left

of the rectangle you specified in your call to CreateWindow().

MORE INFORMATION

The user moves the mouse pointer over to the box, presses and holds the

left mouse button, and drags the mouse pointer to resize the window. When

the user does this, the borders on the window (the frame) move. When the

user releases the mouse button, the window is resized.

You create a size box by creating a child window of type WS_CHILD |

WS_VISIBLE | SBS_SIZEBOX | SBS_SIZEBOXTOPLEFTALIGN. You don't have to do

any of the processing for this; the system will take care of it. You will

notice in your window procedure that you will get the scroll bar messages

plus the WM_MINMAXINFO message. Size boxes work similar to the way the

WS_THICKFRAME/WS_SIZEBOX style does on a window.

Under Windows NT, applications that create a size box either using

WS_SIZEBOX or WS_THICKFRAME or by created the SBS_SIZEBOX control have no

way of showing the user that such a feature exists. Under Windows 95, the

size box appears as a jagged edge, usually at the bottom right corner.

NOTE: Make sure that the main window is created with the WS_VSCROLL and

WS_HSCROLL styles.

Additional reference words: 3.10 3.50 4.00 sizebox

KBCategory: kbprg

KBSubcategory: UsrCtl


The Use of PAGE_WRITECOPY

PSS ID Number: Q105532

Authored 20-Oct-1993	Last modified 21-Feb-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

The documentation to CreateFileMapping(), VirtualAlloc(), and

VirtualProtect() indicates that the PAGE_WRITECOPY protection gives

copy-on-write access to the committed region of pages. As it is,

PAGE_WRITECOPY makes sense only in the context of file mapping, where

you want to map something from the disk into your view and then modify

the view without causing the data to go on the disk.

The only case where VirtualAlloc() should succeed with PAGE_WRITECOPY

is the case where CreateFileMapping() is called with -1 and allocates

memory with the SEC_RESERVE flag and later on, VirtualAlloc() is used

to change this into MEM_COMMIT with a PAGE_WRITECOPY protection.

There is a bug in Windows NT 3.1 such that the following call to

VirtualAlloc() will succeed:

   lpCommit = VirtualAlloc(lpvAddr, cbSize, MEM_COMMIT, PAGE_WRITECOPY);

This call will fail under Windows NT 3.5.

NOTE: lpvAddr is a pointer to memory that was allocated with

MEM_RESERVE and PAGE_NOACCESS.

One case where this might be useful is when emulating the UNIX fork

command. Emulating fork behavior would involve creating instance data

and using threads or multiple processes.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseMm


The Use of the SetLastErrorEx() API

PSS ID Number: Q97926

Authored 25-Apr-1993	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SetLastErrorEx() is intended for better debugging support, not for passing

additional error information.

The SetLastErrorEx() application programming interface (API) differs from

the SetLastError() API only in that it raises a debug "RIP" event. The RIP

event is intended to give text to the debugger so that the user can retry,

ignore, and so forth, these errors. SetLastErrorEx() raises an exception

only if SetDebugErrorLevel() has been called by the debugger to allow the

errors to be passed on.

The error type can be determined from the debugger by examining the debug

event structure that is passed with the event. The debug event structure

contains a RIP_INFO substructure.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: BseMisc


Thread Handles and Thread IDs

PSS ID Number: Q127992

Authored 22-Mar-1995	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.5, 3.51,

   and 4.0

The CreateThread() API is used to create threads. The API returns both a

thread handle and a thread identifier (ID). The thread handle has full

access rights to the thread object created. The thread ID uniquely

identifies the thread on the system level while the thread is running. The

ID can be recycled after the thread has been terminated. This relationship

is similar to that of the process handle and the process ID (PID).

There is no way to get the thread handle from the thread ID. While there is

an OpenProcess() API that takes a PID and returns the handle to the

process, there is no corresponding OpenThread() that takes a thread ID and

returns a thread handle.

The reason that the Win32 API does not make thread handles available this

way is that it can cause damage to an application. The APIs that take a

thread handle allow suspending/resuming threads, adjusting priority of a

thread relative to its process, reading/writing registers, limiting a

thread to a set of processors, terminating a thread, and so forth.

Performing any one of these operations on a thread without the knowledge of

the owning process is dangerous, and may cause the process to fail.

If you will need a thread handle, then you need to request it from the

thread creator or the thread itself. Both the creator or the thread will

have a handle to the thread and can give it to you using DuplicateHandle().

This requirement allows both applications to coordinate their actions.

NOTE: You can also take full control of the application by calling

DebugActiveProcess(). Debuggers receive the thread handles for a process

when the threads are created. These handles have THREAD_GET_CONTEXT,

THREAD_SET_CONTEXT, and THREAD_SUSPEND_RESUME access to the thread.

Additional reference words: 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: BseProcThrd


Thread Local Storage Overview

PSS ID Number: Q94804

Authored 18-Jan-1993	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

Thread local storage (TLS) is a method by which each thread in a given

process is given a location(s) in which to store thread-specific data.

Four functions exist for TLS: TlsAlloc(), TlsGetValue(), TlsSetValue(), and

TlsFree(). These functions manipulate TLS indexes, which refer to storage

areas for each thread in a process. A given index is valid only within the

process that allocated it.

Note that the Visual C++ compiler supports an alternate syntax:

   _declspec( thread )

which can be used in place of directly calling these APIs. Please see the

description of _declspec in the VC++ "Language and Run-time Help" helpfile

for more information.

MORE INFORMATION

A call to TlsAlloc() returns a global TLS index. This one TLS index is

valid for every thread within the process that allocated it, and should

therefore be saved in a global or static variable.

Thread local storage works as follows: when TlsAlloc() is called, every

thread within the process has its own private DWORD-sized space reserved

for it (in its stack space, but this is implementation-specific). However,

only one TLS index is returned. This single TLS index may be used by each

and every thread in the process to refer to the unique space that

TlsAlloc() reserved for it.

For this reason, TlsAlloc() is often called only once. This is convenient

for DLLs, which can distinguish between DLL_PROCESS_ATTACH (where the first

process's thread is connecting to the DLL) and DLL_THREAD_ATTACH

(subsequent threads of that process are attaching). For example, the first

thread calls TlsAlloc() and stores the TLS index in a global or static

variable, and every other thread that attaches to the DLL refers to the

global variable to access their local storage space.

Although one TLS index is usually sufficient, a process may have up to

TLS_MINIMUM_AVAILABLE indexes (guaranteed to be greater than or equal

to 64).

Once a TLS index has been allocated (and stored), the threads within the

process may use it to set and retrieve values in their storage spaces. A

thread may store any DWORD-sized value in its local storage (for example, a

DWORD value, a pointer to some dynamically allocated memory, and so forth).

The TlsSetValue() and TlsGetValue() APIs are used for this purpose.

A process should free TLS indexes with TlsFree() when it has finished using

them. However, if any threads in the process have stored a pointer to

dynamically allocated memory within their local storage spaces, it is

important to free the memory or retrieve the pointer to it before freeing

the TLS index, or it will be lost.

For more information, please see "Using Thread Local Storage" in the

"Processes and Threads" overview in the "Win32 Programmer's Reference".

Example

-------

Thread A within a process calls TlsAlloc(), and stores the index returned

in the global variable TlsIndex:

   TlsIndex = TlsAlloc();

Thread A then allocates 100 bytes of dynamic memory, and stores it in its

local storage:

   TlsSetValue( TlsIndex, malloc(100) );

Thread A creates thread B, which stores a handle to a window in its local

storage space referred to by TlsIndex.

   TlsSetValue( TlsIndex, (LPVOID)hSomeWindow );

Note that TlsIndex refers to a different location when thread B uses it,

than when thread A uses it. Each thread has its own location referred to by

the same value in TlsIndex.

Thread B may terminate safely because it does not need to specifically free

the value in its local storage.

Before thread A terminates, however, it must first free the dynamically

allocated memory in its local storage

   free( TlsGetValue( TlsIndex ) );

and then free the TLS index:

   if ( !TlsFree( TlsIndex ) )

      // TlsFree() failed.  Handle error.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: BseProcThrd


Time Stamps Under the FAT File System

PSS ID Number: Q101186

Authored 07-Jul-1993	Last modified 15-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   versions 3.1 and 3.5

Windows NT considers the time stamp on a file stored on a FAT (file

allocation table) partition to be standard time if the current time is

standard time, and daylight time if the current time is daylight time,

regardless of what time of year the file was originally time stamped.

This is not an issue under NTFS, which consistently implements Universal

Coordinated Time.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseFileio


Timer Resolution in Windows NT

PSS ID Number: Q115232

Authored 22-May-1994	Last modified 01-Feb-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   versions 3.1 and 3.5

In Win32-based applications, the GetTickCount() timer resolution on Windows

NT, version 3.1, is 15 milliseconds (ms) for x86 and 10 ms for MIPS and

Alpha. On Windows NT, version 3.5, the GetTickCount() timer resolution is

10 ms on the 486 or greater, but the resolution is still 15 ms on a 386.

NOTE: The measurements in milliseconds indicate the period of the

interrupt, not the units of the returned value.

The Win32 API QueryPerformanceCounter() returns the resolution of a high-

resolution performance counter if the hardware supports one. For x86, the

resolution is about 0.8 microseconds (0.0008 ms). For MIPS, the resolution

is about twice the clock speed of the processor. You need to call

QueryPerformanceFrequency() to get the frequency of the high-resolution

performance counter.

NOTE: These numbers are likely to change in future versions.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseMisc


Tips for Installing TAPI Service Providers

PSS ID Number: Q131356

Authored 08-Jun-1995	Last modified 20-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) version 4.0

 - Microsoft Windows Telephony Software Development Kit (TAPI SDK)

   version 1.0

SUMMARY

When installing TAPI Service Providers (TSPs), there is more involved than

just copying the TSP files to the system directory. The TAPI system files

may need to be installed, and the TSP must be installed into TAPI. However,

this process can vary greatly from one Windows version to another.

MORE INFORMATION

First and foremost, be sure to do version checking when installing all

files.

Second, use a setup application rather than relying on an .INF file. While

the ATSP sample uses a .INF file to install, there are two major problems

with using a .INF file:

 - TAPI needs to already be installed (which isn't guarenteed under Windows

   version 3.1 or Windows for Workgroups).

 - You can't do operating system version checking if you use an .INF file.

Files Necessary for Windows Version 3.1 or Windows for Workgroups

-----------------------------------------------------------------

When a TSP is installed under Windows version 3.1 or Windows for

Workgroups, it must check and make sure all the necessary system files are

present. The files to be installed can be found in the TAPI 1.0 SDK \REDIST

directory and must be distributed with the TSP. Some of these are optional

and some are not. Here is a list of files and where they should be placed:

Mandidory TAPI files:

    TELEPHON.CPL [system]

    TAPI.DLL     [system]

    TAPIADDR.DLL [system]

    TAPIEXE.EXE  [system]

    TELEPHON.HLP [system]

Optional TAPI files:

    ATSPEXE.EXE  [system]

    ATSP.TSP     [system]

    ATSP.HLP     [system]

    DIALER.EXE   [windows]

    DIALER.HLP   [windows]

Files Necessary for Windows 95

------------------------------

Because the Windows 95 system files are not redistributable and because

TAPI is installed automatically under Windows 95, the TAPI system files

must not be distributed with the TSP. The TAPI version 1.0 files are not

compatible with Windows 95, so it is important that no TAPI system files

are installed under Windows 95.

One complication for Windows 95 is the TELEPHON.CPL file.  This file is

installed to the system directory by default along with all the rest of the

Windows 95 TAPI files. However, because this file is not needed by most

people using Windows 95, it is installed in the system directory as

TELEPHON.CP$ to reduce control panel clutter. TSPs that need this applet

should first look in the system directory for TELEPHON.CPL; if that isn't

found, the TSP should locate TELEPHON.CP$ (also looking in the system

directory), and rename it to TELEPHON.CPL.

Installing the TSP

------------------

Once all the files are installed, the TSP must now be installed into TAPI.

Under Windows version 3.1, this is done through the Telephony Control Panel

applet (TELEPHON.CPL). There are no APIs to automate the installation, so

TSP installation programs must either tell the user how to install their

TSP into TAPI or use an application such as MSTEST that can simulate

keystrokes to automate this part of the installation. Note that TSPs must

have version information (as demonstrated by the ATSP sample) to show in

the Add Driver dialog.

Adding TSPs through the Telephony Control Panel is also available under

Windows 95, but the exact sequence of keystrokes is slightly different.

However, several TAPI APIs (lineAddProvider, lineConfigProvider, and

lineRemoveProvider) have been added that make the TELEPHON.CPL unnecessary.

It's a good idea to have each TSP have its own control panel applet that

calls these APIs, rather than rely on TELEPHON.CPL. The setup program

should install the TSP directly by using these APIs instead of asking the

user to run a control panel applet.

Additional reference words: 1.00 1.30 1.40 4.00 95

KBCategory: kbprg

KBSubcategory: TAPI


Tips for Writing Multiple-Language Scripts

PSS ID Number: Q89865

Authored 01-Oct-1992	Last modified 24-Mar-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

SUMMARY

To aid you in writing multiple-language resources, the Win32 development

system supports language scripts.

MORE INFORMATION

To create a multiple language script, first create a single-language script

file (American English, for example), and duplicate the translations in

your script file. You need a complete translation only once for each major

language. Only those resources that have differences between the major

language and the sublanguage need be included in the sublanguage areas of

the script. The system will use the main language resource if it doesn't

find a resource for the sublanguage.

Sample Code

-----------

LANGUAGE LANG_ENGLISH,SUBLANG_ENGLISH_US

<original script file>

LANGUAGE LANG_ENGLISH,SUBLANG_ENGLISH_UK

<portions of script file that are different for UK>

LANGUAGE LANG_ENGLISH,SUBLANG_ENGLISH_AUS

<portions of script file that are different for Australia>

LANGUAGE LANG_ENGLISH,SUBLANG_ENGLISH_CAN

<portions of script file that are different for Canada>

LANGUAGE LANG_FRENCH,SUBLANG_FRENCH

<entire script file translated to French>

LANGUAGE LANG_FRENCH,SUBLANG_FRENCH_CAN

<portions of script file that are different for Canada>

LANGUAGE LANG_FRENCH,SUBLANG_FRENCH_SWISS

<portions of script file that are different for Switzerland>

LANGUAGE LANG_FRENCH,SUBLANG_FRENCH_BELGIAN

<portions of script file that are different for Belgium>

LANGUAGE LANG_SPANISH,SUBLANG_SPANISH

<entire script file translated to Spanish>

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: WIntlDev


Tips for Writing Windows Sockets Apps That Use AF_NETBIOS

PSS ID Number: Q129316

Authored 24-Apr-1995	Last modified 04-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.5

SUMMARY

The six issues listed in this article must be addressed when writing

Windows Sockets applications that use the AF_NETBIOS protocol family.

NOTE: Windows 95 does not support AF_NETBIOS.

MORE INFORMATION

Issues to Address When Writing Windows Sockets Applications

-----------------------------------------------------------

1. When creating an AF_NETBIOS socket, specify -1 times lana for the

   protocol option.

   The Windows NT WinSock library allows the programmer to create a

   socket that allows communication over a particular lana. The lana

   number is specified via the protocol option of the socket() function.

   To create an AF_NETBIOS socket, specify -1 times the lana for the

   protocol option of the socket() function. For example:

      SOCKET hSock0 = socket( AF_NETBIOS, SOCK_DGRAM, 0 );  // lana 0;

      SOCKET hSock1 = socket( AF_NETBIOS, SOCK_DGRAM, -1 ); // lana 1;

   The lana numbers are basically indices to the list of transports

   supported by the NetBIOS implementation. A given host has one unique

   lana number for every installed transport that supports NetBIOS. For

   example, listed below are some possible lana numbers for a typical

   Windows NT configuration:

      Lana     Transport

      ----------------------------------------------------------

      0        TCP/IP // lana 0 is the default NetBIOS transport

      1        IPX/SPX w/NetBIOS

      3        NetBEUI

   In the case of a multihomed host (a machine with multiple network

   adapters), the number of unique lana numbers equals the number of

   network transports that support NetBIOS times the number of network

   adapters. For example, if the machine depicted above contained

   two network adapters, it would have a total of 3 * 2 = 6 lana numbers.

   Also, please note the WSNETBS.H header included with the Windows NT

   version 3.5 SDK erroneously defines the NBPROTO_NETBEUI symbol. This

   symbol cannot be used as a protocol option and should be ignored.

2. Use the snb_type values provided by the WSNETBS.H header for NetBIOS

   name registration and deregistration.

   When filling out a sockaddr_nb structure, you must specify the

   appropriate value for the snb_type field. This field is used during

   the bind() operation to handle NetBIOS name registration. The WSNETBS.H

   header defines several values for this field; however only the

   following two values are currently implemented:

    - NETBIOS_UNIQUE_NAME

      Registers a unique NetBIOS name. This action is usually performed

      by a client or a server to register an endpoint.

    - NETBIOS_GROUP_NAME

      Registers a group name. This action is typically performed in

      preparation for sending or receiving NetBIOS multicasts.

   Names are registered during the bind() operation.

3. Use the supported socket types of SOCK_DGRAM and SOCK_SEQPACKET.

   Due to the nature of NetBIOS connection services, SOCK_STREAM

   is not supported.

4. Choose a NetBIOS port that does not conflict with your network

   client software.

   The NetBIOS port is an eight-bit value stored in the last position of

   the snb_name that is used by various network services to differentiate

   various type of NetBIOS names. When you register NetBIOS names, choose

   port values that do not cause conflicts with existing network services.

   This is of particular importance if you are registering a NetBIOS name

   that duplicates a user name or a machine name on the network. The

   following lists the reserved port values:

      0x00, 0x03, 0x06, 0x1f, 0x20, 0x21, 0xbe, 0xbf, 0x1b,

      0x1c, 0x1d, 0x1e

5. Applications should use all available lana numbers when initiating

   communication.

   Because the NetBIOS interface can take advantage of multiple transport

   protocols, it is important to use all lanas when initiating

   communication. Server applications should accept connections on

   sockets for each lana number, and client applications should attempt

   to connect on every available lana. In a similar fashion, data gram

   broadcasts should be sent from sockets created from each lana.

   The following diagram depicts the lana mappings for two machines.

   In order for a client application running on Machine A to communicate

   with a server application on Host B, the client application must create

   a socket on lana 3, and the server must create a socket on lana 1.

   Because the client and the server cannot know in advance which single

   lana to use, they must create sockets for all lanas.

      Host A (Client)            Host B (Server)

      ---------------            ---------------

      lana  Transport            lana  Transport

      ----  ---------            ----  ---------

      0     NetBEUI              0     TCP/IP

      3     IPX/SPX <==========> 1     IPX/SPX

                                 3     NetBEUI

   The above diagram illustrates several other important points about

   lanas. First, a transport that has a certain lana number on one host

   does not necessarily have the same lana number on other machines.

   Second, lana numbers do not have to be sequential.

   The EnumProtocols() function can be used to enumerate valid lana

   numbers. Listed below is a code fragment that demonstrates this type

   of functionality:

   #include <nspapi.h>

         DWORD          cb = 0;

         PROTOCOL_INFO *pPI;

         BOOL           pfLanas[100];

         int            iRes,

                        nLanas = sizeof(pfLanas) / sizeof(BOOL);

         // Specify NULL for lpiProtocols to enumerate all protocols.

         // First, determine the output buffer size.

         iRes = EnumProtocols( NULL, NULL, &cb );

         // Verify the expected error was received.

         // The following code must appear on one line.

         assert( iRes == -1 && GetLastError() ==

                      ERROR_INSUFFICIENT_BUFFER );

         if (!cb)

         {

            fprintf( stderr, "No available NetBIOS transports.\n");

            break;

         }

         // Allocate a buffer of the specified size.

         pPI = (PROTOCOL_INFO*) malloc( cb );

         // Enumerate all protocols.

         iRes = EnumProtocols( NULL, pPI, &cb );

         // EnumProtocols() lists each lana number twice, once for

         // SOCK_DGRAM and once for SOCK_SEQPACKET. Set a flag in pfLanas

         // so unique lanas can be identified.

         memset( pfLanas, 0, sizeof( pfLanas ));

         while (iRes > 0)

            // Scan protocols looking for AF_NETBIOS

            if ( pPI[--iRes].iAddressFamily == AF_NETBIOS )

               // found one.

               pfLanas[ pPI[iRes].iProtocol ] = TRUE;

         fprintf( stderr, "Available NetBIOS lana numbers: " );

         while( nLanas-- )

            if ( pfLanas[nLanas] )

               fprintf( stderr, "%d ", nLanas );

         free( pPI );

      }

6. Performance: Use of AF_NETBIOS is recommended for communication with

   down-level clients.

   On Windows NT, NetBIOS is a high level emulated interface.

   Consequently, applications that use the WinSock() function over NetBIOS

   obtain lower throughput than applications that use WinSock() over a

   native transport such as IPX/SPX or TCP/IP. However, due to the

   simplicity of the WinSock interface, it is a desirable interface for

   writing new 32-bit applications that communicate with NetBIOS

   applications running on down-level clients like Windows for Workgroups

   or Novell Netware.

Additional reference words: 3.50

KBCategory: kbnetwork kbcode

KBSubcategory: NtwkWinsock


Top-Level Menu Items in Owner-Draw Menus

PSS ID Number: Q69969

Authored 07-Mar-1991	Last modified 15-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

 - Microsoft Win32 SDK, versions 3.1, 3.5, 3.51, and 4.0

SUMMARY

Microsoft Windows version 3.0 allows an application to specify owner-draw

menus. This provides the application with complete control over the

appearance of items in the menu. However, Windows 3.0 only supports owner-

draw items in a pop-up menu. Top-level menu items with the MF_OWNERDRAW

style do not work properly.

In Windows 3.1, Windows NT, and Windows 95, top-level menu items with the

MF_OWNERDRAW style work properly.

MORE INFORMATION

An application may append an item with the MF_OWNERDRAW style to a top-

level menu. At this point, the parent application should receive a

WM_MEASUREITEM message and a WM_DRAWITEM message.

However, a WM_MEASUREITEM message is never sent to the parent window

for the menu item. In addition, the WM_DRAWITEM message is sent only

when the selection state of the item changes (the action field in the

DRAWITEMSTRUCT is equal to ODA_SELECTED). The WM_DRAWITEM message is

not sent with the action field in the DRAWITEMSTRUCT equal to

ODA_DRAWENTIRE.

Additional reference words: 3.00 3.10 3.50 4.00

KBCategory: kbprg

KBSubcategory: UsrMen


Tracking Brush Origins in a Win32-based Application

PSS ID Number: Q102353

Authored 03-Aug-1993	Last modified 23-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

When writing to the Win32 API on Windows NT, it is no longer necessary to

keep track of brush origins yourself. GDI32 keeps track of the brush

origins by automatically recognizing when the origin has been changed. In

Windows, you have to explicitly tell GDI to recognize the change by calling

UnrealizeObject() with a handle to the brush. When a handle to a brush is

passed to UnrealizeObject() in Windows NT, the function does nothing,

therefore, it is still safe to call this API.

Win32s and Windows 95 require that you track the brush origins yourself,

just as Windows 3.x does.

In Windows 3.1, the default brush origin is the screen origin. In Windows

NT, the default origin is the client origin.

Additional reference words: 3.10 3.50 4.00

KBCategory: kbprg

KBSubcategory: GdiPnbr


Translating Client Coordinates to Screen Coordinates

PSS ID Number: Q11570

Authored 23-Oct-1987	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.1 and 3.0

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

The GetClientRect function always returns the coordinates (0, 0) for

the origin of a window. This behavior is documented in the "Microsoft

Windows Software Development Kit (SDK) Programmer's Reference"

manual.

MORE INFORMATION

To determine the screen coordinates for the client area of a window,

call the ClientToScreen function to translate the client coordinates

returned by GetClientRect into screen coordinates. The following code

demonstrates how to use the two functions together:

   RECT rMyRect;

   GetClientRect(hwnd, (LPRECT)&rMyRect);

   ClientToScreen(hwnd, (LPPOINT)&rMyRect.left);

   ClientToScreen(hwnd, (LPPOINT)&rMyRect.right);

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrWndw


Translating Dialog-Box Size Units to Screen Units

PSS ID Number: Q74280

Authored 15-Jul-1991	Last modified 18-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.1 and 3.0

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

In the Microsoft Windows graphical environment, the MapDialogRect

function converts dialog-box units to screen units easily.

MORE INFORMATION

When a application dynamically adds a child window to a dialog box, it

may be necessary to align the new control with other controls that

were defined in the dialog box's resource template in the RC file.

Because the dialog box template defines the size and position of a

controls in dialog-box units rather than in screen units (pixels), the

application must translate dialog-box units to screen units to align

the new child window.

An application can use the following two methods to translate dialog-

box units to screen units:

1. The MapDialogRect function provides the easier method. This

   function converts dialog-box units to screen units automatically.

   For more details on this method, please see the documentation for

   the MapDialogRect function in the Microsoft Windows Software

   Development Kit (SDK).

2. Use the GetDialogBaseUnits function to retrieve the size of the

   dialog base units in pixels. A dialog unit in the x direction is

   one-fourth of the width that GetDialogBaseUnits returns. A dialog

   unit in the y direction is one-eighth of the height that the

   function returns.

   For more details on this method, see the documentation for the

   GetDialogBaseUnits function in the Windows SDK.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrDlgs


Transparent Blts in Windows NT

PSS ID Number: Q89375

Authored 21-Sep-1992	Last modified 24-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   and 3.51

SUMMARY

In order to perform a transparent blt in Microsoft Windows versions 3.0 and

3.1, the BitBlt() function must be called two or more times. This process

involves nine steps. (For more information on this process, see article

Q79212 in the Microsoft Knowledge Base.)

Windows NT introduces a new method of achieving transparent blts. This

method involves the use of the MaskBlt() function. The MaskBlt() function

lets you use any two arbitrary ROP3 codes (say, SRCCOPY and BLACKNESS) and

apply them on a pel-by-pel basis using a mask.

MORE INFORMATION

For this example, the source and target bitmaps contain 4 BPP. The call to

the MaskBlt() function is as follows:

   MaskBlt(hdcTrg,  // handle of target DC

                0,  // x coord, upper-left corner of target rectangle

                0,  // y coord, upper-left corner of target rectangle

               15,  // width of source and target rectangles

               15,  // height of source and target rectangles

           hdcSrc,  // handle of source DC

                0,  // x coord, upper-left corner of source rectangle

                0,  // y coord, upper-left corner of source rectangle

          hbmMask,  // handle of monochrome bit-mask

                0,  // x coord, upper-left corner of mask rectangle

                0,  // y coord, upper-left corner of mask rectangle

       0xAACC0020   // raster-operation (ROP) code

                );

The legend is as follows

   '.' = 0,

   '@' = 1,

   '+' = 2,

   '*' = 3,

   '#' = 15

Source Bitmap      Mask Bitmap        Target Bitmap      Result

------------------------------------------------------------------------

***+++***+++***    .......@.......    ###############    #######*#######

***+++***+++***    ......@@@......    ###############    ######***######

***+++***+++***    .....@@@@@.....    ##...........##    ##...+***+...##

+++***+++***+++    ....@@@@@@@....    ##...........##    ##..**+++**..##

+++***+++***+++    ...@@@@@@@@@...    ##...........##    ##.***+++***.##

+++***+++***+++    ..@@@@@@@@@@@..    ##...........##    ##+***+++***+##

***+++***+++***    .@@@@@@@@@@@@@.    ##...........##    #**+++***+++**#

***+++***+++***    @@@@@@@@@@@@@@@    ##...........##    ***+++***+++***

***+++***+++***    .@@@@@@@@@@@@@.    ##...........##    #**+++***+++**#

+++***+++***+++    ..@@@@@@@@@@@..    ##...........##    ##+***+++***+##

+++***+++***+++    ...@@@@@@@@@...    ##...........##    ##.***+++***.##

+++***+++***+++    ....@@@@@@@....    ##...........##    ##..**+++**..##

***+++***+++***    .....@@@@@.....    ##...........##    ##...+***+...##

***+++***+++***    ......@@@......    ###############    ######***######

***+++***+++***    .......@.......    ###############    #######*#######

Note that the ROP "AA" is applied where 0 bits are in the mask and the ROP

"CC" is applied where 1 bit is in the mask. This a transparency.

When creating a ROP4, you can use the following macro:

   #define ROP4(fore,back) ((((back) << 8) & 0xFF000000) | (fore))

This macro can be used to call the MaskBlt() function as follows:

   MaskBlt(hdcDest, xTrgt, yTrgt,

                          cx, cy,

              hdcSrc, xSrc, ySrc,

           hbmMask, xMask, yMask,

        ROP4(PATCOPY, NOTSRCCOPY)

                               );

This call would draw the selected brush where 1 bit appears in the mask and

bitwise negation of the source bitmap where 0 bits appear in the mask.

Additional reference words: 3.10 3.50 pixel

KBCategory: kbprg

KBSubcategory: GdiBmp


Transparent Windows

PSS ID Number: Q92526

Authored 09-Nov-1992	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.1 and 3.0

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

Microsoft Windows version 3.1 does not support fully functional transparent

windows.

MORE INFORMATION

If a window is created using CreateWindowEx() with the WS_EX_TRANSPARENT

style, windows below it at the position where the original window was

initially placed are not obscured and show through. Moving the

WS_EX_TRANSPARENT window, however, results in the old window background

moving to the new position, because Windows does not support fully

functional transparent windows.

WS_EX_TRANSPARENT was designed to be used in very modal situations and the

lifetime of a window with this style must be very short. A good use of this

style is for drawing tracking points on the top of another window. For

example, a dialog editor would use it to draw tracking points around the

control that is being selected or moved.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrWndw


Trapping Floating-Point Exceptions in a Win32-based App

PSS ID Number: Q94998

Authored 28-Jan-1993	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

The _controlfp() function is the portable equivalent to the _control87()

function.

To trap floating-point (FP) exceptions via try-except (such as

EXCEPTION_FLT_OVERFLOW), insert the following before doing FP operations:

   // Get the default control word.

   int cw = _controlfp( 0,0 );

   // Set the exception bits ON.

   cw &=~(EM_OVERFLOW|EM_UNDERFLOW|EM_INEXACT|EM_ZERODIVIDE|EM_DENORMAL);

   // Set the control word.

   _controlfp( cw, MCW_EM );

This turns on all possible FP exceptions. To trap only particular

exceptions, choose only the flags that pertain to the exceptions desired.

Note that any handler for FP errors should have _clearfp() as its first FP

instruction.

MORE INFORMATION

By default, Windows NT has all the FP exceptions turned off, and thus

computations result in NAN or INFINITY rather than an exception. Note,

however, that if an exception occurs and an explicit handler does not exist

for it, the default exception handler will terminate the process.

If you want to determine which mask bits are set and which are not during

exception handling, you need to use _clearfp() to clear the floating-point

exception. This routine returns the existing FP status word, giving the

necessary information about the exception. After this, it is safe to query

the chip for the state of its control word with _controlfp(). However, as

long as an unmasked FP exception is active, most FP instructions will

fault, including the fstcw in _controlfp().

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: BseExcept


Treeviews Share Image Lists by Default

PSS ID Number: Q131287

Authored 07-Jun-1995	Last modified 23-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) version 3.51, 4.0

 - Microsoft Win32s version 1.3

SUMMARY

The LVS_SHAREIMAGELISTS style is available for listview controls to enable

the same image lists to be used with multiple listview controls. There is

no equivalent TVS_SHAREIMAGELISTS, however, for the treeview control

because treeviews share image lists by default.

MORE INFORMATION

By default, a listview control takes ownership of the image lists

associated with it. For listviews, this could be any of three image lists

(those with large icons, small icons, or state images). These three image

lists are set by calling ListView_SetImageList() with the flags

LVSIL_NORMAL, LVSIL_SMALL, or LVSIL_STATE respectively. The listview then

takes responsibility for destroying these image lists when it is destroyed.

Setting the LVS_SHAREIMAGELISTS style, however, moves ownership of the

image lists from the listview control to the application. Because this

style assumes that the image lists are shared by multiple listviews,

specifying this style requires that the application destroy the image lists

when the last listview using them is destroyed. Failure to do so causes a

memory leak in the system.

Similarly, because treeviews share image lists by default, an application

that associates an image list with a treeview should ensure that the image

list is destroyed after the last treeview using it is destroyed. Another

way to do this is to first set the treeview's image list to NULL by using

TreeView_SetImageList(); then destroy the handle to the previous image list

returned by the function.

Additional reference words: 1.30 4.00 95 Common Controls

KBCategory: kbprg

KBSubcategory: UsrCtl


Troubleshooting Win32s Installation Problems

PSS ID Number: Q106715

Authored 14-Nov-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32s versions 1.1, 1.15, and 1.2

SUMMARY

The installation guide for Win32s that is included in the Win32 SDK

recommends running Freecell to verify that the installation was successful.

This article discusses some of the errors that may occur when trying to run

Freecell on an unsuccessful install. The article also contains a list of

corrective actions to help you reinstall Win32s.

MORE INFORMATION

Possible symptoms

-----------------

One of the following may occur when running Freecell if the installation is

not successful:

 - File Error: Cannot find OLECLI.DLL

   -or-

 - Win32s - Error:

   Improper installation. Win32s requires WIN32S.EXE and WIN32S16.DLL to

   run. Reinstall Win32s.

   -or-

 - Win32s - Error:

   Improper installation.  Windows requires w32s.386 in order to run.

   Reinstall Win32s.

   -or-

 - Error: Cannot find file freecell.exe (or one of its components)...

   -or-

 - The display is corrupted as soon as you run FreeCell.

Possible solutions

------------------

Check the following when Win32s does not install correctly:

 - If you are having video problems, check to see if you have an S3 video

   card. Certain S3 drivers do not work with Win32s. Either use the generic

   drivers shipped with Windows or contact your video card manufacturer for

   an updated driver. For additional information on the S3 driver and

   Win32s please see the following article(s) in the Microsoft Knowledge

   Base:

      ARTICLE-ID: Q117153

      TITLE     : PRB: Display Problems with Win32s and the S3 Driver

 - Make sure that the following line is in your SYSTEM.INI file

      device=*vmcpd

 - If you have a printer driver by LaserMaster, delete it or comment it out

   because it interferes with installing Win32s. Then reboot the computer

   so that the changes you made will take effect. After you successfully

   reinstall Win32s, reinstall the driver or remove the comment characters.

   The driver interferes with installing Win32s because the LaserMaster

   drivers create a WINSPOOL device . The extension is ignored when the

   filename portion of a path matches a device name. As a result, when

   Setup tries to write to WINSPOOL.DRV, it fails, because it attempts to

   write to WINSPOOL. In fact, any Win32-based application that tries to

   link to WINSPOOL.DRV also fails; however, most Win32-based applications

   that print under Win32s do not use the WINSPOOL application programming

   interfaces(APIs) because they are not supported in Win32s. As a result,

   you can usually just disable this driver while installing Win32s and

   then reenable it afterwards.

 - Delete the \WIN32S directory, the \WIN32APP directory, W32SYS.DLL,

   W32S16.DLL, and WIN32S.EXE from your hard drive before installing.

   Although it is possible to install Win32s on top of an old installation

   of Win32s, it is better to remove the old files before installing the

   new ones.

   Edit the WIN32S.INI file on your hard drive. Change the line(s) SETUP =

   1 to read SETUP = 0. Reboot your computer and reinstall Win32s.

 - Make sure that paging is enabled. From the Control Panel, select the 386

   Enhanced icon, choose Virtual Memory, and choose Change. Verify that the

   drive type is not set to none. The type can be set to either temporary

   or permanent.

 - If you are using SHARE, not VSHARE.386 (which WFW machines use), make

   sure that SHARE is enabled. Edit AUTOEXEC.BAT and add the following

   line if it is not already there:

      C:\DOS\SHARE.EXE

If you still receive errors when running Freecell, compare the binaries on

your hard drive with those on the CD. Use the MS-DOS program FILECOMP.EXE,

COMP.EXE, or FC.EXE and do a binary compare. For example, if you have the

Win32 SDK CD, type the following:

   fc /b <system>\win32s\w32s.386 <cd>:\mstools\win32s\nodebug\w32s.386

If you have the 32-bit Visual C++ CD, type the following:

   fc /b <system>\win32s\w32s.386 <cd>:\msvc32s\win32s\retail\w32s.386

The results of the compare will be, "FC: no differences encountered", if

the binaries were correctly installed. If the binaries are not the same,

you might have a bad copy of the files or a bad CD.

As a last resort, you can try reinstalling Win32s that shipped in the

Visual C++ 32-bit edition. There seems to be a slight difference between

the SETUP.EXE program on the Win32 SDK CD and the SETUP.EXE on the Visual

C++ CD. If you try installing from the 32-bit Visual C++ CD, you should NOT

remove the \WIN32APP or \FREECELL directory or any of the Freecell files.

The Visual C++ CD does not contain Freecell.

NOTE: Using Freecell Help will generate errors, including "Routine Not

Found" or "Help Topic Does Not Exist." The generation of these errors has

nothing to do with whether or not Win32s is installed correctly.

FREECELL.HLP was meant to be used with WINHLP32.EXE. FREECELL.HLP uses the

advanced features of WINHLP32 for full-text searching. WINHELP.EXE, which

runs on Windows 3.1, does not support this. As a result, each time

FREECELL.HLP tries to bind the Find button to the full-text searching APIs,

it fails, and Windows Help displays the message box. You can still read

the information in the help file. You can use the Search button to do

keyword searches.

Additional reference words: 1.10

KBCategory: kbsetup

KBSubcategory: W32s


TrueType Font Converters and Editors

PSS ID Number: Q87817

Authored 06-Aug-1992	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

The text below lists a number of commercial software tools that

convert existing fonts to TrueType fonts or help build new fonts. The

tools are listed in alphabetical order by name. None of these tools is

recommended over any other, nor over any that are absent from the

list. Each of the tools has its own strengths and weaknesses. Before

making any purchase, examine the tool and its documentation to see if

it meets your needs. This list will be updated as more tools become

available.

Some of the following tools run on an Apple Macintosh while others run

on an IBM PC/AT or compatible computer. The same TrueType font can run

on a Macintosh or with Microsoft Windows operating system version 3.1.

To convert a font from the Macintosh to Windows 3.1, save the data

fork from a Macintosh font to a file, copy the file to an

MS-DOS-formatted disk, give the file a .TTF file extension, and use

the Windows 3.1 Control Panel to install the font.

The products included here are manufactured by vendors independent of

Microsoft; we make no warranty, implied or otherwise, regarding these

products' performance or reliability.

MORE INFORMATION

Last Update: 24 July 1992

                      FONT CONVERSION UTILITIES

                      =========================

AllType for MS-DOS

------------------

Author:       Atech Software

              5964 La Place Court, Suite 125

              Carlsbad, CA 92008

              (619) 438-6883

Description:  Character-based application running under MS-DOS.

              Converts almost any font format to any other. Supported

              formats include TrueType, Type-1, Type-3, Nimbus-Q, and

              Intellifont.

Evolution 2.0 for Macintosh

---------------------------

Author:       Image Club Graphics, Inc.

              1902 11th St. SE, Suite 5

              Calgary, Alberta, Canada T2G 3G2

              (403) 262-8008

Description:  Converts almost any font format to any other. Supported

              formats include TrueType, Type-1, and Type-3.

FontMonger for Windows

FontMonger for Macintosh

------------------------

Author:       Ares Software

              561 Pilgrim Drive, Suite D

              Foster City, CA 94404

              (415) 578-9090

Description:  Converts almost any font format to any other. Supported

              formats include TrueType, Type-1, Type-3, and

              Intellifont. Also provides minor font editing by

              creating composite characters or rearranging the

              characters in a font.

Incubator for Windows

---------------------

Author:       Type Solutions, Inc.

              91 Plaistow Rd

              Plaistow, NH 03865

              (603) 382-6400

Description:  Supports adding effects to TrueType fonts. Contact Type

              Solutions for more information.

Metamorphosis Professional for Macintosh

----------------------------------------

Author:       Altsys Corp.

              269 W. Renner Rd

              Richardson, TX 75080

              (214) 680-2060

Description:  Converts almost any font format to any other. Supported

              formats include TrueType, Type-1, Type-3, and PICT

              format. One interesting feature allows the user to read

              a Type-1 font from the ROM of an Apple LaserWriter

              printer and convert the font to another format.

                             FONT EDITORS

                             ============

Fontographer 3.5 for Windows

Fontographer 4.1 for Macintosh

------------------------------

Author:       Altsys Corp.

              269 W. Renner Rd

              Richardson, TX 75080

              (214) 680-2060

Description:  A complete font editing tool. Supports creating a font

              from scratch and modifying existing fonts. Supports a

              variety of formats including TrueType and Type-1.

              Includes an autohinter.

FontStudio 2.0 for Macintosh

----------------------------

Author:       Letraset Graphic Design Software

              40 Eisenhower Dr

              Paramus, NJ 07653

              (800) 343-TYPE  or (201) 845-6100

Description:  A complete font editing tool. Supports creating fonts

              from scratch and modifying existing fonts. Supports a

              variety of formats including TrueType and Type-1.

              Includes an autohinter.

TypeMan 1.0 for Macintosh

-------------------------

Author:       Type Solutions, Inc.

              91 Plaistow Rd

              Plaistow, NH 03865

              (603) 382-6400

Description:  Designed for font foundries, this tool provides precise

              control over the hints in a font and includes an

              autohinter. Supports specifying a font in a high-level

              programming language, which the tool compiles to the

              binary TrueType format.

Additional reference words: 3.10 3.50 4.00 95  true type

KBCategory: kbprg

KBSubcategory: GdiTt


Trusted DDE Shares

PSS ID Number: Q128125

Authored 27-Mar-1995	Last modified 26-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), version 3.5

SUMMARY

To allow someone else to connect to DDE shares when you are logged in, you

have to trust your existing DDE share. The reason is that when the other

person connects to the share remotely, the application he will connect to

is running in your security context, not the remote user's, because you are

the logged-on user. You need to give permission for the other person to

access the share. Even another person who is an administrator cannot trust

a share for your account.

In your code, you would use NDdeShareAdd() to create the share and

NDdeSetTrustedShare() to trust the share.

Alternatively, you can use DDESHARE to create the share. For more

information on DDESHARE, please see the following article in the Microsoft

Knowledge Base:

   ARTICLE-ID: Q114089

   TITLE     : Using the Windows NT NetDDE Share Manager

If you have a DDE share that always needs to be available, you can write

a program that trusts the specific shares and sets up a logon script

to trust the share for every user. The logon script should be a .BAT

file that calls the .EXE file, so that you can add other things to the

logon script as necessary.

MORE INFORMATION

The online documentation for NDdeSetTrustedShare says:

   The NDdeSetTrustedShare function is called to promote the

   referenced DDE share to trusted status within the current

   user's context.

DDE shares are a machine resource, not an account resource, just as

shared drives are. However, NetDDE runs an application that must run

in the context of the current user. This is the reason that the share

must be trusted, so that the application can run in the user's context.

The prototype for the function is:

   UINT NDdeSetTrustedShare(lpszServer, lpszShareName, dwTrustOptions)

The parameter lpszServer is the address of the server name on which the

DDE share resides. The DDE Share Database (DSDM) will be modified. This

service manages the shared DDE conversations and is used by the NetDDE

service. This parameter will generally be the current machine, because

you can't trust a share for someone else.

The dwTrustOptions are NDDE_TRUST_SHARE_START and NDDE_TRUST_SHARE_INIT.

NDDE_TRUST_SHARE_START allows the DDE server, such as Excel, to be

started in the user's context. This allows a DDE client to make a NetDDE

connection without the DDE server already running. When the NetDDE agent

on the server machine detects the attempted connection, it launches the

associated DDE server application if it is not already running.

NDDE_TRUST_SHARE_INIT allows a client to initiate to the DDE server if it

is already executing in the user's context. This allows a DDE client to

make a NetDDE connection to a DDE server already running on the server

machine. If the DDE server is not already running, the connection will

fail.

Additional reference words: 3.50

KBCategory: kbprg

KBSubcategory: UsrNetDde


Types of File I/O Under Win32

PSS ID Number: Q99173

Authored 24-May-1993	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

There are multiple types of file handles that can be opened using the Win32

API and the C Run-time:

   Returned Type  File Creation API      API Set

   ---------------------------------------------

   HANDLE         CreateFile()           Win32

   HFILE          OpenFile()/_lcreat()   Win32

   int            _creat()/_open()       C Run-time

   FILE *         fopen()                C Run-time

In general, these file I/O "families" are incompatible with each other. On

some implementations of the Win32 application programming interfaces

(APIs), the OpenFile()/_lcreat() family of file I/O APIs are implemented as

"wrappers" around the CreateFile() family of file I/O APIs, meaning that

OpenFile(), _lcreat(), and _lopen() end up calling CreateFile(), returning

the handle returned by CreateFile(), and do not maintain any state

information about the file themselves. However, this is an implementation

detail only and is NOT a design feature.

NOTE: You cannot count on this being true on other implementations of the

Win32 APIs. Win32 file I/O APIs may be written using different methods on

other platforms, so reliance on this implementation detail may cause your

application to fail.

The rule to follow is to use one family of file I/O APIs and stick with

them--do not open a file with _lopen() and read from it with ReadFile(),

for example. This kind of incorrect use of the file I/O APIs can easily be

caught by the compiler, because the file types (HFILE and HANDLE

respectively) are incompatible with each other and the compiler will warn

you (at warning level /w3 or higher) when you have incorrectly passed one

type of file handle to a file I/O API that is expecting another, such as

passing an HFILE type to ReadFile(HANDLE, ...) in the above example.

MORE INFORMATION

Compatibility

-------------

The OpenFile() family of file I/O functions is provided only for

compatibility with earlier versions of Windows. New Win32-based

applications should use the CreateFile() family of file I/O APIs, which

provide added functionality that the earlier file I/O APIs do not provide.

Each of the two families of C Run-time file I/O APIs are incompatible with

any of the other file I/O families. It is incorrect to open a file handle

with one of the C Run-time file I/O APIs and operate on that file handle

with any other family of file I/O APIs, nor can a C Run-time file I/O

family operate on file handles opened by any other file I/O family.

_get_osfhandle()

----------------

For the C Run-time unbuffered I/O family of APIs [_open(), and so forth],

it is possible to extract the operating system handle that is associated

with that C run-time handle via the _get_osfhandle() C Run-time API. The

operating system handle is the handle stored in a C Run-time internal

structure associated with that C Run-time file handle. This operating

system handle is the handle that is returned from an operating system call

made by the C Run-time to open a file [CreateFile() in this case] when you

call one of the C Run-time unbuffered I/O APIs [_open(), _creat(),

_sopen(), and so forth].

The _get_osfhandle() C Run-time call is provided for informational purposes

only. Problems may occur if you read or write to the file using the

operating system handle returned from _get_osfhandle(); for these reasons

we recommend that you do not use the returned handle to read or write to

the file.

_open_osfhandle()

-----------------

It is also possible to construct a C Run-time unbuffered file I/O handle

from an operating system handle [a CreateFile() handle] with the

_open_osfhandle() C Run-time API. In this case, the C Run-time uses the

existing operating system handle that you pass in rather than opening the

file itself. It is possible to use the original operating system handle to

read or write to the file, but it is very important that you use only the

original handle or the returned C Run-time handle to access the file, but

not both, because the C Run-time maintains state information that will not

be updated if you use the operating system handle to read or write to the

file.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: BseFileio


Types of Thunking Available in Win32 Platforms

PSS ID Number: Q125710

Authored 02-Feb-1995	Last modified 14-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

 - Microsoft Win32s, version 1.3

SUMMARY

Thunks allow code on one side of the 16-32 process boundary to call into

code on the other side of the boundary. Each Win32 platform employs one or

more thunking mechanisms. This table summarizes the thunking mechanisms

provided by the different Win32 platforms.

                   +-Win32s-+-Windows 95-+-Windows NT-+

   Generic Thunk   |        |      X     |      X     |

                   +--------+------------+------------+

   Universal Thunk |    X   |            |            |

                   +--------+------------+------------+

   Flat Thunk      |        |      X     |            |

                   +--------+------------+------------+

Generic Thunks allow a 16-bit Windows-based application to load and call

a Win32-based DLL on Windows NT and Windows 95.

Windows 95 also supports a thunk compiler, so a Win32-based application

can load and call a 16-bit DLL

Win32s Universal Thunks allow a Win32-based application running under

Win32s to load and call a 16-bit DLL. You can also use UT to allow a 16-

bit Windows-based application to call a 32-bit DLL under Win32s, but

this isn't officially supported. Certain things do not work on the 32-

bit side because the app was loaded with the context of a 16-bit

Windows-based application.

This article describes the types of thunking mechanisms available on each

Win32 platform.

MORE INFORMATION

Windows NT

----------

Windows NT supports Generic Thunks, which allow 16-bit code to call into 32-

bit code. Generic Thunks do not allow 32-bit code to call into 16-bit code.

The generic thunk is implemented by using a set of API functions that are

exported by the WOW KERNEL and WOW32.DLL.

In Windows NT, 16-bit Windows-based applications are executed in a

subsystem (or environment) called WOW (Windows On Win32). Each application

runs as a thread in a VDM (virtual DOS machine).

Using generic thunks is like explicitly loading a DLL. The four major APIs

used in generic thunking are: LoadLibraryEx32W(), FreeLibrary32W(),

GetProcAddress32W(), and CallProc32W(). Their functionality is very similar

to LoadLibraryEx(), FreeLibrary(), GetProcAddress(), and calling the

function through a function pointer. The Win32-based DLL called by the

thunk is loaded into the VDM address space. The following is a example of

thunking a call to GetVersionEx():

   void FAR PASCAL __export MyGetVersionEx(OSVERSIONINFO *lpVersionInfo)

   {

      HINSTANCE32 hKernel32;

      FARPROC lpGetVersionEx;

      // Load KERNEL32.DLL

      if (!(hKernel32 = LoadLibraryEx32W("KERNEL32.DLL", NULL, NULL)))

      {

         MessageBox(NULL, "LoadLibraryEx32W Failed", "DLL16", MB_OK);

         return;

      }

      // Get the address of GetVersionExA in KERNEL32.DLL

      if (!(lpGetVersionEx =

            GetProcAddress32W( hKernel32, "GetVersionExA")))

      {

         MessageBox(NULL, "GetProcAddress32W Failed", "DLL16", MB_OK);

         return;

      }

      lpVersionInfo->dwOSVersionInfoSize = sizeof(OSVERSIONINFO);

      // Call GetVersionExA

      CallProc32W(lpVersionInfo, lpGetVersionEx, 1, 1);

      // Free KERNEL32.DLL

      if (!FreeLibrary32W(hKernel32))

      {

         MessageBox(NULL, "FreeLibrary32W Failed", "DLL16", MB_OK);

         return;

      }

      return;

   }

Win32s

------

All 16-bit Windows-based and Win32-based applications run in a single

address space in Win32s. The mechanism that is provided for accessing

16-bit code from 32-bit code is called the Universal Thunk. The Universal

Thunks consists of 4 APIs. The major APIs, UTRegister() and UTUnRegister(),

are exported by KERNEL32. The prototype for UTRegister() is:

   BOOL UTRegister(HANDLE hModule,        // Win32-based DLL handle

                   LPCTSTR lpsz16BITDLL,  // 16-bit DLL to call

                   LPCTSTR lpszInitName,  // thunk initialization procedure

                   LPCTSTR lpszProcName,    // thunk procedure

                   UT32PROC *ppfn32Thunk,   // pointer to thunk procedure

                   FARPROC pfnUT32CallBack, // optional callback

                   LPVOID lpBuff);          // shared memory buffer

NOTES: lpszInitName, pfnUT32CallBack, and lpBuff are optional parameters.

The value for ppfn32Thunk is the returned value of the 32-bit function

pointer to the thunk procedure. The buffer lpBuff is a globally allocated

shared memory buffer that is available to the 16-bit initialization routine

via a 16-bit selelctor:offset pointer.

The function pointer returned in ppfn32Thunk has the following syntax:

   WORD (*ppfn32Thunk)(lpBuff, dwUserDefined, *lpTranslationList);

where lpBuff is the pointer to the shared data area, dwUserDefined is

available for application use (it is most commonly used as a switch

for multiple thunked functions), and lpTranslationList is an array of flat

pointers within lpBuff that are to be translated into selector:offset

pointers.

This method is not portable to other platforms.

Windows 95

----------

Thunking in Windows 95 allows 16-bit code to call 32-bit code and vice-

versa. The mechanism used is a thunk compiler. To use the thunk compiler

you need to create a thunk script, which is the function prototype with

additional information about input and output variables.

The thunk compiler produces a single assembly language file. This single

assembly language file should be assembled using two different flags -

DIS_32 and -DIS_16 to produce a 16-bit and 32-bit object files. These

object modules should be liked to their respective 16-bit and 32-bit DLL's.

There are no special APIs used, all you have to do is call the function.

In addition to Flat Thunks, Windows 95 supports the Windows NT Generic

Thunk mechanism. Generic thunks are recommended for portability between

Windows 95 and Windows NT.

REFERENCES

For more information on Generic Thunks, see GENTHUNK.TXT on the Win32 SDK

CD.

For more information on the Universal Thunk, see the "Win32s Programmer's

Reference" and the UTSAMP sample on the Win32 SDK CD.

Additional reference words: 1.30 3.50 4.00

KBCategory: kbprg

KBSubcategory: SubSys BseMisc W32s


Understanding Win16Mutex

PSS ID Number: Q125867

Authored 07-Feb-1995	Last modified 06-Apr-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

SUMMARY

Windows 95 offers preemptive multithreaded scheduling for Win32 processes,

yet also provides the familiar non-preemptive task switching found in

Windows 3.x for Win16 applications. Some of the Win32 system DLLs, such as

USER32.DLL and GDI32.DLL, thunk to their 16-bit counterparts for

compatibility and size. Unlike Windows 3.x, which did not preemptively

schedule processes, Windows 95 must be able to handle the possibility that

it might be reentered by two or more processes each calling the same API

functions. Windows 95 must do so in a way that uses little memory and is

compatible with all existing 16-bit applications and DLLs.

Win16Mutex is a global semaphore that is used to protect the 16-bit Windows

95 components from being reentered by preventing Win32 threads from

thunking to 16-bit components while other 16-bit code is running.

Win16Mutex is internal to Windows 95 and is not accessible from

applications or DLLs. This article explains how Win16Mutex works and offers

design tips for minimizing the effects Win16Mutex may have on Win32

applications.

MORE INFORMATION

Because Windows 3.x is a non-preemptive system, Windows 3.x did not need to

be designed to prevent the system from being reentered. Only one task

(application instance) at a time can call system services (API functions)

because other tasks cannot run until the active task voluntarily yields

control of the CPU. Since only one task can execute at a time, it is not

possible to have two different tasks calling the same API function, and

thus Windows does not need to protect itself from reentrancy.

Windows 95 differs from Windows 3.x because Windows 95 provides support for

both Win32 and Win16 applications. In Windows 95, every instance of every

Win16 application is a process with exactly one thread, and every Win32

process has at least one thread. Win32 threads are preemptively scheduled

and may even preempt Win16 processes. Because many Win32 API functions are

thunked to 16-bit Windows API functions, there is now a possibility for the

16-bit Windows components to be reentered. Since the 16-bit Windows

components are largely the same as in Windows 3.x, they need to be

protected from being reentered.

The Win16Mutex provides this protection by allowing only one thread (not

process) at a time to access the 16-bit APIs. Whenever Win16Mutex is owned

by a thread, any other thread that tries to claim Win16Mutex will block

until Win16Mutex is released. Now the question remains: "When does

Win16Mutex get claimed and released?"

Whenever a Win16 process is running, it owns Win16Mutex. That is, when a

Win16 process first gets a message via GetMessage or PeekMessage, the Win16

process claims Win16Mutex. The Win16 process releases Win16Mutex whenever

the process yields, such as when the process calls GetMessage or

PeekMessage and doesn't return. The only way a Win16 process can keep

Win16Mutex indefinitely is to never yield; since the message-processing

mechanism provides the scheduler in 16-bit Windows, the only way to never

yield is to stop processing messages (which makes the application

unresponsive to user input).

The only time a thread in a Win32 process claims Win16Mutex is when the

thread makes a call to an API function which thunks to one of the 16-bit

Windows components or when the thread thunks directly to a Win16 DLL.

Immediately after the call returns, the process releases Win16Mutex. Not

all API functions thunk to 16-bit components; most 32-bit USER and GDI

functions thunk to 16-bit USER and GDI, but none of the 32-bit KERNEL

functions thunk to 16-bit KRNL386. One exception is when a Win32 process

spawns a Win16 process, KERNEL32 thunks to KRNL386 to call the Win16

loader.

Putting 16-bit and 32-bit behaviors together, you can see that when a Win16

process is running, and a thread of a Win32 process preempts the Win16

process and calls a function which thunks to a 16-bit component, the Win32

thread is put to sleep until the Win16 process yields, which releases

Win16Mutex. Likewise, when one Win32 process's thread claims Win16Mutex and

then loses its timeslice, and another thread from either the same or a

different process tries to claim Win16Mutex, the second thread blocks until

Win16Mutex is released.

Win16Mutex is internal to Windows 95 and may not be manipulated or even

checked by applications and DLLs. Win16Mutex is implemented mainly in the

thunk layer so that every Win32 API which thunks to a Win16 component will

automatically claim Win16Mutex before entering 16-bit code. Additionally,

thunks created by the thunk compiler to allow Win32 applications and DLLs

to call 16-bit DLLs claim Win16Mutex automatically, so programmers do not

have to do so explicitly.

One way to lessen the impact that Win16 applications have on the

responsiveness of Win32 applications is to create multiple threads where

the primary thread (the initial thread of the process) controls the entire

user interface for the process and each additional thread performs some

useful task, such as reading or writing to a data file, but does not make

user interface or graphics calls. This way, if the Win32 process's primary

thread blocks waiting for a Win16 process to yield, its other threads are

still performing useful work.

Additional reference words: 4.00

KBCategory: kbprg

KBSubcategory: BseProcThread


UNICODE and _UNICODE Needed to Compile for Unicode

PSS ID Number: Q99359

Authored 26-May-1993	Last modified 18-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   versions 3.1 and 3.5

To compile code for Unicode, you need to #define UNICODE for the Win32

header files and #define _UNICODE for the C Run-time header files. These

#defines must appear before the

   #include <windows.h>

and any included C Run-time headers. The leading underscore indicates

deviance from the ANSI C standard. Because the Windows header files are not

part of this standard, it is allowable to use UNICODE without the leading

underscore.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: UsrNls


Unicode Conversion to Integers

PSS ID Number: Q89295

Authored 16-Sep-1992	Last modified 24-Mar-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

SUMMARY

Under Windows NT, strings may be either Unicode or ANSI. There is no

function for reliably converting a string that might be either Unicode or

ANSI to an integer. This is because, given a random set of bytes, it is

difficult to determine whether the string is in Unicode or ANSI. The

calling program has to know which format the string uses in order to

convert it.

If the string uses Unicode, the functions wcstol(), wcstoul(), and wcstod()

can be used to perform the conversion.

Note that when you are using the Win32 application programming interface

(API), you can choose what kind of characters you get from the console or

window manager. The names of the API functions that are called to use

Unicode and ANSI characters are different. For more details, see Chapter 93

in the overview, "Unicode."

To mark a string as Unicode, insert the byte-ordering-mark (BOM) 0xFEFF in

the string and/or file.

MORE INFORMATION

You can assume that the first 128 bytes in each character set are in the

same codepoint. For portability, you should code character conversions in

this range as:

   {

      TCHAR     c;

        ...

        i = c - TEXT('0');

   }

The TEXT macro places an "L" before the constant if Unicode is defined.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: WIntlDev


Unicode Functions Supported by Windows 95

PSS ID Number: Q125671

Authored 01-Feb-1995	Last modified 15-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

Unlike Windows NT, Windows 95 does not implement the Unicode (or wide

character) version of most Win32 functions that take string parameters.

With some exceptions, these functions are implemented as stubs that

simply return an error value.

In general, Windows 95 implements the ANSI version of these functions.

See the Win32 API documentation for information on particular functions

and differences between the various Win32 platforms.

One major exception to this rule is OLE. All native 32-bit OLE APIs

and interface methods use Unicode exclusively. For more information on

this, please see the OLE documentation.

Excluding OLE, Windows 95 supports the following wide character functions:

   EnumResourceLanguages

   EnumResourceNames

   EnumResourceTypes

   ExtTextOut

   FindResource

   FindResourceEx

   GetCharWidth

   GetCommandLine

   GetTextExtentExPoint

   GetTextExtentPoint32

   GetTextExtentPoint

   lstrlen

   MessageBoxEx

   MessageBox

   TextOut

In addition, Windows 95 implements the following two functions for

converting strings to or from Unicode:

   MultiByteToWideChar

   WideCharToMultiByte

Additional reference words: 4.00

KBCategory: kbprg

KBSubcategory: WIntlDev


Unicode Implementation in Windows NT 3.1 and 3.5

PSS ID Number: Q103977

Authored 02-Sep-1993	Last modified 27-Feb-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.1 and 3.5

SUMMARY

Windows NT is the first widely available operating system to be built

upon the Unicode character encoding. Almost all of the strings used in

the system have 16-bits reserved for each character. However, Windows

NT does not yet realize the Unicode ideal of offering an editor

capable of handling one document containing all of the languages of

the world.

MORE INFORMATION

Unicode support in Windows NT:

 - All Windows USER objects support Unicode strings.

 - The Win32 console is Unicode enabled.

 - NTFS supports Unicode filenames.

 - All of the information strings in the registry are Unicode.

 - The L_10646.TTF (Lucida Sans Unicode) font covers over 1300 Unicode

   characters.

 - Most of the TrueType fonts include a Unicode encoding table.

Unicode features missing from Windows NT:

 - There is no font support for all of the Unicode characters.

 - Although the Win32 console is Unicode enabled, it is not possible to

   use Unicode fonts in the console. Most Unicode characters will be

   represented by the "default character" of the System font.

 - Winhlp32 is not Unicode enabled.

 - There is no general Unicode input method in Windows NT version 3.1. The

   shell applets and File Manager fully support Unicode. You can use the

   new Notepad and Character Mapper applets to create files with Unicode

   text. (Choose the Lucida Sans Unicode font in the Character Mapper, then

   choose the desired Unicode characters in the Character Mapper and copy

   them to the clipboard. Paste the clipboard contents into Notepad, making

   sure Notepad has the Lucida Sans Unicode font selected, and save the

   file as a "Unicode Files". Note, this same process can be used to give

   files Unicode filenames.)

 - The FAT and HPFS file systems do not support Unicode filenames.

   (Nor will they in the future; to accomplish this, use NTFS.)

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: UsrNls


Uniqueness Values in User and GDI Handles

PSS ID Number: Q94917

Authored 25-Jan-1993	Last modified 21-Feb-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

SUMMARY

User and GDI handles, are divided into two parts:

 - The lower 16 bits is an index into a system table of handle

   structures, which includes information such as the type of handle

   (window, menu, cursor, and so forth), as well as a value called the

   uniqueness.

 - The upper 16 bits contain the same uniqueness value.

The first time a handle is issued by the system, the uniqueness value is 0

(zero). It is incremented each time the handle is re-used. In Windows NT

3.1, if you pass in a value of 0xFFFF for the uniqueness, the client side

(that is, USER32.DLL) will look up the correct uniqueness value in shared

memory and use the correct handle. In Windows NT 3.5, use 0x0000 for the

uniqueness value.

This is important because it alleviates potential conflicts with re-used

handles. For example, when a window is destroyed, its handle is reused by

the system. The uniqueness value prevents an old handle to a destroyed

window from being misinterpreted by the system as the handle to a new

object, which was given the same handle value.

MORE INFORMATION

In Win32s, use 0x0000 in the upper 16 bits for the uniqueness.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: UsrMisc


Use 16-Bit .FON Files for Cross-Platform Compatibility

PSS ID Number: Q100487

Authored 22-Jun-1993	Last modified 17-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

The AddFontResource() function installs a font resource in the GDI font

table. Under Windows NT and Windows 95, the module can be a .FON file or a

.FNT file. Under Windows 3.1, the module must be a .FON file. When using

Win32s, AddFontResource() passes its argument to the Win16 AddFontResource,

and therefore .FON files should be used for portability.

In addition, when running under Windows NT or Windows 95, the module can be

either a 32-bit "portable executable" or a 16-bit .FON file. However, if

the same Win32 executable is run under Win32s, the call to

AddFontResource() fails if the .FON is not in 16-bit format. Therefore, for

compatibility across platforms, use 16-bit .FON files. These can be created

using the Windows 3.1 Software Development Kit (SDK).

Additional reference words: 3.10 3.50 4.00

KBCategory: kbprg

KBSubcategory: GdiFnt


Use LoadLibrary() on .EXE Files Only for Resources

PSS ID Number: Q108448

Authored 12-Dec-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

The LoadLibrary() application programming interface (API) can be used to

load an executable module. A common use of this function is to load a

dynamic-link library (DLL), perform a subsequent call to GetProcAddress()

to get the address of an exported DLL routine, and call this DLL routine

through the address that is returned. Another use of LoadLibrary() is to

load an executable module and retrieve its resources.

In Windows NT, a LoadLibrary() of an .EXE file is supported only for the

purposes of retrieving resources. It was decided that it was rather

uncommon to load an .EXE for any other purpose, so this limitation was

imposed on LoadLibrary() to improve the performance in loading resources.

Calling a routine in an .EXE through an address obtained with

GetProcAddress() can cause an access violation.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseMisc


Use MoveWindow to Move an Iconic MDI Child and Its Title

PSS ID Number: Q70079

Authored 09-Mar-1991	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, version 3.5

Although Windows does not have application programming interface (API)

calls to support dragging iconic windows (windows represented by an icon),

calls to MoveWindow() can be used to implement a dragging functionality for

iconic multiple-document interface (MDI) child windows.

However, the icon's title is not in the same window as the icon, so

when the icon is moved, the title will not automatically move with it.

The title is in a small window of its own, so a separate call to

MoveWindow() must be made to place the title window correctly below

the icon.

The information below describes how to get the window handle for the

small title window, so that the appropriate call to MoveWindow() can

be made.

The icon's title window is a window of class #32772. This window is a

child of the MDI client window, and its owner is the icon window.

To get the window handle to the appropriate icon title window for a

given icon, enumerate all the children of the MDI client window,

looking for a window whose owner is the icon.

You can use EnumChildWindows() to loop through all the children of the

MDI client window.

You can use GetWindow(..., GW_OWNER) to check the parent of each

window.

Additional reference words: 3.00 3.10 3.50

KBCategory: kbprg

KBSubcategory: UsrMdi


Use of Allocations w/ cbClsExtra & cbWndExtra in Windows

PSS ID Number: Q11606

Authored 23-Oct-1987	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

The following is an explanation of the use of the allocations with

cbClsExtra and cbWndExtra?:

1. cbClsExtra -- extra bytes to allocate to CLASS data structure in

   USER.EXE local heap when RegisterClass() is called. Accessed by

   Get/Set CLASS Word/Long ();.

2. cbWndExtra -- extra bytes to allocate to WND data structure in

   USER.EXE local heap when CreateWindow() is called. Accessed by

   Get/Set WND Word/Long ();.

You can use these structures at your discretion and for any purpose you

desire.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: UsrCls


Use of DLGINCLUDE in Resource Files

PSS ID Number: Q91697

Authored 02-Nov-1992	Last modified 24-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

The dialog editor needs a way to know what include file is associated with

a resource file that it opens. Rather than prompt the user for the name of

the include file, the name of the include file is embedded in the resource

file in most cases.

MORE INFORMATION

Embedding the name of the include file is done with a resource of type

RCDATA with the special name DLGINCLUDE. This resource is placed into the

.RES file and contains the name of the include file. The dialog editor

looks for this resource when it loads a .RES file. If this resource is

found, then the include file is opened also; if not, the editor prompts the

user for the name of the include file.

In some Windows 3.1 build environments, the dialog editor was used to

create dialogs that were placed in more than one .DLG file. These different

.DLG files were then included in one .RC file, which was compiled with the

resource compiler. Therefore, the resource file gets multiple copies of a

RCDATA type resource with the same name, DLGINCLUDE, but the resource

compiler and dialog editor don't complain.

In the Win32 SDK, changes were made so that this resource has its own

resource type; it was changed from an RCDATA-type resource with the

special name, DLGINCLUDE, to a DLGINCLUDE resource type whose name can

be specified. The dialog editor would look for resources of the type

DLGINCLUDE.

We are being more strict about the need for resources to be unique in the

Win32 SDK than the Windows 3.1 SDK. This is good because there was never

any guarantee at run time as to which of the two or more resources would be

returned by LoadResource().

This means that some applications being ported to Windows NT give an error

when their resources are compiled because they have duplicate RCDATA type

resources with the same name (DLGINCLUDE). This error is by design. The

workaround is straightforward: delete all the DLGINCLUDE RCDATA type

resource statements from all the .DLG files.

Finally, because it does not make sense to have the DLGINCLUDE type

resources in the executable, the linker will strip them out so that they

don't get linked into the EXE.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbtool

KBSubcategory: TlsDlg


Use of DocumentProperties() vs. ExtDeviceMode()

PSS ID Number: Q92514

Authored 08-Nov-1992	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

Windows-based applications have used ExtDeviceMode() to retrieve or modify

device initialization information for printer drivers. The Win32 API

introduces a new function DocumentProperties() that applications can use to

configure the settings of the printer.

Note that ExtDeviceMode() calls DocumentProperties(); therefore, it is

faster for applications to use DocumentProperties() directly.

Specifying the DM_UPDATE mask allows an application to change printer

settings when using DocumentProperties(). Applications should be aware

that the GetProcAddress() function is now case sensitive.

Windows-based applications running on Windows NT (WOW) can call

ExtDeviceMode(). The spooler's ExtDeviceMode() entry is intended for WOW

use.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: GdiPrn


Use of NULL_PEN, NULL_BRUSH, and HOLLOW_BRUSH

PSS ID Number: Q66532

Authored 30-Oct-1990	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

GDI contains several "NULL" stock objects: NULL_BRUSH, HOLLOW_BRUSH, and

NULL_PEN. These objects are defined in WINDOWS.H (16-bit SDK) or in

WINGDI.H (32-bit SDK). These header files define HOLLOW_BRUSH as

NULL_BRUSH, so they are the same objects.

Note that NULL_BRUSH and NULL_PEN are NOT identical to the value NULL. The

value NULL is defined as 0 (zero) in WINDOWS.H and is not a valid stock

object.

Many GDI functions use the current brush to fill interiors and the current

pen to draw lines. In some cases, an application may not want to modify the

areas normally affected by the pen or brush. Selecting a NULL_PEN or

NULL_BRUSH into the device context tells GDI not to modify the normally

affected areas. In short, "NULL_" objects do not draw anything.

For example, the Rectangle() function uses the current brush to fill

the interior of the rectangle and the current pen to draw the border.

If NULL_PEN is selected into the device context, no border is drawn.

If NULL_BRUSH or HOLLOW_BRUSH is selected, the interior of the

rectangle is not painted. If both NULL_PEN and NULL_BRUSH are

selected, the rectangle will not be drawn.

Additional reference words: 3.00 3.10 3.50 4.00 95  hollow

KBCategory: kbprg

KBSubcategory: GdiPnbr


Use of Polygon() Versus PolyPolygon()

PSS ID Number: Q119164

Authored 09-Aug-1994	Last modified 18-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   versions 3.1 and 3.5

SUMMARY

Polygon() draws a polygon, while PolyPolygon() draws a series of polygons.

Using multiple calls to Polygon() can offer better performance than using a

single call to PolyPolygon(); this is because PolyPolygon() does not

consider the polygons to be independent, but considers them to be one

polygon with multiple disjointed edges. However, there are times when

PolyPolygon() is preferable, particularly if the number of polygons is

small.

MORE INFORMATION

PolyPolygon() batches polygons in a single call, so there is less call

overhead than there is for multiple calls to Polygon(). However, to perform

one combined fill, PolyPolygon() has to work with all the edges in all of

the polygons simultaneously, resulting in sorting overhead. The overhead

involved in sorting becomes quite expensive when there are a lot of

polygons, causing a net loss of performance in comparison to Polygon().

GDI batches multiple Polygon() calls to be more efficient. Setting the

batch limit higher than the default of 10 with GdiSetBatchLimit() improves

performance even further. GDI and some drivers optimize convex polygons,

but will only optimize a single polygon drawn with either Polygon() or

PolyPolygon().

Because PolyPolygon() treats all edges as part of one big polygon, it also

draws every pixel to be filled exactly once; this may be a performance

advantage if a lot of overlapping polygons are drawn, because Polygon()

draws every pixel in each polygon only once, even where there is an

overlap.

PolyPolygon() considers all the polygons when applying the current fill

mode, as set by calling SetPolyFillMode(). Consequently, if any polygons

overlap, the result of one PolyPolygon() call may be different than the

result of the equivalent multiple Polygon() calls. If the polygons overlap

and the raster operation takes the destination pixel values into account,

or if you want the fill rule to be applied to overlapping areas, then it is

preferable to use PolyPolygon().

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: GdiDrw


Use Uppercase "K" for Keywords in Windows Help Files

PSS ID Number: Q64050

Authored 20-Jul-1990	Last modified 24-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

The standard keyword list must be defined by using capital "K" footnotes.

Lowercase "k" footnotes may not be used for defining either standard or

alternate keyword lists.

MORE INFORMATION

Using lowercase "k" footnotes can result in problems such as the following:

If your application calls WinHelp() using the HELP_KEY option for doing a

keyword search and you pass a LPSTR to a keyword defined in a footnote

attached to your topic, the Help system displays an "Invalid key word"

error message box. For example

   WinHelp(hWnd,cFileDir,HELP_KEY,(DWORD)(LPSTR)"help");

where

   hWnd     is the handle of the calling window.

   cFileDir is the directory path and filename of the .HLP file.

   "help"   is the keyword defined in the footnote section of the topic.

and the footnote section of the topic is as follows:

   k sample;help

Modifying the footnote for the topic to use an uppercase "K" solves the

problem.

   K sample;help

Additional reference words: 3.00 3.10 3.50 4.00 95 key word

KBCategory: kbtool

KBSubcategory: TlsHlp


Using #include Directive with Windows Resource Compiler

PSS ID Number: Q80945

Authored 20-Feb-1992	Last modified 23-Jun-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

The Windows Resource Compiler supports many standard C language

preprocessor directives such as "#define" to define symbolic

constants, and "#include" to include header and other resource files.

If an application developed for the Windows environment has more than

one resource, each resource can be maintained in a separate file.

Then, use the #include directive to direct the Resource Compiler to

build all the resources into one output file. Using this technique

prevents one resource file from becoming unmanageably large with an

overwhelming number of resources.

It is important to note that the Resource Compiler treats files with

the .C and .H extensions in a special manner. It assumes that a file

with one of these two extensions does not contain resources. When a

file has the .C or .H file extension, the Resource Compiler ignores

all lines in the file except for preprocessor directives (#define,

#include, and so forth). Therefore, a file that contains resources

that is included in another resource file should not have the .C or .H

file extension.

MORE INFORMATION

The following example demonstrates the implications of this situation.

The MSG.H file has the following contents:

   /*

    * This header file defines message IDs for strings in the

    * stringtable resource. All source files can use this header file

    * to reference specific strings.

    */

   #define STRING1   1

   #define STRING2   2

   #define STRING3   3

The STRTABLE.RC file has the following contents:

   /*

    * This file defines the stringtable resource contents for this

    * application. It should be included in the application's resource

    * file. It requires definitions from the MSG.H header file.

    */

   STRINGTABLE

      {

      STRING1, "This is string 1."

      STRING2, "This is string 2."

      STRING3, "This is string 3."

      }

The APP.RC file has the following contents:

   /*

    * This is the "main" resource definition file for this

    * application. Among other things, it includes the stringtable

    * resource definition from other header files.

    */

   RESOURCE 1 (MENU)

   RESOURCE 2 (RAW DATA)

   ...

   #include "MSG.H"

   #include "STRTABLE.RC"

The Resource Compiler treats both MSG.H and STRTABLE.RC as header

files. MSG.H does not include any resources; therefore, it can use the

standard .H file extension. However, because STRTABLE.RC includes a

resource (a STRINGTABLE), it cannot be named with a .C or .H file

extension.

Files that contain resources can have any legal MS-DOS file extension

other than .C and .H.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbtool

KBSubcategory: TlsRc


Using a Dialog Box as the Main Window of an Application

PSS ID Number: Q108936

Authored 20-Dec-1993	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

Dialog boxes might be used as the main window of an application for several

reasons. When an application uses a dialog box as the main window, the

following should be taken into consideration while designing such an

application:

 - The dialog box that acts as the main window of an application can be

   created without an owner.

 - If a modal dialog box is created as a main window,

   TranslateAccelerator() cannot be used.

 - The icon for the dialog box should be drawn manually when the dialog

   box is minimized.

MORE INFORMATION

You can create a modal or modeless dialog box as the main window of an

application. In doing so, there is no need to have an overlapped window

that acts as the owner of the dialog box. Memory for edit controls

created with the DS_LOCALEDIT flag set, and static controls, will come from

the heap represented by the hInstance passed to the CreateDialog() or

DialogBox() call.

When modal dialog boxes are chosen for this purpose, and accelerator keys

are defined in an application, Windows enters a modal message loop that

does not process accelerators, unless a WH_MSGFILTER hook is installed and

TranslateAccelerator() is called from the hook callback function.

One easy way to avoid this limitation is to create a modeless dialog box

and call TranslateAccelerator() from the main message loop.

The icon for a window is stored in its class information. Because a dialog

box is a window of global class that all applications in the system are

using, changing the icon for this application will change the icon for all

dialog boxes in the system. Below is one workaround for drawing the icon

manually when the dialog box is minimized:

Sample Code

-----------

BOOL WINAPI GenericDlgProc (HWND hwnd, UINT msg,

                            WPARAM wParam,  LPARAM lParam)

 {

   RECT rect ;

   switch (msg) {

       case WM_INITDIALOG:

        hIcon = LoadIcon(); // Load the icon that is to be displayed

                            // when minimized.

        return TRUE ;

       case WM_ERASEBKGND:

            if (IsIconic(hwnd) && hIcon) {

              SendMessage( hwnd, WM_ICONERASEBKGND, wParam, 0L );

              return TRUE;

             }

        break;

       case WM_QUERYDRAGICON:

            return (hIcon);

        case WM_PAINT: {

            PAINTSTRUCT ps;

            BeginPaint( hwnd, &ps );

            if (IsIconic(hwnd))   //*** If iconic, paint the icon.

            {

              if (hIcon) {

                //center the icon correctly..

                GetClientRect(hwnd, &rect) ;

                rect.left = (rect.right - GetSystemMetrics(SM_CXICON)) >> 1

;

               rect.top = (rect.bottom - GetSystemMetrics(SM_CYICON)) >> 1

;

                DrawIcon( ps.hdc, rect.left, rect.top, hIcon );

            }

            EndPaint( hwnd, &ps );

        }

        break;

    }

    return FALSE;

} //*** GenericDlgProc

The workaround described above assumes that the dialog box belongs to the

predefined dialog class. For private dialog box classes, there is no need

to manually draw the icon for the dialog box when it is minimized. You can

specify the icon while registering the dialog box class. Remember to set

the cbWndExtra field to DLGWINDOWEXTRA. When the dialog box is minimized,

the icon will be painted automatically.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95  DLGMAIN

KBCategory: kbprg

KBSubcategory: UsrDlgs


Using a Fixed-Pitch Font in a Dialog Box

PSS ID Number: Q77991

Authored 31-Oct-1991	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

To use a fixed-pitch font in a dialog box, during the processing of

the dialog box initialization message, send the WM_SETFONT message to

each control that will use the fixed font. The following code

demonstrates this process:

   case WM_INITDIALOG:

     SendDlgItemMessage(hDlg, ID_CONTROL, WM_SETFONT,

           GetStockObject(ANSI_FIXED_FONT), FALSE);

     /*

      * NOTE: This code will specify the fixed font only for the

      * control ID_CONTROL. To specify the fixed font for other

      * controls in the dialog box, additional calls to

      * SendDlgItemMessage() are required.

      */

     break;

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrDlgs


Using a Modeless Dialog Box with No Dialog Function

PSS ID Number: Q72136

Authored 15-May-1991	Last modified 06-Jun-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

When creating a modeless dialog box with the default dialog class, an

application normally passes a procedure-instance address of the dialog

function to the CreateDialog() function. This dialog function processes

messages such as WM_INITDIALOG and WM_COMMAND, returning TRUE or FALSE.

It is acceptable to create a modeless dialog box that uses NULL for the

lpDialogFunc parameter of CreateDialog(). This type of dialog box is useful

when the no controls or other input facilities are required. In this case,

using NULL simplifies the programming.

However, the dialog box must be closed through some means other than a push

button (for example, via a timer event).

NOTE: A modal dialog box that does not provide a means of closing itself

will hang its parent application because control will never return from the

DialogBox() function call.

If lpDialogFunc is NULL, no WM_INITDIALOG message will be sent, and

DefDlgProc() does not attempt to call a dialog function. Instead,

DefDlgProc() handles all messages for the dialog. The application that

created the modeless dialog must explicitly call DestroyWindow() to free

its system resources.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrDlgs


Using a Mouse with MEP Under Windows NT

PSS ID Number: Q83300

Authored 08-Apr-1992	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

The Microsoft Editor (MEP) included with the Win32 Software Development Kit

(SDK) can be used with a mouse to position the cursor.

By default, the mouse is not enabled for MEP. It is necessary to add the

switch "usemouse:yes" (without the quotation marks) to the TOOLS.INI file

under the [m mep] section. The TOOLS.INI file is a text file editable by

MEP or Notepad.

To change the position of the cursor, first position the mouse pointer on

the new location and then click the left mouse button.

Additional reference words: 3.10 3.50

KBCategory: kbtool

KBSubcategory: TlsMep


Using Built-In Printing Features from a Rich Edit Control

PSS ID Number: Q129860

Authored 08-May-1995	Last modified 23-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.51 and 4.0

 - Microsoft Win32s, version 1.3

SUMMARY

The Rich Edit control contains built-in printing features that can be used

to send formatted text to the printer with minimal effort from the

programmer.

MORE INFORMATION

Printing from a Rich Edit control involves the use of the standard printing

APIs and two Rich Edit control messages, EM_FORMATRANGE and EM_DISPLAYBAND.

The EM_FORMATRANGE message can be used by itself or used in combination

with the EM_DISPLAYBAND message. Included below at the end of this article

is a code sample which demonstrates the usage of these messages.

EM_FORMATRANGE

--------------

This message is used to format the text for the printer DC and can

optionally send the output to the printer.

The wParam parameter for this message is a Boolean value that indicates

whether or not the text should be rendered (printed) to the printer. A zero

value only formats the text, while a nonzero value formats the text and

renders it to the printer.

The lParam parameter for this message is a pointer to the FORMATRANGE

structure. This structure needs to be filled out before sending the message

to the control.

FORMATRANGE Members

-------------------

HDC   hdc - Contains the device context (DC) to render to if the wParam

parameter is nonzero. The output is actually sent to this DC.

HDC   hdcTarget - Contains the device context to format for, which is

usually the same as the hdc member but can be different. For example, if

you create a print preview module, the hdc member is the DC of the window

in which the output is viewed, and the hdcTarget member is the DC for the

printer.

RECT rc - Contains the area to render to. This member contains the

rectangle that the text is formatted to fit in, and subsequently printed

in. It also contains the margins, room for headers and footers, and so

forth. The rc.bottom member may be changed after the message is sent. If it

is changed, it must indicate the largest rectangle that can fit within the

bounds of the original rectangle and still contain the specified text

without printing partial lines. It may be necessary to reset this value

after each page is printed. These dimensions are given in TWIPS.

RECT  rcPage - Contains the entire area of the rendering device. This area

can be obtained using the GetDeviceCaps() function. These dimensions are

given in TWIPS.

CHARRANGE   chrg - Contains the range of characters to be printed. Set

chrg.cpMin to 0 and chrg.cpMax to -1 to print all characters.

The return value from EM_FORMATRANGE is the index of the first character on

the next page. If you are printing multiple pages, you should set

chrg.cpMin to this value before the next EM_FORMATRANGE message is sent.

When printing is complete, this message must be sent to the control with

wParam = 0 and lParam = NULL to free the information cache by the control.

EM_DISPLAYBAND

--------------

If you use 0 for the wParam parameter in the EM_FORMATRANGE message, then

you can use the EM_DISPLAYBAND message to send the output to the printer.

The wParam parameter for this message is not used and should be 0.

The lParam parameter for this message is a pointer to a RECT structure.

This RECT structure is the area to display to and is usually the same as

the rc member of the FORMATRANGE structure used in the EM_FORMATRANGE

message but can be different. For example, the rectangles are not the same

if you are printing on a certain portion of a page or built-in margins are

being used.

This message should only be used after a previous EM_FORMATRANGE message.

Sample Code

-----------

void Print(HDC hPrinterDC, HWND hRTFWnd)

   {

   FORMATRANGE fr;

   int         nHorizRes = GetDeviceCaps(hPrinterDC, HORZRES),

               nVertRes = GetDeviceCaps(hPrinterDC, VERTRES),

               nLogPixelsX = GetDeviceCaps(hPrinterDC, LOGPIXELSX),

               nLogPixelsY = GetDeviceCaps(hPrinterDC, LOGPIXELSY);

   LONG        lTextLength;   // Length of document.

   LONG        lTextPrinted;  // Amount of document printed.

   // Ensure the printer DC is in MM_TEXT mode.

   SetMapMode ( hPrinterDC, MM_TEXT );

   // Rendering to the same DC we are measuring.

   ZeroMemory(&fr, sizeof(fr));

   fr.hdc = fr.hdcTarget = hPrinterDC;

   // Set up the page.

   fr.rcPage.left     = fr.rcPage.top = 0;

   fr.rcPage.right    = (nHorizRes/nLogPixelsX) * 1440;

   fr.rcPage.bottom   = (nVertRes/nLogPixelsY) * 1440;

   // Set up 1" margins all around.

   fr.rc.left   = fr.rcPage.left + 1440;  // 1440 TWIPS = 1 inch.

   fr.rc.top    = fr.rcPage.top + 1440;

   fr.rc.right  = fr.rcPage.right - 1440;

   fr.rc.bottom = fr.rcPage.bottom - 1440;

   // Default the range of text to print as the entire document.

   fr.chrg.cpMin = 0;

   fr.chrg.cpMax = -1;

   // Set up the print job (standard printing stuff here).

   ZeroMemory(&di, sizeof(di));

   di.cbSize = sizeof(DOCINFO);

   if (*szFileName)

      di.lpszDocName = szFileName;

   else

      {

      di.lpszDocName = "(Untitled)";

      // Do not print to file.

      di.lpszOutput = NULL;

      }

   // Start the document.

   StartDoc(hPrinterDC, &di);

   // Find out real size of document in characters.

   lTextLength = SendMessage ( hRTFWnd, WM_GETTEXTLENGTH, 0, 0 );

   do

      {

      // Start the page.

      StartPage(hPrinterDC);

      // Print as much text as can fit on a page. The return value is the

      // index of the first character on the next page. Using TRUE for the

      // wParam parameter causes the text to be printed.

#ifdef USE_BANDING

      lTextPrinted = SendMessage(hRTFWnd,

                                 EM_FORMATRANGE,

                                 FALSE,

                                 (LPARAM)&fr);

      SendMessage(hRTFWnd, EM_DISPLAYBAND, 0, (LPARAM)&fr.rc);

#else

      lTextPrinted = SendMessage(hRTFWnd,

                                 EM_FORMATRANGE,

                                 TRUE,

                                 (LPARAM)&fr);

#endif

      // Print last page.

      EndPage(hPrinterDC);

      // If there is more text to print, adjust the range of characters to

      // start printing at the first character of the next page.

      if (lTextPrinted < lTextLength)

         {

         fr.chrg.cpMin = lTextPrinted;

         fr.chrg.cpMax = -1;

         }

      }

   while (lTextPrinted < lTextLength);

   // Tell the control to release cached information.

   SendMessage(hRTFWnd, EM_FORMATRANGE, 0, (LPARAM)NULL);

   EndDoc (hPrinterDC);

   }

Additional reference words: 1.30 4.00 95

KBCategory: kbprg kbui

KBSubcategory: UsrCtl W32s


Using cChildren Member of TV_ITEM to Add Speed & Use Less RAM

PSS ID Number: Q131278

Authored 07-Jun-1995	Last modified 23-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.51, 4.0

 - Microsoft Win32s version 1.3

SUMMARY

The cChildren member of the TV_ITEM structure is used to denote the number

of child items associated with a treeview item. When used correctly, the

cChildren member helps an application go faster and use less memory.

Applications may specify I_CHILDRENCALLBACK for this member, instead of

passing the actual number of child items. To retrieve the actual number of

child items associated with a treeview item, I_CHILDRENCALLBACK causes the

treeview to send a TVN_GETDISPINFO notification when the item needs to be

redrawn.

MORE INFORMATION

In a treeview with the TVS_HASBUTTONS style, specify a nonzero value for

the cChildren member to add the appropriate plus or minus (+/-) button (to

denote expand or collapse) to the left of the treeview item, without having

to insert each of the child items to the treeview. Specifying a zero value

indicates that the particular item does not have any child items associated

with it.

An application that does not use the cChildren member of the TV_ITEM

structure when inserting items to the treeview has to insert each of the

child items associated with that treeview item in order for the +/- button

to show up.

Using the cChildren member, therefore, helps to speed up an application

and reduce memory requirements by allowing the application to fill the tree

on demand.

Applications such as the Explorer, WinHelp, and RegEdit, which display huge

hierarchical structures, take advantage of this feature by initially

inserting only the visible items of the tree. The child items associated

with a particular item are not inserted until the user clicks the parent

item to expand it. At that point, the treeview's parent window receives a

TVN_ITEMEXPANDING notification message, and the application inserts the

child items for that parent item:

   // WM_NOTIFY message handler

   LRESULT MsgNotifyTreeView(HWND hwnd,

                             UINT uMessage,

                             WPARAM wparam,

                             LPARAM lparam)

   {

       LPNMHDR  lpnmhdr = (LPNMHDR)lparam;

       // Just before the parent item gets EXPANDED,

       // add the children.

       if (lpnmhdr->code == TVN_ITEMEXPANDING)

       {

           LPNM_TREEVIEW lpNMTreeView;

           TV_ITEM   tvi;

           lpNMTreeView = (LPNM_TREEVIEW)lparam;

           tvi = lpNMTreeView->itemNew;

           if ((tvi.lParam == PARENT_NODE) &&

               (lpNMTreeView->action == TVE_EXPAND))

           {

               // Fill in the TV_ITEM struct

               // and call TreeView_InsertItem() for each child item.

           }

        }

        return DefWindowProc(hwnd, uMessage, wparam, lparam);

   }

When the user clicks the same parent item to collapse it, the application

removes all the child items from the tree by using TreeView_Expand

(,,TVE_COLLAPSE | TVE_COLLAPSERESET). The TVN_ITEMEXPANDED notification

message is a good place to do this:

   // WM_NOTIFY message handler

   LRESULT MsgNotifyTreeView(HWND hwnd,

                             UINT uMessage,

                             WPARAM wparam,

                             LPARAM lparam)

   {

       LPNMHDR  lpnmhdr = (LPNMHDR)lparam;

       // Just before the parent item is COLLAPSED,

       // remove the children.

       if (lpnmhdr->code == TVN_ITEMEXPANDED)

       {

           LPNM_TREEVIEW lpNMTreeView;

           TV_ITEM       tvi2;

           lpNMTreeView = (LPNM_TREEVIEW)lparam;

           tvi2 = lpNMTreeView->itemNew;

           // Do a TVE_COLLAPSERESET on the parent to minimize memory use.

           if ((lpNMTreeView->action == TVE_COLLAPSE) &&

               (tvi2.lParam == PARENT_NODE))

           {

                TreeView_Expand (ghWndTreeView,

                                 tvi2.hItem,

                                 TVE_COLLAPSE | TVE_COLLAPSERESET);

           }

      }

      return DefWindowProc(hwnd, uMessage, wparam, lparam);

   }

Applications that dynamically change the number of child items associated

with a particular treeview item may specify I_CHILDRENCALLBACK for the

cChildren member of its TV_ITEM structure when it is inserted into the

tree. Thereafter, when that treeview item needs to be redrawn, the

treeview sends a TVN_GETDISPINFO to its parent window to retrieve the

actual number of child items and display the +/- button to the left of

the treeview item, as appropriate.

An application that uses I_CHILDRENCALLBACK may process the TVN_GETDISPINFO

notification as follows:

   // WM_NOTIFY message handler

   LRESULT MsgNotifyTreeView(HWND hwnd,

                             UINT uMessage,

                             WPARAM wparam,

                             LPARAM lparam)

   {

       LPNMHDR  lpnmhdr = (LPNMHDR)lparam;

       if (lpnmhdr->code == TVN_GETDISPINFO)

       {

          TV_DISPINFO FAR *lptvdi;

          lptvdi = (TV_DISPINFO FAR *)lparam;

       if ((lptvdi->item.mask & TVIF_CHILDREN) &&

(lptvdi->item.lParam == PARENT_NODE))

          lptvdi->item.cChildren = 1;

       }

      return DefWindowProc(hwnd, uMessage, wparam, lparam);

   }

Additional reference words: 4.00 95 Common Control performance speed up

KBCategory: kbprg kbcode

KBSubcategory: UsrCtl


Using Device Contexts Across Threads

PSS ID Number: Q94236

Authored 30-Dec-1992	Last modified 24-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   and 3.51

A window created with the CS_OWNDC style retains its device context (DC)

attributes across GetDC() calls.

However, the DC attributes are not retained if the GetDC() calls are called

from different threads. This is by design because DCs are thread-based. In

the Win32 user interface, if the calling thread is not the owner of the

window, then GetDC() returns a cache DC instead of the owned DC handle.

To save attributes across threads, one must create a routine to initialize

DC attributes, which is then called from threads not owning the given

window.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: GdiDc


Using Device-Independent Bitmaps and Palettes

PSS ID Number: Q72041

Authored 11-May-1991	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

The method Windows version 3.x uses to transfer colors from the color

table of a device-independent bitmap (DIB) to a device-dependent

bitmap (DDB) on a machine that supports palette operations depends on

the value of the wUsage parameter specified in calls to the

CreateDIBitmap or SetDIBits functions.

Specifying DIB_RGB_COLORS matches the colors in the DIB color table to

the logical palette associated with the device context (DC) listed in

the function call.

Specifying DIB_PAL_COLORS causes the entries in the DIB color table to

not be treated as RGB values; instead, they are treated as word

indexes into the logical palette associated with the DC listed in the

function call.

To create a device-dependent (displayable) bitmap from a DIB that

retains the same colors, follow these five steps:

1. Extract the colors from the DIB header.

2. Use the CreatePalette function to make a logical palette with

   those colors.

3. Use the SelectPalette function to select the logical palette

   into a device context.

4. Use the RealizePalette function to map the logical palette into

   the device context.

5. Call the CreateDIBitmap function using the device context that

   has the logical palette selected.

Because the CreateDIBitmap function creates a bitmap compatible with

the device, to create a device-dependent monochrome bitmap from a DIB,

call the CreateBitmap function with the desired width and height,

specifying one color plane and one bit per pixel. Then call the

SetDIBits function to render the image in the newly created

monochrome bitmap.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: GdiPal


Using Drag-Drop in an Edit Control or a Combo Box

PSS ID Number: Q86724

Authored 15-Jul-1992	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

In the Microsoft Windows environment, an application can register an

edit control or a combo box as a drag-drop client through the

DragAcceptFiles function. The application must also subclass the

control to process the WM_DROPFILES message that Windows sends when

the user drops a file.

MORE INFORMATION

The following seven steps demonstrate how to implement drag-drop in an

edit control. The procedure to implement drag-drop in a combo box is

identical.

1. Add SHELL.LIB to the list of libraries required to build the file.

2. Add the name of the subclass procedure (MyDragDropProc) to the

   EXPORTS section of the module definition (DEF) file.

3. Include the SHELLAPI.H file in the application's source code.

4. Declare the following procedure and variables:

      BOOL FAR PASCAL MyDragDropProc(HWND, unsigned, WORD, LONG);

      FARPROC lpfnDragDropProc, lpfnOldEditProc;

      char    szTemp64[64];

5. Add the following code to the initialization of the dialog box:

      case WM_INITDIALOG:

         // ... other code

         // ------- edit control section --------

         hWndTemp = GetDlgItem(hDlg, IDD_EDITCONTROL);

         DragAcceptFiles(hWndTemp, TRUE);

         // subclass the drag-drop edit control

         lpfnDragDropProc = MakeProcInstance(MyDragDropProc, hInst);

         if (lpfnDragDropProc)

            lpfnOldEditProc = SetWindowLong(hWndTemp, GWL_WNDPROC,

                  (DWORD)(FARPROC)lpfnDragDropProc);

         break;

6. Write a subclass window procedure for the edit control.

      BOOL FAR PASCAL MyDragDropProc(HWND hWnd, unsigned message,

                                     WORD wParam, LONG lParam)

      {

         int wFilesDropped;

         switch (message)

            {

         case WM_DROPFILES:

            // Retrieve number of files dropped

            // To retrieve all files, set iFile parameter

            // to -1 instead of 0

            wFilesDropped = DragQueryFile((HDROP)wParam, 0,

                  (LPSTR)szTemp64, 63);

            if (wFilesDropped)

               {

               // Parse the file path here, if desired

               SendMessage(hWnd, WM_SETTEXT, 0, (LPSTR)szTemp64);

               }

            else

               MessageBeep(0);

            DragFinish((HDROP)wParam);

            break;

         default:

            return CallWindowProc(lpfnOldEditProc, hWnd, message,

                  wParam, lParam);

            break;

         }

         return TRUE;

      }

7. After the completion of the dialog box procedure, free the edit

   control subclass procedure.

      if (lpfnDragDropProc)

         FreeProcInstance(lpfnDragDropProc);

Additional reference words: 3.10 3.50 3.51 4.00 95  combobox

KBCategory: kbprg

KBSubcategory: UsrDnd


Using DWL_USER to Access Extra Bytes in a Dialog Box

PSS ID Number: Q88358

Authored 24-Aug-1992	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

Windows extra bytes are used to store private information specific to

an instance of a window. For dialog boxes, these extra bytes are

already allocated by the dialog manager. The offset to the extra byte

location is called DWL_USER.

DWL_USER is the 8th byte offset of the dialog extra bytes. The

programmer has 4 bytes (a long) available from this offset for

personal use.

CAUTION: DO NOT use more than 4 bytes of these extra bytes, as the

rest of them are used by the dialog manager.

Example

-------

   DWORD dwNumber = 10;

            .

            .

            .

            .

   case WM_INITDIALOG:

           SetWindowLong(hWnd,DWL_USER,dwNumber); // Store value 10 at

                                                  // byte offset 8

           dwNumber = GetWindowLong(hWnd,DWL_USER); // Retrieve the value

NOTE: GetWindowWord and SetWindowWord could be used instead.

Additional reference words: 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrDlgs


Using ENTER Key from Edit Controls in a Dialog Box

PSS ID Number: Q102589

Authored 04-Aug-1993	Last modified 20-Jun-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

Windows-based applications often display data-entry dialog boxes to request

information from users. These dialog boxes may contain several edit

controls and two command (push) buttons, labeled OK and CANCEL. An example

of a data-entry dialog box is one that requests personal information, such

as social security number, address, identification (ID) number, date/time,

and so on, from users. Each of these items is entered into an edit control.

By default, the TAB key is used in a dialog box to shift focus between

edit controls. As a common user-interface, however, one could also use

the ENTER (RETURN) key to move between the edit controls (for example,

after the user enters a piece of information, pressing ENTER moves the

focus to the next field).

There are a few ways to enable the use of the ENTER key to move

between edit controls. One method is to make use of WM_COMMAND and the

notification messages that come with it in the dialog box for edit

controls and buttons. Another method involves subclassing the edit

controls. A third involves using App Studio and Class Wizard and creating a

new dialog box member function.

MORE INFORMATION

Method I: (WM_COMMAND)

----------------------

This method is based on the following behavior of dialog boxes (Dialog

Manager) and focus handling in Windows.

If a dialog box or one of its controls currently has the input focus,

then pressing the ENTER key causes Windows to send a WM_COMMAND

message with the idItem (wParam) parameter set to the ID of the

default command button. If the dialog box does not have a default

command button, then the idItem parameter is set to IDOK by default.

When an application receives the WM_COMMAND message with idItem set to

the ID of the default command button, the focus remains with the

control that had the focus before the ENTER key was pressed. Calling

GetFocus() at this point returns the handle of the control that had

the focus before the ENTER key was pressed. The application can check

this control handle and determine whether it belongs to any of the

edit controls in the dialog box. If it does, then the user was

entering data into one of the edit controls and after doing so,

pressed ENTER. At this point, the application can send the

WM_NEXTDLGCTL message to the dialog box to move the focus to the next

control.

However, if the focus was with one of the command buttons (CANCEL or

OK), then GetFocus() returns a button control handle, at which point

one can dismiss the dialog box. The pseudo code for this logic

resembles the following in the application's dialog box procedure:

     case WM_COMMAND:

     if(wParam=IDOFDEFBUTTON || IDOK) {

          // User has hit the ENTER key.

          hwndTest = GetFocus() ;

          retVal = TesthWnd(hWndTest) ;

          //Where retVal is a boolean variable that indicates whether

        //the hwndTest is the handle of one of the edit controls.

          if(hwndTest) {

         //Focus is with an edit control, so do not close the dialog.

            //Move focus to the next control in the dialog.

         PostMessage(hDlg, WM_NEXTDLGCTL, 0, 0L) ;

         return TRUE ;

          }

          else {

            //Focus is with the default button, so close the dialog.

            EndDialog(hDlg, TRUE) ;

            return FALSE ;

          }

        }

     break ;

Method II

---------

This method involves subclassing/superclassing the edit control in the

dialog box. Once the edit controls are subclassed or superclassed, all

keyboard input is sent the subclass/superclass procedure of the edit

control that currently has input focus, regardless of whether or not

the dialog box has a default command button. The application can trap

the key down (or char) messages, look for the ENTER key, and do the

processing accordingly. The following is a sample subclass procedure

that looks for the ENTER key:

//*-------------------------------------------------------------------

//| Title:

//|     SubClassProc

//|

//| Parameters:

//|     hWnd            - Handle to the message's destination window

//|     wMessage        - Message number of the current message

//|     wParam          - Additional info associated with the message

//|     lParam          - Additional info associated with the message

//|

//| Purpose:

//|     This is the window procedure used to subclass the edit control.

//*---------------------------------------------------------------------

long FAR PASCAL SubProc(HWND hWnd, WORD wMessage,WORD wParam,LONG lParam)

{

    switch (wMessage)

     {

          case WM_GETDLGCODE:

            return (DLGC_WANTALLKEYS |

                    CallWindowProc(lpOldProc, hWnd, wMessage,

                                   wParam, lParam));

          case WM_CHAR:

          //Process this message to avoid message beeps.

         if ((wParam == VK_RETURN) || (wParam == VK_TAB))

           return 0;

            else

           return (CallWindowProc(lpOldProc, hWnd,

                                     wMessage, wParam, lParam));

       case WM_KEYDOWN:

            if ((wParam == VK_RETURN) || (wParam == VK_TAB)) {

              PostMessage (ghDlg, WM_NEXTDLGCTL, 0, 0L);

              return FALSE;

            }

         return (CallWindowProc(lpOldProc, hWnd, wMessage,

                                   wParam, lParam));

         break ;

       default:

            break;

     } /* end switch */

Method 3

--------

This method involves using App Studio and ClassWizard and creating a new

dialog box member function.

This method will allow a user to press the ENTER key and have the focus

advance to the next edit control. If the focus is currently on the last

edit control in the dialog box, the focus will advance to the first edit

control.

First, use App Studio to change the ID of the OK button of the dialog box.

The default behavior of App Studio is to give the OK button the ID IDOK.

The OK button's ID should be changed to another value, such as IDC_OK.

Also, change the properties of the OK button so that it is not a default

pushbutton.

Next, use ClassWizard to create a new dialog box member funciton. Name the

new member function something like OnClickedOK. This function should be

tied to the BN_CLICKED message from the IDC_OK control.

Once this is done, write the body of the OnClickedOK function. You should

put the code that you would normally put in the OnOK function into the new

OnClickedOK function, including a class's OnOK function.

Add the following prototype to the header file for the dialog box:

   protected:

      virtual void OnOK();

Add an OnOK function to the dialog box and code is as demonstrated below:

void CMyDialog::OnOK()

{

     CWnd* pwndCtrl = GetFocus();

     CWnd* pwndCtrlNext = pwndCtrl;

     int ctrl_ID = pwndCtrl->GetDlgCtrlID();

     switch (ctrl_ID) {

         case IDC_EDIT1:

             pwndCtrlNext = GetDlgItem(IDC_EDIT2);

             break;

         case IDC_EDIT2:

             pwndCtrlNext = GetDlgItem(IDC_EDIT3);

             break;

         case IDC_EDIT3:

             pwndCtrlNext = GetDlgItem(IDC_EDIT4);

             break;

         case IDC_EDIT4:

             pwndCtrlNext = GetDlgItem(IDC_EDIT1);

             break;

         case IDOK:

             CDialog::OnOK();

             break;

         default:

             break;

     }

     pwndCtrlNext->SetFoucs();

}

Additional reference words: 3.10 3.50 3.51 4.00 95  push RETURN keydown

KBCategory: kbprg

KBSubcategory: UsrDlgs


Using Extra Fields in Window Class Structure

PSS ID Number: Q10841

Authored 01-Dec-1987	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

In order to generate several child windows of the same class, each having

its own set of static variables and independent of the sets of the

variables in the sibling windows, you need to use the cbWndExtra field in

WNDCLASS, the window-class data structure, when registering a window; then,

use SetWindowWord() (or Long) and GetWindowWord() (or Long). These

functions will either get or set additional information about the window

identified by hWnd.

Use positive offsets as indexes to access any additional bytes that were

allocated when the window class structure was created, starting at zero for

the first byte of the extra space. Similarly, if you want to refer to bytes

already defined by Windows within the structure, use offsets defined with

the GWW and GWL prefixes.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: UsrCls


Using FileOpen Common Dialog w/ OFN_ALLOWMULTIPLESELECT Style

PSS ID Number: Q130761

Authored 25-May-1995	Last modified 22-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) version 4.0

SUMMARY

This article covers the format of file names returned by the FileOpen

common dialog with the OFN_ALLOWMULTIPLESELECT style.

The FileOpen common dialog can be used to specify the location (drive and

directory) and name of a file or a set of files. One of the flags needed to

provide mulitple-file selection from the FileOpen common dialog is the

OFN_ALLOWMULTIPLESELECT flag. When this flag is used, and the user makes a

valid selection, the file or files chosen by the user are returned in the

lpstrFile member of the OPENFILENAME structure. The format of the string

returned in the lpstrFile member depends on how many files (single or

multiple) the user selected. This article assumes that the OFN_EXPLORER

Style is set for the file open dialog.

MORE INFORMATION

If multiple files were selected, the string is of this form:

   Drive: \Directory Name\0FileName 1\0FileName 2\0FileName n\0\0.

The Directory Name is listed first. Then each file that was selected is

listed with a terminating NULL Character, except for the last filename,

which is terminated with two NULL characters. The two NULL characters

signal the end of the string.

If a single file was selected, the string is of this form:

   Drive: \Directory Name\FileName\0\0.

The Directory Name in this case is not terminated by a NULL character, and

the file name is terminated with two NULL characters.

Applications must parse the string returned in the lsptrFile member. In

doing so, they should make provisions in the parsing code to have a case

where the user can make a single selection (even though the

OFN_ALLOWMULTIPLESELECT flag is set) or multiple selections.

NOTE: When using OFN_ALLOWMULTIPLESELECT under Windows 95, you need to use

the OFN_EXPLORER flag to get the explorer style dialog and NULL terminated

strings. If you don't use OFN_EXPLORER with OFN_ALLOWMULTIPLESELECT, you

get the old style dialog and space-delimited strings.

Additional reference words: 4.00

KBCategory: kbprg

KBSubcategory: UsrCmnDlg


Using GDI-Synthesized Italic Fonts

PSS ID Number: Q74467

Authored 21-Jul-1991	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

In the Microsoft Windows graphical environment, when an application

uses an italic font synthesized by the graphics device interface

(GDI), each character and its whole character cell are "sheared," or

slanted, to the right, which can cause some unexpected results.

MORE INFORMATION

The capital H in the example below illustrates how GDI synthesizes an

italic font:

   ..........                   ..........

   .        .                  .        .

   . |    | .                 . |    | .

   . |    | .                 . |    | .

   . |----| . italicizes to  . |----| .

   . |    | .               . |    | .

   . |    | .               . |    | .

   .        .              .        .

   ..........              ..........

Note two items in this case:

1. If the text background color is changed so that it does not match

   the window background color, the text background color occupies the

   sheared character cell (in other words, it is also slanted). Gaps

   occur in the background where normal text is adjacent to italic

   text.

2. The italic character is farther to the right in relation to the

   lower-left corner of the character cell than is the normal

   character. Therefore, if normal and italic text start at the same x

   coordinate on different lines, the italic text appears farther to

   the right.

To determine the number of units by which the character cell is

sheared, call the GetTextMetrics function to fill a TEXTMETRIC data

structure with information about the font. The tmOverhang member

describes the amount of shear.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: GdiFnt


Using GetDIBits() for Retrieving Bitmap Information

PSS ID Number: Q85846

Authored 22-Jun-1992	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

When saving a bitmap in .DIB file format, the GDI function is used to

retrieve the bitmap information. The general use of this function and

the techniques for saving a bitmap in .DIB format are largely

unchanged; however, this article provides more details on the use of

the Win32 API version of the GetDIBits() function.

MORE INFORMATION

The function can be used to retrieve the following information:

 - Data in the BitmapInfoHeader (no color table and no bits)

 - Data in the BitmapInfoHeader and the color table (no bits)

 - All the data (BitmapInfoHeader, color table, and the bits)

The fifth and the sixth parameters of the function are used to tell

the graphics engine exactly what the application wants it to return.

If the fifth parameter is NULL, then no bits will be returned. If the

biBitCount is 0 (zero) in the sixth parameter, then no color table

will be returned. In addition, the biSize field of the

BitmapInfoHeader must be set to either the size of BitmapInfoHeader or

BitmapCoreHeader for the function to work properly.

Refer to the SAVEBMP.C file in the MANDEL sample for details. This sample

is included with the Win32 SDK.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: GdiBmp


Using GetForegroundWindow() When Desktop Is Not Active

PSS ID Number: Q118624

Authored 25-Jul-1994	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

GetForegroundWindow() is documented to return the handle of the foreground

window, that is, the window that the user is currently working with. The

proper handle is returned when the desktop that the application is running

on is active; however, when another desktop is active,

GetForegroundWindow() returns NULL.

This is expected behavior. There is no way to get the active window in your

own desktop while another desktop is active.

The application desktop is one desktop. Other desktops include the logon

and screen saver desktops. If GetForegroundWindow() returned a handle to

the logon dialog box, it would be possible to create an application that

could get user passwords. This would violate Windows NT security.

For this reason, it is not possible to create screen savers that melt

or drop out.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: UsrWndw


Using GetUpdateRgn()

PSS ID Number: Q99047

Authored 20-May-1993	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

The documentation provided with the Microsoft Windows Software

Development Kit (SDK) for Microsoft Windows version 3.1 does not

address all the issues surrounding the use of the GetUpdateRgn()

function. This article complements the documentation of

GetUpdateRgn().

MORE INFORMATION

The handle to the region (hRgn) does not have to be selected into a

device context (DC) to be able to use it with GetUpdateRgn(). Even if

the hRgn is selected as the clipping region for a DC, Windows only

makes a copy of the hRgn for the hDC instead of using the hRgn

directly.

When hRgn is used with GetUpdateRgn(), Windows will ignore any

existing region in hRgn. It will replace any existing region with the

current update region of the window.

Calling GetUpdateRgn() soon after BeginPaint() always yields an empty

region because BeginPaint() validates the update region.

A typical Windows query function (functions that typically begin with

Get and Is) does not initiate any action. GetUpdateRgn() is not a

typical function in this respect. The third parameter, fErase, works

as advertised to initiate a repaint on request.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrPnt


Using GMEM_DDESHARE in Win32 Programming

PSS ID Number: Q99114

Authored 23-May-1993	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

The GMEM_DDESHARE flag remains a legitimate value for GlobalAlloc(). This

flag can be used to indicate that the memory will be used for one of the

following so that the system can optimize the allocation for these special

needs:

   DDE

   OLE 1.0

   Clipboard operations

However, GlobalAlloc( GMEM_DDESHARE, ...) cannot be used to allocate a

block of memory that can be shared between processes. This flag was never

intended for this purpose, even under Windows versions 3.0 and 3.1 (3.x).

GlobalAlloc( GMEM_DDESHARE, ...) works in this case because all Windows-

based applications share the same address space; this is not the case under

Windows NT.

All allocations of global shared memory can be used within the process that

they are allocated in, but another mechanism is required to share memory

between processes.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: BseMm


Using Graphics Within a Help File

PSS ID Number: Q90291

Authored 12-Oct-1992	Last modified 25-May-1995

---

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows version 3.1

 - Microsoft Win32 SDK, versions 3.51 and 4.0

---

SUMMARY

This article explains how to use graphics in a Help file with both the help

compiler 3.1 (HC30.EXE, HC31.EXE, and HCP.EXE) and the help compiler 4.0

(HCW.EXE).

MORE INFORMATION

TYPES OF GRAPHICS

-----------------

With the Help Compiler, four types of graphics can be displayed within help

topics: bitmaps, metafiles, segmented hypergraphics, and multiple

resolution bitmaps. With HC30 and HC31, these graphics are limited to 16

colors but it is possible to use embedded windows to create a 256-color

bitmap. HCW is capable of displaying 16 million colors.

The following section discusses the details of the graphics formats listed

above, and provides details on their advantages and disadvantages.

Bitmaps

-------

A bitmap is an image that is described by a matrix of memory bits that,

when copied to a device, define the color and pattern of a corresponding

matrix of pixels on the display surface of the device. The advantage to

using a bitmap is that drawing a bitmap is very fast. The disadvantage is

that the size of a bitmap is very large. Bitmaps can be created with a

graphics editor, such as Paintbrush.

Metafiles

---------

A metafile is a collection of GDI commands that creates desired text or

images. There are two advantages to using metafiles: the size of the

metafile is small, and metafiles are less device-dependent than bitmaps.

The disadvantage of using a metafile is that it takes a long time to draw

one.

Segmented Hypergraphics

-----------------------

A segmented hypergraphic is a graphic that has hot spots defined in various

regions of the graphic. Clicking hot spots either executes a macro or jumps

to a context string. To make a segmented hypergraphic, use the segmented

hypergraphic (hot spot) editor (SHED.EXE) included with the Windows 3.1

SDK.

Multiple Resolution Bitmaps

---------------------------

A multiple resolution bitmap is a single bitmap file that contains one or

more bitmaps that have been marked for use with specific displays. The

advantages of multiple resolution bitmaps are:

1. Bitmaps are prevented from appearing too big or too small on

   different resolutions.

2. Bitmaps are prevented from looking stretched or compressed from

   display to display.

3. Colors are mapped correctly on different displays.

The disadvantage of multiple resolution bitmaps is that the files are

large. multiple resolution bitmaps can be created from bitmap files

with the multiple resolution bitmap compiler, MRBC.

PLACING GRAPHICS

----------------

Direct Pasting

--------------

Bitmaps and metafiles can be pasted directly from the clipboard into

an RTF source file. This allows the help author to see what the topic

will look like while it is being edited. There are several

disadvantages to this method. The first disadvantage only applies to HC30

and HC31. It is that any graphic pasted directly into a topic is limited to

64K. This is the result of the help compiler's 64K per paragraph limit when

processing RTF source files. The second disadvantage applies to all the

help compilers. It is size. If the same graphic is used multiple times

within the same source file, then a copy of the graphic is made each time

it is placed within the source.

By Reference

------------

All of the graphics can be placed "by reference." To insert a graphic

by reference, the help author must type {bm? graphic.ext} where bm? is

bml, bmr, or bmc and graphic.ext is the name of the graphic file that

the author wants to have placed in the help topic. The bml command is

used for a left-justified graphic, the bmr command is used for a right

justified graphic, and the bmc command is used for a character

justified graphic (that is, the graphic is inserted into the paragraph

as if it were a character).

One of the advantages of placing a graphic by reference is that it

lifts the 64K limit on a graphic. Also, a graphic placed by reference

is actually just a "pointer" to the real graphic. Therefore, if the

same graphic is used multiple times, it is only "stored" once within

the .HLP file.

The disadvantage of placing graphics by reference is that the help

author does not see how the topic will appear while in the RTF editor.

The bitmap files inserted by reference must be found in the directory

specified by either the ROOT or BMROOT settings in the [OPTIONS]

section of the help project file. If the bitmap is not located in one

of these directories, then the file must be listed in the [BITMAPS]

section of the project file, so the help compiler can locate the

bitmap.

Hot Spots and Pop Ups

---------------------

When placing a graphic into an RTF source file, it can be turned into

a hot spot or pop up, similar to other text. Just select the graphic

and turn on the double or single underline attribute followed

immediately by the hidden text for the context string or macro.

Additional reference words: 3.10 4.00 95  WinHelp

KBCategory: kbtool

KBSubcategory: TlsHlp


Using Network DDE Under Win32s

PSS ID Number: Q125475

Authored 29-Jan-1995	Last modified 17-Mar-1995

The information in this article applies to:

 - Microsoft Win32s, version 1.2

Network Dynamic Data Exchange (NetDDE) has limited support in Win32s. You

can use DDE across the network, however the NDde APIs are not supported

under Win32s and will not be supported in the future.

The NDde APIs, such as NDdeShareAdd(), are used to create the NetDDE

shares, not for the actual communication. Therefore, to use NetDDE with

Win32s, manually create the shares with the DDESHARE utility included in

the Windows for Workgroups Resource Kit or by thunking to the 16-bit NDde

APIs. Then communicate through DDE or DDEML.

Additional reference words: 1.20

KBCategory: kbprg kbnetwork

KBSubcategory: W32s


Using NTFS Alternate Data Streams

PSS ID Number: Q105763

Authored 24-Oct-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

SUMMARY

The documentation for the NTFS file system states that NTFS supports

multiple streams of data; however, the documentation does not address

the syntax for the streams themselves.

The Windows NT Resource Kit documents the stream syntax as follows:

   filename:stream

Alternate data streams are strictly a feature of the NTFS file system

and may not be supported in future file systems. However, NTFS will be

supported in future versions of Windows NT.

Future file systems will support a model based on OLE 2.0 structured

storage (IStream and IStorage). By using OLE 2.0, an application can

support multiple streams on any file system and all supported operating

systems (Windows, Macintosh, Windows NT, and Win32s), not just Windows NT.

MORE INFORMATION

The following sample code demonstrates NTFS streams:

#include <windows.h>

#include <stdio.h>

void main( )

{

   HANDLE hFile, hStream;

   DWORD dwRet;

   hFile = CreateFile( "testfile",

                    GENERIC_WRITE,

                 FILE_SHARE_WRITE,

                             NULL,

                      OPEN_ALWAYS,

                                0,

                             NULL );

   if( hFile == INVALID_HANDLE_VALUE )

      printf( "Cannot open testfile\n" );

   else

      WriteFile( hFile, "This is testfile", 16, &dwRet, NULL );

   hStream = CreateFile( "testfile:stream",

                             GENERIC_WRITE,

                          FILE_SHARE_WRITE,

                                      NULL,

                               OPEN_ALWAYS,

                                         0,

                                      NULL );

   if( hStream == INVALID_HANDLE_VALUE )

      printf( "Cannot open testfile:stream\n" );

   else

      WriteFile( hStream, "This is testfile:stream", 23, &dwRet, NULL );

}

The file size obtained in a directory listing is 16, because you are

looking only at "testfile", and therefore

   type testfile

produces the following:

   This is testfile

However

   type testfile:stream

produces the following:

   The filename syntax is incorrect

In order to view what is in testfile:stream, use:

   more < testfile:stream

   -or-

   mep testfile:stream

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseFileio


Using One IsDialogMessage() Call for Many Modeless Dialogs

PSS ID Number: Q71450

Authored 18-Apr-1991	Last modified 18-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

In the Windows environment, an application can implement more than one

modeless dialog box with a single call to the IsDialogMessage() function.

This can be done by using the following three-step method:

1. Maintain the window handle to the currently active modeless dialog

   box in a global variable.

2. Pass the global variable as the hDlg parameter to the

   IsDialogMessage() function, which is normally called from the

   application's main message loop.

3. Update the global variable whenever a modeless dialog box's window

   procedure receives a WM_ACTIVATE message, as follows:

   - If the dialog is losing activation (wParam is 0), set the global

     variable to NULL.

   - If the dialog is becoming active (wParam is 1 or 2), set the

     global variable to the dialog's window handle.

MORE INFORMATION

The information below demonstrates how to implement this technique.

1. Declare a global variable for the modeless dialog box's window

   handle.

   HWND hDlgCurrent = NULL;

2. In the application's main message loop, add a call to the

   IsDialogMessage() function.

   while (GetMessage(&msg, NULL, 0, 0))

      {

      if (NULL == hDlgCurrent || !IsDialogMessage(hDlgCurrent, &msg))

         {

         TranslateMessage(&msg);

         DispatchMessage(&msg);

         }

      }

3. In the modeless dialog box's window procedure, process the

   WM_ACTIVATE message.

   switch (message)

      {

      case WM_ACTIVATE:

         if (0 == wParam)             // becoming inactive

            hDlgCurrent = NULL;

         else                         // becoming active

            hDlgCurrent = hDlg;

         return FALSE;

      }

For more information on the WM_ACTIVATE message, see page 6-47 in

"Microsoft Windows Software Development Kit Reference Volume 1" for the

Windows SDK version 3.0 and page 87 of "Programmer's Reference, Volume 3:

Messages, Structures, and Macros" for the Windows SDK version 3.1.

For details on the IsDialogMessage() function, see page 4-266 in "Windows

Software Development Kit Reference Volume 1" for the Windows SDK version

3.0 and page 553 of "Programmer's Reference, Volume 2: Functions" for the

Windows SDK version 3.1.

For details on using a modeless dialog box in an application for the

Windows environment, see Chapter 10 of "Programming Windows," second

edition, (Microsoft Press) written by Charles Petzold.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrDlgs


Using Printer Escapes w/PS Printers on Windows NT & Win32s

PSS ID Number: Q124135

Authored 19-Dec-1994	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32s versions 1.1, 1.15, 1.15a, and 1.2

 - Microsoft Win32 Software Development Kit (SDK) versions 3.1 and 3.5

SUMMARY

To identify and print to PostScript printers from a Win32-based application

under Windows NT and under Win32s, you need to special-case your code. This

is because the printer drivers respond to different Printer Escapes under

Windows NT and Windows/Win32s.

This article discusses how to identify and print to PostScript printers on

both Windows NT and Win32s.

MORE INFORMATION

Identification

--------------

To identify the printer as a PostScript printer, use this code:

   int gPrCode = 0;  // Set according to platform.

   if( Win32s ) // Using the Win16 driver.

   {

      gPrCode = PASSTHROUGH;

      if((Escape(printerIC, GETTECHNOLOGY, NULL, NULL, (LPSTR)szTech) &&

         !lstrcmp(szTech, "PostScript")) &&

         Escape(printerIC, QUERYESCSUPPORT, sizeof(int),

            (LPSTR)gPrCode, NULL )

      {

      // The printer is PostScript.

         ...

      }

   }

   else // Using Win32 driver under Windows NT.

   {

      gPrCode = POSTSCRIPT_PASSTHROUGH; // Fails with Win16 driver

      if( Escape(printerIC, QUERYESCSUPPORT, sizeof(int), (LPSTR)gPrCode,

          NULL))

      {

      // The printer is PostScript.

         ...

      }

   }

Printing

--------

To send PostScript data to the printer on either platform, use this code:

// Assuming a buffer, szPSBuf, of max size MAX_PSBUF containing

// nPSData bytes of PostScript data.

   char szBuf[MAX_PSBUF+sizeof(short)];

// Store length in buffer.

   *((short *)szBuf) = nPSData;

// Store data in buffer.

   memcpy( (char *)szBuf + sizeof(short), szPSBuf, nPSData );

// Note that gPrCode (set when identifying the printer) depends on

// the platform.

   Escape( printerDC, gPrCode, (int) nPSData, szBuf, NULL );

However, your output may appear scaled or translated incorrectly or data

may be transformed off the page under Win32s.

The origin and scale for Windows printer drivers is not the PostScript

default (bottom left/72 dpi) but is instead at the upper left and at the

device scale(300 dpi). Therefore, before sending data to the printer, you

may need to send a couple of PostScript commands to scale or translate the

matrix. For example, for scaling, send the following escape to scale the

PostScript transform to 72 dpi:

   xres = GetDeviceCaps(printerDC, LOGPIXELSX);

   yres = GetDeviceCaps(printerDC, LOGPIXELSY);

// Two leading spaces for the following operation.

   wsprintf(szBuf, "  %d 72 div %d 72 div scale\n", xres, yres);

// Put actual size into buffer

   *((short *)szBuf) = strlen(szBuf)-2;

   Escape( printerDC, gPrCode, strlen(szBuf)-2, szBuf, NULL );

Additional reference words: 1.10 1.20 3.10 3.50

KBCategory: kbprg kbprint kbcode

KBSubcategory: GdiPrn W32s


Using Private Templates with Common Dialogs

PSS ID Number: Q74609

Authored 24-Jul-1991	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK, version 3.5

SUMMARY

An application which uses the common dialog library (COMMDLG.DLL) can

provide its own dialog resource template to be used instead of the standard

template. In this way, the application can include private dialog items

specific to its needs without losing the benefits of using the COMMDLG's

dialog handling.

MORE INFORMATION

Each common dialog data structure contains an lpTemplateName element. (Note

that the Print Dialog structure contains two such elements, each with a

distinct name -- see specifics of PrintDlg for details.) This element

points to a null-terminated string that names the dialog box template

resource to be substituted for the standard dialog template. If the dialog

resource is numbered, the application can use the MAKEINTRESOURCE macro to

convert the number into a pointer to a string. Alternatively, the

application can choose to pass a handle to a preloaded dialog template. The

Flags element of the dialog data structure must be set to indicate which

method is being used.

After loading the application's dialog template, the common dialog DLL

initializes the dialog items as it would for the standard template.

This leads to an important point: all dialog items in the standard

template must also exist in the application's private template. Note

that the items do not have to be enabled or visible -- they just have

to exist.

Once the DLL has finished handling the WM_INITDIALOG message, it

passes that message on to the application's dialog hook function. The

hook function handles WM_INITDIALOG by initializing the application's

private dialog items. It can also disable and hide any items from the

standard template that the application does not want to use.

The hook function should process messages and notifications concerning

the private dialog items.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: UsrCmnDlg


Using Quoted Strings with Profile String Functions

PSS ID Number: Q69752

Authored 28-Feb-1991	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.1 and 3.0

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

Microsoft Windows provides profile files which are a mechanism for an

application to store configuration about itself. The WIN.INI file is

the system profile file in which Windows stores configuration

information about itself. In versions of Windows prior to version 3.0,

applications also stored configuration information in the WIN.INI

file. Windows 3.0 introduced private profile files, which can store

application-specific information.

An application can retrieve information from a profile file by calling

the GetProfileString or GetPrivateProfileString function. If the

profile file associates the specified lpKeyName value with a string

that is delimited by quotation marks, Windows discards the quotation

marks when it copies the associated string into the application-

provided buffer.

For example, if the following entry appears in the profile file:

   [application name]           [application name]

   keyname = 'string'     or     keyname = "string"

The GetPrivateProfileString and GetProfileString functions read the

string value and discard the quotation marks.

MORE INFORMATION

This behavior allows spaces to be put into a string. For example, the

profile entry

   keyname = string

returns the string without a leading space, whereas

   keyname = ' string'     or     keyname = " string"

returns the string with a leading space.

Doubling quotation marks includes quotation marks in the string. For

example:

   keyname = ''string''    or     keyname = ""string""

returns the string with its quotation marks -- 'string' or "string".

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrIni


Using ReadFile() and WriteFile() on Socket Descriptors

PSS ID Number: Q104536

Authored 22-Sep-1993	Last modified 21-Feb-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   versions 3.1 and 3.5

Socket handles for Windows NT sockets are object handles. For example, you

can pass a socket handle in the appropriate state to the ReadFile(),

ReadFileEx(), WriteFile(), or WriteFileEx() application programming

interface (API) to receive and send data. The socket descriptor passed to

the file APIs must be a connected, TCP descriptor.

NOTE: There is no way to specify send and receive out-of-band data.

To use a Windows Sockets handle, the ReadFile() and WriteFile() APIs must

use asynchronous access. That is, you must specify the overlapped parameter

in the call to ReadFile() and WriteFile(). This will allow you to be

notified when the I/O has completed.

This functionality is based upon the implementation of Windows Sockets and

may not be available to all implementations. For example, although this

works in the Win32 subsystem, it is not supported under Win32s.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: NtwkWinsock


Using RLE Bitmaps for Animation Applications In Windows

PSS ID Number: Q75214

Authored 14-Aug-1991	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

Animation that uses a "brute-force" animation scheme, displaying

successive complete bitmaps, can be slow and choppy. The alternative

approach, displaying an initial frame and then modifying the elements

that change, can save a great deal of time, memory, and disk space.

MORE INFORMATION

Animation applications typically use a very simple algorithm to

display a sequence of bitmaps, or frames, one right over another, on

the same display surface. When the application stores an entire frame

in the device-independent bitmap (DIB) format, it suffers from three

particular bottlenecks:

1. With large frames or long sequences, the storage file becomes quite

   large.

2. Loading an entire sequence requires a large amount of memory.

3. Available Windows functions, such as BitBlt or SetDIBitsToDevice,

   may be too slow to animate the sequence smoothly.

For an animation sequence of bitmaps with a consistent set of colors,

preprocessing the animation sequence and storing it in the run-length-

encoded (RLE) format enables an application to run faster with a

smaller storage file and memory requirement. Note that this RLE file

is different from an RLE compressed DIB. This RLE format consists of

several frames that are compressed according to the differences

between frames. This process is straightforward and consists of five

steps:

1. Select the first frame in the sequence and store it in the DIB

   format.

2. Compare the DIB bitmaps of consecutive frames. Due to the nature of

   animation sequences, the number of differences is often quite small

   compared to the size of the entire frame.

3. Encode the set of changed pixels into RLE format. The encoded frame

   will contain information only on the pixels that change, the delta

   records will skip the unchanged pixels. The RLE bitmap is stored

   instead of the latter frame. For example, the RLE-encoded

   difference between the first and second frames is stored as the

   second frame.

4. When the entire sequence is preprocessed, bring each frame into the

   system as a BITMAPINFO structure and stream of bits. Since only the

   first frame is in the DIB format, the memory requirement is quite

   low. Moreover, frames that contain an identical set of colors can

   share the BITMAPINFO structure, only the biCompression and

   biSizeImage fields must be changed.

5. At display time, load the first frame as a DIB. Then use the

   SetDIBitsToDevice function to display subsequent frames in the

   sequence. Because this function requires much less information,

   the sequence can be animated much more quickly and smoothly.

Additional reference words: 3.00 3.10 3.50 4.00 95  rle

KBCategory: kbprg

KBSubcategory: GdiBmp


Using RPC Callback Functions

PSS ID Number: Q96781

Authored 25-Mar-1993	Last modified 26-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

The standard remote procedure call (RPC) model has a server containing one

or more exported function calls, and a client, which calls the server's

exported functions. However, Microsoft's implementation of RPC defines

callbacks as a special interface definition language (IDL) attribute

allowing a server to call a client function.

Callbacks can be used only in the context of a server call. Thus, a server

may call a client's callback function only when the server is performing a

client's remote procedure call (before it returns from processing). For

example:

                CLIENT                SERVER

                ------                ------

       Client makes RPC call. --->

                                <--- Server calls callback procedure.

Client returns from callback. --->

                                <--- Server calls callback procedure.

Client returns from callback. --->

                                <--- Server returns from original RPC call.

MORE INFORMATION

Callbacks are declared in the RPC .IDL file and defined in the source of

the client. The following demonstrates how callbacks are declared and

defined:

[ SAMPLE.IDL ]

[

   uuid(9FEE4F51-0396-101A-AE4F-08002B2D0065),

   version(1.0),

   pointer_default( unique )

]

{

 void RPCProc( [in, string] unsigned char *pszStr );

 [callback] void CallbackProc([in,string] unsigned char *pszStr);

}

[ SAMPLEC.C (Client)]

/*

   Callback RPC call (initiated from server, executed on client).

*/

void CallbackProc( unsigned char *pszString )

{

  printf("Call from server, printed on client: %s", pszStr );

}

[ SAMPLES.C (Server)]

/*

   "Standard" RPC call (initiated from client, executed on server).

   Makes a call to client callback procedure, CallbackProc().

*/

void RPCProc( unsigned char *pszStr )

{

  printf("About to call Callback() client function.."

  CallbackProc( pszStr );

  printf("Called callback function.");

}

In the makefile for the sample, the "-ms_ext" switch must be used for the

MIDL compile. For example:

   midl -ms_ext -cpp_cmd $(cc) -cpp_opt "-E" sample.idl

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: NtwkRpc


Using SendMessage() As Opposed to SendDlgItemMessage()

PSS ID Number: Q12273

Authored 16-Oct-1987	Last modified 10-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.1 and 3.5

The following information describes under what circumstances it

is appropriate to use either the SendMessage() or SendDlgItemMessage()

function.

Both SendMessage() and SendDlgItemMessage() can be used to add strings

to a list box. SendMessage() is used to send a message to a specific

window using the handle to the list box. SendDlgItemMessage() is used

to send a message to the child window of a given window using the list

box resource ID. SendDlgItemMessage() is most often used in dialog box

functions that have a handle to the dialog box and not to the child

window control.

The SendDlgItemMessage() call

   SendDlgItemMessage (hwnd, id, msg, wParam, lParam)

is equivalent to the following SendMessage() call:

   hwnd2 = GetDlgItem (hwnd, id);

   SendMessage (hwnd2, msg, wParam, lParam);

Please note that PostMessage() should never be used to talk to the

child windows of dialog boxes for the following reasons:

1. PostMessage() will only return an error if the message was not

   posted to the control's message queue. Since many messages are

   sent to control return information, PostMessage() will not work,

   since it does not return the information to the caller.

2. 16-bit only: Messages such as the WM_SETTEXT message that include a far

   pointer to a string can potentially cause problems if posted

   using the PostMessage() function. The far pointer may point into a

   buffer that is inside the DS (data segment). Because

   PostMessage() does not process the message immediately, the DS

   might get moved. If the DS is moved before the message is

   processed, the far pointer to the buffer will be invalid.

Additional reference words: 3.00 3.10 3.50

KBCategory: kbprg

KBSubcategory: UsrMsg


Using SendMessageTimeout() in a Multithreaded Application

PSS ID Number: Q106716

Authored 14-Nov-1993	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

SendMessageTimeout() is new to the Win32 application programming interface

(API). The function sends a message to a window and does not return until

either the window procedure processes the message or the timeout occurs.

MORE INFORMATION

This article uses the following scenario to illustrate the behavior of this

function:

Suppose that Win1 and Win2 are created by the same application and

that the following code is included in their window procedures:

   <WindowProc for window Win1>

      ...

      case <xxx>:

         ...

         SendMessageTimeout(      hWnd2,   // window handle

                              WM_USER+1,   // message to send

                                 wParam,   // first message parameter

                                 lParam,   // second message parameter

                            SMTO_NORMAL,   // flag *

                                    100,   // timeout (in milliseconds)

                                   &ret ); // return value

        ...

         break;

      case WM_USER+2:

        <time-consuming procedure>

         break;

* Note that the SMTO_NORMAL flag indicates that the calling thread can

process other requests while waiting for the API to return.

   <WindowProc for window Win2>

      ...

      case WM_USER+1:

         ...

         SendMessage(     hWnd1,    // window handle

                      WM_USER+2,    // message to send

                         wParam,    // first message parameter

                         lParam );  // second message parameter

         OtherStuff();

         ...

         break;

If Win1 executes this SendMessageTimeout() and Win2 uses SendMessage() to

send a message to Win1, Win1 can process the message because SMTO_NORMAL

was specified. If the SendMessageTimeout() expires while the execution is

currently in the window procedure for Win1, the state of the system will

depend on who owns the windows.

If both windows were created by the same thread, the timeout is not used

and the process proceeds exactly as if SendMessage() was being used. If the

windows are owned by different threads, the results can be unpredictable,

because the timeout is restarted whenever a message or some other system

event is received and processed. In other words, the receipt by Win1 of

WM_USER+2 causes the timeout to restart after the message is processed. If

the function executed by Win2, OtherStuff(), then uses up more than 100

milliseconds without awakening the thread that created Win1, the original

SendMessageTimeout() will timeout and return. The OtherStuff() function

continues to completion but any value that was to be returned to Win1 will

be lost. Note that the code paths will always complete.

Additional reference words: 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrMisc


Using Serial Communications Under Win32s

PSS ID Number: Q105759

Authored 24-Oct-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32s versions 1.0, 1.1, and 1.2

Windows NT and Windows provide significantly different serial

communications application programming interfaces (APIs). Win32s does not

support the Win32 Communications API.

A good approach to take in writing a Win32-based application targetted for

Win32s that uses serial communications is to create a pair of dynamic-link

libraries (DLLs) with the same name. One DLL will use Win32 Communications

APIs and be installed under Windows NT. The other DLL will use the

Universal Thunk to call a 16-bit DLL that will call the Windows

Communications API. This DLL will be installed under Win32s.

For more information on the Universal Thunk, see the "Win32s Programmers

Guide" included with the Software Development Kit (SDK). In addition, there

is a sample in MSTOOLS\WIN32S\UT\SAMPLES\UTSAMPLE.

Additional reference words: 1.00 1.10 1.20 comm

KBCategory: kbprg

KBSubcategory: W32s


Using SetClassLong Function to Subclass a Window Class

PSS ID Number: Q32519

Authored 06-Jul-1988	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

It is possible to subclass an entire window class by using the

SetClassLong() function. However, doing so will only subclass windows

of that class created after the call to the SetClassLong() function.

Windows created before the call to the SetClassLong() function are not

affected.

NOTE: In Win32, SetClassLong() only affects Windows in the same address

space. For example, if you subclass EDIT, only edit controls created in

your application will be subclassed.

MORE INFORMATION

Calling the SetClassLong() function with the GCL_WNDPROC index changes

the class function address for that window class, creating a subclass

of the window class. When a subsequent window of that class is created,

the new class function address is inserted into its window structure,

subclassing the new window. Windows created before the call to the

SetClassLong() function (in other words, before the class function

address was changed) are not subclassed.

An application should not use the SetClassLong() function to subclass

standard Windows controls such as edit controls or buttons. If, for

example, an application were to subclass the entire "edit" class,

then subsequent edit controls created by other applications would be

subclassed.

An application can subclass individual standard Windows controls that

it has created by calling the SetWindowLong() function.

Additional reference words: listbox scrollbar 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: UsrWndw


Using SetThreadLocale() for Language Resources

PSS ID Number: Q99392

Authored 27-May-1993	Last modified 24-Mar-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   versions 3.1 and 3.5

Under Windows NT, each resource loading application programming interface

(API) is based on the thread's locale. Each thread has a locale--usually

the default system locale.

You can change the thread locale by calling SetThreadLocale(). To obtain

the language resource you want, just set the thread locale to the locale

you want, then call the normal resource loading API.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: UsrNls WintlDev


Using Temporary File Can Improve Application Performance

PSS ID Number: Q103237

Authored 19-Aug-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   versions 3.1 and 3.5

SUMMARY

The use of temporary files can significantly increase the performance of an

application.

MORE INFORMATION

By using CreateFile() with the FILE_ATTRIBUTE_TEMPORARY flag, you let the

system know that the file is likely to be short lived. The temporary file

is created as a normal file. The system needs to do a minimal amount of

lazy writes to the file system to keep the disk structures (directories and

so forth) consistent. This gives the appearance that the file has been

written to the disk. However, unless the Memory Manager detects an

inadequate supply of free pages and starts writing modified pages to the

disk, the Cache Manager's Lazy Writer may never write the data pages of

this file to the disk. If the system has enough memory, the pages may

remain in memory for any arbitrary amount of time. Because temporary files

are generally short lived, there is a good chance the system will never

write the pages to the disk.

To further increase performance, your application might mark the file as

FILE_FLAG_DELETE_ON_CLOSE. This indicates to the system that when the last

handle of the file is closed, it will be deleted. Although the system

generally purges the cache to ensure that a file being closed is updated

appropriately, because a file marked with this flag won't exist after the

close, the system foregoes the cache purge.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseFileio


Using Text Bullets in a Rich Edit Control

PSS ID Number: Q129859

Authored 08-May-1995	Last modified 23-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.51 and 4.0

 - Microsoft Win32s, version 1.3

The Rich Edit control contains a built-in text bullet feature that is used

to add paragraph bullets to the text. To use this feature, you must send

the Rich Edit control a EM_SETPARAFORMAT message. The EM_SETPARAFORMAT

message takes a pointer to a PARAFORMAT structure as its lParam parameter.

In the PARAFORMAT structure, it is necessary to zero out the structure and

fill in the following members:

   UINT  cbSize - Contains the size of the structure. Use

   sizeof(PARAFORMAT).

   DWORD dwMask - Contains the attributes to set. For bullets, use

   PFM_NUMBERING | PFM_OFFSET.

   WORD  wNumbering - Contains the value that specifies numbering options.

   For bullets, set this member equal to PFN_BULLET.

   LONG  dxOffset - Contains the value that specifies indentation of the

   second line and subsequent lines, relative to the starting indentation.

   For bullets, this value must be positive because the bullet is displayed

   in the area between the starting indentation and the offset. If this

   value is too small, the bullets are not displayed.

Additional reference words: 1.30 4.00 95

KBCategory: kbprg kbui

KBSubcategory: UsrCtl W32s


Using the C Run-Time

PSS ID Number: Q94248

Authored 31-Dec-1992	Last modified 26-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

This document contains the following sections:

   Section 1:  Three Forms of C Run-Time (CRT) Library Are Available

   Section 2:  Using the CRT Libraries When Building a DLL

   Section 3:  Using NTWIN32.MAK to Simplify the Build Process

   Section 4:  Problems Encountered When Using Multiple CRT Libraries

   Section 5:  Mixing Library Types

MORE INFORMATION

Section 1:  Three Forms of C Run-Time (CRT) Libraries Are Available

-------------------------------------------------------------------

There are three forms of the C Run-time library provided with the Win32

SDK:

 - LIBC.LIB is a statically linked library for single-threaded programs.

 - LIBCMT.LIB is a statically linked library that supports multithreaded

   programs.

 - CRTDLL.LIB is an import library for CRTDLL.DLL that also supports

   multithreaded programs. CRTDLL.DLL itself is part of Windows NT.

Microsoft Visual C++ 32-bit edition contains these three forms as well,

however, the CRT in a DLL is named MSVCRT.LIB. The DLL is redistributable.

Its name depends on the version of VC++ (ie MSVCRT10.DLL or MSVCRT20.DLL).

Note however, that MSVCRT10.DLL is not supported on Win32s, while

CRTDLL.LIB is supported on Win32s. MSVCRT20.DLL comes in two versions: one

for Windows NT and the other for Win32s.

Section 2: Using the CRT Libraries When Building a DLL

------------------------------------------------------

When building a DLL which uses any of the C Run-time libraries, in order to

ensure that the CRT is properly initialized, either

1. the initialization function must be named DllMain() and the entry point

   must be specified with the linker option -entry:_DllMainCRTStartup@12

   - or -

2. the DLL's entry point must explicitly call CRT_INIT() on process attach

   and process detach

This permits the C Run-time libraries to properly allocate and initialize C

Run-time data when a process or thread is attaching to the DLL, to properly

clean up C Run-time data when a process is detaching from the DLL, and for

global C++ objects in the DLL to be properly constructed and destructed.

The Win32 SDK samples all use the first method. Use them as an example.

Also refer to the Win32 Programmer's Reference for DllEntryPoint() and the

Visual C++ documentation for DllMain(). Note that DllMainCRTStartup() calls

CRT_INIT() and CRT_INIT() will call your application's DllMain(), if it

exists.

If you wish to use the second method and call the CRT initialization code

yourself, instead of using DllMainCRTStartup() and DllMain(), there are two

techniques:

1. if there is no entry function which performs initialization code, simply

   specify CRT_INIT() as the entry point of the DLL. Assuming that you've

   included NTWIN32.MAK, which defines DLLENTRY as "@12", add the following

   option to the DLL's link line:

      -entry:_CRT_INIT$(DLLENTRY)

   - or -

2. if you *do* have your own DLL entry point, do the following in the entry

   point:

   a. Use this prototype for CRT_INIT():

       BOOL WINAPI _CRT_INIT(HINSTANCE hinstDLL, DWORD fdwReason,

          LPVOID lpReserved);

      For information on CRT_INIT() return values, see the documentation

      DllEntryPoint; the same values are returned.

   b. On DLL_PROCESS_ATTACH and DLL_THREAD_ATTACH (see "DllEntryPoint" in

      the Win32 API reference for more information on these flags), call

      CRT_INIT(), first, before any C Run-time functions are called or any

      floating-point operations are performed.

   c. Call your own process/thread initialization/termination code.

   d. On DLL_PROCESS_DETACH and DLL_THREAD_DETACH, call CRT_INIT() last,

      after all C Run-time functions have been called and all floating-

      point operations are completed.

   Be sure to pass on to CRT_INIT() all of the parameters of the entry

   point; CRT_INIT() expects those parameters, so things may not work

   reliably if they are omitted (in particular, fdwReason is required to

   determine whether process initialization or termination is needed).

   Below is a skeleton sample entry point function that shows when and how

   to make these calls to CRT_INIT() in the DLL entry point:

    BOOL WINAPI DllEntryPoint(HINSTANCE hinstDLL, DWORD fdwReason,

        LPVOID lpReserved)

    {

    if (fdwReason == DLL_PROCESS_ATTACH || fdwReason == DLL_THREAD_ATTACH)

        if (!_CRT_INIT(hinstDLL, fdwReason, lpReserved))

            return(FALSE);

    if (fdwReason == DLL_PROCESS_DETACH || fdwReason == DLL_THREAD_DETACH)

        if (!_CRT_INIT(hinstDLL, fdwReason, lpReserved))

            return(FALSE);

    return(TRUE);

    }

    NOTE that this is *not* necessary if you are using DllMain() and

    -entry:_DllMainCRTStartup@12.

Section 3: Using NTWIN32.MAK to Simplify the Build Process

----------------------------------------------------------

There are macros defined in NTWIN32.MAK that can be used to simplify your

makefiles and to ensure that they are properly built to avoid conflicts.

For this reason, Microsoft highly recommends using NTWIN32.MAK and the

macros therein.

For compilation, use:

   $(cvarsdll)          for apps/DLLs using CRT in a DLL

For linking, use one of the following:

   $(conlibsdll)        for console apps/DLLs using CRT in a DLL

   $(guilibsdll)        for GUI apps using CRT in a DLL

Section 4: Problems Encountered When Using Multiple CRT Libraries

-----------------------------------------------------------------

If an application that makes C Run-time calls links to a DLL that also

makes C Run-time calls, be aware that if they are both linked with one of

the statically-linked C Run-time libraries (LIBC.LIB or LIBCMT.LIB), the

.EXE and DLL will have separate copies of all C Run-time functions and

global variables. This means that C Run-time data cannot be shared between

the .EXE and the DLL. Some of the problems that can occur as a result are:

 - Passing buffered stream handles from the .EXE/DLL to the other module

 - Allocating memory with a C Run-time call in the .EXE/DLL and

   reallocating or freeing it in the other module

 - Checking or setting the value of the global errno variable in the

   .EXE/DLL and expecting it to be the same in the other module. A related

   problem is calling perror() in the opposite module from where the C Run-

   time error occurred, since perror() uses errno.

To avoid these problems, link both the .EXE and DLL with CRTDLL.LIB or

MSVCRT.LIB, which allows both the .EXE and DLL to use the common set of

functions and data contained within CRT in a DLL, and C Run-time data such

as stream handles can then be shared by both the .EXE and DLL.

Section 5: Mixing Library Types

-------------------------------

You can link your DLL with CRTDLL.LIB/MSVCRT.LIB regardless of what your

.EXE is linked with if you avoid mixing CRT data structures and passing

CRT file handles or CRT FILE* pointers to other modules.

When mixing library types adhere to the following:

 - CRT file handles may only be operated on by the CRT module that created

   them.

 - CRT FILE* pointers may only be operated on by the CRT module that

   created them.

 - Memory allocated with the CRT function malloc() may only be freed or

   reallocated by the CRT module that allocated it.

To illustrate this, consider the following example:

   - .EXE is linked with MSVCRT.LIB

   - DLL A is linked with LIBCMT.LIB

   - DLL B is linked with CRTDLL.LIB

   If the .EXE creates a CRT file handle using _create() or _open(), this

   file handle may only be passed to _lseek(), _read(), _write(), _close(),

   etc. in the .EXE file. Do not pass this CRT file handle to either DLL.

   Do not pass a CRT file handle obtained from either DLL to the other DLL

   or to the .EXE.

   If DLL A allocates a block of memory with malloc(), only DLL A may call

   free(), _expand(), or realloc() to operate on that block. You cannot

   call malloc() from DLL A and try to free that block from the .EXE or

   from DLL B.

   NOTE: If all three modules were linked with CRTDLL.LIB or all three were

   linked with MSVCRT.LIb, these restrictions would not apply.

When linking DLLs with LIBC.LIB, be aware that if there is a possibility

that such a DLL will be called by a multithreaded program, the DLL will

not support multiple threads running in the DLL at the same time, which can

cause major problems. If there is a possibility that the DLL will be called

by multithreaded programs, be sure to link it with one of the libraries

that support multithreaded programs (LIBCMT.LIB, CRTDLL.LIB or MSVCRT.LIB).

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbtool

KBSubcategory: TlsMisc


Using the Call-Attributed Profiler (CAP)

PSS ID Number: Q118890

Authored 01-Aug-1994	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   versions 3.1 and 3.5

SUMMARY

The call-attributed profiler (CAP) allows you to profile function calls

within an application.

MORE INFORMATION

To profile an application using CAP, perform the following steps:

1. Replace the Windows NT system DLLs that your application uses with

   DLLs that contain debugging information. To find out which DLLs

   your application uses, run the APF32CVT.EXE utility provided with

   the Win32 SDK. The syntax to use is as follows:

      apf32cvt <application>

   This will list the DLLs to which your program is linked. The system

   DLLs that contain debugging information can be found in the

   \SUPPORT\DEBUGDLL\i386 of the Win32 SDK CD. Rename the DLLs in your

   WINNT\SYSTEM32 directory and copy the debugging DLLs to the

   WINNT\SYSTEM32 directory. You will need to reboot the machine to use

   the DLLs.

2. Recompile your application. If you are using the NTWIN32.MAK file

   in your makefile, all you need to do is to set the environment

   variable PROFILE=on. Otherwise, add /Gh and /Zd to the compiler

   options yourself and be sure that you are linking with the options

   "-debugtype:coff" and "-debug:partial,mapped".

3. Place a CAP.INI file in either the root directory of the drive, the

   application directory, the WINDOWS directory, or the root of the C

   drive. The CAP.INI file specifies the applications for which the

   profiler will gather information. At minimum, CAP.ini must contain

   the following:

      [EXES]

      <app>.exe

      [PATCH IMPORTS]

      <app>.exe

      [PATCH CALLERS]

   where <app> is the application to be profiled. The file CAP.TXT

   included in the \BIN directory of the SDK provides an excellent

   example.

4. Run the application. The profiling information is gathered

   and stored in a file with the same base name as the application

   and a .END extension. This information is in an ASCII format and

   can be viewed by any text editor. You can also use the CAPVIEW

   sample to view a graphical representation of the information.

Walter Oney points out in "Removing Bottlenecks from Your Program with

Windows NT Performance-tuning Tools," from the April 1994 edition of

"Microsoft Systems Journal," that the Visual C++ linker does not correctly

generate debugging information that CAP can use. This is not correct. The

problem is that the SDK 3.1 linker uses "-debug:mapped" by default, but the

Visual C++ linker does not. Adding the switch to the link line (as in

step 2, above) corrects this problem.

A common problem is for the profiling output to have "??? : ???" in place

of the function names from your application. For example:

   1   ??? : ??? (Address=0x77889a1b)    1        4717        4717

             4717        4717        4717         n/a         n/a

This occurs if you use the wrong linker options. You should use

"-debugtype:coff" and "-debug:partial,mapped".

Another common problem is to have function pointers instead of the Win32

API names. For example:

   1    0x77e9b10f                       1      1577         1577

             1577        1577        1577         n/a         n/a

This happens when you do not replace the system DLLs that your application

calls with the DLLs that contain debugging information.

REFERENCES

The release notes for CAP.TXT can be found in the MSTOOLS\BIN directory.

The best source of information is "Optimizing Windows NT" by Russ Blake

in the "Windows NT Resource Kit, Vol. 3".

Additional reference words: 3.10 3.50

KBCategory: kbtool

KBSubcategory: TlsMisc


Using the DeferWindowPos Family of Functions

PSS ID Number: Q87345

Authored 29-Jul-1992	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.1 and 3.0

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

In the Microsoft Windows graphical environment, an application can use

the BeginDeferWindowPos, DeferWindowPos, and EndDeferWindowPos

functions when it moves or sizes a set of windows simultaneously.

Using these functions avoids unnecessary screen painting, which would

occur if the windows were moved individually.

The eighth parameter to the DeferWindowPos function can be any one of

eight flag values that affect the size and position of each moved or

sized window. One of the flags, SWP_NOREDRAW, disables repainting and

prevents Windows from displaying any changes to the screen. This flag

effects both the client and nonclient areas of the window. Any portion

of its parent window uncovered by the move or size operation must be

explicitly invalidated and redrawn.

If the moved or sized windows are child windows or pop-up windows,

then the SWP_NOREDRAW flag has the expected effect. However, if the

window is an edit control, a combo box control, or a list box control,

then specifying SWP_NOREDRAW has no effect; the control is drawn at

its new location and its previous location is not erased. This

behavior is caused by the manner in which these three control classes

are painted. Buttons and static controls function normally.

To work around this limitation and move a group of edit, list box, and

combo box controls in a visually pleasing manner, perform the

following three steps:

1. Use the ShowWindow function to hide all of the controls.

2. Move or size the controls as required with the MoveWindow and

   SetWindowPos functions.

3. Use the ShowWindow function to display all of the controls.

Additional reference words: 3.00 3.10  3.50 3.51 4.00 95 combobox listbox

KBCategory: kbprg

KBSubcategory: UsrWndw


Using the Document Properties Dialog Box

PSS ID Number: Q118622

Authored 25-Jul-1994	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

A number of applications display a printer-configuration dialog box titled

"Document Properties" when the user chooses File from the application menu,

chooses Print, and then chooses the Setup button.

The DocumentProperties() API is used to display this dialog box. You need

to call DocumentProperties() with the DM_IN_PROMPT bit set in the last

parameter (fMode). You also need to call OpenPrinter() before calling

DocumentProperties().

MORE INFORMATION

The following code demonstrates how to call DocumentProperties():

Sample Code

-----------

   HDC         hPrnDC;

   LPDEVMODE   lpDevMode = NULL;

   LPDEVNAMES  lpDevNames;

   LPSTR       lpszDriverName;

   LPSTR       lpszDeviceName;

   LPSTR       lpszPortName;

   PRINTDLG    pd;

   HANDLE      hPrinter;

   int         nDMSize;

   HANDLE      hDevMode;

   NPDEVMODE   npDevMode;

   DEVMODE     DevModeIn;

   // Get the defaults without displaying any dialog boxes.

   pd.Flags = PD_RETURNDEFAULT;

   pd.hDevNames = NULL;

   pd.hDevMode = NULL;

   pd.lStructSize = sizeof(PRINTDLG);

   PrintDlg((LPPRINTDLG)&pd);

   lpDevNames = (LPDEVNAMES)GlobalLock(pd.hDevNames);

   lpszDriverName = (LPSTR)lpDevNames + lpDevNames->wDriverOffset;

   lpszDeviceName = (LPSTR)lpDevNames + lpDevNames->wDeviceOffset;

   lpszPortName   = (LPSTR)lpDevNames + lpDevNames->wOutputOffset;

   OpenPrinter(lpszDeviceName,&hPrinter,NULL);

   // A zero for last param returns the size of buffer needed.

   nDMSize = DocumentProperties(hWnd,hPrinter,lpszDeviceName,NULL,NULL,0);

   if ((nDMSize < 0) || !(hDevMode = LocalAlloc (LHND, nDMSize)))

      return NULL;

   npDevMode = (NPDEVMODE) LocalLock (hDevMode);

   // Fill in the rest of the structure.

   lstrcpy (DevModeIn.dmDeviceName, lpszDeviceName);

   DevModeIn.dmSpecVersion    = 0x300;

   DevModeIn.dmDriverVersion  = 0;

   DevModeIn.dmSize           = sizeof (DevModeIn);

   DevModeIn.dmDriverExtra    = 0;

   // Display the "Document Properties" dialog box.

   DocumentProperties(hWnd,hPrinter,lpszDeviceName,npDevMode,&DevModeIn,

      DM_IN_PROMPT|DM_OUT_BUFFER);

   // Get the printer DC.

   hPrnDC = CreateDC

(lpszDriverName,lpszDeviceName,lpszPortName,(LPSTR)npDevMode);

   LocalUnlock (hDevMode);

   //  Use the printer DC.

   ...

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: GdiPrn


Using the DRAWPATTERNRECT Escape in Windows

PSS ID Number: Q75380

Authored 19-Aug-1991	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.1 and 3.0

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

The DRAWPATTERNRECT escape is implemented by the PCL/HP driver for

Hewlett-Packard (HP) LaserJet printers and compatibles. The escape is

used to draw a patterned rectangle without using the graphics banding

bitmap. Using this escape can enhance the performance for many

applications, particularly when a majority of users have

LaserJet-compatible printers.

MORE INFORMATION

The HP LaserJet Plus and all later LaserJets implement a command

called a rule. A rule is a rectangle filled with some pattern, such as

a black rule, a quasi-halftone gray scale, or a hatch pattern.

The output does not go through the graphics banding bitmap (it is

actually sent to the printer in the text band). The DRAWPATTERNRECT

escape can be used to print line and block graphics in the text band

without using graphics banding at all. Because many applications use

only horizontal and vertical lines or blocks, this is a significant

optimization.

An application should determine support for rules using the

QUERYESCSUPPORT escape. In particular, the application should not

check for the PCL/HP driver, since other page printer drivers may

implement the escape as well.

There are some limitations to the escape. First, rules drawn with

DRAWPATTERNRECT are not subject to clipping regions in the Device

Context (DC). Second, rules cannot be opaqued; no white pixel in the

graphics band will erase a pixel drawn by a rule (the same limitation

occurs for PCL text). Once a rule is drawn, it cannot be erased.

If these limitations are acceptable, if all graphics on the page are

likely to be horizontal and vertical lines, and if a significant

number of users are expected to have LaserJet-type printers (which is

the case for most Windows-based applications), the DRAWPATTERNRECT escape

should be used.

If for any reason DRAWPATTERNRECT cannot be used, then the application

should generally use the PatBlt function. If the device is a

plotter, the Rectangle function should be used. In the case of the

PatBlt function, if a black rectangle is to be printed, the BLACKNESS

raster operator (ROP) should be used to avoid the overhead of

selecting and later deselecting a black brush into the printer DC.

Additional reference words: 3.00 3.10 3.50 4.00 95  HPPCL HP-PCL

KBCategory: kbprg

KBSubcategory: GdiPrn


Using the DS_SETFONT Dialog Box Style

PSS ID Number: Q87344

Authored 29-Jul-1992	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

In the Microsoft Windows graphical environment, an application can

affect the appearance of a dialog box by specifying the DS_SETFONT

style bit. DS_SETFONT is available only when the application creates a

dialog box dynamically from a memory-resident dialog box template

using the CreateDialogIndirect, CreateDialogIndirectParam,

DialogBoxIndirect, or DialogBoxIndirectParam function. The second

parameter to each of these functions is the handle to a global memory

object that contains a DLGTEMPLATE dialog box template data structure.

The dwStyle (first) member of the DLGTEMPLATE structure contains style

information for the dialog box.

When an application creates a dialog box using one of these functions,

Windows determines whether the template contains a FONTINFO data

structure by checking for the DS_FONTSTYLE bit in the dwStyle member

of the DLGTEMPLATE structure. If this bit is set, Windows creates a

font for the dialog box and its controls based on the information in

the FONTINFO structure. Otherwise, Windows uses the default system

font to calculate the size of the dialog box and the placement and

text of its controls.

If Windows creates a font based on the FONTINFO data structure, it

sends a WM_SETFONT message to the dialog box. If Windows uses the

system default font, it does not send a WM_SETFONT message. A dialog

box can change the font of one or more of its controls by creating a

font and sending a WM_SETFONT message with the font handle to the

appropriate controls.

Additional reference words: 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrDlgs


Using the FORCEFONT .HPJ Option

PSS ID Number: Q93395

Authored 09-Dec-1992	Last modified 24-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

The FORCEFONT Help project file (HPJ) option can only be used with the

following font names:

   Helv

   Helvetica

   Courier

   Tms Rmn

   Times

   Symbol

Though Helv, Helvetica, Times, and Tms Rmn are not Windows 3.1 fonts, each

of them is mapped to a 3.1 font in the [FontSubstitutes] section of WIN.INI

by Windows Setup. They are mapped as follows:

   Helv=MS Sans Serif

   Tms Rmn=MS Serif

   Times=Times New Roman

   Helvetica=Arial

To force a Help file to use MS Sans Serif, the FORCEFONT option should be:

   FORCEFONT=Helv

Additional reference words: 3.10 3.50 4.00 95 HC30 HC31 HCP help compiler

MAPFONTSIZE

KBCategory: kbtool

KBSubcategory: TlsHlp


Using the GetWindow() Function

PSS ID Number: Q33161

Authored 20-Jul-1988	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.1 and 3.0

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

An application can use the GetWindow function to enumerate the windows

that have a specified relationship to another window. For example, an

application can determine the windows that are children of the

application's main window.

MORE INFORMATION

The GetWindow function returns NULL when no more windows match the

specified criteria. Given a window handle, hWnd, the following code

determines how many siblings the associated window has:

   int CountSiblings(HWND hWnd)

      {

      HWND hWndNext;

      short nCount = 0;

      hWndNext = GetWindow(hWnd, GW_HWNDFIRST);

      while (hWndNext != NULL)

         {

         nCount++;

         hWndNext = GetWindow(hWndNext, GW_HWNDNEXT);

         }

      return nCount;

      }

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrWndw


Using the Registry Under Win32s

PSS ID Number: Q129542

Authored 27-Apr-1995	Last modified 29-Apr-1995

The information in this article applies to:

 - Microsoft Win32s, version 1.2

SUMMARY

A Win32s-based application running under Win32s is limited to the Windows

version 3.1 view of the registry. This means that there are no named

values. In addition, HKEY_CLASSES_ROOT is available, but not

HKEY_LOCAL_MACHINE or HKEY_CURRENT_USER.

The Windows version 3.1 registry is very limited in size. Microsoft

recommends that you store only the OLE registration information in the

Windows registry.

MORE INFORMATION

While Win32s does support some Registry APIs that Windows does not, it does

not support all of the Win32 Registry APIs. For a complete list of the

Registry APIs supported under Win32s, please see the file WIN32API.CSV,

which is included with the Win32 Software Development Kit (SDK) and in

Microsoft Visual C++ (32-bit edition).

NOTE: All supported Registry APIs, except for RegQueryValueA() and

RegQueryValueExA(), return the error codes defined for Windows verion 3.1,

not the codes defined by the Win32 API.

Additional reference words: 1.20

KBCategory: kbprg

KBSubcategory: W32s


Using the Windows 95 Common Controls on Windows NT and Win32s

PSS ID Number: Q125672

Authored 01-Feb-1995	Last modified 06-Apr-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

 - Microsoft Win32s version 1.3

SUMMARY

To provide greater compatibility between Windows 95, Windows NT, and

Win32s, the common control library from Windows 95 has been ported to

Windows NT and Win32s starting with Windows NT version 3.51 and Win32s

version 1.3.

MORE INFORMATION

The COMCTL32.DLL that provides the common controls in Windows 95 is not

compatible with Windows NT or Win32s, so adding the controls to Windows NT

is not as simple as copying the DLL. Also, the COMCTL32.DLL that comes

with Windows NT version 3.51 and with Win32s is not redistributable.

Customers that want to run programs using the new controls must be running

Windows NT version 3.51 or Win32s version 1.3.

Windows NT version 3.51 and Win32s version 1.3 are targeted to be released

before the release of Windows 95, so any changes in the functionality of

these controls between the release of Windows NT and Win32s and the release

of Windows 95 will be added to Windows NT and Win32s in their next updates.

Additional reference words: 4.00 1.30 3.51

KBCategory: kbui

KBSubcategory: UsrCtl


Using the WM_VKEYTOITEM Message Correctly

PSS ID Number: Q108941

Authored 20-Dec-1993	Last modified 12-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

The WM_VKEYTOITEM message is sent by a list box with the

LBS_WANTKEYBOARDINPUT style to its owner in response to a WM_KEYDOWN

message. The return value from this message specifies the action that the

application performed in response to the message. A return value of -2

indicates that the application handled all aspects of selecting the item

and requires no further action by the list box.

This is true only for certain keys such as the UP ARROW (VK_UP), DOWN ARROW

(VK_DOWN), PAGE DOWN (VK_NEXT) and PAGE UP (VK_PREVIOUS) keys. All other

keys are handled in the normal way by the list box, regardless of the

return value from the WM_VKEYTOITEM message.

MORE INFORMATION

The documentation for the WM_VKEYTOITEM message indicates that the owner of

a list box control can trap the WM_VKEYTOITEM message that is generated in

response to a WM_KEYDOWN message and return -2 if the application does not

want the default list box window procedure to take further action.

This is valid only for keys that are not translated into a character by the

list box control in Windows. If the WM_KEYDOWN message translates to a

WM_CHAR message and the application processes the WM_VKEYTOITEM message

generated as a result of the keydown, the list box ignores the return value

(it will go ahead and do the default processing for that character).

WM_KEYDOWN messages generated by keys such as VK_UP (UP ARROW), VK_DOWN

(DOWN ARROW), VK_NEXT (PAGE DOWN) and VK_PREVIOUS (PAGE UP) are not

translated to WM_CHAR messages. In such cases, trapping the WM_VKEYTOITEM

message and returning a -2 prevents the list box from doing the default

processing for that key.

For example, if an application traps the DOWN ARROW key and does some

nondefault processing (such as moving the selection to the item two indexes

below the currently selected item) and then returns -2, the list box

control will not do any more processing with this message.

Alternatively, if the application trapped the "A" key, does some nondefault

processing, and returns -2, the list box code will still do the default

processing. The list box will select an item in the list box that starts

with an "A" (if one is present).

To trap keys that generate a char message and do special processing, the

application must subclass the list box and trap both the WM_KEYDOWN and

WM_CHAR messages, and process the messages appropriately in the subclass

procedure.

NOTE: This discussion is for regular list boxes that are created with the

LBS_WANTKEYBOARDINPUT style. If the list box is owner draw, the application

must process the WM_CHARTOITEM message. For more information on the

WM_CHARTOITEM message, refer to the SDK documentation.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95 listbox

KBCategory: kbprg

KBSubcategory: UsrCtl


Using UnregisterClass When Removing Custom Control Class

PSS ID Number: Q67248

Authored 28-Nov-1990	Last modified 18-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.1 and 3.0

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

In the Microsoft Windows environment, when no running application

requires a custom control class, the class should be removed from

memory to free the system resources it uses.

If an application registers a control class for temporary use, the

application should use the UnregisterClass function when the control

is no longer needed. If the application is terminated, Windows

automatically removes any classes that the application registered;

therefore, explicit use of UnregisterClass is not required. However,

pairing calls to the RegisterClass and UnregisterClass functions is a

good programming practice.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrCtl


Using volatile to Prevent Optimization of try/except

PSS ID Number: Q91149

Authored 29-Oct-1992	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

The following is an example of a valid optimization that may take

programmers by surprise.

1. A variable (temp) used only within the try-except body is declared

   outside it, and therefore is global with respect to the try.

2. Assignment to the variable (temp) is in the program only for a possible

   side effect of doing a read memory access through the pointer.

MORE INFORMATION

For example:

   VOID

   puRoutine( PULONG pu )

   {

      ...

      ULONG temp;       // Just for probing

      ...

      try {

         temp = *pu;    // See if pu is a valid argument

      }

      except {

         // Handle exception

      }

   }

The compiler optimizes and eliminates the entire try-except statement

because temp is not used later.

If the value of temp were used globally, the compiler should treat the

assignment to temp as volatile and do the assignment immediately even if it

is overwritten later in the body of the try. The reasoning is that, at

almost any point in the try body, control may jump to the except (or an

exception filter). Presumably the programmer accessing the variable outside

the try wants to get the current (most recently assigned) value.

The way to prevent the compiler from performing the optimization is:

   temp = (volatile ULONG) *pu;

If a temporary variable is not needed, given the example, the read access

should still be specified as volatile, for example:

   *(volatile PULONG) pu;

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: BseExcept


Using VxDs and Software Interrupts Under Win32s

PSS ID Number: Q105760

Authored 24-Oct-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32s versions 1.0, 1.1, and 1.2

Calling VxDs directly from a Win32-based application is not supported under

Win32s. Win32s does not support the VxD interfaces, so the call is handled

by the underlying Windows system. The Win32-based application runs with 32-

bit stack and code sections, but Windows expects only 16-bit segments.

Therefore, the calls to the VxD cannot be handled by Windows as expected.

To call software interrupts (such as Interrupt 2F) from a Win32-based

application running under Windows 3.1 via Win32s, place the call in a 16-

bit dynamic-link library (DLL) and use the Universal Thunks to access this

DLL. To convert the addresses between segmented and linear address, use

UTSelectorOffsetToLinear() and UTLinearToSelectorOffset().

Additional reference words: 1.00 1.10 1.20

KBCategory: kbprg

KBSubcategory: W32s


Using Windows Sockets Under Win32s and WOW

PSS ID Number: Q105757

Authored 24-Oct-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32s versions 1.1 and 1.2

SUMMARY

Win32s versions 1.1 and later provide a thunking layer for Windows Sockets.

A 16-bit Windows Sockets 1.1 package must be installed on the Windows

machine. Otherwise, the system will report that WINSOCK.DLL was not found.

Windows NT provides a versions 1.0- and 1.1-compliant WOW (Windows on

Win32) thunking layer.

MORE INFORMATION

There are a number of vendors that sell Windows Sockets packages. Windows

Sockets support is available from Microsoft for LAN Manager version 2.2 for

MS-DOS and Windows 3.1 at no additional cost. Similar support is also being

shipped in "Microsoft TCP/IP for Windows For Workgroups" and the "Microsoft

Network Client."

If you have LAN Manager with Microsoft TCP/IP, you can pick up everything

you need from ftp.microsoft.com. Or, call Microsoft Sales at (800) 426-

9400.

The following is information on how to subscribe to an Internet mailing

list for Windows Socket programming as of 07/94:

   Send mail to majordomo@mailbag.intel.com with a body that has

      SUBSCRIBE WINSOCK <your_full_internet_email_address>.

   If you want to be on the winsock hackers mailing list (for implementors

   of Windows sockets), use the following body in a separate piece of

   email.

      SUBSCRIBE WINSOCK-HACKERS <your_full_internet_email_address>.

Other lists available include:

  winsnmp

  winsock-2

  ws2-app-review-board

  ws2-appletalk

  ws2-conn-oriented-media

  ws2-decnet

  ws2-generic-api-ext

  ws2-ipx-spx

  ws2-name-resolution

  ws2-oper-framework

  ws2-osi

  ws2-spec-clarif

  ws2-tcp-ip

  ws2-transp-review-board

  ws2-wireless

Use the command 'info <list>' to get more information about a specific

list.

Additional reference words: 1.10 1.20

KBCategory: kbprg

KBSubcategory: W32s


Validating User Account Passwords Under Windows NT

PSS ID Number: Q98891

Authored 18-May-1993	Last modified 23-Feb-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1, 3.5, and 3.51

Windows NT stores account names and passwords in the security accounts

manager (SAM) database. Windows NT checks this database to validate

passwords when users log on.

In Windows NT 3.1 and 3.5, there is no nonprivileged service that takes a

user name and a password and returns an indication of whether or not the

user account password is valid. There is a privileged service that handles

this password validation; it is for use by logon processes such as

winlogon.

Windows NT 3.51 introduces new Win32 APIs for logon support:

   LogonUser

   ImpersonateLoggedOnUser

   CreateProcessAsUser

MORE INFORMATION

The SAM application programming interface (API) functions were not

exposed due to their changing nature. Microsoft is working on a

developer's kit that will provide guidelines and tutorial information

about most of the security API functions, including the SAM APIs.

Exposing the SAM API will not compromise security because the

passwords are encrypted within SAM; they are one-way encrypted such

that not even SAM can decrypt them. Even a dictionary attack (encrypt

an entire dictionary and see if any of the words match) would not be

easy, because there is no SAM API function that will read the

encrypted password.

Additional reference words: 3.10 3.50 non-privileged

KBCategory: kbprg

KBSubcategory: BseSecurity


Validating User Accounts (Impersonation)

PSS ID Number: Q96005

Authored 03-Mar-1993	Last modified 23-Feb-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1, 3.5, and 3.51

SUMMARY

Some applications need the ability to execute processes in the context of

another user. This impersonation restricts (or expands) the permissions of

the account in which the application was executed (file access, permission

to change system time, permission to shut down the system, and so forth).

For example, an administrator executes a network server program that allows

remote users to log on to the system and perform actions, as if they were

logged on to the system locally. Because the administrator initiated the

server program and is currently logged on, all actions the server program

performs will be in the security context of the administrator. If a guest

user logs on remotely, he/she will have all the permissions the

administrator account has.

With the Win32 API under Windows NT 3.1 and 3.5, impersonating a remote

client is possible only via the ImpersonateDDEClientWindow(),

ImpersonateNamedPipeClient() and RpcImpersonateClient() APIs.

Windows NT 3.51 introduces new Win32 APIs (Logon Support APIs) to deal with

this problem:

   LogonUser

   ImpersonateLoggedOnUser

   CreateProcessAsUser

MORE INFORMATION

For versions of Windows NT prior to 3.51

----------------------------------------

A common application of impersonation is network server programs (daemons).

For example, a remote login daemon needs a user to be able to to log in to

a remote host and have the host impose all restrictions of the client login

account.

If the daemon is using named pipes, dynamic data exchange (DDE), or a

remote procedure call (RPC) (using the named pipes transport), the client

account may be impersonated on the server daemon, which will impose all the

restrictions of the client's user account.

Using other network interfaces (such as Windows sockets--network

programming interfaces), security cannot be monitored by the system. A

workaround would be to impose password-level security on "login" to the

application. The passwords would be maintained by the application in a

private accounts database. However, none of the user actions are performed

in the security context of the actual client user's account. Therefore,

after the server/daemon has validated the client, the server must be

careful to only perform actions on behalf of the client that the server

knows the client should be allowed to do.

Another option is to create a network share with restricted access. The

WNetAddConnection2() API can verify access to this system resources [disk

or printer network resource (share)]. If the network share was set up to

allow access by a restricted group of people, the WNetAddConnection2()

could validate actual user accounts, maintained by Windows NT. As with the

previous option, the daemon must be careful to perform only restricted

actions on behalf of the client. This option could be used for file server

daemons.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseSecurity


Value Returned by GetWindowLong(hWnd, GWL_STYLE)

PSS ID Number: Q83366

Authored 09-Apr-1992	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

GetWindowLong(hWnd, GWL_STYLE) returns the window style information

stored at the GWL_STYLE offset of the window data structure identified

by hWnd. This offset contains the current state of the window, rather

than the style specified when the window was created.

Windows can set and clear the following styles over the lifetime of a

window: WS_CLIPSIBLINGS, WS_DISABLED, WS_HSCROLL, WS_MAXIMIZE,

WS_MINIMIZE, WS_SYSMENU (for MDI child windows), WS_THICKFRAME,

WS_VISIBLE, and WS_VSCROLL. Windows will not dynamically set or clear

any of the other styles. An application can modify the style state at

the GWL_STYLE offset at any time by calling SetWindowLong(hWnd,

GWL_STYLE, dwNewLong), but Windows will not be aware that the style

has changed. Windows maintains some internal flags on the window style

and may use these rather than checking the GWL_STYLE offset of the

window data structure.

GetWindowLong(hWnd, GWL_STYLE) returns a LONG value, which contains

the currently active styles combined by the Boolean OR operator. An

application can change the information stored at the GWL_STYLE offset

by calling SetWindowLong(hWnd, GWL_STYLE, dwNewLong).

MORE INFORMATION

The following table lists the windows styles that Windows updates

throughout the life span of a window. In the Change column below, an

"S" indicates that the style is set and a "C" indicates that the style

is cleared. The Where column lists the source module involved. Windows

will change a window's styles as follows:

Style       Change  Window      Where       Why

-----       ------  ------      -----       ---

WS_CLIPSIBLINGS

            S       Overlapped  WMCREATE.C  Set on creation.

WS_CLIPSIBLINGS

            S       Popup       WMCREATE.C  Set on creation.

WS_DISABLED S & C   Any         WMACT.C     Set or cleared when

                                            EnableWindow function

                                            disables or enables

                                            window.

WS_HSCROLL  S & C   SB_HORZ     WINSBCTL.C  Set or cleared as scroll

                                            bar range changed (for

                                            window scroll bar, not the

                                            SCROLL BAR class).

WS_HSCROLL  S & C   SB_HORZ     SBRARE.C    Set or cleared in

                                            ShowScrollBar (for window

                                            scroll bar, not the SCROLL

                                            BAR class).

WS_HSCROLL  S & C   List boxes  LBOXCTL1.C  Set if scroll bar required

                                            to see contents.

WS_HSCROLL  S & C   MDI frame   MDIWIN.C    Set if required to see

                                            children.

WS_MAXIMIZE C       Any         WMCREATE.C  On creation (reset

                                            immediately in

                                            WMMINMAX.C).

WS_MAXIMIZE C       Any         WMMOVE.C    Cleared if window resized.

WS_MAXIMIZE S & C   Any         WMMINMAX.C  Set if window maximized,

                                            cleared if no longer

                                            maximized.

WS_MINIMIZE C       Any         WMCREATE.C  On creation (reset

                                            immediately in

                                            WMMINMAX.C).

WS_MINIMIZE C       Any         WMMOVE.C    Cleared if window resized.

WS_MINIMIZE S & C   any         WMMINMAX.C  Set if window minimized,

                                            cleared if no longer

                                            minimized.

WS_SYSMENU  S & C   MDI child   MDIMENU.C   Cleared if child is

                                            maximized and uses frame

                                            menu. Set when child no

                                            longer maximized.

WS_THICKFRAME

            S & C   Any         WINSBCTL.C  State changed for only a

                                            few instructions during

                                            painting.

WS_VISIBLE  C       Any         WMCREATE.C  Cleared and then reset by

                                            call to ShowWindow.

WS_VISIBLE  S & C   Any         WMSHOW.C    Cleared if window hidden

                                            in ShowWindow, set if

                                            shown.

WS_VISIBLE  S & C   Any         WMSWP.C     Cleared if window hidden

                                            in ShowWindow, set if

                                            shown.

WS_VISIBLE  C       MDI client  MDIWIN.C    Cleared when current MDI

                                            child is maximized, and

                                            new child is activated.

                                            Immediately reset with

                                            call to ShowWindow.

WS_VISIBLE  S       Desktop     INLOADW.C   Ensure desktop visible.

WS_VISIBLE  S & C   Any         MSDWP.C     Set or cleared when

                                            DefWindowProc receives

                                            WM_SETREDRAW message to

                                            turn drawing on or off,

                                            respectively.

WS_VISIBLE  S & C   MDI client  MDIWIN.C    Cleared and then

                                            immediately reset to

                                            optimize painting.

WS_VSCROLL  S & C   SB_VERT     WINSBCTL.C  Set or cleared as scroll

                                            bar range changed (for

                                            window scroll bar, not the

                                            SCROLL BAR class).

WS_VSCROLL  S & C   List boxes  LBOXCTL1.C  Set if scroll bar required

                                            to see entire contents.

WS_VSCROLL  S & C   MDI frame   MDIWIN.C    Set if required to see

                                            children.

WS_VSCROLL  S & C   SB_VERT     SBRARE.C    Set/cleared in

                                            ShowScrollBar (for window

                                            scroll bar, not the SCROLL

                                            BAR class).

In addition to the information above, the GetWindowLong function

always reports some style bits to be clear, as follows:

 - Combo boxes always report the following styles as clear:

      CBS_HASSTRINGS, CBS_SORT, WS_BORDER, WS_HSCROLL, and WS_VSCROLL

 - All edit controls report the WS_BORDER style clear.

 - Multiline edit controls report the WS_HSCROLL style clear if the

   control contains centered or right-justified text.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrWndw


Various Ways to Access Submenus and Menu Items

PSS ID Number: Q71454

Authored 18-Apr-1991	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

In calls to Microsoft Windows functions that create, modify, and destroy

menus, an application can access an individual menu item by either its

position or its item ID. A pop-up menu must be accessed by its position

because it does not have a menu-item ID.

Specifically, when an application calls the EnableMenuItem() function to

enable, disable, or dim (gray) an individual menu item, the application can

specify either the MF_BYPOSITION or the MF_BYCOMMAND flag in the wEnable

parameter. When the application calls EnableMenuItem() to access a pop-up

menu, it must specify the MF_BYPOSITION flag.

The information below provides examples of the following:

 - Retrieving a menu handle for a submenu

 - Accessing a submenu

 - Accessing a menu item

MORE INFORMATION

The following resource-file menu template provides the basis for the source

code examples in this article. The template describes a top-level menu with

two pop-up submenus. One of the submenus contains a third, nested submenu.

   GenericMenu MENU

   BEGIN

      POPUP "&Help"

      BEGIN

         MENUITEM "&About Generic...", IDM_ABOUT

      END

      POPUP "&Test"

      BEGIN

         POPUP "&Nested"

         BEGIN

            MENUITEM "&1 Beep", IDM_1BEEP

            MENUITEM "&2 Beeps", IDM_2BEEPS

         END

      END

   END

Retrieving the Handle to a Submenu

----------------------------------

Code such as the following can be used to obtain handles to the menus:

   HMENU hMainMenu, hHelpPopup, hTestPopup, hNestedPopup;

   <other program lines>

   hMainMenu = GetMenu(hWnd);

   hHelpPopup = GetSubMenu(hMainMenu, 0);

   hTestPopup = GetSubMenu(hMainMenu, 1);

   hNestedPopup = GetSubMenu(hTestPopup, 0);

The second parameter of the GetSubMenu() function, nPos, is the position

of the desired submenu. Positions are numbered starting at zero for

the first menu item.

Disabling a Submenu

-------------------

The following call disables and dims the nested pop-up menu:

   EnableMenuItem (hTestPopup, 0, MF_BYPOSITION | MF_GRAYED);

The following call disables and dims the Test pop-up menu:

   EnableMenuItem (hMainMenu, 1, MF_BYPOSITION | MF_GRAYED);

The second parameter of the EnableMenuItem() function, wIDEnabledItem, is

the position of the submenu. As above, positions are numbered starting at

zero. Note that the call must specify the MF_BYPOSITION flag because a pop-

up menu does not have a menu-item ID.

Disabling a Menu Item

---------------------

The 1 Beep menu item can be disabled and dimmed by using any one of

the following calls:

   EnableMenuItem(hMainMenu, IDM_1BEEP, MF_BYCOMMAND | MF_GRAYED);

   EnableMenuItem(hTestPopup, IDM_1BEEP, MF_BYCOMMAND | MF_GRAYED);

   EnableMenuItem(hNestedPopup, IDM_1BEEP, MF_BYCOMMAND | MF_GRAYED);

   EnableMenuItem(hNestedPopup, 0, MF_BYPOSITION | MF_GRAYED);

A menu item can be specified by either by its menu-item ID value (using the

MF_BYCOMMAND flag) or by its position (using the MF_BYPOSITION) flag. If

the application specifies the menu-item ID value, Windows must walk the

menu structure and search for a menu item with the correct ID. This implies

the each menu-item ID value must be unique for a given menu.

Other Windows Menu Functions

----------------------------

Although the EnableMenuItem() function is used in the example above, the

same general approach is used for all Windows menu functions; access

pop-up menus by position, and access menu items by position or menu-

item ID.

Additional reference words: 3.00 3.10 3.50 4.00 95  dimmed unavailable

KBCategory: kbprg

KBSubcategory: UsrMen


Video for Windows 1.1--Automatic Window Shift Problem

PSS ID Number: Q118390

Authored 17-Jul-1994	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

 - Microsoft Win32 SDK, version 4.0

When a video playback window is created using MCI, the Video for Windows

(VfW) system software may shift the window a small distance vertically or

horizontally from the original location.

The video software does this to align the window on even-byte boundaries in

video memory for optimal playback speed. When the window is located on a

byte boundary, the video software is not required to perform bit-intensive

calculations during video playback, increasing the playback speed.

This behavior is particular to Video for Windows and cannot be controlled

by the application being affected.

Additional reference words: 3.10 4.00 95

KBCategory: kbmm kbprg

KBSubcategory: MMVideo


Viewing Globals Out of Context in WinDbg

PSS ID Number: Q105583

Authored 20-Oct-1993	Last modified 26-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

When viewing global variables (either with the ? command or via the Watch

window) and the variables go out of context, their values become:

   CXX0017 Error: symbol not found

An example of this is when a common dialog box is open in the application.

If you break into an application that is inside COMDLG32.DLL and try to do

a ?gVar, where gVar is a global variable in the application, WinDbg will

not find the symbol because the context is wrong. To view the value of gVar

in MYAPP, use the following:

   ?{,,myapp}gVar

WinDbg will then have no trouble locating the symbolic information.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbtool

KBSubcategory: TlsWindbg


Virtual Memory and Win32s

PSS ID Number: Q124137

Authored 19-Dec-1994	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32s versions 1.1, 1.15, 1.15a, and 1.2

SUMMARY

This article discusses virtual memory issues under Win32s. These issues

include how memory is managed, file mappings, and VirtualAlloc().

MORE INFORMATION

Memory Management

-----------------

Win32s does not manage the virtual memory by itself. Win32s sits on top

of the Win386 virtual memory manager (VMM). The Win32s VxD and Win386

must cooperatively manage the memory.

Windows sets the amount of virtual memory (VM) at boot time, based on

the amount of free physical RAM. Windows is also responsible for managing

the physical pages.

The pages that map to the Win32-based application's code and data are

reserved at application initialization time. This decreases the available

virtual memory but not necessarily the available RAM. In 16-bit Windows-

based applications, the selectors are initialized at initialization time,

but they are marked as discarded and are loaded only when the segments are

touched. This may lead you to think that a Win32 version of you application

takes significantly more memory than its 16-bit Windows version. However,

in reality, the available memory drops more when the Win32-based

application is loaded, even though the actual RAM usage during execution

may be lower.

NOTE: Code pages are never backed by the .EXE file, but are always backed

by the pagefile.

File Mappings

-------------

Because of the way memory is managed, you cannot have a file mapping that

is larger than the amount of virtual memory available on Win32s. This works

fine on Windows NT and Windows 95. Win32s allocates regular virtual memory

for the memory mapped section even though it does not need swap space, and

the amount of VM set by Windows is too small to use for mapping large

files.

VirtualAlloc()

--------------

VirtualAlloc() reserves or commits pages in virtual memory. When virtual

memory is allocated (committed), the page is still not present. Touching

the page will make it present and initialized to zero. Unlike Windows NT,

some of the address space on Win32s is not allocated by VirtualAlloc().

You can use VirtualQuery() for every address in the USER address space,

as reported by GetSystemInfo().

VirtualAlloc() allocates private memory, so one process cannot commit or

free memory reserved by another process. This is true for all Win32

platforms. However, on Win32s, the memory is still accessible by all

processes because there is a shared address space provided by Windows.

NOTE: A "not enough memory" error occurs if you reserve memory using

VirtualAlloc() in one application and then try to commit the memory from a

second application. This happens because the call to commit from the second

application is interpreted as a call to reserve. You need to commit at an

address that is not available such as an address already reserved by the

first application.

Additional reference words: 1.10 1.20

KBCategory: kbprg

KBSubcategory: W32s


VirtualLock() Only Locks Pages into Working Set

PSS ID Number: Q94996

Authored 28-Jan-1993	Last modified 03-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

VirtualLock() causes pages to be locked into an application's working set

(virtual memory); it does not lock them absolutely into physical memory.

VirtualLock() essentially means "this page is always part of the process's

working set."

The system is free to swap out any virtually locked pages if it swaps out

the whole process. And when the system swaps the process back in, the

virtually locked pages (similar to any virtual pages) may end up residing

in different real pages.

It is wise to use VirtualLock() very sparingly because it reduces the

flexibility of the system.

Depending upon memory demands on the system, the memory manager may vary

the number of pages a process can lock. Under typical conditions you can

expect to be able to VirtualLock() approximately 28 to 32 pages.

In Windows NT 3.5, you can use SetProcessWorkingSize() to increase the size

of the working set, and therefore increase the number of pages that

VirtualLock() can lock.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseMm


Watching Local Variables That Are Also Globally Declared

PSS ID Number: Q98288

Authored 02-May-1993	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.1, 3.5.

   3.51, and 4.0

SUMMARY

Consider debugging the following program in WinDbg:

   int x = 1;

   int y = 2;

   void main()

   {

      int x = 2;

      x++;

      y++;

   }

Notice that there is a global variable x and a local variable x.

Before you step into main, if you set watchpoints on x and y, the

Watch window will display a value for y but for x will say "Expression

cannot be evaluated." To see the value for x, use ::x and x will

evaluate to the local x in main once you've stepped into main.

MORE INFORMATION

When debugging an application, the X86 C++ evaluator is loaded. Given

this, you can use the scope resolution operator in a watch statement

to view a hidden global variable. Without the use of the scope

resolution operator, there is no way (short of watching it in a memory

window) to watch a hidden global variable.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbtool

KBSubcategory: TlsWindbg


When to Use Synchronous Socket Handles & Blocking Hooks

PSS ID Number: Q131623

Authored 14-Jun-1995	Last modified 15-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

   versions 3.1, 3.5, 3.51, and 4.0

SUMMARY

By default, all socket handles are opened as overlapped handles so that

asynchronous I/O can be performed on them. However, in many situations you

may find it preferable to have nonoverlapped (synchronous) socket handles.

For example, only nonoverlapped handles can be used with the C run-time

libraries or used as standard I/O handles for a process. Under Windows NT

and Windows 95, the SO_OPENTYPE socket option allows an application to open

non-overlapped socket handles.

MORE INFORMATION

There are some Windows Sockets features that you cannot use with

synchronous sockets. Here is an extract from the Winsock Help file:

   The WSAAsyncSelect call cannot be used with synchronous sockets and

   will fail with the error WSAEINVAL. It is also not possible to set the

   SO_SNDTIMEO and SO_RCVTIMEO socket options on synchronous sockets;

   setsockopt with these options on synchronous sockets fails with

   WSAEINVAL as well.

Due to the non-preemptive nature of Windows version 3.1 and Windows for

Workgroups version 3.11, the Winsock specification details a mechanism by

which a Winsock application can "yield" processor time. For more

information, please search for WSASetBlockingHook() in the Winsock Help

file.

NOTE: Use of a blocking hook is not recommended on a 32-bit platform. If a

32-bit application chooses to install a blocking hook, the blocking hook

will be disabled if the application is run under Windows NT, but it will

remain enabled if the application is run under Windows 95.

REFERENCES

Online winsock help file

Additional reference words: 3.10 3.50 3.51 4.00

KBCategory: kbnetwork

KBSubcategory: NtwkWinsock


Where to Get the Microsoft SNMP Headers and Libraries

PSS ID Number: Q127902

Authored 21-Mar-1995	Last modified 26-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.5, 3.51,

   and 4.0

 - Microsoft Windows for Workgroups SDK, version 3.11

The 32-bit SNMP headers and libraries are available in both the Microsoft

Win32 SDK and Microsoft Visual C++ version 2.0 and later. These files are

for use with the Microsoft implementation of SNMP. They will not work with

other implementations because Microsoft does not conform to the WINSNMP

standard of management APIs.

The headers and libraries for the SNMP agent (parts of SNMP.H and SNMP.LIB)

can be used with Windows NT and Windows 95. The headers and libraries for

the Management APIs (parts of SNMP.H, MGMTAPI.H, parts of SNMP.LIB, and

MGMTAPI.LIB) are for use with Windows NT only.

Microsoft offers no 16-bit SNMP for Windows for Workgroups, however, there

are other companies that do offer SNMP for Windows for Workgroups. Here are

two companies that we know of that offer 16-bit SNMP:

   Company: NetManage

   10725 N. De Anza Blvd.

   Cupertino, CA  95014

   Product: Chameleon Utilities

   Phone: (408) 973-7171

   Fax:   (408) 257-6405

   FTP Software

   Corporate Headquarters

   2 High Street

   North Andover, MA 01845-2620

   Phone: (508) 685-4000

   Fax:   (508) 794-4488

The third-party products discussed here are manufactured by vendors

independent of Microsoft; we make no warranty, implied or otherwise,

regarding these products' performance or reliability.

Additional reference words: 3.50 4.00 95

KBCategory: kbprg kb3rdparty

KBSubcategory: NtwkSnmp


Which Windows NT (Server or Workstation) Is Running?

PSS ID Number: Q124305

Authored 27-Dec-1994	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

SUMMARY

You can determine which variant of Windows NT (Windows NT Server or Windows

NT Workstation) is running by using the technique described in this

article. Then you can use this information to execute code based on which

variant is running.

MORE INFORMATION

To find out which product is currently running, you need to determine the

value of the following registry entry:

HKEY_LOCAL_MACHINE\SYSTEM\

CurrentControlSet

Control\

ProductOptions

Use the following table to determine which product is running:

ProductType   Product

----------------------------------------------------

WINNT         Windows NT Workstation is running

SERVERNT      Windows NT Server is running

LANMANNT      Windows NT Advanced Server is running

The sample code creates a WhichNTProduct() function to indicate whether

Windows NT Server or Windows NT Workstation in currently running. The

following table gives the meaning for each return value:

Return Value       Meaning

---------------------------------------------------------

RTN_SERVER         Windows NT Server is running

RTN_WORKSTATION    Windows NT Workstation is running

RTN_NTAS           Windows NT Advanced Server is running

RTN_UNKNOWN        Unknown product type was encountered

RTN_ERROR          Error occurred

To get extended error information, call GetLastError(). Some error checking

is omitted, for brevity.

Sample Code

-----------

#define RTN_UNKNOWN 0

#define RTN_SERVER 1

#define RTN_WORKSTATION 2

#define RTN_NTAS 3

#define RTN_ERROR 13

unsigned int WhichNTProduct(void)

{

    #define MY_BUFSIZE 32 // arbitrary. Use dynamic allocation

    HKEY hKey;

    char szProductType[MY_BUFSIZE];

    DWORD dwBufLen=MY_BUFSIZE;

    if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,

                    "SYSTEM\\CurrentControlSet\\Control\\ProductOptions",

                    0,

                    KEY_EXECUTE,

                    &hKey) != ERROR_SUCCESS) return(RTN_ERROR);

    if(RegQueryValueEx(hKey,

                    "ProductType",

                    NULL,

                    NULL,

                    szProductType,

                    &dwBufLen) != ERROR_SUCCESS) return(RTN_ERROR);

    RegCloseKey(hKey);

    // check product options, in order of likelihood

    if(lstrcmpi("WINNT", szProductType) == 0) return(RTN_WORKSTATION);

    if(lstrcmpi("SERVERNT", szProductType) == 0) return(RTN_SERVER);

    if(lstrcmpi("LANMANNT", szProductType) == 0) return(RTN_NTAS);

    // else return Unknown

    return(RTN_UNKNOWN);

}

Additional reference words: 3.10 3.50

KBCategory: kbprg kbcode

KBSubcategory: BseMisc


Why LoadLibraryEx() Returns an HINSTANCE

PSS ID Number: Q102128

Authored 28-Jul-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

In the Win32 Help files, LoadLibrary() is typed to return a HANDLE, while

LoadLibraryEx() is prototyped to return a HINSTANCE.

An HINSTANCE return from LoadLibraryEx() is useful because processes that

load dynamic-link libraries (DLLs) do not necessarily want the overhead of

having to page in code for a DllEntryPoint routine when the DLL does not

need to initialize information. This is especially useful when you have

multiple threads that attach to already loaded DLLs. In this case, you may

want to not implicitly load via LoadLibrary() and instead use

LoadLibraryEx() to explicitly load without having to page in the code for

every attach.

LoadLibraryEx() is also useful if you want to retrieve resources from a DLL

or an EXE. In this case, you would use LoadLibraryEx() to load the module

you want into your address space, without executing DLLEntryPoint, and then

use the resource application programming interfaces (APIs) to access the

data.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseDll


Win32 Drag and Drop Server

PSS ID Number: Q105530

Authored 20-Oct-1993	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.1, 3.5,

   3.51, 4.0

The supported method for creating a drag and drop server is to use OLE

(Object Linking and Embedding) version 2.0. This works on Windows,

Windows NT, and Windows 95 and will work on future versions of these

operating systems.

Additional reference words: 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrDnd


Win32 Equivalents for C Run-Time Functions

PSS ID Number: Q99456

Authored 30-May-1993	Last modified 13-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

Many of the C Run-time functions have direct equivalents in the Win32

application programming interface (API). This article lists the C Run-time

functions by category with their Win32 equivalents or the word "none" if no

equivalent exists.

MORE INFORMATION

NOTE: the functions that are followed by an asterisk (*) are part of the

16-bit C Run-time only. Functions that are unique to the 32-bit C Run-time

are listed separately in the last section. All other functions are common

to both C Run-times.

Buffer Manipulation

-------------------

   _memccpy                  none

    memchr                   none

    memcmp                   none

    memcpy                   CopyMemory

   _memicmp                  none

    memmove                  MoveMemory

    memset                   FillMemory, ZeroMemory

   _swab                     none

Character Classification

------------------------

     isalnum                 IsCharAlphaNumeric

     isalpha                 IsCharAlpha, GetStringTypeW (Unicode)

   __isascii                 none

     iscntrl                 none, GetStringTypeW (Unicode)

   __iscsym                  none

   __iscsymf                 none

     isdigit                 none, GetStringTypeW (Unicode)

     isgraph                 none

     islower                 IsCharLower, GetStringTypeW (Unicode)

     isprint                 none

     ispunct                 none, GetStringTypeW (Unicode)

     isspace                 none, GetStringTypeW (Unicode)

     isupper                 IsCharUpper, GetStringTypeW (Unicode)

     isxdigit                none, GetStringTypeW (Unicode)

   __toascii                 none

     tolower                 CharLower

    _tolower                 none

     toupper                 CharUpper

    _toupper                 none

Directory Control

-----------------

   _chdir                    SetCurrentDirectory

   _chdrive                  SetCurrentDirectory

   _getcwd                   GetCurrentDirectory

   _getdrive                 GetCurrentDirectory

   _mkdir                    CreateDirectory

   _rmdir                    RemoveDirectory

   _searchenv                SearchPath

File Handling

-------------

   _access                   none

   _chmod                    SetFileAttributes

   _chsize                   SetEndOfFile

   _filelength               GetFileSize

   _fstat                    See Note 5

   _fullpath                 GetFullPathName

   _get_osfhandle            none

   _isatty                   GetFileType

   _locking                  LockFileEx

   _makepath                 none

   _mktemp                   GetTempFileName

   _open_osfhandle           none

    remove                   DeleteFile

    rename                   MoveFile

   _setmode                  none

   _splitpath                none

   _stat                     none

   _umask                    none

   _unlink                   DeleteFile

Creating Text Output Routines

-----------------------------

   _displaycursor*           SetConsoleCursorInfo

   _gettextcolor*            GetConsoleScreenBufferInfo

   _gettextcursor*           GetConsoleCursorInfo

   _gettextposition*         GetConsoleScreenBufferInfo

   _gettextwindow*           GetConsoleWindowInfo

   _outtext*                 WriteConsole

   _scrolltextwindow*        ScrollConsoleScreenBuffer

   _settextcolor*            SetConsoleTextAttribute

   _settextcursor*           SetConsoleCursorInfo

   _settextposition*         SetConsoleCursorPosition

   _settextwindow*           SetConsoleWindowInfo

   _wrapon*                  SetConsoleMode

Stream Routines

---------------

    clearerr                 none

    fclose                   CloseHandle

   _fcloseall                none

   _fdopen                   none

    feof                     none

    ferror                   none

    fflush                   FlushFileBuffers

    fgetc                    none

   _fgetchar                 none

    fgetpos                  none

    fgets                    none

   _fileno                   none

   _flushall                 none

    fopen                    CreateFile

    fprintf                  none

    fputc                    none

   _fputchar                 none

    fputs                    none

    fread                    ReadFile

    freopen (std handles)    SetStdHandle

    fscanf                   none

    fseek                    SetFilePointer

    fsetpos                  SetFilePointer

   _fsopen                   CreateFile

    ftell                    SetFilePointer (check return value)

    fwrite                   WriteFile

    getc                     none

    getchar                  none

    gets                     none

   _getw                     none

    printf                   none

    putc                     none

    putchar                  none

    puts                     none

   _putw                     none

    rewind                   SetFilePointer

   _rmtmp                    none

    scanf                    none

    setbuf                   none

    setvbuf                  none

   _snprintf                 none

    sprintf                  wsprintf

    sscanf                   none

   _tempnam                  GetTempFileName

    tmpfile                  none

    tmpnam                   GetTempFileName

    ungetc                   none

    vfprintf                 none

    vprintf                  none

   _vsnprintf                none

    vsprintf                 wvsprintf

Low-Level I/O

-------------

   _close                   _lclose, CloseHandle

   _commit                   FlushFileBuffers

   _creat                   _lcreat, CreateFile

   _dup                      DuplicateHandle

   _dup2                     none

   _eof                      none

   _lseek                   _llseek, SetFilePointer

   _open                    _lopen, CreateFile

   _read                    _lread, ReadFile

   _sopen                    CreateFile

   _tell                     SetFilePointer (check return value)

   _write                   _lread

Console and Port I/O Routines

-----------------------------

   _cgets                    none

   _cprintf                  none

   _cputs                    none

   _cscanf                   none

   _getch                    ReadConsoleInput

   _getche                   ReadConsoleInput

   _inp                      none

   _inpw                     none

   _kbhit                    PeekConsoleInput

   _outp                     none

   _outpw                    none

   _putch                    WriteConsoleInput

   _ungetch                  none

Memory Allocation

-----------------

   _alloca                   none

   _bfreeseg*                none

   _bheapseg*                none

    calloc                   GlobalAlloc

   _expand                   none

    free                     GlobalFree

   _freect*                  GlobalMemoryStatus

   _halloc*                  GlobalAlloc

   _heapadd                  none

   _heapchk                  none

   _heapmin                  none

   _heapset                  none

   _heapwalk                 none

   _hfree*                   GlobalFree

    malloc                   GlobalAlloc

   _memavl                   GlobalMemoryStatus

   _memmax                   GlobalMemoryStatus

   _msize*                   GlobalSize

    realloc                  GlobalReAlloc

   _set_new_handler          none

   _set_hnew_handler*        none

   _stackavail*              none

Process and Environment Control Routines

----------------------------------------

    abort                    none

    assert                   none

    atexit                   none

   _cexit                    none

   _c_exit                   none

   _exec functions           none

    exit                     ExitProcess

   _exit                     ExitProcess

    getenv                   GetEnvironmentVariable

   _getpid                   GetCurrentProcessId

    longjmp                  none

   _onexit                   none

    perror                   FormatMessage

   _putenv                   SetEnvironmentVariable

    raise                    RaiseException

    setjmp                   none

    signal (ctrl-c only)     SetConsoleCtrlHandler

   _spawn functions          CreateProcess

    system                   CreateProcess

String Manipulation

-------------------

   strcat, wcscat            lstrcat

   strchr, wcschr            none

   strcmp, wcscmp            lstrcmp

   strcpy, wcscpy            lstrcpy

   strcspn, wcscspn          none

  _strdup, _wcsdup           none

   strerror                  FormatMessage

  _strerror                  FormatMessage

  _stricmp, _wcsicmp         lstrcmpi

   strlen, wcslen            lstrlen

  _strlwr, _wcslwr           CharLower, CharLowerBuffer

   strncat, wcsncat          none

   strncmp, wcsncmp          none

   strncpy, wcsncpy          none

  _strnicmp, _wcsnicmp       none

  _strnset, _wcsnset         FillMemory, ZeroMemory

   strpbrk, wcspbrk          none

   strrchr, wcsrchr          none

  _strrev, _wcsrev           none

  _strset, _wcsset           FillMemory, ZeroMemory

   strspn, wcsspn            none

   strstr, wcsstr            none

   strtok, wcstok            none

  _strupr, _wcsupr           CharUpper, CharUpperBuffer

MS-DOS Interface

----------------

  _bdos*                     none

  _chain_intr*               none

  _disable*                  none

  _dos_allocmem*             GlobalAlloc

  _dos_close*                CloseHandle

  _dos_commit*               FlushFileBuffers

  _dos_creat*                CreateFile

  _dos_creatnew*             CreateFile

  _dos_findfirst*            FindFirstFile

  _dos_findnext*             FindNextFile

  _dos_freemem*              GlobalFree

  _dos_getdate*              GetSystemTime

  _dos_getdiskfree*          GetDiskFreeSpace

  _dos_getdrive*             GetCurrentDirectory

  _dos_getfileattr*          GetFileAttributes

  _dos_getftime*             GetFileTime

  _dos_gettime*              GetSystemTime

  _dos_getvect*              none

  _dos_keep*                 none

  _dos_open*                 OpenFile

  _dos_read*                 ReadFile

  _dos_setblock*             GlobalReAlloc

  _dos_setdate*              SetSystemTime

  _dos_setdrive*             SetCurrentDirectory

  _dos_setfileattr*          SetFileAttributes

  _dos_setftime*             SetFileTime

  _dos_settime*              SetSystemTime

  _dos_setvect*              none

  _dos_write*                WriteFile

  _dosexterr*                GetLastError

  _enable*                   none

  _FP_OFF*                   none

  _FP_SEG*                   none

  _harderr*                  See Note 1

  _hardresume*               See Note 1

  _hardretn*                 See Note 1

  _int86*                    none

  _int86x*                   none

  _intdos*                   none

  _intdosx*                  none

  _segread*                  none

Time

----

   asctime                   See Note 2

   clock                     See Note 2

   ctime                     See Note 2

   difftime                  See Note 2

   _ftime                    See Note 2

   _getsystime               GetLocalTime

   gmtime                    See Note 2

   localtime                 See Note 2

   mktime                    See Note 2

   _strdate                  See Note 2

   _strtime                  See Note 2

   time                      See Note 2

   _tzset                    See Note 2

   _utime                    SetFileTime

Virtual Memory Allocation

-------------------------

   _vfree*                   See Note 3

   _vheapinit*               See Note 3

   _vheapterm*               See Note 3

   _vload*                   See Note 3

   _vlock*                   See Note 3

   _vlockcnt*                See Note 3

   _vmalloc*                 See Note 3

   _vmsize*                  See Note 3

   _vrealloc*                See Note 3

   _vunlock*                 See Note 3

32-Bit C Run Time

------------------

   _beginthread              CreateThread

   _cwait                    WaitForSingleObject w/ GetExitCodeProcess

   _endthread                ExitThread

   _findclose                FindClose

   _findfirst                FindFirstFile

   _findnext                 FindNextFile

   _futime                   SetFileTime

   _get_osfhandle            none

   _open_osfhandle           none

   _pclose                   See Note 4

   _pipe                     CreatePipe

   _popen                    See Note 4

NOTE 1: The _harderr functions do not exist in the Win32 API. However, much

of their functionality is available through structured exception handling.

NOTE 2: The time functions are based on a format that is not used in Win32.

There are specific Win32 time functions that are documented in the Help

file.

NOTE 3: The virtual memory functions listed in this document are specific

to the MS-DOS environment and were written to access memory beyond the 640K

of RAM available in MS-DOS. Because this limitation does not exist in

Win32, the standard memory allocation functions should be used.

NOTE 4: While _pclose() and _popen() do not have direct Win32 equivalents,

you can (with some work) simulate them with the following calls:

   _popen                     CreatePipe

                              CreateProcess

   _pclose                    WaitForSingleObject

                              CloseHandle

NOTE 5: GetFileInformationByHandle() is the Win32 equivalent for the

_fstat() C Run-time function. However, GetFileInformationByHandle() is not

supported by Win32s version 1.1. It is supported in Win32s 1.2.

GetFileSize(), GetFileAttributes(), GetFileTime(), and GetFileTitle() are

supported by Win32s 1.1 and 1.2.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: BseMisc


Win32 Graphical Setup Over Network Drives

PSS ID Number: Q98838

Authored 13-May-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

The graphical setup for the Win32 Software Development Kit (SDK) does not

include network drives in the list of drives to choose from, however, the

setup program does support installing to network drives.

In addition, you can use the manual install program, manual.bat, to install

to local or network drives.

Additional reference words: 3.10 3.50

KBCategory: kbsetup

KBSubcategory: Setins


Win32 Priority Class Mechanism and the START Command

PSS ID Number: Q90910

Authored 26-Oct-1992	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

SUMMARY

The Win32 priority class mechanism is exposed through CMD.EXE's START

command.

START accepts the following switches:

   /LOW        -  Start the command in the idle priority class.

   /NORMAL     -  Start the command in the normal priority class

                  (this is the default).

   /HIGH       -  Start the command in the high priority class.

   /REALTIME   -  Start the command in the real-time priority class.

For a complete list of START switches, type the following command at

the Windows NT command prompt:

   start /?

Win32 has also been modified to inherit priority class if the parent's

priority class is idle; thus, a command such as

   start /LOW nmake

causes build and all descendants (compiles, links, and so on) to run in the

idle priority class. Use this method to do a real background build that

will not interfere with anything else on your system.

A command such as

   start /HIGH nmake

runs BUILD.EXE in the high priority class, but all descendants run in the

normal priority class.

MORE INFORMATION

Be very careful with START /HIGH and START /REALTIME. If you use either of

these switches to start applications that require a lot of cycles, the

applications will get all the cycles they ask for, which may cause the

system to appear hung.

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: BseProcThrd


Win32 SDK Knowledge Base Available as Help Files (JUN 94)

PSS ID Number: Q106544

Authored 10-Nov-1993	Last modified 20-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for the Windows NT

   version 3.1

The Microsoft Knowledge Base has been compiled into help files for Windows.

The Win32 SDK Knowledge Base is compiled into two versions. The only

difference is that one of the versions has a full-text search index.

The Win32 SDK Knowledge Base is divided into help files as follows:

   ARCHIVE NAME    FILENAME     TOPIC                    MODIFY DATE

   -----------------------------------------------------------------

   WIN32KBI.EXE    WIN32KB.HLP  Win32 SDK with a         06-JUN-1994

                   WIN32KB.IND  full-text search index.

   WIN32KB.EXE     WIN32KB.HLP  Win32 SDK without a      06-JUN-1994

                                full-text search index.

NOTE: The full-text search index makes the resulting file over twice the

size of a standalone help file.

Win32 SDK with Full-Text Search

-------------------------------

Download WIN32KBI.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for WIN32KBI.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download WIN32KBI.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get WIN32KBI.EXE

Win32 SDK without Full-Text Search

----------------------------------

Download WIN32KB.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for WIN32KB.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download WIN32KB.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get WIN32KB.EXE

Additional reference words: DSKBGuide 3.10

KBCategory: kbref kbtlc kbfile

KBSubcategory: GenSDK


Win32 Shell Dynamic Data Exchange (DDE) Interface

PSS ID Number: Q105446

Authored 20-Oct-1993	Last modified 23-Feb-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1, 3.5, and 3.51

SUMMARY

Information on the DDE Interface to Program Manager can be found in the

Win32 application programming interface (API) reference under the topic

"Shell Dynamic Data Exchange Interface."

The SDK contains a sample program that interfaces with Program

Manager. The sample can be found in MSTOOLS\SAMPLES\DDEML\DDEPROG.

MORE INFORMATION

AppProperties cannot be used to get the item icon, description, or

working directory, as it can in Windows 3.1. Therefore, GetIcon(),

GetDescription(), and GetWorkingDir() do not work in Windows NT.

However, AppProperties can still be used to dump out the contents of a

group, by specifying the group name in lParam.

Here's how a Win32-based application can get the item icon, the

description, and the working directory:

1. Initiate a conversation with the Shell as follows

      SendMessage( -1, WM_DDE_INITIATE, hWndApp, lParam );

   where lParam points to an atom representing:

      LOWORD | HIWORD

      -----------------------------------------------------------

      Shell  | AppIcon        : To get an item's icon

      Shell  | AppDescription : To get an item's description

      Shell  | AppWorkingDir  : To get an item's working directory

2. Get the item DDE number.

   The DDE number is stored by Program Manager in the STARUPINFO

   structure of the application when the application is started. The

   application can get the startup information with:

      GetStartupInfo( &StartupInfo );

   The field lpReserved in the STARUPINFO structure is in the

   following format

      dde.#, hotkey.##

   where the DDE number is # and the hot key for the item is ##.

3. Request data as follows

      SendMessage( hwndProgMan, WM_DDE_REQUEST, hwndApp, lParam );

   where the lParam HIWORD is the item's DDE number obtained in step 2.

4. The data is returned in lParam of WM_DDE_DATA message. The DDE data

   value is a string for AppDescription and AppWorkingDir DDE

   transactions. For AppIcon, the data value has the following

   structure:

      typedef struct _PMIconData {

         DWORD dwResSize;

         DWORD dwVer;

         BYTE iResource;  // icon resource

      } PMICONDATA, *LPPMICONDATA;

   To create the icon, the application must call:

      hIcon = CreateIconFromResource((LPBYTE)&(lpPMIconData->iResource),

                  lpPMIconData->dwResSize,

                  TRUE,

                  lpPMIconData->dwVer

              );

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: UsrDde


Win32 Software Development Kit Buglist

PSS ID Number: Q95804

Authored 17-Jan-1994	Last modified 18-May-1995

The information in this article applies to:

 - FastTips for the Microsoft Win32 Software Development Kit (SDK)

   for Windows NT version 3.5

INSTRUCTIONS

Microsoft FastTips is available 24 hours a day, 7 days a week, from a touch-

tone telephone. To order items from this catalog, first select the items

you want to receive, noting the five- to six-digit number of the Item ID

shown below for each item, and then:

- Dial the toll-free FastTips number (800) 936-4300.

- When prompted, select the Win32 Software Development Kit.

- Press one (1) on your phone keypad to select Express Order Service.

- When prompted, select the delivery method, fax.

- When prompted, enter your three-digit area code and seven-digit fax

  number on your phone keypad.

- When prompted, enter the number of the Item ID and press #, for up

  to five items.

When finished, simply hang up. If you have problems receiving a fax, please

call (206) 635-3105.

ARTICLE LISTING

ITEM ID  ARTICLE TITLE                                               PAGES

--------------------------------------------------------------------------

Q 113739 BUG: Win32s 1.1 Bug List                                        3

Q 121906 BUG: Win32s Version 1.2 Bug List at Time of Release             3

Q 121907 BUG: Win32 SDK Ver. 3.5 Bug List for Win32 SDK and Win32 API    4

Q 122048 BUG: Win32 Ver 3.5 SDK Bug List at Release - Subsystems & WOW   2

Q 122679 BUG: Win32 SDK 3.5 Bug List - OLE                               2

Q 122681 BUG: Win32 SDK 3.5 Bug List - WinDbg Debugger                   4

End of listing.

Additional reference words: DSKBGuide 3.50

KBCategory: kbref kbtlc

KBSubcategory: BseMisc GdiMisc NtwkMisc UsrMisc


Win32 Subsystem Object Cleanup

PSS ID Number: Q89290

Authored 16-Sep-1992	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

SUMMARY

The Win32 subsystem guarantees that all Win32 objects owned by a

process will be freed when an application terminates. To accomplish

this, the Win32 subsystem keeps track of who owns these objects; it

also keeps a reference count. Reference counts are used when the

object is owned by more then one process. For example, a memory mapped

file can be used to provide interprocess communication, where more

than one process would own that object. The subsystem must make sure

that the reference count is zero before the object can be freed.

Freeing of Win32 objects can occur at different times. In general, it

occurs at process termination, but for some objects, it occurs at thread

termination.

NOTE: When running Win32-based applications with Windows 3.1 using the

Win32s environment, it is the responsibility of the Win32-based application

to ensure that all allocated GDI objects are deleted before the program

terminates. This is different from the behavior of the application with

Windows NT. With Windows NT, the GDI subsystem cleans up all orhphaned GDI

objects. Because there is no GDI subsystem with Windows 3.1, this behavior

is not supported.

MORE INFORMATION

At process or thread termination, the Win32 subsystem searches its lists to

find objects owned by this process or thread. Those that are owned by the

terminating process or thread and whose reference counts will be set to

zero when the process or thread is fully terminated will be freed.

The freeing of objects is slightly different for Win32-based applications

running under Win32s on Windows 3.1. The 16-bit objects (GDI objects,

windows, global memory, etc.) follow the same clean-up rules as Windows-

based applications do under Window 3.1. The 32-bit objects, such as memory

allocated via VirtualAlloc(), shared memory via mapped file I/O, 32-bit

modules, thunks allocated on the fly (for hook procedures, wndprocs etc.)

are all handled by Win32s and freed at process termination.

The following is a list of Win32 objects. Note that it may not be complete.

   BASE: console, event, file (including file mapping), mutex,

         semaphore, thread, process, pipe (including named pipes)

   GDI:  device context (DC), bitmap, pen, brush, font, region, palette

   USER: window, cursor, icon, menu, accelerator table, desktop,

         DDE communication objects, DDE conversation objects, dialog

Additional reference words: 3.10

KBCategory: kbprg

KBSubcategory: SubSys


Win32s and LAN Manager APIs

PSS ID Number: Q109204

Authored 28-Dec-1993	Last modified 25-Jan-1995

The information in this article applies to:

 - Microsoft Win32s versions 1.0, 1.1, 1.15, and 1.2

NOTE: Win32s provides support for NetBIOS and Windows Sockets.

There is a NETAPI32.DLL shipping with Win32s. However, this doesn't have

support for Microsoft LAN Manager application programming interfaces

(APIs). This is not a bug because LAN Manager APIs are not supported on

Win32s. However, if NETAPI32.DLL is not in the system and an application

uses LAN Manager APIs, NETAPI32.DLL will not load because the loader cannot

resolve the entry-points from the nonexistent dynamic-link library (DLL).

One of the solutions is to use Universal Thunks. Using Universal Thunks,

calls can be made to 16-bit DLLs. Therefore, the 16-bit NETAPI.DLL that

ships with LAN Manager can be accessed by this mechanism.

Sample programs using Universal Thunks are provided in the Win32 SDK and

the Visual C++ SDK. The sample on the Win32 SDK is in the

MSTOOLS\WIN32S\UT\SAMPLES directory. On the Visual C++ 32-bit Edition

CD-ROM, the sample is located in the MSVC32S\WIN32S\UT\SAMPLES directory.

Additional reference words: 1.00 1.10 1.20

KBCategory: kbprg

KBSubcategory: W32s


Win32s and Windows NT Timer Differences

PSS ID Number: Q105758

Authored 24-Oct-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32s versions 1.0, 1.1, and 1.2

Under Windows NT, timers are system objects; as such, they are not owned by

an application. SetTimer() can be called from within one application with a

handle to a window that was created by a different application. This

application would process the WM_TIMER messages in the window procedure.

The timer event will continue to occur even after the application that

created the timer has terminated. Note that it is fairly uncommon for a

Win32-based application to create a timer for another application, but this

method does work.

Because Win32s runs on top of Windows 3.1 and shares many of its

characteristics, timers are owned by the application that calls SetTimer().

The timer event terminates when the application that owns the timer

terminates.

Additional reference words: 1.00 1.10 1.20

KBCategory: kbprg

KBSubcategory: W32s


Win32s Device-Independent Bitmap Limit

PSS ID Number: Q115084

Authored 18-May-1994	Last modified 06-Jun-1995

The information in this article applies to:

 - Microsoft Win32s, versions 1.1, 1.15, 1.2, and 1.25a

Under versions of Win32s prior to 1.25, a device-independent bitmap (DIB)

is limited to a size of 2.3 MB. This size was chosen to accomodate a bitmap

of 1024 by 768 pixels at 24 bits per pixel.

In Win32s 1.25a, this limit was increased to 1280 by 1024 pixels at 24 bits

per pixel.

This limit can cause a variety of problems to occur, such as painting

problems with SetDIBitstoDevice() if a larger bitmap is used.

Additional reference words: 1.10 1.20

KBCategory: kbprg

KBSubcategory: W32s


Win32s Message Queue Checking

PSS ID Number: Q97918

Authored 25-Apr-1993	Last modified 22-Mar-1995

The information in this article applies to:

 - Microsoft Win32s versions 1.1 and 1.2

Win32-based applications that are designed to run with Win32s need to check

the message queue through a GetMessage() or PeekMessage() call to avoid

locking up the system. With Windows NT this is not a problem, because the

input model is desynchronized. That is, each thread has its own input event

queue rather than having one queue for the entire system. In a synchronous

input model, one application can block all of the others by allowing the

single system queue to fill up with its messages. With Windows NT, an

application that lets its input queue fill up will not affect other

applications.

For more information, please see chapter 3 of the "Win32s Programmer's

Reference".

Additional reference words: 1.10 1.20

KBCategory: kbprg

KBSubcategory: W32s


Win32s NetBIOS Programming Considerations

PSS ID Number: Q104314

Authored 13-Sep-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32s version 1.0, 1.1, and 1.2

This article addresses common questions about NetBIOS programming under

Win32s.

Under Windows 3.1, you normally do not issue a RESET command due to the

common name table. When running your Win32-based application under Windows

version 3.1, you may issue a NetBIOS RESET command.  Win32s keeps an

internal list of all the names added in the Windows 3.1 NetBIOS name table

by Win32 processes. A RESET on Win32s mimics the RESET on Windows NT by

clearing the names added by that process from the system-wide name table.

As a result, issuing a RESET command as the first NetBIOS command (as

required by Windows NT) on Win32s does not clear out all of the names.

The Windows 3.1 NetBIOS VxD expects memory allocated for the NetBIOS

Control Block (NCB) and the data buffer (NCB.ncb_buffer) to be allocated

with GlobalAlloc(). The VxD will lock the specified memory page. If a Win32-

based application running under Win32s passes the Netbios() command virtual

memory, Netbios() will return error 0x22, indicating that there are too

many commands outstanding. On Win32s, each piece of memory that might

pass through Netbios() must be allocated with GlobalAlloc().

The Win32s NetBIOS thunk layer translates the ncb_buffer pointer in the NCB

itself. The translation back from a 16-bit to original 32-bit pointer is

done for asynchronous commands in the Win32s private post routine. A

problem might occur when an application checks the NCB and finds that

the netbios() command is completed (ncb_retcode == NRC_GOODRET), but the

Win32s post routine was not called yet. The ncb_buffer has not been

translated back. The best way to avoid problems is to define and use a post

routine. At that point you are sure that the netbios() command is completed

and the NCB is correct. If you don't want to use a post routine, you should

make sure that the command was completed by checking the the ncb_retcode

field and verifying that the ncb_buffer pointer is a 32-bit pointer.

There is also no need to page lock the NetBIOS post routine code under

Win32s. NetBIOS post routine on Win32s is not called at interrupt time. The

post routine is called in the context of the process, and therefore there

is no need to page lock the post routine code.

Additional reference words: 1.00 1.10 1.20

KBCategory: kbprg

KBSubcategory: W32s


Win32s OLE 16/32 Interoperability

PSS ID Number: Q123422

Authored 01-Dec-1994	Last modified 10-Jan-1995

The information in this article applies to:

 - Microsoft Win32s version 1.20

The OLE support provided in Win32s version 1.2 provides full 16/32

interoperabililty for local servers (EXE servers). Therefore, you can

embed a 32-bit object implemented by a local server in a 16-bit container

and vice-versa.

There is no built-in support in Win32s for 16/32 interoperability for

in-process servers (DLL servers). However, you can use Universal Thunks

to load a 16-bit DLL in the context of a 32-bit process. This allows you

to embed a 16-bit object implemented by a DLL server in a 32-bit

container. However, it is quite complicated to write this code because:

 - Any OLE interface has a hidden "this" pointer which you must handle in

   your thunking code.

 - OLE uses callbacks. If your 32-bit container calls IDataObject:DAdvise,

   then your 16-bit server may call back into the 32-bit side with the

   Advise interface. Your thunking code will have to handle this type of

   conversation.

NOTE: Embedding a 32-bit object implemented by an in-process server in a

16-bit container is supported under Windows NT 3.5. However, this

functionality may not work correctly for your in-process server because

IDispatch and any custom interfaces do not work.

Additional reference words: 1.20

KBCategory: kbole

KBSubcategory: W32s


Win32s Translated Pointers Guaranteed for 32K

PSS ID Number: Q100833

Authored 29-Jun-1993	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32s versions 1.0, 1.1, and 1.2

SUMMARY

Translated pointers are guaranteed to be valid only for 32K, rather than

64K, which selectors are usually limited to. This limitation is for

performance reasons.

Selectors are tiled every 32K. A 0:32 pointer can be quickly translated

into a 16:16 pointer, which will be valid for a minimum of 32K. In other

words, the offset portion of the 16:16 pointer is not guaranteed to be 0

(zero) when translated. As a result, even though the translated selectors

have a limit of 64K, the offset passed to the 16-bit side may be as large

as 32K-1.

Selectors are created on a 32K alignment so that if you pass several

pointers to the same range, the Universal Thunk (UT) uses the same

selector. Selectors are freed when application terminates.

The alternative is to create a selector for each and every translation,

which is very slow.

MORE INFORMATION

For any given address, there are two selectors that point to it, but only

one has a limit less than 32K:

           +-------+-------+-------+-------+-------+-------+

           |Selector 2(64K)|Selector 4(64K)|Selector 6(64K)|

   +-------+-------+-------+-------+-------+-------+-------+

   |Selector 1(64K)|Selector 3(64K)|Selector 5(64K)|       |

   +-------+-------+-------+-------+-------+-------+-------+

   |  32K  |  32K  |  32K  |  32K  |  32K  |  32K  |  32K  |

   +-------+-------+-------+-------+-------+-------+-------+

Under Win32s, 16-bit and 32-bit applications share the same global data

space; therefore, it is possible to share a buffer of up to 64K in size

with a far pointer or more than 64K with a huge pointer by doing the

following:

1. Do a GlobalAlloc() on the 32-bit side. Be sure to use GMEM_MOVEABLE.

2. Copy the data.

3. Send the handle to the 16-bit side.

4. Get a pointer to the data on the 16-bit side by using GlobalLock().

When you pass a pointer to a block that was allocated via GlobalAlloc()

from the 32-bit side, it costs no selectors. The translated pointer is

valid until the memory is freed.

Additional reference words: 1.00 1.10 1.20

KBCategory: kbprg

KBSubcategory: W32s


Win32s Version 1.25a Limitations

PSS ID Number: Q131896

Authored 22-Jun-1995	Last modified 26-Jun-1995

The information in this article applies to:

 - Microsoft Win32s, version 1.25a

SUMMARY

The following lists the limitations of Win32s, not including the complete

list of unsupported Win32 APIs. For information on which Win32 APIs are and

are not supported under Win32s, please see the "Win32 Programmer's

Reference" or the WIN32API.CSV file.

MORE INFORMATION

 - Thread creation is not supported.

 - Win32s uses the Windows version 3.1 nonpreemptive scheduling mechanism.

 - 32-bit processes should be started from a 16-bit application through

   WinExec() or Int 21 4B. LoadModule() does not start a 32-bit process.

 - Win32-based applications cannot use the EM_SETHANDLE or EM_GETHANDLE

   messages to access the text in a multiline edit control. These messages

   allow the sharing of local memory handles between an application and

   USER.EXE. In Win32s, an application's local heap is 32-bit, so USER.EXE

   cannot interpret a local handle. To read and write multi-line edit

   control text, an application should use WM_GETTEXT and WM_SETTEXT.

   Text for multi-line edit controls is stored in the 16-bit local heap in

   DGROUP, which is allocated by Windows version 3.1 for the WIN32S.EXE

   stub loaded before each Win32-based application is loaded. This means

   that the size of edit control text is limited to somewhat less than 64K.

 - The CBT hook thunks do not copy back the contents of structures, so any

   changes are lost.

 - Win32-based applications should not call through the return from

   SetWindowsHook(). SetWindowsHook() returns a pointer to the next hook in

   the chain. To call this function, the application should call

   DefHookProc(), and pass a pointer to a variable where this address is

   stored. Because Win32s simulates the old hook API in terms of the new,

   SetWindowsHook() actually passes back a hook handle, not a function

   pointer.

 - Resource integer IDs must be 16-bit values.

 - PostMessage() and PeekMessage() do not thunk structures. These functions

   do not allocate space for repacking structures, because there is no way

   to know when to free up the space.

 - Private application messages should not use the high word of wParam.

   Win32s uses Windows to deliver window messages. For unknown messages,

   wParam is truncated to make it fit into 16-bits. Therefore, Win32-based

   applications should not put 32-bit quantities into the wParam of

   privately-defined messages, which are unknown to the thunk layer.

 - After calling FindText(), an application cannot directly access the

   FINDREPLACE structure. When an application calls the common dialog

   function FindText(), it passes a FINDREPLACE structure. The FindText()

   dialog communicates with the owner window through a registered message,

   in which the lParam points to the structure. The thunks repack this

   structure in place, so that unless the application is processing the

   registered message, it should not access the structure.

 - Subclassing a window that owns a FindText() common dialog does not work.

   The FindText() thunk repacks the FINDREPLACE structure in place. This

   means that 32-bit window procedures cannot subclass 16-bit owners of

   FindText() dialogs without likely trashing four bytes beyond the end of

   the structure, because the 32-bit FINDREPLACE is four bytes bigger than

   the 16-bit version.

   For 32-bit owners of the dialog box, there are also problems. Whenever

   the structure might be referenced by 16-bit code, it needs to be in the

   16-bit format. However, when the FindText() dialog box terminates, the

   structure needs to be in 32-bit format so that the application can read

   the final values. The dialog box indicates to its owner that it is about

   to be destroyed by sending the commdlg_FindReplace message with the

   FR_DIALOGTERM bit set in the Flags field of the FINDREPLACE structure.

   After sending this message, the FindText() dialog box does not reference

   the structure anymore, so the commdlg_FindReplace thunk leaves it in

   32-bit format.

   The problem occurs when the owner has been subclassed. Once the message

   has moved to the 32-bit side, the structure will not be reconverted to

   16-bits. Suppose the dialog box owner was subclassed by a 16-bit window

   procedure, which was in turn subclassed by a 32-bit window procedure.

   When a message is sent to the owner, it will first go to 32-bits, then

   to 16-bits, then back to 32-bits to the original window procedure:

   1. 16->32 message sent to 32-bit subclasser (struct repacked to 32-bits)

   2. 32->16 message sent to 16-bit subclasser (struct not repacked)

   3. 16->32 message sent to 32-bit original WndProc (struct not repacked)

   The 16-bit subclasser cannot interpret the message parameters because

   they are in 32-bit format. Between steps 2 and 3, the structure is not

   repacked because it's already in 32-bit format.

   Therefore, when a Win32-based application calls FindText(), allocate the

   following:

   1. A structure that contains the htask of WIN32S.EXE.

   2. The original 32-bit FINDREPLACE pointer.

   3. A count of the number of times the structure has been thunked without

      returning.

   4. A 16-bit format copy of FINDREPLACE.

   The structure is repacked into the 16-bit version and this copy is

   passed to Windows. The count is initially 0. When the

   commdlg_FindReplace message is sent in either direction (16->32 or

   32->16), repack the structure on the stack. If it was originally 32-bit,

   increment the count. When returning in either direction, unpack the

   structure and, if originally 32-bit, decrement the count.

   If the Flags field of the structure has the FR_DIALOGTERM bit set, the

   structure is originally 32-bit, and the count goes to 0 on a return,

   then repack the structure back to the original 32-bit space.

 - DDE messages are always posted, not sent, except for two:

   WM_DDE_INITIATE and WM_DDE_ACK (responding to the former). The sent form

   of WM_DDE_ACK is different from the posted form. When sent, no thunking

   of lParam is necessary when going between 16- and 32-bit format.

   However, when posting, the lParam parameter is repacked as two DWORDS

   into private memory, allocated by COMBO.DLL (or by USER.DLL in Windows

   NT). The thunk layer makes this distinction through the InSendMessage()

   function. Therefore, a Win32-based application should not do anything in

   the processing of a WM_DDE_INITIATE message that would cause the return

   code from InSendMessage() to be FALSE.

 - The following DDE messages are handled differently by applications under

   Windows and Win32:

   WM_DDE_ACK

   WM_DDE_ADVISE

   WM_DDE_DATA

   WM_DDE_EXECUTE

   WM_DDE_POKE

   Because of the widening of handles, there is not enough space in the

   Win32 message parameters for all the Windows data. Win32-based

   applications are required to call helper functions that package the data

   into memory (DDEPACK structure) referenced by a special handle. Win32s

   implements the helper functions and allocates the DDEPACK structure on

   behalf of 16-bit code when necessary.

   As with other memory handles shared through DDE, there are rules

   concerning who frees the memory allocated by these helper routines.

   lParam = PackDDElParam(...)

   if (PostMessage(...,lParam))

      receiving window has obligation of freeing memory

      lParam now invalid for this process

   else

      FreeDDElParam(...,lParam)

   A Win32s hook procedure that has called CallNextHookProc() should not

   use the lParam handle as the later's return code indicates that the

   message has been processed. The hooks that could possibly process a DDE

   message are:

   WH_DEBUG

   WH_HARDWARE

   WH_KEYBOARD

   WH_MOUSE

   WH_MSGFILTER

   WH_SYSMSGFILTER

   In each case, if the hook proc (and therefore CallNextHookEx()) returns

   a non-zero value, the message was either discarded or processed.

   Windows-based procedures should not use the lParam of a DDE message

   after handing it off to any other message API because they cannot know

   if the message has been processed, so they must assume that it has been.

 - WDEB386 does not support FreeSegment() for 32-bit segments. Win32s

   Kernel Debugger support depends on it.

 - The maximum size of shared memory is limited by Windows memory.

   CreateFileMapping(hFile,

                     lpsa,

                     fdwProtect,

                     dwMaximumSizeHigh,

                     dwMaximumSizeHigh,

                     lpszMapName)

   lpsa              - Ignored.

   dwMaximumSizeHigh - Must be zero.

   MapViewOfFile(hMapObject,

                 fdwAccess,

                 dwOffsetHigh,

                 dwOffsetLow,

                 cbMap)

   dwOffsetHigh - Must be zero.

 - SetClipbrdData() must be used only with a global handle. Otherwise, the

   data can't be accessed by other applications.

 - Win32s supports printing exactly as Windows version 3.1 does. Win32s

   does not add beziers, paths, or transforms to GDI; to allow applications

   to use these features on PostScript printers, you must call the Escape

   function with the appropriate escape codes.

   Applications link to Windows version 3.1 printer drivers through

   LoadLibrary() and GetProcAddress(), which have special support for this

   purpose. There is no general mechanism allowing a Win32-based

   application to link to a 16-bit DLL.

 - Win32s does not support these escape codes:

   BANDINFO                 ;24

   GETSETPAPERBINS          ;29

   ENUMPAPERMETRICS         ;34

   EXTTEXTOUT               ;512

   SETALLJUSTVALUES         ;771

 - Integer atoms must be in the range 0-0x3FFF. This restriction is

   necessary for the current implementation of the window properties API

   thunks: SetProp(), GetProp(), RemoveProp(), EnumProps(), and

   EnumPropsEx(). Integer atoms above 0x4000 are rejected by the thunk

   layer.

 - Arrays must fit in 64K after converting to 16-bit format. An array

   passed to a function such as SetCharABCWidths() or Polyline() must fit

   within 64K after its elements have been converted to their 16-bit form.

   Its 32-bit form may be bigger than 64K.

 - All Windows version 3.1 APIs that return void, return 1 to the

   Win32-based application.

   You can simulate a boolean return value by validating the API parameters

   and returning FALSE if one is bad. However, you can't always do complete

   validation, and if the API is called, you must assume it succeeded

   unless there is a method to verify whether or not it succeeded.

 - Win32 child window IDs must be sign-extended 16-bit values. This

   excludes the use of 32-bit pointer values as child IDs.

 - When calling PeekMessage(), a Win32-based application should not filter

   any messages for Windows internal window classes (button, edit,

   scrollbar, and so on). The messages for these controls are mapped to

   different values in Win32, and checking for the necessity of mapping is

   time-consuming.

 - The dwThreadId parameter in SetWindowsHookEx() is ignored. The

   dwThreadId is translated to hTask in Windows 3.1. There's a bug in

   Windows version 3.1 where if hTask!=NULL, the call may fail.

 - Floating point (FP) emulation by exception cannot be performed in 16-bit

   applications. When tasks are switched between applications, the CR0-EM

   bit state is not preserved in order to support 32-bit application FP

   emulation by exception without breaking the existing 16-bit applications

   that use FP instructions. The CR0-EM bit is assumed to be cleared during

   execution of 16-bit application FP instructions. Upon executing a 16-bit

   application FP instruction, the bit is cleared and reset when switching

   back to a 32-bit application. The CR0-EM bit management is done in the

   Win32s VxD, thus disabling the possibility of getting an int 7 exception

   just by setting the CR0-EM bit in a 16-bit application.

 - EndDialog() nResult parameter is sign-extended. Applications specify the

   return value for the DialogBox() function by way of the nResult

   parameter to the EndDialog() API. This parameter is of type int, which

   is 32-bit in Win32s. However, this value is thunked through to the

   Windows version 3.1 EndDialog() API, which truncates it to a 16-bit

   value. Win32s sign-extends the return code from DialogBox().

 - GetClipBox() returns SIMPLEREGION(2) and COMPLEXREGION(3). Because

   Windows NT is a preemptive multitasking system, GetClipBox() on Windows

   NT never returns SIMPLEREGION(2). The reason for this is that between

   the time the API was called and the time the application gets the

   result, the region may change. Win32s can return both SIMPLEREGION(2)

   and COMPLEXREGION(3).

 - PeekMessage() filtering for posted messages (hWnd==-1) is not supported.

   The hWnd is replaced with NULL.

 - Message queue length is limited to Windows default: 8 or whatever

   length was set by DefaultQueueSize=n in the WIN.INI file. This limit may

   be increased in the future to a larger size, but there will always be a

   limit.

 - GetFileTime() and SetFileTime() process only the lpLastWriteTime

   parameter and return an error if this parameter is not supplied.

   In the DEBUG version, supplying the other parameters causes a warning

   message to be displayed.

 - The precision of the time of a file is two seconds (MS-DOS limitation).

 - CreateProcess has the following limitations:

    - fdwCreate - Only DEBUG_PROCESS and DEBUG_ONLY_THIS_PROCESS are

      supported.

    - Process priority is always NORMAL.

    - lpsaProcess, lpsaThread - Security information ignored.

 - Always use device-independent bitmaps for color bitmaps. Win32s supports

   the four Win32 device-dependent bitmap APIs. These are device-dependent

   in the sense that the bitmap bits are supplied without a color table to

   explain their meaning.

   CreateBitmap

   CreateBitmapIndirect

   GetBitmapBits

   SetBitmapBits

   These are well defined and fully supported for monochrome bitmaps. For

   color bitmaps, these APIs are not well defined and Win32s relies on the

   Windows display driver for their support. This means that an application

   cannot know the format of the bits returned by GetBitmapBits() and

   should not attempt to directly manipulate them. The values returned by

   GetDeviceCaps() for PLANES and BITSPIXEL and the values returned by

   GetObject() for a bitmap do not necessarily indicate the format of the

   bits returned by GetBitmapBits(). It is possible for the GDI DIB APIs to

   be unsupported on some displays. However, it is now rare for display

   drivers to not support DIBs. The one case where you may encounter a lack

   of DIB support is with printer drivers, which may not support the

   GetDIBits() API, though most do support the SetDIBits() API.

   Win32s does not transform the bits in any way when passing them on to a

   Windows version 3.1 API. When running an application that creates a

   device-dependent bitmap via CreateBitmap() or CreateBitmapIndirect(), be

   aware that the bits it is passing in may not be in the right format for

   the device. Windows NT takes care of this by treating the bits as a DIB

   whose format is consistent with the PLANES and BITSPIXEL values; but

   Win32s simply passes them through.

 - GetPrivateProfileString() and GetProfileString() return an error when

   the lpszSection parameter is NULL. Under Windows NT, they give all the

   sections in the .INI file.

 - String resources are limited to a length of 255, as they were in Windows

   version 3.1.

 - TLS locations are the same in all processes for a specific DLL. This is

   because Win32s does not support per-instance data for DLLs. The TLS

   locations are unique per DLL. Each DLL should call TlsAlloc() only once

   if it is runing on Win32s. The index returned will be valid for all

   Win32 processes.

 - GlobalCompact() is thunked through to Windows version 3.1

   GlobalCompact(). This API has no effect on memory allocated through

   VirtualAlloc(), which does not come from the Windows global heap.

 - GetVolumeInformation() does not support the Volume ID.

 - GetFileInformationByHandle() create time and access time are always 0

   (MS-DOS limitations). The volume id, file index low/high are also 0

   (Win32s limitations). This affects the CRT fstat() as well.

 - CreatePolyPolygonRgn() requires a closed polygon, as it does under

   Windows version 3.1. If the polygons are not closed, the Windows NT call

   closes the polygons for you. In Windows version 3.1 or Win32s, if the

   polygons are not closed, the call does not create the region correctly,

   or it returns an error for an invalid parameter.

 - Win32s does not support the DIB_PAL_INDICES option for SetDIBits(). It

   will be supported in a future release. DIB_PAL_PHYSINDICES and

   DIB_PAL_LOGINDICES are not supported either.

 - The WH_FOREGROUNDIDLE hook type is not supported. Windows version 3.1

   does not provide the necessary support.

 - The brush styles BS_DIBPATTERNPT and BS_PATTERN8X8 are not supported and

   cause an error to be returned.

 - The hFile in DLL and PROCESS DEBUG events is not supported in Win32s

   because there is no support for duplicating file handles between

   processes (basically an MS-DOS limitation).

   There are two way to access the image bytes: ReadProcessMemory() or open

   the file in compatibility mode using the name provided in lplpImageName.

 - Under Windows NT, NetBIOS keeps a different name table for each process.

   On Win32s, there is only one NetBIOS name table for the system. Each

   name (group or unique) added by a process is kept in a doubly-linked

   list. Through NCBRESET or by destroying the process, you delete all the

   names that were added by the process. Win32s does not implement the full

   NetBIOS 3.0 specification, which has a separate name table per process.

 - When calling 32-bit code from 16-bit code with UT (for example, from an

   interrupt routine), the stack must be at least 10K. The interrupt

   routine must assure that the stack will be big enough.

 - GetThreadContext() and SetThreadContext() can be called only from within

   an exception handler or an exception debug event. At all other times,

   these functions return FALSE and the error code is set to

   ERROR_CAN_NOT_COMPLETE.

 - CreateProcess() PROCESS_INFORMATION is not supported for 16-bit

   applications. A valid structure must be passed to CreateProcess(), but

   the function fills all the fields with NULLs and zeroes.

 - Win32s does not support the Windows NT event mechanism, therefore the

   ncb_event field in NCB structure is not supported.

 - CreateFileMapping() does not support SEC_NOCACHE or SEC_NOCOMMIT. The

   call fails with ERROR_INVALID_PARAMETER.

 - WaitForDebugEvent() does not fully support the dwTimeout parameter. If

   the parameter is zero, WaitForDebugEvent() behaves the same as under

   Windows NT. Otherwise, the parameter is treated as if it were INFINITE.

   However, the function returns if any messages arrive. If a message

   arrives, the return value is FALSE. The calling process should call

   SetLastError(0) before calling WaitForDebugEvent() and examine

   GetLastError() if WaitForDebugEvent() returns FALSE. If the error is

   zero, it means that a message arrived and the process should process

   the message. Otherwise, the process should handle the error.

 - If a section contains duplicated keys, GetPrivateProfileSection()

   returns the duplicated keys, but all values are the same as the value

   of the first key.

   Suppose a section contains these keys:

      key1=x1

      key2=x2

      key2=x3

      key2=x4

      key3=x5

      key2=x6

   The values returned are:

      key1=x1

      key2=x2

      key2=x2

      key2=x2

      key3=x5

      key2=x2

 - String IDs of resources should not be longer than 255 characters.

 - String IDs must be in the English language. The resources themselves

   can be mulitilingual.

 - GetDlgItemInt() only translates up to 16-bit int/unsigned values. This

   is because it gets its value from Windows, which translates only 16-bit

   values. As a workaround, call GetDlgItem() and translate the value

   using atoi() or sscanf().

Additional reference words: limits

KBCategory: kbprg

KBSubcategory: W32s


WinDbg Message "Breakpoint Not Instantiated"

PSS ID Number: Q99953

Authored 10-Jun-1993	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

The WinDbg message "Breakpoint Not Instantiated" indicates that the

debugger could not resolve an address. This can happen for several reasons:

 - A specified symbol does not exist. In this case, check for

   misspelling and check the state of the "ignore case" option if the

   symbol contains mixed case.

   -or-

 - The symbol exists, but the EXE or DLL was built with the wrong

   debugging information, or none at all. Use the -Zi and -Od compiler

   options and use the -debug:full, -debugtype:cv, and -pdb:none linker

   options.

   -or-

 - The symbol exists, but it is in a module that has not yet been

   loaded. If the symbol is in a DLL that is dynamically loaded the

   breakpoint was probably set before the DLL was loaded. The message

   is harmless, because WinDbg will instantiated the BP when the module

   is loaded.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbtool

KBSubcategory: TlsWindbg


Window Message Priorities

PSS ID Number: Q96006

Authored 03-Mar-1993	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

Under Windows NT, messages have the same priorities as with Windows 3.1.

With normal use of GetMessage() (passing zeros for all arguments except the

LPMSG parameter) or PeekMessage(), any message on the application queue is

processed before user input messages. And input messages are processed

before WM_TIMER and WM_PAINT "messages."

MORE INFORMATION

For example, PostMessage() puts a message in the application queue.

However, when the user moves the mouse or presses a key, these messages are

placed on another queue (the system queue in Windows 3.1; a private, per-

thread input queue in Win32).

GetMessage() and its siblings do not look at the user input queue until the

application queue is empty. Also, the WM_TIMER and WM_PAINT messages are

not handled until there are no other messages (for the thread) to process.

The WM_TIMER and WM_PAINT messages can be thought of as boolean toggles,

because multiple WM_PAINT or WM_TIMER messages waiting in the queue will be

combined into one message. This reduces the number of times a window must

repaint itself.

Under this scheme, prioritization can be considered tri-level. All posted

messages are higher priority than user input messages because they reside

in different queues. And all user input messages are higher priority than

WM_PAINT and WM_TIMER messages.

The only difference in the Windows NT model from the Windows versions 3.x

model is that there is effectively a system queue per thread (for user

input messages) rather than one global system queue. The prioritization

scheme for messages is identical.

For information concerning SendMessage() from one thread to another, please

see the following article(s) in the Microsoft Knowledge Base:

   ARTICLE-ID: Q95000

   TITLE     : SendMessage() in a Multithreaded Environment

Additional reference words: 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrWndw


Window Owners and Parents

PSS ID Number: Q84190

Authored 04-May-1992	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.1 and 3.0

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

In the Windows environment, two relationships that can exist between

windows are the owner-owned relationship and the parent-child

relationship.

The owner-owned relationship determines which other windows are

automatically destroyed when a window is destroyed. When window A is

destroyed, Windows automatically destroys all of the windows owned by

A.

The parent-child relationship determines where a window can be drawn

on the screen. A child window (that is, a window with a parent) is

confined to its parent window's client area.

This article discusses these relationships and some Windows functions

that provide owner and parent information for a given window.

MORE INFORMATION

A window created with the WS_OVERLAPPED style has no owner and no

parent. Alternatively, the desktop window can be considered the owner

and parent of a WS_OVERLAPPED-style window. A WS_OVERLAPPED-style

window can be drawn anywhere on the screen and Windows will destroy

any existing WS_OVERLAPPED-style windows when it shuts down.

A window created with the WS_POPUP style does not have a parent by

default; a WS_POPUP-style window can be drawn anywhere on the screen.

A WS_POPUP-style window will have a parent only if it is given one

explicitly through a call to the SetParent function.

The owner of a WS_POPUP-style window is set according to the

hWndParent parameter specified in the call to CreateWindow that

created the pop-up window. If hWndParent specifies a nonchild window,

the hWndParent window becomes the owner of the new pop-up window.

Otherwise, the first nonchild ancestor of hWndParent becomes the owner

of the new pop-up window. When the owner window is destroyed, Windows

automatically destroys the pop up. Note that modal dialog boxes work

slightly differently. If hWndParent is a child window, then the owner

window is the first nonchild ancestor that does not have an owner (its

top-level ancestor).

A window created with the WS_CHILD style does not have an explicit

owner; it is implicitly owned by its parent. A child window's parent

is the window specified as the hWndParent parameter in the call to

CreateWindow that created the child. A child window can be drawn only

within its parent's client area, and is destroyed along with its

parent.

An application can change a window's parent by calling the SetParent

function after the window is created. Windows does not provide a

method to change a window's owner.

Windows provides three functions that can be used to find a window's

owner or parent:

 - GetWindow(hWnd, GW_OWNER)

 - GetParent(hWnd)

 - GetWindowWord(hWnd, GWW_HWNDPARENT)

GetWindow(hWnd, GW_OWNER) always returns a window's owner. For child

windows, this function call returns NULL. Because the parent of the

child window behaves similar to its owner, Windows does not maintain

owner information for child windows.

The return value from the GetParent function is more confusing.

GetParent returns zero for overlapped windows (windows with neither

the WS_CHILD nor the WS_POPUP style). For windows with the WS_CHILD

style, GetParent returns the parent window. For windows with the

WS_POPUP style, GetParent returns the owner window.

GetWindowWord(hWnd, GWW_HWNDPARENT) returns the window's parent, if it

has one; otherwise, it returns the window's owner.

Two examples of how Windows uses different windows for the parent and

the owner to good effect are the list boxes in drop-down combo boxes

and the title windows for iconic MDI (multiple document interface)

child windows.

Due to its size, the list box component of a drop-down combo box may

need to extend beyond the client area of the combo box's parent

window. Windows creates the list box as a child of the desktop window

(hWndParent is NULL); therefore, the list box will be clipped only by

the size of the screen. The list box is owned by the first nonchild

ancestor of the combo box. When that ancestor is destroyed, the list

box is automatically destroyed as well.

When an MDI child window is minimized, Windows creates two windows: an

icon and the icon title. The parent of the icon title window is set to

the MDI client window, which confines the icon title to the MDI client

area. The owner of the icon title is set to the MDI child window.

Therefore, the icon title is automatically destroyed with the MDI

child window.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrWndw


WindowFromPoint() Caveats

PSS ID Number: Q65882

Authored 26-Sep-1990	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

When the coordinates passed to the WindowFromPoint() function correspond to

a disabled, hidden, or transparent child window, the handle of that

window's parent is returned.

To retrieve the handle of a disabled, hidden, or transparent child window,

given a point, the ChildWindowFromPoint() function must be used.

MORE INFORMATION

The following code fragment demonstrates the use of the

ChildWindowFromPoint() function during the processing of a WM_MOUSEMOVE

message. This code finds the topmost child window at a given point,

regardless of the current state of the window.

In this fragment, hWnd is the window receiving this message and is assumed

to have captured the mouse via the SetCapture() function.

HWND  hWndChild, hWndPoint;

POINT pt;

    .

    .

    .

    case WM_MOUSEMOVE:

        pt.x = LOWORD(lParam);

        pt.y = HIWORD(lParam);

        /*

         * Convert point to screen coordinates. When the mouse is

         * captured, mouse coordinates are given in the client

         * coordinates of the window with the capture.

         */

        ClientToScreen(hWnd, &pt);

        /*

         * Get the handle of the window at this point. If the window

         * is a control that is disabled, hidden, or transparent, then

         * the parent's handle is returned.

         */

        hWndPoint = WindowFromPoint(pt);

        if (hWndPoint == NULL)

            break;

        /*

         * To look at the child windows of hWnd, screen coordinates

         * need to be converted to client coordinates.

         */

        ScreenToClient (hWndPoint, &pt);

        /*

         * Search through all child windows at this point. This

         * will continue until no child windows remain.

         */

        while (TRUE)

            {

            hWndChild = ChildWindowFromPoint(hWndPoint, pt);

            if (hWndChild && hWndChild != hWndPoint)

                hWndPoint = hWndChild;

            else

                break;

            }

        // Do whatever processing is desired on hWndPoint

        break;

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrWndw


Windows 95 Network Programming Support

PSS ID Number: Q125702

Authored 01-Feb-1995	Last modified 06-Apr-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

Windows 95 supports the network programming interfaces listed in the table

below:

Interface        Comments

--------------------------------------------------------------------------

Microsoft RPC    Supports a subset of the protocol sequences specified in

                 Microsoft RPC 1.0. For additional information, please see

                 the following article(s) in the Microsoft Knowledge Base:

                    ARTICLE-ID:Q125701

                    TITLE     :Windows 95 RPC: Supported Protocol Sequences

Windows Sockets  Supports the TCP/IP and IPX/SPX network transports. For

   (WinSock)     additional information, please see the

                 following article(s) in the Microsoft Knowledge Base:

                    ARTICLE-ID:Q125704

                    TITLE     :Multiprotocol Support for Windows Sockets

NetBIOS          Supports NetBIOS v3.0, including the Microsoft extension

                 function NCBENUM.

Network DDE      Includes the NetDDE agent and a 16 bit NetDDE API DLL.

 (NetDDE)        32-bit applications must thunk to NDDEAPI.DLL. For

                 additional information, please see the following

                 article(s) in the Microsoft Knowledge Base:

                    ARTICLE-ID:Q125703

                    TITLE     :Windows 95 Support for Network DDE

Additional reference words: 4.00

KBCategory: kbprg kbnetwork

KBSubcategory:  NtwkMisc


Windows 95 RPC: Supported Protocol Sequences

PSS ID Number: Q125701

Authored 01-Feb-1995	Last modified 06-Apr-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

The Windows 95 RPC runtime libraries support a subset of the protocol

sequences introduced in Microsoft RPC 1.0. Here is the list of supported

protocol sequences:

  Protocol Sequence  Comments

  -----------------------------------------------------------------

  ncacn_ip_tcp       Requires TCP/IP installation

  ncacn_nb_nb        NetBEUI is the only supported NetBIOS transport

  ncacn_np           Support for client applications only

  ncacn_spx          Requires IPX/SPX installation

  ncalrpc            Local communication only

Regarding ncacn_np: Windows 95 does not support server-side named pipes,

so ncacn_np is not a valid protocol sequence for RPC servers running on

Windows 95. However, ncacn_np is valid for RPC client applications.

Additional reference words: 4.00 NETWORKING

KBCategory: kbnetwork

KBSubcategory: NtwkRpc


Windows 95 Support for LAN Manager APIs

PSS ID Number: Q125700

Authored 01-Feb-1995	Last modified 20-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

Windows 95 supports a subset of the Microsoft LAN Manager API. This is

a list of the supported functions:

  NetAccessAdd

  NetAccessCheck

  NetAccessDel

  NetAccessEnum

  NetAccessGetInfo

  NetAccessGetUserPerms

  NetAccessSetInfo

  NetConnectionEnum

  NetFileClose2

  NetFileEnum

  NetSecurityGetInfo

  NetServerGetInfo

  NetServerSetInfo

  NetSessionDel

  NetSessionEnum

  NetSessionGetInfo

  NetShareAdd

  NetShareDel

  NetShareEnum

  NetShareGetInfo

  NetShareSetInfo

Windows 95 support for these functions differs from Windows NT in two

ways. First, since Windows 95 doesn't support Unicode, these functions

require ANSI strings. Second, Windows 95 exports the Lan Manager

functions from SVRAPI.DLL instead of NETAPI32.DLL. If an attempt is

made to run a native Windows NT application on Windows 95, the

following error will result:

  "The <application> file is linked to missing export NETAPI32.DLL

   <Net...API>"

To handle these differences, applications targeted to both Windows NT

and Windows 95 should do the following:

1. Avoid importing Lan Manager functions from NETAPI32.DLL at link time.

   Instead, applications should do a run time version check and

   dynamically link to NETAPI32.DLL for Windows NT or SVRAPI.DLL for

   Windows 95.

   For additional information on version checking, please see the following

   article(s) in the Microsoft Knowledge Base:

      ARTICLE-ID:Q92395

      TITLE     :Determining System Version from a Win32-based Application

2. Make sure the application doesn't depend on the presence of unsupported

   API's.

3. When calling Lan Manager API's, pass strings using a character set

   appropriate for the host operating system. Use Unicode strings for

   Windows NT and ANSI strings for Windows 95.

If you are only targetting Windows 95 and wish to use SVRAPI.DLL, SVRAPI.H

and SVRAPI.LIB are included in the Windows 95 DDK. NOTE: The formal

parameter lists for the LAN Manager APIs may be slightly different between

the header files for Windows NT and Windows 95.

Additional reference words: 4.00 95

KBCategory: kbnetwork

KBSubcategory: NtwkLmapi


Windows 95 Support for Network DDE

PSS ID Number: Q125703

Authored 01-Feb-1995	Last modified 26-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

Network DDE is a technology that allows applications that use the DDE

transport to transparently exchange data over a network.  It consists

of two major components:

1. The NetDDE agent. This is a service that acts as a proxy for the remote

   DDE application. It communicates with all local DDE applications, and

   with remote NetDDE agents using NetBIOS as shown in this chart:

     Machine A                                        Machine B

   +-----------+                                   +-----------+

   |           |                                   |           |

   | DDE App 1 |                                   | DDE App 2 |

   |           |                                   |           |

   +-----------+                                   +-----------+

           ^ |                                        ^ |

           | |                                        | |

           | |                                        | |

           | |                                        | |

           DDE                                        DDE

       Conversation                               Conversation

           | |                                        | |

           | |                                        | |

           | V                                        | V

        +------+                                   +------+

        |NetDDE|                                   |NetDDE|

        | Agent| < ------ NetBIOS session ------ > | Agent|

        +------+                                   +------+

2. A DLL that implements NetDDE API functions such as NDdeShareAdd,

   NDdeShareDel, and so on. This DLL is usually named NDDEAPI.DLL.

In the interests of backwards compatibility, Windows 95 includes a NetDDE

agent and a 16-bit NetDDE API DLL. However, Windows 95 does not include a

32-bit NetDDE API DLL. Consequently, 32-bit applications that use NetDDE

API functions will need to thunk to the 16-bit NETAPI.DLL.

Additional reference words: 4.00

KBCategory: kbnetwork kbprg

KBSubcategory: UsrNetDde


Windows Dialog-Box Style DS_ABSALIGN

PSS ID Number: Q11590

Authored 23-Oct-1987	Last modified 18-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

The Windows dialog-box style DS_ABSALIGN (used in WINDOWS.H) means

"Dialog Style ABSolute ALIGN." Specifying this style in the dialog

template tells Windows that the dtX and dtY values of the DLGTEMPLATE

struct are relative to the screen origin, not the owner of the dialog

box. When this style bit is not set, the dtX and dtY fields are

relative to the origin of the parent window's client area.

Use this term if the dialog box must always start in a specific part

of the display, no matter where the parent window is on the screen.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrDlgs


Windows Does Not Support Nested MDI Client Windows

PSS ID Number: Q74041

Authored 11-Jul-1991	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.1 and 3.0

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

The Microsoft Windows implementation of the multiple document

interface (MDI) does not support nested MDI client windows. In other

words, neither an MDI client window nor an MDI child window can have

an MDI client window as a child.

MORE INFORMATION

A Windows MDI client window is a member of the MDIClient window class,

and the Windows MDI model assumes that the parent of an MDIClient

window is a top-level frame window with a valid menu bar. This

assumption is necessary to implement the basic functionality defined

by the MDI interface, and it precludes the possibility of using nested

MDIClient windows. However, an application can have multiple top-level

windows, and each top-level window can have a separate MDIClient

window as a child.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrMdi


Windows Help PositionWindow Macro Documented Incorrectly

PSS ID Number: Q83911

Authored 23-Apr-1992	Last modified 24-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK, versions 3.5 and 3.51

SUMMARY

In source files for Windows Help, the help author can specify the

size, position, and state of a window with the PositionWindow macro.

MORE INFORMATION

According to page 326 of the "Microsoft Windows Software Development

Kit: Programmer's Reference, Volume 4: Resources," the state parameter

to the PositionWindow macro is either 0 to specify a normal sized

window or 1 to specify a maximized window. This information is

incorrect. The state parameter can assume any of ten different values,

as follows:

           Corresponding

   Value  Windows Constant    Action

   -----  ----------------    ------

     0    SW_HIDE             Hides the window and passes activation to

                              another window.

     1    SW_SHOWNORMAL       Activates and displays a window. If the

                              window is minimized or maximized, Windows

                              restores it to its original size and

                              position.

     2    SW_SHOWMINIMIZED    Activates the window and displays it as an

                              icon.

     3    SW_SHOWMAXIMIZED    Activates the window and displays it as a

                              maximized window.

     4    SW_SHOWNOACTIVATE   Displays a window in its most recent size

                              and position. The window that is currently

                              active remains active.

     5    SW_SHOW             Activates a window and displays it in its

                              current size and position.

     6    SW_MINIMIZE         Minimizes the specified window and

                              activates the top-level window in the

                              window-manager's list.

     7    SW_SHOWMINNOACTIVE  Displays the window as iconic. The window

                              that is currently active remains active.

     8    SW_SHOW             Displays the window in its current state.

                              The window that is currently active remains

                              active.

     9    SW_RESTORE          Same as SW_SHOWNORMAL.

Note that these constants are valid only for Windows and may change if

Help is ported to another platform.

Additional reference words: 3.10 3.50

KBCategory: kbtool

KBSubcategory: TlsHlp


Windows NT 3.5 Hives Not Compatible with Windows NT 3.1

PSS ID Number: Q117872

Authored 11-Jul-1994	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.5

Hives (registry data) saved from a Windows NT 3.5 machine with the

RegSaveKey() API (application programming interface) cannot be restored on

a Windows NT 3.1 machine with RegLoadKey(), because the hive format for

Windows NT 3.5 is different than the Windows NT 3.1 format (it has been

made more efficient). However, Windows NT 3.5 supports both the new and old

(Windows NT 3.1) hive formats, so hives created on a Windows NT 3.1 machine

can be used on a Windows NT 3.5 machine.

To create a hive on Windows NT 3.5 that can be used on Windows NT 3.1, use

the Win32 registry APIs to read the registry key by key, and save the

values in your own text format. Use the APIs to restore the registry

information on either version of Windows NT.

Additional reference words: 3.50

KBCategory: kbprg

KBSubcategory: BseMisc


Windows NT Servers in Locked Closets

PSS ID Number: Q90083

Authored 08-Oct-1992	Last modified 07-Mar-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

SUMMARY

Some installations are required to restrict access to a server such that

access to the server's keyboard/mouse is unavailable to most personnel.

Such a server is referred to as a server in a locked closet.

The server administrators may provide an emergency reset button to end

users (for example, factory floor workers) in case the system locks up and

no administrators are present. In the case where an emergency reset button

cannot be provided, an administrator must come and physically unlock the

closet in order to get the system up again.

Windows NT requires that the user press CTRL+ALT+DEL to log on. This

requirement implies that Windows NT doesn't lend itself well to the server

in a locked closet situation. Indeed, someone must press CTRL+ALT+DEL and

enter a user ID and a password in order to log on and use the keyboard or

mouse to interact locally with a Windows NT machine. However, it is

possible to configure the machine as a server in a locked closet such that

an administrator is not required to unlock the door to reset the system.

The administrator can configure the system so that services are started

automatically during boot. Once all the services are started, then the

system is fully functional and the administrator need not intervene. If

certain services fail to come up, but network service does come up, then

the system can be remotely administered.

MORE INFORMATION

Remote administration is possible, assuming that the required basic system

services are running. The machine must be on the network. The process

requires only the Windows NT product. In other words, Windows NT Advanced

Server is not an additional requirement.

Make sure that the following steps have been taken to start system services

automatically at system boot and to enable remote administration in case of

failure:

1. Use the Service Control Manager to install any application code that

   must be started as soon as the Windows NT machine reboots.

   Write an application that installs the services and specifies that they

   should be started automatically. To find more information on the Win32

   APIs that support Services, search on "Services Overview" in the Win32

   API help text.

   Once this is done, the necessary application code can be made to start

   automatically upon system reboot, without anyone needing to press

   CTRL+ALT+DEL to log on or to take any other action using the server's

   local mouse/keyboard.

2. Make sure that the Workstation and Server services start automatically

   upon reboot.

   Use the Services application in Control Panel to ensure that both

   the Workstation and Server services start automatically upon

   reboot. Choose the Help button for instructions on how to install a

   service and how to configure it to start automatically.

   This will permit an authorized person to remotely administer the system

   from another machine on the network. Thus, if something from step 1 goes

   wrong, the administrator still does not need to physically unlock the

   closet and log on. The administrator can log on to any machine on the

   network and use the tools on that machine to interact with the server.

Remote administration via dial-up telephone lines is available, but

requires RAS (Microsoft Remote Access Service). RAS permits a machine to

dial over telephone lines into a network, and to become a full participant

on the network. In this way, a system dialing in over RAS can be used to

remotely administer the system in the locked closet.

Note that while these steps allow servers locked in closets to be restored

without an administrator, it is still preferable to install a UPS

(uninterruptable power supply). Servers in locked closets usually need to

provide uninterrupted service to their clients, so a UPS is a better

solution. The capability to do remote administration serves as a backup in

case of failure.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseMisc


Windows NT Support for the MS-DOS LAN Manager APIs

PSS ID Number: Q110776

Authored 28-Jan-1994	Last modified 05-Jan-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

There is no list that shows specifically which MS-DOS LAN Manager APIs

(application programming interfaces) are supported in a VDM (virtual DOS

machine) on Windows NT. This article discusses what influenced whether or

not an API would be implemented.

The set of APIs that is supported is relatively small. It was necessary to

implement named pipes, mailslots, NetServerEnum(), and the NetUseXXX APIs.

The APIs that are commonly used in shipping applications were implemented,

if possible. There were certain APIs that were impossible to implement from

the VDM. The remaining APIs were not added either because Microsoft did not

feel that they were used in applications or because they did not make sense

in this context, such as the NetServiceXXX APIs.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: NtwkLmapi


Windows NT Virtual Memory Manager Uses FIFO

PSS ID Number: Q98216

Authored 29-Apr-1993	Last modified 02-Mar-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

On page 193 of "Inside NT," Helen Custer states that the Windows NT virtual

memory manager uses a FIFO (first in, first out) algorithm, as opposed to a

LRU (least recently used) algorithm, which the Windows virtual memory

manager uses. While it is true that FIFO can result in a commonly used page

being discarded or paged to the pagefile, there are reasons why this

algorithm is preferable.

Here are some of the advantages:

 - FIFO is done on a per-process basis; so at worst, a process that

   causes a lot of page faults will slow only itself down, not the

   entire system.

 - LRU creates significant overhead--the system must update its page

   database every single time a page is touched. However, the database

   may not be properly updated in certain circumstances. For example,

   suppose that a program has good locality of reference and uses a

   page constantly so that it is always in memory. The operating

   system will not keep updating the timestamp in the page database,

   because the process is not hitting the page table. Therefore this

   page may age even though it is in nearly constant use.

 - Pages that are "discarded" are actually kept in memory for a while,

   so if a page is really used frequently, it will be brought back

   into memory before it is written to disk.

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseMm


Windows Regions Do Not Scale

PSS ID Number: Q71229

Authored 10-Apr-1991	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows,

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.5, 3.51, and 4.0

SUMMARY

The coordinates of Windows regions are in device units, not logical

units. Therefore, if the mapping mode is not MM_TEXT, region

coordinates do not scale as would be expected. This causes particular

problems in metafiles because metafiles often use MM_ISOTROPIC or

MM_ANISOTROPIC modes to make pictures appear the same on devices with

different resolutions.

To work around this problem, applications should avoid using regions

if the mapping mode is changed from MM_TEXT. Regions should also be

avoided in metafiles, unless the application knows the scaling factor

and can adjust region coordinates itself.

MORE INFORMATION

If the applications that will read and write the metafile are

developed together, the writing application can include an MFCOMMENT

escape in the metafile to store the region components. This

information can be used by the reading application to scale the

metafile.

However, this comment is not standard across all applications. This

method would not be expected to work if the metafile is imported into

a commercial application.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: GdiDc


Windows Socket API Specification Version

PSS ID Number: Q85965

Authored 23-Jun-1992	Last modified 20-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

The Windows Sockets API Specification version 1.1 is now available in

two formats. WINSOCK.DOC is a Word for Windows, version 2.0, document

and WINSOCK.TXT is an ASCII-text-format document.

These files contain the Windows Sockets API Specification version 1.1,

which defines a standard binary interface for tcp/ip transports based

on the Berkeley Sockets interface originally in Berkeley UNIX with

Windows-specific extensions. This specification has been endorsed by

20 leading companies, and defines the sockets interface in Windows NT.

The specification will be supported by various vendors in their

upcoming tcp/ip product releases for Windows for MS-DOS.

The Windows Sockets API Specification is contained in a file called WINSOCK

(contains ASCII text version) and a file called WINSOCKW (contains a Word

for Windows version) which is located in the Microsoft Software Library.

Download WINSOCK.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for WINSOCK.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download WINSOCK.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \softlib\mslfiles directory

      Get WINSOCK.EXE

Download WINSOCKW.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for WINSOCKW.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download WINSOCKW.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \softlib\mslfiles directory

      Get WINSOCKW.EXE

Additional reference words: 1.00 1.10 3.10 3.50 4.00 95

KBCategory: kbref

KBSubcategory: NtwkWinsock


Windows WM_SYSTIMER Message Is an Undocumented Message

PSS ID Number: Q108938

Authored 20-Dec-1993	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

The WM_SYSTIMER message in Windows is an undocumented system message; it

should not be trapped or relied on by an application. This message can

occasionally be viewed in Spy or in CodeView while debugging.

Windows uses the WM_SYSTIMER message internally to control the scroll rate

of highlighted text (text selected by the user) in edit controls, or

highlighted items in list boxes.

NOTE: The WM_SYSTIMER message is for Windows's internal use only and can be

changed without prior notice.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrMsg


WM_CHARTOITEM Messages Not Received by Parent of List Box

PSS ID Number: Q72552

Authored 30-May-1991	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

When keyboard input is sent to a list box that has the

LBS_WANTKEYBOARDINPUT style bit set, its parent does not receive

WM_CHARTOITEM messages; however, WM_VKEYTOITEM messages are received. This

is because the list box has the LBS_HASSTRINGS style bit set.

This behavior is by design. Windows sets the LBS_HASSTRINGS style bit for

all list boxes except owner-draw list boxes. An owner-draw list box can be

created with this style bit turned on or off. For owner-draw list boxes,

the state of the LBS_HASSTRINGS style bit determines which messages are

sent. WM_CHARTOITEM messages and WM_VKEYTOITEM messages are mutually

exclusive.

The documentation for WM_CHARTOITEM states:

   Only owner-draw list boxes that do not have the LBS_HASSTRINGS style can

   receive this message.

Additional reference words: 3.00 3.10  3.50 3.51 4.00 95 listbox

KBCategory: kbprg

KBSubcategory: UsrInp


WM_COMMNOTIFY is Obsolete for Win32-Based Applications

PSS ID Number: Q94561

Authored 10-Jan-1993	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK), versions 3.1, 3.5,

   3.51, and 4.0

SUMMARY

Under Windows version 3.1, the WM_COMMNOTIFY message is posted by a

communication device driver whenever a COM port event occurs. The message

indicates the status of a window's input or output queue.

This message is not supported for Win32-based applications. However, WOW

supports the EnableCommNotification() API for 16-bit Windows-based

applications running on Windows NT.

MORE INFORMATION

To duplicate the Windows 3.1 functionality for a Win32-based application,

refer to the TTY sample, included with the SDK. The TTY sample is a common

code base sample, which uses EnableCommNotification() under Windows 3.1 to

tell COMM.DRV to post messages to the TTY window.

In Win32, this behavior is simulated with a secondary thread which uses

WaitCommEvent() to block on the port and PostMessage() to indicate

when the desired event has occurred.

TTY.C defines WM_COMMNOTIFY if WIN32 is defined. Using this method,

WM_COMMNOTIFY notifications are simulated but use the same message

definition as Windows 3.1.

The TTY sample is located on the Win32 SDK CD in \MSTOOLS\SAMPLES\COMM.

Additional reference words: 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: BseCommapi


WM_CTLCOLORxxx Message Changes for Windows 95

PSS ID Number: Q130952

Authored 31-May-1995	Last modified 06-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) version 4.0

SUMMARY

In previous versions of Windows, an application could change the

background, text, and/or text background colors of controls by performing

certain actions in response to WM_CTLCOLORxxx messages.

However, in Windows 95, the messages sent by different types of controls

are somewhat different.

MORE INFORMATION

The following list outlines the changes in WM_CTLCOLORxxx messages sent by

standard controls in Windows 95:

WM_CTLCOLORBTN

--------------

Sent By: command buttons (regular and default)

Changes made during this message have no effect on command buttons. Command

buttons always use system colors for drawing themselves.

WM_CTLCOLORSTATIC

-----------------

Sent By: Any control that displays text which would be displayed using the

default dialog/window background color. This includes check boxes, radio

buttons, group boxes, static text, read-only or disabled edit controls, and

disabled combo boxes (all styles).

The changes affect the text drawn in the control. Changes do not affect the

checkmarks on the buttons or the outline of the group box.

WM_CTLCOLOREDIT

---------------

Sent By: Enabled, non-read-only edit controls and enabled combo boxes (all

styles)

The changes affect the background, text, and text background of these

controls. For combo boxes, the changes made in this message affect only the

"edit" portion of the control. The list portion is affected by the

WM_CTLCOLORLISTBOX message.

In previous versions of Windows, radio buttons, check boxes and group boxes

would send WM_CTLCOLORBTN messages and paint themselves accordingly. In

Windows 95, these controls send WM_CTLCOLORSTATIC messages instead.

These changes were implemented to make changing the appearance of controls

more logical (text on the dialog background is now classified as "static").

Additional reference words: 4.00

KBCategory: kbprg

KBSubcategory: UsrCtl


WM_DDE_EXECUTE Message Must Be Posted to a Window

PSS ID Number: Q77842

Authored 28-Oct-1991	Last modified 12-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK)versions 3.0 and 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

Chapter 15 of the "Microsoft Windows Software Development Kit

Reference, Volume 2" documents the dynamic data exchange (DDE)

protocol. The following statement is found on page 15-2:

   An application calls the SendMessage() function to issue the

   WM_DDE_INITIATE message or a WM_DDE_ACK message sent in response to

   WM_DDE_INITIATE. All other messages are sent using the PostMessage()

   function.

In the book "Windows 3: A Developer's Guide" by Jeffrey M. Richter (M

& T Computer Books), the sample setup program uses the SendMessage()

function to send itself a WM_DDE_EXECUTE message that violates the DDE

protocol and may not work in future versions of Windows.

In Richter's sample, no real DDE conversation exists. The correct

method to achieve the desired result is to use the SendMessage()

function to send a user-defined message to the window procedure. When

this message is processed, proceed accordingly.

For more information on user-defined messages, see chapter 6 of the

"Microsoft Windows Software Development Kit Reference, Volume 1" for the

Windows SDK version 3.0 and chapter 2 of the "Programmer's Reference,

Volume 3: Messages, Structures, and Macros" from the Windows SDK version

3.1.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrDde


WM_SIZECLIPBOARD Must Be Sent by Clipboard Viewer App

PSS ID Number: Q74274

Authored 15-Jul-1991	Last modified 12-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) versions 3.1 and 3.0

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

The WM_SIZECLIPBOARD message is not generated by the Windows graphical

environment; the clipboard viewer generates this message.

An application that can display the clipboard contents, such as the

CLIPBRD.EXE application in Windows version 3.0, is a clipboard viewer.

When the size of the clipboard viewer's client area changes and the

clipboard contains a data handle for the CF_OWNERDISPLAY format, the

clipboard viewer must send the WM_SIZECLIPBOARD message to the current

clipboard owner. The GetClipboardOwner function returns the window

handle of the current clipboard owner. This window handle is the

handle in the last call to OpenClipboard.

When sending the WM_SIZECLIPBOARD message, the clipboard viewer must

specify two parameters. The wParam parameter identifies the clipboard

viewer's window handle. The low-order word of the lParam parameter

contains the handle to a block of global memory that holds a RECT data

structure. The RECT structure defines the area in the clipboard viewer

that the clipboard owner should paint.

Additional reference words: 3.00 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrClp


WM_SYSCOLORCHANGE Must Be Sent to Windows 95 Common Controls

PSS ID Number: Q129595

Authored 30-Apr-1995	Last modified 01-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK)

 - Microsoft Win32s version 1.3

SUMMARY

You must ensure that applications that use the new common controls

introduced in Windows 95 and Windows NT version 3.51 forward the

WM_SYSCOLORCHANGE message to the controls.

MORE INFORMATION

Windows 95 makes it very easy for the user to change the colors of common

user interface objects, therefore it is critical that applications not rely

on particular colors being constant. When the user changes the color

settings, Windows 95 will send a WM_SYSCOLORCHANGE message to all top level

windows. Because this message is sent only to top level windows, the common

controls will not be notified of the color change unless the application

forwards the WM_SYSCOLORCHANGE message to the control.

An example of why this is important is the toolbar control. If the color

settings are such that the "3D Objects" color is set to light gray, the

toolbar will create its buttons to light gray. However if the

WM_SYSCOLORCHANGE message is not forwarded to the toolbar and the 3D Object

color is changed to blue, the toolbar buttons will remain light gray while

all the other buttons in the system change to blue.

Additional reference words: 1.30 4.00 grey

KBCategory: kbprg

KBSubcategory: UsrCtl


Working Set Size, Nonpaged Pool, and VirtualLock()

PSS ID Number: Q108449

Authored 12-Dec-1993	Last modified 03-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   versions 3.1 and 3.5

SUMMARY

This article discusses memory management issues such as working set size,

nonpaged pool, and locking pages into physical memory via VirtualLock().

MORE INFORMATION

Working Set

-----------

A process's working set is the set of pages that it has currently in

memory. The values for maximum working set and minimum working set are

hard-coded in Windows NT and are thus impossible to change. There are three

values hard-coded for the maximum working set. The value used for maximum

working set depends on whether your machine is considered to be a small,

medium, or large machine:

   Small machine--less than 16 megabytes (MB)

   Medium machine--between 16 MB and 20 MB

   Large machine--greater than 20 MB

The system tries to keep about 4 MB free to reduce the paging that occurs

when loading a new process, allocating memory, and so forth. Any free RAM

beyond what the system requires is available for the system to use to

increase your working set size if your process is doing a lot of paging.

Process pages that are paged out of your process space are moved into the

"standby list," where they remain until sufficient free RAM is available,

or until system memory is low and they need to be reused. If these pages

are accessed by your process while they are still on the standby list and

more RAM has become available, they will be "soft-faulted" back into the

working set. This does not require any disk access, so it is very quick.

Therefore, even though you have an upper limit to the size of your working

set, you can still have quite a few process pages in memory that can be

pulled back into your working set very quickly.

To minimize working set requirements and increase performance, use the

Working Set Tuner, WST.EXE, to order the functions within your code. One

way to help an application receive a larger working set is to use the

Network application in the Control Panel to set the server configuration to

"Maximize Throughput for Network Applications."

Nonpaged Pool

-------------

System memory is divided into paged pool and nonpaged pool. Paged pool can

be paged to disk, whereas nonpaged pool is never paged to disk. In Windows

NT 3.1, the default amount of nonpaged pool also depends on whether your

machine is considered small, medium, or large. In other words, you will

have X amount of nonpaged pool on a 16 MB machine, Y amount of nonpaged

pool on a 20 MB machine, and Z amount of nonpaged pool on a machine with

more than 20 MB (the exact values for X, Y, and Z were not made public).

Important system data is stored in nonpaged pool. For example, each Windows

NT object created requires a block of nonpaged pool. In fact, it is the

availability of nonpaged pool that determines how many processes, threads,

and other such objects can be created. The error that you will receive if

you have too many object handles open is:

   1816 (ERROR_NOT_ENOUGH_QUOTA)

Many 3.1 applications ran into this error because of the limited amount of

nonpaged pool. This limit were addressed in Windows NT 3.5. We found that

 - Some objects were too large

 - Sharing an object caused excessive quota charges

 - The quota limits were artificial and fixed

The resources used by each object were evaluated and many were drastically

reduced in Windows NT 3.5.

In Windows NT 3.1, every time an object was shared, quota was charged for

each shared instance. For example, if you opened a file inheritable and

then spawn a process and have it inherit your handle table, the quota

charged for the file object was double. Each handle pointing to an object

cost quota. Most applications experienced this problem. Under Windows NT

3.5, quota is only charged once per object rather than once per handle.

Windows NT 3.1 had a fixed quota for paged and nonpaged pool. This was

determined by the system's memory size, or could be controlled by the

registry. The limits were artificial. This was due to the poor design of

quotas with respect to sharing. It was also affected by some objects lying

about their actual resource usage. In any case, Windows NT 3.5 has revised

this scheme.

The Windows NT 3.1 "Resource Kit, Volume I" documents that it is possible

to change the amount of nonpaged pool by modifying the following registry

entry:

   HKEY_LOCAL_MACHINE\SYSTEM\

      CurrentControlSet\

      Control\

      Session Manager\

      Memory Management\

      NonPagedPoolSize

WARNING: This modification can cause the system to crash, and therefore

Microsoft does not recommend that this registry entry be changed.

Quotas can still be controlled in Windows NT 3.5 using these Windows NT 3.1

registry values. However, this technique is now almost never needed. The

new quota mechanism dynamically raises and lowers your quota limits as you

bump into the limits. Before raising a limit, it coordinates this with the

memory manager to make sure you can safely have your limit raised without

using up all of the systems resources.

VirtualLock()

-------------

To lock a particular page into memory so that it cannot be swapped out to

disk, use VirtualLock(). The documentation for VirtualLock() states the

following:

   Locking pages into memory may degrade the performance of the system by

   reducing the available RAM and forcing the system to swap out other

   critical pages to the paging file. There is a limit on the number of

   pages that can be locked: 30 pages. The limit is intentionally small to

   avoid severe performance degradation.

There is no way to raise this limit in Windows NT 3.1--it is fixed at 30

pages (the size of your working set). The reason that you see a severe

performance degradation when an application locks these pages is that

Windows NT must reload all locked pages whenever there is a context switch

to this application. Windows NT was designed to minimize page swapping, so

it is often best to let the system handle swapping itself, unless you are

writing a device driver that needs immediate access to memory.

Windows NT 3.5 allows processes to increase their working set size by using

SetProcessWorkingSetSize(). This API is also useful to trim your minimum

working set size if you want to run many processes at once, because each

process has the default minimum working set size reserved, no matter how

small the process actually is. The limit of 30 pages does not apply to

VirtualLock() when using SetProcessWorkingSetSize().

Additional reference words: 3.10 3.50

KBCategory: kbprg

KBSubcategory: BseMm


Writing Code that Works with Different International Formats

PSS ID Number: Q130056

Authored 10-May-1995	Last modified 16-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   version 3.1

 - Microsoft Win32 Software Development Kit (SDK) version 3.5

 - Microsoft Win32s version 1.2

SUMMARY

Some European coutries like Germany use a different floating point format

that doesn't include the decimal point (.). This has caused problems whtn

the actual numbers use the decimal point format (xxx.xx) and the German

version of Microsoft Excel is expecting a comma (xxx,xx).

Some developers have made the mistake of hard-coding formats or searching

for all periods and replacing them with commas. This is not good

programming practice.

Microsoft Excel uses the Control Panel Number Format for its separators.

So, regardless of what language version of Windows it runs on, it always

uses the correct separators. Microsoft recommends that you use the same

approach. Always use the separators defined in the number format of control

panel.

MORE INFORMATION

All the international information is stored in the WIN.INI file under the

[intl] heading. The application should look for the value of "sDecimal."

It can query this value using the GetProfileString API. If the application

uses this approach, it will have the correct separator for all countries.

To avoid potential problems, never make assumptions about number formats,

currency formats (that is, don't hard-code the dollar symbol), date

formats, or time formats. These are different for different countries. Use

the settings from the Control Panel.

If an application does any text processing, such as sorting or

upper/lowercase conversions, it should use the Windows APIs and not

supply its own conversion tables and functions. For example, if an

application use APIs such as AnsiLower, it will work regardless of

language because it obtains the data from the language DLL.

To output floating point numbers in Windows, Microsoft recommends that you

use wsprintf. The concept of an "international format string" only has

meaning when the string is output to the user. Internal to the computer,

for all calculations and manipulations, the concept does not apply. Thus

the application can keep its floats in the native format and only convert

to strings before calling the wsprintf function.

There is no need to load conversions from float to string, and vice versa.

In other words, there is no need to write any functions such as

InterStringToFloat(), InterFloatToString(), and so on.

Here's a simple algorithm you could use.

1. Convert your float to a string by using the _fcvt or _gcvt standard C

   functions.

2. Get the sThousand and sDecimal separators from the WIN.INI file by using

   the GetProfileString API.

3. Call wsprintf to output the converted string, using sThousand and

   sDecimal in the formatting string.

The following is an example of a mistake made by a developer who was not

thinking internationally:.

   if language=English

      Output_English_Float ()

   else

      Output_International_Float ()

This is not correct. Think of English as just another language and write a

single Output_Float() function that covers all languages.

Also, for ease of localization, a developer should place all strings in the

resource file. This avoids having to search through all the C files looking

for strings to translate.

Additional reference words: 1.20 3.10 3.50 localization kbinf foreign

KBCategory: kbother

KBSubcategory: wintldev


Writing Multiple-Language Resources

PSS ID Number: Q89866

Authored 01-Oct-1992	Last modified 19-May-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) versions 3.1, 3.5,

   3.51, and 4.0

When you are writing multiple-language resources, the dialog box

identifiers need to be identical for each language instance, as

demonstrated below.

   #define DialogID       100

   DialogID DIALOG  0, 0, 210, 10

   LANGUAGE LANG_ENGLISH,SUBLANG_ENGLISH_US

   .

   .

   .

   DialogID DIALOG  0, 0, 210, 10

   LANGUAGE LANG_FRENCH,SUBLANG_FRENCH

The FindResource() application programming interface (API) function is used

by the system to fetch the dialog box. FindResource() gets the locale

information for the process, then attempts to fetch the resource with that

language identifier using FindResourceEx(), the language-specific API

function for fetching resources. If FindResourceEx() fails to load the

language-specific dialog box, FindResource() then attempts to load the

neutral dialog box, which should fetch LANG_FRENCH,SUBLANG_FRENCH, if the

locale is SUBLANG_FRENCH_CAN or similar.

The LANGUAGE identifiers and the VERSIONINFO language identifiers should

also be identical. The code page for resources is always the Unicode code

page. The system will translate from Unicode to the required code page.

The preferred method of developing multiple-language resources is to

include a LANGUAGE statement for each language supported rather than using

the CODEPAGE, LANGUAGE identifier, and VERSIONINFO information. Although

the CODEPAGE information will work, the new method is easier to use.

Additional reference words: 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrNls WintlDev


wsprintf() Buffer Limit in Windows

PSS ID Number: Q77255

Authored 10-Oct-1991	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) for Windows

   versions 3.0 and 3.1

 - Microsoft Win32 SDK, versions 3.1, 3.5, 3.51, and 4.0

The wsprintf(lpOutput, lpFormat [, argument] ...) and wvsprintf()

functions format and store a series of characters and values in a

buffer specified by the first parameter, lpOutput. This buffer is

limited to 1K (1024 bytes); in other words, the largest buffer that

wsprintf can use is 1K.

If an application tries to use a buffer larger than 1K, the string

will be truncated automatically to a length of 1K.

Additional reference words: 3.00 3.10 3.50 4.00 95

KBCategory: kbprg

KBSubcategory: GdiDrw


XFONT.C from SAMPLES\OPENGL\BOOK Subdirectory

PSS ID Number: Q124870

Authored 15-Jan-1995	Last modified 23-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT,

   version 3.5

 - Microsoft Visual C++ for Windows NT, version 2.0

---

SUMMARY

XFONT.C from the SAMPLES\OPENGL\BOOK subdirectory is not in the MAKEFILE,

and subsequently is never built.

MORE INFORMATION

XFONT.C should not be built because the sample uses X Windows system-

specific functions. To use fonts with Windows NT version 3.5 OpenGL, use

the wglUseFontBitmaps() and glCallLists() functions as described in the

OpenGL online reference. Another alternative is to use auxDrawStr(). Note

that auxDrawStr is defined in GLAUX.H as:

   #ifdef UNICODE

   #define auxDrawStr auxDrawStrW

   #else

   #define auxDrawStr auxDrawStrA

   #endif

   void APIENTRY auxDrawStrA(LPCSTR);

   void APIENTRY auxDrawStrW(LPCWSTR);

REFERENCES

For further information on using fonts with OpenGL, please refer to the

OpenGL online reference titled "Fonts and Text."

Additional reference words: 3.50

KBCategory: kbgraphic kbprg

KBSubcategory: GdiOpenGL


XTYP_EXECUTE and its Return Value Limitations

PSS ID Number: Q102574

Authored 04-Aug-1993	Last modified 18-May-1995

The information in this article applies to:

 - Microsoft Windows Software Development Kit (SDK) version 3.1

 - Microsoft Win32 SDK versions 3.5, 3.51, and 4.0

SUMMARY

A DDEML client application can use the XTYP_EXECUTE transaction to

cause a server to execute a command or a series of commands. To do

this, the client creates a buffer that contains the command string,

and passes either a pointer to this buffer or a data handle

identifying the buffer, to the DdeClientTransaction() call.

If the server application generates data as a result of executing the

command it received from the client, the return value from the

DdeClientTransaction() call does not provide a means for the client to

access this data.

MORE INFORMATION

For an XTYP_EXECUTE transaction, the DdeClientTransaction() function

returns TRUE to indicate success, or FALSE to indicate failure. In

most cases, this provides inadequate information to the client

regarding the actual result of the XTYP_EXECUTE command.

Likewise, the functionality that DDEML was supposed to provide through

the lpuResult parameter of the DdeClientTransaction() function upon

return is currently not supported, and may not be supported in future

versions of DDEML. The lpuResult parameter was initially designed to

provide the client application access to the server's actual return

value (for example, DDE_FACK if it processed the execute, DDE_FBUSY if

it was too busy to process the execute, or DDE_FNOTPROCESSED if it

denied the execute).

In cases where the server application generates data as a result of an

execute command, the client has no means to get to that data, nor does

it have a means to determine the status of that execute command

through the DdeClientTransaction() call.

An example of this might be one where the DDEML client application

specifies a command to a server application such as "OpenFile

<FileName>" to open a file, or "DIR C:\WINDOWS" to get a list of files

in a given directory.

There are two ways that the client application can work around this

limitation and gain access to the data generated from the

XTYP_EXECUTE command:

Method 1

--------

The client can issue an XTYP_REQUEST transaction (with the item name

set to "ExecuteResult", for example) immediately after its

XTYP_EXECUTE transaction call returns successfully. The server can

then return a data handle in response to this request, out of the data

generated from executing the command.

Method 2

--------

The client can establish an ADVISE loop with the server (with

topic!item name appropriately set to Execute!Result, for example) just

before issuing the XTYP_EXECUTE transaction. As soon as the server

then executes the command, it can immediately update the advise link

by calling DdePostAdvise(), and return a data handle out of the data

generated from executing the command. The client then receives the

data handle in its callback function, as an XTYP_ADVDATA transaction.

Note that these workarounds apply only if one has access to the server

application's code. Third-party server applications that provide no

means to modify their code as described above can't obtain any data

generated by the application as a result of an XTYP_EXECUTE back to

the client.

Additional reference words: 3.10 3.50 3.51 4.00 95

KBCategory: kbprg

KBSubcategory: UsrDde


Introduction

The Programmer's Guide to Microsoft® Windows® 95 presents a series of articles covering programming issues specific to the Windows 95 operating system. This guide provides conceptual and reference information that is not available in any other document. Topics range widely from issues regarding the Win32® applica-tion programming interface to how to take advantage of Windows 95 features to extend existing MS-DOS®−based applications. To better focus this range of topics, the guide is divided into six main parts.

•	Part 1, "Understanding Windows 95," discusses the Windows 95 architecture and the API differences between version 3.x−based and Windows 95−based applications.

•	Part 2, "Developing Applications for Windows 95," discusses common controls and dialog boxes, the registry, and dragging and dropping. This part also discusses how to create applications for multimedia and pen, and provides an overview about installing applications.

•	Part 3, "Extending the Windows 95 Shell," discusses the shell namespace, shell extensions, application desktop toolbars, shell links, and the taskbar notification area.

•	Part 4, "Using Windows 95 Features," discusses file viewers, file parsers, briefcase reconcilers, the Passwords control panel, device I/O control, system policies, and ToolHelp functions.

•	Part 5, "Using Microsoft MS-DOS Extensions," discusses, MS-DOS extensions, long filenames, exclusive volume locking, program information file (PIF) management, and virtual machine services.

•	Part 6, "Applications for International Markets," discusses guidelines for developing international applications. This part also covers the use of double-byte characters and input method editors (IMEs), and outlines how to write  Middle-Eastern applications.

•	Part 7, "Advanced Programming," discusses the thunk compiler, a tool that assists developers in porting existing applications to the Win32 API.


Windows 95 Architecture

This article introduces the types of software components that you can build for Microsoft® Windows® 95, and it briefly describes the features of Windows 95 that those components can use.


Software Components

The operating environment for Windows 95 consists of a computer's hardware devices and the following software components:

•	Virtual machine manager (VMM).

•	Virtual devices (VxDs).

•	Read-only memory (ROM) basic input and output system (BIOS).

•	Installable device drivers and terminate-and-stay-resident (TSR) programs.

•	16- and 32-bit Windows dynamic-link libraries (DLLs).

•	Microsoft® MS-DOS® − based applications.

•	16- and 32-bit Windows-based applications.


Virtual Machine Manager

The virtual machine manager (VMM) is the 32-bit protected-mode operating system at the core of Windows 95. Its primary responsibility is to create, run, monitor, and terminate virtual machines. The VMM provides services that manage memory, processes, interrupts, and exceptions such as general protection faults. The VMM works with virtual devices, 32-bit protected-mode modules, to allow the virtual devices to intercept interrupts and faults to control the access that an application has to hardware devices and installed software.

Both the VMM and virtual devices run in a single, 32-bit, flat model address space at privilege level 0 (also called ring 0). The system creates two global descriptor table (GDT) selectors, one for code and the other for data, and uses the selectors in the CS, DS, SS, and ES segment registers. Both selectors have a base address of zero and a limit of 4 gigabytes (GBs), so all the segment registers point to the same range of addresses. The VMM and virtual devices never change these registers.

The VMM provides multiple-threaded, preemptive multitasking. It runs multiple applications simultaneously by sharing CPU (central processing unit) time between the virtual machines in which the applications run. The VMM is also nonreentrant. This means that virtual devices must synchronize access to the VMM services. The VMM provides services, such as semaphores and events, to help virtual devices prevent reentering the VMM.

For more information about the VMM, including descriptions of the services that it provides to virtual devices, see the documentation included in the Microsoft Windows 95 Device Driver Kit (DDK).


Virtual Devices

Virtual devices (VxDs) are 32-bit programs that support the device-independent VMM by managing the computer's hardware devices and supporting software. VxDs support all hardware devices for a typical computer, including the programmable interrupt controller (PIC), timer, direct memory access (DMA) device, disk controller, serial ports, parallel ports, keyboard, and display adapter. A VxD is required for any hardware device that has settable operating modes or retains data over any period of time. In other words, if the state of the hardware device can be disrupted by switching between multiple virtual machines or applications, the device must have a corresponding VxD.

Some VxDs support software, but no corresponding hardware device. In general, a VxD can provide any kind of services for the VMM and other virtual devices. Windows 95 allows the user to install new virtual device drivers to support an add-on hardware device or provide some system-wide software service.

A VxD can also provide application programming interface (API) functions for applications running in virtual 8086 mode or protected mode. These functions can give applications direct access to the features of the VxD.

Windows 95 includes a device input and output control (IOCTL) interface that allows Microsoft® Win32® − based applications to communicate directly with VxDs. Applications typically use this interface to carry out selected MS-DOS system functions, to obtain information about a device, or to carry out input and output (I/O) operations that are not available through standard Win32 functions. For more information about the device IOCTL interface, see "Device I/O Control."

For more information about virtual devices, see the documentation included in the Windows 95 DDK.


Device Drivers

A Windows device driver is a DLL that Windows uses to interact with a hardware device, such as a display or keyboard. Rather than access devices directly, Windows loads device drivers and calls functions in the drivers to carry out actions on the device. Each device driver exports a set of functions; Windows calls these functions to complete an action, such as drawing a circle or translating a keyboard scan code. The driver functions also contain the device-specific code needed to carry out actions on the device.

Windows requires device drivers for the display, keyboard, and communication ports. Other drivers may also be required if the user adds optional devices to the system.

The Windows 95 DDK provides independent hardware and software vendors (IHVs and ISVs) with the resources to build device drivers and VxDs that are compatible with the Windows 95 operating system. The resources include a configurable development environment, documentation, tools, and header files and libraries for several device types. The Windows 95 DDK contains the following components:

•	Header files and libraries for building device drivers and VxDs.

•	Sample source code for device drivers and VxDs.

•	16- and 32-bit versions of the driver development tools.


Dynamic-Link Libraries

Dynamic linking provides a mechanism for linking applications to libraries of functions at run time. The libraries reside in their own executable files and are not copied into an application's executable file as with static linking. These libraries are "dynamically linked" because they are linked to an application when it is loaded and executed rather than when it is linked. When an application uses a DLL, the operating system loads the DLL into memory, resolves references to functions in the DLL so that they can be called by the application, and unloads the DLL when it is no longer needed. Dynamic linking can be performed explicitly by applications or implicitly by the operating system.

DLLs are designed to provide resources to applications. Many applications can use the code in a DLL, meaning that only one copy of the code is resident in the system. Also, it is possible to update a DLL without changing applications that use the DLL, as long as the interface to the functions in the DLL does not change.

Software developers can extend the Windows environment by creating a DLL that contains routines for performing operations and then making the DLL available to other Windows-based applications (in addition to internal Windows routines). DLLs most often appear as files with a .DLL filename extension; however, they may also have an .EXE or other filename extension.

Windows 95 supports 32-bit DLLs as well as 16-bit DLLs that were written for Windows version 3.x. For a discussion of the issues involved in mixing 16- and 32-bit components in the Windows 95 environment, see "Thunk Compiler."

For more information about dynamic-link libraries, see the documentation included in the Microsoft Win32 Software Development Kit (SDK).


MS-DOS - Based Applications
MS-DOS − Based Applications

Windows 95 supports applications written for MS-DOS. Each MS-DOS − based application can run as a full-screen application, or it can run in a window on the Windows 95 desktop.

The system can run multiple MS-DOS − based applications at the same time. To do so, it creates a separate virtual machine (VM) for each MS-DOS − based application and shares the microprocessor among the MS-DOS VMs and the system VM (which contains all Windows-based applications). A VM can run an MS-DOS − based application in either the virtual 8086 mode or protected mode of the microprocessor.

Although most MS-DOS − based applications run fine in a window or as a full-screen application, some may not. To ensure absolute backward compatibility for all MS-DOS − based applications, Windows 95 provides a separate operating mode called "single MS-DOS application mode." When in this mode, Windows 95 runs only one MS-DOS − based application at a time. No Windows-based applications run in that mode; in fact, none of the graphical user interface (GUI) components of the system are even loaded.

Windows 95 supports the complete set of MS-DOS system functions and interrupts and provides extensions that permit MS-DOS − based applications to take advantage of long filenames and other Windows 95 features, such as exclusive volume locking, virtual machine services, and program information file management.

Disk utilities and other applications that directly modify file system structures, such as directory entries, must request exclusive use of the volume before making modifications to the structures. Windows 95 provides a set of input and output control (IOCTL) functions to manage exclusive volume use. Exclusive use prevents applications from inadvertently changing the file system while a disk utility is trying modify it.

Virtual machine services let Microsoft MS-DOS − based applications take advantage of features provided by Windows 95 when the applications run in a window. MS-DOS − based applications can retrieve and, optionally, set the title of the window in which they run. Virtual machine services also allow MS-DOS − based applications to periodically check the state of an internal close flag and terminate if the flag is set. Windows 95 sets this flag when the user chooses the Close command from the system menu of the window in which the MS-DOS − based application runs. Close-aware applications enable the Close command, which gives the user an alternate way to exit the application and close the window.

Program information file management lets Microsoft Windows − based applications create, examine, and modify program information files (.PIF files). These files contain the detailed information needed by the operating system to prepare virtual machines for running Microsoft MS-DOS − based applications. Installation programs and other applications can open the files, retrieve and set information in the files, and display the information to the user for editing.

For more information, see the following articles in this guide: "MS-DOS Extensions," "Long Filenames," "Exclusive Volume Locking," "Virtual Machine Services," and "Program Information File Management."


Windows-Based Applications

Windows 95 supports 16-bit applications written for Windows version 3.x as well as 32-bit applications that use the Win32 or Microsoft® Win32s® API. For 16-bit applications, Windows 95 preserves the cooperative multitasking model used in Windows version 3.x; that is, all 16-bit applications share the same virtual address space, the same message queue, and the same thread of execution. By contrast, each 32-bit Windows-based application has its own address space, a private message queue, and one or more threads of execution. In addition, each 32-bit thread is preemptively multitasked.

All new applications should be 32-bit applications developed using the Win32 API. For information about porting a 16-bit application to Win32, see "Version Differences."


Shell Features and Extensions

Windows 95 includes a number of component object module (COM) interfaces and functions that applications can use to enhance various aspects of the shell. This section describes the aspects of the shell that applications can enhance.


Shell Namespace

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

The Windows 95 shell provides a COM interface and several functions that allow an application to browse the namespace and retrieve information about the objects in the namespace. For more information about the shell's namespace, its COM interface, and related functions, see "Shell's Namespace."


Shortcuts

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

Windows 95 includes a COM interface that an application can use to implement shortcuts. For example, an application that manipulates documents might use shortcuts to provide the user with a list of the most recently opened documents. For more information about shortcuts, see "Shell Links."


Shell Extensions

An application developer can extend the Windows 95 shell in a number of different ways. Extending the shell involves adding information to the system registry or writing an OLE COM in-process server (InProcServer32).

A context menu handler is a type of shell extension that modifies the contents of a context menu. The system displays a context menu when the user clicks or drags an object using mouse button 2. The context menu contains commands that apply specifically to the object that was clicked or dragged.

Most context menus have a Properties command that displays the property sheet for the selected item. A property sheet contains information about an object in a set of overlapping windows called pages. A property sheet handler is a shell extension that adds pages to a system-defined property sheet or replaces pages in a Control Panel application's property sheet.

The system uses icons to represent files in the shell's namespace. By default, the system displays the same icon for all files that have the same filename extension. An icon handler can override the default and set the icon for a particular file.

A copy hook handler is an shell extension that approves or disapproves the moving, copying, deleting, or renaming of a file object.

For more information about extending the shell, see "Shell Extensions."


File Viewers and Parsers

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 and without even requiring the presence of the application. When the user chooses Quick View from the File menu or from the context menu for a file, the system runs the file viewer associated with the selected file. The shell uses the filename extension to determine which viewer to run.

A file viewer provides the user interface for viewing a file. It is an OLE component object implemented in an in-process server DLL. You can provide file viewers for new file formats or replace an existing viewer with one that includes more functionality. For more information about file viewers, see "File Viewers."

A file viewer works in conjunction with a file parser, which is a DLL that provides the low-level parsing needed to generate the "quick view" of a file of a given type. You can extend the file viewing capabilities of Windows 95 by supplying additional file parsers. Each file parser is responsible for a specific type or class of file and is associated with a display engine. For example, you can allow a quick view to be generated for a .DOC file by creating a file parser to support the file type and associating the file parser with the word processor display engine. For more information about file parsers, see "File Parsers."


Control Panel Applications

A Control Panel application is a special purpose DLL that lets the user configure the Windows environment. Even though Windows provides a number of standard Control Panel applications, you can create additional applications to let the user examine and modify the settings and operation modes of specific hardware and software. For information about creating Control Panel applications, see the documentation included in the Win32 SDK.


Screen Savers

A screen saver is an application that the system automatically starts when the mouse and keyboard have been idle for a period of time. A screen saver avoids damage to the display caused by static images on the screen or conceals sensitive information left on the screen. The property sheet for the display allows the user to select from a list of screen savers, specify how much time should elapse before the screen saver is started, configure screen savers, and preview screen savers. For information about how to create a screen saver, see the documentation included in the Win32 SDK.


System Features

This section describes some of the main features of Windows 95 that you can use in your Windows-based applications.


Registry

The registry is a central storage location that contains current information about the computer hardware configuration, installed software applications, settings and preferences of the current user, and associations between types of files and the applications that access and manipulate their contents. Much of the information  that was stored in initialization files in previous versions of the Windows operating system is now stored in the Windows 95 registry.

Mentions of the registry occur in several places in documentation for Windows and Win32. The Windows Interface Guidelines for Software Design has a chapter containing a general discussion of the registry. A chapter in the Microsoft Windows 95 Resource Kit explains how to integrate an application into Windows 95 by storing information in the registry. This guide also includes an article that addresses registry coding issues for a program that installs a software application. Finally, the documentation included in the Win32 SDK provides a detailed description of the functions and structures that provide an application with access to the registry.


Fonts

Fonts are used to draw text on video displays and other output devices. In Windows 95, a font is a collection of characters and symbols that share a common design. The three major elements of this design are typeface, style, and size. A typeface is a set of characters that share common characteristics, such as stroke width and the presence or absence of serifs. For example, Arial® and Courier are each typefaces. The font style refers to font characteristics, such as italic and bold. Font size refers to the point size of a font. Applications may use the Font common dialog box to display available fonts and allow users to select the typeface, style, and size. Windows 95 provides functions and related structures that allow applications to enumerate the available fonts on the system and select a specific font.

In addition to enumerating and selecting fonts, Windows 95 provides a set of functions and related structures that allow developers to perform the following tasks:

•	Use a stock font to draw text.

•	Check the text capabilities of a device.

•	Set the text alignment.

•	Draw text from different fonts on the same line.

•	Rotate lines of text.

•	Retrieve character outlines of a TrueType font.

•	Use portable TrueType metrics to achieve a WYSIWYG (what you see is what you get) effect.

•	Use PANOSE™ numbers of a TrueType font.

•	Create and install customized fonts.

For more information about fonts, see the documentation included in the Win32 SDK.


Printing

Windows 95 provides a complete set of functions that allow applications to print on a variety of devices: laser printers, vector plotters, raster printers, and fax machines. One of the chief features of these functions is their support of device independence. Instead of issuing device-specific commands to draw output on a particular printer or plotter, an application calls high-level functions from graphics device interface (GDI). The various printing components in Windows 95 interact with GDI to convert the high-level commands to raw device commands and spool the print job to the printer.

In addition to GDI, the following Windows 95 components are involved in printing.

Device driver	A Windows DLL that supports the Windows device driver interface (DDI). A device driver generates raw device commands when it processes calls to DDI functions made by GDI. The commands are processed by the printer when it prints the image.
Print spooler	The primary component of the printing interface. The print spooler is a Windows executable file that manages the printing process. Management of printing involves retrieving the location of the correct printer driver, loading the driver, converting high-level function calls to journal records, storing the journal records on disk as a print job, and so on.
Print processor	A Windows DLL that reads and converts journal records into DDI calls.
Port monitor	A Windows DLL that passes the raw device commands over the network, through a parallel port, or through a serial port to the device.
Windows 95 provides functions that allow applications to monitor many aspects of the printing process. Applications may enumerate and obtain information about these aspects:

•	Monitors for a specified server.

•	Print jobs for a specified printer.

•	Ports that are available for printing on a specified server.

•	Printer drivers installed on a specified printer server.

•	Available printers, print servers, domains, or print providers.

•	Print processors installed on the specified server.

•	Data types that a specified print processor supports.

For more information about printing, see the documentation included in the Win32 SDK.


File System

The file allocation table (FAT) file system is the original file system of MS-DOS. Except for the introduction of 16-bit FAT in MS-DOS version 3.0, this file system has remained essentially unchanged since MS-DOS version 2.0. Windows 95, however, introduces the following major change: the enhancement of the FAT file system to support long filenames. A long filename is a name for a file or directory that exceeds the standard 8.3 filename format.

The protected-mode FAT file system is the default file system used by Windows 95 for mass storage devices, such as hard disk and floppy disk drives. Protected-mode FAT is compatible with the MS-DOS FAT file system, using file allocation tables and directory entries to store information about the contents of a disk drive. Protected-mode FAT also supports long filenames, storing these names as well as the date and time that the file was created and the date that the file was last accessed in the FAT file system structures.

Win32-based applications automatically have access to long filenames through the use of the Win32 file management functions as well as the common dialog boxes used to open and save files. Applications should support long filenames and use long filenames for displaying all document and data filenames in the shell, in title bars, in dialog boxes and controls, and with icons.

For more information about the file system, see "MS-DOS Extensions" and "Long Filenames."


Plug and Play

Plug and Play is the name of a new industry standard for personal computers that lets personal computers (PCs) and attached hardware work together automatically. The goal of the Plug and Play technology is to make it easier than ever before for users to change the hardware configuration of their computers.

The most obvious beneficiaries of Plug and Play are the users of mobile PCs, whose hardware configurations change whenever they use a PCMCIA (Personal Computer Memory Card International Association) card or docking station. Every PC user, though, will benefit from Plug and Play; anyone who has ever had trouble setting up a new modem, sound card, or compact disc read-only memory (CD-ROM) drive understands the need for this technology.

Most of the Plug and Play architecture is implemented in new hardware, updated device drivers, and Windows itself; for most Windows-based applications, little extra code is required to support Plug and Play. A Windows-based application should be enabled for Plug and Play if it uses hardware that could be reconfigured, added to a system, or removed from a system while the application is running. Any Windows-based application that can be run on a mobile PC or that depends on the state of the monitor or other external devices should check for changes to the system hardware and take appropriate action when changes occur.

The system uses the following messages to send information about configuration changes to Windows applications.

WM_DEVICECHANGE	Tells applications about device changes. It is the most important Plug and Play message. The wParam parameter of this message contains an event code that an application can use to react to the change. For example, the DBT_DEVICEQUERYREMOVE event code asks an application for permission to remove a device. An application can return TRUE to grant permission or FALSE to deny it.
WM_DISPLAYCHANGE	Alerts applications to changes in the resolution of the screen.
WM_POWERBROADCAST	Tells applications about changes in the system's power status, including pending standby requests.
For more information about these messages, see the documentation included in the Win32 SDK. For information about the Plug and Play system architecture and how to write Plug and Play device drivers, see the Windows 95 DDK. For information about the design of Plug and Play hardware, see the Hardware Design Guide for Microsoft Windows 95.


Win32 Application Programming Interface

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

With a few minor exceptions, Microsoft ensures consistent and uniform behavior of the Win32 API across all platforms. Differences in the implementation of the Win32 functions depend on the capabilities of the underlying features of the platform. The most notable difference is that some Win32 functions carry out their tasks only on the more powerful platforms. For example, security functions are only available on the Windows NT operating system. Most other differences are system limitations, such as restrictions on the range of values or the number of items a given function can manage. For more information about system limitations, see "Win32 Limitations in Windows 95."

The Win32 API provides a wide and varied set of functions, messages, and structures that give your 32-bit applications access to the unique features and capabilities of the Windows operating system. The Win32 API can be grouped into these functional categories:

•	Graphics Device Interface (GDI)

•	Windows Management

•	System Services

•	Multimedia

•	Remote Procedure Calls (RPC)


Graphics Device Interface

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

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

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

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


Window Management

Window management gives applications the means to create and manage a user interface. Using the window management functions, you create and use windows to display output, prompt for user input, and carry out the other tasks necessary to support interaction with the user. Nearly all applications create at least one main 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.

Window management functions provide other features related to windows. For example, the clipboard functions provide the means to copy and paste information within the same window, between windows in the same application, and between windows in different applications. Applications also use the clipboard functions to carry out dynamic data exchange (DDE). DDE operations let applications exchange information without requiring specific direction from the user.


System Services

System services are a set of functions that give applications access to the resources of the computer and the features of the underlying operating system, such as memory, file systems, and processes. 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 MS-DOS FAT file system to the CD-ROM file system (CDFS). The network functions create and manage connections to shared resources, such as directories and printers, on computers in the network. Communications functions read from and write to communications ports as well as control the operating modes of these ports.

System services functions provide methods for applications to share resources 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. 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.

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

System services also let applications share information with applications running on the same computer or on other computers in a network. Applications can copy information between processes by using the mailslot and pipe functions to carry out interprocess communication (IPC). 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 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.


Multimedia

Multimedia functions give applications access to high-quality audio and video. Multimedia functions let you enhance and expand the capabilities of your application, giving users the ability to combine these forms of communication with more traditional forms of computer output. Using multimedia functions, applications can create documents and presentations that incorporate music, sound effects, and video clips as well as text and graphics. The multimedia functions provide services for audio, video, file I/O, media control, joysticks, and timers.

Applications use audio functions to play and record audio data using waveform, Musical Instrument Digital Interface (MIDI), and auxiliary audio formats. When playing audio, an application can mix sounds by routing selected audio to specified devices. To ensure efficient storage of audio data, the audio functions provide access to audio compressors and decompressors through the Audio Compression Manager (ACM).

Applications use video functions to capture video clips, compress the clips, and control their playback. An application captures video clips by using simple messages to access video and wave audio acquisition hardware, such as a video tape machine, and to stream selected video clips to disk. To store video data efficiently, an application can use the video compressors and decompressors provided by the Installable Compression Manager (ICM). Applications can play back video clips either on the computer screen or on other media devices by using the Media Control Interface (MCI) indirectly through the functions of the MCIWnd window class.

Applications use file I/O functions to store and retrieve the different types of multimedia data. An application can use unbuffered and buffered I/O with multimedia files, access and navigate Resource Interchange File Format (RIFF) files, and integrate custom I/O functions for multimedia data types. Of particular significance is the audio-video interleaved (AVI) file format, which provides for storing digital video clips consisting of both video and audio data. An AVI file is a RIFF file that has an extensible file architecture. This means that an application can customize AVI files to store and retrieve nonstandard data streams.

The Media Control Interface (MCI) provides a common set of high-level commands through which applications control media devices, such as animation devices, audio compact discs (CDs), digital-video devices, MIDI sequencers, video overlay devices, video disks, VISCA tape recorders (VCRs), and waveform (digital sound) devices. To communicate with a device, an application sends messages or command strings through MCI. The corresponding device handler interprets the message or string and executes the appropriate command at the device.

Applications use joystick functions to provide support for up to two joystick devices. An application can retrieve information about a joystick, calibrate the sensitivity of the device, and receive messages related to movement and button activity. Multimedia timer functions provide high-resolution timing for single or periodic events.


Remote Procedure Calls

Remote procedure calls (RPCs) give applications the means to carry out distributed computing, enabling them to tap the resources and computational power of computers on a network. Using RPC, you create distributed applications, each consisting of a client that presents information to the user and a server that stores, retrieves, and manipulates data and generally handles the bulk of the computing tasks for the client. Shared databases, remote file servers, and remote printer servers are examples of distributed applications.

A distributed application, running as a process in one address space, makes procedure calls that execute in an address space on another computer. Within the application, such calls appear to be standard local procedure calls, but these calls activate stub procedures that interact with the RPC run-time library to carry out the necessary steps to execute the call in the remote address space. RPC manages the network communications needed to support these calls, even the details such as network protocols. This means distributed applications need little or no network-specific code, making development of such applications relatively easy.

Microsoft RPC is just one part of a complete environment for distributed computing defined by the Open Software Foundation (OSF), a consortium of companies that was formed to define the components of a complete environment supporting distributed computing. Microsoft's implementation of RPC is compatible with the OSF standard with minor differences. Client or server applications written using Microsoft RPC version 1.0 will interoperate with any Distributed Computing Environment (DCE) RPC client or server whose run-time libraries implement the connection-based model and run over a supported protocol.


Extension Libraries

Extension libraries give applications services and capabilities beyond the basic services of the Win32 API. The extension libraries either expand on services already provided by the Win32 API or provide unique services that are commonly used by Win32 applications. There are the following extension libraries:

•	Common Controls

•	Common Dialog Boxes

•	Data Decompression

•	File Installation

•	Dynamic Data Exchange (DDE) Management

•	Network DDE


Common Controls and Dialog Boxes

The Windows 95 shell incorporates a number of control windows and dialog boxes that help give Windows 95 its distinctive look and feel. Because these controls and dialog boxes are supported by DLLs that are a part of Windows 95, they are available to all applications. Using the common controls and dialog boxes helps keep an application's user interface consistent with that of the shell and other applications. Because developing a control or dialog box can be a substantial undertaking, using the common controls and dialog boxes 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 control windows, 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. For more information about common controls, see the documentation included in the Win32 SDK.

The common dialog boxes provide a ready-made user interface that you can use to retrieve various kinds of information from the user. They are supported by the common dialog box library, COMDLG32.DLL. The library includes dialog boxes for selecting and creating colors, finding and replacing strings, opening and saving files, and setting printer options. For more information about the common dialog boxes, see the documentation included in the Win32 SDK.


Data Decompression and File Installation

The data decompression and file installation libraries provide useful functions for applications that install files. The data decompression library provides functions that applications use to expand files that have been compressed using the Microsoft File Compression Utility (COMPRESS.EXE). The file installation library provides functions that make it easier for applications to analyze currently installed files and install new files properly.


DDEML and Network DDE

The DDE management and network DDE libraries simplify the process of exchanging data with other applications. The DDE management library (DDEML) provides functions that minimize the amount of code needed in an application to carry out dynamic data exchange and gives an application the means to exchange data without requiring user interaction. The network DDE library provides functions that an application can use to connect to DDE servers on other computers in the network. These functions minimize the amount of code that an application needs to access the network; they also ensure security across network connections.


Win32 Software Development Kit

The Win32 SDK includes the tools and resources you need to build 32-bit applications that use the Win32 API. The Win32 SDK contains the following components:

•	Win32s components for building Win32-based applications that run on Windows version 3.x platforms.

•	32-bit header files and libraries for building Win32 applications that run with the Windows 95 and Windows NT operating systems.

•	Retail and debug versions of the Windows 95 core system DLLs.

•	Applications and utilities that aid in the development process.

•	Sample source code that demonstrates how to implement the Win32 API.

•	Documentation of the Win32 API and information describing how to use Win32 to develop Windows 95 − based applications.

•	Online text of the style guide for Windows-based applications, The Windows Interface Guidelines for Software Design.

•	Articles from the Windows 95 Knowledge Base.

For a description of the features and contents of the Win32 SDK as well as instructions on how to install and use it, see the Getting Started booklet included in the Win32 SDK.


OLE

OLE is a set of API services that allows an application to create documents consisting of information from different applications. Each piece of information is represented as an object and can consist of text, bitmap images, vector graphics, and even voice annotation and video clips. Representing information as objects makes it easier for applications to exchange, incorporate, and process data from applications created by different vendors. Applications that take advantage of OLE can interact seamlessly, allowing the user to focus on creating and managing information rather than on remembering how to perform procedures.

OLE associates two major types of data with an object: presentation data and native data. An object's presentation data is information needed to render the object on a display device, while its native data is all the information needed for an application to edit the object.

An object can be linked to or embedded in a document. Linking is a process whereby only an object's presentation data and a reference (or pointer) to its native data are placed in a document. The actual native data associated with the object exists in another location, such as in a file on disk. Whenever an application updates the object, it appears updated within the document. To the user, a linked object acts as if it were wholly contained within the document. By contrast, embedding places an object's presentation data and its native data physically within a document. All information necessary to edit the object is contained in the document.

Embedding makes a document larger, but it allows the object to be transferred with the document to another computer and to be edited on a different computer. Linked objects cannot "travel" with documents outside the local file system of the computer, but they are more efficient than embedded objects because a single instance of the object's data can serve many different documents.

OLE not only gives applications the ability to add linked and embedded objects to documents but also includes the following powerful features that you incorporate into your Windows-based applications.

Visual editing	Lets the user directly activate an object in-place within a document without switching to a different window. This includes operations such as in-place editing, displaying, recording, and playing.
Nested objects	Lets the user directly manipulate an object nested within another other object and to establish links to nested objects.
Drag and drop	Lets the user drag an object from one application window to another or to drop an object inside another object.
Storage-independent links	Allows links between embedded objects that are not stored as files on disk, enabling embedded objects within the same or different documents to update one another's data, whether or not they are recognized by the file system.
Adaptable links	Enables links between objects to be maintained in certain move or copy operations.
OLE automation	Enables the creation of command sets that operate both within and across applications. For example, a user can activate a command from a word processing application that sorts a range of cells in a spreadsheet created by a different application.
Version management	Allows an object to contain information about the application and the version of the application that created it.
Object conversion	Allows an object type to be converted so that different applications can be used with the same object. For example, an object created with one brand of spreadsheet could be converted so that it could be interpreted by a different spreadsheet application for editing.
OLE is supported by Windows version 3.1, Windows NT, and Windows 95, allowing your application to work the same way on all Windows platforms. The OLE documentation included in the Win32 SDK contains a set of DLLs, sample source code, extensive online information, and tools to assist in adding OLE capabilities to Windows-based applications.


Telephony Application Programming Interface

Telephony application programming interface (TAPI) makes it possible to create applications that combine the capabilities of the personal computer with the telephone. TAPI was created in cooperation with telecommunications companies, personal computer manufacturers, and software vendors as the standard for integrating telephones with PCs running the Windows operating system.

By integrating the PC and the telephone networks, TAPI makes possible the following new classes of applications.

Screen-based telephony	Provides a visual interface for accessing existing phone features and makes new features possible that cannot be implemented due to the today's limited telephone user interface.
Communications management	Provides end-user programmability that enables intelligent filtering and forwarding of telephone communications.
Personal productivity	Automates telephone calls and integrates them into personal productivity software. Calls can be automatically dialed to save time, and call details can be logged.
Integrated messaging	Allows the user to access their different electronic communications media, such as electronic mail, voice mail, and faxes from a single point on the desktop or from a remote location.
Ubiquitous voice on the desktop	Digitizes audio from the telephone directly into the PC, or retrieves audio seamlessly from a voice server and plays it back over a phone's speaker.
Conferencing	Provides video conferences as well as less bandwidth intensive tasks, such as sharing documents or "virtual whiteboards," to create a richer communications medium and attain the benefits of proximity at a distance.
Wide area data networking	Provides cleaner integration with the global telephone network, which facilitates fax and data communications from the PC.
Vertical solutions	Integrates telephone communications with business information systems. For example, an incoming call can be routed to the first available agent by a computer-based queuing system, and the customer's record "popped" onto the agent's screen before they even pick up the phone with caller identification-like functionality.
TAPI provides a standard interface, allowing an application to take advantage of the many capabilities and services of the telephone. At the same time, TAPI isolates an application from the complexity and variability of the underlying telephone network, greatly simplifying the application development task. In addition, TAPI is independent of the method of connection between the PC and telephone. This gives maximum flexibility to integrate the PC with the telephone system.

TAPI is part of the Microsoft Windows Open Services Architecture (WOSA), which provides a single set of open-ended interfaces to enterprise computing services. WOSA services, such as TAPI, consist of two interfaces. Developers write to an applications programming interface (API). The other interface, referred to as the service provider interface (SPI), is used to establish the connection to the specific telephone network.

Applications can combine TAPI with other capabilities of Windows to provide a combination of services. For example, an application can use TAPI to establish a connection and then use the Windows audio functionality to record and play back voice information over the connection.

For more information about TAPI, see the documentation included in the Win32 SDK.


Messaging Application Programming Interface

Windows 95 includes the messaging application programming interface (MAPI). You can use MAPI to add messaging features to your Windows-based applications that make it easy for users to electronically share information, such as charts and reports.

The MAPI architecture is designed to make it easy to write powerful messaging-enabled applications that are independent of the underlying messaging system. To achieve this, MAPI provides two interfaces: the (API), which provides messaging services to an application, and the service-provider interface (SPI), which provides the link to the messaging system. MAPI provides a layer of functionality between an application and the underlying messaging system, allowing them to be developed independently of one other.

MAPI services are high-level (compared to most networking functions) and allow you to implement sophisticated messaging features with a small amount of code. You deal only with functions for sending, receiving, and addressing messages; the underlying messaging system is completely transparent. MAPI also provides other functionality such as access to address books — that is, customized lists of message recipients.

MAPI supports existing standards such as the X.400 API Association's Common Messaging Calls (CMC). By using the CMC or Simple MAPI, you can easily add message capabilities to an existing application's user interface. For example, a word processing program can include a Send Message command that sends a document as a mail message to a recipient. MAPI also supports application macro languages, such as those used in Microsoft® Excel and Word. For example, a spreadsheet user can write a macro that automatically sends a monthly budget spreadsheet to a designated recipient when the file is updated with new sales figures.

You can also use CMC or Simple MAPI to create an application that is centered around messaging capabilities. One example is a scheduling application in which users can view the schedules of their coworkers and send meeting requests to the coworkers' calendars. Another example is a forms-routing application that sends an expense report to a series of recipients and records their approval or disapproval.

MAPI also supports workgroup applications that require full access to all of the back-end messaging services, including the message store, address book or directory, and transport functions. These applications include e-mail clients, workflow automation programs, and bulletin board services. For example, a workflow application might allow a user to inspect a message stored in a certain project folder to see if the appropriate workers have signed off on their tasks. This application could also include a sophisticated search and store feature that retrieves relevant files from a bulletin board system and stores them in the folders of certain recipients. Advanced workgroup applications take advantage of Extended MAPI.

For more information about MAPI, see the documentation included in the Win32 SDK.


Pen

Every computer running Windows 95 can display and manipulate data that was collected on a pen-enabled system. These capabilities are provided by a dynamic-link library, either PKPD.DLL or PKPD32.DLL. A Windows-based application can use pen data in the following ways:

•	To display a signature for letters or faxes.

•	To verify signatures collected on a pen-based mobile computer.

•	To display graphics, maps, or handwritten notes that have been drawn on a pen-based system.

Displaying and manipulating ink, the common term for pen data, is only a subset of the pen services available to Windows-based applications. Pen-enabled applications use the entire set of Pen functions to add ink collection and recognition to their feature sets. Pen services for Microsoft Windows 95 requires either the PENWIN.DLL or PENWIN32.DLL library for all of the functionality of pen data collection. The library is supplied by the pen tablet or computer manufacturer that bundles Microsoft pen services with their product. (Pen-enabled systems use the same pen display library that is available on every Windows 95 computer for pen data manipulation and display: PKPD.DLL or PKPD32.DLL.)

For more information about the pen capabilities of Windows 95, see "Displaying and Using Pen Data." The Programming Guide to Pen Services for Microsoft Windows 95, which is included in the Win32 SDK, provides information about using the entire set of pen API to collect, recognize, manipulate, and display ink.


International Applications

Within six months of its final release, Windows 95 will be available in 30 different language versions. To support all of these languages, Microsoft has developed three separate code bases: one for single-byte character sets (SBCS), one for double-byte character sets (DBCS), and one for the languages of the Middle East.

The DBCS versions, which ship to the Far East, include the input method editor (IME) for complex writing systems, an end-user defined character (EUDC) editor, and all the code for passing DBCS (mixture of 8- or 16-bit) characters through the user interface. For more information about the input method editor, see "Using Input Method Editors." For more information about creating applications that can handle DBCS characters, see "Using Double-Byte Characters."

The versions for the Middle East support both left to right and right to left text placement as well as special ligature and text justification (Kashida) handling. For more information about developing applications for the Middle East, see "Writing Applications for Middle-Eastern Languages."

To make localization easy, you should develop all language-dependent user-interface elements as Win32 resources. Using resources allows you to create versions of your application in any number of languages without having to recompile your application's components. For more information about resources, see the documentation included in the Win32 SDK.

For more information about internationalization issues, see "International Guidelines," and read the International Handbook for Software Design, which is available in the Microsoft Developer Network Development Library.


Creating Great Applications

The Microsoft® Windows® 95 user interface is based on a datacentric design; that is, rather than focusing on applications, the user interface design emphasizes data and tasks that involve the manipulation of data. The interface has been designed to allow the user to browse for data and documents and to edit them directly without necessarily having to locate an appropriate editor or application first. This type of design frees the user to focus on information and tasks rather than on applications and how they interact.


About Creating Great Applications

This article briefly describes some of the features you should use and guidelines you should follow to ensure that your application is a "great" Windows 95 − based application. A great Windows 95 − based application is one that integrates seamlessly with the user interface in Windows 95 and conforms to the system's datacentric design principles. In addition to reading this article, you should follow the user interface guidelines presented in The Windows Interface Guidelines for Software Design.


File Information

Throughout the Windows 95 shell, files appear as icons. When you click on a file's 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 file's property sheet, the user can find out information about a file without having to open it.

By default, a file's property sheet contains general information about the file, including its name, size, location, 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.

For more information about saving document information using the OLE Document Summary Information Property Set, see the OLE documentation included in the Microsoft® Win32® Software Development Kit (SDK).

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 95 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 8.3 filename format. In the past, long filenames typically appeared on network servers that used file systems other than the Microsoft® MS-DOS® file allocation table (FAT) file system. In Windows 95, however, long filenames are available for use with network servers and with local disk drives supporting the protected-mode FAT file system.

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 file's 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.

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 application's 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 application's 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. Window 95 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 pointer's 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.


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 shortcut's 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 application's 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."


Clipboard Data Transfer Operations

Windows 95 supports two types of clipboard data transfer operations — those involving menu commands (such as Cut, Copy, and Paste), and those involving the direct manipulation of objects (drag and drop). An application should support both types extensively.

You should support the OLE style of drag and drop. If you support drag and drop, the user can easily move data among the desktop, folders, and other applications. You should support dragging with mouse button 2 and display a context menu at the end of the drag operation, as the shell does. At a minimum, the menu should include these commands: Move Here, Copy Here, Create Shortcut(s) Here, and Cancel. For more information about supporting the OLE style of drag and drop, see "Dragging and Dropping."

You should make sure your application's menu-based data transfer model works well with the shell. You should test various scenarios, such as copying a shortcut or file in a shell folder to the clipboard and then pasting the shortcut or file into your application. Also, if your application supports shortcuts to its documents, you should offer a link to your OLE data object when the user drags an object out of a document.


Common Controls and Dialog Boxes

The Windows 95 shell incorporates a number of control windows and dialog boxes that help give Windows 95 its distinctive look and feel. Because these controls and dialog boxes are supported by DLLs that are a part of Windows 95, they are available to all applications. You should use the common controls and dialog boxes — rather than developing similar controls and dialog boxes of your own — because they help keep your application's user interface consistent with that of the shell and other applications. Because developing a control or dialog box can be a substantial undertaking, using the common controls and dialog boxes can also save you a significant amount of development time.


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 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.

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.

Status Window. 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 application's 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 user's preferences. The user can select items, edit item labels, and drag items from one location to another.

Trackbar. A trackbar allows the user to select a value from a range of consecutive values. To select a value, the user drags the trackbar's slider to the desired position.


Common Dialog Boxes

Windows 95 provides several common dialog boxes that your application can use to obtain various kinds of information from the user. There are the following types of common dialog boxes.

Dialog box	Description
Color	Enables the user to select and create colors.
Find	Enables the user to specify a search string.
Open	Enables the user to specify the location and filename of a file to be opened.
Page Setup	Enables the user to set the attributes of a printed page, including the paper type, the paper source, the page orientation, and the width of the page margins.
Print	Enables the user to configure a printer for a particular print job. The user can set print job parameters, such as the print quality, print range, and number of copies.
Replace	Enables the user to specify strings for use in a search and replace operation.
Save As	Enables the user to specify the location and name of a file to be saved.
For more information about the common dialog boxes, see the topic "Common Dialog Box Library." Note that the Print Setup dialog box provided in previous versions of Windows is now obsolete; new applications should use the Page Setup dialog box.

The Open and Save As common dialog boxes accessed from the File menu are especially useful because they support many features of the Windows 95 shell, including shell links, long filenames, and direct browsing of the network. If you cannot use the Open and Save As dialog boxes, you should incorporate the following features into your open and save dialog boxes to ensure that they are consistent with the shell, the Windows accessories, and other applications:

•	Support the same namespace hierarchy as the shell; that is, Desktop should be at the root of the hierarchy, followed by all folders and objects on the desktop, including My Computer, My Network, and so on. For more information about the shell namespace, see "Shell's Namespace."

•	Support shortcuts (also known as shell links). Note that opening a shortcut should open the target of the shortcut rather than the shortcut file itself. For more information about shortcuts, see "Shell Links."

•	Display filenames with the corresponding icons and filename extensions removed, as the shell does.

•	Allow the user to browse the network hierarchy directly.

•	Make sure that all of your dialog boxes (not just your open and save dialog boxes) use only nonbold fonts. In addition, you should use the DS_3DLOOK style to give your dialog boxes the three-dimensional look used throughout the system.


Other Development Considerations

In addition to supporting common controls and dialog boxes, an application should include other new shell features, such as context menus, property sheets (with extensions), the details view, and so on. For more information about context menus and property sheets, see "Shell Extensions."

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. For more information about palettes, see the documentation included in the Win32 SDK.


Windows 95 Help

The Windows Help application has been improved for Windows 95. It includes many new 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 application's 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.

For more information about the Windows 95 Help application, see the topic "Help" and the documentation included with the Microsoft Windows Help Compiler.


Multiple Instances

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 95.

When the user attempts to open a document file associated with an application, typically by double-clicking the document file's 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 application's icon when the application is already running. If the application's 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

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.

For more information about supporting pen input, see "Displaying and Using Pen Data."


Application Installation Guidelines

You should follow the Windows 95 guidelines for installing your application so that it works well when running with Windows 95. Some of the important installation guidelines follow:

•	Create a subdirectory in the Applications directory at the root of the hard disk and store your application's executable file and any sample files there. If the Applications directory does not exist at the root of the hard disk, your installation program should create it. If you have any other executable or data files, such as .DLL and .HLP files that are specific to your application, your program should create another subdirectory named Application Extensions in the Applications directory. It should copy the remaining files (except shared files) to this new subdirectory.

•	Copy all system-wide shared files (files shared by applications from many different vendors) to the \Applications\Shared Components directory. If this directory does not exist, your installation program should create it. If a given file already exists in this directory, your program should overwrite it with your file only if your file is a more recent version.

•	Copy all shared files (files shared by applications from the same vendor) to a vendor-specific directory in the \Applications\Shared Components directory. If the vendor-specific directory does not exist, your installation program should create it.

•	Place a single icon (shortcut) for your main application either directly in the Programs folder of the Start menu or in a subfolder of the Programs folder. If your installation program adds a shortcut, the user can easily start your application from the Start menu. However, your program should not overload the Start menu. To prevent overloading that menu, you may want your installation program to prompt the user to choose which shortcuts to add.

•	Register your application-specific icons and commands as described in "Registry" later in this topic.

•	Support the Add/Remove Programs application in Control Panel so that the shell automatically runs your installation and uninstall programs. Note that on some types of hardware, the shell automatically runs your installation program as soon as the user inserts the floppy disk or compact disc (CD).

For more information about installing your application to run with Windows 95, see "Installing Applications."


Registry

Integrating your application into the Windows 95 shell requires that you make full and correct use of the system registry. Your installation program should add the following items to the registry:

•	Register your application under the HKEY_LOCAL_MACHINE\SOFTWARE key. Your installation program should include keys for your company name, product name, and version number.

•	Store user-specific initialization data under the HKEY_CURRENT_USER\SOFTWARE key. Your installation program should not store initialization data in the WIN.INI file.

•	Add application-specific paths to the registry so that Windows sets the PATH environment appropriately when starting your application. Your installation program should set the path in the HKEY_LOCAL_MACHINE root under the \SOFTWARE\Microsoft\Windows\CurrentVersion\AppPaths key and create a new key having the same name as your application's executable file. Under this new key, your program should create the Path value name and assign it a path using the same format as that expected by the PATH environment variable.

•	Register an icon for each type of data file created by your application. When the system displays one of your data files in the shell, the registered icon for that file's type appears along with the file's name. If your installation program does not register icons for data files, the system will generate icons for them, but they may not be as distinctive as you would like them to be.

•	Register data-specific commands for your data files; these commands appear in the context menus for your data files. For example, if your application creates sound files, your installation program might register a Play command that enables the user to play a sound by choosing Play from the context menu.

•	Register a "Print To command" for your data files. Including a printto canonical verb in the registry enables the user to print your data files by performing a drag and drop operation to a specific printer object. Note, however, that the printto canonical verb does not add a command to the context menu of your data files.

For a description of additional items you should add as well as instructions on how to add the items described in the preceding list, see "Installing Applications."


Window 95 Logo Requirements

This section describes the technical requirements that software programs and hardware devices must meet to qualify for the Windows 95 Logo. These requirements are periodically updated. To obtain information about the current requirements, contact Microsoft.


General Requirements for Applications

The requirements for the Windows 95 Logo apply to the following four main types of programs:

•	File-based applications — that is, applications that provide Open, Save, and Close File menu options.

•	Applications that are not file-based and applications that run exclusively in full screen mode. An application that 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).

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 32-bit 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 a Win32 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 Win32 PE format executable file.

2.	An application must support the Windows 95 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 Windows 95 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 the application uses features that are available only in Windows 95, the features must degrade gracefully in Windows NT. Conversely, if it uses features available only in Windows NT, the features must degrade gracefully in Windows 95. The application must run successfully with both Windows 95 and Windows NT, unless architectural differences between the two operating system prevent it.

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 children's 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).

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 version 3.5.

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 tool's 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).


Personal Computer Systems

For a personal computer (PC) system to qualify for the Windows 95 Logo, it must meet a minimum set of requirements as outlined below and pass the System Compatibility Test (SCT) for Windows 95. 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 device's 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 1-16550A 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.


Hardware Peripheral Devices

For a peripheral device to qualify for the Windows 95 Logo, it must meet the requirements described in the Hardware Design Guide for Windows 95 and pass the compatibility tests conducted by MCL. For information about prequalifying test tools and MCL device and driver submission details, see the Windows 95 DDK. The Windows 95 DDK also contains detailed information about designing Windows 95 − based device drivers.

To carry the Windows 95 Logo, a device driver must support the following Plug and Play capabilities in Windows 95:

1.	Retrieves configuration information from Configuration Manager.

2.	Is dynamically loadable.

3.	Is dynamically reconfigurable.

4.	Reacts to system messages that occur when a device is attached or removed.

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.

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.

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.

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.


Parallel Port Devices

Parallel port devices (printers) must meet the following requirements:

1.	Meet the standards described in the current version of the Plug and Play Parallel Port Device specification.

2.	Comply with IEEE P1284-I.

3.	Support the compatibility and nibble mode protocols to read the device identifier from the peripheral.


External Communications Devices

An external communications device must be able to identify itself using the identification method described in the Plug and Play External COM Device Specification.


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 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.


Win32 Limitations in Windows 95

Microsoft® Windows® 95 implements some Microsoft® Win32® functions and messages differently than Microsoft® Windows NT™.


About Windows 95 System Limitations

If you intend to run 32-bit applications on both platforms, you need to understand these differences to minimize development and debugging time.


General Limitations

Some Win32 functions and messages, such as for security and event logging, are not supported by Windows 95. Windows 95 provides stub routines for these unsupported functions so that applications designed for other operating systems that fully support the Win32 application programming interface (API) can run with Windows 95 without errors.

By design, Win32 functions that take string parameters can handle either Unicode™ (wide character) or ANSI strings. However, Windows 95 does not implement the Unicode (or wide character) version of most Win32 functions. With few exceptions, these functions are implemented as stubs that simply return an error value. However, Windows 95 does provide Unicode implementations of the following functions.

ExtTextOut GetCharWidth GetTextExtentExPoint GetTextExtentPoint	MessageBox MessageBoxEx TextOut
In addition, Windows 95 implements the MultiByteToWideChar and WideCharToMultiByte functions for converting strings to and from Unicode.

Although all Boolean functions in the documentation for the Microsoft Win32 Software Development Kit (SDK) are described as returning 1 for TRUE and zero for FALSE, these return values are not necessarily true for Win32 functions in Windows 95. Instead, these functions are guaranteed to return a nonzero value for TRUE and zero for FALSE.


Window Management (User)

Windows 95 implements some window management features in 16 bits. The use of 16 bits imposes some restrictions on parameters in functions and messages and places limits on internal storage. For example, the standard edit control is limited to somewhat less than 64 kilobytes (K) of text. In some cases, Windows 95 provides new features that can be used to avoid these restrictions and limitations, such as the rich edit control in which the amount of text is limited only by available memory.

The wParam parameter for the SendMessageCallback, SendMessageTimeout, and SendNotifyMessage functions is limited to a 16-bit value.

In Windows 95, the wParam parameter in list box messages, such as LB_INSERTSTRING or LB_SETITEMDATA, is limited to a 16-bit value. One effect of this limit is that list boxes cannot contain more than 32,767 items. Although the number of items is restricted, the total size, in bytes, of the items in a list box is limited only by available memory. In contrast, a 64K data limit is imposed by Windows version 3.1.

Windows 95 permits up to 16,364 window handles and 16,364 menu handles. Although these limits are less than in Windows NT, they are significantly greater than the limits imposed by Windows version 3.1.

In Windows 95, the ActivateKeyboardLayout, GetKeyboardLayoutName, and UnloadKeyboardLayout functions do not support extended error code values; that is, you cannot retrieve errors for these functions by using the GetLastError function.

In Windows 95, only one desktop is available while the system runs. Although the thread desktop functions, GetThreadDesktop and SetThreadDesktop, are available under Windows 95, they do not do anything.

Any private application message must be defined above WM_USER + 0x100. A value above this will ensure that there is no collision between private messages and dialog box control messages.

Windows 95 automatically applies the standard three-dimensional shading and color scheme to dialog boxes created by applications marked as version 4.0 or later. Applications that are marked for earlier versions can still get the three-dimensional appearance by applying the DS_3DLOOK style to dialog boxes. If this style is used, the system automatically applies the three-dimensional look without requiring the application to check the operating system version. This is useful, for example, in applications developed for Windows NT version 3.5. The DS_3DLOOK style is ignored in Windows NT version 3.1.

The IDC_SIZE and IDC_ICON values used with the LoadCursor function are obsolete and should not be used in a Windows 95 − based application or in a Win32-based application that is marked as version 4.0.

In Windows 95, the MB_ICONQUESTION style used with the MessageBox, MessageBoxEx, and MessageBoxIndirect functions is obsolete. Win32-based applications should use the MB_ICONEXCLAMATION style instead. Similarly, applications should use the MB_ICONINFORMATION style instead of the MB_ICONASTERISK style and the MB_ICONSTOP style instead of the MB_ICONHAND style.


Graphics Device Interface (GDI)

Windows 95 uses a 16-bit world coordinate system and restricts x- and y- coordinates for text and graphics to the range ±32K. Windows NT uses a 32-bit world coordinate system and allows coordinates in the range ±2 gigabytes (GB). If you pass full 32-bit coordinates to text and graphics functions in Windows 95, the system truncates the upper 16 bits of the coordinates before carrying out the requested operation.

Because Windows 95 uses a 16-bit coordinate system, the sum of the coordinates of the bounding rectangle specified by the Arc, Chord, Pie, Ellipse, and RoundRect functions cannot exceed 32K. In addition, the sum of the nLeftRect and nRightRect parameters or the nTopRect and nBottomRect parameters cannot exceed 32K.

In Windows 95, regions are allocated from the 32-bit heap and can, therefore, be as large as available memory. (In Windows version 3.1, regions were limited to 64K.) All other logical objects, however, share the 64K local heap. In addition, the number of region handles cannot exceed 16K.

To ensure that adequate space is always available for logical objects, applications should always delete objects when no longer needed. The following functions create objects that are placed in the local heap and have corresponding functions used to delete the objects.

Object	Create with	Delete with
Bitmap	CreateBitmap, CreateBitmapIndirect, CreateCompatibleBitmap, CreateDIBitmap, CreateDIBSection, CreateDiscardableBitmap	DeleteObject
Brush	CreateBrushIndirect, CreateDIBPatternBrush, CreateDIBPatternBrushPt, CreateHatchBrush, CreatePatternBrush, CreateSolidBrush	DeleteObject
Color space	CreateColorSpace	DeleteColorSpace
Device context (DC)	CreateDC,  GetDC	DeleteDC, ReleaseDC
Enhanced metafile	CloseEnhMetaFile, CopyEnhMetaFile, GetEnhMetaFile, SetEnhMetaFileBits	DeleteEnhMetaFile
Enhanced metafile DC	CreateEnhMetaFile	CloseEnhMetaFile
Extended pen	ExtCreatePen	DeleteObject
Font	CreateFont, CreateFontIndirect	DeleteObject
Memory DC	CreateCompatibleDC	DeleteDC
Metafile	CloseMetaFile, CopyMetaFile,  GetMetaFile, SetMetaFileBitsEx	DeleteMetaFile
Metafile DC	CreateMetafile	CloseMetaFile
Palette	CreatePalette	DeleteObject
Pen	CreatePen, CreatePenIndirect	DeleteObject
Region	CombineRgn, CreateEllipticRgn, CreateEllipticRgnIndirect, CreatePolygonRgn, CreatePolyPolygonRgn, CreateRectRgn, CreateRectRgnIndirect, CreateRoundRectRgn, ExtCreateRegion, PathToRegion	DeleteObject
Physical objects have always existed in global memory and are, therefore, not limited.

Windows 95 does not support world transformations that involve either shearing or rotations. The ExtCreateRegion function fails if the transformation matrix is anything other than a scaling or translation of the region.

In Windows 95, pens and brushes have several limitations. The ExtCreatePen function supports solid colors only (the PS_SOLID style), and the PS_ALTERNATE and PS_USERSTYLE styles are not supported. Geometric pens (the PS_GEOMETRIC style) are limited to the BS_SOLID brush style specified in the LOGBRUSH structure passed to ExtCreatePen. In addition, the following pen styles are supported in paths only.

PS_ENDCAP_FLAT PS_ENDCAP_ROUND PS_ENDCAP_SQUARE	PS_JOIN_BEVEL PS_JOIN_MITER PS_JOIN_ROUND
Windows 95 does not support the dashed or dotted pen styles, such as PS_DASH or PS_DOT, in wide lines. The BS_DIBPATTERN brush style is limited to an 8- by 8-pixel brush.

Windows 95 does not support brushes from bitmaps or device independent bitmaps (DIBs) that are larger than 8 by 8 pixels. Although bitmaps larger than 8 by 8 pixels can be passed to the CreatePatternBrush or CreateDIBPatternBrush function, only a portion of the bitmap is used to create the brush.

Windows 95 does not provide automatic tracking of the brush origin. An application is responsible for using the UnrealizeObject, SetBrushOrgEx, and SelectObject functions each time it paints using a pattern brush.

Windows 95 does not support the CBM_CREATEDIB value for the CreateDIBitmap function. The CreateDIBSection function should be used instead to create a DIB. CreateDIBSection is also available in Windows NT version 3.5.

If the biCompression member of the BITMAPINFOHEADER structure is the BI_BITFIELDS value, the bmiColors member of the BITMAPINFO structure contains three doubleword color masks that specify the red, green, and blue components, respectively, of each pixel. Windows 95 only supports the following color masks for 16 and 32 bits per pixel (bpp).

16bpp	The blue mask is 0x001F, the green mask is 0x03E0, and the red mask is 0x7C00.
16bpp	The blue mask is 0x001F, the green mask is 0x07E0, and the red mask is 0xF800.
32bpp	The blue mask is 0x000000FF, the green mask is 0x0000FF00, and the red mask is 0x00FF0000.
If the lpvBits parameter is NULL, the GetDIBits function fills in the dimensions and format of the bitmap in the BITMAPINFO structure pointed to by the lpbi parameter. In this case, if the function is successful, the return value in Windows 95 is the total number of scan lines in the bitmap. In Windows NT versions 3.1 and 3.5, however, the return value is 1 (TRUE), indicating success.

Deletion of drawing objects is slightly different in Windows 95 than in Windows NT. In Windows NT, if a drawing object (pen or brush) is deleted while it is still selected into a DC, the DeleteObject function fails. In Windows 95, the function succeeds, but the result is a nonfunctioning object. This nonfunctioning object is automatically destroyed when the DC is deleted.

When a path is constructed in Windows 95, only the following functions are recorded: ExtTextOut, LineTo, MoveToEx, PolyBezier, PolyBezierTo, Polygon, Polyline, PolylineTo, PolyPolygon, PolyPolyline, and TextOut.

In Windows 95, the GetGraphicsMode and SetGraphicsMode functions support the GM_COMPATIBLE value only. The GM_ADVANCED value is not supported.

In Windows 95, the DeviceCapabilities function returns  − 1 when called with the DC_FILEDEPENDENCIES value because that capability is not supported. In Windows 95, DeviceCapabilities supports the following additional capabilities.

DC_DATATYPE_PRODUCED	Retrieves an array of strings containing the data types that the printer driver supports. A return value of   − 1 indicates that the printer driver only understands device-specific commands (in other words, "RAW" data) that are native to the printer. A return value of 2 or more indicates the number of strings in the array.
DC_EMF_COMPLIANT	Returns a flag that indicates if the specified printer driver is capable of accepting an enhanced metafile (EMF) spooled by the system (that is, the printer driver is EMF-compliant). The function returns 1 if the printer driver is EMF-compliant and  − 1 if the printer driver is not.
Although Windows 95 imposes no restrictions on the PlayEnhMetaFile and PlayEnhMetaFileRecord functions, the files and records that these functions execute are subject to the limitations described in this section. For example, the functions ignore records that attempt to draw outside of the 16-bit coordinate space or that apply shearing or rotation to world transformations.

In Windows 95, the maximum length of the description string for an enhanced metafile is 16K. This limit applies to the GetEnhMetaFileDescription, GetEnhMetaFileHeader, and GetEnhMetaFile functions.

In Windows 95, the dmDeviceName member of the DEVMODE structure specifies the "friendly" name of the printer, which may be set to any user-defined value. Windows 95, however, does not support the the following members; they are included for compatibility with Windows NT.

dmBitsPerPel dmDisplayFlags dmDisplayFrequency	dmFormName dmPelsHeight dmPelsWidth
Windows 95 does not support print monitor dynamic-link libraries (DLLs) that have been developed for Windows NT. To add a monitor using the AddMonitor function, you must specify a monitor DLL that has been explicitly created for Windows 95. The following printing and print spooling functions are not available in Windows 95.

AddForm AddPrinterConnection ConnectToPrinterDlg DeleteForm DeletePrinterConnection EnumForms FindClosePrinterChangeNotification	FindFirstPrinterChangeNotification FindNextPrinterChangeNotification GetForm ResetPrinter SetForm WaitForPrinterChange
In Windows 95, the SetPrinter function ignores the pShareName member of the PRINTER_INFO_2 structure. The PRINTER_INFO_3 and PRINTER_INFO_4 structures used with the SetPrinter, GetPrinter, and EnumPrinters functions are not supported in Windows 95. The PRINTER_INFO_5 structure, which is available in Windows 95, is not supported in Windows NT versions 3.1 and 3.5.

The PRINTER_ENUM_CONNECTIONS value used with the EnumPrinters function is not supported in Windows 95. The DOC_INFO_2 structure used with the StartDocPrinter function and the PORT_INFO_2 structure used with the EnumPorts function are not supported in Windows NT versions 3.1 and 3.5.

Windows 95 supports the DRAWPATTERNRECT printer escape.

Win32-based applications that send output to PostScript™ printers should use the GetDeviceCaps function to check for the PC_PATHS value to determine whether to use path functions or printer escapes to draw paths. Applications should use paths functions whenever possible. The following example shows how to check for this capability.

// Determine whether to use path functions on the device.
// hDC is the output device.

OSVERSIONINFO osvi;

osvi.dwOSVersionInfoSize = sizeof(osvi);
GetVersionEx(&osvi);

if ((osvi.dwPlatformId == VER_PLATFORM_WIN32_NT) ||
     ((osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) &&
       (GetDeviceCaps(hDC, POLYCAPS) & PC_PATHS)))
    bUsePaths = TRUE;
else
    bUsePaths = FALSE;

In Windows 95, printer drivers typically set this capability to zero. This means that Win32-based applications sending output to Postscript printers need to use the ExtEscape function and the printer-specific escapes to draw paths at the printer. (The Escape function cannot be used for this.)

In Windows NT, the string specified in the lpszDeviceName parameter of the EnumDisplaySettings function must be of the form "\\.\DisplayX", where X can be 1, 2, or 3. In Windows 95, lpszDeviceName must be NULL.


System Services (Kernel)

The extended error codes returned by the GetLastError function are not guaranteed to be the same in Windows 95 and Windows NT. This difference applies to extended error codes generated by calls to GDI, window management, and system services functions.

Windows 95 does not support asynchronous file input and output (I/O), except on serial devices. Therefore, the ReadFile and WriteFile functions will fail if you pass in an overlapped region on anything other than a serial device. The GetOverlappedResult function works only on serial devices or on files opened by using the DeviceIoControl function.

In Windows 95, the ReadFileEx and WriteFileEx functions will fail if you pass in the handle of a serial device (for example, COM2). ReadFile and WriteFile, however, accept the handle of a serial device.

In Windows NT, the FileTimeToDosDateTime and DosDateTimeToFileTime functions allow dates up to 12/31/2107. In Windows 95, these functions allow dates up to 12/31/2099.

The precision of the time for a file on a file allocation table (FAT) file system volume is 2 seconds. If Windows 95 is connected through a network to a different file system, the time precision is limited only by the remote device.

In Windows NT, the DeleteFile function fails if you attempt to delete a file that is open for normal I/O or is opened as a memory mapped file. In Windows 95, DeleteFile deletes such files. Because deleting open files may cause loss of data and application failure, you must take every precaution to close files before attempting to delete them by using DeleteFile.

In Windows 95, fixed memory blocks cannot be reallocated to be movable. The GMEM_MODIFY and GMEM_MOVEABLE combination of values has no effect when a memory block is reallocated by using the GlobalReAlloc function. Similarly, the LMEM_MODIFY and LMEM_MOVEABLE combination has no effect when a memory block is reallocated by using the LocalReAlloc function.

In Windows 95, committing memory for a page that is already committed is an expensive operation that has no ultimate effect (it is expensive because additional storage is allocated and subsequently freed for each committed page). When committing memory by using the VirtualAlloc function, an application should specify only the pages that actually need to be committed.

Although applications can request that memory allocation be at a specific virtual address, applications must not depend on any given address range always being available on every operating system. Applications can query the address space by using the GetSystemInfo function.

In Windows 95, memory allocated by Win32-based applications falls in the address range 4 megabytes (MB) − 2GB for private memory and 2GB − 3GB for shared memory (shared mapped files). The PAGE_WRITECOPY and PAGE_GUARD access protection values are not supported. Instead of using the PAGE_GUARD value and handling the EXCEPTION_GUARD_PAGE exception, applications can use the PAGE_NOACCESS value and handle the EXCEPTION_ACCESS_VIOLATION exception.

The SEC_IMAGE and SEC_NOCACHE values for the fdwProtect parameter of the CreateFileMapping function are not supported in Windows 95. In addition, the dwMaximumSizeHigh parameter of CreateFileMapping is ignored in Windows 95, so applications should specify zero for the parameter.

In Windows 95, shared memory mapped files that are created by using the MapViewOfFileEx function appear in the same address space across all 32-bit processes in the system. If you pass in a specific base offset in the lpvBase parameter of MapViewOfFileEx and the function succeeds, you are guaranteed that the same memory region is available in every process. This is not true in Windows NT because MapViewOfFileEx fails for any process that already has the given memory region in use.

Coherence guarantees that the data accessible in a file view is an identical copy of the file's contents on disk. In Windows 95, file views derived from a single file-mapping object are coherent only if the file is accessed through one of the views. A view of a file is not guaranteed to be coherent if the file is accessed by normal file I/O functions, such as ReadFile or WriteFile, or by views created from a different file-mapping object.

If you close a file handle that was used to create a file mapping object, both Windows NT and Windows 95 hold the file open until you unmap the last view of the file by using the UnmapViewOfFile function. However, Windows NT holds the file open with no sharing restrictions, whereas Windows 95 holds it open using the sharing restrictions of the original file handle. To ensure exclusive access to a file in Windows NT, the file handle must remain open for the life of the file-mapping object. Because Windows 95 retains the sharing restrictions, both the file handle and the handle to the file-mapping object may be closed after calling MapViewOfFile and exclusive access to the file is ensured.

In Windows 95, if the FILE_MAP_COPY value is specified for the fdwAccess parameter of MapViewOfFile (or MapViewOfFileEx), the hMapObject parameter must have been created with the PAGE_WRITECOPY value. In addition, the dwOffsetHigh parameter of MapViewOfFile (or MapViewOfFileEx) is ignored, so applications should specify zero for the parameter.

Windows 95 implements copy-on-write file mappings slightly differently than Windows NT. In Windows 95, a call to MapViewOfFile with FILE_MAP_COPY returns an error unless PAGE_WRITECOPY was used with the CreateFileMapping function. In both Windows NT and Windows 95, creating the map with PAGE_WRITECOPY and the view with FILE_MAP_COPY produces a view to the file that makes the pages swappable and prevents modifications from going to the original data file. In Windows 95, PAGE_WRITECOPY must be passed to CreateFileMapping, but this is optional in Windows NT.

If you share the mapping between multiple processes by using the DuplicateHandle or OpenFileMapping function and one process writes to a view, the modifications will not be propagated to the other process in Windows NT. However, the modifications will be propagated in Windows 95. The original file, though, will not change on either platform.

In Windows 95, the CreateFile function does not support the standard "\\.\C:" and "\\.\PhysicalDrive0" formats used to gain access to the logical or physical drives. To gain access, applications must specify a virtual device (VxD) name instead and use the DeviceIoControl function to send requests through the VxD to the logical and physical drives. For more information, see "Device I/O Control."

In Windows 95, the DuplicateHandle function cannot duplicate handles of registry keys as it can in Windows NT. The function returns an error if an application attempts to duplicate the handle of a registry key. In addition, when a file handle is duplicated, the duplicated handle will not be granted more access than the original.

The LoadLibrary function does not support loading 16-bit DLLs into a Win32 process.

Thread locales, retrieved and set by using the GetThreadLocale and SetThreadLocale functions, are static and can only be changed at system boot time.

In Windows 95, the FlushInstructionCache function always returns TRUE. Windows 95 supports single processor machines only.

In Windows 95, a call to the FreeResource function must be included for every call to the LoadResource function. The call to FreeResource allows the system to discard a resource that an application no longer needs. Windows NT automatically frees resources, so a call to FreeResource is not required.

The SYNCHRONIZE standard access rights flag is not supported in Windows 95. The following functions are affected.

DuplicateHandle	OpenSemaphore
MsgWaitForMultipleObjects	WaitForMultipleObjects
OpenEvent	WaitForMultipleObjectsEx
OpenMutex	WaitForSingleObject
OpenProcess	WaitForSingleObjectEx
The Windows 95 registry does not allow key names containing control characters. In addition, if the lpszSubKey parameter is an empty string (""), the RegDeleteKey function deletes the key identified by the hKey parameter.

In Windows 95, the RegCreateKeyEx function creates a non-volatile key even if the REG_OPTION_VOLATILE value is specified.


Multimedia

The sndAlias macro is not supported in Windows 95. In addition, the SND_ALIAS and SND_ALIAS_ID values for the PlaySound function are not supported in Windows 95.

The Windows 95 multimedia functions are not designed to be used by two or more threads in the same process. Although most multimedia functions will work if they are called by multiple threads, some are likely to fail. Functions that are particularly likely to fail include PlaySound, any of the functions that prepare or unprepare headers, and any of the open and close functions. PlaySound can never be used simultaneously by multiple threads in the same process. The functions that prepare or unprepare headers and the open and close functions can be used simultaneously by multiple threads in the same process, but only if they do not pass the same structure.


Version Differences

This article describes the differences in the way Windows 95 treats applications based on their subsystem version numbers. It is intended to help you identify areas in an application written for Windows version 3.x that you must revise to take advantage of the new features provided by Windows 95.


About Version Differences

The Microsoft® Windows® 95 operating system supports Windows-based applications that have a subsystem version number of either 3.x or 4.0. An application's subsystem version number is set by the linker.


General Window Management Differences

When a version 4.0 application uses the SetWindowLong function (with GWL_STYLE) to change a window's style, Windows 95 sends the window a WM_STYLECHANGING message before changing the style. The message's lParam parameter is the address of a STYLESTRUCT structure. The styleOld and styleNew members of the structure specify the old and new styles. By processing WM_STYLECHANGING, an application can inspect the styles and perhaps change them.

Windows 95 sends the WM_STYLECHANGED message after changing the style. Again, the lParam parameter is the address of a STYLESTRUCT structure that specifies the new styles. The application can use WM_STYLECHANGED to update any style-dependent information stored in the application's internal data structures.

Windows 95, however, does not send the WM_STYLECHANGING and WM_STYLECHANGED messages to a version 3.x application.

A version 4.0 application cannot use the SetWindowLong function to set the WS_EX_TOPMOST style for a window or to remove the style from a window. The application must use the SetWindowPos function to set or remove the WS_EX_TOPMOST style.

Windows 95 automatically adds and removes the WS_EX_WINDOWEDGE style for windows in both version 3.x and 4.0 applications. In a version 3.x application, Windows 95 adds the WS_EX_WINDOWEDGE style to a window if, in version 3.1, the window would have a dialog border or a sizable border. Windows 95 removes the WS_EX_WINDOWEDGE style if the window's style changes so that it would no longer have a dialog border or sizable border in version 3.1. Windows 95 uses similar criteria for adding and removing the WS_EX_WINDOWEDGE style for a Windows version 4.0 application, except that any window that has a title bar receives the WS_EX_WINDOWEDGE style, regardless of the window's other border styles.

When the user drags the icon of a minimized window created by a version 3.x application, Windows 95 sends the window a WM_QUERYDRAGICON message to retrieve the cursor to use while dragging. Windows 95 also sends WM_QUERYDRAGICON to retrieve the icon to display in the task-switch window that appears when the user presses the ALT+TAB key combination. Windows 95 does not send WM_QUERYDRAGICON to a window created by a version 4.0 application. Instead, the application is expected either to use the WM_SETICON and WM_GETICON messages or to set the big and small icons when registering the window class.

When a window in a version 4.0 application loses the mouse capture as a result of a call to the SetCapture function, the window receives a WM_CAPTURECHANGED message, but Windows 95 sends the message asynchronously. In other words, the window receives the message, but possibly not right away. Some of the ways in which a window can lose the mouse capture include:

•	The user activated a different application by clicking one of its windows.

•	The DefWindowProc function changed the capture in response to a WM_CANCELMODE message.

•	Another window using the same message queue called the SetCapture function. (All 16-bit applications share the same queue, but each 32-bit thread has its own queue.)

If a child window in a version 3.x application has the WS_EX_NOPARENTNOTIFY style, Windows 95 disregards the style when the user clicks the child window. That is, Windows 95 sends the WM_PARENTNOTIFY message to all windows in the parent chain regardless of whether the child window has the WS_EX_NOPARENTNOTIFY style. If a child window in a version 4.0 application has this style, Windows 95 does not send WM_PARENTNOTIFY messages when the user clicks the child window.

In a version 3.x application, it is possible for the horizontal coordinate on the left side of a window's client area to be greater than that on the right side. This happens because version 3.x sometimes incorrectly handles an empty client rectangle that contains a vertical scroll bar. (Fixing the problem would cause some applications to generate general protection faults.) In a version 4.0 application, it is not possible for the horizontal coordinate of the left side of a client area to be greater than that of the right side.


Dialog Boxes

A dialog box created by a version 4.0 application automatically receives the DS_3DLOOK style. This style gives three-dimensional borders to child controls in the dialog box and draws the entire dialog box using the three-dimensional color scheme. The DS_3DLOOK style is available to a dialog box created by a version 3.x application, but you must explicitly add the style to the dialog box template. The application that creates the dialog box determines the version number of the dialog box.

Windows 95 performs a strict validation check on the DS_ styles specified in a dialog box template. If the template contains any styles that Windows 95 does not recognize and a version 4.0 application is creating the dialog box, the creation fails. If a version 3.x application is creating the dialog box, the system debugger generates a warning, but Windows 95 creates the dialog box anyway.


Buttons

The parent window of a button (except push buttons) in a version 3.x application receives a WM_CTLCOLORBTN message when the button is about to be drawn. In a version 4.0 application, however, the parent window of a button receives the WM_CTLCOLORSTATIC message, which retrieves a color appropriate for drawing text on the background of the dialog box. Windows 95 sends WM_CTLCOLORSTATIC to retrieve the background and text colors for the text area of check boxes, radio buttons, and group buttons. An application should process WM_CTLCOLORSTATIC in order to correctly set the colors of any dialog box item that contains text and appears directly on the dialog area.

Windows 95 perform default handling of the WM_CTLCOLORBTN message differently depending on an application's version. For a version 3.x application, the default handling for button colors is to use the COLOR_WINDOW value for the background color and the COLOR_WINDOWTEXT value for the foreground color. For a version 4.0 application, Windows 95 uses the COLOR_3DFACE value for the background and the COLOR_BTNTEXT value for the foreground.

In a version 3.x application, a push button's outer top left corner is nonwhite because the button is typically drawn on a white background. If the border was white, the background would appear to bleed into the button. In a version 4.0 application, a push button's outer top left corner is white (COLOR_3DHILIGHT) because the button is typically drawn on a nonwhite background (COLOR_3DFACE).


Edit Controls

In a version 3.x application, an edit control that is the descendant of an inactive window takes the input focus when the user clicks the control; an edit control in a version 4.0 application does not. Not taking the input focus prevents the situation where the user can enter text into what appears to be an inactive window.

An edit control in a version 3.x application retrieves its text and background colors by sending the WM_CTLCOLOREDIT message to its parent window. In a version 4.0 application, an edit control sends the WM_CTLCOLOREDIT or WM_CTLCOLORSTATIC message. The edit control sends WM_CTLCOLORSTATIC if it is disabled or read-only; otherwise, it sends WM_CTLCOLOREDIT. In addition, a disabled multiline edit control in a version 4.0 application uses the COLOR_GRAYTEXT value as its text color.

A multiline edit control in a version 4.0 application has a proportional scroll box (thumb), but a multiline edit control in a version 3.x application does not.

In a version 3.x application, the wParam parameter of the EM_REPLACESEL message is not used. In a version 4.0 application, the wParam parameter is a flag that specifies whether the replacement operation can be undone.


List Boxes

In a version 4.0 application, a list box that is part of a combo box uses the WM_CAPTURECHANGED notification message to hide its drop-down list if it is open. For more information, see "Combo Boxes" later in this topic.

The DDL_EXCLUSIVE flag of the DlgDirList function does not have the expected result in a version 3.x application. Specifically, the flag does not exclude read-write files from the list. In a version 4.0 application, the DDL_EXCLUSIVE flag excludes read-write files.

If a list box in a version 3.x application has either the WS_HSCROLL or WS_VSCROLL style, the list box receives both horizontal and vertical scroll bars. Although one of the scroll bars is typically hidden, Windows 95 displays the hidden scroll bar if its scrolling range becomes greater than zero. In a version 4.0 application, a list box does not receive a horizontal scroll bar, unless it has the WS_HSCROLL style. Likewise, it does not receive a vertical scroll bar unless it has the WS_VSCROLL style.

When creating a list box in a version 3.x application, Windows 95 always increases the size of the list box by adding the border width to each side. This is done because Windows 95 assumes that the dimensions specified by the application or the dialog template are for the client area of the list box. Unfortunately, increasing the size in this way makes aligning a list box rather difficult. Windows 95 does not increase the size when creating a list box in a version 4.0 application; Windows 95 assumes that the specified size includes the borders.


Combo Boxes

A combo box in a version 4.0 application passes the control color messages (WM_CTLCOLOR*) from its child components (edit control and list box) to the parent window of the combo box. In a version 3.x application, a combo box passes those messages to the DefWindowProc function.

A combo box in a version 4.0 application uses the WM_CAPTURECHANGED message to hide its drop-down list box if it is open. Windows 95 sends the message when another window takes the mouse capture, which typically happens when the user clicks another window. In a version 3.x application, a combo box does not use WM_CAPTURECHANGED to hide the drop-down list.

A combo box in a version 3.x application uses the WM_CTLCOLORLISTBOX message to retrieve the text and background colors. In a version 4.0 application, a combo box uses the WM_CTLCOLOREDIT or WM_CTLCOLORSTATIC message instead. The combo box uses WM_CTLCOLORSTATIC if it is disabled or contains a read-only selection field (in an edit control); otherwise, it uses WM_CTLCOLOREDIT.

In a version 3.x application, the background of the static text area in read-only combo boxes is filled with the system highlight color (COLOR_HILIGHT). In a version 4.0 application, Windows 95 fills the background of the static text area only for a combo box that is not owner drawn.

In a version 4.0 application, Windows 95 adds the ODS_COMBOBOXEDIT value to the itemState member of the DRAWITEMSTRUCT structure when Windows 95 sends the WM_DRAWITEM message to the parent window of an owner-drawn combo box to draw an item in the selection field. The ODS_COMBOBOXEDIT value tells the parent window that the drawing takes place in the selection field of the combo box rather than in the list box.


Menus

A 16-bit version 3.x application that creates or loads a menu is considered to be the owner of the menu. However, when the application exits, the menu is "orphaned" until no 16-bit version components for Windows version 3.x remain. For 16-bit version 4.0 applications and all 32-bit applications, the application that creates the menu is the owner, and the menu is destroyed as soon as the application exits. Unlike graphics device interface (GDI) objects, there is no way to change the ownership of a menu.

In a version 3.x application, the Close command cannot be deleted from the System menu of an multiple document interface (MDI) child window. In a version 4.0 application, the Close command can be deleted.

Windows 95 increases the width of hierarchical, owner-drawn menu items in a version 3.x application. Some applications rely on this increased width and use it to include icons that simulate toolbars. In a version 4.0 application, Windows 95 does not automatically increase the width of hierarchical, owner-drawn menu items.

The wParam parameter of the WM_MENUSELECT message is interpreted differently depending on the subsystem version number of the application and whether the application is written for 16 or 32 bits:

•	In a 16-bit version 3.x application, the wParam parameter is the handle of the pop-up menu if the selected item activates a pop-up menu.

•	In a 16-bit version 4.0 application, wParam is the identifier of the menu item, regardless of whether the item activates a pop-up menu.

•	In a 32-bit application (both subsystem versions), the low-order word of wParam is the identifier of the menu item or, if the item activates a pop-up menu, the index of the pop-up menu. This high-order word contains the menu flags.


System Bitmaps and Colors

In 16-bit version 3.x applications, purpose windows, such as dialog boxes, message boxes, and system-defined control windows, receive WM_CTLCOLOR messages when they are about to be drawn. The high-order word of the lParam parameter indicates the type of special purpose window about to be drawn (CTLCOLOR_BTN, CTLCOLOR_EDIT, and so on). By default, a special purpose window passes the WM_CTLCOLOR message to the parent or owner window (for both subsystem versions), allowing the parent or owner to set the foreground and background colors of the special purpose window. The same is true for 32-bit applications, except that the special purpose window receives one or more of the following messages instead of WM_CTLCOLOR.

WM_CTLCOLORBTN WM_CTLCOLORDLG WM_CTLCOLOREDIT WM_CTLCOLORLISTBOX	WM_CTLCOLORMSGBOX WM_CTLCOLORSCROLLBAR WM_CTLCOLORSTATIC
In 32-bit applications, the message itself indicates the type of special purpose window about to be drawn. The lParam parameter contains the window's 32-bit handle.

Display drivers for Windows version 3.x provide the bitmaps, icons, and cursors used by previous versions of Windows. Because Windows 95 renders and scales the system bitmaps, icons, and cursors itself, its display drivers do not (and should not) contain any OBM_, OIC_, or OCR_ resources.

For a version 3.x application, the default handling of the WM_CTLCOLORSTATIC and WM_CTLCOLORDLG messages is to use the COLOR_WINDOW value for the background and the COLOR_WINDOWTEXT value for the foreground. For a version 4.0 application, Windows 95 uses the COLOR_3DFACE value for the background and the COLOR_WINDOWTEXT value for the foreground.

When an application calls the GetClientRect function to retrieve the client rectangle of a minimized window created by a version 3.x application, Windows 95 retrieves the old dimensions for a minimized window (0, 0, 36, 36). For a minimized window in a version 3.1 or 4.0 application, Windows 95 retrieves 0, 0, GetSystemMetrics(SM_CXMINIMIZED), GetSystemMetrics(SM_CYMINIMIZED). These metrics change if the user changes the title bar height or minimized window width by using Control Panel. In other words, the GetClientRect function returns the dimensions of the entire minimized window, preventing an application from causing a general protection (GP) fault because of an unexpectedly empty client rectangle.


System Metrics

When a version 3.x application calls the GetSystemMetrics function to retrieve the SM_CYVSCROLL or SM_CYHSCROLL metric value, the function returns a value that is one pixel more than the actual height of the corresponding type of standard scroll bar. Windows 95 adds a pixel because applications written for previous versions of windows routinely subtract one pixel from the return value. Subtracting one pixel accounts for the way a standard scroll bar in a version 3.x application overlaps the border of the window in which it resides. A version 4.0 application receives the actual height of the scroll bar.

When a version 3.x application retrieves the SM_CXDLGFRAME and SM_CYDLGFRAME system metric values, GetSystemMetrics returns a value that is one pixel less that the actual frame width or height. A version 4.0 application receives the actual width or height.

GetSystemMetrics returns one pixel more than the actual height of a title bar when a version 3.x application requests the SM_CYCAPTION system metric value. A version 4.0 application receives the actual height of the title bar.

GetSystemMetrics returns one pixel less than the actual height of a menu bar when a version 3.x application requests the SM_CYMENU system metric value. A version 4.0 application receives the actual height of the menu bar.

When a version 3.x application calls GetSystemMetrics to retrieve the SM_CYFULLSCREEN value (height of a maximized window's client area), the function returns a value that is one pixel less than the actual height. This is because GetSystemMetrics returns one pixel more than the actual title bar height when an application retrieves the SM_CYCAPTION value. (The sum of the height of a maximized window's client area and the height of a title bar must equal the height of the working area of the screen.) A version 4.0 application receives the actual height of the maximized window's client area when it requests the SM_CYFULLSCREEN value.


Parameter Validation

If a 32-bit version 3.x application specifies invalid class styles when calling the RegisterClass function, Windows 95 strips out the invalid bits and generates warnings in the system debugger, but allows RegisterClass to succeed anyway. If a 32-bit version 4.0 application passes invalid class styles to RegisterClass, the function fails.

In a version 3.x application, Windows 95 does not validate the length member of the WINDOWPLACEMENT structure that is passed to the GetWindowPlacement and SetWindowPlacement functions. The length member, however, is validated for a version 4.0 application; Windows 95 fails these functions if the value of length is incorrect.

Windows 95 does not validate the cbSize member of the STARTUPINFO structure specified in the CreateProcess and GetStartupInfo functions for applications written for Windows version 3.x. The cbSize member is validated, however, for version 4.0 applications.

In the debugging version of Windows 95, the system fills the specified buffer with zeros up to the length specified by the cbSize parameter when a version 4.0 application calls the LoadString function. The buffer is not filled with zeros for a version 3.x application.


Using Common Controls and Dialog Boxes

This article explains how a developer can create an Explorer-like application that displays real-estate listings for houses.


About Using Common Controls and Dialog Boxes

The Microsoft® Windows® 95 shell looks quite a bit different from the shell used currently by Windows version 3.1x and Microsoft® Windows NT™. This new shell includes Explorer, which integrates the functionality of File Manager and Program Manager in Windows 3.1x. Explorer uses many of the new Windows 95 common controls and follows the guidelines specified in The Windows Interface Guidelines for Software Design.

Because Explorer follows the interface guidelines so closely and uses many of the new Windows 95 controls, developers may want to use it as a model for their new Windows 95−based applications.

This article is based on the article "Creating a Windows 95 Explorer-like Application" and the CHICOAPP sample application, both by Nancy Cluts, available in the Microsoft Developer Network Development Library.


Appearance of Explorer

Explorer includes some new interface objects, such as a toolbar, a status bar, a tree view control, and a list view control. These controls work together to provide a usable and intuitive interface for the objects contained in the system. For more information about these new controls, see the documentation included in the Microsoft® Win32® Software Development Kit (SDK) and the six part series of articles entitled "Win32 Common Controls" in the Microsoft Developer Network Development Library (under Technical Articles), written by Nancy Cluts.

The new controls are provided in a dynamic-link library (DLL) called COMCTL32.DLL. The COMCTL32.DLL file is included in Windows 95 and will also be supported in Microsoft® Win32s® (running with Windows version 3.1x) and in Windows NT. The new controls are 32-bit only; they will not be supported in 16-bit Windows environments.

The following illustration shows the Windows 95 Explorer.


Designing the Sample Application

The sample application displays a real estate listing with the following functionality:

•	A toolbar at the top of the screen with tooltip controls for easy access to commands.

•	A status window at the bottom of the screen displaying the currently selected city and the number of houses listed for that city.

•	A tree view control displaying the cities that have houses for sale.

•	A list view control displaying the houses for sale.

•	A pop-up context menu that can be displayed by mouse clicking.

•	Property sheets for viewing and changing house properties.

•	Long filename support for saving and opening house listing files.

The following illustration shows the finished application. It displays the main screen with an open listing for the city of Seattle.

The application-defined structures used to hold the data for the sample application follow. For more information about how these structures are used, see the section "Parsing and Storing the Data" later in this topic.

typedef struct tagCITYINFO

{

    char szCity[MAX_CITY];  // city name

    int NumHouses;          // number of houses listed in city

    HTREEITEM hItem;        // handle of tree view item

} CITYINFO;

typedef struct tagHOUSEINFO

{

    char szAddress[MAX_ADDRESS];  // address

    char szCity[MAX_CITY];        // city

    int iPrice;                   // price

    int iBeds;                    // number of bedrooms

    int iBaths;                   // number of bathrooms

    int iImage;                   // bitmap index for house

    char szAgent[MAX_CITY];       // listing agent

    char szNumber[MAX_CITY];      // listing agent's phone number

} HOUSEINFO;

The following constants and global variables are used in the sample application.

// Global variables

#define NUM_BUTTONS 8

#define TEMP_LEN 10

// Structure containing information about the for sale listing.

LISTINFO g_Listing;

// Arrays to hold house and city information.

HOUSEINFO rgHouses[MAX_HOUSES];

CITYINFO  rgCities[MAX_CITIES];

// File input and output (I/O) global variables.

OPENFILENAME OpenFileName;

TCHAR        szDirName[MAX_PATH]   = TEXT("");

TCHAR        szFile[MAX_PATH]      = TEXT("\0");

TCHAR        szFileTitle[MAX_PATH];

// Filter specification for the OPENFILENAME structure.

TCHAR szFilter[] = TEXT("Text Files (*.TXT)\0*.TXT\0All Files (*.*)\0*.*\0");

char *lpBufPtr;


Creating the Windows

Because the windows used in the sample application are part of the Windows 95 common control library, you must call InitCommonControls to ensure that COMCTL32.DLL is loaded before calling any functions that use the new common controls. The status window has two parts: the left part, which displays the currently selected city, and the right part, which displays the number of houses listed for that city. The following example demonstrates how the status bar is implemented and calls helper functions to create the toolbar and the list view and tree view windows.

BOOL CreateAppWindows( HWND hwndParent )

{

    RECT rcl;

    int lpSBParts[2];

    static TCHAR szBuf[MAX_PATH];

    // Make sure that the common control library is loaded.

    InitCommonControls();

    // Get the size and position of the parent window.

    GetClientRect(hwndParent, &rcl);

    // First, create the status window.

    g_Listing.hWndStatus = CreateStatusWindow(

    WS_CHILD | WS_BORDER | WS_VISIBLE,  // window styles

    TEXT(""),                           // default window text

    hwndParent,                         // parent window

    ID_STATUS);                         // identifier

    if (g_Listing.hWndStatus == NULL)

         MessageBox (NULL, TEXT("Status Bar not created!"), NULL,
                     MB_OK );

    // Make the multiple parts for the status window.

    lpSBParts[0] = (rcl.right - rcl.left) / 2;

    lpSBParts[1] = -1;

    SendMessage(g_Listing.hWndStatus, SB_SETPARTS, (WPARAM)2,
    (LPARAM)&lpSBParts);

    // Set the text for the status window.

    ChangeSBText(g_Listing.hInst, g_Listing.hWndStatus, -1);

    // Next, create the toolbar.

    g_Listing.hWndToolBar = CreateTheToolbar(hwndParent);

    if (g_Listing.hWndToolBar == NULL )

        MessageBox (NULL, "Toolbar Bar not created!", NULL, MB_OK);

    // Create the list view window.

    g_Listing.hWndListView = LV_CreateListView(hwndParent,
    g_Listing.hInst, g_Listing.NumHouses, &rgHouses[0]);

    if (g_Listing.hWndListView == NULL)

    {

        MessageBox (NULL, "Listview not created!", NULL, MB_OK );

        return FALSE;

    }

    // Create the tree view window, and initialize its

    // image list.

    g_Listing.hWndTreeView = TV_CreateTreeView(hwndParent,
    g_Listing.hInst, g_Listing.NumCities, rgCities);

    if (g_Listing.hWndTreeView == NULL)

    {

        MessageBox(NULL, TEXT("Tree View not created!"), NULL, MB_OK);

        return FALSE;

    }

    return TRUE;

}

VOID ChangeSBText(HINSTANCE hInst, HWND hwnd, int iNumSelected)

{

    static TCHAR szBuf1[MAX_LEN];

    static TCHAR szBuf2[MAX_LEN];

    static TCHAR szSelected[MAX_LEN];

    TCHAR szText[MAX_ITEMLEN];

    int NumHouses;

    if (szBuf1[0] == '\0')

        LoadString (hInst, IDS_SELECTED, szBuf1, sizeof(szBuf1));

    if (szBuf2[0] == '\0')

         LoadString (hInst, IDS_NUMHOUSES, szBuf2, sizeof(szBuf2));

    if (iNumSelected == -1)

    {

        lstrcpy( szSelected, TEXT("None"));

        NumHouses = 0;

    }

    else

    {

        lstrcpy( szSelected, rgCities[iNumSelected].szCity);

        NumHouses = rgCities[iNumSelected].NumHouses;

    }

    wsprintf(szText, TEXT("%s %s"), szBuf1, szSelected);

    SendMessage(hwnd, SB_SETTEXT, 0, (LPARAM)szText);

    wsprintf(szText, TEXT("%s %d"), szBuf2, NumHouses);

    SendMessage(hwnd, SB_SETTEXT, 1, (LPARAM)szText);

}

To make a toolbar, create a bitmap for each button and then create a larger bitmap by stringing together each of the small bitmaps into one long bitmap. The standard toolbar bitmaps are built into COMCTL32.DLL. You can add these images to your toolbar by using the TB_ADDBITMAP message. In the following example, three of the standard file bitmaps (new, open, and save) and four of the view bitmaps (large icon, small icon, list view, and details view) are included in the toolbar. The TBBUTTON structure is filled in with the predefined bitmap indices for the desired bitmaps.

// Toolbar buttons.

TBBUTTON tbButtons[] = {

    { STD_FILENEW, IDM_NEW, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0L, 0},

    { STD_FILEOPEN, IDM_OPEN, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0,
      0L, 0},

    { STD_FILESAVE, IDM_SAVE, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0,
      0L, 0},

    { 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0L, 0},

    { VIEW_LARGEICONS, IDM_LARGEICON, TBSTATE_ENABLED, TBSTYLE_BUTTON,
      0, 0L, 0},

    { VIEW_SMALLICONS, IDM_SMALLICON, TBSTATE_ENABLED, TBSTYLE_BUTTON,
      0, 0L, 0},

    { VIEW_LIST, IDM_LISTVIEW, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0L,
      0},

    { VIEW_DETAILS, IDM_REPORTVIEW, TBSTATE_ENABLED, TBSTYLE_BUTTON,
      0, 0L, 0},

};

In the code that creates the toolbar, the application calls the CreateToolbarEx function, specifying HINST_COMMCTRL as the handle of the instance, IDB_STD_SMALL_COLOR as the bitmap identifier, and a pointer to the TBBUTTON structure. Note that the number of buttons specified is 4 because the last 4 buttons (the view buttons) come from a different bitmap.

HWND CreateTheToolbar(HWND hWndParent)
{
    HWND hWndToolbar;
    TBADDBITMAP tb;
    int index, stdidx;

    hWndToolbar = CreateToolbarEx(hWndParent,
        WS_CHILD | WS_BORDER | WS_VISIBLE |
        TBSTYLE_TOOLTIPS, ID_TOOLBAR, 11, (HINSTANCE)HINST_COMMCTRL,
        IDB_STD_SMALL_COLOR, (LPCTBBUTTON)&tbButtons,
        4, 0, 0, 100, 30, sizeof(TBBUTTON));

    // Add the system-defined view bitmaps.
    tb.hInst = HINST_COMMCTRL;
    tb.nID = IDB_VIEW_SMALL_COLOR;
    stdidx = SendMessage(hWndToolbar, TB_ADDBITMAP, 12, (LPARAM)&tb);

    // Update the indices to the bitmaps.
    for (index = 4; index < NUM_BUTTONS; index++)
        tbButtons[index].iBitmap += stdidx;

    // Add the view buttons.
    SendMessage(hWndToolbar, TB_ADDBUTTONS, 4, (LONG) &tbButtons[4]);

    return (hWndToolbar);
}

The next step is to create the list view and tree view windows. In the following example, the tree view control is one-fourth the width of the window's client area, and its height takes into account the vertical size of the toolbar and status bar. The example demonstrates how to create the tree view window. For this example, the values that determine the size of the controls are hard-coded. Applications should obtain these values by calling the GetSystemMetrics function.

HWND TV_CreateTreeView (HWND hWndParent, HINSTANCE hInst,
                       int NumCities, CITYINFO *pCity)
{
    HWND hwndTree;      // handle to tree view window
    RECT rcl;           // rectangle for setting size of window
    HBITMAP hBmp;       // handle to bitmap
    HIMAGELIST hIml;    // handle to image list

    // Get the size and position of the parent window.
    GetClientRect(hWndParent, &rcl);

    // Create the tree view window, make it 1/4 the width of the
    // parent window, and take the status bar and toolbar into
    // account.

    hwndTree = CreateWindow (
        WC_TREEVIEW,                // window class
        "",                         // no default text
        WS_VISIBLE | WS_CHILD | WS_BORDER | TVS_HASLINES |
           TVS_HASBUTTONS | TVS_LINESATROOT,
        0, 27,                      // x,y
        (rcl.right - rcl.left)/4,   // cx
        rcl.bottom - rcl.top - 45,  // cy
        hWndParent,                 // parent
        (HMENU) ID_TREEVIEW,        // identifier
        hInst,                      // instance
        NULL );
    if (hWndTree == NULL)
        return NULL;

        //  First, create the image list that is needed.
        hIml = ImageList_Create(BITMAP_WIDTH, BITMAP_HEIGHT,FALSE,
        2, 10);

    // Load the bitmaps, and add them to the image lists.
    hBmp = LoadBitmap(hInst, MAKEINTRESOURCE(FORSALE_BMP));
    idxForSale = ImageList_Add(hIml, hBmp, NULL);
    hBmp = LoadBitmap(hInst, MAKEINTRESOURCE(CITY_BMP));
    idxCity = ImageList_Add(hIml, hBmp, NULL);
    hBmp = LoadBitmap(hInst, MAKEINTRESOURCE(SELCITY_BMP));
    idxSelect = ImageList_Add(hIml, hBmp, NULL);

    // Make sure that all of the bitmaps are added.
    if (ImageList_GetImageCount(hIml) != 3)
        return FALSE;

    // Associate the image list with the tree view control.
    TreeView_SetImageList(hwndTree, hIml, idxForSale);

    // Initialize the tree view by adding "Houses For Sale."
    TV_InitTreeView(hInst, hwndTree);

    return (hwndTree);
}

VOID TV_InitTreeView(HINSTANCE hInst, HWND hwndTree)
{
    TCHAR szText[MAX_CITY];

    // Add the root item "Houses for Sale."
    LoadString(hInst, IDS_FORSALE, szText, MAX_LEN);
    hTPrev = (HTREEITEM)TVI_ROOT;
    iImage = idxForSale;
    hParent = (HTREEITEM)NULL;
    iSelect = idxForSale;
    hTRoot = TV_AddOneItem(szText, hwndTree, -1 );

    // Reset the previous item and image.
    hParent = hTRoot;
    hTPrev = (HTREEITEM)TVI_FIRST;
    iImage = idxCity;
    iSelect = idxSelect;
}

In the following example, you create the list view window, make it three-fourths the width of the parent window's client area, place it on the right side, and account vertically for the toolbar and status bar.

HWND LV_CreateListView (HWND hWndParent, HINSTANCE hInst,
                        int NumHouses, HOUSEINFO *pHouse)

{
    HWND hWndList;     // handle to list view window
    RECT rcl;          // rectangle for setting size of window
    HICON hIcon;       // handle to icon
    int index;         // index used in FOR loops
    HIMAGELIST hSmall, hLarge; // handles to image lists
    LV_COLUMN lvC;      // list view column structure
    char szText[64];    // place to store some text
    int iWidth;         // column width

    // Get the size and position of the parent window.
    GetClientRect(hWndParent, &rcl);

    // Create the list view window, make it 3/4 the size of the
    // parent window, and take the status bar and toolbar into
    // account.

    iWidth = (rcl.right - rcl.left) - ((rcl.right - rcl.left)/4);
    hWndList = CreateWindowEx( 0L,
        WC_LISTVIEW,                        // list view class
        "",                                 // no default text
        WS_VISIBLE | WS_CHILD | WS_BORDER | LVS_REPORT,  // styles
        (rcl.right - rcl.left)/4, 27,       // x, y
        iWidth, rcl.bottom - rcl.top - 42,  // cx, cy
        hWndParent,                         // parent
        (HMENU) ID_LISTVIEW,                // identifier
        hInst,                              // instance
        NULL );

    if (hWndList == NULL )
      return NULL;

    // First, initialize the image lists that are needed.
    // Create an image list for the small and large icons.
    // FALSE specifies large icons, and TRUE specifies small icons.
    hSmall = ImageList_Create( 16, 16, TRUE, 1, 0 );
    hLarge = ImageList_Create( 32, 32, FALSE, 1, 0 );

    // Load the icons, and add them to the image lists.
    hIcon = LoadIcon ( hInst, MAKEINTRESOURCE(HOUSE_ICON));
    if ((ImageList_AddIcon(hSmall, hIcon) == -1) ||
        (ImageList_AddIcon(hLarge, hIcon) == -1))
        return NULL;

    // Associate the image list with the list view control.
    ListView_SetImageList(hWndList, hSmall, LVSIL_SMALL);
    ListView_SetImageList(hWndList, hLarge, LVSIL_NORMAL);

    // Initialize the LV_COLUMN structure.
    // The mask specifies that the .fmt, .cx, width, and .isubitem
    // members of the structure are valid.
    lvC.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
    lvC.fmt = LVCFMT_LEFT;  // left-align the column
    lvC.cx = iWidth / NUM_COLUMNS + 1; // width of column,
                                       // in pixels

    lvC.pszText = szText;

    // Add the columns.
    for (index = 0; index < NUM_COLUMNS; index++)
    {
        lvC.iSubItem = index;
        LoadString( hInst,
        IDS_ADDRESS + index,
        szText,
        sizeof(szText));
        if (ListView_InsertColumn(hWndList, index, &lvC) == -1)
        return NULL;
 }

    return (hWndList);

}


Sizing Issues

After creating the windows, you will need to resize the application's main window. To resize all of the windows at the same time, use the DeferWindowPos function. DeferWindowPos updates a structure that contains multiple window positions. You use this function as you would use the window enumeration functions; that is, you begin, defer, and end. The following example illustrates how to resize all of the windows.

BOOL ResizeWindows(HWND hwnd)
{
    RECT rcl;
    HDWP hdwp;

    // Get the client area of the parent window.
    GetClientRect(hwnd, &rcl);

    // Defer four windows.
    hdwp = BeginDeferWindowPos(4);
    if (hdwp == NULL)
         return FALSE;

    // First, reset the status bar size.
    DeferWindowPos(hdwp, g_Listing.hWndStatus, NULL, 0, 0,
         rcl.right - rcl.left, 20, SWP_NOZORDER | SWP_NOMOVE);

    // Next, reset the toolbar size.
    DeferWindowPos(hdwp, g_Listing.hWndToolBar, NULL, 0, 0,
         rcl.right - rcl.left, 20, SWP_NOZORDER | SWP_NOMOVE);

    // Next, reset the tree view size.
    DeferWindowPos(hdwp, g_Listing.hWndTreeView, NULL, 0, 0,
         (rcl.right - rcl.left ) / 4, rcl.bottom - rcl.top - 45,
         SWP_NOZORDER | SWP_NOMOVE);

    // Last, reset the list view size.
    DeferWindowPos(hdwp, g_Listing.hWndListView, NULL,
         (rcl.right - rcl.left ) / 4, 25,
         (rcl.right - rcl.left) - ((rcl.right - rcl.left)/4),
         rcl.bottom - rcl.top - 42,
         SWP_NOZORDER );

    return (EndDeferWindowPos(hdwp));
}


Parsing and Storing the Data

Once the windows are created and resized, you need a method for reading in and storing the house listing data. The easiest way to store the house listing data is to save it to an ASCII file. The file should contain the following information:

•	Number of cities

•	City name (one name per line)

•	Number of houses

•	Information about each house (one house per line with each item of information separated by commas)

The ASCII file has the following form.

3

Bellevue

Redmond

Seattle

9

 100 Main Street,Redmond,175000,3,2,Joan Smith,555-1212

 523 Pine Lake Road,Redmond,125000,4,2,Ed Jones,555-1111

 1212 112th Place SE,Redmond,200000,4,3,Mary Wilson,555-2222

 22 Lake Washington Blvd,Bellevue,2500000,4,4,Joan Smith,555-1212

 33542 116th Ave. NE,Bellevue,180000,3,2,Ed Jones,555-1111

 64134 Nicholas Lane,Bellevue,250000,4,3,Mary Wilson,555-2222

 33 Queen Anne Hill,Seattle,350000,3,2,Joan Smith,555-1212

 555 SE Fifth St,Seattle,140000,3,2,Ed Jones,555-1111

 446 Mariners Way,Seattle,225000,4,3,Mary Wilson,555-2222

To parse the file, use the sscanf function and then convert some of the strings to integers, copy data to the structure, and update the file pointer. The structures used contain information about the houses, the cities, and the current state of the application. You should fill out a CITYINFO structure for each city listed and a HOUSEINFO structure for each house listed. When saving the information to a file, you reverse the procedure.


Using the Common Dialog Boxes

To support long filenames, use the new common dialog boxes to open and save the house listing information. If you have existing code written for the Windows version 3.1 common dialog boxes, you will be able to recompile some of it, and the application will display the new dialog boxes. You will need to hide the filename extension (.TXT, in this case) before setting the caption text for the main window. As shown in the following illustration, the new File Open common dialog box has no problem with long filenames, such as "Listing for the Puget Sound" or "Another saved listing."

The following example demonstrates how to use the common dialog boxes to open and save a file. It also shows how to read and parse the file to initialize the structures.

BOOL OpenNewFile( HWND hWnd )

{

    HANDLE hFile;

    DWORD dwBytesRead;

    DWORD dwFileSize;

    lstrcpy( szFile, TEXT(""));

    lstrcpy( szFileTitle, TEXT(""));

    OpenFileName.lStructSize       = sizeof(OPENFILENAME);

    OpenFileName.hwndOwner         = hWnd;

    OpenFileName.hInstance         = (HANDLE) g_Listing.hInst;

    OpenFileName.lpstrFilter       = szFilter;

    OpenFileName.lpstrCustomFilter = (LPTSTR) NULL;

    OpenFileName.nMaxCustFilter    = 0L;

    OpenFileName.nFilterIndex      = 1L;

    OpenFileName.lpstrFile         = szFile;

    OpenFileName.nMaxFile          = sizeof(szFile);

    OpenFileName.lpstrFileTitle    = szFileTitle;

    OpenFileName.nMaxFileTitle     = sizeof(szFileTitle);

    OpenFileName.lpstrInitialDir   = NULL;

    OpenFileName.lpstrTitle        = TEXT("Open a File");

    OpenFileName.nFileOffset       = 0;

    OpenFileName.nFileExtension    = 0;

    OpenFileName.lpstrDefExt       = TEXT("*.txt");

    OpenFileName.lCustData         = 0;

    OpenFileName.Flags             = OFN_SHOWHELP | OFN_PATHMUSTEXIST
                                     | OFN_FILEMUSTEXIST
                                     | OFN_HIDEREADONLY;

    if (GetOpenFileName(&OpenFileName))

    {

    if ((hFile = CreateFile((LPCTSTR)OpenFileName.lpstrFile,

         GENERIC_READ,

         FILE_SHARE_READ,

         NULL,

         OPEN_EXISTING,

         FILE_ATTRIBUTE_NORMAL,

         (HANDLE)NULL)) == (HANDLE)-1)

    {

         MessageBox( hWnd, TEXT("File open failed."), NULL, MB_OK );

        return FALSE;

    }

    // Get the size of the file.

    dwFileSize = GetFileSize(hFile, NULL);

    if (dwFileSize == 0xFFFFFFFF)

    {

        MessageBox( NULL, TEXT("GetFileSize failed!"), NULL, MB_OK);

        return FALSE;

    }

    // Allocate a buffer for the file to be read into.

    lpBufPtr = (TCHAR *)GlobalAlloc( GMEM_FIXED, dwFileSize );

    if (lpBufPtr == NULL)

    {

        MessageBox( NULL, TEXT("GlobalAlloc failed!"), NULL, MB_OK);

        CloseHandle( hFile );

        return FALSE;

    }

    // Read its contents into a buffer.

    ReadFile(hFile,(LPVOID)lpBufPtr, dwFileSize, &dwBytesRead, NULL);

    if (dwBytesRead == 0)

    {

        MessageBox( hWnd, TEXT("Zero bytes read."), NULL, MB_OK );

        CloseHandle(hFile);

        GlobalFree(lpBufPtr);

        return FALSE;

    }

    // Close the file.

    CloseHandle(hFile);

    // Parse the file buffer.

    return (ParseFile());

    }

    else

    {

    ProcessCDError(CommDlgExtendedError(), hWnd );

    return FALSE;

    }

}

BOOL ParseFile ( VOID )

{

    int count, result, index;

    TCHAR szTemp[MAX_PATH], szBeds[TEMP_LEN], szBaths[TEMP_LEN];

    TCHAR * lpSave;

    HTREEITEM hPrev;

    // Initialize the tree view and list view windows.

    InitTreeAndList();

    lpSave = lpBufPtr;

    // Read in the first line to get the number of cities.

    sscanf( lpBufPtr, TEXT("%s\n"), szTemp);

    g_Listing.NumCities = atoi(szTemp);

    // Move the buffer pointer.

    while (*lpBufPtr != 0x0A)

       lpBufPtr++;

    lpBufPtr++;

    if (g_Listing.NumCities == 0 || g_Listing.NumCities > MAX_CITIES)

    {

        MessageBox(NULL, TEXT("Number of cities must be between 1 and 16"), NULL, MB_OK);

        GlobalFree(lpBufPtr);

        return FALSE;

    }

    // Read a city for each line.

    for (count= 0; count < g_Listing.NumCities; count++)

    {

        sscanf( lpBufPtr, TEXT("%s\n"), rgCities[count].szCity);

        // Move the buffer pointer.

        while (*lpBufPtr != 0x0A)

            lpBufPtr++;

        lpBufPtr++;

        // Add the city to the tree view control.

        hPrev = TV_AddOneItem( rgCities[count].szCity,
        g_Listing.hWndTreeView, count);

    }

    // Get the number of houses.

    sscanf( lpBufPtr, TEXT("%s\n"), szTemp);

    g_Listing.NumHouses = atoi(szTemp);

    // Move the buffer pointer.

    while (*lpBufPtr != 0x0A)

    lpBufPtr++;

    lpBufPtr++;

    if (g_Listing.NumHouses == 0 || g_Listing.NumHouses > MAX_HOUSES)

    {

    MessageBox(NULL, TEXT("Number of houses must be between 1 and 256"), NULL, MB_OK);

    GlobalFree(lpBufPtr);

    return FALSE;

    }

    // Read the house information for each line.

    for (count= 0; count < g_Listing.NumHouses; count++)

    {

        result = sscanf(lpBufPtr,
        TEXT("%[^','],%[^','],%[^','],%[^','],%[^','],%[^','],%s"),

        rgHouses[count].szAddress,rgHouses[count].szCity,

        szTemp, szBeds, szBaths, rgHouses[count].szAgent,

        rgHouses[count].szNumber);

        rgHouses[count].iPrice = atoi(szTemp);

        rgHouses[count].iBeds = atoi(szBeds);

        rgHouses[count].iBaths = atoi(szBaths);

        // Move the buffer pointer.

        while (*lpBufPtr != 0x0A)

            lpBufPtr++;

        lpBufPtr++;

    // Increment the house count for the city.

    for (index=0;index < g_Listing.NumCities; index++)

    {

        if (lstrcmp(rgHouses[count].szCity, rgCities[index].szCity) ==
         0)
        {

            rgCities[index].NumHouses++;

            break;

        }

    }

    }

    // Free up the buffer.

    GlobalFree(lpBufPtr);

    // Then add the cities and houses to the list view and tree

    // view controls.

    return TRUE;

}

VOID UpdateListView( HWND hwndLV, int iSelected )

{

    int count, index;

    LV_RemoveAllItems(hwndLV);

    for (index = 0, count = 0; count < g_Listing.NumHouses; count++)

    {

        if (lstrcmp(rgHouses[count].szCity,
             rgCities[iSelected].szCity) == 0)

        {

            // Add the house to the list view control.

            if (!LV_AddItem(hwndLV, index, &rgHouses[count]))

                MessageBox(NULL, TEXT("LV_AddItem failed!"), NULL,
                MB_OK);

            index++;

        }

    }

}

BOOL SaveToFile( HWND hWnd )

{

   HANDLE hFile;

   DWORD dwOpen;

   DWORD dwBytesWritten;

   TCHAR buf[MAX_PATH];

   DWORD dwFileSize;

   dwFileSize = GetDataBufferAndSize();

   if (dwFileSize == 0)

   {

       MessageBox(NULL,TEXT( "GetDataBufferAndSize failed!"), NULL,
                  MB_OK);

       return FALSE;

   }

   dwOpen = CREATE_ALWAYS;

   // Open the file.

   if ((hFile = CreateFile((LPCTSTR)OpenFileName.lpstrFile,

            GENERIC_WRITE,

            FILE_SHARE_WRITE,

            NULL,

            dwOpen,

            FILE_ATTRIBUTE_NORMAL,

            (HANDLE)NULL)) == (HANDLE)-1)

   {

        sprintf( buf, TEXT("Could not create file %s"),
             OpenFileName.lpstrFile );

         MessageBox( hWnd, buf, NULL, MB_OK );

         return FALSE;

   }

   // Write its contents into a file.

   if (WriteFile( hFile, (LPCVOID)lpBufPtr, dwFileSize,

     &dwBytesWritten, NULL) == FALSE)

   {

      MessageBox( hWnd, TEXT("Error writing file."), NULL, MB_OK );

      return FALSE;

   }

   // Close the file.

   CloseHandle(hFile);

   // Free up the file buffer.

   GlobalFree(lpBufPtr);

   return TRUE;

}

VOID InitTreeAndList( VOID )

{

    g_Listing.NumCities = 0;

    g_Listing.NumHouses = 0;

    g_Listing.iSelected = -1;

g_Listing.iSelHouse = -1;

    TreeView_DeleteAllItems(g_Listing.hWndTreeView);

    ListView_DeleteAllItems(g_Listing.hwndListView);

    TV_InitTreeView(g_Listing.hInst, g_Listing.hWndTreeView);

}


Handling Notification Messages

Notification messages are used extensively to manipulate the behavior and appearance of controls. Because status windows, toolbars, list view controls, and tree view controls all expect notification messages, you must ensure that each control gets the notifications it needs. In the main window procedure for the application, trap the WM_NOTIFY message and either handle the notification messages directly or pass them to handler functions.

case WM_NOTIFY:

    lpToolTipText = (LPTOOLTIPTEXT)lParam;

    if (lpToolTipText->hdr.code == TTN_NEEDTEXT)

    {

        LoadString(g_Listing.hInst,

                   lpToolTipText->hdr.idFrom,  // string ID == cmd ID

                   szBuf,

                   sizeof(szBuf));

        lpToolTipText->lpszText = szBuf;

    }

    if (TV_NotifyHandler(hWnd, message, wParam, lParam, &g_Listing))

    {

        // Update the list view control to show houses

        // in the selected city.

        UpdateListView(g_Listing.hWndListView, g_Listing.iSelected);

        // Update the status text.

        ChangeSBText(g_Listing.hInst, g_Listing.hWndStatus,
                     g_Listing.iSelected );

    }

    LV_NotifyHandler(hWnd, message, wParam, lParam, g_Listing.hInst);

    break;

For the toolbar, the sample application only traps the TTN_NEEDTEXT notification message, which is sent whenever the system needs to display a tooltip control associated with a toolbar button. In response to this notification message, the application must load the appropriate text string into the lpszText member of the LPTOOLTIPTEXT structure.

The tree view window's notification handler only handles the TVN_SELCHANGED notification message, which is sent to the tree view window whenever the selection changes.

LRESULT TV_NotifyHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM
                         lParam, LISTINFO *pList)

{

    static NM_TREEVIEW *pNm;

    pNm = (NM_TREEVIEW *)lParam;

    if (pNm->hdr.idFrom != ID_TREEVIEW)

        return 0L;

    switch(pNm->hdr.code)

    {

        case TVN_SELCHANGED:

            pList->iSelected = (int)(pNm->itemNew.lParam);

            return 1;

            break;

        default:

            break;

    }

return 0L;

In response, the application needs to update the list view control and status bar to reflect the house listings for the newly selected city.

VOID UpdateListView( HWND hwndLV, int iSelected )

{

    int count, index;

    // Remove the previous items.

    LV_RemoveAllItems(hwndLV);

    // Loop through the house listings.

    for (index = 0, count = 0; count < g_Listing.NumHouses; count++)

    {

        // Check whether the house is listed for the new city.

         if (strcmp(rgHouses[count].szCity,
             rgCities[iSelected].szCity) == 0)

         {

             // If it is, add the house to the list view control.

             if (!LV_AddItem(hwndLV, index, &rgHouses[count]))

                 MessageBox(NULL, "LV_AddItem failed!", NULL, MB_OK);

             index++;

         }

    }

}

Handling notification messages for the list view window is a bit more complicated. The application implements the list view control using a callback function that receives the text for each item, so the notification handler needs to trap the LVN_GETDISPINFO notification message and fill in the pszText member of the LV_ITEM structure with the appropriate text, depending on the column.

The application also processes the LVN_COLUMNCLICK notification message in the list view notification handler. This notification message is sent whenever the user clicks a column heading in the list view control. In response, the application must sort the items in the list view control based on the criteria presented in the selected column. For example, if the user clicks the Bedrooms column, the application sorts the list in ascending order by the number of bedrooms for the item (that is, the house). The application uses a simple callback function that is called by using the ListView_SortItems macro. The callback function sorts the data using simple math (returning the greater of two values) for the columns that have integer sort criteria and using the strcmp function for the columns that have string sort criteria.

LRESULT LV_NotifyHandler(HWND hWnd, UINT uMsg, WPARAM wParam,
                          LPARAM lParam, HINSTANCE hInst)

{

    LV_DISPINFO *pLvdi = (LV_DISPINFO *)lParam;

    NM_LISTVIEW *pNm = (NM_LISTVIEW *)lParam;

    HOUSEINFO *pHouse = (HOUSEINFO *)(pLvdi->item.lParam);

    static TCHAR szText[TEMP_LEN];

    if (pNm->hdr.idFrom != ID_LISTVIEW)

        return 0L;

    switch(pLvdi->hdr.code)

    {

        case LVN_GETDISPINFO:

            switch (pLvdi->item.iSubItem)

            {

                case 0:     // address

                    pLvdi->item.pszText = pHouse->szAddress;

                    break;

                case 1:     // city

                    pLvdi->item.pszText = pHouse->szCity;

                    break;

                case 2:     // price

                    sprintf(szText, "$%u", pHouse->iPrice);

                    pLvdi->item.pszText = szText;

                    break;

                case 3:     // number of bedrooms

                    sprintf(szText, "%u", pHouse->iBeds);

                    pLvdi->item.pszText = szText;

                    break;

                case 4:     // number of bathrooms

                    sprintf(szText, "%u", pHouse->iBaths);

                    pLvdi->item.pszText = szText;

                    break;

                default:

                    break;

            }

            break;

        case LVN_COLUMNCLICK:

            // The user clicked on one of the column headings,
            // so sort by this column.

            ListView_SortItems(pNm->hdr.hwndFrom,ListViewCompareProc,

                               (LPARAM)(pNm->iSubItem));

            break;

        default:

            break;

    }

    return 0L;

}

int CALLBACK ListViewCompareProc(LPARAM lParam1, LPARAM lParam2,
                                 LPARAM lParamSort)

{

    HOUSEINFO *pHouse1 = (HOUSEINFO *)lParam1;

    HOUSEINFO *pHouse2 = (HOUSEINFO *)lParam2;

    int iResult;

    if (pHouse1 && pHouse2)

    {

        switch( lParamSort)

        {

            case 0:     // sort by address

                iResult = lstrcmpi(pHouse1->szAddress,

                    pHouse2->szAddress);

                break;

            case 1:     // sort by city

                iResult = lstrcmpi(pHouse1->szCity, pHouse2->szCity);

                break;

            case 2:     // sort by price

                iResult = pHouse1->iPrice - pHouse2->iPrice;

                break;

            case 3:     // sort by number of bedrooms

                iResult = pHouse1->iBeds - pHouse2->iBeds;

                break;

            case 4:     // sort by number of bathrooms

                iResult = pHouse1->iBaths - pHouse2->iBaths;

                break;

            default:

                iResult = 0;

                break;

        }

    }

    return(iResult);

}


Adding Pop-up Context Menus

At this point, the application is functional, but you still need to add the pop-up menu that is displayed when the user clicks mouse button 2. There are two ways to do this. The easiest method is to trap the WM_CONTEXTMENU message and check the wParam parameter to see if the click occurred in the list view window. WM_CONTEXTMENU is sent whenever the user clicks mouse button 2. Another method is to handle the NM_RCLICK notification message and call the ListView_HitTest macro to determine which item, if any, the user has clicked. NM_RCLICK is sent whenever the user clicks mouse button 2 in the list view window.

To display a context menu for an item, you load the menu and call the TrackPopupMenu function. When the user chooses an item from the menu, the appropriate command is generated and sent to the window procedure in the form of a WM_COMMAND message.

case WM_CONTEXTMENU:

    // Mouse button 2 has been clicked.

    if ((HWND)wParam == g_Listing.hWndListView)

    {

         // Get the menu for the pop-up menu from the resource file.

         hMenu = LoadMenu(g_Listing.hInst, "HousePopupMenu");

         if (!hMenu)

             break;

         // Get the first submenu in it for TrackPopupMenu.

         hMenuTrackPopup = GetSubMenu(hMenu, 0);

         // Draw the "floating" pop-up menu, and track it.

         TrackPopupMenu(hMenuTrackPopup,

                        TPM_LEFTALIGN | TPM_RIGHTBUTTON,

                        LOWORD(lParam), HIWORD(lParam),

                        0, g_Listing.hWndListView, NULL);

        // Destroy the menu.

        DestroyMenu(hMenu);

    }

    break;


Incorporating Property Sheets

Property sheets (also known as tabbed dialog boxes) allow users to view and change the properties of an item. In the sample application, the item is a house listing. Each property sheet contains one or more overlapping windows (called pages) that contain a logical grouping of properties. The user switches between pages by clicking tabs that label each property page. The sample contains two property sheets: one allowing the user to view and change the properties for a particular house listing (for example, address and city) and the other displaying information about the listing agent (for example, name and phone number). The following illustration shows the House Listing property sheet page. (An illustration of the Listing Agent property sheet page is found later in this section.)

Processing a property sheet page is similar to processing a dialog box with one major difference. When you process a property sheet page, you handle notification messages instead of the commands generated for the OK and Cancel buttons. You should process the property sheet pages in the following manner:

•	Save the original values for the item in response to the WM_INITDIALOG message.

•	Reset the values of the item in response to the PSN_APPLY and PSN_KILLACTIVE notification messages.

•	Reset the values of the item in response to a PSN_RESET notification message.

•	Set the edit fields in the page for the item in response to the PSN_SETACTIVE notification message.

To initialize the property sheet pages, you need to determine which house is currently selected and save that information for future reference. The first property sheet page displayed is the House Listing page. Responding to the WM_INITDIALOG message gives you the first chance to determine the currently selected house. The following example determines the index of the selected house within the global array of houses.

static char szAddSave[MAX_ADDRESS];

BOOL bErr;

int index, count;

LV_ITEM lvItem;

.

.

.

  case WM_INITDIALOG:

    // Fill in the list box with the cities.

    for (index = 0; index < g_Listing.NumCities; index++)

        SendDlgItemMessage(hDlg, IDE_CITY, CB_INSERTSTRING,
                           (WPARAM)(-1),
                           (LPARAM)(rgCities[index].szCity));

    // Get the index to the selected list view item.

    index = ListView_GetNextItem(g_Listing.hWndListView,

                                 -1, MAKELPARAM(LVNI_SELECTED, 0));

    // Get the house address.

    lvItem.iItem = index;

    lvItem.iSubItem = 0;

    lvItem.mask = LVIF_TEXT;

    lvItem.cchTextMax = sizeof(szAddSave);

    lvItem.pszText = szAddSave;

    ListView_GetItem(g_Listing.hWndListView,&lvItem);

    // Find the house in the list.

    for (count=0; count < g_Listing.NumHouses; count++)

    {

        if (strcmp(lvItem.pszText, rgHouses[count].szAddress) == 0)

            break;

    }

    g_Listing.iSelHouse = count;

.

.

.

The Listing Agent property sheet page allows the user to view and change the name and phone number of the listing agent associated with the selected house. The code used to handle this page is quite similar to that used for the House Listing page, except that the szAgent and szNumber members of the array of HOUSEINFO structures are modified instead of the other house-specific fields. The following illustration shows the Listing Agent property sheet page.


Using the Registry

The registry is a central storage location that contains current information about the computer hardware configuration, installed software applications, settings and preferences of the current user, and associations between types of files and the applications that access and manipulate their contents. Much of the information that was stored in initialization files in early versions of the Microsoft® Windows® operating system is now stored in the registry in Windows 95.


About Using the Registry

Mentions of the registry occur in several places in the documentation for Windows 95 and in the Microsoft® Win32® Software Development Kit (SDK). The documentation included in the Win32 SDK provides a detailed description of the functions and structures that provide an application with access to the registry. The Windows Interface Guidelines for Software Design has a chapter containing a general discussion of the registry. The Microsoft Windows 95 Resource Kit devotes a chapter to integrating an application into the Windows 95 operating system by storing information in the registry.  If you are unfamiliar with the registry or the arrangement of information within it, you should read about the registry before beginning this article. This article assumes you are already familiar with the registry and focuses on using the registry functions to navigate and load the registry as part of installing an application.

After briefly introducing registry terminology, this article identifies procedures involved in working with the registry when installing a software product. Other issues, such as the general registry structure and Windows 95 style recommendations, are mentioned in support of the registry coding described here.

This article describes how to record the following types of information in the registry:

•	Application state information

•	Application path information

•	Filename extensions

•	New data files

•	Icons

•	Icon commands

•	Uninstall information

This article frequently refers to a fictitious company called Buzz Productions, whose fictitious product is named BeeSounds. The product comprises an executable file named BUZZER.EXE, a dynamic-link library (DLL) named BUZZEXT.DLL, and a help file named BUZZER.HLP. Data files used by the product are identified by the .BZZ filename extension.


Introducing the Registry

The registry is a hierarchical database. The database is made up of keys that are linked together to form hierarchies or tree structures. The keys are the fundamental entities in the database. The registry has six keys, also called root keys, that serve as entrypoints to the database for any application. Links provide a mechanism to traverse the database from a root key to other keys. The link between two keys also serves to establish the relationship of a subkey. A subkey is further from the root of the hierarchy than the other key in the link.

Each key has a name and a default value. A key can also have other named values associated with it. A value can be named or unnamed and has its own storage area for a data value. The data value can store binary, numerical, string, or other types of data.

The registry contains information that is critical to the correct operation of the computer. Before accessing and modifying the contents of the registry, you should make a back up copy of the registry. You can do this using the RegEdit utility.

Note  The registries for Windows 95 and Microsoft® Windows NT™ differ in how they handle class information associated with a key. The Windows 95 registry treats all classes alike. If you pass in a valid lpszClass buffer pointer to RegQueryInfoKey but do not pass in a valid lpcchClass pointer (that is, if you pass in NULL), Windows 95 lets the function call proceed.

The Window NT registry, however, distinguishes the different classes. In Windows NT, if you pass in a valid lpszClass buffer pointer to RegQueryInfoKey but do not pass in a valid lpcchClass pointer (that is, if you pass in NULL), the system returns the ERROR_INVALID_PARAMETER error value.


Registering Application State Information

Application state information identifies information about a specific release of a software product, such as the product name, version number, user preferences, and component location. The registry provides two entry level hierarchies for storing this information. Application state information for the current version of a software product that is user-specific is stored in the registry in the following portion of the HKEY_CURRENT_USER hierarchy.

HKEY_CURRENT_USER
    Software
        BuzzProductions
            BeeSounds
                Version2.00

Application state information for the current version of a software product that is specific to an installation (and relevant to all users) is stored in the following portion of the HKEY_LOCAL_MACHINE hierarchy.

HKEY_LOCAL_MACHINE
    SOFTWARE
        BuzzProductions
            BeeSounds
                Version2.00

You can add additional keys and values under your application's Version key in each hierarchy. Key names are canonical; they cannot be changed, so you can use them to group the information types being stored. Key values can easily be changed and are ideal for storing information that changes, such as user preferences.

If the amount of installation-specific and user version information exceeds a few thousand bytes, you might still want to create an initialization (.INI) file.


Registering Application Path Information

Application path information identifies where the application file (.EXE file), application extension files (.DLL files), and other support files for an application are stored in the Windows 95 file system. By following the conventions recommended in The Windows Interface Guidelines for Software Design, the files for the BeeSounds sample product would be installed in the following directories.

Filename	Directory
BUZZER.EXE	\Program Files\BeeSounds
BUZZEXT.DLL	\Program Files\BeeSounds\System
BUZZER.HLP	\Program Files\BeeSounds\System
*.BZZ (data files)	\Program Files\BeeSounds\System
The registry stores directory information that locates the installed application files and their associated application extension files in one or more keys of the HKEY_LOCAL_MACHINE hierarchy. For the BUZZER.EXE file, the key is inserted in the following hierarchy.

HKEY_LOCAL_MACHINE

    SOFTWARE

        Microsoft

            Windows

                CurrentVersion

                    App Paths

                        BUZZER.EXE

Each installed application file should have a key under the App Paths key named after the application file.

The BUZZER.EXE key has two values. The Default value specifies the path to the application file. The optional Path value specifies the paths to other application files.

Note  If an application shares application extension files, the installation program should create a SharedDLLs key under the CurrentVersion key. Under the SharedDLLs key, the installation program should create a key and a data value for each shared file. The key name for each shared file must specify the path and filename of the shared file. The data value associated with the key for a shared file tracks the number of applications that share the application extension file.

You can add keys under the CurrentVersion key in both the HKEY_CURRENT_USER and the HKEY_LOCAL_MACHINE hierarchies to expand the capabilities of an application.

For example, you can automatically start your application whenever Windows 95 starts up by adding the Run key beneath the CurrentVersion key and by including a data value for the Run key that specifies the command line to start the application.

You can automatically restart an application that was interrupted by a system shutdown when Windows 95 starts up by adding the RunOnce key beneath the CurrentVersion key and by including a data value for the RunOnce key that specifies the command line to restart the application. The command line must specify the path to the application file, appropriate data files, and any options needed to restore the application.


Registering Filename Extensions

You can distinguish new file types by registering the filename extensions in the registry. Every file type that you install in the registry requires at least two registry keys. One of the mandatory keys specifies the filename extension. The other mandatory key specifies the application identifier and defines a long (40 character) description of the application identifier or class name that end users will see. Additional keys can specify a class identifier and a short (15 character) description of the application identifier or class name.

The registry stores filename extensions in the HKEY_CLASSES_ROOT hierarchy. The keys needed to register the filename extension used by the BeeSounds data files follow. Note that the CLSID class identifier is not a literal value; it is a unique identifier that can be obtained by running the UUIDGEN.EXE utility included in the Win32 SDK.

HKEY_CLASSES_ROOT
    .BZZ = BeeSounds

    BeeSounds

        CLSID

    CLSID

        {CLSID identifier}

            AuxUserType

                2


Registering Data Files for Creation

If you would like users to be able to create new data files for an application directly from the desktop or folder without running the application, you should register the filename extension for creation.

The registry stores information for data file creation in the HKEY_CLASSES_ROOT hierarchy. The keys needed to register data files used by the BeeSounds data files follow. The ShellNew key has a value associated with it. The value used is the default value, and it contains the string "NullFile".

HKEY_CLASSES_ROOT
    .BZZ

        ShellNew


Registering Icons

Windows 95 determines the icon to display for each file from information stored in the registry. If you would like the user to distinguish data files used by your application from other generic (unidentified) files stored on the file system, you can install icons to associate with a specific file type and register the icon and file association in the registry.

The registry stores icon information in the HKEY_CLASSES_ROOT hierarchy. The keys needed to register an icon for data files used by the BeeSounds data files follow. The DefaultIcon key has a value associated with it. The value used is the default value, and it contains a string identifying the path and file that contains the icon, and either an positive index value or a negative resource identifier that specifies the icon resource within the file. The value can be "%", indicating a per-instance icon (for more infomation about per-instance icons, see "Shell Extensions."

The following example shows a sample DefaultIcon key and its associated value:

HKEY_CLASSES_ROOT
    BeeSounds

        DefaultIcon = "C:\BEE\buzzer.exe, 1"

The file containing the icon can be an application file, an application extension file, or a resource file containing one or more resources. If the first resource in a file is the icon you want to associate with a file, you can omit the comma and index value from the data of the default value.


Registering Icon Commands

Clicking with mouse button 2 on an icon displays a menu of commands that can be executed with the icon. Support for many of these commands is provided by the container (folder or desktop) containing the icon. However, containers do not provide support for the primary commands (Open, Edit, Play, and Print) that can be executed with an icon, nor do they provide support for custom commands. For each primary command or custom command that you want to provide to the user, you must register information for the command. For example, the BeeSounds product supports the Play primary command and the custom command "Play in Reverse."

The registry stores information for icon command support in the HKEY_CLASSES_ROOT hierarchy. The keys needed to register data files used by the BeeSounds data files follow. The Shell key has a value associated with it. The value's name is default, and it has contains the string "Play, Play_In_Reverse".

HKEY_CLASSES_ROOT
    BeeSounds

        Shell

            Play

                command = "C:\WINDOWS\buzzer.exe /play %1"

            Play_In_Reverse

                command = C:\WINDOWS\buzzer.exe /reverse %1"

The Play key has a value associated with it. The value used is the default value, and it contains the text that is displayed in the menu. This value must be localized (for example, "&Play"). If key name matches the menu text, you do not need to specify a value for the key. The command key under the Play key specifies as its value the command line that implements the Play command.

The Play_In_Reverse key uses the default value that contains the "Play In Reverse" text that appears in the menu. The command key under the Play_In_Reverse key specifies as its value the command line that implements the "Play in Reverse" command.

When displaying the menu for an icon, the system lists the order of the commands as they appear under the Shell key. You can override that sequence by specifying a preferred sequence as a comma-delineated key list in the default value of the Shell key. The first command listed in the menu becomes the default command for an icon.


Registering Uninstall Information

Windows 95 includes a property sheet for Control Panel for installing and removing applications. Users might need to remove an application to recover disk space or to move the application to another location. To facilitate this, you should provide an uninstall program with your software application that removes the files and their settings and records information about the application in the registry.

The registry stores uninstall information in the HKEY_LOCAL_MACHINE hierarchy. The keys needed to register uninstall information for the BUZZER.EXE application follow.

HKEY_LOCAL_MACHINE
    SOFTWARE
        Microsoft
            Windows
                CurrentVersion

                    Uninstall

                        BUZZER.EXE

The BUZZER.EXE key has two named values that are required for each application key in the Uninstall hierarchy. The DisplayName value specifies a text string that the Add/Remove Programs property sheet of Control Panel displays to the user. The UninstallString value specifies the command line that runs the uninstall program, and it must specify the path, application file, and needed command-line arguments. For the BeeSounds product, this value is "c:\Program Files\BeeSounds\NOBUZZ.EXE /q."

The following example registers the uninstall information for the BeeSounds product.

case  IDM_REGUNINSTALL:        //register uninstall information

// 1. Navigate to the CurrentVersion key.

// 2. Create CurrentVersion\Uninstall\BUZZER.EXE key(s).

// 3. Create DisplayName and UninstallString values for BUZZER.EXE key.

// 4. Close the keys.

    // Prepare to navigate to the CurrentVersion key.

    hKey = HKEY_LOCAL_MACHINE;

    lstrcpy(lpszChildKey,
        (LPCSTR)"SOFTWARE\\Microsoft\\Windows\\CurrentVersion");

    dwReserved = 0;

    hChildKey = NULL;

    lpszKeyValue = szKeyValue;

    if (ERROR_SUCCESS == RegOpenKeyEx(hKey, lpszChildKey, dwReserved,
        KEY_READ|KEY_WRITE, &hChildKey))

    {

        MessageBox(hwnd, lpszChildKey, "Register Uninstall",MB_OK);

    }

    else {

        MessageBox(hwnd,"Key is not immediate child of other key",
            "Register App Path",MB_OK);

        break;

    }

    // Prepare to create Uninstall\BUZZER.EXE key(s).

    hKey = hChildKey;

    // Identify the filename extension.

    lstrcpy(lpszChildKey,(LPCSTR)"Uninstall\\BUZZER.EXE");

    lstrcpy(lpszClassType,"");     // class identifier for new key

    dwReserved = 0;

    hChildKey = NULL;

    fdwOptions = REG_OPTION_NON_VOLATILE;

    dwDisposition = 0L;    // clear returning parameter for create

    lpdwDisposition = &dwDisposition;

    dwDisposition2 = 0L;   // clear return parameter for nested create

    lpdwDisposition2 = &dwDisposition2;

    if (ERROR_SUCCESS == RegCreateKeyEx(hKey, lpszChildKey, dwReserved,
            lpszClassType, fdwOptions,
            KEY_ALL_ACCESS, NULL, &hChildKey, lpdwDisposition))

    {

        switch (dwDisposition){

        case REG_CREATED_NEW_KEY:

            // Create the DisplayName and UninstallString values.

            MessageBox(hwnd,"Create BUZZER.EXE a Success",
                "Creating key",MB_OK);

            lstrcpy (lpszKeyValueName, (LPCSTR)"DisplayName");

            lstrcpy (lpszKeyValue,
                (LPCSTR)"BeeSounds Removal Application");

            RegSetValueEx(hChildKey, lpszKeyValueName, dwReserved,
                REG_SZ, lpszKeyValue, sizeof(*szKeyValue));

            lstrcpy (lpszKeyValueName, (LPCSTR)"UninstallString");

            lstrcpy (lpszKeyValue,
                (LPCSTR)"C:\\Program Files\\BeeSounds\\NOBUZZ.EXE /q");

            RegSetValueEx(hChildKey, lpszKeyValueName, dwReserved,
                REG_SZ, lpszKeyValue, sizeof(*szKeyValue));

            RegCloseKey(hChildKey);

            RegCloseKey(hKey);

            break;

        case REG_OPENED_EXISTING_KEY:

        // This case should not apply, assuming it is a new installation

        // or the CurrentVersion hierarchy was copied and then deleted.

        // So, delete the existing key and create a new one.

            MessageBox(hwnd,"Create BUZZER.EXE failed",
                "Creating key",MB_OK);

            RegDeleteKey(hKey, hChildKey);

            RegCreateKeyEx(hKey, lpszChildKey, dwReserved,
                lpszClassType, fdwOptions,
                KEY_ALL_ACCESS, NULL, &hChildKey, lpdwDisposition2);

            if (dwDisposition2 == REG_CREATED_NEW_KEY)

            {

            // The second try worked. Now add values.

            lstrcpy (lpszKeyValueName, (LPCSTR)"DisplayName");

            lstrcpy (lpszKeyValue,
                (LPCSTR)"BeeSounds Removal Application");

            RegSetValueEx(hChildKey, lpszKeyValueName, dwReserved,
                REG_SZ, lpszKeyValue, sizeof(*szKeyValue));

            lstrcpy (lpszKeyValueName, (LPCSTR)"UninstallString");

            lstrcpy (lpszKeyValue,
                (LPCSTR)"C:\\Program Files\\BeeSounds\\NOBUZZ.EXE /q");

            RegSetValueEx(hChildKey, lpszKeyValueName, dwReserved,
                REG_SZ, lpszKeyValue, sizeof(*szKeyValue));

            RegCloseKey(hChildKey);

            RegCloseKey(hKey);

            }

            break;

        default:        // other status returned?

            MessageBox(hwnd,"Function successful,
                but status unexpected", "Creating key",MB_OK);

        }

    }

    else {

        MessageBox(hwnd,"Error--Couldn't create key",
            "Creating key",MB_OK);

    }

    // The second attempt did not create a new key.

    if (dwDisposition2 != REG_CREATED_NEW_KEY)

    {  // Place the error correction code here.

    }

    break;

If an application is being removed, the usage count for each shared and system-wide shared application extension file needs to be decremented. If the usage count for a file reaches zero, the user should be given the option of deleting the file.


Dragging and Dropping

This article explains the general concepts that you need to know to support OLE drag and drop capabilities in your applications and lists the basic steps for implementing drag and drop support.


About Dragging and Dropping

A Microsoft® Windows® 95 − based application should fully support the source and target drag and drop capabilities provided by OLE. One of the most attractive features of drag and drop in OLE is that the code that handles the actual data transfer — your implementation of the IDataObject interface — is reusable. You will be able to use the same code to implement cut and paste. OLE separates what the user does to cause the data transfer from how the applications actually transfer the data. This allows you to use the same "back-end" IDataObject interface for any number of ways that the user may want to transfer data.

This article is based in part on "Drag and Drop Target Practice: Implementing OLE 2.0 Support in Your Applications," (Microsoft Developers Network News, January 1994), by Sara Williams.


General OLE Concepts

One of the most attractive aspects of OLE is that it is completely modular. It is designed so that each component can exist, for the most part, on its own. For example, you can add drag and drop support to your application without bothering with in-place activation, automation, or compound storage.

Even if your application only uses a small part of OLE, the Component Object Model (COM) enables other applications to know what your application's OLE capabilities are. COM is the fundamental, underlying model that OLE is based upon; all OLE objects are also component objects.

COM stipulates that any component object must control its own life span and be able to tell other objects about its capabilities in a strictly defined manner. To control its life span, a component object maintains a reference count. Capabilities are grouped into logical sets called interfaces; each interface is a set of member functions necessary to support a certain capability. The "strictly defined manner" that component objects must use is itself an interface, which is called IUnknown. Because all OLE interfaces are derived from IUnknown, they are component objects. IUnknown has three member functions: QueryInterface, AddRef, and Release.

An object uses QueryInterface to tell other objects about its capabilities. If the object implements the requested interface, it returns a pointer to the interface. If it does not implement it, it returns the E_NOTIMPL error value stating that the object does not support the requested interface. AddRef and Release are used to control the object's life span. An object's AddRef member function is called when another object holds a pointer to the object, and the Release member function is called when the pointer is no longer needed. If a call to Release causes the object's reference count to go to zero, the object can safely unload itself.

COM provides a couple of immediate benefits:

•	An object can determine in advance if another object supports a certain feature. If the other object does not support the feature, the calling object can react accordingly.

•	Objects do not remain in memory longer (or shorter) than necessary, and they do not rely on the user to launch or close them.

OLE's new data transfer mechanism is a crucial element of drag and drop support. Data transfer in OLE allows objects to be very specific about the data that they transfer. Instead of simply being able to transfer a plain old bitmap, an object can now transfer a bitmap of the object's contents rendered for a printer device and stored in a stream to be released by OLE.

To accomplish this, OLE uses the IDataObject interface and the FORMATETC and STGMEDIUM structures. Applications implement IDataObject to accomplish all data transfer in OLE; it includes member functions that set and retrieve an object's data, enumerate the available data formats, and receive data change notifications. FORMATETC and STGMEDIUM provide the specific details about the data that is being transferred—that is, the target device, aspect, storage medium, and release method.

Every drag and drop operation involves two objects: a source and a target. The source object contains the data to be dragged, and the target object accepts the dragged data.


Adding Drop Source Capabilities

To enable your application to become the source of a drag and drop operation, follow these steps:

1.	Initialize the OLE libraries. Any application that uses the OLE libraries must check the version of the libraries and call the OleInitialize function during its initialization.

You should use the GetBuildVersion function to make sure that the system's OLE libraries are at least as recent as the ones for which the application was written.

Before you call any other OLE functions, you must call OleInitialize to initialize the OLE libraries. Because each call to OleInitialize must have a matching call to the OleUninitialize function, you should maintain an fOleInitialized flag so that you will know whether to call OleUninitialize when your application exits.

2.	Implement the IDropSource interface. Not including the member functions that it inherits from IUnknown, IDropSource has only two member functions: QueryContinueDrag and GiveFeedback. OLE calls QueryContinueDrag intermittently during the drag operation. Its parameters include the state of the keyboard, which the drop source uses to control the drag operation. The drop source returns the S_OK value to continue dragging, the DRAGDROP_CANCEL value to cancel dragging, or the DRAGDROP_DROP value to drop the object.

3.	OLE calls GiveFeedback to tell the drop source to update the cursor and ask the source window for visual feedback about what would happen if the user dropped at the current point. It sounds like a lot of work to update the cursor, but OLE will use its default cursors if the DRAGDROP_S_USEDEFAULTCURSORS value is returned.

4.	Implement the IDataObject interface, which is used by OLE applications to transfer data. In a drag and drop operation, the drop source gives OLE a pointer to its IDataObject implementation. OLE saves the pointer and passes it to the drop target when the cursor first enters the target window and when the drop occurs. Fortunately, you only need to implement the following (non-IUnknown) IDataObject member functions for drag and drop support: GetData, GetDataHere, QueryGetData, and EnumFormatEtc.

5.	Call the DoDragDrop function to begin the drag operation. After you have detected that the user wants to drag something, you should call DoDragDrop. OLE uses the IDataObject and IDropSource pointers that are passed in, along with its list of registered drop targets, to control the drag operation. When the drag operation is complete, DoDragDrop returns either the DRAGDROP_S_DROP or DRAGDROP_S_CANCEL value. In addition, OLE returns a DWORD in the address pointed to by pdwEffect that tells how the drop should affect the source data—that is, whether the operation was a move, copy, link, or scroll. You should look at the pdwEffect value and modify the source data as necessary.

6.	Call OleUninitialize. Before an OLE application exits, it must call OleUninitialize to release the OLE libraries. You should check your fOleInitialized flag before calling OleUninitialize and should only call OleUninitialize if OleInitialize returned successfully.


Adding Drop Target Capabilities

To enable your application to become a drop target, follow these steps:

1.	Initialize the OLE libraries. You should check the build version and call the OleInitialize function exactly as you would for a drop source.

2.	Call the RegisterDragDrop function. OLE keeps a list of the windows that are drop targets. Every window that accepts dropped objects must register itself and its IDropTarget interface pointer. Then when the user drags the object over a drop target window, OLE has the IDropTarget interface pointer handy.

3.	Implement the IDropTarget interface. OLE uses the IDropTarget interface pointer that you registered with RegisterDragDrop to keep you informed of the state of a drop operation.

When the cursor first enters a registered drop target window, OLE calls the IDropTarget::DragEnter member function. In this member function, you should ensure that your application can create the dragged object if it is dropped. Your application may also display visual feedback showing where the dropped object will appear, if appropriate.

When the cursor moves around inside a drop target window, OLE calls the IDropTarget::DragOver member function, just as Windows 95 sends WM_MOUSEMOVE messages. Here you should update any visual feedback that your application displays to reflect the current cursor position. When the cursor leaves a drop target window, OLE calls the IDropTarget::DragLeave member function. In your DragLeave member function, you should remove any feedback you displayed during DragOver or DragEnter.

OLE calls your IDropTarget::Drop member function when the user drops the object. To be precise, a drop occurs when the drop source returns the DRAGDROP_DROP value from the IDropSource::QueryContinueDrag member function. In your Drop member function, you should create an appropriate object from IDataObject that is passed as a parameter. The following example shows how to implement IDropTarget::Drop.

STDMETHODIMP CDropTarget::Drop (LPDATAOBJECT pDataObj,
    DWORD grfKeyState, POINTL pointl, LPDWORD pdwEffect)

{

    FORMATETC fmtetc;

    SCODE sc = S_OK;

    UndrawDragFeedback(); // removes any visual feedback

    // QueryDrop returns TRUE if the app. can accept a drop based on

    // the current key state, requested action, and cursor position.

    if (pDataObj && QueryDrop(grfKeyState,pointl,FALSE,pdwEffect)) {

        m_pDoc->m_lpSite = CSimpleSite::Create(m_pDoc);

        m_pDoc->m_lpSite->m_dwDrawAspect = DVASPECT_CONTENT;

        // Initialize the FORMATETC structure.

        fmtetc.cfFormat = NULL;

        fmtetc.ptd = NULL;

        fmtetc.lindex = -1;

        fmtetc.dwAspect = DVASPECT_CONTENT; // draws object's content

        fmtetc.tymed = TYMED_NULL;

        HRESULT hrErr = OleCreateFromData

            (pDataObj,IID_IOleObject,OLERENDER_DRAW,

            	&fmtetc, &m_pDoc->m_lpSite->m_OleClientSite,

            m_pDoc->m_lpSite->m_lpObjStorage,

            (LPVOID FAR *)&m_pDoc->m_lpSite->m_lpOleObject);

        if (hrErr == NOERROR)

            // The object was created successfully.

        else

            // The object creation failed.

            sc = GetScode(hrErr);

    }

    return ResultFromScode(sc);

}

4.	Call the RevokeDragDrop function. Before a drop target window is destroyed, it must call RevokeDragDrop to allow OLE to remove the window from its list of drop targets.

5.	Uninitialize the OLE libraries. Like a drop source, your application needs to uninitialize the OLE libraries before terminating.


Other Drag and Drop Considerations

You can use OLE drag and drop to add drag and drop support within your own application. There is nothing to stop your application from being both a drop source and a drop target or from accepting dropped objects from itself.

This article does not discuss reference counting, although it is a crucial part of implementing a stable OLE application.


Scrap Files

Windows 95 allows the user to transfer objects within a data file to the desktop or a folder. The result of the transfer operation is a file icon called a scrap. An OLE application automatically supports the creation of scrap files if its IDataObject interface supports enough data formats so that the drop target can create either an embedding or a shortcut object. You do not need to add any other functionality to your application to allow the user to create a scrap file. However, there are two optional features you may wish to add to your application: round-trip support and caching additional data formats in a scrap file. Round-trip support means that an object can be dragged out of a document and into a new container and then dragged from the new container back into the original document.


Round-Trip Support

When the user transfers a scrap into your application, it should integrate the scrap as if it were being transferred from its original source. For example, if a selected range of cells from a spreadsheet is transferred to the desktop, they become a scrap. If the user transfers the resulting scrap into a word processing document, the cells should be incorporated as if they were transferred directly from the spreadsheet. Similarly, if the user transfers the scrap back into the spreadsheet, the cells should be integrated as if they were originally transferred within that spreadsheet.

Your application must include code that integrates a scrap into a document; otherwise, the embedding object of the scrap is copied into the document rather than the data associated with the scrap. To retrieve the data for the scrap, your application must examine the class identifier, CLSID, of the scrap object by retrieving the CF_OBJECTEDESCRIPTOR file format data. If the application recognizes the CLSID, the application should transfer the native data into the document rather than calling the OleCreateFromData function.


Caching Additional Data Formats

When an IDataObject is dropped onto a file system folder, such as the desktop, the shell receives the CLSID of the object and looks for the list of clipboard formats to be cached in the scrap file. The list is located in the following registry location.

HKEY_CLASSES_ROOT\CLSID\{clsid}\DataFormats\PriorityCacheFormats

The clipboard formats should be added to the registry as the names of named values (the value should be empty). The additional formats give the user more choices when copying the scrap file and opening the Paste Special dialog box from another application. You should choose only useful formats to keep the scrap file from becoming too large. For example, WordPad scrap-caches the RTF format, and MSPaint scrap-caches the CF_BITMAP format.

HKEY_CLASSES_ROOT\CLSID\{D3E34B21-9D75-101A-8C3D-00AA001A1652}\DataFormats\PriorityCacheFormats,"#8",,""

HKEY_CLASSES_ROOT\CLSID\{73FDDC80-AEA9-101A-98A7-00AA00374959}\DataFormats\PriorityCacheFormats,"Rich Text Format",,""


Delayed Rendering

You can specify the list of clipboard formats to be delay-rendered under the HKEY_CLASSESROOT\CLSID\{clsid}\DataFormats\PriorityCacheFormats key. The IDataObject of a scrap object with this CLSID will offer these formats in addition to the native data and cached data. When the drop target requests one of these formats, the shell runs the application and renders the format from the active object. However, you should avoid using this mechanism because it does not work if the server is not available or if the application is a non-OLE application.


Clipboard Formats for Shell Data Transfers

Windows 95 allows the user to transfer data objects between applications and the shell. The user can transfer data objects, such as printers, files, shortcuts, and folders, either by dragging and dropping them or by using the Cut, Copy, and Paste menu commands. Both transfer methods involve the clipboard.

Windows 95 defines several clipboard formats that you must support to transfer objects between your application and the shell. The Windows header files do not include predefined clipboard format identifiers for these clipboard formats. Instead, they provide a set of clipboard format names and corresponding values. To obtain an identifier for a clipboard format, you simply pass the format's value to the RegisterClipboardFormat function. The following table lists the values and corresponding clipboard format names.

Value	Format name
CFSTR_SHELLIDLIST	"Shell IDList Array"
CFSTR_SHELLIDLISTOFFSET	"Shell Object Offsets"
CFSTR_NETRESOURCES	"Net Resource"
CFSTR_FILEDESCRIPTOR	"FileGroupDescriptor"
CFSTR_FILECONTENTS	"FileContents"
CFSTR_FILENAME	"FileName"
CFSTR_PRINTERGROUP	"PrinterFriendlyName"
CFSTR_FILENAMEMAP	"FileNameMap"
The following sections describe the clipboard formats used to transfer data between applications and the shell.


"FileName" Format

The global memory object contains a single null-terminated and fully qualified filename. This format is supported for compatibility with applications written for Windows version 3.1. New applications should support the CF_HDROP clipboard format instead of the "FileName" format.


"FileNameMap" Format

The "FileNameMap" format is used with the CF_HDROP clipboard format to rename a list of files that are copied to a new location during a copy and paste operation or a drag and drop operation. Data in the "FileNameMap" format consist of a double-null terminated list of filenames that correspond to the filenames in the CF_HDROP data. When the files listed in the CF_HDROP data are copied to the new location, the files receive the new names specified in the "FileNameMap" data. For example, if the CF_HDROP data contains two files with the names c:\temp.000 and c:\temp.001, the "FileNameMap" data contains the following list of filenames.

"new.txt\0another.txt\0\0"

If the files are copied to c:\target, they receive the following names.

c:\target\new.txt(was c:\temp.000)

c:\target\another.txt(was c:\temp.001)

The system stores files in the recycle bin using a coding system for the filenames (dcxxxx.ext). When the user drags or copies files from the recycle bin, the system uses the filenames specified in the "FileNameMap" format to rename the files.


CF_HDROP Format

The global memory object contains a DROPFILES structure. If the object was copied to the clipboard as part of a drag and drop operation, the pt member of DROPFILES includes the coordinates of the point where the drop occurred. The pFiles member is the offset to a double − null-terminated list of filenames. An application can retrieve information from the data object by passing the object's handle to the DragQueryFile and DragQueryPoint functions.


"PrinterFriendlyName" Format

This format is similar to the CF_HDROP format, except that the pFiles member of the DROPFILES structure is the address of a double − null-terminated list of printer "friendly" names.


"FileContents" Format

The data object contains the contents of one or more files in a format that can be written to a file. When a group of files is being transferred, the target of the drag and drop operation can use the lindex member of the FORMATETC structure to indicate which file to retrieve. The names and attributes of each file are contained in the "FileGroupDescriptor" data.


"FileGroupDescriptor" Format

The data object contains the filenames and attributes of a group of files being transferred during an OLE style drag and drop operation. The data object consists of a FILEGROUPDESCRIPTOR structure and any number of FILEDESCRIPTOR structures (one for each file in the group).


"Shell Object Offsets" Format

The global memory object contains an array of POINT structures. The first structure specifies the screen coordinates of a group of shell objects, and the remaining structures specify the relative offsets of each item in the group. All coordinates are in pixels.


"Net Resource" Format

The global memory object contains a list of network resources. The memory object consists of a NRESARRAY structure and any number of NETRESOURCE structures (one for each network resource in the list). Note that the string parameters (LPSTR types) in the NETRESOURCE structure contain offsets instead of addresses.


"Shell IDList Array" Format

The global memory object contains an array of item identifier lists. The memory object consists of a CIDA structure that contains offsets to any number of item identifier lists (ITEMIDLIST structures). The first structure in the array corresponds to a folder, and subsequent structures correspond to file objects within the folder.


Additional Information

For more information about how to support drag and drop in your applications, you can read the following documentation:

•	OLE documentation included in the Microsoft® Win32® Software Development Kit (SDK).

Information covered includes drag and drop operations as well as the IDataObject function and the FORMATETC and STGMEDIUM structures. The SimpDnD and Outline samples demonstrate drag and drop implementation.

•	Inside OLE 2 by Craig Brockschmidt, published by Microsoft® Press.

This book provides a thorough description of data transfer and drag and drop operations.


Reference

The following structures define the clipboard formats used to transfer data between applications and the shell.


DROPFILES [New - Windows 95]
DROPFILES

[New - Windows 95]

typedef struct _DROPFILES {

    DWORD pFiles; // offset of file list

    POINT pt;     // drop point (coordinates depend on fNC)

    BOOL fNC;     // see below

    BOOL fWide;   // TRUE if file contains wide characters,

                  // FALSE otherwise

} DROPFILES, FAR * LPDROPFILES;

Defines the CF_HDROP and CF_PRINTERS clipboard formats. In the CF_HDROP case, the data that follows is a double − null-terminated list of file names. For CF_PRINTERS, the data that follows are the printer friendly names.

fNC

Nonclient area flag. If this member is TRUE, pt specifies the screen coordinates of a point in a window's nonclient area. If it is FALSE, pt specifies the client coordinates of a point in the client area.


FD_FLAGS [New - Windows 95]
FD_FLAGS

[New - Windows 95]

typedef enum {

    FD_CLSID = 0x0001,

    FD_SIZEPOINT = 0x0002,

    FD_ATTRIBUTES = 0x0004,

    FD_CREATETIME = 0x0008,

    FD_ACCESSTIME = 0x0010,

    FD_WRITESTIME = 0x0020,

    FD_FILESIZE = 0x0040,

    FD_LINKUI = 0x8000,

} FD_FLAGS;

Specifies an enumerate type that defines the flags used with the dwFlags member of the FILEDESCRIPTOR structure.


FILEDESCRIPTOR [New - Windows 95]
FILEDESCRIPTOR

[New - Windows 95]

typedef struct _FILEDESCRIPTOR { // fod

    DWORD    dwFlags;          // see below

    CLSID    clsid;            // file class identifier

    SIZEL    sizel;            // width and height of file icon

    POINTL   pointl;           // screen coordinates of file object

    DWORD    dwFileAttributes; // file attribute flags (FILE_ATTRIBUTE_)

    FILETIME ftCreationTime;   // time of file creation

    FILETIME ftLastAccessTime; // time of last access to file

    FILETIME ftLastWriteTime;  // time of last write operation

    DWORD    nFileSizeHigh;    // high-order word of file size, in bytes

    DWORD    nFileSizeLow;     // low-order word of file size, in bytes

    CHAR     cFileName[ MAX_PATH ]; // name of file (null-terminated)

} FILEDESCRIPTOR, *LPFILEDESCRIPTOR;

Describes the properties of a file that is being copied by means of the clipboard during an OLE drag and drop operation.

dwFlags

Array of flags that indicate which of the other structure members contain valid data. This member can be a combination of these values:

FD_ACCESSTIME	The ftLastAccessTime member is valid.
FD_ATTRIBUTES	The dwFileAttributes member is valid.
FD_CLSID	The clsid member is valid.
FD_CREATETIME	The ftCreationTime member is valid.
FD_FILESIZE	The nFileSizeHigh and nFileSizeLow members are valid.
FD_LINKUI	Treat the operation as "Link."
FD_SIZEPOINT	The sizel and pointl members are valid.
FD_WRITESTIME	The ftLastWriteTime member is valid.


FILEGROUPDESCRIPTOR [New - Windows 95]
FILEGROUPDESCRIPTOR

[New - Windows 95]

typedef struct _FILEGROUPDESCRIPTOR { // fgd

     UINT cItems;           // number of elements in fgd

     FILEDESCRIPTOR fgd[1]; // array of file descriptor structures

} FILEGROUPDESCRIPTOR, * LPFILEGROUPDESCRIPTOR;

Defines the CF_FILEGROUPDESCRIPTOR clipboard format.


NRESARRAY [New - Windows 95]
NRESARRAY

[New - Windows 95]

typedef struct _NRESARRAY { // anr

    UINT        cItems; // number of elements in nr

    NETRESOURCE nr[1];  // see below

} NRESARRAY, * LPNRESARRAY;

Defines the CF_NETRESOURCE clipboard format.

nr

Array of NETRESOURCE structures that contain information about network resources. The string members (LPSTR types) in the structure contain offsets instead of addresses.


Creating Multimedia Applications

Multimedia is experiencing a technological explosion. Advances in video and audio compression algorithms provide new uses for PC multimedia. Traditional publishing and entertainment industries are converging with multimedia as well. To participate fully in this evolution, companies need to identify the significant trends, new products, and business opportunities likely to influence the future of multimedia.


About Multimedia Applications

Microsoft® Windows® version 3.0 provided the first Windows-based system support for multimedia. This system shipped in the summer of 1991. The multimedia support enabled the Windows operating system to speak, play music, synthesize sounds, show high-quality color images, and access time-dependent data using compact disc read-only memory (CD-ROM). Until that time, Windows had been silent except for system beeps. Later in 1991, the introduction of the Media Control Interface (MCI) allowed Windows to control video and audio recorders, laser disk players, and virtually any other audio or video device.

To enable multimedia, personal computers (PCs) running Windows needed to be equipped with high-performance hardware as well as new drivers for audio, video, and storage. In response to that need, computer manufacturers began introducing PCs specifically designed for Windows multimedia in consultation with Microsoft and with guidance from the Multimedia PC Marketing Council, which was formed to set performance specifications for video, audio, and CD-ROM subsystems. Companies also introduced multimedia upgrade kits for the large, installed base of silent PCs.

As a result of these improvements, Windows has become the leading multimedia PC platform, and hardware and developer support has skyrocketed. Every major PC manufacturer makes multimedia-ready models, and there are more than a dozen multimedia upgrade kits available for Windows.


Future Directions in Multimedia

Multimedia is experiencing a technological explosion. Advances in video and audio compression algorithms provide new uses for PC multimedia. Traditional publishing and entertainment industries are converging with multimedia as well. To participate fully in this evolution, companies need to identify the significant trends, new products, and business opportunities likely to influence the future of multimedia.

Perhaps the most important trend is the rapid adoption of Microsoft Windows on multimedia-ready computers for the home. Both market share and sales rates of home computers are growing, driven largely by falling hardware prices. Continued growth of Windows-based multimedia in the home depends on three factors: ease of use, high-quality video performance, and the availability of great titles.

Microsoft's Plug and Play specification for multimedia components, from audio to video capture adapters, provides the ease of use essential to the continued acceptance of multimedia hardware in the home. For the user, this means hardware that automatically configures itself upon installation, eliminating the need to adjust dip switches or configure drivers.

Video playback has increased in Windows by up to 50 percent, and improved standards for high-performance video rendering are being developed.

In addition to displaying enhanced video, Windows-based computers will be used more frequently for high-quality video capture and editing. Several manufacturers are already demonstrating MPEG-quality video running with Windows, and Microsoft is working with hardware and software developers to specify a true MPEG implementation for Windows. As a result of this work, inexpensive MPEG decoding hardware is becoming available for Windows.

Future work will center on specifying requirements for video and bus performance; implementing MPEG, MPEG 2, and motion JPEG hardware-assisted compression; and using the capabilities of Windows 95 and Windows NT.


Introduction to Writing Multimedia Applications

The remainder of this article covers three main issues related to creating Windows multimedia applications:

•	Working with or without multimedia hardware.

•	Coping with unavailable resources.

•	Yielding resources to other applications.

This article is only an overview of some of the global issues. For discussions of specific categories of multimedia applications and the Windows API that supports each class, see the multimedia documentation included in the Microsoft® Win32® Software Development Kit (SDK).


Classes of Applications

Multimedia applications fall into two general classes: applications that are completely dependent on multimedia support in Windows and applications that take advantage of the support if multimedia hardware is available. Applications in the latter class are called "multimedia aware," because they recognize the multimedia hardware but are not fully dependent on it.


Multimedia-Dependent Applications

Some applications make sense only in a multimedia environment. For example, a speak and spell tutor requires support for playing sounds. The application will not run on a computer that has no multimedia support. Developers should strive to create applications that either fail gracefully or have reduced functionality if a feature they require is unavailable.


Multimedia-Aware Applications

An application that is multimedia aware uses multimedia hardware if it is available. If a user, for example, starts a multimedia-aware application on a computer that does not have a sound card, the application simply disables the audio portion of its interface and continues to run.


Selected Multimedia Components

Applications can be sensitive to the presence of multimedia support or to individual components. For example, an application that displays text and uses animations, waveform, the Musical Instrument Digital Interface (MIDI), and compact disc (CD) audio sounds in various places might at first seem impossible without multimedia support. However, if the application were an encyclopedia that displayed mostly text, occasionally augmented by multimedia inserts, it could provide most of its functionality on a computer with no special multimedia hardware. It would only need the standard Windows window management and graphics device interface (GDI) libraries to display its text.


Video Performance Guidelines

This section discusses issues related to maximizing video performance in multimedia applications.


Window Size and Position

To achieve the best video playback rate (that is, the most frames per second), the playback window must be horizontally aligned on a four-pixel boundary. Without this alignment, playback may be slower by up to 50 percent.

The system typically aligns the playback window automatically. However, if an application plays an audio-video interleaved (AVI) file into a window that is not near the upper left corner of a pop-up window, the automatic alignment does not occur. (In this case, the playback window could move off the screen or could move back and forth repeatedly.) Because automatic alignment is not guaranteed, every programmer must ensure that the upper left corner of a playing AVI file is either on a pixel whose number is evenly divisible by four in the horizontal direction or in the upper left corner of a pop-up window that the system can safely align for the application.

Stretching video playback can slow performance significantly. Performance suffers whenever an AVI file is played back at any size other than its actual dimensions. It is impaired even if the playback size is smaller than the AVI frame size.


Video Compression

To improve image and audio quality, you should avoid compressing an AVI file more than once. You should combine uncompressed pieces of video in your editing system before compressing the final product. Using this method not only promotes image and audio quality, it is faster as well, because editing is always faster with uncompressed video.

To achieve better video compression, you should follow these guidelines:

•	Capture the video on high-end equipment.

•	Keep noise out of the signal to prevent even worse noise in the compressed video.

•	Use a low-pass filter to decrease noise.

You can use the AVISaveOptions or ICCompressorChoose function to display a dialog box that lists compression options. One of these options is "quality." A higher quality setting equates to a larger frame. If you set a target data rate, the highest quality setting uses the entire data rate. However, a lower quality setting results in an even smaller data rate than you requested. Typically, you should set the target data rate in the dialog box and set the quality to maximum.


Interleave Options

Although interleave options are unimportant for editing, they are important for video at run time. At run time, the interleave should be 1:1.


Data and Frame Rates

The data rate your application uses depends on the speed of the CD-ROM player on your target platforms. For single-speed players, 150 kilobytes (K) per second is a reasonable rate.

Most video cards will support 15 fps at sizes up to 320 by 240 pixels. In fact, most video cards will support good full-screen playback at 15 fps if the AVI file is that size or less. If the video is larger than 320 by 240 pixels, however, the performance of full-screen playback is very poor.

Most developers test their applications on a variety of hardware platforms to gauge the data and frame rates.


Key Frames

Most applications use the default setting for key frames. Using fewer key frames can produce a slightly better image quality. However, if the target system cannot keep up with the data rate during playback, an application will stall for a longer time than it would otherwise and performance will suffer. A higher setting for key frames will cause fewer frames to be skipped when playback cannot keep up with the data rate.


Palette Flashing

It is important to avoid palette flashing when an application plays different AVI files and shows different bitmaps. The PALMAP sample application found in the Samples subdirectory of the Win32 SDK shows how to generate an optimal palette from a variety of pictures. Applications should create such a palette using all the AVI files and images to be displayed and should realize this palette when processing the WM_QUERYNEWPALETTE and WM_PALETTECHANGED messages. To cause a video to play mapped to the chosen palette and to avoid palette flashing, MCI applications can send the MCI_REALIZE command with the MCI_DGV_REALIZE_BKGD value (or the realize command with the "background" flag). Similarly, applications can use the DrawDibDraw function with the DDF_BACKGROUNDPAL value when drawing bitmaps.


General Programming Guidelines

This section discusses issues related to developing multimedia applications.


Calling Functions From Within Callback Functions

Win32 applications can call virtually any API element from within a callback function. For Windows 16-bit applications, however, the list of functions that you can safely call is still very small. The list includes the following functions:

•	midiOutLongMsg

•	midiOutShortMsg

•	OutputDebugStr

•	PostMessage

•	timeGetSystemTime

•	timeGetTime

•	timeKillEvent

•	timeSetEvent

Applications that require cross-platform portability must take this restriction into account.


Multiple-Thread Limitations

The Windows 95 multimedia functions are not designed to be used by two or more threads in the same process. Although most multimedia functions will work if they are called by multiple threads, some are likely to fail. Functions that are particularly likely to fail include PlaySound, any of the functions that prepare or unprepare headers, and any of the open and close functions.  The PlaySound function can never be used simultaneously by multiple threads in the same process. The functions that prepare or unprepare headers and the open and close functions can be used simultaneously by multiple threads in the same process, but only if they do not pass the same structure.


Resource Availability

Ideally, an application uses a device or feature only when it is needed and closes it when it is no longer required. If a resource is not available, the application should either continue without it (for example, disable the button that plays sound) or ask the user to release the device or feature from another application.

Unfortunately, loading on demand can result in significant timing delays, especially if a dynamic-link library (DLL) has to be loaded and initialized. A good compromise is to open the device before it is required and release it when another application requires it or when the application terminates. An application will know whether the device is available well before it needs to use it, so it can avoid the delays associated with loading code. To load on demand well, an application must process any WM_ACTIVATEAPP messages it receives. If an application receives WM_ACTIVATEAPP with a wParam value of zero, it should close any devices that it has open when it is no longer active. A subsequent WM_ACTIVATEAPP message with a nonzero wParam value indicates that the application should attempt to reopen any devices it needs because it is active once again.

An application can determine the availability of the multimedia features it uses and selectively disable the parts that are not going to work. The application has the option of notifying the user of the reduced functionality.

An application that tolerates limited functionality must check the error return code after each attempt to open a device so that it can avoid failing when the system configuration changes. You can inform the user either directly (through a dialog box) or indirectly (by disabling a button) that a feature has been lost.


Yielding Resources to Other Applications

Applications that hold devices open for long periods should process the WM_ACTIVATEAPP messages sent to them so that other applications can also use multimedia capabilities. For example, during a game that allows the user to speak a part by recording his or her own voice, the user might decide to bring up Sound Recorder to alter a sound file recorded previously. If the game does not yield control of the waveform-audio output device, Sound Recorder will not work as expected.

As a rule, applications should not play animations or sounds while they are inactive. An exception to this general rule is an application that plays audio CDs, because the user may want to continue playing a CD while running another application. If an application needs to use a CD drive that is unavailable because another application has it open, the application must tell the user about the conflict.

An application should also give the user the option of turning off certain multimedia features, particularly sounds. (This is often done using a menu.) The user may want a background application to play MIDI files or may want to hear an audio CD while using an application. Also, the user may get tired of hearing the same sounds from an application repeatedly.


Hardware Compatibility

The existence of multimedia DLLs on a system does not guarantee that appropriate device drivers are available. For example, the system may be installed on a computer with no sound card, or it may have no multimedia features at all. The existence of multimedia API elements does not mean that all of the multimedia personal computer (MPC) standard features are available either.

In addition, the presence of a CD-ROM device does not mean that it meets MPC specifications. Documentation for an application should inform the user that application performance may suffer if the user does not have MPC- or MPC2-compatible hardware. An application should either fail gracefully (with a message at startup) or tolerate the unavailability of multimedia support at run time.

You should also consider the role of your installation program in this process. If your installation program cannot find multimedia support and consequently disables your application's features, you should provide some way to enable these features if the user later adds multimedia support (for example, a sound card). You could require the user to rerun the installation program, or, preferably, you could put a detection mechanism into the startup code for the application (checking, for example, the registry for the existence of the device). The application does not need to know which sound driver to add; it must simply recognize that the multimedia API elements are now supported. This is easy to detect at run time.

The ability to load and unload drivers on demand adds another layer of complication to an application's use of multimedia. Because the number of available device drivers during the run time of an application may vary, it is not sufficient to simply enumerate them at application startup. To use every available driver while running, an application should check for the WM_DEVICECHANGE message to discover whether a device is changing.


Displaying and Using Pen Data

A subset of the pen services for Microsoft® Windows® 95 is available on every Windows 95 system through the pen display dynamic-link library (DLL) called PKPD.DLL or PKPD32.DLL. Functions in this library allow any Windows 95 − based application to display and manipulate pen data (also called "ink") that was originally collected on a pen-enabled system.


About Displaying and Using Pen

A few practical applications for pen services might include:

•	Using Windows-based applications to display a signature for letters or faxes.

•	Verifying signatures collected on a pen-based mobile computer.

•	Animating the display of ink for presentations or games.

•	Merging, compressing, and storing ink collected on pen-based systems, which might later be recognized as text on a pen-based system.

•	Displaying graphics, maps, or handwritten notes that have been drawn on a pen-based system.

The Programmer's Guide to Pen Services for Microsoft Windows 95, which is included in the Microsoft® Win32® Software Development Kit (SDK), provides information about using the entire set of pen functions to collect, recognize, manipulate, and display ink. The set of functions supported in the Windows 95 pen display library is limited to manipulating and displaying ink. Chapter 4, "The Inking Process," in that guide describes the functions available for displaying pen data, most of which are also available in the pen display library.

This article concentrates on the functions most likely to be used in the pen data display library on a standard Windows 95 system. It also presents a sample application that allows you to display pen data using various methods. The following topics are presented in both overview and sample code descriptions:

•	Retrieving pen data from a file and saving pen data to a file.

•	Scaling pen data.

•	Compressing, decompressing, and trimming pen data.

•	Animating the display of pen data.

•	Retrieving information about pen data.

The final sectionof this article provides guidelines for writing Windows 95 − based applications so that they will run successfully on pen-enabled systems. Although the pen services automatically supply user interface tools to the user so that your application can be used without a keyboard, you should be aware of the issues described in this article  to ensure that your application works well in a pen-enabled environment.


Overview of Pen Services

Pen services for Microsoft Windows 95 provide all of the software requirements for operating a pen-based system. This includes data collection from a tablet- or screen-based pen device, display of ink, routing of data to one or more DLLs for character recognition, and the ability to persist data. It also includes Windows controls for pen input, which are used to recognize ink as text or create ink drawings, and tools, such as the on-screen keyboard. The first five chapters in the Programmer's Guide to Pen Services for Microsoft Windows 95 provide a comprehensive overview of these topics. You should read these chapters in addition to this article  if you need more information about pen services.

This section compares the pen display library functions in Windows 95 to the total set of pen services.


Data Collection and Recognition

Pen data can be collected on a pen-enabled system by using either high-level or low-level calls to pen functions. High-level programming provides defaults for most steps and makes pen data collection and recognition straightforward. Lower-level programming adds a few more function calls to the process; however, data collection and recognition are essentially the same using both programming methods. The high-level method is described here because of its simplicity. For more information about this method, see Chapter 2, "Starting Out with System Defaults," in Programmer's Guide to Pen Services for Microsoft Windows 95.

At the highest level, a pen-aware application makes a call to the pen DoDefaultInput function, passing it a window handle. After this, the window and its child windows start receiving messages generated by the pen services. The first message allows the application to enable or disable itself or its child windows as pen targets. By default, all child windows are set as targets, capable of accepting pen input. Another set of messages sets up each target window's inking information, such as pen color, width, clipping range, and so on. After more "overhead" messages of this sort, the application is required to create an object in memory to collect the data. This object can be a recognition context object (HRC) or a pen data object (HPENDATA). The latter is relevant to this article , because it is the type of data that can be read and displayed using the pen display library functions.

As pen data arrives to each target window, the window is notified by a message, and the collected pen data is placed into the created object (HRC or HPENDATA) by default. Finally, when ink input ends, each target window receives a data-ending message. If an HPENDATA object was created, the application has the opportunity to duplicate or save the data. If an HRC object was created, the default behavior is to send the data to a recognizer. A recognizer is a DLL that is loaded to translate pen strokes into characters. When the recognizer has finished, the window receives a results message, and the default behavior of the pen services is to send the recognizer's "best guess" to the target window as a string of WM_CHAR messages.


Display of Data

Pen services for Microsoft Windows 95 require the PENWIN.DLL or PENWIN32.DLL library for all of the functionality of pen data collection. The library is supplied by the pen tablet or computer manufacturer that bundles the services with their product.

Pen-enabled systems, however, use the same pen display library that is available on every Windows 95 system for pen data manipulation and display: PKPD.DLL or PKPD32.DLL. The remainder of this article  provides information about these services. Because of the overlap of use by both pen-enabled and penless systems, you will find a few functions in the pen display library that are included primarily for pen-enabled systems. These are noted and usually discussed after the functions that are more relevant to displaying ink on standard Windows 95 systems.


Functions in the Pen Display Library

Before turning to the sample application, it might be helpful to provide some information about the pen display library functions used by the application and to describe the categories of functions in the pen display library. It is also highly recommended that you read Chapter 4, "The Inking Process," of the Programmer's Guide to Pen Services for Microsoft Windows 95 for a more information about these functions and consult the reference documentation in that guide for any individual function descriptions.

The functions in the pen display library can be organized into groups according to the following activities:

•	Creating pen data objects.

•	Scaling pen data.

•	Displaying pen data.

•	Examining pen data.

•	Editing or copying pen data.

•	Compressing pen data.

•	Using inkset objects.

Each of these groups and the functions that comprise them are discussed in this section. Functions in Pen Windows version 1.0 that have been superseded by the Pen Windows version 2.0 are not generally discussed in this section.

Before the pen display library functions are presented, it is important to describe exactly what constitutes pen data. Pen data is a collection of strokes composed of coordinate points. When ink is drawn, all of the points collected while the pen is down on the tablet comprise a "pen down stroke." (The time durations collected while the pen is not on the tablet are called a "pen up stroke.") After pen data is collected, it is stored in a pen data (or HPENDATA) object. This pen data object is accessed through a window handle, similar to the way that handles are used to access other Windows objects, such as device contexts.

Internally, a pen data object is composed of a main header followed by a sequence of strokes. The main header provides information, such as the number of strokes and points, the bounding rectangle, the ink color and width, and so on.

Each stroke contains a set of data points, which indicate the positions of the pen during the stroke, and a stroke header, which indicates the number of points in the stroke and when the stroke occurred.

Each point is initially stored in pen tablet coordinates with a resolution of 0.001 inch and an origin in the upper left corner of the tablet. The resolution can be scaled later to a different display resolution if needed.

Additional information provided by the original equipment manufacturer (OEM) for the pen tablet may also be contained in the stroke. If OEM data exists, it follows the point data in the stroke.

The following illustration shows the format of a pen data (HPENDATA) object.


Creating Pen Data Objects

Three functions are associated with the creation of pen data objects:

•	CreatePenDataEx

•	DuplicatePenData

•	DestroyPenData

Although CreatePenDataEx has many parameters, most are only useful when creating a pen data object used to accept pen input. Applications using the Windows 95 display libraries on systems without a pen should normally set the uScale parameter to the PDTS_STANDARDSCALE value and pass zero or NULL to the other parameters.

DuplicatePenData makes a copy in memory of the pen data object and returns a handle to it.

Any memory allocated for pen data objects created by using CreatePenDataEx or DuplicatePenData can and must eventually be freed by using DestroyPenData.


Scaling Pen Data

Three functions are associated with the scaling of pen data points:

•	MetricScalePenData

•	OffsetPenData

•	ResizePenData

MetricScalePenData scales the pen data to display resolutions corresponding to the Windows mapping modes. For example, passing the PDTS_HIENGLISH value to MetricScalePenData is equivalent to MM_HIENGLISH resolution, passing the PDTS_HIMETRIC value is equivalent to MM_HIMETRIC resolution, passing the PDTS_LOMETRIC value is equivalent to MM_LOMETRIC resolution, and so on. The original tablet coordinates are the same as the Windows mapping mode called MM_HIENGLISH (0.001 inch).

OffsetPenData can be used to offset the bounding rectangle within the pen data coordinates. For example, you can pass negative values to this function to move the rectangle containing the points to the left or top edge.

ResizePenData is useful for arbitrarily scaling points to fall within a given rectangle. You might want to use this function on pen data to scale it to a predetermined window size.

Note that rescaling pen data to a lower resolution causes information to be lost. If you need to maintain the highest resolution possible for your pen data, you may want to use the DrawPenDataEx function to scale your data to a window because that method leaves the original data alone and only scales the points as they are displayed.


Displaying Pen Data

Four functions are associated with displaying pen data:

•	DrawPenDataEx

•	DrawPenData (not available in PKPD32.DLL)

•	RedisplayPenData

•	CreatePenDataRegion

Of these functions, DrawPenDataEx is the most useful for systems that are not pen-enabled. DrawPenDataEx is very versatile and handles all of the details of drawing pen data to the device context that it is passed. It has the ability to draw all strokes, a selected range of strokes, or a selected range of points. It also has the ability to animate the drawing of ink, playing back the strokes in their original succession and duration, by reading the timing information stored with each stroke. Part of the animation process involves automatic calls made by DrawPenDataEx to a callback function that you specify. Along with the address of a callback function, an ANIMATEINFO structure is also passed to this function to provide more information about the animation. The sample application and accompanying text describes this process in greater detail.

The other functions listed here are used less often on standard Windows 95 systems. DrawPenData is a 16-bit display function that has been superseded by DrawPenDataEx. RedisplayPenData is primarily designed for displaying ink immediately after a user has drawn it (such as in an ink control) so that pen data objects can be merged.

 CreatePenDataRegion is also primarily used on pen-enabled systems that use "gestures" to communicate system-level commands to the operating system, such as cutting or pasting operations. Gestures are pen movements (such as "circle-P") that require immediate ink display anywhere on the screen.


Examining Pen Data

Nine functions are used to examine the contents of a pen data object:

•	GetPenDataAttributes

•	GetStrokeAttributes and SetStrokeAttributes

•	GetStrokeTableAttributes and SetStrokeTableAttributes

•	BeginEnumStrokes, GetPenDataStroke, and EndEnumStrokes

•	HitTestPenData

GetPenDataAttributes is used to retrieve information from the pen data object's main header, such as the bounding rectangle, the total number of points and strokes, the time that the pen data was created, and the device sampling rate. This function is used in the sample application to retrieve the bounding rectangle of ink before it scaled. It is also used to determine the scaling and compression of the pen data object.

Most of the other functions in this group provide access to individual or group stroke attributes either indirectly through a function call or by providing direct access to the pen data object in memory.

GetStrokeAttributes and SetStrokeAttributes retrieve and modify, respectively, the attributes of individual strokes, including the pen state (up or down), the ink color and width, and the time that the stroke was recorded.

GetStrokeTableAttributes and SetStrokeTableAttributes retrieve and modify, respectively, attributes that are shared by a group of strokes. For example, if all strokes use a red pen color and a width of 1, that attribute can be modified for all strokes by using only one call to SetStrokeTableAttributes.

BeginEnumStrokes returns a far pointer to the HPENDATA object within the global heap, GetPenDataStroke retrieves pointers to point data within the HPENDATA object, and EndEnumStrokes unlocks the pen data memory block and invalidates any pointers retrieved.

HitTestPenData determines if a given point lies on or near a point in the pen data object.


Editing or Copying Pen Data

Functions in this group can be organized into three subgroups. The first subgroup of functions adds strokes to or extracts strokes from a pen data object.

ExtractPenDataStrokes	Copies and, optionally, deletes strokes from a pen data object.
InsertPenDataStroke	Inserts a stroke into an existing pen data object.
RemovePenDataStrokes	Deletes a contiguous set of strokes from a pen data object in memory.
The second subgroup of functions adds points to or extracts points from an existing stroke.

ExtractPenDataPoints	Copies points from a specified stroke in a pen data object to a buffer, optionally removing the points.
GetPointsFromPenData	Copies points from a stroke in a pen data object to a buffer (superseded by ExtractPenDataPoints).
InsertPenDataPoints	Inserts points into an existing stroke in a pen data object.
AddPointsPenData	Appends a set of points to a stroke in a pen data object (used mainly by pen-enabled systems).
The third subgroup performs operations on the entire pen data object.

InsertPenData	Merges two separate pen data objects into a single object.
PenDataToBuffer	Writes the data in an existing HPENDATA object to a serial buffer. The function is used to transfer pen data to a file or the clipboard.
PenDataFromBuffer	Creates and loads an HPENDATA object with the data from the serial buffer created by PenDataToBuffer. The function is used to transfer pen data from a file or the clipboard.


Compressing Pen Data

Data compression plays an important role in pen-based computing. The high sampling rates of a pen device, combined with large amounts of input, result in large blocks of pen data. The pen display library offers two methods of compression, each with advantages and disadvantages depending on the intended use of the pen data. These two functions are associated with data compression:

•	CompressPenData

•	TrimPenData

CompressPenData is generally used to compress pen data before saving it to disk or passing it to the clipboard. It is also used to decompress the data before it is used again. Compressed data must be decompressed to be used by most functions in the pen display library. Compression provides from 60 to 70 percent reduction in pen data size with no loss of data when the data is decompressed (this is called lossless compression).

TrimPenData, in contrast, irreversibly removes data from the pen data object. Much of the information stored in a pen data object can be removed if the data is only to be used for display purposes. Some of the data that you might want to trim from a pen data object includes colinear and duplicate points, empty strokes, timing and "up stroke" information, OEM hardware information, and so on.


Using Inkset Objects

An inkset object consists of time intervals for either individual strokes or a collection of strokes. In turn, the interval of each stroke consists of the times at which the stroke begins and ends. In this way, a pen-based application can refer to a stroke not only by the points it contains but also by the time interval in which the stroke occurs.

Timing information principally serves recognizers. It provides them with an additional characteristic of the raw data that may offer clues for interpretation.

Timing information, though, has other uses as well. For example, it enables an application to accurately verify a signature by comparing not only the coordinates but also the duration of each stroke against a copy of the original signature. This type of verification is an effective safeguard against forgery because of the difficulty of simultaneously duplicating both the pattern and duration of the original signature.

Because inkset objects are more complicated than can be easily described in this article  and because they are not used in the sample application, see the Programmer's Guide to Pen Services for Microsoft Windows 95, which is included in the Win32 SDK, for more information about their use.


AN_PKPD Sample Application

The sample application discussed in this article  is called AN_PKPD. It is based on another animation sample called ANIMATE (provided for pen application developers in the SAMPLES\WIN16\PEN directory of the Win32 SDK), which collects, displays, saves, and loads pen data. The ANIMATE sample requires a pen tablet and the installation of the pen services for Microsoft Windows 95. The AN_PKPD sample, on the other hand, requires only Windows 95, the pen data, and either PKPD.DLL or PKPD32.DLL, both of which are supplied with Windows 95.

Sample pen data files, generated from the ANIMATE sample, are provided with the source code for AN_PKPD so that the sample application has some data to work with. These pen data files contain nothing more than pen data objects that are saved directly to disk without compression or any other alteration. You can, however, save these files in compressed format after displaying them. It is suggested that you do not overwrite the original files if you decide to save them as compressed files.


Reading, Writing, and Compressing Pen Data

The application-defined LoadSave function loads and saves pen data information. The original pen data supplied with the sample files was generated using the ANIMATE sample and is not compressed or trimmed. In the AN_PKPD sample, you have the option of saving any of the files that you load and display. If you do save a file, it is saved in a compressed state. If it has been displayed as "clipped" data (drawn to the original scale, not scaled to a window), it is also in reduced resolution rather than tablet resolution and is trimmed of excess pen data. It is suggested that you do not overwrite the original files if you save them as compressed files.

This section describes the LoadSave function, which calls two internal functions, ReadPenData and WritePenData. The full source for all three functions is at the end of this section.

After retrieving a file name using the FGetFileName local function, CreatePenDataEx is called to create an HPENDATA object that is accessed by the vhpndt variable.

vhpndt = CreatePenDataEx((LPPENINFO)NULL, PDTS_STANDARDSCALE, 0, 0);

Note that CreatePenDataEx specifies the data scaling as the PDTS_STANDARDSCALE value, which is equivalent to PDTS_HIENGLISH (.001 inch per logical unit). This keeps the scaling of the pen data at the highest possible resolution initially — that is, at the same resolution as the pen tablet. All pen tablets are scaled at .001 inches per logical unit.

After opening the file and getting a file handle (hfile), the fOpen variable is checked to determine whether the function was called for reading or writing pen data. If it was called for reading a file, the DestroyPenData function is called on the pen data object to remove any existing ink from a previously displayed file. Then the pen data is read into the pen data object by calling the ReadPenData local function. ReadPenData uses the Windows lread function internally to read the data into the buffer and the pen display library's PenDataFromBuffer function to place that data in the pen data object created by CreatePenDataEx.

Next, the GetPenDataAttributes function is called to determine whether or not the pen data was compressed when it was saved. If it was compressed, the CompressPenData function is called to decompress it. Pen display library functions do not work on compressed data.

The following example shows this process in the LoadSave function.

if (fOpen)

{

   if (vhpndt)  DestroyPenData(vhpndt);

   vhpndt = ReadPenData(hfile);

   // Determine whether the pen data is compressed.

   vnPDTS = GetPenDataAttributes(vhpndt, NULL, GPA_PDTS);

   // If it is compressed, decompress it.

   if ((vnPDTS & PDTS_COMPRESSED) == PDTS_COMPRESSED)

      CompressPenData(vhpndt, CMPD_DECOMPRESS, 0);

Redraw();

}

The final step of loading a file is to call the Redraw local macro, which basically invalidates the window. Redraw can be expanded in the following manner.

PostMessage(vhwndOut, WM_USER, 0, 0);

In the window procedure for vhwndOut, the WM_USER message is handled as follows.

...

   case WM_USER:  // for Redraw macro

      InvalidateRect(hwnd, NULL, TRUE);

      if (IsWindow(vhdlg))

         EnableWindow(GetDlgItem(vhdlg, IDD_PBCLEAR), vhpndt != NULL);

      SetFocus(vhwndOut);     // catch Esc

      break;

...

When data is saved by using the LoadSave function, it is automatically compressed by using the CompressPenData function. Then the internal WritePenData function is called; it uses the pen display library PenDataToBuffer function and the Windows _lwrite function to write the data to a buffer and then to the file. Finally, the pen data in memory is decompressed to its original state so that it can be displayed again.

Compression of pen data is not mandatory, but it is often very useful because it can achieve as much as 70% reduction in size on the disk. To compare compressed and noncompressed pen file sizes, try loading one of the sample pen data files and then save it with a different name. The difference is quite apparent. Here is an example showing WritePenData that compresses, saves, and decompresses the data.

if (fOpen)

{

.

.

.

// Load the pen data here.

.

.

.

}

else{

    // Compress the pen data before saving it.

    CompressPenData(vhpndt, CMPD_COMPRESS, 0);

    WritePenData(hfile, vhpndt);

    // Decompress the pen data for further displaying.

    CompressPenData(vhpndt, CMPD_DECOMPRESS, 0);

 }

Following are the complete listings for the application-defined LoadSave, ReadPenData, and WritePenData functions.

VOID NEAR PASCAL

LoadSave(

   BOOL fOpen)

   {

   HCURSOR hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));

   HFILE hfile;

   static char const szOpenTitle[] = "Open File";

   static char const szSaveTitle[] = "Save File";

   if (!*vszFile)

      lstrcpy((LPSTR)vszFile, vszSaveFileDef);

   if (FGetFileName(vhwndAN, fOpen, vszFile))

      {

      OFSTRUCT of;

      if (!vhpndt)

        // Create a pen data object to read pen data into.

        vhpndt = CreatePenDataEx((LPPENINFO)NULL, PDTS_STANDARDSCALE, 0, 0);

      if ((hfile = OpenFile((LPSTR)vszFile, &of,

         fOpen? OF_READ: OF_CREATE)) != HFILE_ERROR)

        {

        if (fOpen)

         {

            if (vhpndt)  DestroyPenData(vhpndt);

            vhpndt = ReadPenData(hfile);

            // Determine whether the pen data is compressed.

            vnPDTS = GetPenDataAttributes(vhpndt, NULL, GPA_PDTS);

            // If it is compressed, decompress it.

            if ((vnPDTS & PDTS_COMPRESSED) == PDTS_COMPRESSED)

               CompressPenData(vhpndt, CMPD_DECOMPRESS, 0);

            Redraw();

         }

         else{

            // Compress the pen data before saving it.

            CompressPenData(vhpndt, CMPD_COMPRESS, 0);

            WritePenData(hfile, vhpndt);

            // Decompress the pen data for further displaying.

            CompressPenData(vhpndt, CMPD_DECOMPRESS, 0);

         }

         _lclose(hfile);

         }

      else ErrBox("error opening file", szOpenTitle);

      }

   else if (fOpen)

      InfoBox("did not get file", szOpenTitle);

   else

      InfoBox("did not save file", szOpenTitle);

   SetCursor(hCursor);

//-------------------------------------------------------------------------

//  ReadPenData - reads pen data from a file. The file format at this

//  point is a UINT value representing the size of the pen data,

//  followed by that many bytes of pen data.

//

//  Before calling this function, the caller should have already

//  opened the file specified by hfile and ensured that the

//  file pointer is offset to the beginning of the pen data.

//  When the function returns, the file pointer will be offset

//  to the end of the pen data in the file.

HPENDATA NEAR PASCAL ReadPenData(   // return handle to pen data

   HFILE hfile)   // handle of open file

   {

   HPENDATA hpndt = NULL;

   LONG     cb, cbRead, cbHpndt;

   BYTE     lpbBuf[cbBufMax];    // buffer

   DWORD    dwState = 0L;        // required init

   BOOL     fError = FALSE;

   if (!hfile

      || (cb = _lread(hfile, &cbHpndt, sizeof(LONG))) == HFILE_ERROR

      || cb != sizeof(LONG))

         return NULL;

   while (cbHpndt > 0)

      {

      if ((cbRead = _lread(hfile, lpbBuf, (UINT)min(cbHpndt, cbBufMax)))

         == HFILE_ERROR

         || PenDataFromBuffer(&hpndt, 0, lpbBuf, cbBufMax, &dwState) < 0)

         {

         if (hpndt)

            DestroyPenData(hpndt);

         return NULL;

         }

      cbHpndt -= cbRead;

      }

   return hpndt;

   }

//-------------------------------------------------------------------------

//  WritePenData - writes pen data into a file, preceded by a UINT

//  consisting of the size of the pen data, in bytes.

//

//  Before calling this function, the caller should have

//  already opened the file specified by hfile and ensured that

//  the file pointer is correctly placed.  When the function

//  returns, the file pointer will be offset to the end of the

//  pen data in the file. The function fails if the pen data is

//  larger than 64K.

BOOL NEAR PASCAL WritePenData(   // returns true if successful

   HFILE hfile,         // handle to open file

   HPENDATA hpndt)      // pen data to write

   {

   BYTE lpbBuf[cbBufMax];

   DWORD dwState = 0L;  // required initialization

   LONG cb;

   LONG cbSize;

   if (!hfile || !hpndt)

      return FALSE;

   if (GetPenDataAttributes(hpndt, (LPVOID)&cbSize, GPA_SIZE) < 0)

      return FALSE;

   if (_lwrite(hfile, (LPCSTR)&cbSize, sizeof(LONG)) == HFILE_ERROR)

      return FALSE;

   while ((cb = PenDataToBuffer(hpndt, lpbBuf, cbBufMax, &dwState)) > 0L)

      if (_lwrite(hfile, lpbBuf, (UINT)cb) == HFILE_ERROR)

         return FALSE;

   return cb >= 0;

   }


Scaling and Trimming Pen Data

It may or may not be necessary to scale pen data for your application. If your application only requires that the pen data be drawn to the scale of the client window, pen services take care of the scaling of the drawing (not the pen data) during the DrawPenDataEx function. All you need do is pass in the rectangle of the client window as a parameter along with a handle to a device context for the window.

If you want to keep the aspect ratios the same as when the ink was drawn on the tablet, you will need to scale the pen data to fit your display. You can do this on a point by point basis with each pen data point, or you can use the built-in scaling capabilities of the pen services.

The example in this section, taken from the ANOutWndProc window procedure's WM_PAINT case, demonstrates how you might go about setting the proper scale for the pen data and trimming unneeded data from the pen data object. In the AN_PKPD sample, the ANDLG dialog box structure contains an fRenderScale member that determines whether to scale the output to the client window or "clip" the drawing, based on the selection in the Drawing Options dialog box. Clipping means that the pen data is displayed in its original aspect ratios and is not confined to the client window area.

When the Scale option is chosen in the Rendering section of the Drawing Options dialog box, vandlg.fRenderScale is set true and the Windows GetClientRect function is called to retrieve the rectangle into which the drawing will be scaled.

if (vandlg.fRenderScale)            // scale to window

     GetClientRect(hwnd, &r);

When Clip is chosen in the Rendering section of the Drawing Options dialog box, vandlg.fRenderScale is set to FALSE and the pen data is to drawn to its original scale. In this case, you will probably want to fit the entire pen data on the display, although some of it may fall outside the client window, thereby being clipped.

In the sample application, this is done by calling the MetricScalePenData function and scaling the pen data to its lowest possible resolution. The lowest display resolution for pen data corresponds to the MM_TEXT mapping mode in Windows, which is set by using the Windows SetMapMode function. Following this, unneeded data is trimmed from the pen data by calling the TrimPenData function.

else

if (vfScaled == FALSE)

 {

    // Display in same aspect ratio as the original ink, and

    // clip the pen data if it is outside the window.

    // Scale the pen data to display the coordinates and trim the

    // excess data.

    if(MetricScalePenData(vhpndt, PDTS_DISPLAY))

       TrimPenData(vhpndt, TPD_COLLINEAR |    // duplicate strokes

                           TPD_EMPTYSTROKES | // strokes w/o points

                           TPD_USER |         // header info

                           TPD_PENINFO |      // OEM data

                           TPD_OEMDATA ,      // OEM data

                           0);

    // Use the following function if there is no animation or

    // up strokes.

    //TrimPenData(vhpndt, TPD_EVERYTHING, 0);

    // Set the mapping mode to the same as PDTS_DISPLAY.

    SetMapMode(hdc, MM_TEXT);

The TrimPenData function could also be called with just the TPD_EVERYTHING value. However, this removes timing data necessary for correct animation as well as up strokes, which you may find interesting to examine using this sample application.

The GetPenDataAttributes function is called next to retrieve the new bounding rectangle of the pen data. This rectangle is used to determine if the data fits on the screen and also used to calculate an aspect ratio if the data does not fit or needs to be further resized. The screen width and height are then retrieved to determine if the new scaling will fit on the screen.

// Get the bounding rectangle of the pen data in PDTS_DISPLAY

// mapping mode.

GetPenDataAttributes(vhpndt, &r, GPA_RECTBOUND);

nMapWidth = r.right - r.left;

nMapHeight = r.bottom - r.top;

// Get the screen resolution.

nDisplayWidth=GetDeviceCaps(hdc, HORZRES);

nDisplayHeight=GetDeviceCaps(hdc, VERTRES);

If the scaling mode is still too large, the data can be resized to fit the screen by using the ResizePenData function. Note that the use of ResizePenData is only recommended for one-time resizing. Resolution is lost when data is repeatedly resized.

In the example used to resize the data, an aspect ratio is determined from the bounding rectangle of the pen data and the rectangle is reduced for margins to 80% of the screen size. This new rectangle is then passed to ResizePenData, which does the work of modifying the coordinates of each of the points in the pen data object.

// If the pen data is still too big, resize it to fit on the screen.

if (r.right > nDisplayWidth || r.bottom > nDisplayHeight)

{

    // Resize the rectangle, maintaining the aspect ratio.

    if(nMapWidth > nMapHeight)

       AspectRatio = (float)nDisplayWidth/(float)nMapWidth;

    else

       AspectRatio = (float)nDisplayHeight/(float)nMapHeight;

    // Reduce slightly for margins on the screen.

    AspectRatio *= (float) 0.8;

    // Set the right and bottom of the rectangle to a new size.

    r.right = (int) (AspectRatio * (float)r.right);

    r.bottom = (int) (AspectRatio * (float)r.bottom);

    // Resize the pen data to a new rectangle.

    ResizePenData(vhpndt, &r);

}

Remember that when data is reduced in scale by using MetricScalePenData or ResizePenData, data is lost. Rescaling it to a higher resolution will not regain the lost data. If you save the data at this point, you should not overwrite the original file.

There are, of course, other methods than those shown here to display ink in the correct aspect ratio. For example, you could use GetPenDataAttributes to retrieve the rectangle of ink and then size a window to the same aspect ratio and let the DrawPenDataEx function scale the drawing into that window.

The following example demonstrates the effect of setting the Rendering option in the Drawing Options dialog box to either Scale or Clip.

//-------------------------------------------------------------------------

LRESULT CALLBACK        // return LRESULT

ANOutWndProc(           // drawing window procedure

   HWND hwnd,           // == vhwndOut

   UINT message,

   WPARAM wParam,

   LPARAM lParam)

   {

   LRESULT lRet = 1L;

   static char const szBoxTitle[] = "DrawPenDataEx";

   int nDisplayWidth, nDisplayHeight, nMapWidth, nMapHeight;

   switch (message)

      {

   	case WM_USER:  // for Redraw macro

    .

    .

    .

   	case WM_CHAR:

    .

    .

    .

   	case WM_PAINT:

    .

    .

    .

            if (vandlg.fRenderScale)            // scale to window

               GetClientRect(hwnd, &r);

            else

             if (vfScaled == FALSE)

               {

                 // Display in the same aspect ratio as the original ink, and

                 // clip the pen data if it is outside the window.

                 // Scale the pen data to display the coordinates and trim the

                 // excess data.

                 if(MetricScalePenData(vhpndt, PDTS_DISPLAY))

                    TrimPenData(vhpndt, TPD_COLLINEAR |	// duplicate strokes

                                        TPD_EMPTYSTROKES |	// strokes w/o points

                                        TPD_USER |	// header info

                                        TPD_PENINFO |	// OEM data

                                        TPD_OEMDATA ,	// OEM data

                                        0);

                 // Use the following function if there is no animation or

                 // up strokes.

                 //TrimPenData(vhpndt, TPD_EVERYTHING, 0);

                 // Set the mapping mode to the same as PDTS_DISPLAY.

                 SetMapMode(hdc, MM_TEXT);

                 // Get the bounding rectangle of the pen data in the PDTS_DISPLAY

                 // mapping mode.

                 GetPenDataAttributes(vhpndt, &r, GPA_RECTBOUND);

                 nMapWidth = r.right - r.left;

                 nMapHeight = r.bottom - r.top;

                 // Get the screen resolution.

                 nDisplayWidth=GetDeviceCaps(hdc, HORZRES);

                 nDisplayHeight=GetDeviceCaps(hdc, VERTRES);

                 // If the pen data is still too big, resize it to fit on the screen.

                 if (r.right > nDisplayWidth || r.bottom > nDisplayHeight)

                 {

                     // Resize the rectangle, maintaining the aspect ratio.

                     if(nMapWidth > nMapHeight)

                       AspectRatio = (float)nDisplayWidth/(float)nMapWidth;

                     else

                       AspectRatio = (float)nDisplayHeight/(float)nMapHeight;

                     // Reduce slightly for margins on the screen.

                     AspectRatio *= (float) 0.8;

                     // Set the right and bottom of the rectangle to a new size.

                     r.right = (int) (AspectRatio * (float)r.right);

                     r.bottom = (int) (AspectRatio * (float)r.bottom);

                     // Resize the pen data to the new rectangle.

                     ResizePenData(vhpndt, &r);

             }

             // Do scaling only once.

             vfScaled = TRUE;


Displaying the Pen Data

The AN_PKPD.RC resource file sets a menu with two drawing procedure options: AnimatePenData and DrawPenDataEx. The DrawPenDataEx function is used for both procedures.

For nonanimated drawing (IDM_DRAWPARTIAL selection), the DrawPenDataPartial local macro is used.

#define DrawPenDataPartial(hdc, lprect, hpndt, s0, s1, p0, p1)\

   DrawPenDataEx(hdc, lprect, hpndt, s0, s1, p0, p1, NULL, NULL, 0)

Starting and ending strokes and starting and ending points, which can be set in the Drawing Options dialog box, are sent to the DrawPenDataEx function. The following example shows the result of selecting DrawPenDataEx from the DrawProc menu before loading pen data.

case DPDPART:  // partial drawing

  default:

   DrawPenDataPartial(hdc, // DC

      &r,                  // rectangle for scaling and clipping

      vhpndt,              // pen data

      vandlg.uStrk0,       // first stroke to draw

      vandlg.uStrk1,       // last stroke to draw

      vandlg.uPt0,         // first point in first stroke to draw

      vandlg.uPt1);        // last point in last stroke to draw

    break;

  }

The second way that DrawPenDataEx is used in the sample application is for animation. Animation is a process by which DrawPenDataEx draws the pen data using timing information stored when the ink was originally drawn by the user and timing information passed to the function when it is called. Animation requires a callback function and an ANIMATEINFO structure.

To animate pen data, the lpai parameter of DrawPenDataEx must be the address of an ANIMATEINFO structure. The AN_PKPD sample application fills in this structure with the following information.

ANIMATEINFO ai =

{

    sizeof(ANIMATEINFO),                   // structure size

    vandlg.uSpeedPct,                      // speed as a percent

    MakeMs(vandlg.uCBPeriodCode),          // callback period in ms.

    vandlg.fSkipUp? AI_SKIPUPSTROKES: 0,   // options

    0L,                                    // lParam

    0L                                     // reserved

};

The second member of this structure (set here to vandlg.uSpeedPct) sets an animation speed relative to the original speed at which it was drawn. A setting of 100% produces the original speed. The third member sets the callback period. If this is set to None in the dialog box, the callback function is never called and you lose access to the dialog box until animation has finished.

The fourth member of this structure allows you to set options—in this case, the option of skipping "up strokes," which comprise the timing information recorded when the pen is not on the tablet.

To enable animation, you must also supply the address of a callback function to DrawPenDataEx. The AN_PKPD sample application uses a callback function called AnimateProc, which is defined as follows.

AnimateProc(                  // animation callback procedure

   HPENDATA hpndt,            // pen data

   UINT wStroke,              // current stroke

   UINT cPnts,                // number of points yet to draw

   UINT FAR *lpuSpeedPct,     // address of speed percent

   LPARAM lParam)             // application value

The animation callback function is typically used to allow for user activity to occur during animation. For example, the user may want to change the speed of the animation. For this reason, a pointer to the uSpeedPct member of the ANIMATEINFO structure is passed to the animation callback function so that it can be set by the function. The AnimateProc callback function in the application also displays the number of callbacks calls made in the window title of the application, if the user has selected Callback Display from the View menu.

The following example shows the code involved in the three methods of displaying data in the AN_PKPD sample application. Note that some sections of code,  indicated by ellipses, have been removed in order to show only code sections relevant to displaying data. For the complete listing, see the sample application.

AN_PKPD.RC

.

.

.

    POPUP "&DrawProc"

    BEGIN

        MENUITEM "&AnimatePenData",             IDM_DRAWEX, CHECKED

        MENUITEM "DrawPenDataE&x",              IDM_DRAWPARTIAL

    END

AN_PKPD.C

.

.

.

// Defines

.

.

.

#define DPDEX           (IDM_DRAWEX - IDM_DRAWEX)

#define DPDPART         (IDM_DRAWPARTIAL - IDM_DRAWEX)

.

.

.

// Type definitions

typedef struct tagANDLG // dialog box initialization [default values in brackets]

   {

   UINT uStrk0;         // first stroke to render [0]

   UINT uPt0;           // point offset in first stroke [0]

   UINT uStrk1;         // last stroke to render [-1]

   UINT uPt1;           // point offset in last stroke [-1]

   BOOL fSkipUp;        // FALSE to animate upstrokes, TRUE to skip them

   BOOL fAutoRepeat;    // FALSE to end after one rendering, TRUE to repeat to tap

   UINT uCBPeriodCode;  // callback period code [CALLBACKNEVER]

   UINT uSpeedPct;      // speed of animation [100%]

   BOOL fRenderScale;   // TRUE to scale pen data to output window, FALSE to clip

   }

   ANDLG, FAR *LPANDLG;

.

.

.

// Macros

.

.

.

// Draw only part of the pen data.

#define DrawPenDataPartial(hdc, lprect, hpndt, s0, s1, p0, p1)\

   DrawPenDataEx(hdc, lprect, hpndt, s0, s1, p0, p1, NULL, NULL, 0)

.

.

.

//-------------------------------------------------------------------------------

LRESULT CALLBACK        // returns LRESULT

ANOutWndProc(           // drawing window procedure

   HWND hwnd,           // == vhwndOut

   UINT message,

   WPARAM wParam,

   LPARAM lParam)

   {

    .

    .

    .

   switch (message)

      {

   	case WM_USER:  // for Redraw macro

     .

     .

     .

   	case WM_CHAR:

     .

     .

     .

   	case WM_PAINT:

     .

     .

     .

      if (vhpndt)

         {

         PAINTSTRUCT ps;

         HDC hdc = BeginPaint(hwnd, &ps);

         vfDrawing = TRUE;       // set semaphore

         if (hdc)

            {

            RECT r;

            int iRet;

            int nWidthDPD = 1;

            COLORREF crDPD = RGB(0, 255, 255);  // cyan default for DrawPenData pen

            ANIMATEINFO ai =

               {

               sizeof(ANIMATEINFO),                   // structure size

               vandlg.uSpeedPct,                      // speed as a percent

               MakeMs(vandlg.uCBPeriodCode),          // callback Period in ms.

               vandlg.fSkipUp? AI_SKIPUPSTROKES: 0,   // options

               0L,                                    // lParam

               0L                                     // reserved

               };

            .

            .

            .

           // Scaling done here. For more information, see "Scaling

           // and Trimming Pen Data."

            .

            .

            .

            switch (nDrawProc)

               {

            case DPDEX:                      // animation

               vcCB = 0;                     // animation callback counter

               vfReqCxl = FALSE;             // reset

               ShowCancel(vandlg.uCBPeriodCode != CALLBACKNEVER);

               iRet = DrawPenDataEx(

                  hdc,                       // handle to DC

                  &r,                        // rectangle for scaling and clipping

                  vhpndt,                    // pen data

                  vandlg.uStrk0,             // first stroke

                  vandlg.uStrk1,             // last stroke

                  vandlg.uPt0,               // first point in first stroke

                  vandlg.uPt1,               // last point in last stroke

                  vlpfnAnimateProc,          // AnimateProc callback function

                  &ai,

                  0);

               if (iRet < 0 && iRet >= -10)

                  {

                .

                .

                .

                // Error handling code goes here.

                .

                .

                .

               vfReqCxl = FALSE;

               break;

            case DPDPART:  // partial drawing

            default:

               DrawPenDataPartial(hdc, // DC

                  &r,                  // rectangle for scaling and clipping

                  vhpndt,              // pen data

                  vandlg.uStrk0,       // first stroke to draw

                  vandlg.uStrk1,       // last stroke to draw

                  vandlg.uPt0,         // first point in first stroke to draw

                  vandlg.uPt1);        // last point in last stroke to draw

               break;

               }

            ClearAppQueue();  // handle message backlog, if any

            if (vandlg.fAutoRepeat)

               Redraw();

            }

         EndPaint(hwnd, &ps);

         vfDrawing = FALSE;

         }

...

//-------------------------------------------------------------------------

BOOL CALLBACK               // return LRESULT; NB _export to ensure correct ds

AnimateProc(                // animation callback procedure

   HPENDATA hpndt,          // pen data

   UINT wStroke,            // current stroke

   UINT cPnts,              // number of points yet to draw

   UINT FAR *lpuSpeedPct,   // address of speed percent

   LPARAM lParam)           // application value

   {

   BOOL fRet = !vfReqCxl;     // set in dialog box and File menu

   hpndt, wStroke, cPnts, lParam;   // unused

   if (fRet)

      {

      char sz[cbSzTMax];

      if (!vcCB)

         ShowCancel(TRUE);

      ClearAppQueue();     // handle message backlog in app. queue

      *lpuSpeedPct = vandlg.uSpeedPct;    // get latest speed setting

      wsprintf((LPSTR)sz, (LPSTR)"CB=%u", ++vcCB);

        if (vfCB)

         SetWindowText(vhwndAN, (LPSTR)sz);

      // vfReqCxl may have gotten set in ANOutWndProc's WM_PAINT if

      // the user, for example, changed the window size during a callback.

      fRet = !vfReqCxl;

      }

   return fRet;

   }


Enabling Your Applications For Pen-Based Systems

Windows 95 implements pen services that all developers of Windows 95 − based applications need to be aware of, regardless of whether their applications make use of the functions found in the Pen Windows version 2.0. Windows 95 can run on mobile platforms, and physical keyboards may not be available for these devices. In addition, applications for Far-Eastern markets may need to function without keyboard input. To ensure that your Windows 95 − based applications work appropriately on systems that do not use a keyboard, use the guidelines listed in this section.

For personal computer systems that have a pen installed, Windows 95 provides the pen user with a base level of functionality that includes handwriting edit controls and lens buttons. For Windows 95 − based applications to work well when the pen is the only input device, application developers need to implement the functionality described below and to design the interface to work well with a pen.


Handwriting Edit Controls

When the version stamp on your application identifies it as a Windows 95 − based application, all edit controls will be replaced by handwriting edit (hedit) controls. To ensure that your application uses hedit controls appropriately, follow the guidelines in this section.

To support hedit controls, you should mark your application as a Windows 95 − based application.

You should also keep the following points in mind when designing your application to use hedit controls:

•	The behavior of the hedit control may not be exactly identical to that of a standard edit control.

•	A hedit control may not cause the display of a dialog box to change; it may display the lens tool or confirmation dialog boxes.

•	If the focus leaves the dialog box, it may not indicate that the user is finished with the field. Pen-related derivative dialog boxes can be disabled on a case-by-case basis at WM_CTLINIT message and HN_BEGINDIALOG or  HN_ENDDIALOG notification message time.


Lens Buttons

Single-line hedit controls can include a lens button that the user chooses to open a writing window over the control if space permits and if the control is scrollable. This pop-up window acts like a dialog box for entering text. When the window is dismissed, it sends the text to the hedit control. To ensure that your application uses lens buttons appropriately, follow the guidelines in this section.

To support lens buttons, you should include the following in your application:

•	Give multiline edit controls access to the lens tool for multiline edit controls.

•	Leave plenty of room in your hedit controls for the lens button. You should create all single-line hedit controls with the WS_AUTOHSCROLL style even if you think they are wide enough. (Lens buttons will not appear on hedit controls that do not include this style.)

You should also keep the following points in mind when designing your application to use lens buttons:

•	Editing may not only occur within the hedit control.

•	A hedit control may never cause a dialog box to appear.

•	The focus may not have gone away when the hedit control loses focus; the focus may be in the lens control (which is a child of the hedit control).


Installing Applications

This article describes a standard set of guidelines for installing applications to run with the Microsoft® Windows® 95 operating system.


About Installing Applications

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


Installation Program

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

1.	Determines the user's hardware and software configuration and available disk space.

2.	Copies application executable and data files to the appropriate directories on the hard disk.

3.	Sets up the execution environment for the application by modifying existing files and adding entries to the registry.

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 read-only memory (CD-ROM) drives for installation programs, searching for filenames such as SETUP.EXE and INSTALL.EXE. If a file is found and the user agrees to finish the installation, Add/Remove Programs starts the program and exits. After that, the started program is responsible for guiding the user through the rest of the installation process.


Designing the Installation Program

Your installation program should be a "good" Windows-based application, employing the standard Windows graphical user interface, presenting users with options and status. It is recommended that you use the InstallShield SE Toolkit included in the Microsoft® Win32® Software Development Kit (SDK) to develop your installation programs. You should also read relevant sections of The Windows Interface Guidelines for Software Design for information about designing an application that is consistent with the look and feel of the Windows shell. It will also give you information about easy-to-implement features that will add value to your application and make use of new usability functionality in the shell.

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

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

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

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

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


Determining the Configuration

Your installation program should determine the hardware and software config-uration of the user's computer before copying files and setting the environment. It is important for the installation program to verify that everything needed to successfully run the application is available. For example, if your application depends on specific hardware or software, your installation program should make sure the hardware or software is present. If it is not, the program should notify the user immediately and recommend a course of action.

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

Your installation program should always determine whether any of the files to be installed are already on the hard disk. This is especially important for shared files, such as commonly used dynamic-link libraries (DLLs). If the files already exist, your installation program should check the version number to ensure that it is not replacing a file with an older version. In other words, the installation program should always make sure the most recent version of a file is installed on the user's disk.


Copying Files

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

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

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

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

Your installation program should copy all system-wide shared files to the Windows SYSTEM directory. If a given file already exists in this directory, the program should overwrite it with your application file only if your file is a more recent version. The GetFileTime, GetFileVersionInfo, and GetFileInformationByHandle functions can be used to determine which file is more recent. After copying a DLL file, 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" later in this article.

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.


Using a WININIT.INI File to Replace DLLs in Windows 95

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

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

DestinationFileName=SourceFileName

The following syntax is used to delete a file.

NUL=SourceFileName

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

[rename]

C:\WINDOWS\Fonts\arial.ttf=C:\WINDOWS\Fonts\arial.win

C:\WINDOWS\SYSTEM\advapi32.dll=C:\WINDOWS\SYSTEM\advapi32.tmp

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

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

WININIT.INI is not supported in Microsoft® Windows NT™. To replace DLLs already loaded in memory, use the MoveFileEx function.


Setting Up the Environment

Your installation program needs to set up the proper environment for your application. The environment consists of application-specific entries in the initialization files, the registry, and the Start button.


Setting Initialization Files

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

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

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

Your installation program should not make entries in the WIN.INI file. It should use the registry instead. If you have information that you do not want to put in the registry, your installation program should create a private initialization file and place it in the same directory that contains your application's executable files.


Adding Entries to the Registry

Your installation program should add information about your application to the registry. In particular, it should always add the following entries.

HKEY_LOCAL_MACHINE\SOFTWARE\CompanyName\ProductName\Version

Stores information pertaining to this particular copy of the application.

HKEY_CURRENT_USER\SOFTWARE

Stores user-specific preferences. This is information that application vendors used to store in the WIN.INI file. For example Microsoft Word might store the fact that a user wants the automatic save feature turned off here.

Your installation program should always add application-specific paths to the registry for your application. If your installation program registers 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 application's executable file. Under this new key, it creates the Path value name and assigns it a path using the same format as expected by the PATH environment variable.

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

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

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

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

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


Supporting Context Menu Operations

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

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

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

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

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

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


Adding the Application to the Start Button

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

To add an icon to the Start menu, your installation program should create a link to your application's executable file and place the link in the directory named \WINDOWS\STARTMEN\PROGRAMS. (Note that the WINDOWS directory should actually be the path returned by the GetWindowsDirectory function.) An installation program can create a link by using the IShellLink interface.


Using Filename Extensions

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

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

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


Register Document Types

Your installation program should register every file type used that is not provided by Windows 95:

•	For the files of interest to the user, such as document types, the installation program should register both an icon and a description. It should provide good OLE/shell verbs and also add a "ShellNew" entry so your document type shows up in the "New" menu. This menu is available when the user clicks mouse button 2 on any container or chooses the File menu in a folder window.

•	For files that the user would have a good reason to double-click, the installation program should provide the file with a good icon and description and also a registered "open" action so that the user can double-click it.

•	For files that are less interesting to the user, such as .INI or configuration files, the installation program should provide the file with a good icon and description. The best way to do this is to consistently use predefined filename extensions, such as .INI, .SYS, and .TXT.

•	For files of little interest to the user, the installation program should minimally register a file type so that there is a decent description in "Details" view (and possibly an icon). If the program does not register the type, the file is identified by whatever the filename extension may be. Registering the type ensures that the file is identified by the description and related icon.


Network Issues

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

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

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

\Windows

    \Command

    \Inf

    \Fonts

    \Help

    \Hyperterm

    \Pif

    \System

        \Color

        \Iosubsys

        \Viewers

        \VMM32

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

HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Setup

    SharedDir=

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

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

WIN.COM WININIT.EXE *.INI *.GRP	\Spool \Desktop \Startmen \Nethood
Your application and installation program should fully support Universal Naming Convention (UNC) paths. If an application is being installed on a network path, the installation program should store a UNC path in any shortcuts it makes for the Start menu. Your installation program can use the Windows network functions (WinNet*) 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.

For more information about network issues relating to Windows 95, see the Microsoft Windows 95 Resource Kit.


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, Windows 95 automatically runs a file on the CD. The file to run must be specified in an AUTORUN.INF file located in the CD's root directory. The following example shows a typical entry in an AUTORUN.INF file.

[AutoRun]

OPEN=myprog.exe

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

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

•	Even if the user chooses to run your application from the CD, your program will need to copy some files to the hard disk (for example, writable files and files containing the user's preferences).

•	If you include a shortcut on the desktop, your application should display a message when the user selects the shortcut and the CD is not loaded.


Installing Fonts

By carrying out these steps, you can write a single font installation routine that works for both Microsoft® 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 EnumFontsEx function. If that font is present, the program should check to see if its version is newer by matching the installed font name with the filename on the disk. The font name is stored in the following registry location for both Windows 95 and Windows NT.

HKeyLocalMachine\Software\Microsoft\Windows\CurrentVersion\Fonts

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

•	Before copying the .TTF file to the appropriate directory, the installation program should check to see if the filename already exists in that directory. If it does, the program should rename your .TTF file to some other name, perhaps by appending a number to the end of the basename.

•	After copying the .TTF file to the user's disk, the installation program should inform the system that it wants the font to be available. The program should pass it the .TTF filename directly by using the AddFontResource function. Windows 95 and Windows NT do not require the creation of .FOT files.

•	To make the font installation permanent, the installation program should add the font name and filename to the registry by writing both of the values to the following registry location.

HKeyLocalMachine\Software\Microsoft\Windows\CurrentVersion\Fonts


Removing an Application

Your installation program can direct the Add/Remove Programs application in Control Panel to list your application as an application that can be "automatically removed" 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. It is recommended that you use the sample uninstall program in the InstallShield SE Toolkit as the starting point for your own uninstall program. The sample illustrates the appropriate user interface and application removal tasks.

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.

Because computers running Microsoft® Win32s® and Windows NT do not provide Add/Remove Programs in Control Panel, your installation program needs to include an Icon in the Applications program group so that the user can launch the uninstall program.

To summarize, an uninstall program should complete the following steps:

•	Remove all information used by the application from the registry. If decrementing a DLL's usage count results in a usage count of zero, the uninstall program should display a message offering to delete the DLL or save it in case it may be needed later.

•	Remove any shortcuts to the application from the desktop.

•	Remove all program files related to the application. The uninstall program should not remove files that the user created with the application unless the user agrees to delete them. If the user's files are stored in the application's directory tree, the uninstall program should ask the user if the files should be moved to a new directory.

•	Remove empty directories left by the application.


Quick Checklist for Planning an Installation Program

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

•	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.

•	Do not copy files to the WINDOWS or SYSTEM directories. If you include fonts with your application, you should put the fonts in the Fonts folder.

•	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.

•	Do not assume that floppies are on Drive A.

•	Always supply defaults.

•	Name your installation program SETUP.EXE.


Shell's Namespace

A namespace is a collection of symbols, such as database keys or file and directory names.


About the Shell's Namespace

The Microsoft® Windows® 95 shell uses a single hierarchical namespace to organize all objects of interest to the user: files, storage devices, printers, network resources, and anything else that can be viewed using Windows Explorer. The root of this unified namespace is the Windows 95 desktop.

In many ways, the shell's namespace is analogous to a file system's directory structure. However, the namespace contains more types of objects than just files and directories. Familiar file system concepts, such as filename and path, have been replaced by more general and powerful associations. This article discusses some of these associations, outlines the organization of the shell's namespace, and describes the functions and interfaces associated with the namespace.


Folders and File Objects

A folder is a collection of items in the shell's namespace. A folder is analogous to a file system directory, and many folders are, in fact, directories. However, there are also other types of folders, such as remote computers, storage devices, the desktop folder, the Control Panel, the Printers folder, and the Fonts folder. A folder may contain other folders as well as items called file objects. A file object may be an actual file, or it can be a Control Panel application, a printer, or another type of object. Each type of folder can only contain certain kinds of file objects; for example, you cannot move a Control Panel application into a file system directory.

Because there are many kinds of folders and file objects, each folder is a OLE component object model (COM) object that "knows" how to enumerate its contents and carry out other actions. More precisely, each folder implements the IShellFolder interface. Retrieving the IShellFolder object for a shell folder is referred to as binding to the folder. An application that binds to a folder must eventually free the IShellFolder interface object by calling its Release member function.

You can bind to the desktop folder (retrieve the folder's IShellFolder interface) by using the SHGetDesktopFolder member function. You can enumerate subfolders by using the IShellFolder::EnumObjects member function. You can bind to a subfolder of any given folder by using the IShellFolder::BindToObject member function. Using these three functions, an application can navigate throughout the shell's entire namespace.


Item Identifiers and Pointers to Item Identifier Lists

Objects in the shell's namespace are assigned item identifiers and item identifier lists. An item identifier uniquely identifies an item within its parent folder. An item identifier list uniquely identifies an item within the shell's namespace by tracing a path to the item from the desktop. A pointer to an item identifier list, which is sometimes called a PIDL (pronounced piddle), is used with many functions.

Item identifiers and PIDLs are much like the filenames and paths used in a file system. However, they share this important difference: item identifiers and PIDLs are binary data structures that never appear to the user. Item names called display names that can be shown to the user are described later.

An item identifier is defined by the variable-length SHITEMID structure. The first two bytes of this structure specify its size, and the format of the remaining bytes depends on the parent folder, or more precisely on the software that implements the parent folder's IShellFolder interface. Except for the first two bytes, item identifiers are not strictly defined, and applications should make no assumptions about their format. To determine whether two item identifiers are equal, an application can use the IShellFolder::CompareIDs member function.

The ITEMIDLIST structure defines an element in an item identifier list (the only member of this structure is an SHITEMID structure). An item identifier list consists of one or more consecutive ITEMIDLIST structures packed on byte boundaries, followed by a 16-bit zero value. An application can walk a list of item identifiers by examining the size specified in each SHITEMID structure and stopping when it finds a size of zero.

Item identifier lists are almost always allocated using the shell's allocator (an IMalloc interface that you can retrieve by using the SHGetMalloc function). For example, some shell functions create an item identifier list and return a PIDL to it. In such cases, it is usually the application's responsibility to free the PIDL using the shell's allocator. Note that the SHGetMalloc function retrieves the task allocator for OLE applications.


Folder Locations

Certain folders have special meanings for the shell. An application can use shell functions to retrieve the locations of these special folders and to enable the user to browse for specific folders.

Some special folders are virtual folders — so called because they are not actual directories on any storage device, local or remote. Virtual folders like the desktop folder, the My Computer folder, and the Network Neighborhood folder make a unified namespace possible by serving as containers for any number of storage devices and network resources. Other virtual folders contain file objects, such as printers, that are not part of the file system.

File system directories that the shell uses for specific purposes are also considered special folders. Examples include the Programs folder (which contains the user's program groups) and the desktop directory (which is used to physically store files that have been copied to the desktop folder). The locations of special file system folders are stored in the registry under the HKEY_CURRENT_USER / Software / Microsoft / Windows / CurrentVersion / Explorer / Shell Folders key.

You can use the SHGetSpecialFolderLocation function to retrieve the location of a special folder, which can be virtual or part of the file system. The function returns a PIDL, which the application must eventually free using the shell's allocator. If the folder is part of the file system, you can convert the PIDL to a file system path by using the SHGetPathFromIDList function. For a list of special folders, see the description of the SHGetSpecialFolderLocation function.

To display a dialog box that enables the user to browse for a folder, you can use the SHBrowseForFolder function. An application might use this function to prompt the user for a directory or remote computer. This function can also be used to browse for network printers, even though printers are not considered folders. An application can specify the root folder to browse from. For example, to prompt the user for a program group, you might call SHBrowseForFolder specifying the PIDL for the Programs folder as the root.


Item Enumeration

An application that uses the IShellFolder interface for a folder can determine the folder's contents by using the EnumObjects member function. This member function creates an item enumeration object, which is a set of item identifiers that can be retrieved by using the IEnumIDList interface.

One or more item identifiers can be retrieved from the enumeration object by using the IEnumIDList::Next member function. Calling this function repeatedly allows an application to retrieve all of the item identifiers one or more at a time. Using other member functions, you can skip items in the sequence, return to the beginning of the sequence, or "clone" the enumeration object to save its state.

When you are finished using the enumeration object, you must free it by calling the IEnumIDList::Release member function.


Display Names and Filenames

Because item identifiers are binary data structures, each item in a shell folder also has a display name, which is a string that can be shown to the user. You can use member functions in the IShellFolder interface to retrieve an item's display name, to find an item with the specified display name, or to change an item's display name.

The IShellFolder::GetDisplayNameOf member function can be used to retrieve a display name. The actual string returned depends on the type of display name specified. Values identifying the different types of display names are defined by the SHGNO enumerated type and have the SHGDN prefix. The type of display name that an application requests might depend on whether an item is shown by itself or within its parent folder. (A shared directory might be labeled Public on 'bill' in the former case and simply Public in the latter case.)

A special type of display name is one that can be converted back to an item identifier by using the IShellFolder::ParseDisplayName member function. You might use this type of display name as a parameter to the ShellExecute function or as a command-line argument for an application. For items within the file system, the display name for parsing is the same as the file system path. You can also convert a PIDL to a file system path by using the SHGetPathFromIDList function.

The IShellFolder::SetNameOf member function can be used to change the display name of a file object or subfolder. Changing an item's display name also changes its item identifier, so the function returns a PIDL containing the new item identifier. For file objects or folders within the file system, changing the display name renames the file or directory.


Object Attributes and Interfaces

Every file object and folder has attributes that determine, among other things, what actions can be carried out on it. An application can determine the attributes of any file object or folder and can retrieve interfaces for items in a shell folder.

To determine the attributes of a file object or folder, an application can use the IShellFolder::GetAttributesOf member function. Attributes include capabilities (such as whether a file object can be deleted or can be a drop target), display attributes (such as whether a folder is shared), contents flags (such as whether a folder has subfolders), as well as other attributes (such as whether an object is a folder, whether it is part of the file system, and so on). For a list of attributes, see the description of the IShellFolder::GetAttributesOf member function.

An application can retrieve interfaces that can be used to carry out actions on a file object or folder by using the IShellFolder::GetUIObjectOf member function. For example, the application can display the property sheets for a file object by retrieving the object's IContextMenu interface and activating the Properties command.


Using the Shell's Namespace

This section contains examples that demonstrate the functions and interfaces associated with the shell's namespace.


Using PIDLs and Display Names

This section presents an example illustrating how to retrieve the location of a special folder, walk an item identifier list, and use the IShellFolder interface to retrieve display names. The example is a Microsoft® Win32®-based console application that prints the display names of the folders a user would have to open to get to the Programs folder. To display them, the application would carry out these steps:

1.	Retrieve the PIDL (obtain a pointer to an item identifier list) for the Programs folder by using the SHGetSpecialFolderLocation function.

2.	Bind to the desktop folder (retrieve the folder's IShellFolder interface) by using the SHGetDesktopFolder function.

3.	Walk the item identifier list and process elements as follows: print the subfolder's display name, bind to the subfolder, and release the parent folder's IShellFolder interface.

Before carrying out any of the preceding steps, the application uses the SHGetMalloc function to retrieve a pointer to the shell's IMalloc interface, which it saves in the following global variable.

// Global pointer to the shell's IMalloc interface.

LPMALLOC g_pMalloc;

The following example shows the application's main function. This function carries out all of the steps described previously, although it calls the application-defined GetNextItemID and CopyItemID functions to walk the item identifier list and the application-defined PrintStrRet function to print the display names. These application-defined functions are described later in this section.

// main - the application's entrypoint function

int __cdecl main()

{

    LPITEMIDLIST pidlPrograms;

    LPSHELLFOLDER pFolder;

    // Get the shell's allocator.

    if (!SUCCEEDED(SHGetMalloc(&g_pMalloc)))

        return 1;

    // Get the PIDL for the Programs folder.

    if (SUCCEEDED(SHGetSpecialFolderLocation(NULL,

            CSIDL_PROGRAMS, &pidlPrograms))) {

        // Start with the desktop folder.

        if (SUCCEEDED(SHGetDesktopFolder(&pFolder))) {

            LPITEMIDLIST pidl;

            // Process each item identifier in the list.

            for (pidl = pidlPrograms; pidl != NULL;

                    pidl = GetNextItemID(pidl)) {

                STRRET sName;

                LPSHELLFOLDER pSubFolder;

                LPITEMIDLIST pidlCopy;

                // Copy the item identifier to a list by itself.

                if ((pidlCopy = CopyItemID(pidl)) == NULL)

                    break;

                // Display the name of the subfolder.

                if (SUCCEEDED(pFolder->lpVtbl->GetDisplayNameOf(

                        pFolder, pidlCopy, SHGDN_INFOLDER,

                        &sName)))

                    PrintStrRet(pidlCopy, &sName);

                // Bind to the subfolder.

                if (!SUCCEEDED(pFolder->lpVtbl->BindToObject(

                        pFolder, pidlCopy, NULL,

                        &IID_IShellFolder, &pSubFolder))) {

                    g_pMalloc->lpVtbl->Free(g_pMalloc, pidlCopy);

                    break;

                }

                // Free the copy of the item identifier.

                g_pMalloc->lpVtbl->Free(g_pMalloc, pidlCopy);

                // Release the parent folder and point to the

                // subfolder.

                pFolder->lpVtbl->Release(pFolder);

                pFolder = pSubFolder;

            }

            // Release the last folder that was bound to.

            if (pFolder != NULL)

                pFolder->lpVtbl->Release(pFolder);

        }

        // Free the PIDL for the Programs folder.

        g_pMalloc->lpVtbl->Free(g_pMalloc, pidlPrograms);

    }

    // Release the shell's allocator.

    g_pMalloc->lpVtbl->Release(g_pMalloc);

    return 0;

}

Following is the GetNextItemID function. Given a pointer to an element in an item identifier list, the function returns a pointer to the next element (or NULL if there are no more elements). The main function calls this function to walk the item identifier list for the Programs folder.

// GetNextItemID - points to the next element in an item identifier
//     list.

// Returns a PIDL if successful or NULL if at the end of the list.

// pdil - previous element

LPITEMIDLIST GetNextItemID(LPITEMIDLIST pidl)

{

    // Get the size of the specified item identifier.

    int cb = pidl->mkid.cb;

    // If the size is zero, it is the end of the list.

    if (cb == 0)

        return NULL;

    // Add cb to pidl (casting to increment by bytes).

    pidl = (LPITEMIDLIST) (((LPBYTE) pidl) + cb);

    // Return NULL if it is null-terminating or a pidl otherwise.

    return (pidl->mkid.cb == 0) ? NULL : pidl;

}

Following is the CopyItemID function. Given a pointer to an element in an item identifier list, the function allocates a new list containing only the specified element followed by a terminating zero. The main function uses this function to create single-element PIDLs, which it passes to IShellFolder member functions.

// CopyItemID - creates an item identifier list containing the first

//     item identifier in the specified list.

// Returns a PIDL if successful or NULL if out of memory.

LPITEMIDLIST CopyItemID(LPITEMIDLIST pidl)

{

    // Get the size of the specified item identifier.

    int cb = pidl->mkid.cb;

    // Allocate a new item identifier list.

    LPITEMIDLIST pidlNew = (LPITEMIDLIST)

        g_pMalloc->lpVtbl->Alloc(g_pMalloc, cb + sizeof(USHORT));

    if (pidlNew == NULL)

        return NULL;

    // Copy the specified item identifier.

    CopyMemory(pidlNew, pidl, cb);

    // Append a terminating zero.

    *((USHORT *) (((LPBYTE) pidlNew) + cb)) = 0;

    return pidlNew;

}

The IShellFolder::GetDisplayNameOf member function returns a display name in a STRRET structure. The display name may be returned in one of three ways, which is specified by the uType member of the STRRET structure. The main function calls the following PrintStrRet function to print the display name.

// PrintStrRet - prints the contents of a STRRET structure.

// pidl - PIDL containing the display name if STRRET_OFFSET

// lpStr - address of the STRRET structure

void PrintStrRet(LPITEMIDLIST pidl, LPSTRRET lpStr)

{

    LPSTR lpsz;

    int cch;

    switch (lpStr->uType) {

        case STRRET_WSTR:

            cch = WideCharToMultiByte(CP_OEMCP, WC_DEFAULTCHAR,

                lpStr->pOleStr, -1, NULL, 0, NULL, NULL);

            lpsz = (LPSTR) g_pMalloc->lpVtbl->Alloc(g_pMalloc, cch);

            if (lpsz != NULL) {

                WideCharToMultiByte(CP_OEMCP, WC_DEFAULTCHAR,

                    lpStr->pOleStr, -1, lpsz, cch, NULL, NULL);

                printf("%s\n", lpsz);

                g_pMalloc->lpVtbl->Free(g_pMalloc, lpsz);

            }

            break;

        case STRRET_OFFSET:

            printf("%s\n", ((char *) pidl) + lpStr->uOffset);

            break;

        case STRRET_CSTR:

            printf("%s\n", lpStr->cStr);

            break;

    }

}


Browsing for Folders

The following example uses the SHBrowseForFolder function to prompt the user for a program group. The Programs directory is specified as the root.

// Main_OnBrowse - browses for a program folder.

// hwnd - handle of the application's main window

//

// Uses the global variable g_pMalloc, which is assumed to point

//     to the shell's IMalloc interface.

void Main_OnBrowse(HWND hwnd)

{

    BROWSEINFO bi;

    LPSTR lpBuffer;

    LPITEMIDLIST pidlPrograms;  // PIDL for Programs folder

    LPITEMIDLIST pidlBrowse;    // PIDL selected by user

    // Allocate a buffer to receive browse information.

    if ((lpBuffer = (LPSTR) g_pMalloc->lpVtbl->Alloc(

            g_pMalloc, MAX_PATH)) == NULL)

        return;

    // Get the PIDL for the Programs folder.

    if (!SUCCEEDED(SHGetSpecialFolderLocation(

            hwnd, CSIDL_PROGRAMS, &pidlPrograms))) {

        g_pMalloc->lpVtbl->Free(g_pMalloc, lpBuffer);

        return;

    }

    // Fill in the BROWSEINFO structure.

    bi.hwndOwner = hwnd;

    bi.pidlRoot = pidlPrograms;

    bi.pszDisplayName = lpBuffer;

    bi.lpszTitle = "Choose a Program Group";

    bi.ulFlags = 0;

    bi.lpfn = NULL;

    bi.lParam = 0;

    // Browse for a folder and return its PIDL.

    pidlBrowse = SHBrowseForFolder(&bi);

    if (pidlBrowse != NULL) {

        // Show the display name, title, and file system path.

        MessageBox(hwnd, lpBuffer, "Display name", MB_OK);

        if (SHGetPathFromIDList(pidlBrowse, lpBuffer))

            SetWindowText(hwnd, lpBuffer);

        // Free the PIDL returned by SHBrowseForFolder.

        g_pMalloc->lpVtbl->Free(g_pMalloc, pidlBrowse);

    }

    // Clean up.

    g_pMalloc->lpVtbl->Free(g_pMalloc, pidlPrograms);

    g_pMalloc->lpVtbl->Free(g_pMalloc, lpBuffer);

}


Reference

The following interfaces, member functions, structures, macros, and types are associated with the shell's namespace.


Interfaces and Member Functions


IShellFolder [New - Windows 95]
IShellFolder

[New - Windows 95]

Designates an interface implemented by the shell and used to determine the contents of a folder. The IShellFolder interface has the following member functions.

BindToObject	Retrieves the specified interface for the specified subfolder.
BindToStorage	Reserved; this function is not currently implemented.
CompareIDs	Compares two item identifier lists and returns the result.
CreateViewObject	Reserved for use by the shell; do not use.
EnumObjects	Enumerates the objects in the folder.
GetAttributesOf	Retrieves the attributes of the specified file object or subfolder.
GetDisplayNameOf	Retreives the display name of a file object or subfolder.
GetUIObjectOf	Creates an OLE interface that can be used to carry out operations on a file object or subfolder.
ParseDisplayName	Translates a display name into an item identifier list.
SetNameOf	Sets the display name of the specified file object or subfolder and changes its identifier accordingly.
Like all OLE interfaces, IShellFolder also includes the QueryInterface, AddRef, and Release member functions.


IShellFolder::ParseDisplayName [New - Windows 95]
IShellFolder::ParseDisplayName

[New - Windows 95]

HRESULT IShellFolder::ParseDisplayName(

    LPSHELLFOLDER pIface, HWND hwndOwner, LPBC pbcReserved,

    LPWSTR lpwszDisplayName, ULONG *pchEaten,

    LPITEMIDLIST *ppidl, ULONG *pdwAttributes

    );

Translates a file object or folder's display name into an item identifier.

•	Returns the NOERROR value if successful or an OLE-defined error value otherwise.

pIface

Address of the IShellFolder interface. In C++, this parameter is implicit.

hwndOwner

Handle of the owner window that the client should specify if it displays a dialog box or message box.

pbcReserved

Reserved; this parameter is always NULL.

lpwszDisplayName

Address of a null-terminated Unicode string specifying the display name. This parameter must be a display name for parsing — that is, a display name retrieved using the SHGDN_FORPARSING value.

pchEaten

Address of an unsigned long value that receives the number of characters of the display name that were parsed.

ppidl

Address that receives a pointer to the new item identifier list for the object. If an error occurs, a NULL pointer is returned in this address.

The returned item identifier list specifies the relative path (from the parent folder) that corresponds to the specified display name. It contains only one SHITEMID structure followed by a terminating zero.

pdwAttributes

Address that receives the attributes of the file object.

This member function is similar to the IParseDisplayName::IParseDisplayName member function defined by OLE.


IShellFolder::EnumObjects [New - Windows 95]
IShellFolder::EnumObjects

[New - Windows 95]

HRESULT IShellFolder::EnumObjects(

    LPSHELLFOLDER pIface, HWND hwndOwner, DWORD grfFlags,

    LPENUMIDLIST *ppenumIDList

    );

Creates an item enumeration object (an IEnumIDList interface) that can be used to enumerate the contents of a folder.

•	Returns the NOERROR value if successful or an OLE-defined error value otherwise.

pIface

Address of the IShellFolder interface. In C++, this parameter is implicit.

hwndOwner

Handle of the owner window that the client should specify if it displays a dialog box or message box.

grfFlags

Flags determining which items to include in the enumeration. For a list of possible values, see the description of the SHCONTF type.

ppenumIDList

Address that receives a pointer to the IEnumIDList interface created by this member function. If an error occurs, a NULL pointer is returned in this address.

The calling application must free the returned IEnumIDList object by calling its Release member function.

This member function is similar to the IOleContainer::EnumObjects member function defined by OLE.


IShellFolder::BindToObject [New - Windows 95]
IShellFolder::BindToObject

[New - Windows 95]

HRESULT IShellFolder::BindToObject(

    LPSHELLFOLDER pIface, LPCITEMIDLIST pidl, LPBC pbcReserved,

    REFIID riid, LPVOID *ppvOut

    );

Creates an IShellFolder object for a subfolder.

•	Returns the NOERROR value if successful or an OLE-defined error value otherwise.

pIface

Address of the IShellFolder interface. In C++, this parameter is implicit.

pidl

Address of an ITEMIDLIST structure that identifies the subfolder relative to its parent folder.

pbcReserved

Reserved; applications should specify NULL for this parameter.

riid

Identifier of the interface to return. This parameter is almost always the IID_IShellFolder interface identifier.

ppvOut

Address that receives the interface pointer. If an error occurs, a NULL pointer is returned in this address.


IShellFolder::BindToStorage [New - Windows 95]
IShellFolder::BindToStorage

[New - Windows 95]

This member function is reserved for future use and is not currently implemented.


IShellFolder::CompareIDs [New - Windows 95]
IShellFolder::CompareIDs

[New - Windows 95]

HRESULT IShellFolder::CompareIDs(

    LPSHELLFOLDER pIface, LPARAM lParam,

    LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2

    );

Determines the relative ordering of two file objects or folders, given their item identifier lists.

•	Returns a handle to a result code. If this member function is successful, the CODE field of the status code (SCODE) has the following meaning:

CODE field	Meaning
Less than zero	The first item should precede the second (pidl1 < pidl2).
Greater than zero	The first item should follow the second (pidl1 > pidl2).
Zero	The two items are the same (pidl1 = pidl2).
pIface

Address of the IShellFolder interface. In C++, this parameter is implicit.

lParam

Value specifying the type of comparison to perform. The calling application should always specify zero, indicating that the two items should be sorted by name.

pidl1 and pidl2

Addresses of two ITEMIDLIST structures that uniquely identify the items to be compared. Both item identifier lists are relative to the parent folder.


IShellFolder::CreateViewObject [New - Windows 95]
IShellFolder::CreateViewObject

[New - Windows 95]

This member function is reserved for use by the shell and should not be called by applications.


IShellFolder::GetAttributesOf [New - Windows 95]
IShellFolder::GetAttributesOf

[New - Windows 95]

HRESULT IShellFolder::GetAttributesOf(

    LPSHELLFOLDER pIface, UINT cidl, LPCITEMIDLIST *apidl,

    ULONG *rgfInOut

    );

Retrieves the attributes of one or more file objects or subfolders.

•	Returns the NOERROR value if successful or an OLE-defined error value otherwise.

pIface

Address of the IShellFolder interface. In C++, this parameter is implicit.

cidl

Number of file objects to get the attributes of.

apidl

Address of an array of pointers to ITEMIDLIST structures, each of which uniquely identifies a file object relative to the parent folder. Each ITEMIDLIST structure must contain exactly one SHITEMID structure followed by a terminating zero.

rgfInOut

Address of an array of values that specify file object attributes. The calling application should initialize each array element by specifying which file object attributes to retrieve.

This member function returns the actual attributes of each file object in the corresponding array element; it may return all attributes or just the requested attributes.

The following attribute flags may be returned by this member function. File object attributes include capability flags, display attributes, contents flags, and miscellaneous attributes.

A file object's capability flags may include zero or more of these values:

SFGAO_CANCOPY	The specified file objects or folders can be copied (same value as the DROPEFFECT_COPY value).
SFGAO_CANDELETE	The specified file objects or folders can be deleted.
SFGAO_CANLINK	It is possible to create shortcuts for the specified file objects or folders (same value as the DROPEFFECT_LINK value).
SFGAO_CANMOVE	The specified file objects or folders can be moved (same value as the DROPEFFECT_MOVE value).
SFGAO_CANRENAME	The specified file objects or folders can be renamed.
SFGAO_CAPABILITYMASK	Mask for the capability flags.
SFGAO_DROPTARGET	The specified file objects or folders are drop targets.
SFGAO_HASPROPSHEET	The specified file objects or folders have property sheets.
A file object's display attributes may include zero or more of these values:

SFGAO_DISPLAYATTRMASK	Mask for the display attributes.
SFGAO_GHOSTED	The specified file objects or folders should be displayed using a ghosted icon.
SFGAO_LINK	The specified file objects are shortcuts.
SFGAO_READONLY	The specified file objects or folders are read-only.
SFGAO_SHARE	The specified folders are shared.
A file object's contents flags may include zero or more of these values:

SFGAO_CONTENTSMASK	Mask for the contents attributes.
SFGAO_HASSUBFOLDER	The specified folders have subfolders (and are, therefore, expandable in the left pane of Windows Explorer).
A file object may have zero or more of the following miscellaneous attributes:

SFGAO_FILESYSANCESTOR	The specified folders contain one or more file system folders.
SFGAO_FILESYSTEM	The specified folders or file objects are part of the file system (that is, they are files, directories, or root directories).
SFGAO_FOLDER	The specified items are folders.
SFGAO_REMOVABLE	The specified file objects or folders are on removable media.
SFGAO_VALIDATE	Validate cached information.


IShellFolder::GetUIObjectOf [New - Windows 95]
IShellFolder::GetUIObjectOf

[New - Windows 95]

HRESULT IShellFolder::GetUIObjectOf(

    LPSHELLFOLDER pIface, HWND hwndOwner, UINT cidl,

    LPCITEMIDLIST *apidl, REFIID riid, UINT *prgfReserved,

    LPVOID *ppvOut

    );

Returns an interface that can be used to carry out actions on the specified file objects or folders — typically, to create context menus or carry out drag and drop operations.

•	Returns the NOERROR value if successful or an OLE-defined error value otherwise.

pIface

Address of the IShellFolder interface. In C++, this parameter is implicit.

hwndOwner

Handle of the owner window that the client should specify if it displays a dialog box or message box.

cidl

Number of file objects or subfolders specified by apidl.

apidl

Address of an array of pointers to ITEMIDLIST structures, each of which uniquely identifies a file object or subfolder relative to the parent folder. Each item identifier list must contain exactly one SHITEMID structure followed by a terminating zero.

riid

Identifier of the interface to return. This parameter can be a pointer to the IID_IExtractIcon, IID_IContextMenu, IID_IDataObject, or IID_IDropTarget interface identifier.

prgfReserved

Reserved for future versions of Windows; must be NULL.

ppvOut

Address that receives the interface pointer. If an error occurs, a NULL pointer is returned in this address.


IShellFolder::GetDisplayNameOf [New - Windows 95]
IShellFolder::GetDisplayNameOf

[New - Windows 95]

HRESULT IShellFolder::GetDisplayNameOf(

    LPSHELLFOLDER pIface, LPCITEMIDLIST pidl, DWORD uFlags,

    LPSTRRET lpName

    );

Retrieves the display name for the specified file object or subfolder.

•	Returns the NOERROR value if successful or an OLE-defined error value otherwise.

pIface

Address of the IShellFolder interface. In C++, this parameter is implicit.

pidl

Address of an ITEMIDLIST structure that uniquely identifies the file object or subfolder relative to the parent folder.

uFlags

Flag indicating the type of display name to return. For a list of possible values, see the description of the SHGNO enumerated type.

lpName

Address of a STRRET structure in which to return the display name. The string returned in this structure depends on the type of display name requested.


IShellFolder::SetNameOf [New - Windows 95]
IShellFolder::SetNameOf

[New - Windows 95]

HRESULT IShellFolder::SetNameOf(

    LPSHELLFOLDER pIface, HWND hwndOwner, LPCITEMIDLIST pidl,

    LPCOLESTR lpszName, DWORD uFlags, LPITEMIDLIST *ppidlOut

    );

Changes the name of a file object or subfolder, changing its item identifier in the process.

•	Returns the NOERROR value if successful or an OLE-defined error value otherwise.

pIface

Address of the IShellFolder interface. In C++, this parameter is implicit.

hwndOwner

Handle of the owner window that the client should specify if it displays a dialog box or message box.

pidl

Address of an ITEMIDLIST structure that uniquely identifies the file object or subfolder relative to the parent folder.

lpszName

Address of a null-terminated string that specifies the new display name.

uFlags

Flag indicating the type of name specified by lpszName. For a list of possible values, see the description of the SHCONTF enumerated type.

ppidlOut

Address in which the member function returns a pointer to the new ITEMIDLIST structure. This parameter can be NULL, and the member function does not return the new structure for the object in that case.

If this parameter is not NULL, this member function frees the specified ITEMIDLIST structure and allocates a new one using the task allocator. The calling application is responsible for freeing the new ITEMIDLIST structure. If an error occurs, the member function returns NULL in this address.


IEnumIDList [New - Windows 95]
IEnumIDList

[New - Windows 95]

Designates an interface used to enumerate item identifiers. The IShellFolder::EnumObjects member function creates an IEnumIDList interface. The IEnumIDList interface has the following member functions.

Clone	Creates a new item enumeration object having the same contents and state as the given one.
Next	Retrieves one or more item identifiers and advances the current position.
Reset	Returns to the beginning of the enumeration sequence.
Skip	Skips over one or more items in the enumeration sequence.
Like all OLE interfaces, IEnumIDList also includes the QueryInterface, AddRef, and Release methods.


IEnumIDList::Clone [New - Windows 95]
IEnumIDList::Clone

[New - Windows 95]

HRESULT Clone(IEnumIDList FAR * pEnumIDList,
    IEnumIDList **ppenum);

Creates a new item enumeration object with the same contents and state as the current one.

•	Returns the NOERROR value if successful or an OLE-defined error value otherwise.

pEnumIDList

Address of the IEnumIDList interface. In C++, this parameter is implicit.

ppenum

Address that receives a pointer to the new enumeration object. The calling application must eventually free the new object by calling its Release member function.

This member function makes it possible to record a particular point in the enumeration sequence and then return to that point at a later time.


IEnumIDList::Next [New - Windows 95]
IEnumIDList::Next

[New - Windows 95]

HRESULT Next(IEnumIDList FAR * pEnumIDList,
    ULONG celt, LPITEMIDLIST *rgelt, ULONG *pceltFetched);

Retrieves the specified number of item identifiers in the enumeration sequence and advances the current position.

•	Returns the NOERROR value if successful, the S_FALSE value if there are no more items in the enumeration sequence, or an OLE-defined error value if an error occurs.

pEnumIDList

Address of the IEnumIDList interface. In C++, this parameter is implicit.

celt

Specifies the number of elements in the array pointed to by the rgelt parameter.

rgelt

Address of an array in which to return the item identifiers. The calling application must free the item identifiers by using the task allocator (retrieved by the SHGetMalloc function).

pceltFetched

Address of a value that receives a count of the item identifiers actually returned in rgelt. The count can be smaller than the value specified in the celt parameter. This parameter can be NULL if, and only if, celt is one.

If this member function returns any value other than NOERROR, no entries in the rgelt array are valid on exit. They are all in an indeterminate state.


IEnumIDList::Reset [New - Windows 95]
IEnumIDList::Reset

[New - Windows 95]

HRESULT Reset(IEnumIDList FAR * pEnumIDList,);

Returns to the beginning of the enumeration sequence.

•	Returns the NOERROR value if successful or an OLE-defined error value otherwise.

pEnumIDList

Address of the IEnumIDList interface. In C++, this parameter is implicit.


IEnumIDList::Skip [New - Windows 95]
IEnumIDList::Skip

[New - Windows 95]

HRESULT Skip(IEnumIDList FAR * pEnumIDList,
    ULONG celt);

Skips over the specified number of elements in the enumeration sequence.

•	Returns the NOERROR value if successful or an OLE-defined error value otherwise.

pEnumIDList

Address of the IEnumIDList interface. In C++, this parameter is implicit.

celt

Number of item identifiers to skip.


Functions

The following functions are used with the shell's namespace.


BrowseCallbackProc [New - Windows 95]
BrowseCallbackProc

[New - Windows 95]

int BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam,

    LPARAM lpData);

Specifies an application-defined callback function used with the SHBrowseForFolder function. A browse dialog box calls this function to notify it about events. The BFFCALLBACK type defines a pointer to this callback function.

•	Returns zero.

hwnd

Handle of the browse dialog box. The callback function can send the following messages to the window:

BFFM_ENABLEOK	Enables the OK button if wParam is nonzero or disables it if wParam is zero.
BFFM_SETSELECTION	Selects the specified folder. lParam is the PIDL of the folder to select if wParam is FALSE, or it is the path of the folder otherwise.
BFFM_SETSTATUSTEXT	Sets the status text to the null-terminated string specified by lParam.
uMsg

Value identifying the event. This parameter can be one of these values:

BFFM_INITIALIZED	The browse dialog box has finished initializing. lpData is NULL.
BFFM_SELCHANGED	The selection has changed. lpData is a pointer to the item identifier list for the newly selected folder.
lParam

Message-specific value. For more information, see the description of uMsg.

lpData

Application-defined value that was specified in the lParam member of the BROWSEINFO structure.


SHAddToRecentDocs [New - Windows 95]
SHAddToRecentDocs

[New - Windows 95]

void SHAddToRecentDocs(UINT uFlags, LPCVOID pv);

Adds a document to the shell's list of recently used documents or clears all documents from the list. The user accesses the list through the Start menu of the Windows taskbar.

•	No return value.

uFlags

Flag that indicates the meaning of pv. This parameter can be one of these values:

SHARD_PATH	pv is the address of a path string.
SHARD_PIDL	pv is the address of an item identifier list.
pv

Address of a buffer that contains the path and filename of the document, or the address of an ITEMIDLIST structure that contains an item identifier list uniquely identifying the document. If this parameter is NULL, the function clears all documents from the list.


SHBrowseForFolder [New - Windows 95]
SHBrowseForFolder

[New - Windows 95]

LPITEMIDLIST SHBrowseForFolder(LPBROWSEINFO lpbi);

Displays a browse dialog box that enables the user to select a shell folder.

•	Returns a pointer to an item identifier list that specifies the location of the selected folder relative to the root of the namespace. If the user chooses the Cancel button in the dialog box, the return value is NULL.

lpbi

Address of a BROWSEINFO structure that contains information used to display the dialog box.

The calling application is responsible for freeing the returned item identifier list using the shell's task allocator.


SHChangeNotify [New - Windows 95]
SHChangeNotify

[New - Windows 95]

void SHChangeNotify(LONG wEventId, UINT uFlags,
    LPCVOID dwItem1, LPCVOID dwItem2);

Notifies the system of an event that an application has performed. An application should use this function if it performs an action that may affect the shell.

•	No return value.

wEventId

Array of flags that specifies the events. This parameter can be a combination of these values:

SHCNE_ASSOCCHANGED	Changed a file type association.
SHCNE_ATTRIBUTES	Changed a file's attributes.
SHCNE_CREATE	Created a file.
SHCNE_DELETE	Deleted a file.
SHCNE_DRIVEADD	Added a network drive.
SHCNE_DRIVEADDGUI	Added a network drive by way of a graphic user interface (GUI).
SHCNE_DRIVEREMOVED	Removed a network drive.
SHCNE_INTERRUPT	Performed the event as a result of a system interrupt.
SHCNE_MEDIAINSERTED	Added removable media, such as a compact-disc read-only memory (CD-ROM) drive.
SHCNE_MEDIAREMOVED	Removed a removable medium, such as a CD-ROM drive.
SHCNE_MKDIR	Created a new directory.
SHCNE_NETSHARE	Shared a resource on the network.
SHCNE_NETUNSHARE	Stopped sharing a resource.
SHCNE_RENAMEFOLDER	Renamed a folder.
SHCNE_RENAMEITEM	Renamed an item in a folder.
SHCNE_RMDIR	Removed a directory.
SHCNE_SERVERDISCONNECT	Disconnected a network server.
SHCNE_UPDATEDIR	Updated the contents of a directory.
SHCNE_UPDATEIMAGE	Changed an image in the system global image list.
SHCNE_UPDATEITEM	Changed the properties of a printer or file.
uFlags

Flag that indicates the meaning of dwItem1 and dwItem2. This parameter can be one of these values:

SHCNF_DWORD	The dwItem1 and dwItem2 parameters are doubleword values.
SHCNF_FLUSH	Flushes the system event buffer. The function does not return until the system is finished processing the given event.
SHCNF_FLUSHNOWAIT	Flushes the system event buffer. The function returns immediately regardless of whether the system is finished processing the given event.
SHCNF_IDLIST	dwItem1 and dwItem2 are the addresses of item identifier lists.
SHCNF_PATH	dwItem1 and dwItem2 are paths.
SHCNF_PRINTER	dwItem1 and dwItem2 are printer "friendly" names.
dwItem1

First event-dependent value.

dwItem2

Second event-dependent value.


SHFileOperation [New - Windows 95]
SHFileOperation

[New - Windows 95]

int SHFileOperation(LPSHFILEOPSTRUCT lpFileOp);

Performs a copy, move, rename, or delete operation on a file system object.

•	Returns zero if successful or nonzero if an error occurs.

lpFileOp

Address of an SHFILEOPSTRUCT structure containing information that the function needs to carry out the operation.


SHFreeNameMappings [New - Windows 95]
SHFreeNameMappings

[New - Windows 95]

void SHFreeNameMappings(HANDLE hNameMappings);

Frees a filename mapping object that was retrieved by the SHFileOperation function.

•	No return value.

hNameMappings

Handle of the filename mapping object to free.


SHGetDesktopFolder [New - Windows 95]
SHGetDesktopFolder

[New - Windows 95]

HRESULT SHGetDesktopFolder(LPSHELLFOLDER *ppshf);

Retrieves the IShellFolder interface for the desktop folder, which is the root of the shell's namespace.

•	Returns the NOERROR value if successful or an OLE-defined error result otherwise.

ppshf

Address that receives an IShellFolder interface pointer for the desktop folder. The calling application is responsible for eventually freeing the interface by calling its Release member function.


SHGetFileInfo [New - Windows 95]
SHGetFileInfo

[New - Windows 95]

DWORD SHGetFileInfo(LPCSTR pszPath,
    DWORD dwFileAttributes, SHFILEINFO FAR *psfi, UINT cbFileInfo,
    UINT uFlags);

Retrieves information about an object in the file system, such as a file, a folder, a directory, or a drive root.

•	Returns a value whose meaning depends on the uFlags parameter. If uFlags specifies the SHGFI_EXETYPE value, the return value indicates the type of the executable file. For more information, see the comments below.

If uFlags includes the SHGFI_ICON or SHGFI_SYSICONINDEX value, the return value is the handle of the system image list that contains the large icon images. If the SHGFI_SMALLICON value is also included, the return value is the handle of the image list that contains the small icon images.

If uFlags does not include SHGFI_EXETYPE, SHGFI_ICON, SHGFI_SYSICONINDEX, or SHGFI_SMALLICON, the return value is nonzero if successful or zero otherwise.

pszPath

Address of a buffer that contains the path and filename. Both absolute and relative paths are valid. If uFlags includes the SHGFI_PIDL value, pszPath must be the address of an ITEMIDLIST structure that contains the list of item identifiers uniquely identifying the file within the shell's namespace.

dwFileAttributes

Array of file attribute flags (FILE_ATTRIBUTE_ values). If uFlags does not include the SHGFI_USEFILEATTRIBUTES value, this parameter is ignored.

psfi and cbFileInfo

Address and size, in bytes, of the SHFILEINFO structure that receives the file information.

uFlags

Flag that specifies the file information to retrieve. This parameter can be a combination of these values:

SHGFI_ATTRIBUTES	Retrieves the file attribute flags. The flags are copied to the dwAttributes member of the structure specified by psfi.
SHGFI_DISPLAYNAME	Retrieves the display name for the file. The name is copied to the szDisplayName member of the structure specified by psfi.
SHGFI_EXETYPE	Returns the type of the executable file if pszPath identifies an executable file. For more information, see the comments below.
SHGFI_ICON	Retrieves the handle of the icon that represents the file and the index of the icon within the system image list. The handle is copied to the hIcon member of the structure specified by psfi, and the index is copied to the iIcon member. The return value is the handle of the system image list.
SHGFI_ICONLOCATION	Retrieves the name of the file that contains the icon representing the file. The name is copied to the szDisplayName member of the structure specified by psfi.
SHGFI_LARGEICON	Modifies SHGFI_ICON, causing the function to retrieve the file's large icon.
SHGFI_LINKOVERLAY	Modifies SHGFI_ICON, causing the function to add the link overlay to the file's icon.
SHGFI_OPENICON	Modifies SHGFI_ICON, causing the function to retrieve the file's open icon. A container object displays an open icon to indicate that the container is open.
SHGFI_PIDL	Indicates that pszPath is the address of an ITEMIDLIST structure rather than a path name.
SHGFI_SELECTED	Modifies SHGFI_ICON, causing the function to blend the file's icon with the system highlight color.
SHGFI_SHELLICONSIZE	Modifies SHGFI_ICON, causing the function to retrieve a shell-sized icon. If this value is not specified, the function sizes the icon according to the system metric values.
SHGFI_SMALLICON	Modifies SHGFI_ICON, causing the function to retrieve the file's small icon.
SHGFI_SYSICONINDEX	Retrieves the index of the icon within the system image list. The index is copied to the iIcon member of the structure specified by psfi. The return value is the handle of the system image list.
SHGFI_TYPENAME	Retrieves the string that describes the file's type. The string is copied to the szTypeName member of the structure specified by psfi.
SHGFI_USEFILEATTRIBUTES	Indicates that the function should use dwFileAttributes. This flag must be set when retrieving an icon for a file that does not exist.
To retrieve the executable file type, uFlags must specify only SHGFI_EXETYPE. The return value specifies the type of the executable file:

0	Nonexecutable file or an error condition
LOWORD = NE or PE HIWORD = 3.0, 3.5, or 4.0	Windows-based application
LOWORD = MZ HIWORD = 0	Microsoft® MS-DOS® .EXE, .COM, or .BAT file
LOWORD = PE HIWORD = 0	Win32-based console application


SHGetInstanceExplorer [New - Windows 95]
SHGetInstanceExplorer

[New - Windows 95]

HRESULT SHGetInstanceExplorer(IUnknown **ppunk);

Retrieves the address of Explorer's IUnknown interface.

•	Returns the NOERROR value if successful or the E_FAIL value otherwise.

ppunk

Address of a value that receives the address of Explorer's IUnknown interface.


SHGetMalloc [New - Windows 95]
SHGetMalloc

[New - Windows 95]

HRESULT SHGetMalloc(LPMALLOC * ppMalloc);

Retrieves a pointer to the shell's IMalloc interface. A shell extension must use this interface to allocate memory that is later freed by the shell.

•	Returns the NOERROR value if successful or E_FAIL otherwise.

ppMalloc

Address of a value that receives the address of the shell's IMalloc interface.


SHGetPathFromIDList [New - Windows 95]
SHGetPathFromIDList

[New - Windows 95]

BOOL SHGetPathFromIDList(LPCITEMIDLIST pidl,

    LPSTR pszPath);

Converts an item identifier list to a file system path.

•	Returns TRUE if successful or FALSE if an error occurs — for example, if the location specified by pidl is not part of the file system.

pidl

Address of an item identifier list that specifies a file or directory location relative to the root of the namespace (the desktop).

pszPath

Address of a buffer that receives the file system path. The size of this buffer is assumed to be MAX_PATH bytes.


SHGetSpecialFolderLocation [New - Windows 95]
SHGetSpecialFolderLocation

[New - Windows 95]

HRESULT SHGetSpecialFolderLocation(HWND hwndOwner,

    int nFolder, LPITEMIDLIST * ppidl);

Retrieves the location of a special folder.

•	Returns the NOERROR value if successful or an OLE-defined error result otherwise.

hwndOwner

Handle of the owner window that the client should specify if it displays a dialog box or message box.

nFolder

Value specifying the folder to retrieve the location for. This parameter can be one of these values:

CSIDL_BITBUCKET	Recycle bin — file system directory containing file objects in the user's recycle bin. The location of this directory is not in the registry; it is marked with the hidden and system attributes to prevent the user from moving or deleting it.
CSIDL_CONTROLS	Control Panel — virtual folder containing icons for Control Panel applications.
CSIDL_DESKTOP	Windows desktop — virtual folder at the root of the namespace.
CSIDL_DESKTOPDIRECTORY	File system directory used to physically store file objects on the desktop (not to be confused with the desktop folder itself).
CSIDL_DRIVES	My Computer — virtual folder containing everything on the local computer: storage devices, printers, and Control Panel. The folder may also contain mapped network drives.
CSIDL_FONTS	Virtual folder containing fonts.
CSIDL_NETHOOD	File system directory containing objects that appear in Network Neighborhood.
CSIDL_NETWORK	Network Neighborhood — virtual folder representing the top level of the network hierarchy.
CSIDL_PERSONAL	File system directory that serves as a common repository for documents.
CSIDL_PRINTERS	Printers folder — virtual folder containing installed printers.
CSIDL_PROGRAMS	File system directory that contains the user's program groups (which are also file system directories).
CSIDL_RECENT	File system directory that contains the user's most recently used documents.
CSIDL_SENDTO	File system directory that contains Send To menu items.
CSIDL_STARTMENU	File system directory containing Start menu items.
CSIDL_STARTUP	File system directory that corresponds to the user's Startup program group.
CSIDL_TEMPLATES	File system directory that serves as a common repository for document templates.
ppidl

Address that receives a pointer to an item identifier list specifying the folder's location relative to the root of the namespace (the desktop).


SHLoadInProc [New - Windows 95]
SHLoadInProc

[New - Windows 95]

HRESULT SHLoadInProc(REFCLSID rclsid);

Creates an instance of the specified object class from within the context of the shell's process.

•	Returns the NOERROR value if successful or an OLE-defined error result otherwise.

rclsid

Class identifier (CLSID) of the object class to be created.


Structures, Macros, and Types

The following structures, macros, and types are used with the shell's namespace.


BROWSEINFO [New - Windows 95]
BROWSEINFO

[New - Windows 95]

typedef struct _browseinfo {

    HWND hwndOwner;          // see below

    LPCITEMIDLIST pidlRoot;  // see below

    LPSTR pszDisplayName;    // see below

    LPCSTR lpszTitle;        // see below

    UINT ulFlags;            // see below

    BFFCALLBACK lpfn;        // see below

    LPARAM lParam;           // see below

    int iImage;              // see below

} BROWSEINFO, *PBROWSEINFO, *LPBROWSEINFO;

Contains parameters for the the SHBrowseForFolder function and receives information about the folder selected by the user.

hwndOwner

Handle of the owner window for the dialog box.

pidlRoot

Address of an item identifier list (an ITEMIDLIST structure) specifying the location of the "root" folder to browse from. Only the specified folder and its subfolders appear in the dialog box. This member can be NULL, and the namespace root (the desktop folder) is used in that case.

pszDisplayName

Address of a buffer that receives the display name of the folder selected by the user. The size of this buffer is assumed to be MAX_PATH bytes.

lpszTitle

Address of a null-terminated string that is displayed above the tree view control in the dialog box. This string can be used to specify instructions to the user.

ulFlags

Value specifying the types of folders to be listed in the dialog box as well as other options. This member can include zero or more of these values:

BIF_BROWSEFORCOMPUTER	Only returns computers. If the user selects anything other than a computer, the OK button is grayed.
BIF_BROWSEFORPRINTER	Only returns printers. If the user selects anything other than a printer, the OK button is grayed.
BIF_DONTGOBELOWDOMAIN	Does not include network folders below the domain level in the tree view control.
BIF_RETURNFSANCESTORS	Only returns file system ancestors. If the user selects anything other than a file system ancestor, the OK button is grayed.
BIF_RETURNONLYFSDIRS	Only returns file system directories. If the user selects folders that are not part of the file system, the OK button is grayed.
BIF_STATUSTEXT	Includes a status area in the dialog box. The callback function can set the status text by sending messages to the dialog box.
lpfn

Address an application-defined function that the dialog box calls when events occur. For more information, see the description of the BrowseCallbackProc function. This member can be NULL.

lParam

Application-defined value that the dialog box passes to the callback function, if one is specified.

iImage

Variable that receives the image associated with the selected folder. The image is specified as an index to the system image list.


CIDA [New - Windows 95]
CIDA

[New - Windows 95]

typedef struct _IDA {

    UINT cidl;        // number of array elements

    UINT aoffset[1];  // see below

} CIDA, * LPIDA;

Corresponds to the CF_IDLIST clipboard format.

aoffset

Array of offsets relative to the beginning of the CIDA structure. The first element is the offset of the ITEMIDLIST structure for a folder (absolute from the root). Subsequent elements are offsets of ITEMIDLIST structures for file objects (relative from the parent folder).


SHCONTF [New - Windows 95]
SHCONTF

[New - Windows 95]

typedef enum tagSHCONTF {

    SHCONTF_FOLDERS = 32,         // for shell browser

    SHCONTF_NONFOLDERS = 64,      // for default view

    SHCONTF_INCLUDEHIDDEN = 128,  // for hidden or system objects

} SHCONTF;

Specifies an enumerated type that defines flags used with the IShellFolder::EnumObjects member function.


SHFILEINFO [New - Windows 95]
SHFILEINFO

[New - Windows 95]

typedef struct _SHFILEINFO { // shfi

    HICON hIcon;                   // see below

    int   iIcon;                   // see below

    DWORD dwAttributes;            // see below

    char  szDisplayName[MAX_PATH]; // see below

    char  szTypeName[80];          // see below

} SHFILEINFO;

Contains information about a file object.

hIcon

Handle of the icon that represents the file.

iIcon

Index of the icon image within the system image list.

dwAttributes

Array of flags that indicates the attributes of the file object. For information about the flags, see the description of the IShellFolder::GetAttributesOf member function.

szDisplayName

String that contains the name of the file as it appears in the Windows shell, or the path and filename of the file that contains the icon representing the file.

szTypeName

String that describes the type of the file.

This structure is used with the SHGetFileInfo function.


SHFILEOPSTRUCT [New - Windows 95]
SHFILEOPSTRUCT

[New - Windows 95]

typedef struct _SHFILEOPSTRUCT { // shfos

    HWND         hwnd;                  // see below

    UINT         wFunc;                 // see below

    LPCSTR       pFrom;                 // see below

    LPCSTR       pTo;                   // see below

    FILEOP_FLAGS fFlags;                // see below

    BOOL         fAnyOperationsAborted; // see below

    LPVOID       hNameMappings;         // see below

    LPCSTR       lpszProgressTitle;     // see below

} SHFILEOPSTRUCT, FAR *LPSHFILEOPSTRUCT;

Contains information that the SHFileOperation function uses to perform file operations.

hwnd

Handle of the dialog box used to display information about the status of the operation. If fFlags includes the FOF_CREATEPROGRESSDLG value, this parameter is the handle of the parent window for the progress dialog box created by the system.

wFunc

Operation to perform. This member can be one of these values:

FO_COPY	Copies the files specified by pFrom to the location specified by pTo.
FO_DELETE	Deletes the files specified by pFrom (pTo is ignored).
FO_MOVE	Moves the files specified by pFrom to the location specified by pTo.
FO_RENAME	Renames the files specified by pFrom.
pFrom

Address of a string that contains the names of the source files.

pTo

Address of a string that specifies the destination for the moved, copied, or renamed file.

fFlags

Flags that control the file operation. This member can be a combination of these values:

FOF_ALLOWUNDO	Preserves undo information, if possible.
FOF_CONFIRMMOUSE	Not implemented.
FOF_FILESONLY	Performs the operation only on files if a wildcard filename (*.*) is specified.
FOF_MULTIDESTFILES	Indicates that the pTo member specifies multiple destination files (one for each source file) rather than one directory where all source files are to be deposited.
FOF_NOCONFIRMATION	Responds with "yes to all" for any dialog box that is displayed.
FOF_NOCONFIRMMKDIR	Does not confirm the creation of a new directory if the operation requires one to be created.
FOF_RENAMEONCOLLISION	Gives the file being operated on a new name (such as "Copy #1 of...") in a move, copy, or rename operation if a file of the target name already exists.
FOF_SILENT	Does not display a progress dialog box.
FOF_SIMPLEPROGRESS	Displays a progress dialog box, but does not show the filenames.
FOF_WANTMAPPINGHANDLE	Fills in the hNameMappings member. The handle must be freed by using the SHFreeNameMappings function.
fAnyOperationsAborted

Value that receives TRUE if the user aborted any file operations before they were completed or FALSE otherwise.

hNameMappings

Handle of a filename mapping object that contains an array of SHNAMEMAPPING structures. Each structure contains the old and new paths for each file that was moved, copied, or renamed. This member is used only if fFlags includes FOF_WANTMAPPINGHANDLE.

lpszProgressTitle

Address of a string to use as the title for a progress dialog box. This member is used only if fFlags includes FOF_SIMPLEPROGRESS.

If pFrom or pTo are unqualified names, the current directories are taken from the global current drive and directory settings as managed by the GetCurrentDirectory and SetCurrentDirectory functions.

The SHGetNameMappingPtr macro retrieves a pointer to the filename mapping object returned in the hNameMappings member. The SHGetNameMappingCount macro retrieves the number of SHNAMEMAPPING structures in the object.


SHNAMEMAPPING [New - Windows 95]
SHNAMEMAPPING

[New - Windows 95]

typedef struct _SHNAMEMAPPING { // shnm

    LPSTR pszOldPath; // address of old path

    LPSTR pszNewPath; // address of new path

    int   cchOldPath; // number of characters in old path

    int   cchNewPath; // number of characters in new path

} SHNAMEMAPPING, FAR *LPSHNAMEMAPPING;

Contains the old and new paths for each file that was moved, copied, or renamed by the SHFileOperation function.


STRRET [New - Windows 95]
STRRET

[New - Windows 95]

typedef struct _STRRET { // str

    UINT uType; // see below

    union

    {

        LPWSTR pOleStr;        // address of OLE string to free

        UINT   uOffset;        // offset into item identifier list

        char   cStr[MAX_PATH]; // buffer to receive display name

    } DUMMYUNIONNAME;

} STRRET, *LPSTRRET;

Contains strings returned from IShellFolder member functions, such as GetDisplayNameOf.

uType

Value that specifies the desired format of the string. This member can be one of these values:

STRRET_CSTR	The string is returned in cStr.
STRRET_OFFSET	The string is located at uOffset bytes from the beginning of the item identifier list.
STRRET_WSTR	The string is at the address pointed to by pOleStr.
The system may or may not provide the display name in the desired format. When IShellFolder::GetDisplayNameOf returns, uType indicates the format.


SHGetNameMappingCount [New - Windows 95]
SHGetNameMappingCount

[New - Windows 95]

int SHGetNameMappingCount(HANDLE hNameMappings)

Retrieves the number of SHNAMEMAPPING structures in a filename mapping object.

•	Returns the number of SHNAMEMAPPING structures.

hNameMappings

Handle of a filename mapping object retrieved by the SHFileOperation function.

The SHGetNameMappingCount macro is defined as follows.

#define SHGetNameMappingCount(_hnm) \
    DSA_GetItemCount(_hnm)


SHGetNameMappingPtr [New - Windows 95]
SHGetNameMappingPtr

[New - Windows 95]

lpshnm = SHGetNameMappingPtr(HANDLE hNameMappings, int iItem)

Retrieves the address of a SHNAMEMAPPING structure contained in a file mapping object.

•	Returns the address of the SHNAMEMAPPING structure specified by iItem.

hNameMappings

Handle of a filename mapping object retrieved by the SHFileOperation function.

iItem

Index of the SHNAMEMAPPING structure to be retrieved.

The SHGetNameMappingPtr macro is defined as follows.

#define SHGetNameMappingPtr(_hnm, _iItem) \
    (LPSHNAMEMAPPING)DSA_GetItemPtr(_hnm, _iItem)


SHGNO [New - Windows 95]
SHGNO

[New - Windows 95]

typedef enum tagSHGDN {

    SHGDN_NORMAL = 0,           // see below

    SHGDN_INFOLDER = 1,         // see below

    SHGDN_FORPARSING = 0x8000,  // see below

} SHGNO;

Specifies an enumerated type that defines flags used with the IShellFolder::GetDisplayNameOf and IShellFolder::SetNameOf member functions.

SHGDN_NORMAL

Default display name that is suitable for a file object displayed by itself, as shown in the following examples.

File system path	Corresponding display name
C:\WINDOWS\FILE.TXT	File
\\COMPUTER\SHARE	Share on computer
C:\ (where drive C has the volume name My Drive)	My Drive (C)
SHGDN_INFOLDER

Display name that is suitable for a file object displayed within its respective folder, as shown in the following examples.

File system path	Corresponding display name
C:\WINDOWS\FILE.TXT	File
\\COMP\SHARE	User
C:\ (where drive C has the volume name My Drive)	My Drive (C)
SHGDN_FORPARSING

Display name that can be passed to the ParseDisplayName member function of the parent folder's IShellFolder object.

File system path	Corresponding display name
C:\WINDOWS\FILE.TXT	C:\WINDOWS\FILE.TXT
\\COMP\SHARE	\\COMP\SHARE
C:\ (where drive C has the volume name My Drive)	C:\


Shell Extensions

In Microsoft® Windows® 95, applications can extend the shell in a number of ways. A shell extension enhances the shell by providing additional means of manipulating file objects, by simplifying the task of browsing through the file system and networks, or by giving the user easier access to tools that manipulate objects in the file system. For example, a shell extension can assign an icon to each file or add commands to the context menu and File menu for a file.


About Shell Extensions

Windows 95 supports two groups of shell extensions. The first group are registered for each type of file:

•	Context menu handlers. They add items to the context menu for a particular file object. (The context menu is displayed when the user clicks a file object with mouse button 2.)

•	Icon handlers. They typically add instance-specific icons for file objects. They can also be used to add icons for all files belonging to the same class.

•	Data handlers. They provide a type-specific IDataObject interface to be passed to the OLE DoDragDrop function.

•	Drop handlers. They provide type-specific drop behavior to files that can accept drag and drop objects.

•	Property sheet handlers. They add pages to the property sheet dialog box that the shell displays for a file object. The pages are specific to a class of files or a particular file object.

The second group of shell extensions are associated with file operations such as move, copy, rename, and so on:

•	Copy hook handlers. They are called when a folder object is about to be copied, moved, deleted, or renamed. They can either allow or prevent the operation.

•	Drag and drop handlers. They are context menu handlers that the system calls when the user drops an object after dragging it to a new position.

The design of a shell extension is based on the OLE Component Object Model (COM). The shell accesses an object through interfaces. An application implements the interfaces in a shell extension dynamic-link library (DLL), which is essentially an OLE in-process server DLL.

This article explains how to create shell extensions and describes how the shell interacts with them.


Shell Extension Terms

You should be familiar with the following shell extension terms before proceeding.

file object

A file object is an item within the shell. The most familiar file objects are files and directories. However, a file object may not actually be a part of the file system; it may only appear that way. For example, printers, Control Panel applications, and network shares, servers, and workgroups are also considered to be file objects.

file class

Each file object is a member of a file class. The file class refers to the code that "owns" the manipulation of files belonging to the class. For example, text files and Microsoft Word documents are examples of file classes. Each file class has specific shell extensions associated with it. When the shell is about to take an action involving a file object, it uses the file class to determine the shell extensions to load.

handler

A handler is the code that implements a particular shell extension.


Registry Entries for Extending the Shell

An application that creates and maintains files, such as a spreadsheet, word proces-sor, or graphics application, typically adds two keys to the system registry: a file association key and an application identifier key. The file association key maps a filename extension to an application identifier. For example, a word processing application might register the following key under HKEY_CLASSES_ROOT.

HKEY_CLASSES_ROOT

    .doc=AWordProcessor

The value name (.doc) specifies the filename extension, and the value (AWordProcessor) denotes the key name that contains the information about the application handling the filename extension.

The application identifier key is the second registry entry made by an application handling files.

HKEY_CLASSES_ROOT

    AWordProcessor=A Word Processor

The value (A Word Processor) is a string describing the application that recognizes files having the given filename extension. (In this case, it is the .DOC filename extension.)

Extending the shell requires that you add other entries below the file association and application identifier keys. The system checks these entries to determine the commands to add to various shell menus, when to load an extension DLL, where to find the DLL, and so on.

There are several registry keys that allow you to extend the shell without having to write any code at all. These keys let you set the default icon for a class of files or add commands to the File menu and its New submenu in Windows Explorer.


Setting Default Icons for File Classes

The system uses icons to represent file objects in the shell. Typically, all files of the same class have the same icon. By adding the DefaultIcon key to the file association key for a particular file class, you can specify the icon that the system displays for all files of the class. The value of the DefaultIcon key specifies the executable file (or DLL) that contains the icon and the index of the icon within the file.

HKEY_CLASSES_ROOT

    .doc=AWordProcessor

        DefaultIcon=C:\MYDIR\MYAPP.EXE,1

If the registry does not contain a DefaultIcon key for a particular file class, the system uses the default icon for the class. One of the advantages of using a class icon is that it requires no programming; the shell handles displaying the icon for the class.

By writing an icon handler, you give each instance of a file a different icon. For more information about icon handlers, see "Icon Handlers" later in this article.


Modifying the Context Menu for a File Class

When the user clicks a file object using mouse button 2, the system displays a context menu for the object. The context menu contains a set of menu items that allow the user to perform various operations on the file object, such as opening or printing it. A context menu contains two types of items: dynamic items and static items. Dynamic items are added to a context menu by a context menu handler (described later in this article).

Static menu items are listed in the system registry and are automatically added to a context menu by the system. Because static items are listed in the system registry based on their class, the context menus for all file objects belonging to a particular class receive the same set of static items.

You specify static menu items for a file class by adding a shell key below the application identifier key of the file class and then adding verb and command value entries below the shell key. Following is the registry format for static items.

HKEY_CLASSES_ROOT

    <applicationID> = <"description">

        shell

            <verb> = <"menu-item text">

                command = <"command string">

Each verb value entry specifies a menu-item text string for the system to add to the context menu. The command value entry specifies the action that the system takes when the user chooses the menu item. Typically, the command string value specifies the path and filename of an application and includes command-line options that direct the application to perform an action on the corresponding file object. For example, the following registry keys add an Open command and a Print command to the context menu for all files with the .WRI filename extension.

HKEY_CLASSES_ROOT

  wrifile = Write Document

      shell

        open

          command = C:\Progra~1\Access~1\WORDPAD.EXE %1

            print

          command = C:\Progra~1\Access~1\WORDPAD.EXE /p "%1"

            printto

          command =

            C:\Progra~1\Access~1\WORDPAD.EXE /pt "%1" "%2" "%3" "%4"

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

The system defines a set of verbs called canonical verbs that introduce an element of language-independence to context menus. When you include a canonical verb in the registry, the system automatically generates a localized menu item string for the verb before adding it to the context menu. The canonical verbs include the open, print, explore, find, openas, and properties verbs. The printto verb is also canonical, but it is a special case because it is never actually displayed. Instead, it allows the user to print a file by dragging it to a printer object. Canonical verbs are also used with context menu handlers.

If the open canonical verb is included in the registry entries for a file class, the system adds an Open menu item to the corresponding context menu and makes it the default item. If the open verb is not included, the menu item corresponding to the verb listed in the registry is the default item. A context menu handler can change the default item. For more information about context menu handlers, see "Context Menu Handlers" later in this article.


Modifying the New Submenu

The File menu in a file system folder contains a New submenu that, by default, includes the Shortcut and Folder commands. These commands allow the user to create new shortcuts and folders within the current folder. The New submenu can also include other nondefault commands that let the user create new files of various types within the current folder, such as sound files, text files, and bitmap files. For example, the New submenu might include a Sound command that creates a .WAV file in the current folder.

If your application creates a type of file that the user may want to create from within a file system folder, you should consider adding a command for it to the New submenu. For example, suppose you have created a graphics application that creates files with the .XYZ filename extension. You could add a command, such as XYZ Picture, that creates a new .XYZ file or launches your application and opens a new .XYZ file for editing.

You add a command to the New submenu by including a ShellNew key below the file association key for your filetype. When the system needs to create the New submenu, it searches through the file association entries for instances of the ShellNew key. When it finds an instance of ShellNew, the system retrieves the string associated with the application identifier key (xyzfile) and adds the string to the New submenu as a new command. Note that an Open command must be registered below the application identifier key; otherwise, the system does not add the Open command to the New submenu.

The following example shows the registry entries needed to add the XYZ Picture command to the New submenu.

HKEY_CLASSES_ROOT
    .xyz="xyzfile"
        ShellNew

            NullFile=""

    .

    .

    .

    xyzfile="XYZ Picture"

        shell

            open

                command="C:\XYZ\XYZAPP.EXE %1

The data names for the ShellNew key specify the method to use to create a new file of the type designated by the filename extension. There are four possible data names and values for the ShellNew key.

Data name	Value	Description
NullFile	""	Creates an empty (null) file. If this data name is specified, Data and FileName are ignored.
Data	binary-value	Creates a file that contains the data specified by binary-value. This data name is ignored if either NullFile or FileName is specified.
FileName	path-name	Creates a copy of the file specified by path-name. This data name is ignored if NullFile is specified.
Command	path-name	Executes the command specified by path-name when the file is created. For example, the command might start a wizard.


Registering Shell Extensions

A shell extension must be registered in the Windows registry. The class identifier of each handler must be registered under the HKEY_CLASSES_ROOT\CLSID key. The CLSID key contains a list of class identifier key values, such as {00030000-0000-0000-C000-000000000046}. Each class identifier key is a globally unique identifier (GUID) generated by the UUIDGEN tool. Within each class identifier key, the handler adds an InProcServer32 key that gives the location of the handler's DLL. It is best to give the complete path for the handler; using the complete path keeps the handler independent of the current path and speeds up the load time for the DLL.

The information that the shell uses to associate a shell extension handler with a file type is stored under the shellex key. The shell also uses several other special keys under HKEY_CLASSES_ROOT to look for shell extensions: *, Folder, Drives, Printers, and keys for network providers. Descriptions of the keys follow:

•	You can use the * key to register handlers that the shell calls whenever it creates a context menu or property sheet for a file object in the following manner.

HKEY_CLASSES_ROOT

  * = *

    shellex

      ContextMenuHandlers

          {00000000-1111-2222-3333-00000000000001}

      PropertySheetHandlers

          {00000000-1111-2222-3333-00000000000002}

The shell uses instances of the ExtraMenu and SummaryInfo handlers to add to the context menus and property sheets for every file object.

•	You can use Folder key to register a shell extension for directories in the file system. You can register context menu handlers, copy hook handlers, and property sheet handlers in the same way you register these handlers for the * key. An additional handler, the drag and drop handler, applies only to the Folder and Printers keys. An example showing the Folder key follows.

Folder = Folder

  shellex

    DragDropHandlers

        {00000000-1111-2222-3333-00000000000004}

    CopyHookHandlers

        {00000000-1111-2222-3333-00000000000005}

•	You can use the Drives key for the same registrations as the Folder key, but the Drives key is called only for root paths (for example, C: \).

•	The Printers key allows the same registrations as the Folder key, but it uses additional handlers for printer events, deletion or removal of printers (through the copy hook handler), and printer properties (with property sheet handlers and context menu handlers).

To avoid conflicts with other classes, you must use real GUIDs, not the sample strings shown in the previous examples.


Debugging Tips

The shell automatically unloads a DLL when the DLL's usage count is zero, but only after the DLL has not been used for a period of time. The inactive period may be unacceptably long at times, especially when a shell extension DLL is being debugged. You can shorten the inactive period by adding the following information to the registry.

HKLM

    Software

        Microsoft

            Windows

                CurrentVersion

                    Explorer

                        AlwaysUnloadDll

AlwaysUnloadDll shortens the inactive period so that DLLs are unloaded quickly.

While debugging your extension, you may want to shut down the Windows 95 shell without closing the currently running applications. To do so, follow these steps:

1.	From the Start menu on the Windows taskbar, choose Shut Down.

2.	While holding down the CTRL+ALT+SHIFT key combination, click the No button in the Shut Down Windows dialog box.


How the Shell Accesses Shell Extension Handlers

The shell uses two interfaces to initialize instances (objects created by IClassFactory::CreateInstance) of shell extensions: IShellExtInit and IPersistFile. The shell uses the IShellExtInit interface to initialize instances of context menu handlers, drag and drop handlers, and property sheet handlers. The shell uses IPersistFile to initialize instances of icon handlers, data handlers, and drop handlers. This interface is defined by OLE.

The IShellExtInit interface adds an additional member function, Initialize, to the standard IUnknown interface. A handler's Initialize function should keep a copy of the parameters that the shell passes to the function for later use. An example showing how to initialize instances follows.

STDMETHODIMP CShellExt::Initialize(LPCITEMIDLIST pIDFolder,
    LPDATAOBJECT pDataObj, HKEY hRegKey)

{

    // Initialize can be called more than once.

    if (m_pDataObj)

        m_pDataObj->Release();

    // Save the object pointer.

    if (pDataObj) {

        m_pDataObj = pDataObj;

        pDataObj->AddRef();

    }

    // Duplicate the registry handle.

    if (hRegKey)

        RegOpenKeyEx(hRegKey, NULL, 0L, MAXIMUM_ALLOWED,

            &this->hRegKey);

    return NOERROR;

}

A shell extension handler must implement three functions: an entrypoint function (often called DllMain or LibMain), DllCanUnloadNow, and DllGetClassObject.

DllCanUnloadNow and DllGetClassObject are essentially the same as they would be for any OLE in-process server DLL. The use of DllCanUnloadNow is shown in the following example.

STDAPI DllCanUnloadNow(void)

{

    // g_cRefThisDll must be placed in the instance-specifc
    // data section.

    return ResultFromScode((g_cRefThisDll==0) ? S_OK : S_FALSE);

}

DllGetClassObject needs to expose the class factory for the object in the DLL. For more information about exposing the class factory, see the OLE documentation included in the Microsoft® Win32® Software Development Kit (SDK). The following example shows how to expose the class factory.

// DllGetClassObject - a DLL entrypoint function used by
// most in-process server DLLs.

STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppvOut)

{

    *ppvOut = NULL; // assume failure

    if (IsEqualIID(rclsid, CLSID_ShellExtension)) {

        return CShellExtSample_Create(riid, ppvOut);

    } else {

        return CLASS_E_CLASSNOTAVAILABLE;

    }

}


Context Menu Handlers

A context menu handler is a shell extension that adds menu items to any of the shell's context menus. There are two types of context menu handlers. Each type has a different purpose, but the same implementation. Context menu extensions are used when the user clicks a file object by using mouse button 2, and drag and drop handlers are used when the user drags a file object using mouse button 2. This section describes the types of context menu handlers, how they are used, how they are added to the registry, and the interfaces that they must implement.


Context Menu Extensions

When the user clicks mouse button 2 on an item within the shell's namespace (that is, file, directory, server, work group, and so on), it creates the default context menu for the type of item and then loads context menu extensions that are registered for the type (and its base type) so that they can add extra menu items. The context menu extensions are registered at the following location.

HKCR\{ProgID}\shellex\ContextMenuHandlers


IContextMenu Interface

An application implements a context menu handler interface, IContextMenu, to add menu items to the context menu for a file object. The shell displays the object's context menu when the user clicks the object with mouse button 2. The menu items can be either class-specific (that is, applicable to all files of a particular type) or instance-specific (that is, applicable to an individual file).

When the user clicks a file object by using mouse button 2, the system passes the address of the object's context menu to the context menu handler, which should use the handle only to add items to the menu. The handler should not delete or modify existing menu items, because other handlers may add items either before or after it does. In addition, the shell adds items to the menu after all context menu handlers have been called.

Context menu handlers are entered in the registry under the shellex key within an application's information area. The ContextMenuHandlers key lists the names of subkeys that contain the CLSID of each context menu handler. An example showing the ContextMenuHandlers key follows.

ContextMenuHandlers

    {00000000-1111-2222-3333-00000000000001}

You can register multiple context menu handlers for a file type.

In addition to the standard IUnknown member functions, the context menu handler interface uses the QueryContextMenu, InvokeCommand, and GetCommandString member functions.

When the user selects one of the menu items added by a context menu handler, the shell calls the handler's IContextMenu::InvokeCommand member function to let the handler process the command. If multiple context menu handlers are registered for a file type, the value of the ContextMenuHandlers key determines the order of the commands.

When the system is about to display a context menu (or the File menu on the menu bar) for a file object, the system calls the context menu handler's QueryContextMenu member function. The context menu handler inserts menu items by position (MF_POSITION) directly into the context menu by calling the InsertMenu function. The following example shows that menu items must be string items (MF_STRING).

STDMETHODIMP CShellExt::QueryContextMenu(HMENU hMenu,

    UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)

{

    UINT idCmd = idCmdFirst;

    char szMenuText[64];

    char szMenuText2[64];

    char szMenuText3[64];

    char szMenuText4[64];

    BOOL bAppendItems=TRUE;

    if ((uFlags & 0x000F) == CMF_NORMAL) {

        lstrcpy(szMenuText, "&New .GAK menu 1, Normal File");

        lstrcpy(szMenuText2, "&New .GAK menu 2, Normal File");

        lstrcpy(szMenuText3, "&New .GAK menu 3, Normal File");

        lstrcpy(szMenuText4, "&New .GAK menu 4, Normal File");

    } else if (uFlags & CMF_VERBSONLY) {

        lstrcpy(szMenuText, "&New .GAK menu 1, Shortcut File");

        lstrcpy(szMenuText2, "N&ew .GAK menu 2, Shortcut File");

        lstrcpy(szMenuText3, "&New .GAK menu 3, Shortcut File");

        lstrcpy(szMenuText4, "&New .GAK menu 4, Shortcut File");

    } else if (uFlags & CMF_EXPLORE) {

        lstrcpy(szMenuText, "&New .GAK menu 1,

            Normal File right click in Explorer");

        lstrcpy(szMenuText2, "N&ew .GAK menu 2,

            Normal File right click in Explorer");

        lstrcpy(szMenuText3, "&New .GAK menu 3,

            Normal File right click in Explorer");

        lstrcpy(szMenuText4, "&New .GAK menu 4,

            Normal File right click in Explorer");

    } else if (uFlags & CMF_DEFAULTONLY) {

        bAppendItems = FALSE;

    } else {

        char szTemp[32];

       bAppendItems = FALSE;

    }

    if (bAppendItems) {

        InsertMenu(hMenu, indexMenu++, MF_SEPARATOR | MF_BYPOSITION,

            0, NULL);

        InsertMenu(hMenu, indexMenu++, MF_STRING | MF_BYPOSITION,

            idCmd++, szMenuText);

        InsertMenu(hMenu, indexMenu++, MF_SEPARATOR | MF_BYPOSITION,

            0, NULL);

        InsertMenu(hMenu, indexMenu++, MF_STRING | MF_BYPOSITION,

            idCmd++, szMenuText2);

        InsertMenu(hMenu, indexMenu++, MF_SEPARATOR | MF_BYPOSITION,

            0, NULL);

        InsertMenu(hMenu, indexMenu++, MF_STRING | MF_BYPOSITION,

            idCmd++, szMenuText3);

        InsertMenu(hMenu, indexMenu++, MF_STRING | MF_BYPOSITION,

            idCmd++, szMenuText4);

        // Must return the number of menu items added.

        return ResultFromShort(idCmd-idCmdFirst);

    }

    return NOERROR;

}

The system calls the InvokeCommand member function when the user selects a menu item that the context menu handler added to the context menu. The InvokeCommand function in the following example handles the commands associated with the menu items added by the previous example.

STDMETHODIMP CShellExt::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi)

{

    HRESULT hr = E_INVALIDARG;

    // If the high-order word of lpcmi->lpVerb is not NULL, this

    // function was called by an application and lpVerb is a command

    // that should be activated. Otherwise, the shell has called this

    // function, and the low-order word of lpcmi->lpVerb is the

    // identifier of the menu item that the user selected.

    if (!HIWORD(lpcmi->lpVerb)) {

        UINT idCmd = LOWORD(lpcmi->lpVerb);

        switch (idCmd) {

            case 0:

                hr = DoGAKMenu1(lpcmi->hwnd, lpcmi->lpDirectory,

                    lpcmi->lpVerb, lpcmi->lpParameters, lpcmi->nShow);

                break;

            case 1:

                hr = DoGAKMenu2(lpcmi->hwnd, lpcmi->lpDirectory,

                    lpcmi->lpVerb, lpcmi->lpParameters, lpcmi->nShow);

                break;

            case 2:

                hr = DoGAKMenu3(lpcmi->hwnd, lpcmi->lpDirectory,

                    lpcmi->lpVerb, lpcmi->lpParameters, lpcmi->nShow);

                break;

            case 3:

                hr = DoGAKMenu4(lpcmi->hwnd, lpcmi->lpDirectory,

                    lpcmi->lpVerb, lpcmi->lpParameters, lpcmi->nShow);

                break;

        }

    }

    return hr;

}

Windows calls the GetCommandString member function to get a language-independent command string or the help text for a context menu item.


Drag and Drop Handlers

Drag and drop handlers implement the IContextMenu interface. In fact, a drag and drop handler is simply a context menu handler affecting the menu that the shell displays when a user drags and drops a file object with mouse button 2. Because this menu is called the drag and drop menu, shell extensions that add items to this menu are called drag and drop handlers. Drag and drop handlers work the same way as context menu handlers.

Note that drag and drop handlers are registered under the key of folder types (typically the Directory key). To change the behavior of the dragged object (IDataObject), you need to implement a data handler.


Icon Handlers

An application can customize the icons that the shell displays for the application's file types. The icon interface also allows an application to specify icons for folders and subfolders within the application's file structure.

An application can specify icons for its file types in two ways. The simplest way is to specify a class icon to be used for all files of a particular file type by adding a DefaultIcon key to the registry under the program information. For information about specifying a class icon, see "Setting Default Icons for File Classes" earlier in this article.

An application can use the %1 value with the DefaultIcon key. This value denotes that each file instance of this type can have a different icon. The application must supply an icon handler for the file type and add an IconHandler key to the shellex key for the application. An application can have only one entry for the IconHandler key, and the value of its key denotes the CLSID of the icon handler.

shellex

    IconHandler

        {00000000-1111-2222-3333-00000000000003}

DefaultIcon = %1

To have customized icons, an application must provide an icon handler that implements the IExtractIcon interface. The system follows these steps when it is about to display an icon for a file type that has instance-specific icons:

1.	Retrieves the class identifier of the handler.

2.	Creates a handler object by calling the CoCreateInstance function with the CLSID.

3.	Initializes the instance by calling the IPersistFile::Load member function.

4.	Uses the QueryInterface member function to get to the IExtractIcon interface.

5.	Calls the IExtractIcon::GetIconLocation and IExtractIcon::Extract member functions.

The IExtractIcon interface has the Extract and GetIconLocation member functions in addition to the usual IUnknown member functions.

The system calls the GetIconLocation member function to get the location and index of an icon to display. Typically, the icon location is an executable or DLL filename, but it can be any file.

The system calls the Extract member function when it needs to display an icon for a file that does not reside in an executable or DLL file. Applications usually have the file icons in their executable or DLL files, so icon handlers can simply implement this member function as a return-only function that returns the E_FAIL error value. You need to implement the Extract member function only if the icon image is stored in a file in an application-defined format. When the icon for a file is in a separate .ICO file (or any other type of file), the icon handler must extract the icon for the shell and return it in this member function.


Property Sheet Handlers

Another way the shell can be extended is by custom property sheets. When the user selects the properties for a file, the shell displays a standard property sheet. If the registered file type has a property sheet handler, the shell allows the user to access additional sheets that the handler provides. Property sheet handlers implement the IShellPropSheetExt interface.

Property sheet handlers are entered in the registry under the shellex key within an application's information area. The PropertySheetHandlers key lists the names of subkeys that contain the class identifier of each context menu handler, as shown in the following example.

PropertySheetHandlers

    {00000000-1111-2222-3333-00000000000002}

You can register multiple property sheet handlers for a file type. In this case, the order of the subkey names in the PropertySheetHandlers key determines the order of the additional property sheets. You can use a maximum of 24 (the value of MAXPROPPAGES) pages in a property sheet.


Adding Property Sheet Pages

The property sheet handler uses the AddPages member function in addition to the usual IUnknown member functions. The system calls the AddPages member function when it is about to display a property sheet. The system calls each property sheet handler registered to the file type to allow the handlers to add pages to the property sheets. The following example shows how to implement the AddPages member function.

STDMETHODIMP CSamplePageExt::AddPages(LPFNADDPROPSHEETPAGE lpfnAddPage,

    LPARAM lParam)

{

    PROPSHEETPAGE psp;

    HPROPSHEETPAGE hpage;

    psp.dwSize      = sizeof(psp);   // no extra data

    psp.dwFlags     = PSP_USEREFPARENT | PSP_USERELEASEFUNC;

    psp.hInstance   = (HINSTANCE)g_hmodThisDll;

    psp.pszTemplate = MAKEINTRESOURCE(DLG_FSPAGE);

    psp.pfnDlgProc  = FSPage_DlgProc;

    psp.pcRefParent = &g_cRefThisDll;

    psp.pfnRelease  = FSPage_ReleasePage;

    psp.lParam      = (LPARAM)hdrop;

    hpage = CreatePropertySheetPage(&psp);

    if (hpage) {

        if (!lpfnAddPage(hpage, lParam))

            DestroyPropertySheetPage(hpage);

    }

    return NOERROR;

}


Replacing Control Panel Pages

The ReplacePage member function is called only by Control Panel applications. It allows you to replace the property sheet of a standard Control Panel application with a custom page. For example, if a mouse manufacturer adds extra buttons to its mouse, the manufacturer can replace the standard Mouse Control Panel's "Buttons" property sheet page. The ReplacePage member function is not called by the shell because the shell does not have any property sheet pages that can be replaced by a shell extension. Currently, only Control Panel applications call this member function, but other property sheet suppliers could use this member function to allow their property sheet pages to be replaced.

Each property sheet handler that allows a property sheet page to be replaced must specify the registry location where other handlers that replace pages register themselves. For standard Control Panel applications, this location is defined by the REGSTR_PATH_CONTROLSFOLDER macro in the REGSTR.H file. The macro defines the key under the HKEY_LOCAL_MACHINE key in which all Control Panel property sheet page replacement handlers must register. For example, a property sheet handler that needs to replace a property sheet page for the  Mouse Control Panel would register a property sheet extension handler in the following registry location.

HKEY_LOCAL_MACHINE

  REGSTR_PATH_CONTROLSFOLDER

    Mouse

      shellex

        PropertySheetHandlers = NewMousePage

            NewMousePage = {00000000-1111-2222-3333-00000000000002}

In addition, a property sheet handler that allows replaceable pages must define identifiers for each page that can be replaced.

Standard Control Panel applications define this location in the REGSTR.H and CPLEXT.H header files. In REGSTR.H, the REGSTR_PATH_CONTROLSFOLDER macro defines the key under the HKEY_LOCAL_MACHINE key in which all Control Panel property sheet page replacement handlers must register. CPLEXT.H defines the subkey for each Control Panel application that contains a replacable property sheet page: \Mouse for a Mouse Control Panel application and \Keyboard for a Keyboard Control Panel application.

Standard Control Panel applications define these identifiers in CPLEXT.H. For example, CPLPAGE_MOUSE_BUTTONS defines the identifier for the Mouse Control Panel's Buttons page, and CPLPAGE_KEYBOARD_SPEED defines the identifier for the Keyboard Control Panel's Speed page.


Copy Hook Handlers

A copy hook handler is a shell extension that the shell calls before copying, moving, deleting, or renaming a folder object. The copy hook handler does not perform the task itself, but the handler provides approval for the task. When the shell receives approval from the copy hook handler, it performs the actual file system operation (that is, copies, moves, deletes, or renames). Copy hook handlers are not informed about the success of the operation, so they cannot monitor actions that occur to folder objects.

The shell initializes the copy hook handler interface directly — that is, without using an IShellExtInit or IPersistFile interface first. A folder object can have multiple copy hook handlers. The copy hook handler interface has one member function, CopyCallBack, in addition to the standard IUnknown member functions.

The shell calls the CopyCallBack member function before it copies, moves, deletes, or renames a folder object. The function returns an integer value that indicates whether the shell should perform the operation. The shell will call each copy hook handler registered for a folder object until either all the handlers have been called or any handler returns the IDCANCEL value. The handler can also return the IDYES value to specify that the operation should be carried out or the IDNO value to specify that the operation should not be performed.


Data Handlers

When a file is dragged from the shell (or copied to the clipboard from the shell), the shell creates a default IDataObject interface that supports standard clipboard formats (CF_HDROP, "Shell IDList Array", and so on). An application can add more clipboard formats by providing a data handler for the file type. A data handler must support both the IPersistFile and IDataObject interfaces. The shell initializes a data handler by calling the IPersistFile::Load member function. When a data handler is provided, the default IDataObject interface delegates some member function calls to the data handler so that the additional clipboard data formats become available to the drop target.

You register a data handler by adding a DataHandler key and class identifier for the handler under the shellex key for the file type as shown in the following example.

shellex

    DataHandler = {00000000-1111-2222-3333-00000000000003}


Drop Handlers

By default, a file is not a drop target. By providing a drop handler for the file types created by your application, you can make the files into drop targets. A drop handler must support both the IPersistFile and IDropTarget interfaces. The shell initializes a drop handler by calling the IPersistFile::Load member function. When the user drags an object over one of your application's files or drops an object onto one of its files, the system calls the appropriate member functions of the IDropTarget interface.

You register a drop handler by adding a DropHandler key and class identifier for the handler under the shellex key for the file type as shown in the followng example.

shellex

    DropHandler = {00000000-1111-2222-3333-00000000000003}


Reference

The following interfaces, member functions, and structures are associated with shell extensions.


Interfaces and Member Functions


IContextMenu [New - Windows 95]
IContextMenu

[New - Windows 95]

Designates an interface that enables the shell to retrieve extensions to context menus. The IContextMenu interface has the following member functions.

GetCommandString	Retrieves the language-independent name of a menu command or the help text for a menu command.
InvokeCommand	Carries out a menu command, either in response to user input or otherwise.
QueryContextMenu	Adds commands to a context menu.
Like all OLE interfaces, IContextMenu also includes the QueryInterface, AddRef, and Release member functions.


IContextMenu::GetCommandString [New - Windows 95]
IContextMenu::GetCommandString

[New - Windows 95]

HRESULT IContextMenu::GetCommandString(
    LPCONTEXTMENU pIface, UINT idCmd, UINT uFlags,
    UINT *pwReserved, LPSTR pszName, UINT cchMax);

Retrieves the language-independent command string or the help text for a context menu item.

•	Returns the NOERROR value if successful or an OLE-defined error code otherwise.

pIface

Address of the IContextMenu interface. In C++, this parameter is implicit.

idCmd

Menu item identifier offset.

uFlags

Flag specifying the information to retrieve. This parameter can be one of these values:

GCS_HELPTEXT	Returns the help text for the menu item.
GCS_VALIDATE	Validates that the menu item exists.
GCS_VERB	Returns the language-independent command name for the menu item.
pwReserved

Reserved. Applications must specify NULL when calling this member function, and handles must ignore this parameter when called.

pszName and cchMax

Address and size of the buffer that receives the null-terminated string.

The language-independent command name is a name that can be passed to the IContextMenu::InvokeCommand member function to activate a command by an application. The help text is a description that Explorer displays in its status bar; it should be reasonably short (under 40 characters).


IContextMenu::InvokeCommand [New - Windows 95]
IContextMenu::InvokeCommand

[New - Windows 95]

HRESULT IContextMenu::InvokeCommand(
    LPCONTEXTMENU pIface, LPCMINVOKECOMMANDINFO lpici);

Carries out the command associated with a context menu item.

•	Returns the NOERROR value if successful or an OLE-defined error code otherwise.

pIface

Address of the IContextMenu interface. In C++, this parameter is implicit.

lpici

Address of a CMINVOKECOMMANDINFO structure containing information about the command.

The shell calls this member function when the user chooses a command that the handler added to a context menu. This member function may also be called by an application without any corresponding user action.


IContextMenu::QueryContextMenu [New - Windows 95]
IContextMenu::QueryContextMenu

[New - Windows 95]

HRESULT IContextMenu::QueryContextMenu(

    LPCONTEXTMENU pIface, HMENU hmenu, UINT indexMenu,

    UINT idCmdFirst, UINT idCmdLast, UINT uFlags

    );

Adds menu items to the specified menu. The menu items should be inserted at a given position in the menu, and their menu item identifiers must be in a given range.

•	Returns an HRESULT structure in which, if successful, the code member contains the menu identifier offset of the last menu item added.

pIface

Address of the IContextMenu interface. In C++, this parameter is implicit.

hmenu

Handle of the menu. The handler should specify this handle when calling the InsertMenu or InsertMenuItem function.

indexMenu

Zero-based position at which to insert the first menu item.

idCmdFirst and idCmdLast

Minimum and maximum values that the handler can specify for menu item identifiers. The actual identifier of each menu item should be idCmdFirst plus a menu identifier offset in the range zero through (idCmdLast − idCmdFirst).

uFlags

Flag specifying zero or more of these values:

CMF_DEFAULTONLY	The user is activating the default action, typically by double-clicking. A context menu extension or drag and drop handler should not add any menu items if this value is specified. A namespace extension should add only the default item, if any.
CMF_EXPLORE	Context menu handlers should ignore this value. This value is specified if the context menu is for an object in the left pane of the explorer.
CMF_NORMAL	Indicates normal operation. A context menu extension, namespace extension, or drag and drop handler can add any menu items.
CMF_VERBSONLY	Context menu handlers should ignore this value. This value is specified if the context menu is for a shortcut object.
The remaining bits of the low-order word are reserved by the system. The high-order word may be used for context-specific communications.

An extension must not modify other menu items or insert menu items at a location other than that specified by indexMenu. Such an extension will not work in a future version of the Windows operating system.


ICopyHook [New - Windows 95]
ICopyHook

[New - Windows 95]

Designates an interface that allows a copy hook handler to prevent a folder or printer object from being copied, moved, deleted, or renamed. The shell calls a copy hook handler whenever file system directories are about to be copied, moved, deleted, or renamed and whenever the status of a printer is about to change.

The shell creates the copy hook handler interface directly — that is, without using the IShellExtInit or IPersistFile interface first. A folder object can have multiple copy hook handlers.

A copy hook handler interface has one member function, CopyCallBack, in addi-tion to the standard QueryInterface, AddRef, and Release member functions.


ICopyHook::CopyCallback [New - Windows 95]
ICopyHook::CopyCallback

[New - Windows 95]

UINT CopyCallback(ICopyHook FAR * pCopyHook,
    HWND hwnd, UINT wFunc, UINT wFlags, LPCSTR pszSrcFile,
    DWORD dwSrcAttribs, LPCSTR pszDestFile, DWORD dwDestAttribs);

Either allows the shell to carry out a copy, move, delete, or rename operation on a folder object, or prevents the shell from carrying out the operation. The shell calls each copy hook handler registered for a folder object until either all the handlers have been called or any handler returns the IDCANCEL value.

•	Returns an integer value that indicates whether the shell should perform the operation. It can be one of the following values:

IDCANCEL	Prevents the current operation and cancels any pending operations.
IDNO	Prevents the operation on this folder, but continues with any other operations (for example, a batch copy operation).
IDYES	Allows the operation.
pCopyHook

Address of the ICopyHook interface. In C++, this parameter is implicit.

hwnd

Handle of the window that the copy hook handler should use as the parent window for any user interface elements the handler may need to display. If the FOF_SILENT value is specified, the member function should ignore this parameter.

wFunc

Operation to perform. This parameter can be one of these values:

FO_COPY	Copies the file specified by pszSrcFile to the location specified by pszDestFile.
FO_DELETE	Deletes the file specified by pszSrcFile.
FO_MOVE	Moves the file specified by pszSrcFile to the location specified by pszDestFile.
FO_RENAME	Renames the file specified by pszSrcFile.
PO_DELETE	Deletes the printer specified by pszSrcFile.
PO_PORTCHANGE	Changes the printer port. pszSrcFile and pszDestFile contain double-null terminated lists of strings. Each list contains the printer name followed by the port name. The port name in pszSrcFile is the current printer port, and the port name in pszDestFile is the new printer port.
PO_RENAME	Renames the printer specified by pszSrcFile.
PO_REN_PORT	Combination of PO_RENAME and PO_PORTCHANGE.
wFlags

Flags that control the operation. This parameter can be a combination of these values:

FOF_ALLOWUNDO	Preserves undo information, if possible.
FOF_CONFIRMMOUSE	Not implemented.
FOF_FILESONLY	Not implemented. The shell calls a copy hook handler only for folder objects, not files.
FOF_MULTIDESTFILES	Indicates that the SHFileOperation function specifies multiple destination files (one for each source file) rather than one directory where all the source files are to be deposited. A copy hook handler typically ignores this value.
FOF_NOCONFIRMATION	Responds with "yes to all" for any dialog box that is displayed.
FOF_NOCONFIRMMKDIR	Does not confirm the creation of any needed directories if the operation requires a new directory to be created.
FOF_RENAMEONCOLLISION	Gives the file being operated on a new name (such as, "Copy #1 of ...") in a copy, move, or rename operation if a file of the target name already exists.
FOF_SILENT	Displays no progress dialog box.
FOF_SIMPLEPROGRESS	Displays a progress dialog box, but the dialog box does not show the names of the files.
pszSrcFile

Address of a string that contains the name of the source file.

dwSrcAttribs

Attributes of the source file. This parameter can be a combination of any of the file attribute (FILE_ATTRIBUTE_) flags defined in the Windows header files.

pszDestFile

Address of a string that contains the name of the destination file.

dwDestAttribs

Attributes of the source file. This parameter can be a combination of any of the file attribute (FILE_ATTRIBUTE_) flags defined in the Windows header files.


IExtractIcon [New - Windows 95]
IExtractIcon

[New - Windows 95]

Designates an interface that enables the shell to retrieve icons for file objects. The IExtractIcon interface has the following member functions.

GetIconLocation	Retrieves the icon location for a file object.
Extract	Extracts an icon from the specified location.
Like all OLE interfaces, IExtractIcon also includes the QueryInterface, AddRef, and Release member functions.


IExtractIcon::GetIconLocation [New - Windows 95]
IExtractIcon::GetIconLocation

[New - Windows 95]

HRESULT IExtractIcon::GetIconLocation(

    LPEXTRACTICON pIface, UINT uFlags, LPSTR szIconFile,

    UINT cchMax, int *piIndex, UINT *pwFlags

    );

Retrieves the location and index of an icon.

•	Returns the NOERROR value if the function returned a valid location or the S_FALSE value if the shell should use a default icon.

pIface

Address of the IExtractIcon interface. In C++, this parameter is implicit.

uFlags

Flags. This parameter can be zero or these values:

GIL_FORSHELL	The icon is to be displayed in a shell folder.
GIL_OPENICON	The icon is for a folder that is open.
szIconFile and cchMax

Address and size of the buffer that receives the icon location. The icon location is a null-terminated string that typically specifies the name of an icon file.

piIndex

Address of an integer that receives the icon index.

pwFlags

Address of an unsigned integer that receives zero or more of these values:

GIL_DONTCACHE	The shell should use the Extract member function rather than look up the icon in its internal cache.
GIL_NOTFILENAME	The location is not a filename. Instead, it is an extension-specific string that identifies the icon. The caller must use the Extract member function to retrieve the icon image no matter what flags are returned.
GIL_PERCLASS	All file objects of this class have the same icon.
GIL_PERINSTANCE	Each file object of this class has its own icon.
GIL_SIMULATEDOC	The shell should create a document icon using the specified icon.


IExtractIcon::Extract [New - Windows 95]
IExtractIcon::Extract

[New - Windows 95]

HRESULT IExtractIcon::Extract(

    LPEXTRACTICON pIface, LPCSTR pszFile, UINT nIconIndex,

    HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize

    );

Extracts an icon image from the specified location.

•	Returns the NOERROR value if the function extracted the icon or the S_FALSE value if the calling application should extract the icon by calling the ExtractIcon function.

pIface

Address of the IExtractIcon interface. In C++, this parameter is implicit.

pszFile

Address of a null-terminated string specifying the icon location. This parameter must be a string returned by the GetIconLocation member function.

nIconIndex

Icon index.

phiconLarge and phiconSmall

Addresses of variables that receive the handles of the large and small icons, respectively.

nIconSize

Value specifying the size, in pixels, of the large icon required. The size specified can be the width or height. The width of an icon always equals its height.

The icon location and index are the same values as returned by the IExtractIcon::GetIconLocation member function. If this function returns S_FALSE, these values must specify an icon filename and index. If this function does not return S_FALSE, the calling application should make no assumptions about the meanings of the pszFile and nIconIndex parameters.


IShellPropSheetExt [New - Windows 95]
IShellPropSheetExt

[New - Windows 95]

Designates an interface that allows a property sheet handler to add or replace pages in the property sheet for a file object. The IShellPropSheetExt interface has the following member functions.

AddPages	Adds one or more pages to a property sheet for a file object.
ReplacePage	Replaces a page in a property sheet for a Control Panel object.
Like all OLE interfaces, IShellPropSheetExt also includes the QueryInterface, AddRef, and Release member functions.


IShellPropSheetExt::AddPages [New - Windows 95]
IShellPropSheetExt::AddPages

[New - Windows 95]

HRESULT AddPages(IShellPropSheetExt FAR * pProp,
    LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam);

Adds one or more pages to a property sheet that the shell displays for a file object. When it is about to display the property sheet, the shell calls the AddPages member function of each property sheet handler registered to the file type.

•	Returns the NOERROR value if successful or an OLE-defined error value otherwise.

pProp

Address of the IShellPropSheetExt interface. In C++, this parameter is implicit.

lpfnAddPage

Address of a callback function that the property sheet handler calls to add a page to the property sheet. The function takes a property sheet handle returned by the CreatePropertySheetPage function and the lParam parameter passed to the AddPages member function. For more information about the callback function, see the description of the AddPropSheetPageProc function in the documentation included with the Win32 Software Development Kit (SDK).

lParam

Parameter to pass to the function pointed to by lpfnAddPage.

For each page it needs to add to a property sheet, a property sheet handler fills a PROPSHEETPAGE structure, calls CreatePropertySheetPage, and then calls the function pointed to by lpfnAddPage.


IShellPropSheetExt::ReplacePage [New - Windows 95]
IShellPropSheetExt::ReplacePage

[New - Windows 95]

HRESULT ReplacePage(IShellPropSheetExt FAR * pProp,
    UINT uPageID, LPFNADDPROPSHEETPAGE lpfnReplacePage, LPARAM lParam);

Replaces a page in a property sheet for a Control Panel object.

•	Returns the NOERROR value if successful or an OLE-defined error value otherwise.

pProp

Address of the IShellPropSheetExt interface. In C++, this parameter is implicit.

uPageID

Identifier of the page to replace. The values for this parameter for Control Panels can be found in CPLEXT.H.

lpfnReplacePage

Address of a function that the property sheet handler calls to replace a page to the property sheet. The function takes a property sheet handle returned by the CreatePropertySheetPage function and the lParam parameter passed to the ReplacePage member function.

lParam

Parameter to pass to the function pointed to by lpfnReplacePage.

To replace a page, a property sheet handler fills a PROPSHEETPAGE structure, calls CreatePropertySheetPage, and then calls the function pointed to by lpfnReplacePage.


IShellExtInit [New - Windows 95]
IShellExtInit

[New - Windows 95]

Designates an interface used to initialize a property sheet extension, context menu extension, or drag and drop handler. The IShellExtInit interface has the following member functions.

Initialize	Initializes the shell extension.
Like all OLE interfaces, IShellExtInit also includes the QueryInterface, AddRef, and Release member functions.


IShellExtInit::Initialize [New - Windows 95]
IShellExtInit::Initialize

[New - Windows 95]

HRESULT IShellExtInit::Initialize(

    LPSHELLEXTINIT pIface, LPCITEMIDLIST pidlFolder,

    LPDATAOBJECT lpdobj, HKEY hkeyProgID

    );

Initializes a property sheet extension, context menu extension, or drag and drop handler.

•	Returns the NOERROR value if successful or an OLE-defined error value otherwise.

pIface

Address of the IShellExtInit interface. In C++, this parameter is implicit.

pidlFolder

Address of an ITEMIDLIST structure (item identifier list) that uniquely identifies a folder. This parameter is NULL for property sheet extensions and context menu extensions. For nondefault drag and drop menu extensions, this parameter must specify the target folder.

lpdobj

Address of an IDataObject interface object that can be used to retrieve the objects being acted upon.

hkeyProgID

Registry key for the file object or folder type.

This is the first member function that the shell calls (besides AddRef, Release, and QueryInterface) after it creates an instance of a property sheet extension, context menu extension, or drag and drop handler.

The meanings of some parameters depend on the extension type. For drag and drop handlers, the item identifier list specifies the destination folder (the drop target), the IDataObject interface identifies the items being dropped, and the registry key specifies the file class of the destination folder (typically "Directory").

For property sheet extensions and context menu extensions, the item identifier list specifies the folder that contains the selected file objects, the IDataObject interface identifies the selected file objects, and the registry key specifies the file class of the file object that has the focus.


Structures

The following structures are used with shell extensions.


CMINVOKECOMMANDINFO [New - Windows 95]
CMINVOKECOMMANDINFO

[New - Windows 95]

typedef struct _CMInvokeCommandInfo {

    DWORD cbSize;        // sizeof(CMINVOKECOMMANDINFO)

    DWORD fMask;         // see below

    HWND hwnd;           // see below

    LPCSTR lpVerb;       // see below

    LPCSTR lpParameters; // see below

    LPCSTR lpDirectory;  // see below

    int nShow;           // see below

    DWORD dwHotKey;      // see below

    HANDLE hIcon;        // see below

} CMINVOKECOMMANDINFO, *LPCMINVOKECOMMANDINFO;

Contains information about a context menu command.

fMask

Value specifying zero or more of these flags:

CMIC_MASK_HOTKEY	Specifies that dwHotKey is valid.
CMIC_MASK_ICON	Specifies that hIcon is valid.
CMIC_MASK_FLAG_NO_UI	Prevents the system from displaying user interface elements (for example, error messages) while carrying out a command.
hwnd

Handle of the window that owned the context menu, such as the desktop, Explorer, or the tray. An extension might specify this handle as the owner window of any message boxes or dialog boxes that it displays.

lpVerb

32-bit value containing zero in the high-order word and the menu-identifier offset of the command to carry out in the low-order word. The shell specifies this value (using the MAKEINTRESOURCE macro) when the user chooses a menu command.

If the high-order word is not zero, this member is the address of a null-terminated string specifying the language-independent name of the command to carry out. This member is typically a string when a command is being activated by an application. The system provides predefined constant values for the following command strings:

Value	String
CMDSTR_NEWFOLDER	"NewFolder"
CMDSTR_VIEWDETAIL	"ViewDetails"
CMDSTR_VIEWLIST	"ViewList"
lpParameters

Optional parameters. This member is always NULL for menu items inserted by a shell extension.

lpDirectory

Optional working directory name. This member is always NULL for menu items inserted by a shell extension.

nShow

Flag to pass to the ShowWindow function if the command displays a window or starts an application.

dwHotKey

Optional hot key to assign any application activated by the command. If fMask does not specify CMIC_MASK_HOTKEY, this member is ignored. A shell extension should ignore this member.

hIcon

Icon to use for any application activated by the command. If fMask does not specify CMIC_MASK_ICON, this member is ignored. A shell extension should ignore this member.

The address of this structure is passed to the IContextMenu::InvokeCommand member function.


ITEMIDLIST [New - Windows 95]
ITEMIDLIST

[New - Windows 95]

typedef struct _ITEMIDLIST { // idl

    SHITEMID mkid;  // list of item identifers

} ITEMIDLIST, * LPITEMIDLIST;

typedef const ITEMIDLIST * LPCITEMIDLIST;

Contains a list of item identifiers. For more information, see Article 11, "Shell's Namespace."


SHITEMID [New - Windows 95]
SHITEMID

[New - Windows 95]

typedef struct _SHITEMID {       // mkid

    USHORT cb;       // size of identifier, including cb itself

    BYTE   abID[1];  // variable-length item identifier

} SHITEMID, * LPSHITEMID;

typedef const SHITEMID  * LPCSHITEMID;

Defines an item identifier.


Application Desktop Toolbars

An application desktop toolbar (also called an appbar) is a window that is similar to the Microsoft® Windows® taskbar. It is anchored to an edge of the screen, and it typically contains buttons that give the user quick access to other applications and windows. The system prevents other applications from using the desktop area occupied by an appbar. Any number of appbars can exist on the desktop at any given time.


About Application Desktop Toolbars

Windows provides an application programming interface (API) that lets you take advantage of appbar services provided by the system. The services help ensure that application-defined appbars operate smoothly with one another and with the taskbar. The system maintains information about each appbar and sends the appbars messages to notify them about events that can effect their size, position, and appearance.


Sending Messages

An application uses a special set of messages, called appbar messages, to add or remove an appbar, set an appbar's size and position, and retrieve information about the size, position, and state of the taskbar. To send an appbar message, an application must use the SHAppBarMessage function. The function's parameters include a message identifier, such as ABM_NEW, and the address of an APPBARDATA structure. The structure members contain information that the system needs to process the given message.

For any given appbar message, the system uses some members of the APPBARDATA structure and ignores the others. However, because the system always uses the cbSize and hWnd members, an application must fill these members for every appbar message. The cbSize member specifies the size of the structure, and the hWnd member is the handle of the appbar's window.

Some appbar messages request information from the system. When processing these messages, the system copies the requested information into the APPBARDATA structure.


Registration

The system keeps an internal list of appbars and maintains information about each bar in the list. The system uses the information to manage appbars, perform services for them, and send them notification messages.

An application must register an appbar (that is, add it to the internal list) before it can receive appbar services from the system. To register an appbar, an application sends the ABM_NEW message. The accompanying APPBARDATA structure includes the handle of the appbar's window and an application-defined message identifier. The system uses the message identifier to send notification messages to the window procedure of the appbar window. For more information about appbar notification messages, see "Notification Messages" later in this topic.

An application unregisters an appbar by sending the ABM_REMOVE message. Unregistering an appbar removes it from the system's internal list of appbars. The system no longer sends notification messages to the appbar nor prevents other applications from using the screen area occupied by the appbar. An application should always send ABM_REMOVE before destroying an appbar.


Size and Position

An application should set an appbar's size and position so that it does not interfere with any other appbars or the taskbar. Every appbar must be anchored to a particular edge of the screen, and multiple appbars can be anchored to an edge. However, if an appbar is anchored to the same edge as the taskbar, the system ensures that the taskbar is always on the outermost edge.

To set the size and position of an appbar, an application first proposes a screen edge and bounding rectangle for the appbar by sending the ABM_QUERYPOS message. The system determines whether any part of the screen area within the proposed rectangle is occupied by the taskbar or another appbar, adjusts the rectangle (if necessary), and returns the adjusted rectangle to the application.

Next, the application sends the ABM_SETPOS message to set the new bounding rectangle for the appbar. Again, the system may adjust the rectangle before returning it to the application. For this reason, the application should use the adjusted rectangle returned by ABM_SETPOS to set the final size and position. The application can use the MoveWindow function to move the appbar into position.

By using a two-step process to set the size and position, the system allows the application to provide intermediate feedback to the user during the move operation. For example, if the user drags an appbar, the application might display a shaded rectangle indicating the new position before the appbar actually moves.

An application should set the size and position of its appbar after registering it and whenever the appbar receives the ABN_POSCHANGED notification message. An appbar receives this notification message whenever a change occurs in the taskbar's size, position, or visibility state and whenever another appbar on the same side of the screen is resized, added, or removed.

Whenever an appbar receives the WM_ACTIVATE message, it should send the ABM_ACTIVATE message. Similarly, when an appbar receives a WM_WINDOWPOSCHANGED message, it must call ABM_WINDOWPOSCHANGED. Sending these messages ensures that the system properly sets the Z order of any autohide appbars on the same edge.


Autohide Application Desktop Toolbars

An autohide appbar is one that is normally hidden, but becomes visible when the user moves the mouse cursor to the screen edge that the appbar is associated with. The appbar hides itself again when the user moves the mouse cursor out of the bar's bounding rectangle.

Although the system allows a number of different appbars at any given time, it allows only one autohide appbar at a time for each screen edge on a first come, first served basis. The system automatically maintains the Z order of an autohide appbar (within its Z order group only).

An application uses the ABM_SETAUTOHIDEBAR message to register or unregister an autohide appbar. The message specifies the edge for the appbar and a flag that specifies whether the appbar is to be registered or unregistered. The message fails if an autohide appbar is being registered, but one is already associated with the specified edge. An application can retrieve the handle of the autohide appbar associated with an edge by sending the ABM_GETAUTOHIDEBAR message.

An autohide appbar does not need to register as a normal appbar; that is, it does not need to be registered by sending the ABM_NEW message. An appbar that is not registered by ABM_NEW overlaps any appbars anchored on the same edge of the screen.


Notification Messages

The system sends messages to notify an appbar about events that can effect its position and appearance. The messages are sent in the context of an application-defined message. The application specifies the identifier of the message when it sends the ABM_NEW message to register the appbar. The notification code is in the wParam parameter of the application-defined message.

An appbar receives the ABN_POSCHANGED notification message when the taskbar's size, position, or visibility state changes, when another appbar is added to the same edge of the screen, or when another appbar on the same edge of the screen is resized or removed. An appbar should respond to this notification message by sending ABM_QUERYPOS and ABM_SETPOS messages. If an appbar's position has changed, it should call the MoveWindow function to move itself to the new position.

The system sends the ABN_STATECHANGE notification message whenever the taskbar's autohide or always-on-top state has changed — that is, when the user checks or unchecks the "Always on top" or "Auto hide" check box on the taskbar's property sheet. An appbar can use this notification message to set its state to conform to that of the taskbar, if desired.

When a full-screen application is started or when the last full-screen application is closed, an appbar receives the ABN_FULLSCREENAPP notification message. The lParam parameter indicates whether the full-screen application is opening or closing. If it is opening, the appbar must drop to the bottom of the Z order. The appbar should restore its Z order position when the last full-screen application has closed.

An appbar receives the ABN_WINDOWARRANGE notification message when the user selects the Cascade, Tile Horizontally, or Tile Vertically command from the task bar's context menu. The system sends the message two times — before rearranging the windows (lParam is TRUE) and after arranging the windows (lParam is FALSE).

An appbar can use ABN_WINDOWARRANGE messages to exclude itself from the cascade or tile operation. To exclude itself, the appbar should hide itself when lParam is TRUE and show itself when lParam is FALSE. If an appbar hides itself in response to this message, it does not need to send the ABM_QUERYPOS and ABM_SETPOS messages in response to the cascade or tile operation.


Using Application Desktop Toolbars

This section includes examples that demonstrate how to perform the following tasks:

•	Register an application desktop toolbar (appbar).

•	Set its size and position.

•	Process the notification messages that the system sends to a registered appbar.


Registering an Application Desktop Toolbar

An application must register an appbar by sending the ABM_NEW message. Registering an appbar adds it to the system's internal list and provides the system with a message identifier to use to send notification messages to the appbar. Before exiting, an application must unregister the appbar by sending the ABM_REMOVE message. Unregistering removes the appbar from the system's internal list and prevents the bar from receiving appbar notification messages.

The function in the following example either registers or unregisters an appbar, depending on the value of a Boolean flag parameter.

// RegisterAccessBar - registers or unregisters an appbar.

// Returns TRUE if successful or FALSE otherwise.

// hwndAccessBar - handle of the appbar

// fRegister - register and unregister flag

//

// Global variables

//     g_uSide - screen edge (defaults to ABE_TOP)

//     g_fAppRegistered - flag indicating whether the bar is registered

BOOL RegisterAccessBar(HWND hwndAccessBar, BOOL fRegister)

{

    APPBARDATA abd;

    // Specify the structure size and handle of the appbar.

    abd.cbSize = sizeof(APPBARDATA);

    abd.hWnd = hwndAccessBar;

    if (fRegister) {

        // Provide an identifier for notification messages.

        abd.uCallbackMessage = APPBAR_CALLBACK;

        // Register the appbar.

        if (!SHAppBarMessage(ABM_NEW, &abd))

            return FALSE;

        g_uSide = ABE_TOP;       // default edge

        g_fAppRegistered = TRUE;

    } else {

        // Unregister the appbar.

        SHAppBarMessage(ABM_REMOVE, &abd);

        g_fAppRegistered = FALSE;

    }

    return TRUE;

}


Setting the Size and Position

An application should set an appbar's size and position after registering the appbar, after the user user moves or sizes the appbar, and whenever the appbar receives the ABN_POSCHANGED notification message. Before setting the size and position of the appbar, the application queries the system for an approved bounding rectangle by sending the ABM_QUERYPOS message. The system returns a bounding rectangle that does not interfere with the taskbar or any other appbar. The system adjusts the rectangle purely by rectangle subtraction; it makes no effort to preserve the rectangle's initial size. For this reason, the appbar should readjust the rectangle, as necessary, after sending ABM_QUERYPOS.

Next, the application passes the bounding rectangle back to the system by using the ABM_SETPOS message. Then it calls the MoveWindow function to move the appbar into position.

The following example shows how to set an appbar's size and position.

// AppBarQuerySetPos - sets the size and position of an appbar.

// uEdge - screen edge to which the appbar is to be anchored

// lprc - current bounding rectangle of the appbar

// pabd - address of APPBARDATA structure with the hWnd and

//     cbSize members filled

void PASCAL AppBarQuerySetPos(UINT uEdge, LPRECT lprc, PAPPBARDATA pabd)

{

    int iHeight = 0;

    int iWidth = 0;

    pabd->rc = *lprc;

    pabd->uEdge = uEdge;

    // Copy the screen coordinates of the appbar's bounding

    // rectangle into the APPBARDATA structure.

    if ((uEdge == ABE_LEFT) ||

            (uEdge == ABE_RIGHT)) {

        iWidth = pabd->rc.right - pabd->rc.left;

        pabd->rc.top = 0;

        pabd->rc.bottom = GetSystemMetrics(SM_CYSCREEN);

    } else {

        iHeight = pabd->rc.bottom - pabd->rc.top;

        pabd->rc.left = 0;

        pabd->rc.right = GetSystemMetrics(SM_CXSCREEN);

    }

    // Query the system for an approved size and position.

    SHAppBarMessage(ABM_QUERYPOS, pabd);

    // Adjust the rectangle, depending on the edge to which the

    // appbar is anchored.

    switch (uEdge) {

        case ABE_LEFT:

            pabd->rc.right = pabd->rc.left + iWidth;

            break;

        case ABE_RIGHT:

            pabd->rc.left = pabd->rc.right - iWidth;

            break;

        case ABE_TOP:

            pabd->rc.bottom = pabd->rc.top + iHeight;

            break;

        case ABE_BOTTOM:

            pabd->rc.top = pabd->rc.bottom - iHeight;

            break;

    }

    // Pass the final bounding rectangle to the system.

    SHAppBarMessage(ABM_SETPOS, pabd);

    // Move and size the appbar so that it conforms to the

    // bounding rectangle passed to the system.

    MoveWindow(pabd->hWnd, pabd->rc.left, pabd->rc.top,

        pabd->rc.right - pabd->rc.left,

        pabd->rc.bottom - pabd->rc.top, TRUE);

}


Processing Notification Messages

An appbar receives a notification message when the state of the task bar changes, when a full screen application starts (or the last one closes), or when an event occurs that can affect the appbar's size and position. The following example shows how to process the various notification messages.

// AppBarCallback - processes notification messages sent by the system.

// hwndAccessBar - handle of the appbar

// uNotifyMsg - identifier of the notification message

// lParam - message parameter

void AppBarCallback(HWND hwndAccessBar, UINT uNotifyMsg,

    LPARAM lParam)

{

    APPBARDATA abd;

    UINT uState;

    abd.cbSize = sizeof(abd);

    abd.hWnd = hwndAccessBar;

    switch (uNotifyMsg) {

        case ABN_STATECHANGE:

            // Check to see if the taskbar's always-on-top state has

            // changed and, if it has, change the appbar's state

            // accordingly.

            uState = SHAppBarMessage(ABM_GETSTATE, &abd);

            SetWindowPos(hwndAccessBar,

                (ABS_ALWAYSONTOP & uState) ? HWND_TOPMOST : HWND_BOTTOM,

                0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);

            break;

        case ABN_FULLSCREENAPP:

            // A full screen application has started, or the last full

            // screen application has closed. Set the appbar's

            // Z order appropriately.

            if (lParam) {

                SetWindowPos(hwndAccessBar,

                    (ABS_ALWAYSONTOP & uState) ?

                                            HWND_TOPMOST : HWND_BOTTOM,

                    0, 0, 0, 0,

                    SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);

            } else {

                uState = SHAppBarMessage(ABM_GETSTATE, &abd);

                if (uState & ABS_ALWAYSONTOP)

                    SetWindowPos(hwndAccessBar, HWND_TOPMOST,

                        0, 0, 0, 0,

                        SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);

        }

        case ABN_POSCHANGED:

            // The taskbar or another appbar has changed its

            // size or position.

            AppBarPosChanged(&abd);

            break;

    }

}

The following function adjusts an appbar's bounding rectangle and then calls the application-defined AppBarQuerySetPos function (included in the previous section) to set the bar's size and position accordingly.

// AppBarPosChanged - adjusts the appbar's size and position.

// pabd - address of an APPBARDATA structure that contains information

//     used to adjust the size and position

void PASCAL AppBarPosChanged(PAPPBARDATA pabd)

{

    RECT rc;

    RECT rcWindow;

    int iHeight;

    int iWidth;

    rc.top = 0;

    rc.left = 0;

    rc.right = GetSystemMetrics(SM_CXSCREEN);

    rc.bottom = GetSystemMetrics(SM_CYSCREEN);

    GetWindowRect(pabd->hWnd, &rcWindow);

    iHeight = rcWindow.bottom - rcWindow.top;

    iWidth = rcWindow.right - rcWindow.left;

    switch (g_uSide) {

        case ABE_TOP:

            rc.bottom = rc.top + iHeight;

            break;

        case ABE_BOTTOM:

            rc.top = rc.bottom - iHeight;

            break;

        case ABE_LEFT:

            rc.right = rc.left + iWidth;

            break;

        case ABE_RIGHT:

            rc.left = rc.right - iWidth;

            break;

        }

        AppBarQuerySetPos(g_uSide, &rc, pabd);

    }


Reference

The following function, structure, messages, and notification messages are associated with appbars.


Function and Structure

The following function and structure are used with appbars.


SHAppBarMessage [New - Windows 95]
SHAppBarMessage

[New - Windows 95]

WINSHELLAPI UINT APIENTRY SHAppBarMessage(DWORD dwMessage,

    PAPPBARDATA pabd);

Sends an appbar message to the system.

•	Returns a message-dependent value. For more information, see the documentation for the individual appbar messages.

dwMessage

Identifier of the appbar message to send. This parameter can be one of these values:

ABM_ACTIVATE	Notifies the system that an appbar has been activated.
ABM_GETAUTOHIDEBAR	Retrieves the handle of the autohide appbar associated with a particular edge of the screen.
ABM_GETSTATE	Retrieves the autohide and always-on-top states of the Windows taskbar.
ABM_GETTASKBARPOS	Retrieves the bounding rectangle of the Windows taskbar.
ABM_NEW	Registers a new appbar and specifies the message identifier that the system should use to send notification messages to the appbar.
ABM_QUERYPOS	Requests a size and screen position for an appbar.
ABM_REMOVE	Unregisters an appbar, removing the bar from the system's internal list.
ABM_SETAUTOHIDEBAR	Registers or unregisters an autohide appbar for an edge of the screen.
ABM_SETPOS	Sets the size and screen position of an appbar.
ABM_WINDOWPOSCHANGED	Notifies the system when an appbar's position has changed.
pabd

Address of an APPBARDATA structure. The content of the structure depends on the value of dwMessage.


APPBARDATA [New - Windows 95]
APPBARDATA

[New - Windows 95]

typedef struct _AppBarData { // abd

    DWORD  cbSize;           // sizeof(APPBARDATA)

    HWND   hWnd;             // handle of appbar

    UINT   uCallbackMessage; // see below

    UINT   uEdge;            // see below

    RECT   rc;               // see below

    LPARAM lParam;           // see below

} APPBARDATA, *PAPPBARDATA;

Contains information that the system uses to process appbar messages.

uCallbackMessage

Application-defined message identifier. The application uses the specified identifier for notification messages that it sends to the the appbar identified by the hWnd member. This member is used when sending the ABM_NEW message.

uEdge

Flag that specifies an edge of the screen. This member can be one of these values:

ABE_BOTTOM	Bottom edge
ABE_LEFT	Left edge
ABE_RIGHT	Right edge
ABE_TOP	Top edge
This member is used when sending the ABM_GETAUTOHIDEBAR, ABM_QUERYPOS, ABM_SETAUTOHIDEBAR, and ABM_SETPOS messages.

rc

RECT structure that contains the bounding rectangle, in screen coordinates, of an appbar or the Windows taskbar. This member is used when sending the ABM_GETTASKBARPOS, ABM_QUERYPOS, and ABM_SETPOS messages.

lParam

Message-dependent value. This member is used with the ABM_SETAUTOHIDEBAR message.

This structure is used with the SHAppBarMessage function.


Messages

An application sends appbar messages to register an appbar with the system; to set an appbar's size, position, and state; to retrieve information about the Windows taskbar; and so on. To send an appbar message, an application uses the SHAppBarMessage function. There are the following appbar messages.


ABM_ACTIVATE [New - Windows 95]
ABM_ACTIVATE

[New - Windows 95]

SHAppBarMessage(ABM_ACTIVATE, pabd);

Notifies the system that an appbar has been activated. An appbar should call this message in response to the WM_ACTIVATE message.

•	Always returns TRUE.

pabd

Address of an APPBARDATA structure that identifies the appbar to activate. You must specify the cbSize and hWnd members when sending this message; all other members are ignored.

This message is ignored if the hWnd member of the structure pointed to by pabd identifies an autohide appbar. The system automatically sets the Z order for an autohide appbar.


ABM_GETAUTOHIDEBAR [New - Windows 95]
ABM_GETAUTOHIDEBAR

[New - Windows 95]

hwndAutoHide = (HWND) SHAppBarMessage(ABM_GETAUTOHIDEBAR, pabd);

Retrieves the handle of the autohide appbar associated with an edge of the screen.

•	Returns the handle of the autohide appbar. The return value is NULL if an error occurs or if no autohide appbar is associated with the given edge.

pabd

Address of an APPBARDATA structure that specifies the screen edge. You must specify the cbSize, hWnd, and uEdge members when sending this message; all other members are ignored.


ABM_GETSTATE [New - Windows 95]
ABM_GETSTATE

[New - Windows 95]

fuState = (UINT) SHAppBarMessage(ABM_GETSTATE, pabd);

Retrieves the autohide and always-on-top states of the Windows taskbar.

•	Returns zero if the taskbar is not in the autohide or always-on-top state. Otherwise, the return value is one or both of these values:

ABS_ALWAYSONTOP	The taskbar is in the always-on-top state.
ABS_AUTOHIDE	The taskbar is in the autohide state.
pabd

Address of an APPBARDATA structure. You must specify the cbSize and hWnd members when sending this message; all other members are ignored.


ABM_GETTASKBARPOS [New - Windows 95]
ABM_GETTASKBARPOS

[New - Windows 95]

fResult = (BOOL) SHAppBarMessage(ABM_GETTASKBARPOS, pabd);

Retrieves the bounding rectangle of the Windows taskbar.

•	Returns TRUE if successful or FALSE otherwise.

pabd

Address of an APPBARDATA structure whose rc member receives the bounding rectangle, in screen coordinates, of the taskbar. You must specify the cbSize and hWnd members when sending this message; all other members are ignored.


ABM_NEW [New - Windows 95]
ABM_NEW

[New - Windows 95]

fRegistered = (BOOL) SHAppBarMessage(ABM_NEW, pabd);

Registers a new appbar and specifies the message identifier that the system should use to send notification messages to the appbar. An appbar should send this message before sending any other appbar messages.

•	Returns TRUE if successful or FALSE if an error occurs or the appbar is already registered.

pabd

Address of an APPBARDATA structure that contains the new appbar's window handle and message identifier. You must specify the cbSize, hWnd, and uCallbackMessage members when sending this message; all other members are ignored.


ABM_QUERYPOS [New - Windows 95]
ABM_QUERYPOS

[New - Windows 95]

SHAppBarMessage(ABM_QUERYPOS, pabd);

Requests a size and screen position for an appbar. The message proposes a screen edge and a bounding rectangle for the appbar. The system adjusts the bounding rectangle so that the appbar does not interfere with the Windows taskbar or any other appbars. An appbar should send this message before sending the ABM_SETPOS message.

•	Always returns TRUE.

pabd

Address of an APPBARDATA structure. The uEdge member specifies a screen edge, and the rc member contains the proposed bounding rectangle. When the SHAppBarMessage function returns, rc contains the approved bounding rectangle. You must specify the cbSize, hWnd, uEdge, and rc members when sending this message; all other members are ignored.


ABM_REMOVE [New - Windows 95]
ABM_REMOVE

[New - Windows 95]

SHAppBarMessage(ABM_REMOVE, pabd);

Unregisters an appbar, removing it from the system's internal list. The system no longer sends notification messages to the appbar nor prevents other applications from using the screen area occupied by the appbar.

•	Always returns TRUE.

pabd

Address of an APPBARDATA structure that contains the handle of the appbar to unregister. You must specify the cbSize and hWnd members when sending this message; all other members are ignored.

This message causes the system to send the ABN_POSCHANGED notification message to all appbars.


ABM_SETAUTOHIDEBAR [New - Windows 95]
ABM_SETAUTOHIDEBAR

[New - Windows 95]

fSuccess = (BOOL) SHAppBarMessage(ABM_SETAUTOHIDEBAR, pabd);

Registers or unregisters an autohide appbar for an edge of the screen. The system allows only one autohide appbar for each edge on a first come, first served basis.

•	Returns TRUE if successful or FALSE if an error occurs or an autohide appbar is already registered for the given edge.

pabd

Address of an APPBARDATA structure. The uEdge member specifies the screen edge. The lParam parameter is set to TRUE to register the appbar or FALSE to unregister it. You must specify the cbSize, hWnd, uEdge, and lParam members when sending this message; all other members are ignored.


ABM_SETPOS [New - Windows 95]
ABM_SETPOS

[New - Windows 95]

SHAppBarMessage(ABM_SETPOS, pabd);

Sets the size and screen position for an appbar. The message specifies a screen edge and a bounding rectangle for the appbar. The system may adjust the bounding rectangle so that the appbar does not interfere with the Windows taskbar or any other appbars.

•	Always returns TRUE.

pabd

Address of an APPBARDATA structure. The uEdge member specifies a screen edge, and the rc member contains the bounding rectangle. When the SHAppBarMessage function returns, rc contains the approved bounding rectangle. You must specify the cbSize, hWnd, uEdge, and rc members when sending this message; all other members are ignored.

This message causes the system to send the ABN_POSCHANGED notification message to all appbars.


ABM_WINDOWPOSCHANGED [New - Windows 95]
ABM_WINDOWPOSCHANGED

[New - Windows 95]

SHAppBarMessage(ABM_WINDOWPOSCHANGED, pabd);

Notifies the system when an appbar's position has changed. An appbar should call this message in response to the WM_WINDOWPOSCHANGED message.

•	Always returns TRUE.

pabd

Address of an APPBARDATA structure that identifies the appbar to activate. You must specify the cbSize and hWnd members when sending this message; all other members are ignored.

This message is ignored if the hWnd member of the structure pointed to by pabd identifies an autohide appbar.


Notification Messages

The system sends notification messages to an appbar to notify it about events. The message identifier for the notification messages is an application-defined value that is set when the application sends the ABM_NEW message. The system sends the following notification messages to an appbar.


ABN_FULLSCREENAPP [New - Windows 95]
ABN_FULLSCREENAPP

[New - Windows 95]

ABN_FULLSCREENAPP

fOpen = (BOOL) lParam;

Notifies an appbar when a full-screen application is opening or closing. When a full-screen application is opening, an appbar must drop to the bottom of the Z order. When it is closing, the appbar should restore its Z order position. This notification message is sent in the form of an application-defined message that is set by the ABM_NEW message.

•	No return value.

fOpen

Flag specifying whether a full-screen application is opening or closing. This parameter is TRUE if it is opening or FALSE if it is closing.


ABN_POSCHANGED [New - Windows 95]
ABN_POSCHANGED

[New - Windows 95]

Notifies an appbar when an event has occurred that may effect the appbar's size and position. Events include changes in the taskbar's size, position, and visibility state as well as the addition, removal, or resizing of another appbar on the same side of the screen.

•	No return value.

An appbar should respond to this notification message by sending the ABM_QUERYPOS and ABM_SETPOS messages. If its position has changed, the appbar should call the MoveWindow function to move itself to the new position.


ABN_STATECHANGE [New - Windows 95]
ABN_STATECHANGE

[New - Windows 95]

ABN_STATECHANGE

Notifies an appbar that the taskbar's autohide or always-on-top state has changed — that is, the user has checked or unchecked the "Always on top" or "Auto hide" check box on the taskbar's property sheet. An appbar can use this notification message to set its state to conform to that of the taskbar, if desired.

•	No return value.


ABN_WINDOWARRANGE [New - Windows 95]
ABN_WINDOWARRANGE

[New - Windows 95]

ABN_WINDOWARRANGE

fBeginning = (BOOL) lParam;

Notifies an appbar that the user has selected the Cascade, Tile Horizontally, or Tile Vertically command from the taskbar's context menu.

•	No return value.

fBeginning

Flag specifying whether the cascade or tile operation is beginning. This parameter is TRUE if the operation is beginning and the windows have not yet been moved. It is FALSE if the operation has completed.

The system sends this notification message twice — first with lParam set to TRUE and then with lParam set to FALSE. The first notification is sent before the windows are cascaded or tiled, and the second is sent after the cascade or tile operation has occurred.


Shell Links

A shell link is a data object that contains information used to access another object in the shell's namespace — that is, any object visible through Microsoft® Windows® Explorer. The objects that can be accessed through shell links include files, folders, disk drives, and printers. A shell link allows the user or an application to access an object from anywhere in the namespace; the user or application does not need to know the current name and location of the object.


About Shell Links

The user creates a shell link by choosing the Create Shortcut command from an object's context menu. The system automatically creates an icon for the shell link by combining the object's icon with a small arrow (known as the system-defined link overlay icon) that appears in the lower left corner of the icon. A shell link that has an icon is called a shortcut; however, the terms shell link and shortcut are often used interchangeably. Typically, the user creates shortcuts to gain quick access to objects stored in subfolders or in shared folders on other machines. For example, a user can create a shortcut to a Microsoft Word document located in a subfolder and place the shortcut icon on the desktop. Later the user can 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.

Applications can also create and use shell links and shortcuts. For example, a word processing application might create a shell link to implement a list of the most recently used documents. An application creates a shell link by using the IShellLink interface to create a shell link object and uses the IPersistFile or IPersistStream interface to store the object in a file or stream. This article  describes the IShellLink interface and explains how to use the interface to create and resolve shell links from within a Windows-based application.

Because the design of shell links is based on the OLE Component Object Model (COM), you should be familiar with the basic concepts of COM and OLE programming before reading this article . For more information, see the OLE documentation included in the Microsoft Windows Software Development Kit (SDK).


Link Resolution

If a user creates a shortcut to an object and the name or location of the object is subsequently changed, the system automatically takes steps to update, or resolve, the shortcut the next time the user selects it. However, if an application creates a shell link and stores it in a stream, the system does not automatically attempt to resolve the link. The application must resolve the link by calling the IShellLink::Resolve member function.

When a shell link is created, the system saves information about the link. When resolving a link (either automatically or if IShellLink::Resolve is called), the system first retrieves the path associated with the shell link by using a pointer to the shell link's identifier list. (For more information about the identifier list, see "Item Identifiers and Identifier Lists" later in this topic.) The system searches for the associated object in that path and, if it finds the object, resolves the link. If the system cannot find the object, it looks in the same directory for an object that has the same file creation time and attributes, but a different name. This type of search resolves a link to an object that has been renamed.

If the system still cannot find the object, it searches the subdirectories of the current directory, looking recursively though the directory tree for a match with either the same name or creation time. If the system does not find a match after that, it displays a dialog box prompting the user for a location. An application can suppress the dialog box by specifying the SLR_NO_UI value in a call to IShellLink::Resolve.


Initialization of the Component Object Library

Before an application can create and resolve shortcuts, it must initialize the component object library by calling the CoInitialize function. Each call to CoInitialize requires a corresponding call to the CoUninitialize function, which an application should call when it terminates. The call to CoUninitialize ensures that the application does not terminate until it has received all of its pending messages.


Location-Independent Names

The system provides location-independent names for shell links to objects stored in shared folders. If the object is stored locally, the system provides the local path and filename for the object. If the object is stored remotely, the system provides the Universal Naming Convention (UNC) network resource name for the object. Because the system provides location-independent names, a shell link can serve as a universal name for a file that can be transferred to other machines.


Link Files

When the user creates a shortcut to an object by choosing the Create Shortcut command from the object's context menu, Windows stores the information it needs to access the object in a link file — that is, a binary file that has the .LNK filename extension. A link file contains the following information:

•	The location (path) of the object referenced by the shortcut (called the "corresponding object" in this article ).

•	The working directory of the corresponding object.

•	The list of arguments that the system passes to the corresponding object when the IContextMenu::InvokeCommand member function is activated for the shortcut.

•	The show (SW_) command used to set the initial show state of the corresponding object.

•	The location (path and index) of the shortcut's icon.

•	The shortcut's description string.

•	The hot key for the shortcut.

When a link file is deleted, the corresponding object is not affected.

If you create a shortcut to another shortcut, the system simply copies the link file rather than creating a new link file. This is important to remember if you are assuming that the shortcuts will remain independent of each other.

An application can register a filename extension as a "shortcut" file type. If a file has a filename extension that has been registered as a shortcut file type, the system automatically adds the system-defined link overlay icon (a small arrow) to the file's icon. To register a filename extension as a shortcut file type, you must add the "IsShortcut" value to the registry description of the filename extension. Note that the shell must be restarted for the overlay icon to take effect.

HKEY_CLASSES_ROOT

  .xyz    (Default) = "XYZApp"

  .

  .

  .

  XYZApp  IsShortcut = ""


Location in the Namespace

A shortcut can exist on the desktop or anywhere in the shell's namespace. Similarly, the object that is associated with the shortcut can also exist anywhere in the shell's namespace. An application can use the IShellLink::SetPath member function to set the path and filename for the associated object, and the IShellLink::GetPath member function to retrieve the current path and filename for the object.


Working Directory

The working directory is the directory where the corresponding object of a shortcut loads or stores files when the user does not identify a specific directory. A link file contains the name of the working directory for the corresponding object. An application can set the name of the working directory for the corresponding object by using the IShellLink::SetWorkingDirectory member function and can retrieve the name of the current working directory for the corresponding object by using the IShellLink::GetWorkingDirectory member function.


Command-Line Arguments

A link file contains command-line arguments that the shell passes to the corresponding object when the user selects the link. An application can set the command-line arguments for a shortcut by using the IShellLink::SetArguments member function. It is useful to set command-line arguments when the corresponding application, such as a linker or compiler, takes special flags as arguments. An application can retrieve the command-line arguments from a shortcut by using the IShellLink::GetArguments member function.


Show Command

When the user double-clicks a shortcut, the system starts the application associated with the corresponding object and sets the initial show state of the application based on the show command specified by the shortcut. The show command can be any of the SW_ values included in the description of the ShowWindow function. An application can set the show command for a shortcut by using the IShellLink::SetShowCmd member function and can retrieve the current show command by using the IShellLink::GetShowCmd member function.


Shortcut Icon and Description

Like other shell objects, a shortcut has an icon. The user accesses the object associated with a shortcut by double-clicking the shortcut's icon. When the system creates an icon for a shortcut, it uses the bitmap of the corresponding object and adds the system-defined link overlay icon (a small arrow) to the lower left corner. An application can set the location (path and index) of a shortcut's icon by using the IShellLink::SetIconLocation member function. An application can retrieve the current location (path and index) of a shortcut's icon by using the IShellLink::GetIconLocation member function.

A shortcut also has a description, which is a brief string that appears below the shell link icon. By default, the description consists of the words "Shortcut to" followed by the filename of the object. The user can edit the description string by selecting it and entering a new string. An application can set the description string by using the IShellLink::SetDescription member function and can retrieve the current description string by using the IShellLink::GetDescription member function.


Hot Key

A shortcut object can have a hot key associated with it. A hot key allows the user to use the shortcut by pressing a particular combination of keys. An application can set the hot key for a shortcut by using the IShellLink::SetHotkey member function and can retrieve the current hot key for a shortcut by using the IShellLink::GetHotkey member function.


Item Identifiers and Identifier Lists

The shell uses object identifiers within the shell namespace. All of the objects that are visible in the shell (files, directories, servers, workgroups, and so on) have an identifier that is unique among the objects within the parent folder. These identifiers are called item identifiers, and they have the SHITEMID data type as defined in the SHLOBJ.H header file. An item identifier is a variable-length byte stream that contains information for identifying an object within a folder. Only the creator of an item identifier knows the content and format of the identifier. The only part of an item identifier that the shell uses is the first two bytes, which specify the size of the identifier.

Each parent folder has its own item identifier that identifies it within its own parent folder. Thus, any shell object can be uniquely identified by a list of item identifiers. A parent folder keeps a list of identifiers for the items in the folder. The list has the ITEMIDLIST data type. Item identifier lists are allocated by the shell and may be passed across shell interfaces, such as IShellFolder. It is important to remember that each identifier in an item identifier list is only meaningful within the context of the parent folder.

An application can set a shortcut's item identifier list by using the IShellLink::SetIDList member function. This function is useful when setting a shortcut to an object that is not a file, such as a printer or disk drive. An application can retrieve a shortcut's item identifier list by using the IShellLink::GetIDList member function.


Using Shell Links

This section contains examples that demonstrate how to create and resolve shortcuts from within a Windows-based application.


Creating a Shortcut to a File

The CreateLink function in the following example creates a shortcut. The parameters include a pointer to the name of the file to link to, a pointer to the name of the shortcut that you are creating, and a pointer to the description of the link. The description consists of the string, "Shortcut to filename," where filename is the name of the file to link to.

Because CreateLink calls the CoCreateInstance function, it is assumed that the CoInitialize function has already been called. CreateLink uses the IPersistFile interface to save the shortcut and the IShellLink interface to store the filename and description.

// CreateLink - uses the shell's IShellLink and IPersistFile interfaces

//   to create and store a shortcut to the specified object.

// Returns the result of calling the member functions of the interfaces.

// lpszPathObj - address of a buffer containing the path of the object

// lpszPathLink - address of a buffer containing the path where the

//   shell link is to be stored

// lpszDesc - address of a buffer containing the description of the

//   shell link

HRESULT CreateLink(LPCSTR lpszPathObj,

    LPSTR lpszPathLink, LPSTR lpszDesc)

{

    HRESULT hres;

    IShellLink* psl;

    // Get a pointer to the IShellLink interface.

    hres = CoCreateInstance(&CLSID_ShellLink, NULL,

        CLSCTX_INPROC_SERVER, &IID_IShellLink, &psl);

    if (SUCCEEDED(hres)) {

        IPersistFile* ppf;

        // Set the path to the shortcut target, and add the

        // description.

        psl->lpVtbl->SetPath(psl, lpszPathObj);

        psl->lpVtbl->SetDescription(psl, lpszDesc);

       // Query IShellLink for the IPersistFile interface for saving the

       // shortcut in persistent storage.

        hres = psl->lpVtbl->QueryInterface(psl, &IID_IPersistFile,

            &ppf);

        if (SUCCEEDED(hres)) {

            WORD wsz[MAX_PATH];

            // Ensure that the string is ANSI.

            MultiByteToWideChar(CP_ACP, 0, lpszPathLink, -1,

                wsz, MAX_PATH);

            // Save the link by calling IPersistFile::Save.

            hres = ppf->lpVtbl->Save(ppf, wsz, TRUE);

            ppf->lpVtbl->Release(ppf);

        }

        psl->lpVtbl->Release(psl);

    }

    return hres;

}


Resolving A Shortcut

An application may need to access and manipulate a shortcut that was created previously. This operation is referred to as "resolving" the shortcut.

The application-defined ResolveIt function in the following example resolves a shortcut. Its parameters include a window handle, a pointer to the path of the shortcut, and the address of a buffer that receives the new path to the object. The window handle identifies the parent window for any message boxes that the shell may need to display. For example, the shell can display a message box if the link is on unshared media, if network problems occur, if the user needs to insert a floppy disk, and so on.

The ResolveIt function calls the CoCreateInstance function and assumes that the CoInitialize function has already been called. Note that ResolveIt needs to use the IPersistFile interface to store the link information. IPersistFile is implemented by the IShellLink object. The link information must be loaded before the path information is retrieved, which happens later in the example. Failing to load the link information causes the calls to the IShellLink::GetPath and IShellLink::GetDescription member functions to fail.

HRESULT ResolveIt(HWND hwnd, LPCSTR lpszLinkFile, LPSTR lpszPath)

{

    HRESULT hres;

    IShellLink* psl;

    char szGotPath[MAX_PATH];

    char szDescription[MAX_PATH];

    WIN32_FIND_DATA wfd;

    *lpszPath = 0; // assume failure

    // Get a pointer to the IShellLink interface.

    hres = CoCreateInstance(&CLSID_ShellLink, NULL,

            CLSCTX_INPROC_SERVER, &IID_IShellLink, &psl);

    if (SUCCEEDED(hres)) {

        IPersistFile* ppf;

        // Get a pointer to the IPersistFile interface.

        hres = psl->lpVtbl->QueryInterface(psl, &IID_IPersistFile,

            &ppf);

        if (SUCCEEDED(hres)) {

            WORD wsz[MAX_PATH];

            // Ensure that the string is Unicode.

            MultiByteToWideChar(CP_ACP, 0, lpszLinkFile, -1, wsz,

                MAX_PATH);

            // Load the shortcut.

            hres = ppf->lpVtbl->Load(ppf, wsz, STGM_READ);

            if (SUCCEEDED(hres)) {

                // Resolve the link.

                hres = psl->lpVtbl->Resolve(psl, hwnd, SLR_ANY_MATCH);

                if (SUCCEEDED(hres)) {

                    // Get the path to the link target.

                    hres = psl->lpVtbl->GetPath(psl, szGotPath,

                        MAX_PATH, (WIN32_FIND_DATA *)&wfd,

                        SLGP_SHORTPATH );

                    if (!SUCCEEDED(hres)

                        HandleErr(hres); // application-defined function

                    // Get the description of the target.

                    hres = psl->lpVtbl->GetDescription(psl,

                        szDescription, MAX_PATH);

                    if (!SUCCEEDED(hres))

                        HandleErr(hres);

                    lstrcpy(lpszPath, szGotPath);

                }

            }

        // Release the pointer to the IPersistFile interface.

        ppf->lpVtbl->Release(ppf);

        }

    // Release the pointer to the IShellLink interface.

    psl->lpVtbl->Release(psl);

    }

    return hres;

}


Creating a Link to a Nonfile Object

Creating a shortcut to a nonfile object, such as a printer, is similar to creating a shortcut to a file. The main difference is that, rather than setting the path to the file, you must set the identifier list to the printer. To set the identifier list, you must call the IShellLink::SetIDList member function, specifying the address of an identifier list.

Each object within the shell's namespace has an item identifier, a variable-length byte stream containing information that identifies the object within its folder. The shell often concatenates item identifiers into null-terminated lists consisting of any number of item identifiers.

In general, if you need to set a shortcut to an item that does not have a filename, such as a printer, you will already have a pointer to the object's IShellFolder interface. The IShellFolder interface is used to create namespace extensions.

Once you have the class identifier for the IShellFolder interface, you can call the CoCreateInstance function to get the address of the interface. Then you can call the interface to enumerate the objects in the folder and retrieve the address of the item identifier for the object that you are searching for. Finally, you can use the address in a call to the IShellLink::SetIDList member function to create a shortcut to the object.


Reference

The following interface is used with shell links.


Interfaces and Member Functions


IShellLink [New - Windows 95]
IShellLink

[New - Windows 95]

Designates an interface that allows an application to create and resolve shell links. The IShellLink interface has the following member functions.

GetArguments	Retrieves the command-line arguments associated with a shell link object.
GetDescription	Retrieves the description string for a shell link object.
GetHotkey	Retrieves the hot key for a shell link object.
GetIconLocation	Retrieves the location (path and index) of the icon for a shell link object.
GetIDList	Retrieves the list of item identifiers for a shell link object.
GetPath	Retrieves the path and filename of a shell link object.
GetShowCmd	Retrieves the show (SW_) command for a shell link object.
GetWorkingDirectory	Retrieves the name of the working directory for a shell link object.
Resolve	Resolves a shell link by searching for the shell link object and updating the shell link path and its list of identifiers, if necessary.
SetArguments	Sets the command-line arguments associated with a shell link object.
SetDescription	Sets the description string for a shell link object.
SetHotkey	Sets the hot key for a shell link object.
SetIconLocation	Sets the location (path and index) of the icon for a shell link object.
SetIDList	Sets the list of item identifiers for a shell link object.
SetPath	Sets the path and filename of a shell link object.
SetRelativePath	Sets the relative path for a shell link object.
SetShowCmd	Sets the show (SW_) command for a shell link object.
SetWorkingDirectory	Sets the name of the working directory for a shell link object.
Like all OLE interfaces, IShellLink also includes the QueryInterface, AddRef, and Release member functions.


IShellLink::GetArguments [New - Windows 95]
IShellLink::GetArguments

[New - Windows 95]

HRESULT GetArguments(ISHELLLINK FAR * pShlLnk,

    LPSTR pszArgs, int cchMaxPath);

Retrieves the command-line arguments associated with a shell link object.

•	Returns the NOERROR value if successful or an OLE-defined error value otherwise.

pShlLnk

Address of the IShellLink interface. In C++, this parameter is implicit.

pszArgs

Address of a buffer that receives the command-line arguments.

cchMaxPath

Maximum number of characters to copy to the buffer pointed to by pszArgs.


IShellLink::GetDescription [New - Windows 95]
IShellLink::GetDescription

[New - Windows 95]

RESULT GetDescription(ISHELLLINK FAR * pShlLnk,

    LPSTR pszName, int cchMaxName);

Retrieves the description string for a shell link object.

•	Returns the NOERROR value if successful or an OLE-defined error value otherwise.

pShlLnk

Address of the IShellLink interface. In C++, this parameter is implicit.

pszName

Address of a buffer that receives the description string.

cchMaxName

Maximum number of characters to copy to the buffer pointed to by pszName.


IShellLink::GetHotkey [New - Windows 95]
IShellLink::GetHotkey

[New - Windows 95]

HRESULT GetHotkey(ISHELLLINK FAR * pShlLnk,

    WORD *pwHotkey);

Retrieves the hot key for a shell link object.

•	Returns the NOERROR value if successful or an OLE-defined error value otherwise.

pShlLnk

Address of the IShellLink interface. In C++, this parameter is implicit.

pwHotkey

Address of the hot key. The virtual-key code is in the low-order byte, and the modifier flags are in the high-order byte. The modifier flags can be a combination of these values:

HOTKEYF_ALT	ALT key
HOTKEYF_CONTROL	CTRL key
HOTKEYF_EXT	Extended key
HOTKEYF_SHIFT	SHIFT key


IShellLink::GetIconLocation [New - Windows 95]
IShellLink::GetIconLocation

[New - Windows 95]

HRESULT GetIconLocation(ISHELLLINK FAR * pShlLnk,

    LPSTR pszIconPath, int cchIconPath, int *piIcon);

Retrieves the location (path and index) of the icon for a shell link object.

•	Returns the NOERROR value if successful or an OLE-defined error value otherwise.

pShlLnk

Address of the IShellLink interface. In C++, this parameter is implicit.

pszIconPath

Address of a buffer that receives the path of the file containing the icon.

cchIconPath

Maximum number of characters to copy to the buffer pointed to by pszIconPath.

piIcon

Address of a value that receives the index of the icon.


IShellLink::GetIDList [New - Windows 95]
IShellLink::GetIDList

[New - Windows 95]

HRESULT GetIDList(ISHELLLINK FAR * pShlLnk,

    LPITEMIDLIST * ppidl);

Retrieves the list of item identifiers for a shell link object.

•	Returns the NOERROR value if successful or an OLE-defined error value otherwise.

pShlLnk

Address of the IShellLink interface. In C++, this parameter is implicit.

ppidl

Address of a pointer to a list of item identifiers.


IShellLink::GetPath [New - Windows 95]
IShellLink::GetPath

[New - Windows 95]

HRESULT GetPath(IShellLink FAR * pShlLnk,

    LPSTR pszFile, int cchMaxPath, WIN32_FIND_DATA *pfd, DWORD fFlags);

Retrieves the path and filename of a shell link object.

•	Returns the NOERROR value if successful or an OLE-defined error value otherwise.

pShlLnk

Address of the IShellLink interface. In C++, this parameter is implicit.

pszFile

Address of a buffer that receives the path and filename of the shell link object.

cchMaxPath

Maximum number of bytes to copy to the buffer pointed to by pszFile.

pfd

Address of a WIN32_FIND_DATA structure that contains information about the shell link object.

fFlags

Flags that specify the type of path information to retrieve. This parameter can be a combination of these values:

SLGP_SHORTPATH	Retrieves the standard short (8.3) filename.
SLGP_UNCPRIORITY	Retrieves the Universal Naming Convention (UNC) path for the file.


IShellLink::GetShowCmd [New - Windows 95]
IShellLink::GetShowCmd

[New - Windows 95]

HRESULT GetShowCmd(ISHELLLINK FAR * pShlLnk,

    int *piShowCmd);

Retrieves the show command for a shell link object.

•	Returns the NOERROR value if successful or an OLE-defined error value otherwise.

pShlLnk

Address of the IShellLink interface. In C++, this parameter is implicit.

piShowCmd

Address of the show command. For a list of show commands, see the description of the ShowWindow function.


IShellLink::GetWorkingDirectory [New - Windows 95]
IShellLink::GetWorkingDirectory

[New - Windows 95]

HRESULT GetWorkingDirectory(ISHELLLINK FAR * pShlLnk,

    LPSTR pszDir, int cchMaxPath);

Retrieves the name of the working directory for a shell link object.

•	Returns the NOERROR value if successful or an OLE-defined error value otherwise.

pShlLnk

Address of the IShellLink interface. In C++, this parameter is implicit.

pszDir

Address of a buffer that receives the name of the working directory.

cchMaxPath

Maximum number of characters to copy to the buffer pointed to by pszDir. The name of the working directory is truncated if it is longer than the maximum specified by this parameter.


IShellLink::Resolve [New - Windows 95]
IShellLink::Resolve

[New - Windows 95]

HRESULT Resolve(ISHELLLINK FAR * pShlLnk, HWND hwnd,

    DWORD fFlags);

Resolves a shell link. The system searches for the shell link object and, if necessary, updates the shell link path and its list of identifiers.

•	Returns the NOERROR value if successful or an OLE-defined error value otherwise.

pShlLnk

Address of the IShellLink interface. In C++, this parameter is implicit.

hwnd

Handle of a window that the shell uses as the parent window for a dialog box. The shell displays the dialog box if it needs to prompt the user for more information while resolving a shell link.

fFlags

Action flags. This parameter can be a combination of these values:

SLR_ANY_MATCH	Resolves the link, displaying a dialog box if the system needs information from the user.
SLR_NO_UI	Prevents the shell from displaying a dialog box if it cannot resolve the shell link. When this value is specified, the high-order word of this parameter specifies a time-out duration, in milliseconds. The function returns if the link cannot be resolved within the time-out duration. If the high-order word is set to zero, the time-out duration defaults to 3000 milliseconds (3 seconds).
SLR_UPDATE	Directs the shell to update the path to the link and the list of identifiers if the link object has been changed. If this value is used, it is not necessary to call the IPersistFile::IsDirty member function to determine whether the link object has changed.
When this member function is called, the system retrieves the path associated with the current link object and searches for the object in that path. If the system finds the object, it resolves the link. If the system cannot find the object, it looks in the same directory for an object with the same file creation time and attributes, but with a different name. This type of search resolves a link to an object that has been renamed.

If the system still cannot find the link object, it searches the subdirectories of the current directory. It does a recursive search of the directory tree looking for a match with either the same name or creation time. If it does not find a match after that, the shell displays a dialog box prompting the user for a location. An application can suppress the dialog box by specifying the SLR_NO_UI value in a call to this member function.


IShellLink::SetArguments [New - Windows 95]
IShellLink::SetArguments

[New - Windows 95]

HRESULT SetArguments(ISHELLLINK FAR * pShlLnk,

    LPCSTR pszArgs);

Sets the command-line arguments for a shell link object.

•	Returns the NOERROR value if successful or an OLE-defined error value otherwise.

pShlLnk

Address of the IShellLink interface. In C++, this parameter is implicit.

pszArgs

Address of a buffer that contains the new command-line arguments.

This member function is useful when creating a link to an application that takes special flags as arguments, such as a compiler.


IShellLink::SetDescription [New - Windows 95]
IShellLink::SetDescription

[New - Windows 95]

HRESULT SetDescription(ISHELLLINK FAR * pShlLnk,

    LPCSTR pszName);

Sets the description for a shell link object. The description can be any application-defined string.

•	Returns the NOERROR value if successful or an OLE-defined error value otherwise.

pShlLnk

Address of the IShellLink interface. In C++, this parameter is implicit.

pszName

Address of a buffer containing the new description string.


IShellLink::SetHotkey [New - Windows 95]
IShellLink::SetHotkey

[New - Windows 95]

HRESULT SetHotkey(ISHELLLINK FAR * pShlLnk,

    WORD wHotkey);

Sets a hot key for a shell link object.

•	Returns the NOERROR value if successful or an OLE-defined error value otherwise.

pShlLnk

Address of the IShellLink interface. In C++, this parameter is implicit.

wHotkey

Hot key. The virtual-key code is in the low-order byte, and the modifier flags are in the high-order byte. The modifier flags can be a combination of the values specified in the description of the IShellLink::GetHotkey member function.

Setting a hot key allows the user to activate the object by pressing a particular combination of keys.


IShellLink::SetIconLocation [New - Windows 95]
IShellLink::SetIconLocation

[New - Windows 95]

HRESULT SetIconLocation(ISHELLLINK FAR * pShlLnk,

    LPCSTR pszIconPath, int iIcon);

Sets the location (path and index) of the icon for a shell link object.

•	Returns the NOERROR value if successful or an OLE-defined error value otherwise.

pShlLnk

Address of the IShellLink interface. In C++, this parameter is implicit.

pszIconPath

Address of a buffer that contains the path of the file containing the icon.

iIcon

Index of the icon.


IShellLink::SetIDList [New - Windows 95]
IShellLink::SetIDList

[New - Windows 95]

HRESULT SetIDList(ISHELLLINK FAR * pShlLnk,

    LPCITEMIDLIST pidl);

Sets the list of item identifiers for a shell link object.

•	Returns the NOERROR value if successful or an OLE-defined error value otherwise.

pShlLnk

Address of the IShellLink interface. In C++, this parameter is implicit.

pidl

Address of a list of item identifiers.

This member function is useful when an application needs to set a shell link to an object that is not a file, such as a Control Panel application, a printer, or another computer.


IShellLink::SetPath [New - Windows 95]
IShellLink::SetPath

[New - Windows 95]

HRESULT SetPath(ISHELLLINK FAR * pShlLnk,

    LPCSTR pszFile);

Sets the path and filename of a shell link object.

•	Returns the NOERROR value if successful or an OLE-defined error value otherwise.

pShlLnk

Address of the IShellLink interface. In C++, this parameter is implicit.

pszFile

Address of a buffer that contains the new path.


IShellLink::SetRelativePath [New - Windows 95]
IShellLink::SetRelativePath

[New - Windows 95]

HRESULT SetRelativePath(ISHELLLINK FAR * pShlLnk,

    LPCSTR pszPathRel, DWORD dwReserved);

Sets the relative path to the shell link object.

•	Returns the NOERROR value if successful or an OLE-defined error value otherwise.

pShlLnk

Address of the IShellLink interface. In C++, this parameter is implicit.

pszPathRel

Address of a buffer that contains the new relative path.

dwReserved

Reserved; must be zero.

This function sets the relative path for a shortcut that is saved in a stream using the IPersistStream interface, or to override the default relative path tracking for a shortcut. When a shortcut is saved in a file, the system keeps track of the relative path between the file in which the shortcut is saved and the target of the shortcut (if there is one). If the link is broken, the system uses SetRelativePath to attempt to restore the link. For a shortcut is saved in a stream instead of a file, SetRelativePath allows an application to set the link between the shortcut and its target.


IShellLink::SetShowCmd [New - Windows 95]
IShellLink::SetShowCmd

[New - Windows 95]

HRESULT SetShowCmd(ISHELLLINK FAR * pShlLnk,

    int iShowCmd);

Sets the show command for a shell link object. The show command sets the initial show state of the window.

•	Returns the NOERROR value if successful or an OLE-defined error value otherwise.

pShlLnk

Address of the IShellLink interface. In C++, this parameter is implicit.

iShowCmd

Show command. For a list of the show commands, see the description of the ShowWindow function.


IShellLink::SetWorkingDirectory [New - Windows 95]
IShellLink::SetWorkingDirectory

[New - Windows 95]

HRESULT SetWorkingDirectory(ISHELLLINK FAR * pShlLnk,

    LPCSTR pszDir);

Sets the name of the working directory for a shell link object.

•	Returns the NOERROR value if successful or an OLE-defined error value otherwise.

pShlLnk

Address of the IShellLink interface. In C++, this parameter is implicit.

pszDir

Address of a buffer that contains the name of the new working directory.

The working directory must be set only if the object requires it to be set. For example, if an application creates a shell link to a Microsoft Word document that uses a template that resides in a different directory, the application would use this method to set the working directory.


Taskbar Notification Area

The Microsoft® Windows® taskbar includes a notification area where an application can put an icon to indicate the status of an operation or to notify the user about an event. For example, an application might put a printer icon in the taskbar to show that a print job is under way. The notification area is at the right end of the taskbar (if the taskbar has a horizontal orientation) or at the bottom (if the taskbar has a vertical orientation).


About the Taskbar Notification Area

An icon in the taskbar can have a tooltip control associated with it. In addition, the system can send notification messages to the application whenever a mouse event occurs in the bounding rectangle of the icon.


Sending Messages

An application sends messages to add, modify, or delete taskbar icons. To send a message, an application must use the Shell_NotifyIcon function. The function parameters include the identifier of the message to send, such as NIM_ADD, and the address of an NOTIFYICONDATA structure. The structure members contain information that the system needs to process the given message.

To add an icon to the taskbar's notification area, send the NIM_ADD message. The NOTIFYICONDATA structure that accompanies the message specifies the handle of the icon, the identifier of the icon, and, if desired, the tooltip text for the icon. If the taskbar has the Show Clock option selected, the system places the new icon to the immediate left of the clock. Otherwise, the icon appears on the right side or at the bottom of the toolbar. Any existing icons are shifted to the left to make room for the new icon.

An application can delete an icon from the taskbar notification area by sending the NIM_DELETE message. It can send the NIM_MODIFY message to modify the information that the system maintains for a taskbar icon, including its icon handle, tooltip text, and callback message identifier.


Receiving Callback Messages

Each taskbar icon can have an application-defined callback message associated with it. If an icon has a callback message, the system will send the message to the application whenever a mouse event occurs within the icon. In this way, the system can notify an application whenever the user clicks or double-clicks the icon, or moves the mouse cursor into the icon's bounding rectangle.

An application defines an icon's callback message when it adds the icon to the taskbar. The uCallbackMessage member of the NOTIFYICONDATA structure included with the NIM_ADD message specifies the identifier of the callback message. When a mouse event occurs, the system sends the callback message to the window identified by the hWnd member. The message's lParam parameter is the identifier of the mouse message that the system generated as a result of the mouse event. For example, when the mouse cursor moves into a taskbar icon, the lParam parameter of the resulting callback message contains the WM_MOUSEMOVE identifier. The wParam parameter contains the identifier of the taskbar icon in which the mouse event occurred.


Using the Taskbar Notification Area

This section includes examples that demonstrate how to add icons to the taskbar notification area and how to process callback messages for taskbar icons.


Adding and Deleting Icons

You add an icon to the taskbar notification area by filling a NOTIFYICONDATA structure and then sending the structure through the NIM_ADD message. The structure members must specify the handle of the window that is adding the icon and the icon identifier and icon handle. You can also specify tooltip text for the icon, and, if you need to receive mouse messages for the icon, the identifier of the callback message that the system should use to send the message to your window.

The function in the following example demonstrates how to add an icon to the taskbar.

// MyTaskBarAddIcon - adds an icon to the taskbar notification area.

// Returns TRUE if successful or FALSE otherwise.

// hwnd - handle of the window to receive callback messages

// uID - identifier of the icon

// hicon - handle of the icon to add

// lpszTip - tooltip text

BOOL MyTaskBarAddIcon(HWND hwnd, UINT uID, HICON hicon, LPSTR lpszTip)

{

    BOOL res;

    NOTIFYICONDATA tnid;

    tnid.cbSize = sizeof(NOTIFYICONDATA);

    tnid.hWnd = hwnd;

    tnid.uID = uID;

    tnid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;

    tnid.uCallbackMessage = MYWM_NOTIFYICON;

    tnid.hIcon = hicon;

    if (lpszTip)

        lstrcpyn(tnid.szTip, lpszTip, sizeof(tnid.szTip));

    else

        tnid.szTip[0] = '\0';

    res = Shell_NotifyIcon(NIM_ADD, &tnid);

    if (hicon)

        DestroyIcon(hicon);

    return res;

}

To delete an icon from the taskbar notification area, you must fill a NOTIFYICONDATA structure and send it to the system in the context of an NIM_DELETE message. When deleting a taskbar icon, you need to specify only the cbSize, hWnd, and uID members, as the following example shows.

// MyTaskBarDeleteIcon - deletes an icon from the taskbar

//     notification area.

// Returns TRUE if successful or FALSE otherwise.

// hwnd - handle of the window that added the icon

// uID - identifier of the icon to delete

BOOL MyTaskBarDeleteIcon(HWND hwnd, UINT uID)

{

BOOL res;

NOTIFYICONDATA tnid;

tnid.cbSize = sizeof(NOTIFYICONDATA);

tnid.hWnd = hwnd;

tnid.uID = uID;

res = Shell_NotifyIcon(NIM_DELETE, &tnid);

return res;

}


Receiving Mouse Events

If you specify a callback message for a taskbar icon, the system sends the message to your application whenever a mouse event occurs in the icon's bounding rectangle. The wParam parameter specifies the identifier of the taskbar icon, and the lParam parameter specifies the mouse message that the system generated as a result of the mouse event.

The function in the following example is from an application that adds both a battery icon and a printer icon to the taskbar. The application calls the function when it receives a callback message. The function determines if the user has clicked one of the icons and, if a click has occurred, calls an application-defined function to display status information.

// On_MYWM_NOTIFYICON - processes callback messages for taskbar icons.

// wParam - first message parameter of the callback message

// lParam - second message parameter of the callback message

void On_MYWM_NOTIFYICON(WPARAM wParam, LPARAM lParam)

{

    UINT uID;

    UINT uMouseMsg;

    uID = (UINT) wParam;

    uMouseMsg = (UINT) lParam;

    if (uMouseMsg == WM_LBUTTONDOWN) {

        switch (uID) {

            case IDI_MYBATTERYICON:

                // The user clicked the battery icon. Display the

                // battery status.

                ShowBatteryStatus();

                break;

            case IDI_MYPRINTERICON:

                // The user clicked the printer icon. Display the

                // status of the print job.

                ShowJobStatus();

                break;

            default:

                break;

        }

     }

     return;

 }


Reference

The following function, structure, and messages are associated with the taskbar notification area.


Function and Structure

The following function and structure are used with the taskbar notification area.


Shell_NotifyIcon [New - Windows 95]
Shell_NotifyIcon

[New - Windows 95]

WINSHELLAPI BOOL WINAPI Shell_NotifyIcon(DWORD dwMessage,

    PNOTIFYICONDATA pnid);

Sends a message to the system to add, modify, or delete a taskbar icon.

•	Returns TRUE if successful or FALSE otherwise.

dwMessage

Identifier of the message to send. This parameter can be one of these values:

NIM_ADD	Adds an icon to the taskbar notification area.
NIM_DELETE	Deletes an icon from the taskbar notification area.
NIM_MODIFY	Modifies an icon in the taskbar notification area.
pnid

Address of an NOTIFYICONDATA structure. The content of the structure depends on the value of dwMessage.


NOTIFYICONDATA [New - Windows 95]
NOTIFYICONDATA

[New - Windows 95]

typedef struct _NOTIFYICONDATA { // nid

    DWORD cbSize;          // sizeof(NOTIFYICONDATA)

    HWND hWnd;             // see below

    UINT uID;              // see below

    UINT uFlags;           // see below

    UINT uCallbackMessage; // see below

    HICON hIcon;           // see below

    char szTip[64];        // see below

} NOTIFYICONDATA, *PNOTIFYICONDATA;

Contains information that the system needs to process taskbar notification area messages.

hWnd

Handle of the window that receives notification messages associated with an icon in the taskbar notification area.

uID

Application-defined identifier of the taskbar icon.

uFlags

Array of flags that indicate which of the other structure members contain valid data. This member can be a combination of these values:

NIF_ICON	The hIcon member is valid.
NIF_MESSAGE	The uCallbackMessage member is valid.
NIF_TIP	The szTip member is valid.
uCallbackMessage

Application-defined message identifier. The system uses the specified identifier for notification messages that it sends to the window identified by hWnd whenever a mouse event occurs in the bounding rectangle of the icon.

hIcon

Handle of the taskbar icon to add, modify, or delete.

szTip

Tooltip text to display for the taskbar icon.


Messages

An application sends messages to add, modify, or delete taskbar icons. To send a message, an application uses the Shell_NotifyIcon function. The following messages are associated with taskbar icons.


NIM_ADD [New - Windows 95]
NIM_ADD

[New - Windows 95]

fAdded = Shell_NotifyIcon(NIM_ADD, pnid);

Adds an icon to the taskbar notification area.

•	Returns TRUE if successful or FALSE otherwise.

pnid

Address of an NOTIFYICONDATA structure that contains information about the icon to add.


NIM_DELETE [New - Windows 95]
NIM_DELETE

[New - Windows 95]

fDeleted = Shell_NotifyIcon(NIM_DELETE, pnid);

Deletes an icon from the taskbar notification area.

•	Returns TRUE if successful or FALSE otherwise.

pnid

Address of an NOTIFYICONDATA structure that contains information about the taskbar icon to delete.


NIM_MODIFY [New - Windows 95]
NIM_MODIFY

[New - Windows 95]

fModified = Shell_NotifyIcon(NIM_MODIFY, pnid);

Changes the icon, tooltip text, or notification message identifier for an icon in the taskbar notification area.

•	Returns TRUE if successful or FALSE otherwise.

pnid

Address of an NOTIFYICONDATA structure that contains the information used to change the icon, tooltip text, or notification message identifier for the taskbar icon.


File Viewers

A file viewer is an OLE component object (not a compound document object) implemented inside a 32-bit in-process server dynamic-link library (DLL), which is associated, in turn, with the file viewer's class identifier. A file viewer provides the user interface for viewing a file. Menu items, a toolbar, and a status bar are standard parts of the file viewer interface. A file viewer can optionally add other functionality for further shell integration.


About File Viewers

The Microsoft® Windows® 95 shell allows the user to browse the information in the file system and on the network. The Quick View feature of the shell allows the user to quickly view the contents of a file without having to run the full application that created it and without even the presence of the application. To view the file contents, the user selects a file and chooses the Quick View command from the context menu of the selection (or from the File menu). The following illustration shows the context menu.

In response to the user choosing the Quick View command, the shell activates a file-specific viewer for the selected file. The shell uses the extension of the file to determine which viewer to activate. A file viewer associates itself with file classes and filename extensions in the system registry.

A file viewer is an OLE component object (not a compound document object) implemented inside a 32-bit in-process server dynamic-link library (DLL), which is associated, in turn, with the file viewer's class identifier. A file viewer provides the user interface for viewing a file. Menu items, a toolbar, and a status bar are standard parts of the file viewer interface. A file viewer can optionally add other functionality for further shell integration.

A file viewer object, which is separate from the class factory object in the in-process server, uses the standard OLE IPersistFile interface as well as the IFileViewer interface described later in this article. The shell does not interact directly with file viewer objects. Instead, the shell starts an instance of a small program called Quick View (QUIKVIEW.EXE) for each file to be viewed. Each instance of Quick View defines a process for a file viewer, giving the viewer its own message queue. Although Quick View is a Windows executable file, it is not a complete Windows-based application. It associates a path with a file viewer, creates an instance of the file viewer object, and instructs the file viewer to load and display the file.

Because a file viewer is an OLE component object, additional interfaces and functionality can be added in future versions of Windows to support new features. For example, a file viewer can act as an OLE container application and can perform in-place activation of embedded objects inside the file being viewed. A file viewer can let the user make a selection in a document and copy the selection to the clipboard or use the selection in a drag and drop operation. However, such functionality is entirely up to the developer of the file viewer. This article describes the basic functionality that a file viewer must provide and discusses user interface guidelines that all developers of file viewers should follow.


Adding or Replacing File Viewers

The File Viewer interfaces allow you to add file viewers to Windows 95. For example, you may need to add a file viewer that supports a new file format or provides additional functionality. To understand how to add a file viewer to Windows 95, it is important first to understand how the default file viewers work.

The shell calls the Quick View program to display a file. Quick View manages the file viewing process and presents error messages for error conditions returned by the display engines — a collection of DLLs that draws the viewer window and displays the file. Windows 95 includes display engines for word processing documents, spreadsheets, databases, vector graphics, and raster graphics. File parser DLLs are associated with a particular display engine and are specific to a type or class of files. For example, spreadsheet and database files are associated with the spreadsheet or database display engine. These DLLs are typically between 25K and 75K in size and do all the low-level parsing of the files to be viewed.

There are two methods to add file viewing functionality to Windows 95. First, a particular file parser DLL may be added to the system. The advantage of this method is that file parsers are relatively straightforward to write and debug. The disadvantage is that the limitations built into the default display engines (such as no printing and no cut, copy, and paste operations) remain even when a new file parsing DLL is used. For more information about the interface between the file parsers and the display engines, see "File Parsers."

The second method of including file viewing functionality in Windows 95 is to add one or more DLLs that work directly with Quick View. The interaction between QUIKVIEW.EXE and the display engines is the subject of this article. An example of one of these file viewing systems for ASCII files is found in the Samples subdirectory of the Microsoft® Win32® Software Development Kit (SDK). The main advantage of this method is that the code you write can support whatever file viewing functionality you wish to provide. This may be particularly important if your file format does not display well with one of the four default display engines. For example, an accounting package might have this problem. The main disadvantage of this method is that writing for the Quick View interface requires more development and testing effort.

The remainder of this article discusses the interaction between QUIKVIEW.EXE and the display engines. The discussion is split into three sections. The first section describes the entries in the registry necessary to support associations between a pathname and a file viewer. The second section describes how the shell starts Quick View and outlines the steps Quick View performs to locate an appropriate file viewer and activate it. The last section describes the structure and implementation of a file viewer OLE component, including the recommended user interface features.

The file viewing technology used by the Quick View feature in Windows 95 was developed jointly by Microsoft Corporation and Systems Compatibility Corporation.


File Viewer Registration

During installation, a file viewer should ensure that entries exist in the registry that accurately associate a file with the class identifier of the file viewer's in-process server DLL. The file viewer's installation program may merge the contents of a registration (.REG) file into the registry. A file viewer can register itself for more than one file type if it can handle multiple file formats. If a file type has more than one registered file viewer, the shell activates the most recently registered viewer for the file type when the user chooses the Quick View command.


Determining File Types

The Quick View program attempts a simple association using the filename extension. If there is no filename extension or if there are no file viewers registered for the filename extension, Quick View calls each registered file viewer to see if any of them recognize the file. If more than one file viewer is registered for the same filename extension, Quick View calls each file viewer starting with the last one in the list. If Quick View cannot find a file viewer that can read the file, the Quick View operation fails and Quick View displays the following message.

There are no viewers registered for this type of file. Would you like to try the default viewer?

The default viewer displays a hexadecimal dump using the word processing engine.

For more information, see "Quick View Program" later in this topic.


Structure of Registry Entries

The following registry structure is required for Quick View to associate a class identifier or filename extension with the class identifier of a file viewer.

HKEY_CLASSES_ROOT

    \QuickView

        \<extension> = <human-readable document type>

            \{<CLSID>} = <human-readable viewer name>

            \{<CLSID>} = <human-readable viewer name>

            \{<CLSID>} = <human-readable viewer name>

        ...[More extension entries for additional file types]

            ...

    \CLSID

        \{<CLSID>} = <human-readable viewer name>

            \InprocServer32 = <full path to file viewer DLL>

                            = ThreadingModel = "Apartment"

        ...[More class IDs for file viewers and other object servers]

A description of the registry entries follows.

Entry	Description
HKEY_CLASSES_ROOT	Root of the registry.
QuickView	Top-level key under which associations are stored.
CLSID	16-byte OLE class identifier spelled out in hexadecimal digits in the form of 12345678-1234-1234-1234-1234567890AB with the hyphens included. All class identifiers are surrounded by curly braces when stored in the registry.
human-readable document type	String describing the file type associated with the class identifier or filename extension that can be displayed to the user. A file viewer can change the type when it is installed so that the name always reflects the preferred viewer. For example, this string might be "Windows Write Document."
human-readable viewer name	String that describes the vendor of the file viewer, as it might be displayed in an About box, such as "Company ABC Write Document Viewer."
<extension>	Three-character filename extension with the period, as is consistent with the standard 8.3 filename format — for example, .WRI.
CLSID and InprocServer32 are standard OLE (32-bit) subkey names. The "ThreadingModel = Apartment" entry is required for file viewers. The apartment threading model, which is new for OLE in Windows 95 and Microsoft® Windows NT™ version 3.51, allows the OleInitialize and CoInitialize functions to be called from multiple threads.

The QuickView key can have any number of filename extension subkeys, each representing a registered file type. Each filename extension subkey can have one or more class identifier subkeys, each representing a registered file viewer object. The most recently registered file viewer appears first in the list of class identifier subkeys, and it is the first one found when Quick View enumerates the registered file viewers.

Note  The file viewer class identifier should always differ from the file type class identifier because the application that created the file may already be using the class identifier to identify the application as a compound document server.

Each class identifier stored under the filename extension subkeys must correspond to an entry of the same class identifier stored under the top-level key called CLSID. This is the standard location for storing information for OLE object servers. For file viewers, there must be an InprocServer32 subkey under the file viewer's class identifier key. The value of the InprocServer32 subkey is the full path to the file viewer DLL. You should store the full path and not depend on the DLL being in the path of the Windows 95 environment. InprocServer32 is a standard OLE subkey where the path to a component object server is stored. Using this subkey allows the Quick View program to use standard OLE member functions to access and create objects from file viewer servers.


Registering a File Viewer

This section shows how to register a hypothetical file viewer for "AcmeWord Document" files with the .AWD filename extension. The file viewer is implemented in an in-process server DLL called ACMEWRDV.DLL. The DLL has this class identifier: 00021116-0000-0000-C000-000000000046. The program that installs the file viewer creates the following registry entries.

HKEY_CLASSES_ROOT

    \QuickView

        \.AWD = AcmeWord Document

            \{00021117-0000-0000-C000-000000000046} = AcmeWord Document
                                                      Viewer

    \CLSID

        \{00021117-0000-0000-C000-000000000046} = AcmeWord Document
                                                  Viewer

            \InprocServer32 = c:\acmeword\acmewrdv.dll

                            = ThreadingModel = "Apartment"

The .REG file, which is an ASCII text file, contains these entries. (Note that wrapped lines are indented on the second line.)

HKEY_CLASSES_ROOT\QuickView\.AWD = AcmeWord Document

HKEY_CLASSES_ROOT\QuickView\.AWD \{00021117-0000-0000-C000-
    000000000046} = AcmeWord Document Viewer

HKEY_CLASSES_ROOT\CLSID\{00021117-0000-0000-C000-000000000046} =
    AcmeWord Document Viewer

HKEY_CLASSES_ROOT\CLSID\{00021117-0000-0000-C000-000000000046}
    \InprocServer32 = c:\acmeword\acmewrdv.dll

                    = ThreadingModel = "Apartment"

The Quick View program uses these registry entries to associate a path with the class identifier of a file viewer's in-process server DLL.


Quick View Program

The Quick View program (QUIKVIEW.EXE) acts on behalf of the shell to locate and activate a file viewer for a given path. There is a one to one correspondence between each running instance of Quick View and each file being displayed in a file viewer. Each instance of Quick View defines a process for a file viewer, giving the file viewer its own message queue. Quick View turns over execution of the process to the file viewer until the file viewer shuts down.


Quick View Execution and Error Conditions

The lifetime of each instance of the Quick View program consists of the following steps:

1.	When the user chooses the Quick View or Print command, the shell starts an instance of QUIKVIEW.EXE for each selected file (by using the Win32 CreateProcess or WinExec function). The shell may specify a show command, and Quick View passes the command to the file viewer. The command-line argument that the shell passes to Quick View has the following options.

Option	Meaning
-f:pathname	Path of the file to view or print. Universal Naming Convention (UNC) filenames are allowed. If this option is not specified, Quick View terminates without displaying any messages.
-v	File to be opened for viewing in the file viewer. If this option is specified, Quick View ignores all of the options described below. This is the default option in the absence of both -v and -p.
-d	Quick View and the file viewer to suppress all user interface (UI) elements if -p is also specified. Quick View suppresses any error messages, and the file viewer should not display any dialog boxes for printing. Quick View ignores this option in the absence of -p.
-p	File to be opened for printing. If -v is also present, Quick View ignores this option.
-&:pathname	Printer driver to use to print the file. Quick View ignores this option in the absence of -p. If -p is present but -& is not, Quick View instructs the file viewer to use the default printer driver.
2.	Quick View starts and checks for a path on the command line. If there is no path, the user has attempted to start Quick View by itself and the program immediately terminates without displaying any messages.

3.	Quick View parses the filename extension from the path given in the -f option. If no filename extension is given, Quick View proceeds to stage E1 (error condition 1). Otherwise, Quick View uses the following procedure to find a file viewer class identifier associated with the given filename extension.

a.	Quick View attempts to open the HKEY_CLASS_ROOT\QuickView\extension key, where extension is parsed from the path.

i.	If the filename extension maps to a type such as HKEY_CLASS_ROOT\extension = typename and there is a registry entry with the form HKEY_CLASS_ROOT\typename\QuickView = *, Quick View looks for file viewer class identifiers under HKEY_CLASS_ROOT\QuickView\*. If a key with the HKEY_CLASS_ROOT\*\QuickView = * form exists, the system attempts to use all the viewers listed under the "*" section.
ii.	Otherwise, Quick View begins enumerating the file viewer class identifiers under the HKEY_CLASS_ROOT\QuickView\extension key. If the enumeration fails (that is, there is nothing in the registry to enumerate), Quick View closes the key and proceeds to stage E2. Otherwise, Quick View reads the first file viewer class identifier in the enumeration and proceeds to step 4.
b.	If an error occurs in step 4, the enumeration continues until all file viewer class identifiers have been tried. If no file viewer is activated, Quick View closes the key from (a) and proceeds to stage E2.

4.	Given a class identifier of a file viewer DLL, Quick View attempts to create an instance of a file viewer object of the given class by using the following procedure.

a.	Quick View calls a function to create an instance of a file viewer object, specifying parameters that include the class identifier and the IID_IPersistFile interface identifier. This instructs OLE to load the DLL listed under the class identifier's InprocServer32 subkey, obtain an instance of the object from the DLL, and return an IPersistFile interface pointer to the object. If the instance cannot be created because of lack of memory, Quick View proceeds to stage E4. If it fails for some other reason, Quick View proceeds to stage E3. (Note that, because DLL objects are involved, any call to QueryInterface will not fail with REGDB_IID_NOTREG, which typically signals a corrupted registry. That error is generated only when LRPC proxies and stubs are involved.)

b.	Given the IPersistFile interface pointer pIPersistFile, Quick View calls the Load member function of the IPersistFile interface, specifying the path of the file and the STGM_READ and STGM_SHARE_DENY_NONE values, which instruct the object to open the file for read access. If Load fails, Quick View calls the Release member function of pIPersistFile and proceeds to stage E4 if the error is due to a lack of memory. Otherwise, Quick View proceeds to stage E3.

c.	Quick View obtains the file viewer object's IFileViewer interface by specifying the IID_IFileViewer interface identifier in a call to the QueryInterface member function of pIPersistFile. Quick View calls the Release member function of pIPersistFile, regardless of the outcome. If this call fails due to lack of memory, Quick View proceeds to stage E4. Otherwise, Quick View proceeds to stage E3.

d1.	If the -v option was present or both the -v and -p options were absent, Quick View calls the ShowInitialize member function of pIFileViewer, which instructs the file viewer to load the file and perform any preshowing initialization that is prone to failure (including the creation of windows, the loading of resources, and so on). This is the file viewer's one chance to fail. If it fails, Quick View proceeds to stage E4 if the error is due to lack of memory or to stage E3 otherwise. If ShowInitialize succeeds, Quick View calls the Show member function of pIFileViewer, specifying the show command that was passed to Quick View's WinMain function. Show does not return until the user closes the file viewer, and it always returns NOERROR in that case. If Show is called before ShowInitialize, it returns E_UNEXPECTED.

d2.	If the -p option was present (and the -v option was absent), Quick View calls the PrintTo member function of pIFileViewer specifying the path of the printer driver provided in the -& option (or NULL if -& was absent) and a value indicating if the -d option was present on the command line (UI suppression flag). PrintTo does not return until printing is complete or an error occurs. If an error occurs, the file viewer is responsible for notifying the user if the UI suppression flag is FALSE.

e.	When Show or PrintTo returns (whichever was called in steps d1 or d2), Quick View calls the Release member function of pIFileViewer, regardless of the return value. If the file viewer successfully executed the IFileViewer::ShowInitialize member function, the Release member function will not fail. Release fails only if it is called before ShowInitialize. If PrintTo fails but the -d option was not specified on the command line, Quick View assumes that the file viewer displayed a message to indicate printing failed, and Quick View fails without displaying a message in that case. In any case, Quick View proceeds to step 5.

5.	Quick View releases any interface pointers it may have had and calls OleUninitialize (which calls CoFreeUnusedLibraries internally). Quick View then terminates normally.

Quick View may encounter these four error conditions (stages E1 through E4) during the lifetime of an instance.

E1.	If Quick View fails to associate the path with a file viewer class identifier (using a filename extension), it displays this message.

There are no viewers for this type of file. Would you like to try the default viewers.

If the user clicks No, Quick View terminates. If the user clicks Yes, Quick View displays the Searching dialog box, enumerates all registered file viewers (regardless of file type or filename extension ), and attempts to have each one load and display the file. Quick View tries each file viewer of a given class identifier once. If no file viewer successfully displays the file, Quick View removes the Searching dialog box and displays this message.

Error opening or reading file.

When the user closes the dialog box, Quick View terminates.

E2.	 If Quick View successfully determines the file type but fails to enumerate any file viewers associated with the filename extension, it displays the Searching dialog box and attempts to have each registered viewer display the file, trying each file viewer class identifier once. If that fails, the Quick View removes the Searching dialog box and displays this message.

There are no viewers capable of viewing <human-readable document type> files.

When the user closes the dialog box, Quick View terminates.

E3.	If Quick View successfully locates an initial file viewer but fails to view the file for any reason other than an out of memory condition, Quick View displays the Searching dialog box and continues enumerating viewers under the class identifier or filename extension key currently in use (steps 3d or 4c). If Quick View tries all viewers registered for the type unsuccessfully, processing continues as in stage E2 by trying all registered viewers regardless of registered type.

E4.	If an out of memory condition occurs for one file viewer, it is likely that other viewers will not succeed either. In that case, Quick View displays a dialog box (using MB_ICONEXCLAMATION) with this message.

There is not enough memory to view or print <filename>. Quit one or more files or programs, and then try again.

A file viewer can return a number of error values to Quick View. When Quick View receives an error value, it displays an error message. Quick View recognizes the following error values.

FV_E_BADFILE 	((HRESULT)0x8534E102L)
FV_E_EMPTYFILE	((HRESULT)0x8534E108L)
FV_E_FILEOPENFAILED	((HRESULT)0x8534E105L)
FV_E_INVALIDID	((HRESULT)0x8534E106L)
FV_E_MISSINGFILES	((HRESULT)0x8534E104L)
FV_E_NOFILTER	((HRESULT)0x8534E100L)
FV_E_NONSUPPORTEDTYPE	((HRESULT)0x8534E101L)
FV_E_NOVIEWER 	((HRESULT)0x8534E10AL)
FV_E_OUTOFMEMORY	((HRESULT)0x8534E107L)
FV_E_PROTECTEDFILE	((HRESULT)0x8534E109L)
FV_E_UNEXPECTED	((HRESULT)0x8534E103L)


Pinned Windows

The shell can request Quick View to display a new file in the same window as that used by the previous file viewer; that is, Quick View can "pin" a viewer window. Quick View communicates the shell's request by sending a WM_DROPFILES message to the file viewer. The message contains an internal drop files structure whose members include the path of the new file to be displayed. A file viewer uses the same code to handle both the "pinned" state and drag and drop operations in which the file viewer displays a file that the user has dragged and dropped on the file viewer's window.

Quick View implements the IFileViewerSite interface, which allows a file viewer to retrieve the handle of the current pinned window, if there is any, or set a new pinned window. When Quick View calls a file viewer's IFileViewer::ShowInitialize member function, the file viewer receives the address of Quick View's IFileViewerSite interface. If the file viewer saves the address of the interface, it should call the IFileViewerSite::AddRef member function to increment the reference count.

Only one pinned window can exist at a time. A file viewer uses the IFileViewerSite::SetPinnedWindow interface to set a new pinned window and the IFileViewerSite::GetPinnedWindow interface to retrieve the handle of the current pinned window.

When Quick View calls the file viewer's IFileViewer::Show member function, the file viewer receives the address of a FVSHOWINFO structure that includes a optional RECT structure. A valid RECT structure is a hint from the shell that the file viewer window should be pinned; the file viewer should set the size and position of its window based on the information in the structure.

If the file viewer window receives a WM_DROPFILES message, it should fill in the strNewFile member of the FVSHOWINFO structure with the path of the new file to be displayed, fill the rect member with the size and position of the viewer window, and set the appropriate values in the dwFlags member. The file viewer should also fill the punkrel member with the address of an interface that the new file viewer should call to release the previous file viewer. Doing this allows the previous file viewer to perform cleanup operations. The new file viewer may be the same as the current file viewer if the current one supports the new file. If the old file viewer is the same as the new one, the release does not do anything because the reference count is greater than zero.

If a file viewer returns a file but Quick View cannot find a viewer for the new file, it calls the IFileViewer::Show member function for the old file viewer with the FVSIF_NEWFAILED value. The file viewer can either terminate or continue showing the previous file.


Searching Dialog Box

When Quick View must enumerate more than one file viewer from the registry, it displays a dialog box containing a message that reads, as follows.

Searching for a viewer to display or print the <human-readable

document type> in <filename>. Press Cancel to stop the search.

If the document type is not known, the following message appears.

Searching for a viewer to display or print <filename>.

Press Cancel to stop the search.

Quick View animates the magnifying glass icon in the dialog box to indicate that Quick View is searching the hard disk. Pressing the Cancel button stops any search in progress and closes Quick View without performing any further actions or providing any user interface.


File Viewer Structure and Implementation

A file viewer is an OLE component object in an in-process server DLL where the object implements the IPersistFile and IFileViewer interfaces. The in-process server exports the DllGetClassObject and DllCanUnloadNow functions, implements a class factory object with the IClassFactory interface, and implements the file viewer object with the interfaces required. The following illustration shows the structure of a file viewer.

There are a number of reasons why a file viewer is best implemented in a DLL with the given interfaces. In general, a DLL is faster to load and usually comes in a small package. In the future, these same DLLs will provide other nonuser interface features, such as content indexing, and a component object DLL will be the most efficient and fastest way to access those features. In some cases, a file viewer object may need to display pop-up windows and process messages through its own message loop as in Windows 95. The DLL structure still allows this when used in conjunction with a stub process like Quick View, which gives the file viewer DLL the right to execute a message loop.

The IPersistFile interface in the file viewer object is intended to be a general mechanism through which the object is given a path for a file. From then on, the component that loaded the object can ask it to do any number of things with the file. Through Quick View, the Windows 95 shell asks the object to show the file  by using the IFileViewer::ShowInitialize and IFileViewer::Show member functions or asks the object to print the file to a specific printer by using the IFileViewer::PrintTo member function. In the future, the shell may ask the object to perform content indexing, which would happen through an interface other than IFileViewer. For this reason, the file loading member functions of IPersistFile are separate from the operations that perform on the file, which is why IFileViewer was not just extended with its own Load member function. This latter option is a little more efficient (because it avoids IPersistFile entrypoint functions that are not implemented), but the design given here is easier to extend.


IFileViewer Interface

The shell uses the IFileViewer interface to tell a file viewer object when to show its user interface for the file being viewed or to print the file. In addition to the usual IUnknown members, the interface includes the ShowInitialize, Show, and PrintTo member functions.

Before calling the Show member function, the shell calls ShowInitialize to instruct the file viewer to perform any creations, allocations, or loading. ShowInitialize may fail, whereas Show may not because Quick View needs to know, before anything becomes visible and before transferring control to the file viewer, whether the file viewer can show the file. If the file viewer can show the file, Quick View hides its Searching dialog box before the file viewer window appears.

The ShowInitialize member function should return the same FV_ error codes listed in "Structure of Registry Entries" earlier in this topic. Although the sample file viewer included in the Win32 SDK uses a more generic form of error codes, new file viewer DLLs should use the FV_ form.

The Show member function is similar to the Windows ShowWindow function in that it receives a Show command indicating how the file viewer should initially display its window. The meaning of the Show command is exactly the same as for ShowWindow. In general, Quick View passes the Show command from its WinMain function directly to IFileViewer::Show, which passes the command to ShowWindow. Since Quick View obtains this parameter from the shell, this design enables the shell to open a file viewer in the minimized, normal, or maximized state and even allows the shell to hide a file viewer (with the SW_HIDE value). There is no extra overhead in providing this flexibility. Note that the Windows 95 shell always starts Quick View with the SW_SHOWNORMAL value.

The only case when Show may fail is if ShowInitialize has not been called. In that case, it returns the E_UNEXPECTED status code (SCODE). Otherwise, Show must return the NOERROR error code.

The PrintTo member function is like Show in that it does not return until it finishes printing or an error occurs. If an error occurs, the file viewer object is responsible for informing the user of the problem. When calling PrintTo, the shell specifies the name of the printer driver that the file viewer should use to print the file. The shell also specifies a flag that indicates whether the file viewer should display any UI elements, including error message, during the print operation. If the flag is FALSE, the file viewer may show Print dialog boxes, Printer Setup dialog boxes, error messages, and so on.

The interface identifier of IFileViewer is defined in the Windows header files as the IID_IFileViewer interface identifier.


File Viewer Creation

You can create a file viewer that interacts appropriately with Quick View by following these steps:

1.	Define the file viewer object to use the IPersistFile and IFileViewer interfaces. The object must also implement a separate IUnknown interface that does not delegate calls in aggregation situations. In general, a file viewer object creates or attaches to a window that displays a file's contents.

2.	Implement the Load and GetCurFile member functions (as well as the IUnknown member functions) of the IPersistFile interface. The IsDirty member function can simply return ResultFromScode(S_FALSE) because a file viewer does not modify the file, and the Save and SaveCompleted member functions should simply return ResultFromScode(E_NOTIMPL). Load stores the filename, but delays opening the file until the later call to the IFileViewer::ShowInitialize member function. GetCurFile returns ResultFromScode(E_UNEXPECTED) if Load has not yet been called. Otherwise, it copies the pathname and returns the NOERROR error code.

3.	Implement the IFileViewer::ShowInitialize and IFileViewer::Show member functions (as well as the IUnknown member functions of IFileViewer). ShowInitialize must perform all operations that are prone to failure such that if ShowInitialize succeeds, Show will never fail. The implementation of these two member functions is like an implementation of an application's WinMain function, where ShowInitialize registers window classes (using the instance handle that the DLL receives in its DllEntryPoint function, not the instance of Quick View), creates the necessary windows to meet the UI guidelines, and loads the file as read-only with the path given in IPersistFile::Load. Then Show displays the contents of that file in the viewport window, shows the top-level file viewer window, and enters a message loop. To enhance the appearance of the UI, the file should be loaded and completely displayed in the viewport window before the windows are made visible.

Show does not return until the user has closed the window; that is, Quick View waits for Show to return before terminating. Quick View delegates the responsibility of the message loop to the Show member function, so ShowInitialize and Show look and behave exactly like a WinMain function in any application (the code is just stored in a DLL).

Note that the path in the IPersistFile::Load member function may be a uniform naming convention (UNC) path. Functions such as Win32 OpenFile and OLE StgOpenStorage automatically handle UNC paths. If you open a file any other way, you must be sure to handle UNC paths properly.

4.	Define the class factory object with the IClassFactory interface and implement the interface completely to create a file viewer object. The class factory must support aggregation and server locking, as required by the IClassFactory interface.

5.	Implement the DllGetClassObject function to create an instance of the class factory mentioned in step 4 and return a pointer to one of its interfaces, as required for any component object DLL.

6.	Implement the DllCanUnloadNow function to return the appropriate code, depending on the number of file viewer objects in service and the number of lock counts implemented by using the IClassFactory::LockServer member function, as required for any component object DLL.

7.	Include the Print To feature by using the IFileViewer::PrintTo member function. This step is optional. If this feature is not implemented, the member function must return ResultFromScode(E_NOTIMPL).

8.	Finish the DLL implementation by using the DllEntryPoint function, as required for any Win32 DLL.

In general, only the implementations of IPersistFile::Load and the IFileViewer member functions are specific to a file viewer. The other steps that deal with creating an OLE component object are standard OLE mechanisms. For more information about these mechanisms, including objects and interfaces, see the OLE documentation included in the Win32 SDK as well as Chapters 3 and 4 of Inside OLE 2 from Microsoft® Press.


File Viewer User Interface Guidelines

This section describes the minimal user interface recommended for a file viewer. These guidelines are provided to promote a consistent user interface in all file viewers. You should follow these guidelines as closely as possible and include viewer-specific features within the context of these guidelines.


Window Appearance

A file viewer's main window should have Minimize, Maximize, and Close buttons and these top-level menu items: File, View, and Help (the contents of these menus is described later). A file viewer should also include a toolbar and a status window. The appearance and contents of the viewport window, which occupies all space not used by the toolbar and status window, is left to the developer. However, the viewport window typically has proportional scroll bars if the file contents are not entirely visible in the viewport.

The following illustration shows the typical initial state of a file viewer window. The initial state can be minimized or maximized if the file viewer is given a different show command through the IFileViewer::Show member function.

A file viewer can include other top-level menu items for file-specific features. For example, a file viewer should include an Edit menu with a single &Copy item to allow the user to make a selection in the viewport window and copy it to the clipboard. However, such extensions are not part of the basic user interface for a file viewer.

You should also use the new window flags in Windows 95 to create a three-dimensional window appearance and use scroll bars with proportional scroll boxes.


File Menu Items

The standard file viewer File menu has the following four items (as well as separators), two of which are optional. A file viewer can add other items to the menu, but in most cases there is no need for other items.

Menu item string	Result of selecting the menu item
"&Open File for Editing"	Locates and starts the application that can open and edit the file. After successfully starting the application, the file viewer should hide its window immediately, shut down, and eventually return from IFileViewer::Show, after which the Quick View process terminates. If the file viewer fails to start the application, it should display the following message. There is no application available that can open this file.
Separator	Not applicable.
"Page Set&up" (optional)	Activates the standard Page Setup dialog box (or an application-specific dialog box if desired), the results of which affect the display of the file in the viewport window. The effects of the Page Setup command last only for the duration of the file viewer and do not affect the contents of the disk file. This menu item should appear if the file viewer supports printing and only if the Print menu item appears as well.
"&Print\tCtrl+P" (optional)	Activates the standard Print/Printer Setup property sheet. Any changes made to the printer setup that would affect the display of the file in the viewport window last only for the duration of the file viewer and do not affect the contents of the disk file. This menu item should appear only if the file viewer supports printing a file without starting the full application.
Separator	Not applicable.
"E&xit"	Hides the window, closes the file, destroys all the windows, performs other necessary cleanup, and returns with the NOERROR error code from IFileViewer::Show. The window should be hidden before cleanup happens to avoid marring its appearance, when the system destroys the toolbar and other controls.


View Menu Items

The View menu of a standard file viewer has the following items.

Menu item string	Result of selecting the menu item
"&Toolbar"	Toggles the visibility of the toolbar. This item is checked when the toolbar is visible and unchecked when it is hidden.
"&Status Bar"	Toggles the visibility of the status window. This item is checked when the status line is visible and unchecked when it is hidden.
"&Page View"	Toggles between a full-sized view and a single-page view.
"Replace &Window"	Toggles between reusing the current window to view a file and creating a new window to view a file.
Separator	Not applicable.
"&Landscape"	Toggles between landscape and portrait view when in page view.
"&Rotate"	Rotates a raster graphic image 90 degrees every time the image is selected.
Separator	Not applicable.
"&Font"	Displays a dialog box that allows the user to select a font and point size for viewing word processing documents and spreadsheets.


Help Menu Items

The standard file viewer Help menu has the following items.

Menu item string	Result of selecting the menu item
"&Help Topics"	Activates WINHELP.EXE with the file viewer's help file.
"&About fileviewer name"	Displays an About dialog box for the file viewer. The About dialog box identifies the vendor of the file viewer.
A file viewer can also add other help items and context-sensitive help.


Toolbar Buttons

A file viewer must include a toolbar with a single button tied to the Open File for Editing menu item on the File menu described previously. The image in this button is a 16- by 15-pixel bitmap derived from the icon of the application that would be started if the user opened the file from the shell (using the shell's association route). The image is obtained by calling the SHGetFileInfo function with the path of the file. If this function fails, a file viewer can include a button that contains its own image and attempt to start the parent application, or the file viewer can remove the button and disable the Open File for Editing menu item on the File menu. This single button must be the leftmost item on the toolbar and must be separated from any other buttons that are specific to the file viewer.

Other buttons should correspond roughly to the functions present in the file viewer menus. A file viewer that supports a Font menu item should have Increase Font Size and Decrease Font Size buttons. Other file viewer classes may need to include printing and rotation buttons on the toolbar.

A standard toolbar button is the Replace Window button. The default behavior for file viewers is for a new file viewer instance to be created whenever the user chooses the Quick View menu item. When the Replace Window button is toggled to the on position, however, a new instance is not created; instead, the contents of the relevant file viewer window are replaced by a view of the new file.

All buttons should have a corresponding tooltip control that displays some context information when the mouse cursor is positioned on the button. The standard Windows 95 toolbar control provides built-in support for tooltip controls such that you only have to provide the text string. <> The following illustration shows a tooltip control for a toolbar button.

The recommended tooltip strings for various toolbar buttons follow.

Toolbar button	Tooltip string
Open File for Editing	"Open File for Editing"
Font Increase	"Increase Font Size"
Font Decrease	"Decrease Font Size"
Small View	"Toggle view size"
Landscape	"Toggle portrait/landscape"
Rotate [Again]	"Rotate image 90 degrees"
Replace Window	"Replace Window"


Status Window Messages

A file viewer should display status window messages for the system menu and all top-level and pop-up menu items. The messages for the system menu and other menu items used by the default Windows 95 file viewers follow.

[Menu] item	Message
[System]	"Commands for manipulating this and other windows."
[System] Restore	"Restores this window to normal size." / "Expands this window to full screen size."
[System] Move	"Move this window to another screen location."
[System] Size	"Resizes this window."
[System] Minimize	"Collapses this window to an icon."
[System] Maximize	"Expands this window to full screen size."
[System] Close	"Closes this window."
[System] Switch To...	"Switch to another task."
[File]	"Contains commands for opening the file and quitting Quick View."
[File] Open File for Editing	"Opens the file for editing."
[File] Page Setup	"Changes the page setup for printing."
[File] Print...	"Prints the file contents."
[File] Exit	"Quits Quick View."
[View]	"Contains commands for customizing this window."
[View] Toolbar	"Shows or hides the toolbar."
[View] Status Bar	"Shows or hides the status bar."
[View] Page View	"Switches between document and page views."
[View] Replace Window	"Displays new files in current Quick View window."
[View] Landscape	"Switches between portrait and landscape."
[View] Rotate (Again)	"Rotates the image by 90 degrees."
[View] Font	"Changes the display font."
[Help]	"Contains commands for displaying Help and information about Quick View."
[Help] Help Topics	"Displays the Help Contents and Index."
[Help] About	"Displays program information, version number and copyright."
The following standard messages for other conditions not related to menu items are implemented in the Windows 95 default file viewers:

•	In the inactive state, when the user is doing nothing else, the status line should read as follows.

Display details may be inaccurate.

This line should be the first visible message when the file viewer appears.

•	When the mouse cursor is positioned over the viewport window, the status window should read as follows.

To edit, click Open File for Editing on the File menu.

Note that the document type is specific for the file viewer in use, as shown in the following illustration.

•	The status window should reflect longer versions of tooltip messages when tooltip controls are displayed. For example, a longer version of the "Increase Font Size" tooltip is "Increase the font size of the display" shown at the same time in the status window.


Viewport Window Contents and Context Menu

The viewport window is where you provide most file-specific UI elements. The viewport occupies all space in the client area of the main window not used for the toolbar and status bar. It displays the file contents in whatever mode is applicable, and it is sensitive to the user-selected printer and page setup, as well as other View menu commands.

If the contents of the file are too large to be completely displayed within the viewport, the file viewer should provide scroll bars (with proportional scroll boxes) to shift the image. If the contents of the file are smaller than the viewport window, no scroll bars should appear. In addition, the file contents should not be initially scaled to fill the viewport window unless the user selects scaling through the View menu commands.

The only other requirement for the viewport window is that it should provide a context menu for the file. The context menu should appear when the user clicks the viewport with the mouse button 2. The context menu should include the following items.

Menu item string	Equivalent found on other menu
"&Open File for Editing"	Open File for Editing command on the File menu
Separator	Not applicable
"Page Se&tup" (optional)	Page Setup command on the File menu
"&Print" (optional)	Print command on the File menu (note, no accelerator)
Separator	Not applicable
A file viewer may add more items as necessary. The Toolbar and Status bar menu items commands on the View menu should not appear in the context menu.


Drag and Drop Functionality

The default file viewers in Windows 95 allow the user to drag a file from the desktop or Explorer and drop the file on a file viewer's window. A file viewer should show the small document icon that includes the "+" sign when the mouse is over the file viewer's window before the drop takes place. The Replace Window command in the View menu controls whether another file viewer window is displayed or the same window is reused.


Sophisticated File Viewers

This article only describes the minimal file viewer UI. There are, of course, many other possibilities besides just rudimentary printing and viewing capabilities. One useful feature is the ability to copy data from a document either to the clipboard or in a drag and drop operation. In such cases, the file viewer needs to provide the ability to select data in the file, a Copy command (on an Edit menu as well as in a context menu), and the ability to pick up the selection and drag it elsewhere. However, the file viewer should not be a drop target and should not support the Cut and Paste commands on the Edit menu (or other variants) because those operations modify the file.

If the parent application creating the files that are handled in a specific file viewer is an OLE compound document container, the file viewer itself must be sensitive to viewing a compound document. That means that the file viewer itself will support some minimal container features and will, of course, use OLE to load and display compound document objects in the file itself. If the file viewer also supports in-place activation, it can activate inside-out objects in-place to allow the user to select and copy data from embeddings. While there are no standards for such functionality in Windows 95, there will be in future versions of Windows.


Reference

A file viewer in-process server DLL must implement the IFileViewer and IPersistFile interfaces. This section describes the IFileViewer interface and its member functions. For information about the IPersistFile interface and its member functions, see the OLE documentation included in the Win32 SDK.


Interfaces and Member Functions


IFileViewer [New - Windows 95]
IFileViewer

[New - Windows 95]

Designates an interface that allows a registered file viewer to be notified when it must show or print a file. The Windows 95 shell calls this interface when the user selects the Quick View command from a file's context menu and the file is a type that the file viewer recognizes. The IFileViewer interface has the following member functions:

PrintTo	Prints a file.
Show	Displays a file.
ShowInitialize	Prepares to display a file.
Like all OLE interfaces, IFileViewer also includes the QueryInterface, AddRef, and Release member functions.


IFileViewer::PrintTo [New - Windows 95]
IFileViewer::PrintTo

[New - Windows 95]

HRESULT PrintTo(IFileViewer FAR * pFileViewer,
    LPSTR pszDriver, BOOL fSuppressUI);

Prints a file.

•	Returns the NOERROR value if successful or an OLE-defined error value otherwise.

pFileViewer

Address of the IFileViewer interface. In C++, this parameter is implicit.

pszDriver

Address of a buffer that contains the name of the printer device driver that should print the file. If this parameter is NULL, the file viewer determines which device driver to use.

fSuppressUI

User interface suppression flag. If this parameter TRUE, the file viewer should not display any UI whatsoever, including error messages, during the print operation. If this parameter FALSE, the file viewer can show dialog boxes, as needed.

The shell specifies the name of the file to print by calling the file viewer's IPersistFile::Load member function.


IFileViewer::Show [New - Windows 95]
IFileViewer::Show

[New - Windows 95]

HRESULT Show(IFileViewer FAR * pFileViewer,
    LPFVSHOWINFO pvsi);

Displays a file.

•	Returns the NOERROR value if successful or the E_UNEXPECTED value if the IFileViewer::ShowInitialize member function was not called before IFileViewer::Show.

pFileViewer

Address of the IFileViewer interface. In C++, this parameter is implicit.

pvsi

Address of an FVSHOWINFO structure containing information that the file viewer uses to display the file. A file viewer can return information to the shell by modifying the members of the structure.

The shell specifies the name of the file to display by calling the file viewer's IPersistFile::Load member function.

IFileViewer::Show can fail only if IFileViewer::ShowInitialize was not called first, and the return value must be E_UNEXPECTED in that case. Otherwise, IFileViewer::Show must return NOERROR.


IFileViewer::ShowInitialize [New - Windows 95]
IFileViewer::ShowInitialize

[New - Windows 95]

HRESULT ShowInitialize(IFileViewer FAR * pFileViewer,
    LPFILEVIEWERSITE lpfsi);

Allows a file viewer to determine whether it can display a file and, if it can, to perform initialization operations before showing the file.

•	Returns the NOERROR value if successful or an OLE-defined error value otherwise.

pFileViewer

Address of the IFileViewer interface. In C++, this parameter is implicit.

lpfsi

Address of a IFileViewerSite interface. A file viewer uses this interface to retrieve the handle of the current pinned window or to specify a new pinned window.

The shell calls this member function before the IFileViewer::Show member function. The shell specifies the name of the file to display by calling the file viewer's IPersistFile::Load member function.

IFileViewer::ShowInitialize must perform all operations that are prone to failure so that if it succeeds, IFileViewer::Show will not fail.


IFileViewerSite [New - Windows 95]
IFileViewerSite

[New - Windows 95]

Designates an interface that allows a file viewer to retrieve the handle of the current pinned window or to set a new pinned window. The pinned window is the window in which the current file viewer is displaying a file. When the user selects a new file to view, the shell directs the file viewer to display the new file in the pinned window rather than to create a new window.

The IFileViewerSite interface has the following member functions.

GetPinnedWindow	Retrieves the handle of the current pinned window.
SetPinnedWindow	Sets a new pinned window.
Like all OLE interfaces, IFileViewerSite also includes the QueryInterface, AddRef, and Release member functions.


IFileViewerSite::GetPinnedWindow [New - Windows 95]
IFileViewerSite::GetPinnedWindow

[New - Windows 95]

HRESULT GetPinnedWindow(IFileViewerSite FAR * pFileVS,
    HWND *phwnd);

Retrieves the handle of the current pinned window, if it exists.

•	Returns the NOERROR value if successful or an OLE-defined error value otherwise.

pFileVS

Address of the IFileViewer interface. In C++, this parameter is implicit.

phwnd

Address of a window handle of the current pinned window or NULL if no pinned window exists.


IFileViewerSite::SetPinnedWindow [New - Windows 95]
IFileViewerSite::SetPinnedWindow

[New - Windows 95]

HRESULT SetPinnedWindow(IFileViewerSite FAR * pFileVS,
    HWND hwnd);

Sets a new pinned window.

•	Returns the NOERROR value if successful or an OLE-defined error value otherwise.

pFileVs

Address of the IFileViewer interface. In C++, this parameter is implicit.

hwnd

Handle of the new pinned window or NULL if there is to be no pinned window.

When the user selects a new file to view, the shell directs the file viewer to display the new file in the pinned window instead of creating a new window.


Structure

The following structure is used with file viewers.


FVSHOWINFO [New - Windows 95]
FVSHOWINFO

[New - Windows 95]

typedef struct {

    DWORD     cbSize;    // size of structure, in bytes

    HWND      hwndOwner; // see below

    int       iShow;     // see below

    DWORD     dwFlags;   // see below

    RECT      rect;      // see below

    LPUNKNOWN punkrel;   // see below

    OLECHAR   strNewFile[MAX_PATH];  // see below

} FVSHOWINFO, *LPFVSHOWINFO;

Contains information that the IFileViewer::Show member function uses to display a file.

hwndOwner

Handle of the owner window. When a file viewer creates a window to display a file, it should specify this handle as the owner of the window.

iShow

Show command. For a list of show commands, see the description of the ShowWindow function.

dwFlags

Show information flags. This member can be a combination of these values:

FVSIF_CANVIEWIT	The file viewer can display the file.
FVSIF_NEWFAILED	The file viewer specified a new file to display, but no viewer could display the file. The file viewer should either terminate or continue to display the previous file.
FVSIF_NEWFILE	A drag and drop operation has dropped a file on the file viewer window. The file viewer passes the name of the file to the shell by copying the name to strNewFile. The shell attempts to load a file viewer that can display the new file.
FVSIF_PINNED	A pinned window exists. A file viewer should either use the pinned window to display the file or set a new pinned window and display the file in it.
FVSIF_RECT	rect contains valid data.
rect

Address of a RECT structure that specifies the size and position of the file viewer's window. This member is valid only if dwFlags includes the FVSIF_RECT value.

punkrel

Address of an interface whose Release member function is called by a new file viewer to release the previous file viewer. This member is used when a drag and drop operation drops a file on the file viewer's window.

strNewFile

Address of a string that specifies the name of a new file to display. A file viewer sets this member when a drag and drop operation drops a file on the file viewer's window.

The shell uses this structure to pass information to a file viewer, and a file viewer uses it to return information to the shell.


File Parsers

A file parser is a dynamic-link library (DLL) that provides the low-level parsing needed to generate a "quick view" for a file of a given type.


About File Parsers

File parsers work in conjunction with the file viewing components of the Microsoft® Windows® 95 operating system. These components are the shell, the Quick View program (QUIKVIEW.EXE), display engines, and file parsers. The shell responds to user requests to generate a quick view for a file by calling the Quick View program. The program manages the process, directing one of the display engines to draw the Quick View window and fill it with a view of the file. The display engine uses a file parser to determine the contents of the file and to draw those contents correctly.

You can extend the file viewing capabilities of Windows 95 by supplying additional file parsers. Each file parser is responsible for a specific type or class of file and is associated with one of the display engines. For example, you can allow a quick view to be generated for a .DOC file by creating a file parser to support that file type and associating the file parser with the word processor display engine.

This article describes the file parser interface and explains how to write file parsers for word processing documents, spreadsheets, databases, bitmapped graphics, and vector graphics. The functions, macros, and structures described here can be found with the file parser sample code in the Samples subdirecory of the Microsoft® Win32® Software Development Kit (SDK). For information about extending the file viewing capabilities in other ways, see "File Viewers."

The file viewing technology used in the Quick View feature of the Microsoft Windows 95 operating system has been jointly developed by Microsoft Corporation and Systems Compatibility Corporation.


Adding or Removing File Parsers

For performance reasons, the file viewer builds a cache of the file parsers in the system the first time the Quick View feature is used. This cache is stored in the registry. If a file parser is added or removed, this cache must be rebuilt. To make the system rebuild the cache, set verify data not equal to zero under the following key.

\\HKEY_LOCAL_MACHINE\SOFTWARE\SCC\Viewer Technology\MS1


File Parser Functions

Every file parser must implement the following functions.

VwStreamCloseFunc	VwStreamSectionFunc
VwStreamOpenFunc	VwStreamSeekFunc
VwStreamReadFunc	VwStreamTellFunc
VwStreamReadRecordFunc
The display engine calls these functions to display a file of the type supported by the file parser.

The display engine starts the file viewing process by calling VwStreamOpenFunc, sending the name of a file to the file parser. The first responsibility of any parser is to verify that the given file has the proper format and can be processed. If the file is viewable, the file parser returns a value to the display engine acknowledging the request.

Once the parser completes verification, the display engine calls VwStreamSectionFunc, directing the file parser to identify the type and name of the first section of the file to be processed. A section is a portion of the file in which all the data is of one type; it forms a logical breaking point for the processing of the file. The standard section types are word processing, spreadsheet, database, bitmapped graphics, and vector graphics. A file can consist of a single section, multiple sections of the same type, or a combination of sections of different types. The actions that the display engine takes to display the file depend on the type of section currently being processed. The file parser must call the SOPutSectionType and SOPutSectionName functions to output the section type and to set the section name.

Before the file parser returns from VwStreamSectionFunc, it may need to provide the display engine with additional information. If the portion to be processed is a word processing section, the file parser must set entries for the font table by using the SOPutFontTableEntry function. If it is a spreadsheet section, the file parser must set the column width by calling the SOPutColumnInfo function. If it is a database section, the file parser must set the field format by calling the SOPutFieldInfo function. The file parser can also set the date base used by spreadsheets and databases to calculate dates by using the SOSetDateBase function. In addition, the file parser can set header entries by calling the SOPutHdrEntry function.

After the section type and general information is set, the display engine requests data for the section by calling VwStreamReadFunc. The file parser fulfills this request by calling the stream output functions. These functions pass the data to the display engine in a form that is easiest for the engine to display, copy to the clipboard, or write to disk.

The stream output functions used by the file parser depend on the section type. For word processing sections, the file parser uses the SOPutParaSpacing, SOPutCharAttr, and SOPutChar functions to set the spacing for paragraphs, set the style attributes for characters, and output characters. For spreadsheet sections, the parser uses the SOPutDataCell and SOPutTextCell functions to output the content (data or text) of cells. For database sections, it uses the SOPutField and SOPutVarField functions to output the data of fields. The parser uses the SOPutBitmapHeader and SOPutScanLineData functions for bitmapped graphics sections and the SOVectorAttr and SOVectorObject functions for vector graphics sections.

To set a break for a paragraph, cell, or field, the file parser calls the SOPutBreak function with an appropriate value, either SO_PARABREAK, SO_CELLBREAK, or SO_RECORDBREAK. The return value from SOPutBreak tells the file parser how to proceed. If it is the SO_STOP value, the file parser stops all processing and returns from VwStreamReadFunc.

The file parser continues to output data until it reaches the end of the section. The parser must end a section by calling SOPutBreak with the SO_SECTIONBREAK value. If this is the last section in the file, the file parser indicates that the end of the file has been reached by using the SO_EOFBREAK value instead.

If there are subsequent sections in the file, the display engine calls VwStreamSectionFunc again to request the type and name of the next section, and processing continues just as it did for the first section.

After the last section, the display engine calls VmStreamCloseFunc to indicate that processing is complete and that no further requests for data will be made. The file parser must close the file and any related files it has opened and clean up resources, such as freeing memory.

If an error occurs while a file is parsed, the file parser should call the SOBailOut function to notify the display engine of the error condition. The parser must immediately return from VwStreamReadFunc after calling the SOBailOut function.


Restartable Parsing

You must design the file parser so that parsing can be efficiently restarted at discrete locations within the file. The goal is to give the display engine the best performance without it having to store a completely converted copy of a file.

To facilitate restartable parsing, the display engine incorporates a module, which is called the chunker, that essentially caches data from the parser. The chunker does not cache all the data, only the data that the display engine has most recently requested. However, it does cache state data for restartable locations in the file. This means that as long as the parser maintains its own internal data in a way that can be efficiently restarted, the display engine and the parser can work cooperatively to locate and restart processing at the cached locations.

The file parser is responsible for determining the best locations for restarting parsing. It does this by calling the SOPutBreak function. The chunker assumes that each break is a restartable location in the file. Before calling SOPutBreak, however, the file parser must save up-to-date data about the location so that it can quickly retrieve and begin processing the data at the location if requested to do so.

The display engine uses the VwStreamSeekFunc and VwStreamTellFunc functions to direct the file parser to a restartable location.


Word Processing Sections

Word processing sections contain text organized as paragraphs, tables, and subdocuments. Of these, paragraphs and tables can have attributes, such as indentation, tab stops, and spacing. The text in word processing sections consists of characters having attributes, such as typeface, height, and weight. Word processing sections can also include embedded objects, allowing bitmapped art and other graphics to be included with the text.

A file parser processes the text associated with a word processing section when the display engine calls the VwStreamReadFunc function. The file parser must set all attributes before calling the SOPutChar function or other text output functions. The file parser must never automatically set an attribute as a default. If the state of a current attribute is not known, the file parser must not set it.


Paragraph Attributes

The file parser sets the attributes of a paragraph before outputting characters for the paragraph. The attributes are the alignment, indent, spacing, tab stops, and margins.

The file parser sets the alignment to be left, right, centered, or justified by using the SOPutParaAlign function and sets the left, right, and first line indents by using the SOPutParaIndents function. The file parser sets the spacing before and after the paragraph and between lines of the paragraph by using the SOPutParaSpacing function. The file parser sets tab stops by using the SOPutTabStop function, calling the function once for each tab stop. To mark the start and end of a tab stop definition, the file parser calls the SOStartTabStops and SOEndTabStops functions. The file parser sets page margins for the paragraph by using the SOPutParaMargins function.


Tables

The file parser can add tables to text output by using the SOBeginTable and SOEndTable functions to mark the start and end of the table definition and can format the rows and cells in tables by using the SOPutTableRowFormat and SOPutTableCellInfo functions. The file parser uses the character and paragraph functions to output the text for each cell and set the attributes.

The file parser marks the end of each cell and each row by using the SOPutBreak function with the SO_TABLECELLBREAK and SO_TABLEROWBREAK values. A file parser must insert a cell break after each cell and a row break at the end of each row. If a file parser inserts a row break before inserting as many cells as were defined for the row, the remaining cells are assumed to be empty. Empty cells may be inserted in the middle of a row by inserting consecutive cell breaks.

Row and cell formats must be defined before the last cell of a row. After defining the row properties by using the SOPutTableRowFormat function, the parser must call the SOPutTableCellInfo function for each cell in the row. After a row is defined, the row properties are assumed to apply to subsequent rows until new row properties are specified. A filter may, thus, define an entire table by specifying the row and cell properties once and then using the appropriate row and cell breaks.

You can add borders to cells by setting the pLeftBorder, pRightBorder, pTopBorder, and pBottomBorder members of the SOTABLECELLINFO structure to appropriate values when setting the cell format.

You can add tabs to cells by using the special character, the SO_CHCELLTAB value. This character is defined for cells that are merged with their neighbors and acts as a tab that moves the current text position to the location of the next boundary that would have existed if the cells had not been merged.


Subdocuments

The file parser adds subdocuments — that is, headers, footers, footnotes, and comments — to the document by using the SOPutBreak function. The file parser must call SOPutBreak with the SO_SUBDOCBEGINBREAK value to start a subdocument and with the SO_SUBDOCENDBREAK value to end it.

After ending a subdocument, the file parser must restore character and paragraph attributes to their state before the subdocument was started. The file parser can use the SUUserPushData and SUUserPopData functions to save and restore nested subdocument information. A parser can nest subdocuments without limit. The following example shows when to save and restore this information.

This is a <Bold On> test

    // At this point, the filter should save its internal
    // information to reflect the fact that bold is on.
    SOPutBreak(SO_SUBDOCBEGINBREAK);
    SoPutSubdocInfo(...);
<Subdoc Begin> This is a <Bold Off>subdocument<Subdoc End>

    // At this point, the filter should restore its internal
    // information to reflect the fact that bold is on.
    SOPutBreak(SO_SUBDOCENDBREAK);

document <Bold Off>of mine.

File parsers are not expected to correctly exit a subdocument when run from a regular paragraph break (with the SO_PARABREAK value) inside the subdocument. The display engine lets the file parser run to the subdocument's end break (that is, the SO_SUBDOCENDBREAK value) and returns the SO_STOP value to it.


Characters and Character Attributes

The file parser outputs characters by using the SOPutChar function. It can specify extra properties for a character, such as grouped or hidden, when outputting by using the SOPutCharX function. The file parser outputs special characters, such as tabs, hard line breaks, hard page breaks, and hyphens by using the SOPutSpecialCharX function.

Before outputting characters, the file parser sets character attributes by using the SOPutCharAttr, SOPutCharFontById, SOPutCharFontByName, and SOPutCharHeight functions. These functions set the style, font, height, and width of the character. The SOPutCharAttr function lets the file parser set style attributes, such as italic, underline, and strikeout. The SOPutCharFontById and SOPutCharFontByName functions can specify any font that the parser added to the font table during processing of the VwStreamSectionFunc function. The SOPutCharHeight function sets the character height, in half points.


Embedded Objects

The file parser can embed graphics objects in the text of a paragraph section by using the SOPutEmbeddedObject function. The function inserts the embedded graphics object at the current location.


Spreadsheet Sections

The file parser outputs content (data or text) for cells in a spreadsheet by using the SOPutDataCell and SOPutTextCell functions. Before outputting cell data, the file parser must get the range of columns to be output by using the SOGetInfo function with the SOINFO_COLUMNRANGE value. When SOGetInfo returns, the low-order word of its pInfo parameter identifies the first column of data to generate output for, and the high-order word identifies the last column. The file parser should only call SOPutDataCell or SOPutTextCell for cells within the range indicated by a call to SOGet. When there is no more data within a range of columns, the file parser must call the SOPutBreak function with either the SO_EOFBREAK or SO_SECTIONBREAK value, whichever applies. This must be done for each range of columns in the document.

For example, if the first column is 10 and the last column is 19, the filter reads the file from its current position, but it only calls SOPutDataCell or SOPutTextCell for cells that belong in columns 10 through column 19, inclusively. (Column numbers are zero based.) The parser skips over cells that belong in columns outside of this range. The filter must produce cells for all columns in the range, filling in with empty cells, if necessary. As before, the filter continues until SOPutBreak returns the SO_STOP value.

In general, the file parser should carry out the following steps:

1.	Determine the desired range of columns.

2.	Determine the next cell available from the input file.

3.	If the cell is not in the given range of columns, jump to step 2.

4.	If the cell is not empty, call SOPutDataCell or SOPutTextCell with the current data. Otherwise, call SOPutDataCell for a cell of the SO_CELLEMPTY type.

5.	Update local variables, such as row and column numbers.

6.	Call SOPutBreak with the SO_CELLBREAK value.

7.	If SOPutBreak returns the SO_STOP value, return from the VwStreamReadFunc function.

8.	If at the beginning of the next section, call SOPutBreak with the SO_SECTIONBREAK value and return.

9.	If at the end of the file, call SOPutBreak with the SO_EOFBREAK value and return.

10.	Repeat steps 2 through 10.

When the chunker saves local data for various seek positions in a document, it does so within SOPutBreak, when the break is of the SO_CELLBREAK type. Thus, when a file parser has its local data restored for a random seek position, the data will reflect the state of the file parser during its call to SOPutBreak for the last cell of the previous chunk in the current range of cells. Any tracking done by the parser, such as the current row number, should be updated before SOPutBreak is called for each cell.

Every horizontal range of columns, specified by dwExtraData in each call to your VwStreamReadFunc function, must eventually be terminated by a call to SOPutBreak with SO_EOFBREAK or SO_SECTIONBREAK value, whichever is applicable. The type of break depends on the input file. A file parser must not put a section break at the end of the file, and an end-of-file (EOF) break, of course, cannot occur anywhere but at the actual end of the file.

For example, if the input document contains a single spreadsheet that is 30 columns wide, the display engine can call the parser with three different ranges of columns: 0 to 11, 12 to 23, and 24 to 29. The file parser calls SOPutBreak with an EOF break three times, once for each time it reaches the end of the file while processing a given range.

When calling SOPutBreak with a section break, the file parser must be sure that the seek position is at the beginning of the next section — that is, the file position where the file parser needs to be when VwStreamSectionFunc is next called. Any one of the calls to SOPutBreak for a section break may be the one that sets the seek position for the top of the next section.


Database Sections

The file parser outputs data and text for a database by using the SOPutField, SOPutMoreVarField, and SOPutVarField functions. The parser uses the SOPutField function for fields of a fixed size. The other functions are used for variable length fields. The parser sets field information by using the SOPutFieldInfo function while processing the VmStreamSectionFunc function.


Bitmapped Sections

The file parser starts a bitmapped section by calling the SOPutSectionType function with the SO_BITMAP value while processing the VmStreamSectionFunc function. The file parser must also set the bitmap header information for the section by using the SOPutBitmapHeader function before returning from VmStreamSectionFunc. The information in the bitmap header allows the chunker to allocate storage for other bitmap information, such as the palette. This means that the file parser must call SOPutBitmapHeader before any other bitmapped section functions.


Palettes

The file parser must generate a palette for those sections that have the SO_COLORPALETTE value set in the wImageFlags member of the SOBITMAPHEADER structure. The parser uses the SOStartPalette, SOPutPaletteEntry, and SOEndPalette functions to define the color palette for a bitmapped section. Only one palette may be defined for a bitmapped section.

All SOCOLORREF members set during the stream read can use RGB (red, green, blue) values, palette index values, or palette-relative RGB values. All settings of these values must be done through the SOPALETTEINDEX, SORGB, or SOPALETTERGB macro. For more information about these types of color values, see the description of the COLORREF value.


Tiles and Scan Lines

A bitmap image in a bitmapped section consists of tiles and scan lines. A tile is a rectangular portion of an image, containing at least one scan line. An image is one or more tiles wide and one or more tiles long. A tile column is the horizontal positioning of a tile; the tiles that have their x-coordinate equal to zero belong to tile column zero, with tile column numbers incrementing in the direction of the increasing x-coordinates.

The file parser specifies its tile length in terms of scan lines. Once the length is specified, the display engine always requests bitmap data as whole tiles; that is, it tells the parser to stop only on integral multiples of the tile length. For formats that contain multiple tiles, file parsers should set the tile length to the minimum number of scan lines required for a single tile. Formats that are not stored in tiles should have the tile width set equal to the image width and the tile length set to one scan line.

The following values are expected to be valid when tiles are created.

TILESACROSS = (ImageWidth+TileWidth-1)/TileWidth
TILESDOWN = (ImageLength+TileLength-1)/TileLength
TILESPERIMAGE=TILESACROSS*TILESDOWN

To output bitmap data, the file parser outputs a scan line at a time, in sequential order, by using the SOPutScanLineData function. All of the scan line must belong to the same tile column. After each scan line, the file parser calls the SOPutBreak function with the SO_SCANLINEBREAK value. As is normally the case, the return value from SOPutBreak indicates whether the file parser should return from the VwStreamReadFunc function.


Building Scan Lines

The file parser builds the scan line data as a continuous stream of bits that define each pixel. Each pixel is packed into an array of bytes in such a way that if the data were written out in hexadecimal or binary numbers, the pixels could be read in order from left to right. That is, for a 4-bit-per-pixel format, the first pixel is stored in the high-order bits of the first byte (bit 7, bit 6, bit 5, and bit 4), and the second pixel is stored in low-order bits of that byte (bit 3, bit 2, bit 1, and bit 0). Thus, if the first eight pixels of a 4-bit-per-pixel scan line have the hex values of 0, 2, C, 9, A, 4, 3, and F, the first four bytes of scan line data would be 02, C9, A4, and 3F.

If the parser provides a palette for the image, the data for each pixel is interpreted as an index into the palette. If no palette exists for the image, the bits for each pixel specify either a true color (24-bit only) or a gray scale value. For 24-bit color, each 3 bytes of a scan line represent the intensities of red, green, and blue of a single pixel.

When the scan line has been completely specified, the parser must call SOPutBreak with the SO_SCANLINEBREAK value, except for the last line of the bitmap. The last line of the bitmap must end with a break of the SO_SECTIONBREAK or SO_EOFBREAK type, whichever applies.

The following example illustrates the use of the bitmapped functions in the simplest possible case: a parser with scan line data stored one tile wide and with the same format that parsers are required to provide it, so the data requires no additional processing after being read in. This example also does not check for EOF or read errors.

WORD  wBytesRead;
WORD  wBufSize = Proc.ScanLineBufSize;

do
{
...

xread( hFile, Proc.ScanLineBuf, wBufSize, &wBytesRead );

SOPutScanLineData( Proc.ScanLineBuf, hProc );

...

} while( SOPutBreak( SO_SCANLINEBREAK, 0, hProc ) == SO_CONTINUE );


Vector Graphics Sections

The file parser starts a vector graphics section by calling the SOPutSectionType function with the SO_VECTOR value while processing the VmStreamSectionFunc function. The file parser must also set the vector header by using the SOPutVectorHeader function before returning from VmStreamSectionFunc. The information in the SOVECTORHEADER structure defines the size and attributes of the rectangle in which vector graphics are drawn.

The vector graphics functions are similar to the primitive GDI functions, but they include extensions that are based on the file formats being supported. All vector graphics objects are described in two-dimensional space on a logical coordinate system. The direction and resolution of the x- and y-axis is defined in SOVECTORHEADER.

The file parser uses two functions to transfer data. The SOVectorAttr function sets attributes related to drawing vector graphics objects, and the SOVectorObject function defines a vector graphics object to be drawn. The parser specifies an identifier, a data size, and the address of data when it calls a function. The identifier specifies the action to take and the size and data-defined details of the action. Each action has a corresponding structure in which the data must be given. For example, to define a logical font, the parser must set the members of the SOLOGFONT structure and pass the structure to SOVectorAttr.

Although vector graphics functions are similar to the graphics device interface (GDI) functions, they are not exactly the same. This means, for example, that the members of the SOLOGFONT and LOGFONT structures are not necessarily the same.

The file parser should call the SOPutBreak function with the SO_VECTOROBJECTBREAK value after drawing every object.


Writing a File Parser

File parsers should be contained in a set of source and include files as follows, where XXX represents a mnemonic for the data format. For specific examples, see the sample ASCII filter files identified in the following table.

Generic file name	Contents	Sample ASCII filter file
VS_XXX.C	Code	VS_ASC.C
VSD_XXX.C	Data	VSD_ASC.C
VS_XXX.H	Type definitions	VS_ASC.H
VSP_XXX.H	Portability information	VSP_ASC.H
The portability information file makes porting of filters between 16- and 32-bit versions of Windows and multiple Microsoft® Windows NT™ platforms easier. To allow file parsers to be used for content indexing, a set of include files is provided that will allow conditional compilations to yield executable DLLs for all of these needs from the same set of source files.

Your VSP_XXX.H file should look something like the following. (For further information, see the corresponding ASCII filter file.)

•	The structure type and name of the static data.

#define VwStreamStaticType  ???
#define VwStreamStaticName  ???

The parser must not change the contents of the structure, because it is shared among all instances of the parser.

•	The structure type and name of the dynamic data.

#define VwStreamDynamicType  ???
#define VwStreamDynamicName  ???

VwStreamDynamicName is for consistency and has no real use, because all dynamic data is accessed through the pseudonym Proc. Each instance of the parser has a separate copy of dynamic data.

•	The structure type and name of the save data.

#define VwStreamSaveType  ???
#define VwStreamSaveName  ???

VwStreamSaveName should reference an element in the VwStreamDynamicType structure. The data in this structure is saved after every call to VwStreamSectionFunc and VwStreamReadFunc and restored before every call to VwStreamReadFunc.

•	The structure type and name of the section data.

#define VwStreamSectionType  ???
#define VwStreamSectionName  ???

If neither of these is defined, the file parser is assumed to be single section only. VwStreamSectionName should reference an element in the VwStreamDynamicType structure. The data in this structure is saved after each call to VwStreamSectionFunc and is guaranteed to contain the current section's data on entry to VwStreamReadFunc.

The example below shows the relationship of the various save areas to the dynamic data structure.

typedef struct {
 ...
} VwStreamSaveType;
typedef struct {
 ...
} VwStreamSectionType;
typedef struct {
 ...
    VwStreamSectionType VwStreamSectionName; // multisection only
    VwStreamSaveType VwStreamSaveName;
} VwStreamDynamicType;

•	The stream identifier name and count.

#define VwStreamIdName   ???
#define VwStreamIdCount   ???

VwStreamIdName is the name of the FILTER_DESC array in VSD_XXX.C, and VwStreamIdCount is the number of elements in this array. Like the static data, this data should never be changed by a parser.

•	The name of the include file. All the structure types used by the parser should be defined in this file.

#define VwInclude              "vs_xxx.h"
#define VwStreamUserSaveType   ???
#define VwStreamGenSeekName    ???
#define VwStreamOpenFunc        xxx_stream_open
#define VwStreamSeekFunc        xxx_stream_seek
#define VwStreamTellFunc        xxx_stream_tell
#define VwStreamReadFunc        xxx_stream_read
#define VwStreamReadRecordFunc  xxx_stream_readrecord
#define VwStreamSectionFunc     xxx_stream_section
#define VwStreamCloseFunc       xxx_stream_close
#define VwGetInfoFunc           xxx_getinfo
#define VwGetRtnsFunc           xxx_getrtns
#define VwGetDataFunc           xxx_getdata
#define VwSetDataFunc           xxx_setdata
#define VwAllocProcFunc         xxx_alloc_proc
#define VwFreeProcFunc          xxx_free_proc
#define VwLocalUpFunc           xxx_local_up
#define VwLocalDownFunc         xxx_local_down
#define VwGetSectionDataFunc    xxx_getsectiondata
#define VwSetSectionDataFunc    xxx_setsectiondata

•	The top of the VS_XXX.C file should look like this.

#include "VSP_XXX.H"
#include "VSCTOP.H"
#include "VS_XXX.PRO"


Reference

The following functions, helper functions, and structures are associated with file parsers.


Functions

The following functions are used with file parsers.


VwStreamCloseFunc [New - Windows 95]
VwStreamCloseFunc

[New - Windows 95]

VOID VwStreamCloseFunc(SOFILE hFile, HPROC reserved);

Closes the file. The file parser must carry out any necessary cleanup, such as closing any other open files related to the given file.

•	No return value.

hFile

Handle of the file for execute input and output (XIO) routines.

reserved

Reserved; do not use.


VwStreamOpenFunc [New - Windows 95]
VwStreamOpenFunc

[New - Windows 95]

INT VwStreamOpenFunc(SOFILE hFile, INT wFileId,
    U_BYTE VWPTR * pFileName, SOFILTERINFO VWPTR * pFilterInfo,
    HPROC reserved);

Checks the validity of the specified file and returns information about the file parser.

•	Returns the VWERR_OK value if successful or one of the following error values otherwise:

VWERR_BADFILE	Corrupt or unreadable file
VWERR_EMPTYFILE	Empty file
VWERR_PROTECTEDFILE	Password-protected or encrypted file
VWERR_SUPFILEOPENFAILS	Supplementary file failed to open
hFile

Handle of the file for execute input and output (XIO) routines.

wFileId

Identifier for the file.

pFileName

Address of the null-terminated string specifying the base name of the file. This string does not include path information.

pFilterInfo

Address of the SOFILTERINFO structure that receives information about the file parser.

reserved

Reserved; do not use.


VwStreamReadFunc [New - Windows 95]
VwStreamReadFunc

[New - Windows 95]

INT VwStreamReadFunc(SOFILE hFile, HPROC reserved);

Outputs characters, cells, or fields, depending on the current section type and file contents.

•	Returns zero if successful or  − 1 if the end of the file is reached.

hFile

Handle of the file for execute input and output (XIO) routines.

reserved

Reserved; do not use.


VwStreamReadRecordFunc [New - Windows 95]
VwStreamReadRecordFunc

[New - Windows 95]

VOID VwStreamReadRecordFunc(SOFILE hFile, DWORD dwData, HPROC reserved);

Outputs a single record by calling various stream output functions.

•	No return value.

hFile

Handle of the file for execute input and output (XIO) routines.

dwData

Data to be saved for the record.

reserved

Reserved; do not use.

This function should output a single record and then call the SOPutBreak function with the SO_RECORDBREAK value before returning. The SO_EOFBREAK and SO_SECTIONBREAK conditions do not need to be trapped by this function.


VwStreamSectionFunc [New - Windows 95]
VwStreamSectionFunc

[New - Windows 95]

INT VwStreamSectionFunc(SOFILE hFile, HPROC reserved);

Sets the parameters for a section.

•	Always returns zero.

hFile

Handle of the file for execute input and output (XIO) routines.

reserved

Reserved; do not use.

At a minimum, this function should call the SOPutSectionType and SOPutSectionName functions to set the section type and name. The function should also set the cell width if the section is a spreadsheet or the field format if the section is a database.

The display engine calls the function after calling the VwStreamOpenFunc function but before calling the VwStreamReadFunc function. It is also called after any VwStreamReadFunc that ends with a call to the SOPutBreak function with the SO_SECTIONBREAK value.


VwStreamSeekFunc [New - Windows 95]
VwStreamSeekFunc

[New - Windows 95]

INT VwStreamSeekFunc(SOFILE hFile, HPROC reserved);

Same definition as the line filters Seek function

•	Returns zero if successful or  − 1 if the function fails.

hFile

Handle of the file for execute input and output (XIO) routines.

reserved

Reserved; do not use.


VwStreamTellFunc [New - Windows 95]
VwStreamTellFunc

[New - Windows 95]

INT VwStreamTellFunc(SOFILE hFile, HPROC reserved);

Same definition as the line filters Tell function.

•	Returns zero if successful or  − 1 if the function fails.

hFile

Handle of the file for execute input and output (XIO) routines.

reserved

Reserved; do not use.


Helper Functions


SOBailOut [New - Windows 95]
SOBailOut

[New - Windows 95]

VOID SOBailOut(WORD wError, HPROC reserved);

Allows the file parser to return an error condition.

•	No return value.

wError

Error flag. This parameter can be one of these values:

SOERROR_BADFILE	Invalid file format
SOERROR_EOF	Unexpected end of file (EOF)
SOERROR_GENERAL	Unspecified error
reserved

Reserved; do not use.

The parser should return from the VwReadStreamFunc function as soon as possible after this function is called.


SOBeginTable [New - Windows 95]
SOBeginTable

[New - Windows 95]

VOID SOBeginTable(HPROC reserved);

Starts a table definition, indicating that the text in subsequent output calls is part of a table.

•	No return value.

reserved

Reserved; do not use.

This function must be called between paragraphs and before row and cell formats are specified.


SOEndColumnInfo [New - Windows 95]
SOEndColumnInfo

[New - Windows 95]

VOID SOEndColumnInfo(HPROC reserved);

Ends the definition of column information.

•	No return value.

reserved

Reserved; do not use.

The file parser must call this function immediately after setting the column information. This function can only be called from the VwStreamSection function.


SOEndFieldInfo [New - Windows 95]
SOEndFieldInfo

[New - Windows 95]

VOID SOEndFieldInfo(HPROC reserved);

Ends the definition of field information.

•	No return value.

reserved

Reserved; do not use.

The file parser must have previously called the SOStartFieldInfo function.

The file parser calls this function immediately after setting the field information. This function can only be called from the VwStreamSection function.


SOEndFontTable [New - Windows 95]
SOEndFontTable

[New - Windows 95]

VOID SOEndFontTable(HPROC reserved);

Ends the definition of a font table.

•	No return value.

reserved

Reserved; do not use.

The file parser must call this function immediately after setting font entries. This function can only be called from the VwStreamSection function.


SOEndPalette [New - Windows 95]
SOEndPalette

[New - Windows 95]

VOID SOEndPalette( HPROC reserved );

Ends the definition of a color palette.

•	No return value.

reserved

Reserved; do not use.

The file parser calls this function immediately after specifying the last palette entry.


SOEndTable [New - Windows 95]
SOEndTable

[New - Windows 95]

VOID SOEndTable(HPROC reserved);

Ends a table definition, indicating that the text in subsequent output calls is no longer part of a table.

•	No return value.

reserved

Reserved; do not use.

The function must be called after a row break.


SOEndTabStops [New - Windows 95]
SOEndTabStops

[New - Windows 95]

VOID SOEndTabStops(HPROC reserved);

Ends the definition of tabs stops for a paragraph.

•	No return value.

reserved

Reserved; do not use.

To set tab stops, use the SOPutTabStop function.

The file parser calls this function immediately after setting the last tab stop for the paragraph.


SOGetInfo [New - Windows 95]
SOGetInfo

[New - Windows 95]

VOID SOGetInfo(WORD wInfo, void VWPTR * pInfo, HPROC reserved);

Retrieves information about a spreadsheet.

•	No return value.

wInfo

Information type. If this parameter is the SOINFO_COLUMNRANGE value, the function retrieves the range of columns for a spreadsheet to read.

pInfo

Address of a 32-bit variable that receives the first column number in the low-order word and the second column number in the high-order word.

reserved

Reserved; do not use.


SOGetScanLineBuffer [New - Windows 95]
SOGetScanLineBuffer

[New - Windows 95]

WORD SOGetScanLineBuffer(VOID VWPTR * ppScanLineData, HPROC reserved );

Retrieves the address of the buffer for storing the current scan line.

•	Returns the size, in bytes, of the scan line data buffer. The size is the maximum number of bytes that may be accessed using the returned address and is guaranteed to be sufficient to hold a scan line as wide as the entire tile.

ppScanLineData

Address of the variable that receives the address of the scan line data buffer.

reserved

Reserved; do not use.

This function is called from the VwStreamReadFunc function for each scan line produced.

This function sets the variable pointed to by ppScanLineData to the address where the scan line data should be built.


SOPutBitmapHeader [New - Windows 95]
SOPutBitmapHeader

[New - Windows 95]

VOID SOPutBitmapHeader(PSOBITMAPHEADER pBitmapHeader, HPROC reserved);

Outputs information about a bitmap.

•	No return value.

pBitmapHeader

Address of the SOBITMAPHEADER structure that contains the bitmap header information.

reserved

Reserved; do not use.


SOPutBreak [New - Windows 95]
SOPutBreak

[New - Windows 95]

WORD SOPutBreak(WORD wType, DWORD dwInfo, HPROC reserved);

Sets a paragraph, cell, record, page, section, or other type of break.

•	Returns the SO_STOP value to direct the file parser to stop processing and return or the SO_CONTINUE value to direct the file parser to continue processing.

wType

Type of break. This parameter can one of these values:

SO_CELLBREAK	Regular cell break
SO_EOFBREAK	End of file (EOF) break, which implies a section break
SO_PARABREAK	Regular paragraph break
SO_RECORDBREAK	Regular record break
SO_SECTIONBREAK	Section break
SO_SUBDOCBEGINBREAK	Subdocument's begin break
SO_SUBDOCENDBREAK	Subdocument's end break
dwInfo

Data to save for each record. This data is for database section breaks. For all other section types, this parameter should be zero.

reserved

Reserved; do not use.

dwInfo is saved after every SOPutBreak function and, like the regular save information, should represent the next record, not the one just read.

In spreadsheet sections, the last cell in a section must have an associated SO_CELLBREAK break before the SO_SECTIONBREAK or SO_EOFBREAK break.

In database sections, the last record in a section must have an associated SO_RECORDBREAK break before the SO_SECTIONBREAK or SO_EOFBREAK break.

In word processing sections, the last paragraph does not need an SO_PARABREAK break before the SO_SECTIONBREAK or SO_EOFBREAK break.


SOPutChar [New - Windows 95]
SOPutChar

[New - Windows 95]

VOID SOPutChar(WORD wCh, HPROC reserved);

Outputs a character, applying the current font, height, and attributes.

•	No return value.

wCh

Character value. This parameter must be within the range specified by the current character set.

reserved

Reserved; do not use.

The character is assumed to belong to the character set selected by the open function and is countable and visible.


SOPutCharAttr [New - Windows 95]
SOPutCharAttr

[New - Windows 95]

VOID SOPutCharAttr(WORD wAttr, WORD wState, HPROC reserved);

Sets the style attributes for characters in text.

•	No return value.

wAttr

Style attribute type. This parameter can be one of these values:

SO_BOLD	Bold
SO_CAPS	All capital letters
SO_DOTUNDERLINE	Dotted underline
SO_DUNDERLINE	Double underline
SO_ITALIC	Italic
SO_OUTLINE	Outlined rather than solid
SO_SHADOW	Shadow slightly beneath and behind
SO_SMALLCAPS	Small capital letters
SO_STRIKEOUT	Strikeout
SO_SUBSCRIPT	Subscript
SO_SUPERSCRIPT	Superscript
SO_UNDERLINE	Single underline
SO_WORDUNDERLINE	Underline
wState

Style attribute state. This parameter can be the SO_ON or SO_OFF value.

reserved

Reserved; do not use.


SOPutCharFontById [New - Windows 95]
SOPutCharFontById

[New - Windows 95]

VOID SOPutCharFontById(DWORD dwFontId, HPROC reserved);

Sets the font for characters in text.

•	No return value.

dwFontId

Font identifier, relative to the previously given font table.

reserved

Reserved; do not use.


SOPutCharFontByName [New - Windows 95]
SOPutCharFontByName

[New - Windows 95]

VOID SOPutCharFontByName(WORD wFontType, char VWPTR * pFontName, HPROC reserved);

Sets the font for characters in text.

•	No return value.

wFontType

Font family. This parameter can be one of these values:

SO_FAMILYDECORATIVE	Fancy display font
SO_FAMILYMODERN	Fixed width
SO_FAMILYROMAN	Variable width with serifs
SO_FAMILYSCRIPT	Handwriting
SO_FAMILYSWISS	Variable width without serifs
SO_FAMILYSYMBOL	Symbol font
SO_FAMILYUNKNOWN	Not known
pFontName

Address of a null-terminated string specifying the name of the font.

reserved

Reserved; do not use.


SOPutCharHeight [New - Windows 95]
SOPutCharHeight

[New - Windows 95]

VOID SOPutCharHeight(WORD wHeight, HPROC reserved);

Sets the height, in half points, of a character in text.

•	No return value.

wHeight

Height, in half points, of the character.

reserved

Reserved; do not use.


SOPutCharX [New - Windows 95]
SOPutCharX

[New - Windows 95]

VOID SOPutCharX(WORD wCh, WORD wType, HPROC reserved);

Outputs a character, applying the specified character type.

•	No return value.

wCh

Character value. This parameter must be within the range specified by the current character set.

wType

Type flag. This parameter can be one or more of these values:

SO_COUNT	The character is countable and may be deleted. Characters without this value are for display purposes and do not enter into character count calculations for write back.
SO_HIDDEN	The character is not visible on the display.
SO_LIMITEDIT	Consecutive characters of this type will be deleted as a group. No write back command will begin on one of these characters, but it may encompass a group of these characters.
reserved

Reserved; do not use.

The character is assumed to belong to the character set selected by the open function.


SOPutColumnInfo [New - Windows 95]
SOPutColumnInfo

[New - Windows 95]

VOID SOPutColumnInfo(PSOCOLUMN pColumn, HPROC reserved);

Sets column information.

•	No return value.

pColumn

Address of the SOCOLUMN structure containing the column information.

reserved

Reserved; do not use.

The file parser must call the SOStartColumnInfo function before calling this function.

This function can only be called from the VwStreamSection function.


SOPutDataCell [New - Windows 95]
SOPutDataCell

[New - Windows 95]

VOID SOPutDataCell(PSODATACELL pCell, HPROC reserved);

Outputs data for a cell.

•	No return value.

pCell

Address of a SODATACELL structure.

reserved

Reserved; do not use.


SOPutEmbeddedObject [New - Windows 95]
SOPutEmbeddedObject

[New - Windows 95]

VOID SOPutEmbeddedObject(PSOEMBEDDEDOBJECT pObject, HPROC reserved);

Sets an embedded graphics object.

•	No return value.

pObject

Address of the SOEMBEDDEDOBJECT structure that contains information about the object to be embedded.

reserved

Reserved; do not use.

The file parser must set the SOEMBEDDEDOBJECT structure with the appropriate values.


SOPutField [New - Windows 95]
SOPutField

[New - Windows 95]

VOID SOPutField(void VWPTR * pData, HPROC reserved);

Outputs data for a field.

•	No return value.

pData

Address of the data for the field.

reserved

Reserved; do not use.

This function is used for all wStorage types except the SO_FIELDTEXTVAR value.


SOPutFieldInfo [New - Windows 95]
SOPutFieldInfo

[New - Windows 95]

VOID SOPutFieldInfo(PSOFIELD pField, HPROC reserved);

Sets field information.

•	No return value.

pField

Address of the SOFIELD structure containing the field information.

reserved

Reserved; do not use.

The file parser must call the SOStartFieldInfo function before calling this function.

This function can only be called from the VwStreamSection function.


SOPutFontTableEntry [New - Windows 95]
SOPutFontTableEntry

[New - Windows 95]

VOID SOPutFontTableEntry(DWORD dwFontId, WORD wFontType,
    char VWPTR * pFontName, HPROC reserved);

Sets a font table entry.

•	No return value.

dwFontId

Font identifier. This parameter can be any number, but it must be unique within the font table.

wFontType

Font family. This parameter can be one of these values:

SO_FAMILYDECORATIVE	Fancy display font
SO_FAMILYMODERN	Fixed width
SO_FAMILYROMAN	Variable width with serifs
SO_FAMILYSCRIPT	Handwriting
SO_FAMILYSWISS	Variable width without serifs
SO_FAMILYSYMBOL	Symbol font
SO_FAMILYUNKNOWN	Not known
pFontName

Address of a null-terminated string specifying the name of the font.

reserved

Reserved; do not use.

The file parser must call the SOStartFontTable function before calling this function. SOPutFontTableEntry must be called once for each font to be added to the table. Font identifiers must be unique, but they can be given in any order.

This function can only be called from the VwStreamSection function.


SOPutHdrEntry [New - Windows 95]
SOPutHdrEntry

[New - Windows 95]

VOID SOPutHdrEntry(char VWPTR *pLabel, char VWPTR * pData, WORD wId,
    HPROC reserved);

Sets strings for the header information.

•	No return value.

pLabel

Label that the display engine should use when presenting this value.

pData

Value to display.

wId

Identifier for this item that the display engine and filter agree upon.

reserved

Reserved; do not use.

This function can only be called from the VwStreamSection function.


SOPutMoreText [New - Windows 95]
SOPutMoreText

[New - Windows 95]

VOID SOPutMoreText(WORD wCount, char VWPTR * pText, WORD bMore,
    HPROC reserved);

Outputs the text for a cell and indicates whether there is more text to be output for the cell.

•	No return value.

wCount

Number of characters pointed to by pText. The number must not exceed 128 bytes.

pText

Address of the string of text characters to output.

bMore

More data flag. This parameter can be the SO_YES value to indicate more text to be output or the SO_NO value to indicate none.

reserved

Reserved; do not use.

This function is used to output a sequence of text initially started by using the SOPutText function.

If there is more text to output, the file parser must use a subsequent call or calls to the SOPutMoreText function to output the text. The 128 byte limit is for the convenience of the function processing SOPutMoreText.


SOPutMoreVarField [New - Windows 95]
SOPutMoreVarField

[New - Windows 95]

VOID SOPutMoreVarField(VOID VWPTR * pData, WORD wCount, WORD bMore,
    HPROC reserved);

Outputs data for a variable field and indicates whether there is more data to be output for the field.

•	No return value.

pData

Address of the data for the field.

wCount

Number of bytes pointed to by pData. The number must not exceed 128 bytes.

bMore

More data flag. This parameter can be the SO_YES value to indicate more data to be output or the SO_NO value to indicate none.

reserved

Reserved; do not use.

This function can be called any number of times.

If there is more data to output, the file parser must use a subsequent call or calls to SOPutMoreVarField to output the data. The 128 byte limit is for the convenience of the function processing SOPutMoreVarField.

This function is used to output a sequence of data initially started using the SOPutVarField function.


SOPutPaletteEntry [New - Windows 95]
SOPutPaletteEntry

[New - Windows 95]

VOID SOPutPaletteEntry(unsigned char Red, unsigned char Green,
    unsigned char Blue, HPROC reserved);

Sets the colors for a palette entry.

•	No return value.

Red

Relative red intensity in the range 0 to 255.

Green

Relative green intensity in the range 0 to 255.

Blue

Relative blue intensity in the range 0 to 255.

reserved

Reserved; do not use.

The file parser must call the SOStartPalette function before calling this function.

The order of calls to this function determines the order of entries in the color table for an image. The first palette entry is color 0, the color displayed for pixels with a value of 0; the second palette entry is color 1; and so on.


SOPutParaAlign [New - Windows 95]
SOPutParaAlign

[New - Windows 95]

VOID SOPutParaAlign(WORD wType,HPROC reserved);

Sets the alignment for a paragraph.

•	No return value.

wType

Type of alignment. This parameter can be the SO_ALIGNLEFT, SO_ALIGNRIGHT, SO_ALIGNCENTER, or SO_ALIGNJUSTIFY value.

reserved

Reserved; do not use.


SOPutParaIndents [New - Windows 95]
SOPutParaIndents

[New - Windows 95]

VOID SOPutParaIndents(LONG dwLeft, LONG dwRight, LONG dwFirst,
    HPROC reserved);

Sets indents for a paragraph. Indents are relative to the corresponding left or right margin.

•	No return value.

dwLeft

Width, in twips, of the left indent. The indent is measured from the left page margin.

dwRight

Width, in twips, of the right indent. The indent is measured from the right page margin.

dwFirst

Width, in twips, of the left indent for the first line in the paragraph. The indent is measured from the left page margin.

reserved

Reserved; do not use.


SOPutParaMargins [New - Windows 95]
SOPutParaMargins

[New - Windows 95]

VOID SOPutParaMargins(LONG dwLeft, LONG dwRight, HPROC reserved);

Sets paragraph margins. The margins are relative to the left or right edge of the page.

•	No return value.

dwLeft

Width, in twips, of the left margin.

dwRight

Width, in twips, of the right margin.

reserved

Reserved; do not use.


SOPutParaSpacing [New - Windows 95]
SOPutParaSpacing

[New - Windows 95]

VOID SOPutParaSpacing(WORD wLineHeightType, DWORD dwLineHeight,
    DWORD dwSpaceBefore, DWORD dwSpaceAfter, HPROC reserved);

Sets the spacing for a paragraph.

•	No return value.

wLineHeightType

Type of line height. This parameter can be one of these values:

SO_HEIGHTATLEAST	Sets the line height to the height given by dwLineHeight or sets it to fit the tallest character in the line, whichever height is greater.
SO_HEIGHTAUTO	Sets the line height automatically to fit the tallest character in the line.
SO_HEIGHTEXACTLY	Sets the line height to the height given by dwLineHeight.
dwLineHeight

Baseline to baseline height, in twips.

dwSpaceBefore

Space before the paragraph, in twips.

dwSpaceAfter

Space after the paragraph, in twips.

reserved

Reserved; do not use.


SOPutScanLineData [New - Windows 95]
SOPutScanLineData

[New - Windows 95]

VOID SOPutScanLineData(U_BYTE VWPTR * pScanLineData, HPROC reserved);

Sets the bit values in a single scan line of a bitmap.

•	No return value.

pScanLineData

Address of the bitmap data for the current scan line.

reserved

Reserved; do not use.

The bitmap format must have been previously defined by using the SOPutBitmapHeader function.


SOPutSectionName [New - Windows 95]
SOPutSectionName

[New - Windows 95]

VOID SOPutSectionName(char VWPTR * pName, HPROC reserved);

Sets the name of a section.

•	No return value.

pName

Address of a null-terminated string specifying the name of the section.

reserved

Reserved; do not use.


SOPutSectionType [New - Windows 95]
SOPutSectionType

[New - Windows 95]

VOID SOPutSectionType(WORD wType, HPROC reserved);

Outputs a section type.

•	No return value.

wType

Section type. This parameter can be one of these values:

SO_BITMAP	Sets the section type to be a bitmap. When generating output for the section, the file parser should use only general and bitmap stream output functions.
SO_CELLS	Sets the section type to be a spreadsheet consisting of cells. When generating output for the section, the file parser should use only the general and spreadsheet stream output functions.
SO_FIELDS	Sets the section type to be a database consisting of fields. When generating output for the section, the file parser should use only the general and database stream output functions.
SO_PARAGRAPHS	Sets the section type to be a word processing document consisting of paragraphs. When generating output for the section, the file parser should use only general and word processing stream output functions.
SO_VECTOR	Sets the section type to be a vector graphics section consisting of graphics objects. When generating output for the section, the file parser should use only the general and vector graphics stream output functions.
reserved

Reserved; do not use.


SOPutSpecialCharX [New - Windows 95]
SOPutSpecialCharX

[New - Windows 95]

VOID SOPutSpecialCharX(WORD wCh, WORD wType, HPROC reserved);

Outputs a special character, applying the specified character type.

•	No return value.

wCh

Character value. This parameter can be one of these values:

SO_CHDATE	Automatic current date
SO_CHHHYPHEN	Nonbreaking hyphen
SO_CHHLINE	Hard line break
SO_CHHPAGE	Hard page break
SO_CHHSPACE	Nonbreaking space
SO_CHPAGENUMBER	Automatic page number
SO_CHSHYPHEN	Hyphen
SO_CHTAB	Tab
SO_CHTIME	Automatic current time
SO_CHUNKNOWN	Default character
wType

Type flag. This parameter can be one or more of these values:

SO_COUNT	The character is countable and may be deleted. Characters without this value are for display purposes and do not enter into character count calculations for write back.
SO_HIDDEN	The character is not visible on the display.
SO_LIMITEDIT	Consecutive characters of this type will be deleted as a group. No write back command will begin on one of these characters, but it may encompass a group of these characters.
reserved

Reserved; do not use.


SOPutSubdocInfo [New - Windows 95]
SOPutSubdocInfo

[New - Windows 95]

VOID SOPutSubdocInfo(WORD wType, WORD wSubType, HPROC reserved);

Outputs subdocument data.

•	No return value.

wType

Type of data. This parameter can be one of these values:

SO_COMMENT	The data is a comment.
SO_FOOTER	The data applies to the document footer.
SO_FOOTNOTE	The data applies to a footnote.
SO_HEADER	The data applies to the document header.
wSubType

Subtype of data. This parameter can be one of these values:

SO_BOTH	The data is for a header or footer on both left and right pages. This value is used with SO_HEADER or SO_FOOTER.
SO_LEFT	The data is for a header or footer on even pages only. This value is used with SO_HEADER or SO_FOOTER.
SO_RIGHT	The data is for a header or footer on odd pages only. This value is used with SO_HEADER or SO_FOOTER.
0 through 65535	The data is a footnote number. This value is used with SO_FOOTNOTE only.
If wType is SO_COMMENT, no subtype is needed.

reserved

Reserved; do not use.


SOPutTableCellInfo [New - Windows 95]
SOPutTableCellInfo

[New - Windows 95]

VOID SOPutTableCellInfo(PSOTABLECELLINFO pCellInfo, HPROC reserved);

Sets cell information.

•	No return value.

pCellInfo

Address of a SOTABLECELLINFO structure containing information about the cell.

reserved

Reserved; do not use.


SOPutTableRowFormat [New - Windows 95]
SOPutTableRowFormat

[New - Windows 95]

VOID SOPutTableRowFormat(WORD wLeftEdge, WORD wRowHeight,
    WORD wRowHeightType, WORD wCellMargin, WORD wRowAlignment,
    WORD wNumCells, HPROC reserved );

Sets the format of a row in a table.

•	No return value.

wLeftEdge

Position, in twips, of the left edge of the table, relative to the left margin.

wRowHeight

Row height, in twips.

wRowHeightType

Type of height for the row. This parameter can be one of these values:

SO_HEIGHTATLEAST	Sets the  row height at least as high as that given by wRowHeight.
SO_HEIGHTAUTO	Sets the  row height automatically to fit text in the row.
SO_HEIGHTEXACTLY	Sets the row height exactly as given by wRowHeight.
wCellMargin

White space on either side of text in a cell within the specified cell width. It is equal to half the total white space between adjacent cells.

wRowAlignment

Alignment of row within margins. This parameter can be the SO_ALIGNLEFT, SO_ALIGNRIGHT, or SO_ALIGNCENTER value.

wNumCells

Number of cells in the row.

reserved

Reserved; do not use.


SOPutTabStop [New - Windows 95]
SOPutTabStop

[New - Windows 95]

VOID SOPutTabStop(PSOTAB pTabs, HPROC reserved);

Sets a tab stop for the paragraph.

•	No return value.

pTabs

Address of the SOTAB structure containing the tab stop information.

reserved

Reserved; do not use.

The file parser must call the SOStartTabStops function before calling this function and can set multiple tab stops for a paragraph by calling it multiple times. The file parser must not call any other output function while setting tab stops and must call the SOEndTabStops function after setting the last tab stop.


SOPutTextCell [New - Windows 95]
SOPutTextCell

[New - Windows 95]

VOID SOPutTextCell(PSOTEXTCELL pCell, WORD wCount, char VWPTR * pText,
    WORD bMore, HPROC reserved);

Outputs the text for a cell and indicates whether there is more text to be output for the cell.

•	No return value.

pCell

Address of a SOTEXTCELL structure.

wCount

Number of characters pointed to by pText. The number must not exceed 128 bytes.

pText

Address of the string of text characters to be output.

bMore

More data flag. This parameter can be the SO_YES value to indicate more text to be output or the SO_NO value to indicate none.

reserved

Reserved; do not use.

If there is more text to be output, the file parser must use a subsequent call or calls to the SOPutMoreText function to output the text.


SOPutVarField [New - Windows 95]
SOPutVarField

[New - Windows 95]

VOID SOPutVarField(void VWPTR * pData, WORD wCount, WORD bMore,
    HPROC reserved);

Outputs data for a variable field and indicates whether there is more data to be output for the field.

•	No return value.

pData

Address of the data for the variable field.

wCount

Number of bytes pointed to by pData. The number must not exceed 128 bytes.

bMore

More data flag. This parameter can be the SO_YES value to indicate more data to be output or the SO_NO value to indicate none.

reserved

Reserved; do not use.

If there is more data to be output, the file parser must use a subsequent call or calls to the SOPutMoreVarField function to output the data.


SOPutVectorHeader [New - Windows 95]
SOPutVectorHeader

[New - Windows 95]

VOID SOPutVectorHeader(PSOVECTORHEADER pVectorHeader, HPROC reserved);

Outputs the vector header, specifying the display resolution, x- and y-axis orientation, background color, and color value type (RGB or palette).

•	No return value.

pVectorHeader

Address of a SOVECTORHEADER structure.

reserved

Reserved; do not use.


SOSetDateBase [New - Windows 95]
SOSetDateBase

[New - Windows 95]

VOID SOSetDateBase(DWORD dwBase, WORD wFlags, HPROC reserved);

Sets the base date. All subsequent dates are calculated as the sum of the base date and the given date value.

•	No return value.

dwBase

Base number of Julian days to be automatically added to dates. All dates are entered in Julian day format in the following manner:

Jan. 1, 4713 B.C.	Julian Day 1
Jan. 1, 1 A.D.	Julian Day 1721424
Jan. 1, 1900	Julian Day 2415021
Jan. 1, 1904	Julian Day 2416481
Formats supporting dates before 1582 are not supported.

wFlags

Action flag. This parameter can be the SO_LOTUSHELL value to correct for the Lotus 1-2-3® 1990 leap year bug.

reserved

Reserved; do not use.

This function can only be called from the VwStreamSection function.


SOStartColumnInfo [New - Windows 95]
SOStartColumnInfo

[New - Windows 95]

VOID SOStartColumnInfo(HPROC reserved);

Starts the definition of column information.

•	No return value.

reserved

Reserved; do not use.

The file parser must call this function immediately before setting the information. This function can only be called from the VwStreamSection function.


SOStartFieldInfo [New - Windows 95]
SOStartFieldInfo

[New - Windows 95]

VOID SOStartFieldInfo(HPROC reserved);

Starts the definition of field information.

•	No return value.

reserved

Reserved; do not use.

The file parser calls this function immediately before setting field information. This function can only be called from the VwStreamSection function.


SOStartFontTable [New - Windows 95]
SOStartFontTable

[New - Windows 95]

VOID SOStartFontTable(HPROC reserved);

Starts the definition of a font table.

•	No return value.

reserved

Reserved; do not use.

The file parser must call this function immediately before setting font entries. The function can only be called from the VwStreamSection function.


SOStartPalette [New - Windows 95]
SOStartPalette

[New - Windows 95]

VOID SOStartPalette(HPROC reserved);

Starts the definition of a color palette.

•	No return value.

reserved

Reserved; do not use.

The file parser calls this function immediately before defining palette entries.


SOStartTabStops [New - Windows 95]
SOStartTabStops

[New - Windows 95]

VOID SOStartTabStops(HPROC reserved);

Starts the definition of tab stops for a paragraph.

•	No return value.

reserved

Reserved; do not use.

To set tab stops, use the SOPutTabStop function.

The file parser calls this function immediately before setting the first tab stop for the paragraph.


SOVectorAttr [New - Windows 95]
SOVectorAttr

[New - Windows 95]

VOID SOVectorAttr(INT nItemId, DWORD wDataSize, VOID VWPTR *pData,
    HPROC reserved);

Sets attributes related to drawing vector graphics objects.

•	No return value.

nItemId

Action identifier. This parameter, which specifies the action to carry out and determines the appropriate values for wDataSize and pData, can be one of the vector attribute values in "Constants" later in this topic.

wDataSize

Size, in bytes, of data pointed to by pData.

pData

Address of a buffer containing the information used to carry out the requested action. The meaning and format of the buffer depends on the value of nItemId.

reserved

Reserved; do not use.


SOVectorObject [New - Windows 95]
SOVectorObject

[New - Windows 95]

VOID SOVectorObject(INT nItemId, DWORD dwDataSize, VOID VWPTR *pData,
    HPROC reserved );

Draws or defines the given vector graphics object.

•	No return value.

nItemId

Action flag. This parameter, which specifies the action to carry out and determines the appropriate values for wDataSize and pData, can be one of the vector object values in "Constants" later in this topic.

wDataSize

Size, in bytes, of the data pointed to by pData.

pData

Address of a buffer containing the information used to carry out the requested action. The meaning and format of the buffer depends on the value of nItemId.

reserved

Reserved; do not use.


SUUserPopData [New - Windows 95]
SUUserPopData

[New - Windows 95]

VOID SUUserPopData(VOID VWPTR * pData, HPROC reserved);

Pops user data. The data must have been pushed previously by using the SUUserPushData function.

•	No return value.

pData

Address of the VwStreamUserSaveType structure receiving the data.

reserved

Reserved; do not use.


SUUserPushData [New - Windows 95]
SUUserPushData

[New - Windows 95]

VOID SUUserPushData(VOID VWPTR * pData, HPROC reserved);

Pushes user data.

•	No return value.

pData

Address of a VwStreamUserSaveType structure containing the data to be saved.

reserved

Reserved; do not use.

The data can be retrieved by using the SUUserPopData function.


SUUserRetrieveData [New - Windows 95]
SUUserRetrieveData

[New - Windows 95]

VOID SUUserRetrieveData(WORD wIndex, VOID VWPTR * pData, HPROC reserved);

Retrieves user data.

•	No return value.

wIndex

Index value specifying the data to retrieve. This value must have been previously returned by the SUUserSaveData function.

pData

Address of the VwStreamUserSaveType structure receiving the data.

reserved

Reserved; do not use.

The data must have been previously saved by using the SUUserSaveData function.

This function should not be used. The SUUserPopData function should be used instead.


SUUserSaveData [New - Windows 95]
SUUserSaveData

[New - Windows 95]

WORD SUUserSaveData(VOID VWPTR * pData, HPROC reserved);

Saves user data.

•	Returns the index used to retrieve the data. Indexes are guaranteed to be zero-based and sequential.

pData

Address of a VwStreamUserSaveType structure containing the data to be saved.

reserved

Reserved; do not use.

This function should not be used. The SUUserPushData function should be used instead.


Macros

The following macros are used with file parsers.


SOANGLETENTHS [New - Windows 95]
SOANGLETENTHS

[New - Windows 95]

SOANGLETENTHS(AngleInTenthsOfADegree)

Sets the angle in tenths of a degree.


SOPALETTEINDEX [New - Windows 95]
SOPALETTEINDEX

[New - Windows 95]

SOPALETTEINDEX(Index)

Creates a palette-index color value. Index must specify a valid palette entry index. When this color value is used, the system uses the color from the given palette entry.


SOPALETTERGB [New - Windows 95]
SOPALETTERGB

[New - Windows 95]

SOPALETTERGB(Red, Green, Blue)

Creates a palette-relative RGB color value. Red, Green, and Blue specify the red, green, and blue color intensities and must be in the range 0 to 255. When this color value is specified, the system uses the palette entry that has the color that most closely matches this value.


SORGB [New - Windows 95]
SORGB

[New - Windows 95]

SORGB(Red, Green, Blue)

Creates an RGB color value. Red, Green, and Blue specify the red, green, and blue color intensities and must be in the range 0 to 255.


SOSETRATIO [New - Windows 95]
SOSETRATIO

[New - Windows 95]

SOSETRATIO(Numerator, Denominator)

Sets the ratio. Numerator and Denominator specify the ratio factors and must be values in the range 0 to 65,535.


Structures

The following structures are used with file parsers.


SOARCINFO [New - Windows 95]
SOARCINFO

[New - Windows 95]

typedef struct SOARCINFOtag {
    SORECT Rect;        // see below
    SOANGLE StartAngle; // see below
    SOANGLE EndAngle;   // see below
} SOARCINFO, VWPTR *PSOARCINFO;

Contains information defining the arc to be drawn.

Rect

Rectangle that bounds the ellipse containing the arc.

StartAngle

Angle specifying the starting point of the arc. The angle is defined in tenths of a degree, counterclockwise from the positive x-axis. To set this member, use the SOANGLETENTHS macro.

EndAngle

Angle specifying the ending point of the arc. The angle is defined in tenths of a degree, counterclockwise from the positive x-axis. To set this member, use the SOANGLETENTHS macro.


SOBITMAPHEADER [New - Windows 95]
SOBITMAPHEADER

[New - Windows 95]

typedef struct SOBITMAPHEADERtag {
    WORD wStructSize;   // see below
    WORD wImageFlags;   // see below
    WORD wImageWidth;   // see below
    WORD wImageLength;  // see below
    WORD wTileWidth;    // see below
    WORD wTileLength;   // see below
    WORD wBitsPerPixel; // see below
    WORD wNPlanes;      // see below
    WORD wHDpi;         // see below
    WORD wVDpi;         // see below
} SOBITMAPHEADER, VWPTR *PSOBITMAPHEADER;

Contains information about the bitmap to be output.

wStructSize

Size, in bytes, of the structure.

wImageFlags

Image flags. This member can be a combination of one (and only one) color format value and other attribute values.

The color format can be one of these values:

SO_BGRCOLOR	Pixel values are RGB color values (24-bit only); bytes are stored consecutively in the order B,G,R.
SO_BLACKANDWHITE	Pixels are black or white (1 bit per pixel only).
SO_COLORPALETTE	Pixel values are indexes into the color palette for the bitmap.
SO_GRAYSCALE	Pixel values are gray scale values.
SO_RGBCOLOR	Pixel values are RGB color values (24-bit only); bytes are stored consecutively in the order R,G,B.
Other attributes can be a combination of these values:

SO_BOTTOMTOTOP	The image is provided in scan lines from the bottom up. The default is top to bottom.
SO_WHITEZERO	For gray scale images and black and white images only, a pixel with a value of zero is a white pixel, and increasing pixel values become darker. By default, a value of zero is defined as a black pixel with increasing values becoming lighter.
wImageWidth

Horizontal width, in pixels, of the image.

wImageLength

Vertical length, in pixels, of the image.

wTileWidth

Horizontal width, in pixels, of the tile.

wTileLength

Vertical length, in pixels, of the tile.

wBitsPerPixel

Number of consecutive bits that define the pixel color. The number is currently limited to 1, 4, 8, or 24.

wNPlanes

Color planes. This member must be 1.

wHDpi

Horizontal resolution, in pixels per inch, of the display on which the image originated. If the resolution is not known, this member can be zero.

wVDpi

Vertical resolution, in pixels per inch, of the display on which the image originated. If the resolution is not known, this member can be zero.


SOBORDER [New - Windows 95]
SOBORDER

[New - Windows 95]

typedef struct SOBORDERtag {
    WORD wWidth;         // see below
    SOCOLORREF rgbColor; // see below
    WORD wFlags;         // see below
} SOBORDER, VWPTR * PSOBORDER;

Contains information about the border around a cell in table.

wWidth

Width, in twips, of the border.

rgbColor

Color of the border. This member can be a RGB color value. To set this member, use the SORGB macro.

wFlags

Type of border and the edges to which it applies. This member can be a combination of the SO_BORDERNONE, SO_BORDERDOUBLE, SO_BORDERHAIRLINE, SO_BORDERTHICK, SO_BORDERSHADOW, and SO_BORDERDOTTED values.


SOCOLUMN [New - Windows 95]
SOCOLUMN

[New - Windows 95]

typedef struct SOCOLUMNtag {
    WORD wStructSize; // see below
    LONG dwWidth;     // see below
    char szName[40];  // see below
} SOCOLUMN, VWPTR * PSOCOLUMN;

Contains information about the columns in a spreadsheet.

wStructSize

Size, in bytes, of the structure.

dwWidth

Width, in characters, of the column.

szName

Null-terminated string specifying the name of the column.


SOCPARCANGLE [New - Windows 95]
SOCPARCANGLE

[New - Windows 95]

typedef struct SOCPARCANGLEtag {
    SOPOINT Center;     // center point
    SOANGLE SweepAngle; // sweep angle
} SOCPARCANGLE, VWPTR *PSOCPARCANGLE;

Contains information defining an arc for use in vector graphics output.


SOCPPIEANGLE [New - Windows 95]
SOCPPIEANGLE

[New - Windows 95]

typedef struct SOCPPIEANGLEtag {
    INT nRadius;        // radius
    SOANGLE StartAngle; // starting angle
    SOANGLE SweepAngle; // sweep angle
} SOCPPIEANGLE, VWPTR *PSOCPPIEANGLE;

Contains information defining a pie shape for use in vector graphics output.


SOCPTEXTATPOINT [New - Windows 95]
SOCPTEXTATPOINT

[New - Windows 95]

typedef struct SOCPTEXTATPOINTtag {
    WORD wFormat;    // format of text
    INT nTextLength; // text length
} SOCPTEXTATPOINT, VWPTR *PSOCPTEXTATPOINT;

Contains information defining the format and length of text for use in vector graphics output.


SODATACELL [New - Windows 95]
SODATACELL

[New - Windows 95]

typedef struct SODATACELLtag {
    WORD wStructSize;   //see below
    WORD wStorage;      //see below
    WORD wDisplay;      //see below
    DWORD dwSubDisplay; //see below
    WORD wPrecision;    //see below
    WORD wAlignment;    //see below
    WORD wAttribute;    //see below
    union {
        SOINT32S Int32S; //see below
        SOINT32U Int32U; //see below
        BYTE IEEE4[4];   //see below
        BYTE IEEE8[8];   //see below
        BYTE IEEE10[10]; //see below
        BYTE BCD8[8];    //see below
    } uStorage;
} SODATACELL, VWPTR * PSODATACELL;

Contains information about the data to be placed in a cell of a spreadsheet.

wStructSize

Size, in bytes, of the structure.

wStorage

Storage type. This member can be one of these values:

SO_CELLBCD8I	Packed BCD excess-63.
SO_CELLEMPTY	The cell is empty.
SO_CELLERROR	The cell has an error condition.
SO_CELLIEEE4I	IEEE 4-byte in Intel® (PC) ordering.
SO_CELLIEEE8I	IEEE 8-byte in Intel (PC) ordering.
SO_CELLIEEE10I	IEEE 10-byte in Intel (PC) ordering.
SO_CELLINT32S	32-bit signed integer.
SO_CELLINT32U	32-bit unsigned integer.
wDisplay

Display type. This member can be one of these values:

SO_CELLBOOL	Boolean (0 = FALSE and 1 = TRUE).
SO_CELLDATE	Julian Days since the base date. wStorage may be either an IEEE or integer value.
SO_CELLDATETIME	Julian Days since the base date. wStorage may be either an IEEE or integer value.
SO_CELLDECIMAL	Decimal notation.
SO_CELLDOLLARS	Dollar sign.
SO_CELLEXPONENT	Exponential notation.
SO_CELLNUMBER	General number format.
SO_CELLPERCENT	Percent (not constrained to 0 − 100).
SO_CELLTIME	Decimal part of a day if wStorage is an IEEE value or seconds since 00:00 if wStorage is an integer value.
dwSubDisplay

Display subtype. The values depend on wDisplay value.

For SO_CELLNUMBER and SO_CELLDOLLARS, this member can be a combination of one negative-number format, thousands separator, and cell multiplier.

Negative Number Format
SO_CELLNEG_MINUS	Negative numbers have a minus sign.
SO_CELLNEG_MINUSRED	Negative numbers have a minus sign and are red.
SO_CELLNEG_PAREN	Negative numbers have parentheses.
SO_CELLNEG_PARENRED	Negative numbers have parentheses and are red.
Thousands Separator
SO_CELL1000SEP_COMMA	Commas as 1,000s separator.
SO_CELL1000SEP_NONE	No 1000s separator.
Cell Multiplier
SO_CELLMULT_1	Used for all file parsers.
SO_CELLMULT_01	Used only for Microsoft® Excel viewer.
SO_CELLMULT_05	Used only for Lotus viewer.
SO_CELLMULT_005	Used only for Lotus viewer.
SO_CELLMULT_0005	Used only for Lotus viewer.
SO_CELLMULT_00005	Used only for Lotus viewer.
SO_CELLMULT_500	Used only for Lotus viewer.
SO_CELLMULT_5000	Used only for Lotus viewer.
SO_CELLMULT_0625	Used only for Lotus viewer.
SO_CELLMULT_015625	Used only for Lotus viewer.
For SO_CELLDATETIME, SO_CELLDATE, and SO_CELLTIME, this member can be a combination of one date separator, day format, month format, year format, day of week format, and time format.

Date Separator
SO_CELLDATESEP_MINUS
SO_CELLDATESEP_NONE
SO_CELLDATESEP_PERIOD
SO_CELLDATESEP_SPACE
Day Format
SO_CELLDAY_NONE
SO_CELLDAY_NUMBER
Month Format
SO_CELLMONTH_ABBREV
SO_CELLMONTH_FULL
SO_CELLMONTH_NONE
SO_CELLMONTH_NUMBER
Year Format
SO_CELLYEAR_ABBREV
SO_CELLYEAR_FULL
SO_CELLYEAR_NONE
Day of Week Format
SO_CELLDAYOFWEEK_ABBREV
SO_CELLDAYOFWEEK_FULL
SO_CELLDAYOFWEEK_NONE
Time Format
SO_CELLTIME_HHMM24
SO_CELLTIME_HHMMAM
SO_CELLTIME_HHMMHMS	For example, 14h45m
SO_CELLTIME_HHMMSS24
SO_CELLTIME_HHMMSSAM
SO_CELLTIME_HHMMSSHMS	For example, 14h45m34s
SO_CELLTIME_NONE
wPrecision

Precision or positioning value, depending on the wDisplay value.

For SO_CELLNUMBER and SO_CELLDOLLARS, this member specifies the number of places to the right of the decimal point.

For SO_CELLDATETIME, SO_CELLDATE, and SO_CELLTIME, this member specifies the position in the date time string of each element. It must be a combination of one value for each of the day of week position, month position, day position, year position, and time position.

Day of Week Position
SO_CELLDAYOFWEEK_1
SO_CELLDAYOFWEEK_2
SO_CELLDAYOFWEEK_3
SO_CELLDAYOFWEEK_4
SO_CELLDAYOFWEEK_5
Month Position
SO_CELLMONTH_1
SO_CELLMONTH_2
SO_CELLMONTH_3
SO_CELLMONTH_4
SO_CELLMONTH_5
Day Position
SO_CELLDAY_1
SO_CELLDAY_2
SO_CELLDAY_3
SO_CELLDAY_4
SO_CELLDAY_5
Year Position
SO_CELLYEAR_1
SO_CELLYEAR_2
SO_CELLYEAR_3
SO_CELLYEAR_4
SO_CELLYEAR_5
Time Position
SO_CELLTIME_1
SO_CELLTIME_2
SO_CELLTIME_3
SO_CELLTIME_4
SO_CELLTIME_5
wAlignment

Alignment of data in the cell. This member can be the SO_CELLLEFT, SO_CELLRIGHT, or SO_CELLCENTER value.

wAttribute

Attribute of data in the cell. This member can be a combination of the SO_CELLBOLD, SO_CELLITALIC, SO_CELLUNDERLINE, and SO_CELLSTRIKEOUT values.

Int32S

Signed 32-bit integer.

Int32U

Unsigned 32-bit integer.

IEEE4

Four-byte array representing an IEEE 4-byte floating-point number.

IEEE8

Eight-byte array representing an IEEE 8-byte floating-point number.

IEEE10

Ten-byte array representing an IEEE 10-byte floating-point number.

BCD8

Eight-byte array representing an excess-63 floating-point packed BCD.


SOEMBEDDEDGRAPHIC [New - Windows 95]
SOEMBEDDEDGRAPHIC

[New - Windows 95]

typedef struct SOEMBEDDEDGRAPHICtag {
    SOPOINT Size;       // see below
    SORECT Crop;        // see below
    SOPOINT ScaledSize; // see below
    WORD wBorder;       // see below
    DWORD dwFlags;      // see below
} SOEMBEDDEDGRAPHIC;

Contains information about the size and positioning of an embedded graphics object.

Size

Initial size of the image before scaling and cropping.

Crop

Cropping amount on the top, bottom, left, and right edges.

ScaledSize

Final size of the image after scaling and cropping.

wBorder

Border thickness, in twips. If this member is zero, there is no border.

dwFlags

Flags. This member can be a combination of these values:

SO_CENTERIMAGE	The image is centered in its final rectangle.
SO_MAINTAINASPECT	The image aspect ratio is preserved.


SOEMBEDDEDOBJECT [New - Windows 95]
SOEMBEDDEDOBJECT

[New - Windows 95]

typedef struct SOEMBEDDEDOBJECTtag {
    WORD wStructSize;   // see below
    WORD wObjectType;   // see below
    char szFile[144];   // see below
    WORD wFIType;       // see below
    DWORD dwFileOffset; // see below
    SOEMBEDINFO Info;   // see below
} SOEMBEDDEDOBJECT, VWPTR * PSOEMBEDDEDOBJECT;

Contains information about an embedded object.

wStructSize

Size, in bytes, of the structure.

wObjectType

Type of object type. This member can be the SOEMBED_GRAPHIC or SO_UNKNOWN value.

szFile

Null-terminated string specifying the path and filename of the file that contains the object. If the object is in the current file, this member is NULL.

wFIType

File identifier for object's file. If the object type is the SO_UNKNOWN value, this member is zero.

dwFileOffset

Offset, in bytes, to the embedded object from the start of the given file.

Info

Union containing object-specific information.


SOEMBEDINFO [New - Windows 95]
SOEMBEDINFO

[New - Windows 95]

typedef union SOEMBEDINFOtag {
    SOEMBEDDEDGRAPHIC Graphic; // embedded graphics structure
} SOEMBEDINFO;

Contains information specific to embedded graphics objects.


SOFIELD [New - Windows 95]
SOFIELD

[New - Windows 95]

typedef struct SOFIELDtag {
    WORD wStructSize;
    LONG dwWidth;
    char szName[40];
    WORD wStorage;
    WORD wDisplay;
    DWORD dwSubDisplay;
    WORD wPrecision;
    WORD wAlignment;
} SOFIELD, VWPTR * PSOFIELD;

Contains information about a field in a database.

wStructSize

Size, in bytes, of the structure.

dwWidth

Width, in characters, of the column.

szName

Null-terminated string specifying the name of the field.

wStorage

Storage type. This member can be one of these values:

SO_CELLBCD8I	Packed BCD excess-63.
SO_CELLEMPTY	The cell is empty.
SO_CELLERROR	The cell has an error condition.
SO_CELLIEEE4I	IEEE 4-byte in Intel (PC) ordering.
SO_CELLIEEE8I	IEEE 8-byte in Intel (PC) ordering.
SO_CELLIEEE10I	IEEE 10-byte in Intel (PC) ordering.
SO_CELLINT32S	32-bit signed integer.
SO_CELLINT32U	32-bit unsigned integer.
SO_FIELDTEXTFIX	The field contains a string of fixed length.
SO_FIELDTEXTVAR	The field contains a string of unknown length.
wDisplay

Display type. For more information, see the wDisplay member in the SODATACELL structure.

dwSubDisplay

Display subtype. For more information, see the dwSubDisplay member in the SODATACELL structure.

wPrecision

Precision or positioning value. For more information, see the wPrecision member in the SODATACELL structure.

If wStorage is the SO_FIELDTEXTFIX value, this member specifies the number of characters in the string.

wAlignment

Alignment of data in the cell. This member can be the SO_CELLLEFT, SO_CELLRIGHT, or SO_CELLCENTER value.


SOFILTERINFO [New - Windows 95]
SOFILTERINFO

[New - Windows 95]

typedef struct SOFILTERINFOtag {
    INT wFilterCharSet;      // see below
    U_BYTE szFilterName[32]; // see below
} SOFILTERINFO;

Contains information identifying the file parser.

wFilterCharSet

Character set used for text by the file parser. This member must be the SO_WINDOWS value.

szFilterName

Null-terminated string specifying the name of the file parser. The name should identify either the format of the files being parsed or the product that created the files.


SOGROUPINFO [New - Windows 95]
SOGROUPINFO

[New - Windows 95]

typedef struct SOGROUPINFOtag {
    WORD wStructSize;    // see below
    SORECT BoundingRect; // see below
    INT nTransforms;     // see below
} SOGROUPINFO, VWPTR *PSOGROUPINFO;

Contains information about a group for use with vector graphics output.

wStructSize

Size, in bytes, of the structure.

BoundingRect

Rectangle that bounds all points displayed in the group. This rectangle does not cause clipping to occur. If clipping is needed, a clipping path must be selected.

nTransforms

Number of transformation structures following this structure.


SOLOGBRUSH [New - Windows 95]
SOLOGBRUSH

[New - Windows 95]

typedef struct SOLOGBRUSHtag {
    WORD lbStyle;       // see below
    SOCOLORREF lbColor; // see below
    INT lbHatch;        // see below
} SOLOGBRUSH, VWPTR *PSOLOGBRUSH;

Contains information defining a logical brush for use with vector graphics output.

lbStyle

Brush style. This member can be the SOBS_HATCHED, SOBS_HOLLOW, or SOBS_SOLID value.

lbColor

Color of the brush. This member can be an RGB or palette-relative value. To set this member, use the SORGB or SOPALETTE macro.

lbHatch

Hatch style. This member is used only if lbStyle is SO_HATCHED. This member can be the SOHS_BDIAGONAL, SOHS_CROSS, SOHS_DIAGCROSS, SOHS_FDIAGONAL, SOHS_HORIZONTAL, or SOHS_VERTICAL value.

For a complete definition of the members, see the LOGBRUSH structure.


SOLOGFONT [New - Windows 95]
SOLOGFONT

[New - Windows 95]

typedef struct SOLOGFONTtag {
    INT lfHeight;                   // font height
    INT lfWidth;                    // font width
    INT lfEscapement;               // angle of text line
    INT lfOrientation;              // angle of character baseline
    INT lfWeight;                   // font weight
    BYTE lfItalic;                  // italics
    BYTE lfUnderline;               // underline
    BYTE lfStrikeOut;               // strikeout
    BYTE lfCharSet;                 // character set
    BYTE lfOutputPrecision;         // output precision
    BYTE lfClipPrecision;           // clipping precision
    BYTE lfQuality;                 // output quality
    BYTE lfPitchAndFamily;          // pitch and family of font
    BYTE lfFaceName[SOLF_FACESIZE]; // typeface name of font
} SOLOGFONT, VWPTR *PSOLOGFONT;

Contains information that defines a logical font for use with vector graphics output. The lfHeight and lfWidth members must be in the same logical units as all of the other drawing commands. For a description of the members, see the LOGFONT structure.


SOLOGPEN [New - Windows 95]
SOLOGPEN

[New - Windows 95]

typedef struct SOLOGPENtag {
    INT loPenStyle;     // see below
    SOPOINT loWidth;    // see below
    SOCOLORREF loColor; // see below
} SOLOGPEN, VWPTR *PSOLOGPEN;

Contains information that defines a logical pen for use with vector graphics output. For a complete definition of the members, see the LOGPEN structure.

loPenStyle

Pen Style. This member can be the SOPS_SOLID, SOPS_DASH, SOPS_DOT, SOPS_DASHDOT, SOPS_DASHDOTDOT, SOPS_NULL, or SOPS_INSIDEFRAME value.

loWidth

Width, in logical units, of the pen. The x member in the POINT structure is used, and the y member is ignored.

loColor

Color of the brush. This member can be an RGB or palette-relative value. To set this member, use the SORGB or SOPALETTE macro.


SOPARAINDENTS [New - Windows 95]
SOPARAINDENTS

[New - Windows 95]

typedef struct SOPARAINDENTStag {
    INT FirstLineIndent; // see below
    INT LeftIndent;      // see below
    INT RightIndent;     // see below
} SOPARAINDENTS, VWPTR *PSOPARAINDENTS;

Contains information about paragraph indents for use with vector graphics output.

FirstLineIndent

Distance, from the left edge of the frame, to indent the first line of each paragraph.

LeftIndent

Distance, from the left edge of the frame, to indent all lines but the the first line of each paragraph.

RightIndent

Distance, from the right edge of the frame, to indent all lines of each paragraph.


SOPATHINFO [New - Windows 95]
SOPATHINFO

[New - Windows 95]

typedef struct SOPATHINFOtag {
    WORD wStructSize;    // see below
    SORECT BoundingRect; // see below
    INT nTransforms;     // see below
} SOPATHINFO, VWPTR *PSOPATHINFO;

Contains information about a path for use with vector graphics output.

wStructSize

Size, in bytes, of the structure.

BoundingRect

Rectangle that bounds all points displayed in the path. This rectangle does not cause clipping to occur. If clipping is needed, a clipping path must be selected.

nTransforms

Number of transformation structures following this structure.


SOPOINT [New - Windows 95]
SOPOINT

[New - Windows 95]

typedef struct SOPOINTtag {
    INT x;  // x-coordinate
    INT y;  // y-coordinate
} SOPOINT, VWPTR *PSOPOINT;

Contains coordinates for a point.


SOPOLYINFO [New - Windows 95]
SOPOLYINFO

[New - Windows 95]

typedef struct SOPOLYINFOtag {
    WORD wFormat; // see below
    INT nPoints;  // see below
} SOPOLYINFO, VWPTR *PSOPOLYINFO;

Contains information about the type and number of vertices of a polyline, polygon, spline, or Bezier curve.

wFormat

Format type. This member can be one of these values:

SOPT_BEZIERCLOSE	SOPT_POLYGON
SOPT_BEZIEROPEN	SOPT_POLYLINE
SOPT_CPPOLYGON	SOPT_SPLINECLOSE
SOPT_CPPOLYLINE	SOPT_SPLINEOPEN
nPoints

Number of vertices in the object.


SORECT [New - Windows 95]
SORECT

[New - Windows 95]

typedef struct SORECTtag {
    INT left;    // x-coordinate of upper left corner
    INT top;     // y-coordinate of upper left corner
    INT right;   // x-coordinate of lower right corner
    INT bottom;  // y-coordinate of lower right corner
} SORECT, VWPTR *PSORECT;

Contains the dimensions of a rectangle.


SOTAB [New - Windows 95]
SOTAB

[New - Windows 95]

typedef struct SOTABtag {
    WORD wType;    // see below
    WORD wChar;    // see below
    WORD wLeader;  // see below
    LONG dwOffset; // see below
} SOTAB, VWPTR * PSOTAB;

Contains information about tab stops.

wType

Type of tab stop. This member can be the SO_TABLEFT, SO_TABRIGHT, SO_TABCENTER, or SO_TABCHAR value.

wChar

Alignment character if wType is SO_TABCHAR. Tabs are aligned on this character.

wLeader

Repeating leader character for the tab. If this member is zero, there is no leader.

dwOffset

Offset of the tab from the left page margin.


SOTABLECELLINFO [New - Windows 95]
SOTABLECELLINFO

[New - Windows 95]

typedef struct SOTABLECELLINFOtag {
    WORD wWidth;             // see below
    WORD wMerge;             // see below
    WORD wShading;           // see below
    PSOBORDER pLeftBorder;   // see below
    PSOBORDER pRightBorder;  // see below
    PSOBORDER pTopBorder;    // see below
    PSOBORDER pBottomBorder; // see below
} SOTABLECELLINFO, VWPTR *PSOTABLECELLINFO;

Contains information about cells in a table.

wWidth

Width, in twips, of the cell.

wMerge

Merge flag specifying whether the cell is merged with any neighboring cells. This member can be a combination of the SO_MERGELEFT, SO_MERGERIGHT, SO_MERGEABOVE, and SO_MERGEBELOW values.

wShading

Intensity value for background shading in the range of 0 to 255. If this member is zero, there is no background shading.

pLeftBorder

Left border.

pRightBorder

Right border.

pTopBorder

Top border.

pBottomBorder

Bottom border.


SOTEXTATARCANGLE [New - Windows 95]
SOTEXTATARCANGLE

[New - Windows 95]

typedef struct SOTEXTATARCANGLEtag {
    SOARCINFO ArcInfo; // see below
    WORD wFormat;      // see below
    INT nTextLength;   // see below
} SOTEXTATARCANGLE, VWPTR *PSOTEXTATARCANGLE;

Contains information about text for use with vector graphics output.

ArcInfo

Arc information defining the arc relative to which the text is located. Only the starting angle is used to locate the point; the ending angle is ignored.

wFormat

Alignment format, indicating the relationship between the given point and the base line or bounding rectangle of the text. This member can be a combination of these values:

SOTA_BASELINE	Aligns the point and base line of the font.
SOTA_BOTTOM	Aligns the point and bottom of the bounding rectangle.
SOTA_CENTER	Aligns the point and horizontal center of the bounding rectangle.
SOTA_LEFT	Aligns the point and left side of the bounding rectangle.
SOTA_RIGHT	Aligns the point and right side of the bounding rectangle.
SOTA_TOP	Aligns the point and top of the bounding rectangle.
nTextLength

Length of text string that follows the structure.


SOTEXTATPOINT [New - Windows 95]
SOTEXTATPOINT

[New - Windows 95]

typedef struct SOTEXTATPOINTtag {
    SOPOINT Point;   // see below
    WORD wFormat;    // see below
    INT nTextLength; // see below
} SOTEXTATPOINT, VWPTR *PSOTEXTATPOINT;

Contains information about text at a point.

Point

Point that locates the text.

wFormat

Alignment format, indicating the relationship between the point and the base line or bounding rectangle of the text. This member can be a combination of these values:

SOTA_BASELINE	Aligns the point and base line of the font.
SOTA_BOTTOM	Aligns the point and bottom of the bounding rectangle.
SOTA_CENTER	Aligns the point and horizontal center of the bounding rectangle.
SOTA_LEFT	Aligns the point and left side of the bounding rectangle.
SOTA_RIGHT	Aligns the point and right side of the bounding rectangle.
SOTA_TOP	Aligns the point and top of the bounding rectangle.
nTextLength

Length of the text string that follows the structure.


SOTEXTCELL [New - Windows 95]
SOTEXTCELL

[New - Windows 95]

typedef struct SOTEXTCELLtag {
    WORD wStructSize; // see below
    WORD wAlignment;  // see below
    WORD wAttribute;  // see below
} SOTEXTCELL, VWPTR * PSOTEXTCELL;

Contains information about the alignment and attributes of text in a spreadsheet cell.

wStructSize

Size, in bytes, of the structure.

wAlignment

Alignment. This member can be the SO_CELLLEFT, SO_CELLRIGHT, SO_CELLCENTER, or SO_CELLFILL value.

wAttribute

Attributes. This member can be a combination of the SO_CELLBOLD, SO_CELLITALIC, SO_CELLUNDERLINE, and SO_CELLSTRIKEOUT values.


SOTEXTINRECT [New - Windows 95]
SOTEXTINRECT

[New - Windows 95]

typedef struct SOTEXTINRECTtag {
    SORECT Rect;     // see below
    WORD wFormat;    // see below
    INT nTextLength; // see below
} SOTEXTINRECT, VWPTR *PSOTEXTINRECT;

Contains information about text for use with vector graphics output.

Rect

Rectangle in which text is formatted.

wFormat

Format of the string. This member can be a combination of these values:

SODT_BOTTOM	SODT_NOPREFIX
SODT_CALCRECT	SODT_RIGHT
SODT_CENTER	SODT_SINGLELINE
SODT_EXPANDTABS	SODT_TABSTOP
SODT_EXTERNALLEADING	SODT_TOP
SODT_LEFT	SODT_VCENTER
SODT_NOCLIP	SODT_WORDBREAK
nTextLength

Length of the text string that follows the structure.


SOTRANSFORM [New - Windows 95]
SOTRANSFORM

[New - Windows 95]

typedef struct SOTRANSFORMtag {
    WORD wTransformFlags;  // see below
    SOPOINT Origin;        // see below
    INT xOffset;           // see below
    INT yOffset;           // see below
    SORATIO xScale;        // see below
    SORATIO yScale;        // see below
    SORATIO xSkew;         // see below
    SORATIO ySkew;         // see below
    SOANGLE RotationAngle; // see below
} SOTRANSFORM, VWPTR *PSOTRANSFORM;

Contains information about a transformation for use with vector graphics output.

wTransformFlags

Type of transformation. This member can be a combination of these values:

SOTF_NOTRANSFORM	SOTF_XSKEW
SOTF_ROTATE	SOTF_YOFFSET
SOTF_XOFFSET	SOTF_YSCALE
SOTF_XSCALE	SOTF_YSKEW
TSOTF_ROTATE may be combined only with SOTF_XOFFSET and SOTF_YOFFSET. In addition, no other values may be combined with SOTF_NOTRANSFORM.

Origin

Point of origin for all transformations, except for SOTF_XOFFSET and SOTF_YOFFSET.

xOffset and yOffset

Offset values to use for the SOTF_XOFFSET and OTF_YOFFSET transformations. The x and y members of this value are added to the x- and y-coordinates of all points in the transformed object.

xScale

Ratio to use for SOTF_XSCALE transformations. This ratio is used to scale the image on the x-axis from the given origin. To set this member, use the SOSETRATIO macro.

yScale

Ratio to use for SOTF_YSCALE transformations. This ratio is used to scale the image on the y-axis from the given origin. To set this member, use the SOSETRATIO macro.

xSkew

Ratio to use for SOTF_XSKEW transformations. This ratio used to skew the image horizontally from the given origin. To set this member, use the SOSETRATIO macro.

ySkew

Ratio to use for SOTF_YSKEW transformations. This ratio used to skew the image vertically from the given origin. To set this member, use the SOSETRATIO macro.

RotationAngle

Angle, in tenths of a degree, to use for SOTF_ROTATE transformations. All points are rotated this many degrees about the given origin. This value must be set by using the SOANGLETENTHS macro. A SOANGLE variable should not be set directly. Additional macros will be made available as needed.

The transformation equation follows.

x' = Origin.x + (xScale * (x-Origin.x)) + (xSkew*(y-Origin.y)) + xOffset
y' = Origin.y + (yScale * (y-Origin.y)) + (ySkew*(x-Origin.x)) + yOffset


SOVECTORHEADER [New - Windows 95]
SOVECTORHEADER

[New - Windows 95]

typedef struct SOVECTORHEADERtag {
    WORD wStructSize;    // see below
    SORECT BoundingRect; // see below
    WORD wHDPI;          // see below
    WORD wVDPI;          // see below
    WORD wImageFlags;    // see below
    SOCOLOR BkgColor;    // see below
} SOVECTORHEADER, VWPTR *PSOVECTORHEADER;

Contains information defining the size and attributes of the rectangle in which vector graphics are drawn.

wStructSize

Size, in bytes, of the structure.

BoundingRect

Rectangle that bounds all drawing commands.

wHDpI

Dots per inch resolution along the x-axis.

wVDpI

Dots per inch resolution along the y-axis.

wImageFlags

Image flags. This member can be a combination of these values:

SO_VECTORCOLORPALETTE	Uses a color palette. Color values must be palette entry indexes or palette-relative RGB values.
SO_VECTORRGBCOLOR	Uses RGB color values.
SO_XISLEFT	Has positive x-coordinates left of the y-axis.
SO_YISUP	Has positive y-coordinates up from the x-axis.
BkgColor

Color of the background in the bounding rectangle. This value must be set by using one of the three color macros: SOPALETTEINDEX, SORGB, or SOPALETTERGB. However, SORGB should not be used if a palette is defined.


Constants

The following vector object values and vector attribute values are used with the vector graphics functions.


Vector Object Values [New - Windows 95]
Vector Object Values

[New - Windows 95]

SO_ARC

Draws an arc. dwDataSize must be 4* sizeof(SOPOINT), and pData must be the address of four SOPOINT structures.

SO_ARCCLOCKWISE

Draws an arc in the clockwise direction. dwDataSize must be 4* sizeof(SOPOINT), and pData must be the address of four SOPOINT structures.

SO_ARCANGLE

Draws an arc by defining the angles of the two points on the ellipse that locate the start and end of the arc. dwDataSize must be sizeof(SOARCINFO), and pData must be the address of a SOARCINFO structure that defines the arc.

SO_ARCANGLECLOCKWISE

Draws an arc in the clockwise direction by defining the angles of the two points on the ellipse that locate the start and end of the arc. dwDataSize must be sizeof(SOARCINFO), and pData must be the address of a SOARCINFO structure.

SO_CHORD

Draws a chord. dwDataSize must be 4 * sizeof(SOPOINT), and pData must be the address of four SOPOINT structures.

SO_CHORDANGLE

Draws a chord by defining the angles of the two points on the ellipse that locate the start and end of the chord. dwDataSize must be sizeof(SOARCINFO), and pData must be the address of a SOARCINFO structure that defines the chord in terms of the arc located on the chord.

SO_TEXTINRECT

Draws text in a rectangle. dwDataSize must be sizeof(SOTEXTINRECT) added to the length of the text string, and pData must be the address of a SOTEXTINRECT structure followed by the text string.

SO_ELLIPSE

Draws an ellipse. dwDataSize must be 2 * sizeof(SOPOINT), and pData must be the address of two SOPOINT structures.

SO_FLOODFILL

Fills the area with the given color. dwDataSize must be sizeof(SOPOINT) added to sizeof(SOCOLORREF), and pData must be the address of a variable containing the coordinates of the point to start at followed by the RGB color value to use to fill the area.

SO_LINE

Draws a line from point 1 to point 2 using the current pen. dwDataSize must be 2 * sizeof(SOPOINT), and pData must be the address of two SOPOINT structures.

SO_PIE

Draws a pie shape. dwDataSize must be 4 * sizeof(SOPOINT), and pData must be the address of four SOPOINT structures.

SO_PIEANGLE

Draws a pie by defining the angles of the two points on the ellipse that locate the start and end of the pie. dwDataSize must be sizeof(SOARCINFO), and pData must be the address of a SOARCINFO structure that defines the pie in terms of the arc located on the pie.

SO_STARTPOLY

Starts drawing of a polygon. dwDataSize must be sizeof(SOPOLYINFO), and pData must be the address of a SOPOLYINFO structure.

SO_POINTS

Specifies vertices of a polygon. dwDataSize must be N * sizeof(SOPOINT), and pData must be the address of consecutively stored SOPOINT structures. At most, SOMAXPOINTS can be passed in a single SO_POINTS object. Multiple SO_POINTS objects can be generated to define all of the points associated with a polygon object. The number of points defined in SO_STARTPOLY must be defined using SO_POINTS before the object is closed with SO_ENDPOLY.

SO_ENDPOLY

Ends drawing of a polygon. dwDataSize must be zero, and pData must be NULL.

SO_RECTANGLE

Draws a rectangle. dwDataSize must be 2 * sizeof(SOPOINT), and pData must be the address of two SOPOINT structures.

SO_ROUNDRECT

Draws a rectangle with rounded corners. dwDataSize must be 3 * sizeof(SOPOINT), and pData must be address of the three SOPOINT structures.

SO_SETPIXEL

Sets the color of a pixel. dwDataSize must be sizeof(SOPOINT) added to sizeof(SOCOLORREF), and pData must be the address of a variable containing the pixel point followed by the RGB color value to set.

SO_TEXTATPOINT

Draws text at the given point. dwDataSize must be sizeof(SOTEXTATPOINT) added to the length of the text string, and pData must be the address of a SOTEXTATPOINT structure followed by the text string.

SO_TEXTATARCANGLE

Draws text at the given location. dwDataSize must be sizeof(SOTEXTATARCANGLE) added to the length of the text string, and pData must be the address of a SOTEXTATARCANGLE structure followed by the text string.

SO_BEGINPATH

Starts the definition of a path. dwDataSize must be sizeof(SOPATHINFO) added to GroupInfo.nTransforms*sizeof(SOTRANSFORM), and pData must be the address of a SOPATHINFO structure followed by the number of SOTRANSFORM structures defined in the nTransforms member of the SOPATHINFO structure. The transformations will occur to all objects in the path in the order supplied. For more information, see the SO_OBJECTTRANSFORM vector attribute value.

This item is used to begin the definition of a path. Paths are a collection of points connected by lines that form opened or closed objects. Multiple subpaths may be created using SO_CLOSESUBPATH while defining a path. Note that the current object and group transformations will also apply during creation of a path. This allows maximum flexibility with transforming paths. Any object can be rendered to create the path. However, due to current limitations, text objects will not be added to the path. Multiple levels of paths are also allowed.

SO_ENDPATH

Ends the definition of a path. dwDataSize must be zero, and pData must be NULL.

SO_CLOSESUBPATH

Closes the current subpath. dwDataSize must be zero, and pData must be NULL.

SO_DRAWPATH

Strokes, fills, or both strokes and fills the current path with the current pen and brush. Since the group, path, and object transformations were applied when the path was created, they are not applied again. dwDataSize must be sizeof(WORD), and pData must be the address of a variable containing the SODP_STROKE or SODP_FILL value, or both.

SO_BEGINGROUP

Starts the definition of a group. dwDataSize must be sizeof(SOGROUPINFO) added to GroupInfo.nTransforms*sizeof(SOTRANSFORM), and pData must be the address of a SOGROUPINFO structure followed by the number of SOTRANSFORM structures defined in the nTransforms member of the SOGROUPINFO structure. The transformations will occur to all objects in the group in the order supplied. For more information, see the SO_OBJECTTRANSFORM vector attribute value.

SO_ENDGROUP

Ends the definition of a group. dwDataSize must be zero, and pData must be NULL.

SO_CPSET

Moves the current pen position to this point. dwDataSize must be sizeof(SOPOINT), and pData must be the address of the variable containing the point.

SO_CPLINE

Draws a line from the current pen position. dwDataSize must be sizeof(SOPOINT), and pData must be the address of a variable containing the point to draw to.

SO_CPRECTANGLE

Draws a rectangle starting at the current pen position. dwDataSize must be sizeof(SOPOINT), and pData must be the address of a variable containing the point to be the opposite corner of the rectangle.

SO_CPELLIPSE

Draws an ellipse around the current point with an x- and y-radius described by the SOPOINT data. dwDataSize must be sizeof(SOPOINT), and pData must be the address of a variable containing the x- and y-radius values.

SO_CPARCTRIPLE

Draws a circle arc from the current point through the first point and ending at the second point. dwDataSize must be 2*(sizeof(SOPOINT), and pData must be the address of two SOPOINT structures.

SO_CPARCANGLE

Draws an arc from the current point pivoting around the center point of the specified sweep angle. dwDataSize must be sizeof(SOCPARCANGLE), and pData must be the address of a SOCPARCANGLE structure that gives the center point of the arc and the sweep angle.

SO_CPPIEANGLE

Draws a pie with the current position as the center and with the given start and sweep angles. dwDataSize must be sizeof(SOCPPIECANGLE), and pData must be the address of a SOCPPIEANGLE structure that gives the radius of the circle.

SO_BEGINSYMBOL

Starts the definition of a symbol. A symbol is collection of vector commands that together make up a single symbol. Symbols are considered in the wrapping algorithm of frame text. dwDataSize must be sizeof(SORECT), and pData must be the address of a SORECT structure that identifies the bounding rectangle of all commands used within the symbol.

SO_ENDSYMBOL

Ends the definition of a symbol. dwDataSize must be zero, and pData must be NULL.

SO_BEGINTEXTFRAME

Starts the definition of a text frame. A text frame is used in conjunction with SO_TEXTINPARA to wrap text within a frame. Text is wrapped according to the SO_PARAINDENTS vector attribute value. Symbols are included in the wrapping algorithm. dwDataSize must be sizeof(SORECT), and pData must be the address of a SORECT structure that identifies the bounding rectangle of the text frame.

SO_ENDTEXTFRAME

Ends the definition of a text frame. dwDataSize must be zero, and pData must be NULL.

SO_TEXTINPARA

Draws the text string in the current font and text attributes at the current wrap location. The wrap location is moved by the text extent. Any words that would extend beyond the right indent of the frame are wrapped. This object is only valid within a text frame. dwDataSize must be sizeof(INT) added to the length of the text string, and pData must be the address of a integer variable containing the size of the text string that follows.

SO_PARAEND

Ends a paragraph. dwDataSize must be zero, and pData must be NULL.


Vector Attribute Values [New - Windows 95]
Vector Attribute Values

[New - Windows 95]

SO_SELECTFONT

Selects the given font. dwDataSize must be sizeof(SOLOGFONT), and pData must be the address of a SOLOGFONT structure.

SO_SELECTPEN

Selects the given pen. dwDataSize must be sizeof(SOLOGPEN), and pData must be the address of a SOLOGPEN structure.

SO_SELECTBRUSH

Selects the given brush. dwDataSize must be sizeof(SOLOGBRUSH), and pData must be the address of a SOLOGBRUSH structure.

SO_POLYFILLMODE

Sets the polygon-filling mode. dwDataSize must be sizeof(INT), and pData must be the address of a variable containing either the SOPF_ALTERNATE or SOPF_WINDING value.

SO_TEXTCHAREXTRA

Sets the text character extra value. dwDataSize must be sizeof(INT), and pData must be the address of a variable containing a value. This attribute affects text objects.

SO_DRAWMODE

Sets the drawing mode used when drawing the pen and interiors. dwDataSize  must be sizeof(INT), and pData must be the address of a variable containing one of these values:

SOR2_BLACK	SOR2_NOT
SOR2_COPYPEN	SOR2_NOTCOPYPEN
SOR2_MASKNOTPEN	SOR2_NOTMASKPEN
SOR2_MASKPEN	SOR2_NOTMERGEPEN
SOR2_MASKPENNOT	SOR2_NOTXORPEN
SOR2_MERGENOTPEN	SOR2_WHITE
SOR2_MERGEPEN	SOR2_XORPEN
SOR2_NOP
SO_TEXTCOLOR

Sets the foreground color. dwDataSize must be sizeof(SOCOLORREF), and pData must be the address of a variable containing a RGB or palette-relative color value. To set this value, use the SORGB or SOPALETTE macro.

SO_BKMODE

Sets the background mode. dwDataSize must be sizeof(INT), and pData must be the address of a variable containing either the SOBK_OPAQUE or SOBK_TRANSPARENT value.

SO_BKCOLOR

Sets the background color used for styled lines, hatched brushes, and text when the background mode is SOBK_OPAQUE. dwDataSize must be sizeof(SOCOLORREF), and pData must be the address of a variable containing an RGB or palette-relative color value. To set this value, use the SORGB or SOPALETTE macro.

SO_OBJECTTRANSFORM

Sets object transformations. dwDataSize must be sizeof (INT) added to nCount*sizeof(SOTRANSFORM), and pData must be one INT (nCount) followed by that  number of SOTRANSFORM structures. The transformations will occur in the order supplied.

SO_CLIPMODE

Sets the clipping mode. dwDataSize must be sizeof(WORD), and pData must be the address of a variable containing either the SO_DONOTCLIP or SO_CLIPTOPATH value.

SO_POINTRELATION

Sets the coordinate orientation. dwDataSize must be sizeof(INT), and pData must be the address of a variable containing the SOPR_ABSOLUTE or SOPR_RELATIVE value.

SO_PARAINDENTS

Sets the paragraph indents within a text frame, defining the first, left, and right indents of paragraph text being built into the frame. These values are only valid when within a text frame. All values are in the current coordinate system. dwDataSize must be sizeof(SOPARAINDENTS), and pData must be the address of a SOPARAINDENTS structure.

SO_PARAALIGN

Sets the alignment of paragraph text being built into a text frame. dwDataSize must be sizeof(WORD), and pData must be the address of a 16-bit variable containing the SO_ALIGNLEFT, SO_ALIGNCENTER, SO_ALIGNRIGHT, or SO_ALIGNJUSTIFY value.


Briefcase Reconcilers

A briefcase reconciler gives the Windows 95 Briefcase the means to reconcile different versions of a document.


About Briefcase Reconcilers

A briefcase reconciler combines different input versions of a document to produce a single, new output version of the document. You may need to create a briefcase reconciler to support your type of document. This article describes briefcase reconcilers and explains how to create them.


Reconciliation

A document is a collection of information that can be copied and changed. A document is said to have versions if the content of at least two copies of the document are different. Reconciliation produces a single version of a document from two or more initial versions. Typically, the final version is a combination of information from the initial versions with the most recent or most useful information preserved.

Reconciliation is initiated by the Briefcase when it determines that two or more copies of the same document are different. The Briefcase, which is called the initiator in this context, locates and starts the briefcase reconciler associated with the given document type. The reconciler compares the documents and determines which portions of the documents to retain. Some reconcilers may require user interaction to complete reconciliation. Others may complete reconciliation without user interaction. The reconciler can be contained within an application or be an extension implemented as a dynamic-link library (DLL).

Some briefcase reconcilers may create residues. A residue is a document, usually having the same file type as the initial document, that contains information not saved in the merged version. Residues are typically used to give authors a quick way to determine what information from their original document is not in the final merged version. If a reconciler supports residues, it creates one residue for each of the original versions of the document. Residues are not created unless the initiator requests them. The Briefcase does not currently request residues, but future initiators may.

Some briefcase reconcilers work in conjunction with the Briefcase to provide the user with a means to terminate reconciliation. This capability is useful for a user who may decide that the reconciliation should not proceed. A reconciler typically provides a termination object when the reconciliation requires user interaction and may be lengthy. In some environments, a reconciler may allow partial reconciliation, enabling a user to temporarily suspend a reconciliation and resume it later. The Briefcase does not currently support partial reconciliation, but future initiators may.


Creating a Briefcase Reconciler

You create a briefcase reconciler by implementing the reconciliation interfaces. At a minimum, a reconciler implements the IReconcilableObject interface and the IPersistStorage or IPersistFile interface. As the initiator, the Briefcase determines when reconciliation is needed and calls the IReconcilableObject::Reconcile member function to initiate reconciliation.

Although the Reconcile member function can provide a wide-ranging set of reconciliation capabilities, a briefcase reconciler carries out only minimal reconciliation in most cases. In particular, the Briefcase does not require the reconciler to support residue generation or to support the termination object. Also, the reconciler carries out a single top to bottom reconciliation and must not return the REC_E_NOTCOMPLETE value; that is, it should not attempt partial reconciliation.

The Briefcase provides the IReconcileInitiator interface. The briefcase reconciler can use the IReconcileInitiator::SetAbortCallback member function to set the termination object. The Briefcase does not use version identifiers and can, therefore, not provide previous versions of a document if a reconciler requests them using the corresponding member functions in IReconcileInitiator.

The Briefcase passes file monikers to Reconcile representing the versions of the document to be reconciled. The briefcase reconciler gains access to the versions by using either the IMoniker::BindToObject or IMoniker::BindToStorage member function. The latter is generally faster and is recommended. The reconciler must release any objects or storage to which it binds.

When the briefcase reconciler uses BindToStorage, it binds to storage that is either flat storage (a stream) or OLE-defined structured storage. If the reconciler expects flat storage, it should use BindToStorage to request the IStream interface. If the reconciler expects structured storage, it should request the IStorage interface. In both cases, it should request read-only direct (nontransacted) access to the storage; read-write access may not generally be available.

A minimal briefcase reconciler typically looks directly at the storage of the other versions and deals with embedded objects in a very primitive manner, such as merging two versions of the object by including both versions in the output version.

The initiator locates the appropriate briefcase reconciler by using a subset of the logic implemented by the GetClassFile function to determine the class of a given file and then looks in the registry for the reconciler class associated with the given file class. The Briefcase, like other shell components, determines the class of a file solely by the filename extension. A file's extension must have a registered class for the Briefcase to invoke a reconciler for the file. You must set a registry entry of the following form when installing your reconciler.

CLSID\clsid\Roles\Reconciler\reconciler-classid

The class must be quick loading, must be designated _MULTIPLEUSE, and, unless marshallers are provided for the reconciliation interface, must be an in-process server (contained in a DLL) rather than a local server (implemented in an .EXE file).


User Interaction

A briefcase reconciler should attempt to carry out reconciliation without user intervention. The more automated the reconciliation, the better the user's perception of the process.

In some cases, user intervention may be valuable. For example, a document system may require a user to review changes before accepting the merged version of a document or may require comments from the user explaining the changes that have been made. In these cases, the initiator, not the briefcase reconciler, is responsible for querying the user and carrying out the user's instructions.

In other cases, user intervention may be necessary. For example, when two versions have been edited in incompatible ways. In such cases, either the initiator or briefcase reconciler must query the user for instructions on how to resolve the conflict. In general, no initiator can rely on completing a reconciliation without expecting some user interaction. Reconcilers, on the other hand, have the option of interacting with the user to resolve conflicts or requiring the initiator to do so.


Embedded Objects

When reconciling a document, the briefcase reconciler itself may become an initiator if it discovers an embedded object of a type that it cannot reconcile. In this case, the reconciler needs to recursively reconcile each of the embedded objects and assume all the responsibilities of an initiator.

To carry out the recursion, the briefcase reconciler loads the object and queries for the appropriate interface. The handler for the object must support the interface. If any member function of the interface returns the OLE_E_NOTRUNNING value, the reconciler must run the object in order to carry out the operation. Because code for embedded objects is not always available, a reconciler must provide a solution for this condition. For example, the reconciler might include both old and new versions of the embedded object in the reconciled version. The reconciler must not attempt to reconcile across links.

The initiator stores the document versions being merged. In many cases, the initiator has access to the storage of each version and saves the result of reconciliation using similar storage. Sometimes, however, the initiator may have an in-memory object for which no persistent version is available. This situation can occur when a document containing open embedded objects must be reconciled before being saved. In such cases, the initiator saves the result of the reconciliation in the version found in memory.

The initiator uses the IPersistStorage interface to bind (load) the merged version. The initiator uses the IPersistStorage::Load member function if an initial version has already been created and uses the IPersistStorage::InitNew member function for the initial version. Once the merged version is loaded, the initiator uses QueryInterface to retrieve the address of the IReconcilableObject interface. This interface gives the initiator access to the storage of the existing residues and gives it a way to create storage for any new residues. Then the initiator directs the interface to carry out the reconciliation. The initiator actually queries for the IPersistFile interface before IPersistStorage. If the reconciler supports IPersistFile, the initiator manipulates the replica through the IPersistFile rather than IPersistStorage member functions. This permits reconciliation of files that are not stored as compound documents.

Once the reconciliation is complete, the initiator can save the merged version by using the IPersistStorage or IPersistFile interface. During reconciliation, the briefcase reconciler creates residues as needed and writes their persistent bits to storage. If the merged version is a stream, the IStorage interface passed to IPersistStorage::Load contains a stream named "Contents" with its storage state set to STATEBITS_FLAT. (You can set the state bits by using the IStorage::Stat member function.) After the merge, the initiator saves the merged version by writing the data in an appropriate manner. It should ensure that STATEBITS_FLAT is set as appropriate for the storage.


Residues

The initiator indicates whether it wants residues by setting the pstgNewResidues parameter to a valid address when calling the IReconcilableObject::Reconcile member function. If the reconciler does not support the creation of residues, it must return immediately the REC_E_NORESIDUES value, unless the dwFlags parameter specifies the RECONCILEF_NORESIDUESOK value.

The briefcase reconciler returns residues to the initiator by creating new storage elements and copying them to the array pointed to by pstgNewResidues. For structured storage residues, the reconciler copies an IStorage interface, and for flat storage residues, it copies either an IStream or IStorage interface with the STATEBITS_FLAT flag set. The reconciler uses IStorage to create the necessary storage, using IStorage::CreateStream to create flat storage for a residue that is a stream and IStorage::CreateStorage to create structured storage.

The initiator prepares pstgNewResidues such that it contains no elements in the nonreserved part of the IStorage namespace. The briefcase reconciler places each residue in an element whose name corresponds to the order of its initial version. For example, the first residue is contained in "1," the second in "2," and so on. If the reconciled object itself produces a residue, that is found in the element named "0."

The briefcase reconciler commits each of the newly created elements individually, ensuring that the initiator has access to the information. The reconciler does not, however, commit pstgNewResidues itself. The initiator is responsible for committing this or otherwise disposing of it.


Reference

This section contains information about the reconciliation interfaces. When handling errors, a member function can return only those error values that are explicitly defined as possible return values. Furthermore, the member function must set all variables whose addresses are passed as parameters to NULL before returning from the error.


Interfaces and Member Functions


IReconcilableObject [New - Windows 95]
IReconcilableObject

[New - Windows 95]

The IReconcilableObject interface carries out the reconciliation of a document. This interface has the GetProgressFeedbackMaxEstimate and Reconcile member functions. The briefcase reconciler is responsible for implementing this interface.


IReconcilableObject::GetProgressFeedbackMaxEstimate [New - Windows 95]
IReconcilableObject::GetProgressFeedbackMaxEstimate

[New - Windows 95]

HRESULT IReconcilableObject::GetProgressFeedbackMaxEstimate(
    ULONG * pulProgressMax);

Retrieves an estimated measurement of the amount of work required to complete a reconciliation. This value corresponds to a similar value that is passed with the IReconcileInitiator::SetProgressFeedback member function during reconciliation. Reconcilers typically use this member function to estimate the work needed to reconcile an embedded document.

•	Returns the S_OK value if successful. Otherwise, the member function returns one of the following error values:

OLE_E_NOTRUNNING	The object is an OLE embedded document that must be run before this operation can be carried out. The object state is unchanged as a result of the call.
E_UNEXPECTED	Unspecified error.
pulProgressMax

Address of the variable that receives the work estimate value.

The work estimate value, if available, is only approximate.


IReconcilableObject::Reconcile [New - Windows 95]
IReconcilableObject::Reconcile

[New - Windows 95]

HRESULT IReconcilableObject::Reconcile(
    IReconcileInitiator * pInitiator,
    DWORD dwFlags,
    HWND hwndOwner,

    HWND hwndProgressFeedback,
    ULONG ulcInput,
    IMoniker ** rgpmkOtherInput,
    LONG * plOutIndex,
    IStorage * pstgNewResidues,
    void * pvReserved);

Reconciles the state of an object with one or more other objects. The reconciliation updates the internal state of the object by merging the states of all objects to form a combined state.

•	Returns one of the following success values if successful:

S_OK
	Reconciliation was completed successfully, and the changes must be propagated to the other objects.
S_FALSE
	No reconciliation actions were performed. The briefcase reconciler wishes to fall back to the initiator's bit copy implementation. This value may only be returned if RECONCILEF_ONLYYOUWERECHANGED is set in dwFlags.
REC_S_IDIDTHEUPDATES
	Reconciliation was completed successfully, and all the objects involved (the object implementing the Reconcile member function and all the other objects described by the passed-in monikers) have been updated appropriately. The initiator does not need, therefore, to do anything further to propagate the changes. The variable pointed to by plOutIndex should be set to  − 1L if Reconcile returns this value. The initiator will not save the source object's storage if Reconcile returns this value. This value may only be returned if RECONCILEF_YOUMAYDOTHEUPDATES was set in dwFlags.
REC_S_NOTCOMPLETE
	The briefcase reconciler completed some, but not all, of the reconciliation. It may need user interaction. The changes will not be propagated to other objects.
REC_S_NOTCOMPLETEBUTPROPAGATE
	The briefcase reconciler completed some, but not all, of the reconciliation. It may need user interaction. The changes will be propagated to the other objects.
Otherwise, the member function returns one of the following error values:

REC_E_NORESIDUES
	The briefcase reconciler does not support the generation of residues, so the request for residues is denied. The state of the object is unchanged.
REC_E_ABORTED
	The briefcase reconciler terminated reconciliation in response to a termination request from the initiator (for more information, see IReconcileInitiator::SetAbortCallback). The state of the object is unspecified.
REC_E_TOODIFFERENT
	Reconciliation cannot be carried out because the provided document versions are too dissimilar.
REC_E_INEEDTODOTHEUPDATES
	The object's Reconcile implementation was called with RECONCILEF_YOUMAYDOTHEUPDATES clear in dwFlags; the object's Reconcile implementation requires that value to be set in dwFlags.
OLE_E_NOTRUNNING
	The object is an OLE embedded object that must be run before this operation can be carried out. The state of the object is unchanged.
E_UNEXPECTED
	Unspecified error.
pInitiator

Address of the IReconcileInitiator interface for the initiator of the reconciliation process. This parameter must not be NULL.

dwFlags

Control flags for the reconciliation. This parameter may be zero or a combination of these values:

RECONCILEF_FEEDBACKWINDOWVALID
	hwndProgressFeedback is valid.
RECONCILEF_MAYBOTHERUSER
	The briefcase reconciler can prompt for user interaction if it is needed. Without this value, user interaction is not permitted. hwndOwner is valid.
RECONCILEF_NORESIDUESOK
	The briefcase reconciler can ignore requests for residues and carry out reconciliation. Reconcilers that do not support residues should check for this value whenever an initiator requests residues. Without this value, a reconciler that does not support residues must immediately return REC_E_NORESIDUES.
RECONCILEF_OMITSELFRESIDUE
	The briefcase reconciler can discard any residue associated with this object. Initiators typically use this value for reconciliations that loop from generation to generation.
RECONCILEF_ONLYYOUWERECHANGED
	The Reconcile member function is being called to propagate changes in the changed object to other unchanged objects. This value will only be set if the HKEY_CLASSES_ROOT\CLSID\clsid_of_reconciler\SingleChangeHook key exists in the registry. If that key is not present in the registry, the initiator carries out reconciliation by making the other unchanged objects binary identical copies of the changed object. The rgpmkOtherInput monikers identify the other objects. This value will only be set in dwFlags if RECONCILEF_YOUMAYDOTHEUPDATES is also set. If the briefcase reconciler completes the updates itself successfully, REC_S_IDIDTHEUPDATES should be returned and the variable pointed to by plOutIndex should be set to  − 1L. Note that S_OK should not be returned on success if this value is set in dwFlags. The initiator will not save the source object's storage if Reconcile returns REC_S_IDIDTHEUPDATES. If the reconciler wishes to fall back to the initiator's bit copy implementation, it may return S_FALSE.
RECONCILEF_RESUMEDRECONCILIATION
	The briefcase reconciler should resume reconciliation, using the partial residues provided. Without this value, the reconciler should ignore any "considered but rejected" information in any of the input versions.
RECONCILEF_YOUMAYDOTHEUPDATES
	The briefcase reconciler may do the updates itself. Without this value, the reconciler may not do the updates itself. If reconciliation is completed successfully, the reconciler should return REC_S_IDIDTHEUPDATES if it did the updates itself or S_OK if it did not do the updates itself.
hwndOwner

Handle of the parent window to use for child windows that the briefcase reconciler creates. This parameter is valid only if RECONCILEF_MAYBOTHERUSER is specified in dwFlags.

hwndProgressFeedback

Handle of the progress feedback window displayed by the initiator. This parameter is valid only if RECONCILEF_FEEDBACKWINDOWVALID is specified in dwFlags. The briefcase reconciler may call the SetWindowText function using this window handle to display additional reconciliation status information to the user.

ulcInput

Number of versions or partial residues specified in dwFlags. This parameter must not be zero.

rgpmkOtherInput

Address of an array that contains the addresses of the monikers to use to access the versions or partial residues to be reconciled.

plOutIndex

Address of the variable that receives an index value indicating whether the result of the reconciliation is identical to one of the initial versions. The variable is set to  − 1L if the reconciliation result is a combination of two or more versions. Otherwise, it is a zero-based index, with 0 indicating this object, 1 indicating the first version, 2 indicating the second version, and so on.

pstgNewResidues

Address of the IStorage interface used to store newly created residues. This parameter may be NULL to indicate that residues should not be saved.

pvReserved

Reserved; must be NULL.


IReconcileInitiator [New - Windows 95]
IReconcileInitiator

[New - Windows 95]

The IReconcileInitiator interface provides the briefcase reconciler with the means to notify the initiator of its progress, to set a termination object, and to request a given version of a document. This interface has the SetArbortCallback and SetProgressFeedback member functions. The initiator is responsible for implementing this interface.


IReconcileInitiator::SetAbortCallback [New - Windows 95]
IReconcileInitiator::SetAbortCallback

[New - Windows 95]

HRESULT IReconcileInitiator::SetAbortCallback(
    IUnknown * pUnkForAbort);

Sets the object through which the initiator can asynchronously terminate a reconciliation. A briefcase reconciler typically sets this object for reconciliations that are lengthy or involve user interaction.

•	Returns the S_OK value if successful. Otherwise, the member function returns one of the following error values:

REC_E_NOCALLBACK	The initiator does not support termination of reconciliation operations and does not hold the specified object.
E_UNEXPECTED	Unspecified error.
pUnkForAbort

Address of the IUnknown interface for the object. The initiator signals a request to terminate the reconciliation by using the IUnknown::Release member function to release the object. This parameter may be NULL to direct the initiator to remove the previously specified object.

The initiator can accept or reject the object. If the initiator accepts the object, the briefcase reconciler must later remove the object by subsequently calling this function with a NULL parameter when the reconciliation is complete. Because the reconciler removes the object after completing reconciliation, there may be times when the initiator releases the object after reconciliation is complete. In such cases, the reconciler ignores the request to terminate.

If the reconciliation is terminated, the IReconcilableObject::Reconcile member function must return either the REC_E_ABORTED or REC_E_NOTCOMPLETE value.


IReconcileInitiator::SetProgressFeedback [New - Windows 95]
IReconcileInitiator::SetProgressFeedback

[New - Windows 95]

HRESULT IReconcileInitiator::SetProgressFeedback(
    ULONG ulProgress,
    ULONG ulProgressMax);

Indicates the amount of progress the briefcase reconciler has made toward completing the reconciliation. The amount is a fraction of 1 and is computed as the quotient of the ulProgress and ulProgressMax. Reconcilers should call this member function periodically during their reconciliation process.

•	Returns the S_OK value if successful or the E_UNEXPECTED value if some unspecified error occurred.

ulProgress

Numerator of the progress fraction.

ulProgressMax

Denominator of the progress fraction.

The initiator typically uses this measure of progress to update a thermometer gauge or some other form of visual feedback for the user. The briefcase reconciler can change the value of ulProgressMax from call to call. This means successive calls to this member function do not necessarily indicate steady forward progress. Backward progress is legal, although not desirable. It is the responsibility of the initiator to determine whether backward progress should be revealed to the user.


INotifyReplica [New - Windows 95]
INotifyReplica

[New - Windows 95]

The INotifyReplica interface provides the initiator with the means to notify an object that it may be subject to subsequent reconciliation. This interface has the YouAreAReplica member function. The briefcase reconciler is responsible for implementing this interface.


INotifyReplica::YouAreAReplica [New - Windows 95]
INotifyReplica::YouAreAReplica

[New - Windows 95]

HRESULT INotifyReplica::YouAreAReplica(
    ULONG ulcOtherReplicas,
    IMoniker ** rgpmkOtherReplicas);

Notifies on object that it may be subject to subsequent reconciliation through the IReconilableObject::Reconcile member function.

Briefcase calls INotifyReplica when objects are added to it.

•	Returns the S_OK value if successful. Otherwise, the member function returns one of the following error values:

E_UNEXPECTED	Unspecified error.
ulcOtherReplicas

Number of other replicas of the object. This parameter must not be zero.

rgpmkOtherReplicas

Address of an array that contains the addresses of the monikers to use to access the other replicas.

An object may be notified that it is a replica more than once. Briefcase reconcilers are not required to implement this interface. Initiators are not required to call this interface if it is implemented. However, an object's implementation of IReconcilableObject::Reconcile may reasonably fail if that object has not previously been notified through INotifyReplica::YouAreAReplica that it may be subject to reconciliation.


Passwords Control Panel

The Passwords Control Panel is a system-defined property sheet that allows the user to set security options and manage passwords for all password-protected services (also called password providers) in the system, including screen savers, electronic mail (email), and network logon. In addition, the Passwords Control Panel allows the user to set the Windows logon password and to keep passwords for other password-protected services identical to the Windows logon password. This means that the Windows logon password can work as a universal password for all password-protected services in the system.


About the Passwords Control Panel

The Passwords Control Panel includes a programming interface that allows an application to add property sheet pages. You should add a property sheet page to the Passwords Control Panel if your application provides security-related services that have properties the user can set.

If your application provides a password-protected service, the programming interface of the Passwords Control Panel allows you to add the name of your service to the control panel's list of password-protected services. If you add your service to the list, the user can change the password by using the Passwords Control Panel and keep the password identical to the Windows logon password.

This article describes the Passwords Control Panel and explains how to use its programming interface. The following illustration shows the Passwords Control Panel.


Adding a Property Sheet Page

You should add a property sheet page to the Passwords Control Panel if your application provides security-related functionality that goes beyond simply activating and changing passwords.

To add a property sheet page to the Passwords Control Panel, write a property sheet extension and register the extension with the Microsoft® Windows® 95 shell. A property sheet extension is a 32-bit dynamic-link library (DLL) that implements the IShellPropSheetExt interface. The Windows 95 shell calls a property sheet extension when the shell is about to display a property sheet. The extension provides code that creates a page, which the shell adds to the property sheet.

You register a property sheet extension by placing information into the system registry. The Windows 95 shell enumerates the property sheet extension DLLs first under the \shellex\PropertySheetHandlers registry key of the default class for system-wide property sheet pages and then under the \shellex\PropertySheetHandlers registry key of the object's class for class-specific property sheet pages.

For more information about creating and registering property sheet extensions, see "Shell Extensions."


Managing Passwords

If your application provides a password-protected service, you should add your service to the Passwords Control Panel. When you add your service, the name of the service appears in the Select Password dialog box that appears when the user clicks the Change Other Passwords button. The user can change the password for the service by selecting the name and clicking the Change button and then filling in the resulting Change Password dialog box.

The name of your service also appears in the Change Windows Password dialog box with a check box next to it. By checking the check box, the user can choose to keep the password for the service identical to the Windows logon password. Likewise, the user can disassociate the service from the Windows logon password by unchecking the check box.


Including a Password User Interface

Any application that provides a password-protected service should make the password for the service accessible through the Passwords Control Panel. However, if the previous version of your application includes a user interface for setting a password, you may choose to retain that interface as well as making the password accessible through the Passwords Control Panel. If your application includes user interface elements for accomplishing tasks besides setting a password, you should make the change password functionality available both within the application's user interface and within the Passwords Control Panel. If you do not include the change password functionality in the user interface, you should make it available only through the Passwords Control Panel.

Your application should take into account that the user may have multiple keyboard languages installed. Such a user may inadvertently type a password in the wrong language and become confused when the password is rejected. Your application should check for multiple keyboard languages and alert the user when multiple languages are installed.

If your application includes a user interface for setting a password, you should use the Windows built-in change password dialog boxes to get password information from the user. For more information about the Windows change password dialog boxes, see "Change Password Dialog Boxes" later in this topic.


Adding a Service to the Passwords Control Panel

If you add a service to the Passwords Control Panel, your installation program should add information about your service to the following location in the registry.

HKEY_LOCAL_MACHINE

    System

        CurrentControlSet

            Control

                PwdProvider

                    <Provider Name>

Provider Name is the name of your password-protected service. The name should be similar to the name of your executable file. The provider name is used when calling all password functions.

You must specify the following values for Provider Name.

Value name	Description
ChangePassword	Exported name of the PPChangePassword function.
Description	String that appears in the Select Password dialog box.
ProviderPath	Name of the executable module that provides the password-protected service.
GetPasswordStatus	Exported name of the PPGetPasswordStatus function.
Network Provider	Doubleword value that indicates whether the password-protected service provides network services. A network provider should set this value to 1. This value is optional.
In addition to adding information to the registry, you must provide a 32-bit DLL that exports the PPChangePassword function. Windows calls the function when the user wants to change the password associated with your password-protected service.

PPChangePassword is a Windows network function that uses a two-stage process to change a password. The function first determines whether it can change the password, and then it actually changes it. This two stage process is particularly important when the user is changing the Windows logon password because the logon password can have many other services associated with it, including network providers. For example, if a service that uses the Windows logon password is not running when the user changes the logon password, Windows shows a dialog box that explains the implications of changing the logon password. If the user goes ahead and changes the Windows logon password, the services with passwords that were not changed are displayed differently in the Change Windows Password and Select Password dialog boxes.

An application that is not a network provider can identify itself as load on demand. In this case, the application is loaded only when the user wants to change a password and is unloaded after the process is complete.


Adding a Service to the Windows Password

When the user checks the check box associated with a password-protected service listed in the Change Windows Password dialog box, Windows calls the PPChangePassword function of the application that provides the service. The function attempts to change the password to the current Windows logon password, prompting the user for the old password first, if necessary. If the function fails, it should return an error value so that Windows can display the appropriate error message.


Removing a Service from the Windows Logon Password

When the user unchecks the check box associated with a password-protected service, Windows removes the service from the list of services associated with the Windows logon password. When the user clicks the Change Other Passwords button, Windows calls the application's PPChangePassword function. If the user does not change the password, Windows displays a dialog box asking the user whether to change the password for the service that was removed from the Windows logon password.


Changing the Windows Logon Password

The user changes the Windows logon password by clicking the Change Windows Password button, which causes Windows to display the Change Windows Password dialog box. In the dialog box, the user must enter the old and new Windows logon passwords, confirm the new logon password, and then click the OK button. Windows responds by calling the PPChangePassword function associated with each password-protected service that the user has added to the Windows logon password. Windows calls the function with the dwAction parameter set to the Passwd_Change_Pending value. If any PPChangePassword function returns an error value, Windows displays a dialog box that lists the services that cannot use the new Windows logon password. If the user continues to change the Windows logon password, Windows again calls the PPChangePassword function of each application that can change the password for its service. Windows sets the dwAction parameter to the Passwd_Change_Commit value this time.

Windows appends text to the name of each service whose password could not be changed, explaining that the service is no longer associated with the Windows logon password, even though it is checked. The user can then change the password.


Handling Error Conditions

If an application-defined error occurs while a password is being changed, the application should use the MPRSetError function to return an application-defined error value. If a standard error occurs, the application should return one of the following standard error values.

Error value	Meaning
ERROR_EXTENDED_ERROR	The application has a text error message to report.
WN_ACCESS_DENIED	There was a security violation.
WN_BAD_PASSWORD	An incorrect password was specified.
WN_BAD_POINTER	An invalid pointer was specified.
WN_BAD_VALUE	An invalid numeric value was specified.
WN_MORE_DATA	There is a warning that  the buffer is too small.
WN_NOT_SUPPORTED	The function is not supported.
WN_SUCCESS	No error occurred; the function succeeded.
WN_WINDOWS_ERROR	A required Windows function failed.


Change Password Dialog Boxes

Windows includes built-in dialog boxes that you can use to get password information from the user. To display a built-in dialog box from within your application, implement the password functionality described previously, and then call the PwdChangePassword function. For example, when the user of an email application chooses the command to change the email password, the application can direct Windows to display a built-in change passwords dialog box.

Because Windows keeps track of which password-protected services are associated with the Windows logon password and which are not, Windows presents either the Change Other Passwords or Change Windows Password dialog box, whichever is appropriate.

For example, when the user of an email application chooses the command to change the email password, the application can direct Windows to display one of its built-in change passwords dialog boxes. Windows displays the appropriate dialog box, which depends on whether the user has associated the email password with the Windows logon password.


Using the Passwords Control Panel

The following example shows how to implement the PPChangePassword function.

#include <windows.h>

#include "mpr.h"

HANDLE hInstance;

#define USE_CRT_INIT 1

BOOL _stdcall _CRT_INIT(HINSTANCE hInstDLL, DWORD fdwReason,

    LPVOID lpReserved);

int FAR PASCAL LibMain(HINSTANCE hInst, WORD wDataSeg,

    WORD wcbHeapSize, LPSTR lpstrCmdLine);

SPIENTRY PPChangePassword(LPLOGONINFO lpAuthentInfo,

    LPLOGONINFO lpPreviousAuthentInfo, DWORD dwAction)

{

    switch (dwAction) {

        case PWDCHANGE_MASTERPWD_NOTIFY:

            // The Windows password has changed. A network provider can
            // add a new password to its store at this point.

            return WN_SUCCESS;

        case PWDCHANGE_PROVIDERPWD_PENDING:

            MessageBox((HWND) NULL,"Got PWDCHANGE_PROVIDERPWD_PENDING",

                "GenProv",MB_OK);

            // Do first-phase password change actions: query the server

            // to see if it is running, verify the old password, and so

            // on. Do not change the password in response to this

            // message. If there are no first-phase actions to do,

            // return WN_SUCCESS. Report errors (and error text, if

            // appropriate) by using NPSSetExtendedError

            // if there is a provider-specific extended error or

            // MPRSetError if the error can be expressed with a

            // WN_ error code. Return either ERROR_EXTENDED_ERROR or

            // the WN_ error code.

            return WN_SUCCESS;

        case PWDCHANGE_PROVIDERPWD_COMMIT:

            MessageBox(NULL,"Got PWDCHANGE_PROVIDERPWD_COMMIT",

                "GenProv",MB_OK);

            // Change the password. Report errors and display error

            // text, if appropriate, through NPSSetExtendedError

            // if there is a provider-specific extended error

            // or MPRSetError if the error can be expressed with a

            // WN_ error code. Return ERROR_EXTENDED_ERROR or the WN_

            // error code.

            return WN_SUCCESS;

    }

return WN_SUCCESS;

}

BOOL _stdcall DllEntryPoint(HINSTANCE hInstDll, DWORD fdwReason,

    LPVOID lpReserved)

{

    static BOOL fInit = FALSE;

#if USE_CRT_INIT

    // Initialize the C run-time library before calling any of our code.

    if(fdwReason == DLL_PROCESS_ATTACH ||

            fdwReason == DLL_THREAD_ATTACH)

        if(!_CRT_INIT(hInstDll, fdwReason, lpReserved))

            return(FALSE);

#endif

    if(fdwReason == DLL_PROCESS_ATTACH) {

        hInstance = hInstDll;

    }

#if USE_CRT_INIT

    // Terminate the C run-time library after all of your code.

    if(fdwReason == DLL_PROCESS_DETACH ||

            fdwReason == DLL_THREAD_DETACH)

        if(!_CRT_INIT(hInstDll, fdwReason, lpReserved))

            return(FALSE);

#endif

    return TRUE;

}


Reference

The following functions are used with the Passwords Control Panel.


PPChangePassword [New - Windows 95]
PPChangePassword

[New - Windows 95]

DWORD PPChangePassword(LPLOGONINFO lpAuthentInfo,
    LPLOGONINFO lpPreviousAuthentInfo, DWORD dwAction);

Informs a password provider that the user has successfully changed the password using the standard PPChangePassword dialog box. This notification message is useful if the password provider uses the Window logon password as the default password for network connections. Some password providers are not concerned with any feature of system logon except the password cache; these providers do not need to support this function.

•	Returns the WN_SUCCESS value if successful or a WN_ error value otherwise.

lpAuthentInfo

Address of a LOGONINFO structure that contains the name of the user who is currently logged on and the new password.

lpPreviousAuthentInfo

Address of a LOGONINFO structure that contains the name of the user who is currently logged on and the old password.

dwAction

Action flag. This parameter can be one of these values:

PWDCHANGE_MASTERPWD_NOTIFY
	The logon password has changed. The password provider may need to perform an action, such as giving the new password to its redirector.
PWDCHANGE_PROVIDERPWD_CANCEL
	A password provider will receive this message if it has already received a first-phase notification (PWDCHANGE_PROVIDERPWD_ PENDING) and the password change action has been canceled (for example, in response to another password provider being unable to change its password).
PWDCHANGE_PROVIDERPWD_COMMIT
	This message is a commit-phase notification. The password provider should change the password in response to this message.
PWDCHANGE_PROVIDERPWD_PENDING
	The user wants to change a password maintained by the password provider.  This message is a first-phase notification; the password provider should not change the password at this time. The password provider should do any precommit verification that is appropriate, such as checking that the old password is valid, if possible.


PPGetPasswordStatus [New - Windows 95]
PPGetPasswordStatus

[New - Windows 95]

DWORD PPGetPasswordStatus(DWORD nIndex);

Queries a password provider about the status of its password. A password provider can report whether it is on or off (enabled or disabled) and whether it requires the user to type in the old password to change it. If a password provider does not support this function but does support PPChangePassword, it is assumed that the password is always enabled and that typing the old password is required.

•	The return value depends on the nIndex parameter.

nIndex

Type of information to retrieve. This parameter can be one of these values:

PS_HASOLDPWD	Requests the "old password" status of the password. The return value is one of these values: PS_HASOLDPWD_ON PS_HASOLDPWD_OFF
PS_ONOFF	Requests the on or off status of the password. The return value is one of these values: PS_ONOFF_ON PS_ONOFF_OFF
PS_STORAGETYPE	Requests the storage type of the password. The return value is one of these values: PS_STORAGETYPE_LOCAL PS_STORAGETYPE_NETWORK


PwdChangePassword [New - Windows 95]
PwdChangePassword

[New - Windows 95]

DWORD PwdChangePassword(LPCTSTR lpProvider, HWND hwndOwner,
    DWORD dwFlags);

Changes the user's system logon password or a password provider's password. Master provider router (MPR) displays a dialog box for changing the password. If the user changes the logon password, MPR reencrypts the user's password cache with the new password. Password providers are notified through the PPChangePassword function.

•	Returns the WN_SUCCESS value if successful or the WN_CANCEL value if the user cancels the operation.

lpProvider

Address of the name of the provider whose password is to be changed. If this parameter is NULL, the logon password is to be changed. Changing the logon password can also result in other password providers being notified to change their passwords, if the user has selected to synchronize a password provider's password with the Windows logon password.

hwndOwner

Handle of the owner window for the dialog box displayed by MPR.

dwFlags

Flag that causes MPR to display a dialog box that prompts only for the previous password. This parameter can be either zero or the CHANGEPWD_OLDPWDONLY value. The current logon password is given to the password provider as the new password. This flag is ignored if PPChangePassword is called to change the logon password — that is, if lpProvider is NULL. CHANGEPWD_OLDPWDONLY is intended for use by the system; an application should not use it.


PwdGetPasswordStatus [New - Windows 95]
PwdGetPasswordStatus

[New - Windows 95]

DWORD PwdGetPasswordStatus(LPCTSTR lpProvider, DWORD dwIndex,
    LPDWORD lpStatus);

Retrieves information about a password provider's password. The request is passed to the password provider through the PPGetPasswordStatus function.

•	Returns the WN_SUCCESS value if successful or a WN_ error value otherwise.

lpProvider

Address of the name of the network provider that owns the password.

dwIndex

Type of information to retrieve. This parameter can be one of these values:

PS_HASOLDPWD	Indicates whether it is necessary to supply the previous password to change the current password. When the function returns, lpStatus includes one of these values:  PS_HASOLDPWD_ON PS_HASOLDPWD_OFF
PS_ONOFF	Indicates whether the password is active. When the function returns, lpStatus includes one of these values:  PS_ONOFF_ON PS_ONOFF_OFF
PS_SYNCMASTERPWD	Indicates whether the password should be kept the same as the Windows logon password. When the function returns, lpStatus includes one of these values:   PS_SYNCMASTERPWD_ON PS_SYNCMASTERPWD_OFF
PS_STORAGETYPE	Indicates whether the password is stored locally or in a network location. When the function returns, lpStatus includes one of these values:  PS_STORAGETYPE_LOCAL PS_STORAGETYPE_NETWORK
lpStatus

Address of a doubleword value that receives bit flag values. The meaning of the values depends on the dwIndex parameter.


PwdSetPasswordStatus [New - Windows 95]
PwdSetPasswordStatus

[New - Windows 95]

DWORD PwdSetPasswordStatus(LPCTSTR lpProvider, DWORD dwIndex,
    DWORD dwStatus);

Sets information about a password provider's password. Currently, this function can only determine whether the password is kept the same as the Windows logon password.

•	Returns the WN_SUCCESS value if successful or a WN_ error value otherwise.

lpProvider

Address of the name of the network provider that owns the password.

dwIndex

Type of information to retrieve. Currently, only the PS_SYNCMASTERPWD value is supported.

dwStatus

Status flag. This parameter can be either the PS_SYNCMASTERPWD_ON or PS_SYNCMASTERPWD_OFF value.


Device I/O Control

Microsoft® Windows® 95 includes a device input and output control (IOCTL) interface that allows applications developed for the Microsoft® Win32® application programming interface (API) to communicate directly with virtual device drivers.


About Device I/O Control

Applications typically use the IOCTL interface to carry out selected Microsoft® MS-DOS® system functions, to obtain information about a device, or to carry out input and output (I/O) operations that are not available through standard Win32 functions.

This article describes the device IOCTL interface, explains how to use the interface in applications, and describes how to implement the interface in virtual devices (VxDs). For information about the device IOCTL interface for other operating systems that support the Win32 API, see the documentation included in the Microsoft Win32 Software Development Kit (SDK).


Input and Output Control in Applications

You use the device IOCTL interface in an application to carry out "low-level" operations that are not supported by the Win32 API and that require direct communication with a VxD. Windows 95 implements the interface through the DeviceIoControl function, which sends commands and accompanying data directly to the given VxD. To use the interface, you open the VxD by using the CreateFile function, send commands to the VxD by using DeviceIoControl, and finally close the VxD by using the CloseHandle function.


Opening the VxD

You can open a static or dynamically loadable VxD by specifying the module name, filename, or registry entry identifying the VxD in a call to the CreateFile function. If the VxD exists and it supports the device IOCTL interface, the function returns a device handle that you can use in subsequent calls to the DeviceIoControl function. Otherwise, the function fails and sets the last error value to ERROR_NOT_SUPPORTED or ERROR_FILE_NOT_FOUND. You can use the GetLastError function to retrieve the error value.

When you open a VxD, you must specify a name having the following form.

\\.\VxdName

VxDName can be the module name of the VxD, the name of the VxD file, or the name of a registry entry that specifies the filename.

CreateFile checks for a filename extension to determine whether VxDName specifies a file. If a filename extension (such as .VXD) is present, the function looks for the file in the standard search path. In the following example, CreateFile looks for the SAMPLE.VXD file in the standard search path.

HANDLE hDevice;

hDevice = CreateFile("\\\\.\\SAMPLE.VXD", 0, 0, NULL, 0,
    FILE_FLAG_DELETE_ON_CLOSE, NULL);

If VxDName has no filename extension, CreateFile checks the registry to see if the name is also a value name under the KnownVxDs key in HKLM\System\CurrentControlSet\Control\SessionManager. If it is a value name, CreateFile uses the current value associated with the name as the full path of the VxD file. This method is useful for specifying VxDs that are not in the standard search path. In the following example, CreateFile searches the registry for the MYVXDPATH value.

hDevice = CreateFile("\\\\.\\MYVXDPATH", 0, 0, NULL, 0,
    FILE_FLAG_DELETE_ON_CLOSE, NULL);

If VxDName has no filename extension and is not in the registry, CreateFile assumes that the name is a VxD module name and searches the internally maintained device descriptor blocks for an already loaded VxD having the given name. In the following example, CreateFile opens the standard VxD named VWIN32.VXD.

hDevice = CreateFile("\\\\.\\VWIN32", 0, 0, NULL, 0,
    0, NULL);

In all cases, if CreateFile cannot find or load the VxD, it sets the last error value to ERROR_FILE_NOT_FOUND. If the function loads the VxD but the VxD does not support the device IOCTL interface, CreateFile sets the last error value to ERROR_NOT_SUPPORTED.

You can open the same VxD any number of times. CreateFile provides a unique handle each time you open a VxD, but it makes sure that no more than one copy of the VxD is loaded into memory. To ensure that the system removes the VxD from memory when you close the last instance of the VxD, use the FILE_FLAG_DELETE_ON_CLOSE value when opening dynamically loadable VxDs. Static VxDs cannot be removed from memory.

Although CreateFile has several parameters, only the lpName and fdwAttrsAndFlags parameters are useful when opening an VxD. fdwAttrsAndFlags can be zero, the FILE_FLAG_DELETE_ON_CLOSE value, or the FILE_FLAG_OVERLAPPED value. FILE_FLAG_OVERLAPPED is used for asynchronous operation and is described later in this article.


Sending Commands

You use DeviceIoControl to send commands to a VxD. You must specify the previously opened device handle, control code, and input and output parameters for the call. The device handle identifies the VxD, and the control code specifies an action for the VxD to perform. In the following example, the DIOC_GETVERSION control code directs the given VxD to return version information.

HANDLE hDevice
BYTE bOutput[4];
DWORD cb;

fResult = DeviceIoControl(
    hDevice,          // device handle
    DIOC_GETVERSION,  // control code
    NULL, 0,          // input parameters
    bOutput, 4, &cb,  // output parameters
    0);

The input and output parameters of DeviceIoControl include the addresses and sizes of any buffers needed to pass data into or out of the VxD. Whether you use these parameters depends on how the VxD processes the control code. You supply an input buffer if the VxD requires that you pass it data for processing, and you supply an output buffer if the VxD returns the results of processing. In the previous example, only the output parameters are supplied. These include the address of the output buffer; the size, in bytes, of the buffer; and the address of the variable to receive the count of bytes actually copied to the buffer by the VxD.

Although the Win32 header files define a set of standard control codes, Windows 95 does not support these standard codes. Instead, the meaning and value of control codes in Windows 95 are specific to each VxD. Different VxDs may support different control codes.

Some VxDs support the DIOC_GETVERSION control code, which directs the VxD to return version information in the output buffer. Although the version information can have any format that helps the application determine the version of the VxD, keeping the information to 4 bytes or less is recommended. The VxD returns the version information only if you supply a buffer and specify a nonzero size for the buffer.

If you opened the VxD using the FILE_FLAG_OVERLAPPED value, you must also provide an OVERLAPPED structure when calling DeviceIoControl. This structure contains information that the VxD uses to process the control code asynchronously.


Closing a VxD

When you have finished using a VxD, you can close the associated device handle by using the CloseHandle function, or you can let the operating system close the handle when the application terminates. The following example closes a VxD.

CloseHandle(hDevice);

Closing a VxD does not necessarily remove the VxD from memory. If you open a dynamically loadable VxD using the FILE_FLAG_DELETE_ON_CLOSE value, CloseHandle also removes the VxD if no other valid handles are present in the system. The system maintains a reference count for dynamically loadable VxDs, incrementing the count each time the VxD is opened and decrementing when the VxD is closed. CloseHandle checks this count and removes the VxD from memory when the count reaches zero. The system does not keep a reference count for static VxDs; it does not remove these VxDs when their corresponding handles are closed.

In rare cases, you may need to use the DeleteFile function to remove a dynamically loadable VxD from memory. For example, you use DeleteFile if another application has loaded the VxD and you just want to unload it. You also use DeleteFile if you have successfully loaded a VxD by using CreateFile, but the VxD does not support the device IOCTL interface. In such cases, CreateFile loads the VxD but provides no handle to close and remove the VxD. The following example removes the VxD named SAMPLE from memory.

DeleteFile("\\\\.\\SAMPLE");

In this example, SAMPLE is the module name of the VxD. (Do not specify the filename.) Be aware that the module name of a VxD is not necessarily the same as the VxD's filename without a filename extension. In general, avoid using DeleteFile to remove a VxD from memory.


Asynchronous Operations

You can direct a VxD to process a control code asynchronously. In an asynchronous operation, the DeviceIoControl function returns immediately, regardless of whether the VxD has finished processing the control code. Asynchronous operation allows an application to continue while the VxD processes the control code in the background. You request an asynchronous operation by specifying the address of an OVERLAPPED structure in the DeviceIoControl function. The hDevice member of OVERLAPPED specifies the handle of an event that the system sets to the signaled state when the VxD has completed the operation.

Asynchronous (overlapped) operations are useful for lengthy operations, such as formatting a disk. To perform an asynchronous operation, you must specify the FILE_FLAG_OVERLAPPED value when calling CreateFile to obtain a device handle. When calling DeviceIoControl, you must specify the address of an OVERLAPPED structure in the lpOverlapped parameter and the handle of a manual reset event in the hEvent member of the structure. The system ignores all other members.

If DeviceIoControl completes the operation before returning, it returns TRUE; otherwise, it returns FALSE. When the operation is finished, the system signals the manual reset event. You should call GetOverlappedResult when the thread that called DeviceIoControl needs to wait (that is, stop executing) until the operation has finished.


Using VWIN32 to Carry Out MS-DOS Functions

Windows 95 provides a VxD called VWIN32.VXD that supports a set of control codes that Win32 applications can use to carry out selected MS-DOS system functions. These system-defined control codes consist of the following values.

Control code (value)	Meaning
VWIN32_DIOC_DOS_INT13 (4)	Performs Interrupt 13h commands.
VWIN32_DIOC_DOS_INT25 (2)	Performs the Absolute Disk Read command (Interrupt 25h).
VWIN32_DIOC_DOS_INT26 (3)	Performs the Absolute Disk Write command (Interrupt 25h).
VWIN32_DIOC_DOS_IOCTL (1)	Performs the specified MS-DOS device I/O control function (Interrupt 21h Function 4400h through 4411h).
When a Windows 95 − based application calls DeviceIoControl with the dwIoControlCode parameter set to one of the predefined control codes, the lpvInBuffer and lpvOutBuffer parameters must specify the addresses of DIOC_REGISTERS structures. The DIOC_REGISTERS structure specified by lpvInBuffer contains a set of register values that specify a command for the VxD to execute and any data that the VxD needs to execute the command. After completing the command, the VxD fills the DIOC_REGISTERS structure specified by lpvOutBuffer with the register values that resulted from executing the command. The meaning of the register values depends on the specified command.

Some interrupt functions require far pointers passed in segment:offset pairs where the segment is placed in a segment register. Because the 32-bit code does not have segments, the DIOC_REGISTERS structure contains no segment registers. To specify segment:offset pairs, place the full pointer into the structure member that corresponds to the register used to hold the offset portion of the real-mode pointer. For example, use reg_EDX for pointers that go into the DS:DX registers.

Many of the MS-DOS and BIOS functions require segment registers, but segment registers are not part of the DIOC_REGISTERS structure. To specify an address that includes a segment selector, use the structure member that corresponds to the offset of the real-mode segment:offset register pair to hold the entire address. For example, a pointer in the ES:DI registers would be put into the reg_EDI member.

When a Windows 95 − based application uses the DeviceIoControl function to send commands to a VxD other than VWIN32.VXD, the meaning of the function's parameters are defined by the VxD. The system does not validate any parameter.

The system VxD, VWIN32.VXD, supports the IOCTL functions originally provided by MS-DOS Interrupt 21h. The following example shows how to call Get Media ID (Interrupt 21h Function 440Dh Minor Code 66h) from a Win32-based application.

#define VWIN32_DIOC_DOS_IOCTL 1

typedef struct _DIOC_REGISTERS {
    DWORD reg_EBX;
    DWORD reg_EDX;
    DWORD reg_ECX;
    DWORD reg_EAX;
    DWORD reg_EDI;
    DWORD reg_ESI;
    DWORD reg_Flags;
} DIOC_REGISTERS, *PDIOC_REGISTERS;

// Important: All MS_DOS data structures must be packed on a
// one-byte boundary.

#pragma pack(1)
typedef struct _MID {
    WORD  midInfoLevel;
    DWORD midSerialNum;
    BYTE  midVolLabel[11];
    BYTE  midFileSysType[8];
} MID, *PMID;
#pragma pack()

HANDLE hDevice;
DIOC_REGISTERS reg;
MID mid;
BOOL fResult;
DWORD cb;
int nDrive = 3;  // Drive C:

hDevice = CreateFile("\\\\.\\vwin32",
    0, 0, NULL, 0, FILE_FLAG_DELETE_ON_CLOSE, NULL);

reg.reg_EAX = 0x440D;       /* IOCTL for block devices           */
reg.reg_EBX = nDrive;       /* zero-based drive identifier       */
reg.reg_ECX = 0x0866;       /* Get Media ID command              */
reg.reg_EDX = (DWORD) &mid; /* receives media identifier info.   */
reg.reg_Flags = 0x0001;     /* assume error (carry flag is set)  */

fResult = DeviceIoControl(hDevice,
    VWIN32_DIOC_DOS_IOCTL,
    &reg, sizeof(reg),
    &reg, sizeof(reg),
    &cb, 0);

if (!fResult || (reg.reg_Flags & 0x0001))
    ; // error if carry flag is set

CloseHandle(hDevice);


Supporting Input-Output Control in VxDs

A VxD can support the device IOCTL interface by processing the W32_DEVICEIOCONTROL message in the VxD's control procedure. You can take advantage of the device IOCTL interface by providing a VxD that performs privileged (ring 0) operations for your application.


Loading and Opening the VxD

When your application calls CreateFile, the system sends the W32_DEVICEIOCONTROL message to the control procedure of the specified VxD to determine if it supports the device IOCTL interface. The ESI register contains the address of a DIOCParams structure whose dwIoControlCode member specifies the DIOC_GETVERSION control code. A VxD that supports the device IOCTL interface must respond to the DIOC_GETVERSION control code by clearing the EAX register. (A VxD can also return version information in the buffer pointed to by the lpvOutBuffer member so long as the cbOutBuffer member is nonzero. If cbOutBuffer is zero, the calling application is not interested in version information, but the VxD must still return zero to indicate success.) If the VxD does not support the device IOCTL interface, it must place a nonzero value in EAX.

For dynamically loadable VxDs, the system sends a SYS_DYNAMIC_INIT control message to the VxD the first time that it is opened. If the VxD returns success, the system sends the W32_DEVICEIOCONTROL message with the DIOC_OPEN (identical in value to the DIOC_GETVERSION control code) control code. The VxD must return zero to inform the calling application that it supports W32_DEVICEIOCONTROL. The system sets the reference count for the VxD to 1. On every subsequent call to CreateFile for the VxD, the VxD receives the W32_DEVICEIOCONTROL message with the DIOC_OPEN control code and the reference count for the VxD is incremented.

The VxD receives a W32_DEVICEIOCONTROL message with the DIOC_CLOSEHANDLE control code if the application closes the device handle by calling the CloseHandle function, or if the operating system closes the handle when the application terminates (or DeleteFile if the VxD was not opened with the FILE_FLAG_DELETE_ON_CLOSE value). The VxD can use this notification to perform cleanup operations and release structures associated with the application. The reference count for the VxD is decremented before the message is sent. If the reference count is decremented to zero, the VxD receives the SYS_DYNAMIC_EXIT message and is subsequently unloaded.


Processing Control Codes

When an application calls DeviceIoControl, the system calls the control procedure of the VxD identified by the given device handle. The EAX register contains the W32_DEVICEIOCONTROL message, and the ESI register contains the address of a DIOCParams structure. The structure contains all of the parameters that the application specified in the DeviceIoControl function as well as additional information. The VxD should examine the dwIoControlCode member of the DIOCParams structure to determine the action to perform. The lpvInBuffer member contains supporting data that the VxD needs to complete the action. After processing the control code, the VxD should copy any information that it needs to return to the application to the buffer specified by the lpvOutBuffer member.

If the VxD successfully processes the control code, it should clear the EAX register before returning. Otherwise, the VxD should set EAX to a nonzero value.


Asynchronous Operations

A VxD can determine whether an application has requested an asynchronous operation by checking the lpoOverlapped member of the DIOCParams structure. If lpoOverlapped specifies the address of an OVERLAPPED structure, the application has requested an asynchronous operation. In that case, the VxD should return  − 1 in the EAX register and then process the specified control code.

The operating system does not take any steps to make the application's memory available to the VxD at all times (in all contexts) for asynchronous operations. When implementing asynchronous operations, the VxD must use the appropriate virtual machine manager (VMM) services, such as LinPageLock with the PAGEMAPGLOBAL value, to make the application's memory pages available across contexts, including access to the OVERLAPPED structure.

When the VxD finishes processing the control code, it must notify the application by calling the VWIN32_DIOCCompletionRoutine service provided by VWIN32.VXD. The EBX register must contain the value of the Internal member of the OVERLAPPED structure. This member is reserved for operating system use only. Also, if the VxD copies any data to the buffer specified by the lpvOutBuffer member of the DIOCParams structure, the VxD must specify the count of bytes copied to the buffer in the InternalHigh member of OVERLAPPED. The remaining members of OVERLAPPED, Offset and OffsetHigh, can be used for developer-defined data.

Essentially, the VWIN32_DIOCCompletionRoutine service helps signal the event identified by the hEvent member of the OVERLAPPED structure. The application monitors the event to determine when the asynchronous operation is completed.


Reference

The following structures, system messages, and service are associated with the device IOCTL interface.


Structures

These structures are used to carry out device IOCTL functions.


DIOC_REGISTERS [New - Windows 95]
DIOC_REGISTERS

[New - Windows 95]

typedef struct DIOCRegs {

    DWORD   reg_EBX;   // EBX register

    DWORD   reg_EDX;   // EDX register

    DWORD   reg_ECX;   // ECX register

    DWORD   reg_EAX;   // EAX register

    DWORD   reg_EDI;   // EDI register

    DWORD   reg_ESI;   // ESI register

    DWORD   reg_Flags; // Flags register

} DIOC_REGISTERS;

Contains the register values for calling Interrupt 21h commands through the DeviceIoControl function. The meaning of the registers depends on the given command.

Some interrupt functions require far pointers passed in segment:offset pairs where the segment is placed in a segment register. Since the 32-bit code does not have segments, the DIOC_REGISTERS structure contains no segment registers. You should place the full pointer into the structure member that corresponds to the register used to hold the offset portion of the real-mode pointer. For example, use reg_EDX for pointers that go into the DS:DX registers.


DIOCParams [New - Windows 95]
DIOCParams

[New - Windows 95]

include vwin32.inc

DIOCParams STRUC
    Internal1             DD  ?  ; reserved
    VMHandle              DD  ?  ; handle of virtual machine
    Internal2             DD  ?  ; reserved
    dwIoControlCode       DD  ?  ; see below
    lpvInBuffer           DD  ?  ; see below
    cbInBuffer            DD  ?  ; see below
    lpvOutBuffer          DD  ?  ; see below
    cbOutBuffer           DD  ?  ; see below
    lpcbBytesReturned     DD  ?  ; see below
    lpoOverlapped         DD  ?  ; see below
    hDevice               DD  ?  ; handle of device
    tagProcess            DD  ?  ; see below
DIOCParams ENDS

Contains information that an application has passed to the virtual device driver (VxD) by calling the DeviceIoControl function.

dwIoControlCode

Control code to process. This member can be a developer-defined value or one of these system-defined values:

DIOC_CLOSEHANDLE	Notifies a VxD that an application has closed its device handle for the VxD. The VxD should perform cleanup operations and release any structures associated with the application.
DIOC_GETVERSION	Queries the VxD to determine if it supports the device IOCTL interface. If the VxD supports the interface, it must clear the EAX register. Otherwise, it must place a nonzero value in EAX. If cbOutBuffer is nonzero and the VxD supports the interface, the VxD should copy version information to the lpvOutBuffer.
lpvInBuffer

Address of a buffer that contains data needed to process the control code.

cbInBuffer

Size, in bytes, of the buffer pointed to by lpvInBuffer.

lpvOutBuffer

Address of a buffer that receives the results of processing the control code.

cbOutBuffer

Size, in bytes, of the buffer pointed to by lpvOutBuffer.

lpcbBytesReturned

Number of bytes copied to the buffer pointed to by lpvOutBuffer.

lpoOverlapped

Address of an OVERLAPPED structure that contains information used to complete the command asynchronously. If the command is to be completed synchronously, this member is NULL.

tagProcess

Information that the VxD can use to tag the current request along with hDevice. When the VxD receives a DIOC_CLOSEHANDLE control code for hDevice and tagProcess, it should perform appropriate cleanup operations.


System Message

The following system message is used to implement the device IOCTL interface of a VxD.


W32_DEVICEIOCONTROL [New - Windows 95]
W32_DEVICEIOCONTROL

[New - Windows 95]

include VMM.INC

mov ebx, VMHandle           ; see below

mov eax, W32_DEVICEIOCONTROL

mov esi, OFFSET32 dioparams ; see below

VMMCall System_Control

Passes a control code and related information to a virtual device driver.

•	Returns one of the following values in the EAX register:

0	The control code processed successfully.
− 1	An asynchronous operation is in progress. A VxD must return this value only if the lpoOverlapped member of the DIOCParams structure is not NULL.
Error code	An error occurred. For a list of Win32 error codes, see the documentation included in the Win32 SDK.
VMHandle

Handle of the virtual machine.

dioparams

Address of a DIOCParams structure containing a control code and information that the VxD needs to process the control code.

This message is sent to a VxD when an application specifies the name of a VxD in the CreateFile function and when an application specifies the device handle of the VxD in a call to the DeviceIoControl or CloseHandle function. This message uses the ESI register.


Service

The following service is used with device IOCTL.


VWIN32_DIOCCompletionRoutine [New - Windows 95]
VWIN32_DIOCCompletionRoutine

[New - Windows 95]

mov ebx, Internal  ; see below
VxDCall VWIN32_DIOCCompletionRoutine

Notifies the system that an asynchronous operation in a virtual device driver is complete. The VxD calls this service after the asynchronous input and output (I/O) operation to signal the application.

•	No return value.

Internal

Event identifier. This parameter must be the same value initially passed to the VxD in the Internal member of the OVERLAPPED structure.

Before calling this service, the VxD must set the InternalHigh member of the OVERLAPPED structure to the number of bytes of return data.


System Policies

System administrators can use Microsoft® Windows® 95 system policies to control user and computer configurations from a single location on a network. System Policies propagate registry settings to a large number of computers without requiring the administrator to have detailed knowledge of the registry.


About System Policies

There are many settings in the registry, and multiple registry settings must often be manipulated to achieve a particular result. The System Policies feature provides a layer of abstraction that makes it easier to control registry settings.

Instead of changing individual registry settings, a system administrator can specify policies. Each policy has some text that describes its effect. Some examples of policies follow:

•	Disable file sharing.

•	Display a custom logon banner.

•	Remove the Run command from the Start menu.

•	Use user-level security.


Registry Settings

Each policy is associated with one or more registry settings. When the administrator chooses to enforce a policy, the System Policies tool identifies registry changes that must be made and then makes the changes to the registries of the users and computers for which the policy applies. The administrator can specify policies for individual users, user groups, and individual computers. Default values can also be specified.

Policies have been implemented for most of the registry settings that an administrator might want to control and propagate. Although System Policies control only a subset of the registry, they are extensible. Application developers are encouraged to supply template files and implement policies for registry settings used by their products so that customers can plug the template files into a policy editor and control policies for the application.


Policy Editors and Downloaders

There are two administrative components involved in specifying policies: a policy editor and a policy downloader. A policy editor is an application that lets administrators specify registry settings for particular computers, users, and user groups, and a policy downloader is a small program installed on every client computer that merges the administrator's settings into the local registry.

The policy editor uses a template file, which is a text file describing registry settings and specifying how the settings should appear in the policy editor's user interface. The policy editor creates a policy file, which is a single file containing policy settings for a number of computers, users, and user groups. The policy file is a registry hive that is created and manipulated using Microsoft® Win32® functions. Windows 95 includes a policy editor, the System Policy Editor. Developers may create their own policy editors, but the editors must be able to read template files and be able to read and write policy files.

Windows 95 provides a policy downloader, which is built into Multiple Provider Router (MPR). Developers may also create their own policy downloaders. Policy downloaders may be installed so that MPR will call the installed component to do the downloading rather than doing so itself. Because the policy file format allows for extensions, developers may provide additional functionality.


Architecture

A computer's configuration is defined in terms of policies. The policies are ultimately stored in the local computer's registry. Every component that provides a policy is responsible for reading the registry at appropriate times and acting accordingly. For example, the policy that removes the Run command from the Start menu requires the shell code that displays the Start menu to check the appropriate registry setting to determine whether or not it is supposed to display the Run command. The policies are generic data items; the administrative tools and components have no information about them besides their names, their associated data, and where they reside in the registry. The only responsibilities of the administrative components are to allow the administrator to make policy settings and propagate those settings to the user's registry.


Policy Primitives

The following definitions are important for a complete understanding of policies:

•	A policy is a permission or attribute for a particular item, action, or object. It is either enabled or disabled.

•	A part is a subcomponent of a policy. A policy may have zero or more parts. Policy parts may have various data types, including Boolean values, numeric values, and string values. The values of the parts apply only if the policy is enabled.

•	A category is a collection of similar policies.

Some policies do not need any parts. For instance, "Lock Desktop Links" could be a policy. For such a policy, it would be sufficient to say that it was either enabled or disabled. If it were enabled, the user could not modify his or her desktop links in any way. "Desktop Links" could be another policy, and it could have the Boolean parts "Create Links," "Delete Links," and "Modify Links." As another example, "Password Expiration" could be a policy, and "Number of days" (a numeric value) could be its part.

Policies and parts are analogous to a group of controls in a dialog box that are all enabled by a single check box. The check box, which corresponds to whether or not the policy is enabled, "turns on" the controls in the dialog box (the policy parts) and allows data to be entered into the controls. A policy with no parts (that is, no associated controls) is analogous to a single check box.

The following types of policies can be specified:

•	A user-specific policy can be specified for each user or group. A default set of policies can be specified for users or groups who do not have sets of policies defined for them explicitly. Most policies are user-specific. User-specific policies are always merged into the HKEY_CURRENT_USER key of the registry.

•	A machine-specific policy should not change according to user. A machine-specific policy applies to all users. It does not follow users as they move between different computers. Machine-specific policies are always merged into the HKEY_LOCAL_MACHINE key of the registry.


Policy Information

Any application or component can define a policy. The policy will appear in the administrator user interface, and information that the administrator sets about the policy will migrate to the local computer's registry. The application or component that defines a policy must check the registry appropriately to enforce its own policy.

Policy information is typically added to a local registry in the following sequence:

1.	Categories, policies, and parts are described in a template (.ADM) file. The .ADM file format is described in "Template File Format" later in this topic. An ADMIN.ADM file with all the policies that the system supports is shipped with Windows 95. Developers, however, may also provide their own template files.

2.	The administrator runs the policy editor, which reads one or more policies and lists the available categories and policies. The administrator sets up the desired policies, and the policy editor uses registry functions to save the work to a policy (.POL) file. The format of policy files is described in "Policy File Format" later in this topic.

3.	After the user logs on (and user profiles are reconciled if they are enabled), the policy downloader is activated. It determines where to find the file on the network, opens the policy file, and merges the appropriate computer, user, and user group policies into the local registry.


Default User and Computer Names

There is a standard user name called DEFAULT USER and a standard computer name called DEFAULT COMPUTER. When the policy downloader updates machine- and user-specific policies, it first tries to find an entry in the policy file for the local computer name or user name. If the downloader does not find an entry, it looks for the DEFAULT USER or DEFAULT COMPUTER entry and uses those entries for the update. If there are no entries for a particular user or computer and default entries do not exist, no update takes place.

The DEFAULT USER and DEFAULT COMPUTER entries are powerful because administrators can set policies for a large number of users and computers and then manage the exceptions by creating specific user and computer entries in a .POL file.


Policy Downloading

Policy downloading can be set in one of the following three states:

•	Off

•	Automatic

•	Manual

If policy downloading is off, no downloading takes place.

If policy downloading is set to automatic, MPR asks the primary network provider to provide a place to look on the network for the policy file. Microsoft® Windows NT™ and Novell® NetWare® providers both support this capability. (For a Windows NT network, MPR looks in the primary domain controller's NETLOGON directory for a file named CONFIG.POL. For a NetWare version 3..x network, MPR looks on the preferred server's SYS\PUBLIC directory for a file named CONFIG.POL.) Any software vendor who provides a 32-bit network provider can support this capability by implementing the NPGetPolicyPath function. If policy downloading is set to automatic and the primary network provider does not support NPGetPolicyPath, no downloading takes place.

If policy downloading is set to manual, a specific path to the policy file must also be supplied. It can be either a Universal Naming Convention (UNC) path or a path beginning with a drive letter. (In the latter case, the drive letter must be appropriately mapped before downloading takes place.)

The default setting for policy downloading is automatic. No error messages are displayed if a policy file cannot be found in the location that the network provider suggests. This means that a site can install a number of Windows 95 clients and then deploy the policies at a later date. To deploy them, the administrator just needs to place the policy file(s) in the appropriate location(s) on the network, and the clients will immediately begin using them the next time they log on.


Policy Editor User Interface

This section describes the user interface of the System Policy Editor that ships with Windows 95. Other software vendors may, however, choose to use a different user interface.

The System Policy Editor requires an .ADM file describing the available policies to use. By default, it will use a file named ADMIN.ADM, but different template files may be specified using the Templates menu.

The main window of the System Policy Editor displays the users and computers that have entries in the policy file that is currently open. To create a new policy file, choose the New command on the File menu. A new policy file contains entries for the default user and default computer. To add entries for particular users or particular computers, use the Add User, Add Group, or Add Computer button. Note that policies for all of the entries shown in the main window are saved to one policy file. Typically, an administrator saves the policy file to the network location where the policy downloader looks by default.

The following illustration shows the main window of the System Policy Editor.

Double-clicking an entry, such as Default Computer, brings up a properties dialog box containing the policies for the entry. The Default Computer Properties dialog box shown in the following illustration has an upper section listing the policies and a lower section showing settings for a specific policy.

A check box in the properties dialog box has three states. If it is checked, the policy will be enforced; that is, the corresponding settings will be added to the registry when the policy is downloaded. If the check box is empty, the settings will be deleted from the registry when the policy is downloaded. If the check box is gray, the registry settings will not be changed when the policy is downloaded; that is, the user has the freedom to choose settings, assuming that the settings can be changed from the user interface.

For example, there is a user policy for desktop wallpaper. By checking that policy, the administrator specifies the particular wallpaper that the user will have. Even if the user uses the Display Control Panel application to change the wallpaper, the wallpaper specified by the administrator will appear the next time he or she logs on. If the administrator unchecks this policy, the wallpaper setting is deleted so that when the user logs on, there is no wallpaper. If the administrator makes the check box gray, nothing is enforced, and the user can choose the wallpaper.

As a second example, there is a user policy "Remove Run from Start menu" (under the Shell/Restrictions registry key). Checking this policy adds a registry setting that tells the shell not to include the Run command on the Start menu. By unchecking this policy, this registry key is deleted, and the shell displays the Run command. If the policy is left gray, the setting will not be changed. If the policy was already in force, it will stay that way, and the Run command will continue to be denied to the user. If the policy had not been applied already, the user would continue to see the Run command. Note that unlike the wallpaper example, the user cannot change this setting by using Control Panel or another user interface element.

The System Policy Editor can also operate directly on the local registry rather than on a policy file. This capability is useful for troubleshooting problems that may be policy-related, because it shows what policies are currently in place for a user on a particular computer. There is no policy file involved in this mode. To switch to the local registry view, use the Open Registry command on the File menu. Note that the check boxes will show only two states, checked and unchecked, because the registry settings for the policy are either present (the policy is on) or not present (the policy is off).


Template File Format

A template (.ADM) file describes a number of categories. Each category can contain zero or more policies, and each policy can contain zero or more parts. The following sections describe categories, policies, policy parts, and part types.

The ADMIN.ADM file that ships with Windows 95 identifies strings that are important for an internal localization tool by using two exclamation points (!!). Each of these strings is explicitly defined in the [strings] section of ADMIN.ADM. You do not need to use this mechanism when you create a template file.


Categories

A category is specified as follows.

CATEGORY name TYPE category type
[KEYNAME key name]

[... policy definition statements ...]

END CATEGORY

name

Category name as it should appear in the System Policy Editor list box. It may optionally be enclosed by double quotation marks. (Names with spaces must be enclosed by double quotation marks.)

category type

Type, which must be USER or MACHINE. It specifies whether the category is user-specific or machine-specific.

key name

Optional registry key name to use for the category. If a key name is specified, it will be used by all child categories, policies, and parts, unless they specifically provide a key name of their own.

A policy definition statement may not appear more than once in a single category.


Policies

A policy is specified as follows.

POLICY name
[KEY key name]
[... part definition statements ...]
END POLICY

name

Policy name as it should appear in the System Policy Editor list box. It may optionally be enclosed by double quotation marks. (Names with spaces must be enclosed by double quotation marks.)

key name

Optional registry key name to use for the policy. If a key name is specified, it will be used by all child parts of the policy, unless they specifically provide a key name of their own.


Policy Parts

A policy part is specified as follows.

PART name TYPE part type
type-dependent data
[KEYNAME key name ]
VALUENAME value name
END PART

name

Part name as it should appear in the System Policy Editor list box. It may optionally be enclosed by double quotation marks. (Names with spaces must be enclosed by double quotation marks.)

part type

Policy part type. Part types are discussed individually in the following section.

type-dependent data

Information about the part. Type-dependent data is discussed in the following section.

key name

Optional key name to use. If no key name is specified, the previous key name in hierarchy is used.

value name

Value name to use to set the data for this part.


Part Types

The following policy part types are defined:

CHECKBOX	Displays a check box. The value is set in the registry with the REG_DWORD type. The value will be nonzero if the check box is checked by the user and zero if it is unchecked.
COMBOBOX	Displays a combo box.
DROPDOWNLIST	Displays a combo box with a drop-down list style. The user may only choose from one of the entries supplied. The main advantage of a combo box with a drop-down list is that a number of extra registry edits may be specified, based on the user's selection.
EDITTEXT	Displays an edit field that accepts alphanumeric text. The text is set in the registry with the REG_SZ type.
LISTBOX	Displays a list box with "add" and "remove" buttons. This is the only part type that can be used to manage multiple values under one key.
NUMERIC	Displays an edit field with an optional spinner control (an up-down control) that accepts a numeric value. The value is set in the registry with the REG_DWORD type.
TEXT	Displays a line of static (label) text. There is no associated registry value with this part type.
Descriptions of these policy part types follow.


CHECKBOX Part Type [New - Windows 95]
CHECKBOX Part Type

[New - Windows 95]

The CHECKBOX part type accepts the following options:

ACTIONLISTOFF	Specifies an optional action list to be used if the check box is turned off. For more information, see "Action Lists" later in this topic.
ACTIONLISTON	Specifies an optional action list to be used if the check box is turned on. For more information, see "Action Lists" later in this topic.
DEFCHECKED	Causes the check box to be initially checked.
VALUEOFF	Overrides the default "off" behavior of the check box if specified.
VALUEON	Overrides the default "on" behavior of the check box if specified.
The default behavior of a check box is to write the value 1 to the registry if it is checked and 0 if it is unchecked. VALUEON and VALUEOFF are used to override this behavior. For example, the following option writes "Fred" to the registry when the check box is checked.

VALUEON "Fred"

The following option writes the value 12 to the registry when the check box is unchecked.

VALUEOFF NUMERIC 12


COMBOBOX Part Type [New - Windows 95]
COMBOBOX Part Type

[New - Windows 95]

The COMBOBOX part type accepts all the options that EDITTEXT does as well as the following option:

SUGGESTIONS	Begins a list of suggestions to be placed in the drop-down list. Suggestions are separated with spaces and can be enclosed by double quotation marks. The list ends with END SUGGESTIONS. Following is an example: SUGGESTIONS Alaska Alabama Mississippi "New York" END SUGGESTIONS


DROPDOWNLIST Part Type [New - Windows 95]
DROPDOWNLIST Part Type

[New - Windows 95]

The DROPDOWNLIST part type accepts the following options:

ITEMLIST	Begins a list of the items in the drop-down list. The list must end with END ITEMLIST.
REQUIRED	Specifies that the policy editor will not allow a policy containing this part to be enabled unless a value has been entered for the part.
Each item in the ITEMLIST option must be specified as follows.

NAME name VALUE value
[ACTIONLIST actionlist]
...

name

Text to be displayed in the drop-down list for this item.

value

Value to be written as the part's value if this item is selected. Values are assumed to be strings, unless they are preceded by NUMERIC. The following example shows both string and numeric values.

   VALUE "Some value"

   VALUE NUMERIC 1

If VALUE is followed by DELETE (for example, VALUE DELETE), the registry valuename and value pair will be deleted.

actionlist

Optional action list to be used if this value is selected. For more information about action lists, see "Action Lists" later in this topic.


EDITTEXT Part Type [New - Windows 95]
EDITTEXT Part Type

[New - Windows 95]

The EDITTEXT part type accepts the following options:

DEFAULT value	Specifies the initial string to place in the edit field. If this option is not specified, the field is initially empty.
MAXLEN value	Specifies the maximum length of a string. The string in the edit field is limited to this length.
REQUIRED	Specifies that the policy editor will not allow a policy containing this part to be enabled, unless a value has been entered for this part.
OEMCONVERT	Sets the ES_OEMCONVERT style in the edit field so that typed text is mapped from ANSI to OEM and back.


LISTBOX Part Type [New - Windows 95]
LISTBOX Part Type

[New - Windows 95]

The VALUENAME option cannot be used with the LISTBOX part type, because there is no single value name associated with this type. By default, only one column appears in the list box, and for each entry a value is created whose name and value are the same. For instance, a "fred" entry in the list box would create a value named "fred" whose data was "fred".

The LISTBOX part type accepts the following options:

ADDITIVE	By default, the content of list boxes will "override" whatever values are set in the target registry. (That is, a control value is inserted in the policy file, which causes existing values to be deleted before the values set in the policy file are merged.) If this option is specified, existing values are not deleted, and the values set in the list box will be in addition to whatever values exist in the target registry.
EXPLICITVALUE	This option makes the user specify not only the value data, but the value name as well. The list box will show two columns for each item, one for the name and one for the data. This option cannot be used with the VALUEPREFIX option.
VALUEPREFIX prefix	The prefix specified is used in determining value names. If a prefix is specified, the prefix and an incremented integer will be used instead of the default value naming scheme described previously. For example, a prefix of "SomeName" will generate the value names "SomeName1", "SomeName2", and so on. The prefix can be empty (""), which will cause the value names to be "1", "2", and so on.


NUMERIC Part Type [New - Windows 95]
NUMERIC Part Type

[New - Windows 95]

The NUMERIC part type accepts the following options:

DEFAULT value	Specifies the initial numeric value for the edit field. If this option is not specified, the field is initially empty.
MAX value	Specifies the maximum value for the number. The default value is 9999.
MIN value	Specifies the minimum value for the number. The default value is 0.
REQUIRED	Specifies that the policy editor will not allow a policy containing this part to be enabled unless a value has been entered for this part.
SPIN value	Specifies increments to use for the spinner control. SPIN 0 removes the spinner control. SPIN 1 is the default.
TXTCONVERT	Writes values as REG_SZ strings ("1," "2," or "128") rather than as binary values.


TEXT Part Type [New - Windows 95]
TEXT Part Type

[New - Windows 95]

The TEXT part type accepts no type-specific data.


Action Lists

An action list is a set of arbitrary changes to the registry that are made in response to a control being in a certain state. For instance, if a check box is turned on, an application could install some virtual device drivers and record some other changes.

The syntax for an actionlist follows.

ACTIONLIST
    [KEYNAME key name]
    VALUENAME value name
    VALUE value
    [KEYNAME key name]
    VALUENAME value name
    VALUE value
    ....
END ACTIONLIST

The actionlist specifies a number of key name, value name, and value triplets. A key name is not required for every action, but if it is not listed, the key name from the previous action will be used. (This is useful for writing a number of values to one key.) Values are treated as strings unless they are preceded by NUMERIC, as in the following examples.

VALUE "Some value"

VALUE NUMERIC 1

If VALUE is followed by DELETE (for example, VALUE DELETE), the registry valuename and value pair will be deleted.


Comments

Comments can be added to a template (.ADM) file by preceding the line with two forward slashes (//) or a semicolon (;).


Conditional Expressions

Future policy editors may include new capabilities. If these new capabilities require revisions to the template file format, older versions of the System Policy Editor will not be able to read the new template files. You can use conditional expressions to ensure that any future template files you create will be compatible with older policy editors.

The System Policy Editor supports two conditional expressions. The first one allows you to include different parts of the template file, based on the version number. This expression has the following syntax.

#if VERSION operator version_number

.

.

.

[#else]

.

.

.

#endif

The operator can be one of the following symbols: >, >=, <, <=, ==, or !=. The version_number can be any integer; for Windows 95, the version number is 1.

The other conditional expression is #ifdef. This expression has the following syntax.

[#ifdef | #ifndef] keyword

.

.

.

[#else]

.

.

.

#endif

Keywords are implicitly understood by the policy editor. For example, a fictitious company named PolicyCorp might implement its own policy editor that could recognize the POLICYCORP keyword. This company could use the #ifdef and #endif conditional expressions to make sure its template files can be recognized by the Windows 95 System Policy Editor. (Because the Windows 95 System Policy Editor does not currently recognize any keywords, #ifdef always evaluates to FALSE and #ifndef always evaluates to TRUE.)


Policy File Format

A policy (.POL) file is a registry hive, which is created by using the Win32 RegSaveKey function.

The following top-level keys are defined:

•	Computers

•	Groups

•	GroupData

•	Users

•	Misc

A policy downloader uses the following steps to download policies:

1.	Locates the appropriate computer key, if any, under Computers. Beneath that key is an image of the registry settings to be merged. The policy downloader should walk through all the subkeys and values and merge those settings into the HKEY_LOCAL_MACHINE key, paying attention to the control codes that are defined in the following section.

2.	Locates the appropriate groups key(s), if any, under Groups. Under the Groups keys is an image of the registry settings to be merged. These settings must be merged into the HKEY_CURRENT_USER key.

3.	Locates the appropriate user key, if any, under Users. Under the Users key is an image of the registry settings to be merged. These settings must be merged into the HKEY_CURRENT_USER key.


Control Codes

Control codes are used to signify that special processing of a value or key name must take place. All control codes are prefixes to a value or key name and take the form of the code name (that is, **code.) directly followed by value name or key name.

The following control codes are defined for use with value names.

**del.	Specifies that the value name following the control code should be deleted.
**delvals.	Deletes all values under this key in the local registry before propagating values under this key from the policy file. When processing a particular key, a downloader must look for and process this value first. This control code is inserted by a list box control so that existing values are removed before the new values are added.
**soft.	Specifies that it is a soft value. The downloader only propagates the value name following the control code if a value by that name does not exist in the local registry; that is, the downloader does not overwrite existing settings with soft values.
No control codes are currently defined for use with key names.

If a policy downloader encounters a control code that it does not understand, it must not process the key or value. If the control code is part of a value name, the policy downloader should skip that value in the hive file but continue to process other values under that key and its subkeys. If the control code is part of a key name, the downloader should ignore the key and not process any values under it or its subkeys. This behavior is important because it allows developers to create new control codes without breaking existing downloaders.

Developers may create new control codes in the same format as shown in the preceding table (that is, **code.). Developers who do so should notify Microsoft so that Microsoft can document the new codes.


Computers Key

Underneath the Computers key is a list of computers that have entries in the policy file. The steps to use in locating a Computers key follow:

1.	Determine whether there is a key that is the same as the computer name. If there is one, merge the registry image beneath it into the HKEY_LOCAL_MACHINE key.

2.	If the key is not there, determine whether there is a key called ".default". (This appears in the System Policy Editor user interface as Default Computer.) If a default key exists, merge the registry image beneath it.

3.	If neither of the two steps work, do nothing.


Groups and GroupData Keys

Underneath the Groups key is a list of user groups who have entries in the policy file. Since a user may belong to many groups and those groups may have conflicting settings, it is important to specify an order in which groups are processed. This order is contained in the GroupData\Priority key, which has values in the form "1"="group name", "2"="group name", and so on. "1" is highest priority, and the priority diminishes as the number in the value name increases. The downloader reads the group priority values and then processes groups from lowest priority to highest; that is, the downloader begins with the highest numbered value and works to the value "1".

For each group in the priority list, the downloader determines if the user is a member of the group. If the user is in the group, the downloader should try to find a key with the group name under the Groups key. If such a key exists, the downloader merges the registry image under that key into the HKEY_CURRENT_USER key. It is not an error if a group is specified in the priority list but does not have an entry under the Groups key; it simply means that nothing happens. This process is repeated for each group in the priority list. (If a group has an entry under the Groups key but does not have an entry in the priority list, it is never processed.)


Users Key

Underneath the Users key is a list of computers that have entries in the policy file. The steps to use in locating a Users key follow:

1.	Determine whether there is a key that is the same as the user name. If there is one, merge the registry image beneath it into the HKEY_CURRENT_USER key.

2.	If the key is not there, determine whether there is a key called ".default". This appears in the System Policy Editor user interface as Default User. If a default key exists, merge the registry image beneath it.

3.	If neither of the two steps work, do nothing.


Misc Key

The Misc key can be used by developers to store vendor-specific data. The naming convention for this key follows.

Misc\Vendor Name \Product Name\Version\ data

A software vendor may store any needed information in data. A key or value containing version information is highly recommended. As is recommended for the registry, Version should be "CurrentVersion" for the most current version of the product.


Installable Policy Downloaders

An installable policy downloader must be a Win32 dynamic-link library (DLL). It should export a named function that has the following form.

VOID FAR PASCAL ProcessPolicies(HWND hwndOwner,
LPSTR lpszPolicyFilePath, LPSTR lpszUserName,
LPSTR lpszComputerName, DWORD dwFlags);

hwndOwner

Handle of the parent window.

lpszPolicyFilePath

Address of the full path and filename that MPR would have used to look for the policy file. The downloader may use this parameter, or ignore it and use a different path.

lpszUserName

Address of the user name for the user who is logged on.

lpszComputerName

Address of the local computer name.

dwFlags

Flags. This parameter can be this value:

PP_DISPLAYERRORS	Displays error messages about errors encountered during downloading (including the file is not found, the network resource is not found, and so on). Otherwise, the function should fail silently if there is an error.
In addition to defining and exporting this function, an application must record it in the registry. The following entry should be added under the HKEY_LOCAL_MACHINE\Network\Logon key.

PolicyHandler = "dll name, function name"

In this example, dll name is the name of the DLL containing the function, and function name is the exported function name.


Tool Help Functions

Tool help functions make it easier for developers to obtain information about currently executing Microsoft® Win32®-based applications. These functions are designed to streamline the creation of Win32-hosted tools, specifically Windows-based debugging applications.


About Tool Help Functions

The following topics are discussed in this article:

•	Snapshots of the system

•	Process walking

•	Thread walking

•	Module walking

•	Heap lists and heap walking


Snapshots of the System

Snapshots are at the core of the tool help functions. A snapshot is a read-only copy of the current state of one or more of the following lists that reside in system memory: processes, threads, modules, and heaps.

Win32 processes that use tool help functions access these lists from snapshots instead of directly from the operating system. The lists in system memory change when processes are started and ended, threads are created and destroyed, executable modules are loaded and unloaded from system memory, and heaps are created and destroyed. The use of information from a snapshot prevents inconsistencies. Otherwise, changes to a list could possibly cause a thread to incorrectly traverse the list or cause an access violation (a GP fault). For example, if an application traverses the thread list while other threads are created or terminated, information that the application is using to traverse the thread list might become outdated and could cause an error for the application traversing the list.

You can take a snapshot of the system memory by using the CreateToolhelp32Snapshot function. You can control the content of a snapshot by specifying one or more of the following values when calling this function: TH32CS_SNAPHEAPLIST, TH32CS_SNAPMODULE, TH32CS_SNAPPROCESS, and TH32CS_SNAPTHREAD.

The TH32CS_SNAPHEAPLIST and TH32CS_SNAPMODULE values are process specific. When these values are specified, the heap and module lists of the specified process are included in the snapshot. If no process identifier is specified, the current process is assumed. The TH32CS_SNAPTHREAD value always creates a system-wide snapshot even if a process identifier is passed to CreateToolhelp32Snapshot.

You can enumerate the heap or module state for all Win32 processes by specifying the TH32CS_SNAPALL value and the current process. Then, for each process in the snapshot that is not the current process, you can call CreateToolhelp32Snapshot again, specifying the process identifier and the TH32CS_SNAPHEAPLIST or TH32CS_SNAPMODULE value.

You can retrieve an extended error status code for CreateToolhelp32Snapshot by using the GetLastError function. For more information about GetLastError, see the documentation included in the Microsoft Win32 Software Development Kit (SDK).

When your process finishes using a snapshot, you should destroy it by using the CloseHandle function. Not destroying a snapshot causes the process to leak memory until the process exits, at which time the system reclaims the memory. For more information about CloseHandle, see the documentation included in the Win32 SDK.

Note  The snapshot handle acts like a file handle and is subject to the same rules regarding which processes and threads it is valid in.


Process Walking

A snapshot that includes the Win32 process list contains information about each currently executing process. You can retrieve information for the first process in the list by using the Process32First function. After retrieving the first process in the list, you can traverse the process list for subsequent entries by using the Process32Next function. Process32First and Process32Next fill a PROCESSENTRY32 structure with information about a process in the snapshot.

You can retrieve an extended error status code for Process32First and Process32Next by using the GetLastError function. For more information about GetLastError, see the documentation included in the Win32 SDK.

You can read the memory in a specific process into a buffer by using the Toolhelp32ReadProcessMemory function (or the VirtualQueryEx function).

Note  The contents of the th32ProcessID and th32ParentProcessID members of PROCESSENTRY32 are Win32 process identifiers and can be used with other Win32 application programming interface (API) elements.


Thread Walking

A snapshot that includes the Win32 thread list contains information about each thread of each currently executing Win32 process. You can retrieve information for the first thread in the list by using the Thread32First function. After retrieving the first thread in the list, you can retrieve information for subsequent threads by using the Thread32Next function. Thread32First and Thread32Next fill a THREADENTRY32 structure with information about individual threads in the snapshot.

You can enumerate the threads of a specific process by taking a snapshot that includes the threads and then by traversing the thread list, keeping information about the threads that have the same process identifier as the specified process.

You can retrieve an extended error status code for Thread32First and Thread32Next by using the GetLastError function. For more information about GetLastError, see the documentation included in the Win32 SDK.


Module Walking

A snapshot that includes the module list for a specified Win32 process contains information about each module, executable file, or dynamic-link library (DLL), used by the specified process. You can retrieve information for the first module in the list by using the Module32First function. After retrieving the first module in the list, you can retrieve information for subsequent modules in the list by using the Module32Next function. Module32First and Module32Next fill a MODULEENTRY32 structure with information about the module.

You can retrieve an extended error status code for Module32First and Module32Next by using the GetLastError function. For more information about GetLastError, see the documentation included in the Win32 SDK.

Note  The module identifier, which is specified in the th32ModuleID member of MODULEENTRY32, has meaning only to the tool help functions. It is not a handle, nor is it usable by other Win32 API elements.


Heap Lists and Heap Walking

A snapshot that includes the heap list for a specified Win32 process contains identification information for each heap associated with the specified process and detailed information about each heap. You can retrieve an identifier for the first heap of the heap list by using the Heap32ListFirst function. After retrieving the first heap in the list, you can traverse the heap list for subsequent heaps associated with the process by using the Heap32ListNext function. Heap32ListFirst and Heap32ListNext fill a HEAPLIST32 structure with the process identifier, the heap identifier, and flags describing the heap.

You can retrieve information about the first block of a heap by using the Heap32First function. After retrieving the first block of a heap, you can retrieve information about subsequent blocks of the same heap by using the Heap32Next function. Heap32First and Heap32Next fill a HEAPENTRY32 structure with information for the appropriate block of a heap.

You can retrieve an extended error status code for Heap32ListFirst, Heap32ListNext, Heap32First, and Heap32Next by using the GetLastError function. For more information about GetLastError, see the documentation included in the Win32 SDK.

Note  The heap identifier, which is specified in the th32HeapID member of the HEAPENTRY32 structure, has meaning only to the tool help functions. It is not a handle, nor is it usable by other Win32 API elements.


Using the Tool Help Functions

This section contains examples demonstrating how to perform the following tasks:

•	Access tool help functions.

•	Take a snapshot and view the processes in the system address space.

•	Traverse the threads listed in a snapshot.

•	Traverse the modules listed for a specific process.

The following examples have been taken from the PVIEW95 application included in the Win32 SDK.

Note  Each of the HEAPENTRY32, HEAPLIST32, MODULEENTRY32, PROCESSENTRY32, and THREADENTRY32 structures that are used with the tool help functions has a dwSize member that must be initialized to the size of the structure before the structure is included in a call to a tool help function. The value of dwSize is used to indicate the version of the tool help functions used. If your application does not initialize dwSize, the tool help function will fail.


Accessing the Tool Help Functions

The tool help functions reside in the operating system kernel. The following example provides a platform-independent approach to accessing the tool help functions.

#include <tlhelp32.h> // needed for tool help declarations

// Type definitions for pointers to call tool help functions.

typedef BOOL (WINAPI *MODULEWALK)(HANDLE hSnapshot,
    LPMODULEENTRY32 lpme);

typedef BOOL (WINAPI *THREADWALK)(HANDLE hSnapshot,
    LPTHREADENTRY32 lpte);

typedef BOOL (WINAPI *PROCESSWALK)(HANDLE hSnapshot,
    LPPROCESSENTRY32 lppe);

typedef HANDLE (WINAPI *CREATESNAPSHOT)(DWORD dwFlags,
    DWORD th32ProcessID);

// File scope globals. These pointers are declared because of the need

// to dynamically link to the functions.  They are exported only by

// the Windows 95 kernel. Explicitly linking to them will make this

// application unloadable in Microsoft(R) Windows NT(TM) and will

// produce an ugly system dialog box.

static CREATESNAPSHOT pCreateToolhelp32Snapshot = NULL;

static MODULEWALK  pModule32First  = NULL;

static MODULEWALK  pModule32Next   = NULL;

static PROCESSWALK pProcess32First = NULL;

static PROCESSWALK pProcess32Next  = NULL;

static THREADWALK  pThread32First  = NULL;

static THREADWALK  pThread32Next   = NULL;

// Function that initializes tool help functions.

BOOL InitToolhelp32 (void)

{

    BOOL   bRet  = FALSE;

    HANDLE hKernel = NULL;

    // Obtain the module handle of the kernel to retrieve addresses of

    // the tool helper functions.

    hKernel = GetModuleHandle("KERNEL32.DLL");

    if (hKernel){

        pCreateToolhelp32Snapshot =

            (CREATESNAPSHOT)GetProcAddress(hKernel,
            "CreateToolhelp32Snapshot");

        pModule32First  = (MODULEWALK)GetProcAddress(hKernel,

            "Module32First");

        pModule32Next   = (MODULEWALK)GetProcAddress(hKernel,

            "Module32Next");

        pProcess32First = (PROCESSWALK)GetProcAddress(hKernel,

            "Process32First");

        pProcess32Next  = (PROCESSWALK)GetProcAddress(hKernel,

            "Process32Next");

        pThread32First  = (THREADWALK)GetProcAddress(hKernel,

            "Thread32First");

        pThread32Next   = (THREADWALK)GetProcAddress(hKernel,

            "Thread32Next");

        // All addresses must be non-NULL to be successful.

        // If one of these addresses is NULL, one of

        // the needed lists cannot be walked.

        bRet =  pModule32First && pModule32Next  && pProcess32First &&

                pProcess32Next && pThread32First && pThread32Next &&

                pCreateToolhelp32Snapshot;

    }

    else

        bRet = FALSE; // could not even get the module handle of kernel

    return bRet;

}


Taking a Snapshot and Viewing Processes

The following function takes a snapshot of the currently executing processes in the system and walks through the list recorded in the snapshot.

BOOL GetProcessList (VOID)

{

    HANDLE         hSnapshot = NULL;

    BOOL           bRet      = FALSE;

    PROCESSENTRY32 pe32      = {0};

    //  Take a snapshot of all processes currently in the system.

    hSnapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

    if (hProcessSnap == (HANDLE)-1)

        return (FALSE);

    //  Fill in the size of the structure before using it.

    pe32.dwSize = sizeof(PROCESSENTRY32);

    //  Walk the snapshot of the processes, and for each process, get

    //  information to display.

    if (pProcess32First(hProcessSnap, &pe32)) {

        BOOL          bGotModule = FALSE;

        MODULEENTRY32 me32       = {0};

        PINFO         pi         = {0};

        do {

            bGotModule = GetProcessModule(pe32.th32ProcessID,

                pe32.th32ModuleID, &me32, sizeof(MODULEENTRY32));

            if (bGotModule) {

                HANDLE hProcess;

                // Get the actual priority class.

                hProcess = OpenProcess (PROCESS_ALL_ACCESS,

                    FALSE, pe32.th32ProcessID);

                pi.dwPriorityClass = GetPriorityClass (hProcess);

                CloseHandle (hProcess);

                // Get the process's base priority value.

                pi.pcPriClassBase = pe32.pcPriClassBase;

                pi.pid            = pe32.th32ProcessID;

                pi.cntThreads     = pe32.cntThreads;

                lstrcpy(pi.szModName, me32.szModule);

                lstrcpy(pi.szFullPath, me32.szExePath);

                AddProcessItem(hListView, pi);

            }

        }

        while (pProcess32Next(hProcessSnap, &pe32));

        bRet = TRUE;

    }

    else

        bRet = FALSE;    // could not walk the list of processes

    // Do not forget to clean up the snapshot object.

    CloseHandle (hProcessSnap);

    return (bRet);

}


Traversing the Thread List

The following function takes a snapshot of the threads currently executing in the system and walks through the list recorded in the snapshot.

// Returns TRUE if the threads were successfully enumerated

//   and listed or FALSE if the threads could not be enumerated

//   or listed.

// hListView  - handle of the listview that lists thread information

// dwOwnerPID - identifier of the process whose threads are to

//   be listed

BOOL RefreshThreadList (HWND hListView, DWORD dwOwnerPID)

{

    HANDLE        hThreadSnap = NULL;

    BOOL          bRet        = FALSE;

    THREADENTRY32 te32        = {0};

    // Take a snapshot of all threads currently in the system.

    hThreadSnap = pCreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);

    if (hThreadSnap == (HANDLE)-1)

        return (FALSE);

    // Clear the current contents of the thread list view

    // (which are now old).

    ListView_DeleteAllItems(g_hwndThread);

    // Fill in the size of the structure before using it.

    te32.dwSize = sizeof(THREADENTRY32);

    // Walk the thread snapshot to find all the threads of the process.

    // If the thread belongs to the process, add its information

    // to the display list.

    if (pThread32First(hThreadSnap, &te32)) {

        do {

            if (te32.th32OwnerProcessID == dwOwnerPID) {

                TINFO ti;

                ti.tid        = te32.th32ThreadID;

                ti.pidOwner   = te32.th32OwnerProcessID;

                ti.tpDeltaPri = te32.tpDeltaPri;

                ti.tpBasePri  = te32.tpBasePri;

                AddThreadItem(hListView, ti);

            }

        }

        while (pThread32Next(hThreadSnap, &te32));

        bRet = TRUE;

    }

    else

        bRet = FALSE;          // could not walk the list of threads

    // Do not forget to clean up the snapshot object.

    CloseHandle (hThreadSnap);

    return (bRet);

}


Traversing the Module List

The following function takes a snapshot of the modules in the address space of a specified Win32 process and retrieves information for a specific module from the list recorded in the snapshot.

// Returns TRUE if there is information about the specified module or

//   FALSE if it could not enumerate the modules in the process or

//   the module is not found in the process.

// dwPID - identifier of the process that owns the module to

//   retrieve information about.

// dwModuleID - tool help identifier of the module within the

//   process

// lpMe32 - structure to return data about the module

// cbMe32 - size of the buffer pointed to by lpMe32 (to ensure

//   the buffer is not over filled)

BOOL GetProcessModule (DWORD dwPID, DWORD dwModuleID,
        LPMODULEENTRY32 lpMe32, DWORD cbMe32)

{

    BOOL          bRet        = FALSE;

    BOOL          bFound      = FALSE;

    HANDLE        hModuleSnap = NULL;

    MODULEENTRY32 me32        = {0};

    // Take a snapshot of all modules in the specified process.

    hModuleSnap = pCreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwPID);

    if (hModuleSnap == (HANDLE)-1)

        return (FALSE);

    // Fill the size of the structure before using it.

    me32.dwSize = sizeof(MODULEENTRY32);

    // Walk the module list of the process, and find the module of

    // interest. Then copy the information to the buffer pointed

    // to by lpMe32 so that it can be returned to the caller.

    if (pModule32First(hModuleSnap, &me32)) {

        do {

            if (me32.th32ModuleID == dwModuleID) {

                CopyMemory (lpMe32, &me32, cbMe32);

                bFound = TRUE;

            }

        }

        while (!bFound && pModule32Next(hModuleSnap, &me32));

        bRet = bFound;   // if this sets bRet to FALSE, dwModuleID

                         // no longer exists in specified process

    }

    else

        bRet = FALSE;           // could not walk module list

    // Do not forget to clean up the snapshot object.

    CloseHandle (hModuleSnap);

    return (bRet);

}


Reference

The following functions and structures are associated with the tool help services.


Functions

The following functions are used with tool help services.


CreateToolhelp32Snapshot [New - Windows 95]
CreateToolhelp32Snapshot

[New - Windows 95]

HANDLE WINAPI CreateToolhelp32Snapshot(DWORD dwFlags,
    DWORD th32ProcessID);

Takes a snapshot of the Win32 processes, heaps, modules, and threads used by the Win32 processes.

•	Returns an open handle to the specified snapshot if successful or  − 1 otherwise.

dwFlags

Flags specifying portions of the system to include in the snapshot. These values are defined:

TH32CS_INHERIT	Indicates that the snapshot handle is to be inheritable.
TH32CS_SNAPALL	Equivalent to specifying the TH32CS_SNAPHEAPLIST, TH32CS_SNAPMODULE, TH32CS_SNAPPROCESS, and TH32CS_SNAPTHREAD values.
TH32CS_SNAPHEAPLIST	Includes the heap list of the specified Win32 process in the snapshot.
TH32CS_SNAPMODULE	Includes the module list of the specified Win32 process in the snapshot.
TH32CS_SNAPPROCESS	Includes the Win32 process list in the snapshot.
TH32CS_SNAPTHREAD	Includes the Win32 thread list in the snapshot.
th32ProcessID

Win32 process identifier. This parameter can be zero to indicate the current process. This parameter is used when the TH32CS_SNAPHEAPLIST or TH32CS_SNAPMODULE value is specified. Otherwise, it is ignored.

The snapshot taken by this function is examined by the other tool help functions to provide their results. Access to the snapshot is read only. The snapshot handle acts like a Win32 object handle and is subject to the same rules regarding which processes and threads it is valid in.

To retrieve an extended error status code generated by this function, use the GetLastError function.

To destroy the snapshot, use the CloseHandle function.


Heap32First [New - Windows 95]
Heap32First

[New - Windows 95]

BOOL WINAPI Heap32First(LPHEAPENTRY32 lphe, DWORD th32ProcessID,
    DWORD th32HeapID);

Retrieves information about the first block of a heap that has been allocated by a Win32 process.

•	Returns TRUE if information for the first heap block has been copied to the buffer or FALSE otherwise. The ERROR_NO_MORE_FILES error value is returned by the GetLastError function if the heap is invalid or empty.

lphe

Address of a buffer containing a HEAPENTRY32 structure.

th32ProcessID

Identifier of the Win32 process context that owns the heap.

th32HeapID

Identifier of the heap to enumerate.

The calling application must set the dwSize member of HEAPENTRY32 to the size, in bytes, of the structure.

To access subsequent blocks of the same heap, use the Heap32Next function.


Heap32ListFirst [New - Windows 95]
Heap32ListFirst

[New - Windows 95]

BOOL WINAPI Heap32ListFirst(HANDLE hSnapshot, LPHEAPLIST32 lphl);

Retrieves information about the first heap that has been allocated by a specified Win32 process.

•	Returns TRUE if the first entry of the heap list has been copied to the buffer or FALSE otherwise. The ERROR_NO_MORE_FILES error value is returned by the GetLastError function when no heap list exists or the snapshot does not contain heap list information.

hSnapshot

Handle of the snapshot returned from a previous call to the CreateToolhelp32Snapshot function.

lphl

Address of a buffer containing a HEAPLIST32 structure.

The calling application must set the dwSize member of HEAPLIST32 to the size, in bytes, of the structure.

To retrieve information about other heaps in the heap list, use the Heap32ListNext function.


Heap32ListNext [New - Windows 95]
Heap32ListNext

[New - Windows 95]

BOOL WINAPI Heap32ListNext(HANDLE hSnapshot, LPHEAPLIST32 lphl);

Retrieves information about the next heap that has been allocated by a Win32 process.

•	Returns TRUE if the next entry of the heap list has been copied to the buffer or FALSE otherwise. The ERROR_NO_MORE_FILES error value is returned by the GetLastError function when no more entries in the heap list exist.

hSnapshot

Handle of the snapshot returned from a previous call to the CreateToolhelp32Snapshot function.

lphl

Address of a buffer containing a HEAPLIST32 structure.

The calling application must set the dwSize member of HEAPLIST32 to the size, in bytes, of the structure.

To retrieve information about the first heap in a heap list, use the Heap32ListFirst function.


Heap32Next [New - Windows 95]
Heap32Next

[New - Windows 95]

BOOL WINAPI Heap32Next(LPHEAPENTRY32 lphe);

Retrieves information about the next block of a heap that has been allocated by a Win32 process.

•	Returns TRUE if information about the next block in the heap has been copied to the buffer or FALSE otherwise. The ERROR_NO_MORE_FILES error value is returned by the GetLastError function when no more objects in the heap exist.

lphe

Address of a buffer containing a HEAPENTRY32 structure.

The calling application must set the dwSize member of HEAPENTRY32 to the size, in bytes, of the structure.

To retrieve information for the first block of a heap, use the Heap32First function.


Module32First [New - Windows 95]
Module32First

[New - Windows 95]

BOOL WINAPI Module32First(HANDLE hSnapshot, LPMODULEENTRY32 lpme);

Retrieves information about the first module associated with a Win32 process.

•	Returns TRUE if the first entry of the module list has been copied to the buffer or FALSE otherwise. The ERROR_NO_MORE_FILES error value is returned by the GetLastError function if no modules exist or the snapshot does not contain module information.

hSnapshot

Handle of the snapshot returned from a previous call to the CreateToolhelp32Snapshot function.

lpme

Address of a buffer containing a MODULEENTRY32 structure.

The calling application must set the dwSize member of MODULEENTRY32 to the size, in bytes, of the structure.

To retrieve information about other modules associated with the specified process, use the Module32Next function.


Module32Next [New - Windows 95]
Module32Next

[New - Windows 95]

BOOL WINAPI Module32Next(HANDLE hSnapshot, LPMODULEENTRY32 lpme);

Retrieves information about the next module associated with a Win32 process or thread.

•	Returns TRUE if the next entry of the module list has been copied to the buffer or FALSE otherwise. The ERROR_NO_MORE_FILES error value is returned by the GetLastError function if no more modules exist.

hSnapshot

Handle of the snapshot returned from a previous call to the CreateToolhelp32Snapshot function.

lpme

Address of a buffer containing a MODULEENTRY32 structure.

The calling application must set the dwSize member of MODULEENTRY32 to the size, in bytes, of the structure.

To retrieve information about first module associated with a Win32 process, use the Module32First function.


Process32First [New - Windows 95]
Process32First

[New - Windows 95]

BOOL WINAPI Process32First(HANDLE hSnapshot, LPPROCESSENTRY32 lppe);

Retrieves information about the first Win32 process encountered in a system snapshot.

•	Returns TRUE if the first entry of the process list has been copied to the buffer or FALSE otherwise. The ERROR_NO_MORE_FILES error value is returned by the GetLastError function if no processes exist or the snapshot does not contain process information.

hSnapshot

Handle of the snapshot returned from a previous call to the CreateToolhelp32Snapshot function.

lppe

Address of a PROCESSENTRY32 structure.

The calling application must set the dwSize member of PROCESSENTRY32 to the size, in bytes, of the structure.

To retrieve information about other processes recorded in the same snapshot, use the Process32Next function.


Process32Next [New - Windows 95]
Process32Next

[New - Windows 95]

BOOL WINAPI Process32Next(HANDLE hSnapshot, LPPROCESSENTRY32 lppe);

Retrieves information about the next Win32 process recorded in a system snapshot.

•	Returns TRUE if the next entry of the process list has been copied to the buffer or FALSE otherwise. The ERROR_NO_MORE_FILES error value is returned by the GetLastError function if no processes exist or the snapshot does not contain process information.

hSnapshot

Handle of the snapshot returned from a previous call to the CreateToolhelp32Snapshot function.

lppe

Address of a PROCESSENTRY32 structure.

The calling application must set the dwSize member of PROCESSENTRY32 to the size, in bytes, of the structure.

To retrieve information about the first process recorded in a snapshot, use the Process32First function.


Thread32First [New - Windows 95]
Thread32First

[New - Windows 95]

BOOL WINAPI Thread32First(HANDLE hSnapshot, LPTHREADENTRY32 lpte);

Retrieves information about the first thread of any Win32 process encountered in a system snapshot.

•	Returns TRUE if the first entry of the thread list has been copied to the buffer or FALSE otherwise. The ERROR_NO_MORE_FILES error value is returned by the GetLastError function if no threads exist or the snapshot does not contain thread information.

hSnapshot

Handle of the snapshot returned from a previous call to the CreateToolhelp32Snapshot function.

lpte

Address of a THREADENTRY32 structure.

The calling application must set the dwSize member of THREADENTRY32 to the size, in bytes, of the structure.

To retrieve information about other threads recorded in the same snapshot, use the Thread32Next function.


Thread32Next [New - Windows 95]
Thread32Next

[New - Windows 95]

BOOL WINAPI Thread32Next(HANDLE hSnapshot, LPTHREADENTRY32 lpte);

Retrieves information about the next thread of any Win32 process encountered in the system memory snapshot.

•	Returns TRUE if the next entry of the thread list has been copied to the buffer or FALSE otherwise. The ERROR_NO_MORE_FILES error value is returned by the GetLastError function if no threads exist or the snapshot does not contain thread information.

hSnapshot

Handle of the snapshot returned from a previous call to the CreateToolhelp32Snapshot function.

lpte

Address of a THREADENTRY32 structure.

The calling application must set the dwSize member of THREADENTRY32 to the size, in bytes, of the structure.

To retrieve information about the first thread recorded in a snapshot, use the Thread32First function.


Toolhelp32ReadProcessMemory [New - Windows 95]
Toolhelp32ReadProcessMemory

[New - Windows 95]

BOOL WINAPI Toolhelp32ReadProcessMemory(DWORD th32ProcessID,
    LPCVOID lpBaseAddress, LPVOID lpBuffer, DWORD cbRead,
    LPDWORD lpNumberOfBytesRead);

Copies memory allocated to another process into an application-supplied buffer.

•	Returns TRUE if successful.

th32ProcessID

Identifier of the Win32 process whose memory is being copied. This parameter can be zero to copy the memory of the current process.

lpBaseAddress

Base address in the specified process to read. Before transferring any data, the system verifies that all data in the base address and memory of the specified size is accessible for read access. If this is the case, the function proceeds. Otherwise, the function fails.

lpBuffer

Address of the buffer that receives the contents of the address space of the specified process.

cbRead

Number of bytes to read from the specified process.

lpNumberOfBytesRead

Number of bytes copied to the specified buffer. If this parameter is NULL, it is ignored.


Structures

The following structures are used with tool help services.


HEAPENTRY32 [New - Windows 95]
HEAPENTRY32

[New - Windows 95]

typedef struct tagHEAPENTRY32

{

    DWORD  dwSize;         // size, in bytes, of structure

    HANDLE hHandle;        // handle of heap block

    DWORD  dwAddress;      // linear address of start of block

    DWORD  dwBlockSize;    // size, in bytes, of heap block

    DWORD  dwFlags;        // see below

    DWORD  dwLockCount;    // see below

    DWORD  dwResvd;        // reserved; do not use

    DWORD  th32ProcessID;  // see below

    DWORD  th32HeapID;     // see below

} HEAPENTRY32;

typedef HEAPENTRY32 *  PHEAPENTRY32;

typedef HEAPENTRY32 *  LPHEAPENTRY32;

Describes one entry (block) of a heap that is being examined.

dwFlags

Flags. These values are defined:

LF32_FIXED	The memory block has a fixed (unmovable) location.
LF32_FREE	The memory block is not used.
LF32_MOVEABLE	The memory block location can be moved.
dwLockCount

Lock count on the memory block. The lock count is incremented each time the GlobalLock or LocalLock function is called on the block either by the application or the DLL that the heap belongs to.

th32ProcessID

Identifier of the Win32 process to examine. The contents of this member can be used by other Win32 functions and macros.

th32HeapID

Heap identifier in the owning process context. The contents of this member has meaning only to the tool help functions. It is not a handle, nor is it usable by other Win32 API elements.


HEAPLIST32 [New - Windows 95]
HEAPLIST32

[New - Windows 95]

typedef struct tagHEAPLIST32 {

    DWORD dwSize;         // size, in bytes, of structure

    DWORD th32ProcessID;  // see below

    DWORD th32HeapID;     // see below

    DWORD dwFlags;        // see below

} HEAPLIST32;

typedef HEAPLIST32 *  PHEAPLIST32;

typedef HEAPLIST32 *  LPHEAPLIST32;

Describes an entry from a list that enumerates the heaps used by a specified process.

th32ProcessID

Identifier of the Win32 process to examine. The contents of this member can be used by other Win32 functions and macros.

th32HeapID

Heap identifier in the owning process context. The contents of this member has meaning only to the tool help functions. It is not a handle, nor is it usable by other Win32 API elements.

dwFlags

Flags. These values are defined:

HF32_DEFAULT	Process's default heap
HF32_SHARED	Shared heap


MODULEENTRY32 [New - Windows 95]
MODULEENTRY32

[New - Windows 95]

typedef struct tagMODULEENTRY32 {

    DWORD   dwSize;         // size, in bytes, of structure

    DWORD   th32ModuleID;   // see below

    DWORD   th32ProcessID;  // see below

    DWORD   GlblcntUsage;   // see below

    DWORD   ProccntUsage;   // see below

    BYTE  * modBaseAddr;    // see below

    DWORD   modBaseSize;    // see below

    HMODULE hModule;        // see below

    char    szModule[MAX_MODULE_NAME32 + 1];

    char    szExePath[MAX_PATH];

} MODULEENTRY32;

typedef MODULEENTRY32 *  PMODULEENTRY32;

typedef MODULEENTRY32 *  LPMODULEENTRY32;

Describes an entry from a list that enumerates the modules used by a specified process.

th32ModuleID

Module identifier in the context of the owning process. The contents of this member has meaning only to the tool help functions. It is not a handle, nor is it usable by other Win32 API elements.

th32ProcessID

Identifier of the Win32 process being examined. The contents of this member can be used by other Win32 functions and macros.

GlblcntUsage

Global usage count on the module.

ProccntUsage

Module usage count in the context of the owning process.

modBaseAddr

Base address of the module in the context of the owning process.

modBaseSize

Size, in bytes, of the module.

hModule

Handle of the module in the context of the owning process.

szModule

String containing the module name.

szExePath

String containing the location (path) of the module.

Note  modBaseAddr and hModule are valid only in the context of the process specified by th32ProcessID.


PROCESSENTRY32 [New - Windows 95]
PROCESSENTRY32

[New - Windows 95]

typedef struct tagPROCESSENTRY32 {

    DWORD dwSize;               // size, in bytes, of structure

    DWORD cntUsage;             // see below

    DWORD th32ProcessID;        // specified process

    DWORD th32DefaultHeapID;    // see below

    DWORD th32ModuleID;         // see below

    DWORD cntThreads;           // see below

    DWORD th32ParentProcessID;  // see below

    LONG  pcPriClassBase;       // see below

    DWORD dwFlags;              // reserved; do not use

    char szExeFile[MAX_PATH];   // see below

} PROCESSENTRY32;

typedef PROCESSENTRY32 *  PPROCESSENTRY32;

typedef PROCESSENTRY32 *  LPPROCESSENTRY32;

Describes an entry from a list that enumerates the processes residing in the system address space when a snapshot was taken.

cntUsage

Number of references to the process. A process exists as long as its usage count is nonzero. As soon as its usage count becomes zero, a process terminates.

th32ProcessID

Identifier of the Win32 process. The contents of this member can be used by other Win32 functions and macros.

th32DefaultHeapID

Identifier of the default heap for the process. The contents of this member has meaning only to the tool help functions. It is not a handle, nor is it usable by other Win32 API elements.

th32ModuleID

Module identifier of the process. The contents of this member has meaning only to the tool help functions. It is not a handle, nor is it usable by other Win32 API elements.

cntThreads

Number of execution threads started by the process.

th32ParentProcessID

Identifier of the Win32 process that created the process being examined. The contents of this member can be used by other Win32 functions and macros.

pcPriClassBase

Base priority of any threads created by this process.

szExeFile

Path and filename of the executable file for the process.


THREADENTRY32 [New - Windows 95]
THREADENTRY32

[New - Windows 95]

typedef struct tagTHREADENTRY32{

    DWORD  dwSize;              // size, in bytes, of structure

    DWORD  cntUsage;            // see below

    DWORD  th32ThreadID;        // see below

    DWORD  th32OwnerProcessID;  // see below

    LONG   tpBasePri;           // see below

    LONG   tpDeltaPri;          // see below

    DWORD  dwFlags;             // reserved; do not use

} THREADENTRY32;

typedef THREADENTRY32 *  PTHREADENTRY32;

typedef THREADENTRY32 *  LPTHREADENTRY32;

Describes an entry from a list that enumerates the threads executing in the system when a snapshot was taken.

cntUsage

Number of references to the thread. A thread exists as long as its usage count is nonzero. As soon as its usage count becomes zero, a thread terminates.

th32ThreadID

Identifier of the thread. The contents of this member has meaning only to the tool help functions. It is not usable by other Win32 API elements.

th32OwnerProcessID

Identifier of the process that created the thread. The contents of this member can be used by other Win32 functions and macros.

tpBasePri

Initial priority level assigned to a thread. These values are defined:

THREAD_PRIORITY_IDLE

Indicates a base priority level of 1 for IDLE_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS, or HIGH_PRIORITY_CLASS processes, and a base priority level of 16 for REALTIME_PRIORITY_CLASS processes.

THREAD_PRIORITY_LOWEST

Indicates 2 points below normal priority for the priority class.

THREAD_PRIORITY_BELOW_NORMAL

Indicates 1 point below normal priority for the priority class.

THREAD_PRIORITY_NORMAL

Indicates normal priority for the priority class.

THREAD_PRIORITY_ABOVE_NORMAL

Indicates 1 point above normal priority for the priority class.

THREAD_PRIORITY_HIGHEST

Indicates 2 points above normal priority for the priority class.

THREAD_PRIORITY_TIME_CRITICAL

Indicates a base priority level of 15 for IDLE_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS, or HIGH_PRIORITY_CLASS processes, and a base priority level of 31 for REALTIME_PRIORITY_CLASS processes.

tpDeltaPri

Change in the priority level of a thread. This value is a signed delta from the base priority level assigned to the thread.

For additional information about thread priority levels, see the documentation included in the Win32 SDK.


MS-DOS Extensions

This article describes various MS-DOS extensions for Windows 95 and provides general information about the file system.


About MS-DOS Extensions

Microsoft® Windows 95® not only supports the complete set of Microsoft® MS-DOS® system functions and interrupts but also provides extensions that permit MS-DOS − based applications to take advantage of Windows 95 features, such as long filenames, exclusive volume locking, virtual machine services, message services, and program information file management. For more information about these topics, see the articles with those names in this guide. For more information about MS-DOS functions and interrupts, see the Microsoft MS-DOS Programmer's Reference.


Windows 95 Version of MS-DOS

When running with Windows 95, MS-DOS − based applications can check the operating system version by using Get MS-DOS Version Number (Interrupt 21h, Function 30h). For Windows 95, this function returns 7 as the major version number and 0 as the minor version number.

If you need to know that the system is running MS-DOS version 7.0, you must use Interrupt 2Fh Function 4A33h. This function returns zero in the AX register for MS-DOS version 7.0 or higher and returns a nonzero value in AX for any other versions of the disk operating system. In addition to the AX register, this function uses the DS, SI, DX, and BX registers.


File System Support

Windows 95 supports the long filename file allocation table (FAT) when running Windows. Any physical file on this extended FAT file system will logically be associated with two names — namely, the primary filename (also referred to as the long filename) and its alternate name or alias. Windows 95 automatically generates the alias, and it is always in the standard 8.3 filename format. When a file is saved to disk, the system creates a directory entry for both the long filename and alias. Because the number of entries in the root directory is limited, it is best to store files in a directory below it to avoid filling up the root. For more information about the filename conventions and how the system generates the alias, see "Long Filenames."


Filename Limitations Under Real Mode

If Windows 95 is started in single MS-DOS application mode (real mode), only the standard FAT file system (and not the long filename FAT file system) is supported. This means that long filenames that are created in a Windows environment will not be visible when the user exits to single MS-DOS application mode, although the names themselves are physically present on the media. Only the alias (the 8.3 filename) will be visible.

When down-level file systems (such as MS-DOS version 6.0, Windows version 3.1, Microsoft® Windows NT™ version 3.1, and OS/2® version 2.11) read a floppy disk that contains long filenames created using Windows 95, the long filename will not be visible; only the alias (the 8.3 filename) will be visible. However, Windows NT version 3.5 supports long filenames. Windows 95 will see the long filenames of files on a floppy disk that were created using Microsoft Windows NT version 3.5, and Windows NT version 3.5 will see the long filenames of files on a floppy disk that were created using Windows 95. Windows 95 will be able to see the long filenames on New Technology file system (NTFS), OS/2's high performance file system (HPFS), or Novell NetWare's file system if there are long filenames on the server.

Because down-level systems are not aware of long filenames, they will not preserve them. If you copy a file from a floppy disk to the hard disk on a down-level system, the long filename associated with the file is not copied over. If you edit a file on the floppy disk using the alias and then save a new copy back on the floppy disk using the down-level system, the long filename associated with the file will most likely be lost. If you take the floppy disk back to the Windows 95 system, only the alias will be associated with the file.


Preserving Filenames

Certain operations, such as copy, backup, and restore, using older versions of utilities that have not been updated to support long filenames will destroy the long filename. Running a utility called LFNBK that comes with Windows 95 before using older backup utilities will preserve the long filenames. Following are the steps for using LFNBK to backup and restore a disk:

1.	Preserve the long filename and alias (the 8.3 filename) association by running LFNBK /b drive-letter, where drive-letter is the drive that you plan to back up.

2.	Back up the drive (specified as drive-letter in the previous step) using an old backup program that is not be aware of long filenames.

3.	Restore the backup files to a drive, when necessary at some later point, using an old restore program that is not be aware of long filenames.

4.	Restore the long filenames on the drive, by running LFNBK /r drive-letter, where drive-letter is the drive where the files were restored to.


Searching Filenames

Searches of filenames apply to both the filename and its alias. The system presents a single unified namespace so that a single physical view of the file is preserved. However, if the result of a search shows only the long filename, it could be confusing to the user. For example, a set of files in a directory might include the following filenames and aliases.

Filename	Alias
LongFileName	LONGFI~1
File-1	FILE-1
A search of files in the directory using DIR *1 would display the following information.

LONGFI~1    123    05-11-95    15:26    LongFileName

FILE-1      352    05-11-95    16:01    File-1

Note that the DIR command displays the alias first for compatibility with the older DIR format. However, a search utility that is aware of long filenames but displays only the filename, would also show both the LongFileName and File-1 files. This could be confusing at first glance to the user because the LongFileName file does not have the number 1 as specified in the search criteria. The file was matched to the search pattern because its alias contains the number 1.

The wildcard searches have been expanded in Windows 95. Using the old search criteria, the first * encountered caused all following characters to be ignored. However, in the preceding example, *1 is a valid specification. More than one wildcard can be used in Windows 95 when specifying search criteria. For example, to search for all files that contain the word mid somewhere in the filename, *mid* can be specified as the search criteria.


Exclusive Volume Locking

Previously reserved fields in the file system directory entry are used for storing the last access date and the creation date and time. A file with a long filename, which is longer than 5 characters, will also cause the system to use previously reserved fields in the directory entry. In previous versions of MS-DOS and Windows, these reserved entries were zero. Older disk repair and checking utilities that have not been updated for Windows 95 might display errors about the disk because of the usage of these reserved entries. It is possible that an older disk repair utility could either destroy the long filename or the actual data in a file because it would mistakenly interpret the file as corrupted. For this reason, Windows 95 is designed to fail utilities that perform direct disk writes. This feature is called exclusive volume locking. A newer version of the utility that understands the newer on-disk file system structures will obtain an exclusive volume lock and proceed correctly.

Exclusive volume locking is also needed because the system is a multitasking system and disk utilities need exclusive access so that they can modify the file system without causing the file system to be inconsistent for the other executing applications. For more information, see "Exclusive Volume Locking."


Storing Filenames

When an application stores filenames, it should follow these guidelines:

•	Using an alias instead of a long filename can break the association with the file because certain operations, such as editing the file, can potentially change the alias. For example, if the server side of a network uses the alias instead of the long filename of a client file to store information related to the file (such as access permissions), it will be more susceptible to lose the association of permissions with the file. If the user edits the file on the client side, the alias may potentially change, and if it changes, the server side will lose the associated information.

•	When an application caches the absolute path to a filename, the path itself can be a mixture of filenames and aliases. Because of this, applications that need to store a path should store a canonical form of the absolute path. Applications may use either Get Short Path Name (Interrupt 21h Function 7160h) or the Microsoft® Win32® GetShortPathName function to retrieve the canonical form of a path. Applications that need to determine if two files are the same can use the nFileIndexHigh and nFileIndexLow members of the BY_HANDLE_FILE_INFORMATION structure. Note, however, that nFileIndexHigh and nFileIndexLow might not be supported on real-mode file systems, such as Microsoft CD-ROM Extensions (MSCDEX), or real-mode networks.

•	An installation program that needs to enter information into configuration files, such as CONFIG.SYS, should make sure it uses paths that only consist of 8.3 filename components, because the long filenames will not be visible at boot up time when startup files, such as CONFIG.SYS and AUTOEXEC.BAT, are processed. Again, the GetShortPathName function should be used for this purpose.


Filename Functions

With the exception of the OpenFile function, all of the functions in Windows version 3. x that require the application to pass in a filename (such as LoadLibrary, WinExec, _lopen, and _lcreate) have been updated to support long filenames. For compatibility reasons, functions that return filenames should return only aliases (8.3 filenames) to 16-bit Windows − based applications marked less than 4.0.

MS-DOS − based applications generally use the Interrupt 21h functions. Except for Extended Open/Create (Interrupt 21h Function 6Ch), the older Interrupt 21h functions have not changed in Windows 95. Extended Open/Create has been enhanced in Windows 95 to make use of the last access date for a file. To support long filenames, Windows 95 provides many new Interrupt 21h functions. Any MS-DOS − based application that will use long filenames must be updated to support the new functions. For information about the long filename Interrupt 21h functions, see "Long Filenames."

Windows 95 supports the new Interrupt 21h long filename functions on as many file systems as possible. On file systems, such as MSCDEX, Flash, and real-mode network redirectors, that do not support long filenames, the system automatically translates the newer Interrupt 21h calls to the appropriate older Interrupt 21h calls, as long as the filename passed as a parameter is a valid alias (8.3 filename). Applications may use Get Volume Information (Interrupt 21h Function 71A0h) to retrieve information on the capabilities of the underlying file system.


Command Interpreter for Command

The for command in the command interpreter (COMMAND.COM) is modal. The default is LFNFOR=OFF, which causes the for command to use the old Interrupt 21h function calls. In that case, only aliases (8.3 filenames) can be used in the for command. If LFNFOR=ON is set, the for command uses the new Interrupt 21h functions, and long filenames can be used as part of the for command.


Long Command Lines

Although in previous versions of MS-DOS the limit for environment variables and batch file lines is 128 characters, it is 1024 characters in Windows 95. The limit for the keyboard buffer, however, is still 128 characters. Although 1024 and 128 are the standard limits, users may configure their systems to lower these limits.

In previous versions of MS-DOS, command-line arguments are located in the command tail of the program segment prefix (PSP). The command tail in the PSP is limited to 128 characters, including the leading byte that specifies the length of the command line and the trailing carriage return character. In Windows 95, if the command line is less than or equal to 126 characters, it is set in the command tail of the PSP. For command lines that are greater than 126 characters, an application should follow these steps:

1.	Set the count byte in the command tail to 7Fh.

2.	Fill in 7Eh bytes of the command tail followed by the carriage return character (0Dh).

3.	Place the rest of the command line in the CMDLINE environment variable.


Reference

This section provides information about the following functions and structures.

Get Compressed File Size	Interrupt 21h Function 4302h
Lock/Unlock Removable Media	Interrupt 21h Function 440Dh Minor Code 48h
Eject Removable Media	Interrupt 21h Function 440Dh Minor Code 49h
Get Drive Map Info	Interrupt 21h Function 440Dh Minor Code 6Fh
Get First Cluster	Interrupt 21h Function 440Dh Minor Code 71h
Extended Open/Create	Interrupt 21h Function 6Ch
DRIVE_MAP_INFO	Get Drive Map Info returns information about the specified drive in this structure.
MID	This structure, which is used by Get Media ID (Interrupt 21h Function 440Dh Minor Code 66h) and Set Media ID (Interrupt 21h Function 440Dh Minor Code 46h), has been updated to support compact disc (CD) file systems. For information about using these functions, see the Microsoft MS-DOS Programmer's Reference.
PARAMBLOCK	This structure is needed by Lock/Unlock Removable Media.


Functions

The following functions are used with MS-DOS extensions.


Interrupt 21h Function 4302h Get Compressed File Size [New - Windows 95]
Interrupt 21h Function 4302h Get Compressed File Size

[New - Windows 95]

mov ax, 4302h            ; Get Compressed File Size
mov dx, seg PathName     ; see below
mov ds, dx
mov dx, offset PathName
int 21h

jc error

Obtains the compressed size, in bytes, of a given file or directory.

•	Clears the carry flag if successful. Otherwise, the function sets the carry flag and sets the AX register to an error value.

PathName

Address of a null-terminated string that specifies the file or directory to retrieve the file size for.

The function obtains the actual number of bytes of disk storage used to store the file. If the file is located on a volume that supports compression and the file is compressed, the value obtained is the compressed size of the specified file. If the file is not located on a volume that supports compression or if the file is not compressed, the value obtained is the file size, in bytes, rounded up to the nearest cluster boundary.


Interrupt 21h Function 440Dh Minor Code 48h  Lock/Unlock Removable Media [New - Windows 95]
Interrupt 21h Function 440Dh Minor Code 48h  Lock/Unlock Removable Media

[New - Windows 95]

mov ax, 440Dh           ; generic IOCTL
mov bx, DriveNum        ; see below
mov ch, 8               ; device category
mov cl, 48h             ; Lock or Unlock Removable Media
mov dx, seg ParamBlock  ; see below
mov ds, dx
mov dx, offset ParamBlock
int 21h

jc  error

Locks or unlocks the volume in the given drive (preventing or permitting its removal) or returns the locked status of the given drive.

•	Clears the carry flag and copies the number of pending locks on the given drive to the NumLocks member of the PARAMBLOCK structure if successful. Otherwise, the function sets the carry flag and sets the AX register to one of the following error values:

01h	The function is not supported.
B0h	The volume is not locked in the drive.
B2h	The volume is not removable.
B4h	The lock count has been exceeded.
DriveNum

Drive to lock or unlock. This parameter can be 0 for default drive, 1 for A, 2 for B, and so on.

ParamBlock

Address of a PARAMBLOCK structure that specifies the operation to carry out and receives a count of the number of locks on the drive.


Interrupt 21h Function 440Dh Minor Code 49h  Eject Removable Media [New - Windows 95]
Interrupt 21h Function 440Dh Minor Code 49h  Eject Removable Media

[New - Windows 95]

mov ax, 440Dh     ; generic IOCTL
mov bx, DriveNum  ; see below
mov ch, 8         ; device category
mov cl, 49h       ; Eject Removable Media
int 21h

jc  error

Ejects the specified media.

•	Clears the carry flag if successful. Otherwise, the function sets the carry flag and sets the AX register to one of the following error values:

01h	The function is not supported.
B1h	The volume is locked in the drive.
B2h	The volume is not removable.
B5h	The valid eject request has failed.
DriveNum

Drive to eject. This parameter can be 0 for default drive, 1 for A, 2 for B, and so on.

If a given physical drive has more than one logical volume, all volumes must be unlocked by using Lock/Unlock Removable Media (Interrupt 21h Function 440Dh Minor Code 48h) before the drive will eject.


Interrupt 21h Function 440Dh Minor Code 6Fh  Get Drive Map Info [New - Windows 95]
Interrupt 21h Function 440Dh Minor Code 6Fh  Get Drive Map Info

[New - Windows 95]

mov ax, 440Dh            ; generic IOCTL
mov bx, DriveNum         ; see below
mov ch, 8                ; device category
mov cl, 6Fh              ; Get Drive Map Info
mov dx, seg DriveMapInfo ; see below
mov ds, dx
mov dx, offset DriveMapInfo
int 21h

jc  error

Retrieves information about the specified drive.

DriveNum

Drive to obtain information about. This parameter can be 0 for the default drive, 1 for A, 2 for B, and so on.

DriveMapInfo

Address of the DRIVE_MAP_INFO structure that receives information about the specified drive.


Interrupt 21h Function 440Dh Minor Code 71h  Get First Cluster [New - Windows 95]
Interrupt 21h Function 440Dh Minor Code 71h  Get First Cluster

[New - Windows 95]

mov ax, 440Dh            ; generic IOCTL
mov bx, CharSet          ; see below
mov ch, 08h              ; device category
mov cl, 71h              ; Get First Cluster
mov dx, seg PathName     ; see below

mov ds, dx
mov dx, offset PathName
int 21h

jc error

Retrieves the first cluster of the specified file or directory.

•	Clears the carry flag and sets DX:AX to the first cluster number if successful. Otherwise, the function sets the carry flag and returns either the ERROR_INVALID_FUNCTION or ERROR_ACCESS_DENIED value in AX.

CharSet

Character set of PathName. This parameter must be one of these values:

BCS_WANSI (0)	Windows ANSI character set
BCS_OEM (1)	Current OEM character set
BCS_UNICODE (2)	Unicode character set
PathName

Address of a null-terminated string containing the path of the file or directory to retrieve the first cluster for.

The first cluster of a file is the first cluster of the FAT cluster chain describing the data associated with the file. The first cluster of a directory is the first cluster of the FAT cluster chain associated with the directory. It is the cluster that contains the "." and ".." entries. The function finds any file or directory regardless of attribute (system, hidden, or read-only). It does not find volume labels.

If your application is unable to accommodate a 32-bit cluster number, you must check to see if the value returned in the DX register is greater than zero.

if(MAKELONG(regAX,regDX) > 0x0000FFF8)
    b32BitNum = TRUE;
else
    b32BitNum = FALSE;

It is the calling application's responsibility to check to see if the returned cluster number is valid.

if((MAKELONG(regAX,regDX) < 2L) || (MAKELONG(regAX,regDX) > maxClus))
    bInvalidNum = TRUE;
else
    bInvalidNum = FALSE;

In the preceding example, the maxClus variable is the maximum legal cluster number, as a DWORD type, computed from the drive parameters.


Interrupt 21h Function 6Ch  Extended Open/Create [New - Windows 95]
Interrupt 21h Function 6Ch  Extended Open/Create

[New - Windows 95]

mov ah, 6Ch             ; Extended Open/Create
mov bx, ModeAndFlags    ; see below
mov cx, Attributes      ; see below
mov dx, Action          ; action to take
mov si, seg Filename    ; see below
mov ds, si
mov si, offset Filename
int 21h

jc error
mov [Handle], ax        ; file handle
mov [ActionTaken], cx   ; action taken to open file

Opens or creates a file having the given name and attributes.

•	Clears the carry flag, copies the file handle to the AX register, and sets CX to one of the following values if successful:

ACTION_OPENED (0001h)

ACTION_CREATED_OPENED (0002h)

ACTION_REPLACED_OPENED (0003h)

Otherwise, this function sets the carry flag and sets the AX register to one of the following error values:

ERROR_INVALID_FUNCTION (0001h)

ERROR_FILE_NOT_FOUND (0002h)

ERROR_PATH_NOT_FOUND (0003h)

ERROR_TOO_MANY_OPEN_FILES (0004h)

ERROR_ACCESS_DENIED (0005h)

ModeAndFlags

Combination of access mode, sharing mode, and open flags. This parameter can be one value each from the access and sharing modes and any combination of open flags:

Access mode	Meaning
OPEN_ACCESS_READONLY (0000h)
	Opens the file for reading only.
OPEN_ACCESS_WRITEONLY (0001h)
	Opens the file for writing only.
OPEN_ACCESS_READWRITE (0002h)
	Opens the file for reading and writing.
0003h
	Reserved; do not use.
OPEN_ACCESS_RO_NOMODLASTACCESS (0004h)
	Opens the file for reading only without modifying the file's last access date.
Sharing mode	Meaning
OPEN_SHARE_COMPATIBLE (0000h)
	Opens the file with compatibility mode, allowing any process on a given computer to open the file any number of times.
OPEN_SHARE_DENYREADWRITE (0010h)
	Opens the file and denies both read and write access to other processes.
OPEN_SHARE_DENYWRITE (0020h)
	Opens the file and denies write access to other processes.
OPEN_SHARE_DENYREAD (0030h)
	Opens the file and denies read access to other processes.
OPEN_SHARE_DENYNONE (0040h)
	Opens the file without denying read or write access to other processes, but no process may open the file with compatibility mode.
Open flags	Meaning
OPEN_FLAGS_NOINHERIT (0080h)
	If this flag is set, a child process created with Load and Execute Program (Interrupt 21h Function 4B00h) does not inherit the file handle. If the handle is needed by the child process, the parent process must pass the handle value to the child process. If this flag is not set, child processes inherit the file handle.
OPEN_FLAGS_NOCRITERR (2000h)
	If a critical error occurs while MS-DOS is opening this file, Critical-Error Handler (Interrupt 24h) is not called. Instead, MS-DOS simply returns an error value to the program.
OPEN_FLAGS_COMMIT (4000h)
	After each write operation, MS-DOS commits the file (flushes the contents of the cache buffer to disk).
Attributes

Attributes for files that are created or truncated. This parameter may be a combination of these values:

FILE_ATTRIBUTE_NORMAL (0000h)
	The file can be read from or written to. This value is valid only if used alone.
FILE_ATTRIBUTE_READONLY (0001h)
	The file can be read from, but not written to.
FILE_ATTRIBUTE_HIDDEN (0002h)
	The file is hidden and does not appear in an ordinary directory listing.
FILE_ATTRIBUTE_SYSTEM (0004h)
	The file is part of the operating system or is used exclusively by it.
FILE_ATTRIBUTE_VOLUME (0008h)
	The name specified by Filename is used as the volume label for the current medium.
FILE_ATTRIBUTE_ARCHIVE (0020h)
	The file is an archive file. Applications use this value to mark files for backup or removal.
Action

Action to take it the file exists or does not exist. This parameter can be a combination of these values:

FILE_CREATE (0010h)	Creates a new file if it does not already exist or fails if the file already exists.
FILE_OPEN (0001h)	Opens the file. The function fails if the file does not exist.
FILE_TRUNCATE (0002h)	Opens the file and truncates it to zero length (replaces the existing file). The function fails if the file does not exist.
The only valid combinations are FILE_CREATE combined with FILE_OPEN or FILE_CREATE combined with FILE_TRUNCATE.

Filename

Address of a null-terminated string specifying the name of the file to be opened or created. The name must be in the standard MS-DOS 8.3 filename format. The string must be a valid path for the volume associated with the given drive.

This function does not support long filenames. If the specified name is too long, this function truncates the name to the standard 8.3 format following the same naming scheme that the system uses when creating an alias for a long filename.

A file on a remote directory — that is, a directory on the network — cannot be opened, unless appropriate permissions for the directory exist.


Structures

The following structures are used with MS-DOS extensions.


DRIVE_MAP_INFO [New - Windows 95]
DRIVE_MAP_INFO

[New - Windows 95]

DRIVE_MAP_INFO	struc

    dmiAllocationLength   db ?  ; see below
    dmiInfoLength         db ?  ; see below
    dmiFlags              db ?  ; see below
    dmiInt13Unit          db ?  ; see below
    dmiAssociatedDriveMap dd ?  ; see below
    dmiPartitionStartRBA  dq ?  ; see below
DRIVE_MAP_INFO	ends

Contains information about the drive specified in the call to Get Drive Map Info (Interrupt 2lh Function 440Dh Minor Code 6Fh).

dmiAllocationLength

Length of the buffer provided by the application calling Get Drive Map Info. This value should be the size of the DRIVE_MAP_INFO structure.

dmiInfoLength

Number of bytes that Get Drive Map Info used in the buffer provided by the calling application. Typically, this value is the size of the DRIVE_MAP_INFO structure.

dmiFlags

Flags describing the given drive. This member, which is filled by Get Drive Map Info, can be a combination of these values:

PROT_MODE_LOGICAL_DRIVE (01h)	A protected-mode driver is in use for this logical drive.
PROT_MODE_PHYSICAL_DRIVE (02h)	A protected-mode driver is in use for the physical drive corresponding to this logical drive.
PROT_MODE_ONLY_DRIVE (04h)	The drive is not available when running with MS-DOS.
PROT_MODE_EJECT (08h)	A protected-mode drive supports an electronic eject operation.
PROT_MODE_ASYNC_NOTIFY (10h)	The drive issues media arrival and removal notifications. This value is currently used for CD-ROM drives that are controlled by the protected-mode driver and that cause a broadcast message when media is removed or inserted without the application having to make a request to the drive. It can also be used by disk drivers.
dmiInt13Unit

Physical drive number of the given drive. This member, which is filled by Get Drive Map Info, can be one of these values:

00 - 7Fh	Floppy disk drive (00 for the first floppy drive, 01 for the second, and so on).
80 - FEh	Hard disk drive (80 for the first hard disk drive, 81 for the second, and so on).
FFh	The given drive does not map to a physical drive.
dmiAssociatedDriveMap

Logical drive numbers that are associated with the given physical drive. For example, a host drive C with child drive letters A and B would return with bits 0 and 1 set.

dmiPartitionStartRBA

Relative block address offset from the start of the physical volume to the start of the given partition.

Before an application makes a call to Get Drive Map Info, the dmiAllocationLength member must be set to the size of the DRIVE_MAP_INFO structure. All other members of the structure are filled in by Get Drive Map Info.


MID [New - Windows 95]
MID

[New - Windows 95]

MID struc
    midInfoLevel   dw 0           ; see below
    midSerialNum   dd ?           ; see below
    midVolLabel    db 11 dup (?)  ; see below
    midFileSysType db 8 dup (?)   ; see below
MID ends

Contains information that uniquely identifies a disk or other storage medium.

midInfoLevel

Information level. This member must be zero.

midSerialNum

Serial number for the medium.

midVolLabel

Volume label for the medium. If the label has fewer than 11 characters, space characters (ASCII 20h) fill the remaining bytes in this member.

midFileSysType

Type of file system as an 8-byte ASCII string. This member can be one of these values:

FAT12	12-bit file allocation table (FAT)
FAT16	16-bit FAT
CDROM	High Sierra file system
CD001	ISO9660 file system
CDAUDIO	Audio disk
If the name has fewer than eight characters, space characters (ASCII 20h) fill the remaining bytes in this member.


PARAMBLOCK [New - Windows 95]
PARAMBLOCK

[New - Windows 95]

PARAMBLOCK struc
    Operation db ?  ; see below
    NumLocks  db ?  ; see below
PARAMBLOCK ends

Contains information about locked drives.

Operation

Operation to carry out provided by the calling application of Lock/Unlock Removable Media (Interrupt 21h Function 440Dh Minor Code 48h). This member can be one of these values:

0	Locks the volume in the drive.
1	Unlocks the volume in the drive.
2	Returns the lock or unlock status.
All other values are reserved.

NumLocks

Number of locks pending on the given drive filled in by Lock/Unlock Removable Media.


Long Filenames

Microsoft® Windows® 95 allows users and applications to create and use long names for their files and directories. A long filename is a name for a file or directory that exceeds the standard 8.3 filename format.


About Long Filenames

In the past, long filenames typically appeared on network servers that used file systems other than the Microsoft® MS-DOS® file allocation table (FAT) file system. In Windows 95, however, long filenames are available for use with network servers and with local disk drives supporting the protected-mode FAT file system.

This article describes the long filename functions and explains how to create and use long filenames in applications written for MS-DOS and 16-bit Windows version 3. x. Microsoft® Win32®-based applications automatically have access to long filenames through the use of the corresponding Win32 file management functions.


Long Filenames and the Protected-Mode FAT File System

The protected-mode FAT file system is the default file system used by Windows 95 for mass storage devices, such as hard disk and floppy disk drives. Protected-mode FAT is compatible with the MS-DOS FAT file system, using file allocation tables and directory entries to store information about the contents of a disk drive. Protected-mode FAT also supports long filenames, storing these names as well as the date and time that the file was created and the date that the file was last accessed in the FAT file system structures.

The protected-mode FAT file system allows filenames of up to 256 characters, including the terminating null character. In this regard, it is similar to the Microsoft® Windows NT™ file system (NTFS), which allows filenames of up to 256 characters. Protected-mode FAT allows directory paths (excluding the filename) of up to 246 characters, including the drive letter, colon, and leading backslash. This limit of 246 allows for the addition of a filename in the standard 8.3 format with the terminating null character. The maximum number of characters in a full path, including the drive letter, colon, leading backslash, filename, and terminating null character, is 260.

When an application creates a file or directory that has a long filename, the system automatically generates a corresponding alias for that file or directory using the standard 8.3 format. The characters used in the alias are the same characters that are available for use in MS-DOS file and directory names. Valid characters for the alias are any combination of letters, digits, or characters with ASCII codes greater than 127, the space character (ASCII 20h), as well as any of the following special characters.

$ % ' - _ @   ~ ` ! ( ) { } ^ # &

The space character has been available to applications for filenames and directory names through the functions in current and earlier versions of MS-DOS. However, many applications do not recognize the space character as a valid character, and the system does not use the space character when it generates an alias for a long filename. MS-DOS does not distinguish between uppercase and lowercase letters in filenames and directory names, and this is also true for aliases.

The set of valid characters for long filenames includes all the characters that are valid for an alias as well as the following additional characters.

+ , ; = [ ]

Windows 95 preserves the case of the letters used in long filenames. However, the protected-mode FAT file system, which is not case sensitive, will not allow more than one file to have the same name except for case in the same directory. For example, files named Long File Name and long file name are not allowed to exist in the same directory. Although extended ASCII characters (characters with ASCII codes greater than 127) are also permitted in filenames, programs should avoid them, because the meanings of the extended characters may vary according to code page. On disk, the characters in the alias are stored using the OEM character set of the current code page, and the long filename is stored using Unicode format.

Although the protected-mode FAT file system is the default file system in Windows 95, it is not the only file system accessible to applications running with Windows 95. For example, applications that connect to network drives may encounter other file systems, such as NTFS. Before using long filenames for files and directories on a volume in a given drive, you must determine the maximum lengths of filenames and paths by using Get Volume Information (Interrupt 21h Function 71A0h). The function returns values that you can use to make sure your filenames and paths are within the limits of the file system.

In general, you should avoid using static buffers for filenames and paths. Instead, you should use the values returned by Get Volume Information to allocate buffers as you need them. If you must use static buffers, you should reserve 256 characters for filenames and 260 characters for paths. These are the maximum sizes currently recommended for Win32-based applications.


Filename Aliases

When an application creates a file or directory that has a long filename, the system automatically generates a corresponding short filename (alias) for that file or directory, using the standard 8.3 format. Aliases ensure that existing applications that do not handle long filenames can, nevertheless, access those files and directories.

If the long filename follows the standard 8.3 format, the alias has the same name except that all lowercase letters are converted to uppercase. For example, if the long filename is Examples.Txt, the corresponding alias will be EXAMPLES.TXT.

If the long filename does not follow the standard 8.3 format, the system automatically generates an alias, using the following scheme to ensure that the alias has a unique name. The system tries to create a name by using the first 6 characters of the long filename followed by a numeric tail. A numeric tail consists of the tilde (~) character followed by a number. The system starts with the number 1 in the numeric tail. If that filename already exists, it uses the number 2. It continues in this fashion until a unique name is found. If the long filename has a filename extension, the system will use the first three characters of the long filename's extension as the extension for the alias.

As the number of digits in the numeric tail grows, fewer characters in the long filename are used for the 8 characters in the alias. For example, the alias for Long File Name.File would be LONGFI~10.FIL if the names LONGFI~1.FIL through LONGFI~9.FIL already existed in the directory. Applications can override the default alias numbering scheme when creating a file by specifying the OPEN_FLAGS_ALIAS_HINT value and supplying a number to use in the call to Create or Open File (Interrupt 21h Function 716Ch).

A period is just another character in a long filename. Leading periods are allowed in a long filename, but trailing periods are stripped. A file can have multiple periods as part of its name. For example, MyFile.081293.Document is a valid filename, and its alias will be MYFILE~1.DOC. The first three characters after the last period in the filename are used as the filename extension for the alias, as long as the last period is not a leading period. A filename of .login is also valid, and its alias is LOGIN~1.

In a given directory, the long filename and its alias must uniquely identify a file. For example, if there is a file with the long filename Long File Name and the alias LONGFI~1, the system will not allow either Long File Name or LONGFI~1 to be used as another file's long filename.

If a file with a long filename is copied or edited, the alias for the resulting file may be different from the original alias. For example, if the destination directory contains an alias that conflicts with the original alias, the system generates another unique alias. If a long filename LongFileName is associated with the alias LONGFI~2 and is later copied to a different directory using the long filename, the alias in the destination directory might be LONGFI~1 (unless a file with that name already existed in the destination directory). The system always generates new aliases during these operations and always chooses aliases that do not conflict with existing filenames. An application must never rely on an alias being the same for all copies and versions of a given file.

Applications can open, read, and write from a file using the alias without affecting the long filename. However, some operations on the alias, such as copy, move, backup, and restore, may result in the original long filename being destroyed. For example, older versions of utilities that do not support long filenames can destroy the long filename while performing those operations.

The system attempts to preserve a long filename, even when the file associated with it is edited by an application that is not aware of long filenames. Typically, these applications operate on a temporary copy of the file, and when the user elects to save the file, the application deletes the destination file or renames it to another name. The application then renames the temporary file to the destination name or creates a new file with new contents.

When an application makes a system call to delete or rename an alias, the system first gathers and saves a packet of information about the file and then performs the delete or rename operation. The information saved includes the long filename as well as the creation date and time, the last modification date and time, and the last access date of the original file. After the system performs the delete or rename operation, the system watches for a short period of time (the default is 15 seconds) to see if a call is made to create or rename a file with the same name. If the system detects a create or rename operation of a recently deleted alias, it applies the packet of information that it had saved to the new file, thus preserving the long filename.

Currently, Load and Execute Program (Interrupt 21h Function 4B00h) does not accept long filenames. If an application starts other applications, it must retrieve the filename alias for the given executable file and pass that alias to Load and Execute Program.


File and Directory Management

The standard MS-DOS file and directory management functions do not accept long filenames. You must, therefore, use the long filename functions to create and manage files and directories having long names. The long filename functions are similar to existing MS-DOS system functions. You copy function parameters to registers and issue an Interrupt 21h instruction to carry out the call. The function sets or clears the carry flag to indicate whether the operation was successful and may also return information in registers.

If a long filename function has a corresponding MS-DOS function, the number that identifies the long filename function is four digits long, beginning with the number 71 and ending in the same number as the corresponding MS-DOS function. For example, the long filename function Make Directory (Interrupt 21h Function 7139h) corresponds to MS-DOS Create Directory (Interrupt 21h Function 39h).

You can create or open a file having a long filename by using Create or Open File (Interrupt 21h Function 716Ch). This function takes the name and attributes of the file to create or open and returns a handle that you use to identify the file in subsequent calls to standard MS-DOS functions, such as Read File or Device (Interrupt 21h Function 3Fh) and Write File or Device (Interrupt 21h Function 40h).

You can set or retrieve the time and attributes for a file having a long filename by using Get or Set File Time (Interrupt 21h Function 57h) and Get or Set File Attributes (Interrupt 21h Function 7143h). You can move a file having a long filename by using Rename File (Interrupt 21h Function 7156h) or delete the file by using Delete File (Interrupt 21h Function 7141h).

You can create a directory having a long filename by using Make Directory (Interrupt 21h Function 7139h) or remove the directory by using Remove Directory (Interrupt 21h Function 713Ah).

You can set and retrieve the current directory by using Change Directory (Interrupt 21h Function 713Bh) and Get Current Directory (Interrupt 21h Function 7147h).


File Searches

You can search directories for selected files by using Find First File and Find Next File (Interrupt 21h Functions 714Eh and 714Fh). These functions search for and return information about files having long filenames and aliases (filenames in the standard 8.3 format). The functions return information in a WIN32_FIND_DATA structure, which contains both the filename and the corresponding alias, if any.

Unlike MS-DOS Find First File (Interrupt 21h Function 4Eh), the long filename version of Find First File allocates internal storage for the search operations and returns a handle that identifies the storage. This handle is used with Find Next File. To make sure the internal storage is freed, you must use Find Close (Interrupt 21h Function 71A1h) to end the search.

You pass the Delete File (Interrupt 21h Function 7141h) and Find First File functions a filename, which may contain wildcard characters, such as an asterisk (*) or question mark (?). Because Find First File, Find Next File, and Delete File examine long filenames and aliases during the search, some wildcard searches may yield unexpected results. For example, if the system has generated the alias LONGFI~1 for the long filename LongFileName, a search for names that match the *1 pattern would always return the LongFileName file, even though that name does not end with a 1. Searches are not case-sensitive. For example, a search for names that match the *mid* pattern will yield the same results as that for the *MID* pattern. In general, you should check both names returned in the WIN32_FIND_DATA structure to determine which of them matched the pattern.

Wildcard searches are more flexible in Windows 95 than in MS-DOS. In the preceding examples, *1 finds the filenames that end in a 1 and *mid* finds filenames that contain the characters mid. In MS-DOS and in Windows 95 searching on real-mode FAT directories, all characters after the first * are ignored.


Down-Level Systems

Long filenames, file last access date, and file creation date and time are not supported while the file system is in single MS-DOS application mode. They are not supported either in versions of MS-DOS that only use the real-mode FAT file system. These file systems and others that do not support long filenames are referred to as down-level systems. If you intend for an application to run with both Windows 95 and down-level systems, you should always check the system to determine whether it supports the long filename functions. The easiest way to check is to call Get Volume Information (Interrupt 21h Function 71A0h). This function returns an error if the system does not support the long filename functions.

Another way of handling down-level systems is to use a combination of calls to long filename and standard MS-DOS functions to carry out file management. In this case, you call the standard function only if the long filename function is not supported. To indicate an unsupported function, the system sets the AL register to zero but leaves the AH register and the carry flag unchanged. The following example shows how to combine long filename and standard functions to carry out a file or directory management operation.

stc            ; set carry for error flag
               ; set registers here for LFN function call
int 21h        ; call long filename function
jnc success    ; call succeeded, continue processing
cmp ax, 7100h  ; is call really not supported?
jne failure    ; supported, but error occurred
               ; set registers here for MS-DOS function call
int 21h        ; call standard MS-DOS function

Application developers have to decide what to do when users save a file with a long filename to a down-level system. One approach is to imitate the behavior of the command interpreter (COMMAND.COM) and save the file using the alias without informing the user. A different approach is to have the application inform the user that the file system does not support long filenames and allow the user to save the file with a filename in the standard 8.3 format.


Last Access Date

The Windows 95 last access date is intended to reflect the last time a file was accessed for the purpose for which it was created. This date is intended to provide a means for applications, users, or both to determine which files have not been used recently. When an application saves a file, the system automatically resets the last access date. An application that cannot understand the contents of the files it is accessing should save the last access date and restore it after closing the file. For example, applications that back up a file, search files for strings, and scan for viruses should save and restore the last access date.

Applications should allow the system to set the last access date in the following cases:

•	Running a program should set the last access date for the .EXE file.

•	Loading a dynamic-link library (DLL) should set the last access date for the .DLL file.

•	Editing or printing a document should set the last access date for the document file.

•	In general, any use of a document by an application that creates or modifies that type of document should set the last access date (unless the document is being opened only to decide whether it is to be used in a find operation).

•	Application use of peripheral files (.INI files and so on) should set the last access date.

Win32-based applications can preserve the last access date by using the GetFileTime and SetFileTime functions. Applications written for MS-DOS or Windows version 3. x can use Get Last Access Date and Time (Interrupt 21h Function 5704h) and Set Last Access Date and Time (Interrupt 21h Function 5705h), or they can open the file with Create or Open File (Interrupt 21h Function 716Ch) using the OPEN_ACCESS_RO_NOMODLASTACCESS (0004h) access mode.


Reference

The long filename functions described previously match the following Win32 file management functions.

Long filename function	Win32 function
Interrupt 21h Function 5704h Get Last Access Date and Time	GetFileTime
Interrupt 21h Function 5705h Set Last Access Date and Time	SetFileTime
Interrupt 21h Function 5706h Get Creation Date and Time	GetFileTime
Interrupt 21h Function 5707h Set Creation Date and Time	SetFileTime
Interrupt 21h Function 7139h Make Directory	CreateDirectory
Interrupt 21h Function 713Ah Remove Directory	RemoveDirectory
Interrupt 21h Function 713Bh Change Directory	SetCurrentDirectory
Interrupt 21h Function 7141h Delete File	DeleteFile
Interrupt 21h Function 7143h Get or Set File Attributes	GetFileAttributes, SetFileAttributes
Interrupt 21h Function 7147h Get Current Directory	GetCurrentDirectory
Interrupt 21h Function 714Eh Find First File	FindFirstFile
Interrupt 21h Function 714Fh Find Next File	FindNextFile
Interrupt 21h Function 7156h Rename File	MoveFile
Interrupt 21h Function 7160h Get Full Path Name	GetFullPathName
Interrupt 21h Function 7160h Get Short Path Name	GetShortPathName
Interrupt 21h Function 7160h Get Long Path Name	No Win32 function equivalent.
Interrupt 21h Function 716Ch Create or Open File	CreateFile, OpenFile
Interrupt 21h Function 71A0h Get Volume Information	GetVolumeInformation
Interrupt 21h Function 71A1h Find Close	FindClose
Interrupt 21h Function 71A6h Get File Info By Handle	GetFileInformationByHandle
Interrupt 21h Function 71A7h  File Time To DOS Time	FileTimeToDOSDateTime
Interrupt 21h Function 71A7h  DOS Time To File Time	DOSDateTimeToFileTime
Interrupt 21h Function 71A8h Generate Short Name	No Win32 function equivalent
Interrupt 21h Function 71A9h  Server Create or Open File	No Win32 function equivalent
Interrupt 21h Function 71AAh Create Subst	No Win32 function equivalent
Interrupt 21h Function 71AAh Terminate Subst	No Win32 function equivalent
Interrupt 21h Function 71AAh Query Subst	No Win32 function equivalent
Note that Interrupt 21h Functions 71A2h through 71A5h exist, but they are for internal use by Windows 95 only.


Functions

The following functions are associated with long filenames.


Interrupt 21h Function 5704h  Get Last Access Date and Time [New - Windows 95]
Interrupt 21h Function 5704h  Get Last Access Date and Time

[New - Windows 95]

mov ax, 5704h   ; Get Last Access Date and Time
mov bx, Handle  ; see below
int 21h

jc  error
mov [Date], dx  ; last access date
mov [Time], cx  ; currently not supported, always 0

Retrieves the last access date for the given file.

•	Clears the carry flag and sets the CX register to zero and the DX register to these values if successful:

Bits	Contents
0−4	Day of the month (1−31)
5−8	Month (1 = January, 2 = February, and so on)
9−15	Year offset from 1980 (that is, add 1980 to get the actual year)
Otherwise, the function sets the carry flag and sets the AX register to an error value.

Handle

File handle.


Interrupt 21h Function 5705h  Set Last Access Date and Time [New - Windows 95]
Interrupt 21h Function 5705h  Set Last Access Date and Time

[New - Windows 95]

mov ax, 5705h       ; Set Last Access Date and Time
mov bx, Handle      ; see below
mov cx, 0           ; time currently not supported, always 0
mov dx, AccessDate  ; see below
int 21h

jc  error

Sets the last access date for the given file.

•	Clears the carry flag if successful. Otherwise, the function sets the carry flag and sets the AX register to an error value.

Handle

File handle.

AccessDate

New access date. The date is a packed 16-bit value with this form:

Bits	Contents
0−4	Day of the month (1−31)
5−8	Month (1 = January, 2 = February, and so on)
9−15	Year offset from 1980 (that is, add 1980 to get the actual year)


Interrupt 21h Function 5706h  Get Creation Date and Time [New - Windows 95]
Interrupt 21h Function 5706h  Get Creation Date and Time

[New - Windows 95]

mov ax, 5706h           ; Get Creation Date and Time
mov bx, Handle          ; see below
int 21h

jc  error
mov [Time], cx          ; creation time
mov [Date], dx          ; creation date
mov [MilliSeconds], si  ; number of 10 ms intervals in 2 seconds

Retrieves the creation date and time for the given file.

•	Clears the carry flag and sets the CX, DX, and SI registers to these values if successful:

CX	Creation time. The time is a packed 16-bit value with the following form:
Bits	Contents
0−4	Second divided by 2
5−10	Minute (0−59)
11−15	Hour (0−23 on a 24-hour clock)
DX	Creation date. The date is a packed 16-bit value with the following form:
Bits	Contents
0−4	Day of the month (1−31)
5−8	Month (1 = January, 2 = February, and so on)
9−15	Year offset from 1980 (that is, add 1980 to get the actual year)
SI	Number of 10 millisecond intervals in 2 seconds to add to the MS-DOS time. The number can be a value in the range of 0 to 199.
Otherwise, the function sets the carry flag and sets the AX register to an error value.

Handle

File handle.


Interrupt 21h Function 5707h  Set Creation Date and Time [New - Windows 95]
Interrupt 21h Function 5707h  Set Creation Date and Time

[New - Windows 95]

mov ax, 5707h         ; Set Creation Date and Time
mov bx, Handle        ; see below
mov cx, Time          ; see below
mov dx, Date          ; see below
mov si, MilliSeconds  ; see below
int 21h

jc  error

Sets the creation date and time for the given file.

•	Clears the carry flag if successful. Otherwise, the function sets the carry flag and sets the AX register to an error value.

Handle

File handle.

Time

New creation time. The time is a packed 16-bit value with the following form:

Bits	Contents
0−4	Second divided by 2
5−10	Minute (0−59)
11−15	Hour (0−23 on a 24-hour clock)
Date

New creation date. The date is a packed 16-bit value with the following form:

Bits	Contents
0−4	Day of the month (1−31)
5−8	Month (1 = January, 2 = February, and so on)
9−15	Year offset from 1980 (that is, add 1980 to get the actual year)
MilliSeconds

Number of 10 millisecond intervals in 2 seconds to add to the MS-DOS time. The number can be a value in the range 0 to 199.


Interrupt 21h Function 7139h  Make Directory [New - Windows 95]
Interrupt 21h Function 7139h  Make Directory

[New - Windows 95]

mov ax, 7139h     ; Make Directory
mov dx, seg Name  ; see below
mov ds, dx
mov dx, offset Name
int 21h

jc  error

Creates a new directory having the given name.

•	Clears the carry flag if successful. Otherwise, the function sets the carry flag and sets the AX register to an error value.

Name

Address of a null-terminated string specifying the name of the directory to create. Long filenames are allowed.


Interrupt 21h Function 713Ah  Remove Directory [New - Windows 95]
Interrupt 21h Function 713Ah  Remove Directory

[New - Windows 95]

mov ax, 713Ah     ; Remove Directory
mov dx, seg Name  ; see below
mov ds, dx
mov dx, offset Name
int 21h

jc  error

Removes the given directory. The directory must be empty.

•	Clears the carry flag if successful. Otherwise, the function sets the carry flag and sets the AX register to an error value.

Name

Address of a null-terminated string specifying the name of the directory to remove. Long filenames are allowed.

The root directory cannot be deleted.


Interrupt 21h Function 713Bh  Change Directory [New - Windows 95]
Interrupt 21h Function 713Bh  Change Directory

[New - Windows 95]

mov ax, 713Bh     ; Change Directory
mov dx, seg Path  ; see below
mov ds, dx
mov dx, offset Path
int 21h

jc error

Changes the current directory to the directory specified by the given path.

•	Clears the carry flag if successful. Otherwise, the function sets the carry flag and sets the AX register to an error value.

Path

Address of a null-terminated string specifying the directory to change to. The path, which can include the drive letter, must be a valid path for the given volume. Long filenames are allowed.

The current or default directory is the directory that the system uses whenever an application supplies a filename that does not explicitly specify a directory. Similarly, the current or default drive is the drive the system uses whenever an application supplies a path that does not explicitly specify a drive. If a drive other than the default drive is specified as part of the new directory path, this function changes the current directory on that drive but does not change the default drive. Set Default Drive (Interrupt 21h Function 0Eh) can be used to change the default drive.


Interrupt 21h Function 7141h  Delete File [New - Windows 95]
Interrupt 21h Function 7141h  Delete File

[New - Windows 95]

mov ax, 7141h             ; Delete File
mov ch, MustMatchAttrs    ; see below

mov cl, SearchAttrs       ; see below
mov dx, seg Filename      ; see below
mov ds, dx
mov dx, offset Filename
mov si, WildcardAndAttrs  ; see below
int 21h

jc error

Deletes the given file or files. If the specified filename contains a wildcard character, this function can delete multiple files that match the wildcard.

•	Clears the carry flag if successful. Otherwise, the function sets the carry flag and sets the AX register to an error value.

MustMatchAttrs

Additional filter on the attributes specified in SearchAttrs. This parameter can be a combination of these values:

FILE_ATTRIBUTE_NORMAL (0000h)
	The file can be read from or written to. This value is valid only if used alone.
FILE_ATTRIBUTE_READONLY (0001h)
	The file can be read from, but not written to.
FILE_ATTRIBUTE_HIDDEN (0002h)
	The file is hidden and does not appear in an ordinary directory listing.
FILE_ATTRIBUTE_SYSTEM (0004h)
	The file is part of the operating system or is used exclusively by it.
FILE_ATTRIBUTE_VOLUME (0008h)
	The name specified by Filename is used as the volume label for the current medium.
FILE_ATTRIBUTE_DIRECTORY (0010h)
	The name specified by Filename is used as a directory, not a file.
FILE_ATTRIBUTE_ARCHIVE (0020h)
	The file is an archive file. Applications use this value to mark files for backup or removal.
SearchAttrs

File attributes to search for. This parameter can be a combination of these values:

FILE_ATTRIBUTE_NORMAL (0000h)

FILE_ATTRIBUTE_READONLY (0001h)

FILE_ATTRIBUTE_HIDDEN (0002h)

FILE_ATTRIBUTE_SYSTEM (0004h)

FILE_ATTRIBUTE_VOLUME (0008h)

FILE_ATTRIBUTE_DIRECTORY (0010h)

FILE_ATTRIBUTE_ARCHIVE (0020h)

Filename

Address of a null-terminated string specifying the name of the file to delete. If WildcardAndAttrs is 1, the "*" and "?" wildcard characters are permitted in the filename. Long filenames are allowed.

WildcardAndAttrs

Search criteria. This parameter must be one of these values:

0	Wildcard characters are not allowed in Filename. Any specified attributes are ignored.
1	Wildcard characters are allowed in Filename. Files with specified attributes are matched.
Wildcard searches are more flexible in Windows 95 than in MS-DOS. Both long filenames and aliases are considered in searches. For example, *1 finds Windows 95 filenames (both long filenames and aliases) that end in a 1 and *mid* finds filenames that contain the characters mid. In MS-DOS and in Windows 95 searching on real-mode FAT directories, all characters after the first * are ignored.

For more information about how MustMatchAttrs and SearchAttrs are used, see the comments for Find First File (Interrupt 21h Function 714Eh).


Interrupt 21h Function 7143h  Extended Get or Set File Attributes [New - Windows 95]
Interrupt 21h Function 7143h  Extended Get or Set File Attributes

[New - Windows 95]

mov ax, 7143h         ; Get or Set File Attributes
mov bl, Action        ; see below
mov cx, Attributes    ; see below
mov di, Date          ; see below
mov cx, Time          ; see below
mov si, MilliSeconds  ; see below
mov dx, seg Filename  ; see below
mov ds, dx
mov dx, offset Filename
int 21h

jc  error
; see below for return values

Retrieves or sets the file attributes, gets the compressed file size, or retrieves or sets the date and time for the given file.

•	Clears the carry flag if successful.

If Action is zero (retrieve attributes), the file attributes returned in the CX register may be a combination of the following values :

FILE_ATTRIBUTE_NORMAL (0000h)

FILE_ATTRIBUTE_READONLY (0001h)

FILE_ATTRIBUTE_HIDDEN (0002h)

FILE_ATTRIBUTE_SYSTEM (0004h)

FILE_ATTRIBUTE_VOLUME (0008h)

FILE_ATTRIBUTE_DIRECTORY (0010h)

FILE_ATTRIBUTE_ARCHIVE (0020h)

If Action is 2 (get physical size of a compressed file), the size, in bytes, of the compressed file is returned in DX:AX. This value is the physical size of the compressed file — that is, the actual number of bytes that the compressed file occupies on disk.

If Action is 4 (get last write date/time) or 8 (get creation date/time), the CX register contains the time as a packed 16-bit value with the following form:

Bits	Contents
0−4	Second divided by 2
5−10	Minute (0−59)
11−15	Hour (0−23 on a 24-hour clock)
If Action is 4 (get last write date/time), 6 (get last access date), or 8 (get creation date/time), the DI register contains the date as a packed 16-bit value with the following form:

Bits	Contents
0−4	Day of the month (1−31)
5−8	Month (1 = January, 2 = February, and so on)
9−15	Year offset from 1980 (that is, add 1980 to get the actual year)
If Action is 8 (get creation date/time), the SI register contains the number of 10 millisecond intervals in 2 seconds to add to the MS-DOS time. The number can be a value in the range of 0 to 199.

If the function is not successful, it sets the carry flag and sets the AX register to an error value.

Action

Action to take. This parameter can be one of the following values:

0	Retrieve attributes.
1	Set specified attributes.
2	Get physical size of a compressed file.
3	Set last write date/time.
4	Get last write date/time.
5	Set last access date.
6	Get last access date.
7	Set creation date/time.
8	Get creation date/time.
Attributes

File attributes to set, which are used only if Action is 1. This parameter can be a combination of these values:

FILE_ATTRIBUTE_NORMAL (0000h)
	The file can be read from or written to. This value is valid only if used alone.
FILE_ATTRIBUTE_READONLY (0001h)
	The file can be read from, but not written to.
FILE_ATTRIBUTE_HIDDEN (0002h)
	The file is hidden and does not appear in an ordinary directory listing.
FILE_ATTRIBUTE_SYSTEM (0004h)
	The file is part of the operating system or is used exclusively by it.
FILE_ATTRIBUTE_ARCHIVE (0020h)
	The file is an archive file. Applications use this value to mark files for backup or removal.
Time

New time to set, which is used only if Action is 3 (set last write date/time) or 7 (set creation date/time) The time is a packed 16-bit value with the following form:

Bits	Contents
0−4	Second divided by 2
5−10	Minute (0−59)
11−15	Hour (0−23 on a 24-hour clock)
Date

New date to set, which is used only if Action is 3 (set last write date/time), 5 (set last access date), or 7 (set creation date/time). The date is a packed 16-bit value with the following form:

Bits	Contents
0−4	Day of the month (1−31)
5−8	Month (1 = January, 2 = February, and so on)
9−15	Year offset from 1980 (that is, add 1980 to get the actual year)
MilliSeconds

Number of 10 millisecond intervals in 2 seconds to add to the MS-DOS time. The number can be a value in the range 0 to 199. This value is only used if Action is 7 (set creation date/time).

Filename

Address of a null-terminated string specifying the name of the file to retrieve or set attributes for. Long filenames are allowed.


Interrupt 21h Function 7147h  Get Current Directory [New - Windows 95]
Interrupt 21h Function 7147h  Get Current Directory

[New - Windows 95]

mov ax, 7147h       ; Get Current Directory
mov dl, Drive       ; see below
mov si, seg Buffer  ; see below
mov ds, si
mov si, offset Buffer
int 21h

jc  error

Copies the path of the current directory for the given drive to the buffer. The copied path does not include the drive letter or the leading backslash.

•	Clears the carry flag and copies the path if successful. Otherwise, the function sets the carry flag and sets the AX register to an error value.

Drive

Drive number. This parameter can be 0 for current drive, 1 for A, 2 for B, and so on.

Buffer

Address of the buffer that receives the path. The buffer must be at least as big as the maximum allowed path for this volume as returned by Get Volume Information (Interrupt 21h Function 71A0h).


Interrupt 21h Function 714Eh  Find First File [New - Windows 95]
Interrupt 21h Function 714Eh  Find First File

[New - Windows 95]

mov ax, 714Eh             ; Find First File
mov ch, MustMatchAttrs    ; see below

mov cl, SearchAttrs       ; see below
mov dx, seg Filename      ; see below
mov ds, dx
mov dx, offset Filename
mov di, seg FindData      ; see below
mov es, di
mov di, offset FindData
mov si, DateTimeFormat    ; see below
int 21h

jc  error
mov [Handle], ax          ; search handle
mov [ConversionCode], cx  ; Unicode to OEM/ANSI conversion OK?

Searches a directory for the first file or directory whose name and attributes match the specified name and attributes.

•	Clears the carry flag, copies information about the file to the specified buffer, returns the search handle in the AX register, and sets the CX register to a combination of the following values if successful:

0x0000	All characters in the primary and alternate name members in the structure specified by FindData were successfully converted from Unicode.
0x0001	The primary name returned in the structure specified by FindData contains underscore characters in place of characters that could not be converted from Unicode.
0x0002	The alternate name returned in the structure specified by FindData contains underscore characters in place of characters that could not be converted from Unicode.
Otherwise, the function sets the carry flag and sets the AX register to an error value.

MustMatchAttrs

Additional filter on the attributes specified in SearchAttrs. This parameter can be a combination of these values:

FILE_ATTRIBUTE_NORMAL (0000h)
	The file can be read from or written to. This value is valid only if used alone.
FILE_ATTRIBUTE_READONLY (0001h)
	The file can be read from, but not written to.
FILE_ATTRIBUTE_HIDDEN (0002h)
	The file is hidden and does not appear in an ordinary directory listing.
FILE_ATTRIBUTE_SYSTEM (0004h)
	The file is part of the operating system or is used exclusively by it.
FILE_ATTRIBUTE_VOLUME (0008h)
	The name specified by Filename is used as the volume label for the current medium.
FILE_ATTRIBUTE_DIRECTORY (0010h)
	The name specified by Filename is used as a directory, not a file.
FILE_ATTRIBUTE_ARCHIVE (0020h)
	The file is an archive file. Applications use this value to mark files for backup or removal.
SearchAttrs

File attributes to search for. This parameter can be a combination of these values:

FILE_ATTRIBUTE_NORMAL (0000h)

FILE_ATTRIBUTE_READONLY (0001h)

FILE_ATTRIBUTE_HIDDEN (0002h)

FILE_ATTRIBUTE_SYSTEM (0004h)

FILE_ATTRIBUTE_VOLUME (0008h)

FILE_ATTRIBUTE_DIRECTORY (0010h)

FILE_ATTRIBUTE_ARCHIVE (0020h)

Filename

Address of a null-terminated string specifying the name of the file or directory to search for. The name, which must be a valid filename or directory name, can include the "*" and "?" wildcard characters. Long filenames are allowed.

FindData

Address of a WIN32_FIND_DATA structure that receives information about the file.

DateTimeFormat

Date and time format to be returned. This parameter must be one of these values:

0	Returns the date and time in 64-bit file time format.
1	Returns the MS-DOS date and time values. MS-DOS date and time values are returned in the low doubleword of the FILETIME structure. Within the doubleword, the date is returned in the high-order word; the time is in the low-order word.
Find First File and subsequent calls to Find Next File (Interrupt 21h Function 714Fh) use the following algorithm to match the attributes of a file or directory (referred to as Attributes in the algorithm) against MustMatchAttrs and SearchAttrs.

if  ((((<MustMatchAttrs> & ~<Attributes>) & 0x3F) == 0)
      && (((~<SearchAttrs> & <Attributes>) & 0x1E) == 0))
    {
         return the file or directory name
    }
    else
    {
         continue searching for the next name
    }

The following table lists the MustMatchAttrs and SearchAttrs values for some common searches where the specified filename is "*.*". In the table, the word normal means that the read only, hidden, or system attributes have not been set. Parentheses are used to indicate that a file or directory has more than one attribute. For example, (hidden and system) indicates that a file or directory has both the hidden attribute and the system attribute.

MustMatchAttrs	SearchAttrs	Find results
10h	10h	All normal directories
10h	12h	All normal and hidden directories
10h	14h	All normal and system directories
10h	16h	All normal, hidden, system and (hidden and system) directories
12h	12h	All hidden directories
14h	14h	All system directories
16h	16h	All (hidden and system) directories
00h	00h	All normal files
00h	01h	All normal and read only files
00h	02h	All normal and hidden files
00h	04h	All normal and system files
00h	06h	All normal, hidden, system, and (hidden and system) files
00h	10h	All normal files and directories
01h	01h	All read only files
02h	02h	All hidden files
02h	06h	All hidden and (hidden and system) files
This function can be used to return the volume label by specifying only FILE_ATTRIBUTE_VOLUME (0008h) in both MustMatchAttrs and SearchAttrs.

An application may use the handle returned in the AX register in subsequent calls to Find Next File (Interrupt 21h Function 714Fh). It is important to close the handle when it is no longer needed by calling Find Close (Interrupt 21h Function 71A1h).

Wildcard searches are more flexible in Windows 95 than in MS-DOS. For example, *1 finds the filenames (both long filenames and aliases) that end in a 1, and *mid* finds filenames that contain the characters mid. In MS-DOS and in Windows 95 searching on real-mode FAT directories, all characters after the first * are ignored.


Interrupt 21h Function 714Fh  Find Next File [New - Windows 95]
Interrupt 21h Function 714Fh  Find Next File

[New - Windows 95]

mov ax, 714Fh            ; Find Next File
mov bx, Handle           ; see below
mov di, seg FindData     ; see below
mov es, di
mov di, offset FindData
mov si, DateTimeFormat   ; see below
int 21h

jc error
mov [ConversionCode], cx  ; Unicode to OEM/ANSI conversion OK?

Searches for the next file in a directory, returning information about the file in the given buffer.

•	Clears the carry flag, copies information to the specified buffer, and sets the CX register to a combination of these values if successful:

0x0000	All characters in the primary and alternate name member in the structure specified by FindData were successfully converted from Unicode.
0x0001	The primary name returned in the structure specified by FindData contains underscore characters in place of characters that could not be converted from Unicode.
0x0002	The alternate name returned in the structure specified by FindData contains underscore characters in place of characters that could not be converted from Unicode.
Otherwise, the function sets the carry flag and sets the AX register to an error value.

Handle

Search handle. It must have been previously returned from Find First File (Interrupt 21h Function 714Eh).

FindData

Address of a WIN32_FIND_DATA structure that receives information about the file.

DateTimeFormat

Date and time format to be returned. This parameter must be one of these values:

0	Returns the date and time in 64-bit file time format.
1	Returns the MS-DOS date and time values. MS-DOS date and time values are returned in the low doubleword of the FILETIME structure. Within the doubleword, the date is returned in the high-order word; the time is in the low-order word.
It is important to close the handle when it is no longer needed by calling Find Close (Interrupt 21h Function 71A1h).


Interrupt 21h Function 7156h  Rename File [New - Windows 95]
Interrupt 21h Function 7156h  Rename File

[New - Windows 95]

mov ax, 7156h           ; Rename File
mov dx, seg OldName     ; see below
mov ds, dx

mov dx, offset OldName
mov di, seg NewName     ; see below
mov es, di

mov di, offset NewName
int 21h

jc  error

Changes the name of the given file or directory to the new name.

•	Clears the carry flag if successful. Otherwise, the function sets the carry flag and sets the AX register to an error value.

OldName

Address of a null-terminated string specifying the original name of the file or the directory to rename. Long filenames are allowed.

NewName

Address of a null-terminated string specifying the new name for the file or the directory. The function will fail if this parameter specifies an existing file or directory. The new name must not specify a drive different than the original drive. Long filenames are allowed.


Interrupt 21h Function 7160h  Get Full Path Name [New - Windows 95]
Interrupt 21h Function 7160h  Get Full Path Name

[New - Windows 95]

mov ax, 7160h
mov cl, 0                  ; Get Full Path Name
mov ch, SubstExpand        ; see below
mov si, seg SourcePath     ; see below
mov ds, si
mov si, offset SourcePath
mov di, seg DestPath       ; see below
mov es, di
mov di, offset DestPath
int 21h

jc  error

Retrieves the full path for the specified file or path.

•	Clears the carry flag, modifies the AX register, and returns the full path in the given buffer if successful. Otherwise, the function sets the carry flag and sets the AX register to an error value.

SubstExpand

Flag that indicates whether the returned path should contain a SUBST drive letter or the path associated with the SUBST drive. Zero is specified to indicate that the returned path should contain the path associated with the SUBST drive, and 80h is specified to indicate that the returned path should contain the SUBST drive letter.

SourcePath

Address of a null-terminated string that names the file or path to retrieve the full path for. Either the long filename or the standard 8.3 filename format is acceptable.

DestPath

Address of the buffer that receives the full path. The buffer should be large enough to contain the largest possible Windows 95 path (260 characters, including the drive letter, colon, leading backslash, and terminating null character).

When just a filename is specified, this function merges the name of the current drive and directory with the specified filename to determine the full path. Relative paths containing the characters "." and ".." in SourcePath are fully expanded. The function does no validation, so the specified filename or path does not need to exist.


Interrupt 21h Function 7160h  Get Short Path Name [New - Windows 95]
Interrupt 21h Function 7160h  Get Short Path Name

[New - Windows 95]

mov ax, 7160h
mov cl, 1                  ; Get Short Path Name
mov ch, SubstExpand        ; see below
mov si, seg SourcePath     ; see below
mov ds, si
mov si, offset SourcePath
mov di, seg DestPath       ; see below
mov es, di
mov di, offset DestPath
int 21h
jc  error

Retrieves the complete path in its short form (the standard 8.3 format) for the specified file or path. The function returns the 8.3 filename for all directories in the path.

•	Clears the carry flag, modifies the AX register, and returns the complete short path in the given buffer if successful. Otherwise, the function sets the carry flag and sets the AX register to an error value.

SubstExpand

Flag that indicates if the returned path should contain a SUBST drive letter or the path associated with the SUBST drive. Zero is specified to indicate that the returned path should contain the path associated with the SUBST drive, and 80h is specified to indicate that the returned path should contain the SUBST drive letter.

SourcePath

Address of a null-terminated string that names the file or path to retrieve the complete short path for. Either the long or short form is acceptable as the source string.

DestPath

Address of the buffer that receives the complete path. The buffer should be large enough to contain the largest possible Windows 95 path in the short form (260 characters, including the drive letter, colon, leading backslash, and terminating null character).

Relative paths containing the characters "." and ".." in SourcePath are fully expanded. Since this function performs validation, SourcePath must contain either a valid filename or path.


Interrupt 21h Function 7160h  Get Long Path Name [New - Windows 95]
Interrupt 21h Function 7160h  Get Long Path Name

[New - Windows 95]

mov ax, 7160h
mov cl, 2                  ; Get Long Path Name
mov ch, SubstExpand        ; see below
mov si, seg SourcePath     ; see below
mov ds, si
mov si, offset SourcePath
mov di, seg DestPath       ; see below
mov es, di
mov di, offset DestPath
int 21h
jc  error

Retrieves the complete path in its long filename form for the specified file or path. The function returns the long name for all directories in the path.

•	Clears the carry flag, modifies the AX register, and returns the complete long path in the given buffer if successful. Otherwise, the function sets the carry flag and sets the AX register to an error value.

SubstExpand

Flag that indicates if the returned path should contain a SUBST drive letter or the path associated with the SUBST drive. Zero is specified to indicate that the returned path should contain the path associated with the SUBST drive, and 80h is specified to indicate that the returned path should contain the SUBST drive letter.

SourcePath

Address of a null-terminated string that names the file or path to retrieve the complete long path for. Either the long filename or the short form is acceptable as the source string.

DestPath

Address of the buffer that receives the complete path. The buffer should be large enough to contain the largest possible Windows 95 path (260 characters, including the drive letter, colon, leading backslash, and terminating null character).

Relative paths containing the characters "." and ".." in SourcePath are fully expanded. Since this function performs validation, SourcePath must contain either a valid filename or path.


Interrupt 21h Function 716Ch  Create or Open File [New - Windows 95]
Interrupt 21h Function 716Ch  Create or Open File

[New - Windows 95]

mov ax, 716Ch          ; Create or Open File
mov bx, ModeAndFlags   ; see below
mov cx, Attributes     ; see below
mov dx, Action         ; see below
mov si, seg Filename   ; see below
mov ds, si
mov si, offset Filename
mov di, AliasHint      ; see below
int 21h

jc error
mov [Handle], ax       ; file handle
mov [ActionTaken], cx  ; action taken to open file

Creates or opens a file.

•	Clears carry flag, copies the file handle to the AX register, and sets the CX register to one of the following values if successful:

ACTION_OPENED (0001h)

ACTION_CREATED_OPENED (0002h)

ACTION_REPLACED_OPENED (0003h)

Otherwise, the function sets the carry flag and sets the AX register to an error value.

ModeAndFlags

Combination of access mode, sharing mode, and open flags. This parameter can be one value each from the access and sharing modes and any combination of open flags:

Access mode	Meaning
OPEN_ACCESS_READONLY (0000h)
	Opens the file for reading only.
OPEN_ACCESS_WRITEONLY (0001h)
	Opens the file for writing only.
OPEN_ACCESS_READWRITE (0002h)
	Opens the file for reading and writing.
0003h
	Reserved; do not use.
OPEN_ACCESS_RO_NOMODLASTACCESS (0004h)
	Opens the file for reading only without modifying the file's last access date.
Sharing mode	Meaning
OPEN_SHARE_COMPATIBLE (0000h)
	Opens the file with compatibility mode, allowing any process on a given computer to open the file any number of times.
OPEN_SHARE_DENYREADWRITE (0010h)
	Opens the file and denies both read and write access to other processes.
OPEN_SHARE_DENYWRITE (0020h)
	Opens the file and denies write access to other processes.
OPEN_SHARE_DENYREAD (0030h)
	Opens the file and denies read access to other processes.
OPEN_SHARE_DENYNONE (0040h)
	Opens the file without denying read or write access to other processes, but no process may open the file for compatibility access.
Open flags	Meaning
OPEN_FLAGS_NOINHERIT (0080h)
	If this flag is set, a child process created with Load and Execute Program (Interrupt 21h Function 4B00h) does not inherit the file handle. If the handle is needed by the child process, the parent process must pass the handle value to the child process. If this flag is not set, child processes inherit the file handle.
OPEN_FLAGS_NO_BUFFERING (0100h)
	The file is to be opened with no intermediate buffering or caching done by the system. Read and write operations access the disk directly. All reads and writes to the file must be done at file positions that are multiples of the disk sector size, in bytes, and the number of bytes read or written should also be a multiple of the sector size. Applications can determine the sector size, in bytes, with the Get Disk Free Space function (Interrupt 21h, Function 36h).
OPEN_FLAGS_NO_COMPRESS (0200h)
	The file should not be compressed on a volume that performs file compression. If the volume does not perform file compression, this flag is ignored. This flag is valid only on file creation and is ignored on file open.
OPEN_FLAGS_ALIAS_HINT (0400h)
	The number in the DI register is to be used as the numeric tail for the alias (short filename). For more information, see AliasHint below.
OPEN_FLAGS_NOCRITERR (2000h)
	If a critical error occurs while MS-DOS is opening this file, Critical-Error Handler (Interrupt 24h) is not called. Instead, MS-DOS simply returns an error value to the program.
OPEN_FLAGS_COMMIT (4000h)
	After each write operation, MS-DOS commits the file (flushes the contents of the cache buffer to disk).
Attributes

Attributes for files that are created or truncated. This parameter may be a combination of these values:

FILE_ATTRIBUTE_NORMAL (0000h)
	The file can be read from or written to. This value is valid only if used alone.
FILE_ATTRIBUTE_READONLY (0001h)
	The file can be read from, but not written to.
FILE_ATTRIBUTE_HIDDEN (0002h)
	The file is hidden and does not appear in an ordinary directory listing.
FILE_ATTRIBUTE_SYSTEM (0004h)
	The file is part of the operating system or is used exclusively by it.
FILE_ATTRIBUTE_VOLUME (0008h)
	The name specified by Filename is used as the volume label for the current medium and is restricted to the standard 8.3 format. For information about an alternative way to set the volume label, see Set Media ID (Interrupt 21h Function 440Dh Minor Code 46h) in the Microsoft MS-DOS Programmer's Reference.
FILE_ATTRIBUTE_ARCHIVE (0020h)
	The file is an archive file. Applications use this value to mark files for backup or removal.
Action

Action to take it the file exists or if it does not exist. This parameter can be a combination of these values:

FILE_CREATE (0010h)	Creates a new file if it does not already exist. The function fails if the file already exists.
FILE_OPEN (0001h)	Opens the file. The function fails if the file does not exist.
FILE_TRUNCATE (0002h)	Opens the file and truncates it to zero length (replaces the existing file). The function fails if the file does not exist.
The only valid combinations are FILE_CREATE combined with FILE_OPEN or FILE_CREATE combined with FILE_TRUNCATE.

Filename

Address of a null-terminated string specifying the name of the file to be opened or created. The string must be a valid path for the volume associated with the given drive. Long filenames are allowed.

AliasHint

Number that is used in the numeric tail for the alias (short filename). A numeric tail, which consists of the tilde character (~) followed a number, is appended to the end of a filename. The system constructs the alias from the first few characters of the long filename followed by the numeric tail. The system starts with the number 1 in the numeric tail. If that filename is in use, it uses the number 2. It continues in this fashion until a unique name is found. To override the default numbering scheme, you must specify the OPEN_FLAGS_ALIAS_HINT value when you create the file in addition to specifying this parameter. If a filename already exists with the specified numeric tail, the system uses the default numbering scheme. You should specify a number for this parameter, not the tilde character.

A file on a remote directory — that is, a directory on the network — cannot be opened, created, or modified, unless the appropriate permissions for the directory exist.


Interrupt 21h Function 71A0h  Get Volume Information [New - Windows 95]
Interrupt 21h Function 71A0h  Get Volume Information

[New - Windows 95]

mov ax, 71A0h          ; Get Volume Information
mov di, seg Buffer     ; see below
mov es, di
mov di, offset Buffer
mov cx, BufSize        ; see below
mov dx, seg RootName   ; see below
mov ds, dx
mov dx, offset RootName
int 21h

jc  error
mov [Flags], bx        ; file system flags
mov [MaxFilename], cx  ; max. filename length, excluding null
mov [MaxPath], dx      ; max. path length, including null

Returns information about the volume associated with the given root directory.

•	Clears the carry flag, copies the file system name to the buffer given by the ES:DI register pair, and sets the BX, CX, and DX registers to the following values if successful:

BX	File system flags, which can be a combination of these values:

FS_CASE_SENSITIVE (0001h)
Specifies that searches are case-sensitive.

FS_CASE_IS_PRESERVED (0002h)
Preserves case in directory entries.

FS_UNICODE_ON_DISK (0004h)
Uses Unicode characters in file and directory names.

FS_LFN_APIS (4000h)
Supports new long filename functions.

FS_VOLUME_COMPRESSED (8000h)
Specifies that the volume is compressed.

CX	Maximum allowed length, excluding the terminating null character, of a filename for this volume. For example, on the protected-mode FAT file system, this value is 255.
DX	Maximum allowed length of a path for this volume, including the drive letter, colon, leading slash, and terminating null character. For example, on the protected-mode FAT file system, this value is 260.
Otherwise, the function sets the carry flag and sets the AX register to an error value.

Buffer

Address of a buffer that receives a null-terminated string specifying the name of the file system.

BufSize

Size, in bytes, of the buffer that receives the name. The buffer should include space for the terminating null character.

RootName

Address of a null-terminated string specifying the name of the root directory of the volume to check. This parameter must not be NULL, or the function will fail. The format for this parameter is "C:\".

This function accesses the disk the first time it is called, but subsequent calls do not access the disk.


Interrupt 21h Function 71A1h  Find Close [New - Windows 95]
Interrupt 21h Function 71A1h  Find Close

[New - Windows 95]

mov ax, 71A1h   ; Find Close
mov bx, Handle  ; see below
int 21h

jc  error

Closes the file search identified by the search handle.

•	Clears the carry flag if successful. Otherwise, the function sets the carry flag and sets the AX register to an error value.

Handle

Search handle. It must have been previously returned from Find First File (Interrupt 21h Function 714Eh).

Unlike MS-DOS Find First File (Interrupt 21h Function 4Eh), the long filename version of Find First File (Interrupt 21h Function 714Eh) allocates internal storage for the search operations and returns a handle that identifies the storage. This handle is used with Find Next File. To make sure this internal storage is freed, you must call Find Close to end the search.


Interrupt 21h Function 71A6h  Get File Info By Handle [New - Windows 95]
Interrupt 21h Function 71A6h  Get File Info By Handle

[New - Windows 95]

mov ax, 71a6h              ; Get File Info By Handle
mov bx, Handle             ; see below
mov dx, seg lpFileInfo     ; see below
mov ds, dx
mov dx, offset lpFileInfo
stc                        ; must set carry flag
int 21h

jnc success
cmp ax, 7100h
je not_supported

Retrieves information about the specified file.

•	Clears the carry flag if successful. Otherwise, the function sets the carry flag and sets the AX register to an error value.

Handle

File handle to retrieve information about.

lpFileInfo

Address of a BY_HANDLE_FILE_INFORMATION structure that receives the file information. The structure can be used in subsequent calls to Get File Info By Handle to refer to the information about the file.

Note that it is important to explicitly set the carry flag before calling this function.


Interrupt 21h Function 71A7h  File Time To DOS Time [New - Windows 95]
Interrupt 21h Function 71A7h  File Time To DOS Time

[New - Windows 95]

mov ax, 71A7h           ; date and time format conversion
mov bl, 0               ; File Time To DOS Time
mov si, seg lpft        ; see below
mov ds, si
mov si, offset lpft
int 21h

jc  error
mov [DOSTime], cx
mov [DOSDate], dx
mov [MilliSeconds], bh  ; number of 10ms intervals in 2 seconds

Converts a 64-bit file time to MS-DOS date and time values.

•	Clears the carry flag, and sets the BH, CX, and DX registers to these values if successful:

BH	Number of 10 millisecond intervals in 2 seconds to add to the MS-DOS time. It can be a value in the range 0 to 199.
CX	MS-DOS time. The time is a packed 16-bit value with the following form:
Bits	Contents
0−4	Second divided by 2
5−10	Minute (0−59)
11−15	Hour (0−23 on a 24-hour clock)
DX	MS-DOS date. The date is a packed 16-bit value with the following form:
Bits	Contents
0−4	Day of the month (1−31)
5−8	Month (1 = January, 2 = February, and so on)
9−15	Year offset from 1980 (that is, add 1980 to get the actual year)
Otherwise, the function sets the carry flag and sets the AX register to an error value.

lpft

Address of a FILETIME structure containing the 64-bit file time to convert to the MS-DOS date and time format.

The MS-DOS date format can represent only dates between 1/1/1980 and 12/31/2107; this conversion fails if the input file time is outside this range.

The time in FILETIME must be Coordinated Universal Time (UTC). The MS-DOS time is local time.


Interrupt 21h Function 71A7h  DOS Time To File Time [New - Windows 95]
Interrupt 21h Function 71A7h  DOS Time To File Time

[New - Windows 95]

mov ax, 71A7h         ; date and time format conversion
mov bl, 1             ; Dos Time To File Time
mov bh, MilliSeconds  ; see below
mov cx, DOSTime       ; see below
mov dx, DOSDate       ; see below
mov di, seg lpft      ; see below
mov es, di
mov di, offset lpft
int 21h

jc  error

Converts MS-DOS date and time values to 64-bit file time.

•	Clears the carry flag and returns the 64-bit file time in the specified structure if successful. Otherwise, the function sets the carry flag and sets the AX register to an error value.

MilliSeconds

Number of 10 millisecond intervals in 2 seconds to add to the MS-DOS time. The number can be a value in the range 0 to 199.

DOSTime

MS-DOS time to convert. The time is a packed 16-bit value with the following form:

Bits	Contents
0−4	Second divided by 2
5−10	Minute (0−59)
11−15	Hour (0−23 on a 24-hour clock)
DOSDate

MS-DOS date to convert. The date is a packed 16-bit value with the following form:

Bits	Contents
0−4	Day of the month (1−31)
5−8	Month (1 = January, 2 = February, and so on)
9−15	Year offset from 1980 (that is, add 1980 to get the actual year)
lpft

Address of a FILETIME structure to receive the converted 64-bit file time.

The time in FILETIME must be Coordinated Universal Time (UTC). The MS-DOS time is local time.


Interrupt 21h Function 71A8h  Generate Short Name [New - Windows 95]
Interrupt 21h Function 71A8h  Generate Short Name

[New - Windows 95]

mov ax, 71a8h               ; generate short name
mov si, seg LongFilename    ; see below

mov ds, si
mov si, offset LongFilename
mov di, seg ShortFilename   ; see below

mov es, di

mov di, offset ShortFilename
mov dh, ShortNameFormat     ; see below
mov dl, CharSet             ; see below
int 21h

Generates an alias (a filename in the 8.3 format) for the specified long filename.

•	Returns the generated alias in the specified buffer if successful.

LongFilename

Address of null-terminated string that names the long filename to generate an alias for. This string must contain only a filename, not a path.

ShortFilename

Address of null-terminated string that receives the generated alias.

ShortNameFormat

Format for the returned alias (0 is specified for an 11 character directory entry format or 1 for an 8.3 format).

CharSet

Character set of both the long filename and alias. This parameter is a packed 8-bit value with the following form:

Bits	Contents
0−3	Specifies the character set of the source long filename.
4−7	Specifies the character set of the destination alias.
One of the following values is specified to indicate the character set for the long filename and alias:

BCS_WANSI (0)	Windows ANSI character set
BCS_OEM (1)	Current OEM character set
BCS_UNICODE (2)	Unicode character set
This function generates the alias using the same algorithm that the system uses with the exception that the returned alias will never have a numeric tail. A numeric tail is appended to the end of an alias and consists of the tilde character (~) followed a number. When the system generates an alias, it may attach a numeric tail if the default alias already exists in the current directory. Because this function does not check the current directory to see if the alias already exists, the returned alias will never have a numeric tail. This service is useful for disk utilities that are trying to establish whether the alias, which seems to be associated with a long filename, is correctly associated.


Interrupt 21h Function 71A9h Server Create or Open File [New - Windows 95]
Interrupt 21h Function 71A9h Server Create or Open File

[New - Windows 95]

Creates or opens a file. This function is for use by real-mode servers only. It takes the same parameters as Create or Open File (Interrupt 21h Function 716Ch) and returns a global file handle. For more information, see Create or Open File.


Interrupt 21h Function 71AAh  Create Subst [New - Windows 95]
Interrupt 21h Function 71AAh  Create Subst

[New - Windows 95]

mov ax, 71aah            ; SUBST
mov bh, 0                ; Create Subst
mov bl, DriveNum         ; see below
mov dx, seg PathName     ; see below
mov ds, dx
mov dx, offset PathName
int 21h

jc error

Associates a path with a drive letter.

•	Clears the carry flag if successful. Otherwise the function sets the carry flag and returns an error value in the AX register

DriveNum

Drive to SUBST. This parameter can be 0 for the default drive, 1 for A, 2 for B, and so on.

PathName

Address of path to associate the drive with.


Interrupt 21h Function 71AAh  Terminate Subst [New - Windows 95]
Interrupt 21h Function 71AAh  Terminate Subst

[New - Windows 95]

mov ax, 71aah            ; SUBST
mov bh, 1                ; Terminate Subst
mov bl, DriveNum         ; see below
int 21h

jc error

Terminate the association between a path and a drive letter.

•	Clears the carry flag if successful. Otherwise, the function sets the carry flag and returns an error value in the AX register.

DriveNum

Drive to terminate SUBST. This parameter can 1 for A, 2 for B, and so on. Note that DriveNum cannot be 0 to indicate the default drive.


Interrupt 21h Function 71AAh  Query Subst [New - Windows 95]
Interrupt 21h Function 71AAh  Query Subst

[New - Windows 95]

mov ax, 71aah            ; SUBST
mov bh, 2                ; Query SUBST
mov bl, DriveNum         ; see below
mov dx, seg PathName     ; see below
mov ds, dx
mov dx, offset PathName

int 21h

jc error

Determines if the specified drive is associated with a path and, if it is, retrieves the associated path.

•	Clears the carry flag and retrieves the associated path in the specified buffer if successful. Otherwise, the function sets the carry flag and returns an error value in the AX register.

DriveNum

Drive to SUBST. This parameter can 1 for A, 2 for B, and so on. Note that DriveNum cannot be 0 to indicate the default drive.

PathName

Address of buffer that receives the null-terminated string of the path associated with the specified drive. The buffer must be of MAXPATHLEN size.


Structures

The following structures are used with long filenames.


BY_HANDLE_FILE_INFORMATION [New - Windows 95]
BY_HANDLE_FILE_INFORMATION

[New - Windows 95]

BY_HANDLE_FILE_INFORMATION struc
    dwFileAttributes     dd ?         ; see below
    ftCreationTime       dd 2 dup(?)  ; see below
    ftLastAccessTime     dd 2 dup(?)  ; see below
    ftLastWriteTime      dd 2 dup(?)  ; see below
    dwVolumeSerialNumber dd ?         ; see below
    nFileSizeHigh        dd ?         ; see below
    nFileSizeLow         dd ?         ; see below
    nNumberOfLinks       dd ?         ; see below
    nFileIndexHigh       dd ?         ; see below
    nFileIndexLow        dd ?         ; see below
BY_HANDLE_FILE_INFORMATION ends

Contains file information retrieved by Get File Info By Handle (Interrupt 21h Function 71A6h).

dwFileAttributes

File attributes. This parameter can be one or more of these values:

FILE_ATTRIBUTE_NORMAL (00000000h)
	The file can be read from or written to. This value is valid only if used alone.
FILE_ATTRIBUTE_READONLY (00000001h)
	The file can be read from, but not written to.
FILE_ATTRIBUTE_HIDDEN (00000002h)
	The file is hidden and does not appear in an ordinary directory listing.
FILE_ATTRIBUTE_SYSTEM (00000004h)
	The file is part of the operating system or is used exclusively by it.
FILE_ATTRIBUTE_DIRECTORY (00000010h)
	The name specifies a directory, not a file.
FILE_ATTRIBUTE_ARCHIVE (00000020h)
	The file is an archive file. Applications use this value to mark files for backup or removal.
ftCreationTime

Time that the file was created in 64-bit file time format. A value of 0,0 indicates that the file system containing the file does not support this member.

ftLastAccessTime

Time that the file was last accessed in 64-bit file time format. A value of 0,0 indicates that the file system containing the file does not support this member.

ftLastWriteTime

Time that the file was last written to in 64-bit file time format. All file systems support this member. If the underlying file system does not support the last write time, this member is the time that the file was created.

dwVolumeSerialNumber

Serial number of the volume that contains the file.

nFileSizeHigh

High-order word of the file size.

nFileSizeLow

Low-order word of the file size.

nNumberOfLinks

Number of links to this file. For FAT and HPFS file systems, this member is always 1. For the NTFS file system, this member may be more than 1.

nFileIndexHigh

High-order word of a unique identifier associated with the file.

nFileIndexLow

Low-order word of a unique identifier associated with the file. This identifier and the volume serial number uniquely identify a file. This number may change when the system is restarted or when the file is opened. After a process opens a file, the identifier is constant until the file is closed. An application can use this identifier and the volume serial number to determine whether two handles refer to the same file.

The value returned by nFileIndexHigh and nFileIndexLow may be invalid on some file systems, such as real-mode network redirected file systems. In this case, an invalid index value will be returned.


FILETIME [New - Windows 95]
FILETIME

[New - Windows 95]

FILETIME struc
    dwLowDateTime  dd ?  ; see below
    dwHighDateTime dd ?  ; see below
FILETIME ends

Contains a 64-bit value specifying the number of 100-nanosecond intervals that have elapsed since 12:00 A.M. January 1, 1901.

dwLowDateTime

Low-order 32 bits of the file time.

dwHighDateTime

High-order 32 bits of the file time.


WIN32_FIND_DATA [New - Windows 95]
WIN32_FIND_DATA

[New - Windows 95]

WIN32_FIND_DATA struc
    dwFileAttributes   dd ?         ; see below
    ftCreationTime     dd 2 dup(?)  ; see below
    ftLastAccessTime   dd 2 dup(?)  ; see below
    ftLastWriteTime    dd 2 dup(?)  ; see below
    nFileSizeHigh      dd ?         ; high word of file size, in bytes
    nFileSizeLow       dd ?         ; low word of file size, in bytes
    dwReserved0        dd 0         ; reserved; do not use
    dwReserved1        dd 0         ; reserved; do not use
    cFileName          db MAX_PATH dup(?)  ; see below
    cAlternateFileName db 14 dup(?)        ; see below
WIN32_FIND_DATA ends

Describes a file found by Find First File (Interrupt 21h Function 714Eh) or Find Next File (Interrupt 21h Function 714Fh).

dwFileAttributes

File attributes of the file found. This parameter can be one or more of these values:

FILE_ATTRIBUTE_NORMAL (00000000h)
	The file can be read from or written to. This value is valid only if used alone.
FILE_ATTRIBUTE_READONLY (00000001h)
	The file can be read from, but not written to.
FILE_ATTRIBUTE_HIDDEN (00000002h)
	The file is hidden and does not appear in an ordinary directory listing.
FILE_ATTRIBUTE_SYSTEM (00000004h)
	The file is part of the operating system or is used exclusively by it.
FILE_ATTRIBUTE_DIRECTORY (00000010h)
	The name specifies a directory, not a file.
FILE_ATTRIBUTE_ARCHIVE (00000020h)
	The file is an archive file. Applications use this value to mark files for backup or removal.
ftCreationTime

Time that the file was created in either MS-DOS date and time format or in 64-bit file time format, depending on the date and time format specified in either Find First File or Find Next File. A value of 0,0 indicates that the file system containing the file does not support this member.

ftLastAccessTime

Time that the file was last accessed in either MS-DOS date and time format or in 64-bit file time format, depending on the date and time format specified in either Find First File or Find Next File. A value of 0,0 indicates that the file system containing the file does not support this member.

ftLastWriteTime

Time that the file was last written to in either MS-DOS date and time format or in 64-bit file time format, depending on the date and time format specified in either Find First File or Find Next File. All file systems support this member.

cFileName

Null-terminated string that is the name of the file. Because long filenames are allowed, the buffer size must be large enough for 256 characters, including the terminating null character.

cAlternateFileName

Null-terminated string, in the standard 8.3 filename format, that is an alternate name of the file. If the cFileName member contains an 8.3 format name or the file system does not permit 8.3 format alternates, this member is set to zero.


Exclusive Volume Locking

This article describes exclusive volume locking and provides guidelines for applications that carry out direct access on volumes while running with Microsoft® Windows® 95. This article also describes the input and output control (IOCTL) functions that applications need for managing exclusive volume locking.


About Exclusive Volume Locking

Disk utilities and other applications that directly modify file system structures, such as directory entries, must request exclusive volume locking (that is, exclusive use of the volume) before making modifications to the structures. Exclusive use prevents applications from inadvertently changing the file system while a disk utility is trying modify it and ensures that the information on a volume represents the current state of the volume.


Direct Access

Applications typically use direct access to make changes to the directory entries, paths, and allocation chains in the file allocation table (FAT) of a given volume. The applications access this information by using the Interrupt 13h functions, Absolute Disk Read and Write (Interrupts 25h and 26h), or the Interrupt 21h read, write, and format track IOCTL functions. Some applications may also access the volume using the disk controller input and output (I/O) ports.

As a multitasking operating system, Windows 95 permits any number of applications to access a volume at a given time. Applications that change the file system structures of a volume without regard to other applications risk corruption of that information and subsequent data loss. To prevent data loss, the system manages all requests for direct access. With the exception of floppy disk drives, Windows 95 does not permit direct write operations, unless the volume has been locked by the application. The system returns the ERROR_WRITE_PROTECT error value to functions or interrupts that attempt direct write operations when the volume has not been locked. An application can read directly from a volume, but the system may satisfy the request by reading from internal caches rather than from the medium itself. An application cannot access disk controller I/O ports; the system traps all access.

An application can override the default behavior of the system by requesting exclusive use of the volume using the lock and unlock volume IOCTL functions. An application that has exclusive use of a volume can read and write directly to the medium, and because the system flushes internal caches to the medium, the information there reflects the actual state of the volume. Locking a volume (including the floppy disk drives) ensures consistency of data, because other processes cannot update information about the volume while it is locked.


Exclusive Use Lock

To request exclusive use of a volume, an application use either Lock Logical Volume (Interrupt 21h Function 440Dh Minor Code 4Ah) or Lock Physical Volume (Interrupt 21h Function 440Dh Minor Code 4Bh). Before issuing an Interrupt 13h function, an application must acquire a physical volume lock. An application that only modifies logical volumes should acquire a logical volume lock. The calling interface for both locks is the same except for how the volume to lock is specified; the physical lock requires an Interrupt 13h device unit number, but the logical lock requires a logical drive number. When an application obtains a lock on a physical drive, the system acquires a logical volume lock for each logical volume on the physical drive. Obtaining a lock on a logical volume that is the parent (or host) drive also locks the child drives. For example, a compressed volume is locked when its host drive is locked.

The application that owns the lock can carry out direct disk write operations. Only one application at a time can lock the volume. If an application already owns the volume lock, the system fails subsequent calls to lock the volume.

The volume-locking functions allow the lock owner to control the kind of access that other processes have to the volume. There are three categories of access: read operations, which include opening a file as well as reading from a file; write operations, which include deleting and renaming a file as well as writing to a file; and new file mappings.

When an application calls either of the lock volume functions, it specifies a lock level and, depending on the level, passes in additional information known as permissions. The lock level and permissions specify what kind of operations the system allows processes other than the lock owner to do on the volume while it is locked.

When another process attempts to access the volume, the file system will fail the operation and return the ERROR_WRITE_PROTECT error value or it will block the operation, depending on the lock level and permissions. The system queues a blocked operation and puts the process requesting the operation to sleep until the lock is released and the operation can be performed.

When an application has completed its work, it must unlock the volume. Depending on whether it acquired a logical or physical lock, the application unlocks the volume by calling either Unlock Logical Volume (Interrupt 21h Function 440Dh Minor Code 6Ah) or Unlock Physical Volume (Interrupt 21h Function 440Dh Minor Code 6Bh). Unlocking the volume lets the system perform any blocked operations (in the order that they occurred) and resume normal activity. If an application exits without releasing the lock, the system automatically releases it.

If an application has a lock and the user attempts to close the virtual machine in which the application is running, the system displays a message warning the user that closing the virtual machine could result in damage to the volume. If the user confirms the closing, the system releases the lock and closes the virtual machine.

An application can lock volumes on local drives, but not on network drives or on drives that are not managed by the I/O supervisor, a virtual device driver. Also, the lock and unlock volume IOCTL functions are not available in previous versions of Microsoft® MS-DOS®. If the functions are used with a previous version, they return an error value.

Windows 95 provides 4 levels of exclusive volume locks. The level 0 lock is used alone, and lock levels 1, 2, and 3 form a hierarchy that increasingly restricts access to the file system based on the permissions set when the application obtains the level 1 lock. Although the level 0 lock is not part of the locking hierarchy formed by lock levels 1, 2, and 3, it has a more restrictive sublevel for applications that format volumes. Applications should perform direct disk write operations only in either a level 0 or 3 lock.


Level 0 Lock

The level 0 lock cannot be obtained on volumes that have any open files or handles. This restriction includes handles returned by the Windows FindFirstFile and FindFirstChangeNotification functions. Because the system always has open files, an application cannot take a level 0 lock on the drive that contains the Windows 95 system files. The locking hierarchy can be used on volumes with open files and handles. If the system fails a level 0 lock request because of open files, an application can obtain a list of all the open files on the volume by calling Enumerate Open Files (Interrupt 21h Function 440Dh Minor Code 6Dh).

Before returning from the call to lock the volume, Windows 95 flushes to disk all data from the file system cache. To ensure that the disk and file system remain in a consistent state, the system puts the cache into write-through mode so that it can immediately commit to disk all data from file write operations. If an application has obtained a lock on a child volume, the system does not automatically flush the file system cache after a write operation to the parent volume. To ensure that the cache is flushed when opening files with Open or Create File (Interrupt 21h Function 716Ch), an application should specify the OPEN_FLAGS_NO_BUFFERING (0100h) value. If a file has not been opened with OPEN_FLAGS_NO_BUFFERING or Absolute Disk Write (Interrupt 26h) has been used to write to the parent volume, an application should call Reset Drive (Interrupt 21h Function 710Dh) to flush the cache.

After a process obtains a level 0 lock, the system only allows the lock owner to have access to the volume. The system fails all read operations, write operations, and new file mappings by other processes until the lock owner releases the lock. An application should use a level 0 lock whenever possible, because it guarantees that no other process can access the locked volume.

An application that formats volumes must obtain a more restrictive mode of the level 0 lock. To format a volume, the application should follow these steps:

1.	Call the lock volume function to obtain a level 0 lock.

2.	Do any needed file system I/O that uses the Interrupt 21h file handle I/O functions while in the level 0 lock.

3.	Call the lock volume function a second time to obtain the more restrictive level 0 lock for formatting. When calling the lock volume function the second time, an application should specify 0 as the lock level and specify 4 in the permissions. The application, however, must already own the level 0 lock to obtain this lock.

4.	Format the disk using the Interrupt 21h IOCTL functions (such as Read/Write/Format/Verify Track on Logical Drive or Get/Set Device Parameters). Interrupt 13h will work too, but it is not the preferred method for performance reasons. The system allows direct disk I/O, but it fails all other file system I/O that uses the Interrupt 21h file handle I/O functions while the restrictive level 0 lock is in effect.

5.	Release the level 0 lock for formatting. An application is still in a level 0 lock at this point. Before the application releases this lock, the disk must be in a state that would be recognizable as normal FAT media. Otherwise, the functions mentioned in step 6 will not work.

6.	Resume normal file system I/O using the Interrupt 21h file handle I/O functions.

7.	Release the level 0 lock.


Locking Hierarchy

The locking hierarchy allows an application to obtain a lock in preparation for modifying the file system and yet allows other processes access to the drive. In this way, other processes are only denied access to the volume when absolutely necessary.

An application should perform direct disk write operations only within a level 3 lock. To obtain a level 3 lock, an application must make three calls to the lock volume function — first to obtain a level 1 lock, then a level 2 lock, and finally a level 3 lock. After obtaining the level 3 lock, the application can safely access the volume directly.

To release the lock on a volume, an application must call the appropriate unlock volume function the same number of times that the corresponding lock volume function was called. Each call to the unlock volume function decrements the lock level. For example, a level 3 lock returns to a level 2 lock, and the system processes any blocked read operations. A level 2 lock returns to a level 1 lock, and the system processes any blocked write operations or new file mappings. A call to the unlock volume function on a level 1 lock, however, releases the lock on the volume and allows other processes to obtain the lock.

Exclusive volume locks are owned by a process, not a thread. If necessary, a multithreaded application can obtain a level 1 lock in one thread, a level 2 lock in another, and a level 3 lock in yet another.

Even though the system may block or fail new file mappings, other processes are allowed to write to files through existing file mappings, because file mappings cannot be resized. Writing to an existing file mapping only changes the contents of the memory-mapped file, it does not cause changes to the file system.


Level 1

The level 1 lock acts as a sentinel to guarantee that only one application may obtain the level 2 and 3 locks. An application specifies permissions only when requesting the level 1 lock. The lock level and permissions determine the kind of access that processes other than the lock owner have to the volume while it is locked. Bit 0 of the Permissions parameter for the lock volume function determines if the system allows or fails write operations by other processes. Bit 1 of Permissions determines if the system allows or fails new file mappings by other processes. Bit 2 of Permissions is only used when obtaining the restrictive level 0 lock for formatting and is ignored for a level 1 lock. The following table shows which operations are allowed at each lock level based on the permissions set on the level 1 lock.

Permissions	Level 1	Level 2	Level 3
Bit 0 = 0 Bit 1 = 0	Write operations are    failed. New file mappings    are allowed.  Read operations are    allowed.	Write operations are    failed. New file mappings    are allowed. Read operations are    allowed.	Write operations are    failed. New file mappings    are blocked. Read operations are    blocked.
Bit 0 = 0 Bit 1 = 1	Write operations are    failed. New file mappings    are failed. Read operations are    allowed.	Write operations are    failed. New file mappings    are failed. Read operations are    allowed.	Write operations are    failed. New file mappings    are failed. Read operations are    blocked.
Bit 0 = 1 Bit 1 = 0	Write operations are    allowed. New file mappings    are allowed. Read operations are    allowed.	Write operations    are blocked. New file mappings    are allowed. Read operations    are allowed.	Write operations are    blocked. New file mappings     are blocked. Read operations are    blocked.
Bit 0 = 1 Bit 1 = 1	Write operations are    allowed. New file mappings    are failed. Read operations are    allowed.	Write operations are    blocked. New file mappings    are failed. Read operations are    allowed.	Write operations are    blocked. New file mappings    are failed. Read operations are    blocked.
Calling an unlock physical or logical volume function on a level 1 lock completely releases the lock on the volume.


Level 2

The level 2 lock prevents all processes except the lock owner from writing to the disk, but the lock allows any application to read from it. Depending on the permissions set when the application obtained the level 1 lock, the system will either block or fail write operations and either allow or fail new file mappings. Before obtaining a level 3 lock, an application should call Get Lock Flag State (Interrupt 21h Function 440Dh Minor Code 6Ch) to determine if anything on the disk has changed, such as the swap file growing or shrinking. Calling Get Lock Flag State at this point is an optimization that is done to avoid obtaining the level 3 lock unnecessarily.

Calling an unlock physical or logical volume function on a level 2 lock decrements the lock level to 1 and causes the system to perform previously blocked operations that are allowed at the lower lock level.


Level 3

The level 3 lock prevents all processes except the lock owner from reading or writing to the disk. Read operations are blocked, and write operations and new file mappings are either blocked or failed depending on the permissions set in the level 1 lock. This is the most restrictive lock, not only because it prevents all other processes from accessing the disk but also because the lock owner is limited in what it can do.

Because read operations are blocked in the level 3 lock, an application must not execute any user interface or screen update functions, spawn applications, load dynamic-link libraries (DLLs), or yield to avoid deadlock. For example, if an application yields to a process with a discardable segment that the system has discarded, the system cannot reload the discarded segment because the process cannot read from the disk. This situation results in deadlock. Whenever a process obtains a level 3 lock, it should keep the lock for as short a period as possible to avoid severely degrading system performance. The purpose of the level 3 lock is to write changes to disk, so processes should only call disk I/O functions inside the lock.

After a level 3 lock is obtained, the file system takes several steps to allow a process to write directly to the disk. First, the system flushes all file system buffers and caches. Next, it puts the cache into write-through mode so that changes will be written to disk immediately. Finally, all open files are closed at the file system driver (FSD) level, which is invisible to all processes. While an application is in a level 3 lock, the system does not permit the swap file to grow or shrink, but it can still be read from or written to.

If an application has obtained a lock on a child volume, the system does not automatically flush the file system cache after a write operation to the parent volume. To ensure that the cache is flushed when Open or Create File (Interrupt 21h Function 716Ch) is used, the application should specify the OPEN_FLAGS_NO_BUFFERING (0100h) value. If the file has not been opened with OPEN_FLAGS_NO_BUFFERING or Absolute Disk Write (Interrupt 26h) has been used to write to the parent volume, the application should call Reset Drive (Interrupt 21h Function 710Dh) to flush the cache.

Before releasing the level 3 lock, the process is responsible for putting the file system into a state consistent with what existed before the lock was obtained. The process must be careful to correctly update all file system data, such as the FAT or directory entries. If a file was opened, it must not be deleted, renamed, or moved to a different volume. Otherwise, the system can become very unstable. An application should use Enumerate Open Files (Interrupt 21h Function 440Dh Minor Code 6Dh) to obtain a list of all open files on the volume.

When the level 3 lock is released, the system unblocks all pending read operations, reopens closed files on demand, and puts the cache back into write-behind mode. The lock owner returns to a level 2 lock.


Using the Locking Hierarchy

An application should obtain a level 1 lock before beginning an operation, such as a complete defragmentation or compression. The application should release the level 1 lock only after the entire operation is finished. This approach prevents other processes from obtaining a lock on the same disk, which would keep the lock owner from finishing its work.

To minimize the time spent in the level 3 lock, a process should remain in the level 2 lock to perform certain tasks, such as computing disk statistics and preparing data packets to be written before actually writing them in the level 3 lock. As soon as a process enters the level 3 lock, the application must call Get Lock Flag State (Interrupt 21h Function 440Dh Minor Code 6Ch) to determine if anything on the disk has changed, such as the swap file growing or shrinking. If a change has occurred, the process should release the level 3 lock, return to the level 2 lock to recompute any needed information, and then obtain the level 3 lock again. If Get Lock Flag State shows that the disk has not changed, the process should do its writing and then release the level 3 lock.


Swap File

The system pager requires access to the swap file at all times, even when an application has locked the volume containing the file. To ensure access, the system always gives the system pager the opportunity to accept or reject a lock request.

If the system grants a lock to a process, the requesting process must ensure that data for the swap file remains unchanged and that the pager can safely read from or write to the swap file at any time. In particular, the process must not change the allocation chain of the swap file, and if it moves the swap file's directory entry, it must ensure that the path to it is always consistent. Failure to observe these guidelines can result in a system crash.

An application can determine the directory entry and allocation chain of the swap file by retrieving the path of the file using Find Swap File (Interrupt 21h Function 440Dh Minor Code 6Eh).

The system permits the swap file to grow or shrink in the level 1 and 2 locks. Because of this, an application should call Get Lock Flag State (Interrupt 21h Function 440Dh Minor Code 6Ch) after obtaining a level 3 lock to determine if anything on the disk has changed as the result of the swap file growing or shrinking.


Virtual Devices

The system broadcasts a message to all virtual devices (VxDs) when an application makes a request for a lock. Any VxD that uses virtual block device and I/O supervisor services to carry out direct I/O on the given volume must check for this message and either accept or reject the request when the message is received.

If the VxD rejects the request, it must return the appropriate error value. In such cases, the system does not grant the lock to the requesting application. If a VxD accepts the request, it must avoid all operations that may affect the consistency of the volume for the duration of the lock.

When the application releases the lock, the system again issues a broadcast message. The VxD can resume normal operation at this point.


Volume-Locking Guidelines

Applications that lock and modify volumes should follow these guidelines to avoid degrading system performance and to prevent data loss:

•	If there are no open files on the volume, applications should perform direct disk writes in a level 0 lock. Otherwise, they should use the locking hierarchy and perform disk write operations in a level 3 lock.

•	Applications should utilize the locking hierarchy to minimize the time spent in a level 3 lock. They should only call disk I/O functions inside a level 3 lock and drop down to a level 1 or 2 lock whenever possible.

•	Applications should neither terminate or relinquish control nor leave a level 0 or 3 lock if the volume information is incomplete or invalid. When applications leave one of these locks, the file system must be consistent with what it was when they entered the lock because other applications will regain access to the drive.

•	Because the Interrupt 21h file handle I/O functions rely on accurate information about the volume, applications should not use these functions when the volume information is incomplete or invalid.

•	Applications should not move the swap file.

•	Applications should not move memory-mapped files opened for write access. Read-only memory-mapped files may be moved cluster by cluster.

•	Applications may only move 32-bit Windows-based DLLs and executables cluster by cluster.

•	Applications may move directory entries for the swap file and open memory-mapped files, but the path to them must always be consistent, even in a level 3 lock.

Because read operations are blocked in the level 3 lock, all applications written for 16-bit Windows, 32-bit Windows, or MS-DOS should follow these guidelines to avoid deadlock while in a level 3 lock:

•	Applications should only access the disk by using the low-level disk functions (Interrupt 13h, Interrupt 25h, and Interrupt 26h) or the Interrupt 21h file handle read, write, seek, and IOCTL functions. Other MS-DOS functions are not guaranteed to work. Windows or C run-time library file I/O functions should not be used, because these functions may contain code or call code that is not safe to execute inside the level 3 lock.

•	Applications should not yield control, update the screen, execute any user-interface code, or do anything else that could cause Windows 95 to load a new or previously discarded segment, such as by spawning an application or loading a DLL.

•	Windows-based applications must have all the code for a level 3 lock contained within the processing for a single message. The application should not process other messages or call any Windows functions.


Special Considerations for 32-bit Windows-Based Applications

32-bit Windows-based applications must call the exclusive volume-locking IOCTL functions indirectly by opening VWIN32.VXD and using its DeviceIoControl interface.

In response, VWIN32.VXD issues the low-level disk I/O functions (Interrupt 13h, Interrupt 25h, and Interrupt 26h) as well as the MS-DOS Interrupt 21h file handle read, write, seek, and IOCTL functions in the context of the calling process.

32-bit Windows-based applications may safely call the Windows ReadFile, WriteFile, SetFilePointer, and DeviceIoControl functions within a level 3 lock. Other Windows or C run-time library functions should not be used while in the level 3 lock, because these functions may call other functions that are not safe inside a level 3 lock.


Special Considerations for 16-bit Windows-Based Applications

16-bit Windows-based applications may call the exclusive volume-locking IOCTL functions directly using the Interrupt 21h interface, which is described in the reference material. These applications must mark all of the code, data, and resource segments that will be accessed while inside the level 2 and 3 locks as PRELOAD NONDISCARDABLE in the module-definition (.DEF) file. This marking prevents deadlock in case the system needs to load one of the application's segments from the executable file inside a level 3 lock.


Special Considerations for MS- DOS - Based Applications
Special Considerations for MS- DOS − Based Applications

MS-DOS − based applications may directly call the volume-locking IOCTL functions by using Interrupt 21h, as described in the reference material.

When a windowed MS-DOS − based application obtains a level 3 lock, the system forces it to full screen mode to avoid deadlock with the display driver. When the application releases the level 3 lock, it remains in full screen mode.

Applications must not call the Advanced SCSI Programming Interface (ASPI) functions inside a level 3 lock. These functions bypass the file system, leaving it in an inconsistent state.

When MS-DOS − based applications run in single MS-DOS application mode (real mode), they may issue the volume-locking IOCTL functions and the functions will succeed. However, because there is no multitasking, there is only one lock rather than a hierarchy as when Windows 95 is running. The volume-locking IOCTL functions will fail on down-level versions of MS-DOS.


Functions

The following functions can be used to manage exclusive volume locking.

Lock Logical Volume	Interrupt 21h Function 440Dh Minor Code 4Ah
Lock Physical Volume	Interrupt 21h Function 440Dh Minor Code 4Bh
Unlock Logical Volume	Interrupt 21h Function 440Dh Minor Code 6Ah
Unlock Physical Volume	Interrupt 21h Function 440Dh Minor Code 6Bh
Get Lock Flag State	Interrupt 21h Function 440Dh Minor Code 6Ch
Enumerate Open Files	Interrupt 21h Function 440Dh Minor Code 6Dh
Find Swap File	Interrupt 21h Function 440Dh Minor Code 6Eh
Get Current Lock State	Interrupt 21h Function 440Dh Minor Code 70h
Reset Drive	Interrupt 21h Function 710Dh
The exclusive-volume locking IOCTL functions are similar to other MS-DOS functions. An application must copy function parameters to registers and issue an Interrupt 21h instruction to carry out the call.


Reference

The following functions and structures are associated with exclusive-volume locking IOCTL.


Functions


Interrupt 21h Function 440Dh Minor Code 4Ah  Lock Logical Volume [New - Windows 95]
Interrupt 21h Function 440Dh Minor Code 4Ah  Lock Logical Volume

[New - Windows 95]

mov ax, 440Dh        ; generic IOCTL
mov bh, LockLevel    ; see below
mov bl, DriveNum     ; see below
mov ch, 08h          ; device category (must be 08h)
mov cl, 4Ah          ; Lock Logical Volume
mov dx, Permissions  ; see below
int 21h

jc error

Locks the logical volume.

•	Clears the carry flag if successful. Otherwise, the function sets the carry flag and sets the AX register to an error value.

LockLevel

Level of the lock. This parameter must be either 0, 1, 2, or 3.

DriveNum

Drive to lock. This parameter can be 0 for the default drive, 1 for A, 2 for B, and so on.

Permissions

Operations that the system permits while the volume is locked. This parameter is specified only when a level 1 lock is obtained or when a level 0 lock is obtained for the second time for formatting the volume. For other lock levels, this parameter is zero. When a level 1 lock is obtained, bits 0 and 1 of this parameter specify whether the system permits write operations, new file mappings, or both by other processes during a level 1 lock as well as during level 2 and 3 locks. If this parameter specifies that write operations, new file mappings, or both are failed, these operations are failed during level 1, 2, and 3 locks. This parameter has the following form:

Bit	Meaning
0	0 = Write operations are failed (specified when a level 1 lock is obtained).
0	1 = Write operations are allowed (specified when a level 1 lock is obtained).
1	0 = New file mapping are allowed (specified when a level 1 lock is obtained).
1	1 = New file mapping are failed (specified when a level 1 lock is obtained).
2	1 = The volume is locked for formatting (specified when a level 0 lock is obtained for the second time).
The volume must be locked before the application performs direct disk write operations by using Interrupt 26h or the IOCTL control functions. Lock Physical Volume (Interrupt 21h Function 440Dh Minor Code 4Bh) is used instead of this function before a call to an Interrupt 13h function. Unlock Logical Volume (Interrupt 21h Function 440Dh Minor Code 6Ah) should be used to release the lock.


Interrupt 21h Function 440Dh Minor Code 4Bh  Lock Physical Volume [New - Windows 95]
Interrupt 21h Function 440Dh Minor Code 4Bh  Lock Physical Volume

[New - Windows 95]

mov ax, 440Dh        ; generic IOCTL
mov bh, LockLevel    ; see below
mov bl, DriveNum     ; see below
mov ch, 08h          ; device category (must be 08h)
mov cl, 4Bh          ; Lock Physical Volume
mov dx, Permissions  ; see below
int 21h

jc error

Locks the physical volume.

•	Clears the carry flag if successful. Otherwise, the function sets the carry flag and sets the AX register to an error value.

LockLevel

Level of the lock. This parameter must be either 0, 1, 2, or 3.

DriveNum

Drive to lock. This parameter must be one of these values (same device unit numbers as for Interrupt 13h):

00 - 7Fh	Floppy disk drive (00 for the first floppy drive, 01 for the second, and so on).
80 - FFh	Hard disk drive (80 for the first hard disk drive, 81 for the second, and so on).
Permissions

Operations that the system permits while the volume is locked. This parameter is specified only when a level 1 lock is obtained or when a level 0 lock is obtained for the second time for formatting the volume. For other lock levels, this parameter is zero. When a level 1 lock is obtained, bits 0 and 1 of this parameter specify whether the system permits write operations, new file mappings, or both by other processes during a level 1 lock as well as during level 2 and 3 locks. If this parameter specifies that write operations, new file mappings, or both are failed, these operations are failed during level 1, 2, and 3 locks. This parameter has the following form:

Bit	Meaning
0	0 = Write operations are failed (specified when a level 1 lock is obtained).
0	1 = Write operations are allowed (specified when a level 1 lock is obtained).
1	0 = New file mapping are allowed (specified when a level 1 lock is obtained).
1	1 = New file mapping are failed (specified when a level 1 lock is obtained).
2	1 = The volume is locked for formatting (specified when a level 0 lock is obtained for the second time).
The volume must be locked before the application performs direct disk write operations by using Interrupt 13h, Interrupt 26h, or the Interrupt 21h IOCTL functions. A single physical volume may be divided into more than one logical volume, which is also called a partition. The system automatically takes a logical volume lock on all logical volumes on the specified physical drive. If the application performs disk writes only to a logical drive, Lock Logical Volume (Interrupt 21h Function 440Dh Minor Code 4Ah) is used instead of this function. Unlock Physical Volume (Interrupt 21h Function 440Dh Minor Code 6Bh) should be called to release the lock.


Interrupt 21h Function 440Dh Minor Code 6Ah  Unlock Logical Volume [New - Windows 95]
Interrupt 21h Function 440Dh Minor Code 6Ah  Unlock Logical Volume

[New - Windows 95]

mov ax, 440Dh      ; generic IOCTL
mov bl, DriveNum   ; see below
mov ch, 08h        ; device category (must be 08h)
mov cl, 6Ah        ; Unlock Logical Volume
int 21h

jc error

Unlocks the logical volume or decrements the lock level.

•	Clears the carry flag if successful. Otherwise, the function sets the carry flag and sets the AX register to an error value.

DriveNum

Drive to unlock. This parameter can be 0 for the default drive, 1 for A, 2 for B, and so on.

This function is used to release the lock obtained by using Lock Logical Volume (Interrupt 21h Function 440Dh Minor Code 4Ah). Only the lock owner can release the lock on a volume.

To release the lock on the volume, an application must call Unlock Logical Volume the same number of times that Lock Logical Volume was called.


Interrupt 21h Function 440Dh Minor Code 6Bh  Unlock Physical Volume [New - Windows 95]
Interrupt 21h Function 440Dh Minor Code 6Bh  Unlock Physical Volume

[New - Windows 95]

mov ax, 440Dh      ; generic IOCTL
mov bl, DriveNum   ; see below
mov ch, 08h        ; device category (must be 08h)
mov cl, 6Bh        ; Unlock Physical Volume
int 21h

jc enter

Unlocks the physical volume or decrements the lock level.

•	Clears the carry flag if successful. Otherwise, the function sets the carry flag and sets the AX register to an error value.

DriveNum

Drive to unlock. This parameter must be one of these values (same device unit numbers as for Interrupt 13h):

00 - 7Fh	Floppy disk drive (00 for the first floppy drive, 01 for the second, and so on).
80 - FFh	Hard disk drive (80 for the first hard disk drive, 81 for the second, and so on).
This function is used to release the lock obtained by using Lock Physical Volume (Interrupt 21h Function 440Dh Minor Code 4Bh). Only the lock owner can release the lock on a volume.

To release the lock on the volume, an application must call Unlock Physical Volume the same number of times that Lock Physical Volume was called.


Interrupt 21h Function 440Dh Minor Code 6Ch  Get Lock Flag State [New - Windows 95]
Interrupt 21h Function 440Dh Minor Code 6Ch  Get Lock Flag State

[New - Windows 95]

mov ax, 440Dh        ; generic IOCTL
mov bl, DriveNum     ; see below
mov ch, 08h          ; device category (must be 08h)
mov cl, 6Ch          ; Get Lock Flag State
int 21h

jc error
mov [AccessFlag], ax  ; state of access flag

Polls the state of the access flag on a volume to determine if a write operation (for example, deleting or renaming a file or writing to a file) or a new file mapping has occurred since the last poll.

•	Clears the carry flag and sets the AX register to one of the following values if successful:

0	No write operations or file mappings have occurred since the last poll.
1	A write operation has occurred since the last poll (clears the volume access flag).
2	A file mapping has occurred since the last poll, or a 32-bit Windows-based DLL or executable has been opened (clears the volume access flag).
Otherwise, the function sets the carry flag and sets the AX register to an error value.

DriveNum

Drive to poll. This parameter can be 0 for the default drive, 1 for A, 2 for B, and so on.

Only the current lock owner may poll the access flag. The system fails other processes with ERROR_ACCESS_DENIED error value. Write operations performed by the lock owner do not cause a change in the state of the access flag.

When a lock is obtained that allows write operations or new file mappings, the system sets a flag whenever one of these operations happens on the volume. If a write operation or new file mapping has occurred since the last poll, Get Lock Flag State returns 1 or 2 respectively in the AX register and clears the volume access flag. If the swap file has grown or shrunk since the last poll, Get Lock Flag State returns 1. Note that write operations to the swap file that do not cause a change in size do not cause a change in the state of the access flag. If a 32-bit Windows-based DLL or executable has been opened since the last poll, Get Lock Flag State returns 2.


Interrupt 21h Function 440Dh Minor Code 6Dh  Enumerate Open Files [New - Windows 95]
Interrupt 21h Function 440Dh Minor Code 6Dh  Enumerate Open Files

[New - Windows 95]

mov ax, 440Dh           ; generic IOCTL
mov bx, DriveNum        ; see below
mov ch, 08h             ; device category (must be 08h)
mov cl, 6Dh             ; Enumerate Open Files
mov dx, seg PathBuf     ; see below
mov ds, dx
mov dx, offset PathBuf
mov si, FileIndex       ; see below
mov di, EnumType        ; see below
int 21h

jc  error
mov [OpenMode], ax      ; mode file was opened in
mov [FileType], cx      ; normal file or memory-mapped file

Enumerates open files on the specified drive.

•	Clears the carry flag, copies the path of an open file to the given buffer, and sets the AX and CX registers to the following values if successful:

AX	Mode that the file was opened in, which is a combination of access mode, sharing mode, and open flags. It can be one value each from the access and sharing modes and any combination of open flags.
	Access modes
	OPEN_ACCESS_READONLY (0000h)
	OPEN_ACCESS_WRITEONLY (0001h)
	OPEN_ACCESS_READWRITE (0002h)
	OPEN_ACCESS_RO_NOMODLASTACCESS (0004h)
	Share modes
	OPEN_SHARE_COMPATIBLE (0000h)
	OPEN_SHARE_DENYREADWRITE (0010h)
	OPEN_SHARE_DENYWRITE (0020h)
	OPEN_SHARE_DENYREAD (0030h)
	OPEN_SHARE_DENYNONE (0040h)
	Open flags
	OPEN_FLAGS_NOINHERIT (0080h)
	OPEN_FLAGS_NO_BUFFERING (0100h)
	OPEN_FLAGS_NO_COMPRESS (0200h)
	OPEN_FLAGS_ALIAS_HINT (0400h)
	OPEN_FLAGS_NOCRITERR (2000h)
	OPEN_FLAGS_COMMIT (4000h)
CX	File type. It can be one of the following values:
	0	For normal files
	1	For a memory-mapped files (memory-mapped files are unmovable)
	2	For any other unmovable files (32-bit Windows-based DLLs and executables)
	4	For the swap file
Note that if a memory-mapped file is returned (CX = 1), the value returned in the AX register is limited to the following values:

OPEN_ACCESS_READONLY (0000h)
OPEN_ACCESS_READWRITE (0002h)
Otherwise, the function sets the carry flag and sets the AX register to the following error value:

ERROR_ACCESS_DENIED	The value of FileIndex exceeds the number of open files on the drive.
DriveNum

Drive on which to enumerate the files. This parameter can be 0 for the default drive, 1 for A, 2 for B, and so on.

PathBuf

Address of a buffer that receives the path of the open file. The length of the buffer varies depending on the volume. Get Volume Information (Interrupt 21h Function 71A0h) is used to determine the maximum allowed length of a path for the volume.

FileIndex

Index of the file to retrieve the path for.

EnumType

Kind of file to enumerate. This parameter can be 0 to enumerate all open files or 1 to enumerate only open unmovable files, including open memory-mapped files and other open unmovable files (32-bit Windows-based DLLs and executables).

This function returns information about one file at a time. To enumerate all open files, the function must be called repeatedly with FileIndex set to a new value for each call. FileIndex should be set to zero initially and then incremented by one for each subsequent call. The function returns the ERROR_NO_MORE_FILES error value when all open files on the volume have been enumerated.

This function may return inconsistent results when used to enumerate files on an active volume — that is, on a volume where other processes may be opening and closing files. Applications should use Lock Logical Volume (Interrupt 21h Function 440Dh Minor Code 4Ah) to take a level 3 lock before enumerating open files.


Interrupt 21h Function 440Dh Minor Code 6Eh  Find Swap File [New - Windows 95]
Interrupt 21h Function 440Dh Minor Code 6Eh  Find Swap File

[New - Windows 95]

mov ax, 440Dh           ; generic IOCTL
mov ch, 08h             ; device category (must be 08h)
mov cl, 6Eh             ; Find Swap File
mov dx, seg PathBuf     ; see below
mov ds, dx
mov dx, offset PathBuf
int 21h

jc  error
mov [PagerType], ax            ; pager type
mov WORD PTR [FileSize], bx    ; swap file size in 4K pages
mov WORD PTR [FileSize+2], cx

Retrieves information about the swap file.

•	Clears the carry flag, copies the swap file path to the given buffer, and sets the following registers if successful:

AX	Pager type. It can be 1 for no pager, 2 for paging through MS-DOS, and 3 for paging through the protected-mode input and output (I/O) supervisor.
CX:BX	Current size of the swap file in 4K pages.
Otherwise, this function sets the carry flag and sets the AX register to an error value.

PathBuf

Address of the buffer that receives the path of the swap file. To determine the maximum allowed length of a path for the volume, call Get Volume Information (Interrupt 21h Function 71A0h).


Interrupt 21h Function 440Dh Minor Code 70h  Get Current Lock State [New - Windows 95]
Interrupt 21h Function 440Dh Minor Code 70h  Get Current Lock State

[New - Windows 95]

mov ax, 440Dh        ; generic IOCTL
mov bl, DriveNum     ; see below
mov ch, 08h          ; device category (must be 08h)
mov cl, 70h          ; Get Current Lock State
int 21h

jc error

Retrieves the current lock level and permissions on the specified drive.

•	Clears the carry flag and sets the AX and CX registers to these values if successful:

AX	Current lock level. It may be either  0, 1, 2 or 3. If the volume is not locked, AX contains  − 1
CX	Lock permissions. The bits have the following form:
Bit	Meaning
0	0 = Write operations are failed.
0	1 = Write operations are allowed, unless they are blocked by the lock level.
1	0 = New file mapping are allowed, unless they are blocked by the lock level.
1	1 = New file mapping are failed.
2	1 = The volume is locked for formatting.
DriveNum

Drive to retrieve lock information about. This parameter can be 0 for the default drive, 1 for A, 2 for B, and so on.

The lock level and the permissions determine the kind of access processes other than the lock owner have to the volume while it is locked. The following operations are allowed by processes other than lock owner at each lock level:

Level	Operations
0	Read operations, write operations, and new file mappings are failed.
1	Read operations are allowed. Write operations and new file mappings are either allowed or failed based on permissions.
2	Read operations are allowed. Write operations and new file mappings are either failed or blocked based on permissions.
3	Read operations are blocked. Write operations and new file mappings are either failed or blocked based on permissions.


Interrupt 21h Function 710Dh  Reset Drive [New - Windows 95]
Interrupt 21h Function 710Dh  Reset Drive

[New - Windows 95]

mov ax, 710Dh      ; Reset Drive
mov cx, Flag       ; see below
mov dx, DriveNum   ; see below
int 21h

jc  error

Flushes file system buffers and caches and optionally remounts the drivespace volume. Any write operations that the system has buffered are performed, and all waiting data is written to the appropriate drive.

•	This function has no return value.

Flag

Flag specifying whether the system should flush and invalidate the data in the cache as well as the file system buffers. This parameter must be one of these values:

0000h	Resets the drive and flushes the file system buffers for the given drive.
0001h	Resets the drive, flushes the file system buffers, and flushes and invalidates the cache for the specified drive.
0002h	Remounts the drivespace volume.
The Flag value of 0002h is only supported on drivespace volumes. You should specify this value when the on-media format of the drivespace volume has changed and you want the file system to reinitialize and read the new format.

DriveNum

Drive to reset. This parameter can be 0 for the default drive, 1 for A, 2 for B, and so on.


Program Information File Management

This article describes program information file management and the corresponding functions and structures provided by the dynamic-link library (DLL) called PIFMGR.DLL.


About Program Information File Management

Program information file management lets Microsoft® Windows® − based applications create, examine, and modify program information files (.PIF files). Program information files contain the detailed information needed by the operating system to prepare virtual machines for running Microsoft® MS-DOS® − based applications. Installation programs and other applications can open the files, retrieve and set information in these files, and display the information to the user for editing.


Program Information Files

A .PIF file contains information about the properties of an MS-DOS − based application. These properties define how the application uses resources, such as memory, and specify the computer's devices, the virtual machine, and the window that the application is displayed in.

A .PIF file typically has the same filename as the corresponding MS-DOS − based application, but with the .PIF filename extension. Every .PIF file contains one or more sections called information groups. Each group has a unique name or ordinal. Applications use the name or ordinal to identify the group to be examined or modified.

Many groups are predefined and have associated structures that define the content of the group. The following predefined groups are listed by their ordinal.

Group ordinal	Information
GROUP_ENV	Environment. This group uses a PROPENV structure.
GROUP_FNT	Fonts. This group uses a PROPFNT structure.
GROUP_KBD	Keyboard. This group uses a PROPKBD structure.
GROUP_MEM	Memory. This group uses a PROPMEM structure.
GROUP_MSE	Mouse. This group uses a PROPMSE structure.
GROUP_PRG	Program. This group uses a PROPPRG structure.
GROUP_TSK	Task. This group uses a PROPTSK structure.
GROUP_VID	Video. This group uses a PROPVID structure.
GROUP_WIN	Windows. This group uses a PROPWIN structure.
The following predefined groups are identified by name (null-terminated string).

Group name	Information
AUTOEXECBAT 4.0	AUTOEXEC.BAT file image used for an application if the application is marked to run in MS-DOS mode.
CONFIG SYS 4.0	CONFIG.SYS file image used for an application if the application is marked to run in MS-DOS mode.
MICROSOFT PIFEX	Windows versions 1. x and 2. x information.
WINDOWS 286 3.0	Windows version 3. x standard mode information. This group uses a W286PIF30 structure.
WINDOWS 386 3.0	Windows version 3. x enhanced mode information. This group uses a W386PIF30 structure.
WINDOWS VMM 4.0	Windows 95 information. This group uses a WENHPIF40 structure.
Applications can also create new groups called PIF extensions to store information that is specific to the given MS-DOS − based application. All new groups are identified by name only, and the format of the information is entirely application-defined. If PIF extensions are used to store application-specific information, applications do not need to store the information in .INI files.

Program information file management supports .PIF files in these formats: Windows version 1. x, Windows version 2. x, Windows version 3. x, and Windows 95.


Properties

To access the properties in a .PIF file, you first open the file by using the OpenProperties function. You can open a .PIF file directly by supplying the name of the file. Otherwise, you can supply the name of an MS-DOS − based application (that is, a file having the .COM, .EXE, or .BAT filename extension), and the function will open the corresponding .PIF file. If the function does not find the .PIF file in the current directory, it searches the WINDOWS directory, the Windows SYSTEM directory, the Windows PIF directory, and finally the directories on the current path to locate the file.

After opening the .PIF file, OpenProperties loads the properties into memory and returns a properties handle that you use in subsequent functions to identify the information. If you try to open a .PIF file that does not exist, the function creates a temporary file in memory and initializes it using internal data or data from the _DEFAULT.PIF file. To locate _DEFAULT.PIF, the function first searches the PIF directory and then searches for it in the directories on the current path. Unlike Windows version 3.1, Windows 95 does not create a _DEFAULT.PIF file. A system will have a _DEFAULT.PIF file only if it inherited one from a Windows version 3.1 installation, or if one was created manually.

You can retrieve individual properties by using the GetProperties function. You specify the property to retrieve by group name or ordinal. The name can be any predefined name, as given in the previous section, or the name of your own group. If you do not know the size of the information group, you can determine it by using the GetProperties function, specifying zero as the size. The function copies no data, but it returns the size of the requested group. You use this size in a subsequent call to retrieve the group.

You can change property information by using the SetProperties function. You specify the property to change by group name or ordinal and provide a copy of the new information. SetProperties typically saves changes to disk as you make the changes. You can direct SetProperties to cache the changes in memory by specifying the SETPROPS_CACHE value. Caching the changes lets you use the FlushProperties function later to either discard the changes or save them to disk.

You can create your own information group by using the SetProperties function, specifying the format for the information in the group. The operating system returns the information in exactly the same format as you create it. You can also use SetProperties to remove an information group.

Once you have finished using the properties information from a .PIF file, you must close it by using the CloseProperties function. If you make changes to a temporary file, CloseProperties will permanently save the property information in a new file on disk.

You can enumerate all loaded .PIF files by using the EnumProperties function. Each call to the function retrieves a properties handle, which you can use in the next call to EnumProperties to retrieve the next handle. The function returns zero when all open properties have been enumerated.

You can enumerate all named information groups associated with a properties handle by using the GetProperties function. The function copies the name of the group that corresponds to a zero-based group index to the specified 16-byte buffer. You can continue to call GetProperties, incrementing the index before each call, to retrieve all group names. The function returns zero when all groups have been enumerated. To minimize disk usage, the PIF manager does not store an information group if all settings have default values. This means that GetProperties may return the name of a group for which no PIF extension actually exists.

You can let the user edit property information by using the EditProperties function. The function displays a property sheet for each group listed in the previous section. When the user chooses a sheet, the function displays all the properties within the group and allows the user to edit the properties. EditProperties saves any changes, copying them back to the .PIF file. Some changes may not affect currently running applications, but they will apply to subsequently started applications.

The operating system may associate a given virtual machine or window handle with a specific set of properties. You can determine which handles are associated with a given set by using the AssociateProperties function. Generally, only system components should change these associations.

You can retrieve a complete copy of the .PIF file by specifying the OPENPROPS_RAWIO value when opening the file by using the OpenProperties function. Reading or writing the entire file requires a thorough understanding of the .PIF file format and is not recommended.


Property Sheets

A property sheet is a set of controls that gives users access to the information in an information group. Property sheets are used by the EditProperties function to create a dialog box that displays the current values for settings in the information group and lets users edit those values. EditProperties uses default property sheets for each of the predefined information groups, but the function requires custom property sheets for any information groups that contain application-specific information.

An application or DLL can add a property sheet to the system by using the AddPropertySheet function. Before adding the property sheet, you must fill a PROPSHEETPAGE structure with names or values identifying the dialog box template, dialog box procedure, icon resource, and other resources to be used to display and manage the property sheet. Property sheets can be simple or advanced. Simple property sheets typically display a small set of values from the information group, and advanced property sheets display all values. You specify the property sheet type when you add the property sheet to the .PIF file.

You can retrieve information about the property sheets associated with a .PIF file by using the EnumPropertySheets function. For each property sheet, the function copies information, such as the name of the dialog box template and dialog box procedure, to a PROPSHEETPAGE structure. To use EnumPropertySheets, you must first load the property sheets by using the LoadPropertySheets function. After retrieving the property sheet information, you should free the loaded sheets by using the FreePropertySheets function.

To remove a property sheet from the system, use the RemovePropertySheet function.


Property Libraries

A property library is a DLL that provides dialog box templates and procedures for displaying property sheets and editing properties. Property libraries let you develop property sheets for information groups that are specific to your MS-DOS − based applications. These libraries ensure that system applications, such as the shell, can display the application-specific information and allow users to edit it.

You can register a property library by using the LoadPropertyLib function. The function records the name of the library and returns a handle, but it does not actually load the library. You use the handle when adding property sheets to the .PIF file to identify the library containing the template and dialog box procedure for the property sheet. The system eventually loads the library when the user attempts to access the property sheet. You can enumerate the currently registered property libraries by using the EnumPropertyLibs function. When you no longer need a given property library, you should free it by using the FreePropertyLib function.


Properties and Virtual Devices

Virtual devices (VxDs) also have access to information in .PIF files. This means that any VxDs you create to support MS-DOS − based applications can use information in the .PIF file. Typically, you add a specific PIF extension for use by the VxD and create corresponding a property sheet to give the user the opportunity to edit the information.

A VxD cannot retrieve property information directly. Instead, it installs a callback procedure using the SHELL_Hook_Properties service provided by the Shell virtual device (SHELL.VXD). The system notifies the VxD of changes to the properties by calling the callback procedure. The VxD can install callback procedures as either predefined or customized groups.


Reference

The following functions and structures are associated with program information file management.


Functions

The following functions are used with program information file management.


AddPropertySheet [New - Windows 95]
AddPropertySheet

[New - Windows 95]

int AddPropertySheet(LPPROPSHEETPAGE lppsi, int iType)

Adds a new property sheet.

•	Returns a property sheet handle if successful or NULL otherwise.

lppsi

Address of the PROPSHEETPAGE structure containing the property sheet information.

iType

Sheet type. This parameter can be either the SHEETTYPE_SIMPLE or SHEETTYPE_ADVANCED value.


AssociateProperties [New - Windows 95]
AssociateProperties

[New - Windows 95]

long AssociateProperties(int hProps, int iAssociate, long lData)

Associates data with the given property information. This function can also return the currently associated data without associating new data.

•	Returns the data previously associated with the given index data. If no data was previously associated or an error occurs, the function returns zero.

hProps

Properties handle. It must have been created previously by using the OpenProperties function.

iAssociate

Association index. This parameter can be the HVM_ASSOCIATION or HWND_ASSOCIATION value.

lData

Data to associate. This parameter can be any 32-bit value or address.

Association of data is reserved exclusively for system components. Applications may use this function to retrieve the associated data, but they must not set the associated data.

If iAssociate is negative, the currently associated value is returned, but it is not modified. In other words, lData is ignored.


CloseProperties [New - Windows 95]
CloseProperties

[New - Windows 95]

int CloseProperties(int hProps, int flOpt)

Closes the property information for the application.

•	Returns NULL if successful or the properties handle otherwise.

hProps

Properties handle. It must have been created previously by using the OpenProperties function.

flOpt

Operation flag. This parameter can be the CLOSEPROPS_DISCARD value to discard the data or zero to save cached program information data by copying it to the .PIF file on disk.


EditProperties [New - Windows 95]
EditProperties

[New - Windows 95]

int EditProperties(int hProps, LPSTR lpszTitle, UINT uStartPage,
    HWND hwnd, UINT uMsgPost)

Displays the editing dialog box, allowing the user to edit the given property sheet information.

•	Returns TRUE if successful or FALSE otherwise.

hProps

Properties handle. It must have been created previously by using the OpenProperties function.

lpszTitle

Address of null-terminated string specifying the title of the editing dialog box. If no title is needed, this parameter can be NULL.

uStartPage

Number of the first property sheet to edit.

hwnd

Parent window handle. If no parent window needed, this parameter can be NULL.

uMsgPost

Notification message value. If no notification message is needed, this parameter can be zero. If it is not zero, the function posts a message having this value to the parent window whenever properties change. The wParam parameter in the posted message specifies the size of the changed data, and the lParam parameter specifies the name or ordinal of the changed group.


EnumProperties [New - Windows 95]
EnumProperties

[New - Windows 95]

int EnumProperties(int hProps)

Enumerates all open properties handles.

•	Returns a properties handle or zero if all properties have been enumerated.

hProps

Properties handle. It must have been previously returned by EnumProperties, or it must be NULL to start enumeration.


EnumPropertyLibs [New - Windows 95]
EnumPropertyLibs

[New - Windows 95]

int EnumPropertyLibs(int iLib, LPHANDLE lphDLL, LPSTR lpszDLL,
    int cbszDLL)

Enumerates property libraries, filling the variables with the module handle and name of each library.

•	Returns a library identifier if successful. If all libraries have been enumerated or an error occurs, the function returns zero.

iLib

Library identifier. It must have been previously returned by the EnumPropertyLibs function or must be zero to start enumeration.

lphDLL

Address of the variable that receives the module handle of the library. If the handle is not needed, this parameter can be NULL.

lpszDLL

Address of the buffer that receives the zero-terminated name of the library. If the name is not needed, this parameter can be NULL.

cbszDLL

Size, in bytes, of the buffer pointed to by lpszDLL.


EnumPropertySheets [New - Windows 95]
EnumPropertySheets

[New - Windows 95]

int EnumPropertySheets(int hProps, int iType, int iSheet,
    LPPROPSHEETPAGE lppsi)

Enumerates property sheets.

•	Returns a property sheet handle if successful. If all property sheets have been enumerated or an error occurs, the function returns zero.

hProps

Properties handle. It must have been created previously by using the Open Properties function.

iType

Sheet type. This parameter can be either the SHEETTYPE_SIMPLE or SHEETTYPE_ADVANCED value.

iSheet

Property sheet handle. It must have been previously returned by EnumPropertySheets or must be zero to start enumeration.

lppsi

Address of the PROPSHEETPAGE structure that receives the property sheet information.


FlushProperties [New - Windows 95]
FlushProperties

[New - Windows 95]

int FlushProperties(int hProps, int flOpt)

Flushes or discards cached property information. The function flushes data by copying the data to the corresponding .PIF file on disk.

•	Returns TRUE if successful or FALSE otherwise.

hProps

Properties handle. It must have been created previously by using the OpenProperties function.

flOpt

Operations flag. This parameter can be the FLUSHPROPS_DISCARD value to discard the cached program information data or zero to flush the data to the corresponding .PIF file.


FreePropertyLib [New - Windows 95]
FreePropertyLib

[New - Windows 95]

BOOL FreePropertyLib(int hLib)

Frees an installable property library.

•	Returns TRUE if successful or FALSE otherwise.

hLib

Handle of the property library.


FreePropertySheets [New - Windows 95]
FreePropertySheets

[New - Windows 95]

int FreePropertySheets(int hProps, int flags)

Frees all property sheets for the .PIF file identified by the given properties handle.

•	No return value.

hProps

Properties handle. It must have been created previously by using the OpenProperties function.

flags

Reserved; must be zero.


GetProperties [New - Windows 95]
GetProperties

[New - Windows 95]

int GetProperties(int hProps, LPSTR lpszGroup, LPVOID lpProps,
    int cbProps, int flOpt)

Retrieves property information for the given group; retrieves the size, in bytes, of the property information; or enumerates all named groups in the .PIF file.

•	Returns the size, in bytes, of the information retrieved if successful. If the group is not found, all groups have been enumerated, or an error occurred, the function returns zero.

hProps

Properties handle.

lpszGroup

Group ordinal, address of a null-terminated string specifying the name of the property group, or NULL. If a name is given, it must be the name of a valid PIF extension or one of these predefined group names:

MICROSOFT PIFEX	WINDOWS 386 3.0
WINDOWS 286 3.0	WINDOWS VMM 4.0
If a group ordinal is given, it can be one of these predefined ordinals:

GROUP_ENV	GROUP_PRG
GROUP_KBD	GROUP_TSK
GROUP_MEM	GROUP_VID
GROUP_MSE	GROUP_WIN
The ordinal must be in the low-order word, and zero must be in the high-order word.

If NULL is specified, the function enumerates all named groups. In this case, cbProps must be a zero-based group name index, and lpProps must be the address of the 16-byte buffer that receives the name of the given group.

lpProps

Address of the buffer that receives the property information. The size of the buffer depends on the type of information retrieved.

cbProps

Size, in bytes, of the buffer pointed to by lpProps. If cbProps is zero and lpszGroup is not NULL, the function returns the size of the corresponding property information without copying that information to the lpProps buffer.

flOpt

Operations flag. This parameter can be the GETPROPS_RAWIO value to read the entire .PIF file as a single, unformatted block (that is, lpszGroup is ignored) or zero to read the given group.


LoadPropertyLib [New - Windows 95]
LoadPropertyLib

[New - Windows 95]

int LoadPropertyLib(LPSTR lpszDLL, int fLoad)

Loads a property library.

•	Returns the handle of the property library if successful or FALSE otherwise.

lpszDLL

Address of a null-terminated string specifying the name of a property library.

fLoad

Load flags. This parameter can be either zero or the LOADPROPLIB_.DEFER value. Specifying LOADPROPLIB_.DEFER defers loading of the property library until LoadPropertySheets is called and automatically unloads the library when FreePropertySheets is called. LoadPropertySheets and FreePropertySheets may be called directly by an application or indirectly when an application calls the EditProperties function. When a deferred library is loaded, its initialization handler must call AddPropertySheet for all the sheets to be added. When the deferred library is unloaded, its Windows exit procedure (WEP) handler must call RemovePropertySheet for all added sheets if it has not already freed them.


LoadPropertySheets [New - Windows 95]
LoadPropertySheets

[New - Windows 95]

int LoadPropertySheets(int hProps, int flags)

Loads all property sheets for the .PIF file identified by the given properties handle.

•	Returns the number of sheets loaded if successful or zero otherwise.

hProps

Properties handle. It must have been created previously by using the  OpenProperties function.

flags

Reserved; must be zero.


OpenProperties [New - Windows 95]
OpenProperties

[New - Windows 95]

int OpenProperties(LPSTR lpszApp, LPSTR lpszPIF, int hInf, int flOpt)

Opens the .PIF file associated with the given application and returns a properties handle that identifies the property information for the application.

•	Returns a properties handle if successful. If the .PIF file cannot be opened or there is insufficient memory to load the PIF data, the function returns FALSE.

lpszApp

Address of a null-terminated string specifying the filename of an MS-DOS − based application.

lpszPIF

Address of a null-terminated string specifying a new PIF filename to create. If the file is created successfully, the returned properties handle operates on that file. Any .PIF file for the specified MS-DOS − based application that exists in the PIF directory or on the path is still opened and read to obtain the initial set of properties to be stored in the new .PIF file.

hInf

Information handle. This parameter can be zero if no information handle is needed or  − 1 to prevent information processing. If zero is specified, the APPS.INF file is used by default.

flOpt

Operations flag. This parameter can be the OPENPROPS_RAWIO value to open the .PIF file for raw file input and output (I/O) or zero to open the file for standard access.

The function loads the content of the given .PIF file into memory and then closes the file, preserving the contents in memory until the properties handle is closed. If the given .PIF file does not exist, the function allocates memory and loads it with default PIF data. This function fails if there is insufficient memory for the PIF data or the given .PIF file exists but cannot be opened.


RemovePropertySheet [New - Windows 95]
RemovePropertySheet

[New - Windows 95]

BOOL RemovePropertySheet(int hSheet)

Removes a property sheet.

•	Returns TRUE if successful or FALSE otherwise.

hSheet

Property sheet handle. It must have been previously created by using the AddPropertySheet function.


SetProperties [New - Windows 95]
SetProperties

[New - Windows 95]

int SetProperties(int hProps, LPSTR lpszGroup, LPVOID lpProps,
    int cbProps, int flOpt)

Sets property information for the given group, removes the given group from the .PIF file, or writes raw data to the .PIF file.

•	Returns the number of information bytes written to the .PIF file if successful. If the group does not exist or an error occurs, the function returns zero.

hProps

Properties handle. It must have been previously opened by using the OpenProperties function.

lpszGroup

Group ordinal or address of a null-terminated string specifying the name of the property group. If a name is given, it must be the name of a valid PIF extension or one of these predefined names:

MICROSOFT PIFEX	WINDOWS 386 3.0
WINDOWS 286 3.0	WINDOWS VMM 4.0
If a group ordinal is given, it can be one of these predefined ordinals:

GROUP_ENV	GROUP_PRG
GROUP_KBD	GROUP_TSK
GROUP_MEM	GROUP_VID
GROUP_MSE	GROUP_WIN
The ordinal must be in the low-order word, and zero must be in the high-order word.

lpProps

Address of the buffer that contains the property information to write to the .PIF file.

cbProps

Size, in bytes, of the information pointed to by lpProps. If cbProps is zero and lpszGroup is not NULL, the function removes the given group from the .PIF file.

flOpt

Operations flag. This parameter can be one of these values:

0	Writes information to the given group.
SETPROPS_RAWIO	Writes data to the .PIF file as if it were a single, unformatted block. (The lpszGroup parameter is ignored).
SETPROPS_CACHE	Caches changes until properties are closed by using the CloseProperties function.


Structure

The following structure is used with program information file management.


PROPSHEETPAGE [New - Windows 95]
PROPSHEETPAGE

[New - Windows 95]

typedef struct _PROPSHEETPAGE {
    DWORD  dwSize;           // size of structure, in bytes
    DWORD  dwFlags;          // see below
    HINSTANCE  hInstance;    // instance handle for template
    union {
        LPCSTR  pszTemplate;        // resource name of template
        const VOID FAR *pResource;  // address of resource in memory
    };
    union {
        HICON       hIcon;   // icon handle
        LPCSTR      pszIcon; // icon name or identifier
    };
    LPCSTR      pszTitle;    // string or string identifier
    DLGPROC     pfnDlgProc;  // address of dialog box procedure
    LPARAM      lParam;      // user data
    LPFNRELEASEPROPSHEETPAGE pfnRelease; // see below
    UINT FAR * pcRefParent;  // address of ref count variable
} PROPSHEETPAGE, FAR *LPPROPSHEETPAGE;

Contains information about the property sheet.

dwFlags

Flags identifying which members contain valid values. This member can be a combination of these values:

PSP_DEFAULT	The pszTemplate member contains address of resource template name. The pResource member is not valid. The hIcon, pszIcon, pfnRelease, and pcRefParent members are not used.
PSP_DLGINDIRECT	The pResource member contains address of a dialog box template in memory. The pszTemplate member is not valid.
PSP_USEICON	The hIcon member contains a valid icon handle.  The pszIcon member is not valid.
PSP_USEICONID	The pszIcon member contains the address of a valid resource name or resource identifier. The hIcon member is not valid.
PSP_USERELEASEFUNC	The pfnRelease member has the address of the function to call before releasing the property sheet.
PSP_USERREFPARENT	The pcRefParent member contains the address of the variable to the receive reference count.
pfnRelease

Address of the release function. The operating system calls this function before destroying the given property sheet.


Virtual Machine Services

This article describes the virtual machine services and shows how to use them in MS-DOS − based applications.


About Virtual Machine Services

Virtual machine services allow Microsoft® MS-DOS® − based applications to take advantage of features provided by Microsoft® Windows® 95 when the applications run in a window. MS-DOS − based applications can retrieve and, optionally, set the title of the window in which they run.


Window Title

The window title for an MS-DOS − based application, which is displayed when the application runs in a window, identifies the application and its operating state. The operating system sets the title when an application first starts, but the application can change portions of the title to better communicate its state to the user.

The window title consists of three strings: a virtual machine state, a virtual machine title, and an application title. The system creates the window title by concatenating the three strings, separating the strings with a system-defined separator, typically a hyphen.

The virtual machine state, which can be set by the operating system only, identifies whether the virtual machine is inactive or whether the user is carrying out tasks, such as cut and paste operations. The state is frequently an empty string. The virtual machine title and the application title, which can be set by an application, identify the application and the current document or activity of the application, respectively.

By default, the operating system sets the virtual machine title to the title stored in the corresponding .PIF file or to a title specified by the shell. You can determine the current virtual machine title by using the Get Virtual Machine Title function. You can change the title by using the Set Virtual Machine Title function.

The system typically sets the application title to the name of the application, so the virtual machine title and application title are frequently the same when the application first starts. Many applications change this title to the name of the current document or to an empty string if there is no current document. You can determine the current application title by using the Get Application Title function. You can change the title by using the Set Application Title function.

If you set the virtual machine title or application title, the length of the individual titles must not exceed 30 and 80 characters, respectively.

You can call the window title functions at any time. Furthermore, you can call these functions regardless of whether your application is running with the Windows 95 or MS-DOS operating system. However, not all operating systems support these calls. The functions are not supported if a call to a function leaves the AX register unchanged.


Close-Aware Applications

A close-aware application is any MS-DOS − based application that periodically checks the state of an internal close flag and terminates if the flag is set. Windows 95 sets this flag when the user chooses the Close command from the system menu of the window in which the MS-DOS − based application runs. Close-aware applications enable the Close command, which gives the user an alternate way to exit the application and close the window.

An application enables or disables the Close command by using the Enable or Disable Close Command function. The function takes a flag indicating whether to enable or disable the command. Once the command is enabled, the application must periodically check the close flag by using the Query Close function. The function returns zero in the AX register if the user has chosen the command.

If the Query Close function returns zero in AX, the application should call the Acknowledge Close function to acknowledge the close state of the internal close flag. After the application acknowledges the close state, subsequent calls to the Query Close function will return 1 in AX, indicating that the user has chosen the Close command and the close state has been acknowledged. After acknowledging the close state, an application should take all necessary steps to shut down and eventually exit, or it should cancel the close operation by calling the Cancel Close function.

An application should acknowledge the close state if it needs to perform additional keyboard input before exiting. When the close state has been signaled but has not yet been acknowledged by the application, all keyboard reads will return NULL and buffered line input will return an empty string.

After an application acknowledges the close state, the state reverts to unacknowledged if the application either exits or cancels the close operation. If the application acknowledges the close state and then exits, the parent process will be in an unacknowledged close state. The application must then acknowledge the close state to perform additional keyboard input before exiting or canceling the close operation.

For example, if a text editor receives a positive response from the Query Close function and has some buffers that have not been saved, it should call Acknowledge Close and ask the user if the buffers should be saved with these possible responses: "Yes," "No," or "Cancel."

If the user responds "Yes" or "No," the text editor should save (or not save if the response was "No") the buffers and then exit. The close state remains active, and the parent process (probably the command interpreter) will also receive a positive response from Query Close and will also terminate.

If the response is "Cancel," the application should call the Cancel Close function and not exit. Canceling the close operation informs the system that any attempted shutdown should be abandoned.

This sequence of operations is analogous to the way that Windows-based applications handle the WM_QUERYENDSESSION message.

Depending on the tasking option chosen for the application, there may be some time between when the user chooses the Close command and the application checks the internal close flag. During this time, the system changes the window title of the application, appending the word "Closing" to it, and gives the user the opportunity to cancel the command by changing the command name to Cancel Close. If the user chooses the Cancel Close command, the close flag is reset, preventing the application from closing. If a close-aware application fails to check the close flag within a system-defined amount of time, the system automatically abandons the operation and resets the close flag.

The system tracks the close-awareness and close state for each process. For the virtual machine to close, all applications in the virtual machine must close. When the user chooses the Close command, the operating system detects applications that are not close-aware and displays a dialog box with a warning message, but gives the user the option of forcing the application to exit anyway. If you make an application close-aware, it can shut down cleanly.


Reference

The following functions and commands are associated with virtual machine services.


Window Title Functions

The following window title functions are used with virtual machine services.


Get Application Title [New - Windows 95]
Get Application Title

[New - Windows 95]

mov  ah, 16h           ; Windows multiplex function
mov  al, 8Eh           ; VM Title
mov  di, seg AppTitle  ; see below
mov  es, di
mov  di, offset AppTitle
mov  cx, Size          ; see below
mov  dx, 2             ; Get Application Title
int  2Fh
cmp  ax, 1
je   success

Copies the application title to the specified buffer.

•	Returns 1 in the AX register if successful or zero otherwise.

AppTitle

Address of a buffer that receives the application title. This parameter must not be zero.

Size

Size, in bytes, of the buffer pointed to by AppTitle.

Get Application Title copies as much of the title as possible, but never more than the specified number of bytes. The function always appends a terminating null character to the title in the buffer.


Get Virtual Machine Title [New - Windows 95]
Get Virtual Machine Title

[New - Windows 95]

mov  ah, 16h           ; Windows multiplex function
mov  al, 8Eh           ; VM Title
mov  di, seg VMTitle   ; see below
mov  es, di
mov  di, offset VMTitle
mov  cx, Size          ; see below
mov  dx, 3             ; Get Virtual Machine Title
int  2Fh
cmp  ax, 1
je   success

Copies the virtual machine title to the specified buffer.

•	Returns 1 in the AX register if successful or zero otherwise.

VMTitle

Address of a buffer that receives the virtual machine title. This parameter must not be zero.

Size

Size, in bytes, of the buffer pointed to by VMTitle.

Get Virtual Machine Title copies as much of the title as possible, but never more than the specified number of bytes. The function always appends a terminating null character to the title in the buffer.


Set Application Title [New - Windows 95]
Set Application Title

[New - Windows 95]

mov  ah, 16h           ; Windows multiplex function
mov  al, 8Eh           ; VM Title
mov  di, seg AppTitle  ; see below
mov  es, di
mov  di, offset AppTitle
mov  dx, 0             ; Set Application Title
int  2Fh
cmp   ax, 1
je   success

Sets the application title to the given string.

•	Returns 1 in the AX register if successful or zero otherwise.

AppTitle

Address of a null-terminated string specifying the application title. The title must not exceed 80 characters, including the terminating null character. If this parameter is zero or points to an empty string, the function removes the current application title.

Although not common, Set Application Title may return 1 in the AX register even though the title was not changed. In general, applications must not rely on the operating system to keep an accurate copy of the current title.


Set Virtual Machine Title [New - Windows 95]
Set Virtual Machine Title

[New - Windows 95]

mov  ah, 16h           ; Windows multiplex function
mov  al, 8Eh           ; VM Title
mov  di, seg VMTitle   ; see below
mov  es, di
mov  di, offset VMTitle
mov  dx, 1             ; Set Virtual Machine Title
int  2Fh
cmp   ax, 1
je   success

Sets the virtual machine title to the given string. Applications should not change the virtual machine title except under explicit instructions from the user.

•	Returns 1 in the AX register if successful or zero otherwise.

VMTitle

Address of a null-terminated string specifying the virtual machine title. The title must not exceed 30 characters, including the terminating null character. If this parameter is zero or points to an empty string, the function removes the current virtual machine title.

Although not common, Set Virtual Machine Title may return 1 in the AX register even though the title was not changed. In general, applications must not rely on the operating system to keep an accurate copy of the current title.


Close-Aware Application Functions

The following close-aware application functions are used with virtual machine services.


Acknowledge Close [New - Windows 95]
Acknowledge Close

[New - Windows 95]

mov ah, 16h    ; Windows multiplex function

mov al, 8Fh    ; VM Close

mov dh, 2      ; Acknowledge Close

mov dl, 0      ; always 0

int 2Fh

or ax, ax

jz success

Acknowledges the close state of the internal close flag.

•	Returns zero in the AX register if successful.

Acknowledging the close state is necessary if an application needs to perform additional keyboard input before exiting. If the close state has been signaled but not yet acknowledged by an application, all keyboard read operations will return NULL and buffered line input will return an empty string.


Cancel Close [New - Windows 95]
Cancel Close

[New - Windows 95]

mov ah, 16h    ; Windows multiplex function

mov al, 8Fh    ; VM Close

mov dh, 3      ; Cancel Close

mov dl, 0      ; always 0

int 2Fh

or ax, ax

jz success

Cancels the close operation.

•	Returns zero in the AX register if successful.

After acknowledging the close state of the internal close flag, an application should either exit or cancel the close operation by calling Cancel Close.


Enable or Disable Close Command [New - Windows 95]
Enable or Disable Close Command

[New - Windows 95]

mov ah, 16h    ; Windows multiplex function

mov al, 8Fh    ; VM Close

mov dh, 0      ; Enable or Disable Close Command

mov dl, Flags  ; see below

int 2Fh

or ax, ax

jz success

Enables or disables the Close command in the system menu.

•	Returns zero in the AX register if successful.

Flags

Close flags. This parameter can be one of these values:

00h	Disables the Close command.
01h	Enables the Close command.


Query Close [New - Windows 95]
Query Close

[New - Windows 95]

mov ah, 16h   ; Windows multiplex function

mov al, 8Fh   ; VM Close

mov dh, 1     ; Query Close

mov dl, 0     ; always 0

int 2Fh

Indicates whether the user has attempted to close an MS-DOS − based application from Windows by choosing the Close command from the system menu.

•	Returns one of the following values in the AX register:

0	The close command was chosen, and the application has not acknowledged the close state.
1	The close command was chosen, and the application has acknowledged the close state.
168Fh	The close command has not been chosen, and the application should continue running.
Query Close returns a nonzero value if the application has not enabled the Close command by using the Enable or Disable Close Command function.


International Guidelines

This overview describes the rules you should follow when writing Windows 95 modules or applications for international audiences.


About International Guidelines

This section is a reference guide to help developers write modules or applications that can be localized and that take full advantage of the Microsoft® Windows® 95 international environment.


Windows 95 Platform Strategy

Windows 95 is available in many different languages. The languages and the rules associated with them can be divided into these three groups:

•	Western/Eastern European languages, such as German, French, and Russian. These languages use an 8-bit character set and are written from left to right. In this article, these languages are called "WE" languages.

•	Middle-Eastern languages, such as Hebrew and Arabic. These languages use an 8-bit character set and are written from both left to right and right to left. In this article, these languages are called "ME" languages.

•	Far-Eastern languages, such as Japanese and Chinese. These languages use a 16-bit character set (also referred to as a double-byte character set or DBCS) and are written from left to right or top to bottom. In this article, these languages are called "FE" languages.

Windows 95 is a multiple character-set system, which means you can use more than one character set at a time. To accommodate the text management rules associated with WE, ME, and FE languages, Windows 95 uses a three-platform strategy that can be summarized in the following manner.


WE Platform

The WE platform (U.S. Windows 95) is the code base of Windows 95. It supports all WE languages and the rules associated with them, and it includes application programming interface (API) elements and other mechanisms for manipulating these languages. The WE platform is also the base on which the ME and FE platforms are built. Applications built for the WE platform can also run on the ME and FE platforms, but they can not take advantage of functions written specifically for those platforms.

The WE platform will be localized in the following languages: German, French, Spanish, Swedish, Dutch, Italian, Norwegian, Danish, Finnish, Portuguese (Brazil), Portuguese (Portugal), Russian, Czech, Polish, Hungarian, Turkish, Greek, and Catalan.


ME Platform

The ME platform is built on the WE platform. It includes the API elements and other mechanisms found in the WE platform. It also includes additional API elements specifically designed to support ME languages. To take full advantage of the ME platform, an application must use the additional API elements and may need to be recompiled.

The ME platform will be localized in the Arabic and Hebrew languages.


FE Platform

The FE platform is built on the WE platform. It includes the API elements and other mechanisms found in the WE platform. It also includes additional API elements specifically designed to support FE languages. To take full advantage of the FE platform, an application must use the additional API elements and may need to be recompiled.

The FE platform will be localized in the Japanese, Chinese (Traditional), Chinese (Simplified), and Korean languages.


International Language Requirements

This section is divided into three subsections: localization, national language support functions, and multilingual content support. Each subsection describes a set of rules that you should follow when writing Windows 95 modules or applications for international audiences.


Localization

Certain rules should be followed so that Windows 95 modules or applications can be translated into different languages. For example, you should use resources for all elements to be localized, including strings, messages, icons, and so on.


General Programming Guidelines

You should follow these general programming guidelines when writing applications for international audiences:

•	Do not store handles or identifiers in resources.

•	Do not shift resource identifiers when adding resources to a file. Instead, just add an identifier (allowing no duplicate identifiers).

•	Do not store user interface elements (strings, messages, menus, and so on) in initialization (.INI) files.

•	Use the FormatMessage function to dynamically allocate buffer sizes for your Microsoft® Win32® − based applications. For more information, see the description of FormatMessage.

•	Do not hard code filenames into a binary file. Windows 95 modules or applications may use long filenames, and these filenames appear on the desktop. Because the filenames are visible to the user, they may need to be translated. Windows 95 − based modules or applications should be able to be renamed without requiring any code change.


Guidelines for Using Strings

You should follow these guidelines when using strings in applications for international audiences:

•	Do not concatenate strings in dialog box controls. Doing so can create a string that crosses a character set boundary. For example, setting a control's text to be the result of "Can not find %s" will create a string that does not make sense if the user types in Greek in an application with English resources. You should use two controls instead of one in this situation.

•	Use %numbers instead of %letters when using a string with variables in case translators and localizers need to invert the variables. The wrong and right approaches follow.

WRONG	"The file type %s on the drive %s should first be copied to the drive %s."
RIGHT	"The file type %1 on the drive %2 should first be copied to the drive %3."
•	Do not allow English text strings to use more than 70 percent of the available space in dialog boxes. Providing extra space ensures that a translated string will not exceed the length limit. An English string of 240 characters will sometimes result in a localized string of 300 characters. In a dialog box where the string limit is 256 characters, incomplete and improper localization will appear. In general, if a string that must be localized exceeds 70 percent of the limit, it should be split into two parts.


National Language Support Functions

Windows 95 includes a set of functions that allows Windows 95 − based modules or applications to find and use locale-dependent information. A locale is a collection of user-preference information related to the user's language and sublanguage, represented as a list of values. The system has one default locale, but an application can also get locale information that is specific to an application or task. To take advantage of this feature, an application must use the National Language Support (NLS) functions described in the Microsoft Win32 Software Development Kit (SDK).


Multilingual Content Support

Windows 95 includes multilingual content support for documents, which means Windows 95 applications can mix characters from different character sets in the same document. For example, an application can mix Greek and German in the same document, even though characters for these languages belong to two different character sets. This feature makes Windows 95 a multiple character set (or multiple code page) operating system.

The basic multilingual architecture is based on languages, especially keyboard languages. A user can create a list of keyboard languages from the set of all keyboard languages available. The system can be started with one language active, and the additional selected languages loaded and available. When the user switches from one language to another, a WM_INPUTLANGCHANGE message is sent to the application with the focus to indicate that the language has changed. The message includes the handle of the new keyboard layout (language) and character. The application can then use the information to determine whether the locale has changed and whether the character set has changed.

To take full advantage of multilingual content support, you should not assume that the character set is U.S. ANSI. Many "ANSI" character sets are available today. For example, Russian Windows 95 uses the "Cyrillic ANSI" character set, which is different from the one used by U.S. Windows 95 (U.S. ANSI). In addition, you should always use the Choose Font common dialog box. If that is not possible, you should use the EnumFontFamiliesEx function. Finally, you should always save the character set with the font names in documents and process multilingual Windows messages, including WM_INPUTLANGCHANGEREQUEST and WM_INPUTLANGCHANGE. They either request that the keyboard language be changed or indicate that a the keyboard language has changed.

Note  You should store the character set and keyboard layout of the next run of text when your application receives the WM_INPUTLANGCHANGEREQUEST or WM_INPUTLANGCHANGE message. You should also modify your Find or Search dialog boxes or algorithms so that they support multilingual search and replace operations. In addition, any headers, footers, and other peripheral annotations should be able to handle different fonts and languages.

After the keyboard language has changed, you should use the following API elements:

•	Determine whether the character set has changed by using the wParam parameter from the WM_INPUTLANGCHANGE message.

•	Select a new font by using EnumFontFamiliesEx function if the character set has changed.

•	Use the "Ex" versions of keyboard functions — for example, ToAsciiEx instead of ToAscii.

•	Use the CR_ formats with the SetClipboardData function when placing text on the clipboard and with the GetClipboardData function when getting text from the clipboard.

•	Use the GetCharacterPlacement and GetFontLanguageInfo functions when drawing text, calculating caret positions, or performing any other action related to a device. The functions provide intermediate information that make caret placement easier and allow the application to take advantage of new features in graphics device interface (GDI). They also ensure that the application is compatible across all three platforms. Even if you write your application for non-ME and non-FE platforms, using GetFontLanguageInfo allows you to detect when the user tries to use one of the ME or FE fonts and allows you to prevent the user from producing strange text on the screen and printer.

For more information about multilingual content and support, see the reference pages for the functions and messages mentioned in this section.


Using the Far-Eastern Platform

For your Windows 95 − based module or application to run on the FE platform, you must enable your module or application to use double-byte characters by using the CharNext, CharPrev, and IsDBCSLeadByte functions. For information about double-byte characters enabling, see "Using Double-Byte Characters." You should also enable your module to use the IMM (Input Method Manager) functions and modify your application to interact with an IME (Input Method Editor) so that the user will be able to use Far-Eastern characters. For information about FE enabling, see "Using Input Method Editors."


Using the Middle-Eastern Platform

You should follow certain guidelines to enable your Windows 95 − based module or application to run on the ME platform:

•	Use the Windows 95 functions. There are no specific ME functions. All of the functions for writing ME-based software are built into the basic Windows 95 code, and all the items mentioned under "Multilingual Content Support" earlier in this topic are also relevant. However, for standard left to right languages, these features are desirable, but not necessary.

•	Call the GetCharacterPlacement function to provide line layout support for getting the visual orientation, character widths, and character placement required for laying out and displaying any single-byte character text.

•	Call the GetFontLanguageInfo function to determine which services are required for a particular language. The main difference between ME and WE languages is that the text may be oriented to the right of the page instead of to the left. This means that you need some form of user interface for switching direction, and you need the ability to write text from right to left instead of left to right. You can achieve this by using the SetTextAlign function.

•	Use the ME-specific window styles and common control styles. If you have enabled your application to run using ME resources (for example, right to left menus), you must also modify calls to functions, such as MessageBox and CreateWindow, to use the ME-specific flags (for example, to allow right to left orientation of menus). If a particular window class has no specific right to left style, like the button class, use extended window styles, such as WS_EX_RTLREADING and WS_EX_RIGHT.

For more information about ME enabling, see "Writing Applications for Middle-Eastern Languages."


Using Double-Byte Characters

This article provides guidelines to reduce the work necessary to port an application written for a single-byte character set system (SBCS) to a double-byte character set (DBCS) system.


About Using Double-Byte Characters

String operations in applications running with an operating system that uses a DBCS are slightly different from those in applications running with a system that uses a single-byte character set. A DBCS-enabled application allows users to create, edit, print, and save documents in their own languages, even if the user interface has not been localized. DBCS enabling involves adding code to handle DBCS strings, which are made up of a mixture of 1-byte and 2-byte characters. For example, a user could run an English version of a DBCS-enabled application with a Japanese version of Microsoft® Windows®, freely typing in and editing kanji strings without any problem.

DBCS enabling is only one step in internationalizing an application. For more information about DBCS and other internationalization issues, see Developing International Software for Microsoft Windows by Nadine Kano, available through Microsoft Press®.


Code Pages

Accented characters are an integral part of many languages. However, the 7-bit ASCII character set does not provide support for accented characters. To compensate, Microsoft® MS-DOS® uses 8-bit code pages as a means of providing support for character sets and keyboard layouts used in different countries. Each code page table relates the binary character codes used by an application to keys on the keyboard or to the appearance of characters on the display.

Over the years, support for code pages that include different accented characters has been added to MS-DOS. In each of these code pages, the characters numbered 32 through 127 are the same characters that form the 7-bit ASCII set. The characters above 127, known as extended characters, vary from code page to code page. The set of extended characters, which contains accented characters, determines which languages the code page can support.

Microsoft Windows 95 uses the same type of code pages introduced in Windows version 3.1. These code pages are different from the ones in MS-DOS. For example, the line-drawing characters that allow MS-DOS − based applications to draw boxes have not been included in Windows code pages and have been replaced with additional publishing characters.


Double-Byte Character Sets

The Chinese language defines more than 10,000 basic ideographic characters. Each ideographic character represents a word or syllable, and many of these characters were adapted long ago by other Far-Eastern languages. These characters are called kanji in Japanese, hantsu or hanzi in Chinese, and hanja in Korean. Because there are so many ideographic characters, single-byte character sets, which have room for only 256 characters, are too small to accommodate those languages.

The solution used in Windows 95 (and in earlier versions of Windows) has been to encode most characters (primarily ideographs) with 2-byte values, making many more than 256 characters available. However, characters, such as the ASCII set, the Japanese phonetic syllabary known as katakana, and some symbols still have single-byte representations. The result is a code page that mixes 1-byte and 2-byte characters. Double-byte character sets typically contain a mixture of 1-byte and 2-byte characters.

The mixing of byte lengths in Far-Eastern versions of Windows leads to more complex string parsing code. Each 2-byte character is composed of a lead byte and a trail byte, which must be stored together and manipulated as a unit. A lead byte value always falls into one or more ranges above 127. Although 1-byte characters may be defined above 127, they cannot exist in the lead byte ranges. NULL can never be a trail byte, but the range of possible trail bytes can overlap to some degree with the ASCII character set. Lead byte values are frequently indistinguishable from trail byte values; the only way to tell the difference is from the context of the surrounding characters. For that reason, if a trail byte is taken without its lead byte, it can be mistaken for a 1-byte character.

Because 1-byte characters are displayed in half the width of 2-byte characters for most fonts on Far-Eastern versions of Windows, they are sometimes referred to as half-width characters. Most half-width characters also have a full-width (2-byte) representation to make column layout on a display easier. Ideographic characters exist only in full-width form; there is, for example, no such thing as a 1-byte kanji character. In Windows 95, ASCII characters can be drawn with proportional fonts, but ideographic characters, including Japanese kanji, are always monospaced.


Using Double-Byte Characters in an Application

To handle 2-byte characters, you should have any code that searches, selects, edits, moves, replaces, deletes, or inserts text check for double-byte pairs. An application should not split 2-byte characters and should accommodate 2-byte characters in its display operations. Rules of selection, cursor placement, and cursor movement are the same as for alphabetic characters; the cursor should always end up between characters, never in the middle of one.

Because 1- and 2-byte characters can be mixed, it is not safe to use unary operators, such as ++ or - -, which increment or decrement string pointers one byte at a time instead of a character at a time. These operators can be replaced with the Microsoft® Win32® CharNext and CharPrev functions (or the AnsiNext and AnsiPrev functions used in Windows version 3.x). These functions increment string pointers properly whether the current character is a single byte or a double byte.

In addition, it is not safe to access a string with 2-byte characters randomly in the following manner.

Mychar = string[i]

Unless a string is searched from the beginning, there is no way of knowing if the byte accessed is a single byte, lead byte, or trail byte.

For string processing, it is often important to determine if a byte is a lead byte. The IsDBCSLeadByte function can be used to test whether a particular byte is in the default code page's lead byte range, and the IsDBCSLeadByteEx function can be used to check the lead byte range of a specified code page. The following example shows how to search for a backslash ('\') character in a DBCS string by using IsDBCSLeadByte.

// Returns a pointer to the first '\' in a given string.

char* GetBackSlash( char *pszString)

{

 while(*pszString)

 {

     if (!IsDBCSLeadByte(*pszString))

     {

        if (*pszString == '\\')

            break;

     }

     else // it is a lead byte

     {

        // Increment the pointer 1 byte to point to the trail byte.

        pszString++;

     }

     // Increment the pointer 1 byte to point to the next character.

     pszString++;

 }

 return( pszString);

}

Although IsDBCSLeadByte and IsDBCSLeadByteEx are convenient, calls to these functions may impact performance if you have a large number of bytes to test. As an alternative, you can check the ranges yourself by calling the GetCPInfo function, which returns the lead byte ranges in the LeadByte member of the CPINFO structure. LeadByte is an array of bytes. Each range, which consists of two bytes, specifies a starting and ending value for the range. Ranges are inclusive, and there can be a maximum of five ranges. Any unused bytes in LeadByte are set to zero.

To further optimize your code, you should only call DBCS functions or special string handling code when using a DBCS code page. There are several methods of doing this. For example, an application can determine whether it is running on a DBCS system at run time by using GetCPInfo in its initialization code. GetCPInfo returns the maximum number of bytes for a character in the code page in the MaxCharSize member of the CPINFO structure. The advantage of this method is that it requires having only one executable file.

Another method is to use a DBCS command-line option at compile time and bracket sections of string handling code with #ifdef directives. The number of #ifdef blocks can be greatly reduced by defining the following macros.

#ifndef DBCS

#define CharNext(pc)    ((*pc) ? pc + 1 : pc)

#define CharPrev(pcStart, pc) ((pc > pcStart) ? \

                                     pc - 1 : pcStart)

#ifndef WIN32

#define IsDBCSLeadByte (bByte) (FALSE)

#endif

#endif


Using Input Method Editors

This article shows some simple ways to customize the operation of an input method editor (IME) for your application.


About Using Input Method Editors

In Asian versions of Microsoft® Windows® 95, an IME allows users to generate single- and double-byte characters by typing at the keyboard. By default, Windows 95 carries out all actions required to enable the user to generate characters for input to your application. However, you can also customize this process by using input method manager (IMM) functions to carry out actions on your own. For more information about the IMM functions, see the documentation included in the Microsoft® Win32® Software Development Kit (SDK).


Handling Character Input

You receive character input from an IME in the form of WM_CHAR or WM_IME_CHAR messages. Windows 95 provides a default IME that automatically displays a status window enabling users to choose the conversion mode and other properties for generating single- and double-byte characters for the current application. (Users can also purchase third-party IMEs that may have additional capabilities.)

Depending on the conversion mode, an IME provides a composition window into which the user types the initial characters and a candidates window from which the user picks the final character(s). Selecting the final character causes the IME to send either one or two WM_CHAR messages to the window procedure for the application.

You can use the IsDBCSLeadByte function to determine whether the character in a WM_CHAR message is the first byte of a double-byte character. If it is, the next WM_CHAR message contains the second byte. Once you have both bytes, you can display the character by using a function such as ExtTextOut.

In some cases, you may receive WM_IME_CHAR messages from the IME. The wParam parameter of this message contains one or two bytes, depending on the user's final selection. To determine the size of the character, you need to use the IsDBCSLeadByte function in the following manner.

WORD wChar;

case WM_IME_CHAR:
    wChar = (WORD) wParam;
    if (IsDBCSLeadByte(HIBYTE(wChar) == TRUE)
        // wChar is a double-byte character.
    else
        // wChar is a single-byte character.
    break;

If you choose not to handle the WM_IME_CHAR message, you can pass it to the DefWindowProc function. This function converts the message into one or two WM_CHAR messages and sends them to your window procedure.


Managing the IME

You manage the IME by enabling (opening) it for conversions, setting the conversion modes, and positioning the composition window. By default, the IME opens when the user chooses a conversion mode from the status window, and the IME displays the composition window when the user begins to type. You can change this default behavior by using the ImmSetOpenStatus, ImmSetConversionStatus, and ImmSetCompositionWindow functions.

You open the IME when you want to allow users to enter characters for conversion. You can determine whether the IME is currently open by by using the ImmGetOpenStatus function. If it is not, you can open the IME by using the ImmSetOpenStatus function as follows.

HIMC hIMC;
BOOL bOpen;

if (hIMC = ImmGetContext(hwnd)){
    bOpen = ImmGetOpenStatus(hIMC);
    if (!bOpen)
        ImmSetOpenStatus(hIMC, TRUE);
    ImmReleaseContext(hwnd,hIMC);
}

Once you open the IME, the composition window opens as soon as the user begins to type in the window associated with the input context. By default, the composition is displayed as a pop-up window placed near the window having the input focus. You can change this default position and appearance by using the ImmSetCompositionWindow function. The following example shows how to embed the composition window into the current line of text (similar to edit controls) by using the CFS_POINT style.

HIMC hIMC;
COMPOSITIONFORM cf;

if (hIMC = ImmGetContext(hwnd)){
    cf.dwStyle = CFS_POINT;
    cf.ptCurrentPos.x = ptCurrent.x;
    cf.ptCurrentPos.y = ptCurrent.y;
    ImmSetCompositionWindow(hIMC, &cf);
    ImmReleaseContext(hWnd,hIMC);
}

In this example, the ptCurrent member contains the coordinates of the caret in the window identified by the hwnd parameter. The function places the composition window at that position, and characters that the user types appear there.

Once the user starts typing, the IME converts and displays the characters using the current conversion and sentence modes. The user typically sets the modes through the status window, but you can set them as well by using the ImmSetConversionStatus function. In most cases, it is best to retrieve and change the current modes by using both the ImmGetConversionStatus and ImmSetConversionStatus functions in the following manner.

HIMC hIMC;
DWORD dwConvMode, dwSentence;

if (hIMC = ImmGetContext(hWnd)){
    // Get the current modes.
    ImmGetConversionStatus(hIMC, &fdwConversion, &fdwSentence);
    // Change to full shape input mode.
    fdwConversion |= IME_CMODE_FULLSHAPE;
    // Set the new modes.
    ImmSetConversionStatus(hIMC, fdwConversion, fdwSentence);
    ImmReleaseContext(hWnd,hIMC);
}


Managing the IME Window

Windows 95 creates an IME window for each thread in an application. The IME window, belonging to the system-defined "IME" window class, creates and owns the status, composition, and candidates windows that give users the means to control the conversion of characters. The IME window carries out default processing for the status, composition, and candidates windows for the application, so changing the IME window changes those windows too.

You can control the position and style of the status, composition, and candidates windows directly by using functions such as ImmSetStatusWindow, ImmSetCompositionWindow, and ImmSetCandidateWindow. You can also control the windows indirectly be sending WM_IME_CONTROL messages to the IME window. You can retrieve the handle of the IME window by using the ImmGetDefaultIMEWnd function.

The following example shows how to create an IME window by using the "IME" window class in a call to the CreateWindowEx function.

hwndIME = CreateWindowEx(
    0,
    "IME",                  // IME class
    NULL,                   // no window title
    WS_DISABLED | WS_POPUP, // disabled window
    0, 0, 0, 0,             // no need to set size
    hwnd,                   // owner window
    NULL,
    hinstance,
    NULL);

If your application does not process character input from the keyboard, you can close an IME window by retrieving the handle and passing it to the DestroyWindow function.


Monitoring the Composition

You can monitor the user's interaction with the status, composition, and candidates windows by processing WM_IME_NOTIFY and WM_IME_COMPOSITION messages. The IME sends these messages to the window having the input focus whenever the user carries out some action in one of the IME windows.

WM_IME_NOTIFY is useful for monitoring changes that the user makes through the status window. For example, the IME sends this message with the IMN_SETCONVERSIONMODE value when the user changes modes in the status window. When you receive this message, you can use the ImmGetConversionStatus function to determine the new conversion and sentence modes.

WM_IME_NOTIFY is also useful for monitoring selections made by the user in the candidates window. The IME sends this message with the IMN_CHANGECANDIDATE value when the user changes the selection. When you receive this message, you can use the ImmGetCandidateList function to retrieve the list of candidates and the index of the current selection.

WM_IME_COMPOSITION is useful for monitoring input and conversions made in the composition window. The IME sends this message whenever the user types a character. When you receive this message, you can use the ImmGetCompositionString function, as shown in the following example, to retrieve the characters typed by the user or the converted characters proposed by the IME.

HIMC hIMC;
char szComp[256];
DWORD dwSize;

case WM_IME_COMPOSITION:
    if ((hIMC = ImmGetContext(hwnd)) == NULL)
        break;

    // Get the composition string.
    dwSize = ImmGetCompositionString(hIMC, GCS_COMPSTR, szComp, 256);

    ImmReleaseContext(hWnd,hIMC);
    break;

The IME sets the lParam parameter in WM_IME_COMPOSITION to the GCS_RESULTSTR value when the user completes the composition. The following example shows how to retrieve the final result of the conversion by using ImmGetCompositionString.

HIMC hIMC:
LPSTR lpstr;
DWORD dwSize;

case WM_IME_COMPOSITION:
    if (!(lParam & GCS_RESULTSTR))
        break;

    // Get the context.
    if ((hIMC = ImmGetContext(hwnd)) == NULL)
        break;

    // Get the result string size, and add 1 for the terminating
    // null character.
    dwSize = ImmGetCompositionString(hIMC, GCS_RESULTSTR, NULL, 0);

    // Allocate memory to receive the string.
    if ((lpstr = GlobalAlloc(GPTR, dwSize)) == NULL) {
         MyError();
         break;
    }

    // Get the result string.
    ImmGetCompositionString(hIMC, GCS_RESULTSTR, lpstr, dwSize);

    // Release the context when it is no longer needed.
    ImmReleaseContext(hWnd,hIMC);

    // Do something with the result string here.

    // Free the memory now.
    GlobalFree((HGLOBAL)lpstr);
    break;

When you process WM_IME_COMPOSITION in this manner, you can safely ignore any WM_IME_CHAR messages sent for the result string.


Customizing the User Interface

You can customize the user interface for the IME by replacing the default IME window with your own window. In this case, you define your own IME window class and window procedure and create the IME window for your application after destroying the default IME window.

Your IME window must provide the same capabilities as the default IME window, or your application windows must be prepared to provide the same functionality as the status, composition, and candidates windows. The window also must handle any WM_IME_CONTROL messages sent to it and send WM_IME_NOTIFY and other messages in response to any user input to it.

To ensure that your IME window receives all appropriate messages, you must call the ImmIsUIMessage function from every window procedure in your application that accepts character input from the keyboard. The following example shows how to restructure your window procedure to process these messages.

HWND hwndIME;  // handle of IME window

long CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{

    if (ImmIsUIMessage(hwndIME, msg, wParam, lParam)==TRUE) {
        // Already processed and ready for post-processing.
        switch(msg) {
            // Post-process WM_IME_COMPOSITION and other messages.
        }
        return 0;
    } else {
        // Not processed yet.
        switch(msg) {
        case WM_CREATE:
             // Create your IME window here.
             break;
        case WM_DESTROY:
             // Destroy your IME window here.
             break;
        }
    }
}

If you choose not to create an IME window and provide instead the status, composition, and candidates functionality from within the window procedures of your application, your window procedures must handle the following IME messages rather than pass them to the DefWindowProc function.

COMPOSITIONFORM cf;
POINT ptMyPoint;
LOGFONT lf;

// The message was not handled by the IME window.
switch(uMsg) {
    case WM_CREATE:
        hIMC = ImmCreateContext();
        hOldIMC = ImmAssociateContext(hWnd ,hIMC);
        break;

    case WM_IME_STARTCOMPOSITION:
        // Prepare to receive the WM_IME_COMPOSITION message.
        break;

    case WM_IME_ENDCOMPOSITION:
        // Finish handling the composition string.
        break;

    case WM_IME_COMPOSITION:
        // Get the composition string, the result string,
        // and also the information for displaying the strings.
        break;

    case WM_IME_SETCONTEXT:
        // Remove bits from lParam to indicate that
        // this window can draw the composition string
        // and index 0 candidate list.
        lParam &= ~(ISC_SHOWUICOMPOSITIONWINDOW &
                    ISC_SHOWUICANDIDATEWINDOW);
        return DefWindowProc(hWnd, uMsg, wParam, lParam);

    case WM_IME_NOTIFY:
        // Handle each IMN_ submessage, and display the IME
        // and candidate list status.
        switch (wParam) {
        case IMN_OPENCANDIDATE:
        case IMN_CHANGECANDIDATE:
        case IMN_CLOSECANDIDATE:
            // This application can draw only one candidate list
            //  whose index is 0.

            if (lParam == 0x01)  // Bit 0 is On, it is index 0.

                // Draw the candidate list.
            else
                return DefWindowProc(hWnd, uMsg, wParam, lParam);
            break;
        default:

            // Make a notification to the IME window.
            return DefWindowProc(hWnd, uMsg, wParam, lParam);
        }

    break;

    case WM_IME_COMPOSITIONFULL:
        // Adjust the size of the window/area to draw the
        // composition string.
        break;

    case WM_DESTROY:
        ImmAssociateContext(hWnd, hOldIMC);
        ImmDestroyContext(hIMC);
        break;
}

To draw the composition string without the default IME window, you need to handle the WM_IME_COMPOSITION, WM_IME_STARTCOMPOSITION, and WM_IME_ENDCOMPOSITION messages. If you receive WM_IME_COMPOSITION and the composition is not final, you need to retrieve the attribute information as well as the composition characters to determine how to draw the characters.

HIMC hIMC:
LPSTR lpCompStr;
LPBYTE lpbAttr;
LPSTR lpResultStr;
DWORD dwStrSize;
DWORD dwAttrSize;

case WM_IME_COMPOSITION:
    if ((hIMC = ImmGetContext(hwnd)) == NULL)
        break;

    if (lParam & GCS_RESULTSTR) {
         // Received the final result, so grab it.
         dwSize = ImmGetCompositionString(hIMC, GCS_RESULTSTR,
             NULL, 0);

         // Allocate space for the string and attributes.

         // Draw the result string here.

    } else if (lParam & (GCS_COMPSTR | GCS_COMPATTR)) {

        // Get the size of the composition string and the attribute
        // information.
        dwStrSize = ImmGetCompositionString(hIMC, GCS_COMPSTR, NULL, 0);
        dwAttrSize = ImmGetCompositionString(hIMC, GCS_COMPATTR,
            NULL, 0);

        // Allocate space for the string and attributes.

        // Get the strings and attributes.
        ImmGetCompositionString(hIMC, GCS_COMPSTR, lpCompStr, dwSize);
        ImmGetCompositionString(hIMC, GCS_COMPATTR, lpAttrStr, dwSize);

        // Draw text using attributes to distinguish converted
        // characters from user input.
    }

    // Free the memory for the buffers here.

    ImmReleaseContext(hWnd,hIMC);

case WM_IME_SETCONTEXT:
    // Remove bits from lParam to indicate that
    // this window can draw the composition string.
    lParam &= ~(ISC_SHOWUICOMPOSITIONWINDOW);
    return DefWindowProc(hWnd, uMsg, wParam, lParam);


Setting the IME Context

Applications that use the default IME window must pass the WM_IME_SETCONTEXT message to the DefWindowProc or ImmIsUIMessage function without modification. This message identifies the current IME context and specifies which window or windows must be shown. If you choose to customize the IME interface by drawing the composition string, candidate lists, guideline string, and soft keyboard on your own, you must process WM_IME_SETCONTEXT before passing the message to DefWindowProc or ImmIsUIMessage by modifying the lParam parameter.

If you draw the composition string in addition to processing the WM_IME_STARTCOMPOSITION, WM_IME_ENDCOMPOSTION, and WM_IME_COMPOSITION messages, you must also clear the ISC_SHOWUICOMPOSITIONWINDOW value in the lParam parameter of WM_IME_SETCONTEXT before passing the message to DefWindowProc or ImmIsUIMessage.

If you draw the candidate lists in addition to processing the IMN_OPENCANDIDATEWINDOW, IMN_CLOSECANDIDATEWINDOW, and IMN_CHANGECANDIDATEWINDOW notification messages (passed with the WM_IME_NOTIFY message), you must clear the ISC_SHOWUICANDIDATEWINDOW values in the lParam parameter of WM_IME_SETCONTEXT that correspond to the candidate lists that you can draw. For example, if you draw the second candidate list (index 2), you must clear the corresponding ISC_SHOWUICANDIDATEWINDOW value as follows.

lParam &= ~ISC_SHOWUICANDIDATEWINDOW<<2;

If you draw all candidate lists, clear all values by using the ISC_SHOWUIALLCANDIDATEWINDOW value in the following manner.

lParam &= ~ISC_SHOWUIALLCANDIDATEWINDOW;

If you draw the guideline string in addition to processing the IMN_GUIDELINE notification message (passed with the WM_IME_NOTIFY message), you must clear the ISC_SHOWUIGUIDEWINDOW value in the lParam parameter of WM_IME_SETCONTEXT before passing the message to DefWindowProc or ImmIsUIMessage.

If you hide the soft keyboard, you must clear the ISC_SHOWUISOFTKBD value in the lParam parameter of WM_IME_SETCONTEXT before passing the message to DefWindowProc or ImmIsUIMessage.


Compatibility

Windows 95 supports IME applications that were written for previous versions of the operating system as long as the applications are compatible with the Windows version 3.1 IME. In addition Windows 95 supports Windows version 3.1 IMEs and can load and assign any Windows version 3.1 IME to a keyboard layout, making the IME available to applications written for either Windows version 3.1 or Windows 95. Also, because Windows 95 manages the interface with Windows version 3.1 IMEs, applications can use either the Windows 95 or Windows 3.1 input method management functions to access Windows version 3.1 IMEs. You can retrieve the operating system version number of an IME by using the ImmGetProperty function and specifying the IGP_GETIMEVERSION value. (Note, however, that Korean Windows version 3.1 IMEs are not supported by Korean Windows 95.)

Although any application can use a Windows version 3.1 IME, not all functions and messages are available. In particular, the ImmGetCandidateListCount, ImmGetCandidateList, ImmGetGuideLine, and ImmGetConversionList functions return an error if called, and the IMC_OPENSTATUSWINDOW, IMC_CLOSESTATUSWINDOW, IMC_GETSTATUSWINDOWPOS, and IMC_SETSTATUSWINDOWPOS messages are not available. Also, the clause information of the result string and the reading information of the composition string are not available.

Windows 95 does not support IME applications written for versions of IME that are earlier than Windows version 3.1 IME.


Writing Applications for Middle-Eastern Languages

This article describes the process of developing applications for Middle-Eastern languages. It is assumed that the reader is familiar with techniques used to write international applications, especially separating resources from code.


About Writing Applications for Middle-Eastern Languages

Writing applications for the Middle-Eastern languages is relatively simple. The multilingual features of the Microsoft® Win32® application programming interface (API) together with the unified architecture of international versions of Microsoft® Windows® 95 makes it possible to develop these applications just by changing the application resource files.


Middle-Eastern Language Elements

In Middle-Eastern languages, portions of written text are read right to left and other portions are read left to right. Arabic and Hebrew are two such languages. These languages have the following similarities:

•	Both have a right to left orientation of characters within each word.

•	Both have a right to left orientation for reading order of words, but both find a left to right reading order acceptable in some cases.

•	Both have a left to right order of numbers and characters in foreign (Latin-based) text.

•	Both use a left to right reading order for foreign (Latin-based) text.

•	Both have diacritics, as most Latin scripts do. A diacritic is an accent or phonetic element that modifies another element (for example, ` + A = À).

•	Both are single-byte character set languages. In some cases, two or more of their characters may actually represent a single character called a ligature. A ligature is two or more letters joined together (for example, A + E = Æ).

Arabic and Hebrew language are different in these ways:

•	Arabic has contextual shaping of characters, depending on whether the character is positioned at the beginning, middle, or end of a word or whether it stands alone. (Hebrew has a few characters that change at the end of a sentence, but these are typed as a separate character.)

•	Arabic uses kashidas. A kashida is a null element that is the extension of the end of a character, either filling empty space or joining two characters.

In general, the languages and cultures of the Middle East have a general right to left orientation just as Latin-based languages and cultures have a left to right orientation. This means that lists, menus, sets of buttons, or anything else that can have an alignment should be designed with a right to left orientation. Although this general right to left orientation and contextual shaping of Arabic may be intimidating at first, Windows 95 provides the resources and functions needed to make handling these language easier.


System Resources and Text Handling

In Windows 95, any string of text is saved in the order typed. This means that what you see on the screen or on the printed page may be in a different order than what you typed in. Obviously, this makes the modification of existing text a little tricky, but the Windows 95 and Win32 functions help make this easier.

Whenever possible, applications should use system edit controls for text input, subclassing them as necessary. If an application edits and displays text, it should use the GetCharacterPlacement function to determine the order in which the individual characters in the string are displayed. If the application displays a caret with the text, it should use GetCharacterPlacement to determine the caret position for each character in the text. The function also returns information about the order and number of glyphs for the string. This information is useful for determining whether the displayed string contains ligatures or extra characters, such as kashidas.

Everything in the resource file that pertains to country specific information should be thought of as part of the localization process. For the Middle East, this includes the orientation of menu items, buttons, dialog boxes, and so on. All these should be set in the resource file. If an application has menus, dialog boxes, lists, list boxes, and other visual elements that contain text, it must display the text in right to left order. Because Windows 95 allows applications to use the same functions to display text in right to left order as are used to display in left to right order, you can adapt a carefully designed application for the Middle Eastern market simply by changing the text strings, control positions, and text orientation styles in the resource file. In such cases, the application does not need to be recompiled.

In some cases, it may still make sense to modify and recompile your application source code — for example, if you need a highly optimized version of your application to compete successfully in the Middle-Eastern market.


Thunk Compiler

These topics describe how to use thunking to avoid porting all of your code to 32 bits or to take advantage of 16-bit components in order to save development time. In addition, these topics describe issues related to thunking that may make you choose to avoid it in your application.


About the Thunk Compiler

Writing applications for the Microsoft® Win32® application programming interface (API) is recommended for these reasons:

•	The flat address space — that is, no segments or offsets

•	Better performance

•	Greater robustness

However, as compelling as arguments are to move to the 32-bit programming model, there may be pragmatic reasons for not making the move all at once. Certain components of an application may lend themselves to the migration to 32 bits, while other components may be more tightly bound to the 16-bit environment. For example, an application developer may want to move the application's user interface code to 32 bits to take advantage of new system features, but may have an existing dynamic-link library (DLL) specifically optimized for the 16-bit architecture. Rather than delay the release of a new version of the application, the developer can decide instead to take advantage of the Microsoft Thunk Compiler to mix 16- and 32-bit components.


Thunking Mechanics

The Thunk Compiler needs to check for these elements in a mixed 16- and 32-bit environment:

•	Pointers consist of a selector and a 16-bit offset in a 16-bit Microsoft Windows® environment. However, in a 32-bit Windows environment, pointers essentially consist of a 32-bit offset; that is, the DS, ES, SS, and CS registers all contain selectors with the same base address. All pointers in this environment are considered to be near 0:32 pointers. Translating a 16:16 pointer to a 0:32 pointer involves determining the segment base for the selector portion of the pointer and adding the offset to it. Translating a 0:32 pointer to a 16:16 pointer involves allocating a selector and calculating the offset from the base of the corresponding segment.

•	Both 16- and 32-bit applications pass function parameters on the stack. However, 16-bit applications address the stack using the SS:SP registers, but 32-bit applications use the SS:ESP registers. When thunking from 16 bits to 32 bits (or thunking back in the other direction), the processor's method of addressing the stack must be switched.

•	The word size is 32 bits in a 32-bit environment and 16 bits in a 16-bit environment. When an application uses both 16- and 32-bit environments, some piece of software must be able to translate 16-bit words to 32-bit words. The following 16-bit function can be used to illustrate the translation.

DWORD Sample(WORD i);

If a 32-bit component calls this 16-bit function, it pushes a 32-bit argument on the stack, but the 16-bit function only pops 16 bits off the stack. Later, when the function returns, it places the returned doubleword value in the DX:AX register pair, but the 32-bit calling application expects the return value to be in the EAX register. It is the thunking layer's responsibility to negotiate these translations.

•	To correctly handle packing and conversion, the Thunk Compiler translates structure members one at a time. The Thunk Compiler supports structure packing on 1-, 2-, or 4-byte boundaries (corresponding to the /Zp1, /Zp2, and /Zp4 compiler options for Microsoft C language products). However, 8-byte structure alignment is not supported. Structure packing boundaries must be the same on both sides of a thunk.

•	Unlike 32-bit code, 16-bit code is usually not reentrant; 16-bit code is typically written with the assumption of a cooperative mulitasking model. The thunk layer must serialize access to 16-bit code. In contrast, 32-bit code must execute without serialization to prevent deadlocks. The thunk layer manages serialization on transitions in both directions.


Thunking Benefits and Drawbacks

If you use thunking to avoid porting all of your code to 32 bits or to take advantage of 16-bit components, you may save development time. In addition, your executable files may have a smaller memory footprint than if they were full 32-bit applications. However, there are some issues related to thunking that may make you choose to avoid it in your application. These issues are described in the following sections.


Thunking Models

Microsoft® Win32s®, Microsoft® Windows NT™, and Windows 95 use different thunking models. Win32s supports "universal thunks," which are not supported by either Windows NT or Windows 95. Window NT supports "generic thunks," which only allow thunking from 16 bits to 32 bits. Although Windows 95 supports generic thunks, it does not support the underlying process model used by Windows NT. Use of the Windows 95 model can lead to serious incompatibilities with the Windows NT generic thunking model. (For more information about generic thunks in Windows 95, see "Generic Thunking Mechanism" later in this topic.) Windows 95 implements a new thunking model, "flat thunks." Flat thunks allow thunking from 32 bits to 16 bits or vice versa. The flat thunking model requires use of the Thunk Compiler described in this topic.

If you use flat thunks, your application cannot be ported to Windows NT.


Compatibility with Existing 16-Bit DLLs

The Thunk Compiler accepts the following compatibility statement.

win31compat = true;

You must use this statement if a 16-bit DLL replaces a DLL that is currently used in a Windows version 3.1 environment or if the DLL runs as part of a graphics device interface (GDI) device driver. You should probably use this statement even if your 16-bit DLL does not fit into one of these categories, because it provides extra protection against poorly behaved DLLs that might be used by your thunk DLL.

The compatibility statement causes the unloading of a 32-bit DLL to be deferred until the containing process terminates. Use of this statement ensures that interprocess loading and freeing procedures, which may have worked with a pure 16-bit DLL, will not cause the thunked version of the 32-bit DLL to be freed prematurely. It also allows the 16-bit library to be freed without execution of the 32-bit DLL's notification routine — an occurrence that could cause reentry into 16-bit code.


16- to 32-Bit Thunks and Preemption

Because 16-bit processes multitask cooperatively with respect to each other, 16-bit code is often written with the assumption that it will not be interrupted by another process until it explicitly yields the 16-bit scheduler (typically by calling the GetMessage function). In contrast, 32-bit code is written with the expectation that it can wait on Win32 synchronization objects without impeding the progress of other processes. If you mix code written under these different assumptions, you should take care to avoid deadlocks or errors due to unexpected reentrancy.

While a process is executing 32-bit code, it is possible for other processes to enter 16-bit code, possibly reentering the 16-bit code that was thunked from. That is, entering a 16- to 32-bit thunk releases the 16-bit subsystem for use by other processes (under certain conditions noted in the following paragraph). Thus, 16- to 32-bit thunks should not be used if your code cannot be reentered at that time. In addition, you should avoid using 16- to 32-bit thunks inside callback functions passed to a third-party DLL, unless it is documented that the code calling the callback function is reentrant. (For example, if the callback function is allowed to yield, it is probably reentrant.)

If the process executing the thunk is 32 bits, any other process can reenter 16-bit code inside a 16- to 32-bit thunk. On the other hand, if the process executing the thunk is 16 bits, only 32-bit processes can reenter 16-bit code, because 16-bit processes are cooperatively multitasked with respect to each other. Thus, if your 16-bit code is used only by 16-bit processes, the reentrancy requirement can be relaxed, because other 16-bit processes can get control only if your 16-bit process yields. (A DLL cannot control what applications call it, of course, so guaranteeing that your 16-bit code will be used only by 16-bit processes is difficult.) There are other restrictions on what can be done in 16-bit processes, as described in the following section, "Behavior of Win32 Functions Inside 16-Bit Processes" later in this topic.


Behavior of Win32 Functions Inside 16-Bit Processes

In Windows 95, 16- to 32-bit thunks are primarily useful for implementing callback thunks on 32-bit processes. They can also be used to execute 32-bit code in 16-bit processes. Although the latter can improve performance and multitasking, there are important restrictions on what can be done in a 16-bit process.

The "bitness" of a process is determined by the format of the executable file that launched it, and it is a permanent attribute of the process. A 16-bit process executing 32-bit code is not the same as a 32-bit process executing the same code. The following important differences apply:

•	The 32-bit code will still execute on the stack reserved by the 16-bit application, which is much smaller than the 1MB stack used by true 32-bit applications.

•	16-bit processes cannot create new threads. Certain Win32 API elements, such as the functions supporting the new common dialog boxes or those supporting console applications, create threads on behalf of the calling application. These functions cannot be used in a 16-bit process.

•	Thunking into 32-bit code releases the 16-bit subsystem to other 32-bit processes, but other 16-bit processes will still be blocked, unless your process explicitly yields (typically by calling the GetMessage function). In other words, 16-bit applications still multitask cooperatively even when executing 32-bit code. This means that no 16-bit application will get processing time if a 16-bit application blocks for a long time without yielding. A common problem is using the CreateProcess function to launch a 16-bit application and then waiting on a synchronization object to do something. If the application does not yield, the new application will never run and signal the object, so deadlock will occur.

One way to avoid this problem is to use the MsgWaitForMultipleObjects function to wait for either messages or synchronization objects. Although this solution is effective when required, it still results in a less efficient blocking operation than that of a 32-bit application.

In general, 32-bit code within 16-bit processes should be limited to code that uses the 32-bit heap functions, memory-mapped file functions, file functions, and functions involving the current process and thread. 32-bit code using GDI, dialog box, message box, and message functions will also work within 16-bit processes. You should avoid using third party libraries, unless you are sure they work safely in a 16 bit-environment.


Globally Fixing Handles

Translating a 16:16 pointer to a 0:32 pointer involves determining the segment base for the selector portion of the pointer and adding the offset to it. The global memory compacter in Windows 95 may move a block of memory at any time, however, making the linear address invalid. When the Thunk Compiler converts pointers from 16 bits to 32 bits, it fixes the segment portion before computing the linear address. If you translate pointers without using the Thunk Compiler, however, you must be aware of the requirement to fix the segment portion. For more information about the functions you can use to translate pointers, see "Translating Pointers Outside Thunks" later in this topic.


16- to 32-Bit Thunks in GDI Device Drivers

The following compatibility statement is required for any 16- to 32-bit thunk script that runs as part of a GDI device driver.

win31compat = true;

You may only thunk using the following control display driver interface (DDI) functions in a GDI device driver.

Control(ABORTDOC)

Control(ENDDOC)

Control(NEWFRAME)

Control(NEXTBAND)

Control(STARTDOC)

If you use thunking, your driver must be reentrant.

You may call the OpenJob, StartSpoolPage, EndSpoolPage, CloseJob, and DeleteJob functions during the five listed control DDI calls. These calls will go through drivers written for Windows version 3.x for the sake of backward compatibility, but they will fail for Windows 95−based drivers.


Generic Thunking Mechanism

Windows 95 supports the Windows NT generic thunk functions and the Windows NT version 3.5 extensions. The Win32s universal thunk mechanism is not supported.

The same limitations apply to generic thunks as to the flat thunks introduced in Windows 95. For more information, see "Thunking Models" earlier in this topic.

The following thunking functions are implemented in the Windows 95 KRNL386 and can be called by 16-bit Windows applications.

CallProc32W	GetProcAddress32W
CallProcEx32W	GetVDMPointer32W
FreeLibraryEx32W	LoadLibraryEx32W
The following WOW32 thunking functions are implemented in Windows 95. Win32 applications can call these functions. (You should avoid using these functions inside shared DLLs.)

WOWCallback16	WOWGlobalFree16
WOWCallback16Ex	WOWGlobalLock16
WOWGetVDMPointer	WOWGlobalLockSize16
WOWGetVDMPointerFix	WOWGlobalUnlock16
WOWGetVDMPointerUnfix	WOWGlobalUnlockFree16
WOWGlobalAlloc16	WOWHandle16
WOWGlobalAllocLock16	WOWHandle32
Because of architectural differences between Windows NT and Windows 95, programs using generic thunks may not be portable between the two platforms. In particular, a Win32 function that works with Windows NT in a 16-bit process is not guaranteed to do so with Windows 95 and vice versa. Also, Windows 95 may invoke the global memory compacter at times where Windows NT would not and vice versa. Finally, generic thunks work differently in 32-bit processes in Windows 95, and they do not work at all on 32-bit processes in Windows NT.

Because generic thunks are wrappers around flat thunks, they are subject to the same synchronization issues as flat thunks. For more information about synchronization issues, see "Compatibility with Existing 16-Bit DLLs" earlier in this topic and "Behavior of Win32 Functions Inside 16-Bit Processes" earlier in this topic.


Using the Thunk Compiler

The Microsoft Win32 Software Development Kit (SDK) includes a sample application that illustrates the use of the Thunk Compiler. This application, APP32.EXE, simply thunks some basic types from 32 bits to 16 bits. This sample is an important supplement to the information in this topic.

The thunk compiler's input is a "thunk script," which is a list of C style function prototypes and type definitions. The compiler produces an .ASM file, which is really two .ASM files in one. You can assemble this .ASM file with the -DIS_16 option to get the 16-bit .OBJ file to link to the 16-bit component and then assemble it with the -DIS_32 option to get the 32-bit .OBJ file to link to the 32-bit component.

The 16-bit component of the .ASM file contains a jump table containing the 16:16 address of each function named in the thunk scripts. (The linker must be able to resolve these references; the functions must use the Pascal calling convention and either be implemented in the 16-bit DLL or be imported by the DLL.) The 32-bit half of the .ASM file contains a Stdcall function for each thunk, which converts its parameters to 16 bits and then employs some internal processing to call the 16-bit target referenced in the jump table. When a 32-bit application uses a thunked function, it calls these compiler-generated Stdcall functions directly.

For example, a thunk script's declaration for the LineTo function might look like this.

typedef          int INT;

typedef unsigned int UINT;

typedef UINT         HANDLE;

typedef HANDLE       HDC;

BOOL LineTo(HDC, INT, INT) {

}

For more information about thunk script files, see "Script Files" later in this topic.

An application would never include the LineTo function in a thunk script, of course, because this function already exists in 16- and 32-bit versions. This example (and the assembly language example that follows) are intended to illustrate the process; the assembly language code, in particular, could differ from the actual code that is generated by the current version of the Thunk Compiler.

When the preceding example from a thunk script is processed by the Thunk Compiler, the following assembly language code is generated. On the 16-bit half, there is the following jump table.

externDef LineTo:far16

FT_gdiTargetTable label word

    dw    offset LineTo

    dw       seg LineTo

The 32-bit half contains the following code.

public LineTo@12

LineTo@12:

    mov    cl,0

; LineTo(16) = LineTo(32) {}

;

; dword ptr [ebp+8]:  param1

; dword ptr [ebp+12]:  param2

; dword ptr [ebp+16]:  param3

;

public IILineTo@12

IILineTo@12:

    call    QT_Entry

    push    word ptr [ebp+8]    ;param1: dword->word

    push    word ptr [ebp+12]    ;param2: dword->word

    push    word ptr [ebp+16]    ;param3: dword->word

    call    QT_Target_gdi

    movsx    ebx,ax

    jmp        QT_Exit12

When a Win32-based application calls the LineTo function, it transfers directly to this routine, which builds a 16-bit call frame and calls a local routine asking it to look up the appropriate address in the jump table and sign-extend the return value. (Each component receives its own set of QT_ routines, which automatically use the correct jump table. The QT_ and FT_ routines are exported by the kernel.)


Script Files

Script files contain descriptions of the functions that are thunked. These files usually have a .THK filename extension. The script files are easily created using function prototypes. For example, a function might be prototyped in the following manner.

BOOL WINAPI Sample(int n);

The corresponding definition would look like this in the script file.

typedef bool BOOL;

typedef int INT;

BOOL Sample(INT n)

{

}

Many functions take pointers in their parameter lists. Some pointers are for input only, some are output only, and some are for both input and output. For example, a "ThunkIt" function might take a pointer to an input string, update a second string, and produce a third string as output in the following manner.

BOOL WINAPI ThunkIt(LPSTR lpstrInput, LPSTR lpstrInOut, LPSTR Output);

The corresponding thunk script declaration for the function follows.

typedef char *LPSTR;

BOOL ThunkIt(LPSTR lpstrInput, LPSTR lpstrInOut, LPSTR Output)

{

    pstrInput = input;      // optional, because pointers are input

                            // by default

    lpstrInOut = inout;     // pointer taken in and updated

    lpstrOutput = output;   // pointer returned

}

When a pointer is passed from 32-bit to 16-bit code, a single selector with a limit of 64K is allocated in the thunk. If the Win16 code needs to access more than the first 64K of the block, it must change the base address of the selector or allocate additional selectors to access the block.

The thunk compiler supports the following constructions:

•	Structures passed by value or reference.

•	Structures within structures.

•	Pointers within structures, provided that the object pointed to does not require repacking. The object can be another structure.

•	Arrays of scalar values embedded in structures.

•	The "input", "output," and "inout" qualifiers for pointers, as shown in the preceding example. The default qualifier is "input."

•	Returning pointers for 32- to 16-bit thunks, provided that the object pointed to requires no repacking. The object can be a structure. The segment is not globally fixed by the thunk compiler. As a general rule, the Thunk Compiler deallocates the selectors that it allocates.

•	The bool type. This type is preferred over int in situations where an application may use nonzero values other than 1 to represent TRUE.

The Thunk Compiler does not support arrays of pointers, arrays of structures, or floating-point types (such as float or double).


Procedure for Adding Flat Thunks

You should follow these steps to add flat thunks:

1.	Write a thunk script containing thunk declarations and type definitions for the functions that need to be thunked. You should place the following line at the beginning of the script to create 32- to 16-bit thunks.

enablemapdirect3216 = true;     // creates 32 to 16 thunks

Alternatively, you can use this line to create 16- to 32-bit thunks.

enablemapdirect1632 = true;     // creates 16 to 32 thunks

2.	Compile your thunk script.

thunk.exe <inputfile> [-o <outputfile>]

The thunk compiler has the following command line.

thunk [{-|/}options] infile[.ext]

?	Displays the help screen.
h	Displays the help screen.
o name	Overrides the default output filename.
p n	Changes the 16-bit structure alignment (default = 2).
P n	Changes the 32-bit structure alignment (default = 4).
t name	Overrides the default base name.
Nx name	Specifies the name segment or class where x is either C32 (for 32-bit code segment name) or C16 (for 16-bit code segment name).
3.	Assemble the resulting .ASM file to create the 16-bit side of the thunk, and make sure to define the DIS_16 option. For example, using Microsoft MASM version 6.11, you might use the following command line.

ml /DIS_16 /c /W3 /nologo /Fo thk16.obj 32to16.asm

4.	Make sure to mark your 16-bit DLL as being compatible with subsystem version 4.0 by running the Microsoft Resource Compiler (RC.EXE), which is included in the Win32 SDK, on the DLL.

\mstools\bin16\rc -40 <.DLL output file>

Important  	If the 16-bit DLL is not marked for subsystem version 4.0, the 32-bit DLL will not load. For more information, see "Troubleshooting" later in this topic.

5.	Assemble the resulting .ASM file to create the 32-bit side of the thunk, and make sure to define the DIS_32 option. For example, using Microsoft MASM version 6.11, you might use the following command line.

ml /DIS_32 /c /W3 /nologo /Fo thk32.obj 32to16.asm

6.	Add the entrypoint functions to the DLLs and the export and import statements to their module-definition (.DEF) files.

7.	Compile and link the 16- and 32-bit components.

8.	The code generated by the Thunk Compiler links to several Windows 95 entrypoint functions in KRNL386.EXE and KERNEL32.DLL. These entrypoint functions are specific to the Thunk Compiler and are not supported in Windows NT.

The entrypoint functions for KERNEL32.DLL are defined in THUNK32.LIB. You must link your 32-bit DLL with this library file.

In addition, the following two import statements should be added to the .DEF file for the 16-bit DLL.

C16ThkSL01     = KERNEL.631
ThunkConnect16 = KERNEL.651

Once again, these entrypoint functions exist only in Windows 95 and not in Windows NT. Attempts to load DLLs that use these functions will fail in Windows NT.


Implementing a Thunking Layer

The thunking model allows either the 16- or 32-bit thunk component to start first and clean up everything afterward. Follow these steps to implement the thunking layer:

1.	Add a procedure named "DllEntryPoint" to your 16-bit DLL. This procedure should look like the following example. (The names of the DLLs are for illustration only.)

BOOL FAR PASCAL __export SAMP_ThunkConnect16(LPSTR pszDll16,

    LPSTR pszDll32, WORD hInst, DWORD dwReason);

BOOL FAR PASCAL __export DllEntryPoint(DWORD dwReason, WORD hInst,

        WORD wDS, WORD wHeapSize, DWORD dwReserved1,
        WORD wReserved2) {

    if (!(SAMP_ThunkConnect16("DLL16.DLL", // name of 16-bit DLL

            "DLL32.DLL",                   // name of 32-bit DLL

            hInst, dwReason))) {

        return FALSE;

    }

    return TRUE;

}

In this example, "SAMP" is the base name — that is, the name of the thunk script file, not including the path and filename extension. If you used the /t option with the Thunk Compiler to specify a different base name, you would use the new base name in your procedure. You could, for example, use following command line.

THUNK /t MYNAME SAMP.THK

The thunk compiler generates the MYNAME_ThunkConnect16 routine, which should then be called in the DllEntryPoint procedure.

2.	Add the following import and export statements to your 16-bit DLL's module definition (.DEF) file, picking ordinals that are appropriate for your DLL.

EXPORTS
DllEntryPoint       @1 RESIDENTNAME
SAMP_ThunkData16    @2
IMPORTS
C16ThkSL01     = KERNEL.631
ThunkConnect16 = KERNEL.651

3.	Add the following function to your 32-bit DLL's entrypoint procedure (named DllMain by default). Again, the names of the DLLs are for illustration only.

BOOL WINAPI SAMP_ThunkConnect32(LPSTR pszDll16, LPSTR pszDll32,
    DWORD hIinst, DWORD dwReason);
BOOL _stdcall DllMain(DWORD hInst, DWORD dwReason,
        DWORD dwReserved) {
    if (!(SAMP_ThunkConnect32("DLL16.DLL", // name of 16-bit DLL
            "DLL32.DLL",                   // name of 32-bit DLL
            hInst, dwReason))) {
        return FALSE;

    }

    // Process dwReason.
}

4.	Add the following export statement to your 32-bit DLL's .DEF file.

EXPORT
SAMP_ThunkData32

The following implementation rules are very important:

•	The 16-bit DllEntryPoint function is called each time the module's usage count is incremented or decremented. The dwReason parameter is 1 when the usage count is incremented and zero when it is decremented.

•	Because the system calls the DllEntryPoint function while loading is underway, the value returned by the GetModuleUsage function is not reliable if you call it inside your DllEntryPoint function.

•	Do not call thunks inside the DllEntryPoint routines. Do not perform operations that reenter the 16-bit loader, yield the 16-bit scheduler, or release the 16-bit subsystem. These actions could cause unpredictable results and are not guaranteed to work in future versions of the Thunk Compiler.

•	You can have multiple ThunkConnectXX calls, so long as they connect to the same DLL. In fact, this is the only way to get both 32- to 16-bit and 16- to 32-bit thunks in one thunk-paired DLL set. The procedure is to have a thunk script for each direction and link both into each DLL. Then each entrypoint function will have two ThunkConnect calls.


Translating Pointers Outside Thunks

You may occasionally need to translate 16:16 pointers to 0:32 pointers outside of thunks. The GetVDMPointer32W, WOWGetVDMPointer, and WOWGetVDMPointerFix functions accomplish this. These functions are only required outside of thunks, because when pointers are thunked from 16 to 32 bits by the Thunk Compiler, no special handling is required to fix the segments. Because the Thunk Compiler fixes these segments automatically, 16:16 pointers can be passed to these thunks with no special treatment.

GetVDMPointer32W is a 16-bit function and is portable across Windows NT versions 3.1 and 3.5.

WOWGetVDMPointer is a 32-bit function and is portable across Windows NT version 3.5, but not Windows NT version 3.1.

WOWGetVDMPointerFix is a new 32-bit function. It is similar to WOWGetVDMPointer, but ensures that the memory pointed to will not be moved by the global memory compacter until WOWGetVDMPointerUnfix has been called. Using WOWGetVDMPointerFix and WOWGetVDMPointerUnfix is faster and easier than using WOWGetVDMPointer or GetVDMPointer32W.

If you use GetVDMPointer32W or WOWGetVDMPointer and the affected segment points to a movable global memory manager block, it is important to call the GlobalFix or GlobalWire function on the segment portion before computing its linear address. In Windows 95, the global memory compacter can break in at any time when your process is in 32-bit code. If this happens, the block may move and the linear address will become invalid. The debugging version of Windows 95 generates warnings about calls to GetVDMPointer32W on unfixed segments.

WOWGetVDMPointerFix converts a 16:16 pointer to a linear address like WOWGetVDMPointer. However, it also 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 implement and performance is better.

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 bottlenecks in the global memory manager. It is faster than the GlobalUnfix function and correctly handles (that is, ignores) selectors that are not from the global memory manager.

Note that the CallProc32W and CallProc32ExW functions do not call these functions for you. Pointers passed to these functions must be fixed manually.


Late Loading

Windows 95 improves system performance by supporting late loading for thunk DLLs. Loading the 16-bit DLL does not cause the corresponding 32-bit DLL to load immediately. Instead, the thunk subsystem loads the 32-bit DLL when the first 16- to 32-bit thunk is started.

Late loading has the following implications:

•	The performance and working set are improved for 16-bit applications that use only the 16-bit portions of thunked DLLs. The 32-bit DLL will not load into those processes.

•	The 16-bit DLL must not depend on any action taken by the 32-bit DLL's initialization code until at least one 16- to 32-bit thunk has been called.

•	Missing 32-bit DLLs or failed 32-bit loads will not be detected until the first call is made to a 16- to 32-bit thunk. If the 32-bit DLL cannot load or fails to initialize, the 16- to 32-bit thunk call will return a value of zero. This error code may be changed on a thunk by thunk basis by including a faulterrorcode = dword; line between the curly braces of a function call. For example, the following function instructs the thunk subsytem to return a  − 1 from the thunk call if it is the first thunk call and the 32-bit DLL cannot finish loading.

int Sample(void) {
    faulterrorcode = -1;
}

Although late loading is a valuable optimization for a 16-bit DLL that can execute autonomously from its 32-bit partner, it does complicate error recovery. Late loading can be disabled by including the following line in the thunk script.

preload32 = true;

If you use this option, the 16-bit subsystem will be released during the loading of your 16-bit DLL, possibly causing other 16-bit code to be reentered. For this reason, the preload32 statement is not available if your thunk script requires the win31compat statement. For more information about the win31compat statement, see "Compatibility with Existing 16-Bit DLLs" earlier in this topic.

Although the thunk compiler supports a "preload16" keyword for future expansion, late loading of 16-bit DLLs is neither supported nor planned.


Troubleshooting

This section outlines two common problems when thunking is implemented and describes their likely causes.

•	The 32-bit DLL will not load.

The Windows 95 loader requires that the 16-bit DLL be marked as subsystem version 4.0 or greater for the DllEntryPoint function to run. In addition, DllEntryPoint must be exported using the name "DllEntryPoint" and must be marked RESIDENTNAME.

To check the version number, run the Microsoft EXE File Header Utility (EXEHDR), using the following command line.

exehdr -v <your-16-bit-DLL>

The output should contain the following line.

Operating system: Microsoft Windows - version 4.0

If the subsystem version number is less than 4.0, you should use RC.EXE from the Win32 SDK to set the version of your 16-bit DLL correctly.

•	Loading the 16-bit DLL does not load the 32-bit DLL.

This is by design. A 32-bit DLL does not load into a process context until that process calls its first 16- to 32-bit thunk. For more information, see "Late Loading" earlier in this topic.

If this feature is incompatible with your DLL design, you may disable it by including the following line in your thunk script.

preload32 = true;


Reference

The following functions are associated with the Thunk Compiler.


16-bit WOW Functions

The functions in this section are 16-bit WOW API elements exported by KERNEL for use in generic thunks.


CallProc32W [New - Windows 95]
CallProc32W

[New - Windows 95]

DWORD FAR PASCAL CallProc32W(DWORD param1, DWORD param2, ... ,
    LPVOID lpProcAddress32, DWORD fAddressConvert, DWORD nParams);

Used by a 16-bit thunk dynamic-link library (DLL) to call an entrypoint function in a 32-bit DLL.

•	Returns a 32-bit value if successful. This value is the return value from the 32-bit entrypoint function represented by lpProcAddress32. The return value can also be zero if lpProcAddress32 is zero or if nParams is greater than 32.

param1 through param32

Parameters for the 32-bit procedure represented by lpProcAddress32.

lpProcAddress32

32-bit value corresponding to the procedure to be called, which is returned by the GetProcAddress32 function.

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.

nParams

Number of DWORD parameters passed (not counting fAddressConvert and nParams). For functions that take no parameters, this parameter will be zero.

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. Note that the lowest bit in the mask represents param1, the second lowest bit represents param2, and so on.

This function causes Windows 95 to release the 16-bit subsystem. If this function is used exclusively in 16-bit processes (as in Windows NT), there are no new reentrancy issues. Otherwise, the use of this function can cause 16-bit code to be reentered. For more information about reentrancy issues, see "Behavior of Win32 Functions Inside 16-Bit Processes" earlier in this topic.

Unlike the flat thunks, CallProc32W and CallProc32WEx 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. In Windows 95, global compaction can move memory blocks at any time while the current thread is executing 32-bit code. Because of this, certain pointer translation practices that worked in Windows NT may cause small, but undesirable, 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 DWORDs and are passed directly to the function called without conversion). No checks of the 16:16 address are made (limit checks, NULL checks, correct ring level, and so on).


CallProcEx32W [New - Windows 95]
CallProcEx32W

[New - Windows 95]

DWORD FAR CallProcEx32W(DWORD nParams, DWORD fAddressConvert,
    DWORD lpProcAddress, DWORD param1, ...);

Used by a 16-bit thunk dynamic-link library (DLL) to call an entrypoint function in a 32-bit DLL.

•	Returns a 32-bit value if successful. This value is the return value from the 32-bit entrypoint function represented by lpProcAddress. The return value can also be zero if lpProcAddress is zero or if nParams is greater than 32.

nParams

Number of DWORD parameters passed (not counting fAddressConvert and nParams). For functions that take no parameters, this parameter will be zero.

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.

lpProcAddress

32-bit value corresponding to the procedure to be called, which is returned by the GetProcAddress32 function.

param1 through param32

Parameters for the 32-bit procedure represented by lpProcAddress

CallProcEx32W is similar to CallProc32W, but it uses the C calling convention to allow easier and more flexible prototyping.

This function causes Windows 95 to release the 16-bit subsystem. If this function is used exclusively in 16-bit processes (as in Windows NT), there are no new reentrancy issues. Otherwise, the use of this function can cause 16-bit code to be reentered. For more information about reentrancy issues, see "Behavior of Win32 Functions Inside 16-Bit Processes" earlier in this topic.

Unlike the flat thunks, CallProc32W and CallProc32WEx 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. In Windows 95, global compaction can move memory blocks at any time while the current thread is executing 32-bit code. Because of this, certain pointer translation practices that worked in Windows NT may cause small, but undesirable, race conditions in Windows 95.


FreeLibrary32W [New - Windows 95]
FreeLibrary32W

[New - Windows 95]

BOOL FAR PASCAL FreeLibrary32W(DWORD hInst);

Allows a 16-bit thunk dynamic-link library (DLL) to free a 32-bit thunk DLL that it had previously loaded by using the LoadLibraryEx32W function.

•	Returns TRUE if successful or FALSE otherwise.

hInst

This function thunks to the Win32 FreeLibrary function. For a complete description of this parameter, see the documentation included in the Win32 SDK.

Note that WOW does not do any cleanup of 32-bit thunk DLLs when the WOW task exits. It is up to the 16-bit thunk DLLs to free the 32-bit thunk DLLs, as necessary.

This function causes Windows 95 to release the 16-bit subsystem. Therefore, your code may be reentered during the call to this function. However, if this function is only used in 16-bit processes (as in Windows NT) and none of the DLL's notification routines yield, this reentrancy will not occur.


GetProcAddress32W [New - Windows 95]
GetProcAddress32W

[New - Windows 95]

DWORD FAR PASCAL GetProcAddress32W(DWORD hModule, LPCSTR lpszProc);

Allows a 16-bit thunk dynamic-link library (DLL) to retrieve a value that corresponds to a 32-bit thunk routine.

•	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.

hModule through lpszProc

This function thunks to the Win32 GetProcAddress function. For a complete description of this parameter, see the documentation included in the Win32 SDK.

This function causes Windows 95 to release the 16-bit subsystem. Therefore, your code may be reentered during the call to this function. However, if this function is only used in 16-bit processes (as in Windows NT) and none of the DLL's notification routines yield, this reentrancy will not occur.


GetVDMPointer32W [New - Windows 95]
GetVDMPointer32W

[New - Windows 95]

DWORD FAR PASCAL GetVDMPointer32W(LPVOID lpAddress, UINT fMode);

Allows a 16-bit thunk dynamic-link library (DLL) to translate a 16-bit far pointer into a 32-bit flat pointer for use by a 32-bit thunk DLL.

•	Returns a 32-bit linear address if successful or NULL otherwise.

lpAddress

Valid 16:16 address, either in protected or real mode.

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.
The WOW KERNEL memory manager moves segments in memory and keeps the selectors the same. However, if you get the linear address, it may not be valid if the memory manager has moved memory. You should assume that global compaction can occur any time that a 16- to 32-bit flat thunk or generic thunk is entered, a function is called, or the current task yields.


LoadLibraryEx32W [New - Windows 95]
LoadLibraryEx32W

[New - Windows 95]

DWORD FAR PASCAL LoadLibraryEx32W(LPCSTR lpszLibFile, DWORD hFile,
    DWORD dwFlags);

Allows a 16-bit thunk dynamic-link library (DLL) to load a 32-bit thunk DLL.

•	Returns a 32-bit handle to a DLL instance if successful or NULL otherwise.

lpszLibFile through dwFlags

This function thunks to the Win32 LoadLibraryEx function. For a complete description of this parameter, see the documentation included in the Win32 SDK.

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 function.

This function causes Windows 95 to release the 16-bit subsystem. Therefore, your code may be reentered during the call to this function. However, if this function is only used in 16-bit processes (as in Windows NT) and none of the DLL's notification routines yield, this reentrancy will not occur.


32-bit WOW Functions

The functions in this section are 32-bit WOW API elements exported by WOW32.DLL.


WOWCallback16 [New - Windows 95]
WOWCallback16

[New - Windows 95]

DWORD WINAPI WOWCallback16(DWORD vpfn16, DWORD dwParam);

Used in 32-bit code called from 16-bit code (through generic thunks) to call back to the 16-bit side (generic callback).

•	The return value comes from the callback routine. If the callback routine returns a WORD types instead of a DWORD types, the upper 16 bits of the return value are undefined. If the callback routine has no return value, the entire return value of this function is undefined.

vpfn16

Pointer to 16-bit callback routine, which is passed from the 16-bit side.

dwParam

Parameter for the 16-bit callback routine.

This function will not work when called in a 32-bit process.

The 16-bit function to be called must be declared with one of the following types.

   LONG FAR PASCAL CallbackRoutine(DWORD dwParam);

   LONG 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.


WOWCallback16Ex [New - Windows 95]
WOWCallback16Ex

[New - Windows 95]

BOOL WINAPI WOWCallback16Ex(DWORD vpfn16, DWORD dwFlags, DWORD cbArgs,
    PVOID pArgs, PDWORD pdwRetCode);

Used in 32-bit code called from 16-bit code (through generic thunks) to call back to the 16-bit side (generic callback).

•	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 types, the upper 16 bits of the return code are undefined and should be ignored by using LOWORD(dwRetCode).

vpfn16

Pointer to 16-bit callback routine, which is 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).
cbArgs

Count of bytes in arguments (used to properly clean the 16-bit stack).

pArgs

Arguments for the callback routine.

pdwRetCode

Return code from the callback routine.

This function will not work when called in a 32-bit process.

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 routine's calling convention. For example, to call the Pascal routine SetWindowText, pArgs would point to an array of words.

LONG FAR PASCAL SetWindowText(HWND hwnd, LPCSTR lpsz);

WORD SetWindowTextArgs[] = {OFFSETOF(lpsz), SELECTOROF(lpsz), hwnd};

In other words, the arguments are placed in the array in reverse order, with the least significant word first for DWORD types and offset first for FAR pointers.

To call the _cdecl routine wsprintf, pArgs would also point to an array of words.

LPSTR lpszFormat = "%d %s";

int _cdecl wsprintf(lpsz, lpszFormat, nValue. lpszString);

WORD wsprintfArgs[] = {OFFSETOF(lpsz), SELECTOROF(lpsz),
    OFFSETOF(lpszFormat), SELECTOROF(lpszFormat), nValue,
    OFFSETOF(lpszString), SELECTOROF(lpszString)};

In other words, the arguments are placed in the array in the order listed in the function prototype with the least significant word first for DWORD types and offset first for FAR pointers.


WOWGetVDMPointer [New - Windows 95]
WOWGetVDMPointer

[New - Windows 95]

LPVOID WINAPI WOWGetVDMPointer(DWORD vp, DWORD dwBytes,
    BOOL fProtectedMode);

Converts a 16:16 address to the equivalent flat address.

•	Returns a 32-bit address if successful. If the selector is invalid, the return value is NULL.

vp

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.
0	The upper 16 bits are treated as a real-mode segment value.
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.

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 16-bit subsystem is not locked by the current thread.


WOWGetVDMPointerFix [New - Windows 95]
WOWGetVDMPointerFix

[New - Windows 95]

LPVOID WINAPI WOWGetVDMPointerFix(DWORD vp, DWORD dwBytes,
    BOOL fProtectedMode);

Converts a 16:16 address to the equivalent flat address. Unlike the WOWGetVDMPointer function, this function calls the GlobalFix function before returning the flat address so that the 16-bit memory will not move around in linear space.

•	Returns a 32-bit address if successful. If the selector is invalid, the return value is NULL.

vp

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.
0	The upper 16 bits are treated as a real-mode segment value.


WOWGetVDMPointerUnfix [New - Windows 95]
WOWGetVDMPointerUnfix

[New - Windows 95]

VOID WINAPI WOWGetVDMPointerUnfix(DWORD vp);

Uses the GlobalUnfix function to unfix a pointer retrieved by the WOWGetVDMPointerFix function.

•	No return value.

vp

Address retrieved by the WOWGetVDMPointerFix function.


WOWGlobalAlloc16 [New - Windows 95]
WOWGlobalAlloc16

[New - Windows 95]

WORD  WINAPI WOWGlobalAlloc16(WORD wFlags, DWORD cb);

Thunks to the 16-bit version of the function with the same name. For more information, see the documentation for the 16-bit versions.


WOWGlobalAllocLock16 [New - Windows 95]
WOWGlobalAllocLock16

[New - Windows 95]

DWORD WINAPI WOWGlobalAllocLock16(WORD wFlags, DWORD cb, WORD *phMem);

Combines the functionality of the WOWGlobalAlloc16 and WOWGlobalLock16 functions, thunking to the 16-bit versions of the functions with those names. For more information, see the documentation for the 16-bit versions.


WOWGlobalFree16 [New - Windows 95]
WOWGlobalFree16

[New - Windows 95]

WORD  WINAPI WOWGlobalFree16(WORD hMem);

Thunks to the 16-bit version of the function with the same name. For more information, see the documentation for the 16-bit versions.


WOWGlobalLock16 [New - Windows 95]
WOWGlobalLock16

[New - Windows 95]

DWORD WINAPI WOWGlobalLock16(WORD hMem);

Thunks to the 16-bit version of the function with the same name. For more information, see the documentation for the 16-bit versions.


WOWGlobalLockSize16 [New - Windows 95]
WOWGlobalLockSize16

[New - Windows 95]

DWORD WINAPI WOWGlobalLockSize16(WORD hMem, PDWORD pcb);

Combines the functionality of the WOWGlobalLock16 and GlobalSize functions, thunking to the 16-bit versions of the functions with those names. For more information, see the documentation for the 16-bit versions.


WOWGlobalUnlock16 [New - Windows 95]
WOWGlobalUnlock16

[New - Windows 95]

BOOL  WINAPI WOWGlobalUnlock16(WORD hMem);

Thunks to the 16-bit version of the function with the same name. For more information, see the documentation for the 16-bit versions.


WOWGlobalUnlockFree16 [New - Windows 95]
WOWGlobalUnlockFree16

[New - Windows 95]

WORD  WINAPI WOWGlobalUnlockFree16(DWORD vpMem);

Combines the functionality of the WOWGlobalUnlock16 and WOWGlobalFree16 functions, thunking to the 16-bit versions of the functions with those names. For more information, see the documentation for the 16-bit versions.


WOWHandle16 [New - Windows 95]
WOWHandle16

[New - Windows 95]

WORD WINAPI WOWHandle16(HANDLE, WOW_HANDLE_TYPE);

This function (and the associated macro) is used to map a 32-bit handle to a 16-bit handle. Because the relationship between a Win16 handle and a Win32 handle may change in the future, this function should be used instead of any private knowledge of the relationship between them.

This function uses the WOW_HANDLE_TYPE parameter to indicate the type of handle being translated. Types supported include HWND, HMENU, HDWP, HDROP, HDC, HFONT, HMETAFILE, HRGN, HBITMAP, HBRUSH, HPALETTE, HPEN, HACCEL, HTASK, and FULLHWND.

The WOW_HANDLE_TYPE name corresponding to each of these types is of the form WOW_TYPE_handle (for example, WOW_TYPE_HWND).

You can use macros to map handles between Win16 and Win32. For example, to map a Win16 HWND to a Win32 HWND, you would use the HWND_32 macro.

(hWnd32 = HWND_32(hWnd16))

A "full" hWnd is a hWnd that a Win32-based application would see (and therefore can be used in comparisons with 32-bit hWnds received from Win32 functions.) The other hWnd type has a different value, but is recognized by the system. Do not make assumptions about the relationship between the 16-bit hWnd, the 32-bit Hwnd, and the 32-bit Full hWnd. This relationship has changed in the past (for performance reasons), and it may change again in the future.


WOWHandle32 [New - Windows 95]
WOWHandle32

[New - Windows 95]

HANDLE WINAPI WOWHandle32(WORD, WOW_HANDLE_TYPE);

This function (and the associated macro) 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, this function should be used instead of any private knowledge of the relationship between them.

This function uses the WOW_HANDLE_TYPE parameter to indicate the type of handle being translated. Types supported include HWND, HMENU, HDWP, HDROP, HDC, HFONT, HMETAFILE, HRGN, HBITMAP, HBRUSH, HPALETTE, HPEN, HACCEL, HTASK, and FULLHWND.

The WOW_HANDLE_TYPE name corresponding to each of these types is of the form WOW_TYPE_handle (for example, WOW_TYPE_HWND).

You can use macros to map handles between Win16 and Win32. For example, to map a Win16 HWND to a Win32 HWND, you would use the HWND_32 macro.

(hWnd32 = HWND_32(hWnd16))

A "full" hWnd is a hWnd that a Win32-based application would see (and therefore can be used in comparisons with 32-bit hWnds received from Win32 functions.) The other hWnd type has a different value, but is recognized by the system. Do not make assumptions about the relationship between the 16-bit hWnd, the 32-bit Hwnd, and the 32-bit Full hWnd. This relationship has changed in the past (for performance reasons), and it may change again in the future.


Overview of the Build Process

This guide describes how to build 32-bit applications for Windows and dynamic-link libraries (DLLs) using the Microsoft Win32 Software Development Kit (SDK). It describes the components of a generalized makefile and includes information on using the C run-time libraries.

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

Steps to Building Applications

Step	Tool
1. Compile C and C++ source-language files into object files.	C/C++ compiler (CL)
2. Create and edit resources. Doing so may also create include (.H) files which define useful constants.	Dialog Editor, Image Editor, and Font Editor (DLGEDIT, IMAGEDIT, and FONTEDIT)
3. Compile resource scripts to linkable resource files.	Resource Compiler (RC)
4. Compile the module-definition file for each DLL to an import library and export library.	Library manager (LIB)
5. Link the object modules, resources, standard libraries, and import libraries (for an application using DLLs) or export library (for a DLL) to produce an application.	Linker (LINK)
6. Use the appropriate switches to build a debugging version of the application or DLL.	Linker switches: /debug:full, /debugtype:cv
If you are familiar with the process of building applications and DLLs for Windows 3.x, you will notice some differences. The following parts of the build process are new or different with Win32:

•	Resources are linked along with object modules and libraries. You do not need to run the resource compiler to add resources to the executable file.

•	When building a DLL, create an import library from a .DEF file, then link the DLL with the import library. The linker does not accept a .DEF file when resolving imports.

•	When linking a DLL, you must specify the name of the initialization routine using the linker /ENTRY option. This is the result of the new DLL initialization and termination model in Win32.

•	You link a DLL with an export library (.EXP file). The export library is generated by LIB at the same time it generates the import library from the .DEF file.

The sample makefiles provided with the SDK samples give good examples of the build process. Each of them includes WIN32.MAK, which defines most of the common macros you need to build 32-bit applications for Windows NT and Windows 95. For information on source code considerations in porting your code from 16- to 32-bits, see the following topics:

Porting 16-Bit Code to 32-Bit Windows
Handling Messages with Portable Macros
Writing Portable C Programs
WINDOWS.H and STRICT Type Checking


Using WIN32.MAK

It is recommended that you examine the contents of WIN32.MAK, located in the \MSTOOLS\H subdirectory. There are macros defined in this makefile template that can be used to simplify your own makefiles and to ensure that they are properly built to avoid conflicts.

For example, WIN32.MAK includes the following macros to simplify compilation:

•	$(CVARSDLL)

This macro is used for DLLs (single-threaded or multi-threaded). It expands to the following flags:

-DWIN32 -D_WIN32 -DNULL=0 -D_MT -D_DLL

•	$(CVARS)

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

-DWIN32 -D_WIN32 -DNULL=0

WIN32.MAK also includes macros to simplify linking, among which are the following:

•	$(CONLIBSDLL)

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

CRTDLL.LIB KERNEL32.LIB ADVAPI32.LIB

•	$(GUILIBSDLL)

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

CRTDLL.LIB KERNEL32.LIB ADVAPI32.LIB USER32.LIB GDI32.LIB \

COMDLG32.LIB WINSPOOL.LIB


Building Applications

In the following example, the object files and libraries are linked to produce the application executable file. Note that the resource file (*.res) is linked along with the object files.

The following is a simple example of a linker command line (used in an inline response file):

#  Build an executable (.exe) file
$(TARGET).exe : $(OBJS) $(TARGET).res
$(LINK) @<<
/out:$(TARGET).exe
/debug:notmapped,full
/debugtype:cv
/machine:$(CPU)
/subsystem:windows
$(LINK_FLAGS)
$(OBJS)
$(TARGET).res
$(LIBS)
<<


Building DLLs

The following example illustrates how to create the import and export libraries for a DLL. The import library is linked with the application that uses this DLL. The export library is linked with the DLL. The export library is not explicitly listed in the command because the library tool automatically generates it along with the import library.

#  Generate import library (.lib) and export library (.exp)
#  from a module-definition (.def) file for a DLL
$(TARGET).lib $(TARGET).exp : $(TARGET).def
$(IMPLIB) /out:$(TARGET).lib /machine:$(CPU)
/def:$(TARGET).def

The following example links the DLL. The /DLL and /ENTRY options are required to build a DLL. The /DLL option specifies that the output file is a DLL. The /ENTRY option specifies the name of the DLL initialization routine.

# Build DLL using objects and export library
$(TARGET).dll : $(OBJS) $(TARGET).exp
$(LINK) @<<
/out:$(TARGET).dll
/dll
-entry:_DllMainCRTStartup$(DLLENTRY)
/debug:full
/debugtype:cv
/machine:$(CPU)
/subsystem:windows
$(LFLAGS)
$(OBJS)
$(TARGET).exp
$(CONLIBSDLL)
<<

The WIN32.MAK file supplied in \MSTOOLS\H will help simplify the build process. The compiler and linker switches shown in the above examples are defined as macros in this file.


Using the C Run-Time Library

This guide describes how to use the different forms of the C run-time libraries when building your 32-bit application. It also describes how to specify the entry point when linking a DLL with the run-time libraries.

With the original Win32 SDK, three forms of the C run-time library were provided:

LIBC.LIB

Statically linked library for single-threaded applications.

LIBCMT.LIB

Statically linked library that supports multi-threaded applications.

CRTDLL.LIB

Import library for CRTDLL.DLL (the C run-time DLL) that also supports multi-threaded applications.

The C run-time library is not intrinsic to the Win32 SDK, however. These libraries should come from the same source as the compiler. For new computer architectures, the Win32 SDK typically provided the compiler and C run-time libraries until there were other offerings available. At that point, the SDK stopped including these pieces and allowed programmers to choose their favorite vendor.

The names of the libraries may differ from vendor to vendor. These name differences can be encapsulated in WIN32.MAK. The Microsoft names used in the Visual C++ product are LIBC.LIB, LIBCMT.LIB, and MSVCRT.DLL.


Calling the C Run-Time Library from a DLL

When linking a DLL with any of the C run-time libraries, the entry point for the DLL must be the routine _CRT_INIT, or your initialization code must explicitly call _CRT_INIT every time the DLL entry point is called.

To call _CRT_INIT if you do not have your own DLL entry point

1.	Specify _CRT_INIT as the entry point of the DLL.

2.	Assuming that you have included WIN32.MAK (which defines the macro DLLENTRY as @12), add the following option to the DLL's linker command line:

-entry:_CRT_INIT$(DLLENTRY)

To call _CRT_INIT if you have your own DLL entry point

1.	Add the following code in the entry point, using this prototype for _CRT_INIT:

BOOL WINAPI _CRT_INIT( HINSTANCE hinstDLL, DWORD fdwReason,
LPVOID lpReserved );

For information on _CRT_INIT return values, see DllEntryPoint. This function returns the same values as _CRT_INIT.

2.	On PROCESS_ATTACH and THREAD_ATTACH (see DllEntryPoint for more information on these flags), call _CRT_INIT at the beginning of the initialization routine, before any C run-time functions are called or any floating-point operations are performed.

3.	Call your own process/thread initialization/termination code.

4.	On PROCESS_DETACH and THREAD_DETACH, call _CRT_INIT near the end of the initialization routine, after all C run-time functions are called and all floating-point operations are completed.

Be sure to pass all of the parameters of the entry point to _CRT_INIT. Because _CRT_INIT expects these parameters, your application may not work reliably if they are omitted (in particular, fdwReason is required to determine whether process initialization or termination is needed).

The following is a sample entry point function that shows how and when to make these calls to _CRT_INIT in the DLL entry point:

BOOL WINAPI DllEntryPoint( HINSTANCE hinstDLL, DWORD 	fdwReason, LPVOID lpReserved )

{

// Initialize the C run-time before calling any of your code.

if( fdwReason == DLL_PROCESS_ATTACH || fdwReason ==
DLL_THREAD_ATTACH )

if( !_CRT_INIT( hinstDLL, fdwReason, lpReserved ) )

return( FALSE );

// Place your DLL's initialization/termination code here. If you
// are porting from 16-bits and have an existing LibMain routine,
// you can call it here. For example:

// if( fdwReason == DLL_PROCESS_ATTACH )

// 	LibMain();

// Terminate the C run-time after all your code.

if( fdwReason == DLL_PROCESS_DETACH || fdwReason ==
DLL_THREAD_DETACH )

if( !_CRT_INIT( hinstDLL, fdwReason, lpReserved ) )

return( FALSE );

return( TRUE );

}

For more information, see DllMainCRTStartup.


DllMainCRTStartup

The complexity involved in initializing the C run-time library from a DLL is cleared up by using the $(dlllflags) macro in NTWIN32.MAK. It will specify the following switch to the linker:

-entry:_DllMainCRTStattup$(DLLENTRY)

This entry point is exported from the C run-time libraries.

DllMainCRTStartup will call CRT_INIT and it will call the DllMain function exported from your own DLL. The order of the calls is dependent on whether the process or thread is attaching (in which case CRT_INIT is called first) or detaching (in which case CRT_INIT is called last).

In summary, export DllMain from your DLL, use the $(dlllflags) macro in the link line of your makefile, and don't call CRT_INIT explicitly.


Using Multiple C Run-Time Libraries

If your application makes C run-time library calls and also calls functions contained in a DLL that makes C run-time library calls, note the following. If the executable and the DLL are both linked with one of the statically linked C run-time libraries (LIBC.LIB or LIBCMT.LIB), the executable and the DLL will have separate copies of all C run-time functions and global variables. This means that C run-time data cannot be shared between the executable and the DLL.

To avoid this problem, link both the executable and the DLL with CRTDLL.LIB. This allows both the executable and the DLL to use the common set of functions and data contained in CRTDLL.DLL. C run-time data such as stream handles can then be shared by both the executable and the DLL.


Mixing Library Types

If your DLL is linked with CRTDLL.LIB, any executables that call your DLL must also be linked with CRTDLL.LIB. Linking the executable with either LIBC.LIB or LIBCMT.LIB and the DLL with CRTDLL.LIB can cause unpredictable results. Unless you are sure that the DLL will only be called by EXEs that are linked with CRTDLL.LIB, you must link the DLL with one of the statically linked C run-time libraries (LIBC.LIB or LIBCMT.LIB). If you are unsure, you should link the EXE and all DLLs it will call with CRTDLL.DLL.

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


Storage Class Attributes

This section describes extended attribute syntax, which simplifies and standardizes the Microsoft-specific extensions to the Microsoft C and C++ languages. The storage class attributes that use extended attribute syntax include thread, naked, dllimport, and dllexport.


Extended Attribute Syntax (Microsoft Specific)

The extended attribute syntax for specifying storage class information uses the declspec keyword, which specifies that an instance of a given type is to be stored with a Microsoft-specific storage class attribute (thread, naked, dllimport, or dllexport). Some examples of other storage class modifiers include the static and extern keywords. However, these keywords are part of the ANSI specification of the C and C++ languages, and as such are not covered by extended attribute syntax.

This is the extended attribute syntax for C:

Syntax

storage-class-specifier:
typedef
extern
static
auto
register
__declspec ( extended-decl-modifier-list )

For C++, the syntax looks like this:

Syntax

decl-specifier:
storage-class-specifier
type-specifier
fct-specifier
friend
typedef
__declspec ( extended-decl-modifier-list )

For C and C++, the extended-decl-modifier-list syntax looks like this:

Syntax

extended-decl-modifier-list:
extended-decl-modifier
extended-decl-modifier extended-decl-modifier-list

extended-decl-modifier:
thread
naked
dllimport
dllexport

White space separates the declaration modifier lists. Examples of the syntax appear in later sections.

The thread, naked, dllimport, and dllexport storage class attributes are a property only of the declaration of the object or function to which they are applied. Unlike the __near and __far keywords, which actually affect the type of object or function (in this case, 2- and 4-byte addresses), these storage class attributes do not redefine the type attributes of the object itself. The thread attribute affects data and objects only. The naked attribute affects functions only. The dllimport and dllexport attributes affect functions, data, and objects.

The following statement declares an integer variable, tls_i, which is used to store thread-specific data.

__declspec( thread ) int tls_i = 1;

To make your code more readable, you can control such declarations using macro definitions:

#define Thread  __declspec( thread )
Thread int tls_i = 1;


The Thread Attribute (32-bit Specific)

Thread Local Storage (TLS) is the mechanism by which each thread in a given multi-threaded process allocates storage for thread-specific data. In standard multi-threaded programs, data is shared among all threads of a given process, whereas thread-local storage is the mechanism for allocating per-thread data. For a complete discussion of threads, see Processes and Threads.

The C and C++ languages include a new extended storage class attribute, thread. The thread attribute must be used with the __declspec keyword to declare a thread variable. For example, the following code declares an integer thread local variable and initializes it with a value:

__declspec( thread ) int tls_i = 1;

Rules and Limitations

The following guidelines must be observed when you are declaring statically bound thread local objects and variables.

•	You can apply the thread attribute only to data declarations and definitions. It cannot be used on function declarations or definitions. For example, the following code generates a compiler error:

#define Thread	__declspec( thread )
Thread void func();	// Error

•	You can specify the thread attribute only on data items with static storage duration. This includes global data objects (both static and extern), local static objects, and static data members of C++ classes. You cannot declare automatic data objects with the thread attribute. For example, the following code generates compiler errors:

#define Thread	__declspec( thread )

void func1()

{

Thread int tls_i;	// Error

}

int func2( Thread int tls_i )	// Error

{

return tls_i;

}

•	You must use the thread attribute for the declaration and the definition of a thread local object, regardless of whether the declaration and definition occur in the same file or separate files. For example, the following code generates an error:

#define Thread	__declspec( thread )

extern int tls_i;	// This generates an error, because the

int Thread tls_i;	// declaration and the definition differ.

•	You cannot use the thread attribute as a type modifier. For example, the following code generates a compiler error:

char __declspec( thread ) *ch;	// Error

•	C++ classes cannot use the thread attribute. However, you can instantiate C++ class objects with the thread attribute. For example, the following code generates a compiler error:

#define Thread __declspec( thread )

class Thread C	// Error: classes can't be declared Thread.

{

// Code

};

C CObject;

Because the declaration of C++ objects that use the thread attribute is permitted, these two examples are semantically equivalent:

#define Thread	__declspec( thread )

Thread class B

{

// Code

} BObject;	// Okay--BObject declared thread local.

class B

{

// Code

}

Thread B BObject;	// Okay--BObject declared thread local.

•	Because C++ objects with constructors and destructors, as well as objects that use initialization semantics, can be allocated as thread local, an associated initialization routine must be called to initialize the object. In this example, the constructor initializes the thread local object:

class tlsClass

{

private:

int x;

public:

tlsClass() { x = 1; } ;

~tlsClass();

}

__declspec( thread ) tlsClass tlsObject;

extern int func();

__declspec( thread ) int y = func();

•	The address of a thread local object is not considered constant, and any expression involving such an address is not considered a constant expression. In C and C++, this means that you cannot use the address of a thread local variable as an initializer for an object or pointer. For example, the compiler flags the following code as an error:

#define Thread	__declspec( thread )

Thread int tls_i;

int *p = &tls_i;	//Error

•	Standard C permits initialization of an object or variable with an expression involving a reference to itself, but only for objects of non-static extent. Although C++ normally permits such dynamic initialization of an object with an expression involving a reference to itself, this type of initialization is not permitted with thread local objects. For example:

#define Thread	__declspec( thread )

Thread int tls_i = tls_i;	// C and C++ error

int j = j;	// Okay in C++; C error

Thread int tls_i = sizeof( tls_i )	// Okay in C and C++

Note that a sizeof expression that includes the object being initialized does not constitute a reference to itself, and is allowed in C and C++.


The Naked Attribute (32-bit Specific)

For functions declared with the naked attribute, the compiler generates code without prolog and epilog code. You can use this feature to write your own prolog/epilog code sequences using inline assembly code. Naked functions are particularly useful in writing virtual device drivers and interrupt handlers.

Because the naked attribute is only relevant to the definition of a function and is not a type modifier, naked functions use the extended attribute syntax, described previously. For example, this code defines a function with the naked attribute:

__declspec( naked ) int func( formal_parameters )

{

// Function body

}

Or, alternatively:

#define Naked	__declspec( naked )

Naked int func( formal_parameters )

{

// Function body

}

The naked modifier affects only the nature of the compiler's code generation for the function's prolog and epilog sequences. It does not affect the code that is generated for calling such functions. Thus, the naked attribute is not considered part of the function's type, and function pointers cannot have the naked attribute. Furthermore, the naked attribute cannot be applied to a data definition. For example, the following code samples generate errors:

__declspec( naked ) int i;	// Error--naked attribute not
// permitted on data
// declarations.

The naked attribute is relevant only to the definition of the function and cannot be specified in the function's prototype. The following declaration generates a compiler error:

__declspec( naked ) int func();	// Error--naked attribute
// not permitted on function
// declarations.

Rules and Limitations

•	The return statement is not permitted in a naked function. However, you can return an int by moving the return value into the eax register before the ret instruction.

•	Structured exception handling constructs are not permitted in a naked function because the constructs must unwind across the stack frame.

•	Any use of the setjmp run-time function is not permitted in a naked function because it too must unwind across the stack frame. However, use of the longjmp run-time function is permitted.

•	Use of the _alloca function is not permitted in a naked function.

•	To ensure that no initialization code for local variables appears before the prolog sequence, initialized local variables are not permitted at function scope. In particular, the declaration of C++ objects is not permitted at function scope. There can, however, be initialized data in a nested scope.

•	Frame pointer optimization (the /Oy compiler option) is not recommended, but it is automatically suppressed for a naked function.


Considerations for Writing Prolog/Epilog Code

Before writing your own prolog and epilog code sequences, it is important to understand how the stack frame is laid out, and some differences in stack frame layout between 16-bit and 32-bit targets. It is also useful to know how to use the _LOCAL_SIZE symbol. These topics are discussed in the following sections.


Stack Frame Layout

A few minor differences exist between 16- and 32-bit stack frame layout. This example shows the standard prolog code that might appear in a 32-bit function:

push	ebp	; Save ebp

mov	ebp, esp	; Set stack frame pointer

sub	esp, localbytes	; Allocate space for locals

push	registers	; Save registers

The localbytesvariable represents the number of bytes needed on the stack for local variables, and the registers variable is a placeholder that represents the list of registers to be saved on the stack. After pushing the registers, you can place any other appropriate data on the stack. The following is the corresponding epilog code:

pop	registers	; Restore registers

mov	esp, ebp	; Restore stack pointer

pop	ebp	; Restore ebp

ret	; Return from function

The stack always grows down (from high to low memory addresses). The base pointer (ebp) points to the pushed value of ebp. The locals area begins at ebp-2. To access local variables, calculate an offset from ebp by subtracting the appropriate value from ebp.

The only change in these code sequences for 16-bit targets is that the register names do not begin with an e. For 16-bit targets, the register names in the examples above would be bp and sp.


__LOCAL_SIZE

The compiler provides a symbol, __LOCAL_SIZE, for use in the inline assembly block of function prolog code. This symbol is used to allocate space for local variables on the stack frame in custom prolog code.

The compiler determines the value of __LOCAL_SIZE. Its value is the total number of bytes of all user-defined local variables and compiler-generated temporary variables. __LOCAL_SIZE can be used only as an immediate operand; it cannot be used in an expression. You must not change or redefine the value of this symbol. For example:

mov	eax, __LOCAL_SIZE	;Immediate operand--Okay

mov	eax, __LOCAL_SIZE + 4	;Error

mov	eax, [ebp - __LOCAL_SIZE]	;Error

The following example of a naked function containing custom prolog and epilog sequences uses __LOCAL_SIZE symbol in the prolog sequence:

__declspec ( naked ) func()

{

int i;

int j;

__asm	/* prolog */

{

push	ebp

mov	ebp, esp

sub	esp, __LOCAL_SIZE

}

/* Function body */

__asm	/* epilog */

{

mov	esp, ebp

pop	ebp

ret

}

}


The Dllexport and Dllimport Attributes (32-bit Specific)

The dllexport and dllimport storage class modifiers export and import functions, data, and objects to and from a DLL. These modifiers, or attributes, explicitly define the DLL's interface to its client, which can be the executable file or another DLL. Declaring functions as dllexport eliminates the need for a module-definition (.DEF) file, at least with respect to the specification of exported functions. Note that dllexport replaces the __export keyword.

The declaration of dllexport and dllimport uses extended attribute syntax:

#define DllImport	__declspec( dllimport )

#define DllExport	__declspec( dllexport )

DllExport void func();

DllExport int i = 10;

DllImport int j;

DllExport int n;


Definitions and Declarations

The DLL interface refers to all items (functions and data) that are known to be exported by some program in the system, that is, all items that are declared as dllimport or dllexport. All declarations included in the DLL interface must specify either the dllimport or dllexport attribute. However, the definition can specify only the dllexport attribute. For example, the following function definition generates a compiler error:

#define DllImport	__declspec( dllimport )

#define DllExport	__declspec( dllexport )

DllImport int func()	// Error; dllimport prohibited on definition.

{

return 1;

}

This code also generates an error:

DllImport int i = 10;	// Error; this is a definition.

However, this is correct syntax:

DllExport int i = 10;	// Okay; this is an export definition.

The use of dllexport implies a definition, while dllimport implies a declaration. You must use the extern keyword with dllexport to force a declaration; otherwise, a definition is implied. Thus, the following examples are correct:

extern DllImport int k;	// These are both correct and imply a
DllImport int j;	// declaration.

The following examples help to further clarify the above:

static DllImport int l;	// Error; not declared extern.

void func()

{

static DllImport int s;	// Error; not declared extern.

DllImport int m;	// Okay; this is a declaration.

DllExport int n;	// Error; implies external
// definition in local scope.

extern DllImport int i;	// Okay; this is a declaration.

extern DllExport int k;	// Okay; extern implies
// declaration.

DllExport int x = 5;	// Error; implies external
// definition in local scope.

}


Defining Inline Functions with Dllexport and Dllimport

You can define as inline a function with the dllexport attribute. In this case, the function is always instantiated and exported, whether or not any module in the program references the function. The function is presumed to be imported by another program.

You can also define as inline a function declared with the dllimport attribute. In this case, the function can be expanded (subject to /Ob compiler switch specifications), but never instantiated. In particular, if the address of an inline imported function is taken, the address of the function residing in the DLL is returned. This behavior is the same as taking the address of a non-inline imported function.

These rules apply to inline functions whose definitions appear within a class definition. In addition, static local data and strings in inline functions maintain the same identities between the DLL and client as they would in a single program (that is, an executable file without a DLL interface).

Exercise care when providing imported inline functions. For example, if you update the DLL, don't assume that the client will use the changed version of the DLL. To ensure that you are loading the proper version of the DLL, rebuild the DLL's client as well.


General Rules and Limitations

•	If you declare a function or object without the dllimport or dllexport attribute, the function or object is not considered part of the DLL interface. Therefore, the definition of the function or object must be present in that module or in another module of the same program. To make the function or object part of the DLL interface, you must declare the definition of the function or object in the other module as dllexport. Otherwise, a linker error is generated.

If you declare a function or object with the dllexport attribute, its definition must appear in some module of the same program. Otherwise, a linker error is generated.

•	If a single module in your program contains both dllimport and dllexport declarations for the same function or object, the dllexport attribute takes precedence over the dllimport attribute. However, a compiler warning is generated. For example:

DllImport int i;

DllExport int i;	// Warning; inconsistent, but
// dllexport takes precedence.

•	In C, if you initialize a globally declared pointer with the address of a data object declared with the dllimport attribute, a compiler error is generated. Similarly, you cannot initialize a static local function pointer with the address of a function declared with the dllimport attribute, or initialize a static local data pointer with the address of a data object declared with the dllimport attribute. The C++ compiler does not enforce this restriction, because C++ supports dynamic initialization of local and global static objects. For example, the following code generates errors when compiled with the C compiler, but not with the C++ compiler:

DllImport void func1( void );

DllImport int i;

int *pi = &i;	// Error in C

static void ( *pf )( void ) = &func1;	// Error in C

void func2()

{

static int *pi = &i;	// Error in C

static void ( *pf )( void ) = &func1;	// Error in C

}

However, because a program that includes the dllexport attribute in the declaration of an object must provide the definition for that object somewhere in the program, you can initialize a global or local static function pointer with the address of a dllexport function. Similarly, you can initialize a global or local static data pointer with the address of a dllexport data object. For example, the following code does not generate errors in C or C++:

DllExport void func1( void );

DllExport int i;

int *pi = &i;	// Okay

static void ( *pf )( void ) = &func1;	// Okay

void func2()

{

static int *pi = &i;	// Okay

static void ( *pf )( void ) = &func1;	// Okay

}


C++ Specific Rules and Limitations

You can declare C++ classes with the dllimport or dllexport attribute. These forms imply that the entire class is imported or exported. Classes exported in this manner are referred to as exportable classes.

The following example defines an exportable class. All its member functions and static data are exported:

class DllExport C

{

int i;

virtual int func( void )

{ return 1; }

};

Note that explicit use of the dllimport and dllexport attributes on members of an exportable class is prohibited.


Dllexport Classes

When you declare a class dllexport, all its member functions and static data members are exported. You must provide the definitions of all such members in the same program. Otherwise, a linker error is generated. The one exception to this rule applies to pure virtual functions, for which you need not provide explicit definitions. However, because a destructor for an abstract class is always called by the destructor for the base class, pure virtual destructors must always provide a definition. Note that these rules are the same for non-exportable classes.

If you export data of class type or functions that return classes, be sure to export the class.


Dllimport Classes

When you declare a class dllimport, all its member functions and static data members are imported. Unlike the behavior of dllimport and dllexport on non-class types, static data members cannot specify a definition in the same program in which a dllimport class is defined.


Inheritance and Exportable Classes

All base classes of an exportable class must be exportable. If not, a compiler warning is generated. Moreover, all accessible members that are also classes must be exportable. This rule permits a dllexport class to inherit from a dllimport class, and a dllimport class to inherit from a dllexport class (though the latter is not recommended). As a rule, everything that is accessible to the DLL's client (according to C++ access rules) should be part of the exportable interface. This includes private data members referenced in inline functions.


Selective Member Import/Export

Because member functions and static data within a class implicitly have external linkage, you can declare them with the dllimport or dllexport attributes, unless the entire class is exported. If the entire class is imported or exported, the explicit declaration of member functions and data as dllimport or dllexport is prohibited. If you declare a static data member within a class definition as dllexport, a definition must occur somewhere within the same program (as with non-class external linkage).

Similarly, you can declare member functions with the dllimport or dllexport attributes. In this case, you must provide a dllexport definition somewhere within the same program.

It is worthwhile to note several important points regarding selective member import and export:

•	Selective member import/export is best used for providing a version of the exported class interface that is more restrictive; that is, one for which you can design a DLL that exposes fewer public and private features than the language would otherwise allow. It is also useful for fine tuning the exportable interface: when you know that the client, by definition, is unable to access some private data, you need not export the entire class.

•	If you export one virtual function in a class, you must export all of them, or at least provide versions that the client can use directly.

If you have a class in which you are using selective member import/export with virtual functions, the functions must be in the exportable interface or defined inline (visible to the client).

•	If you define a member as dllexport but do not include it in the class definition, a compiler error is generated. You must define the member in the class header.

•	Although the definition of class members as dllimport or dllexport is permitted, you cannot override the interface specified in the class definition.

•	If you define a member function in a place other than the body of the class definition in which you declared it, a warning is generated if the function is defined as dllexport or dllimport (if this definition differs from that specified in the class declaration).


Shared Header Files

A good way to ensure that the DLL and its client agree on the interface to a DLL is to use the same header files for building the DLL and the client. In this case, all header files should use dllimport since dllexport overrides dllimport in the case of definition.


Using Calling Conventions

The Intel®-based Windows C/C++ compilers provide several ways to call internal and external functions. The information in this guide can help you when debugging your program and when interfacing your code with assembly-language routines.

This guide covers the differences between the calling conventions, how arguments are passed, and how values are returned by functions.


Details on Calling Conventions

All arguments are widened to 32 bits when they are passed. Parameters are pushed onto the stack from right to left. Return values are also widened to 32 bits.

For Intel-based Windows C/C++ compilers, the return value is placed in the EAX register, except for 8-byte structures, which are returned in the EDX:EAX register pair. Larger structures are returned in the EAX register as pointers to hidden return structures.

For Intel-based Windows C/C++ compilers, the compiler generates prolog and epilog code to save and restore the ESI, EDI, EBX, and EBP registers, if they are used in the function.

Note  For information on how to define your own function prolog and epilog code, see Storage Class Attributes.


Obsolete Calling Conventions

The __pascal, __fortran, and __syscall calling conventions are no longer supported. Their functionality can be emulated by using one of the supported calling conventions and appropriate linker options.

WINDOWS.H now supports the WINAPI macro, which translates to the appropriate calling convention for the target. Use WINAPI where you previously used PASCAL or __far __pascal.


Argument Passing and Naming Conventions

The following table lists the calling conventions supported by most Windows C/C++ compilers:

Supported Calling Conventions

Keyword	Stack clean-up	Argument passing
__cdecl	Caller	Pushed on stack
__stdcall	Callee	Pushed on stack
__fastcall	Callee	Stored in registers, then pushed on stack
thiscall  (not a keyword)	Callee	Pushed on stack
For an example of these calling conventions, see Example.


__cdecl

This is the default calling convention for C and C++ programs. Because the stack is cleaned up by the caller, it can do vararg functions. The __cdecl calling convention creates larger executables than __stdcall because it requires each function call to include stack clean-up code.

All function arguments are pushed on the stack. In C, the __cdecl function names are prefixed by an underscore when decorated.

Note  See your C++ compiler documentation for information on C++ name decoration.


__stdcall

The __stdcall calling convention is used to call Win32 API functions. The stack is cleaned up by the callee, so the compiler makes vararg functions __cdecl. Functions that use this calling convention require a function prototype.

All function arguments are pushed on the stack. In C, the __stdcall function names are prefixed by an underscore and suffixed with @number when decorated, where number is the number of bytes (in decimal) used by the widened arguments pushed to the stack.


__fastcall

The __fastcall calling convention is similar to the __stdcall calling convention, but __fastcall speeds up function calling by storing some number of arguments in registers. Any additional arguments are pushed to the stack as in the other calling conventions.

In C, the __fastcall function names are prefixed by the at sign (@) and suffixed with @number when decorated, where number is the number of bytes (in decimal) used by the widened arguments pushed to the stack plus the number of bytes taken by the widened arguments passed in registers.

Note  Future compiler versions may use different registers to store parameters.


thiscall

This is the default calling convention used by C++ member functions that do not use variable arguments. The stack is cleaned up by the callee, so the compiler makes vararg functions __cdecl and pushes the this pointer on the stack last. The thiscall calling convention cannot be explicitly specified in a program because thiscall is not a keyword.

All function arguments are pushed on the stack. Because this calling convention applies only to C++, there is no C name decoration scheme.


Example

The following example shows the results of making a function call using various calling conventions. This example is specific to an Intel-based Windows C/C++ compiler.

Function Prototype and Call

This example is based on the following function skeleton. Replace calltype with the appropriate calling convention. The C decorated names are listed; see your compiler documentation for the C++ decorated names.

void	calltype MyFunc( char c, short s, int i, double f );

.

.

.

void	MyFunc( char c, short s, int i, double f )

{

.

.

.

}

.

.

.

MyFunc ('x', 12, 8192, 2.7183);

Results

The following lists display the stack and register contents using the __cdecl calling convention. The C decorated function name is "_MyFunc".

Address	Contents
ESP+0x14 ESP+0x10	2.7183
ESP+0x0C	8192
ESP+0x08	12
ESP+0x04	x
ESP	Return address
Register	Contents
ECX	Not used
EDX	Not used
The following lists display the stack and register contents using the __stdcall and thiscall calling conventions. The C decorated name (for __stdcall, not for thiscall) is "_MyFunc@20".

Address	Contents
ESP+0x14 ESP+0x10	2.7183
ESP+0x0C	8192
ESP+0x08	12
ESP+0x04	x
ESP	Return address
Register	Contents
ECX	this  (thiscall only)
EDX	Not used
The following lists display the stack and register contents using the __fastcall calling convention. The C decorated name is "@MyFunc@20".

Address	Contents
ESP+0x0C ESP+0x08	2.7183
ESP+0x04	8192
ESP	Return address
Register	Contents
ECX	x
EDX	12


Porting 16-bit Code to 32-bit Windows

When you begin writing applications for 32-bit Windows, you probably already have existing applications for 16-bit Windows. Porting these applications is the quickest way to start producing 32-bit software.

This guide describes how to create a 32-bit version of an application written for Windows 3.x in C, as well as how to make the code portable between versions of Windows. Portable code can be recompiled as either a 16-bit application or a 32-bit application, by setting an option.

This guide includes the following topics:

•	Overview of 32-bit programming

•	Using PORTTOOL to automate porting

•	Steps in porting applications

•	Special considerations for advanced applications

•	Dynamic-link libraries


Overview of 32-bit Programming

The Application Program Interface (API) for Win32 uses the flat 32-bit addressing mode, supports source code portability with RISC processors, and supports high-end capabilities such as security and true multitasking.

One of the major design goals of the 32-bit 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. Pointers are all 32 bits wide and no longer near or far, and your code cannot make assumptions based on segmented memory.

Items which have increased to 32 bits include the following:

•	Pointers

•	Window handles

•	Handles to other objects, such as pens, brushes, and menus

•	Graphics coordinates

These size differences are generally resolved in the header files (see WINDOWS.H) or by the C language, but some changes to source code are necessary. Because the different sizes cause some message parameters to be packed with information differently, you must rewrite code that handles these messages. The larger size of graphics coordinates also affects a number of function calls.

Some source-code changes are required because Win32 uses higher-level mechanisms for certain operations, such as file-system calls. These mechanisms make the 32-bit API adaptable to a wide number of platforms, and it supports powerful new features such as multiple threads of execution.

Although Windows 3.x and Win32 were designed to be as compatible as possible, you may need to look carefully over a large amount of source code. Where do you start? The top-down approach is recommended:

1.	Compile the application for 32 bits, and note the errors generated by the compiler.

2.	Replace complex procedures that are difficult to port, as well as procedures written in assembly language, with stub procedures. (These do nothing except return).

3.	Fix errors in the main portion of the application, using the techniques described in this guide.

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.


Using PORTTOOL to Automate Porting

You can use the PORTTOOL utility (PORTTOOL.EXE) to help port applications more easily. This utility finds locations in your code, such as references to certain functions and messages, that are likely to need revision. You should use PORTTOOL in conjunction with the information in this guide.

PORTTOOL uses settings in the file PORT.INI to determine what items to look for. This file is based on the Summary of Function and Message Differences table. You may want to add the following setting to this file, to make sure that PORTTOOL can find the Help file on the Win32 API:

[PORTTOOL]

    WinHelp=c:\mstools\bin\win32.hlp

Run PORTTOOL and load a Windows 3.x source file. Select the SearchAPI option from the Search menu to search for occurrences of problematic functions and messages. When an occurrence of either is found, a dialog box appears specifying the message or function and briefly suggesting what change needs to be made. Although the porting tool is not intended to replace your primary editor, it does support basic editing capabilities (such as Cut, Paste, and Search).


Steps in Porting Applications

The next few topics describe general steps you should take each time you port a 16-bit application to Win32. If your application uses advanced techniques, such as manipulating the WIN.INI file, focus, and mouse capture, you may need to consult Special Considerations for Advanced Applications.

The basic steps to porting an application include rewriting the Windows procedure, replacing WORD by proper data types, handling 32-bit messages, and adjusting some of the function calls.


Revising the Window Procedure Declaration

The first step in porting a Windows 3.x application is to revise the declaration of the window procedure. The declaration of a window procedure for a Windows 3.x application is shown below. Note the use of FAR PASCAL, unsigned, and WORD, respectively, in the first three lines:

LONG FAR PASCAL MainWndProc(	HWND hWnd,

unsigned message,

WORD wParam,

LONG lParam)

To revise the declaration for Win32, replace the data types used in Windows 3.x (FAR PASCAL and WORD) with CALLBACK and WPARAM. The revised version is shown below.

LRESULT CALLBACK MainWndProc(	HWND hWnd,

UINT message,

WPARAM wParam,

LPARAM lParam)

FAR PASCAL, shown in the Windows 3.x version of this code, can be used to compile applications for Win32, but it will be defined as an empty string (and is thus ignored). The CALLBACK function type is recommended because the header files define it as appropriate for the compiler; currently, Win32 uses the stdcall calling convention, but future versions of the Win32 Development Kit may use different conventions to optimize for more advanced processors.

The following table summarizes the changes to the declaration noted in the above example:

Changes to the Window Procedure Declaration

Windows 3.x	Win32 (portable code)	Reason for changing
FAR PASCAL	CALLBACK	CALLBACK is guaranteed to use whatever calling convention is appropriate for Windows
unsigned	UINT	Meaning is the same, but UINT guarantees portability for future platforms
WORD	WPARAM	WORD is always 16 bits. WPARAM is portable.
LONG	LPARAM	Not required, but consistent with WPARAM convention
The most significant difference between the Windows 3.x declaration and the portable version involves the wParam parameter, which under Win32 grows to 32 bits in size.

The combination of a 32-bit wParam message parameter, along with the fact that addresses and handles grow to 32 bits, means that a number of messages must be repacked, as described in Handling 32-bit Messages.


Using Proper Data Types

16-bit Windows source code often uses the type WORD interchangeably with types such as HWND and HANDLE. For example, the typecast (WORD) might be used to cast a data type to a handle:

hWnd = (WORD) SendMessage( hWnd, WM_GETMDIACTIVATE, 0, 0 );

This code compiles Windows 3.x application correctly, because both the WORD type and handles are 16 bits. But the code produces errors when compiled for Win32, because handles (such as HWND types) grow to 32 bits while the WORD type is still 16 bits.

To write portable code, examine each occurrence of WORD casts and data definitions in your code, and revise as follows:

•	If a variable or expression is to hold a handle, replace WORD with HWND, HPEN, HINSTANCE, or another handle type.

•	If a variable or expression is a graphics coordinate or some other integer value that grows from 16 to 32 bits, replace WORD with UINT.

•	Maintain use of the WORD type only if the data type needs to be 16 bits for all versions of Windows (usually because it is a function argument or structure member).

•	If in doubt, check reference documentation.

UINT is defined to be the natural integer size for the target environment: either 16 or 32 bits. Thirty-two−bit operating environments, especially with RISC processors, actually handle 32-bit data more efficiently than 16-bit data.

In the portable version of the previous example, the (WORD) cast is replaced by (HWND):

hWnd = (HWND) SendMessage( hWnd, WM_GETMDIACTIVATE, 0, 0 );

In general, use of the most specific type possible is recommended for writing more portable code. Avoid using a generic handle type such as HANDLE when you can. Try to use a more specific type such as HPEN. You should also define specific types for application-specific objects you might create.


Handling 32-bit Messages

When you move from Windows 3.x to Win32, 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.

The second method is strongly recommended. This guide focuses primarily on writing portable versions of the code.

Handles grow to 32 bits under Win32 and can therefore no longer be combined with other information and still fit into a 32-bit parameter (lParam). 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 also grows to 32 bits, 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	hwnd, cmd
Win32	id, cmd	hwnd (32 bits)
The following figure illustrates how the sizes of the parameters change, as well as how information is repacked:                            wParam                      lParam

                     +----------+               +----------+----------+

WM_COMMAND,          |   id     |               |   hwnd   |    cmd   |

Windows 3.x          +----------+               +----------+----------+

                                                                ^

                                      +-------------------------+

                                      V

                     +----------+----------+    +----------+----------+

WM_COMMAND,          |   id     |   cmd    |    |         hwnd        |

Win32                +----------+----------+    +----------+----------+


Extracting Data from Messages with Portable Code

When your code handles a Windows message that has been repacked, the cleanest way to revise the code is to first extract needed information from the message and store the information in local variables. This localizes message packing issues to a few lines of your code.

For example, if your application was written for 16 bits, you can use the following code to handle the WM_COMMAND message:

case WM_COMMAND:

id = wParam;

hwndChild = LOWORD(lParam);

cmd = HIWORD(lParam);

Here is the portable version of the same code, which yields correct results, whether you compile for the 16-bit or 32-bit environment:

case WM_COMMAND:

id = LOWORD(wParam);

hwndChild = (HWND)(UINT)lParam;

#ifdef WIN32

cmd = HIWORD(wParam);

#else

cmd = HIWORD(lParam);

#endif

Each of the examples of data extraction above (id, hwndChild, and cmd) illustrates a common case of repacking problems. The following topics deal with each case in turn:

•	Data always occupying the low 16 bits

•	A handle changing size but not location

•	Data that changes in location

Data Always Occupying the Low 16 Bits

The id data, in this case, always occupies the low word of wParam and is always 16 bits. The LOWORD macro produces the correct results because it always returns a 16-bit data type. The result is either all of wParam (if 16 bits) or the low half (if 32 bits):

id = LOWORD(wParam);	 // 16-bit: id=wParam

Handles Not Changing Location

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;	 // 16-bit: hwnd=LOWORD(lParam);

Data Changing Location

In cases where a piece of data changes packing location under Win32, 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.


Using Message Crackers to Write Portable Code

Message crackers are a set of macros that parse message parameters.  They enable you to write portable code without having to use #ifdef statements to parse messages. Some examples of macros used to parse message parameters follow:

GET_WM_COMMAND_ID  (wParam, lParam)   // Parse control ID value

GET_WM_COMMAND_HWND(wParam, lParam)   // Parse control HWND

GET_WM_COMMAND_CMD (wParam, lParam)   // Parse notification command

For each version of Windows (Windows 3.x and Win32), there is a WINDOWSX.H header file that defines these macros as appropriate. Refer to Handling Messages with Portable Macros for more information.


Summary of Windows Messages Affected

Use the following table to reference the packing of Windows messages affected by porting. The approaches discussed in the previous sections can be used for each message. Where two parameters are given, the one listed first corresponds to the least-significant 16 bits.

Except for the WM_CTLCOLOR messages, each message is given below with two rows: the first row gives 16-bit Windows packing for the message, the one below it gives Win32 packing.

Message		wParam:  Windows 3.x  Win32	lParam:  Windows 3.x  Win32
WM_ACTIVATE	(16-bit Windows)	state	fMinimized, hwnd
	(Win32)	state, fMinimized	hwnd (32 bits)
WM_CHARTOITEM	(16-bit Windows)	char	pos, hwnd
	(Win32)	char, pos	hwnd (32 bits)
WM_COMMAND	(16-bit Windows)	id	hwnd, cmd
	(Win32)	id, cmd	hwnd (32 bits)
WM_CTLCOLOR	(16-bit Windows)	hdc	hwnd, type
WM_CTLCOLORtype (Win32)	(Win32)	hdc (32 bits)	hwnd (32 bits)
Note  	Under Win32, 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.

Message		wParam:  Windows 3.x  Win32	lParam:  Windows 3.x  Win32
WM_MENUSELECT	(16-bit Windows)	cmd	flags, hMenu
	(Win32)	cmd, flags	hMenu (32 bits)
WM_MDIACTIVATE	(16-bit Windows)	fActivate	hwndDeactivate, hwndActivate
	(Win32)	hwndActivate (32 bits)	hwndDeactivate (32 bits)
WM_MDISETMENU	(16-bit Windows)	0	hMenuFrame, hMenuWindow
	(Win32)	hMenuFrame (32 bits)	hMenuWindow (32 bits)
WM_MENUCHAR	(16-bit Windows)	char	hMenu, fMenu
	(Win32)	char, fMenu	hMenu (32 bits)
WM_PARENTNOTIFY	(16-bit Windows)	msg	id, hwndChild
	(Win32)	msg, id	hwndChild (32 bits)
WM_VKEYTOITEM	(16-bit Windows)	code	item, hwnd
	(Win32)	code, item	hwnd (32 bits)
EM_GETSEL (returns wStart, wEnd)	(16-bit Windows)	0	0
	(Win32)	0 or lpdwStart	0 or lpdwEnd
EM_LINESCROLL	(16-bit Windows)	0	nLinesVert, nLinesHorz
	(Win32)	mLinesHorz (32 bits)	nLinesVert (32 bits)
EM_SETSEL	(16-bit Windows)	0	wStart, wEnd
	(Win32)	wStart (32 bits)	wEnd (32 bits)
WM_HSCROLL, WM_VSCROLL	(16-bit Windows)	code	pos, hwnd
	(Win32)	code, pos	hwnd (32 bits)


Summary of DDE Messages Affected

DDE messages are packed differently for Win32 and Windows 3.x. These differences are shown in the following table.

Message		wParam:  Windows 3.x  Win32	lParam:  Windows 3.x  Win32
WM_DDE_ACK (posted form only)	(16-bit Windows)	hwnd	wStatus, aItem or wStatus, hCommands
	(Win32)	hwnd (32 bits)	hDDEAck (see below)
WM_DDE_ADVISE	(16-bit Windows)	hwnd	hOptions, aItem
	(Win32)	hwnd (32 bits)	hDDEAdvise (see below)
WM_DDE_DATA	(16-bit Windows)	hwnd	hData, aItem
	(Win32)	hwnd (32 bits)	hDDEData (see below)
WM_DDE_POKE	(16-bit Windows)	hwnd	hData, aItem
	(Win32)	hwnd (32 bits)	hDDEPoke (see below)
Because of storage limitations, some of the information in the 32-bit versions of the messages is stored in a structure, which is accessed through the handle in lParam. You can use the following functions to extract information from these structures:

PackDDElParam
UnPackDDElParam
FreeDDElParam


Adjusting Calls to Functions

Most of your source code is not affected by differences between the APIs of Windows 3.x and Win32. The underlying definitions in the header files (see WINDOWS.H) automatically adjust data to the correct size. But you may need to revise code if you call functions in any of the following categories:

•	Graphics functions

•	Functions accessing "extra" window data

•	MS-DOS system calls

•	Far-pointer functions

•	Functions getting list and combo box contents


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 Win32, 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 Win32 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 Win32 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 versions:

Windows 3.x function	Portable 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, 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 under Win32.

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 function's 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 both 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, for the Get functions.

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;

rect.right = LOWORD(dwXY);

rect.top = HIWORD(dwXY);

InvertRect( hDC, &rect );

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 );


Functions That Access the Extra Window Data

The functions described in this topic manipulate the "extra" data area of a window structure. This structure can contain system information as well as user-defined data. You specify the size of this data area by using the cbClsExtra member of the WNDCLASS structure when you register the window class.

The following Windows 3.x functions get or set 16 bits during each call:

GetClassWord
GetWindowWord
SetClassWord
SetWindowWord

You can use these functions in Windows 3.x to access system information, stored as 16-bit items. But in Win32, each of these system-information items grows to 32 bits. Therefore, in Win32, you would use the following functions which access 32 bits at a time:

GetClassLong
GetWindowLong
SetClassLong
SetWindowLong

Each of these functions take two parameters: a window handle and an offset into the data area. These offsets differ depending on whether you are compiling for Windows 3.x or Win32.

The index values specifying these offsets correspond to each other as follows. Note that neither version is portable.

Windows 3.x	Win32 (nonportable)
GCW_CURSOR	GCL_CURSOR
GCW_HBRBACKGROUND	GCL_HBRBACKGROUND
GCW_HICON	GCL_HICON
GWW_HINSTANCE	GWL_HINSTANCE
GWW_HWNDPARENT	GWL_HWNDPARENT
GWW_ID	GWL_ID
GWW_USERDATA	GWL_USERDATA
To create portable code using these offsets, you need to use #ifdef statements as shown below. Both the function and the value of the second parameter change:

#ifdef WIN32

hwndParent = (HWND)GetWindowLong(hWnd, GWL_HWNDPARENT);

#else

hwndParent = (HWND)GetWindowWord(hWnd, GWW_HWNDPARENT);

#endif

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, noting that some data types, such as handles, increase in size.


Porting MS-DOS System Calls

The DOS3Call function in Windows 3.0 must be called from assembly language. It is typically used to perform file I/O. In Win32, assembly language code that calls DOS3Call should be replaced by the appropriate Win32 file I/O calls. Other (non-file) INT 21H functions should be replaced, as shown in the following table, with the portable Windows call:

INT 21H subfunction	MS-DOS operation	Win32 API equivalent
0EH	Select Disk	SetCurrentDirectory
19H	Get Current Disk	GetCurrentDirectory
2AH	Get Date	GetSystemTime
2BH	Set Date	SetSystemTime
2CH	Get Time	GetSystemTime
2DH	Set Time	SetSystemTime
36H	Get Disk Free Space	GetDiskFreeSpace
39H	Create Directory	CreateDirectory
3AH	Remove Directory	RemoveDirectory
3BH	Set Current Directory	SetCurrentDirectory
3CH	Create Handle	CreateFile
3DH	Open Handle	CreateFile
3EH	Close Handle	CloseHandle
3FH	Read Handle	ReadFile
40H	Write Handle	WriteFile
41H	Delete File	DeleteFile
42H	Move File Pointer	SetFilePointer
43H	Get File Attributes	GetFileAttributes
43H	Set File Attributes	SetFileAttributes
47H	Get Current Directory	GetCurrentDirectory
4EH	Find First File	FindFirstFile
4FH	Find Next File	FindNextFile
56H	Change Directory Entry	MoveFile
57H	Get Date/Time of File	GetFileTime
57H	Set Date/Time of File	SetFileTime
59H	Get Extended Error	GetLastError
5AH	Create Unique File	GetTempFileName
5BH	Create New File	CreateFile
5CH	Lock	LockFile
5CH	Unlock	UnlockFile
67H	Set Handle Count	SetHandleCount


File Operations

Fixed-length buffers for filenames and environment strings may need to be increased in size. Windows NT (one implementation of Win32) supports filenames of up to 256 characters, 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 Win32, these functions are replaced by similarly named functions of the form xxxx, because there is no need for far pointers in Win32. (The _f prefix is dropped from the name.)

The WINDOWSX.H file defines the _fxxxx function names so that in Win32, 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 don't have to rewrite calls to these functions. Some of the definitions are:

#define _fmemcpy(x,y,z)    memcpy(x,y,z)

#define _fstrcpy(x,y)      	strcpy(x,y)

#define _fstrcmp(x,y)      	strcmp(x,y)

#define _fstrcat(x,y)      	strcat(x,y)


Functions Getting List and Combo Box Contents

The Win32 API contains two new functions, shown in the following table, that provide an improved means of extracting list and combo box contents. In each case, the portable version of the function lets you specify a buffer size for a string that receives the information.

Windows 3.x function	Portable version of the function
DlgDirSelect	DlgDirSelectEx
DlgDirSelectComboBox	DlgDirSelectComboBoxEx
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 );


Revising the WinMain Function

You need to revise the WinMain function if either of the following conditions is true. Otherwise, the code in this function generally needs no change.

•	Your application needs to know when another instance of the application is running, or

•	You you need to access the command line

The parameter list for WinMain is the same for Win32 and Windows 3.x:

APIENTRY WinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow)

However, under Win32, there are two differences in the values passed through these parameters:

•	Unlike Windows 3.x, hPrevInstance always returns NULL.

•	The lpCmdLine parameter points to a string containing the entire command line, not just the parameters.

The following two sections discuss each of these differences.


Initializing Instances

The hPrevInstance parameter always returns NULL in Win32. 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 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 (indicating there is no previous instance), the code registers the window class. This code is automatically portable to Win32 and needs no change: the result under Win32 is simply 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. Examples of this latter case include Control Panel and Task Manager.

Applications cannot use hPrevInstance to test for previous instances under Win32. An alternative method must be used, such as creating a unique named pipe, creating/testing for a named semaphore, broadcasting a unique message, or calling FindWindow.


Accessing the Command Line Through LpCmdLine

In Windows 3.x, the lpCmdLine parameter points to a string containing the command line starting with the first parameter. The name of the application is not included. In Win32, lpCmdLine points to a string containing the entire command line, including the application itself.


Special Considerations for Advanced Applications

If you have applied the guidelines and procedures described in the preceding topics, you may well have been able to revise your entire application so that it is portable. However, problems specific to applications that use advanced calls or C coding tricks require additional revision. If your application is fairly complex, you should scan through the next two topics to make sure that you don't need additional changes.


Revising Advanced Function Calls

Applications may need further revision if they use calls dealing with any of the following: accessing .INI files, setting focus and active window, capturing the mouse, and sharing graphical objects.


Profile Strings and .INI Files

Although Windows NT and Win32s are both examples of Win32, Windows NT presents some additional features not present in Win32s.

Windows 3.x applications can access .INI files directly. In Windows NT, however, such code doesn't work because the information in .INI files is replaced by a registration database. This database offers a number of advantages, including security controls that prevent an application from corrupting system information, error logging, remote software updating, and remote administration of workstation software.

You can write portable code by using the profile API supported by Windows 3.x and all versions of Win32, including Windows NT. Call the GetProfileString and WriteProfileString functions instead of accessing .INI files directly. These functions use whichever underlying mechanism (.INI file or registration database) is supported by the environment you are compiling for.


Focus, Mouse Capture, and Localized Input

The Windows NT environment differs from Windows 3.x in that each thread of execution has its own message queue. This change affects window focus and mouse capture.

Window Focus

In Windows NT, each thread of execution can set or get the focus only to windows created by the current thread. This behavior prevents applications from interfering with each other. One application's delay in responding cannot cause other applications to suspend their response to user actions, as often happens in Windows 3.x.

Consequently, the following functions work differently under Windows NT:

GetActiveWindow
GetCapture
GetFocus
ReleaseCapture
SetActiveWindow
SetCapture
SetFocus

Get functions can now return NULL, which could not happen in Windows 3.x. Therefore, it's important to test the return value of GetFocus before using it. Instead of returning the window handle of another thread, the function returns NULL. For example, you call GetFocus and another thread has the focus. Note that it's 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 the Windows NT 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.


Shared Graphical Objects

Win32 applications run in separate address spaces. Graphical objects are specific to the application and cannot be manipulated by other processes as in Windows 3.x. A handle to a bitmap passed to another process cannot be used because the original process retains ownership.

Each process should create its own pens and brushes. A cooperative process may access the bitmap data in shared memory (by way of standard interprocess communications) and create its own copy of the bitmap. Alterations to the bitmap must be communicated between the cooperative processes by way of interprocess communication.


Solving Problems Due to C Coding Techniques

Some portability problems can be caused by C coding techniques that do not translate successfully to other memory models and processors. You can avoid these problems if your code doesn't attempt to exploit the fact you know about segmented memory. Standard pointer and memory management techniques will be correctly resolved by the header files.

The coding techniques most likely to cause porting problems are described in the following sections. For a more thorough general treatment of this subject, read Writing Portable C Programs.


Memory and Pointers

To be portable, source code must avoid any techniques that rely on the 16-bit segment:offset address structure, because all pointers are 32 bits in size under Win32 and use flat rather than segmented memory.

This difference in pointer structure is usually not a problem unless the code uses HIWORD, LOWORD, or similar macros to manipulate portions of the pointer.

For example, in Windows 3.x, memory is allocated to align on a segment boundary, which makes memory allocation functions return a pointer with an offset of 0x0000. The following code exploits this fact to run successfully under Windows 3.x:

ptr2 = ptr1 = malloc();                 // ptr2 = xxxx:0000

LOWORD( ptr2 ) = index * elementsize;   // Place offset of array element

                                        //   into ptr2 low word

Such code does not work properly under Win32. But standard pointer constructs, such as the following, always result in portable code:

ptr1 = malloc();            // Set ptr1 to start of memory block

ptr2 = ptr1[i];             // 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 under Win32.

•	Addresses never wrap, as they can with the low word in segmented addressing; for example, in Windows 3.x, an address can wrap from 1000:FFFF to 1000:0000.

•	Structures that hold near pointers in Windows 3.x must be revised because all pointers are 32 bits in Win 32. 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. The guidelines following ensure proper alignment for processors targeted by Win32:

Type	Alignment
char	Align on byte boundaries
short (16-bit)	Align on even byte boundaries
int and long (32-bit)	Align on 32-bit boundaries
float	Align on 32-bit boundaries
double	Align on 64-bit boundaries
structures	Align on 32-bit boundaries


Ranges and Promotions

Occurrences of int, unsigned, and unsigned int indicate potential portability problems because size and range are not constant. Data that would not exceed its range in Win32 could exceed range in Windows 3.x. Sign extension also works differently, so exercise caution in performing bitwise manipulation of this data.

Source code that relies on wrapping often presents portability problems, and should be avoided. For example, a loop should not rely on an unsigned int variable wrapping at 65535 (the maximum value in Windows 3.x) back down to 0.


Dynamic-Link Libraries

Development of dynamic-link libraries (DLLs) is different under Win32 compared to Windows 3.x. There are differences in the initialization and termination routines: how often they are called, what is passed, and how much code must be written in assembly language:

•	In Win32 DLLs, one function handles both initialization and termination. In Windows 3.x, the initialization function must be provided, and the termination function, if present, must be named WEP.

•	The Win32 initialization function is called every time a new process or an additional thread accesses the DLL for the first time, and when a process or thread detaches. In Windows 3.x, initialization and termination functions are called only once during the lifetime of the DLL.

•	In Win32, the entire DLL can be written in C (which is recommended as an aid to porting to other processors). In Windows 3.x, the start-up code is linked to an object file written in assembly language. Microsoft C/C++ links in an object file, LIBENTRY.OBJ, that accesses information in information in registers and calls LibMain in the C code. In Win32, you don't need this file.

In Win32, the DLL initialization function is the same as the termination function. By convention this function is named DllMain. A DWORD (32-bit) parameter, dwReason,  notifies the function whether initialization or termination is taking place, and whether a process or a thread is involved. When a process first accesses a DLL, the initialization function is called with process-attach notification: it is assumed that the process has one thread to being with. When there is an access by an additional thread of that process, the function is called with thread-attach notification. However, in Win32s there is notification only for process attach and detach.

The Win32 DLL initialization function should return 1 to indicate success. Returning NULL indicates failure.

Windows 3.x DLL initialization functions are passed the following information:

•	The DLL's instance handle

•	The DLL's data segment (DS)

•	The heap size specified in the DLL's .DEF file

•	The command line

Win32 DLL initialization functions are passed the following information:

•	The hModule parameter, a module handle

•	The dwReason parameter, an enumerated type which indicates which of four reasons the LibMain procedure is being called: process attach, thread attach, thread detach, or process detach.

•	The lpReserved parameter, which is unused.

The definition Win32 initialization function should look like the following code:

BOOL APIENTRY DllMain( HANDLE hModule,

DWORD dwReason,

LPVOID lpReserved )

{

switch( dwReason) {

case DLL_PROCESS_ATTACH:

...

case DLL_THREAD_ATTACH:

...

case DLL_THREAD_DETACH:

...

case DLL_PROCESS_DETACH:

...

}

}

The Win32 module handle has the same purpose as the Windows 3.x instance handle. Otherwise, Win32 DLL initialization functions do not include the parameters for Windows 3.x initialization, as described in the following table.

Parameter	Comment
DLL data segment	Not needed in Win32; memory model is flat, not segmented.
Size of DLL's local heap	All calls to local memory management functions operate on the default heap
Pointer to command line	The command line can be obtained through a call to the GetCommandLine function.
Windows 3.x assembly code is often limited to the LIBENTRY.ASM module, which simply accesses information in registers and passes it to a LibMain routine written in C. DllMain will be called directly in Win32, and LibMain will be called indirectly in Windows 3.x through the LIBENTRY code. If more of your DLL is written in assembly language, it is a good idea to rewrite all of it in C, to make it more portable.


Summary of Function and Message Differences

The following table provides a list of function calls and messages that required implementation changes for Win32.

Function/Message	Support	Comments
AccessResource	Dropped	No Win32 equivalent
AddFontResource	Enhanced	Must use string, not handle, for filename
AllocDSToCSAlias	Dropped	No Win32 equivalent
AllocResource	Dropped	No Win32 equivalent
AllocSelector	Dropped	No Win32 equivalent
ChangeSelector	Dropped	No Win32 equivalent
CloseComm	Dropped	Replaced by CloseHandle
CloseSound	Dropped	Replaced by multimedia sound support
CountVoiceNotes	Dropped	Replaced by multimedia sound support
DefineHandleTable	Dropped	No Win32 equivalent
DeviceMode	Dropped	Replaced by portable DocumentProperties
DlgDirSelect	Dropped	Replaced by portable DlgDirSelectEx
DlgDirSelectComboBox	Dropped	Replaced by portable DlgDirSelectComboBoxEx
DOS3Call	Dropped	Replaced by named, portable Win32 function
ExtDeviceMode	Dropped	Replaced by portable DocumentProperties
FlushComm	Dropped	Replaced by PurgeComm
FreeSelector	Dropped	No Win32 equivalent
GetAspectRatioFilter	Dropped	Replaced by portable GetAspectRatioFilterEx
GetBitmapDimension	Dropped	Replaced by portable GetBitmapDimensionEx
GetBrushOrg	Dropped	Replaced by portable GetBrushOrgEx
GetClassWord	Enhanced	Use GetClassLong for values that grow to 32-bits in Win32
GetCodeHandle	Dropped	No Win32 equivalent
GetCodeInfo	Dropped	No Win32 equivalent
GetCommError	Dropped	Replaced by GetCommState
GetCurrentPDB	Dropped	No Win32 equivalent
GetCurrentPosition	Dropped	Replaced by portable GetCurrentPositionEx
GetEnvironment	Dropped	No Win32 equivalent
GetFreeSpace	Dropped	Replaced by GlobalMemoryStatus
GetFreeSystemResources	Dropped	Replaced by GlobalMemoryStatus
GetInstanceData	Dropped	No equivalent; use alternative supported IPC mechanism.
GetKBCodePage	Dropped	No Win32 function equivalent
GetMetaFileBits	Dropped	Replaced by portable GetMetaFileBitsEx
GetModuleUsage	Enhanced	Always returns 1 on Win32
GetTempDrive	Dropped	Replaced by portable GetTempPath
GetTextExtent	Dropped	Replaced by portable GetTextExtentPoint
GetTextExtentEx	Dropped	Replaced by portable GetTextExtentExPoint
GetThresholdEvent	Dropped	Replaced by multimedia sound support
GetThresholdStatus	Dropped	Replaced by multimedia sound support
GetViewportExt	Dropped	Replaced by portable GetViewportExtEx
GetViewportOrg	Dropped	Replaced by portable GetViewportOrgEx
GetWindowExt	Dropped	Replaced by portable GetWindowExtEx
GetWindowOrg	Dropped	Replaced by portable GetWindowOrgEx
GetWindowWord	Enhanced	Use GetWindowLong for values that grow to 32-bits on Win32
GlobalCompact	Dropped	No Win32 equivalent
GlobalDosAlloc	Dropped	No Win32 equivalent
GlobalDosFree	Dropped	No Win32 equivalent
GlobalFix	Dropped	No Win32 equivalent
GlobalLRUNewest	Dropped	No Win32 equivalent
GlobalLRUOldest	Dropped	No Win32 equivalent
GlobalNotify	Dropped	No Win32 equivalent
GlobalPageLock	Dropped	No Win32 equivalent
GlobalPageUnlock	Dropped	No Win32 equivalent
GlobalUnfix	Dropped	No Win32 equivalent
GlobalUnwire	Dropped	No Win32 equivalent
GlobalWire	Dropped	No Win32 equivalent
LimitEmsPages	Dropped	No Win32 equivalent
LocalCompact	Dropped	No Win32 equivalent
LocalInit	Dropped	No Win32 equivalent
LocalNotify	Dropped	No Win32 equivalent
LocalShrink	Dropped	No Win32 equivalent
LockSegment	Dropped	No Win32 equivalent
MoveTo	Dropped	Replaced by portable MoveToEx
NetBIOSCall	Dropped	Replaced by named, portable Win32 function
OffsetViewportOrg	Dropped	Replaced by portable OffsetViewportOrgEx
OffsetWindowOrg	Dropped	Replaced by portable OffsetWindowOrgEx
OpenComm	Dropped	Replaced by OpenFile
OpenSound	Dropped	Replaced by multimedia sound support
ProfClear	Dropped	Replaced by Win32 profile-string function
ProfFinish	Dropped	Replaced by Win32 profile-string function
ProfFlush	Dropped	Replaced by Win32 profile-string function
ProfInsChk	Dropped	Replaced by Win32 profile-string function
ProfSampRate	Dropped	Replaced by Win32 profile-string function
ProfSetup	Dropped	Replaced by Win32 profile-string function
ProfStart	Dropped	Replaced by Win32 profile-string function
ProfStop	Dropped	Replaced by Win32 profile-string function
ReadComm	Dropped	Replaced by ReadFile
RemoveFontResource	Enhanced	Must use string, not handle, for filename
ScaleViewportExt	Dropped	Replaced by portable ScaleViewportExtEx
ScaleWindowExt	Dropped	Replaced by portable ScaleWindowExtEx
SetBitmapDimension	Dropped	Replaced by portable SetBitmapDimensionEx
SetClassWord	Enhanced	Use SetClassLong for values that grow to 32-bits on Win32
SetCommEventMask	Dropped	Replaced by SetCommMask
SetEnvironment	Dropped	No Win32  equivalent
SetMetaFileBits	Dropped	Replaced by portable SetMetaFileBitsEx
SetResourceHandler	Dropped	No Win32 equivalent
SetSoundNoise	Dropped	Replaced by multimedia sound support
SetSwapAreaSize	Dropped	No Win32 equivalent
SetViewportExt	Dropped	Replaced by portable SetViewportExtEx
SetViewportOrg	Dropped	Replaced by portable SetViewportOrgEx
SetVoiceAccent	Dropped	Replaced by multimedia sound support
SetVoiceEnvelope	Dropped	Replaced by multimedia sound support
SetVoiceNote	Dropped	Replaced by multimedia sound support
SetVoiceQueueSize	Dropped	Replaced by multimedia sound support
SetVoiceSound	Dropped	Replaced by multimedia sound support
SetVoiceThreshold	Dropped	Replaced by multimedia sound support
SetWindowExt	Dropped	Replaced by portable SetWindowExtEx
SetWindowOrg	Dropped	Replaced by portable SetWindowOrgEx
SetWindowWord	Enhanced	Use SetWindowLong for values that grow to 32-bits on Win32
StartSound	Dropped	Replaced by multimedia sound support
StopSound	Dropped	Replaced by multimedia sound support
SwitchStackBack	Dropped	No Win32 equivalent
SwitchStackTo	Dropped	No Win32 equivalent
SyncAllVoices	Dropped	Replaced by multimedia sound support
UngetCommChar	Dropped	No Win32 equivalent
UnlockSegment	Dropped	No Win32 equivalent
ValidateCodeSegments	Dropped	No Win32 equivalent
ValidateFreeSpaces	Dropped	No Win32 equivalent
WaitSoundState	Dropped	Replaced by multimedia sound support
WriteComm	Dropped	Replaced by WriteFile
EM_GETSEL	Enhanced	wParam/lParam packing changed
EM_LINESCROLL	Enhanced	wParam/lParam packing changed
EM_SETSEL	Enhanced	wParam/lParam packing changed
WM_ACTIVATE	Enhanced	wParam/lParam packing changed
WM_CHANGECBCHAIN	Enhanced	wParam/lParam packing changed
WM_CHARTOITEM	Enhanced	wParam/lParam packing changed
WM_COMMAND	Enhanced	wParam/lParam packing changed
WM_CTLCOLOR	Dropped	Replaced by WM_CTLCOLOR<type> messages
WM_DDE_ACK	Enhanced	wParam/lParam packing changed
WM_DDE_ADVISE	Enhanced	wParam/lParam packing changed
WM_DDE_DATA	Enhanced	wParam/lParam packing changed
WM_DDE_EXECUTE	Enhanced	wParam/lParam packing changed
WM_DDE_POKE	Enhanced	wParam/lParam packing changed
WM_HSCROLL	Enhanced	wParam/lParam packing changed
WM_MDIACTIVATE	Enhanced	wParam/lParam packing changed
WM_MDISETMENU	Enhanced	wParam/lParam packing changed
WM_MENUCHAR	Enhanced	wParam/lParam packing changed
WM_MENUSELECT	Enhanced	wParam/lParam packing changed
WM_PARENTNOTIFY	Enhanced	wParam/lParam packing changed
WM_VKEYTOITEM	Enhanced	wParam/lParam packing changed
WM_VSCROLL	Enhanced	wParam/lParam packing changed
DCB	Enhanced	Changes to bitfields and additional structure members
(WORD)	16-bit	Check if incorrect cast of 32-bit value
GCW_HCURSOR	Dropped	Replaced by GCL_HCURSOR
GCW_HBRBACKGROUND	Dropped	Replaced by GCL_HBRBACKGROUND
GCW_HICON	Dropped	Replaced by GCL_HICON
GWW_HINSTANCE	Dropped	Replaced by GWL_HINSTANCE
GWW_HWNDPARENT	Dropped	Replaced by GWL_HWNDPARENT
GWW_ID	Dropped	Replaced by GWL_ID
GWW_USERDATA	Dropped	Replaced by GWL_USERDATA
READ	Dropped	Replaced by OF_READ
WRITE	Dropped	Replaced by OF_WRITE
READ_WRITE	Dropped	Replaced by OF_READ_WRITE
HIWORD	16-bit	Check if HIWORD target is 16- or 32-bit
LOWORD	16-bit	Check if LOWORD target is 16- or 32-bit
MAKEPOINT	Dropped	Replaced by LONG2POINT


Handling Messages with Portable Macros

Instead of taking the case-by-case approach, you can use message-cracking macros to write message handlers similar to those you'd write when using Microsoft Foundation Classes. These message handlers use the same parameter list regardless of operating system, thereby solving message-packing issues. This guide describes these and other macros defined in WINDOWSX.H (or WINDOWSX.H16 in the case of 16-bit applications).

This guide includes the following topics:

•	Using message crackers

•	Writing message crackers for user-defined messages

•	Adapting message crackers to special cases

•	Using control message functions


Using Message Crackers

Message crackers are a set of macros that extract useful information from the wParam and lParam parameters of a message and hide the details of how information is packed.

Using message crackers initially requires you to revise some of your code. They also have a minor impact on performance by involving an additional function call. However, they offer the following major advantages:

•	Portability. Message crackers free you from packing issues and guarantee proper extraction of information, regardless of which environment you're compiling for.

•	Readability. With message crackers, you can understand source code because message parameters are translated into data with meaningful names.

•	Ease of use. In addition to decoding wParam and lParam, message crackers place message-handling code in separate functions. Instead of a long switch statement, you have a separate handler for each message.


Overview of Message Crackers

You use message crackers in your code by writing a separate message handler function for each message. Then you use a macro to call each of those functions from within your window procedure.

Use of message crackers for all messages is recommended, but you can optionally combine code that uses message crackers for some messages with code that responds to other messages directly.

Note  To use message crackers, make sure you include the file WINDOWSX.H (or WINDOWSX.H16, in the case of 16-bit applications).

Suppose you have a message, WM_THIS. The code to handle this message would look something like this:

LONG WINAPI My_WndProc( HWND hwnd, UINT msg, UINT wParam, LONG lParam )

.

.

.

switch( msg ) {

case WM_THIS:

// Place code to handle message here

To use message crackers, write a message handler, and then call it from the switch statement. Suppose that there are two pieces of information contained in the WM_THIS message: thisHdc and thisData. Message crackers unpack this information from wParam and lParam, and pass it as parameters to your message handler, MyWnd_OnThis:

switch ( msg) {

case WM_THIS:

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.


Declaring Message-Handler Prototypes

To use message crackers, first declare a prototype for the message handling function ("message handler" for short). Although you can give your message handlers any name you want, a recommended convention is:

WndClass_OnMsg

in which WndClass is the name of the window class, and Msg is the name of the message in mixed case, with the "WM" dropped. For example, the following code contains prototypes for functions handling WM_CREATE, WM_PAINT, and WM_MOUSEMOVE:

BOOL MyWnd_OnCreate( HWND hwnd, CREATESTRUCT FAR* lpCreateStruct );

void MyWnd_OnPaint( HWND hwnd );

void MyWnd_OnMouseMove( HWND hwnd, int x, int y, UINT keyFlags );

The first parameter to each function is always hwnd, which is a handle to the window that received the message. The rest of the parameters vary; each message handler has its own customized parameter list. To declare the appropriate parameters for a message, see the corresponding definitions in WINDOWSX.H.


Calling the Message Handler

In your window procedure, you call a message handler by using a message-decoder macro such as HANDLE_WM_CREATE or HANDLE_WM_PAINT. The general form for using these macros is:

case msg:
return HANDLE_msg ( hwnd, wParam, lParam, handler );

You should always return the value of the macro, even if no return value is expected and the corresponding message handler has void return type.

For example, you could place the following macros in your code:

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.


Writing the Message Handler

In the message-handling function, you respond to the message using parameters that have been translated from wParam and lParam and passed to the function. In the following example, lpCreateStruct is an example of a parameter translated from wParam and lParam:

BOOL MyCls_OnCreate(HWND hwnd, CREATESTRUCT FAR* lpCreateStruct)

{

// Place message-handling code here

    return FORWARD_WM_CREATE(hwnd, lpCreateStruct, DefWindowProc);

}

Message-handling code often finishes by calling DefWindowProc or some other default message procedure. You make this function call by using a "message forwarder," which uses the following form:

return FORWARD_msg( parmlist, defaultMsgProc );

The parmlist is the same list of parameters in the message handler, and defaultMsgProc is the default message procedure, typically DefWindowProc. The message forwarder repacks the information in the parameter list into the appropriate wParam/lParam format (depending on target environment) and forwards the message to the default message procedure.


Putting It Together: An Example

The following example demonstrates the use of several message handlers in a window procedure, showing where the various prototypes and macros fit into the code.

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)

{

    .

.

.

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.


Handling Special Cases of Messages

As a general rule, there is one set of message crackers for each message: a message decoder and a message forwarder. Another rule is that each message handler you write should return the same value that your code would normally return for that message. The following messages present exceptions to these rules:

Message handler	Comment
OnCreate, OnNCCreate	BOOL return type: return TRUE if there are no errors. If FALSE is returned, a window will not be created.
OnKey	Handles both key up and key down messages. The extra parameter fDown indicates whether the key is down or up.
OnLButtonDown, OnRButtonDown	Handles both click (button down) and double-click messages. The extra parameter fDoubleClick indicates whether the message received is a double-click message.
OnChar	This handler is passed only by character, and not the virtual key or key flags information.


Writing Message Crackers for User-Defined Messages

You can use message crackers with window messages that you define, but you must write your own macros. The easiest way to do this is to copy and modify existing macros from WINDOWSX.H.

To understand how to write these macros, consider some of the message crackers defined in WINDOWSX.H:

/* BOOL Cls_OnCreate(HWND hwnd, CREATESTRUCT FAR* lpCreateStruct) */

#define HANDLE_WM_CREATE(hwnd, wParam, lParam, fn) \

    ((fn)(hwnd, (CREATESTRUCT FAR*)lParam) ? 0L : (LRESULT)-1L)

#define FORWARD_WM_CREATE(hwnd, lpCreateStruct, fn) \

    (BOOL)(DWORD)(fn)(hwnd, WM_CREATE, 0, (LPARAM)lpCreateStruct)

The message decoder (HANDLE_msg) should be defined as a function call, (fn), followed by hwnd and other parameters derived from wParam and lParam. The message forwarder (FORWARD_msg) performs the reverse operation on the parameters, putting information back together to restore wParam and lParam before making the function call (fn). Each of these macros must cast the return value so that the correct type is returned.

When calling the message crackers you write, be careful about variable message values. If your message value 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 can't 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);
    	.

.

.
}


Adapting Message Crackers to Special Cases

Message crackers can generally be used with all types of application code. However, certain situations require modifications in coding style.

Dialog Procedures, Window Subclassing, and Window Instance Data  show how to adapt message-cracker coding techniques for dialog procedures, window subclassing, and window instance data.


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 can't use HANDLE_MSG. You must invoke the message-decoder macro explicitly. Here's an example that shows how you'd 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:
        HANDLE_WM_COMMAND(hwndDlg, wParam, lParam, MyDlg_OnCommand);
        return TRUE;
        break;

    default:
        return FALSE;
    }
}


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.
//
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);

    }

}


Window Instance Data

It is common for a window to have user-declared state variables (or "instance data") kept in a separate data structure allocated by the application. You associate this data structure with its corresponding window by storing a pointer to the structure in a specially named window property or in a window word (allocated by setting the cbWndExtra field of the WNDCLASS structure when the class is registered).

Message crackers can be adapted to work with this use of instance data. Place the hwnd of the window in the first member of the structure. Then, in the message decoders (HANDLE_msg macros), pass the address of the structure instead of the hwnd. The message handler now gets a pointer to the structure instead of the hwnd, but it can access the hwnd through indirection. You may need to rewrite some of the message handler to make it use indirection to access the window handle.

The following example illustrates this technique:

// Window instance data structure.  Must include window handle field.
//
typedef struct _test
{
    HWND hwnd;
    int otherStuff;
} test;

// "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.
        	//
    	}
    	else
    	{
        	// 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);
    }
}


Using Control Message Functions

The control message API functions perform a role that is the converse of message crackers: instead of handling messages sent to your window, they send messages to other windows (controls).

Each of the control message functions packs parameters into the appropriate wParam/lParam format and then calls SendMessage. These functions offer the same portability advantages that message crackers do; they free you from having to know how the current operating system packs wParam and lParam.

The function calls also improve readability of code and support better type checking. When used with the STRICT enhancements, the control message functions help prevent incorrect passing of message parameters.

To see how the control message functions work, first look at the following source code, which makes two calls to SendMessage to print all the lines in an edit control:

void PrintLines(HWND hwndEdit, WHND hwndDisplay)
{

    int line;

    int lineLast = (int)SendMessage(hwndEdit, EM_GETLINECOUNT, 0, 0L);

    for (line = 0; line < lineLast; line++)

    {

        int cch;

        char ach[80];

        *((LPINT)ach) = sizeof(ach);

        cch = (int)SendMessage(hwndEdit, EM_GETLINE,

                line, (LONG)(LPSTR)ach);

        PrintInWindow(ach, hwndDisplay);

    }

}

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, doesn't generate compiler warnings, and doesn't 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	Functions
Static Text Controls:	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 Controls:	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 Controls:	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)
	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)
Scroll Bar Controls:	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)
List Box Controls:	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)
	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)
Combo Box Controls:	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)
	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.


Writing Portable C Programs

Because C compilers exist on a variety of computers, some C applications developed for one computer system can be ported to other systems. However, some aspects of language behavior depend on how a particular C compiler is implemented and how a specific computer operates. Therefore, when designing a program to be ported to another system, it is important that you examine programming assumptions. This guide describes those assumptions that can affect writing portable programs.

The American National Standards Institute Standard for the C Language (the ANSI Standard) details every instance where language behavior is defined by the implementation.


Assumptions About Hardware

To make C programs portable, you must examine two aspects of your code: hardware assumptions and compiler dependency. This guide deals with hardware assumptions. Assumptions About the Compiler deals with compiler dependency.


Size of Basic Types

In C, the size of basic types (char, signed int, unsigned int, float, double, and long double) is implementation-defined, so relying on a particular data type to be a given size reduces the portability of a program.

Because the size of basic types is left to the implementation, do not make assumptions about the size or alignment of data types within aggregate types. You should always use the sizeof operator to determine the size or amount of storage required for a variable or a type.

The following topics discuss rules governing the size of specific data types.

•	Type char

•	Type int and Type short int

•	Type float, Type double, and Type long double

•	Microsoft C Type Sizes


Type Char

Type char is the smallest of the basic types, but it must be large enough to hold any of the characters in the implementation's basic character set. Normally, variables of type char are 1 byte.


Type Int and Type Short Int

Type int often corresponds to the register size of the target computer. Type short int may be less than or equal to the size of type int. Both int and short are greater than or equal to the size of type char but less than or equal to the size of type long.

If you assume that type int is a certain size, your code may not be portable because:

•	An int can be defined as a 16-bit (2-byte) or a 32-bit quantity.

•	An int is not always large enough to hold array indexes. For large arrays, you must use unsigned int; for extremely large arrays, use long or unsigned long. To be certain your code is portable, define your array indexes as type size_t. You may not know, before porting your code, the maximum value to expect an array index of type int to hold. The file LIMITS.H contains manifest constants, listed below, for the maximum and minimum values of each basic integral type.

Constant	Value
CHAR_BIT	Number of bits in a variable of type char
CHAR_MIN	Minimum value a variable of type char can hold
CHAR_MAX	Maximum value a variable of type char can hold
SCHAR_MIN	Minimum value a variable of type signed char can hold
SCHAR_MAX	Maximum value a variable of type signed char can hold
UCHAR_MAX	Maximum value a variable of type unsigned char can hold
SHRT_MIN	Minimum value a variable of type short can hold
SHRT_MAX	Maximum value a variable of type short can hold
USHRT_MAX	Maximum value a variable of type unsigned short can hold
INT_MIN	Minimum value a variable of type int can hold
INT_MAX	Maximum value a variable of type int can hold
UINT_MAX	Maximum value a variable of type unsigned int can hold
LONG_MIN	Minimum value a variable of type long can hold
LONG_MAX	Maximum value a variable of type long can hold
ULONG_MAX	Maximum value a variable of type unsigned long can hold


Type Float, Type Double, and Type Long Double

Type float is the smallest of the basic floating-point types. Type double is usually larger than type float, and type long double is usually the largest of the floating-point types. You can make the following portability assumptions about floating-point types:

•	Any value that can be represented as type float can be represented as type double (type float is a subset of type double).

•	Any value that can be represented as type double can be represented as type long double (type double is a subset of type long double).

The file FLOAT.H contains manifest constants, listed below, for the maximum and minimum values of each basic floating-point type.

Constant	Value
DBL_DIG	Number of decimal digits of precision a variable of type double can hold
DBL_MAX	Maximum value a variable of type double can hold
DBL_MAX_10_EXP	Maximum value (base 10) the exponent of a variable of type double can hold
DBL_MAX_EXP	Maximum value (base 2) the exponent of a variable of type double can hold
DBL_MIN	Minimum positive value a variable of type double can hold
DBL_MIN_10_EXP	Minimum value (base 10) the exponent of a variable of type double can hold
DBL_MIN_EXP	Minimum value (base 2) the exponent of a variable of type double can hold
FLT_DIG	Number of decimal digits of precision a variable of type float can hold
FLT_MAX	Maximum value a variable of type float can hold
FLT_MAX_10_EXP	Maximum value (base 10) the exponent of a variable of type float can hold
FLT_MAX_EXP	Maximum value (base 2) the exponent of a variable of type float can hold
FLT_MIN	Minimum positive value a variable of type float can hold
FLT_MIN_10_EXP	Minimum value (base 10) the exponent of a variable of type float can hold
FLT_MIN_EXP	Minimum value (base 2) the exponent of a variable of type float can hold
LDBL_DIG	Number of decimal digits of precision a variable of type long double can hold
LDBL_MAX	Maximum value a variable of type long double can hold
LDBL_MAX_10_EXP	Maximum value (base 10) the exponent of a variable of type long double can hold
LDBL_MAX_EXP	Maximum value (base 2) the exponent of a variable of type long double can hold
LDBL_MIN	Minimum positive value a variable of type long double can hold
LDBL_MIN_10_EXP	Minimum value (base 10) the exponent of a variable of type long double can hold
LDBL_MIN_EXP	Minimum value (base 2) the exponent of a variable of type long double can hold


Microsoft C Type Sizes

The following table summarizes the size of the basic types in Microsoft C:

Size of Basic Types in Microsoft C

Type	Number of bytes
char, unsigned char	1
short, unsigned short	2
int, unsigned int	2 or 4 (*)
near pointer	2 or 4 (*)
long, unsigned long	4
far pointer	4
float	4
double	8
long double	10
* These data types have different sizes in 16- and 32-bit environments.


Storage Order and Alignment

The C language does not define any specific layout for the storage of data items relative to one another. The layout for storage of structure elements, or unions within a structure or union, is defined by the implementation.

Some processors require that data longer than 1 byte be aligned to 2-byte or 4-byte boundaries. Other processors, such as the 80x86 family, do not have such a restriction. However, the 80x86 processors work more efficiently with aligned data.

Most RISC processors expect each piece of data in memory to be aligned on a boundary appropriate to its size. For example, an n-byte integer can be aligned on a boundary whose address is a multiple of n-bytes, up to a maximum of 8 bytes. This restriction permits the memory system to run much faster.

Ordinarily, alignment has no effect on correctly written programs because the compiler inserts unused space ("padding") between variables wherever necessary to conform to the rules.


Structure Order and Alignment

The following example illustrates how alignment can affect your program. In the example, a structure is cast to type long because the programmer knew the order in which a particular implementation stored data.

/* Nonportable code */
struct time
{
    char hour;     /* 0 < hour < 24   — fits in a char */
    char minute;   /* 0 < minute < 60 — fits in a char */
    char second;   /* 0 < second < 60 — fits in a char */
};

    .
    .
    .
    struct time now, alarm_time;
    .
    .
    .
    if ( *(long *)&now >= *(long *)&alarm_time )
    {
        /* sound an alarm */
    }

The preceding code makes these nonportable assumptions:

•	The data for hour will be stored in a higher order position than minute or second. Because C does not guarantee storage order or alignment of structures or unions, the code may not be portable to other computers.

•	Three variables of type char will be shorter than or the same length as a variable of type long. Thus, the code is not portable according to the rules governing the size of basic types, as described in Size of Basic Types.

If either of these assumptions proves false, the comparison (if statement) is invalid.

To make the program in the preceding example portable, you can break the comparison between the two long integers into a component-by-component comparison. This technique is illustrated in the following example:

/* Portable code */
struct time
{
    char hour;     /* 0 < hour < 24   — fits in a char */
    char minute;   /* 0 < minute < 60 — fits in a char */

    char second;   /* 0 < second < 60 — fits in a char */
};

    .
    .
    .
    struct time now, alarm_time;
    .
    .
    .
    if ( time_cmp( now, alarm_time ) >= 0 )
    {
        /* sound an alarm */
    }
    .
    .
    .

int time_cmp( struct time t1, struct time t2 )
{
    if( t1.hour != t2.hour )
        return( t2.hour - t1.hour );
    if( t1.minute != t2.minute )
        return( t2.minute - t1.minute );
    return( t2.second - t1.second );
}

Even a program that follows the rules given previously may have trouble when writing data on one computer and reading it on another. In addition to padding, computers differ with regard to endian-ness, floating-point formats, and size of data types. If I/O speed is not important, a possible solution is to use ASCII files rather than binary ones.


Union Order and Alignment

Programmers use unions most often for two purposes: to store data whose exact type is not known until run time or to access the same data in different ways.

Unions falling into the second category are usually not portable. For example, the following union is not portable:

union tag_u
{
char bytes_in_long[4];
long a_long;
};

The intent of the preceding union is to access the individual bytes of a variable of type long. However, the union may not work as intended when ported to other computers because:

•	It relies on a constant size for type long.

•	It may assume byte ordering within a variable of type long. (Byte ordering is described in detail in Byte Order in a Word.)


Byte Order in a Word

The order of bytes within an integral type longer than a byte (short, int, or long) can vary among computers. Computers that number the bytes from left to right with the least-significant byte within a word being byte zero are called "little-endian." Computers that number the bytes from left to right with the least-significant byte being byte 3 are called "big-endian." Code that assumes an internal order is not portable, as shown by this example:

/*
 * Nonportable structure to access an int in bytes.
 */
struct tag_int_bytes
{
    char lobyte;
    char hibyte;
};

A more portable way to access the individual bytes in a word is to define two macros that rely on the constant CHAR_BIT, defined in LIMITS.H:

#define LOBYTE(a) (char)((a) & 0xff)
#define HIBYTE(a) (char)((unsigned)(a) >> CHAR_BIT)

The LOBYTE macro is still not completely portable. It assumes that a char is 8 bits long, and it uses the constant 0xff to mask the high-order 8 bits. Because portable programs cannot rely on a given number of bits in a byte, consider the revision below:

#define LOBYTE(a) (char)((a) & ((unsigned)~0>>CHAR_BIT))
#define HIBYTE(a) (char)((unsigned)(a) >> CHAR_BIT)

This revised LOBYTE macro performs a bitwise complement on 0; that is, all zero bits are turned into ones. The macro then takes that unsigned quantity and shifts it right far enough to create a mask of the correct length for the implementation.

The following code assumes that the order of bytes in a word will be least-significant first:

int c;
.
.
.
fread( &c, sizeof( char ), 1, fp );

The code attempts to read one byte as an int, without converting it from a char. However, the code will fail in any implementation where the low-order byte is not the first byte of an int. The following solution is more portable. In this example, the data is read into an intermediate variable of type char before being assigned to the integer variable:

int c;
char ch;
.
.
.
fread( &ch, sizeof( char ), 1, fp );
c = ch;

The following example shows how to use the C run-time function fgetc to return the value. The fgetc function returns type char, but the value is promoted to type int when it is assigned to a variable of type int:

int c;
.
.
.
c = fgetc( fp );

You might create porting problems by placing small objects side by side to make a bigger object, or splitting a big object into several small objects. For example, the following code that reads and compares a pair of short integers is computer-dependent because on some computers the 0th element of the array represents the high-order half of the word rather than the low-order half:

char carr[BUFSIZ];

err = read( 0, carr, 4 );

if ( ( carr[0] | ( carr[1] << 8 ) ) > ( carr[2] | ( carr[3] << 8 ) )

...

There is never a problem if you use the correct data type and let the compiler deal with the order of the bytes:

short sarr[BUFSIZ];

err = read( 0, (char *) sarr, 2 * sizeof( short ) );

if ( sarr[0] > sarr[i] )

...

Microsoft C Specific

Microsoft C normally aligns data types longer than one byte to an even-byte address for improved performance. See the /Zp compiler option.


Floating-Point Accuracy

Some compilers use extended precision even when your program does not specify it because it is more natural for the design of the processor to use the extended precision. When an expression is evaluated using extended precision, you may get a slightly different answer than if it were evaluated in double precision. Intel 80x87 math coprocessors use 80-bit precision for calculations, whereas RISC processors often use 64-bit precision.

In addition to differences resulting from hardware, each implementation typically differs in the algorithms and characteristics of its math library. Even IEEE computers that are otherwise identical may produce different results due to differences in math libraries.


Reading and Writing Structures

Many C programs read data from disk into structures and write data to disk from structures. The functions that perform disk I/O in C require you to specify the number of bytes to be transferred. You should always use the sizeof operator to obtain the size of the data to be read or written, because differing data type sizes or alignment schemes may alter the size of a given structure. The following code shows one such use of the sizeof operator:

fread( &my_struct, sizeof(my_struct), 1, fp );

Microsoft C Specific

When performing disk input and output in Microsoft C, structures may be different sizes depending on the structure-packing option you have selected. See the /Zp compiler option.


Bit Fields in Structures

The Microsoft C compiler implements bit fields. However, many C compilers do not.

Bit fields allow you to access the individual bits within a data item. While the practice of accessing the bits in a data item is inherently nonportable, you can improve your chances of porting a program that uses bit fields if you make no assumptions about order of assignment, or size and alignment of bit fields.


Order of Assignment

Because the order of assignment of bit fields in memory is left to the implementation, you cannot rely on a particular entry in a bit field structure to be in a higher order position than another. (This problem is similar to the portability constraint imposed by alignment of basic data types in structures. The C language does not define any specific layout for the storage of data items relative to one another.) See Storage Order and Alignment for more information.


Size and Alignment of Bit Fields

The Microsoft C compiler supports bit fields up to the size of the type long. Each individual member of the bit field structure can be up to the size of the declared type. Some compilers do not support bit field structure elements that are longer than type int.

The following example defines a bit field, short_bitfield, that is shorter than type int:

struct short_bitfield
{
    unsigned usr_bkup : 1; /* 0  <= usr_bkup <  1 */
    unsigned usr_sec  : 4; /* 9 <= usr_sec < 16 */
};

The following example defines a bit field, long_bitfield, that has an element longer than type int in a 16-bit environment:

struct long_bitfield
{
    unsigned long disk_pos : 22;  /* 0 <= disk_pos   < 4,194,304 */
    unsigned long rec_no   : 10;  /* 0 <= rec_no < 1,024 */
};

The bit field short_bitfield is likely to be supported by more implementations than long_bitfield.

Microsoft C Specific

The following example introduces another portability issue: alignment of data defined in bit fields.

struct long_bitfield
{
    unsigned int day    : 5;  /* 0 <= day   < 32 */
    unsigned int month  : 4;  /* 0 <= month < 16 */
    unsigned int year   : 11; /* 0 <= year  < 2048 */
};

In the 32-bit environment, all three elements can fit within a single 32-bit int, so there is no gap between any of the elements in Microsoft C's representation of the structure. Microsoft C for the 16-bit environment, by contrast, uses a word size of 16 bits. Because the compiler does not allow structure elements to cross a word boundary, there is a 7-bit gap between the second and third elements in the 16-bit environment.


Processor Arithmetic Mode

Two types of arithmetic are common on digital computers: one's-complement arithmetic and two's-complement arithmetic. Some programs assume that all target computers perform two's-complement arithmetic. If you take advantage of the fact that a given operation causes a particular bit pattern to be set on either a one's-complement or two's-complement computer, your program will not be portable. For example, two's-complement computers represent the 8-bit integer value −1 as a binary 11111111. A one's-complement computer represents the same decimal value (−1) as 11111110. Some programmers assume that −1 will fill a byte or a word with ones, and they use it to construct a mask template that they later shift. This will not work correctly on one's-complement computers, but the error will not surface until the least-significant bit is used.

In two's-complement arithmetic, there is only one value that represents zero. In one's-complement arithmetic, there is a value for zero and a value for negative zero. Use the C relational operators to handle this anomaly correctly; if you write code that deliberately circumvents the C relational operators, tests for zero or NULL may not operate correctly.

Microsoft C Specific

Microsoft C uses two's-complement arithmetic exclusively.


Pointers

One of the most powerful but potentially dangerous features of the C language is its use of indirect addressing through pointers. Bugs introduced by misusing pointers can be difficult to detect and isolate because the error often corrupts memory unpredictably.


Casting Pointers

Be sure you do not make nonportable assumptions when casting pointers to different types. The following code is nonportable because using a cast to change an array of char to a pointer of type long assumes a particular byte-ordering scheme. This is discussed in greater detail in Byte Order in a Word.

/* Nonportable coercion */
char c[4];
long *lp;

lp = (long *)c;
*lp = 0x12345678L;


Pointer Size

A pointer can be assigned (or cast) to any integer type large enough to hold it, but the size of the integer type depends on the computer and the implementation. Therefore, you cannot assume that a pointer is the same size as an integer; that is:

sizeof( char * ) != sizeof( int )

To determine the size of any unmodified data pointer, use:

sizeof( void * )

This expression returns the size of a generic data pointer.


Pointer Subtraction

Code that assumes that pointer subtraction yields an int value is nonportable. Pointer subtraction yields a result of type ptrdiff_t (defined in STDDEF.H). Portable code must always use variables of type ptrdiff_t for storing the result of pointer subtraction.


The Null Pointer

In most implementations, NULL is defined as 0. In Microsoft C, it is defined as ((void *)0). Because code pointers and data pointers are often different sizes, using 0 for the null pointer for both can lead to nonportability. The difference in size between code pointers and data pointers causes problems for functions that expect pointer arguments longer than an int. To avoid these problems, use the null pointer, as defined in the include file STDDEF.H; use prototypes; or explicitly cast NULL to the correct data type. Here is a portable way to use the null pointer:

/* Portable use of the null pointer */
main()
{
    func1( (char *)NULL );
    func2( (void *(*)())NULL );
}

void func1( char * c )
{
}

void func2( void *(* func)() )
{
}

The invocations of func1 and func2 explicitly cast NULL to the correct size. In the case of func1, NULL is cast to type char *; in the case of func2, it is cast to a pointer to a function that returns type void.

Microsoft C Specific

In the 32-bit environment, support for memory models and pointers of different sizes (__near, __far, and __huge) is removed. All pointers are 32 bits in size, and an attempt to use near pointers causes an error. You can, however, use the /Zf option to cause the compiler to simply ignore __far pointers.


Address Space

The amount of available memory and the address space on systems varies, depending on many factors outside your control. A program designed with portability in mind should handle insufficient-memory situations. To ensure that your program handles these situations, you should always check the error return from any of the dynamic-memory-allocation routines, such as malloc, calloc, strdup, and realloc.


Character Set

The C language does not define the character set used in an implementation. This means that any programs that assume the character set to be ASCII are nonportable.


Character Classification

The standard C run-time support contains a complete set of character classification macros and functions. These functions are defined in the CTYPE.H file and are guaranteed to be portable:

isalnum

isalpha

iscntrl

isdigit

isgraph

islower

isprint

ispunct

isspace

isupper

isxdigit

The following code fragment is not portable to implementations that do not use the ASCII character set:

/* Nonportable */
if( c >= 'A' && c <= 'Z' )
    /* uppercase alphabetic */

Instead, consider using this:

/* Portable */
if( isalpha(c) && isupper(c) )
    /* uppercase alphabetic */

The first example is nonportable because it assumes that uppercase A is represented by a smaller value than uppercase Z and that no lowercase characters fall between the values of A and Z. The second example is portable because it uses the character classification functions to perform the tests.

In a portable program, you should not perform any comparison on variables of type char except strict equality (==). You cannot assume the character set follows an increasing sequence — that may not be true on a different computer.


Case Translation

Translation of characters from uppercase to lowercase or from lowercase to uppercase is called case translation. The following example shows a coding technique for case translation not portable to implementations using a non-ASCII character set:

#define make_upper(c) ((c)&0xcf)
#define make_lower(c) ((c)|0x20)

This code takes advantage of the fact that you can map uppercase to lowercase simply by changing the state of bit 6. It is extremely efficient but nonportable. To write portable code, use the case-translation macros toupper and tolower (defined in CTYPE.H).


Assumptions About the Compiler

Different compilers translate C source code into object code in different ways. The ANSI draft standard for the C programming language defines how many of these translations must be done; others are implementation-defined.

This guide describes assumptions about how the compiler translates your C code, which can make your programs nonportable.


Sign Extension

"Sign extension" is the propagation of the sign bit to fill unoccupied space when promoting to a more significant type or when performing bitwise right-shift operations.


Promotion from Shorter Types

Integral promotions from shorter types occur when you make an assignment, perform arithmetic, perform a comparison, or perform an explicit cast.

The behavior of integral promotion is well defined, except for type char. The implementation defines whether type char is treated as signed or unsigned. The following code fragment is an example of promotion as a result of assignment:

char c1 = -3;
int  i1;

i1 = c1;

In this example, the expected result of the assignment statement is that i1 will be set to −3. If the implementation defines type char as unsigned, however, sign extension will not occur, and i1 will be 253 (on a two's-complement computer).

Promotion can also occur as a result of a comparison of different types:

char c;

if( c == 0x80 )
    .
    .
    .

This comparison never evaluates as true on an implementation that sign-extends char types but treats hexadecimal constants as unsigned. Use a character constant of the form '\x80', or explicitly cast the constant to type char to perform the comparison correctly.

The following comparison, which is an example of promotion as a result of a cast, is also nonportable:

char c;
unsigned int u;

if( u == (unsigned)c )

There are two problems with this code:

•	The char type may be treated as signed or unsigned, depending on the implementation.

•	If the char type is treated as signed, it can be converted to unsigned in two ways: the char value may first be sign-extended to int, then converted to unsigned; or the char may be converted to unsigned char, then sign-extended to int length.

It is always safe to compare a signed int with a char constant because C requires all character constants to be positive.

Variables of type char are promoted to type int when passed as arguments to a function. This causes sign extension on some computers. Consider the following code:

char c = 128;

printf( "%d\n", c );

Microsoft C Specific

Microsoft C allows you to treat type char as signed or unsigned. By default, a char is considered signed, but if you change the default char type using the /J compiler option, you can treat it as unsigned.


Bitwise Right-Shift Operations

Positive or unsigned integral types (char, short, int, and long) yield positive or zero values after a bitwise right-shift (>>) operation. For example,

(char)120 >> 4

yields 7,

(unsigned char)240 >> 8

yields 0,

(int)500 >> 8

yields 1, and

(unsigned int)65535 >> 4

yields 4,095.

Negative-signed integral types yield implementation-defined values after a bitwise right-shift operation. This means that you must know whether you want to do a signed or unsigned shift, then code accordingly.

If you don't know how the implementation performs, you might get unexpected results. For example, (signed char)0x80 >> 3 yields 0xf0 if the implementation performs sign extension on right bitwise shifts. If the implementation does not perform the sign extension, the result is 0x10.

You can use right shifts to speed up division when the divisor can be represented by powers of 2 and the dividend is positive. To maintain portability, you should use the division operator.

To perform an unsigned shift, explicitly cast the data to an unsigned type. To perform a shift that extends the sign bit, use the division operator as follows: divide by 2^ (n) , where n is the number of bits you want to shift.


Length and Case of Identifiers

Some implementations do not support long identifiers. Some allow only 6 characters, while others allow as many as 32. They may report each identifier that exceeds the maximum length or truncate identifiers to a given length. Truncation causes serious problems, especially if you have a number of similarly named variables within the scope of a block of code, such as the following:

double acct_receivable_30_days;
double acct_receivable_60_days;
double acct_receivable_90_days;
double current_interest_rate;

acct_receivable_30_days *= current_interest_rate;

If your target system retains only six significant characters, you need to rename all your acct_receivable variables.

Case sensitivity also affects portability. C is usually a case-sensitive language. That is, CalculateInterest is not considered the same identifier as calculateinterest. Some systems are not case sensitive, however, so to write portable code, differentiate your identifiers by something other than case.

These problems with identifiers can occur in two locations: the compiler and the linker or loader. Even if the compiler can handle long and case-differentiated identifiers, if the linker or loader cannot, you can get duplicate definitions or other unexpected errors.

Microsoft C Specific

The Microsoft C compiler issues the /NOIGNORECASE command to the Microsoft Linker (LINK), which directs it to consider case significant.


Register Variables

The number and type of register variables in a function depend on the implementation. You can declare more variables as register than the number of physical registers the implementation uses. In such a case, the compiler treats the excess register variables as automatic.

Because the types that qualify for register class differ among implementations, invalid register declarations are treated as automatic.

If you declare variables as register to optimize performance, declare them in decreasing order of importance to make sure the compiler allocates a register to the most important variables.

Microsoft C Specific

The compiler ignores register declarations if you select the global register allocation optimization. You can select global register allocation as follows:

Environment	Selection
CL command line	Specify either the /Oe or /Ox option.
pragma	Use the optimize pragma with the e parameter.


Evaluation Order

The C language does not guarantee the evaluation order of most expressions. Avoid writing constructs that depend on evaluation within an expression to proceed in a particular manner. For example,

i = 0;
func( i++, i++ );
.
.
.
func( int a, int b )
{

A compiler could evaluate this code fragment and pass 0 as a and 1 as b. It could also pass 1 as a and 0 as b and conform equally with the standards.

The C language does guarantee that an expression will be completely evaluated at any given "sequence point." A sequence point is a point in the syntax of the language at which all side effects of an expression or series of expressions have been completed.

These are the sequence points in the C language:

•	The semicolon (;) statement separator

•	The call to a function after the arguments have been evaluated

•	The end of the first operand of one of the following:

•	Logical AND (&&)

•	Logical OR (||)

•	Conditional (?)

•	Comma separator (,) when used to separate statements or in expressions; the comma separator is not a sequence point when it is used between variables in declaration statements or between parameters in a function invocation

•	The end of a full expression, such as:

•	An initializer

•	The expression in an expression statement (for example, any expression inside parentheses)

•	The controlling expression of a while or do statement

•	Any of the three expressions of a for statement

•	The expression in a return statement


Function and Macro Arguments with Side Effects

Run-time support functions can be implemented either as functions or as macros. Avoid including expressions with side effects inside function invocations unless you are sure the function will not be implemented as a macro. Here is an illustration of how an argument with side effects can cause problems:

#define limit_number(x) ((x > 1000) ? 1000 : (x))

a = limit_number( a++ );

If a is greater than 1000, it is incremented once. If a is less than or equal to 1000, it is incremented twice, which is probably not the intended behavior.

A macro can be used safely with an argument that has side effects if it evaluates its parameter only once. You can determine whether a macro is safe only by inspecting the code.

A common example of a run-time support function that is often implemented as a macro is toupper. You will find your program's behavior confusing if you use the following code:

char c;

c = toupper( getc() );

If toupper is implemented as a function, getc will be called only once, and its return value will be translated to uppercase. However, if toupper is implemented as a macro, getc will be called once or twice, depending on whether c is uppercase or lowercase. Consider the following macro example:

#define toupper(c) ( (islower(c)) ? _toupper(c) : (c) )

If you include the toupper macro in your code, the preprocessor expands it as follows:

/* What you wrote */
c = toupper( getc() );

/* Macro expansion */
ch = (islower( (getc()) ) ? _toupper( getc() ) : (getc()) );

The expansion of the macro shows that the argument to toupper will always be called twice: once to determine if the character is lowercase and the next time to perform case translation (if necessary). In the example, this double evaluation calls the getc function twice. Because getc is a function whose side effect is to read a character from the standard input device, the example requests two characters from standard input.


Environment Differences

Many programs perform some file I/O. When writing these programs for portability, consider the following:

•	Do not hard code filenames or paths. Use constants you define either in a header file or at the beginning of the program.

•	Do not assume the use of any particular file system.

•	Do not assume a particular display size (number of rows and columns).

•	Do not assume that display attributes exist. Some environments do not support such attributes as color, underlined text, blinking text, highlighted text, inverse text, protected text, or dim text.


Microsoft C Byte Ordering

For all Windows programming, the processor runs in "little endian" mode. If b0 represents a less significant byte than b1, the layout of a short will be b0 b1, and the layout of a long will be b0 b1 b2 b3.  This is in contrast to "big endian" mode where a short would be b1 b0, and a long would be b3 b2 b1 b0.


WINDOWS.H and STRICT Type Checking

The WINDOWS.H file contains a number of type definitions, macros, and structures that aid in writing source code portable between versions of Microsoft Windows. Some of the WINDOWS.H features are enabled when the STRICT symbol is defined on the command line or makefile. This guide explains how these STRICT features affect the writing of correct code and what the advantages of using them are.

This guide discusses the following major topics:

•	New types and macros

•	Using STRICT to improve type checking


New Types and Macros

Porting 16-bit Code to 32-bit Windows introduced some new standard types for Windows programming. Use of the old types, such as FAR PASCAL for declaring Windows procedures, may work in existing code but is not guaranteed to work in all future versions of Windows. Therefore, you should convert your code to use the new standards wherever appropriate.


General Data Types

The following table summarizes the new standard types defined in WINDOWS.H. These types are polymorphic (they can contain different kinds of data) and are useful generally throughout applications. There are also other new types, handles, and function pointers that are introduced in following sections.

Typedef	Description
WINAPI	Use in place of FAR PASCAL in function declarations. If you are writing a DLL with exported function entry points, you can use this for your own functions.
CALLBACK	Use in place of FAR PASCAL in application callback routines such as window procs and dialog procs.
LPCSTR	Same as LPSTR, except used for read-only string pointers. Defined as (const char FAR*).
UINT	Portable unsigned integer type whose size is determined by host environment (32 bits for Windows 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.
LPARAM	Type used for declaration of second general purpose Window procedure parameter.
LPVOID	Generic pointer type, equivalent to (void *). Should be used in preference to LPSTR.


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, high)	Combines two 16-bit quantities into an LPARAM.
MAKELRESULT(low, high)	Combines two 16-bit quantities into an LRESULT.
MAKELP(sel, off)	Combines a selector and an offset into a FAR VOID* pointer. Useful only for Windows 3.x.
SELECTOROF(lp)	Extracts the selector part of a far pointer. Returns a UINT. Useful only for Windows 3.x.
OFFSETOF(lp)	Extracts the offset part of a far pointer. Returns a UINT. Useful only for Windows 3.x.
FIELDOFFSET(type, field)	Calculates the offset of a member of a data structure. The type is the type of structure, and field is the name of the structure member or field.


New Handle Types

In addition to the existing Windows handle types such as HWND, HDC, HBRUSH, and so on, WINDOWS.H defines the following new handle types. They are particularly important if STRICT type checking is enabled, but you can use these even if you do not define STRICT.

Handle	Description
HINSTANCE	Instance handle type
HMODULE	Module handle type
HBITMAP	Bitmap handle type
HLOCAL	Local handle type
HGLOBAL	Global handle type
HTASK	Task handle type
HFILE	File handle type
HRSRC	Resource handle type
HGDIOBJ	Generic GDI object handle type (except HMETAFILE)
HMETAFILE	Metafile handle type
HDWP	DeferWindowPos() handle
HACCEL	Accelerator table handle
HDRVR	Driver handle (Windows NT only)


Using STRICT to Improve Type Checking

Defining the STRICT symbol enables features that require you to be more careful in declaring and using types. This may sound like a burden, but it is actually an aid to writing more portable code. This extra care will also reduce the time you spend debugging. Enabling STRICT redefines certain data types so that the compiler won't permit assignment from one type to another without an explicit cast. This is especially helpful with Windows code. Errors in passing data types are reported at compile time instead of causing fatal errors at run time.

When STRICT is defined, WINDOWS.H type definitions change as follows:

•	Specific handle types are defined so as to be mutually exclusive; for example, you won't be able to pass an HWND where an HDC type argument is required. Without STRICT, all handles are defined as integers, so the compiler doesn't prevent you from using one type of handle where another type is expected.

•	All callback function types (dialog procedures, window procedures, and hook procedures) are defined with full prototypes. This prevents you from declaring callback functions with incorrect parameter lists.

•	Parameter and return value types that should use a generic pointer are declared correctly as LPVOID instead of as LPSTR or other pointer type.

•	The COMSTAT structure is now declared according to the ANSI standard.


Enabling STRICT Type Checking

To enable STRICT type checking, just define the symbol name "STRICT". You can specify this definition on the command line or in a makefile by giving /DSTRICT as a compiler option.

To define STRICT on a file-by-file basis (supported by C but not C++ as explained in the note in this section), insert a #define statement before including WINDOWS.H in files where you want to enable STRICT:

#define STRICT

#include WINDOWS.H

For best results, you should also set the warning level for error messages to at least /W3. This is good policy with Windows applications in any case, because a coding practice that causes a warning (for example, passing the wrong number of parameters) usually causes a fatal error at run time if it is not corrected.

Note  If you are writing a C++ application, you don't have the option of applying STRICT to only some of your source files. Because of the way C++ "type safe linking" works, mixing STRICT and non-STRICT source files in your application can cause linking errors.


Making Your Application STRICT Compliant

Some source code that in the past compiled successfully might produce error messages when you enable STRICT type checking. The following sections describe the minimal requirements you need to follow, where applicable, to make sure your code compiles when STRICT is enabled. There are other steps not strictly required but recommended, especially if you want to produce portable code. These are covered in Making Best Use of STRICT Type Checking.


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 New Types and Macros for a list of new specific handle types.


Using Function Pointers

Always declare function pointers with the proper function type (such as DLGPROC or WNDPROC) rather than FARPROC. You'll 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 you'll 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 you've 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
LocalLock	Cast result to the proper kind of data pointer.
GlobalLock	Cast result to the proper kind of data pointer.
GetWindowWord	Cast result to appropriate data type.
GetWindowLong	Cast result to appropriate data type
SetWindowWord	Cast argument as it is passed to function.
SetWindowLong	Cast argument as it is passed to function.
SendMessage	Cast result to appropriate data type; cast to UINT before casting to a handle type.
DefWindowProc	See comment for SendMessage.
SendDlgItemMessage	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);


Making Best Use of STRICT Type Checking

To get the most benefit from STRICT type checking, there are other guidelines you should follow in addition to those in Making Your Application STRICT Compliant. Your code will be more portable in future versions of Windows if you make the following changes:

Change	To
HANDLE	A specific handle such as HINSTANCE, HMODULE, HGLOBAL, HLOCAL, and so on
WORD	UINT, except where you want a 16-bit value even when the platform is 32 bits
WORD	WPARAM, where wParam is declared
LONG	LPARAM or LRESULT as appropriate
Any time you need an integer data type, you should declare it as UINT except where a 16-bit value is specifically required (as in a structure or parameter). For even if a variable never exceeds the range of a 16-bit integer, it can be more efficiently handled by the processor if it is 32 bits.

The types WPARAM, LPARAM, LRESULT, and void * are "polymorphic data types": they hold different kinds of data at different times, even when STRICT type checking is enabled. To get the benefit of type checking, you should cast values of these types as soon as possible. Note that message crackers (as well as the Microsoft Foundation Classes) automatically recast wParam and lParam for you in a portable way.

Take special care to distinguish HMODULE and HINSTANCE types. Even with STRICT enabled, they are defined as the same base type. Most kernel module management functions use HINSTANCE types, but there are a few functions that return or accept only HMODULE types.


Accessing the New COMSTAT Structure

The Windows 3.0 declaration of the COMSTAT structure is not compatible with ANSI standards. WINDOWS.H now defines the COMSTAT structure to be compatible with ANSI compilers and so that the /W4 option does not issue warnings.

To support backward compatibility of source code, WINDOWS.H does not use the new structure definition unless the Windows version (as indicated by WINVER) is greater than 3.0 or if STRICT is defined. When you enable STRICT, the presumption is that you are trying to write portable code. Therefore, WINDOWS.H uses the new COMSTAT structure for all versions of Windows if STRICT is enabled.

The new structure definition replaces the bit fields by flags accessing bits in a single field, named status, as shown below. Each flag turns on a different bit.

Windows 3.0 field name	Flag accessing the status field
fCtsHold	CSTF_CTSHOLD
fDsrHold	CSTF_DSRHOLD
fEof	CSTF_EOF
fRlsdHold	CSTF_RLSDHOLD
fTxim	CSTF_TXIM
fXoffHold	CSTF_XOFFHOLD
fXoffSent	CSTF_XOFFSENT
If you have code that accesses any of these status fields, you need to change your code as appropriate. For example, suppose you have the following code written for Windows 3.0:

if (comstat.fEof || fCondition)
comstat.fCtsHold = TRUE;
comstat.fTxim = FALSE;

This code should be replaced by code that access individual bits of the status field by using flags. Note the use of bitwise operators.

if ((comstat.status & CSTF_EOF) || fCondition)
comstat.status |= CSTF_CTSHOLD;
comstat.status ~= CSTF_TXIM;


Interpreting Error Messages Affected by STRICT

Enabling STRICT type checking may affect the kind of error messages you receive. With STRICT enabled, all handle types as well as the types LRESULT, WPARAM, and LPARAM are defined as pointer types. When you incorrectly use these types (for example, passing an int where an HDC is expected), you will get error messages referring to errors in pointer indirection.

Another effect of STRICT is to require that FARPROC function pointers be recast as more specific function pointer types such as DLGPROC. However, MakeProcInstance and FreeProcInstance still work with the FARPROC type. If you fail to cast between FARPROC and the appropriate function pointer type, the compiler will report an error in function parameter lists.

Note that using MakeProcInstance is useful for the sake of portability, if you want to use the same source to compile for Windows 3.x. Under Win32, however, MakeProcInstance performs no operation, but just returns the function name.


Multimedia Possibilities

A multimedia application delivers information in ways that can be more powerful than printed material or standard video and sound. Unlike printed material, a multimedia application communicates using more than a series of static images or text. Unlike standard video or sound presentations, a multimedia application allows the user to navigate through media and interact with information quickly and easily. The new information media that typically define a multimedia application are sound and video. An application that incorporates sound, video, or both is a multimedia application.

For many years, computers were expected to arrange data, but not to deliver it. The result of the user's work was typically printed on paper. Today, however, inexpensive computers are capable of overcoming many of the inherent limitations of printed material. Practically any computer that uses the Microsoft® Windows® operating system and has a VGA monitor and a sound card can exploit many of the features of a multimedia application. Millions of computer users already own equipment like this, and many also have more powerful multimedia computers with monitors that can display 256 colors or more and compact disc (CD) players. More and more, these computers are becoming the final delivery system for information. People are sending electronic mail instead of letters. Instead of reaching for a bulky printed encyclopedia, they are enjoying the full-color graphics, sound, and animation of a CD-based encyclopedia.

A multimedia application written for the Microsoft Win32® application programming interface (API) delivers information in ways that a printed page cannot. Even when the focus of the application is to help a user produce a printed document or perform calculations, the application can use sound, video, or both to enrich the user's experience.

The definition of a multimedia computer has been established by an industry-wide group, the Multimedia PC Marketing Council. This council has defined two sets of minimum specifications for multimedia computers. For a description of these specifications, see Multimedia PC Specifications. An application does not need to take full advantage of all of this hardware to qualify as a multimedia application.

Developing multimedia applications can be as simple as adding an existing sound or video recording to an application or as complex as building an editing tool for customizing multimedia presentations. No matter how complex your goal, this volume will help you achieve it.

The intended audience for this book is programmers who already have some background in the opportunities presented by multimedia computing. It focuses strictly on helping readers implement the multimedia features of the Win32 API. This book will help programmers who want to incorporate multimedia capabilities into their applications, create multimedia-based applications, or create tools for writing or editing multimedia publications.


What You Can Do with Multimedia

If you think about it for a few minutes, you are sure to come up with a number of applications that could use sound and video in new and exciting ways. For example, real estate agents have long organized descriptions and photographs of homes in large catalogs. Because these catalogs are printed on paper, the presentation of the homes is limited to a small picture and a paragraph or two of text. If the catalog were produced as a multimedia application, on the other hand, it could display a guided audio and visual tour of the inside and outside of these homes. Having potential buyers view these listings could be a powerful sales tool and could prevent wasted trips to unsuitable locations.

This real estate application is just one example of what you can do with multimedia. You can use multimedia to create applications that play, edit, and capture sounds and images. You can also create applications that can control multimedia hardware, such as CD players, video-cassette recorders, and MIDI (Musical Instrument Digital Interface) devices. For entertainment applications, the Win32 API also supports the use of joysticks and provides a timer mechanism that is more accurate than the standard Win32 timers.

Many developers use multimedia to improve applications that did not use sound and video when they were first designed and written. For example, developers are adding voice-annotation capabilities to word-processing applications, or video clips to presentation-graphics applications. More generally, developers are adding sounds to all types of applications; for example, to request input from the user (such as a password) or to signify an action (such as opening or closing a file).

Some applications integrate multimedia features more completely. Software developers are creating hundreds of such applications, such as entertainment programs, computerized reference works, and educational programs. Because extensive use of sound or video requires a great deal of data-storage space, these applications are often distributed on CDs.

You can create multimedia applications for anyone who routinely needs fast access to large amounts of data. These applications are often written for niche markets; the multimedia real estate catalogue discussed earlier is a good example. The possible variety and uses of such applications are almost limitless:

•	Doctors could consolidate their records about a case on a CD, including not only all the relevant reports and histories but also such items as videotapes of surgical procedures and consultations with the client.

•	Telephone directories for businesses could include full-color graphics, sophisticated search capabilities, audio clips, and detailed maps.

•	A voicemail system could be integrated into an electronic mail application. It is feasible that a combination of multimedia software and hardware could be used to integrate the functions currently performed by telephones, modems, faxes, voicemail systems, and electronic mail applications.


Multimedia Playback with One Function Call

You can play waveform-audio files, CDs, video clips, or MIDI files in your application with a call to a single function: MCIWndCreate. This function creates a button that the user can use to play or stop the playback, a trackbar that displays the current position in the file, and, in the case of a video clip, a window in which the video is displayed. The following call to MCIWndCreate plays the video clip SAMPLE.AVI:

MCIWndCreate(hwndParent,                      // parent window handle
    g_hinst,                                  // instance handle
    WS_VISIBLE | WS_CHILD | MCIWNDF_SHOWALL,  // window styles
    "sample.avi");                            // filename

Another function, PlaySound, also enables you to implement multimedia playback with a single function call. You can use this function to play a waveform-audio file. For example, the following line of code plays the sound stored in the file CHIMES.WAV:

PlaySound("chimes.wav", NULL, SND_SYNC);

Note  PlaySound cannot play a waveform-audio file larger than will fit in available memory. To play larger files, you should use either the MCIWnd window class or the high-level audio interface. For more information about the MCIWnd window class than is presented in this section, see Getting Started Using MCIWnd. For more information about PlaySound, see Waveform Audio.


Multimedia Data Formats

Windows supports three distinct types of multimedia data: waveform audio, MIDI sound, and video.

Waveform audio is a digitized recording of a sound. You can typically edit waveform audio using insertions and deletions, or you can modify it using filters. This sound format can store voice, music, and sound effects exactly as they should be heard by the user. Compared to MIDI sound, however, editing waveform audio is difficult and the storage requirements are high. In Windows, waveform-audio files typically have a .WAV filename extension.

MIDI sounds are stored as a series of instructions, rather than as a waveform. A synthesizer (often part of the computer's sound card) interprets the instructions to produce the sound. Because different synthesizers interpret MIDI instructions with greatly varying quality, the sound heard by the user cannot be guaranteed. This sound format can store music, and sometimes sound effects, but voice is not a practical option. Compared to waveform audio, however, MIDI is easy to edit and the storage requirements are low. In Windows, MIDI sound files typically have a .MID filename extension.

Video is a multiple-track recording that includes waveform audio and moving images. The moving images are recorded as a series of still images. In Windows, video files typically have an .AVI filename extension.


Version Checking

You may need to check the installed version of the multimedia system, particularly if your application takes advantage of features that were not available in previous releases. Although the multimedia header files contain two version-checking functions, they are obsolete. These obsolete functions are mmsystemGetVersion and VideoForWindowsVersion. Your application should rely on the standard Windows functions, GetVersion or GetVersionEx, instead.


The Multimedia Documentation

Unless you are developing a very complex multimedia application, you need not read all of the multimedia documentation. This volume is divided into five parts; the parts you need to read depend on the type of application you are writing. Your application can interact with a multimedia device using a high-level, mid-level, or low-level interface. The parts of this volume mirror this hierarchy of implementation levels.

Part 1 discusses how to design applications that use high-level interfaces based on window classes. Read this part if you want to add sound or video to an application and you do not need to implement complicated editing or recording functionality.

Part 2 discusses how to design applications that use a mid-level interface — called the Media Control Interface (MCI) — which offers applications a standard set of commands to use when communicating with a multimedia device. Read this part if you want to implement a customized user interface for your video or sound files but you do not need to take full advantage of the capabilities of a particular device.

Parts 3, 4, and 5 discuss how to design applications that use a set of low-level multimedia interfaces. These interfaces allow applications to achieve nearly complete control over an audio or video presentation. Read these parts if your application needs to take full advantage of one or more multimedia devices, if you plan to implement recording or editing features, or if you need a custom format for your data.


High-Level Interfaces

An application can use the MCIWnd window class to play a video, MIDI, or waveform-audio file. Several functions that play only waveform audio are also available. Part 1 of this volume describes the most widely used parts of this high-level multimedia interface. In addition, Multimedia Playback with One Function Call earlier  shows you how to use this high-level interface to play a video or sound file very easily.

Another window class, AVICap, makes it easy to develop an interface for capturing video clips. For more information about AVICap, see Video Capture.


Mid-Level Interface

MCI is a device-independent interface for controlling virtually any multimedia device. Although many MCI commands are appropriate for any multimedia device, some commands exploit the features of a particular device or class of devices. You can use this mid-level interface to implement a customized user interface and achieve greater control over a multimedia device while still developing applications simply and quickly. Part 2 of this topic describes MCI.


Low-Level Interfaces

Part 3 of this topic describes advanced video techniques, including how to work with video files, and how to work with the compression management component that provides compression and decompression services for these files.

Part 4 describes advanced audio techniques (including MIDI services that are not available through the MCI interface documented in Part 2), advanced waveform-audio techniques, audio mixers, and the component for managing audio compression.

Other parts of the low-level interface to multimedia are discussed in Part 5 and the appendixes. These subjects include joysticks and multimedia timers, the file input and output services for multimedia files, and file formats for multimedia data files.


Getting Started Using MCIWnd

MCIWnd is a window class for controlling multimedia devices. A library of functions, messages, and macros associated with MCIWnd provides a simple method to add multimedia playback or recording capabilities to your applications.

Using a single function, your application can create a control that plays devices such as video, CD audio, waveform audio, MIDI (Musical Instrument Digital Interface), or any device that uses the Media Control Interface (MCI). Automating playback is also quick and easy. Using a function and two macros, an application can create an MCIWnd window with the appropriate media device, play the device, and close both the device and the window when the content has finished playing.

Note  Some devices, such as CD audio devices, play content that is stored on a medium. Other devices play content that is stored in files. For purposes of clarity, this book refers to both circumstances as "playing the device."


MCIWnd Window User Interface

MCIWnd provides additional features to adjust the look of the MCIWnd window, customize the behavior of your application, and tune playback performance. The major features of the MCIWnd window include the following:

•	A toolbar with Play, Stop, Record and Menu buttons

•	A trackbar that controls positioning within the playback content

•	A pop-up menu containing common commands

•	A playback area for video and other devices requiring it

The MCIWnd window includes a playback area for video, animation, and other devices that display images during playback. MCIWnd omits the playback area from waveform-audio devices, MIDI sequencers, and other devices that do not write to the display.

The Play button is located in the lower-left corner of the MCIWnd window. It appears when the content is stopped. The user can play the content in the following ways:

•	To play the content from the current position, select the Play button.

•	To play the content full-screen from the current position, select the Play button while holding down the CTRL key.

•	To play the content backward from the current position, select the Play button while holding down the SHIFT key.

The Menu button, located next to the Play button, activates a menu that allows the user to open and close audio-video interleaved (AVI) files, and to adjust the image size, playback speed, and volume. (The user can also activate the menu by clicking the right mouse button whenever the cursor is in the client area of the window.) The menu also includes commands to change the configuration of the current device, to copy the playback content to the clipboard, and to issue MCI commands.

The trackbar to the right of the Menu button represents the duration of the playback (or recorded) content. The slider on the trackbar represents the current position within the content. When the slider is positioned at the left end of the trackbar, the current position is the beginning of the content. The user can move to different locations in the content by dragging the slider along the trackbar.

The MCIWnd controls can also include a Record button for devices that can record. The Record button is marked with a red circle and appears only when the device is capable of recording.

Note  The playback window must be aligned on a four-pixel boundary for the best video playback performance. Typically, the Microsoft Windows operating system aligns the window automatically when it is created. If a user moves or stretches the window from its initial position, video playback speed might be reduced by half.


Multimedia Playback

The MCIWndCreate function is the basis for controlling an MCIWnd window and the device associated with it. In general, this function registers the MCIWnd window class and creates an MCIWnd window for using MCI services. This section describes how to use this function to perform the following tasks:

•	Add user-controlled playback to an application

•	Automate playback in an application

•	Use window styles to change the appearance and behavior of an MCIWnd window

•	Allow the user to select files and MCI devices for playback


User-Controlled Playback

You can add user-controlled playback to an existing application by calling the MCIWndCreate function as follows:

MCIWndCreate(hwndParent, hInstModule, NULL, "filename.typ");

The MCIWndCreate parameters identify handles to the parent window and to the module instance associated with the MCIWnd window. They also specify window styles and the filename (or device name) to associate with the MCIWnd window.

MCIWndCreate automatically performs the following steps that, for other window classes, you would normally have to code in your application:

1.	Registers the MCIWnd window class.

2.	Creates the MCIWnd window.

3.	Loads the specified content.

4.	Establishes the current position at the beginning of the content.

5.	Displays the device control.

6.	Displays the playback area of the window if needed.


Automated Playback

You can automate playback in your application by using MCIWndCreate and the MCIWndPlay macro, along with either the MCIWndDestroy or the MCIWndClose macro. To automate playback, specify the MCIWNDF_NOPLAYBAR and MCIWNDF_NOTIFYMODE styles in the dwStyle parameter. MCIWNDF_NOPLAYBAR hides the toolbar, and MCIWNDF_NOTIFYMODE issues an appropriate notification message when the device stops playing.

You can play the device or file specified in MCIWndCreate by using MCIWndPlay. MCIWndPlay starts playing the content from its current position and continues to its end.

You can destroy or close an MCIWnd window by using the MCIWndDestroy or MCIWndClose macro. MCIWndDestroy closes the device or file and destroys the MCIWnd window by invalidating its handle. If your application can reuse the MCIWnd window, use MCIWndClose to close the device without destroying the window.

Your application can detect when the device stops playing and automatically close the window. To do this, specify the MCIWNDF_NOTIFYMODE style for the dwStyle parameter of MCIWndCreate. This causes the device to send a MCIWNDM_NOTIFYMODE message whenever it changes modes. Your application can trap this message to determine whether the device has stopped playing and, if so, close the window.


MCIWnd Window Styles

As with any window, you can change the appearance and behavior of an MCIWnd window by choosing from the standard Microsoft Win32 window styles. In addition, you can choose from several other window styles that are specific to MCIWnd windows. With these styles, your application can change these MCIWnd windows in the following ways:

•	Change window size.

•	Hide or display controls.

•	Issue notification messages.

•	Display information in the title bar.

You can set window styles by specifying them in the MCIWndCreate function, or you can use the MCIWndChangeStyles macro to change the style of an existing MCIWnd window. You can also query an MCIWnd window for its current styles by using the MCIWndGetStyles macro.

For a list of the MCIWnd-specific window styles, see the description of MCIWndCreate in the Reference section.


Additional Methods to Specify Files

You can associate a device or file with an existing MCIWnd window by using the MCIWndOpenDialog, MCIWndOpen, and MCIWndOpenInterface macros, and the GetOpenFileNamePreview function.

To let a user of your application select a file to play, use MCIWndOpenDialog. This macro displays the Open dialog box for choosing a file and associates the selected file with the current MCIWnd window.

You can let a user of your application select a file to associate with an MCIWnd window and preview that file by using GetOpenFileNamePreview and MCIWndOpen. GetOpenFileNamePreview displays the Open dialog box for choosing a file and lets the user preview (play) its contents. When the name of an existing file is specified in the dialog box, GetOpenFileNamePreview provides a small control to let the user preview the contents of the file. You can associate a specified file, selected with GetOpenFileNamePreview or specified in another manner, with an MCIWnd window by using MCIWndOpen.

You can also specify a device, such as "CDAudio," to associate with an MCIWnd window by using MCIWndOpen.

To associate an MCIWnd window with a file interface or data-stream interface to multimedia data, use MCIWndOpenInterface. For more information about file and data-stream interfaces, see AVIFile Functions and Macros.

Note  Before associating a new file or device with an MCIWnd window, MCIWndOpenDialog and MCIWndOpen implicitly close any device currently associated with the window. Your application does not need to close any open devices before using these macros.


Playback Controls

MCIWnd includes several macros for controlling playback. This section describes how to use these macros to perform the following tasks:

•	Determine and change the current position.

•	Start, pause, and resume playback.

•	Play a portion of the content (scope).

•	Play backward.

•	Play in a continuous loop.


Current Position

When a file or device is associated with an MCIWnd window, the position is initially set at the start of the content, regardless of the media type. During playback, the position moves linearly through the content and, if playback is uninterrupted, eventually reaches the end of the content. If an interruption occurs, the current position is the location in the content where playback was stopped or paused.

You can retrieve the locations for the beginning and end of the content by using the MCIWndGetStart and MCIWndGetEnd macros. You can determine the length of the content by subtracting the value returned by MCIWndGetStart from the value returned by MCIWndGetEnd, or by using the MCIWndGetLength macro. You can retrieve the current position by using the MCIWndGetPosition macro, or you can retrieve the position as a null-terminated string by using the MCIWndGetPositionString macro.

To change the current position, use the MCIWndHome, MCIWndEnd, and MCIWndSeek macros. You can move the playback position to the start of the content by using MCIWndHome or to the end of the content by using MCIWndEnd. Use MCIWndSeek to move the playback position to any location in the content.

You can also step through the content by using the MCIWndStep macro. Beginning from the current position, this macro moves the position forward or backward by a specified increment.

Note  The units used to specify position vary among the different media types and devices. For example, the position for AVI files used by the MCIAVI device is measured in frames; the position for CD audio, waveform-audio, and MIDI files is measured in milliseconds.

Devices for other media types and third-party devices might use other units. For information about determining these units, see Playback Enhancements.


Starting, Pausing, and Resuming Playback

MCIWndPlay is the most general playback macro. This macro lets you play a file or device from the current position. Playback continues through the end of the content unless it is interrupted.

You can temporarily interrupt a device that is playing by using the MCIWndPause macro. You can resume playback from the paused position by using the MCIWndResume macro. Some devices do not support the pause and resume commands. These devices usually map MCIWndPause to the MCIWndStop macro, which stops playback or recording. You can restart a device that does not support pause or resume by using MCIWndPlay, which starts playback from the current position.


Playback Scope

MCIWnd provides macros that allow you to define the playback scope. The scope is the portion of the playback you want to play. For example, you can play the content from a position other than the beginning position by using the MCIWndPlayFrom macro. This macro seeks the specified location, begins playback, and continues to the end of the content. Similarly, you can play the content to a specified end point by using the MCIWndPlayTo macro. MCIWndPlayTo starts at the current position and plays until the specified location or the end of the content is reached, whichever comes first.

Also, you can define both the beginning and ending positions by using the MCIWndPlayFromTo macro. This macro seeks the specified beginning location and plays until the specified ending location or the end of the content is reached.


Reverse Playback

Some devices support playback in the reverse direction. You can play the content of such a device in the reverse direction by using the MCIWndPlayReverse macro. This macro defines the playback scope from the current position to the beginning of the content. The digital-video device, MCIAVI, can play backward. Devices that cannot play backward, such as CD audio, can issue an error message when MCIWndPlayReverse is invoked.


Playback Loops

MCIWnd supports playback as a continuous loop. You can play the content of a file or device repeatedly as a loop by using the MCIWndSetRepeat macro in combination with the Play button on the toolbar. The video playback device, MCIAVI, supports playback loops. To determine if continuous playback has been activated, use the MCIWndGetRepeat macro.


Multimedia Recording

You can implement recording capabilities in your application by using the user interface built into MCIWnd. You can use the MCIWndCreate function and the MCIWndNew macro to provide controls for starting and stopping recording and for saving the recorded information. Using MCIWndCreate, you can specify window styles to display an MCIWnd window and to include the Record button on the toolbar. Using MCIWndNew, you can specify the device type that is being recorded and that the information is to be captured in a new file.

If your application requires more sophistication, you can automate and customize the recording by using the MCIWndRecord macro. For additional information about customizing the recording process, see Customizing the Recording Process.

Note  Some devices, such as CD audio and MCIAVI, are used for playback only. Other devices, such as waveform-audio devices, can be used for recording. If you specify a device that cannot record, MCIWnd omits the Record button from the toolbar.


Saving Recorded Content

After completing the recording, you can save the content by using the MCIWndSave or MCIWndSaveDialog macro, or by using the GetSaveFileNamePreview function with MCIWndSave. MCIWndSave saves data in the file associated with the MCIWnd window. MCIWndSaveDialog lets the user specify a filename and save the recorded data in the specified file. GetSaveFileNamePreview displays the SaveAs dialog box for choosing a file and lets the user preview (play) the file. When the name of an existing file is specified in the SaveAs dialog, GetSaveFileNamePreview provides a small control in the dialog box to let the user preview the contents of the file. You can save the recorded data in a file selected with GetSaveFileNamePreview by using MCIWndSave.


Playback Enhancements

When your application can play multimedia data using an MCIWnd window, you can enhance and adjust the window's appearance and behavior. This section describes how to perform the following tasks:

•	Specify time formats.

•	Adjust speed, volume, and zoom.

•	Provide controls for cropping and stretching images.

•	Use palettes.

•	Provide status updates.

•	Use a multiple document interface.


Time Formats

Multimedia data types typically can use time to identify significant positions within their content. Common time formats are milliseconds, tracks, and frames; other less common time formats, such as SMPTE 24, also exist. Time is the format and reference system for waveform-audio, MIDI, and CD audio data. Video supports time even though it is recorded as a sequence of frames (stream) that is normally played at a specific speed. Several macros are available for designating time format.

You can retrieve the current time format for a file or device by using the MCIWndGetTimeFormat macro. You can change the current time format to any other time format supported by a device by using the MCIWndSetTimeFormat macro. Or you can the set the time format to milliseconds or frames by using the MCIWndUseTime or MCIWndUseFrames macros.

Note  Noncontinuous formats, such as tracks and SMPTE (Society of Motion Picture and Television Engineers), can cause the toolbar to behave erratically. For these time formats, you might want to turn off the toolbar by specifying the MCIWNDF_NOPLAYBAR window style when creating an MCIWnd window.


Speed, Volume, and Zoom

The speed, volume, and zoom macros provide the functionality of the View, Volume, and Speed commands of the MCIWnd menu. The macros in this section are generally used with video and other devices that display images during playback.

Some devices support multiple playback speed changes. You can set the playback speed for these devices by using the MCIWndSetSpeed macro. This macro defines the normal playback speed as 1000. Higher values indicate faster speeds. Lower values indicate slower speeds.

You can retrieve the current playback speed by using the MCIWndGetSpeed macro. This macro uses the same numerical values and range as MCIWndSetSpeed.

Some devices support volume changes. You can adjust or set the volume by using the MCIWndSetVolume macro. This macro defines the normal volume level as 1000. Higher values indicate louder volumes. Lower values indicate quieter volumes.

You can retrieve the current volume level by using the MCIWndGetVolume macro. This macro uses the same numerical values and range as MCIWndSetVolume.

For devices that use a playback window, MCIWnd supports a zoom feature that sets the size of the playback image. You can set the playback image size by using the MCIWndSetZoom macro. The macro redefines the playback image size while maintaining a constant aspect ratio for the image. The zoom value is defined as a percentage of the original image size. Thus, 100 represents the original image size, 50 indicates the image is shown half its original size, and 200 indicates the image is shown twice its original size.

You can retrieve the current zoom value by using the MCIWndGetZoom macro. This macro uses the same numerical values and range as MCIWndSetZoom.

Note  The standard MCI CD audio and waveform-audio drivers do not support volume or speed changes.


Cropping and Stretching Images

MCIWnd allows you to crop and stretch images of a video clip. To understand these features, you need to understand the relationships between frame size, source rectangle, destination rectangle, and playback area.

A video clip consists of several frames, each containing one image. The frame size of a video clip is the size of the image in the current frame. Typically, a video clip has one frame size because all the images in the clip are the same size.

The source rectangle is a rectangular area that overlays the frames of a video clip. The source rectangle defines the portion of each frame that is displayed during playback. When a video clip is loaded with MCIWnd, the source rectangle is initialized to the same dimensions and position as the initial frame of the video clip.

The destination rectangle is a rectangular area that defines a virtual playback window. The destination rectangle receives the image data from the source rectangle for each frame of the video clip. When the source and destination rectangle dimensions are different, MCIWnd adjusts the image data horizontally and vertically as needed to fill the destination rectangle. When a video clip is loaded with MCIWnd, the destination rectangle is initialized to the same dimensions and position as the initial frame of the video clip.

The playback area is the portion of an MCIWnd window an application uses to display the video clip. The playback area is the client area of an MCIWnd window or the portion of the client area that excludes the MCIWnd toolbar. When a video clip is loaded with MCIWnd, the playback area is initialized to the same dimensions and position as the initial frame of the video clip.

You can crop a video clip by using the MCIWndGetSource and MCIWndPutSource macros to alter the source rectangle. Cropping an image determines only which portion of the frames are displayed during playback; it does not alter the content of the file being played. Before you crop an image, you can retrieve the current size of the source rectangle by using MCIWndGetSource. After the new size and location of the source rectangle are calculated, you can set the cropping boundaries of the source rectangle by using MCIWndPutSource.

You can stretch a video clip by using the MCIWndGetDest and MCIWndPutDest macros to alter the destination rectangle. When you stretch a video clip, you lengthen or shorten the frame size of a video clip vertically, horizontally, or in both directions. Before you stretch an image, you can retrieve the current size and location of the destination rectangle by using MCIWndGetDest. MCIWndPutDest allows you to redefine the destination rectangle. Stretching can distort the image during playback, but it does not alter the content of the file being played.

If the size of the destination rectangle becomes larger than the playback area, you can specify which portion of the playback area will display the video clip by using MCIWndPutDest.

Note  MCIWndPutDest does not change the size of the playback area. To stretch the MCIWnd window along with the destination rectangle, you need to know the current size of the MCIWnd window and issue new window dimensions based on the destination rectangle. You can retrieve the MCIWnd window dimensions by using the GetWindowRect function and resize the MCIWnd window by using the SetWindowPos function.


MCIWnd Palettes

Playing video clips or animations with 8-bit color depth (256-color capacity) requires a palette to define the colors being used. Sometimes, the palette included with a video clip is not the most appropriate palette to use during playback. In this case, MCIWnd provides three ways to manage palettes for playback.

You can retrieve a handle to the palette associated with an MCIWnd window by using the MCIWndGetPalette macro. The palette is not necessarily associated exclusively with the MCIWnd window. Other applications can access, and even invalidate, the palette handle. Consequently, your application should anticipate the global use of the palette and, when finished with the palette, should not free it.

You can also specify a new palette to use with the video clip or animation associated with an MCIWnd window by using the MCIWndSetPalette macro.

Finally, you can realize the palette associated with an MCIWnd window to the system palette by using the MCIWndRealize macro. This macro calls the RealizePalette function with the palette associated with the MCIWnd window. If your application message handlers for WM_PALETTECHANGED and WM_QUERYNEWPALETTE call only RealizePalette or MCIWndRealize, you must forward these messages to MCIWnd if you do not handle them.

Note  When a video clip or animation with 8-bit color depth is loaded into the MCIWnd window, the palette included with that clip replaces the palette associated with the MCIWnd window.


Status Updates

MCIWnd uses timers to periodically update information in the window title bar and scroll bar, and to send notification messages to the parent window. One timer controls the update period of the active MCIWnd window, and a second timer controls the update period for MCIWnd windows that are inactive. Your application can use the MCIWnd timer macros to retrieve the current timer settings and to adjust the update periods.

You can set the update period used by the active window timer by using the MCIWndSetActiveTimer macro. This macro sets the period used by MCIWnd to update the trackbar, to update the position reported in the window title bar, and to notify the parent window that the media has changed. You can retrieve the current update period used by the active window timer by using the MCIWndGetActiveTimer macro. The default update period for the active window timer is 500 milliseconds.

You can set the update period used by the inactive window timer by using the MCIWndSetInactiveTimer macro. This macro sets the period used by MCIWnd to update the trackbar, to update the position reported in the window caption, and to notify the parent window that the media has changed. You can retrieve the current update period used by the inactive window timer by using the MCIWndGetInactiveTimer macro. The default update period for the inactive window timer is 2000 milliseconds.

Your application can simultaneously set the update period for both timers by using the MCIWndSetTimers macro. This macro limits the size of each update period to 16 bits. If a larger quantity for either update period is needed, set the timers individually.


Multiple Document Interface Windows

Applications that use a multiple document interface (MDI) might need to specify window styles that are not available through the MCIWndCreate function. For these applications, you can register and create an MCIWnd window by using the MCIWndRegisterClass function with the CreateWindowEx function. MCIWndRegisterClass registers the MCIWND_WINDOW_CLASS window class and then CreateWindowEx creates an instance of an MCIWnd window.


Error Messages and Notifications

MCIWnd uses MCI to control the devices that play and record multimedia data. In general, MCIWnd displays MCI errors in an error dialog box. An MCI error is generated whenever an MCI command fails. For example, if your application tries to resume paused playback by using the MCIWndResume macro and the current device does not support resume, an error is reported to the user.

MCIWnd allows you two choices for handling error messages: you can prevent error messages from reaching the user, or you can redirect them to your application for display. To prevent the display of MCI error messages, specify the MCIWNDF_NOERRORDLG window style when you create an instance of an MCIWnd window by using the MCIWndCreate or CreateWindowEx function. To redirect MCI error messages to your application, specify the MCIWNDF_NOTIFYERROR window style when you create an instance of an MCIWnd window by using MCIWndCreate or CreateWindowEx.

When error notification is enabled, MCIWnd sends each notification message (MCIWNDM_NOTIFYERROR) to the main message handler of the parent of the MCIWnd window. Your application must have a message handler to process the notification messages it receives.

You can obtain a textual description of the most recent MCI error message by using the MCIWndGetError macro. This macro returns the text in an application-defined buffer. If the error string is longer than the buffer, MCIWnd truncates the string.

You can route all notifications to another window by using the MCIWndSetOwner macro.


Communicating with MCI Devices

The driver of each MCI device maintains a list of its current settings and capabilities, so it can issue an accurate response when it is queried for information. When you want to communicate with an MCI device, you can use MCIWnd macros and functions, or you can send MCI commands directly to the device by using either the message or string form of the commands. For more information about MCI, see Chapter 3, "MCI Overview."

Many of the most common MCI commands and queries are defined as macros; however, if the task you want to perform is unavailable as a function or macro, you can issue MCI commands directly to the device driver by using the MCIWndSendString macro. This macro is equivalent to using the mciSendString function as follows:

mciSendString(sz, Null, 0, Null)

The parameters of MCIWndSendString include only the window handle and the string form of the command. To retrieve the information returned by a string command, use the MCIWndReturnString macro.

Note  You must exclude the device alias from the MCI command when you use MCIWndSendString. The MCIWnd library adds this alias when it sends the command to the MCI device.


Communication with MCI Devices

Each MCI device can have several identifications associated with it that include the following: a device identifier, a device name, an alias, and the filename of the currently loaded content. MCIWnd provides macros you can use to retrieve this information. You can then use this information to communicate through MCI directly with MCI devices associated with MCIWnd windows.

You can retrieve the identifier of the currently open MCI device by using the MCIWndGetDeviceID macro. The MCI device identifier is a numerical value that identifies the instance of the MCI device your application is using. Your application can use this identifier when communicating with an MCI device by using the mciSendCommand function.

To retrieve the name of the currently open MCI device, use the MCIWndGetDevice macro. The MCI device name is a null-terminated string that identifies the device type associated with an MCIWnd window. Your application can use this name when communicating with an MCI device by using mciSendCommand.

You can retrieve the alias of the currently open MCI device by using the MCIWndGetAlias macro. Your application can use this alias when communicating with an MCI device by using the mciSendString function.

Finally, you can retrieve the filename currently used by the MCI device by using the MCIWndGetFileName macro. The filename identifies the content currently associated with an MCIWnd window. Your application can use this filename when communicating with a MCI device by using mciSendCommand or mciSendString.


MCI Device Capabilities

Each MCI device has functions and features that identify how it can be useful. MCIWnd includes the following macros to let you query MCI devices for these capabilities.

Macro	Description
MCIWndCanPlay	Determines whether a device can play the existing content.
MCIWndCanRecord	Determines whether a device can record.
MCIWndCanWindow	Determines whether a device supports MCI window commands (such as window, put and where).
MCIWndCanSave	Determines whether a device can store data.
MCIWndCanEject	Determines whether a device has a software-controlled eject function.
MCIWndCanConfig	Determines whether a device has a configuration dialog box to support multiple configurations, such as the MCIAVI device.
These macros return TRUE if the device supports the specific capability or FALSE otherwise.


Using the MCIWnd Window Class

This section contains examples demonstrating how to perform the following tasks:

•	Create an MCIWnd window.

•	Automate playback.

•	Pause and resume playback.

•	Limit the playback scope.

•	Record with MCIWnd controls.

•	Customize the recording process.

•	Crop an image.

•	Stretch an image.

•	Stretch an image and window.


Creating an MCIWnd Window

The MCIWndCreate function registers and creates an MCIWnd window. The window can be a parent, child, or pop-up window. The following example creates an MCIWnd window as a child window and lets the user control playback by providing access to the trackbar and the Play, Stop, and Menu buttons. The example specifies a handle of a parent window and NULL for the window styles, so the default window styles of WS_CHILD, WS_BORDER, and WS_VISIBLE are used to create the MCIWnd window.

// Global variable and constants

// extern HINSTANCE g_hinst;       instance handle

// extern HWND g_hwndMCIWnd;       MCIWnd window handle

case WM_COMMAND:

    switch (LOWORD(wParam)) {

    case IDM_CREATEMCIWND:

        g_hwndMCIWnd = MCIWndCreate(hwnd, g_hinst, NULL,
            "sample.avi");

        break;

    }

    break;

Note  You could also specify NULL for the parent window handle and for the window styles, in which case the default window styles would be WS_OVERLAPPED and WS_VISIBLE.


Automating Playback

You can automate playback for MCIWnd by specifying a few window styles in the MCIWndCreate function. To play the device, the window needs a parent window to process notification messages, a playback area to play AVI files, and notification of device mode changes to identify when playback stops. The window does not need a toolbar. You can set these characteristics by specifying the appropriate styles in MCIWndCreate.

The following example uses menu commands to create an MCIWnd window to play content from several different types of devices. MCIWndCreate creates the MCIWnd window, and devices and files are loaded by using the MCIWndOpen macro in the device-specific commands. When a device finishes playing, it is closed by trapping the MCIWNDM_NOTIFYMODE message and issuing the MCIWndClose macro.

case WM_COMMAND:

    switch (LOWORD(wParam)) {

    case IDM_CREATEMCIWND:

        	dwMCIWndStyle = WS_CHILD |	// child window
            WS_VISIBLE |	// visible
            MCIWNDF_NOTIFYMODE |	// notifies of mode changes
            MCIWNDF_NOPLAYBAR;	// hides toolbar

        g_hwndMCIWnd = MCIWndCreate(hwnd,
            g_hinst, dwMCIWndStyle, NULL);

        break;

    case IDM_PLAYCDA:

        LoadNGoMCIWnd(hwnd, "CDAudio");

        	break;

    case IDM_PLAYWAVE:

        LoadNGoMCIWnd(hwnd, "SoundWave.WAV");

        break;

    case IDM_PLAYMIDI:

        LoadNGoMCIWnd(hwnd, "MIDIFile.MID");

        break;

    case IDM_PLAYAVI:

        LoadNGoMCIWnd(hwnd, "AVIFile.AVI");

        break;

    case IDM_EXIT:

        MCIWndDestroy(g_hwndMCIWnd);

        DestroyWindow(hwnd);

        break;

}

    break;

case MCIWNDM_NOTIFYMODE:

    if (lParam == MCI_MODE_STOP){        // device stopped

        MessageBox(hwnd,"","Closing Device",MB_OK);

        MCIWndClose(g_hwndMCIWnd);

    }

    break;

.

. // Handle other messages here.

.

// LoadNGoMCIWnd - Automatically loads and plays a multimedia device.

//

// hwnd -  handle to the parent window

// lpstr - pointer to device or filename played by device

//

// Global variable

// extern HINSTANCE g_hwndMCIWnd;  instance handle to MCIWnd window

VOID LoadNGoMCIWnd(HWND hwnd, LPSTR lpstr)

{

    MessageBox(hwnd, lpstr, "Loading Device", MB_OK);

    MCIWndOpen(g_hwndMCIWnd, lpstr, NULL);   // new device in window

    MCIWndPlay(g_hwndMCIWnd);                // plays device

}


Pausing and Resuming Playback

You can interrupt playback of a device or file associated with an MCIWnd window by using the MCIWndPause macro. You can then restart playback by using the MCIWndResume macro. If the device does not support resume or an error occurs, you can use the MCIWndPlay macro to restart playback.

The following example creates an MCIWnd window and plays an AVI file. Pause and resume menu commands are available to the user to interrupt and restart playback.

MCIWnd window styles are changed temporarily by using the MCIWndChangeStyles macro to inhibit an MCI error dialog box from being displayed if MCIWndResume fails.

case WM_COMMAND:

    switch (LOWORD(wParam)) {

        	case IDM_CREATEMCIWND:             // creates and plays clip

            g_hwndMCIWnd = MCIWndCreate(hwnd,
                g_hinst,
                WS_CHILD | WS_VISIBLE |    // standard styles
                MCIWNDF_NOPLAYBAR |        // hides toolbar

                MCIWNDF_NOTIFYMODE,        // notifies of mode changes
                "sample.avi");

            MCIWndPlay(g_hwndMCIWnd);

            break;

        	case IDM_PAUSEMCIWND:              // pauses playback

            MCIWndPause(g_hwndMCIWnd);

            MessageBox(hwnd, "MCIWnd", "Pausing Playback", MB_OK);

            break;

        	case IDM_RESUMEMCIWND:	// resumes playback

            MCIWndChangeStyles(	// hides error dialog messages
                g_hwndMCIWnd,	// MCIWnd window
                MCIWNDF_NOERRORDLG,	// mask of style to change
                MCIWNDF_NOERRORDLG);	// suppresses MCI error dialogs

            lResult = MCIWndResume(g_hwndMCIWnd);

            if(lResult){                   // device doesn't resume

                MessageBox(hwnd, "MCIWnd",
                    "Resume with Stop and Play", MB_OK);

                MCIWndStop(g_hwndMCIWnd);

                MCIWndPlay(g_hwndMCIWnd);

                MCIWndChangeStyles(         // resumes original styles
                    g_hwndMCIWnd,

                    MCIWNDF_NOERRORDLG,
                    NULL);

            }

        break;

    }

break;

.

. // Handle other messages here.

.


Limiting the Playback Scope

Controlling playback begins with the MCIWndPlay macro, which plays the content or file associated with an MCIWnd window from the current position to the end of the content. If you want to limit playback to a specific portion of the content or file, you can choose from the other playback MCIWnd macros: MCIWndPlayFrom, MCIWndPlayTo, and MCIWndPlayFromTo.

You also need to set an appropriate time format. The time format determines whether the content is measured in frames, milliseconds, tracks, or some other units.

The following example creates an MCIWnd window and provides menu commands to play the last third, first third, or middle third of the content. These menu commands use MCIWndPlayFrom, MCIWndPlayTo, and MCIWndPlayFromTo to play the content segments. The example also uses the MCIWndGetStart and MCIWndGetEnd macros to identify the beginning and end of the content, and the MCIWndHome macro to move the playback position to the beginning of the content.

The MCIWndCreate function uses the WS_CAPTION and MCIWNDF_SHOWALL styles in addition to the standard window styles to display the filename, mode, and current position in the title bar of the MCIWnd window.

case WM_COMMAND:

    switch (LOWORD(wParam)) {

    case IDM_CREATEMCIWND:

        g_hwndMCIWnd = MCIWndCreate(hwnd,
            g_hinst,
            WS_CHILD | WS_VISIBLE | WS_CAPTION |

            MCIWNDF_SHOWALL,
            "sample.avi");

        break;

    case IDM_PLAYFROM:                    // plays last third of clip

        MCIWndUseTime(g_hwndMCIWnd);      // millisecond format

        // Get media start and end positions.

        lStart = MCIWndGetStart(g_hwndMCIWnd);

        lEnd = MCIWndGetEnd(g_hwndMCIWnd);

        // Determine playback end position.

        lPlayStart = 2 * (lEnd - lStart) / 3 + lStart;

        MCIWndPlayFrom(g_hwndMCIWnd, lPlayStart);

        break;

    case IDM_PLAYTO:                      // plays first third of clip

        MCIWndUseTime(g_hwndMCIWnd);      // millisecond format

        // Get media start and end positions.

        lStart = MCIWndGetStart(g_hwndMCIWnd);

        lEnd = MCIWndGetEnd(g_hwndMCIWnd);

        // Determine playback start position.

        lPlayEnd = (lEnd - lStart) / 3 + lStart;

        MCIWndHome(g_hwndMCIWnd);

        MCIWndPlayTo(g_hwndMCIWnd, lPlayEnd);

        break;

    case IDM_PLAYSOME:                    // plays middle third of clip

        MCIWndUseTime(g_hwndMCIWnd);      // millisecond format

        // Get media start and end positions.

        lStart = MCIWndGetStart(g_hwndMCIWnd);

        lEnd = MCIWndGetEnd(g_hwndMCIWnd);

        // Determine playback start and end positions.

        lPlayStart = (lEnd - lStart) / 3 + lStart;
        lPlayEnd = 2 * (lEnd - lStart) / 3 + lStart;

        MCIWndPlayFromTo(g_hwndMCIWnd, lPlayStart, lPlayEnd);

        break;

    .

    . // Handle other commands here.

    .

    }


Recording with MCIWnd Controls

The following example records waveform audio using the built-in controls of the MCIWnd window. The example creates an MCIWnd window by using the MCIWNDF_RECORD window style with the MCIWndCreate function to add a Record button to the toolbar. The MCIWndNew macro indicates a new file is associated with the MCIWnd window and that a waveform-audio device will provide its content. A second menu command, IDM_SAVEMCIWND, lets the user save the recording and select a filename by using the MCIWndSaveDialog macro.

case WM_COMMAND:

    switch (LOWORD(wParam)) {

    case IDM_CREATEMCIWND:

        g_hwndMCIWnd = MCIWndCreate(hwnd, g_hinst,

            WS_VISIBLE | MCIWNDF_RECORD, NULL);

        MCIWndNew(g_hwndMCIWnd, "waveaudio");

        break;

    case IDM_SAVEMCIWND:

        MCIWndSaveDialog(g_hwndMCIWnd);

        break;

    }


Customizing the Recording Process

You can customize the recording process, taking complete control of most everything — from creating the MCIWnd window to saving the recorded information in a file. The following example provides a more general case than "Recording with MCIWnd Controls" earlier in this chapter in adding the recording feature to an application. It queries the MCI device for recording and saving capabilities, and includes menu commands to record at the beginning or end of the content.

The following example uses the MCIWndCreate function to create a new window and allows you to specify an existing file to store the recorded data, or it allows you to use an existing window and uses the MCIWndNew, MCIWndOpen, or MCIWndOpenDialog macros to specify a file. Then it uses the MCIWndCanRecord and MCIWndCanSave macros to verify that the device can record and save information. The example then sets the current position by using the MCIWndHome, MCIWndEnd, and MCIWndSeek macros. The MCIWndRecord macro is used to start recording, and the MCIWndStop or the MCIWndPause macro stops recording. After the information is recorded, it is saved by using the MCIWndSave or MCIWndSaveDialog macros.

case WM_COMMAND:

    switch (LOWORD(wParam)) {

    case IDM_CREATEMCIWND:

        g_hwndMCIWnd = MCIWndCreate(hwnd, g_hinst,

            WS_VISIBLE | WS_CHILD |
            MCIWNDF_RECORD,                    // adds Record button
            NULL);

        MCIWndNew(g_hwndMCIWnd, "waveaudio");   // new file

        if (MCIWndCanRecord(g_hwndMCIWnd)) {

            MessageBox(hwnd,

            "Press the red button on the toolbar to start recording.",
            "MCIWnd Record",
            MB_OK);

        }

        else {

            MessageBox(hwnd,

                "This device doesn't record.",

                "MCIWnd Record",
                MB_OK);

        }

            break;

    case IDM_RECORDATSTART:

        if (MCIWndCanRecord(g_hwndMCIWnd)) {

            MCIWndHome(g_hwndMCIWnd);

            MCIWndRecord(g_hwndMCIWnd);

        }

        else {

            MessageBox(hwnd,

                "This device doesn't record.",

                "MCIWnd Record",

                MB_OK);

        }

        break;

    case IDM_RECORDATEND:

        if (MCIWndCanRecord(g_hwndMCIWnd)) {

            MCIWndEnd(g_hwndMCIWnd);

            MCIWndRecord(g_hwndMCIWnd);

        }

        else {

            MessageBox(hwnd,

                "This device doesn't record.",
                "MCIWnd Record",

                MB_OK);

        }

        break;

    case IDM_SAVEMCIWND:

        if (MCIWndCanSave(g_hwndMCIWnd))

            MCIWndSaveDialog(g_hwndMCIWnd);

    }

    break;

    .

    . // Handle other messages here.

    .


Cropping an Image

When you crop an image, you trim one or more edges of the video content from view during playback. Cropping allows you to choose which portions of the content to view without changing the content of the clip.

You can crop one or more edges from a video clip by redefining the dimensions of the source rectangle. The source rectangle overlays each frame in a video clip, encompassing the portion of each image used during playback. Initially, the source rectangle is as large as the video frame size.

The following example creates an MCIWnd window and loads an AVI file. The window includes a crop command in the menu, which crops one-quarter of the height or width off each of the four sides of the frame. The example retrieves the current (initial) dimensions of the source rectangle by using the MCIWndGetSource macro. The modified source rectangle is one-half the original height and width and centered in the original frame. The call to the MCIWndPutSource macro redefines the coordinates of the source rectangle.

// extern RECT rSource, rDest;

case WM_COMMAND:

    switch (LOWORD(wParam)) {

    case IDM_CREATEMCIWND:

        g_hwndMCIWnd = MCIWndCreate(hwnd,

            g_hinst,

            WS_CHILD | WS_VISIBLE,

            "sample.avi");

        break;

    case IDM_CROPIMAGE:                          // crops image

        MCIWndGetSource(g_hwndMCIWnd, &rSource); // source rectangle

        rDest.left = rSource.left +              // new boundaries
            ((rSource.right - rSource.left) / 4);

        rDest.right = rSource.right -
            ((rSource.right - rSource.left) / 4);

        rDest.top = rSource.top +
            ((rSource.bottom - rSource.top) / 4);

        rDest.bottom = rSource.bottom -
            ((rSource.bottom - rSource.top) / 4);

        MCIWndPutSource(g_hwndMCIWnd, &rDest);   // new source rectangle

    }

break;

.

. // Handle other messages here.

.


Stretching an Image

The following example stretches the images of a video clip. It increases the dimensions of the destination rectangle by using the MCIWndPutDest macro. The size of the playback area remains unchanged, so the result is a distorted, zoomed image. MCIWndPutDest is also used to reposition the destination rectangle with respect to the playback area, providing a way to view different portions of the stretched image.

// extern RECT rCurrent, rDest;

case WM_COMMAND:

    switch (LOWORD(wParam)) {

    case IDM_CREATEMCIWND:

        g_hwndMCIWnd = MCIWndCreate(hwnd,

        g_hinst,

        WS_CHILD | WS_VISIBLE,

        "sample.avi");

        break;

    case  IDM_STRETCHIMAGE:          // stretches dest. rectangle 3:2

                                     // leaves playback area same size

        MCIWndGetDest(g_hwndMCIWnd, &rCurrent);  // dest. rectangle

        rDest.top = rCurrent.top;                // new boundaries

        rDest.right = rCurrent.right;

        rDest.left = rCurrent.left +
            ((rCurrent.left - rCurrent.right) * 3);

        rDest.bottom = rCurrent.top +
            ((rCurrent.bottom - rCurrent.top) * 2);

        MCIWndPutDest(g_hwndMCIWnd, &rDest); // new dest. rectangle

        break;

    case IDM_MOVEDOWN:              // moves toward bottom of image

        MCIWndGetDest(g_hwndMCIWnd, &rCurrent); // dest. rectangle

        rCurrent.top -= 100;                    // new boundaries

        rCurrent.bottom -= 100;

        MCIWndPutDest(g_hwndMCIWnd, &rCurrent); // new dest. rectangle

        break;

    case IDM_MOVEUP:                // moves toward top of image

        MCIWndGetDest(g_hwndMCIWnd, &rCurrent); // dest. rectangle

        rCurrent.top += 100;                    // new boundaries

        rCurrent.bottom += 100;

        MCIWndPutDest(g_hwndMCIWnd, &rCurrent); // new dest. rectangle

        break;

    case IDM_MOVELEFT:              // moves toward image left edge

        MCIWndGetDest(g_hwndMCIWnd, &rCurrent); // dest. rectangle

        rCurrent.right += 100;                  // new boundaries

        rCurrent.left += 100;

        MCIWndPutDest(g_hwndMCIWnd, &rCurrent); // new dest. rectangle

        break;

    case  IDM_MOVERIGHT:            // moves toward image right edge

        MCIWndGetDest(g_hwndMCIWnd, &rCurrent); // dest. rectangle

        rCurrent.right -= 100;                  // new boundaries

        rCurrent.left -= 100;

        MCIWndPutDest(g_hwndMCIWnd, &rCurrent); // new dest. rectangle

        break;

    }

break;

.

. // Handle other messages here.

.


Stretching an Image and Window

The following example stretches the images of a video clip and changes the aspect ratio of the displayed frames. The frames displayed in the MCIWnd window are twice the height and three times the width of the original frame. The MCIWndGetDest and MCIWndPutDest macros retrieve and redefine the destination rectangle coordinates. The GetWindowRect and SetWindowPos functions manage changes to the MCIWnd window dimensions.

// extern RECT rCurrent, rDest;

case WM_COMMAND:

    switch (LOWORD(wParam)) {

        	case IDM_CREATEMCIWND:

            g_hwndMCIWnd = MCIWndCreate(hwnd,

        g_hinst,

        WS_CHILD | WS_VISIBLE,

        "sample.avi");

            break;

        case IDM_RESIZEWINDOW:           // stretches dest. rectangle

                                         // and playback area 3:2

            GetWindowRect(g_hwndMCIWnd, &rWin);     // window size

            MCIWndGetDest(g_hwndMCIWnd, &rCurrent); // dest. rectangle

            rDest.top = rCurrent.top;               // new boundaries
            rDest.right = rCurrent.right;

            rDest.left = rCurrent.left +

                ((rCurrent.left - rCurrent.right) * 3);

            rDest.bottom = rCurrent.top +
                ((rCurrent.bottom - rCurrent.top) * 2);

            MCIWndPutDest(g_hwndMCIWnd, &rDest); // new dest. rectangle

            SetWindowPos(g_hwndMCIWnd,           // window being resized

                NULL,                            // z-order: don't care

                0, 0,                            // position: don't care

                rDest.right - rDest.left,        // width

                (rWin.bottom - rWin.top +          // height (window -

                (rCurrent.bottom - rCurrent.top) + // orig dest. rect. +

                (rDest.bottom - rDest.top)),       // new dest. rect.)

                SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);

            break;

        }

    break;

    .

    . // Handle other messages here.

    .


MCIWnd Reference

This section describes the functions, messages, macros, and notifications associated with the MCIWnd window class. These elements are grouped as follows.

Window Management

MCIWndChangeStyles
MCIWndCreate
MCIWndGetStyles
MCIWndRegisterClass

File and Device Management

MCIWndClose
MCIWndDestroy
MCIWndEject
MCIWndNew
MCIWndOpen
MCIWndOpenDialog
MCIWndSave
MCIWndSaveDialog

Playback Options

MCIWndGetRepeat
MCIWndPlay
MCIWndPlayFrom
MCIWndPlayFromTo
MCIWndPlayReverse
MCIWndPlayTo
MCIWndSetRepeat

Recording

MCIWndRecord

Positioning

MCIWndEnd
MCIWndGetEnd
MCIWndGetLength
MCIWndGetPosition
MCIWndGetPositionString
MCIWndGetStart
MCIWndHome
MCIWndSeek
MCIWndStep

Pause and Resume Playback

MCIWndGetRepeat
MCIWndPlay
MCIWndPlayFrom
MCIWndPlayFromTo
MCIWndPlayReverse
MCIWndPlayTo
MCIWndSetRepeat

Performance Tuning

MCIWndGetSpeed
MCIWndGetVolume
MCIWndGetZoom
MCIWndSetSpeed
MCIWndSetVolume
MCIWndSetZoom

Image and Palette Adjustments

MCIWndGetDest
MCIWndGetPalette
MCIWndGetSource
MCIWndPutDest
MCIWndPutSource
MCIWndRealize
MCIWndSetPalette

Event and Error Notification

MCIWndGetError
MCIWNDM_NOTIFYERROR
MCIWNDM_NOTIFYMEDIA
MCIWNDM_NOTIFYMODE
MCIWNDM_NOTIFYPOS
MCIWNDM_NOTIFYSIZE

Time Formats

MCIWndGetTimeFormat
MCIWndSetTimeFormat
MCIWndUseFrames
MCIWndUseTime
MCIWndValidateMedia

Status Updates

MCIWndGetActiveTimer
MCIWndGetInactiveTimer
MCIWndSetActiveTimer
MCIWndSetInactiveTimer
MCIWndSetTimers

Device Capabilities

MCIWndCanConfig
MCIWndCanEject
MCIWndCanPlay
MCIWndCanRecord
MCIWndCanSave
MCIWndCanWindow

MCI Device Settings

MCIWndGetAlias
MCIWndGetDevice
MCIWndGetDeviceID
MCIWndGetFileName
MCIWndGetMode

MCI Command-String Interface

MCIWndReturnString
MCIWndSendString


MCIWnd Functions

An application uses the MCIWnd functions to register the MCIWnd window class or to register and create an MCIWnd window. An MCIWnd window can use standard window styles as well as a set of MCIWnd-specific styles.


GetOpenFileNamePreview

BOOL GetOpenFileNamePreview(LPOPENFILENAME lpofn);

Selects a file by using the Open dialog box. The dialog box also allows the user to preview the currently specified AVI file. This function augments the capability found in the GetOpenFileName function.

•	Returns a handle of the selected file.

lpofn

Address of an OPENFILENAME structure used to initialize the dialog box. On return, the structure contains information about the user's file selection.


GetSaveFileNamePreview

BOOL GetSaveFileNamePreview(LPOPENFILENAME lpofn);

Selects a file by using the SaveAs dialog box. The dialog box also allows the user to preview the currently specified file. This function augments the capability found in the GetSaveFileName function.

•	Returns a handle of the selected file.

lpofn

Address of an OPENFILENAME structure used to initialize the dialog box. On return, the structure contains information about the user's file selection.


MCIWndCreate

HWND MCIWndCreate(HWND hwndParent, HINSTANCE hInstance, DWORD dwStyle,
    LPSTR szFile);

Registers the MCIWnd window class and creates an MCIWnd window for using MCI services. MCIWndCreate can also open an MCI device or file (such as an AVI file) and associate it with the MCIWnd window.

•	Returns a handle of an MCIWnd window if successful or zero otherwise.

hwndParent

Handle of the parent window.

hInstance

Handle of the module instance to associate with the MCIWnd window.

dwStyle

Flags defining the window style. In addition to specifying the window styles used with the CreateWindowEx function, you can specify the following styles to use with MCIWnd windows:

MCIWNDF_NOAUTOSIZEWINDOW

Will not change the dimensions of an MCIWnd window when the image size changes.

MCIWNDF_NOAUTOSIZEMOVIE

Will not change the dimensions of the destination rectangle when an MCIWnd window size changes.

MCIWNDF_NOERRORDLG

Inhibits display of MCI errors to users.

MCIWNDF_NOMENU

Hides the Menu button from view on the toolbar and prohibits users from accessing its pop-up menu.

MCIWNDF_NOOPEN

Hides the open and close commands from the MCIWnd menu and prohibits users from accessing these choices in the pop-up menu.

MCIWNDF_NOPLAYBAR

Hides the toolbar from view and prohibits users from accessing it.

MCIWNDF_NOTIFYANSI

Causes MCIWnd to use an ANSI string instead of a Unicode string when notifying the parent window of device mode changes. This flag is used in combination with MCIWNDF_NOTIFYMODE and is exclusive to Windows NT.

MCIWNDF_NOTIFYMODE

Causes MCIWnd to notify the parent window with an MCIWNDM_NOTIFYMODE message whenever the device changes operating modes. The lParam parameter of this message identifies the new mode, such as MCI_MODE_STOP.

MCIWNDF_NOTIFYPOS

Causes MCIWnd to notify the parent window with an MCIWNDM_NOTIFYPOS message whenever a change in the playback or record position within the content occurs. The lParam parameter of this message contains the new position in the content.

MCIWNDF_NOTIFYMEDIA

Causes MCIWnd to notify the parent window with an MCIWNDM_NOTIFYMEDIA message whenever a new device is used or a data file is opened or closed. The lParam parameter of this message contains a pointer to the new filename.

MCIWNDF_NOTIFYSIZE

Causes MCIWnd to notify the parent window when the MCIWnd window size changes.

MCIWNDF_NOTIFYERROR

Causes MCIWnd to notify the parent window when an MCI error occurs.

MCIWNDF_NOTIFYALL

Causes all MCIWNDF window notification styles to be used.

MCIWNDF_RECORD

Adds a Record button to the toolbar and adds a new file command to the menu if the MCI device has recording capability.

MCIWNDF_SHOWALL

Causes all MCIWNDF_SHOW styles to be used.

MCIWNDF_SHOWMODE

Displays the current mode of the MCI device in the window title bar. For a list of device modes, see the MCIWndGetMode macro.

MCIWNDF_SHOWNAME

Displays the name of the open MCI device or data file in the MCIWnd window title bar.

MCIWNDF_SHOWPOS

Displays the current position within the content of the MCI device in the window title bar.

szFile

Null-terminated string indicating the name of an MCI device or data file to open.

Default window styles for a child window are WS_CHILD, WS_BORDER, and WS_VISIBLE. MCIWndCreate assumes a child window when a non-NULL handle of a parent window is specified.

Default window styles for a parent window are WS_OVERLAPPEDWINDOW and WS_VISIBLE. MCIWndCreate assumes a parent window when a NULL handle of a parent window is specified.

Use the window handle returned by this function for the window handle in the MCIWnd macros. If your application uses this function, it does not need to use the MCIWndRegisterClass function.


MCIWndRegisterClass

BOOL MCIWndRegisterClass(HINSTANCE hInstance);

Registers the MCI window class MCIWND_WINDOW_CLASS.

•	Returns zero if successful.

hInstance

Handle of the device instance.

After registering the MCI window class, use the CreateWindow or CreateWindowEx functions to create an MCIWnd window. If your application uses this function, it does not need to use the MCIWndCreate function.


MCIWnd Macros and Messages

Applications use messages to communicate with MCIWnd windows and MCI devices associated with these windows. MCIWnd macros provide a shorthand method of sending these messages. The macros are based on the SendMessage function. Definitions of the macros identify the corresponding messages that are sent to MCIWnd windows.

You can control properties and behavior of MCIWnd windows by using the following macros and messages.


MCIWndCanConfig

BOOL MCIWndCanConfig(hwnd)

// Corresponding message

MCIWNDM_CAN_CONFIG

wParam = 0;

lParam = 0;

Determines if an MCI device can display a configuration dialog box.

•	Returns TRUE if the device supports configuration or FALSE otherwise.

hwnd

Handle of the MCIWnd window.


MCIWndCanEject

BOOL MCIWndCanEject(hwnd)

// Corresponding message

MCIWNDM_CAN_EJECT

wParam = 0;

lParam = 0;

Determines if an MCI device can eject its media.

•	Returns TRUE if the device can eject its media or FALSE otherwise.

hwnd

Handle of the MCIWnd window.


MCIWndCanPlay

BOOL MCIWndCanPlay(hwnd)

// Corresponding message

MCIWNDM_CAN_PLAY

wParam = 0;

lParam = 0;

Determines if an MCI device can play a data file or content of some other kind.

•	Returns TRUE if the device supports playing the data or FALSE otherwise.

hwnd

Handle of the MCIWnd window.


MCIWndCanRecord

BOOL MCIWndCanRecord(hwnd)

// Corresponding message

MCIWNDM_CAN_RECORD

wParam = 0;

lParam = 0;

Determines if an MCI device supports recording.

•	Returns TRUE if the device supports recording or FALSE otherwise.

hwnd

Handle of the MCIWnd window.


MCIWndCanSave

BOOL MCIWndCanSave(hwnd)

// Corresponding message

MCIWNDM_CAN_SAVE

wParam = 0;

lParam = 0;

Determines if an MCI device can save data.

•	Returns TRUE if the device supports saving data or FALSE otherwise.

hwnd

Handle of the MCIWnd window.


MCIWndCanWindow

BOOL MCIWndCanWindow(hwnd)

// Corresponding message

MCIWNDM_CAN_WINDOW

wParam = 0;

lParam = 0;

Determines if an MCI device supports window-oriented MCI commands.

•	Returns TRUE if the device supports window-oriented MCI commands or FALSE otherwise.

hwnd

Handle of the MCIWnd window.


MCIWndChangeStyles

LONG MCIWndChangeStyles(hwnd, mask, value)

// Corresponding message

MCIWNDM_CHANGESTYLES

wParam = (WPARAM) (UINT) mask;

lParam = (LPARAM) (LONG) value;

Changes the styles used by the MCIWnd window.

•	Returns zero.

hwnd

Handle of the MCIWnd window.

mask

Mask that identifies the styles that can change. This mask is the bitwise OR operator of all styles that will be permitted to change.

value

New style settings for the window. Specify zero for this parameter to turn off all styles identified in the mask. For a list of the available styles, see the MCIWndCreate function.

For an example of using MCIWndChangeStyles, see "Pausing and Resuming Playback" earlier in this chapter.


MCIWndClose

LONG MCIWndClose(hwnd)

// Corresponding command

MCI_CLOSE

wParam = 0;

lParam = 0;

Closes an MCI device or file associated with an MCIWnd window. Although the MCI device closes, the MCIWnd window is still open and can be associated with another MCI device.

•	Returns zero.

hwnd

Handle of the MCIWnd window.


MCIWndDestroy

VOID MCIWndDestroy(hwnd)

// Corresponding message

WM_CLOSE

wParam = 0;

lParam = 0;

Closes an MCI device or file associated with an MCIWnd window and destroys the window.

•	No return value.

hwnd

Handle of the MCIWnd window.


MCIWndEject

LONG MCIWndEject(hwnd)

// Corresponding message

MCIWNDM_EJECT

wParam = 0;

lParam = 0;

Sends a command to an MCI device to eject its media.

•	Returns zero if successful or an error otherwise.

hwnd

Handle of the MCIWnd window.


MCIWndEnd

LONG MCIWndEnd(hwnd)

// Corresponding command

MCI_SEEK

wParam = 0;

lParam = (LPARAM) (LONG) MCIWND_END;

Moves the current position to the end of the content.

•	Returns zero if successful or an error otherwise.

hwnd

Handle of the MCIWnd window.


MCIWndGetActiveTimer

UINT MCIWndGetActiveTimer(hwnd)

// Corresponding message

MCIWNDM_GETACTIVETIMER

wParam = 0;

lParam = 0L;

Retrieves the update period used when the MCIWnd window is the active window.

•	Returns the update period in milliseconds. The default is 500 milliseconds.

hwnd

Handle of the MCIWnd window.


MCIWndGetAlias

UINT MCIWndGetAlias(hwnd)

// Corresponding message

MCIWNDM_GETALIAS

wParam = 0;

lParam = 0;

Retrieves the alias used to open an MCI device or file with the mciSendString function.

•	Returns the device alias.

hwnd

Handle of the MCIWnd window.


MCIWndGetDest

LONG MCIWndGetDest(hwnd, prc)

// Corresponding message

MCIWNDM_GET_DEST

wParam = 0;

lParam = (LPARAM) (LPRECT) prc;

Retrieves the coordinates of the destination rectangle used for zooming or stretching the images of an AVI file during playback.

•	Returns zero if successful or an error otherwise.

hwnd

Handle of the MCIWnd window.

prc

Address of a RECT structure to return the coordinates of the destination rectangle.


MCIWndGetDevice

LONG MCIWndGetDevice(hwnd, lp, len)

// Corresponding message

MCIWNDM_GETDEVICE

wParam = (WPARAM) (UINT) len;

lParam = (LPARAM) (LPVOID) lp;

Retrieves the name of the currently open MCI device.

•	Returns zero if successful or a nonzero value otherwise.

hwnd

Handle of the MCIWnd window.

lp

Address of an application-defined buffer to return the device name.

len

Size, in bytes, of the buffer.

If the null-terminated string containing the device name is longer than the buffer, MCIWnd truncates it.


MCIWndGetDeviceID

UINT MCIWndGetDeviceID(hwnd)

// Corresponding message

MCIWNDM_GETDEVICEID

wParam = 0;

lParam = 0;

Retrieves the identifier of the currently open MCI device to use with the mciSendCommand function.

•	Returns the device identifier.

hwnd

Handle of the MCIWnd window.


MCIWndGetEnd

LONG MCIWndGetEnd(hwnd)

// Corresponding message

MCIWNDM_GETEND

wParam = 0;

lParam = 0;

Retrieves the location of the end of the content of an MCI device or file.

•	Returns the location in the current time format.

hwnd

Handle of the MCIWnd window.


MCIWndGetError

LONG MCIWndGetError(hwnd, lp, len)

// Corresponding message

MCIWNDM_GETERROR

wParam = (WPARAM) (UINT) len;

lParam = (LPARAM) (LPVOID) lp;

Retrieves the last MCI error encountered.

•	Returns the integer error value if successful.

hwnd

Handle of the MCIWnd window.

lp

Address of an application-defined buffer used to return the error string.

len

Size, in bytes, of the error buffer.

If lp is a valid pointer, a null-terminated string corresponding to the error is returned in its buffer. If the error string is longer than the buffer, MCIWnd truncates it.


MCIWndGetFileName

LONG MCIWndGetFileName(hwnd, lp, len)

// Corresponding message

MCIWNDM_GETFILENAME

wParam = (WPARAM) (UINT) len;

lParam = (LPARAM) (LPVOID) lp;

Retrieves the filename currently used by an MCI device.

•	Returns 0 if successful or 1 otherwise.

hwnd

Handle of the MCIWnd window.

lp

Address of an application-defined buffer to return the filename.

len

Size, in bytes, of the buffer.

If the null-terminated string containing the filename is longer than the buffer, MCIWnd truncates the filename.


MCIWndGetInactiveTimer

UINT MCIWndGetInactiveTimer(hwnd)

// Corresponding message

MCIWNDM_GETINACTIVETIMER

wParam = 0;

lParam = 0L;

Retrieves the update period used when the MCIWnd window is the inactive window.

•	Returns the update period, in milliseconds. The default value is 2000 milliseconds.

hwnd

Handle of the MCIWnd window.


MCIWndGetLength

LONG MCIWndGetLength(hwnd)

// Corresponding message

MCIWNDM_GETLENGTH

wParam = 0;

lParam = 0;

Retrieves the length of the content or file currently used by an MCI device.

•	Returns the length. The units for the length depend on the current time format.

hwnd

Handle of the MCIWnd window.

This value added to the value returned for the MCIWndGetStart macro equals the end of the content.


MCIWndGetMode

LONG MCIWndGetMode(hwnd, lp, len)

// Corresponding message

MCIWNDM_GETMODE

wParam = (WPARAM) (UINT) len;

lParam = (LPARAM) (LPSTR) lp;

Retrieves the current operating mode of an MCI device. MCI devices have several operating modes, which are designated by constants.

•	Returns an integer corresponding to the MCI constant defining the mode.

hwnd

Handle of the MCIWnd window.

lp

Address of the application-defined buffer used to return the mode.

len

Size, in bytes, of the buffer.

If the null-terminated string describing the mode is longer than the buffer, it is truncated.

Not all devices can operate in every mode. For example, the MCIAVI device is a playback device; it doesn't support the recording mode. The following modes can be retrieved by using MCIWNDM_GETMODE:

Operating mode	MCI constant
not ready	MCI_MODE_NOT_READY
open	MCI_MODE_OPEN
paused	MCI_MODE_PAUSE
playing	MCI_MODE_PLAY
recording	MCI_MODE_RECORD
seeking	MCI_MODE_SEEK
stopped	MCI_MODE_STOP


MCIWndGetPalette

HPALETTE MCIWndGetPalette(hwnd)

// Corresponding message

MCIWNDM_GETPALETTE

wParam = 0;

lParam = 0;

Retrieves a handle of the palette used by an MCI device.

•	Returns the handle of the palette if successful.

hwnd

Handle of the MCIWnd window.


MCIWndGetPosition

LONG MCIWndGetPosition(hwnd)

// Corresponding messages

MCIWNDM_GETPOSITION

wParam = 0;

lParam = 0;

Retrieves the numerical value of the current position within the content of the MCI device.

•	Returns an integer corresponding to the current position. The units for the position value depend on the current time format.

hwnd

Handle of the MCIWnd window.


MCIWndGetPositionString

LONG MCIWndGetPositionString(hwnd, lp, len)

// Corresponding messages

MCIWNDM_GETPOSITION

wParam = (WPARAM) (UINT) len;

lParam = (LPARAM) (LPTSTR) lp;

Retrieves the numerical value of the current position within the content of the MCI device. This macro also provides the current position in string form in an application-defined buffer.

•	Returns an integer corresponding to the current position. The units for the position value depend on the current time format.

hwnd

Handle of the MCIWnd window.

lp

Address of an application-defined buffer used to return the position. Use zero to inhibit retrieval of the position as a string.

If the device supports tracks, the string position information is returned in the form TT:MM:SS:FF where TT corresponds to tracks, MM and SS correspond to minutes and seconds, and FF corresponds to frames.

len

Size, in bytes, of the buffer. If the null-terminated string is longer than the buffer, it is truncated. Use zero to inhibit retrieval of the position as a string.


MCIWndGetRepeat

BOOL MCIWndGetRepeat(hwnd)

// Corresponding message

MCIWNDM_GETREPEAT

wParam = 0;

lParam = 0;

Determines if continuous playback has been activated.

•	Returns TRUE if continuous playback is activated or FALSE otherwise.

hwnd

Handle of the MCIWnd window.


MCIWndGetSource

LONG MCIWndGetSource(hwnd, prc)

// Corresponding message

MCIWNDM_GET_SOURCE

wParam = 0;

lParam = (LPARAM) (LPRECT) prc;

Retrieves the coordinates of the source rectangle used for cropping the images of an AVI file during playback.

•	Returns zero if successful or an error otherwise.

hwnd

Handle of the MCIWnd window.

prc

Address of a RECT structure to contain the coordinates of the source rectangle.


MCIWndGetSpeed

LONG MCIWndGetSpeed(hwnd)

// Corresponding message

MCIWNDM_GETSPEED

wParam = 0;

lParam = 0;

Retrieves the playback speed of an MCI device.

•	Returns the playback speed if successful. The value for normal speed is 1000. Larger values indicate faster speeds; smaller values indicate slower speeds.

hwnd

Handle of the MCIWnd window.


MCIWndGetStart

LONG MCIWndGetStart(hwnd)

// Corresponding message

MCIWNDM_GETSTART

wParam = 0;

lParam = 0;

Retrieves the location of the beginning of the content of an MCI device or file.

•	Returns the location in the current time format.

hwnd

Handle of the MCIWnd window.

Typically, the return value is zero; but some devices use a nonzero starting location. Seeking to this location sets the device to the start of the media.


MCIWndGetStyles

UINT MCIWndGetStyles(hwnd)

// Corresponding message

MCIWNDM_GETSTYLES

wParam = 0;

lParam = 0;

Retrieves the flags specifying the current MCIWnd window styles used by a window.

•	Returns a value representing the current styles of the MCIWnd window. The return value is the bitwise OR operator of the MCIWnd window styles (MCIWNDF flags).

hwnd

Handle of the MCIWnd window.


MCIWndGetTimeFormat

LONG MCIWndGetTimeFormat(hwnd, lp, len)

// Corresponding message

MCIWNDM_GETTIMEFORMAT

wParam = (WPARAM) (UINT) len;

lParam = (LPARAM) (LPSTR) lp;

Retrieves the current time format of an MCI device in two forms: as a numerical value and as a string.

•	Returns an integer corresponding to the MCI constant defining the time format.

hwnd

Handle of the MCIWnd window.

lp

Address of a buffer to contain the null-terminated string form of the time format.

len

Size, in bytes, of the buffer.

If the time format string is longer than the return buffer, MCIWnd truncates the string.

An MCI device can support one or more of the following time formats:

Time format	MCI constant
Bytes	MCI_FORMAT_BYTES
Frames	MCI_FORMAT_FRAMES
Hours, minutes, seconds	MCI_FORMAT_HMS
Milliseconds	MCI_FORMAT_MILLISECONDS
Minutes, seconds, frames	MCI_FORMAT_MSF
Samples	MCI_FORMAT_SAMPLES
SMPTE 24	MCI_FORMAT_SMPTE_24
SMPTE 25	MCI_FORMAT_SMPTE_25
SMPTE 30 drop	MCI_FORMAT_SMPTE_30DROP
SMPTE 30 (non-drop)	MCI_FORMAT_SMPTE_30
Tracks, minutes, seconds, frames	MCI_FORMAT_TMSF


MCIWndGetVolume

LONG MCIWndGetVolume(hwnd)

// Corresponding message

MCIWNDM_GETVOLUME

wParam = 0;

lParam = 0;

Retrieves the current volume setting of an MCI device.

•	Returns the current volume setting. The default value is 1000. Higher values indicate louder volumes; lower values indicate quieter volumes.

hwnd

Handle of the MCIWnd window.


MCIWndGetZoom

UINT MCIWndGetZoom(hwnd)

// Corresponding message

MCIWNDM_GETZOOM

wParam = 0;

lParam = 0;

Retrieves the current zoom value used by an MCI device.

•	Returns the most recent values used with MCIWndSetZoom.

hwnd

Handle of the MCIWnd window.

A return value of 100 indicates the image is not zoomed. A value of 200 indicates the image is enlarged to twice its original size. A value of 50 indicates the image is reduced to half its original size.


MCIWndHome

LONG MCIWndHome(hwnd)

// Corresponding command

MCI_SEEK

wParam = 0;

lParam = (LPARAM) (LONG) MCIWND_START;

Moves the current position to the beginning of the content.

•	Returns zero if successful or an error otherwise.

hwnd

Handle of the MCIWnd window.


MCIWndNew

LONG MCIWndNew(hwnd, lp)

// Corresponding message

MCIWNDM_NEW

wParam = 0;

lParam = (LPARAM) (LPVOID) lp;

Creates a new file for the current MCI device.

•	Returns zero if successful or an error otherwise.

hwnd

Handle of the MCIWnd window.

lp

Address of a buffer containing the name of the MCI device that will use the file.


MCIWndOpen

LONG MCIWndOpen(hwnd, szFile, wFlags)

// Corresponding message

MCIWNDM_OPEN

wParam = (WPARAM) (UINT) wFlags;

lParam = (LPARAM) (LPVOID) szFile;

Opens an MCI device and associates it with an MCIWnd window. For MCI devices that use data files, this macro can also open a specified data file, name a new file to be created, or display a dialog box to let the user select a file to open.

•	Returns zero if successful or an error otherwise.

hwnd

Handle of the MCIWnd window.

szFile

Address of a null-terminated string identifying the filename or MCI device name to open. Specify −1 for this parameter to display the Open dialog box.

wFlags

Flags associated with the device or file to open. The MCIWNDOPENF_NEW flag specifies a new file is to be created with the name specified in szFile.


MCIWndOpenDialog

LONG MCIWndOpenDialog(hwnd)

// Corresponding command

MCI_OPEN

wParam = -1;

lParam = 0;

Opens a user-specified data file and corresponding type of MCI device, and associates them with an MCIWnd window. This macro displays the Open dialog box for the user to select the data file to associate with an MCI window.

•	Returns zero if successful or an error otherwise.

hwnd

Handle of the MCIWnd window.


MCIWndOpenInterface

MCIWndOpenInterface(hwnd, pUnk)

// Corresponding message

MCIWNDM_OPENINTERFACE

wParam = 0;

lParam = (LPARAM) (LPUNKNOWN) pUnk;

Attaches the data stream or file associated with the specified interface to an MCIWnd window.

•	Returns zero if successful or an error otherwise.

hwnd

Handle of the MCIWnd window.

pUnk

Address of an IAVI interface that points to a file or a data stream in a file.

For information about IAVI interfaces, see Chapter 6, "AVIFile Functions and Macros ."


MCIWndPause

LONG MCIWndPause(hwnd)

// Corresponding command

MCI_PAUSE

wParam = 0;

lParam = 0;

Sends a command to an MCI device to pause playing or recording.

•	Returns zero if successful or an error otherwise.

hwnd

Handle of the MCIWnd window.


MCIWndPlay

LONG MCIWndPlay(hwnd)

// Corresponding command

MCI_PLAY

wParam = 0;

lParam = 0;

Sends a command to an MCI device to start playing from the current position in the content.

•	Returns zero if successful or an error otherwise.

hwnd

Handle of the MCIWnd window.


MCIWndPlayFrom

LONG MCIWndPlayFrom(hwnd, lPos)

// Corresponding message

MCIWNDM_PLAYFROM

wParam = 0;

lParam = (LPARAM) (LONG) lPos;

Plays the content of an MCI device from the specified location to the end of the content or until another command stops playback.

•	Returns zero if successful or an error otherwise.

hwnd

Handle of the MCIWnd window.

lPos

Starting location. The units for the starting location depend on the current time format.

You can also specify both a starting and ending location for playback by using the MCIWndPlayFromTo macro.


MCIWndPlayFromTo

LONG MCIWndPlayFromTo(hwnd, lStart, lEnd)

// Corresponding command and message

MCI_SEEK

wParam = 0;

lParam = (LPARAM) (LONG) lStart;

MCIWNDM_PLAYTO

wParam = 0;

lParam = (LPARAM) (LONG) lEnd;

Plays a portion of content between specified starting and ending locations. This macro seeks to the specified point to begin playback, then plays the content to the specified ending location. This macro is defined using the MCIWndSeek and MCIWndPlayTo macros, which in turn use the MCI_SEEK command and the MCIWNDM_PLAYTO message.

•	Returns zero if successful or an error otherwise.

hwnd

Handle of the MCIWnd window.

lStart

Position to seek; it is also the starting location.

lEnd

Ending location.

The units for the seek position depend on the current time format.


MCIWndPlayReverse

LONG MCIWndPlayReverse(hwnd)

// Corresponding message

MCIWNDM_PLAYREVERSE

wParam = 0;

lParam = 0;

Plays the current content in the reverse direction, beginning at the current position and ending at the beginning of the content or until another command stops playback.

•	Returns zero if successful or an error otherwise.

hwnd

Handle of the MCIWnd window.


MCIWndPlayTo

LONG MCIWndPlayTo(hwnd, lPos)

// Corresponding message

MCIWNDM_PLAYTO

wParam = 0;

lParam = (LPARAM) (LONG) lPos;

Plays the content of an MCI device from the current position to the specified ending location or until another command stops playback. If the specified ending location is beyond the end of the content, playback stops at the end of the content.

•	Returns zero if successful or an error otherwise.

hwnd

Handle of the MCIWnd window.

lPos

Ending location. The units for the ending location depend on the current time format.

You can also specify both a starting and ending location for playback by using the MCIWndPlayFromTo macro.


MCIWndPutDest

LONG MCIWndPutDest(hwnd, prc)

// Corresponding message

MCIWNDM_PUT_DEST

wParam = 0;

lParam = (LPARAM) (LPRECT) prc;

Redefines the coordinates of the destination rectangle used for zooming or stretching the images of an AVI file during playback.

•	Returns zero if successful or an error otherwise.

hwnd

Handle of the MCIWnd window.

prc

Address of a RECT structure containing the coordinates of the destination rectangle.


MCIWndPutSource

LONG MCIWndPutSource(hwnd, prc)

// Corresponding message

MCIWNDM_PUT_SOURCE

wParam = 0;

lParam = (LPARAM) (LPRECT) prc;

Redefines the coordinates of the source rectangle used for cropping the images of an AVI file during playback.

•	Returns zero if successful or an error otherwise.

hwnd

Handle of the MCIWnd window.

prc

Address of a RECT structure containing the coordinates of the source rectangle.


MCIWndRealize

LONG MCIWndRealize(hwnd, fBkgnd)

// Corresponding message

MCIWNDM_REALIZE

wParam = (WPARAM) (BOOL) fBkgnd;

lParam = 0;

Realizes the palette currently used by the MCI device in an MCIWnd window. This macro is defined with the MCIWNDM_REALIZE message.

•	Returns zero if successful or an error otherwise.

hwnd

Handle of the MCIWnd window.

fBkgnd

Background flag. Specify TRUE for this parameter if the window is a background application.

MCIWNDM_REALIZE uses the palette of the MCI device and calls the RealizePalette function. If your application explicitly handles the WM_PALETTECHANGED and WM_QUERYNEWPALETTE messages, you should use this message in your application instead of using RealizePalette. If the body of one of these message handlers contains only RealizePalette, forward the message to the MCIWnd window, which will automatically realize the palette.


MCIWndRecord

LONG MCIWndRecord(hwnd)

// Corresponding command

MCI_RECORD

wParam = 0;

lParam = 0;

Begins recording content using the MCI device. The recording process begins at the current position in the content and will overwrite existing data for the duration of the recording.

•	Returns zero if successful or an error otherwise.

hwnd

Handle of the MCIWnd window.

The function that an MCI device performs during recording depends on the characteristics of the device. An MCI device that uses files, such as a waveform-audio device, sends data to the file during recording. An MCI device that does not use files, such as a video-cassette recorder, receives and externally records data on another medium.


MCIWndResume

LONG MCIWndResume(hwnd)

// Corresponding command

MCI_RESUME

wParam = 0;

lParam = 0;

Resumes playback or recording content from the paused mode. This macro restarts playback or recording from the current position in the content.

•	Returns zero if successful or an error otherwise.

hwnd

Handle of the MCIWnd window.


MCIWndReturnString

LONG MCIWndReturnString(hwnd, lp, len)

// Corresponding message

MCIWNDM_RETURNSTRING

wParam = (WPARAM) (UINT) len;

lParam = (LPARAM) (LPVOID) lp;

Retrieves the reply to the most recent MCI string command sent to an MCI device. Information in the reply is supplied as a null-terminated string.

•	Returns an integer corresponding to the MCI string.

hwnd

Handle of the MCIWnd window.

lp

Address of an application-defined buffer to contain the null-terminated string.

len

Size, in bytes, of the buffer.

If the null-terminated string is longer than the buffer, the string is truncated.


MCIWndSave

LONG MCIWndSave(hwnd, szFile)

// Corresponding command

MCI_SAVE

wParam = 0;

lParam = (LPARAM) (LPVOID) szFile;

Saves the content currently used by an MCI device. This macro can save the content to a specified data file or display the Save dialog box to let the user select a filename to store the content.

•	Returns zero if successful or an error otherwise.

hwnd

Handle of the MCIWnd window.

szFile

Null-terminated string containing the name and path of the destination file. Specify  − 1 for this parameter to display the Save dialog box.


MCIWndSaveDialog

LONG MCIWndSaveDialog(hwnd)

// Corresponding command

MCI_SAVE

wParam = 0;

lParam = -1;

Saves the content currently used by an MCI device. This macro displays the Save dialog box to let the user select a filename to store the content.

•	Returns zero if successful or an error otherwise.

hwnd

Handle of the MCIWnd window.


MCIWndSeek

LONG MCIWndSeek(hwnd, lPos)

// Corresponding command

MCI_SEEK

wParam = 0;

lParam = (LPARAM) (LONG) lPos;

Moves the playback position to the specified location in the content.

•	Returns zero if successful or an error otherwise.

hwnd

Handle of the MCIWnd window.

lPos

Position to seek. You can specify a position using the current time format, the MCIWND_START constant to designate the beginning of the content, or the MCIWND_END constant to designate the end of the content.


MCIWndSendString

LONG MCIWndSendString(hwnd, sz)

// Corresponding message

MCIWNDM_SENDSTRING

wParam = 0;

lParam = (LPARAM) (LPSTR) sz;

Sends an MCI command in string form to the device associated with the MCIWnd window.

•	Returns zero if successful or an error otherwise.

hwnd

Handle of the MCIWnd window.

sz

String command to send to the MCI device.

The message handler for MCIWndSendString (and MCIWNDM_SENDSTRING) appends a device alias to the MCI command you send to the device. Therefore, you should not use any alias in an MCI command that you issue with MCIWndSendString.

For more information about MCI string commands, see Chapter 4, "MCI Command Strings."


MCIWndSetActiveTimer

VOID MCIWndSetActiveTimer(hwnd, active)

// Corresponding message

MCIWNDM_SETACTIVETIMER

wParam = (WPARAM) (UINT) active;

lParam = 0L;

Sets the update period used by MCIWnd to update the trackbar in the MCIWnd window, update position information displayed in the window title bar, and send notification messages to the parent window when the MCIWnd window is active.

•	No return value.

hwnd

Handle of the MCIWnd window.

active

Update period, in milliseconds. The default is 500 milliseconds.


MCIWndSetInactiveTimer

VOID MCIWndSetInactiveTimer(hwnd, inactive)

// Corresponding message

MCIWNDM_SETINACTIVETIMER

wParam = (WPARAM) (UINT) inactive;

lParam = 0;

Sets the update period used by MCIWnd to update the trackbar in the MCIWnd window, update position information displayed in the window title bar, and send notification messages to the parent window when the MCIWnd window is inactive.

•	No return value.

hwnd

Handle of the MCIWnd window.

inactive

Update period, in milliseconds. The default is 2000 milliseconds.


MCIWndSetOwner

LONG MCIWndSetOwner(hwnd, hwndP)

// Corresponding message

MCIWNDM_SETOWNER

wParam = (WPARAM) hwndP;

lParam = 0;

Sets the window to receive notification messages associated with the MCIWnd window.

•	Returns zero.

hwnd

Handle of the MCIWnd window.

hwndP

Handle of the window to receive the notification messages.


MCIWndSetPalette

MCIWndSetPalette(hwnd, hpal)

// Corresponding message

MCIWNDM_SETPALETTE

wParam = (WPARAM) (HPALETTE) hpal;

lParam = 0;

Sends a palette handle to the MCI device associated with the MCIWnd window.

•	Returns zero if successful or an error otherwise.

hwnd

Handle of the MCIWnd window.

hpal

Palette handle.


MCIWndSetRepeat

VOID MCIWndSetRepeat(hwnd, f)

// Corresponding message

MCIWNDM_SETREPEAT

wParam = 0;

lParam = (LPARAM) (BOOL) f;

Sets the repeat flag associated with continuous playback. The MCIWNDM_SETREPEAT message works in conjunction with the MCI_PLAY command to provide a continuous playback loop.

•	Returns zero.

hwnd

Handle of the MCIWnd window.

f

New state of the repeat flag. Specify TRUE to turn on continuous playback.

Currently, MCIAVI is the only device that supports continuous playback.


MCIWndSetSpeed

LONG MCIWndSetSpeed(hwnd,iSpeed)

// Corresponding message

MCIWNDM_SETSPEED

wParam = 0;

lParam = (LPARAM) (UINT) iSpeed;

Sets the playback speed of an MCI device.

•	Returns zero if successful or an error otherwise.

hwnd

Handle of the MCIWnd window.

iSpeed

Playback speed. Specify 1000 for normal speed, larger values for faster speeds, and smaller values for slower speeds.


MCIWndSetTimeFormat

LONG MCIWndSetTimeFormat(hwnd, lp)

// Corresponding message

MCIWNDM_SETTIMEFORMAT

wParam = 0;

lParam = (LPARAM) (LPSTR) lp;

Sets the time format of an MCI device.

•	Returns zero if successful or an error otherwise.

hwnd

Handle of the MCIWnd window.

lp

Address of a buffer containing the null-terminated string indicating the time format. Specify "frames" to set the time format to frames, or "ms" to set the time format to milliseconds.

An application can specify time formats other than frames or milliseconds as long as the formats are supported by the MCI device. Noncontinuous formats, such as tracks and SMPTE, can cause the trackbar to behave erratically. For these time formats, you might want to turn off the toolbar by using the MCIWndChangeStyles macro and specifying the MCIWNDF_NOPLAYBAR window style.

If you want to set the time format to frames or milliseconds, you can also use the MCIWndUseFrames or MCIWndUseTime macro. For a list of time formats, see the MCIWndGetTimeFormat macro.


MCIWndSetTimers

VOID MCIWndSetTimers(hwnd, active, inactive)

// Corresponding message

MCIWNDM_SETTIMERS

wParam = (WPARAM) (UINT) active;

lParam = (LPARAM) (UINT) inactive;

Sets the update periods used by MCIWnd to update the trackbar in the MCIWnd window, update the position information displayed in the window title bar, and send notification messages to the parent window.

•	No return value.

hwnd

Handle of the MCIWnd window.

active

Update period used by MCIWnd when it is the active window. The default value is 500 milliseconds. Storage for this value is limited to 16 bits.

inactive

Update period used by MCIWnd when it is the inactive window. The default value is 2000 milliseconds. Storage for this value is limited to 16 bits.


MCIWndSetVolume

LONG MCIWndSetVolume(hwnd, iVol)

// Corresponding message

MCIWNDM_SETVOLUME

wParam = 0;

lParam = (LPARAM) (UINT) iVol;

Sets the volume level of an MCI device.

•	Returns zero if successful or an error otherwise.

hwnd

Handle of the MCIWnd window.

iVol

New volume level. Specify 1000 for normal volume level. Specify a higher value for a louder volume or a lower value for a quieter volume.


MCIWndSetZoom

VOID MCIWndSetZoom(hwnd, iZoom)

// Corresponding message

MCIWNDM_SETZOOM

wParam = 0;

lParam = (LPARAM) (UINT) iZoom;

Resizes a video image according to a zoom factor. This marco adjusts the size of an MCIWnd window while maintaining a constant aspect ratio.

•	No return value.

hwnd

Handle of the MCIWnd window.

iZoom

Zoom factor expressed as a percentage of the original image. Specify 100 to display the image at its authored size, 200 to display the image at twice its normal size, or 50 to display the image at half its normal size.


MCIWndStep

LONG MCIWndStep(hwnd, n)

// Corresponding command

MCI_STEP

wParam = 0;

lParam = (LPARAM) (long) n;

Moves the current position in the content forward or backward by a specified increment.

•	Returns zero if successful or an error otherwise.

hwnd

Handle of the MCIWnd window.

n

Step value. Negative values step the device through the content in reverse. The units for the step value depend on the current time format.


MCIWndStop

LONG MCIWndStop(hwnd)

// Corresponding command

MCI_STOP

wParam = 0;

lParam = 0;

Stops playing or recording the content of the MCI device associated with the MCIWnd window.

•	Returns zero if successful or an error otherwise.

hwnd

Handle of the MCIWnd window.


MCIWndUseFrames

LONG MCIWndUseFrames(hwnd)

// Corresponding message

MCIWNDM_SETTIMEFORMAT

wParam = 0;

lParam = TEXT ("frames");

Sets the time format of an MCI device to frames.

•	Returns zero if successful or an error otherwise.

hwnd

Handle of the MCIWnd window.


MCIWndUseTime

LONG MCIWndUseTime(hwnd)

// Corresponding message

MCIWNDM_SETTIMEFORMAT

wParam = 0;

lParam = TEXT ("ms");

Sets the time format of an MCI device to milliseconds.

•	Returns zero if successful or an error otherwise.

hwnd

Handle of the MCIWnd window.


MCIWndValidateMedia

VOID MCIWndValidateMedia(hwnd)

// Corresponding message

MCIWNDM_VALIDATEMEDIA

wParam = 0;

lParam = 0;

Updates the starting and ending locations of the content, the current position in the content, and the trackbar according to the current time format.

•	No return value.

hwnd

Handle of the MCIWnd window.

Typically, you should not need to use this macro; however, if your application changes the time format of a device without using MCIWnd; the starting and ending locations of the content, as well as the trackbar, continue to use the old format. You can use this macro to update these values.


MCIWnd Notifications

The MCIWnd message handler can send event notifications to the parent of an MCIWnd window in the form of MCIWNDM_NOTIFY messages. You can enable notification for an event type by specifying an appropriate style for an MCIWnd window when the window is created or its styles are updated. The following notifications are specific to MCIWnd windows.


MCIWNDM_NOTIFYERROR

MCIWNDM_NOTIFYERROR

wParam = (WPARAM) (HWND) hwnd;

lParam = (LPARAM) (LONG) errorCode;

Notifies the parent window of an application that an MCI error occurred.

hwnd

Handle of the MCIWnd window.

errorCode

Numerical code for the MCI error.

You can enable MCI error notification by specifying the MCIWNDF_NOTIFYERROR window style.


MCIWNDM_NOTIFYMEDIA

MCIWNDM_NOTIFYMEDIA

wParam = (WPARAM) (HWND) hwnd;

lParam = (LPARAM) (LPSTR) lp;

Notifies the parent window of an application that the media has changed.

hwnd

Handle of the MCIWnd window.

lp

Address of a null-terminated string containing the new filename. If the media is closing, it specifies a null string.

You can enable notification of media changes by specifying the MCIWNDF_NOTIFYMEDIA window style.


MCIWNDM_NOTIFYMODE

MCIWNDM_NOTIFYMODE

wParam = (WPARAM) (HWND) hwnd;

lParam = (LPARAM) (LONG) mode;

Notifies the parent window of an application that the operating mode of the MCI device has changed.

hwnd

Handle of the MCIWnd window.

mode

Integer corresponding to the MCI mode.

You can enable notification of mode changes of an MCI device by specifying the MCIWNDF_NOTIFYMODE window style.


MCIWNDM_NOTIFYPOS

MCIWNDM_NOTIFYPOS

wParam = (WPARAM) (HWND) hwnd;

lParam = (LPARAM) (LONG) pos;

Notifies the parent window of an application that the window position has changed.

hwnd

Handle of the MCIWnd window.

pos

Describes the new position.

You can enable notification of changes in the position of an MCIWnd window by specifying the MCIWNDF_NOTIFYPOS window style.


MCIWNDM_NOTIFYSIZE

MCIWNDM_NOTIFYSIZE

wParam = (WPARAM) (HWND) hwnd;

lParam = 0;

Notifies the parent window of an application that the window size has changed.

hwnd

Handle of the MCIWnd window.

You can enable notification of changes in the size of an MCIWnd window by specifying the MCIWNDF_NOTIFYSIZE window style.


MCI Overview

The Media Control Interface (MCI) is a high-level command interface to multimedia devices and resource files. MCI provides applications with device-independent capabilities for controlling audio and visual peripherals. Your application can use MCI to control any supported multimedia device, including waveform-audio devices, MIDI sequencers, CD audio devices, and digital-video (video playback) devices.

MCI provides standard commands for playing multimedia devices and recording multimedia resource files. These commands are a generic interface to virtually every kind of multimedia device.


MCI Command Strings and Messages

There are two forms of MCI commands: strings and messages. You can use either or both forms in your MCI application.

•	The command-message interface consists of constants and structures of the C programming language. You use the mciSendCommand function to send a message to an MCI device.

•	The command-string interface provides a textual version of the command messages. You use the mciSendString function to send a string to an MCI device. Command strings duplicate the functionality of the command messages. The Microsoft Windows operating system converts the command strings to command messages before sending them to the MCI driver for processing.

The command messages that retrieve information do so in the form of structures, which are easy to interpret in a C application. These structures can contain information on many different aspects of a device. The command strings that retrieve information do so in the form of strings, and can only retrieve one string at a time. Your application must parse or test each string to interpret it. You might find that the command messages are easier to use than the command strings in some cases, but the command strings are easy to remember and implement. Some MCI applications use command strings when the return value is unimportant or simply "true" or "false" and command messages when retrieving information from the device.

This chapter documents MCI without going into great detail on either the command-string or command-message interfaces. When commands or flags are discussed, this chapter uses the string form of the command or flag followed by the message form in parentheses. For information about the command-string interface, see Chapter 4, "MCI Command Strings." For information about the command-message interface, see Chapter 5, "MCI Command Messages."


MCI Devices

Every MCI multimedia device reacts to a core set of MCI commands as you would probably expect it to. For example, the play (MCI_PLAY) command causes the open device to play a file or track, no matter what kind of data the device works with. This section discusses MCI devices and how they respond to standard MCI commands.


Device Control

To control an MCI device, you open the device, send the necessary commands to it, and then close the device. The commands can be very similar, even for completely different MCI devices. For example, the following series of MCI commands plays the sixth track of an audio CD by using the command-string interface:

mciSendString("open cdaudio", lpszReturnString,
    lstrlen(lpszReturnString), NULL);
mciSendString("set cdaudio time format tmsf", lpszReturnString,
    lstrlen(lpszReturnString), NULL);
mciSendString("play cdaudio from 6 to 7", lpszReturnString,
    lstrlen(lpszReturnString), NULL);
mciSendString("close cdaudio", lpszReturnString,
    lstrlen(lpszReturnString), NULL);

The next example shows a similar series of MCI commands that plays the first 10,000 samples of a waveform-audio file:

mciSendString(
    "open c:\mmdata\purplefi.wav type waveaudio alias finch",
    lpszReturnString, lstrlen(lpszReturnString), NULL);
mciSendString("set finch time format samples", lpszReturnString,
    lstrlen(lpszReturnString), NULL);
mciSendString("play finch from 1 to 10000", lpszReturnString,
    lstrlen(lpszReturnString), NULL);
mciSendString("close finch", lpszReturnString,
    lstrlen(lpszReturnString), NULL);

These examples illustrate some interesting facts about MCI commands:

•	The same basic commands (open, set, play, and close) are used with CD audio and waveform-audio devices. The same MCI commands are used with all MCI devices.

•	The open command for the waveform-audio device includes a filename specification. The waveform-audio device is a compound device (one associated with a data file), while the CD audio device is a simple device (one without an associated data file).

•	The set command specifies time formats in each case, but the time-format flag for the CD audio device specifies tracks/minutes/seconds/frames (TMSF) format, while the time format used with the waveform-audio device specifies "samples".

•	The variables used with the "from" and "to" flags are appropriate to the respective time format. For example, for the CD audio device, the variables specify a range of tracks, but for the waveform-audio device, the variables specify a range of samples.


Playback and Positioning

A number of MCI commands, such as play (MCI_PLAY), stop (MCI_STOP), pause (MCI_PAUSE), resume (MCI_RESUME), and seek (MCI_SEEK), affect the playback or positioning of a multimedia file. If an MCI device receives a playback command while another playback command is in progress, it accepts the command and either stops or supersedes the previous command.

Many MCI commands, such as set (MCI_SET), do not affect playback. A notification from one of these commands does not interfere with pending playback or position commands as long as the notifications are not performed from the same instance of the driver. For example, you can issue a set or status (MCI_STATUS) command while a device is performing a seek command without stopping or superseding the seek command.

However, there can only be one pending notification. For example, if an application requests a notification for play and follows that request with status "start position notify," the play notification will return "superseded" and the notification for the status command will return when it is finished. In this case, however, the play command will still succeed, even though the application did not receive the notification.


Device Types

MCI recognizes a basic set of device types. A device type is a set of MCI drivers that share a common command set and are used to control similar multimedia devices or data files. Many MCI commands, such as open (MCI_OPEN), require you to specify a device type.

The following table lists the defined device types. The current implementation of MCI includes command sets for a subset of these devices.

Device type	Constant	Description
animation	MCI_DEVTYPE_ANIMATION	Animation device
cdaudio	MCI_DEVTYPE_CD_AUDIO	CD audio player
dat	MCI_DEVTYPE_DAT	Digital-audio tape player
digitalvideo	MCI_DEVTYPE_DIGITAL_VIDEO	Digital video in a window (not GDI based)
other	MCI_DEVTYPE_OTHER	Undefined MCI device
overlay	MCI_DEVTYPE_OVERLAY	Overlay device (analog video in a window)
scanner	MCI_DEVTYPE_SCANNER	Image scanner
sequencer	MCI_DEVTYPE_SEQUENCER	MIDI sequencer
vcr	MCI_DEVTYPE_VCR	Video-cassette recorder or player
videodisc	MCI_DEVTYPE_VIDEODISC	Videodisc player
waveaudio	MCI_DEVTYPE_WAVEFORM_AUDIO	Audio device that plays digitized waveform files
In this document, the names of device types are bold. Device-type names are used with the command-string interface. Device-type constants are used with the command-message interface.


Device Names

For any given device type, there might be several MCI drivers that share the command set but operate on different data formats. For example, the animation device type might include several MCI drivers that use the same command set but play different types of animation files. To uniquely identify an MCI driver, MCI uses device names.

Device names are identified either in the [mci] section of the SYSTEM.INI file or in the appropriate part of the registry. This information identifies all MCI drivers to Windows. The entries in the [mci] section use the following form:

device_name = driver_filename.extension

The following example shows a typical [mci] section from SYSTEM.INI:

[mci]
cdaudio=mcicda.drv

sequencer=mciseq.drv

waveaudio=mciwave.drv

avivideo=mciavi.drv

If an MCI driver is installed using a device name that already exists in SYSTEM.INI or the registry, the system appends an integer to the device name of the new driver, creating a unique device name. In the preceding example, an additional driver installed using the "cdaudio" device name would be assigned the device name "cdaudio1".


Driver Support for MCI Commands

MCI drivers provide the functionality for MCI commands. The system software performs some basic data-management tasks, but all the multimedia playback, presentation, and recording is handled by the individual MCI drivers.

Drivers vary in their support for MCI commands and command flags. Because multimedia devices can have widely different capabilities, MCI is designed to let individual drivers extend or reduce the command sets to match the capabilities of the device. For example, the record (MCI_RECORD) command is part of the command set for MIDI sequencers, but the MCISEQ driver included with Windows does not support this command. The reference material for the record command explains that devices of the sequencer device type recognize the command; this does not mean that all devices of this type support the command. Applications should use the capability (MCI_GETDEVCAPS) command to determine the capabilities of a particular device.


Default Behavior of Drivers

In many situations, the MCI command specifications define the default values and behavior for drivers of a particular device type. Since multimedia devices can have a wide range of features (and limitations), there can be undefined areas of behavior. Also, drivers might handle exceptions differently based on the device capabilities and the design goals of the programmer who developed the driver.

For example, consider the following commands sent to a waveform-audio driver:

mciSendString("open sound.wav alias sound", lpszReturnString,
    lstrlen(lpszReturnString), NULL);
mciSendString("play sound notify", lpszReturnString,
    lstrlen(lpszReturnString), NULL);
mciSendString("record sound from 0 notify", lpszReturnString,
    lstrlen(lpszReturnString), NULL);

The record command returns a "Parameter out of range" value and stops the playback started by the previous play command. One might expect the driver to validate the record command before stopping playback, but the driver stops the playback first.


Classifications of MCI Commands

MCI defines four command classifications: system, required, basic, and extended. The following list describes these command classifications:

•	System commands are handled by MCI directly, rather than by the driver.

•	Required commands are handled by the driver. All MCI drivers must support the required commands and flags.

•	Basic commands (or optional commands) are used by some devices. If a device supports a basic command, it must support a defined set of flags for that command.

•	Extended commands are specific to a device type or driver. Extended commands include new commands (like the put (MCI_PUT) and where (MCI_WHERE) commands for the animation, digitalvideo, and overlay device types) and extensions to existing commands (like the "stretch" flag of the status (MCI_STATUS) command for the animation and overlay device types).

While system and required commands are the minimum command set for any MCI driver, basic and extended commands are not supported by all drivers. Your application can always use system and required commands and their flags, but if it needs to use a basic or extended command or flag, it should first query the driver by using the capability (MCI_GETDEVCAPS) command. The following sections summarize the specific commands in each category.

System Commands

MCI processes the following system commands directly, rather than passing them to MCI devices:

String	Message	Description
break	MCI_BREAK	Sets a break key for an MCI device.
sysinfo	MCI_SYSINFO	Returns information about MCI devices.
Required Commands

All MCI devices support the following required commands:

String	Message	Description
capability	MCI_GETDEVCAPS	Obtains the capabilities of a device.
close	MCI_CLOSE	Closes the device.
info	MCI_INFO	Obtains textual information from a device.
open	MCI_OPEN	Initializes the device.
status	MCI_STATUS	Obtains status information from the device. Some of this command's flags are not required, so it is also a basic command.
Devices must also support a standard set of command flags for the required commands.

Basic Commands

The following list summarizes the basic commands. The use of these commands by an MCI device is optional.

String	Message	Description
load	MCI_LOAD	Loads data from a file.
pause	MCI_PAUSE	Stops playing. Playback or recording can be resumed at the current position.
play	MCI_PLAY	Starts transmitting output data.
record	MCI_RECORD	Starts recording input data.
resume	MCI_RESUME	Resumes playing or recording on a paused device.
save	MCI_SAVE	Saves data to a disk file.
seek	MCI_SEEK	Seeks forward or backward.
set	MCI_SET	Sets the operating state of the device.
status	MCI_STATUS	Obtains status information about the device. This is also a required command; since some of its flags are not required, it is also listed here. (The optional items support devices that use linear media with identifiable positions.)
stop	MCI_STOP	Stops playing.
If a driver supports a basic command, it must also support a standard set of flags for the command.

Extended Commands

Some MCI devices have additional commands, or they add flags to existing commands. While some extended commands apply only to a specific device driver, most of them apply to all drivers of a particular device type. For example, the command set for the sequencer device type extends the set (MCI_SET) command to add time formats that are needed by MIDI sequencers.

You should not assume that the device supports the extended commands or flags. You can use the capability (MCI_GETDEVCAPS) command to determine whether a specific feature is supported, and your application should be ready to deal with "unsupported command" or "unsupported function" return values.

The following extended commands are available with the listed device types:

String	Message	Device types	Description
configure	MCI_CONFIGURE	digitalvideo	Displays a configuration dialog box.
cue	MCI_CUE	digitalvideo, waveaudio	Prepares for playing or recording.
delete	MCI_DELETE	waveaudio	Deletes a data segment from the media file.
escape	MCI_ESCAPE	videodisc	Sends custom information to a device.
freeze	MCI_FREEZE	overlay	Disables video acquisition to the frame buffer.
put	MCI_PUT	animation, digitalvideo, overlay	Defines the source, destination, and frame windows.
realize	MCI_REALIZE	animation, digitalvideo	Tells the device to select and realize its palette into a device context (DC) of the displayed window.
setaudio	MCI_SETAUDIO	digitalvideo	Sets audio parameters for video.
setvideo	MCI_SETVIDEO	digitalvideo	Sets video parameters.
signal	MCI_SIGNAL	digitalvideo	Identifies a specified position with a signal.
spin	MCI_SPIN	videodisc	Starts the disc spinning or stops the disc from spinning.
step	MCI_STEP	animation, digitalvideo, videodisc	Steps the play one or more frames forward or reverse.
unfreeze	MCI_UNFREEZE	overlay	Enables the frame buffer to acquire video data.
update	MCI_UPDATE	animation, digitalvideo	Repaints the current frame into the DC.
where	MCI_WHERE	animation, digitalvideo, overlay	Obtains the rectangle specifying the source, destination, or frame area.
window	MCI_WINDOW	animation, digitalvideo, overlay	Controls the display window.


Working with MCI Devices

This section describes how to perform the following tasks:

•	Open a device.

•	Retrieve information about a device.

•	Obtain MCI system information.

•	Play a device.

•	Record.

•	Stop, pause, and resume a device.

•	Close a device.

In addition, this section provides you with shortcuts you can use with MCI commands.


Opening a Device

Before using a device, you must initialize it by using the open (MCI_OPEN) command. This command loads the driver into memory (if it isn't already loaded) and retrieves the device identifier you will use to identify the device in subsequent MCI commands. You should check the return value of the mciSendString or mciSendCommand function before using a new device identifier to ensure that the identifier is valid. (You can also retrieve a device identifier by using the mciGetDeviceID function.)

Like all MCI command messages, MCI_OPEN has an associated structure. These structures are sometimes called parameter blocks. The default structure for MCI_OPEN is MCI_OPEN_PARMS. Certain devices (such as waveform, animation, and overlay) have extended structures to accommodate additional optional parameters. Unless you need to use these additional parameters, you can use the MCI_OPEN_PARMS structure with any MCI device.

The number of devices you can have open is limited only by the amount of available memory.

Using an Alias

When you open a device, you can use the "alias" flag  to specify a device identifier for the device. This flag lets you assign a short device identifier for compound devices with lengthy filenames, and it lets you open multiple instances of the same file or device.

For example, the following command assigns the device identifier "birdcall" to the lengthy filename C:\NABIRDS\SOUNDS\MOCKMTNG.WAV:

mciSendString(
    "open c:\nabirds\sounds\mockmtng.wav type waveaudio alias birdcall",
    lpszReturnString, lstrlen(lpszReturnString), NULL);

In the command-message interface, you specify an alias by using the lpstrAlias member of the MCI_OPEN_PARMS structure.

Specifying a Device Type

When you open a device, you can use the "type" flag to refer to a device type, rather than to a specific device driver. The following example opens the waveform-audio file C:\WINDOWS\CHIMES.WAV (using the "type" flag to specify the waveaudio device type) and assigns the alias "chimes":

mciSendString(
    "open c:\windows\chimes.wav type waveaudio alias chimes",
    lpszReturnString, lstrlen(lpszReturnString), NULL);

In the command-message interface, the functionality of the "type" flag is supplied by the lpstrDeviceType member of the MCI_OPEN_PARMS structure.

Simple and Compound Devices

MCI classifies device drivers as compound or simple. Drivers for compound devices require the name of a data file for playback; drivers for simple devices do not.

Simple devices include cdaudio and videodisc devices. There are three ways to open simple devices:

•	Specify a pointer to a null-terminated string containing the device name from the registry or the SYSTEM.INI file.

For example, you can open a videodisc device by using the following command:

mciSendString("open videodisc", lpszReturnString,
    lstrlen(lpszReturnString), NULL);

In this case, "videodisc" is the device name from the registry or the [mci] section of SYSTEM.INI.

•	Specify the actual name of the device driver. Opening a device using the device-driver filename, however, makes the application device-dependent and can prevent the application from running if the system configuration changes. If you use a filename, you do not need to specify the complete path or the filename extension; MCI assumes drivers are located in a system directory and have the .DRV filename extension.

Compound devices include waveaudio and sequencer devices. The data for a compound device is sometimes called a device element. This document, however, generally refers to this data as a file, even though in some cases the data might not be stored as a file.

There are three ways to open a compound device:

•	Specify only the device name. This lets you open a compound device without associating a filename. Most compound devices process only the capability (MCI_GETDEVCAPS) and close (MCI_CLOSE) commands when they are opened this way.

•	Specify only the filename. The device name is determined from the associations entered in the registry.

•	Specify the filename and the device name. MCI ignores the entries in the registry and opens the specified device name.

To associate a data file with a particular device, you can specify the filename and device name. For example, the following command opens the waveaudio device with the filename MYVOICE.SND:

mciSendString("open myvoice.snd type waveaudio", lpszReturnString,
    lstrlen(lpszReturnString), NULL);

In the command-string interface, you can also abbreviate the device name specification by using the alternative exclamation-point format, as documented with the open command.

Opening a Device Using the Filename Extension

If the open (MCI_OPEN) command specifies only the filename, MCI uses the filename extension to select the appropriate device from the list in the registry or the [mci extensions] section of the SYSTEM.INI file. The entries in the [mci extensions] section use the following form:

filename_extension=device_name

MCI implicitly uses device_name if the extension is found and if a device name has not been specified in the open command.

The following example shows a typical [mci extensions] section:

[mci extensions]
wav=waveaudio
mid=sequencer
rmi=sequencer

Using these definitions, MCI opens the waveaudio device if the following command is issued:

mciSendString("open train.wav", lpszReturnString,
    lstrlen(lpszReturnString), NULL);

New Data Files

To create a new data file, simply specify a blank filename. MCI does not save a new file until you save it by using the save (MCI_SAVE) command. When creating a new file, you must include a device alias with the open (MCI_OPEN) command.

The following example opens a new waveaudio file, starts and stops recording, then saves and closes the file:

mciSendString("open new type waveaudio alias capture", lpszReturnString,
    lstrlen(lpszReturnString), NULL);
mciSendString("record capture", lpszReturnString,
    lstrlen(lpszReturnString), NULL);
mciSendString("stop capture", lpszReturnString,
    lstrlen(lpszReturnString), NULL);
mciSendString("save capture orca.wav", lpszReturnString,
    lstrlen(lpszReturnString), NULL);
mciSendString("close capture", lpszReturnString,
    lstrlen(lpszReturnString), NULL);

Shareable Devices

The "shareable" (MCI_OPEN_SHAREABLE) flag of the open (MCI_OPEN) command lets multiple applications access the same device (or file) and device instance simultaneously. If your application opens a device or file as shareable, other applications can also access it by opening it as shareable. The shared device or file gives each application the ability to change the parameters governing its operating state. Each time a device or file is opened as shareable, MCI returns a unique device identifier, even though the identifiers refer to the same instance.

If your application opens a device or file without specifying that it is shareable, no other application can access it until your application closes it. Also, if a device supports only one open instance, the open command will fail if you specify the shareable flag.

If your application opens a device and specifies that it is shareable, your application should not make any assumptions about the state of this device. Your application might need to compensate for changes made by other applications accessing the device.

Most compound files are not shareable; however, you can open multiple files (where each is unique), or you can open a single file multiple times. If you open a single file multiple times, MCI creates an independent instance for each, with each instance having a unique operating status.

If you open multiple instances of a file, you must assign a unique device identifier to each. You can use an alias, as described in the following section, to assign a unique name for each file.


Retrieving Information About a Device

Every device responds to the capability (MCI_GETDEVCAPS), status (MCI_STATUS), and info (MCI_INFO) commands. These commands obtain information about the device. For example, the following command returns "true" if a cdaudio device can eject the disc:

mciSendString(
    "capability cdaudio can eject",
    lpszReturnString, lstrlen(lpszReturnString), NULL);

The flags listed for the required and basic commands provide a minimum amount of information about a device. Many devices supplement the required and basic commands with extended flags to provide additional information about the device.


Obtaining MCI System Information

The sysinfo (MCI_SYSINFO) command obtains system information about MCI devices. MCI handles this command without relaying it to any MCI device. For the command-message interface, MCI returns the system information in the MCI_SYSINFO_PARMS structure.

You can use the sysinfo (MCI_SYSINFO) command to retrieve information such as the number of MCI devices on a system, the number of MCI devices of a particular type, the number of open MCI devices, and the names of the devices. This command is often called more than once to retrieve a particular piece of information. For example, you might retrieve the number of devices of a particular type in the first call and then enumerate the names of the devices in the next.


Playing a Device

The play (MCI_PLAY) command starts playing a device. Without any flags, this command starts playing from the current position and plays until the command is interrupted or until the end of the media or file is reached. After playback, the current position is at the end of the media. You can also use the seek (MCI_SEEK) command to change the current position.

Most devices that support the play command also support the "from" (MCI_FROM) and "to" (MCI_TO) flags. These flags indicate the position at which the device should start and stop playing. For example, the following command plays a CD audio disc from the beginning of the first track:

mciSendString("play cdaudio from 0", lpszReturnString,
    lstrlen(lpszReturnString), NULL);

Some device types extend this command to exploit the capabilities of a particular device. For example, the play command for the videodisc device type includes the "fast" (MCI_VD_PLAY_FAST) , "slow" (MCI_VD_PLAY_SLOW), and "scan" (MCI_VD_PLAY_SCAN) flags.

Note  The units assigned to the position value depend on the time format used by the device. Each device has a default time format, but you should specify the time format by using the set (MCI_SET) command before issuing any commands that use position values.

Playing an AVI File

Video files in Windows are made up of at least two interleaved data streams: a video (pictorial) stream and an audio stream. You can easily play these audio-video interleaved (AVI) files by using MCI commands. The following sections discuss playing AVI files.

Setting Up an MCIAVI Playback Window

Your application can specify the following options to define the playback window for playing an AVI file:

•	Use the MCIAVI driver's default pop-up window.

•	Specify a parent window and window style that the MCIAVI driver can use to create the playback window.

•	Specify a playback window for the MCIAVI driver to use for playback.

•	Play the AVI file on a full-screen display.

If your application does not specify any window options, the MCIAVI driver creates a default window for playing the sequence. The driver creates this playback window for the open (MCI_OPEN) command, but it does not display the window until your application sends a command to either display the window or play the file. This default playback window is a pop-up window with a sizing border, title bar, a thick frame, a system menu, and a minimize button.

Your application can also specify a parent window handle and a window style when it issues the open command. In this case, the MCIAVI driver creates a window based on these specifications instead of the default pop-up window. Your application can specify any window style available for the CreateWindow function. Styles that require a parent window, such as WS_CHILD, should include a parent window handle.

Your application can also create its own window and supply the handle to the MCIAVI driver by using the window (MCI_WINDOW) command. The MCIAVI driver uses this window instead of creating one of its own.

When the MCIAVI driver creates the playback window or obtains a window handle from your application, it does not display the window until your application either plays the sequence or sends a command to display the window. Your application can use the window command to display the window without playing the sequence. For example, the following command displays the window using the command-string interface:

mciSendString("window movie state show", lpszReturnString,
    lstrlen(lpszReturnString), NULL);

In this example, "movie" is an alias for the digital-video device.

Your application can also play an AVI file full-screen. To play full-screen, modify the play (MCI_PLAY) command with the "fullscreen" (MCI_MCIAVI_PLAY_FULLSCREEN) flag. When your application uses this flag, the MCIAVI driver uses a 320- by 240-pixel full-screen format for playing the sequence. For example, the following command plays the opened file full-screen (using "movie" as an alias):

mciSendString("play movie fullscreen", lpszReturnString,
    lstrlen(lpszReturnString), NULL);

Changing the Playback State for an AVI file

Your application can use the seek (MCI_SEEK) command to move the current position to the beginning, the end, or an arbitrary position in an AVI file. There are two seek modes for the MCIAVI driver: exact and inexact. Your application can change the seek mode by using the set (MCI_SET) command. When seek exactly is enabled (set "seek exactly on"), the MCIAVI driver seeks exactly to the frame your application specifies. This might cause a delay if the file is temporally encoded and your application does not specify a key frame. With seek exactly disabled (set "seek exactly off"), the MCIAVI driver seeks to the nearest key frame in a temporally encoded file.

Some MCI commands let your application alter the playback of an AVI file in other ways. For example, an AVI file, by default, plays at its normal speed, but your application can increase or decrease this speed by using the "speed" flag for the set command. For AVI files, a speed value of 1000 is normal. Thus, to play a movie at half its normal speed, your application can use the command set "movie speed 500"; alternatively, it can use set "movie speed 2000" to play the sequence at twice its normal speed.

The setaudio (MCI_SETAUDIO) command lets your application control the audio portion of an AVI file. Your application can mute audio during playback or, in the case of multiple audio stream files, select the audio stream that is played.

The MCIAVI driver has a dialog box to control some of its playback options. Some of the options available to the user include selecting window-oriented or full-screen playback, selecting the seek mode, and zooming the image. Your application can have MCIAVI display this dialog box by using the configure (MCI_CONFIGURE) command.

Stream Handlers

The data in an AVI file is treated as a series of streams. An AVI file typically contains an audio and video stream, and there might be a custom stream as well containing text or some other custom data. The MCIAVI driver can use different handlers for these data streams. For more information about custom AVI files, see Chapter 9, "Custom File and Stream Handlers."


Recording

The general MCI specification supports recording with digital-video, MIDI sequencer, video-cassette recorder (VCR), and waveform-audio devices; however, only waveform-audio and VCR devices currently implement recording capabilities. You can insert or overwrite recorded information into an existing file or record into a new file. To record to an existing file, open a waveform-audio device and file as you would normally. To record into a new file, when you open the device specify "new" as the device name if you are using the command-string interface, or a zero-length filename if you are using the command-message interface.

When MCI creates a new file for recording, the data format is set to a default format specified by the device driver. To use a format other than the default format, you can use the set (MCI_SET) command.

To begin recording, use the record command (or MCI_RECORD and the MCI_RECORD_PARMS structure).

If you record in insert mode to an existing file, you can use the "from" (MCI_FROM) and "to" (MCI_TO) flags of the record command to specify starting and ending locations for recording. For example, if you record to a file that is 20 seconds long, and you begin recording at 5 seconds and end recording at 10 seconds, the resulting file will be 25 seconds long. The file will have a 5-second segment inserted 5 seconds into the original recording.

If you record with overwrite mode to an existing file, you can use the "from" and "to" flags to specify starting and ending locations of the section that is overwritten. For example, if you record to a file that is 20 seconds long, and you begin recording at 5 seconds and end recording at 10 seconds, you still have a recording 20 seconds long, but the section beginning at 5 seconds and ending at 10 seconds will have been replaced.

If you do not specify an ending location, recording continues until you send a stop (MCI_STOP) command, or until the driver runs out of free disk space. If you record to a new file, you can omit the "from" flag or set it to zero to start recording at the beginning of a new file. You can specify an ending location to terminate recording when recording to a new file.

The record command is sometimes accurate to within only 1 second of the starting location, such as with VCR devices. To record more accurately, you should use the cue (MCI_CUE) command. This command is recognized by digital-video, VCR, and waveform-audio devices. For more information about recording with VCR devices, see "VCR Services" later in this chapter.

Saving a Recorded File

When recording is complete, use the save command (or MCI_SAVE and the MCI_SAVE_PARMS structure) to save the recording before closing the device.

Note  If you close the device without saving, the recorded data is lost.

Checking Input Levels (PCM only)

To get the level of the input signal before recording on a PCM (Pulse Code Modulation) waveform-audio input device, use the status (MCI_STATUS) command. Specify the "level" flag (or the MCI_STATUS_ITEM flag and set the dwItem member of the MCI_STATUS_PARMS structure to MCI_WAVE_STATUS_LEVEL). The average input signal level is returned. The left-channel value is in the high-order word and the right- or mono-channel value is in the low-order word

The input level is represented as an unsigned value. For 8-bit samples, this value is in the range 0 through 127 (0x7F). For 16-bit samples, it is in the range 0 through 32,767 (0x7FFF).


Stopping, Pausing, and Resuming a Device

The stop (MCI_STOP) command suspends the playing or recording of a device. Many devices also support the pause (MCI_PAUSE) command. The difference between stop and pause depends on the device. Usually pause suspends operation but leaves the device ready to resume playing or recording immediately.

Using the play (MCI_PLAY) or record (MCI_RECORD) command to restart a device resets the locations specified with the "to" (MCI_TO) and "from" (MCI_FROM) flags before the device was paused or stopped. Without the "from" flag, these commands reset the starting location to the current position. Without the "to" flag, they reset the ending location to the end of the media. To continue playing or recording without resetting a previously specified stop position, use the play or record command's "to" flag to specify an ending location.

Some devices support the resume (MCI_RESUME) command to restart a paused device. This command does not change the "to" and "from" locations specified with the play or record command that preceded the pause command.


Closing a Device

The close (MCI_CLOSE) command releases access to a device or file. MCI frees a device when all tasks using a device have closed it. To help MCI manage the devices, your application must close each device or file when it is finished using it.

When you close an external MCI device that uses its own media instead of files (such as CD audio), the driver leaves the device in its current mode of operation. Thus, if you close a CD audio device that is playing, even though the device driver is released from memory, the CD audio device will continue to play until it reaches the end of its content.

Note  Closing an application with open MCI devices can prevent other applications from using those devices until Windows is restarted.


MCI Implementations for Specific Devices

This section discusses using MCI commands with specific MCI devices.


MCIAVI

An AVI file can contain more than two streams — for example, a video sequence, an English soundtrack, and a French soundtrack. Your application can use a stream independently of the other streams in the file.

The digitalvideo device type controls video files. For a list of the MCI commands recognized by digital-video devices, see "Digital-Video Command Set" later in this chapter.

The MCIAVI driver plays video sequences and other data streams under the control of MCI commands. Data streams can contain images, audio, and palettes. The image data can consist of images with either color palettes or true-color information.

Audio is synchronized with the video within one-thirtieth of a second. If audio hardware is not available, however, the driver plays only the video stream. The MCIAVI driver can drop video frames, if necessary, to play a stream without audio interruption.

Your application can use the MCIWnd window class services instead of the MCI command interface to control any MCI driver. This window class handles many of the details of managing the window supporting the MCI device and simplifies the programming required to send the MCI commands. Your application can use the MCIWnd library services directly to control the MCI device, or it can have MCIWnd display a toolbar, scroll bar, and menus that let the user control the device. For more information about the MCIWnd window class, see Chapter 2, "Getting Started Using MCIWnd."


VCR Services

Windows provides VCR services through a device driver that is based on the MCI command set for VCRs. This section describes the MCI Video System Control Architecture (VISCA) driver and explains how to use it to control a VCR.

The vcr device type controls VCRs. For a list of the MCI commands recognized by VCR devices, see "VCR Command Set" later in this chapter.

The MCI VISCA Driver

The MCI VISCA driver controls Sony® VISCA-compatible VCRs, such as the CVD-1000 VDeck. The VISCA driver controls the tape transport, channel tuners, and VCR input and output channels.

Searching and Positioning with a VCR

The VISCA driver uses two methods to track videotape movement within the VCR tape transport: timecode information and tape counters. Timecode information is timing information that has been recorded on the videotape. Most VCRs allow timecodes to be recorded without destroying audio and video tracks. Tape counters estimate the amount of videotape that travels past the videotape head to obtain a position.

Both timecode information and tape counters increase as the videotape moves from beginning to end. Because of its accuracy, using timecode information to position a videotape is almost always preferable to using tape counters.

The MCI command flags for specifying positioning information are expressed as time dependencies: "time format", "duration", "from", "to", and "seek". (Also, the status "position" command returns its time value in the current time format.)

The VISCA driver uses the set "time mode" command to select the type of positioning to use with a videotape. When the time mode is set to "timecode", the status "position" and set "time format" commands use the timecode on the videotape. When the time mode is set to "counter", the status "position" and set "time format" commands use counters.

An application can set the time mode to "detect" if it doesn't matter that there might be two sources of position information. When in detect mode, the VISCA driver uses timecode information for positioning when any of the following conditions occur:

•	The timecode information is present when the driver is opened.

•	You change a videotape with the set "door open" command and timecode information is present on the videotape.

•	The set "time mode" command is reissued.

If timecode information cannot be found, the driver uses the tape counters.

To determine the current positioning method, issue the status "time type" command, which returns either "timecode" or "counter". You can also identify the current positioning mode by using the status "time mode" command, which returns "timecode", "counter", or "detect".

The status "counter" command retrieves the current tape counter value, regardless of the current positioning method; however, you can use this counter reading only with the set "counter" command.

The VISCA driver can retrieve the native timecode format recorded on a videotape by using the status "timecode type" and status "frame rate" commands together. For example, if timecode type is "smpte" and frame rate is 25, the native timecode format recorded on the videotape is SMPTE 25.

The VISCA driver can also retrieve the counter resolution by using the status "counter resolution" command, which returns "seconds" or "frames". The counter format might still be set to SMPTE 30, but the return value returns only a frame of 0. If the current time type is counter, then this resolution applies also to the value returned by status "position".

Capturing Frames

Frame-capturing commands provide still images for a frame-capture device. A frame-capture device is a separate piece of hardware capable of reading and storing the video image. The VISCA driver supports the freeze (MCI_FREEZE) command to stabilize a still image for capturing. Also, the unfreeze (MCI_UNFREEZE) command can be used to restart the tape transport following a freeze command.

The freeze command provides a high-quality, stabilized, time-base − corrected image for a frame-capture device. This command exists because a device might not always deliver its maximum-quality output image during playback or while paused; such a video image is not suitable for capturing.

The unfreeze command unlocks the tape transport and resumes the transport mode in effect prior to the freeze command.

When your application needs to record a video image on the VCR, as is common with software-animation applications, use the freeze "input" command or the cue (MCI_CUE) command to record the image.

Selecting Inputs

The VISCA driver supports three input types: video, audio, and timecode. The video inputs include two standard channels (lines 1 and 2), an SVideo channel, an auxiliary channel, and a channel from an internal tuner. The audio inputs include two standard channels (lines 1 and 2) and a channel from an internal tuner. The timecode input is internal to the VCR.

The normal outputs carry the currently selected inputs when the VCR is recording or when the tape transport is stopped, and they carry the contents of the videotape when the tape transport is playing or paused. The monitored outputs carry the same information as the normal outputs plus current timecode and channel information.

Assuming the appropriate external inputs are connected to your VCR and you have decided what you want to record, you can select the inputs to be recorded. For example, to record or view from the "svideo" video and the "line 1" audio inputs, you would use the setvideo (MCI_SETVIDEO) and setaudio (MCI_SETAUDIO) commands to select these input sources. You can verify these selections by using the status (MCI_STATUS) command.

By default, the monitor shows exactly what appears as the output. Sometimes, however, you might want to view one source while recording from another. This is a common practice using the tuner. For example, you might want to watch channel 4 while you record channel 7. In this case, you have two logical tuner inputs. You could set up the VCR by using the following commands:

1.	Use the settuner (MCI_SETTUNER) command to select the channels to watch and record.

2.	Use the setvideo command to select the video-recording source.

3.	Use the setaudio command to select the audio-recording source.

4.	Use the setvideo command to route the channel 4 video input to the monitored output to display it on-screen.

5.	Use the setaudio command to route the channel 4 audio input to the monitored output to play the audio.

6.	Verify your selections by using the status command.

The VISCA driver also supports a special input type for audio and video called mute. Mute allows the selection of "no input," which is useful when recording a blank signal.

Selecting Recording Tracks

There are three types of recording tracks on a videotape: video, audio, and timecode. You have only one video or timecode track, but you can use more than one audio track. When you do so, make track 1 the main audio track.

The VISCA driver supports two operating modes: assemble and insert. In assemble mode, all tracks are selected to be recorded. In insert mode, tracks can be independently selected for recording. Most VCRs are in assemble mode by default. Use the set (MCI_SET) command to change these modes.

Recording and Editing

The record (MCI_RECORD) command provides simple recording and is accurate to approximately 1 second of the starting position. To record more accurately or if you expect to edit the video content while simultaneously operating multiple decks, you should use the cue (MCI_CUE) command.

The cue command prepares the device for recording or playing. Use the cue "input" command to prepare the device for recording. The cue command is required because an application must know when the device is ready to perform the command (and because it can take several minutes to prepare for a play (MCI_PLAY) or record command).

The VCR prepares itself for recording or playing by seeking to the in-point, which is the current position or the position specified by using the cue "from" command. If the "preroll" flag is specified with the cue command, however, the VCR positions itself the preroll distance from the in-point. The "preroll" flag also indicates that the VCR uses any applicable editing mode, so it's important that you use "preroll", especially when you want the most accurate recording. (Use the capability (MCI_GETDEVCAPS) command with the "can preroll" flag to check whether preroll is supported.)

Note  When you record using "from" and "to" positions, the "from" position is included in the edit, and the "to" position is not.

For more information about recording, see "Recording" earlier in this chapter.

Using the Clock While Editing

When editing, you might want to record segments from one VCR to another. You can begin recording at a specific time and position on one VCR while another begins playing at the same time and position by specifying an action (play or record), a position, and a time for each VCR.

Both VCRs must use the same clock for this type of editing; the clock helps synchronize both devices. You can determine if two VCRs share the same clock by using the status (MCI_STATUS) command with the "clock id" flag to query each VCR. If the identification numbers returned by the status command are the same, the devices use the same clock. As a shared resource, the clock can be connected to multiple VCRs. The VISCA driver supports only one shared clock.

You can also determine clock resolution by using the status "clock increment rate" command. This command returns the number of increments the clock supports per second. For example, if the clock is updated every millisecond, the command returns 1000 as the clock increment rate. The advantage of using the increment rate is that the rate is expressed as an integer; otherwise, the increment would be a (single- or double-precision) floating-point value. As an integer, manipulating the increment rate is a simple operation and is not susceptible to rounding errors. You can reset the clock by using the set (MCI_SET) command with the "clock 0" (zero) flag.

When issuing a play (MCI_PLAY), record (MCI_RECORD), or seek (MCI_SEEK) command, you can specify when the command is to be executed. The characteristics of the VCRs being used determine when to start each VCR. The timing must account for the amount of preroll each device requires and the amount of time needed to complete the MCI commands used to set up the edit session. To do this, retrieve the clock time and add a waiting interval of 5 to 10 seconds. (The waiting interval must be long enough to let the preroll and any outstanding MCI commands complete.)

To ensure that the waiting period is long enough, place the record command last in your application and check the time immediately before it. If the interval is too short, restart the play command. Alternatively, you could check the time immediately after the last command of the script to verify that there is enough time to send and complete all of the commands.


Using the "Wait", "Notify", and "Test" Flags

Most MCI commands include flags that modify the command. The "wait" (MCI_WAIT) and "notify" (MCI_NOTIFY) flags are common to every command. The "test" (MCI_TEST) flag is available to digital-video and VCR devices. This section describes the use of these flags.


The "Wait" Flag

MCI commands usually return to the user immediately, even if it takes several minutes to complete the action initiated by the command. You can use the "wait" (MCI_WAIT) flag to direct the device to wait until the requested action is completed before returning control to the application.

For example, the following play command will not return control to the application until the playback completes:

mciSendString("play mydevice from 0 to 100 wait",
    lpszReturnString, lstrlen(lpszReturnString), NULL);

Note  The user can cancel a wait operation by pressing a break key. By default, this key is CTRL+BREAK. Applications can redefine this key by using the break (MCI_BREAK) command. (MCI_BREAK uses the MCI_BREAK_PARMS structure.) When a wait operation is canceled, MCI attempts to return control to the application without interrupting the command associated with the "wait" flag.


The "Notify" Flag

The "notify" (MCI_NOTIFY) flag directs the device to post an MM_MCINOTIFY message when the device completes an action. Your application must have a window procedure to process the MM_MCINOTIFY message for notification to have any effect. An MM_MCINOTIFY message indicates that the processing of a command has completed, but it does not indicate whether the command was completed successfully, failed, or was superseded or aborted.

The application specifies the handle to the destination window for the message when it issues a command. In the command-string interface, this handle is the last parameter of the mciSendString function. In the command-message interface, the handle is specified in the low-order word of the dwCallBack member of the structure sent with the command message. (Every structure associated with a command message contains this member.)


The "Test" Flag

The "test" (MCI_TEST) flag queries the device to determine if it can execute the command. The device returns an error if it cannot execute the command. It returns no error if it can handle the command. When you specify this flag, MCI returns control to the application without executing the command.

This flag is supported by digital-video and VCR devices for all commands except open (MCI_OPEN) and close (MCI_CLOSE).


Using Command Shortcuts and Variations

You can use several shortcuts when working with MCI commands. These shortcuts enable you to use a single identifier to refer to all the devices your application has opened, or to open a device without explicitly issuing an open (MCI_OPEN) command.


Using "All" as a Device Identifier

You can specify "all" (MCI_ALL_DEVICE_ID) as a device identifier for any command that does not return information. When you specify "all", MCI sends the command sequentially to all devices opened by the current application.

For example, the close "all" command closes all open devices and the play "all" command starts playing all devices opened by the application. Because MCI sequentially sends the commands to the MCI devices, there is an interval between when the first and last devices receive the command.

Using "all" is a convenient way to broadcast a command to all your devices, but you should not rely on it to synchronize devices; the timing between messages can vary.


Automatically Opening a Device

When you issue a command and specify a device that is not open, MCI tries to open the device before implementing the command. The following rules apply to automatically opening devices :

•	Automatic open works only with the command-string interface.

•	Automatic open fails for commands that are specific to custom device drivers.

•	Automatically opened devices do not respond to commands that use "all" as a device name.

•	Automatic open does not let your application specify the "type" flag. Without the device name, MCI determines the device name from the entries in the registry. To use a specific device, you can combine the device name with the filename by using the exclamation point, as described in the reference material for the open command.

If an application uses automatic open to open a device, the application should check the return value of every subsequent open command to verify that the device is still open. MCI also automatically closes any device that it automatically opens. MCI typically closes a device in the following situations:

•	The command is completed.

•	You abort the command.

•	You request notification in a subsequent command.

•	MCI detects a failure.


MCI Functions, Macros, and Messages

Most MCI applications use the mciSendString and mciSendCommand functions dozens of times. MCI provides some other useful functions that your application will use less frequently.

The device identifier that is required by most MCI commands is typically retrieved in a call to the open (MCI_OPEN) command. If you need a device identifier but do not want to open the device — for example, if you want to query the capabilities of the device before taking any other action — you can call the mciGetDeviceID function.

The mciGetCreatorTask function allows your application to use a device identifier to retrieve a handle to the task that created that identifier.

You can use the mciGetYieldProc and mciSetYieldProc functions to assign and retrieve the address of the callback function associated with the "wait" (MCI_WAIT) flag.

The mciGetErrorString function retrieves a string that describes an MCI error value. Each string that MCI returns, whether data or an error description, is a maximum of 128 characters. Dialog box fields that are smaller than 128 characters will truncate the longer strings returned by MCI. For more information about these strings, see "Constants: MCIERR Return Values" later in this chapter.

The MCI macros are tools you can use to create and disassemble values that specify time formats. These time formats are used in many MCI commands. The formats acted on by the macros are hours/minutes/seconds (HMS), minutes/seconds/frames (MSF), and tracks/minutes/seconds/frames (TMSF). The following table lists the macros and their descriptions:

Macro	Description
MCI_HMS_HOUR	Retrieves the hours component from an HMS value.
MCI_HMS_MINUTE	Retrieves the minutes component from an HMS value.
MCI_HMS_SECOND	Retrieves the seconds component from an HMS value.
MCI_MAKE_HMS	Creates an HMS value.
MCI_MAKE_MSF	Creates an MSF value.
MCI_MAKE_TMSF	Creates a TMSF value.
MCI_MSF_FRAME	Retrieves the frames component from an MSF value.
MCI_MSF_MINUTE	Retrieves the minutes component from an MSF value.
MCI_MSF_SECOND	Retrieves the seconds component from an MSF value.
MCI_TMSF_FRAME	Retrieves the frames component from a TMSF value.
MCI_TMSF_MINUTE	Retrieves the minutes component from a TMSF value.
MCI_TMSF_SECOND	Retrieves the seconds component from a TMSF value.
MCI_TMSF_TRACK	Retrieves the tracks component from a TMSF value.
MCI also provides two messages: MM_MCINOTIFY and MM_MCISIGNAL. MM_MCINOTIFY notifies an application of the outcome of an MCI command whenever that command specifies the "notify" (MCI_NOTIFY) flag. MM_MCISIGNAL is specific to digital-video devices; it notifies the application when a specified position is reached.


Device-Specific Command Sets

This section lists the commands supported by each device type.


Animation Command Set

Animation devices support the following set of commands:

String form	Message form
break	MCI_BREAK
capability	MCI_GETDEVCAPS
close	MCI_CLOSE
info	MCI_INFO
open	MCI_OPEN
pause	MCI_PAUSE
play	MCI_PLAY
put	MCI_PUT
realize	MCI_REALIZE
resume	MCI_RESUME
seek	MCI_SEEK
set	MCI_SET
status	MCI_STATUS
step	MCI_STEP
stop	MCI_STOP
sysinfo	MCI_SYSINFO
update	MCI_UPDATE
where	MCI_WHERE
window	MCI_WINDOW


CD Audio Command Set

CD audio devices support the following set of commands:

String form	Message form
break	MCI_BREAK
capability	MCI_GETDEVCAPS
close	MCI_CLOSE
info	MCI_INFO
open	MCI_OPEN
pause	MCI_PAUSE
play	MCI_PLAY
resume	MCI_RESUME
seek	MCI_SEEK
set	MCI_SET
status	MCI_STATUS
stop	MCI_STOP
sysinfo	MCI_SYSINFO


Digital-Video Command Set

Digital-video devices (for example, the MCIAVI driver) support the following set of commands:

String form	Message form
break	MCI_BREAK
capability	MCI_GETDEVCAPS
capture	MCI_CAPTURE
close	MCI_CLOSE
configure	MCI_CONFIGURE
copy	MCI_COPY
cue	MCI_CUE
cut	MCI_CUT
delete	MCI_DELETE
freeze	MCI_FREEZE
info	MCI_INFO
list	MCI_LIST
load	MCI_LOAD
monitor	MCI_MONITOR
open	MCI_OPEN
paste	MCI_PASTE
pause	MCI_PAUSE
play	MCI_PLAY
put	MCI_PUT
quality	MCI_QUALITY
realize	MCI_REALIZE
record	MCI_RECORD
reserve	MCI_RESERVE
restore	MCI_RESTORE
resume	MCI_RESUME
save	MCI_SAVE
seek	MCI_SEEK
set	MCI_SET
setaudio	MCI_SETAUDIO
setvideo	MCI_SETVIDEO
signal	MCI_SIGNAL
status	MCI_STATUS
step	MCI_STEP
stop	MCI_STOP
sysinfo	MCI_SYSINFO
undo	MCI_UNDO
unfreeze	MCI_UNFREEZE
update	MCI_UPDATE
where	MCI_WHERE
window	MCI_WINDOW


MIDI Sequencer Command Set

The MIDI sequencer supports the following set of commands:

String form	Message form
break	MCI_BREAK
capability	MCI_GETDEVCAPS
close	MCI_CLOSE
info	MCI_INFO
open	MCI_OPEN
pause	MCI_PAUSE
play	MCI_PLAY
record	MCI_RECORD
resume	MCI_RESUME
save	MCI_SAVE
seek	MCI_SEEK
set	MCI_SET
status	MCI_STATUS
stop	MCI_STOP
sysinfo	MCI_SYSINFO


VCR Command Set

VCRs support the following set of commands:

String form	Message form
break	MCI_BREAK
capability	MCI_GETDEVCAPS
cue	MCI_CUE
freeze	MCI_FREEZE
index	MCI_INDEX
info	MCI_INFO
list	MCI_LIST
mark	MCI_MARK
pause	MCI_PAUSE
play	MCI_PLAY
record	MCI_RECORD
resume	MCI_RESUME
seek	MCI_SEEK
set	MCI_SET
setaudio	MCI_SETAUDIO
settimecode	MCI_SETTIMECODE
settuner	MCI_SETTUNER
setvideo	MCI_SETVIDEO
status	MCI_STATUS
step	MCI_STEP
stop	MCI_STOP
sysinfo	MCI_SYSINFO
unfreeze	MCI_UNFREEZE


Videodisc Command Set

Videodisc devices support the following set of commands:

String form	Message form
break	MCI_BREAK
capability	MCI_GETDEVCAPS
close	MCI_CLOSE
escape	MCI_ESCAPE
info	MCI_INFO
open	MCI_OPEN
pause	MCI_PAUSE
play	MCI_PLAY
resume	MCI_RESUME
seek	MCI_SEEK
set	MCI_SET
spin	MCI_SPIN
status	MCI_STATUS
step	MCI_STEP
stop	MCI_STOP
sysinfo	MCI_SYSINFO


Video-Overlay Command Set

Video-overlay devices support the following set of commands:

String form	Message form
break	MCI_BREAK
capability	MCI_GETDEVCAPS
close	MCI_CLOSE
freeze	MCI_FREEZE
info	MCI_INFO
load	MCI_LOAD
open	MCI_OPEN
put	MCI_PUT
save	MCI_SAVE
set	MCI_SET
status	MCI_STATUS
sysinfo	MCI_SYSINFO
unfreeze	MCI_UNFREEZE
where	MCI_WHERE
window	MCI_WINDOW


Waveform-Audio Command Set

Waveform-audio devices support the following set of commands:

String form	Message form
break	MCI_BREAK
capability	MCI_GETDEVCAPS
close	MCI_CLOSE
cue	MCI_CUE
delete	MCI_DELETE
info	MCI_INFO
open	MCI_OPEN
pause	MCI_PAUSE
play	MCI_PLAY
record	MCI_RECORD
resume	MCI_RESUME
save	MCI_SAVE
seek	MCI_SEEK
set	MCI_SET
status	MCI_STATUS
stop	MCI_STOP
sysinfo	MCI_SYSINFO


MCI Reference

This section describes the MCI functions, macros, messages, and error values. These elements are grouped as follows.

Notifications

MM_MCINOTIFY
MM_MCISIGNAL

Retrieving Information

mciGetCreatorTask
mciGetDeviceID
mciGetErrorString

Sending Commands

mciSendCommand
mciSendString

Time Formats

MCI_HMS_HOUR
MCI_HMS_MINUTE
MCI_HMS_SECOND
MCI_MAKE_HMS
MCI_MAKE_MSF
MCI_MAKE_TMSF
MCI_MSF_FRAME
MCI_MSF_MINUTE
MCI_MSF_SECOND
MCI_TMSF_FRAME
MCI_TMSF_MINUTE
MCI_TMSF_SECOND
MCI_TMSF_TRACK

Yield Procedures

mciGetYieldProc
mciSetYieldProc


mciGetCreatorTask

HANDLE mciGetCreatorTask(MCIDEVICEID IDDevice);

Retrieves a handle to the creator task for the specified device.

•	Returns the handle of the creator task responsible for opening the device if successful. If the device identifier is invalid, the return value is NULL.

IDDevice

Device for which the creator task is returned.


mciGetDeviceID

MCIDEVICEID mciGetDeviceID(LPCTSTR lpszDevice);

Retrieves the device identifier corresponding to the name of an open device.

•	Returns the device identifier assigned to the device when it was opened if successful. The identifier is used in the mciSendCommand function. If the device name is not known, if the device is not open, or if there was not enough memory to complete the operation, the return value is zero.

lpszDevice

Address of a null-terminated string that specifies the device name or the alias name by which the device is known.

Each file for a compound device has a unique device identifier. The identifier of the "all" device is MCI_ALL_DEVICE_ID.


mciGetErrorString

BOOL mciGetErrorString(DWORD fdwError, LPTSTR lpszErrorText,
    UINT cchErrorText);

Retrieves a string that describes the specified MCI error code.

•	Returns TRUE if successful or FALSE if the error code is not known.

fdwError

Error code returned by the mciSendCommand or mciSendString function.

lpszErrorText

Address of a buffer that receives a null-terminated string describing the specified error.

cchErrorText

Length of the buffer, in characters, pointed to by the lpszErrorText parameter.

Each string that MCI returns, whether data or an error description, can be a maximum of 128 characters.


mciGetYieldProc

YIELDPROC mciGetYieldProc(MCIDEVICEID IDDevice, LPDWORD lpdwYieldData);

Retrieves the address of the callback function associated with the "wait" (MCI_WAIT) flag. The callback function is called periodically while an MCI device waits for a command specified with the "wait" flag to finish.

•	Returns the address of the current yield callback function if successful or NULL if the device identifier is invalid.

IDDevice

MCI device being monitored (the device performing an MCI command).

lpdwYieldData

Address of a buffer containing yield data to be passed to the callback function. This parameter can be NULL if there is no yield data.


mciSendCommand

MCIERROR mciSendCommand(MCIDEVICEID IDDevice, UINT uMsg,
    DWORD fdwCommand, DWORD dwParam);

Sends a command message to the specified MCI device.

•	Returns zero if successful or an error otherwise. The low-order word of the returned doubleword value contains the error return value. If the error is device-specific, the high-order word of the return value is the driver identifier; otherwise, the high-order word is zero. For a list of possible return values, see "Constants: MCIERR Return Values" later in this chapter.

To retrieve a text description of mciSendCommand return values, pass the return value to the mciGetErrorString function.

IDDevice

Device identifier of the MCI device that is to receive the command message. This parameter is not used with the MCI_OPEN command message.

uMsg

Command message.  For information about command messages, see Chapter 5, "MCI Command Messages."

fdwCommand

Flags for the command message.

dwParam

Address of a structure that contains parameters for the command message.

Error values that are returned when a device is being opened are listed with the MCI_OPEN command message. In addition to the MCI_OPEN error return values, this function can return the values listed in "Constants: MCIERR Return Values" later in this chapter.

Use MCI_OPEN to obtain the device identifier specified by the IDDevice parameter.


mciSendString

MCIERROR mciSendString(LPCTSTR lpszCommand, LPTSTR lpszReturnString,
    UINT cchReturn, HANDLE hwndCallback);

Sends a command string to an MCI device. The device that the command is sent to is specified in the command string.

•	Returns zero if successful or an error otherwise. The low-order word of the returned doubleword value contains the error return value. If the error is device-specific, the high-order word of the return value is the driver identifier; otherwise, the high-order word is zero. For a list of possible error values, see "Constants: MCIERR Return Values" later in this chapter.

To retrieve a text description of mciSendString return values, pass the return value to the mciGetErrorString function.

lpszCommand

Address of a null-terminated string that specifies an MCI command string. For more information about the command strings, see Chapter 4, "MCI Command Strings."

lpszReturnString

Address of a buffer that receives return information. If no return information is needed, this parameter can be NULL.

cchReturn

Size, in characters, of the return buffer specified by the lpszReturnString parameter.

hwndCallback

Handle of a callback window if the "notify" flag was specified in the command string.


mciSetYieldProc

UINT mciSetYieldProc(MCIDEVICEID IDDevice, YIELDPROC yp,
    DWORD dwYieldData);

Sets the address of a procedure to be called periodically when an MCI device is waiting for a command to finish because the "wait" (MCI_WAIT) flag was specified.

•	Returns TRUE if successful or FALSE otherwise.

IDDevice

Identifier of the device to assign a procedure to.

yp

Address of the procedure to call when yielding for the specified device. If this parameter is NULL, the function disables any existing yield procedure.

dwYieldData

Data to be sent to the yield procedure when it is called for the specified device.

This function overrides any previous yield procedure for this device.


MCI_HMS_HOUR

BYTE MCI_HMS_HOUR(DWORD dwHMS)

Retrieves the hours component from a parameter containing packed hours/minutes/seconds (HMS) information.

•	Returns the hours component of the specified HMS information.

dwHMS

Time in HMS format.

Time in HMS format is expressed as a doubleword value with the least significant byte containing hours, the next least significant byte containing minutes, and the next least significant byte containing seconds. The most significant byte is unused.

The MCI_HMS_HOUR macro is defined as follows:

#define MCI_HMS_HOUR(hms) ((BYTE)(hms))


MCI_HMS_MINUTE

BYTE MCI_HMS_MINUTE(DWORD dwHMS)

Retrieves the minutes component from a parameter containing packed hours/minutes/seconds (HMS) information.

•	Returns the minutes component of the specified HMS information.

dwHMS

Time in HMS format.

Time in HMS format is expressed as a doubleword value with the least significant byte containing hours, the next least significant byte containing minutes, and the next least significant byte containing seconds. The most significant byte is unused.

The MCI_HMS_MINUTE macro is defined as follows:

#define MCI_HMS_MINUTE(hms) ((BYTE)(((WORD)(hms)) >> 8))


MCI_HMS_SECOND

BYTE MCI_HMS_SECOND(DWORD dwHMS)

Retrieves the seconds component from a parameter containing packed hours/minutes/seconds (HMS) information.

•	Returns the seconds component of the specified HMS information.

dwHMS

Time in HMS format.

Time in HMS format is expressed as a doubleword value with the least significant byte containing hours, the next least significant byte containing minutes, and the next least significant byte containing seconds. The most significant byte is unused.

The MCI_HMS_SECOND macro is defined as follows:

#define MCI_HMS_SECOND(hms) ((BYTE)((hms) >> 16))


MCI_MAKE_HMS

DWORD MCI_MAKE_HMS(BYTE hours, BYTE minutes, BYTE seconds)

Creates a time value in packed hours/minutes/seconds (HMS) format from the given hours, minutes, and seconds values.

•	Returns the time in packed HMS format.

hours, minutes, and seconds

Number of hours, minutes, and seconds.

Time in HMS format is expressed as a doubleword value with the least significant byte containing hours, the next least significant byte containing minutes, and the next least significant byte containing seconds. The most significant byte is unused.

The MCI_MAKE_HMS macro is defined as follows:

#define MCI_MAKE_HMS(h, m, s) ((DWORD)(((BYTE)(h) | \

                              ((WORD)(m) << 8)) | \

                              (((DWORD)(BYTE)(s)) << 16)))


MCI_MAKE_MSF

DWORD MCI_MAKE_MSF(BYTE minutes, BYTE seconds, BYTE frames)

Creates a time value in packed minutes/seconds/frames (MSF) format from the given minutes, seconds, and frame values.

•	Returns the time in packed MSF format.

minutes, seconds, and frames

Number of minutes, seconds, and frames.

Time in MSF format is expressed as a doubleword value with the least significant byte containing minutes, the next least significant byte containing seconds, and the next least significant byte containing frames. The most significant byte is unused.

The MCI_MAKE_MSF macro is defined as follows:

#define MCI_MAKE_MSF(m, s, f) ((DWORD)(((BYTE)(m) | \

                              ((WORD)(s) << 8)) | \

                              (((DWORD)(BYTE)(f)) << 16)))


MCI_MAKE_TMSF

DWORD MCI_MAKE_TMSF(BYTE tracks, BYTE minutes, BYTE seconds,
    BYTE frames)

Creates a time value in packed tracks/minutes/seconds/frames (TMSF) format from the given tracks, minutes, seconds, and frames values.

•	Returns the time in packed TMSF format.

tracks, minutes, seconds, and frames

Number of tracks, minutes, seconds, and frames.

Time in TMSF format is expressed as a doubleword value with the least significant byte containing tracks, the next least significant byte containing minutes, the next least significant byte containing seconds, and the most significant byte containing frames.

The MCI_MAKE_TMSF macro is defined as follows:

#define MCI_MAKE_TMSF(t, m, s, f) ((DWORD)(((BYTE)(t) | \

                                  ((WORD)(m) << 8)) | \

                                  (((DWORD)(BYTE)(s) | \

                                  ((WORD)(f) << 8)) << 16)))


MCI_MSF_FRAME

BYTE MCI_MSF_FRAME(DWORD dwMSF)

Creates the frames component from a parameter containing packed minutes/seconds/frames (MSF) information.

•	Returns the frames component of the specified MSF information.

dwMSF

Time in MSF format.

Time in MSF format is expressed as a doubleword value with the least significant byte containing minutes, the next least significant byte containing seconds, and the next least significant byte containing frames. The most significant byte is unused.

The MCI_MSF_FRAME macro is defined as follows:

#define MCI_MSF_FRAME(msf) ((BYTE)((msf) >> 16))


MCI_MSF_MINUTE

BYTE MCI_MSF_MINUTE(DWORD dwMSF)

Retrieves the minutes component from a parameter containing packed minutes/seconds/frames (MSF) information.

•	Returns the minutes component of the specified MSF information.

dwMSF

Time in MSF format.

Time in MSF format is expressed as a doubleword value with the least significant byte containing minutes, the next least significant byte containing seconds, and the next least significant byte containing frames. The most significant byte is unused.

The MCI_MSF_MINUTE macro is defined as follows:

#define MCI_MSF_MINUTE(msf) ((BYTE)(msf))


MCI_MSF_SECOND

BYTE MCI_MSF_SECOND(DWORD dwMSF)

Retrieves the seconds component from a parameter containing packed minutes/seconds/frames (MSF) information.

•	Returns the seconds component of the specified MSF information.

dwMSF

Time in MSF format.

Time in MSF format is expressed as a doubleword value with the least significant byte containing minutes, the next least significant byte containing seconds, and the next least significant byte containing frames. The most significant byte is unused.

The MCI_MSF_SECOND macro is defined as follows:

#define MCI_MSF_SECOND(msf) ((BYTE)(((WORD)(msf)) >> 8))


MCI_TMSF_FRAME

BYTE MCI_TMSF_FRAME(DWORD dwTMSF)

Retrieves the frames component from a parameter containing packed tracks/minutes/seconds/frames (TMSF) information.

•	Returns the frames component of the specified TMSF information.

dwTMSF

Time in TMSF format.

Time in TMSF format is expressed as a doubleword value with the least significant byte containing tracks, the next least significant byte containing minutes, the next least significant byte containing seconds, and the most significant byte containing frames.

The MCI_TMSF_FRAME macro is defined as follows:

#define MCI_TMSF_FRAME(tmsf) ((BYTE)((tmsf) >> 24))


MCI_TMSF_MINUTE

BYTE MCI_TMSF_MINUTE(DWORD dwTMSF)

Retrieves the minutes component from a parameter containing packed tracks/minutes/seconds/frames (TMSF) information.

•	Returns the minutes component of the specified TMSF information.

dwTMSF

Time in TMSF format.

Time in TMSF format is expressed as a doubleword value with the least significant byte containing tracks, the next least significant byte containing minutes, the next least significant byte containing seconds, and the most significant byte containing frames.

The MCI_TMSF_MINUTE macro is defined as follows:

#define MCI_TMSF_MINUTE(tmsf) ((BYTE)(((WORD)(tmsf)) >> 8))


MCI_TMSF_SECOND

BYTE MCI_TMSF_SECOND(DWORD dwTMSF)

Retrieves the seconds component from a parameter containing packed tracks/minutes/seconds/frames (TMSF) information.

•	Returns the seconds component of the specified TMSF information.

dwTMSF

Time in TMSF format.

Time in TMSF format is expressed as a doubleword value with the least significant byte containing tracks, the next least significant byte containing minutes, the next least significant byte containing seconds, and the most significant byte containing frames.

The MCI_TMSF_SECOND macro is defined as follows:

#define MCI_TMSF_SECOND(tmsf) ((BYTE)((tmsf) >> 16))


MCI_TMSF_TRACK

BYTE MCI_TMSF_TRACK(DWORD dwTMSF)

Retrieves the tracks component from a parameter containing packed tracks/minutes/seconds/frames (TMSF) information.

•	Returns the tracks component of the specified TMSF information.

dwTMSF

Time in TMSF format.

Time in TMSF format is expressed as a doubleword value with the least significant byte containing tracks, the next least significant byte containing minutes, the next least significant byte containing seconds, and the most significant byte containing frames.

The MCI_TMSF_TRACK macro is defined as follows:

#define MCI_TMSF_TRACK(tmsf) ((BYTE)(tmsf))


MM_MCINOTIFY

MM_MCINOTIFY

wParam = (WPARAM) wFlags

lParam = (LONG) lDevID

Notifies an application that an MCI device has completed an operation. MCI devices send this message only when the "notify" (MCI_NOTIFY) flag is used.

•	Returns zero if successful or an error otherwise.

wFlags

Reason for the notification. The following values are defined:

MCI_NOTIFY_ABORTED

The device received a command that prevented the current conditions for initiating the callback function from being met. If a new command interrupts the current command and it also requests notification, the device sends this message only and not MCI_NOTIFY_SUPERCEDED.

MCI_NOTIFY_FAILURE

A device error occurred while the device was executing the command.

MCI_NOTIFY_SUCCESSFUL

The conditions initiating the callback function have been met.

MCI_NOTIFY_SUPERSEDED

The device received another command with the "notify" flag set and the current conditions for initiating the callback function have been superseded.

lDevID

Identifier of the device initiating the callback function.

For more information about the "notify" (MCI_NOTIFY) flag, see "The "Notify" Flag" earlier in this chapter.

A device returns the MCI_NOTIFY_SUCCESSFUL flag with MM_MCINOTIFY when the action for a command finishes. For example, a CD audio device uses this flag for notification for the play (MCI_PLAY) command when the device finishes playing. The play command is successful only when it reaches the specified end position or reaches the end of the media. Similarly, the seek (MCI_SEEK) and record (MCI_RECORD) commands do not return MCI_NOTIFY_SUCCESSFUL until they reach the specified end position or reach the end of the media.

A device returns the MCI_NOTIFY_ABORTED flag with MM_MCINOTIFY only when it receives a command that prevents it from meeting the notification conditions. For example, the play command would not abort notification for a previous play command provided that the new command does not change the play direction or change the ending position. The seek and record commands behave similarly. MCI also does not send MCI_NOTIFY_ABORTED when playback or recording is paused with the pause (MCI_PAUSE) command. Sending the resume (MCI_RESUME) command allows them to continue to meet the callback conditions.

When your application requests notification for a command, check the error return of the mciSendString or mciSendCommand functions. If these functions encounter an error and return a nonzero value, MCI will not set notification for the command.


MM_MCISIGNAL

MM_MCISIGNAL

wParam = (WPARAM) wID
lParam = (LONG) lUserParm

Sent to a window to notify an application that an MCI device has reached a position defined in a previous signal (MCI_SIGNAL) command.

wID

Identifier of the device initiating the signal message.

lUserParm

Value passed in the dwUserParm member of the MCI_DGV_SIGNAL_PARAMS structure when the signal command has defined this callback function. Alternatively, it might contain the position value.


Constants: MCIERR Return Values

The mciSendCommand and mciSendString functions return zero if they are successful; otherwise, they return a doubleword value that contains one of the following error values in the low word. You can obtain a description of individual return values by passing the return values to the mciGetErrorString function.


General Error Values

The following error values can be returned by either the mciSendCommand or mciSendString function:

Value	Meaning
MCIERR_BAD_TIME_FORMAT	The specified value for the time format is invalid.
MCIERR_CANNOT_LOAD_DRIVER	The specified device driver will not load properly.
MCIERR_CANNOT_USE_ALL	The device name "all" is not allowed for this command.
MCIERR_CREATEWINDOW	Could not create or use window.
MCIERR_DEVICE_LENGTH	The device or driver name is too long. Specify a device or driver name that is less than 79 characters.
MCIERR_DEVICE_LOCKED	The device is now being closed. Wait a few seconds, then try again.
MCIERR_DEVICE_NOT_INSTALLED	The specified device is not installed on the system. Use the Drivers option from the Control Panel to install the device.
MCIERR_DEVICE_NOT_READY	The device driver is not ready.
MCIERR_DEVICE_OPEN	The device name is already used as an alias by this application. Use a unique alias.
MCIERR_DEVICE_ORD_LENGTH	The device or driver name is too long. Specify a device or driver name that is less than 79 characters.
MCIERR_DEVICE_TYPE_REQUIRED	The specified device cannot be found on the system. Check that the device is installed and the device name is spelled correctly.
MCIERR_DRIVER	The device driver exhibits a problem. Check with the device manufacturer about obtaining a new driver.
MCIERR_DRIVER_INTERNAL	The device driver exhibits a problem. Check with the device manufacturer about obtaining a new driver.
MCIERR_DUPLICATE_ALIAS	The specified alias is already used in this application. Use a unique alias.
MCIERR_EXTENSION_NOT_FOUND	The specified extension has no device type associated with it. Specify a device type.
MCIERR_EXTRA_CHARACTERS	You must enclose a string with quotation marks; characters following the closing quotation mark are not valid.
MCIERR_FILE_NOT_FOUND	The requested file was not found. Check that the path and filename are correct.
MCIERR_FILE_NOT_SAVED	The file was not saved. Make sure your system has sufficient disk space or has an intact network connection.
MCIERR_FILE_READ	A read from the file failed. Make sure the file is present on your system or that your system has an intact network connection.
MCIERR_FILE_WRITE	A write to the file failed. Make sure your system has sufficient disk space or has an intact network connection.
MCIERR_FILENAME_REQUIRED	The filename is invalid. Make sure the filename is no longer than eight characters, followed by a period and an extension.
MCIERR_FLAGS_NOT_COMPATIBLE	The specified parameters cannot be used together.
MCIERR_GET_CD	The requested file OR MCI device was not found. Try changing directories or restarting your system.
MCIERR_HARDWARE	The specified device exhibits a problem. Check that the device is working correctly or contact the device manufacturer.
MCIERR_ILLEGAL_FOR_AUTO_OPEN	MCI will not perform the specified command on an automatically opened device. Wait until the device is closed, then try to perform the command.
MCIERR_INTERNAL	A problem occurred in initializing MCI. Try restarting the Windows operating system.
MCIERR_INVALID_DEVICE_ID	Invalid device ID. Use the ID given to the device when the device was opened.
MCIERR_INVALID_DEVICE_NAME	The specified device is not open nor recognized by MCI.
MCIERR_INVALID_FILE	The specified file cannot be played on the specified MCI device. The file may be corrupt or may use an incorrect file format.
MCIERR_MISSING_PARAMETER	The specified command requires a parameter, which you must supply.
MCIERR_MULTIPLE	Errors occurred in more than one device. Specify each command and device separately to identify the devices causing the errors.
MCIERR_MUST_USE_SHAREABLE	The device driver is already in use. You must specify the "shareable" parameter with each open command to share the device.
MCIERR_NO_ELEMENT_ALLOWED	The specified device does not use a filename.
MCIERR_NO_INTEGER	The parameter for this MCI command must be an integer value.
MCIERR_NO_WINDOW	There is no display window.
MCIERR_NONAPPLICABLE_FUNCTION	The specified MCI command sequence cannot be performed in the given order. Correct the command sequence; then, try again.
MCIERR_NULL_PARAMETER_BLOCK	A null parameter block (structure) was passed to MCI.
MCIERR_OUT_OF_MEMORY	Your system does not have enough memory for this task. Quit one or more applications to increase the available memory, then, try to perform the task again.
MCIERR_OUTOFRANGE	The specified parameter value is out of range for the specified MCI command.
MCIERR_SET_CD	The specified file or MCI device is inaccessible because the application cannot change directories.
MCIERR_SET_DRIVE	The specified file or MCI device is inaccessible because the application cannot change drives.
MCIERR_UNNAMED_RESOURCE	You cannot store an unnamed file. Specify a filename.
MCIERR_UNRECOGNIZED_COMMAND	The driver cannot recognize the specified command.
MCIERR_UNSUPPORTED_FUNCTION	The MCI device driver the system is using does not support the specified command.


mciSendString Errors

The following errors are returned by the mciSendString function but not by mciSendCommand:

Value	Meaning
MCIERR_BAD_CONSTANT	The value specified for a parameter is unknown.
MCIERR_BAD_INTEGER	An integer in the command was invalid or missing.
MCIERR_DUPLICATE_FLAGS	A flag or value was specified twice.
MCIERR_MISSING_COMMAND_STRING	No command was specified.
MCIERR_MISSING_DEVICE_NAME	No device name was specified.
MCIERR_MISSING_STRING_ARGUMENT	A string value was missing from the command.
MCIERR_NEW_REQUIRES_ALIAS	An alias must be used with the "new" device name.
MCIERR_NO_CLOSING_QUOTE	A closing quotation mark is missing.
MCIERR_NOTIFY_ON_AUTO_OPEN	The "notify" flag is illegal with auto-open.
MCIERR_PARAM_OVERFLOW	The output string was not long enough.
MCIERR_PARSER_INTERNAL	An internal parser error occurred.
MCIERR_UNRECOGNIZED_KEYWORD	An unknown command parameter was specified.


Digital-Video Errors

The following additional return values are defined for digital-video devices:

Value	Meaning
MCIAVI_PRODUCTNAME	Video
MCIERR_AVI_AUDIOERROR	Unknown error while attempting to play audio.
MCIERR_AVI_BADPALETTE	Unable to switch to new palette.
MCIERR_AVI_CANTPLAYFULLSCREEN	This AVI file cannot be played in full screen mode.
MCIERR_AVI_DISPLAYERROR	Unknown error while attempting to display video.
MCIERR_AVI_NOCOMPRESSOR	Can't locate installable compressor needed to play this file.
MCIERR_AVI_NODISPDIB	256 color VGA mode not available.
MCIERR_AVI_NOTINTERLEAVED	This AVI file is not interleaved.
MCIERR_AVI_OLDAVIFORMAT	This AVI file is of an obsolete format.
MCIERR_AVI_TOOBIGFORVGA	This AVI file is too big to be played in the selected VGA mode.


Sequencer Errors

The following additional return values are defined for MCI sequencers:

Value	Meaning
MCIERR_SEQ_DIV_INCOMPATIBLE	The time formats of the "song pointer" and SMPTE are singular. You can't use them together.
MCIERR_SEQ_NOMIDIPRESENT	This system has no installed MIDI devices. Use the Drivers option from the Control Panel to install a MIDI driver.
MCIERR_SEQ_PORT_INUSE	The specified MIDI port is already in use. Wait until it is free; then, try again.
MCIERR_SEQ_PORT_MAPNODEVICE	The current MIDI Mapper setup refers to a MIDI device that is not installed on the system. Use the MIDI Mapper from the Control Panel to edit the setup.
MCIERR_SEQ_PORT_MISCERROR	An error occurred with specified port.
MCIERR_SEQ_PORT_NONEXISTENT	The specified MIDI device is not installed on the system. Use the Drivers option from the Control Panel to install a MIDI device.
MCIERR_SEQ_PORTUNSPECIFIED	The system does not have a current MIDI port specified.
MCIERR_SEQ_TIMER	All multimedia timers are being used by other applications. Quit one of these applications; then, try again.


Waveform-Audio Errors

The following additional return values are defined for MCI waveform-audio devices:

Value	Meaning
MCIERR_WAVE_INPUTSINUSE	All waveform devices that can record files in the current format are in use. Wait until one of these devices is free; then, try again.
MCIERR_WAVE_INPUTSUNSUITABLE	No installed waveform device can record files in the current format. Use the Drivers option from the Control Panel to install a suitable waveform recording device.
MCIERR_WAVE_INPUTUNSPECIFIED	You can specify any compatible waveform recording device.
MCIERR_WAVE_OUTPUTSINUSE	All waveform devices that can play files in the current format are in use. Wait until one of these devices is free; then, try again.
MCIERR_WAVE_OUTPUTSUNSUITABLE	No installed waveform device can play files in the current format. Use the Drivers option from the Control Panel to install a suitable waveform device.
MCIERR_WAVE_OUTPUTUNSPECIFIED	You can specify any compatible waveform playback device.
MCIERR_WAVE_SETINPUTINUSE	The current waveform device is in use. Wait until the device is free; then, try again to set the device for recording.
MCIERR_WAVE_SETINPUTUNSUITABLE	The device you are using to record a waveform cannot recognize the data format.
MCIERR_WAVE_SETOUTPUTINUSE	The current waveform device is in use. Wait until the device is free; then, try again to set the device for playback.
MCIERR_WAVE_SETOUTPUTUNSUITABLE	The device you are using to playback a waveform cannot recognize the data format.


MCI Command Strings

The Media Control Interface (MCI) is a high-level command interface to multimedia devices and resource files. MCI provides standard commands for playing multimedia devices and recording multimedia resource files. MCI commands are a generic interface to multimedia devices.

There are two forms of MCI commands: strings and messages. You can use either or both forms in your MCI application. This chapter documents the command-string interface to MCI. For information about the command-message interface, see Chapter 5, "MCI Command Messages." For an overview of MCI, including information about whether you should use the string interface or the message interface in your application, see Chapter 3, "MCI Overview."

You can send a string command by using the mciSendString function, which includes parameters for the string command and a buffer for any returned information. For more information about mciSendString, see "Sending Command Strings" later in this chapter.


Syntax of Command Strings

MCI command strings use a consistent verb-object-modifier syntax. Each command string includes a command, a device identifier, and command arguments. Arguments are optional for some commands and required for others.

A command string has the following form:

command device_id arguments

These components contain the following information:

•	The command specifies an MCI command, such as open, close, or play.

•	The device_id identifies an instance of an MCI driver. The device_id is created when the device is opened.

•	The arguments specify the flags and variables used by the command. Flags are keywords recognized with the MCI command. Variables are numbers or strings that apply to the MCI command or flag.

For example, the play command uses the arguments "from position" and "to position" to indicate the positions to start and end playing. You can list the flags used with a command in any order. When you use a flag that has a variable associated with it, you must supply a value for the variable.

Unspecified (and optional) command arguments assume a default value.


Data Types for Command Variables

You can use the following data types for the variables in a command string:

Data type	Description
Strings	String data types are delimited by leading and trailing white spaces and quotation marks ("). MCI removes single quotation marks from a string. To put a quotation mark in a string, use a set of two quotation marks where you want to embed your quotation mark. To use an empty string, use two quotation marks delimited by leading and trailing white spaces.
Signed long integers	Signed long integer data types are delimited by leading and trailing white spaces. Unless otherwise specified, integers can be positive or negative. If you use negative integers, you should not separate the minus sign and the first digit with a space.
Rectangles	Rectangle data types are an ordered list of four signed short values. White space delimits this data type and separates each integer in the list.


Sending Command Strings

Windows provides two functions to send command strings to devices and to query devices for error information: The mciSendString function sends a command string to an MCI device. The mciGetErrorString function returns the error string corresponding to an error number.

The mciSendString function returns zero if successful. If the function fails, the low-order word of the return value contains an error code. You can pass this error code to mciGetErrorString to get a text description of it.


Using MCI Command Strings

This section contains examples demonstrating how to use the MCI command-string interface to perform the following tasks:

•	Send a command.

•	Open an audio-video interleaved (AVI) file.

•	Change the playback state.

•	Convert strings.


Sending a Command

The following example function sends the play command with the "from" and "to" flags.

DWORD PlayFromTo(LPSTR lpstrAlias, DWORD dwFrom, DWORD dwTo)

{

    char    achCommandBuff[128];

    wsprintf(achCommandBuff, "play %s from %u to %u",
        lpstrAlias, dwFrom, dwTo);

    return mciSendString(achCommandBuff, NULL, 0, NULL);

}


Opening Multiple AVI Files

If your application opens multiple files, it should include routines such as the following simple functions. The application would use the "initAVI" function during its initialization and the "termAVI" function during its termination.

// Initialize the MCIAVI driver. This returns TRUE if OK,

// FALSE on error.

BOOL initAVI(VOID)

{

    // Perform additional initialization before loading first file.

    return mciSendString("open digitalvideo", NULL, 0, NULL) == 0;

}

// Close the MCIAVI driver.

void termAVI(VOID)

{

    mciSendString("close digitalvideo", NULL, 0, NULL);

}


Changing the Playback State

The following examples show how to use the pause, resume, stop, and seek commands.

// Assume the file was opened with the alias 'movie'.

// Pause play.

mciSendString("pause movie", NULL, 0, NULL);

// Resume play.

mciSendString("resume movie", NULL, 0, NULL);

// Stop play.

mciSendString("stop movie", NULL, 0, NULL);

// Seek to the beginning.

mciSendString("seek movie to start", NULL, 0, NULL);

The following example shows how to change the seek mode:

// Set seek mode with the string interface.

// Assume the file was opened with the alias 'movie'.

void SetSeekMode(BOOL fExact)

{

    if (fExact)

        mciSendString("set movie seek exactly on", NULL, 0, NULL);

    else

        mciSendString("set movie seek exactly off", NULL, 0, NULL);

}


Converting Strings

When you use the string interface, all values passed with the command and all return values are text strings, so your application needs conversion routines to translate from variables to strings or back again. The following example retrieves the source rectangle and converts the returned string into rectangle coordinates.

void GetSourceRect(LPSTR lpstrAlias, LPRECT lprc)

{

    char achRetBuff[128];

    char achCommandBuff[128];

    // Build the command string.

    wsprintf(achCommandBuff, "where %s source", lpstrAlias);

    SetRectEmpty(lprc);    // clears the RECT

    // Send the command.

    if (mciSendString(achCommandBuff, achRetBuff,

        sizeof(achRetBuff), NULL) == 0){

        // The rectangle is returned as "x y dx dy".

        // Both x and y are 0 because this is the source

        // rectangle. Translate the string into the RECT

        // structure.

        char *p;

        p = achRetBuff;           // point to the return string

        while (*p != ' ') p++;    // go past the x (0)

        while (*p == ' ') p++;    // go past spaces

        while (*p != ' ') p++;    // go past the y (0)

        while (*p == ' ') p++;    // go past spaces

        // Retrieve the width.

        for ( ; *p != ' '; p++)

            lprc->right = (10 * lprc->right) + (*p - '0');

        while (*p == ' ') p++;    // go past spaces

        // Retrieve the height.

        for ( ; *p != ' '; p++)

            lprc->bottom = (10 * lprc->bottom) + (*p - '0');

    }

}

Note  RECT structures are handled differently in MCI than in other parts of Windows; in MCI, rc.right contains the width of the rectangle and rc.bottom contains its height. In the string interface, a rectangle is specified as X1 Y1 X2 Y2. The coordinates X1 Y1 specify the upper left corner of the rectangle, and the coordinates X2 Y2 specify the width and height.


MCI Command String Reference

This section describes the MCI command strings. These elements are grouped as follows.

Configuring a Device

break
configure
escape
index
set
setaudio
settimecode
settuner
setvideo
spin

Controlling Playback

freeze
load
pause
play
resume
stop
unfreeze

Controlling the Position

cue
mark
seek
signal
step

Editing

copy
cut
delete
paste
undo

Opening and Closing

close
open

Realizing a Palette

realize

Repainting a Frame

update

Retrieving Information

capability
info
list
status
sysinfo

Saving

record
save

Video Control

capture
monitor
quality
reserve
restore

Window or Display Rectangles

put
where
window


break

wsprintf(lpstrCommand, "break %s %s %s", lpszDeviceID, lpszVirtKey,
    lpszFlags);

Specifies a key to abort a command that was invoked using the "wait" flag. This command is an MCI system command; it is interpreted directly by MCI.

•	Returns zero if successful or an error otherwise.

lpszDeviceID

Identifier of an MCI device. This identifier or alias is assigned when the device is opened.

lpszVirtKey

One of the following flags:

on virtual key code	Specifies the key that aborts a command that was started using the "wait" flag.
off	Disables the current break key.
lpszFlags

Can be "wait", "notify", or both. For digital-video and VCR devices, "test" can also be specified. For more information about these flags, see Chapter 3, "MCI Overview."

When the break key is enabled and the user presses the key identified by the virtual-key code specified in the lpsVirtKey parameter, the device returns control to the application. If possible, the command continues execution.

The following command sets F2 as the break key for the "mysound" device:

break mysound on 113


capability

wsprintf(lpstrCommand, "capability %s %s %s", lpszDeviceID, lpszRequest,
    lpszFlags);

Requests information about a particular capability of a device. All MCI devices recognize this command.

•	Returns information in the lpstrReturnString parameter of the mciSendString function. The information is dependent on the request type.

lpszDeviceID

Identifier of an MCI device. This identifier or alias is assigned when the device is opened.

lpszRequest

Flag that identifies a device capability. The following table lists device types that recognize the capability command and the flags used by each type:

animation	can eject can play can record can reverse can save can stretch compound device device type	fast play rate has audio has video normal play rate slow play rate uses files uses palettes windows
cdaudio	can eject can play can record can save compound device	device type has audio has video uses files
digitalvideo	can eject can freeze can lock can play can record can reverse can save can stretch can stretch input can test	compound device device type has audio has still has video maximum play rate minimum play rate uses files uses palettes windows
overlay	can eject can freeze can play can record can save can stretch	compound device device type has audio has video uses files windows
sequencer	can eject can play can record can save compound device	device type has audio has video uses files
vcr	can detect length can eject can freeze can monitor sources can play can preroll can preview can record can reverse can save can test	clock increment rate compound device device type has audio has clock has timecode has video number of marks seek accuracy uses files
videodisc	can eject can play can record can reverse can save CAV CLV compound device	device type fast play rate has audio has video normal play rate slow play rate uses files
waveaudio	can eject can play can record can save compound device device type	has audio has video inputs outputs uses files
The following table lists the flags that can be specified in the lpszRequest parameter and their meanings:

can detect length	Returns TRUE if the device can detect the length of the media.
can eject	Returns TRUE if the device can eject the media.
can freeze	Returns TRUE if the device can freeze data in the frame buffer.
can lock	Returns TRUE if the device can lock data.
can monitor sources	Returns TRUE if the device can pass an input (source) to the monitored output, independent of the current input selection.
can play	Returns TRUE if the device can play.
can preroll	Returns TRUE if the device supports the "preroll" flag with the cue command.
can preview	Returns TRUE if the device supports previews.
can record	Returns TRUE if the device supports recording.
can reverse	Returns TRUE if the device can play in reverse.
can save	Returns TRUE if the device can save data.
can stretch	Returns TRUE if the device can stretch frames to fill a given display rectangle.
can stretch input	Returns TRUE if the device can resize an image in the process of digitizing it into the frame buffer.
can test	Returns TRUE if the device recognizes the test keyword.
cav	When combined with other items, this flag specifies that the return information applies to CAV format videodiscs. This is the default if no videodisc is inserted.
clock increment rate	Returns the number of subdivisions the external clock supports per second. If the external clock is a millisecond clock, the return value is 1000. If the return value is 0, no clock is supported.
clv	When combined with other items, this flag specifies that the return information applies to CLV format videodiscs.
compound device	Returns TRUE if the device supports an element name (filename).
device type	Returns a device type name, which can be one of the following: animation cdaudio dat digitalvideo other overlay scanner sequencer vcr videodisc waveaudio
fast play rate	Returns the fast play rate in frames per second, or zero if the device cannot play fast.
has audio	Returns TRUE if the device supports audio playback.
has clock	Returns TRUE if the device has a clock.
has still	Returns TRUE if the device treats files with a single image more efficiently than motion video files.
has timecode	Returns TRUE if the device is capable of supporting timecode, or if it is unknown.
has video	Returns TRUE if the device supports video.
inputs	Returns the total number of input devices.
maximum play rate	Returns the maximum play rate, in frames per second, for the device.
minimum play rate	Returns the minimum play rate, in frames per second, for the device.
normal play rate	Returns the normal play rate, in frames per second, for the device.
number of marks	Returns the maximum number of marks that can be used; zero indicates that marks are unsupported.
outputs	Returns the total number of output devices.
seek accuracy	Returns the expected accuracy of a search in frames; 0 indicates that the device is frame accurate, 1 indicates that the device expects to be within one frame of the indicated seek position, and so on.
slow play rate	Returns the slow play rate in frames per second, or zero if the device cannot play slowly.
uses files	Returns TRUE if the data storage used by a compound device is a file.
uses palettes	Returns TRUE if the device uses palettes.
windows	Returns the number of simultaneous display windows the device can support.
lpszFlags

Can be "wait", "notify", or both. For digital-video and VCR devices, "test" can also be specified. For more information about these flags, see Chapter 3, "MCI Overview."

The following command returns the device type of the "mysound" device:

capability mysound device type


capture

wsprintf(lpstrCommand, "capture %s %s %s", lpszDeviceID, lpszCapture,
    lpszFlags);

Copies the contents of the frame buffer and stores it in the specified file. Digital-video devices recognize this command.

•	Returns zero if successful or an error otherwise.

lpszDeviceID

Identifier of an MCI device. This identifier or alias is assigned when the device is opened.

lpszCapture

One or more of the following flags:

as pathname	Specifies the destination path and filename for the captured image. This flag is required.
at rectangle	Specifies the rectangular region within the frame buffer that the device crops and saves to disk. If omitted, the cropped region defaults to the rectangle specified or defaulted on a previous put "source" command for this device instance.
lpszFlags

Can be "wait", "notify", "test", or a combination of these. For more information about these flags, see Chapter 3, "MCI Overview."

This command might fail if the device is currently playing motion video or executing some other resource-intensive operation. If the frame buffer is being updated in real time, the updating momentarily pauses so that a complete image is captured. If the device pauses the updating, there might be a visual or audible effect. If the file format, compression algorithm, and quality levels have not been set, their defaults are used.


close

wsprintf(lpstrCommand, "close %s %s", lpszDeviceID, lpszFlags);

Closes the device or file and any associated resources. MCI unloads a device when all instances of the device or all files are closed. All MCI devices recognize this command.

•	Returns zero if successful or an error otherwise.

lpszDeviceID

Identifier of an MCI device. This identifier or alias is assigned when the device is opened.

lpszFlags

Can be "wait", "notify", or both. For more information about these flags, see Chapter 3, "MCI Overview."

To close all devices opened by your application, specify the "all" device identifier for the lpszDeviceID parameter.

The following command closes the "mysound" device:

close mysound


configure

wsprintf(lpstrCommand, "configure %s %s", lpszDeviceID, lpszFlags);

Displays a dialog box used to configure the device. Digital-video devices recognize this command.

•	Returns zero if successful or an error otherwise.

lpszDeviceID

Identifier of an MCI device. This identifier or alias is assigned when the device is opened.

lpszFlags

Can be "wait", "notify", or  "test". For more information about these flags, see Chapter 3, "MCI Overview."


copy

wsprintf(lpstrCommand, "copy %s %s %s", lpszDeviceID, lpszItem,
    lpszFlags);

Copies data to the clipboard. Digital-video devices recognize this command.

•	Returns zero if successful or an error otherwise.

lpszDeviceID

Identifier of an MCI device. This identifier or alias is assigned when the device is opened.

lpszItem

One of the following flags identifying the item to copy:

at rectangle	Specifies the portion of each frame that will be copied. If omitted, the default setting is the entire frame.
audio stream stream	Specifies the audio stream in the workspace affected by the command. If you use this flag and also want to copy video, you must also use the "video stream" flag. (If neither flag is specified, all audio and video streams are copied.)
from position	Specifies the start of the range copied. If omitted, the default setting is the current position.
to position	Specifies the end of the range copied. The audio and video data copied are exclusive of this position. If omitted, the default setting is the end of the workspace.
video stream stream	Specifies the video stream in the workspace affected by the command. If you use this flag and also want to copy audio, you must also use the "audio stream" flag. (If neither flag is specified, all audio and video streams are copied.)
lpszFlags

Can be "wait", "notify", "test", or a combination of these. For more information about these flags, see Chapter 3, "MCI Overview."


cue

wsprintf(lpstrCommand, "cue %s %s %s", lpszDeviceID, lpszInOutTo,
    lpszFlags);

Prepares for playing or recording. Digital-video, VCR, and waveform-audio devices recognize this command.

•	Returns zero if successful or an error otherwise.

lpszDeviceID

Identifier of an MCI device. This identifier or alias is assigned when the device is opened.

lpszInOutTo

Flag that prepares a device for playing or recording. The following table lists device types that recognize the cue command and the flags used by each type:

digitalvideo	input noshow	output to position
vcr	from position input output	preroll reverse to position
waveaudio	input	output
The following table lists the flags that can be specified in the lpszInOutTo parameter and their meanings:

from position	Indicates where to start.
input	Prepares for recording. For digital-video devices, this flag can be omitted if the current presentation source is already the external input.
noshow	Prepares for playing a frame without displaying it. When this flag is specified, the display continues to show the image in the frame buffer even though its corresponding frame is not the current position. A subsequent cue command without this flag and without the "to" flag displays the current frame.
output	Prepares for playing. If neither "input" nor "output" is specified, the default setting is "output".
preroll	Moves the preroll distance from the in-point. The in-point is the current position, or the position specified by the "from" flag.
reverse	Indicates play direction is in reverse (backward).
to position	Moves the workspace to the specified position. For VCR devices, this flag indicates where to stop.
lpszFlags

Can be "wait", "notify", or both. For digital-video and VCR devices, "test" can also be specified. For more information about these flags, see Chapter 3, "MCI Overview."

Although it is not necessary, issuing the cue command before playing or recording on some devices might reduce the delay before the device starts the action.

This command fails if playing or recording is in progress or if the device is paused.

When cueing for playback (using cue "output"), issuing the play command with the "from", "to", or "reverse" flag cancels the cue command.

When cueing for recording (using cue "input"), issuing the record command with the "from", "to", or "initialize" flag cancels the cue command.

The following command prepares the "mysound" device for recording:

cue mysound input


cut

wsprintf(lpstrCommand, "cut %s %s %s", lpszDeviceID, lpszItem,
    lpszFlags);

Removes data from the workspace and copies it to the clipboard. Digital-video devices recognize this command.

•	Returns zero if successful or an error otherwise.

lpszDeviceID

Identifier of an MCI device. This identifier or alias is assigned when the device is opened.

lpszItem

One of the following flags identifying the item to cut:

at rectangle	Specifies the portion of each frame cut. If omitted, it defaults to the entire frame. When this item is specified, frames are not deleted. Instead the area inside the rectangle becomes black.
audio stream stream	Specifies the audio stream in the workspace affected by the command. If you use this flag and also want to cut video, you must also use the "video stream" flag. (If neither flag is specified, all audio and video streams are cut.)
from position	Specifies the start of the range cut. If omitted, it defaults to the current position.
to position	Specifies the end of the range cut. The audio and video data cut are exclusive of this position. If omitted it defaults to the end of the workspace.
video stream stream	Specifies the video stream in the workspace affected by the command. If you use this flag and also want to cut audio, you must also use the "audio stream" flag. (If neither flag is specified, all audio and video streams are cut.)
lpszFlags

Can be "wait", "notify", "test", or a combination of these. For more information about these flags, see Chapter 3, "MCI Overview."

The change becomes permanent only when the data is explicitly saved; however, playback acts as if the data has been removed.


delete

wsprintf(lpstrCommand, "delete %s %s %s", lpszDeviceID, lpszPosition,
    lpszFlags);

Deletes a data segment from a file. Digital-video and waveform-audio devices recognize this command.

•	Returns zero if successful or an error otherwise.

lpszDeviceID

Identifier of an MCI device. This identifier or alias is assigned when the device is opened.

lpszPosition

Flag that identifies a data segment to delete. The following table lists device types that recognize the delete command and the flags used by each type:

digitalvideo	at rectangle audio stream stream from position	to position video stream stream
waveaudio	from position	to position
The following table lists the flags that can be specified in the lpszPosition parameter and their meanings:

at rectangle	Specifies the portion of each frame deleted. If omitted, it defaults to the entire frame. When this item is specified, frames are not deleted. Instead the area inside the rectangle becomes black.
audio stream stream	Specifies the audio stream in the workspace affected by the command. If you use this flag and also want to delete video, you must also use the "video stream" flag. (If neither flag is specified, all audio and video streams are deleted.)
from position	Specifies the position at which deletion begins. If this flag is omitted, the deletion begins at the current position.
to position	Specifies the position at which deletion ends. If this flag is omitted, the deletion continues to the end of the content or workspace.
video stream stream	Specifies the video stream in the workspace affected by the command. If you use this flag and also want to delete audio, you must also use "audio stream" flag. (If neither flag is specified, all audio and video streams are deleted.)
lpszFlags

Can be "wait", "notify", or both. For digital-video and VCR devices, "test" can also be specified. For more information about these flags, see Chapter 3, "MCI Overview."

Before issuing any commands that use position values, you should set the desired time format by using the set command.

The following command deletes the waveform-audio data from 1 millisecond through 900 milliseconds (assuming the time format is set to milliseconds):

delete mysound from 1 to 900


escape

wsprintf(lpstrCommand, "escape %s %s %s", lpszDeviceID, lpszEscape,
    lpszFlags);

Sends device-specific information to a device. Videodisc devices recognize this command.

•	Returns zero if successful or an error otherwise.

lpszDeviceID

Identifier of an MCI device. This identifier or alias is assigned when the device is opened.

lpszEscape

Custom information to send to the device.

lpszFlags

Can be "wait", "notify", or both. For more information about these flags, see Chapter 3, "MCI Overview."

The following command sends the escape string "SA" to the videodisc device:

escape videodisc SA


freeze

wsprintf(lpstrCommand, "freeze %s %s %s", lpszDeviceID, lpszFreezeFlags,
    lpszFlags);

Freezes video input or video output on a VCR or disables video acquisition to the frame buffer. Digital-video, video-overlay, and VCR devices recognize this command.

•	Returns zero if successful or an error otherwise.

lpszDeviceID

Identifier of an MCI device. This identifier or alias is assigned when the device is opened.

lpszFreezeFlags

Flag that identifies what to freeze. The following table lists device types that recognize the freeze command and the flags used by each type:

digitalvideo	at rectangle	outside
overlay	at rectangle
vcr	field frame	input output
The following table lists the flags that can be specified in the lpszFreezeFlags parameter and their meanings:

at rectangle	Specifies the region that will be frozen. For video-overlay devices, this region will have video acquisition disabled. For digital-video devices, the pixels within the rectangle will have their lock mask bit turned on (unless the "outside" flag is specified). The rectangle is relative to the video buffer origin and is specified as X1 Y1 X2 Y2. The coordinates X1 Y1 specify the upper left corner of the rectangle, and the coordinates X2 Y2 specify the width and height.
field	Freezes the first field. Field is assumed by default (if neither frame nor field is specified).
frame	Freezes the entire frame, displaying both fields.
input	Freezes the current frame of the input image, whether it is paused or running.
output	Freezes the current frame of the output from the VCR. If the VCR is playing when freeze is issued, the current frame is frozen and the VCR is paused. If the VCR is paused when this command is issued, the current frame is frozen. The frozen image remains on the output device until an unfreeze command is issued. If neither "input" nor "output" is specified, "output" is assumed.
outside	Indicates that the area outside the region specified using the "at" flag is frozen.
lpszFlags

Can be "wait", "notify", or both. For digital-video and VCR devices, "test" can also be specified. For more information about these flags, see Chapter 3, "MCI Overview."

When used with VCR devices, this command is intended for frame-grabbing cards.

To specify irregular acquisition regions with the "at" flag, use a series of freeze and unfreeze commands. Some video-overlay devices limit the complexity of the acquisition region.

This command is supported only if a call to the capability command with the "can freeze" flag returns TRUE.

The following command disables video acquisition in a 100-pixel square at the upper left corner of the video buffer:

freeze vboard at 0 0 100 100


index

wsprintf(lpstrCommand, "index %s %s %s", lpszDeviceID, lpszIndex,
    lpszFlags);

Controls a VCR's on-screen display. VCR devices recognize this command.

•	Returns zero if successful or an error otherwise.

lpszDeviceID

Identifier of an MCI device. This identifier or alias is assigned when the device is opened.

lpszIndex

One of the following flags:

off	Turns off the on-screen display.
on	Turns on the on-screen display. The item to be displayed is specified by the "index" flag of the set command.
lpszFlags

Can be "wait", "notify", or "test". For more information about these flags, see Chapter 3, "MCI Overview."


info

wsprintf(lpstrCommand, "info %s %s %s", lpszDeviceID, lpszInfoType,
    lpszFlags);

Retrieves a hardware description from a device. All MCI devices recognize this command.

•	Returns zero if successful or an error otherwise.

lpszDeviceID

Identifier of an MCI device. This identifier or alias is assigned when the device is opened.

lpszInfoType

Flag that identifies the type of information required. The following table lists device types that recognize the info command and the flags used by each type:

animation	file product	window text
cdaudio	info identity info upc	product
digitalvideo	audio algorithm audio quality file product still algorithm still quality	usage version video algorithm video quality window text
overlay	file product	window text
sequencer	copyright file	name product
vcr	product	version
videodisc	product
waveaudio	file input	output product
The following table lists the flags that can be specified in the lpszInfoType parameter and their meanings:

audio algorithm	Returns the name of the current audio compression algorithm.
audio quality	Returns the name for the current audio quality descriptor. This might return "unknown" if the application has set parameters to specific values that do not correspond to defined qualities.
copyright	Retrieves the MIDI file copyright notice from the copyright meta event.
file	Retrieves the name of the file used by the compound device. If the device is opened without a file and the load command has not been used, a null string is returned.
info identity	Produces a unique identifier for the audio CD currently loaded in the player being queried.
info upc	Produces the Universal Product Code (UPC) that is encoded on an audio CD. The UPC is a string of digits. It might not be available for all CDs.
input	Retrieves the description of the current input device. Returns "none" if an input device is not set.
name	Retrieves the sequence name from the sequence/track name meta event.
output	Retrieves the description of the current output device. Returns "none" if an output device is not set.
product	Retrieves a description of the device. This information often includes the product name and model. The string length will be 31 characters or fewer.
still algorithm	Returns the name of the current still image compression algorithm.
still quality	Returns the name for the current still image quality descriptor. This might return "unknown" if the application has set parameters to specific values that do not correspond to defined qualities.
usage	Returns a string describing usage restrictions that might be imposed by the owner of the visual or audio data in the workspace.
version	Returns the release level of the device driver and hardware.
video algorithm	Returns the name of the current video compression algorithm.
video quality	Returns the name for the current video quality descriptor. This might return "unknown" if the application has set parameters to specific values that do not correspond to defined qualities.
window text	Retrieves the caption of the window used by the device.
lpszFlags

Can be "wait", "notify", or both. For digital-video and VCR devices, "test" can also be specified. For more information about these flags, see Chapter 3, "MCI Overview."

The following command retrieves a description of the hardware associated with the "mysound" device:

info mysound product


list

wsprintf(lpstrCommand, "list %s %s %s", lpszDeviceID, lpszList,
    lpszFlags);

Determines the number and types of video and audio inputs. Digital-video and VCR devices recognize this command.

•	Returns zero if successful or an error otherwise.

lpszDeviceID

Identifier of an MCI device. This identifier or alias is assigned when the device is opened.

lpszList

Flag that identifies the number and types of video and audio inputs. The following table lists device types that recognize the list command and the flags used by each type:

digitalvideo	audio algorithm audio quality algorithm algorithm audio stream count number index	still algorithm still quality algorithm algorithm video algorithm video quality algorithm algorithm video source video stream
vcr	audio source count audio source number index	video source count video source number index
The following table lists the flags that can be specified in the lpszList parameter and their meanings:

audio algorithm	Specifies the command should retrieve audio algorithm names.
audio quality algorithm algorithm	Specifies the command should retrieve quality levels associated with the specified algorithm. If algorithm is "current", the quality level of the current algorithm is returned.
audio source count	Returns the total number of audio inputs.
audio source number index	Returns the type of audio input of source index.
audio stream	Specifies the command should retrieve the names of the audio streams associated with the workspace. These strings (such as "English" or "German") are embedded in the file and identify the stream.
count	Returns the number of options of the specified type.
number index	Returns a string describing a specific option (as identified by index) of the specified option type. Index must be an integer between 1 and the value returned by "count".
still algorithm	Specifies the command should retrieve still algorithm names.
still quality algorithm algorithm	Specifies the command should retrieve quality levels associated with the specified still algorithm. If algorithm is "current", the quality level of the current algorithm is returned.
video algorithm	Specifies the command should retrieve video algorithm names.
video quality algorithm algorithm	Specifies the command should retrieve quality levels associated with the specified video algorithm. If algorithm is "current", the quality level of the current algorithm is returned.
video source	Specifies the command should return information about the video sources. When used with the "count" flag, it returns the number of video sources. When used with the "number" flag, it returns the type of a video source. MCI defines the following constants for type: "ntsc", "rgb", "pal", "secam", "svideo", and "generic". There might be more than one source of each type returned. The "generic" source type is used when more than one signal is allowed for that connector.
video source count	Returns total number of video inputs.
video source number index	Returns the type of video input of source index.
video stream	Specifies the command should retrieve the names of video streams associated with the workspace. These strings (such as "funny ending" or "sad ending") are embedded in the file and identify the stream.
lpszFlags

Can be "wait", "notify", or "test". For more information about these flags, see Chapter 3, "MCI Overview."

For VCR devices, either "video source" or "audio source" must be specified with either the "count" or "number" flags. If "count" is specified, the total number of inputs of video or audio is returned. If "number" is specified, the driver returns a type corresponding to the input. The type can be any one of the following: "tuner", "line", "svideo", "aux", or "generic". Typically, you should first query the VCR for the "count" and then use the count as the range for the "number" flag. The "source" numbers start from 1.


load

wsprintf(lpstrCommand, "load %s %s %s", lpszDeviceID, lpszFilePos,
    lpszFlags);

Loads a file in a device-specific format. Digital-video and video-overlay devices recognize this command.

•	Returns zero if successful or an error otherwise.

lpszDeviceID

Identifier of an MCI device. This identifier or alias is assigned when the device is opened.

lpszFilePos

Path and filename to load. For video-overlay devices, this can also include a target rectangle for the data. To specify a target rectangle, specify "at" followed by X1 Y1 X2 Y2, where X1 Y1 specify the upper left corner of the rectangle, and X2 Y2 specify the width and height. The rectangle is relative to the video buffer origin.

lpszFlags

Can be "wait", "notify", or both. For digital-video devices, "test" can also be specified. For more information about these flags, see Chapter 3, "MCI Overview."

The following command loads a file into the "vidboard" device:

load vidboard c:\vid\fish.vid notify

The "vidboard" device sends a notification message when the loading is completed.


mark

wsprintf(lpstrCommand, "mark %s %s %s", lpszDeviceID, lpszMark,
    lpszFlags);

Controls recording and erasing of marks on the videotape. VCR devices recognize this command.

•	Returns zero if successful or an error otherwise.

lpszDeviceID

Identifier of an MCI device. This identifier or alias is assigned when the device is opened.

lpszMark

One of the following flags:

erase	Erases a mark at the current position, if one exists. To erase a mark, first seek to the mark and then issue the mark "erase" command.
write	Writes a mark at the current position. The VCR might need to be in play or record mode for this command to succeed.
lpszFlags

Can be "wait", "notify", or "test". For more information about these flags, see Chapter 3, "MCI Overview."

Marks are special signals written to the content that can be detected by the VCR during high-speed searches. Marks are VCR specific.


monitor

wsprintf(lpstrCommand, "monitor %s %s %s", lpszDeviceID, lpszMonitor,
    lpszFlags);

Specifies the presentation source. (The default presentation source is the workspace.) Switching the presentation source switches all audio and video streams in the source. Digital-video devices recognize this command.

•	Returns zero if successful or an error otherwise.

lpszDeviceID

Identifier of an MCI device. This identifier or alias is assigned when the device is opened.

lpszMonitor

One or more of the following flags:

file	Specifies that the workspace is the presentation source. This is the default source.
input	Specifies that the external input is the presentation source. If a play command is in progress, it is first paused. If setvideo is "on", this flag displays a default hidden window. Devices might limit what other device instances can do while monitoring input.
method method	When used with monitor "input", this flag selects the method of monitoring. The method is either "pre", "post", or "direct". Direct monitoring requests that the device be configured for optimum display quality during monitoring. The direct monitoring method might be incompatible with motion video recording.  Pre- and post-monitoring allow motion video recording. Pre-monitoring shows the external input prior to compression, while post-monitoring shows the external input after compression. Typically, different monitoring methods have different hardware implications. The default monitoring method is selected by the device.
lpszFlags

Can be "wait", "notify", "test", or a combination of these. For more information about these flags, see Chapter 3, "MCI Overview."

The presentation source automatically switches to the workspace after a play, step, pause, cue "output", or seek command. The record command does not automatically switch presentation sources, which gives your application the option of not showing video while it is being recorded.


open

wsprintf(lpstrCommand, "open %s %s %s", lpszDevice, lpszOpenFlags,
    lpszFlags);

Initializes a device. All MCI devices recognize this command.

•	Returns zero if successful or an error otherwise. If an error occurs, it returns one of the values listed in the reference section of Chapter 3, "MCI Overview."

lpszDevice

Identifier of an MCI device or device driver. This can be either a device name (as given in the registry or the SYSTEM.INI file) or the filename of the device driver. If you specify the filename of the device driver, you can optionally include the .DRV extension, but you should not include the path to the file.

lpszOpenFlags

Flag that identifies what to initialize. The following table lists device types that recognize the open command and the flags used by each type:

animation	alias device_alias nostatic parent hwnd shareable style child	style overlapped style popup style style_type type device_type
cdaudio	alias device_alias shareable	type device_type
digitalvideo	alias device_alias elementname nostatic parent hwnd shareable	style child style overlapped style popup style style_type type device_type
overlay	alias device_alias parent hwnd shareable style child	style overlapped style popup style style_type type device_type
sequencer	alias device_alias shareable	type device_type
vcr	alias device_alias shareable	type device_type
videodisc	alias device_alias shareable	type device_type
waveaudio	alias device_alias buffer buffer_size	shareable type device_type
The following table lists the flags that can be specified in the lpszOpenFlags parameter and their meanings:

alias device_alias	Specifies an alternate name for the given device. If specified, it must be used as the device_id in subsequent commands.
elementname	Specifies the name of the device element (file) loaded when the device opens.
buffer buffer_size	Sets the size, in seconds, of the buffer used by the waveform-audio device. The default size of the buffer is set when the waveform-audio device is installed or configured. Typically the buffer size is set to 4 seconds. With the MCIWAVE device, the minimum size is 2 seconds and the maximum size is 9 seconds.
nostatic	Indicates that the animation device should reduce the number of static (system) colors in the palette. This increases the number of colors controlled by the animation.
parent hwnd	Specifies the window handle of the parent window.
shareable	Initializes the device or file as shareable. Subsequent attempts to open the device or file fail unless you specify "shareable" in both the original and subsequent open commands.  MCI returns an invalid device error if the device is already open and not shareable. The MCISEQ sequencer and MCIWAVE devices do not support shared files.
style child	Opens a window with a child window style.
style overlapped	Opens a window with an overlapped window style.
style popup	Opens a window with a pop-up window style.
style style_type	Indicates a window style.
type device_type	Specifies the device type of a file.
lpszFlags

Can be "wait", "notify", or both. For more information about these flags, see Chapter 3, "MCI Overview."

MCI reserves "cdaudio" for the CD audio device type, "videodisc" for the videodisc device type, "sequencer" for the MIDI sequencer device type, "AVIVideo" for the digital-video device type, and "waveaudio" for the waveform-audio device type.

As an alternative to the "type" flag, MCI can select the device based on the extension used by the file, as recorded in the registry or the [mci extension] section of the SYSTEM.INI file.

MCI can open AVI files by using a file-interface pointer or a stream-interface pointer. To open a file by using either type of interface pointer, specify an at sign (@) followed by the interface pointer in place of the file or device name for the lpszDevice parameter. For more information about the file and stream interfaces, see Chapter 6, "AVIFile Functions and Macros ."

The following command opens the "mysound" device:

open new type waveaudio alias mysound buffer 6

With device name "new", the waveform driver prepares a new waveform resource. The command assigns the device alias "mysound" and specifies a 6-second buffer.

You can eliminate the "type" flag if you combine the device name with the filename. MCI recognizes this combination when you use the following syntax:

device_name!element_name

The exclamation point separates the device name from the filename. The exclamation point should not be delimited by white spaces.

The following example opens the RIGHT.WAV file using the "waveaudio" device:

open waveaudio!right.wav

The MCIWAVE driver requires an asynchronous waveform-audio device.


paste

wsprintf(lpstrCommand, "paste %s %s %s", lpszDeviceID, lpszItem,
    lpszFlags);

Copies the contents of the clipboard into the workspace. Digital-video devices recognize this command.

•	Returns zero if successful or an error otherwise.

lpszDeviceID

Identifier of an MCI device. This identifier or alias is assigned when the device is opened.

lpszItem

One or more of the following flags:

at rectangle	Specifies the location within the frame where the data is pasted. The upper left corner of the rectangle corresponds to the upper left corner of the added data. If the rectangle has a nonzero size in X or Y, the contents of the clipboard are scaled in those dimensions when they are pasted into the frame. If omitted, the rectangle defaults to the entire frame. If this flag is specified in "insert" mode (the default), any region outside the rectangle is painted a solid color.
audio stream stream	Specifies the audio stream in the workspace affected by the command. If only one audio stream exists on the clipboard, the audio data is pasted into the designated stream. If more than one audio stream exists on the clipboard, the stream indicates the starting number for the stream sequences. If you use this flag and also want to paste video, you must also use the "video stream" flag. (If neither flag is specified, all audio and video streams are pasted and retain their original stream numbers.)
insert	Specifies that the data is inserted into the workspace. Any data after the insertion point is moved forward in the workspace to make room. This is the default value.
overwrite	Specifies that the data is copied into the workspace by writing over any existing data after the insertion point. The "insert" and "overwrite" flags affect whether frames are destroyed or moved during the paste operation, not how the data is pasted within each frame.
to position	Specifies the position in the workspace at which the data is pasted. If omitted, it defaults to the current position.
video stream stream	Specifies the video stream in the workspace affected by the command. If only one video stream exists on the clipboard, the video data is pasted into the designated stream. If more than one video stream exists on the clipboard, the stream indicates the starting number for the stream sequences. If you use this flag and also want to paste audio, you must also use the "audio stream" flag. (If neither flag is specified, all audio and video streams are pasted and retain their original stream numbers.)
lpszFlags

Can be "wait", "notify", "test", or a combination of these. For more information about these flags, see Chapter 3, "MCI Overview."

No signals are present in the data copied from the clipboard. The change becomes permanent only when the data is explicitly saved; however, playback acts as if the data has been added.


pause

wsprintf(lpstrCommand, "pause %s %s", lpszDeviceID, lpszFlags);

Pauses playing or recording. Most drivers retain the current position and eventually resume playback or recording at this position. Animation, CD audio, digital-video, MIDI sequencer, VCR, videodisc, and waveform-audio devices recognize this command.

•	Returns zero if successful or an error otherwise.

lpszDeviceID

Identifier of an MCI device. This identifier or alias is assigned when the device is opened.

lpszFlags

Can be "wait", "notify", or both. For digital-video and VCR devices, "test" can also be specified. For more information about these flags, see Chapter 3, "MCI Overview."

With the MCICDA, MCISEQ, and MCIPIONR drivers, the pause command works the same as the stop command.

The following command pauses the "mysound" device:

pause mysound


play

wsprintf(lpstrCommand, "play %s %s %s", lpszDeviceID, lpszPlayFlags,
    lpszFlags);

Starts playing a device. Animation, CD audio, digital-video, MIDI sequencer, videodisc, VCR, and waveform-audio devices recognize this command.

•	Returns zero if successful or an error otherwise.

lpszDeviceID

Identifier of an MCI device. This identifier or alias is assigned when the device is opened.

lpszPlayFlags

Flag for playing a device. The following table lists device types that recognize the play command and the flags used by each type:

animation	fast from position  reverse scan	slow speed fps to position
cdaudio	from position	to position
digitalvideo	from position  fullscreen repeat	reverse to position window
sequencer	from position	to position
vcr	at time from position  reverse	scan to position
videodisc	fast from position  reverse scan	slow speed integer to position
waveaudio	from position	to position
The following table lists the flags that can be specified in the lpszPlayFlags parameter and their meanings:

at time	Indicates when the device should begin performing this command, or, if the device has been cued, when the cued command begins. For more information, see the cue command.
fast	Indicates that the device should play faster than normal. To determine the exact speed on a videodisc player, use the "speed" flag of the status command. To specify the speed more precisely, use the "speed" flag of this command.
from position	Specifies a starting position for the playback. If the "from" flag is not specified, playback begins at the current position. For cdaudio devices, if the "from" position is greater than the end position of the disc, or if the "from" position is greater than the "to" position, the driver returns an error. For videodisc devices, the default positions are in frames for CAV discs and in hours, minutes, and seconds for CLV discs.
fullscreen	Specifies that a full-screen display should be used. Use this flag only when playing compressed files. (Uncompressed files won't play full-screen.)
repeat	Specifies that playback should restart when the end of the content is reached.
reverse	Specifies that the play direction is backward. You cannot specify an ending location with the "reverse" flag. For videodiscs, "scan" applies only to CAV format.
scan	Plays as fast as possible without disabling video (although audio might be disabled). For videodiscs, "scan" applies only to CAV format.
slow	Plays slowly. To determine the exact speed on a videodisc player, use the "speed" flag of the status command. To specify the speed more precisely, use the "speed" flag of this command. For videodiscs, "slow" applies only to CAV format.
speed fps	Plays an animation sequence at the specified speed, in frames per second.
speed integer	Plays a videodisc at the specified speed, in frames per second. This flag applies only to CAV discs.
to position	Specifies an ending position for the playback. If the "to" flag is not specified, playback stops at the end of the content. For cdaudio devices, if the "to" position is greater than the end position of the disc, the driver returns an error. For videodisc devices, the default positions are in frames for CAV discs and in hours, minutes, and seconds for CLV discs.
window	Specifies that playing should use the window associated with the device instance. This is the default setting.
lpszFlags

Can be "wait", "notify", or both. For digital-video and VCR devices, "test" can also be specified. For more information about these flags, see Chapter 3, "MCI Overview."

Before issuing commands that use position values, you should set the desired time format by using the set command. This command begins playing at the current speed, as set with the set "speed" command. The direction is reverse if the "reverse" flag is specified, or if the "to" flag is specified as a value less than the "from" flag. If the "from" flag is not specified, playback begins at the current position. The "to" and "reverse" flags cannot be used together.

The following command plays the "mysound" device from position 1000 through position 2000, sending a notification message when the playback completes:

play mysound from 1000 to 2000 notify


put

wsprintf(lpstrCommand, "put %s %s %s", lpszDeviceID, lpszRegions,
    lpszFlags);

Defines the area of the source image and destination window used for display. Animation, digital-video, and video-overlay devices recognize this command.

•	Returns zero if successful or an error otherwise.

lpszDeviceID

Identifier of an MCI device. This identifier or alias is assigned when the device is opened.

lpszRegions

Flag for defining the area. The following table lists device types that recognize the put command and the flags used by each type:

animation	destination destination at rectangle	source source at rectangle
digitalvideo	destination destination at rectangle frame frame at rectangle source source at rectangle	video video at rectangle window window at rectangle window client window client at rectangle
overlay	destination destination at rectangle frame frame at rectangle	source source at rectangle video video at rectangle
The following table lists the flags that can be specified in the lpszRegions parameter and their meanings:

destination	Selects the entire client area of the destination window to display the data.
destination at rectangle	Selects a portion of the client area of the destination window used to display the image. When an area of the display window is specified and the device supports stretching, the source image is stretched to the destination offset and extent.
frame	Selects the entire frame buffer to receive the incoming video images.
frame at rectangle	Selects a portion of the frame buffer to receive the incoming video images.
source	Selects the entire image for display in the destination window.
source at rectangle	Selects a portion of the image to display in the destination window. When an area of the source image is specified, and the device supports stretching, the source image is stretched to the destination offset and extent.
video	Selects the entire incoming video image to capture in the frame buffer.
video at rectangle	Selects a portion of the incoming video image to capture in the frame buffer.
window	Restores the initial window size on the display. This command also displays the window.
window at rectangle	Changes the size and location of the display window. The specified rectangle is relative to the parent window of the display window (usually the desktop) if the "style child" flag has been used for the open command. To change the location of the window without changing its height or width, specify zero for the height and width.
window client	Restores the client area of the window.
window client at rectangle	Changes the size and location of the client area of the window. The specified rectangle is relative to the parent window of the client window. To change the location of the window without changing its height or width, specify zero for the height and width.
When a flag includes a rectangle, the rectangle coordinates are relative to the window origin or the image origin, as appropriate, and are specified as X1 Y1 X2 Y2. The coordinates X1 Y1 specify the upper left corner, and the coordinates X2 Y2 specify the width and height of the rectangle.

lpszFlags

Can be "wait", "notify", or both. For digital-video devices, "test" can also be specified. For more information about these flags, see Chapter 3, "MCI Overview."

The put command defines one or more of the following rectangles when working with video-overlay devices:

•	The video rectangle defines the region of the incoming video image to capture.

•	The frame rectangle defines the region of the frame buffer that receives the incoming video image.

•	The source rectangle defines which region of the frame buffer is copied to the destination rectangle.

•	The destination rectangle defines the region of the display window client area that receives the video image.

The video rectangle is related to the frame rectangle in the same way the source rectangle is related to the destination rectangle. Stretching can occur from the video rectangle to the frame rectangle and from the source rectangle to the destination rectangle. Not all devices support stretching, and stretching must be enabled (by using the set command).

The following command defines three regions for the video, frame, and source:

put vboard video 120 120 200 200 frame 0 0 200 200 source 0 0 200 200

The regions in this example are defined as follows:

•	A 200- by 200-pixel region of the incoming video data, starting at an origin 120 pixels from the upper left corner, will be captured to the frame buffer.

•	The video data will be placed in a 200- by 200-pixel region at the upper left corner of the frame buffer.

•	Transfers are made from the 200- by 200-pixel region at the upper left corner of the frame buffer to the destination window.


quality

wsprintf(lpstrCommand, "quality %s %s %s", lpszDeviceID, lpszQuality,
    lpszFlags);

Defines a custom quality level for either audio, video or still image data compression. Digital-video devices recognize this command.

•	Returns zero if successful or an error otherwise.

lpszDeviceID

Identifier of an MCI device. This identifier or alias is assigned when the device is opened.

lpszQuality

One or more of the following flags. (One of the three flags "audio", "still", and "video" must be present.)

algorithm algorithm	Associates the quality level with the specified algorithm. This algorithm must be supported by the device and be compatible with the "audio", "still", or "video" flag that is used. If omitted, the current algorithm is used.
audio name	Indicates this command specifies an "audio" quality level identified with name.
dialog	Requests that the device display a dialog box. This dialog box has algorithm-specific fields that are used internally by the device to create the structure describing a specific quality level.
handle handle	Specifies a handle to a structure that contains algorithmic-specific data describing a specific quality level. The structures for the data referenced by this handle are device specific.
still name	Indicates the command specifies a "still" quality level identified with name.
video name	Indicates the command specifies a "video" quality level identified with name.
lpszFlags

Can be "wait", "notify", "test", or a combination of these. For more information about these flags, see Chapter 3, "MCI Overview."

This command defines a string name for the quality level, which can then be used in a setvideo "quality", setvideo "still quality", or setaudio "quality" command to establish it as the current video, still, or audio-compression quality level.


realize

wsprintf(lpstrCommand, "realize %s %s %s", lpszDeviceID, lpszPalette,
    lpszFlags);

Instructs a device to select and realize its palette into the display context of the displayed window. Animation and digital-video devices recognize this command.

•	Returns zero if successful or an error otherwise.

lpszDeviceID

Identifier of an MCI device. This identifier or alias is assigned when the device is opened.

lpszPalette

One of the following flags:

background	Realizes the palette as a background palette.
normal	Realizes the palette for a top-level window. This is the default setting.
lpszFlags

Can be "wait", "notify", or both. For digital-video devices, "test" can also be specified. For more information about these flags, see Chapter 3, "MCI Overview."

Use this command only if your application uses a window handle and receives a WM_QUERYNEWPALLETTE or WM_PALETTECHANGED message.

The following command tells the "myvideo" device to realize its palette:

realize myvideo normal


record

wsprintf(lpstrCommand, "record %s %s %s", lpszDeviceID, lpszRecordFlags,
    lpszFlags);

Starts recording data. VCR and waveform-audio devices recognize this command. Although digital-video devices and MIDI sequencers also recognize this command, the MCIAVI and MCISEQ drivers do not implement it.

•	Returns zero if successful or an error otherwise.

lpszDeviceID

Identifier of an MCI device. This identifier or alias is assigned when the device is opened.

lpszRecordFlags

Flag for recording data. The following table lists device types that recognize the record command and the flags used by each type:

digitalvideo	at rectangle audio stream stream from position hold	insert overwrite to position video stream stream
sequencer	from position insert	overwrite to position
vcr	at time from position initialize	insert overwrite to position
waveaudio	from position insert	overwrite to position
The following table lists the flags that can be specified in the lpszRecordFlags parameter and their meanings:

at rectangle	Specifies a rectangular region of the external input used as the source for the pixels compressed and saved. If not specified, the rectangle defaults to the rectangle specified for put "video". When it is set differently from the "video" rectangle, the displayed image is not what is recorded.
at time	Indicates when the device should begin performing this command, or, if the device has been cued, when the cued command begins. For more information, see the cue command.
audio stream stream	Specifies the audio stream used for recording. If this flag is not specified and the file format does not define a default, it is recorded into the stream that is physically first.
from position	Specifies a starting position for the recording. If the "from" flag is not specified, the device starts recording at the current position.
hold	Freezes the image when recording has finished instead of showing live video. When recording stops, an automatic monitor "file" command is performed. To return to live video, issue the monitor "input" command.
initialize	Initialize the tape (media), which involves recording timecode (if possible) for blank video and audio. This command might take several hours if the entire tape must be initialized.
insert	Specifies that new data is added to the file at the current position.
overwrite	Specifies that new data will replace data in the file.
to position	Specifies an ending position for the recording. If the "to" flag is not specified, the device records until it receives a stop or pause command.
video stream stream	Specifies the video stream used for recording. If this is not specified and the file format does not define a default, then it is recorded into the stream that is physically first.
lpszFlags

Can be "wait", "notify", or both. For digital-video and VCR devices, "test" can also be specified. For more information about these flags, see Chapter 3, "MCI Overview."

The recording stops when a stop or pause command is issued. For the MCIWAVE driver, all data recorded after a file is opened is discarded if the file is closed without saving it.

Before issuing any commands that use position values, you should set the desired time format by using the set command. The tracks to be recorded are specified by the settimecode "record", set "assemble record", setvideo "record", and setaudio "record" commands.

The following command starts recording at the current position:

record mysound


reserve

wsprintf(lpstrCommand, "reserve %s %s %s", lpszDeviceID, lpszReserve,
    lpszFlags);

Allocates contiguous disk space for the device instance's workspace. Digital-video devices recognize this command.

•	Returns zero if successful or an error otherwise.

lpszDeviceID

Identifier of an MCI device. This identifier or alias is assigned when the device is opened.

lpszReserve

One or more of the following flags:

in path	Specifies the drive and directory path (but not the name) of a temporary file used to hold recorded data. The name of this file is specified by the device. The temporary file is deleted when the device is closed. If this flag is omitted, the device specifies the location of the disk space.
size duration	Specifies the approximate amount of disk space to reserve in the workspace. The duration value is specified in the current time format. The device bases its estimate of the required disk space on the following parameters: the requested time, the file format, the video and audio compression algorithm, and the compression quality values in effect. If setvideo "record" is "off", then space is reserved only for audio. If setaudio "record" is "off", then space is reserved only for video. If both are "off", or if duration is zero, then no space is reserved and any existing reserved space is deallocated. If this flag is omitted, the device will use a device-defined default.
lpszFlags

Can be "wait", "notify", "test", or a combination of these. For more information about these flags, see Chapter 3, "MCI Overview."

If needed, subsequent record or save commands use the space reserved by this command. If the workspace contains unsaved data, the data is lost. Some devices do not require reserve and ignore it. If disk space is not reserved prior to recording, the record command performs an implied reserve with device-specific default flags. Use an explicit reserve command if you want better control of when the delay for disk allocation occurs, control of how much space is allocated, and control of where the disk space is allocated. Your application can change the amount and location of previously reserved disk space with subsequent reserve commands. Any allocated and still unused disk space is not deallocated until any recorded data is saved, or until the device instance is closed.


restore

wsprintf(lpstrCommand, "restore %s %s %s", lpszDeviceID, lpszRestore,
    lpszFlags);

Copies a still image from a file to the frame buffer. This is the reverse of the capture command. Digital-video devices recognize this command.

•	Returns zero if successful or an error otherwise.

lpszDeviceID

Identifier of an MCI device. This identifier or alias is assigned when the device is opened.

lpszRestore

One or more of the following flags:

at rectangle	Specifies a rectangle relative to the frame buffer origin. The rectangle is specified as X1 Y1 X2 Y2. The coordinates X1 Y1 specify the upper left corner and the coordinates X2 Y2 specify the width and height.  If this flag is not used, the image is copied to the upper left corner of the frame buffer.
from filename	Specifies the image filename to recall. This flag is required.
lpszFlags

Can be "wait", "notify", "test", or a combination of these. For more information about these flags, see Chapter 3, "MCI Overview."

Devices can recognize a variety of image formats; a Windows device-independent bitmap is always recognized.


resume

wsprintf(lpstrCommand, "resume %s %s", lpszDeviceID, lpszFlags);

Continues playing or recording on a device that has been paused using the pause command. Animation, digital-video, VCR, and waveform-audio devices recognize this command. Although CD audio, MIDI sequencer, and videodisc devices also recognize this command, the MCICDA, MCISEQ, and MCIPIONR device drivers do not support it.

•	Returns zero if successful or an error otherwise.

lpszDeviceID

Identifier of an MCI device. This identifier or alias is assigned when the device is opened.

lpszFlags

Can be "wait", "notify", or both. For digital-video and VCR devices, "test" can also be specified. For more information about these flags, see Chapter 3, "MCI Overview."

The following command continues playing or recording the "newsound" device:

resume newsound


save

wsprintf(lpstrCommand, "save %s %s %s", lpszDeviceID, lpszFilename,
    lpszFlags);

Saves an MCI file. Video-overlay and waveform-audio devices recognize this command. Although digital-video devices and MIDI sequencers also recognize this command, the MCIAVI and MCISEQ drivers do not support it.

•	Returns zero if successful or an error otherwise.

lpszDeviceID

Identifier of an MCI device. This identifier or alias is assigned when the device is opened.

lpszFilename

Flag specifying the name of the file being saved and, optionally, additional flags modifying the save operation. The following table lists device types that recognize the save command and the flags used by each type:

digitalvideo	abort at rectangle	filename keepreserve
overlay	at rectangle	filename
sequencer	filename
waveaudio	filename
The following table lists the flags that can be specified in the lpszFilename parameter and their meanings:

abort	Stops a save operation in progress. If used, this must be the only item present.
at rectangle	Specifies a rectangle relative to the frame buffer origin. The rectangle is specified as X1 Y1 X2 Y2. The coordinates X1 Y1 specify the upper left corner and the coordinates X2 Y2 specify the width and height. For digital-video devices, the capture command is used to capture the contents of the frame buffer.
filename	Specifies the filename to assign to the data file. If a path is not specified, the file will be placed on the disk and in the directory previously specified on the explicit or implicit reserve command. If reserve has not been issued, the default drive and directory are those associated with the application's task. If a path is specified, the device might require it to be on the disk drive specified by the explicit or implicit reserve. This flag is required.
keepreserve	Specifies that unused disk space left over from the original reserve command is not deallocated.
lpszFlags

Can be "wait", "notify", or both. For digital-video and VCR devices, "test" can also be specified. For more information about these flags, see Chapter 3, "MCI Overview."

The filename variable is required if the device was opened using the "new" device identifier.

The following command saves the entire video buffer to a file named VCAPFILE.TGA:

save vboard c:\vcap\vcapfile.tga


seek

wsprintf(lpstrCommand, "seek %s %s %s", lpszDeviceID, lpszSeekFlags,
    lpszFlags);

Moves to the specified position and stops. Animation, CD audio, digital-video, MIDI sequencer, VCR, videodisc, and waveform-audio devices recognize this command.

•	Returns zero if successful or an error otherwise.

lpszDeviceID

Identifier of an MCI device. This identifier or alias is assigned when the device is opened.

lpszSeekFlags

Flag for moving to a specified position. The following table lists device types that recognize the seek command and the flags used by each type:

animation	to end to position	to start
cdaudio	to end to position	to start
digitalvideo	to end to position	to start
sequencer	to end to position	to start
vcr	at time mark mark_num reverse	to end to position to start
videodisc	reverse to end	to position to start
waveaudio	to end to position	to start
The following table lists the flags that can be specified in the lpszSeekFlags parameter and their meanings:

at time	Indicates when the device should begin performing this command, or, if the device has been cued, when the cued command begins. For more information, see the cue command.
mark mark_num	Seeks to the relative mark indicated by mark_num, which must be a positive integer value. Marks are signals written to the VCR tape using the mark command and are used for high-speed searching.
reverse	Indicates that the seek direction on VCRs and CAV videodiscs is backward. This flag is invalid if the "to" flag is specified. For VCRs, this flag must be used with the "mark" flag.
to end	Seeks to the end of the content.
to position	Specifies the position to stop the seek. For cdaudio devices, MCI returns an out-of-range error if the specified position is greater than the length of the disc.
to start	Seeks to the start of the content.
lpszFlags

Can be "wait", "notify", or both. For digital-video and VCR devices, "test" can also be specified. For more information about these flags, see Chapter 3, "MCI Overview."

Before issuing any commands that use position values, you should set the desired time format by using the set command.

Digital-video devices support two seek modes, which you can change by using the set command. The "seek exactly on" mode causes the seek command to move to the specified frame. The "seek exactly off" mode causes the seek command to move to the closest key frame prior to the specified frame.

If a CD audio device is playing when the seek command is issued, playback is stopped. When the seek command is issued with a videodisc device, the device searches using fast forward or fast reverse with video and audio off.

When the seek command is issued with a waveform-audio device, the behavior depends on the sample size. If the sample size is 16 bits or greater, seek moves to the beginning of the nearest sample when a specified position does not coincide with the start of a sample.

The following command seeks to the start of the media file associated with the "mysound" device:

seek mysound to start


set

wsprintf(lpstrCommand, "set %s %s %s", lpszDeviceID, lpszSetting,
    lpszFlags);

Establishes control settings for the device. Animation, CD audio, digital-video, MIDI sequencer, VCR, videodisc, video-overlay, and waveform-audio devices recognize this command.

•	Returns zero if successful or an error otherwise.

lpszDeviceID

Identifier of an MCI device. This identifier or alias is assigned when the device is opened.

lpszSetting

Flag for establishing control settings. The following table lists device types that recognize the set command and the flags used by each type:

animation	audio all off audio all on audio left off audio left on audio right off audio right on	door closed door open time format frames time format milliseconds video off video on
cdaudio	audio all off audio all on audio left off audio left on audio right off audio right on	door closed door open time format milliseconds time format msf time format tmsf
digitalvideo	audio all off audio all on audio left off audio left on audio right off audio right on door closed door open	file format format seek exactly on seek exactly off speed factor still file format format time format frames time format milliseconds video off video on
overlay	audio all off audio all on audio left off audio left on audio right off	audio right on door closed door open video off video on
sequencer	audio all off audio all on audio left off audio left on audio right off audio right on door closed door open master MIDI master none master SMPTE offset time	port mapper port none port port_number slave file slave MIDI slave none slave SMPTE tempo tempo_value time format milliseconds time format SMPTE fps time format SMPTE 30 drop time format song pointer
vcr	assemble record on assemble record off audio all off audio all on audio left off audio left on audio right off audio right on clock time counter format counter value door closed door open index counter index date index time index timecode length duration pause timeout postroll duration -     duration	power on power off preroll duration duration record format SP record format LP record format EP speed factor time format frames time format hms time format milliseconds time format msf time format SMPTE fps time format SMPTE 30 drop time format tmsf time mode counter time mode detect time mode timecode tracking plus tracking minus tracking reset
videodisc	audio all off audio all on audio left off audio left on audio right off audio right on door closed	door open time format frames time format hms time format milliseconds time format track video off video on
waveaudio	alignment integer any input any output audio all off audio all on audio left off audio left on audio right off audio right on bitspersample bit_count bytespersec byte_rate	channels channel_count door closed door open format tag pcm format tag tag input integer output integer samplespersec integer time format bytes time format milliseconds time format samples
The following table lists the flags that can be specified in the lpszSetting parameter and their meanings:

alignment integer	Sets the alignment of data blocks relative to the start of data passed to the waveform-audio device. The file is saved in this format.
any input	Use any input that supports the current format when recording. This is the default setting.
any output	Use any output that supports the current format when playing. This is the default.
assemble record on assemble record off	In assemble mode, all tracks are recorded as defined by the device. Most VCRs are in assemble mode by default.
audio all off audio all on	Disables or enables audio output. Video-overlay devices, the MCISEQ sequencer, and the MCIWAVE waveform-audio device do not support this flag.
audio left off audio left on audio right off audio right on	Disables or enables output to either the left or the right audio channel. Video-overlay devices, the MCISEQ sequencer, and the MCIWAVE waveform-audio device do not support this flag.
bitspersample bit_count	Sets the number of bits per PCM (Pulse Code Modulation) sample played or recorded. The file is saved in this format.
bytespersec byte_rate	Sets the average number of bytes per second played or recorded. The file is saved in this format.
channels channel_count	Sets the channels for playing and recording. The file is saved in this format.
clock time	Sets time on the external clock to time. The format is specified as a long unsigned integer.
counter format	Set the time format for the counter, as returned by status "counter". For information about applicable types, see the set "time format" command.
counter value	Sets the VCR counter to the specified value. The value must be specified in the current counter format. For more information, see the set "counter format" command.
door closed	Retracts the tray and closes the door, if possible. For VCRs, loads the tape automatically.
door open	Opens the door and ejects the tray or tape, if possible.
file format format	Specifies a file format that is used for save or capture commands. If omitted, this might default to a device driver defined format. If the specified file format conflicts with the currently selected algorithm and quality, then they are changed to the defaults for the file format. The following file formats are defined: avi Specifies AVI format.  avss Specifies AVSS format.  dib Specifies DIB format.  jfif Specifies JFIF format.  jpeg Specifies JPEG format.  mpeg Specifies MPEG format.  rdib Specifies RLE DIB format.  rjpeg Specifies RJPEG format.
format tag pcm	Sets the format type to PCM for playing and recording. The file is saved in this format.
format tag tag	Sets the format type for playing and recording. The file is saved in this format.
index timecode index counter index date index time	Sets the current display screen on the VCR.
input integer	Sets the audio channel used as the input.
length duration	Sets the user-specified length of the tape in the VCR. This length is returned by the status "length" command and is provided for compatibility with applications that require this command to return a valid length.
master midi	Sets the MIDI sequencer as the synchronization source. Synchronization data is sent in MIDI format. The MCISEQ sequencer does not support this flag.
master none	Inhibits the MIDI sequencer from sending synchronization data. The MCISEQ sequencer does not support this flag.
master smpte	Sets the MIDI sequencer as the synchronization source. Synchronization data is sent in SMPTE (Society of Motion Picture and Television Engineers) format. The MCISEQ sequencer does not support this flag.
offset time	Sets the SMPTE offset time. The offset is the beginning time of a SMPTE based sequence. The time is expressed as hh:mm:ss:ff, where hh is hours, mm is minutes, ss is seconds, and ff is frames.
output integer	Sets the audio channel used as the output.
pause timeout	Sets the maximum duration, in milliseconds, of a pause command. A timeout value of zero indicates that no time-out will occur.
postroll duration duration	Sets the length, in the current time format, needed to brake the VCR transport when a stop or pause command is issued.
port mapper	Sets the MIDI mapper as the port receiving the MIDI messages. This command fails if the MIDI mapper or a port it needs is being used by another application.
port none	Disables the sending of MIDI messages. This command also closes a MIDI port.
port port_number	Sets the MIDI port receiving the MIDI messages. This command fails if the port you are trying to open is being used by another application.
power on power off	Sets the device power to on or off.
preroll duration duration	Sets the length, in the current time format, needed to stabilize the VCR output.
record format SP record format LP record format EP	Sets the recording mode for the VCR to SP for standard play, EP for extended play, or LP for long play. These values are not intended to be VHS specific. They map to any three appropriate modes with other tape formats. For example, SP maps to the fastest, highest quality recording.
samplespersec integer	Sets the sample rate for playing and recording. The file is saved in this format.
seek exactly on seek exactly off	Selects one of two seek modes. With "seek exactly on", seek will always move to the frame specified. With "seek exactly off", seek will move to the closest key frame prior to the frame specified.
slave file	Sets the MIDI sequencer to use file data as the synchronization source. This is the default setting.
slave midi	Sets the MIDI sequencer to use incoming MIDI data for the synchronization source. The sequencer recognizes synchronization data with the MIDI format. The MCISEQ sequencer does not support this flag.
slave none	Sets the MIDI sequencer to ignore synchronization data.
slave smpte	Sets the MIDI sequencer to use incoming MIDI data for the synchronization source. The sequencer recognizes synchronization data with the SMPTE format. The MCISEQ sequencer does not support this flag.
speed factor	Sets the relative speed of video and audio playback from the workspace. Factor is the ratio between the nominal frame rate and the desired frame rate, where the nominal frame rate is designated as 1000. (A rate of 500 is half normal speed, 2000 is twice normal speed, and so on.) Setting the speed to zero plays the video as fast as possible without dropping frames and without audio.
still file format format	Specifies the file format used for capture commands.
tempo tempo_value	Sets the tempo of the sequence according to the current time format. For a PPQN-based file, the tempo_value is interpreted as beats per minute. For a SMPTE-based file, the tempo_value is interpreted as frames per second.
time format bytes	In a PCM file format, sets the time format to bytes. All position information is specified as bytes following this command.
time format frames	Sets the time format to frames. All commands that use position values will assume frames. When the device is opened, frames is the default mode. Supported by videodiscs using CAV format.
time format hms	Sets the time format to hours, minutes, and seconds. All commands that use position values will assume HMS. HMS is the default format for CLV videodiscs.  Specify an HMS value as hh:mm:ss, where hh is hours, mm is minutes, and ss is seconds. You can omit a field if it and all following fields are zero. For example,  3, 3:0, and 3:0:0 are all valid ways to express 3 hours.
time format milliseconds	Sets the time format to milliseconds. All commands that use position values will assume milliseconds. You can abbreviate milliseconds as "ms". For sequencer devices, the sequence file sets the default format to PPQN or SMPTE. Video-overlay devices do not support this flag.
time format msf	Sets the time format to minutes, seconds, and frames. All commands that use position values will assume MSF (the default format for CD audio). Specify an MSF value as mm:ss:ff, where mm is minutes, ss is seconds, and ff is frames. You can omit a field if it and all following fields are zero. For example, 3, 3:0, and 3:0:0 are valid ways to express 3 minutes.  The MSF fields have the following maximum values: Minutes 99 Seconds 59 Frames  74
time format samples	Sets the time format to samples. All position information is specified as samples following this command.
time format smpte 24 time format smpte 25 time format smpte 30	Sets the time format to an SMPTE frame rate.  For VCRs, sets the time format to hh:mm:ss:ff, where the legal values are 00:00:00:00 through 23:59:59:xx, and xx is one less than the frames per second as specified by the number 24, 25, or 30 as specified in the flag. On input, colons (:) are required to separate the components. The least significant units can be  omitted if they are 00; for example, 02:00 is the same  as 02:00:00:00.  All commands that use position values will assume SMPTE format.  The sequence file sets the default format to PPQN or SMPTE.
time format smpte 30 drop	Sets the time format to SMPTE 30 drop frame rate.  For VCRs, same as SMPTE 30, except that certain timecode positions are dropped from the format to have the recorded timecode positions for each frame (at the NTSC frame rate of 29.97 fps) correspond to real time (at 30 fps). Timecode positions that are dropped are as follows: two every minute, on the minute, for the first nine of every ten minutes of recorded content. For example, at 01:04:59:29, the next timecode position would be 01:05:00:02, not 01:05:00:00.  All commands that use position values will assume SMPTE format.  The sequence file sets the default format to PPQN or SMPTE.
time format song pointer	Sets the time format to song pointer (sixteenth notes). All commands that use position values will assume song pointer units. This flag is valid only for a sequence of division type PPQN.
time format tmsf	Sets the time format to tracks, minutes, seconds, and frames. All commands that use position values will assume TMSF. Specify a TMSF value as tt:mm:ss:ff, where tt is tracks, mm is minutes, ss is seconds, and ff is frames. You can omit a field if it and all following fields are zero. For example, 3, 3:0, 3:0:0, and 3:0:0:0 are all valid ways to express track 3.  The TMSF fields have the following maximum values: Tracks 99 Minutes 99 Seconds 59 Frames  74
time format track	Sets the position format to tracks. All commands that use position values will assume tracks.
time mode counter	Sets the position-information mode to use the VCR counters.
time mode detect	Sets the position information mode based on detection of timecode information on the tape. If timecode information is detected, the time type is set to "timecode"; otherwise, the time type is set to "counter". "Detect" is a special mode. Whenever the driver is opened, a new tape is inserted, or the "time mode" command is issued, the driver checks the current time mode available on the tape and sets "time type" to either "timecode" or "counter". Once "time type" is set, the driver doesn't change it until one of the above conditions occurs again.
time mode timecode	Sets the position information mode to use "timecode" information on the tape.
tracking plus tracking minus tracking reset	Adjusts the speed of the videotape transport in fine increments. Use the "tracking" flags when a noisy picture is obtained from a VCR. "Tracking plus" increases the transport speed. "Tracking minus" decreases the transport speed. "Tracking reset" returns the tracking adjustment to zero.
video off	Disables video output.
video on	Enables video output.
lpszFlags

Can be "wait", "notify", or both. For digital-video and VCR devices, "test" can also be specified. For more information about these flags, see Chapter 3, "MCI Overview."

Several properties of waveform-audio data are defined when the file to store the data is created. These properties describe how the data is structured within the file and cannot be changed once recording begins. The following list identifies these properties:

•	alignment

•	bitspersample

•	bytespersec

•	channels

•	format tag

•	samplespersec

The following command sets the time format to milliseconds and sets the waveform-audio format to 8 bit, mono, 11 kHz:

set mysound time format ms bitspersample 8 channels 1 samplespersec 11025


setaudio

wsprintf(lpstrCommand, "setaudio %s %s %s", lpszDeviceID, lpszAudio,
    lpszFlags);

Sets values associated with audio playback and capture. Digital-video and VCR devices recognize this command.

•	Returns zero if successful or an error otherwise.

lpszDeviceID

Identifier of an MCI device. This identifier or alias is assigned when the device is opened.

lpszAudio

Flag for audio playback and capture. The following table lists device types that recognize the setaudio command and the flags used by each type:

digitalvideo	algorithm algorithm alignment to integer bass to factor bitspersample to bit_count bytespersec to integer clocktime input left off left on left volume to factor off on output	over duration quality descriptor record off record on right off right on right volume to factor samplespersec to integer source to sourcename stream to number treble to factor volume to factor
vcr	off on monitor to type number number record off record track track_number off	record on  record track track_number on  source to type number number track track_number off track track_number on
The following table lists the flags that can be specified in the lpszAudio parameter and their meanings:

algorithm algorithm	Selects a specific audio compression algorithm for use by a subsequent reserve or record command. The algorithms supported are device specific. MCI defines the values "g711", "g721", "g722", "g728", "pcm", "cdxa", "adpcm", and "adpcm4e" for algorithm. If a device supports the algorithm names "pcm", "cdxa", and "adpcm4e", they adhere to standard definitions. The "cdxa" algorithm has been defined by Sony Corporation. The "adpcm4e" algorithm has been defined by Intel Corporation. The "g711", "g721", "g722", and "g728" values represent audio algorithms recommended by the International Telegraph and Telephone Consultative Committee (CCITT). If the specified algorithm conflicts with the current file format, the file format is changed to the default format for the algorithm.
alignment to integer	Sets the alignment of data blocks relative to the start of input waveform-audio data.
bass to factor	Sets the audio low frequency level.
bitspersample to bit_count	Sets the number of bits per sample recorded. The file is saved in this format. This flag applies only to devices supporting the "pcm" algorithm.
bytespersec to integer	Sets the average number of bytes per second for recording in the "pcm" and "adpcm" algorithms. The file is saved in this format.
clocktime	Indicates the time specified in the "over" flag is in milliseconds. This time is absolute and not in step with the playing of the workspace.
input	Modifies the "bass", "treble", or "volume" flag so that it affects the input signal and modifies what is recorded. If possible, this is the default when monitoring the input.
left off left on	Enables or disables audio output on the left channel. The audio presentation source can be the external input or the workspace. The default is "left on". If there is only one channel, that channel is set on or off.
left volume to factor	Sets the audio volume of the left audio channel. If there is only one channel it sets its volume.
monitor to type number number	Controls which source input will be passed to the VCR output without changing the recording source input selection. Type can be "output," or one of the valid input sources. If number is not specified, then the first input of that type will be chosen.
off on	Enables or disables audio. The audio presentation source can either be the external input or the workspace. This command affects the left and right audio channels simultaneously. The default is setaudio "on".
output	Modifies the "bass", "treble", or "volume" flag so that it modifies only the played signal and not what is recorded. If possible, this is the default when monitoring a file.
over duration	Specifies how long it should take to make a change that uses a factor variable. The units for duration are in the current time format. Changes occur in step with the playing of the workspace. When playing is suspended, the change is also suspended until the play continues. If "over" is not specified or not supported, the change occurs immediately.
quality descriptor	Specifies the characteristics of the audio compression performed when audio is recorded to a file. All devices support the three descriptors "low", "medium", and "high". The default is device specific. If the "algorithm" flag is not specified, the "quality" adjustment applies to the current algorithm. The quality command can be used to define additional descriptor names.
record off	Clears the audio-source selection so that no audio will be recorded with the next record command.
record on	Enables recording of audio data. The default is to record audio data.
record track track_number off	Clears the audio-source selection so that no audio will be recorded with the next record command. "Track" allows independent track selection. Track 2 corresponds to the PCM track in Hi8. If "track" is not specified, a default value of 1 is assumed.
record track track_number on	Selects the audio source to be recorded with the next record command. "Track" allows independent track selection. Track 2 corresponds to the PCM track in Hi8. If "track" is not specified, a default value of 1 is assumed.
right off right on	Enables or disables audio output on the right channel. The audio presentation source can be the external input or the workspace. The default is "right on". If there is only one channel, this flag has no effect.
right volume to factor	Sets the audio volume to the right audio channel. If there is only one channel, it has no effect.
samplespersec to integer	Sets the sample rate for recording with the "pcm" and "adpcm" algorithms. The file is saved in this format.
source to sourcename	Specifies the source for the audio input digitizer. The constants defined for sourcename include: "left", "right", "average", and "stereo". The first three specify monophonic recording using the left input only, the right input only, and the average of the two inputs.
source to type number number	Selects the audio source to be recorded on the tape. Type must be "tuner", "line", "svideo", "aux", "generic", or "mute".
stream to number	Specifies the audio stream played back from the workspace. If the stream is not specified and the file format does not define a default, then the interleaved audio stream that is physically first will be played.
track track_number off	Disables an individual track.
track track_number on	Enables an individual track.
treble to factor	Sets the audio high-frequency level.
volume to factor	Sets the average audio volume for both audio channels. If the left and right volumes have been set to different values, then the ratio of left-to-right volume is approximately unchanged.
lpszFlags

Can be "wait", "notify", "test", or a combination of these. For more information about these flags, see Chapter 3, "MCI Overview."

For VCR devices, using setaudio with a flag that turns off an individual track ("track track_number off") might cause your application to receive a status message indicating that the command could not be carried out. Some VCRs can turn off only combinations of tracks, not individual tracks; for example, the first audio track and a video track of a video cassette. In this case, simply use setaudio and setvideo to continue to turn off the other tracks that make up the combination. The driver will turn off the tracks when it receives the command to turn off the last track in the combination.


settimecode

wsprintf(lpstrCommand, "settimecode %s %s %s", lpszDeviceID,
    lpszTimecode, lpszFlags);

Enables or disables timecode recording for a VCR. VCR devices recognize this command.

•	Returns zero if successful or an error otherwise.

lpszDeviceID

Identifier of an MCI device. This identifier or alias is assigned when the device is opened.

lpszTimecode

One of the following flags:

record on	Sets the VCR to record timecode.
record off	Disables timecode recording.
lpszFlags

Can be "wait", "notify", "test", or a combination of these. For more information about these flags, see Chapter 3, "MCI Overview."


settuner

wsprintf(lpstrCommand, "settuner %s %s %s", lpszDeviceID, lpszTuner,
    lpszFlags);

Changes the current tuner or the channel setting of the current tuner. VCR devices recognize this command.

•	Returns zero if successful or an error otherwise.

lpszDeviceID

Identifier of an MCI device. This identifier or alias is assigned when the device is opened.

lpszTuner

One of the following flags:

channel channel	Sets the tuner to channel. You might not be able to change the channel while recording, depending on the VCR. A channel larger than the maximum sets the tuner to the maximum channel.
channel seek up channel seek down	Seeks the next channel with a valid signal. "Seek up" increments the channel number in its search. "Seek down" decrements the channel number in its search. The tuner wraps to channel 1 when the maximum channel number is exceeded. Similarly, when seeking down, the tuner wraps to the maximum channel.
channel up  channel down	Increments or decrements the tuner channel. You might not be able to change the channel while recording, depending on the VCR. The tuner wraps to channel 1 when the maximum channel number is exceeded. Similarly, when seeking down, the tuner wraps to the maximum channel.
number number	Specifies the tuner to be affected by the settuner command. If number is not given, the default value of 1 is assumed.
lpszFlags

Can be "wait", "notify", "test", or a combination of these. For more information about these flags, see Chapter 3, "MCI Overview."


setvideo

wsprintf(lpstrCommand, "setvideo %s %s %s", lpszDeviceID, lpszVideo,
    lpszFlags);

Sets values associated with video playback and capture. Digital-video and VCR devices recognize this command.

•	Returns zero if successful or an error otherwise.

lpszDeviceID

Identifier of an MCI device. This identifier or alias is assigned when the device is opened.

lpszVideo

Flag for video playback and capture. The following table lists device types that recognize the setvideo command and the flags used by each type:

digitalvideo	algorithm algorithm bitsperpel to count brightness to factor clocktime color to factor contrast to factor gamma to value halftone input key color to r:g:b key index to index off on output	over duration palette color color over index      to newrgb palette handle to handle quality descriptor record frame rate to rate  record on record off sharpness to factor source to source number value still algorithm algorithm still quality descriptor stream to number tint to factor
vcr	off on monitor to type number number record off record track track_number off	record on  record track track_number on  source to type number number track track_number off track track_number on
The following table lists the flags that can be specified in the lpszVideo parameter and their meanings:

algorithm algorithm	Specifies a video compression algorithm for use by a subsequent reserve or record command. Algorithms supported by a device are device specific. MCI defines the constants "mpeg" and "h261" for algorithm. If the specified algorithm conflicts with the current file format, the file format is changed to the default format for the algorithm.
bitsperpel to count	Sets the number of bits per pixel for saving data with the capture or record command.
brightness to factor	Sets the video brightness level.
clocktime	Indicates that the time specified in the "over" flag is in milliseconds. The time is absolute and not in step with the playing of the workspace.
color to factor	Sets the color-saturation level.
contrast to factor	Sets the video-contrast level.
gamma to value	Specifies the gamma correction exponent multiplied by 1000. For example, to specify an exponent of 2.2, use 2200 for value. A gamma value of 1.0 (1000) indicates no gamma correction is applied. Gamma correction adjusts the mapping between the intensity encoded in the presentation source and the displayed brightness.
halftone	Causes the halftone palette to be used instead of the default palette. This flag is recognized only by the MCIAVI digital-video driver.
input	Modifies the "brightness", "color", "contrast", "gamma", "sharpness", or "tint" flag so that it affects the input signal and modifies what is recorded. If possible, this is the default when monitoring the input.
key color to r:g:b	Sets the key color. The r:g:b variable is a Windows RGB value. Colons (:) separate the individual red, green, and blue values.
key index to index	Sets the key index. The index variable is a physical palette index.
monitor to type number number	Controls which source input will be passed to the VCR output, without changing the recording source input selection. Type can be "output", or one of the valid input sources. If "number" is not specified, then the first input of that type is chosen.
off on	Enables or disables display of video. Disabling video sets the pixels in the put "destination" rectangle (or its default, the client region of the current window) to a solid color. It has no effect on the frame buffer. The video source, whether the workspace or an external input, might continue to store new images in the frame buffer. They are not displayed until video is enabled. You can use the window "state" command to hide the window. The default is setvideo "on".
output	Modifies the "brightness", "color", "contrast", "gamma", "sharpness", or "tint" flag so that it modifies only the displayed signal and not what is recorded. If possible, this is the default when monitoring a file.
over duration	Specifies how long it should take to make a change that uses a factor variable. The units for duration are in the current time format. Changes occur in step with the playing of the workspace. When playing is suspended, the change is also suspended until the play continues. If "over" is not used or not supported, the change occurs immediately.
palette color color over index to newrgb	Sets a new palette color. The color and palette index to be changed are specified by the color and index parameters; the new color is specified by newrgb. This flag is recognized only by the MCIAVI digital-video driver.
palette handle to handle	Specifies the handle to a palette the device must use for rendering. This item is supported only by devices that use palettes. If handle is zero, the default palette is used. Digital-video devices should not free the palette passed with this command. Applications should free it after they close the device.
quality descriptor	Specifies the characteristics of the video compression performed when video is recorded to a file. All devices support the three descriptors: "low", "medium", and "high". The default is device specific. The significance of these names depends on the algorithm and the device. Devices might define additional descriptor names. The quality command can be used to define additional descriptor names. If the "algorithm" flag is not used, the descriptor applies to the current algorithm.
record frame rate to rate	Sets the recording for motion video. The recording rate is specified in units of frames per second multiplied by 1000. For example, the NTSC frame rate of 29.97 frames per second is represented as 29970.
record on record off	Enables or disables recording of video data. Recording video data is the default.
record track track_number off	Clears the video-source selection so that no video will be recorded with the next record command. "Track" allows independent track selection. If "track" is not specified, a default value of 1 is assumed. It might be necessary to first issue a set "assemble record off" command before the video recording can be turned off.
record track track_number on	Selects the video source to be recorded with the next record command. "Track" allows independent track selection. Track 2 corresponds to the PCM track in Hi8. If "track" is not specified, a default of 1 is assumed.
sharpness to factor	Sets the video sharpness level.
source to source number value	Sets the source of the video input. This usually corresponds to external connectors. The constants defined for source include "rgb", "pal", "ntsc", "svideo", and "secam". If more than one input of the specified type exists, the optional "number" value indicates the desired input. For example, setvideo "source to ntsc number 2" specifies the second NTSC input. If "to" source is omitted, then the absolute source is used as defined by the list "video source" command.
source to type number number	Selects the video source to be recorded on the tape. Type must be "tuner", "line", "svideo", "aux", "generic", "mute", or "rgb".
still algorithm algorithm	Specifies the still image compression algorithm used by the capture command. Every device must support an algorithm of "none", which means no compression. This is the default. In this case, digital-video devices save still images as RGB format device-independent bitmaps. Devices might also support a device-specific list of additional algorithms.
still quality descriptor	Specifies the characteristics of the still-image compression performed while capturing a still image. All devices support the descriptors "low", "medium", and "high". The default is device specific.  If the "algorithm" flag is not used, the descriptor applies to the current algorithm. The quality command can be used to define other descriptor names.
stream to number	Specifies the video stream played back from the workspace. If the stream is not specified and a default stream is not defined by the file format, then the physically first interleaved video stream is played.
tint to factor	Sets the image tint. Typically, this adjustment is modeled after the tint control of many color television sets, with 250 meaning green, 750 meaning red, and 0 (or 1000) meaning blue. The nominal value is always 500.
track track_number off	Disables an individual video track.
track track_number on	Enables an individual video track.
lpszFlags

Can be "wait", "notify", "test", or a combination of these. For more information about these flags, see Chapter 3, "MCI Overview."

For VCR devices, using setvideo with a flag that turns off an individual track ("track track_number off") might cause your application to receive a status message indicating that the command could not be carried out. Some VCRs can turn off only combinations of tracks, not individual tracks; for example, the first audio track and a video track of a video cassette. In this case, simply use setaudio and setvideo to continue to turn off the other tracks that make up the combination. The driver will turn off the tracks when it receives the command to turn off the last track in the combination.


signal

wsprintf(lpstrCommand, "signal %s %s %s", lpszDeviceID, lpszSignalFlags,
    lpszFlags);

Identifies a specified position in the workspace by sending the application an MM_MCISIGNAL message. Digital-video devices recognize this command. MCIAVI supports only one active signal at a time.

•	Returns zero if successful or an error otherwise.

lpszDeviceID

Identifier of an MCI device. This identifier or alias is assigned when the device is opened.

lpszSignalFlags

One of the following flags:

at position	Specifies the frame to invoke a signal.
cancel	Removes signals from the workspace. An individual signal is specified by using the "uservalue" flag. If the "uservalue" flag is not specified by using "cancel", the device cancels all signals. The "cancel" flag is incompatible with the "at", "every", and "return position" flags.
every interval	Specifies the period of the signals. The interval value is specified in the current time format.  If used with "at" position, signals are placed throughout the workspace with one signal mark placed at position.  Without the "at" flag, signals are placed throughout the workspace with one signal at the current position.  If this flag is omitted, only the position indicated by the "at" flag is marked.  If the interval value is less than the minimum frequency supported by a device, it will use its minimum value.
return position	Indicates the device should send the position value instead of the "uservalue" identifier in the signaling message. The "uservalue" identifier can still be used to cancel or to redefine the signal marks.
uservalue id	Specifies an identifier that is reported back with the signaling message. This identifier acts as an identifier that can be used with other signal commands to reference this signal setting. If omitted, the default value is zero.
lpszFlags

Can be "wait", "notify", "test", or a combination of these. For more information about these flags, see Chapter 3, "MCI Overview."


spin

wsprintf(lpstrCommand, "spin %s %s %s", lpszDeviceID, lpszUpDown,
    lpszFlags);

Starts spinning a disc or stops the disc from spinning. Videodisc devices recognize this command.

•	Returns zero if successful or an error otherwise.

lpszDeviceID

Identifier of an MCI device. This identifier or alias is assigned when the device is opened.

lpszUpDown

One of the following flags:

down	Stops the disc from spinning.
up	Starts spinning the disc.
lpszFlags

Can be "wait", "notify", or both. For more information about these flags, see Chapter 3, "MCI Overview."

The following command starts spinning a videodisc device:

spin videodisc up


status

wsprintf(lpstrCommand, "status %s %s %s", lpszDeviceID, lpszRequest,
    lpszFlags);

Requests status information from a device. All devices recognize this command.

•	Returns information in the lpstrReturnString parameter of mciSendString. The information is dependent on the request type.

lpszDeviceID

Identifier of an MCI device. This identifier or alias is assigned when the device is opened.

lpszRequest

Flag for requesting status information. The following table lists device types that recognize the status command and the flags used by each type:

animation	current track forward length length track number media present mode number of tracks palette handle	position position track number ready speed start position stretch time format window handle
cdaudio	cdaudio type track number current track length length track number media present mode	number of tracks position position track number ready start position time format
digitalvideo	audio audio alignment audio bitspersample audio breaks audio bytespersec audio input audio record audio source audio samplespersec audio stream bass bitsperpel brightness color contrast current track disk space drive file completion file format  file mode forward frames skipped gamma input left volume length length track number media present mode monitor monitor method nominal nominal frame rate nominal record frame rate number of tracks	output palette handle pause mode play speed position position track number ready record frame rate reference frame reserved size right volume seek exactly sharpness smpte speed start position still file format time format tint treble unsaved video video key index video key color video record video source video source number video stream volume window handle window visible window minimized window maximized
overlay	media present mode number of tracks	ready stretch window handle
sequencer	current track division type length length track number master media present mode number of tracks offset	port position position track number ready slave start position tempo time format
vcr	assemble record audio monitor audio monitor number audio record  audio record track number audio source audio source number channel channel tuner number clock clock id counter counter format counter resolution current track frame rate index index on length length track number media present media type mode number of audio tracks number of tracks number of video tracks	pause timeout play format position position start position track number postroll duration power on preroll duration ready record format speed time format time mode time type timecode present timecode record timecode type tuner number video monitor video monitor number video record video record track number video source video source number write protected
videodisc	current track disc size forward length length track number media present media type mode	number of tracks position position track number ready side speed start position time format
waveaudio	alignment bitspersample bytespersec channels current track format tag input length length track number level	media present mode number of tracks output position position track number ready samplespersec start position time format
The following table lists the flags that can be specified in the lpszRequest parameter and their meanings:

alignment	Returns the block alignment of data, in bytes.
assemble record	Returns TRUE if the device is set to assemble mode recording.
audio	Returns "on" or "off" depending on the most recent setaudio "on" or "off" command. It returns "on" if either or both speakers are enabled, and "off" otherwise.
audio alignment	Returns the alignment of data blocks relative to the start of input waveform-audio data.
audio bitspersample	Returns the number of bits per sample the device uses for recording. This flag applies only to devices supporting the "pcm" algorithm.
audio breaks	Returns the number of times the audio portion of the last AVI sequence broke up. The system counts an audio break whenever it attempts to write audio data to the device driver and discovers that the driver has already played all of the available data. This flag is recognized only by the MCIAVI digital-video driver. It is meant for performance evaluation only; the return value is difficult to interpret.
audio bytespersec	Returns the average number of bytes per second used for recording.
audio input	Returns the approximate instantaneous audio level of the analog input audio signal. A value greater than 1000 implies clipping distortion. Some devices can return this value only while recording audio. The value has no associated set or setaudio command.
audio monitor	Returns "output", or one of the valid source-input types. For more information, see the setaudio "monitor" command.
audio monitor number	Returns the monitored-video number of the type specified by status "audio monitor". For more information, see the setaudio command.
audio record	Returns "on" or "off", reflecting the state set by setaudio "record".
audio record track number	Returns TRUE if the VCR is set to record audio. If no track number is given, the default value of 1 is assumed.
audio samplespersec	Returns the number of samples per second recorded.
audio source	Returns the current audio digitizer source: "left", "right", "average", or "stereo".
audio source number	Returns the audio-source number of the type returned by status "audio source". For more information, see the setaudio command.
audio stream	Returns the current audio-stream number.
bass	Returns the current audio-bass level.
bitsperpel	Returns the number of bits per pixel for saving captured or recorded data.
bitspersample	Returns the bits per sample.
brightness	Returns the current video-brightness level.
bytespersec	Returns the average number of bytes per second played or recorded.
cdaudio type track number	Returns the type of the specified track number. This can be "audio" or "other."
channel	Returns the integer value of the channel set on the tuner.
channel tuner number	If "tuner" number is given, then the currently selected channel on the logical tuner number will be returned. Note that there can be several logical tuners.
channels	Returns the number of channels set (1 for mono, 2 for stereo).
clock	Returns the external time. The time must be an unsigned long integer expressing total increments. For more information, see the capability "clock increment rate" command.
clock id	Returns a unique integer identifying the clock.
color	Returns the current color level.
contrast	Returns the current contrast level.
counter	Returns the counter position, in the current counter format.
counter format	Returns the current counter format. For more information, see the set "counter format" command.
counter resolution	Returns "frames" or "seconds", indicating the counter's resolution. This is not the same as accuracy.
current track	Returns the current track. The MCISEQ sequencer returns 1.
disc size	Returns either 8 or 12, indicating the size of the loaded disc in inches.
disk space drive	Returns the approximate disk space, in the current time format, that can be obtained by a reserve command for the specified disk drive. The drive is usually specified as a single letter or a single letter followed by a colon (:). Some devices, however, might use a path.
division type	Returns one of the following file division types: PPQN  SMPTE 24 frame SMPTE 25 frame SMPTE 30 drop frame  SMPTE 30 frame Use this information to determine the format of the MIDI file and the meaning of tempo and position information.
file completion	Returns the estimated percentage a load, save, capture, cut, copy, delete, paste, or undo operation has progressed. (Applications can use this to provide a visual indicator of progress.)
file format	Returns the current file format for record or save commands.
file mode	Returns "loading", "saving", "editing", or "idle". During a load operation, it returns "loading". During save and capture operations, it returns "saving". During cut, copy, delete, paste, or undo operations, it returns "editing".
format tag	Returns the format tag.
forward	Returns TRUE if the play direction is forward or if the device is not playing.
frame rate	Returns the number of frames per second that the device will use by default. NTSC devices return 30, PAL 25, and so on.
frames skipped	Returns the number of frames that were not drawn when the last AVI sequence was played. This flag is recognized only by the MCIAVI digital-video driver. It is meant for performance evaluation only; the return value is difficult to interpret.
gamma	Returns the value set with setvideo "gamma to" value.
index	Returns the current index display. For more information, see the set "index" command.
index on	Returns TRUE if the index is on.
input	Returns the input set. If one is not set, the error returned indicates that any device can be used.  For digital-video devices, modifies the "bass", "treble", "volume", "brightness", "color", "contrast", "gamma", "sharpness", or "tint" flag so that it applies only to the input. This is the default when monitoring the input.
left volume	Returns the volume set for the left audio channel.
length	Returns the total length of the media, in the current time format.  For PPQN files, the length is returned in song pointer units. For SMPTE files, it is returned as hh:mm:ss:ff, where hh is hours, mm is minutes, ss is seconds, and ff is frames. For VCR devices, the length is 2 hours (unless the length has been explicitly changed using the set command).
length track number	Returns the length of the track, in time or frames, specified by number.  For PPQN files, the length is returned in song pointer units. For SMPTE files, it is returned as hh:mm:ss:ff, where hh is hours, mm is minutes, ss is seconds, and ff is frames.
level	Returns the current PCM audio sample value.
master	Returns "midi", "none", or "smpte" depending on the type of synchronization set.
media present	Returns TRUE if the media is inserted in the device or FALSE otherwise. Sequencer, video-overlay, digital-video, and waveform-audio devices return TRUE.
media type	Returns the type of the media. For VCRS, this is "8mm", "vhs", "svhs", "beta", "Hi8", "edbeta", or "other". For videodiscs, this is "CAV", "CLV", or "other", depending on the type of videodisc.
mode	Returns the current mode of the device. All devices can return the "not ready", "paused", "playing", and "stopped" values. Some devices can return the additional "open", "parked", "recording", and "seeking" values.
monitor	Returns "file" or "input". The returned value indicates the current presentation source.
monitor method	Returns "pre", "post", or "direct". The returned value indicates the method used for input monitoring.
nominal	The item modifies the "bass", "brightness", "color", "contrast", "gamma", "sharpness", "tint", "treble," and "volume" flags to return the nominal value instead of the current setting.
nominal frame rate	Returns the nominal frame rate associated with the file. The units are in frames per second multiplied by 1000.
nominal record frame rate	Returns the nominal frame rate associated with the input video signal. The units are in frames per second multiplied by 1000.
number of audio tracks	Returns the number of audio tracks on the media.
number of tracks	Returns the number of tracks on the media. The MCISEQ and MCIWAVE devices return 1, as do most VCR devices. The MCIPIONR device does not support this flag.
number of video tracks	Returns the number of video tracks on the media.
offset	Returns the offset of a SMPTE-based file. The offset is the start time of a SMPTE-based sequence. The time is returned as hh:mm:ss:ff, where hh is hours, mm is minutes, ss is seconds, and ff is frames.
output	Returns the currently set output. If no output is set, the error returned indicates that any device can be used.  For digital-video devices, modifies the "bass", "treble", "volume", "brightness", "color", "contrast", "gamma", "sharpness", or "tint" flag so that it applies only to the output. This is the default when monitoring a file.
palette handle	Returns the handle of the palette used for the animation in the low-order word of the return value.
pause mode	Returns "recording" if the device is paused while recording. It returns "playing" if the device is paused while playing. It returns the error "Action not applicable in current mode" if the device is not paused.
pause timeout	Returns the maximum duration, in milliseconds, of a pause command.
play format	Returns a code indicating the format that the videotape will be played back in, if detectable: "lp", "ep", "sp", or "other". For more information, see the "record format" flag.
play speed	Returns a value representing how closely the actual playing time of the last AVI sequence matched the target playing time. The value 1000 indicates that the target time and the actual time were the same. A value of 2000, for example, would indicate that the AVI sequence took twice as long to play as it should have. This flag is recognized only by the MCIAVI digital-video driver. It is meant for performance evaluation only; the return value is difficult to interpret.
port	Returns the MIDI port number assigned to the sequence.
position	Returns the current position. For PPQN files, the position is returned in song pointer units. For SMPTE files, it is returned as hh:mm:ss:ff, where hh is hours, mm is minutes, ss is seconds, and ff is frames.
position start	Returns the position of the start of the usable media.
position track number	Returns the position of the start of the track specified by number. For PPQN files, the time format is returned in song pointer units. For SMPTE files, it is returned as hh:mm:ss:ff, where hh is hours, mm is minutes, ss is seconds, and ff is frames. The MCISEQ sequencer returns zero. The MCIPIONR device does not support this flag. The MCIWAVE device returns zero.
postroll duration	Returns the length of videotape, in the current time format, needed to brake the VCR transport when a stop or pause command is issued.
power on	Returns TRUE if the VCR's power is on.
preroll duration	Returns the length of videotape, in the current time format, needed to stabilize the VCR output.
ready	Returns TRUE if the device is ready to accept another command.
record format	Returns a code indicating the format that the videotape will be recorded in. The current return types are "lp", "ep", "sp", or "other". These formats are not VHS specific and can be applied to any VCR that has multiple selectable recording formats. The "sp" type is the fastest, highest quality recording format and is used as default on single format VCRs.
record frame rate	Returns the frame rate, in frames per second multiplied by 1000, used for compression.
reference frame	Returns the frame number for the nearest key frame image that precedes the specified frame.
reserved size	Returns the size, in the current time format, of the reserved workspace. The size corresponds to the approximate time it would take to play the compressed data from a full workspace. It returns zero if there is no reserved disk space. This flag returns the approximate size because the precise disk space for compressed data cannot, in general, be predicted until after the data has been compressed.
right volume	Returns the volume set for the right audio channel.
samplespersec	Returns the number of samples per second played or recorded.
seek exactly	Returns "on" or "off", indicating whether or not the "seek exactly" flag is set.
sharpness	Returns the current sharpness level of the device.
side	Returns 1 or 2 to indicate which side of the videodisc is loaded.
slave	Returns "file", "midi", "none", or "smpte" depending on the type of synchronization set.
smpte	Returns the SMPTE timecode associated with the current position in the workspace. This is a string with the form dd:dd:dd:dd, where each d denotes a digit from 0 to 9. If the workspace data does not include timecode data, then this flag returns 00:00:00:00.
speed	Returns the current speed of the device in frames per second (or in the same format used by the set "speed" command). The MCIPIONR videodisc player does not support this flag.
start position	Returns the starting position of the media.
still file format	Returns the current file format for the capture command.
stretch	Returns TRUE if stretching is enabled.
tempo	Returns the current tempo of a MIDI sequence in the current time format. For files with PPQN format, the tempo is in beats per minute. For files with SMPTE format, the tempo is in frames per second.
time format	Returns the current time format. For more information, see the time formats in the set command.
time mode	Returns the current position time mode. It can be "detect", "timecode", or "counter".
time type	Returns the current position time in use: "timecode" or "counter".
timecode present	Returns TRUE if timecode has been recorded at the current position on the tape. The timecode must advance from the current position. A VCR might need to be played to check this condition.
timecode record	Returns TRUE if the VCR is set to record timecode.
timecode type	Returns "smpte", "smpte drop", "other", or "none". Note the frames per second can be obtained from the status "frame rate" command, and the accuracy of the device can be returned by the capability "seek accuracy" command.
tint	Returns the current video-tint level.
treble	Returns the current audio-treble level.
tuner number	Returns the current logical-tuner number.
unsaved	Returns TRUE if there is recorded data in the workspace that might be lost as a result of a close, load, record, reserve, cut, delete, or paste command. Returns FALSE otherwise.
video	Returns "on" or "off", reflecting the state set by the setvideo command.
video key color	Returns the value for the key color.
video key index	Returns the value for the key index.
video monitor	Returns "output" or one of the valid source-input types. For more information, see the setvideo "monitor" command.
video monitor number	Returns the monitored-video number of the type returned by status "video monitor". For more information, see the setvideo command.
video record	Returns "on" or "off", reflecting the current state set by setvideo "record".
video record track number	Return TRUE if the VCR is set to record video. If no track number is given, the default value of 1 is assumed.
video source	Returns the video-source type. For more information, see the setvideo command.
video source number	Returns a number corresponding to the video source of the type in use. For example, it returns 2 if the second NTSC video source input is being used.
video stream	Returns the current video-stream number.
volume	Returns the average volume to the left and right speaker. This returns an error if the device has not been played or volume has not been set.
window handle	Returns ASCII decimal value for the window handle in the low-order word of the return value.
window maximized	Returns TRUE if the window is maximized.
window minimized	Returns TRUE if the window is minimized.
window visible	Returns TRUE if the window is not hidden.
write protected	Returns TRUE if the device detects that it cannot record (that is, if the write protect is on). If it can record, or if it is unable to determine whether or not it can record (without actually writing), the driver returns FALSE.
lpszFlags

Can be "wait", "notify", or both. For digital-video and VCR devices, "test" can also be specified. For more information about these flags, see Chapter 3, "MCI Overview."

Before issuing any commands that use position values, you should set the desired time format by using the set command.

The following command returns the current mode of the "mysound" device:

status mysound mode


step

wsprintf(lpstrCommand, "step %s %s %s", lpszDeviceID, lpszStepFlags,
    lpszFlags);

Steps the play one or more frames forward or reverse. The default action is to step forward one frame. Animation, digital-video, VCR, and CAV-format videodisc devices recognize this command.

•	Returns zero if successful or an error otherwise.

lpszDeviceID

Identifier of an MCI device. This identifier or alias is assigned when the device is opened.

lpszStepFlags

One or both of the following flags:

by frames	Indicates the number of frames to step. If you specify a negative frames value, you cannot specify the "reverse" flag.
reverse	Step the frames in reverse.
lpszFlags

Can be "wait", "notify", or both. For digital-video and VCR devices, "test" can also be specified. For more information about these flags, see Chapter 3, "MCI Overview."

The following command plays five frames of the animation file associated with the "movie" device, starting at the current frame:

step movie by 5


stop

wsprintf(lpstrCommand, "stop %s %s %s", lpszDeviceID, lpszStopFlags,
    lpszFlags);

Stops playback or recording. Animation, CD audio, digital-video, MIDI sequencer, videodisc, VCR, and waveform-audio devices recognize this command.

•	Returns zero if successful or an error otherwise.

lpszDeviceID

Identifier of an MCI device. This identifier or alias is assigned when the device is opened.

lpszStopFlags

For digital-video devices, it can be the following flag:

hold	Prevents the release of resources required to redraw a still image on the screen. The frame buffer remains available for use in updating the display when, for example, the window is moved.
lpszFlags

Can be "wait", "notify", or both. For digital-video and VCR devices, "test" can also be specified. For more information about these flags, see Chapter 3, "MCI Overview."

For CD audio devices, the stop command stops playback and resets the current track position to zero.

The following command stops playback or recording on the "mysound" device:

stop mysound


sysinfo

wsprintf(lpstrCommand, "sysinfo %s %s %s", lpszDeviceID, lpszRequest,
    lpszFlags);

Retrieves MCI system information. The sysinfo command is an MCI system command; it is interpreted directly by MCI.

•	Returns zero if successful or an error otherwise.

lpszDeviceID

Identifier of an MCI device or device type. If a device type is specified, it must be a standard MCI device-type name, as listed in the reference material for the capability command. You can specify "all" when the flag specified in lpszRequest allows that possibility.

lpszRequest

One of the following flags:

installname	Returns the name listed in the registry or the SYSTEM.INI file used to install the open device with the specified device identifier.
quantity	Returns the number of MCI devices listed in the registry or the SYSTEM.INI file of the type specified in the lpszDeviceID parameter. This device identifier must be a standard MCI device-type name. Any digits after the device type are ignored. Specifying "all" for lpszDeviceID returns the total number of MCI devices in the system.
quantity open	Returns the number of open MCI devices of the type specified in lpszDeviceID. This device identifier must be a standard MCI device-type name. Specifying "all" for lpszDeviceID returns the total number of open MCI devices in the system.
name index	Returns the name of an MCI device. The device identifier must be a standard MCI device-type name. The index ranges from 1 to the number of devices of that type. If "all" is specified for lpszDeviceID, index ranges from 1 to the total number of devices in the system.
name index open	Returns the name of an open MCI device. The device identifier must be a standard MCI device-type name. The index ranges from 1 to the number of open devices of that device type. If "all" is specified for lpszDeviceID, index ranges from 1 to the total number of open devices in the system.
lpszFlags

Can be "wait", "notify", or both. For digital-video and VCR devices, "test" can also be specified. For more information about these flags, see Chapter 3, "MCI Overview."

The following command returns the number of open waveform-audio devices:

sysinfo waveaudio quantity open

The following command returns the name (device alias) of the first open waveform-audio device:

sysinfo waveaudio name 1 open


undo

wsprintf(lpstrCommand, "undo %s %s", lpszDeviceID, lpszFlags);

Reverses the action taken by the most recent successful copy, cut, delete, undo, or paste command. Digital-video devices recognize this command.

•	Returns zero if successful or an error otherwise.

lpszDeviceID

Identifier of an MCI device. This identifier or alias is assigned when the device is opened.

lpszFlags

Can be "wait", "notify", "test", or a combination of these. For more information about these flags, see Chapter 3, "MCI Overview."


unfreeze

wsprintf(lpstrCommand, "unfreeze %s %s %s", lpszDeviceID, lpszUnfreeze,
    lpszFlags);

Reenables video acquisition to the frame buffer after it has been disabled by the freeze command. Digital-video, VCR, and video-overlay devices recognize this command.

•	Returns zero if successful or an error otherwise.

lpszDeviceID

Identifier of an MCI device. This identifier or alias is assigned when the device is opened.

lpszUnfreeze

Flag for reenabling video acquisition to the frame buffer. The following table lists device types that recognize the unfreeze command and the flags used by each type:

digitalvideo	at rectangle
overlay	at rectangle
vcr	input output
The following table lists the flags that can be specified in the lpszUnfreeze parameter and their meanings:

at rectangle	Specifies the region that will have video acquisition reenabled. The rectangle is relative to the video buffer origin and is specified as X1 Y1 X2 Y2. The coordinates X1 Y1 specify the upper left corner of the rectangle, and the coordinates X2 Y2 specify the width and height.
input	Unfreeze the input image.
output	Unfreeze the output image. If neither "input" nor "output" is given, "output" is assumed.
lpszFlags

Can be "wait", "notify", or both. For digital-video and VCR devices, "test" can also be specified. For more information about these flags, see Chapter 3, "MCI Overview."

The following command unfreezes a region of the video buffer:

unfreeze vboard at 10 20 90 165


update

wsprintf(lpstrCommand, "update %s %s %s", lpszDeviceID, lpszHDC,
    lpszFlags);

Repaints the current frame into the specified device context (DC). Animation and digital-video devices recognize this command.

•	Returns zero if successful or an error otherwise.

lpszDeviceID

Identifier of an MCI device. This identifier or alias is assigned when the device is opened.

lpszHDC

Handle of a DC. The following table lists device types that recognize the update command and the flags used by each type:

animation	hdc hdc	hdc hdc at rect
digitalvideo	hdc hdc hdc hdc at rect	paint hdc hdc
The following table lists the flags that can be specified in the lpszHDC parameter and their meanings:

hdc hdc	Specifies the handle of the DC to paint.
hdc hdc at rect	Specifies the clipping rectangle relative to the client rectangle.
paint hdc hdc	Paints the DC when the application receives a WM_PAINT message intended for a DC.
To specify the handle of the DC, use the string "hdc" followed by an ASCII representation of the handle. The rectangle is specified as X1 Y1 X2 Y2. The coordinates X1 Y1 specify the upper left corner of the rectangle, and the coordinates X2 Y2 specify the width and height.

lpszFlags

Can be "wait", "notify", or both. For digital-video devices, "test" can also be specified. For more information about these flags, see Chapter 3, "MCI Overview."

The following command updates the entire display window used by the "movie" device. The number 203 is a handle to a DC obtained from the BeginPaint function:

update movie hdc 203


where

wsprintf(lpstrCommand, "where %s %s %s", lpszDeviceID, lpszRequestRect,
    lpszFlags);

Retrieves the rectangle specifying the source or destination area. This rectangle was specified using the put command. Animation, digital-video, and video-overlay devices recognize this command.

•	Returns a rectangle in the lpstrReturnString parameter of the mciSendString function. The rectangle describes the area specified in the lpszRequestRect parameter of this command. The rectangle is specified as X1 Y1 X2 Y2. The coordinates X1 Y1 specify the upper left corner of the rectangle, and the coordinates X2 Y2 specify the width and height.

lpszDeviceID

Identifier of an MCI device. This identifier or alias is assigned when the device is opened.

lpszRequestRect

Flag that identifies the rectangle whose dimensions are retrieved. The following table lists device types that recognize the where command and the flags used by each type:

animation	destination	source
digitalvideo	destination destination max frame frame max source	source max video video max window window max
overlay	destination frame	source video
The following table lists the flags that can be specified in the lpszRequestRect parameter and their meanings:

destination	Retrieves the destination offset and extent. For video-overlay devices, the destination rectangle defines the area of the display window client area that displays the image data from the frame buffer.
destination max	Retrieves the current size of the client rectangle.
frame	Retrieves the offset and extent of the frame buffer rectangle. The frame buffer rectangle defines the area of the frame buffer that receives incoming video data. Images from the "video" rectangle are scaled into this region.
frame max	Returns the maximum size of the frame buffer.
source	Retrieves the source offset and extent. For video-overlay devices, the source rectangle defines the region of the frame buffer that is displayed in the destination window. The device uses this rectangle to crop the image before it is stretched to fit the destination rectangle on the display.
source max	Retrieves the maximum size of the frame buffer.
video	Retrieves the offset and extent of the video rectangle. The video rectangle defines the region of the incoming video data that is transferred to the frame buffer.
video max	Returns the maximum size of the input.
window	Retrieves the current size and position of the display-window frame.
window max	Retrieves the size of the entire display.
lpszFlags

Can be "wait", "notify", or both. For digital-video devices, "test" can also be specified. For more information about these flags, see Chapter 3, "MCI Overview."

The following command returns the display rectangle of the "movie" device:

where movie destination


window

wsprintf(lpstrCommand, "window %s %s %s", lpszDeviceID, lpszWindowFlags,
    lpszFlags);

Controls the display window. You can use this command to change the display characteristics of the window or provide a destination window for the driver to use in place of the default display window. Animation, digital-video, and video-overlay devices recognize this command.

•	Returns zero if successful or an error otherwise.

lpszDeviceID

Identifier of an MCI device. This identifier or alias is assigned when the device is opened.

lpszWindowFlags

Flag for controlling the display window. The following table lists device types that recognize the window command and the flags used by each type:

animation	fixed handle default handle hwnd state hide state iconic state maximized state minimize state minimized state no action state no activate state normal	state restore state show show maximized show minimized show min noactive show na show noactivate show normal stretch text caption
digitalvideo	handle hwnd state hide state minimize state restore state show show maximized	show minimized show min noactive show na show noactivate show normal text caption
overlay	fixed handle default handle hwnd state hide state iconic state maximized state minimize state minimized state no action state no activate state normal	state restore state show show maximized show minimized show min noactive show na show noactivate show normal stretch text caption
The following table lists the flags that can be specified in the lpszWindowFlags parameter and their meanings:

fixed	Disables stretching of the image.
handle default	Specifies that the device should set the display window back to the default window created during the open operation. For  video-overlay devices, specifies that the device should create and manage its own destination window.
handle hwnd	Specifies the handle of the destination window to use instead of the default window. The hwnd parameter contains the ASCII numeric equivalent of the window handle returned by the CreateWindow function. Two device instances can use the same window handle provided that each instance updates the video and image pixels in the window as if the other instance did not exist. When video output is disabled with setvideo "off", an update command will make the destination rectangle a solid color.
show maximized	Maximizes the destination window.
show min noactive	Displays the destination window as an icon.
show minimized	Minimizes the destination window.
show na	Displays the destination window in its current state; the window that is currently active remains active.
show noactivate	Displays the destination window in its most recent size and position; the window that is currently active remains active.
show normal	Activates and displays the destination window in its original size and position. (This is the same as the "state restore" flag.)
state hide	Hides the destination window.
state iconic	Displays the destination window as an icon.
state maximized	Maximizes the destination window.
state minimize	Minimizes the destination window and activates the top-level window in the window-manager's list.
state minimized	Minimizes the destination window.
state no action	Displays the destination window in its current state. The window that is currently active remains active.
state no activate	Displays the destination window in its most recent size and state. The currently active window remains active.
state normal	Activates and displays the destination window in its original size and position.
state restore	Activates and displays the destination window in its original size and position.
state show	Shows the destination window.
stretch	Enables stretching of the image.
text caption	Specifies the caption for the destination window. If this text contains embedded blanks, the entire caption must be enclosed in quotation marks. The default caption for the default window is blank.
lpszFlags

Can be "wait", "notify", or both. For digital-video devices, "test" can also be specified. For more information about these flags, see Chapter 3, "MCI Overview."

Generally, animation devices create a window when opened but don't display the window until they receive a play command. Video-overlay devices, on the other hand, typically create and display a window when opened. If your application provides a window to the driver, your application is responsible for managing the messages sent to the window.

Since you can use the status command to retrieve the handle to the driver display window, you can also use the standard window manager functions (such as ShowWindow) to manipulate the window.

The following command displays and sets the caption for the "movie" playback window:

window movie text "Welcome to the Movies" state show


MCI Command Messages

The Media Control Interface (MCI) is a high-level command interface to multimedia devices and resource files. MCI provides standard commands for playing multimedia devices and recording multimedia resource files. MCI commands are a generic interface to multimedia devices.

There are two forms of MCI commands: strings and messages. You can use either or both forms in your MCI application. This chapter documents the command-message interface to MCI. For information about the command-string interface, see Chapter 4, "MCI Command Strings." For an overview of MCI, including information about whether you should use the string interface or the message interface in your application, see Chapter 3, "MCI Overview."

The command-message interface is designed to be used by applications requiring a C-language interface to control multimedia devices. It uses a message-passing paradigm to communicate with MCI devices. You can send a command by using the mciSendCommand function.


Syntax of Command Messages

MCI command messages consist of the following three elements:

•	A constant message value

•	A structure containing parameters for the command

•	A set of flags specifying options for the command and validating fields in the parameter block

The following example sends the MCI_PLAY command to the device identified by a device identifier:

mciSendCommand(wDeviceID,            // device identifier
    MCI_PLAY,                        // command message
    0,                               // flags
    (DWORD)(LPVOID) &mciPlayParms);  // parameter block

The device identifier given in the first parameter is retrieved when the device is opened using the MCI_OPEN command. The last parameter is the address of an MCI_PLAY_PARMS structure, which might contain information about where to begin and end playback. Many MCI command messages use a structure to contain parameters of this kind. The first member of each of these structures identifies the window that receives an MM_MCINOTIFY message when the operation finishes.


Sending Command Messages

The Microsoft Windows operating system provides two functions for sending command messages to devices and to query devices for error information: mciSendCommand and mciGetErrorString. The mciSendCommand function sends a command message to an MCI device. The mciGetErrorString function returns the error string corresponding to an error number.

The mciSendCommand function returns zero if successful. If the function fails, the low-order word of the return value contains an error code. You can pass this error code to mciGetErrorString to get a text description of it.


Using MCI Command Messages

This section contains examples demonstrating how to perform the following tasks:

•	Close all MCI devices used by an application.

•	Open a simple device by using the device name.

•	Open a simple device by using the device-type constant.

•	Open a compound device by using a filename.

•	Verify the output device.

•	Select the MIDI mapper as the output device.

•	Handle MCI errors.

•	Play a waveform-audio file.

•	Play a MIDI file.

•	Play a compact disc (CD) track.

•	Play a movie.

•	Use the MCI_NOTIFY flag.

•	Retrieve information about a movie.

•	Retrieve CD track-specific information.

•	Record with a waveform-audio device.


Closing All MCI Devices Used by an Application

The following example closes all of the MCI devices that are opened by an application:

UINT wDeviceID;
DWORD dwReturn;

// Closes all MCI devices opened by this application.
// Waits until devices are closed before returning.
if (dwReturn = mciSendCommand(MCI_ALL_DEVICE_ID, MCI_CLOSE, MCI_WAIT,
    NULL))
    .
    . // Error, unable to close all devices.
    .


Opening a Simple Device by Using the Device Name

The following example opens a CD audio device by specifying the device name:

UINT wDeviceID;
DWORD dwReturn;
MCI_OPEN_PARMS mciOpenParms;

// Opens a CD audio device by specifying the device name.
mciOpenParms.lpstrDeviceType = "cdaudio";
if (dwReturn = mciSendCommand(NULL, MCI_OPEN, MCI_OPEN_TYPE,
    (DWORD)(LPVOID) &mciOpenParms))
    .
    . // Error, unable to open device.
    .
// The device opened successfully; get the device ID.
wDeviceID = mciOpenParms.wDeviceID;


Opening a Simple Device by Using the Device-Type Constant

The following example opens a CD audio device by specifying a device-type constant:

UINT wDeviceID;
DWORD dwReturn;
MCI_OPEN_PARMS mciOpenParms;

// Opens a CD audio device by specifying a device-type constant.
mciOpenParms.lpstrDeviceType = (LPCSTR) MCI_DEVTYPE_CD_AUDIO;
if (dwReturn = mciSendCommand(NULL, MCI_OPEN,
    MCI_OPEN_TYPE | MCI_OPEN_TYPE_ID, (DWORD)(LPVOID) &mciOpenParms))
    .
    . // Error, unable to open device.
    .
// The device opened successfully; get the device ID.
wDeviceID = mciOpenParms.wDeviceID;


Opening a Compound Device by Using the Filename

The following example opens the waveform-audio device by specifying a waveform-audio file named "TIMPANI.WAV":

UINT wDeviceID;
DWORD dwReturn;
MCI_OPEN_PARMS mciOpenParms;

// Opens a waveform-audio device by specifying the device and filename.
mciOpenParms.lpstrDeviceType = "waveaudio";
mciOpenParms.lpstrElementName = "timpani.wav";
if (dwReturn = mciSendCommand(NULL, MCI_OPEN,
    MCI_OPEN_TYPE | MCI_OPEN_ELEMENT, (DWORD)(LPVOID) &mciOpenParms))
    .
    . // Error, unable to open device.
    .
// The device opened successfully; get the device ID.
wDeviceID = mciOpenParms.wDeviceID;


Verifying the Output Device

After opening the sequencer, you should check whether the MIDI mapper was available and selected as the output device. The following example uses the MCI_STATUS command to verify that the MIDI mapper is the output device for the MCI sequencer:

UINT wDeviceID;      // valid MCI sequencer ID
DWORD dwReturn;
MCI_STATUS_PARMS mciStatusParms;
.
. // Make sure the opened device is the MIDI mapper.
.
mciStatusParms.dwItem = MCI_SEQ_STATUS_PORT;
if (dwReturn = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM,
    (DWORD)(LPVOID) &mciStatusParms))
{
    .
    . // Error sending MCI_STATUS command.
    .
    return;
}
if (LOWORD(mciStatusParms.dwReturn) == MIDI_MAPPER)
    .
    . // The MIDI mapper is the output device.
    .
else
    .
    . // The MIDI mapper is not the output device.
    .


Handling MCI Errors

You should always check the return value of the mciSendCommand function. If it indicates an error, you can use mciGetErrorString to get a textual description of the error.

The following example passes the MCI error code specified by dwError to mciGetErrorString, and then displays the resulting textual error description using the MessageBox function.

// Uses mciGetErrorString to get a textual description of an MCI error.
// Displays the error description using MessageBox.
void showError(DWORD dwError)
{
    char szErrorBuf[MAXERRORLENGTH];
    MessageBeep(MB_ICONEXCLAMATION);
    if(mciGetErrorString(dwError, (LPSTR) szErrorBuf, MAXERRORLENGTH))
        MessageBox(hMainWnd, szErrorBuf, "MCI Error",
        MB_ICONEXCLAMATION);
    else
        MessageBox(hMainWnd, "Unknown Error", "MCI Error",
            MB_ICONEXCLAMATION);
}

Note  To interpret an mciSendCommand error return value yourself, mask the high-order word (the low-order word contains the error code). If you pass the error return value to mciGetErrorString, however, you must pass the entire doubleword value.


Playing a Waveform-Audio File

The following example opens a waveform-audio device and plays the waveform-audio file specified by the lpszWAVEFileName parameter:

// Plays a given waveform-audio file using MCI_OPEN and MCI_PLAY.
// Returns when playback begins. Returns 0L on success, otherwise
// returns an MCI error code.
DWORD playWAVEFile(HWND hWndNotify, LPSTR lpszWAVEFileName)
{
    UINT wDeviceID;
    DWORD dwReturn;
    MCI_OPEN_PARMS mciOpenParms;
    MCI_PLAY_PARMS mciPlayParms;

    // Open the device by specifying the device and filename.
    // MCI will choose a device capable of playing the given file.
    mciOpenParms.lpstrDeviceType = "waveaudio";
    mciOpenParms.lpstrElementName = lpszWAVEFileName;
    if (dwReturn = mciSendCommand(0, MCI_OPEN,
       MCI_OPEN_TYPE | MCI_OPEN_ELEMENT, (DWORD)(LPVOID) &mciOpenParms))
    {
        // Failed to open device. Don't close it; just return error.
        return (dwReturn);
    }

    // The device opened successfully; get the device ID.
    wDeviceID = mciOpenParms.wDeviceID;

    // Begin playback. The window procedure function for the parent
    // window will be notified with an MM_MCINOTIFY message when
    // playback is complete. At this time, the window procedure closes
    // the device.
    mciPlayParms.dwCallback = (DWORD) hWndNotify;
    if (dwReturn = mciSendCommand(wDeviceID, MCI_PLAY, MCI_NOTIFY,
        (DWORD)(LPVOID) &mciPlayParms))
    {
        mciSendCommand(wDeviceID, MCI_CLOSE, 0, NULL);
        return (dwReturn);
    }

    return (0L);
}


Playing a MIDI File

The following example opens a MIDI sequencer device, verifies that the MIDI mapper was selected as the output port, plays the MIDI file specified by the lpszMIDIFileName parameter, and closes the device after playback is complete:

// Plays a specified MIDI file by using MCI_OPEN and MCI_PLAY. Returns
// as soon as playback begins. The window procedure function for the
// given window will be notified when playback is complete. Returns 0L
// on success; otherwise, it returns an MCI error code.
DWORD playMIDIFile(HWND hWndNotify, LPSTR lpszMIDIFileName)
{
    UINT wDeviceID;
    DWORD dwReturn;
    MCI_OPEN_PARMS mciOpenParms;
    MCI_PLAY_PARMS mciPlayParms;
    MCI_STATUS_PARMS mciStatusParms;
    MCI_SEQ_SET_PARMS mciSeqSetParms;

    // Open the device by specifying the device and filename.
    // MCI will attempt to choose the MIDI mapper as the output port.
    mciOpenParms.lpstrDeviceType = "sequencer";
    mciOpenParms.lpstrElementName = lpszMIDIFileName;
    if (dwReturn = mciSendCommand(NULL, MCI_OPEN,
        MCI_OPEN_TYPE | MCI_OPEN_ELEMENT,
        (DWORD)(LPVOID) &mciOpenParms))
    {
        // Failed to open device. Don't close it; just return error.
        return (dwReturn);
    }

    // The device opened successfully; get the device ID.
    wDeviceID = mciOpenParms.wDeviceID;

    // Check if the output port is the MIDI mapper.
    mciStatusParms.dwItem = MCI_SEQ_STATUS_PORT;
    if (dwReturn = mciSendCommand(wDeviceID, MCI_STATUS,
        MCI_STATUS_ITEM, (DWORD)(LPVOID) &mciStatusParms))
    {
        mciSendCommand(wDeviceID, MCI_CLOSE, 0, NULL);
        return (dwReturn);
    }

    // The output port is not the MIDI mapper.
    // Ask if the user wants to continue.
    if (LOWORD(mciStatusParms.dwReturn) != MIDI_MAPPER)
    {
        if (MessageBox(hMainWnd,
            "The MIDI mapper is not available. Continue?",
            "", MB_YESNO) == IDNO)
        {
            // User does not want to continue. Not an error;
            // just close the device and return.
            mciSendCommand(wDeviceID, MCI_CLOSE, 0, NULL);
            return (0L);
        }
    }

    // Begin playback. The window procedure function for the parent
    // window will be notified with an MM_MCINOTIFY message when
    // playback is complete. At this time, the window procedure closes
    // the device.
    mciPlayParms.dwCallback = (DWORD) hWndNotify;
    if (dwReturn = mciSendCommand(wDeviceID, MCI_PLAY, MCI_NOTIFY,
        (DWORD)(LPVOID) &mciPlayParms))
    {
        mciSendCommand(wDeviceID, MCI_CLOSE, 0, NULL);
        return (dwReturn);
    }

    return (0L);
}


Playing a Compact Disc Track

The following example opens a CD audio device, plays the track specified by the bTrack parameter, and closes the device after playback is complete:

// Plays a given CD audio track using MCI_OPEN, MCI_PLAY. Returns as
// soon as playback begins. The window procedure function for the given
// window will be notified when playback is complete. Returns 0L on
// success; otherwise, returns an MCI error code.
DWORD playCDTrack(HWND hWndNotify, BYTE bTrack)
{
    UINT wDeviceID;
    DWORD dwReturn;
    MCI_OPEN_PARMS mciOpenParms;
    MCI_SET_PARMS mciSetParms;
    MCI_PLAY_PARMS mciPlayParms;

    // Open the CD audio device by specifying the device name.
    mciOpenParms.lpstrDeviceType = "cdaudio";
    if (dwReturn = mciSendCommand(NULL, MCI_OPEN,
        MCI_OPEN_TYPE, (DWORD)(LPVOID) &mciOpenParms))
    {
        // Failed to open device. Don't close it; just return error.
        return (dwReturn);
    }

    // The device opened successfully; get the device ID.
    wDeviceID = mciOpenParms.wDeviceID;

    // Set the time format to track/minute/second/frame (TMSF).
    mciSetParms.dwTimeFormat = MCI_FORMAT_TMSF;
    if (dwReturn = mciSendCommand(wDeviceID, MCI_SET,
        MCI_SET_TIME_FORMAT, (DWORD)(LPVOID) &mciSetParms))
    {
        mciSendCommand(wDeviceID, MCI_CLOSE, 0, NULL);
        return (dwReturn);
    }

    // Begin playback from the given track and play until the beginning
    // of the next track. The window procedure function for the parent
    // window will be notified with an MM_MCINOTIFY message when
    // playback is complete. Unless the play command fails, the window
    // procedure closes the device.
    mciPlayParms.dwFrom = 0L;
    mciPlayParms.dwTo = 0L;
    mciPlayParms.dwFrom = MCI_MAKE_TMSF(bTrack, 0, 0, 0);
    mciPlayParms.dwTo = MCI_MAKE_TMSF(bTrack + 1, 0, 0, 0);
    mciPlayParms.dwCallback = (DWORD) hWndNotify;
    if (dwReturn = mciSendCommand(wDeviceID, MCI_PLAY,
        MCI_FROM | MCI_TO | MCI_NOTIFY, (DWORD)(LPVOID) &mciPlayParms))
    {
        mciSendCommand(wDeviceID, MCI_CLOSE, 0, NULL);
        return (dwReturn);
    }

    return (0L);
}

To specify a position relative to a track on a CD, you must use the track/minute/second/frame (TMSF) time format.


Playing a Movie

The following examples show how to set up and play an audio-video interleaved (AVI) file.


Opening the Playback Window

The following example shows how to use the MCI_OPEN command to set a parent window and create a child of that window:

MCI_DGV_OPEN_PARMS    mciOpen;

mciOpen.lpstrElementName = lpstrFile;  // set the filename

mciOpen.dwStyle = WS_CHILD;            // set the style

mciOpen.hWndParent = hWnd;             // give a window handle

if (mciSendCommand(0, MCI_OPEN,

   (DWORD)(MCI_OPEN_ELEMENT|MCI_DGV_OPEN_PARENT|MCI_DGV_OPEN),

   (DWORD)(LPSTR)&mciOpen) == 0){

    // Open operation is successful. Continue.

}


Setting Up the Playback Window

The following example finds the dimensions needed to play an AVI file, creates a window corresponding to that size, and plays the file in the window by using the MCIAVI driver:

HWND hwnd;

MCI_DGV_RECT_PARMS mciRect;

// Get the movie dimensions with MCI_WHERE.

mciSendCommand(wDeviceID, MCI_WHERE, MCI_DGV_WHERE_SOURCE,

    (DWORD)(LPSTR)&mciRect);

// Create the playback window. Make it bigger for the border.

// Note that the right and bottom members of RECT structures in MCI

// are unusual; rc.right is set to the rectangle's width, and rc.bottom
// is set to the rectangle's height.
hwndMovie = CreateWindow("mywindow", "Playback",

    WS_CHILD|WS_BORDER, 0,0,

    mciRect.rc.right+(2*GetSystemMetric(SM_CXBORDER)),
    mciRect.rc.bottom+(2*GetSystemMetric(SM_CYBORDER)),

    hwndParent, hInstApp, NULL);

if (hwndMovie){

    // Window created OK; make it the playback window.

    MCI_DGV_WINDOW_PARMS mciWindow;

    mciWindow.hWnd = hwndMovie;

    mciSendCommand(wDeviceID, MCI_WINDOW, MCI_DGV_WINDOW_HWND,

        (DWORD)(LPSTR)&mciWindow);

}


Playing the AVI File

Before using the mciSendCommand function to send the MCI_PLAY command, your application allocates the memory for the structure, initializes the members it will use, and sets the flags corresponding to the members used in the structure. (If your application does not set a flag for a structure member, MCI drivers ignore the member.) For example, the following example plays a movie from the starting location specified by dwFrom to the ending location specified by dwTo. (If either location is zero, the example assumes the location is not used.)

DWORD PlayMovie(WORD wDevID, DWORD dwFrom, DWORD dwTo)

{

    MCI_DGV_PLAY_PARMS mciPlay;    // play parameters

    DWORD dwFlags = 0;

    // Check dwFrom. If it is != 0 then set parameters and flags.

    if (dwFrom){

        mciPlay.dwFrom = dwFrom; // set parameter

        dwFlags |= MCI_FROM;     // set flag to validate member

    }

    // Check dwTo. If it is != 0 then set parameters and flags.

    if (dwTo){

        mciPlay.dwTo = dwTo;    // set parameter

        dwFlags |= MCI_TO;      // set flag to validate member

    }

    // Send the MCI_PLAY command and return the result.

    return mciSendCommand(wDevID, MCI_PLAY, dwFlags,

       (DWORD)(LPVOID)&mciPlay);

}


Using the MCI_NOTIFY Flag

The following example shows how the MCI_NOTIFY flag is used with the MCI_PLAY command. The handle to the window procedure that will process the MM_MCINOTIFY message is specified in hwnd.

MCI_DGV_PLAY_PARMS mciPlay;

DWORD dwFlags;

mciPlay.dwCallback = MAKELONG(hwnd, 0);

dwFlags = MCI_NOTIFY;

mciSendCommand(wMCIDeviceID, MCI_PLAY, dwFlags, (DWORD)(LPSTR)&mciPlay);


Retrieving Information About a Movie

The following example sets the time format to frames and obtains the current position if the device is playing:

MCI_DGV_SET_PARMS mciSet;

MCI_DGV_STATUS_PARMS mciStatus;

// Put in frame mode.

mciSet.dwTimeFormat = MCI_FORMAT_FRAMES;

mciSendCommand(wDeviceID, MCI_SET,

    MCI_SET_TIME_FORMAT,
    (DWORD)(LPSTR)&mciSet);

mciStatus.dwItem = MCI_STATUS_MODE;

mciSendCommand(wDeviceID, MCI_STATUS,

    MCI_STATUS_ITEM,

    (DWORD)(LPSTR)&mciStatus);

// If device is playing, get the position.

if (mciStatus.dwReturn == MCI_MODE_PLAY){

mciStatus.dwItem = MCI_STATUS_POSITION;

mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM,

(DWORD)(LPSTR)&mciStatus);

// Update the position from mciStatus.dwReturn.

}


Retrieving Compact Disc Track-Specific Information

For CD audio devices, you can get the starting location and length of a track by specifying the MCI_TRACK flag and setting the dwTrack member of MCI_STATUS_PARMS to the desired track number. To get the starting location of a track, set the dwItem member to MCI_STATUS_POSITION. To get the length of a track, set dwItem to MCI_STATUS_LENGTH. For example, the following example retrieves the total number of tracks on the CD and the starting location of each track. Then, it uses the MessageBox function to report the starting locations of the tracks.

// Uses the MCI_STATUS command to get and display the
// starting times for the tracks on a CD.
// Returns 0L if successful; otherwise, it returns an
// MCI error code.
DWORD getCDTrackStartTimes(VOID)
{
    UINT wDeviceID;
    int i, iNumTracks;
    DWORD dwReturn;
    DWORD dwPosition;
    DWORD *pMem;
    char szTempString[64];
    char szTimeString[512] = "\0";  // room for 20 tracks
    MCI_OPEN_PARMS mciOpenParms;
    MCI_SET_PARMS mciSetParms;
    MCI_STATUS_PARMS mciStatusParms;

    // Open the device by specifying the device name.

    mciOpenParms.lpstrDeviceType = "cdaudio";
    if (dwReturn = mciSendCommand(NULL, MCI_OPEN,
        MCI_OPEN_TYPE, (DWORD)(LPVOID) &mciOpenParms))
    {
        // Failed to open device;

        // don't have to close it, just return error.
        return (dwReturn);
    }

    // The device opened successfully; get the device ID.
    wDeviceID = mciOpenParms.wDeviceID;

// Set the time format to minute/second/frame (MSF) format.

    mciSetParms.dwTimeFormat = MCI_FORMAT_MSF;
    if (dwReturn = mciSendCommand(wDeviceID, MCI_SET,
        MCI_SET_TIME_FORMAT,
        (DWORD)(LPVOID) &mciSetParms)) {
        mciSendCommand(wDeviceID, MCI_CLOSE, 0, NULL);
        return (dwReturn);
    }

    // Get the number of tracks;

    // limit to number that can be displayed (20).
    mciStatusParms.dwItem = MCI_STATUS_NUMBER_OF_TRACKS;
    if (dwReturn = mciSendCommand(wDeviceID, MCI_STATUS,
        MCI_STATUS_ITEM, (DWORD)(LPVOID) &mciStatusParms)) {
        mciSendCommand(wDeviceID, MCI_CLOSE, 0, NULL);
        return (dwReturn);
    }
    iNumTracks = mciStatusParms.dwReturn;
    iNumTracks = min(iNumTracks, 20);

    // Allocate memory to hold starting positions.
    pMem = (DWORD *)LocalAlloc(LPTR,
        iNumTracks * sizeof(DWORD));
    if (pMem == NULL) {
        mciSendCommand(wDeviceID, MCI_CLOSE, 0, NULL);
        return (-1);
    }

// For each track, get and save the starting location and
// build a string containing starting locations.
    for(i=1; i<=iNumTracks; i++) {
        mciStatusParms.dwItem = MCI_STATUS_POSITION;
        mciStatusParms.dwTrack = i;
        if (dwReturn = mciSendCommand(wDeviceID,

            MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK,
            (DWORD)(LPVOID) &mciStatusParms)) {
            mciSendCommand(wDeviceID, MCI_CLOSE, 0, NULL);
            return (dwReturn);
        }

        pMem[i-1] = mciStatusParms.dwReturn;

        wsprintf(szTempString,
            "Track %2d - %02d:%02d:%02d\n", i,
            MCI_MSF_MINUTE(pMem[i-1]),
            MCI_MSF_SECOND(pMem[i-1]),
            MCI_MSF_FRAME(pMem[i-1]));

        lstrcat(szTimeString, szTempString);
    }

    // Use MessageBox to display starting times.
    MessageBox(hMainWnd, szTimeString,
        "Track Starting Position", MB_ICONINFORMATION);

    // Free memory and close the device.
    LocalFree((HANDLE) pMem);
    if (dwReturn = mciSendCommand(wDeviceID,
        MCI_CLOSE, 0, NULL)) {
        return (dwReturn);
    }

    return (0L);
}


Recording with a Waveform-Audio Device

The following example opens a waveform-audio device with a new file, records for the specified time, plays the recording, and prompts the user to save the recording if desired:

// Uses the MCI_OPEN, MCI_RECORD, and MCI_SAVE commands to record and
// save a waveform-audio file. Returns 0L if successful; otherwise,
// it returns an MCI error code.
DWORD recordWAVEFile(DWORD dwMilliSeconds)
{
    UINT wDeviceID;
    DWORD dwReturn;
    MCI_OPEN_PARMS mciOpenParms;
    MCI_RECORD_PARMS mciRecordParms;
    MCI_SAVE_PARMS mciSaveParms;
    MCI_PLAY_PARMS mciPlayParms;

    // Open a waveform-audio device with a new file for recording.
    mciOpenParms.lpstrDeviceType = "waveaudio";
    mciOpenParms.lpstrElementName = "";
    if (dwReturn = mciSendCommand(0, MCI_OPEN,
        MCI_OPEN_ELEMENT | MCI_OPEN_TYPE,
        (DWORD)(LPVOID) &mciOpenParms))
    {
        // Failed to open device; don't close it, just return error.
        return (dwReturn);
    }

    // The device opened successfully; get the device ID.
    wDeviceID = mciOpenParms.wDeviceID;

    // Begin recording and record for the specified number of
    // milliseconds. Wait for recording to complete before continuing.
    // Assume the default time format for the waveform-audio device
    // (milliseconds).
    mciRecordParms.dwTo = dwMilliSeconds;
    if (dwReturn = mciSendCommand(wDeviceID, MCI_RECORD,
        MCI_TO | MCI_WAIT, (DWORD)(LPVOID) &mciRecordParms))
    {
        mciSendCommand(wDeviceID, MCI_CLOSE, 0, NULL);
        return (dwReturn);
    }

    // Play the recording and query user to save the file.
    mciPlayParms.dwFrom = 0L;
    if (dwReturn = mciSendCommand(wDeviceID, MCI_PLAY,
        MCI_FROM | MCI_WAIT, (DWORD)(LPVOID) &mciPlayParms))
    {
        mciSendCommand(wDeviceID, MCI_CLOSE, 0, NULL);
        return (dwReturn);
    }
    if (MessageBox(hMainWnd, "Do you want to save this recording?",
        "", MB_YESNO) == IDNO)
    {
        mciSendCommand(wDeviceID, MCI_CLOSE, 0, NULL);
        return (0L);
    }

    // Save the recording to a file named TEMPFILE.WAV. Wait for
    // the operation to complete before continuing.
    mciSaveParms.lpfilename = "tempfile.wav";
    if (dwReturn = mciSendCommand(wDeviceID, MCI_SAVE,
        MCI_SAVE_FILE | MCI_WAIT, (DWORD)(LPVOID) &mciSaveParms))
    {
        mciSendCommand(wDeviceID, MCI_CLOSE, 0, NULL);
        return (dwReturn);
    }

    return (0L);
}


MCI Command Reference

This section describes MCI command messages and structures. These elements are grouped as follows.

Configuring a Device

MCI_BREAK
MCI_BREAK_PARMS
MCI_CONFIGURE
MCI_DGV_SET_PARMS
MCI_DGV_SETAUDIO_PARMS
MCI_DGV_SETVIDEO_PARMS
MCI_ESCAPE
MCI_INDEX
MCI_SEQ_SET_PARMS
MCI_SET
MCI_SET_PARMS
MCI_SETAUDIO
MCI_SETTIMECODE
MCI_SETTUNER
MCI_SETVIDEO
MCI_SPIN
MCI_VCR_SET_PARMS
MCI_VCR_SETAUDIO_PARMS
MCI_VCR_SETTUNER_PARMS
MCI_VCR_SETVIDEO_PARMS
MCI_VD_ESCAPE_PARMS
MCI_WAVE_SET_PARMS

Controlling Playback

MCI_ANIM_PLAY_PARMS
MCI_DGV_FREEZE_PARMS
MCI_DGV_LOAD_PARMS
MCI_DGV_PAUSE_PARMS
MCI_DGV_PLAY_PARMS
MCI_DGV_RESUME_PARMS
MCI_DGV_STOP_PARMS
MCI_FREEZE
MCI_LOAD
MCI_LOAD_PARMS
MCI_OVLY_LOAD_PARMS
MCI_PAUSE
MCI_PLAY
MCI_PLAY_PARMS
MCI_RESUME
MCI_STOP
MCI_UNFREEZE
MCI_VCR_PLAY_PARMS
MCI_VD_PLAY_PARMS

Controlling the Position

MCI_ANIM_STEP_PARMS
MCI_CUE
MCI_DGV_CUE_PARMS
MCI_DGV_SIGNAL_PARMS
MCI_DGV_STEP_PARMS
MCI_MARK
MCI_SEEK
MCI_SEEK_PARMS
MCI_SIGNAL
MCI_STEP
MCI_VCR_CUE_PARMS
MCI_VCR_SEEK_PARMS
MCI_VCR_STEP_PARMS
MCI_VD_STEP_PARMS

Editing

MCI_COPY
MCI_CUT
MCI_DELETE
MCI_DGV_COPY_PARMS
MCI_DGV_CUT_PARMS
MCI_DGV_DELETE_PARMS
MCI_DGV_PASTE_PARMS
MCI_PASTE
MCI_UNDO
MCI_WAVE_DELETE_PARMS

Miscellaneous

MCI_GENERIC_PARMS

Opening and Closing

MCI_ANIM_OPEN_PARMS
MCI_CLOSE
MCI_DGV_OPEN_PARMS
MCI_OPEN
MCI_OPEN_PARMS
MCI_OVLY_OPEN_PARMS
MCI_WAVE_OPEN_PARMS

Realizing a Palette

MCI_REALIZE

Repainting a Frame

MCI_ANIM_UPDATE_PARMS
MCI_DGV_UPDATE_PARMS
MCI_UPDATE

Retrieving Information

MCI_DGV_INFO_PARMS
MCI_DGV_LIST_PARMS
MCI_DGV_STATUS_PARMS
MCI_GETDEVCAPS
MCI_GETDEVCAPS_PARMS
MCI_INFO
MCI_INFO_PARMS
MCI_LIST
MCI_STATUS
MCI_STATUS_PARMS
MCI_SYSINFO
MCI_SYSINFO_PARMS
MCI_VCR_LIST_PARMS
MCI_VCR_STATUS_PARMS

Saving

MCI_DGV_RECORD_PARMS
MCI_DGV_SAVE_PARMS
MCI_OVLY_SAVE_PARMS
MCI_RECORD
MCI_RECORD_PARMS
MCI_SAVE
MCI_SAVE_PARMS
MCI_VCR_RECORD_PARMS

Video Control

MCI_CAPTURE
MCI_DGV_MONITOR_PARMS
MCI_DGV_QUALITY_PARMS
MCI_DGV_RESERVE_PARMS
MCI_DGV_RESTORE_PARMS
MCI_MONITOR
MCI_QUALITY
MCI_RESERVE
MCI_RESTORE

Window or Display Rectangles

MCI_ANIM_RECT_PARMS
MCI_ANIM_WINDOW_PARMS
MCI_DGV_PUT_PARMS
MCI_DGV_RECT_PARMS
MCI_DGV_WINDOW_PARMS
MCI_OVLY_RECT_PARMS
MCI_OVLY_WINDOW_PARMS
MCI_PUT
MCI_WHERE
MCI_WINDOW


MCI_BREAK

MCIERROR mciSendCommand(MCIDEVICEID wDeviceID, MCI_BREAK,
    DWORD dwFlags, (DWORD) (LPMCI_BREAK_PARMS) lpBreak);

Sets a break key for an MCI device. MCI supports this command directly rather than passing it to the device. Any MCI application can use this command.

•	Returns zero if successful or an error otherwise.

dwFlags

MCI_NOTIFY, MCI_WAIT, or, for digital-video and video-cassette recorder (VCR) devices, MCI_TEST. For information about these flags, see Chapter 3, "MCI Overview."

lpBreak

Address of an MCI_BREAK_PARMS structure.

You might have to press the break key multiple times to interrupt a wait operation. Pressing the break key after a device wait is canceled can send the break to an application. If an application has an action defined for the virtual-key code, then it can inadvertently respond to the break. For example, an application using VK_CANCEL for an accelerator key can respond to the default CTRL+BREAK key if it is pressed after a wait is canceled.

Additional Flags

The following additional flags apply to all devices:

MCI_BREAK_HWND

The hwndBreak member of the structure identified by lpBreak contains a window handle that must be the current window in order to enable break detection for that MCI device. This is usually the application's main window. If omitted, MCI does not check the window handle of the current window.

MCI_BREAK_KEY

The nVirtKey member of the structure identified by lpBreak specifies the virtual-key code used for the break key. By default, MCI assigns CTRL+BREAK as the break key. This flag is required if MCI_BREAK_OFF is not specified.

MCI_BREAK_OFF

Disables any existing break key for the indicated device.


MCI_CAPTURE

MCIERROR mciSendCommand(MCIDEVICEID wDeviceID, MCI_CAPTURE,
    DWORD dwFlags, (DWORD) (LPMCI_DGV_CAPTURE_PARMS) lpCapture);

Captures the contents of the frame buffer and stores it in a specified file. Digital-video devices recognize this command.

•	Returns zero if successful or an error otherwise.

dwFlags

MCI_NOTIFY, MCI_WAIT, or MCI_TEST. For information about these flags, see Chapter 3, "MCI Overview."

lpCapture

Address of an MCI_DGV_CAPTURE_PARMS structure.

Additional Flags

The following additional flags apply to digital-video devices:

MCI_DGV_CAPTURE_AS

The lpstrFileName member of the structure identified by lpCapture contains an address of a buffer specifying the destination path and filename. (This flag is required.)

MCI_DGV_CAPTURE_AT

The rc member of the structure identified by lpCapture contains a valid rectangle. The rectangle specifies the rectangular region within the frame buffer that is cropped and saved to disk. If omitted, the cropped region defaults to the rectangle specified or defaulted on a previous MCI_PUT command that specifies the source area for this instance of the device driver.


MCI_CLOSE

MCIERROR mciSendCommand(MCIDEVICEID wDeviceID, MCI_CLOSE,
    DWORD dwFlags, (DWORD) (LPMCI_GENERIC_PARMS) lpClose);

Releases access to a device or file. All devices recognize this command.

•	Returns zero if successful or an error otherwise.

dwFlags

MCI_NOTIFY or MCI_WAIT. For information about these flags, see Chapter 3, "MCI Overview."

lpClose

Address of an MCI_GENERIC_PARMS structure. (You can also use an MCI_CLOSE_PARMS structure, which is identical to MCI_GENERIC_PARMS. Devices with extended command sets might replace this structure with a device-specific structure.)

Exiting an application without closing any MCI devices it has opened can leave the device inaccessible. Your application should explicitly close each device or file when it is finished with it. MCI unloads the device when all instances of the device or all associated files are closed.


MCI_CONFIGURE

MCIERROR mciSendCommand(MCIDEVICEID wDeviceID, MCI_CONFIGURE,
    DWORD dwFlags, (DWORD) (LPMCI_GENERIC_PARMS) lpConfigure);

Displays a dialog box for setting the operating options. Digital-video devices recognize this command.

•	Returns zero if successful or an error otherwise.

dwFlags

MCI_NOTIFY, MCI_WAIT, or MCI_TEST. For information about these flags, see Chapter 3, "MCI Overview."

lpConfigure

Address of an MCI_GENERIC_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)


MCI_COPY

MCIERROR mciSendCommand(MCIDEVICEID wDeviceID, MCI_COPY,
    DWORD dwFlags, (DWORD) (LPMCI_DGV_COPY_PARMS) lpCopy);

Copies data to the clipboard. Digital-video devices recognize this command.

dwFlags

MCI_NOTIFY, MCI_WAIT, or MCI_TEST. For information about these flags, see Chapter 3, "MCI Overview."

lpCopy

Address of an MCI_DGV_COPY_PARMS structure.

Additional Flags

The following additional flags apply to digital-video devices:

MCI_DGV_COPY_AT

A rectangle is included in the rc member of the structure identified by lpCopy. The rectangle specifies the portion of each frame to copy. If the flag is omitted, MCI_COPY copies the entire frame.

MCI_DGV_COPY_AUDIO_STREAM

An audio-stream number is included in the dwAudioStream member of the structure identified by lpCopy. If you use this flag and also want to copy video, you must also use the MCI_DGV_COPY_VIDEO_STREAM flag. (If neither flag is specified, data from all audio and video streams is copied.)

MCI_DGV_COPY_VIDEO_STREAM

A video-stream number is included in the dwVideoStream member of the structure identified by lpCopy. If you use this flag and also want to copy audio, you must also use the MCI_DGV_COPY_AUDIO_STREAM flag. (If neither flag is specified, data from all audio and video streams is copied.)

MCI_FROM

A starting location is included in the dwFrom member of the structure identified by lpCopy. The units assigned to the position values are specified with the MCI_SET_TIME_FORMAT flag of the MCI_SET command.

MCI_TO

An ending location is included in the dwTo member of the structure identified by lpCopy. The units assigned to the position values are specified with the MCI_SET_TIME_FORMAT flag of the MCI_SET command.


MCI_CUE

MCIERROR mciSendCommand(MCIDEVICEID wDeviceID, MCI_CUE,
    DWORD dwFlags, (DWORD) (LPMCI_GENERIC_PARMS) lpCue);

Cues a device so that playback or recording begins with minimum delay.Digital-video, VCR, and waveform-audio devices recognize this command.

•	Returns zero if successful or an error otherwise.

dwFlags

MCI_NOTIFY, MCI_WAIT, or, for digital-video and VCR devices, MCI_TEST. For information about these flags, see Chapter 3, "MCI Overview."

lpCue

Address of an MCI_GENERIC_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

Digital-Video Flags

The following additional flags are used with the digitalvideo device type:

MCI_DGV_CUE_INPUT

A digital-video instance should prepare for recording. If the application has not reserved disk space, the device reserves the disk space using its default parameters. The application can omit this flag if the current presentation source is already the external input. (This flag has no effect on selecting the presentation source.)

MCI_DGV_CUE_NOSHOW

A digital-video instance should prepare for playing the frame specified with the command without displaying it. When this flag is specified, the display continues to show the image in the frame buffer even though its corresponding frame is not the current position. For example, if the frame buffer contains the image from frame 7, the device continues to show frame 7 when this flag is used to cue the device to any other position. A subsequent cue command without this flag and without the MCI_TO flag displays the current frame.

MCI_DGV_CUE_OUTPUT

A digital-video instance should prepare for playing. If the workspace is paused, no positioning occurs. If the workspace is stopped, the position might change to a previous key-frame image. The application can omit this flag if the current presentation source is already the workspace.

MCI_TO

A workspace position is included in the dwTo member of the structure identified by lpCue. The units assigned to position values are specified using the MCI_SET_TIME_FORMAT flag of the MCI_SET command. This is equivalent to seeking to a position, except the device is paused after the command.

For digitalvideo devices, the lpCue parameter points to an MCI_DGV_CUE_PARMS structure.

VCR Flags

The following additional flags are used with the vcr device type:

MCI_FROM

The dwFrom member of the structure pointed to by lpCue contains the starting location specified in the current time format.

MCI_TO

The dwTo member of the structure pointed to by lpCue contains the ending (pausing) location specified in the current time format.

MCI_VCR_CUE_INPUT

Prepare for recording.

MCI_VCR_CUE_OUTPUT

Prepare for playing. If neither MCI_VCR_CUE_INPUT nor MCI_VCR_CUE_OUTPUT is specified, MCI_VCR_CUE_OUTPUT is assumed.

MCI_VCR_CUE_PREROLL

Cue the device to the current position, or the dwFrom position, minus the preroll duration. This will allow the device to prepare itself before entering record or playback mode.

MCI_VCR_CUE_REVERSE

The direction of the next play or record command is reverse.

When cueing for playback by using the MCI_CUE command with the MCI_VCR_CUE_OUTPUT flag, you can cancel MCI_CUE by issuing the MCI_PLAY command with MCI_FROM, MCI_TO, or MCI_VCR_PLAY_REVERSE.

When cueing for recording by using MCI_CUE with the MCI_VCR_CUE_INPUT flag, you can cancel MCI_CUE by issuing the MCI_RECORD command with MCI_FROM, MCI_TO, or MCI_VCR_RECORD_INITIALIZE.

For vcr devices, the lpCue parameter points to an MCI_VCR_CUE_PARMS structure.

Waveform-Audio Flags

The following additional flags are used with the waveaudio device type:

MCI_WAVE_INPUT

A waveform-audio input device should be cued.

MCI_WAVE_OUTPUT

A waveform-audio output device should be cued. This is the default flag if a flag is not specified.


MCI_CUT

MCIERROR mciSendCommand(MCIDEVICEID wDeviceID, MCI_CUT,
    DWORD dwFlags, (DWORD) (LPMCI_DGV_CUT_PARMS) lpCut);

Removes data from the file and copies it to the clipboard. Digital-video devices recognize this command.

•	Returns zero if successful or an error otherwise.

dwFlags

MCI_NOTIFY, MCI_WAIT, or MCI_TEST. For information about these flags, see Chapter 3, "MCI Overview."

lpCut

Address of an MCI_DGV_CUT_PARMS structure.

Additional Flags

The following additional flags apply to digital-video devices:

MCI_DGV_CUT_AT

A rectangle is included in the rc member of the structure identified by lpCut. The rectangle specifies the portion of each frame to cut. If the flag is omitted, MCI_CUT cuts the entire frame.

MCI_DGV_CUT_AUDIO_STREAM

An audio-stream number is included in the dwAudioStream member of the structure identified by lpCut. If you use this flag and also want to cut video, you must also use the MCI_DGV_CUT_VIDEO_STREAM flag. (If neither flag is specified, data from all audio and video streams is cut.)

MCI_DGV_CUT_VIDEO_STREAM

A video-stream number is included in the dwVideoStream member of the structure identified by lpCut. If you use this flag and also want to cut audio, you must also use the MCI_DGV_CUT_AUDIO_STREAM flag. (If neither flag is specified, data from all audio and video streams is cut.)

MCI_FROM

A starting location is included in the dwFrom member of the structure identified by lpCut. The units assigned to the position values are specified with the MCI_SET_TIME_FORMAT flag of the MCI_SET command.

MCI_TO

An ending location is included in the dwTo member of the structure identified by lpCut. The units assigned to the position values are specified with the MCI_SET_TIME_FORMAT flag of MCI_SET.


MCI_DELETE

MCIERROR mciSendCommand(MCIDEVICEID wDeviceID, MCI_DELETE,
    DWORD dwFlags, (DWORD) (LPMCI_GENERIC_PARMS) lpDelete);

Removes data from the file. Digital-video and waveform-audio devices recognize this command.

dwFlags

MCI_NOTIFY, MCI_WAIT, or, for digital-video devices, MCI_TEST. For information about these flags, see Chapter 3, "MCI Overview."

lpDelete

Address of an MCI_GENERIC_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

Digital-Video Flags

The following flags apply to the digitalvideo device type:

MCI_DGV_DELETE_AT

A rectangle is included in the rc member of the structure identified by lpDelete. The rectangle specifies the portion of each frame to delete. When this flag is used, the frame is retained in the workspace and the area specified by the rectangle becomes black. If the flag is omitted, MCI_DELETE defaults to the entire frame and removes the frame from the workspace.

MCI_DGV_DELETE_AUDIO_STREAM

An audio-stream number is included in the dwAudioStream member of the structure identified by lpDelete. If you use this flag and also want to delete video, you must also use the MCI_DGV_DELETE_VIDEO_STREAM flag. (If neither flag is specified, data from all audio and video streams is deleted.)

MCI_DGV_DELETE_VIDEO_STREAM

A video-stream number is included in the dwVideoStream member of the structure identified by lpDelete. If you use this flag and also want to delete audio, you must also use the MCI_DGV_DELETE_AUDIO_STREAM flag. (If neither flag is specified, data from all audio and video streams is deleted.)

MCI_FROM

A starting location is included in the dwFrom member of the structure identified by lpDelete. The units assigned to the position values are specified with the MCI_SET_TIME_FORMAT flag of the MCI_SET command.

MCI_TO

An ending location is included in the dwTo member of the structure identified by lpDelete. The units assigned to the position values are specified with the MCI_SET_TIME_FORMAT flag of MCI_SET.

For digital-video devices, the lpDelete parameter points to an MCI_DGV_DELETE_PARMS structure.

Waveform-Audio Flags

The following flags apply to the waveaudio device type:

MCI_FROM

A starting location is included in the dwFrom member of the structure identified by lpDelete. The units assigned to the position values are specified with the MCI_SET_TIME_FORMAT flag of MCI_SET.

MCI_TO

An ending location is included in the dwTo member of the structure identified by lpDelete. The units assigned to the position values are specified with the MCI_SET_TIME_FORMAT flag of MCI_SET.

For waveform-audio devices, the lpDelete parameter points to an MCI_WAVE_DELETE_PARMS structure.


MCI_ESCAPE

MCIERROR mciSendCommand(MCIDEVICEID wDeviceID, MCI_ESCAPE,
    DWORD dwFlags, (DWORD) (LPMCI_VD_ESCAPE_PARMS) lpEscape);

Sends a string directly to the device. Videodisc devices recognize this command.

•	Returns zero if successful or an error otherwise.

dwFlags

MCI_NOTIFY or MCI_WAIT. For information about these flags, see Chapter 3, "MCI Overview."

lpEscape

Address of an MCI_VD_ESCAPE_PARMS structure.

The data sent with MCI_ESCAPE is device-dependent and is usually passed directly to the hardware associated with the device.

Additional Flag

The following additional flag applies to videodisc devices:

MCI_VD_ESCAPE_STRING

A command string is specified in the lpstrCommand member of the structure identified by lpEscape. This flag is required.


MCI_FREEZE

MCIERROR mciSendCommand(MCIDEVICEID wDeviceID, MCI_FREEZE,
    DWORD dwFlags, (DWORD) (LPMCI_GENERIC_PARMS) lpFreeze);

Freezes motion on the display. Digital-video, video-overlay, and VCR devices recognize this command.

•	Returns zero if successful or an error otherwise.

dwFlags

MCI_NOTIFY, MCI_WAIT, or, for digital-video and VCR devices, MCI_TEST. For information about these flags, see Chapter 3, "MCI Overview."

lpFreeze

Address of an MCI_GENERIC_PARMS structure. (Devices with additional parameters might replace this structure with a device-specific structure.)

Digital-Video Flags

The following additional flags are used by the digitalvideo device type:

MCI_DGV_FREEZE_AT

The rc member of the structure identified by lpFreeze contains a valid rectangle. The rectangle specifies a region within the frame buffer that will have the lock mask bit for each pixel turned on. The specified pixels will not be updated until their lock mask bit is turned off. If this flag is not specified, the rectangle defaults to the entire frame buffer. This flag is supported only if the MCI_GETDEVCAPS command returns TRUE for the MCI_DGV_GETDEVCAPS_CAN_LOCK flag.

MCI_DGV_FREEZE_OUTSIDE

The area outside the region specified for the MCI_DGV_FREEZE_AT flag is frozen.

For digital-video devices, the lpFreeze parameter points to an MCI_DGV_FREEZE_PARMS structure.

VCR Flags

The following additional flags are used by the vcr device type:

MCI_VCR_FREEZE_FIELD

Freeze only one member of the current frame.

MCI_VCR_FREEZE_FRAME

Freeze both fields of the current frame.

MCI_VCR_FREEZE_INPUT

Freeze the current frame on the screen (used for recording).

MCI_VCR_FREEZE_OUTPUT

Freeze the current frame from the VCR (used with frame capture).

For VCR devices, the lpFreeze parameter points to an MCI_GENERIC_PARMS structure.

Video-Overlay Flags

The following additional flag is used by the overlay device type:

MCI_OVLY_RECT

The rc member of the structure identified by lpFreeze contains a valid rectangle. If this flag is not specified, the device driver will freeze the entire frame.

For video-overlay devices, the lpFreeze parameter points to an MCI_OVLY_RECT_PARMS structure.


MCI_GETDEVCAPS

MCIERROR mciSendCommand(MCIDEVICEID wDeviceID, MCI_GETDEVCAPS,
    DWORD dwFlags, (DWORD) (LPMCI_GETDEVCAPS_PARMS) lpCapsParms);

Retrieves static information about a device. All devices recognize this command. The parameters and flags available for this command depend on the selected device. Information is returned in the dwReturn member of the structure identified by lpCapsParms.

•	Returns zero if successful or an error otherwise.

dwFlags

MCI_NOTIFY, MCI_WAIT, or, for digital-video and VCR devices, MCI_TEST. For information about these flags, see Chapter 3, "MCI Overview."

lpCapsParms

Address of an MCI_GETDEVCAPS_PARMS structure.

Additional Flags

The following additional standard and command-specific flags apply to all devices supporting MCI_GETDEVCAPS:

MCI_GETDEVCAPS_COMPOUND_DEVICE

The dwReturn member is set to TRUE if the device uses data storage that must be explicitly opened and closed; it is set to FALSE otherwise.

MCI_GETDEVCAPS_DEVICE_TYPE

The dwReturn member is set to one of the values listed in "Constants: Device Types" later in this chapter.

MCI_GETDEVCAPS_HAS_AUDIO

The dwReturn member is set to TRUE if the device has audio output; it is set to FALSE otherwise.

MCI_GETDEVCAPS_HAS_VIDEO

The dwReturn member is set to TRUE if the device has video output; it is set to FALSE otherwise. For example, the member is set to TRUE for devices that support the animation or videodisc command set.

MCI_GETDEVCAPS_ITEM

Specifies that the dwItem member of the MCI_GETDEVCAPS_PARMS structure contains one of the following constants:

MCI_GETDEVCAPS_CAN_EJECT

The dwReturn member is set to TRUE if the device can eject the media; otherwise, it is set to FALSE.

MCI_GETDEVCAPS_CAN_PLAY

The dwReturn member is set to TRUE if the device can play the media; otherwise, it is set to FALSE. If a device specifies TRUE, it implies the device supports the MCI_PAUSE and MCI_STOP commands as well as the MCI_PLAY command.

MCI_GETDEVCAPS_CAN_RECORD

The dwReturn member is set to TRUE if the device supports recording; otherwise, it is set to FALSE. If a device specifies TRUE, it implies the device supports the MCI_PAUSE and MCI_STOP commands as well as the MCI_RECORD command.

MCI_GETDEVCAPS_CAN_SAVE

The dwReturn member is set to TRUE if the device can save a file; otherwise, it is set to FALSE.

MCI_GETDEVCAPS_USES_FILES

The dwReturn member is set to TRUE if the device requires a filename; it is set to FALSE otherwise. Only compound devices use files.

Animation Flags

The following flags can be specified in the dwItem member of MCI_GETDEVCAPS_PARMS for the animation device type:

MCI_ANIM_GETDEVCAPS_CAN_REVERSE

The dwReturn member is set to TRUE if the device can play in reverse; otherwise, it is set to FALSE.

MCI_ANIM_GETDEVCAPS_CAN_STRETCH

The dwReturn member is set to TRUE if the device can stretch the image to fill the frame; otherwise, it is set to FALSE.

MCI_ANIM_GETDEVCAPS_FAST_RATE

The dwReturn member is set to the standard fast play rate in frames per second.

MCI_ANIM_GETDEVCAPS_MAX_WINDOWS

The dwReturn member is set to the maximum number of windows that the device can handle simultaneously.

MCI_ANIM_GETDEVCAPS_NORMAL_RATE

The dwReturn member is set to the normal play rate in frames per second.

MCI_ANIM_GETDEVCAPS_PALETTES

The dwReturn member is set to TRUE if the device can return a palette handle; otherwise, it is set to FALSE.

MCI_ANIM_GETDEVCAPS_SLOW_RATE

The dwReturn member is set to the standard slow play rate in frames per second.

Digital-Video Flags

The following flags can be specified in the dwItem member of MCI_GETDEVCAPS_PARMS for the digitalvideo device type:

MCI_DGV_GETDEVCAPS_CAN_FREEZE

The dwReturn member is set to TRUE if the device can freeze frames; otherwise, it is set to FALSE.

MCI_DGV_GETDEVCAPS_CAN_LOCK

The dwReturn member is set to TRUE if the device can lock; otherwise, it is set to FALSE.

MCI_DGV_GETDEVCAPS_CAN_REVERSE

The dwReturn member is set to TRUE if the device can play in reverse; otherwise, it is set to FALSE.

MCI_DGV_GETDEVCAPS_CAN_STR_IN

The dwReturn member is set to TRUE if the device can stretch input; otherwise, it is set to FALSE.

MCI_DGV_GETDEVCAPS_CAN_STRETCH

The dwReturn member is set to TRUE if the device can stretch an image; otherwise, it is set to FALSE.

MCI_DGV_GETDEVCAPS_CAN_TEST

The dwReturn member is set to TRUE if the device can perform tests; otherwise, it is set to FALSE.

MCI_DGV_GETDEVCAPS_HAS_STILL

The dwReturn member is set to TRUE if the device can display still images; otherwise, it is set to FALSE.

MCI_DGV_GETDEVCAPS_MAX_WINDOWS

The dwReturn member is set to the maximum number of windows that the device can handle simultaneously.

MCI_DGV_GETDEVCAPS_MAXIMUM_RATE

The dwReturn member is set to the maximum play rate for the device, in frames per second.

MCI_DGV_GETDEVCAPS_MINIMUM_RATE

The dwReturn member is set to the minimum play rate for the device, in frames per second.

MCI_DGV_GETDEVCAPS_PALETTES

The dwReturn member is set to TRUE if the device can return a palette handle; otherwise, it is set to FALSE.

VCR Flags

The following flags can be specified in the dwItem member of MCI_GETDEVCAPS_PARMS for the vcr device type:

MCI_GETDEVCAPS_CLOCK_INCREMENT_RATE

The dwReturn member is set to the number of increments per second.

MCI_VCR_GETDEVCAPS_CAN_DETECT_LENGTH

The dwReturn member is set to TRUE if the device is capable of detecting the length of the media; otherwise, it is set to FALSE.

MCI_VCR_GETDEVCAPS_CAN_FREEZE

The dwReturn member is set to TRUE if the device is capable of freezing the output image; otherwise, it is set to FALSE.

MCI_VCR_GETDEVCAPS_CAN_MONITOR_SOURCES

The dwReturn member is set to TRUE if the device is capable of monitoring sources; otherwise, it is set to FALSE.

MCI_VCR_GETDEVCAPS_CAN_PREROLL

The dwReturn member is set to TRUE if the device is capable of preroll; otherwise, it is set to FALSE.

MCI_VCR_GETDEVCAPS_CAN_PREVIEW

The dwReturn member is set to TRUE if the device is capable of previews; otherwise, it is set to FALSE.

MCI_VCR_GETDEVCAPS_CAN_REVERSE

The dwReturn member is set to TRUE if the device is capable of playing in reverse; otherwise, it is set to FALSE.

MCI_VCR_GETDEVCAPS_CAN_TEST

The dwReturn member is set to TRUE if the device is capable of testing; otherwise, it is set to FALSE.

MCI_VCR_GETDEVCAPS_HAS_CLOCK

The dwReturn member is set to TRUE if the device supports an external clock; otherwise, it is set to FALSE.

MCI_VCR_GETDEVCAPS_HAS_TIMECODE

The dwReturn member is set to TRUE if device has timecode capability or if this capability is unknown; otherwise, it is set to FALSE.

MCI_VCR_GETDEVCAPS_NUMBER_OF_MARKS

The dwReturn member is set to the number of marks (99).

MCI_VCR_GETDEVCAPS_SEEK_ACCURACY

The dwReturn member is set to the seek accuracy of the device.

Video-Overlay Flags

The following flags can be specified in the dwItem member of MCI_GETDEVCAPS_PARMS for the overlay device type:

MCI_OVLY_GETDEVCAPS_CAN_FREEZE

The dwReturn member is set to TRUE if the device can freeze the image; otherwise, it is set to FALSE.

MCI_OVLY_GETDEVCAPS_CAN_STRETCH

The dwReturn member is set to TRUE if the device can stretch the image to fill the frame; otherwise, it is set to FALSE.

MCI_OVLY_GETDEVCAPS_MAX_WINDOWS

The dwReturn member is set to the maximum number of windows that the device can handle simultaneously.

Videodisc Flags

The following flags can be specified in the dwItem member of MCI_GETDEVCAPS_PARMS for the videodisc device type:

MCI_VD_GETDEVCAPS_CAN_REVERSE

The dwReturn member is set to TRUE if the videodisc player can play in reverse; otherwise, it is set to FALSE. Some players can play CLV discs in reverse as well as CAV discs.

MCI_VD_GETDEVCAPS_CAV

When combined with other items, specifies that the return information applies to CAV format videodiscs. This is the default if no videodisc is inserted.

MCI_VD_GETDEVCAPS_CLV

When combined with other items, specifies that the return information applies to CLV format videodiscs.

MCI_VD_GETDEVCAPS_FAST_RATE

The dwReturn member is set to the standard fast play rate in frames per second.

MCI_VD_GETDEVCAPS_NORMAL_RATE

The dwReturn member is set to the normal play rate in frames per second.

MCI_VD_GETDEVCAPS_SLOW_RATE

The dwReturn member is set to the standard slow play rate in frames per second.

Waveform-Audio Flags

The following flags can be specified in the dwItem member of MCI_GETDEVCAPS_PARMS for the waveaudio device type:

MCI_WAVE_GETDEVCAPS_INPUT

The dwReturn member is set to the total number of waveform input (recording) devices.

MCI_WAVE_GETDEVCAPS_OUTPUT

The dwReturn member is set to the total number of waveform output (playback) devices.


MCI_INDEX

MCIERROR mciSendCommand(MCIDEVICEID wDeviceID, MCI_INDEX,
    DWORD dwFlags, (DWORD) (LPMCI_GENERIC_PARMS) lpIndex);

Turns the on-screen display on or off. VCR devices recognize this command.

•	Returns zero if successful or an error otherwise.

dwFlags

MCI_NOTIFY, MCI_WAIT, or MCI_TEST. For information about these flags, see Chapter 3, "MCI Overview."

lpIndex

Address of an MCI_GENERIC_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

The information presented in the on-screen display is controlled by the MCI_VCR_SET_INDEX flag in the MCI_SET command.

Additional Flags

The following additional flags apply to VCR devices:

MCI_SET_OFF

Turns on-screen display off.

MCI_SET_ON

Turns on-screen display on.


MCI_INFO

MCIERROR mciSendCommand(MCIDEVICEID wDeviceID, MCI_INFO,
    DWORD dwFlags, (DWORD) (LPMCI_INFO_PARMS) lpInfo);

Retrieves string information from a device. All devices recognize this command. Information is returned in the lpstrReturn member of the structure identified by lpInfo. The dwRetSize member specifies the buffer length for the returned data.

•	Returns zero if successful or an error otherwise.

dwFlags

MCI_NOTIFY, MCI_WAIT, or, for digital-video and VCR devices, MCI_TEST. For information about these flags, see Chapter 3, "MCI Overview."

lpInfo

Address of an MCI_INFO_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

Additional Flag

The following additional standard and command-specific flag applies to all devices supporting MCI_INFO:

MCI_INFO_PRODUCT

Obtains a description of the hardware associated with a device. Devices should supply a description that identifies both the driver and the hardware used.

Animation Flags

The following additional flags apply to the animation device type:

MCI_ANIM_INFO_TEXT

Obtains the window caption.

MCI_INFO_FILE

Obtains the filename of the current file. This flag is supported only by devices that return TRUE when you call the MCI_GETDEVCAPS command with the MCI_GETDEVCAPS_USES_FILES flag.

CD Audio Flags

The following additional flags apply to the cdaudio device type:

MCI_INFO_MEDIA_IDENTITY

Produces a unique identifier for the audio CD currently loaded in the player being queried. This flag returns a string of 16 hexadecimal digits.

MCI_INFO_MEDIA_UPC

Produces the Universal Product Code (UPC) that is encoded on an audio CD. The UPC is a string of digits. It might not be available for all CDs.

Digital-Video Flags

The following additional flags apply to the digitalvideo device type:

MCI_DGV_INFO_ITEM

A constant indicating the information desired is included in the dwItem member of the structure identified by lpInfo. The following constants are defined for digital-video devices:

MCI_DGV_INFO_AUDIO_ALG

Returns the name for the current audio compression algorithm.

MCI_DGV_INFO_AUDIO_QUALITY

Returns the name for the current audio quality descriptor.

MCI_DGV_INFO_STILL_ALG

Returns the name for the current still image compression algorithm.

MCI_DGV_INFO_STILL_QUALITY

Returns the name for the current still image quality descriptor.

MCI_DGV_INFO_USAGE

Returns a string describing usage restrictions that might be imposed by the owner of the visual or audible data in the workspace.

MCI_DGV_INFO_VIDEO_ALG

Returns the name for the current video compression algorithm.

MCI_DGV_INFO_VIDEO_QUALITY

Returns the name for the current video quality descriptor.

MCI_INFO_VERSION

Returns the release level of the device driver and hardware. Device driver developers must document the syntax of the returned string.

MCI_DGV_INFO_TEXT

Obtains the window caption.

MCI_INFO_FILE

Obtains the path and filename of the last file specified with the MCI_OPEN or MCI_LOAD command. If a file has not been specified, the device returns a null-terminated string. This flag is supported only by devices that return TRUE to the MCI_GETDEVCAPS_USES_FILES flag of the MCI_GETDEVCAPS command.

For digital-video devices, lpInfo points to an MCI_DGV_INFO_PARMS structure.

Sequencer Flags

The following additional flags apply to the sequencer device type:

MCI_INFO_COPYRIGHT

Obtains the MIDI file copyright notice from the copyright meta event.

MCI_INFO_FILE

Obtains the filename of the current file. This flag is supported only by devices that return TRUE when you call the MCI_GETDEVCAPS command with the MCI_GETDEVCAPS_USES_FILES flag.

MCI_INFO_NAME

Obtains the sequence name from the sequence/track name meta event.

VCR Flags

The following additional flag applies to the vcr device type:

MCI_VCR_INFO_VERSION

Sets lpstrReturn member of the MCI_INFO_PARMS structure to point to the version number. Also sets the dwRetSize member equal to the length of the string pointed to.

Video-Overlay Flags

The following additional flags apply to the overlay device type:

MCI_INFO_FILE

Obtains the filename of the current file. This flag is supported only by devices that return TRUE to the MCI_GETDEVCAPS_USES_FILES flag of the MCI_GETDEVCAPS command.

MCI_OVLY_INFO_TEXT

Obtains the caption of the window associated with the video-overlay device.

Waveform-Audio Flags

The following additional flags apply to the waveaudio device type:

MCI_INFO_FILE

Obtains the filename of the current file. This flag is supported by devices that return TRUE when you call the MCI_GETDEVCAPS command with the MCI_GETDEVCAPS_USES_FILES flag.

MCI_WAVE_INPUT

Obtains the product name of the current input.

MCI_WAVE_OUTPUT

Obtains the product name of the current output and its value is device specific.


MCI_LIST

MCIERROR mciSendCommand(MCIDEVICEID wDeviceID, MCI_LIST,
    DWORD dwFlags, (DWORD) (LPMCI_GENERIC_PARMS) lpList);

Obtains information about the number and types of inputs available to the device. Digital-video and VCR devices recognize this command.

•	Returns zero if successful or an error otherwise.

dwFlags

MCI_NOTIFY, MCI_WAIT, or MCI_TEST. For information about these flags, see Chapter 3, "MCI Overview."

lpList

Address of an MCI_GENERIC_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

Digital-Video Flags

The following additional flags apply to the digitalvideo device type:

MCI_DGV_LIST_ALG

The lpstrAlgorithm member of the structure identified by lpList contains an address of a buffer containing the name of an algorithm. The name is used to retrieve the types of quality descriptors associated with an algorithm.

MCI_DGV_LIST_COUNT

Returns the number of options of the specified type.

MCI_DGV_LIST_ITEM

A constant indicating the list type is included in the dwItem member of the structure identified by lpList. This flag is required. Use one of the following constants to indicate the list type:

MCI_DGV_LIST_AUDIO_ALG

The command should retrieve names of audio algorithms.

MCI_DGV_LIST_AUDIO_QUALITY

The command should retrieve audio quality levels. The levels returned are associated with the algorithm referenced by the lpstrAlgorithm member of the structure identified by lpList. If that member is specified using the string "current", then the qualities associated with the current algorithm are returned.

MCI_DGV_LIST_AUDIO_STREAM

The command should retrieve names of audio streams.

MCI_DGV_LIST_STILL_AL

The command should retrieve names of still algorithms.

MCI_DGV_LIST_STILL_QUALITY

The command should retrieve quality levels. The levels returned are associated with the algorithm referenced by the lpstrAlgorithm member of the structure identified by lpList. If that member is specified using the string "current", then the qualities associated with the current algorithm are returned.

MCI_DGV_LIST_VIDEO_ALG

The command should retrieve names of video algorithms.

MCI_DGV_LIST_VIDEO_QUALITY

The command should retrieve video quality levels. The levels returned are associated with the algorithm referenced by the lpstrAlgorithm member of the structure identified by lpList. If that member is specified using the string "current", then the qualities associated with the current algorithm are returned.

MCI_DGV_LIST_VIDEO_SOURCE

The command should return information about the video sources. When used with MCI_DGV_LIST_COUNT, the command returns the number of video sources. When used with MCI_DGV_LIST_NUMBER, the command returns the type of a video source. MCI defines the following types:

MCI_DGV_SETVIDEO_SRC_GENERIC

MCI_DGV_SETVIDEO_SRC_NTSC

MCI_DGV_SETVIDEO_SRC_PAL

MCI_DGV_SETVIDEO_SRC_RGB

MCI_DGV_SETVIDEO_SRC_SECAM

MCI_DGV_SETVIDEO_SRC_SVIDEO

There might be more than one source of each type returned. The generic source type is used when more then one type of signal is allowed for that connector.

MCI_DGV_LIST_VIDEO_STREAM

The command should retrieve names of video streams.

MCI_DGV_LIST_NUMBER

An index is specified in the dwNumber member of the structure identified by lpList. The index must be an integer between 1 and the value returned for the MCI_DGV_LIST_COUNT flag.

For digital-video devices, lpList points to an MCI_DGV_LIST_PARMS structure.

VCR Flags

The following additional flags apply to the vcr device type:

MCI_VCR_LIST_AUDIO_SOURCE

List audio inputs or types.

MCI_VCR_LIST_COUNT

Sets the dwReturn member of the structure identified by lpList to the total number of video or audio inputs.

MCI_VCR_LIST_NUMBER

Sets the dwReturn member of the structure identified by lpList to the type of the video or audio input specified by the dwNumber member.

MCI_VCR_LIST_VIDEO_SOURCE

List video inputs or types.

For VCR devices, lpList points to an MCI_VCR_LIST_PARMS structure.


MCI_LOAD

MCIERROR mciSendCommand(MCIDEVICEID wDeviceID, MCI_LOAD,
    DWORD dwFlags, (DWORD) (LPMCI_LOAD_PARMS) lpLoad);

Loads a file. Digital-video and video-overlay devices recognize this command.

•	Returns zero if successful or an error otherwise.

dwFlags

MCI_NOTIFY, MCI_WAIT, or, for digital-video devices, MCI_TEST. For information about these flags, see Chapter 3, "MCI Overview."

lpLoad

Address of an MCI_LOAD_PARMS structure. (Devices with additional parameters might replace this structure with a device-specific structure. For digital-video devices, the lpLoad parameter points to an MCI_DGV_LOAD_PARMS structure.)

Additional Flag

The following additional flag applies to all devices supporting MCI_LOAD:

MCI_LOAD_FILE

The lpfilename member of the structure identified by lpLoad contains an address of a buffer containing the filename.

Video-Overlay Flags

The following additional flag is used with the overlay device type:

MCI_OVLY_RECT

The rc member of the structure identified by lpLoad contains a valid display rectangle that identifies the area of the video buffer to update.

For video-overlay devices, the lpLoad parameter points to an MCI_OVLY_LOAD_PARMS structure.


MCI_MARK

MCIERROR mciSendCommand(MCIDEVICEID wDeviceID, MCI_MARK,
    DWORD dwFlags, (DWORD) (LPMCI_GENERIC_PARMS) lpMark);

Records or erases marks that can be used with the MCI_SEEK command for high-speed searches. VCR devices recognize this command.

•	Returns zero if successful or an error otherwise.

dwFlags

MCI_NOTIFY, MCI_WAIT, or MCI_TEST. For information about these flags, see Chapter 3, "MCI Overview."

lpMark

Address of an MCI_GENERIC_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

Additional Flags

The following additional flags apply to VCR devices:

MCI_VCR_MARK_ERASE

Erases a mark at the current position if one exists.

MCI_VCR_MARK_WRITE

Writes a mark at the current position.


MCI_MONITOR

MCIERROR mciSendCommand(MCIDEVICEID wDeviceID, MCI_MONITOR,
    DWORD dwFlags, (DWORD) (LPMCI_DGV_MONITOR_PARMS) lpMonitor);

Specifies the presentation source. Digital-video devices recognize this command.

•	Returns zero if successful or an error otherwise.

dwFlags

MCI_NOTIFY, MCI_WAIT, or MCI_TEST. For information about these flags, see Chapter 3, "MCI Overview."

lpMonitor

Address of an MCI_DGV_MONITOR_PARMS structure.

Additional Flags

The following additional flags apply to digital-video devices:

MCI_DGV_MONITOR_METHOD

A constant indicating the method of monitoring is included in the dwMethod member of the structure identified by lpMonitor.

When the MCI_DGV_MONITOR_INPUT flag is used in the dwSource member, this selects the method of monitoring. Typically, different monitoring methods have different implications on how the hardware is used. The default monitoring method is selected by the device.

MCI_DGV_MONITOR_SOURCE

A constant indicating the monitor source is included in the dwSource member of the structure identified by lpMonitor.


MCI_OPEN

MCIERROR mciSendCommand(MCIDEVICEID wDeviceID, MCI_OPEN,
    DWORD dwFlags, (DWORD) (LPMCI_OPEN_PARMS) lpOpen);

Initializes a device or file. All devices recognize this command.

•	Returns zero if successful or an error otherwise.

dwFlags

MCI_NOTIFY or MCI_WAIT. For information about these flags, see Chapter 3, "MCI Overview."

lpOpen

Address of an MCI_OPEN_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

The MCI_OPEN_TYPE flag must be used whenever a device is specified in the mciSendCommand function. If you open a device by specifying a device-type constant, you must specify the MCI_OPEN_TYPE_ID flag in addition to MCI_OPEN_TYPE. For a list of device-type constants, see "Constants: Device Types" later in this chapter.

If the MCI_OPEN_SHAREABLE flag is not specified when a device or file is initially opened, all subsequent MCI_OPEN commands to the device or file will fail. If the device or file is already open and this flag is not specified, the call will fail even if the first open command specified MCI_OPEN_SHAREABLE. Files opened for the MCISEQ.DRV and MCIWAVE.DRV devices are nonshareable.

Case is ignored in the device name, but there cannot be leading or trailing blanks.

To use automatic type selection (via the entries in the registry), assign the filename and file extension to the lpstrElementName member of the structure identified by lpOpen, set the lpstrDeviceType member to NULL, and set the MCI_OPEN_ELEMENT flag.

Additional Flags

The following additional flags apply to all devices supporting MCI_OPEN:

MCI_OPEN_ALIAS

An alias is included in the lpstrAlias member of the structure identified by lpOpen.

MCI_OPEN_SHAREABLE

The device or file should be opened as shareable.

MCI_OPEN_TYPE

A device type name or constant is included in the lpstrDeviceType member of the structure identified by lpOpen.

MCI_OPEN_TYPE_ID

The low-order word of the lpstrDeviceType member of the structure identified by lpOpen contains a standard MCI device type identifier and the high-order word optionally contains the ordinal index for the device. Use this flag with the MCI_OPEN_TYPE flag.

The following additional flags apply to compound devices:

MCI_OPEN_ELEMENT

A filename is included in the lpstrElementName member of the structure identified by lpOpen.

MCI_OPEN_ELEMENT_ID

The lpstrElementName member of the structure identified by lpOpen is interpreted as a doubleword value and has meaning internal to the device. Use this flag with the MCI_OPEN_ELEMENT flag.

Animation Flags

The following additional flags are used with the animation device type:

MCI_ANIM_OPEN_NOSTATIC

The device should reduce the number of static (system) colors in the palette to two.

MCI_ANIM_OPEN_PARENT

The parent window handle is specified in the hWndParent member of the structure identified by lpOpen. The parent window handle is required for some window styles.

MCI_ANIM_OPEN_WS

A window style is specified in the dwStyle member of the structure identified by lpOpen. The dwStyle value specifies the style of the window that the driver will create and display if the application does not provide one. The style parameter takes an integer that defines the window style. These window style constants are the same as the ones that are used in the CreateWindow function (for example, WS_CHILD, WS_OVERLAPPEDWINDOW, and WS_POPUP).

For animation devices, the lpOpen parameter points to an MCI_ANIM_OPEN_PARMS structure.

Digital-Video Flags

The following additional flags are used with the digitalvideo device type:

MCI_DGV_OPEN_NOSTATIC

The device should reduce the number of static (system) colors in the palette. This increases the number of colors available for rendering the video stream. This flag applies only to devices that share a palette with Windows.

MCI_DGV_OPEN_PARENT

The parent window handle is specified in the hWndParent member of the structure identified by lpOpen.

MCI_DGV_OPEN_WS

A window style is specified in the dwStyle member of the structure identified by lpOpen.

For digital-video devices, the lpOpen parameter points to an MCI_DGV_OPEN_PARMS structure.

Video-Overlay Flags

The following additional flags are used with the overlay device type:

MCI_OVLY_OPEN_PARENT

The parent window handle is specified in the hWndParent member of the structure identified by lpOpen.

MCI_OVLY_OPEN_WS

A window style is specified in the dwStyle member of the structure identified by lpOpen. The dwStyle value specifies the style of the window that the driver will create and display if the application does not provide one. The style parameter takes an integer that defines the window style. These constants are the same as the standard window styles (such as WS_CHILD, WS_OVERLAPPEDWINDOW, or WS_POPUP).

For video-overlay devices, the lpOpen parameter points to an MCI_OVLY_OPEN_PARMS structure.

Waveform-Audio Flag

The following additional flag is used with the waveaudio device type:

MCI_WAVE_OPEN_BUFFER

A buffer length is specified in the dwBufferSeconds member of the structure identified by lpOpen.

For waveform-audio devices, the lpOpen parameter points to an MCI_WAVE_OPEN_PARMS structure. The MCIWAVE driver requires an asychronous waveform-audio device.


MCI_PASTE

MCIERROR mciSendCommand(MCIDEVICEID wDeviceID, MCI_PASTE,
    DWORD dwlags, (DWORD) (LPMCI_DGV_PASTE_PARMS) lpPaste);

Pastes data from the clipboard into a file. Digital-video devices recognize this command.

•	Returns zero if successful or an error otherwise.

dwFlags

MCI_NOTIFY, MCI_WAIT, or  MCI_TEST. For information about these flags, see Chapter 3, "MCI Overview."

lpPaste

Address of an MCI_DGV_PASTE_PARMS structure.

Additional Flags

The following additional flags apply to digital-video devices:

MCI_DGV_PASTE_AT

A rectangle is included in the rc member of the structure identified by lpPaste. The first two values of the rectangle specify the point within the frame to place the clipboard information. If the rectangle height and width are nonzero, the clipboard contents are scaled to those dimensions when they are pasted in the frame. If the flag is omitted, MCI_PASTE defaults to the entire frame rectangle.

MCI_DGV_PASTE_AUDIO_STREAM

An audio-stream number is included in the dwAudioStream member of the structure identified by lpPaste. If only one audio stream exists on the clipboard, the audio data is pasted into the designated stream. If more than one audio stream exists on the clipboard, the stream indicates the starting number for the stream sequences. If you use this flag and also want to paste video, you must also use the MCI_DGV_PASTE_VIDEO_STREAM flag. (If neither flag is specified, all audio and video streams are pasted starting with the first audio and video stream. Each pasted stream retains its original stream number.)

MCI_DGV_PASTE_INSERT

Clipboard data should be inserted in the existing workspace at the position specified by the MCI_TO flag. Any existing data after the insertion point is moved in the workspace to make room. This is the default.

MCI_DGV_PASTE_OVERWRITE

Clipboard data should replace data already present in the workspace. The workspace data replaced follows the insertion point.

MCI_DGV_PASTE_VIDEO_STREAM

A video-stream number is included in the dwVideoStream member of the structure identified by lpPaste. If only one video stream exists on the clipboard, the video data is pasted into the designated stream. If more than one video stream exists on the clipboard, the stream indicates the starting number for the stream sequences. If you use this flag and also want to paste audio, you must also use the MCI_DGV_PASTE_AUDIO_STREAM flag. (If neither flag is specified, all audio and video streams are pasted starting with the first audio and video stream. Each pasted stream retains its original stream number.)

MCI_TO

A position value is included in the dwTo member of the structure identified by lpPaste. The position value specifies the position to begin pasting data into the workspace. If this flag is omitted, the position defaults to the current position.


MCI_PAUSE

MCIERROR mciSendCommand(MCIDEVICEID wDeviceID, MCI_PAUSE,
    DWORD dwFlags, (DWORD) (LPMCI_GENERIC_PARMS) lpPause);

Pauses the current action. Animation, CD audio, digital-video, MIDI sequencer, VCR, videodisc, and waveform-audio devices recognize this command.

•	Returns zero if successful or an error otherwise.

dwFlags

MCI_NOTIFY, MCI_WAIT, or, for digital-video and VCR devices, MCI_TEST. For information about these flags, see Chapter 3, "MCI Overview."

lpPause

Address of an MCI_GENERIC_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

The difference between the MCI_STOP and MCI_PAUSE commands depends on the device. If possible, MCI_PAUSE suspends device operation but leaves the device ready to resume play immediately. With the MCICDA, MCISEQ, and MCIPIONR drivers, the MCI_PAUSE command works the same as the MCI_STOP command.

For digital-video devices, the lpPause parameter points to an MCI_DGV_PAUSE_PARMS structure.


MCI_PLAY

MCIERROR mciSendCommand(MCIDEVICEID wDeviceID, MCI_PLAY,
    DWORD dwFlags, (DWORD) (LPMCI_PLAY_PARMS ) lpPlay);

Signals the device to begin transmitting output data. Animation, CD audio, digital-video, MIDI sequencer, videodisc, VCR, and waveform-audio devices recognize this command.

•	Returns zero if successful or an error otherwise.

dwFlags

MCI_NOTIFY, MCI_WAIT, or, for digital-video and VCR devices, MCI_TEST. For information about these flags, see Chapter 3, "MCI Overview."

lpPlay

Address of an MCI_PLAY_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

Additional Flags

The following additional flags apply to all devices supporting MCI_PLAY:

MCI_FROM

A starting location is included in the dwFrom member of the structure identified by lpPlay. The units assigned to the position values are specified with the MCI_SET_TIME_FORMAT flag of the MCI_SET command. If MCI_FROM is not specified, the starting location defaults to the current position.

MCI_TO

An ending location is included in the dwTo member of the structure identified by lpPlay. The units assigned to the position values are specified with the MCI_SET_TIME_FORMAT flag of MCI_SET. If MCI_TO is not specified, the ending location defaults to the end of the media.

Animation Flags

The following additional flags are used with the animation device type:

MCI_ANIM_PLAY_FAST

Play fast.

MCI_ANIM_PLAY_REVERSE

Play in reverse.

MCI_ANIM_PLAY_SCAN

Play as quickly as possible.

MCI_ANIM_PLAY_SLOW

Play slowly.

MCI_ANIM_PLAY_SPEED

The play speed is included in the dwSpeed member of the structure identified by lpPlay.

For animation devices, lpPlay points to an MCI_ANIM_PLAY_PARMS structure.

Digital-Video Flags

The following additional flags are used with the digitalvideo device type:

MCI_DGV_PLAY_REPEAT

Playback should start again at the beginning when the end of the content is reached.

MCI_DGV_PLAY_REVERSE

Playback should occur in reverse.

MCI_MCIAVI_PLAY_WINDOW

Playback should occur in the window associated with a device instance (the default). (This flag is specific to MCIAVI.DRV.)

MCI_MCIAVI_PLAY_FULLSCREEN

Playback should use a full-screen display. Use this flag only when playing compressed or 8-bit files.

For digital-video devices, lpPlay points to an MCI_DGV_PLAY_PARMS structure.

VCR Flags

The following additional flags are used with the vcr device type:

MCI_VCR_PLAY_AT

The dwAt member of the structure identified by lpPlay contains a time when the entire command begins, or if the device is cued, when the device reaches the from position given by the MCI_CUE command.

MCI_VCR_PLAY_REVERSE

Playback should occur in reverse.

MCI_VCR_PLAY_SCAN

Playback should be as fast as possible while maintaining video output.

For VCR devices, lpPlay points to an MCI_VCR_PLAY_PARMS structure.

Videodisc Flags

The following additional flags are used with the videodisc device type:

MCI_VD_PLAY_FAST

Play fast.

MCI_VD_PLAY_REVERSE

Play in reverse.

MCI_VD_PLAY_SCAN

Scan quickly.

MCI_VD_PLAY_SLOW

Play slowly.

MCI_VD_PLAY_SPEED

The play speed is included in the dwSpeed member in the structure identified by lpPlay.

For animation devices, lpPlay points to an MCI_VD_PLAY_PARMS structure.


MCI_PUT

MCIERROR mciSendCommand(MCIDEVICEID wDeviceID, MCI_PUT,
    DWORD dwFlags, (DWORD) (LPMCI_GENERIC_PARMS) lpDest);

Sets the source, destination, and frame rectangles. Animation, digital-video, and video-overlay devices recognize this command.

•	Returns zero if successful or an error otherwise.

dwFlags

MCI_NOTIFY, MCI_WAIT, or, for digital-video devices, MCI_TEST. For information about these flags, see Chapter 3, "MCI Overview."

lpDest

Address of an MCI_GENERIC_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

Animation Flags

The following additional flags are used with the animation device type:

MCI_ANIM_PUT_DESTINATION

The rectangle defined for MCI_ANIM_RECT specifies the area of the client window used to display an image. The rectangle contains the offset and visible extent of the image relative to the window origin. If the frame is being stretched, the source is stretched to the destination rectangle.

MCI_ANIM_PUT_SOURCE

The rectangle defined for MCI_ANIM_RECT specifies a clipping rectangle for the animation image. The rectangle contains the offset and extent of the image relative to the image origin.

MCI_ANIM_RECT

The rc member of the structure identified by lpDest contains a valid rectangle. If this flag is not specified, the default rectangle matches the coordinates of the image or window being clipped.

For animation devices, lpDest points to an MCI_ANIM_RECT_PARMS structure.

Digital-Video Flags

The following additional flags are used with the digitalvideo device type:

MCI_DGV_PUT_CLIENT

The rectangle defined for MCI_DGV_RECT applies to the position of the client window. The rectangle specified is relative to the parent window of the display window. MCI_DGV_PUT_WINDOW must be set concurrently with this flag.

MCI_DGV_PUT_DESTINATION

The rectangle defined for MCI_DGV_RECT specifies a destination rectangle. The destination rectangle specifies the portion of the client window associated with this device driver instance that shows the image or video.

MCI_DGV_PUT_FRAME

The rectangle defined for MCI_DGV_RECT applies to the frame rectangle. The frame rectangle specifies the portion of the frame buffer used as the destination of the video images obtained from the video rectangle. The video should be scaled to fit within the frame buffer rectangle.

The rectangle is specified in frame buffer coordinates. The default rectangle is the full frame buffer. Specifying this rectangle lets the device scale the image as it digitizes the data. Devices that cannot scale the image reject this command with MCIERR_UNSUPPORTED_FUNCTION. You can use the MCI_GETDEVCAPS_CAN_STRETCH flag with the MCI_GETDEVCAPS command to determine if a device scales the image. A device returns FALSE if it cannot scale the image.

MCI_DGV_PUT_SOURCE

The rectangle defined for MCI_DGV_RECT specifies a source rectangle. The source rectangle specifies which portion of the frame buffer is to be scaled to fit into the destination rectangle.

MCI_DGV_PUT_VIDEO

The rectangle defined for MCI_DGV_RECT applies to the video rectangle. The video rectangle specifies which portion of the current presentation source is stored in the frame buffer. The rectangle is specified using the natural coordinates of the presentation source. It allows the specification of cropping that occurs prior to storing images and video in the frame buffer. The default rectangle is the full active scan area or the full decompressed images and video.

MCI_DGV_PUT_WINDOW

The rectangle defined for MCI_DGV_RECT applies to the display window. This rectangle is relative to the parent window of the display window (usually the desktop). If the window is not specified, it defaults to the initial window size and position.

MCI_DGV_RECT

The rc member of the structure identified by lpDest contains a valid rectangle.

For digital-video devices, lpDest points to an MCI_DGV_PUT_PARMS structure.

Video-Overlay Flags

The following additional flags are used with the overlay device type:

MCI_OVLY_PUT_DESTINATION

The rectangle defined for MCI_OVLY_RECT specifies the area of the client window used to display an image. The rectangle contains the offset and visible extent of the image relative to the window origin. If the frame is being stretched, the source is stretched to the destination rectangle.

MCI_OVLY_PUT_FRAME

The rectangle defined for MCI_OVLY_RECT specifies the area of the video buffer used to receive the video image. The rectangle contains the offset and extent of the buffer area relative to the video buffer origin.

MCI_OVLY_PUT_SOURCE

The rectangle defined for MCI_OVLY_RECT specifies the area of the video buffer used as the source of the digital image. The rectangle contains the offset and extent of the clipping rectangle for the video buffer relative to its origin.

MCI_OVLY_PUT_VIDEO

The rectangle defined for MCI_OVLY_RECT specifies the area of the video source capture by the video buffer. The rectangle contains the offset and extent of the clipping rectangle for the video source relative to its origin.

MCI_OVLY_RECT

The rc member of the structure identified by lpDest contains a valid display rectangle. If this flag is not specified, the default rectangle matches the coordinates of the video buffer or window being clipped.

For video-overlay devices, lpDest points to an MCI_OVLY_RECT_PARMS structure.


MCI_QUALITY

MCIERROR mciSendCommand(MCIDEVICEID wDeviceID, MCI_QUALITY,
    DWORD dwFlags, (DWORD) (LPMCI_DGV_QUALITY_PARMS) lpQuality);

Defines a custom quality level for audio, video, or still image data compression. Digital-video devices recognize this command.

•	Returns zero if successful or an error otherwise.

dwFlags

MCI_NOTIFY, MCI_WAIT, or MCI_TEST. For information about these flags, see Chapter 3, "MCI Overview."

lpQuality

Address of an MCI_DGV_QUALITY_PARMS structure.

The name defined for this quality level can be used when setting the audio, video, or still quality with the MCI_SETAUDIO and MCI_SETVIDEO commands.

Additional Flags

The following additional flags apply to digital-video devices:

MCI_QUALITY_ALG

The lpstrAlgorithm member of the structure identified by lpQuality contains an address of a buffer containing the name of the algorithm. This algorithm must be supported by the device driver, and must be compatible with the audio, still, or video descriptor that is used. If this flag is omitted, the current algorithm is used.

MCI_QUALITY_DIALOG

The device driver should display a dialog box for specifying the quality level. The dialog box has algorithm-specific fields used internally by the device driver to create a structure describing a specific quality level.

MCI_QUALITY_HANDLE

The dwHandle member of the structure identified by lpQuality contains a handle to a structure. The structure contains algorithmic-specific data describing the specific quality level. The format of the structures for the algorithms is device dependent.

MCI_QUALITY_ITEM

A constant indicating the type of algorithm is included in the dwItem member of the structure identified by lpQuality.

MCI_QUALITY_NAME

The lpstrName member of the structure identified by lpQuality contains an address of a buffer containing the quality descriptor.


MCI_REALIZE

MCIERROR mciSendCommand(MCIDEVICEID wDeviceID, MCI_REALIZE,
    DWORD dwFlags, (DWORD) (LPMCI_GENERIC_PARMS) lpRealize);

Causes a graphic device to realize its palette into a device context (DC). Animation and digital-video devices recognize this command.

•	Returns zero if successful or an error otherwise.

dwFlags

MCI_NOTIFY, MCI_WAIT, or, for digital-video devices, MCI_TEST. For information about these flags, see Chapter 3, "MCI Overview."

lpRealize

Address of an MCI_GENERIC_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

You should use this command when your application receives the WM_QUERYNEWPALETTE message.

Animation Flags

The following additional flags are used with the animation device type:

MCI_ANIM_REALIZE_BKGD

Realizes the palette as a background palette.

MCI_ANIM_REALIZE_NORM

Realizes the palette normally. This is the default.

Digital-Video Flags

The following additional flags are used with the digitalvideo device type:

MCI_DGV_REALIZE_BKGD

Realizes the palette as a background palette.

MCI_DGV_REALIZE_NORM

Realizes the palette normally. This is the default.

For digital-video devices, the lpRealize parameter points to an MCI_REALIZE_PARMS structure. The MCI_REALIZE_PARMS structure is identical to the MCI_GENERIC_PARMS structure.


MCI_RECORD

MCIERROR mciSendCommand(MCIDEVICEID wDeviceID, MCI_RECORD,
    DWORD dwFlags, (DWORD) (LPMCI_RECORD_PARMS) lpRecord);

Starts recording from the current position or from one specified location to another specified location. VCR and waveform-audio devices recognize this command. Although digital-video devices and MIDI sequencers also recognize this command, the MCIAVI and MCISEQ drivers do not implement it.

•	Returns zero if successful or an error otherwise.

dwFlags

MCI_NOTIFY, MCI_WAIT, or, for digital-video and VCR devices, MCI_TEST. For information about these flags, see Chapter 3, "MCI Overview."

lpRecord

Address of an MCI_RECORD_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

This command is supported by devices that return TRUE when you call the MCI_GETDEVCAPS command with the MCI_GETDEVCAPS_CAN_RECORD flag. For the MCIWAVE driver, all data recorded after a file is opened is discarded if the file is closed without saving it.

Additional Flags

The following additional flags apply to all devices supporting MCI_RECORD:

MCI_FROM

A starting location is included in the dwFrom member of the structure identified by lpRecord. The units assigned to the position values are specified with the MCI_SET_TIME_FORMAT flag of the MCI_SET command. If MCI_FROM is not specified, the starting location defaults to the current position.

MCI_RECORD_INSERT

Newly recorded information should be inserted or pasted into the existing data. Some devices might not support this. If supported, this is the default.

MCI_RECORD_OVERWRITE

Data should overwrite existing data. The MCIWAVE.DRV device returns MCIERR_UNSUPPORTED_FUNCTION in response to this flag.

MCI_TO

An ending location is included in the dwTo member of the structure identified by lpRecord. The units assigned to the position values are specified with the MCI_SET_TIME_FORMAT flag of the MCI_SET command. If MCI_TO is not specified, the ending location defaults to the end of the content.

Digital-Video Flags

The following additional flags are used with the digitalvideo device type:

MCI_DGV_RECORD_AUDIO_STREAM

An audio-stream number is included in the dwAudioStream member of the structure identified by lpRecord. If you omit this flag, audio data is recorded into the first physical stream.

MCI_DGV_RECORD_HOLD

When recording stops, the screen will hold the last image and will not resume showing the video until an MCI_MONITOR command is issued.

MCI_DGV_RECORD_VIDEO_STREAM

A video-stream number is included in the dwVideoStream member of the structure identified by lpRecord. If you omit this flag, video data is recorded into the first physical stream.

MCI_DGV_RECT

A rectangle is specified in the rc member of the structure identified by lpRecord. The rectangle specifies the region of the external input used as the source for the pixels compressed and saved. This rectangle defaults to the rectangle specified (or defaulted) by the MCI_DGV_PUT_VIDEO flag for the MCI_PUT command. When it is set differently than the video rectangle, what is displayed is not what is recorded

For digital-video devices, lpRecord points to an MCI_DGV_RECORD_PARMS structure.

VCR Flags

The following additional flags are used with the vcr device type:

MCI_VCR_RECORD_AT

The dwAt member of the structure identified by lpRecord contains a time when the entire command begins, or if the device is cued, when the device reaches the from position given by the cue command.

MCI_VCR_RECORD_INITIALIZE

Seek the device to the start of the media, begin recording blank video and audio, and record timecode, if possible.

For VCR devices, lpRecord points to an MCI_VCR_RECORD_PARMS structure.


MCI_RESERVE

MCIERROR mciSendCommand(MCIDEVICEID wDeviceID, MCI_RESERVE,
    DWORD dwFlags, (DWORD) (LPMCI_DGV_RESERVE_PARMS) lpReserve);

Allocates contiguous disk space for the workspace of the device driver instance for use with subsequent recording. Digital-video devices recognize this command.

•	Returns zero if successful or an error otherwise.

dwFlags

MCI_NOTIFY, MCI_WAIT, or MCI_TEST. For information about these flags, see Chapter 3, "MCI Overview."

lpReserve

Address of an MCI_DGV_RESERVE_PARMS structure.

If the workspace contains unsaved data, this data is lost. If disk space is not reserved prior to recording, the MCI_RECORD command performs an implied reserve with device-specific default parameters. On some implementations, reserve is not required and might be ignored by the device driver. Explicitly reserving space gives you better control over when the delay for disk allocation occurs, how much space is allocated, and where the disk space is allocated. The amount and location of disk space already reserved for this device instance can be changed by issuing MCI_RESERVE again. Any allocated and still unused disk space is not deallocated until any recorded data is saved or until the device driver instance is closed.

If video is turned off with the MCI_OFF flag of the MCI_SETVIDEO command, the space reserved does not include any video. If audio is turned off with the MCI_OFF flag of the MCI_SETAUDIO command, the space reserved does not include any audio. If both audio and video are turned off or if the requested size is zero, no space is reserved and any existing reserved space is deallocated.

Additional Flags

The following additional flags apply to digital-video devices:

MCI_DGV_RESERVE_IN

The lpstrPath member of the structure identified by lpReserve contains an address of a buffer containing the location of a temporary file. The buffer contains only the drive and directory path of the file used to hold recorded data; the filename is specified by the device driver. This temporary file is deleted when the device instance is closed unless it is explicitly saved. If this flag is omitted, the device driver specifies where disk space is allocated.

MCI_DGV_RESERVE_SIZE

The dwSize member of the structure identified by lpReserve specifies the approximate amount of disk space to reserve in the workspace for recording. The value is specified in the current time format. The amount of disk space is estimated from the requested time and from which file format and video and audio algorithm and quality values are in effect. If this flag is omitted, the device driver might use a default value it defines.


MCI_RESTORE

MCIERROR mciSendCommand(MCIDEVICEID wDeviceID, MCI_RESTORE,
    DWORD dwFlags, (DWORD) (LPMCI_DGV_RESTORE_PARMS) lpRestore);

Copies a bitmap from a file to the frame buffer. Digital-video devices recognize this command. This command performs the opposite action of the MCI_CAPTURE command.

•	Returns zero if successful or an error otherwise.

dwFlags

MCI_NOTIFY, MCI_WAIT, or MCI_TEST. For information about these flags, see Chapter 3, "MCI Overview."

lpRestore

Address of an MCI_DGV_RESTORE_PARMS structure.

The implementation can recognize a variety of image formats, but a Windows device-independent bitmap (DIB) is always accepted.

Additional Flags

The following additional flags apply to digital-video devices:

MCI_DGV_RESTORE_FROM

The lpstrFileName member of the structure identified by lpRestore contains an address of a buffer containing the source filename. The filename is required.

MCI_DGV_RESTORE_AT

The rc member of the structure identified by lpRestore contains a valid rectangle. The rectangle specifies a region of the frame buffer relative to its origin. The first pair of coordinates specifies the upper left corner of the rectangle; the second pair specifies the width and height. If this flag is not specified, the image is copied to the upper left corner of the frame buffer.


MCI_RESUME

MCIERROR mciSendCommand(MCIDEVICEID wDeviceID, MCI_RESUME,
    DWORD dwFlags, (DWORD) (LPMCI_GENERIC_PARMS) lpResume);

Causes a paused device to resume the paused operation. Animation, digital-video, VCR, and waveform-audio devices recognize this command. Although CD audio, MIDI sequencer, and videodisc devices also recognize this command, the MCICDA, MCISEQ, and MCIPIONR device drivers do not support it.

•	Returns zero if successful or an error otherwise.

dwFlags

MCI_NOTIFY, MCI_WAIT, or, for digital-video and VCR devices, MCI_TEST. For information about these flags, see Chapter 3, "MCI Overview."

lpResume

Address of an MCI_GENERIC_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

This command resumes playing and recording without changing the current track position set with MCI_PLAY or MCI_RECORD.


MCI_SAVE

MCIERROR mciSendCommand(MCIDEVICEID wDeviceID, MCI_SAVE,
    DWORD dwFlags, (DWORD) (LPMCI_SAVE_PARMS ) lpSave);

Saves the current file. Devices that modify files should not destroy the original copy until they receive the save message. Video-overlay and waveform-audio devices recognize this command. Although digital-video devices and MIDI sequencers also recognize this command, the MCIAVI and MCISEQ drivers do not implement it.

•	Returns zero if successful or an error otherwise.

dwFlags

MCI_NOTIFY, MCI_WAIT, or, for digital-video and VCR devices, MCI_TEST. For information about these flags, see Chapter 3, "MCI Overview."

lpSave

Address of an MCI_SAVE_PARMS structure. (Devices with additional parameters might replace this structure with a device-specific structure.)

This command is supported by devices that return TRUE when you call the MCI_GETDEVCAPS command with the MCI_GETDEVCAPS_CAN_SAVE flag.

Additional Flag

The following additional flag applies to all devices supporting MCI_SAVE:

MCI_SAVE_FILE

The lpfilename member of the structure identified by lpSave contains an address of a buffer containing the destination filename.

Digital-Video Flags

The following additional flags are used with the digitalvideo device type:

MCI_DGV_RECT

The rc member of the structure identified by lpSave contains a valid rectangle. The rectangle specifies a region of the frame buffer that will be saved to the specified file. The first pair of coordinates specifies the upper left corner of the rectangle; the second pair specifies the width and height. Digital-video devices must use the MCI_CAPTURE command to capture the contents of the frame buffer. (Video-overlay devices should also use MCI_CAPTURE.) This flag is for compatibility with the existing MCI video-overlay command set.

MCI_DGV_SAVE_ABORT

Stops a save operation in progress. This must be the only flag present.

MCI_DGV_SAVE_KEEPRESERVE

Unused disk space left over from the original MCI_RESERVE command is not deallocated.

For digital-video devices, the lpSave parameter points to an MCI_DGV_SAVE_PARMS structure.

Video-Overlay Flags

The following additional flag is used with the overlay device type:

MCI_OVLY_RECT

The rc member of the structure identified by lpSave contains a valid display rectangle indicating the area of the video buffer to save.

For video-overlay devices, the lpSave parameter points to an MCI_OVLY_SAVE_PARMS structure.


MCI_SEEK

MCIERROR mciSendCommand(MCIDEVICEID wDeviceID, MCI_SEEK,
    DWORD dwFlags, (DWORD) (LPMCI_SEEK_PARMS) lpSeek);

Changes the current position in the content as quickly as possible. Video and audio output are disabled during the seek. After the seek is complete, the device is stopped. Animation, CD audio, digital-video, MIDI sequencer, VCR, videodisc, and waveform-audio devices recognize this command.

•	Returns zero if successful or an error otherwise.

dwFlags

MCI_NOTIFY, MCI_WAIT, or, for digital-video and VCR devices, MCI_TEST. For information about these flags, see Chapter 3, "MCI Overview."

lpSeek

Address of an MCI_SEEK_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

If a data sample size for a device is larger than 1 byte (such as with waveform-audio stereo data), this command moves to the beginning of the nearest sample when a specified position does not coincide with the start of a sample.

Additional Flags

The following additional flags apply to all devices supporting MCI_SEEK:

MCI_SEEK_TO_END

Seek to the end of the content.

MCI_SEEK_TO_START

Seek to the beginning of the content.

MCI_TO

A position is included in the dwTo member of the structure identified by lpSeek. The units assigned to the position values are specified with the MCI_SET_TIME_FORMAT flag of the MCI_SET command. Do not use this flag with MCI_SEEK_TO_END or MCI_SEEK_TO_START.

VCR Flags

The following additional flags are used with the vcr device type:

MCI_VCR_SEEK_AT

The dwAt member of the structure identified by lpSeek contains a time when the entire command begins.

MCI_VCR_SEEK_MARK

The dwMark member of the structure identified by lpSeek contains the numbered mark to search for.

MCI_VCR_SEEK_REVERSE

Seek direction is reverse; this is used only with the MCI_VCR_SEEK_MARK flag.

For VCR devices, the lpSeek parameter points to an MCI_VCR_SEEK_PARMS structure.

Videodisc Flag

The following additional flag is used with the videodisc device type:

MCI_VD_SEEK_REVERSE

Seek direction is reverse.


MCI_SET

MCIERROR mciSendCommand(MCIDEVICEID wDeviceID, MCI_SET,
    DWORD dwFlags, (DWORD) (LPMCI_SET_PARMS) lpSet);

Sets device information. Animation, CD audio, digital-video, MIDI sequencer, VCR, videodisc, video-overlay, and waveform-audio devices recognize this command.

•	Returns zero if successful or an error otherwise.

dwFlags

MCI_NOTIFY, MCI_WAIT, or, for digital-video and VCR devices, MCI_TEST. For information about these flags, see Chapter 3, "MCI Overview."

lpSet

Address of an MCI_SET_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

Additional Flags

The following additional flags apply to all devices supporting MCI_SET:

MCI_SET_AUDIO

An audio channel number is included in the dwAudio member of the structure identified by lpSet. This flag must be used with MCI_SET_ON or MCI_SET_OFF. Use one of the following constants to indicate the channel number:

MCI_SET_AUDIO_ALL

All audio channels.

MCI_SET_AUDIO_LEFT

Left channel.

MCI_SET_AUDIO_RIGHT

Right channel.

MCI_SET_DOOR_CLOSED

Closes the media cover (if any).

MCI_SET_DOOR_OPEN

Opens the media cover (if any).

MCI_SET_OFF

Disables the specified video or audio channel.

MCI_SET_ON

Enables the specified video or audio channel.

MCI_SET_TIME_FORMAT

A time format parameter is included in the dwTimeFormat member of the structure identified by lpSet. The following flags are used with this flag:

MCI_FORMAT_BYTES

Within a PCM (Pulse Code Modulation) data format, changes the time member description to bytes for input or output. Recognized by the waveaudio device type.

MCI_FORMAT_FRAMES

Subsequent commands will use frames. Recognized by the animation, digitalvideo, vcr, and videodisc device types.

MCI_FORMAT_HMS

Changes the time format to hours, minutes, and seconds. Recognized by the vcr and videodisc device types.

MCI_FORMAT_MILLISECONDS

Changes the time format to milliseconds. Recognized by all device types.

MCI_FORMAT_MSF

Changes the time format to minutes, seconds, and frames. Recognized by the cdaudio and vcr device types.

MCI_FORMAT_SAMPLES

Changes the time format to samples for input or output. Recognized by the waveaudio device type.

MCI_FORMAT_SMPTE_24, MCI_FORMAT_SMPTE_25, and MCI_FORMAT_SMPTE_30

Sets the time format to 24, 25, and 30 frame SMPTE (Society of Motion Picture and Television Engineers), respectively. Recognized by the sequencer and vcr device types.

MCI_FORMAT_SMPTE_30DROP

Sets the time format to 30 drop-frame SMPTE. Recognized by the sequencer and vcr device types.

MCI_FORMAT_TMSF

Changes the time format to tracks, minutes, seconds, and frames. (MCI uses continuous track numbers.) Recognized by the cdaudio and vcr device types.

MCI_SET_VIDEO

Sets the video signal on or off. This flag must be used with either MCI_SET_ON or MCI_SET_OFF. Devices that do not have video return MCIERR_UNSUPPORTED_FUNCTION.

Digital-Video Flags

The following additional flags are used with the digitalvideo device type:

MCI_DGV_SET_FILEFORMAT

A file format parameter is included in the dwFileFormat member of the structure identified by lpSet. For digital-video devices, the file format is used for save or capture commands. If omitted, this might default to a device driver defined format. If the specified file format conflicts with the currently selected algorithm and quality, then they are changed to the defaults for the file format. The following file format constants are defined:

MCI_DGV_FF_AVI

AVI format.

MCI_DGV_FF_AVSS

AVSS format.

MCI_DGV_FF_DIB

DIB format.

MCI_DGV_FF_JFIF

JFIF format.

MCI_DGV_FF_JPEG

JPEG format.

MCI_DGV_FF_MPEG

MPEG format.

MCI_DGV_FF_RDIB

RLE DIB format.

MCI_DGV_FF_RJPEG

RJPEG format.

MCI_DGV_SET_SEEK_EXACTLY

Sets the format used for positioning. This flag must be used with MCI_SET_ON or MCI_SET_OFF. If MCI_SET_ON is specified, playing or recording precisely accesses the frame specified with the MCI_FROM flag. This might add some extra delay if the requested frame is not a key frame. If MCI_SET_OFF is specified, the device will seek to a key-frame image that precedes the requested frame. For some files and devices, this might be the first frame of the file. The default for this flag is device dependent.

MCI_DGV_SET_SPEED

A speed parameter is included in the dwSpeed member of the structure identified by lpSet. Speed is specified as a ratio between the nominal frame rate and the desired frame rate where the nominal frame rate is designated as 1000. Half speed is 500 and double speed is 2000. The allowable speed range is dependent on the device and possibly the file, too.

MCI_DGV_SET_STILL

When used with MCI_DGV_SET_FILEFORMAT, MCI_SET sets the file format used for capture commands.

For digital-video devices, the lpSet parameter points to an MCI_DGV_SET_PARMS structure.

Sequencer Flags

The following additional flags are used with the sequencer device type:

MCI_SEQ_FORMAT_SONGPTR

Sets the time format to song pointer units.

MCI_SEQ_SET_MASTER

Sets the sequencer as a source of synchronization data and indicates that the type of synchronization is specified in the dwMaster member of the structure identified by lpSet. MCISEQ returns MCIERR_UNSUPPORTED_FUNCTION. The following constants are defined for the synchronization type:

MCI_SEQ_MIDI

The sequencer will send MIDI format synchronization data.

MCI_SEQ_SMPTE

The sequencer will send SMPTE format synchronization data.

MCI_SEQ_NONE

The sequencer will not send synchronization data.

MCI_SEQ_SET_OFFSET

Changes the SMPTE offset of a sequence to that specified by the dwOffset member of the structure identified by lpSet. This affects only sequences with a SMPTE division type.

MCI_SEQ_SET_PORT

Sets the output MIDI port of a sequence to that specified by the MIDI device identifier in the dwPort member of the structure identified by lpSet. The device closes the previous port (if any), and attempts to open and use the new port. If it fails, it returns an error and reopens the previously used port (if any). The following constants are defined for the ports:

MCI_SEQ_NONE

Closes the previously used port (if any). The sequencer behaves exactly the same as if a port were open, except no MIDI message is sent.

MIDI_MAPPER

Sets the port opened to the MIDI mapper.

MCI_SEQ_SET_SLAVE

Sets the sequencer to receive synchronization data and indicates that the type of synchronization is specified in the dwSlave member of the structure identified by lpSet. MCISEQ returns MCIERR_UNSUPPORTED_FUNCTION. The following constants are defined for the synchronization type:

MCI_SEQ_FILE

Sets the sequencer to receive synchronization data contained in the MIDI file.

MCI_SEQ_MIDI

Sets the sequencer to receive MIDI synchronization data.

MCI_SEQ_NONE

Sets the sequencer to ignore synchronization data in a MIDI stream.

MCI_SEQ_SMPTE

Sets the sequencer to receive SMPTE synchronization data.

MCI_SEQ_SET_TEMPO

Changes the tempo of the MIDI sequence to that specified by the dwTempo member of the structure pointed to by lpSet. For sequences with division type PPQN, tempo is specified in beats per minute; for sequences with division type SMPTE, tempo is specified in frames per second.

For sequencer devices, the lpSet parameter points to an MCI_SEQ_SET_PARMS structure.

VCR Flags

The following additional flags are used with the vcr device type:

MCI_VCR_SET_ASSEMBLE_RECORD

Sets the device to record in assemble or insert modes (when assemble is off, insert is on, and vice-versa). Use with one of the following flag:

MCI_SET_ON

Sets assemble record on, and turns insert record off. Records all video, audio and timecode tracks.

MCI_SET_OFF

Sets assemble record off, and turns insert record on. When assemble record is off, individual tracks of video, audio, and timecode can be selected for recording.

MCI_VCR_SET_CLOCK

The dwClock member of the structure identified by lpSet contains the new clock time.

MCI_VCR_SET_COUNTER_FORMAT

The dwCounterFormat member of the structure identified by lpSet contains a constant specifying the new counter-time format to be used by the status counter. For a list of valid constants, see MCI_SET_TIME_FORMAT in the list of additional flags for this command.

MCI_VCR_SET_COUNTER_VALUE

The dwCounterValue member of the structure identified by lpSet contains the new counter value.

MCI_VCR_SET_INDEX

The dwIndex member of the structure identified by lpSet contains a constant indicating the contents of the on-screen display and must be one of the following:

MCI_VCR_INDEX_COUNTER

Displays counter.

MCI_VCR_INDEX_DATE

Displays date.

MCI_VCR_INDEX_TIME

Displays time.

MCI_VCR_INDEX_TIMECODE

Displays timecode.

For more information, see the MCI_INDEX command.

MCI_VCR_SET_PAUSE_TIMEOUT

The dwPauseTimeout member of the structure identified by lpSet contains the maximum duration, in milliseconds, of a pause command.

MCI_VCR_SET_POSTROLL_DURATION

The dwPostrollDuration member of the structure identified by lpSet contains the videotape length, in the current time format, needed to brake the VCR transport when a stop or pause command is issued.

MCI_VCR_SET_POWER

Sets the power on or off. Must be used with one of the following flags:

MCI_SET_OFF

Turns power off.

MCI_SET_ON

Turns power on.

MCI_VCR_SET_PREROLL_DURATION

The dwPrerollDuration member of the structure identified by lpSet contains the videotape length, in the current time format, needed to stabilize the VCR output.

MCI_VCR_SET_RECORD_FORMAT

The dwRecordFormat member of the structure identified by lpSet contains a constant describing the record speed, which must be one of the following:

MCI_VCR_FORMAT_EP

Records at slow speed.

MCI_VCR_FORMAT_LP

Records at medium-slow speed.

MCI_VCR_FORMAT_SP

Records at standard speed.

MCI_VCR_SET_SPEED

The dwSpeed member of the structure identified by lpSet contains the new speed setting, where 1000 is normal speed, 2000 is double speed, and 500 is half speed, and so on.

MCI_VCR_SET_TAPE_LENGTH

The dwTapeLength member of the structure identified by lpSet contains the new length of the tape, provided that the length of the tape is undetectable.

MCI_VCR_SET_TIME_MODE

The dwTimeMode member of the structure identified by lpSet contains a constant indicating the new positional time mode. The following constants are valid:

MCI_VCR_TIME_COUNTER

Forces the device to use counter exclusively.

MCI_VCR_TIME_DETECT

Each time a new videotape is inserted into the device, or the mode changes from not ready to ready, the device should attempt to determine if there is timecode available on the videotape. If timecode is available, use timecode in all subsequent commands that specify positions. Otherwise, use the counter.

MCI_VCR_TIME_TIMECODE

Forces the device to use timecode exclusively.

MCI_VCR_SET_TRACKING

Tunes the speed of the VCR tape transport with a fine adjustment, and must be used with one of the following flags:

MCI_VCR_PLUS

Increases the tape transport speed.

MCI_VCR_MINUS

Decreases the tape transport speed.

MCI_VCR_RESET

Returns the tracking adjustment to zero.

For VCR devices, the lpSet parameter points to an MCI_VCR_SET_PARMS structure.

Videodisc Flags

The following additional flag is used with the videodisc device type:

MCI_VD_FORMAT_TRACK

Changes the time format to tracks. MCI uses continuous track numbers.

For videodisc devices, the lpSet parameter points to an MCI_VD_SET_PARMS structure.

Waveform-Audio Flags

The following additional flags are used with the waveaudio device type:

MCI_WAVE_INPUT

Sets the input used for recording to the wInput member of the structure identified by lpSet.

MCI_WAVE_OUTPUT

Sets the output used for playing to the wOutput member of the structure identified by lpSet.

MCI_WAVE_SET_ANYINPUT

Any wave input compatible with the current format can be used for recording.

MCI_WAVE_SET_ANYOUTPUT

Any wave output compatible with the current format can be used for playing.

MCI_WAVE_SET_AVGBYTESPERSEC

Sets the bytes per second used for playing, recording, and saving to the nAvgBytesPerSec member of the structure identified by lpSet.

MCI_WAVE_SET_BITSPERSAMPLE

Sets the bits per sample used for playing, recording, and saving to the nBitsPerSample member of the PCM data format identified by lpSet.

MCI_WAVE_SET_BLOCKALIGN

Sets the block alignment used for playing, recording, and saving to the nBlockAlign member of the structure identified by lpSet.

MCI_WAVE_SET_CHANNELS

The number of channels is indicated in the nChannels member of the structure identified by lpSet.

MCI_WAVE_SET_FORMATTAG

Sets the format type used for playing, recording, and saving to the wFormatTag member of the structure identified by lpSet. Specifying WAVE_FORMAT_PCM changes the format to PCM.

MCI_WAVE_SET_SAMPLESPERSEC

Sets the samples per second used for playing, recording, and saving to the nSamplesPerSec member of the structure identified by lpSet.

For waveform-audio devices, the lpSet parameter points to an MCI_WAVE_SET_PARMS structure.

Several properties of waveform-audio data are defined when the file to store the data is created. These properties describe how the data is structured within the file and cannot be changed once recording begins. The following list of flags identifies these properties:

•	MCI_WAVE_SET_AVGBYTESPERSEC

•	MCI_WAVE_SET_BITSPERSAMPLE

•	MCI_WAVE_SET_BLOCKALIGN

•	MCI_WAVE_SET_CHANNELS

•	MCI_WAVE_SET_FORMATTAG

•	MCI_WAVE_SET_SAMPLESPERSEC


MCI_SETAUDIO

MCIERROR mciSendCommand(MCIDEVICEID wDeviceID, MCI_SETAUDIO,
    DWORD dwFlags, (DWORD) (LPMCI_GENERIC_PARMS) lpSetAudio);

Sets values associated with audio playback and capture. Digital-video and VCR devices recognize this command.

•	Returns zero if successful or an error otherwise.

dwFlags

MCI_NOTIFY, MCI_WAIT, or MCI_TEST. For information about these flags, see Chapter 3, "MCI Overview."

lpSetAudio

Address of an MCI_GENERIC_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

Digital-Video Flags

The following flags apply to the digitalvideo device type:

MCI_DGV_SETAUDIO_ALG

The lpstrAlgorithm member of the structure identified by lpSetAudio contains an address of a buffer containing the name of an audio compression algorithm. The compression algorithm is used by subsequent MCI_RESERVE or MCI_RECORD commands. The available algorithms are device dependent. If the algorithm is incompatible with the current file format, the file format is changed to the default format for the algorithm.

MCI_DGV_SETAUDIO_CLOCKTIME

The time specified is in milliseconds and is absolute time when used with MCI_DGV_SETAUDIO_OVER. (This time is not in step with the playing of the workspace.)

MCI_DGV_SETAUDIO_INPUT

Modifies the bass, treble, or volume flag so that it affects the input signal and modifies what is recorded. If possible, this is the default when monitoring the input.

MCI_DGV_SETAUDIO_ITEM

An audio constant is specified in the dwItem member of the structure identified by lpSetAudio. The constant identifies the value that is being set. The following constants are defined:

MCI_DGV_SETAUDIO_AVGBYTESPERSEC

The average number of bytes is specified in the dwValue member of the structure identified by lpSetAudio. This value sets the average number of bytes per second for playing or recording in the PCM (Pulse Code Modulation) and ADPCM (Adaptive Differential Pulse Code Modulation) formats. The file is saved in this format.

MCI_DGV_SETAUDIO_BASS

The audio low frequency level is specified as a factor in the dwValue member of the structure identified by lpSetAudio.

MCI_DGV_SETAUDIO_BITSPERSAMPLE

The number of bits per sample is specified in the dwValue member of the structure identified by lpSetAudio. This value sets the number of bits per sample played or recorded in the PCM format. The file is saved in this format.

MCI_DGV_SETAUDIO_BLOCKALIGN

The data block alignment is specified in the dwValue member of the structure identified by lpSetAudio. This value sets the alignment of data blocks relative to the start of input waveform data.

MCI_DGV_SETAUDIO_SAMPLESPERSEC

The sample rate is specified in the dwValue member of the structure identified by lpSetAudio. This value sets the sample rate for playing and recording with the PCM and ADPCM algorithms. The file is saved in this format.

MCI_DGV_SETAUDIO_SOURCE

A constant specifying the source of audio input is included in the dwValue member of the structure identified by lpSetAudio. The following constants are defined for the audio input sources:

MCI_DGV_SETAUDIO_SOURCE_AVERAGE

The average of the left and right audio channels.

MCI_DGV_SETAUDIO_SOURCE_LEFT

Left audio channel.

MCI_DGV_SETAUDIO_SOURCE_RIGHT

Right audio channel.

MCI_DGV_SETAUDIO_SOURCE_STEREO

Stereo.

MCI_DGV_SETAUDIO_STREAM

An audio-stream is specified in the dwValue member of the structure identified by lpSetAudio. The integer value specifies the audio stream played back from the workspace. If the stream is not specified, the first physically interleaved audio stream is played.

MCI_DGV_SETAUDIO_TREBLE

The audio high-frequency level is specified as a factor in the dwValue member of the structure identified by lpSetAudio.

MCI_DGV_SETAUDIO_VOLUME

The audio level for one or both audio channels is specified as a factor in the dwValue member of the structure identified by lpSetAudio. If the left and right volumes have been set to different values, then the ratio of left to right volume is approximately unchanged.

MCI_DGV_SETAUDIO_LEFT

Enables the left audio channel when used with MCI_SET_ON. Disables the left audio channel when used with MCI_SET_OFF. When this flag is used with the combination of MCI_DGV_SETAUDIO_VALUE and MCI_DGV_SETAUDIO_VOLUME, it sets the volume of the left audio channel. When this flag is used with MCI_DGV_SETAUDIO_SOURCE, it specifies the left audio channel as the source for the audio input digitizer.

MCI_DGV_SETAUDIO_OVER

A transition length parameter is included in the dwOver member of the structure identified by lpSetAudio. The length value specifies how long (in units of the current time format) it should take to make a change that uses a factor. If this flag is not used, changes occur immediately.

MCI_DGV_SETAUDIO_QUALITY

The lpstrQuality member of the structure identified by lpSetAudio contains an address of a buffer defining the audio quality. A text-string within the buffer specifies the characteristics of the audio compression algorithm.

The MCI_DGV_SETAUDIO_ALG flag can be used to select a quality descriptor for the specified algorithm. If this flag is omitted, then the current algorithm is used.

The algorithms and descriptor names available depend on the device. Each device supplies documentation for the available algorithms and a description of the applicable descriptor names. The MCI_QUALITY command can define additional descriptor names.

MCI_DGV_SETAUDIO_RECORD

Specifies whether recording includes or excludes audio data. When combined with MCI_SET_ON, audio data is recorded. When combined with MCI_SET_OFF, audio data is excluded. The default includes audio data.

MCI_DGV_SETAUDIO_RIGHT

Enables the right audio channel when used with MCI_SET_ON. Disables the right audio channel when used with MCI_SET_OFF. When this flag is used with the combination of MCI_DGV_SETAUDIO_VALUE and MCI_DGV_SETAUDIO_VOLUME, it sets the volume of the right audio channel.

MCI_DGV_SETAUDIO_VALUE

A value is specified in the dwValue member of the structure identified by lpSetAudio. The meaning of the value is specified by the constant defined for the MCI_DGV_SETAUDIO_ITEM flag.

MCI_SET_OFF

Disables the specified audio channel.

MCI_SET_ON

Enables the specified audio channel.

MCI_SETAUDIO_OUTPUT

Modifies the bass, treble, or volume flag so that it modifies only the played signal and not what is recorded. If possible, this is the default when monitoring the input.

For digital-video devices, the lpSetAudio parameter points to an MCI_DGV_SETAUDIO_PARMS structure.

VCR Flags

The following additional flags are used with the vcr device type:

MCI_VCR_SETAUDIO_RECORD

Sets the audio recording to on or off, which is used in conjunction with one of following flags:

MCI_SET_ON

Audio recording on.

MCI_SET_OFF

Audio recording off. It might be necessary to first turn off the assemble recording (using the MCI_SET command with the MCI_VCR_SET_ASSEMBLE_RECORD flag set to off) before the audio recording can be turned off.

MCI_TRACK

The dwTrack member of the structure identified by lpSetAudio specifies which track is affected by the command.

MCI_VCR_SETAUDIO_SOURCE

Sets the audio source. This flag must be used with the MCI_VCR_SETAUDIO_TO flag.

MCI_VCR_SETAUDIO_MONITOR

Sets the audio source monitor. This flag must be used with the MCI_VCR_SETAUDIO_TO flag.

MCI_VCR_SETAUDIO_TO

The dwTo member of the structure identified by lpSetAudio contains a constant describing the type of input or monitored input. It must be one of the following:

MCI_VCR_SRC_TYPE_TUNER

Type is tuner.

MCI_VCR_SRC_TYPE_LINE

Type is line.

MCI_VCR_SRC_TYPE_AUX

Type is auxiliary.

MCI_VCR_SRC_TYPE_GENERIC

Type is generic.

MCI_VCR_SRC_TYPE_MUTE

Type is mute. This can be used only with the MCI_VCR_SETAUDIO_SOURCE flag.

MCI_VCR_SRC_TYPE_OUTPUT

Type is output.

MCI_VCR_SETAUDIO_NUMBER

The dwNumber member of the structure identified by lpSetAudio contains the audio input (of the type specified in the dwTo member) to use.

For VCR devices, the lpSetAudio parameter points to an MCI_VCR_SETAUDIO_PARMS structure.


MCI_SETTIMECODE

MCIERROR mciSendCommand(MCIDEVICEID wDeviceID, MCI_SETTIMECODE,
    DWORD dwFlags, (DWORD) (LPMCI_GENERIC_PARMS) lpSetTimeCode);

Enables or disables timecode recording for a VCR. VCR devices recognize this command.

•	Returns zero if successful or an error otherwise.

dwFlags

MCI_NOTIFY, MCI_WAIT, or MCI_TEST. For information about these flags, see Chapter 3, "MCI Overview."

lpSetTimeCode

Address of an MCI_GENERIC_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

Additional Flags

The following additional flag applies to VCR devices:

MCI_VCR_SETTIMECODE_RECORD

Sets the timecode track recording to on or off. This flag is used in combination with one of the following additional flags:

MCI_SET_ON

Timecode recording on.

MCI_SET_OFF

Timecode recording off.


MCI_SETTUNER

MCIERROR mciSendCommand(MCIDEVICEID wDeviceID, MCI_SETTUNER,
    DWORD dwFlags, (DWORD) (LPMCI_GENERIC_PARMS) lpSetTuner);

Sets the current channel on the tuner. VCR devices recognize this command.

•	Returns zero if successful or an error otherwise.

dwFlags

MCI_NOTIFY, MCI_WAIT, or MCI_TEST. For information about these flags, see Chapter 3, "MCI Overview."

lpSetTuner

Address of an MCI_VCR_SETTUNER_PARMS structure.

Additional Flags

The following additional flags apply to VCR devices:

MCI_VCR_SETTUNER_CHANNEL

The dwChannel member of the structure identified by lpSetTuner contains the new channel number.

MCI_VCR_SETTUNER_CHANNEL_DOWN

Decrements the tuner channel.

MCI_VCR_SETTUNER_CHANNEL_SEEK_DOWN

Searches for a valid channel in the reverse direction.

MCI_VCR_SETTUNER_CHANNEL_SEEK_UP

Searches for a valid channel in the forward direction.

MCI_VCR_SETTUNER_CHANNEL_UP

Increments the tuner channel.

MCI_VCR_SETTUNER_NUMBER

The dwNumber member of the structure identified by lpSetTuner specifies which logical tuner to affect with this command.


MCI_SETVIDEO

MCIERROR mciSendCommand(MCIDEVICEID wDeviceID, MCI_SETVIDEO,
    DWORD dwFlags, (DWORD) (LPMCI_GENERIC_PARMS) lpSetVideo);

Sets values associated with video playback. Digital-video and VCR devices recognize this command.

•	Returns zero if successful or an error otherwise.

dwFlags

MCI_NOTIFY, MCI_WAIT, or MCI_TEST. For information about these flags, see Chapter 3, "MCI Overview."

lpSetVideo

Address of an MCI_GENERIC_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

Digital-Video Flags

The following additional flags are used with the digitalvideo device type:

MCI_DGV_SETVIDEO_ALG

The lpstrAlgorithm member of the structure identified by lpSetVideo contains an address of a buffer containing the name of a video compression algorithm. The compression algorithm is used by subsequent MCI_RESERVE or MCI_RECORD commands. The available algorithms are device dependent.

If the specified algorithm is incompatible with the current file format, the file format is changed to the default format for the algorithm.

MCI_DGV_SETVIDEO_CLOCKTIME

When used with MCI_DGV_SETVIDEO_OVER, indicates time is specified in milliseconds and is absolute time. (This time is not in step with the playing of the workspace.)

MCI_DGV_SETVIDEO_INPUT

Modifies the MCI_DGV_SETVIDEO_BRIGHTNESS, MCI_DGV_SETVIDEO_COLOR, MCI_DGV_SETVIDEO_CONTRAST, MCI_DGV_SETVIDEO_GAMMA, MCI_DGV_SETVIDEO_SHARPNESS, or MCI_DGV_SETVIDEO_TINT so that it affects the input signal and modifies what is recorded. If possible, this is the default when monitoring the input.

MCI_DGV_SETVIDEO_ITEM

A video constant is specified in the dwItem member of the structure identified by lpSetVideo. The constant identifies the value that is being set. You can specify the following constants with this flag:

MCI_AVI_SETVIDEO_DRAW_PROCEDURE

A new drawing procedure address is specified in the dwValue member of the structure identified by lpSetVideo. You can specify a new drawing procedure only when the device is idle. This flag is recognized only by the MCIAVI digital-video driver. There is no equivalent to this flag in the string command interface.

MCI_AVI_SETVIDEO_PALETTE_COLOR

A new palette color is specified in the dwOver and dwValue members of the structure identified by lpSetVideo. The dwOver member specifies the palette index of the color to be changed and the dwValue member specifies the new color, as an RGB value. You must also specify the MCI_DGV_SETVIDEO_OVER and MCI_DGV_SETVIDEO_VALUE flags with MCI_DGV_SETVIDEO_ITEM when you use this constant. This flag is recognized only by the MCIAVI digital-video driver.

MCI_AVI_SETVIDEO_PALETTE_HALFTONE

Indicates that the halftone palette should be used, instead of the default palette. This flag is recognized only by the MCIAVI digital-video driver.

MCI_DGV_SETVIDEO_BITSPERPEL

The number of bits per pixel is specified in the dwValue member of the structure identified by lpSetVideo. The number of bits per pixel is used for saving captured or recorded data

MCI_DGV_SETVIDEO_BRIGHTNESS

The video brightness level is specified as a factor in the dwValue member of the structure identified by lpSetVideo.

MCI_DGV_SETVIDEO_COLOR

The video color saturation level is specified as a factor in the dwValue member of the structure identified by lpSetVideo.

MCI_DGV_SETVIDEO_CONTRAST

The video contrast level is specified as a factor in the dwValue member of the structure identified by lpSetVideo.

MCI_DGV_SETVIDEO_FRAME_RATE

A frame rate is specified in the dwValue member of the structure identified by lpSetVideo. The rate is specified in units of frames per second times 1000. For example, 29.97 frames per second is specified as 29970.

MCI_DGV_SETVIDEO_GAMMA

A gamma correction exponent value is specified in the dwValue member of the structure identified by lpSetVideo. Gamma correction adjusts the mapping between the intensity encoded in the presentation source and the displayed brightness. The value is the exponent multiplied by 1000. For example, 2200 indicates an exponent of 2.2. A value of 1000 indicates an exponent of 1, which applies no gamma correction.

MCI_DGV_SETVIDEO_KEY_COLOR

A key color is specified in the dwValue member of the structure identified by lpSetVideo. The key color is a Windows RGB value.

MCI_DGV_SETVIDEO_KEY_INDEX

A key index value is specified in the dwValue member of the structure identified by lpSetVideo. The index parameter is a physical palette index.

MCI_DGV_SETVIDEO_PALHANDLE

A palette handle is specified in the dwValue member of the structure identified by lpSetVideo. The palette handle is contained in the low-order word. Digital-video devices should not free the palette passed with this command. Applications should free it after they close the device. This flag is supported only by devices that use palettes. If this specified palette handle is zero, then the default palette is used.

MCI_DGV_SETVIDEO_SHARPNESS

A video sharpness value is specified as a factor in the dwValue member of the structure identified by lpSetVideo.

MCI_DGV_SETVIDEO_SOURCE

A constant specifying the source of the video input is specified in the dwValue member of the structure identified by lpSetVideo. The following constants are defined:

MCI_DGV_SETVIDEO_SRC_NTSC

Specifies NTSC.

MCI_DGV_SETVIDEO_SRC_PAL

Specifies PAL.

MCI_DGV_SETVIDEO_SRC_RGB

Specifies RGB.

MCI_DGV_SETVIDEO_SRC_SECAM

Specifies SECAM.

MCI_DGV_SETVIDEO_SRC_SVIDEO

Specifies SVIDEO.

MCI_DGV_SETVIDEO_STREAM

A video stream is specified in the dwValue member of the structure identified by lpSetVideo. The integer value specifies the video stream played back from the workspace. If the stream is not specified and the file format does not define a default stream, the first physically interleaved video stream is played.

MCI_DGV_SETVIDEO_TINT

A video tint value is specified as a factor in the dwValue member of the structure identified by lpSetVideo. Typically, this adjustment is modeled after the tint control of many color television sets, with 250 defined as green, 750 defined as red, and 0 (or 1000) defined as blue. The nominal value is always 500.

MCI_DGV_SETVIDEO_OUTPUT

The MCI_DGV_SETVIDEO_BRIGHTNESS, MCI_DGV_SETVIDEO_COLOR, MCI_DGV_SETVIDEO_CONTRAST, MCI_DGV_SETVIDEO_GAMMA, MCI_DGV_SETVIDEO_SHARPNESS, or MCI_DGV_SETVIDEO_TINT flag is modified so that it affects only the displayed signal and not what is recorded. If possible, this is the default when monitoring a file.

MCI_DGV_SETVIDEO_OVER

A transition length parameter is included in the dwOver member of the structure identified by lpSetVideo. The transition length specifies how long (in the current time format) it should take to make a change. If this flag is not used, the change occurs immediately.

MCI_DGV_SETVIDEO_QUALITY

The lpstrQuality member of the structure identified by lpSetVideo contains an address of a buffer describing the video quality. A text-string in the buffer specifies the characteristics of the video compression algorithm.

The MCI_DGV_SETVIDEO_ALG flag can be used to select a quality descriptor for the specified algorithm. If this flag is omitted, then the current algorithm is used.

The algorithms and descriptor names available depend on the device. Each device supplies documentation for the available algorithms and a description of the applicable descriptor names. The MCI_QUALITY command can define additional descriptor names. All devices support the descriptors "low", "medium", and "high". The default is driver specific.

MCI_DGV_SETVIDEO_RECORD

Specifies whether recording includes or excludes video data. When combined with MCI_SET_ON, video data is recorded. When combined with MCI_SET_OFF, video data is excluded. The default includes video data.

MCI_DGV_SETVIDEO_SRC_NUMBER

A number for the video source is specified in the dwSourceNumber member of the structure identified by lpSetVideo. If there is more than one input of the type specified by MCI_DGV_SETVIDEO_VALUE, the value selects the input. This flag must always be used with MCI_DGV_SETVIDEO_SOURCE. If MCI_DGV_SETVIDEO_VALUE is omitted, however, the specified source number indicates the absolute source to use as specified in the MCI_LIST command.

MCI_DGV_SETVIDEO_STILL

The algorithm name or quality value specified applies to still images.

Every device driver must support an algorithm of "none", which means no compression. This is the default. In this case, digital-video devices save still images as RGB format device-independent bitmaps (DIBs).

MCI_DGV_SETVIDEO_VALUE

A value is included in the dwValue member of the structure identified by lpSetVideo. The meaning of the value is specified by the MCI_DGV_SETVIDEO_ITEM flag.

MCI_SET_OFF

Disables video output. For digital-video devices, disabling video sets the pixels in the destination rectangle defined by the MCI_PUT command (or its default, the client region of the current window) to a solid color, but it has no effect on the frame buffer. You can hide the window with the MCI_WINDOW command if desired. The source of video, whether it's the workspace or an external input, might continue to store new images in the frame buffer, but they are not displayed until the video is enabled. While applications should use the MCI_SETVIDEO command to control this function, digital-video devices must still support this flag. The default value after an open is on.

MCI_SET_ON

Enables video output.

For digital-video devices, the lpSetVideo parameter points to an MCI_DGV_SETVIDEO_PARMS structure.

VCR Flags

The following additional flags are used with the vcr device type:

MCI_VCR_SETVIDEO_RECORD

Sets the video recording to on or off. Used in conjunction with one of following flags:

MCI_SET_ON

Video recording on.

MCI_SET_OFF

Video recording off. It might be necessary to first turn off the assemble recording (using the MCI_SET command with the MCI_VCR_SET_ASSEMBLE_RECORD flag set to off) before the video recording can be turned off.

MCI_TRACK

The dwTrack member of the structure identified by lpSetVideo specifies which track is affected by the command.

MCI_VCR_SETVIDEO_SOURCE

Sets the video source, and must be used with the MCI_VCR_SETVIDEO_TO flag.

MCI_VCR_SETVIDEO_MONITOR

Sets the video source monitor, and must be used with the MCI_VCR_SETVIDEO_TO flag.

MCI_VCR_SETVIDEO_TO

The dwTo member of the structure identified by lpSetVideo contains one of the following constants:

MCI_VCR_SRC_TYPE_TUNER
MCI_VCR_SRC_TYPE_LINE
MCI_VCR_SRC_TYPE_AUX
MCI_VCR_SRC_TYPE_GENERIC
MCI_VCR_SRC_TYPE_MUTE
MCI_VCR_SRC_TYPE_OUTPUT
MCI_VCR_SRC_TYPE_RGB

MCI_VCR_SETVIDEO_NUMBER

The dwNumber member of the structure identified by lpSetVideo contains the video input (of the type specified in the dwTo member) to use.

For VCR devices, the lpSetVideo parameter points to an MCI_VCR_SETVIDEO_PARMS structure.


MCI_SIGNAL

MCIERROR mciSendCommand(MCIDEVICEID wDeviceID, MCI_SIGNAL,
    DWORD dwFlags, (DWORD) (LPMCI_DGV_SIGNAL_PARMS) lpSignal);

Sets a specified position in the workspace. Digital-video devices recognize this command. MCIAVI supports only one active signal at a time.

•	Returns zero if successful or an error otherwise.

dwFlags

MCI_NOTIFY, MCI_WAIT, or MCI_TEST. For information about these flags, see Chapter 3, "MCI Overview."

lpSignal

Address of an MCI_DGV_SIGNAL_PARMS structure.

Additional Flags

The following flags apply to digital-video devices:

MCI_DGV_SIGNAL_AT

A signal position is included in the dwPosition member of the structure identified by lpSignal.

MCI_DGV_SIGNAL_CANCEL

Removes the signal position specified by the value associated with MCI_DGV_SIGNAL_USERVAL.

MCI_DGV_SIGNAL_EVERY

A signal-period value is included in the dwEvery member of the structure identified by lpSignal.

MCI_DGV_SIGNAL_POSITION

The device will send the position value with the Windows message instead of the user-specified value.

MCI_DGV_SIGNAL_USERVAL

A data value is included in the dwUserParm member of the structure identified by lpSignal. The data value associated with this request is reported back with the Windows message.


MCI_SPIN

MCIERROR mciSendCommand(MCIDEVICEID wDeviceID, MCI_SPIN,
    DWORD dwFlags, (DWORD) (LPMCI_GENERIC_PARMS) lpSpin);

Starts the device spinning up or down. Videodisc devices recognize this command.

•	Returns zero if successful or an error otherwise.

dwFlags

MCI_NOTIFY or MCI_WAIT. For information about these flags, see Chapter 3, "MCI Overview."

lpSpin

Address of an MCI_GENERIC_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

Additional Flags

The following additional flags apply to videodisc devices:

MCI_VD_SPIN_DOWN

Stops the disc spinning.

MCI_VD_SPIN_UP

Starts the disc spinning.


MCI_STATUS

MCIERROR mciSendCommand(MCIDEVICEID wDeviceID, MCI_STATUS,
    DWORD dwFlags, (DWORD) (LPMCI_STATUS_PARMS) lpStatus);

Retrieves information about an MCI device. All devices recognize this command. Information is returned in the dwReturn member of the structure identified by the lpStatus parameter.

•	Returns zero if successful or an error otherwise.

dwFlags

MCI_NOTIFY, MCI_WAIT, or, for digital-video and VCR devices, MCI_TEST. For information about these flags, see Chapter 3, "MCI Overview."

lpStatus

Address of an MCI_STATUS_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

Additional Flags

The following additional standard and command-specific flags apply to all devices supporting MCI_STATUS:

MCI_STATUS_ITEM

Specifies that the dwItem member of the structure identified by lpStatus contains a constant specifying which status item to obtain. The following constants define which status item to return in the dwReturn member of the structure:

MCI_STATUS_CURRENT_TRACK

The dwReturn member is set to the current track number. MCI uses continuous track numbers.

MCI_STATUS_LENGTH

The dwReturn member is set to the total media length.

MCI_STATUS_MODE

The dwReturn member is set to the current mode of the device. The modes include the following:

MCI_MODE_NOT_READY

MCI_MODE_PAUSE

MCI_MODE_PLAY

MCI_MODE_STOP

MCI_MODE_OPEN

MCI_MODE_RECORD

MCI_MODE_SEEK

MCI_STATUS_NUMBER_OF_TRACKS

The dwReturn member is set to the total number of playable tracks.

MCI_STATUS_POSITION

The dwReturn member is set to the current position.

MCI_STATUS_READY

The dwReturn member is set to TRUE if the device is ready; it is set to FALSE otherwise.

MCI_STATUS_TIME_FORMAT

The dwReturn member is set to the current time format of the device. The time formats include:

MCI_FORMAT_BYTES

MCI_FORMAT_FRAMES

MCI_FORMAT_HMS

MCI_FORMAT_MILLISECONDS

MCI_FORMAT_MSF

MCI_FORMAT_SAMPLES

MCI_FORMAT_TMSF

MCI_STATUS_START

Obtains the starting position of the media. To get the starting position, combine this flag with MCI_STATUS_ITEM and set the dwItem member of the structure identified by lpStatus to MCI_STATUS_POSITION.

MCI_TRACK

Indicates a status track parameter is included in the dwTrack member of the structure identified by lpStatus. You must use this flag with the MCI_STATUS_POSITION or MCI_STATUS_LENGTH constants. When used with MCI_STATUS_POSITION, MCI_TRACK obtains the starting position of the specified track. When used with MCI_STATUS_LENGTH, MCI_TRACK obtains the length of the specified track. MCI uses continuous track numbers.

Animation Flags

The following additional flags are used with the animation device type. These constants are used in the dwItem member of the structure pointed to by the lpStatus parameter when MCI_STATUS_ITEM is specified for the dwFlags parameter.

MCI_ANIM_STATUS_FORWARD

The dwReturn member is set to TRUE if playing forward; it is set to FALSE otherwise.

MCI_ANIM_STATUS_HPAL

The dwReturn member is set to the handle of the movie palette.

MCI_ANIM_STATUS_HWND

The dwReturn member is set to the handle of the playback window.

MCI_ANIM_STATUS_SPEED

The dwReturn member is set to the animation speed.

MCI_ANIM_STATUS_STRETCH

The dwReturn member is set to TRUE if stretching is enabled; it is set to FALSE otherwise.

MCI_STATUS_MEDIA_PRESENT

The dwReturn member is set to TRUE if the media is inserted in the device; it is set to FALSE otherwise.

CD Audio Flags

The following additional flags are used with the cdaudio device type. These constants are used in the dwItem member of the structure pointed to by the lpStatus parameter when MCI_STATUS_ITEM is specified for the dwFlags parameter.

MCI_CDA_STATUS_TYPE_TRACK

The dwReturn member is set to one of the following values:

MCI_CDA_TRACK_AUDIO
MCI_CDA_TRACK_OTHER

To use this flag, the MCI_TRACK flag must be set, and the dwTrack member of the structure identified by lpStatus must contain a valid track number.

MCI_STATUS_MEDIA_PRESENT

The dwReturn member is set to TRUE if the media is inserted in the device; it is set to FALSE otherwise.

Digital-Video Flags

The following additional flags are used with the digitalvideo device type:

MCI_DGV_STATUS_DISKSPACE

The lpstrDrive member of the structure identified by lpStatus specifies a disk drive or, in some implementations, a path. The MCI_STATUS command returns the approximate amount of disk space that could be obtained by the MCI_RESERVE command in the dwReturn member of the structure identified by lpStatus. The disk space is measured in units of the current time format.

MCI_DGV_STATUS_INPUT

The constant specified by the dwItem member of the structure identified by lpStatus applies to the input.

MCI_DGV_STATUS_LEFT

The constant specified by the dwItem member of the structure identified by lpStatus applies to the left audio channel.

MCI_DGV_STATUS_NOMINAL

The constant specified by the dwItem member of the structure identified by lpStatus requests the nominal value rather than the current value.

MCI_DGV_STATUS_OUTPUT

The constant specified by the dwItem member of the structure identified by lpStatus applies to the output.

MCI_DGV_STATUS_RECORD

The frame rate returned for the MCI_DGV_STATUS_FRAME_RATE flag is the rate used for compression.

MCI_DGV_STATUS_REFERENCE

The dwReturn member of the structure identified by lpStatus returns the nearest key-frame image that precedes the frame specified in the dwReference member.

MCI_DGV_STATUS_RIGHT

The constant specified by the dwItem member of the structure identified by lpStatus applies to the right audio channel.

The following constants are used with the digitalvideo device type in the dwItem member of the structure pointed to by the lpStatus parameter when MCI_STATUS_ITEM is specified for the dwFlags parameter.

MCI_AVI_STATUS_AUDIO_BREAKS

The dwReturn member returns the number of times the audio portion of the last AVI sequence broke up. The system counts an audio break whenever it attempts to write audio data to the device driver and discovers that the driver has already played all of the available data. This flag is recognized only by the MCIAVI digital-video driver.

MCI_AVI_STATUS_FRAMES_SKIPPED

The dwReturn member returns the number of frames that were not drawn when the last AVI sequence was played. This flag is recognized only by the MCIAVI digital-video driver.

MCI_AVI_STATUS_LAST_PLAY_SPEED

The dwReturn member returns a value representing how closely the actual playing time of the last AVI sequence matched the target playing time. The value 1000 indicates that the target time and the actual time were the same. A value of 2000, for example, would indicate that the AVI sequence took twice as long to play as it should have. This flag is recognized only by the MCIAVI digital-video driver.

MCI_DGV_STATUS_AUDIO

The dwReturn member returns MCI_ON or MCI_OFF depending on the most recent MCI_SET_AUDIO option for the MCI_SET command. It returns MCI_ON if either or both speakers are enabled, and MCI_OFF otherwise.

MCI_DGV_STATUS_AUDIO_INPUT

The dwReturn member returns the approximate instantaneous audio level of the analog audio signal. A value greater than 1000 implies there is clipping distortion. Some devices can determine this value only while recording audio. This status value has no associated MCI_SET or MCI_SETAUDIO command. This value is related to, but normalized differently from, the waveform-audio command MCI_WAVE_STATUS_LEVEL.

MCI_DGV_STATUS_AUDIO_RECORD

The dwReturn member returns MCI_ON or MCI_OFF reflecting the state set by the MCI_DGV_SETAUDIO_RECORD flag of the MCI_SETAUDIO command.

MCI_DGV_STATUS_AUDIO_SOURCE

The dwReturn member returns the current audio digitizer source:

MCI_DGV_SETAUDIO_AVERAGE

Specifies the average of the left and right audio channels.

MCI_DGV_SETAUDIO_LEFT

Specifies the left audio channel.

MCI_DGV_SETAUDIO_RIGHT

Specifies the right audio channel.

MCI_DGV_SETAUDIO_STEREO

Specifies stereo.

MCI_DGV_STATUS_AUDIO_STREAM

The dwReturn member returns the current audio-stream number.

MCI_DGV_STATUS_AVGBYTESPERSEC

The dwReturn member returns the average number of bytes per second used for recording.

MCI_DGV_STATUS_BASS

The dwReturn member returns the current audio bass level. Use MCI_DGV_STATUS_NOMINAL with this flag to obtain the nominal level.

MCI_DGV_STATUS_BITSPERPEL

The dwReturn member returns the number of bits per pixel used for saving captured or recorded data.

MCI_DGV_STATUS_BITSPERSAMPLE

The dwReturn member returns the number of bits per sample the device uses for recording. This applies only to devices supporting the PCM format.

MCI_DGV_STATUS_BLOCKALIGN

The dwReturn member returns the alignment of data blocks relative to the start of the input waveform.

MCI_DGV_STATUS_BRIGHTNESS

The dwReturn member returns the current video brightness level. Use MCI_DGV_STATUS_NOMINAL with this flag to obtain the nominal level.

MCI_DGV_STATUS_COLOR

The dwReturn member returns the current color level. Use MCI_DGV_STATUS_NOMINAL with this flag to obtain the nominal level.

MCI_DGV_STATUS_CONTRAST

The dwReturn member returns the current contrast level. Use MCI_DGV_STATUS_NOMINAL with this flag to obtain the nominal level.

MCI_DGV_STATUS_FILEFORMAT

The dwReturn member returns the current file format for recording or saving.

MCI_DGV_STATUS_FILE_MODE

The dwReturn member returns the state of the file operation:

MCI_DGV_FILE_MODE_EDITING

Returned during cut, copy, delete, paste, and undo operations.

MCI_DGV_FILE_MODE_IDLE

Returned when the file is ready for the next operation.

MCI_DGV_FILE_MODE_LOADING

Returned while the file is being loaded.

MCI_DGV_FILE_MODE_SAVING

Returned while the file is being saved.

MCI_DGV_STATUS_FILE_COMPLETION

The dwReturn member returns the estimated percentage a load, save, capture, cut, copy, delete, paste, or undo operation has progressed. (Applications can use this to provide a visual indicator of progress.) This flag is not supported by all digital-video devices.

MCI_DGV_STATUS_FORWARD

The dwReturn member returns TRUE if the device direction is forward or the device is not playing.

MCI_DGV_STATUS_FRAME_RATE

The dwReturn member must be used with MCI_DGV_STATUS_NOMINAL, MCI_DGV_STATUS_RECORD, or both. When used with MCI_DGV_STATUS_RECORD, the current frame rate used for recording is returned. When used with both MCI_DGV_STATUS_RECORD and MCI_DGV_STATUS_NOMINAL, the nominal frame rate associated with the input video signal is returned. When used with MCI_DGV_STATUS_NOMINAL, the nominal frame rate associated with the file is returned. In all cases the units are in frames per second multiplied by 1000.

MCI_DGV_STATUS_GAMMA

The dwReturn member returns the current gamma value. Use MCI_DGV_STATUS_NOMINAL with this flag to obtain the nominal level.

MCI_DGV_STATUS_HPAL

The dwReturn member returns the ASCII decimal value for the current palette handle. The handle is contained in the low-order word of the returned value.

MCI_DGV_STATUS_HWND

The dwReturn member returns the ASCII decimal value for the current explicit or default window handle associated with this device driver instance. The handle is contained in the low-order word of the returned value.

MCI_DGV_STATUS_KEY_COLOR

The dwReturn member returns the current key-color value.

MCI_DGV_STATUS_KEY_INDEX

The dwReturn member returns the current key-index value.

MCI_DGV_STATUS_MONITOR

The dwReturn member returns a constant indicating the source of the current presentation. The following constants are defined:

MCI_DGV_MONITOR_FILE

A file is the source.

MCI_DGV_MONITOR_INPUT

The input is the source.

MCI_DGV_STATUS_MONITOR_METHOD

The dwReturn member returns a constant indicating the method used for input monitoring. The following constants are defined:

MCI_DGV_METHOD_DIRECT

Direct input monitoring.

MCI_DGV_METHOD_POST

Post-input monitoring.

MCI_DGV_METHOD_PRE

Pre-input monitoring.

MCI_DGV_STATUS_PAUSE_MODE

The dwReturn member returns MCI_MODE_PLAY if the device was paused while playing and returns MCI_MODE_RECORD if the device was paused while recording. The command returns MCIERR_NONAPPLICABLE_FUNCTION as an error return if the device is not paused.

MCI_DGV_STATUS_SAMPLESPERSECOND

The dwReturn member returns the number of samples per second recorded.

MCI_DGV_STATUS_SEEK_EXACTLY

The dwReturn member returns TRUE or FALSE indicating whether or not the seek exactly format is set. (Applications can set this format by using the MCI_SET command with the MCI_DGV_SET_SEEK_EXACTLY flag.)

MCI_DGV_STATUS_SHARPNESS

The dwReturn member returns the current sharpness level. Use MCI_DGV_STATUS_NOMINAL with this flag to obtain the nominal level.

MCI_DGV_STATUS_SIZE

The dwReturn member returns the approximate playback duration of compressed data that the reserved workspace will hold. The duration units are in the current time format. It returns zero if there is no reserved disk space. The size returned is approximate since the precise disk space for compressed data cannot, in general, be predicted until after the data has been compressed.

MCI_DGV_STATUS_SMPTE

The dwReturn member returns the SMPTE time code associated with the current position in the workspace.

MCI_DGV_STATUS_SPEED

The dwReturn member returns the current playback speed.

MCI_DGV_STATUS_STILL_FILEFORMAT

The dwReturn member returns the current file format for the MCI_CAPTURE command.

MCI_DGV_STATUS_TINT

The dwReturn member returns the current video tint level. Use MCI_DGV_STATUS_NOMINAL with this flag to obtain the nominal level.

MCI_DGV_STATUS_TREBLE

The dwReturn member returns the current audio treble level. Use MCI_DGV_STATUS_NOMINAL with this flag to obtain the nominal level.

MCI_DGV_STATUS_UNSAVED

The dwReturn member returns TRUE if there is recorded data in the workspace that might be lost as a result of a MCI_CLOSE, MCI_LOAD, MCI_RECORD, MCI_RESERVE, MCI_CUT, MCI_DELETE, or MCI_PASTE command. The member returns FALSE otherwise.

MCI_DGV_STATUS_VIDEO

The dwReturn member returns MCI_ON if video is enabled or MCI_OFF if it is disabled.

MCI_DGV_STATUS_VIDEO_RECORD

The dwReturn member returns MCI_ON or MCI_OFF, reflecting the state set by the MCI_DGV_SETVIDEO_RECORD flag of the MCI_SETVIDEO command.

MCI_DGV_STATUS_VIDEO_SOURCE

The dwReturn member returns a constant indicating the type of video source set by the MCI_DGV_SETVIDEO_SOURCE flag of the MCI_SETVIDEO command.

MCI_DGV_STATUS_VIDEO_SRC_NUM

The dwReturn member returns the number within its type of the video-input source currently active.

MCI_DGV_STATUS_VIDEO_STREAM

The dwReturn member returns the current video-stream number.

MCI_DGV_STATUS_VOLUME

The dwReturn member returns the average of the volume to the left and right speakers. Use MCI_DGV_STATUS_NOMINAL with this flag to obtain the nominal level.

MCI_DGV_STATUS_WINDOW_VISIBLE

The dwReturn member returns TRUE if the window is not hidden.

MCI_DGV_STATUS_WINDOW_MINIMIZED

The dwReturn member returns TRUE if the window is minimized.

MCI_DGV_STATUS_WINDOW_MAXIMIZED

The dwReturn member returns TRUE if the window is maximized.

MCI_STATUS_MEDIA_PRESENT

The dwReturn member returns TRUE.

For digital-video devices, the lpStatus parameter points to an MCI_DGV_STATUS_PARMS structure.

Sequencer Flags

The following additional flags are used with the sequencer device type. These constants are used in the dwItem member of the structure pointed to by the lpStatus parameter when MCI_STATUS_ITEM is specified for the dwFlags parameter.

MCI_SEQ_STATUS_DIVTYPE

The dwReturn member is set to one of the following values indicating the current division type of a sequence:

MCI_SEQ_DIV_PPQN

MCI_SEQ_DIV_SMPTE_24

MCI_SEQ_DIV_SMPTE_25

MCI_SEQ_DIV_SMPTE_30

MCI_SEQ_DIV_SMPTE_30DROP

MCI_SEQ_STATUS_MASTER

The dwReturn member is set to the synchronization type used for master operation.

MCI_SEQ_STATUS_OFFSET

The dwReturn member is set to the current SMPTE offset of a sequence.

MCI_SEQ_STATUS_PORT

The dwReturn member is set to the MIDI device identifier for the current port used by the sequence.

MCI_SEQ_STATUS_SLAVE

The dwReturn member is set to the synchronization type used for slave operation.

MCI_SEQ_STATUS_TEMPO

The dwReturn member is set to the current tempo of a MIDI sequence in beats per minute for PPQN files, or frames per second for SMPTE files.

MCI_STATUS_MEDIA_PRESENT

The dwReturn member is set to TRUE if the media is inserted in the device; it is set to FALSE otherwise.

VCR Flags

The following additional flags are used with the vcr device type. These constants are used in the dwItem member of the structure pointed to by the lpStatus parameter when MCI_STATUS_ITEM is specified for the dwFlags parameter.

MCI_STATUS_MEDIA_PRESENT

The dwReturn member is set to TRUE if the media is inserted in the device; it is set to FALSE otherwise.

MCI_VCR_STATUS_ASSEMBLE_RECORD

The dwReturn member is set to TRUE if assemble mode is on; it is set to FALSE otherwise.

MCI_VCR_STATUS_AUDIO_MONITOR

The dwReturn member is set to a constant, indicating the currently selected audio-monitor type.

MCI_VCR_STATUS_AUDIO_MONITOR_NUMBER

The dwReturn member is set to the number of the currently selected audio-monitor type.

MCI_VCR_STATUS_AUDIO_RECORD

The dwReturn member is set to TRUE if audio will be recorded when the next record command is given; it is set to FALSE otherwise. If you specify MCI_TRACK in the dwFlags parameter of this command, dwTrack contains the track this inquiry applies to.

MCI_VCR_STATUS_AUDIO_SOURCE

The dwReturn member is set to a constant, indicating the current audio-source type.

MCI_VCR_STATUS_AUDIO_SOURCE_NUMBER

The dwReturn member is set to the number of the currently selected audio-source type.

MCI_VCR_STATUS_CLOCK

The dwReturn member is set to the current clock value, in total clock increments.

MCI_VCR_STATUS_CLOCK_ID

The dwReturn member is set to a number which uniquely describes the clock in use.

MCI_VCR_STATUS_COUNTER_FORMAT

The dwReturn member is set to a constant describing the current counter format. For more information, see the MCI_SET_TIME_FORMAT flag of the MCI_SET command.

MCI_VCR_STATUS_COUNTER_RESOLUTION

The dwReturn member is set to a constant describing the resolution of the counter, and is one of the following values:

MCI_VCR_COUNTER_RES_FRAMES

Counter has resolution of frames.

MCI_VCR_COUNTER_RES_SECONDS

Counter has resolution of seconds.

MCI_VCR_STATUS_COUNTER_VALUE

The dwReturn member is set to the current counter reading, in the current counter-time format.

MCI_VCR_STATUS_FRAME_RATE

The dwReturn member is set to the current native frame rate of the device.

MCI_VCR_STATUS_INDEX

The dwReturn member is set to a constant, describing the current contents of the on-screen display, and is one of the following:

MCI_VCR_INDEX_COUNTER

MCI_VCR_INDEX_DATE

MCI_VCR_INDEX_TIME

MCI_VCR_INDEX_TIMECODE

MCI_VCR_STATUS_INDEX_ON

The dwReturn member is set to TRUE if the on-screen display is on; it is set to FALSE otherwise.

MCI_VCR_STATUS_MEDIA_TYPE

The dwReturn member is set to one of the following:

MCI_VCR_MEDIA_8MM

MCI_VCR_MEDIA_HI8

MCI_VCR_MEDIA_VHS

MCI_VCR_MEDIA_SVHS

MCI_VCR_MEDIA_BETA

MCI_VCR_MEDIA_EDBETA

MCI_VCR_MEDIA_OTHER

MCI_VCR_STATUS_NUMBER

The dwNumber member is set to the logical-tuner number when you use this flag with the MCI_VCR_STATUS_TUNER_CHANNEL flag.

MCI_VCR_STATUS_NUMBER_OF_AUDIO_TRACKS

The dwReturn member is set to the number of audio tracks that are independently selectable.

MCI_VCR_STATUS_NUMBER_OF_VIDEO_TRACKS

The dwReturn member is set to the number of video tracks that are independently selectable.

MCI_VCR_STATUS_PAUSE_TIMEOUT

The dwReturn member is set to the maximum duration, in milliseconds, of a pause command. The return value of zero indicates that no time-out will occur.

MCI_VCR_STATUS_PLAY_FORMAT

The dwReturn member is set to one of the following:

MCI_VCR_FORMAT_EP

MCI_VCR_FORMAT_LP

MCI_VCR_FORMAT_OTHER

MCI_VCR_FORMAT_SP

MCI_VCR_STATUS_POSTROLL_DURATION

The dwReturn member is set to the length of the videotape that will play after the spot at which it was stopped, in the current time format. This is needed to brake the VCR tape transport from a stop or pause command.

MCI_VCR_STATUS_POWER_ON

The dwReturn member is set to TRUE if the power is on; it is set to FALSE otherwise.

MCI_VCR_STATUS_PREROLL_DURATION

The dwReturn member is set to the length of the videotape that will play before the spot at which it was started, in the current time format. This is needed to stabilize the VCR output.

MCI_VCR_STATUS_RECORD_FORMAT

The dwReturn member is set to one of the following:

MCI_VCR_FORMAT_EP

MCI_VCR_FORMAT_LP

MCI_VCR_FORMAT_OTHER

MCI_VCR_FORMAT_SP

MCI_VCR_STATUS_SPEED

The dwReturn member is set to the current speed. For more information, see the MCI_VCR_SET_SPEED flag of the MCI_SET command.

MCI_VCR_STATUS_TIME_MODE

The dwReturn member is set to one of the following:

MCI_VCR_TIME_COUNTER

MCI_VCR_TIME_DETECT

MCI_VCR_TIME_TIMECODE

For more information, see the MCI_VCR_SET_TIME_MODE flag of the MCI_SET command.

MCI_VCR_STATUS_TIME_TYPE

The dwReturn member is set to a constant describing the current time type in use (used by play, record, seek, and so on), and is one of the following:

MCI_VCR_TIME_COUNTER

Counter is in use.

MCI_VCR_TIME_TIMECODE

Timecode is in use.

MCI_VCR_STATUS_TIMECODE_PRESENT

The dwReturn member is set to TRUE if timecode is present at the current position in the content; it is set to FALSE otherwise.

MCI_VCR_STATUS_TIMECODE_RECORD

The dwReturn member is set to TRUE if the timecode will be recorded when the next record command is given; it is set to FALSE otherwise.

MCI_VCR_STATUS_TIMECODE_TYPE

The dwReturn member is set to a constant, describing the type of timecode that is directly supported by the device, and is one of the following:

MCI_VCR_TIMECODE_TYPE_NONE

This device does not use a timecode.

MCI_VCR_TIMECODE_TYPE_OTHER

This device uses an unspecified timecode.

MCI_VCR_TIMECODE_TYPE_SMPTE

This device uses SMPTE timecode.

MCI_VCR_TIMECODE_TYPE_SMPTE_DROP

This device uses SMPTE drop timecode.

MCI_VCR_STATUS_TUNER_CHANNEL

The dwReturn member is set to the current channel number. If you specify MCI_VCR_STATUS_NUMBER in the dwFlags parameter of this command, dwNumber contains the logical-tuner number this command applies to.

MCI_VCR_STATUS_VIDEO_MONITOR

The dwReturn member is set to a constant, indicating the currently selected video-monitor type.

MCI_VCR_STATUS_VIDEO_MONITOR_NUMBER

The dwReturn member is set to the number of the currently selected video-monitor type.

MCI_VCR_STATUS_VIDEO_RECORD

The dwReturn member is set to TRUE if video will be recorded when the next record command is given; it is set to FALSE otherwise. If you specify MCI_TRACK in the dwFlags parameter of this command, dwTrack contains the track this inquiry applies to.

MCI_VCR_STATUS_VIDEO_SOURCE

The dwReturn member is set to a constant indicating the currently selected video-source type.

MCI_VCR_STATUS_VIDEO_SOURCE_NUMBER

The dwReturn member is set to the number of the currently selected video-source type.

MCI_VCR_STATUS_WRITE_PROTECTED

The dwReturn member is set to TRUE if the media is write-protected; it is set to FALSE otherwise.

For VCR devices, the lpStatus parameter points to an MCI_VCR_STATUS_PARMS structure.

Using the MCI_STATUS_LENGTH flag to determine the length of the media always returns 2 hours for VCR devices, unless the length has been explicitly changed using the MCI_SET command.

Video-Overlay Flags

The following additional flags are used with the overlay device type. These constants are used in the dwItem member of the structure pointed to by the lpStatus parameter when MCI_STATUS_ITEM is specified for the dwFlags parameter.

MCI_OVLY_STATUS_HWND

The dwReturn member is set to the handle of the window associated with the video-overlay device.

MCI_OVLY_STATUS_STRETCH

The dwReturn member is set to TRUE if stretching is enabled; it is set to FALSE otherwise.

MCI_STATUS_MEDIA_PRESENT

The dwReturn member is set to TRUE if the media is inserted in the device; it is set to FALSE otherwise.

Videodisc Flags

The following additional flags are used with the videodisc device type. These constants are used in the dwItem member of the structure pointed to by the lpStatus parameter when MCI_STATUS_ITEM is specified for the dwFlags parameter.

MCI_STATUS_MEDIA_PRESENT

The dwReturn member is set to TRUE if the media is inserted in the device; it is set to FALSE otherwise.

MCI_STATUS_MODE

The dwReturn member is set to the current mode of the device. Videodisc devices can return the MCI_VD_MODE_PARK constant, in addition to the constants any device can return, as documented with the dwFlags parameter.

MCI_VD_STATUS_DISC_SIZE

The dwReturn member is set to the size of the loaded disc in inches (8 or 12).

MCI_VD_STATUS_FORWARD

The dwReturn member is set to TRUE if playing forward; it is set to FALSE otherwise.

The MCI videodisc device does not support this flag.

MCI_VD_STATUS_MEDIA_TYPE

The dwReturn member is set to the media type of the inserted media. The following media types can be returned:

MCI_VD_MEDIA_CAV

MCI_VD_MEDIA_CLV

MCI_VD_MEDIA_OTHER

MCI_VD_STATUS_SIDE

The dwReturn member is set to 1 or 2 to indicate which side of the disc is loaded. Not all videodisc devices support this flag.

MCI_VD_STATUS_SPEED

The dwReturn member is set to the play speed in frames per second. The MCIPIONR.DRV device driver returns MCIERR_UNSUPPORTED_FUNCTION.

Waveform-Audio Flags

The following additional flags are used with the waveaudio device type. These constants are used in the dwItem member of the structure pointed to by the lpStatus parameter when MCI_STATUS_ITEM is specified for the dwFlags parameter.

MCI_WAVE_FORMATTAG

The dwReturn member is set to the current format tag used for playing, recording, and saving.

MCI_WAVE_INPUT

The dwReturn member is set to the wave input device used for recording. If no device is in use and no device has been explicitly set, then the error return is MCIERR_WAVE_INPUTUNSPECIFIED.

MCI_WAVE_OUTPUT

The dwReturn member is set to the wave output device used for playing. If no device is in use and no device has been explicitly set, then the error return is MCIERR_WAVE_OUTPUTUNSPECIFIED.

MCI_WAVE_STATUS_AVGBYTESPERSEC

The dwReturn member is set to the current bytes per second used for playing, recording, and saving.

MCI_WAVE_STATUS_BITSPERSAMPLE

The dwReturn member is set to the current bits per sample used for playing, recording, and saving PCM formatted data.

MCI_WAVE_STATUS_BLOCKALIGN

The dwReturn member is set to the current block alignment used for playing, recording, and saving.

MCI_WAVE_STATUS_CHANNELS

The dwReturn member is set to the current channel count used for playing, recording, and saving.

MCI_WAVE_STATUS_LEVEL

The dwReturn member is set to the current record or playback level of PCM formatted data. The value is returned as an 8- or 16-bit value, depending on the sample size used. The right or mono channel level is returned in the low-order word. The left channel level is returned in the high-order word.

MCI_WAVE_STATUS_SAMPLESPERSEC

The dwReturn member is set to the current samples per second used for playing, recording, and saving.


MCI_STEP

MCIERROR mciSendCommand(MCIDEVICEID wDeviceID, MCI_STEP,
    DWORD dwFlags, (DWORD) (LPMCI_GENERIC_PARMS) lpStep);

Steps the player one or more frames. Animation, digital-video, VCR, and CAV-format videodisc devices recognize this command.

•	Returns zero if successful or an error otherwise.

dwFlags

MCI_NOTIFY, MCI_WAIT, or, for digital-video and VCR devices, MCI_TEST. For information about these flags, see Chapter 3, "MCI Overview."

lpStep

Address of an MCI_GENERIC_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

This command supports devices that return TRUE to the MCI_GETDEVCAPS_HAS_VIDEO flag of the MCI_GETDEVCAPS command.

Animation Flags

The following additional flags are used with the animation device type:

MCI_ANIM_STEP_FRAMES

The dwFrames member of the structure identified by lpStep specifies the number of frames to step.

MCI_ANIM_STEP_REVERSE

Steps in reverse.

For animation devices, the lpStep parameter points to an MCI_ANIM_STEP_PARMS structure.

Digital-Video Flags

The following additional flags are used with the digitalvideo device type:

MCI_DGV_STEP_FRAMES

The dwFrames member of the structure identified by lpStep specifies the number of frames to advance before displaying another image.

MCI_DGV_STEP_REVERSE

Steps in reverse.

For digital-video devices, the lpStep parameter points to an MCI_DGV_STEP_PARMS structure.

VCR Flags

The following additional flags are used with the vcr device type:

MCI_VCR_STEP_FRAMES

The dwFrames member of the structure identified by lpStep specifies the number of frames to advance before displaying another image.

MCI_VCR_STEP_REVERSE

Steps in reverse.

For VCR devices, the lpStep parameter points to an MCI_VCR_STEP_PARMS structure.

Videodisc Flags

The following additional flags are used with the videodisc device type:

MCI_VD_STEP_FRAMES

The dwFrames member of the structure identified by lpStep specifies the number of frames to step.

MCI_VD_STEP_REVERSE

Steps in reverse.

For videodisc devices, the lpStep parameter points to an MCI_VD_STEP_PARMS structure.


MCI_STOP

MCIERROR mciSendCommand(MCIDEVICEID wDeviceID, MCI_STOP,
    DWORD dwFlags, (DWORD) (LPMCI_GENERIC_PARMS) lpStop);

Stops all play and record sequences, unloads all play buffers, and ceases display of video images. Animation, CD audio, digital-video, MIDI sequencer, videodisc, VCR, and waveform-audio devices recognize this command.

•	Returns zero if successful or an error otherwise.

dwFlags

MCI_NOTIFY, MCI_WAIT, or, for digital-video and VCR devices, MCI_TEST. For information about these flags, see Chapter 3, "MCI Overview."

lpStop

Address of an MCI_GENERIC_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

The difference between the MCI_STOP and MCI_PAUSE commands depends on the device. If possible, MCI_PAUSE suspends device operation but leaves the device ready to resume play immediately.

For the CD audio device, MCI_STOP resets the current track position to zero; in contrast, MCI_PAUSE maintains the current track position, anticipating that the device will resume playing.


MCI_SYSINFO

MCIERROR mciSendCommand(MCIDEVICEID wDeviceID, MCI_SYSINFO,
    DWORD dwFlags, (DWORD) (LPMCI_SYSINFO_PARMS) lpSysInfo);

Retrieves information about MCI devices. MCI supports this command directly rather than passing it to the device. Any MCI application can use this command. String information is returned in the application-supplied buffer pointed to by the lpstrReturn member of the structure identified by lpSysInfo. Numeric information is returned as a doubleword value placed in the application-supplied buffer. The dwRetSize member specifies the buffer length.

•	Returns zero if successful or an error otherwise.

dwFlags

One or more of the following standard and command-specific flags:

MCI_SYSINFO_INSTALLNAME

Obtains the name (listed in the registry or the SYSTEM.INI file) used to install the device.

MCI_SYSINFO_NAME

Obtains a device name corresponding to the device number specified in the dwNumber member of the structure identified by lpSysInfo. If the MCI_SYSINFO_OPEN flag is set, MCI returns the names of open devices.

MCI_SYSINFO_OPEN

Obtains the quantity or name of open devices.

MCI_SYSINFO_QUANTITY

Obtains the number of devices of the specified type that are listed in the registry or the [mci] section of the SYSTEM.INI file. If the MCI_SYSINFO_OPEN flag is set, the number of open devices is returned.

lpSysInfo

Address of an MCI_SYSINFO_PARMS structure.

The wDeviceType member of the structure identified by lpSysInfo is used to indicate the device type of the query. If the wDeviceID parameter is set to MCI_ALL_DEVICE_ID, it overrides the value of wDeviceType. For a list of device types, see "Constants: Device Types" later in this chapter.

Integer return values are doubleword values returned in the buffer pointed to by the lpstrReturn member of the structure identified by lpSysInfo.

String return values are null-terminated strings returned in the buffer pointed to by the lpstrReturn member of the structure identified by lpSysInfo.


MCI_UNDO

MCIERROR mciSendCommand(MCIDEVICEID wDeviceID, MCI_UNDO,
    DWORD dwFlags, (DWORD) (LPMCI_GENERIC_PARMS) lpUndo);

Reverses the most recent successful MCI_CUT, MCI_COPY, MCI_DELETE, or MCI_PASTE command. Digital-video devices recognize this command.

•	Returns zero if successful or an error otherwise.

dwFlags

MCI_NOTIFY, MCI_WAIT, or MCI_TEST. For information about these flags, see Chapter 3, "MCI Overview."

lpUndo

Address of an MCI_GENERIC_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)


MCI_UNFREEZE

MCIERROR mciSendCommand(MCIDEVICEID wDeviceID, MCI_UNFREEZE,
    DWORD dwFlags, (DWORD) (LPMCI_GENERIC_PARMS) lpUnfreeze);

Restores motion to an area of the video buffer frozen with the MCI_FREEZE command. Digital-video, VCR, and video-overlay devices recognize this command.

•	Returns zero if successful or an error otherwise.

dwFlags

MCI_NOTIFY, MCI_WAIT, or, for digital-video and VCR devices, MCI_TEST. For information about these flags, see Chapter 3, "MCI Overview."

lpUnfreeze

Address of an MCI_GENERIC_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

Digital-Video Flags

The following additional flag is used with the digitalvideo device type:

MCI_DGV_RECT

The rc member of the structure identified by lpUnfreeze contains a valid display rectangle. The rectangle specifies a region within the frame buffer whose pixels should have their lock mask bit turned off. Rectangular regions are specified as described for the MCI_PUT command. If omitted, the rectangle defaults to the entire frame buffer. By using a sequence of freeze and unfreeze commands with different rectangles, arbitrary patterns of lock mask bits can be described.

For digital-video devices, the lpUnfreeze parameter points to an MCI_DGV_UNFREEZE_PARMS structure. The MCI_DGV_UNFREEZE_PARMS structure is identical to the MCI_DGV_RECT_PARMS structure.

VCR Flags

The following additional flags are used with the vcr device type:

MCI_VCR_UNFREEZE_INPUT

Unfreeze the input.

MCI_VCR_UNFREEZE_OUTPUT

Unfreeze the output.

Video-Overlay Flags

The following additional flag is used with the overlay device type:

MCI_OVLY_RECT

The rc member of the structure identified by lpUnfreeze contains a valid display rectangle. This is a required parameter.

For video-overlay devices, the lpUnfreeze parameter points to an MCI_OVLY_RECT_PARMS structure.


MCI_UPDATE

MCIERROR mciSendCommand(MCIDEVICEID wDeviceID, MCI_UPDATE,
    DWORD dwFlags, (DWORD) (LPMCI_GENERIC_PARMS) lpDest);

Updates the display rectangle. Animation and digital-video devices recognize this command.

•	Returns zero if successful or an error otherwise.

dwFlags

MCI_NOTIFY, MCI_WAIT, or, for digital-video devices, MCI_TEST. For information about these flags, see Chapter 3, "MCI Overview."

lpDest

Address of an MCI_GENERIC_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

Animation Flags

The following additional flags are used with the animation device type:

MCI_ANIM_RECT

The rc member of the structure identified by lpDest contains a valid rectangle. If this flag is not specified, the entire window is updated.

MCI_ANIM_UPDATE_HDC

The hDC member of the structure identified by lpDest contains a handle to the display context (DC). This flag is required.

For animation devices, the lpDest parameter points to an MCI_ANIM_UPDATE_PARMS structure.

Digital-Video Flags

The following additional flags are used with the digitalvideo device type:

MCI_DGV_UPDATE_HDC

The hDC member of the structure identified by lpDest contains a valid window of the DC to paint. This flag is required.

MCI_DGV_RECT

The rc member of the structure identified by lpUnfreeze contains a valid display rectangle. The rectangle specifies the clipping rectangle relative to the client rectangle.

MCI_DGV_UPDATE_PAINT

An application uses this flag when it receives a WM_PAINT message that is intended for a display DC. A frame-buffer device usually paints the key color. If the display device does not have a frame buffer, it might ignore the MCI_UPDATE command when the MCI_DGV_UPDATE_PAINT flag is used because the display will be repainted during the playback operation.

For digital-video devices, the lpDest parameter points to an MCI_DGV_UPDATE_PARMS structure.


MCI_WHERE

MCIERROR mciSendCommand(MCIDEVICEID wDeviceID, MCI_WHERE,
    DWORD dwFlags, (DWORD) (LPMCI_GENERIC_PARMS) lpQuery);

Obtains the clipping rectangle for the video device. Animation, digital-video, and video-overlay devices recognize this command. The top and left members of the returned RECT contain the origin of the clipping rectangle, and the right and bottom members contain the width and height of the clipping rectangle. (This is not the standard use of the right and bottom members.)

•	Returns zero if successful or an error otherwise.

dwFlags

MCI_NOTIFY, MCI_WAIT, or, for digital-video devices, MCI_TEST. For information about these flags, see Chapter 3, "MCI Overview."

lpQuery

Address of an MCI_GENERIC_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

Animation Flags

The following additional flags are used with the animation device type:

MCI_ANIM_WHERE_DESTINATION

Obtains the destination display rectangle. The rectangle coordinates are placed in the rc member of the structure identified by lpQuery.

MCI_ANIM_WHERE_SOURCE

Obtains the animation source rectangle. The rectangle coordinates are placed in the rc member of the structure identified by lpQuery.

For animation devices, the lpQuery parameter points to an MCI_ANIM_RECT_PARMS structure.

Digital-Video Flags

The following additional flags are used with the digitalvideo device type:

MCI_DGV_WHERE_DESTINATION

Obtains a description of the rectangular region used to display video and images in the client area of the current window.

MCI_DGV_WHERE_FRAME

Obtains a description of the rectangular region of the frame buffer into which images from the video rectangle are scaled. The rectangle coordinates are placed in the rc member of the structure identified by lpQuery.

MCI_DGV_WHERE_MAX

When used with MCI_DGV_WHERE_DESTINATION or MCI_DGV_WHERE_SOURCE, the rectangle returned indicates the maximum width and height of the specified region. When used with MCI_DGV_WHERE_WINDOW, the rectangle returned indicates the size of the entire display.

MCI_DGV_WHERE_SOURCE

Obtains a description of the rectangular region (cropped from the frame buffer) that is stretched to fit the destination rectangle on the display.

MCI_DGV_WHERE_VIDEO

Obtains a description of the rectangular region cropped from the presentation source to fill the frame rectangle in the frame buffer. The rectangle coordinates are placed in the rc member of the structure identified by lpQuery.

MCI_DGV_WHERE_WINDOW

Obtains a description of the display-window frame.

For digital-video devices, the lpQuery parameter points to an MCI_DGV_WHERE_PARMS structure. The MCI_DGV_WHERE_PARMS structure is identical to the MCI_DGV_RECT_PARMS structure.

Video-Overlay Flags

The following additional flags are used with the overlay device type:

MCI_OVLY_WHERE_DESTINATION

Obtains the destination display rectangle. The rectangle coordinates are placed in the rc member of the structure identified by lpQuery.

MCI_OVLY_WHERE_FRAME

Obtains the overlay frame rectangle. The rectangle coordinates are placed in the rc member of the structure identified by lpQuery.

MCI_OVLY_WHERE_SOURCE

Obtains the source rectangle. The rectangle coordinates are placed in the rc member of the structure identified by lpQuery.

MCI_OVLY_WHERE_VIDEO

Obtains the video rectangle. The rectangle coordinates are placed in the rc member of the structure identified by lpQuery.

For video-overlay devices, the lpQuery parameter points to an MCI_OVLY_RECT_PARMS structure.


MCI_WINDOW

MCIERROR mciSendCommand(MCIDEVICEID wDeviceID, MCI_WINDOW,
    DWORD dwFlags, (DWORD) (LPMCI_GENERIC_PARMS) lpWindow);

Specifies the window and the window characteristics for graphic devices. Animation, digital-video, and video-overlay devices recognize this command.

•	Returns zero if successful or an error otherwise.

dwFlags

MCI_NOTIFY, MCI_WAIT, or, for digital-video devices, MCI_TEST. For information about these flags, see Chapter 3, "MCI Overview."

lpWindow

Address of an MCI_GENERIC_PARMS structure. (Devices with extended command sets might replace this structure with a device-specific structure.)

Graphic devices should create a default window when a device is opened but should not display it until they receive the MCI_PLAY command. The MCI_WINDOW command is used to supply an application-created window to the device and to change the display characteristics of an application-defined or default display window. If the application supplies the display window, it should be prepared to update an invalid rectangle on the window.

Animation Flags

The following additional flags are used with the animation device type:

MCI_ANIM_WINDOW_DISABLE_STRETCH

Disables stretching of the image.

MCI_ANIM_WINDOW_ENABLE_STRETCH

Enables stretching of the image.

MCI_ANIM_WINDOW_HWND

The handle of the window to use for the destination is included in the hWnd member of the structure identified by lpWindow. Set this to MCI_ANIM_WINDOW_DEFAULT to return to the default window.

MCI_ANIM_WINDOW_STATE

The nCmdShow member of the structure identified by lpWindow contains parameters for setting the window state. This flag is equivalent to calling the ShowWindow function with a state parameter such as SW_HIDE, SW_MINIMIZE, or SW_SHOWNORMAL.

MCI_ANIM_WINDOW_TEXT

The lpstrText member of the structure identified by lpWindow contains an address of a buffer containing the caption used for the window.

For animation devices, the lpWindow parameter points to an MCI_ANIM_WINDOW_PARMS structure.

Digital-Video Flags

The following additional flags are used with the digitalvideo device type:

MCI_DGV_WINDOW_HWND

The handle of the window needed for use as the destination is included in the hWnd member of the structure identified by lpWindow.

MCI_DGV_WINDOW_STATE

The nCmdShow member of the structure identified by lpWindow contains parameters for setting the window state.

MCI_DGV_WINDOW_TEXT

The lpstrText member of the structure identified by lpWindow contains an address of a buffer containing the caption used in the window title bar.

For digital-video devices, the lpWindow parameter points to an MCI_DGV_WINDOW_PARMS structure.

Video-Overlay Flags

The following additional flags are used with the overlay device type:

MCI_OVLY_WINDOW_DISABLE_STRETCH

Disables stretching of the image.

MCI_OVLY_WINDOW_ENABLE_STRETCH

Enables stretching of the image.

MCI_OVLY_WINDOW_HWND

The handle of the window used for the destination is included in the hWnd member of the structure identified by lpWindow. Set this flag to MCI_OVLY_WINDOW_DEFAULT to return to the default window.

MCI_OVLY_WINDOW_STATE

The nCmdShow member of the lpWindow structure contains parameters for setting the window state. This flag is equivalent to calling ShowWindow with the state parameter. The constants are the same as those defined in WINDOWS.H (such as SW_HIDE, SW_MINIMIZE, or SW_SHOWNORMAL).

MCI_OVLY_WINDOW_TEXT

The lpstrText member of the structure identified by lpWindow contains an address of a buffer containing the caption used for the window.

For video-overlay devices, the lpWindow parameter points to an MCI_OVLY_WINDOW_PARMS structure.


MCI_ANIM_OPEN_PARMS

typedef struct {
    DWORD  dwCallback;        // see below
    MCIDEVICEID wDeviceID;    // identifier returned to application
    LPCSTR lpstrDeviceType;   // see below
    LPCSTR lpstrElementName;  // device element name (usually a path)
    LPCSTR lpstrAlias;        // optional device alias
    DWORD  dwStyle;           // window style
    HWND   hWndParent;        // handle of parent window
} MCI_ANIM_OPEN_PARMS;

Contains window and device information for the MCI_OPEN command for animation devices.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

lpstrDeviceType

The name or constant identifier of the device type. If this member is a constant, it can be one of the values listed in "Constants: Device Types" later in this chapter.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.

You can use the MCI_OPEN_PARMS structure instead of MCI_ANIM_OPEN_PARMS if you are not using the extended data members.


MCI_ANIM_PLAY_PARMS

typedef struct {
    DWORD dwCallback;  // see below
    DWORD dwFrom;      // position to play from
    DWORD dwTo;        // position to play to
    DWORD dwSpeed;     // play rate, in frames per second
} MCI_ANIM_PLAY_PARMS;

Contains play information for the MCI_PLAY command for animation devices.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.

You can use the MCI_PLAY_PARMS structure instead of MCI_ANIM_PLAY_PARMS if you are not using the extended data members.


MCI_ANIM_RECT_PARMS

typedef struct {
    DWORD dwCallback;
    RECT  rc;
} MCI_ANIM_RECT_PARMS;

Contains positioning information for the MCI_PUT and MCI_WHERE commands for animation devices.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

rc

Rectangle containing positioning information. RECT structures are handled differently in MCI than in other parts of Windows; in MCI, rc.right contains the width of the rectangle and rc.bottom contains its height.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_ANIM_STEP_PARMS

typedef struct {
    DWORD dwCallback;  // see below
    DWORD dwFrames;    // number of frames to step
} MCI_ANIM_STEP_PARMS;

Contains information for the MCI_STEP command for animation devices.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_ANIM_UPDATE_PARMS

typedef struct {
    DWORD dwCallback;  // see below
    RECT  rc;          // see below
    HDC   hDC;         // handle to device context (DC)
} MCI_ANIM_UPDATE_PARMS;

Contains position and DC information for the MCI_UPDATE command for animation devices.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

rc

Rectangle containing positioning information. RECT structures are handled differently in MCI than in other parts of Windows; in MCI, rc.right contains the width of the rectangle and rc.bottom contains its height.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_ANIM_WINDOW_PARMS

typedef struct {
    DWORD  dwCallback;  // see below
    HWND   hWnd;        // handle to display window
    UINT   nCmdShow;    // window-display command
    LPCSTR lpstrText;   // window caption
} MCI_ANIM_WINDOW_PARMS;

Contains display information for the MCI_WINDOW command for animation devices.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_BREAK_PARMS

typedef struct {
    DWORD dwCallback;  // see below
    int   nVirtKey;    // virtual-key code for break key
    HWND  hwndBreak;   // see below
} MCI_BREAK_PARMS;

Contains virtual-key code and window information for the MCI_BREAK command.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

hwndBreak

Handle of the window that must be the current window for break detection.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members. The following flags are defined:

MCI_BREAK_HWND

Validates the hwndBreak member specifying the window that must have focus to enable break detection.

MCI_BREAK_KEY

Validates the nVirtKey member specifying the virtual-key code to be used for the break key.

MCI_BREAK_OFF

Disables any existing break key.


MCI_DGV_CAPTURE_PARMS

typedef struct  {
    DWORD dwCallback;
    LPSTR lpstrFileName;
    RECT  rc;
} MCI_DGV_CAPTURE_PARMS;

Contains parameters for the MCI_CAPTURE command for digital-video devices.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

lpstrFileName

Address of a null-terminated string specifying the destination path and filename for the file that receives the captured data.

rc

Rectangle containing positioning information. RECT structures are handled differently in MCI than in other parts of Windows; in MCI, rc.right contains the width of the rectangle and rc.bottom contains its height.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_DGV_CUE_PARMS

typedef struct {
    DWORD dwCallback;  // see below

    DWORD dwTo;        // cue position
} MCI_DGV_CUE_PARMS;

Contains parameters for the MCI_CUE command for digital-video devices.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_DGV_COPY_PARMS

typedef struct  {
    DWORD dwCallback;     // see below
    DWORD dwFrom;         // starting position for copy
    DWORD dwTo;           // ending position for copy
    RECT  rc;             // see below
    DWORD dwAudioStream;  // audio stream
    DWORD dwVideoStream;  // video stream
} MCI_DGV_COPY_PARMS;

Contains parameters for the MCI_COPY command for digital-video devices.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

rc

Rectangle describing area to be copied. RECT structures are handled differently in MCI than in other parts of Windows; in MCI, rc.right contains the width of the rectangle and rc.bottom contains its height.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_DGV_CUT_PARMS

typedef struct  {
    DWORD dwCallback;     // see below
    DWORD dwFrom;         // starting position for cut
    DWORD dwTo;           // ending position for cut
    RECT  rc;             // see below
    DWORD dwAudioStream;  // audio stream
    DWORD dwVideoStream;  // video stream
} MCI_DGV_CUT_PARMS;

Contains parameters for the MCI_CUT command for digital-video devices.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

rc

Rectangle describing area to be cut. RECT structures are handled differently in MCI than in other parts of Windows; in MCI, rc.right contains the width of the rectangle and rc.bottom contains its height.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_DGV_DELETE_PARMS

typedef struct  {
    DWORD dwCallback;     // see below
    DWORD dwFrom;         // starting position for delete
    DWORD dwTo;           // ending position for delete
    RECT  rc;             // see below
    DWORD dwAudioStream;  // audio stream
} MCI_DGV_DELETE_PARMS;

Contains parameters for the MCI_DELETE command for digital-video devices.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

rc

Rectangle describing area to delete. RECT structures are handled differently in MCI than in other parts of Windows; in MCI, rc.right contains the width of the rectangle and rc.bottom contains its height.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_DGV_FREEZE_PARMS

typedef struct  {
    DWORD dwCallback;
    RECT  rc;
} MCI_DGV_FREEZE_PARMS;

Contains parameters for the MCI_FREEZE and MCI_UNFREEZE commands for digital-video devices.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

rc

Rectangle containing positioning information. RECT structures are handled differently in MCI than in other parts of Windows; in MCI, rc.right contains the width of the rectangle and rc.bottom contains its height.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_DGV_INFO_PARMS

typedef struct {
    DWORD  dwCallback;   // see below
    LPSTR  lpstrReturn;  // address of buffer for return string
    DWORD  dwRetSize;    // size, in bytes, of return buffer
    DWORD  dwItem;       // constant describing information to return
} MCI_DGV_INFO_PARMS;

Contains parameters for the MCI_INFO command for digital-video devices.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_DGV_LIST_PARMS

typedef struct  {
    DWORD dwCallback;      // see below
    LPSTR lpstrReturn;     // buffer for return string
    DWORD dwLength;        // length, in bytes, of buffer
    DWORD dwNumber;        // index of item in list
    DWORD dwItem;          // type of list item
    LPSTR lpstrAlgorithm;  // string containing algorithm name
} MCI_DGV_LIST_PARMS;

Contains the information for the MCI_LIST command for digital-video devices.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_DGV_LOAD_PARMS

typedef struct  {
    DWORD dwCallback;  // see below
    LPSTR lpfilename;  // string naming file to load
} MCI_DGV_LOAD_PARMS;

Contains the information for the MCI_LOAD command for digital-video devices.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_DGV_MONITOR_PARMS

typedef struct  {
    DWORD dwCallback;
    DWORD dwSource;
    DWORD dwMethod;
} MCI_DGV_MONITOR_PARMS;

Contains parameters for the MCI_MONITOR command.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

dwSource

One of the following flags for the monitor source:

MCI_DGV_MONITOR_FILE

The workspace is the presentation source. (This is the default source.) If this flag is used during recording, the recording pauses. If the MCI_MONITOR command changes the presentation source, recording or playing stops and the current position is the value returned by the MCI_STATUS command for the start position.

MCI_DGV_MONITOR_INPUT

The external input is the presentation source. Playback is paused before the input is selected. If the MCI_SETVIDEO command has been enabled using the MCI_SET_ON flag, this flag displays a default hidden window. Device drivers might limit what other device instances can do while monitoring input.

dwMethod

One of the following constants for the type of monitoring:

MCI_DGV_METHOD_DIRECT

The device should be configured for optimum display quality during monitoring. Direct monitoring might be incompatible with motion-video recording.

MCI_DGV_METHOD_POST

The device should show the external input after compression. Post monitoring supports motion-video recording.

MCI_DGV_METHOD_PRE

The device should show the external input prior to compression.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_DGV_OPEN_PARMS

typedef struct {
    DWORD dwCallback;        // see below
    UINT  wDeviceID;         // device ID returned to user
    LPSTR lpstrDeviceType;   // name or constant ID of device type
    LPSTR lpstrElementName;  // device element name (usually a path)
    LPSTR lpstrAlias;        // optional device alias
    DWORD dwStyle;           // window style
    HWND  hWndParent;        // handle of parent window
} MCI_DGV_OPEN_PARMS;

Contains information for the MCI_OPEN command for digital-video devices.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_DGV_PASTE_PARMS

typedef struct  {
    DWORD dwCallback;     // see below
    DWORD dwTo;           // starting position for paste
    RECT  rc;             // see below
    DWORD dwAudioStream;  // audio stream
    DWORD dwVideoStream;  // video stream
} MCI_DGV_PASTE_PARMS;

Contains parameters for the MCI_PASTE command for digital-video devices.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

rc

Rectangle containing positioning information. RECT structures are handled differently in MCI than in other parts of Windows; in MCI, rc.right contains the width of the rectangle and rc.bottom contains its height.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_DGV_PAUSE_PARMS

typedef struct {
    DWORD dwCallback;
} MCI_DGV_PAUSE_PARMS;

Contains information for the MCI_PAUSE command.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_DGV_PLAY_PARMS

typedef struct {
    DWORD dwCallback;  // see below
    DWORD dwFrom;      // position to play from

    DWORD dwTo;        // position to play to
} MCI_DGV_PLAY_PARMS;

Contains parameters for the MCI_PLAY command for digital-video devices.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_DGV_PUT_PARMS

typedef struct {
    DWORD dwCallback;
    RECT  rc;
} MCI_DGV_PUT_PARMS;

Contains parameters for the MCI_PUT command for digital-video devices.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

rc

Rectangle containing positioning information. RECT structures are handled differently in MCI than in other parts of Windows; in MCI, rc.right contains the width of the rectangle and rc.bottom contains its height.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_DGV_QUALITY_PARMS

typedef struct  {
    DWORD dwCallback;      // see below
    DWORD dwItem;          // see below
    LPSTR lpstrName;       // string naming descriptor
    DWORD lpstrAlgorithm;  // string naming algorithm
    DWORD dwHandle;        // see below
} MCI_DGV_QUALITY_PARMS;

Contains parameters for the MCI_QUALITY command for digital-video devices.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

dwItem

One of the following constants indicating the type of algorithm:

MCI_QUALITY_ITEM_AUDIO

Definitions are for an audio compression algorithm.

MCI_QUALITY_ITEM_STILL

Definitions are for a still video compression algorithm.

MCI_QUALITY_ITEM_VIDEO

Definitions are for a video compression algorithm.

dwHandle

Handle of a structure containing information describing the quality attributes.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_DGV_RECORD_PARMS

typedef struct  {
    DWORD dwCallback;     // see below
    DWORD dwFrom;         // position to record from
    DWORD dwTo;           // position to record to
    RECT  rc;             // see below
    DWORD dwAudioStream;  // audio stream
    DWORD dwVideoStream;  // video stream
} MCI_DGV_RECORD_PARMS;

Contains parameters for the MCI_RECORD command for digital-video devices.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

rc

The region of the frame buffer used as the source for the pixels compressed and saved. RECT structures are handled differently in MCI than in other parts of Windows; in MCI, rc.right contains the width of the rectangle and rc.bottom contains its height.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_DGV_RECT_PARMS

typedef struct {
    DWORD dwCallback;
    RECT  rc;
} MCI_DGV_RECT_PARMS;

Contains parameters for the MCI_FREEZE, MCI_PUT, MCI_UNFREEZE, and MCI_WHERE commands for digital-video devices.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

rc

Rectangle containing positioning information. RECT structures are handled differently in MCI than in other parts of Windows; in MCI, rc.right contains the width of the rectangle and rc.bottom contains its height.

The MCI_DGV_UNFREEZE_PARMS and MCI_DGV_WHERE_PARMS structures are identical to the MCI_DGV_RECT_PARMS structure.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_DGV_RESERVE_PARMS

typedef struct  {
    DWORD dwCallback;  // see below
    LPSTR lpstrPath;   // see below
    DWORD dwSize;      // size of reserved disk space
} MCI_DGV_RESERVE_PARMS;

Contains information for the MCI_RESERVE command for digital-video devices.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

lpstrPath

Address of a null-terminated string containing the location of a temporary file. The buffer contains only the drive and directory path of the file used to hold recorded data; the filename is specified by the device driver.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_DGV_RESTORE_PARMS

typedef struct  {
    DWORD dwCallback;
    DWORD lpstrFileName;
    RECT  rc;
} MCI_DGV_RESTORE_PARMS;

Contains information for the MCI_RESTORE command for digital-video devices.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

lpstrFileName

Address of a null-terminated string containing the filename from which the frame buffer information will be restored.

rc

Rectangle containing positioning information. RECT structures are handled differently in MCI than in other parts of Windows; in MCI, rc.right contains the width of the rectangle and rc.bottom contains its height.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_DGV_RESUME_PARMS

typedef struct  {
    DWORD dwCallback;
} MCI_DGV_RESUME_PARMS;

Contains information for the MCI_RESUME command.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_DGV_SAVE_PARMS

typedef struct  {
    DWORD dwCallback;     // see below
    DWORD lpstrFileName;  // string for filename to save
    RECT  rc;             // see below
} MCI_DGV_SAVE_PARMS;

Contains information for the MCI_SAVE command for digital-video devices.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

rc

Rectangle containing positioning information. RECT structures are handled differently in MCI than in other parts of Windows; in MCI, rc.right contains the width of the rectangle and rc.bottom contains its height.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_DGV_SET_PARMS

typedef struct {
    DWORD dwCallback;    // see below
    DWORD dwTimeFormat;  // time format of device
    DWORD dwAudio;       // channel for audio output
    DWORD dwFileFormat;  // file format
    DWORD dwSpeed;       // playback speed
} MCI_DGV_SET_PARMS;

Contains parameters for the MCI_SET command for digital-video devices.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_DGV_SETAUDIO_PARMS

typedef struct {
    DWORD dwCallback;      // see below
    DWORD dwItem;          // see below
    DWORD dwValue;         // adjustment level
    DWORD dwOver;          // transmission length
    LPSTR lpstrAlgorithm;  // see below
    LPSTR lpstrQuality;    // see below
} MCI_DGV_SETAUDIO_PARMS;

Contains parameters for the MCI_SETAUDIO command for digital-video devices.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

dwItem

Constant indicating the target adjustment. For a list of possible values, see the MCI_SETAUDIO command.

lpstrAlgorithm

Address of a null-terminated string containing the name of the audio-compression algorithm.

lpstrQuality

Address of a null-terminated string containing a descriptor of the audio-compression algorithm.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_DGV_SETVIDEO_PARMS

typedef struct {
    DWORD  dwCallback;      // see below
    DWORD  dwItem;          // see below
    DWORD  dwValue;         // adjustment level
    DWORD  dwOver;          // transmission length
    LPSTR  lpstrQuality;    // see below
    LPSTR  lpstrAlgorithm;  // see below
    DWORD  dwSourceNumber;  // index of input source
} MCI_DGV_SETVIDEO_PARMS;

Contains parameters for the MCI_SETVIDEO command for digital-video devices.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

dwItem

Constant indicating the target adjustment.

lpstrQuality

Address of a null-terminated string containing a descriptor of the video-compression algorithm.

lpstrAlgorithm

Address of a null-terminated string containing the name of the video-compression algorithm.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_DGV_SIGNAL_PARMS

typedef struct {
    DWORD dwCallback;  // see below
    DWORD dwPosition;  // position to be marked
    DWORD dwPeriod;    // interval of the position marks
    DWORD dwUserParm;  // user value associated with signals
} MCI_DGV_SIGNAL_PARMS;

Contains parameters for the MCI_SIGNAL command for digital-video devices.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_DGV_STATUS_PARMS

typedef struct {
    DWORD dwCallback;   // see below
    DWORD dwReturn;     // buffer for return information
    DWORD dwItem;       // identifies capability being queried
    DWORD dwTrack;      // length or number of tracks
    LPSTR lpstrDrive;   // see below
    DWORD dwReference;  // see below
} MCI_DGV_STATUS_PARMS;

Contains parameters for the MCI_STATUS command for digital-video devices.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

lpstrDrive

Specifies the approximate amount of disk space that can be obtained by the MCI_RESERVE command.

dwReference

Specifies the approximate location of the nearest previous intraframe-encoded image.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_DGV_STEP_PARMS

typedef struct {
    DWORD dwCallback;  // see below
    DWORD dwFrames;    // number of frames to step
} MCI_DGV_STEP_PARMS;

Contains parameters for the MCI_STEP command for digital-video devices.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_DGV_STOP_PARMS

typedef struct {
    DWORD dwCallback;
} MCI_DGV_STOP_PARMS;

Contains information for the MCI_STOP command for digital-video devices.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_DGV_UPDATE_PARMS

typedef struct {
    DWORD dwCallback;  // see below
    RECT  rc;          // see below
    HDC   hDC;         // handle to display context
} MCI_DGV_UPDATE_PARMS;

Contains parameters for the MCI_UPDATE command.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

rc

Rectangle containing positioning information. RECT structures are handled differently in MCI than in other parts of Windows; in MCI, rc.right contains the width of the rectangle and rc.bottom contains its height.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_DGV_WINDOW_PARMS

typedef struct {
    DWORD dwCallback;  // see below
    WORD  hWnd;        // see below
    WORD  nCmdShow;    // window-display command
    LPSTR lpstrText;   // window caption
} MCI_DGV_WINDOW_PARMS;

Contains parameters for MCI_WINDOW command for digital-video devices.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

hWnd

Handle to the display window. If this member is MCI_DGV_WINDOW_HWND, the system uses a default window.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members


MCI_GENERIC_PARMS

typedef struct {
    DWORD dwCallback;
} MCI_GENERIC_PARMS;

Contains the handle of the window that receives notification messages. This structure is used for MCI command messages that have empty parameter lists.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

The MCI_CLOSE_PARMS and MCI_REALIZE_PARMS structures are identical to the MCI_GENERIC_PARMS structure.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_GETDEVCAPS_PARMS

typedef struct {
    DWORD dwCallback;  // see below
    DWORD dwReturn;    // contains information on exit
    DWORD dwItem;      // see below
} MCI_GETDEVCAPS_PARMS;

Contains device-capability information for the MCI_GETDEVCAPS command.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

dwItem

Capability being queried. This member can be one of the constants listed in the reference material for the MCI_GETDEVCAPS command.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_INFO_PARMS

typedef struct {
    DWORD dwCallback;   // see below
    LPSTR lpstrReturn;  // buffer for return string
    DWORD dwRetSize;    // size, in bytes, of return string
} MCI_INFO_PARMS;

Contains information for the MCI_INFO command.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_LOAD_PARMS

typedef struct {
    DWORD   dwCallback;  // see below
    LPCSTR  lpfilename;  // filename to load
} MCI_LOAD_PARMS;

Contains the filename to load for the MCI_LOAD command.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_OPEN_PARMS

typedef struct {
    DWORD        dwCallback;        // see below
    MCIDEVICEID  wDeviceID;  // identifier returned to application
    LPCSTR       lpstrDeviceType;   // see below
    LPCSTR       lpstrElementName;  // device element (often a path)
    LPCSTR       lpstrAlias;        // optional device alias
} MCI_OPEN_PARMS;

Contains information for the MCI_OPEN command.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

lpstrDeviceType

Name or constant identifier of the device type. (The name of the device is typically obtained from the registry or SYSTEM.INI file.) If this member is a constant, it can be one of the values listed in "Constants: Device Types" later in this chapter.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_OVLY_LOAD_PARMS

typedef struct {
    DWORD  dwCallback;  // see below
    LPCSTR lpfilename;  // name of file to load
    RECT   rc;          // see below
} MCI_OVLY_LOAD_PARMS;

Contains information for the MCI_LOAD command for video-overlay devices.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

rc

Identifies the area of the video buffer to update. RECT structures are handled differently in MCI than in other parts of Windows; in MCI, rc.right contains the width of the rectangle and rc.bottom contains its height.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_OVLY_OPEN_PARMS

typedef struct {
    DWORD  dwCallback;        // see below
    MCIDEVICEID wDeviceID;    // identifier returned to application
    LPCSTR lpstrDeviceType;   // see below
    LPCSTR lpstrElementName;  // device element name (usually a path)
    LPCSTR lpstrAlias;        // optional device alias
    DWORD  dwStyle;           // window style
    DWORD  hWndParent;        // handle of parent window
} MCI_OVLY_OPEN_PARMS;

Contains information for the MCI_OPEN command for video-overlay devices.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

lpstrDeviceType

Name or constant identifier of the device type. (The name of the device is typically obtained from the registry or SYSTEM.INI file.) If this member is a constant, it can be one of the values listed in "Constants: Device Types" later in this chapter.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.

You can use the MCI_OPEN_PARMS structure in place of  MCI_OVLY_OPEN_PARMS if you are not using the extended data members.


MCI_OVLY_RECT_PARMS

typedef struct {
    DWORD dwCallback;
    RECT  rc;
} MCI_OVLY_RECT_PARMS;

Contains positioning information for the MCI_PUT and MCI_WHERE commands for video-overlay devices.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

rc

Rectangle containing positioning information. RECT structures are handled differently in MCI than in other parts of Windows; in MCI, rc.right contains the width of the rectangle and rc.bottom contains its height.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_OVLY_SAVE_PARMS

typedef struct {
    DWORD  dwCallback;  // see below
    LPCSTR lpfilename;  // name of file to save
    RECT   rc;          // see below
} MCI_OVLY_SAVE_PARMS;

Contains information for the MCI_SAVE command for video-overlay devices.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

rc

Rectangle indicating the area of the video buffer to save. RECT structures are handled differently in MCI than in other parts of Windows; in MCI, rc.right contains the width of the rectangle and rc.bottom contains its height.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_OVLY_WINDOW_PARMS

typedef struct {
    DWORD  dwCallback;  // see below
    HWND   hWnd;        // handle of display window
    UINT   nCmdShow;    // window-display command
    LPCSTR lpstrText;   // window caption
} MCI_OVLY_WINDOW_PARMS;

Contains window-display information for the MCI_WINDOW command for video-overlay devices.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_PLAY_PARMS

typedef struct {
    DWORD dwCallback;  // see below
    DWORD dwFrom;      // position to play from
    DWORD dwTo;        // position to play to
} MCI_PLAY_PARMS;

Contains positioning information for the MCI_PLAY command.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_RECORD_PARMS

typedef struct {
    DWORD dwCallback;  // see below
    DWORD dwFrom;      // position to record from
    DWORD dwTo;        // position to record to
} MCI_RECORD_PARMS;

Contains positioning information for the MCI_RECORD command.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_SAVE_PARMS

typedef struct {
    DWORD  dwCallback;  // see below
    LPCSTR lpfilename;  // name of file to save
} MCI_SAVE_PARMS;

Contains the filename information for the MCI_SAVE command.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_SEEK_PARMS

typedef struct {
    DWORD dwCallback;  // see below
    DWORD dwTo;        // position to seek to
} MCI_SEEK_PARMS;

Contains positioning information for the MCI_SEEK command.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_SEQ_SET_PARMS

typedef struct {
    DWORD dwCallback;    // see below
    DWORD dwTimeFormat;  // sequencer's time format
    DWORD dwAudio;       // audio output channel
    DWORD dwTempo;       // tempo
    DWORD dwPort;        // output port
    DWORD dwSlave;       // see below
    DWORD dwMaster;      // see below
    DWORD dwOffset;      // data offset
} MCI_SEQ_SET_PARMS;

Contains information for the MCI_SET command for MIDI sequencer devices.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

dwSlave

Type of synchronization used by the sequencer for slave operation.

dwMaster

Type of synchronization used by the sequencer for master operation.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_SET_PARMS

typedef struct {
    DWORD dwCallback;    // see below
    DWORD dwTimeFormat;  // time format for device
    DWORD dwAudio;       // audio output channel
} MCI_SET_PARMS;

Contains information for the MCI_SET command.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_STATUS_PARMS

typedef struct {
    DWORD dwCallback;  // see below
    DWORD dwReturn;    // contains information on return
    DWORD dwItem;      // capability being queried
    DWORD dwTrack;     // length or number of tracks
} MCI_STATUS_PARMS;

Contains information for the MCI_STATUS command.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

The MCI_STATUS_ITEM flag must be set in the fdwCommand parameter of the mciSendCommand function to validate the dwItem member, which should contain one of the constants indicating what status information is being requested.


MCI_SYSINFO_PARMS

typedef struct {
    DWORD dwCallback;   // see below
    LPSTR lpstrReturn;  // see below
    DWORD dwRetSize;    // size, in bytes, of return buffer
    DWORD dwNumber;     // see below
    UINT  wDeviceType;  // see below
} MCI_SYSINFO_PARMS;

Contains information for the MCI_SYSINFO command.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

lpstrReturn

Address of a user-supplied buffer for the return string. It is also used to return a doubleword value when the MCI_SYSINFO_QUANTITY flag is used.

dwNumber

Number indicating the device position in the MCI device table or in the list of open devices if the MCI_SYSINFO_OPEN flag is set.

wDeviceType

Type of device. This member can be one of the values listed in "Constants: Device Types" later in this chapter.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_VCR_CUE_PARMS

typedef struct tagMCI_VCR_CUE_PARMS {
    DWORD dwCallback;  // see below
    DWORD dwFrom;      // position to cue from
    DWORD dwTo;        // position to cue to
} MCI_VCR_CUE_PARMS;

Contains parameters for the MCI_CUE command for video-cassette recorders.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_VCR_LIST_PARMS

typedef struct tagMCI_VCR_LIST_PARMS {
    DWORD dwCallback;  // see below
    DWORD dwReturn;    // buffer for returned information
    DWORD dwNumber;    // number of VCR's video or audio inputs
} MCI_VCR_LIST_PARMS;

Contains parameters for the MCI_LIST command for video-cassette recorders.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_VCR_PLAY_PARMS

typedef struct tagMCI_VCR_PLAY_PARMS {
    DWORD dwCallback;  // see below
    DWORD dwFrom;      // position to play from
    DWORD dwTo;        // position to play to
    DWORD dwAt;        // see below
} MCI_VCR_PLAY_PARMS;

Contains parameters for the MCI_PLAY command for video-cassette recorders.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

dwAt

Time value that affects the MCI_PLAY or MCI_CUE command. For MCI_PLAY, this is the time when playback begins. For MCI_CUE, this is the time when the cued device reaches the position given in dwFrom.

Positions are specified in the current time format.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_VCR_RECORD_PARMS

typedef struct tagMCI_VCR_RECORD_PARMS {
    DWORD dwCallback;  // see below
    DWORD dwFrom;      // position to record from
    DWORD dwTo;        // position to record to
    DWORD dwAt;        // see below
} MCI_VCR_RECORD_PARMS;

Contains parameters for the MCI_RECORD command for video-cassette recorders.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

dwAt

Time value that affects the MCI_RECORD or MCI_CUE command. For MCI_RECORD, this is the time when recording begins. For MCI_CUE, this is the time when the cued device reaches the position given in dwFrom.

Positions are specified in the current time format.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_VCR_SEEK_PARMS

typedef struct tagMCI_VCR_SEEK_PARMS {
    DWORD dwCallback;  // see below
    DWORD dwTo;        // position to seek to
    DWORD dwMark;      // numbered mark to seek for
    DWORD dwAt;        // time when seek begins
} MCI_VCR_SEEK_PARMS;

Contains parameters for the MCI_SEEK command for video-cassette recorders.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

Positions are specified in the current time format.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_VCR_SET_PARMS

typedef struct tagMCI_VCR_SET_PARMS {
    DWORD dwCallback;          // see below
    DWORD dwTimeFormat;        // current time format
    DWORD dwAudio;             // not used
    DWORD dwTimeMode;          // see below
    DWORD dwRecordFormat;      // recording rate
    DWORD dwCounterFormat;     // format of a new counter time value
    DWORD dwIndex;             // contents of on-screen display
    DWORD dwTracking;          // see below
    DWORD dwSpeed;             // see below
    DWORD dwLength;            // see below
    DWORD dwCounter;           // new counter value
    DWORD dwClock;             // new clock time
    DWORD dwPauseTimeout;      // new timeout value for pause command
    DWORD dwPrerollDuration;   // see below
    DWORD dwPostrollDuration;  // see below
} MCI_VCR_SET_PARMS;

Contains parameters for the MCI_SET command for video-cassette recorders.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

dwTimeMode

Constant that specifies the timing source used by the device. The timing source is either a timecode recorded on videotape, or the counters in the device that sense videotape movement.

dwTracking

Speed adjustment used when tracking the VCR playback rate.

dwSpeed

Playback speed used by the device as an integer. Normal playback speed is 1000, double speed is 2000, and half speed is 500.

dwLength

Videotape length when the length is undetectable by the device.

dwPrerollDuration

Videotape length needed to stabilize the VCR output.

dwPostrollDuration

Videotape length needed to brake the VCR transport when a MCI_STOP or MCI_PAUSE command is issued.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_VCR_SETAUDIO_PARMS

typedef struct tagMCI_VCR_SETAUDIO_PARMS {
    DWORD dwCallback;  // see below
    DWORD dwTrack;     // audio track
    DWORD dwTo;        // type of input or monitored input
    DWORD dwNumber;    // see below
} MCI_VCR_SETAUDIO_PARMS;

Contains parameters for the MCI_SETAUDIO command for video-cassette recorders.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

dwNumber

Audio input (of the type specified in the dwTo member) to use.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_VCR_SETTUNER_PARMS

typedef struct tagMCI_VCR_SETTUNER_PARMS {
    DWORD dwCallback;  // see below
    DWORD dwChannel;   // new channel number
    DWORD dwNumber;    // see below
} MCI_VCR_SETTUNER_PARMS;

Contains parameters for the MCI_SETTUNER command for video-cassette recorders.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

dwNumber

Logical tuner that the MCI_SETTUNER command affects.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_VCR_SETVIDEO_PARMS

typedef struct tagMCI_VCR_SETVIDEO_PARMS {
    DWORD dwCallback;  // see below
    DWORD dwTrack;     // affected track
    DWORD dwTo;        // type of input or monitored input
    DWORD dwNumber;    // see below
} MCI_VCR_SETVIDEO_PARMS;

Contains parameters for the MCI_SETVIDEO command for video-cassette recorders.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

dwNumber

Video input (of the type specified in the dwTo member) to use.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_VCR_STATUS_PARMS

typedef struct tagMCI_VCR_STATUS_PARMS {
    DWORD dwCallback;  // see below
    DWORD dwReturn;    // see below
    DWORD dwItem;      // type of information requested
    DWORD dwTrack;     // see below
    DWORD dwNumber;    // see below
} MCI_VCR_STATUS_PARMS;

Contains parameters for the MCI_STATUS command for video-cassette recorders.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

dwReturn

Value returned by the MCI_STATUS command. The return value varies according to the inquiry of the command. For more information, see the description of the MCI_STATUS command.

dwTrack

Audio or video track that will store information during the next recording. This member is used to return information when the MCI_STATUS command inquires about the video or audio recording status.

dwNumber

Logical tuner that the current channel is associated with. This member is used to return information when the MCI_STATUS command inquires about the current channel number.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_VCR_STEP_PARMS

typedef struct tagMCI_VCR_STEP_PARMS {
    DWORD dwCallback;
    DWORD dwFrames;
} MCI_VCR_STEP_PARMS;

Contains parameters for the MCI_STEP command for video-cassette recorders.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

dwFrames

Number of frames to jump (the length of a single step) as the MCI_STEP command steps forward or backward through the content.

When assigning data to the members in this structure, set the corresponding flags in the fdwCommand parameter of mciSendCommand to validate the members.


MCI_VD_ESCAPE_PARMS

typedef struct {
    DWORD  dwCallback;    // see below
    LPCSTR lpstrCommand;  // command to send to device
} MCI_VD_ESCAPE_PARMS;

Contains the command sent to a device for the MCI_ESCAPE command for videodisc devices.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_VD_PLAY_PARMS

typedef struct {
    DWORD dwCallback;  // see below
    DWORD dwFrom;      // position to play from
    DWORD dwTo;        // position to play to
    DWORD dwSpeed;     // playback speed in frames per second
} MCI_VD_PLAY_PARMS;

Contains position and speed information for the MCI_PLAY command for videodisc devices.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.

You can use the MCI_PLAY_PARMS structure instead of MCI_VD_PLAY_PARMS if you are not using the extended data members.


MCI_VD_STEP_PARMS

typedef struct {
    DWORD dwCallback;  // see below
    DWORD dwFrames;    // number of frames to step
} MCI_VD_STEP_PARMS;

Contains information for the MCI_STEP command for videodisc devices.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_WAVE_DELETE_PARMS

typedef struct {
    DWORD dwCallback;  // see below
    DWORD dwFrom;      // position to delete from
    DWORD dwTo;        // position to delete to
} MCI_WAVE_DELETE_PARMS;

Contains position information for the MCI_DELETE command for waveform-audio devices.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


MCI_WAVE_OPEN_PARMS

typedef struct {
    DWORD  dwCallback;        // see below
    MCIDEVICEID   wDeviceID;  // identifier returned to application
    LPCSTR lpstrDeviceType;   // see below
    LPCSTR lpstrElementName;  // device element name (usually a path)
    LPCSTR lpstrAlias;        // optional device alias
    DWORD  dwBufferSeconds;   // buffer length, in seconds
} MCI_WAVE_OPEN_PARMS;

Contains information for MCI_OPEN command for waveform-audio devices.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

lpstrDeviceType

Name or constant identifier of the device type. (The name of the device is typically obtained from the registry or SYSTEM.INI file.) This member can be one of the values listed in "Constants: Device Types" later in this chapter.

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.

You can use the MCI_OPEN_PARMS structure instead of MCI_WAVE_OPEN_PARMS if you are not using the extended data members.


MCI_WAVE_SET_PARMS

typedef struct {
    DWORD dwCallback;       // see below
    DWORD dwTimeFormat;     // device's time format
    DWORD dwAudio;          // see below
    UINT  wInput;           // audio input channel
    UINT  wOutput;          // see below
    WORD  wFormatTag;       // see below
    WORD  wReserved2;       // reserved
    WORD  nChannels;        // mono (1) or stereo (2)
    WORD  wReserved3;       // reserved
    DWORD nSamplesPerSec;   // samples per second
    DWORD nAvgBytesPerSec;  // sample rate in bytes per second
    WORD  nBlockAlign;      // block alignment of the data
    WORD  wReserved4;       // reserved
    WORD  wBitsPerSample;   // bits per sample
    WORD  wReserved5;       // reserved
} MCI_WAVE_SET_PARMS;

Contains information for the MCI_SET command for waveform-audio devices.

dwCallback

The low-order word specifies a window handle used for the MCI_NOTIFY flag.

dwAudio

Channel number for audio output. Typically used when turning a channel on or off.

wOutput

Output device to use. For example, this value could be 2 if a system had two installed sound cards.

wFormatTag

Format of the waveform-audio data. This member can be one of the following:

WAVE_FORMAT_ADPCM

Microsoft Corporation

WAVE_FORMAT_ALAW

Microsoft Corporation

WAVE_FORMAT_ANTEX_ADPCME

Antex Electronics Corporation

WAVE_FORMAT_APTX

Audio Processing Technology

WAVE_FORMAT_AUDIOFILE_AF10

Audiofile

WAVE_FORMAT_AUDIOFILE_AF36

Audiofile

WAVE_FORMAT_CONTROL_RES_CR10

Control Resources Corporation

WAVE_FORMAT_CONTROL_RES_VQLPC

Control Resources Corporation

WAVE_FORMAT_CREATIVE_ADPCM

Creative Labs, Inc.

WAVE_FORMAT_CREATIVE_FASTSPEECH10

Creative Labs, Inc.

WAVE_FORMAT__CREATIVE__FASTSPEECH8

Creative Labs, Inc.

WAVE_FORMAT_DIALOGIC_OKI_ADPCM

Dialogic Corporation

WAVE_FORMAT_DIGIADPCM

DSP Solutions, Inc.

WAVE_FORMAT_DIGIFIX

DSP Solutions, Inc.

WAVE_FORMAT_DIGIREAL

DSP Solutions, Inc.

WAVE_FORMAT_DIGISTD

DSP Solutions, Inc.

WAVE_FORMAT_DOLBY_AC2

Dolby Laboratories, Inc.

WAVE_FORMAT_DSPGROUP_TRUESPEECH

DSP Group, Inc.

WAVE_FORMAT_DVI_ADPCM

Intel Corporation

WAVE_FORMAT_ECHOSC1

Echo Speech Corporation

WAVE_FORMAT_FM_TOWNS_SND

Fujitsu, Ltd.

WAVE_FORMAT_G721_ADPCM

Antex Electronics Corporation

WAVE_FORMAT_G723_ADPCM

Antex Electronics Corporation

WAVE_FORMAT_GSM610

Microsoft Corporation

WAVE_FORMAT_IBM_CVSD

International Business Machines

WAVE_FORMAT_IMA_ADPCM

Intel Corporation

WAVE_FORMAT_MEDIASPACE_ADPCM

VideoLogic, Inc.

WAVE_FORMAT_MPEG

Microsoft Corporation

WAVE_FORMAT_MULAW

Microsoft Corporation

WAVE_FORMAT_NMS_VBXADPCM

Natural MicroSystems Corporation

WAVE_FORMAT_OKI_ADPCM

OKI

WAVE_FORMAT_OLIADPCM

Ing C. Olivetti & C., S.p.A.

WAVE_FORMAT_OLICELP

Ing C. Olivetti & C., S.p.A.

WAVE_FORMAT_OLIGSM

Ing C. Olivetti & C., S.p.A.

WAVE_FORMAT_OLIOPR

Ing C. Olivetti & C., S.p.A.

WAVE_FORMAT_OLISBC

Ing C. Olivetti & C., S.p.A.

WAVE_FORMAT_SIERRA_ADPCM

Sierra Semiconductor Corporation

WAVE_FORMAT_SONARC

Speech Compression

WAVE_FORMAT_UNKNOWN

Microsoft Corporation

WAVE_FORMAT_YAMAHA_ADPCM

Yamaha Corporation of America

When assigning data to the members of this structure, set the corresponding flags in the fdwCommand parameter of the mciSendCommand function to validate the members.


Constants: Device Types

The following values identify devices in MCI messages and structures:

Value	Meaning
MCI_ALL_DEVICE_ID	Any device
MCI_DEVTYPE_ANIMATION	Animation-playback device
MCI_DEVTYPE_CD_AUDIO	CD audio device
MCI_DEVTYPE_DAT	Digital-audio tape device
MCI_DEVTYPE_DIGITAL_VIDEO	Digital-video playback device
MCI_DEVTYPE_OTHER	Undefined device
MCI_DEVTYPE_OVERLAY	Video-overlay device
MCI_DEVTYPE_SCANNER	Scanner device
MCI_DEVTYPE_SEQUENCER	MIDI sequencer device
MCI_DEVTYPE_VCR	Video-cassette recorder
MCI_DEVTYPE_VIDEODISC	Videodisc players
MCI_DEVTYPE_WAVEFORM_AUDIO	Waveform-audio device


AVIFile Functions and Macros

AVIFile functions and macros provide access to time-based files that use the Resource Information File Format (RIFF), such as waveform-audio and audio-video interleaved (AVI) files. These functions and macros manage the internals of RIFF files, making it unnecessary for you to manage and navigate through the RIFF architecture.

The AVIFile functions and macros handle the information in time-based files as one or more data streams instead of tagged blocks of data called chunks. Data streams refer to the components of a time-based file. An AVI file can contain several different types of data, such as a video sequence, an English soundtrack, and a French soundtrack. Using AVIFile, an application can access each of these components separately.

Note  Although the AVIFile functions and macros work with any RIFF file, this chapter demonstrates their use with AVI files only. AVI files are typically the time-based files used with the AVIFile macros and functions.

AVIFile functions and macros are contained in a dynamic-link library. You can initialize the library by using the AVIFileInit function. After you initialize the library, you can use any of the AVIFile functions or macros. You can release the library by using the AVIFileExit function. AVIFile maintains a reference count of the applications that are using the library, but not those that have released it. Your applications should balance each use of AVIFileInit with a call to AVIFileExit to completely release the library after each application finishes using it.


Function Data Types and Return Values

The AVIFile functions and macros use file and stream handlers implemented with OLE technology. The standard data type of an OLE function is STDAPI, and the function returns an HRESULT value (zero for success or an error otherwise). If a function returns a value other than an HRESULT, the type of the function's prototype has a slightly different syntax that embeds the return value type in parentheses following STDAPI_. For example, a function that returns a LONG data value uses STDAPI_(LONG) in the prototype statement.


AVIFile Operations

This section describes the AVIFile file input and output (I/O) operations.


Opening and Closing Files

An application must open an AVI file before reading or writing. You can open an AVI file by using the AVIFileOpen function. AVIFileOpen returns the address of an AVI file interface that contains the handle of the open file and increments the reference count of the file.

AVIFileOpen supports the OF flags used with the OpenFile function. If an application writes to an existing file, it must include the OF_WRITE flag in AVIFileOpen. Similarly, if your application creates and writes to a new file, you must include the OF_CREATE and OF_WRITE flags in AVIFileOpen.

When you open a file using AVIFileOpen, you can use a default file handler or you can specify a custom file handler to read and write to the file and its data streams. In either case, AVIFile searches the registry for the correct file handler to use. You must ensure custom file handlers are in the registry before an application can access them.

You can increment the reference count of a file by using the AVIFileAddRef function. For example, you might want to do this when passing a handle of the file interface to another application or when you want to keep a file open when using a function that would normally close the file.

You can close a file by using the AVIFileRelease function. AVIFileRelease decrements the reference count of an AVI file, saves changes made to the file, and when the reference count reaches zero, closes the file. Your applications should balance the reference count by including a call to AVIFileRelease for each use of AVIFileOpen and AVIFileAddRef.

Note  An application can open a file with one or more program threads; however, only one thread should access the file at a time for the best possible performance.


Reading from a File

You can retrieve information about an open file by using the AVIFileInfo function. This function fills the AVIFILEINFO structure with information such as the maximum data rate, the number of streams in the file, whether the file uses an index, and whether the file is copyrighted.

You can retrieve supplementary information in an AVI file by using the AVIFileReadData function. Supplementary information is applicable to the entire file and is not included in the normal file headers. For example, the name of the company or person who holds the copyrights of a file could be supplementary information. Supplementary information does not adhere to a specific format; it can be file specific. AVIFileReadData returns the supplementary information in an application-supplied buffer.


Writing to a File

You can write supplementary information to a file that has been opened with write privileges by using the AVIFileWriteData function. This function copies the information from an application-supplied buffer and places it in one or more chunks in the file. The "INFO" chunk is a common RIFF chunk type in which the function stores supplementary information. For a description of RIFF files and their data chunks, see Chapter 15, "File Input and Output."


Using the Clipboard with AVI Files

The clipboard provides convenient, temporary storage for an application to copy or transfer AVI files. AVIFile includes clipboard functions that you can use with disk or memory files.

You can copy a file to the clipboard by using the AVIPutFileOnClipboard function. You can write a file that is on the clipboard to memory or to disk by using the AVIGetFromClipboard function.

You can clear a file from the clipboard by using the AVIClearClipboard function. This function does not clear other types of information, such as text, from the clipboard. If you use clipboard functions in your application, clear the clipboard with AVIClearClipboard before closing the application or closing the file on the clipboard. You can call AVIClearClipboard in your application whether or not AVIPutFileOnClipboard has been used.

Note  If your application copies a file to the clipboard and the file contains stream data that might change, you can create a memory file of cloned streams by using the AVIMakeFileFromStreams function. You can then place the file on the clipboard and then release the original file without invalidating it.


Stream Operations

Most of the features of AVIFile focus on data streams. This section describes the functions and macros that deal with streams and stream data.


Opening and Closing Streams

Opening data streams is similar to opening files. You can open a stream by using the AVIFileGetStream function. This function creates a stream interface, places a handle of the stream in the interface, and returns a pointer to the interface. AVIFileGetStream also maintains a reference count of the applications that have opened a stream, but not of those that have closed it.

If you want to access a single stream in a file, you can open the file and the stream by using the AVIStreamOpenFromFile function. This function combines the operations and function arguments of the AVIFileOpen and AVIFileGetStream functions.

If you want to access more than one stream in a file, you can use AVIFileOpen once followed by multiple calls to AVIFileGetStream.

You can increment the reference count of a stream by using the AVIStreamAddRef function to keep a stream open when using a function that would normally close the stream.

You can close a stream by using the AVIStreamRelease function. This function decrements the reference count of the stream and closes it when the reference count reaches zero. Your applications should balance the reference count by including a call to AVIStreamRelease for each use of the AVIFileGetStream, AVIFileCreateStream, AVIStreamAddRef, or AVIStreamOpenFromFile function. When you release a stream that has been opened by using AVIStreamOpenFromFile, AVIFile closes the file containing the stream. If your application releases a file that has open data streams, AVIFile will not close the streams until all of the streams are released.


Reading from a Stream

You can retrieve information about an open stream by using the AVIStreamInfo function. This function fills the AVISTREAMINFO structure with information such as the type of data in the stream, the compression method used when writing stream data, the suggested buffer size, the playback rate, and a text description of the stream.

Some members of the AVISTREAMINFO structure are also present in the AVIFILEINFO structure. The information in the AVIFILEINFO structure applies to the entire file. The information in the AVISTREAMINFO structure is specific to the accessed stream and has precedence over the information in the AVIFILEINFO structure.

If a stream has supplementary information associated with it, you can retrieve this information by using the AVIStreamReadData function. AVIStreamReadData returns the information in an application-supplied buffer. Supplementary stream information might include configuration settings for the compression and decompression methods used on a stream. You can obtain the required buffer size by using the AVIStreamDataSize macro.

You can retrieve formatting information about a stream by using the AVIStreamReadFormat function. This function returns a stream-specific structure in an application-supplied buffer. For a video stream, the buffer contains formatting information in a BITMAPINFO structure. For an audio stream, the buffer contains formatting information in a WAVEFORMATEX or PCMWAVEFORMAT structure. For other stream types, the stream handler returns information specific to the stream. You can determine the required buffer size by using AVIStreamReadFormat and specifying a NULL buffer address or by using the AVIStreamFormatSize macro.

You can retrieve the multimedia content in a stream by using the AVIStreamRead function. This function copies raw data from the stream into an application-supplied buffer. For video streams, this function retrieves the bitmapped images that make up the frame content. For audio streams, this function retrieves waveform-audio samples that make up the sound content. You can determine the required buffer size by using AVIStreamRead and specifying a NULL buffer address or by using the AVIStreamSampleSize macro.

Some AVI stream handlers introduce delays associated with software and hardware initialization or coordination. You can inform these handlers to prepare for data streaming by using the AVIStreamBeginStreaming function. This function lets the stream handler allocate the resources it needs and initialize them. You can also inform these handlers when streaming has ended by using the AVIStreamEndStreaming function. This function lets the stream handler deallocate the resources it allocated for AVIStreamBeginStreaming.

AVIStreamRead does not provide decompression services. For information about compressing and decompressing audio streams, see Chapter 12, "Audio Compression Manager." For information about compressing and decompressing video streams, see Chapter 7, "Video Compression Manager." For information about compressing and decompressing individual frames in a video stream, see "Working with Compressed Video Data in a Stream" later in this chapter.


Working with Compressed Video Data in a Stream

AVIFile provides several ways for you to access compressed video streams.

If you want to display one or more frames of a compressed video stream, you can retrieve the frames by using the AVIStreamRead function and forwarding the compressed frame data to DrawDib functions to display them. DrawDib functions can display images of several image depths and automatically dither images for displays that cannot handle certain types of device-independent bitmaps (DIBs). These functions work with uncompressed and compressed images. For more information about DrawDib functions, see Chapter 10, "DrawDib Functions ."

AVIFile provides functions for decompressing a single video frame. You can allocate resources by using the AVIStreamGetFrameOpen function. This function creates a buffer for the decompressed data.

You can decompress a single video frame by using the AVIStreamGetFrame function. This function decompresses the frame and retrieves a complete frame of image data and returns the address of the DIB in the BITMAPINFOHEADER structure. Your application can display the DIB by using standard Microsoft Win32 drawing functions or by using the DrawDib functions.

If your application makes successive calls to AVIStreamGetFrame, the function overwrites its buffer with each retrieved frame.

When you finish using AVIStreamGetFrame and the decompressed DIB is in its buffer, you can release the allocated resources by using the AVIStreamGetFrameClose function.

For more information about decompressing images, see Chapter 7, "Video Compression Manager."


Creating a File from Existing Streams

One way to create a file that contains data streams is to combine existing streams into a new file. The streams that provide data for the new file can reside in memory or in one or more files.

You can build a file from several streams by using the AVISave function. This function creates a file and writes the data streams specified in its calling sequence to the file. The calling sequence for AVISave uses a variable number of arguments that include interfaces for the streams combined in the new file.

You can also combine data streams in a new file by using the AVISaveV function. This function provides the same functionality as AVISave, but when you use AVISaveV, your application specifies the data streams as an array, not as a variable number of arguments.

You can create a dialog box in which the user can select compression settings for the new file by using the AVISaveOptions function. The dialog box displays the current compression settings and lets the user edit them. Compression setting changes are stored in an AVICOMPRESSOPTIONS structure.

You can also include a callback function with AVISave and AVISaveV that your application can use to display the progress of writing the file and, if needed, let the user cancel the save operation. You can include the address of the callback function in the calling sequence of AVISave or AVISaveV.

You can let the user select a filename for the new file by using the GetSaveFileNamePreview function. This function displays the Save As dialog box in which the user can preview the first stream (normally the video stream) of an AVI file.

You can create a file interface pointer (and a virtual file) for a group of streams by using the AVIMakeFileFromStreams function. Other AVIFile functions can use the file interface pointer returned by this function to access the streams in the virtual file. When you finish using the virtual file, delete the file interface pointer by using the AVIFileRelease function.

Note  To minimize image and audio degradation, avoid compressing an AVI file more than once. Combine uncompressed pieces of video in your editing system and then compress the final product. For information about compression options, see Chapter 7, "Video Compression Manager."


Writing Streams to a File

You can also create a file containing data streams by writing a new data stream to a file.

You can create a new stream in a new or existing file by using the AVIFileCreateStream function. This function defines a new stream according to the characteristics described in an AVISTREAMINFO structure, creates a stream interface for the new stream, increments the reference count of the stream, and returns the address of the stream-interface pointer.

Before you write the content of the stream, you must specify the stream format. You can set the stream format by using the AVIStreamSetFormat function. When setting the format of a video stream, you must supply this function with a BITMAPINFO structure containing the appropriate information. When setting the format of an audio stream, you must supply a WAVEFORMAT or WAVEFORMATEX structure containing the appropriate information. The information you need to supply to the function for other stream types depends on the stream type and the stream handler.

You can write the multimedia content in a stream by using the AVIStreamWrite function. This function copies raw data from an application-supplied buffer into the specified stream. The default AVI file handler appends information to the end of a stream. The default WAVE handler can write waveform-audio data within a stream as well as at the end of a stream.

You can write supplementary information about the file or stream that is not included in the AVIFileCreateStream or AVIStreamSetFormat function by using the AVIFileWriteData and AVIStreamWriteData functions. You can record data that is applicable to the entire file, such as copyright information and modification history, by using AVIFileWriteData. You can record stream-specific information, such as compression and decompression settings, by using AVIStreamWriteData. The supplementary information is stored in separate chunks within the file.

You can close the stream after you finish writing to the new stream by using the AVIStreamRelease function. This function clears buffers used in recording the stream data, and it completes and closes any incomplete data chunks in the file.


Positioning in Streams

AVIFile provides several ways to locate and move to a position in a data stream. The functions and macros in this section let your application find the starting position, length, and key frames (containing a complete image in the sample) within a stream. The functions and macros also associate time with positions in a stream by calculating the elapsed time needed to play a stream from its beginning to any point in a stream.

Finding the Starting Position

You can retrieve the sample number of the first frame in a video stream by using the AVIStreamStart function. (The frames of a movie might start at sample 0 or 1 depending on the preference of the author.) You can also obtain this information by using the AVIStreamInfo function. This function stores the sample number in the dwStart member of the AVISTREAMINFO structure. You can retrieve the starting time of a stream's first sample by using the AVIStreamStartTime macro.

You can retrieve the stream length by using the AVIStreamLength function. This function returns the number of samples in the stream. You can also obtain this information by using the AVIStreamInfo function. This function stores the stream length in the dwLength member of the AVISTREAMINFO structure. You can retrieve the length of a stream in milliseconds by using the AVIStreamLengthTime macro.

In a video stream, each sample generally corresponds to a frame of video. There might, however, be samples for which no video data is present. If you call the AVIStreamRead function specifying one of those positions, it returns a data length of 0 bytes. You can find samples that contain data by using the AVIStreamFindSample function and specifying the FIND_ANY flag.

In an audio stream, each sample corresponds to one data block of audio data. For example, if the audio data has a 22 kHz ADPCM (Adaptive Differential Pulse Code Modulation) format, each sample for AVIStreamLength corresponds to a block of 256 bytes of compressed audio data. This block of audio data contains approximately 500 audio samples when uncompressed. The functions and macros of AVIFile, however, treat each 256-byte block as a single sample.

Note  Valid positions within a stream range from the beginning to the end of the stream, which is the sum of the stream starting point and its length. The position represented by the sum of the starting position and the length corresponds to a time after the last data has been rendered; it does not contain any data. You can retrieve the sample number that represents the end of the stream by using the AVIStreamEnd macro. You can retrieve the time value in milliseconds that represents the end of the stream by using the AVIStreamEndTime macro.

Finding Sample and Key Frames

You can search for different types of samples in a stream by using the AVIStreamFindSample function. This function searches backward or forward through a stream for a sample of the appropriate type, beginning with the sample number you specify. You can search for different types of samples in a stream by specifying a flag in the AVIStreamFindSample calling sequence. Specify the FIND_ANY flag to locate nonempty samples or to skip samples that lack data. Specify the FIND_KEY flag to search for key frames that contain the data to render a complete image without needing to reference previous frames. Specify the FIND_FORMAT flag to search for changes to the format. AVIStreamFindSample is used mainly with video streams.

Several macros that use AVIFile functions supplement the stream search features. The following list provides a brief description of each macro. The macros that search for a specific position or type of data require a starting location to be specified in the stream.

Macro	Description
AVIStreamIsKeyFrame	Indicates whether a sample in a specified stream is a key frame.
AVIStreamNearestKeyFrame	Locates the key frame at or preceding a specified position in a stream.
AVIStreamNearestKeyFrameTime	Determines the time corresponding to the beginning of the key frame nearest (at or preceding) a specified time in a stream.
AVIStreamNearestSample	Locates the nearest nonempty sample at or preceding a specified position in a stream.
AVIStreamNearestSampleTime	Determines the time corresponding to the beginning of a sample that is nearest to a specified time in a stream.
AVIStreamNextKeyFrame	Locates the next key frame following a specified position in a stream.
AVIStreamNextKeyFrameTime	Returns the time of the next key frame in a stream, starting at a given time.
AVIStreamNextSample	Locates the next nonempty sample from a specified position in a stream.
AVIStreamNextSampleTime	Returns the time that a sample changes to the next sample in the stream. This macro finds the next interesting time in a stream.
AVIStreamPrevKeyFrame	Locates the key frame that precedes a specified position in a stream.
AVIStreamPrevKeyFrameTime	Returns the time of the previous key frame in the stream, starting at a given time.
AVIStreamPrevSample	Locates the nonempty sample that precedes a specified position in a stream.
AVIStreamPrevSampleTime	Determines the time that the previous sample replaces its predecessor in the stream.
AVIStreamSampleToSample	Returns the sample in a stream that occurs at the same time as a sample that occurs in a second stream.
Switching Between Samples and Time

You can determine the elapsed time from the beginning of a stream to a sample using the AVIStreamSampleToTime function. This function converts the sample number to a time value expressed in milliseconds. For a video frame (which spans several milliseconds), this value represents the time the sample begins to play since playback began and assumes the video clip plays at normal speed. For an audio sample (which has several samples in a millisecond), the time value corresponds to the time the sample begins to play and assumes the audio stream plays at normal speed.

Conversely, you can find the sample number associated with a time value by using the AVIStreamTimeToSample function. This function converts the millisecond value to a sample number and assumes the video clip plays at normal speed.

Because AVIStreamSampleToTime returns the time a frame begins to play, AVIStreamSampleToTime and AVIStreamTimeToSample are not true inverses. They more accurately determine the position in a file than time. For example, two consecutive audio samples might both play in the same millisecond. Using AVIStreamSampleToTime to convert the sample numbers would result in identical time values. If you convert the time value back to a sample number by using AVIStreamTimeToSample, a single sample would be referenced.


Creating Temporary Streams

Temporary streams can be beneficial in several ways. You can use a temporary stream as a work stream, such as when changing the stream format. Or you can create a temporary stream to hold portions of other streams that have been copied.

You can create a stream in memory that is not associated with any file by using the AVIStreamCreate function. This function returns the address of the interface to the new stream in a specified location and is used internally by other functions that create temporary streams.

You can create a compressed stream from an uncompressed stream by using the AVIMakeCompressedStream function. You identify the stream to compress, the compression method and compression options, and the handler for the new stream.

When you finish using a stream created with AVIStreamCreate or AVIMakeCompressedStream, close the stream by using the AVIStreamRelease function. AVIStreamRelease frees the resources the temporary stream used.


Editing Streams

You can create a stream that you can edit by using the CreateEditableStream function. This function initializes the environment for editing a stream. This includes creating an interface to the new stream and internal edit tables that track changes made to the stream. CreateEditableStream returns a stream pointer to an editable stream that is required by other stream editing functions. The editable stream pointer can also be used by other AVIFile functions that accept stream pointers.

You can cut one or more samples from an editable stream by using the EditStreamCut function. This function adds an entry to the edit table to remove the samples from the editable stream and then places a copy of the cut samples in a new temporary stream whose interface pointer is returned in a variable.

You can copy one or more samples from an editable stream into a temporary stream by using the EditStreamCopy function. EditStreamCopy places copies of the samples in a new temporary stream whose interface pointer is returned in a variable.

You can copy one or more samples from a stream and paste them into an editable stream by using the EditStreamPaste function. This function adds an entry in the edit table of the target editable stream to insert the samples at the specified position.

You can duplicate an editable stream by using the EditStreamClone function. This function returns a pointer to the stream interface of the new stream. You can copy these streams to the clipboard or use them to maintain a trail of edits made to a stream.

You can change several of the characteristics of an editable stream by using the EditStreamSetInfo function. This function updates the priority setting, language, scale and rate, starting time, quality setting, destination rectangle dimensions and coordinates, and the textual description of the stream. These items are stored in the AVISTREAMINFO structure associated with the editable stream.

You can also change the textual description of an editable stream by using the EditStreamSetName function. This function updates the szName member of the AVISTREAMINFO structure associated with the editable stream.

The editing functions work on streams. You need to cut and paste each stream individually, and then use the AVIMakeFileFromStreams function to create a new file pointer.

Note  The edit tables in an editable stream maintain all the changes for a stream. The source stream is never changed.


Using AVIFile Functions and Macros

This section contains examples demonstrating how to perform the following tasks:

•	Open an AVI file.

•	Open streams in an AVI file and close the file.

•	Read streams from an AVI file.

•	Read from one stream and write to another.

•	Use the editing functions and put a file on the clipboard.


Opening an AVI File

The following example initializes the AVIFile library and opens an AVI file. The function uses a default file handler:

// LoadAVIFile - loads AVIFile and opens an AVI file.

//

// szfile - filename

// hwnd - window handle

//

VOID LoadAVIFile(LPCSTR szFile, HWND hwnd)

{

    LONG hr;

    PAVIFILE *pfile;

    AVIFileInit();          // opens AVIFile library

    hr = AVIFileOpen(&pfile, szFile, OF_SHARE_DENY_WRITE, 0L);

    if (hr != 0){

        ErrMsg("Unable to open %s", szFile);

        return;

    }

//  .

//  . Place functions here that interact with the open file.

//  .

    AVIFileRelease(pfile);  // closes the file

    AVIFileExit();          // releases AVIFile library

}


Opening Streams in an AVI File and Closing the File

The following example opens all the streams in an AVI file. If an error is encountered, the file is closed.

// InsertAVIFile - opens the streams in an AVI file.

//

// pfile - file-interface pointer from AVIFileOpen

//

// Global variables

// gcpavi - count of the number of streams in an AVI file

// gapavi[] = array of stream-interface pointers

void InsertAVIFile(PAVIFILE pfile, HWND hwnd, LPSTR lpszFile)

{

    int    i;

    gcpavi = 0;

    // Open the streams until a stream is not available.

    for (i = gcpavi; i < MAXNUMSTREAMS; i++) {

        gapavi[i] = NULL;

        if (AVIFileGetStream(pfile, &gapavi[i], 0L, i - gcpavi)
            != AVIERR_OK)

        break;

    if (gapavi[i] == NULL)

        break;

    }

    // Display error message-stream not found.

    if (gcpavi == i)

    {

        ErrMsg("Unable to open %s", lpszFile);

        if (pfile) // If file is open, close it

        AVIFileRelease(pfile);

        return;

    }

    else {

        gcpavi = i - 1;

    }

//  .

//  . Place functions to process data here.

//  .

}


Reading Streams from an AVI File

The following subroutine obtains stream information from an AVI file and determines the stream type from the AVISTREAMINFO structure.

// StreamTypes - opens the streams in an AVI file and determines

// stream types.

//

// Global variables

// gcpavi - count of streams in an AVI file

// gapavi[] = array of stream-interface pointers

void StreamTypes(HWND hwnd)

{

    AVISTREAMINFO     avis;

    LONG    r, lHeight = 0;

    WORD    w;

    int     i;

    RECT    rc;

// Walk through all streams.

    for (i = 0; i < gcpavi; i++) {

        AVIStreamInfo(gapavi[i], &avis, sizeof(avis));

        if (avis.fccType == streamtypeVIDEO) {

        // Place video-processing functions here.

        }

        else if (avis.fccType == streamtypeAUDIO) {

        // Place audio-processing functions here.

        }

        else if (avis.fccType == streamtypeTEXT) {

        // Place text-processing functions here.

        }

    .

    .

    .

    }

}


Reading from One Stream and Writing to Another

The following example reads data from a stream, compresses it into a new stream, and writes the compressed data into a stream of a new file.

// SaveSmall - copies a stream of data from one file, compresses

// the stream, and writes the compressed stream to a new file.

//

// ps stream interface pointer

// lpFilename - new AVI file to build

//

void SaveSmall(PAVISTREAM ps, LPSTR lpFilename)

{

    PAVIFILE         pf;

    PAVISTREAM       psSmall;

    HRESULT          hr;

    AVISTREAMINFO    strhdr;

    BITMAPINFOHEADER bi;

    BITMAPINFOHEADER biNew;

    LONG             lStreamSize;

    LPVOID           lpOld;

    LPVOID           lpNew;

    // Determine the size of the format data.

    AVIStreamFormatSize(ps, 0, &lStreamSize);

    if (lStreamSize > sizeof(bi)) // Format larger than space allocated?

        return;

    lStreamSize = sizeof(bi);

    hr = AVIStreamReadFormat(ps, 0, &bi, &lStreamSize); // Read format

    if (bi.biCompression != BI_RGB) // Wrong compression format?

        return;

    hr = AVIStreamInfo(ps, &strhdr, sizeof(strhdr));

    // Create new AVI file.

    hr = AVIFileOpen(&pf, lpFilename, OF_WRITE | OF_CREATE, NULL);

    if (hr != 0)

        return;

    // Set parameters for the new stream.

    biNew = bi;

    biNew.biWidth /= 2;

    biNew.biHeight /= 2;

    biNew.biSizeImage = ((((UINT)biNew.biBitCount * biNew.biWidth
                        + 31)&~31) / 8) * biNew.biHeight;

    SetRect(&strhdr.rcFrame, 0, 0, (int) biNew.biWidth,
            (int) biNew.biHeight);

    // Create a stream.

    hr = AVIFileCreateStream(pf, &psSmall, &strhdr);

    if (hr != 0) {            //Stream created OK? If not close file.

        AVIFileRelease(pf);

        return;

    }

    // Set format of new stream.

    hr = AVIStreamSetFormat(psSmall, 0, &biNew, sizeof(biNew));

    if (hr != 0) {

        AVIStreamRelease(psSmall);

        AVIFileRelease(pf);

        return;

    }

    // Allocate memory for the bitmaps.

    lpOld = GlobalAllocPtr(GMEM_MOVEABLE, bi.biSizeImage);

    lpNew = GlobalAllocPtr(GMEM_MOVEABLE, biNew.biSizeImage);

    // Read the stream data.

    for (lStreamSize = AVIStreamStart(ps); lStreamSize <
        AVIStreamEnd(ps); lStreamSize++) {

        hr = AVIStreamRead(ps, lStreamSize, 1, lpOld, bi.biSizeImage,
            NULL, NULL);

        //  .

        //  . Place error check here.

        //  .

        // Compress the data.

        CompressDIB(&bi, lpOld, &biNew, lpNew);

        // Save the compressed data.

        hr = AVIStreamWrite(psSmall, lStreamSize, 1, lpNew,
            biNew.biSizeImage, AVIIF_KEYFRAME, NULL, NULL);

    }

     // Close the stream and file.

    AVIStreamRelease(psSmall);

    AVIFileRelease(pf);

}


Using the Editing Functions and Putting a File on the Clipboard

The following example cuts, copies, or deletes segments from an array of streams. The cut and copied streams are merged into a new file and placed on the clipboard.

// Global variables

// gcpavi - count of streams in an AVI file

// gapavi[] - array of stream-interface pointers, used as data source

// gapaviSel[] - stream-interface pointers of edited streams

// galSelStart[] - edit starting point in each stream

// galSelLen[] - length of edit to make in each stream

// gapaviTemp[] - array of stream-interface pointers put on clipboard

//

// Comment:

//     The editable streams in gapaviSel have been

//     initialized with CreateEditableStream.

//

case MENU_CUT:

case MENU_COPY:

case MENU_DELETE:

{

    PAVIFILE pf;

    int      i;

    // Walk list of selections and make streams out of each section.

    gcpaviSel = 0;  // index counter for destination streams

    for (i = 0; i < gcpavi; i++) {

        if (galSelStart[i] != -1) {

            if (wParam == MENU_COPY)

                EditStreamCopy(gapavi[i], &galSelStart[i],

                &galSelLen[i], &gapaviSel[gcpaviSel++]);

            else {

                EditStreamCut(gapavi[i], &galSelStart[i],

                &galSelLen[i], &gapaviSel[gcpaviSel++]);

            }

        }

    }

.

.

.

    // Put on the clipboard if segment is not deleted.

    if (gcpaviSel && wParam != MENU_DELETE) {

        PAVISTREAM   gapaviTemp[MAXNUMSTREAMS];

        int i;

        // Clone the edited streams, so that if the user does

        // more editing, the clipboard won't change.

        for (i = 0; i < gcpaviSel; i++) {

            gapaviTemp[i] = NULL;

            EditStreamClone(gapaviSel[i], &gapaviTemp[i]);

            //  .

            //  . Place error check here.

            //  .

        }

        // Create a file from the streams and put on clipboard.

        AVIMakeFileFromStreams(&pf, gcpaviSel, gapaviTemp);

        AVIPutFileOnClipboard(pf);

        // Release clone streams.

        for (i = 0; i < gcpaviSel; i++) {

            AVIStreamRelease(gapaviTemp[i]);

        }

        // Release file put on clipboard.

        AVIFileRelease(pf);

    }

    // Release streams created.

    for (i = 0; i < gcpaviSel; i++)

        AVIStreamRelease(gapaviSel[i]);

.

.

.

}


AVIFile Reference

This section describes the functions, macros, and structures for applications using the AVIFile services. These elements are grouped as follows:

AVIFile Library Operations

AVIFileInit
AVIFileExit

Opening and Closing AVI Files

AVIFileOpen
AVIFileAddRef
AVIFileRelease
GetOpenFileNamePreview

Reading from a File

AVIFileInfo
AVIFILEINFO
AVIFileReadData

Writing to a File

AVIFileWriteData

Using the Clipboard

AVIPutFileOnClipboard
AVIGetFromClipboard
AVIClearClipboard

Opening and Closing Streams

AVIFileGetStream
AVIStreamOpenFromFile
AVIStreamAddRef
AVIStreamRelease

Reading Stream Information

AVISTREAMINFO
AVIStreamReadData
AVIStreamDataSize
AVIStreamReadFormat
AVIStreamFormatSize
AVIStreamRead
AVIStreamSampleSize
AVIStreamBeginStreaming
AVIStreamEndStreaming

Decompressing Video Data in a Stream

AVIStreamGetFrameOpen
AVIStreamGetFrame
AVIStreamGetFrameClose

Creating a File from Existing Streams

AVISave
AVISaveV
AVISaveOptions
GetSaveFileNamePreview
AVIMakeFileFromStreams

Writing Individual Streams

AVIFileCreateStream
AVIStreamSetFormat
AVIStreamWrite
AVIFileWriteData
AVIStreamWriteData
AVIStreamRelease

Finding the Starting Position in a Stream

AVIStreamStart
AVIStreamStartTime
AVIStreamLength
AVIStreamLengthTime
AVIStreamFindSample
AVIStreamEnd
AVIStreamEndTime

Finding Sample and Key Frames

AVIStreamFindSample
AVIStreamIsKeyFrame
AVIStreamNearestKeyFrame
AVIStreamNearestKeyFrameTime
AVIStreamNearestSample
AVIStreamNearestSampleTime
AVIStreamNextKeyFrame
AVIStreamNextKeyFrameTime
AVIStreamNextSample
AVIStreamNextSampleTime
AVIStreamPrevKeyFrame
AVIStreamPrevKeyFrameTime
AVIStreamPrevSample
AVIStreamPrevSampleTime
AVIStreamSampleToSample

Switching Between Samples and Time

AVIStreamSampleToTime
AVIStreamTimeToSample

Creating Temporary Streams

AVIStreamCreate
AVIMakeCompressedStream
AVIStreamRelease

Editing AVI Streams

CreateEditableStream
EditStreamCut
EditStreamCopy
EditStreamPaste
EditStreamClone
EditStreamSetInfo
EditStreamSetName


AVIBuildFilter

STDAPI AVIBuildFilter(LPTSTR lpszFilter, LONG cbFilter, BOOL fSaving);

Builds a filter specification that is subsequently used by the GetOpenFileName or GetSaveFileName function.

•	Returns AVIERR_OK if successful or an error otherwise. The following error values are defined:

AVIERR_BUFFERTOOSMALL	The buffer size cbFilter was smaller than the generated filter specification.
AVIERR_MEMORY	There was not enough memory to complete the read operation.
lpszFilter

Address of the buffer containing the filter string.

cbFilter

Size, in bytes, of buffer pointed to by lpszFilter.

fSaving

Flag that indicates whether the filter should include read or write formats. Specify TRUE to include write formats or FALSE to include read formats.

This function accesses the registry for all filter types that the AVIFile library can use to open, read, or write multimedia files. It does not search the hard disk for filter DLLs and formats.


AVIClearClipboard

STDAPI AVIClearClipboard(VOID);

Removes an AVI file from the clipboard.

•	Returns zero if successful or an error otherwise.


AVIFileAddRef

STDAPI_(ULONG) AVIFileAddRef(PAVIFILE pfile);

Increments the reference count of an AVI file.

•	Returns the updated reference count for the file interface.

pfile

Handle of an open AVI file.


AVIFileCreateStream

STDAPI AVIFileCreateStream(PAVIFILE pfile, PAVISTREAM FAR * ppavi,
    AVISTREAMINFO FAR * psi);

Creates a new stream in an existing file and creates an interface to the new stream.

•	Returns zero if successful or an error otherwise. Unless the file has been opened with write permission, this function returns AVIERR_READONLY.

pfile

Handle of an open AVI file.

ppavi

Address of the new stream interface.

psi

Address of a structure containing information about the new stream, including the stream type and its sample rate.

This function starts a reference count for the new stream.


AVIFileEndRecord

STDAPI AVIFileEndRecord(PAVIFILE pfile);

Marks the end of a record when writing an interleaved file that uses a 1:1 interleave factor of video to audio data. (Each frame of video is interspersed with an equivalent amount of audio data.)

•	Returns zero if successful or an error otherwise.

pfile

Handle of an open AVI file.

The AVISave function uses this function internally. In general, applications should not need to use this function.


AVIFileExit

STDAPI_(VOID) AVIFileExit(VOID);

Exits the AVIFile library and decrements the reference count for the library.

This function supercedes the obsolete AVIStreamExit function.


AVIFileGetStream

STDAPI AVIFileGetStream(PAVIFILE pfile, PAVISTREAM FAR * ppavi,
    DWORD fccType, LONG lParam);

Returns the address of a stream interface that is associated with a specified AVI file.

•	Returns zero if successful or an error otherwise. Possible error values include the following:

AVIERR_NODATA	The file does not contain a stream corresponding to the values of fccType and lParam.
AVIERR_MEMORY	Not enough memory.
pfile

Handle of an open AVI file.

ppavi

Address of the new stream interface.

fccType

Four-character code indicating the type of stream to open. Zero indicates any stream can be opened. The following definitions apply to the data commonly found in AVI streams:

streamtypeAUDIO	Indicates an audio stream.
streamtypeMIDI	Indicates a MIDI stream.
streamtypeTEXT	Indicates a text stream.
streamtypeVIDEO	Indicates a video stream.
lParam

Count of the stream type. Identifies which occurrence of the specified stream type to access.


AVIFileInfo

STDAPI AVIFileInfo(PAVIFILE pfile, AVIFILEINFO FAR * pfi, LONG lSize);

Obtains information about an AVI file.

•	Returns zero if successful or an error otherwise.

pfile

Handle of an open AVI file.

pfi

Address of the structure used to return file information. Typically, this parameter points to an AVIFILEINFO structure.

lSize

Size, in bytes, of the structure.


AVIFileInit

STDAPI_(VOID) AVIFileInit(VOID);

Initializes the AVIFile library.

The AVIFile library maintains a count of the number of times it is initialized, but not the number of times it was released. Use the AVIFileExit function to release the AVIFile library and decrement the reference count. Call AVIFileInit before using any other AVIFile functions.

This function supercedes the obsolete AVIStreamInit function.


AVIFileOpen

STDAPI AVIFileOpen(PAVIFILE FAR * ppfile, LPCTSTR szFile,
    UINT mode, CLSID FAR * pclsidHandler);

Opens an AVI file and returns the address of a file interface used to access it. The AVIFile library maintains a count of the number of times a file is opened, but not the number of times it was released. Use the AVIFileRelease function to release the file and decrement the count.

•	Returns zero if successful or an error otherwise. Possible error values include the following:

AVIERR_BADFORMAT	The file couldn't be read, indicating a corrupt file or an unrecognized format.
AVIERR_MEMORY	The file could not be opened because of insufficient memory.
AVIERR_FILEREAD	A disk error occurred while reading the file.
AVIERR_FILEOPEN	A disk error occurred while opening the file.
REGDB_E_CLASSNOTREG	According to the registry, the type of file specified in AVIFileOpen does not have a handler to process it.
ppfile

Address to contain the new file interface pointer.

szFile

Null-terminated string containing the name of the file to open.

mode

Access mode to use when opening the file. The default access mode is OF_READ. The following access modes can be specified with AVIFileOpen:

OF_CREATE

Creates a new file. If the file already exists, it is truncated to zero length.

OF_SHARE_DENY_NONE

Opens the file nonexclusively. Other processes can open the file with read or write access. AVIFileOpen fails if another process has opened the file in compatibility mode.

OF_SHARE_DENY_READ

Opens the file nonexclusively. Other processes can open the file with write access. AVIFileOpen fails if another process has opened the file in compatibility mode or has read access to it.

OF_SHARE_DENY_WRITE

Opens the file nonexclusively. Other processes can open the file with read access. AVIFileOpen fails if another process has opened the file in compatibility mode or has write access to it.

OF_SHARE_EXCLUSIVE

Opens the file and denies other processes any access to it. AVIFileOpen fails if any other process has opened the file.

OF_READ

Opens the file for reading.

OF_READWRITE

Opens the file for reading and writing.

OF_WRITE

Opens the file for writing.

pclsidHandler

Address of a class identifier of the standard or custom handler you want to use. If the value is NULL, the system chooses a handler from the registry based on the file extension or the RIFF type specified in the file.


AVIFileReadData

STDAPI AVIFileReadData(PAVIFILE pfile, DWORD ckid, LPVOID lpData,
    LONG FAR * lpcbData);

Reads optional header data that applies to the entire file, such as author or copyright information.

•	Returns zero if successful or an error otherwise. The return value AVIERR_NODATA indicates that data with the requested chunk identifier does not exist.

pfile

Handle of an open AVI file.

ckid

RIFF chunk identifier (four-character code) of the data.

lpData

Address of the buffer used to return the data read.

lpcbData

Address of a location indicating the size of the memory block referenced by lpData. If the data is read successfully, the value is changed to indicate the amount of data read.

The optional header information is custom and does not have a set format.


AVIFileRelease

STDAPI_(ULONG) AVIFileRelease(PAVIFILE pfile);

Decrements the reference count of an AVI file interface handle and closes the file if the count reaches zero.

•	Returns the reference count of the file. This return value should be used only for debugging purposes.

pfile

Handle of an open AVI file.

This function supercedes the obsolete AVIFileClose function.


AVIFileWriteData

STDAPI AVIFileWriteData(PAVIFILE pfile, DWORD ckid, LPVOID lpData,
    LONG cbData);

Writes supplementary data (other than normal header, format, and stream data) to the file.

•	Returns zero if successful or an error otherwise. If an application has read-only access to the file, the error code AVIERR_READONLY is returned.

pfile

Handle of an open AVI file.

ckid

RIFF chunk identifier (four-character code) of the data.

lpData

Address of the buffer used to write the data.

cbData

Size, in bytes, of the memory block referenced by lpData.

Use the AVIStreamWriteData function to write data that applies to an individual stream.


AVIGetFromClipboard

STDAPI AVIGetFromClipboard(PAVIFILE * lppf);

Copies an AVI file from the clipboard.

•	Returns zero if successful or an error otherwise.

lppf

Address of the location used to return the handle created for the AVI file.

If the clipboard does not contain an AVI file, AVIGetFromClipboard also can copy data with the CF_DIB or CF_WAVE clipboard flags to an AVI file. In this case, the function creates an AVI file with one DIB stream and one waveform-audio stream, and fills each stream with the data from the clipboard.


AVIMakeCompressedStream

STDAPI AVIMakeCompressedStream(PAVISTREAM FAR * ppsCompressed,
    PAVISTREAM psSource, AVICOMPRESSOPTIONS FAR * lpOptions,
    CLSID FAR * pclsidHandler);

Creates a compressed stream from an uncompressed stream and a compression filter, and returns the address of a pointer to the compressed stream. This function supports audio and video compression.

•	Returns AVIERR_OK if successful or an error otherwise. Possible error values include the following:

AVIERR_NOCOMPRESSOR	A suitable compressor cannot be found.
AVIERR_MEMORY	There is not enough memory to complete the operation.
AVIERR_UNSUPPORTED	Compression is not supported for this type of data. This error might be returned if you try to compress data that is not audio or video.
ppsCompressed

Address to contain the compressed stream pointer.

psSource

Address of the stream to be compressed.

lpOptions

Address of a structure that identifies the type of compression to use and the options to apply. You can specify video compression by identifying an appropriate handler in the AVICOMPRESSOPTIONS structure. For audio compression, specify the compressed data format.

pclsidHandler

Address of a class identifier used to create the stream.

Applications can read from or write to the compressed stream.


AVIMakeFileFromStreams

STDAPI AVIMakeFileFromStreams(PAVIFILE FAR * ppfile,
    int nStreams, PAVISTREAM FAR * papStreams);

Constructs an AVIFile interface pointer from separate streams.

•	Returns zero if successful or an error otherwise.

ppfile

Address to contain the new file interface pointer.

nStreams

Count of the number of streams in the array of stream interface pointers referenced by papStreams.

papStreams

Address of an array of stream interface pointers.

Use the AVIFileRelease function to close the file.

Other functions can use the AVIFile interface created by this function to copy and edit the streams associated with the interface. For example, you can retrieve a specific stream by using AVIFileGetStream with the file interface pointer.


AVIMakeStreamFromClipboard

SDTAPI AVIMakeStreamFromClipboard(UINT cfFormat,
    HANDLE hGlobal, PAVISTREAM FAR * ppstream);

Creates an editable stream from stream data on the clipboard.

•	Returns zero if successful or an error otherwise.

cfFormat

Clipboard flag.

hGlobal

Handle of stream data on the clipboard.

ppstream

Handle of the created stream.

When an application finishes using the editable stream, it must release the stream to free the resources associated with it.


AVIPutFileOnClipboard

STDAPI AVIPutFileOnClipboard(PAVIFILE pf);

Copies an AVI file to the clipboard.

•	Returns zero if successful or an error otherwise.

pf

Handle of an open AVI file.

This function also copies data with the CF_DIB, CF_PALETTE, and CF_WAVE clipboard flags onto the clipboard using the first frame of the first video stream of the file as a DIB and using the audio stream as CF_WAVE.


AVISave

HRESULT AVISave(LPCTSTR szFile, CLSID FAR * pclsidHandler,
    AVISAVECALLBACK lpfnCallback, int nStreams, PAVISTREAM pavi,
    LPAVICOMPRESSOPTIONS lpOptions, . . .);

Builds a file by combining data streams from other files or from memory.

•	Returns AVIERR_OK if successful or an error otherwise.

szFile

Null-terminated string containing the name of the file to save.

pclsidHandler

Address of the file handler used to write the file. The file is created by calling the AVIFileOpen function using this handler. If a handler is not specified, a default is selected from the registry based on the file extension.

lpfnCallback

Address of a callback function for the save operation.

nStreams

Number of streams saved in the file.

pavi

Address of an AVI stream. This parameter is paired with lpOptions. The parameter pair can be repeated as a variable number of arguments.

lpOptions

Address of an application-defined AVICOMPRESSOPTIONS structure containing the compression options for the stream referenced by pavi. This parameter is paired with pavi. The parameter pair can be repeated as a variable number of arguments.

This function creates a file, copies stream data into the file, closes the file, and releases the resources used by the new file. The last two parameters of this function identify a stream to save in the file and define the compression options of that stream. When saving more than one stream in an AVI file, repeat these two stream-specific parameters for each stream in the file.

A callback function (referenced by using lpfnCallback) can display status information and let the user cancel the save operation. The callback function uses the following format:

LONG FAR PASCAL SaveCallback(int nPercent)

The nPercent parameter specifies the percentage of the file saved.

The callback function should return AVIERR_OK if the operation should continue and AVIERR_USERABORT if the user wishes to abort the save operation.


AVISaveOptions

BOOL AVISaveOptions(HWND hwnd, UINT uiFlags, int nStreams,
    PAVISTREAM FAR * ppavi, LPAVICOMPRESSOPTIONS FAR * plpOptions);

Retrieves the save options for a file and returns them in a buffer.

•	Returns TRUE if the user pressed OK, FALSE for CANCEL, or an error otherwise.

hwnd

Handle of the parent window for the Compression Options dialog box.

uiFlags

Flags for displaying the Compression Options dialog box. The following flags are defined:

ICMF_CHOOSE_KEYFRAME

Displays a Key Frame Every dialog box for the video options. This is the same flag used in the ICCompressorChoose function.

ICMF_CHOOSE_DATARATE

Displays a Data Rate dialog box for the video options. This is the same flag used in ICCompressorChoose.

ICMF_CHOOSE_PREVIEW

Displays a Preview button for the video options. This button previews the compression by using a frame from the stream. This is the same flag used in ICCompressorChoose.

nStreams

Number of streams that have their options set by the dialog box.

ppavi

Address of an array of stream interface pointers. The nStreams parameter indicates the number of pointers in the array.

plpOptions

Address of an array of pointers to AVICOMPRESSOPTIONS structures. These structures hold the compression options set by the dialog box. The nStreams parameter indicates the number of pointers in the array.

This function presents a standard Compression Options dialog box using hwnd as the parent window handle. When the user is finished selecting the compression options for each stream, the options are returned in the AVICOMPRESSOPTIONS structure in the array referenced by plpOptions. The calling application must pass the interface pointers for the streams in the array referenced by ppavi.

An application must allocate memory for the AVICOMPRESSOPTIONS structures and the array of pointers to these structures.


AVISaveOptionsFree

LONG AVISaveOptionsFree(int nStreams, LPAVICOMPRESSOPTIONS
    FAR * plpOptions);

Frees the resources allocated by the AVISaveOptions function.

•	Returns AVIERR_OK.

nStreams

Count of the AVICOMPRESSOPTIONS structures referenced in plpOptions.

plpOptions

Address of an array of pointers to AVICOMPRESSOPTIONS structures. These structures hold the compression options set by the dialog box. The resources allocated by AVISaveOptions for each of these structures will be freed.


AVISaveV

STDAPI AVISaveV(LPCTSTR szFile, CLSID FAR * pclsidHandler,
    AVISAVECALLBACK lpfnCallback, int nStreams, PAVISTREAM FAR * ppavi,
    LPAVICOMPRESSOPTIONS FAR * plpOptions);

Builds a file by combining data streams from other files or from memory.

•	Returns AVIERR_OK if successful or an error otherwise.

szFile

Null-terminated string containing the name of the file to save.

pclsidHandler

Address of the file handler used to write the file. The file is created by calling the AVIFileOpen function using this handler. If a handler is not specified, a default is selected from the registry based on the file extension.

lpfnCallback

Address of a callback function used to display status information and to let the user cancel the save operation.

nStreams

Number of streams to save.

ppavi

Address of an array of pointers to the AVISTREAM function structures. The array uses one pointer for each stream.

plpOptions

Address of an array of pointers to AVICOMPRESSOPTIONS structures. The array uses one pointer for each stream.

This function is equivalent to the AVISave function except the streams are passed in an array instead of as a variable number of arguments.

This function creates a file, copies stream data into the file, closes the file, and releases the resources used by the new file. The last two parameters of this function are arrays that identify the streams to save in the file and define the compression options of those streams.

An application must allocate memory for the AVICOMPRESSOPTIONS structures and the array of pointers to these structures.


AVIStreamAddRef

STDAPI_(LONG) AVIStreamAddRef(PAVISTREAM pavi);

Increments the reference count of an AVI stream.

•	Returns the current reference count of the stream. This value should be used only for debugging purposes.

pavi

Handle of an open AVI stream.


AVIStreamBeginStreaming

STDAPI AVIStreamBeginStreaming(PAVISTREAM pavi, LONG lStart,
    LONG lEnd, LONG lRate);

Specifies the parameters used in streaming and lets a stream handler prepare for streaming.

•	Returns zero if successful or an error otherwise.

pavi

Address of a stream.

lStart

Starting frame for streaming.

lEnd

Ending frame for streaming.

lRate

Speed at which the file is read relative to its natural speed.  Specify 1000 for the normal speed. Values less than 1000 indicate a slower-than-normal speed; values greater than 1000 indicate a faster-than-normal speed.


AVIStreamCreate

STDAPI AVIStreamCreate(PAVISTREAM FAR * ppavi, LONG lParam1,
    LONG lParam2, CLSID FAR * pclsidHandler);

Creates a stream not associated with any file.

•	Returns zero if successful or an error otherwise.

ppavi

Address to contain the new stream interface.

lParam1

Stream-handler specific information.

lParam2

Stream-handler specific information.

pclsidHandler

Address of the class identifier used for the stream.

You should not need to call this function. Some functions, such as CreateEditableStream and AVIMakeCompressedStream, use it internally.


AVIStreamDataSize

AVIStreamDataSize(pavi, fcc, plSize)

Determines the buffer size, in bytes, needed to retrieve optional header data for a specified stream.

•	Returns zero if successful or an error otherwise. The return value AVIERR_NODATA indicates the system could not find any data with the specified four-character code.

pavi

Handle of an open stream.

fcc

Four-character code specifying the stream type.

plSize

Address to contain the buffer size for the optional header data.

The AVIStreamDataSize macro is defined as follows:

#define AVIStreamDataSize(pavi, fcc, plSize) \

    AVIStreamReadData(pavi, fcc, NULL, plSize)


AVIStreamEnd

AVIStreamEnd(pavi)

Calculates the sample associated with the end of a stream.

•	Returns the sample number associated with the end of a stream, or, if an error occurs, one less than the first sample or one less than the stream length.

pavi

Handle of an open stream.

The sample number returned is not a valid sample number for reading data. It represents the end of the file. (The end of the file is equal to the start of the file plus its length.)

The AVIStreamEnd macro is defined as follows:

#define AVIStreamEnd(pavi) \

    (AVIStreamStart(pavi) + AVIStreamLength(pavi))


AVIStreamEndStreaming

STDAPI AVIStreamEndStreaming(PAVISTREAM pavi);

Ends streaming.

•	Returns zero if successful or an error otherwise.

pavi

Address of a stream.

Many stream implementations ignore this function.


AVIStreamEndTime

AVIStreamEndTime(pavi)

Returns the time representing the end of the stream.

•	Returns the time if successful or  − 1 otherwise.

pavi

Handle of an open stream.

The AVIStreamEndTime macro is defined as follows:

#define AVIStreamEndTime(pavi) \

    AVIStreamSampleToTime(pavi, AVIStreamEnd(pavi))


AVIStreamFindSample

STDAPI_(LONG) AVIStreamFindSample(PAVISTREAM pavi, LONG lPos,
    LONG lFlags);

Returns the position of a sample (key frame, nonempty frame, or a frame containing a format change) relative to the specified position.

•	Returns the position of the frame found or -1 if the search is unsuccessful.

pavi

Handle of an open stream.

lPos

Starting frame for the search.

lFlags

Flags that designate the type of frame to locate, the direction in the stream to search, and the type of return information. The following flags are defined:

FIND_ANY

Finds a nonempty frame. This flag supercedes the SEARCH_ANY flag.

FIND_KEY

Finds a key frame. This flag supercedes the SEARCH_KEY flag.

FIND_FORMAT

Finds a format change.

FIND_NEXT

Finds nearest sample, frame, or format change searching forward. The current sample is included in the search. Use this flag with the FIND_ANY, FIND_KEY, or FIND_FORMAT flag. This flag supercedes the SEARCH_FORWARD flag.

FIND_PREV

Finds nearest sample, frame, or format change searching backward. The current sample is included in the search. Use this flag with the FIND_ANY, FIND_KEY, or FIND_FORMAT flag. This flag supercedes the SEARCH_NEAREST and SEARCH_BACKWARD flags.

FIND_FROM_START

Finds first sample, frame, or format change beginning from the start of the stream. Use this flag with the FIND_ANY, FIND_KEY, or FIND_FORMAT flag.

The FIND_KEY, FIND_ANY, and FIND_FORMAT flags are mutually exclusive, as are the FIND_NEXT and FIND_PREV flags.

This function supercedes the obsolete AVIStreamFindKeyFrame function.


AVIStreamFormatSize

AVIStreamFormatSize(pavi, lPos, plSize)

Determines the buffer size, in bytes, needed to store format information for a sample in a stream.

•	Returns zero if successful or an error otherwise.

pavi

Handle of an open stream.

lPos

Position of a sample in the stream.

plSize

Address to contain the buffer size.

The AVIStreamFormatSize macro is defined as follows:

#define AVIStreamFormatSize(pavi, lPos, plSize) \

    AVIStreamReadFormat(pavi, lPos, NULL, plSize)


AVIStreamGetFrame

STDAPI_(LPVOID) AVIStreamGetFrame(PGETFRAME pgf, LONG lPos);

Returns the address of a decompressed video frame.

•	Returns a pointer to the frame data if successful or NULL otherwise. The frame data is returned as a packed DIB.

pgf

Address of a GetFrame object.

lPos

Position, in samples, within the stream of the desired frame.

The returned frame is valid only until the next call to this function or the AVIStreamGetFrameClose function.


AVIStreamGetFrameClose

STDAPI AVIStreamGetFrameClose(PGETFRAME pget);

Releases resources used to decompress video frames.

•	Returns zero if successful or an error otherwise.

pget

Handle returned from the AVIStreamGetFrameOpen function. After calling this function, the handle is invalid.


AVIStreamGetFrameOpen

STDAPI_(PGETFRAME) AVIStreamGetFrameOpen(PAVISTREAM pavi,
    LPBITMAPINFOHEADER lpbiWanted);

Prepares to decompress video frames from the specified video stream.

•	Returns a GetFrame object that can be used with the AVIStreamGetFrame function. If the system cannot find a decompressor that can decompress the stream to the given format, or to any RGB format, the function returns NULL.

pavi

Address of the video stream used as the video source.

lpbiWanted

Address of a structure that defines the desired video format. Specify NULL to use a default format. You can also specify AVIGETFRAMEF_BESTDISPLAYFMT to decode the frames to the best format for your display.


AVIStreamInfo

STDAPI AVIStreamInfo(PAVISTREAM pavi, AVISTREAMINFO FAR * psi,
    LONG lSize);

Obtains stream header information.

•	Returns zero if successful or an error otherwise.

pavi

Handle of an open stream.

psi

Address of a structure to contain the stream information.

lSize

Size, in bytes, of the structure used for psi.


AVIStreamIsKeyFrame

AVIStreamIsKeyFrame(pavi, lPos)

Indicates whether a sample in a specified stream is a key frame.

•	Returns TRUE if the sample is a key frame or FALSE otherwise.

pavi

Handle of an open stream.

lPos

Position to search in the stream.

The AVIStreamIsKeyFrame macro is defined as follows:

#define AVIStreamIsKeyFrame(pavi, lPos) \

    (AVIStreamNearestKeyFrame(pavi, lPos) == 1)


AVIStreamLength

STDAPI_(LONG) AVIStreamLength(PAVISTREAM pavi);

Returns the length of the stream.

•	Returns the stream's length, in samples, if successful or  − 1 otherwise.

pavi

Handle of an open stream.


AVIStreamLengthTime

AVIStreamLengthTime(pavi)

Returns the length of a stream in time.

•	Returns the time if successful or  − 1 otherwise.

pavi

Handle of an open stream.

The AVIStreamLengthTime macro is defined as follows:

#define AVIStreamLengthTime(pavi) \

    AVIStreamSampleToTime(pavi, AVIStreamLength(pavi))


AVIStreamNearestKeyFrame

AVIStreamNearestKeyFrame(pavi, lPos)

Locates the key frame at or preceding a specified position in a stream.

•	Returns the position of the key frame if successful or  − 1 otherwise.

pavi

Handle of an open stream.

lPos

Starting position to search in the stream.

The AVIStreamNearestKeyFrame macro is defined as follows:

#define AVIStreamNearestKeyFrame(pavi, lPos) \

    AVIStreamFindSample(pavi, lPos , FIND_PREV | FIND_KEY)


AVIStreamNearestKeyFrameTime

AVIStreamNearestKeyFrameTime(pavi, lTime)

Determines the time corresponding to the beginning of the key frame nearest (at or preceding) a specified time in a stream.

•	Returns the time of the nearest key frame if successful or  − 1 otherwise.

pavi

Handle of an open stream.

lTime

Starting time, in milliseconds, to search in the stream.

The AVIStreamNearestKeyFrameTime macro is defined as follows:

#define AVIStreamNearestKeyFrameTime(pavi, lTime) \

    AVIStreamSampleToTime(pavi, AVIStreamNearestKeyFrame(pavi,

    AVIStreamTimeToSample(pavi, lTime)))


AVIStreamNearestSample

AVIStreamNearestSample(pavi, lPos)

Locates the nearest nonempty sample at or preceding a specified position in a stream.

•	Returns the sample position if successful or  − 1 otherwise.

pavi

Handle of an open stream.

lPos

Starting position to search in the stream.

The AVIStreamNearestSample macro is defined as follows:

#define AVIStreamNearestSample(pavi, lPos) \

    AVIStreamFindSample(pavi, lPos, FIND_PREV | FIND_ANY)


AVIStreamNearestSampleTime

AVIStreamNearestSampleTime(pavi, lTime)

Determines the time corresponding to the beginning of a sample that is nearest to a specified time in a stream.

•	Returns the time of the nearest sample if successful or  − 1 otherwise.

pavi

Handle of an open stream.

lTime

Starting time, in milliseconds, to search in the stream.

The AVIStreamNearestSampleTime macro is defined as follows:

#define AVIStreamNearestSampleTime(pavi, lTime) \

    AVIStreamSampleToTime(pavi, AVIStreamNearestSample(pavi,

    AVIStreamTimeToSample(pavi, lTime)))


AVIStreamNextKeyFrame

AVIStreamNextKeyFrame(pavi, lPos)

Locates the next key frame following a specified position in a stream.

•	Returns the position of the key frame if successful or  − 1 otherwise.

pavi

Handle of an open stream.

lPos

Starting position to search in the stream.

The search performed by this macro does not include the frame at the specified position.

The AVIStreamNextKeyFrame macro is defined as follows:

#define AVIStreamNextKeyFrame(pavi, lPos) \

    AVIStreamFindSample(pavi, lPos + 1, FIND_NEXT | FIND_KEY)


AVIStreamNextKeyFrameTime

AVIStreamNextKeyFrameTime(pavi, time)

Returns the time of the next key frame in the stream, starting at a given time.

•	Returns the time if successful or  − 1 otherwise.

pavi

Handle of an open stream.

time

Position in the stream to begin searching.

The search performed by this macro includes the frame that corresponds to the specified time.

The AVIStreamNextKeyFrameTime macro is defined as follows:

#define AVIStreamNextKeyFrameTime(pavi, time) \

    AVIStreamSampleToTime(pavi, \

    AVIStreamNextKeyFrame(pavi, \

    AVIStreamTimeToSample(pavi, time)))


AVIStreamNextSample

AVIStreamNextSample(pavi, lPos)

Locates the next nonempty sample from a specified position in a stream.

•	Returns the sample position if successful or  − 1 otherwise.

pavi

Handle of an open stream.

lPos

Starting position to search in the stream.

The sample position returned does not include the sample specified by lPos.

The AVIStreamNextSample macro is defined as follows:

#define AVIStreamNextSample(pavi, lPos) \

    AVIStreamFindSample(pavi, lPos + 1, FIND_NEXT | FIND_ANY)


AVIStreamNextSampleTime

AVIStreamNextSampleTime(pavi, time)

Returns the time that a sample changes to the next sample in the stream. This macro finds the the next interesting time in a stream.

•	Returns the time if successful or  − 1 otherwise.

pavi

Handle of an open stream.

time

Position information of the sample in the stream.

The AVIStreamNextSampleTime macro is defined as follows:

#define AVIStreamNextSampleTime(pavi, time) \

    AVIStreamSampleToTime(pavi, \

    AVIStreamNextSample(pavi, \

    AVIStreamTimeToSample(pavi, t)))


AVIStreamOpenFromFile

STDAPI AVIStreamOpenFromFile(PAVISTREAM FAR * ppavi,
    LPCTSTR szFile, DWORD fccType, LONG lParam, UINT mode,
    CLSID FAR * pclsidHandler);

Opens a single stream from a file.

•	Returns zero if successful or an error otherwise.

ppavi

Address to contain the new stream handle.

szFile

Null-terminated string containing the name of the file to open.

fccType

Four-character code indicating the type of stream to be opened. Zero indicates that any stream can be opened. The following definitions apply to the data commonly found in AVI streams:

streamtypeAUDIO	Indicates an audio stream.
streamtypeMIDI	Indicates a MIDI stream.
streamtypeTEXT	Indicates a text stream.
streamtypeVIDEO	Indicates a video stream.
lParam

Stream of the type specified in fccType to access. This parameter is zero-based; use zero to specify the first occurrence.

mode

Access mode to use when opening the file. This function can open only existing streams, so the OF_CREATE mode flag cannot be used. For more information about the available flags for the mode parameter, see the OpenFile function.

pclsidHandler

Address of a class identifier of the handler you want to use. If the value is NULL, the system chooses one from the registry based on the file extension or the file RIFF type.

This function calls the AVIFileOpen, AVIFileGetStream, and AVIFileRelease functions.


AVIStreamPrevKeyFrame

AVIStreamPrevKeyFrame(pavi, lPos)

Locates the key frame that precedes a specified position in a stream.

•	Returns the position of the key frame if successful or  − 1 otherwise.

pavi

Handle of an open stream.

lPos

Starting position to search in the stream.

The search performed by this macro does not include the frame at the specified position.

The AVIStreamPrevKeyFrame macro is defined as follows:

#define AVIStreamPrevKeyFrame(pavi, lPos) \

    AVIStreamFindSample(pavi, lPos - 1, FIND_PREV | FIND_KEY)


AVIStreamPrevKeyFrameTime

AVIStreamPrevKeyFrameTime(pavi, time)

Returns the time of the previous key frame in the stream, starting at a given time.

•	Returns the time if successful or  − 1 otherwise.

pavi

Handle of an open stream.

time

Position in the stream to begin searching.

The search performed by this macro includes the frame that corresponds to the specified time.

The AVIStreamPrevKeyFrameTime macro is defined as follows:

#define AVIStreamPrevKeyFrameTime(pavi, time) \

    AVIStreamSampleToTime(pavi, AVIStreamPrevKeyFrame(pavi,
    AVIStreamTimeToSample(pavi, time)))


AVIStreamPrevSample

AVIStreamPrevSample(pavi, lPos)

Locates the nearest nonempty sample that precedes a specified position in a stream.

•	Returns the sample position if successful or  − 1 otherwise.

pavi

Handle of an open stream.

lPos

Starting position to search in the stream.

The sample position returned does not include the sample specified by lPos.

The AVIStreamPrevSample macro is defined as follows:

#define AVIStreamPrevSample(pavi, lPos) \

    AVIStreamFindSample(pavi, lPos - 1, FIND_PREV | FIND_ANY)


AVIStreamPrevSampleTime

AVIStreamPrevSampleTime(pavi, time)

Determines the time of the nearest nonempty sample that precedes a specified time in a stream.

•	Returns the time if successful or  − 1 otherwise.

pavi

Handle of an open stream.

time

Position information of the sample in the stream.

The AVIStreamPrevSampleTime macro is defined as follows:

#define AVIStreamPrevSampleTime(pavi, time) \

    AVIStreamSampleToTime(pavi, \

    AVIStreamPrevSample(pavi, \

    AVIStreamTimeToSample(pavi, t)))


AVIStreamRead

STDAPI AVIStreamRead(PAVISTREAM pavi, LONG lStart, LONG lSamples,
    LPVOID lpBuffer, LONG cbBuffer, LONG FAR * plBytes,
    LONG FAR * plSamples);

Reads audio, video or other data from a stream according to the stream type.

•	Returns zero if successful or an error otherwise. The values returned in plBytes and plSamples report the amount of data read by this function. Possible error values include the following:

AVIERR_BUFFERTOOSMALL	The buffer size cbBuffer was smaller than a single sample of data.
AVIERR_MEMORY	There was not enough memory to complete the read operation.
AVIERR_FILEREAD	A disk error occurred while reading the file.
pavi

Handle of an open stream.

lStart

First sample to read.

lSamples

Number of samples to read. You can also specify the value AVISTREAMREAD_CONVENIENT to let the stream handler determine the number of samples to read.

lpBuffer

Address of a buffer to contain the data.

cbBuffer

Size, in bytes, of the buffer pointed to by lpBuffer.

plBytes

Address to contain the number of bytes of data written in the buffer referenced by lpBuffer. This value can be NULL.

plSamples

Address to contain the number of samples written in the buffer referenced by lpBuffer. This value can be NULL.

If lpBuffer is NULL, this function does not read any data; it returns information about the size of data that would be read.


AVIStreamReadData

STDAPI AVIStreamReadData(PAVISTREAM pavi, DWORD ckid,
    LPVOID lpData, LONG FAR * lpcbData);

Reads optional header data from a stream.

•	Returns zero if successful or an error otherwise. The return value AVIERR_NODATA indicates the system could not find any data with the specified chunk identifier.

pavi

Handle of an open stream.

ckid

Four-character code identifying the data.

lpData

Address of the buffer to contain the optional header data.

lpcbData

Address of the location that specifies the buffer size used for lpData. If the read is successful, AVIFile changes this value to indicate the amount of data written into the buffer for lpData.

This function retrieves only optional header information from the stream. This information is custom and does not have a set format.


AVIStreamReadFormat

STDAPI AVIStreamReadFormat(PAVISTREAM pavi, LONG lPos,
    LPVOID lpFormat, LONG FAR * lpcbFormat);

Reads the stream format data.

•	Returns zero if successful or an error otherwise.

pavi

Handle of an open stream.

lPos

Position in the stream used to obtain the format data.

lpFormat

Address of a buffer to contain the format data.

lpcbFormat

Address of a location indicating the size of the memory block referenced by lpFormat. On return, the value is changed to indicate the amount of data read. If lpFormat is NULL, this parameter can be used to obtain the amount of memory needed to return the format.


AVIStreamRelease

STDAPI_(LONG) AVIStreamRelease(PAVISTREAM pavi);

Decrements the reference count of an AVI stream interface handle, and closes the stream if the count reaches zero.

•	Returns the current reference count of the stream. This value should be used only for debugging purposes.

pavi

Handle of an open stream.

This function supercedes the obsolete AVIStreamClose function.


AVIStreamSampleSize

AVIStreamSampleSize(pavi, lPos, plSize)

Determines the size of the buffer needed to store one sample of information from a stream. The size corresponds to the sample at the position specified by lPos.

•	Returns zero if successful or an error otherwise. The value returned in plSize reports the number of bytes in the sample read by this function. Possible error values include the following:

AVIERR_BUFFERTOOSMALL	The buffer size was smaller than a single sample of data.
AVIERR_MEMORY	There was not enough memory to complete the read operation.
AVIERR_FILEREAD	A disk error occurred while reading the file.
pavi

Handle of an open stream.

lPos

Position of a sample in the stream.

plSize

Address to contain the buffer size.

The AVIStreamSampleSize macro is defined as follows:

#define AVIStreamSampleSize(pavi, lPos, plSize) \

    AVIStreamRead(pavi, lPos, 1, NULL, 0, plSize, NULL)


AVIStreamSampleToSample

AVIStreamSampleToSample(pavi1, pavi2, lSample)

Returns the sample in a stream that occurs at the same time as a sample that occurs in a second stream.

•	Returns the sample if successful or  − 1 otherwise.

pavi1

Handle of an open stream that contains the sample that is returned.

pavi2

Handle of a second stream that contains the reference sample.

lSample

Position information of the sample in the stream referenced by pavi2.

The AVIStreamSampleToSample macro is defined as follows:

#define AVIStreamSampleToSample(pavi1, pavi2, lsample) \

    AVIStreamTimeToSample(pavi1, AVIStreamSampleToTime \

    (pavi2, lsample))


AVIStreamSampleToTime

STDAPI_(LONG) AVIStreamSampleToTime(PAVISTREAM pavi, LONG lSample);

Converts a stream position from samples to milliseconds.

•	Returns the converted time if successful or  − 1 otherwise.

pavi

Handle of an open stream.

lSample

Position information. A sample can correspond to blocks of audio, a video frame, or other format, depending on the stream type.


AVIStreamSetFormat

STDAPI AVIStreamSetFormat(PAVISTREAM pavi, LONG lPos,
    LPVOID lpFormat, LONG cbFormat);

Sets the format of a stream at the specified position.

•	Returns zero if successful or an error otherwise.

pavi

Handle of an open stream.

lPos

Position in the stream to receive the format.

lpFormat

Address of a structure containing the new format.

cbFormat

Size, in bytes, of the block of memory referenced by lpFormat.

The handler for writing AVI files does not accept format changes. Besides setting the initial format for a stream, only changes in the palette of a video stream are allowed in an AVI file. The palette change must occur after any frames already written to the AVI file. Other handlers might impose different restrictions.


AVIStreamStart

STDAPI_(LONG) AVIStreamStart(PAVISTREAM pavi);

Returns the starting sample number for the stream.

•	Returns the number if successful or  − 1 otherwise.

pavi

Handle of an open stream.


AVIStreamStartTime

AVIStreamStartTime(pavi)

Returns the starting time of a stream's first sample.

•	Returns the time if successful or  − 1 otherwise.

pavi

Handle of an open stream.

The AVIStreamStartTime macro is defined as follows:

#define AVIStreamStartTime(pavi) \

    AVIStreamSampleToTime(pavi, AVIStreamStart(pavi))


AVIStreamTimeToSample

STDAPI_(LONG) AVIStreamTimeToSample(PAVISTREAM pavi, LONG lTime);

Converts from milliseconds to samples.

•	Returns the converted time if successful or  − 1 otherwise.

pavi

Handle of an open stream.

lTime

Time, expressed in milliseconds.

Samples typically correspond to audio samples or video frames. Other stream types might support different formats than these.


AVIStreamWrite

STDAPI AVIStreamWrite(PAVISTREAM pavi, LONG lStart, LONG lSamples,
    LPVOID lpBuffer, LONG cbBuffer, DWORD dwFlags,
    LONG FAR * plSampWritten, LONG FAR * plBytesWritten);

Writes data to a stream.

•	Returns zero if successful or an error otherwise.

pavi

Handle of an open stream.

lStart

First sample to write.

lSamples

Number of samples to write.

lpBuffer

Address of a buffer containing the data to write.

cbBuffer

Size of the buffer referenced by lpBuffer.

dwFlags

Flag associated with this data. The following flag is defined:

AVIIF_KEYFRAME

Indicates this data does not rely on preceding data in the file.

plSampWritten

Address to contain the number of samples written. This can be set to NULL.

plBytesWritten

Address to contain the number of bytes written. This can be set to NULL.

The default AVI file handler supports writing only at the end of a stream. The "WAVE" file handler supports writing anywhere.

This function overwrites existing data, rather than inserting new data.


AVIStreamWriteData

STDAPI AVIStreamWriteData(PAVISTREAM pavi, DWORD ckid,
    LPVOID lpData, LONG cbData);

Writes optional header information to the stream.

•	Returns zero if successful or an error otherwise. The return value AVIERR_READONLY indicates the file was opened without write access.

pavi

Handle of an open stream.

ckid

Four-character code identifying the data.

lpData

Address of a buffer containing the data to write.

cbData

Number of bytes of data to write into the stream.

Use the AVIStreamWrite function to write the multimedia content of the stream. Use AVIFileWriteData to write data that applies to an entire file.


CreateEditableStream

STDAPI CreateEditableStream(PAVISTREAM FAR * ppsEditable,
    PAVISTREAM psSource);

Creates an editable stream. Use this function before using other stream editing functions.

•	Returns zero if successful or an error otherwise.

ppsEditable

Address to contain the new stream handle.

psSource

Handle of the stream supplying data for the new stream. Specify NULL to create an empty editable string that you can copy and paste data into.

The stream pointer returned in ppsEditable must be used as the source stream in the other stream editing functions.

Internally, this function creates tables to keep track of changes to a stream. The original stream is never changed by the stream editing functions. The stream pointer created by this function can be used in any AVIFile function that accepts stream pointers. You can use this function on the same stream multiple times. A copy of a stream is not affected by changes in another copy.


EditStreamClone

STDAPI EditStreamClone(PAVISTREAM pavi, PAVISTREAM FAR * ppResult);

Creates a duplicate editable stream.

•	Returns zero if successful or an error otherwise.

pavi

Handle of an editable stream that will be copied.

ppResult

Address to contain the new stream handle.

The editable stream that is being cloned must have been created by the CreateEditableStream function or one of the stream editing functions.

The new stream can be treated as any other AVI stream.


EditStreamCopy

STDAPI EditStreamCopy(PAVISTREAM pavi, LONG FAR * plStart,
    LONG FAR * plLength, PAVISTREAM FAR * ppResult);

Copies an editable stream (or a portion of it) into a temporary stream.

•	Returns zero if successful or an error otherwise.

pavi

Handle of the stream being copied.

plStart

Starting position within the stream being copied. The starting position is returned.

plLength

Amount of data to copy from the stream referenced by pavi. The length of the copied data is returned.

ppResult

Address to contain the handle created for the new stream.

The stream that is copied must be created by the CreateEditableStream function or one of the stream editing functions.

The temporary stream can be treated as any other AVI stream.


EditStreamCut

STDAPI EditStreamCut(PAVISTREAM pavi, LONG FAR * plStart,
    LONG FAR * plLength, PAVISTREAM FAR * ppResult);

Deletes all or part of an editable stream and creates a temporary editable stream from the deleted portion of the stream.

•	Returns zero if successful or an error otherwise.

pavi

Handle of the stream being edited.

plStart

Starting position of the data to cut from the stream referenced by pavi.

plLength

Amount of data to cut from the stream referenced by pavi.

ppResult

Address of the handle created for the new stream.

The stream being edited must have been created by the CreateEditableStream function or one of the stream editing functions.

The temporary stream is an editable stream and can be treated as any other AVI stream. An application must release the temporary stream to free the resources associated with it.


EditStreamPaste

STDAPI EditStreamPaste(PAVISTREAM pavi, LONG FAR * plPos,
    LONG FAR * plLength, PAVISTREAM pstream, LONG lStart,
    LONG lLength);

Copies a stream (or a portion of it) from one stream and pastes it within another stream at a specified location.

•	Returns zero if successful or an error otherwise.

pavi

Handle of an editable stream that will receive the copied stream data.

plPos

Starting position to paste the data within the destination stream (referenced by pavi).

plLength

Address to contain the amount of data pasted in the stream.

pstream

Handle of a stream supplying the data to paste. This stream does not need to be an editable stream.

lStart

Starting position of the data to copy within the source stream.

lLength

Amount of data to copy from the source stream. If lLength is -1, the entire stream referenced by pstream is pasted in the other stream.

The stream referenced by pavi must have been created by the CreateEditableStream function or one of the stream editing functions.

This function inserts data into the specified stream as a continuous block of data. It opens the specified data stream at the insertion point, pastes the specified stream segment at the insertion point, and appends the stream segment that trails the insertion point to the end of pasted segment.


EditStreamSetInfo

SDTAPI EditStreamSetInfo(PAVISTREAM pavi, AVISTREAMINFO FAR * lpInfo,
    LONG cbInfo);

Changes characteristics of an editable stream.

•	Returns zero if successful or an error otherwise.

pavi

Handle of an open stream.

lpInfo

Address of an AVISTREAMINFO structure containing new information.

cbInfo

Size, in bytes, of the structure pointed to by lpInfo.

You must supply information for the entire AVISTREAMINFO structure, including the members you will not use. You can use the AVIStreamInfo function to initialize the structure and then update selected members with your data.

This function does not change the following members:

dwCaps

dwEditCount

dwFlags

dwInitialFrames

dwLength

dwSampleSize

dwSuggestedBufferSize

fccHandler

fccType

The function changes the following members:

dwRate

dwQuality

dwScale

dwStart

rcFrame

szName

wLanguage

wPriority


EditStreamSetName

SDTAPI EditStreamSetName(PAVISTREAM pavi, LPCSTR lpszName);

Assigns a descriptive string to a stream.

•	Returns zero if successful or an error otherwise.

pavi

Handle of an open stream.

lpszName

Null-terminated string containing the description of the stream.

This function updates the szName member of the AVISTREAMINFO structure.


AVICOMPRESSOPTIONS

typedef struct {

DWORD  fccType;

DWORD  fccHandler;

DWORD  dwKeyFrameEvery;

DWORD  dwQuality;

DWORD  dwBytesPerSecond;

DWORD  dwFlags;

LPVOID lpFormat;

DWORD  cbFormat;

LPVOID lpParms;

DWORD  cbParms;

DWORD  dwInterleaveEvery;

} AVICOMPRESSOPTIONS;

Contains information about a stream and how it is compressed and saved. This structure passes data to the AVIMakeCompressedStream function (or the AVISave function, which uses AVIMakeCompressedStream).

fccType

Four-character code indicating the stream type. The following constants have been defined for the data commonly found in AVI streams:

streamtypeAUDIO	Indicates an audio stream.
streamtypeMIDI	Indicates a MIDI stream.
streamtypeTEXT	Indicates a text stream.
streamtypeVIDEO	Indicates a video stream.
fccHandler

Four-character code for the compressor handler that will compress this video stream when it is saved (for example, mmioFOURCC('M','S','V','C')). This member is not used for audio streams.

dwKeyFrameEvery

Maximum period between video key frames. This member is used only if the AVICOMPRESSF_KEYFRAMES flag is set; otherwise every video frame is a key frame.

dwQuality

Quality value passed to a video compressor. This member is not used for an audio compressor.

dwBytesPerSecond

Video compressor data rate. This member is used only if the AVICOMPRESSF_DATARATE flag is set.

dwFlags

Flags used for compression. The following values are defined:

AVICOMPRESSF_DATARATE

Compresses this video stream using the data rate specified in dwBytesPerSecond.

AVICOMPRESSF_INTERLEAVE

Interleaves this stream every dwInterleaveEvery frames with respect to the first stream.

AVICOMPRESSF_KEYFRAMES

Saves this video stream with key frames at least every dwKeyFrameEvery frames. By default, every frame will be a key frame.

AVICOMPRESSF_VALID

Uses the data in this structure to set the default compression values for AVISaveOptions. If an empty structure is passed and this flag is not set, some defaults will be chosen.

lpFormat

Address of a structure defining the data format. For an audio stream, this is an LPWAVEFORMAT structure.

cbFormat

Size, in bytes, of the data referenced by lpFormat.

lpParms

Video-compressor-specific data; used internally.

cbParms

Size, in bytes, of the data referenced by lpParms

dwInterleaveEvery

Interleave factor for interspersing stream data with data from the first stream. Used only if the AVICOMPRESSF_INTERLEAVE flag is set.


AVIFILEINFO

typedef struct {

DWORD dwMaxBytesPerSec;       \\ approximate max. data rate of file

DWORD dwFlags;                \\ see below

DWORD dwCaps;                 \\ see below

DWORD dwStreams;              \\ see below

DWORD dwSuggestedBufferSize;  \\ see below

DWORD dwWidth;                \\ width, in pixels, of the AVI file

DWORD dwHeight;               \\ height, in pixels, of the AVI file

DWORD dwScale;                \\ see below

DWORD dwRate;                 \\ see dwScale

DWORD dwLength;               \\ see below

DWORD dwEditCount;            \\ see below

char  szFileType[64];         \\ see below

} AVIFILEINFO;

Contains global information for an entire AVI file.

dwFlags

Applicable flags. The following flags are defined:

AVIFILEINFO_HASINDEX

The AVI file has an index at the end of the file. For good performance, all AVI files should contain an index.

AVIFILEINFO_MUSTUSEINDEX

The file index contains the playback order for the chunks in the file. Use the index rather than the physical ordering of the chunks when playing back the data. This could be used for creating a list of frames for editing.

AVIFILEINFO_ISINTERLEAVED

The AVI file is interleaved.

AVIFILEINFO_WASCAPTUREFILE

The AVI file is a specially allocated file used for capturing real-time video. Applications should warn the user before writing over a file with this flag set because the user probably defragmented this file.

AVIFILEINFO_COPYRIGHTED

The AVI file contains copyrighted data and software. When this flag is used, software should not permit the data to be duplicated.

dwCaps

Capability flags. The following flags are defined:

AVIFILECAPS_CANREAD

An application can open the AVI file with with the read privilege.

AVIFILECAPS_CANWRITE

An application can open the AVI file with the write privilege.

AVIFILECAPS_ALLKEYFRAMES

Every frame in the AVI file is a key frame.

AVIFILECAPS_NOCOMPRESSION

The AVI file does not use a compression method.

dwStreams

Number of streams in the file. For example, a file with audio and video has at least two streams.

dwSuggestedBufferSize

Suggested buffer size, in bytes, for reading the file. Generally, this size should be large enough to contain the largest chunk in the file. For an interleaved file, this size should be large enough to read an entire record, not just a chunk.

If the buffer size is too small or is set to zero, the playback software will have to reallocate memory during playback, reducing performance.

dwScale

Time scale applicable for the entire file. Dividing dwRate by dwScale gives the number of samples per second.

Any stream can define its own time scale to supersede the file time scale.

dwLength

Length of the AVI file. The units are defined by dwRate and dwScale.

dwEditCount

Number of streams that have been added to or deleted from the AVI file.

szFileType

Null-terminated string containing descriptive information for the file type.


AVISTREAMINFO

typedef struct {                  \\ see below

DWORD fccType;                \\ see below

DWORD fccHandler;             \\ see below

DWORD dwFlags;                \\ see below

DWORD dwCaps;                 \\ capability flags; currently unused

WORD  wPriority;              \\ priority of the stream

WORD  wLanguage;              \\ language of the stream

DWORD dwScale;                \\ see below

DWORD dwRate;                 \\ see dwScale

DWORD dwStart;                \\ see below

DWORD dwLength;               \\ see below

DWORD dwInitialFrames;        \\ see below

DWORD dwSuggestedBufferSize;  \\ see below

DWORD dwQuality;              \\ see below

DWORD dwSampleSize;           \\ see below

RECT  rcFrame;                \\ see below

DWORD dwEditCount;            \\ see below

DWORD dwFormatChangeCount;    \\ see below

char  szName[64];             \\ see below

} AVISTREAMINFO;                  \\ see below

Contains information for a single stream.

fccType

Four-character code indicating the stream type. The following constants have been defined for the data commonly found in AVI streams:

streamtypeAUDIO	Indicates an audio stream.
streamtypeMIDI	Indicates a MIDI stream.
streamtypeTEXT	Indicates a text stream.
streamtypeVIDEO	Indicates a video stream.
fccHandler

Four-character code of the compressor handler that will compress this video stream when it is saved (for example, mmioFOURCC('M','S','V','C')). This member is not used for audio streams.

dwFlags

Applicable flags for the stream. The bits in the high-order word of these flags are specific to the type of data contained in the stream. The following flags are defined:

AVISTREAMINFO_DISABLED

Indicates this stream should be rendered when explicitly enabled by the user.

AVISTREAMINFO_FORMATCHANGES

Indicates this video stream contains palette changes. This flag warns the playback software that it will need to animate the palette.

dwScale

Time scale applicable for the stream. Dividing dwRate by dwScale gives the playback rate in number of samples per second.

For video streams, this rate should be the frame rate. For audio streams, this rate should correspond to the audio block size (the nBlockAlign member of the WAVEFORMAT or PCMWAVEFORMAT structure), which for PCM (Pulse Code Modulation) audio reduces to the sample rate.

dwStart

Sample number of the first frame of the AVI file. The units are defined by dwRate and dwScale. Normally, this is zero, but it can specify a delay time for a stream that does not start concurrently with the file.

The 1.0 release of the AVI tools does not support a nonzero starting time.

dwLength

Length of this stream. The units are defined by dwRate and dwScale.

dwInitialFrames

Audio skew. This member specifies how much to skew the audio data ahead of the video frames in interleaved files. Typically, this is about 0.75 seconds.

dwSuggestedBufferSize

Recommended buffer size, in bytes, for the stream. Typically, this member contains a value corresponding to the largest chunk in the stream. Using the correct buffer size makes playback more efficient. Use zero if you do not know the correct buffer size.

dwQuality

Quality indicator of the video data in the stream. Quality is represented as a number between 0 and 10,000. For compressed data, this typically represents the value of the quality parameter passed to the compression software. If set to  − 1, drivers use the default quality value.

dwSampleSize

Size, in bytes, of a single data sample. If the value of this member is zero, the samples can vary in size and each data sample (such as a video frame) must be in a separate chunk. A nonzero value indicates that multiple samples of data can be grouped into a single chunk within the file.

For video streams, this number is typically zero, although it can be nonzero if all video frames are the same size. For audio streams, this number should be the same as the nBlockAlign member of the WAVEFORMAT or WAVEFORMATEX structure describing the audio.

rcFrame

Dimensions of the video destination rectangle. The values represent the coordinates of upper left corner, the height, and the width of the rectangle.

dwEditCount

Number of times the stream has been edited. The stream handler maintains this count.

dwFormatChangeCount

Number of times the stream format has changed. The stream handler maintains this count.

szName

Null-terminated string containing a description of the stream.


Video Compression Manager

The video compression manager (VCM) provides access to the interface used by installable compressors to handle real-time data. Applications can use installable compressors to perform the following tasks:

•	Compress and decompress video data.

•	Send a renderer compressed video data and have it draw it to the display.

•	Compress, decompress, or draw data with application-defined renderers.

•	Use renderers to handle text and custom data.

Typically, installable compressors operate with video-image data stored in audio-video interleaved (AVI) files. This chapter explains the programming techniques used to access installable compressors through VCM and covers the following topics:

•	VCM and the Video for Windows architecture

•	Compressing and decompressing image data from your application

•	Using VCM renderers to draw data from your application

•	VCM functions and structures

Before you read this chapter, you should be familiar with the Microsoft Win32 graphic services. In particular, bitmaps and bitmap-related structures, such as BITMAPINFO and BITMAPINFOHEADER, are used extensively by VCM. For additional information about the BITMAPINFO and BITMAPINFOHEADER structures, see Chapter 29, "Bitmaps."

Note  The audio compression manager (ACM) provides system-level support for audio compression and decompression drivers. For a description of the audio compression services, see Chapter 12, "Audio Compression Manager."


VCM Architecture

VCM is an intermediary between an application and compression and decompression drivers. The compression and decompression drivers compress and decompress individual frames of data.

When an application makes a call to VCM, VCM translates the call into a message. The message is sent by using the ICSendMessage function to the appropriate compressor or decompressor, which compresses or decompresses the data. VCM receives the return value from the compression or decompression driver and then returns control to the application.

If a macro is defined for a message, the macro expands to an ICSendMessage function call supplying appropriate parameters for that message. If a macro is defined for a message, your application should use it rather than the message. In this chapter, these macros follow messages in parentheses.


System Entries for Compressors, Decompressors, and Renderers

The system uses entries in the registry to find VCM drivers. These entries are in the form of 2 four-character codes separated by a period. The first four-character code is defined by the system and can be one of the following:

Four-character code	Description
"VIDC"	Identifies compressors and decompressors.
"VIDS"	Identifies video-stream renderers.
"TXTS"	Identifies text-stream renderers.
"AUDS"	Identifies audio-stream handlers.
Custom renderers can define their own four-character codes.

The second four-character code is defined by the driver. Typically, the second four-character code corresponds to the type of data the driver can handle.

When opening a VCM driver, an application specifies the type of driver and the type of data handler it needs. Typically, this information comes from the stream header. The system tries to open the specified data handler, but if it fails, the system searches the registry for a driver that has the required handler.

When searching for the driver, the system tries to match the four-character codes specified for the driver type and data handler with those specified in the driver entry. For example, if an application specifies the compressor MSSQ, the system searches the registry for the driver entry VIDC.MSSQ. If it cannot find a match, it opens each driver corresponding to the driver type and locates one that can handle the type of data your application specifies. In the previous example, if the system could not find VIDC.MSSQ, it would open all drivers with the "VIDC" four-character code and locate one that can handle the data.


VCM Services

In general, an application uses VCM to perform the following tasks:

•	Locate, open, or install a compressor or decompressor.

•	Configure or obtain configuration information about the compressor or decompressor.

•	Use a series of functions to compress, decompress, or draw the data.

The functions and macros of the DrawDib library perform these tasks implicitly and might provide the most convenient way to use VCM. For more information about the DrawDib library, see Chapter 10, "DrawDib Functions ."

The following sections describe tasks you can perform by using VCM.


Compressor and Decompressor Basics

To open and locate a compressor, you can use the ICLocate and ICOpen functions. You can use ICLocate to find a compressor of a specific type and to obtain a handle of it for use in other VCM functions. To open a compressor, you can use ICOpen. Your application uses the handle returned by this function to identify the opened compressor when it uses other VCM functions.

To open and locate a decompressor, applications can use the ICDecompressOpen and ICDrawOpen macros. These macros use ICLocate for operation.

When your application is finished using a compressor or decompressor, it must close it to free any resources used for compression or decompression. Your application can use the ICClose function to close the compressor or decompressor.

Also, your application can enumerate the compressors or decompressors on a system by using the ICInfo function.

Note  The stream header in an AVI file contains information about the stream type and the specific handler for that stream. Within the stream header, the fccType and fccHandler members identify the stream type and the stream handler specified for the stream.


User-Selected Compressors

When compressing data, your application can use the ICCompressorChoose function to create a dialog box in which the user can select the compressor. You can specify flags for this function to allow the user to specify the key-frame frequency and the movie-data rate, or to display a preview window.

The compressor selected by the user is automatically opened and its handle is returned in the hic member of the COMPVARS structure specified in ICCompressorChoose.

If you use ICCompressorChoose, use the ICCompressorFree function to close the compressor and free any resources associated with the COMPVARS structure.


Compressor and Decompressor Installation and Removal

An application can use compressors and decompressors that are already installed on a system running the Microsoft Windows operating system. An application can also install compressors and decompressors for general or special uses. Most applications will not need to install or remove compressors or decompressors because they are usually installed by a setup program. An application might, however, install a compressor directly or install a function as a compressor.

An application can install a compressor or decompressor (or a function used as a compressor or decompressor) by using the ICInstall function. This function creates an entry in the registry identifying the compressor or decompressor. Your application or another application can search the registry to determine if the system contains a compressor or decompressor suitable for its data. Use ICInstall to install all compression and decompression drivers.

An application can locate and open an installed compressor or decompressor by using the ICLocate and ICOpen functions. When an application finishes using a compressor or decompressor, it closes it by using the ICClose function.

An application can remove the registry entry for an installed compressor or decompressor by using the ICRemove function. This function removes the registry entry of a compressor or decompressor that is not currently loaded in memory.

An application can restrict the use of a compressor or decompressor by installing, opening, closing, and removing the compressor.

Alternatively, an application can use a function internally as a compressor or decompressor without installing the function in the registry by using the ICOpenFunction function. This function requires the calling application to have the address of the function. When the application finishes using the function, it must close it by using ICClose. Because the function was not installed, the application does not need to remove the function from the registry.

The internal structure of a function used as a compressor or decompressor should be the same as the DriverProc entry-point function used by installable drivers. For more information about the DriverProc entry-point function, see Chapter 0, "Installable Drivers."

Note  An application installing a function as a compressor or decompressor must remove the function before the application is closed so other applications do not try to use the function. When removing a function, the application must identify it with the four-character code used to install it.


Compressor and Decompressor Configuration

Your application can configure the compressor or decompressor automatically, or it can allow the user to configure them. If it is practical, you should allow the user to configure the compressor or decompressor because it frees you from considering all the compressor's or decompressor's options.

The user can configure the compressor or decompressor by using a configuration dialog box. You can send the ICM_CONFIGURE message to VCM or use the ICQueryConfigure macro to determine if a compressor or decompressor can display a configuration dialog box. If so, you can send the ICM_CONFIGURE message (or the ICConfigure macro) to display it.

Your application can send the ICM_GETSTATE and ICM_SETSTATE messages (or the ICGetStateSize, ICGetState, and ICSetState macros) to get and set the status for a compressor or decompressor. If your application creates or modifies the status, it must obtain the layout of the compressor or decompressor data before restoring its status. Alternatively, if your application obtains the status from a compressor or decompressor and uses it to restore the status in a subsequent session, it must ensure that it restores only status information obtained from the compressor or decompressor it is currently using.


Getting Information About Compressors and Decompressors

To get general information about a compressor or decompressor, your application can use the ICGetInfo function. This function fills an ICINFO structure with information about the compressor or decompressor. Your application must allocate the memory for the ICINFO structure and pass a pointer to it in ICGetInfo. Unless your application searches for a particular compressor or decompressor, the flags in the ICINFO structure provide the most useful information about the capabilities of a compressor or decompressor.

To get the default key-frame rate and default quality value of a compressor or decompressor, your application can send the ICM_GETDEFAULTKEYFRAMERATE and ICM_GETDEFAULTQUALITY messages (or the ICGetDefaultKeyFrameRate and ICGetDefaultQuality macros).

To determine the best display format of a compressor or decompressor, your application can use the ICGetDisplayFormat function.

You can determine if a compressor or decompressor can display an About dialog box by sending the ICM_ABOUT message (or the ICQueryAbout macro). You can also display the About dialog box of a compressor or decompressor by sending the ICM_ABOUT message and changing the value of the wParam parameter (or by using the ICAbout macro).


Single-Image Compression

You can use the ICImageCompress function to compress a single image. This function returns a handle of the compressed device-independent bitmap (DIB). The compressed DIB is packed using the CF_DIB format.


Sequence Compression

Your application can use the ICSeqCompressFrame, ICSeqCompressFrameStart, and ICSeqCompressFrameEnd functions to compress a sequence of frames. These functions use the data stored in the COMPVARS structure. Applications use the ICCompressorChoose function to allow the user to select a compressor, open it, and set the compression parameters in the COMPVARS structure; however, applications can set the parameters in the structure manually.

Before an application can begin compressing a sequence of frames, it must use ICSeqCompressFrameStart to allocate the necessary resources. After the resources are allocated, the application can use ICSeqCompressFrame to compress each frame individually. The frame rate and key-frame frequency used in compressing the sequence are specified in members of the COMPVARS structure. The return value for ICSeqCompressFrame points to the compressed data.

When an application finishes compressing a sequence, it can use ICSeqCompressFrameEnd to free system resources allocated for ICSeqCompressFrameStart, and ICCompressorFree to free the resources allocated for the COMPVARS structure.


Image-Data Compression

Your application can use a series of ICCompress functions and macros to compress data. The functions and macros can help you perform the following tasks:

•	Determine the compression format to use for a specified input format.

•	Prepare the compressor.

•	Compress the data.

•	End compression.

Your application can increase control over the compression process by using the ICCompress functions and macros. This group of functions and macros deals with individual frames, rather than the sequence as a whole. For example, your application can identify the frames to compress as key frames by using the ICCompress function.

A compressor receives data in one format, compresses the data, and returns a compressed version of the data using a specified format. The typical input format specifies DIBs using the BITMAPINFO structure. The typical output format specifies compressed DIBs, also using the BITMAPINFO structure.

Note  To minimize image and audio degradation during playback, avoid compressing an AVI file more than once. Combine uncompressed pieces of video in your editing system and then compress the final product.

Compressor and Compression Format Selection

If you want to compress data and your application requires a specific output format, you can send the ICM_COMPRESS_QUERY message (or the ICCompressQuery macro) to query the compressor to determine if it supports the input and output formats.

If the output format is not important to your application, you need only find a compressor that can handle the input format. To determine if a compressor can handle the input format, you can send ICM_COMPRESS_QUERY, specifying NULL for the lParam parameter. This message does not return the output format to your application. Your application can determine the buffer size needed for the data specifying the compression format by sending the ICM_COMPRESS_GET_FORMAT message (or the ICCompressGetFormatSize macro). You can also retrieve the format data by sending ICM_COMPRESS_GET_FORMAT (or the ICCompressGetFormat macro).

If you want to determine the largest buffer that the compressor could require for compression, send the ICM_COMPRESS_GET_SIZE message (or the ICCompressGetSize macro). You can use the number of bytes returned by the ICSendMessage function to allocate a buffer for subsequent image compressions.

Compressor Initialization

After your application selects a compressor that can handle the input and output formats it needs, you can initialize the compressor by using the ICM_COMPRESS_BEGIN message (or the ICCompressBegin macro). This message requires the compressor handle and the input and output formats.

Data Compression

You can use the ICCompress function to compress a frame. Your application must use this function repeatedly until all the frames in a sequence are compressed. Your application must also track and increment the number of each frame compressed with ICCompress. The compressor uses this value to check if frames are sent out of order during fast temporal compression (storing differences between successive frames). If your application recompresses a frame, it should use the same frame number as when the frame was first compressed. If your application compresses a still-frame image, it can specify a frame number of zero.

Your application can use the ICCOMPRESS_KEYFRAME flag to make the frame compressed by ICCompress a key frame.

When VCM returns control to your application after compressing a frame, VCM stores the compressed data in the structures referenced by the lpbiOutput and lpData parameters. If your application needs to move the compressed data, it can find its size in the biSizeImage member of the BITMAPINFO structure specified in lpbiOutput.

Note  Your application must allocate the structures and buffers that store the uncompressed and compressed data. If the compressor supports temporal compression, your application must also allocate a structure and buffer to hold the format and data for the previous frame of information.

Ending Compression

After your application has compressed the data, it can use the ICCompressEnd macro to notify the compressor that it has finished. If you want to restart compression after using this function, your application must reinitialize the compressor by sending the ICM_COMPRESS_BEGIN message (or the ICCompressBegin macro).


Single-Image Decompression

You can use the ICImageDecompress function to decompress a single image. This function returns a handle of the decompressed DIB. The decompressed DIB is stored in the CF_DIB format.


Image-Data Decompression

Your application uses a series of ICDecompressEx functions to control the decompressor. The functions can help you perform the following tasks:

•	Select a decompressor.

•	Prepare the decompressor.

•	Decompress the data.

•	End decompression.

Your application handles decompression similarly to compression except that the input format is a compressed format and the output format is a displayable format. The input format for decompression is usually obtained from the stream header. After determining the input format, your application can use the ICLocate or ICOpen functions to find a decompressor that can handle it.

The ICDecompressEx functions and macros are a superset of the ICDecompress function group and provide more capabilities. The functionality of ICDecompressEx, ICDecompressExBegin, ICDecompressExEnd, and ICDecompressExQuery replaces that of the ICDecompress, ICDecompressBegin, ICDecompressEnd, and ICDecompressQuery. Use the ICDecompressEx functions and macros in place of the ICDecompress equivalents.

Decompressor and Decompression Format Selection

If you want to decompress data and your application requires a specific output format, you can use the ICDecompressExQuery function to query the decompressor to determine if it supports the input and output formats.

If the output format is not important in your application, you need only find a decompressor that can handle the input format. To determine if a decompressor can handle the input format, use ICDecompressExQuery and specify NULL for the lpbiDst parameter. Your application can determine the buffer size needed for the data specifying the decompression format by sending the ICM_DECOMPRESS_GET_FORMAT message (or the ICDecompressGetFormatSize macro). You can also send ICM_DECOMPRESS_GET_FORMAT (or the ICDecompressGetFormat macro) to retrieve the format data. The decompressor returns its suggested format in a BITMAPINFO structure. This format typically preserves the most information during decompression. Your application should ensure that the decompressor returns successfully before it decompresses the information.

Because your application allocates the memory required for decompression, it needs to determine the maximum memory the decompressor can require for the output format. The ICM_DECOMPRESS_GET_FORMAT message obtains the number of bytes the decompressor uses for the default format.

If your application defines its own format by using ICDecompressExQuery, it must also obtain a palette for the bitmap; ICDecompressExQuery does not provide palette definitions. (Most applications use standard formats and do not need to obtain a palette.) Your application can obtain the palette by sending the ICM_DECOMPRESS_GET_PALETTE message (or the ICDecompressGetPalette macro).

Decompressor Initialization

After your application selects a decompressor that can handle the input and output formats it needs, you can initialize the decompressor by using the ICDecompressExBegin function. This function requires the decompressor handle and the input and output formats.

Data Decompression

You can use the ICDecompressEx function to decompress a frame. Your application must use this function repeatedly until all the frames in a sequence are decompressed.

If your video stream lags behind other components (such as audio) during playback, your application can specify the ICDECOMPRESS_HURRYUP flag to speed decompression. To do this, a decompressor might extract only the information it needs to decompress the next frame and not fully decompress the current frame. Therefore, your application should not try to draw the decompressed data when it uses this flag.

After your application has decompressed the data, it can send the ICM_DECOMPRESSEX_END message (or the ICDecompressExEnd macro) to notify the decompressor that it has finished. If you want to restart decompression after using this function, your application must reinitialize the decompressor by using ICDecompressExBegin.


Monitoring the Progress of Compressors and Decompressors

Your application can monitor the progress of a lengthy operation performed by a compressor or decompressor by sending it the address of a callback function. You can use the ICSetStatusProc function to send the address to the compressor or decompressor. When the compressor or decompressor receives this address, it sends status messages to the function. These messages indicate whether the operation is starting, stopping, yielding, or proceeding.


Hardware Drawing Capabilities

Some renderers can draw directly to video hardware as they decompress video frames. These renderers return the VIDCF_DRAW flag in response to the ICGetInfo function. When using this type of renderer, your application does not have to handle the decompressed data. It lets the renderer retain the decompressed data for drawing.

If your application uses a renderer with drawing capabilities, it must handle the following tasks:

•	Select a renderer.

•	Specify image formats.

•	Initialize the renderer.

•	Draw the data.

•	Control drawing parameters.

Renderer Selection

The ICDrawOpen macro opens a renderer that can draw images with the specified format. It returns a handle of a renderer if it is successful or zero otherwise. This macro uses the ICLocate function to open the renderer.

Specifying Image Formats

Because your application does not need to draw the decompressed data, it does not require a specific output format. It must, however, ensure that the renderer can draw using the input format by using the ICM_DRAW_QUERY message (or the ICDrawQuery macro). This message cannot determine if a renderer can draw a bitmap. If your application must determine if the renderer can draw the bitmap, use this message with the ICDrawBegin function.

Your application can have a renderer suggest an input format by using the ICDrawSuggestFormat function. This function is used when a renderer separates the drawing capabilities from the decompressing capabilities. Most applications using the drawing functions will not need to determine the output format.

Renderer Initialization

The ICDrawBegin function initializes a renderer and tells it the drawing destination. This function can also perform the following tasks:

•	Determine whether the renderer supports a specific input format.

•	Specify whether the drawing operation occupies a window or the entire screen.

•	Specify the part of the image to display using the source rectangle.

•	Define the playback rate of the image sequence.

Some renderers buffer the compressed data to operate more efficiently. Your application can send the ICM_GETBUFFERSWANTED message (or the ICGetBuffersWanted macro) to determine the number of buffers the renderer requests. Your application should preload these buffers and send them to the renderer before drawing.

Drawing the Data

You can use the ICDraw function to decompress the data for drawing. The renderer, however, does not start drawing data until your application sends the ICM_DRAW_START message (or the ICDrawStart macro). When your application calls this function, the renderer begins to draw the frames at the rate specified by the dwRate parameter divided by the dwScale parameter; these parameters were supplied when the application initialized the renderer by using the ICDrawBegin function. Drawing continues until your application stops the renderer drawing clock by sending the ICM_DRAW_STOP message (or the ICDrawStop macro).

Note  If a renderer buffers the data before drawing, your application should not use ICDrawStart until it has sent the number of frames the renderer returned for the ICGetBuffersWanted macro.

The lTime parameter of ICDraw specifies the time to draw a frame. The renderer divides this integer by the time scale specified with ICDrawBegin to obtain the actual time. Times for ICDraw functions are relative to ICDrawStart. ICDrawStart sets the clock to zero. For example, if your application specifies 1000 for the time scale and 75 for lTime, the renderer draws the frame 75 milliseconds into the sequence.

Controlling Drawing Parameters

You can monitor the clock of a renderer by sending the ICM_DRAW_GETTIME message (or the ICDrawGetTime macro), and you can set the clock of a renderer that can draw data by sending the ICM_DRAW_SETTIME message (or the ICDrawSetTime macro).

To change the current position while a renderer is drawing, your application can send the ICM_DRAW_WINDOW message (or the ICDrawWindow macro) for repositioning the window. Applications typically use this message whenever the window changes.

If the playback window gets a palette-realize message, your application must send the ICM_DRAW_REALIZE message (or the ICDrawRealize macro) to have the renderer realize the palette again for playback. Applications can change the palette by sending the ICM_DRAW_CHANGEPALETTE message (or the ICDrawChangePalette macro) and obtain the current palette by sending the ICM_DRAW_GET_PALETTE message.

Some renderers must be specifically instructed to display frames passed to them. Sending the ICM_DRAW_RENDERBUFFER message (or the ICDrawRenderBuffer macro) causes these renderers to draw the frame.


Using the Video Compression Manager

This section contains examples demonstrating how to perform the following tasks:

•	Locate and open compressors and decompressors.

•	Install compressors and decompressors.

•	Configure compressors and decompressors.

•	Get information about compressors and decompressors.

•	Determine a compressor's output format.

•	Compress data.

•	Determine a decompressor's output format.

•	Decompress data.

•	Determine if a driver can handle the input format.

•	Prepare to draw data.

•	Draw data.

•	Monitor compressor and decompressor progress.


Locating and Opening Compressors and Decompressors

The following example attempts to find a compressor that can compress an 8-bits-per-pixel bitmap:

BITMAPINFOHEADER bih;

HIC              hIC

// Initialize the bitmap structure.

bih.biSize = sizeof(BITMAPINFOHEADER);

bih.biWidth = bih.biHeight = 0;

bih.biPlanes = 1;

bih.biCompression = BI_RGB;      // standard RGB bitmap

bih.biBitcount = 8;              // 8 bits-per-pixel format

bih.biSizeImage = 0;

bih.biXPelsPerMeter = bih.biYPelsPerMeter = 0;

bih.biClrUsed = bih.biClrImportant = 256;

hIC = ICLocate (ICTYPE_VIDEO, 0L, (LPBITMAPINFOHEADER) &bih,
    NULL, ICMODE_COMPRESS);

The following example enumerates the decompressors in the system to find one that can handle the format of its images. This example uses ICTYPE_VIDEO (which is equivalent to the "VIDC" four-character code) and the ICDecompressQuery macro to determine if a compressor or decompressor supports the image format.

for (i=0; ICInfo(fccType, i, &icinfo); i++)

{

    hic = ICOpen(icinfo.fccType, icinfo.fccHandler, ICMODE_QUERY);

    if (hic)

    {

        // Skip this compressor if it can't handle the specified format.

        if (fccType == ICTYPE_VIDEO && pvIn != NULL &&

            ICDecompressQuery(hic, pvIn, NULL) != ICERR_OK)

        {

            ICClose(hic);

            continue;

        }

        // Find out the compressor name.

        ICGetInfo(hic, &icinfo, sizeof(icinfo));

        // Add it to the combo box.

        n = ComboBox_AddString(hwndC,icinfo.szDescription);

        ComboBox_SetItemData(hwndC, n, hic);

    }

}

The following example attempts to locate a specific compressor to compress the 8-bit RGB format to an 8-bit RLE format.

BITMAPINFOHEADER    bihIn, bihOut;

HIC                 hIC

// Initialize the bitmap structure.

biSize = bihOut.biSize = sizeof(BITMAPINFOHEADER);

bihIn.biWidth = bihIn.biHeight = bihOut.biWidth = bihOut.biHeight = 0;

bihIn.biPlanes = bihOut.biPlanes= 1;

bihIn.biCompression = BI_RGB;        // standard RGB bitmap for input

bihOut.biCompression = BI_RLE8;      // 8-bit RLE for output format

bihIn.biBitcount = bihOut.biBitCount = 8;  // 8 bits-per-pixel format

bihIn.biSizeImage = bihOut.biSizeImage = 0;

bihIn.biXPelsPerMeter = bih.biYPelsPerMeter =
    bihOut.biXPelsPerMeter = bihOut.biYPelsPerMeter = 0;

bihIn.biClrUsed = bih.biClrImportant =
    bihOut.biClrUsed = bihOut.biClrImportant = 256;

hIC = ICLocate (ICTYPE_VIDEO, 0L,

    (LPBITMAPINFOHEADER)&bihIn,

    (LPBITMAPINFOHEADER)&bihOut, ICMODE_COMPRESS);


Installing Compressors and Decompressors

The following example shows how an application can install a function as a compressor or decompressor.

// This function looks like a DriverProc entry point.

LRESULT MyCodecFunction(DWORD dwID, HDRVR hDriver,

    UINT uiMessage, LPARAM lParam1, LPARAM lParam2);

// This function installs the MyCodecFunction as a compressor.

result = ICInstall ( ICTYPE_VIDEO, mmioFOURCC('s','a','m','p'),

(LPARAM)(FARPROC)&MyCodecFunction, NULL, ICINSTALL_FUNCTION);


Configuring Compressors and Decompressors

The following example demonstrates how to test if a compressor supports the configuration dialog box and to display it if it does.

// If the compressor handles a configuration dialog box, display it

// using our application window as the parent window.

if (ICQueryConfigure(hIC)) ICConfigure(hIC, hwndApp);

The following example shows how to obtain the state data.

dwStateSize = ICGetStateSize(hIC);    // gets size of buffer required

h = GlobalAlloc(GHND, dwStateSize);   // allocates buffer

ICGetState(hIC, (LPVOID)lpData, dwStateSize);  // gets the state data

// Store the state data as required.

The following example shows how to restore state data. State data restored by applications should not contain any changes to the state data obtained from a driver.

ICSetState(hIC, (LPVOID)lpData, dwStateSize); // sets the new state data


Obtaining Information About Compressors and Decompressors

The following example shows how to obtain information about a compressor or decompressor.

ICINFO ICInfo;

ICGetInfo(hIC, &ICInfo, sizeof(ICInfo));

The following example uses the ICGetDefaultKeyFrameRate and ICGetDefaultQuality macros to obtain the default values:

DWORD dwKeyFrameRate, dwQuality;

dwKeyFrameRate = ICGetDefaultKeyFrameRate(hIC);

dwQuality = ICGetDefaultQuality(hIC);

The following example uses the ICQueryAbout and ICAbout macros to display an About dialog box for the compressor or decompressor, if the dialog box exists.

// If the compressor has an About dialog box, display it.
if ( ICQueryAbout(hIC)) ICAbout(hIC, hwndApp);


Determining a Compressor's Output Format

The following example determines the buffer size needed for the data specifying the compression format, allocates a buffer of the appropriate size, and retrieves the compression format information.

LPBITMAPINFOHEADER	lpbiIn, lpbiOut;

.

. // *lpbiIn must be initialized to the input format.

.

dwFormatSize = ICCompressGetFormatSize(hIC, lpbiIn);

h = GlobalAlloc(GHND, dwFormatSize);

lpbiOut = (LPBITMAPINFOHEADER)GlobalLock(h);

ICCompressGetFormat(hIC, lpbiIn, lpbiOut);

The following example uses the ICCompressQuery macro to determine if a compressor can handle the input and output formats.

LPBITMAPINFOHEADER	lpbiIn, lpbiOut;

// Both *lpbiIn and *lpbiOut must be initialized to the respective
// formats.

if (ICCompressQuery(hIC, lpbiIn, lpbiOut) == ICERR_OK){

.

. // Format is supported; use the compressor.

.

}

The following example determines the buffer size and allocates a buffer of that size.

// Find the worst-case buffer size.

dwCompressBufferSize = ICCompressGetSize(hIC, lpbiIn, lpbiOut);

// Allocate a buffer and get lpOutput to point to it.

h = GlobalAlloc(GHND, dwCompressBufferSize);

lpOutput = (LPVOID)GlobalLock(h);


Compressing Data

The following example compresses image data for use in an AVI file. It assumes the compressor does not support the VIDCF_CRUNCH or VIDCF_TEMPORAL flags, but it does support VIDCF_QUALITY.

DWORD dwCkID;

DWORD dwCompFlags;

DWORD dwQuality;

LONG  lNumFrames, lFrameNum;

// Assume dwNumFrames is initialized to the total number of frames.

// Assume dwQuality holds the proper quality value (0-10000).

// Assume lpbiOut, lpOut, lpbiIn, and lpIn are initialized properly.

// If OK to start, compress each frame.

if (ICCompressBegin(hIC, lpbiIn, lpbiOut) == ICERR_OK){

    for ( lFrameNum = 0; lFrameNum < lNumFrames; lFrameNum++){

        if (ICCompress(hIC, 0, lpbiOut, lpOut, lpbiIn, lpIn,

            &dwCkID, &dwCompFlags, lFrameNum,

            0, dwQuality, NULL, NULL) == ICERR_OK){

            // Write compressed data to the AVI file.

            .

            .  // Set lpIn to the next frame in the sequence.

            .

        }

        else {

            // Handle compressor error.

        }

    }

    ICCompressEnd(hIC);    // terminate compression

}

else {

    // Handle the error identifying the unsupported format.

}


Determining a Decompressor's Output Format

The following example determines the buffer size needed for the data specifying the decompression format, allocates a buffer of the appropriate size, and retrieves the decompression format information.

LPBITMAPINFOHEADER lpbiIn, lpbiOut;

// Assume *lpbiIn points to the input (compressed) format.

dwFormatSize = ICDecompressGetFormatSize(hIC, lpbiIn);

h = GlobalAlloc(GHND, dwFormatSize);

lpbiOut = (LPBITMAPINFOHEADER)GlobalLock(h);

ICDecompressGetFormat(hIC, lpbiIn, lpbiOut);

The following example shows how an application can use the ICDecompressQuery macro to determine if a decompressor can handle the input and output formats.

LPBITMAPINFOHEADER lpbiIn, lpbiOut;

// Assume *lpbiIn & *lpbiOut are initialized to the respective
// formats.

if (ICDecompressQuery(hIC, lpbiIn, lpbiOut) == ICERR_OK){

    .

    . // Format is supported - use the decompressor.

    .

}

The following fragment shows how to get the palette information:

ICDecompressGetPalette(hIC, lpbiIn, lpbiOut);

// Move up to the palette.

lpPalette = (LPBYTE)lpbiOut + lpbi->biSize;


Decompressing Data

The following example shows how an application can initialize a decompressor, decompress a frame sequence, and terminate decompression.

LPBITMAPINFOHEADER lbpiIn, lpbiOut;

LPVOID             lpIn, lpOut;

LONG               lNumFrames, lFrameNum;

// Assume lpbiIn and lpbiOut are initialized to the input and output

// format and lpIn and lpOut are pointing to the buffers.

if (ICDecompressBegin(hIC, lpbiIn, lpbiOut) == ICERR_OK){

    for (lFrameNum = 0; lFrameNum < lNumFrames, lFrameNum++){

        if (ICDecompress(hIC, 0, lpbiIn, lpIn, lpbiOut,

            lpOut) == ICERR_OK)

        {

            // Frame decompressed OK so we can process it as required.

        } else {

            // Handle the decompression error that occurred.

        }

    }

    ICDecompressEnd(hIC);

} else {

    // Handle the error identifying an unsupported format.

}


Determining If a Driver Can Handle the Input Format

The following example shows how to check the input format with the ICDrawQuery macro.

// lpbiIn points to BITMAPINFOHEADER structure indicating the input
// format.

if (ICDrawQuery(hIC, lpbiIn) == ICERR_OK)

{

    // Driver recognizes the input format.

} else {

    // Need a different decompressor.

}


Preparing to Draw Data

The following example shows the initialization sequence that instructs the decompressor to draw full-screen.

// Assume lpbiIn has the input format, dwRate has the data rate.

if (ICDrawBegin(hIC, ICDRAW_QUERY | ICDRAW_FULLSCREEN, NULL, NULL,

    NULL, 0, 0, 0, 0, lpbiIn, 0, 0, 0, 0, dwRate,

    dwScale) == ICERR_OK)

{

    // Decompressor supports this drawing so set up to draw.

    ICDrawBegin(hIC, ICDRAW_FULLSCREEN, hPal, NULL, NULL, 0, 0, 0,
        0, lpbiIn, 0, 0, lbpi->biWidth, lpbi->biHeight, dwRate,
        dwScale);

    .

    . // Start decompressing and drawing frames.

    .

    // Drawing done. Terminate procedure.

    ICDrawEnd(hIC);

} else {

    .

    . // Use another renderer to draw data on the screen;

    . // ICDraw does not support the format.

}


Drawing Data

The following example uses the ICDraw functions to draw data on the screen.

DWORD    dwNumBuffers;

// Find out how many buffers need filling before drawing starts.
ICGetBuffersWanted(hIC, &dwNumBuffers);

for (dw = 0; dw < dwNumBuffers; dw++){

    ICDraw(hIC, 0, lpFormat, lpData, cbData, dw); // fill the pipeline
    .

    . // Point lpFormat and lpData to next format and buffer.
    .

}

ICDrawStart(hIC);  // starts the clock

dw = 0;

while (fPlaying) {

    ICDraw(hIC, 0, lpFormat, lpData, chData, dw); // fill more buffers

    .

    . // Point lpFormat and lpData to next format and buffer,
    . // update dw.
}

ICDrawStop(hIC);   // stops drawing and decompressing when done

ICDrawFlush(hIC);  // flushes any existing buffers

ICDrawEnd(hIC);    // ends decompression


Monitoring Compressor and Decompressor Progress

The following example shows how the ICSetStatusProc function is used to inform the compressor or decompressor of the callback function address:

ICSetStatusProc(compvars.hic, 0, (LPARAM) (UINT) hwndApp,
    &PreviewStatusProc);

The following example shows the callback function installed by the previous fragment:

LONG CALLBACK export PreviewStatusProc(LPARAM lParam,
    UINT message, LONG l)

{

    switch (message) {

    MSG msg;

    case ICSTATUS_START:

         .

         . // Create and display status dialog box.

         .

         break;

    case ICSTATUS_STATUS:

        ProSetBarPos((int) l); // sets status bar positions

        // Watch for abort message

        while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {

            if (msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE)

                return 1;

            if (msg.message == WM_SYSCOMMAND &&
                (msg.wParam & 0xFFF0) == SC_CLOSE)

        	        return 1;

            TranslateMessage(&msg);

            DispatchMessage(&msg);

        }

        break;

    case ICSTATUS_END:

         .

         . // Close and destroy status dialog box.

         .

        break;

    case ICSTATUS_YIELD:

         .

         .

         .

        break;

    }

    return 0;

}


Video Compression Manager Reference

This section describes the functions, messages and macros, notifications, and structures associated with VCM. These elements are grouped as follows.

Compressor Installation and Removal

ICInstall
ICLocate
ICOPEN
ICClose
ICRemove
ICOpenFunction

Locating and Opening a Compressor

ICLocate
ICOPEN
ICDecompressOpen
ICDrawOpen
ICINFO
ICClose

Selecting Compressors

ICCompressorChoose
ICCompressorFree
COMPVARS

Configuring Compressors

ICM_CONFIGURE
ICM_CONFIGURE
ICM_GETSTATE
ICM_GETSTATE
ICM_SETSTATE
ICSendMessage

Compressor Information

ICGetInfo
ICINFO
ICM_GETDEFAULTKEYFRAMERATE
ICGetDisplayFormat
ICM_GETDEFAULTQUALITY
ICM_ABOUT
ICM_ABOUT

Single Image Compression

ICImageCompress

Sequence Compression

ICSeqCompressFrame
ICSeqCompressFrameStart
ICSeqCompressFrameEnd

COMPVARS

ICCompressorChoose

Image Data Compression

ICM_COMPRESS_GET_FORMAT
ICM_COMPRESS_GET_FORMAT
ICM_COMPRESS_QUERY
ICM_COMPRESS_GET_SIZE
ICM_COMPRESS_BEGIN
ICCOMPRESS
ICM_COMPRESS_END
ICM_COMPRESS_BEGIN

Compressor Monitoring

ICSETSTATUSPROC

Decompressing Single Images

ICImageDecompress

Decompressing Image Data

ICDECOMPRESSEX
ICDecompressExBegin
ICM_DECOMPRESSEX_END
ICM_DECOMPRESS_GET_FORMAT
ICM_DECOMPRESS_GET_FORMAT
ICM_DECOMPRESS_GET_PALETTE
ICDecompressExQuery
ICDECOMPRESS
ICM_DECOMPRESS_BEGIN
ICM_DECOMPRESS_END
ICM_DECOMPRESS_QUERY

Using Hardware-Drawing Capabilities

ICGetInfo
ICDRAWBEGIN
ICM_DRAW_END
ICM_DRAW_FLUSH
ICM_DRAW_QUERY
ICDrawSuggestFormat
ICM_DRAW_START
ICM_DRAW_STOP
ICM_GETBUFFERSWANTED
ICM_DRAW_REALIZE
ICDrawOpen
ICDRAW
ICM_DRAW_GETTIME
ICM_DRAW_SETTIME
ICM_DRAW_WINDOW
ICM_DRAW_REALIZE
ICM_DRAW_CHANGEPALETTE
ICM_DRAW_RENDERBUFFER


Video Compression Manager Functions and Macros

An application uses VCM functions to initialize and control compression and decompression operations. These macros extend the feature set.


ICClose

LRESULT ICClose(HIC hic);

Closes a compressor or decompressor.

•	Returns ICERR_OK if successful or an error otherwise.

hic

Handle of a compressor or decompressor.


ICCompress

DWORD ICCompress(HIC hic, DWORD dwFlags, LPBITMAPINFOHEADER lpbiOutput,
    LPVOID lpData, LPBITMAPINFOHEADER lpbiInput, LPVOID lpBits,
    LPDWORD lpckid, LPDWORD lpdwFlags, LONG lFrameNum,
    DWORD dwFrameSize, DWORD dwQuality, LPBITMAPINFOHEADER lpbiPrev,
    LPVOID lpPrev);

Compresses a single video image.

•	Returns ICERR_OK if successful or an error otherwise.

hic

Handle of the compressor to use.

dwFlags

Compression flag. The following value is defined:

ICCOMPRESS_KEYFRAME

Compressor should make this frame a key frame.

lpbiOutput

Address of a BITMAPINFO structure containing the output format.

lpData

Address of an output buffer large enough to contain a compressed frame.

lpbiInput

Address of a BITMAPINFO structure containing the input format.

lpBits

Address of the input buffer.

lpckid

Reserved; do not use.

lpdwFlags

Address of the return flags used in the AVI index. The following value is defined:

AVIIF_KEYFRAME

Current frame is a key frame.

lFrameNum

Frame number.

dwFrameSize

Requested frame size, in bytes. Specify a nonzero value if the compressor supports a suggested frame size, as indicated by the presence of the VIDCF_CRUNCH flag returned by the ICGetInfo function. If this flag is not set or a data rate for the frame is not specified, specify zero for this parameter.

A compressor might have to sacrifice image quality or make some other trade-off to obtain the size goal specified in this parameter.

dwQuality

Requested quality value for the frame. Specify a nonzero value if the compressor supports a suggested quality value, as indicated by the presence of the VIDCF_QUALITY flag returned by ICGetInfo. Otherwise, specify zero for this parameter.

lpbiPrev

Address of a BITMAPINFO structure containing the format of the previous frame.

lpPrev

Address of the uncompressed image of the previous frame. This parameter is not used for fast temporal compression. Specify NULL for this parameter when compressing a key frame, if the compressor does not support temporal compression, or if the compressor does not require an external buffer to store the format and data of the previous image.

You can obtain the required by size of the output buffer by sending the ICM_COMPRESS_GET_SIZE message (or by using the ICCompressGetSize macro).

The compressor sets the contents of lpdwFlags to AVIIF_KEYFRAME when it creates a key frame. If your application creates AVI files, it should save the information returned for lpckid and lpdwFlags in the file.

Compressors use lpbiPrev and lpPrev to perform temporal compression and require an external buffer to store the format and data of the previous frame. Specify NULL for lpbiPrev and lpPrev when compressing a key frame, when performing fast compression, or if the compressor has its own buffer to store the format and data of the previous image. Specify non-NULL values for these parameters if ICGetInfo returns the VIDCF_TEMPORAL flag, the compressor is performing normal compression, and the frame to compress is not a key frame.


ICCompressorChoose

BOOL ICCompressorChoose(HWND hwnd, UINT uiFlags, LPVOID pvIn,
    LPVOID lpData, PCOMPVARS pc, LPSTR lpszTitle);

Displays a dialog box in which a user can select a compressor. This function can display all registered compressors or list only the compressors that support a specific format.

•	Returns TRUE if the user chooses a compressor and presses OK. Returns FALSE on error or if the user presses CANCEL.

hwnd

Handle of a parent window for the dialog box.

uiFlags

Applicable flags. The following values are defined:

ICMF_CHOOSE_ALLCOMPRESSORS

All compressors should appear in the selection list. If this flag is not specified, only the compressors that can handle the input format appear in the selection list.

ICMF_CHOOSE_DATARATE

Displays a check box and edit box to enter the data rate for the movie.

ICMF_CHOOSE_KEYFRAME

Displays a check box and edit box to enter the frequency of key frames.

ICMF_CHOOSE_PREVIEW

Displays a button to expand the dialog box to include a preview window. The preview window shows how frames of your movie will appear when compressed with the current settings.

pvIn

Uncompressed data input format. Only compressors that support the specified data input format are included in the compressor list. This parameter is optional.

lpData

Address of an AVI stream interface to use in the preview window. You must specify a video stream. This parameter is optional.

pc

Address of a COMPVARS structure. The information returned initializes the structure for use with other functions.

lpszTitle

Address of a null-terminated string containing a title for the dialog box. This parameter is optional.

Before using this function, set the cbSize member of the COMPVARS structure to the size of the structure. Initialize the rest of the structure to zeros unless you want to specify some valid defaults for the dialog box. If specifying defaults, set the dwFlags member to ICMF_COMPVARS_VALID and initialize the other members of the structure. For more information about initializing the structure, see the  ICSeqCompressFrameStart function and COMPVARS.


ICCompressorFree

void ICCompressorFree(PCOMPVARS pc);

Frees the resources in the COMPVARS structure used by other VCM functions.

pc

Address of the COMPVARS structure containing the resources to be freed.

Use this function to release the resources in the COMPVARS structure after using the ICCompressorChoose, ICSeqCompressFrameStart, ICSeqCompressFrame, and ICSeqCompressFrameEnd functions.


ICDecompress

DWORD ICDecompress(HIC hic, DWORD dwFlags,
    LPBITMAPINFOHEADER lpbiFormat, LPVOID lpData,
    LPBITMAPINFOHEADER lpbi, LPVOID lpBits);

Decompresses a single video frame.

•	Returns ICERR_OK if successful or an error otherwise.

hic

Handle of the decompressor to use.

dwFlags

Applicable decompression flags. The following values are defined:

ICDECOMPRESS_HURRYUP

Tries to decompress at a faster rate. When an application uses this flag, the driver should buffer the decompressed data but not draw the image.

ICDECOMPRESS_NOTKEYFRAME

Current frame is not a key frame.

ICDECOMPRESS_NULLFRAME

Current frame does not contain data and the decompressed image should be left the same.

ICDECOMPRESS_PREROLL

Current frame precedes the point in the movie where playback starts and, therefore, will not be drawn.

ICDECOMPRESS_UPDATE

Screen is being updated or refreshed.

lpbiFormat

Address of a BITMAPINFO structure containing the format of the compressed data.

lpData

Address of the input data.

lpbi

Address of a BITMAPINFO structure containing the output format.

lpBits

Address of a buffer that is large enough to contain the decompressed data.


ICDecompressEx

DWORD ICDecompressEx(HIC hic, DWORD dwFlags, LPBITMAPINFOHEADER lpbiSrc,
    LPVOID lpSrc, int xSrc, int ySrc, int dxSrc, int dySrc,
    LPBITMAPINFOHEADER lpbiDst, LPVOID lpDst, int xDst, int yDst,
    int dxDst, int dyDst);

Decompresses a single video frame.

•	Returns ICERR_OK if successful or an error otherwise.

hic

Handle of the decompressor.

dwFlags

Decompression flags. The following values are defined:

ICDECOMPRESS_HURRYUP

Tries to decompress at a faster rate. When an application uses this flag, the driver should buffer the decompressed data but not draw the image.

ICDECOMPRESS_NOTKEYFRAME

Current frame is not a key frame.

ICDECOMPRESS_NULLFRAME

Current frame does not contain data and the decompressed image should be left the same.

ICDECOMPRESS_PREROLL

Current frame precedes the point in the movie where playback starts and, therefore, will not be drawn.

ICDECOMPRESS_UPDATE

Screen is being updated or refreshed.

lpbiSrc

Address of a BITMAPINFOHEADER structure containing the format of the compressed data.

lpSrc

Address of the input data.

xSrc, ySrc

The x- and y- coordinates of the source rectangle for the DIB specified by lpbiSrc.

dxSrc, dySrc

Width and height of the source rectangle.

lpbiDst

Address of a BITMAPINFOHEADER structure containing the output format.

lpDst

Address of a buffer that is large enough to contain the decompressed data.

xDst, yDst

The x- and y-coordinates of the destination rectangle for the DIB specified by lpbiDst.

dxDst, dyDst

Width and height of the destination rectangle.

Typically, applications use the ICDECOMPRESS_PREROLL flag to seek to a key frame in a compressed stream. The flag is sent with the key frame and with subsequent frames required to decompress the desired frame.


ICDecompressExBegin

DWORD ICDecompressExBegin(HIC hic, DWORD dwFlags,
    LPBITMAPINFOHEADER lpbiSrc, LPVOID lpSrc, int xSrc, int ySrc,
    int dxSrc, int dySrc, LPBITMAPINFOHEADER lpbiDst, LPVOID lpDst,
    int xDst, int yDst, int dxDst, int dyDst);

Prepares a decompressor for decompressing data.

•	Returns ICERR_OK if successful or an error otherwise.

hic

Handle of the decompressor to use.

dwFlags

Decompression flags. The following values are defined:

ICDECOMPRESS_HURRYUP

Tries to decompress at a faster rate. When an application uses this flag, the driver should buffer the decompressed data but not draw the image.

ICDECOMPRESS_NOTKEYFRAME

Current frame is not a key frame.

ICDECOMPRESS_NULLFRAME

Current frame does not contain data and the decompressed image should be left the same.

ICDECOMPRESS_PREROLL

Current frame precedes the point in the movie where playback starts and, therefore, will not be drawn.

ICDECOMPRESS_UPDATE

Screen is being updated or refreshed.

lpbiSrc

Address of a BITMAPINFOHEADER structure containing the format of the compressed data.

lpSrc

Address of the input data.

xSrc, ySrc

The x- and y-coordinates of the source rectangle for the DIB specified by lpbiSrc.

dxSrc, dySrc

Width and height of the source rectangle.

lpbiDst

Address of a BITMAPINFOHEADER structure containing the output format.

lpDst

Address of a buffer that is large enough to contain the decompressed data.

xDst, yDst

The x- and y-coordinates of the destination rectangle for the DIB specified by lpbiDst.

dxDst, dyDst

Width and height of the destination rectangle.


ICDecompressExQuery

DWORD ICDecompressExQuery(HIC hic, DWORD dwFlags,
    LPBITMAPINFOHEADER lpbiSrc, LPVOID lpSrc, int xSrc, int ySrc,
    int dxSrc, int dySrc, LPBITMAPINFOHEADER lpbiDst, LPVOID lpDst,
    int xDst, int yDst, int dxDst, int dyDst);

Determines if a decompressor can decompress data with a specific format.

•	Returns ICERR_OK if successful or an error otherwise.

hic

Handle of the decompressor to use.

dwFlags

Reserved; do not use.

lpbiSrc

Address of a BITMAPINFOHEADER structure containing the format of the compressed data to decompress.

lpSrc

Reserved; must be NULL.

xSrc, ySrc

The x- and y-coordinates of the source rectangle for the DIB specified by lpbiSrc.

dxSrc, dySrc

Width and height of the source rectangle.

lpbiDst

Address of a BITMAPINFOHEADER structure containing the output format. If the value of this parameter is NULL, the function determines whether the input format is supported and this parameter is ignored.

lpDst

Address of a buffer that is large enough to contain the decompressed data.

xDst, yDst

The x- and y-coordinates of the destination rectangle for the DIB specified by lpbiDst.

dxDst, dyDst

Width and height of the destination rectangle.


ICDecompressOpen

HIC ICDecompressOpen(DWORD fccType, DWORD fccHandler,
    LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)

Opens a decompressor that is compatible with the specified formats.

•	Returns a handle of a decompressor if successful or zero otherwise.

fccType

Four-character code indicating the type of compressor to open. For video streams, the value of this parameter is "VIDC" or ICTYPE_VIDEO.

fccHandler

Four-character code indicating the preferred stream handler to use. Typically, this information is stored in the stream header in an AVI file.

lpbiIn

Address of a structure defining the input format. A decompressor handle is not returned unless it can decompress this format. For bitmaps, this parameter refers to a BITMAPINFOHEADER structure.

lpbiOut

Address of a structure defining an optional decompression format. You can also specify zero to use the default output format associated with the input format.

If this parameter is nonzero, a compressor handle is not returned unless it can create this output format. For bitmaps, this parameter refers to a BITMAPINFOHEADER structure.

The ICDecompressOpen macro is defined as follows:

#define ICDecompressOpen(fccType, fccHandler, lpbiIn, lpbiOut) \

    ICLocate(fccType, fccHandler, lpbiIn, lpbiOut, ICMODE_DECOMPRESS);


ICDraw

DWORD ICDraw(HIC hic, DWORD dwFlags, LPVOID lpFormat,
    LPVOID lpData, DWORD cbData, LONG lTime);

Decompresses an image for drawing.

•	Returns ICERR_OK if successful or an error otherwise.

hic

Handle of an decompressor.

dwFlags

Decompression flags. The following values are defined:

ICDRAW_HURRYUP

Data is buffered and not drawn to the screen. Use this flag for fastest decompression.

ICDRAW_NOTKEYFRAME

Current frame is not a key frame.

ICDRAW_NULLFRAME

Current frame does not contain any data and the previous frame should be redrawn.

ICDRAW_PREROLL

Current frame of video occurs before playback should start. For example, if playback will begin on frame 10, and frame 0 is the nearest previous key frame, frames 0 through 9 are sent to the driver with the ICDRAW_PREROLL flag set. The driver needs this data to display frame 10 properly.

ICDRAW_UPDATE

Updates the screen based on previously received data. Set lpData to NULL when this flag is used.

lpFormat

Address of a BITMAPINFOHEADER structure containing the input format of the data.

lpData

Address of the input data.

cbData

Size of the input data, in bytes.

lTime

Time, in samples, to draw this frame. The units for video data are frames. For a definition of the playback rate, see the dwRate and dwScale members of the ICDRAWBEGIN structure.

You can initiate drawing the frames by sending the ICM_DRAW_START message (or by using the ICDrawStart macro). The application should be sure to buffer the required number of frames before drawing is started. Send the KM_GETBUFFERSWANTED message (or use the ICGetBuffersWanted macro) to obtain this value.


ICDrawBegin

DWORD ICDrawBegin(HIC hic, DWORD dwFlags, HPALETTE hpal, HWND hwnd,
    HDC hdc, int xDst, int yDst, int dxDst, int dyDst,
    LPBITMAPINFOHEADER lpbi, int xSrc, int ySrc, int dxSrc,
    int dySrc, DWORD dwRate, DWORD dwScale);

Initializes the renderer and prepares the drawing destination for drawing.

•	Returns ICERR_OK if the renderer can decompress the data or ICERR_UNSUPPORTED otherwise.

hic

Handle of the decompressor to use.

dwFlags

Decompression flags. The following values are defined:

ICDRAW_ANIMATE

Application can animate the palette.

ICDRAW_CONTINUE

Drawing is a continuation of the previous frame.

ICDRAW_FULLSCREEN

Draws the decompressed data on the full screen.

ICDRAW_HDC

Draws the decompressed data to a window or a DC.

ICDRAW_MEMORYDC

DC is off-screen.

ICDRAW_QUERY

Determines if the decompressor can decompress the data. The driver does not decompress the data.

ICDRAW_UPDATING

Current frame is being updated rather than played.

hpal

Handle of the palette used for drawing.

hwnd

Handle of the window used for drawing.

hdc

DC used for drawing.

xDst, yDst

The x- and y-coordinates of the upper right corner of the destination rectangle.

dxDst, dyDst

Width and height of the destination rectangle.

lpbi

Address of a BITMAPINFO structure containing the format of the input data to be decompressed.

xSrc, ySrc

The x- and y-coordinates of the upper right corner of the source rectangle.

dxSrc, dySrc

Width and height of the source rectangle.

dwRate

Frame rate numerator. The frame rate, in frames per second, is obtained by dividing dwRate by dwScale.

dwScale

Frame rate denominator. The frame rate, in frames per second, is obtained by dividing dwRate by dwScale.

The ICDRAW_HDC and ICDRAW_FULLSCREEN flags are mutually exclusive. If an application sets the ICDRAW_HDC flag in dwFlags, the decompressor uses hwnd, hdc, and the parameters defining the destination rectangle (xDst, yDst, dxDst, and dyDst). Your application should set these parameters to the size of the destination rectangle. Specify destination rectangle values relative to the current window or DC.

If an application sets the ICDRAW_FULLSCREEN flag in dwFlags, the hwnd and hdc parameters are not used and should be set to NULL. Also, the destination rectangle is not used and its parameters can be set to zero.

The source rectangle is relative to the full video frame. The portion of the video frame specified by the source rectangle is stretched or shrunk to fit the destination rectangle.

The dwRate and dwScale parameters specify the decompression rate. The integer value specified for dwRate divided by the integer value specified for dwScale defines the frame rate in frames per second. This value is used by the renderer when it is responsible for timing frames during playback.


ICDrawOpen

HIC ICDrawOpen(DWORD fccType, DWORD fccHandler,
    LPBITMAPINFOHEADER lpbiIn)

Opens a driver that can draw images with the specified format.

•	Returns a handle of a driver if successful or zero otherwise.

fccType

Four-character code indicating the type of driver to open. For video streams, the value of this parameter is "VIDC" or ICTYPE_VIDEO.

fccHandler

Four-character code indicating the preferred stream handler to use. Typically, this information is stored in the stream header in an AVI file.

lpbiIn

Address of the structure defining the input format. A driver handle will not be returned unless it can decompress this format. For images, this parameter refers to a BITMAPINFOHEADER structure.

The ICDrawOpen macro is defined as follows:

#define ICDrawOpen(fccType, fccHandler, lpbiIn) \
    ICLocate(fccType, fccHandler, lpbiIn, NULL, ICMODE_DRAW);


ICDrawSuggestFormat

DWORD ICDrawSuggestFormat(HIC hic, LPBITMAPINFOHEADER lpbiIn,
    LPBITMAPINFOHEADER lpbiOut, int dxSrc, int dySrc, int dxDst,
    int dyDst, HIC hicDecompressor);

Notifies the drawing handler to suggest the input data format.

•	Returns ICERR_OK if successful or an error otherwise.

hic

Handle of the driver to use.

lpbiIn

Address of a structure containing the format of the compressed data. For bitmaps, this is a BITMAPINFOHEADER structure.

lpbiOut

Address of a structure to return the suggested format. The drawing handler can receive and draw data from this format. For bitmaps, this is a BITMAPINFOHEADER structure.

dxSrc, dySrc

Width and height of the source rectangle.

dxDst, dyDst

Width and height of the destination rectangle.

hicDecompressor

Decompressor that can use the format of data in lpbiIn.

Applications can use this function to determine alternative input formats that a drawing handler can decompress and if the drawing handler can stretch data. If the drawing handler cannot stretch data as requested, the application might have to stretch the data.

If the drawing handler cannot decompress a format provided by an application, use the ICDecompress, ICDecompressEx, ICDecompressExBegin, ICDecompressExQuery, and ICDecompressOpen functions to obtain alternate formats.


ICGetDisplayFormat

HIC ICGetDisplayFormat(HIC hic, LPBITMAPINFOHEADER lpbiIn,
    LPBITMAPINFOHEADER lpbiOut, int BitDepth, int dx, int dy);

Determines the best format available for displaying a compressed image. The function also opens a compressor if a handle of an open compressor is not specified.

•	Returns a handle of a decompressor if successful or zero otherwise.

hic

Handle of the compressor to use. Specify NULL to have VCM select and open an appropriate compressor.

lpbiIn

Address of BITMAPINFOHEADER structure containing the compressed format.

lpbiOut

Address of a buffer to return the decompressed format. The buffer should be large enough for a BITMAPINFOHEADER structure and 256 color entries.

BitDepth

Preferred bit depth, if nonzero.

dx, dy

Width and height multipliers to stretch the image. If this parameter is zero, that dimension is not stretched.


ICGetInfo

LRESULT ICGetInfo(HIC hic, ICINFO FAR * lpicinfo, DWORD cb);

Obtains information about a compressor.

•	Returns the number of bytes copied into the structure or zero if an error occurs.

hic

Handle of a compressor.

lpicinfo

Address of the ICINFO structure to return information about the compressor.

cb

Size, in bytes, of the structure pointed to by lpicinfo.


ICImageCompress

HANDLE ICImageCompress(HIC hic, UINT uiFlags, LPBITMAPINFO lpbiIn,
    LPVOID lpBits, LPBITMAPINFO lpbiOut, LONG lQuality,
    LONG FAR * plSize);

Compresses an image to a given size. This function does not require initialization functions.

•	Returns a handle of a compressed DIB. The image data follows the format header.

hic

Handle of a compressor opened with the ICOpen function. Specify NULL to have VCM select an appropriate compressor for the compression format. An application can have the user select the compressor by using the ICCompressorChoose function, which opens the selected compressor and returns a handle of the compressor in this parameter.

uiFlags

Reserved; must be zero.

lpbiIn

Address of the BITMAPINFO structure containing the input data format.

lpBits

Address of input data bits to compress. The data bits exclude header and format information.

lpbiOut

Address of the BITMAPINFO structure containing the compressed output format. Specify NULL to have the compressor use an appropriate format.

lQuality

Quality value used by the compressor. Values range from 0 to 10,000.

plSize

Maximum size desired for the compressed image. The compressor might not be able to compress the data to fit within this size. When the function returns, this parameter points to the size of the compressed image. Image sizes are specified in bytes.

To obtain the format information from the LPBITMAPINFOHEADER structure, use the GlobalLock function to lock the data. Use the GlobalFree function to free the DIB when you are finished.


ICImageDecompress

HANDLE ICImageDecompress(HIC hic, UINT uiFlags, LPBITMAPINFO lpbiIn,
    LPVOID lpBits, LPBITMAPINFO lpbiOut);

Decompresses an image without using initialization functions.

•	Returns a handle of an uncompressed DIB in the CF_DIB format if successful or NULL otherwise. Image data follows the format header.

hic

Handle of a decompressor opened with the ICOpen function. Specify NULL to have VCM select an appropriate decompressor for the compressed image.

uiFlags

Reserved; must be zero.

lpbiIn

Compressed input data format.

lpBits

Address of input data bits to compress. The data bits exclude header and format information.

lpbiOut

Decompressed output format. Specify NULL to let decompressor use an appropriate format.

To obtain the format information from the LPBITMAPINFOHEADER structure, use the GlobalLock function to lock the data. Use the GlobalFree function to free the DIB when you are finished.


ICInfo

BOOL ICInfo(DWORD fccType, DWORD fccHandler, ICINFO FAR * lpicinfo);

Retrieves information about specific installed compressors or enumerates the installed compressors.

•	Returns TRUE if successful or FALSE otherwise.

fccType

Four-character code indicating the type of compressor. Specify zero to match all compressor types.

fccHandler

Four-character code identifying a specific compressor or a number between zero and the number of installed compressors of the type specified by fccType.

lpicinfo

Address of a ICINFO structure to return information about the compressor.

To enumerate the compressors or decompressors, specify an integer for fccHandler. This function returns information for integers between zero and the number of installed compressors or decompressors of the type specified for fccType.


ICInstall

BOOL ICInstall(DWORD fccType, DWORD fccHandler, LPARAM lParam,
    LPSTR szDesc, UINT wFlags);

Installs a new compressor or decompressor.

•	Returns TRUE if successful or FALSE otherwise.

fccType

Four-character code indicating the type of data used by the compressor or decompressor. Specify "VIDC" for a video compressor or decompressor.

fccHandler

Four-character code identifying a specific compressor or decompressor.

lParam

Address of a null-terminated string containing the name of the compressor or decompressor, or the address of a function used for compression or decompression. The contents of this parameter are defined by the flags set for wFlags.

szDesc

Reserved; do not use.

wFlags

Flags defining the contents of lParam. The following values are defined:

ICINSTALL_DRIVER

The lParam parameter contains the address of a
null-terminated string that names the compressor to install.

ICINSTALL_FUNCTION

The lParam parameter contains the address of a compressor function. This function should be structured like the DriverProc entry point function used by compressors.

Applications must open an installed compressor or decompressor before using it.

If your application installs a function as a compressor or decompressor, it should remove the function with the ICRemove function before it terminates. This prevents other applications from trying to access the function when it is not available.


ICLocate

HIC ICLocate(DWORD fccType, DWORD fccHandler, LPBITMAPINFOHEADER lpbiIn,
    LPBITMAPINFOHEADER lpbiOut, WORD wFlags);

Finds a compressor or decompressor that can handle images with the specified formats, or finds a driver that can decompress an image with a specified format directly to hardware.

•	Returns a handle of a compressor or decompressor if successful or zero otherwise.

fccType

Four-character code indicating the type of compressor or decompressor to open. For video streams, the value of this parameter is "VIDC".

fccHandler

Preferred handler of the specified type. Typically, the handler type is stored in the stream header in an AVI file. Specify NULL if your application can use any handler type or it does not know the handler type to use.

lpbiIn

Address of a BITMAPINFOHEADER structure defining the input format. A compressor handle is not returned unless it supports this format.

lpbiOut

Address of a BITMAPINFOHEADER structure defining an optional decompressed format. You can also specify zero to use the default output format associated with the input format.

If this parameter is nonzero, a compressor handle is not returned unless it can create this output format.

wFlags

Flags that describe the search criteria for a compressor or decompressor. The following values are defined:

ICMODE_COMPRESS

Finds a compressor that can compress an image with a format defined by lpbiIn to the format defined by lpbiOut.

ICMODE_DECOMPRESS

Finds a decompressor that can decompress an image with a format defined by lpbiIn to the format defined by lpbiOut.

ICMODE_DRAW

Finds a decompressor that can decompress an image with a format defined by lpbiIn and draw it directly to hardware.

ICMODE_FASTCOMPRESS

Has the same meaning as ICMODE_COMPRESS except the compressor is used for a real-time operation and emphasizes speed over quality.

ICMODE_FASTDECOMPRESS

Has the same meaning as ICMODE_DECOMPRESS except the decompressor is used for a real-time operation and emphasizes speed over quality.


ICOpen

HIC ICOpen(DWORD fccType, DWORD fccHandler, UINT wMode);

Opens a compressor or decompressor.

•	Returns a handle of a compressor or decompressor if successful or zero otherwise.

fccType

Four-character code indicating the type of compressor or decompressor to open. For video streams, the value of this parameter is "VIDC".

fccHandler

Preferred handler of the specified type. Typically, the handler type is stored in the stream header in an AVI file.

wMode

Flag defining the use of the compressor or decompressor. The following values are defined:

ICMODE_COMPRESS

Compressor will perform normal compression.

ICMODE_DECOMPRESS

Decompressor will perform normal decompression.

ICMODE_DRAW

Decompressor will decompress and draw the data directly to hardware.

ICMODE_FASTCOMPRESS

Compressor will perform fast (real-time) compression.

ICMODE_FASTDECOMPRESS

Decompressor will perform fast (real-time) decompression.

ICMODE_QUERY

Queries the compressor or decompressor for information.


ICOpenFunction

HIC ICOpenFunction(DWORD fccType, DWORD fccHandler, UINT wMode,
    FARPROC lpfnHandler);

Opens a compressor or decompressor defined as a function.

•	Returns a handle of a compressor or decompressor if successful or zero otherwise.

fccType

Type of compressor to open. For video, the value of this parameter is ICTYPE_VIDEO.

fccHandler

Preferred handler of the specified type. Typically, this comes from the stream header in an AVI file.

wMode

Flag to define the use of the compressor or decompressor. The following values are defined:

ICMODE_COMPRESS

Compressor will perform normal compression.

ICMODE_DECOMPRESS

Decompressor will perform normal decompression.

ICMODE_DRAW

Decompressor will decompress and draw the data directly to hardware.

ICMODE_FASTCOMPRESS

Compressor will perform fast (real-time) compression.

ICMODE_FASTDECOMPRESS

Decompressor will perform fast (real-time) decompression.

ICMODE_QUERY

Queries the compressor or decompressor for information.

lpfnHandler

Address of the function used as the compressor or decompressor.


ICRemove

BOOL ICRemove(DWORD fccType, DWORD fccHandler, UINT wFlags);

Removes an installed compressor.

•	Returns TRUE if successful or FALSE otherwise.

fccType

Four-character code indicating the type of data used by the compressor or decompressor. Specify "VIDC" for a video compressor or decompressor.

fccHandler

Four-character code identifying a specific compressor or a number between zero and the number of installed compressors of the type specified by fccType.

wFlags

Reserved; do not use.


ICSendMessage

LRESULT ICSendMessage(HIC hic, UINT wMsg, DWORD dw1, DWORD dw2);

Sends a message to a compressor.

•	Returns a message-specific result.

hic

Handle of the compressor to receive the message.

wMsg

Message to send.

dw1

Additional message-specific information.

dw2

Additional message-specific information.


ICSeqCompressFrame

LPVOID ICSeqCompressFrame(PCOMPVARS pc, UINT uiFlags,
    LPVOID lpBits, BOOL FAR * pfKey, LONG FAR * plSize);

Compresses one frame in a sequence of frames.

•	Returns the address of the compressed bits or NULL if an error occurs.

pc

Address of a COMPVARS structure initialized with information about the compression.

uiFlags

Reserved; must be zero.

lpBits

Address of the data bits to compress. (The data bits exclude header or format information.)

pfKey

Returns whether or not the frame was compressed into a key frame.

plSize

Maximum size desired for the compressed image. The compressor might not be able to compress the data to fit within this size. When the function returns, the parameter points to the size of the compressed image. Images sizes are specified in bytes.

This function uses a COMPVARS structure to provide settings for the specified compressor and intersperses key frames at the rate specified by the ICSeqCompressorFrameStart function. You can specify values for the data rate for the sequence and the key-frame frequency by using the appropriate members of COMPVARS.

Use this function instead of the ICCompress function to compress a video sequence.

You can allow the user to specify a compressor and initialize a COMPVARS structure by using the ICCompressorChoose function. Or, you can initialize a COMPVARS structure manually.

Use the ICSeqCompressFrameStart, ICSeqCompressFrame, and ICSeqCompressFrameEnd functions to compress a sequence of frames to a specified data rate and number of key frames. Use ICSeqCompressFrame once for each frame to be compressed.

When finished with compression, use the ICCompressorFree function to release the resources specified by COMPVARS.


ICSeqCompressFrameEnd

void ICSeqCompressFrameEnd(PCOMPVARS pc);

Ends sequence compression that was initiated by using the ICSeqCompressFrameStart and ICSeqCompressFrame functions.

pc

Address of a COMPVARS structure used during sequence compression.

When finished with compression, use the ICCompressorFree function to release the resources specified by COMPVARS.


ICSeqCompressFrameStart

BOOL ICSeqCompressFrameStart(PCOMPVARS pc, LPBITMAPINFO lpbiIn);

Initializes resources for compressing a sequence of frames using the ICSeqCompressFrame function.

•	Returns TRUE if successful or FALSE otherwise.

pc

Address of a COMPVARS structure initialized with information for compression.

lpbiIn

Format of the data to be compressed.

This function uses a COMPVARS structure to provide settings for the specified compressor and intersperses key frames at the rate specified by the lKey member of COMPVARS. You can specify values for the data rate for the sequence and the key-frame frequency by using the appropriate members of COMPVARS.

Use the ICSeqCompressFrameStart, ICSeqCompressFrame, and ICSeqCompressFrameEnd functions to compress a sequence of frames to a specified data rate and number of key frames.

When finished with compression, use the ICCompressorFree function to release the resources specified in COMPVARS.

COMPVARS needs to be initialized before you use this function. You can initialize the structure manually or you can allow the user to specify a compressor and initialize a COMPVARS structure by using the ICCompressorChoose function.


ICSetStatusProc

DWORD ICSetStatusProc(HIC hic, DWORD dwFlags, LONG lParam,
    LONG (CALLBACK * ()) fpfnStatus);

Sends the address of a status callback function to a compressor. The compressor calls this function during lengthy operations.

•	Returns ICERR_OK if successful or an error otherwise.

hic

Handle of the compressor.

dwFlags

Applicable flags. Set to zero.

lParam

Constant specified with the status callback address.

fpfnStatus

Address of the status callback function. Specify NULL to indicate no status callbacks should be sent.


MyStatusProc

LONG MyStatusProc(LPARAM lParam, UINT Message);

Describes an application-defined status callback function used by the ICM_SET_STATUS_PROC message and the ICSetStatusProc function.

•	Returns zero if processing should continue or a nonzero value if it should end.

lParam

Constant specified with the status callback address.

Message

Status flag. It can be one of the following values:

ICSTATUS_END

A lengthy operation is finishing.

ICSTATUS_START

A lengthy operation is starting.

ICSTATUS_STATUS

Operation is proceeding, and is lParam percent done.

ICSTATUS_YIELD

A lengthy operation is proceeding. This value has the same meaning as ICSTATUS_STATUS but does not indicate a value for percentage done.


Video Compression Manager Messages

Applications use messages to communicate with VCM, compression drivers, decompression drivers, and rendering drivers. VCM macros provide a shorthand method of sending these messages. VCM messages are based on the ICSendMessage function. Definitions of VCM macros are included with the associated message definitions.


ICM_ABOUT

ICM_ABOUT

wParam = (DWORD) (UINT) hwnd;

lParam = 0;

// Corresponding macros

DWORD ICAbout(hic, hwnd);

DWORD ICQueryAbout(hic);

Notifies a video compression driver to display its About dialog box or queries a video compression driver to determine if it has an About dialog box.

•	Returns ICERR_OK if the driver supports this message or ICERR_UNSUPPORTED otherwise.

hic

Handle of the compressor.

hwnd

Handle of the parent window of the displayed dialog box.

You can also determine if a driver has an About dialog box by specifying -1 in this parameter, as in the ICQueryAbout macro. The driver returns ICERR_OK if it has an About dialog box or ICERR_UNSUPPORTED otherwise.


ICM_COMPRESS

ICM_COMPRESS

wParam = (DWORD) (LPVOID) &icc;

lParam = sizeof(ICCOMPRESS);

Notifies a video compression driver to compress a frame of data into an application-defined buffer.

•	Returns ICERR_OK if successful or an error otherwise.

icc

Address of an ICCOMPRESS structure. The following members of this structure specify the compression parameters: lpbiInput, lpInput, lpbiOutput, lpOutput, lpbiPrev, lpPrev, lpckid, lpdwFlags, dwFrameSize, and dwQuality.

The driver should also use the biSizeImage member of the BITMAPINFOHEADER structure associated with lpbiOutput of ICCOMPRESS to return the size of the compressed frame.

lParam

Size, in bytes, of ICCOMPRESS.


ICM_COMPRESS_BEGIN

ICM_COMPRESS_BEGIN

wParam = (DWORD) (LPVOID) lpbiInput;

lParam = (DWORD) (LPVOID) lpbiOutput;

// Corresponding macro

DWORD ICCompressBegin(hic, lpbiInput, lpbiOutput);

Notifies a video compression driver to prepare to compress data.

•	Returns ICERR_OK if the specified compression is supported or ICERR_BADFORMAT if the input or output format is not supported.

hic

Handle of a compressor.

lpbiInput

Address of a BITMAPINFO structure containing the input format.

lpbiOutput

Address of a BITMAPINFO structure containing the output format.

The driver should allocate and initialize any tables or memory that it needs for compressing the data formats when it receives the ICM_COMPRESS message.

VCM saves the settings of the most recent ICM_COMPRESS_BEGIN message. The ICM_COMPRESS_BEGIN and ICM_COMPRESS_END messages do not nest. If your driver receives ICM_COMPRESS_BEGIN before compression is stopped with ICM_COMPRESS_END, it should restart compression with new parameters.


ICM_COMPRESS_END

ICM_COMPRESS_END

wParam = 0;

lParam = 0;

// Corresponding macro

DWORD ICCompressEnd(hic);

Notifies a video compression driver to end compression and free resources allocated for compression.

•	Returns ICERR_OK if successful or an error otherwise.

hic

Handle of the compressor.

VCM saves the settings of the most recent ICM_COMPRESS_BEGIN message. ICM_COMPRESS_BEGIN and ICM_COMPRESS_END do not nest. If your driver receives ICM_COMPRESS_BEGIN before compression is stopped with ICM_COMPRESS_END, it should restart compression with new parameters.


ICM_COMPRESS_FRAMES_INFO

ICM_COMPRESS_FRAMES_INFO

wParam = (DWORD) (LPVOID) &icf;

lParam = sizeof(ICCOMPRESSFRAMES);

Notifies a compression driver to set the parameters for the pending compression.

•	Returns ICERR_OK if successful or an error otherwise.

wParam

Address of an ICCOMPRESSFRAMES structure. The GetData and PutData members of this structure are not used with this message.

lParam

Size, in bytes, of ICCOMPRESSFRAMES.

A compressor can use this message to determine how much space to allocate for each frame while compressing.


ICM_COMPRESS_GET_FORMAT

ICM_COMPRESS_GET_FORMAT

wParam = (DWORD) (LPVOID) lpbiInput;

lParam = (DWORD) (LPVOID) lpbiOutput;

// Corresponding macros

DWORD ICCompressGetFormat(hic, lpbiInput, lpbiOutput);

DWORD ICCompressGetFormatSize(hic, lpbi);

Requests the output format of the compressed data from a video compression driver.

•	Returns ICERR_OK if successful or an error otherwise.

hic

Handle of the compressor.

lpbiInput

Address of a BITMAPINFO structure containing the input format.

lpbiOutput

Address of a BITMAPINFO structure to contain the output format. You can specify zero for this parameter to request only the size of the output format, as in the ICCompressGetFormatSize macro.

If lpbiOutput is nonzero, the driver should fill the BITMAPINFO structure with the default output format corresponding to the input format specified for lpbiInput. If the compressor can produce several formats, the default format should be the one that preserves the greatest amount of information.


ICM_COMPRESS_GET_SIZE

ICM_COMPRESS_GET_SIZE

wParam = (DWORD) (LPVOID) lpbiInput;

lParam = (DWORD) (LPVOID) lpbiOutput;

// Corresponding macro

DWORD ICCompressGetSize(hic, lpbiInput, lpbiOutput);

Requests that the video compression driver supply the maximum size of one frame of data when compressed into the specified output format.

•	Returns the maximum number of bytes a single compressed frame can occupy.

hic

Handle of a compressor.

lpbiInput

Address of a BITMAPINFO structure containing the input format.

lpbiOutput

Address of a BITMAPINFO structure containing the output format.

Typically, applications send this message to determine how large a buffer to allocate for the compressed frame.

The driver should calculate the size of the largest possible frame based on the input and output formats.


ICM_COMPRESS_QUERY

ICM_COMPRESS_QUERY

wParam = (DWORD) (LPVOID) lpbiInput;

lParam = (DWORD) (LPVOID) lpbiOutput;

// Corresponding macro

DWORD ICCompressQuery(hic, lpbiInput, lpbiOutput);

Queries a video compression driver to determine if it supports a specific input format or if it can compress a specific input format to a specific output format.

•	Returns ICERR_OK if the specified compression is supported or ICERR_BADFORMAT otherwise.

hic

Handle of a compressor.

lpbiInput

Address of a BITMAPINFO structure containing the input format.

lpbiOutput

Address of a BITMAPINFO structure containing the output format. You can specify zero for this parameter to indicate any output format is acceptable.

When a driver receives this message, it should examine the BITMAPINFO structure associated with lpbiInput to determine if it can compress the input format.


ICM_CONFIGURE

ICM_CONFIGURE

wParam = (DWORD) (UINT) hwnd;

lParam = 0;

// Corresponding macros

DWORD ICQueryConfigure(hic);

DWORD ICConfigure(hic, hwnd);

Notifies a video compression driver to display its configuration dialog box or queries a video compression driver to determine if it has a configuration dialog box.

•	Returns ICERR_OK if the driver supports this message or ICERR_UNSUPPORTED otherwise.

hic

Handle of the compressor.

hwnd

Handle of the parent window of the displayed dialog box.

You can determine if a driver has a configuration dialog box by specifying
 − 1 in this parameter, as in the ICQueryConfigure macro.

This message is different from the DRV_CONFIGURE message used for hardware configuration. The dialog box for this message should let the user set and edit the internal state referenced by the ICM_GETSTATE and ICM_SETSTATE messages. For example, this dialog box can let the user change parameters affecting the quality level and other similar compression options.


ICM_DECOMPRESS

ICM_DECOMPRESS

wParam = (DWORD) (LPVOID) &icd;

lParam = sizeof(ICDECOMPRESS);

Notifies a video decompression driver to decompress a frame of data into an application-defined buffer.

•	Returns ICERR_OK if successful or an error otherwise.

wParam

Address of an ICDECOMPRESS structure.

lParam

Size, in bytes, of ICDECOMPRESS.

If you want the driver to decompress data directly to the screen, send the ICM_DRAW message.

The driver returns an error if this message is received before the ICM_DECOMPRESS_BEGIN message.


ICM_DECOMPRESS_BEGIN

ICM_DECOMPRESS_BEGIN

wParam = (DWORD) (LPVOID) lpbiInput;

lParam = (DWORD) (LPVOID) lpbiOutput;

// Corresponding macro

DWORD ICDecompressBegin(hic, lpbiInput, lpbiOutput);

Notifies a video decompression driver to prepare to decompress data.

•	Returns ICERR_OK if the specified decompression is supported or ICERR_BADFORMAT otherwise.

hic

Handle of a decompressor.

lpbiInput

Address of a BITMAPINFO structure containing the input format.

lpbiOutput

Address of a BITMAPINFO structure containing the output format.

When the driver receives this message, it should allocate buffers and do any time-consuming operations so that it can process ICM_DECOMPRESS messages efficiently.

If you want the driver to decompress data directly to the screen, send the ICM_DRAW message.

The ICM_DECOMPRESS_BEGIN and ICM_DECOMPRESS_END messages do not nest. If your driver receives ICM_DECOMPRESS_BEGIN before decompression is stopped with ICM_DECOMPRESS_END, it should restart decompression with new parameters.


ICM_DECOMPRESS_END

ICM_DECOMPRESS_END

wParam = 0;

lParam = 0;

// Corresponding macro

DWORD ICDecompressEnd(hic);

Notifies a video decompression driver to end decompression and free resources allocated for decompression.

•	Returns ICERR_OK if successful or an error otherwise.

hic

Handle of a decompressor.

The driver should free any resources allocated for the ICM_DECOMPRESS_BEGIN message.

ICM_DECOMPRESS_BEGIN and ICM_DECOMPRESS_END do not nest. If your driver receives ICM_DECOMPRESS_BEGIN before decompression is stopped with ICM_DECOMPRESS_END, it should restart decompression with new parameters.


ICM_DECOMPRESS_GET_FORMAT

ICM_DECOMPRESS_GET_FORMAT

wParam = (DWORD) (LPVOID) lpbiInput;

lParam = (DWORD) (LPVOID) lpbiOutput;

// Corresponding macros

DWORD ICDecompressGetFormat(hic, lpbiInput, lpbiOutput);

DWORD ICDecompressGetFormatSize(hic, lpbi);

Requests the output format of the decompressed data from a video decompression driver.

•	Return ICERR_OK if successful or an error otherwise.

hic

Handle of a decompressor.

lpbiInput

Address of a BITMAPINFO structure containing the input format.

lpbiOutput

Address of a BITMAPINFO structure to contain the output format. You can specify zero to request only the size of the output format, as in the ICDecompressGetFormatSize macro.

If lpbiOutput is nonzero, the driver should fill the BITMAPINFO structure with the default output format corresponding to the input format specified for lpbiInput. If the compressor can produce several formats, the default format should be the one that preserves the greatest amount of information.


ICM_DECOMPRESS_GET_PALETTE

ICM_DECOMPRESS_GET_PALETTE

wParam = (DWORD) (LPVOID) lpbiInput;

lParam = (DWORD) (LPVOID) lpbiOutput;

// Corresponding macro

DWORD ICDecompressGetPalette(hic, lpbiInput, lpbiOutput);

Requests that the video decompression driver supply the color table of the output BITMAPINFOHEADER structure.

•	Returns ICERR_OK if successful or an error otherwise.

hic

Handle of a decompressor.

lpbiInput

Address of a BITMAPINFOHEADER structure containing the input format.

lpbiOutput

Address of a BITMAPINFOHEADER structure to contain the color table. The space reserved for the color table is always at least 256 colors. You can specify zero for this parameter to return only the size of the color table.

If lpbiOutput is nonzero, the driver sets the biClrUsed member of BITMAPINFOHEADER to the number of colors in the color table. The driver fills the bmiColors members of BITMAPINFO with the actual colors.

The driver should support this message only if it uses a palette other than the one specified in the input format.


ICM_DECOMPRESS_QUERY

ICM_DECOMPRESS_QUERY

wParam = (DWORD) (LPVOID) lpbiInput;

lParam = (DWORD) (LPVOID) lpbiOutput;

// Corresponding macro

DWORD ICDecompressQuery(hic, lpbiInput, lpbiOutput);

Queries a video decompression driver to determine if it supports a specific input format or if it can decompress a specific input format to a specific output format.

•	Returns ICERR_OK if the specified decompression is supported or ICERR_BADFORMAT otherwise.

hic

Handle of a decompressor.

lpbiInput

Address of a BITMAPINFO structure containing the input format.

lpbiOutput

Address of a BITMAPINFO structure containing the output format. You can specify zero for this parameter to indicate any output format is acceptable.


ICM_DECOMPRESS_SET_PALETTE

ICM_DECOMPRESS_SET_PALETTE

wParam = (DWORD) (LPVOID) lpbiPalette;

lParam = 0;

// Corresponding macro

ICDecompressSetPalette(hic, lpbiPalette);

Specifies a palette for a video decompression driver to use if it is decompressing to a format that uses a palette.

•	Returns ICERR_OK if the decompression driver can precisely decompress images to the suggested palette using the set of colors as they are arranged in the palette. Returns ICERR_UNSUPPORTED otherwise.

lpbiPalette

Address of a BITMAPINFOHEADER structure whose color table contains the colors that should be used if possible. You can specify zero to use the default set of output colors.

This message should not affect decompression already in progress; rather, colors passed using this message should be returned in response to future ICM_DECOMPRESS_GET_FORMAT and ICM_DECOMPRESS_GET_PALETTE messages. Colors are sent back to the decompression driver in a future ICM_DECOMPRESS_BEGIN message.

This message is used primarily when a driver decompresses images to the screen and another application that uses a palette is in the foreground, forcing the decompression driver to adapt to a foreign set of colors.


ICM_DECOMPRESSEX

ICM_DECOMPRESSEX

wParam = (DWORD) (LPVOID) &icdex;

lParam = sizeof(ICDECOMPRESSEX);

Notifies a video compression driver to decompress a frame of data directly to the screen, decompress to an upside-down DIB, or decompress images described with source and destination rectangles.

•	Returns ICERR_OK if successful or an error otherwise.

wParam

Address of an ICDECOMPRESSEX structure.

lParam

Size, in bytes, of ICDECOMPRESSEX.

This message is similar to ICM_DECOMPRESS except that it uses the ICDECOMPRESSEX structure to define its decompression information.

If you want the driver to decompress data directly to the screen, send the ICM_DRAW message.

The driver returns an error if this message is received before the ICM_DECOMPRESSEX_BEGIN message.


ICM_DECOMPRESSEX_BEGIN

ICM_DECOMPRESSEX_BEGIN

wParam = (DWORD) (LPVOID) &icdex;

lParam = sizeof(ICDECOMPRESSEX);

Notifies a video compression driver to prepare to decompress data.

•	Returns ICERR_OK if the specified decompression is supported or ICERR_BADFORMAT otherwise.

wParam

Address of a ICDECOMPRESSEX structure containing the input and output formats.

lParam

Size, in bytes, of ICDECOMPRESSEX.

When the driver receives this message, it should allocate buffers and do any time-consuming operations so that it can process ICM_DECOMPRESSEX messages efficiently.

If you want the driver to decompress data directly to the screen, send the ICM_DRAW_BEGIN message.

The ICM_DECOMPRESSEX_BEGIN and ICM_DECOMPRESSEX_END messages do not nest. If your driver receives ICM_DECOMPRESSEX_BEGIN before decompression is stopped with ICM_DECOMPRESSEX_END, it should restart decompression with new parameters.


ICM_DECOMPRESSEX_END

ICM_DECOMPRESSEX_END

wParam = 0;

lParam = 0;

// Corresponding macro

DWORD ICDecompressExEnd(hic);

Notifies a video decompression driver to end decompression and free resources allocated for decompression.

•	Returns ICERR_OK if successful or an error otherwise.

hic

Handle of a decompressor.

The driver frees any resources allocated for the ICM_DECOMPRESSEX_BEGIN message.

ICM_DECOMPRESSEX_BEGIN and ICM_DECOMPRESSEX_END do not nest. If your driver receives ICM_DECOMPRESSEX_BEGIN before decompression is stopped with ICM_DECOMPRESSEX_END, it should restart decompression with new parameters.


ICM_DECOMPRESSEX_QUERY

ICM_DECOMPRESSEX_QUERY

wParam = (DWORD) (LPVOID) &icdex;

lParam = sizeof(ICDECOMPRESSEX);

Queries a video compression driver to determine if it supports a specific input format or if it can decompress a specific input format to a specific output format.

•	Returns ICERR_OK if the specified decompression is supported or ICERR_BADFORMAT otherwise.

wParam

Address of a ICDECOMPRESSEX structure containing the input format.

lParam

Size, in bytes, of ICDECOMPRESSEX.


ICM_DRAW

ICM_DRAW

wParam = (DWORD) (LPVOID) &icdraw;

lParam = sizeof(ICDRAW);

Notifies a rendering driver to decompress a frame of data and draw it to the screen.

•	Returns ICERR_OK if successful or an error otherwise.

wParam

Address of an ICDRAW structure.

lParam

Size, in bytes, of ICDRAW.

If the ICDRAW_UPDATE flag is set in the dwFlags member of ICDRAW, the area of the screen used for drawing is invalid and needs to be updated. The extent of updating depends on the contents of the lpData member.

If lpData is NULL, the driver should update the entire destination rectangle with the current image. If the driver maintains a copy of the image in an off-screen buffer, it can fail this message. If lpData is not NULL, the driver should draw the data and make sure the entire destination is updated.

If the ICDRAW_HURRYUP flag is set in dwFlags, the calling application wants the driver to proceed as quickly as possible, possibly not even updating the screen.

If the ICDRAW_PREROLL flag is set in dwFlags, this video frame is preliminary information and should not be displayed if possible. For example, if play is to start from frame 10, and frame 0 is the nearest previous key frame, frames 0 through 9 will have ICDRAW_PREROLL set.

If you want the driver to decompress data into a buffer, send the ICM_DECOMPRESS message.


ICM_DRAW_BEGIN

ICM_DRAW_BEGIN

wParam = (DWORD) (LPVOID) &icdrwBgn;

lParam = sizeof(ICDRAW);

Notifies a rendering driver to prepare to draw data.

•	Returns ICERR_OK if the driver supports drawing the data to the screen in the specified manner and format, or an error code otherwise. Possible error values include the following:

ICERR_BADFORMAT	Input or output format is not supported.
ICERR_NOTSUPPORTED	Driver does not draw directly to the screen or does not support this message.
wParam

Address of an ICDRAWBEGIN structure containing the input format.

lParam

Size, in bytes, of ICDRAWBEGIN.

If you want the driver to decompress data into a buffer, send the ICM_DECOMPRESS_BEGIN message.

The ICM_DRAW_BEGIN and ICM_DRAW_END messages do not nest. If your driver receives ICM_DRAW_BEGIN before decompression is stopped with ICM_DRAW_END, it should restart decompression with new parameters.


ICM_DRAW_CHANGEPALETTE

ICM_DRAW_CHANGEPALETTE

wParam = (DWORD) (LPVOID) lpbiInput;

lParam = 0;

// Corresponding macro

DWORD ICDrawChangePalette(hic, lpbiInput);

Notifies a rendering driver that the movie palette is changing.

•	Returns ICERR_OK if successful or FALSE otherwise.

hic

Handle of a rendering driver.

lpbiInput

Address of a BITMAPINFO structure containing the new format and optional color table.

This message should be supported by installable rendering handlers that draw DIBs with an internal structure that includes a palette.


ICM_DRAW_END

ICM_DRAW_END

wParam = 0;

lParam = 0;

// Corresponding macro

DWORD ICDrawEnd(hic);

Notifies a rendering driver to decompress the current image to the screen and to release resources allocated for decompression and drawing.

•	Returns ICERR_OK if successful or an error otherwise.

hic

Handle of a driver.

The ICM_DRAW_BEGIN and ICM_DRAW_END messages do not nest. If your driver receives ICM_DRAW_BEGIN before decompression is stopped with ICM_DRAW_END, it should restart decompression with new parameters.


ICM_DRAW_FLUSH

ICM_DRAW_FLUSH

wParam = 0;

lParam = 0;

// Corresponding macro

DWORD ICDrawFlush(hic);

Notifies a rendering driver to render the contents of any image buffers that are waiting to be drawn.

•	Returns ICERR_OK if successful or an error otherwise.

hic

Handle of a driver.

This message is used only by hardware that performs its own asynchronous decompression, timing, and drawing.


ICM_DRAW_GET_PALETTE

ICM_DRAW_GET_PALETTE

wParam = 0;

lParam = 0;

Requests a rendering driver to return a palette.

•	The driver should return one of the following: a handle of the palette being used, NULL if it doesn't have a handle to return, or ICERR_UNSUPPORTED if it doesn't support palettes.


ICM_DRAW_GETTIME

ICM_DRAW_GETTIME

wParam = (DWORD) (LPVOID) lplTime;

lParam = 0;

// Corresponding macro

DWORD ICDrawGetTime(hic, lplTime);

Requests a rendering driver that controls the timing of drawing frames to return the current value of its internal clock.

•	Returns ICERR_OK if successful or an error otherwise.

hic

Handle of a driver.

lplTime

Address to contain the current time. The return value should be specified in samples.

This message is generally supported by hardware that performs its own asynchronous decompression, timing, and drawing. The message can also be sent if the hardware is being used as the synchronization master.


ICM_DRAW_QUERY

ICM_DRAW_QUERY

wParam = (DWORD) (LPVOID) lpbiInput;

lParam = 0;

// Corresponding macro

DWORD ICDrawQuery(hic, lpbiInput);

Queries a rendering driver to determine if it can render data in a specific format.

•	Returns ICERR_OK if the driver can render data in the specified format or ICERR_BADFORMAT otherwise.

hic

Handle of a driver.

lpbiInput

Address of a BITMAPINFO structure containing the input format.

This message differs from the ICM_DRAW_BEGIN message in that it queries the driver in a general sense. ICM_DRAW_BEGIN determines if the driver can draw the data using the specified format under specific conditions, such as stretching the image.


ICM_DRAW_REALIZE

ICM_DRAW_REALIZE

wParam = (DWORD) (UINT) (HDC) hdc;

lParam = (DWORD) (BOOL) fBackground;

// Corresponding macro

DWORD ICDrawRealize(hic, hdc, fBackground);

Notifies a rendering driver to realize its drawing palette while drawing.

•	Returns ICERR_OK if the drawing palette is realized or ICERR_UNSUPPORTED if the palette associated with the decompressed data is realized.

hic

Handle of a driver.

hdc

Handle of the DC used to realize the palette.

fBackground

Background flag. Specify TRUE to realize the palette as a background task or FALSE to realize the palette in the foreground.

Drivers need to respond to this message only if the drawing palette is different from the decompressed palette.


ICM_DRAW_RENDERBUFFER

ICM_DRAW_RENDERBUFFER

wParam = 0;

lParam = 0;

// Corresponding macro

DWORD ICDrawRenderBuffer(hic);

Notifies a rendering driver to draw the frames that have been passed to it.

•	No return value.

hic

Handle of a driver.

Use this message with hardware that performs its own asynchronous decompression, timing, and drawing.

This message is typically used to perform a seek operation when the driver must be specifically instructed to display each video frame passed to it rather than playing a sequence of video frames.


ICM_DRAW_SETTIME

ICM_DRAW_SETTIME

wParam = (DWORD) lpTime;

lParam = 0;

// Corresponding macro

DWORD ICDrawSetTime(hic, lpTime);

Provides synchronization information to a rendering driver that handles the timing of drawing frames. The synchronization information is the sample number of the frame to draw.

•	Returns ICERR_OK if successful or an error otherwise.

hic

Handle of a driver.

lpTime

Sample number of the frame to render.

Typically, the driver compares the specified value with the frame number associated with the time of its internal clock and attempts to synchronize the two if the difference is significant.

Use this message when the hardware performs its own asynchronous decompression, timing, and drawing, and the hardware relies on an external synchronization signal (the hardware is not being used as the synchronization master).


ICM_DRAW_START

ICM_DRAW_START

wParam = 0;

lParam = 0;

// Corresponding macro

DWORD ICDrawStart(hic);

Notifies a rendering driver to start its internal clock for the timing of drawing frames.

•	No return value.

hic

Handle of a driver.

This message is used by hardware that performs its own asynchronous decompression, timing, and drawing.

When the driver receives this message, it should start rendering data at the rate specified with the ICM_DRAW_BEGIN message.

The ICM_DRAW_START and ICM_DRAW_STOP messages do not nest. If your driver receives ICM_DRAW_START before rendering is stopped with ICM_DRAW_STOP, it should restart rendering with new parameters.


ICM_DRAW_START_PLAY

ICM_DRAW_START_PLAY

wParam = (DWORD) lFrom;

lParam = (DWORD) lTo;

// Corresponding macro

ICDrawStartPlay(hic, lFrom, lTo);

Provides the start and end times of a play operation to a rendering driver.

•	No return value.

lFrom

Start time.

lTo

End time.

This message precedes any frame data sent to the rendering driver.

Units for lFrom and lTo are specified with the ICM_DRAW_BEGIN message. For video data this is normally a frame number. For more information about the playback rate, see the dwRate and dwScale members of the ICDRAWBEGIN structure.

If the end time is less than the start time, the playback direction is reversed.


ICM_DRAW_STOP

ICM_DRAW_STOP

wParam = 0;

lParam = 0;

// Corresponding macro

DWORD ICDrawStop(hic);

Notifies a rendering driver to stop its internal clock for the timing of drawing frames.

•	No return value.

hic

Handle of a driver.

This message is used by hardware that performs its own asynchronous decompression, timing, and drawing.


ICM_DRAW_STOP_PLAY

ICM_DRAW_STOP_PLAY

wParam = 0;

lParam = 0;

// Corresponding macro

ICDrawStopPlay(hic);

Notifies a rendering driver when a play operation is complete.

•	No return value.

Use this message when the play operation is complete. Use the ICM_DRAW_STOP message to end timing.


ICM_DRAW_SUGGESTFORMAT

ICM_DRAW_SUGGESTFORMAT

wParam = (DWORD) (LPVOID) &icdrwSuggest;

lParam = sizeof(ICDRAWSUGGEST);

Queries a rendering driver to suggest a decompressed format that it can draw.

•	Returns ICERR_OK if successful. If the lpbiSuggest member of the ICDRAWSUGGEST structure is NULL, this message returns the amount of memory required to contain the suggested format.

wParam

Address of an ICDRAWSUGGEST structure.

lParam

Size, in bytes, of ICDRAWSUGGEST.

The driver should examine the format specified in the lpbiIn member of the ICDRAWSUGGEST structure and use the lpbiSuggest member to return a format it can draw. The output format should preserve as much data as possible from the input format.

Optionally, the driver can use the installable compressor handle passed in the hicDecompressor member of ICDRAWSUGGEST to make more complex selections. For example, if the input format is 24-bit JPEG data, a renderer could query the decompressor to find out if it can decompress to a YUV format (which might be drawn more efficiently) before selecting the format to suggest.


ICM_DRAW_WINDOW

ICM_DRAW_WINDOW

wParam = (DWORD) (LPVOID) prc;

lParam = 0;

// Corresponding macro

DWORD ICDrawWindow(hic, prc);

Notifies a rendering driver that the window specified for the ICM_DRAW_BEGIN message needs to be redrawn. The window has moved or become temporarily obscured.

•	Returns ICERR_OK if successful or an error otherwise.

hic

Handle of a driver.

prc

Address of the destination rectangle in screen coordinates. If this parameter points to an empty rectangle, drawing should be turned off.

This message is supported by hardware that performs its own asynchronous decompression, timing, and drawing.

Video-overlay drivers use this message to draw when the window is obscured or moved. When a window specified for ICM_DRAW_BEGIN is completely hidden by other windows, the destination rectangle is empty. Drivers should turn off video-overlay hardware when this condition occurs.


ICM_GET

ICM_GET

wParam = (DWORD) (LPVOID) pv;

lParam = (DWORD) cb;

Retrieves an application-defined doubleword from a video compression driver.

•	Returns the amount of memory, in bytes, required to store the status information.

wParam

Address of a block of memory to be filled with the current state. You can also specify NULL to determine the amount of memory required by the state information.

lParam

Size, in bytes, of the block of memory.

The structure used to represent state information is driver specific and is defined by the driver.


ICM_GETBUFFERSWANTED

ICM_GETBUFFERSWANTED

wParam = (DWORD) (LPVOID) lpdwBuffers;

lParam = 0;

// Corresponding macro

DWORD ICGetBuffersWanted(hic, lpdwBuffers);

Queries a driver for the number of buffers to allocate.

•	Returns ICERR_OK if successful or ICERR_UNSUPPORTED otherwise.

hic

Handle of a driver.

lpdwBuffers

Address to contain the number of samples the driver needs to efficiently render the data.

This message is used by drivers that use hardware to render data and want to ensure a minimal time lag caused by waiting for buffers to arrive. For example, if a driver controls a video decompression board that can hold 10 frames of video, it could return 10 for this message. This instructs applications to try to stay 10 frames ahead of the frame it currently needs.


ICM_GETDEFAULTKEYFRAMERATE

ICM_GETDEFAULTKEYFRAMERATE

wParam = (DWORD) (LPVOID) &dwICValue;

lParam = 0;

// Corresponding macro

DWORD ICGetDefaultKeyFrameRate(hic);

Queries a video compression driver for its default (or preferred) key-frame spacing.

•	Returns ICERR_OK if the driver supports this message or ICERR_UNSUPPORTED otherwise. The ICGetDefaultKeyFrameRate macro returns the default key-frame rate.

hic

Handle of a compressor.

wParam

Address to contain the preferred key-frame spacing.


ICM_GETDEFAULTQUALITY

ICM_GETDEFAULTQUALITY

wParam = (DWORD) (LPVOID) &dwICValue;

lParam = 0;

// Corresponding macro

DWORD ICGetDefaultQuality(hic);

Queries a video compression driver to provide its default quality setting.

•	Returns ICERR_OK if the driver supports this message or ICERR_UNSUPPORTED otherwise. The ICGetDefaultQuality macro returns the default quality value.

hic

Handle of a compressor.

wParam

Address to contain the default quality value. Quality values range from 0 to 10,000.


ICM_GETINFO

ICM_GETINFO

wParam = (DWORD) (LPVOID) lpicinfo;

lParam = sizeof(icinfo);

Queries a video compression driver to return a description of itself in an ICINFO structure.

•	Returns the size, in bytes, of ICINFO or zero if an error occurs.

wParam

Address of an ICINFO structure to contain information.

lParam

Size, in bytes, of ICINFO.

Typically, applications send this message to display a list of the installed compressors.

The driver should fill all members of the ICINFO structure except szDriver.


ICM_GETQUALITY

ICM_GETQUALITY

wParam = (DWORD) (LPVOID) &dwICValue;

lParam = 0;

Queries a video compression driver to return its current quality setting.

•	Returns ICERR_OK if the driver supports this message or ICERR_UNSUPPORTED otherwise.

wParam

Address to contain the current quality value. Quality values range from 0 to 10,000.


ICM_GETSTATE

ICM_GETSTATE

wParam = (DWORD) (LPVOID) pv;

lParam = (DWORD) cb;

// Corresponding macros

DWORD ICGetState(hic, pv, cb);

DWORD ICGetStateSize(hic);

Queries a video compression driver to return its current configuration in a block of memory or to determine the amount of memory required to retrieve the configuration information.

•	Returns the amount of memory, in bytes, required by the state information. The ICGetStateSize macro returns the number of bytes used by the state data.

hic

Handle of the compressor.

pv

Address of a block of memory to contain the current configuration information. You can specify NULL for this parameter to determine the amount of memory required for the configuration information, as in ICGetStateSize.

cb

Size, in bytes, of the block of memory.

The structure used to represent configuration information is driver specific and is defined by the driver.

Use ICGetStateSize before calling the ICGetState macro to determine the size of buffer to allocate for the call.


ICM_SET_STATUS_PROC

ICM_SET_STATUS_PROC

wParam = (DWORD) (LPVOID) icsetstatusProc;

lParam = sizeof(icsetstatusProc);

Provides a status callback function with the status of a lengthy operation.

•	Return ICERR_OK if successful or an error otherwise.

wParam

Address of an ICSETSTATUSPROC structure.

lParam

Size, in bytes, of ICSETSTATUSPROC.

Support of this message is optional but strongly recommended if compression or decompression takes longer than approximately one-tenth of a second.

An application can send this message periodically to a status callback function during lengthy operations.


ICM_SETQUALITY

ICM_SETQUALITY

wParam = (DWORD) (LPVOID) &dwICValue;

lParam = 0;

Provides a video compression driver with a quality level to use during compression.

•	Returns ICERR_OK if the driver supports this message or ICERR_UNSUPPORTED otherwise.

wParam

New quality value. Quality values range from 0 to 10,000.


ICM_SETSTATE

ICM_SETSTATE

wParam = (DWORD) (LPVOID) pv;

lParam = (DWORD) cb;

// Corresponding macro

DWORD ICSetState(hic, pv, cb);

Notifies a video compression driver to set the state of the compressor.

•	Returns the number of bytes used by the compressor if successful or zero otherwise.

hic

Handle of the compressor.

pv

Address of a block of memory containing configuration data. You can specify NULL for this parameter to reset the compressor to its default state.

cb

Size, in bytes, of the block of memory.

The information used by this message is private and specific to a given compressor. Client applications should use this message only to restore information previously obtained with the ICM_GETSTATE message and should use the ICM_CONFIGURE message to adjust the configuration of a video compression driver.


Video Compression Manager Structures

Applications use structures to transfer data in VCM messages and functions. The following structures are specific to VCM and provide support for VCM functions and messages.


COMPVARS

typedef struct {

    LONG         cbSize;      // see below

    DWORD        dwFlags;     // see below

    HIC          hic;         // see below

    DWORD        fccType;     // see below

    DWORD        fccHandler;  // see below

    LPBITMAPINFO lpbiIn;      // reserved; do not use

    LPBITMAPINFO lpbiOut;     // see below

    LPVOID       lpBitsOut;   // reserved; do not use

    LPVOID       lpBitsPrev;  // reserved; do not use

    LONG         lFrame;      // reserved; do not use

    LONG         lKey;        // see below

    LONG         lDataRate;   // see below

    LONG         lQ;          // see below

    LONG         lKeyCount;   // reserved; do not use

    LPVOID       lpState;     // reserved; do not use

    LONG         cbState;     // reserved; do not use

} COMPVARS;

Describes compressor settings for functions such as ICCompressorChoose, ICSeqCompressFrame, and ICCompressorFree.

cbSize

Size, in bytes, of this structure. This member must be set to validate the structure before calling any function using this structure.

dwFlags

Applicable flags. The following value is defined:

ICMF_COMPVARS_VALID

Data in this structure is valid and has been manually entered. Set this flag before you call any function if you fill this structure manually. Do not set this flag if you let ICCompressorChoose initialize this structure.

hic

Handle of the compressor to use. You can open a compressor and obtain a handle of it by using the ICOpen function. You can also choose a compressor by using ICCompressorChoose. ICCompressorChoose opens the chosen compressor and returns the handle of the compressor in this member. You can close the compressor by using ICCompressorFree.

fccType

Type of compressor used. Currently only ICTYPE_VIDEO (VIDC) is supported. This member can be set to zero.

fccHandler

Four-character code of the compressor. Specify NULL to indicate the data is not to be recompressed. Specify "DIB" to indicate the data is an uncompressed, full frame. You can use this member to specify which compressor is selected by default when the dialog box is displayed.

lpbiOut

Address of a BITMAPINFO structure containing the image output format. You can specify a specific format to use or you can specify NULL to use the default compressor associated with the input format. You can also set the image output format by using ICCompressorChoose.

lKey

Key-frame rate. Specify an integer to indicate the frequency that key frames are to occur in the compressed sequence or zero to not use key frames. You can also let ICCompressorChoose set the key-frame rate selected in the dialog box. The ICSeqCompressFrameStart function uses the value of this member for making key frames.

lDataRate

Data rate, in kilobytes per second. ICCompressorChoose copies the selected data rate from the dialog box to this member.

lQ

Quality setting. Specify a quality setting of 1 to 10,000 or specify ICQUALITY_DEFAULT to use the default quality setting. You can also let ICCompressorChoose set the quality value selected in the dialog box. ICSeqCompressFrameStart uses the value of this member as its quality setting.

You can let ICCompressorChoose fill the contents of this structure or you can do it manually. If you manually fill the structure, you must provide information for the following members: cbSize, hic, lpbiOut, lKey, and lQ. Also, you must set the ICMF_COMPVARS_VALID flag in the dwFlags member.


ICCOMPRESS

typedef struct {

    DWORD              dwFlags;      // see below

    LPBITMAPINFOHEADER lpbiOutput;   // see below

    LPVOID             lpOutput;     // see below

    LPBITMAPINFOHEADER lpbiInput;    // see below

    LPVOID             lpInput;      // see below

    LPDWORD            lpckid;       // see below

    LPDWORD            lpdwFlags;    // see below

    LONG               lFrameNum;    // see below

    DWORD              dwFrameSize;  // see below

    DWORD              dwQuality;    // quality setting

    LPBITMAPINFOHEADER lpbiPrev;     // see below

    LPVOID             lpPrev;       // see below

} ICCOMPRESS;

Contains compression parameters used with the ICM_COMPRESS message.

dwFlags

Flags used for compression. The following value is defined:

ICCOMPRESS_KEYFRAME

Input data should be treated as a key frame.

lpbiOutput

Address of a BITMAPINFOHEADER structure containing the output (compressed) format. The biSizeImage member must contain the size of the compressed data.

lpOutput

Address of the buffer where the driver should write the compressed data.

lpbiInput

Address of a BITMAPINFOHEADER structure containing the input (uncompressed) format.

lpInput

Address of the buffer containing input data.

lpckid

Address to contain the chunk identifier for data in the AVI file. If the value of this member is not NULL, the driver should specify a two-character code for the chunk identifier corresponding to the chunk identifier used in the AVI file.

lpdwFlags

Address to contain flags for the AVI index. If the returned frame is a key frame, the driver should set the AVIIF_KEYFRAME flag.

lFrameNum

Number of the frame to compress.

dwFrameSize

Desired maximum size, in bytes, for compressing this frame. The size value is used for compression methods that can make tradeoffs between compressed image size and image quality. Specify zero for this member to use the default setting.

lpbiPrev

Address of a BITMAPINFOHEADER structure containing the format of the previous frame, which is typically the same as the input format.

lpPrev

Address of the buffer containing input data of the previous frame.

Drivers that perform temporal compression use data from the previous frame (found in the lpbiPrev and lpPrev members) to prune redundant data from the current frame.


ICCOMPRESSFRAMES

typedef struct {

    DWORD              dwFlags;      // see below

    LPBITMAPINFOHEADER lpbiOutput;   // see below

    LPARAM             lOutput;      // reserved; do not use

    LPBITMAPINFOHEADER lpbiInput;    // see below

    LPARAM             lInput;       // reserved; do not use

    LONG               lStartFrame;  // see below

    LONG               lFrameCount;  // see below

    LONG               lQuality;     // quality setting

    LONG               lDataRate;    // see below

    LONG               lKeyRate;     // see below

    DWORD              dwRate;       // see below

    DWORD              dwScale;      // see below

    DWORD              dwOverheadPerFrame;   // reserved; do not use

    DWORD              dwReserved2;  // reserved; do not use

    LONG (CALLBACK* GetData) (LPARAM lInput, LONG lFrame,
        LPVOID lpBits, LONG len);

    LONG (CALLBACK* PutData) (LPARAM lInput, LONG lFrame,
        LPVOID lpBits, LONG len);

} ICCOMPRESSFRAMES;

Contains compression parameters used with the ICM_COMPRESS_FRAMES_INFO message.

dwFlags

Applicable flags. The following value is defined:

ICDECOMPRESSFRAMES_PADDING

Padding is used with the frame.

lpbiOutput

Address of a BITMAPINFOHEADER structure containing the output format.

lpbiInput

Address of a BITMAPINFOHEADER structure containing the input format.

lStartFrame

Number of the first frame to compress.

lFrameCount

Number of frames to compress.

lDataRate

Maximum data rate, in bytes per second.

lKeyRate

Maximum number of frames between consecutive key frames.

dwRate

Compression rate in an integer format. To obtain the rate in frames per second, divide this value by the value in dwScale.

dwScale

Value used to scale dwRate to frames per second.

GetData

Reserved; do not use.

PutData

Reserved; do not use.


ICDECOMPRESS

typedef struct {

    DWORD              dwFlags;

    LPBITMAPINFOHEADER lpbiInput;

    LPVOID             lpInput;

    LPBITMAPINFOHEADER lpbiOutput;

    LPVOID             lpOutput;

    DWORD              ckid;

} ICDECOMPRESS;

Contains decompression parameters used with the ICM_DECOMPRESS message.

dwFlags

Applicable flags. The following values are defined:

ICDECOMPRESS_HURRYUP

Tries to decompress at a faster rate. When an application uses this flag, the driver should buffer the decompressed data but not draw the image.

ICDECOMPRESS_NOTKEYFRAME

Current frame is not a key frame.

ICDECOMPRESS_NULLFRAME

Current frame does not contain data and the decompressed image should be left the same.

ICDECOMPRESS_PREROLL

Current frame precedes the point in the movie where playback starts and, therefore, will not be drawn.

ICDECOMPRESS_UPDATE

Screen is being updated or refreshed.

lpbiInput

Address of a BITMAPINFOHEADER structure containing the input format.

lpInput

Address of a buffer containing the input data.

lpbiOutput

Address of a BITMAPINFOHEADER structure containing the output format.

lpOutput

Address of a buffer where the driver should write the decompressed image.

ckid

Chunk identifier from the AVI file.


ICDECOMPRESSEX

typedef struct {

    DWORD              dwFlags;

    LPBITMAPINFOHEADER lpbiSrc;

    LPVOID             lpSrc;

    LPBITMAPINFOHEADER lpbiDst;

    LPVOID             lpDst;

    int                xDst;

    int                yDst;

    int                dxDst;

    int                dyDst;

    int                xSrc;

    int                ySrc;

    int                dxSrc;

    int                dySrc;

} ICDECOMPRESSEX;

Contains decompression parameters used with the ICM_DECOMPRESSEX message

dwFlags

Applicable flags. The following values are defined:

ICDECOMPRESS_HURRYUP

Tries to decompress at a faster rate. When an application uses this flag, the driver should buffer the decompressed data but not draw the image.

ICDECOMPRESS_NOTKEYFRAME

Current frame is not a key frame.

ICDECOMPRESS_NULLFRAME

Current frame does not contain data and the decompressed image should be left the same.

ICDECOMPRESS_PREROLL

Current frame precedes the point in the movie where playback starts and, therefore, will not be drawn.

ICDECOMPRESS_UPDATE

Screen is being updated or refreshed.

lpbiSrc

Address of a BITMAPINFOHEADER structure containing the input format.

lpSrc

Address of a buffer containing the input data.

lpbiDst

Address of a BITMAPINFOHEADER structure containing the output format.

lpDst

Address of a buffer where the driver should write the decompressed image.

xDst, yDst

The x- and y-coordinates of the destination rectangle within the DIB specified by lpbiDst.

dxDst, dyDst

Width and height of the destination rectangle.

xSrc, ySrc

The x- and y- coordinates of the source rectangle within the DIB specified by lpbiSrc.

dxSrc, dySrc

Width and height of the source rectangle.


ICDRAW

typedef struct {

    DWORD  dwFlags;   // see below

    LPVOID lpFormat;  // see below

    LPVOID lpData;    // address of the data to render

    DWORD  cbData;    // number of bytes of data to render

    LONG   lTime;     // see below

} ICDRAW;

Contains parameters for drawing video data to the screen. This structure is used with the ICM_DRAW message.

dwFlags

Flags from the AVI file index. The following values are defined:

ICDRAW_HURRYUP

Data is buffered and not drawn to the screen. Use this flag for fastest decompression.

ICDRAW_NOTKEYFRAME

Current frame is not a key frame.

ICDRAW_NULLFRAME

Current frame does not contain any data, and the previous frame should be redrawn.

ICDRAW_PREROLL

Current frame of video occurs before playback should start. For example, if playback will begin on frame 10, and frame 0 is the nearest previous key frame, frames 0 through 9 are sent to the driver with this flag set. The driver needs this data to display frame 10 properly.

ICDRAW_UPDATE

Updates the screen based on data previously received. In this case, lpData should be ignored.

lpFormat

Address of a structure containing the data format. For video streams, this is a BITMAPINFOHEADER structure.

lTime

Time, in samples, when this data should be drawn. For video data this is normally a frame number.


ICDRAWBEGIN

typedef struct {

    DWORD              dwFlags;

    HPALETTE           hpal;

    HWND               hwnd;

    HDC                hdc;

    int                xDst;

    int                yDst;

    int                dxDst;

    int                dyDst;

    LPBITMAPINFOHEADER lpbi;

    int                xSrc;

    int                ySrc;

    int                dxSrc;

    int                dySrc;

    DWORD              dwRate;

    DWORD              dwScale;

} ICDRAWBEGIN;

Contains decompression parameters used with the ICM_DRAW_BEGIN message.

dwFlags

Applicable flags. The following values are defined:

ICDRAW_ANIMATE

Application can animate the palette.

ICDRAW_BUFFER

Buffers this data off-screen; it will need to be updated.

ICDRAW_CONTINUE

Drawing is a continuation of the previous frame.

ICDRAW_FULLSCREEN

Draws the decompressed data on the full screen.

ICDRAW_HDC

Draws the decompressed data to a window or a DC.

ICDRAW_MEMORYDC

DC is off-screen.

ICDRAW_QUERY

Determines if the decompressor can handle the decompression. The driver does not actually decompress the data.

ICDRAW_RENDER

Renders but does not draw the data.

ICDRAW_UPDATING

Current frame is being updated rather than played.

hpal

Handle of the palette used for drawing.

hwnd

Handle of the window used for drawing.

hdc

Handle of the DC used for drawing. Specify NULL to use a DC associated with the specified window.

xDst, yDst

The x- and y-coordinates of the destination rectangle.

dxDst, dyDst

Width and height of the destination rectangle.

lpbi

Address of a BITMAPINFOHEADER structure containing the input format.

xSrc, ySrc

The x- and y-coordinates of the source rectangle.

dxSrc, dySrc

Width and height of the source rectangle.

dwRate

Decompression rate in an integer format. To obtain the rate in frames per second, divide this value by the value in dwScale.

dwScale

Value used to scale dwRate to frames per second.


ICDRAWSUGGEST

typedef struct {

    LPBITMAPINFOHEADER lpbiIn;           // see below

    LPBITMAPINFOHEADER lpbiSuggest;      // see below

    int                dxSrc;            // see below

    int                dySrc;            // see below

    int                dxDst;            // see below

    int                dyDst;            // see below

    HIC                hicDecompressor;  // see below

} ICDRAWSUGGEST;

Contains compression parameters used with the ICM_DRAW_SUGGESTFORMAT message to suggest an appropriate input format.

lpbiIn

Address of the structure containing the compressed input format.

lpbiSuggest

Address of a buffer to return a compatible input format for the renderer.

dxSrc, dySrc

Width and height of the source rectangle.

dxDst, dyDst

Width and height of the destination rectangle.

hicDecompressor

Handle of a decompressor that supports the format of data described in lpbiIn.


ICINFO

typedef struct {

    DWORD dwSize;              // see below

    DWORD fccType;             // see below

    DWORD fccHandler;          // see below

    DWORD dwFlags;             // see below

    DWORD dwVersion;           // version member of driver

    DWORD dwVersionICM;        // see below

    WCHAR szName[16];          // see below

    WCHAR szDescription[128];  // see below

    WCHAR szDriver[128];       // see below

} ICINFO;

Contains compression parameters supplied by a video compression driver. The driver fills or updates the structure when it receives the ICM_GETINFO message.

dwSize

Size, in bytes, of the ICINFO structure.

fccType

Four-character code indicating the type of stream being compressed or decompressed. Specify "VIDC" for video streams.

fccHandler

A four-character code identifying a specific compressor.

dwFlags

Applicable flags. Zero or more of the following flags can be set:

VIDCF_COMPRESSFRAMES

Driver is requesting to compress all frames. For information about compressing all frames, see the ICM_COMPRESS_FRAMES_INFO message.

VIDCF_CRUNCH

Driver supports compressing to a frame size.

VIDCF_DRAW

Driver supports drawing.

VIDCF_FASTTEMPORALC

Driver can perform temporal compression and maintains its own copy of the current frame. When compressing a stream of frame data, the driver doesn't need image data from the previous frame.

VIDCF_FASTTEMPORALD

Driver can perform temporal decompression and maintains its own copy of the current frame. When decompressing a stream of frame data, the driver doesn't need image data from the previous frame.

VIDCF_QUALITY

Driver supports quality values.

VIDCF_TEMPORAL

Driver supports inter-frame compression.

dwVersionICM

Version of VCM supported by the driver. This member should be set to ICVERSION.

szName

Short version of the compressor name. The name in the null-terminated string should be suitable for use in list boxes.

szDescription

Long version of the compressor name.

szDriver

Name of the module containing VCM compression driver. Normally, a driver does not need to fill this out.


ICOPEN

typedef struct {

    DWORD    dwSize;       // size, in bytes, of the structure

    DWORD    fccType;      // see below

    DWORD    fccHandler;   // see below

    DWORD    dwVersion;    // see below

    DWORD    dwFlags;      // see below

    LPRESULT dwError;      // error return values

    LPVOID   pV1Reserved;  // reserved; do not use

    LPVOID   pV2Reserved;  // reserved; do not use

    DWORD    dnDevNode;    // device node for Plug and Play devices

} ICOPEN;

Contains information about the data stream being compressed or decompressed, the version number of the driver, and how the driver is used.

fccType

Four-character code indicating the type of stream being compressed or decompressed. Specify "VIDC" for video streams.

fccHandler

Four-character code identifying a specific compressor.

dwVersion

Version of the installable driver interface used to open the driver.

dwFlags

Applicable flags indicating why the driver is opened. The following values are defined:

ICMODE_COMPRESS

Driver is opened to compress data.

ICMODE_DECOMPRESS

Driver is opened to decompress data.

ICMODE_DRAW

Device driver is opened to decompress data directly to hardware.

ICMODE_QUERY

Driver is opened for informational purposes, rather than for compression.

This structure is passed to video capture drivers when they are opened. This allows a single installable driver to function as either an installable compressor or a video capture device. By examining the fccType member of the ICOPEN structure, the driver can determine its function. For example, a fccType value of "VIDC" indicates that it is opened as an installable video compressor.


ICSETSTATUSPROC

typedef struct {

    DWORD  dwFlags;                     // reserved; set to zero

    LPARAM lParam;                      // see below

    LONG   (CALLBACK * ()) fpfnStatus;  // see below

} ICSETSTATUSPROC;

Contains status information used with the ICM_SET_STATUS_PROC message.

lParam

Parameter that contains a constant to pass to the status procedure.

fpfnStatus

Address of the status function. Specify NULL if status messages should not be sent. For more information about the callback function, see the MyStatusProc function.


Video Capture

You can easily incorporate video capture capabilities into your application by using the AVICap window class. AVICap provides applications with a simple, message-based interface to access video and waveform-audio acquisition hardware and to control the process of streaming video capture to disk.

AVICap supports streaming video capture and single-frame capture in real-time. In addition, AVICap provides control of video sources that are Media Control Interface (MCI) devices so the user can control (through an application) the start and stop positions of a video source, and augment the capture operation to include step frame capture.

The windows you create by using the AVICap window class can perform the following tasks:

•	Capture audio and video streams to an audo-video interleaved (AVI) file.

•	Connect and disconnect video and audio input devices dynamically.

•	View a live incoming video signal by using the overlay or preview methods.

•	Specify a file to use when capturing and copy the contents of the capture file to another file.

•	Set the capture rate.

•	Display dialog boxes that control the video source and format.

•	Create, save, and load palettes.

•	Copy images and palettes to the clipboard.

•	Capture and save a single image as a device-independent bitmap (DIB).


Video Capture: A Minimal Approach

Video capture digitizes a stream of video and audio data, and stores it on a hard disk or some other type of persistent storage device. This section describes how to add a simple form of video capture to an application using three statements of code. It also describes how to end or abort a capture session by sending messages to the capture window.

An AVICap capture window handles the details of streaming audio and video capture to AVI files. This frees your application from involvement in the AVI file format, video and audio buffer management, and the low-level access of video and audio device drivers. AVICap provides a flexible interface for applications. You can add video capture to your application with only the following lines of code:

hWndC = capCreateCaptureWindow ( "My Own Capture Window",
WS_CHILD | WS_VISIBLE , 0, 0, 160, 120, hwndParent, nID);
SendMessage (hWndC, WM_CAP_DRIVER_CONNECT, 0 /* wIndex */, 0L);
SendMessage (hWndC, WM_CAP_SEQUENCE, 0, 0L);

A macro interface is also available that provides an alternative to using the SendMessage function and improves the readability of an application. The following example uses the macro interface to add video capture to an application.

hWndC = capCreateCaptureWindow (	"My Own Capture Window",
WS_CHILD | WS_VISIBLE ,	0, 0, 160, 120, hwndParent, nID);
capDriverConnect (hWndC, 0);
capCaptureSequence (hWndC);

Once your application creates a capture window of the AVICap window class and connects it to a video driver, the capture window is ready to capture data. At this point, your application can simply send the WM_CAP_SEQUENCE message (or the capCaptureSequence macro) to begin capturing.

Using default settings, WM_CAP_SEQUENCE initiates capture of video and audio to a file named CAPTURE.AVI. Capture continues until one of the following events occurs:

•	The user presses the ESC key or a mouse button.

•	Your application stops or aborts capture operation.

•	The disk becomes full.

In an application, you can stop streaming captured data to a file by sending the WM_CAP_STOP (or the capCaptureStop macro) message to a capture window. You can also abort the capture operation by sending the WM_CAP_ABORT message (or the capCaptureAbort macro) to a capture window.


Basic Capture Options

By modifying one or more of the capture parameters defined in the CAPTUREPARMS structure, you can perform the following tasks:

•	Change the frame capture rate.

•	Specify keyboard or mouse control for ending a capture session.

•	Specify a duration for a capture session.


Capture Rate

The capture rate is the number of frames that are captured each second of a capture session. You can retrieve the current capture rate by using the WM_CAP_GET_SEQUENCE_SETUP message (or the capCaptureGetSetup macro). The current capture rate is stored in the dwRequestMicroSecPerFrame member of the CAPTUREPARMS structure. You can set the capture rate by specifying the number of microseconds between successive frames as the value of this member, and then sending the updated CAPTUREPARMS structure to the capture window by using the WM_CAP_SET_SEQUENCE_SETUP message (or the capCaptureSetSetup macro). The default value of dwRequestMicroSecPerFrame is 66667, which corresponds to 15 frames per second.


Keys Ending Capture

You can allow the user to abort a capture session by pressing a key or keystroke combination from the keyboard, or by pressing the right or left mouse button. If the user aborts a real-time capture session, the contents of the capture file are discarded. If the user aborts a step-frame capture session, the contents of the capture file up to the point of aborting the capture are saved.

You can retrieve the settings for aborting a capture session by using the WM_CAP_GET_SEQUENCE_SETUP message (or the capCaptureGetSetup macro). The current keystroke setting is stored in the vKeyAbort member of the CAPTUREPARAMS structure; the current mouse settings are stored in the fAbortLeftMouse and fAbortRightMouse members. You can set a new key or keystroke combination by specifying the keycode or keycode combination (as in a CTRL or SHIFT key combination) as the value of vKeyAbort, or set the left or right mouse button as the abort key by specifying the fAbortLeftMouse or fAbortRightMouse member. After you set these members, send the updated CAPTUREPARMS structure to the capture window by using the WM_CAP_SET_SEQUENCE_SETUP message (or the capCaptureSetSetup macro). The default value of vKeyAbort is VK_ESCAPE. The default values of fAbortLeftMouse and fAbortRightMouse are TRUE.


Time Limit

You can limit the duration of a capture operation by using the fLimitEnabled and wTimeLimit members of the CAPTUREPARAMS structure. The fLimitEnabled member indicates whether the capture operation is to be timed, while wTimeLimit specifies the maximum duration of the capture operation.

You can retrieve the values for fLimitEnabled and wTimeLimit by using the WM_CAP_GET_SEQUENCE_SETUP message (or the capCaptureGetSetup macro). You can enable a timer for the capture operation by specifying TRUE as the value of fLimitEnabled, or you can set the duration of the capture operation by specifying a value, in seconds, for wTimeLimit. After you set these members, send the updated CAPTUREPARMS structure to the capture window by using the WM_CAP_SET_SEQUENCE_SETUP message (or the capCaptureSetSetup macro). The default value of fLimitEnabled is FALSE.


Capture Windows

Capture windows are conceptually similar to standard controls (such as buttons, list boxes, or scroll bars) for the Microsoft Windows operating system. Typically, capture windows use the WS_CHILD and WS_VISIBLE window styles.


Creating an AVICap Capture Window

You can create a capture window of the AVICap window class by using the capCreateCaptureWindow function. This function returns a window handle that identifies the capture window and is used by an application to send subsequent messages to the window.

You can create one or more capture windows in an application and connect each capture window to a different capture device.


Connecting a Capture Window to a Capture Driver

You can dynamically connect or disconnect a capture window to a capture driver. You can connect or associate a capture window with a capture driver by using the WM_CAP_DRIVER_CONNECT message (or the capDriverConnect macro). After a capture window and capture driver are connected, you can send device-specific messages to the capture driver associated with a capture window.

If you have more than one capture device installed on a system, you can connect a capture window to a particular video capture device driver by specifying an integer for the wParam parameter of the WM_CAP_DRIVER_CONNECT message. The integer is an index that identifies a video capture driver listed in the registry or in  the [drivers] section of the SYSTEM.INI file. Use zero for the first index entry.

You can retrieve the name and version of an installed capture driver by using the the capGetDriverDescription function. Your application can use this function to enumerate the installed capture devices and drivers, so the user can select a capture device to connect to a capture window.

You can retrieve the name of the capture device driver connected to a capture window by using the WM_CAP_DRIVER_GET_NAME message (or the capDriverGetName macro). To retrieve the version of an installed capture driver, use the WM_CAP_DRIVER_GET_VERSION message (or the capDriverGetVersion macro).

You can disconnect a capture window from a capture driver by using the WM_CAP_DRIVER_DISCONNECT message (or the capDriverDisconnect macro).

When an capture window is destroyed, any connected video capture device drivers are automatically disconnected.


Parent-Child Window Interaction

Some system-level messages, such as WM_PALETTECHANGED and WM_QUERYNEWPALETTE, are sent only to top-level and overlapped windows. If a capture window is a child window, its parent must forward these messages.

Similarly, if the parent window changes size, it might need to send notification messages to the capture window. Conversely, if the dimensions of the captured video change, the capture window might need to send notification messages to the parent window. The simplest way to manage this is to always keep the capture window dimensions equal to the size of the captured video stream, notifying the parent whenever these dimensions change.


Capture Window Status

You can retrieve the current status of a capture window by using the WM_CAP_GET_STATUS message (or the capGetStatus macro). This message retrieves a copy of the CAPSTATUS structure with the current values of its members. The CAPSTATUS structure contains information regarding the dimensions of the image, scroll position, and whether overlay or preview of the image is enabled. Because the information represented in CAPSTATUS is dynamic, your application should refresh the contents of the structure whenever the size or format of the captured video stream might have changed (such as after displaying the video format of the capture driver).

Changing the dimensions of the capture window has no effect on the dimensions of the actual captured video stream. The format dialog box displayed by the video capture device driver controls the dimensions of the captured video stream.


Capture and Audio Drivers

A capture driver and the underlying hardware can dictate several aspects of video capture, including acceptable video sources, display options, formats, and compression options. An audio driver specifies the audio format and possibly a compression option used with captured audio data.


Capture Driver Capabilities

You can retrieve the hardware capabilities of the currently connected capture driver by using the WM_CAP_DRIVER_GET_CAPS message (or the capDriverGetCaps macro). This message returns the capabilities of the capture driver and underlying hardware in the CAPDRIVERCAPS structure.


Video Dialog Boxes

Each capture driver can provide up to four dialog boxes to control aspects of the video digitization and capture process, and to define compression attributes used in reducing the size of the video data. The contents of these dialog boxes are defined by the video capture driver.

The Video Source dialog box controls the selection of video input channels and parameters affecting the video image being digitized in the frame buffer. This dialog box enumerates the types of signals that connect the video source to the capture card (typically SVHS and composite inputs), and provides controls to change hue, contrast or saturation. If the dialog box is supported by a video capture driver, you can display and update it by using the WM_CAP_DLG_VIDEOSOURCE message (or the CapDlgVideoSource macro).

The Video Format dialog box controls selection of the digitized video frame dimensions and image-depth, and compression options of the captured video. If the dialog box is supported by a video capture driver, you can display and update it by using the WM_CAP_DLG_VIDEOFORMAT message (or the capDlgVideoFormat macro).

The Video Display dialog box controls the appearance of the video on the monitor during capture. The controls in this dialog box have no effect on the digitized video data, but they might affect the presentation of the digitized signal. For example, capture devices that support overlay might allow altering hue and saturation, key color, or alignment of the overlay. If the dialog box is supported by a video capture driver, you can display and update it by using the WM_CAP_DLG_VIDEODISPLAY message (or the capDlgVideoDisplay macro).

The Video Compression dialog box controls the post-capture video compression attributes. If the dialog box is supported by a video capture driver, you can display and update it by using the WM_CAP_DLG_VIDEOCOMPRESSION message (or the capDlgVideoCompression macro).


Preview and Overlay Modes

A capture driver can implement two methods for viewing an incoming video stream: preview mode and overlay mode. If a capture driver implements both methods, the user can choose which method to use.

Preview mode transfers digitized frames from the capture hardware to system memory and then displays the digitized frames in the capture window by using graphics device interface (GDI) functions. Applications might decrease the preview rate when the parent window loses focus, and increase the preview rate when the parent window gains focus. This action improves general system responsiveness because the preview operation is processor intensive.

Three messages control the preview operation. You can enable or disable preview mode by sending the WM_CAP_SET_PREVIEW message (or the capPreview macro) to a capture window, or you can set the rate at which frames are displayed in preview mode by sending the WM_CAP_SET_PREVIEWRATE message (or the capPreviewRate macro), or you can enable or disable scaling of the preview video by sending the WM_CAP_SET_SCALE message (or the capPreviewScale macro). When preview and scaling are both enabled, the captured video frame is stretched to the dimensions of the capture window. Enabling preview mode automatically disables overlay mode.

Overlay mode is a hardware function that displays the contents of the capture buffer on the monitor without using CPU resources. You can enable and disable overlay mode by sending the WM_CAP_SET_OVERLAY message (or the capOverlay macro) to a capture window. Enabling overlay mode automatically disables preview mode.

You can also set the scroll position of the video frame within the client area of the capture window for preview mode or overlay mode by sending the WM_CAP_SET_SCROLL message (or the capSetScrollPos macro) to a capture window.


Video Format

You can retrieve the structure that specifies the video format or the size of that structure by sending the WM_CAP_GET_VIDEOFORMAT message (or the capGetVideoFormat and capGetVideoFormatSize macros) to a capture window. You can set the format of captured video data by sending the WM_CAP_SET_VIDEOFORMAT message (or the capSetVideoFormat macro) to a capture window.


Video Capture Settings

The CAPTUREPARMS structure contains the control parameters for streaming video capture. This structure controls several aspects of the capture process, and allows you to perform the following tasks:

•	Specify the frame rate.

•	Specify the number of allocated video buffers.

•	Disable and enable audio capture.

•	Specify the time interval for the capture.

•	Specify if an MCI device (VCR or videodisc) is used during capture.

•	Specify keyboard or mouse control for ending streaming.

•	Specify the type of video averaging applied during capture.

You can retrieve the current capture settings within the CAPTUREPARMS structure by sending the WM_CAP_GET_SEQUENCE_SETUP message (or the capCaptureGetSetup macro) to a capture window. You can set one or more current capture settings by updating the appropriate members of the CAPTUREPARMS structure and then sending the WM_CAP_SET_SEQUENCE_SETUP message (or the capCaptureSetSetup macro) and CAPTUREPARMS to a capture window.


Audio Format

You can retrieve the current capture format for audio data or the size of the audio format structure by sending the WM_CAP_GET_AUDIOFORMAT message (or the capGetAudioFormat and capGetAudioFormatSize macros) to a capture window. The default audio capture format is mono, 8-bit, 11 kHz PCM (Pulse Code Modulation). When you retrieve the format by using WM_CAP_GET_AUDIOFORMAT, always use the WAVEFORMATEX structure.

You can set the capture format for audio data by sending the WM_CAP_SET_AUDIOFORMAT message (or the capSetAudioFormat macro) to a capture window. When setting the audio format, you can pass a pointer to a WAVEFORMAT, WAVEFORMATEX, or PCMWAVEFORMAT structure, depending on the specified audio format.


Capture File and Buffers

This section describes tips and options for using the capture file and for specifying buffers for the capture operation.


Capture Filename

AVICap, by default, routes video and audio stream data from a capture window to a file named CAPTURE.AVI in the root directory of the current drive. You can specify an alternate filename by sending the WM_CAP_FILE_SET_CAPTURE_FILE message (or the capFileSetCaptureFile macro) to a capture window. This message specifies the filename; it does not create, allocate, or open the file. You can retrieve the current capture filename by sending the WM_CAP_FILE_GET_CAPTURE_FILE message (or the capFileGetCaptureFile macro) to a capture window.


Saving Captured Data to a New File

If the user wants to save captured data, you should save the contents of the capture file to another file by using the WM_CAP_FILE_SAVEAS message (or the capFileSaveAs macro). This message does not change the name or contents of the capture file. Your application must specify a name for the new file because the capture file retains its original filename.

Typically, a capture file is preallocated for the largest capture segment anticipated and only a portion of it might be used to capture data. This message copies only the portion of the capture file containing the capture data.


Disk Space Preallocation for the Capture File

Preallocating disk space for the capture file builds a file of a specified size on the disk before the start of a capture operation. Preallocating a capture file reduces the processing required while capture is in progress and results in fewer dropped frames. You can preallocate a capture file by using the WM_CAP_FILE_ALLOCATE message (or the capFileAlloc macro).

Typically, your application should preallocate enough disk space to contain the largest capture file anticipated. Preallocating disk space does not restrict the size of the captured file. The file size is automatically enlarged if the captured data exceeds the allocated space. Subsequent write operations to the capture file reuse the portions of disk space allocated for the file, preserving the size and state of fragmentation of the file.

You can also improve capture performance by defragmenting the capture file. To defragment the file, use a defragmentation utility such as Disk Defragmenter. If you use a defragmented capture file and later enlarge it, you should defragment the enlarged file. Enlarging a defragmented capture file can fragment the expanded portion of the file and reduce performance in the capture operation.

You might also improve performance by using an uncompressed disk for video capture. Compressing data during capture can limit capture throughput to the disk.

An application can reserve a permanent capture file to eliminate the time required to preallocate and defragment a file each time it is started. Because a capture file can require considerable disk space, and preallocating a capture file removes all data from an existing capture file, an application should let the user decide if the file is permanent or temporary.


Index Size

Each AVI file uses an index of a specified size to locate video and audio data chunks within the file. An entry in the index locates one video frame or waveform-audio buffer. Consequently, the value of the index size indirectly sets the upper limit on the number of frames that can be captured in a file.

You can retrieve the current index size by using the WM_CAP_GET_SEQUENCE_SETUP message (or the capCaptureGetSetup macro). The current index size is stored in the dwIndexSize member of the CAPTUREPARAMS structure. You can specify a new index size as the value of dwIndexSize and then send the updated CAPTUREPARMS structure to the capture window by using the WM_CAP_SET_SEQUENCE_SETUP message (or the capCaptureSetSetup macro). The default index size is 34,952 entries (allowing 32K frames and a proportional number of audio buffers).


Video and Audio Chunk Granularity

The chunk granularity is a logical block size for an AVI file that is used for writing and retrieving audio and video data chunks. When writing audio and video chunks to disk, AVICap adds filler chunks (RIFF "JUNK" chunks) as necessary to fill each logical block of data.

You can retrieve the current chunk granularity setting by using the WM_CAP_GET_SEQUENCE_SETUP message (or the capCaptureGetSetup macro). The current chunk granularity is stored in the wChunkGranularity member of the CAPTUREPARMS structure. You can specify a new chunk granularity as the value of wChunkGranularity and then send the updated CAPTUREPARMS structure to the capture window by using the WM_CAP_SET_SEQUENCE_SETUP message (or the capCaptureSetSetup macro). You can also specify zero for this member to set the chunk granularity to the sector size of the disk.


Video Buffers

The buffers used with video capture reside in the memory heap. The number of buffers used in a capture operation can vary and depend on the value of the wNumVideoRequested member of the CAPTUREPARMS structure and available system memory.

You can retrieve the current value of requested video buffers by using the WM_CAP_GET_SEQUENCE_SETUP message (or the capCaptureGetSetup macro). The current requested number of video buffers is stored in the wNumVideoRequested member of the CAPTUREPARMS structure. You can request the placement and number of buffers by updating this member, and then sending the updated CAPTUREPARMS structure to the capture window by using the WM_CAP_SET_SEQUENCE_SETUP message (or the capCaptureSetSetup macro).


Audio Buffers

You can control the audio portion of a capture operation in three ways:

•	Include or exclude audio from the capture operation.

•	Request a specific number of audio buffers.

•	Request audio buffers be a specific size.

You can retrieve the settings for audio buffers by using the WM_CAP_GET_SEQUENCE_SETUP message (or the capCaptureGetSetup macro). The fCaptureAudio member of the CAPTUREPARMS structure specifies whether audio is included or excluded from the capture operation. The current requested number of audio buffers is stored in the wNumAudioRequested member, and the current audio buffer size is stored in the dwAudioBufferSize member. You can specify whether to include audio capture, and the size and number of audio buffers by updating these members, and then sending the updated CAPTUREPARMS structure to the capture window by using the WM_CAP_SET_SEQUENCE_SETUP message (or the capCaptureSetSetup macro).

By default, audio is included in the capture operation and four audio buffers are allocated. The default value of fCaptureAudio is TRUE. The default buffer size (the value of dwAudioBufferSize) can contain 0.5 seconds of audio data or 10K, whichever is greater.


Capture Variations

In addition to streaming capture based on a constant time interval, AVICap supports the following types of capture:

•	Manual frame capture (programmable control frames that are captured)

•	Still-image capture

•	Capture without using disk storage

•	Streaming capture from an MCI device (real-time and step-frame)


Manual Frame Capture

If you want to individually specify the frames to capture in a video stream, you can control the sequence by using the WM_CAP_SINGLE_FRAME_OPEN, WM_CAP_SINGLE_FRAME, and WM_CAP_SINGLE_FRAME_CLOSE messages (or the capCaptureSingleFrameOpen, capCaptureSingleFrame, and capCaptureSingleFrameClose macros). Typically, these messages are used to create animation by appending individual frames to the capture file. WM_CAP_SINGLE_FRAME_OPEN opens a file for a manually-driven capture operation. WM_CAP_SINGLE_FRAME captures an individual frame and appends it to the capture file. WM_CAP_SINGLE_FRAME_CLOSE closes the file used for manual frame capture.

Note  This capture method does not support simultaneous audio capture with video capture.


Still-Image Capture

If you want to capture a single frame as a still image, you can use the WM_CAP_GRAB_FRAME_NOSTOP or WM_CAP_GRAB_FRAME message (or the capGrabFrameNoStop or capGrabFrame macro) to capture the digitized image in an internal frame buffer. You can freeze the display on the captured image by using WM_CAP_GRAB_FRAME. Otherwise, use WM_CAP_GRAB_FRAME_NOSTOP.

Once captured, you can copy the image for use by other applications. You can copy an image from the frame buffer to the clipboard by using the WM_CAP_EDIT_COPY message (or the capEditCopy macro). You can also copy the image from the frame buffer to a device-independent bitmap (DIB) by using the WM_CAP_FILE_SAVEDIB message (or the capFileSaveDIB macro).

Your application can also use the two single-frame capture messages to edit a sequence frame by frame, or to create a time-lapse photography sequence.


Capture Without Using Disk Storage

You can use capture services without writing the data to a disk file by using the WM_CAP_SEQUENCE_NOFILE message (or the capCaptureSequenceNoFile macro). This message is useful only in conjunction with callback functions that allow your application to use the video and audio data directly. For example, videoconferencing applications might use this message to obtain streaming video frames. The callback functions would transfer the captured images to the remote computer.


Streaming Capture from an MCI Device

MCI devices augment the capture operation in real-time capture and step-frame capture. You can specify the MCI device, such as a videodisc or video-cassette recorder (VCR), acting as the video source for your capture operation by using the WM_CAP_SET_MCI_DEVICE message (or the capSetMCIDeviceName macro) and specifying the name of the device. You can also retrieve the device name currently set by using the WM_CAP_GET_MCI_DEVICE message (or the capGetMCIDeviceName macro).

In real-time capture, the capture window synchronizes the capture operation and compensates for delays associated with positioning the MCI video source and initializing the resources (such as capture buffers) required for capturing data. The capture window expects a valid MCI video device to be installed in the system for capturing data this way.

Specifications for controlling an MCI device are stored in the members of the CAPTUREPARMS structure. MCI-compatible video sources include VCRs and laserdiscs. If the fMCIControl member of this structure is set to TRUE, the capture window coordinates MCI operation. The capture window uses the parameters specified in the dwMCIStartTime and dwMCIStopTime members to obtain the starting and stopping positions, in milliseconds, of the sequence. If the value of fMCIControl is FALSE, the video source is not treated as an MCI device and the contents of dwMCIStartTime and dwMCIStopTime are ignored.

You can use Media Player to quickly verify that an MCI video device is properly connected to the system. Playing a device with Media Player verifies that the MCI configuration for the device is correct. If an image appears on the video display, the video source is connected properly to the capture hardware.

In step-frame capture, the capture window synchronizes the capture operation and compensates for the delays associated with positioning the MCI video source and initializing the resources required for capturing data. In addition, the capture window ensures that no frames are dropped; it steps through the video frames individually, ensuring that the frame is captured and stored before capturing the next frame in the video stream.

Specifications for controlling step-frame capture are stored in the members of the CAPTUREPARMS structure. Step-frame capture uses the following members in addition to the members used for real-time capture: fStepMCIDevice, fStepCaptureAt2x, and wStepCaptureAverageFrames. If the fStepMCIDevice member is set to TRUE, the capture window coordinates step-frame capture. The capture window uses the parameters specified in the dwMCIStartTime and dwMCIStopTime members for the starting and stopping positions, in milliseconds, of the sequence. The capture window uses fStepCaptureAt2x to determine if the capture hardware should capture video frames at twice the normal resolution and uses wStepCaptureAverageFrames to specify the number of times each frame in the capture operation is sampled.

If fStepMCIDevice is FALSE, real-time capture is used instead of step-frame capture and the contents of fStepCaptureAt2x, and wStepCaptureAverageFrames are ignored.

If a step-frame capture is specified and fStepCaptureAt2x is set to TRUE, the capture hardware captures at twice the specified resolution. (The resolutions of both the height and width are doubled.) The software interpolates the pixels in the higher resolution image to produce the image at the specified resolution. This form of averaging can improve the edge definition of images in a frame. You can enable this option if the hardware does not support hardware-based decimation and you are capturing in the RGB format.

Note  If your hardware supports hardware-based decimation, it can capture samples at a higher rate than specified and use these additional samples to obtain color definitions that are more consistent with the original image. The additional samples are discarded after they are used, and the hardware passes samples to the capture driver at the specified rate.

If a step-frame capture is specified, the wStepCaptureAverageFrames member specifies the number of times a frame is sampled when creating a frame based on the average sample. This averaging technique reduces the random digitization noise appearing in a frame. A typical value for the number of averages is 5.

For more information about MCI, see Chapter 3, "MCI Overview."


Advanced Capture Options

This section describes other options you can include in a capture operation.


Measuring Video Quality

One way to measure video quality is to limit the number of captured frames that are dropped during the capture operation. When streaming capture has finished, the quality value is compared with the ratio of dropped frames to total frames. If the percentage of dropped frames is greater than the value of the wPercentDropForError member of the CAPTUREPARMS structure, AVICap sends an error message to the error callback function if it is installed.

You can retrieve the current limit of dropped frames (expressed as a percentage) by using the WM_CAP_GET_SEQUENCE_SETUP message (or the capCaptureGetSetup macro). You can set a new limit by specifying a percentage as the value of the wPercentDropForError member of the CAPTUREPARAMS structure, and then sending the updated structure to the capture window by using the WM_CAP_SET_SEQUENCE_SETUP message (or the capCaptureSetSetup macro). The default value of wPercentDropForError is 10 percent.


User-Initiated Capture

You can retrieve the current value of the user-initiated capture flag by using the WM_CAP_GET_SEQUENCE_SETUP message (or the capCaptureGetSetup macro). The value of the flag is stored in the fMakeUserHitOKToCapture member of the CAPTUREPARAMS structure. You can provide the user with precise control over when to start a capture session by setting this member to TRUE. AVICap displays a dialog box after allocating all video and audio buffers for a capture session. This lets the user eliminate capture delays because of software initialization. If your applications uses a small number of video buffers, this dialog box is probably unnecessary. The default value is FALSE.


Working with Palettes

Initially, if the video capture format requires a palette, the capture window uses the palette supplied by the capture driver. This palette might consist of gray-scale values for black-and-white reproduction, or a broad selection of color values. You can retrieve an existing palette to replace the default palette by using the WM_CAP_PAL_PASTE or WM_CAP_PAL_OPEN message (or the capPalettePaste or capPaletteOpen macro). Alternatively, you can create a custom palette to replace the default palette by using the WM_CAP_PAL_AUTOCREATE or WM_CAP_PAL_MANUALCREATE message (or the capPaletteAuto or capPaletteManual macro). After you replace the default palette, the capture window and driver use the replacement palette until you create or open another palette.

The WM_CAP_PAL_AUTOCREATE or WM_CAP_PAL_MANUALCREATE message creates an optimized palette based on the current video input. This custom palette gives a video sequence the best color fidelity because it is based on colors that exist in the sequence. The capture window creates a three-dimensional histogram of the colors it samples. It reduces the number of colors by examining the absolute error between adjacent colors and consolidating those with the smallest error value.

When sending WM_CAP_PAL_AUTOCREATE, you must specify the number of frames for AVICap to sample and the size of the color palette. When specifying the number of frames, include enough frames to ensure that all colors in the sequence are sampled.

You can sample the current frame by using WM_CAP_PAL_MANUALCREATE. By using this message with several manually selected frames, you can create a palette that contains the colors you want to appear in the palette.

A palette can contain up to 256 colors. If you merge palettes or if the video sequence is to be displayed simultaneously with other video or images, you should use a smaller color selection so that colors from each image or video clip can coexist.

You save a new palette by using the WM_CAP_PAL_SAVE message (or the capPaletteSave macro) and later retrieve it by using the WM_CAP_PAL_OPEN message. You can save a palette for post-processing of the palette or for use in another application.

You can paste a palette from the clipboard into the capture window by using the WM_CAP_PAL_PASTE message. The capture window passes the palette to the capture driver. Other applications can copy palettes to the clipboard. You can also copy a palette to the clipboard by using the WM_CAP_EDIT_COPY message (or the capEditCopy macro). This message copies the video frame buffer, including the palette, onto the clipboard.


Embedding Information Chunks in an AVI File

You can insert information chunks, such as text or custom data, in an AVI file by using the WM_CAP_FILE_SET_INFOCHUNK message (or the capFileSetInfoChunk macro). You can also use this message to clear information chunks from an AVI file.


User Data Messages

You can associate data with a capture window by using the WM_CAP_GET_USER_DATA and WM_CAP_SET_USER_DATA messages (or the capGetUserData and capSetUserData macros). You can retrieve a LONG data value by using the WM_CAP_GET_USER_DATA message and set a LONG data value by using the WM_CAP_SET_USER_DATA message.


AVICap Callback Functions

Your application can register callback functions with a capture window to have it notify your application when the status changes, when errors occur, when video frame and audio buffers become available, and to yield during streaming capture. The following messages set the callback function.

Message	Description
WM_CAP_SET_CALLBACK_CAPCONTROL	Specifies the callback function in the application called to give precise control over capture start and end. You can also use the capSetCallbackOnCapControl macro to send this message.
WM_CAP_SET_CALLBACK_ERROR	Specifies the callback function in the application called when an error occurs. You can also use the capSetCallbackOnError macro to send this message.
WM_CAP_SET_CALLBACK_FRAME	Specifies the callback function in the application called when preview frames are captured. You can also use the capSetCallbackOnFrame macro to send this message.
WM_CAP_SET_CALLBACK_STATUS	Specifies the callback function in the application called when the status changes. You can also use the capSetCallbackOnStatus macro to send this message.
WM_CAP_SET_CALLBACK_VIDEOSTREAM	Specifies the callback function in the application called during streaming capture when a new video buffer becomes available. You can also use the capSetCallbackOnVideoStream macro to send this message.
WM_CAP_SET_CALLBACK_WAVESTREAM	Specifies the callback function in the application called during streaming capture when a new audio buffer becomes available. You can also use the capSetCallbackOnWaveStream macro to send this message.
WM_CAP_SET_CALLBACK_YIELD	Specifies the callback function in the application called when yielding during streaming capture. You can also use the capSetCallbackOnYield macro to send this message.
The following sections describe the different callback functions, the notifications sent to the functions, and their uses.


Precise Capture Control

A capture window can provide the capture-control callback function with precise control over the moments that streaming capture begin and end. The first message sent from the capture driver to the callback procedure sets the nState parameter to CONTROLCALLBACK_PREROLL after allocating all buffers and all other capture preparations are complete. This message gives the application the ability to preroll the video sources. (The callback function specifies nState as its second parameter.) The callback function then returns at the exact moment recording is to begin. A return value of TRUE from the callback function continues capture. A return value of FALSE aborts capture. Once capture begins, the callback function is called frequently with nState set to CONTROLCALLBACK_CAPTURING to allow the application to end capture by returning false.


Error

A capture window uses error notification messages to notify your application of AVICap errors, such as running out of disk space, attempting to write to a read-only file, failing to access hardware, or dropping too many frames. The content of an error notification includes a message identifier and a formatted text string ready for display. Your application can use the message identifier to filter the notifications and limit the messages to present to the user. A message identifier of zero indicates a new operation is starting and the callback function should clear any displayed error message.


Frame

A capture window uses frame callback notification messages to notify your application when a new video frame is available. The capture window enables these callback notifications only if the preview rate is non-zero and streaming capture is not in progress.


Status Callback Functions

A capture window can send messages to the status callback function while capturing video to disk or during other lengthy operations to notify your application of the progress of an operation. The status information includes a message identifier and a formatted text string ready for display. Your application can use the message identifier to filter the notifications and limit the messages to present to the user. During capture operations, the first message sent to the callback function is always IDS_CAP_BEGIN and the last is always IDS_CAP_END. A message identifier of zero indicates a new operation is starting and the callback function should clear the current status.


Videostream

Applications can use videostream callback functions during streaming capture to process a captured video frame. The capture window calls a videostream callback function just before writing each captured frame to the disk.


Wavestream

Applications use the wavestream callback functions during streaming capture to process audio buffers. The capture window calls a wavestream callback function just before writing each audio buffer to the disk.


Yield Callback Functions

Applications can use yield callback functions during streaming capture. (A yield callback function typically consists of a PeekMessage, TranslateMessage, DispatchMessage loop.) The capture window calls the yield callback function at least once for every captured video frame, but the exact rate depends on the frame rate and the overhead of the capture driver and disk.


Disabling Callback Functions

You can permanently or temporarily disable any of the callback functions by specifying NULL in place of the callback function when sending the appropriate message to set a callback function.


Using Video Capture

This section contains examples demonstrating how to perform the following tasks:

•	Create a capture window.

•	Connect to a capture driver.

•	Enumerate installed capture drivers.

•	Obtain the capabilities of a capture driver.

•	Obtain the status of a capture window.

•	Display dialog boxes to set video characteristics.

•	Obtain and setting the video format.

•	Preview video.

•	Enable video overlay.

•	Name the capture file.

•	Preallocate disk space for the capture file.

•	Format audio capture.

•	Change a video capture setting.

•	Capture data.

•	Adding an information chunk.

•	Add callback functions to an application.

•	Create a status callback function.

•	Create an error callback function.

•	Create a frame callback function.


Creating a Capture Window

The following example creates a capture window by using the capCreateCaptureWindow function.

hWndC = capCreateCaptureWindow (
(LPSTR) "My Capture Window", // window name if pop-up
WS_CHILD | WS_VISIBLE,       // window style
0, 0, 160, 120,              // window position and dimensions
(HWND) hwndParent,
(int) nID /* child ID */);


Connecting to a Capture Driver

The following example connects the capture window with the handle hWndC to the MSVIDEO driver and then disconnects them:

fOK = SendMessage (hWndC, WM_CAP_DRIVER_CONNECT, 0, 0L);

//

// Or, use the macro to connect to the MSVIDEO driver:

// fOK = capDriverConnect(hWndC, 0);

// .

// . Place code to set up and capture video here.

// .

capDriverDisconnect (hWndC);


Enumerating Installed Capture Drivers

The following example uses the capGetDriverDescription function to obtain the names and versions of the installed capture drivers.

char szDeviceName[80];
char szDeviceVersion[80];

for (wIndex = 0; wIndex < 10; wIndex++) {
    if (capGetDriverDescription (wIndex, szDeviceName,
        sizeof (szDeviceName), szDeviceVersion,
        sizeof (szDeviceVersion))
    {
        \\ Append name to list of installed capture drivers
        \\ and then let the user select a driver to use.
    }
}


Obtaining the Capabilities of a Capture Driver

The WM_CAP_DRIVER_GET_CAPS message returns the capabilities of the capture driver and underlying hardware in the CAPDRIVERCAPS structure. Each time an application connects a new capture driver to the capture window, it should update the CAPDRIVERCAPS structure. The following example obtains the capture driver capabilities.

CAPDRIVERCAPS CapDrvCaps;

// .

// .

// .

SendMessage (hWndC, WM_CAP_DRIVER_GET_CAPS,
sizeof (CAPDRIVERCAPS), (LONG) (LPVOID) &CapDrvCaps);

//

// Or, use the macro to retrieve the driver capabilities.

// capDriverGetCaps(hWndC, &CapDrvCaps, sizeof (CAPDRIVERCAPS));


Obtaining the Status of a Capture Window

The following example sets the size of the capture window to the overall dimensions of the incoming video stream based on information returned in the CAPSTATUS structure.

CAPSTATUS CapStatus;
// .

// .

// .

capGetStatus(hWndC, &CapStatus, sizeof (CAPSTATUS));

SetWindowPos(hWndC, NULL, 0, 0, CapStatus.uiImageWidth,
    CapStatus.uiImageHeight, SWP_NOZORDER | SWP_NOMOVE);


Displaying Dialog Boxes to Set Video Characteristics

Each capture driver can provide up to three different dialog boxes used to control aspects of the video digitization and capture process. The following example demonstrates how to display these dialog boxes. Before displaying each dialog box, the example checks the CAPDRIVERCAPS structure to see if the capture driver can display it.

CAPDRIVERCAPS CapDrvCaps;

// .

// .

// .

capDriverGetCaps(hWndC, &CapDrvCaps, sizeof (CAPDRIVERCAPS));

// Video source dialog box.

if (CapDriverCaps.fHasDlgVideoSource)
    capDlgVideoSource(hWndC);

// Video format dialog box.

if (CapDriverCaps.fHasDlgVideoFormat) {
    capDlgVideoFormat(hWndC);

    // New image dimensions?
    capGetStatus(hWndC, &CapStatus, sizeof (CAPSTATUS));

    // If so, notify the parent of a size change.
}

// Video display dialog box.

if (CapDriverCaps.fHasDlgVideoDisplay)
    capDlgVideoDisplay(hWndC);


Obtaining and Setting the Video Format

The BITMAPINFO structure is of variable length to accommodate standard and compressed data formats. Because this structure is of variable length, applications must always query the size of the structure and allocate memory before retrieving the current video format. The following example uses the capGetVideoFormatSize macro to retrieve the buffer size and then calls the capGetVideoFormat macro to retrieve the current video format.

LPBITMAPINFO lpbi;
DWORD dwSize;

dwSize = capGetVideoFormatSize(hWndC);
lpbi = GlobalAllocPtr (GHND, dwSize);
capGetVideoFormat(hWndC, lpbi, dwSize);

// Access the video format and then free the allocated memory.

Applications can use the capSetVideoFormat macro (or the WM_CAP_SET_VIDEOFORMAT message) to send a BITMAPINFO header structure to the capture window. Because video formats are device specific, your application should check the return value to determine if the format was accepted.


Previewing Video

The following example sets the frame display rate for preview mode to 66 milliseconds per frame and then places the capture window in preview mode.

capPreviewRate(hWndC, 66);     // rate, in milliseconds
capPreview(hWndC, TRUE);       // starts preview

// .

// .

// .

capPreview(hWnd, FALSE);        // disables preview


Enabling Video Overlay

The following example determines if a capture driver has overlay capabilities; if it does, it enables the overlay.

CAPDRIVERCAPS CapDrvCaps;

// .

// .

// .

capDriverGetCaps(hWndC, &CapDrvCaps, sizeof (CAPDRIVERCAPS));

if (CapDrvCaps.fHasOverlay)
    capOverlay(hWndC, TRUE);


Naming the Capture File

The following example specifies an alternate filename (MYCAP.AVI) for the capture file and preallocates the file to 5 MB.

char szCaptureFile[] = "MYCAP.AVI";

capFileSetCaptureFile( hWndC	, szCaptureFile);

capFileAlloc( hWndC, (1024L * 1024L * 5));


Formatting Audio Capture

The following example sets the audio format to 11-kHz PCM 8-bit, stereo.

WAVEFORMATEX wfex;
// .
// .
// .
wfex.wFormatTag = WAVE_FORMAT_PCM;
wfex.nChannels = 2;	                // Use stereo
wfex.nSamplesPerSec = 11025;
wfex.nAvgBytesPerSec = 22050;
wfex.nBlockAlign = 2;
wfex.wBitsPerSample = 8;
wfex.cbSize = 0;

capSetAudioFormat(hWndC, &wfex, sizeof(WAVEFORMATEX));


Changing a Video Capture Setting

The following example changes the capture rate from the default value (15 frames per second) to 10 frames per second.

CAPTUREPARMS CaptureParms;
float FramesPerSec = 10.0;
// .
// .
// .
capCaptureGetSetup(hWndC, &CaptureParms, sizeof(CAPTUREPARMS));

CaptureParms.dwRequestMicroSecPerFrame = (DWORD) (1.0e6 / FramesPerSec);
capCaptureSetSetup(hWndC, &CaptureParms, sizeof (CAPTUREPARMS));


Capturing Data

The following example starts video capture and copies the captured data from the capture file to the file NEWFILE.AVI.

char szNewName[] = "NEWFILE.AVI";
// .
// . Set up the capture operation.
// .
capCaptureSequence(hWndC);

// .
// .
// .
capFileSaveAs(hWndC, szNewName);


Adding an Information Chunk

If your application needs to include other information in addition to audio and video, you can create information chunks and insert them into a capture file. Information chunks can contain several types of information, including the details of a copyright notice, identification of the video source, or external timing information. The following example stores external timing information — a SMPTE (Society of Motion Picture and Television Engineers) timecode — in an information chunk and adds the chunk to a capture file.

//  This example assumes the application controls

//  the video source for preroll and postroll.

CAPINFOCHUNK cic;
// .

// .

// .

cic.fccInfoID = infotypeSMPTE_TIME;
cic.lpData = "00:20:30:12";
cic.cbData = strlen (cic.lpData) + 1;
capFileSetInfo (hwndC, &cic);


Adding Callback Functions to an Application

An application can register callback functions with the capture window to have it notify the application when the status changes, when errors occur, when video frame and audio buffers become available, and to yield during streaming capture.

The following example creates a capture window and registers status, error, video stream, and frame callback functions in the message processing loop of an application. It also includes a sample statement for disabling a callback function. Subsequent examples describe the status, error, and frame callback functions.

case WM_CREATE:

{

    char    achDeviceName[80] ;

    char    achDeviceVersion[100] ;

    char    achBuffer[100] ;

    WORD    wDriverCount = 0 ;

    WORD    wIndex ;

    WORD    wError ;

    HMENU   hMenu ;

    // Create the capture window.

    ghWndCap = capCreateCaptureWindow((LPSTR)"Capture Window",

        WS_CHILD | WS_VISIBLE, 0, 0, 160, 120, (HWND) hWnd, (int) 0);

    // Register the error callback function before connecting capture
    // driver.

    fpErrorCallback = MakeProcInstance((FARPROC)ErrorCallbackProc,
        ghInst);

    capSetCallbackOnError(ghWndCap, fpErrorCallback);

    // Register the status callback function.

    fpStatusCallback = MakeProcInstance((FARPROC)StatusCallbackProc,
        ghInst);

    capSetCallbackOnStatus(ghWndCap, fpStatusCallback);

    // Register the video-stream callback function.

    fpVideoCallback = MakeProcInstance((FARPROC)VideoCallbackProc,
        ghInst);

    capSetCallbackOnVideoStream(ghWndCap, fpVideoCallback);

    // Register the frame callback function.

    fpFrameCallback = MakeProcInstance((FARPROC)FrameCallbackProc,
        ghInst);

    capSetCallbackOnFrame(ghWndCap, fpFrameCallback);

// .

// . Connect to a capture driver

// .

break;

}

case WM_CLOSE:

{

// Use the following macro to disable the frame callback.

// Similar macros exist for disabling other callback functions.

//

// FreeProcInstance(fpFrameCallback);

// capSetCallbackOnFrame(hWndC, NULL);

break;

}


Creating a Status Callback Function

The following example is a simple status callback function.

// StatusCallbackProc: Status Callback Function

// hWnd:           capture window handle

// nID:            status code for the current status

// lpStatusText:   status text string for the current status

//

LRESULT FAR PASCAL StatusCallbackProc(HWND hWnd, int nID,
    LPSTR lpStatusText)

{

    if (!ghWndMain)

        return FALSE;

    if (nID == 0) {              // Zero means clear old status messages

        SetWindowText(ghWndMain, (LPSTR) gachAppName);

        return (LRESULT) TRUE;

    }

    // Show the status ID and status text...

    wsprintf(gachBuffer, "Status# %d: %s", nID, lpStatusText);

    SetWindowText(ghWndMain, (LPSTR)gachBuffer);

    return (LRESULT) TRUE;

}


Creating an Error Callback Function

The following example is a simple error callback function.

// ErrorCallbackProc: Error Callback Function

// hWnd:          capture window handle

// nErrID:        error code for the encountered error

// lpErrorText:   error text string for the encountered error

//

LRESULT FAR PASCAL ErrorCallbackProc(HWND hWnd, int nErrID,
    LPSTR lpErrorText)

{

    if (!ghWndMain)

        return FALSE;

    if (nErrID == 0)            // starting a new major function

        return TRUE;            // clear out old errors

    // Show the error identifier and text

    wsprintf(gachBuffer, "Error# %d", nErrID);

    MessageBox(hWnd, lpErrorText, gachBuffer,
        MB_OK | MB_ICONEXCLAMATION);

    return (LRESULT) TRUE;

}


Creating a Frame Callback Function

The following example is a simple frame callback function.

// FrameCallbackProc: Frame Callback Function

// Called whenever a new frame is captured but not streaming

// hWnd:       capture window handle

// lpVHdr:     long pointer to VideoHdr struct containing captured

//             frame information

//

LRESULT FAR PASCAL FrameCallbackProc(HWND hWnd, LPVIDEOHDR lpVHdr)

{

    if (!ghWndMain)

        return FALSE;

    wsprintf(gachBuffer, "Preview frame# %ld ", gdwFrameNum++);

    SetWindowText(ghWndMain, (LPSTR)gachBuffer);

    return (LRESULT) TRUE ;

}


Video Capture Reference

This section describes the functions, messages and macros, and structures associated with the AVICap window class. These elements are grouped as follows.

Basic Capture Operations

capCreateCaptureWindow
WM_CAP_ABORT
WM_CAP_DRIVER_CONNECT
WM_CAP_SEQUENCE
WM_CAP_STOP

Capture Windows

CAPSTATUS
capGetDriverDescription
WM_CAP_DRIVER_CONNECT
WM_CAP_DRIVER_DISCONNECT
WM_CAP_GET_STATUS

Capture Drivers

CAPDRIVERCAPS
WM_CAP_DRIVER_GET_CAPS
WM_CAP_DRIVER_GET_NAME
WM_CAP_DRIVER_GET_VERSION
WM_CAP_GET_AUDIOFORMAT
WM_CAP_GET_VIDEOFORMAT
WM_CAP_SET_AUDIOFORMAT
WM_CAP_SET_VIDEOFORMAT

Capture Driver Preview and Overlay Modes

WM_CAP_SET_OVERLAY
WM_CAP_SET_PREVIEW
WM_CAP_SET_PREVIEWRATE
WM_CAP_SET_SCALE
WM_CAP_SET_SCROLL

Capture Driver Video Dialog Boxes

WM_CAP_DLG_VIDEOCOMPRESSION
WM_CAP_DLG_VIDEODISPLAY
WM_CAP_DLG_VIDEOFORMAT
WM_CAP_DLG_VIDEOSOURCE

Audio Format

WM_CAP_GET_AUDIOFORMAT
WM_CAP_SET_AUDIOFORMAT

Video Capture Settings

CAPTUREPARMS
WM_CAP_GET_SEQUENCE_SETUP
WM_CAP_SET_SEQUENCE_SETUP

Capture File and Buffers

CAPTUREPARMS
WM_CAP_FILE_ALLOCATE
WM_CAP_FILE_GET_CAPTURE_FILE
WM_CAP_FILE_SAVEAS
WM_CAP_FILE_SET_CAPTURE_FILE

Directly Using Capture Data

WM_CAP_SEQUENCE_NOFILE

Capture from MCI Device

WM_CAP_SET_MCI_DEVICE

Manual Frame Capture

WM_CAP_SINGLE_FRAME
WM_CAP_SINGLE_FRAME_CLOSE
WM_CAP_SINGLE_FRAME_OPEN

Still-Image Capture

WM_CAP_EDIT_COPY
WM_CAP_FILE_SAVEDIB
WM_CAP_GRAB_FRAME
WM_CAP_GRAB_FRAME_NOSTOP

Advanced Capture Options

WM_CAP_FILE_SET_INFOCHUNK
WM_CAP_GET_USER_DATA
WM_CAP_SET_USER_DATA

Working with Palettes

WM_CAP_EDIT_COPY
WM_CAP_PAL_AUTOCREATE
WM_CAP_PAL_MANUALCREATE
WM_CAP_PAL_OPEN
WM_CAP_PAL_PASTE
WM_CAP_PAL_SAVE

Yielding to Other Applications

WM_CAP_GET_SEQUENCE_SETUP
WM_CAP_SET_CALLBACK_YIELD
WM_CAP_SET_SEQUENCE_SETUP

AVICap Callback Functions

capControlCallback
capErrorCallback
capStatusCallback
capVideoStreamCallback
capWaveStreamCallback
capYieldCallback
WM_CAP_SET_CALLBACK_CAPCONTROL
WM_CAP_SET_CALLBACK_ERROR
WM_CAP_SET_CALLBACK_FRAME
WM_CAP_SET_CALLBACK_STATUS
WM_CAP_SET_CALLBACK_VIDEOSTREAM
WM_CAP_SET_CALLBACK_WAVESTREAM
WM_CAP_SET_CALLBACK_YIELD


Video Capture Functions

An application uses the AVICap functions to create a capture window and to retrieve information about the capture driver. A capture window uses standard window styles.


capCreateCaptureWindow

HWND VFWAPI capCreateCaptureWindow(LPCSTR lpszWindowName,
    DWORD dwStyle, int x, int y, int nWidth, int nHeight,
    HWND hWnd, int nID);

Creates a capture window.

•	Returns a handle of the capture window if successful or NULL otherwise.

lpszWindowName

Null-terminated string containing the name used for the capture window.

dwStyle

Window styles used for the capture window. Window styles are described with the CreateWindowEx function.

x and y

The x- and y-coordinates of the upper left corner of the capture window.

nWidth and nHeight

Width and height of the capture window.

hWnd

Handle of the parent window.

nID

Window identifier.


capControlCallback

LRESULT CALLBACK capControlCallback(HWND hWnd, int nState);

Callback function used for precision control to begin and end streaming capture. The capControlCallback callback function is a placeholder for the application-supplied function name.

•	When nState is set to CONTROLCALLBACK_PREROLL, this callback function must return TRUE to start capture or FALSE to abort it. When nState is set to CONTROLCALLBACK_CAPTURING, this callback function must return TRUE to continue capture or FALSE to end it.

hWnd

Handle of the capture window associated with the callback function.

nState

Current state of the capture operation. The CONTROLCALLBACK_PREROLL value is sent initially to enable prerolling of the video sources and to return control to the capture application at the exact moment recording is to begin. The CONTROLCALLBACK_CAPTURING value is sent once per captured frame to indicate that streaming capture is in progress and to enable the application to end capture.

The first message sent to the callback procedure sets the nState parameter to CONTROLCALLBACK_PREROLL after allocating all buffers and all other capture preparations are complete.


capGetDriverDescription

BOOL VFWAPI capGetDriverDescription(WORD wDriverIndex,
    LPSTR lpszName, INT cbName, LPSTR lpszVer, INT cbVer);

Retrieves the version description of the capture driver.

•	Returns TRUE if successful or FALSE otherwise.

wDriverIndex

Index of the capture driver. The index can range from 0 through 9.

Plug-and-Play capture drivers are enumerated first, followed by capture drivers listed in the registry, which are then followed by capture drivers listed in SYSTEM.INI.

lpszName

Address of a buffer containing a null-terminated string corresponding to the capture driver name.

cbName

Length, in bytes, of the buffer pointed to by lpszName.

lpszVer

Address of a buffer containing a null-terminated string corresponding to the description of the capture driver.

cbVer

Length, in bytes, of the buffer pointed to by lpszVer.

If the information description is longer than its buffer, the description is truncated. The returned string is always null-terminated. If a buffer size is zero, its corresponding description is not copied.


capErrorCallback

LRESULT CALLBACK capErrorCallback(HWND hWnd, int nID, LPCSTR lpsz);

Error callback function used with video capture. The capErrorCallback error callback function is a placeholder for the application-supplied function name.

hWnd

Handle of the capture window associated with the callback function.

nID

Error identification number.

lpsz

Address of a textual description of the returned error.

A message identifier of zero indicates a new operation is starting and the callback function should clear the current error.


capStatusCallback

LRESULT CALLBACK capStatusCallback(HWND hWnd, int nID, LPCSTR lpsz);

Status callback function used with video capture. The capStatusCallback status callback function is a placeholder for the application-supplied function name.

hWnd

Handle of the capture window associated with the callback function.

nID

Message identification number.

lpsz

Address of a textual description of the returned status.

During capture operations, the first message sent to the callback function is always IDS_CAP_BEGIN and the last is always IDS_CAP_END. A message identifier of zero indicates a new operation is starting and the callback function should clear the current status.


capVideoStreamCallback

LRESULT CALLBACK capVideoStreamCallback(HWND hWnd, LPVIDEOHDR lpVHdr);

Callback function used with streaming capture to optionally process a frame of captured video. The capVideoStreamCallback callback function is a placeholder for the application-supplied function name.

hWnd

Handle of the capture window associated with the callback function.

lpVHdr

Address of a VIDEOHDR structure containing information about the captured frame.

The capture window calls a videostream callback function when a video buffer is marked done by the capture driver. When capturing to disk, this will preceed the disk write operation.


capWaveStreamCallback

LRESULT CALLBACK capWaveStreamCallback(HWND hWnd, LPWAVEHDR lpWHdr);

Callback function used with streaming capture to optionally process buffers of audio data. The capWaveStreamCallback callback function is a placeholder for the application-supplied function name.

hWnd

Handle of the capture window associated with the callback function.

lpWHdr

Address of a WAVEHDR structure containing information about the captured audio data.

The capture window calls a wavestream callback function when an audio buffer is marked done by the waveform-audio driver. When capturing to disk, this will preceed the disk write operation.


capYieldCallback

LRESULT CALLBACK capYieldCallback(HWND hWnd);

Yield callback function used with video capture. The capYieldCallback yield callback function is a placeholder for the application-supplied function name.

hWnd

Handle of the capture window associated with the callback function.

The capture window calls the yield callback function at least once for every captured video frame, but the exact rate depends on the frame rate and the overhead of the capture driver and disk.


Video Capture Messages and Macros

Applications communicate with capture windows through messages. AVICap macros provide a shorthand method of sending these messages, and they isolate your application from the SendMessage function. AVICap macros are identified with the prefix cap. Definitions of the AVICap macros are included with the message definitions.


WM_CAP_ABORT

WM_CAP_ABORT

wParam = (WPARAM) 0;

lParam = 0L;

// Corresponding macro

capCaptureAbort(hwnd);

Stops the capture operation. In the case of step capture, the image data collected up to the point of the WM_CAP_ABORT message will be retained in the capture file, but audio will not be captured.

•	Returns TRUE if successful or FALSE otherwise.

hwnd

Handle of a capture window.

The capture operation must yield to use this message.

Use the WM_CAP_STOP message to halt step capture at the current position, and then capture audio.


WM_CAP_DLG_VIDEOCOMPRESSION

WM_CAP_DLG_VIDEOCOMPRESSION

wParam = (WPARAM) 0;

lParam = 0L;

// Corresponding macro

capDlgVideoCompression(hwnd);

Displays a dialog box in which the user can select a compressor to use during the capture process. The list of available compressors can vary with the video format selected in the capture driver's Video Format dialog box.

•	Returns TRUE if successful or FALSE otherwise.

hwnd

Handle of a capture window.

Use this message with capture drivers that provide frames only in the BI_RGB format. This message is most useful in the step capture operation to combine capture and compression in a single operation. Compressing frames with a software compressor as part of a real-time capture operation is most likely too time-consuming to perform.

Compression does not affect the frames copied to the clipboard.


WM_CAP_DLG_VIDEODISPLAY

WM_CAP_DLG_VIDEODISPLAY

wParam = (WPARAM) 0;

lParam = 0L;

// Corresponding macro

capDlgVideoDisplay(hwnd);

Displays a dialog box in which the user can set or adjust the video output. This dialog box might contain controls that affect the hue, contrast, and brightness of the displayed image, as well as key color alignment.

•	Returns TRUE if successful or FALSE otherwise.

hwnd

Handle of a capture window.

The controls in this dialog box do not affect digitized video data; they affect only the output or redisplay of the video signal.

The Video Display dialog box is unique for each capture driver. Some capture drivers might not support a Video Display dialog box. Applications can determine if the capture driver supports this message by checking the fHasDlgVideoDisplay member of CAPDRIVERCAPS.


WM_CAP_DLG_VIDEOFORMAT

WM_CAP_DLG_VIDEOFORMAT

wParam = (WPARAM) 0;

lParam = 0L;

// Corresponding macro

capDlgVideoFormat(hwnd)

Displays a dialog box in which the user can select the video format. The Video Format dialog box might be used to select image dimensions, bit depth, and hardware compression options.

•	Returns TRUE if successful or FALSE otherwise.

hwnd

Handle of a capture window.

After this message returns, applications might need to update the CAPSTATUS structure because the user might have changed the image dimensions.

The Video Format dialog box is unique for each capture driver. Some capture drivers might not support a Video Format dialog box. Applications can determine if the capture driver supports this message by checking the fHasDlgVideoFormat member of CAPDRIVERCAPS.


WM_CAP_DLG_VIDEOSOURCE

WM_CAP_DLG_VIDEOSOURCE

wParam = (WPARAM) 0;

lParam = 0L;

// Corresponding macro

capDlgVideoSource(hwnd);

Displays a dialog box in which the user can control the video source. The Video Source dialog box might contain controls that select input sources; alter the hue, contrast, brightness of the image; and modify the video quality before digitizing the images into the frame buffer.

•	Returns TRUE if successful or FALSE otherwise.

hwnd

Handle of a capture window.

The Video Source dialog box is unique for each capture driver. Some capture drivers might not support a Video Source dialog box. Applications can determine if the capture driver supports this message by checking the fHasDlgVideoSource member of the CAPDRIVERCAPS structure.


WM_CAP_DRIVER_CONNECT

WM_CAP_DRIVER_CONNECT

wParam = (WPARAM) (iIndex);

lParam = 0L;

// Corresponding macro

capDriverConnect(hwnd, iIndex);

Connects a capture window to a capture driver.

•	Returns TRUE if successful or FALSE if the specified capture driver cannot be connected to the capture window.

iIndex

Index of the capture driver. The index can range from 0 through 9.

hwnd

Handle of a capture window.

Connecting a capture driver to a capture window automatically disconnects any previously connected capture driver.


WM_CAP_DRIVER_DISCONNECT

WM_CAP_DRIVER_DISCONNECT

wParam = (WPARAM) 0;

lParam = 0L;

// Corresponding macro

capDriverDisconnect(hwnd);

Disconnects a capture driver from a capture window.

•	Returns TRUE if successful or FALSE if the capture window is not connected to a capture driver.


WM_CAP_DRIVER_GET_CAPS

WM_CAP_DRIVER_GET_CAPS

wParam = (WPARAM) (wSize);

lParam = (LPARAM) (LPVOID) (LPCAPDRIVERCAPS) (psCaps);

// Corresponding macro

capDriverGetCaps(hwnd, psCaps, wSize);

Returns the hardware capabilities of the capture driver currently connected to a  capture window.

•	Returns TRUE if successful or FALSE if the capture window is not connected to a capture driver.

hwnd

Handle of a capture window.

wSize

Size, in bytes, of the structure referenced by s.

psCaps

Address of the CAPDRIVERCAPS structure to contain the hardware capabilities.

The capabilities returned in CAPDRIVERCAPS are constant for a given capture driver. Applications need to retrieve this information once when the capture driver is first connected to a capture window.


WM_CAP_DRIVER_GET_NAME

WM_CAP_DRIVER_GET_NAME

wParam = (WPARAM) (wSize);

lParam = (LPARAM) (LPVOID) (LPSTR) (szName);

// Corresponding macro

capDriverGetName(hwnd, szName, wSize);

Returns the name of the capture driver connected to the capture window.

•	Returns TRUE if successful or FALSE if the capture window is not connected to a capture driver.

hwnd

Handle of a capture window.

wSize

Size, in bytes, of the buffer referenced by szName.

szName

Address of an application-defined buffer used to return the device name as a null-terminated string.

The name is a text string retrieved from the driver's resource area. Applications should allocate approximately 80 bytes for this string. If the driver does not contain a name resource, the full path name of the driver listed in the registry or in the SYSTEM.INI file is returned.


WM_CAP_DRIVER_GET_VERSION

WM_CAP_DRIVER_GET_VERSION

wParam = (WPARAM) (wSize);

lParam = (LPARAM) (LPVOID) (LPSTR) (szVer);

// Corresponding macro

capDriverGetVersion(hwnd, szVer, wSize);

Returns the version information of the capture driver connected to a capture window.

•	Returns TRUE if successful or FALSE if the capture window is not connected to a capture driver.

wSize

Size, in bytes, of the application-defined buffer referenced by szVer.

szVer

Address of an application-defined buffer used to return the version information as a null-terminated string.

The version information is a text string retrieved from the driver's resource area. Applications should allocate approximately 40 bytes for this string. If version information is not available, a NULL string is returned.


WM_CAP_EDIT_COPY

WM_CAP_EDIT_COPY

wParam = (WPARAM) 0;

lParam = 0L;

// Corresponding macro

capEditCopy(hwnd);

Copies the contents of the video frame buffer and associated palette to the clipboard.

•	Returns TRUE if successful or FALSE otherwise.

hwnd

Handle of a capture window.


WM_CAP_FILE_ALLOCATE

WM_CAP_FILE_ALLOCATE

wParam = (WPARAM) 0;

lParam = (LPARAM) (DWORD) (dwSize);

// Corresponding macro

capFileAlloc(hwnd, dwSize);

Creates (preallocates) a capture file of a specified size.

•	Returns TRUE if successful or FALSE otherwise. Also, if an error occurs and an error callback function is set using the WM_CAP_SET_CALLBACK_ERROR message, the error callback function is called.

hwnd

Handle of a capture window.

dwSize

Size, in bytes, to create the capture file.

You can improve streaming capture performance significantly by preallocating a capture file large enough to store an entire video clip and by defragmenting the capture file before capturing the clip.


WM_CAP_FILE_GET_CAPTURE_FILE

WM_CAP_FILE_GET_CAPTURE_FILE

wParam = (WPARAM) (wSize);

lParam = (LPARAM) (LPVOID) (LPSTR) (szName);

// Corresponding macro

capFileGetCaptureFile(hwnd, szName, wSize);

Returns the name of the current capture file.

•	Returns TRUE if successful or FALSE otherwise.

wSize

Size, in bytes, of the application-defined buffer referenced by szName.

szName

Address of an application-defined buffer used to return the name of the capture file as a null-terminated string.

The default capture filename is C:\CAPTURE.AVI.


WM_CAP_FILE_SAVEAS

WM_CAP_FILE_SAVEAS

wParam = (WPARAM) 0;

lParam = (LPARAM) (LPVOID) (LPSTR) (szName);

// Corresponding macro

capFileSaveAs(hwnd, szName);

Copies the contents of the capture file to another file.

•	Returns TRUE if successful or FALSE otherwise. Also, if an error occurs and an error callback function is set using the WM_CAP_SET_CALLBACK_ERROR message, the error callback function is called.

hwnd

Handle of a capture window.

szName

Address of the null-terminated string that contains the name of the destination file used to copy the file.

This message does not change the name or contents of the current capture file.

If the copy operation is unsuccessful due to a disk full error, the destination file is automatically deleted.

Typically, a capture file is preallocated for the largest capture segment anticipated and only a portion of it might be used to capture data. This message copies only the portion of the file containing the capture data.


WM_CAP_FILE_SAVEDIB

WM_CAP_FILE_SAVEDIB

wParam = (WPARAM) 0;

lParam = (LPARAM) (LPVOID) (LPSTR) (szName);

// Corresponding macro

capFileSaveDIB(hwnd, szName);

Copies the current frame to a DIB file.

•	Returns TRUE if successful or FALSE otherwise. Also, if an error occurs and an error callback function is set using the WM_CAP_SET_CALLBACK_ERROR message, the error callback function is called.

hwnd

Handle of a capture window.

szName

Address of the null-terminated string that contains the name of the destination DIB file.

If the capture driver supplies frames in a compressed format, this call attempts to decompress the frame before writing the file.


WM_CAP_FILE_SET_CAPTURE_FILE

WM_CAP_FILE_SET_CAPTURE_FILE

wParam = (WPARAM) 0;

lParam = (LPARAM) (LPVOID) (LPSTR) (szName);

// Corresponding macro

capFileSetCaptureFile(hwnd, szName);

Names the file used for video capture.

•	Returns TRUE if successful or FALSE if the filename is invalid, or if streaming or single-frame capture is in progress.

hwnd

Handle of a capture window.

szName

Address of the null-terminated string that contains the name of the capture file to use.

This message stores the filename in an internal structure. It does not create, allocate, or open the specified file. The default capture filename is C:\CAPTURE.AVI.


WM_CAP_FILE_SET_INFOCHUNK

WM_CAP_FILE_SET_INFOCHUNK

wParam = (WPARAM)0;

lParam = (LPARAM) (LPCAPINFOCHUNK) (lpInfoChunk);

// Corresponding macro

capFileSetInfoChunk(hwnd, lpInfoChunk);

Sets and clears information chunks. Information chunks can be inserted in an AVI file during capture to embed text strings or custom data.

•	Returns TRUE if successful or FALSE otherwise. Also, if an error occurs and an error callback function is set using the WM_CAP_SET_CALLBACK_ERROR message, the error callback function is called.

hwnd

Handle of a capture window.

lpInfoChunk

Address of a CAPINFOCHUNK structure defining the information chunk to be created or deleted.

Multiple registered information chunks can be added to an AVI file. After an information chunk is set, it continues to be added to subsequent capture files until either the entry is cleared or all information chunk entries are cleared. To clear a single entry, specify the information chunk in the fccInfoID member and NULL in the lpData member of the CAPINFOCHUNK structure. To clear all entries, specify NULL in fccInfoID.


WM_CAP_GET_AUDIOFORMAT

WM_CAP_GET_AUDIOFORMAT

wParam = (WPARAM) (wSize);

lParam = (LPARAM) (LPVOID) (LPWAVEFORMATEX) (psAudioFormat);

// Corresponding macros

capGetAudioFormat(hwnd, psAudioFormat, wSize);

capGetAudioFormatSize(hwnd);

Obtains the audio format or the size of the audio format.

•	Returns the size, in bytes, of the audio format.

hwnd

Handle of a capture window.

wSize

Size, in bytes, of the structure referenced by s.

psAudioFormat

Address of a WAVEFORMATEX structure, or NULL. If the value is NULL, the size, in bytes, required to hold the WAVEFORMATEX structure is returned.

Because compressed audio formats vary in size requirements applications must first retrieve the size, then allocate memory, and finally request the audio format data.


WM_CAP_GET_MCI_DEVICE

WM_CAP_GET_MCI_DEVICE

wParam = (WPARAM) (wSize);

lParam = (LPARAM) (LPVOID) (LPSTR) (szName);

// Corresponding macro

capGetMCIDeviceName(hwnd, szName, wSize);

Retrieves the name of an MCI device previously set with the WM_CAP_SET_MCI_DEVICE message.

•	Returns TRUE if successful or FALSE otherwise.

hwnd

Handle of a capture window.

wSize

Length, in bytes, of the buffer referenced by szName .

szName

Address of a null-terminated string that contains the MCI device name.


WM_CAP_GET_SEQUENCE_SETUP

WM_CAP_GET_SEQUENCE_SETUP

wParam = (WPARAM) (wSize);

lParam = (LPARAM) (LPVOID) (LPCAPTUREPARMS) (s);

// Corresponding macro

capCaptureGetSetup(hwnd, s, wSize);

Retrieves the current settings of the streaming capture parameters.

•	Returns TRUE if successful or FALSE otherwise.

hwnd

Handle of a capture window.

wSize

Size, in bytes, of the structure referenced by s.

s

Address of a CAPTUREPARMS structure.

For information about the parameters used to control streaming capture, see the CAPTUREPARMS structure.


WM_CAP_GET_STATUS

WM_CAP_GET_STATUS

wParam = (WPARAM) (wSize);

lParam = (LPARAM) (LPVOID) (LPCAPSTATUS) (s);

// Corresponding macro

capGetStatus(hwnd, s, wSize);

Retrieves the status of the capture window.

•	Returns TRUE if successful or FALSE if the capture window is not connected to a capture driver.

hwnd

Handle of a capture window.

wSize

Size, in bytes, of the structure referenced by s.

s

Address of a CAPSTATUS structure.

The CAPSTATUS structure contains the current state of the capture window. Since this state is dynamic and changes in response to various messages, the application should initialize this structure after sending the WM_CAP_DLG_VIDEOFORMAT message (or using the capDlgVideoFormat macro) and whenever it needs to enable menu items or determine the actual state of the window.


WM_CAP_GET_USER_DATA

WM_CAP_GET_USER_DATA

wParam = (WPARAM) 0;

lParam = 0L;

// Corresponding macro

capGetUserData(hwnd);

Retrieves a LONG data value associated with a capture window.

•	Returns a value previously saved by using the WM_CAP_SET_USER_DATA message.

hwnd

Handle of a capture window.


WM_CAP_GET_VIDEOFORMAT

WM_CAP_GET_VIDEOFORMAT

wParam = (WPARAM) (wSize);

lParam = (LPARAM) (LPVOID) (psVideoFormat);

// Corresponding macros

capGetVideoFormat(hwnd, psVideoFormat, wSize);

capGetVideoFormatSize(hwnd);

Retrieves a copy of the video format in use or the size required for the video format.

•	Returns the size, in bytes, of the video format or zero if the capture window is not connected to a capture driver. For video formats that require a palette, the current palette is also returned.

hwnd

Handle of a capture window.

wSize

Size, in bytes, of the structure referenced by s.

psVideoFormat

Address of a BITMAPINFO structure. You can also specify NULL to retrieve the number of bytes needed by BITMAPINFO.

Because compressed video formats vary in size requirements applications must first retrieve the size, then allocate memory, and finally request the video format data.


WM_CAP_GRAB_FRAME

WM_CAP_GRAB_FRAME

wParam = (WPARAM)0;

lParam = (LPARAM)0L;

// Corresponding macro

capGrabFrame(hwnd);

Retrieves and displays a single frame from the capture driver. After capture, overlay and preview are disabled.

•	Returns TRUE if successful or FALSE otherwise.

hwnd

Handle of a capture window.

For information about installing callback functions, see the WM_CAP_SET_CALLBACK_ERROR and WM_CAP_SET_CALLBACK_FRAME messages.


WM_CAP_GRAB_FRAME_NOSTOP

WM_CAP_GRAB_FRAME_NOSTOP

wParam = (WPARAM) 0;

lParam = 0L;

// Corresponding macro

capGrabFrameNoStop(hwnd);

Fills the frame buffer with a single uncompressed frame from the capture device and displays it. Unlike with the WM_CAP_GRAB_FRAME message, the state of overlay or preview is not altered by this message.

•	Returns TRUE if successful or FALSE otherwise.

hwnd

Handle of a capture window.

For information about installing callback functions, see the WM_CAP_SET_CALLBACK_ERROR and WM_CAP_SET_CALLBACK_FRAME messages.


WM_CAP_PAL_AUTOCREATE

WM_CAP_PAL_AUTOCREATE

wParam = (WPARAM) (iFrames);

lParam = (LPARAM) (DWORD) (iColors);

// Corresponding macro

capPaletteAuto(hwnd, iFrames, iColors);

Requests that the capture driver sample video frames and automatically create a new palette.

•	Returns TRUE if successful or FALSE otherwise. Also, if an error occurs and an error callback function is set using the WM_CAP_SET_CALLBACK_ERROR message, the error callback function is called.

hwnd

Handle of a capture window.

iFrames

Number of frames to sample.

iColors

Number of colors in the palette. The maximum value for this parameter is 256.

The sampled video sequence should include all the colors you want in the palette. To obtain the best palette, you might have to sample the whole sequence rather than a portion of it.


WM_CAP_PAL_MANUALCREATE

WM_CAP_PAL_MANUALCREATE

wParam = (WPARAM) (fGrab);

lParam = (LPARAM) (DWORD) (iColors);

// Corresponding macro

capPaletteManual(hwnd, fGrab, iColors);

Requests that the capture driver manually sample video frames and create a new palette.

•	Returns TRUE if successful or FALSE otherwise. Also, if an error occurs and an error callback function is set using the WM_CAP_SET_CALLBACK_ERROR message, the error callback function is called.

hwnd

Handle of a capture window.

fGrab

Palette histogram flag. Set this parameter to TRUE for each frame included in creating the optimal palette. After the last frame has been collected, set this parameter to FALSE to calculate the optimal palette and send it to the capture driver.

iColors

Number of colors in the palette. The maximum value for this parameter is 256. This value is used only during collection of the first frame in a sequence.


WM_CAP_PAL_OPEN

WM_CAP_PAL_OPEN

wParam = (WPARAM) 0;

lParam = (LPARAM) (LPVOID) (LPSTR) (szName);

// Corresponding macro

capPaletteOpen(hwnd, szName);

Loads a new palette from a palette file and passes it to a capture driver. Palette files typically use the filename extension .PAL. A capture driver uses a palette when required by the specified digitized image format.

•	Returns TRUE if successful or FALSE otherwise. Also, if an error occurs and an error callback function is set using the WM_CAP_SET_CALLBACK_ERROR message, the error callback function is called.

hwnd

Handle of a capture window.

szName

Address of a null-terminated string containing the palette filename.


WM_CAP_PAL_PASTE

WM_CAP_PAL_PASTE

wParam = (WPARAM) 0;

lParam = 0L;

// Corresponding macro

capPalettePaste(hwnd);

Copies the palette from the clipboard and passes it to a capture driver.

•	Returns TRUE if successful or FALSE otherwise. Also, if an error occurs and an error callback function is set using the WM_CAP_SET_CALLBACK_ERROR message, the error callback function is called.

hwnd

Handle of a capture window.

A capture driver uses a palette when required by the specified digitized video format.


WM_CAP_PAL_SAVE

WM_CAP_PAL_SAVE

wParam = (WPARAM) 0;

lParam = (LPARAM) (LPVOID) (LPSTR) (szName);

// Corresponding macro

capPaletteSave(hwnd, szName);

Saves the current palette to a palette file. Palette files typically use the filename extension .PAL.

•	Returns TRUE if successful or FALSE otherwise. Also, if an error occurs and an error callback function is set using the WM_CAP_SET_CALLBACK_ERROR message, the error callback function is called.

hwnd

Handle of a capture window.

szName

Address of a null-terminated string containing the palette filename.


WM_CAP_SEQUENCE

WM_CAP_SEQUENCE

wParam = (WPARAM) 0;

lParam = 0L;

// Corresponding macro

capCaptureSequence(hwnd);

Initiates streaming video and audio capture to a file.

•	Returns TRUE if successful or FALSE otherwise. Also, if an error occurs and an error callback function is set using the WM_CAP_SET_CALLBACK_ERROR message, the error callback function is called.

hwnd

Handle of a capture window.

If you want to alter the parameters controlling streaming capture, use the WM_CAP_SET_SEQUENCE_SETUP message prior to starting the capture.

By default, the capture window does not allow other applications to continue running during capture. To override this, either set the fYield member of the CAPTUREPARMS structure to TRUE, or install a yield callback function.

During streaming capture, the capture window can optionally issue notifications to your application of specific types of conditions. To install callback procedures for these notifications, use the following messages:

WM_CAP_SET_CALLBACK_ERROR
WM_CAP_SET_CALLBACK_STATUS
WM_CAP_SET_CALLBACK_YIELD
WM_CAP_SET_CALLBACK_VIDEOSTREAM
WM_CAP_SET_CALLBACK_WAVESTREAM


WM_CAP_SEQUENCE_NOFILE

WM_CAP_SEQUENCE_NOFILE

wParam = (WPARAM) 0;

lParam = 0L;

// Corresponding macro

capCaptureSequenceNoFile(hwnd);

Initiates streaming video capture without writing data to a file.

•	Returns TRUE if successful or FALSE otherwise.

hwnd

Handle of a capture window.

This message is useful in conjunction with video stream or waveform-audio stream callback functions that let your application use the video and audio data directly.

If you want to alter the parameters controlling streaming capture, use the WM_CAP_SET_SEQUENCE_SETUP message prior to starting the capture.

By default, the capture window does not allow other applications to continue running during capture. To override this, either set the fYield member of the CAPTUREPARMS structure to TRUE, or install a yield callback function.

During streaming capture, the capture window can optionally issue notifications to your application of specific types of conditions. To install callback procedures for these notifications, use the following messages:

WM_CAP_SET_CALLBACK_ERROR
WM_CAP_SET_CALLBACK_STATUS
WM_CAP_SET_CALLBACK_YIELD
WM_CAP_SET_CALLBACK_VIDEOSTREAM
WM_CAP_SET_CALLBACK_WAVESTREAM


WM_CAP_SET_AUDIOFORMAT

WM_CAP_SET_AUDIOFORMAT

wParam = (WPARAM) (wSize);

lParam = (LPARAM) (LPVOID) (LPWAVEFORMATEX) (psAudioFormat);

// Corresponding macro

capSetAudioFormat(hwnd, psAudioFormat, wSize);

Sets the audio format to use when performing streaming or step capture.

•	Returns TRUE if successful or FALSE otherwise.

hwnd

Handle of a capture window.

wSize

Size, in bytes, of the structure referenced by s.

psAudioFormat

Address of a WAVEFORMATEX or PCMWAVEFORMAT structure that defines the audio format.


WM_CAP_SET_CALLBACK_CAPCONTROL

WM_CAP_SET_CALLBACK_CAPCONTROL

wParam = (WPARAM) 0;

lParam = (LPARAM) (LPVOID) (fpProc);

// Corresponding macro

capSetCallbackOnCapControl(hwnd, fpProc);

Sets a callback function in the application giving it precise recording control.

•	Returns TRUE if successful or FALSE if a streaming capture or a single-frame capture session is in progress.

hwnd

Handle of a capture window.

fpProc

Address of the callback function. Specify NULL for this parameter to disable a previously installed callback function.

A single callback function is used to give the application precise control over the moments that streaming capture begins and completes. The capture window first calls the procedure with nState set to CONTROLCALLBACK_PREROLL after all buffers have been allocated and all other capture preparations have finished. This gives the application the ability to preroll video sources, returning from the callback function at the exact moment recording is to begin. A return value of TRUE from the callback function continues capture, and a return value of FALSE aborts capture. After capture begins, this callback function will be called frequently with nState set to CONTROLCALLBACK_CAPTURING to allow the application to end capture by returning FALSE.


WM_CAP_SET_CALLBACK_ERROR

WM_CAP_SET_CALLBACK_ERROR

wParam = (WPARAM) 0;

lParam = (LPARAM) (LPVOID) (fpProc);

// Corresponding macro

capSetCallbackOnError(hwnd, fpProc);

Sets an error callback function in the client application. AVICap calls this procedure when errors occur.

•	Returns TRUE if successful or FALSE if streaming capture or a single-frame capture session is in progress.

hwnd

Handle of a capture window.

fpProc

Address of the error callback function. Specify NULL for this parameter to disable a previously installed error callback function.

Applications can optionally set an error callback function. If set, AVICap calls the error procedure in the following situations:

•	The disk is full.

•	A capture window cannot be connected with a capture driver.

•	A waveform-audio device cannot be opened.

•	The number of frames dropped during capture exceeds the specified percentage.

•	The frames cannot be captured due to vertical synchronization interrupt problems.


WM_CAP_SET_CALLBACK_FRAME

WM_CAP_SET_CALLBACK_FRAME

wParam = (WPARAM) 0;

lParam = (LPARAM) (LPVOID) (fpProc);

// Corresponding macro

capSetCallbackOnFrame(hwnd, fpProc);

Sets a preview callback function in the application. AVICap calls this procedure when the capture window captures preview frames.

•	Returns TRUE if successful or FALSE if streaming capture or a single-frame capture session is in progress.

hwnd

Handle of a capture window.

fpProc

Address of the preview callback function. Specify NULL for this parameter to disable a previously installed callback function.

The capture window calls the callback function before displaying preview frames. This allows an application to modify the frame if desired. This callback function is not used during streaming video capture.


WM_CAP_SET_CALLBACK_STATUS

WM_CAP_SET_CALLBACK_STATUS

wParam = (WPARAM) 0;

lParam = (LPARAM) (LPVOID) (fpProc);

// Corresponding macro

capSetCallbackOnStatus(hwnd, fpProc);

Sets a status callback function in the application. AVICap calls this procedure whenever the capture window status changes.

•	Returns TRUE if successful or FALSE if streaming capture or a single-frame capture session is in progress.

hwnd

Handle of a capture window.

fpProc

Address of the status callback function. Specify NULL for this parameter to disable a previously installed status callback function.

Applications can optionally set a status callback function. If set, AVICap calls this procedure in the following situations:

•	A capture session is completed.

•	A capture driver successfully connected to a capture window.

•	An optimal palette is created.

•	The number of captured frames is reported.


WM_CAP_SET_CALLBACK_VIDEOSTREAM

WM_CAP_SET_CALLBACK_VIDEOSTREAM

wParam = (WPARAM) 0;

lParam = (LPARAM) (LPVOID) (fpProc);

// Corresponding macro

capSetCallbackOnVideoStream(hwnd, fpProc);

Sets a callback function in the application. AVICap calls this procedure during streaming capture when a video buffer is filled.

•	Returns TRUE if successful or FALSE if streaming capture or a single-frame capture session is in progress.

hwnd

Handle of a capture window.

fpProc

Address of the video-stream callback function. Specify NULL for this parameter to disable a previously installed video-stream callback function.

The capture window calls the callback function before writing the captured frame to disk. This allows applications to modify the frame if desired.

If a video stream callback function is used for streaming capture, the procedure must be installed before starting the capture session and it must remain enabled for the duration of the session. It can be disabled after streaming capture ends.


WM_CAP_SET_CALLBACK_WAVESTREAM

WM_CAP_SET_CALLBACK_WAVESTREAM

wParam = (WPARAM) 0;

lParam = (LPARAM) (LPVOID) (fpProc);

// Corresponding macro

capSetCallbackOnWaveStream(hwnd, fpProc);

Sets a callback function in the application. AVICap calls this procedure during streaming capture when a new audio buffer becomes available.

•	Returns TRUE if successful or FALSE if streaming capture or a single-frame capture session is in progress.

hwnd

Handle of a capture window.

fpProc

Address of the wave stream callback function. Specify NULL for this parameter to disable a previously installed wave stream callback function.

The capture window calls the procedure before writing the audio buffer to disk. This allows applications to modify the audio buffer if desired.

If a wave stream callback function is used, it must be installed before starting the capture session and it must remain enabled for the duration of the session. It can be disabled after streaming capture ends.


WM_CAP_SET_CALLBACK_YIELD

WM_CAP_SET_CALLBACK_YIELD

wParam = (WPARAM) 0;

lParam = (LPARAM) (LPVOID) (fpProc);

// Corresponding macro

capSetCallbackOnYield(hwnd, fpProc);

Sets a callback function in the application. AVICap calls this procedure when the capture window yields during streaming capture.

•	Returns TRUE if successful or FALSE if streaming capture or a single-frame capture session is in progress.

hwnd

Handle of a capture window.

fpProc

Address of the yield callback function. Specify NULL for this parameter to disable a previously installed yield callback function.

Applications can optionally set a yield callback function. The yield callback function is called at least once for each video frame captured during streaming capture. If a yield callback function is installed, it will be called regardless of the state of the fYield member of the CAPTUREPARMS structure.

If the yield callback function is used, it must be installed before starting the capture session and it must remain enabled for the duration of the session. It can be disabled after streaming capture ends.

Applications typically perform some type of message processing in the callback function consisting of a PeekMessage, TranslateMessage, DispatchMessage loop, as in the message loop of a WinMain function. The yield callback function must also filter and remove messages that can cause reentrancy problems.

An application typically returns TRUE in the yield procedure to continue streaming capture. If a yield callback function returns FALSE, the capture window stops the capture process.


WM_CAP_SET_MCI_DEVICE

WM_CAP_SET_MCI_DEVICE

wParam = (WPARAM) 0;

lParam = (LPARAM) (LPVOID) (LPSTR) (szName);

// Corresponding macro

capSetMCIDeviceName(hwnd, szName);

Specifies the name of the MCI video device to be used to capture data.

•	Returns TRUE if successful or FALSE otherwise.

hwnd

Handle of a capture window.

szName

Address of a null-terminated string containing the name of the device.

This message stores the MCI device name in an internal structure. It does not open or access the device. The default device name is NULL.


WM_CAP_SET_OVERLAY

WM_CAP_SET_OVERLAY

wParam = (WPARAM) (BOOL) (f);

lParam = 0L;

// Corresponding macro

capOverlay(hwnd, f);

Enables or disables overlay mode. In overlay mode, video is displayed using hardware overlay.

•	Returns TRUE if successful or FALSE otherwise.

hwnd

Handle of a capture window.

f

Overlay flag. Specify TRUE for this parameter to enable overlay mode or FALSE to disable it.

Using an overlay does not require CPU resources.

The fHasOverlay member of the CAPDRIVERCAPS structure indicates whether the device is capable of overlay. The fOverlayWindow member of the CAPSTATUS structure indicates whether overlay mode is currently enabled.

Enabling overlay mode automatically disables preview mode.


WM_CAP_SET_PREVIEW

WM_CAP_SET_PREVIEW

wParam = (WPARAM) (BOOL) (f);

lParam = 0L;

// Corresponding macro

capPreview(hwnd, f);

Enables or disables preview mode. In preview mode, frames are transferred from the capture hardware to system memory and then displayed in the capture window using GDI functions.

•	Returns TRUE if successful or FALSE otherwise.

hwnd

Handle of a capture window.

f

Preview flag. Specify TRUE for this parameter to enable preview mode or FALSE to disable it.

The preview mode uses substantial CPU resources. Applications can disable preview or lower the preview rate when another application has the focus. The fLiveWindow member of the CAPSTATUS structure indicates if preview mode is currently enabled.

Enabling preview mode automatically disables overlay mode.


WM_CAP_SET_PREVIEWRATE

WM_CAP_SET_PREVIEWRATE

wParam = (WPARAM) (wMS);

lParam = 0L;

// Corresponding macro

capPreviewRate(hwnd, wMS);

Sets the frame display rate in preview mode.

•	Returns TRUE if successful or FALSE if the capture window is not connected to a capture driver.

hwnd

Handle of a capture window.

wMS

Rate, in milliseconds, at which new frames are captured and displayed.

The preview mode uses substantial CPU resources. Applications can disable preview or lower the preview rate when another application has the focus. During streaming video capture, the previewing task is lower priority than writing frames to disk, and preview frames are displayed only if no other buffers are available for writing.


WM_CAP_SET_SCALE

WM_CAP_SET_SCALE

wParam = (WPARAM) (BOOL)f;

lParam = 0L;

// Corresponding macro

capPreviewScale(hwnd, f);

Enables or disables scaling of the preview video images. If scaling is enabled, the captured video frame is stretched to the dimensions of the capture window.

•	Returns TRUE if successful or FALSE otherwise.

hwnd

Handle of a capture window.

f

Preview scaling flag. Specify TRUE for this parameter to stretch preview frames to the size of the capture window or FALSE to display them at their natural size.

Scaling preview images controls the immediate presentation of captured frames within the capture window. It has no effect on the size of the frames saved to file.

Scaling has no effect when using overlay to display video in the frame buffer.


WM_CAP_SET_SCROLL

WM_CAP_SET_SCROLL

wParam = (WPARAM) 0;

lParam = (LPARAM) (LPPOINT) (lpP);

// Corresponding macro

capSetScrollPos(hwnd, lpP);

Defines the portion of the video frame to display in the capture window. This message sets the upper left corner of the client area of the capture window to the coordinates of a specified pixel within the video frame.

•	Returns TRUE if successful or FALSE otherwise.

hwnd

Handle of a capture window.

lpP

Address to contain the desired scroll position.

The scroll position affects the image in both preview and overlay modes.


WM_CAP_SET_SEQUENCE_SETUP

WM_CAP_SET_SEQUENCE_SETUP

wParam = (WPARAM) (wSize);

lParam = (LPARAM) (LPVOID) (LPCAPTUREPARMS) (psCapParms);

// Corresponding macro

capCaptureSetSetup(hwnd, psCapParms, wSize);

Sets the configuration parameters used with streaming capture.

•	Returns TRUE if successful or FALSE otherwise.

hwnd

Handle of a capture window.

psCapParms

Address of a CAPTUREPARMS structure.

wSize

Size, in bytes, of the structure referenced by s.

For information about the parameters used to control streaming capture, see the CAPTUREPARMS structure.


WM_CAP_SET_USER_DATA

WM_CAP_SET_USER_DATA

wParam = (WPARAM) 0;

lParam = (LPARAM)lUser;

// Corresponding macro

capSetUserData(hwnd, lUser);

Associates a LONG data value with a capture window.

•	Returns TRUE if successful or FALSE if streaming capture is in progress.

hwnd

Handle of a capture window.

lUser

Data value to associate with a capture window.

Typically this message is used to point to a block of data associated with a capture window.


WM_CAP_SET_VIDEOFORMAT

WM_CAP_SET_VIDEOFORMAT

wParam = (WPARAM) (wSize);

lParam = (LPARAM) (LPVOID) (psVideoFormat);

// Corresponding macro

capSetVideoFormat(hwnd, psVideoFormat, wSize);

Sets the format of captured video data.

•	Returns TRUE if successful or FALSE otherwise.

hwnd

Handle of a capture window.

psVideoFormat

Address of a BITMAPINFO structure.

wSize

Size, in bytes, of the structure referenced by s.

Because video formats are device-specific, applications should check the return value from this function to determine if the format is accepted by the driver.


WM_CAP_SINGLE_FRAME

WM_CAP_SINGLE_FRAME

wParam = (WPARAM) 0;

lParam = 0L;

// Corresponding macro

capCaptureSingleFrame(hwnd);

Appends a single frame to a capture file that was opened using the WM_CAP_SINGLE_FRAME_OPEN message.

•	Returns TRUE if successful or FALSE otherwise.

hwnd

Handle of a capture window.


WM_CAP_SINGLE_FRAME_CLOSE

WM_CAP_SINGLE_FRAME_CLOSE

wParam = (WPARAM) 0;

lParam = 0L;

// Corresponding macro

capCaptureSingleFrameClose(hwnd);

Closes the capture file opened by the WM_CAP_SINGLE_FRAME_OPEN message.

•	Returns TRUE if successful or FALSE otherwise.

hwnd

Handle of a capture window.

For information about installing callback functions, see the WM_CAP_SET_CALLBACK_ERROR and WM_CAP_SET_CALLBACK_FRAME messages.


WM_CAP_SINGLE_FRAME_OPEN

WM_CAP_SINGLE_FRAME_OPEN

wParam = (WPARAM) 0;

lParam = 0L;

// Corresponding macro

capCaptureSingleFrameOpen(hwnd);

Opens the capture file for single-frame capturing. Any previous information in the capture file is overwritten.

•	Returns TRUE if successful or FALSE otherwise.

hwnd

Handle of a capture window.

For information about installing callback functions, see the WM_CAP_SET_CALLBACK_ERROR and WM_CAP_SET_CALLBACK_FRAME messages.


WM_CAP_STOP

WM_CAP_STOP

wParam = (WPARAM) 0;

lParam = 0L;

// Corresponding macro

capCaptureStop(hwnd);

Stops the capture operation.

In step frame capture, the image data that was collected before this message was sent is retained in the capture file. An equivalent duration of audio data is also retained in the capture file if audio capture was enabled.

•	Returns TRUE if successful or FALSE otherwise.

hwnd

Handle of a capture window.

The capture operation must yield to use this message. Use the WM_CAP_ABORT message to abandon the current capture operation.


Video Capture Structures

The AVICap functions, messages, and macros use structures to describe, configure, and control the capture operation. Some of the structures described in this section, such as BITMAPINFOHEADER, are borrowed from other Win32 subsystems; others are specific to AVICap.


CAPDRIVERCAPS

typedef struct {

UINT   wDeviceIndex;

BOOL   fHasOverlay;

BOOL   fHasDlgVideoSource;

BOOL   fHasDlgVideoFormat;

BOOL   fHasDlgVideoDisplay;

BOOL   fCaptureInitialized;

BOOL   fDriverSuppliesPalettes;

HANDLE hVideoIn;

HANDLE hVideoOut;

HANDLE hVideoExtIn;

HANDLE hVideoExtOut;

} CAPDRIVERCAPS;

Defines the capabilities of the capture driver.

An application should use the WM_CAP_DRIVER_GET_CAPS message or capDriverGetCaps macro to place a copy of the driver capabilities in a CAPDRIVERCAPS structure whenever the application connects a capture window to a capture driver.

wDeviceIndex

Index of the capture driver. An index value can range from 0 to 9.

fHasOverlay

Video-overlay flag. The value of this member is TRUE if the device supports video overlay.

fHasDlgVideoSource

Video source dialog flag. The value of this member is TRUE if the device supports a dialog box for selecting and controlling the video source.

fHasDlgVideoFormat

Video format dialog flag. The value of this member is TRUE if the device supports a dialog box for selecting the video format.

fHasDlgVideoDisplay

Video display dialog flag. The value of this member is TRUE if the device supports a dialog box for controlling the redisplay of video from the capture frame buffer.

fCaptureInitialized

Capture initialization flag. The value of this member is TRUE if a capture device has been successfully connected.

fDriverSuppliesPalettes

Driver palette flag. The value of this member is TRUE if the driver can create palettes.

hVideoIn

Not used in Win32 applications.

hVideoOut

Not used in Win32 applications.

hVideoExtIn

Not used in Win32 applications.

hVideoExtOut

Not used in Win32 applications.


CAPINFOCHUNK

typedef struct {

FOURCC fccInfoID;

LPVOID lpData;

LONG   cbData;

} CAPINFOCHUNK;

Contains parameters that can be used to define an information chunk within an AVI capture file. The WM_CAP_FILE_SET_INFOCHUNK message or capSetInfoChunk macro is used to send a CAPINFOCHUNK structure to a capture window.

fccInfoID

Four-character code that identifies the representation of the chunk data. If this value is NULL and lpData is NULL, all accumulated information chunks are deleted.

lpData

Address of the data. If this value is NULL, all fccInfoID information chunks are deleted.

cbData

Size, in bytes, of the data pointed to by lpData. If lpData specifies a
null-terminated string, use the string length incremented by one to save the NULL with the string.


CAPSTATUS

typedef struct {

UINT     uiImageWidth;                 // image width, in pixels

UINT     uiImageHeight;                // image height, in pixels

BOOL     fLiveWindow;                  // see below

BOOL     fOverlayWindow;               // see below

BOOL     fScale;                       // see below

POINT    ptScroll;                     // see below

BOOL     fUsingDefaultPalette;         // see below

BOOL     fAudioHardware;               // see below

BOOL     fCapFileExists;               // see below

DWORD    dwCurrentVideoFrame;          // see below

DWORD    dwCurrentVideoFramesDropped;  // see below

DWORD    dwCurrentWaveSamples;         // see below

DWORD    dwCurrentTimeElapsedMS;       // see below

HPALETTE hPalCurrent;                  // handle of current pallette

BOOL     fCapturingNow;                // see below

DWORD    dwReturn;                     // see below

UINT     wNumVideoAllocated;           // see below

UINT     wNumAudioAllocated;           // see below

} CAPSTATUS;

Defines the current state of the capture window.

fLiveWindow

Live window flag. The value of this member is TRUE if the window is displaying video using the preview method.

fOverlayWindow

Overlay window flag. The value of this member is TRUE if the window is displaying video using hardware overlay.

fScale

Input scaling flag. The value of this member is TRUE if the window is scaling the input video to the client area when displaying video using preview. This parameter has no effect when displaying video using overlay.

ptScroll

The x- and y-offset of the pixel displayed in the upper left corner of the client area of the window.

fUsingDefaultPalette

Default palette flag. The value of this member is TRUE if the capture driver is using its default palette.

fAudioHardware

Audio hardware flag. The value of this member is TRUE if the system has waveform-audio hardware installed.

fCapFileExists

Capture file flag. The value of this member is TRUE if a valid capture file has been generated.

dwCurrentVideoFrame

Number of frames processed during the current (or most recent) streaming capture. This count includes dropped frames.

dwCurrentVideoFramesDropped

Number of frames dropped during the current (or most recent) streaming capture. Dropped frames occur when the capture rate exceeds the rate at which frames can be saved to file. In this case, the capture driver has no buffers available for storing data. Dropping frames does not affect synchronization because the previous frame is displayed in place of the dropped frame.

dwCurrentWaveSamples

Number of waveform-audio samples processed during the current (or most recent) streaming capture.

dwCurrentTimeElapsedMS

Time, in milliseconds, since the start of the current (or most recent) streaming capture.

fCapturingNow

Capturing flag. The value of this member is TRUE when capturing is in progress.

dwReturn

Error return values. Use this member if your application does not support an error callback function.

wNumVideoAllocated

Number of video buffers allocated. This value might be less than the number specified in the wNumVideoRequested member of the CAPTUREPARMS structure.

wNumAudioAllocated

Number of audio buffers allocated. This value might be less than the number specified in the wNumAudioRequested member of the CAPTUREPARMS structure.

Because the state of a capture window changes in response to various messages, an application should update the information in this structure whenever it needs to enable menu items, determine the actual state of the capture window, or call the video format dialog box. If the application yields during streaming capture, this structure returns the progress of the capture in the dwCurrentVideoFrame, dwCurrentVideoFramesDropped, dwCurrentWaveSamples, and dwCurrentTimeElapsedMS members. Use the WM_CAP_GET_STATUS message or capGetStatus macro to update the contents of this structure.


CAPTUREPARMS

typedef struct {

DWORD dwRequestMicroSecPerFrame;

BOOL  fMakeUserHitOKToCapture;

UINT  wPercentDropForError;

BOOL  fYield;

DWORD dwIndexSize;

UINT  wChunkGranularity;

BOOL  fUsingDOSMemory;

UINT  wNumVideoRequested;

BOOL  fCaptureAudio;

UINT  wNumAudioRequested;

UINT  vKeyAbort;

BOOL  fAbortLeftMouse;

BOOL  fAbortRightMouse;

BOOL  fLimitEnabled;

UINT  wTimeLimit;

BOOL  fMCIControl;

BOOL  fStepMCIDevice;

DWORD dwMCIStartTime;

DWORD dwMCIStopTime;

BOOL  fStepCaptureAt2x;

UINT  wStepCaptureAverageFrames;

DWORD dwAudioBufferSize;

BOOL  fDisableWriteCache;

UINT  AVStreamMaster;

} CAPTUREPARMS;

Contains parameters that control the streaming video capture process. This structure is used to get and set parameters that affect the capture rate, the number of buffers to use while capturing, and how capture is terminated.

dwRequestMicroSecPerFrame

Requested frame rate, in microseconds. The default value is 66667, which corresponds to 15 frames per second.

fMakeUserHitOKToCapture

User-initiated capture flag. If this member is TRUE, AVICap displays a dialog box prompting the user to initiate capture. The default value is FALSE.

wPercentDropForError

Maximum allowable percentage of dropped frames during capture. Values range from 0 to 100. The default value is 10.

fYield

Yield flag. If this member is TRUE, the capture window spawns a separate background thread to perform step and streaming capture. The default value is FALSE.

Applications that set this flag must handle potential reentry issues because the controls in the application are not disabled while capture is in progress.

dwIndexSize

Maximum number of index entries in an AVI file. Values range from 1800 to 324,000. If set to 0, a default value of 34,952 (32K frames plus a proportional number of audio buffers) is used.

Each video frame or buffer of waveform-audio data uses one index entry. The value of this entry establishes a limit for the number of frames or audio buffers that can be captured.

wChunkGranularity

Logical block size, in bytes, of an AVI file. The value 0 indicates the current sector size is used as the granularity.

fUsingDOSMemory

Not used in Win32 applications.

wNumVideoRequested

Maximum number of video buffers to allocate. The memory area to place the buffers is specified with fUsingDOSMemory. The actual number of buffers allocated might be lower if memory is unavailable.

fCaptureAudio

Capture audio flag. If this member is TRUE, audio is captured during streaming capture. This is the default value if audio hardware is installed.

wNumAudioRequested

Maximum number of audio buffers to allocate. The maximum number of buffers is 10.

vKeyAbort

Virtual keycode used to terminate streaming capture. The default value is VK_ESCAPE.

You can combine keycodes that include CTRL and SHIFT keystrokes by using the logical OR operator with the keycodes for CTRL (0x8000) and SHIFT (0x4000).

fAbortLeftMouse

Abort flag for left mouse button. If this member is TRUE, streaming capture stops if the left mouse button is pressed. The default value is TRUE.

fAbortRightMouse

Abort flag for right mouse button. If this member is TRUE, streaming capture stops if the right mouse button is pressed. The default value is TRUE.

fLimitEnabled

Time limit enabled flag. If this member is TRUE, streaming capture stops after the number of seconds in wTimeLimit has elapsed. The default value is FALSE.

wTimeLimit

Time limit for capture, in seconds. This parameter is used only if fLimitEnabled is TRUE.

fMCIControl

MCI device capture flag. If this member is TRUE, AVICap controls an
MCI-compatible video source during streaming capture. MCI-compatible video sources include VCRs and laserdiscs.

fStepMCIDevice

MCI device step capture flag. If this member is TRUE, step capture using an MCI device as a video source is enabled. If it is FALSE, real-time capture using an MCI device is enabled. (If fMCIControl is FALSE, this member is ignored.)

dwMCIStartTime

Starting position, in milliseconds, of the MCI device for the capture sequence. (If fMCIControl is FALSE, this member is ignored.)

dwMCIStopTime

Stopping position, in milliseconds, of the MCI device for the capture sequence. When this position in the content is reached, capture ends and the MCI device stops. (If fMCIControl is FALSE, this member is ignored.)

fStepCaptureAt2x

Double-resolution step capture flag. If this member is TRUE, the capture hardware captures at twice the specified resolution. (The resolution for the height and width is doubled.)

Enable this option if the hardware does not support hardware-based decimation and you are capturing in the RGB format.

wStepCaptureAverageFrames

Number of times a frame is sampled when creating a frame based on the average sample. A typical value for the number of averages is 5.

dwAudioBufferSize

Audio buffer size. If the default value of zero is used, the size of each buffer will be the maximum of 0.5 seconds of audio or 10K bytes.

fDisableWriteCache

Not used in Win32 applications.

AVStreamMaster

Indicates whether the audio stream controls the clock when writing an AVI file. If this member is set to AVSTREAMMASTER_AUDIO, the audio stream is considered the master stream and the video stream duration is forced to match the audio duration. If this member is set to AVSTREAMMASTER_NONE, the durations of audio and video streams can differ.

The WM_CAP_GET_SEQUENCE_SETUP message or capCaptureGetSetup macro is used to retrieve the current capture parameters. The WM_CAP_SET_SEQUENCE_SETUP message or capCaptureSetSetup macro is used to set the capture parameters.

The WM_CAP_GET_SEQUENCE_SETUP message or capCaptureGetSetup macro is used to retrieve the current capture parameters. The WM_CAP_SET_SEQUENCE_SETUP message or capCaptureSetSetup macro is used to set the capture parameters.


Custom File and Stream Handlers

File and stream handlers are drivers that provide consistent interfaces to an application controlling multimedia data. The file and stream handlers included in the Microsoft Windows operating system access video and waveform-audio data stored in audio-video interleaved (AVI) and waveform-audio files.

You can write handlers to allow your application to write or access multimedia data from another source, such as a file using a proprietary format, an AVI file that has been expanded to contain additional data streams, or a handler that generates its own multimedia data. If you have a custom file format for AVI data that you would like to use with the AVIFile functions provided with the Microsoft Win32 application programming interface (API), you need to write a custom handler.

Your application can use a custom file handler to read from a file or write to a file that is in a nonstandard format. To do this, your application simply uses the name of your file handler when opening the file or allocating the file interface. The AVIFile library then uses the functions from your file handler instead of those from another file handler. The nonstandard format appears as standard AVI data to your application or to any other application using your custom file handler.

Similarly, your application can use a custom stream handler to read a stream that is in a nonstandard format. A stream — whether it constitutes audio, video, MIDI (Musical Instrument Digital Interface), text, or custom data — is a component of an AVI file. For example, an AVI file that contains a video sequence, an English soundtrack, and a French soundtrack consists of three streams. Your application can specify the streams in an AVI file to process and direct each of those streams to a handler that can optimally process the appropriate type of multimedia data.

Note  You must place custom stream and file handlers in one or more DLLs, separated from main application files.


Handler Architecture

The internal function of a file or stream handler is defined by the handler itself. To an application, a file handler typically appears as a module to read and write AVI files. Similarly, a stream handler appears as a module to read and write a specific type of data stream. The consistent stream interface makes the source and destination of the stream unimportant to the application that uses the handler.

A file handler provides access to a data source consisting of one or more data streams. File handlers typically provide access to disk files containing one or more data streams and the internal functions of the file handler read and write the multimedia data; however, file handlers can work with any data source, such as a digital transmission channel containing several intermingled data streams.

In contrast, a stream handler processes one type of data and appears as a data stream to an application. A stream handler can provide data that it manufactures or it can retrieve data from a file or an external source. It supplies its data in a format that your application can use.


C++ and OLE Programming Concepts

The file and stream handlers included with Windows use an object-oriented design to promote a standard interface and to share functionality. These handlers are written in C++ and use the OLE Component Object Model.

You can develop custom handlers using the C or C++ development systems; however, C++ is recommended primarily because it provides an easier and more straightforward approach to implement a handler. Using C++, you can explicitly define data as objects and you can associate the functions that manipulate the data as member functions of an object.

This section identifies and briefly summarizes the important concepts of C++ and the OLE Component Object Model that apply to designing and implementing file and stream handlers.


Classes, Objects, Methods, and Interfaces

For file and stream handlers, an object can be considered as simply a pointer to a structure. For example, a pointer to the RECT data type can be considered an object. A method is an object with a function associated with it. A class is a composite group of member objects, functions to manipulate these members, and (optionally) access-control specifications to member objects and functions. An interface is a set of related methods.


The Scope Resolution Operator in C++

Two colons (::) are used in C+ + as a scope resolution operator. This operator gives you more freedom in naming your variables by letting you distinguish between variables with the same name. For example, MyFile::Read refers to the Read method of the MyFile class of objects, as opposed to YourFile::Read, which refers to a Read method in the YourFile class.


Virtual Function Tables

A virtual function table (Vtbl) is an array of pointers to the methods an object supports. If you're using C, an object appears as a structure whose first member is a long pointer to the Vtbl (lpVtbl); that is, the first member points to a structure containing the function pointers. Thus, the following example calls the Read method of a pStream object:

pStream->lpVtbl->Read(pStream, parameters)

In C+ +, the pointer to Vtbl is implicit, and C+ + automatically passes the object itself as a first parameter. (Objects can obtain this information from the this parameter that is implicitly defined.) The following is equivalent to the previous example when using C+ +:

pStream->Read(parameters)


The OLE Component Object Model

The objects used by the AVIFile library are all part of the OLE Component Object Model. Primarily, this means that they share certain methods that make them easier to work with, and the values they return are common to most OLE interface methods.

The OLE Component Object Model of the file and stream handlers uses the OLE IClassFactory interface to create instances of their object class. As component objects, they implement the QueryInterface, Release, and AddRef methods defined by the IUnknown interface. The IUnknown interface lets an application obtain pointers to other interfaces supported by the same object.

You can determine if an object supports a specific interface by using the QueryInterface method. If an object supports a specified interface, QueryInterface returns a pointer to that interface.

You can increment and decrement the reference count associated with an object by using the AddRef and Release methods. The reference count lets multiple clients access an object. When an object is used by the first application, its reference count is set to 1. Applications subsequently use the AddRef method to increment the count to let the object keep track of how many times it is being accessed.

When an application is done using an object, it calls the Release method to decrement the reference count. When the reference count is zero, the object is no longer needed and Release frees any resources it uses and destroys the object. Because an object uses internal resources transparent to the application, the object is responsible for freeing them. For example, a file handler might need to close open disk files and free buffer memory when released.

Most OLE interface methods and API functions return result handles that are defined by using the HRESULT data type. This data type is made of a severity code, contextual information, a facility code, and a status code. A return result handle that indicates success has the value zero. A nonzero value indicates failure and the status code member of the return result handle provides a basis for additional interpretation. For additional information about OLE return result handles, see the Microsoft OLE 2 Programmer's Reference.


IAVIStream and IAVIFile Interfaces

The IAVIStream and IAVIFile interfaces contain the methods used by file and stream handlers. These interfaces use the PAVISTREAM and PAVIFILE data types as object pointers. From a C point of view, an object pointer like PAVISTREAM or PAVIFILE is a pointer to a structure whose first member is a pointer to a Vtbl table of functions. Other members of the structure retain data used by the interfaces.

For example, to create an object pointer, first allocate space for a structure large enough to contain the pointer to the Vtbl and any other members you want in the structure. Then, create a function table with the read, write, and other functions to operate on your type of stream, and then set the first member of the object pointer to point at the table.


File and Stream Handler Installation

The AVIFile library uses installed stream and file handlers for reading and writing AVI files and streams. A handler is installed when it resides in the Windows SYSTEM directory and the registry contains the following information needed to describe and identify a handler:

•	The 16-byte class identifier for the handler

•	A brief description of the handler

•	The name of the file containing the handler

•	The file extension that a file handler can process

•	File-access and non-RGB properties associated with a file handler

•	Four-character codes identifying stream types that a stream handler can process

The AVIFile library queries the registry for handlers that are external to an application when opening files and accessing streams. The result of a successful query returns the filename of a handler that can process the file or stream type specified in the query. The registry lists each handler by creating three entries that have the following form:

[HKEY_CLASSES_ROOT\Clsid\{00010023-0000-0000-C000-000000000046}]

@="Wave File reader/writer"

[HKEY_CLASSES_ROOT\Clsid\{00010023-0000-0000-C000-

000000000046}\InprocServer32]

@="wavefile.dll"

"ThreadingModel"="Apartment"

[HKEY_CLASSES_ROOT\Clsid\{00010023-0000-0000-C000-

000000000046}\AVIFile]

@="3"

These entries consist of the following parts:

Part	Description
HKEY_CLASSES_ROOT	Identifies the root entry of the registry.
Clsid	Identifies this entry as a class identifier.
{00010023-0000-0000-C000-000000000046}	Specifies an interface identifier (IID) or class identifier. This value is a unique 16-byte identifier. (The identifier might also be referred to as a GUID or a UUID in other manuals.)
Wave File reader/writer	Specifies a string to describe the handler. This string can be displayed in dialog boxes for selecting stream and file handlers.
InProcServer32	Specifies the file (in this example, WAVEFILE.DLL) that can be loaded to handle this class.
AVIFile	Specifies the properties of a file handler. In this example, the handler can read and write to an AVI file.
A file handler can have one or more of its properties stored in the registry. The following constants identify the properties currently associated with a file:

Constant	Description
AVIFILEHANDLER_CANACCEPTNONRGB	Indicates that a file handler can process non-RGB image data.
AVIFILEHANDLER_CANREAD	Indicates that a file handler can open a file with read access.
AVIFILEHANDLER_CANWRITE	Indicates that a file handler can open a file with write access.
When creating a file or stream handler, you can obtain a new identifier by running UUIDGEN.EXE. Always use UUIDGEN.EXE to create a new identifier. The 16-byte hexadecimal number created by this executable will uniquely identify your handler.

The AVIFile library uses additional entries in the registry to identify a class identifier based on the file extension that a file handler can process or a four-character code that a file or stream handler can process. For example, the following entries associate a class identifier with the file extension .WAV and the four-character code "WAVE":

[HKEY_CLASSES_ROOT\AVIFile\Extensions\WAV]

@="{00010023-0000-0000-C000-000000000046}"

[HKEY_CLASSES_ROOT\AVIFile\RIFFHandlers\WAVE]

@="{00010023-0000-0000-C000-000000000046}"

These entries consist of the following parts:

Part	Description
HKEY_CLASSES_ROOT	Identifies the root entry of the registry.
AVIFile	Identifies this entry as an entry used by AVIFile.
Extensions	Specifies the file extension (in this example, .WAV) that a file handler can process.
RIFFHandlers	Specifies the four-character code (in this example, "WAVE") a file or stream handler can process.
{00010023-0000-0000-C000-000000000046}	Specifies an interface identifier (IID) or class identifier.
If you distribute your stream or file handler without a setup application to install it in the user's system, you must include a .REG file so the user can install the handler. The user will use the registry editor to create registry entries for your stream or file handler.

The following example shows the contents of a typical .REG file. The first entry in the following example holds the descriptive string for the handler. The second entry identifies the file containing the handler. The third entry identifies the properties of the file handler (in this case, read-only access to files). The fourth entry associates the type of file the handler processes (in this case, files with a .JPG filename extension) with the class identifier.

[HKEY_CLASSES_ROOT\Clsid\{5C2B8200-E2C8-1068-B1CA-6066188C6002}]

@="JFIF (JPEG) Files"

[HKEY_CLASSES_ROOT\Clsid\{5C2B8200-E2C8-1068-B1CA-6066188C6002}]\InprocServer32]

@="jfiffile.dll"

[HKEY_CLASSES_ROOT\AVIFile\Extensions\JPG]

@="{5C2B8200-E2C8-1068-B1CA-6066188C6002}"

When creating this file, save it with a .REG extension to identify it as an update file for the registry. Also, substitute a unique IID for the 16-byte code used in the example.

Users can update the registry on their system by using the following procedure:

1.	From the Program Manager File menu, choose the Run command.

2.	In the Run dialog box, type the following command and press ENTER:

regedit -s filename.reg


Using Custom File and Stream Handlers

This section contains examples demonstrating how to perform the following tasks:

•	Create a file or stream handler.

•	Create a virtual function table for a stream handler.

•	Create an object pointer.

•	Obtain the address of a virtual function table.

•	Create a file-handler instance in a dynamic-link library (DLL).

•	Determine which interface an object supports.

•	Increment the handler reference counter.

•	Delete an object.


Creating a File or Stream Handler

In C, a file or stream handler usually creates a function for each method. Your application accesses these functions through an array of function pointers the stream handler creates. An IAVIStreamVtbl structure contains the array of function pointers. A stream handler can assign any name it wants to functions it creates for the methods. The position of the function pointer in the structure implies the correspondence of the function to the method. For example, the first function pointer in the structure corresponds to the QueryInterface method. Your stream handler must provide all the functions of an interface.


Creating a Virtual Function Table for a Stream Handler

The following example (written in C) shows how an application (AVIBall) creates the Vtbl used to reference its services.

HRESULT STDMETHODCALLTYPE AVIBallQueryInterface (PAVISTREAM ps,

REFIID riid, LPVOID FAR* ppvObj);

HRESULT STDMETHODCALLTYPE AVIBallCreate (PAVISTREAM ps,

LONG lParam1, LONG lParam2);

ULONG STDMETHODCALLTYPE AVIBallAddRef (PAVISTREAM ps);

ULONG STDMETHODCALLTYPE AVIBallRelease (PAVISTREAM ps);

HRESULT STDMETHODCALLTYPE AVIBallInfo (PAVISTREAM ps,

AVIStreamHeader FAR * psi, LONG lSize);

LONG STDMETHODCALLTYPE AVIBallFindSample (PAVISTREAM ps,

LONG lPos, LONG lFlags);

HRESULT STDMETHODCALLTYPE AVIBallReadFormat (PAVISTREAM ps,

LONG lPos, LPVOID lpFormat, LONG FAR *lpcbFormat);

HRESULT STDMETHODCALLTYPE AVIBallSetFormat (PAVISTREAM ps,

LONG lPos, LPVOID lpFormat, LONG cbFormat);

HRESULT STDMETHODCALLTYPE AVIBallRead (PAVISTREAM ps,

LONG lStart, LONG lSamples, LPVOID lpBuffer, LONG cbBuffer,

LONG FAR * plBytes,LONG FAR * plSamples);

HRESULT STDMETHODCALLTYPE AVIBallWrite (PAVISTREAM ps, LONG lStart,

LONG lSamples, LPVOID lpBuffer, LONG cbBuffer, DWORD dwFlags);

HRESULT STDMETHODCALLTYPE AVIBallDelete (PAVISTREAM ps,

LONG lStart, LONG lSamples);

HRESULT STDMETHODCALLTYPE AVIBallReadData (PAVISTREAM ps,

DWORD fcc, LPVOID lp,LONG FAR *lpcb);

HRESULT STDMETHODCALLTYPE AVIBallWriteData (PAVISTREAM ps,

DWORD fcc, LPVOID lp,LONG cb);

IAVIStreamVtbl AVIBallHandler = {

    AVIBallQueryInterface,  // Function pointer for ::QueryInterface

    AVIBallAddRef,          // Function pointer for ::AddRef

    AVIBallRelease,         // Function pointer for ::Release

    AVIBallCreate,          // Function pointer for ::Create

    AVIBallInfo,            // Function pointer for ::Info

    AVIBallFindSample,      // Function pointer for ::FindSample

    AVIBallReadFormat,      // Function pointer for ::ReadFormat

    AVIBallSetFormat,       // Function pointer for ::SetFormat

    AVIBallRead,            // Function pointer for ::Read

    AVIBallWrite,           // Function pointer for ::Write

    AVIBallDelete,          // Function pointer for ::Delete

    AVIBallReadData,        // Function pointer for ::ReadData

    AVIBallWriteData        // Function pointer for ::WriteData

};

File handlers use a similar procedure, except they use a different definition for the Vtbl.


Creating an Object Pointer

AVIBall uses the following structure as its object pointer. The first member of this structure points to the Vtbl AVIBall uses to access its functions. Applications can cast this structure to the PAVISTREAM data type. Methods that use the PAVISTREAM data type use only the pointer to the Vtbl. The members following the pointer to the Vtbl are used internally by AVIBall.

typedef struct {

    IAVIStreamVtbl FAR * lpvtbl;

    // Ball instance data.

    ULONG	  ulRefCount;

    DWORD	  fccType;  // is this audio/video?

    int	  width;    // size, in pixels, of each frame

    int	  height;

    int	  length;   // length, in frames

    int	  size;

    COLORREF	 color;    // ball color

} AVIBALL, FAR * PAVIBALL;


Obtaining the Address of a Virtual Function Table

Applications written in C can retrieve the address of the IAVIStreamVtbl structure by using the NewBall function. This function returns the address of a structure containing a pointer to IAVIStreamVtbl. Information following the IAVIStreamVtbl pointer specifies data used internally by AVIBall. Your stream handler can append its own information after the IAVIStreamVtbl pointer. This information is returned in subsequent calls to your stream handler.

PAVISTREAM FAR PASCAL NewBall(VOID)

{

    PAVIBALL pball;

    pball = (PAVIBALL) GlobalAllocPtr(GHND, sizeof(AVIBALL));

    if (!pball)

return 0;

    pball->lpvtbl = &AVIBallHandler;

    pball->lpvtbl->Create((PAVISTREAM) pball, 0, 0);

    return (PAVISTREAM) pball;

}


Creating a File-Handler Instance in a DLL

When an application specifies your file-handler DLL or stream handler, it is looked up in the registry by its class identifier and loaded. The system then calls the DllGetClassObject function of the DLL to create an instance of the file or stream handler. The following example (written in C++) shows how a file handler creates an instance:

// Main DLL entry point.

STDAPI DllGetClassObject(const CLSID FAR& rclsid,

    const IID FAR& riid, void FAR* FAR* ppv)

{

    HRESULT hresult;

hresult = CAVIFileCF::Create(rclsid, riid, ppv);

return hresult;

}

HRESULT CAVIFileCF::Create(const CLSID FAR&	rclsid,

const IID FAR& riid, void FAR* FAR*	ppv)

{

// The following is the class factory creation and not an

// actual PAVIFile.

CAVIFileCF FAR*	pAVIFileCF;

IUnknown FAR*	pUnknown;

HRESULT hresult;

// Create the instance.

pAVIFileCF = new FAR CAVIFileCF(rclsid, &pUnknown);

if (pAVIFileCF == NULL)

return ResultFromScode(E_OUTOFMEMORY);

// Set the interface pointer.

hresult = pUnknown->QueryInterface(riid, ppv);

if (FAILED(GetScode(hresult)))

delete pAVIFileCF;

return hresult;

}


Determining Which Interface an Object Supports

The QueryInterface method lets an application query an object to determine which interfaces it supports. The sample application sets the ppv pointer to the current interface.

STDMETHODIMP CAVIFileCF::QueryInterface(

const IID FAR&	iid,

void FAR* FAR*	ppv)

{

if (iid == IID_IUnknown)

*ppv = this;                     // set the interface pointer

                                         // to this instance

else if (iid == IID_IClassFactory)

*ppv = this;                     // second chance to set the

                                         // interface pointer to this

                                         // instance

else

return ResultFromScode(E_NOINTERFACE);

AddRef();  //Increment the reference count

return NULL;

}


Incrementing the Handler Reference Count

The AddRef method increments the stream- or file-handler reference count.

STDMETHODIMP_(ULONG) CAVIFileCF::AddRef()

{

return ++m_refs;

}


Deleting an Object

The Release method deletes the object when its reference count is zero.

STDMETHODIMP_(ULONG) CAVIFileCF::Release()

{

if (!--m_refs) {

delete this;   // if O, delete this instance

return 0;

}

return m_refs;

}


Custom File and Stream Handler Reference

This section describes the functions, interfaces, and member functions that make up the standard AVI file and stream handlers. These elements are grouped as follows:

Handler Entry Point

DllGetClassObject

AVI File Interface

IAVIFile
IAVIFile::CreateStream
IAVIFile::EndRecord
IAVIFile::GetStream
IAVIFile::Info
IAVIFile::Open
IAVIFile::WriteData

Stream Interface

IAVIStream
IAVIStream::Create
IAVIStream::Delete
IAVIStream::Info
IAVIStream::FindSample
IAVIStream::Read
IAVIStream::ReadData
IAVIStream::ReadFormat
IAVIStream::SetFormat
IAVIStream::Write
IAVIStream::WriteData

Data Streaming Interface

IAVIStreaming
IGetFrame::Begin
IGetFrame::End

Editable Stream Interface

IAVIEditStream
IAVIEditStream::Clone
IAVIEditStream::Copy
IAVIEditStream::Cut
IAVIEditStream::Paste
IAVIEditStream::SetInfo

Frame Extraction Interface

IGetFrame
IGetFrame::SetFormat
IGetFrame::End
IGetFrame::GetFrame
IGetFrame::SetFormat

IUnknown Interface

IUnknown
IUnknown::QueryInterface
IUnknown::AddRef
IUnknown::Release


Custom File and Stream Handler Function

A file or stream handler needs to export the DllGetClassObject function entry point so an application can access the handler.


DllGetClassObject

STDAPI DllGetClassObject(const CLSID FAR& rclsid, const IID FAR& riid,

    void FAR* FAR* ppv)

Entry point used by C+ + file and stream handlers to create an instance of the handler.

•	Returns a handle of an instance of the file or stream handler.

rclsid

Class identifier of the file or stream handler.

riid

Interface identifier of the file or stream handler.

ppv

Address returned for the object of the interface query. If the interface specified in riid is not supported by the object, S_FALSE is returned and the ppvObj parameter used in the IUnknown interface must be set to NULL.

DllGetClassObject is the only export function your DLL needs. The OLE component object DLL calls this function to obtain an instance of the stream- or file-handler interface.

Your file or stream handler should ensure that the system requests the correct class identifier before creating an instance of it.


Custom File and Stream Handler Interfaces and Members

A file or stream handler uses one or more interfaces to define the member functions for manipulating a file or data stream. Each of the interfaces described in this section is based on the OLE Component Object Model. The prefixes of member function names correspond to the interface names they are associated with.


IAVIEditStream

Interface for manipulating and modifying editable streams. Uses IUnknown::QueryInterface, IUnknown::AddRef, IUnknown::Release in addition to the following custom methods:

Clone	Duplicates a stream.
Copy	Copies a stream or a portion of it to a temporary stream.
Cut	Removes a portion of a stream and places it in a temporary stream.
Paste	Copies a stream or a portion of it and places it in another stream.
SetInfo	Changes the characteristics of a stream.


IAVIEditStream::Clone

HRESULT STDMETHODCALLTYPE Clone(PAVISTREAM pavi,

    PAVISTREAM FAR *ppResult);

Duplicates a stream. Called when an application uses the EditStreamClone function.

•	Returns the HRESULT defined by OLE.

pavi

Address of the interface to the stream being cloned.

ppResult

Address to contain a pointer to the interface to the new stream.

For handlers written in C++, Clone has the following syntax:

STDMETHODIMP Clone(PAVISTREAM FAR *ppResult);


IAVIEditStream::Copy

HRESULT STDMETHODCALLTYPE Copy(PAVISTREAM pavi, LONG FAR *plStart,

    LONG FAR *plLength, PAVISTREAM FAR * ppResult);

Copies a stream or a portion of it to a temporary stream. Called when an application uses the EditStreamCopy function.

•	Returns the HRESULT defined by OLE.

pavi

Address of the interface to the stream to copy.

plStart

Address that contains the starting position of the operation.

plLength

Address that contains the length, in frames, of the operation.

ppResult

Address to contain a pointer to the interface to the new stream.

For handlers written in C++, Copy has the following syntax:

STDMETHODIMP Copy(LONG FAR *plStart, LONG FAR *plLength,

    PAVISTREAM FAR * ppResult);


IAVIEditStream::Cut

HRESULT STDMETHODCALLTYPE Cut(PAVISTREAM pavi, LONG FAR *plStart,

    LONG FAR *plLength, PAVISTREAM FAR * ppResult);

Removes a portion of a stream and places it in a temporary stream. Called when an application uses the EditStreamCut function.

•	Returns the HRESULT defined by OLE.

pavi

Address of the interface to the stream to cut.

plStart

Address that contains the starting position of the operation.

plLength

Address that contains the length, in frames, of the operation.

ppResult

Address to contain a pointer to the interface to the new stream.

For handlers written in C++, Cut has the following syntax:

STDMETHODIMP Cut(LONG FAR *plStart, LONG FAR *plLength,

    PAVISTREAM FAR * ppResult);


IAVIEditStream::Paste

HRESULT STDMETHODCALLTYPE Paste(PAVISTREAM pavi, LONG FAR *plPos,

    LONG FAR *plLength, PAVISTREAM pstream, LONG lStart,

    LONG lLength);

Copies a stream or a portion of it in another stream. Called when an application uses the EditStreamPaste function.

•	Returns the HRESULT defined by OLE.

pavi

Address of the interface to the stream to receive the pasted data.

plPos

Address that contains the starting position of the operation.

plLength

Address that contains the length, in bytes, of the data to paste from the source stream.

pstream

Address of the interface to the source stream.

lStart

Starting position of the copy operation within the source stream.

lLength

Length, in frames, of the copy operation within the source stream.

For handlers written in C++, Paste has the following syntax:

STDMETHODIMP Paste(LONG FAR *plPos, LONG FAR *plLength,

    PAVISTREAM pstream, LONG lStart, LONG lLength);


IAVIEditStream::SetInfo

HRESULT STDMETHODCALLTYPE SetInfo(PAVISTREAM pavi,

    AVISTREAMINFO FAR *lpInfo, LONG cbInfo);

Changes the characteristics of a stream. Called when an application uses the EditStreamSetInfo function.

•	Returns the HRESULT defined by OLE.

pavi

Address of the interface to a stream.

lpInfo

Address of an AVISTREAMINFO structure containing the new stream characteristics.

cbInfo

Size, in bytes, of the buffer.

For handlers written in C++, SetInfo has the following syntax:

STDMETHODIMP SetInfo(AVISTREAMINFO FAR *lpInfo, LONG cbInfo);


IAVIFile

Interface for opening and manipulating files and file headers, and creating and obtaining stream interfaces. Uses IUnknown::QueryInterface, IUnknown::AddRef, and IUnknown::Release in addition to the following custom methods:

CreateStream	Creates a stream for writing.
EndRecord	Writes the "REC" chunk in a tightly interleaved AVI file.
GetStream	Opens a stream by accessing it in a file.
Info	Fills and returns an AVIFILEINFO structure with information about a file.
Open	Initializes a file handler.
ReadData	Reads file headers data, format data, or nonaudio and nonvideo data.
WriteData	Writes file headers data, format data, or nonaudio and nonvideo data.


IAVIFile::CreateStream

HRESULT STDMETHODCALLTYPE CreateStream(PAVIFILE pf,

    PAVISTREAM FAR * ppstream, AVISTREAMINFO FAR * psi);

Creates a stream for writing. Called when an application uses the AVIFileCreateStream function.

•	Returns HRESULT defined by OLE.

pf

Address of the interface to a file.

ppStream

Address to contain a pointer to the interface to the new stream.

psi

Address of an AVISTREAMINFO structure defining the stream to create.

For handlers written in C++, CreateStream has the following syntax:

STDMETHODIMP CreateStream(PAVISTREAM FAR * ppStream,

    AVISTREAMINFO FAR * psi);


IAVIFile::EndRecord

HRESULT STDMETHODCALLTYPE EndRecord(PAVISTREAM pf);

Writes the "REC" chunk in a tightly interleaved AVI file (having a one-to-one interleave factor of audio to video). Called when an application uses the AVIFileEndRecord function.

•	Returns the HRESULT defined by OLE.

pf

Address of the interface to a file.

This file handler method is typically not used.

For handlers written in C++, EndRecord has the following syntax:

STDMETHODIMP EndRecord(VOID);


IAVIFile::GetStream

STDMETHODIMP GetStream(PAVIFILE pf, PAVISTREAM FAR * ppStream,

    DWORD fccType, LONG lParam);

Opens a stream by accessing it in a file. Called when an application uses the AVIFileGetStream function.

•	Returns the HRESULT defined by OLE.

pf

Address of the interface to a file.

ppStream

Address to contain a pointer to the interface to a stream.

fccType

Four-character code indicating the type of stream to locate.

lParam

Stream number.

It is typically easier to implement this method by creating all of the stream objects in advance by using the IAVIFile::Open method. Then, this method accesses the interface to the specified stream.

Remember to increment the reference count maintained by the AddRef method for the stream when this method is used.

For handlers written in C++, GetStream has the following syntax:

STDMETHODIMP GetStream(PAVISTREAM FAR * ppStream,

    DWORD fccType, LONG lParam);


IAVIFile::Info

HRESULT STDMETHODCALLTYPE Info (PAVISTREAM pf,

    AVISTREAMINFO FAR * pfi, LONG lSize);

Fills and returns an AVIFILEINFO structure with information about a file. Called when an application uses the AVIFileInfo function.

•	Returns the HRESULT defined by OLE.

pf

Address of the interface to a file.

pfi

Address of an application-defined buffer to contain file information.

lSize

Size, in bytes, of the buffer specified by pfi.

If the buffer allocated is too small for the structure, this method should fail the call by returning AVIERR_BUFFERTOOSMALL. Otherwise, it should fill the structure and return its size.

For handlers written in C++, Info has the following syntax:

STDMETHODIMP Info(AVIFILEINFO FAR * psi, LONG lSize)


IAVIFile::Open

HRESULT STDMETHODIMP Open(PAVISTREAM pf, LPCSTR szFile, UINT mode);

Initializes a file handler. Called when an application uses the AVIFileOpen function.

•	Returns the HRESULT defined by OLE.

pf

Address to contain a pointer to the interface to a file.

szFile

Address of a null-terminated string that contains the filename.

mode

Flags for the open operation.

This method is always the first method called, regardless of whether your application is reading or writing a file.

For handlers written in C++, Open has the following syntax:

STDMETHODIMP Open(LPCSTR szFile, UINT mode);


IAVIFile::ReadData

HRESULT STDMETHODCALLTYPE ReadData (PAVISTREAM ps, DWORD fcc,

    LPVOID lpBuffer, LONG FAR * lpcbBuffer);

Reads file headers. Called when an application uses the AVIFileReadData function.

•	Returns the HRESULT defined by OLE.

ps

Address of the interface to a file.

fcc

Four-character code of the header to read.

lpBuffer

Address of the buffer for the data.

lpcbBuffer

Size, in bytes, of the buffer specified by lpBuffer. When this method returns control to the application, the contents of this parameter specifies the amount of data read.

For handlers written in C++, ReadData has the following syntax:

STDMETHODIMP ReadData(DWORD fcc, LPVOID lp, LONG FAR *lpcb);


IAVIFile::WriteData

HRESULT STDMETHODCALLTYPE AVIBallWriteData(PAVISTREAM ps, DWORD fcc,

    LPVOID lpBuffer, LONG cbBuffer);

Writes file headers. Called when an application uses the AVIFileWriteData function.

•	Returns the HRESULT defined by OLE.

ps

Address of the interface to a file.

fcc

Four-character code of the header to write.

lpBuffer

Address of the buffer for the data.

cbBuffer

Size, in bytes, of the buffer specified by lpBuffer.

For handlers written in C++, WriteData has the following syntax:

STDMETHODIMP WriteData(DWORD fcc, LPVOID lpBuffer, LONG cbBuffer);


IAVIStream

Interface for creating and manipulating data streams within a file. Uses IUnknown::QueryInterface, IUnknown::AddRef, IUnknown::Release in addition to the following custom methods:

Create	Initializes a stream handler that is not associated with any file.
Delete	Deletes data from a stream.
Info	Fills and returns an AVISTREAMINFO structure with information about a stream.
FindSample	Obtains the position in a stream of a key frame or a nonempty frame.
Read	Reads data from a stream and copies it to an application-defined buffer.
ReadData	Reads data headers, format data, or nonaudio and nonvideo data. (Use  the Read method to read audio and video data.)
ReadFormat	Obtains format information from a stream.
SetFormat	Sets format information in a stream.
Write	Writes data to a stream.
WriteData	Writes data headers, format data, or nonaudio and nonvideo data. (Use the Write method to write audio and video data.)


IAVIStream::Create

HRESULT STDMETHODCALLTYPE Create(PAVISTREAM ps, LONG lParam1,

    LONG lParam2);

Initializes a stream handler that is not associated with any file. Called when an application uses the AVIStreamCreate function.

•	Returns the HRESULT defined by OLE.

ps

Address of the interface to a stream.

lParam1 and lParam2

Stream handler-specific data.

For handlers written in C++, Create has the following syntax:

STDMETHODIMP Create(LONG lParam1, LONG lParam2)


IAVIStream::Delete

HRESULT STDMETHODCALLTYPE Delete(PAVISTREAM ps, LONG lStart,

    LONG lSamples);

Deletes data from a stream.

•	Returns the HRESULT defined by OLE.

ps

Address of the interface to a stream.

lStart

Starting sample or frame number to delete.

lSamples

Number of samples to delete.

For handlers written in C++, Delete has the following syntax:

STDMETHODIMP Delete(LONG lStart, LONG lSamples);


IAVIStream::Info

HRESULT STDMETHODCALLTYPE Info(PAVISTREAM ps, AVISTREAMINFO FAR * psi,

    LONG lSize);

Fills and returns an AVISTREAMINFO structure with information about a stream. Called when an application uses the AVIStreamInfo function.

•	Returns the HRESULT defined by OLE.

ps

Address of the interface to a stream.

psi

Address of an AVISTREAMINFO structure to contain stream information.

lSize

Size, in bytes, of the structure specified by psi.

If the buffer allocated is too small for the structure, the Info method should fail the call by returning AVIERR_BUFFERTOOSMALL. Otherwise, it should fill the structure and return its size.

For handlers written in C++, Info has the following syntax:

STDMETHODIMP Info(AVIFILEINFO FAR * psi, LONG lSize)


IAVIStream::FindSample

LONG STDMETHODCALLTYPE FindSample(PAVISTREAM ps, LONG lPos,

    LONG lFlags);

Obtains the position in a stream of a key frame or a nonempty frame. Called when an application uses the AVIStreamFindSample function.

•	Returns the location of the key frame corresponding to the frame specified by the application.

ps

Address of the interface to a stream.

lPos

Position of the sample or frame.

lFlags

Applicable flags. The following values are defined:

FIND_ANY

Searches for a nonempty frame.

FIND_FORMAT

Searches for a format change.

FIND_KEY

Searches for a key frame.

FIND_NEXT

Searches forward through a stream, beginning with the current frame.

FIND_PREV

Searches backward through a stream, beginning with the current frame.

The FIND_ANY, FIND_KEY, and FIND_FORMAT flags are mutually exclusive, as are the FIND_NEXT and FIND_PREV flags. You must specify one value from each group.

If key frames are not significant in your custom format, return the position specified for lPos.

For handlers written in C++, FindSample has the following syntax:

STDMETHODIMP_(LONG) FindSample(LONG lPos, LONG lFlags)


IAVIStream::Read

HRESULT STDMETHODCALLTYPE Read(PAVISTREAM ps, LONG lStart,

    LONG lSamples, LPVOID lpBuffer, LONG cbBuffer,

    LONG FAR * plBytes, LONG FAR * plSamples);

Reads data from a stream and copies it to an application-defined buffer. If no buffer is supplied, it determines the buffer size needed to retrieve the next buffer of data. Called when an application uses the AVIStreamRead function.

•	Returns AVIERR_OK if successful or AVIERR_BUFFERTOOSMALL if the buffer is not large enough to hold the data. If successful, Read also returns either a buffer of data with the number of frames (samples) included in the buffer or the required buffer size, in bytes.

ps

Address of the interface to a stream.

lStart

Starting sample or frame number to read.

lSamples

Number of samples to read.

lpBuffer

Address of the application-defined buffer to contain the stream data. You can also specify NULL to request the required size of the buffer. Many applications precede each read operation with a query for the buffer size to see how large a buffer is needed.

cbBuffer

Size, in bytes, of the buffer specified by lpBuffer.

plBytes

Address to contain the number of bytes read.

plSamples

Address to contain the number of samples read.

For handlers written in C++, Read has the following syntax:

STDMETHODIMP Read(LONG lStart, LONG lSamples,

    LPVOID lpBuffer, LONG cbBuffer,

    LONG FAR * plBytes, LONG FAR * plSamples);


IAVIStream::ReadData

HRESULT STDMETHODCALLTYPE ReadData(PAVISTREAM ps, DWORD fcc,

    LPVOID lpBuffer, LONG FAR * lpcbBuffer);

Reads data headers of a stream. Called when an application uses the AVIStreamReadData function.

•	Returns the HRESULT defined by OLE.

ps

Address of the interface to a stream.

fcc

Four-character code of the stream header to read.

lpBuffer

Address of the buffer to contain the header data.

lpcbBuffer

Size, in bytes, of the buffer specified by lpBuffer. When this method returns control to the application, the contents of this parameter specifies the amount of data read.

For handlers written in C++, ReadData has the following syntax:

STDMETHODIMP ReadData(DWORD fcc, LPVOID lp, LONG FAR *lpcb);


IAVIStream::ReadFormat

HRESULT STDMETHODCALLTYPE ReadFormat(PAVISTREAM ps, LONG lPos,

    LPVOID lpFormat, LONG FAR * lpcbFormat);

Obtains format information from a stream. Fills and returns a structure with the data in an application-defined buffer. If no buffer is supplied, determines the buffer size needed to retrieve the buffer of format data. Called when an application uses the AVIStreamReadFormat function.

•	Returns the HRESULT defined by OLE.

ps

Address of the interface to a stream.

lPos

Position of the sample or frame.

lpFormat

Address of the buffer for the format data. Specify NULL to request the required size of the buffer.

lpcbFormat

Address that contains the size, in bytes, of the buffer specified by lpFormat. When this method is called, the contents of this parameter indicates the size of the buffer specified by lpFormat. When this method returns control to the application, the contents of this parameter specifies the amount of data read or the required size of the buffer.

The type of data stored in a stream dictates the format information and the structure that contains the format information. A stream handler should return all applicable format information in this structure, including palette information when the format uses a palette. A stream handler should not return stream data with the structure.

Standard video stream handlers provide format information in a BITMAPINFOHEADER structure. Standard audio stream handlers provide format information in a PCMWAVEFORMAT structure. Other data streams can use other structures that describe the stream data.

For handlers written in C++, ReadFormat has the following syntax:

STDMETHODIMP ReadFormat(LONG lPos, LPVOID lpFormat,
    LONG FAR *lpcbFormat)


IAVIStream::SetFormat

HRESULT STDMETHODCALLTYPE SetFormat (PAVISTREAM ps, LPVOID lpFormat,

    LONG cbFormat);

Sets format information in a stream. Called when an application uses the AVIStreamSetFormat function.

•	Returns the HRESULT defined by OLE.

ps

Address of the interface to a stream.

lpFormat

Address of the buffer for the format data.

cbFormat

Address containing the size, in bytes, of the buffer specified by lpFormat.

Standard video stream handlers provide format information in a BITMAPINFOHEADER structure. Standard audio stream handlers provide format information in a PCMWAVEFORMAT structure. Other data streams can use other structures that describe the stream data.

For handlers written in C++, SetFormat has the following syntax:

STDMETHODIMP SetFormat(LONG lPos, LPVOID lpFormat, LONG cbFormat)


IAVIStream::Write

HRESULT STDMETHODCALLTYPE Write (PAVISTREAM ps, LONG lStart,

    LONG lSamples, LPVOID lpBuffer, LONG cbBuffer, DWORD dwFlags,

    LONG FAR *plSampWritten, LONG FAR *plBytesWritten);

Writes data to a stream. Called when an application uses the AVIStreamWrite function.

•	Returns the HRESULT defined by OLE.

ps

Address of the interface to a stream.

lStart

Starting sample or frame number to write.

lSamples

Number of samples to write.

lpBuffer

Address of the buffer for the data.

cbBuffer

Size, in bytes, of the buffer specified by lpBuffer.

dwFlags

Applicable flags. The AVIF_KEYFRAME flag is defined and indicates that this frame contains all the information needed for a complete image.

plSampWritten

Address of a buffer used to contain the number of samples written.

plBytesWritten

Address to contain the number of bytes written.

For handlers written in C++, Write has the following syntax:

STDMETHODIMP Write(LONG lStart, LONG lSamples, LPVOID lpBuffer,

    LONG cbBuffer, DWORD dwFlags, LONG FAR *plSampWritten,

    LONG FAR *plBytesWritten);


IAVIStream::WriteData

HRESULT STDMETHODCALLTYPE WriteData (PAVISTREAM ps, DWORD fcc,

    LPVOID lpBuffer, LONG cbBuffer);

Writes headers for a stream. Called when an application uses the AVIStreamWriteData function.

•	Returns the HRESULT defined by OLE.

ps

Address of the interface to a stream.

fcc

Four-character code of the stream header to write.

lpBuffer

Address of the buffer that contains the header data to write.

cbBuffer

Size, in bytes, of the buffer specified by lpBuffer.

For handlers written in C++, WriteData has the following syntax:

STDMETHODIMP WriteData(DWORD fcc, LPVOID lpBuffer, LONG cbBuffer);


IAVIStreaming

Interface for preparing open data streams for playback in streaming operations. Uses IUnknown::QueryInterface, IUnknown::AddRef, IUnknown::Release in addition to the Begin and End custom methods.


IAVIStreaming::Begin

STDMETHODCALLTYPE Begin(PAVISTREAM ps, LONG lStart, LONG lEnd,

    LONG lRate);

Prepares for the streaming operation. Called when an application uses the AVIStreamBeginStreaming function.

•	Returns the HRESULT defined by OLE.

ps

Address of the interface to a stream.

lStart

Starting frame for streaming.

lEnd

Ending frame for streaming.

lRate

Speed at which the file is read relative to its normal playback rate. Normal speed is 1000. Larger values indicate faster speeds; smaller values indicate slower speeds.

For handlers written in C++, Begin has the following syntax:

STDMETHODIMP Begin(LONG lStart, LONG lEnd, LONG lRate);


IAVIStreaming::End

STDMETHODCALLTYPE End(PAVISTREAM ps);

Ends the streaming operation. Called when an application uses the AVIStreamEndStreaming function.

•	Returns the HRESULT defined by OLE.

ps

Address of the interface to a stream.

For handlers written in C++, End has the following syntax:

STDMETHODIMP End(VOID);


IGetFrame

Interface for extracting, decompressing, and displaying individual frames from an open stream. Uses IUnknown::QueryInterface, IUnknown::AddRef, IUnknown::Release in addition to the following custom methods:

Begin	Prepares to extract and decompress copies of video frames from a stream.
End	Ends frame extraction and decompression.
GetFrame	Retrieves a decompressed copy of a frame from a stream.
SetFormat	Sets the image format of the frames being extracted.


IGetFrame::Begin

STDMETHODCALLTYPE Begin(PAVISTREAM ps, LONG lStart, LONG lEnd,

    LONG lRate);

Prepares to extract and decompress copies of frames from a stream. Called when an application uses the AVIStreamGetFrameOpen function.

•	Returns the HRESULT defined by OLE.

ps

Address of the interface to a stream.

lStart

Starting frame for extracting and decompressing.

lEnd

Ending frame for extracting and decompressing.

lRate

Speed at which the file is read relative to its normal playback rate. Normal speed is 1000. Larger values indicate faster speeds; smaller values indicate slower speeds.

For handlers written in C++, Begin has the following syntax:

STDMETHODIMP Begin(LONG lStart, LONG lEnd, LONG lRate);


IGetFrame::End

STDMETHODCALLTYPE End(PAVISTREAM ps);

Ends frame extraction and decompression. Called when an application uses the AVIStreamGetFrameClose function.

•	Returns the HRESULT defined by OLE.

ps

Address of the interface to a stream.

For handlers written in C++, Begin has the following syntax:

STDMETHODIMP End(VOID);


IGetFrame::GetFrame

LPVOID STDMETHODCALLTYPE GetFrame(PAVISTREAM ps, LONG lPos);

Retrieves a decompressed copy of a frame from a stream. Called when an application uses the AVIStreamGetFrame function.

•	Returns the address of the decompressed frame data.

ps

Address of the interface to a stream.

lPos

Frame to copy and decompress.

For handlers written in C++, GetFrame has the following syntax:

STDMETHODIMP_(LPVOID) GetFrame(LONG lPos);


IGetFrame::SetFormat

STDMETHODCALLTYPE SetFormat(PAVISTREAM ps, LPBITMAPINFOHEADER lpbi,

    LPVOID lpBits, int x, int y, int dx, int dy);

Sets the decompressed image format of the frames being extracted and optionally provides a buffer for the decompression operation.

•	Returns NOERROR if successful, E_OUTOFMEMORY if the decompressed image is larger than the buffer size, or E_FAIL otherwise.

ps

Address of the interface to a stream.

lpbi

Address of a BITMAPINFOHEADER structure defining the decompressed image format. You can also specify NULL or the value ((LPBITMAPINFOHEADER) 1) for this parameter. NULL causes the decompressor to choose a format that is appropriate for editing (normally a 24-bit image depth format). The value ((LPBITMAPINFOHEADER) 1) causes the decompressor to choose a format appropriate for the current display mode.

lpBits

Address of a buffer to contain the decompressed image data. Specify NULL to have this method allocate a buffer.

x and y

The x- and y-coordinates of the destination rectangle within the DIB specified by lpbi. This parameter is used when lpBits is not NULL.

dx and dy

Width and height of the destination rectangle. These parameters are used when lpBits is not NULL.

The x, y, dx, and dy parameters identify the portion of the bitmap specified by lpbi and lpBits that receives the decompressed image.

For handlers written in C++, SetFormat has the following syntax:

STDMETHODIMP SetFormat(LPBITMAPINFOHEADER lpbi, LPVOID lpBits, int x,

    int y, int dx, int dy);


IUnknown

OLE interface from which AVIFile and AVIStream interfaces are derived. Interfaces used with AVI files rely on definitions of the QueryInterface, AddRef, and Release methods from this factory.


IUnknown::QueryInterface

HRESULT STDMETHODCALLTYPE QueryInterface(LPUNKNOWN ps,

    const IID FAR& riid, void FAR* ppvObj);

Determines if an interface can be used with an object. Used by the following interfaces: IAVIEditStream, IAVIFile, IAVIStream, IAVIStreaming, and IGetFrame.

•	Returns a pointer to the current interface if successful or E_NOINTERFACE otherwise.

ps

Address of an IAVIEditStream, IAVIFile, IAVIStream, IAVIStreaming, or IGetFrame interface.

riid

Identifier of the interface being queried.

ppvObj

Address to contain a pointer to the object whose interface is queried or NULL when an interface is not supported.

For handlers written in C++, QueryInterface has the following syntax:

STDMETHODIMP QueryInterface(const IID FAR& riid, void FAR* ppvObj);


IUnknown::AddRef

ULONG STDMETHODCALLTYPE AddRef(LPUNKNWON ps);

Increments the reference count of the appropriate handler: IAVIEditStream, IAVIFile, IAVIStream, IAVIStreaming, or IGetFrame. When the reference count is nonzero, the handler must retain resources for the file or stream.

•	Returns the resulting reference count.

ps

Address of an IAVIEditStream, IAVIFile, IAVIStream, IAVIStreaming, or IGetFrame interface.

For handlers written in C++, AddRef has the following syntax:

STDMETHODIMP AddRef(VOID);


IUnknown::Release

ULONG STDMETHODCALLTYPE Release(LPUNKNOWN ps);

Decrements the reference count of the appropriate handler: IAVIEditStream, IAVIFile, IAVIStream, IAVIStreaming, or IGetFrame. When the reference count reaches zero, the handler must free resources established for the file or stream.

•	Returns the resulting reference count.

ps

Address of an IAVIEditStream, IAVIFile, IAVIStream, IAVIStreaming, or IGetFrame interface.

For handlers written in C++, Release has the following syntax:

STDMETHODIMP Release(VOID);


DrawDib Functions

The DrawDib functions are a group of functions that provide high performance image-drawing capabilities for device-independent bitmaps (DIBs). DrawDib functions support DIBs of 8-bit, 16-bit, 24-bit, and 32-bit image depths.

DrawDib functions write directly to video memory. They do not rely upon functions of the graphics device interface (GDI).


Do I Need DrawDib?

Collectively, the DrawDib functions are similar to the StretchDIBits function in that they provide image-stretching and dithering capabilities. But, the DrawDib functions support image decompression, data-streaming, and a greater number of display adapters.

You will find it beneficial to use the DrawDib functions in some circumstances. Still, StretchDIBits is more diverse than the DrawDib functions and should be used when the DrawDib functions cannot provide the desired functionality. The following list describes factors to consider when deciding whether to use the DrawDib functions or StretchDIBits.

•	Color table information format. DrawDib functions display images that use the DIB_RGB_COLORS format for their color table. If images in your application store color table information with the DIB_PAL_COLORS or DIB_PAL_INDICES format, you must use StretchDIBits to display them.

•	Transfer mode. DrawDib functions require that your application use the SRCCOPY transfer mode. If your application uses StretchDIBits with a transfer mode other than SRCCOPY, you should continue to use StretchDIBits. Similarly, if you need to use other raster operations in your application, such as an XOR, use StretchDIBits.

•	Quality of video and animation playback. You can use the DrawDib functions for data-streaming applications, such as playing video clips and animated sequences. The DrawDib functions outperform StretchDIBits in that they provide higher-quality images and improve motion during playback.

•	Display adapters. DrawDib functions support a greater number of display adapters than StretchDIBits. The DrawDib functions support VGA color adapters that provide 16-color palettes using 4-bit image depth, SVGA adapters that provide 256-color palettes using 8-bit image depth, and true-color display adapters that provide thousands of colors using 16-bit, 24-bit, and 32-bit image depths.

The DrawDib functions also improve the speed and quality of displaying images on display adapters with more limited capabilities. For example, when using an 8-bit display adapter, the DrawDib functions efficiently dither true-color images to 256 colors. They also dither 8-bit images when using 4-bit display adapters.

•	Image-stretching. Like StretchDIBits, the DrawDib functions use source and destination rectangles to control the portion of an image that is displayed. You can crop unwanted portions of an image or stretch an image by varying the position and size of the source and destination rectangles. If a display driver does not support image-stretching, the DrawDib functions provide more efficient stretching capabilities than StretchDIBits.

•	Compressed images. The DrawDib functions support several compression and decompression methods, including run-length encoding, JPEG, Cinepak, 411 YUV, and Indeo™.


DrawDib Operations

You can access the entire group of DrawDib functions by using the DrawDibOpen function. DrawDibOpen loads the dynamic-link library (DLL), allocates memory resources, creates a DrawDib device context (DC), and maintains a reference count of the number of DCs that are initialized. DrawDibOpen also returns a handle of the new DC that you use with the other DrawDib functions.

You can release a DrawDib DC when you finish using it by using the DrawDibClose function. DrawDibClose also decrements the reference count of the applications accessing the DLL. The call to DrawDibClose should be the last DrawDib function in your application.

You can create as many DrawDib DCs as you want. You can use multiple DrawDib DCs to draw several bitmaps simultaneously. You can also create multiple DrawDib DCs, each with unique characteristics, so your application can choose and then use the DC with the most appropriate settings. For example, you can create two DrawDib DCs in an application, one that displays an image at its normal resolution and the other that displays an enlarged portion of the image.

To run efficiently, DrawDib functions require information about the display adapter and its driver. The display profile is obtained by running a series of tests on the display adapter the first time the DLL containing the DrawDib functions is accessed. The DrawDib functions use this information for all applications. You can repeat these tests when necessary by using the DrawDibProfileDisplay function.

Note  Retrieving and storing the display profile is typically a one-time occurrence. If, however, the profile information deleted or another display driver is installed in the system, DrawDib reruns the tests.


Image Rendering

After you create a DrawDib DC, you can draw a DIB to the screen by using the DrawDibDraw function. DrawDibDraw dithers true-color bitmaps when displaying them with 8-bit display adapters.

DrawDibDraw also supports video compressors transparently when displaying compressed bitmaps. You can access the buffer that contains the decompressed image by using the DrawDibGetBuffer function. DrawDibGetBuffer returns NULL when drawing an uncompressed bitmap. You should prepare your application to handle compressed and uncompressed bitmaps.

You can refresh an image or a portion of an image displayed by your application by using the DrawDibUpdate macro.


Sequences of Images

You can display a sequence of bitmaps with the same dimensions and formats by using the DrawDibDraw function with the DrawDibBegin function. DrawDibBegin improves the efficiency of DrawDibDraw by preparing the DrawDib DC for drawing.

Note  If your application does not use DrawDibBegin, DrawDibDraw implicitly executes it prior to drawing. If your application uses DrawDibBegin prior to DrawDibDraw, DrawDibDraw does not have to process the function and wait for it to complete.

DrawDibBegin provides DrawDibDraw with the DrawDib DC, the DC handle, the address of the BITMAPINFOHEADER structure, and the source and destination rectangle dimensions. When you display a sequence of bitmaps, DrawDibDraw checks the values of these items for each image in the sequence. If DrawDibDraw detects changes to any of these items, it implicitly calls DrawDibBegin again to adjust the DrawDib DC settings.

After using DrawDibBegin, you can draw the image sequence by using DrawDibDraw and specifying one or more flags as appropriate. Specify the DDF_SAME_HDC flag as long as the DC handle has not changed. Specify the DDF_SAME_DRAW flag when the following parameters for DrawDibDraw have not changed: the address of the BITMAPINFOHEADER structure and the source and destination rectangle dimensions.

You can update the flags set with DrawDibBegin by using the DrawDibEnd function followed by another call to DrawDibBegin. DrawDibEnd clears the DrawDib DC of its current flags and settings. The subsequent call to DrawDibBegin reinitializes the DrawDib DC with the appropriate flags and settings. Alternatively, you can update the flags for a DrawDib DC by using DrawDibBegin without DrawDibEnd, as long as you change at least one of the following settings concurrently with the flags: the address of the BITMAPINFOHEADER structure or the source or destination rectangle dimensions.

You can increase the efficiency of DrawDibDraw for data-streaming operations that use compressed images, such as playing a video clip, by using the DrawDibStart and DrawDibStop functions. DrawDibStart prepares the DrawDib DC to receive a stream of images by sending a message to the video compression manager (VCM). When streaming has ended, DrawDibStop sends a message to VCM indicating that it can release resources it allocated for the data-streaming operation. For more information about VCM, see Chapter 7, "Video Compression Manager."

Note  You must specify the width and height of the source and destination rectangles in your application; however, you do not need to specify the origins of the rectangles. Your application can redefine the origins in DrawDibDraw to use different portions of the image or to update different portions of the display.


Palettes

The DrawDib functions require that an application respond to two palette-oriented messages: WM_QUERYNEWPALETTE and WM_PALETTECHANGED. If your application is not palette-aware, you will need to add a handler for each of these messages. For more information about processing the WM_QUERYNEWPALETTE and WM_PALETTECHANGED messages, see "Adding Palette Message Handlers" later in this chapter.

You can realize the current DrawDib palette to the DC by using the DrawDibRealize function. You should realize the palette in response to the WM_QUERYNEWPALETTE or WM_PALETTECHANGED message, or when you prepare to display an image sequence by using the DrawDibDraw function.

You can draw an image mapped to another palette by using the DrawDibSetPalette function. DrawDibSetPalette forces the DrawDib DC to use the specified palette. This can affect the image quality. For example, an application that is palette-aware might have realized a palette and needs to prevent DrawDib from realizing its own palette. The application can use DrawDibSetPalette to notify DrawDib of the palette to use.

You can obtain a handle of the current foreground palette by using the DrawDibGetPalette function. If your application uses the current foreground palette, it does not have exclusive use of the palette and another application can invalidate the palette handle. Your application should not free the palette when you finish using it. Freeing the palette could invalidate the palette handle for another application.

You can prepare DrawDib to receive new color values for its palette by using the DrawDibChangePalette function. In the code following DrawDibChangePalette, you assign new values for the palette color table. If the DDF_ANIMATE flag is not set in the DrawDib DC when you call DrawDibChangePalette, you can enact the palette changes by using DrawDibRealize to realize the palette and by using DrawDibDraw to redraw the image. If the DDF_ANIMATE flag is set in the DrawDib DC, you can animate the palette and the colors of the displayed bitmap by using DrawDibDraw or DrawDibRealize. You can update the DDF_ANIMATE flag by using the DrawDibEnd and DrawDibBegin functions.

Note  If you free the DrawDib palette while it is selected by a DC, a GDI error can result when the DC uses the palette. Instead, your application should use DrawDibSetPalette to change the DrawDib DC to use the default palette or another palette.

The following functions can free the DrawDib palette and should not be used until the palette is not selected by the DC: DrawDibEnd, DrawDibClose, and DrawDibBegin. DrawDibDraw can also free the palette when it uses the same DrawDib DC but specifies different drawing parameters (lpbi, dxDst, dyDst, dxSrc, or dySrc) or a different format.


Timing

As part of debugging an application, you can obtain information about the amount of time it takes to complete repetitive DrawDib operations a specified number of times by using the DrawDibTime function. DrawDibTime returns timing information for the following operations:

•	Drawing a bitmap

•	Decompressing a bitmap

•	Dithering a bitmap

•	Stretching a bitmap

•	Transferring a bitmap by using the BitBlt function

•	Transferring a bitmap by using the StretchDIBits function

After retrieving a set of values, DrawDibTime resets the count and value for each operation.

DrawDibTime is available only in the debug version of the DrawDib functions.


Using DrawDib

This section contains examples demonstrating how to perform the following tasks:

•	Add palette message handlers.

•	Draw a DC.

•	Animate a palette.


Adding Palette Message Handlers

The following example illustrates simple message handlers for the WM_PALETTECHANGED and WM_QUERYNEWPALETTE messages. The example uses the DrawDibRealize function to process the WM_QUERYNEWPALETTE message.

Your application should respond to the WM_QUERYNEWPALETTE message by invalidating the destination window to let the DrawDibDraw function redraw an image. You should respond to the WM_PALETTECHANGED message by using the DrawDibRealize function to realize the palette.

case WM_PALETTECHANGED:

if ((HWND)wParam == hwnd)

break;

case WM_QUERYNEWPALETTE:

hdc = GetDC(hwnd);

f = DrawDibRealize(hdd, hdc, FALSE) > 0;

ReleaseDC(hwnd, hdc);

if (f)

InvalidateRect(hwnd, NULL, TRUE);

break;


Drawing a Display Context

The following example prepares a DrawDib DC by using the DrawDibRealize function prior to displaying several images in a bitmap sequence.

hdc = GetDC(hwnd);

DrawDibBegin(hdd, hdc, dxDest, dyDest, lpbi, dxSrc, dySrc, NULL);

DrawDibRealize(hdd, hdc, fBackground);

DrawDibDraw(hdd, hdc, xDst, yDst, dxDst, dyDst, lpbi, lpBits,

    xSrc, ySrc, dxSrc, dySrc, DDF_SAME_DRAW|DDF_SAME_HDC);

DrawDibDraw(hdd, hdc, xDst, yDst, dxDst, dyDst, lpbi, lpBits,

    xSrc, ySrc, dxSrc, dySrc, DDF_SAME_DRAW|DDF_SAME_HDC);

DrawDibDraw(hdd, hdc, xDst, yDst, dxDst, dyDst, lpbi, lpBits,

    xSrc, ySrc, dxSrc, dySrc, DDF_SAME_DRAW|DDF_SAME_HDC);

ReleaseDC(hwnd, hdc);


Animating a Palette

The following example animates a palette by using the DrawDibRealize, DrawDibChangePalette, and DrawDibDraw functions.

You can change the colors of a bitmap by using the DrawDibBegin function in combination with DrawDibChangePalette. First, allow palette changes by specifying the DDF_ANIMATE flag in the call to DrawDibBegin. Second, set the color table values from the palette entries by using DrawDibChangePalette.

For example, if lppe is an address of the PALETTEENTRY array containing the new colors, and lpbi is the LPBITMAPINFOHEADER structure used in DrawDibBegin or DrawDibDraw, the following fragment updates the DIB color table.

hdc = GetDC(hwnd);

DrawDibBegin(hdd, ....., DDF_ANIMATE);

DrawDibRealize(hdd, hdc, fBackground);

DrawDibDraw(hdd, hdc, ...., DDF_SAME_DRAW|DDF_SAME_HDC);

// Call to change color.

DrawDibChangePalette(hDD, iStart, iLen, lppe);

.

.

.

ReleaseDC(hwnd, hdc);


DrawDib Reference

This section describes the DrawDib functions and associated structures. These elements are grouped as follows:

DrawDib Library Operations

DrawDibOpen
DrawDibClose
DrawDibProfileDisplay

Image Rendering

DrawDibDraw
DrawDibGetBuffer
DrawDibUpdate

Sequences of Images

DrawDibBegin
DrawDibEnd
DrawDibStart
DrawDibStop

Palettes

DrawDibRealize
DrawDibSetPalette
DrawDibGetPalette
DrawDibChangePalette

Timing DrawDib

DRAWDIBTIME
DRAWDIBTIME


DrawDib Function Reference

An application uses DrawDib functions to create and manage a DrawDib DC, display and update images on-screen, manipulate palettes, and to close the DrawDib DC when it's no longer needed. The DrawDib functions also include a timing function and a test function to determine display characteristics.


DrawDibBegin

BOOL DrawDibBegin(HDRAWDIB hdd, HDC hdc, int dxDest, int dyDest,

    LPBITMAPINFOHEADER lpbi, int dxSrc, int dySrc, UINT wFlags);

Changes parameters of a DrawDib DC or initializes a new DrawDib DC.

•	Returns TRUE if successful or FALSE otherwise.

hdd

Handle of a DrawDib DC.

hdc

Handle of a DC for drawing. This parameter is optional.

dxDest and dyDest

Width and height, in MM_TEXT client units, of the destination rectangle.

lpbi

Address of a BITMAPINFOHEADER structure containing the image format. The color table for the DIB follows the image format and the biHeight member must be a positive value.

dxSrc and dySrc

Width and height, in pixels, of the source rectangle.

wFlags

Applicable flags for the function. The following values are defined:

DDF_ANIMATE

Allows palette animation. If this value is present, DrawDib reserves as many entries as possible by setting PC_RESERVED in the palPalEntry members of the LOGPALETTE structure, and the palette can be animated by using the DrawDibChangePalette function. If your application uses the DrawDibBegin function with the DrawDibDraw function, set this value with DrawDibBegin rather than DrawDibDraw.

DDF_BACKGROUNDPAL

Realizes the palette used for drawing as a background task, leaving the current palette used for the display unchanged. (This value is mutually exclusive of DDF_SAME_HDC.)

DDF_BUFFER

Causes DrawDib to try to use an off-screen buffer so DDF_UPDATE can be used. This disables decompression and drawing directly to the screen. If DrawDib is unable to create an off-screen buffer, it will decompress or draw directly to the screen. For more information, see the DDF_UPDATE and DDF_DONTDRAW values described for DrawDibDraw.

DDF_DONTDRAW

Current image is not drawn, but is decompressed. DDF_UPDATE can be used later to draw the image. This flag supercedes the DDF_PREROLL flag.

DDF_FULLSCREEN

Not supported.

DDF_HALFTONE

Always dithers the DIB to a standard palette regardless of the palette of the DIB. If your application uses DrawDibBegin with DrawDibDraw, set this value with DrawDibBegin rather than DrawDibDraw.

DDF_JUSTDRAWIT

Draws the image by using GDI. Prohibits DrawDib functions from decompressing, stretching, or dithering the image. This strips DrawDib of capabilities that differentiate it from the StretchDIBits function.

DDF_SAME_DRAW

Use the current drawing parameters for DrawDibDraw. Use this value only if lpbi, dxDest, dyDest, dxSrc, and dySrc have not changed since using DrawDibDraw or DrawDibBegin. This flag supercedes the DDF_SAME_DIB and DDF_SAME_SIZE flags.

DDF_SAME_HDC

Use the current DC handle and the palette currently associated with the DC.

DDF_UPDATE

Last buffered bitmap needs to be redrawn. If drawing fails with this value, a buffered image is not available and a new image needs to be specified before the display can be updated.

This function prepares to draw a DIB specified by lpbi to the DC. The image
 is stretched to the size specified by dxDest and dyDest. If dxDest and dyDest are set to − 1, the DIB is drawn to a 1:1 scale without stretching.

You can update the flags of a DrawDib DC by reissuing DrawDibBegin, specifying the new flags, and changing at least one of the following settings: dxDest, dyDest, lpbi, dxSrc, or dySrc.

If the parameters of DrawDibBegin have not changed, subsequent calls to the function have no effect.


DrawDibChangePalette

BOOL DrawDibChangePalette(HDRAWDIB hdd, int iStart, int iLen,

    LPPALETTEENTRY lppe);

Sets the palette entries used for drawing DIBs.

•	Returns TRUE if successful or FALSE otherwise.

hdd

Handle of a DrawDib DC.

iStart

Starting palette entry number.

iLen

Number of palette entries.

lppe

Address of an array of palette entries.

This function changes the physical palette only if the current DrawDib palette is realized by calling the DrawDibRealize function.

If the color table is not changed, the next call to the DrawDibDraw function that does not specify DDF_SAME_DRAW calls the DrawDibBegin function implicitly.


DrawDibClose

BOOL DrawDibClose(HDRAWDIB hdd);

Closes a DrawDib DC and frees the resources DrawDib allocated for it.

•	Returns TRUE if successful or FALSE otherwise.

hdd

Handle of a DrawDib DC.


DrawDibDraw

BOOL DrawDibDraw(HDRAWDIB hdd, HDC hdc, int xDst, int yDst, int dxDst,

    int dyDst, LPBITMAPINFOHEADER lpbi, LPVOID lpBits, int xSrc,

    int ySrc, int dxSrc, int dySrc, UINT wFlags);

Draws a DIB to the screen.

•	Returns TRUE if successful or FALSE otherwise.

hdd

Handle of a DrawDib DC.

hdc

Handle of the DC.

xDst and yDst

The x- and y-coordinates, in MM_TEXT client coordinates, of the upper left corner of the destination rectangle.

dxDst and dyDst

Width and height, in MM_TEXT client coordinates, of the destination rectangle. If dxDst is − 1, the width of the bitmap is used. If dyDst is − 1, the height of the bitmap is used.

lpbi

Address of the BITMAPINFOHEADER structure containing the image format. The color table for the DIB within BITMAPINFOHEADER follows the format and the biHeight member must be a positive value; DrawDibDraw will not draw inverted DIBs.

lpBits

Address of the buffer that contains the bitmap bits.

xSrc and ySrc

The x- and y-coordinates, in pixels, of the upper left corner of the source rectangle. The coordinates (0,0) represent the upper left corner of the bitmap.

dxSrc and dySrc

Width and height, in pixels, of the source rectangle.

wFlags

Applicable flags for drawing. The following values are defined:

DDF_BACKGROUNDPAL

Realizes the palette used for drawing in the background, leaving the actual palette used for display unchanged. This value is valid only if DDF_SAME_HDC is not set.

DDF_DONTDRAW

Current image is decompressed but not drawn. This flag supercedes the DDF_PREROLL flag.

DDF_FULLSCREEN

Not supported.

DDF_HALFTONE

Always dithers the DIB to a standard palette regardless of the palette of the DIB. If your application uses the DrawDibBegin function, set this value in DrawDibBegin rather than in DrawDibDraw.

DDF_HURRYUP

Data does not have to be drawn (that is, it can be dropped) and DDF_UPDATE will not be used to recall this information. DrawDib checks this value only if it is required to build the next frame; otherwise, the value is ignored.

This value is usually used to synchronize video and audio. When synchronizing data, applications should send the image with this value in case the driver needs to buffer the frame to decompress subsequent frames.

DDF_NOTKEYFRAME

DIB data is not a key frame.

DDF_SAME_HDC

Use the current DC handle and the palette currently associated with the DC.

DDF_SAME_DRAW

Use the current drawing parameters for DrawDibDraw. Use this value only if lpbi, dxDst, dyDst, dxSrc, and dySrc have not changed since using DrawDibDraw or DrawDibBegin. DrawDibDraw typically checks the parameters, and if they have changed, DrawDibBegin prepares the DrawDib DC for drawing. This flag supercedes the DDF_SAME_DIB and DDF_SAME_SIZE flags.

DDF_UPDATE

Last buffered bitmap is to be redrawn. If drawing fails with this value, a buffered image is not available and a new image needs to be specified before the display can be updated.

DDF_DONTDRAW causes DrawDibDraw to decompress but not display an image. A subsequent call to DrawDibDraw specifying DDF_UPDATE displays the image.

If the DrawDib DC does not have an off-screen buffer specified, specifying DDF_DONTDRAW causes the frame to be drawn to the screen immediately. Subsequent calls to DrawDibDraw specifying DDF_UPDATE fail.

Although they are set at different times, DDF_UPDATE and DDF_DONTDRAW can be used together to create composite images off-screen. When the off-screen image is complete, you can display the image by calling DrawDibDraw.


DrawDibEnd

BOOL DrawDibEnd(HDRAWDIB hdd);

Clears the flags and other settings of a DrawDib DC that are set by the DrawDibBegin or DrawDibDraw functions.

•	Returns TRUE if successful or FALSE otherwise.

hdd

Handle of the DrawDib DC to free.


DrawDibGetBuffer

LPVOID DrawDibGetBuffer(HDRAWDIB hdd, LPBITMAPINFOHEADER lpbi,

    DWORD dwSize, DWORD dwFlags);

Retrieves the location of the buffer used by DrawDib for decompression.

•	Returns the address of the buffer or NULL if no buffer is used. If lpbi is not NULL, it is filled with a copy of the BITMAPINFO structure describing the buffer.

hdd

Handle of a DrawDib DC.

lpbi

Address of a BITMAPINFO structure. This structure is made up of a BITMAPINFOHEADER structure and a 256-entry table defining the colors used by the bitmap.

dwSize

Size, in bytes, of the BITMAPINFO structure pointed to by lpbi

dwFlags

Reserved; must be zero.


DrawDibGetPalette

HPALETTE DrawDibGetPalette(HDRAWDIB hdd);

Retrieves the palette used by a DrawDib DC.

•	Returns a handle of the palette if successful or NULL otherwise.

hdd

Handle of a DrawDib DC.

This function assumes the DrawDib DC contains a valid palette entry, implying that a call to this function must follow calls to the DrawDibDraw or DrawDibBegin functions.

You should rarely need to call this function because you can realize the correct palette in response to a window message by using the DrawDibRealize function.


DrawDibOpen

HDRAWDIB DrawDibOpen(VOID);

Opens the DrawDib library for use and creates a DrawDib DC for drawing.

•	Returns a handle of a DrawDib DC if successful or NULL otherwise.

When drawing multiple DIBs simultaneously, create a DrawDib DC for each of the images that will be simultaneously on-screen.


DrawDibProfileDisplay

BOOL DrawDibProfileDisplay(LPBITMAPINFOHEADER lpbi);

Determines settings for the display system when using DrawDib functions.

•	Returns a value that indicates the fastest drawing and stretching capabilities of the display system. This value can be zero if the bitmap format is not supported, or one or more of the following flags:

PD_CAN_DRAW_DIB	DrawDib can draw images using this format. Stretching might or might not also be supported.
PD_CAN_STRETCHDIB	DrawDib can stretch and draw images using this format.
PD_STRETCHDIB_1_1_OK	StretchDIBits draws unstretched images using this format faster than an alternative method.
PD_STRETCHDIB_1_2_OK	StretchDIBits draws stretched images (in a 1:2 ratio) using this format faster than an alternative method.
PD_STRETCHDIB_1_N_OK	StretchDIBits draws stretched images (in a 1:N ratio) using this format faster than an alternative method.
lpbi

Address of a BITMAPINFOHEADER structure that contains bitmap information. You can also specify NULL to verify that the profile information is current. If the profile information is not current, DrawDib will rerun the profile tests to obtain a current set of information. When you call DrawDibProfileDisplay with this parameter set to NULL, the return value is meaningless.


DrawDibRealize

UINT DrawDibRealize(HDRAWDIB hdd, HDC hdc, BOOL fBackground);

Realizes the palette of the DrawDib DC for use with the specified DC.

•	Returns the number of entries in the logical palette mapped to different values in the system palette. If an error occurs or no colors were updated, it returns zero.

hdd

Handle of a DrawDib DC.

hdc

Handle of the DC containing the palette.

fBackground

Background palette flag. If this value is nonzero, the palette is a background palette. If this value is zero and the DC is attached to a window, the logical palette becomes the foreground palette when the window has the input focus. (A DC is attached to a window when the window class style is CS_OWNDC or when the DC is obtained by using the GetDC function.)

To select the palette of the DrawDib DC as a background palette, use the DrawDibDraw function and specify the DDF_BACKGROUNDPAL flag.


DrawDibSetPalette

BOOL DrawDibSetPalette(HDRAWDIB hdd, HPALETTE hpal);

Sets the palette used for drawing DIBs.

•	Returns TRUE if successful or FALSE otherwise.

hdd

Handle of a DrawDib DC.

hpal

Handle of the palette. Specify NULL to use the default palette.


DrawDibStart

BOOL DrawDibStart(HDRAWDIB hdd, LONG rate);

Prepares a DrawDib DC for streaming playback.

•	Returns TRUE if successful or FALSE otherwise.

hdd

Handle of a DrawDib DC.

rate

Playback rate, in microseconds per frame.


DrawDibStop

BOOL DrawDibStop(HDRAWDIB hdd);

Frees the resources used by a DrawDib DC for streaming playback.

•	Returns TRUE if successful or FALSE otherwise.

hdd

Handle of a DrawDib DC.


DrawDibTime

BOOL DrawDibTime(HDRAWDIB hdd, LPDRAWDIBTIME lpddtime);

Retrieves timing information about the drawing operation and is used during debug operations.

•	Returns TRUE if successful or FALSE otherwise.

hdd

Handle of a DrawDib DC.

lpddtime

Address of a DRAWDIBTIME structure.

This function is present only in the debug version of the Win32 Software Development Kit libraries.


DrawDibUpdate

BOOL DrawDibUpdate(HDRAWDIB hdd, HDC hdc, int xDst, int yDst);

Draws the last frame in the DrawDib off-screen buffer.

•	Returns TRUE if successful or FALSE otherwise.

hdd

Handle of a DrawDib DC.

hdc

Handle of the DC.

xDst and yDst

The x- and y-coordinates, in MM_TEXT client coordinates, of the upper left corner of the destination rectangle.

The DrawDibUpdate macro is defined as follows:

#define DrawDibUpdate( hdd, hdc, x, y) \

    DrawDibDraw( hdd, hdc, x, y, 0, 0, NULL, NULL, 0, 0, \

    0, 0, DDF_UPDATE)

This macro can be used to refresh an image or a portion of an image displayed by your application.


DrawDib Structure

The DrawDib functions use three structures: DRAWDIBTIME, BITMAPINFO, and BITMAPINFOHEADER. The description for DRAWDIBTIME follows. For full descriptions of BITMAPINFO and BITMAPINFOHEADER, see the Microsoft Win32 Programmer's Reference, Volume 5.


DRAWDIBTIME

typedef struct {

    LONG timeCount;       // see below

    LONG timeDraw;        // time to draw bitmaps

    LONG timeDecompress;  // time to decompress bitmaps

    LONG timeDither;      // time to dither bitmaps

    LONG timeStretch;     // time to stretch bitmaps

    LONG timeBlt;         // time to transfer bitmaps (BitBlt)

    LONG timeSetDIBits;   // time to transfer bitmaps (SetDIBits)

}   DRAWDIBTIME, *LPDRAWDIBTIME;

Contains elapsed timing information for performing a set of DrawDib operations. The DrawDibTime function resets the count and the elapsed time value for each operation each time it is called.

timeCount

Number of times the following operations have been performed since DrawDibTime was last called:

•	Draw a bitmap on the screen.

•	Decompress a bitmap.

•	Dither a bitmap.

•	Stretch a bitmap.

•	Transfer bitmap data by using the BitBlt function.

•	Transfer bitmap data by using the SetDIBits function.


Waveform Audio

This chapter explains how to use the waveform and auxiliary audio services of the Microsoft Win32 application programming interface (API) to add sound to applications.

Adding sound to your application can make it more efficient and more fun to use. You can improve your users' efficiency by using sounds to get their attention at critical points, to help them avoid mistakes, or to let them know that a time-consuming operation has finished. You can help them have more fun by adding music or sound effects.

This chapter explains how to do the following things with sound:

•	Play waveform audio.

•	Use low-level audio services.

•	Record waveform audio.

•	Use auxiliary audio devices.

•	Use audio clipboard formats.

This chapter documents several methods for adding sound to your application. The simplest method documented here is using the PlaySound function. Most of the other waveform-audio API elements documented in this chapter are relatively low-level, however. Part Two of this volume, "Media Control Interface," documents a mid-level interface to multimedia programming that offers a simpler and faster method of adding sound to your application than using the low-level sound API.


The PlaySound Function

You can use the PlaySound function to play waveform audio, as long as the sound fits into available memory. (The sndPlaySound function offers a subset of the capabilities of PlaySound. To maximize the portability of your Win32 application, use PlaySound, not sndPlaySound.)

PlaySound allows you to specify a sound in one of three ways:

•	As a system alert, using the alias stored in the WIN.INI file or the registry

•	As a filename

•	As a resource identifier

One PlaySound capability allows you to play a sound in a continuous loop, ending only when you call PlaySound again, specifying either NULL or the sound identifier of another sound for the pszSound parameter.

You can use PlaySound to play the sound synchronously or asynchronously, and to control the behavior of the function in other ways when it must share system resources.

For examples of how to use PlaySound in your Win32 applications, see "Playing WAVE Resources" later in this chapter.


Waveform-Audio Files

In the Microsoft Windows operating system, most waveform-audio files use the .WAV filename extension.

The following statement plays the C:\SOUNDS\BELLS.WAV file:

PlaySound("C:\\SOUNDS\\BELLS.WAV", NULL, SND_SYNC);

If the specified file does not exist, or if the file does not fit into the available memory, PlaySound plays the default system sound. If no default system sound has been defined, PlaySound fails without producing any sound. If you do not want the default system sound to play, specify the SND_NODEFAULT flag, as shown in the following example:

PlaySound("C:\\SOUNDS\\BELLS.WAV", NULL, SND_SYNC | SND_NODEFAULT);


Looping Sounds

If you specify the SND_LOOP and SND_ASYNC flags for the fdwSound parameter of the PlaySound function, the sound will continue to play repeatedly as shown in the following example:

PlaySound("C:\\SOUNDS\\BELLS.WAV", NULL, SND_LOOP | SND_ASYNC);

If you want to loop a sound, you must play it asynchronously; you cannot use the SND_SYNC flag with the SND_LOOP flag. A looped sound will continue to play until PlaySound is called to play another sound. To stop playing a sound (looped or asynchronous) without playing another sound, use the following statement:

PlaySound(NULL, NULL, 0);


Playing Sounds Specified in the Registry

The PlaySound function will also play sounds referred to by a keyname in the registry. This allows users to assign their own sounds to system alerts and warnings, or to user actions, such as a mouse button click. Sounds that are associated with system alerts and warnings are called sound events.

To play a sound event, call PlaySound with the pszSound parameter pointing to a string containing the name of the registry entry that identifies the sound. For example, to play the sound associated with the "MouseClick" entry and to wait for the sound to complete before returning, use the following statement:

PlaySound("MouseClick", NULL, SND_SYNC);

If the specified registry entry or the waveform-audio file it identifies does not exist, or if the file does not fit into the available memory, PlaySound plays the default system sound.

The sound events that are predefined by the system can vary with the Win32 platform. The following list gives the sound events that are defined for all Win32 implementations:

SystemAsterisk

SystemExclamation

SystemExit

SystemHand

SystemQuestion

SystemStart

If an application registers its own sound events, the user can configure the sound event by using the standard Control Panel interface. The application should register the sound event by using the standard registry functions; for more information about the registry, see Chapter 52, "Registry." The entries belong at the same position in the registry hierarchy as the rest of the sound events. This position varies with the Win32 implementation. The appropriate data value also varies with the implementation.

The sndPlaySound function always searches the registry for a keyname matching lpszSound before attempting to load a file with this name. PlaySound accepts flags that specify the location of the sound.


Low-Level Audio Interface

This section documents the low-level audio interface, which is used by applications that need the finest possible control over audio devices. The functions and structures of this interface are named with the prefix "wave".


Devices and Data Types

This section discusses working with waveform-audio devices, such as how to open, close and query them for their capabilities. It also describes how to keep track of the devices in a system by using device handles and device identifiers.

Opening Waveform-Audio Output Devices

Use the waveOutOpen function to open a waveform-audio output device for playback. This function opens the device associated with the given device identifier and returns a handle of the open device by writing the handle of a specified memory location.

Some multimedia computers have multiple waveform-audio output devices. Unless you know you want to open a specific waveform-audio output device in a system, you should use the WAVE_MAPPER flag for the device identifier when you open a device. The waveOutOpen function chooses the device in the system that is best able to play the given data format.

Querying Audio Devices

Windows provides the following functions to determine how many devices of a certain type are available in a given system.

Function	Description
auxGetNumDevs	Retrieves the number of auxiliary output devices present in the system.
waveInGetNumDevs	Retrieves the number of waveform-audio input devices present in the system.
waveOutGetNumDevs	Retrieves the number of waveform-audio output devices present in the system.
Audio devices are identified by a device identifier. The device identifier is determined implicitly from the number of devices present in a given system. Device identifiers range from zero to one less than the number of devices present. For example, if there are two waveform-audio output devices in a system, valid device identifiers are 0 and 1.

After you determine how many devices of a certain type are present in a system, you can use one of the following functions to query the capabilities of each device.

Function	Description
auxGetDevCaps	Retrieves the capabilities of a given auxiliary output device.
waveInGetDevCaps	Retrieves the capabilities of a given waveform-audio input device.
waveOutGetDevCaps	Retrieves the capabilities of a given waveform-audio output device.
Each of these functions fills a structure with information about the capabilities of a specified device. The following table lists the structures that correspond to each of these functions.

Function	Structure
auxGetDevCaps	AUXCAPS
waveInGetDevCaps	WAVEINCAPS
waveOutGetDevCaps	WAVEOUTCAPS
Waveform-audio devices can support nonstandard formats. (Standard formats are listed in the dwFormats member of the WAVEOUTCAPS structure, later in this chapter.) To determine whether a particular format (standard or nonstandard) is supported by a device, you can call the waveOutOpen function with the WAVE_FORMAT_QUERY flag. This flag does not open the device. You specify the format in question in the WAVEFORMATEX structure pointed to by the pwfx parameter passed to waveOutOpen. For information about setting up this structure, see "Devices and Data Types" earlier in this chapter.

Waveform-audio output devices vary in the capabilities they support. The dwSupport member of the WAVEOUTCAPS structure indicates whether a given device supports such capabilities as volume and pitch changes.

Device Handles and Device Identifiers

Each function that opens an audio device specifies a device identifier, a pointer to a memory location, and some parameters that are unique to each type of device. The memory location is filled with a device handle. Use this device handle to identify the open audio device when calling other audio functions.

The difference between identifiers and handles for audio devices is subtle but important:

•	Device identifiers are determined implicitly from the number of devices present in a system. This number is obtained by using the auxGetNumDevs, waveInGetNumDevs, or waveOutGetNumDevs function.

•	Device handles are returned when device drivers are opened by using the waveInOpen or waveOutOpen function.

There are no functions for opening and closing auxiliary audio devices. Auxiliary audio devices need not be opened and closed like waveform-audio devices because there is no continuous data transfer associated with them. All auxiliary audio functions use device identifiers to identify devices.

Waveform-Audio Output Data Types

The following data types are defined for waveform-audio output functions.

Type	Description
HWAVEOUT	Handle of an open waveform-audio output device.
WAVEFORMATEX	Structure that specifies the data formats supported by a particular waveform-audio input device. This structure is used also for waveform-audio input devices.
WAVEHDR	Structure used as a header for a block of waveform-audio input data. This structure is also used for waveform-audio input devices.
WAVEOUTCAPS	Structure used to query the capabilities of a particular waveform-audio output device.
Specifying Waveform-Audio Data Formats

When you call the waveOutOpen function to open a device driver for playback or to query whether the driver supports a particular data format, use the pwfx parameter to specify a pointer to a WAVEFORMATEX structure containing the requested waveform-audio data format. The WAVEFORMATEX structure is an extended version of the WAVEFORMAT structure. It contains all the members of WAVEFORMAT, and adds two more: a wBitsPerSample member, which contains extra information required for the PCM (Pulse Code Modulation) format, and a cbSize member at the end. You can append data to the structure following cbSize as long as you fill cbSize with the size of the data. You can use the WAVEFORMATEX structure to describe PCM data, although you could also use the PCMWAVEFORMAT structure. When the waveform-audio format type is not PCM, you must use WAVEFORMATEX instead of WAVEFORMAT.

The outmoded WAVEFORMAT structure does not contain all the information required to describe the PCM format. The PCMWAVEFORMAT structure includes a WAVEFORMAT structure along with an additional member containing PCM-specific information. The PCMWAVEFORMAT structure has also been superseded by the WAVEFORMATEX structure.

There are also two clipboard formats you can use to represent audio data: CF_WAVE and CF_RIFF. Use the CF_WAVE format to represent data in one of the standard formats, such as 11 kHz or 22 kHz PCM. Use the CF_RIFF format to represent more complex data formats that cannot be represented as standard waveform-audio files.

Writing Waveform-Audio Data

After successfully opening a waveform-audio output device driver, you can begin playing a sound. Windows provides the waveOutWrite function for sending data blocks to waveform-audio output devices.

Use the WAVEHDR structure to specify the waveform-audio data block you are sending using waveOutWrite. This structure contains a pointer to a locked data block, the length of the data block, and some flags. This data block must be prepared before you use it; for information about preparing a data block, see "Audio Data Blocks" later in this chapter.

After you send a data block to an output device by using waveOutWrite, you must wait until the device driver is finished with the data block before freeing it. If you are sending multiple data blocks, you must monitor the completion of data blocks to know when to send additional blocks. For more information about data blocks, see "Audio Data Blocks" later in this chapter.

PCM Waveform-Audio Data Format

The lpData member of the WAVEHDR structure points to the waveform-audio data samples. For 8-bit PCM data, each sample is represented by a single unsigned data byte. For 16-bit PCM data, each sample is represented by a 16-bit signed value. The following table summarizes the maximum, minimum, and midpoint values for PCM waveform-audio data.

Data format	Maximum value	Minimum value	Midpoint value
8-bit PCM	255 (0xFF)	0	128 (0x80)
16-bit PCM	32,767 (0x7FFF)	− 32,768 (0x8000)	0
PCM Data Packing

The order of the data bytes varies between 8-bit and 16-bit formats and between mono and stereo formats. The following list describes data packing for the different PCM waveform-audio data formats.

PCM waveform-audio format	Description
8-bit mono	Each sample is 1 byte that corresponds to a single audio channel. Sample 1 is followed by samples 2, 3, 4, and so on.
8-bit stereo	Each sample is 2 bytes. Sample 1 is followed by samples 2, 3, 4, and so on. For each sample, the first byte is channel 0 (the left channel) and the second byte is channel 1 (the right channel).
16-bit mono	Each sample is 2 bytes. Sample 1 is followed by samples 2, 3, 4, and so on. For each sample, the first byte is the low-order byte of channel 0 and the second byte is the high-order byte of channel 0.
16-bit stereo	Each sample is 4 bytes. Sample 1 is followed by samples 2, 3, 4, and so on. For each sample, the first byte is the low-order byte of channel 0 (left channel); the second byte is the high-order byte of channel 0; the third byte is the low-order byte of channel 1 (right channel); and the fourth byte is the high-order byte of channel 1.
Closing Waveform-Audio Output Devices

After waveform-audio playback is complete, call waveOutClose to close the output device. If waveOutClose is called while a waveform-audio file is playing, the close operation fails and the function returns an error code indicating that the device was not closed. If you do not want to wait for playback to end before closing the device, call the waveOutReset function before closing. This ends playback and allows the device to be closed. Be sure to use the waveOutUnprepareHeader function to clean up the preparation on all data blocks before closing the device.


Playing Waveform-Audio Files

It's easy to play sounds in your application by using the functions, macros, and messages discussed in this chapter. The techniques and API elements documented here operate only on waveform audio; that is, digitized representations of a sound's physical shape. If you want to add music to your application, and you do not care about other kinds of sounds, you might want to use MIDI. For a discussion of a simple playback MIDI implementation, see Chapter 2, "Getting Started Using MCIWnd." For a discussion of the low-level MIDI interface, see Chapter 13, "Musical Instrument Digital Interface (MIDI)."

You can use the following functions to play waveform audio in your application in a single function call:

Function	Description
MessageBeep	Plays the sound that corresponds to a given system-alert level.
sndPlaySound	Plays the sound that corresponds to the system sound entered in the registry or the contents of the given filename.
PlaySound	Provides all of the functionality of sndPlaySound and can directly access resources.
The MessageBeep function is a standard part of the Win32 API; because its capabilities are very limited and it is documented elsewhere, it is not discussed here.

The functions in this list provide the following methods of playing waveform audio:

•	Playing waveform-audio files associated with system-alert levels

•	Playing waveform-audio files specified by entries in the registry

•	Playing in-memory WAVE resources

•	Playing waveform-audio files stored on a hard disk or compact disc − read-only memory (CD-ROM)

The sndPlaySound and PlaySound functions load an entire waveform-audio file into memory and, in effect, limit the size of file they can play. Use sndPlaySound and PlaySound to play waveform-audio files that are relatively small — up to about 100K. These two functions also require the sound data to be in a format that is playable by one of the installed waveform-audio drivers, including the wave mapper.

For larger sound files, use the Media Control Interface (MCI) services or the low-level audio API. For information on using MCI, see Chapter 3, "MCI Overview."

Using Window Messages to Manage Waveform-Audio Playback

The following messages can be sent to a window procedure function for managing waveform-audio playback.

Message	Description
MM_WOM_CLOSE	Sent when the device is closed by using the waveOutClose function.
MM_WOM_DONE	Sent when the device driver is finished with a data block sent by using the waveOutWrite function.
MM_WOM_OPEN	Sent when the device is opened by using the waveOutOpen function.
A wParam and lParam parameter is associated with each of these messages. The wParam parameter always specifies a handle of the open waveform-audio device. For the MM_WOM_DONE message, lParam specifies a pointer to a WAVEHDR structure that identifies the completed data block. The lParam parameter is unused for the MM_WOM_CLOSE and MM_WOM_OPEN messages.

The most useful message is probably MM_WOM_DONE. When this message signals that playback of a data block is complete, you can clean up and free the data block. Unless you need to allocate memory or initialize variables, you probably do not need to process the MM_WOM_OPEN and MM_WOM_CLOSE messages.

The callback function for waveform-audio output devices is supplied by the application. For information about this callback function, see the waveOutProc function, later in this chapter.

Retrieving the Current Playback Position

You can monitor the current playback position within the file while waveform audio is playing by using the waveOutGetPosition function.

For waveform-audio devices, samples are the preferred time format in which to represent the current position. Thus, the current position of a waveform-audio device is specified as the number of samples for one channel from the beginning of the waveform-audio file. To query the current position of a waveform-audio device, set the wType member of the MMTIME structure to TIME_SAMPLES and pass this structure to waveOutGetPosition.

The MMTIME structure can represent time in one or more different formats, including milliseconds, samples, SMPTE (Society of Motion Picture and Television Engineers), and MIDI song pointer formats. The wType member specifies the format used to represent time. Before calling a function that uses the MMTIME structure, you must set wType to indicate your requested time format. Be sure to check wType after the call to see whether the requested time format is supported. If the requested time format is not supported, the device driver specifies the time in an alternate time format and changes the wType member to the selected time format.

For more information about the MMTIME structure, see Chapter 17, "Timers."

Stopping, Pausing, and Restarting Playback

You can stop or pause playback while waveform audio is playing. After playback has been paused, you can restart it. Windows provides the following functions for controlling waveform-audio playback.

Function	Description
waveOutPause	Pauses playback on a waveform-audio output device.
waveOutReset	Stops playback on a waveform-audio output device and marks all pending data blocks as done.
waveOutRestart	Resumes playback on a paused waveform-audio output device.
Pausing a waveform-audio device by using waveOutPause might not be instantaneous; the driver can finish playing the current block before pausing playback.

Generally, as soon as the first waveform-audio data block is sent by using the waveOutWrite function, the waveform-audio device begins playing. If you do not want the sound to start playing immediately, call waveOutPause before calling waveOutWrite. Then, when you want to begin playing the waveform, call waveOutRestart.

You cannot use waveOutRestart to restart a device that has been stopped with waveOutReset; you must use waveOutWrite to send the first data block to resume playback on the device.

Looping Playback

Looping a sound is controlled by the dwLoops and dwFlags members in the WAVEHDR structures passed to the device with the waveOutWrite function. Use the WHDR_BEGINLOOP and WHDR_ENDLOOP flags in the dwFlags member to specify the beginning and ending data blocks for looping.

To loop a single data block, specify both flags for the same block. To specify the number of loops, use the dwLoops member in the WAVEHDR structure for the first block in the loop.

You can call the waveOutBreakLoop function to stop a looping sound.

Changing the Volume of Waveform-Audio Playback

Windows provides the following functions to query and set the volume level of waveform-audio output devices.

Function	Description
waveOutGetVolume	Retrieves the current volume level of the specified waveform-audio output device.
waveOutSetVolume	Sets the volume level of the specified waveform-audio output device.
Not all waveform-audio devices support volume changes. Some devices support individual volume control on both the left and right channels. For information about how to determine the volume-control capabilities of waveform-audio devices, see "Devices and Data Types" earlier in this chapter.

Some applications allow the user to control the volume for all audio devices in a system. (Many applications of this type use the audio mixer services; for more information, see Chapter 14, "Audio Mixers.") Unless your application is capable of this kind of master volume control, you should open an audio device before changing its volume. You should also query the volume level before changing it and restore the volume level to its previous level as soon as possible.

Volume is specified in a doubleword value. When the audio format is stereo, the upper 16 bits specify the relative volume of the right channel and the lower 16 bits specify the relative volume of the left channel. For devices that do not support left- and right-channel volume control, the lower 16 bits specify the volume level, and the upper 16 bits are ignored.

Volume-level values range from 0x0 (silence) to 0xFFFF (maximum volume) and are interpreted logarithmically. The perceived volume increase is the same when increasing the volume level from 0x5000 to 0x6000 as it is from 0x4000 to 0x5000.

Changing Pitch and Playback Rate

Some waveform-audio output devices can vary the pitch and the playback rate of waveform-audio data. Not all waveform-audio devices support pitch and playback-rate changes. For information about how to determine whether a particular waveform-audio device supports pitch and playback rate changes, see "Devices and Data Types" earlier in this chapter.

The differences between changing pitch and playback rate are as follows:

•	Changing the playback rate is performed by the device driver and does not require specialized hardware. The sample rate is not changed, but the driver interpolates by skipping or synthesizing samples. For example, if the playback rate is changed by a factor of two, the driver skips every other sample.

•	Changing the pitch requires specialized hardware. The playback rate and sample rate are not changed.

Windows provides the following functions to query and set waveform-audio pitch and playback rates.

Function	Description
waveOutGetPitch	Retrieves the pitch for the specified waveform-audio output device.
waveOutGetPlaybackRate	Retrieves the playback rate for the specified waveform-audio output device.
waveOutSetPitch	Sets the pitch for the specified waveform-audio output device.
waveOutSetPlaybackRate	Sets the playback rate for the specified waveform-audio output device.
The pitch and playback rates are changed by a factor specified with a fixed-point number packed into a doubleword value. The upper 16 bits specify the integer part of the number; the lower 16 bits specify the fractional part. For example, the value 1.5 is represented as 0x00018000L. The value 0.75 is represented as 0x0000C000L. A value of 1.0 (0x00010000) means the pitch or playback rate is unchanged.


Recording Waveform Audio

If the MCI waveform-audio recording services do not meet the needs of your application, you can handle waveform-audio recording using the low-level waveform-audio services. For more information about MCI, see Chapter 3, "MCI Overview."

Waveform-Audio Input Data Types

The following data types are defined for waveform-audio input functions:

Type	Description
HWAVEIN	Handle of an open waveform-audio input device.
WAVEFORMATEX	Structure that specifies the data formats supported by a particular waveform-audio input device. This structure is also used for waveform-audio output devices.
WAVEHDR	Structure used as a header for a block of waveform-audio input data. This structure is also used for waveform-audio output devices.
WAVEINCAPS	Structure used to inquire about the capabilities of a particular waveform-audio input device.
Querying Waveform-Audio Input Devices

Before recording waveform audio, you should call the waveInGetDevCaps function to determine the waveform-audio input capabilities of the system. This function fills a WAVEINCAPS structure with information about the capabilities of a given device. This information includes the manufacturer and product identifiers, a product name for the device, and the version number of the device driver. In addition, the WAVEINCAPS structure provides information about the standard waveform-audio formats that the device supports.

Opening Waveform-Audio Input Devices

Use the waveInOpen function to open a waveform-audio input device for recording. This function opens the device associated with the given device identifier and returns a handle of the open device by writing the handle of a specified memory location.

Some multimedia computers have multiple waveform-audio input devices. Unless you know you want to open a specific waveform-audio input device in a system, you should use the WAVE_MAPPER constant for the device identifier when you open a device. The waveInOpen function will choose the device in the system best able to record in the given data format.

Managing Waveform-Audio Recording

After you open a waveform-audio input device, you can begin recording waveform-audio data. Waveform-audio data is recorded into application-supplied buffers specified by a WAVEHDR structure. These data blocks must be prepared before they are used; for more information, see "Audio Data Blocks" later in this chapter.

Windows provides the following functions to manage waveform-audio recording.

Function	Description
waveInAddBuffer	Sends a buffer to the device driver so it can be filled with recorded waveform-audio data.
waveInReset	Stops waveform-audio recording and marks all pending buffers as done.
waveInStart	Starts waveform-audio recording.
waveInStop	Stops waveform-audio recording.
Use the waveInAddBuffer function to send buffers to the device driver. As the buffers are filled with recorded waveform-audio data, the application is notified with a window message, callback message, thread message, or event, depending on the flag specified when the device was opened.

Before you begin recording by using waveInStart, you should send at least one buffer to the driver, or incoming data might be lost.

Before closing the device using waveInClose, call waveInReset to mark any pending data blocks as being done.

Using Window Messages to Manage Waveform-Audio Recording

The following messages can be sent to a window procedure function for managing waveform-audio recording.

Message	Description
MM_WIM_CLOSE	Sent when the device is closed by using the waveInClose function.
MM_WIM_DATA	Sent when the device driver is finished with a buffer sent by using the waveInAddBuffer function.
MM_WIM_OPEN	Sent when the device is opened by using the waveInOpen function.
The lParam parameter of MM_WIM_DATA specifies a pointer to a WAVEHDR structure that identifies the buffer. This buffer might not be completely filled with waveform-audio data; recording can stop before the buffer is filled. Use the dwBytesRecorded member of the WAVEHDR structure to determine the amount of valid data present in the buffer.

The most useful message is probably MM_WIM_DATA. When your application finishes using the data block sent by the device driver, you can clean up and free the data block. Unless you need to allocate memory or initialize variables, you probably do not need to use the MM_WIM_OPEN and MM_WIM_CLOSE messages.

The callback function for waveform-audio input devices is supplied by the application. For information about this callback function, see the waveInProc function, later in this chapter.


Auxiliary Audio Interface

Auxiliary audio devices are audio devices whose output is mixed with the MIDI and waveform-audio output devices in a multimedia computer. An example of an auxiliary audio device is the CD audio output from a CD-ROM drive.


Querying Auxiliary Audio Devices

Not all multimedia systems have auxiliary audio support. You can use the auxGetNumDevs function to determine the number of controllable auxiliary devices present in a system.

To get information about a particular auxiliary audio device, use the auxGetDevCaps function. This function fills an AUXCAPS structure with information about the capabilities of a given device. This information includes the manufacturer and product identifiers, a product name for the device, and the device-driver version number.


Changing the Volume of Auxiliary Audio-Devices

Windows provides the following functions to query and set the volume for auxiliary audio devices.

Function	Description
auxGetVolume	Retrieves the current volume setting of the specified auxiliary output device.
auxSetVolume	Sets the volume of the specified auxiliary output device.
Not all auxiliary audio devices support volume changes. Some devices can support individual volume changes on both the left and the right channels.

Volume is specified in a doubleword value, as with the waveform-audio and MIDI volume-control functions . When the audio format is stereo, the upper 16 bits specify the relative volume of the right channel and the lower 16 bits specify the relative volume of the left channel. For devices that do not support left- and right-channel volume control, the lower 16 bits specify the volume level, and the upper 16 bits are ignored.

Volume-level values range from 0x0 (silence) to 0xFFFF (maximum volume) and are interpreted logarithmically. The perceived volume increase is the same when increasing the volume level from 0x5000 to 0x6000 as it is from 0x4000 to 0x5000.


Audio Data Blocks

The waveInAddBuffer and waveOutWrite functions require applications to allocate data blocks to pass to the device drivers for recording or playback purposes. Each of these functions uses the WAVEHDR structure to describe its data block.

Before using one of these functions to pass a data block to a device driver, you must allocate memory for the data block and the header structure that describes the data block. The headers can be prepared and unprepared by using the following functions.

Function	Description
waveInPrepareHeader	Prepares a waveform-audio input data block.
waveInUnprepareHeader	Cleans up the preparation on a waveform-audio input data block.
waveOutPrepareHeader	Prepares a waveform-audio output data block.
waveOutUnprepareHeader	Cleans up the preparation on a waveform-audio output data block.
Before you pass an audio data block to a device driver, you must prepare the data block by passing it to either waveInPrepareHeader or waveOutPrepareHeader. When the device driver is finished with the data block and returns it, you must clean up this preparation by passing the data block to either waveInUnprepareHeader or waveOutUnprepareHeader before any allocated memory can be freed.

Unless the waveform-audio input and output data is small enough to be contained in a single data block, applications must continually supply the device driver with data blocks until playback or recording is complete.

Even if a single data block is used, an application must be able to determine when a device driver is finished with the data block so the application can free the memory associated with the data block and header structure. There are several ways to determine when a device driver is finished with a data block:

•	By specifying a callback function to receive a message sent by the driver when it is finished with a data block

•	By using an event callback

•	By specifying a window or thread to receive a message sent by the driver when it is finished with a data block

•	By polling the WHDR_DONE bit in the dwFlags member of the WAVEHDR structure sent with each data block

If an application does not get a data block to the device driver when needed, there can be an audible gap in playback or a loss of incoming recorded information. This requires at least a double-buffering scheme — staying at least one data block ahead of the device driver.

The following sections describe ways to determine when a device driver is finished with a data block.


Using a Callback Function to Process Driver Messages

You can write your own callback function to process messages sent by the device driver. To use a callback function, specify the CALLBACK_FUNCTION flag in the fdwOpen parameter and the address of the callback in the dwCallback parameter of the waveInOpen or waveOutOpen function.

Messages sent to a callback function are similar to messages sent to a window, except they have two DWORD parameters instead of a UINT and a DWORD parameter. For details on these messages, see "Playing Waveform-Audio Files" earlier in this chapter.

To pass instance data from an application to a callback function, use one of the following techniques:

•	Pass the instance data using the dwInstance parameter of the function that opens the device driver.

•	Pass the instance data using the dwUser member of the WAVEHDR structure that identifies an audio data block being sent to a device driver.

If you need more than 32 bits of instance data, pass a pointer to a structure containing the additional information.


Using an Event Callback to Process Driver Messages

To use an event callback, use the CreateEvent function to retrieve the handle of an event. In the call to the waveOutOpen function, specify CALLBACK_EVENT for the fdwOpen parameter. After calling the waveOutPrepareHeader function but before sending waveform-audio data to the device, create a nonsignalled event by calling the ResetEvent function, specifying the event handle retrieved by CreateEvent. Then, inside a loop that checks whether the WHDR_DONE bit is set in the dwFlags member of the WAVEHDR structure, call the WaitForSingleObject function, specifying as parameters the event handle and a time-out value of INFINITE.

An event callback is set by anything that might cause a function callback.

Because event callbacks do not receive specific close, done, or open notifications, an application might have to check the status of the process it is waiting for after the event occurs. It is possible that a number of tasks could have been completed by the time WaitForSingleObject returns.


Using a Window or Thread to Process Driver Messages

To use a window callback function, specify the CALLBACK_WINDOW flag in the fdwOpen parameter and a window handle in the low-order word of the dwCallback parameter of the waveInOpen or waveOutOpen function. Driver messages will be sent to the window procedure for the window identified by the handle in dwCallback.

Similarly, to use a thread callback, specify CALLBACK_THREAD and a thread handle in the call to waveInOpen or waveOutOpen. In this case, messages are posted to the specified thread instead of to a window.

Messages sent to the window or thread callback are specific to the audio device type used. For more information about these messages, see "Playing Waveform-Audio Files" earlier in this chapter.


Managing Data Blocks by Polling

In addition to using a callback function, you can poll the dwFlags member of a WAVEHDR structure to determine when an audio device is finished with a data block. Sometimes it is better to poll dwFlags than to wait for another mechanism to receive messages from the drivers. For example, after you call the waveOutReset function to release pending data blocks, you can immediately poll to be sure that the data blocks are done before calling waveOutUnprepareHeader and freeing the memory for the data block.

You can use the WHDR_DONE flag to test the dwFlags member. As soon as the WHDR_DONE flag is set in the dwFlags member of the WAVEHDR structure, the driver is finished with the data block.


Handling Errors with Audio Functions

The waveform-audio and auxiliary-audio functions return a nonzero value when an error occurs. Windows provides functions that convert these error values into textual descriptions of the errors. The application must still examine the error values to determine how to proceed, but textual descriptions of errors can be used in dialog boxes that describe errors to users.

You can use the following functions to retrieve textual descriptions of audio error values:

Function	Description
waveInGetErrorText	Retrieves a textual description of a specified waveform-audio input error.
waveOutGetErrorText	Retrieves a textual description of a specified waveform-audio output error.
The only audio functions that do not return error values are auxGetNumDevs,  waveInGetNumDevs, and waveOutGetNumDevs. These functions return zero if no devices are present in a system or if they encounter any errors.


Using Waveform and Auxiliary Audio

This section demonstrates implementing waveform and auxiliary audio in your application. The following topics are discussed:

•	Playing WAVE resources

•	Determining support for nonstandard data formats

•	Processing the MM_WOM_DONE message


Playing WAVE Resources

You can use the PlaySound function to play a sound that is stored as a resource. Although this is also possible using the sndPlaySound function, sndPlaySound requires you to find, load, lock, unlock, and free the resource; PlaySound achieves all of this with a single line of code.

PlaySound("SoundName", hInst, SND_RESOURCE | SND_ASYNC);


Determining Nonstandard Format Support

To see whether a device supports a particular format (standard or nonstandard), you can call the waveOutOpen function with the WAVE_FORMAT_QUERY flag. The following example uses this technique to determine whether a given waveform-audio device supports a given format.

// Determines whether the given waveform-audio output device supports a

// given waveform-audio format. Returns MMSYSERR_NOERROR if the format

// is supported, WAVEERR_BADFORMAT if the format is not supported, and

// one of the other MMSYSERR_ error codes if there are other errors

// encountered in opening the given waveform-audio device.

MMRESULT IsFormatSupported(LPWAVEFORMATEX pwfx, UINT uDeviceID) {

    return (waveOutOpen(

        NULL,                 // ptr can be NULL for query

        uDeviceID,            // the device identifier

        pwfx,                 // defines requested format

        NULL,                 // no callback

        NULL,                 // no instance data

        WAVE_FORMAT_QUERY));  // query only, do not open device

}

This technique for determining nonstandard format support also applies to waveform-audio input devices. The only difference is that the waveInOpen function is used in place of waveOutOpen to query for format support.

To determine whether a particular waveform-audio data format is supported by any of the waveform-audio devices in a system, use the technique illustrated in the previous example, but specify the WAVE_MAPPER constant for the uDeviceID parameter.


Processing the MM_WOM_DONE Message

The following example shows how to process the MM_WOM_DONE message. This example assumes the application does not play multiple data blocks, so it can close the output device after playing a single data block.

// WndProc--Main window procedure.

LRESULT FAR PASCAL WndProc(HWND hWnd, UINT msg, WPARAM wParam,

    LPARAM lParam)

{

    switch (msg)

    {

    .

    .

    .

case MM_WOM_DONE:

    // A waveform-audio data block has been played and

    // can now be freed.

    waveOutUnprepareHeader((HWAVEOUT) wParam,

        (LPWAVEHDR) lParam, sizeof(WAVEHDR) );

    .

    . // Free hData memory.

    .

    waveOutClose((HWAVEOUT) wParam);

    break;

    }

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

}


Waveform Audio Reference

This section describes the functions, messages, and structures associated with waveform audio. These elements are grouped as follows.

Auxiliary Devices

AUXCAPS
auxGetDevCaps
auxGetNumDevs
auxGetVolume
auxOutMessage
auxSetVolume

Easy Playback

PlaySound
sndPlaySound

Errors

waveInGetErrorText
waveOutGetErrorText

Opening and Closing

PCMWAVEFORMAT
MM_WIM_CLOSE
MM_WIM_OPEN
MM_WOM_CLOSE
MM_WOM_OPEN
WAVEFORMAT
WAVEFORMATEX
waveInClose
waveInProc
waveInOpen
waveOutClose
waveOutProc
waveOutOpen
WIM_CLOSE
WIM_OPEN
WOM_CLOSE
WOM_OPEN

Pitch

waveOutGetPitch
waveOutSetPitch

Playback Rate

waveOutGetPlaybackRate
waveOutSetPlaybackRate

Playback Progress

MM_WOM_DONE
waveOutBreakLoop
waveOutPause
waveOutReset
waveOutRestart
WOM_DONE

Playing

MM_WOM_DONE
WAVEHDR
waveOutPrepareHeader
waveOutUnprepareHeader
waveOutWrite
WOM_DONE

Querying a Device

WAVEINCAPS
waveInGetDevCaps
waveInGetNumDevs
WAVEOUTCAPS
waveOutGetDevCaps
waveOutGetNumDevs

Recording

MM_WIM_DATA
waveInAddBuffer
waveInPrepareHeader
waveInReset
waveInStart
waveInStop
waveInUnprepareHeader
WIM_DATA

Retrieving Device Identifiers

waveInGetID
waveOutGetID

Retrieving the Current Position

waveInGetPosition
waveOutGetPosition

Sending Custom Messages

waveInMessage
waveOutMessage

Volume

waveOutGetVolume
waveOutSetVolume


auxGetDevCaps

MMRESULT auxGetDevCaps(UINT uDeviceID, LPAUXCAPS lpCaps, UINT cbCaps);

Retrieves the capabilities of a given auxiliary output device.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_BADDEVICEID	Specified device identifier is out of range.
uDeviceID

Identifier of the auxiliary output device to be queried. Specify a valid device identifier (see the following comments section), or use the following constant:

AUX_MAPPER

Auxiliary audio mapper. The function returns an error if no auxiliary audio mapper is installed.

lpCaps

Address of an AUXCAPS structure to be filled with information about the capabilities of the device.

cbCaps

Size, in bytes, of the AUXCAPS structure.

The device identifier in uDeviceID varies from zero to one less than the number of devices present. AUX_MAPPER may also be used. Use the auxGetNumDevs function to determine the number of auxiliary output devices present in the system.


auxGetNumDevs

UINT auxGetNumDevs(VOID);

Retrieves the number of auxiliary output devices present in the system.

•	Returns the number of devices. A return value of zero means that no devices are present or that an error occurred.


auxGetVolume

MMRESULT auxGetVolume(UINT uDeviceID, LPDWORD lpdwVolume);

Retrieves the current volume setting of the specified auxiliary output device.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_BADDEVICEID	Specified device identifier is out of range.
uDeviceID

Identifier of the auxiliary output device to be queried.

lpdwVolume

Address of a variable to be filled with the current volume setting. The low-order word of this location contains the left channel volume setting, and the high-order word contains the right channel setting. A value of 0xFFFF represents full volume, and a value of 0x0000 is silence.

If a device does not support both left and right volume control, the low-order word of the specified location contains the volume level.

The full 16-bit setting(s) set with the auxSetVolume function are returned, regardless of whether the device supports the full 16 bits of volume-level control.

Not all devices support volume control. To determine whether a device supports volume control, use the AUXCAPS_VOLUME flag to test the dwSupport member of the AUXCAPS structure (filled by the auxGetDevCaps function).

To determine whether a device supports volume control on both the left and right channels, use the AUXCAPS_LRVOLUME flag to test the dwSupport member of the AUXCAPS structure (filled by auxGetDevCaps).


auxOutMessage

DWORD auxOutMessage(UINT uDeviceID, UINT uMsg, DWORD dwParam1,

    DWORD dwParam2);

Sends a message to the given auxiliary output device. This function also performs error checking on the device identifier passed as part of the message.

•	Returns the message return value.

uDeviceID

Identifier of the auxiliary output device to receive the message.

uMsg

Message to send.

dwParam1 and dwParam2

Message parameters.


auxSetVolume

MMRESULT auxSetVolume(UINT uDeviceID, DWORD dwVolume);

Sets the volume of the specified auxiliary output device.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_BADDEVICEID	Specified device identifier is out of range.
uDeviceID

Identifier of the auxiliary output device to be queried. Device identifiers are determined implicitly from the number of devices present in the system. Device identifier values range from zero to one less than the number of devices present. Use the auxGetNumDevs function to determine the number of auxiliary devices in the system.

dwVolume

Specifies the new volume setting. The low-order word specifies the left-channel volume setting, and the high-order word specifies the right-channel setting. A value of 0xFFFF represents full volume, and a value of 0x0000 is silence.

If a device does not support both left and right volume control, the low-order word of dwVolume specifies the volume level, and the high-order word is ignored.

Not all devices support volume control. To determine whether the device supports volume control, use the AUXCAPS_VOLUME flag to test the dwSupport member of the AUXCAPS structure (filled by the auxGetDevCaps function).

To determine whether the device supports volume control on both the left and right channels, use the AUXCAPS_LRVOLUME flag to test the dwSupport member of the AUXCAPS structure (filled by auxGetDevCaps).

Most devices do not support the full 16 bits of volume-level control and will use only the high-order bits of the requested volume setting. For example, for a device that supports 4 bits of volume control, requested volume level values of 0x4000, 0x4FFF, and 0x43BE will produce the same physical volume setting, 0x4000. The auxGetVolume function will return the full 16-bit setting set with auxSetVolume.

Volume settings are interpreted logarithmically. This means the perceived volume increase is the same when increasing the volume level from 0x5000 to 0x6000 as it is from 0x4000 to 0x5000.


PlaySound

BOOL PlaySound(LPCSTR pszSound, HMODULE hmod, DWORD fdwSound);

Plays a sound specified by the given filename, resource, or system event. (A system event may be associated with a sound in the registry or in the WIN.INI file.)

•	Returns TRUE if successful or FALSE otherwise.

pszSound

A string that specifies the sound to play. If this parameter is NULL, any currently playing waveform sound is stopped. To stop a non-waveform sound, specify SND_PURGE in the fdwSound parameter.

Three flags in fdwSound (SND_ALIAS, SND_FILENAME, and SND_RESOURCE) determine whether the name is interpreted as an alias for a system event, a filename, or a resource identifier. If none of these flags are specified, PlaySound searches the registry or the WIN.INI file for an association with the specified sound name. If an association is found, the sound event is played. If no association is found in the registry, the name is interpreted as a filename.

hmod

Handle of the executable file that contains the resource to be loaded. This parameter must be NULL unless SND_RESOURCE is specified in fdwSound.

fdwSound

Flags for playing the sound. The following values are defined:

SND_APPLICATION

The sound is played using an application-specific association.

SND_ALIAS

The pszSound parameter is a system-event alias in the registry or the WIN.INI file. Do not use with either SND_FILENAME or SND_RESOURCE.

SND_ALIAS_ID

The pszSound parameter is a predefined sound identifier.

SND_ASYNC

The sound is played asynchronously and PlaySound returns immediately after beginning the sound. To terminate an asynchronously played waveform sound, call PlaySound with pszSound set to NULL.

SND_FILENAME

The pszSound parameter is a filename.

SND_LOOP

The sound plays repeatedly until PlaySound is called again with the pszSound parameter set to NULL. You must also specify the SND_ASYNC flag to indicate an asynchronous sound event.

SND_MEMORY

A sound event's file is loaded in RAM. The parameter specified by pszSound must point to an image of a sound in memory.

SND_NODEFAULT

No default sound event is used. If the sound cannot be found, PlaySound returns silently without playing the default sound.

SND_NOSTOP

The specified sound event will yield to another sound event that is already playing. If a sound cannot be played because the resource needed to generate that sound is busy playing another sound, the function immediately returns FALSE without playing the requested sound.

If this flag is not specified, PlaySound attempts to stop the currently playing sound so that the device can be used to play the new sound.

SND_NOWAIT

If the driver is busy, return immediately without playing the sound.

SND_PURGE

Sounds are to be stopped for the calling task. If pszSound is not NULL, all instances of the specified sound are stopped. If pszSound is NULL, all sounds that are playing on behalf of the calling task are stopped.

You must also specify the instance handle to stop SND_RESOURCE events.

SND_RESOURCE

The pszSound parameter is a resource identifier; hmod must identify the instance that contains the resource.

SND_SYNC

Synchronous playback of a sound event. PlaySound returns after the sound event completes.

The sound specified by pszSound must fit into available physical memory and be playable by an installed waveform-audio device driver. PlaySound searches the following directories for sound files: the current directory; the Windows directory; the Windows system directory; directories listed in the PATH environment variable; and the list of directories mapped in a network. For more information about the directory search order, see the documentation for the OpenFile function.

If it cannot find the specified sound, PlaySound uses the default system event sound entry instead. If the function can find neither the system default entry nor the default sound, it makes no sound and returns FALSE.


sndAlias

DWORD sndAlias(ch0, ch1)

Creates an alias identifier from two characters, for use with the PlaySound function.

•	Returns an alias identifier corresponding to the two supplied characters.

ch0 and ch1

Characters describing the sound alias.

This macro is defined as follows:

sndAlias(ch0, ch1)    (SND_ALIAS_START + (DWORD)(BYTE)(ch0) |

    ((DWORD)(BYTE)(ch1) << 8))


sndPlaySound

BOOL sndPlaySound(LPCSTR lpszSound, UINT fuSound);

Plays a waveform sound specified either by a filename or by an entry in the registry or the WIN.INI file. This function offers a subset of the functionality of the PlaySound function; sndPlaySound is being maintained for backward compatibility.

•	Returns TRUE if successful or FALSE otherwise.

lpszSound

A string that specifies the sound to play. This parameter can be either an entry in the registry or in WIN.INI that identifies a system sound, or it can be the name of a waveform-audio file. (If the function does not find the entry, the parameter is treated as a filename.) If this parameter is NULL, any currently playing sound is stopped.

fuSound

Flags for playing the sound. The following values are defined:

SND_ASYNC

The sound is played asynchronously and the function returns immediately after beginning the sound. To terminate an asynchronously played sound, call sndPlaySound with lpszSoundName set to NULL.

SND_LOOP

The sound plays repeatedly until sndPlaySound is called again with the lpszSoundName parameter set to NULL. You must also specify the SND_ASYNC flag to loop sounds.

SND_MEMORY

The parameter specified by lpszSoundName points to an image of a waveform sound in memory.

SND_NODEFAULT

If the sound cannot be found, the function returns silently without playing the default sound.

SND_NOSTOP

If a sound is currently playing, the function immediately returns FALSE, without playing the requested sound.

SND_SYNC

The sound is played synchronously and the function does not return until the sound ends.

If the specified sound cannot be found, sndPlaySound plays the system default sound. If there is no system default entry in the registry or WIN.INI file, or if the default sound cannot be found, the function makes no sound and returns FALSE.

The specified sound must fit in available physical memory and be playable by an installed waveform-audio device driver. If sndPlaySound does not find the sound in the current directory, the function searches for it using the standard directory-search order.


waveInAddBuffer

MMRESULT waveInAddBuffer(HWAVEIN hwi, LPWAVEHDR pwh, UINT cbwh);

Sends an input buffer to the given waveform-audio input device. When the buffer is filled, the application is notified.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALHANDLE	Specified device handle is invalid.
MMSYSERR_NODRIVER	No device driver is present.
MMSYSERR_NOMEM	Unable to allocate or lock memory.
WAVERR_UNPREPARED	The buffer pointed to by the pwh parameter hasn't been prepared.
hwi

Handle of the waveform-audio input device.

pwh

Address of a WAVEHDR structure that identifies the buffer.

cbwh

Size, in bytes, of the WAVEHDR structure.

When the buffer is filled, the WHDR_DONE bit is set in the dwFlags member of the WAVEHDR structure.

The buffer must be prepared with the waveInPrepareHeader function before it is passed to this function.


waveInClose

MMRESULT waveInClose(HWAVEIN hwi);

Closes the given waveform-audio input device.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALHANDLE	Specified device handle is invalid.
MMSYSERR_NODRIVER	No device driver is present.
MMSYSERR_NOMEM	Unable to allocate or lock memory.
WAVERR_STILLPLAYING	There are still buffers in the queue.
hwi

Handle of the waveform-audio input device. If the function succeeds, the handle is no longer valid after this call.

If there are input buffers that have been sent with the waveInAddBuffer function and that haven't been returned to the application, the close operation will fail. Call the waveInReset function to mark all pending buffers as done.


waveInGetDevCaps

MMRESULT waveInGetDevCaps(UINT uDeviceID, LPWAVEINCAPS pwic,

    UINT cbwic);

Retrieves the capabilities of a given waveform-audio input device.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error include the following:

MMSYSERR_BADDEVICEID	Specified device identifier is out of range.
MMSYSERR_NODRIVER	No device driver is present.
MMSYSERR_NOMEM	Unable to allocate or lock memory.
uDeviceID

Identifier of the waveform-audio output device. It can be either a device identifier or a handle of an open waveform-audio input device.

pwic

Address of a WAVEINCAPS structure to be filled with information about the capabilities of the device.

cbwic

Size, in bytes, of the WAVEINCAPS structure.

Use this function to determine the number of waveform-audio input devices present in the system. If the value specified by the uDeviceID parameter is a device identifier, it can vary from zero to one less than the number of devices present. The WAVE_MAPPER constant can also be used as a device identifier. Only cbwic bytes (or less) of information is copied to the location pointed to by pwic. If cbwic is zero, nothing is copied and the function returns zero.


waveInGetErrorText

MMRESULT waveInGetErrorText(MMRESULT mmrError, LPSTR pszText,

    UINT cchText);

Retrieves a textual description of the error identified by the given error number.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_BADERRNUM	Specified error number is out of range.
MMSYSERR_NODRIVER	No device driver is present.
MMSYSERR_NOMEM	Unable to allocate or lock memory.
mmrError

Error number.

pszText

Address of the buffer to be filled with the textual error description.

cchText

Size, in characters, of the buffer pointed to by pszText.

If the textual error description is longer than the specified buffer, the description is truncated. The returned error string is always null-terminated. If cchText is zero, nothing is copied and the function returns zero. All error descriptions are less than MAXERRORLENGTH characters long.


waveInGetID

MMRESULT waveInGetID(HWAVEIN hwi, LPUINT puDeviceID);

Gets the device identifier for the given waveform-audio input device.

This function is supported for backward compatibility. New applications can cast a handle of the device rather than retrieving the device identifier.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALHANDLE	The hwi parameter specifies an invalid handle.
MMSYSERR_NODRIVER	No device driver is present.
MMSYSERR_NOMEM	Unable to allocate or lock memory.
hwi

Handle of the waveform-audio input device.

puDeviceID

Address of a variable to be filled with the device identifier.


waveInGetNumDevs

UINT waveInGetNumDevs(VOID);

Returns the number of waveform-audio input devices present in the system.

•	Returns the number of devices. A return value of zero means that no devices are present or that an error occurred.


waveInGetPosition

MMRESULT waveInGetPosition(HWAVEIN hwi, LPMMTIME pmmt, UINT cbmmt);

Retrieves the current input position of the given waveform-audio input device.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALHANDLE	Specified device handle is invalid.
MMSYSERR_NODRIVER	No device driver is present.
MMSYSERR_NOMEM	Unable to allocate or lock memory.
hwi

Handle of the waveform-audio input device.

pmmt

Address of an MMTIME structure.

cbmmt

Size, in bytes, of the MMTIME structure.

Before calling this function, set the wType member of the MMTIME structure to indicate the time format you want. After calling this function, check wType to determine whether the desired time format is supported. If the format is not supported, the member will specify an alternative format.

The position is set to zero when the device is opened or reset.


waveInMessage

DWORD waveInMessage(HWAVEIN hwi, UINT uMsg, DWORD dwParam1,

    DWORD dwParam2);

Sends messages to the waveform-audio input device drivers.

•	Returns the value returned from the driver.

hwi

Handle of the waveform-audio input device.

uMsg

Message to send.

dwParam1 and dwParam2

Message parameters.


waveInOpen

MMRESULT waveInOpen(LPHWAVEIN phwi, UINT uDeviceID, LPWAVEFORMATEX pwfx,

    DWORD dwCallback, DWORD dwCallbackInstance, DWORD fdwOpen);

Opens the given waveform-audio input device for recording.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_ALLOCATED	Specified resource is already allocated.
MMSYSERR_BADDEVICEID	Specified device identifier is out of range.
MMSYSERR_NODRIVER	No device driver is present.
MMSYSERR_NOMEM	Unable to allocate or lock memory.
WAVERR_BADFORMAT	Attempted to open with an unsupported waveform-audio format.
phwi

Address filled with a handle identifying the open waveform-audio input device. Use this handle to identify the device when calling other waveform-audio input functions. This parameter can be NULL if WAVE_FORMAT_QUERY is specified for fdwOpen.

uDeviceID

Identifier of the waveform-audio input device to open. It can be either a device identifier or a handle of an open waveform-audio input device.You can use the following flag instead of a device identifier:

WAVE_MAPPER

The function selects a waveform-audio input device capable of recording in the specified format.

pwfx

Address of a WAVEFORMATEX structure that identifies the desired format for recording waveform-audio data. You can free this structure immediately after waveInOpen returns.

dwCallback

Address of a fixed callback function, an event handle, or a handle of a window or thread called during waveform-audio recording to process messages related to the progress of recording. If no callback function is required, this value can be zero.

dwCallbackInstance

User-instance data passed to the callback mechanism. This parameter is not used with the window callback mechanism.

fdwOpen

Flags for opening the device. The following values are defined:

CALLBACK_EVENT

The dwCallback parameter is an event handle.

CALLBACK_FUNCTION

The dwCallback parameter is a callback procedure address.

CALLBACK_NULL

No callback mechanism. This is the default setting.

CALLBACK_THREAD

The dwCallback parameter is a thread handle.

CALLBACK_WINDOW

The dwCallback parameter is a window handle.

WAVE_FORMAT_QUERY

The function queries the device to determine whether it supports the given format, but it does not open the device.

WAVE_MAPPED

The uDeviceID parameter specifies a waveform-audio device to be mapped to by the wave mapper.

Use the waveInGetNumDevs function to determine the number of waveform-audio input devices present on the system. The device identifier specified by uDeviceID varies from zero to one less than the number of devices present. The WAVE_MAPPER constant can also be used as a device identifier.

If you choose to have a window or thread receive callback information, the following messages are sent to the window procedure or thread to indicate the progress of waveform-audio input: MM_WIM_OPEN, MM_WIM_CLOSE, and MM_WIM_DATA.

If you choose to have a function receive callback information, the following messages are sent to the function to indicate the progress of waveform-audio input: WIM_OPEN, WIM_CLOSE, and WIM_DATA.


waveInPrepareHeader

MMRESULT waveInPrepareHeader(HWAVEIN hwi, LPWAVEHDR pwh, UINT cbwh);

Prepares a buffer for waveform-audio input.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALHANDLE	Specified device handle is invalid.
MMSYSERR_NODRIVER	No device driver is present.
MMSYSERR_NOMEM	Unable to allocate or lock memory.
hwi

Handle of the waveform-audio input device.

pwh

Address of a WAVEHDR structure that identifies the buffer to be prepared.

cbwh

Size, in bytes, of the WAVEHDR structure.

The lpData, dwBufferLength, and dwFlags members of the WAVEHDR structure must be set before calling this function (dwFlags must be zero).


waveInProc

void CALLBACK waveInProc(HWAVEIN hwi, UINT uMsg, DWORD dwInstance,

    DWORD dwParam1, DWORD dwParam2);

Callback function used with the waveform-audio input device. This function is a placeholder for the application-defined function name.

hwi

Handle of the waveform-audio device associated with the callback function.

uMsg

Waveform-audio input message. It can be one of the following messages:

WIM_CLOSE

Sent when the device is closed using the waveInClose function.

WIM_DATA

Sent when the device driver is finished with a data block sent using the waveInAddBuffer function.

WIM_OPEN

Sent when the device is opened using the waveInOpen function.

dwInstance

User instance data specified with waveInOpen.

dwParam1 and dwParam2

Message parameters.

Applications should not call any system-defined functions from inside a callback function, except for PostMessage, timeGetSystemTime, timeGetTime, timeSetEvent, timeKillEvent, midiOutShortMsg, midiOutLongMsg, and OutputDebugStr.


waveInReset

MMRESULT waveInReset(HWAVEIN hwi);

Stops input on the given waveform-audio input device and resets the current position to zero. All pending buffers are marked as done and returned to the application.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALHANDLE	Specified device handle is invalid.
MMSYSERR_NODRIVER	No device driver is present.
MMSYSERR_NOMEM	Unable to allocate or lock memory.
hwi

Handle of the waveform-audio input device.


waveInStart

MMRESULT waveInStart(HWAVEIN hwi);

Starts input on the given waveform-audio input device.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALHANDLE	Specified device handle is invalid.
MMSYSERR_NODRIVER	No device driver is present.
MMSYSERR_NOMEM	Unable to allocate or lock memory.
hwi

Handle of the waveform-audio input device.

Buffers are returned to the application when full or when the waveInReset function is called (the dwBytesRecorded member in the header will contain the length of data). If there are no buffers in the queue, the data is thrown away without notifying the application, and input continues.

Calling this function when input is already started has no effect, and the function returns zero.


waveInStop

MMRESULT waveInStop(HWAVEIN hwi);

Stops waveform-audio input.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALHANDLE	Specified device handle is invalid.
MMSYSERR_NODRIVER	No device driver is present.
MMSYSERR_NOMEM	Unable to allocate or lock memory.
hwi

Handle of the waveform-audio input device.

If there are any buffers in the queue, the current buffer will be marked as done (the dwBytesRecorded member in the header will contain the length of data), but any empty buffers in the queue will remain there.

Calling this function when input is not started has no effect, and the function returns zero.


waveInUnprepareHeader

MMRESULT waveInUnprepareHeader(HWAVEIN hwi, LPWAVEHDR pwh, UINT cbwh);

Cleans up the preparation performed by the waveInPrepareHeader function. This function must be called after the device driver fills a buffer and returns it to the application. You must call this function before freeing the buffer.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALHANDLE	Specified device handle is invalid.
MMSYSERR_NODRIVER	No device driver is present.
MMSYSERR_NOMEM	Unable to allocate or lock memory.
WAVERR_STILLPLAYING	The buffer pointed to by the pwh parameter is still in the queue.
hwi

Handle of the waveform-audio input device.

pwh

Address of a WAVEHDR structure identifying the buffer to be cleaned up.

cbwh

Size, in bytes, of the WAVEHDR structure.

This function complements the waveInPrepareHeader function.

You must call this function before freeing the buffer. After passing a buffer to the device driver with the waveInAddBuffer function, you must wait until the driver is finished with the buffer before calling waveInUnprepareHeader. Unpreparing a buffer that has not been prepared has no effect, and the function returns zero.


waveOutBreakLoop

MMRESULT waveOutBreakLoop(HWAVEOUT hwo);

Breaks a loop on the given waveform-audio output device and allows playback to continue with the next block in the driver list.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALHANDLE	Specified device handle is invalid.
MMSYSERR_NODRIVER	No device driver is present.
MMSYSERR_NOMEM	Unable to allocate or lock memory.
hwo

Handle of the waveform-audio output device.

The blocks making up the loop are played to the end before the loop is terminated.

Calling this function when nothing is playing or looping has no effect, and the function returns zero.


waveOutClose

MMRESULT waveOutClose(HWAVEOUT hwo);

Closes the given waveform-audio output device.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALHANDLE	Specified device handle is invalid.
MMSYSERR_NODRIVER	No device driver is present.
MMSYSERR_NOMEM	Unable to allocate or lock memory.
WAVERR_STILLPLAYING	There are still buffers in the queue.
hwo

Handle of the waveform-audio output device. If the function succeeds, the handle is no longer valid after this call.

If the device is still playing a waveform-audio file, the close operation fails. Use the waveOutReset function to terminate playback before calling waveOutClose.


waveOutGetDevCaps

MMRESULT waveOutGetDevCaps(UINT uDeviceID, LPWAVEOUTCAPS pwoc,

    UINT cbwoc);

Retrieves the capabilities of a given waveform-audio output device.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_BADDEVICEID	Specified device identifier is out of range.
MMSYSERR_NODRIVER	No device driver is present.
MMSYSERR_NOMEM	Unable to allocate or lock memory.
uDeviceID

Identifier of the waveform-audio output device. It can be either a device identifier or a handle of an open waveform-audio output device.

pwoc

Address of a WAVEOUTCAPS structure to be filled with information about the capabilities of the device.

cbwoc

Size, in bytes, of the WAVEOUTCAPS structure.

Use the waveOutGetNumDevs function to determine the number of waveform-audio output devices present in the system. If the value specified by the uDeviceID parameter is a device identifier, it can vary from zero to one less than the number of devices present. The WAVE_MAPPER constant can also be used as a device identifier. Only cbwoc bytes (or less) of information is copied to the location pointed to by pwoc. If cbwoc is zero, nothing is copied and the function returns zero.


waveOutGetErrorText

MMRESULT waveOutGetErrorText(MMRESULT mmrError, LPSTR pszText,

    UINT cchText);

Retrieves a textual description of the error identified by the given error number.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_BADERRNUM	Specified error number is out of range.
MMSYSERR_NODRIVER	No device driver is present.
MMSYSERR_NOMEM	Unable to allocate or lock memory.
mmrError

Error number.

pszText

Address of a buffer to be filled with the textual error description.

cchText

Size, in characters, of the buffer pointed to by pszText.

If the textual error description is longer than the specified buffer, the description is truncated. The returned error string is always null-terminated. If cchText is zero, nothing is copied and the function returns zero. All error descriptions are less than MAXERRORLENGTH characters long.


waveOutGetID

MMRESULT waveOutGetID(HWAVEOUT hwo, LPUINT puDeviceID);

Retrieves the device identifier for the given waveform-audio output device.

This function is supported for backward compatibility. New applications can cast a handle of the device rather than retrieving the device identifier.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALHANDLE	The hwo parameter specifies an invalid handle.
MMSYSERR_NODRIVER	No device driver is present.
MMSYSERR_NOMEM	Unable to allocate or lock memory.
hwo

Handle of the waveform-audio output device.

puDeviceID

Address of a variable to be filled with the device identifier.


waveOutGetNumDevs

UINT waveOutGetNumDevs(VOID);

Retrieves the number of waveform-audio output devices present in the system.

•	Returns the number of devices. A return value of zero means that no devices are present or that an error occurred.


waveOutGetPitch

MMRESULT waveOutGetPitch(HWAVEOUT hwo, LPDWORD pdwPitch);

Retrieves the current pitch setting for the specified waveform-audio output device.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALHANDLE	Specified device handle is invalid.
MMSYSERR_NODRIVER	No device driver is present.
MMSYSERR_NOMEM	Unable to allocate or lock memory.
MMSYSERR_NOTSUPPORTED	Function isn't supported.
hwo

Handle of the waveform-audio output device.

pdwPitch

Address of a variable to be filled with the current pitch multiplier setting. The pitch multiplier indicates the current change in pitch from the original authored setting. The pitch multiplier must be a positive value.

The pitch multiplier is specified as a fixed-point value. The high-order word of the variable contains the signed integer part of the number, and the low-order word contains the fractional part. A value of 0x8000 in the low-order word represents one-half, and 0x4000 represents one-quarter. For example, the value 0x00010000 specifies a multiplier of 1.0 (no pitch change), and a value of 0x000F8000 specifies a multiplier of 15.5.

Changing the pitch does not change the playback rate, sample rate, or playback time. Not all devices support pitch changes. To determine whether the device supports pitch control, use the WAVECAPS_PITCH flag to test the dwSupport member of the WAVEOUTCAPS structure (filled by the waveOutGetDevCaps function).


waveOutGetPlaybackRate

MMRESULT waveOutGetPlaybackRate(HWAVEOUT hwo, LPDWORD pdwRate);

Retrieves the current playback rate for the specified waveform-audio output device.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALHANDLE	Specified device handle is invalid.
MMSYSERR_NODRIVER	No device driver is present.
MMSYSERR_NOMEM	Unable to allocate or lock memory.
MMSYSERR_NOTSUPPORTED	Function isn't supported.
hwo

Handle of the waveform-audio output device.

pdwRate

Address of a variable to be filled with the current playback rate. The playback rate setting is a multiplier indicating the current change in playback rate from the original authored setting. The playback rate multiplier must be a positive value.

The rate is specified as a fixed-point value. The high-order word of the variable contains the signed integer part of the number, and the low-order word contains the fractional part. A value of 0x8000 in the low-order word represents one-half, and 0x4000 represents one-quarter. For example, the value 0x00010000 specifies a multiplier of 1.0 (no playback rate change), and a value of 0x000F8000 specifies a multiplier of 15.5.

Changing the playback rate does not change the sample rate but does change the playback time. Not all devices support playback rate changes. To determine whether a device supports playback rate changes, use the WAVECAPS_PLAYBACKRATE flag to test the dwSupport member of the WAVEOUTCAPS structure (filled by the waveOutGetDevCaps function).


waveOutGetPosition

MMRESULT waveOutGetPosition(HWAVEOUT hwo, LPMMTIME pmmt, UINT cbmmt);

Retrieves the current playback position of the given waveform-audio output device.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALHANDLE	Specified device handle is invalid.
MMSYSERR_NODRIVER	No device driver is present.
MMSYSERR_NOMEM	Unable to allocate or lock memory.
hwo

Handle of the waveform-audio output device.

pmmt

Address of an MMTIME structure.

cbmmt

Size, in bytes, of the MMTIME structure.

Before calling this function, set the wType member of the MMTIME structure to indicate the time format you want. After calling this function, check wType to determine whether the time format is supported. If the format is not supported, wType will specify an alternative format.

The position is set to zero when the device is opened or reset.


waveOutGetVolume

MMRESULT waveOutGetVolume(HWAVEOUT hwo, LPDWORD pdwVolume);

Retrieves the current volume level of the specified waveform-audio output device.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALHANDLE	Specified device handle is invalid.
MMSYSERR_NODRIVER	No device driver is present.
MMSYSERR_NOMEM	Unable to allocate or lock memory.
MMSYSERR_NOTSUPPORTED	Function isn't supported.
hwo

Handle of an open waveform-audio output device.

pdwVolume

Address of a variable to be filled with the current volume setting. The low-order word of this location contains the left-channel volume setting, and the high-order word contains the right-channel setting. A value of 0xFFFF represents full volume, and a value of 0x0000 is silence.

If a device does not support both left and right volume control, the low-order word of the specified location contains the mono volume level.

The full 16-bit setting(s) set with the waveOutSetVolume function is returned, regardless of whether the device supports the full 16 bits of volume-level control.

Not all devices support volume changes. To determine whether the device supports volume control, use the WAVECAPS_VOLUME flag to test the dwSupport member of the WAVEOUTCAPS structure (filled by the waveOutGetDevCaps function).

To determine whether the device supports left- and right-channel volume control, use the WAVECAPS_LRVOLUME flag to test the dwSupport member of the WAVEOUTCAPS structure (filled by waveOutGetDevCaps).

Volume settings are interpreted logarithmically. This means the perceived increase in volume is the same when increasing the volume level from 0x5000 to 0x6000 as it is from 0x4000 to 0x5000.


waveOutMessage

DWORD waveOutMessage(HWAVEOUT hwo, UINT uMsg, DWORD dwParam1,

    DWORD dwParam2);

Sends messages to the waveform-audio output device drivers.

•	Returns the value returned from the driver.

hwo

Handle of the waveform-audio output device.

uMsg

Message to send.

dwParam1 and dwParam2

Message parameters.


waveOutOpen

MMRESULT waveOutOpen(LPHWAVEOUT phwo, UINT uDeviceID,

    LPWAVEFORMATEX pwfx, DWORD dwCallback, DWORD dwCallbackInstance,

    DWORD fdwOpen);

Opens the given waveform-audio output device for playback.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_ALLOCATED	Specified resource is already allocated.
MMSYSERR_BADDEVICEID	Specified device identifier is out of range.
MMSYSERR_NODRIVER	No device driver is present.
MMSYSERR_NOMEM	Unable to allocate or lock memory.
WAVERR_BADFORMAT	Attempted to open with an unsupported waveform-audio format.
WAVERR_SYNC	The device is synchronous but waveOutOpen was called without using the WAVE_ALLOWSYNC flag.
phwo

Address filled with a handle identifying the open waveform-audio output device. Use the handle to identify the device when calling other waveform-audio output functions. This parameter might be NULL if the WAVE_FORMAT_QUERY flag is specified for fdwOpen.

uDeviceID

Identifier of the waveform-audio output device to open. It can be either a device identifier or a handle of an open waveform-audio input device.You can use the following flag instead of a device identifier:

WAVE_MAPPER

The function selects a waveform-audio output device capable of playing the given format.

pwfx

Address of a WAVEFORMATEX structure that identifies the format of the waveform-audio data to be sent to the device. You can free this structure immediately after passing it to waveOutOpen.

dwCallback

Address of a fixed callback function, an event handle, or a handle of a window or thread called during waveform-audio playback to process messages related to the progress of the playback. If no callback function is required, this value can be zero.

dwCallbackInstance

User-instance data passed to the callback mechanism. This parameter is not used with the window callback mechanism.

fdwOpen

Flags for opening the device. The following values are defined:

CALLBACK_EVENT

The dwCallback parameter is an event handle.

CALLBACK_FUNCTION

The dwCallback parameter is a callback procedure address.

CALLBACK_NULL

No callback mechanism. This is the default setting.

CALLBACK_THREAD

The dwCallback parameter is a thread handle.

CALLBACK_WINDOW

The dwCallback parameter is a window handle.

WAVE_ALLOWSYNC

If this flag is specified, a synchronous waveform-audio device can be opened. If this flag is not specified while opening a synchronous driver, the device will fail to open.

WAVE_FORMAT_QUERY

If this flag is specified, waveOutOpen queries the device to determine if it supports the given format, but the device is not actually opened.

WAVE_MAPPED

If this flag is specified, the uDeviceID parameter specifies a waveform-audio device to be mapped to by the wave mapper.

Use the waveOutGetNumDevs function to determine the number of waveform-audio output devices present in the system. If the value specified by the uDeviceID parameter is a device identifier, it can vary from zero to one less than the number of devices present. The WAVE_MAPPER constant can also be used as a device identifier.

The structure pointed to by pwfx can be extended to include type-specific information for certain data formats. For example, for PCM data, an extra UINT is added to specify the number of bits per sample. Use the PCMWAVEFORMAT structure in this case. For all other waveform-audio formats, use the WAVEFORMATEX structure to specify the length of the additional data.

If you choose to have a window or thread receive callback information, the following messages are sent to the window procedure function to indicate the progress of waveform-audio output: MM_WOM_OPEN, MM_WOM_CLOSE, and MM_WOM_DONE.

If you choose to have a function receive callback information, the following messages are sent to the function to indicate the progress of waveform-audio output: WOM_OPEN, WOM_CLOSE, and WOM_DONE.


waveOutPause

MMRESULT waveOutPause(HWAVEOUT hwo);

Pauses playback on the given waveform-audio output device. The current position is saved. Use the waveOutRestart function to resume playback from the current position.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALHANDLE	Specified device handle is invalid.
MMSYSERR_NODRIVER	No device driver is present.
MMSYSERR_NOMEM	Unable to allocate or lock memory.
MMSYSERR_NOTSUPPORTED	Specified device is synchronous and does not support pausing.
hwo

Handle of the waveform-audio output device.

Calling this function when the output is already paused has no effect, and the function returns zero.


waveOutPrepareHeader

MMRESULT waveOutPrepareHeader(HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh);

Prepares a waveform-audio data block for playback.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALHANDLE	Specified device handle is invalid.
MMSYSERR_NODRIVER	No device driver is present.
MMSYSERR_NOMEM	Unable to allocate or lock memory.
hwo

Handle of the waveform-audio output device.

pwh

Address of a WAVEHDR structure that identifies the data block to be prepared.

cbwh

Size, in bytes, of the WAVEHDR structure.

The lpData, dwBufferLength, and dwFlags members of the WAVEHDR structure must be set before calling this function (dwFlags must be zero).

The dwFlags, dwBufferLength, and dwLoops members of the WAVEHDR structure can change between calls to this function and the waveOutWrite function. (The only flags that can change in this interval for the dwFlags member are WHDR_BEGINLOOP and WHDR_ENDLOOP.) If you change the size specified by dwBufferLength before the call to waveOutWrite, the new value must be less than the prepared value.

Preparing a header that has already been prepared has no effect, and the function returns zero.


waveOutProc

void CALLBACK waveOutProc(HWAVEOUT hwo, UINT uMsg, DWORD dwInstance,

    DWORD dwParam1, DWORD dwParam2);

Callback function used with the waveform-audio output device. The waveOutProc function is a placeholder for the application-defined function name.

hwo

Handle of the waveform-audio device associated with the callback.

uMsg

Waveform-audio output message. It can be one of the following values:

WOM_CLOSE

Sent when the device is closed using the waveOutClose function.

WOM_DONE

Sent when the device driver is finished with a data block sent using the waveOutWrite function.

WOM_OPEN

Sent when the device is opened using the waveOutOpen function.

dwInstance

User-instance data specified with waveOutOpen.

dwParam1 and dwParam2

Message parameters.

Applications should not call any system-defined functions from inside a callback function, except for PostMessage, timeGetSystemTime, timeGetTime, timeSetEvent, timeKillEvent, midiOutShortMsg, midiOutLongMsg, and OutputDebugStr.


waveOutReset

MMRESULT waveOutReset(HWAVEOUT hwo);

Stops playback on the given waveform-audio output device and resets the current position to zero. All pending playback buffers are marked as done and returned to the application.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALHANDLE	Specified device handle is invalid.
MMSYSERR_NODRIVER	No device driver is present.
MMSYSERR_NOMEM	Unable to allocate or lock memory.
MMSYSERR_NOTSUPPORTED	Specified device is synchronous and does not support pausing.
hwo

Handle of the waveform-audio output device.


waveOutRestart

MMRESULT waveOutRestart(HWAVEOUT hwo);

Resumes playback on a paused waveform-audio output device.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALHANDLE	Specified device handle is invalid.
MMSYSERR_NODRIVER	No device driver is present.
MMSYSERR_NOMEM	Unable to allocate or lock memory.
MMSYSERR_NOTSUPPORTED	Specified device is synchronous and does not support pausing.
hwo

Handle of the waveform-audio output device.

Calling this function when the output is not paused has no effect, and the function returns zero.


waveOutSetPitch

MMRESULT waveOutSetPitch(HWAVEOUT hwo, DWORD dwPitch);

Sets the pitch for the specified waveform-audio output device.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALHANDLE	Specified device handle is invalid.
MMSYSERR_NODRIVER	No device driver is present.
MMSYSERR_NOMEM	Unable to allocate or lock memory.
MMSYSERR_NOTSUPPORTED	Function isn't supported.
hwo

Handle of the waveform-audio output device.

dwPitch

New pitch multiplier setting. This setting indicates the current change in pitch from the original authored setting. The pitch multiplier must be a positive value.

The pitch multiplier is specified as a fixed-point value. The high-order word contains the signed integer part of the number, and the low-order word contains the fractional part. A value of 0x8000 in the low-order word represents one-half, and 0x4000 represents one-quarter. For example, the value 0x00010000 specifies a multiplier of 1.0 (no pitch change), and a value of 0x000F8000 specifies a multiplier of 15.5.

Changing the pitch does not change the playback rate or the sample rate, nor does it change the playback time. Not all devices support pitch changes. To determine whether the device supports pitch control, use the WAVECAPS_PITCH flag to test the dwSupport member of the WAVEOUTCAPS structure (filled by the waveOutGetDevCaps function).


waveOutSetPlaybackRate

MMRESULT waveOutSetPlaybackRate(HWAVEOUT hwo, DWORD dwRate);

Sets the playback rate for the specified waveform-audio output device.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALHANDLE	Specified device handle is invalid.
MMSYSERR_NODRIVER	No device driver is present.
MMSYSERR_NOMEM	Unable to allocate or lock memory.
MMSYSERR_NOTSUPPORTED	Function isn't supported.
hwo

Handle of the waveform-audio output device.

dwRate

New playback rate setting. This setting is a multiplier indicating the current change in playback rate from the original authored setting. The playback rate multiplier must be a positive value.

The rate is specified as a fixed-point value. The high-order word contains the signed integer part of the number, and the low-order word contains the fractional part. A value of 0x8000 in the low-order word represents one-half, and 0x4000 represents one-quarter. For example, the value 0x00010000 specifies a multiplier of 1.0 (no playback rate change), and a value of 0x000F8000 specifies a multiplier of 15.5.

Changing the playback rate does not change the sample rate but does change the playback time. Not all devices support playback rate changes. To determine whether a device supports playback rate changes, use the WAVECAPS_PLAYBACKRATE flag to test the dwSupport member of the WAVEOUTCAPS structure (filled by the waveOutGetDevCaps function).


waveOutSetVolume

MMRESULT waveOutSetVolume(HWAVEOUT hwo, DWORD dwVolume);

Sets the volume level of the specified waveform-audio  output device.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALHANDLE	Specified device handle is invalid.
MMSYSERR_NODRIVER	No device driver is present.
MMSYSERR_NOMEM	Unable to allocate or lock memory.
MMSYSERR_NOTSUPPORTED	Function is not supported.
hwo

Handle of an open waveform-audio output device.

dwVolume

New volume setting. The low-order word contains the left-channel volume setting, and the high-order word contains the right-channel setting. A value of 0xFFFF represents full volume, and a value of 0x0000 is silence.

If a device does not support both left and right volume control, the low-order word of dwVolume specifies the volume level, and the high-order word is ignored.

Changing the volume on a handle changes it for an instance of the device, rather than changing the default volume for the device (and affecting all instances of the device).

Not all devices support volume changes. To determine whether the device supports volume control, use the WAVECAPS_VOLUME flag to test the dwSupport member of the WAVEOUTCAPS structure (filled by the waveOutGetDevCaps function). To determine whether the device supports volume control on both the left and right channels, use the WAVECAPS_LRVOLUME flag.

Most devices do not support the full 16 bits of volume-level control and will not use the high-order bits of the requested volume setting. For example, for a device that supports 4 bits of volume control, requested volume level values of 0x4000, 0x4FFF, and 0x43BE all produce the same physical volume setting: 0x4000. The waveOutGetVolume function returns the full 16-bit setting set with waveOutSetVolume.

Volume settings are interpreted logarithmically. This means the perceived increase in volume is the same when increasing the volume level from 0x5000 to 0x6000 as it is from 0x4000 to 0x5000.


waveOutUnprepareHeader

MMRESULT waveOutUnprepareHeader(HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh);

Cleans up the preparation performed by the waveOutPrepareHeader function. This function must be called after the device driver is finished with a data block. You must call this function before freeing the buffer.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALHANDLE	Specified device handle is invalid.
MMSYSERR_NODRIVER	No device driver is present.
MMSYSERR_NOMEM	Unable to allocate or lock memory.
WAVERR_STILLPLAYING	The data block pointed to by the pwh parameter is still in the queue.
hwo

Handle of the waveform-audio output device.

pwh

Address of a WAVEHDR structure identifying the data block to be cleaned up.

cbwh

Size, in bytes, of the WAVEHDR structure.

This function complements waveOutPrepareHeader. You must call this function before freeing the buffer. After passing a buffer to the device driver with the waveOutWrite function, you must wait until the driver is finished with the buffer before calling waveOutUnprepareHeader.

Unpreparing a buffer that has not been prepared has no effect, and the function returns zero.


waveOutWrite

MMRESULT waveOutWrite(HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh);

Sends a data block to the given waveform-audio output device.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALHANDLE	Specified device handle is invalid.
MMSYSERR_NODRIVER	No device driver is present.
MMSYSERR_NOMEM	Unable to allocate or lock memory.
WAVERR_UNPREPARED	The data block pointed to by the pwh parameter hasn't been prepared.
hwo

Handle of the waveform-audio output device.

pwh

Address of a WAVEHDR structure containing information about the data block.

cbwh

Size, in bytes, of the WAVEHDR structure.

When the buffer is finished, the WHDR_DONE bit is set in the dwFlags member of the WAVEHDR structure.

The buffer must be prepared with the waveOutPrepareHeader function before it is passed to waveOutWrite. Unless the device is paused by calling the waveOutPause function, playback begins when the first data block is sent to the device.


MM_WIM_CLOSE

MM_WIM_CLOSE

wParam = (WPARAM) hInputDev  // see below

lParam = reserved            // must be zero

Sent to a window when a waveform-audio input device is closed. The device handle is no longer valid after this message has been sent.

•	No return value.

hInputDev

Handle of the waveform-audio input device that was closed.


MM_WIM_DATA

MM_WIM_DATA

wParam = (WPARAM) hInputDev

lParam = (LONG) lpwvhdr

Sent to a window when waveform-audio data is present in the input buffer and the buffer is being returned to the application. The message can be sent either when the buffer is full or after the waveInReset function is called.

•	No return value.

hInputDev

Handle of the waveform-audio input device that received the data.

lpwvhdr

Address of a WAVEHDR structure that identifies the buffer containing the data.

The returned buffer might not be full. Use the dwBytesRecorded member of the WAVEHDR structure specified by lParam to determine the number of bytes recorded into the returned buffer.


MM_WIM_OPEN

MM_WIM_OPEN

wParam = (WPARAM) hInputDev  // see below

lParam = reserved            // must be zero

Sent to a window when a waveform-audio input device is opened.

•	No return value.

hInputDev

Handle of the device that was opened.


MM_WOM_CLOSE

MM_WOM_CLOSE

wParam = (WPARAM) hOutputDev  // see below

lParam = reserved             // must be zero

Sent to a window when a waveform-audio output device is closed. The device handle is no longer valid after this message has been sent.

•	No return value.

hOutputDev

Handle of the device that was closed.


MM_WOM_DONE

MM_WOM_DONE

wParam = (WPARAM) hOutputDev

lParam = (LONG) lpwvhdr

Sent to a window when the given output buffer is being returned to the application. Buffers are returned to the application when they have been played, or as the result of a call to the waveOutReset function.

•	No return value.

hOutputDev

Handle of the waveform-audio output device that played the buffer.

lpwvhdr

Address of a WAVEHDR structure identifying the buffer.


MM_WOM_OPEN

MM_WOM_OPEN

wParam = (WPARAM) hOutputDev  // see below

lParam = reserved             // must be zero

Sent to a window when the given waveform-audio output device is opened.

•	No return value.

hOutputDev

Handle of the device that was opened.


WIM_CLOSE

WIM_CLOSE

dwParam1 = reserved  // must be zero

dwParam2 = reserved  // must be zero

Sent to the given waveform-audio input callback function when a waveform-audio input device is closed. The device handle is no longer valid after this message has been sent.

•	No return value.


WIM_DATA

WIM_DATA

dwParam1 = (DWORD) lpwvhdr  // see below

dwParam2 = reserved         // must be zero

Sent to the given waveform-audio input callback function when waveform-audio data is present in the input buffer and the buffer is being returned to the application. The message can be sent when the buffer is full or after the waveInReset function is called.

•	No return value.

lpwvhdr

Address of a WAVEHDR structure that identifies the buffer containing the data.

The returned buffer might not be full. Use the dwBytesRecorded member of the WAVEHDR structure specified by lpwvhdr to determine the number of bytes recorded into the returned buffer.


WIM_OPEN

WIM_OPEN

dwParam1 = reserved  // must be zero

dwParam2 = reserved  // must be zero

Sent to a waveform-audio input callback function when a waveform-audio input device is opened.

•	No return value.


WOM_CLOSE

WOM_CLOSE

dwParam1 = reserved  // must be zero

dwParam2 = reserved  // must be zero

Sent to a waveform-audio output callback function when a waveform-audio output device is closed. The device handle is no longer valid after this message has been sent.

•	No return value.


WOM_DONE

WOM_DONE

dwParam1 = (DWORD) lpwvhdr  // see below

dwParam2 = reserved         // must be zero

Sent to a waveform-audio output callback function when the given output buffer is being returned to the application. Buffers are returned to the application when they have been played, or as the result of a call to the waveOutReset function.

•	No return value.

lpwvhdr

Address of a WAVEHDR structure identifying the buffer.


WOM_OPEN

WOM_OPEN

dwParam1 = reserved  // must be zero

dwParam2 = reserved  // must be zero

Sent to a waveform-audio output callback function when a waveform-audio output device is opened.

•	No return value.


AUXCAPS

typedef struct {

    WORD      wMid;

    WORD      wPid;

    MMVERSION vDriverVersion;

    CHAR      szPname[MAXPNAMELEN];

    WORD      wTechnology;

    WORD      wReserved1;  // padding

    DWORD     dwSupport;

} AUXCAPS;

Describes the capabilities of an auxiliary output device.

wMid

Manufacturer identifier for the device driver for the auxiliary audio device. The following identifier is defined:

MM_MICROSOFT

Drivers developed by Microsoft Corporation.

wPid

Product identifier for the auxiliary audio device. Currently, no product identifiers are defined for auxiliary audio devices.

vDriverVersion

Version number of the device driver for the auxiliary audio device.  The high-order byte is the major version number, and the low-order byte is the minor version number.

szPname

Product name in a null-terminated string.

wTechnology

Type of the auxiliary audio output:

AUXCAPS_AUXIN

Audio output from auxiliary input jacks.

AUXCAPS_CDAUDIO

Audio output from an internal CD-ROM drive.

dwSupport

Describes optional functionality supported by the auxiliary audio device.

AUXCAPS_LRVOLUME

Supports separate left and right volume control.

AUXCAPS_VOLUME

Supports volume control.

If a device supports volume changes, the AUXCAPS_VOLUME flag will be set. If a device supports separate volume changes on the left and right channels, both AUXCAPS_VOLUME and the AUXCAPS_LRVOLUME will be set.


PCMWAVEFORMAT

typedef struct {

    WAVEFORMAT wf;              // see below

    WORD       wBitsPerSample;  // number of bits per sample

} PCMWAVEFORMAT;

Describes the data format for PCM waveform-audio data. This structure has been superseded by the WAVEFORMATEX structure.

wf

A WAVEFORMAT structure containing general information about the format of the data.


WAVEFORMAT

typedef struct {

    WORD  wFormatTag;       // see below

    WORD  nChannels;        // see below

    DWORD nSamplesPerSec;   // sample rate, in samples per second

    DWORD nAvgBytesPerSec;  // see below

    WORD  nBlockAlign;      // see below

} WAVEFORMAT;

Describes the format of waveform-audio data. Only format information common to all waveform-audio data formats is included in this structure. This structure has been superseded by the WAVEFORMATEX structure.

wFormatTag

Format type. The following type is defined:

WAVE_FORMAT_PCM

Waveform-audio data is PCM.

nChannels

Number of channels in the waveform-audio data. Mono data uses one channel and stereo data uses two channels.

nAvgBytesPerSec

Required average data transfer rate, in bytes per second. For example, 16-bit stereo at 44.1 kHz has an average data rate of 176,400 bytes per second (2 channels × 2 bytes per sample per channel × 44,100 samples per second).

nBlockAlign

Block alignment, in bytes. The block alignment is the minimum atomic unit of data. For PCM data, the block alignment is the number of bytes used by a single sample, including data for both channels if the data is stereo. For example, the block alignment for 16-bit stereo PCM is 4 bytes (2 channels × 2 bytes per sample).

For formats that require additional information, this structure is included as a member in another structure along with the additional information.


WAVEFORMATEX

typedef struct {

    WORD  wFormatTag;

    WORD  nChannels;

    DWORD nSamplesPerSec;

    DWORD nAvgBytesPerSec;

    WORD  nBlockAlign;

    WORD  wBitsPerSample;

    WORD  cbSize;

} WAVEFORMATEX;

Defines the format of waveform-audio data. Only format information common to all waveform-audio data formats is included in this structure. For formats that require additional information, this structure is included as the first member in another structure, along with the additional information.

wFormatTag

Waveform-audio format type. Format tags are registered with Microsoft Corporation for many compression algorithms. A complete list of format tags can be found in the MMREG.H header file.

nChannels

Number of channels in the waveform-audio data. Monaural data uses one channel and stereo data uses two channels.

nSamplesPerSec

Sample rate, in samples per second (hertz), that each channel should be played or recorded. If wFormatTag is WAVE_FORMAT_PCM, then common values for nSamplesPerSec are 8.0 kHz, 11.025 kHz, 22.05 kHz, and 44.1 kHz. For non-PCM formats, this member must be computed according to the manufacturer's specification of the format tag.

nAvgBytesPerSec

Required average data-transfer rate, in bytes per second, for the format tag. If wFormatTag is WAVE_FORMAT_PCM, nAvgBytesPerSec should be equal to the product of nSamplesPerSec and nBlockAlign. For non-PCM formats, this member must be computed according to the manufacturer's specification of the format tag.

Playback and record software can estimate buffer sizes by using the nAvgBytesPerSec member.

nBlockAlign

Block alignment, in bytes. The block alignment is the minimum atomic unit of data for the wFormatTag format type. If wFormatTag is WAVE_FORMAT_PCM, nBlockAlign should be equal to the product of nChannels and wBitsPerSample divided by 8 (bits per byte). For non-PCM formats, this member must be computed according to the manufacturer's specification of the format tag.

Playback and record software must process a multiple of nBlockAlign bytes of data at a time. Data written and read from a device must always start at the beginning of a block. For example, it is illegal to start playback of PCM data in the middle of a sample (that is, on a non-block-aligned boundary).

wBitsPerSample

Bits per sample for the wFormatTag format type. If wFormatTag is WAVE_FORMAT_PCM, then wBitsPerSample should be equal to 8 or 16. For non-PCM formats, this member must be set according to the manufacturer's specification of the format tag. Note that some compression schemes cannot define a value for wBitsPerSample, so this member can be zero.

cbSize

Size, in bytes, of extra format information appended to the end of the WAVEFORMATEX structure. This information can be used by non-PCM formats to store extra attributes for the wFormatTag. If no extra information is required by the wFormatTag, this member must be set to zero. Note that for WAVE_FORMAT_PCM formats (and only WAVE_FORMAT_PCM formats), this member is ignored.

An example of a format that uses extra information is the Microsoft Adaptive Delta Pulse Code Modulation (MS-ADPCM) format. The wFormatTag for MS-ADPCM is WAVE_FORMAT_ADPCM. The cbSize member will typically be set to 32. The extra information stored for WAVE_FORMAT_ADPCM is coefficient pairs required for encoding and decoding the waveform-audio data.


WAVEHDR

typedef struct {

    LPSTR  lpData;                   // address of the waveform buffer

    DWORD  dwBufferLength;           // length, in bytes, of the buffer

    DWORD  dwBytesRecorded;          // see below

    DWORD  dwUser;                   // 32 bits of user data

    DWORD  dwFlags;                  // see below

    DWORD  dwLoops;                  // see below

    struct wavehdr_tag far * lpNext; // reserved; must be zero

    DWORD  reserved;                 // reserved; must be zero

} WAVEHDR;

Defines the header used to identify a waveform-audio buffer.

dwBytesRecorded

When the header is used in input, this member specifies how much data is in the buffer.

dwFlags

Flags supplying information about the buffer. The following values are defined:

WHDR_BEGINLOOP

This buffer is the first buffer in a loop.  This flag is used only with output buffers.

WHDR_DONE

Set by the device driver to indicate that it is finished with the buffer and is returning it to the application.

WHDR_ENDLOOP

This buffer is the last buffer in a loop.  This flag is used only with output buffers.

WHDR_INQUEUE

Set by Windows to indicate that the buffer is queued for playback.

WHDR_PREPARED

Set by Windows to indicate that the buffer has been prepared with the waveInPrepareHeader or waveOutPrepareHeader function.

dwLoops

Number of times to play the loop. This member is used only with output buffers.

Use the WHDR_BEGINLOOP and WHDR_ENDLOOP flags in the dwFlags member to specify the beginning and ending data blocks for looping. To loop on a single block, specify both flags for the same block. Use the dwLoops member in the WAVEHDR structure for the first block in the loop to specify the number of times to play the loop.

The lpData, dwBufferLength, and dwFlags members must be set before calling the waveInPrepareHeader or waveOutPrepareHeader function. (For either function, the dwFlags member must be set to zero.)


WAVEINCAPS

typedef struct {

    WORD      wMid;

    WORD      wPid;

    MMVERSION vDriverVersion;

    CHAR      szPname[MAXPNAMELEN];

    DWORD     dwFormats;

    WORD      wChannels;

    WORD      wReserved1; // padding

} WAVEINCAPS;

Describes the capabilities of a waveform-audio input device.

wMid

Manufacturer identifier for the device driver for the waveform-audio input device. Manufacturer identifiers are defined in Chapter 0, "Manufacturer and Product Identifiers."

wPid

Product identifier for the waveform-audio input device. Product identifiers are defined in Chapter 0, "Manufacturer and Product Identifiers."

vDriverVersion

Version number of the device driver for the waveform-audio input device. The high-order byte is the major version number, and the low-order byte is the minor version number.

szPname

Product name in a null-terminated string.

dwFormats

Standard formats that are supported. Can be a combination of the following:

WAVE_FORMAT_1M08	11.025 kHz, mono, 8-bit
WAVE_FORMAT_1M16	11.025 kHz, mono, 16-bit
WAVE_FORMAT_1S08	11.025 kHz, stereo, 8-bit
WAVE_FORMAT_1S16	11.025 kHz, stereo, 16-bit
WAVE_FORMAT_2M08	22.05 kHz, mono, 8-bit
WAVE_FORMAT_2M16	22.05 kHz, mono, 16-bit
WAVE_FORMAT_2S08	22.05 kHz, stereo, 8-bit
WAVE_FORMAT_2S16	22.05 kHz, stereo, 16-bit
WAVE_FORMAT_4M08	44.1 kHz, mono, 8-bit
WAVE_FORMAT_4M16	44.1 kHz, mono, 16-bit
WAVE_FORMAT_4S08	44.1 kHz, stereo, 8-bit
WAVE_FORMAT_4S16	44.1 kHz, stereo, 16-bit
wChannels

Number specifying whether the device supports mono (1) or stereo (2) input.


WAVEOUTCAPS

typedef struct {

    WORD      wMid;

    WORD      wPid;

    MMVERSION vDriverVersion;

    CHAR      szPname[MAXPNAMELEN];

    DWORD     dwFormats;

    WORD      wChannels;

    WORD      wReserved1;  // packing

    DWORD     dwSupport;

} WAVEOUTCAPS;

Describes the capabilities of a waveform-audio output device.

wMid

Manufacturer identifier for the device driver for the device. Manufacturer identifiers are defined in Chapter 0, "Manufacturer and Product Identifiers."

wPid

Product identifier for the device. Product identifiers are defined in Chapter 0, "Manufacturer and Product Identifiers."

vDriverVersion

Version number of the device driver for the device. The high-order byte is the major version number, and the low-order byte is the minor version number.

szPname

Product name in a null-terminated string.

dwFormats

Standard formats that are supported. Can be a combination of the following:

WAVE_FORMAT_1M08	11.025 kHz, mono, 8-bit
WAVE_FORMAT_1M16	11.025 kHz, mono, 16-bit
WAVE_FORMAT_1S08	11.025 kHz, stereo, 8-bit
WAVE_FORMAT_1S16	11.025 kHz, stereo, 16-bit
WAVE_FORMAT_2M08	22.05 kHz, mono, 8-bit
WAVE_FORMAT_2M16	22.05 kHz, mono, 16-bit
WAVE_FORMAT_2S08	22.05 kHz, stereo, 8-bit
WAVE_FORMAT_2S16	22.05 kHz, stereo, 16-bit
WAVE_FORMAT_4M08	44.1 kHz, mono, 8-bit
WAVE_FORMAT_4M16	44.1 kHz, mono, 16-bit
WAVE_FORMAT_4S08	44.1 kHz, stereo, 8-bit
WAVE_FORMAT_4S16	44.1 kHz, stereo, 16-bit
wChannels

Number specifying whether the device supports mono (1) or stereo (2) output.

dwSupport

Optional functionality supported by the device. The following values are defined:

WAVECAPS_LRVOLUME	Supports separate left and right volume control.
WAVECAPS_PITCH	Supports pitch control.
WAVECAPS_PLAYBACKRATE	Supports playback rate control.
WAVECAPS_SYNC	The driver is synchronous and will block while playing a buffer.
WAVECAPS_VOLUME	Supports volume control.
WAVECAPS_SAMPLEACCURATE	Returns sample-accurate position information.
If a device supports volume changes, the WAVECAPS_VOLUME flag will be set for the dwSupport member. If a device supports separate volume changes on the left and right channels, both the WAVECAPS_VOLUME and the WAVECAPS_LRVOLUME flags will be set for this member.


Audio Compression Manager

The audio compression manager (ACM) adds system-level support for the following services:

•	Transparent run-time audio compression and decompression

•	Waveform-audio data format selection

•	Waveform-audio data filter selection

•	Waveform-audio data format conversion

•	Waveform-audio data filtering

This chapter describes the services available in the ACM and explains the programming techniques used to access these services.


Mapping Waveform-Audio Devices

The Microsoft® Win32® application programming interface (API) provides a set of standard functions for audio devices. These functions issue calls to device drivers that manage hardware devices. The system uses a module called a "mapper" to manage installed devices. The mapper uses special hooks in the driver interface to intercept calls and to act as an intermediary between the system and the drivers installed in the system. The mapper is responsible for matching an application's requests for access to a device with the available devices and for finding a device that meets the current application's audio requirements. The system provides mappers for standard driver types: waveform-audio, MIDI (Musical Instrument Digital Interface), and auxiliary devices.

The ACM is an extension of the basic multimedia system and is installed as a mapper. This means the ACM uses the driver-interface mapper hooks for waveform-audio devices. Using these hooks allows the ACM to decode or encode waveform-audio data before passing it to or from a waveform-audio device driver. The difference between the ACM and the standard system mapper is that the ACM can search for a waveform-audio device that supports a given format or find a combination of a waveform-audio device and an ACM compressor or decompressor that supports a given format.

When an application requests that the system open a waveform-audio device for input or output, the request specifies the format and device. When the specified device is the mapper, the mapper must find a device that supports the given format. The mapper implemented in the ACM searches for an installed waveform-audio device that supports the given format. If the ACM cannot find such a device, it searches for a waveform-audio device and a compressor or decompressor that together support the format. Specifically, the ACM searches for a compressor or decompressor that converts the specified format into a format that is supported by an installed waveform-audio device. After the ACM finds a device that supports the converted format, it can honor requests to play or record the format originally requested, even though no installed waveform-audio device directly supports that format.

In addition to format conversion, the ACM also offers services to support compression, decompression, filtering, format selection, and filter selection. It provides a standard API that it supports by calling its own drivers.


How the Audio Compression Manager Works

The ACM uses existing driver interface hooks to override the default mapping algorithm for waveform-audio devices. This allows the ACM to intercept device-open calls. After a call has been intercepted, the ACM can perform a variety of tasks to process the audio data, such as inserting an external compressor or decompressor into the sequence.

The ACM manages the following types of drivers:

•	Compressor and decompressor (codec) drivers

•	Format converter drivers

•	Filter drivers

Compressors and decompressors change one format type to another. For example, a compressor or decompressor can change a PCM (Pulse Code Modulation) file to an ADPCM (Adaptive Differential Pulse Code Modulation) file. Format converters change the format, but not the data type. For example, a converter can change 44-kHz, 16-bit data to 44-kHz, 8-bit data. Filters do not change the data format at all, but they change the waveform-audio data in some manner. For example, a filter could combine a data stream and an echo of itself. A single ACM driver, or a filter tag or format tag within a driver, might also support combinations of the above types.

For waveform-audio output, the ACM passes each buffer of data to the converter as it arrives. The converter decompresses the data and returns the decompressed data to the ACM in a "shadow" buffer. The ACM then passes the decompressed shadow buffer to the waveform-audio driver. The ACM allocates the shadow buffers whenever it receives a prepare message.

For waveform-audio input, the ACM passes empty shadow buffers to the driver. It uses a background task to receive a notification after the driver has filled the shadow buffer. The ACM then passes the buffers to the driver for compression. After compression is finished, the driver passes the data to the application.


Audio Compression Manager Functions and Structures

The ACM functions fall into several categories. Naming conventions for the functions make it easy to identify these categories. Function names (with two exceptions) are of the form acmGroupFunction, where Group designates the ACM category (such as "Driver," "Format," "FormatTag," "Filter," "FilterTag," or "Stream"), and Function describes the action performed by the function.

The functions in the filter and format groups are very similar. Almost every function that acts on filters has a parallel function that acts on formats.

In the format group, some functions use waveform-audio format tags (the wFormatTag member of a WAVEFORMATEX structure) while others require full waveform-audio formats (the full WAVEFORMATEX structure). (For reference information about the WAVEFORMATEX structure, see Error.)

In the filter group, some functions use waveform-audio filter tags (the dwFilterTag member of a WAVEFILTER structure) while others require full waveform-audio filters (the full WAVEFILTER structure).

The functions in the stream group represent the many steps involved in a conversion: opening a conversion instance, preparing for the conversion, performing the conversion, cleaning up after the conversion is complete, and closing the conversion instance.


Functions Called by the System

The system calls three different kinds of application-defined functions. Callback functions are functions in your application that the system calls in response to a request made by an application. Hook procedures help an application handle the customization of dialog boxes. A driver procedure is an application's implementation of its own codec, converter, or filter. In the reference section of this chapter, the prototypes of these three function types are alphabetized with the other function descriptions.

The callback functions have the following names:

•	acmDriverEnumCallback

•	acmFilterEnumCallback

•	acmFilterTagEnumCallback

•	acmFormatEnumCallback

•	acmFormatTagEnumCallback

•	acmStreamConvertCallback

Most of the enumeration functions in the ACM use callback functions. For example, when you call an enumeration function, the ACM enumerates the items by repeatedly calling the application through the callback function.

Some functions cannot be called from within these callback functions. Functions that cannot be called manipulate internal ACM structures that are used by the enumeration functions. The following functions should not be called from within a callback function:

•	acmDriverAdd

•	acmDriverPriority

•	acmDriverRemove

The system calls the following functions to help an application handle the customization of dialog boxes:

•	acmFilterChooseHookProc

•	acmFormatChooseHookProc

The following function is given as a prototype that allows an application to use a customized codec, converter, or filter. A function conforming to this prototype may be passed as an argument to the acmDriverAdd function.

•	acmDriverProc


Using the Audio Compression Manager

This section contains examples demonstrating how to perform the following tasks:

•	Retrieve a string that describes a filter.

•	Produce a dialog box for selecting a filter.

•	Produce a dialog box for selecting a specific type of format.

•	Produce a dialog box for selecting restricted formats.

•	Produce a dialog box for selecting a format for saving.

•	Produce a dialog box for selecting a format for recording.

•	Convert data from one format to another.

•	Multistep format conversion.

•	Find a specific format.

•	Find a specific driver.

•	Add drivers within an application.

•	Generate a nonstandard format.


Retrieving a String That Describes a Filter

An application often needs to display a string that describes the current format. This task can be accomplished easily with the acmFilterTagDetails and acmFilterDetails functions. These functions must be called with the appropriate filter or filter tag. The following example shows how to use these functions.

BOOL GetFilterDescription

(

    LPWAVEFILTER  pwfltr,

    LPTSTR        pszFilterTag,

    LPTSTR        pszFilter

)

{

    MMRESULT      mmr;

    // Retrieve the name for the filter tag of the specified filter.

    if (NULL != pszFilterTag) {

        ACMFILTERTAGDETAILS aftd;

        // Initialize all unused members of the ACMFILTERTAGDETAILS

        // structure to zero.

        memset(&aftd, 0, sizeof(aftd));

        // Fill in the required members of the ACMFILTERTAGDETAILS

        // structure for the ACM_FILTERTAGDETAILSF_FILTERTAG query.

        aftd.cbStruct = sizeof(aftd);

        aftd.dwFilterTag = pwfltr->dwFilterTag;

        // Ask the ACM to find the first available driver that

        // supports the specified filter tag.

        mmr = acmFilterTagDetails(NULL, &aftd,

            ACM_FILTERTAGDETAILSF_FILTERTAG);

        if (MMSYSERR_NOERROR != mmr) {

            // No ACM driver is available that supports the

            // specified filter tag.

            return (FALSE);

        }

        // Copy the filter tag name into the calling application's

        // buffer.

        lstrcpy(pszFilterTag, aftd.szFilterTag);

    }

    // Retrieve the description of the attributes for the specified

    // filter.

    if (NULL != pszFilter) {

        ACMFILTERDETAILS afd;

        // Initialize all unused members of the ACMFILTERDETAILS

        // structure to zero.

        memset(&afd, 0, sizeof(afd));

        // Fill in the required members of the ACMFILTERDETAILS

        // structure for the ACM_FILTERDETAILSF_FILTER query.

        afd.cbStruct    = sizeof(afd);

        afd.dwFilterTag = pwfltr->dwFilterTag;

        afd.pwfltr      = pwfltr;

        afd.cbwfltr     = pwfltr->cbStruct;

        // Ask the ACM to find the first available driver that

        // supports the specified filter.

        mmr = acmFilterDetails(NULL, &afd, ACM_FILTERDETAILSF_FILTER);

        if (MMSYSERR_NOERROR != mmr) {

            // No ACM driver is available that supports the

            // specified filter.

            return (FALSE);

        }

        // Copy the filter attributes description into the calling

        // application's buffer.

        lstrcpy(pszFilter, afd.szFilter);

    }

    return (TRUE);

}


Producing a Dialog Box for Selecting a Filter

An application can allow users to select an arbitrary filter operation and apply it to waveform-audio data. In the following example, the application allocates a buffer to hold the filter and then uses the acmFilterChoose function to select the filter. The functions in this example must be called with the appropriate filter or filter tag.

MMRESULT        mmr;

ACMFILTERCHOOSE afc;

PWAVEFILTER     pwfltr;

DWORD           cbwfltr;

// Determine the maximum size required for any valid filter

// for which the ACM has a driver installed and enabled.

mmr = acmMetrics(NULL, ACM_METRIC_MAX_SIZE_FILTER, &cbwfltr);

if (MMSYSERR_NOERROR != mmr) {

    // The ACM probably has no drivers installed and

    // enabled for filter operations.

    return (mmr);

}

// Dynamically allocate a structure large enough to hold the

// maximum sized filter enabled in the system.

pwfltr = (PWAVEFILTER)LocalAlloc(LPTR, (UINT)cbwfltr);

if (NULL == pwfltr) {

    return (MMSYSERR_NOMEM);

}

// Initialize the ACMFILTERCHOOSE members.

memset(&afc, 0, sizeof(afc));

afc.cbStruct    = sizeof(afc);

afc.fdwStyle    = 0L;               // no special style flags

afc.hwndOwner   = hwnd;             // hwnd of parent window

afc.pwfltr      = pwfltr;           // wfltr to receive selection

afc.cbwfltr     = cbwfltr;          // size of wfltr buffer

afc.pszTitle    = TEXT("Any Filter Selection");

// Call the ACM to bring up the filter-selection dialog box.

mmr = acmFilterChoose(&afc);

if (MMSYSERR_NOERROR == mmr) {

    // The user selected a valid filter. The pwfltr buffer,

    // allocated above, contains the complete filter description.

}

// Clean up and exit.

LocalFree((HLOCAL)pwfltr);

return (mmr);


Producing a Dialog Box for Selecting a Specific Type of Format

You might want an application to allow the user to select a format from a restricted list of formats in a dialog box. Restrictions might limit the number of channels, the sampling rate, the waveform-audio format tag, or the number of bits per sample. In all of these cases, the list can be automatically generated by using the acmFormatChoose function, setting the fdwEnum and pwfxEnum members of the ACMFORMATCHOOSE structure. The following example illustrates this process.

MMRESULT            mmr;

ACMFORMATCHOOSE     afc;

WAVEFORMATEX        wfxSelection;

WAVEFORMATEX        wfxEnum;

// Initialize the ACMFORMATCHOOSE members.

memset(&afc, 0, sizeof(afc));

afc.cbStruct    = sizeof(afc);

afc.fdwStyle    = 0L;               // no special style flags

afc.hwndOwner   = hwnd;             // hwnd of parent window

afc.pwfx        = &wfxSelection;    // wfx to receive selection

afc.cbwfx       = sizeof(wfxSelection);

afc.pszTitle    = TEXT("16 Bit PCM Selection");

//  Request all 16-bit PCM formats be displayed for the user

//  to select from.

memset(&wfxEnum, 0, sizeof(wfxEnum));

wfxEnum.wFormatTag = WAVE_FORMAT_PCM;

wfxEnum.wBitsPerSample = 16;

afc.fdwEnum = ACM_FORMATENUMF_WFORMATTAG |

    ACM_FORMATENUMF_WBITSPERSAMPLE;

afc.pwfxEnum = &wfxEnum;

mmr = acmFormatChoose(&afc);

if ((MMSYSERR_NOERROR != mmr) && (ACMERR_CANCELED != mmr))

{

    // There was a fatal error in bringing up the list

    // dialog box (probably invalid input parameters).

}


Producing a Dialog Box for Selecting Restricted Formats

You might want to use the dialog box created by the acmFormatChoose function, but limit or control the formats in the dialog box. You can do this by using the ACMFORMATCHOOSE_STYLEF_ENABLEHOOK flag to hook the dialog procedure. The application can then filter the formats by responding to the MM_ACM_FORMATCHOOSE message in the message procedure for the dialog box.


Producing a Dialog Box for Selecting a Format for Saving

You might want an application to save existing waveform-audio data in another format. For example, a waveform-audio editor could save a waveform-audio file as a compressed file. To list only the suggested destination formats for a given source format in the dialog box created by the acmFormatChoose function, specify the source format in the pwfxEnum member and the ACM_FORMATENUMF_SUGGEST flag in the fdwEnum member of the ACMFORMATCHOOSE structure.

Similarly, to list valid destination formats for a given format, use the ACM_FORMATENUMF_CONVERT flag instead of the ACM_FORMATENUMF_SUGGEST flag.


Producing a Dialog Box for Selecting a Format for Recording

An application can allow the user to select a format for which an installed waveform-audio device provides native support. For example, you might want a waveform-audio editor to record new waveform-audio data without using an ACM compressor or decompressor to provide a translation layer. To do this, use the acmFormatChoose function, specifying the ACM_FORMATENUMF_HARDWARE and ACM_FORMATENUMF_INPUT flags in the fdwEnum member of the ACMFORMATCHOOSE structure.


Converting Data from One Format to Another

The ACM uses stream functions to support data format conversion. Converters in the ACM change the format, but not the data type. For example, a converter module can change 44-kHz, 16-bit data to 44-kHz, 8-bit data.

The following ACM functions support data format conversion. They are listed in the order you would typically use them.

•	The acmStreamOpen function opens a conversion stream.

•	The acmStreamSize function calculates the appropriate size of the source or destination buffer.

•	The acmStreamPrepareHeader function prepares source and destination buffers to be used in a conversion.

•	The acmStreamConvert function converts data in a source buffer into the destination format, writing the converted data into the destination buffer.

•	The acmStreamUnprepareHeader function cleans up the preparation performed by acmStreamPrepareHeader. You must call this function before freeing the source and destination buffers.

•	The acmStreamClose function closes a conversion stream.

When converting data, first identify the source format, and then choose the destination format. The easiest way to do this is by using the acmFormatChoose function, which displays a format-selection dialog box and returns the user's choice.

When you know the source and destination formats, you can use acmStreamOpen to open a conversion stream. Then you can use the acmStreamSize function to determine the appropriate buffer sizes.

The next step is to prepare the buffers to be used in the conversion by using acmStreamPrepareHeader.

To perform the conversion, use acmStreamConvert until all the buffers have been processed. When the conversion is complete, use acmStreamUnprepareHeader to clean up the buffers and then use acmStreamClose to close the conversion stream.


Multistep Format Conversion

Sometimes the ACM cannot convert data from one format to another in a single step. For example, an application might need to convert 16-bit, 44-kHz stereo data to 11-kHz mono ADPCM. If the compressor or decompressor cannot do this conversion directly, the application might attempt it in two steps. This usually means making one conversion between two PCM formats and then another to the final format type.

To convert in two steps, use the acmFormatSuggest function to find a PCM format that matches the ADPCM format. Then use two conversion streams to perform the conversion. For example, perform one conversion from 16-bit, 44-kHz stereo PCM to 16-bit, 11-kHz mono and then convert from 16-bit, 11-kHz mono to 11-kHz mono ADPCM.

Multistep conversion also happens when either the source or the destination format is not PCM. If the source format is not PCM, it should be changed to a PCM format before conversion. If the destination format is not PCM, the source must be converted to an intermediate PCM format and then converted to the final destination format.

The most straightforward conversions occur when the source and destination formats are both PCM formats. When either the source or destination format is not PCM, the conversion might require an additional step. If both source and destination formats are not PCM, the conversion will usually require more than one step, and, in some instances, conversion might not be possible.


Finding a Specific Format

An application might have only a partial specification for a format when it needs the full specification. For example, the specification might stipulate an 11-kHz mono, 4-bit ADPCM format, but not the average bytes per second. The application can get the full format without user intervention by using the acmFormatEnum function and specifying flags in the fdwEnum parameter.


Finding a Specific Driver

You might want your application to send a message directly to a specific driver or to identify certain drivers from the list. For example, you might want your application to identify those drivers which support filters and then query each driver to determine which filter tags it supports. You can use the acmDriverEnum function to obtain a handle of the desired driver or drivers; this handle can then be used to communicate with that driver.

Note that when an application installs a local driver for its own use, the acmDriverAdd function returns a driver handle, which can be used to communicate with the driver. It is not necessary to use acmDriverEnum in this case.


Adding Drivers Within an Application

If you need your application to implement its own compression routines internally, the application can add drivers to the ACM by calling the acmDriverAdd function. The application implements the driver by providing a function that conforms to the acmDriverProc prototype. Once the application has added the driver, the application can use the driver through the ACM like any other driver.

The ACM treats drivers as either global or local. An application specifies whether a driver should be added as global or local when it calls acmDriverAdd. There are two differences between global and local drivers:

•	For Win32 platforms, unlike the Microsoft Windows operating system versions 3.x, drivers added as global drivers are not shared with other applications.

•	An application can directly alter the priority of a global driver (but not a local driver) by calling the acmDriverPriority function. The ACM conducts a prioritized search when seeking an appropriate driver to satisfy a function call. The ACM always gives local drivers higher priority than global drivers. The most recently added local driver has highest priority.


Generating a Nonstandard Format

Sometimes an application needs a nonstandard format. For example, an application might need a 16-kHz ADPCM-format file. Because 16 kHz is nonstandard, the enumeration functions will not generate this format. In fact, short of custom coding the format algorithms into the application, there is no reliable way to generate a nonstandard format. It is sometimes possible, however, to generate an analogous format by setting up a valid PCM format with all the required information and then using the acmFormatSuggest function. Because compressors and decompressors try to suggest a format that is closest to the desired format, the number of channels and frequency are usually preserved.


Audio Compression Manager Reference

This section describes the functions, messages, and structures associated with the ACM. These elements are grouped as follows.

Drivers

acmDriverAdd
acmDriverClose
ACMDRIVERDETAILS
ACMDRIVERDETAILS
acmDriverEnum
acmDriverEnumCallback
acmDriverID
acmDriverMessage
acmDriverOpen
acmDriverPriority
acmDriverProc
acmDriverRemove

Filters

ACMFILTERCHOOSE
ACMFILTERCHOOSE
acmFilterChooseHookProc
ACMFILTERDETAILS
ACMFILTERDETAILS
acmFilterEnum
acmFilterEnumCallback
ACMFILTERTAGDETAILS
ACMFILTERTAGDETAILS
acmFilterTagEnum
acmFilterTagEnumCallback
WAVEFILTER

Formats

ACMFORMATCHOOSE
ACMFORMATCHOOSE
acmFormatChooseHookProc
ACMFORMATDETAILS
ACMFORMATDETAILS
acmFormatEnum
acmFormatEnumCallback
acmFormatSuggest
ACMFORMATTAGDETAILS
ACMFORMATTAGDETAILS
acmFormatTagEnum
acmFormatTagEnumCallback

Messages

MM_ACM_FILTERCHOOSE
MM_ACM_FORMATCHOOSE

Miscellaneous

acmGetVersion
acmMetrics

Streams

acmStreamClose
acmStreamConvert
acmStreamConvertCallback
ACMSTREAMHEADER
acmStreamMessage
acmStreamOpen
acmStreamPrepareHeader
acmStreamReset
acmStreamSize
acmStreamUnprepareHeader


acmDriverAdd

MMRESULT acmDriverAdd(LPHACMDRIVERID phadid, HINSTANCE hinstModule,
    LPARAM lParam, DWORD dwPriority, DWORD fdwAdd);

Adds a driver to the list of available ACM drivers. The driver type and location are dependent on the flags used to add ACM drivers. After a driver is successfully added, the driver entry function will receive ACM driver messages.

•	Returns zero if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALFLAG	At least one flag is invalid.
MMSYSERR_INVALPARAM	At least one parameter is invalid.
MMSYSERR_NOMEM	The system is unable to allocate resources.
phadid

Address that is filled with a handle identifying the installed driver. This handle is used to identify the driver in calls to other ACM functions.

hinstModule

Handle of the instance of the module whose executable or dynamic-link library (DLL) contains the driver entry function.

lParam

Driver function address or a notification window handle, depending on the fdwAdd flags.

dwPriority

Window message to send for notification broadcasts. This parameter is used only with the ACM_DRIVERADDF_NOTIFYHWND flag. All other flags require this member to be set to zero.

fdwAdd

Flags for adding ACM drivers. The following values are defined:

ACM_DRIVERADDF_FUNCTION

The lParam parameter is a driver function address conforming to the acmDriverProc prototype. The function may reside in either an executable or DLL file.

ACM_DRIVERADDF_GLOBAL

Provided for compatibility with 16-bit applications. For the Win32 API, ACM drivers added by the acmDriverAdd function can be used only by the application that added the driver. This is true whether or not ACM_DRIVERADDF_GLOBAL is specified. For more information, see "Adding Drivers Within an Application" earlier in this chapter.

ACM_DRIVERADDF_LOCAL

The ACM automatically gives a local driver higher priority than a global driver when searching for a driver to satisfy a function call. For more information, see "Adding Drivers Within an Application" earlier in this chapter.

ACM_DRIVERADDF_NOTIFYHWND

The lParam parameter is a handle of a notification window that receives messages when changes to global driver priorities and states are made. The window message to receive is defined by the application and must be passed in dwPriority. The wParam and lParam parameters passed with the window message are reserved for future use and should be ignored. ACM_DRIVERADDF_GLOBAL cannot be specified in conjunction with this flag. For more information about driver priorities, see the description for the acmDriverPriority function.


acmDriverClose

MMRESULT acmDriverClose(HACMDRIVER had, DWORD fdwClose);

Closes a previously opened ACM driver instance. If the function is successful, the handle is invalidated.

•	Returns zero if successful or an error otherwise. Possible error values include the following:

ACMERR_BUSY	The driver is in use and cannot be closed.
MMSYSERR_INVALFLAG	At least one flag is invalid.
MMSYSERR_INVALHANDLE	The specified handle is invalid.
had

Handle of the open driver instance to be closed.

fdwClose

Reserved; must be zero.


acmDriverDetails

MMRESULT acmDriverDetails(HACMDRIVERID hadid, LPACMDRIVERDETAILS padd,
    DWORD fdwDetails);

Queries a specified ACM driver to determine its capabilities.

•	Returns zero if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALFLAG	At least one flag is invalid.
MMSYSERR_INVALHANDLE	The specified handle is invalid.
MMSYSERR_INVALPARAM	At least one parameter is invalid.
hadid

Handle of the driver identifier of an installed ACM driver. Disabled drivers can be queried for details.

padd

Address of an ACMDRIVERDETAILS structure that will receive the driver details. The cbStruct member must be initialized to the size, in bytes, of the structure.

fdwDetails

Reserved; must be zero.


acmDriverEnum

MMRESULT acmDriverEnum(ACMDRIVERENUMCB fnCallback, DWORD dwInstance,
    DWORD fdwEnum);

Enumerates the available ACM drivers, continuing until there are no more drivers or the callback function returns FALSE.

•	Returns zero if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALFLAG	At least one flag is invalid.
MMSYSERR_INVALPARAM	At least one parameter is invalid.
fnCallback

Procedure instance address of the application-defined callback function.

dwInstance

A 32-bit application-defined value that is passed to the callback function along with ACM driver information.

fdwEnum

Flags for enumerating ACM drivers. The following values are defined:

ACM_DRIVERENUMF_DISABLED

Disabled ACM drivers should be included in the enumeration. Drivers can be disabled by the user through the Control Panel or by an application using the acmDriverPriority function. If a driver is disabled, the fdwSupport parameter to the callback function will have the ACMDRIVERDETAILS_SUPPORTF_DISABLED flag set.

ACM_DRIVERENUMF_NOLOCAL

Only global drivers should be included in the enumeration.

The acmDriverEnum function will return MMSYSERR_NOERROR (zero) if no ACM drivers are installed. Moreover, the callback function will not be called.


acmDriverEnumCallback

BOOL ACMDRIVERENUMCB acmDriverEnumCallback(HACMDRIVERID hadid,
    DWORD dwInstance, DWORD fdwSupport);

Specifies a callback function used with the acmDriverEnum function. The acmDriverEnumCallback name is a placeholder for an application-defined function name.

•	The callback function must return TRUE to continue enumeration or FALSE to stop enumeration.

hadid

Handle of an ACM driver identifier.

dwInstance

Application-defined value specified in acmDriverEnum.

fdwSupport

Driver-support flags specific to the driver specified by hadid. These flags are identical to the fdwSupport flags of the ACMDRIVERDETAILS structure. This parameter can be a combination of the following values:

ACMDRIVERDETAILS_SUPPORTF_ASYNC

Driver supports asynchronous conversions.

ACMDRIVERDETAILS_SUPPORTF_CODEC

Driver supports conversion between two different format tags. For example, if a driver supports compression from WAVE_FORMAT_PCM to WAVE_FORMAT_ADPCM, this flag is set.

ACMDRIVERDETAILS_SUPPORTF_CONVERTER

Driver supports conversion between two different formats of the same format tag. For example, if a driver supports resampling of WAVE_FORMAT_PCM, this flag is set.

ACMDRIVERDETAILS_SUPPORTF_DISABLED

Driver has been disabled. An application must specify the ACM_DRIVERENUMF_DISABLED flag with acmDriverEnum to include disabled drivers in the enumeration.

ACMDRIVERDETAILS_SUPPORTF_FILTER

Driver supports a filter (modification of the data without changing any of the format attributes). For example, if a driver supports volume or echo operations on WAVE_FORMAT_PCM, this flag is set.

The acmDriverEnum function will return MMSYSERR_NOERROR (zero) if no ACM drivers are installed. Moreover, the callback function will not be called.

The following functions should not be called from within the callback function: acmDriverAdd, acmDriverRemove, and acmDriverPriority.


acmDriverID

MMRESULT acmDriverID(HACMOBJ hao, LPHACMDRIVERID phadid,
    DWORD fdwDriverID);

Returns the handle of an ACM driver identifier associated with an open ACM driver instance or stream handle.

•	Returns zero if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALFLAG	At least one flag is invalid.
MMSYSERR_INVALHANDLE	The specified handle is invalid.
MMSYSERR_INVALPARAM	At least one parameter is invalid.
hao

Handle of the open driver instance or stream handle. This is the handle of an ACM object, such HACMDRIVER or HACMSTREAM.

phadid

Address that is filled with a handle identifying the installed driver that is associated with hao.

fdwDriverID

Reserved; must be zero.


acmDriverMessage

LRESULT acmDriverMessage(HACMDRIVER had, UINT uMsg, LPARAM lParam1,
    LPARAM lParam2);

Sends a user-defined message to a given ACM driver instance.

•	The return value is specific to the user-defined ACM driver message specified by the uMsg parameter. However, possible error values include the following:

MMSYSERR_INVALHANDLE	The specified handle is invalid.
MMSYSERR_INVALPARAM	The uMsg parameter is not in the ACMDM_USER range.
MMSYSERR_NOTSUPPORTED	The ACM driver did not process the message.
had

Handle of the ACM driver instance to which the message will be sent.

uMsg

Message that the ACM driver must process. This message must be in the ACMDM_USER message range (above or equal to ACMDM_USER and less than ACMDM_RESERVED_LOW). The exceptions to this restriction are the ACMDM_DRIVER_ABOUT, DRV_QUERYCONFIGURE, and DRV_CONFIGURE messages.

lParam1 and lParam2

Message parameters.

To display a custom About dialog box from an ACM driver, an application must send the ACMDM_DRIVER_ABOUT message to the driver. The lParam1 parameter should be the handle of the owner window for the custom About dialog box, and lParam2 must be set to zero. If the driver does not support a custom About dialog box, MMSYSERR_NOTSUPPORTED will be returned and it is the application's responsibility to display its own dialog box. For example, the Control Panel Sound Mapper option will display a default About dialog box based on the ACMDRIVERDETAILS structure when an ACM driver returns MMSYSERR_NOTSUPPORTED. An application can query a driver for custom About dialog box support without the dialog box being displayed by setting lParam1 to − 1L. If the driver supports a custom About dialog box, MMSYSERR_NOERROR will be returned. Otherwise, the return value is MMSYSERR_NOTSUPPORTED.

User-defined messages must be sent only to an ACM driver that specifically supports the messages. The caller should verify that the ACM driver is the correct driver by retrieving the driver details and checking the wMid, wPid, and vdwDriver members of the ACMDRIVERDETAILS structure.

Never send user-defined messages to an unknown ACM driver.


acmDriverOpen

MMRESULT acmDriverOpen(LPHACMDRIVER phad, HACMDRIVERID hadid,
    DWORD fdwOpen);

Opens the specified ACM driver and returns a driver instance handle that can be used to communicate with the driver.

•	Returns zero if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALFLAG	At least one flag is invalid.
MMSYSERR_INVALHANDLE	The specified handle is invalid.
MMSYSERR_INVALPARAM	At least one parameter is invalid.
MMSYSERR_NOMEM	The system is unable to allocate resources.
MMSYSERR_NOTENABLED	The driver is not enabled.
phad

Address that will receive the new driver instance handle that can be used to communicate with the driver.

hadid

Handle of the driver identifier of an installed and enabled ACM driver.

fdwOpen

Reserved; must be zero.


acmDriverPriority

MMRESULT acmDriverPriority(HACMDRIVERID hadid, DWORD dwPriority,
    DWORD fdwPriority);

Modifies the priority and state of an ACM driver.

•	Returns zero if successful or an error otherwise. Possible error values include the following:

MMSYSERR_ALLOCATED	The deferred broadcast lock is owned by a different task.
MMSYSERR_INVALFLAG	At least one flag is invalid.
MMSYSERR_INVALHANDLE	The specified handle is invalid.
MMSYSERR_INVALPARAM	At least one parameter is invalid.
MMSYSERR_NOTSUPPORTED	The requested operation is not supported for the specified driver. For example, local and notify driver identifiers do not support priorities (but can be enabled and disabled). If an application specifies a nonzero value for dwPriority for local and notify driver identifiers, this error will be returned.
hadid

Handle of the driver identifier of an installed ACM driver. If the ACM_DRIVERPRIORITYF_BEGIN and ACM_DRIVERPRIORITYF_END flags are specified, this parameter must be NULL.

dwPriority

New priority for a global ACM driver identifier. A zero value specifies that the priority of the driver identifier should remain unchanged. A value of 1 specifies that the driver should be placed as the highest search priority driver. A value of − 1 specifies that the driver should be placed as the lowest search priority driver. Priorities are used only for global drivers.

fdwPriority

Flags for setting priorities of ACM drivers. The following values are defined:

ACM_DRIVERPRIORITYF_BEGIN

Change notification broadcasts should be deferred. An application must reenable notification broadcasts as soon as possible with the ACM_DRIVERPRIORITYF_END flag. Note that hadid must be NULL, dwPriority must be zero, and only the ACM_DRIVERPRIORITYF_BEGIN flag can be set.

ACM_DRIVERPRIORITYF_DISABLE

ACM driver should be disabled if it is currently enabled. Disabling a disabled driver does nothing.

ACM_DRIVERPRIORITYF_ENABLE

ACM driver should be enabled if it is currently disabled. Enabling an enabled driver does nothing.

ACM_DRIVERPRIORITYF_END

Calling task wants to reenable change notification broadcasts. An application must call acmDriverPriority with ACM_DRIVERPRIORITYF_END for each successful call with the ACM_DRIVERPRIORITYF_BEGIN flag. Note that hadid must be NULL, dwPriority must be zero, and only the ACM_DRIVERPRIORITYF_END flag can be set.

All driver identifiers can be enabled and disabled, including global, local and notification driver identifiers.

If more than one global driver identifier needs to be enabled, disabled or shifted in priority, an application should defer change notification broadcasts by using the ACM_DRIVERPRIORITYF_BEGIN flag. A single change notification will be broadcast when the ACM_DRIVERPRIORITYF_END flag is specified.

An application can use the acmMetrics function with the ACM_METRIC_DRIVER_PRIORITY metric index to retrieve the current priority of a global driver. Drivers are always enumerated from highest to lowest priority by the acmDriverEnum function.

All enabled driver identifiers will receive change notifications. An application can register a notification message by using the acmDriverAdd function in conjunction with the ACM_DRIVERADDF_NOTIFYHWND flag. Changes to nonglobal driver identifiers will not be broadcast.

Priorities are simply used for the search order when an application does not specify a driver. Boosting the priority of a driver will have no effect on the performance of a driver.


acmDriverProc

LRESULT CALLBACK acmDriverProc(DWORD dwID, HDRIVER hdrvr, UINT uMsg,
    LPARAM lParam1, LPARAM lParam2);

Specifies a callback function used with the ACM driver. The acmDriverProc name is a placeholder for an application-defined function name. The actual name must be exported by including it in the module-definition file of the executable or DLL file.

dwID

Identifier of the installable ACM driver.

hdrvr

Handle of the installable ACM driver. This parameter is a unique handle the ACM assigns to the driver.

uMsg

ACM driver message.

lParam1 and lParam2

Message parameters.

Applications should not call any system-defined functions from inside a callback function, except for PostMessage, timeGetSystemTime, timeGetTime, timeSetEvent, timeKillEvent, midiOutShortMsg, midiOutLongMsg, and OutputDebugStr.


acmDriverRemove

MMRESULT acmDriverRemove(HACMDRIVERID hadid, DWORD fdwRemove);

Removes an ACM driver from the list of available ACM drivers. The driver will be removed for the calling application only. If the driver is globally installed, other applications will still be able to use it.

•	Returns zero if successful or an error otherwise. Possible error values include the following:

ACMERR_BUSY	The driver is in use and cannot be removed.
MMSYSERR_INVALFLAG	At least one flag is invalid.
MMSYSERR_INVALHANDLE	The specified handle is invalid.
hadid

Handle of the driver identifier to be removed.

fdwRemove

Reserved; must be zero.


acmFilterChoose

MMRESULT acmFilterChoose(LPACMFILTERCHOOSE pafltrc);

Creates an ACM-defined dialog box that enables the user to select a waveform-audio filter.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

ACMERR_CANCELED	The user chose the Cancel button or the Close command on the System menu to close the dialog box.
ACMERR_NOTPOSSIBLE	The buffer identified by the pwfltr member of the ACMFILTERCHOOSE structure is too small to contain the selected filter.
MMSYSERR_INVALFLAG	At least one flag is invalid.
MMSYSERR_INVALHANDLE	The specified handle is invalid.
MMSYSERR_INVALPARAM	At least one parameter is invalid.
MMSYSERR_NODRIVER	A suitable driver is not available to provide valid filter selections.
pafltrc

Address of an ACMFILTERCHOOSE structure that contains information used to initialize the dialog box. When acmFilterChoose returns, this structure contains information about the user's filter selection.

The pwfltr member of this structure must contain a valid pointer to a memory location that will contain the returned filter header structure. The cbwfltr member must be filled in with the size, in bytes, of this memory buffer.


acmFilterChooseHookProc

UINT ACMFILTERCHOOSEHOOKPROC acmFilterChooseHookProc(HWND hwnd,
    UINT uMsg, WPARAM wParam, LPARAM lParam);

Specifies a user-defined function that hooks the acmFilterChoose dialog box.

hwnd

Window handle for the dialog box.

uMsg

Window message.

wParam and lParam

Message parameters.

To customize the dialog box selections, a hook function can optionally process the MM_ACM_FILTERCHOOSE message.

You should use this function the same way as you use the Common Dialog hook functions for customizing common dialog boxes.


acmFilterDetails

MMRESULT acmFilterDetails(HACMDRIVER had, LPACMFILTERDETAILS pafd,
    DWORD fdwDetails);

Queries the ACM for details about a filter with a specific waveform-audio filter tag.

•	Returns zero if successful or an error otherwise. Possible error values include the following:

ACMERR_NOTPOSSIBLE	The details requested are not available.
MMSYSERR_INVALFLAG	At least one flag is invalid.
MMSYSERR_INVALHANDLE	The specified handle is invalid.
MMSYSERR_INVALPARAM	At least one parameter is invalid.
had

Handle of the ACM driver to query for waveform-audio filter details for a filter tag. If this parameter is NULL, the ACM uses the details from the first suitable ACM driver.

pafd

Address of the ACMFILTERDETAILS structure that is to receive the filter details for the given filter tag.

fdwDetails

Flags for getting the details. The following values are defined:

ACM_FILTERDETAILSF_FILTER

A WAVEFILTER structure pointed to by the pwfltr member of the ACMFILTERDETAILS structure was given and the remaining details should be returned. The dwFilterTag member of the ACMFILTERDETAILS structure must be initialized to the same filter tag pwfltr specifies. This query type can be used to get a string description of an arbitrary filter structure. If an application specifies an ACM driver handle for had, details on the filter will be returned for that driver. If an application specifies NULL for had, the ACM finds the first acceptable driver to return the details.

ACM_FILTERDETAILSF_INDEX

A filter index for the filter tag was given in the dwFilterIndex member of the ACMFILTERDETAILS structure. The filter details will be returned in the structure defined by pafd. The index ranges from zero to one less than the cStandardFilters member returned in the ACMFILTERTAGDETAILS structure for a filter tag. An application must specify a driver handle for had when retrieving filter details with this flag. For information about what members should be initialized before calling this function, see the ACMFILTERDETAILS structure.


acmFilterEnum

MMRESULT acmFilterEnum(HACMDRIVER had, LPACMFILTERDETAILS pafd,
    ACMFILTERENUMCB fnCallback, DWORD dwInstance, DWORD fdwEnum);

Enumerates waveform-audio filters available for a given filter tag from an ACM driver. This function continues enumerating until there are no more suitable filters for the filter tag or the callback function returns FALSE.

•	Returns zero if successful or an error otherwise. Possible error values include the following:

ACMERR_NOTPOSSIBLE	The details for the filter cannot be returned.
MMSYSERR_INVALFLAG	At least one flag is invalid.
MMSYSERR_INVALHANDLE	The specified handle is invalid.
MMSYSERR_INVALPARAM	At least one parameter is invalid.
had

Handle of the ACM driver to query for waveform-audio filter details. If this parameter is NULL, the ACM uses the details from the first suitable ACM driver.

pafd

Address of the ACMFILTERDETAILS structure that contains the filter details when it is passed to the function specified by fnCallback. When your application calls acmFilterEnum, the cbStruct, pwfltr, and cbwfltr members of this structure must be initialized. The dwFilterTag member must also be initialized to either WAVE_FILTER_UNKNOWN or a valid filter tag.

fnCallback

Procedure-instance address of the application-defined callback function.

dwInstance

A 32-bit, application-defined value that is passed to the callback function along with ACM filter details.

fdwEnum

Flags for enumerating the filters for a given filter tag. The following values are defined:

ACM_FILTERENUMF_DWFILTERTAG

The dwFilterTag member of the WAVEFILTER structure pointed to by the pwfltr member of the ACMFILTERDETAILS structure is valid. The enumerator will enumerate only a filter that conforms to this attribute. The dwFilterTag member of the ACMFILTERDETAILS structure must be equal to the dwFilterTag member of the WAVEFILTER structure.

The acmFilterEnum function will return MMSYSERR_NOERROR (zero) if no suitable ACM drivers are installed. Moreover, the callback function will not be called.

The following functions should not be called from within the callback function: acmDriverAdd, acmDriverRemove, acmDriverPriority.


acmFilterEnumCallback

BOOL ACMFILTERENUMCB acmFilterEnumCallback(HACMDRIVERID hadid,
    LPACMFILTERDETAILS pafd, DWORD dwInstance, DWORD fdwSupport);

Specifies a callback function used with the acmFilterEnum function. The acmFilterEnumCallback name is a placeholder for an application-defined function name.

•	The callback function must return TRUE to continue enumeration or FALSE to stop enumeration.

hadid

Handle of the ACM driver identifier.

pafd

Address of an ACMFILTERDETAILS structure that contains the enumerated filter details for a filter tag.

dwInstance

Application-defined value specified in acmFilterEnum.

fdwSupport

Driver-support flags specific to the driver identified by hadid for the specified filter. These flags are identical to the fdwSupport flags of the ACMDRIVERDETAILS structure, but they are specific to the filter that is being enumerated. This parameter can be a combination of the following values and identifies which operations the driver supports for the filter tag:

ACMDRIVERDETAILS_SUPPORTF_ASYNC

Driver supports asynchronous conversions with the specified filter tag.

ACMDRIVERDETAILS_SUPPORTF_CODEC

Driver supports conversion between two different format tags while using the specified filter. For example, if a driver supports compression from WAVE_FORMAT_PCM to WAVE_FORMAT_ADPCM with the specified filter, this flag is set.

ACMDRIVERDETAILS_SUPPORTF_CONVERTER

Driver supports conversion between two different formats of the same format tag while using the specified filter. For example, if a driver supports resampling of WAVE_FORMAT_PCM with the specified filter, this flag is set.

ACMDRIVERDETAILS_SUPPORTF_FILTER

Driver supports a filter (modification of the data without changing any of the format attributes). For example, if a driver supports volume or echo operations on WAVE_FORMAT_PCM, this flag is set.

ACMDRIVERDETAILS_SUPPORTF_HARDWARE

Driver supports hardware input, output, or both with the specified filter through a waveform-audio device. An application should use the acmMetrics function with the ACM_METRIC_HARDWARE_WAVE_INPUT and ACM_METRIC_HARDWARE_WAVE_OUTPUT metric indices to get the waveform-audio device identifiers associated with the supporting ACM driver.

The acmFilterEnum function will return MMSYSERR_NOERROR (zero) if no filters are to be enumerated. Moreover, the callback function will not be called.

The following functions should not be called from within the callback function: acmDriverAdd, acmDriverRemove, acmDriverPriority.


acmFilterTagDetails

MMRESULT acmFilterTagDetails(HACMDRIVER had,
    LPACMFILTERTAGDETAILS paftd, DWORD fdwDetails);

Queries the ACM for details about a specific waveform-audio filter tag.

•	Returns zero if successful or an error otherwise. Possible error values include the following:

ACMERR_NOTPOSSIBLE	The details requested are not available.
MMSYSERR_INVALFLAG	At least one flag is invalid.
MMSYSERR_INVALHANDLE	The specified handle is invalid.
MMSYSERR_INVALPARAM	At least one parameter is invalid.
had

Handle of the ACM driver to query for waveform-audio filter tag details. If this parameter is NULL, the ACM uses the details from the first suitable ACM driver. An application must specify a valid HACMDRIVER or HACMDRIVERID identifier when using the ACM_FILTERTAGDETAILSF_INDEX query type. Driver identifiers for disabled drivers are not allowed.

paftd

Address of the ACMFILTERTAGDETAILS structure that is to receive the filter tag details.

fdwDetails

Flags for getting the details. The following values are defined:

ACM_FILTERTAGDETAILSF_FILTERTAG

A filter tag was given in the dwFilterTag member of the ACMFILTERTAGDETAILS structure. The filter tag details will be returned in the structure pointed to by paftd. If an application specifies an ACM driver handle for had, details on the filter tag will be returned for that driver. If an application specifies NULL for had, the ACM finds the first acceptable driver to return the details.

ACM_FILTERTAGDETAILSF_INDEX

A filter tag index was given in the dwFilterTagIndex member of the ACMFILTERTAGDETAILS structure. The filter tag and details will be returned in the structure pointed to by paftd. The index ranges from zero to one less than the cFilterTags member returned in the ACMDRIVERDETAILS structure for an ACM driver. An application must specify a driver handle for had when retrieving filter tag details with this flag.

ACM_FILTERTAGDETAILSF_LARGESTSIZE

Details on the filter tag with the largest filter size, in bytes, are to be returned. The dwFilterTag member must either be WAVE_FILTER_UNKNOWN or the filter tag to find the largest size for. If an application specifies an ACM driver handle for had, details on the largest filter tag will be returned for that driver. If an application specifies NULL for had, the ACM finds an acceptable driver with the largest filter tag requested to return the details.


acmFilterTagEnum

MMRESULT acmFilterTagEnum(HACMDRIVER had, LPACMFILTERTAGDETAILS paftd,
    ACMFILTERTAGENUMCB fnCallback, DWORD dwInstance, DWORD fdwEnum);

Enumerates waveform-audio filter tags available from an ACM driver. This function continues enumerating until there are no more suitable filter tags or the callback function returns FALSE.

•	Returns zero if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALFLAG	At least one flag is invalid.
MMSYSERR_INVALHANDLE	The specified handle is invalid.
MMSYSERR_INVALPARAM	At least one parameter is invalid.
had

Handle of the ACM driver to query for waveform-audio filter tag details. If this parameter is NULL, the ACM uses the details from the first suitable ACM driver.

paftd

Address of the ACMFILTERTAGDETAILS structure that contains the filter tag details when it is passed to the fnCallback function. When your application calls acmFilterTagEnum, the cbStruct member of this structure must be initialized.

fnCallback

Procedure instance address of the application-defined callback function.

dwInstance

A 32-bit application-defined value that is passed to the callback function along with ACM filter tag details.

fdwEnum

Reserved; must be zero.

This function will return MMSYSERR_NOERROR (zero) if no suitable ACM drivers are installed. Moreover, the callback function will not be called.


acmFilterTagEnumCallback

BOOL ACMFILTERTAGENUMCB acmFilterTagEnumCallback(HACMDRIVERID hadid,
    LPACMFILTERTAGDETAILS paftd, DWORD dwInstance, DWORD fdwSupport);

Specifies a callback function used with the acmFilterTagEnum function. The acmFilterTagEnumCallback function name is a placeholder for an application-defined function name.

•	The callback function must return TRUE to continue enumeration or FALSE to stop enumeration.

hadid

Handle of the ACM driver identifier.

paftd

Address of an ACMFILTERTAGDETAILS structure that contains the enumerated filter tag details.

dwInstance

Application-defined value specified in acmFilterTagEnum.

fdwSupport

Driver-support flags specific to the driver identifier hadid. These flags are identical to the fdwSupport flags of the ACMDRIVERDETAILS structure. This parameter can be a combination of the following values and identifies which operations the driver supports with the filter tag:

ACMSDRIVERDETAILS_SUPPORTF_ASYNC

Driver supports asynchronous conversions with the specified filter tag.

ACMDRIVERDETAILS_SUPPORTF_CODEC

Driver supports conversion between two different format tags while using the specified filter tag. For example, if a driver supports compression from WAVE_FORMAT_PCM to WAVE_FORMAT_ADPCM with the specified filter tag, this flag is set.

ACMDRIVERDETAILS_SUPPORTF_CONVERTER

Driver supports conversion between two different formats of the same format tag while using the specified filter tag. For example, if a driver supports resampling of WAVE_FORMAT_PCM with the specified filter tag, this flag is set.

ACMDRIVERDETAILS_SUPPORTF_FILTER

Driver supports a filter (modification of the data without changing any of the format attributes). For example, if a driver supports volume or echo operations on WAVE_FORMAT_PCM, this flag is set.

ACMDRIVERDETAILS_SUPPORTF_HARDWARE

Driver supports hardware input, output, or both with the specified filter tag through a waveform-audio device. An application should use the acmMetrics function with the ACM_METRIC_HARDWARE_WAVE_INPUT and ACM_METRIC_HARDWARE_WAVE_OUTPUT metric indices to get the waveform-audio device identifiers associated with the supporting ACM driver.

The acmFilterTagEnum function will return MMSYSERR_NOERROR (zero) if no filter tags are to be enumerated. Moreover, the callback function will not be called.

The following functions should not be called from within the callback function: acmDriverAdd, acmDriverRemove, and acmDriverPriority.


acmFormatChoose

MMRESULT acmFormatChoose(LPACMFORMATCHOOSE pfmtc);

Creates an ACM-defined dialog box that enables the user to select a waveform-audio format.

•	Returns MMSYSERR_NOERROR if the function was successful or an error otherwise. Possible error values include the following:

ACMERR_CANCELED	The user chose the Cancel button or the Close command on the System menu to close the dialog box.
ACMERR_NOTPOSSIBLE	The buffer identified by the pwfx member of the ACMFORMATCHOOSE structure is too small to contain the selected format.
MMSYSERR_INVALFLAG	At least one flag is invalid.
MMSYSERR_INVALHANDLE	The specified handle is invalid.
MMSYSERR_INVALPARAM	At least one parameter is invalid.
MMSYSERR_NODRIVER	A suitable driver is not available to provide valid format selections.
pfmtc

Address of an ACMFORMATCHOOSE structure that contains information used to initialize the dialog box. When this function returns, this structure contains information about the user's format selection.

The pwfx member of this structure must contain a valid pointer to a memory location that will contain the returned format header structure. Moreover, the cbwfx member must be filled in with the size, in bytes, of this memory buffer.


acmFormatChooseHookProc

UINT ACMFORMATCHOOSEHOOKPROC acmFormatChooseHookProc(HWND hwnd,
    UINT uMsg, WPARAM wParam, LPARAM lParam);

Specifies a user-defined function that hooks the acmFormatChoose dialog box. The acmFormatChooseHookProc name is a placeholder for an application-defined name.

hwnd

Window handle for the dialog box.

uMsg

Window message.

wParam and lParam

Message parameters.

If the hook function processes one of the WM_CTLCOLOR messages, this function must return a handle of the brush that should be used to paint the control background.

A hook function can optionally process the MM_ACM_FORMATCHOOSE message.

You should use this function the same way as you use the Common Dialog hook functions for customizing common dialog boxes.


acmFormatDetails

MMRESULT acmFormatDetails(HACMDRIVER had, LPACMFORMATDETAILS pafd,
    DWORD fdwDetails);

Queries the ACM for format details for a specific waveform-audio format tag.

•	Returns zero if successful or an error otherwise. Possible error values include the following:

ACMERR_NOTPOSSIBLE	The details requested are not available.
MMSYSERR_INVALFLAG	At least one flag is invalid.
MMSYSERR_INVALHANDLE	The specified handle is invalid.
MMSYSERR_INVALPARAM	At least one parameter is invalid.
had

Handle of the ACM driver to query for waveform-audio format details for a format tag. If this parameter is NULL, the ACM uses the details from the first suitable ACM driver.

pafd

Address of an ACMFORMATDETAILS structure to contain the format details for the given format tag.

fdwDetails

Flags for getting the waveform-audio format tag details. The following values are defined:

ACM_FORMATDETAILSF_FORMAT

A WAVEFORMATEX structure pointed to by the pwfx member of the ACMFORMATDETAILS structure was given and the remaining details should be returned. The dwFormatTag member of the ACMFORMATDETAILS structure must be initialized to the same format tag as pwfx specifies. This query type can be used to get a string description of an arbitrary format structure. If an application specifies an ACM driver handle for had, details on the format will be returned for that driver. If an application specifies NULL for had, the ACM finds the first acceptable driver to return the details.

ACM_FORMATDETAILSF_INDEX

A format index for the format tag was given in the dwFormatIndex member of the ACMFORMATDETAILS structure. The format details will be returned in the structure defined by pafd. The index ranges from zero to one less than the cStandardFormats member returned in the ACMFORMATTAGDETAILS structure for a format tag. An application must specify a driver handle for had when retrieving format details with this flag. For information about which members should be initialized before calling this function, see the ACMFORMATDETAILS structure.


acmFormatEnum

MMRESULT acmFormatEnum(HACMDRIVER had, LPACMFORMATDETAILS pafd,
    ACMFORMATENUMCB fnCallback, DWORD dwInstance, DWORD fdwEnum);

Enumerates waveform-audio formats available for a given format tag from an ACM driver. This function continues enumerating until there are no more suitable formats for the format tag or the callback function returns FALSE.

•	Returns zero if successful or an error otherwise. Possible error values include the following:

ACMERR_NOTPOSSIBLE	The details for the format cannot be returned.
MMSYSERR_INVALFLAG	At least one flag is invalid.
MMSYSERR_INVALHANDLE	The specified handle is invalid.
MMSYSERR_INVALPARAM	At least one parameter is invalid.
had

Handle of the ACM driver to query for waveform-audio format details. If this parameter is NULL, the ACM uses the details from the first suitable ACM driver.

pafd

Address of an ACMFORMATDETAILS structure to contain the format details passed to the fnCallback function. This structure must have the cbStruct, pwfx, and cbwfx members of the ACMFORMATDETAILS structure initialized. The dwFormatTag member must also be initialized to either WAVE_FORMAT_UNKNOWN or a valid format tag.

fnCallback

Procedure instance address of the application-defined callback function.

dwInstance

A 32-bit application-defined value that is passed to the callback function along with ACM format details.

fdwEnum

Flags for enumerating the formats for a given format tag. The following values are defined:

ACM_FORMATENUMF_CONVERT

The WAVEFORMATEX structure pointed to by the pwfx member of the ACMFORMATDETAILS structure is valid. The enumerator will only enumerate destination formats that can be converted from the given pwfx format.

ACM_FORMATENUMF_HARDWARE

The enumerator should only enumerate formats that are supported as native input or output formats on one or more of the installed waveform-audio devices. This flag provides a way for an application to choose only formats native to an installed waveform-audio device. This flag must be used with one or both of the ACM_FORMATENUMF_INPUT and ACM_FORMATENUMF_OUTPUT flags. Specifying both ACM_FORMATENUMF_INPUT and ACM_FORMATENUMF_OUTPUT will enumerate only formats that can be opened for input or output. This is true regardless of whether this flag is specified.

ACM_FORMATENUMF_INPUT

Enumerator should enumerate only formats that are supported for input (recording).

ACM_FORMATENUMF_NCHANNELS

The nChannels member of the WAVEFORMATEX structure pointed to by the pwfx member of the ACMFORMATDETAILS structure is valid. The enumerator will enumerate only a format that conforms to this attribute.

ACM_FORMATENUMF_NSAMPLESPERSEC

The nSamplesPerSec member of the WAVEFORMATEX structure pointed to by the pwfx member of the ACMFORMATDETAILS structure is valid. The enumerator will enumerate only a format that conforms to this attribute.

ACM_FORMATENUMF_OUTPUT

Enumerator should enumerate only formats that are supported for output (playback).

ACM_FORMATENUMF_SUGGEST

The WAVEFORMATEX structure pointed to by the pwfx member of the ACMFORMATDETAILS structure is valid. The enumerator will enumerate all suggested destination formats for the given pwfx format. This mechanism can be used instead of the acmFormatSuggest function to allow an application to choose the best suggested format for conversion. The dwFormatIndex member will always be set to zero on return.

ACM_FORMATENUMF_WBITSPERSAMPLE

The wBitsPerSample member of the WAVEFORMATEX structure pointed to by the pwfx member of the ACMFORMATDETAILS structure is valid. The enumerator will enumerate only a format that conforms to this attribute.

ACM_FORMATENUMF_WFORMATTAG

The wFormatTag member of the WAVEFORMATEX structure pointed to by the pwfx member of the ACMFORMATDETAILS structure is valid. The enumerator will enumerate only a format that conforms to this attribute. The dwFormatTag member of the ACMFORMATDETAILS structure must be equal to the wFormatTag member.

This function will return MMSYSERR_NOERROR (zero) if no suitable ACM drivers are installed. Moreover, the callback function will not be called.


acmFormatEnumCallback

BOOL ACMFORMATENUMCB acmFormatEnumCallback(HACMDRIVERID hadid,
    LPACMFORMATDETAILS pafd, DWORD dwInstance, DWORD fdwSupport);

Specifies a callback function used with the acmFormatEnum function. The acmFormatEnumCallback name is a placeholder for the application-defined function name.

•	The callback function must return TRUE to continue enumeration or FALSE to stop enumeration.

hadid

Handle of the ACM driver identifier.

pafd

Address of an ACMFORMATDETAILS structure that contains the enumerated format details for a format tag.

dwInstance

Application-defined value specified in the acmFormatEnum function.

fdwSupport

Driver support flags specific to the driver identified by hadid for the specified format. These flags are identical to the fdwSupport flags of the ACMDRIVERDETAILS structure, but they are specific to the format that is being enumerated. This parameter can be a combination of the following values and indicates which operations the driver supports for the format tag:

ACMDRIVERDETAILS_SUPPORTF_ASYNC

Driver supports asynchronous conversions with the specified filter tag.

ACMDRIVERDETAILS_SUPPORTF_CODEC

Driver supports conversion between two different format tags for the specified format. For example, if a driver supports compression from WAVE_FORMAT_PCM to WAVE_FORMAT_ADPCM with the specified format, this flag is set.

ACMDRIVERDETAILS_SUPPORTF_CONVERTER

Driver supports conversion between two different formats of the same format tag while using the specified format. For example, if a driver supports resampling of WAVE_FORMAT_PCM to the specified format, this flag is set.

ACMDRIVERDETAILS_SUPPORTF_FILTER

Driver supports a filter (modification of the data without changing any of the format attributes) with the specified format. For example, if a driver supports volume or echo operations on WAVE_FORMAT_PCM, this flag is set.

ACMDRIVERDETAILS_SUPPORTF_HARDWARE

Driver supports hardware input, output, or both of the specified format tags through a waveform-audio device. An application should use the acmMetrics function with the ACM_METRIC_HARDWARE_WAVE_INPUT and ACM_METRIC_HARDWARE_WAVE_OUTPUT metric indexes to get the waveform-audio device identifiers associated with the supporting ACM driver.

The acmFormatEnum function will return MMSYSERR_NOERROR (zero) if no formats are to be enumerated. Moreover, the callback function will not be called.

The following functions should not be called from within the callback function: acmDriverAdd, acmDriverRemove, and acmDriverPriority.


acmFormatSuggest

MMRESULT acmFormatSuggest(HACMDRIVER had, LPWAVEFORMATEX pwfxSrc,
    LPWAVEFORMATEX pwfxDst, DWORD cbwfxDst, DWORD fdwSuggest);

Queries the ACM or a specified ACM driver to suggest a destination format for the supplied source format. For example, an application can use this function to determine one or more valid PCM formats to which a compressed format can be decompressed.

•	Returns zero if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALFLAG	At least one flag is invalid.
MMSYSERR_INVALHANDLE	The specified handle is invalid.
MMSYSERR_INVALPARAM	At least one parameter is invalid.
had

Handle of an open instance of a driver to query for a suggested destination format. If this parameter is NULL, the ACM attempts to find the best driver to suggest a destination format.

pwfxSrc

Address of a WAVEFORMATEX structure that identifies the source format for which a destination format will be suggested by the ACM or specified driver.

pwfxDst

Address of a WAVEFORMATEX structure that will receive the suggested destination format for the pwfxSrc format. Depending on the fdwSuggest parameter, some members of the structure pointed to by pwfxDst may require initialization.

cbwfxDst

Size, in bytes, available for the destination format. The acmMetrics and acmFormatTagDetails functions can be used to determine the maximum size required for any format available for the specified driver (or for all installed ACM drivers).

fdwSuggest

Flags for matching the desired destination format. The following values are defined:

ACM_FORMATSUGGESTF_NCHANNELS

The nChannels member of the structure pointed to by pwfxDst is valid. The ACM will query acceptable installed drivers that can suggest a destination format matching nChannels or fail.

ACM_FORMATSUGGESTF_NSAMPLESPERSEC

The nSamplesPerSec member of the structure pointed to by pwfxDst is valid. The ACM will query acceptable installed drivers that can suggest a destination format matching nSamplesPerSec or fail.

ACM_FORMATSUGGESTF_WBITSPERSAMPLE

The wBitsPerSample member of the structure pointed to by pwfxDst is valid. The ACM will query acceptable installed drivers that can suggest a destination format matching wBitsPerSample or fail.

ACM_FORMATSUGGESTF_WFORMATTAG

The wFormatTag member of the structure pointed to by pwfxDst is valid. The ACM will query acceptable installed drivers that can suggest a destination format matching wFormatTag or fail.


acmFormatTagDetails

MMRESULT acmFormatTagDetails(HACMDRIVER had,
    LPACMFORMATTAGDETAILS paftd, DWORD fdwDetails);

Queries the ACM for details on a specific waveform-audio format tag.

•	Returns zero if successful or an error otherwise. Possible error values include the following:

ACMERR_NOTPOSSIBLE	The details requested are not available.
MMSYSERR_INVALFLAG	At least one flag is invalid.
MMSYSERR_INVALHANDLE	The specified handle is invalid.
MMSYSERR_INVALPARAM	At least one parameter is invalid.
had

Handle of the ACM driver to query for waveform-audio format tag details. If this parameter is NULL, the ACM uses the details from the first suitable ACM driver. An application must specify a valid handle or driver identifier when using the ACM_FORMATTAGDETAILSF_INDEX query type. Driver identifiers for disabled drivers are not allowed.

paftd

Address of the ACMFORMATTAGDETAILS structure that is to receive the format tag details.

fdwDetails

Flags for getting the details. The following values are defined:

ACM_FORMATTAGDETAILSF_FORMATTAG

A format tag was given in the dwFormatTag member of the ACMFORMATTAGDETAILS structure. The format tag details will be returned in the structure pointed to by paftd. If an application specifies an ACM driver handle for had, details on the format tag will be returned for that driver. If an application specifies NULL for had, the ACM finds the first acceptable driver to return the details.

ACM_FORMATTAGDETAILSF_INDEX

A format tag index was given in the dwFormatTagIndex member of the ACMFORMATTAGDETAILS structure. The format tag and details will be returned in the structure defined by paftd. The index ranges from zero to one less than the cFormatTags member returned in the ACMDRIVERDETAILS structure for an ACM driver. An application must specify a driver handle for had when retrieving format tag details with this flag.

ACM_FORMATTAGDETAILSF_LARGESTSIZE

Details on the format tag with the largest format size, in bytes, are to be returned. The dwFormatTag member of the ACMFORMATTAGDETAILS structure must either be WAVE_FORMAT_UNKNOWN or the format tag to find the largest size for. If an application specifies an ACM driver handle for had, details on the largest format tag will be returned for that driver. If an application specifies NULL for had, the ACM finds an acceptable driver with the largest format tag requested to return the details.


acmFormatTagEnum

MMRESULT acmFormatTagEnum(HACMDRIVER had, LPACMFORMATTAGDETAILS paftd,
    ACMFORMATTAGENUMCB fnCallback, DWORD dwInstance, DWORD fdwEnum);

Enumerates waveform-audio format tags available from an ACM driver. This function continues enumerating until there are no more suitable format tags or the callback function returns FALSE.

•	Returns zero if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALFLAG	At least one flag is invalid.
MMSYSERR_INVALHANDLE	The specified handle is invalid.
MMSYSERR_INVALPARAM	At least one parameter is invalid.
had

Handle of the ACM driver to query for waveform-audio format tag details. If this parameter is NULL, the ACM uses the details from the first suitable ACM driver.

paftd

Address of the ACMFORMATTAGDETAILS structure that is to receive the format tag details passed to the function specified in fnCallback. This structure must have the cbStruct member of the ACMFORMATTAGDETAILS structure initialized.

fnCallback

Procedure instance address of the application-defined callback function.

dwInstance

A 32-bit application-defined value that is passed to the callback function along with ACM format tag details.

fdwEnum

Reserved; must be zero.

This function will return MMSYSERR_NOERROR (zero) if no suitable ACM drivers are installed. Moreover, the callback function will not be called.


acmFormatTagEnumCallback

BOOL ACMFORMATTAGENUMCB acmFormatTagEnumCallback(HACMDRIVERID hadid,
    LPACMFORMATTAGDETAILS paftd, DWORD dwInstance, DWORD fdwSupport);

Specifies a callback function used with the acmFormatTagEnum function. The acmFormatTagEnumCallback name is a placeholder for an application-defined function name.

•	The callback function must return TRUE to continue enumeration or FALSE to stop enumeration.

hadid

Handle of the ACM driver identifier.

paftd

Address of an ACMFORMATTAGDETAILS structure that contains the enumerated format tag details.

dwInstance

Application-defined value specified in the acmFormatTagEnum function.

fdwSupport

Driver-support flags specific to the format tag. These flags are identical to the fdwSupport flags of the ACMDRIVERDETAILS structure. This parameter can be a combination of the following values and indicates which operations the driver supports with the format tag:

ACMDRIVERDETAILS_SUPPORTF_ASYNC

Driver supports asynchronous conversions with the specified filter tag.

ACMDRIVERDETAILS_SUPPORTF_CODEC

Driver supports conversion between two different format tags where one of the tags is the specified format tag. For example, if a driver supports compression from WAVE_FORMAT_PCM to WAVE_FORMAT_ADPCM, this flag is set.

ACMDRIVERDETAILS_SUPPORTF_CONVERTER

Driver supports conversion between two different formats of the specified format tag. For example, if a driver supports resampling of WAVE_FORMAT_PCM, this flag is set.

ACMDRIVERDETAILS_SUPPORTF_FILTER

Driver supports a filter (modification of the data without changing any of the format attributes). For example, if a driver supports volume or echo operations on the specified format tag, this flag is set.

ACMDRIVERDETAILS_SUPPORTF_HARDWARE

Driver supports hardware input, output, or both of the specified format tag through a waveform-audio device. An application should use acmMetrics with the ACM_METRIC_HARDWARE_WAVE_INPUT and ACM_METRIC_HARDWARE_WAVE_OUTPUT metric indexes to get the waveform-audio device identifiers associated with the supporting ACM driver.

The acmFormatTagEnum function will return MMSYSERR_NOERROR (zero) if no format tags are to be enumerated. Moreover, the callback function will not be called.

The following functions should not be called from within the callback function: acmDriverAdd, acmDriverRemove, and acmDriverPriority.


acmGetVersion

DWORD acmGetVersion(VOID);

Returns the version number of the ACM.

•	The version number is returned as a hexadecimal number of the form 0xAABBCCCC, where AA is the major version number, BB is the minor version number, and CCCC is the build number.

Win32 applications must verify that the ACM version is at least 0x03320000 (version 3.50) or greater before attempting to use any other ACM functions. The build number (CCCC) is always zero for the retail (non-debug) version of the ACM.

To display the ACM version for a user, an application should use the following format (note that the values should be printed as unsigned decimals):

{

    DWORD   dw;

    TCHAR   ach[10];

    dw = acmGetVersion();

    wsprintf(ach, "%u.%.02u", HIWORD(dw) >> 8, HIWORD(dw) & 0x00FF);

}


acmMetrics

MMRESULT acmMetrics(HACMOBJ hao, UINT uMetric, LPVOID pMetric);

Returns various metrics for the ACM or related ACM objects.

•	Returns zero if successful or an error otherwise. Possible error values include the following:

ACMERR_NOTPOSSIBLE	The index specified in uMetric cannot be returned for the specified hao.
MMSYSERR_INVALHANDLE	The specified handle is invalid.
MMSYSERR_INVALPARAM	At least one parameter is invalid.
MMSYSERR_NOTSUPPORTED	The index specified in uMetric is not supported.
hao

Handle of the ACM object to query for the metric specified in uMetric. For some queries, this parameter can be NULL.

uMetric

Metric index to be returned in pMetric.

ACM_METRIC_COUNT_CODECS

Returned value is the number of global ACM compressor or decompressor drivers in the system. The hao parameter must be NULL for this metric index. The pMetric parameter must point to a buffer of a size equal to a doubleword value.

ACM_METRIC_COUNT_CONVERTERS

Returned value is the number of global ACM converter drivers in the system. The hao parameter must be NULL for this metric index. The pMetric parameter must point to a buffer of a size equal to a doubleword value.

ACM_METRIC_COUNT_DISABLED

Returned value is the total number of global disabled ACM drivers (of all support types) in the system. The hao parameter must be NULL for this metric index. The pMetric parameter must point to a buffer of a size equal to a doubleword value. The sum of the ACM_METRIC_COUNT_DRIVERS and ACM_METRIC_COUNT_DISABLED metric indices is the total number of globally installed ACM drivers.

ACM_METRIC_COUNT_DRIVERS

Returned value is the total number of enabled global ACM drivers (of all support types) in the system. The hao parameter must be NULL for this metric index. The pMetric parameter must point to a buffer of a size equal to a doubleword value.

ACM_METRIC_COUNT_FILTERS

Returned value is the number of global ACM filter drivers in the system. The hao parameter must be NULL for this metric index. The pMetric parameter must point to a buffer of a size equal to a doubleword value.

ACM_METRIC_COUNT_HARDWARE

Returned value is the number of global ACM hardware drivers in the system. The hao parameter must be NULL for this metric index. The pMetric parameter must point to a buffer of a size equal to a doubleword value.

ACM_METRIC_COUNT_LOCAL_CODECS

Returned value is the number of local ACM compressor drivers, ACM decompressor drivers, or both for the calling task. The hao parameter must be NULL for this metric index. The pMetric parameter must point to a buffer of a size equal to a doubleword value.

ACM_METRIC_COUNT_LOCAL_CONVERTERS

Returned value is the number of local ACM converter drivers for the calling task. The hao parameter must be NULL for this metric index. The pMetric parameter must point to a buffer of a size equal to a doubleword value.

ACM_METRIC_COUNT_LOCAL_DISABLED

Returned value is the total number of local disabled ACM drivers, of all support types, for the calling task. The hao parameter must be NULL for this metric index. The pMetric parameter must point to a buffer of a size equal to a doubleword value. The sum of the ACM_METRIC_COUNT_LOCAL_DRIVERS and ACM_METRIC_COUNT_LOCAL_DISABLED metric indices is the total number of locally installed ACM drivers.

ACM_METRIC_COUNT_LOCAL_DRIVERS

Returned value is the total number of enabled local ACM drivers (of all support types) for the calling task. The hao parameter must be NULL for this metric index. The pMetric parameter must point to a buffer of a size equal to a doubleword value.

ACM_METRIC_COUNT_LOCAL_FILTERS

Returned value is the number of local ACM filter drivers for the calling task. The hao parameter must be NULL for this metric index. The pMetric parameter must point to a buffer of a size equal to a doubleword value.

ACM_METRIC_DRIVER_PRIORITY

Returned value is the current priority for the specified driver. The hao parameter must be a valid ACM driver identifier of the HACMDRIVERID data type. The pMetric parameter must point to a buffer of a size equal to a doubleword value.

ACM_METRIC_DRIVER_SUPPORT

Returned value is the fdwSupport flags for the specified driver. The hao parameter must be a valid ACM driver identifier of the HACMDRIVERID data type. The pMetric parameter must point to a buffer of a size equal to a doubleword value.

ACM_METRIC_HARDWARE_WAVE_INPUT

Returned value is the waveform-audio input device identifier associated with the specified driver. The hao parameter must be a valid ACM driver identifier of the HACMDRIVERID data type that supports the ACMDRIVERDETAILS_SUPPORTF_HARDWARE flag. If no waveform-audio input device is associated with the driver, MMSYSERR_NOTSUPPORTED is returned. The pMetric parameter must point to a buffer of a size equal to a doubleword value.

ACM_METRIC_HARDWARE_WAVE_OUTPUT

Returned value is the waveform-audio output device identifier associated with the specified driver. The hao parameter must be a valid ACM driver identifier of the HACMDRIVERID data type that supports the ACMDRIVERDETAILS_SUPPORTF_HARDWARE flag. If no waveform-audio output device is associated with the driver, MMSYSERR_NOTSUPPORTED is returned. The pMetric parameter must point to a buffer of a size equal to a doubleword value.

ACM_METRIC_MAX_SIZE_FILTER

Returned value is the size of the largest WAVEFILTER structure. If hao is NULL, the return value is the largest WAVEFILTER structure in the system. If hao identifies an open instance of an ACM driver of the HACMDRIVER data type or an ACM driver identifier of the HACMDRIVERID data type, the largest WAVEFILTER structure for that driver is returned. The pMetric parameter must point to a buffer of a size equal to a doubleword value. This metric is not allowed for an ACM stream handle of the HACMSTREAM data type.

ACM_METRIC_MAX_SIZE_FORMAT

Returned value is the size of the largest WAVEFORMATEX structure. If hao is NULL, the return value is the largest WAVEFORMATEX structure in the system. If hao identifies an open instance of an ACM driver of the HACMDRIVER data type or an ACM driver identifier of the HACMDRIVERID data type, the largest WAVEFORMATEX structure for that driver is returned. The pMetric parameter must point to a buffer of a size equal to a doubleword value. This metric is not allowed for an ACM stream handle of the HACMSTREAM data type.

pMetric

Address of the buffer to receive the metric details. The exact definition depends on the uMetric index.


acmStreamClose

MMRESULT acmStreamClose(HACMSTREAM has, DWORD fdwClose);

Closes an ACM conversion stream. If the function is successful, the handle is invalidated.

•	Returns zero if successful or an error otherwise. Possible error values include the following:

ACMERR_BUSY	The conversion stream cannot be closed because an asynchronous conversion is still in progress.
MMSYSERR_INVALFLAG	At least one flag is invalid.
MMSYSERR_INVALHANDLE	The specified handle is invalid.
has

Handle of the open conversion stream to be closed.

fdwClose

Reserved; must be zero.


acmStreamConvert

MMRESULT acmStreamConvert(HACMSTREAM has, LPACMSTREAMHEADER pash,
    DWORD fdwConvert);

Requests the ACM to perform a conversion on the specified conversion stream. A conversion may be synchronous or asynchronous, depending on how the stream was opened.

•	Returns zero if successful or an error otherwise. Possible error values include the following:

ACMERR_BUSY	The stream header specified in pash is currently in use and cannot be reused.
ACMERR_UNPREPARED	The stream header specified in pash is currently not prepared by the acmStreamPrepareHeader function.
MMSYSERR_INVALFLAG	At least one flag is invalid.
MMSYSERR_INVALHANDLE	The specified handle is invalid.
MMSYSERR_INVALPARAM	At least one parameter is invalid.
has

Handle of the open conversion stream.

pash

Address of a stream header that describes source and destination buffers for a conversion. This header must have been prepared previously by using the acmStreamPrepareHeader function.

fdwConvert

Flags for doing the conversion. The following values are defined:

ACM_STREAMCONVERTF_BLOCKALIGN

Only integral numbers of blocks will be converted. Converted data will end on block-aligned boundaries. An application should use this flag for all conversions on a stream until there is not enough source data to convert to a block-aligned destination. In this case, the last conversion should be specified without this flag.

ACM_STREAMCONVERTF_END

ACM conversion stream should begin returning pending instance data. For example, if a conversion stream holds instance data, such as the end of an echo filter operation, this flag will cause the stream to start returning this remaining data with optional source data. This flag can be specified with the ACM_STREAMCONVERTF_START flag.

ACM_STREAMCONVERTF_START

ACM conversion stream should reinitialize its instance data. For example, if a conversion stream holds instance data, such as delta or predictor information, this flag will restore the stream to starting defaults. This flag can be specified with the ACM_STREAMCONVERTF_END flag.

You must use the acmStreamPrepareHeader function to prepare the source and destination buffers before they are passed to acmStreamConvert.

If an asynchronous conversion request is successfully queued by the ACM or driver and the conversion is later determined to be impossible, the ACMSTREAMHEADER structure is posted back to the application's callback function with the cbDstLengthUsed member set to zero.


acmStreamConvertCallback

void CALLBACK acmStreamConvertCallback(HACMSTREAM has, UINT uMsg,
    DWORD dwInstance, LPARAM lParam1, LPARAM lParam2);

Specifies an application-provided callback function to be used when the acmStreamOpen function specifies the CALLBACK_FUNCTION flag. The acmStreamConvertCallback name is a placeholder for an application-defined function name.

has

Handle of the ACM conversion stream associated with the callback function.

uMsg

ACM conversion stream message. The following values are defined:

MM_ACM_CLOSE

ACM has successfully closed the conversion stream identified by has. The handle specified by has is no longer valid after receiving this message.

MM_ACM_DONE

ACM has successfully converted the buffer identified by lParam1 (which is a pointer to the ACMSTREAMHEADER structure) for the stream handle identified by has.

MM_ACM_OPEN

ACM has successfully opened the conversion stream identified by has.

dwInstance

User-instance data given as the dwInstance parameter of the acmStreamOpen function.

lParam1 and lParam2

Message parameters.

The following functions should not be called from within the callback function: acmDriverAdd, acmDriverRemove, and acmDriverPriority.


acmStreamMessage

MMRESULT ACMAPI acmStreamMessage(HACMSTREAM has, UINT uMsg,
    LPARAM lParam1, LPARAM lParam2);

Sends a driver-specific message to an ACM driver.

•	Returns the value returned by the ACM device driver.

has

Handle of an open conversion stream.

uMsg

Message to send.

lParam1 and lParam2

Message parameters.


acmStreamOpen

MMRESULT acmStreamOpen(LPHACMSTREAM phas, HACMDRIVER had,
    LPWAVEFORMATEX pwfxSrc, LPWAVEFORMATEX pwfxDst, LPWAVEFILTER pwfltr,
    DWORD dwCallback, DWORD dwInstance, DWORD fdwOpen);

Opens an ACM conversion stream. Conversion streams are used to convert data from one specified audio format to another.

•	Returns zero if successful or an error otherwise. Possible error values include the following:

ACMERR_NOTPOSSIBLE	The requested operation cannot be performed.
MMSYSERR_INVALFLAG	At least one flag is invalid.
MMSYSERR_INVALHANDLE	The specified handle is invalid.
MMSYSERR_INVALPARAM	At least one parameter is invalid.
MMSYSERR_NOMEM	The system is unable to allocate resources.
phas

Address of a handle that will receive the new stream handle that can be used to perform conversions. This handle is used to identify the stream in calls to other ACM stream conversion functions. If the ACM_STREAMOPENF_QUERY flag is specified, this parameter should be NULL.

had

Handle of an ACM driver. If this handle is specified, it identifies a specific driver to be used for a conversion stream. If this parameter is NULL, all suitable installed ACM drivers are queried until a match is found.

pwfxSrc

Address of a WAVEFORMATEX structure that identifies the desired source format for the conversion.

pwfxDst

Address of a WAVEFORMATEX structure that identifies the desired destination format for the conversion.

pwfltr

Address of a WAVEFILTER structure that identifies the desired filtering operation to perform on the conversion stream. If no filtering operation is desired, this parameter can be NULL. If a filter is specified, the source (pwfxSrc) and destination (pwfxDst) formats must be the same.

dwCallback

Address of a callback function, a handle of a window, or a handle of an event. A callback function will be called only if the conversion stream is opened with the ACM_STREAMOPENF_ASYNC flag. A callback function is notified when the conversion stream is opened or closed and after each buffer is converted. If the conversion stream is opened without the ACM_STREAMOPENF_ASYNC flag, this parameter should be set to zero.

dwInstance

User-instance data passed to the callback function specified by the dwCallback parameter. This parameter is not used with window and event callbacks. If the conversion stream is opened without the ACM_STREAMOPENF_ASYNC flag, this parameter should be set to zero.

fdwOpen

Flags for opening the conversion stream. The following values are defined:

ACM_STREAMOPENF_ASYNC

Stream conversion should be performed asynchronously. If this flag is specified, the application can use a callback function to be notified when the conversion stream is opened and closed and after each buffer is converted. In addition to using a callback function, an application can examine the fdwStatus member of the ACMSTREAMHEADER structure for the ACMSTREAMHEADER_STATUSF_DONE flag.

ACM_STREAMOPENF_NONREALTIME

ACM will not consider time constraints when converting the data. By default, the driver will attempt to convert the data in real time. For some formats, specifying this flag might improve the audio quality or other characteristics.

ACM_STREAMOPENF_QUERY

ACM will be queried to determine whether it supports the given conversion. A conversion stream will not be opened, and no handle will be returned in the phas parameter.

CALLBACK_EVENT

The dwCallback parameter is a handle of an event.

CALLBACK_FUNCTION

The dwCallback parameter is a callback procedure address. The function prototype must conform to the acmStreamConvertCallback prototype.

CALLBACK_WINDOW

The dwCallback parameter is a window handle.

If an ACM driver cannot perform real-time conversions and the ACM_STREAMOPENF_NONREALTIME flag is not specified for the fdwOpen parameter, the open operation will fail returning an ACMERR_NOTPOSSIBLE error code. An application can use the ACM_STREAMOPENF_QUERY flag to determine if real-time conversions are supported for input.

If an application uses a window to receive callback information, the MM_ACM_OPEN, MM_ACM_CLOSE, and MM_ACM_DONE messages are sent to the window procedure function to indicate the progress of the conversion stream. In this case, the wParam parameter identifies the HACMSTREAM handle. The lParam parameter identifies the ACMSTREAMHEADER structure for MM_ACM_DONE, but it is not used for MM_ACM_OPEN and MM_ACM_CLOSE.

If an application uses a function to receive callback information, the MM_ACM_OPEN, MM_ACM_CLOSE, and MM_ACM_DONE messages are sent to the function to indicate the progress of waveform-audio output. The callback function must reside in a dynamic-link library (DLL).

If an application uses an event for callback notification, the event is signaled to indicate the progress of the conversion stream. The event will be signaled when a stream is opened, after each buffer is converted, and when the stream is closed.


acmStreamPrepareHeader

MMRESULT acmStreamPrepareHeader(HACMSTREAM has, LPACMSTREAMHEADER pash,
    DWORD fdwPrepare);

Prepares an ACMSTREAMHEADER structure for an ACM stream conversion. This function must be called for every stream header before it can be used in a conversion stream. An application needs to prepare a stream header only once for the life of a given stream. The stream header can be reused as long as the sizes of the source and destination buffers do not exceed the sizes used when the stream header was originally prepared.

•	Returns zero if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALFLAG	At least one flag is invalid.
MMSYSERR_INVALHANDLE	The specified handle is invalid.
MMSYSERR_INVALPARAM	At least one parameter is invalid.
MMSYSERR_NOMEM	The system is unable to allocate resources.
has

Handle of the conversion steam.

pash

Address of an ACMSTREAMHEADER structure that identifies the source and destination buffers to be prepared.

fdwPrepare

Reserved; must be zero.

Preparing a stream header that has already been prepared has no effect, and the function returns zero. Nevertheless, you should ensure your application does not prepare a stream header multiple times.


acmStreamReset

MMRESULT acmStreamReset(HACMSTREAM has, DWORD fdwReset);

Stops conversions for a given ACM stream. All pending buffers are marked as done and returned to the application.

•	Returns zero if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALFLAG	At least one flag is invalid.
MMSYSERR_INVALHANDLE	The specified handle is invalid.
has

Handle of the conversion stream.

fdwReset

Reserved; must be zero.

Resetting an ACM conversion stream is necessary only for asynchronous conversion streams. Resetting a synchronous conversion stream will succeed, but no action will be taken.


acmStreamSize

MMRESULT acmStreamSize(HACMSTREAM has, DWORD cbInput,
    LPDWORD pdwOutputBytes, DWORD fdwSize);

Returns a recommended size for a source or destination buffer on an ACM stream.

•	Returns zero if successful or an error otherwise. Possible error values include the following:

ACMERR_NOTPOSSIBLE	The requested operation cannot be performed.
MMSYSERR_INVALFLAG	At least one flag is invalid.
MMSYSERR_INVALHANDLE	The specified handle is invalid.
MMSYSERR_INVALPARAM	At least one parameter is invalid.
has

Handle of the conversion stream.

cbInput

Size, in bytes, of the source or destination buffer. The fdwSize flags specify what the input parameter defines. This parameter must be nonzero.

pdwOutputBytes

Address of a variable that contains the size, in bytes, of the source or destination buffer. The fdwSize flags specify what the output parameter defines. If the acmStreamSize function succeeds, this location will always be filled with a nonzero value.

fdwSize

Flags for the stream size query. The following values are defined:

ACM_STREAMSIZEF_DESTINATION

The cbInput parameter contains the size of the destination buffer. The pdwOutputBytes parameter will receive the recommended source buffer size, in bytes.

ACM_STREAMSIZEF_SOURCE

The cbInput parameter contains the size of the source buffer. The pdwOutputBytes parameter will receive the recommended destination buffer size, in bytes.

An application can use this function to determine suggested buffer sizes for either source or destination buffers. The buffer sizes returned might be only an estimation of the actual sizes required for conversion. Because actual conversion sizes cannot always be determined without performing the conversion, the sizes returned will usually be overestimated.

In the event of an error, the location pointed to by pdwOutputBytes will receive zero. This assumes that the pointer specified by pdwOutputBytes is valid.


acmStreamUnprepareHeader

MMRESULT acmStreamUnprepareHeader(HACMSTREAM has,
    LPACMSTREAMHEADER pash, DWORD fdwUnprepare);

Cleans up the preparation performed by the acmStreamPrepareHeader function for an ACM stream. This function must be called after the ACM is finished with the given buffers. An application must call this function before freeing the source and destination buffers.

•	Returns zero if successful or an error otherwise. Possible error values include the following:

ACMERR_BUSY	The stream header specified in pash is currently in use and cannot be unprepared.
ACMERR_UNPREPARED	The stream header specified in pash is currently not prepared by the acmStreamPrepareHeader function.
MMSYSERR_INVALFLAG	At least one flag is invalid.
MMSYSERR_INVALHANDLE	The specified handle is invalid.
MMSYSERR_INVALPARAM	At least one parameter is invalid.
has

Handle of the conversion steam.

pash

Address of an ACMSTREAMHEADER structure that identifies the source and destination buffers to be unprepared.

fdwUnprepare

Reserved; must be zero.

Unpreparing a stream header that has already been unprepared is an error. An application must specify the source and destination buffer lengths (cbSrcLength and cbDstLength, respectively) that were used during a call to the corresponding acmStreamPrepareHeader. Failing to reset these member values will cause acmStreamUnprepareHeader to fail with an MMSYSERR_INVALPARAM error.

The ACM can recover from some errors. The ACM will return a nonzero error, yet the stream header will be properly unprepared. To determine whether the stream header was actually unprepared, an application can examine the ACMSTREAMHEADER_STATUSF_PREPARED flag. If acmStreamUnprepareHeader returns success, the header will always be unprepared.


MM_ACM_FILTERCHOOSE

MM_ACM_FILTERCHOOSE

wParam = (WPARAM) wDropDown

lParam = (LONG) lCustom

Notifies an acmFilterChoose dialog box hook function before adding an element to one of the three drop-down list boxes. This message allows an application to further customize the selections available through the user interface.

•	Returns TRUE if an application handles this message or FALSE otherwise.

wDropDown

Drop-down list box being initialized and a verify or add operation.

FILTERCHOOSE_CUSTOM_VERIFY

The lParam parameter is a pointer to a WAVEFILTER structure to be added to the custom Name drop-down list box.

FILTERCHOOSE_FILTER_ADD

The lParam parameter is a pointer to a buffer that will accept a WAVEFILTER structure to be added to the Filter drop-down list box. The application must copy the filter structure to be added into this buffer.

FILTERCHOOSE_FILTER_VERIFY

The lParam parameter is a pointer to a WAVEFILTER structure to be added to the Filter drop-down list box.

FILTERCHOOSE_FILTERTAG_ADD

The lParam parameter is a pointer to a DWORD that will accept a waveform-audio filter tag to be added to the Filter Tag drop-down list box.

FILTERCHOOSE_FILTERTAG_VERIFY

The lParam parameter is a waveform-audio filter tag to be listed in the Filter Tag drop-down list box.

lCustom

Value defined by the listbox specified in the wParam parameter.

If the application processes the FILTERCHOOSE_FILTER_ADD operation, the size of the memory buffer supplied in lParam will be determined from the acmMetrics function.

If the application processes a verify operation, the application must precede the return value with SetWindowLong(hwnd, DWL_MSGRESULT, (LONG) FALSE) to prevent the dialog box from listing this selection or with SetWindowLong(hwnd, DWL_MSGRESULT, (LONG)TRUE) to allow the dialog box to list this selection. If processing an add operation, the application must precede the return with SetWindowLong(hwnd, DWL_MSGRESULT, (LONG)FALSE) to indicate that no more additions are required or with SetWindowLong(hwnd, DWL_MSGRESULT, (LONG)TRUE) if more additions are required.


MM_ACM_FORMATCHOOSE

MM_ACM_FORMATCHOOSE

wParam = (WPARAM) wDropDown

lParam = (LONG) lCustom

Notifies an acmFormatChoose dialog hook function before adding an element to one of the three drop-down list boxes. This message allows an application to further customize the selections available through the user interface.

•	Returns TRUE if an application handles this message or FALSE otherwise.

wDropDown

Drop-down listbox being initialized and a verify or add operation.

FORMATCHOOSE_CUSTOM_VERIFY

The lParam parameter is a pointer to a WAVEFORMATEX structure to be added to the custom Name drop-down list box.

FORMATCHOOSE_FORMAT_ADD

The lParam parameter is a pointer to a buffer that will accept a WAVEFORMATEX structure to be added to the Format drop-down list box. The application must copy the format structure to be added into this buffer.

FORMATCHOOSE_FORMAT_VERIFY

The lParam parameter is a pointer to a WAVEFORMATEX structure to be added to the Format drop-down list box.

FORMATCHOOSE_FORMATTAG_ADD

The lParam parameter is a pointer to a variable that will accept a waveform-audio format tag to be added to the Format Tag drop-down list box.

FORMATCHOOSE_FORMATTAG_VERIFY

The lParam parameter is a waveform-audio format tag to be listed in the Format Tag drop-down list box.

lCustom

Value defined by the listbox specified in the wParam parameter.

If the application processes the FILTERCHOOSE_FORMAT_ADD operation, the size of the memory buffer supplied in lParam will be determined from the acmMetrics function.

If your application is processing a verify operation, it can prevent the dialog box from listing this selection by calling the SetWindowLong function with nIndex set to DWL_MSGRESULT and lNewLong set to FALSE (cast to a LONG data type). To allow the dialog box to list this selection, call this function with lNewLong set to TRUE.

If your application is processing an add operation, it can indicate that no more additions are required by calling the SetWindowLong function with nIndex set to DWL_MSGRESULT and lNewLong set to FALSE (cast to a LONG data type). To indicate more additions are required, call this function with lNewLong set to TRUE.


ACMDRIVERDETAILS

typedef struct {

    DWORD  cbStruct;     // see below

    FOURCC fccType;      // see below

    FOURCC fccComp;      // see below

    WORD   wMid;         // manufacturer identifier

    WORD   wPid;         // product identifier

    DWORD  vdwACM;       // see below

    DWORD  vdwDriver;    // see below

    DWORD  fdwSupport;   // see below

    DWORD  cFormatTags;  // see below

    DWORD  cFilterTags;  // see below

    HICON  hicon;        // see below

    char  szShortName[ACMDRIVERDETAILS_SHORTNAME_CHARS];  // see below

    char  szLongName[ACMDRIVERDETAILS_LONGNAME_CHARS];    // see below

    char  szCopyright[ACMDRIVERDETAILS_COPYRIGHT_CHARS];  // see below

    char  szLicensing[ACMDRIVERDETAILS_LICENSING_CHARS];  // see below

    char  szFeatures[ACMDRIVERDETAILS_FEATURES_CHARS];    // see below

} ACMDRIVERDETAILS;

Describes the features of an ACM driver.

cbStruct

Size, in bytes, of the valid information contained in the ACMDRIVERDETAILS structure. An application should initialize this member to the size, in bytes, of the desired information. The size specified in this member must be large enough to contain the cbStruct member of the ACMDRIVERDETAILS structure. When the acmDriverDetails function returns, this member contains the actual size of the information returned. The returned information will never exceed the requested size.

fccType

Type of the driver. For ACM drivers, set this member to ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC.

fccComp

Subtype of the driver. This member is currently set to ACMDRIVERDETAILS_FCCCOMP_UNDEFINED (zero).

vdwACM

Version of the ACM for which this driver was compiled. The version number is a hexadecimal number in the format 0xAABBCCCC, where AA is the major version number, BB is the minor version number, and CCCC is the build number. The version parts (major, minor, and build) should be displayed as decimal numbers.

vdwDriver

Version of the driver. The version number is a hexadecimal number in the format 0xAABBCCCC, where AA is the major version number, BB is the minor version number, and CCCC is the build number. The version parts (major, minor, and build) should be displayed as decimal numbers.

fdwSupport

Support flags for the driver. The following values are defined:

ACMDRIVERDETAILS_SUPPORTF_ASYNC

Driver supports asynchronous conversions.

ACMDRIVERDETAILS_SUPPORTF_CODEC

Driver supports conversion between two different format tags. For example, if a driver supports compression from WAVE_FORMAT_PCM to WAVE_FORMAT_ADPCM, this flag is set.

ACMDRIVERDETAILS_SUPPORTF_CONVERTER

Driver supports conversion between two different formats of the same format tag. For example, if a driver supports resampling of WAVE_FORMAT_PCM, this flag is set.

ACMDRIVERDETAILS_SUPPORTF_DISABLED

Driver has been disabled. This flag is set by the ACM for a driver when it has been disabled for any of a number of reasons. Disabled drivers cannot be opened and can be used only under very limited circumstances.

ACMDRIVERDETAILS_SUPPORTF_FILTER

Driver supports a filter (modification of the data without changing any of the format attributes). For example, if a driver supports volume or echo operations on WAVE_FORMAT_PCM, this flag is set.

ACMDRIVERDETAILS_SUPPORTF_HARDWARE

Driver supports hardware input, output, or both through a waveform-audio device. An application should use the acmMetrics function with the ACM_METRIC_HARDWARE_WAVE_INPUT and ACM_METRIC_HARDWARE_WAVE_OUTPUT metric indexes to get the waveform-audio device identifiers associated with the supporting ACM driver.

ACMDRIVERDETAILS_SUPPORTF_LOCAL

The driver has been installed locally with respect to the current task.

cFormatTags

Number of unique format tags supported by this driver.

cFilterTags

Number of unique filter tags supported by this driver.

hicon

Handle of a custom icon for this driver. An application can use this icon for referencing the driver visually. This member can be NULL.

szShortName

Null-terminated string that describes the name of the driver. This string is intended to be displayed in small spaces.

szLongName

Null-terminated string that describes the full name of the driver. This string is intended to be displayed in large (descriptive) spaces.

szCopyright

Null-terminated string that provides copyright information for the driver.

szLicensing

Null-terminated string that provides special licensing information for the driver.

szFeatures

Null-terminated string that provides special feature information for the driver.


ACMFILTERCHOOSE

typedef struct {

    DWORD                   cbStruct;

    DWORD                   fdwStyle;

    HWND                    hwndOwner;

    LPWAVEFILTER            pwfltr;

    DWORD                   cbwfltr;

    LPCSTR                  pszTitle;

    char szFilterTag[ACMFILTERTAGDETAILS_FILTERTAG_CHARS];

    char szFilter[ACMFILTERDETAILS_FILTER_CHARS];

    LPSTR                   pszName;

    DWORD                   cchName;

    DWORD                   fdwEnum;

    LPWAVEFILTER            pwfltrEnum;

    HINSTANCE               hInstance;

    LPCSTR                  pszTemplateName;

    LPARAM                  lCustData;

    ACMFILTERCHOOSEHOOKPROC pfnHook;

} ACMFILTERCHOOSE;

Contains information the ACM uses to initialize the system-defined waveform-audio filter selection dialog box. After the user closes the dialog box, the system returns information about the user's selection in this structure.

cbStruct

Size, in bytes, of the ACMFILTERCHOOSE structure. This member must be initialized before an application calls the acmFilterChoose function. The size specified in this member must be large enough to contain the base ACMFILTERCHOOSE structure.

fdwStyle

Optional style flags for the acmFilterChoose function. This member must be initialized to a valid combination of the following flags before an application calls the acmFilterChoose function. The following values are defined:

ACMFILTERCHOOSE_STYLEF_CONTEXTHELP

Context-sensitive help will be available in the dialog box. To use this feature, an application must register the ACMHELPMSGCONTEXTMENU and ACMHELPMSGCONTEXTHELP constants, using the RegisterWindowMessage function. When the user invokes help, the registered message will be posted to the owning window. The message will contain the wParam and lParam parameters from the original WM_CONTEXTMENU or WM_CONTEXTHELP message.

ACMFILTERCHOOSE_STYLEF_ENABLEHOOK

Enables the hook function specified in the pfnHook member. An application can use hook functions for a variety of customizations, including answering the MM_ACM_FILTERCHOOSE message.

ACMFILTERCHOOSE_STYLEF_ENABLETEMPLATE

Causes the ACM to create the dialog box template identified by the hInstance and pszTemplateName members.

ACMFILTERCHOOSE_STYLEF_ENABLETEMPLATEHANDLE

The hInstance member identifies a data block that contains a preloaded dialog box template. If this flag is specified, the ACM ignores the pszTemplateName member.

ACMFILTERCHOOSE_STYLEF_INITTOFILTERSTRUCT

The buffer pointed to by pwfltr contains a valid WAVEFILTER structure that the dialog box will use as the initial selection.

ACMFILTERCHOOSE_STYLEF_SHOWHELP

A help button will appear in the dialog box. To use a custom Help file, an application must register the ACMHELPMSGSTRING value with the RegisterWindowMessage function. When the user presses the help button, the registered message is posted to the owner.

hwndOwner

Handle of the window that owns the dialog box. This member can be any valid window handle or NULL if the dialog box has no owner. This member must be initialized before calling the acmFilterChoose function.

pwfltr

Address of a WAVEFILTER structure. If the ACMFILTERCHOOSE_STYLEF_INITTOFILTERSTRUCT flag is specified in the fdwStyle member, this structure must be initialized to a valid filter. When the acmFilterChoose function returns, this buffer contains the selected filter. If the user cancels the dialog box, no changes will be made to this buffer.

cbwfltr

Size, in bytes, of the buffer pointed to by the pwfltr member. The acmFilterChoose function returns ACMERR_NOTPOSSIBLE if the buffer is too small to contain the filter information; the ACM also copies the required size into this member. An application can use the acmMetrics and acmFilterTagDetails functions to determine the largest size required for this buffer.

pszTitle

Address of a string to be placed in the title bar of the dialog box. If this member is NULL, the ACM uses the default title (that is, "Filter Selection").

szFilterTag

Buffer containing a null-terminated string describing the filter tag of the filter selection when the acmFilterChoose function returns. This string is equivalent to the szFilterTag member of the ACMFILTERTAGDETAILS structure returned by acmFilterTagDetails. If the user cancels the dialog box, this member will contain a null-terminated string.

szFilter

Buffer containing a null-terminated string describing the filter attributes of the filter selection when the acmFilterChoose function returns. This string is equivalent to the szFilter member of the ACMFILTERDETAILS structure returned by acmFilterDetails. If the user cancels the dialog box, this member will contain a null-terminated string.

pszName

Address of a string for a user-defined filter name. If this is a non-null-terminated string, the ACM attempts to match the name with a previously saved user-defined filter name. If a match is found, the dialog box is initialized to that filter. If a match is not found or this member is a null-terminated string, this member is ignored for input. When the acmFilterChoose function returns, this buffer contains a null-terminated string describing the user-defined filter. If the filter name is untitled (that is, the user has not given a name for the filter), this member will be a null-terminated string on return. If the user cancels the dialog box, no changes will be made to this buffer.

If the ACMFILTERCHOOSE_STYLEF_INITTOFILTERSTRUCT flag is specified by the fdwStyle member, the pszName member is ignored as an input member.

cchName

Size, in characters, of the buffer identified by the pszName member. This buffer should be at least 128 characters long. If pszName is NULL, this member is ignored.

fdwEnum

Optional flags for restricting the type of filters listed in the dialog box. These flags are identical to the fdwEnum flags for the acmFilterEnum function. If pwfltrEnum is NULL, this member should be zero.

ACM_FILTERENUMF_DWFILTERTAG

The dwFilterTag member of the WAVEFILTER structure pointed to by the pwfltrEnum member is valid. The enumerator will only enumerate a filter that conforms to this attribute.

pwfltrEnum

Address of a WAVEFILTER structure that will be used to restrict the filters listed in the dialog box. The fdwEnum member defines which members of this structure should be used for the enumeration restrictions. The cbStruct member of this WAVEFILTER structure must be initialized to the size of the WAVEFILTER structure. If no special restrictions are desired, this member can be NULL.

hInstance

Handle of a data block that contains a dialog box template specified by the pszTemplateName member. This member is used only if the fdwStyle member specifies the ACMFILTERCHOOSE_STYLEF_ENABLETEMPLATE or ACMFILTERCHOOSE_STYLEF_ENABLETEMPLATEHANDLE flag; otherwise, this member should be NULL on input.

pszTemplateName

Address of a null-terminated string that specifies the name of the resource file for the dialog box template that is to be substituted for the dialog box template in the ACM. An application can use the MAKEINTRESOURCE macro for numbered dialog box resources. This member is used only if the fdwStyle member specifies the ACMFILTERCHOOSE_STYLEF_ENABLETEMPLATE flag; otherwise, this member should be NULL on input.

lCustData

Application-defined data that the ACM passes to the hook function identified by the pfnHook member. The system passes the data in the lParam parameter of the WM_INITDIALOG message.

pfnHook

Address of a hook function that processes messages intended for the dialog box. An application must specify the ACMFILTERCHOOSE_STYLEF_ENABLEHOOK flag in the fdwStyle member to enable the hook; otherwise, this member should be NULL. The hook function should return FALSE to pass a message to the standard dialog box procedure or TRUE to discard the message.


ACMFILTERDETAILS

typedef struct {

    DWORD        cbStruct;

    DWORD        dwFilterIndex;

    DWORD        dwFilterTag;

    DWORD        fdwSupport;

    LPWAVEFILTER pwfltr;

    DWORD        cbwfltr;

    char        szFilter[ACMFILTERDETAILS_FILTER_CHARS];

} ACMFILTERDETAILS;

Details a waveform-audio filter for a specific filter tag for an ACM driver.

cbStruct

Size, in bytes, of the ACMFILTERDETAILS structure. This member must be initialized before calling the acmFilterDetails or acmFilterEnum functions. The size specified in this member must be large enough to contain the base ACMFILTERDETAILS structure. When the acmFilterDetails function returns, this member contains the actual size of the information returned. The returned information will never exceed the requested size.

dwFilterIndex

Index of the filter about which details will be retrieved. The index ranges from zero to one less than the number of standard filters supported by an ACM driver for a filter tag. The number of standard filters supported by a driver for a filter tag is contained in the cStandardFilters member of the ACMFILTERTAGDETAILS structure. The dwFilterIndex member is used only when querying standard filter details about a driver by index; otherwise, this member should be zero. Also, this member will be set to zero by the ACM when an application queries for details on a filter; in other words, this member is used only for input and is never returned by the ACM or an ACM driver.

dwFilterTag

Waveform-audio filter tag that the ACMFILTERDETAILS structure describes. This member is used as an input for the ACM_FILTERDETAILSF_INDEX query flag. For the ACM_FILTERDETAILSF_FORMAT query flag, this member must be initialized to the same filter tag as the pwfltr member specifies. If the acmFilterDetails function is successful, this member is always returned. This member should be set to WAVE_FILTER_UNKNOWN for all other query flags.

fdwSupport

Driver-support flags specific to the specified filter. These flags are identical to the fdwSupport flags of the ACMDRIVERDETAILS structure, but they are specific to the filter that is being queried. This member can be a combination of the following values and identifies which operations the driver supports for the filter tag:

ACMDRIVERDETAILS_SUPPORTF_ASYNC

Driver supports asynchronous conversions.

ACMDRIVERDETAILS_SUPPORTF_CODEC

Driver supports conversion between two different format tags while using the specified filter. For example, if a driver supports compression from WAVE_FORMAT_PCM to WAVE_FORMAT_ADPCM with the specified filter, this flag is set.

ACMDRIVERDETAILS_SUPPORTF_CONVERTER

Driver supports conversion between two different formats of the same format tag while using the specified filter. For example, if a driver supports resampling of WAVE_FORMAT_PCM with the specified filter, this flag is set.

ACMDRIVERDETAILS_SUPPORTF_FILTER

Driver supports a filter (modification of the data without changing any of the format attributes). For example, if a driver supports volume or echo operations on WAVE_FORMAT_PCM, this flag is set.

ACMDRIVERDETAILS_SUPPORTF_HARDWARE

Driver supports hardware input, output, or both with the specified filter through a waveform-audio device. An application should use the acmMetrics function with the ACM_METRIC_HARDWARE_WAVE_INPUT and ACM_METRIC_HARDWARE_WAVE_OUTPUT metric indexes to retrieve the waveform-audio device identifiers associated with the supporting ACM driver.

pwfltr

Address of a WAVEFILTER structure that will receive the filter details. This structure requires no initialization by the application unless the ACM_FILTERDETAILSF_FILTER flag is specified with the acmFilterDetails function. In this case, the dwFilterTag member of the WAVEFILTER structure must be equal to the dwFilterTag member of the ACMFILTERDETAILS structure.

cbwfltr

Size, in bytes, available for pwfltr to receive the filter details. The acmMetrics and acmFilterTagDetails functions can be used to determine the maximum size required for any filter available for the specified driver (or for all installed ACM drivers).

szFilter

String that describes the filter for the dwFilterTag type. If the acmFilterDetails function is successful, this string is always returned.


ACMFILTERTAGDETAILS

typedef struct {

    DWORD cbStruct;

    DWORD dwFilterTagIndex;

    DWORD dwFilterTag;

    DWORD cbFilterSize;

    DWORD fdwSupport;

    DWORD cStandardFilters;

    char szFilterTag[ACMFILTERTAGDETAILS_FILTERTAG_CHARS];

} ACMFILTERTAGDETAILS;

Details a waveform-audio filter tag for an ACM filter driver.

cbStruct

Size, in bytes, of the ACMFILTERTAGDETAILS structure. This member must be initialized before an application calls the acmFilterTagDetails or acmFilterTagEnum function. The size specified in this member must be large enough to contain the base ACMFILTERTAGDETAILS structure. When the acmFilterTagDetails function returns, this member contains the actual size of the information returned. The returned information will never exceed the requested size.

dwFilterTagIndex

Index of the filter tag to retrieve details for. The index ranges from zero to one less than the number of filter tags supported by an ACM driver. The number of filter tags supported by a driver is contained in the cFilterTags member of the ACMDRIVERDETAILS structure. The dwFilterTagIndex member is used only when querying filter tag details about a driver by index; otherwise, this member should be zero.

dwFilterTag

Waveform-audio filter tag that the ACMFILTERTAGDETAILS structure describes. This member is used as an input for the ACM_FILTERTAGDETAILSF_FILTERTAG and ACM_FILTERTAGDETAILSF_LARGESTSIZE query flags. This member is always returned if the acmFilterTagDetails function is successful. This member should be set to WAVE_FILTER_UNKNOWN for all other query flags.

cbFilterSize

Largest total size, in bytes, of a waveform-audio filter of the dwFilterTag type. For example, this member will be 40 for WAVE_FILTER_ECHO and 36 for WAVE_FILTER_VOLUME.

fdwSupport

Driver-support flags specific to the filter tag. These flags are identical to the fdwSupport flags of the ACMDRIVERDETAILS structure. This member can be a combination of the following values and identifies which operations the driver supports with the filter tag:

ACMDRIVERDETAILS_SUPPORTF_ASYNC

Driver supports asynchronous conversions.

ACMDRIVERDETAILS_SUPPORTF_CODEC

Driver supports conversion between two different format tags while using the specified filter tag. For example, if a driver supports compression from WAVE_FORMAT_PCM to WAVE_FORMAT_ADPCM with the specified filter tag, this flag is set.

ACMDRIVERDETAILS_SUPPORTF_CONVERTER

Driver supports conversion between two different formats of the same format tag while using the specified filter tag. For example, if a driver supports resampling of WAVE_FORMAT_PCM with the specified filter tag, this flag is set.

ACMDRIVERDETAILS_SUPPORTF_FILTER

Driver supports a filter (modification of the data without changing any of the format attributes). For example, if a driver supports volume or echo operations on WAVE_FORMAT_PCM, this flag is set.

ACMDRIVERDETAILS_SUPPORTF_HARDWARE

Driver supports hardware input, output, or both with the specified filter tag through a waveform-audio device. An application should use the acmMetrics function with the ACM_METRIC_HARDWARE_WAVE_INPUT and ACM_METRIC_HARDWARE_WAVE_OUTPUT metric indexes to get the waveform-audio device identifiers associated with the supporting ACM driver.

cStandardFilters

Number of standard filters of the dwFilterTag type (that is, the combination of all filter characteristics). This value cannot specify all filters supported by the driver.

szFilterTag

String that describes the dwFilterTag type. This string is always returned if the acmFilterTagDetails function is successful.


ACMFORMATCHOOSE

typedef struct {

    DWORD                   cbStruct;

    DWORD                   fdwStyle;

    HWND                    hwndOwner;

    LPWAVEFORMATEX          pwfx;

    DWORD                   cbwfx;

    LPCSTR                  pszTitle;

    char szFormatTag[ACMFORMATTAGDETAILS_FORMATTAG_CHARS];

    char szFormat[ACMFORMATDETAILS_FORMAT_CHARS];

    LPSTR                   pszName;

    DWORD                   cchName;

    DWORD                   fdwEnum;

    LPWAVEFORMATEX          pwfxEnum;

    HINSTANCE               hInstance;

    LPCSTR                  pszTemplateName;

    LPARAM                  lCustData;

    ACMFORMATCHOOSEHOOKPROC pfnHook;

} ACMFORMATCHOOSE;

Contains information the ACM uses to initialize the system-defined waveform-audio format selection dialog box. After the user closes the dialog box, the system returns information about the user's selection in this structure.

cbStruct

Size, in bytes, of the ACMFORMATCHOOSE structure. This member must be initialized before an application calls the acmFormatChoose function. The size specified in this member must be large enough to contain the base ACMFORMATCHOOSE structure.

fdwStyle

Optional style flags for the acmFormatChoose function. This member must be initialized to a valid combination of the following flags before an application calls the acmFormatChoose function:

ACMFORMATCHOOSE_STYLEF_CONTEXTHELP

Context-sensitive help will be available in the dialog box. To use this feature, an application must register the ACMHELPMSGCONTEXTMENU and ACMHELPMSGCONTEXTHELP constants, using the RegisterWindowMessage function. When the user invokes help, the registered message will be posted to the owning window. The message will contain the wParam and lParam parameters from the original WM_CONTEXTMENU or WM_CONTEXTHELP message.

ACMFORMATCHOOSE_STYLEF_ENABLEHOOK

Enables the hook function pointed to by the pfnHook member. An application can use hook functions for a variety of customizations, including answering the MM_ACM_FORMATCHOOSE message.

ACMFORMATCHOOSE_STYLEF_ENABLETEMPLATE

Causes the ACM to create the dialog box template identified by hInstance and pszTemplateName.

ACMFORMATCHOOSE_STYLEF_ENABLETEMPLATEHANDLE

The hInstance member identifies a data block that contains a preloaded dialog box template. If this flag is specified, the ACM ignores the pszTemplateName member.

ACMFORMATCHOOSE_STYLEF_INITTOWFXSTRUCT

The buffer pointed to by pwfx contains a valid WAVEFORMATEX structure that the dialog box will use as the initial selection.

ACMFORMATCHOOSE_STYLEF_SHOWHELP

A help button will appear in the dialog box. To use a custom Help file, an application must register the ACMHELPMSGSTRING constant with the RegisterWindowMessage function. When the user presses the help button, the registered message will be posted to the owner.

hwndOwner

Handle of the window that owns the dialog box. This member can be any valid window handle, or NULL if the dialog box has no owner. This member must be initialized before calling the acmFormatChoose function.

pwfx

Address of a WAVEFORMATEX structure. If the ACMFORMATCHOOSE_STYLEF_INITTOWFXSTRUCT flag is specified in the fdwStyle member, this structure must be initialized to a valid format. When the acmFormatChoose function returns, this buffer contains the selected format. If the user cancels the dialog box, no changes will be made to this buffer.

cbwfx

Size, in bytes, of the buffer pointed to by pwfx. If the buffer is too small to contain the format information, the acmFormatChoose function returns ACMERR_NOTPOSSIBLE. Also, the ACM copies the required size into this member. An application can use the acmMetrics and acmFormatTagDetails functions to determine the largest size required for this buffer.

pszTitle

Address of a string to be placed in the title bar of the dialog box. If this member is NULL, the ACM uses the default title (that is, "Sound Selection").

szFormatTag

Buffer containing a null-terminated string describing the format tag of the format selection when the acmFormatChoose function returns. This string is equivalent to the szFormatTag member of the ACMFORMATTAGDETAILS structure returned by the acmFormatTagDetails function. If the user cancels the dialog box, this member will contain a null-terminated string.

szFormat

Buffer containing a null-terminated string describing the format attributes of the format selection when the acmFormatChoose function returns. This string is equivalent to the szFormat member of the ACMFORMATDETAILS structure returned by the acmFormatDetails function. If the user cancels the dialog box, this member will contain a null-terminated string.

pszName

Address of a string for a user-defined format name. If this is a non-null-terminated string, the ACM will attempt to match the name with a previously saved user-defined format name. If a match is found, the dialog box is initialized to that format. If a match is not found or this member is a null-terminated string, this member is ignored on input. When the acmFormatChoose function returns, this buffer contains a null-terminated string describing the user-defined format. If the format name is untitled (that is, the user has not given a name for the format), this member will be a null-terminated string on return. If the user cancels the dialog box, no changes will be made to this buffer.

If the ACMFORMATCHOOSE_STYLEF_INITTOWFXSTRUCT flag is specified in the fdwStyle member, the pszName member is ignored for input.

cchName

Size, in characters, of the buffer identified by the pszName member. This buffer should be at least 128 characters long. If the pszName member is NULL, this member is ignored.

fdwEnum

Optional flags for restricting the type of formats listed in the dialog box. These flags are identical to the fdwEnum flags for the acmFormatEnum function. If pwfxEnum is NULL, this member should be zero. The following values are defined:

ACM_FORMATENUMF_CONVERT

The WAVEFORMATEX structure pointed to by the pwfxEnum member is valid. The enumerator will enumerate only destination formats that can be converted from the given pwfxEnum format.

ACM_FORMATENUMF_HARDWARE

The enumerator should enumerate only formats that are supported in hardware by one or more of the installed waveform-audio devices. This flag provides a way for an application to choose only formats native to an installed waveform-audio device.

ACM_FORMATENUMF_INPUT

The enumerator should enumerate only formats that are supported for input (recording).

ACM_FORMATENUMF_NCHANNELS

The nChannels member of the WAVEFORMATEX structure pointed to by the pwfxEnum member is valid. The enumerator will enumerate only a format that conforms to this attribute.

ACM_FORMATENUMF_NSAMPLESPERSEC

The nSamplesPerSec member of the WAVEFORMATEX structure pointed to by the pwfxEnum member is valid. The enumerator will enumerate only a format that conforms to this attribute.

ACM_FORMATENUMF_OUTPUT

The enumerator should enumerate only formats that are supported for output (playback).

ACM_FORMATENUMF_SUGGEST

The WAVEFORMATEX structure pointed to by the pwfxEnum member is valid. The enumerator will enumerate all suggested destination formats for the given pwfxEnum format.

ACM_FORMATENUMF_WBITSPERSAMPLE

The wBitsPerSample member of the WAVEFORMATEX structure pointed to by the pwfxEnum member is valid. The enumerator will enumerate only a format that conforms to this attribute.

ACM_FORMATENUMF_WFORMATTAG

The wFormatTag member of the WAVEFORMATEX structure pointed to by the pwfxEnum member is valid. The enumerator will enumerate only a format that conforms to this attribute.

pwfxEnum

Address of a WAVEFORMATEX structure that will be used to restrict the formats listed in the dialog box. The fdwEnum member defines the members of the structure pointed to by pwfxEnum that should be used for the enumeration restrictions. If no special restrictions are desired, this member can be NULL. For other requirements associated with the pwfxEnum member, see the description for the acmFormatEnum function.

hInstance

Handle of a data block that contains a dialog box template specified by the pszTemplateName member. This member is used only if the fdwStyle member specifies the ACMFORMATCHOOSE_STYLEF_ENABLETEMPLATE or ACMFORMATCHOOSE_STYLEF_ENABLETEMPLATEHANDLE flag; otherwise, this member should be NULL on input.

pszTemplateName

Address of a null-terminated string that specifies the name of the resource file for the dialog box template that is to be substituted for the dialog box template in the ACM. An application can use the MAKEINTRESOURCE macro for numbered dialog box resources. This member is used only if the fdwStyle member specifies the ACMFORMATCHOOSE_STYLEF_ENABLETEMPLATE flag; otherwise, this member should be NULL on input.

lCustData

Application-defined data that the ACM passes to the hook function identified by the pfnHook member. The system passes the data in the lParam parameter of the WM_INITDIALOG message.

pfnHook

Address of a hook function that processes messages intended for the dialog box. An application must specify the ACMFORMATCHOOSE_STYLEF_ENABLEHOOK flag in the fdwStyle member to enable the hook; otherwise, this member should be NULL. The hook function should return FALSE to pass a message to the standard dialog box procedure or TRUE to discard the message.


ACMFORMATDETAILS

typedef struct {

    DWORD          cbStruct;

    DWORD          dwFormatIndex;

    DWORD          dwFormatTag;

    DWORD          fdwSupport;

    LPWAVEFORMATEX pwfx;

    DWORD          cbwfx;

    char szFormat[ACMFORMATDETAILS_FORMAT_CHARS];

} ACMFORMATDETAILS;

Details a waveform-audio format for a specific format tag for an ACM driver.

cbStruct

Size, in bytes, of the ACMFORMATDETAILS structure. This member must be initialized before an application calls the acmFormatDetails or acmFormatEnum function. The size specified by this member must be large enough to contain the base ACMFORMATDETAILS structure. When the acmFormatDetails function returns, this member contains the actual size of the information returned. The returned information will never exceed the requested size.

dwFormatIndex

Index of the format to retrieve details for. The index ranges from zero to one less than the number of standard formats supported by an ACM driver for a format tag. The number of standard formats supported by a driver for a format tag is contained in the cStandardFormats member of the ACMFORMATTAGDETAILS structure. The dwFormatIndex member is used only when an application queries standard format details about a driver by index; otherwise, this member should be zero. Also, this member will be set to zero by the ACM when an application queries for details on a format; in other words, this member is used only for input and is never returned by the ACM or an ACM driver.

dwFormatTag

Waveform-audio format tag that the ACMFORMATDETAILS structure describes. This member is used for input for the ACM_FORMATDETAILSF_INDEX query flag. For the ACM_FORMATDETAILSF_FORMAT query flag, this member must be initialized to the same format tag as the pwfx member specifies. If a call to the acmFormatDetails function is successful, this member is always returned. This member should be set to WAVE_FORMAT_UNKNOWN for all other query flags.

fdwSupport

Driver-support flags specific to the specified format. These flags are identical to the fdwSupport flags of the ACMDRIVERDETAILS structure. This member can be a combination of the following values and indicates which operations the driver supports for the format tag:

ACMDRIVERDETAILS_SUPPORTF_ASYNC

Driver supports asynchronous conversions with the specified format tag.

ACMDRIVERDETAILS_SUPPORTF_CODEC

Driver supports conversion between two different format tags for the specified format. For example, if a driver supports compression from WAVE_FORMAT_PCM to WAVE_FORMAT_ADPCM with the specified format, this flag is set.

ACMDRIVERDETAILS_SUPPORTF_CONVERTER

Driver supports conversion between two different formats of the same format tag while using the specified format. For example, if a driver supports resampling of WAVE_FORMAT_PCM to the specified format, this flag is set.

ACMDRIVERDETAILS_SUPPORTF_FILTER

Driver supports a filter (which modifies data without changing any format attributes) with the specified format. For example, if a driver supports volume or echo operations on WAVE_FORMAT_PCM, this flag is set.

ACMDRIVERDETAILS_SUPPORTF_HARDWARE

Driver supports hardware input and/or output of the specified format through a waveform-audio device. An application should use acmMetrics with the ACM_METRIC_HARDWARE_WAVE_INPUT and ACM_METRIC_HARDWARE_WAVE_OUTPUT metric indexes to get the waveform-audio device identifiers associated with the supporting ACM driver.

pwfx

Address of a WAVEFORMATEX structure that will receive the format details. This structure requires no initialization by the application unless the ACM_FORMATDETAILSF_FORMAT flag is specified in the acmFormatDetails function. In this case, the wFormatTag member of the WAVEFORMATEX structure must be equal to the dwFormatTag of the ACMFORMATDETAILS structure.

cbwfx

Size, in bytes, available for pwfx to receive the format details. The acmMetrics and acmFormatTagDetails functions can be used to determine the maximum size required for any format available for the specified driver (or for all installed ACM drivers).

szFormat

String that describes the format for the dwFormatTag type. If the acmFormatDetails function is successful, this string is always returned.


ACMFORMATTAGDETAILS

typedef struct {

    DWORD cbStruct;

    DWORD dwFormatTagIndex;

    DWORD dwFormatTag;

    DWORD cbFormatSize;

    DWORD fdwSupport;

    DWORD cStandardFormats;

    char szFormatTag[ACMFORMATTAGDETAILS_FORMATTAG_CHARS];

} ACMFORMATTAGDETAILS;

Details a waveform-audio format tag for an ACM driver.

cbStruct

Size, in bytes, of the ACMFORMATTAGDETAILS structure. This member must be initialized before an application calls the acmFormatTagDetails or acmFormatTagEnum function. The size specified by this member must be large enough to contain the base ACMFORMATTAGDETAILS structure. When the acmFormatTagDetails function returns, this member contains the actual size of the information returned. The returned information will never exceed the requested size.

dwFormatTagIndex

Index of the format tag for which details will be retrieved. The index ranges from zero to one less than the number of format tags supported by an ACM driver. The number of format tags supported by a driver is contained in the cFormatTags member of the ACMDRIVERDETAILS structure. The dwFormatTagIndex member is used only when querying format tag details on a driver by index; otherwise, this member should be zero.

dwFormatTag

Waveform-audio format tag that the ACMFORMATTAGDETAILS structure describes. This member is used for input for the ACM_FORMATTAGDETAILSF_FORMATTAG and ACM_FORMATTAGDETAILSF_LARGESTSIZE query flags. If the acmFormatTagDetails function is successful, this member is always returned. This member should be set to WAVE_FORMAT_UNKNOWN for all other query flags.

cbFormatSize

Largest total size, in bytes, of a waveform-audio format of the dwFormatTag type. For example, this member will be 16 for WAVE_FORMAT_PCM and 50 for WAVE_FORMAT_ADPCM.

fdwSupport

Driver-support flags specific to the format tag. These flags are identical to the fdwSupport flags of the ACMDRIVERDETAILS structure. This member may be some combination of the following values and refer to what operations the driver supports with the format tag:

ACMDRIVERDETAILS_SUPPORTF_ASYNC

Driver supports asynchronous conversions with the specified format tag.

ACMDRIVERDETAILS_SUPPORTF_CODEC

Driver supports conversion between two different format tags where one of the tags is the specified format tag. For example, if a driver supports compression from WAVE_FORMAT_PCM to WAVE_FORMAT_ADPCM, this flag is set.

ACMDRIVERDETAILS_SUPPORTF_CONVERTER

Driver supports conversion between two different formats of the specified format tag. For example, if a driver supports resampling of WAVE_FORMAT_PCM, this flag is set.

ACMDRIVERDETAILS_SUPPORTF_FILTER

Driver supports a filter (modification of the data without changing any of the format attributes). For example, if a driver supports volume or echo operations on the specified format tag, this flag is set.

ACMDRIVERDETAILS_SUPPORTF_HARDWARE

Driver supports hardware input, output, or both of the specified format tag through a waveform-audio device. An application should use the acmMetrics function with the ACM_METRIC_HARDWARE_WAVE_INPUT and ACM_METRIC_HARDWARE_WAVE_OUTPUT metric indexes to get the waveform-audio device identifiers associated with the supporting ACM driver.

cStandardFormats

Number of standard formats of the dwFormatTag type; that is, the combination of all sample rates, bits per sample, channels, and so on. This value can specify all formats supported by the driver, but not necessarily.

szFormatTag

String that describes the dwFormatTag type. If the acmFormatTagDetails function is successful, this string is always returned.


ACMSTREAMHEADER

typedef struct {

    DWORD  cbStruct;

    DWORD  fdwStatus;

    DWORD  dwUser;

    LPBYTE pbSrc;

    DWORD  cbSrcLength;

    DWORD  cbSrcLengthUsed;

    DWORD  dwSrcUser;

    LPBYTE pbDst;

    DWORD  cbDstLength;

    DWORD  cbDstLengthUsed;

    DWORD  dwDstUser;

    DWORD  dwReservedDriver[10];

} ACMSTREAMHEADER;

Defines the header used to identify an ACM conversion source and destination buffer pair for a conversion stream.

cbStruct

Size, in bytes, of the ACMSTREAMHEADER structure. This member must be initialized before the application calls any ACM stream functions using this structure. The size specified in this member must be large enough to contain the base ACMSTREAMHEADER structure.

fdwStatus

Flags giving information about the conversion buffers. This member must be initialized to zero before the application calls the acmStreamPrepareHeader function and should not be modified by the application while the stream header remains prepared.

ACMSTREAMHEADER_STATUSF_DONE

Set by the ACM or driver to indicate that it is finished with the conversion and is returning the buffers to the application.

ACMSTREAMHEADER_STATUSF_INQUEUE

Set by the ACM or driver to indicate that the buffers are queued for conversion.

ACMSTREAMHEADER_STATUSF_PREPARED

Set by the ACM to indicate that the buffers have been prepared by using the acmStreamPrepareHeader function.

dwUser

User data. This can be any instance data specified by the application.

pbSrc

Address of the source buffer. This pointer must always refer to the same location while the stream header remains prepared. If an application needs to change the source location, it must unprepare the header and reprepare it with the alternate location.

cbSrcLength

Length, in bytes, of the source buffer pointed to by pbSrc. When the header is prepared, this member must specify the maximum size that will be used in the source buffer. Conversions can be performed on source lengths less than or equal to the original prepared size. However, this member must be reset to the original size when an application unprepares the header.

cbSrcLengthUsed

Amount of data, in bytes, used for the conversion. This member is not valid until the conversion is complete. This value can be less than or equal to cbSrcLength. An application must use the cbSrcLengthUsed member when advancing to the next piece of source data for the conversion stream.

dwSrcUser

User data. This can be any instance data specified by the application.

pbDst

Address of the destination buffer. This pointer must always refer to the same location while the stream header remains prepared. If an application needs to change the destination location, it must unprepare the header and reprepare it with the alternate location.

cbDstLength

Length, in bytes, of the destination buffer pointed to by pbDst. When the header is prepared, this member must specify the maximum size that will be used in the destination buffer.

cbDstLengthUsed

Amount of data, in bytes, returned by a conversion. This member is not valid until the conversion is complete. This value can be less than or equal to cbDstLength. An application must use the cbDstLengthUsed member when advancing to the next destination location for the conversion stream.

dwDstUser

User data. This can be any instance data specified by the application.

dwReservedDriver

Reserved; do not use. This member requires no initialization by the application and should never be modified while the header remains prepared.

Before an ACMSTREAMHEADER structure can be used for a conversion, it must be prepared by using the acmStreamPrepareHeader function. When an application is finished with an ACMSTREAMHEADER structure, it must call the acmStreamUnprepareHeader function before freeing the source and destination buffers.


WAVEFILTER

typedef struct {

    DWORD cbStruct;

    DWORD dwFilterTag;

    DWORD fdwFilter;

    DWORD dwReserved[5];

} WAVEFILTER;

Defines a filter for waveform-audio data. Only filter information common to all waveform-audio data filters is included in this structure. For filters that require additional information, this structure is included as the first member in another structure along with the additional information.

cbStruct

Size, in bytes, of the WAVEFILTER structure. The size specified in this member must be large enough to contain the base WAVEFILTER structure.

dwFilterTag

Waveform-audio filter type. Filter tags are registered with Microsoft Corporation for various filter algorithms.

fdwFilter

Flags for the dwFilterTag member. The flags defined for this member are universal to all filters. Currently, no flags are defined.

dwReserved

Reserved for system use; should not be examined or modified by an application.


Musical Instrument Digital Interface (MIDI)

The Musical Instrument Digital Interface (MIDI) is a protocol and set of commands for storing and transmitting information about music. MIDI output devices interpret this information and use it to synthesize music.

The Microsoft Win32 application programming interface (API) provides the following methods for applications to work with MIDI data:

•	The Media Control Interface (MCI). Although the simplest way to play a MIDI file is to use the MCIWnd window class, you can also use MCI commands to create a customized interface to a MIDI device. For more information about the MCIWnd window class, see Chapter 2, "Getting Started Using MCIWnd." For more information about MCI, see Chapter 3, "MCI Overview," or the next section, "Media Control Interface (MCI)".

•	Stream buffers. This format allows an application to manipulate buffers of time-stamped MIDI data for playback. Stream buffers are useful to applications that require more precise control over output than MCI offers.

•	Low-level MIDI services. Applications that need the most precise control of MIDI data typically use these low-level services.

This chapter discusses each of these methods, provides an overview of the MIDI services of the Microsoft Windows operating system, and contains a detailed reference to the MIDI-related functions, structures, and messages.


Media Control Interface (MCI)

The MCI system component that plays MIDI files is the MCI MIDI sequencer. Applications can play MIDI files easily using MCI, but MCI imposes the following restrictions on MIDI capabilities:

•	MCI supports MIDI output only.

•	MCI does not allow close synchronization between MIDI events and other real-time events (such as video).

If you need accurate MIDI synchronization, you must use the stream buffers or the low-level MIDI services. If you need MIDI input capabilities, you must use the low-level MIDI services.

The MCI MIDI sequencer plays standard MIDI files and resource interchange file format (RIFF) MIDI files, known as RMID files. Standard MIDI files conform to the Standard MIDI Files 1.0 specification. Because RMID files are standard MIDI files with a RIFF header, information about standard MIDI files also applies to RMID files. For more information about RIFF files, see Chapter 15, "File Input and Output."

Although there are currently three kinds of standard MIDI files, the MCI sequencer plays only two of them: Format 0 and Format 1 MIDI files.

For more information about controlling multimedia devices (including sequencers) using MCI commands, see Chapter 3, "MCI Overview."


Stream Buffers

Applications can use stream buffers to send streams of MIDI events to a device. Each stream buffer is a block of memory pointed to by a MIDIHDR structure. This block of memory contains data for one or more MIDI events, each of which is defined by a MIDIEVENT structure. An application controls the buffer by calling the stream-manipulation functions, such as midiStreamOpen, midiStreamOut, and midiStreamClose.


Stream Buffer Format

The lpData member of the MIDIHDR structure points to a stream buffer, and the dwBufferLength member specifies the actual size of this buffer. The dwBytesRecorded member of MIDIHDR specifies the number of bytes in the buffer that are actually used by the MIDI events; this value must be less than or equal to the value specified by dwBufferLength.

Each of the MIDI events in the stream buffer is specified by a MIDIEVENT structure, which contains the time for the event, a stream identifier, an event code, and, when appropriate, parameters for the event. Each of these MIDIEVENT structures must begin on a doubleword boundary. If necessary, pad bytes must be added to the end of the structure to ensure that the next one starts on a doubleword boundary.


Timing Information

Timing information for a MIDI event is stored in the dwDeltaTime member of the MIDIEVENT structure. Time is given in ticks, as defined in the Standard MIDI Files 1.0 specification. The length of a tick is defined by the time format and possibly the tempo associated with the stream. For more information about streams, see MIDI Streams.

A tick is expressed either as microseconds per quarter note or as ticks of SMPTE (Society of Motion Picture and Television Engineers) time. Applications that send MIDI messages individually or use unprocessed MIDI messages use quarter note time and tempo information to determine the duration of a tick. Applications that preprocess MIDI messages can store the elapsed time as a count of the SMPTE units being used.

Quarter note time is indicated with a 0 in the high-word bit (bit 15) of the time-division word. The remainder of the word contains the ticks per quarter note. A tempo associated with a stream of MIDI data is kept in units (microseconds per quarter note) consistent with the Standard MIDI Files 1.0 specification. For example, a quarter note in 4/4 time that uses a tempo of 500,000 microseconds per quarter note plays at the rate of 120 beats per minute.

SMPTE time division formats completely specify the length of a tick without the need for tempo information. Using SMPTE time formats, MIDI sequences can be synchronized exactly with other SMPTE events, such as video or striped audio. SMPTE time is indicated with a 1 in the high-order bit (bit 15) of the time-division word. The rest of the most-significant byte specifies the SMPTE format in use as negative values. The supported SMPTE formats and their corresponding values (in parentheses) are 24 (-24), 25 (-25), 30 (-30), and 30 drop (-29). The low byte of the time-division word specifies the number of ticks per SMPTE frame.


Event Types

The dwEvent member of the MIDIEVENT structure describes the MIDI event that is to take place. Short events fit entirely into this member. Long events require one or more doubleword values in addition to the dwEvent member to store the event descriptions.

The high byte of the dwEvent member contains information about whether the event is long or short and about whether a callback is generated along with the event. In addition, this byte is used to describe the event type. The remaining 24 bits of the dwEvent member are used either to contain the event parameters (for short messages) or to contain the length of the event parameters (for long messages). To extract information from the dwEvent member, use the MEVT_EVENTTYPE and MEVT_EVENTPARM macros .

For a description of the predefined event types, see the reference material for the MIDIEVENT structure.


MIDI Streams

MIDI events occur in the context of a stream of MIDI data. Although an application can use several streams to define musical data, the MIDI mapper does not recognize multiple streams. Most applications that use streams will use a single MIDI stream.

The following functions work with streams:

midiStreamClose	Closes a MIDI stream.
midiStreamOpen	Opens a MIDI stream and retrieves a handle of it.
midiStreamOut	Plays or queues a stream (buffer) of MIDI data to a MIDI output device.
midiStreamPause	Pauses playback of a specified MIDI stream.
midiStreamPosition	Retrieves the current position in a MIDI stream.
midiStreamProperty	Sets and retrieves stream properties.
midiStreamRestart	Restarts playback of a paused MIDI stream.
midiStreamStop	Turns off all notes on all MIDI channels for the specified MIDI stream.


Low-Level MIDI Services

Most applications will be able to use the MCI MIDI sequencer or stream buffers (and the midiStreamOut function) to implement all the MIDI functionality they need. Serious MIDI developers — those producing MIDI authoring or sequencing tools — can use either a combination of the stream capabilities and the low-level MIDI services or use only the low-level services. This section presents general information about using the low-level MIDI services.


Querying MIDI Devices

Before playing or recording MIDI data, you must determine the capabilities of the MIDI hardware present in the system. MIDI capability can vary from one multimedia computer to the next; applications should not make assumptions about the hardware present in a given system.

Windows provides the following functions to determine how many MIDI devices are available for input or output in a given system:

midiInGetNumDevs	Retrieves the number of MIDI input devices present in the system.
midiOutGetNumDevs	Retrieves the number of MIDI output devices present in the system.
Like other audio devices, MIDI devices are identified by a device identifier, which is determined implicitly from the number of devices present in a given system. Device identifiers range from zero to one less than the number of devices present. For example, if there are two MIDI output devices in a system, valid device identifiers are 0 and 1.

After you determine how many MIDI input or output devices are present in a system, you can inquire about the capabilities of each device. Windows provides the following functions to determine the capabilities of audio devices:

midiInGetDevCaps	Retrieves the capabilities of a given MIDI input device and places this information in the MIDIINCAPS structure.
midiOutGetDevCaps	Retrieves the capabilities of a given MIDI output device and places this information in the MIDIOUTCAPS structure.
Each of these functions has a parameter specifying the address of a structure that the function fills with information about the capabilities of a specified device.


Opening and Closing Device Drivers

You must open a MIDI device before using it, and you should close the device as soon as you finish using it. Windows provides the following functions to open and close different types of MIDI devices:

midiInClose	Closes a specified MIDI input device.
midiInOpen	Opens a specified MIDI input device for recording.
midiOutClose	Closes a specified MIDI output device.
midiOutOpen	Opens a MIDI output device for playback.
Each function that opens a MIDI device takes as parameters a device identifier, an address of a memory location, and some parameters unique to MIDI devices. The memory location is filled with a device handle, which is used to identify the open audio device in calls to other audio functions.

Many MIDI functions can accept either a device handle or a device identifier. Although you can use a device handle wherever you would use a device identifier, you cannot always use a device identifier when a handle is called for.

Note  MIDI devices are not guaranteed to be shareable, so a particular device might not be available when a user requests it. If this happens, the applications should notify the user and allow the user to try to open the device again.


Allocating and Preparing MIDI Data Blocks

The midiOutLongMsg, midiInAddBuffer, and midiStreamOut functions require applications to allocate data blocks to pass to the device drivers for playback or recording purposes. Each of these functions uses a MIDIHDR structure to describe its data block.

Before you use one of these functions to pass a data block to a device driver, you must allocate memory for the buffer and the header structure that describes the data block.

Windows provides the following functions for preparing and cleaning up MIDI data blocks:

midiInPrepareHeader	Prepares a MIDI input data block.
midiInUnprepareHeader	Cleans up the preparation of a MIDI input data block.
midiOutPrepareHeader	Prepares a MIDI output data block.
midiOutUnprepareHeader	Cleans up the preparation of a MIDI output data block.
Before you pass a MIDI data block to a device driver, you must prepare the buffer by passing it to the midiInPrepareHeader or midiOutPrepareHeader function. When the device driver is finished with the buffer and returns it, you must clean up this preparation by passing the buffer to the midiInUnprepareHeader or midiOutUnprepareHeader function before any allocated memory can be freed.


Managing MIDI Data Blocks

Applications that use data blocks for passing system-exclusive messages (using the midiOutLongMsg and midiInAddBuffer functions) and stream buffers (using the midiStreamOut function) must continually supply the device driver with data blocks until playback or recording is complete.

Even if a single data block is used, applications must be able to determine when a device driver is finished with the data block so that the application can free the memory associated with the data block and header structure. Three methods can be used to determine when a device driver is finished with a data block:

•	Specify a callback function to receive a message sent by the driver when it is finished with a data block. To get time-stamped MIDI input data, you must use a callback function.

•	Use an event callback (for output only).

•	Use a window or thread callback to receive a message sent by the driver when it is finished with a data block.

If an application does not get a data block to the device driver when it is needed, there can be an audible gap in playback or a loss of incoming recorded information. An application should use at least a double-buffering scheme to stay at least one data block ahead of the device driver.

Using a Callback Function to Process Driver Messages

You can write your own callback function to process messages sent by the device driver. To use a callback function, specify the CALLBACK_FUNCTION flag in the dwFlags parameter and the address of the callback function in the dwCallback parameter of the midiInOpen or midiOutOpen function.

Messages sent to a callback function are similar to messages sent to a window, except they have two doubleword parameters instead of a unsigned integer parameter and a doubleword parameter. For more information about these messages, see "Sending System-Exclusive Messages" later in this chapter and "Managing MIDI Recording" later in this chapter.

Use one of the following techniques to pass instance data from an application to a callback function:

•	Use the dwCallbackInstance parameter of the function that opens the device driver.

•	Use the dwUser member of the MIDIHDR structure that identifies a data block being sent to a MIDI device driver.

If you need more than 32 bits of instance data, pass an address of a structure containing the additional information.

Using an Event Callback to Process Driver Messages

To use an event callback, use the CreateEvent function to retrieve the handle of an event and specify CALLBACK_EVENT in the call to the midiOutOpen function.

An event callback is set by anything that might cause a function callback. Unlike callback functions and window or thread callbacks, event callbacks do not receive specific close, done, or open notifications. An application might, therefore, have to check the status of the process it is waiting for after the event occurs.

For more information about event callbacks, see "Using an Event Callback to Manage Buffered Playback" later in this chapter.

Using a Window or Thread Callback to Process Driver Messages

To use a window callback, specify the CALLBACK_WINDOW flag in the dwFlags parameter and a window handle in the low-order word of the dwCallback parameter of the midiInOpen or midiOutOpen function. Driver messages will be sent to the window procedure function for the window identified by the handle in dwCallback.

Similarly, to use a thread callback, specify the CALLBACK_THREAD flag and a thread identifier in the call to midiInOpen or midiOutOpen. In this case, messages will be posted to the specified thread instead of to a window.

Messages sent to a window or thread callback are specific to the MIDI device used. For more information about these messages, see "Sending System-Exclusive Messages" later in this chapter and "Managing MIDI Recording" later in this chapter.


Requesting Time Formats

Windows uses the MMTIME structure to represent time in one or more different formats, including milliseconds, samples, SMPTE, and MIDI song pointer formats. The wType member specifies the time format.

The midiStreamPosition function uses the MMTIME structure. Before calling this function, you must set the wType member to indicate your requested time format. To see if the requested time format is supported, check wType after the call. If the requested time format is not supported, the time is specified in an alternate time format selected by the device driver and the wType member is changed to indicate the selected time format.

For more information about the MMTIME structure, see Chapter 17, "Timers."


Handling Errors with MIDI Functions

Low-level audio functions return a nonzero error code. For MIDI-associated errors, the midiInGetErrorText and midiOutGetErrorText functions retrieve textual descriptions for the error codes. The application must still look at the error value itself to determine how to proceed, but it can use the error descriptions in dialog boxes to inform users of the error conditions.

The only low-level MIDI functions that do not return error codes are the midiInGetNumDevs and midiOutGetNumDevs functions. These functions return a value of zero if no devices are present in a system or if any errors are encountered by the function.


Playing MIDI Files

You should use the MCI MIDI sequencer to play MIDI files whenever you can. If the sequencer services do not meet the needs of your application, you can manage MIDI playback by using stream buffers or the low-level MIDI services.


MIDI Output Data Types

Windows defines the following data types for low-level MIDI output functions:

HMIDIOUT	Handle of a MIDI output device.
MIDIHDR	Header for a block of MIDI system-exclusive or stream data.
MIDIOUTCAPS	Structure used to inquire about the capabilities of a particular MIDI output device.


Querying MIDI Output Devices

Before playing a MIDI file, you should use the midiOutGetDevCaps function to determine the capabilities of the MIDI output device that is present in the system. This function takes an address of a MIDIOUTCAPS structure, which it fills with information about the capabilities of the given device. This information includes the manufacturer and product identifiers, a product name for the device, and the version number of the device driver (specified in the wMid, wPid, szPname, and vDriverVersion members, respectively).

MIDI output devices can be either internal synthesizers or external MIDI output ports. The wTechnology member of the MIDIOUTCAPS structure specifies the technology of the device.

If the device is an internal synthesizer, additional device information is available in the wVoices, wNotes, and wChannelMask members. The wVoices member specifies the number of voices that the device supports. Each voice can have a different sound or timbre. Voices are organized into MIDI channels. The wNotes member specifies the polyphony of the device — that is, the maximum number of notes that can be played simultaneously. The wChannelMask member is a bit representation of the MIDI channels that the device responds to. For example, if the device responds to the first eight MIDI channels, wChannelMask is 0x00FF. If the device is an external output port, wVoices and wNotes are unused, and wChannelMask is set to 0xFFFF.

The dwSupport member of the MIDIOUTCAPS structure indicates whether the device driver supports volume changes, patch caching, and streaming. Volume changes are supported only by internal synthesizer devices. External MIDI output ports do not support volume changes. For information about changing volume, see "Changing Internal MIDI Synthesizer Volume" later in this chapter.


Opening MIDI Output Devices

To open a MIDI output device for playback, use the midiOutOpen function. This function opens the device associated with the specified device identifier and returns a handle of the open device by writing the handle to a specified memory location.

One of the parameters of midiOutOpen is a doubleword value that specifies a window or thread handle, an event handle, or the address of a callback function that is used to monitor the progress of the playback of MIDI system-exclusive data and stream buffers. Monitoring enables the application to determine when to send additional data blocks and when to free data blocks that have been sent. For more information about these methods, see "Managing MIDI Data Blocks" earlier in this chapter.


Sending MIDI Messages with Stream Buffers

When your application works with stream buffers, it uses the midiStreamOut function to send all (short and long) MIDI messages to the device. To specify stream data blocks, use the MIDIHDR and MIDIEVENT structures. The MIDIHDR structure contains an address of a locked data block, the data-block length, and some assorted flags. The data is stored in the form of MIDIEVENT structures. The system imposes a size limit of 64K on stream buffers.

After you use midiStreamOut to send a stream buffer of data, you must wait until the device driver is finished with the data block before freeing it. If you are sending multiple data blocks, you must monitor the completion of each data block so that you know when to send additional blocks. For information about different techniques for monitoring data-block completion, see "Managing MIDI Data Blocks" earlier in this chapter.


Sending Individual MIDI Messages

You can work with individual MIDI messages by using the following functions:

midiOutLongMsg	Sends a buffer of MIDI data to the specified MIDI output device. Use this function to send system-exclusive messages to a MIDI device.
midiOutReset	Turns off all notes on all channels for a specified MIDI output device. Any pending system-exclusive buffers and stream buffers are marked as done and returned to the application.
midiOutShortMsg	Sends a MIDI message to a specified MIDI output device.
To send any MIDI message (except for system-exclusive messages), use midiOutShortMsg.


Sending System-Exclusive Messages

MIDI system-exclusive messages are the only MIDI messages that will not fit into a single doubleword value. System-exclusive messages can be any length. Windows provides the midiOutLongMsg function for sending system-exclusive messages to MIDI output devices. To specify MIDI system-exclusive data blocks, use the MIDIHDR structure.

After you send a system-exclusive data block using midiOutLongMsg, you must wait until the device driver is finished with the data block before freeing it. If you are sending multiple data blocks, you must monitor the completion of each data block so that you know when to send additional blocks. For information about different techniques for monitoring data-block completion, see "Managing MIDI Data Blocks" earlier in this chapter.

Note  Any MIDI status byte other than a system − real-time message will terminate a system-exclusive message. If you are using multiple data blocks to send a single system-exclusive message, do not send any MIDI messages other than system − real-time messages between data blocks.


Using a Window or Thread to Manage Buffered Playback

The following messages can be sent to a window or thread for managing playback of MIDI system-exclusive messages or stream buffers:

MM_MOM_CLOSE	Sent when the device is closed by using the midiOutClose function.
MM_MOM_DONE	Sent when the device driver is finished with a data block sent by using the midiOutLongMsg or midiStreamOut function.
MM_MOM_OPEN	Sent when the device is opened by using the midiOutOpen function.
A wParam parameter and an lParam parameter are associated with each of these messages. The wParam parameter always specifies the handle of an open MIDI device. For MM_MOM_DONE, lParam specifies an address of a MIDIHDR structure identifying the completed data block. The lParam parameter is unused for MM_MOM_CLOSE and MM_MOM_OPEN.

The most useful message is probably MM_MOM_DONE. Unless you need to allocate memory or initialize variables, you probably do not need to process MM_MOM_OPEN and MM_MOM_CLOSE. When playback of a data block is complete, you can clean up and free the data block.


Using a Callback Function to Manage Buffered Playback

You can define your own callback function to manage buffered playback of MIDI output devices. The callback function is documented as MidiOutProc in the Reference section of this chapter.

The following messages can be sent to the wMsg parameter of the MidiOutProc callback function.

MOM_CLOSE	Sent when the device is closed by using the midiOutClose function.
MOM_DONE	Sent when the device driver is finished with a data block sent by using the midiOutLongMsg or midiStreamOut function.
MOM_OPEN	Sent when the device is opened by using the midiOutOpen function.
These messages are similar to those sent to window procedure functions, but the parameters are different. A handle of the open MIDI device is passed as a parameter to the callback function, along with the doubleword of instance data passed by using midiOutOpen.

After the driver is finished with a data block, you can clean up and free the data block.


Using an Event Callback to Manage Buffered Playback

To use an event callback, use the CreateEvent function to retrieve the handle of an event. In a call to the midiOutOpen function, specify CALLBACK_EVENT for the dwFlags parameter. After using the midiOutPrepareHeader function but before sending MIDI events to the device, create a nonsignaled event by calling the ResetEvent function, specifying the event handle retrieved by CreateEvent. Then, inside a loop that checks whether the MHDR_DONE bit is set in the dwFlags member of the MIDIHDR structure, use the WaitForSingleObject function, specifying the event handle and a time-out value of INFINITE as parameters.

An event callback is set by anything that might cause a function callback.

Because event callbacks do not receive specific close, done, or open notifications, an application might have to check the status of the process it is waiting for after the event occurs. It is possible that a number of tasks could be completed by the time WaitForSingleObject returns.


Resetting MIDI Output

The midiOutReset function turns off all notes on all MIDI channels for a specified MIDI device. Then the function marks any pending system-exclusive buffers as done and returns them to the application. This function can be useful in an application that uses MIDI output to provide the user with the ability to reset MIDI output.

Note  Terminating a system-exclusive message without sending an EOX (end-of-exclusive) byte might cause problems for the receiving device. The midiOutReset function does not send an EOX byte when it terminates a system-exclusive message — applications are responsible for doing this.


Changing Internal MIDI Synthesizer Volume

Windows provides the following functions to retrieve and set the volume level of internal MIDI synthesizer devices:

midiOutGetVolume	Retrieves the volume level of the specified internal MIDI synthesizer device.
midiOutSetVolume	Sets the volume level of the specified internal MIDI synthesizer device.
Not all MIDI output devices support volume changes. Some devices can support individual volume changes on both the left and right channels. For information about how to determine if a particular device supports volume changes, see "Querying MIDI Output Devices" earlier in this chapter.

Unless your application is designed to be a master volume-control application providing the user with volume control for all audio devices in a system, you should open an audio device before changing its volume. You should also check the volume level before changing it and restore the volume level to its previous level as soon as possible.

Volume is specified as a doubleword value. The upper 16 bits specify the relative volume of the right channel, and the lower 16 bits specify the relative volume of the left channel.

For devices that do not support individual volume changes on both the left and right channels, the lower 16 bits specify the volume level and the upper 16 bits are ignored. Values for the volume level range from 0x0 (silence) to 0xFFFF (maximum volume) and are interpreted logarithmically. The perceived volume increase is the same when increasing the volume level from 0x5000 to 0x6000 as it is from 0x4000 to 0x5000.


Preloading Patches with Internal MIDI Synthesizers

Some internal MIDI synthesizer devices cannot keep all of their patches loaded simultaneously. These devices must preload their patch data.

Windows provides the following functions to request that a synthesizer preload and cache specified patches:

midiOutCachePatches	Requests that an internal MIDI synthesizer device preload and cache specified melodic patches.
midiOutCacheDrumPatches	Requests that an internal MIDI synthesizer device preload and cache specified key-based percussion patches.
For information about how to determine if a particular device supports preloading patches, see "Querying MIDI Output Devices" earlier in this chapter.


Recording MIDI Audio

To record MIDI audio data, you must use low-level MIDI input functions. MCI does not provide a device handler for recording MIDI audio.


MIDI Input Data Types

Windows defines the following data types for low-level MIDI input functions:

HMIDIIN	Handle of a MIDI input device.
MIDIHDR	Header for a stream buffer or a block of MIDI system-exclusive data. For input applications, this structure records only system-exclusive data (streaming is not supported for MIDI input).
MIDIINCAPS	Structure used to inquire about the capabilities of a MIDI input device.


Querying MIDI Input Devices

Before recording MIDI audio, you should use the midiInGetDevCaps function to determine the capabilities of the MIDI input device that is present in the system. This function takes an address of a MIDIINCAPS structure, which it fills with information about the capabilities of the given device. This information includes the manufacturer and product identifiers, a product name for the device, and the version number of the device driver.


Opening MIDI Input Devices

To open a MIDI input device for recording, use the midiInOpen function. This function opens the device associated with the specified device identifier and returns a handle of the open device by writing the handle to a specified memory location.

If you use the MIDI_IO_STATUS flag with midiInOpen, the system uses the MIM_MOREDATA message to alert your application's callback function whenever it is not processing MIDI data fast enough to keep up with the input device driver. (The MM_MIM_MOREDATA message does the same job with window callbacks, but most applications will use callback functions instead of window callbacks, for performance reasons.) If your application processes MIDI data in a separate thread, boosting the thread's priority can have a significant impact on the application's ability to keep up with the data flow.


Managing MIDI Recording

After you open a MIDI device, you can begin recording MIDI data. Windows provides the following functions for managing MIDI recording:

midiInAddBuffer	Sends a buffer to the device driver so that it can be filled with recorded system-exclusive MIDI data.
midiInReset	Stops MIDI recording and marks all pending buffers as done.
midiInStart	Starts MIDI recording and resets the time stamp to zero.
midiInStop	Stops MIDI recording.
To send buffers to the device driver for recording system-exclusive messages, use midiInAddBuffer. The application is notified as the buffers are filled with system-exclusive recorded data. For more information about the notification techniques, see "Managing MIDI Data Blocks" earlier in this chapter.

The midiInStart function begins the recording process. When recording system-exclusive messages, send at least one buffer to the driver before starting recording. To stop recording, use midiInStop. Before closing the device by using the midiInClose function, mark any pending data blocks as being done by calling midiInReset.

Applications that require time-stamped data use a callback function to receive MIDI data. If your timing requirements are not strict, you can use a window or thread callback. You cannot use an event callback to receive MIDI data, however.

To record system-exclusive messages with applications that do not use stream buffers, you must supply the device driver with buffers. These buffers are specified by using a MIDIHDR structure.


Managing MIDI Thru

It is possible to connect a MIDI input device directly to a MIDI output device so that whenever the input device receives an MIM_DATA message, the system sends a message with the same MIDI event data to the output device driver. To connect a MIDI output device to a MIDI input device, use the midiConnect function.

To achieve the best possible performance with multiple outputs, an application can choose to supply a special form of MIDI output driver, called a thru driver. Although the system allows only one MIDI output device to be connected to a MIDI input device, multiple MIDI output devices can be connected to a thruing driver. An application on such a system could connect the MIDI input device to this thru device and connect the MIDI thru device to as many MIDI output devices as needed. For more information about thru drivers, see the Windows device-driver documentation.

Using Messages to Manage MIDI Recording

The following messages can be sent to a window or thread callback procedure for managing MIDI recording:

MM_MIM_CLOSE	Sent when a MIDI input device is closed by using the midiInClose function.
MM_MIM_DATA	Sent when a complete MIDI message is received. (This message is used for all MIDI messages except system-exclusive messages.)
MM_MIM_ERROR	Sent when an invalid MIDI message is received. (This message is used for all MIDI messages except system-exclusive messages.)
MM_MIM_LONGDATA	Sent when either a complete MIDI system-exclusive message is received or when a buffer has been filled with system-exclusive data.
MM_MIM_LONGERROR	Sent when an invalid MIDI system-exclusive message is received.
MM_MIM_MOREDATA	Sent when an application is not processing MIM_DATA messages fast enough to keep up with the input device driver.
MM_MIM_OPEN	Sent when a MIDI input device is opened by using the midiInOpen function.
A wParam parameter and an lParam parameter are associated with each of these messages. The wParam parameter always specifies the handle of an open MIDI device. The lParam parameter is unused for the MM_MIM_CLOSE and MM_MIM_OPEN messages.

For the MM_MIM_LONGDATA message, lpMidiHdr specifies an address of a MIDIHDR structure that identifies the buffer for system-exclusive messages. The buffer might not be completely filled, because you usually do not know the size of the system-exclusive messages before recording them and must allocate buffers whose total size can contain the largest expected message. To determine the amount of valid data present in the buffer, use the dwBytesRecorded member of the MIDIHDR structure.

Using a Callback Function to Manage MIDI Recording

You can define your own callback function to manage recording for MIDI input devices. The callback function is documented as MidiInProc in the Reference section of this chapter.

The following messages can be sent to the wMsg parameter of the MidiInProc callback function:

MIM_CLOSE	Sent when the device is closed by using the midiInClose function.
MIM_DATA	Sent when a complete MIDI message is received (this message is used for all MIDI messages except system-exclusive messages).
MIM_ERROR	Sent when an invalid MIDI message is received (this message is used for all MIDI messages except system-exclusive messages).
MIM_LONGDATA	Sent when either a complete MIDI system-exclusive message is received or when a buffer has been filled with system-exclusive data.
MIM_LONGERROR	Sent when an invalid MIDI system-exclusive message is received.
MIM_MOREDATA	Sent when an application is not processing MIM_DATA messages fast enough to keep up with the input device driver.
MIM_OPEN	Sent when the MIDI input device is opened by using the midiInOpen function.
These messages are similar to those sent to window procedure functions, but the parameters are different. A handle of the open MIDI device is passed as a parameter to the callback function, along with the doubleword of instance data that was passed by using midiInOpen.

For the MIM_LONGDATA message, lpMidiHdr specifies an address of a MIDIHDR structure that identifies the buffer for system-exclusive messages. The buffer might not be completely filled. To determine the amount of valid data present in the buffer, use the dwBytesRecorded member of the MIDIHDR structure.

After the device driver is finished with a data block, you can clean up and free the data block.


Receiving Time-Stamped MIDI Messages

Because of the delay between when the device driver receives a MIDI message and the time the application receives the message, MIDI input device drivers time stamp the MIDI message with the time that the message was received. MIDI time stamps, which are defined as the time the first byte of the message was received, are specified in milliseconds. The midiInStart function resets the time stamps for a device to zero.

As stated previously, to receive time stamps with MIDI input, you must use a callback function. The dwParam2 parameter of the callback function specifies the time stamp for data associated with the MIM_DATA and MIM_LONGDATA messages.


Receiving Running-Status Messages

The Standard MIDI Files 1.0 specification allows the use of running status when a message has the same status byte as the previous message. When running status is used, the status byte of subsequent messages can be omitted. All MIDI input device drivers are required to expand messages using running status into complete messages, so that you always receive complete MIDI messages from a MIDI input device driver.


Processing MIDI Data from Two MIDI Sources

The MIDI subsystem can route MIDI messages from two data sources to a single MIDI output device for concurrent playback. For example, one source could be background music or a bass line that has been pre-recorded and stored in a file. The second source could be live data from a MIDI instrument, such as a keyboard or guitar.

Both data sources send MIDI data to a single MIDI device that is identified with one handle. You send one data stream by using the midiStreamOut function and one or more stream buffers. This data stream typically contains prerecorded data that is packed into the buffer.

You send the second data stream (typically from a MIDI instrument) asynchronously by using the midiOutShortMsg function. The running status of a stream buffer will not be adversely affected by the asynchronous calls made by the second data stream.

Each short message sent with midiOutShortMsg must be a complete MIDI message, with a status byte and the appropriate number of data bytes. If the status byte is omitted, midiOutShortMsg returns an error. (There is no running status with stream output, however.)


Creating MIDI Files

When creating MIDI files, you should use the guidelines set forth in the General MIDI Level 1.0 specification published by the International MIDI Association. This document defines standard voice and percussive patch assignments for MIDI instruments.

For more information about the general MIDI specification, contact the International MIDI Association at the following address:

The International MIDI Association
23634 Emelita Street
Woodland Hills, CA  91367
Phone: (818) 598-0088


Using MIDI

This section contains examples demonstrating how to perform the following tasks:

•	Use the MCI MIDI sequencer.

•	Send individual MIDI messages.


Using the MCI MIDI Sequencer

Like all MCI devices, the MCI MIDI sequencer responds to standard MCI commands. This section discusses how to retrieve a sequence division type and how to retrieve and set a tempo. For more information about MCI, see Chapter 3, "MCI Overview."


Retrieving the Sequence Division Type

The division type of a MIDI sequence determines the amount of time between MIDI events in the sequence. To determine the division type of a sequence, use the MCI_STATUS command and set the dwItem member of the MCI_STATUS_PARMS structure to MCI_SEQ_STATUS_DIVTYPE .

If the MCI_STATUS command is successful, the dwReturn member of the MCI_STATUS_PARMS structure contains one of the following values to indicate the division type.

Value	Division type
MCI_SEQ_DIV_PPQN	PPQN (parts-per-quarter note)
MCI_SEQ_DIV_SMPTE_24	SMPTE, 24 fps (frames per second)
MCI_SEQ_DIV_SMPTE_25	SMPTE, 25 fps
MCI_SEQ_DIV_SMPTE_30	SMPTE, 30 fps
MCI_SEQ_DIV_SMPTE_30DROP	SMPTE, 30 fps drop frame
You must know the division type of a sequence to change or query its tempo. You cannot change the division type of a sequence by using the MCI sequencer.


Querying and Setting the Tempo

To retrieve the tempo of a sequence, use the MCI_STATUS command and set the dwItem member of the MCI_STATUS_PARMS structure to MCI_SEQ_STATUS_TEMPO. If the MCI_STATUS command is successful, the dwReturn member of the MCI_STATUS_PARMS structure contains the current tempo.

To change tempo, use the MCI_SET command with the MCI_SEQ_SET_PARMS structure, specifying the MCI_SEQ_SET_TEMPO flag and setting the dwTempo member of the structure to the desired tempo.

The way tempo is represented depends on the division type of the sequence. If the division type is PPQN, the tempo is represented in beats per minute. If the division type is one of the SMPTE division types, the tempo is represented in frames per second. For information about determining the division type of a sequence, see "Retrieving the Sequence Division Type" earlier in this chapter.


Using midiOutShortMsg to Send Individual MIDI Messages

The following example uses the midiOutShortMsg function to send a specified MIDI event to a given MIDI output device:

UINT sendMIDIEvent(HMIDIOUT hmo, BYTE bStatus, BYTE bData1,

    BYTE bData2)

{

    union {

        DWORD dwData;

        BYTE bData[4];

    } u;

    // Construct the MIDI message.

    u.bData[0] = bStatus;  // MIDI status byte

    u.bData[1] = bData1;   // first MIDI data byte

    u.bData[2] = bData2;   // second MIDI data byte

    u.bData[3] = 0;

    // Send the message.

    return midiOutShortMsg(hmo, u.dwData);

}

Note  MIDI output drivers are not required to verify data before sending it to an output port. Applications must ensure that only valid data is sent.


MIDI Reference

This section describes the functions, macros, messages, and structures associated with the Musical Instrument Digital Interface (MIDI). These elements are grouped as follows.

Allocating and Managing Buffers

MIDIHDR
midiInAddBuffer
midiInPrepareHeader
midiInUnprepareHeader
midiOutPrepareHeader
midiOutUnprepareHeader

Callback Functions

MidiInProc
MidiOutProc

Device Capabilities

MIDIINCAPS
midiInGetDevCaps
midiInGetID
midiInGetNumDevs
MIDIOUTCAPS
midiOutGetDevCaps
midiOutGetID
midiOutGetNumDevs
MIDISTRMBUFFVER

Error Processing

midiInGetErrorText
midiOutGetErrorText
MIM_ERROR
MIM_LONGERROR
MM_MIM_ERROR
MM_MIM_LONGERROR

Managing MIDI Streams

midiStreamClose
midiStreamOpen
midiStreamOut
midiStreamPause
midiStreamPosition
midiStreamProperty
midiStreamRestart
midiStreamStop

Opening and Closing Devices

midiInClose
midiInOpen
midiOutClose
midiOutOpen
MIM_CLOSE
MIM_OPEN
MM_MIM_CLOSE
MM_MIM_OPEN
MM_MOM_CLOSE
MM_MOM_OPEN
MOM_CLOSE
MOM_OPEN

Output Devices

KEYARRAY
midiOutCacheDrumPatches
midiOutCachePatches
midiOutGetVolume
midiOutSetVolume
PATCHARRAY

Playing a Message or Messages

MEVT_EVENTPARM
MEVT_EVENTTYPE
MIDIEVENT
midiOutLongMsg
midiOutReset
midiOutShortMsg
midiStreamOut
midiStreamPause
midiStreamRestart
midiStreamStop
MM_MOM_DONE
MM_MOM_POSITIONCB
MOM_DONE
MOM_POSITIONCB

Recording

midiConnect
midiDisconnect
midiInReset
midiInStart
midiInStop
MIDIPROPTEMPO
MIDIPROPTIMEDIV
MIM_DATA
MIM_LONGDATA
MIM_MOREDATA
MM_MIM_DATA
MM_MIM_MOREDATA
MM_MIM_LONGDATA

Sending Messages to Devices

midiInMessage
midiOutMessage


midiConnect

MMRESULT midiConnect(HMIDI hMidi, HMIDIOUT hmo,

    LPVOID pReserved);

Connects a MIDI input device to a MIDI thru or output device, or connects a MIDI thru device to a MIDI output device.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MIDIERR_NOTREADY	Specified input device is already connected to an output device.
MMSYSERR_INVALHANDLE	Specified device handle is invalid.
hMidi

Handle of a MIDI input device or a MIDI thru device. (For thru devices, this handle must have been returned by a call to the midiOutOpen function.)

hmo

Handle of the MIDI output or thru device.

pReserved

Reserved; must be NULL.

After calling this function, the MIDI input device receives event data in an MIM_DATA message whenever a message with the same event data is sent to the output device driver.

A thru driver is a special form of MIDI output driver. The system will allow only one MIDI output device to be connected to a MIDI input device, but multiple MIDI output devices can be connected to a MIDI thru device. Whenever the given MIDI input device receives event data in an MIM_DATA message, a message with the same event data is sent to the given output device driver (or through the thru driver to the output drivers).


midiDisconnect

MMRESULT midiDisconnect(HMIDI hMidi, HMIDIOUT hmo,

    LPVOID pReserved);

Disconnects a MIDI input device from a MIDI thru or output device, or disconnects a MIDI thru device from a MIDI output device.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALHANDLE	Specified device handle is invalid.
hMidi

Handle of a MIDI input device or a MIDI thru device.

hmo

Handle of the MIDI output device to be disconnected.

pReserved

Reserved; must be NULL.

MIDI input, output, and thru devices can be connected by using the midiConnect function. Thereafter, whenever the MIDI input device receives event data in an MIM_DATA message, a message with the same event data is sent to the output device driver (or through the thru driver to the output drivers).


midiInAddBuffer

MMRESULT midiInAddBuffer(HMIDIIN hMidiIn, LPMIDIHDR lpMidiInHdr,

    UINT cbMidiInHdr);

Sends an input buffer to a specified opened MIDI input device. This function is used for system-exclusive messages.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MIDIERR_STILLPLAYING	The buffer pointed to by lpMidiInHdr is still in the queue.
MIDIERR_UNPREPARED	The buffer pointed to by lpMidiInHdr has not been prepared.
MMSYSERR_INVALHANDLE	The specified device handle is invalid.
MMSYSERR_INVALPARAM	The specified pointer or structure is invalid.
MMSYSERR_NOMEM	The system is unable to allocate or lock memory.
hMidiIn

Handle of the MIDI input device.

lpMidiInHdr

Address of a MIDIHDR structure that identifies the buffer.

cbMidiInHdr

Size, in bytes, of the MIDIHDR structure.

When the buffer is filled, it is sent back to the application.

The buffer must be prepared by using the midiInPrepareHeader function before it is passed to the midiInAddBuffer function.


midiInClose

MMRESULT midiInClose(HMIDIIN hMidiIn);

Closes the specified MIDI input device.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MIDIERR_STILLPLAYING	Buffers are still in the queue.
MMSYSERR_INVALHANDLE	The specified device handle is invalid.
MMSYSERR_NOMEM	The system is unable to allocate or lock memory.
hMidiIn

Handle of the MIDI input device. If the function is successful, the handle is no longer valid after the call to this function.

If there are input buffers that have been sent by using the midiInAddBuffer function and have not been returned to the application, the close operation will fail. To return all pending buffers through the callback function, use the midiInReset function.


midiInGetDevCaps

MMRESULT midiInGetDevCaps(UINT uDeviceID, LPMIDIINCAPS lpMidiInCaps,

    UINT cbMidiInCaps);

Determines the capabilities of a specified MIDI input device.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_BADDEVICEID	The specified device identifier is out of range.
MMSYSERR_INVALPARAM	The specified pointer or structure is invalid.
MMSYSERR_NODRIVER	The driver is not installed.
MMSYSERR_NOMEM	The system is unable to allocate or lock memory.
uDeviceID

Identifier of the MIDI input device. The device identifier varies from zero to one less than the number of devices present. This parameter can also be a properly cast device handle.

lpMidiInCaps

Address of a MIDIINCAPS structure that is filled with information about the capabilities of the device.

cbMidiInCaps

Size, in bytes, of the MIDIINCAPS structure. Only cbMidiInCaps bytes (or less) of information is copied to the location pointed to by lpMidiInCaps. If cbMidiInCaps is zero, nothing is copied, and the function returns MMSYSERR_NOERROR.

To determine the number of MIDI input devices present on the system, use the midiInGetNumDevs function.


midiInGetErrorText

MMRESULT midiInGetErrorText(MMRESULT wError, LPSTR lpText,

    UINT cchText);

Retrieves a textual description for an error identified by the specified error code.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_BADERRNUM	The specified error number is out of range.
MMSYSERR_INVALPARAM	The specified pointer or structure is invalid.
MMSYSERR_NOMEM	The system is unable to allocate or lock memory.
wError

Error code.

lpText

Address of the buffer to be filled with the textual error description.

cchText

Length, in characters, of the buffer pointed to by lpText.

If the textual error description is longer than the specified buffer, the description is truncated. The returned error string is always null-terminated. If cchText is zero, nothing is copied, and the function returns zero. All error descriptions are less than MAXERRORLENGTH characters long.


midiInGetID

MMRESULT midiInGetID(HMIDIIN hmi, LPUINT puDeviceID);

Gets the device identifier for the given MIDI input device.

This function is supported for backward compatibility. New applications can cast a handle of the device rather than retrieving the device identifier.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALHANDLE	The hwi parameter specifies an invalid handle.
MMSYSERR_NODRIVER	No device driver is present.
MMSYSERR_NOMEM	Unable to allocate or lock memory.
hmi

Handle of the MIDI input device.

puDeviceID

Address of a variable to be filled with the device identifier.


midiInGetNumDevs

UINT midiInGetNumDevs(VOID);

Retrieves the number of MIDI input devices in the system.

•	Returns the number of MIDI input devices present in the system. A return value of zero means that there are no devices (not that there is no error).


midiInMessage

DWORD midiInMessage(HMIDIIN hMidiIn, UINT msg, DWORD dw1, DWORD dw2);

Sends a message to the MIDI device driver.

•	Returns the value returned by the audio device driver.

hMidiIn

Handle of the MIDI device.

msg

Message to send.

dw1 and dw2

Message parameters.

This function is used only for driver-specific messages that are not supported by the MIDI API.


midiInOpen

MMRESULT midiInOpen(LPHMIDIIN lphMidiIn, UINT uDeviceID,

    DWORD dwCallback, DWORD dwCallbackInstance, DWORD dwFlags);

Opens a specified MIDI input device.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_ALLOCATED	The specified resource is already allocated.
MMSYSERR_BADDEVICEID	The specified device identifier is out of range.
MMSYSERR_INVALFLAG	The flags specified by dwFlags are invalid.
MMSYSERR_INVALPARAM	The specified pointer or structure is invalid.
MMSYSERR_NOMEM	The system is unable to allocate or lock memory.
lphMidiIn

Address of an HMIDIIN handle. This location is filled with a handle identifying the opened MIDI input device. The handle is used to identify the device in calls to other MIDI input functions.

uDeviceID

Identifier of the MIDI input device to be opened.

dwCallback

Address of a callback function, a thread identifier, or a handle of a window called with information about incoming MIDI messages.

dwCallbackInstance

User instance data passed to the callback function. This parameter is not used with window callback functions or threads.

dwFlags

Callback flag for opening the device and, optionally, a status flag that helps regulate rapid data transfers. It can be the following values:

CALLBACK_FUNCTION

The dwCallback parameter is a callback procedure address.

CALLBACK_NULL

There is no callback mechanism. This value is the default setting.

CALLBACK_THREAD

The dwCallback parameter is a thread identifier.

CALLBACK_WINDOW

The dwCallback parameter is a window handle.

MIDI_IO_STATUS

When this parameter also specifies CALLBACK_FUNCTION, MIM_MOREDATA messages are sent to the callback function as well as MIM_DATA messages. Or, if this parameter also specifies CALLBACK_WINDOW, MM_MIM_MOREDATA messages are sent to the window as well as MM_MIM_DATA messages. This flag does not affect event or thread callbacks.

Most applications that use a callback mechanism will specify CALLBACK_FUNCTION for this parameter.

To determine the number of MIDI input devices present in the system, use the midiInGetNumDevs function. The device identifier specified by wDeviceID varies from zero to one less than the number of devices present.

If a window or thread is chosen to receive callback information, the following messages are sent to the window procedure or thread to indicate the progress of MIDI input: MM_MIM_OPEN, MM_MIM_CLOSE, MM_MIM_DATA, MM_MIM_LONGDATA, MM_MIM_ERROR, MM_MIM_LONGERROR, and MM_MIM_MOREDATA.

If a function is chosen to receive callback information, the following messages are sent to the function to indicate the progress of MIDI input: MIM_OPEN, MIM_CLOSE, MIM_DATA, MIM_LONGDATA, MIM_ERROR, MIM_LONGERROR, and MIM_MOREDATA.


midiInPrepareHeader

MMRESULT midiInPrepareHeader(HMIDIIN hMidiIn, LPMIDIHDR lpMidiInHdr,

    UINT cbMidiInHdr);

Prepares a buffer for MIDI input.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALHANDLE	The specified device handle is invalid.
MMSYSERR_INVALPARAM	The specified address is invalid.
MMSYSERR_NOMEM	The system is unable to allocate or lock memory.
hMidiIn

Handle of the MIDI input device.

lpMidiInHdr

Address of a MIDIHDR structure that identifies the buffer to be prepared.

cbMidiInHdr

Size, in bytes, of the MIDIHDR structure.

Preparing a header that has already been prepared has no effect, and the function returns zero.

Before using this function, you must set the lpData, dwBufferLength, and dwFlags members of the MIDIHDR structure. The dwFlags member must be set to zero.


MidiInProc

void CALLBACK MidiInProc(HMIDIIN hMidiIn, UINT wMsg, DWORD dwInstance,

    DWORD dwParam1, DWORD dwParam2);

Callback function for handling incoming MIDI messages. MidiInProc is a placeholder for the application-supplied function name.

hMidiIn

Handle of the MIDI input device.

wMsg

MIDI input message.

dwInstance

Instance data supplied with the midiInOpen function.

dwParam1 and dwParam2

Message parameters.

Applications should not call any system-defined functions from inside a callback function, except for PostMessage, timeGetSystemTime, timeGetTime, timeSetEvent, timeKillEvent, midiOutShortMsg, midiOutLongMsg, and OutputDebugStr.


midiInReset

MMRESULT midiInReset(HMIDIIN hMidiIn);

Stops input on a given MIDI input device.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALHANDLE	The specified device handle is invalid.
hMidiIn

Handle of the MIDI input device.

This function returns all pending input buffers to the callback function and sets the MHDR_DONE flag in the dwFlags member of the MIDIHDR structure.


midiInStart

MMRESULT midiInStart(HMIDIIN hMidiIn);

Starts MIDI input on the specified MIDI input device.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALHANDLE	The specified device handle is invalid.
hMidiIn

Handle of the MIDI input device.

This function resets the time stamp to zero; time stamp values for subsequently received messages are relative to the time that this function was called.

All messages except system-exclusive messages are sent directly to the client when they are received. System-exclusive messages are placed in the buffers supplied by the midiInAddBuffer function. If there are no buffers in the queue, the system-exclusive data is thrown away without notification to the client and input continues. Buffers are returned to the client when they are full, when a complete system-exclusive message has been received, or when the midiInReset function is used. The dwBytesRecorded member of the MIDIHDR structure will contain the actual length of data received.

Calling this function when input is already started has no effect, and the function returns zero.


midiInStop

MMRESULT midiInStop(HMIDIIN hMidiIn);

Stops MIDI input on the specified MIDI input device.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALHANDLE	The specified device handle is invalid.
hMidiIn

Handle of the MIDI input device.

If there are any system-exclusive messages or stream buffers in the queue, the current buffer is marked as done (the dwBytesRecorded member of the MIDIHDR structure will contain the actual length of data), but any empty buffers in the queue remain there and are not marked as done.

Calling this function when input is not started has no effect, and the function returns zero.


midiInUnprepareHeader

MMRESULT midiInUnprepareHeader(HMIDIIN hMidiIn, LPMIDIHDR lpMidiInHdr,

    UINT cbMidiInHdr);

Cleans up the preparation performed by the midiInPrepareHeader function.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MIDIERR_STILLPLAYING	The buffer pointed to by lpMidiInHdr is still in the queue.
MMSYSERR_INVALPARAM	The specified pointer or structure is invalid.
MMSYSERR_INVALHANDLE	The specified device handle is invalid.
hMidiIn

Handle of the MIDI input device.

lpMidiInHdr

Address of a MIDIHDR structure identifying the buffer to be cleaned up.

cbMidiInHdr

Size of the MIDIHDR structure.

This function is complementary to midiInPrepareHeader. You must use this function before freeing the buffer. After passing a buffer to the device driver by using the midiInAddBuffer function, you must wait until the driver is finished with the buffer before using midiInUnprepareHeader. Unpreparing a buffer that has not been prepared has no effect, and the function returns MMSYSERR_NOERROR.


midiOutCacheDrumPatches

MMRESULT midiOutCacheDrumPatches(HMIDIOUT hmo, UINT wPatch,

    WORD FAR* lpKeyArray, UINT wFlags);

Requests that an internal MIDI synthesizer device preload and cache a specified set of key-based percussion patches.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALFLAG	The flag specified by wFlags is invalid.
MMSYSERR_INVALHANDLE	The specified device handle is invalid.
MMSYSERR_INVALPARAM	The array pointed to by the lpKeyArray array is invalid.
MMSYSERR_NOMEM	The device does not have enough memory to cache all of the requested patches.
MMSYSERR_NOTSUPPORTED	The specified device does not support patch caching.
hmo

Handle of the opened MIDI output device. This device should be an internal MIDI synthesizer. This parameter can also be the handle of a MIDI stream, cast to HMIDIOUT.

wPatch

Drum patch number that should be used. This parameter should be set to zero to cache the default drum patch.

lpKeyArray

Address of a KEYARRAY array indicating the key numbers of the specified percussion patches to be cached or uncached.

wFlags

Options for the cache operation. It can be one of the following flags:

MIDI_CACHE_ALL

Caches all of the specified patches. If they cannot all be cached, it caches none, clears the KEYARRAY array, and returns MMSYSERR_NOMEM.

MIDI_CACHE_BESTFIT

Caches all of the specified patches. If they cannot all be cached, it caches as many patches as possible, changes the KEYARRAY array to reflect which patches were cached, and returns MMSYSERR_NOMEM.

MIDI_CACHE_QUERY

Changes the KEYARRAY array to indicate which patches are currently cached.

MIDI_UNCACHE

Uncaches the specified patches and clears the KEYARRAY array.

Some synthesizers are not capable of keeping all percussion patches loaded simultaneously. Caching patches ensures that the specified patches are available.

Each element of the KEYARRAY array represents one of the 128 key-based percussion patches and has bits set for each of the 16 MIDI channels that use the particular patch. The least-significant bit represents physical channel 0, and the most-significant bit represents physical channel 15. For example, if the patch on key number 60 is used by physical channels 9 and 15, element 60 would be set to 0x8200.

This function applies only to internal MIDI synthesizer devices. Not all internal synthesizers support patch caching. To see if a device supports patch caching, use the MIDICAPS_CACHE flag to test the dwSupport member of the MIDIOUTCAPS structure filled by the midiOutGetDevCaps function.


midiOutCachePatches

MMRESULT midiOutCachePatches(HMIDIOUT hmo, UINT wBank,

    WORD FAR* lpPatchArray, UINT wFlags);

Requests that an internal MIDI synthesizer device preload and cache a specified set of patches.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALFLAG	The flag specified by wFlags is invalid.
MMSYSERR_INVALHANDLE	The specified device handle is invalid.
MMSYSERR_INVALPARAM	The array pointed to by lpPatchArray is invalid.
MMSYSERR_NOMEM	The device does not have enough memory to cache all of the requested patches.
MMSYSERR_NOTSUPPORTED	The specified device does not support patch caching.
hmo

Handle of the opened MIDI output device. This device must be an internal MIDI synthesizer. This parameter can also be the handle of a MIDI stream, cast to HMIDIOUT.

wBank

Bank of patches that should be used. This parameter should be set to zero to cache the default patch bank.

lpPatchArray

Address of a PATCHARRAY array indicating the patches to be cached or uncached.

wFlags

Options for the cache operation. It can be one of the following flags:

MIDI_CACHE_ALL

Caches all of the specified patches. If they cannot all be cached, it caches none, clears the PATCHARRAY array, and returns MMSYSERR_NOMEM.

MIDI_CACHE_BESTFIT

Caches all of the specified patches. If they cannot all be cached, it caches as many patches as possible, changes the PATCHARRAY array to reflect which patches were cached, and returns MMSYSERR_NOMEM.

MIDI_CACHE_QUERY

Changes the PATCHARRAY array to indicate which patches are currently cached.

MIDI_UNCACHE

Uncaches the specified patches and clears the PATCHARRAY array.

Some synthesizers are not capable of keeping all patches loaded simultaneously and must load data from disk when they receive MIDI program change messages. Caching patches ensures that the specified patches are immediately available.

Each element of the PATCHARRAY array represents one of the 128 patches and has bits set for each of the 16 MIDI channels that use the particular patch. The least-significant bit represents physical channel 0, and the most-significant bit represents physical channel 15 (0x0F). For example, if patch 0 is used by physical channels 0 and 8, element 0 would be set to 0x0101.

This function applies only to internal MIDI synthesizer devices. Not all internal synthesizers support patch caching. To see if a device supports patch caching, use the MIDICAPS_CACHE flag to test the dwSupport member of the MIDIOUTCAPS structure filled by the midiOutGetDevCaps function.


midiOutClose

MMRESULT midiOutClose(HMIDIOUT hmo);

Closes the specified MIDI output device.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MIDIERR_STILLPLAYING	Buffers are still in the queue.
MMSYSERR_INVALHANDLE	The specified device handle is invalid.
MMSYSERR_NOMEM	The system is unable to load mapper string description.
hmo

Handle of the MIDI output device. If the function is successful, the handle is no longer valid after the call to this function.

If there are output buffers that have been sent by using the midiOutLongMsg function and have not been returned to the application, the close operation will fail. To mark all pending buffers as being done, use the midiOutReset function.


midiOutGetDevCaps

MMRESULT midiOutGetDevCaps(UINT uDeviceID, LPMIDIOUTCAPS lpMidiOutCaps,

    UINT cbMidiOutCaps);

Queries a specified MIDI output device to determine its capabilities.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_BADDEVICEID	The specified device identifier is out of range.
MMSYSERR_INVALPARAM	The specified pointer or structure is invalid.
MMSYSERR_NODRIVER	The driver is not installed.
MMSYSERR_NOMEM	The system is unable to load mapper string description.
uDeviceID

Identifier of the MIDI output device. The device identifier specified by this parameter varies from zero to one less than the number of devices present. The MIDI_MAPPER constant is also a valid device identifier.

This parameter can also be a properly cast device handle.

lpMidiOutCaps

Address of a MIDIOUTCAPS structure. This structure is filled with information about the capabilities of the device.

cbMidiOutCaps

Size, in bytes, of the MIDIOUTCAPS structure. Only cbMidiOutCaps bytes (or less) of information is copied to the location pointed to by lpMidiOutCaps. If cbMidiOutCaps is zero, nothing is copied, and the function returns MMSYSERR_NOERROR.

To determine the number of MIDI output devices present in the system, use the midiOutGetNumDevs function.


midiOutGetErrorText

UINT midiOutGetErrorText(MMRESULT mmrError, LPSTR lpText, UINT cchText);

Retrieves a textual description for an error identified by the specified error code.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_BADERRNUM	The specified error number is out of range.
MMSYSERR_INVALPARAM	The specified pointer or structure is invalid.
mmrError

Error code.

lpText

Address of a buffer to be filled with the textual error description.

cchText

Length, in characters, of the buffer pointed to by lpText.

If the textual error description is longer than the specified buffer, the description is truncated. The returned error string is always null-terminated. If cchText is zero, nothing is copied, and the function returns MMSYSERR_NOERROR. All error descriptions are less than MAXERRORLENGTH characters long.


midiOutGetID

MMRESULT midiOutGetID(HMIDIOUT hmo, LPUINT puDeviceID);

Retrieves the device identifier for the given MIDI output device.

This function is supported for backward compatibility. New applications can cast a handle of the device rather than retrieving the device identifier.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALHANDLE	The hwo parameter specifies an invalid handle.
MMSYSERR_NODRIVER	No device driver is present.
MMSYSERR_NOMEM	Unable to allocate or lock memory.
hmo

Handle of the MIDI output device.

puDeviceID

Address of a variable to be filled with the device identifier.


midiOutGetNumDevs

UINT midiOutGetNumDevs(VOID);

Retrieves the number of MIDI output devices present in the system.

•	Returns the number of MIDI output devices. A return value of zero means that there are no devices (not that there is no error).


midiOutGetVolume

MMRESULT midiOutGetVolume(HMIDIOUT hmo, LPDWORD lpdwVolume);

Retrieves the current volume setting of a MIDI output device.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALHANDLE	The specified device handle is invalid.
MMSYSERR_INVALPARAM	The specified pointer or structure is invalid.
MMSYSERR_NOMEM	The system is unable to allocate or lock memory.
MMSYSERR_NOTSUPPORTED	The function is not supported.
hmo

Handle of an open MIDI output device. This parameter can also contain the handle of a MIDI stream, as long as it is cast to HMIDIOUT.

lpdwVolume

Address of the location to contain the current volume setting. The low-order word of this location contains the left-channel volume setting, and the high-order word contains the right-channel setting. A value of 0xFFFF represents full volume, and a value of 0x0000 is silence.

If a device does not support both left and right volume control, the low-order word of the specified location contains the mono volume level.

Any value set by using the midiOutSetVolume function is returned, regardless of whether the device supports that value.

Not all devices support volume control. You can determine whether a device supports volume control by querying the device by using the midiOutGetDevCaps function and specifying the MIDICAPS_VOLUME flag.

You can also determine whether the device supports volume control on both the left and right channels by querying the device by using the midiOutGetDevCaps function and specifying the MIDICAPS_LRVOLUME flag.


midiOutLongMsg

MMRESULT midiOutLongMsg(HMIDIOUT hmo, LPMIDIHDR lpMidiOutHdr,

    UINT cbMidiOutHdr);

Sends a system-exclusive MIDI message to the specified MIDI output device.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MIDIERR_NOTREADY	The hardware is busy with other data.
MIDIERR_UNPREPARED	The buffer pointed to by lpMidiOutHdr has not been prepared.
MMSYSERR_INVALHANDLE	The specified device handle is invalid.
MMSYSERR_INVALPARAM	The specified pointer or structure is invalid.
hmo

Handle of the MIDI output device. This parameter can also be the handle of a MIDI stream cast to HMIDIOUT.

lpMidiOutHdr

Address of a MIDIHDR structure that identifies the MIDI buffer.

cbMidiOutHdr

Size, in bytes, of the MIDIHDR structure.

Before the buffer is passed to midiOutLongMsg, it must be prepared by using the midiOutPrepareHeader function. The MIDI output device driver determines whether the data is sent synchronously or asynchronously.


midiOutMessage

DWORD midiOutMessage(HMIDIOUT hmo, UINT msg, DWORD dw1, DWORD dw2);

Sends a message to the MIDI device drivers. This function is used only for driver-specific messages that are not supported by the MIDI API.

•	Returns the value returned by the audio device driver.

hmo

Handle of the MIDI device.  This parameter can also be the handle of a MIDI stream cast to HMIDIOUT.

msg

Message to send.

dw1 and dw2

Message parameters.


midiOutOpen

UINT midiOutOpen(LPHMIDIOUT lphmo, UINT uDeviceID,

    DWORD dwCallback, DWORD dwCallbackInstance, DWORD dwFlags);

Opens a MIDI output device for playback.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MIDIERR_NODEVICE	No MIDI port was found. This error occurs only when the mapper is opened.
MMSYSERR_ALLOCATED	The specified resource is already allocated.
MMSYSERR_BADDEVICEID	The specified device identifier is out of range.
MMSYSERR_INVALPARAM	The specified pointer or structure is invalid.
MMSYSERR_NOMEM	The system is unable to allocate or lock memory.
lphmo

Address of an HMIDIOUT handle. This location is filled with a handle identifying the opened MIDI output device. The handle is used to identify the device in calls to other MIDI output functions.

uDeviceID

Identifier of the MIDI output device that is to be opened.

dwCallback

Address of a callback function, an event handle, a thread identifier, or a handle of a window or thread called during MIDI playback to process messages related to the progress of the playback. If no callback is desired, specify NULL for this parameter.

dwCallbackInstance

User instance data passed to the callback. This parameter is not used with window callbacks or threads.

dwFlags

Callback flag for opening the device. It can be the following values:

CALLBACK_EVENT

The dwCallback parameter is an event handle. This callback mechanism is for output only.

CALLBACK_FUNCTION

The dwCallback parameter is a callback function address.

CALLBACK_NULL

There is no callback mechanism. This value is the default setting.

CALLBACK_THREAD

The dwCallback parameter is a thread identifier.

CALLBACK_WINDOW

The dwCallback parameter is a window handle.

To determine the number of MIDI output devices present in the system, use the midiOutGetNumDevs function. The device identifier specified by wDeviceID varies from zero to one less than the number of devices present. MIDI_MAPPER can also be used as the device identifier.

If a window or thread is chosen to receive callback information, the following messages are sent to the window procedure or thread to indicate the progress of MIDI output: MM_MOM_OPEN, MM_MOM_CLOSE, and MM_MOM_DONE.

If a function is chosen to receive callback information, the following messages are sent to the function to indicate the progress of MIDI output: MOM_OPEN, MOM_CLOSE, and MOM_DONE.


midiOutPrepareHeader

MMRESULT midiOutPrepareHeader(HMIDIOUT hmo, LPMIDIHDR lpMidiOutHdr,

    UINT cbMidiOutHdr);

Prepares a MIDI system-exclusive or stream buffer for output.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALHANDLE	The specified device handle is invalid.
MMSYSERR_INVALPARAM	The specified address is invalid or the given stream buffer is greater than 64K.
MMSYSERR_NOMEM	The system is unable to allocate or lock memory.
hmo

Handle of the MIDI output device. This parameter can also be the handle of a MIDI stream cast to HMIDIOUT.

lpMidiOutHdr

Address of a MIDIHDR structure that identifies the buffer to be prepared.

cbMidiOutHdr

Size, in bytes, of the MIDIHDR structure.

A stream buffer cannot be larger than 64K.

Preparing a header that has already been prepared has no effect, and the function returns MMSYSERR_NOERROR.

Before using this function, you must set the lpData, dwBufferLength, and dwFlags members of the MIDIHDR structure. The dwFlags member must be set to zero.


MidiOutProc

void CALLBACK MidiOutProc(HMIDIOUT hmo, UINT wMsg,

    DWORD dwInstance, DWORD dwParam1, DWORD dwParam2);

Callback function for handling outgoing MIDI messages. MidiOutProc is a placeholder for the application-supplied function name.

hmo

Handle of the MIDI device associated with the callback function.

wMsg

MIDI output message.

dwInstance

Instance data supplied by using the midiOutOpen function.

dwParam1 and dwParam2

Message parameters.

Applications should not call any system-defined functions from inside a callback function, except for PostMessage, timeGetSystemTime, timeGetTime, timeSetEvent, timeKillEvent, midiOutShortMsg, midiOutLongMsg, and OutputDebugStr.


midiOutReset

MMRESULT midiOutReset(HMIDIOUT hmo);

Turns off all notes on all MIDI channels for the specified MIDI output device.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALHANDLE	The specified device handle is invalid.
hmo

Handle of the MIDI output device. This parameter can also be the handle of a MIDI stream cast to HMIDIOUT.

Any pending system-exclusive or stream output buffers are returned to the callback function and the MHDR_DONE flag is set in the dwFlags member of the MIDIHDR structure.

Terminating a system-exclusive message without sending an EOX (end-of-exclusive) byte might cause problems for the receiving device. The midiOutReset function does not send an EOX byte when it terminates a system-exclusive message — applications are responsible for doing this.

To turn off all notes, a note-off message for each note in each channel is sent. In addition, the sustain controller is turned off for each channel.


midiOutSetVolume

MMRESULT midiOutSetVolume(HMIDIOUT hmo, DWORD dwVolume);

Sets the volume of a MIDI output device.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALHANDLE	The specified device handle is invalid.
MMSYSERR_NOMEM	The system is unable to allocate or lock memory.
MMSYSERR_NOTSUPPORTED	The function is not supported.
hmo

Handle of an open MIDI output device. This parameter can also contain the handle of a MIDI stream, as long as it is cast to HMIDIOUT.

dwVolume

New volume setting. The low-order word contains the left-channel volume setting, and the high-order word contains the right-channel setting. A value of 0xFFFF represents full volume, and a value of 0x0000 is silence.

If a device does not support both left and right volume control, the low-order word of dwVolume specifies the mono volume level, and the high-order word is ignored.

Changing the volume on a handle affects only one instance of the device. It does not change the default volume for the device (and affect all instances of the device).

Not all devices support volume changes. You can determine whether a device supports it by querying the device using the midiOutGetDevCaps function and the MIDICAPS_VOLUME flag.

You can also determine whether the device supports volume control on both the left and right channels by querying the device using the midiOutGetDevCaps function and the MIDICAPS_LRVOLUME flag.

Devices that do not support a full 16 bits of volume-level control use the high-order bits of the requested volume setting. For example, a device that supports 4 bits of volume control produces the same volume setting for the following volume-level values: 0x4000, 0x43be, and 0x4fff. The midiOutGetVolume function returns the full 16-bit value, as set by midiOutSetVolume, irrespective of the device's capabilities.

Volume settings are interpreted logarithmically. This means that the perceived increase in volume is the same when increasing the volume level from 0x5000 to 0x6000 as it is from 0x4000 to 0x5000.


midiOutShortMsg

MMRESULT midiOutShortMsg(HMIDIOUT hmo, DWORD dwMsg);

Sends a short MIDI message to the specified MIDI output device.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MIDIERR_BADOPENMODE	The application sent a message without a status byte to a stream handle.
MIDIERR_NOTREADY	The hardware is busy with other data.
MMSYSERR_INVALHANDLE	The specified device handle is invalid.
hmo

Handle of the MIDI output device. This parameter can also be the handle of a MIDI stream cast to HMIDIOUT.

dwMsg

MIDI message. The message is packed into a doubleword value with the first byte of the message in the low-order byte. The message is packed into this parameter as follows:

High word	High-order byte	Not used.
	Low-order byte	Contains a second byte of MIDI data (when needed).
Low word	High-order byte	Contains the first byte of MIDI data (when needed).
	Low-order byte	Contains the MIDI status.
The two MIDI data bytes are optional, depending on the MIDI status byte. When a series of messages have the same status byte, the status byte can be omitted from messages after the first one in the series, creating a running status. Pack a message for running status as follows:

High word	High-order byte	Not used.
	Low-order byte	Not used.
Low word	High-order byte	Contains a second byte of MIDI data (when needed).
	Low-order byte	Contains the first byte of MIDI data.
This function is used to send any MIDI message except for system-exclusive or stream messages.

This function might not return until the message has been sent to the output device. You can send short messages while streams are playing on the same device (although you cannot use a running status in this case).


midiOutUnprepareHeader

MMRESULT midiOutUnprepareHeader(HMIDIOUT hmo,

    LPMIDIHDR lpMidiOutHdr, UINT cbMidiOutHdr);

Cleans up the preparation performed by the midiOutPrepareHeader function.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MIDIERR_STILLPLAYING	The buffer pointed to by lpMidiOutHdr is still in the queue.
MMSYSERR_INVALHANDLE	The specified device handle is invalid.
MMSYSERR_INVALPARAM	The specified pointer or structure is invalid.
hmo

Handle of the MIDI output device. This parameter can also be the handle of a MIDI stream cast to HMIDIOUT.

lpMidiOutHdr

Address of a MIDIHDR structure identifying the buffer to be cleaned up.

cbMidiOutHdr

Size, in bytes, of the MIDIHDR structure.

This function is complementary to the midiOutPrepareHeader function. You must call midiOutUnprepareHeader before freeing the buffer. After passing a buffer to the device driver with the midiOutLongMsg function, you must wait until the device driver is finished with the buffer before calling midiOutUnprepareHeader.

Unpreparing a buffer that has not been prepared has no effect, and the function returns MMSYSERR_NOERROR.


midiStreamClose [New - Windows 95]
midiStreamClose

[New - Windows 95]

MMRESULT midiStreamClose(HMIDISTRM hStream);

Closes an open MIDI stream.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. You can use either the midiInGetErrorText or midiOutGetErrorText function to interpret error values for the stream functions. A possible error value is:

MMSYSERR_INVALHANDLE	The specified device handle is invalid.
hStream

Handle of a MIDI stream, as retrieved by using the midiStreamOpen function.


midiStreamOpen [New - Windows 95]
midiStreamOpen

[New - Windows 95]

MMRESULT midiStreamOpen(LPHMIDISTRM lphStream, LPUINT puDeviceID,

    DWORD cMidi, DWORD dwCallback, DWORD dwInstance, DWORD fdwOpen);

Opens a MIDI stream for output. By default, the device is opened in paused mode. The stream handle retrieved by this function must be used in all subsequent references to the stream.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. You can use the midiOutGetErrorText function to interpret error values for the stream functions. Possible error values include the following:

MMSYSERR_BADDEVICEID	The specified device identifier is out of range.
MMSYSERR_INVALPARAM	The given handle or flags parameter is invalid.
MMSYSERR_NOMEM	The system is unable to allocate or lock memory.
lphStream

Address of a variable to contain the stream handle when the function returns.

puDeviceID

Address of a device identifier. The device is opened on behalf of the stream and closed again when the stream is closed.

cMidi

Reserved; must be 1.

dwCallback

Address of a callback function, an event handle, a thread identifier, or a handle of a window or thread called during MIDI playback to process messages related to the progress of the playback. If no callback mechanism is desired, specify NULL for this parameter.

dwInstance

Application-specific instance data that is returned to the application with every callback function.

fdwOpen

Callback flag for opening the device. One of the following callback flags must be specified:

CALLBACK_EVENT

The dwCallback parameter is an event handle. This callback mechanism is for output only.

CALLBACK_FUNCTION

The dwCallback parameter is a callback procedure address.

CALLBACK_NULL

There is no callback mechanism. This is the default setting.

CALLBACK_THREAD

The dwCallback parameter is a thread identifier.

CALLBACK_WINDOW

The dwCallback parameter is a window handle.


midiStreamOut [New - Windows 95]
midiStreamOut

[New - Windows 95]

MMRESULT midiStreamOut(HMIDISTRM hMidiStream, LPMIDIHDR lpMidiHdr,

    UINT cbMidiHdr);

Plays or queues a stream (buffer) of MIDI data to a MIDI output device.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. You can use the midiOutGetErrorText function to interpret error values for the stream functions. Possible error values include the following:

MMSYSERR_NOMEM	The system is unable to allocate or lock memory.
MIDIERR_STILLPLAYING	The output buffer pointed to by lpMidiHdr is still playing or is queued from a previous call to midiStreamOut.
MIDIERR_UNPREPARED	The header pointed to by lpMidiHdr has not been prepared.
MMSYSERR_INVALHANDLE	The specified device handle is invalid.
MMSYSERR_INVALPARAM	The pointer specified by lpMidiHdr is invalid.
hMidiStream

Handle of a MIDI stream. This handle must have been returned by a call to the midiStreamOpen function. This handle identifies the output device.

lpMidiHdr

Address of a MIDIHDR structure that identifies the MIDI buffer.

cbMidiHdr

Size, in bytes, of the MIDIHDR structure.

Because the midiStreamOpen function opens the output device in paused mode, you must call the midiStreamRestart function before you can use midiStreamOut to start the playback.

For the current implementation of this function, the buffer must be smaller than 64K.

The buffer pointed to by the MIDIHDR structure contains one or more MIDI events, each of which is defined by a MIDIEVENT structure.


midiStreamPause [New - Windows 95]
midiStreamPause

[New - Windows 95]

MMRESULT midiStreamPause(HMIDISTRM hms);

Pauses playback of a specified MIDI stream.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. You can use the midiOutGetErrorText function to interpret error values for the stream functions. Possible error values include the following:

MMSYSERR_INVALHANDLE	The specified device handle is invalid.
hms

Handle of a MIDI stream. This handle must have been returned by a call to the midiStreamOpen function. This handle identifies the output device.

The current playback position is saved when playback is paused. To resume playback from the current position, use the midiStreamRestart function.

Calling this function when the output is already paused has no effect, and the function returns MMSYSERR_NOERROR.


midiStreamPosition [New - Windows 95]
midiStreamPosition

[New - Windows 95]

MMRESULT midiStreamPosition(HMIDISTRM hms, LPMMTIME pmmt, UINT cbmmt);

Retrieves the current position in a MIDI stream.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. You can use the midiOutGetErrorText function to interpret error values for the stream functions. Possible error values include the following:

MMSYSERR_INVALHANDLE	Specified device handle is invalid.
MMSYSERR_INVALPARAM	Specified pointer or structure is invalid.
hms

Handle of a MIDI stream. This handle must have been returned by a call to the midiStreamOpen function. This handle identifies the output device.

pmmt

Address of an MMTIME structure.

cbmmt

Size, in bytes, of the MMTIME structure.

Before calling midiStreamPosition, set the wType member of the MMTIME structure to indicate the time format you desire. After calling midiStreamPosition, check the wType member to determine if the desired time format is supported. If the desired format is not supported, wType will specify an alternative format.

The position is set to zero when the device is opened or reset.


midiStreamProperty [New - Windows 95]
midiStreamProperty

[New - Windows 95]

MMRESULT midiStreamProperty(HMIDISTRM hm, LPBYTE lppropdata,

    DWORD dwProperty);

Sets or retrieves properties of a MIDI data stream associated with a MIDI output device.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. You can use the midiOutGetErrorText function to interpret error values for the stream functions. Possible error values include the following:

MMSYSERR_INVALHANDLE	The specified handle is not a stream handle.
MMSYSERR_INVALPARAM	The given handle or flags parameter is invalid.
hm

Handle of the MIDI device that the property is associated with.

lppropdata

Address of the property data.

dwProperty

Flags that specify the action to perform and identify the appropriate property of the MIDI data stream. The midiStreamProperty function requires setting two flags in each use. One flag (either MIDIPROP_GET or MIDIPROP_SET) specifies an action, and the other identifies a specific property to examine or edit:

MIDIPROP_GET

Retrieves the current setting of the given property.

MIDIPROP_SET

Sets the given property.

MIDIPROP_TEMPO

Retrieves the tempo property. The lppropdata parameter points to a MIDIPROPTEMPO structure. The current tempo value can be retrieved at any time. Output devices set the tempo by inserting MEVT_TEMPO events into the MIDI data.

MIDIPROP_TIMEDIV

Specifies the time division property. You can get or set this property. The lppropdata parameter points to a MIDIPROPTIMEDIV structure. This property can be set only when the device is stopped.

These properties are the default properties defined by the system. Driver writers can implement and document their own properties.


midiStreamRestart [New - Windows 95]
midiStreamRestart

[New - Windows 95]

MMRESULT midiStreamRestart(HMIDISTRM hms);

Restarts a paused MIDI stream.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. You can use the midiOutGetErrorText function to interpret error values for the stream functions. Possible error values include the following:

MMSYSERR_INVALHANDLE	The specified device handle is invalid.
hms

Handle of a MIDI stream. This handle must have been returned by a call to the midiStreamOpen function. This handle identifies the output device.

Calling this function when the output is not paused has no effect, and the function returns MMSYSERR_NOERROR.


midiStreamStop [New - Windows 95]
midiStreamStop

[New - Windows 95]

MMRESULT midiStreamStop(HMIDISTRM hms);

Turns off all notes on all MIDI channels for the specified MIDI output device.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. You can use the midiOutGetErrorText function to interpret error values for the stream functions. Possible error values include the following:

MMSYSERR_INVALHANDLE	The specified device handle is invalid.
hms

Handle of a MIDI stream. This handle must have been returned by a call to the midiStreamOpen function. This handle identifies the output device.

When you call this function, any pending system-exclusive or stream output buffers are returned to the callback mechanism and the MHDR_DONE bit is set in the dwFlags member of the MIDIHDR structure.

While the midiOutReset function turns off all notes, midiStreamStop turns off only those notes that have been turned on by a MIDI note-on message.


MEVT_EVENTPARM

DWORD MEVT_EVENTPARM(DWORD dwEvent)

Retrieves the event parameters or length from the value specified in the dwEvent member of a MIDIEVENT structure.

dwEvent

Code for the MIDI event and the event parameters or length, as specified in the dwEvent member of the MIDIEVENT structure.

The MEVT_EVENTPARM macro is defined as follows:

#define MEVT_EVENTPARM(x) ((DWORD) ((x)&0x00FFFFFFL))


MEVT_EVENTTYPE

BYTE MEVT_EVENTTYPE(DWORD dwEvent)

Retrieves the event type from the value specified in the dwEvent member of a MIDIEVENT structure.

dwEvent

Code for the MIDI event and the event parameters or length, as specified in the dwEvent member of the MIDIEVENT structure.

The MEVT_EVENTTYPE macro is defined as follows:

#define MEVT_EVENTTYPE(x) ((BYTE) (((x)>>24)&0xFF))


KEYARRAY

typedef WORD KEYARRAY[MIDIPATCHSIZE];

Specifies a type used to define an array of keys. Each element in the array corresponds to a key-based percussion patch with each of the 16 bits representing one of the 16 MIDI channels. Bits are set for each of the channels that use that particular patch. For example, if the percussion patch for key number 60 is used by physical MIDI channels 9 and 15, element 60 of the array should be set to 0x8200.


MIDIEVENT

typedef struct {

    DWORD dwDeltaTime;  // see below

    DWORD dwStreamID;   // reserved; must be zero

    DWORD dwEvent;      // see below

    DWORD dwParms[];    // see below

} MIDIEVENT;

Describes a MIDI event in a stream buffer.

dwDeltaTime

Time, in MIDI ticks, between the previous event and the current event. The length of a tick is defined by the time format and possibly the tempo associated with the stream. (The definition is identical to the specification for a tick in a standard MIDI file.)

dwEvent

Event code and event parameters or length. To parse this information, use the MEVT_EVENTTYPE and MEVT_EVENTPARM macros.

The high byte of this member contains one or more of the following flags and an event code:

MEVT_F_CALLBACK

The system generates a callback when the event is about to be executed.

MEVT_F_LONG

The event is a long event. The low 24 bits of dwEvent contain the length of the event parameters.

MEVT_F_SHORT

The event is a short event. The event parameters are contained in the low 24 bits of dwEvent.

Either MEVT_F_LONG or MEVT_F_SHORT must be specified, but MEVT_F_CALLBACK is optional.

The remainder of the high byte contains one of the following event codes:

MEVT_COMMENT

Long event. The event data will be ignored. This event is intended to store commentary information about the stream that might be useful to authoring programs or sequencers if the stream data were to be stored in a file in stream format. In a buffer of this data, the zero byte identifies the comment class and subsequent bytes contain the comment data.

MEVT_LONGMSG

Long event. The event data is transmitted verbatim. The event data is assumed to be system-exclusive data; that is, running status will be cleared when the event is executed and running status from any previous events will not be applied to any channel events in the event data. Using this event to send a group of channel messages at the same time is not recommended; a set of MEVT_SHORTMSG events with zero delta times should be used instead.

MEVT_NOP

Short event. This event is a placeholder; it does nothing. The low 24 bits are ignored. This event will still generate a callback if MEVT_F_CALLBACK is set in dwEvent.

MEVT_SHORTMSG

Short event. The data in the low 24 bits of dwEvent is a MIDI short message. (For a description of how a short message is packed into a doubleword value, see the midiOutShortMsg function.)

MEVT_TEMPO

Short event. The data in the low 24 bits of dwEvent contain the new tempo for following events. The tempo is specified in the same format as it is for the tempo change meta-event in a MIDI file — that is, in microseconds per quarter note. (This event will have no affect if the time format specified for the stream is SMPTE time.)

MEVT_VERSION

Long event. The event data must contain a MIDISTRMBUFFVER structure.

dwParms

Parameters for the event, if dwEvent specifies MEVT_F_LONG and the length of the buffer. This parameter data must be padded with zeros so that an integral number of doubleword values are stored. For example, if the event data is five bytes long, three pad bytes must follow the data for a total of eight bytes. In this case, the low 24 bits of dwEvent would contain the value 5.


MIDIHDR

typedef struct {

    LPSTR  lpData;                    // address of MIDI data

    DWORD  dwBufferLength;            // size of the buffer

    DWORD  dwBytesRecorded;           // see below

    DWORD  dwUser;                    // custom user data

    DWORD  dwFlags;                   // see below

    struct midihdr_tag far * lpNext;  // reserved; do not use

    DWORD  reserved;                  // reserved; do not use

    DWORD  dwOffset;                  // see below

    DWORD  dwReserved[4];             // reserved; do not use

} MIDIHDR;

Defines the header used to identify a MIDI system-exclusive or stream buffer.

dwBytesRecorded

Actual amount of data in the buffer. This value should be less than or equal to the value given in the dwBufferLength member.

dwFlags

Flags giving information about the buffer.

MHDR_DONE

Set by the device driver to indicate that it is finished with the buffer and is returning it to the application.

MHDR_INQUEUE

Set by Windows to indicate that the buffer is queued for playback.

MHDR_ISSTRM

Set to indicate that the buffer is a stream buffer.

MHDR_PREPARED

Set by Windows to indicate that the buffer has been prepared by using the midiInPrepareHeader or midiOutPrepareHeader function.

dwOffset

Offset into the buffer when a callback is performed. (This callback is generated because the MEVT_F_CALLBACK flag is set in the dwEvent member of the MIDIEVENT structure.) This offset enables an application to determine which event caused the callback.


MIDIINCAPS

typedef struct {

    WORD      wMid;                  // see below

    WORD      wPid;                  // see below

    MMVERSION vDriverVersion;        // see below

    CHAR      szPname[MAXPNAMELEN];  // see below

    DWORD     dwSupport;             // reserved; must be zero

} MIDIINCAPS;

Describes the capabilities of a MIDI input device.

wMid

Manufacturer identifier of the device driver for the MIDI input device. For a list of identifiers, see Manufacturer and Product Identifiers.

wPid

Product identifier of the MIDI input device. For a list of identifiers, see Manufacturer and Product Identifiers.

vDriverVersion

Version number of the device driver for the MIDI input device. The high-order byte is the major version number, and the low-order byte is the minor version number.

szPname

Product name in a null-terminated string.


MIDIOUTCAPS

typedef struct {

    WORD      wMid;

    WORD      wPid;

    MMVERSION vDriverVersion;

    CHAR      szPname[MAXPNAMELEN];

    WORD      wTechnology;

    WORD      wVoices;

    WORD      wNotes;

    WORD      wChannelMask;

    DWORD     dwSupport;

} MIDIOUTCAPS;

Describes the capabilities of a MIDI output device.

wMid

Manufacturer identifier of the device driver for the MIDI output device. For a list of identifiers, see Chapter 0, "Manufacturer and Product Identifiers."

wPid

Product identifier of the MIDI output device. For a list of identifiers, see Chapter 0, "Manufacturer and Product Identifiers."

vDriverVersion

Version number of the device driver for the MIDI output device. The high-order byte is the major version number, and the low-order byte is the minor version number.

szPname

Product name in a null-terminated string.

wTechnology

Flags describing the type of the MIDI output device. It can be one of the following:

MOD_FMSYNTH

The device is an FM synthesizer.

MOD_MAPPER

The device is the Microsoft MIDI mapper.

MOD_MIDIPORT

The device is a MIDI hardware port.

MOD_SQSYNTH

The device is a square wave synthesizer.

MOD_SYNTH

The device is a synthesizer.

wVoices

Number of voices supported by an internal synthesizer device. If the device is a port, this member is not meaningful and is set to 0.

wNotes

Maximum number of simultaneous notes that can be played by an internal synthesizer device. If the device is a port, this member is not meaningful and is set to 0.

wChannelMask

Channels that an internal synthesizer device responds to, where the least significant bit refers to channel 0 and the most significant bit to channel 15. Port devices that transmit on all channels set this member to 0xFFFF.

dwSupport

Optional functionality supported by the device. It can be one or more of the following:

MIDICAPS_CACHE

Supports patch caching.

MIDICAPS_LRVOLUME

Supports separate left and right volume control.

MIDICAPS_STREAM

Provides direct support for the midiStreamOut function.

MIDICAPS_VOLUME

Supports volume control.

If a device supports volume changes, the MIDICAPS_VOLUME flag will be set for the dwSupport member. If a device supports separate volume changes on the left and right channels, both the MIDICAPS_VOLUME and the MIDICAPS_LRVOLUME flags will be set for this member.


MIDIPROPTEMPO

typedef struct {

    DWORD cbStruct;

    DWORD dwTempo;

} MIDIPROPTEMPO;

Contains the tempo property for a stream.

cbStruct

Length, in bytes, of this structure. This member must be filled in for both the MIDIPROP_SET and MIDIPROP_GET operations of the midiStreamProperty function.

dwTempo

Tempo of the stream, in microseconds per quarter note. The tempo is honored only if the time division for the stream is specified in quarter note format. This member is set in a MIDIPROP_SET operation and is filled on return from a MIDIPROP_GET operation.

The tempo property is read or written by the midiStreamProperty function.


MIDIPROPTIMEDIV

typedef struct {

    DWORD cbStruct;

    DWORD dwTimeDiv;

} MIDIPROPTIMEDIV;

Contains the time division property for a stream.

cbStruct

Length, in bytes, of this structure. This member must be filled in for both the MIDIPROP_SET and MIDIPROP_GET operations of the midiStreamProperty function.

dwTimeDiv

Time division for this stream, in the format specified in the Standard MIDI Files 1.0 specification. The low 16 bits of this doubleword value contain the time division. This member is set in a MIDIPROP_SET operation and is filled on return from a MIDIPROP_GET operation.

The time division property is read or written by the midiStreamProperty function.


MIDISTRMBUFFVER

typedef struct {

    DWORD dwVersion;

    DWORD dwMid;

    DWORD dwOEMVersion;

} MIDISTRMBUFFVER;

Contains version information for a long MIDI event of the MEVT_VERSION type.

dwVersion

Version of the stream. The high 16 bits contain the major version, and the low 16 bits contain the minor version. The version number for the first implementation of MIDI streams should be 1.0.

dwMid

Manufacturer identifier. For a list of manufacturer identifiers, see Chapter 0, "Manufacturer and Product Identifiers."

dwOEMVersion

OEM version of the stream. Original equipment manufacturers can use this field to version-stamp any custom events they have specified. If a custom event is specified, it must be the first event sent after the stream is opened.


PATCHARRAY

typedef WORD PATCHARRAY[MIDIPATCHSIZE];

Specifies a type used to define an array of MIDI patches. Each element in the array corresponds to a patch with each of the 16 bits representing one of the 16 MIDI channels. Bits are set for each of the channels that use that particular patch. For example, if patch number 0 is used by physical MIDI channels 0 and 8, element 0 of the array should be set to 0x0101.


MIM_CLOSE

MIM_CLOSE

dwParam1 = reserved

dwParam2 = reserved

Sent to a MIDI input callback function when a MIDI input device is closed.

•	No return value.

dwParam1 and dwParam2

Reserved; do not use.

The device handle is no longer valid after this message has been sent.


MIM_DATA

MIM_DATA

dwParam1 = dwMidiMessage

dwParam2 = dwTimestamp

Sent to a MIDI input callback function when a MIDI message is received by a MIDI input device.

•	No return value.

dwMidiMessage

MIDI message that was received. The message is packed into a doubleword value as follows:

High word	High-order byte	Not used.
	Low-order byte	Contains a second byte of MIDI data (when needed).
Low word	High-order byte	Contains the first byte of MIDI data (when needed).
	Low-order byte	Contains the MIDI status.
The two MIDI data bytes are optional, depending on the MIDI status byte.

dwTimestamp

Time that the message was received by the input device driver. The time stamp is specified in milliseconds, beginning at zero when the midiInStart function was called.

MIDI messages received from a MIDI input port have running status disabled; each message is expanded to include the MIDI status byte.

This message is not sent when a MIDI system-exclusive message is received.


MIM_ERROR

MIM_ERROR

dwParam1 = dwMidiMessage

dwParam2 = dwTimestamp

Sent to a MIDI input callback function when an invalid MIDI message is received.

•	No return value.

dwMidiMessage

Invalid MIDI message that was received. The message is packed into a doubleword value with the first byte of the message in the low-order byte.

dwTimestamp

Time that the message was received by the input device driver. The time stamp is specified in milliseconds, beginning at zero when the midiInStart function was called.


MIM_LONGDATA

MIM_LONGDATA

dwParam1 = (DWORD) lpMidiHdr

dwParam2 = dwTimestamp

Sent to a MIDI input callback function when a system-exclusive buffer has been filled with data and is being returned to the application.

•	No return value.

lpMidiHdr

Address of a MIDIHDR structure identifying the input buffer.

dwTimestamp

Time that the data was received by the input device driver. The time stamp is specified in milliseconds, beginning at zero when the midiInStart function was called.

The returned buffer might not be full. To determine the number of bytes recorded into the returned buffer, use the dwBytesRecorded member of the MIDIHDR structure specified by lpMidiHdr.


MIM_LONGERROR

MIM_LONGERROR

dwParam1 = (DWORD) lpMidiHdr

dwParam2 = dwTimestamp

Sent to a MIDI input callback function when an invalid or incomplete MIDI system-exclusive message is received.

•	No return value.

lpMidiHdr

Address of a MIDIHDR structure identifying the buffer containing the invalid message.

dwTimestamp

Time that the data was received by the input device driver. The time stamp is specified in milliseconds, beginning at zero when the midiInStart function was called.

The returned buffer might not be full. To determine the number of bytes recorded into the returned buffer, use the dwBytesRecorded member of the MIDIHDR structure specified by lpMidiHdr.


MIM_MOREDATA

MIM_MOREDATA

dwParam1 = dwMidiMessage

dwParam2 = dwTimestamp

Sent to a MIDI input callback function when a MIDI message is received by a MIDI input device but the application is not processing MIM_DATA messages fast enough to keep up with the input device driver. The callback function receives this message only when the application specifies MIDI_IO_STATUS in the call to the midiInOpen function.

•	No return value.

dwMidiMessage

Specifies the MIDI message that was received. The message is packed into a doubleword value as follows:

High word	High-order byte	Not used.
	Low-order byte	Contains a second byte of MIDI data (when needed).
Low word	High-order byte	Contains the first byte of MIDI data (when needed).
	Low-order byte	Contains the MIDI status.
The two MIDI data bytes are optional, depending on the MIDI status byte.

dwTimestamp

Specifies the time that the message was received by the input device driver. The time stamp is specified in milliseconds, beginning at 0 when the midiInStart function was called.

An application should do only a minimal amount of processing of MIM_MOREDATA messages. (In particular, applications should not call the PostMessage function while processing MIM_MOREDATA.) Instead, the application should place the event data into a buffer and then return.

When an application receives an MIM_DATA message after a series of MIM_MOREDATA messages, it has caught up with incoming MIDI events and can safely call time-intensive functions.

MIDI messages received from a MIDI input port have running status disabled; each message is expanded to include the MIDI status byte.

This message is not sent when a MIDI system-exclusive message is received.


MIM_OPEN

MIM_OPEN

dwParam1 = reserved

dwParam2 = reserved

Sent to a MIDI input callback function when a MIDI input device is opened.

•	No return value.

dwParam1 and dwParam2

Reserved; do not use.


MM_MIM_CLOSE

MM_MIM_CLOSE

wParam = (WPARAM) hInput

lParam = reserved

Sent to a window when a MIDI input device is closed.

•	No return value.

hInput

Handle of the MIDI input device that was closed.

lParam

Reserved; do not use.

The device handle is no longer valid after this message has been sent.


MM_MIM_DATA

MM_MIM_DATA

wParam = (WPARAM) hInput

lParam = (LPARAM) (DWORD) lMidiMessage

Sent to a window when a complete MIDI message is received by a MIDI input device.

•	No return value.

hInput

Handle of the MIDI input device that received the MIDI message.

lMidiMessage

MIDI message that was received. The message is packed into a doubleword value as follows:

High word	High-order byte	Not used.
	Low-order byte	Contains a second byte of MIDI data (when needed).
Low word	High-order byte	Contains the first byte of MIDI data (when needed).
	Low-order byte	Contains the MIDI status.
The two MIDI data bytes are optional, depending on the MIDI status byte.

MIDI messages received from a MIDI input port have running status disabled; each message is expanded to include the MIDI status byte.

This message is not sent when a MIDI system-exclusive message is received. No time stamp is available with this message. For time-stamped input data, you must use the messages that are sent to callback functions.


MM_MIM_ERROR

MM_MIM_ERROR

wParam = (WPARAM) hInput

lParam = (LPARAM) (DWORD) lMidiMessage

Sent to a window when an invalid MIDI message is received.

•	No return value.

hInput

Handle of the MIDI input device that received the invalid message.

lMidiMessage

Invalid MIDI message. The message is packed into a doubleword value with the first byte of the message in the low-order byte.


MM_MIM_LONGDATA

MM_MIM_LONGDATA

wParam = (WPARAM) hInput

lParam = (LPARAM) lpMidiHdr

Sent to a window when either a complete MIDI system-exclusive message is received or when a buffer has been filled with system-exclusive data.

•	No return value.

hInput

Handle of the MIDI input device that received the data.

lpMidiHdr

Address of a MIDIHDR structure identifying the buffer.

The returned buffer might not be full. To determine the number of bytes recorded into the returned buffer, use the dwBytesRecorded member of the MIDIHDR structure pointed to by lpMidiHdr.

No time stamp is available with this message. For time-stamped input data, you must use the messages that are sent to callback functions.


MM_MIM_LONGERROR

MM_MIM_LONGERROR

wParam = (WPARAM) hInput

lParam = (LPARAM) lpMidiHdr

Sent to a window when an invalid or incomplete MIDI system-exclusive message is received.

•	No return value.

hInput

Handle of the MIDI input device that received the invalid message.

lpMidiHdr

Address of a MIDIHDR structure identifying the buffer containing the invalid message.

The returned buffer might not be full. To determine the number of bytes recorded into the returned buffer, use the dwBytesRecorded member of the MIDIHDR structure specified by lpMidiHdr.


MM_MIM_MOREDATA

MM_MIM_MOREDATA

wParam = (WPARAM) hInput

lParam = (LPARAM) (DWORD) lMidiMessage

Sent to a callback window when a MIDI message is received by a MIDI input device but the application is not processing MIM_DATA messages fast enough to keep up with the input device driver. The window receives this message only when the application specifies MIDI_IO_STATUS in the call to the midiInOpen function.

•	No return value.

hInput

Handle of the MIDI input device that received the MIDI message.

lMidiMessage

Specifies the MIDI message that was received. The message is packed into a doubleword value as follows:

High word	High-order byte	Not used.
	Low-order byte	Contains a second byte of MIDI data (when needed).
Low word	High-order byte	Contains the first byte of MIDI data (when needed).
	Low-order byte	Contains the MIDI status.
The two MIDI data bytes are optional, depending on the MIDI status byte.

If your application will receive MIDI data faster than it can process it, you should not use a window callback mechanism. To maximize speed, use a callback function, and use the MIM_MOREDATA message instead of MM_MIM_MOREDATA.

An application should do only a minimal amount of processing of MM_MIM_MOREDATA messages. (In particular, applications should not call the PostMessage function while processing MM_MIM_MOREDATA.) Instead, the application should place the event data into a buffer and then return.

When an application receives an MM_MIM_DATA message after a series of MM_MIM_MOREDATA messages, it has caught up with incoming MIDI events and can safely call time-intensive functions.

MIDI messages received from a MIDI input port have running status disabled; each message is expanded to include the MIDI status byte.

This message is not sent when a MIDI system-exclusive message is received. No time stamp is available with this message. For time-stamped input data, you must use the messages that are sent to callback functions.


MM_MIM_OPEN

MM_MIM_OPEN

wParam = (WPARAM) hInput

lParam = reserved

Sent to a window when a MIDI input device is opened.

•	No return value.

hInput

Handle of the MIDI input device that was opened.

lParam

Reserved; do not use.


MM_MOM_CLOSE

MM_MOM_CLOSE

wParam = (WPARAM) hOutput

lParam = reserved

Sent to a window when a MIDI output device is closed.

•	No return value.

hOutput

Handle of the MIDI output device.

lParam

Reserved; do not use.

The device handle is no longer valid after this message has been sent.


MM_MOM_DONE

MM_MOM_DONE

wParam = (WPARAM) hOutput

lParam = (LPARAM) lpMidiHdr

Sent to a window when the specified MIDI system-exclusive or stream buffer has been played and is being returned to the application.

•	No return value.

hOutput

Handle of the MIDI output device that played the buffer.

lpMidiHdr

Address of a MIDIHDR structure identifying the buffer.


MM_MOM_OPEN

MM_MOM_OPEN

wParam = (WPARAM) hOutput

lParam = reserved

Sent to a window when a MIDI output device is opened.

•	No return value.

hOutput

Handle of the MIDI output device.

lParam

Reserved; do not use.


MM_MOM_POSITIONCB

MM_MOM_POSITIONCB

wParam = (WPARAM) lpMidiHdr

lParam = reserved

Sent to a window when an MEVT_F_CALLBACK event is reached in the MIDI output stream.

•	No return value.

lpMidiHdr

Address of a MIDIHDR structure that identifies the event that caused the callback. The dwOffset member gives the offset of the event.

lParam

Reserved; do not use.

Playback of the stream buffer continues even while the callback function is executing. Any events after the MEVT_F_CALLBACK event in the buffer will be scheduled and sent on time regardless of how much time is spent in the callback function.

If position callbacks are being generated more quickly than your application can process them, the dwOffset member of the MIDIHDR structure might refer to an event your application has not yet processed.


MOM_CLOSE

MOM_CLOSE

dwParam1 = reserved

dwParam2 = reserved

Sent to a MIDI output callback function when a MIDI output device is closed.

•	No return value.

dwParam1 and dwParam2

Reserved; do not use.

The device handle is no longer valid after this message has been sent.


MOM_DONE

MOM_DONE

dwParam1 = (DWORD) lpMidiHdr

dwParam2 = reserved

Sent to a MIDI output callback function when the specified system-exclusive or stream buffer has been played and is being returned to the application.

•	No return value.

lpMidiHdr

Address of a MIDIHDR structure identifying the buffer.

dwParam2

Reserved; do not use.


MOM_OPEN

MOM_OPEN

dwParam1 = reserved

dwParam2 = reserved

Sent to a MIDI output callback function when a MIDI output device is opened.

•	No return value.

dwParam1 and dwParam2

Reserved; do not use.


MOM_POSITIONCB

MOM_POSITIONCB

dwParam1 = (DWORD) hOutput

dwParam2 = (DWORD) lpMidiHdr

Sent to a window when a MEVT_F_CALLBACK event is reached in the MIDI output stream.

•	No return value.

hOutput

Handle of the MIDI output device.

lpMidiHdr

Address of a MIDIHDR structure that identifies the event that caused the callback function. The dwOffset member gives the offset of the event.

Playback of the stream buffer continues even while the callback function is executing. Any events after the MEVT_F_CALLBACK event in the buffer will be scheduled and sent on time regardless of how much time is spent in the callback function.

If position callbacks are being generated more quickly than your application can process them, the dwOffset member of the MIDIHDR structure might refer to an event your application has not yet processed.


Audio Mixers

Audio mixer services control the routing of audio lines to a destination device for playing or recording. These services can also control volume and other effects. Many of the techniques required to use these services are similar to those for audio devices discussed in other chapters. This section presents general information about using audio mixer services.


Mixer Architecture

The basic element of the mixer architecture is an audio line. An audio line consists of one or more channels of data originating from a single source or a system resource. For example, a stereo audio line has two data channels, but it is considered a single audio line because it originates from a single source.

The mixer architecture provides routing services to manage audio lines on a computer. You can use the routing services if you have adequate hardware devices and software drivers installed. The mixer architecture allows several audio source lines to map to a single destination audio line.

Each audio line can have mixer controls associated with it. A mixer control can perform any number of functions (such as control volume), depending on the characteristics of the associated audio line.


Control Types

The mixer services include the following classes of standard controls to associate with audio lines:

•	Custom controls

•	Faders

•	Lists

•	Meters

•	Numbers

•	Sliders

•	Switches

•	Time controls


Audio Mixer Custom Controls

Custom controls are the most generic. This control allows a mixer driver to define the control's characteristics, and by implication, the visual representation of the control.


Faders

The fader controls are typically vertical controls that can be adjusted up or down. These controls have a linear scale and use the MIXERCONTROLDETAILS_UNSIGNED structure to retrieve and set control details. Types of faders include the following:

Control	Description
Fader	General fade control. The range of acceptable values is 0 through 65,535.
Volume	General volume fade control. The range of acceptable values is 0 through 65,535. For information about changing this range, see the documentation for your mixer device.
Bass	Bass volume fade control. The range of acceptable values is 0 through 65,535. The limits of the bass frequency band are hardware specific. For information about band limits, see the documentation for your mixer device.
Treble	Treble volume fade control. The range of acceptable values is 0 through 65,535. The limits of the treble frequency band are hardware specific. For information about the band limits, see the documentation for your mixer device.
Equalizer	Graphic equalizer control. The range of acceptable values for one band of the equalizer is 0 through 65,535. The number of equalizer bands and their limits are hardware specific. For information about the equalizer, see the documentation for your mixer device. You can use the MIXERCONTROLDETAILS_LISTTEXT structure to retrieve text labels for the equalizer.


Lists

The list controls provide single-select or multiple-select states for complex audio lines. These controls use the MIXERCONTROLDETAILS_BOOLEAN structure to retrieve and set control properties. The MIXERCONTROLDETAILS_LISTTEXT structure is also used to retrieve all text descriptions of a multiple-item control. Types of list controls include the following:

Control	Description
Single-select	Restricts the control selection to one item at a time. Unlike the multiplexer control, this control can be used to control more than audio source lines. For example, you could use this control to select a low-pass filter from a list of filters supported by a mixer device.
Multiplexer (MUX)	Restricts the line selection to one source line at a time.
Multiple-select	Allows the user to select multiple items from a list simultaneously. Unlike the mixer control, the multiple-select control can be used to control more than audio source lines.
Mixer	Allows the user to select source lines from a list simultaneously.


Meters

The meter controls measure data passing through an audio line. These controls use the MIXERCONTROLDETAILS_BOOLEAN, MIXERCONTROLDETAILS_SIGNED, and MIXERCONTROLDETAILS_UNSIGNED structures to retrieve and set control properties. Types of meters include the following:

Control	Description
Boolean	Measures whether an integer value is FALSE/OFF (zero) or TRUE/ON (nonzero).
Peak	Measures the deflection from 0 in both the positive and negative directions. The range of integer values for the peak meter is − 32,768 through 32,767.
Signed	Measures integer values in the range of − 2 (31)  through (2 (31)  −  1). The mixer driver defines the limits of this meter.
Unsigned	Measures integer values in the range of 0 through (2 (32)  −  1). The mixer driver defines the limits of this meter.


Numbers

The number controls allow the user to enter numerical data associated with a line. The numerical data is expressed as signed integers, unsigned integers, or integer decibel values. These controls use the MIXERCONTROLDETAILS_SIGNED and MIXERCONTROLDETAILS_UNSIGNED structures to retrieve and set control properties. Types of number controls include the following:

Control	Description
Signed	Allows integer values entered in the range of  − 2 (31)  through (2 (31)  −  1).
Unsigned	Allows integer values entered in the range of 0 through (2 (32)  −  1).
Decibel	Allows integer decibel values to be entered, in tenths of decibels. The range of values for this control is − 32,768 through 32,767.
Percent	Allows values to be entered as percentages.


Sliders

The slider controls are typically horizontal controls that can be adjusted to the left or right. These controls use the MIXERCONTROLDETAILS_SIGNED structure to retrieve and set control properties. Types of sliders include the following:

Control	Description
Slider	Has a range of  − 32,768 through 32,767. The mixer driver defines the limits of this control.
Pan	Has a range of −32,768 through 32,767. The mixer driver defines the limits of this control, with 0 as the midrange value.
QSound® Pan	Provides expanded sound control through QSound. This control has a range of −15 through 15.


Switches

The switch controls are two-state switches. These controls use the MIXERCONTROLDETAILS_BOOLEAN structure to retrieve and set control properties. Types of switches include the following:

Control	Description
Boolean	The generic switch. It can be set to TRUE or FALSE.
Button	Set to TRUE for all buttons in an application that the driver should handle as though they had been pressed. If the value is FALSE, no action is taken.
On/Off	An alternative switch that is represented by a different graphic than the Boolean switch. It can be set to ON or OFF.
Mute	Mutes an audio line (suppressing the data flow of the line) or allows the audio data to play. This switch is frequently used to help control the lines feeding into the mixer.
Mono	Switches between mono and stereo output for a stereo audio line. Set to OFF to play stereo data as separate channels. Set to ON to combine data from both channels into a mono audio line.
Loudness	Boosts low-volume bass for an audio line. Set to ON to boost low-volume bass. Set to OFF to set volume levels to normal. The amount of boost is hardware specific. For more information, see the documentation for your mixer device.
Stereo Enhanced	Increases stereo separation. Set to ON to increase stereo separation. Set to OFF for no enhancement.


Time Controls

The time controls allow the user to enter timing-related data, such as an echo delay or reverberation. The time data is expressed as positive integers. Types of time controls include the following:

Control	Description
Microsecond	Supports timing data expressed in microseconds. The range of acceptable values is 0 through (2 (32)  −1).
Millisecond	Supports timing data expressed in milliseconds. The range of acceptable values is 0 through (2 (32)  −1).


Mixer Device Queries

The mixer services provide functions for determining the number of mixer devices present in the system and the capabilities of the devices. You can also use a mixer services function to determine the device identifier for a mixer device.

You can use the mixerGetNumDevs function to determine how many mixer devices are present in the system. Mixer devices are identified by a device identifier. Device identifiers are determined implicitly from the number of devices present in a given system. They range from zero through one less than the number of devices present.

Before using a mixer device, you must determine its capabilities. Audio capabilities can vary from one multimedia computer to another, so applications should not make assumptions about audio hardware.

You can use the mixerGetDevCaps function to determine the capabilities of mixer devices. This function fills a MIXERCAPS structure with information about the capabilities of a specified device.

The mixerGetID function retrieves the audio mixer device identifier associated with a specified device handle. For example, you could use this function to retrieve the device identifier for an audio mixer and then use the device identifier to adjust the volume or to display another control.


Opening and Closing Mixer Devices

When you want to use a mixer device, you can either simply begin using it or you can explicitly open the device before using it. Explicitly opening a mixer device offers two main benefits:

•	It guarantees the continued existence of that mixer device.

•	It lets you receive notification of audio line and control changes.

You can use the mixerOpen function to explicitly open a mixer device. This function takes as parameters a device identifier, a pointer to a memory location, and other values unique to each type of device. The memory location is filled with a device handle. Use this device handle to identify the open mixer device when calling other audio mixer functions. As long as a handle of a mixer device exists, the device continues to exist in the system. If a configuration change occurs to the mixer device and it hasn't been explicitly opened, your application might suddenly be unable to access it.

Note  The difference between device identifiers and device handles is important. Device handles are returned when you open a device driver by using mixerOpen. Device identifiers are determined implicitly from the number of devices present in a system, which is obtained by using the mixerGetNumDevs function.

You can use the mixerClose function to close a mixer device. You should close the device after you finish using it.


Window Callback Services

The mixer services provide window callback services so that your application can process messages from mixer drivers. To use these services, specify the CALLBACK_WINDOW flag in the fdwOpen parameter and a window handle in the dwCallback parameter of the mixerOpen function. Driver messages are sent to the window procedure function for the window identified by the handle in dwCallback. The messages are specific to the audio device type.


Audio Line and Control Queries

The mixer services provide functions for determining information about audio lines, audio line controls, and control details. The services also provide functions for setting control details.

You can use the mixerGetLineInfo function to retrieve information about a specified audio line. This function fills the MIXERLINE structure for a specified source audio line, destination audio line, or line identifier. The structure includes the destination line number, the number of channels in the audio line, as well as a short and a long name for the audio line.

The mixerGetLineControls function retrieves general information about one or more controls associated with an audio line. This function fills the MIXERLINECONTROLS structure with information about the specified control or controls. You can use mixerGetLineControls to retrieve control properties for one of the following:

•	All controls for a specified source line

•	Specified control for a specified source line

•	First control of a specific class for a specified source line

The mixerGetControlDetails function retrieves properties of a single control associated with an audio line. This function fills the MIXERCONTROLDETAILS structure with the current values for a control.

The mixerSetControlDetails function uses the contents of the MIXERCONTROLDETAILS structure to set the properties of the specified control. You must ensure all members of this structure are filled before you call mixerSetControlDetails.


Audio Mixer Reference

This section describes the functions, structures, and messages associated with audio mixers. These elements are grouped as follows.

Querying Devices

MIXERCAPS
mixerGetDevCaps
mixerGetNumDevs

Opening and Closing

mixerClose
mixerOpen

Retrieving Mixer Identifiers

mixerGetID

Retrieving Line Controls

MIXERCONTROL
mixerGetLineControls
MIXERLINECONTROLS

Changing Control Attributes

MIXERCONTROLDETAILS
MIXERCONTROLDETAILS_BOOLEAN
MIXERCONTROLDETAILS_LISTTEXT
MIXERCONTROLDETAILS_SIGNED
MIXERCONTROLDETAILS_UNSIGNED
mixerGetControlDetails
mixerSetControlDetails

Retrieving Line Information

mixerGetLineInfo
MIXERLINE
MM_MIXM_CONTROL_CHANGE
MM_MIXM_LINE_CHANGE

Sending User-Defined Messages

mixerMessage


mixerClose

MMRESULT mixerClose(HMIXER hmx);

Closes the specified mixer device.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_INVALHANDLE	Specified device handle is invalid.
hmx

Handle of the mixer device. This handle must have been returned successfully by the mixerOpen function. If mixerClose is successful, hmx is no longer valid.


mixerGetControlDetails

MMRESULT mixerGetControlDetails(HMIXEROBJ hmxobj,
    LPMIXERCONTROLDETAILS pmxcd, DWORD fdwDetails);

Retrieves details about a single control associated with an audio line.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MIXERR_INVALCONTROL	The control reference is invalid.
MMSYSERR_BADDEVICEID	The hmxobj parameter specifies an invalid device identifier.
MMSYSERR_INVALFLAG	One or more flags are invalid.
MMSYSERR_INVALHANDLE	The hmxobj parameter specifies an invalid handle.
MMSYSERR_INVALPARAM	One or more parameters are invalid.
MMSYSERR_NODRIVER	No mixer device is available for the object specified by hmxobj.
hmxobj

Handle of the mixer device object being queried.

pmxcd

Address of a MIXERCONTROLDETAILS structure, which is filled with state information about the control.

fdwDetails

Flags for retrieving control details. The following values are defined:

MIXER_GETCONTROLDETAILSF_LISTTEXT

The paDetails member of the MIXERCONTROLDETAILS structure points to one or more MIXERCONTROLDETAILS_LISTTEXT structures to receive text labels for multiple-item controls. An application must get all list text items for a multiple-item control at once. This flag cannot be used with MIXERCONTROL_CONTROLTYPE_CUSTOM controls.

MIXER_GETCONTROLDETAILSF_VALUE

Current values for a control are retrieved. The paDetails member of the MIXERCONTROLDETAILS structure points to one or more details structures appropriate for the control class.

MIXER_OBJECTF_AUX

The hmxobj parameter is an auxiliary device identifier in the range of zero to one less than the number of devices returned by the auxGetNumDevs function.

MIXER_OBJECTF_HMIDIIN

The hmxobj parameter is the handle of a MIDI (Musical Instrument Digital Interface) input device. This handle must have been returned by the midiInOpen function.

MIXER_OBJECTF_HMIDIOUT

The hmxobj parameter is the handle of a MIDI output device. This handle must have been returned by the midiOutOpen function.

MIXER_OBJECTF_HMIXER

The hmxobj parameter is a mixer device handle returned by the mixerOpen function. This flag is optional.

MIXER_OBJECTF_HWAVEIN

The hmxobj parameter is a waveform-audio input handle returned by the waveInOpen function.

MIXER_OBJECTF_HWAVEOUT

The hmxobj parameter is a waveform-audio output handle returned by the waveOutOpen function.

MIXER_OBJECTF_MIDIIN

The hmxobj parameter is the identifier of a MIDI input device. This identifier must be in the range of zero to one less than the number of devices returned by the midiInGetNumDevs function.

MIXER_OBJECTF_MIDIOUT

The hmxobj parameter is the identifier of a MIDI output device. This identifier must be in the range of zero to one less than the number of devices returned by the midiOutGetNumDevs function.

MIXER_OBJECTF_MIXER

The hmxobj parameter is the identifier of a mixer device in the range of zero to one less than the number of devices returned by the mixerGetNumDevs function. This flag is optional.

MIXER_OBJECTF_WAVEIN

The hmxobj parameter is the identifier of a waveform-audio input device in the range of zero to one less than the number of devices returned by the waveInGetNumDevs function.

MIXER_OBJECTF_WAVEOUT

The hmxobj parameter is the identifier of a waveform-audio output device in the range of zero to one less than the number of devices returned by the waveOutGetNumDevs function.

All members of the MIXERCONTROLDETAILS structure must be initialized before calling this function.


mixerGetDevCaps

MMRESULT mixerGetDevCaps(UINT uMxId, LPMIXERCAPS pmxcaps,
    UINT cbmxcaps);

Queries a specified mixer device to determine its capabilities.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_BADDEVICEID	The specified device identifier is out of range.
MMSYSERR_INVALHANDLE	The mixer device handle is invalid.
MMSYSERR_INVALPARAM	One or more parameters are invalid.
uMxId

Identifier or handle of an open mixer device.

pmxcaps

Address of a MIXERCAPS structure that receives information about the capabilities of the device.

cbmxcaps

Size, in bytes, of the MIXERCAPS structure.

Use the mixerGetNumDevs function to determine the number of mixer devices present in the system. The device identifier specified by uMxId varies from zero to one less than the number of mixer devices present.

Only the number of bytes (or less) of information specified in cbmxcaps is copied to the location pointed to by pmxcaps. If cbmxcaps is zero, nothing is copied, and the function returns successfully.

This function also accepts a mixer device handle returned by the mixerOpen function as the uMxId parameter. The application should cast the HMIXER handle to a UINT.


mixerGetID

MMRESULT mixerGetID(HMIXEROBJ hmxobj, UINT FAR * puMxId, DWORD fdwId);

Retrieves the device identifier for a mixer device associated with a specified device handle.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_BADDEVICEID	The hmxobj parameter specifies an invalid device identifier.
MMSYSERR_INVALFLAG	One or more flags are invalid.
MMSYSERR_INVALHANDLE	The hmxobj parameter specifies an invalid handle.
MMSYSERR_INVALPARAM	One or more parameters are invalid.
MMSYSERR_NODRIVER	No audio mixer device is available for the object specified by hmxobj. The location referenced by puMxId also contains the value −1.
hmxobj

Handle of the audio mixer object to map to a mixer device identifier.

puMxId

Address of a variable that receives the mixer device identifier. If no mixer device is available for the hmxobj object, the value − 1 is placed in this location and the MMSYSERR_NODRIVER error value is returned.

fdwId

Flags for mapping the mixer object hmxobj. The following values are defined:

MIXER_OBJECTF_AUX

The hmxobj parameter is an auxiliary device identifier in the range of zero to one less than the number of devices returned by the auxGetNumDevs function.

MIXER_OBJECTF_HMIDIIN

The hmxobj parameter is the handle of a MIDI input device. This handle must have been returned by the midiInOpen function.

MIXER_OBJECTF_HMIDIOUT

The hmxobj parameter is the handle of a MIDI output device. This handle must have been returned by the midiOutOpen function.

MIXER_OBJECTF_HMIXER

The hmxobj parameter is a mixer device handle returned by the mixerOpen function. This flag is optional.

MIXER_OBJECTF_HWAVEIN

The hmxobj parameter is a waveform-audio input handle returned by the waveInOpen function.

MIXER_OBJECTF_HWAVEOUT

The hmxobj parameter is a waveform-audio output handle returned by the waveOutOpen function.

MIXER_OBJECTF_MIDIIN

The hmxobj parameter is the identifier of a MIDI input device. This identifier must be in the range of zero to one less than the number of devices returned by the midiInGetNumDevs function.

MIXER_OBJECTF_MIDIOUT

The hmxobj parameter is the identifier of a MIDI output device. This identifier must be in the range of zero to one less than the number of devices returned by the midiOutGetNumDevs function.

MIXER_OBJECTF_MIXER

The hmxobj parameter is the identifier of a mixer device in the range of zero to one less than the number of devices returned by the mixerGetNumDevs function. This flag is optional.

MIXER_OBJECTF_WAVEIN

The hmxobj parameter is the identifier of a waveform-audio input device in the range of zero to one less than the number of devices returned by the waveInGetNumDevs function.

MIXER_OBJECTF_WAVEOUT

The hmxobj parameter is the identifier of a waveform-audio output device in the range of zero to one less than the number of devices returned by the waveOutGetNumDevs function.


mixerGetLineControls

MMRESULT mixerGetLineControls(HMIXEROBJ hmxobj,
    LPMIXERLINECONTROLS pmxlc, DWORD fdwControls);

Retrieves one or more controls associated with an audio line.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MIXERR_INVALCONTROL	The control reference is invalid.
MIXERR_INVALLINE	The audio line reference is invalid.
MMSYSERR_BADDEVICEID	The hmxobj parameter specifies an invalid device identifier.
MMSYSERR_INVALFLAG	One or more flags are invalid.
MMSYSERR_INVALHANDLE	The hmxobj parameter specifies an invalid handle.
MMSYSERR_INVALPARAM	One or more parameters are invalid.
MMSYSERR_NODRIVER	No mixer device is available for the object specified by hmxobj.
hmxobj

Handle of the mixer device object that is being queried.

pmxlc

Address of a MIXERLINECONTROLS structure. This structure is used to reference one or more MIXERCONTROL structures to be filled with information about the controls associated with an audio line. The cbStruct member of the MIXERLINECONTROLS structure must always be initialized to be the size, in bytes, of the MIXERLINECONTROLS structure.

fdwControls

Flags for retrieving information about one or more controls associated with an audio line. The following values are defined:

MIXER_GETLINECONTROLSF_ALL

The pmxlc parameter references a list of MIXERCONTROL structures that will receive information on all controls associated with the audio line identified by the dwLineID member of the MIXERLINECONTROLS structure. The cControls member must be initialized to the number of controls associated with the line. This number is retrieved from the cControls member of the MIXERLINE structure returned by the mixerGetLineInfo function. The cbmxctrl member must be initialized to the size, in bytes, of a single MIXERCONTROL structure. The pamxctrl member must point to the first MIXERCONTROL structure to be filled. The dwControlID and dwControlType members are ignored for this query.

MIXER_GETLINECONTROLSF_ONEBYID

The pmxlc parameter references a single MIXERCONTROL structure that will receive information on the control identified by the dwControlID member of the MIXERLINECONTROLS structure. The cControls member must be initialized to 1. The cbmxctrl member must be initialized to the size, in bytes, of a single MIXERCONTROL structure. The pamxctrl member must point to a MIXERCONTROL structure to be filled. The dwLineID and dwControlType members are ignored for this query. This query is usually used to refresh a control after receiving a MM_MIXM_CONTROL_CHANGE control change notification message by the user-defined callback (see mixerOpen).

MIXER_GETLINECONTROLSF_ONEBYTYPE

The mixerGetLineControls function retrieves information about the first control of a specific class for the audio line that is being queried. The pmxlc parameter references a single MIXERCONTROL structure that will receive information about the specific control. The audio line is identified by the dwLineID member. The control class is specified in the dwControlType member of the MIXERLINECONTROLS structure.

The dwControlID member is ignored for this query. This query can be used by an application to get information on a single control associated with a line. For example, you might want your application to use a peak meter only from a waveform-audio output line.

MIXER_OBJECTF_AUX

The hmxobj parameter is an auxiliary device identifier in the range of zero to one less than the number of devices returned by the auxGetNumDevs function.

MIXER_OBJECTF_HMIDIIN

The hmxobj parameter is the handle of a MIDI input device. This handle must have been returned by the midiInOpen function.

MIXER_OBJECTF_HMIDIOUT

The hmxobj parameter is the handle of a MIDI output device. This handle must have been returned by the midiOutOpen function.

MIXER_OBJECTF_HMIXER

The hmxobj parameter is a mixer device handle returned by the mixerOpen function. This flag is optional.

MIXER_OBJECTF_HWAVEIN

The hmxobj parameter is a waveform-audio input handle returned by the waveInOpen function.

MIXER_OBJECTF_HWAVEOUT

The hmxobj parameter is a waveform-audio output handle returned by the waveOutOpen function.

MIXER_OBJECTF_MIDIIN

The hmxobj parameter is the identifier of a MIDI input device. This identifier must be in the range of zero to one less than the number of devices returned by the midiInGetNumDevs function.

MIXER_OBJECTF_MIDIOUT

The hmxobj parameter is the identifier of a MIDI output device. This identifier must be in the range of zero to one less than the number of devices returned by the midiOutGetNumDevs function.

MIXER_OBJECTF_MIXER

The hmxobj parameter is the identifier of a mixer device in the range of zero to one less than the number of devices returned by the mixerGetNumDevs function. This flag is optional.

MIXER_OBJECTF_WAVEIN

The hmxobj parameter is the identifier of a waveform-audio input device in the range of zero to one less than the number of devices returned by the waveInGetNumDevs function.

MIXER_OBJECTF_WAVEOUT

The hmxobj parameter is the identifier of a waveform-audio output device in the range of zero to one less than the number of devices returned by the waveOutGetNumDevs function.


mixerGetLineInfo

MMRESULT mixerGetLineInfo(HMIXEROBJ hmxobj, LPMIXERLINE pmxl,
    DWORD fdwInfo);

Retrieves information about a specific line of a mixer device.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MIXERR_INVALLINE	The audio line reference is invalid.
MMSYSERR_BADDEVICEID	The hmxobj parameter specifies an invalid device identifier.
MMSYSERR_INVALFLAG	One or more flags are invalid.
MMSYSERR_INVALHANDLE	The hmxobj parameter specifies an invalid handle.
MMSYSERR_INVALPARAM	One or more parameters are invalid.
MMSYSERR_NODRIVER	No mixer device is available for the object specified by hmxobj.
hmxobj

Handle of the mixer device object that controls the specific audio line.

pmxl

Address of a MIXERLINE structure. This structure is filled with information about the audio line for the mixer device. The cbStruct member must always be initialized to be the size, in bytes, of the MIXERLINE structure.

fdwInfo

Flags for retrieving information about an audio line. The following values are defined:

MIXER_GETLINEINFOF_COMPONENTTYPE

The pmxl parameter will receive information about the first audio line of the type specified in the dwComponentType member of the MIXERLINE structure. This flag is used to retrieve information about an audio line of a specific component type. Remaining structure members except cbStruct require no further initialization.

MIXER_GETLINEINFOF_DESTINATION

The pmxl parameter will receive information about the destination audio line specified by the dwDestination member of the MIXERLINE structure. This index ranges from zero to one less than the value in the cDestinations member of the MIXERCAPS structure. All remaining structure members except cbStruct require no further initialization.

MIXER_GETLINEINFOF_LINEID

The pmxl parameter will receive information about the audio line specified by the dwLineID member of the MIXERLINE structure. This is usually used to retrieve updated information about the state of an audio line. All remaining structure members except cbStruct require no further initialization.

MIXER_GETLINEINFOF_SOURCE

The pmxl parameter will receive information about the source audio line specified by the dwDestination and dwSource members of the MIXERLINE structure. The index specified by dwDestination ranges from zero to one less than the value in the cDestinations member of the MIXERCAPS structure. The index specified by dwSource ranges from zero to one less than the value in the cConnections member of the MIXERLINE structure returned for the audio line stored in the dwDestination member. All remaining structure members except cbStruct require no further initialization.

MIXER_GETLINEINFOF_TARGETTYPE

The pmxl parameter will receive information about the audio line that is for the dwType member of the Target structure, which is a member of the MIXERLINE structure. This flag is used to retrieve information about an audio line that handles the target type (for example, MIXERLINE_TARGETTYPE_WAVEOUT). An application must initialize the dwType, wMid, wPid, vDriverVersion and szPname members of the MIXERLINE structure before calling mixerGetLineInfo. All of these values can be retrieved from the device capabilities structures for all media devices. Remaining structure members except cbStruct require no further initialization.

MIXER_OBJECTF_AUX

The hmxobj parameter is an auxiliary device identifier in the range of zero to one less than the number of devices returned by the auxGetNumDevs function.

MIXER_OBJECTF_HMIDIIN

The hmxobj parameter is the handle of a MIDI input device. This handle must have been returned by the midiInOpen function.

MIXER_OBJECTF_HMIDIOUT

The hmxobj parameter is the handle of a MIDI output device. This handle must have been returned by the midiOutOpen function.

MIXER_OBJECTF_HMIXER

The hmxobj parameter is a mixer device handle returned by the mixerOpen function. This flag is optional.

MIXER_OBJECTF_HWAVEIN

The hmxobj parameter is a waveform-audio input handle returned by the waveInOpen function.

MIXER_OBJECTF_HWAVEOUT

The hmxobj parameter is a waveform-audio output handle returned by the waveOutOpen function.

MIXER_OBJECTF_MIDIIN

The hmxobj parameter is the identifier of a MIDI input device. This identifier must be in the range of zero to one less than the number of devices returned by the midiInGetNumDevs function.

MIXER_OBJECTF_MIDIOUT

The hmxobj parameter is the identifier of a MIDI output device. This identifier must be in the range of zero to one less than the number of devices returned by the midiOutGetNumDevs function.

MIXER_OBJECTF_MIXER

The hmxobj parameter is a mixer device identifier in the range of zero to one less than the number of devices returned by the mixerGetNumDevs function. This flag is optional.

MIXER_OBJECTF_WAVEIN

The hmxobj parameter is the identifier of a waveform-audio input device in the range of zero to one less than the number of devices returned by the waveInGetNumDevs function.

MIXER_OBJECTF_WAVEOUT

The hmxobj parameter is the identifier of a waveform-audio output device in the range of zero to one less than the number of devices returned by the waveOutGetNumDevs function.


mixerGetNumDevs

UINT mixerGetNumDevs(VOID);

Retrieves the number of mixer devices present in the system.

•	Returns the number of mixer devices or zero if no mixer devices are available.


mixerMessage

DWORD mixerMessage(HMIXER hmx, UINT uMsg, DWORD dwParam1,
    DWORD dwParam2);

Sends a custom mixer driver message directly to a mixer driver.

•	Returns a value that is specific to the custom mixer driver message in the uMsg parameter.

MMSYSERR_INVALHANDLE	The specified device handle is invalid.
MMSYSERR_INVALPARAM	The uMsg parameter specified in the MXDM_USER message is invalid.
MMSYSERR_NOTSUPPORTED	The mixer device did not process the message.
hmx

Handle of an open instance of a mixer device. This handle is returned by the mixerOpen function.

uMsg

Custom mixer driver message to send to the mixer driver. This message must be above or equal to the MXDM_USER constant.

dwParam1 and dwParam2

Arguments associated with the message being sent.

User-defined messages must be sent only to a mixer driver that supports the messages. The application should verify that the mixer driver is the driver that supports the message by retrieving the mixer capabilities and checking the wMid, wPid, vDriverVersion, and szPname members of the MIXERCAPS structure.


mixerOpen

MMRESULT mixerOpen(LPHMIXER phmx, UINT uMxId, DWORD dwCallback,
    DWORD dwInstance, DWORD fdwOpen);

Opens a specified mixer device and ensures that the device will not be removed until the application closes the handle.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMSYSERR_ALLOCATED	The specified resource is already allocated by the maximum number of clients possible.
MMSYSERR_BADDEVICEID	The uMxId parameter specifies an invalid device identifier.
MMSYSERR_INVALFLAG	One or more flags are invalid.
MMSYSERR_INVALHANDLE	The uMxId parameter specifies an invalid handle.
MMSYSERR_INVALPARAM	One or more parameters are invalid.
MMSYSERR_NODRIVER	No mixer device is available for the object specified by uMxId. Note that the location referenced by uMxId will also contain the value  − 1.
MMSYSERR_NOMEM	Unable to allocate resources.
phmx

Address of a variable that will receive a handle identifying the opened mixer device. Use this handle to identify the device when calling other audio mixer functions. This parameter cannot be NULL.

uMxId

Identifier of the mixer device to open. Use a valid device identifier or any HMIXEROBJ (see the mixerGetID function for a description of mixer object handles). A "mapper" for audio mixer devices does not currently exist, so a mixer device identifier of − 1 is not valid.

dwCallback

Handle of a window called when the state of an audio line and/or control associated with the device being opened is changed. Specify zero for this parameter if no callback mechanism is to be used.

dwInstance

User instance data passed to the callback function. This parameter is not used with window callback functions.

fdwOpen

Flags for opening the device. The following values are defined:

CALLBACK_WINDOW

The dwCallback parameter is assumed to be a window handle.

MIXER_OBJECTF_AUX

The uMxId parameter is an auxiliary device identifier in the range of zero to one less than the number of devices returned by the auxGetNumDevs function.

MIXER_OBJECTF_HMIDIIN

The uMxId parameter is the handle of a MIDI input device. This handle must have been returned by the midiInOpen function.

MIXER_OBJECTF_HMIDIOUT

The uMxId parameter is the handle of a MIDI output device. This handle must have been returned by the midiOutOpen function.

MIXER_OBJECTF_HMIXER

The uMxId parameter is a mixer device handle returned by the mixerOpen function. This flag is optional.

MIXER_OBJECTF_HWAVEIN

The uMxId parameter is a waveform-audio input handle returned by the waveInOpen function.

MIXER_OBJECTF_HWAVEOUT

The uMxId parameter is a waveform-audio output handle returned by the waveOutOpen function.

MIXER_OBJECTF_MIDIIN

The uMxId parameter is the identifier of a MIDI input device. This identifier must be in the range of zero to one less than the number of devices returned by the midiInGetNumDevs function.

MIXER_OBJECTF_MIDIOUT

The uMxId parameter is the identifier of a MIDI output device. This identifier must be in the range of zero to one less than the number of devices returned by the midiOutGetNumDevs function.

MIXER_OBJECTF_MIXER

The uMxId parameter is a mixer device identifier in the range of zero to one less than the number of devices returned by the mixerGetNumDevs function. This flag is optional.

MIXER_OBJECTF_WAVEIN

The uMxId parameter is the identifier of a waveform-audio input device in the range of zero to one less than the number of devices returned by the waveInGetNumDevs function.

MIXER_OBJECTF_WAVEOUT

The uMxId parameter is the identifier of a waveform-audio output device in the range of zero to one less than the number of devices returned by the waveOutGetNumDevs function.

Use the mixerGetNumDevs function to determine the number of audio mixer devices present in the system. The device identifier specified by uMxId varies from zero to one less than the number of devices present.

If a window is chosen to receive callback information, the MM_MIXM_LINE_CHANGE and MM_MIXM_CONTROL_CHANGE messages are sent to the window procedure function to indicate when an audio line or control state changes. For both messages, the wParam parameter is the handle of the mixer device. The lParam parameter is the line identifier for MM_MIXM_LINE_CHANGE or the control identifier for MM_MIXM_CONTROL_CHANGE that changed state.

To query for audio mixer support or a media device, use the mixerGetID function.


mixerSetControlDetails

MMRESULT mixerSetControlDetails(HMIXEROBJ hmxobj,
    LPMIXERCONTROLDETAILS pmxcd, DWORD fdwDetails);

Sets properties of a single control associated with an audio line.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MIXERR_INVALCONTROL	The control reference is invalid.
MMSYSERR_BADDEVICEID	The hmxobj parameter specifies an invalid device identifier.
MMSYSERR_INVALFLAG	One or more flags are invalid.
MMSYSERR_INVALHANDLE	The hmxobj parameter specifies an invalid handle.
MMSYSERR_INVALPARAM	One or more parameters are invalid.
MMSYSERR_NODRIVER	No mixer device is available for the object specified by hmxobj.
hmxobj

Handle of the mixer device object for which properties are being set.

pmxcd

Address of a MIXERCONTROLDETAILS structure. This structure is used to reference control detail structures that contain the desired state for the control.

fdwDetails

Flags for setting properties for a control. The following values are defined:

MIXER_OBJECTF_AUX

The hmxobj parameter is an auxiliary device identifier in the range of zero to one less than the number of devices returned by the auxGetNumDevs function.

MIXER_OBJECTF_HMIDIIN

The hmxobj parameter is the handle of a MIDI input device. This handle must have been returned by the midiInOpen function.

MIXER_OBJECTF_HMIDIOUT

The hmxobj parameter is the handle of a MIDI output device. This handle must have been returned by the midiOutOpen function.

MIXER_OBJECTF_HMIXER

The hmxobj parameter is a mixer device handle returned by the mixerOpen function. This flag is optional.

MIXER_OBJECTF_HWAVEIN

The hmxobj parameter is a waveform-audio input handle returned by the waveInOpen function.

MIXER_OBJECTF_HWAVEOUT

The hmxobj parameter is a waveform-audio output handle returned by the waveOutOpen function.

MIXER_OBJECTF_MIDIIN

The hmxobj parameter is the identifier of a MIDI input device. This identifier must be in the range of zero to one less than the number of devices returned by the midiInGetNumDevs function.

MIXER_OBJECTF_MIDIOUT

The hmxobj parameter is the identifier of a MIDI output device. This identifier must be in the range of zero to one less than the number of devices returned by the midiOutGetNumDevs function.

MIXER_OBJECTF_MIXER

The hmxobj parameter is a mixer device identifier in the range of zero to one less than the number of devices returned by the mixerGetNumDevs function. This flag is optional.

MIXER_OBJECTF_WAVEIN

The hmxobj parameter is the identifier of a waveform-audio input device in the range of zero to one less than the number of devices returned by the waveInGetNumDevs function.

MIXER_OBJECTF_WAVEOUT

The hmxobj parameter is the identifier of a waveform-audio output device in the range of zero to one less than the number of devices returned by the waveOutGetNumDevs function.

MIXER_SETCONTROLDETAILSF_CUSTOM

A custom dialog box for the specified custom mixer control is displayed. The mixer device gathers the required information from the user and returns the data in the specified buffer. The handle for the owning window is specified in the hwndOwner member of the MIXERCONTROLDETAILS structure. (This handle can be set to NULL.) The application can then save the data from the dialog box and use it later to reset the control to the same state by using the MIXER_SETCONTROLDETAILSF_VALUE flag.

MIXER_SETCONTROLDETAILSF_VALUE

The current value(s) for a control are set. The paDetails member of the MIXERCONTROLDETAILS structure points to one or more mixer-control details structures of the appropriate class for the control.

All members of the MIXERCONTROLDETAILS structure must be initialized before calling mixerSetControlDetails.

If an application needs to retrieve only the current state of a custom mixer control and not display a dialog box, then mixerGetControlDetails can be used with the MIXER_GETCONTROLDETAILSF_VALUE flag.


MIXERCAPS

typedef struct {

    WORD    wMid;

    WORD    wPid;

    MMVERSION vDriverVersion;

    CHAR    szPname[MAXPNAMELEN];

    DWORD   fdwSupport;

    DWORD   cDestinations;

} MIXERCAPS;

Describes the capabilities of a mixer device.

wMid

A manufacturer identifier for the mixer device driver. For more information about manufacturer identifiers, see Chapter 0, "Manufacturer and Product Identifiers."

wPid

A product identifier for the mixer device driver. For more information about product identifiers, see Chapter 0, "Manufacturer and Product Identifiers."

vDriverVersion

Version number of the mixer device driver. The high-order byte is the major version number, and the low-order byte is the minor version number.

szPname

Name of the product. If the mixer device driver supports multiple cards, this string must uniquely and easily identify (potentially to a user) the specific card.

fdwSupport

Various support information for the mixer device driver. No extended support bits are currently defined.

cDestinations

The number of audio line destinations available through the mixer device. All mixer devices must support at least one destination line, so this member cannot be zero. Destination indexes used in the dwDestination member of the MIXERLINE structure range from zero to the value specified in the cDestinations member minus one.


MIXERCONTROL

typedef struct {

    DWORD cbStruct;

    DWORD dwControlID;

    DWORD dwControlType;

    DWORD fdwControl;

    DWORD cMultipleItems;

    CHAR  szShortName[MIXER_SHORT_NAME_CHARS];

    CHAR  szName[MIXER_LONG_NAME_CHARS];

    union {                    // start Bounds union

        struct {

            LONG lMinimum;

            LONG lMaximum;

        };

        struct {

            DWORD dwMinimum;

            DWORD dwMaximum;

        };

        DWORD dwReserved[6];

    } Bounds;

    union {                    // start Metrics union

        DWORD cSteps;

        DWORD cbCustomData;

        DWORD dwReserved[6];   // reserved; do not use.

    } Metrics;

} MIXERCONTROL, *PMIXERCONTROL, FAR *LPMIXERCONTROL;

Describes the state and metrics of a single control for an audio line.

cbStruct

Size, in bytes, of the MIXERCONTROL structure.

dwControlID

Audio mixer-defined identifier that uniquely refers to the control described by the MIXERCONTROL structure. This identifier can be in any format supported by the mixer device. An application should use this identifier only as an abstract handle. No two controls for a single mixer device can ever have the same control identifier.

dwControlType

Class of the control for which the identifier is specified in dwControlID. An application must use this information to display the appropriate control for input from the user. An application can also display tailored graphics based on the control class or search for a particular control class on a specific line. If an application does not know about a control class, this control must be ignored. There are eight control class classifications, each with one or more standard control types:

MIXERCONTROL_CT_CLASS_CUSTOM

MIXERCONTROL_CONTROLTYPE_CUSTOM

MIXERCONTROL_CT_CLASS_FADER

MIXERCONTROL_CONTROLTYPE_BASS
MIXERCONTROL_CONTROLTYPE_EQUALIZER
MIXERCONTROL_CONTROLTYPE_FADER
MIXERCONTROL_CONTROLTYPE_TREBLE
MIXERCONTROL_CONTROLTYPE_VOLUME

MIXERCONTROL_CT_CLASS_LIST

MIXERCONTROL_CONTROLTYPE_MIXER
MIXERCONTROL_CONTROLTYPE_MULTIPLESELECT
MIXERCONTROL_CONTROLTYPE_MUX
MIXERCONTROL_CONTROLTYPE_SINGLESELECT

MIXERCONTROL_CT_CLASS_METER

MIXERCONTROL_CONTROLTYPE_BOOLEANMETER
MIXERCONTROL_CONTROLTYPE_PEAKMETER
MIXERCONTROL_CONTROLTYPE_SIGNEDMETER
MIXERCONTROL_CONTROLTYPE_UNSIGNEDMETER

MIXERCONTROL_CT_CLASS_NUMBER

MIXERCONTROL_CONTROLTYPE_DECIBELS
MIXERCONTROL_CONTROLTYPE_PERCENT
MIXERCONTROL_CONTROLTYPE_SIGNED
MIXERCONTROL_CONTROLTYPE_UNSIGNED

MIXERCONTROL_CT_CLASS_SLIDER

MIXERCONTROL_CONTROLTYPE_PAN
MIXERCONTROL_CONTROLTYPE_QSOUNDPAN
MIXERCONTROL_CONTROLTYPE_SLIDER

MIXERCONTROL_CT_CLASS_SWITCH

MIXERCONTROL_CONTROLTYPE_BOOLEAN
MIXERCONTROL_CONTROLTYPE_BUTTON
MIXERCONTROL_CONTROLTYPE_LOUDNESS
MIXERCONTROL_CONTROLTYPE_MONO
MIXERCONTROL_CONTROLTYPE_MUTE
MIXERCONTROL_CONTROLTYPE_ONOFF
MIXERCONTROL_CONTROLTYPE_STEREOENH

MIXERCONTROL_CT_CLASS_TIME

MIXERCONTROL_CONTROLTYPE_MICROTIME
MIXERCONTROL_CONTROLTYPE_MILLITIME

fdwControl

Status and support flags for the audio line control. The following values are defined:

MIXERCONTROL_CONTROLF_DISABLED

The control is disabled, perhaps due to other settings for the mixer hardware, and cannot be used. An application can read current settings from a disabled control, but it cannot apply settings.

MIXERCONTROL_CONTROLF_MULTIPLE

The control has two or more settings per channel. An equalizer, for example, requires this flag because each frequency band can be set to a different value. An equalizer that affects both channels of a stereo line in a uniform fashion will also specify the MIXERCONTROL_CONTROLF_UNIFORM flag.

MIXERCONTROL_CONTROLF_UNIFORM

The control acts on all channels of a multichannel line in a uniform fashion. For example, a control that mutes both channels of a stereo line would set this flag. Most MIXERCONTROL_CONTROLTYPE_MUX and MIXERCONTROL_CONTROLTYPE_MIXER controls also specify the MIXERCONTROL_CONTROLF_UNIFORM flag.

cMultipleItems

Number of items per channel that make up a MIXERCONTROL_CONTROLF_MULTIPLE control. This number is always two or greater for multiple-item controls. If the control is not a multiple-item control, do not use this member; it will be zero.

szShortName

Short string that describes the audio line control specified by dwControlID. This description should be appropriate to use as a concise label for the control.

szName

String that describes the audio line control specified by dwControlID. This description should be appropriate to use as a complete description for the control.

Bounds

Union of boundary types.

lMinimum

Minimum signed value for a control that has a signed boundary nature. This member cannot be used in conjunction with dwMinimun.

lMaximum

Maximum signed value for a control that has a signed boundary nature. This member cannot be used in conjunction with dwMaximun.

dwMinimum

Minimum unsigned value for a control that has an unsigned boundary nature. This member cannot be used in conjunction with lMinimun.

dwMaximum

Maximum unsigned value for a control that has an unsigned boundary nature. This member cannot be used in conjunction with lMaximum.

Metrics

Union of boundary metrics.

cSteps

Number of discrete ranges within the union specified for a control specified by the Bounds member. This member overlaps with the other members of the Metrics structure member and cannot be used in conjunction with those members.

cbCustomData

Size, in bytes, required to contain the state of a custom control class. This member is appropriate only for the MIXERCONTROL_CONTROLTYPE_CUSTOM control class.

To determine if the dwMinimum, dwMaximum, lMinimum, lMaximum, cSteps, and cbCustomData members are appropriate for a control class, see "Control Types" earlier in this chapter.

The calling application does not need to initialize any members of this structure because the MIXERCONTROL structure is passed to the mixerGetLineControls function as a receiving buffer that is referenced and described by the MIXERLINECONTROLS structure. When mixerGetLineControls returns, the cbStruct member contains the actual size of the information returned by the mixer device. The returned information will not exceed the requested size, nor will it be smaller than the MIXERCONTROL structure.


MIXERCONTROLDETAILS

typedef struct {

    DWORD cbStruct;

    DWORD dwControlID;

    DWORD cChannels;

    union {

        HWND  hwndOwner;

        DWORD cMultipleItems;

    };

    DWORD  cbDetails;

    LPVOID paDetails;

} MIXERCONTROLDETAILS;

Refers to control-detail structures, retrieving or setting state information of an audio mixer control. All members of this structure must be initialized before calling the mixerGetControlDetails and mixerSetControlDetails functions.

cbStruct

Size, in bytes, of the MIXERCONTROLDETAILS structure. The size must be large enough to contain the base MIXERCONTROLDETAILS structure. When mixerGetControlDetails returns, this member contains the actual size of the information returned. The returned information will not exceed the requested size, nor will it be smaller than the base MIXERCONTROLDETAILS structure.

dwControlID

Control identifier on which to get or set properties.

cChannels

Number of channels on which to get or set control properties. The following values are defined:

0

Use this value when the control is a MIXERCONTROL_CONTROLTYPE_CUSTOM control.

1

Use this value when the control is a MIXERCONTROL_CONTROLF_UNIFORM control or when an application needs to get and set all channels as if they were uniform.

MIXERLINE.cChannels

Use this value when the properties for the control are expected on all channels for a line.

An application cannot specify a value that falls between 1 and the number of channels for the audio line. For example, specifying 2 or 3 for a four-channel line is not valid. This member cannot be 0 for noncustom control types.

hwndOwner

Handle of the window that owns a custom dialog box for a mixer control. This member is used when the MIXER_SETCONTROLDETAILSF_CUSTOM flag is specified in the mixerSetControlDetails function.

cMultipleItems

Number of multiple items per channel on which to get or set properties. The following values are defined:

0

Use this value for all controls except for a MIXERCONTROL_CONTROLF_MULTIPLE or a MIXERCONTROL_CONTROLTYPE_CUSTOM control.

MIXERCONTROL.cMultipleItems

Use this value when the control class is MIXERCONTROL_CONTROLF_MULTIPLE.

MIXERCONTROLDETAILS.hwndOwner

Use this value when the control is a MIXERCONTROL_CONTROLTYPE_CUSTOM control and the MIXER_SETCONTROLDETAILSF_CUSTOM flag is specified for the mixerSetControlDetails function. In this case, the hwndOwner member overlaps with cMultipleItems, providing the value of the window handle.

When using a MIXERCONTROL_CONTROLTYPE_CUSTOM control without the MIXERCONTROL_CONTROLTYPE_CUSTOM flag, specify zero for this member.

An application cannot specify any value other than the value specified in the cMultipleItems member of the MIXERCONTROL structure for a MIXERCONTROL_CONTROLF_MULTIPLE control.

cbDetails

Size, in bytes, of one of the following details structures being used:

MIXERCONTROLDETAILS_BOOLEAN

Boolean value for an audio line control.

MIXERCONTROLDETAILS_LISTTEXT

List text buffer for an audio line control. For information about the appropriate details structure for a specific control, see "Control Types" earlier in this chapter.

MIXERCONTROLDETAILS_SIGNED

Signed value for an audio line control.

MIXERCONTROLDETAILS_UNSIGNED

Unsigned value for an audio line control.

If the control is a MIXERCONTROL_CONTROLTYPE_CUSTOM control, this member must be equal to the cbCustomData member of the MIXERCONTROL structure.

paDetails

Address of an array of one or more structures in which properties for the specified control are retrieved or set. For MIXERCONTROL_CONTROLF_MULTIPLE controls, the size of this buffer should be the product of the cChannels, cMultipleItems and cbDetails members of the MIXERCONTROLDETAILS structure. For controls other than MIXERCONTROL_CONTROLF_MULTIPLE types, the size of this buffer is the product of the cChannels and cbDetails members of the MIXERCONTROLDETAILS structure.

For controls that are MIXERCONTROL_CONTROLF_MULTIPLE types, the array can be treated as a two-dimensional array that is channel major. That is, all multiple items for the left channel are given, then all multiple items for the right channel, and so on.

For controls other than MIXERCONTROL_CONTROLF_MULTIPLE types, each element index is equivalent to the zero-based channel that it affects. That is, paDetails[0] is for the left channel and paDetails[1] is for the right channel.

If the control is a MIXERCONTROL_CONTROLTYPE_CUSTOM control, this member must point to a buffer that is at least large enough to contain the size, in bytes, specified by the cbCustomData member of the MIXERCONTROL structure.


MIXERCONTROLDETAILS_BOOLEAN

typedef struct {

    LONG fValue;

} MIXERCONTROLDETAILS_BOOLEAN;

Retrieves and sets Boolean control properties for an audio mixer control.

fValue

Boolean value for a single item or channel. This value is assumed to be zero for a FALSE state (such as off or disabled), and nonzero for a TRUE state (such as on or enabled).

The following standard control types use this structure for retrieving and setting properties.

Meter controls:

MIXERCONTROL_CONTROLTYPE_BOOLEANMETER

Switch controls:

MIXERCONTROL_CONTROLTYPE_BOOLEAN
MIXERCONTROL_CONTROLTYPE_BUTTON
MIXERCONTROL_CONTROLTYPE_LOUDNESS
MIXERCONTROL_CONTROLTYPE_MONO
MIXERCONTROL_CONTROLTYPE_MUTE
MIXERCONTROL_CONTROLTYPE_ONOFF
MIXERCONTROL_CONTROLTYPE_STEREOENH

List controls:

MIXERCONTROL_CONTROLTYPE_MIXER
MIXERCONTROL_CONTROLTYPE_MULTIPLESELECT
MIXERCONTROL_CONTROLTYPE_MUX
MIXERCONTROL_CONTROLTYPE_SINGLESELECT


MIXERCONTROLDETAILS_LISTTEXT

typedef struct {

    DWORD dwParam1;

    DWORD dwParam2;

    CHAR  szName[MIXER_LONG_NAME_CHARS];

} MIXERCONTROLDETAILS_LISTTEXT;

Retrieves list text, label text, and/or band-range information for multiple-item controls. This structure is used when the MIXER_GETCONTROLDETAILSF_LISTTEXT flag is specified in the mixerGetControlDetails function.

dwParam1 and dwParam2

Control class-specific values. The following control types are listed with their corresponding values:

EQUALIZER

MIXERCONTROL.Bounds.dwMinimum

MIXER and MUX

MIXERLINE.dwLineID

MULTIPLESELECT and SINGLESELECT

Undefined; must be zero

szName

Name describing a single item in a multiple-item control. This text can be used as a label or item text, depending on the control class.

The following standard control types use this structure for retrieving the item text descriptions on multiple-item controls:

Fader control:

MIXERCONTROL_CONTROLTYPE_EQUALIZER

List controls:

MIXERCONTROL_CONTROLTYPE_MIXER
MIXERCONTROL_CONTROLTYPE_MULTIPLESELECT
MIXERCONTROL_CONTROLTYPE_MUX
MIXERCONTROL_CONTROLTYPE_SINGLESELECT


MIXERCONTROLDETAILS_SIGNED

typedef struct {

    LONG lValue;

} MIXERCONTROLDETAILS_SIGNED;

Retrieves and sets signed type control properties for an audio mixer control.

lValue

Signed integer value for a single item or channel. This value must be inclusively within the bounds given in the Bounds member of this structure for signed integer controls.

The following standard control types use this structure for retrieving and setting properties:

Meter controls:

MIXERCONTROL_CONTROLTYPE_PEAKMETER
MIXERCONTROL_CONTROLTYPE_SIGNEDMETER

Member controls:

MIXERCONTROL_CONTROLTYPE_SIGNED

Number controls:

MIXERCONTROL_CONTROLTYPE_DECIBELS

Slider controls:

MIXERCONTROL_CONTROLTYPE_PAN
MIXERCONTROL_CONTROLTYPE_QSOUNDPAN
MIXERCONTROL_CONTROLTYPE_SLIDER


MIXERCONTROLDETAILS_UNSIGNED

typedef struct {

    DWORD dwValue;

} MIXERCONTROLDETAILS_UNSIGNED;

Retrieves and sets unsigned type control properties for an audio mixer control.

dwValue

Unsigned integer value for a single item or channel. This value must be inclusively within the bounds given in the Bounds structure member of the MIXERCONTROL structure for unsigned integer controls.

The following standard control types use this structure for retrieving and setting properties:

Meter control:

MIXERCONTROL_CONTROLTYPE_UNSIGNEDMETER

Number control:

MIXERCONTROL_CONTROLTYPE_UNSIGNED

Fader controls:

MIXERCONTROL_CONTROLTYPE_BASS
MIXERCONTROL_CONTROLTYPE_EQUALIZER
MIXERCONTROL_CONTROLTYPE_FADER
MIXERCONTROL_CONTROLTYPE_TREBLE
MIXERCONTROL_CONTROLTYPE_VOLUME

Time controls:

MIXERCONTROL_CONTROLTYPE_MICROTIME
MIXERCONTROL_CONTROLTYPE_MILLITIME
MIXERCONTROL_CONTROLTYPE_PERCENT


MIXERLINE

typedef struct {

    DWORD cbStruct;

    DWORD dwDestination;

    DWORD dwSource;

    DWORD dwLineID;

    DWORD fdwLine;

    DWORD dwUser;

    DWORD dwComponentType;

    DWORD cChannels;

    DWORD cConnections;

    DWORD cControls;

    CHAR  szShortName[MIXER_SHORT_NAME_CHARS];

    CHAR  szName[MIXER_LONG_NAME_CHARS];

    struct {                     // start Target structure

        DWORD     dwType;

        DWORD     dwDeviceID;

        WORD      wMid;

        WORD      wPid;

        MMVERSION vDriverVersion;

        CHAR      szPname[MAXPNAMELEN];

    } Target;

} MIXERLINE;

Describes the state and metrics of an audio line.

cbStruct

Size, in bytes, of the MIXERLINE structure. This member must be initialized before calling the mixerGetLineInfo function. The size specified in this member must be large enough to contain the MIXERLINE structure. When mixerGetLineInfo returns, this member contains the actual size of the information returned. The returned information will not exceed the requested size.

dwDestination

Destination line index. This member ranges from zero to one less than the value specified in the cDestinations member of the MIXERCAPS structure retrieved by the mixerGetDevCaps function. When the mixerGetLineInfo function is called with the MIXER_GETLINEINFOF_DESTINATION flag, properties for the destination line are returned. (The dwSource member must be set to zero in this case.) When called with the MIXER_GETLINEINFOF_SOURCE flag, the properties for the source given by the dwSource member that is associated with the dwDestination member are returned.

dwSource

Index for the audio source line associated with the dwDestination member. That is, this member specifies the nth audio source line associated with the specified audio destination line. This member is not used for destination lines and must be set to zero when MIXER_GETLINEINFOF_DESTINATION is specified in the mixerGetLineInfo function. When the MIXER_GETLINEINFOF_SOURCE flag is specified, this member ranges from zero to one less than the value specified in the cConnections member for the audio destination line given in the dwDestination member.

dwLineID

An identifier defined by the mixer device that uniquely refers to the audio line described by the MIXERLINE structure. This identifier is unique for each mixer device and can be in any format. An application should use this identifier only as an abstract handle.

fdwLine

Status and support flags for the audio line. This member is always returned to the application and requires no initialization.

MIXERLINE_LINEF_ACTIVE

Audio line is active. An active line indicates that a signal is probably passing through the line.

MIXERLINE_LINEF_DISCONNECTED

Audio line is disconnected. A disconnected line's associated controls can still be modified, but the changes have no effect until the line is connected.

MIXERLINE_LINEF_SOURCE

Audio line is an audio source line associated with a single audio destination line. If this flag is not set, this line is an audio destination line associated with zero or more audio source lines.

If an application is not using a waveform-audio output device, the audio line associated with that device would not be active (that is, the MIXERLINE_LINEF_ACTIVE flag would not be set). If the waveform-audio output device is opened, then the audio line is considered active and the MIXERLINE_LINEF_ACTIVE flag will be set. A paused or starved waveform-audio output device is still considered active. In other words, if the waveform-audio output device is opened by an application regardless of whether data is being played, the associated audio line is considered active. If a line cannot be strictly defined as active, the mixer device will always set the MIXERLINE_LINEF_ACTIVE flag.

dwUser

Instance data defined by the audio device for the line. This member is intended for custom mixer applications designed specifically for the mixer device returning this information. Other applications should ignore this data.

dwComponentType

Component type for this audio line. An application can use this information to display tailored graphics or to search for a particular component. If an application does not use component types, this member should be ignored. This member can be one of the following values:

MIXERLINE_COMPONENTTYPE_DST_DIGITAL

Audio line is a digital destination (for example, digital input to a DAT or CD audio device).

MIXERLINE_COMPONENTTYPE_DST_HEADPHONES

Audio line is an adjustable (gain and/or attenuation) destination intended to drive headphones. Most audio cards use the same audio destination line for speakers and headphones, in which case the mixer device simply uses the MIXERLINE_COMPONENTTYPE_DST_SPEAKERS type.

MIXERLINE_COMPONENTTYPE_DST_LINE

Audio line is a line level destination (for example, line level input from a CD audio device) that will be the final recording source for the analog-to-digital converter (ADC). Because most audio cards for personal computers provide some sort of gain for the recording audio source line, the mixer device will use the MIXERLINE_COMPONENTTYPE_DST_WAVEIN type.

MIXERLINE_COMPONENTTYPE_DST_MONITOR

Audio line is a destination used for a monitor.

MIXERLINE_COMPONENTTYPE_DST_SPEAKERS

Audio line is an adjustable (gain and/or attenuation) destination intended to drive speakers. This is the typical component type for the audio output of audio cards for personal computers.

MIXERLINE_COMPONENTTYPE_DST_TELEPHONE

Audio line is a destination that will be routed to a telephone line.

MIXERLINE_COMPONENTTYPE_DST_UNDEFINED

Audio line is a destination that cannot be defined by one of the standard component types. A mixer device is required to use this component type for line component types that have not been defined by Microsoft Corporation.

MIXERLINE_COMPONENTTYPE_DST_VOICEIN

Audio line is a destination that will be the final recording source for voice input. This component type is exactly like MIXERLINE_COMPONENTTYPE_DST_WAVEIN but is intended specifically for settings used during voice recording/recognition. Support for this line is optional for a mixer device. Many mixer devices provide only MIXERLINE_COMPONENTTYPE_DST_WAVEIN.

MIXERLINE_COMPONENTTYPE_DST_WAVEIN

Audio line is a destination that will be the final recording source for the waveform-audio input (ADC). This line typically provides some sort of gain or attenuation. This is the typical component type for the recording line of most audio cards for personal computers.

MIXERLINE_COMPONENTTYPE_SRC_ANALOG

Audio line is an analog source (for example, analog output from a video-cassette tape).

MIXERLINE_COMPONENTTYPE_SRC_AUXILIARY

Audio line is a source originating from the auxiliary audio line. This line type is intended as a source with gain or attenuation that can be routed to the MIXERLINE_COMPONENTTYPE_DST_SPEAKERS destination and/or recorded from the MIXERLINE_COMPONENTTYPE_DST_WAVEIN destination.

MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC

Audio line is a source originating from the output of an internal audio CD. This component type is provided for audio cards that provide an audio source line intended to be connected to an audio CD (or CD-ROM playing an audio CD).

MIXERLINE_COMPONENTTYPE_SRC_DIGITAL

Audio line is a digital source (for example, digital output from a DAT or audio CD).

MIXERLINE_COMPONENTTYPE_SRC_LINE

Audio line is a line-level source (for example, line-level input from an external stereo) that can be used as an optional recording source. Because most audio cards for personal computers provide some sort of gain for the recording source line, the mixer device will use the MIXERLINE_COMPONENTTYPE_SRC_AUXILIARY type.

MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE

Audio line is a microphone recording source. Most audio cards for personal computers provide at least two types of recording sources: an auxiliary audio line and microphone input. A microphone audio line typically provides some sort of gain. Audio cards that use a single input for use with a microphone or auxiliary audio line should use the MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE component type.

MIXERLINE_COMPONENTTYPE_SRC_PCSPEAKER

Audio line is a source originating from personal computer speaker. Several audio cards for personal computers provide the ability to mix what would typically be played on the internal speaker with the output of an audio card. Some audio cards support the ability to use this output as a recording source.

MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER

Audio line is a source originating from the output of an internal synthesizer. Most audio cards for personal computers provide some sort of MIDI synthesizer (for example, an Adlib®-compatible or OPL/3 FM synthesizer).

MIXERLINE_COMPONENTTYPE_SRC_TELEPHONE

Audio line is a source originating from an incoming telephone line.

MIXERLINE_COMPONENTTYPE_SRC_UNDEFINED

Audio line is a source that cannot be defined by one of the standard component types. A mixer device is required to use this component type for line component types that have not been defined by Microsoft Corporation.

MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT

Audio line is a source originating from the waveform-audio output digital-to-analog converter (DAC). Most audio cards for personal computers provide this component type as a source to the MIXERLINE_COMPONENTTYPE_DST_SPEAKERS destination. Some cards also allow this source to be routed to the MIXERLINE_COMPONENTTYPE_DST_WAVEIN destination.

cChannels

Maximum number of separate channels that can be manipulated independently for the audio line. The minimum value for this field is 1 because a line must have at least one channel. Most modern audio cards for personal computers are stereo devices; for them, the value of this member is 2.

Channel 1 is assumed to be the left channel; channel 2 is assumed to be the right channel. A multichannel line might have one or more uniform controls (controls that affect all channels of a line uniformly) associated with it.

cConnections

Number of connections that are associated with the audio line. This member is used only for audio destination lines and specifies the number of audio source lines that are associated with it. This member is always zero for source lines and for destination lines that do not have any audio source lines associated with them.

cControls

Number of controls associated with the audio line. This value can be zero. If no controls are associated with the line, the line is likely to be a source that might be selected in a MIXERCONTROL_CONTROLTYPE_MUX or MIXERCONTROL_CONTROLTYPE_MIXER but allows no manipulation of the signal.

szShortName

Short string that describes the audio mixer line specified in the dwLineID member. This description should be appropriate as a concise label for the line.

szName

String that describes the audio mixer line specified in the dwLineID member. This description should be appropriate as a complete description for the line.

Target

Target media information.

dwType

Target media device type associated with the audio line described in the MIXERLINE structure. An application must ignore target information for media device types it does not use. The following values are defined:

MIXERLINE_TARGETTYPE_AUX

The audio line described by the MIXERLINE structure is strictly bound to the auxiliary device detailed in the remaining members of the Target structure member of the MIXERLINE structure.

MIXERLINE_TARGETTYPE_MIDIIN

The audio line described by the MIXERLINE structure is strictly bound to the MIDI input device detailed in the remaining members of the Target structure member of the MIXERLINE structure.

MIXERLINE_TARGETTYPE_MIDIOUT

The audio line described by the MIXERLINE structure is strictly bound to the MIDI output device detailed in the remaining members of the Target structure member of the MIXERLINE structure.

MIXERLINE_TARGETTYPE_UNDEFINED

The audio line described by the MIXERLINE structure is not strictly bound to a defined media type. All remaining Target structure members of the MIXERLINE structure should be ignored. An application cannot use the MIXERLINE_TARGETTYPE_UNDEFINED target type when calling the mixerGetLineInfo function with the MIXER_GETLINEINFOF_TARGETTYPE flag.

MIXERLINE_TARGETTYPE_WAVEIN

The audio line described by the MIXERLINE structure is strictly bound to the waveform-audio input device detailed in the remaining members of the Target structure member of the MIXERLINE structure.

MIXERLINE_TARGETTYPE_WAVEOUT

The audio line described by the MIXERLINE structure is strictly bound to the waveform-audio output device detailed in the remaining members of the Target structure member of the MIXERLINE structure.

dwDeviceID

Current device identifier of the target media device when the dwType member is a target type other than MIXERLINE_TARGETTYPE_UNDEFINED. This identifier is identical to the current media device index of the associated media device. When calling the mixerGetLineInfo function with the MIXER_GETLINEINFOF_TARGETTYPE flag, this member is ignored on input and will be returned to the caller by the audio mixer manager.

wMid

Manufacturer identifier of the target media device when the dwType member is a target type other than MIXERLINE_TARGETTYPE_UNDEFINED. This identifier is identical to the wMid member of the device-capabilities structure for the associated media.

wPid

Product identifier of the target media device when the dwType member is a target type other than MIXERLINE_TARGETTYPE_UNDEFINED. This identifier is identical to the wPid member of the device-capabilities structure for the associated media.

vDriverVersion

Driver version of the target media device when the dwType member is a target type other than MIXERLINE_TARGETTYPE_UNDEFINED. This version is identical to the vDriverVersion member of the device-capabilities structure for the associated media.

szPname

Product name of the target media device when the dwType member is a target type other than MIXERLINE_TARGETTYPE_UNDEFINED. This name is identical to the szPname member of the device-capabilities structure for the associated media.


MIXERLINECONTROLS

typedef struct {

    DWORD cbStruct;

    DWORD dwLineID;

    union {

        DWORD dwControlID;

        DWORD dwControlType;

    };

    DWORD          cControls;

    DWORD          cbmxctrl;

    LPMIXERCONTROL pamxctrl;

} MIXERLINECONTROLS;

Contains information about the controls of an audio line.

cbStruct

Size, in bytes, of the MIXERLINECONTROLS structure. This member must be initialized before calling the mixerGetLineControls function. The size specified in this member must be large enough to contain the MIXERLINECONTROLS structure. When mixerGetLineControls returns, this member contains the actual size of the information returned. The returned information will not exceed the requested size, nor will it be smaller than the MIXERLINECONTROLS structure.

dwLineID

Line identifier for which controls are being queried. This member is not used if the MIXER_GETLINECONTROLSF_ONEBYID flag is specified for the mixerGetLineControls function, but the mixer device still returns this member in this case. The dwControlID and dwControlType members are not used when MIXER_GETLINECONTROLSF_ALL is specified.

dwControlID

Control identifier of the desired control. This member is used with the MIXER_GETLINECONTROLSF_ONEBYID flag for the mixerGetLineControls function to retrieve the control information of the specified control. Note that the dwLineID member of the MIXERLINECONTROLS structure will be returned by the mixer device and is not required as an input parameter. This member overlaps with the dwControlType member and cannot be used in conjunction with the MIXER_GETLINECONTROLSF_ONEBYTYPE query type.

dwControlType

Class of the desired control. This member is used with the MIXER_GETLINECONTROLSF_ONEBYTYPE flag for the mixerGetLineControls function to retrieve the first control of the specified class on the line specified by the dwLineID member of the MIXERLINECONTROLS structure. This member overlaps with the dwControlID member and cannot be used in conjunction with the MIXER_GETLINECONTROLSF_ONEBYID query type.

cControls

Number of MIXERCONTROL structure elements to retrieve. This member must be initialized by the application before calling the mixerGetLineControls function. This member can be 1 only if MIXER_GETLINECONTROLSF_ONEBYID or MIXER_GETLINECONTROLSF_ONEBYTYPE is specified or the value returned in the cControls member of the MIXERLINE structure returned for an audio line. This member cannot be zero. If an audio line specifies that it has no controls, mixerGetLineControls should not be called.

cbmxctrl

Size, in bytes, of a single MIXERCONTROL structure. The size specified in this member must be at least large enough to contain the base MIXERCONTROL structure. The total size, in bytes, required for the buffer pointed to by the pamxctrl member is the product of the cbmxctrl and cControls members of the MIXERLINECONTROLS structure.

pamxctrl

Address of one or more MIXERCONTROL structures to receive the properties of the requested audio line controls. This member cannot be NULL and must be initialized before calling the mixerGetLineControls function. Each element of the array of controls must be at least large enough to contain a base MIXERCONTROL structure. The cbmxctrl member must specify the size, in bytes, of each element in this array. No initialization of the buffer pointed to by this member is required by the application. All members are filled in by the mixer device (including the cbStruct member of each MIXERCONTROL structure) upon returning successfully.


MM_MIXM_CONTROL_CHANGE

MM_MIXM_CONTROL_CHANGE

wParam = (WPARAM) hMixer

lParam = (LPARAM) dwControlID

Sent by a mixer device to notify an application that the state of a control associated with an audio line has changed. The application should refresh its display and cached values for the specified control.

hMixer

Handle of the mixer device (HMIXER) that sent the notification message.

dwControlID

Control identifier for the mixer control that has changed state. This identifier is the same as the dwControlID member of the MIXERCONTROL structure returned by the mixerGetLineControls function.

An application must open a mixer device and specify a callback window to receive the MM_MIXM_CONTROL_CHANGE message.


MM_MIXM_LINE_CHANGE

MM_MIXM_LINE_CHANGE

wParam = (WPARAM) hMixer

lParam = (LPARAM) dwLineID

Sent by a mixer device to notify an application that the state of an audio line on the specified device has changed. The application should refresh its display and cached values for the specified audio line.

hMixer

Handle of the mixer device that sent the notification message.

dwLineID

Line identifier for the audio line that has changed state. This identifier is the same as the dwLineID member of the MIXERLINE structure returned by the mixerGetLineInfo function.

An application must open a mixer device and specify a callback window to receive the MM_MIXM_LINE_CHANGE message.


File Input and Output

Most multimedia applications require file input and output (I/O) — that is, the ability to create, read, and write disk files. Multimedia file I/O services provide buffered and unbuffered file I/O and support for standard Resource Interchange File Format (RIFF) files. The services are extensible with custom I/O procedures that can be shared among applications.

Most applications need only the basic file I/O services and the RIFF file I/O services. Applications sensitive to file I/O performance, such as applications that stream data from compact disc − read-only memory (CD-ROM) in real time, can optimize performance by using services to directly access the file I/O buffer. Applications that access custom storage systems, such as file archives and databases, can provide their own I/O procedure that reads and writes elements of the storage system.

The multimedia file I/O services provide more functionality than the standard Microsoft Windows operating system services, including support for buffered I/O, RIFF files, memory files, and custom storage systems. In addition, the multimedia file I/O services are optimized for applications sensitive to performance.


File Input and Output Services

This section describes procedures for using the following multimedia file I/O services:

•	Basic

•	Buffered

•	RIFF

•	Custom


Basic Services

Using the basic I/O services is similar to using the run-time file I/O services of the C development system. Files must be opened before they can be read or written. After reading or writing, the file must be closed. You can also change the current read or write location within an open file.

Before you begin any I/O operations to a file, you must open the file by using the mmioOpen function. This function returns a file handle of type HMMIO. You can use this file handle to identify the open file when calling other file I/O functions.

Note  An HMMIO file handle is not a  standard file handle. Do not use HMMIO file handles with MS-DOS, standard Windows, or C run-time file I/O functions.

When you use mmioOpen to open a file, you use a flag to specify whether you are opening it for reading, writing, or both. You can also specify flags that enable you to create or delete a file. Use the mmioClose function to close a file when you are finished reading or writing to it.

You can read and write files by using the mmioRead and mmioWrite functions respectively. The next read or write operation occurs at the current file position or file pointer in a file. The current file position is advanced each time a file is read or written.

You can also change the current file position by using the mmioSeek function. You should ensure that you seek to a valid location in a file; if you seek to an invalid location, such as past the end of the file, mmioSeek might not return an error, but subsequent I/O operations might fail.

There are flags you can use with the mmioOpen function for operations beyond basic file I/O. By specifying an MMIOINFO structure, for example, you can open memory files, specify a custom I/O procedure, or supply a buffer for buffered I/O.


Buffered Services

Most of the overhead in file I/O occurs when accessing the media device. If you are reading or writing many small blocks of information, the device can spend a lot of time seeking to the physical location on the media for each read or write operation. In this case, you can achieve better performance by using buffered file I/O services. With buffered I/O, the file I/O manager maintains an intermediate buffer larger than the blocks of information you are reading or writing. It accesses the device only when the buffer must be filled from or written to the disk.

Before you set up and use buffered file I/O, you must decide whether you want the file I/O manager or the application to allocate the buffer. It is simpler to let the file I/O manager allocate the buffer; however, you can let the application allocate the buffer if you want to directly access the buffer or open a memory file. For more information about using memory files, see "Performing Memory File Input and Output" later in this chapter. For an example of directly accessing an I/O buffer, see "Accessing a File I/O Buffer" later in this chapter.

A buffer allocated by the file I/O manager is called an internal I/O buffer. To open a file for buffered I/O using an internal buffer, specify the MMIO_ALLOCBUF flag with the mmioOpen function when you open the file. After a file is opened for buffered I/O, the buffer is essentially transparent to the application; you can read, write, and seek the same way as with unbuffered I/O.

The default size of the internal I/O buffer is 8K. If this size is not adequate, you can use the mmioSetBuffer function to change it. You can also use this function to enable buffering on a file opened for unbuffered I/O, or to supply your own buffer for use as a memory file.

You can force the contents of an I/O buffer to be written to disk by using the mmioFlush function. When you close a file by using the mmioClose function, however, you don't have to call mmioFlush to flush an I/O buffer; the mmioClose function automatically flushes it. If you run out of disk space, mmioFlush might fail, even if the preceding calls of the mmioWrite function were successful. Similarly, mmioClose might fail when it is flushing its I/O buffer.

Applications that are performance-sensitive — such as those that stream data in real time from a CD-ROM — can optimize file I/O performance by directly accessing the I/O buffer. You should be careful if you choose to do this because you bypass some of the safeguards and error checking provided by the file I/O manager.

The multimedia file I/O manager uses the MMIOINFO structure to maintain state information about an open file. You use three members in this structure to read and write the I/O buffer: pchNext, pchEndRead, and pchEndWrite. The pchNext member points to the next location in the buffer to read or write. You must increment this member as you read and write the buffer. The pchEndRead member identifies the last valid character you can read from the buffer. Likewise, this member identifies the last location in the buffer you can write. More precisely, both pchEndRead and pchEndWrite point to the memory location that follows the last valid data in the buffer. Use the mmioGetInfo and mmioSetInfo functions to retrieve and set state information about the file I/O buffer.

When you reach the end of the I/O buffer, you must advance the buffer to fill it from the disk (if you are reading) or flush it to the disk (if you are writing). Use the mmioAdvance function to advance an I/O buffer. To fill an I/O buffer from disk, use mmioAdvance with the MMIO_READ flag. If there is not enough data remaining in the file to fill the buffer, the pchEndRead member of the MMIOINFO structure points to the location following the last valid byte in the buffer. To flush a buffer to disk, set the MMIO_DIRTY flag in the dwFlags member of the MMIOINFO structure, and then call mmioAdvance with the MMIO_WRITE flag.


Resource Interchange File Format Services

The preferred format for multimedia files is RIFF. The RIFF file I/O functions work with the basic buffered and unbuffered file I/O services. You can open, read, and write RIFF files in the same way as other file types. For detailed information about RIFF, see Chapter 6, "AVIFile Functions and Macros ."

RIFF files use four-character codes to identify file elements. These codes are 32-bit quantities representing a sequence of one to four ASCII alphanumeric characters, padded on the right with space characters. The data type for four-character codes is FOURCC. Use the mmioFOURCC macro to convert four characters into a four-character code. To convert a null-terminated string into a four-character code, use the mmioStringToFOURCC function.

The basic building block of a RIFF file is a chunk. A chunk is a logical unit of multimedia data, such as a single frame in a video clip. Each chunk contains the following fields:

•	A four-character code specifying the chunk identifier

•	A doubleword value specifying the size of the data member in the chunk

•	A data field

A chunk contained in another chunk is a subchunk. The only chunks allowed to contain subchunks are those with a chunk identifier of "RIFF" or "LIST". A chunk that contains another chunk is called a parent chunk. The first chunk in a RIFF file must be a "RIFF" chunk. All other chunks in the file are subchunks of the "RIFF" chunk.

"RIFF" chunks include an additional field in the first four bytes of the data field. This additional field provides the form type of the field. The form type is a four-character code identifying the format of the data stored in the file. For example, Microsoft waveform-audio files have a form type of "WAVE".

"LIST" chunks also include an additional field in the first four bytes of the data field. This additional field contains the list type of the field. The list type is a four-character code identifying the contents of the list. For example, a "LIST" chunk with a list type of "INFO" can contain "ICOP" and "ICRD" chunks providing copyright and creation date information.

Multimedia file I/O services include two functions you can use to navigate among chunks in a RIFF file: mmioAscend and mmioDescend. You can use these functions as high-level seek functions. When you descend into a chunk, the file position is set to the data field of the chunk (8 bytes from the beginning of the chunk). For "RIFF" and "LIST" chunks, the file position is set to the location following the form type or list type (12 bytes from the beginning of the chunk). When you ascend out of a chunk, the file position is set to the location following the end of the chunk. To create a new chunk, use the mmioCreateChunk function to write a chunk header at the current position in an open file. The mmioAscend, mmioDescend, and mmioCreateChunk functions use the MMCKINFO structure to specify and retrieve information about "RIFF" chunks.


Custom Services

Multimedia file I/O services use I/O procedures to handle the physical input and output associated with reading and writing to different types of storage systems, such as file-archival systems and database-storage systems. Predefined I/O procedures exist for the standard file systems and for memory files, but you can supply a custom I/O procedure for accessing a unique storage system by using the mmioInstallIOProc function.

To open a file by using a custom I/O procedure, use the mmioOpen function. Include a plus sign (+) or the CFSEPCHAR constant in the filename to separate the name of the physical file from the name of the element of the file you want to open. The following example opens a file element named "element" from a file named FILENAME.ARC:

mmioOpen("filename.arc+element", NULL, MMIO_READ);

When the file I/O manager encounters a plus sign in a filename, it examines the filename extension to determine which I/O procedure to associate with the file. In the previous example, the file I/O manager would attempt to use the I/O procedure associated with the .ARC filename extension; this I/O procedure would have been installed by using mmioInstallIOProc. If no I/O procedure is installed, mmioOpen returns an error.

I/O procedures must respond to the MMIOM_CLOSE, MMIOM_OPEN, MMIOM_READ, MMIOM_WRITE, MMIOM_SEEK, MMIOM_RENAME, and MMIOM_WRITEFLUSH messages. You can also create custom messages and send them to your I/O procedure by using the mmioSendMessage function. If you define your own messages, make sure they are defined at or above the value defined by the MMIOM_USER constant.

In addition to processing messages, an I/O procedure must maintain the lDiskOffset member of the MMIOINFO structure (pointed to by the lpmmioinfo parameter of the mmioOpen function). The lDiskOffset member must always contain the file offset to the location that the next MMIOM_READ or MMIOM_WRITE message will access. The offset is specified in bytes and is relative to the beginning of the file. The I/O procedure can use the adwInfo member to maintain any required state information. The I/O procedure should not modify any other members in the MMIOINFO structure.


Using File Input and Output

This section contains examples demonstrating how to perform the following tasks:

•	Open a file.

•	Create and delete a file.

•	Seek to a new position in a file.

•	Change the I/O buffer size.

•	Access a file I/O buffer.

•	Generate four-character codes.

•	Create a "RIFF" chunk.

•	Search for a "RIFF" chunk.

•	Search for a subchunk.

•	Perform file I/O on RIFF files.

•	Perform memory file input and output.

•	Install custom I/O procedures.

•	Share I/O procedures with other applications.


Using mioOpen to Open a File

To open a file for basic I/O operations, set the lpmmioinfo parameter of the mmioOpen function to NULL. The following example opens a file named "C:\SAMPLES\SAMPLE1.TXT" for reading, and checks the return value for error.

HMMIO hFile;

.

.

.

if ((hFile = mmioOpen("C:\\SAMPLES\\SAMPLE1.TXT", NULL,

    MMIO_READ)) != NULL)

    // File opened successfully.

else

    // File cannot be opened.

Use the dwFlags parameter of mmioOpen to specify flags for opening a file.


Creating and Deleting a File

To create a file, set the dwOpenFlags parameter of the mmioOpen function to MMIO_CREATE. The following example creates a file and opens it for reading and writing.

HMMIO hFile;

.

.

.

hFile = mmioOpen("NEWFILE.TXT", NULL, MMIO_CREATE | MMIO_READWRITE);

if (hFile != NULL)

    // File created successfully.

else

    // File cannot be created.

If the file you are creating already exists, it will be truncated to zero length.

To delete a file, set the dwOpenFlags parameter of the mmioOpen function to MMIO_DELETE. After you delete a file, it cannot be recovered by any standard means. If your application is deleting a file at the request of a user, query the user before deleting the file to make sure the user wants to delete it.


Seeking to a New Position in a File

The following example seeks to the beginning of an open file.

mmioSeek(hFile, 0L, SEEK_SET);

The following example seeks to the end of an open file.

mmioSeek(hFile, 0L, SEEK_END);

The following example seeks to a position 10 bytes from the end of an open file.

mmioSeek(hFile, -10L, SEEK_END);


Changing the I/O Buffer Size

The following example opens a file named "SAMPLE.TXT" for unbuffered I/O, and then enables buffered I/O with an internal 16K buffer.

HMMIO hFile;

.

.

.

if ((hFile = mmioOpen("SAMPLE.TXT", NULL, MMIO_READ)) != NULL)

{

    // File opened successfully; request an I/O buffer.

    if (mmioSetBuffer(hFile, NULL, 16384L, 0))

        // Buffer cannot be allocated.

    else

        // Buffer allocated successfully.

}

else

    // File cannot be opened.


Accessing a File I/O Buffer

The following example accesses an I/O buffer directly to read data from a waveform-audio file.

HMMIO    hmmio;

MMIOINFO mmioinfo;

DWORD    dwDataSize;

DWORD    dwCount;

HPSTR    hptr;

.

.

.

// Get information about the file I/O buffer.

if (mmioGetInfo(hmmio, &mmioinfo, 0)) {

    Error("Failed to get I/O buffer info.");

    .

    .

    .

    mmioClose(hmmio, 0);

    return;

}

// Read the entire file by directly reading the file I/O buffer.

// When the end of the I/O buffer is reached, advance the buffer.

for (dwCount = dwDataSize, hptr = lpData; dwCount  0; dwCount--)

{

    // Check to see if the I/O buffer must be advanced.

    if (mmioinfo.pchNext == mmioinfo.pchEndRead)

    {

        if(mmioAdvance(hmmio, &mmioinfo, MMIO_READ))

        {

            Error("Failed to advance buffer.");

            .

            .

            .

            mmioClose(hmmio, 0);

            return;

        }

    }

    // Get a character from the buffer.

    *hptr++ = *mmioinfo.pchNext++;

}

// End direct buffer access and close the file.

mmioSetInfo(hmmio, &mmioinfo, 0);

mmioClose(hmmio, 0);

When you finish accessing a file I/O buffer, call the mmioSetInfo function, passing an address of the MMIOINFO structure filled by the mmioGetInfo function. If you wrote to the buffer, set the MMIO_DIRTY flag in the dwFlags member of the MMIOINFO structure before calling mmioSetInfo. Otherwise, the buffer will not be flushed to disk.


Generating Four-Character Codes

You can use the mmioFOURCC macro or the mmioStringToFOURCC function to generate four-character codes. The following example uses mmioFOURCC to generate a four-character code for "WAVE".

FOURCC fourccID;

.

.

.

fourccID = mmioFOURCC('W', 'A', 'V', 'E');

The following example uses mmioStringToFOURCC to generate a four-character code for "WAVE".

FOURCC fourccID;

.

.

.

fourccID = mmioStringToFOURCC("WAVE", 0);

The second parameter in mmioStringToFOURCC specifies flags for converting the string to a four-character code. If you specify the MMIO_TOUPPER flag, mmioStringToFOURCC converts all alphabetic characters in the string to uppercase. This is useful when you need to specify a four-character code to identify a custom I/O procedure because four-character codes identifying file-extension names must be all uppercase.


Creating a "RIFF" Chunk

The following example creates a chunk with a chunk identifier of "RIFF" and a form type of "RDIB".

HMMIO    hmmio;

MMCKINFO mmckinfo;

.

.

.

mmckinfo.fccType = mmioFOURCC('R', 'D', 'I', 'B');

mmioCreateChunk(hmmio, &mmckinfo, MMIO_CREATERIFF);

If you're creating a "RIFF" or "LIST" chunk, you must specify the form type or list type in the fccType member of the MMCKINFO structure. In the previous example, the form type is "RDIB".

If you know the size of the data field in a new chunk, you can set the cksize member of the MMCKINFO structure when you create the chunk. This value will be written to the data size field in the new chunk. If this value is not correct when you call mmioAscend to mark the end of the chunk, it will be automatically rewritten to reflect the correct size of the data field.

After you create a chunk by using the mmioCreateChunk function, the file position is set to the data field of the chunk (8 bytes from the beginning of the chunk). If the chunk is a "RIFF" or "LIST" chunk, the file position is set to the location following the form type or list type (12 bytes from the beginning of the chunk).


Searching for a "RIFF" Chunk

The following example searches for a "RIFF" chunk with a form type of "WAVE" to verify that the file that has just been opened is a waveform-audio file.

HMMIO    hmmio;

MMCKINFO mmckinfoParent;

MMCKINFO mmckinfoSubchunk;

.

.

.

// Locate a "RIFF" chunk with a "WAVE" form type to make

// sure the file is a waveform-audio file.

mmckinfoParent.fccType = mmioFOURCC('W', 'A', 'V', 'E');

if (mmioDescend(hmmio, (LPMMCKINFO) &mmckinfoParent, NULL,

    MMIO_FINDRIFF))

    // The file is not a waveform-audio file.

else

    // The file is a waveform-audio file


Searching for a Subchunk

The following example searches for the "FMT" chunk in the "RIFF" chunk of the previous example.

// Find the format chunk (form type "FMT"); it should be

// a subchunk of the "RIFF" parent chunk.

mmckinfoSubchunk.ckid = mmioFOURCC('f', 'm', 't', ' ');

if (mmioDescend(hmmio, &mmckinfoSubchunk, &mmckinfoParent,

    MMIO_FINDCHUNK))

    // Error, cannot find the "FMT" chunk.

else

    // "FMT" chunk found.

To search for a subchunk (that is, any chunk other than a "RIFF" or "LIST" chunk), identify its parent chunk in the lpckParent parameter of the mmioDescend function.

If you do not specify a parent chunk, the current file position should be at the beginning of a chunk before you call the mmioDescend function. If you do specify a parent chunk, the current file position can be anywhere in that chunk.

If the search for a subchunk fails, the current file position is undefined. You can use the mmioSeek function and the dwDataOffset member of the MMCKINFO structure describing the parent chunk to seek back to the beginning of the parent chunk, as in the following example:

mmioSeek(hmmio, mmckinfoParent.dwDataOffset + 4, SEEK_SET);

Because dwDataOffset specifies the offset to the beginning of the data portion of the chunk, you must seek 4 bytes past dwDataOffset to set the file position after the form type.


Performing File Input and Output on RIFF Files

The following example shows how to open a RIFF file for buffered I/O, as well as how to descend, ascend, and read "RIFF" chunks.

// ReversePlay--Plays a waveform-audio file backward.

void ReversePlay()

{

    char        szFileName[128];    // filename of file to open

    HMMIO       hmmio;              // file handle for open file

    MMCKINFO    mmckinfoParent;     // parent chunk information

    MMCKINFO    mmckinfoSubchunk;   // subchunk information structure

    DWORD       dwFmtSize;          // size of "FMT" chunk

    DWORD       dwDataSize;         // size of "DATA" chunk

    WAVEFORMAT  *pFormat;           // address of "FMT" chunk

    HPSTR       lpData;             // address of "DATA" chunk

    // Get the filename from the edit control.

    .

    .

    .

    // Open the file for reading with buffered I/O

    // by using the default internal buffer

    if(!(hmmio = mmioOpen(szFileName, NULL,

        MMIO_READ | MMIO_ALLOCBUF)))

    {

        Error("Failed to open file.");

        return;

    }

    // Locate a "RIFF" chunk with a "WAVE" form type to make

    // sure the file is a waveform-audio file.

    mmckinfoParent.fccType = mmioFOURCC('W', 'A', 'V', 'E');

    if (mmioDescend(hmmio, (LPMMCKINFO) &mmckinfoParent, NULL,

        MMIO_FINDRIFF))

    {

        Error("This is not a waveform-audio file.");

        mmioClose(hmmio, 0);

        return;

    }

    // Find the "FMT" chunk (form type "FMT"); it must be

    // a subchunk of the "RIFF" chunk.

    mmckinfoSubchunk.ckid = mmioFOURCC('f', 'm', 't', ' ');

    if (mmioDescend(hmmio, &mmckinfoSubchunk, &mmckinfoParent,

        MMIO_FINDCHUNK))

    {

        Error("Waveform-audio file has no "FMT" chunk.");

        mmioClose(hmmio, 0);

        return;

    }

    // Get the size of the "FMT" chunk. Allocate

    // and lock memory for it.

    dwFmtSize = mmckinfoSubchunk.cksize;

    .

    .

    .

    // Read the "FMT" chunk.

    if (mmioRead(hmmio, (HPSTR) pFormat, dwFmtSize) != dwFmtSize){

        Error("Failed to read format chunk.");

        .

        .

        .

        mmioClose(hmmio, 0);

        return;

    }

    // Ascend out of the "FMT" subchunk.

    mmioAscend(hmmio, &mmckinfoSubchunk 0);

    // Find the data subchunk. The current file position should be at

    // the beginning of the data chunk; however, you should not make

    // this assumption. Use mmioDescend to locate the data chunk.

    mmckinfoSubchunk.ckid = mmioFOURCC('d', 'a', 't', 'a');

    if (mmioDescend(hmmio, &mmckinfoSubchunk, &mmckinfoParent,

        MMIO_FINDCHUNK))

    {

        Error("Waveform-audio file has no data chunk.");

        .

        .

        .

        mmioClose(hmmio, 0);

        return;

    }

    // Get the size of the data subchunk.

    dwDataSize = mmckinfoSubchunk.cksize;

    if (dwDataSize == 0L){

        Error("The data chunk contains no data.");

        .

        .

        .

        mmioClose(hmmio, 0);

        return;

    }

    // Open a waveform-audio output device.

    .

    .

    .

    // Allocate and lock memory for the waveform-audio data.

    .

    .

    .

    // Read the waveform-audio data subchunk.

    if(mmioRead(hmmio, (HPSTR) lpData, dwDataSize) != dwDataSize){

        Error("Failed to read data chunk.");

        .

        .

        .

        mmioClose(hmmio, 0);

        return;

    }

    // Close the file.

    mmioClose(hmmio, 0);

    // Reverse the sound and play it.

    .

    .

    .

}


Performing Memory File Input and Output

The multimedia file I/O services let you to treat a block of memory as a file. This can be useful if you already have a file image in memory. Memory files let you reduce the number of special-case conditions in your code because, for I/O purposes, you can treat memory files as if they were disk-based files. You can also use memory files with the clipboard.

As with I/O buffers, memory files can use memory allocated by the application or by the file I/O manager. In addition, memory files can be either expandable or nonexpandable. When the file I/O manager reaches the end of an expandable memory file, it expands the memory file by a predefined increment.

To open a memory file, use the mmioOpen function with the szFilename parameter set to NULL and the MMIO_READWRITE flag set in the dwOpenFlags parameter. Set the lpmmioinfo parameter to point to an MMIOINFO structure that has been set up as follows:

1.	Set the pIOProc member to NULL.

2.	Set the fccIOProc member to FOURCC_MEM.

3.	Set the pchBuffer member to point to the memory block. To request that the file I/O manager allocate the memory block, set pchBuffer to NULL.

4.	Set the cchBuffer member to the initial size of the memory block.

5.	Set the adwInfo member to the minimum expansion size of the memory block. For a nonexpandable memory file, set adwInfo to NULL.

6.	Set all other members to zero.

There are no restrictions on allocating memory for use as a nonexpandable memory file.


Installing Custom I/O Procedures

To install an I/O procedure associated with the .ARC filename extension, use the mmioInstallIOProc function as follows:

mmioInstallIOProc (mmioFOURCC('A', 'R', 'C', ' '),

    (LPMMIOPROC)lpmmioproc, MMIO_INSTALLPROC);

When you install an I/O procedure using mmioInstallIOProc, the procedure remains installed until you remove it. The I/O procedure is used for any file you open as long as the file has the appropriate filename extension.

You can also temporarily install an I/O procedure by using the mmioOpen function. In this case, the I/O procedure is used only with a file opened by using mmioOpen and is removed when the file is closed by using the mmioClose function. To specify an I/O procedure when you open a file by using mmioOpen, use the lpmmioinfo parameter to reference an MMIOINFO structure as follows:

1.	Set the fccIOProc member to NULL.

2.	Set the pIOProc member to the procedure-instance address of the I/O procedure.

3.	Set all other members to zero (unless you are opening a memory file, or directly reading or writing to the file I/O buffer).

Be sure to remove any I/O procedures you have installed before you exit your application.


Sharing an I/O Procedure with Other Applications

If you want to share an I/O procedure with other applications, you need to write a dynamic-link library (DLL) for your application. You can share the I/O procedure by doing one of the following:

•	Include the code for the I/O procedure in the DLL.

•	Create a function in the DLL that calls the mmioInstallIOProc function to install the I/O procedure.

•	Export this function in the module-definitions file of the DLL.

To use the shared I/O procedure, an application must first call the function in the DLL to install the I/O procedure.


File Input and Output Reference

This section describes the functions, macros, messages, and structures associated with multimedia file input and output. These elements are grouped as follows.

Basic I/O

mmioClose
mmioOpen
mmioRead
mmioRename
mmioSeek
mmioWrite

Buffered I/O

mmioAdvance
mmioFlush
mmioGetInfo
MMIOINFO
mmioSetBuffer
mmioSetInfo

RIFF I/O

mmioAscend
MMCKINFO
mmioCreateChunk
mmioDescend
mmioFOURCC
mmioStringToFOURCC

Custom I/O Procedures

IOProc
mmioInstallIOProc
MMIOM_CLOSE
MMIOM_OPEN
MMIOM_READ
MMIOM_RENAME
MMIOM_SEEK
MMIOM_WRITE
MMIOM_WRITEFLUSH
mmioSendMessage


IOProc

LRESULT FAR PASCAL IOProc(LPSTR lpmmioinfo, UINT wMsg, LPARAM lParam1,

    LPARAM lParam2);

Accesses a unique storage system, such as a database or file archive. You can install or remove this callback function by using the mmioInstallIOProc function.

IOProc is a placeholder for the application-defined function name. The actual name must be exported by including it in a EXPORTS statement in the application's module-definition file.

•	Returns a value that corresponds to the message specified by wMsg. If the I/O procedure does not recognize a message, it should return zero.

lpmmioinfo

Address of an MMIOINFO structure containing information about the open file. The I/O procedure must maintain the lDiskOffset member in this structure to indicate the file offset to the next read or write location. The I/O procedure can use the adwInfo member to store state information. The I/O procedure should not modify any other members of the MMIOINFO structure.

wMsg

Message indicating the requested I/O operation. Messages that can be received include MMIOM_OPEN, MMIOM_CLOSE, MMIOM_READ, MMIOM_WRITE, and MMIOM_SEEK.

lParam1 and lParam2

Parameters for the message.

The four-character code specified by the fccIOProc member of the MMIOINFO structure associated with a file identifies a filename extension for a custom storage system. When an application calls the mmioOpen function with a filename such as EXAMPLE.XYZ!ABC, the I/O procedure associated with the four-character code "XYZ" is called to open the ABC element of the file EXAMPLE.XYZ.

The mmioInstallIOProc function maintains a separate list of installed I/O procedures for each Windows application. Therefore, different applications can use the same I/O procedure identifier for different I/O procedures without conflict.

If an application calls mmioInstallIOProc more than once to register the same I/O procedure, it must call this function to remove the procedure once for each time it installed the procedure.

The mmioInstallIOProc function does not prevent an application from installing two different I/O procedures with the same identifier, or installing an I/O procedure with one of the predefined identifiers (DOS or MEM). The most recently installed procedure takes precedence, and the most recently installed procedure is the first one to be removed.

When searching for a specified I/O procedure, local procedures are searched first, then global procedures.


mmioAdvance

MMRESULT mmioAdvance(HMMIO hmmio, LPMMIOINFO lpmmioinfo, UINT wFlags);

Advances the I/O buffer of a file set up for direct I/O buffer access with the mmioGetInfo function.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMIOERR_CANNOTEXPAND	The specified memory file cannot be expanded, probably because the adwInfo member of the MMIOINFO structure was set to zero in the initial call to the mmioOpen function.
MMIOERR_CANNOTREAD	An error occurred while refilling the buffer.
MMIOERR_CANNOTWRITE	The contents of the buffer could not be written to disk.
MMIOERR_OUTOFMEMORY	There was not enough memory to expand a memory file for further writing.
MMIOERR_UNBUFFERED	The specified file is not opened for buffered I/O.
hmmio

File handle of a file opened by using the mmioOpen function.

lpmmioinfo

Address of the MMIOINFO structure obtained by using the mmioGetInfo function. This structure is used to set the current file information, and then it is updated after the buffer is advanced. This parameter is optional.

wFlags

Flags for the operation. It can be one of the following:

MMIO_READ

Buffer is filled from the file.

MMIO_WRITE

Buffer is written to the file.

If the file is opened for reading, the I/O buffer is filled from the disk. If the file is opened for writing and the MMIO_DIRTY flag is set in the dwFlags member of the MMIOINFO structure, the buffer is written to disk. The pchNext, pchEndRead, and pchEndWrite members of the MMIOINFO structure are updated to reflect the new state of the I/O buffer.

If the specified file is opened for writing or for both reading and writing, the I/O buffer is flushed to disk before the next buffer is read. If the I/O buffer cannot be written to disk because the disk is full, mmioAdvance returns MMIOERR_CANNOTWRITE.

If the specified file is open only for writing, the MMIO_WRITE flag must be specified.

If you have written to the I/O buffer, you must set the MMIO_DIRTY flag in the dwFlags member of the MMIOINFO structure before calling mmioAdvance. Otherwise, the buffer will not be written to disk.

If the end of file is reached, mmioAdvance still returns successfully even though no more data can be read. To check for the end of the file, check if the pchNext and pchEndRead members of the MMIOINFO structure are equal after calling mmioAdvance.


mmioAscend

MMRESULT mmioAscend(HMMIO hmmio, LPMMCKINFO lpck, UINT wFlags);

Ascends out of a chunk in a RIFF file descended into with the mmioDescend function or created with the mmioCreateChunk function.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMIOERR_CANNOTSEEK	There was an error while seeking to the end of the chunk.
MMIOERR_CANNOTWRITE	The contents of the buffer could not be written to disk.
hmmio

File handle of an open RIFF file.

lpck

Address of an application-defined MMCKINFO structure previously filled by the mmioDescend or mmioCreateChunk function.

wFlags

Reserved; must be zero.

If the chunk was descended into by using mmioDescend, mmioAscend seeks to the location following the end of the chunk (past the extra pad byte, if any).

If the chunk was created and descended into by using mmioCreateChunk, or if the MMIO_DIRTY flag is set in the dwFlags member of the MMCKINFO structure referenced by lpck, the current file position is assumed to be the end of the data portion of the chunk. If the chunk size is not the same as the value stored in the cksize member of the MMCKINFO structure when mmioCreateChunk was called, mmioAscend corrects the chunk size in the file before ascending from the chunk. If the chunk size is odd, mmioAscend writes a null pad byte at the end of the chunk. After ascending from the chunk, the current file position is the location following the end of the chunk (past the extra pad byte, if any).


mmioClose

MMRESULT mmioClose(HMMIO hmmio, UINT wFlags);

Closes a file that was opened by using the mmioOpen function.

•	Returns zero if successful or an error otherwise. The error value can originate from the mmioFlush function or from the I/O procedure. Possible error values include the following:

MMIOERR_CANNOTWRITE	The contents of the buffer could not be written to disk.
hmmio

File handle of the file to close.

wFlags

Flags for the close operation. The following value is defined:

MMIO_FHOPEN

If the file was opened by passing a file handle whose type is not HMMIO, using this flag tells the mmioClose function to close the multimedia file handle, but not the standard file handle.


mmioCreateChunk

MMRESULT mmioCreateChunk(HMMIO hmmio, LPMMCKINFO lpck, UINT wFlags);

Creates a chunk in a RIFF file that was opened by using the mmioOpen function. The new chunk is created at the current file position. After the new chunk is created, the current file position is the beginning of the data portion of the new chunk.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMIOERR_CANNOTSEEK	Unable to determine offset of the data portion of the chunk.
MMIOERR_CANNOTWRITE	Unable to write the chunk header.
hmmio

File handle of an open RIFF file.

lpck

Address an application-defined MMCKINFO structure containing information about the chunk to be created.

wFlags

Flags identifying what type of chunk to create. The following values are defined:

MMIO_CREATELIST

"LIST" chunk.

MMIO_CREATERIFF

"RIFF" chunk.

This function cannot insert a chunk into the middle of a file. If an application attempts to create a chunk somewhere other than at the end of a file, mmioCreateChunk overwrites existing information in the file.

The MMCKINFO structure pointed to by the lpck parameter should be set up as follows:

•	The ckid member specifies the chunk identifier. If wFlags includes MMIO_CREATERIFF or MMIO_CREATELIST, this member will be filled by mmioCreateChunk.

•	The cksize member specifies the size of the data portion of the chunk, including the form type or list type (if any). If this value is not correct when the mmioAscend function is called to mark the end of the chunk, mmioAscend corrects the chunk size.

•	The fccType member specifies the form type or list type if the chunk is a "RIFF" or "LIST" chunk. If the chunk is not a "RIFF" or "LIST" chunk, this member does not need to be filled in.

•	The dwDataOffset member does not need to be filled in. The mmioCreateChunk function fills this member with the file offset of the data portion of the chunk.

•	The dwFlags member does not need to be filled in. The mmioCreateChunk function sets the MMIO_DIRTY flag in dwFlags.


mmioDescend

MMRESULT mmioDescend(HMMIO hmmio, LPMMCKINFO lpck,

    LPMMCKINFO lpckParent, UINT wFlags);

Descends into a chunk of a RIFF file that was opened by using the mmioOpen function. It can also search for a given chunk.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMIOERR_CHUNKNOTFOUND	The end of the file (or the end of the parent chunk, if given) was reached before the desired chunk was found.
hmmio

File handle of an open RIFF file.

lpck

Address an application-defined MMCKINFO structure.

lpckParent

Address of an optional application-defined MMCKINFO structure identifying the parent of the chunk being searched for. If this parameter is not NULL, mmioDescend assumes the MMCKINFO structure it refers to was filled when mmioDescend was called to descend into the parent chunk, and mmioDescend searches for a chunk within the parent chunk. Set this parameter to NULL if no parent chunk is being specified.

wFlags

Search flags. If no flags are specified, mmioDescend descends into the chunk beginning at the current file position. The following values are defined:

MMIO_FINDCHUNK

Searches for a chunk with the specified chunk identifier.

MMIO_FINDLIST

Searches for a chunk with the chunk identifier "LIST" and with the specified form type.

MMIO_FINDRIFF

Searches for a chunk with the chunk identifier "RIFF" and with the specified form type.

A "RIFF" chunk consists of a four-byte chunk identifier (type FOURCC), followed by a four-byte chunk size (type DWORD), followed by the data portion of the chunk, followed by a null pad byte if the size of the data portion is odd. If the chunk identifier is "RIFF" or "LIST", the first four bytes of the data portion of the chunk are a form type or list type (type FOURCC).

If you use mmioDescend to search for a chunk, make sure the file position is at the beginning of a chunk before calling the function. The search begins at the current file position and continues to the end of the file. If a parent chunk is specified, the file position should be somewhere within the parent chunk before calling mmioDescend. In this case, the search begins at the current file position and continues to the end of the parent chunk.

If mmioDescend is unsuccessful in searching for a chunk, the current file position is undefined. If mmioDescend is successful, the current file position is changed. If the chunk is a "RIFF" or "LIST" chunk, the new file position will be just after the form type or list type (12 bytes from the beginning of the chunk). For other chunks, the new file position will be the start of the data portion of the chunk (8 bytes from the beginning of the chunk).

The mmioDescend function fills the MMCKINFO structure pointed to by the lpck parameter with the following information:

•	The ckid member is the chunk. If the MMIO_FINDCHUNK, MMIO_FINDRIFF, or MMIO_FINDLIST flag is specified for wFlags, the MMCKINFO structure is also used to pass parameters to mmioDescend. In this case, the ckid member specifies the four-character code of the chunk identifier, form type, or list type to search for.

•	The cksize member is the size, in bytes, of the data portion of the chunk. The size includes the form type or list type (if any), but does not include the 8-byte chunk header or the pad byte at the end of the data (if any).

•	The fccType member is the form type if ckid is "RIFF", or the list type if ckid is "LIST". Otherwise, it is NULL.

•	The dwDataOffset member is the file offset of the beginning of the data portion of the chunk. If the chunk is a "RIFF" chunk or a "LIST" chunk, this member is the offset of the form type or list type.

•	The dwFlags member contains other information about the chunk. Currently, this information is not used and is set to zero.


mmioFlush

MMRESULT mmioFlush(HMMIO hmmio, UINT fuFlush);

Writes the I/O buffer of a file to disk if the buffer has been written to.

•	Returns zero if successful or an error otherwise. The following value is defined:

MMIOERR_CANNOTWRITE	The contents of the buffer could not be written to disk.
hmmio

File handle of a file opened by using the mmioOpen function.

fuFlush

Flag determining how the flush is carried out. It can be zero or the following:

MMIO_EMPTYBUF	Empties the buffer after writing it to the disk.
Closing a file with the mmioClose function automatically flushes its buffer.

If there is insufficient disk space to write the buffer, mmioFlush fails, even if the preceding calls of the mmioWrite function were successful.


mmioFOURCC

FOURCC mmioFOURCC(CHAR ch0, CHAR ch1, CHAR ch2, CHAR ch3)

Converts four characters into a four-character code.

•	Returns the four-character code created from the given characters.

ch0, ch1, ch2, and ch3

First, second, third, and fourth characters of the four-character code.

This macro does not check whether the four-character code it returns is valid.

The mmioFOURCC macro is defined as follows:

#define mmioFOURCC(ch0, ch1, ch2, ch3)  MAKEFOURCC(ch0, ch1, ch2, ch3);

The MAKEFOURCC macro, in turn, is defined as follows:

#define MAKEFOURCC(ch0, ch1, ch2, ch3)  \

    ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) |  \

    ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24 ));


mmioGetInfo

MMRESULT mmioGetInfo(HMMIO hmmio, LPMMIOINFO lpmmioinfo, UINT wFlags);

Retrieves information about a file opened by using the mmioOpen function. This information allows the application to directly access the I/O buffer, if the file is opened for buffered I/O.

•	Returns zero if successful or an error otherwise.

hmmio

File handle of the file.

lpmmioinfo

Address an MMIOINFO structure that mmioGetInfo fills with information about the file.

wFlags

Reserved; must be zero.

To directly access the I/O buffer of a file opened for buffered I/O, use the following members of the MMIOINFO structure filled by mmioGetInfo:

•	The pchNext member points to the next byte in the buffer that can be read or written. When you read or write, increment pchNext by the number of bytes read or written.

•	The pchEndRead member points to 1 byte past the last valid byte in the buffer that can be read.

•	The pchEndWrite member points to 1 byte past the last location in the buffer that can be written.

After you read or write to the buffer and modify pchNext, do not call any multimedia file I/O functions except mmioAdvance until you call the mmioSetInfo function. Call mmioSetInfo when you are finished directly accessing the buffer.

When you reach the end of the buffer specified by the pchEndRead or pchEndWrite member, call mmioAdvance to fill the buffer from the disk or write the buffer to the disk. The mmioAdvance function updates the pchNext, pchEndRead, and pchEndWrite members in the MMIOINFO structure for the file.

Before calling mmioAdvance or mmioSetInfo to flush a buffer to disk, set the MMIO_DIRTY flag in the dwFlags member of the MMIOINFO structure for the file. Otherwise, the buffer will not be written to disk.

Do not decrement pchNext or modify any members in the MMIOINFO structure other than pchNext and dwFlags. Do not set any flags in dwFlags except MMIO_DIRTY.


mmioInstallIOProc

LPMMIOPROC mmioInstallIOProc(FOURCC fccIOProc, LPMMIOPROC pIOProc,

    DWORD dwFlags);

Installs or removes a custom I/O procedure. This function also locates an installed I/O procedure, using its corresponding four-character code.

•	Returns the address of the I/O procedure installed, removed, or located. Returns NULL if there is an error.

fccIOProc

Four-character code identifying the I/O procedure to install, remove, or locate. All characters in this code should be uppercase.

pIOProc

Address of the I/O procedure to install. To remove or locate an I/O procedure, set this parameter to NULL.

dwFlags

Flag indicating whether the I/O procedure is being installed, removed, or located. The following values are defined:

MMIO_FINDPROC

Searches for the specified I/O procedure.

MMIO_GLOBALPROC

This flag is a modifier to the MMIO_INSTALLPROC flag and indicates the I/O procedure should be installed for global use. This flag is ignored if MMIO_FINDPROC or MMIO_REMOVEPROC is specified.

MMIO_INSTALLPROC

Installs the specified I/O procedure.

MMIO_REMOVEPROC

Removes the specified I/O procedure.


mmioOpen

HMMIO mmioOpen(LPSTR szFilename, LPMMIOINFO lpmmioinfo,

    DWORD dwOpenFlags);

Opens a file for unbuffered or buffered I/O. The file can be a standard file, a memory file, or an element of a custom storage system. The handle returned by mmioOpen is not a standard file handle; do not use it with any file I/O functions other than multimedia file I/O functions.

•	Returns a handle of the opened file. If the file cannot be opened, the return value is NULL. If lpmmioinfo is not NULL, the wErrorRet member of the MMIOINFO structure will contain one of the following error values:

MMIOERR_ACCESSDENIED	The file is protected and cannot be opened.
MMIOERR_INVALIDFILE	Another failure condition occurred. This is the default error for an open-file failure.
MMIOERR_NETWORKERROR	The network is not responding to the request to open a remote file.
MMIOERR_PATHNOTFOUND	The directory specification is incorrect.
MMIOERR_SHARINGVIOLATION	The file is being used by another application and is unavailable.
MMIOERR_TOOMANYOPENFILES	The number of files simultaneously open is at a maximum level. The system has run out of available file handles.
szFilename

Address of a string containing the filename of the file to open. If no I/O procedure is specified to open the file, the filename determines how the file is opened, as follows:

•	If the filename does not contain a plus sign (+), it is assumed to be the name of a standard  file (that is, a file whose type is not HMMIO).

•	If the filename is of the form EXAMPLE.EXT+ABC, the extension EXT is assumed to identify an installed I/O procedure which is called to perform I/O on the file. For more information, see mmioInstallIOProc.

•	If the filename is NULL and no I/O procedure is given, the adwInfo member of the MMIOINFO structure is assumed to be the standard (non-HMMIO) file handle of a currently open file.

The filename should not be longer than 128 bytes, including the terminating NULL character.

When opening a memory file, set szFilename to NULL.

lpmmioinfo

Address of an MMIOINFO structure containing extra parameters used by mmioOpen. Unless you are opening a memory file, specifying the size of a buffer for buffered I/O, or specifying an uninstalled I/O procedure to open a file, this parameter should be NULL. If this parameter is not NULL, all unused members of the MMIOINFO structure it references must be set to zero, including the reserved members.

dwOpenFlags

Flags for the open operation. The MMIO_READ, MMIO_WRITE, and MMIO_READWRITE flags are mutually exclusive — only one should be specified. The MMIO_COMPAT, MMIO_EXCLUSIVE, MMIO_DENYWRITE, MMIO_DENYREAD, and MMIO_DENYNONE flags are file-sharing flags. The following values are defined:

MMIO_ALLOCBUF

Opens a file for buffered I/O. To allocate a buffer larger or smaller than the default buffer size (8K, defined as MMIO_DEFAULTBUFFER), set the cchBuffer member of the MMIOINFO structure to the desired buffer size. If cchBuffer is zero, the default buffer size is used. If you are providing your own I/O buffer, this flag should not be used.

MMIO_COMPAT

Opens the file with compatibility mode, allowing any process on a given machine to open the file any number of times. If the file has been opened with any of the other sharing modes, mmioOpen fails.

MMIO_CREATE

Creates a new file. If the file already exists, it is truncated to zero length. For memory files, this flag indicates the end of the file is initially at the start of the buffer.

MMIO_DELETE

Deletes a file. If this flag is specified, szFilename should not be NULL. The return value is TRUE (cast to HMMIO) if the file was deleted successfully or FALSE otherwise. Do not call the mmioClose function for a file that has been deleted. If this flag is specified, all other flags that open files are ignored.

MMIO_DENYNONE

Opens the file without denying other processes read or write access to the file. If the file has been opened in compatibility mode by any other process, mmioOpen fails.

MMIO_DENYREAD

Opens the file and denies other processes read access to the file. If the file has been opened in compatibility mode or for read access by any other process, mmioOpen fails.

MMIO_DENYWRITE

Opens the file and denies other processes write access to the file. If the file has been opened in compatibility mode or for write access by any other process, mmioOpen fails.

MMIO_EXCLUSIVE

Opens the file and denies other processes read and write access to the file. If the file has been opened in any other mode for read or write access, even by the current process, mmioOpen fails.

MMIO_EXIST

Determines whether the specified file exists and creates a fully qualified filename from the path specified in szFilename. The filename is placed back into szFilename. The return value is TRUE (cast to HMMIO) if the qualification was successful and the file exists or FALSE otherwise. The file is not opened, and the function does not return a valid multimedia file I/O file handle, so do not attempt to close the file.

MMIO_GETTEMP

Creates a temporary filename, optionally using the parameters passed in szFilename. For example, you can specify "C:F" to create a temporary file residing on drive C, starting with letter "F". The resulting filename is placed in the buffer pointed to by szFilename. The return value is MMSYSERR_NOERROR (cast to HMMIO) if the temporary filename was created successfully or MMIOERR_FILENOTFOUND otherwise. The file is not opened, and the function does not return a valid multimedia file I/O file handle, so do not attempt to close the file. This flag overrides all other flags.

MMIO_PARSE

Creates a fully qualified filename from the path specified in szFilename. The filename is placed back into szFilename. The return value is TRUE (cast to HMMIO) if the qualification was successful or FALSE otherwise. The file is not opened, and the function does not return a valid multimedia file I/O file handle, so do not attempt to close the file. If this flag is specified, all flags that open files are ignored.

MMIO_READ

Opens the file for reading only. This is the default if MMIO_WRITE and MMIO_READWRITE are not specified.

MMIO_READWRITE

Opens the file for reading and writing.

MMIO_WRITE

Opens the file for writing only.

If lpmmioinfo references an MMIOINFO structure, set up the members of that structure as described below. All unused members must be set to zero, including reserved members.

•	To request that a file be opened with an installed I/O procedure, set fccIOProc to the four-character code of the I/O procedure, and set pIOProc to NULL.

•	To request that a file be opened with an uninstalled I/O procedure, set IOProc to point to the I/O procedure, and set fccIOProc to NULL.

•	To request that mmioOpen determine which I/O procedure to use to open the file based on the filename contained in szFilename, set fccIOProc and pIOProc to NULL. This is the default behavior if no MMIOINFO structure is specified.

•	To open a memory file using an internally allocated and managed buffer, set pchBuffer to NULL, fccIOProc to FOURCC_MEM, cchBuffer to the initial size of the buffer, and adwInfo to the incremental expansion size of the buffer. This memory file will automatically be expanded in increments of the number of bytes specified in adwInfo when necessary. Specify the MMIO_CREATE flag for the dwOpenFlags parameter to initially set the end of the file to be the beginning of the buffer.

•	To open a memory file using an application-supplied buffer, set pchBuffer to point to the memory buffer, fccIOProc to FOURCC_MEM, cchBuffer to the size of the buffer, and adwInfo to the incremental expansion size of the buffer. The expansion size in adwInfo should be nonzero only if pchBuffer is a pointer obtained by calling the GlobalAlloc and GlobalLock functions; in this case, the GlobalReAlloc function will be called to expand the buffer. In other words, if pchBuffer points to a local or global array, a block of memory in the local heap, or a block of memory allocated by the GlobalDosAlloc function, adwInfo must be zero. Specify the MMIO_CREATE flag for the dwOpenFlags parameter to initially set the end of the file to be the beginning of the buffer. Otherwise, the entire block of memory is considered readable.

•	To use a currently open standard file handle (that is, a file handle that does not have the HMMIO type) with multimedia file I/O services, set fccIOProc to FOURCC_DOS, pchBuffer to NULL, and adwInfo to the standard file handle. Offsets within the file will be relative to the beginning of the file and are not related to the position in the standard file at the time mmioOpen is called; the initial multimedia file I/O offset will be the same as the offset in the standard file when mmioOpen is called. To close the multimedia file I/O file handle without closing the standard file handle, pass the MMIO_FHOPEN flag to mmioClose.

You must call mmioClose to close a file opened by using mmioOpen. Open files are not automatically closed when an application exits.


mmioRead

LONG mmioRead(HMMIO hmmio, HPSTR pch, LONG cch);

Reads a specified number of bytes from a file opened by using the mmioOpen function.

•	Returns the number of bytes actually read. If the end of the file has been reached and no more bytes can be read, the return value is 0. If there is an error reading from the file, the return value is − 1.

hmmio

File handle of the file to be read.

pch

Address of a buffer to contain the data read from the file.

cch

Number of bytes to read from the file.


mmioRename

MMRESULT mmioRename(LPCSTR szFilename, LPCSTR szNewFilename,

    const LPMMIOINFO lpmmioinfo, DWORD dwRenameFlags);

Renames the specified file.

•	Returns zero if the file was renamed. Otherwise, returns an error code returned from mmioRename or from the I/O procedure.

szFilename

Address of a string containing the filename of the file to rename.

szNewFileName

Address of a string containing the new filename.

lpmmioinfo

Address of an MMIOINFO structure containing extra parameters used by mmioRename. If this parameter is not NULL, all unused members of the MMIOINFO structure it references must be set to zero, including the reserved members.

dwRenameFlags

Flags for the rename operation. This parameter should be set to zero.


mmioSeek

LONG mmioSeek(HMMIO hmmio, LONG lOffset, int iOrigin);

Changes the current file position in a file opened by using the mmioOpen function.

•	Returns the new file position, in bytes, relative to the beginning of the file. If there is an error, the return value is − 1.

hmmio

File handle of the file to seek in.

lOffset

Offset to change the file position.

iOrigin

Flags indicating how the offset specified by lOffset is interpreted. The following values are defined:

SEEK_CUR

Seeks to lOffset bytes from the current file position.

SEEK_END

Seeks to lOffset bytes from the end of the file.

SEEK_SET

Seeks to lOffset bytes from the beginning of the file.

Seeking to an invalid location in the file, such as past the end of the file, might not cause mmioSeek to return an error, but it might cause subsequent I/O operations on the file to fail.

To locate the end of a file, call mmioSeek with lOffset set to zero and iOrigin set to SEEK_END.


mmioSendMessage

LRESULT mmioSendMessage(HMMIO hmmio, UINT wMsg, LPARAM lParam1,

    LPARAM lParam2);

Sends a message to the I/O procedure associated with the specified file.

•	Returns a value that corresponds to the message. If the I/O procedure does not recognize the message, the return value should be zero.

hmmio

File handle for a file opened by using the mmioOpen function.

wMsg

Message to send to the I/O procedure.

lParam1 and lParam2

Parameters for the message.

Use this function to send custom user-defined messages. Do not use it to send the MMIOM_OPEN, MMIOM_CLOSE, MMIOM_READ, MMIOM_WRITE, MMIOM_WRITEFLUSH, or MMIOM_SEEK messages. Define custom messages to be greater than or equal to the MMIOM_USER constant.


mmioSetBuffer

MMRESULT mmioSetBuffer(HMMIO hmmio, LPSTR pchBuffer, LONG cchBuffer,

    UINT wFlags);

Enables or disables buffered I/O, or changes the buffer or buffer size for a file opened by using the mmioOpen function.

•	Returns zero if successful or an error otherwise. If an error occurs, the file handle remains valid. The following values are defined:

MMIOERR_CANNOTWRITE	The contents of the old buffer could not be written to disk, so the operation was aborted.
MMIOERR_OUTOFMEMORY	The new buffer could not be allocated, probably due to a lack of available memory.
hmmio

File handle of the file.

pchBuffer

Address of an application-defined buffer to use for buffered I/O. If this parameter is NULL, mmioSetBuffer allocates an internal buffer for buffered I/O.

cchBuffer

Size, in characters, of the application-defined buffer, or the size of the buffer for mmioSetBuffer to allocate.

wFlags

Reserved; must be zero.

To enable buffering using an internal buffer, set pchBuffer to NULL and cchBuffer to the desired buffer size.

To supply your own buffer, set pchBuffer to point to the buffer, and set cchBuffer to the size of the buffer.

To disable buffered I/O, set pchBuffer to NULL and cchBuffer to zero.

If buffered I/O is already enabled using an internal buffer, you can reallocate the buffer to a different size by setting pchBuffer to NULL and cchBuffer to the new buffer size. The contents of the buffer can be changed after resizing.


mmioSetInfo

MMRESULT mmioSetInfo(HMMIO hmmio, LPMMIOINFO lpmmioinfo, UINT wFlags);

Updates the information retrieved by the mmioGetInfo function about a file opened by using the mmioOpen function. Use this function to terminate direct buffer access of a file opened for buffered I/O.

•	Returns zero if successful or an error otherwise.

hmmio

File handle of the file.

lpmmioinfo

Address of an MMIOINFO structure filled with information by the mmioGetInfo function.

wFlags

Reserved; must be zero.

If you have written to the file I/O buffer, set the MMIO_DIRTY flag in the dwFlags member of the MMIOINFO structure before calling mmioSetInfo to terminate direct buffer access. Otherwise, the buffer will not get flushed to disk.


mmioStringToFOURCC

FOURCC mmioStringToFOURCC(LPCSTR sz, UINT wFlags);

Converts a null-terminated string to a four-character code.

•	Returns the four-character code created from the given string.

sz

Address of a null-terminated string to convert to a four-character code.

wFlags

Flags for the conversion. The following value is defined:

MMIO_TOUPPER

Converts all characters to uppercase.

This function copies the string to a four-character code and pads it with space characters or truncates it if necessary. It does not check whether the code it returns is valid.


mmioWrite

LONG mmioWrite(HMMIO hmmio, char _huge* pch, LONG cch);

Writes a specified number of bytes to a file opened by using the mmioOpen function.

•	Returns the number of bytes actually written. If there is an error writing to the file, the return value is − 1.

hmmio

File handle of the file.

pch

Address of the buffer to be written to the file.

cch

Number of bytes to write to the file.

The current file position is incremented by the number of bytes written.


MMCKINFO

typedef struct {

    FOURCC ckid;          // chunk identifier

    DWORD  cksize;        // see below

    FOURCC fccType;       // see below

    DWORD  dwDataOffset;  // see below

    DWORD  dwFlags;       // see below

} MMCKINFO;

Contains information about a chunk in a RIFF file.

cksize

Size, in bytes, of the data member of the chunk. The size of the data member does not include the 4-byte chunk identifier, the 4-byte chunk size, or the optional pad byte at the end of the data member.

fccType

Form type for "RIFF" chunks or the list type for "LIST" chunks.

dwDataOffset

File offset of the beginning of the chunk's data member, relative to the beginning of the file.

dwFlags

Flags specifying additional information about the chunk. It can be zero or the following flag:

MMIO_DIRTY

The length of the chunk might have changed and should be updated by the mmioAscend function. This flag is set when a chunk is created by using the mmioCreateChunk function.


MMIOINFO

typedef struct {

    DWORD      dwFlags;      // see below

    FOURCC     fccIOProc;    // see below

    LPMMIOPROC pIOProc;      // address of file's I/O procedure

    UINT       wErrorRet;    // see below

    HTASK      hTask;        // see below

    LONG       cchBuffer;    // see below

    HPSTR      pchBuffer;    // see below

    HPSTR      pchNext;      // see below

    HPSTR      pchEndRead;   // see below

    HPSTR      pchEndWrite;  // see below

    LONG       lBufOffset;   // reserved

    LONG       lDiskOffset;  // see below

    DWORD      adwInfo[4];   // see below

    DWORD      dwReserved1;  // reserved

    DWORD      dwReserved2;  // reserved

    HMMIO      hmmio;        // see below

} MMIOINFO;

Contains the current state of a file opened by using the mmioOpen function.

dwFlags

Flags specifying how a file was opened. The following values are defined:

MMIO_ALLOCBUF

File's I/O buffer was allocated by the mmioOpen or mmioSetBuffer function.

MMIO_CREATE

The mmioOpen function was directed to create the file (or truncate it to zero length if it already existed).

MMIO_DIRTY

The I/O buffer has been modified.

MMIO_EXIST

Checks for the existence of the file.

MMIO_GETTEMP

A temporary name was retrieved by the mmioOpen function.

MMIO_PARSE

The new file's path is returned.

The following values may be set when the file is opened in share mode (identified by using the MMIO_SHAREMODE bit mask):

MMIO_COMPAT

File was opened with compatibility mode, allowing any process on a given machine to open the file any number of times.

MMIO_DENYNONE

Other processes are not denied read or write access to the file.

MMIO_DENYREAD

Other processes are denied read access to the file.

MMIO_DENYWRITE

Other processes are denied write access to the file.

MMIO_EXCLUSIVE

Other processes are denied read and write access to the file.

The following values may be set when the file is opened in read/write mode (identified by using the MMIO_RWMODE bit mask):

MMIO_READ

File was opened only for reading.

MMIO_READWRITE

File was opened for reading and writing.

MMIO_WRITE

File was opened only for writing.

fccIOProc

Four-character code identifying the file's I/O procedure. If the I/O procedure is not an installed I/O procedure, this member is NULL.

wErrorRet

Extended error value from the mmioOpen function if it returns NULL. This member is not used to return extended error information from any other functions.

hTask

Handle of a local I/O procedure. Media Control Interface (MCI) devices that perform file I/O in the background and need an I/O procedure can locate a local I/O procedure with this handle.

cchBuffer

Size, in bytes, of the file's I/O buffer. If the file does not have an I/O buffer, this member is zero.

pchBuffer

Address of the file's I/O buffer. If the file is unbuffered, this member is NULL.

pchNext

Address of the next location in the I/O buffer to be read or written. If no more bytes can be read without calling the mmioAdvance or mmioRead function, this member points to the pchEndRead member. If no more bytes can be written without calling the mmioAdvance or mmioWrite function, this member points to the pchEndWrite member.

pchEndRead

Address of the location that is 1 byte past the last location in the buffer that can be read.

pchEndWrite

Address of the location that is 1 byte past the last location in the buffer that can be written.

lDiskOffset

Current file position, which is an offset, in bytes, from the beginning of the file. I/O procedures are responsible for maintaining this member.

adwInfo

State information maintained by the I/O procedure. I/O procedures can also use these members to transfer information from the application to the I/O procedure when the application opens a file.

hmmio

Handle of the open file, as returned by the mmioOpen function. I/O procedures can use this handle when calling other multimedia file I/O functions.


MMIOM_CLOSE

MMIOM_CLOSE

lParam1 = (LPARAM) lCloseFlags

lParam2 = reserved

Sent to an I/O procedure by the mmioClose function to request that a file be closed.

•	Returns zero if the file is successfully closed or an error otherwise.

lCloseFlags

Flags contained in the wFlags parameter of mmioClose.


MMIOM_OPEN

MMIOM_OPEN

lParam1 = (LPARAM) lpszFileName

lParam2 = reserved

Sent to an I/O procedure by the mmioOpen function to request that a file be opened or deleted.

•	Returns MMSYSERR_NOERROR if successful or an error otherwise. Possible error values include the following:

MMIOM_CANNOTOPEN	The file could not be opened.
MMIOM_OUTOFMEMORY	Not enough memory to perform the operation.
lpszFileName

Null-terminated string containing the name of the file to open.

The dwFlags member of the MMIOINFO structure contains flags passed to the mmioOpen function.

The lDiskOffset member of the MMIOINFO structure is initialized to zero. If this value is incorrect, the I/O procedure must correct it.

If the application passed an MMIOINFO structure to mmioOpen, the return value is returned in the wErrorRet member.


MMIOM_READ

MMIOM_READ

lParam1 = (LPARAM) lBuffer // see below

lParam2 = (LPARAM) cbRead  // number of bytes to read from file

Sent to an I/O procedure by the mmioRead function to request that a specified number of bytes be read from an open file.

•	Returns the number of bytes actually read from the file. If no more bytes can be read, the return value is 0. If there is an error, the return value is − 1.

lBuffer

Address of the buffer to be filled with data read from the file.

The I/O procedure is responsible for updating the lDiskOffset member of the MMIOINFO structure to reflect the new file position after the read operation.


MMIOM_RENAME

MMIOM_RENAME

lParam1 = (LPARAM) lpszOldFilename

lParam2 = (LPARAM) lpszNewFilename

Sent to an I/O procedure by the mmioRename function to request that the specified file be renamed.

•	If the file is renamed successfully, the return value is zero. If the specified file was not found, the return value is MMIOERR_FILENOTFOUND.

lpszOldFilename

Address of a string containing the filename of the file to rename.

lpszNewFilename

Address of a string containing the new filename.


MMIOM_SEEK

MMIOM_SEEK

lParam1 = (LPARAM) lNewFilePos

lParam2 = (LPARAM) lChangeFlag

Sent to an I/O procedure by the mmioSeek function to request that the current file position be moved.

•	Returns the new file position. If there is an error, the return value is − 1.

lNewFilePos

New file position. The meaning of this value is dependent on the flag specified in lChangeFlag.

lChangeFlag

Flag specifying how the file position is changed. The following values are defined:

SEEK_CUR

Move the file position to be lNewFilePos bytes from the current position. NewFilePos can be positive or negative.

SEEK_END

Move the file position to be lNewFilePos bytes from the end of the file.

SEEK_SET

Move the file position to be lNewFilePos bytes from the beginning of the file.

The I/O procedure is responsible for maintaining the current file position in the lDiskOffset member of the MMIOINFO structure.


MMIOM_WRITE

MMIOM_WRITE

lParam1 = (LPARAM) lpBuffer // see below

lParam2 = (LPARAM) cbWrite  // number of bytes to write to file

Sent to an I/O procedure by the mmioWrite function to request that data be written to an open file.

•	Returns the number of bytes actually written to the file. If there is an error, the return value is − 1.

lpBuffer

Address of a buffer containing the data to write to the file.

The I/O procedure is responsible for updating the lDiskOffset member of the MMIOINFO structure to reflect the new file position after the write operation.


MMIOM_WRITEFLUSH

MMIOM_WRITEFLUSH

lParam1 = (LPARAM) lpBuffer // see below

lParam2 = (LPARAM) cbWrite  // number of bytes to write to file

Sent to an I/O procedure by the mmioWrite function to request that data be written to an open file and that any internal buffers used by the I/O procedure be flushed to disk.

•	Returns the number of bytes actually written to the file. If there is an error, the return value is − 1.

lpBuffer

Address of a buffer containing the data to write to the file.

The I/O procedure is responsible for updating the lDiskOffset member of the MMIOINFO structure to reflect the new file position after the write operation.

This message is equivalent to the MMIOM_WRITE message except that it requests that the I/O procedure flush its internal buffers, if any. Unless an I/O procedure performs internal buffering, this message can be handled exactly like the MMIOM_WRITE message.


Joysticks

The Win32 application programming interface supports ancillary input devices for applications that provide alternatives to using the keyboard and mouse. The joystick is one such device. The joystick provides positional information within a coordinate system that has absolute maximum and minimum values in each axis of movement.

This chapter describes the Win32 functions and messages that support joysticks, as well as other ancillary input devices that track positions within an absolute coordinate system, such as a touch screen, digitizing tablet, and light pen. Extended capabilities also provide support for rudder pedals, flight yokes, and other devices that use up to six axes of movement, a point-of-view hat, and 32 buttons.

Joystick services are loaded when the operating system is started. The joystick services can simultaneously monitor two joysticks, each with two- or three-axis movement. Each joystick can have up to four buttons. You can use the joystick functions to determine the capabilities of the joysticks and joystick driver. Also, you can process a joystick's positional and button information by querying the joystick directly or by capturing the joystick and processing messages from it. The latter method is simpler because your application does not have to manually query the joystick or track the time to generate queries at regular intervals.


Joystick Capabilities

Joysticks can support two- or three-axis movement and up to four buttons. Joysticks also support different ranges of motion and polling frequencies. The range of motion is the distance a joystick handle can move from its resting position to the position farthest from its resting position. The polling frequency is the time interval between joystick queries.

Joystick drivers can support either one or two joysticks. You can determine the number of joysticks supported by a joystick driver by using the joyGetNumDevs function. This function returns an unsigned integer that contains the number of supported joysticks or zero if there is no joystick support. The return value does not indicate the number of joysticks attached to the system.

You can determine if a joystick is attached to the system by using the joyGetPos function. This function returns JOYERR_NOERROR if the specified device is attached or JOYERR_UNPLUGGED otherwise.

Each joystick has several capabilities that are available to your application. You can retrieve the capabilities of a joystick by using the joyGetDevCaps function. This function fills a JOYCAPS structure with joystick capabilities such as the minimum and maximum values for its coordinate system, the number of buttons on the joystick, and the minimum and maximum polling frequencies.


Joystick Position

You can query a joystick for position and button information by using the joyGetPos function. For example, an application can query the joystick for baseline position values. The Joystick Control Panel property sheet uses this technique when calibrating the joystick.

You can also query a joystick or other device that has extended capabilities by using the joyGetPosEx function.


Joystick Notifications

You can capture direct joystick messages to be sent to a function by using the joySetCapture function. Only one application at a time can capture messages from a joystick, but you can query the joystick from another application by using the joyGetPos or joyGetPosEx function.

Note  A joystick message can fail to reach the application that captured the joystick if a second application uses joyGetPos or joyGetPosEx to query the joystick near the same time that the message is sent. In this case, the second application might intercept the message.

If you want to capture messages from two joysticks attached to the system, use joySetCapture twice, once for each joystick. Your window receives separate and distinct messages for each device.

You can release a captured joystick by using the joyReleaseCapture function. If an application does not release the joystick before ending, the joystick is automatically released shortly after the capture window is destroyed.

You cannot capture an unplugged joystick. The joySetCapture function returns JOYERR_UNPLUGGED if the specified device is unplugged.


Time-Based Notifications

You can notify the Microsoft Windows operating system to send joystick messages to an application at regular time intervals by setting the fChanged parameter of joySetCapture to FALSE and by specifying the interval length between successive messages. Assign the uPeriod parameter a value between the minimum and maximum polling frequencies for the joystick. You can determine this range by using the joyGetDevCaps function, which fills the wPeriodMin and wPeriodMax members in the JOYCAPS structure. If the uPeriod value is outside the range of valid polling frequencies for the joystick, the joystick driver uses the minimum or maximum polling frequency, whichever is closer to the uPeriod value.

Note  Windows sets up a timer event with each call to joySetCapture.


Event-Based Notifications

You can notify Windows to send joystick messages to an application whenever the position of a joystick axis changes by a value greater than the movement threshold of the device. The movement threshold is the distance the joystick must be moved before a WM_JOYMOVE message is sent to a window that has captured the device. The threshold is initially zero. You can set the movement threshold by using the joySetThreshold function. You can retrieve the minimum polling frequency of the joystick by using the joyGetDevCaps function.


Joystick Notification Messages

Joystick messages notify your application that a joystick has changed position or that one of its buttons has changed states. Messages beginning with MM_JOY1 are sent to the function if your application requests input from the joystick using the identifier JOYSTICKID1, and MM_JOY2 messages are sent if your application requests input from the joystick using the identifier JOYSTICKID2.

The messages in the following table identify the status of the joystick buttons:

Message	Description
MM_JOY1BUTTONDOWN	A button of joystick JOYSTICKID1 has been pressed.
MM_JOY1BUTTONUP	A button of joystick JOYSTICKID1 has been released.
MM_JOY1MOVE	Joystick JOYSTICKID1 changed position in the x- or y-direction.
MM_JOY1ZMOVE	Joystick JOYSTICKID1 changed position in the z-direction.
MM_JOY2BUTTONDOWN	A button of joystick JOYSTICKID2 has been pressed.
MM_JOY2BUTTONUP	A button of joystick JOYSTICKID2 has been released.
MM_JOY2MOVE	Joystick JOYSTICKID2 changed position in the x- or y-direction
MM_JOY2ZMOVE	Joystick JOYSTICKID2 changed position in the z-direction.
All messages report nonexistent buttons as released.


Using Joysticks

This section contains examples demonstrating how to perform the following tasks:

•	Get the driver capabilities.

•	Capture joystick input.

•	Process joystick messages.

The examples are taken from a simple joystick application that gets position and button-state information from the joystick services, plays waveform-audio resources, and paints bullet holes on the screen when a user presses the joystick buttons.


Getting the Driver Capabilities

The following example determines whether the joystick services are available and if a joystick is attached to one of the ports.

JOYINFO joyinfo;

UINT wNumDevs, wDeviceID;

BOOL bDev1Attached, bDev2Attached;

    if((wNumDevs = joyGetNumDevs()) == 0)

        return ERR_NODRIVER;

    bDev1Attached = joyGetPos(JOYSTICKID1,&joyinfo) != JOYERR_UNPLUGGED;

    bDev2Attached = wNumDevs == 2 && joyGetPos(JOYSTICKID2,&joyinfo) !=

        JOYERR_UNPLUGGED;

    if(bDev1Attached || bDev2Attached)   // decide which joystick to use

        wDeviceID = bDev1Attached ? JOYSTICKID1 : JOYSTICKID2;

    else

        return ERR_NODEVICE;


Capturing Joystick Input

Most of the code controlling the joystick is in the main window function. In the following portion of the message handler, the application captures input from the joystick JOYSTICKID1.

case WM_CREATE:

    if(joySetCapture(hWnd, JOYSTICKID1, NULL, FALSE))

    {

        MessageBeep(MB_ICONEXCLAMATION);

        MessageBox(hWnd, "Couldn't capture the joystick.", NULL,

            MB_OK | MB_ICONEXCLAMATION);

        PostMessage(hWnd,WM_CLOSE,0,0L);

    }

    break;


Processing Joystick Messages

The following example illustrates how an application might respond to joystick movements and changes in the button states. When the joystick changes position, the application moves the cursor and, if either button is pressed, draws a bullet hole on the desktop. When a joystick button is pressed, the application draws a hole on the desktop and plays a sound continuously until a button is released.

case MM_JOY1MOVE :                     // changed position

    if((UINT) wParam & (JOY_BUTTON1 | JOY_BUTTON2))

        DrawFire(hWnd);

    DrawSight(lParam);                 // calculates new cursor position

    break;

case MM_JOY1BUTTONDOWN :               // button is down

    if((UINT) wParam & JOY_BUTTON1)

    {

        PlaySound(lpButton1, SND_LOOP | SND_ASYNC | SND_MEMORY);

        DrawFire(hWnd);

    }

    else if((UINT) wParam & JOY_BUTTON2)

    {

        PlaySound(lpButton2, SND_ASYNC | SND_MEMORY |  SND_LOOP);

        DrawFire(hWnd);

    }

    break;

case MM_JOY1BUTTONUP :                 // button is up

    sndPlaySound(NULL, 0);             // stops the sound

    break;


Joystick Reference

This section describes the functions, structures, and messages associated with joysticks. The elements are grouped as follows:

Device Capabilities

joyGetDevCaps
joyGetNumDevs
JOYCAPS

Querying a Joystick

joyGetPos
joyGetPosEx
JOYINFO
JOYINFOEX

Capturing a Joystick

joyGetThreshold
joyReleaseCapture
joySetCapture
joySetThreshold
MM_JOY1BUTTONDOWN
MM_JOY1BUTTONUP
MM_JOY1MOVE
MM_JOY1ZMOVE
MM_JOY2BUTTONDOWN
MM_JOY2BUTTONUP
MM_JOY2MOVE
MM_JOY2ZMOVE


Joystick Functions

An application uses the joystick functions to query a joystick driver and to prepare an application to receive notification messages from a joystick driver.


joyGetDevCaps [New - Windows 95]
joyGetDevCaps

[New - Windows 95]

MMRESULT joyGetDevCaps(UINT uJoyID, LPJOYCAPS pjc, UINT cbjc);

Queries a joystick to determine its capabilities.

•	Returns JOYERR_NOERROR if successful or one of the following error values:

MMSYSERR_NODRIVER	The joystick driver is not present.
MMSYSERR_INVALPARAM	An invalid parameter was passed.
uJoyID

Identifier of the joystick (JOYSTICKID1 or JOYSTICKID2) to be queried.

pjc

Address of a JOYCAPS structure to contain the capabilities of the joystick.

cbjc

Size, in bytes, of the JOYCAPS structure.

Use the joyGetNumDevs function to determine the number of joystick devices supported by the driver.


joyGetNumDevs [New - Windows 95]
joyGetNumDevs

[New - Windows 95]

UINT joyGetNumDevs(VOID);

Queries the joystick driver for the number of joysticks it supports.

•	Returns the number of joysticks supported by the joystick driver or zero if no driver is present.

Use the joyGetPos function to determine whether a given joystick is physically attached to the system. If the specified joystick is not connected, joyGetPos returns a JOYERR_UNPLUGGED error value.


joyGetPos [New - Windows 95]
joyGetPos

[New - Windows 95]

MMRESULT joyGetPos(UINT uJoyID, LPJOYINFO pji);

Queries a joystick for its position and button status.

•	Returns JOYERR_NOERROR if successful or one of the following error values:

MMSYSERR_NODRIVER	The joystick driver is not present.
MMSYSERR_INVALPARAM	An invalid parameter was passed.
JOYERR_UNPLUGGED	The specified joystick is not connected to the system.
uJoyID

Identifier of the joystick (JOYSTICKID1 or JOYSTICKID2) to be queried.

pji

Address of a JOYINFO structure that contains the position and button status of the joystick.

For devices that have four to six axes of movement, a point-of-view control, or more than four buttons, use the joyGetPosEx function.


joyGetPosEx [New - Windows 95]
joyGetPosEx

[New - Windows 95]

MMRESULT joyGetPosEx(UINT uJoyID, LPJOYINFOEX pji);

Queries a joystick for its position and button status.

•	Returns JOYERR_NOERROR if successful or one of the following error values:

MMSYSERR_NODRIVER	The joystick driver is not present.
MMSYSERR_INVALPARAM	An invalid parameter was passed.
MMSYSERR_BADDEVICEID	The specified joystick identifier is invalid.
JOYERR_UNPLUGGED	The specified joystick is not connected to the system.
uJoyID

Identifier of the joystick (JOYSTICKID1 or JOYSTICKID2) to be queried.

pji

Address of a JOYINFOEX structure that contains extended position information and button status of the joystick.

This function provides access to extended devices such as rudder pedals, point-of-view hats, devices with a large number of buttons, and coordinate systems using up to six axes. For joystick devices that use three axes or fewer and have fewer than four buttons, use the joyGetPos function.


joyGetThreshold [New - Windows 95]
joyGetThreshold

[New - Windows 95]

MMRESULT joyGetThreshold(UINT uJoyID, LPUINT puThreshold);

Queries a joystick for its current movement threshold.

•	Returns JOYERR_NOERROR if successful or one of the following error values:

MMSYSERR_NODRIVER	The joystick driver is not present.
MMSYSERR_INVALPARAM	An invalid parameter was passed.
uJoyID

Identifier of the joystick (JOYSTICKID1 or JOYSTICKID2) to be queried.

puThreshold

Address of a variable that contains the movement threshold value.

The movement threshold is the distance the joystick must be moved before a WM_JOYMOVE message is sent to a window that has captured the device. The threshold is initially zero.


joyReleaseCapture [New - Windows 95]
joyReleaseCapture

[New - Windows 95]

MMRESULT joyReleaseCapture(UINT uJoyID);

Releases the specified captured joystick.

•	Returns JOYERR_NOERROR if successful or one of the following error values:

MMSYSERR_NODRIVER	The joystick driver is not present.
JOYERR_PARMS	The specified joystick device identifier uJoyID is invalid.
uJoyID

Identifier of the joystick (JOYSTICKID1 or JOYSTICK2) to be released.


joySetCapture [New - Windows 95]
joySetCapture

[New - Windows 95]

MMRESULT joySetCapture(HWND hwnd, UINT uJoyID, UINT uPeriod,

    BOOL fChanged);

Captures a joystick by causing its messages to be sent to the specified window.

•	Returns JOYERR_NOERROR if successful or one of the following error values:

MMSYSERR_NODRIVER	The joystick driver is not present.
JOYERR_NOCANDO	Cannot capture joystick input because a required service (such as a Windows timer) is unavailable.
JOYERR_UNPLUGGED	The specified joystick is not connected to the system.
hwnd

Handle of the window to receive the joystick messages.

uJoyID

Identifier of the joystick (JOYSTICKID1 or JOYSTICKID2) to be captured.

uPeriod

Polling frequency, in milliseconds.

fChanged

Change position flag. Specify TRUE for this parameter to send messages only when the position changes by a value greater than the joystick movement threshold. Otherwise, messages are sent at the polling frequency specified in uPeriod.

This function fails if the specified joystick is currently captured. Call the joyReleaseCapture function to release the captured joystick, or destroy the window to release the joystick automatically.


joySetThreshold [New - Windows 95]
joySetThreshold

[New - Windows 95]

MMRESULT joySetThreshold(UINT uJoyID, UINT uThreshold);

Sets the movement threshold of a joystick.

•	Returns JOYERR_NOERROR if successful or one of the following error values:

MMSYSERR_NODRIVER	The joystick driver is not present.
JOYERR_PARMS	The specified joystick device identifier uJoyID is invalid.
uJoyID

Identifier of the joystick (JOYSTICKID1 or JOYSTICKID2).

uThreshold

New movement threshold.

The movement threshold is the distance the joystick must be moved before a WM_JOYMOVE message is sent to a window that has captured the device. The threshold is initially zero.


Joystick Messages

A joystick device driver sends the following messages to notify an application that a joystick has changed position or one of its buttons has changed states.


MM_JOY1BUTTONDOWN [New - Windows 95]
MM_JOY1BUTTONDOWN

[New - Windows 95]

MM_JOY1BUTTONDOWN

fwButtons = wParam;

xPos = LOWORD(lParam);

yPos = HIWORD(lParam);

Notifies the window that has captured joystick JOYSTICKID1 that a button has been pressed.

fwButtons

Identifies the button that has changed state and the buttons that are pressed. It can be one of the following:

JOY_BUTTON1CHG	First joystick button has changed state.
JOY_BUTTON2CHG	Second joystick button has changed state.
JOY_BUTTON3CHG	Third joystick button has changed state.
JOY_BUTTON4CHG	Fourth joystick button has changed state.
and one or more of the following:

JOY_BUTTON1	First joystick button is pressed.
JOY_BUTTON2	Second joystick button is pressed.
JOY_BUTTON3	Third joystick button is pressed.
JOY_BUTTON4	Fourth joystick button is pressed.
xPos and yPos

The x- and y-coordinates of the joystick relative to the upper left corner of the client area.


MM_JOY1BUTTONUP [New - Windows 95]
MM_JOY1BUTTONUP

[New - Windows 95]

MM_JOY1BUTTONUP

fwButton = wParam;

xPos = LOWORD(lParam);

yPos = HIWORD(lParam);

Notifies the window that has captured joystick JOYSTICKID1 that a button has been released.

fwButtons

Identifies the button that has changed state and the buttons that are pressed. It can be one of the following:

JOY_BUTTON1CHG	First joystick button has changed state.
JOY_BUTTON2CHG	Second joystick button has changed state.
JOY_BUTTON3CHG	Third joystick button has changed state.
JOY_BUTTON4CHG	Fourth joystick button has changed state.
and one or more of the following:

JOY_BUTTON1	First joystick button is pressed.
JOY_BUTTON2	Second joystick button is pressed.
JOY_BUTTON3	Third joystick button is pressed.
JOY_BUTTON4	Fourth joystick button is pressed.
xPos and yPos

The x- and y-coordinates of the joystick relative to the upper left corner of the client area.


MM_JOY1MOVE [New - Windows 95]
MM_JOY1MOVE

[New - Windows 95]

MM_JOY1MOVE

fwButtons = wParam;

xPos = LOWORD(lParam);

yPos = HIWORD(lParam);

Notifies the window that has captured joystick JOYSTICKID1 that the joystick position has changed.

fwButtons

Identifies the buttons that are pressed. It can be one or more of the following values:

JOY_BUTTON1	First joystick button is pressed.
JOY_BUTTON2	Second joystick button is pressed.
JOY_BUTTON3	Third joystick button is pressed.
JOY_BUTTON4	Fourth joystick button is pressed.
xPos and yPos

The x- and y-coordinates of the joystick relative to the upper left corner of the client area.


MM_JOY1ZMOVE [New - Windows 95]
MM_JOY1ZMOVE

[New - Windows 95]

MM_JOY1ZMOVE

fwButtons = wParam;

zPos = LOWORD(lParam);

Notifies the window that has captured joystick JOYSTICKID1 that the joystick position on the z-axis has changed.

fwButtons

Identifies the buttons that are pressed. It can be one or more of the following values:

JOY_BUTTON1	First joystick button is pressed.
JOY_BUTTON2	Second joystick button is pressed.
JOY_BUTTON3	Third joystick button is pressed.
JOY_BUTTON4	Fourth joystick button is pressed.
zPos

The z-coordinate of the joystick.


MM_JOY2BUTTONDOWN [New - Windows 95]
MM_JOY2BUTTONDOWN

[New - Windows 95]

MM_JOY2BUTTONDOWN

fwButtons = wParam;

xPos = LOWORD(lParam);

yPos = HIWORD(lParam);

Notifies the window that has captured joystick JOYSTICKID2 that a button has been pressed.

fwButtons

Identifies the button that has changed state and the buttons that are pressed. It can be one of the following:

JOY_BUTTON1CHG	First joystick button has changed state.
JOY_BUTTON2CHG	Second joystick button has changed state.
JOY_BUTTON3CHG	Third joystick button has changed state.
JOY_BUTTON4CHG	Fourth joystick button has changed state.
and one or more of the following:

JOY_BUTTON1	First joystick button is pressed.
JOY_BUTTON2	Second joystick button is pressed.
JOY_BUTTON3	Third joystick button is pressed.
JOY_BUTTON4	Fourth joystick button is pressed.
xPos and yPos

The x- and y-coordinates of the joystick relative to the upper left corner of the client area.


MM_JOY2BUTTONUP [New - Windows 95]
MM_JOY2BUTTONUP

[New - Windows 95]

MM_JOY2BUTTONUP

fwButton = wParam;

xPos = LOWORD(lParam);

yPos = HIWORD(lParam);

Notifies the window that has captured joystick JOYSTICKID2 that a button has been released.

fwButtons

Identifies the button that has changed state and the buttons that are pressed. It can be one of the following:

JOY_BUTTON1CHG	First joystick button has changed state.
JOY_BUTTON2CHG	Second joystick button has changed state.
JOY_BUTTON3CHG	Third joystick button has changed state.
JOY_BUTTON4CHG	Fourth joystick button has changed state.
and one or more of the following:

JOY_BUTTON1	First joystick button is pressed.
JOY_BUTTON2	Second joystick button is pressed.
JOY_BUTTON3	Third joystick button is pressed.
JOY_BUTTON4	Fourth joystick button is pressed.
xPos and yPos

The x- and y-coordinates of the joystick relative to the upper left corner of the client area.


MM_JOY2MOVE [New - Windows 95]
MM_JOY2MOVE

[New - Windows 95]

MM_JOY2MOVE

fwButtons = wParam;

xPos = LOWORD(lParam);

yPos = HIWORD(lParam);

Notifies the window that has captured joystick JOYSTICKID2 that the joystick position has changed.

fwButtons

Identifies the buttons that are pressed. It can be one or more of the following values:

JOY_BUTTON1	First joystick button is pressed.
JOY_BUTTON2	Second joystick button is pressed.
JOY_BUTTON3	Third joystick button is pressed.
JOY_BUTTON4	Fourth joystick button is pressed.
xPos and yPos

The x- and y-coordinates of the joystick relative to the upper left corner of the client area.


MM_JOY2ZMOVE [New - Windows 95]
MM_JOY2ZMOVE

[New - Windows 95]

MM_JOY2ZMOVE

fwButtons = wParam;

zPos = LOWORD(lParam);

Notifies the window that has captured joystick JOYSTICKID2 that the joystick position on the z-axis has changed.

fwButtons

Identifies the buttons that are pressed. It can be one or more of the following values:

JOY_BUTTON1	First joystick button is pressed.
JOY_BUTTON2	Second joystick button is pressed.
JOY_BUTTON3	Third joystick button is pressed.
JOY_BUTTON4	Fourth joystick button is pressed.
zPos

The z-coordinate of the joystick.


Joystick Structures

The following structures store information about the capabilities of a joystick or its current position and button states.


JOYCAPS [New - Windows 95]
JOYCAPS

[New - Windows 95]

typedef struct {

    WORD wMid;                  \\ manufacturer identifier

    WORD wPid;                  \\ product identifier

    CHAR szPname[MAXPNAMELEN];  \\ see below

    UINT wXmin;                 \\ min. x-coordinate

    UINT wXmax;                 \\ max. x-coordinate

    UINT wYmin;                 \\ min. y-coordinate

    UINT wYmax;                 \\ max. y-coordinate

    UINT wZmin;                 \\ min. z-coordinate

    UINT wZmax;                 \\ max. z-coordinate

    UINT wNumButtons;           \\ no. of joystick buttons

    UINT wPeriodMin;            \\ see below

    UINT wPeriodMax;            \\ see below

\\  The following members are not in previous versions of Windows.

    UINT wRmin;                 \\ see below

    UINT wRmax;                 \\ see below

    UINT wUmin;                 \\ see below

    UINT wUmax;                 \\ see below

    UINT wVmin;                 \\ see below

    UINT wVmax;                 \\ see below

    UINT wCaps;                 \\ see below

    UINT wMaxAxes;              \\ see below

    UINT wNumAxes;              \\ see below

    UINT wMaxButtons;           \\ see below

    CHAR szRegKey[MAXPNAMELEN]; \\ see below

    CHAR szOEMVxD[MAXOEMVXD];   \\ see below

} JOYCAPS;

Contains information about the joystick capabilities.

szPname

Null-terminated string containing the joystick product name.

wPeriodMin

Smallest polling frequency supported when captured by the joySetCapture function.

wPeriodMax

Largest polling frequency supported when captured by joySetCapture.

wRmin and wRmax

Minimum and maximum rudder values. The rudder is a fourth axis of movement.

wUmin and wUmax

Minimum and maximum u-coordinate (fifth axis) values.

wVmin and wVmax

Minimum and maximum v-coordinate (sixth axis) values.

wCaps

Joystick capabilities The following flags define individual capabilities that a joystick might have:

JOYCAPS_HASZ	Joystick has z-coordinate information.
JOYCAPS_HASR	Joystick has rudder (fourth axis) information.
JOYCAPS_HASU	Joystick has u-coordinate (fifth axis) information.
JOYCAPS_HASV	Joystick has v-coordinate (sixth axis) information.
JOYCAPS_HASPOV	Joystick has point-of-view information.
JOYCAPS_POV4DIR	Joystick point-of-view supports discrete values (centered, forward, backward, left, and right).
JOYCAPS_POVCTS	Joystick point-of-view supports continuous degree bearings.
wMaxAxes

Maximum number of axes supported by the joystick.

wNumAxes

Number of axes currently in use by the joystick.

wMaxButtons

Maximum number of buttons supported by the joystick.

szRegKey

Null-terminated string containing the registry key for the joystick.

szOEMVxD

Null-terminated string identifying the joystick driver OEM.


JOYINFO [New - Windows 95]
JOYINFO

[New - Windows 95]

typedef struct {

    UINT wXpos;     \\ current x-coordinate

    UINT wYpos;     \\ current y-coordinate

    UINT wZpos;     \\ current z-coordinate

    UINT wButtons;  \\ see below

} JOYINFO;

Contains information about the joystick position and button state.

wButtons

Current state of joystick buttons described by one or more of the following values:

JOY_BUTTON1	First joystick button is pressed.
JOY_BUTTON2	Second joystick button is pressed.
JOY_BUTTON3	Third joystick button is pressed.
JOY_BUTTON4	Fourth joystick button is pressed.


JOYINFOEX [New - Windows 95]
JOYINFOEX

[New - Windows 95]

typedef struct joyinfoex_tag {

    DWORD dwSize;         \\ size, in bytes, of this structure

    DWORD dwFlags;        \\ see below

    DWORD dwXpos;         \\ current x-coordinate

    DWORD dwYpos;         \\ current y-coordinate

    DWORD dwZpos;         \\ current z-coordinate

    DWORD dwRpos;         \\ see below

    DWORD dwUpos;         \\ current 5th axis position

    DWORD dwVpos;         \\ current 6th axis position

    DWORD dwButtons;      \\ see below

    DWORD dwButtonNumber; \\ see below

    DWORD dwPOV;          \\ see below

    DWORD dwReserved1;    \\ reserved; do not use

    DWORD dwReserved2;    \\ reserved; do not use

} JOYINFOEX;

Contains extended information about the joystick position, point-of-view position, and button state.

dwFlags

Flags indicating the valid information returned in this structure. Members that do not contain valid information are set to zero. The following flags are defined:

JOY_RETURNALL	Equivalent to setting all of the JOY_RETURN bits except JOY_RETURNRAWDATA.
JOY_RETURNBUTTONS	The dwButtons member contains valid information about the state of each joystick button.
JOY_RETURNCENTERED	Centers the joystick neutral position to the middle value of each axis of movement.
JOY_RETURNPOV	The dwPOV member contains valid information about the point-of-view control, expressed in discrete units.
JOY_RETURNPOVCTS	The dwPOV member contains valid information about the point-of-view control expressed in continuous, one-hundredth degree units.
JOY_RETURNR	The dwRpos member contains valid rudder pedal data. This information represents another (fourth) axis.
JOY_RETURNRAWDATA	Data stored in this structure is uncalibrated joystick readings.
JOY_RETURNU	The dwUpos member contains valid data for a fifth axis of the joystick, if such an axis is available, or returns zero otherwise.
JOY_RETURNV	The dwVpos member contains valid data for a sixth axis of the joystick, if such an axis is available, or returns zero otherwise.
JOY_RETURNX	The dwXpos member contains valid data for the x-coordinate of the joystick.
JOY_RETURNY	The dwYpos member contains valid data for the y-coordinate of the joystick.
JOY_RETURNZ	The dwZpos member contains valid data for the z-coordinate of the joystick.
JOY_USEDEADZONE	Expands the range for the neutral position of the joystick and calls this range the dead zone. The joystick driver returns a constant value for all positions in the dead zone.
The following flags provide data to calibrate a joystick and are intended for custom calibration applications.

JOY_CAL_READ3	Read the x-, y-, and z-coordinates and store the raw values in dwXpos, dwYpos, and dwZpos.
JOY_CAL_READ4	Read the rudder information and the x-, y-, and z-coordinates and store the raw values in dwXpos, dwYpos, dwZpos, and dwRpos.
JOY_CAL_READ5	Read the rudder information and the x-, y-, z-, and u-coordinates and store the raw values in dwXpos, dwYpos, dwZpos, dwRpos, and dwUpos.
JOY_CAL_READ6	Read the raw v-axis data if a joystick mini driver is present that will provide the data. Returns zero otherwise.
JOY_CAL_READALWAYS	Read the joystick port even if the driver does not detect a device.
JOY_CAL_READRONLY	Read the rudder information if a joystick mini-driver is present that will provide the data and store the raw value in dwRpos. Return zero otherwise.
JOY_CAL_READXONLY	Read the x-coordinate and store the raw (uncalibrated) value in dwXpos.
JOY_CAL_READXYONLY	Reads the x- and y-coordinates and place the raw values in dwXpos and dwYpos.
JOY_CAL_READYONLY	Reads the y-coordinate and store the raw value in dwYpos.
JOY_CAL_READZONLY	Read the z-coordinate and store the raw value in dwZpos.
JOY_CAL_READUONLY	Read the u-coordinate if a joystick mini-driver is present that will provide the data and store the raw value in dwUpos. Return zero otherwise.
JOY_CAL_READVONLY	Read the v-coordinate if a joystick mini-driver is present that will provide the data and store the raw value in dwVpos. Return zero otherwise.
dwRpos

Current position of the rudder or fourth joystick axis.

dwButtons

Current state of the 32 joystick buttons. The value of this member can be set to any combination of JOY_BUTTONn flags, where n is a value in the range of 1 through 32 corresponding to the button that is pressed.

dwButtonNumber

Current button number that is pressed.

dwPOV

Current position of the point-of-view control. Values for this member are in the range 0 through 35,900. These values represent the angle, in degrees, of each view multiplied by 100.

The value of the dwSize member is also used to identify the version number for the structure when it's passed to the joyGetPosEx function.

Most devices with a point-of-view control have only five positions. When the JOY_RETURNPOV flag is set, these positions are reported by using the following constants:

Point-of-view flags	Description
JOY_POVBACKWARD	Point-of-view hat is pressed backward. The value 18,000 represents an orientation of 180.00 degrees (to the rear).
JOY_POVCENTERED	Point-of-view hat is in the neutral position. The value -1 means the point-of-view hat has no angle to report.
JOY_POVFORWARD	Point-of-view hat is pressed forward. The value 0 represents an orientation of 0.00 degrees (straight ahead).
JOY_POVLEFT	Point-of-view hat is being pressed to the left. The value 27,000 represents an orientation of 270.00 degrees (90.00 degrees to the left).
JOY_POVRIGHT	Point-of-view hat is pressed to the right. The value 9,000 represents an orientation of 90.00 degrees (to the right).
The default Windows 95 joystick driver currently supports these five discrete directions. If an application can accept only the defined point-of-view values, it must use the JOY_RETURNPOV flag. If an application can accept other degree readings, it should use the JOY_RETURNPOVCTS flag to obtain continuous data if it is available. The JOY_RETURNPOVCTS flag also supports the JOY_POV constants used with the JOY_RETURNPOV flag.


Multimedia Timers

Multimedia timer services allow applications to schedule timer events with the greatest resolution (or accuracy) possible for the hardware platform. These multimedia timer services allow you to schedule timer events at a higher resolution than through other timer services.

The multimedia timer services are useful for applications that demand high-resolution timing. For example, a MIDI sequencer requires a high-resolution timer because it must maintain the pace of MIDI events within a resolution of 1 millisecond.

Applications that do not use high-resolution timing should use the SetTimer function instead of multimedia timer services. The timer services provided by SetTimer post WM_TIMER messages to a message queue; the multimedia timer services call a callback function.

The multimedia timer services allow an application to schedule periodic timer events — that is, the application can request and receive timer messages at application-specified intervals.


Obtaining the System Time

Typically, before an application begins using the multimedia timer services, it retrieves the current system time. The system time is the time, in milliseconds, since the Microsoft Windows operating system was started. You can use the timeGetTime or timeGetSystemTime function to retrieve the system time. These two functions are very similar: timeGetTime returns the system time, and timeGetSystemTime fills an MMTIME structure with the system time.


Timer Resolution

You can use the timeGetDevCaps function to determine the minimum and maximum timer resolutions supported by the timer services. This function fills the wPeriodMin and wPeriodMax members of the TIMECAPS structure with the minimum and maximum resolutions. This range can vary across computers and Windows platforms.

After you determine the minimum and maximum available timer resolutions, you must establish the minimum resolution you want your application to use. Use the timeBeginPeriod and timeEndPeriod functions to set and clear this resolution. You must match each call to timeBeginPeriod with a call to timeEndPeriod, specifying the same minimum resolution in both calls. An application can make multiple timeBeginPeriod calls, as long as each call is matched with a call to timeEndPeriod.

In both functions, the uPeriod parameter indicates the minimum timer resolution, in milliseconds. You can specify any timer resolution value within the range supported by the timer.


Timer Event Operations

After you have established your application's timer resolution, you can start timer events by using the timeSetEvent function. This function returns a timer identifier that can be used to stop or identify timer events. One of the function's parameters is the address of a TimeProc callback function that is called when the timer event takes place.

There are two types of timer events: single and periodic. A single timer event occurs once, after a specified number of milliseconds. A periodic timer event occurs every time a specified number of milliseconds elapses. The interval between periodic events is called an event delay. Periodic timer events with an event delay of 10 milliseconds or less consume a significant portion of CPU resources.

The relationship between the resolution of a timer event and the length of the event delay is important in timer events. For example, if you specify a resolution of 5 and an event delay of 100, the timer services notify the callback function after an interval ranging from 95 to 105 milliseconds.

You can cancel an active timer event at any time by using the timeKillEvent function. Be sure to cancel any outstanding timers before freeing the memory containing the callback function.

Using Multimedia Timers

This section contains examples demonstrating how to perform the following tasks:

•	Obtain and set the timer resolution.

•	Start a single timer event.

•	Write a timer callback function.

•	Cancel a timer event.


Obtaining and Setting Timer Resolution

The following example calls the timeGetDevCaps function to determine the minimum and maximum timer resolutions supported by the timer services. Before it sets up any timer events, the example establishes the minimum timer resolution by using the timeBeginPeriod function.

#define TARGET_RESOLUTION 1         // 1-millisecond target resolution

TIMECAPS tc;
UINT     wTimerRes;

if (timeGetDevCaps(&tc, sizeof(TIMECAPS)) != TIMERR_NOERROR) {
    // Error; application can't continue.
}

wTimerRes = min(max(tc.wPeriodMin, TARGET_RESOLUTION), tc.wPeriodMax);
timeBeginPeriod(wTimerRes);


Starting a Single Timer Event

To start a single timer event, an application must specify the amount of time before the callback occurs, the resolution, the address of the callback function, and the user data to supply with the callback function. An application can use a function like the following to start a single timer event.

UINT SetTimerCallback(NPSEQ npSeq,  // sequencer data
    UINT msInterval)                // event interval
{

    npSeq->wTimerID = timeSetEvent(
        msInterval,                    // delay
        wTimerRes,                     // resolution (global variable)
        OneShotCallback,               // callback function
        (DWORD)npSeq,                  // user data
        TIME_ONESHOT );                // single timer event
    if(! npSeq->wTimerID)
        return ERR_TIMER;
    else
        return ERR_NOERROR;
}


Writing a Timer Callback Function

The following callback function invalidates the identifier for the single timer event and calls a timer routine to handle the application-specific tasks.

void FAR PASCAL OneShotTimer(UINT wTimerID, UINT msg,
    DWORD dwUser, DWORD dw1, DWORD dw2)

{

    NPSEQ npSeq;             // pointer to sequencer data
    npSeq = (NPSEQ)dwUser;
    npSeq->wTimerID = 0;     // invalidate timer ID (no longer in use)
    TimerRoutine(npSeq);     // handle tasks
}


Canceling a Timer Event

The application must cancel any outstanding timers before it frees the memory that contains the callback function. To cancel a timer event, it might call the following function.

void DestroyTimer(NPSEQ npSeq)
{
    if(npSeq->wTimerID) {                // is timer event pending?
        timeKillEvent(npSeq->wTimerID);  // cancel the event
        npSeq->wTimerID = 0;
    }
}


Timer Reference

This section describes the functions and structures associated with multimedia timer services. These elements are grouped as follows.

Retrieving the System Time

MMTIME
timeGetSystemTime
timeGetTime

Retrieving Timer Information

TIMECAPS
timeGetDevCaps

Time Events

timeKillEvent
TimeProc
timeSetEvent

Time Periods

timeBeginPeriod
timeEndPeriod


timeBeginPeriod

MMRESULT timeBeginPeriod(UINT uPeriod);

Sets the minimum timer resolution for an application or device driver.

•	Returns TIMERR_NOERROR if successful or TIMERR_NOCANDO if the resolution specified in uPeriod is out of range.

uPeriod

Minimum timer resolution, in milliseconds, for the application or device driver.

Call this function immediately before using timer services, and call the timeEndPeriod function immediately after you are finished using the timer services.

You must match each call to timeBeginPeriod with a call to timeEndPeriod, specifying the same minimum resolution in both calls. An application can make multiple timeBeginPeriod calls as long as each call is matched with a call to timeEndPeriod.


timeEndPeriod

MMRESULT timeEndPeriod(UINT uPeriod);

Clears a previously set minimum timer resolution.

•	Returns TIMERR_NOERROR if successful or TIMERR_NOCANDO if the resolution specified in uPeriod is out of range.

uPeriod

Minimum timer resolution specified in the previous call to the timeBeginPeriod function.

Call this function immediately after you are finished using timer services.

You must match each call to timeBeginPeriod with a call to timeEndPeriod, specifying the same minimum resolution in both calls. An application can make multiple timeBeginPeriod calls as long as each call is matched with a call to timeEndPeriod.


timeGetDevCaps

MMRESULT timeGetDevCaps(LPTIMECAPS ptc, UINT cbtc);

Queries the timer device to determine its resolution.

•	Returns TIMERR_NOERROR if successful or TIMERR_STRUCT if it fails to return the timer device capabilities.

ptc

Address of a TIMECAPS structure. This structure is filled with information about the resolution of the timer device.

cbtc

Size, in bytes, of the TIMECAPS structure.


timeGetSystemTime

MMRESULT timeGetSystemTime(LPMMTIME pmmt, UINT cbmmt);

Retrieves the system time, in milliseconds. The system time is the time elapsed since Windows was started. This function works very much like the timeGetTime function. See timeGetTime for details of these functions' operation.

•	Returns TIMERR_NOERROR. The system time is returned in the ms member of the MMTIME structure.

pmmt

Address of an MMTIME structure.

cbmmt

Size, in bytes, of the MMTIME structure.


timeGetTime

DWORD timeGetTime(VOID);

Retrieves the system time, in milliseconds. The system time is the time elapsed since Windows was started.

•	Returns the system time, in milliseconds.

The only difference between this function and the timeGetSystemTime function is that timeGetSystemTime uses the MMTIME structure to return the system time. The timeGetTime function has less overhead than timeGetSystemTime.

Note that the value returned by the timeGetTime function is a DWORD value. The return value wraps around to 0 every 2^32 milliseconds, which is about 49.71 days.This can cause problems in code that directly uses the timeGetTime return value in computations, particularly where the value is used to control code execution. You should always use the difference between two timeGetTime return values in computations.

Windows NT: The default precision of the timeGetTime function can be five milliseconds or more, depending on the machine. You can use the timeBeginPeriod and timeEndPeriod functions to increase the precision of timeGetTime. If you do so, the minimum difference between successive values returned by timeGetTime can be as large as the minimum period value set using timeBeginPeriod and timeEndPeriod. Use the QueryPerformanceCounter and QueryPerformanceFrequency functions to measure short time intervals at a high resolution,

Windows 95: The default precision of the timeGetTime function is 1 millisecond. In other words, the timeGetTime function can return successive values that differ by just 1 millisecond. This is true no matter what calls have been made to the timeBeginPeriod and timeEndPeriod functions.


timeKillEvent

MMRESULT timeKillEvent(UINT uTimerID);

Cancels a specified timer event.

•	Returns TIMERR_NOERROR if successful or MMSYSERR_INVALPARAM if the specified timer event does not exist.

uTimerID

Identifier of the timer event to cancel. This identifier was returned by the timeSetEvent function when the timer event was set up.


TimeProc

void CALLBACK TimeProc(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1,
    DWORD dw2);

Callback function that is called once upon the expiration of a single event or periodically upon the expiration of periodic events.

TimeProc is a placeholder for the application-defined function name.

uID

Identifier of the timer event. This identifier was returned by the timeSetEvent function when the timer event was set up.

uMsg

Reserved; do not use.

dwUser

User instance data supplied to the dwUser parameter of timeSetEvent.

dw1 and dw2

Reserved; do not use.

Applications should not call any system-defined functions from inside a callback function, except for PostMessage, timeGetSystemTime, timeGetTime, timeSetEvent, timeKillEvent, midiOutShortMsg, midiOutLongMsg, and OutputDebugString.


timeSetEvent

MMRESULT timeSetEvent(UINT uDelay, UINT uResolution,
    LPTIMECALLBACK lpTimeProc, DWORD dwUser, UINT fuEvent);

Starts a specified timer event. After the event is activated, it calls the specified callback function.

•	Returns an identifier for the timer event if successful or an error otherwise. This function returns NULL if it fails and the timer event was not created. (This identifier is also passed to the callback function.)

uDelay

Event delay, in milliseconds. If this value is not in the range of the minimum and maximum event delays supported by the timer, the function returns an error.

uResolution

Resolution of the timer event, in milliseconds. The resolution increases with smaller values; a resolution of 0 indicates periodic events should occur with the greatest possible accuracy. To reduce system overhead, however, you should use the maximum value appropriate for your application.

lpTimeProc

Address of a callback function that is called once upon expiration of a single event or periodically upon expiration of periodic events.

dwUser

User-supplied callback data.

fuEvent

Timer event type. The following values are defined:

TIME_ONESHOT

Event occurs once, after uDelay milliseconds.

TIME_PERIODIC

Event occurs every uDelay milliseconds.

Each call to timeSetEvent for periodic timer events must be matched with a call to the timeKillEvent function.


MMTIME

typedef struct mmtime_tag {

    UINT wType;

    union {              // start u union

        DWORD ms;        // see below

        DWORD sample;    // see below

        DWORD cb;        // see below

        DWORD ticks;     // see below

        struct {

            BYTE hour;   // hours

            BYTE min;    // minutes

            BYTE sec;    // seconds

            BYTE frame;  // frames

            BYTE fps;    // frames/sec. (24, 25, 29 (30 drop), or 30)

            BYTE dummy;  // dummy byte for alignment

            BYTE pad[2]  // more padding

        } smpte;

        struct {

            DWORD songptrpos;  // song pointer position

        } midi;

    } u;

} MMTIME;

Contains timing information for different types of multimedia data.

wType

Time format. It can be one of the following values:

TIME_BYTES	Current byte offset from beginning of the file.
TIME_MIDI	MIDI time.
TIME_MS	Time in milliseconds.
TIME_SAMPLES	Number of waveform-audio samples.
TIME_SMPTE	SMPTE (Society of Motion Picture and Television Engineers) time.
TIME_TICKS	Ticks within a MIDI stream.
ms

Number of milliseconds. Used when wType is TIME_MS.

sample

Number of samples. Used when wType is TIME_SAMPLES.

cb

Byte count. Used when wType is TIME_BYTES.

ticks

Ticks in MIDI stream. Used when wType is TIME_TICKS.

smpte

SMPTE time structure. Used when wType is TIME_SMPTE.

midi

MIDI time structure. Used when wType is TIME_MIDI.


TIMECAPS

typedef struct {

    UINT wPeriodMin;  \\ minimum supported resolution

    UINT wPeriodMax;  \\ maximum supported resolution

} TIMECAPS;

Contains information about the resolution of the timer.


Multimedia PC Specifications

The Multimedia PC (MPC) Marketing Council has developed two specifications to encourage the adoption of multimedia capabilities. The Level 1 specification, developed in 1990, provides a baseline definition of multimedia computing in functionality, hardware components, and software components. The Level 2 specification, issued in 1993, builds on the first specification and focuses on enhanced multimedia capabilities since the first specification was issued.

This appendix summarizes the specifications. For more information or complete specifications, contact the MPC Marketing Council at the following address:

Multimedia PC Marketing Council
1730 M Street NW, Suite 707
Washington, DC  20036


Level 1 Specification

The Level 1 specification was developed to encourage the adoption of basic multimedia capabilities at a minimum performance level. The most common multimedia components available to the marketplace when the Level 1 specification was issued included several compact disc − read-only memory (CD-ROM) drives that provided data at sustained transfer rates varying from 90 to 150 kilobytes per second, 8-bit sound cards, and 16-color and 256-color (SVGA) video adapters.


Level 1 System Resources

The minimum configuration for a PC to satisfy the Level 1 specification includes the following items:

•	A 386SX microprocessor with 2 megabytes (MB) of random-access memory (RAM)

•	A 3.5-inch high-density floppy disk drive

•	A hard disk drive with at least 30 MB of disk space

•	A color monitor with a display resolution of 640 by 480 pixels with 16 colors

•	System software that offers binary compatibility with the Microsoft Windows operating system version 3.0


Level 1 Optical Storage

The minimum performance optical storage device is a CD-ROM drive that meets the following criteria:

•	A sustained data transfer rate of 150 kilobytes per second

•	A CPU bandwidth usage of 40 percent or less when maintaining a sustained data transfer rate of 150 kilobytes per second

•	An average seek time of 1 second or less


Level 1 Audio Requirements

The audio subsystem of a PC satisfying the Level 1 specification includes the following items:

•	An 8-bit digital-to-analog converter (DAC) capable of processing waveform-audio files recorded at 22.05 and 11.025 kHz sampling rates

•	An 8-bit analog-to-digital converter (ADC) capable of recording waveform-audio files at the sample rate of 11.025 kHz through an external source, such as a microphone

•	Internal synthesizer capabilities with four or nine multivoice, multitimbral capacity, and two simultaneous percussive notes


Level 2 Specification

The Level 2 specification was developed to encourage the adoption of enhanced multimedia capabilities. This specification builds on the requirements set in the Level 1 specification and is a superset of it. The Level 2 specification defines the minimum system functionality for enhanced multimedia capabilities. It is not a recommendation for a system configuration.


Level 2 System Resources

The minimum configuration for a PC to satisfy the Level 2 specification includes the following items:

•	A 25 Mhz 486SX microprocessor with 4 MB of RAM

•	A 3.5-inch high-density floppy disk drive

•	A hard disk drive with at least 160 MB of disk space

•	A 101-key keyboard with a standard DIN connector or one that provides identical functionality by using key combinations

•	A two-button mouse with a serial or bus connector

•	A MIDI (Musical Instrument Digital Interface) port that includes MIDI Out, MIDI In, and MIDI Thru, and that has interrupt support for input and FIFO transfer

•	An IBM-style analog or digital joystick (game) port

•	A color monitor with a display resolution of 640 by 480 pixels with 65,536 colors

•	System software that offers binary compatibility with Windows 3.0 or Windows 3.1

In addition, the recommended performance goal for the video adapter (VGA+) is 1.2 million pixels per second using 40 percent or less of the CPU bandwidth. The device-independent bitmaps (DIBs) used to measure this performance goal have color depths of 1, 4, and 8 bits, and can use run-length encoding or be unencoded. A second method of measuring the video performance is to deliver 256-color, 320 by 240 pixel digital-video images at 15 frames per second.


Level 2 Optical Storage

The minimum performance optical storage device is a double-speed CD-ROM drive that meets the following criteria:

•	A sustained data transfer rate of 300 kilobytes per second

•	A CPU bandwidth usage of 40 percent or less when maintaining a sustained data transfer rate of 150 kilobytes per second, or a CPU bandwidth of 60 percent or less when maintaining a sustained data transfer rate of 300 kilobytes per second

•	An average seek time of 400 milliseconds or less

•	A 10,000 hour mean-time-between-failures rating

•	CD-ROM XA ready (mode 1 capable, mode 2 form 1 capable, mode form 2 capable)

•	Multisession capable

•	MSCDEX-2.2 driver or equivalent that implements the extended audio functions

The recommended CPU bandwidth should be reached by using a read-block size of at least 16K and a lead time of no more than the time needed to load one read-block of data into the CD-ROM buffer.


Level 2 Audio Requirements

The audio subsystem of a PC satisfying the Level 2 specification includes the following items:

•	A CD-ROM driver with CD-DA (Red Book audio) outputs and volume control

•	A 16-bit DAC with the following characteristics:

•	Linear PCM (Pulse Code Modulation) sampling

•	DMA or FIFO buffered transfer capability with interrupt on buffer empty

•	Mandatory sample rates of 44.1, 22.05, and 11.025 kHz

•	Stereo channels

•	CPU bandwidth usage of 10 percent or less when outputting audio of 22.05 or 11.025 kHz sample rate, or a CPU bandwidth of 15 percent or less when outputting audio of 44.1 kHz sample rate

•	A 16-bit ADC with the following characteristics:

•	Linear PCM sampling

•	DMA or FIFO buffered transfer capability with interrupt on buffer empty

•	Mandatory sample rates of 44.1, 22.05, and 11.025 kHz

•	Microphone input

•	Internal synthesizer capabilities with multivoice, multitimbral, six simultaneous melody notes plus two simultaneous percussive notes

•	Internal mixing with the following capabilities:

•	Can combine three audio sources and present the output as a stereo, line-level audio signal at the back panel

•	Mixing sources are CD Red Book audio, synthesizer, and DAC

•	Each mixing source has 3-bit volume control with a logarithmic taper


Manufacturer and Product Identifiers

This appendix documents the manufacturer and product identifiers defined for multimedia applications. These identifiers are used when an application issues a query about the installed devices on a computer.


Manufacturer Identifiers

Company name	Identifier
Advanced Gravis Computer Technology, Ltd.	MM_GRAVIS
Antex Electronics Corporation	MM_ANTEX
APPS Software	MM_APPS
Artisoft, Inc.	MM_ARTISOFT
AST Research, Inc.	MM_AST
ATI Technologies, Inc.	MM_ATI
Audio, Inc.	MM_AUDIOFILE
Audio Processing Technology	MM_APT
Audio Processing Technology	MM_AUDIOPT
Auravision Corporation	MM_AURAVISION
Aztech Labs, Inc.	MM_AZTECH
Canopus, Co., Ltd.	MM_CANOPUS
Compusic	MM_COMPUSIC
Computer Aided Technology, Inc.	MM_CAT
Computer Friends, Inc.	MM_COMPUTER_FRIENDS
Control Resources Corporation	MM_CONTROLRES
Creative Labs, Inc.	MM_CREATIVE
Dialogic Corporation	MM_DIALOGIC
Dolby Laboratories, Inc.	MM_DOLBY
DSP Group, Inc.	MM_DSP_GROUP
DSP Solutions, Inc.	MM_DSP_SOLUTIONS
Echo Speech Corporation	MM_ECHO
ESS Technology, Inc.	MM_ESS
Everex Systems, Inc.	MM_EVEREX
EXAN, Ltd.	MM_EXAN
Fujitsu, Ltd.	MM_FUJITSU
I/O Magic Corporation	MM_IOMAGIC
ICL Personal Systems	MM_ICL_PS
Ing. C. Olivetti & C., S.p.A.	MM_OLIVETTI
Integrated Circuit Systems, Inc.	MM_ICS
Intel Corporation	MM_INTEL
InterActive, Inc.	MM_INTERACTIVE
International Business Machines	MM_IBM
Iterated Systems, Inc.	MM_ITERATEDSYS
Logitech, Inc.	MM_LOGITECH
Lyrrus, Inc.	MM_LYRRUS
Matsushita Electric Corporation of America	MM_MATSUSHITA
Media Vision, Inc.	MM_MEDIAVISION
Metheus Corporation	MM_METHEUS
microEngineering Labs	MM_MELABS
Microsoft Corporation	MM_MICROSOFT
MOSCOM Corporation	MM_MOSCOM
Motorola, Inc.	MM_MOTOROLA
Natural MicroSystems Corporation	MM_NMS
NCR Corporation	MM_NCR
NEC Corporation	MM_NEC
New Media Corporation	MM_NEWMEDIA
OKI	MM_OKI
OPTi, Inc.	MM_OPTI
Roland Corporation	MM_ROLAND
SCALACS	MM_SCALACS
Seiko Epson Corporation, Inc.	MM_EPSON
Sierra Semiconductor Corporation	MM_SIERRA
Silicon Software, Inc.	MM_SILICONSOFT
Sonic Foundry	MM_SONICFOUNDRY
Speech Compression	MM_SPEECHCOMP
Supermac Technology, Inc.	MM_SUPERMAC
Tandy Corporation	MM_TANDY
Toshihiko Okuhura, Korg, Inc.	MM_KORG
Truevision, Inc.	MM_TRUEVISION
Turtle Beach Systems	MM_TURTLE_BEACH
Video Associates Labs, Inc.	MM_VAL
VideoLogic, Inc.	MM_VIDEOLOGIC
Visual Information Technologies, Inc.	MM_VITEC
VocalTec, Inc.	MM_VOCALTEC
Voyetra Technologies	MM_VOYETRA
Wang Laboratories	MM_WANGLABS
Willow Pond Corporation	MM_WILLOWPOND
Winnov, LP	MM_WINNOV
Xebec Multimedia Solutions Limited	MM_XEBEC
Yamaha Corporation of America	MM_YAMAHA


Microsoft Corporation Product Identifiers

Product name	Identifier
Adlib-compatible synthesizer	MM_ADLIB
G.711 codec	MM_MSFT_ACM_G711
GSM 610 codec	MM_MSFT_ACM_GSM610
IMA ADPCM codec	MM_MSFT_ACM_IMAADPCM
Joystick adapter	MM_PC_JOYSTICK
MIDI mapper	MM_MIDI_MAPPER
MPU 401-compatible MIDI input port	MM_MPU401_MIDIIN
MPU 401-compatible MIDI output port	MM_MPU401_MIDIOUT
MS ADPCM codec	MM_MSFT_ACM_MSADPCM
MS audio board stereo FM synthesizer	MM_MSFT_WSS_FMSYNTH_STEREO
MS audio board aux port	MM_MSFT_WSS_AUX
MS audio board mixer driver	MM_MSFT_WSS_MIXER
MS audio board waveform input	MM_MSFT_WSS_WAVEIN
MS audio board waveform output	MM_MSFT_WSS_WAVEOUT
MS audio compression manager	MM_MSFT_MSACM
MS filter	MM_MSFT_ACM_MSFILTER
MS OEM audio aux port	MM_MSFT_WSS_OEM_AUX
MS OEM audio board mixer driver	MM_MSFT_WSS_OEM_MIXER
MS OEM audio board stereo FM synthesizer	MM_MSFT_WSS_OEM_FMSYNTH_STEREO
MS OEM audio board waveform input	MM_MSFT_WSS_OEM_WAVEIN
MS OEM audio board waveform output	MM_MSFT_WSS_OEM_WAVEOUT
MS vanilla driver aux (CD)	MM_MSFT_GENERIC_AUX_CD
MS vanilla driver aux (line in)	MM_MSFT_GENERIC_AUX_LINE
MS vanilla driver aux (mic)	MM_MSFT_GENERIC_AUX_MIC
MS vanilla driver MIDI external out	MM_MSFT_GENERIC_MIDIOUT
MS vanilla driver MIDI in	MM_MSFT_GENERIC_MIDIIN
MS vanilla driver MIDI synthesizer	MM_MSFT_GENERIC_MIDISYNTH
MS vanilla driver waveform input	MM_MSFT_GENERIC_WAVEIN
MS vanilla driver wavefrom output	MM_MSFT_GENERIC_WAVEOUT
PC speaker waveform output	MM_PCSPEAKER_WAVEOUT
PCM converter	MM_MSFT_ACM_PCM
Sound Blaster internal synthesizer	MM_SNDBLST_SYNTH
Sound Blaster MIDI input port	MM_SNDBLST_MIDIIN
Sound Blaster MIDI output port	MM_SNDBLST_MIDIOUT
Sound Blaster waveform input	MM_SNDBLST_WAVEIN
Sound Blaster waveform output	MM_SNDBLST_WAVEOUT
Wave mapper	MM_WAVE_MAPPER


Microsoft Windows Sound System Drivers

Driver	Identifier
Sound Blaster 16 waveform output	MM_MSFT_SB16_WAVEOUT
Sound Blaster 16 aux (CD)	MM_WSS_SB16_AUX_CD
Sound Blaster 16 aux (CD)	MM_MSFT_SB16_AUX_CD
Sound Blaster 16 aux (line in)	MM_WSS_SB16_AUX_LINE
Sound Blaster 16 aux (line in)	MM_MSFT_SB16_AUX_LINE
Sound Blaster 16 FM synthesizer	MM_WSS_SB16_SYNTH
Sound Blaster 16 FM synthesizer	MM_MSFT_SB16_SYNTH
Sound Blaster 16 MIDI out	MM_WSS_SB16_MIDIOUT
Sound Blaster 16 MIDI out	MM_MSFT_SB16_MIDIOUT
Sound Blaster 16 MIDI in	MM_WSS_SB16_MIDIIN
Sound Blaster 16 MIDI in	MM_MSFT_SB16_MIDIIN
Sound Blaster 16 mixer device	MM_WSS_SB16_MIXER
Sound Blaster 16 mixer device	MM_MSFT_SB16_MIXER
Sound Blaster 16 waveform input	MM_WSS_SB16_WAVEIN
Sound Blaster 16 waveform input	MM_MSFT_SB16_WAVEIN
Sound Blaster 16 waveform output	MM_WSS_SB16_WAVEOUT
Sound Blaster Pro aux (CD)	MM_WSS_SBPRO_AUX_CD
Sound Blaster Pro aux (CD)	MM_MSFT_SBPRO_AUX_CD
Sound Blaster Pro aux (line in)	MM_WSS_SBPRO_AUX_LINE
Sound Blaster Pro aux (line in)	MM_MSFT_SBPRO_AUX_LINE
Sound Blaster Pro FM synthesizer	MM_WSS_SBPRO_SYNTH
Sound Blaster Pro FM synthesizer	MM_MSFT_SBPRO_SYNTH
Sound Blaster Pro MIDI in	MM_WSS_SBPRO_MIDIIN
Sound Blaster Pro MIDI in	MM_MSFT_SBPRO_MIDIIN
Sound Blaster Pro MIDI out	MM_WSS_SBPRO_MIDIOUT
Sound Blaster Pro MIDI out	MM_MSFT_SBPRO_MIDIOUT
Sound Blaster Pro mixer	MM_WSS_SBPRO_MIXER
Sound Blaster Pro mixer	MM_MSFT_SBPRO_MIXER
Sound Blaster Pro waveform input	MM_WSS_SBPRO_WAVEIN
Sound Blaster Pro waveform input	MM_MSFT_SBPRO_WAVEIN
Sound Blaster Pro waveform output	MM_WSS_SBPRO_WAVEOUT
Sound Blaster Pro waveform output	MM_MSFT_SBPRO_WAVEOUT
WSS NT aux	MM_MSFT_WSS_NT_AUX
WSS NT FM synthesizer	MM_MSFT_WSS_NT_FMSYNTH_STEREO
WSS NT mixer	MM_MSFT_WSS_NT_MIXER
WSS NT wave in	MM_MSFT_WSS_NT_WAVEIN
WSS NT wave out	MM_MSFT_WSS_NT_WAVEOUT


Product Identifiers

Company	Product identifiers
Artisoft, Inc.	MM_ARTISOFT_SBWAVEIN MM_ARTISOFT_SBWAVEOUT
Audio Processing Technology	MM_APT_ACE100CD
Aztech Labs, Inc.	MM_AZTECH_AUX_CD MM_AZTECH_AUX_LINE MM_AZTECH_AUX_MIC MM_AZTECH_DSP16_FMSYNTH MM_AZTECH_DSP16_WAVEIN MM_AZTECH_DSP16_WAVEOUT MM_AZTECH_DSP16_WAVESYNTH MM_AZTECH_FMSYNTH MM_AZTECH_MIDIIN MM_AZTECH_MIDIOUT MM_AZTECH_PRO16_FMSYNTH MM_AZTECH_PRO16_WAVEIN MM_AZTECH_PRO16_WAVEOUT MM_AZTECH_WAVEIN MM_AZTECH_WAVEOUT
Computer Aided Technology, Inc.	MM_CAT_WAVEOUT
Creative Labs, Inc.	MM_CREATIVE_AUX_CD MM_CREATIVE_AUX_LINE MM_CREATIVE_AUX_MASTER MM_CREATIVE_AUX_MIC MM_CREATIVE_AUX_MIDI MM_CREATIVE_AUX_PCSPK MM_CREATIVE_AUX_WAVE MM_CREATIVE_FMSYNTH_MONO MM_CREATIVE_FMSYNTH_STEREO MM_CREATIVE_MIDIIN MM_CREATIVE_MIDIOUT MM_CREATIVE_SB15_WAVEIN MM_CREATIVE_SB15_WAVEOUT MM_CREATIVE_SB16_MIXER MM_CREATIVE_SB20_WAVEIN MM_CREATIVE_SB20_WAVEOUT MM_CREATIVE_SBP16_WAVEIN MM_CREATIVE_SBP16_WAVEOUT MM_CREATIVE_SBPRO_MIXER MM_CREATIVE_SBPRO_WAVEIN MM_CREATIVE_SBPRO_WAVEOUT
DSP Group, Inc.	MM_DSP_GROUP_TRUESPEECH
DSP Solutions, Inc.	MM_DSP_SOLUTIONS_AUX MM_DSP_SOLUTIONS_SYNTH MM_DSP_SOLUTIONS_WAVEIN MM_DSP_SOLUTIONS_WAVEOUT
Echo Speech Corporation	MM_ECHO_AUX MM_ECHO_MIDIIN MM_ECHO_MIDIOUT MM_ECHO_SYNTH MM_ECHO_WAVEIN MM_ECHO_WAVEOUT
ESS Technology, Inc.	MM_ESS_AMAUX MM_ESS_AMMIDIIN MM_ESS_AMMIDIOUT MM_ESS_AMSYNTH MM_ESS_AMWAVEIN MM_ESS_AMWAVEOUT
Everex Systems, Inc.	MM_EVEREX_CARRIER
I/O Magic Corporation	MM_IOMAGIC_TEMPO_AUXOUT MM_IOMAGIC_TEMPO_MIDIOUT MM_IOMAGIC_TEMPO_MXDOUT MM_IOMAGIC_TEMPO_SYNTH MM_IOMAGIC_TEMPO_WAVEIN MM_IOMAGIC_TEMPO_WAVEOUT
Ing. C. Olivetti & C., S.p.A.	MM_OLIVETTI_ACM_ADPCM MM_OLIVETTI_ACM_CELP MM_OLIVETTI_ACM_GSM MM_OLIVETTI_ACM_OPR MM_OLIVETTI_ACM_SBC MM_OLIVETTI_AUX MM_OLIVETTI_JOYSTICK MM_OLIVETTI_MIDIIN MM_OLIVETTI_MIDIOUT MM_OLIVETTI_MIXER MM_OLIVETTI_SYNTH MM_OLIVETTI_WAVEIN MM_OLIVETTI_WAVEOUT
Integrated Circuit Systems, Inc.	MM_ICS_WAVEDECK_AUX MM_ICS_WAVEDECK_MIXER MM_ICS_WAVEDECK_SYNTH MM_ICS_WAVEDECK_WAVEIN MM_ICS_WAVEDECK_WAVEOUT
InterActive, Inc.	MM_INTERACTIVE_WAVEIN MM_INTERACTIVE_WAVEOUT
International Business Machines	MM_IBM_PCMCIA_AUX MM_IBM_PCMCIA_MIDIIN MM_IBM_PCMCIA_MIDIOUT MM_IBM_PCMCIA_SYNTH MM_IBM_PCMCIA_WAVEIN MM_IBM_PCMCIA_WAVEOUT MM_MMOTION_WAVEAUX MM_MMOTION_WAVEIN MM_MMOTION_WAVEOUT
Iterated Systems, Inc.	MM_ITERATEDSYS_FUFCODEC
Lyrrus, Inc.	MM_LYRRUS_BRIDGE_GUITAR
Matsushita Electric Corporation of America	MM_MATSUSHITA_AUX MM_MATSUSHITA_FMSYNTH_STEREO MM_MATSUSHITA_MIXER MM_MATSUSHITA_WAVEIN MM_MATSUSHITA_WAVEOUT
Media Vision, Inc.	MM_MEDIAVISION_CDPC MM_CDPC_AUX MM_CDPC_MIDIIN MM_CDPC_MIDIOUT MM_CDPC_MIXER MM_CDPC_SYNTH MM_CDPC_WAVEIN MM_CDPC_WAVEOUT
	MM_OPUS401_MIDIIN MM_OPUS401_MIDIOUT
	MM_MEDIAVISION_OPUS1208 MM_OPUS1208_AUX MM_OPUS1208_MIXER MM_OPUS1208_SYNTH MM_OPUS1208_WAVEIN MM_OPUS1208_WAVEOUT
	MM_MEDIAVISION_OPUS1216 MM_OPUS1216_AUX MM_OPUS1216_MIDIIN MM_OPUS1216_MIDIOUT MM_OPUS1216_MIXER MM_OPUS1216_SYNTH MM_OPUS1216_WAVEIN MM_OPUS1216_WAVEOUT
	MM_MEDIAVISION_PROAUDIO MM_PROAUD_AUX MM_PROAUD_MIDIIN MM_PROAUD_MIDIOUT MM_PROAUD_MIXER
	MM_MEDIAVISION_PROAUDIO_16 MM_PROAUD_16_AUX MM_PROAUD_16_MIDIIN MM_PROAUD_16_MIDIOUT MM_PROAUD_16_MIXER MM_PROAUD_16_SYNTH MM_PROAUD_16_WAVEIN MM_PROAUD_16_WAVEOUT
	MM_MEDIAVISION_PROAUDIO_PLUS MM_PROAUD_PLUS_AUX MM_PROAUD_PLUS_MIDIIN MM_PROAUD_PLUS_MIDIOUT MM_PROAUD_PLUS_MIXER MM_PROAUD_PLUS_SYNTH MM_PROAUD_PLUS_WAVEIN MM_PROAUD_PLUS_WAVEOUT MM_PROAUD_SYNTH MM_PROAUD_WAVEIN MM_PROAUD_WAVEOUT
	MM_MEDIAVISION_PROSTUDIO_16 MM_STUDIO_16_AUX MM_STUDIO_16_MIDIIN MM_STUDIO_16_MIDIOUT MM_STUDIO_16_MIXER MM_STUDIO_16_SYNTH MM_STUDIO_16_WAVEIN MM_STUDIO_16_WAVEOUT
	MM_MEDIAVISION_THUNDER MM_THUNDER_AUX MM_THUNDER_SYNTH MM_THUNDER_WAVEIN MM_THUNDER_WAVEOUT
	MM_MEDIAVISION_TPORT MM_TPORT_SYNTH MM_TPORT_WAVEIN MM_TPORT_WAVEOUT
Metheus Corporation	MM_METHEUS_ZIPPER
microEngineering Labs	MM_MELABS_MIDI2GO
MOSCOM Corporation	MM_MOSCOM_VPC2400
NCR Corporation	MM_NCR_BA_AUX MM_NCR_BA_MIXER MM_NCR_BA_SYNTH MM_NCR_BA_WAVEIN MM_NCR_BA_WAVEOUT
New Media Corporation	MM_NEWMEDIA_WAVJAMMER
OPTi, Inc.	MM_OPTI_M16_AUX MM_OPTI_M16_FMSYNTH_STEREO MM_OPTI_M16_MIDIIN MM_OPTI_M16_MIDIOUT MM_OPTI_M16_MIXER MM_OPTI_M16_WAVEIN MM_OPTI_M16_WAVEOUT MM_OPTI_M32_AUX MM_OPTI_M32_MIDIIN MM_OPTI_M32_MIDIOUT MM_OPTI_M32_MIXER MM_OPTI_M32_SYNTH_STEREO MM_OPTI_M32_WAVEIN MM_OPTI_M32_WAVEOUT MM_OPTI_P16_AUX MM_OPTI_P16_FMSYNTH_STEREO MM_OPTI_P16_MIDIIN MM_OPTI_P16_MIDIOUT MM_OPTI_P16_MIXER MM_OPTI_P16_WAVEIN MM_OPTI_P16_WAVEOUT
Roland Corporation	MM_ROLAND_MPU401_MIDIIN MM_ROLAND_MPU401_MIDIOUT MM_ROLAND_SC7_MIDIIN MM_ROLAND_SC7_MIDIOUT MM_ROLAND_SERIAL_MIDIIN MM_ROLAND_SERIAL_MIDIOUT MM_ROLAND_SMPU_MIDIINA MM_ROLAND_SMPU_MIDIINB MM_ROLAND_SMPU_MIDIOUTA MM_ROLAND_SMPU_MIDIOUTB
Sierra Semiconductor Corporation	MM_SIERRA_ARIA_AUX MM_SIERRA_ARIA_AUX2 MM_SIERRA_ARIA_MIDIIN MM_SIERRA_ARIA_MIDIOUT MM_SIERRA_ARIA_SYNTH MM_SIERRA_ARIA_WAVEIN MM_SIERRA_ARIA_WAVEOUT
Silicon Software, Inc.	MM_SILICONSOFT_SC1_WAVEIN MM_SILICONSOFT_SC1_WAVEOUT MM_SILICONSOFT_SC2_WAVEIN MM_SILICONSOFT_SC2_WAVEOUT MM_SILICONSOFT_SOUNDJR2_WAVEOUT MM_SILICONSOFT_SOUNDJR2PR_WAVEIN MM_SILICONSOFT_SOUNDJR2PR_WAVEOUT MM_SILICONSOFT_SOUNDJR3_WAVEOUT
Tandy Corporation	MM_TANDY_PSSJWAVEIN MM_TANDY_PSSJWAVEOUT MM_TANDY_SENS_MMAMIDIIN MM_TANDY_SENS_MMAMIDIOUT MM_TANDY_SENS_MMAWAVEIN MM_TANDY_SENS_MMAWAVEOUT MM_TANDY_SENS_VISWAVEOUT MM_TANDY_VISBIOSSYNTH MM_TANDY_VISWAVEIN MM_TANDY_VISWAVEOUT
Toshihiko Okuhura, Korg, Inc.	MM_KORG_PCIF_MIDIIN MM_KORG_PCIF_MIDIOUT
Truevision, Inc.	MM_TRUEVISION_WAVEIN1 MM_TRUEVISION_WAVEOUT1
VideoLogic, Inc.	MM_VIDEOLOGIC_MSWAVEIN MM_VIDEOLOGIC_MSWAVEOUT
Visual Information Technologies, Inc.	MM_VITEC_VMAKER MM_VITEC_VMPRO
VocalTec, Inc.	MM_VOCALTEC_WAVEIN MM_VOCALTEC_WAVEOUT
Wang Laboratories	MM_WANGLABS_WAVEIN1 MM_WANGLABS_WAVEOUT1
Winnov, LP	MM_WINNOV_CAVIAR_CHAMPAGNE MM_WINNOV_CAVIAR_VIDC MM_WINNOV_CAVIAR_WAVEIN MM_WINNOV_CAVIAR_WAVEOUT MM_WINNOV_CAVIAR_YUV8
Yamaha Corporation of America	MM_YAMAHA_GSS_AUX MM_YAMAHA_GSS_MIDIIN MM_YAMAHA_GSS_MIDIOUT MM_YAMAHA_GSS_SYNTH MM_YAMAHA_GSS_WAVEIN MM_YAMAHA_GSS_WAVEOUT


Installable Drivers

An installable driver is a Microsoft Windows dynamic-link library (DLL) that provides a standard interface through which Windows-based applications and DLLs communicate with and manage the driver. Installable drivers are used most commonly for as multimedia device drivers, but installable drivers can also be used for other purposes and are particularly useful in situations that require a standard interface and control of multiple instances.

This chapter describes the general format of installable drivers and defines the installable driver functions that applications and DLLs use to open and manage installable drivers.


Installable Driver Format

Every installable driver exports a DriverProc function. This common entry-point function receives driver messages from the system that direct the driver to carry out actions or provide information. The system sends driver messages to the DriverProc function when an application or DLL opens or closes the driver or requests that a message be sent to the driver. The DriverProc function either processes the message or passes the message to the default message handler, the DefDriverProc function. In either case, DriverProc must return a value indicating whether the requested action was successful.


Driver Messages

Each driver message consists of a message identifier and two 32-bit parameters. The message identifier is a unique value that the DriverProc function checks to determine which action to carry out. The meaning of the message parameters depends on the message. The parameters may represent values or addresses. In many cases, the parameters are not used and are set to zero.

Driver messages can be standard or custom. Window sends standard driver messages, such as DRV_OPEN, DRV_CLOSE, and DRV_CONFIGURE, to an installable driver in response to a request to open, close, or configure the driver. The standard messages direct the installable driver to load or unload its resources, enable or disable its operation, open or close a driver instance, and display a configuration dialog box. Some standard messages, such as DRV_POWER and DRV_EXITSESSION, notify the driver of system-wide events that affect the operation of the driver or any related hardware.

Applications and DLLs send custom driver messages to direct an installable driver to carry out driver-specific actions. Installable drivers that support custom messages must include appropriate processing in the DriverProc function. To prevent conflict between custom and standard driver messages, custom message identifiers must have values ranging from DRV_RESERVED to DRV_USER. Custom messages passed to the DefDriverProc function are ignored.


Driver Instances

Windows allows for multiples instances of an installable driver. The system creates an instance of the driver each time the driver is opened and destroys the instance when the driver is closed. Driver instances are especially useful for installable drivers that support multiple devices or that are opened by multiple applications or by the same application multiple times.

To help the driver keep track of the instances, the system sends a driver instance handle with each driver message after the instance has been created. Because this handle uniquely identifies the instance, installable drivers often associate the handle with memory and other resources that they have specifically allocated for the instance.

When the first instance is opened, the system sends the DRV_LOAD, DRV_ENABLE, and DRV_OPEN messages to the driver in that order. The DRV_LOAD and DRV_ENABLE messages notify the driver that it is now in memory and is enabled for operation. The DRV_OPEN message identifies the instance handle and may include configuration information for the instance. On each subsequent opening of an instance of the same driver, the system sends only a DRV_OPEN message.

When processing a DRV_LOAD message, a driver typically reads configuration settings from the registry, configures the driver and any associated hardware, and allocates memory for use by all instances of the driver. If a driver cannot complete the configuration or allocate memory, it returns zero to direct the system to immediately remove the driver from memory and prevent any subsequent messages from being sent. When processing the DRV_ENABLE message, the driver prepares the hardware to receive and process input and output (I/O) requests. The preparation may include installing interrupt handlers.

When processing the DRV_OPEN message, the driver allocates memory or resources required by the given instance of the driver and then returns a nonzero value. The system uses this nonzero value as the driver identifier in subsequent driver messages for the instance. The driver can use this identifier for any purpose. For example, some drivers use a memory handle for the identifier to gain quick access to memory containing information about the given instance.

Many installable drivers process the second parameter of the DRV_OPEN message, giving the system and applications the means to send additional information to the driver when opening an instance. The parameter can be a single value or an address of a structure containing a set of values. When processing DRV_OPEN, the driver checks the parameter to determine whether it is a value and uses the given values, if any, to complete the creation of the instance.

The system sends a DRV_CLOSE message each time an instance is closed. The instance handle sent with the message identifies which instance to close. When the last remaining instance is closed, the system sends the DRV_CLOSE, DRV_DISABLE, and DRV_FREE messages in that order. The DRV_CLOSE message directs the driver to close the instance, and the DRV_DISABLE and DRV_FREE messages notify the driver that it is now disabled and will be immediately freed from memory.

When processing the DRV_CLOSE message, the driver typically frees any memory or resources allocated for the instance. When processing the DRV_DISABLE message, the driver places any hardware in an inactive state, which may include the removal of interrupt handlers. When processing the DRV_FREE message, the driver frees any memory or resources that are still allocated.

Installable drivers are not required to support multiple instances. A driver can prevent any instance from being created by returning zero for the DRV_OPEN message.


Configuration

An installable driver can let users choose configuration settings for the driver and associated hardware by displaying a configuration dialog box when processing the DRV_CONFIGURE message. The driver is responsible for creating and managing the dialog box, processing any user input from the dialog box, and changing the configuration of the driver or hardware as requested by the user. The driver must provide a separate dialog box procedure to process window messages for the dialog box and a dialog box template to define the appearance and content of the dialog box.

Before receiving the DRV_CONFIGURE message, a driver receives the DRV_QUERYCONFIGURE message. The driver must return a nonzero value to the query to ensure receipt of the subsequent DRV_CONFIGURE message.

When initializing the configuration dialog box, the driver typically retrieves configuration information from the registry. To help locate this information, the DRV_CONFIGURE message usually includes the address of a DRVCONFIGINFO structure that contains the names of the registry key and value associated with the driver. If the user requests changes to the configuration, the driver should update the configuration information in the registry.


Installation

An installable driver can carry out driver-specific installation tasks when processing the DRV_INSTALL and DRV_REMOVE messages. An installation application, such as a Control Panel application, sends the messages to the driver when installing or removing the driver, respectively.

When processing the DRV_INSTALL message, the driver typically verifies that the required hardware is present and then displays the configuration dialog box to let the user choose the initial configuration settings for the driver and associated hardware. The message includes the address of a DRVCONFIGINFO structure that contains the names of the registry key and value associated with the driver; the driver checks the registry value for default configuration information. Finally, the driver also creates any additional registry keys and values needed for successful operation.

When processing the DRV_REMOVE message, the driver removes any registry keys and values it may have created.


Callback Functions

Installable drivers can notify the application, window, or task that opened the given instance about events by using the DriverCallback function. This function gives the driver the means to return information to an application or DLL while continuing to process a request.

If a driver supports callback functions, the application or DLL that opens the instance must supply a value this is either the address of a callback function, a window handle, or a task handle. This value and a flag identifying the type of the value are typically passed in a structure pointed to by the second parameter of the DRV_OPEN message.


Installable Drive Module-Definition File

The module-definition (.DEF) file of an installable driver names the driver, exports the DriverProc function, and defines a driver description. The following example shows a typical module-definition file for an installable driver:

LIBRARY OSCI

DESCRIPTION 'FREQ,AMPL:Oscilloscope frequency and amplitude drivers.'
EXPORTS
    DriverProc

Some installation applications may open the driver and retrieve the description line to use when installing the driver. To remain compatible with these installation applications, the description line should have this form:

DESCRIPTION alias[,alias]...:text

The alias specifies a unique name for the driver that applications can use to open the driver. The alias also serves as the value name associated with the driver in the registry. Multiple aliases are separated by commas. The text describes the purpose of the driver.


Installable Driver Functions and Messages

You can open an installable driver from an application by using the OpenDriver function. This function creates an instance of the driver, loading the driver into memory if no other instance exists, and returns the handle of the new instance. When opening an installable driver, you must supply either the full path of the driver or the names of the registry key and value associated with the driver.

Once a driver is open, you can direct it to carry out tasks by using the SendDriverMessage function to send driver messages to the driver. For example, you can direct the driver to display its configuration dialog box by sending the DRV_CONFIGURE message. Before sending this message, you must determine whether the driver has a configuration dialog box by sending the DRV_QUERYCONFIGURE message and checking for a nonzero return value. Many drivers provide a set of custom messages that you can send to direct the operations of the driver.

If you need special access to an installable driver, such as access to its resources, you can retrieve the module handle of the driver by using the GetDriverModuleHandle function.

When you no longer need the installable driver, you can close it by using the CloseDriver function.

You can use the installable driver functions and messages to open and manage any installable driver. However, the recommended course of action for opening and managing multimedia devices is to first use standard services (such as waveOutOpen, waveOutMessage, and waveOutClose for waveform output devices), if they exist. If standard services do not exist for a multimedia driver, then open and manage the driver using the installable driver functions and messages.

Note  The SendDriverMessage and GetDriverModuleHandle functions are the preferred functions to use to send messages to a driver and to obtain a handle to a module instance. The older DrvSendMessage and DrvGetModuleHandle functions, however, have been included to maintain compatibility with previous versions of the Windows operating system.


Using Installable Drivers

You use installable drivers to give applications or DLLs a standard way to access a device or a set of useful routines. The following sections show how to create an installable driver by using a DriverProc function and how to open an installable driver and direct it to carry out useful tasks.


Creating a DriverProc Function

You create a DriverProc function in much the same way as you create a window procedure. The function consists of a switch statement, and each case processes a given driver message, returning a value indicating success or failure. The DriverProc function has the following form:

LONG DriverProc(DWORD dwDriverId, HDRVR hdrvr, UINT msg,
    LONG lParam1, LONG lParam2)
{
    DWORD dwRes = 0L;

    switch (msg) {
    case DRV_LOAD:
    // Sent when the driver is loaded. This is always
    // the first message received by a driver.
        dwRes = 1L;  // returns 0L to fail
        break;

    case DRV_FREE:
    // Sent when the driver is about to be discarded.
    // This is the last message a driver receives
    // before it is freed.
        dwRes = 1L;  // return value ignored
        break;

    case DRV_OPEN:
    // Sent when the driver is opened.
        dwRes = 1L;  // returns 0L to fail
        break;       // value subsequently used
                     // for dwDriverId.

    case DRV_CLOSE:
    // Sent when the driver is closed. Drivers are
    // unloaded when the open count reaches zero.
        dwRes = 1L;  // returns 0L to fail
        break;

    case DRV_ENABLE:
    // Sent when the driver is loaded or reloaded and
    // when Windows is enabled. Install interrupt
    // handlers and initialize hardware. Expect the
    // driver to be in memory only between the enable
    // and disable messages.
        dwRes = 1L;  // return value ignored
        break;

    case DRV_DISABLE:
    // Sent before the driver is freed or when Windows
    // is disabled. Remove interrupt handlers and place
    // hardware in an inactive state.
        dwRes = 1L;  // return value ignored
        break;

    case DRV_INSTALL:
    // Sent when the driver is installed.
        dwRes = DRVCNF_OK;  // Can also return
        break;              // DRVCNF_CANCEL
                            // and DRV_RESTART

    case DRV_REMOVE:
    // Sent when the driver is removed.
        dwRes = 1L;  // return value ignored
        break;

    case DRV_QUERYCONFIGURE:
    // Sent to determine if the driver can be
    // configured.
        dwRes = 0L;  // Zero indicates configuration
        break;       // NOT supported

    case DRV_CONFIGURE:
    // Sent to display the configuration
    // dialog box for the driver.
        dwRes = DRVCNF_OK;  // Can also return
        break;              // DRVCNF_CANCEL
                            // and DRVCNF_RESTART

    default:
    // Process any other messages.
        return DefDriverProc (dwDriverId, hdrvr,
            msg, lParam1, lParam2);

    }
    return dwRes;
}


Configuring an Installable Driver

To direct an installable driver to carry out useful tasks, you must open the driver by using the OpenDriver function and send it messages by using the SendDriverMessage function. The following example shows how to direct the driver to display its configuration dialog box.

LONG MyConfigureDriver()
{
    HDRVR hdrvr;
    DRVCONFIGINFO dci;
    LONG lRes;

    // Open the driver (no additional parameters needed this time).
    if ((hdrvr = OpenDriver(L"\\samples\\sample.drv", 0, 0)) == 0) {
        // Can't open the driver
        return DRVCNF_CANCEL;
    }

    // Make sure driver has a configuration dialog box.
    if (SendDriverMessage(hdrvr, DRV_QUERYCONFIGURE, 0, 0) != 0) {
        // Set the DRVCONFIGINFO structure and send the message
        dci.dwDCISize = sizeof (dci);
        dci.lpszDCISectionName = (LPWSTR)0;
        dci.lpszDCIAliasName = (LPWSTR)0;
        lRes = SendDriverMessage(hdrvr, DRV_CONFIGURE, 0, (LONG)&dci);
     }

    // Close the driver (no additional parameters needed this time).
    CloseDriver(hdrvr, 0, 0);

    return lRes;
}


Installable Driver Reference

Thie functions and messages associated with installable drivers are grouped as follows.

Loading and Unloading Drivers

OpenDriver
SendDriverMessage
GetDriverModuleHandle

CloseDriver

DRV_LOAD
DRV_ENABLE
DRV_OPEN
DRV_CLOSE
DRV_DISABLE
DRV_FREE

Configuring a Driver

DRV_CONFIGURE
DRV_QUERYCONFIGURE
DRVCONFIGINFO

Installing a Driver

DRV_INSTALL
DRV_REMOVE

Driver Functions

DefDriverProc
DriverProc
DriverCallback


Installable Driver Functions

The functions in this sectioncan be used in an application to open, close, and communicate with an installable driver.


CloseDriver

LRESULT CloseDriver(HDRVR hdrvr, LONG lParam1, LONG lParam2);

Closes an installable driver.

•	Returns nonzero if successful or zero otherwise.

hdrvr

Handle of an installable driver instance. The handle must have been previously created by using the OpenDriver function.

lParam1 and lParam2

32-bit driver-specific data.

The function passes the lParam1 and lParam2 parameters to the DriverProc function of the installable driver.


DrvGetModuleHandle

WINMMAPI HMODULE WINAPI DrvGetModuleHandle(HDRVR hDriver);

Retrieves the instance handle of the module that contains the installable driver.

•	Returns an instance handle of the driver module if successful or NULL otherwise.

hDriver

Handle of the installable driver instance. The handle must have been previously created by using the OpenDriver function.

This function is provided for compatibility with previous versions of Windows.


DrvSendMessage

WINMMAPI LRESULT WINAPI DrvSendMessage(HDRVR hdrvr, UINT uMsg,
    LPARAM lParam1, LPARAM lParam2);

Sends the specified message to the insntallable driver.

•	Returns nonzero if successful or zero otherwise.

hdrvr

Handle of the installable driver instance. The handle must have been previously created by using the OpenDriver function.

uMsg

Driver message value. It can be a custom message value or one of these standard message values:

DRV_QUERYCONFIGURE	Queries an installable driver about whether it supports the DRV_CONFIGURE message and can display a configuration dialog box.
DRV_CONFIGURE	Notifies an installable driver that it should display a configuration dialog box. (This message should be sent only if the driver returns a nonzero value when the DRV_QUERYCONFIGURE message is processed.)
DRV_INSTALL	Notifies an installable driver that it has been successfully installed.
DRV_REMOVE	Notifies an installable driver that it is about to be removed from the system.
lParam1 and lParam2

Message parameters containing 32-bit information specific to the message value.

This function is provided for compatibility with previous versions of Windows.


GetDriverModuleHandle

HMODULE GetDriverModuleHandle(HDRVR hdrvr);

Retrieves the instance handle of the module that contains the installable driver.

•	Returns an instance handle of the driver module if successful or NULL otherwise.

hdrvr

Handle of the installable driver instance. The handle must have been previously created by using the OpenDriver function.

This function is specific to Windows 95.


OpenDriver

HDRVR OpenDriver(LPCWSTR lpDriverName, LPCWSTR lpSectionName,
    LONG lParam);

Opens an instance of an installable driver and initializes the instance using either the driver's default settings or a driver-specific value.

•	Returns the handle of the installable driver instance if successful or NULL otherwise.

lpDriverName

Address of a null-terminated, wide-character string that specifies the filename of an installable driver or the name of a registry value associated with the installable driver. (This value must have been previously set when the driver was installed.)

lpSectionName

Address of a null-terminated, wide-character string that specifies the name of the registry key containing the registry value given by the lpDriverName parameter. If lpSectionName is NULL, the registry key is assumed to be Drivers32.

lParam

32-bit driver-specific value. This value is passed as the lParam2 parameter to the DriverProc function of the installable driver.


SendDriverMessage

LRESULT SendDriverMessage(HDRVR hdrvr, UINT msg, LONG lParam1,
    LONG lParam2);

Sends the specified message to the installable driver.

•	Returns nonzero if successful or zero otherwise.

hdrvr

Handle of the installable driver instance. The handle must been previously created by using the OpenDriver function.

msg

Driver message value. It can be a custom message value or one of these standard message values:

DRV_QUERYCONFIGURE	Queries an installable driver about whether it supports the DRV_CONFIGURE message and can display a configuration dialog box.
DRV_CONFIGURE	Notifies an installable driver that it should display a configuration dialog box. (This message should only be sent if the driver returns a nonzero value when the DRV_QUERYCONFIGURE message is processed.)
DRV_INSTALL	Notifies an installable driver that it has been successfully installed.
DRV_REMOVE	Notifies an installable driver that it is about to be removed from the system.
lParam1 and lParam2

32-bit message-dependent information.

This function is specific to Windows 95.


Driver Functions

The functions is this sectiondescribe the entry point, default processing, and callback functions to use in an installable driver.


DefDriverProc

LONG DefDriverProc(DWORD dwDriverId, HDRVR hdrvr, UINT msg,
    LONG lParam1, LONG lParam2);

Provides default processing for any messages not processed by an installable driver. This function is intended to be used only within the DriverProc function of an installable driver.

•	Returns nonzero if successful or zero otherwise.

dwDriverId

Identifier of the installable driver.

hdrvr

Handle of the installable driver instance.

msg

Driver message value.

lParam1 and lParam2

32-bit message-dependent information.


DriverProc

LONG DriverProc(DWORD dwDriverId, HDRVR hdrvr, UINT msg,
    LONG lParam1, LONG lParam2);

Processes driver messages for the installable driver. DriverProc is a driver-supplied function.

•	Returns nonzero if successful or zero otherwise.

dwDriverId

Identifier of the installable driver.

hdrvr

Handle of the installable driver instance. Each instance of the installable driver has a unique handle.

msg

Driver message value. It can be a custom value or one of these standard values:

DRV_CLOSE	Notifies the driver that it should decrement its usage count and unload the driver if the count is zero.
DRV_CONFIGURE	Notifies the driver that it should display a configuration dialog box. This message is sent only if the driver returns a nonzero value when processing the DRV_QUERYCONFIGURE message.
DRV_DISABLE	Notifies the driver that its allocated memory is about to be freed.
DRV_ENABLE	Notifies the driver that it has been loaded or reloaded or that Windows has been enabled.
DRV_FREE	Notifies the driver that it will be discarded.
DRV_INSTALL	Notifies the driver that it has been successfully installed.
DRV_LOAD	Notifies the driver that it has been successfully loaded.
DRV_OPEN	Notifies the driver that it is about to be opened.
DRV_POWER	Notifies the driver that the device's power source is about to be turned on or off.
DRV_QUERYCONFIGURE	Directs the driver to specify whether it supports the DRV_CONFIGURE message.
DRV_REMOVE	Notifies the driver that it is about to be removed from the system.
lParam1 and lParam2

32-bit message-specific value.

When msg is DRV_OPEN, lParam1 is the string following the driver filename from the SYSTEM.INI file and lParam2 is the value given as the lParam parameter in a call to the OpenDriver function.

When msg is DRV_CLOSE, lParam1 and lParam2 are the same values as the lParam1 and lParam2 parameters in a call to the CloseDriver function.


DriverCallback

BOOLEAN DriverCallback(DWORD dwCallBack, DWORD dwFlags, HDRVR hdrvr,
    DWORD msg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2);

Calls a callback function, sends a message to a window, or unblocks a thread. The action depends on the value of the notification flag. This function is intended to be used only within the DriverProc function of an installable driver.

•	Returns TRUE if successful or FALSE if a parameter is invalid or the task's message queue is full.

dwCallBack

Address of the callback function, a window handle, or a task handle, depending on the flag specified in the dwFlags parameter.

dwFlags

Notification flags. It can be one of these values:

DCB_NOSWITCH	The system is prevented from switching stacks. This value is only used if enough stack space for the callback function is known to exist.
DCB_FUNCTION	The dwCallback parameter is the address of an application-defined callback function. The system sends the callback message to the callback function.
DCB_WINDOW	The dwCallback parameter is the handle of an application-defined window. The system sends subsequent notifications to the window.
DCB_TASK	The dwCallback parameter is the handle of an application or task. The system sends subsequent notifications to the application or task.
hdrvr

Handle of the installable driver instance.

msg

Message value.

dwUser

32-bit user-instance data supplied by the application when the device was opened.

dwParam1 and dwParam2

32-bit message-dependent parameter.

The client specifies how to notify it when the device is opened. The DCB_FUNCTION and DCB_WINDOW flags are equivalent to the high-order word of the corresponding flags CALLBACK_FUNCTION and CALLBACK_WINDOW specified in the lParam2 parameter of the DRV_OPEN message when the device was opened.

If notification is accomplished with a callback function, hdrvr, msg, dwUser, dwParam1, and dwParam2 are passed to the callback function. If notification is accomplished by means of a window, only msg, hdrvr, and dwParam1 are passed to the window.


DRV_CLOSE

Directs the driver to close the given instance. If no other instances are open, the driver should prepare for subsequent release from memory.

•	Returns nonzero if successful or zero otherwise.

dwDriverId

Identifier of the installable driver. This is the same value previously returned by the driver from the DRV_OPEN message.

hdrvr

Handle of the installable driver instance.

lParam1

32-bit value specified as the lParam1 parameter in a call to the DriverClose function.

lParam2

32-bit value specified as the lParam2 parameter in a call to the DriverClose function.


DRV_CONFIGURE

Directs the installable driver to display its configuration dialog box and let the user specify new settings for the given installable driver instance.

•	Returns one of these values:

DRVCNF_OK	The configuration is successful; no further action is required.
DRVCNF_CANCEL	The user canceled the dialog box; no further action is required.
DRVCNF_RESTART	The configuration is successful, but the changes do not take effect until the system is restarted.
dwDriverId

Identifier of the installable driver. This is the same value previously returned by the driver from the DRV_OPEN message.

hdrvr

Handle of the installable driver instance.

lParam1

Handle of the parent window. This window is used as the parent window for the configuration dialog box.

lParam2

Address of a DRVCONFIGINFO structure or NULL. If the structure is given, it contains the names of the registry key and value associated with the driver.

Some installable drivers append configuration information to the value assigned to the registry value associated with the driver.

The DRV_CANCEL, DRV_OK, and DRV_RESTART return values are obsolete; they have been replaced by DRVCNF_CANCEL, DRVCNF_OK, and DRVCNF_RESTART, respectively.


DRV_DISABLE

Disables the driver. The driver should place the corresponding device, if any, in an inactive state and terminate any callback functions or threads.

•	No return value.

hdrvr

Handle of the installable driver instance.

The dwDriverId, lParam1, and lParam2 parameters are not used.

After disabling the driver, the system typically sends the driver a DRV_FREE message before removing the driver from memory.


DRV_ENABLE

Enables the driver. The driver should initialize any variables and locate devices with the input and output (I/O) interface.

•	No return value.

hdrvr

Handle of the installable driver instance.

The dwDriverId, lParam1, and lParam2 parameters are not used.

Drivers are considered enabled from the time they receive this message until they are disabled by using the DRV_DISABLE message.


DRV_EXITSESSION

Notifies the driver that Windows is preparing to exit. The driver should prepare for termination.

•	No return value.

dwDriverId

Identifier of the installable driver. This is the same value previously returned by the driver from the DRV_OPEN message.

hdrvr

Handle of the installable driver instance.

The lParam1 and lParam2 parameters are not used.


DRV_FREE

Notifies the driver that it is being removed from memory. The driver should free any memory and other system resources that it has allocated.

•	No return value.

hdrvr

Handle of the installable driver instance.

The dwDriverId, lParam1, and lParam2 parameters are not used.

The DRV_FREE message is always the last message that a device driver receives.


DRV_INSTALL

Notifies the driver that is it being installed. The driver should create and initialize any needed registry keys and values and verify that the supporting drivers and hardware are installed and properly configured.

•	Returns one of these values:

DRVCNF_OK	The installation is successful; no further action is required.
DRVCNF_CANCEL	The installation failed..
DRVCNF_RESTART	The installation is successful, but it does not take effect until the system is restarted.
dwDriverId

Identifier of the installable driver. This is the same value previously returned by the driver from the DRV_OPEN message.

hdrvr

Handle of the installable driver instance.

lParam2

Address of a DRVCONFIGINFO structure or NULL. If a structure is given, it contains the names of the registry key and value associated with the driver.

The lParam1 parameter is not used.

Some installable drivers append configuration information to the value assigned to the registry value associated with the driver.


DRV_LOAD

Notifies the driver that it has been loaded. The driver should make sure that any hardware and supporting drivers it needs to function properly are present.

•	Returns nonzero if successful or zero otherwise.

The hdrvr parameter is always zero. The dwDriverId, lParam1, and lParam2 parameters are not used.

The DRV_LOAD message is always the first message that a device driver receives.


DRV_OPEN

Directs the driver to open an new instance.

•	Returns a nonzero value if successful or zero otherwise.

dwDriverId

Identifier of the installable driver.

hdrvr

Handle of the installable driver instance.

lParam1

Address of a null-terminated, wide-character string that specifies configuration information used to open the instance. If no configuration information is available, either this string is empty or the parameter is NULL.

lParam2

32-bit driver-specific data.

If the driver returns a nonzero value, the system uses that value as the driver identifier (the dwDriverId parameter) in messages it subsequently sends to the driver instance. The driver can return any type of value as the identifier. For example, some drivers return memory addresses that point to instance-specific information. Using this method of specifying identifiers for a driver instance gives the drivers ready access to the information while they are processing messages.


DRV_POWER

Notifies the driver that power to the device is being turned on or off.

•	Returns nonzero if successful or zero otherwise.

dwDriverId

Identifier of the installable driver. This is the same value previously returned by the driver from the DRV_OPEN message.

hdrvr

Handle of the installable driver instance.

The lParam1 and lParam2 parameters are not used.


DRV_QUERYCONFIGURE

Directs the driver to specify whether it supports custom configuration.

•	Returns a nonzero value if the driver can display a configuration dialog box or zero otherwise.

dwDriverId

Identifier of the installable driver. This is the same value previously returned by the driver from the DRV_OPEN message.

hdrvr

Handle of the installable driver instance.

The lParam1 and lParam2 parameters are not used.


DRV_REMOVE

Notifies the driver that it is about to be removed from the system. When a driver receives this message, it should remove any sections it created in the registry.

•	No return value.

dwDriverId

Identifier of the installable driver. This is the same value previously returned by the driver from the DRV_OPEN message.

hdrvr

Handle of the installable driver instance.

The lParam1 and lParam2 parameters are not used.


DRVCONFIGINFO

typedef struct tagDRVCONFIGINFO {
    DWORD dwDCISize;             // see below
    LPCWSTR lpszDCISectionName;  // see below
    LPCWSTR lpszDCIAliasName;    // see below
} DRVCONFIGINFO;

Contains the registry key and value names associated with the installable driver.

dwDCISize

Size of the structure, in bytes.

lpszDCISectionName

Address of a null-terminated, wide-character string specifying the name of the registry key associated with the driver.

lpszDCIAliasName

Address of a null-terminated, wide-character string specifying the name of the registry value associated with the driver.


Legal Information

Information in this online help system is subject to change without notice and does not represent a commitment on the part of Microsoft Corporation. The software and/or files described in this online help system are furnished under a license agreement or nondisclosure agreement. The software and/or files may be used or copied only in accordance with the terms of the agreement. The purchaser may make one copy of the software for backup purposes. No part of this online help system may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopying, recording, or information and retrieval systems, for any purpose other than the purchaser's personal use, without the written permission of Microsoft Corporation.

Microsoft may have patents or pending patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in this document. The furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other intellectual property rights except as expressly provided in any written license agreement from Microsoft.

Copyright © 1994-1995 Microsoft Corporation. All rights reserved.

Microsoft, MS, MS-DOS, Visual Basic, Win32, Win32s, and Windows are registered trademarks, and Visual C++ and Windows NT are trademarks of Microsoft Corporation.

Apple and Macintosh are registered trademarks of Apple Computer, Inc. Corel is a registered trademark of Corel Systems Corporation. IBM is a registered trademark of International Business Machines Corporation. Ami Pro, Lotus, and 1-2-3 are registered trademarks of Lotus Development Corporation. WordPerfect is a registered trademark of Novell, Inc.


Overview

Today's software applications are more capable and easier to use than ever before. Yet as their feature sets have grown in complexity and size, they have become increasingly difficult and costly to engineer, maintain, and upgrade. Adding new features always runs the risk of introducing new, sometimes intractable bugs and endangers backward compatibility with earlier versions. In addition, most applications are monolithic, providing rich sets of features but no easy way to add missing features or remove unneeded ones. Applications that do support adding and removing features in the form of plug-in components may expose their services to sibling applications from the same vendor but rarely to those from entirely different vendors. As a result, applications from different vendors typically work together poorly or not at all.

Operating systems have a related set of problems. Because most operating systems are not sufficiently modular, upgrading, replacing, or overriding existing services in a clean, flexible way is difficult. Like application developers, systems vendors face the difficult choice of foregoing or compromising needed improvements in order to maintain backward compatibility, or disenfranchising existing users in order to move the technology forward. These are choices that serve no one.

Software developers have recognized for some time that object-oriented programming offers promising solutions to several of these problems. By encapsulating data and functions in a single entity, then providing access to this rich content through a single reference, or pointer, object-oriented programming makes it possible to break down monolithic applications into functional modules, or components, that can be added or removed as they are needed. Moreover, object-oriented programming can potentially reduce the expense of implementing new objects by enabling them, through mechanisms such as inheritance, polymorphism, and aggregation, to make use of the capabilities built into already-existing objects.

Even so, object-oriented programming has yet to reach its full potential because no standard framework has existed through which software objects created by different vendors could interact with one another within the same address space, much less across process, machine, and network boundaries. Once you have broken down software into manageable, interchangeable components, you need some way for those components to communicate. That's where OLE comes in.

OLE provides a standard conceptual framework for creating, managing, and accessing object-based components that provide services to other objects and applications. OLE components can exist as parts of an operating system or application, or as stand-alone entities, and the services they provide can be most anything that operating systems and applications currently supply. You can use OLE components to expose both data and services to programs created by other vendors and write your own applications in such a way as to take advantage of services provided by others. You can also extend or customize basic OLE services to suit the needs of your objects and applications while guaranteeing that they continue to work with other OLE components.


Explaining the Component Object Model

The bedrock on which OLE rests is the Component Object Model (COM), which provides both the programming model and binary standard for OLE components. COM defines and implements mechanisms that enable software components, such as applications, data objects, controls, and services, to interact as objects. A software object comprises some body of data, along with one or more functions for accessing and using that data. An OLE component is one in which access to an object's data is achieved exclusively through one or more sets of related functions called interfaces.

An object provider, or server, makes an OLE component available by implementing one or more interfaces. A prospective user, or client, of an OLE component gains access to the object by obtaining a pointer to one of its interfaces. With this pointer, the client can reliably use the object without understanding its implementation and with the assurances that the object will always behave the same way. In this sense, an object's interface is a contract defining its behavior for prospective clients. The object will honor that contract even if its client lives in a different process or on a different machine, runs under a different operating system, is written by a different software developer using a different computer language, or represents an earlier or later version than the client used before.

By defining interfaces as contracts between objects and their clients, COM effectively solves the versioning problem. Here's how. To create a new version of an object, you simply add new interfaces while leaving the older ones in place. You define the new interfaces in such a way that clients are permitted to query for either the new version of the interface, or the old version, but not for both. Because of this restriction, adding new interfaces, or new versions of older interfaces, in no way interferes with the way existing clients work with an object.

Because OLE components conform to a binary standard, you can implement them using nearly any programming language. Object-oriented languages such as C++ and Smalltalk are ideal for this purpose, but any procedural language, such as C or Pascal, that supports the notion of a reference, or pointer, to an object will do. OLE components implemented in one programming language will work, without modification, with applications or other objects implemented in another language. In addition, because OLE components are language-independent, they are not constrained by language-based requirements to operate in the same address space as the objects or applications using them. As a result, OLE components provide the basis for sharing information among separate objects in different processes on the same machine or on different networked computers.


OLE Information Management

Built on top of COM are core facilities for storing and naming objects and for transferring data between them. Together, these facilities form the core of system-wide information management. You can take advantage of these facilities by using OLE's supplied implementations, or you can extend or replace them with your own. These core facilities include structured storage, monikers, and uniform data transfer. Together they provide the infrastructure required for objects to interrelate across process, machine, and network boundaries.

OLE's structured storage model defines an architecture for storing and retrieving objects that reside inside files or other containers. The basic problem addressed by the structured storage model is how to write an object to and retrieve an object from any persistent storage when that object resides inside the flat file space of some container. OLE solves the problem by providing interfaces that support storage and stream objects. A storage object provides a hierarchical structure for mapping the location of storage and stream objects just as directories provide a way of locating files on disk. A stream object contains the object's data, or contents. Using structured storage is mandatory if you want to support compound documents or other forms of containment. OLE also provides a default implementation of structured storage called compound files.

OLE supports the persistent naming of objects through a mechanism called a moniker. A moniker provides a way for clients of an object to locate that object even when it resides in a different process or on a different computer. Objects have a file moniker, which is similar to their absolute pathnames, but their clients normally bind to them using a relative moniker, which indicates the object's location relative to the client. In this way, if client and object are both relocated, they can maintain their connection as long as their locations relative to each other remain the same. In general, a moniker also enables clients to locate and connect to some portion of an object—a certain range of cells in a spreadsheet, for example—by providing an item moniker, by which that pseudo-object is always known.

OLE's uniform data transfer model provides a single, standard mechanism for transferring objects and data between applications. Through a single interface, OLE supports standard Microsoft® Windows® clipboard transfers, as well as drag and drop, and embedded objects. Uniform data transfer greatly enhances the clipboard model by providing rich structures for describing the format of the data to be transferred and the storage medium in which a transfer is to occur. For example, instead of always having to pass data in a global memory handle, you can choose from among several storage media, including a disk-based file and pointers to OLE storage and stream interfaces.

Built on top of COM, structured storage, monikers, and uniform data transfer are the three technologies for which OLE is best known: compound documents, OLE automation, and OLE controls. For many software vendors, the desire to incorporate one or both of these technologies in their applications, or to make sure their applications work easily with operating systems and other applications that do, has been the prime motivation for turning to OLE.


Describing Compound Documents

A compound document is one that contains, along with its native data, one or more objects that were created in other applications and therefore have different data formats. Such objects are called compound document objects. An application used to create compound document objects is called an OLE server application. An application whose documents act as object clients is called a container application or, simply, a container. Any given application can be one, or the other, or both.

Compound document objects are essentially OLE components that also implement interfaces that support object linking and embedding. A linked object includes information about the location of its data and the formats necessary to present it on screen to the user, but the data itself is stored elsewhere. An embedded object is one whose data is stored along with that of its container. Applications that support linking and embedding can share data without having knowledge of one another's data structures and without having to implement separate protocols for every other application with which they communicate. Users of OLE compound document applications can embed data created in one application in a document created in another, and can view, edit, or otherwise manipulate that data without having to exit the application in which they are working. Users can also create links in one document to data in another so that changes to data in the source document are updated in the link.


Defining OLE Automation

OLE automation is the ability for one application or tool to manipulate programmatically objects exposed by another application. Using OLE automation, you can also create tools that access and manipulate objects. Such tools can include embedded macro languages, programming tools, object browsers, and compilers. Like compound documents, OLE automation is based on COM, but applications can implement OLE automation independently of compound documents or other OLE technologies.


Where to Find Additional Information

The current release of OLE Programmer's Guide examines the architecture and capabilities of OLE as a whole, as well as of each of its core facilities: COM, structured storage, and uniform data transfer. A separate chapter is devoted to compound documents, the technology that inspired the original development of OLE and laid the groundwork for its evolution into a systemwide, object-based service architecture. A subsequent release of the OLE Programmer's Guide will include detailed instructions for developing both OLE client and server applications for compound documents that work under both Microsoft® Windows NT™ and Microsoft® Windows® 95. For descriptions of specific interfaces, helper functions, data structures, and enumerations, refer to  the OLE Programmer's Reference, Volume 1. For information on OLE automation and developing OLE controls, see the OLE Programmer's Reference, Volume 2 Automation.


The Component Object Model

The Component Object Model (COM) is the base technology of OLE, a broad set of object-oriented technology standards. OLE includes, besides COM, object design standards at a higher level. Among these are standards for OLE Structured Storage, OLE Compound Documents, and OLE Controls. COM is the binary standard that defines the means for applications to interact within these technology standards.

To understand COM (and therefore all OLE technologies), it is crucial to bear in mind that it is not an object-oriented language, but a standard. Nor does COM specify how an application should be structured. Language, structure, and implementation details are left to the application programmer. COM does specify an object model and programming requirements that enable COM objects (also called OLE Components, or sometimes simply objects) to interact with other objects. These objects can be within a single process, in other processes, even on remote machines. They can have been written in other languages, and may be structurally quite dissimilar. That is why COM is referred to as a binary standard — it is a standard that applies after a program has been translated to binary machine code.

The only language requirement for COM is that code is generated in a language that can create structures of pointers and, either explicitly or implicitly, call functions through pointers. Object-oriented languages such as C++ and Smalltalk provide programming mechanisms that simplify the implementation of COM objects, but languages such as C, Pascal, Ada, and even BASIC programming environments can create and use OLE objects.

COM defines the essential nature of an OLE Component. In general, a software object is made up of a set of data and the functions that manipulate the data. An OLE Component is one in which access to an object's data is achieved exclusively through one or more sets of related functions. These function sets are called interfaces, and the functions of an interface are called methods. Further, COM requires that the only way to gain access to the methods of an interface is through a pointer to the interface.

Besides specifying the basic binary object standard, COM defines certain basic interfaces that provide function common to all COM-based technologies. It also provides a small number of API functions that all components require.


OLE Components and Interfaces

COM is a technology that allows objects to interact across process and machine boundaries as easily as objects within a single process interact. COM enables this by specifying that the only way to manipulate the data associated with an object is through what is called an interface on the object. When this term is used, it refers to an implementation in code of a COM binary-compliant interface that is associated with an object.

Talking about an object that implements an interface means that the object uses code that implements each method of the interface and provides COM binary-compliant pointers to those functions to the COM library. COM then makes those functions available to any client who asks for a pointer to the interface, whether the client is inside or outside of the process that implements those functions.


Interfaces and Interface Implementations

COM makes a fundamental distinction between interface definitions and their implementations. An interface is actually a contract that consists of a group of related function prototypes whose usage is defined but whose implementation is not. These function prototypes are equivalent to pure virtual base classes in C++ programming. An interface definition specifies the interface's member functions, called methods, their return types, the number and types of their parameters, and what they must do. There is no implementation associated with an interface.

An interface implementation is the code a programmer supplies to carry out the actions specified in an interface definition. Implementations of many of the interfaces a programmer could use in an object-based application are included in the OLE libraries. Programmers are, however, free to ignore these implementations and write their own. An interface implementation is to be associated with an object when an instance of that object is created, and provides the services that the object offers.

For example, a hypothetical interface named IStack (many interface names begin with the letter "I") might define two methods, named Push and Pop, specifying that successive calls to the Pop method return, in reverse order, values previously passed to the Push method. This interface definition, however, would not specify how the functions are to be implemented in code. In implementing the interface, however, one programmer might implement the stack as an array and implement the Push and Pop methods in such a way as to access that array; while another programmer might prefer to use a linked list and would implement the methods accordingly. Regardless of a particular implementation of the Push and Pop methods, however, the in-memory representation of a pointer to an IStack interface, and therefore its use by a client, is completely defined by the interface definition.

Simple objects may support only a single interface. More complicated objects, such as embeddable objects, typically support several interfaces. Clients have access to an OLE object only through a pointer to one of its interfaces, which, in turn, allows the client to call any of the methods that make up that interface. These methods determine how a client can use the object's data.

Interfaces, in fact, define a contract between an object and its clients. The contract specifies the methods that must be associated with each interface, and what the behavior of each of the methods must be in terms of input and output. The contract generally does not define how to implement the methods in an interface. Another important aspect of the contract is that if an object supports an interface, it must support all of its methods in some way. Not all of the methods in an implementation need to do something—if an object does not support the function implied by a method, its implementation may be a simple return, or perhaps the return of a meaningful error message—but the methods must exist.

COM uses the word "interface" in a sense different from that typically used in C++ programming. A C++ interface refers to all of the functions that a class supports and that clients of an object can call to interact with it. A COM interface refers to a predefined group of related functions that a COM class implements, but does not necessarily represent all the functions that the class supports.


Interface Pointers and Interfaces

An instance of an interface implementation is actually a pointer to an array of pointers to methods (a function table that refers to an implementation of all of the methods specified in the interface). Objects with multiple interfaces can provide pointers to more than one function table. Any code that has a pointer through which it can access the array can call the methods in that interface.

Speaking precisely about this multiple indirection is inconvenient, so instead, the pointer to the interface function table that another object must have to call its methods is called simply an interface pointer. You can manually create function tables in a C application or almost automatically with C++ (or other object-oriented languages that support COM).

With appropriate compiler support (which is inherent in C and C++), a client can call an interface method through its name, not its position in the array. Because an interface is a type, given the names of methods the compiler can check the types of parameters and return values of each interface method call. In contrast, such type-checking is not available even in C or C++ if a client uses a position-based calling scheme.

Each interface—the immutable contract of a functional group of methods—is referred to at runtime with a globally-unique interface identifier, an "IID". This IID, which is a specific instance of a GUID (a Globally Unique IDentifier supported by OLE) allows a client to ask an object precisely if it supports the semantics of the interface without unnecessary overhead and without the confusion that could arise in a system from having multiple versions of the same interface with the same name.

To summarize, it is important to understand what an interface is, and is not:

•	An interface is not the same as a C++ class.

•	An interface is not an object.

•	Interfaces are strongly typed.

•	Interfaces are immutable.

An interface is not a C++ class—the pure virtual definition carries no implementation. If you are a C++ programmer, you can, however, define your implementation of an interface as a class, but this falls under the heading of implementation details, which COM does not specify. An instance of an object that implements an interface must be created for the interface actually to exist. Furthermore, different object classes may implement an interface differently yet be used interchangeably in binary form, as long as the behavior conforms to the interface definition.

An interface is not an object — it is simply a related group of functions and is the binary standard through which clients and objects communicate. The object can be implemented in any language with any internal state representation, as long as it can provide pointers to interface methods.

Interfaces are strongly typed — every interface has its own interface identifier (a GUID), which eliminates the possibility of duplication that could occur with any other naming scheme.

Interfaces are immutable contracts — you cannot define a new version of an old interface and give it the same identifier. Adding or removing methods of an interface, or changing semantics creates a new interface, not a new version of an old interface. Therefore a new interface cannot conflict with an old interface. Objects can, of course, support multiple interfaces simultaneously, and can expose interfaces that are successive revisions of an interface, with different identifiers. Thus, each interface is a separate contract, so system-wide objects need not be concerned about whether the version of the interface they are calling is the one they expect. The interface ID (IID) defines the interface contract explicitly and uniquely.


IUnknown and Interface Definition Inheritance

Inheritance in COM does not mean code reuse. Because no implementations are associated with interfaces, interface inheritance does not mean code inheritance. It means only that the contract associated with an interface is inherited in a C++ pure-virtual base-class fashion and modified—either by adding new methods or by further qualifying the allowed usage of methods. There is no selective inheritance in COM: If one interface inherits from another, it includes all the methods that the other interface defines.

Inheritance is used sparingly in the predefined COM interfaces. All predefined interfaces inherit their definitions from the important interface IUnknown, which contains three vital methods: QueryInterface, AddRef, and Release. All COM objects must implement the IUnknown interface, because it provides the means to move freely between the different interfaces that an object supports with QueryInterface, and to manage its lifetime with AddRef and Release. More on these methods is discussed later in this chapter.

Any single object usually requires only a single implementation of the IUnknown methods. This means that by implementing any interface on an object you must completely implement the IUnknown functions. You do not generally need to explicitly inherit from nor implement IUnknown as its own interface. When a client of the object queries for it, it is usually necessary only to typecast another interface pointer into an IUnknown, as this interface makes up the first three entries in the function table already.

In some specific situations, notably in creating an object that supports aggregation, you may need to implement one set of IUnknown functions for all interfaces as well as a stand-alone IUnknown interface. This is described in the following section. In any case, any object implementor will implement IUnknown methods.

While there are a few interfaces that inherit their definitions from a second interface, in addition to IUnknown, the majority are simply the IUnknown interface methods plus the methods defined in the interface. This makes most interfaces relatively compact and easy to encapsulate.


Reusing Objects

An important goal of any object model is that object authors can reuse and extend objects provided by others as pieces of their own implementations. One way to do this in C++ and other languages is implementation inheritance, which allows an object to inherit ("subclass") some of its functions from another object while overriding other functions.

The problem for system-wide object interaction using traditional implementation inheritance is that the contract (the interface) between objects in an implementation hierarchy is not clearly defined. In fact, it is implicit and ambiguous. When the parent or child object changes its implementation, the behavior of related components may become undefined, or unstably implemented. In any single application, where the implementation can be managed by a single engineering team, who update all of the components at the same time, this is not always a major concern. In an environment where the components of one team are built through black-box reuse of other components built by other teams, this type of instability jeapordizes reuse. Additionally, implementation inheritance usually works only within process boundaries. This makes traditional implementation inheritance impractical for large, evolving systems composed of software components built by many engineering teams.

The key to building reusable components is to be able to treat the object as a black box. This means that the piece of code attempting to reuse another object knows nothing, and needs to know nothing, about the internal structure or implementation of the component being used. In other words, the code attempting to reuse a component depends upon the behavior of the object and not the exact implementation.

To achieve black-box reusability, COM adopts other established reusability mechanisms: containment/delegation and aggregation. For convenience in describing them, the object being reused is called the inner object and the object making use of that inner object is the outer object.

It is important to remember in both these mechanisms how the outer object appears to its clients. As far as the clients are concerned, both objects implement any interfaces to which the client can get a pointer. The client treats the outer object as a black box, and thus does not care, nor does it need to care, about the internal structure of the outer object — the client cares only about behavior.


Containment/Delegation

The first, and most common, mechanism is called containment/delegation. This type of reuse is a familiar concept found in most object-oriented languages and systems. The outer object acts as an object client to the inner object. The outer object "contains" the inner object and when the outer object requires the services of the inner object, the outer object explicitly delegates implementation to the inner object's methods. Thus, the outer object uses the inner object's services to implement itself.

It is not necessary for the outer and inner objects to support the same interfaces, although it certainly is reasonable to contain an object that implements an interface that the outer object does not, and implement the methods of the outer object simply as calls to the corresponding methods in the inner object. When the complexity of the outer and inner objects differs greatly, however, the outer object may implement some of the methods of its interfaces by delegating calls to interface methods implemented in the inner object.

It is simple to implement containment for an outer object. The outer object creates the inner objects it needs to use as any other client would. This is nothing new — the process is like a C++ object that itself contains a C++ string object that it uses to perform certain string functions, even if the outer object is not considered a "string" object in its own right. Then, using its pointer to the inner object, a call to a method in the outer object generates a call to an inner object method.


Aggregation

Aggregation is the other, richer, reuse mechanism, in which the outer object exposes interfaces from the inner object as if they were implemented on the outer object itself. This is useful when the outer object would always delegate every call to one of its interfaces to the same interface in the inner object. Aggregation is actually a specialized case of containment/delegation, and is available as a convenience to avoid extra implementation overhead in the outer object in these cases.

Aggregation is almost as simple to implement as containment is, except for the three IUnknown functions: QueryInterface, AddRef, and Release. The catch is that from the client's perspective, any IUnknown function on the outer object must affect the outer object. That is, AddRef and Release affect the outer object and QueryInterface exposes all the interfaces available on the outer object. However, if the outer object simply exposes an inner object's interface as its own, that inner object's IUnknown members called through that interface will behave differently than those IUnknown members on the outer object's interfaces, an absolute violation of the rules and properties governing IUnknown.

The solution is for the outer object to somehow pass the inner object some IUnknown pointer to which the inner object can re-route (that is, delegate) IUnknown calls in its own interfaces, and yet there must be a method through which the outer object can access the inner object's IUnknown functions that affect only the inner object. COM provides specific support for this solution. Briefly, aggregation requires an explicit implementation of IUnknown on the inner object and delegation of the IUnknown methods of any other interface to the outer object's IUnknown methods.


The COM Library

In addition to being a specification, COM also implements some important services in the COM Library. Provided as a DLL in Microsoft® Windows®, the COM Library includes:

•	A small number of fundamental API functions that facilitate the creation of COM applications, both client and server. For clients, COM supplies basic functions for creating objects. For servers, COM supplies the means of exposing their objects.

•	Implementation-locator services through which COM determines from a unique class identifier (CLSID) which server implements that class and where that server is located. This service includes support for a level of indirection, usually a system registry, between the identity of an object class and the packaging of the implementation such that clients are independent of the packaging, which can change in the future.

•	Transparent remote procedure calls when an object is running in a local or remote server.

•	A standard mechanism to allow an application to control how memory is allocated within its process, particularly memory that needs to be passed between cooperating objects such that it can be freed properly.

To use the basic services that COM supplies, all COM applications must call the CoInitialize function before calling any other COM function. This function initializes the COM library, allowing the application to use its services. OLE Compound Document applications call the OleInitialize function, which calls CoInitialize and also does some initialization required for compound documents.

It is also important to uninitialize the library. For each call to CoInitialize (or OleInitialize, there must be a corresponding call to CoUninitialize (or OleUninitialize).


OLE Class Objects and CLSIDs

A COM class is an implementation of a group of interfaces in code executed whenever you interact with a given object. It is important to make the distinction between a C++ class and a COM class. In C++, a class is a type. A COM class is simply a definition of the object, and carries no type, although a C++ programmer might implement it using a C++ class. COM is designed to allow a class (object definition) to be used by different applications, including applications written without knowledge of that particular class's existence. Therefore, class code for a given type of object exists either in a dynamic linked library (DLL) or in another application (EXE). COM specifies a mechanism by which the class code can be used by many different applications.

A COM class is identified by a unique 128-bit CLSID. This CLSID is used to associate an object class with the DLL or EXE in the file system whose code implements the class. A CLSID, like an interface identifier, is a GUID, so no other class, no matter who writes it, has a duplicate CLSID. Server implementors generally obtain CLSIDs through the CoCreateGUID function in COM. This function is guaranteed to produce unique CLSIDs, so server implementors across the world can independently develop and deploy their software without fear of accidental collision with software written by others.

Using unique CLSIDs avoids the possibility of name collisions among classes because CLSIDs are in no way connected to the names used in the underlying implementation. So, for example, two different vendors can write classes called "StackClass," but each would have a unique CLSID and therefore could not be confused.

On its host system, COM maintains a database (it makes use of the system registration database, or "registry" on Windows platforms) of all the CLSIDs for the servers installed on the system. This is a mapping between each CLSID and the location of the DLL or EXE that houses the code for that CLSID. COM consults this database whenever a client wants to create an instance of a COM class and use its services. The client, however, that needs to know only the CLSID, is independent of the specific installation location of the DLL or EXE on the particular machine.

When a COM application passes a CLSID to COM and asks for an object instance in return, it is a COM client. No matter where the server is located (in-process, local, or remote), a COM client always asks COM to create an object instance in exactly the same way.

The basic way to implement a class is through a COM class object. This is a simply an intermediate object that supports functions common to creating new instances of a given class. All class objects used to create objects from a CLSID support the IClassFactory interface, an interface that includes the important method CreateInstance. You implement an IClassFactory interface for each class of object that you offer to be instantiated.

When a client wants to create an instance of a class, it calls the COM function CoGetClassObject, supplying to it the CLSID of the desired class. This call instantiates the class object for the class and returns a pointer to the class object's IClassFactory interface implementation. The client would then call the returned interface's CreateInstance method, which creates an instance of the class and returns a pointer to a requested interface on the object.

At that point the client has interface pointers for two separate objects, the class object and an object of that class, each with their own reference counts. This is an important distinction.

The simplest way to create one instance is to call the COM function CoCreateInstance. It is a convenient helper function for clients that want to create a single instance of a class. The CoCreateInstance function internally calls CoGetClassObject itself, encapsulates the process just described, and additionally releases the class object for you.

In summary, a COM Client, in addition to its responsibilities as a COM application, must use COM to obtain a class object, ask the class object to create an object, initialize the object, and to call that object's (and the class object's) Release function when the client is finished with it.


Registering a COM Server

After you have defined a class in code and given it a CLSID and a class object, it is important to make OLE aware of the object by associating a DLL or EXE server with the CLSID.  By doing so, clients can create instances of it. There are two ways of doing this, depending on whether your class is available only dynamically (while some process or activity is running), or at any time (by running code that has been installed in the system).

In the former case, you can register a dynamic class with the system by using CoRegisterClassObject, passing to that function a CLSID and a pointer to an IClassFactory interface. Subsequent clients who call CoCreateInstance or CoGetClassObject with this CLSID will retrieve a reference to this IClassFactory pointer.

In the latter case, you can register information in the class database (within the registry) during installation of your component, telling COM what type of object you are defining and how it is to be instantiated. For example, classes implemented in dynamic-link libraries can specify that COM will load their DLL and call a well-known entry-point (DllGetClassObject) to retrieve an IClassFactory interface. Similarly, classes implemented in executables can specify that COM should execute their process and wait for the process to register their class object's IClassFactory through a call to the CoRegisterClassObject function.

Details about the information required in the registry can be found in Appendix A.


Getting a Pointer to an Object

Because OLE does not have a strict class model, there are several ways to instantiate or to get a pointer to an interface on an object. There are, in fact, four methods through which a client obtains its first interface pointer to a given object:

•	Call a COM Library API function that creates an object of a pre-determined type — that is, the function will only return a pointer to one specific interface for a specific object class.

•	Call a COM Library API function that can create an object based on a class identifier (CLSID) and that returns any type of interface pointer requested.

•	Call a method of some interface that creates another object (or connects to an existing one) and returns an interface pointer on that separate object.

•	Implement an object with an interface through which other objects pass their interface pointer to the client directly.

There are numerous OLE functions that return specific pointers to specific functions, such as CoGetMalloc, which returns a pointer to the standard OLE memory allocator.

The COM API functions CoGetClassObject and CoCreateInstance, described earlier, create a class object and return a pointer to a requested object. A special case of this kind of API is the OLE Compound Document helper API OleCreate, which creates an instance of an embeddable object based on a CLSID.

Among the many interface methods that return a pointer to a separate object are several that create and return a pointer to an enumerator object, which allows you to determine how many items of a given type an object maintains. OLE defines interfaces for enumerating a wide variety of items, such as strings, several structures important in various OLE technologies, monikers, and IUnknown interface pointers. The typical way to create an enumerator instance and get a pointer to its interface is to call a method from another interface. For example, the IDataObject interface defines two methods, EnumDAdvise and EnumFormatEtc, that return pointers to interfaces on two different enumeration objects. There are many other examples in OLE of methods that return pointers to objects, such as the OLE Compound Document interface IOleObject::GetClientSite, which, when called on the embedded or linked object, returns a pointer to the container object's implementation of IOleClientSite.

The fourth way to get a pointer to an object is used when two objects, such as an OLE Compound Document container and server need bi-directional communication. Each implements an object containing an interface method to which other objects can pass interface pointers. In the case of containers and servers, each object then passes its pointer to the other object. The implementing object, which is also the client of the created object, can then call the method and get the pointer that was passed.


QueryInterface: Navigating in an Object

Once you have an initial pointer to an interface on an object, OLE has a very simple mechanism to find out whether the object supports another specific interface, and, if so, to get a pointer to it. This mechanism is the QueryInterface method of the IUnknown interface. If the object supports the requested interface, the method must return a pointer to that interface. This permits an object to navigate freely through the interfaces that an object supports. QueryInterface separates the request "Do you support a given contract?" from the high-performance use of that contract once negotiations have been successful.

When a client initially gains access to an object, that client will receive, at a minimum, an IUnknown interface pointer (the most fundamental interface) through which it can control the lifetime of the object — tell the object when it is done using the object — and invoke QueryInterface. The client is programmed to ask each object it manages to perform some operations, but the IUnknown interface has no functions for those operations. Instead, those operations are expressed through other interfaces. The client is thus programmed to negotiate with objects for those interfaces. Specifically, the client will ask an object — by calling QueryInterface — for an interface through which the client may invoke the desired operations.

Since the object implements QueryInterface, it has the ability to accept or reject the request. If the object accepts the client's request, QueryInterface returns a new pointer to the requested interface to the client. Through that interface pointer, the client has access to the methods of that interface. If, on the other hand, the object rejects the client's request, QueryInterface returns a null pointer — an error — and the client has no pointer through which to call the desired functions. In this case, the client must deal gracefully with that possibility. For example, suppose a client has a pointer to interface A on an object, and asks for interfaces B and C. While the object supports interface B, it does not support interface C. The object returns a pointer to B, and reports that C is not supported.

A key point is that when an object rejects a call to QueryInterface, it is impossible for the client to ask the object to perform the operations expressed through the requested interface. A client must have an interface pointer to invoke methods in that interface. There is no alternative. If the object refuses to provide one, a client must be prepared to do without, simply not doing whatever it had intended to do with that object. Had the object supported that interface, the client might have done something useful with it. This works well in comparison with other object-oriented systems in which you cannot know whether a function will work until you call that function, and even then, handling failure is uncertain. QueryInterface provides a reliable and consistent way to know whether an object supports an interface before attempting to call its methods.

The QueryInterface method also provides a robust and reliable way for an object to indicate that it does not support a given contract. That is, if in a call to QueryInterface one asks an "old" object whether it supports a "new" interface (one, for example, that was invented after the old object had been shipped), the old object will reliably and , without causing a crash, answer "no." The technology that supports this is the algorithm by which IIDs are allocated. While this may seem like a small point, it is extremely important to the overall architecture of the system, and the ability to inquire of old things about new functionality is, surprisingly, a feature not present in most other object architectures.


Managing Object Lifetimes through Reference Counting

In traditional object systems, the life cycle of objects — the issues surrounding the creation and deletion of objects — is handled implicitly by the language (or the language runtime) —instances go explicitly out of scope as parameters or global variables, for example— or explicitly by application programmers.

In an evolving, decentrally constructed system made up of reused components, it is no longer true that any one or client, or even programmer, always "knows" how to deal with a component's lifetime. For a client with the right security privileges, it is still relatively easy to create objects through a simple request. But object deletion is another matter entirely. It is not necessarily clear when an object is no longer needed and should be deleted. Even when the original client is done with the object, it cannot simply shut the object down, because some other client (or clients) in the system may still have a reference to it.

One way to ensure that an object is no longer needed, so it can be deleted, is to depend entirely upon an underlying communication channel to inform the system when all connections to a cross-process or cross-channel object have disappeared. Schemes that use this method are unacceptable for several reasons. One problem is that it could require a major difference between the cross-process/cross-network programming model and the single-process programming model. In the cross-process/cross-network programming model, the communication system would provide the hooks necessary for component lifetime management, while in the single-process programming model, objects are directly connected without any intervening communications channel. Another problem is that this scheme could also result in a layer of system-provided software that would interfere with component performance in the in-process case. Furthermore, such a mechanism based on explicit monitoring would not tend to scale towards many thousands or millions of objects.

COM offers a scalable and distributed approach to this set of problems. Clients tell an object when they are using it and when they are done, and objects delete themselves when they are no longer needed. This approach mandates that all objects count references to themselves.

Just as an application must free memory it has allocated once that memory is no longer in use, a client of an object is responsible for freeing its references to the object when that object is no longer needed. In an object-oriented system, the client can only do this by giving the object an instruction to free itself.

It is important that an object be deallocated when it is no longer being used. The difficulty lies in determining when it is safe to deallocate an object. This is easy with automatic variables (those allocated on the stack) — they cannot be used outside the block in which they're declared, so the compiler deallocates them when the end of the block is reached. For COM objects, which are dynamically allocated, it is up to the clients of an object to decide when they no longer need to use the object — especially local or remote objects that may be in use by multiple clients at the same time. The object must wait until all clients are finished with it before freeing itself. Because COM objects are manipulated through interface pointers and can be used by objects in different processes or on other machines, the system cannot keep track of an object's clients.

COM's method of determining when it is safe to deallocate an object is manual reference counting. Each object maintains a 32-bit reference count that tracks how many clients are connected to it, that is, how many pointers exist to any of its interfaces in any client.


Implementing Reference Counting

Reference counting requires work on the part of both the implementor of a class and the clients who use objects of that class. When you implement a class, you must implement the AddRef and Release methods as part of the IUnknown interface. These two functions have simple implementations:

1.	AddRef increments the object's internal reference count.

2.	Release first decrements the object's internal reference count; then it checks whether the reference count has fallen to zero. If it has, that means no one is using the object any longer, so the Release function deallocates the object.

A common implementation approach for most objects is to have only one implementation of these functions (along with QueryInterface), which are shared between all interfaces, and therefore a reference count which applies to the entire object. Architecturally, however, from a client's perspective, reference counting is strictly and clearly a per-interface-pointer notion, and objects may be implemented which take advantage of this capability by dynamically constructing, destroying, loading, or unloading portions of their functionality based on the currently extant interface pointers

Whenever a client calls a method (or API function) that returns a new interface pointer, such as QueryInterface, the method being called is responsible for incrementing the reference count through the returned pointer. For example, when a client first creates an object, it receives an interface pointer to an object that, from the client's point of view, has a reference count of one. If the client then calls AddRef on the interface pointer, the reference count becomes two. The client must call Release twice on the interface pointer to drop all of its references to the object.

An illustration of how reference counts are strictly per-interface-pointer occurs when a client calls QueryInterface on the first pointer for either a new interface or the same interface. In either of these cases the client is required to call Release once for each pointer. COM does not require that an object return the same pointer when asked for the same interface multiple times. (The only exception to this is a query to IUnknown, which acts as an object's identity to COM.) This allows the object implementation to manage resources efficiently.


Rules for Managing Reference Counts

The elegance of using reference counting for object lifetime management is that independent objects can obtain and release access to a single object, and not have to coordinate with each other over lifetime management. In a sense, the object provides this management, so long as the client objects conform to the rules of use. Within a single object that is completely under the control of a single development organization, that organization can adopt whatever strategy it chooses. The following rules are about how to manage and communicate interface instances between objects, and are a reasonable starting point for a policy within an object.

The conceptual model is that interface pointers are thought of as living in pointer variables, which, for this discussion, include variables in memory locations and in internal processor registers, and both programmer- and compiler-generated variables. In short, it includes all internal computation state that holds an interface pointer. Assignment to or initialization of a pointer variable involves creating a new copy of an already existing pointer. Where there was one copy of the pointer in some variable (the value used in the assignment/initialization), there are now two. An assignment to a pointer variable destroys the pointer copy presently in the variable, as does the destruction of the variable itself (that is, the scope in which the variable is found, such as the stack frame, is destroyed).

Rule 1:

AddRef must be called for every new copy of an interface pointer, and Release called for every destruction of an interface pointer except where subsequent rules explicitly permit otherwise.

This is the default case. Unless special knowledge permits otherwise, the worst case must be assumed. The exceptions to Rule 1 all involve knowledge of the relationships of the lifetimes of two or more copies of an interface pointer. In general, they fall into two categories: 1) nested lifetimes and 2) overlapping lifetimes.

In a nested lifetime relationship, the first copy of the interface pointer is created, followed by the creation of the second copy. The second copy is destroyed before the end of the first copy's lifetime. The calls to AddRef and Release for the second copy can be omitted. The overlapping lifetime relationship begins like the nested lifetime relationship—the second interface pointer is created after the first. In overlapping lifetimes, however, the first pointer copy is destroyed before the second pointer copy. The calls to AddRef for the second copy and Release for the first copy can be omitted.

Rule 2:

If the piece of code has special knowledge of the relationships of the beginnings and the endings of the lifetimes of two or more copies of an interface pointer, it allows you to omit AddRef/Release pairs. The following rules call out specific common cases of Rule 2. The first two of these rules are particularly important, as they are especially common.

In-parameters to functions

The copy of an interface pointer which is passed as an actual parameter to a function has a lifetime which is nested in that of the pointer used to initialize the value. The actual parameter, therefore, need not be separately reference counted.

Out-parameters from functions, including return values

This situation falls under Rule 2. To set the out parameter, the function itself, by Rule 1, must have a stable copy of the interface pointer. On exit, the responsibility for releasing the pointer is transferred from the one called to the caller. Thus, the out-parameter need not be separately reference counted.

Local variables

A method implementation clearly has omniscient knowledge of the lifetimes of each of the pointer variables allocated on the stack frame. It can, therefore, use this knowledge to omit redundant AddRef/Release pairs.

Backpointers

Some data structures are contain two components, A and B, each with a pointer to the other. If the lifetime of one component (A) is known to contain the lifetime of the other (B), then the pointer from the second component back to the first (from B to A) need not be reference counted. Often, avoiding the cycle that would otherwise be created is important in maintaining the appropriate deallocation behavior. However, such non-reference counted pointers should be used with extreme caution. In particular, as the remoting infrastructure cannot know about the semantic relationship in use here, such backpointers cannot be remote references. In almost all cases, an alternative design of having the backpointer refer a second "friend" object of the first, rather than the object itself (thus avoiding the circularity), is a superior design.

The following rules call out common situations that follow from Rule 1.

In-Out parameters to functions

The caller must AddRef the actual parameter, since it will be released (with a call to Release) by the one called when the out-value is stored on top of it.

Fetching a global variable

The local copy of the interface pointer fetched from an existing copy of the pointer in a global variable must be independently reference counted since called functions might destroy the copy in the global while the local copy is still alive.

New pointers synthesized out of "thin air."

A function that synthesizes an interface pointer using special internal knowledge rather than obtaining it from some other source must do an initial AddRef on the newly synthesized pointer. Important examples of such routines include instance creation routines, implementations of IUnknown::QueryInterface, etc.

Returning a copy of an internally stored pointer

Once the pointer has been returned, the one called has no idea how its lifetime relates to that of the internally stored copy of the pointer. Thus, the one called must call AddRef on the pointer copy before returning it.

Finally, when implementing or using reference counted objects, a technique called artificial reference counts sometimes proves useful. In implementing a method of an interface, if you invoke functions that have even the remotest chance of decrementing your reference count, this may cause you to release before it returns to the method when it is called. The subsequent code in the method would  crash.

A robust way to protect yourself from this is to insert an AddRef at the beginning of the method implementation which is paired with a Release just before the method  returns.

These "artificial" reference counts guarantee object stability while processing is done.


Managing Memory Allocation

In COM, many, if not most, interface methods and APIs are called by code written by one programming organization and implemented by code written by another. Many of the parameters and return values of these functions are of types that can be passed around by value. Sometimes, however, it is necessary to pass data structures for which this is not the case, so it is necessary for both caller and called to have a compatible allocation and de-allocation policy. COM defines a universal convention for memory allocation, both because it is more reasonable than defining case-by-case rules, and so the COM remote procedure call implementation can correctly manage memory.

The methods of COM interface always provide memory management of pointers to the interface by calling the AddRef and Release functions found in the IUnknown interface, from which all other COM interfaces derive. This section describes only how to allocate memory for parameters that are not passed by value — not pointers to interfaces, but more mundane things like strings, pointers to structures, etc.


The OLE Memory Allocator

The COM Library provides an implementation of a memory allocator that is thread-safe (cannot cause problems in multi-threaded situations). A call to the API function CoGetMalloc provides a pointer to the OLE allocator, which is an implementation of the IMalloc interface. Whenever ownership of an allocated chunk of memory is passed through a COM interface or between a client and the COM library, you must use this allocator to allocate the memory. Allocation internal to an object can use any allocation scheme desired, but the COM memory allocator is a handy, efficient, and thread-safe allocator.


Allocation Rules for Non-by-value Parameters

Each parameter and the return value of a function can be classified into one of three groups: an in parameter, an out parameter (which includes return values), or an in-out parameter. In each class of parameter, the responsibility for allocating and freeing non-by-value parameters is the following:

•	in parameter must be allocated and freed by the caller.

•	out parameter must be allocated by the one called; freed by the caller.

•	in-out parameter is initially allocated by the caller, then freed and re-allocated by the one called if necessary. As is true for out parameters, the caller is responsible for freeing the final returned value.

In the latter two cases, one piece of code allocates the memory and a different piece of code frees it. COM, again, requires the use of the COM allocator to ensure that the two pieces of code are using the same allocation methods.

Another area that needs special attention is the treatment of out and in-out parameters in failure conditions. If a function returns a status code which is a failure code, then, in general, the caller has no way to clean up the out or in-out parameters that are returned. This leads to a few additional rules:

out parameter

In error returns, the out parameters must always be reliably set to a value that will be cleaned up without any action by the caller. Further, it is the case that all out pointer parameters must explicitly be set to NULL. These are usually passed in a pointer-to-pointer parameter, but can also be passed as a member of a structure that the caller allocates and the called code fills. The most straightforward way to ensure this is (in part) to set these values to NULL on function entry. This rule is strong to promote more robust application interoperability.

in-out parameter

In error returns, all in-out parameters must either be left alone by the one called (and thus remaining at the value to which it was initialized by the caller; if the caller didn't initialize it, then it is an out-parameter, not an in-out-parameter) or be explicitly set as in the out-parameter error return case.

Remember that these memory management conventions for COM applications apply only across public interfaces and APIs — there is no requirement at all that memory allocation strictly internal to a COM application need be done using these mechanisms.


Debugging Memory Allocations

OLE provides an interface for developers to use to debug their memory allocations: the IMallocSpy interface. For each method in IMalloc, there are two methods in IMallocSpy, a "pre" method and a "post" method. Once a developer implements it and publishes it to the system, the system calls the IMallocSpy "pre" method just before the corresponding IMalloc method, effectively allowing the debug code to "spy" on the allocation operation, and calling the "post" method to release the spy.

For example, when OLE detects that the next call is a call to IMalloc::Alloc, it would call IMallocSpy::PreAlloc, executing whatever debug operations the developer wants during the Alloc execution, and then, when the Alloc call returns, call IMallocSpy::PostAlloc to release the spy and return control to the code.


Transparent Inter-object Communication

COM is designed to allow clients to communicate transparently with objects, regardless of where those objects are running — the same process, the same machine, or a different machine. This provides a single programming model for all types of objects, both object clients and object servers.

From a client's point of view, all objects are accessed through interface pointers. A pointer must be in-process. In fact, any call to an interface function always reaches some piece of in-process code first. If the object is in-process, the call reaches it directly, with no intervening system-infrastructure code. If the object is out-of-process, the call first reaches what is called a "proxy" object provided either by COM itself or by the object (if the implementor wishes). The proxy packages the interface pointer and generates the appropriate remote procedure call (or other communication mechanism in the case of custom generated proxies) to the other process or the other machine where the object implementation is located. This process of packaging pointers for transmission across process boundaries is called marshaling.

From a server's point of view, all calls to an object's interface functions are made through a pointer to that interface. Again, a pointer only has context in a single process, and so the caller must always be some piece of in-process code. If the object is in-process, the caller is the client itself. Otherwise, the caller is a "stub" object provided either by COM or by the object itself. The stub receives the remote procedure call (or other communication mechanism in the case of custom generated proxies) from the "proxy" in the client process, unmarshals the parameters, and calls the appropriate interface on the server object. From the points of view of both clients and servers, they always communicate directly with some other in-process code.

OLE provides an implementation of marshaling, referred to as standard marshaling. This implementation works very well for most objects, and greatly reduces programming requirements, making the marshaling process effectively transparent.

The clear separation of interface from implementation of OLE's process transparency can get, however, in the way for some situations when performance is of critical concern. The design of an interface that focuses on its function from the client's point of view can sometimes lead to design decisions that conflict with efficient implementation of that interface across a network. In cases like this, what is needed is not pure process transparency, but "process transparency, unless you need to care." COM provides this capability by allowing an object implementor to support custom marshaling. Standard marshaling is, in fact, an instance of custom marshaling—it is the default implementation used when an object does not require custom marshaling.

You can implement custom marshaling to allow an object to take different actions when used from across a network than it takes under local access — and it is completely transparent to the client. This architecture makes it possible to design client/object interfaces without regard to network performance issues, then, later, to address network performance issues without disrupting the established design.

COM does not specify how components are structured; it specifies how they interact. COM leaves the concern about the internal structure of a component to programming languages and development environments. Conversely, programming environments have no set standards for working with objects outside of the immediate application. C++, for example, works extremely well to manipulate objects inside an application, but has no support for working with objects outside the application. Generally, all other programming languages are the same in this regard. Therefore COM, through language-independent interfaces, picks up where programming languages leave off to provide the network-wide interoperability.

The double indirection of the vtbl structure means that the pointers in the table of function pointers do not need to point directly to the real implementation in the real object. This is the heart of process transparency.

For in-process servers, where the object is loaded directly into the client process, the function pointers in the table point directly to the actual implementation. In this case, a function call from the client to an interface method directly transfers execution control to the method. This cannot, however, work for local, let alone remote, objects because pointers to memory cannot be shared between processes. Nevertheless, the client must be able to call interface methods as if it were calling the actual implementation. Thus, the client uniformly transfers control to a method in some object by making the call.

A client always calls interface methods in some in-process object. If the actual object is local or remote, the call is made to a proxy object which then makes a remote procedure call to the actual object.

So what method is actually executed? The answer is that whenever there is a call to an out-of-process interface, each interface method is implemented by a proxy object. The proxy object is always an in-process object that acts on behalf of the object being called. This proxy object knows that the actual object is running in a local or remote server.

The proxy object packages up the function parameters in some data packets and generates an RPC call to the local or remote object. That packet is picked up by a stub object in the server's process on the local or a remote machine, which unpacks the parameters and makes the call to the real implementation of the method. When that function returns, the stub packages up any out-parameters and the return value, sends it back to the proxy, which unpacks them and returns them to the original client.

Thus, client and server always talk to each other as if everything was in-process. All calls from the client and all calls to the server are, at some point, in-process. But because the vtbl structure allows some agent, like COM, to intercept all function calls and all returns from functions, that agent can redirect those calls to an RPC call as necessary. Although in-process calls are, naturally, faster than out-of-process calls, the process differences are completely transparent to the client and server.


Concurrency and Synchronization Issues

Concurrency deals with things that can occur at the same time in the system. Whenever there is concurrency, synchronization is an issue. In OLE, there are two primary topics that raise issues in these categories: threading and calls that are not synchronous.


Processes and Threads

COM now permits you to create processes that contain more than one thread of execution, rather than the previous single-thread-per-process model, using a threading model called the apartment model. This multithreading model offers a message-based paradigm for dealing with multiple objects running concurrently. It allows you to write more efficient code by allowing a thread that is waiting for some time-consuming operation to allow another thread to be executed.

A thread of execution is the serial execution of code within a process. When there is only a single thread per process, each process is, effectively, a thread. Processes communicate through messages, using RPC to pass information between processes.

It is important to clarify what a COM object really is. Internal to any object server, a COM object is simply a pointer to data whose first piece of data is a pointer to a table of functions. Inside an object server there is really no difference between an this interface pointer and an instance of a C++ class derived from a pure-virtual base. Therefore, for a particular object server, there are really no OLE objects distinguishable from any other programming construct, as opposed to a window, which has operating-system-enforced behavior and existence. COM objects really only exist as the result of communication between two components.

A more exact way of stating this is that a COM object only appears as a result of a call to CoCreateInstance, being returned from another OLE interface, or as a programming construct being passed as an in-parameter to an interface. Thus, unless an application uses an OLE mechanism to create an instance of the interface, the only threading behavior is the Microsoft® Win32® base threading behavior. This provides a certain threading model with multiple threads of execution within a completely shared memory space, synchronized by various system implementations of semaphore primitives.

The big issue in programming with a multithreaded model is to ensure the code is thread-safe, so messages intended for a particular thread go only to that thread, and access to threads is protected somehow. The issues become more complicated when, for example, a single-threaded application loads a DLL server that creates multiple threads, and begins accessing an object of the single-threaded server from multiple threads at the same time. The apartment model addresses these issues.

The term apartment is used to indicate a logical grouping of related objects that all execute on the same thread, so must have synchronous execution. In addition, under the apartment model, while there can be multiple objects on a thread, an object cannot reside on more than one thread. This model means that calls to objects in other threads must be made on the thread that owns the object, in the same way that calls to objects in other processes must be made within the context of the owning process.

The inter-process and inter-thread models are similar. When it is necessary to pass an interface pointer to an object in another apartment (on another thread) within the same process, you use the same marshaling model that objects in different processes use to pass pointers across process boundaries. By getting a pointer to the standard marshaling object, you can marshal interface pointers across thread boundaries (between apartments) in the same way you do between processes.

Apartment threading rules are simple, but you must follow them carefully:

•	Every object should live on only one thread (within a single apartment).

•	You must call OleInitialize or CoInitialize to initialize each thread.

•	All pointers to objects must be marshaled between apartments (ensuring that all calls to an object are made on its thread).

•	Each apartment with objects in it must have a message queue to handle calls from other processes and apartments within the same process.

•	Apartment-aware in-process objects must be registered as such in the system registry.

•	Apartment-aware objects must write DLL entry points carefully.

While multiple objects can live on a single thread, no object can live on more than one thread. In addition, it is necessary to call OleInitialize or CoInitialize on each thread, because each thread requires the services of the OLE library

To facilitate marshaling interface pointers between apartments, OLE provides two helper functions. CoMarshalInterThreadInterfaceInStream, which marshals an interface into a stream object that is returned to the caller, and CoGetInterfaceAndReleaseStream, which unmarshals an interface pointer from a stream object and releases it. These functions are simply helpers that use CoMarshalInterface and CoUnmarshalInterface, which require the use of the flag MSHCTX_INPROC flag.

To set up a message queue for a thread, all that is necessary is that the thread's work function must have a GetMessage/DispatchMessage loop. If you use other synchronization primitives to communicate between threads, you can use the Win32 function MsgWaitForMultipleObjects to wait both for messages and for thread synchronization procedures (the Win32 SDK documentation for this function has an example of this sort of combination loop).

For thread-aware DLL-based or in-process objects, you need to set the threading model in the registry. The default model when you do not specify a threading model is single-thread-per-process. To specify a model, you add the ThreadingModel subkey to the InprocServer32 key in the registration database.

To specify the apartment model, set ThreadingModel=Apartment. This permits in-process objects that can be created in multiple threads of a client application to interoperate correctly with older in-process objects that are not aware of multithreading. In-process objects not marked in this way are always created in the first initialized apartment (called the main apartment) in the process and other apartments automatically get proxied pointers to them.

You can also set ThreadingModel=Both. This subkey allows you to design a DLL that is thread-safe, but can run in both an apartment model server, and, when free-threading is supported in future releases of COM, a free-threading server.

DLLs that support instantiation of a class object must implement and export the functions DllGetClassObject and DllCanUnloadNow. When another object wants an instance of the class the DLL supports, a call to CoGetClassObject (either directly or through a call to CoCreateInstance) calls DllGetClassObject to get a pointer to its class object when the object is implemented in a DLL. As its name implies, DllCanUnloadNow is called to determine whether the DLL that implements it is in use, so the caller can safely unload it if it is not.

An apartment-aware object that calls CoCreateInstance on an apartment-aware object will call DllGetClassObject from its thread. DllGetClassObject should therefore be able to give away multiple class objects or a single thread-safe object (essentially just using InterlockedIncrement/InterlockedDecrement on their internal reference count). Calls to CoFreeUnusedLibraries from any thread always route through the main apartment's thread to call DllCanUnloadNow.

OLE also provides another helper function, CoCreateFreeThreadedMarshaler, which provides a pointer to an aggregatable object that implements code. This code allows direct access to an object's VTBL from multiple threads within the same process, but uses standard marshaling if a reference to the object is sent to another process.


Call Synchronization

OLE applications must be able to deal correctly with user input while processing one or more calls from OLE or the operating system. OLE calls between processes fall into three categories:

•	Synchronous calls

•	Asynchronous notifications

•	Input-synchronized calls

Most of the communication that takes place within OLE is synchronous. When making synchronous calls, the caller waits for the reply before continuing and can receive incoming messages while waiting. OLE enters a modal loop to wait for the reply, receiving and dispatching other messages in a controlled manner.

When sending asynchronous notifications, the caller does not wait for the reply. OLE uses PostMessage or high-level events to send asynchronous notifications, depending on the platform. OLE defines five asynchronous methods:

•	IAdviseSink::OnDataChange

•	IAdviseSink::OnViewChange

•	IAdviseSink::OnRename

•	IAdviseSink::OnSave

•	IAdviseSink::OnClose

While OLE is processing an asynchronous call, synchronous calls cannot be made. For example, a container application's implementation of IAdviseSink::OnDataChange cannot contain a call to IPersistStorage::Save.

When making input-synchronized calls, the object called must complete the call before yielding control. This ensures that focus management works correctly and that data entered by the user is processed appropriately. These calls are made by OLE through the Windows SendMessage function, without entering a modal loop. While processing an input-synchronized call, the object called must not call any function or method (including synchronous methods) that might yield control.

The following methods are input synchronized:

•	IOleWindow::GetWindow

•	IOleInPlaceActiveObject::OnFrameWindowActivate

•	IOleInPlaceActiveObject::OnDocWindowActivate

•	IOleInPlaceActiveObject::ResizeBorder

•	IOleInPlaceUIWindow::GetBorder

•	IOleInPlaceUIWindow::RequestBorderSpace

•	IOleInPlaceUIWindow::SetBorderSpace

•	IOleInPlaceFrame::SetMenu

•	IOleInPlaceFrame::SetStatusText

•	IOleInPlaceObject::SetObjectRects

To minimize problems that can arise from asynchronous message processing, the majority of OLE method calls are synchronous. With synchronous communication, there is no need for special code to dispatch and handle incoming messages. When an application makes a synchronous method call, OLE enters a modal wait loop that handles the required replies and dispatches incoming messages to applications capable of processing them.

OLE manages method calls by assigning an identifier called a logical thread ID. A new one is assigned when a user selects a menu command or when the application initiates a new OLE operation. Subsequent calls that relate to the initial OLE call are assigned the same logical thread ID as the initial call.


Monikers

A moniker in COM is not only, as the name implies, a way to identify an object. A moniker is also implemented as an object. This object provides services allowing a component to obtain a pointer to the object identified by the moniker. This process is referred to as binding.

Monikers are objects that implement the IMoniker interface, and are generally implemented in DLLs as component objects. There are two ways of viewing the use of monikers: as a moniker client, a component that uses a moniker to get a pointer to another object, and as a moniker provider, a component that supplies monikers identifying its objects to moniker clients.

OLE uses monikers, for example, to identify, connect to, and run OLE Compound Document link objects. In this case, the link source acts as the moniker provider, and the container holding the link object acts as the moniker client.


Moniker Clients

Moniker clients must start by getting a moniker. There are several ways for a moniker client to get a moniker. For example, in OLE Compound Documents, when the end-user creates a linked item (either using Insert Object dialog, the clipboard, or drag-and drop), a moniker is embedded as part of the linked item. In that case, the programmer has minimal contact with monikers. Programmatically, if you have an interface pointer to an object that implements the IMoniker interface, you can use that to get a moniker, and there are methods on other interfaces that are defined to return monikers.

There are different kinds of monikers, which are used to identify different kinds of objects, but to a moniker client, all monikers look the same. A moniker client simply calls IMoniker::BindToObject on a moniker and gets an interface pointer to the object that the moniker identifies. No matter whether the moniker identifies an object as large as an entire spreadsheet or as small as a single cell within a spreadsheet, calling IMoniker::BindToObject will return a pointer to that object. If the object is already running, IMoniker::BindToObject will find it in memory. If the object is stored passively on disk, IMoniker::BindToObject will locate a server for that object, run the server, and have the server bring the object into the running state. All the details of the binding process are hidden from the moniker client. Thus, for a moniker client, using the moniker is very simple.


Moniker Providers

In general, a component should be a moniker provider when it allows access to one of its objects, while still controlling the object's storage. If a component is going to hand out monikers that identify its objects, it must be capable of performing the following tasks:

•	On request, create a moniker that identifies an object.

•	Enable the moniker to be bound when a client calls IMoniker::BindToObject on it.

A moniker provider must create a moniker of an appropriate moniker class to identify an object. The moniker class refers to a specific implementation of the IMoniker interface that defines the type of moniker created. While you can create a new moniker class through an implementation of the IMoniker interface, it is frequently unnecessary because OLE provides five different moniker classes, each with its own CLSID:

•	File moniker

•	Composite Moniker

•	Item Moniker

•	Anti-moniker

•	Pointer moniker

The file, composite, and item monikers are the most frequently used monikers, as they can be used to make nearly any object in any location. Anti- and pointer monikers are primarily used inside OLE, but have some application in implementing custom monikers.


File Monikers

File monikers are the simplest moniker class. File monikers can be used to identify any object that is stored in its own file. A file moniker acts as a wrapper for the path name the native file system assigns to the file. Calling IMoniker::BindToObject for this moniker would cause this object to be activated and then would return an interface pointer to the object. The source of the object named by the moniker must provide an implementation of the IPersistFile interface to support binding a file moniker. File monikers can represent either a complete or a relative path.

For example, the file moniker for a spreadsheet object stored as the file C:\WORK\MYSHEET.XLS would contain information equivalent to that path name. The moniker would not necessarily consist of the same string, however. The string is just its display name, a representation of the moniker's contents that is meaningful to an end user. The display name, which is available through the IMoniker::GetDisplayName method, is used only when displaying a moniker to an end-user. This method gets the display name for any of the moniker classes. Internally, the moniker may store the same information in a format that is more efficient for performing moniker operations, but isn't meaningful to users. Then, when this same object is bound through a call to the BindToObject method. the object would be activated, probably by loading the file into the spreadsheet.

OLE offers moniker providers the helper API CreateFileMoniker that creates a file moniker object and returns its pointer to the provider.


Composite Monikers

One of the most useful features of monikers is that you can concatenate or compose monikers together. A composite moniker is a moniker that is a composition of other monikers, and can determine the relation between the parts. This lets you assemble the complete path to an object given two or more monikers that are the equivalent of partial paths. You can compose monikers of the same class (like two file monikers) or of different classes (like a file moniker and an item moniker). If you were to write your own moniker class, you could also compose your monikers with file or item monikers. The basic advantage of a composite is that it gives you one piece of code to implement every possible moniker that is a combination of simpler monikers.  That reduces tremendously the need for specific custom moniker classes.

Because monikers of different classes can be composed with one another, monikers provide the ability to join multiple namespaces. The file system defines a common namespace for objects stored as files because all applications understand a file-system path name. Similarly, a container object also defines a private namespace for the objects that it contains, because no container understands the names generated by another container. Monikers allow these name spaces to be joined because file monikers and item monikers can be composed. A moniker client can search the namespace for all objects using a single mechanism. The client simply calls IMoniker::BindToObject on the moniker, and the moniker code handles the rest. A call to IMoniker::GetDisplayName on a composite creates a name using the concatenation of all the individual monikers' display names.

Furthermore, because you can write your own moniker class, moniker composition allows you to add customized extensions to the namespace for objects.

Sometimes two monikers of specific classes can be combined in a special way. For example, a file moniker representing an incomplete path and another file moniker representing a relative path can be combined to form a single file moniker representing the complete path. For example, the file monikers c:\work\art could be composed with the relative file moniker ..\backup\myfile.doc to equal c:\work\backup\myfile.doc. This is an example of "non-generic" composition.

"Generic" composition, on the other hand, permits the connection of any two monikers, no matter what their classes. For example, you could compose an item moniker onto a file moniker, though not, of course, the other way around.

Because a non-generic composition depends on the class of the monikers involved, its details are defined by a the implementation of a particular moniker class. You can define new types of non-generic compositions if you write a new moniker class. By contrast, generic compositions are defined by OLE. Monikers created as a result of generic composition are called generic composite monikers.

These three classes -- file monikers, item monikers, and generic composite monikers -- all work together, and they are the most commonly used classes of monikers.

Moniker clients should call IMoniker::ComposeWith to create a composite on moniker with another. The moniker it is called on internally decides whether it can do a generic or non-generic composition. If the moniker implementation determines that a generic composition is usable, OLE provides the CreateGenericComposite API function to facilitate this.


Item Monikers

Another OLE-implemented moniker class is the item moniker, which can be used to identify an object contained in another object. One type of contained object is an OLE object embedded in a compound document. A compound document could identify the embedded objects it contains by assigning each one an arbitrary name, such as "embedobj1," "embedobj2," and so forth. Another type of contained object is a user selection in a document, such as a range of cells in a spreadsheet or a range of characters in a text document. An object that consists of a selection is called a pseudo-object because it isn't treated as a distinct object until a user marks the selection. A spreadsheet might identify a cell range using a name such as "1A:7F", while a word processing document might identify a range of characters using the name of a bookmark.

An item moniker is useful primarily when concatenated -- or "composed" -- with another moniker, one that identifies the container. An item moniker is usually created, then composed onto (for example) a file moniker to create the equivalent of a complete path to the object. For example, you can compose the file moniker "C:\work\report.doc" (which identifies the container object) with the item moniker "embedobj1" (which identifies an object within the container) to form the moniker "C:\work\report.doc\embedobj1," which uniquely identifies a particular object within a particular file. You can also concatenate additional item monikers to identify deeply nested objects. For example, if "embedobj1" is the name of a spreadsheet object, then to identify a certain range of cells in that spreadsheet object you could append another item moniker to create a moniker that would be the equivalent of "C:\work\report.doc\embedobj1\1A:7F."

When combined with a file moniker, an item moniker forms a complete path. Item monikers thus extend the notion of path names beyond the file system, defining path names to identify individual objects, not just files.

There is a significant difference between an item moniker and a file moniker. The path contained in a file moniker is meaningful to anyone who understands the file system, while the partial path contained in an item moniker is meaningful only to a particular container. Everyone knows what "c:\work\report.doc" refers to, but only one particular container object knows what "1A:7F" refers to. One container cannot interpret an item moniker created by another application; the only container that knows which object is referred to by an item moniker is the container that assigned the item moniker to the object in the first place. For this reason, the source of the object named by the combination of a file and item moniker must not only implement IPersistFile to facilitate binding the file moniker, but also IOleItemContainer to facilitate resolving the name of the item moniker into the appropriate object, in the context of a file

The advantage of monikers is that someone using a moniker to locate an object doesn't need to understand the name contained within the item moniker, as long as the item moniker is part of a composite. Generally, it would not make sense for an item moniker to exist on its own. Instead, you would compose an item moniker onto a file moniker. You would then call IMoniker::BindToObject on the composite, which binds the individual monikers within it, interpreting the names.

To create an item moniker object and return its pointer to the moniker provider, OLE provides the helper API CreateItemMoniker. This function creates an item moniker object and returns its pointer to the provider.


Anti-monikers

OLE provides an implementation of a special type of moniker called an anti-moniker. You use this moniker in the creation of new moniker classes. You use it as the inverse of the moniker that it is composed onto, effectively canceling that moniker, in much the same way that the ".." operator moves up a directory level in a file system command.

It is necessary to have an anti-moniker available, because once a composite moniker is created, it is not possible to delete parts of the moniker if, for example, an object moves. Instead, you use an anti-moniker to remove one or more entries from a composite moniker.

Anti-monikers are a moniker class explicitly intended for use as an inverse. COM defines an API function named CreateAntiMoniker, which returns an anti-moniker. You generally use this function to implement the IMoniker::Inverse method.

An anti-moniker is only an inverse for those types of monikers that are implemented to treat anti-monikers as an inverse. For example, if you want to remove the last piece of a composite moniker, you should not create an anti-moniker and compose it to the end of the composite. You cannot be sure that the last piece of the composite considers an anti-moniker to be its inverse. Instead, you should call IMoniker::Enum on the composite moniker, specifying FALSE as the first parameter. This creates an enumerator that returns the component monikers in reverse order. Use the enumerator to retrieve the last piece of the composite, and call IMoniker::Inverse on that moniker. The moniker returned by IMoniker::Inverse is what you need to remove the last piece of the composite.


Pointer Monikers

A pointer moniker identifies an object that can exist only in the active or running state. This differs from other classes of monikers, which identify objects that can exist either in the passive or active state.

Suppose, for example, an application has an object that has no persistent representation. Normally, if a client of your application needs access to that object, you could simply pass the client a pointer to the object. However, suppose your client is expecting a moniker. The object cannot be identified with a file moniker, since it isn't stored in a file, nor with an item moniker, since it isn't contained in another object.

Instead, your application can create a pointer moniker, which is a moniker that simply contains a pointer internally, and pass that to the client. The client can treat this moniker like any other. However, when the client calls IMoniker::BindToObject on the pointer moniker, the moniker code does not check the Running Object Table (ROT) or load anything from storage. Instead, the moniker code simply calls IUnknown::QueryInterface on the pointer stored inside the moniker.

Pointer monikers allow objects that exist only in the active or running state to participate in moniker operations and be used by moniker clients. One important difference between pointer monikers and other classes of monikers is that pointer monikers cannot be saved to persistent storage. If you do, calling the IMoniker::Save method returns an error. This means that pointer monikers are useful only in specialized situations. You can use the CreatePointerMoniker API function if you need to use a pointer moniker.


Error Handling

At the source code level, all error values consist of three parts, separated by underscores. The first part is the prefix that identifies the facility associated with the error, the second part is E for error, and the third part is a string that describes the actual condition. For example, STG_E_MEDIUMFULL is returned when there is no space left on a hard disk. The STG prefix indicates the storage facility, the E indicates that the status code represents an error, and the MEDIUMFULL provides specific information about the error. Many of the values that you might want to return from an interface method or function are defined in winerror.h.

Success, warning, and error values are returned using a 32-bit number known as a result handle, or HRESULT. HRESULTs are really not handles to anything, but merely 32-bit values with several fields encoded in the value. A zero result indicates success and a non-zero result indicates failure.

HRESULTs work differently depending on the platform you are using. On 16-bit platforms, an HRESULT is generated from a 32-bit value known as a status code, or SCODE. On 32-bit platforms, an HRESULT is the same as an SCODE; they are synonymous. In fact, the SCODE is no longer used. 32-bit OLE uses only HRESULTs.


Structure of OLE Error Codes

SCODES on 16-bit platforms are divided into four fields: a severity code, a context field, a facility field, and an error code. The format of an SCODE on a 16-bit platform is shown below; the numbers indicate bit positions:

HRESULTs on 32-bit platforms have the following format:

The severity code in the 16-bit SCODE and the high order bit in the HRESULT indicates whether the return value represents success or failure. If set to zero, SEVERITY_SUCCESS, the value indicates success. If set to 1, SEVERITY_ERROR, it indicates failure.

In the 16-bit version of the SCODE, the context field is reserved; this field does not exist in the 32-bit version. The R, C, N, and r bits are reserved in both.

The facility field in both versions indicates the area of responsibility for the error. There are currently five facilities: FACILITY_NULL, FACILITY_ITF, FACILITY_DISPATCH, FACILITY_RPC, and FACILITY_STORAGE. If new facilities are necessary, Microsoft allocates them because they need to be unique. Most SCODEs and HRESULTs set the facility field to FACILITY_ITF, indicating an interface method error. The following table describes the various facility fields:

Facility	Description
FACILITY_NULL	For broadly applicable common status codes such as S_OK. This facility code has a value of zero.
FACILITY_ITF	For most status codes returned from interface methods, value is defined by the interface. That is, two SCODEs or HRESULTs with exactly the same 32-bit value returned from two different interfaces might have different meanings. This facility has a value of 4.
FACILITY_DISPATCH	For late binding IDispatch interface errors. This facility has a value of 2.
FACILITY_RPC	For status codes returned from remote procedure calls. This facility has a value of 1.
FACILITY_STORAGE	For status codes returned from IStorage or IStream method calls relating to structured storage. Status codes whose code (lower 16 bits) value is in the range of DOS error codes (that is, less than 256) have the same meaning as the corresponding DOS error. This facility has a value of 3.
FACILITY_WINDOWS	Used for additional error codes from Microsoft-defined interfaces.
FACILITY_WIN32	Used to provide a means of handling error codes from functions in the Win32 API as an HRESULT. Error codes in 16-bit OLE that duplicated Win32 error codes have also been changed to FACILITY_WIN32.
The code field is a unique number that is assigned to represent the error or warning.

By convention, HRESULTs generally have names in the following form:

<Facility>_<Severity>_<Reason>

where <Facility> is either the facility name or some other distinguishing identifier, <Severity> is a single letter, S or E, that indicates the severity of the error, and <Reason> is an identifier that describes the meaning of the code. For example, the status code STG_E_FILENOTFOUND indicates a storage-related error has occurred; specifically, a requested file does not exist. Status codes from FACILITY_NULL omit the <Facility>_ prefix.

Error codes are defined within the context of an interface implementation. Once defined, success codes cannot be changed or new success codes added. However, new failure codes can be written since they generally only provide hints at what might have gone wrong. Microsoft reserves the right to define new failure codes (but not success codes) for the interfaces described in this book in FACILITY_ITF or in new facilities.


Codes in FACILITY_ITF

These HRESULTSs with facilities such as FACILITY_NULL and FACILITY_RPC have universal meaning because they are defined at a single source: Microsoft. However, HRESULTs in FACILITY_ITF are determined by the interface method (or function) from which they are returned. That is, the same 32-bit value in FACILITY_ITF returned from two different interface methods might have different meanings.

The reason HRESULTs in FACILITY_ITF can have different meanings in different interfaces is that HRESULTs are kept to an efficient data type size of 32 bits. Unfortunately 32 bits is not large enough for the development of an allocation system for error codes that avoid conflict between codes allocated by different non-communicating programmers at different times in different places (unlike the handling of interface IDs and CLSIDs). As a result, the 32-bit HRESULT is structured in a way that Microsoft can define some universally-defined error codes, while allowing other programmers to define new error codes without fear of conflict. The status code convention is as follows:

1.	Status codes in facilities other than FACILITY_ITF can only be defined by Microsoft.

2.	Status codes in facility FACILITY_ITF are defined solely by the developer of the interface or API that returns the status code. To avoid conflicting error codes, whoever defines the interface is responsible for coordinating and publishing the FACILITY_ITF status codes associated with that interface.

All the OLE-defined FACILITY_ITF codes have a code value in the range of 0x0000 − 0x01FF. While it is legal to use any codes in FACILITY_ITF, it is recommended that only code values in the range of 0x0200 — 0xFFFF be used. This recommendation is made as a means of reducing confusion with any OLE-defined errors.

It is also recommended that developers define new functions and interfaces to return error codes as defined by OLE and in facilities other than FACILITY_ITF. In particular, interfaces that have any chance of being remoted using RPC in the future should define the FACILITY_RPC codes as legal. E_UNEXPECTED is a specific error code that most developers will want to make universally legal.


Macros for Error Handling
Using Macros for Error Handling

OLE defines a number of macros that make it easier to work with SCODEs on 16-bit platforms and HRESULTs on both platforms. Some of the macros and functions below provide conversion between the two data types and are quite useful in code that runs only on 16-bit platforms, code that runs on both 16-bit and 32-bit platforms, and 16-bit code that is being ported to a 32-bit platform. These same macros are meaningless in 32-bit environments and are available in order to provide compatibility and make porting easier. Newly written code should use the HRESULT macros and functions.

Error handling macros are listed below. Refer to The OLE Programmer's Reference for a complete description of each.

Macro	Description
GetScode	(Obsolete) Returns an SCODE given an HRESULT.
ResultFromScode	(Obsolete) Returns an HRESULT given an SCODE.
PropagateResult	(Obsolete) Generates an HRESULT to return to a function in cases where an error is being returned from an internally called function.
MAKE_HRESULT	Returns an HRESULT given an SCODE that represents an error.
MAKE_SCODE	Returns an SCODE given an HRESULT.
HRESULT_CODE	Extracts the error code part of the HRESULT.
HRESULT_FACILITY	Extracts the facility from the HRESULT.
HRESULT_SEVERITY	Extracts the severity bit from the SEVERITY.
SCODE_CODE	Extracts the error code part of the SCODE.
SCODE_FACILITY	Extracts the facility from the SCODE.
SCODE_SEVERITY	Extracts the severity field from the SCODE.
SUCCEEDED	Tests the severity of the SCODE or HRESULT - returns TRUE if the severity is zero and FALSE if it is one.
FAILED	Tests the severity of the SCODE or HRESULT - returns TRUE if the severity is one and FALSE if it is zero.
IS_ERROR	Provides a generic test for errors on any status value.
FACILITY_NT_BIT	Defines bits so macros are guaranteed to work.
RESULT_FROM_WIN32	Maps a Win32 error value into an HRESULT. This assumes that Win32 errors fall in the range -32k to 32k.
HRESULT_FORM_NT	Maps an NT status value into an HRESULT.
Note  Calling MAKE_HRESULT for S_OK verification carries a performance penalty. You should not routinely use MAKE_HRESULT for successful results.


Error Handling Strategies

Because interface methods are virtual, it is not possible to know, as a caller, the full set of values that may be returned from any one call. One implementation of a method may return five values; another may return eight. The OLE Programmer's Reference lists common values that may be returned for each method; these are the values that you must check for and handle in your code because they have special meanings. Other values may be returned, but since they are not meaningful, you do not need to write special code to handle them. A simple check for zero or not zero is adequate.


HRESULTs

The values of some HRESULTs have been changed in 32-bit OLE to eliminate all duplication and overlapping with Win32 error codes. Those that duplicate Win32 error codes have been changed to FACILITY_WIN32 and those that overlap remain in FACILITY_NULL. Following is a list of their 32-bit values:

HRESULT	Value
E_UNEXPECTED	0x8000FFFF
E_NOTIMPL	0x80004001
E_OUTOFMEMORY	0x8007000E
E_INVALIDARG	0x80070057
E_NOINTERFACE	0x80004002
E_POINTER	0x80004003
E_HANDLE	0x80070006
E_ABORT	0x80004004
E_FAIL	0x80004005
E_ACCESSDENIED	0x80070005


Handling Error Information

Keep in mind that it is legal to return a status code only from the implementation of an interface method sanctioned as legally returnable. Failure to observe this rule invites the possibility of conflict between returned error code values and those sanctioned by the application. In particular, pay attention to this potential problem when propagating error codes from internally-Qcalled functions.

Applications that call interfaces should treat any unknown returned error code (as opposed to a success code) as synonymous with E_UNEXPECTED. This practice of handling unknown error codes is required by clients of the OLE-defined interfaces and APIs. Because typical programming practice is to handle a few specific error codes in detail and treat the rest generically, this requirement of handling unexpected or unknown error codes is easily met.

The following code sample shows the recommended way of handling unknown errors:

HRESULT hrErr;

hrErr = xxMethod();

switch (GetScode(hrErr))  {

case NOERROR:

  //success

  break;

case x1:

  .

  .

  break;

case x2:

  .

  .

  break;

case E_UNEXPECTED:

default:

  //general failure

  break;

}

The following error check is often used with those routines that don't return anything special (other than S_OK or some unexpected error):

if (xxMethod() == NOERROR)

//success

else

//general failure;


Structured Storage

Traditional file systems face challenges when they try to efficiently store multiple kinds of objects in one document. OLE provides a solution:  a file system within a file. OLE structured storage defines how to treat a single file entity as a structured collection of two types of objects — storages and streams — that act like directories and files. This scheme is called structured storage. The purpose of structured storage is to reduce the performance penalties and overhead associated with storing separate objects in a flat file


The Evolution of File Systems

Years ago, in the days before disk operating systems, each computer was built to run a single, proprietary application, which had complete and exclusive control of the entire machine. The application would write its persistent data directly to a disk, or drum, by sending commands directly to the disk controller. The application was responsible for managing the absolute locations of data on the disk, making sure that it was not overwriting data that was already there, but since the application was the only one running on the machine, this task was not too difficult.

The advent of computer systems that could run more than one application required some sort of mechanism to make sure that applications did not write over each other's data. Application developers addressed this problem by adopting a single standard for marking which disk sectors were in use and which were free. In time, these standards coalesced to become a disk operating system, which provided various services to the applications, including a file system for managing persistent storage. With the advent of a file system, applications no longer had to deal directly with the physical storage medium. Instead, they simply told the file system to write blocks of data to the disk and let the file system worry about how to do it. In addition, the file system allowed applications to create data hierarchies through the abstraction known as a directory. A directory could contain not only files but other directories. which in turn could contain their own files and directories, and so on.

The file system provided a single level of indirection between applications and the disk, and the result was that every application saw a file as a single contiguous stream of bytes on the disk even though the file system was actually storing the file in discontiguous sectors. The indirection freed the applications from having to care about the absolute position of data on a storage device.

Today, virtually all system APIs for file input and output provide applications with some way to write information into a flat file that applications see as a single stream of bytes that can grow as large as necessary until the disk is full. For a long time these APIs have been sufficient for applications to store their persistent information. Applications have made significant innovations in how they deal with a single stream of information to provide features like incremental "fast" saves.

In a world of component objects, however, storing data in a single flat file is no longer efficient. Just as file systems arose out of the need for multiple applications to share the same storage medium, so now, component objects require a system that allows them to share storage within the conceptual framework of a single file. Even though it is possible to store the separate objects using conventional flat file storage, should one of the objects increase in size, or should you simple add another object, it becomes necessary to load the entire file into memory, insert the new object, and then save the whole file. Such a process can be extremely time-consuming.

The solution provided by OLE is to implement a second level of indirection: a file system within a file. Instead of requiring that a large contiguous sequence of bytes on the disk be manipulated through a single file handle with a single seek pointer, OLE structured storage defines how to treat a single file system entity as a structured collection of two types of objects — storages and streams — that act like directories and files.


Storages and Streams

OLE provides a set of services collectively called structured storage. The purpose of these services is to reduce the performance penalties and overhead associated with storing separate objects in a flat file. Instead, OLE stores the separate objects in a single, structured file consisting of two main elements: storage objects and stream objects. Together, they function like a file system within a file.

A storage object is analogous to a file system directory. Just as a directory can contain other directories and files, a storage object can contain other storage objects and stream objects. Also like a directory, a storage object tracks the locations and sizes of the storage objects and stream objects nested beneath it.

A stream object is analogous to the traditional notion of a file. Like a file, a stream contains data stored as a consecutive sequence of bytes.

An OLE compound file consists of a root storage object containing at least one stream object representing its native data along with one or more storage objects corresponding to its linked and embedded objects. The root storage object maps to a filename in whatever file system it happens to reside in. Each of the objects inside the document also is represented by a storage object containing one or more stream objects, and perhaps also containing one or more storage objects. In this way, a document can consist of an unlimited number of nested objects.

Structured storage solves the performance problem because whenever a new object is added to a compound file, or an existing object increases in size, the file does not have to be totally rewritten to storage. Instead, the new data is written to the next available location in permanent storage, and the storage object updates the table of pointers it maintains to track the locations of its storage objects and stream objects. At the same time, structured storage enables end users to interact and manage a compound file as if it were a single file rather than a nested hierarchy of separate objects.

Structured storage also provides additional benefits:

•	Incremental access. If a user needs access to an object within a compound file, the user can load and save only that object, rather than the entire file.

•	Multiple use. More than one end user or application can concurrently read and write information in the same compound file.

•	Transaction processing. Users can read or write to OLE compound files in transacted mode, where changes made to the file are buffered and can subsequently either be committed to the file or reversed.

•	Low memory saves. Structured storage provides facilities for saving files in low memory situations.


Compound Files

Although you can implement your own structured storage objects and interfaces, OLE provides a standard implementation called Compound Files. Using Compound Files saves you the work of coding your own implementation of structured storage and confers several additional benefits derived from adhering to a defined standard. These benefits include the following:

•	File-system and platform independence. Since OLE's Compound Files implementation runs on top of existing flat file systems, compound files stored in FAT, NTFS, or the Macintosh file systems can be opened by applications using any one of the others.

•	Browsability. Since the separate objects in a compound file are saved in a standard format and can be accessed using standard OLE interfaces and APIs, any browser utility using these interfaces and APIs can list the objects in the file, even though the data within a given object may be in a proprietary format.

•	Access to certain internal data. Since the Compound Files implementation provides standard ways of writing certain types of data — summary information, for example — applications can read this data using OLE interfaces and APIs.


Structured Storage Elements

Structured storage provides the equivalent of a complete file system for storing objects through the following elements:

•	The IStorage, IStream, ILockBytes, and IRootStorage interfaces, along with a set of related interfaces — IPersistStorage , IPersist, IPersistFile, and IPersistStream.

•	Helper APIs that facilitate your implementation of structured storage, as well as a second set of APIs for compound files, OLE's implementation of the structured storage interfaces. OLE also provides a set of supporting structures and enumeration values used to organize parameters for interface methods and APIs.

•	A set of access modes for regulating access to compound files.


Interfaces

Structured storage services are organized into three categories of interfaces. Each set represents a successive level of indirection, or abstraction, between a compound file, the objects it contains, and the physical media on which these individual components are stored.

The first category of interfaces consists of IStorage, IStream, and IRootStorage. The first two interfaces define how objects are stored within a compound file. These interfaces provide methods for opening storage elements, committing and reverting changes, copying and moving elements, and reading and writing streams. These interfaces do not understand the native data formats of the individual objects and therefore have no methods for saving those objects to persistent storage. The IRootStorage interface has a single method for associating a compound document with an underlying file system name. Clients are responsible for implementing these interfaces on behalf of their compound files.

The second category of interfaces consists of the IPersist interfaces, which objects implement to manage their persistent data. These interfaces provide methods to read the data formats of individual objects and therefore know how to store them. Objects are responsible for implementing these interfaces because clients do not know the native data formats of their nested objects. These interfaces, however, have no knowledge of specific physical storage media.

A third category consists of a single interface, ILockBytes, which provides methods for writing files to specific physical media, such as a hard disk or tape drive. OLE provides an ILockBytes interface for the operating system's file system.


API Functions

Some of the API functions for structured storage are helper functions that perform a sequence of calls to other API functions and interface methods. You can use these helper functions as short cuts.

Other API functions provide access to OLE's implementation of structured storage, Compound Files.

Still another set of API functions enable you to convert OLE 1 objects to structured storage. You can use these functions to determine if an object class is from OLE 1 and to convert objects between OLE 1 and current OLE storage formats.

Finally, there are API functions for converting and emulating other objects. These functions provide services for one server application to work with data from another application. The data can be converted to the native format of the server application by reading the data from its original format but writing it in the native format of the object application. Or the data can remain in its original format while the server application both reads and writes the data in its original format.


Access Modes

In a world where multiple processes and users can access an object simultaneously, mechanisms for controlling that access are essential. OLE provides these mechanisms by defining access modes for both storage and stream objects. The access mode specified for a parent storage object is inherited by its children, though you can place additional restrictions on the child storage or stream. A nested storage or stream object can be opened in the same mode or in a more restricted mode than that of its parent, but it cannot be opened in a less restricted mode than that of its parent.

You specify access modes by using the values listed in the STGM enumeration. These values serve as flags to be passed as arguments to methods in the IStorage interface and associated API functions. Typically, several flags are combined in the parameter grfMode, using a Boolean OR operation.

The flags fall into six groups: transaction flags, storage creation flags, temporary creation flag, priority flag, access permission flags, and shared access flags. Only one flag from each group can be specified at a time.

Transaction Flags

An object can be opened in either direct or transacted mode. When an object is opened in direct mode, changes are made immediately and permanently. When an object is opened in transacted mode, changes are buffered so they can be explicitly committed or reverted once editing is complete. Committed changes are saved to the object while reverted changes are discarded. Direct mode is the default access mode.

Transacted mode is not required on a parent storage object in order to use it on a nested element. A transaction for a nested element, however, is nested within the transaction for its parent storage object. Therefore, changes made to a child object cannot be committed until those made to the parent are committed, and both are not committed until the root storage object (the top-level parent) is actually written to disk. In other words, the changes move outward: inner objects publish changes to the transactions of their immediate containers.

Storage Creation Flags

Storage creation flags specify what OLE should do if an existing storage, stream, or lockbytes object has the same name as a new storage or stream object that you are creating. The default is to return an error message and not create the new object. You can use only one of these flags in a given creation call.

Temporary Creation Flag

The temporary creation flag indicates that the underlying file is to be automatically destroyed when the root storage object is released. This capability is most useful for creating temporary files.

Priority Flag

The priority flag opens a storage object in priority mode. When it opens an object, an application usually works from a snapshot copy because other applications may also be using the object at the same time. When opening a storage object in priority mode, however, the application has exclusive rights to commit changes to the object.

Priority mode enables an application to read some streams from storage before opening the object in a mode that would require the system to make a snapshot copy to be made. Since the application has exclusive access, it doesn't have to make a snapshot copy of the object. When the application subsequently opens the object in a mode where a snapshot copy is required, the application can exclude from the snapshot the streams it has already read, thereby reducing the overhead of opening the object.

Since other applications cannot commit changes to an object while it is open in priority mode, applications should keep it in that mode for as short a time as possible.

Access Permission Flags

Access permission flags specify the type of access a client application has to an open object: read, write, or read/write. Read permission enables an application to read the contents of a stream but not to write changes to the stream. Write permission enables an application to call a function that commits changes to an object's storage but not to read the contents of the stream. Read/write permission enables an application to either read the object's streams or write to the object's storage.

Shared Access Flags

The shared access flags specify the degree of access other applications can have to an object that your application is opening. You can deny read access, deny write access, or deny all access. You can also specify explicitly that no type of access be denied.


Storage Object Naming Conventions

Storage and stream objects are named according to a set of conventions.

The name of a root storage object is the actual name of the file in the underlying file system. It obeys the conventions and restrictions the file system imposes. Filename strings passed to storage-related methods and functions are passed on, uninterpreted and unchanged, to the file system.

The name of a nested element contained within a storage object is managed by the implementation of the particular storage object. All implementations of storage objects must support nested element names 32 characters in length (including the NULL terminator), although some implementations might support longer names. Whether the storage object does any case conversion is implementation-defined. As a result, applications that define element names must choose names that are acceptable in either situation. The OLE implementation of compound files supports names up to 32 characters in length, and does not perform any case conversion.


Data Transfer

The Component Object Model (COM) provides a standard mechanism for transferring data between applications. This mechanism is the data object, which is simply any COM object that implements the IDataObject interface. Some data objects, such as a piece of text copied to the clipboard, have IDataObject as their sole interface. Others, such as compound document objects, expose several interfaces, of which IDataObject is simply one. Data objects are fundamental to the working of compound documents, although they also have widespread application outside that OLE technology.

By exchanging pointers to a data object, providers and consumers of data can manage data transfers in a uniform manner, regardless of the format of the data, the type of medium used to transfer the data, or the target device on which it is to be rendered. You can include support in your application for basic clipboard transfers, drag and drop transfers, and OLE compound document transfers with a single implementation of IDataObject. Having done that, the amount of code required to accommodate the special semantics of each protocol is minimal.


Data Transfer Interfaces

The IDataObject interface provides consumers of data with methods for getting and setting an object's data, determining which formats the object supports, and registering for and receiving notifications when data in the object changes. When obtaining data, a caller can specify the format in which it wants to render the data. The source of the data, however, determines the storage medium, which it returns in an out parameter provided by the caller.

By itself, IDataObject supplies all the tools you need to implement Microsoft® Windows® clipboard transfers or compound document transfers in your applications. If you also want to support drag and drop transfers, you need to implement the IDropSource and IDropTarget interfacesalong with IDataObject.

The IDataObject interface combined with OLE clipboard APIs provide all the capabilities of the Microsoft® Win32® clipboard APIs. Using both the platform's clipboard APIs and OLE's is usually redundant and unnecessary. Suppliers of data that support either drag and drop transfers or OLE compound documents must implement the IDataObject interface. If your application supports only clipboard transfers now, but you intend to add drag and drop or compound documents in later releases, you may want to implement IDataObject and the OLE clipboard APIs now in order to minimize the amount of time spent recoding and debugging later. You may also want to implement IDataObject in order to utilize transfer media other than global memory.

The following table summarizes which ones to use, depending on what types of data transfer you want to support:

If You Want to Support	You Must Use
Compound documents	IDataObject
Drag and drop transfers	IDataObject, IDropSource, IDropTarget, DoDragDrop (or the equivalent)
Windows clipboard transfers using global memory exclusively	Windows clipboard APIs
Windows clipboard transfers using exchange mediums other than global memory.	IDataObject
Clipboard transfers now but drag and drop or compound documents later	IDataObject and the interfaces and function listed above for "Drag and drop transfers"
When a user initiates a data transfer operation, the source application creates an instance of IDataObject and through it makes the data available in one or more formats. In a clipboard transfer, the application calls the OleSetClipboard function to pass a data-object pointer to OLE. (OleSetClipboard also offers standard clipboard data formats for both OLE version 1 and non-OLE applications.) In a drag and drop transfer, the application calls the DoDragDrop function instead.

On the receiving side of the transfer, the destination receives the IDataObject pointer either as an argument to an invocation of IDropTarget::Drop or by calling the OleGetClipboard function, depending on whether the transfer is by means of drag and drop or the clipboard. Having obtained this pointer, the destination calls IDataObject::EnumFormatEtc to learn what formats are available for retrieval and on what types of media they can be obtained. Armed with this information, the receiving application requests the data with a call to IDataObject::GetData.


Data Formats and Transfer Media

Most platforms, including Windows, define a standard protocol for transferring data between applications, based on a set of functions called the clipboard. Applications using these functions can share data even if their native data formats are wildly different. Generally, these clipboards have two significant shortcomings that COM has overcome.

First, data descriptions use only a format identifier, such as the single 16-bit clipboard format identifier on Windows, which means the clipboard can only describe the structure of its data, that is, the ordering of the bits. It can report, "I have a bitmap" or "I have some text," but it cannot specify the target devices for which the data is composed, which views or aspects of itself the data can provide, or which storage media are best suited for its transfer. For example, it cannot report, "I have a string of text that is stored in global memory and formatted for presentation either on screen or on a printer" or "I have a thumbnail sketch bitmap rendered for a 100 dpi dot-matrix printer and stored as a disk file."

Second, all data transfers using the clipboard generally occur through global memory. Using global memory is reasonably efficient for small amounts of data but horribly inefficient for large amounts, such as a 20 MB multimedia object. Global memory is slow for a large data object, whose size requires considerable swapping to virtual memory on disk. In cases where the data being exchanged is going to reside mostly on disk anyway, forcing it through this virtual-memory bottleneck is highly inefficient. A better way would skip global memory entirely and simply transfer the data directly to disk.

To alleviate these problems, COM introduces two new data structures: FORMATETC and STGMEDIUM.


The FORMATETC Structure

The FORMATETC structure is a generalized clipboard format, enhanced to encompass a target device, an aspect or view of the data, and a storage medium. A data consumer, such as an OLE container application, passes the FORMATETC structure as an argument in calls to IDataObject to indicate the type of data it wants from a data source, such as a compound document object. The source uses the FORMATETC structure to describe what formats it can provide. FORMATETC can describe virtually any data, including other objects such as monikers. A container can ask one of its embedded objects to list its data formats by calling IDataObject::EnumFormatetc, which returns an enumerator object that implements the IEnumFormatEtc interface. Instead of replying merely that it has "text and a bitmap," the object can provide a detailed description of the data, including the device (normally screen or printer) for which it is rendered, the aspect to be presented to the user (full contents, thumbnail, icon, or formatted for printing), and the storage medium containing the data (global memory, disk file, storage object, or stream). This ability to tightly describe data will, in time, result in higher quality printer and screen output as well as more efficiency in data browsing, where a thumbnail sketch is much faster to retrieve and display than a fully detailed rendering.

The following table lists fields of the FORMATETC data structure and the information they specify:

Field	Specifies
cfFormat	The format in which the data is to be rendered, which can be a standard clipboard format, a proprietary format, or an OLE format. For more information on OLE formats, see Chapter 5, "Compound Documents."
ptd	A DVTARGETDEVICE structure, which contains enough information about a Windows target device, such as a screen or printer, so that a handle to its device context (hDC) can be created using the Windows CreateDC function.
dwAspect	The aspect or view of the data to be rendered; can be the full contents, a thumbnail sketch, an icon, or formatted for printing.
lindex	The part of the aspect that is of interest; for the present, the value must be -1, indicating that the entire view is of interest.
tymed	The data's storage medium, which can be global memory, disk file, or an instance of one of COM's structured-storage interfaces.


The STGMEDIUM Structure

Just as the FORMATETC structure is an enhancement of the Windows clipboard format identifier, so the STGMEDIUM structure is an improvement of the global memory handle used to transfer the data. The STGMEDIUM structure includes a flag, tymed, which indicates the medium to be used, and a union comprising pointers and a handle for getting whichever medium is specified in tymed.

The STGMEDIUM structure enables both data sources and consumers to choose the most efficient exchange medium on a per-rendering basis. If the data is so big that it should be kept on disk, the data source can indicate a disk-based medium in its preferred format, only using global memory as a backup if that's the only medium the consumer understands. Being able to use the best medium for exchanges as the default improves overall performance of data exchange between applications. For example, if some of the data to be transferred is already on disk, the source application can move or copy it to a new destination, either in the same application or in some other, without having first to load the data into global memory. At the receiving end, the consumer of the data does not have to write it back to disk.


Drag and Drop

"Drag and drop" refers to data transfers in which a mouse or other pointing device is used to specify both the data source and its destination. In a typical drag and drop operation, a user selects the object to be transferred by moving the mouse pointer to it and holding down either the left button or some other button designated for this purpose. While continuing to hold down the button, the user initiates the transfer by dragging the object to its destination, which can be any OLE container. Drag and drop provides exactly the same functionality as the OLE Clipboard copy and paste but adds visual feedback and eliminates the need for menus. In fact, if an application supports Clipboard copy and paste, little extra is needed to support drag and drop.

During an OLE drag and drop operation, the following three separate pieces of code are used:

Drag-and-drop code source	Implementation and use
IDropSource interface	Implemented by the object containing the dragged data, referred to as the drag source.
IDropTarget interface	Implemented by the object that is intended to accept the drop, referred to as the drop target.
DoDragDrop function	Implemented by OLE and used to initiate a drag and drop operation. Once the operation is in progress, it facilitates communication between the drag source and the drop target.
The IDropSource and IDropTarget interfaces can be implemented in either a container or in an object application. The role of drag source or drop target is not limited to any one type of OLE application.

The OLE function DoDragDrop implements a loop that tracks mouse and keyboard movement until such time as the drag is canceled or a drop occurs. DoDragDrop is the key function in the drag and drop process, facilitating communication between the drag source and drop target.

During a drag and drop operation, three types of feedback can be displayed to the user:

Type of feedback	Description
Source feedback	Provided by the drag source, the source feedback indicates the data is being dragged and does not change during the course of the drag. Typically, the data is highlighted to signal it has been selected.
Pointer feedback	Provided by the drag source, the pointer feedback indicates what happens if the mouse is released at any given moment. Pointer feedback changes continually as the user moves the mouse and/or presses a modifier key. For example, if the pointer is moved into a window that cannot accept a drop, the pointer changes to the "not allowed" symbol.
Target feedback	Provided by the drop target, target feedback indicates where the drop is to occur.
Although the Windows 3.1 File Manager does not use OLE to implement drag and drop transfers, it is nevertheless an example of an application that acts as both a drag source and drop target and that provides all three types of feedback. When a user selects a file to copy, File Manager supplies source feedback by indicating the selection. As the selection is dragged and modifier keys are pressed, the mouse pointer changes. For example, if the user presses the CTRL key, a plus sign is added, indicating that the drop would result in a copy rather than moving the original. When the file is dragged over an area that is not a drop target, the pointer changes appropriately. Target feedback, a line drawn around a file or directory, is provided when the pointer is over an area that is a drop target.


Drag Source Responsibilities

The drag source is responsible for the following tasks:

•	Providing a data-transfer object for the drop target that exposes the IDataObject and IDropSource interfaces.

•	Generating pointer and source feedback.

•	Determining when the drag operation has been canceled or a drop operation has occurred.

•	Performing any action on the original data caused by the drop operation, such as deleting the data or creating a link to it.

The main task is creating a data-transfer object that exposes the IDataObject and IDropSource interfaces. The drag source might or might not include a copy of the selected data. Including it is not mandatory, but doing so safeguards against inadvertent changes and allows the Clipboard operations code to be identical to the drag and drop code.

While a drag operation is in progress, the drag source is responsible for setting the mouse pointer and, if appropriate, for providing additional source feedback to the user. The drag source cannot provide any feedback that tracks the mouse position other than by actually setting the real pointer (see the Windows SetCursor function). This rule must be enforced to avoid conflicts with the feedback provided by the drop target. (A drag source can also be a drop target. When dropping on itself, the source/target can, of course, provide target feedback to track the mouse position. In this case, however, it is the drop target tracking the mouse, not the source.) Based on the feedback offered by the drop target, the source sets an appropriate pointer.


Data Notification

Objects that consume data from an external source sometimes need to be informed when data in that source changes. For example, a stock ticker tape viewer that relies on data in some spreadsheet needs to be notified when that data changes so it can update its display. Similarly, a compound document needs information about data changes in its embedded objects so that it can update its data caches. In cases such as this, where dynamic updating of data is desirable, sources of data require some mechanism of notifying data consumers of changes as they occur without obligating the consumers to drop everything in order to update their data. Ideally, having been notified that a change has occurred in the data source, a consuming object can ask for an updated copy at its leisure.

COM's mechanism for handling asynchronous notifications of this type is an object called an advise sink, which is simply any COM object that implements an interface called IAdviseSink.  Consumers of data implement the IAdviseSink. They register to receive notifications by handing a pointer to the data object of interest.

The IAdviseSink interfaces exposes the following methods for receiving asynchronous notifications:

Method	Notifies the Advise Sink that
OnDataChange	Calling object's data has changed.
OnViewChange	Instructions for drawing the calling object have changed.
OnRename	Calling object's moniker has changed.
OnSave	Calling object has been saved to persistent storage.
OnClose	Calling object has been closed.
As the table indicates, the IAdviseSink interface exposes methods for notifying the advise sink of events other than changes in the calling object's data. The calling object can also notify the sink when the way in which it draws itself changes, or it is renamed, saved, or closed. These other notifications are used mainly or entirely in the context of compound documents, although the notification mechanism is identical. For more information on compound-document notifications, see "Compound Documents."

In order to take advantage of the advise sink, a data source must implement IDataObject::DAdvise, IDataObject::DUnadvise, and IDataObject::EnumDAdvise. A data consumer calls the DAdvise mothod to notify a data object that it wishes to be notified when the object's data changes. The consuming object calls the DUnadvise method to tear down this connection. Any interested party can call the EnumAdvise method to learn the number of objects having an advisory connection with a data object.

When data changes at the source, the data object calls IAdviseSink::OnDataChange on all data consumers that have registered to receive notifications. To keep track of advisory connections and manage the dispatch of notifications, data sources rely on an object called a data advise holder. You can create your own data advise holder by implementing the IDataAdviseHolder interface. Or, you can let COM do it for you by calling the helper function CreateDataAdviseHolder.


Compound Documents

OLE compound documents enable users working within a single application to manipulate data written in various formats and derived from multiple sources. For example, a user might insert into a word processing document a graph created in a second application and a sound object created in a third application. Activating the graph causes the second application to load its user interface, or at least that part containing tools necessary to edit the object. Activating the sound object causes the third application to play it. In both cases, a user is able to manipulate data from external sources from within the context of a single document.

OLE compound document technology rests on a foundation consisting of COM, structured storage, and .uniform data transfer. As summarized below, each of these core technologies plays a critical role in OLE compound documents:

COM

A compound document object is essentially a COM object that can be embedded in, or linked to, an existing document. As a COM object, a compound document object exposes the IUnknown interface, through which clients can obtain pointers to its other interfaces, including several, such as IOleObject, IOleLink, and IViewObject2, that provide special features unique to compound document objects.

Structured Storage

A compound document object must implement the IPersistStorage or, optionally, IPersistStream interfaces to manage its own storage. A container used to create compound documents must supply the IStorage interface, through which objects store and retrieve data. Containers almost always provide instances of IStorage obtained from OLE's Compound Files implementation. Containers must also use an object's IPersistStorage and/or IPersistStream interfaces.

Uniform Data Transfer

Applications that support compound documents must implement IDataObject because embedded objects and linked objects begin as data that has been transferred using special OLE clipboard formats, rather than standard Microsoft® Windows® clipboard formats. In other words, formatting data as an embedded or linked object is simply one more option provided by OLE's uniform data transfer model.

OLE's compound document technology benefits both software developers and users alike. Instead of feeling obligated to cram every conceivable feature into a single application, software developers are now free, if they like, to develop smaller, more focused applications that rely on other applications to supply additional features. In cases where a software developer decides to provide an application with capabilities beyond its core features, the developer can implement these additional services as separate DLLs, which are loaded into memory only when their services are required. Users benefit from smaller, faster, more capable software that they can mix and match as needed, manipulating all required components from within a single master document.


Containers and Servers

Compound document applications are of two basic types: container applications and server applications. OLE container applications provide users with the ability to create, edit, save, and retrieve compound documents. OLE server applications provide users with the means to create documents and other data representations that can be contained as either links or embeddings in container applications. An OLE application can be a container application, a server application, or both.

OLE server applications also differ in whether they are implemented as in-process servers or local servers. An in-process server is a dynamic link library (DLL) that runs in the container application's process space. You can run an in-process server only from within the container application.

Note  Future releases of OLE will enable linking and embedding across machine boundaries, so that a container application on one computer will be able to use a compound document object provided by a remote server running on another computer. From a container application's point of view, any OLE server application that runs in its own process space, whether on the same computer or a remote machine, is an out-of-process server.


Linking and Embedding

Users can create two types of compound-document objects: linked or embedded. The difference between the two types lies in how and where the object's source data is stored. Where the object resides affects, in turn, the object's portability and methods of activation, how data updates are performed, and the size and structure of its container.


Linked Objects

When a link to an object is inserted in a compound document, the source data, or link source, continues to reside wherever it was initially created, usually in another document. The compound document contains only a reference, or link, to the actual data stored at the link source, along with information about how to present that data to the user. Currently, moving a link source breaks the link unless both source and client maintain their relative positions in the directory tree. Eventually, link tracking by Windows will allow a link source to be moved independently of its client without breaking the link.

Activating a link runs the link source's server application, which the user requires in order to edit or otherwise manipulate the link data. Linking keeps the size of a compound document small. It is also useful when the data source is maintained by someone else and must be shared among many users. If  the person maintaining the link source changes the data, the change is automatically updated in all documents containing a link to that data. In addition to creating simple links, users can nest links and combine linked and embedded objects to create complex documents.


Embedded Objects

An embedded object is physically stored in the compound document, along with all the information needed to manage the object. In other words, the embedded object is actually a part of the compound document in which it resides. This arrangement has a couple of disadvantages. First, a compound document containing embedded objects will be larger than one containing the same objects as links. Second, changes made to the source of an embedded object will not be automatically replicated in the embedded copy, and changes in the source will not be reflected in the source, as they are with a link.

Still, for certain purposes, embedding offers several advantages over links. First, users can transfer compound documents with embedded objects to other computers, or other locations on the same computer, without breaking a link. Second, users can edit embedded objects without changing the content of the original. Sometimes, this separation is precisely what is required. Third, embedded objects can be activated in place, meaning that the user can edit or otherwise manipulate the object without having to work in a separate window from that of the object's container. Instead, when the object is activated, the container application's user interface changes to expose those tools that are necessary to manage or modify the object.


Object Handlers

If an OLE server application is a local server, meaning that it runs in its own process space, communication between container and server must occur across process boundaries. Since this process is expensive, OLE relies on a surrogate object loaded into the container's process space to act on behalf of a local server application. This surrogate object, known as an object handler services container requests that do not require the attention of the server application, such as requests for drawing. When a container requests something that the object handler cannot provide, the handler communicates with the server application using COM's out-of-process communication mechanism.

An object handler is unique to an object class. When you create an instance of a handler for one class, you cannot use it for another. When used for a compound document, the object handler implements the container-side data structures when objects of a particular class are accessed remotely.

OLE provides a default object handler that local server applications can use. For applications that require special behaviors, developers can implement a custom handler that either replaces the default handler or uses it to provide certain default behaviors.

An object handler is a DLL containing several interacting components. These components include remoting pieces to manage communication between the handler and its server application, a cache for storing an object's data, along with information on how that data should be formatted and displayed, and a controlling object that coordinates the activities of the DLL's other components. In addition, if an object is a link, the DLL also includes a linking component, or linked object, which keeps track of the name and location of the link source.

The cache contains data and presentation information sufficient for the handler to display a loaded, but not running, object in its container. OLE provides an implementation of the cache used by OLE's default object handler and the link object. The cache stores data in formats needed by the object handler to satisfy container draw requests. When an object's data changes, the object sends a notification to the cache so that an update can occur. For more information on the cache, see "View Caching" later in this chapter.


The Default Handler and Custom Handlers

The default handler, an implementation provided by OLE, is used by most applications as the handler. An application implements a custom handler when the default handler's capabilities are insufficient. A custom handler can either completely replace the default handler or use parts of the functionality it provides where appropriate. In the latter case, the application handler is implemented as an aggregate object composed of a new control object and the default handler. Combination application/default handlers are also known as in-process handlers. The remoting handler is used for objects that are not assigned a CLSID in the system registry or that have no specified handler. All that is required from a handler for these types of objects is that they pass information across the process boundary.


In-Process Servers

If you implement an OLE server application as an in-process server — a DLL running in the process space of the container application — rather than as a local server — an EXE running in its own process space — communication between container and server is simplified because communication between the two can take the form of normal function calls. Remote procedure calls are not required because the two applications run in the same process space. As you would expect, the objects that manage the marshaling of parameters are also unnecessary , although they may be aggregated within the DLL without interfering with the communication between container and server.

When an OLE server application is implemented as an in-process server, a separate object handler is not required because the server itself lives in the client's process space. The main difference between an in-process server and object handler is that the server is able to manage the object in a running state while the handler cannot. One consequence of this difference is that a server must provide a user interface for manipulating the running object, while a handler delegates this requirement to the object's server. In creating an in-process server, you can aggregate on the OLE default handler, letting it handle basic chores, such as display, storage, and notifications while you implement only those services that the handler either does not provide or does not implement in the way you require


Advantages

The advantages of implementing your application as an in-process server are speed and combining some the advantages of an object handler and a local server. In-process servers are faster than local servers for several reasons. First, because they are smaller and run in the process space of the container application, they load more quickly. Second, they are optimized to perform certain tasks. Third, communication between container and server does not rely on remote procedure calls.


Disadvantages

In-process servers provide the speed and size advantage of an object handler with the editing capability of a local server. So why would you ever choose to implement your OLE application as a local server rather than an in-process server? There are several reasons:

•	Security. Only a local server has its address space isolated from that of the client. An in-process server shares the address space and process context of the client and can therefore be less robust in the face of faults or malicious programming.

•	Granularity. A local server can host multiple instances of its object across many different clients, sharing server state between objects in multiple clients in ways that would be difficult or impossible if implemented as an in-process server, which is simply a DLL loaded into each client.

•	Compatibility. If you choose to implement an in-process server, you relinquish compatibility with OLE 1, which does not support such servers. This will not be a consideration for many developers, but if it is, then it is of critical concern.

•	Inability to support links. An in-process server cannot serve as a link source. Since a DLL cannot run by itself, it cannot create a file object to be linked to.

Despite these disadvantages, an in-process server can be an excellent choice for its speed and size—if it fits all your other requirements.


Linked Objects

Linked objects, like embedded objects, rely on an object handler to communicate with server applications.The linked object itself, however, manages the naming and tracking of link sources.The linked object acts like an in-process server. For example, when activated, a linked object locates and launches the OLE server application that is the link source.

A linked object's handler is made up of two main components: the handler component and the linking component. The handler component contains the controlling and remoting pieces and functions much like a handler for an embedded object. The linking component has its own controller and cache and provides access to the object's structured storage. The linking component's controller supports source naming through the use of monikers, and binding, the process of locating and running the link source. (For more information on monikers and binding, see "The Component Object Model.")

When a user initially creates a linked object or loads an existing one from storage, the container loads an instance of the linking component into memory, along with the object handler. The linking component supplies interfaces — most notably IOleLink — that identify the object as a link and enable it to manage the naming, tracking, and updating of its link source.

By implementing the IOleLink interface, a linked object provides its container with functions that support linking. Only linked objects implement IOleLink, and by querying for this interface a container can determine whether a given object is embedded or linked. The most important function provided by IOleLink enables a container to binding to the source of the linked object, that is, to activate the connection to the document that stores the linked object's native data. IOleLink also defines functions for managing information about the linked object, such as cached presentation data and the location of the link source.

When a compound document containing a linked object is saved, the link's data is saved with the link source, not with the container. Only information about its name and location is saved along with the compound document. This behavior is in contrast to that of an embedded object, whose data is stored along with that of its container.

Container applications can provide information about their embedded objects such that the latter, or portions thereof, can act as link sources. By implementing support for linking to your container's embedded objects, you make nested embeddings possible, relieving the user of having to track down the originals of every embedding object to which a link is desired. For example, if a user wants to embed a Microsoft® Excel worksheet in Microsoft® Word, and the worksheet contains a bitmap created in Paintbrush™, the user can link to a copy of the bitmap contained in the worksheet rather than the original.


Notifications

Notifications are callbacks generated by an object when it detects a change in its name, state, data, or presentation. Containers and other clients require notifications to respond appropriately to these changes. A container registers to receive notifications by setting up an advisory connection to an object of interest. Other interested clients can do the same. The container also creates an advisory sink to receive the notifications. Using the connection established by the container, an object experiencing a change notifies the advisory sink. Upon receiving a notification, the container takes whatever action has been defined for the type of change that has occurred.


Types of Notifications

Notifications fall into three groups: compound document, data, and view. An object sends compound document notifications in response to being renamed, saved, closed or, in the case of a link, having its link source renamed. As you would expect, objects send data notifications in response to changes in their data and send view notifications in response to changes in their presentation. Container applications must register separately for each of these notification types, but all can be handled by a single advisory sink.

All containers, the object handler, and the linked object register for compound document notifications. The typical container also registers for view notifications. Data notifications are usually sent to both the linked object and object handler. A special purpose container, such as one that renders the data itself, might benefit from receiving data notifications instead of view notifications. For example, an embedded chart container with a link to a table can register for data notifications. Because a change to the table affects the chart, the receipt of a data notification would direct the container to get the new tabular data.


How Notifications Work

Notifications originate in the object application and flow to the container by way of the object handler. If the object is a linked object, the linked object intercepts the notifications from the object handler and notifies the container directly.

An object application must manage registration requests, keeping track of where to send which notifications and sending those notifications when appropriate. OLE provides two component objects to simplify this task: the OleAdviseHolder for compound document notifications and the DataAdviseHolder for data notifications.

Object applications determine the conditions that prompt the sending of each specific notification and the frequency with which each notification should be sent. When it is appropriate for multiple notifications to be sent, it does not matter which notification is sent first; they can be sent in any order.

The timing of notifications affects the performance and coordination between an object application and its containers. Whereas notifications sent too frequently slow processing, notifications sent too infrequently result in an out-of-sync container. Notification frequency can be compared with the rate at which an application repaints. Therefore, using similar logic for the timing of notifications (as is used for repainting) is wise.


Compound Document Interfaces

The following tables list the interfaces implemented by OLE containers, OLE servers, and compound document objects. The required interfaces must be implemented on the components for which they are listed. For example, containers must implement the IOleClientSite and IAdviseSink interfaces. All other features are optional. If you want to include a particular feature in your application, however, you must implement the interfaces shown for that feature in the table below. All other interfaces are required only if you are including a particular feature. For example, if you want your application to do message filtering (recommended), you must implement IMessageFilter.

The following table lists required and optional behaviors for OLE containers and which interfaces you must implement for each.

OLE Containers
Behavior	Interfaces
Required Behaviors	IOleClientSite
	IAdviseSink
Message Filtering	IMessageFilter
Linking	none
Linking to Embedded Objects	IOleItemContainer
	IPersistFile
	IClassFactory
In-Place Activation	IOleInPlaceSite
	IOleInPlaceActive-Frame
	IOleInPlaceUIObject
Drag and Drop	IDropSource
	IDropTarget
	IDataObject
The following table lists required and optional behaviors for OLE servers and their compound document objects and which interfaces you must implement for each. The table distinguishes OLE servers and their objects in order to clarify which component implements which interfaces. The table also notes the different requirements of objects provided by out-of-process versus in-process servers.

Feature	OLE Server	Compound Document Object
		Out-of-Process	In-Process
Required Behaviors	IClassFactory	IOleObject	IOleObject
		IDataObject	IDataObject
		IPersistStorage	IPersistStorage
			IViewObject2
			IOleCache2
Message  Filtering	IMessageFilter
Linking	IOleItemContainer		IOleLink
	IPersistFile		IExternalConnection
In-Place- Activation		IOleInPlaceObject	IOleInPlaceObject
		IOleInPlace- ActiveObject	IOleInPlaceActive- Object
Drag and Drop	IDropSource
	IDropTarget
	IDataObject


Object States

A compound object exists in one of three states: passive, loaded, or running. A compound-document object's state describes the relationship between the object in its container and the application responsible for its creation. The following table summarizes these states:

Object State	Description
Passive	The compound-document object exists only in storage, either on disk or in a database. In this state, the object is unavailable for viewing or editing.
Loaded	The object's data structures created by the object handler are in the container's memory. The container has established communication with the object handler and there is cached presentation data available for rendering the object. Calls are processed by the object handler. This state, because of its low overhead, is used when a user is simply viewing or printing an object.
Running	The objects that control remoting have been created and the OLE server application is running. The object's interfaces are accessible, and the container can receive notification of changes. In this state, an end user can edit or otherwise manipulate the object.


Entering the Loaded State

When an object enters the loaded state, the in-memory structures representing the object are created so that operations can be invoked on it. The object's handler or in-process server is loaded. This process, referred to as instantiation, occurs when an object is loaded from persistent storage (a transition from the passive to the loaded state) or when an object is being created for the first time.

Internally, instantiation is a two-phase process. An object of the appropriate class is created, after which a method on that object is called to perform initialization and give access to the object's data. The initialization method is defined in one of the object's supported interfaces. The particular initialization method called depends on the context in which the object is being instantiated and the location of the initialization data.


Entering the Running State

When an embedded object makes the transition to the running state, the object handler must locate and run the server application in order to utilize the services that only the server provides. Embedded objects are placed in the running state either explicitly through a request by the container, such as a need to draw a format not currently cached, or implicitly by OLE in response to invoking some operation, such as when a user of the container double-clicks the object.

When a linked object makes the transition into the running state, the process is known as binding. In the process of binding, the object handler asks its stored moniker to locate the link's data, then runs the server application.

At first glance, binding a linked object appears to be no more complicated than running an embedded object. However, the following points complicate the process:

•	A link can refer to an object, or a portion thereof, that is embedded in another container. This capability implies a potential for nested embeddings. Resolving references to such a hierarchy requires recursively traversing a composite moniker, beginning with the rightmost member.

•	When the link source is running, OLE binds to the running instance of the object rather than running another instance. In the case of nested embedded objects, one of which is the link source, OLE must be able to bind to an already running object at any point.

•	Running an object requires accessing the storage area for the object. When an embedded object is run, OLE receives a pointer to the storage during the load process, which it passes on to the OLE server application. For linked objects, however, there is no standard interface for accessing storage. The OLE server application may use the file system interface or some other mechanism.


Entering the Passive State

Object closure forces an embedded or linked object into the passive state. It is typically initiated from the OLE server application's user interface, such as when the user selects the File Close command. In this case, the OLE server application notifies the container, which releases its reference count on the object. When all references to the object have been released, the object can be freed. When all objects have been freed, the OLE server application can safely terminate.

A container application can also initiate object closure. To close an object, the container releases its reference count after completing an optional save operation. You can design containers to release objects when they are deactivating after an in-place activation session, allowing the user to click outside the object without losing the active editing session.


Implementing In-Place Activation

In-place activation enables a user to interact with an embedded object without leaving the container document. When a user activates the object, a composite menu bar comprising elements from both the container application's and server application's menu bars replaces the container's main menu bar. Commands and features from both applications are thus available to the user, including context sensitive help for the active object. When a user begins working with some non-object portion of the document, the object is deactivated, causing the container document's original menu to replace the composite menu.

This capability originally went by the name of in-place editing. The name was changed because editing is only one way for a user to interact with a running object. Sound clips, for example, can be listened to instead of editing. Video clips can be viewed instead of editing. In-place activation is particularly apt in the case of video clips because it allows them to run in place, without calling up a separate window. This could be critical if the video were to be viewed, say, in conjunction with adjacent text data in the container document.

Implementing in-place activation is strictly optional for both container and server applications. OLE still supports the model in which activating an object causes the server application to open a separate window. Linked objects always open in a separate window to emphasize that they reside in a separate document.

In-place activation begins with the object in response to an IOleObject::DoVerb call from its container. This call usually happens in response to a user double-clicking the object or selecting a command (verb) from the container application's Edit menu.

The in-place window receives keyboard and mouse input while the embedded object is active. When a user selects commands from the composite menu bar, the command and associated menu messages are sent to the container or object application, depending on which owns the particular drop-down menu selected. Input by means of an object's rulers, toolbars, or frame adornments go directly to the embedded object, which owns these windows.

An in-place-activated embedded object remains active until either the container deactivates it in response to user input or the object voluntarily gives up the active state, as a video clip might do, for example. A user can deactivate an object by clicking inside the container document but outside the object's in-place-activation window, or simply by clicking another object. An in-place-activated object remains active, however, if the user clicks the container's title bar, scroll bar or, in particular, menu bar.

You can implement an in-place-activation-object server either as an in-process server (DLL) or a local server (EXE). In both cases, the composite menu bar contains items (typically drop-down menus) from both the server and container processes. In the case of a in-process server, the in-place activation window is simply another child window in the container's window hierarchy, receiving its input through the container application's message pump.

In the case of a local server, the in-place activation window belongs to the embedded object's server application process, but its parent window belongs to the container. Input for the in-place-activation window appears in the server's message queue and is dispatched by the server's message loop. The OLE libraries are responsible for seeing to it that menu commands and messages are dispatched correctly.


Creating Linked and Embedded Objects from Existing Data

A user typically assembles a compound document by using either the clipboard or drag and drop to copy a data object from its server application to the user's container application. With applications that support OLE, the user can initiate the transfer from either the server or the container. For example, the server can copy data to the clipboard in the server application, then switch to the container application and choose Paste Special/Embedded Object or an equivalent menu command to create a new embedded object from the selected data. Or, the user can drag the data from one application to the other. The process is similar for creating a linked object.

Note  An application that functions as both OLE server and container can use a selection of its own data to create an embedded or linked object at a new location within the same document.

Data transfer between OLE server and container applications is built on uniform data transfer, as described in Chapter 4, "Data Transfer." OLE servers and object handlers implement IDataObject in order to make their data available for transfers using either the clipboard or drag and drop. OLE objects support all the usual clipboard formats. In addition, they support six clipboard formats that support the creation of linked and embedded objects from a selected data object.

OLE clipboard formats describe data objects that, upon being dropped or pasted in OLE containers, are to become embedded or linked compound-document objects. The data object presents these formats to container applications in order of their fidelity as descriptions of the data. In other words, the object presents first the format that best represents it, followed by the next best format, and so on. This intentional ordering encourages a container application to use the best possible format.


View Caching

A container application must be able to obtain a presentation of an object for the purpose of displaying or printing it for users when the document is open but the object's server application is not running or is not installed on the user's machine. To assume, however, that the servers for all the objects that might conceivably be found in a document are installed on every user's machine and can always run on demand is unrealistic. The default object handler, which is available at all times, solves this dilemma by caching object presentations in the document's storage and manipulating these presentations on any platform regardless of the availablility of the object server on any particular installation of the container.

Containers can maintain drawing presentations for one or more specific target devices in addition to the one required to maintain the object on screen. Moreover, if you port the object from one platform to another, OLE automatically converts the object's data formats to ones supported on the new platform. For example, if you move an object from Windows to the Macintosh, OLE will convert its metafile presentations to PICT formats.

In order to present an accurate representation of an embedded object to the user, the object's container application initiates a dialog with the object handler, requesting data and drawing instructions. To be able to fulfill the container's requests, the handler must implement the IDataObject, IViewObject2, and IOleCache interfaces.

IDataObject enables an OLE container application to get data from and send data to its embedded or linked objects. When data changes in an object, this interface provides a way for the object to make its new data available to its container and provides the container with a way to update the data in its copy of the object. (For a discussion of data transfer in general, see Chapter 4, "Data Transfer.")

The IViewObject2 interface is very much like the IDataObject interface except that it asks an object to draw itself on a device context, such as a screen, printer, or metafile, rather than move or copy its data to memory or some other transfer medium. The purpose of the interface is to enable an OLE container to obtain alternative pictorial representations of its embedded objects, whose data it already has, thereby avoiding the overhead of having to transfer entirely new instances of the same data objects simply to obtain new drawing instructions. Instead, the IViewObject2 interface enables the container to ask an object to provide a pictorial representation of itself by drawing on a device context specified by the container.

When calling the IViewObject2 interface, a container application can also specify that the object draw itself on a target device different than the one on which it will actually be rendered. This enables the container, as needed, to generate different renderings from a single object. For example, the caller could ask the object to compose itself for a printer even though the resulting drawing will be rendered on screen. The result, of course, would be a print-preview of the object.

The IViewObject2 interface also provides methods that enable containers to register for view-change notifications. As with data and OLE advisories, a view advisory connection enables a container to update its renderings of an object at its own convenience rather than in response to a call from the object. For example, if a new version of an object's server application were to offer additional views of the same data, the object's default handler would call each container's implementation of IAdviseSink::OnViewChange to let them know that the new presentations were available. The container would retrieve this information from the advise sink only when needed.

Because Windows device contexts have meaning only within a single process,  you cannot pass IViewObject2 pointers across process boundaries. As a result, OLE local and remote servers have no need whatsoever to implement the interface, which wouldn't work properly even if they did. Only object handlers and in-process servers implement the IViewObject2 interface. OLE provides a default implementation, which you can use in your own OLE in-process servers and object handlers simply by aggregating the OLE default handler. Or you can write your own implementation of IViewObject.

An object implements the IOleCache interface in order to let the handler know what capabilities it should cache. The object handler also owns the cache and ensures it is kept up to date. As the embedded object enters the running state, the handler sets up appropriate advisory connections on the server object, with itself acting as the sink. The IDataObject and IViewObject2 interface implementations operate out of data cached on the client side. The handler's implementation of IViewObject2 is responsible for determining what data formats to cache in order to satisfy client draw requests. The handler's implementation of IDataObject is responsible for getting data in various formats, etc., between memory and the underlying IStorage instance of the embedded object. Custom handlers can use these implementations by aggregating on the default handler.

Note  The IViewObject2 interface is a simple functional extension of IViewObject and should be implemented instead of the latter interface, which is now obsolete. In addition to providing the IViewObject methods, the IViewObject2 interface provides a single additional member, GetExtent, which enables a container application to get the size of an object's presentation from the cache without first having to move the object into the running state with a call to IOleObject::GetExtent.


Registering Object Applications

To become functional, object applications must register in the Microsoft® Windows® registry. The registry contains information about the application that is needed to support OLE features. This chapter discusses registering object applications and describes OLE registry entries and the subkeys under which they are entered.

Your installation/setup program must add information to the registry, and its associated subkeys, if it is to perform any of the three following types of installations:

•	Installing an object application.

•	Installing a container/object application.

•	Installing a container application that allows linking to its embedded objects.

In all three cases, you must register OLE 2 library (DLL) information as well as application-specific information.

The subkeys are contained in the following registry keys:

HKEY_CLASSES_ROOT\CLSID
HKEY_CLASSES_ROOT\Interface

Note that HKEY_CLASSES_ROOT provides compatibility with Windows 3.1 and Windows 95.

For information about OLE registry functions, refer to the following API functions:

•	CoGetTreatAsClass

•	CoTreatAsClass

•	OleDoAutoConvert

•	OleGetAutoConvert

•	OleSetAutoConvert

•	SetConvertStg

•	GetConvertStg

•	OleRegGetUserType

•	OleRegEnumFormatEtc

•	OleRegGetMiscStatus

•	OleRegEnumVerbs

For information on the registry, the structure of registry entries, and registry functions, refer to the Microsoft Win32 Programmer's Reference.


New Registry Subkeys for 32-bit OLE

This section describes changes made to the Windows NT™ registry to allow it to support 32-bit OLE. The Windows NT registry introduces new subkeys that are specific to 32-bit applications. Otherwise, a 32-bit application is registered in exactly the same manner as a 16-bit application.

The subkeys that are support 16-bit OLE applications are:

LocalServer	Full path to the application '16- or 32-bit'.
InprocServer	Registers a 16-bit in-process server DLL.
InprocHandler	Registers a 16-bit handler DLL.
ProxyStubClsid	Maps an IID to a CLSID in a 16-bit proxy DLL.

For 32-bit OLE applications, the following registry subkeys are added:

LocalServer32	Full path to the application '32-bit'.
InprocServer32	Registers a 32-bit in-process server DLL.
InprocHandler32	Registers a 32-bit handler DLL.
ProxyStubClsid32	Maps an IID to a CLSID in a 32-bit proxy DLL.


Registry Support for 32-bit OLE

The Insertable subkey is a required subkey for 32-bit OLE applications whose objects can be inserted into existing 16-bit applications. Existing 16-bit applications look in the registry for the Insertable key. This key informs the application that the server supports embeddings. If the Insertable key exists, 16-bit applications may also attempt to verify that the server exists on the machine. 16-bit applications typically will retrieve the value of the LocalServer key from the class, and check to see if it is a valid file on the system. Therefore, in order for a 32-bit implementation to be insertable by a 16-bit application, the 32-bit application should register the LocalServer subkey in addition to registering LocalServer32.

For 32-bit local servers, the required entries are InprocHandler32, LocalServer, LocalServer32, and Insertable. For a 32-bit InprocServer, the required entries are InprocHandler32, InprocServer, InprocServer32, and Insertable. Note that the LocalServer entry and the InprocServer entry provide backward compatibility. If they are missing, the class still works, but can't be inserted in 16-bit applications. The InprocServer32 key has a ThreadingModel subkey to support more than one thread per process. See the section "The CLSID Key and Subkeys" later in this appendix for more information.

If a container is searching the registry for a local server, a 32-bit local server has priority over a 16-bit local server. With InprocHandlers and InprocServers, the 16-bit versions have priority with a 16-bit container, and 32-bit versions have priority with a 32-bit container.

Note that ProxyStubClsid32 is required because the IID-to-CLSID mapping may be different for 16- and 32- bit interfaces. The IID-to-CLSID mapping depends on the way the interface proxies are packaged into a set of proxy DLLs.


OLE Registry Entries

This section describes the following OLE registry entries:

•	Programmatic Identifiers

•	The ProgID Key and Subkeys

•	The CLSID Key and Subkeys

•	The Version-Independent ProgID Key and Subkeys

•	The File Extension Key

•	The (Non-Compound) FileType Key and Subkeys

•	The New Interface Key and Subkeys


Programmatic Identifiers

Every OLE 2 object class that is to appear in an Insert Object dialog box (also referred to as an "insertable class") must have a programmatic identifier or ProgID. This string uniquely identifies a given class and is intended to be in a form that can be read by users. Programmatic identifiers are not guaranteed to be universally unique so they can be used only where name collisions are manageable, such as in achieving compatibility with OLE 1. Also, the ProgID is the "class name" used for an OLE 2 class when it is placed in an object application (OLE 1 server).

The ProgID string must:

•	Have no more than 39 characters.

•	Contain no punctuation (including underscores) except one or more periods.

•	Not start with a digit.

•	Be different from the class name of any OLE 1 application, including the OLE 1 version of the same application, if there is one.

The user must never see the ProgID in the user interface. If you need a short displayable string for an object, call the IOleObject::GetUserType method.

Because it is necessary to make a conversion between the ProgId and the CLSID, it is important to note that there are two kinds of ProgIDs. One depends on the version of the object application (the version-dependent ProgId); and one does not (the version-independent ProgId).


Version-dependent Identifiers

The version-dependent ProgID is the string used when OLE 1 is trying to contact OLE 2 using DDE. Version-dependent ProgID-to-CLSID conversions must be specific, well-defined, and one-to-one.


Version-independent Identifiers

The version-independent ProgID, on the other hand, can be used when a container application creates a chart or table with a toolbar button. In this situation, the application can use the version-independent ProgID to determine the latest version of the needed object application.

The version-independent ProgID is stored and maintained solely by application code. When given the version-independent ProgID, the CLSIDFromProgID function returns the CLSID of the current version. The CLSIDFromProgID function works on the version-independent ProgID because the subkey, CLSID, is the same as it is for the version-dependent one.

You can call the IOleObject::GetUserType method or the OleRegGetUserType function to change the identifier to a displayable string.


Converting Identifiers

The CLSIDFromProgID and ProgIdFromCLSID API functions can be called to convert back and forth between the two representations. These functions use information stored in the registry to perform the conversion.

The ProgID-to-CLSID conversion is done using the HKEY_LOCAL_MACHINE\SOFTWARE\Classes\<ProgID>\CLSID key. The reverse translation is done using the HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\<clsid>\ProgID subkey. This means that the ProgID subkey under HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\<clsid> is version-dependent.


The ProgID Key and Subkeys

OLE 2 classes that belong in the Insert Object dialog box each have a ProgID. The value assigned to this key is the name displayed in the dialog box; it should be the same as the "MainUserTypeName" of the class. If this class is insertable in an OLE 2 container, the ProgID key must have an immediate subkey named Insertable, which must have no value assigned to it.

Note  Because OLE 2 provides a built-in OLE 1/OLE 2 compatibility layer, rarely will an OLE 2 class that is insertable in an OLE 2 container not be insertable in an OLE 1 container.


Conventions Used in Examples

In the registry examples in this appendix, boldface indicates a literal standard key or subkey, <italics> indicates an application-supplied string or value, and <boldface-italics> indicates an application-supplied key or subkey. In the first example, "OLE1ClassName," "OLE1UserTypeName," and "CLSID" are all supplied by the application.


Inserting an OLE 2 Object in an OLE 1 Application

If a particular class is insertable in an OLE 1 container, the "ProgID" root key will contain a Protocol\StdFileEditing subkey with appropriate subkeys Verb, Server, and so on, as in OLE 1. The Server that should be registered here is the full path to the executable file of the OLE 2 object application. An OLE 1 container uses the path and executable file names to launch the OLE 2 object application. The initialization of this application, in turn, loads the OLE 2 compatibility layer. This layer handles subsequent interactions with the OLE 1 container (client), turning them into OLE 2−like requests to the OLE 2 application. An OLE 2 object application doesn't have to take any special action beyond setting up these registry entries to make objects insertable into an OLE 1 container.

The ProgID key and its subkeys appear in the registry as shown in the following example, where "<Progid>" is the key, and "Insertable," "Protocol," "StdFileEditing," "Verb," and so on are subkeys.

<ProgId> = <MainUserTypeName>
Insertable	// class is insertable in OLE 2 containers
Protocol
StdFileEditing	// OLE 1 compatibility info; present if, and only if,
// objects of this class are insertable in OLE 1 containers.
Server = <full path to the OLE 2 object application>
Verb
0 = <verb 0>	// Verb entries for the OLE 2
// application must start with zero as the
1 = <verb 1>	// primary verb and run consecutively.
CLSID = <CLSID>	// The corresponding CLSID. Needed by GetClassFile.
Shell	// Windows 3.1 File Manager Info
Print
Open
Command = <appname.exe> %1

To summarize, any root key that has either an Insertable or a Protocol\StdFileEditing subkey is the ProgID (or OLE 1 class name) of a class that should appear in the Insert Object dialog box. The value of that root key is the name displayed in the Insert Object dialog box.

The values of each key in the example below are used for registering the "Ole 2 In-Place Server Outline" sample application. Set these values as required and used by your application.


Long Form String Subkey Entry

The entry to register the string (long form), such as that used in the Insert New dialog box, is as follows.

HKEY_CLASSES_ROOT\OLE2ISvrOtl = Ole 2 In-Place Server Outline

The recommended maximum length for the string is 40 characters.


Information for OLE 1 Applications Subkey Entries

To maintain compatibility with OLE 1, you must include specific OLE 1 information. The "server" key entry should contain a full path to the application. The entries for verbs must start with 0 as the primary verb and be consecutively numbered.

HKEY_CLASSES_ROOT\OLE2ISvrOtl\protocol\StdFileEditing\server =
c:\samp\isvrotl.exe

HKEY_CLASSES_ROOT\OLE2ISvrOtl\protocol\StdFileEditing\verb\0 = &Edit

HKEY_CLASSES_ROOT\OLE2ISvrOtl\protocol\StdFileEditing\verb\1 = &Open


Windows 3.1 Shell Subkey Entries

These entries are for Windows 3.1 shell printing and File Open use. They should contain the path and filename of the object application. The examples below contain simple entries only; more complicated ones could include DDE entries.

HKEY_CLASSES_ROOT\OLE2ISvrOtl\Shell\Print\Command = c:\svr\isvrotl.exe %1

HKEY_CLASSES_ROOT\OLE2ISvrOtl\Shell\Open\Command = c:\svr\isvrotl.exe %1


Insertable Subkey Entry

This entry indicates that the object application should appear in the Insert New dialog box's list box when used by OLE 2 container applications.

HKEY_CLASSES_ROOT\OLE2ISvrOtl\Insertable


Entry Point Subkey

This entry points to the application's OLE 2 information in the registry. To assign a CLSID for your application, run the UUIDGEN.EXE found in the \TOOLS directory of the OLE 2 Toolkit.

HKEY_CLASSES_ROOT\OLE2ISvrOtl\CLSID = {00000402-0000-0000-C000-000000000046}


The CLSID Key and Subkeys

Most of the OLE 2 object application information is stored in subkeys under the CLSID root key. The immediate subkey of the CLSID key is a string version CLSID. Subkeys of this version of the CLSID indicate where the code that services this class is found. For more information about converting the CLSID, see the StringFromCLSID function.

Most of the CLSID information is used by the default OLE 2 handler to return various information about the class when it is in the loaded state. Examples of this include the Verb, the AuxUserType, and the MiscStatus entries. The Insertable subkey appears under both this key and the ProgId key.

CLSID
<CLSID> = <Main User Type Name>
LocalServer = <path to 16- or 32-bit exe>	// local (same machine) server; see "Server ="
// under ProgID key.
LocalServer32 = <path to 32-bit exe>	// local (same machine) server; see "Server ="
// under ProgID key.
InprocServer = <path to dll>	// in process server; relatively rare for insertable classes.
InprocServer32 = <path to 32-bit dll>	// in process server; relatively rare for insertable classes.
InprocHandler = <path to dll>	// in process handler. "OLE2.DLL" for the default OLE 2 handler
InprocHandler32 = <path to 32-bit dll>	// in process handler. "OLE2.DLL" for the default OLE 2
// handler
Verb	// info returned in IOleObject::EnumVerbs().
verb number = <name, menu flags, verb flags>
// several examples follow:
 0 = &Edit, 0, 2	// primary verb; often Edit; on menu; possibly dirties object,
// MF_STRING | MF_UNCHECKED | MF_ENABLED == 0.
 1 = &Play, 0, 3	// other verb; appears on menu; leaves object clean
-3 = Hide, 0, 1	// pseudo verb for hiding window; not on menu, opt.
-2 = Open, 0, 1	// pseudo verb for opening in sep. window; not on menu, opt.
-1 = Show, 0, 1	// pseudo verb for showing in preferred state; not on menu, opt.
AuxUserType	// auxiliary user types (main user type above)
<form of type> = <string>	// See IOleObject::GetUserType(); for example:
2 = <ShortName>	// key 1 should not be used
3 = <Application name>	// Contains the displayable name of the application. Used when
// the actual name of the app is needed (for example in
// the Paste Special dialog's result field) Example: Acme Draw
MiscStatus = <default>	// def status used for all aspects; see IOleObject::GetMiscStatus
<aspect> = <integer>	// exceptions to above;  for example:
4 = 1	// DVASPECT_ICON = OLEMISC_RECOMPOSEONRESIZE
DataFormats
DefaultFile = <format>	// default main file/object format of objects of this class.
GetSet	// list of formats for default impl. of EnumFormatEtc; very similar
// to Request/SetDataFormats in OLE 1 entries
<n> = <format ,aspect, medium, flag>	// in this line,
// n  is a zero-based integer index;
// format is clipboard format;
// aspect is one or more of DVASPECT_*, -1 for "all";
// medium is one or more of TYMED_*;
// flag is one or more of DATADIR_*.
// three examples follow:
0 = 3, -1, 32, 1	// CF_METAFILE, all aspects, TYMED_MFPICT,
// DATADIR_GET
1 = Biff3, 1, 15, 3	// this example shows
// Microsoft Excel's Biff format version 3,
// DVASPECT_CONTENT,
// TYMED_HGLOBAL | TYMED_FILE |
// TYMED_ISTREAM | TYMED_ISTORAGE,
// (DATADIR_SET | DATADIR_GET)
2 = Rich Text Format, 1,1,3
Insertable	// when present, the class appears in the Insert Object dialog.
// (not present for internal classes like the moniker classes)
ProgID = <ProgID>	// the programmatic identifier for this class.
TreatAs = <CLSID>	// see CoGetTreatAs()
AutoTreatAs = <CLSID>	//see CoTreatAsClass
AutoConvertTo = <CLSID>	// see OleGetAutoConvert()
Conversion	// support for Change Type dialog box
Readable
Main = <format,format,format,format, ...>
Readwritable
Main = <format,format,format,format, ...>
DefaultIcon = <path to exe, index>	// parameters passed to ExtractIcon
Interfaces = <IID, IID, ...>	// optional. If this key is present, then its values are the
                                              // totality of the interfaces supported by this class: if the
                                              // IID is not in this list, then the interface is never supported
                                              // by an instance of this class.
VersionIndependentProgID = <VersionIndependentProgID>

Existing 16-bit applications look in the registry for the Insertable keyword. This key informs the application that the server supports embeddings. If the Insertable keyword exists, 16-bit applications may also attempt to verify that the server exists on the machine. 16-bit applications typically will retrieve the value of the LocalServer key from the class, and check to see if it is a valid file on the system. Therefore, to be insertable by 16-bit applications, 32-bit applications should register LocalServer in addition to registering LocalServer32.

The InprocServer32 key has a ThreadingModel subkey to support more than one thread per process. You can set the ThreadingModel key to Apartment to support the apartment model threading or to Both to support both the apartment model and free threading. See the chapter "The Component Object Model" for more information on apartment model threading and free threading.


CLSID (Object Class ID) Subkey Entry

The following information creates a CLSID subkey under the CLSID key. To obtain a CLSID for your application, run the UUIDGEN.EXE found in the \TOOLS directory of the OLE 2 Toolkit.

HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046} = Ole 2 In-Place Server Outline


LocalServer Subkey Entry

This subkey designates the application's location. The LocalServer subkey should contain a full path. The entry can contain command-line arguments. Note that OLE 2 appends the "-Embedding" flag to the string, so the application that uses flags must parse the whole string and check for the -Embedding flag.

HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\LocalServer = c:\samp\isvrotl.exe

To run an OLE object server in a separate memory space (Windows NT 3.5 and above only), change the LocalServer key in the registry for the CLSID to the following:

cmd /c start /separate <path.exe


LocalServer32 Subkey Entry

This subkey designates the location of the 32-bit version of the application. The LocalServer32 subkey should contain a full path. The entry can contain command-line arguments. Note that OLE 2 appends the "-Embedding" flag to the string, so the application that uses flags will need to parse the whole string and check for the -Embedding flag.

HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\LocalServer32 = c:\samp\isvrotl.exe

When OLE starts a 32-bit local server, the server must register a class object within an elapsed time set by the user. By default, the elapsed time value must be at least five minutes, in milliseconds, but cannot exceed the number of milliseconds in 30 days. Applications typically should not set this value which is in the \HKEY_CLASSES_ROOT\Software\Microsoft\OLE2\ServerStartElapsedTime entry.


InprocHandler Subkey Entry

This subkey designates whether the application uses a custom handler. If no custom handler is used, the entry should be set to OLE2.DLL, as shown in the following example.

HKEY_-CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\InprocHandler = ole2.dll


InprocHandler32 Subkey Entry

This subkey designates whether the application uses a custom handler. If no custom handler is used, the entry should be set to OLE32.DLL, as shown in the following example.

HKEY_-CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\InprocHandler32 = ole32.dll


Verb Subkey Entry

The verbs to be registered for the application must be numbered consecutively. The first value after the verb string describes how the verb is appended by AppendMenu function call. See the Win32 SDK documentation for details.

The second value indicates whether the verb will dirty the object. It also indicates whether the verb should appear in the menu (as defined by OLEVERBATTRIB_). For more information, see the IOleObject::EnumVerbs method and the OleRegEnumVerbs function.

Verb 0: "Edit", MF_UNCHECKED | MF_ENABLED, no OLEVERATTRIB flags

HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\Verb\0 = &Edit,0,0

Verb 1: "Open", MF_UNCHECKED | MF_ENABLED, no OLEVERATTRIB flags

HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\Verb\1 = &Open,0,0


AuxUserType Subkey Entry

This key describes the short and actual displayable names of the application. See also the IOleObject::GetUserType method. The short name is used in the menus, including pop-ups, and the recommended maximum length for the string is 15 characters. A short name example follows.

HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\AuxUserType\2 = In-Place Outline

The long displayable name of the application is used in the Results field of the Paste Special dialog box. This string should contain the actual name of the application (such as "Acme Draw 2.0").

HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\AuxUserType\3 = Ole 2 In-Place Server


MiscStatus Subkey Entry

The following is an example of a MiscStatus subkey. Refer to the IOleObject::GetMiscStatus method description for information on the different settings.

HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\MiscStatus = 0


DataFormats Subkey Entry

The DataFormats subkey lists the default and main data formats supported by the application. This entry is used by the IDataObject::GetData, IDataObject::SetData and IDataObject::EnumFormatEtc methods.

The values defined in the following example entry are CF_TEXT, DVASPECT_CONTENT, TYMED_HGLOBAL, and DATADIR_GET | DATADIR_SET.
HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\DataFormats\GetSet\0 = 1,1,1,3

The values defined in the following entry are: CF_METAFILEPICT DVASPECT_CONTENT, TYMED_MFPICT, DATADIR_GET.

HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\DataFormats\GetSet\1 = 3,1,32,1

The values defined in the following entry are: 2 = cfEmbedSource, DVASPECT_CONTENT, TYMED_ISTORAGE, and DATADIR_GET.

HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\DataFormats\GetSet\2 = Embed Source,1,8,1

The values defined in the following entry are: 3 = cfOutline, DVASPECT_CONTENT, TYMED_HGLOBAL, and DATADIR_GET | DATADIR_SET.

HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\DataFormats\GetSet\3 = Outline,1,1,3

The following entry declares that the default File Format supported by this application is CF_OUTLINE.

HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\DataFormats\DefaultFile = Outline


Insertable Subkey

The Insertable entry indicates that this application should appear in the Insert New dialog box's list box when used by OLE 2 container applications. Note that this is a duplicate entry of the one above but is required for future use.

HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\Insertable


ProgID Subkey Entry

Every insertable object class has a "programmatic identifier" or ProgID. For information on the creation and syntax of programmatic identifiers, see "Programmatic Identifiers" earlier in this chapter.

HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\ProgID = OLE2ISvrOtl


Conversion Subkey Entry

Conversion information is used by the Convert dialog box to determine what formats the application can read and write. A comma-delimited file format is indicated by a number if it is one of the Clipboard formats defined in WINDOWS.H. A string indicates the format is not one defined in WINDOWS.H (private). Note that in this case the readable and writeable format is CF_OUTLINE (private).

Shown below is an entry that registers a file format the application can read (convert from).

HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\Conversion\Readable\Main = Outline,1

Shown below is an entry that registers a file format the application can read and write (activate as).

HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\Conversion\Readwritable\Main = Outline,1


DefaultIcon Subkey Entry

The DefaultIcon subkey provides default icon information for iconic presentations of objects. This entry contains the full path to the executable name of the object application and the index of the icon within the executable. Applications can use this information to obtain an icon handle with ExtractIcon.

HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\DefaultIcon = c:\samp\isvrotl.exe,0


The Version-Independent ProgID Key and Subkeys

An application must register a version-independent programmatic identifier in the "Version-Independent ProgID" key, that is, a second ProgID referring to its class, one that would not change from version to version, but would remain constant across all versions. This key provides a constant name, referred to as the MainUserTypeName. It is used with macro languages and refers to the currently installed version of the application's class. The MainUserTypeName must correspond to the name of the latest version of the object application.

<VersionIndependentProgID> = <MainUserTypeName>
CLSID = <CLSID> 	// the class id of the newest installed version of that class
CurVer = <ProgID>	// the ProgID of the newest installed version of that class

In addition to the preceding entry, you should add the following entry to the CLSID root key.

CLSID
<CLSID> = <Main User Type Name>
VersionIndependentProgID = <VersionIndependentProgID>


The File Extension Key

If your OLE 2 application can handle requests from the Windows 3.1 File Manager, create the file extension root key.

<.ext>  = <ProgID>	// used by File Manager and by GetClassFile (and thus File Monikers).


The (Non-Compound) FileType Key and Subkeys

Entries under the FileType key are used by the GetClassFile function to match patterns against various file bytes in a non-compound file. FileType has CLSID subkeys, each of which has a series of subkeys 0, 1, 2, ... These values contain a pattern that, if matched, should yield the indicated CLSID. See also the GetClassFile function.

FileType	// used by GetClassFile()
<CLSID>
<n> = <offset, cb, mask, value>	// Offset and cb are limited to 16 bits. Offset can
//be negative for file end.
// As above, offset and byte count are decimal unless preceded by "0x", in which
// case they are hex. The mask and the pattern are always hex and cannot be
// preceded by "0x". Mask can be omitted, implying a value of all ones.
// An example:
0 = 0, 4, FFFFFFFF, ABCD1234	// This requires that the first 4 bytes be AB CD
// 12 34, in that order,
1 = 0, 4, FFFFFFFF, 9876543	// or requires that they match 9876543.
2 = -4, 4, FEFEFEFE	// The last four bytes in the file must be FEFEFEFE


The Interface Key and Subkeys

If your application adds a new interface, the Interface key must be completed for OLE 2 to register the new interface. There must be one IID subkey for each new interface.

Interface
<IID> = <textual name of interface> 	// for example: "IOleObject"
ProxyStubClsID = <CLSID	>	// Maps an IID to a CLSID in a 16-bit proxy DLL.
//Used internally by OLE 2 for interprocess
// communication.
ProxyStubClsID32 = <CLSID	>	// Maps an IID to a CLSID in a 32-bit proxy DLL.
//Used internally by OLE 2 for interprocess
// communication.
NumMethods = <integer>	// Number of methods in the interface.
BaseInterface = <IID>	// Interface from which this was derived. Absence
// of key means IUnknown. Key present but empty value
// means derived from nothing.

Note that you must use ProxyStubClsid32 because the IID-to-CLSID mapping may be different for 16- and 32-bit interfaces. The IID-to-CLSID mapping depends on the way the interface proxies are packaged into a set of proxy DLLs.


OLE 1 Compatibility Subkeys

To handle two-way compatibility, the OLE 2 compatibility layer creates OLE 2-style entries for OLE 1 classes it discovers and places them under the CLSID key. When installing an OLE 2 object application on a system that contains an OLE 1 version of the same application, it might be necessary to add "AutoConvertTo" or "TreatAs" subkeys to the original OLE 1 application portion of the registry. For more information, see "When the OLE 1 Version is Overwritten."

CLSID
<CLSID> = <OLE1UserTypeName>	// This entry is generated automatically by OLE 2 for an OLE 1 	class.
OLE1Class = <OLE 1 class name>	// This entry is created the first time an object of that class
// is inserted in an OLE 2 container.
ProgId = <OLE 1 class name>	// Allows OLE 2 to convert CLSID back to an OLE 1 class name.


OLE 1 Application Entries

When an OLE 1 class is inserted into an OLE 2 container for the first time, a new subkey, CLSID, is added to the original OLE 1 registration information by the OLE 2 compatibility layer. The value given to this key is a CLSID assigned by OLE 2 to this OLE 1 class as shown in the following portion of the registry.

<OLE1ClassName> = <OLE1UserTypeName>
Protocol
StdFileEditing
Verb
CLSID = <CLSID>


Registering OLE 2 Libraries

The OLE 2 libraries require that many internal interfaces be registered. Thus, if your installation program installs the OLE 2 libraries on a machine that does not already have them, it should register OLE 2-specific information during installation.

If your installation program does not install OLE 2 libraries when it finds more recent libraries on the user's drive, it should not register the OLE 2 interface information.

Note  When checking the version stamp (using VER.DLL) on existing OLE 2 libraries to determine whether or not to replace them on the user's hard drive, do so on a per file basis.


Accommodating OLE 1 Versions of the Object Application

When the OLE 1 version of an object application is superseded by an OLE 2 version and the OLE 2 version is to be installed in the user's system, such as when upgrading, two situations can arise:

•	An OLE 1 version of the application is present on the user's system and the installation process overwrites the OLE 1 executable with the OLE 2 version.

•	An OLE 1 version of the application is present on the user's system and the user chooses not to overwrite it with the OLE 2 version.

Note  Even if the OLE 1 object application is not on the user's system, the install/setup program for the OLE 2 object application should register the application as capable of servicing its OLE 1 objects. To do this, follow the guidelines presented under "When the OLE 1 Version is Overwritten," and add the following entry to the CLSID root key:

<OLE 1 class name>/CLSID = <CLSID of OLE 1 application>


When the OLE 1 Version is Overwritten

When the OLE 1 object application is replaced by the OLE 2 version, do the following. (For the purpose of illustration, the OLE 1 object application is referred to as Ole 1 In-Place Server Outline while the OLE 2 version is Ole 2 In-Place Server Outline, as shown in the dialog box illustrations that follow).

1.	Register Ole 2 In-Place Server Outline.

2.	Modify (with your install/setup program) the original registry entries of Ole 1 In-Place Server Outline by changing the executable path to point to the Ole 2 In-Place Server Outline executable.

For example, the Server subkey for the OLE 1 executable, named svrapp.exe in this example, changes from

OLE1ISvrOtl\Protocol\StdFileEditing\Server = svrapp.exe

to

OLE1ISvrOtl\Protocol\StdFileEditing\Server = isvrotl.exe

where isvrotl.exe is the name of the OLE 2 object application.

Next, proceed to either step 3 or step 4, depending on whether or not you want OLE 1 objects converted automatically to the OLE 2 format.

3.	If Ole 1 In-Place Server Outline objects will be converted automatically to the Ole 2 In-Place Server Outline format when the application is saved, create or modify the following registration database entries:

a.	Modify the original registry entry of Ole 1 In-Place Server Outline by changing the "Value of the ProgID = Main User Type Name" key of the entry to Ole 2 In-Place Server Outline.

For example, where OLE1ISvrOtl is the ProgID of the OLE 1 application,

OLE1ISvrOtl = Ole 1 In-Place Server Outline

becomes

OLE1ISvrOtl = Ole 2 In-Place Server Outline

b.	Modify the original registry entry of Ole 1 In-Place Server Outline by adding a NotInsertable subkey under the ProgID key. For example:

HKEY_CLASSES_ROOT\OLE1SvrOtl\NotInsertable

Note  Since the original registry entries for the OLE 1 server application remain (but with a pointer to the OLE 2 object application as shown in the preceding step 3a), the OLE 1 ProgID will appear in the Insert Object dialog box of any OLE 2 container application installed on the system. The NotInsertable subkey mentioned in step 3b prevents the ProgID of the OLE 1 application from appearing in the Insert Object dialog box of OLE 2 containers. The NotInsertable subkey overrides any Insertable subkey entries for that ProgID key.

c.	Set the "AutoConvertTo = CLSID" subkey entry for Ole 1 In-Place Server Outline under the CLSID key to the CLSID of Ole 2 In-Place Server Outline. (See also "OLE 1 Compatibility Subkeys").

CLSID\{CLSID of OLE 1 app.}\AutoConvertTo = {CLSID of OLE 2 app.}

Note  You can obtain the CLSID of the OLE 1 object application for inclusion in registration entry file by calling CLSIDFromProgID.

d.	Modify the original registry entry of Ole 1 In-Place Server Outline by setting the verbs to those of Ole 2 In-Place Server Outline.

For example, change

OLE1ISvrOtl\Protocol\StdFileEditing\Verb\0 = &Edit

to

OLE1ISvrOtl\Protocol\StdFileEditing\Verb\0 = &Edit

OLE1ISvrOtl\Protocol\StdFileEditing\Verb\1 = &Open

4.	If the user is allowed to open Acme Draw 1.0 objects and save them back to disk in the Acme Draw 1.0 format:

a.	Set the "TreatAs = CLSID" entry to the CLSID of Ole 2 In-Place Server Outline using the following form.

CLSID\{CLSID of OLE 1 app.}\TreatAs = {CLSID of OLE 2 app.}

b.	Set the Ole 1 In-Place Server Outline verbs to those of Ole 2 In-Place Server Outline as described in the preceding step 3.


When the OLE 1 Version is Not Overwritten

You can install your program so the OLE 1 object application (Ole 1 In-Place Server Outline) is not replaced by the OLE 2 version (Ole 2 In-Place Server Outline). Instead, the user is allowed to open Ole 1 In-Place Server Outline objects with the Ole 2 In-Place Server Outline and save them back to disk in the Ole 1 In-Place Server Outline format. To do this, set the "TreatAs = CLSID" entry (Ole 1 In-Place Server Outline's portion of the registry) to the CLSID of Ole 2 In-Place Server Outline (as in step 4 above).

If the OLE 1 version of the application is not overwritten, or if the user does not want to set the "Treat As" option, register the OLE 2 version as a separate and new application.


Checking Registration During Run Time

The application should check its registration at the application load time, noting three particular issues:

•	If the CLSID(s) that the application services is not present in the registry, the application should register as it does during the original setup.

•	If the application's CLSID is present, but has no OLE 2-related information in it, the application should register as it does during the original setup.

•	If the path containing server entries (LocalServer and LocalServer32, InprocServer and InprocServer32, and DefaultIcon entries) does not point to the location in which the application is currently installed, the application should rewrite the path entries to point to its current location.


Using the Registry for Localization

It is possible to address a pair of product-localization issues by adding a key to the registry. This key, described below, allows functions to return a specified string instead of a default value or "Unknown."

This section includes the following topics:

•	Specifying Unregistered Verbs

•	Specifying Unknown User Types


Specifying Unregistered Verbs

It is possible to register OLE 1 object applications (servers) with no specified verbs. In such cases, the application has a single implied verb that is understood to be "edit" by OLE 1 containers. When an OLE 2 application calls the IOleObject::EnumVerbs method (or the OleRegEnumVerbs function) on an object of this class, one verb is enumerated. By default, the name of the verb is "Edit." To avoid having the string "Edit" as the enumerated verb, a key can be included in the registry. This key is

\Software\Microsoft\OLE1\UnregisteredVerb = <verbname>

(where verbname is the value that will be returned from the enumeration) and allows for localization of the default verb to a specified string to accommodate a specific language.

Note  Do not attempt to register a verb (under ProgID\Protocol\StdFileEditing) for an application that did not register the verb itself.


Specifying Unknown User Types

The OLE 2 default handler's implementation of the IOleObject::GetUserType method first examines the registry by calling the OleRegGetUserType method. If the object's class is not found in the registry, the User Type from the object's IStorage instance is returned. If the class is not found in the object's IStorage instance, the string "Unknown" is returned.

By inserting the

\Software\Microsoft\OLE2\UnknownUserType = <usertype>

key in the registry, the IOleObject::GetUserType method returns the value of the string specified by <usertype>. This string can be localized for a different language user-type name, instead of using the "Unknown" string, for the User Type.


Compatibility with OLE 1 and 16:32-Bit Interoperability

Note  In moving from OLE 1 to OLE 2, the following changes in terminology were made:

•	The OLE 1 term "server application" has been changed to "object application."

•	The OLE 1 term "client application" has been changed to "container application."

Compatibility implies that an OLE 1 client application can contain OLE 2 embedded and linked objects and that an OLE 1 server application can create objects to be embedded in and linked to by OLE 2 containers. OLE provides these capabilities by means of a built-in compatibility layer in the core code, which includes a set of functions for conversion.

Interoperability is not the same as OLE 1 to OLE 2 compatibility. Interoperability implies that a 16-bit OLE application can interact with a 32-bit application running on the same system. Interoperability between 16- and 32-bit implementations means that 16-bit and 32-bit implementations can call each other.


Compatibility with OLE 1

The following figure illustrates how OLE 1 and OLE 2 applications communicate. OLE 1 applications make calls to other OLE 1 applications and to OLE 2 applications using DDE.

Compatibility between OLE 2 and OLE 1 applications is achieved through the implementation of two types of special remoting objects, called stubs and proxies. The stub is instantiated on the object, or server, application's side of the process; the proxy is instantiated on the container, or client, application's side. These special stubs and proxies use DDE to communicate rather than LRPC. When an OLE 2 object makes a call to a function in an OLE 1 client application, for example, the stub intercepts the call and responds appropriately. For the most part, this response simulates the response that an OLE 2 object or container would make. However, in a few cases the behavior is different or special HRESULT (SCODE) values are returned.

This chapter discusses the issues that affect applications that must be compatible with an earlier or more recent version of OLE and describes the functions that promote this compatibility.


Working with OLE 1 Clients

This section describes some of the idiosyncrasies of working with OLE 1 clients.

A successful call to the IOleClientSite::GetContainer method returns a pointer to the container's IOleContainer interface. If the container does not support the IOleContainer interface, OLE_E_NOT_SUPPORTED is returned. All OLE 1 clients fall in this category, as do OLE 2 containers that do not support linking to their embedded objects.

The IOleClientSite::ShowObject method, a request to make the embedded or linked object visible, always returns OLE_E_NOT_SUPPORTED when called on an OLE 1 client. The purpose of this method is to help make the user model work smoothly; its failure does not effect OLE functionality.

When an OLE 1 client contains an OLE 2 object and the object is activated or the OleUpdate function is called, the aspect of the data returned will always be DVASPECT_CONTENT. This is because OLE 1 clients have no concept of a FORMATETC data structure. This situation may occur when an iconic OLE 2 object is pasted from an OLE 2 container into an OLE 1 container. When the object is first pasted, its presentation remains iconic. With the next update, however, the object's content picture is returned.

OLE 1 clients can link to OLE 2 objects only if the link source:

•	is represented by a file moniker or a generic composite moniker consisting of a file moniker and one item moniker.

•	is not an embedded OLE 2 object.

An OLE 1 client can contain an incompatible link when a linked object is pasted from an OLE 2 container into the OLE 1 client or when an OLE 2 container saves the data to an OLE 1 file, to allow the OLE 1 version of the application access to its data. When the OLE 1 client loads the incompatible link, the link is converted to an embedded object and assigned the class name "Ole2Link." The OLE 1 client cannot connect to the link source. However, if the newly embedded object is then pasted into an OLE 2 container using the Clipboard, or converted to an OLE 2 object using the OleConvertOLESTREAMToIStorage function, it will be converted back to its original state as an OLE 2 linked object.

When the link source for an OLE 1 linked object changes its name, the link can remain intact only if the file moniker for the link source has changed. That is, if the link source is a range of cells within an OLE 2 spreadsheet application and the name of the file that contains the cell range changes, OLE will track the link. However, if the name of the cell range changes, the link will break.

Pasting an OLE 2 linked object into an OLE 1 client document and then calling the OleCopyFromLink function to convert it to an embedded object will fail if the data transfer object provided by the link source does not support the IPersistStorage interface. Creating an embedded object always requires native data, and the IPersistStorage interface provides access to native data.


Working with OLE 1 Servers

This section describes some of the known idiosyncrasies of embedding or linking OLE 1 objects.

As with OLE 2 objects, either the IPersistStorage::InitNew method or the IPersistStorage::Load method must be called to properly initialize a newly instantiated OLE 1 object before any other OLE calls are made. The InitNew method should be called to initialize a newly created object; the Load method should be called for existing objects. If one of the OleCreate helper functions or the OleLoad function is being used, these functions make the IPersistStorage call, eliminating the need to make the call directly. When an OLE 2 container with an OLE 1 embedded or linked object calls the IDataObject::GetData method or the IDataObject::GetDataHere method, the container can anticipate support for a smaller set of formats and storage mediums than would be supported for an OLE 2 object. The following table lists the combinations that can be supported.

Tymed Formats	Data Formats
TYMED_MFPICT	CF_METAFILEPICT
TYMED_GDI	CF_BITMAP
TYMED_HGLOBAL	cfNative, CF_DIB, and other OLE 1 server formats
For the aspect value of DVASPECT_ICON, only TYMED_MFPICT with CF_METAFILEPICT is supported. The icon returned from the IDataObject::GetData or IDataObject::GetDataHere call will always be the first icon (index 0) in the executable object application.

Several methods typically called by containers have unique implementations for OLE 1. The IPersistStorage::IsDirty method is defined to return S_OK if the object has changed since its last save to persistent storage; S_FALSE if it has not changed. When an OLE 2 container with an OLE 1 embedded object calls the IPersistStorage::IsDirty method, the compatibility code always returns S_OK when the server is running, because there is no way to determine if the object has in fact changed until the File Close or File Update command is selected. S_FALSE is returned when the server is not running.

An OLE 2 implementation of IOleObject::IsUpToDate can return either S_OK if the object is up-to-date, S_FALSE if it is not up-to-date, or OLE_E_UNAVAILABLE if the object cannot determine whether it is up-to-date. The OLE 1 implementation always returns either E_NOT_RUNNING, if the object is in the loaded state, or S_FALSE, if the server is running.

The OLE 1 implementation of the IOleItemContainer::EnumObjects method always returns OLE_E_NOTSUPPORTED because it is not possible for an OLE 1 server to enumerate its objects.

The IOleObject::Close method takes a save option as a parameter that indicates whether the object should be saved before the close occurs. For OLE 2 objects, there are three possible save options: OLECLOSE_SAVEIFDIRTY, OLECLOSE_NOSAVE, and OLECLOSE_PROMPTSAVE. The OLE 1 implementation of the IOleObject::Close method treats OLECLOSE_PROMPTSAVE as equivalent to OLECLOSE_SAVEIFDIRTY, because it is not possible to require an OLE 1 server to prompt the user.

OLE 2 containers cannot expect an OLE 1 object to activate in-place; all OLE 1 objects support activation in a separate, open window.

OLE 1 servers do not support linking to their embedded objects. It is up to OLE 2 containers with OLE 1 embedded objects to prevent a possible link from occurring. Containers can call the CoIsOle1Class function to determine at Clipboard copy time if a data selection being copied is an OLE 1 object. If the CoIsOle1Class function returns TRUE, indicating that the selection is an OLE 1 object, the container should not offer the Link Source format. Link Source must be available for a linked object to be created.

OLE 2 containers can store multiple presentations for an OLE 1 object. However, only the first presentation format is sent to the container when the OLE 1 server closes. After that, the server is in the process of closing down and cannot honor requests for any more formats. Therefore, only the first presentation cache will be updated. The rest will be out of date (perhaps blank) if the object has changed since the last update.

Because OLE 1 servers do not update the cache for every change to an embedded object until the user selects the File Update command, an OLE 2 container may not be obtaining the latest data from the server. By calling the IOleObject::Update method, the container can obtain the latest object data.

An OLE 1 embedded (not linked) object does not notify its container that its data has changed until the user chooses File Update or File Close. Therefore, if an OLE 2 container registers for a data-change notification on an OLE 2 object in a particular format, it should be aware that it will not be notified immediately when the data changes.

When an OLE 1 object is inserted into a container document and then closed without an update being invoked, the container document is not saved. Neither are the correct streams for the object written into storage. Any subsequent loading of the object by the container will fail. To protect against this, containers can keep data available after the object closes without updating by implementing the following:

OleCreate();             \\ to insert the object

OleRun();                \\ if OLERENDER_NONE was specified

IOleObject::Update();    \\ to get snapshot of data

OleSave();

IOleObject::DoVerb();


Upgrading Applications

When an OLE 1 server is upgraded to an OLE 2 object application, several issues arise. A primary issue is whether the OLE 2 application will replace the OLE 1 application or both versions will coexist. If only the newer version will be available to the user, it is best to convert objects from the older version of the application automatically to the new version format. Objects can be converted on a global basis, where all objects of a specific class are converted, or on a more selective basis, where only some objects are converted. Conversion can be either automatic, under programmatic control, or under the control of a user.

The ability to detect whether an object is from an OLE 1 server is helpful for implementing conversion functionality. The OLE 2 implementation of the IPersistStorage::Load method can check for a stream named "\1Ole10Native." The "\1Ole10Native" stream contains a DWORD header whose value is the length of the native data that follows. The existence of this stream indicates that the data is coming from an OLE 1 server. Applications can check whether a storage object contains an object in an OLE 1 format by calling the ReadFmtUserTypeStg method and examining the contents of pcfFormat. This is where the OLE 1 class name would appear.

In the IPersistStorage::Save method, objects that are being permanently converted should be written back to storage in the new format and the "\1Ole10Native" stream should be deleted. The conversion bit in the storage should also be cleared once the conversion to the new format is complete.

To allow manual conversion of an old OLE 1 object to the new OLE 2 version, the OLE 2 object application must put the OLE 1 server's ProgID (OLE 1 server class name) into the registry under the CLSID\{...}\Conversion\Readable\Main entry. This entry indicates that the OLE 2 application can read its OLE 1 data format; the 'Clipboard format' of the OLE 1 data is the ProgID (that is, the class name) of the OLE 1 object.

To get a CLSID for an OLE 1 server, the CLSIDFromProgId function or the CLSIDFromString function must be called. That is, an OLE 1 application cannot be assigned a CLSID from an OLE 2 application with uuidgen.exe, CoCreateGuid, or by using a GUID from a range assigned by Microsoft. Because all OLE 1 CLSIDs are expected to fall in a specific range, OLE 1 CLSIDs are assigned with the CLSIDFromProgId function.

Refer to the appendix called "Registering Object Applications" for detailed information on the required registry entries for upgraded applications.


Functions to Support Compatibility

The following functions enable applications to determine whether an object class is from OLE 1, and to support conversion between OLE 1 and OLE 2 storage formats.

OLE 1 Compatibility Functions	Description
CoIsOle1Class	Determines if a given CLSID represents an OLE 1 object.
OleConvertIStorageToOLESTRAM	Converts the specified storage object from OLE 2 structured storage to the OLE 1 storage model.
OleConvertIStorageToOLESTREAMEx	Converts the specified storage object from OLE 2 structured storage to the OLE 1 storage model.
OleConvertOLESTREAMToIStorage	Converts the specified object from the OLE 1 storage model to an OLE 2 structured storage object.
OleConvertOLESTREAMToIStorageEx	Converts the specified object from the OLE 1 storage model to an OLE 2 structured storage object.


16:32 Bit Interoperability

The 32-bit implementation of OLE 2 is compatible with OLE 1 applications in the manner described above. Interoperability is achieved by converting calls made on objects in one model into calls suitable in another model. For example, if a call is made by a 16-bit application to an object that is a 32-bit implementation, the OLE 16:32 interoperability (thunk) layer takes care of marshalling and converting parameters between the two models.


Thunk Layer Operation

The thunk layer replaces the 16-bit implementations of OLE 2 with a new set of binaries that allow the 16-bit implementations to call the updated 32-bit implementation of OLE 2. These new binaries, collectively known as the thunk layer, forward all OLE 2 method and function calls to the 32-bit implementation of OLE. The OLE thunk layer inserts itself between implementations of different models. Whenever an interface is passed between implementation types, the system provides a thunk proxy and stub.

For example, a call to the CreateFileMoniker function returns a pointer to a moniker. When a 16-bit implementation calls the CreateFileMoniker function, the system thunks the call to the 32-bit OLE 2 implementation and creates a file moniker using a 32-bit implementation. When the call returns through the OLE thunk layer, the moniker pointer is translated into a 16/32 proxy.

A 16/32 proxy sets up an object in the 16-bit address space that, when called, converts each parameter for the specific method into the appropriate values for calling the 32-bit implementation. It then performs a model switch from 16-bit to 32-bit. The call is made on the 32-bit implementation, and then another model switch is made from the 32-bit to 16-bit implementation. In the process of switching back, any output parameters are converted into their 16-bit counterparts.

The system keeps track of the model of each pointer. For example, if a 16-bit application calls a 32-bit application, it passes a 16-bit pointer to an object. The thunk layer will create a 32/16 proxy to let the 32-bit application call the 16-bit application's object. In response, the 32-bit application calls back to the 16-bit application, passing the pointer it received. In this direction, the pointer being held by the 32-bit application holds is to a 32/16 proxy. The thunk layer also detects that the 32-bit pointer being passed in is a proxy, and passes the original pointer it started with to the 16-bit application. Thus, the 16-bit application sees the same pointer it passed in. This works when passing from 16 to 32 to 16, or from 32 to16 to 32. For more information about thunking, see the Win32 SDK.


Interoperability Using Standard Interfaces (OLE 2 Defined)

In its 32-bit implementation, OLE 2 is provided by the operating system and can translate OLE-defined interfaces and methods. Existing OLE 2 applications will continue to work as before. The following combinations of interoperability using the standard interfaces defined by OLE 2 are supported:

•	16 to 16 (in-process server)

•	16 to 16 (local server)

•	16 to 32 (local server)

•	32 to 32 (in-process server)

•	32 to 32 (local server)

•	32 to 16 (local server)

32- to16-bit (in-process server) interoperability using the standard interfaces is not supported.


Interoperability Using Custom Interfaces (either MIDL or Manually Written Marshalling)

Due to major architectural changes in the OLE communication layer, 16-bit applications that require remoting of custom interfaces are not supported at this time. However, 16-bit applications that use custom interfaces to an inprocess server should still function correctly. The following combinations of interoperability using custom interfaces are supported:

•	16 to 16 (inprocess server)

•	32 to 32 (inprocess server)

•	32 to 32 (local server using MIDL-generated stubs)

The following combinations of interoperability using custom interfaces are not supported:

•	16 to 16 (local server)

•	16 to 32 (all combinations)

•	32 to 16 (all combinations)

Programmers who have written applications that provide custom interfaces must rewrite the custom interface marshalling code to conform to the RPC-based communication layer. However, information about writing a 16-bit custom-marshalling library is not available at this time. For more information about RPC, see the RPC Programmer's Guide and Reference.


OLE Property Sets

Property sets store information in such a way that any conforming program can later manipulate the information. Examples of property sets are the character-formatting properties in a word processor or rendering attributes of an element in a drawing program. OLE does not provide any code or interfaces for manipulating property sets, it only specifies a standard data format structure.


Structure of Property Sets

Property sets are made up of a tagged section of values, with the section uniquely identified by a Format Identifier (FMTID). Every property consists of a property identifier and a type indicator that represents a value. Each value stored in a property set has a unique property identifier that names the property. The type indicator describes the representation of the data in the value. For example, if a specific property in a property set holds an animal's scientific name, that name could be stored as a zero-terminated string. Stored along with the name would be a type indicator to indicate the value is a zero-terminated string. The representation of properties is shown below:

Property Identifier	Type Indicator	Value Represented
PID_ANIMALNAME	VT_LPSTR	Zero-terminated string
PID_LEGCOUNT	VT_I2	WORD
Any application that recognizes the property set format can look at the property with an ID of PID_ANIMALNAME, determine it is a zero-terminated string, and read and write the value. Of course, the given application might not have any information about the property. The standard structure defined by OLE for property sets is generic as it relates to the semantics of the properties being represented; it says nothing about what they mean.

Each property set can have a dictionary associated with it to provide a displayable name for each property ID in the set. An application can read and write this dictionary and can allow end users to choose the displayable names for property IDs.


Examples of Using Property Sets

To illustrate the diverse functionality of property sets, this section presents two samples. The first uses the OLE Document Summary Information property set to show how property sets can be stored within files to allow common access to the information represented. The second example shows how property sets can be transferred between applications or OLE objects as an effective means of communication.


Storing Document Summary Information

The Document Summary Information property set is one of the simplest and most commonly used property sets. Most documents created by applications have a common set of attributes that are useful to users of those documents. These attributes include the name of the document's author, the subject of the document, when it was created, and so on.

In Windows 3.1, each application has a different way of storing this information within its documents. To examine the summary information for a given document, the user has to run the application that created the document, open it, and invoke the application's Summary Information dialog box. For example, the summary information dialog boxes that Microsoft Word 2.0 displays for its documents are shown in the following drawings:

Unfortunately, no application but Microsoft Word 2.0 can display the summary information for a Microsoft Word 2.0 document. However, with OLE property sets, this limitation can be overcome. This appendix describes one standard property set, the OLE Document Summary Information Property Set. Any application that understands the data format for this property set will be able to access the summary information contained in any document created by an OLE application that also understands the format.

For example, Microsoft Word 6.0 and many other OLE-enabled applications now save their documents using OLE structured storage and the property set standard described here. Thus, applications other than Word 6.0 are able to display the summary information property set for such a file, as long as that file is an OLE structured storage file, and the creating application saved the information in the OLE Property Set format.

For more information about the Document Summary Information property set and implementing it in your applications, see "Guidelines for Implementing the Document Summary Information Property Set" later in this appendix.


Transferring Data Contained in Property Sets

Storing information about the contents of a document is useful, and a standard that would allow all files to share the same information with all applications would be even better. However, this is only one example of how property sets can be used.

Another use for them is in the transfer of data between OLE objects or applications. To better understand the process of transferring data between two OLE objects, consider the following example. A trader on Wall Street relies on large amounts of data to make important financial decisions regarding trades of securities. This market data must be delivered to the trader's workstation in real time (or at least very soon after it was generated).

Assume that, at any given moment during an open day on Wall Street, the trader is interested in the opening, high, low, current, and last closing price of an instrument (a specific stock), and the volume of trading on that stock so far that day. The symbol for the stock will also be needed.

As noted earlier, a property in a property set has three attributes: the property identifier, a value type indicator, and a value. In this example, the following properties can be defined:

Property Identifier	Type Indicator	Value Represented
PID_SYMBOL	VT_LPSTR	Zero-terminated string
PID_OPEN	VT_CY	Currency value
PID_CLOSE	VT_CY	Currency value
PID_HIGH	VT_CY	Currency value
PID_LOW	VT_CY	Currency value
PID_LAST	VT_CY	Currency value
PID_VOLUME	VT_I4	32-bit unsigned integer
Without worrying about how the data is transferred between the data server and the trader's application, think about the data transferred and its format. Every property set must have a FMTID associated with it.

A single data element representing the stock of XYZ during the day might look like this:

PID_SYMBOL  contains "XYZ"

PID_OPEN    contains 42-3/4

PID_CLOSE   contains 42-3/4

PID_HIGH    contains 49-1/8

PID_LOW     contains 40-7/8

PID_LAST    contains 47-3/8

PID_VOLUME  contains 123,032

During a trading day on Wall Street only a few of the properties of a single instrument change. The opening price doesn't change all day, and the low price may go unchanged for several hours. Using property sets as the data transfer format allows applications to transfer only the data that has changed. For example, at some point during the day the Data Server may update the Traders Application by transferring the following StockQuote property set:

PID_SYMBOL  contains "XYZ"

PID_HIGH    contains 49-1/8

PID_LAST    contains 49-1/8

PID_VOLUME  contains 23,321

This example demonstrates how property sets can be used as a data transfer format, allowing sparse data representation. Transferring only the changed data enhances the overall performance of the trader's workstation.


Other Uses for Property Sets

Just about any object in the system can be tagged with properties. For example, a printer object can have a property set that includes such information as Location. A user object can have a property set including information like First Name, Last Name, Office, and Phone.

Applications can be written to query a system-wide set of objects based on their properties, for example, displaying all printers located in a certain building.

These examples illustrate the potential power of using property sets.


Notes on Using Property Sets

OLE property sets were designed to store data that is suited to representation as a moderately-sized collection of fine-grained values. Data sets that are too large for this to be feasible should be broken into separate streams and/or storages. The OLE property set data format was not meant to provide a substitute for a database of millions of tiny objects.


OLE Property Set Specification

All data elements within a property set are stored in Intel representation (that is, in little-endian byte order).

OLE defines a standard, serialized data format for property sets, which gives them the following characteristics:

•	Property sets allow for different applications to create their own independent property sets to serve the application's needs.

•	Property sets can be stored in a single IStream instance or in an IStorage instance containing multiple streams. Indeed, in the abstract, property sets are simply another data type that can be stored in many different forms of an in-memory or on-disk storage. For recommended conventions on creating the string name for the storage object, see the section "Naming Property Sets" later in this appendix.

•	Property sets can be transmitted using the IDataObject interface and/or the Clipboard. Because property sets are self-identifying, they are ideal for transferring data between applications.

•	Property sets allow for a dictionary of displayable names to be included to further describe the contents. A set of conventions for choosing property names are recommended. For more information on this optional dictionary, see "Property ID Zero" later in this appendix.

The figure below shows the overall structure of a property set:

The property set stream is divided into three major parts:

•	Header

•	FORMATID/offset pair

•	Section containing the actual property set values

The overall length of the property set stream is 256Kb. The following sections of this chapter describe the individual components that make up the property set data format as shown in the previous figure.

Note  Previous versions of this document described extensions to the property set stream with more than one section allowed, but that has been revised now to provide for one section in the property stream.


Property Set Header

At the beginning of the property set stream is a header. It consists of a byte-order indicator, a format version, the originating operating system version, the CLSID, and a reserved field. Each offset is the distance in bytes from the start of the whole stream to where the section begins.

The following pseudo-structure illustrates the header:

typedef struct tagPROPERTYSETHEADER

{

// Header

WORD  wByteOrder ;  // Always 0xFFFE

WORD  wFormat ;     // Always 0

WORD  dwOSVer ;     // System version

CLSID  clsID ;      // Application CLSID

DWORD  reserved ;   // Should be 1

} PROPERTYSETHEADER;


Byte-Order Indicator

The byte-order indicator is a WORD and should always hold the value 0xFFFE. This is the same as the Unicode byte-order indicator. This value is always written in Intel byte order and, thus, appears in the file or stream as 0xFE, 0xFF.


Format Version

The Format Version is a WORD used to indicate the format version of this stream. It should always be zero. The format-version indicator should be checked when reading the property set. If it is not zero, then the stream was written to a different specification and cannot be read by code developed according to the OLE 2 specification.


Originating OS Version

This DWORD should hold the kind of operating system in the high word and the version number of the operating system in the low word. Possible values for the operating system are:

Operating System	Value
32-Bit Windows (Win32)	0x0002
Macintosh	0x0001
16-Bit Windows (Win16)	0x0000
For Windows, the operating system version is the low order word returned by the GetVersion function. On Windows, the following code would correctly set the version of the originating operating system:

#ifdef WIN32

dwOSVer = (DWORD)MAKELONG( LOWORD(GetVersion()), 2 ) ;

#else

dwOSVer = (DWORD)MAKELONG( LOWORD(GetVersion()), 0 ) ;

#endif


CLSID

The CLSID is that of a class that can display and/or provide programmatic access to the property values. If there is no such class, it is recommended that you set this value the same as the Format ID (see below). Alternately, you can set this value to all zeroes; however, using the Format ID allows more flexibility in the future.


Reserved

This DWORD is reserved for future use. Writers of property sets should set this value to 1; readers of property sets should ensure that this value is at least 1.


Format Identifier/Offset Pair

The second part of the property set stream contains one Format Identifier (FMTID)/Offset Pair. The FMTID is the name of the property set; it uniquely identifies how to interpret the contents of the following section. The Offset is the distance of bytes from the start of the whole stream to where the section begins.

The following structure is helpful in dealing with Format Identifier/Offset Pairs:

typedef struct tagFORMATIDOFFSET

{

FMTID  fmtid ;     // The name of the section.

DWORD  dwOffset ;  // The offset for the section

} FORMATIDOFFSET;


Format Identifiers

Property set values are stored in a section that is tagged with a unique format identifier. For example, the FMTID for the OLE Document Summary Information property set is:

F29F85E0-4FF9-1068-AB91-08002B27B3D9

To define a FMTID for the Document Summary Information property set, you would use the DEFINE_GUID macro in an include file for the code that manipulates the property set:

DEFINE_GUID(FormatID_SummaryInformation, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9);

Anywhere in your code you need to use the FMTID for the Document Summary Information property set, you can access it through the FormatID_SummaryInformation variable.

When storing property sets in IStorage instances, you need to convert the FMTID to a string name for the storage object. For more information on recommended conventions for creating the string name, see the section "Naming Property Sets" later in this appendix.


Allocating Format Identifiers

FMTIDs are created and represented in the same way as OLE CLSIDs and interface IDs. To create a unique FMTID, use the UUIDGEN.EXE program included in the Win32 SDK.


Section

This is the third part of the property set stream, as shown in Figure C.2. A section contains:

•	byte count for the section (which is inclusive of the byte count itself)

•	count of the property values in the section

•	array of 32-bit Property ID/Offset pairs

•	array of property Type Indicators/Value pairs

Offsets are the distance from the start of the section to the start of the property (type, value) pair. This allows a section to be copied as an array of bytes without any translation of internal structure.

The following pseudo-structures illustrate the format of a section:

typedef struct tagPROPERTYSECTIONHEADER

{

DWORD  cbSection ;    // Size of Section

DWORD  cProperties ;  // Count of Properties in section

} PROPERTYSECTIONHEADER;

typedef struct tagPROPERTYIDOFFSET

{

DWORD  propid;   // Name of property

DWORD  dwOffset; // Offset from start of section to that property

} PROPERTYIDOFFSET;

typedef struct tag SERIALIZEDPROPERTYVALUE

{

DWORD  dwType;  // Property Type

BYTE  rgb[];    // Property Value

} SERIALIZEDPROPERTYVALUE ;


Size of Section

This DWORD indicates the size of the section. Because the section size is the first four bytes, you can copy sections as an array of bytes.

For example, an empty section (one with zero properties in it) would have a byte count of eight (the DWORD byte count and the DWORD count of properties). The section itself would contain the eight bytes:

08 00 00 00 00 00 00 00


Count of Properties

This DWORD gives a count of the property values in the section. A property set may contain any number of property values. Readers must be able to handle the case where there are zero properties.


Property ID/Offset Pairs

Following the Count of Properties is an array of Property ID/Offset Pairs. Property IDs are 32-bit values that uniquely identify a property within a section. The Offsets indicate the distance from the start of the section to the start of the property Type/Value Pair. If the offsets are relative to the section, sections can be copied as an array of bytes.

Property IDs are not sorted in any particular order. Properties can be omitted from the stored property set; readers must not rely on a specific order or range of property IDs.


Type Indicators

After the table of Property ID/Offset Pairs comes the actual properties. Each property is stored as a DWORD type followed by the data value.

Type indicators and their associated values are defined in the OLE header files that are shipped with the Win32 SDK.

All Type/Value pairs must begin on a 32-bit boundary. Thus values may be followed with null bytes to align the subsequent pair on a 32-bit boundary. Given a count of bytes, the following code will calculate how many bytes are needed to align on a 32-bit boundary:

cbAdd = (((cbCurrent + 3) >> 2) << 2) - cbCurrent ;

Within a vector of values, each repetition of value must align with its natural alignment rather than with a 32-bit alignment. In practice, this is only significant for types VT_I2 and VT_BOOL (which have two-byte natural alignment). All other types have four-byte natural alignment. Therefore, a property value with type indicator VT_I2 | VT_VECTOR would be:

•	A DWORD element count, followed by

•	A sequence of packed two-byte integers with no padding between them.

A property value of type identifier VT_LPSTR | VT_VECTOR would be:

•	A DWORD element count (DWORD cch), followed by

•	A sequence of strings (char rgch[]), each of which may be followed by null padding to round to a 32-bit boundary.

The following table lists the standard OLE-defined property type indicators and their meaning:

Type Indicator	Code	Value Representation
VT_EMPTY	0	None. A property set with a type indicator of VT_EMPTY has no data associated with it; that is, the size of the value is zero.
VT_NULL	1	None. This is like a pointer to NULL.
VT_I2	2	Two bytes representing a 2-byte signed int value. This value will be zero-padded to a 32-bit boundary.
VT_I4	3	Four bytes representing a 4-byte signed int value.
VT_R4	4	Four bytes representing a 32-bit IEEE floating point value.
VT_R8	5	Eight bytes representing a 64-bit IEEE floating point value.
VT_CY	6	Eight-byte two's complement integer (scaled by 10,000). This type is commonly used for currency amounts.
VT_DATE	7	Time format used by many applications, it is a 64-bit floating point number representing days since December 31, 1899. This is stored in the same representation as VT_R8. For example, January 1, 1900 is 2.0, while January 2, 1900 is 3.0, and so on.
VT_BSTR	8	Counted, zero-terminated binary string; represented as a DWORD byte count (including the terminating null character) followed by the bytes of data.
VT_BOOL	11	Two bytes representing a Boolean (WORD) value containing 0 (FALSE) or -1 (TRUE). This type must be zero-padded to a 32-bit boundary.
VT_VARIANT	12	Four-byte indicator followed by the corresponding value. This is only used in conjunction with VT_VECTOR.
VT_I8	20	Eight bytes representing a signed integer.
VT_LPSTR	30	Same as VT_BSTR; this is the representation of most strings.
VT_LPWSTR	31	A counted and zero-terminated Unicode string; a DWORD character count (where the count includes the terminating null character) followed by that many Unicode (16-bit) characters. Note that the count is not a byte count, but a WORD count.
VT_FILETIME	64	64-bit FILETIME structure, as defined by Win32: typedef struct_FILETIME{   DWORD dwLowDateTime;   DWORD dwHighDateTime; }FILETIME;
VT_BLOB	65	DWORD count of bytes, followed by that many bytes of data. The byte count does not include the four bytes for the length of the count itself; an empty BLOB would have a count of zero, followed by zero bytes. This is similar to VT_BSTR but does not guarantee a null byte at the end of the data.
VT_STREAM	66	A VT_LPSTR (DWORD count of bytes followed by a zero-terminated string that many bytes long) that names the stream containing the data. The real value for this property is stored in a stream object, which is a sibling to the Contents stream. This type is only valid for property sets stored in the Contents stream of a storage object.
VT_STORAGE	67	A VT_LPSTR (DWORD count of bytes followed by a zero-terminated string that many bytes long) that names the storage containing the data. The real value for this property is stored in a storage object, which is a sibling to the Contents stream that contains the property set. This type is only valid for property sets stored in the Contents stream of a storage object.
VT_STREAMED_OBJECT	68	Same as VT_STREAM, but indicates that the stream object named in this property contains a serialized object, which is a CLSID followed by initialization data for the class. The named stream is a sibling to the Contents stream that contains the property set. This type is only valid for property sets stored in the Contents stream of a storage object.
VT_STORED_OBJECT	69	Same as VT_STORAGE, but indicates that the storage object named in this property contains an object. This type is only valid for property sets stored in the Contents stream of a storage object.
VT_BLOB_OBJECT	70	An array of bytes containing a serialized object in the same representation as would appear in a VT_STREAMED_OBJECT (VT_LPSTR). The only significant difference between this type and VT_STREAMED_OBJECT is that VT_BLOB_OBJECT does not have the system-level storage overhead as VT_STREAMED_OBJECT. VT_BLOB_OBJECT is more suitable for scenarios involving numerous small objects.
VT_CF	71	An array of bytes containing a Clipboard format identifier followed by the data in that format. That is, following the VT_CF identifier is the data in the format of a VT_BLOB. This is a DWORD count of bytes followed by that many bytes of data in the following format: a LONG followed by an appropriate Clipboard identifier and a property whose value is plain text should use VT_LPSTR, not VT_CF to represent the text. Notice also that an application should choose a single Clipboard format for a property's value when using VT_CF. For more information, see "Clipboard Format Identifiers," later in this appendix.
VT_CLSID	72	A CLSID, which is a DWORD, two WORDs, and eight bytes.
VT_VECTOR	0x1000	If the type indicator is one of the previous values in addition to this bit being set, then the value is a DWORD count of elements, followed by that many repetitions of the value. When VT_VECTOR is combined with VT_VARIANT (VT_VARIANT must be combined with VT_VECTOR) the value contains a DWORD element count, a DWORD type indicator, the first value, a DWORD type indicator, the second value, and so on. Examples: VT_LPSTR | VT_VECTOR has a DWORD element count, a DWORD byte count, the first string data, a DWORD byte count, the second string data, and so on.  VT_I2 | VT_VECTOR has a DWORD element count followed by a sequence of two-byte integers, with no padding between them.


New Type Indicators

There is no provision in the OLE specification for adding new type indicators to the list above. However, new types can be defined by using the VT_VARIANT type combined with the VT_VECTOR flag. For example, assume you want to store the following packed structure in a property set:

typedef struct tagPACKED

{

DWORD  dwValue1 ;  // 32 bit value

WORD   wFlag ;     // 16 bits of flags

WORD   wValue2 ;   // 16 bit value

} PACKED ;

This 64-bit structure could be stored using VT_VARIANT | VT_VECTOR as follows:

DWORD  // dwTypeIndicator = VT_VARIANT | VT_VECTOR ;

DWORD  // dwElementCount = 3 ;

DWORD  // dwTypeIndicator = VT_I4 ;

DWORD  // dwValue1 ;

DWORD  // dwTypeIndicator = VT_I2 ;

WORD   // wFlag ;

DWORD  // dwTypeIndicator = VT_I2 ;

WORD   // wValue2 ;


Reserved Property IDs

As a designer of property sets you can use any Property ID for your properties except 0, 1, 0xFFFFFFFE, and all negative values. These Property ID values are reserved for use by applications as follows.


Property ID Zero

To enable users of property sets to attach meaning to properties beyond those provided by the type indicator, property ID zero is reserved for an optional dictionary of displayable names for the property set.

The dictionary contains a count of entries in the list followed by a list of dictionary entries.

typedef struct tagDICTIONARY

{

DWORD  cbEntries ;            	// Count of entries in the list

ENTRY  rgEntry[ cbEntries ] ; // Property ID/String pair

} DICTIONARY ;

Each dictionary entry in the list is a Property ID/String pair. This can be illustrated using the following pseudo-structure definition for a dictionary entry (it's a pseudo-structure because the sz[] member is variable in size):

typedef struct tagENTRY

{

DWORD  dwPropID ; // Property ID

DWORD  cb ;       // Count of characters in the string

char  sz[cb];     // Zero-terminated string

} ENTRY ;

Note the following about property set dictionaries:

•	Property ID Zero does not have a type indicator. The DWORD that indicates the count of entries sits in the type indicator position.

•	The count of characters in the string (cb) includes the zero character that terminates the string.

•	The dictionary is entirely optional. Not all the names of properties in the set need appear in the dictionary. The dictionary can omit entries for properties assumed to be universally known by clients that manipulate the property set. Typically, names for the base property sets for widely accepted standards are omitted, but special purpose property sets may include dictionaries for use by browsers.

•	Property names in the dictionary are stored in the code page indicated by Property ID One (see below). For all code pages other than the Unicode code page (1200), each name is byte aligned. Thus, there is no padding between property names with Property ID Zero. If the Unicode code page is specified, the property name strings must be aligned on 32-bit boundaries.

•	Property names that begin with the binary Unicode characters 0x0001 through 0x001F are reserved for future use.

The dictionary is stored as a VT_BLOB | VT_VECTOR value. Each BLOB in the vector contains the prerequisite DWORD count of bytes followed by a DWORD indicating the Property ID followed by the name (a zero-terminated string).


Example Dictionary

The stock market data transfer example (see "Transferring Data Contained in Property Sets," earlier in this appendix) might include a displayable name of "Stock Quote" for the entire set, and "Ticker Symbol" for PID_SYMBOL. If a property set contained just a symbol and the dictionary, the property set section would have a byte stream that looked like the following:

Offset     Bytes

; Start of section

0000    43 01 00 00      ; DWORD size of section

0004    03 00 00 00      ; DWORD number of properties in section

; Start of PropID/Offset pairs

0008    00 00 00 00      ; DWORD Property ID (0 == dictionary)

000C    20 00 00 00      ; DWORD offset to property ID

0010    01 00 00 00      ; DWORD Property ID (1 == code page)

0014    D0 00 00 00      ; DWORD offset to property ID

0018    07 00 00 00      ; DWORD Property ID (i.e., PID_SYMBOL)

001C    34 01 00 00      ; DWORD offset to property ID

; Start of Property 0 (which is really the dictionary

0020    08 00 00 00    ; DWORD Number of entries in dictionary

                       ; (Note: No type indicator)

0024    00 00 00 00	    ; DWORD dwPropID = 0

0028    18 00 00 00    ; DWORD cb = (wstrlen("Stock Quote")+1)

                       ;     * sizeof(WCHAR) == 24

002C    L"Stock Quote\0"    ; char sz[24]

0044    03 00 00 00     ; DWORD dwPropID = 3 (PID_SYMBOL)

0048    1C 00 00 00     ; DWORD cb = (wstrlen("Ticker Symbol") + 1

                        ;     * sizeof(WCHAR) == 28

004C    L"Ticker Symbol\0"    ; char sz[28]

; The dictionary would continue, but may not contain entries for

; every possible property. Also entries do not need to be in order

; (except dwPropID == 0 must be first).

; Start of Property 1 (code page indicator)

00D0    02 00 00 00    ; DWORD type indicator (VT_12)

00D4    B0 04 00 00    ; USHORT codepage (0x04B0 == 1200 == Unicode)

; Start of Property 7 (PID_SYMBOL)

0134     1E 00 00 00     ; DWORD type indicator (VT_LPWSTR == 1F)

0138     0A 00 00 00     ; DWORD count of bytes

013C    L"MSFT\0"        ; WCHAR sz[5] (incl 2 bytes for the NULL)


Property ID One

Property ID One is reserved as an indicator of which code page (Windows) or Script (Macintosh) to use when interpreting the strings in the property set. All string values in the property set must be stored with the same code page. The originating operating system value in the property set header (PROPERTYSETHEADER::dwOSVer) determines whether the code page indicator corresponds to a Windows code page or Macintosh script.

When an application that is not the author of a property set changes a property of type string in the set, it should examine the code page indicator and take one of the following actions:

•	Write the new value using the code page found in the code page indicator.

•	Rewrite all string values in the property set using the new code page (including the new value), and modify the code page indicator to reflect the new code page.

If an application cannot understand this indicator, it should not modify the property. All writers of property sets must write a code page indicator; however, if the code page indicator is not present, the prevailing code page on the reader's machine must be assumed.

Possible values for the code page are given in the Window 32 API (see the GetACP function) and Inside Macintosh Volume VI, §14-111. For example, the code page US ANSI is represented by 0x04E4 (1252 in decimal) while the code page for Unicode is 0x04B0 (1200 in decimal).

It is recommended that the Unicode code page be used whenever possible. Using the same code page for all property sets is the only way to achieve interoperable property sets on a worldwide basis. In the Unicode code page, note that the count at the start of a VT_LPSTR or VT_BSTR or other eight-bit character quantities in the property set is a byte count and not a character count. This byte count includes the two zero bytes at the end of the string.

Property ID one is a VT_12 type and thus starts with a DWORD containing the value VT_12 followed by a USHORT indicating the code page.


Property ID 0xFFFFFFFE

Property ID 0xFFFFFFFE (Locale Indicator) is reserved as an indication of the locale for which the property set is written. The default locale for a property set is the system's default locale (LOCALE_SYSTEM_DEFAULT). See the Win32 SDK for more information on LOCALE_SYSTEM_DEFAULT. The default is used in the event that the locale indicator does not exist in the property set.

Applications can choose to support the locale or just get the default behavior. It is recommended that applications allow users to specify a working locale. Such applications should write the user-specified locale identifier to the property. Applications that use the user's default locale (LOCALE_USER_DEFAULT) should write the user's default locale identifier to the property. See the Win32 SDK for more information on LOCALE_USER_DEFAULT.

Applications should also handle the case of a foreign object which is one where the locale is not the application's locale, the user's locale, or the system's locale.

The locale indicator property is of type VT_U4, and therefore consists of a DWORD containing VT_U4 followed by a DWORD containing the Locale Identifier (LCID) as defined in the Win32 SDK.


Other Reserved Property IDs

Property IDs with the high bit set (that is, negative values) are reserved for future use by Microsoft.


Clipboard Format Identifiers

There are five kinds of Clipboard FMTIDs that can occur in VT_CF values: Windows Clipboard Format Values, Macintosh Format Values, Format Identifiers, Clipboard Format Names, and No Format Name. The following table illustrates the representation of each of these five types:

First Four Bytes	Following Value Size	Meaning
-1L	4 bytes (DWORD)	Windows built-in Clipboard Format Value (CF_TEXT).
-2L	4 bytes (DWORD)	Macintosh Format Value (4-byte tag).
-3L	16 bytes (Format ID)	FMTID.
Length of String	Variable	Clipboard format name that has been registered by RegisterClipboardFormat (or some Macintosh equivalent, if any). The string length includes the null terminator.
0L	Zero	No format name.
Therefore, the format of a VT_CF value is:

DWORD cb ;	              // count of bytes that follow (4 + cbTag +

                        // cbData)

DWORD cftag ;	           // contains one of the five cftag values

                        // (0,-1,-2,-3, or positive)

BYTE rgcftag[ cbTag ] ; 	// cbTag bytes representing the FMTID

BYTE rgData[ cbData ] ; // clipboard data in the specified format

For example, if a VT_CF property contained a 4235 byte bitmap that was stored in the Windows CF_DIB (0x08) Clipboard format, the count of bytes would be 4243 (4235 + 4 + 4) or 0x1093. The following stream of bytes would be stored:

93 10 00 00 FF FF FF FF 08 00 00 00 ?? ?? ?? ?? ?? ?? ...

|--- cb ---|-- cftag --|- rgcftag -|--- rgData (4235 bytes )...


Storing Property Sets

Applications can expose some of the state of their documents so that other applications can locate and read that information. Some examples are a property set describing the author, title, and keywords of a document created with a word processor, or the list of fonts used in a document. This facility is not restricted to documents; it can also be used on embedded objects.

Note  If you are storing a property set that is internal to your application, you might not want to follow the guidelines described below. If you want to expose your property set to other applications, you need to follow the guidelines.

To store a property set in a compound file:

1.	Create an IStorage or IStream instance in the same level of the storage structure as its data streams. Prepend the name of your IStorage or IStream instance with "\005." Stream and storage names that begin with 0x05 are reserved for common property sets that can be shared among applications. Also, streams beginning with that value are limited to 256Kb. The names can be selected from either published names and formats or by assigning the property set a FMTID and deriving the name from the FMTID according to the conventions described in the section "Naming Property Sets".

2.	A property set may be stored in a single IStream instance or in an IStorage instance containing multiple streams. In the case of an IStorage instance, the contained stream named "Contents" is the primary stream containing property values, where some values may be names of other streams or storage instances within the storage for this property set.

3.	Specify the CLSID of the object class that can display and/or provide programmatic access to the property values. If there is no such class, the the CLSID should be set to CLSID_NULL. For a property set that uses an IStorage instance, either set the CLSID of the IStorage instance to be the same as that stored in the Contents stream or to CLSID_NULL (the value in a newly created IStorage instance).

4.	You have the option of specifying displayable names that form the contents of the dictionary.

Some applications can read only implementations of property sets stored as IStream instances. Applications should be written to expect that a property set may be stored in either an IStorage or IStream instance, unless the property set definition indicates otherwise. For example, the Document Summary Information property set's definition says that it can only be stored in a named IStream instance. In cases where you are searching for a property set and you don't know whether it is a storage or stream, look for an IStream instance with your property set name first. If that fails, look for an IStorage instance.

To better understand storing property sets in an IStorage implementation, suppose there is a class of applications that edit information about animals. First, a CLSID (CLSID_AnimalApp) is defined for this set of applications so they can indicate that they understand property sets containing animal information (FormatID_AnimalInfo) and others containing medical information (FormatID_MedicalInfo).

IStorage (File): "C:\OLE\REVO.DOC"

  IStorage: "\005AnimalInfo", CLSID = CLSID_AnimalApp

    IStream: "Contents"

      WORD dwByteOrder, WORD wFmtVersion, DWORD dwOSVer,

      CLSID CLSID_AnimalApp, DWORD cSections...

      ...

      FormatID = FormatID_AnimalInfo

      Property: Type = PID_ANIMALTYPE, Type = VT_LPSTR, Value = "Dog"

      Property: Type = PID_ANIMALNAME, Type = VT_LPSTR, Value = "Revo"

      Property: Type = PID_MEDICALHISTORY, Type = VT_STREAMED_OBJECT,

              Value = "MedicalInfo"

      ...

    IStream: "MedicalInfo"

      WORD dwByteOrder, WORD wFmtVersion, DWORD dwOSVer,

      CLSID CLSID_AnimalApp, DWORD cSections...

      ...

      FormatID = CLSID_MedicalInfo

      Property: Type = PID_VETNAME, Type = VT_LPSTR, Value = "Dr. Woof"

      Property: Type = PID_LASTEXAM, Type = VT_DATE, Value = ...

Note that the class IDs of the IStorage and both property sets is CLSID_AnimalApp. This identifies any application that can display and/or provide programmatic access to these property sets. Any application can read the information within the property sets (the point behind property sets), but only applications identified with the class ID of CLSID_AnimalApp can understand the meaning of the data in the property sets.


Naming Property Sets

Property sets are named with FMTIDs, but in IStorage and IStream instances, they are named with strings with a maximum length of 32 characters. As a result, you need to create string names corresponding to the FMTID.

To create a string name corresponding to the FMTID, first check to determine if the FMTID is one of a fixed set of established values. If it is an already established value, then use the corresponding string name as follows:

FMTID	String Name	Meaning
F29F85E0-4FF9-1068- AB91-08002B27B3D9	"\005SummaryInformation"	OLE Summary Information.
With the exception of the SummaryInformation property set (described in the following section), all other stream and storage objects used to store property sets should be named using the algorithm described in the following steps. The algorithm maps the 16-byte FMTID of the property set to a 31-character string. Storage and stream objects are restricted to 32-character names.

1.	Convert the FMTID to little-endian byte order if necessary.

2.	Take the 128 bits of the FMTID and treat them as one long bit string by concatenating each of the bytes together. The first bit of the 128 bit value is the most significant bit of the first byte in memory of the FMTID. The last bit of the 128 value is the least significant bit of the last byte in memory of the FMTID.

3.	Extend these 128 bits to 130 bits by adding two zero bits to the end.

4.	Divide the 130 bits into groups of five bits. There will be 26 groups of five bits each.

5.	Consider each of the 26 groups as an integer value and use it as the index into the following array of 32 characters:

ABCDEFGHIJKLMNOPQRSTUVWXYZ012345

This results a sequence of 26 Unicode characters (one character from each of the 26 groups). Only the uppercase alphabet and numerals are used. No two characters in this range will compare as equal in any locale even when case is ignored.

6.	Concatenate "\005" with the resulting 26-character string from step 5 for a total string length of 27 characters.

Note  To be compatible with future versions of the operating system, you need to follow the mapping scheme described here.

The following code illustrates this process:

#define CCH_MAP	(1 << CBIT_CHARMASK)	// 32

#define CHARMASK	(CCH_MAP - 1)	// 0x1f

#define CBIT_BYTE 	8

#define CBIT_CHARMASK	5

#define CBIT_GUID	(CBIT_BYTE * sizeof(GUID))

#define WC_PROPSET0	((WCHAR) 0x0005)

#define CWC_PROPSET	(1 + (CBIT_GUID + CBIT_CHARMASK-1)/CBIT_CHARMASK)

#define CWC_PROPSETSZ	(CWC_PROPSET + 1)            // allow null

CHAR awcMap[CCH_MAP + 1] = "abcdefghijklmnopqrstuvwxyz012345";

#define CALPHACHARS	('z' - 'a' + 1)

GUID guidSummary =

    { 0xf29f85e0,

      0x4ff9, 0x1068,

      { 0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9 } };

WCHAR wszSummary[] = L"SummaryInformation";

// ---------------------------------------------------------------------

// Function:    GuidToPropertySetName

//

// Synopsis:    Map property set GUID to null-terminated UNICODE name string.

//

//    The awcname parameter is assumed to be a buffer with room for

//    CWC_PROPSETSZ (28) UNICODE characters.  The first character

//    is always WC_PROPSET0 (0x05), as specified by the OLE Appendix

//    C documentation.  The colon character normally used as an NT

//    stream name separator is not written to the caller's buffer.

//

// Arguments:   IN GUID *pguid      -- pointer to GUID to convert

//    OUT WCHAR awcname[] -- output string buffer

//

// Returns:     count of non-NULL characters in the output string buffer

//----------------------------------------------------------------------

ULONG

GuidToPropertySetName(

    IN GUID const *pguid,

    OUT WCHAR awcname[])

{

    BYTE *pb = (BYTE *) pguid;

    BYTE *pbEnd = pb + sizeof(*pguid);

    ULONG cbitRemain = CBIT_BYTE;

    WCHAR *pwc = awcname;

    *pwc++ = WC_PROPSET0;

    // Note: CWC_PROPSET includes the WC_PROPSET0, and sizeof(wsz...)

    // includes the trailing L'\0', so sizeof(wsz...) is ok because the

    // WC_PROPSET0 character compensates for the trailing NULL character.

    ASSERT(CWC_PROPSET >= sizeof(wszSummary)/sizeof(WCHAR));

    if (*pguid == guidSummary)

    {

  CopyMemory(pwc, wszSummary, sizeof(wszSummary));

  return(sizeof(wszSummary)/sizeof(WCHAR));

    }

     while (pb < pbEnd)

    {

  ULONG i = *pb >> (CBIT_BYTE - cbitRemain);

  if (cbitRemain >= CBIT_CHARMASK)

  {

      *pwc = MapChar(i);

      if (cbitRemain == CBIT_BYTE && *pwc >= L'a' && *pwc <= L'z')

      {

    *pwc += (WCHAR) (L'A' - L'a');

      }

      pwc++;

      cbitRemain -= CBIT_CHARMASK;

      if (cbitRemain == 0)

      {

    pb++;

    cbitRemain = CBIT_BYTE;

      }

  }

  else

  {

      if (++pb < pbEnd)

      {

    i |= *pb << cbitRemain;

      }

            *pwc++ = MapChar(i);

      cbitRemain += CBIT_BYTE - CBIT_CHARMASK;

  }

    }

    *pwc = L'\0';

    return(CWC_PROPSET);

}

// ---------------------------------------------------------------------

// Function:    PropertySetNameToGuid

//

// Synopsis:    Map non null-terminated UNICODE string to a property set GUID.

//

//    If the name is not properly formed as per

//    GuidToPropertySetName(), STATUS_INVALID_PARAMETER is

//    returned.  The pguid parameter is assumed to point to a buffer

//    with room for a GUID structure.

//

// Arguments:   IN ULONG cwcname   -- count of WCHARs in string to convert

//    IN WCHAR awcname[] -- input string to convert

//    OUT GUID *pguid     -- pointer to buffer for converted GUID

//

// Returns:     ULONG status

//----------------------------------------------------------------------

ULONG

PropertySetNameToGuid(

    IN ULONG cwcname,

    IN WCHAR const awcname[],

    OUT GUID *pguid)

{

    ULONG Status = ERROR_INVALID_PARAMETER;

    WCHAR const *pwc = awcname;

    if (pwc[0] == WC_PROPSET0)

    {

  // Note: cwcname includes the WC_PROPSET0, and sizeof(wsz...)

  // includes the trailing L'\0', but the comparison excludes both

  // the leading WC_PROPSET0 and the trailing L'\0'.

  if (cwcname == sizeof(wszSummary)/sizeof(WCHAR) &&

      wcsnicmp(&pwc[1], wszSummary, cwcname - 1) == 0)

  {

      *pguid = guidSummary;

      return(NO_ERROR);

  }

  if (cwcname == CWC_PROPSET)

  {

      ULONG cbit;

      BYTE *pb = (BYTE *) pguid - 1;

      ZeroMemory(pguid, sizeof(*pguid));

      for (cbit = 0; cbit < CBIT_GUID; cbit += CBIT_CHARMASK)

      {

    ULONG cbitUsed = cbit % CBIT_BYTE;

    ULONG cbitStored;

    WCHAR wc;

    if (cbitUsed == 0)

    {

        pb++;

    }

    wc = *++pwc - L'A';        // assume upper case

    if (wc > CALPHACHARS)

    {

        wc += (WCHAR) (L'A' - L'a');    // oops, try lower case

        if (wc > CALPHACHARS)

        {

      wc += L'a' - L'0' + CALPHACHARS;  // must be a digit

      if (wc > CHARMASK)

      {

          goto fail;      // invalid character

      }

        }

    }

    *pb |= (BYTE) (wc << cbitUsed);

    cbitStored = min(CBIT_BYTE - cbitUsed, CBIT_CHARMASK);

    // If the translated bits wouldn't all fit in the current byte

    if (cbitStored < CBIT_CHARMASK)

    {

        wc >>= CBIT_BYTE - cbitUsed;

        if (cbit + cbitStored == CBIT_GUID)

        {

      if (wc != 0)

      {

          goto fail;      // extra bits

      }

      break;

        }

        pb++;

        *pb |= (BYTE) wc;

    }

      }

      Status = NO_ERROR

  }

    }

fail:

    return(Status);

}


The Document Summary Information Property Set

OLE defines a standard common property set for storing summary information about documents. The Document Summary Information property set must be stored in an IStream instance off of the root storage object; it is not valid to store the property set in the "Contents" stream of a named IStorage instance.

All shared property sets are identified by a stream or storage name prepended with "\005" (or 0x05) to show it is a property set shareable among applications and the Document Summary Information property set is no exception. The name of the stream that contains the Document Summary Information property set is:

"\005SummaryInformation"

The FMTID for the Document Summary Information property set is:

  F29F85E0-4FF9-1068-AB91-08002B27B3D9

Use the DEFINE_GUID macro to define the FMTID for the property set:

DEFINE_GUID(FormatID_SummaryInformation, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9);

On an Intel byte-ordered machine, the FMTID has the following representation:

  E0 85 9F 4F 68 10 AB 91 08 00 2B 27 B3 D9

The following table shows the property names for the Document Summary Information property set, along with the respective property IDs and type indicators.

Property Name	Property ID	Property ID Code	Type
Title	PID_TITLE	0x00000002	VT_LPSTR
Subject	PID_SUBJECT	0x00000003	VT_LPSTR
Author	PID_AUTHOR	0x00000004	VT_LPSTR
Keywords	PID_KEYWORDS	0x00000005	VT_LPSTR
Comments	PID_COMMENTS	0x00000006	VT_LPSTR
Template	PID_TEMPLATE	0x00000007	VT_LPSTR
Last Saved By	PID_LASTAUTHOR	0x00000008	VT_LPSTR
Revision Number	PID_REVNUMBER	0x00000009	VT_LPSTR
Total Editing Time	PID_EDITTIME	0x0000000A	VT_FILETIME
Last Printed	PID_LASTPRINTED	0x0000000B	VT_FILETIME
Create Time/Date (*)	PID_CREATE_DTM	0x0000000C	VT_FILETIME
Last saved Time/Date (*)	PID_LASTSAVE_DTM	0x0000000D	VT_FILETIME
Number of Pages Number of Words Number of Characters	PID_PAGECOUNT PID_WORDCOUNT PID_CHARCOUNT	0x0000000E 0x0000000F 0x00000010	VT_I4 VT_I4 VT_I4
Thumbnail	PID_THUMBNAIL	0x00000011	VT_CF
Name of Creating Application	PID_APPNAME	0x00000012	VT_LPSTR
Security	PID_SECURITY	0x00000013	VT_I4
* Some methods of file transfer (such as a download from a BBS) do not maintain the file system's
version of this information correctly.


Guidelines for Implementing the Document Summary Information Property Set

The following guidelines pertain to the Document Summary Information property set described in the preceding section:

•	PID_TEMPLATE refers to an external document containing formatting and styling information. The means by which the template is located is implementation defined.

•	PID_LASTAUTHOR is the name stored in User Information by the application. For example, suppose Mary creates a document on her machine and gives it to John, who then modifies and saves it. Mary is the author, John is the last saved by value.

•	PID_REVNUMBER is the number of times the File/Save command has been called on this document.

•	PID_CREATE_DTM is a read-only property; this property should be set when a document is created, but should not be subsequently changed.

•	For PID_THUMBNAIL, applications should store data in CF_DIB or CF_METAFILEPICT format. CF_METAFILEPICT is recommended.

•	PID_SECURITY is the suggested security level for the document. By noting the security level on the document, an application other than the originator of the document can adjust its user interface to the properties appropriately. An application should not display any information about a password protected document or allow modifications to enforced read-only or locked-for-annotations documents. Applications should warn the user about read-only recommended if the user attempts to modify properties:

Security Level	Value
None	0
Password protected	1
Read-only recommended	2
Read-only enforced	3
Locked for annotations	4


OLE Custom Interfaces

As an OLE developer, you implement and use objects that are based on the Component Object Model (COM). COM interfaces specify a contract between the interface implementor and its user. The contract applies to every COM object that supports that interface.

OLE provides a standard set of interfaces, but these OLE-provided interfaces may not be perfectly suited to your needs. Through custom interfaces, you can create new ones tailored to fulfill the specific needs of your application. Custom interfaces are extensions to the COM standard; they let you extend the standard behavior and still take advantage of the services provided by the base interface. Like all COM interfaces, custom interfaces derive from the IUnknown interface and must contain the three methods of IUnknown. Otherwise, they can support a wide range of methods and parameters. (Note that, currently, custom interfaces cannot include asynchronous methods. Asynchronous methods may be supported in future versions of OLE.)

Once the interface is written, anyone can use it. Calls to methods in COM interfaces can cross process boundaries as long as both processes are running on the same machine.

This appendix introduces custom interfaces and explains how to implement them. OLE experience is a prerequisite, as is a basic knowledge of RPC. For more information about OLE and COM technology, see the OLE Reference Guide and the other parts of this OLE Programmer's Guide. Refer to the RPC Programmer's Guide and Reference for information about the RPC programming environment.


How Do Client/Server Objects Work?

A client application, such as a compound document container, makes a call to methods in a COM interface. An object application (sometimes called the server) implements an object that provides the interface and methods that are called by the client. A reference to the object application is stored in the registry. OLE locates the object application through this reference and runs it.

The object application is a piece of code that implements one or more COM interfaces. It can be an in-process server in a DLL or a local executable that runs in another process. Making a call to an interface method in an object in another process involves the cooperation of several components. The standard proxy is a piece of interface-specific code that resides in the client's process space and prepares the interface parameters for transmittal. It packages, or marshals, them in such a way that they can be re-created and understood in the receiving process. The standard stub, also a piece of interface-specific code, resides in the server's process space and reverses the work of the proxy. The stub unpackages, or unmarshals, the sent parameters and forwards them to the object application. It also packages reply information to send back to the client.

Note  Readers more familiar with RPC than OLE may be used to seeing the terms client stub and server stub. These terms are analogous to proxy and stub.

The following diagram shows the flow of communication between the components involved. On the client side of the process boundary, the client's method call goes through the proxy and then onto the channel. Note that the channel is part of the COM library. The channel sends the buffer containing the marshalled parameters to the RPC run-time library, which transmits it across the process boundary. The RPC run-time and the COM libraries exist on both sides of the process. Note also that the distinction between the channel and the RPC run-time is a characteristic of this implementation and is not part of the programming model or the conceptual model for OLE client/server objects. OLE object applications see only the proxy or stub and, indirectly, the channel. Future implementations may use different layers below the channel or no layers.

The following sections discuss some of the issues involved in Custom Interface technology and describe these components in greater detail.


Connecting to the Object Application

An internal OLE component ensures that when a client request is made, the appropriate object is connected and ready to receive the request. OLE keeps a database of class information based on the system registry that the client caches locally through the COM library.

When the server is an in-process DLL, OLE simply passes the name of the DLL to the COM library. The COM library then loads the server and makes the method call. When the server is an executable in another process, OLE either creates the server process and starts the server or contacts it directly if it is already running.


Marshalling

Marshalling is the process of packaging and unpackaging parameters so a remote procedure call can take place. Different parameter types are marshalled in different ways. For example, marshalling an integer parameter involves simply copying the value into the message buffer (although even in this simple case, there are issues such as byte ordering to deal with with cross-machine calls). Marshalling an array, however, is a more complex process. Array members are copied in a specific order so that the other side can reconstruct the array exactly. When a pointer is marshalled, the data that the pointer is pointing to is copied following rules and conventions for dealing with nested pointers in structures. Unique functions exist to handle the marshalling of each parameter type.

There are two types of OLE marshalling: standard and custom.

With standard marshalling, the proxies and stubs are system-wide resources for the interface, and they interact with the channel through a standard protocol. Standard marshalling can be used by both standard OLE interfaces and custom interfaces:

•	In the case of most OLE interfaces, the proxies and stubs for standard marshalling are themselves in-process component objects which are loaded from a system-wide DLL provided by OLE, OLE32.DLL.

•	In the case of custom interfaces, the proxies and stubs for standard marshalling are generated by the interface designer, typically with MIDL. These proxies and stubs are statically configured in the registry, so any potential client can use the custom interface across process boundaries. These proxies and stubs are loaded from a DLL that is located via the system registry using the interface ID (IID) for the custom interface they marshal.

Standard marshalling is the default method for the provision of marshalling code when passing interface pointers. However, because multiple objects may implement a single interface any number of ways, standard marshalling may not be sufficient for a particular implementation. Therefore, any object may override the default and provide custom marshalling for its interfaces. Other implementations of the interface are not affected.

As an alternative to standard marshalling, an interface (standard or custom) can use custom marshalling. With custom marshalling, an object dynamically implements the proxies at run-time for each interface that it supports. For any given interface, the object can select OLE-provided standard marshalling or custom marshalling. This choice is made by the object on an interface by interface basis. Once the choice is made for a given interface, it remains in effect during the object's lifetime. However one interface on an object can use custom marshalling while another uses standard marshalling.

Custom marshalling is inherently unique to the object application that implements it. It uses proxies implemented by the object and provided to the system on request at run-time. Objects that custom-marshal must implement the IMarshal interface, whereas objects that support standard marshalling do not. For complete documentation of the IMarshal interface, see the OLE Reference Guide. Also, see the chapter "The Component Object Model" for more information on marshalling.

Marshalling support is provided by the system for all OLE-defined interfaces. This support is via component objects in the file OLE32.DLL. If you decide to write a custom interface, you must provide marshalling support for it. Typically, you will provide a standard marshalling DLL for the interface you design. You can use the tools contained in the Win32 SDK CD to create the proxy/stub code and the proxy/stub DLL.


Proxy

A proxy resides in the address space of the calling process and acts as a surrogate for the remote object. From the perspective of the calling object, the proxy is the object. Typically, the proxy's role is to package the interface parameters for calls to methods in its object interfaces. The proxy packages the parameters into a message buffer and passes the buffer onto the channel, which handles the transport between processes. The proxy is implemented as an aggregate, or composite, object. It contains a system-provided, manager piece called the proxy manager and one or more interface-specific components called interface proxies. The number of interface proxies equals the number of object interfaces that have been exposed to that particular client. To the client complying with the component object model, the proxy appears to be the real object.

Note  With custom marshalling, the proxy can be implemented similarly or it can communicate directly to the object without using a stub.

Each interface proxy is a component object that implements the marshalling code for one of the object's interfaces. The proxy represents the object for which it provides marshalling code. Each proxy also implements the IRpcProxyBuffer interface. Although the object interface represented by the proxy is public, the IRpcProxyBuffer implementation is private and is used internally within the proxy. The proxy manager keeps track of the interface proxies and also contains the public implementation of the controlling IUnknown interface for the aggregate. Each interface proxy can exist in a separate DLL that is loaded when the interface it supports is materialized to the client.

The following diagram shows the structure of a proxy that supports the standard marshalling of parameters belonging to two interfaces: IFoo1 and IFoo2. Each interface proxy implements IRpcProxyBuffer that is used for internal communication between the aggregate pieces. When the proxy is ready to pass its marshalled parameters across the process boundary, it calls methods in the IRpcChannelBuffer interface, which is implemented by the channel. The channel in turn forwards the call to the RPC run-time library so that it can reach its destination in the object.


Stub

The stub, like the proxy, is made up of one or more interface pieces and a manager. Each interface stub provides code to unmarshal the parameters and code that calls one of the object's supported interfaces. Each stub also provides an interface for internal communication. The stub manager keeps track of the available interface stubs.

There are, however, some differences between the stub and the proxy:

•	The most important difference is that the stub represents the client in the object's address space.

•	The stub is not implemented as an aggregate object since there is no requirement that the client be viewed as a single unit; each piece in the stub is a separate component.

•	The interface stubs are private, rather than public.

•	The interface stubs implement IRpcStubBuffer, not IRpcProxyBuffer.

•	Instead of packaging parameters to be marshalled, the stub unpackages them after they have been marshalled and then packages the reply.

The following diagram shows the structure of the stub. Each interface stub is connected to an interface on the object. The channel dispatches incoming messages to the appropriate interface stub. All the components talk to the channel through IRpcChannelBuffer, the interface that provides access to the RPC run-time library.


Channel

The channel has the responsibility of transmitting all messages between client and object across the process boundary. The channel has been designed to work transparently with different channel types, is compatible with OSF DCE standard RPC, and supports single and multi-threaded applications.


Microsoft RPC

RPC is a model for programming in a distributed computing environment. The goal of RPC is to provide transparent communication so that the client appears to be directly communicating with the server. Microsoft's implementation of RPC is compatible with the Open Software Foundation (OSF) Distributed Computing Environment (DCE) RPC.

You can configure RPC to use one or more transports, one or more name services, and one or more security servers. The interface to those providers are handled by RPC. Because Microsoft RPC is designed to work with multiple providers, you can choose the providers that work best for your network. The transport is responsible for transmitting the data across the network. The name service takes an object name, such as a moniker, and finds its location on the network. The security server offers applications the option of denying access to specific users and/or groups. Refer to the next section "Writing a Custom Interface" for more detailed information about application security.

In addition to the RPC run-time libraries, Microsoft RPC includes the Interface Definition Language (IDL) and its compiler. Although the IDL file is a standard part of RPC, Microsoft has enhanced it to extend its functionality to support custom COM interfaces. The Microsoft Interface Definition Language (MIDL) compiler uses the IDL file that describes your custom interface to generate several files discussed in the section "Building a Proxy/Stub DLL".


Writing a Custom Interface

In order to perform the tasks discussed in the following section, you must obtain a Microsoft Win32 Software Development Kit (SDK). It contains a toolkit and all of the libraries you need for building a custom interface project. It provides more detailed information about how to write a custom interface using the MIDL compiler.

After installing the toolkit, you can design and write your custom interface using the MIDL compiler, and build the standard-marshalling proxy/stub DLL for your interface from the files generated by the compiler. You will then install the DLL in the system registry.


Designing Efficient Interfaces

There are some special considerations to keep in mind when designing a custom interface. If you follow these guidelines, your marshalling code can be used across the network when support for remotable objects is provided in a future release.

First of all, because data is shipped across address spaces, using architecture-dependent types such as int may prohibit the data from being re-created correctly in the object application's address space. The size of an integer varies from architecture to architecture. Thus, the data type int should not be used for structure data members or interface method parameters. Specifying data types unambiguously to the MIDL compiler will allow your interface to be more easily transferred to remote machines with different architectures and addressing schemes. The MIDL compiler requires all integer variables that may be remoted to be explicitly declared as short, long, or their unsigned equivalents.

A frequently used data type for pointers, the void * construct, allows the callee of a method to interpret the data pointed to according to the need. While local interfaces can use this construct, distributed applications cannot. This is because the MIDL compiler must know exactly what types of data are being transmitted so that the data can be accurately re-created on the receiving side. The void * construct is too vague.

Pointers to data must be used carefully. To re-create the data in the callee's address space, RPC must know the exact size of the data. If, for example, a char * parameter points to a buffer of characters rather than to a single character (as is implied), the data cannot be correctly re-created. Use the syntax available with MIDL to accurately describe the data structures represented by your type definitions.

Initialization is essential for pointers that are embedded in arrays and structures and passed across process boundaries. Uninitialized pointers may work when passed to a program in the same process space, but proxies and stubs assume that all pointers are initialized with valid addresses or are null.

Be careful when aliasing pointers (allowing pointers to point to the same piece of memory). If the aliasing is intentional, these pointers should be declared aliased in the IDL file. Pointers declared as non-aliased should never alias each other.

The MIDL has directional attributes that let you specify the data flow direction. The proxies and stubs use these attributes to determine whether to send the data from the client to the object or from the object to the client, respectively. Data labeled as out only is uninitialized on the way to the interface stub; data labeled as in only does not affect the data structures upon return. The in, out attribute indicates that data is sent to the object initialized and the object will change it before sending it back.

It is also imperative to realize the importance of defining status codes. This must be coordinated by the definer of the interface to avoid conflicting error codes.

Finally, the designer of an interface must develop an understanding of how the interface will be used by client applications. In particular, the frequency of method calls across the interface boundary and the amount of data to be transferred to complete a given method call together determine whether the interface will be efficient across process and machine boundaries. Although OLE makes cross-process and, eventually, cross-network calls transparent to programs, it cannot make high-frequency and high-bandwidth calls efficient across address spaces. In some cases, it is more appropriate to design interfaces that will normally be implemented only as in-process servers while other interfaces are more appropriate for remote use.


Creating a Custom Interface

Writing an application using a custom interface is similar to writing an OLE application using standard interfaces, with two important differences. First, in addition to registering the class identifier (CLSID) for your object, you also must register the unique interface identifier (IID) for your custom interface. Second, you must provide OLE with proxy and stub components capable of remoting the interface. In most cases, you will use the MIDL compiler to generate code to create the proxy/stub DLL for your custom interface.

As an OLE developer, you should already be familiar with the concept of using CLSIDs and interface identifiers (IIDs) to uniquely identify class objects and interfaces. The MIDL compiler refers to universally unique identifiers (UUIDs) and uses UUIDs to uniquely represent its interfaces. In this case, a UUID is the same as an IID. Every custom interface must have a IID; the UUIDGEN.EXE tool provided with the toolkit can create one for you.

MIDL is a rich, complex language that allows you to define interface parameters carefully in terms of their direction and type. Although the MIDL compiler offers much, you will need only a small subset of its attributes to define your interface.

The IDL file consists of two parts: the interface header and the interface body. The interface header, delimited by brackets, contains information about the interface as a whole, such as its IID. A prerequisite to completing the interface header is running the RPC utility UUIDGEN.EXE to create the IID. Because IIDs must be unique, never reuse one of them by copying it from one IDL file to another. The header also contains the keyword object, indicating that this interface is a COM-style interface (that is, derived from IUnknown). Whereas standard RPC interfaces have the version attribute in their interface headers, object interfaces do not.

The following excerpt is from an actual IDL file:

[

    object,

    uuid(7ACC12C3-C4BB-101A-BB6E-0000C09A6549),

    pointer_default(unique)

]

The uuid attribute precedes the unique identifier for the interface. The pointer_default attribute specifies the default IDL type for all pointers except for those included in parameter lists. Parameter list pointers must be explicitly declared with the pointer attribute. The default pointer type may either be unique, ref, or ptr. For more information on using IDL with pointers, see the RPC Programmer's Guide and Reference.

The interface body contains declarations for data members, prototypes for all methods, and other information such as directives to the preprocessor and include statements for other IDL files. The following example is the interface body for ICustomInterface:

interface ICustomInterface : IUnknown

{

    import "unknwn.idl";

    HRESULT CustomReport(void);

}

The import attribute allows an interface to reference constructs defined in other IDL files. Because ICustomInterface derives from IUnknown, the UNKNWN.IDL file must be included. ICustomInterface has only one method that takes no parameters; few interfaces will be this simple.


Building a Proxy/Stub DLL

Completed IDL files must be compiled with the IDL compiler, MIDL.EXE. The IDL compiler takes each IDL file and generates proxy/stub code (IDLNAME_P.C), an interface header file (IDLNAME.H), and an interface identifier file (IDLNAME_I.C). The header files contain both C and C++ class definitions.

By default, MIDL.EXE generates names based on your IDL file's name. However, you can use the following command line switches to override the default:

Command line switch	Description
-header	Specifies the name of the interface header file.
-proxy	Specifies the name of the proxy source file.
-iid	Specifies the name of the interface identifier file.
After a successful compile of the IDL file, the generated files are run through the standard C/C++ compile and link steps. These source files implement helper functions for marshalling and an implementation of DllGetClassObject for the proxy/stub libraries, among other things. Note that the RPC4RT.LIB library includes an implementation of the DllGetClassObject function. In this provided implementation, the CLSID of the proxy/stub has to be the same as the IID of your custom interface. If you want to use a CLSID that differs from the IID then you must provide your own implementation of the DllGetClassObject function.

The following diagram shows all the pieces involved in a build of a custom proxy/stub DLL. The IDL file, ITF.IDL, is fed into the IDL compiler. Three files are generated: ITF_P.C, ITF.H, and ITF_I.C. These three files are compiled and linked and the result is PROXSTUB.DLL.


Registering a Proxy/Stub DLL

Before a client can use your custom interface, the proxy/stub DLL for the interface must be installed in the system registry. Registering the proxy/stub DLL involves creating a .REG file and running REGINI. In the following entries, notice that the IID for ICustomInterface is the same as the CLSID for the proxy/stub DLL.

 \Registry\MACHINE\SOFTWARE\Classes\Interface\

{7ACC12C3-C4BB-101A-BB6E-0000C09A6549}

    = ICustomInterface

\Registry\MACHINE\SOFTWARE\Classes\Interface\

{7ACC12C3-C4BB-101A-BB6E-0000C09A6549}\ProxyStubClsid32

    = {7ACC12C3-C4BB-101A-BB6E-0000C09A6549}

\Registry\MACHINE\SOFTWARE\Classes\CLSID\

{7ACC12C3-C4BB-101A-BB6E-0000C09A6549}

    = ICustomInterface_PSFactory

\Registry\MACHINE\SOFTWARE\Classes\CLSID\

{7ACC12C3-C4BB-101A-BB6E-0000C09A6549}\InprocServer32

    = proxstub.dll


Using a Custom Interface

The client code is the user of the custom interface. To use any interface, custom or standard, a client must know its IID. In the following function, CustomRpt, the driver that calls CustomRpt passes it the name of the object that is converted to a wide-character format. The object name is fed to CreateFileMoniker so that a file moniker can be created and the client can bind to the running object. Once the object is running, CustomRpt can access a pointer to either an interface in the standard proxy/stub, such as IPersistFile, or to the custom interface, ICustomInterface.

void CustomRpt(char *pszObject)

{

    HRESULT          hr;

    WCHAR	       	    szObject[128];

    WCHAR               wszMsg[128] = {L"Your Message Here...\n"};

    IMoniker	             *pmkObject = NULL;

    IUnknown            *pIUnk = NULL;

    IPersistFile        *pIPersistFile = NULL;

    ICustomInterface   	*pICustomInterface = NULL;

    // Create a wide-character version of the object's file name.

    wsprintf(wszObject, L"%hs", pszObject);

    // Get a file moniker for the object (a *.smp file).

    hr = CreateFileMoniker(wszObject, &pmkObject);

    if(FAILED(hr))

    {

    printf("Client: CreateFileMoniker for Object failed");

    return;

    }

    // BindMoniker is equivalent to calling CreateBindCtx() followed by

    // a call to BindToObject(). It has the net result of binding the

    // interface (specified by the IID) to the moniker.

    hr = BindMoniker(pmkObject, 0, IID_IUnknown, (void **)&pIUnk);

    if (FAILED(hr))

    {

    printf("Client: BindMoniker failed (%x)\n", hr);

    return;

    }

    // Try a couple QueryInterface calls into the object code, first a

    // QueryInterface to IPersistFile...

    hr = pIUnk->QueryInterface(IID_IPersistFile,

       (void **)&pIPersistFile);

    if (FAILED(hr)) {

        printf("Client: QueryInterface IPersistFile failed (%x)\n", hr);

        pIUnk->Release();

        return;

    }

    // Followed by a QueryInterface to ICustomInterface.

    hr = pIUnk->QueryInterface(IID_ICustomInterface,

                    (void **)&pICustomInterface);

    if (FAILED(hr)) {

        printf("Client: QueryInterface failed (%x)\n", hr);

        pIUnk->Release();

        pIPersistFile->Release();

        return;

    }

    // CustomReport() is the object function that displays the time and

    // date information on the object.

    hr = pICustomInterface->CustomReport();

    if (FAILED(hr))

    {

        printf("Client: pICustomInterface->CustomReport failed (%x)\n",

             hr);

        pIUnk->Release();

        pIPersistFile->Release();

        return;

    }

    // Clean up resources by calling release on each of the interfaces.

    pIPersistFile->Release();

    pICustomInterface->Release();

    pIUnk->Release();

    return;

}


Programming Considerations

While detailed application-specific information is beyond the scope of this appendix, this section contains some helpful guidelines for developing OLE applications.


Designing Component Objects

Component objects contain data specific to the object and one or more interface implementations. The data is private and inaccessible from outside the object, while the interface implementations are public and you can access them through pointers.

Because interfaces are a binary standard, interface implementation is language independent. However, C++ is the preferred language because it supports many of the object-oriented concepts inherent in OLE. Using a procedural language such as C involves extra work, as summarized below:

·	You must explicitly initialize VTBLs either at compile-time or run-time and you should not change them later. Once initialized with function pointers, those pointers should remain unchanged until the application shuts down. VTBLs in C++ are declared as constants to prevent them from being modified inadvertently. However, in C there is no way to ensure that a VTBL will remain unchanged.

To overcome this difference, OLE provides a mechanism that lets C developers declare VTBLs as constants. To do so, place the following statement before the #include statement for the "ole2.h" header file:

#define CONST_VTABLE

·	Each method requires a pointer to the object that owns the method. In C++, all members are implicitly dereferenced off the this pointer. In C, there must be an additional first parameter passed to each method that is a pointer to the interface in which the method is declared.

·	Methods in C++ can have identical names because methods are actually known by a name that is the result of concatenating the method name to the class name. Methods in C must have a unique name to designate the object with which they are associated.

For example, the following C++ code sample defines an implementation of IUnknown::QueryInterface. The method name is QueryInterface and there are two parameters: a REFIID and a pointer to where to return the requested interface instance.

CUnknown::QueryInterface (REFIID riid, LPVOID * ppvObj);

A similar C implementation would require a more complex name and an additional first parameter to indicate the object owning the method:

IUnknown_Doc_QueryInterface (LPUNKNOWN pUnk, REFIID riid,

LPVOID * ppvObj);

The following sections demonstrate how to declare a component object in a few typical ways: using C nested data structures, C++ nested classes, and C++ multiple inheritance. The demonstration object, called CObj, derives from IUnknown and supports two interfaces that also derive from IUnknown, InterfaceA and InterfaceB. CObj's private data includes a pointer to another component object in the application (m_pCDoc), a count of all the external references to the object (m_ObjRefCount), and pointers to two interfaces implemented by other component objects and used by CObj (m_pOleObj and m_pStg). All object members use the m_ prefix to make it easy to distinguish between member variables and other variables.


Component Objects: C Nested Structures

C interface implementations comprise data structures nested within the object's data structure. Each interface structure contains a VTBL pointer as its first member (pVtbl), a pointer to the object (pCObj), and a count of the external references to the interface (m_RefCount). The order of the members in the interface structures is identical, to facilitate code sharing.

typedef struct CObj {

  ULONG            m_ObjRefCount;

  LPSTORAGE        m_pStg;

  LPOLEOBJECT      m_pOleObj;

  struct CDOC    *  m_pCDoc;

  struct InterfaceA  {

    LPVTBL        pVtbl;

    struct CObj  *  pCObj;

    ULONG        m_RefCount;

  } m_InterfaceA;

  struct InterfaceB {

    LPVTBL       pVtbl;

    struct Obj  *    pCObj;

    ULONG        m_RefCount;

  } m_InterfaceB;

} COBJ;


Component Objects: C++ Nested Classes

The next example shows how the same object is declared and initialized using the C++ nested class approach. As in the C example, the nested class declaration includes one data structure for each interface and four private data members: an object-level reference count, two interface pointers, and a pointer to the enclosing object. The private implementations of the IUnknown methods are called by the implementations declared for the derived interfaces. For each interface implementation, there is a structure containing a public constructor and destructor, private declarations of the interface methods, a private pointer to CObj, and an interface-level reference counter for debugging purposes. To allow the nested interface classes to access the private members of the outer class, each interface class is made a friend of the outer class.

The benefits of implementing with C++ nested classes lie in the ability to include initialization code and method implementation inline. However, inline declaration is for the convenience of illustration and is not required.

class  CObj  {

private:

  ULONG          m_ObjRefCount;

  LPSTORAGE      m_pStg;

  LPOLEOBJECT    m_pOleObj;

  CDOC    *      m_pCDoc;

public:

  CObj();

  ~CObj();

  struct CUnknown : IUnknown

{

  private:

  ULONG          m_RefCount;

  CObj  *        m_pCObj;

  public:

  CUnknown(CObj (pCObj)

  { m_pCObj = pCObj; m_RefCount = 0; }

  HRESULT QueryInterface(REFIID riid, LPVOID  * ppvObj)

  ULONG AddRef(void) { return ++m_ObjRefCount; }

  ULONG Release(void);

}

friend CUnknown;

CUnknown m_Unknown;

struct InterfaceA : InterfaceA

{

  private:

  ULONG          m_RefCount;

  CObj  *        m_pCObj;

  public:

  CInterfaceA(CObj *pCObj)

  { m_pCObj = pCObj; m_RefCount = 0; }

  HRESULT QueryInterface(REFIID riid, LPVOID  * ppvObj)

  ULONG AddRef(void) { return ++m_ObjRefCount; }

  ULONG Release(void);

  HRESULT MethodA1(LPVOID  * ppvObj);

  HRESULT MethodA2(DWORD dwArg);

}

friend CInterfaceA;

CInterfaceA m_InterfaceA;

struct InterfaceB : InterfaceB

{

  private:

  ULONG          m_RefCount;

  CObj  *        m_pCObj;

  public:

  CInterfaceB(CObj *pCObj)

  { m_pCObj = pCObj; m_RefCount = 0; }

  HRESULT QueryInterface(REFIID riid, LPVOID  * ppvObj)

  ULONG AddRef(void) { return ++m_ObjRefCount; }

  ULONG Release(void);

  HRESULT MethodB1(void);

  HRESULT MethodB2(DWORD dwArg1, DWORD dwArg2);

}

friend CInterfaceB;

CInterfaceB m_InterfaceB;


Multiple Inheritance

The next example illustrates the use of C++ multiple inheritance. There are two disadvantages to using multiple inheritance with OLE. First, it is not possible to have an interface-level reference count. For more information about reference counting, see Chapter 2, "The Component Object Model." Second, there is the potential for confusion over the interpretation of the class statement. A standard C++ multiple inheritance declaration implies the "is a" relationship where an object inherits implementations. In OLE, however, interfaces are attributes of the object and implementations are not inherited.

The main advantage to using multiple inheritance lies in its simplicity. Only the prototypes for each of the interface methods are listed; no interface data structures or class definitions are necessary.

Because both InterfaceA and InterfaceB inherit from IUnknown, it is not necessary to list IUnknown explicitly in the class statement. A single implementation of the IUnknown methods (QueryInterface, AddRef, and Release) is sufficient.

class  CObj : public InterfaceA, public InterfaceB

{

private:

  ULONG          m_ObjRefCount;

  LPSTORAGE      m_pStg;

  LPOLEOBJECT    m_pOleObj;

  CDOC  *        m_pCDoc;

public:

  CObj();

  ~CObj();

  HRESULT QueryInterface(REFIID riid, LPVOID  * ppvObj)

  ULONG AddRef(void) { return ++m_ObjRefCount; }

  ULONG Release(void);

  HRESULT MethodA1(LPVOID  * ppvObj);

  HRESULT MethodA2(DWORD dwArg);

  HRESULT MethodB1(void);

  HRESULT MethodB2(DWORD dwArg1, DWORD dwArg2);

};


Aggregating Objects

An aggregate is an object like any other object in that it implements one or more interfaces. Internal to the aggregate, the implementation of certain interfaces is actually provided by one or more contained objects. Users of the object are unaware of this internal structure. They cannot tell and do not care that the object is an aggregate: aggregation is purely an implementation technique.

The figure below shows an aggregate object consisting of a control object that implements Interface A and Interface B, and a noncontrol object that implements Interface C. All these interface implementations are exposed publicly, as indicated by the line and circle extending to the outside of the aggregate.

In the aggregation model, the control object determines how an aggregate behaves and operates, making decisions about which interfaces are exposed outside of the object and which interfaces remain private. The control object has a special instance of the IUnknown interface known as the controlling unknown. The controlling unknown must always be implemented as part of the new code written when the aggregate is put together from other objects. However, when the controlling unknown is passed in, it does not increment the reference count; instead it is a non-incrementing pointer.

The other objects can be implemented at any time. These noncontrol objects can be instantiated separately or as part of the aggregate. However, if these objects are to be capable of aggregation, they must be written to cooperate with the control object by forwarding their QueryInterface, AddRef, and Release calls to the controlling unknown. A reference count for the aggregate as a whole is maintained by the control object so that it is kept alive if there are one or more references to any of the interfaces supported by either the control or noncontrol objects.

It is possible for an object to call a method that may cause the object to be released. A technique known as "artificial reference counting" can be used to guard against this untimely release. The object calls IUnknown::AddRef before the potentially destructive method call and IUnknown::Release after it. If the object in question can be aggregated, it must call the controlling unknown's implementations of AddRef and Release (pUnkOuter->AddRef and pUnkOuter->Release) to artificially increment the reference count rather than its own implementations. For more information about reference counting, see Chapter 2, "The Component Object Model."

The next figure shows how the coordination between the control and noncontrol object works. The control object exposes the controlling unknown, Interface A and Interface B. The noncontrol object supports IUnknown and Interface C. All three interfaces derive from IUnknown.

The control object holds a pointer to the noncontrol object's IUnknown implementation so it can call the noncontrol methods when appropriate. The noncontrol object holds a pointer to the controlling unknown for the same reason. The pointer to the controlling unknown is supplied when the noncontrol object is instantiated. When the controlling unknown pointer is saved by the noncontrol object, AddRef is not called to increment the reference count as you might expect. This is because of the reference-counting cycle it would create. Instead, the noncontrol object just keeps a copy of the pointer and delegates calls to it as described in this section.

Referring again to the next figure, whereas the controlling unknown is available to the outside, as is indicated by the line and circle identifying it extending past the bounds of the aggregate, the noncontrol object's IUnknown implementation works locally and can't be obtained from outside the aggregate. It is called solely by the controlling unknown to obtain instances of the noncontrol interfaces, such as Interface C, to expose to the outside.


Aggregation and Cached Interface Pointers

Interface-based reference counting has generally been a preferable way of keeping OLE objects stable, although 16-bit aggregates have proven troublesome. However, 32-bit OLE applications can overcome this difficulty with relative ease. For example, when a control object holds an interface pointer to a noncontrol object and the reference count has not been incremented, the pointer is said to be cached. In 16-bit OLE applications, this is achieved by calling QueryInterface to get the cached pointer and then releasing it in the following manner:

// 16-bit method for caching pointers to interfaces on noncontrol

// objects

IInterface1 *m_pi1;

m_pUnkInner->QueryInterface(IID_Interface1, &m_pi1);

m_pi1->Release();

To facilitate the use of per-interface reference counting in 32-bit OLE, the method for caching interface pointers has changed, as shown in the following:

// 32-bit method for caching pointers to interfaces on noncontrol

// objects.

IInterface1 *m_pi1;

m_pUnkInner->QueryInterface(IID_Interface1, &m_pi1);

m_pUnkOuter->Release();	\\ Uses the same m_pUnkOuter given to 	\\ the aggregated object.

The difference is in the third line of code. Furthermore, when a cached pointer is released, include the following lines (no equivalent actions are done for 16-bit applications at the same point):

m_pUnkOuter->Addref();

m_pi1->Release();

Note  These two approaches are not compatible; all 16-bit aggregate control objects must use the first method and all 32-bit aggregate control objects must use the second one.

Note that interface-based reference counting works best when control objects delay the acquisition of cached pointers and release them when there is no possible use for them.

During the destruction of any aggregate, even those in which the control object does not cache pointers, the control object must guard the destructor by means of artifical reference counting, as shown below:

ULONG Release_ObjectXXX(ObjectXXX *this)

{

if(- -this->m_refs;

{

++this->m_refs;

...destroy the instance..

return 0;

}

return this->m_refs;

}

This code must be included because the sequence m_pUnkOuter->AddRef() followed by m_pi1->Release increments and decrements the reference count of the aggregate as a whole. Since this may occur in the destruction of the aggregate itself, the destructor must be guarded.

Note  You cannot use this technique for noncontrol objects to hold cached pointers to objects higher up in the aggregate. The noncontrol object has no way of determining whether it has the same pUnkOuter as any other object in the aggregate. Although this is usually the case, it cannot be guaranteed.

Aggregation is entirely optional, and you should decide whether to use it as you design each object. However, providing support for aggregation costs little in time and complexity. The reward is larger than the cost in that aggregation enables the effective re-use of interface implementations. The key in implementing an aggregate object is making the correct delegation decision in both the aggregated and non-aggregated situations.

The following code example is an aggregate object implemented using C++ nested classes. The constructor takes as an argument the pointer to the control object's IUnknown implementation, or controlling unknown. If this pointer is NULL, indicating that the new object is not being aggregated, the m_pUnkOuter member is set to the address of m_Unknown, the local implementation of IUnknown. If pUnkOuter is not NULL, indicating that the new object is being aggregated, m_pUnkOuter is set to pUnkOuter. The Interface A implementations of the IUnknown methods forward their calls to the controlling unknown implementations. The controlling unknown IUnknown implementation manages queries for interfaces for the aggregate and maintains a master reference count.

class CAggregateObj

{

public:

  static HRESULT CreateObj(LPUNKNOWN pUnkOuter, REFIID riid,

        LPVOID  * ppvObj)

  {

    HRESULT hr;

    CAggregateObj *pObj = new CAggregateObj(pUnkOuter);

    if (pObj == NULL)

    {

      *ppvObj = NULL;

      return E_OUTOFMEMORY;

    }

    if ((hr = pObj->m_Unknown.QueryInterface(riid, ppvObj)) !=             NOERROR)

          // QI call above will set *ppvObj on success

          // and NULL it on error

delete pObj;

    return hr;

  }

private:

  CAggregateObj(LPUNKNOWN pUnkOuter)

    : m_Unknown(this), m_InterfaceA(this)

  {

    if (pUnkOuter == NULL)

          // not aggregated; make like the

          // aggregated case

      pUnkOuter = &m_Unknown;

    m_pUnkOuter = pUnkOuter;

    m_cRefs = 0;

  }

  ~CAggregateObj();

  struct CUnknown : IUnknown

  {

    CUnknown(CAggregateObj  * pAgg)

    { m_pAgg = pAgg; }

    HRESULT QueryInterface(REFIID riid, LPVOID  * ppvObj);

    ULONG AddRef(void)

    { return ++m_pAgg->m_ObjRefCount; }

    ULONG Release(void)

    {

      if (--m_pAgg->m_cRefs  == 0)

      {

          // don't need guard here since this object

          // doesn't aggregate another one

        delete m_pAgg;

        return 0;

      }

      return m_pAgg->m_cRefs;

    }

    private:

    CAggregateObj  * m_pAgg;

  }

  friend CUnknown;

  CUnknown m_Unknown;

  struct CInterfaceA : InterfaceA

  {

    CInterfaceA(CAggregateObj  * pAgg)

    { m_pAgg = pAgg; }

    HRESULT QueryInterface(REFIID riid, LPVOID  * ppvObj)

    { return m_pAgg->m_pUnkOuter->QueryInterface(riid, ppvObj); }

    ULONG AddRef(void)

    { return m_pAgg->m_pUnkOuter->AddRef(); }

    ULONG Release(void)

    { return m_pAgg->m_pUnkOuter->Release(); }

    HRESULT MethodA1(LPVOID  * ppvObj);

    HRESULT MethodA2(DWORD dwArg);

    private:

    CAggregateObj  * m_pAgg;

  }

  friend CInterfaceA;

  CInterfaceA m_InterfaceA;

private:

  ULONG      m_cRefs;

  LPUNKNOWN    m_pUnkOuter;

}


Grouping Interfaces

Interface relationships are based on the ability to successfully obtain interface pointers by using IUnknown::QueryInterface. Although interface implementors are advised to design objects in such a way that interfaces are accessible from many other interfaces, there is generally no guarantee to a user that a specific interface is accessible from another interface. Implementations of QueryInterface are application-specific, so it usually cannot be assumed that it returns a pointer to another specific interface.

Two interfaces can be related in one of three possible ways. Each of these is set forth in the following list, using Interfaces named A and B as examples. Notice the importance of reference counting in managing the three types of relationships.

1.	Given a pointer to Interface A, it should be possible to obtain a pointer to Interface B. Interface A and Interface B are managed by a single reference count. OLE defines the following interfaces that fall in this category:

·	IOleObject, IDataObject, IViewObject, IOleCache, IOleInPlaceObject, and IPersistStorage. If the object is a link, IOleLink should also be available.

·	IPersistFile and IOleItemContainer

·	IOleClientSite and IOleInPlaceSite

2.	Given a pointer to Interface A, it must not be possible to obtain a pointer to Interface B. Interface A and Interface B can be managed by either a single reference count or separate reference counts. IOleInPlaceActiveObject and IOleInPlaceObject fall in this category. IStorage and IStream, typically implemented by OLE, also fall in this category, simply because they point to different objects.

3.	Given a pointer to Interface A, it might be possible to obtain a pointer to Interface B, depending on the implementing application. Interface A and Interface B can be managed by a single reference count. Clients of the interfaces cannot assume it is always possible to obtain the same set of interfaces in this category from all implementing applications. The decision to group these interfaces is up to the implementor, and there is no guarantee they will be implemented in the same manner by all applications.

All OLE interfaces not specifically mentioned as belonging to the first or second groups belong to the third type. These interfaces can be grouped in a manner that works best for the application. It is wise to implement interfaces together whenever possible, because doing so leads to greater flexibility and interconnectivity. Implementing interfaces together implies they are within a single object supported by one piece of memory. The interfaces share one IUnknown::QueryInterface implementation that recognizes all related interfaces. Pointers to the interfaces are managed by a single reference count.

An object that has multiple groups of interfaces, each managed by its own reference count, is kept alive if there is at least one reference to any interface in one of the groups.

There are two possible approaches to interfaces that cannot be implemented together. They can be implemented either in separate objects, or in a single object that manages the interfaces independently. In the single object approach, there can be one IUnknown::QueryInterface implementation or several, depending on the number of interface groups in the object. In the single QueryInterface implementation, explicit steps must be taken to return pointers only to related interfaces.


Converting Mapping Modes

In Windows, mapping modes define how numbers relating to object sizes are to be passed and interpreted. The 32-bit version of OLE uses only one mapping mode, MM_HIMETRIC. The other Win32 mapping modes include MM_HIENGLISH, MM_LOENGLISH, MM_LOMETRIC, TWIPS, and PIXEL Modes (MM_ISOTROPIC and MM_ANISOTROPIC being PIXEL modes). When working with the visual presentation of OLE data, it is important to be aware of the mapping mode that OLE uses and how this mapping mode affects an application.

The mapping modes communicate physical sizes. For example, if an application using MM_HIMETRIC is to display a line ten centimeters long, the number of units would be 10,000. However, the line drawn on the screen would be ten centimeters long, regardless of the size of the video display area. The printed output would also be a line ten centimeters long.

Note  For those applications that use a mapping mode other than MM_HIMETRIC, the sample user interface library provides some functions that can be used to convert objects to and from MM_HIMETRIC units.

Because people read display screens from a greater distance than they do printed copy, most applications written for Windows display text in a larger size than they print it, using what is commonly referred to as logical resolution. For example, a ten-point font is easy enough to read on the printed page, but generally appears too small on a screen for comfortable reading. To afford more comfortable viewing, applications typically expand the size of the displayed text to some logical size. Using this approach, a column of text that is physically six inches wide might be eight inches wide on the screen, yet still print as a six-inch column.

While this display-enlargement scheme works well from the user's point of view, a problem can occur when pasting objects into container documents. It is possible to lose the correct size ratio between the pasted object and the text owned and displayed by the container. The result is that the container's text is scaled up for readability but the pasted object might not be. Consequently, applications must preserve the relative size and position of text and objects, meaning that if text uses logical resolution, it should scale objects accordingly.

In the examples shown in the figure below, a chart object has been pasted from a source application that uses physical size into documents of two different containers that use logical resolution for display of the text. The container displaying the object on the left has scaled up the chart object to the logical size of the adjacent text to maintain the object/text size ratio. That is, it has been enlarged from its physical size by an amount that maintains its proportion to the text of the container document. In the document on the right, the application displays the chart object at its physical size, with no scaling to logical resolution for display. Both documents print with the correct object-to-text-size ratio.

In OLE, the units for specifying the size of drawn objects is MM_HIMETRIC, which means object sizes are in physical units. However, containers need not use the MM_HIMETRIC mapping mode to draw pasted objects to the display. Rather, they should should map objects to the screen in the same manner as text. That is, if the container application displays text to the screen using a mapping mode that enlarges it, objects should be mapped to the display in the same manner. Using the same mapping mode for both the text and objects is required to establish the correct object-to-text ratio as shown in the document on the left side of the preceding figure. Because most Windows applications use logical resolution for this type of display mapping, we suggest that OLE containers also use logical resolution and set up their mapping modes and coordinate transforms accordingly. This allows objects to be moved from one application to another without changing their displayed size.


IAdviseSink

The IAdviseSink interface enables containers and other interested objects to receive notifications of data changes, view changes, and compound-document changes occurring in objects of interest. Container applications, for example, require such notifications to keep cached presentations of their linked and embedded objects up-to-date.

For an advisory connection to exist, the object that is to receive notifications must implement IAdviseSink, and the objects in which it is interested must implement one or more of the following: IOleObject::Advise, IDataObject::DAdvise, or IViewObject::SetAdvise. Objects implementing IOleObject must support all of these methods.

As shown in the following table, an object that has implemented an advise sink registers its interest in receiving certain types of notifications by calling the appropriate method:

Call This Method	To Register for These Notifications
IOleObject::Advise	When a document is saved, closed, or renamed.
IDataObject::DAdvise	When a document's data changes.
IViewObject::SetAdvise	When a document's presentation changes.
When an event occurs that applies to a registered notification type, the object application calls the appropriate IAdviseSink method. For example, when an embedded object closes, it calls the IAdviseSink::OnClose method to notify its container. These notifications are asynchronous, occurring after the events that trigger them

When to Implement

Objects, such as container applications, compound documents, and client sites implement IAdviseSink to receive notification of changes in data, presentation, name, or state of their linked and embedded objects. Implementors register for one or more types of notification, depending on their needs.

Notifications for an embedded object originate in the object application and flow to the container by way of the object handler. If the object is a linked object, the OLE link object intercepts the notifications from the object handler and notifies the container directly. All containers, the object handler, and the OLE link object register for OLE notifications. The typical container also registers for view notifications. Data notifications are usually sent to the OLE link object and object handler.

When to Use

Objects call IAdviseSink to notify other objects with whom they have an advisory connection of changes in data, view, name, or state.

Note  Making synchronous calls within asynchronous methods is not valid, so you cannot make synchronous calls within any of the the IAdviseSink interface's methods. For example, an implementation of IAdviseSink::OnDataChange cannot contain a call to IDataObject::GetData.

Methods in Vtable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments reference count.
Release	Decrements reference count.
IAdviseSink Methods	Description
OnDataChange	Advises that data has changed.
OnViewChange	Advises that view of object has changed.
OnRename	Advises that name of object has changed.
OnSave	Advises that object has been saved to disk.
OnClose	Advises that object has been closed.
See Also

IAdviseSink2, IDataAdviseHolder, IOleAdviseHolder, IOleObject::Advise, IOleObject::Unadvise, IOleObject::EnumAdvise


IAdviseSink::OnClose

Notifies all registered advisory sinks that the object has changed from the running to the loaded state.

Void OnClose();

Comments

OnClose notification indicates that an object is making the transition from the running to the loaded state, so that appropriate measures to ensure orderly shutdown should be taken. For example, an object handler must release its pointer to the object.

If the object that is closing is the last open object supported by its OLE server application, then the application can also shut down.

In the case of a link object, the notification that the object is closing should always be interpreted to mean that the connection to the link source has broken.


IAdviseSink::OnDataChange

Notifies a data object's currently registered advise sinks that data in the object has changed.

void OnDataChange(

FORMATETC * pFormatetc,	//Pointer to format information
STGMEDIUM * pStgmed	//Pointer to storage medium
);
Parameters

pFormatetc

[in] Points to the FORMATETC structure, which describes the format, target device, rendering, and storage information of the calling data object.

pStgmed

[in] Points to the STGMEDIUM structure, which defines the storage medium (global memory, disk file, storage object, stream object, GDI object, or undefined) and ownership of that medium for the calling data object.

Comments

Object handlers and link objects implement IAdviseSink::OnDataChange to receive data-change notifications. They also must call IDataObject::DAdvise to set up an advisory connection with the data objects in which they are interested. (See IDataObject::DAdvise for more information on how to specify an advisory connection for data objects.)

Containers that take advantage of OLE's caching support do not need to register for data-change notifications, because the information necessary to update the container's presentation of the object, including any changes in its data, are maintained in the object's cache.

Notes to Implementors

If you implement IAdviseSink::OnDataChange for a container, remember that this method is asynchronous and that making synchronous calls within asynchronous methods is not valid. Therefore, you cannot call IDataObject::GetData to obtain the data you need to update your object. Instead, you either post an internal message or invalidate the rectangle for the changed data by calling InvalidateRect and then wait for a WM_PAINT message, at which point you are free to get the data and update the object.

The data itself, which is valid only for the duration of the call, is passed using the storage medium pointed to by pmedium. Since the medium is owned by the caller, the advise sink should not free it. Also, if pmedium points to an IStorage or IStream, the sink must not increment the reference count.

See Also

IDataObject::DAdvise


IAdviseSink::OnRename

Notifies all registered advisory sinks that the object has been renamed.

Void OnRename(

IMoniker * pmk	//Points to the IMoniker interface
);
Parameter

pmk

Pointer to the new full moniker of the object.

Comments

OLE link objects normally implement IAdviseSink::OnRename to receive notification of a change in the name of a link source or its container. The object serving as the link source calls OnRename and passes its new full moniker to the object handler, which forwards the notification to the link object. In response, the link object must update its moniker. The link object, in turn, forwards the notification to its own container.


IAdviseSink::OnSave

Notifies all registered advisory sinks that the object has been saved.

Void OnSave();

Comments

Object handlers and link objects normally implement IAdviseSink::OnSave to receive notifications of when an object is saved to disk, either to its original storage (through a Save operation) or to new storage (through a Save As operation). Object Handlers and link objects register to be notified when an object is saved for the purpose of updating their caches, but then only if the advise flag passed during registration specifies ADVFCACHE_ONSAVE. Object handlers and link objects forward these notifications to their containers.


IAdviseSink::OnViewChange

Notifies an object's registered advise sinks that its view has changed.

Void OnViewChange(

DWORD dwAspect,	//A value specifying aspect of object
LONG lindex	//Currently must be -1
);
Parameters

dwAspect

[in] Specifies the aspect, or view, of the object. Contains a value taken from the enumeration, DVASPECT.

lindex

[in] Identifies which piece of the view has changed. Currently only -1 is valid.

Comments

Containers register to be notified when an object's view changes by calling IViewObject::SetAdvise. Once registered, the object will call the sink's IAdviseSink::OnViewChange method when appropriate. OnViewChange can be called when the object is in either the loaded or running state.

Even though DVASPECT values are individual flag bits, dwAspect may only represent one value. That is, dwAspect cannot contain the result of an OR operation combining two or more DVASPECT values.

The lindex member represents the part of the aspect that is of interest. The value of lindex depends on the value of dwAspect. If dwAspect is either DVASPECT_THUMBNAIL or DVASPECT_ICON, lindex is ignored. If dwAspect is DVASPECT_CONTENT, lindex must be -1, which indicates that the entire view is of interest and is the only value that is currently valid.

See Also

IViewObject::SetAdvise


IAdviseSink2

The IAdviseSink2 interface is an extension of IAdviseSink and was defined to prevent overloading the IAdviseSink::OnRename method. Without IAdviseSink2, embedded objects and link sources, upon being renamed, would both have to notify their containers by calling IAdviseSink::OnRename. In applications where different blocks of code might execute depending on which of these two similar events has occurred, using the same method for both events complicates testing and debugging. With IAdviseSink2, embedded objects whose name has changed still call IAdviseSink::OnRename, but the link object maps this notification to IAdviseSink2::OnLinkSrcChange. Making this distinction explicit makes it easier to test and maintain your code.

When to Implement

If your application supports links, you should definitely implement IAdviseSink2. Even if your application does not support links, it may do so in future releases. Since the IAdviseSink2 interface inherits all the methods of IAdviseSink without additional overhead, it makes sense to implement IAdviseSink2 in all cases.

When to Use

When a link source is renamed, the link object should notify its container by calling IAdviseSink::OnLinkSrcChange.

Methods in Vtable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments reference count.
Release	Decrements reference count.
IAdviseSink Methods	Description
OnDataChange	Advises that data has changed.
OnViewChange	Advises that view of object has changed.
OnRename	Advises that name of object has changed.
OnSave	Advises that object has been saved to disk.
OnClose	Advises that object has been closed.
IAdviseSink2 Method	Description
OnLinkSrcChange	Advises that link source has changed.


IAdviseSink2::OnLinkSrcChange

Notifies the container that registered the advise sink that a link source has changed, enabling the container to update the link's moniker.

void OnLinkSrcChange(

IMoniker *pmk	//A pointer to the new link source
);
Parameter

pmk

[in] Points to the new link source contained within the link object.

Comments

A container of linked objects implements this method to receive notification in the event of a change in the moniker of its link source.

IAdviseSink2::OnLinkSrcChange is called by the OLE link object when it receives the OnRename notification from the link-source (object) application. The link object updates its moniker and sends the OnLinkSrcChange notification to containers that have implemented IAdviseSink2.

Notes to Implementors

Nothing prevents a link object from notifying its container of the moniker change by calling IAdviseSink::OnRename instead of OnLinkSrcChange. In practice, however, overloading OnRename to mean either that a link object's moniker has changed or that the corresponding link source's moniker has changed makes it difficult for applications to determine which event has, in fact, occurred. If the two events trigger different processing, as will often be the case, then using a different method for each makes the job of determining which event occurred much easier.

See Also

IAdviseSink::OnRename


IBindCtx

The IBindCtx interface provides access to a bind context, which is an object that stores information about a particular moniker binding operation. You pass a bind context as a parameter when calling many methods of IMoniker and in certain API functions related to monikers.

A bind context includes the following information:

•	A BIND_OPTS structure containing a set of parameters that do not change during the binding operation. When a composite moniker is bound, each component uses the same bind context; a bind context is thus a mechanism for passing the same parameters to each component of a composite moniker.

•	A set of pointers to objects that the binding operation has activated. The bind context holds pointers to these bound objects, keeping them loaded and thus eliminating redundant activations if the objects are needed again during subsequent binding operations.

•	A pointer to the Running Object Table on the machine of the process that started the bind operation. Moniker implementations that need to access the Running Object Table should use the IBindCtx::GetRunningObjectTable method rather than using the GetRunningObjectTable API function. This allows future enhancements to the system's IBindCtx implementation to modify binding behavior.

•	A table of interface pointers, each associated with a string key. This capability enables moniker implementations to store interface pointers under a well-known string so that they can later be retrieved from the bind context. For example, OLE defines several string keys (e.g., "ExceededDeadline", "ConnectManually") that can be used to store a pointer to the object that caused an error during a binding operation.

When to Implement

You do not need to implement this interface. The system provides an IBindCtx implementation, accessible using the CreateBindCtx API function, that is suitable for all situations.

When to Use

The primary users of IBindCtx are those who write their own implementation of the IMoniker interface; they must call IBindCtx methods from the implementation of several IMoniker methods. Another category of IBindCtx users are moniker providers (that is, those who hand out monikers that identify their objects). They may need to call IBindCtx methods from their implementations of the IOleItemContainer or IParseDisplayName interfaces.

Moniker clients (that is, those who use monikers to acquire interface pointers to objects) typically don't call many IBindCtx methods; they simply pass a bind context as a parameter to the IMoniker method they're using. Moniker clients typically perform the following steps:

1.	Call the CreateBindCtx API function to create a bind context.

2.	Optionally, call the IBindCtx::SetBindOptions method in order to specify the bind options. Moniker clients rarely perform this step.

3.	Pass the bind context as a parameter to the desired IMoniker method (most commonly IMoniker::BindToObject).

4.	Call IUnknown::Release on the bind context to release it.

The most common example of moniker clients are applications that act as link containers, that is, container applications that allow their documents to contain linked objects. However, link containers are a special case in that they rarely call IMoniker methods directly. Generally, they manipulate linked objects through the IOleLink interface; the system-supplied linked object implements this interface and calls the appropriate IMoniker methods as needed. Consequently, the linked object is the one that passes bind contexts to the IMoniker methods.

Methods in Vtable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments the reference count.
Release	Decrements the reference count.
IBindCtx Methods	Description
RegisterObjectBound	Registers an object with the bind context.
RevokeObjectBound	Revokes an object's registration.
ReleaseBoundObjects	Releases all registered objects.
SetBindOptions	Sets the binding options.
GetBindOptions	Retrieves the binding options.
GetRunningObjectTable	Retrieves a pointer to the Running Object Table.
RegisterObjectParam	Associates an object with a string key.
GetObjectParam	Returns the object associated with a given string key.
EnumObjectParam	Enumerates all the string keys in the table.
RevokeObjectParam	Revokes association between an object and a string key.
See Also

CreateBindCtx, IMoniker, IOleItemContainer, IParseDisplayName


IBindCtx::EnumObjectParam

Returns a pointer to an enumerator that can return the keys of the bind context's string-keyed table of pointers.

HRESULT EnumObjectParam(

IEnumString **ppenum	//Receives a pointer to an enumerator
);
Parameter

ppenum

[out] Receives an IEnumString pointer to the enumerator. If an error occurs, *ppenum is set to NULL. If *ppenum is non-NULL, the implementation calls IUnknown::AddRef on the parameter; it is the caller's responsibility to call IUnknown::Release.

Return Values

S_OK

An enumerator was successfully returned.

E_OUTOFMEMORY

Indicates insufficient memory.

Comments

This method eturns an IEnumString pointer to an enumerator that can return the keys of the bind context's string-keyed table of pointers. The keys returned are the ones previously specified in calls to IBindCtx::RegisterObjectParam.

Notes to Callers

A bind context maintains a table of interface pointers, each associated with a string key. This enables communication between a moniker implementation and the caller that initiated the binding operation. One party can store an interface pointer under a string known to both parties so that the other party can later retrieve it from the bind context.

See Also

IBindCtx::RegisterObjectParam, IEnumString


IBindCtx::GetBindOptions

Returns the binding options stored in this bind context.

HRESULT GetBindOptions(

BIND_OPTS *pbindopts	//Points to a BIND_OPTS structure
);
Parameter

pbindopts

[in, out] Points to a BIND_OPTS structure that receives the current binding parameters. For more information on the BIND_OPTS structure, see the "Data Structures" section.

Return Values

S_OK

The stored binding options were successfully returned.

E_UNEXPECTED

Indicates an unexpected error.

Comments

A bind context contains a block of parameters, stored in a BIND_OPTS structure, that are common to most IMoniker operations and that do not change as the operation moves from piece to piece of a composite moniker.

Notes to Callers

You typically call this method if you are writing your own moniker class (that is, implementing the IMoniker interface). You call this method to retrieve the parameters specified by the moniker client.

You must provide the BIND_OPTS structure that is filled in by this method. Before calling this method, you must initialize the cbStruct field of the structure to the size of the BIND_OPTS structure.

See Also

IBindCtx::SetBindOptions


IBindCtx::GetObjectParam

Retrieves the pointer associated with the specified key in the bind context's string-keyed table of pointers.

HRESULT GetObjectParam(

LPOLESTR pszKey,	//Points to the key to be used
IUnknown **ppunk	//Receives a pointer to the object associated with the key
);
Parameters

pszKey

[in] Points to a zero-terminated string containing the key to search for. For Win32 applications, the LPOLESTR type indicates a wide character string (two bytes per character); otherwise, the string has one byte per character. Key string comparison is case sensitive.

ppunk

[out] Receives a pointer to the object associated with pszKey. If an error occurs, *ppunk is set to NULL. If *ppunk is non-NULL, the implementation calls IUnknown::AddRef on the parameter; it is the caller's responsibility to call IUnknown::Release.

Return Values

S_OK

The pointer associated with the specified key was successfully returned.

E_FAIL

Indicates that no object has been registered with the specified key.

Comments

A bind context maintains a table of interface pointers, each associated with a string key. This enables communication between a moniker implementation and the caller that initiated the binding operation. One party can store an interface pointer under a string known to both parties so that the other party can later retrieve it from the bind context.

The pointer this method retrieves must have previously been inserted into the table using the IBindCtx::RegisterObjectParam method.

Notes to Callers

You can call IBindCtx::GetObjectParam if you are either a moniker implementor or a sophisticated moniker client.

If you are a moniker client, you can call this method if a binding operation failed to get specific information about the error that occurred. Depending on the error, you may be able to correct the situation and retry the binding operation. See IBindCtx::RegisterObjectParam for more information.

If you are a moniker implementor, you can call this method to retrieve information specified by the caller that initiated the binding operation. By convention, you should use key names that begin with the string form of the CLSID of your moniker class (see the StringFromCLSID API function).

See Also

IBindCtx::RegisterObjectParam, IBindCtx::EnumObjectParam


IBindCtx::GetRunningObjectTable

Returns an interface pointer to the Running Object Table (ROT) for the machine on which this bind context is running.

HRESULT GetRunningObjectTable(

IRunningObjectTable **pprot	//Receives a pointer to the Running Object Table
);
Parameter

pprot

[out] Receives a pointer to the Running Object Table. If an error occurs, *pprot is set to NULL. If *pprot is non-NULL, the implementation calls IUnknown::AddRef on the parameter; it is the caller's responsibility to call IUnknown::Release.

Return Values

S_OK

A pointer to the ROT was returned successfully.

E_OUTOFMEMORY

Indicates insufficient memory.

E_UNEXPECTED

Indicates an unexpected error.

Comments

The Running Object Table is a globally-accessible table on each machine. It keeps track of all the objects that are currently running on the machine.

Notes to Callers

You typically call this method if you are writing your own moniker class (that is, implementing the IMoniker interface). You can call this method from your implementation of IMoniker::BindToObject or IMoniker::IsRunning to check whether a given object is currently running. You can also call this method from your implementation of IMoniker::GetTimeOfLastChange to learn when a running object was last modified.

Moniker implementations should always use this method instead of using the GetRunningObjectTable API function. This makes it possible for future implementations of IBindCtx to modify binding behavior.

See Also

IMoniker, IRunningObjectTable


IBindCtx::RegisterObjectBound

Calls the IUnknown::AddRef method on the specified object to ensure that the object remains active until the bind context is released. The method stores a pointer to the object in the bind context's internal list of pointers.

HRESULT RegisterObjectBound(

IUnknown *punk	//Pointer to the object being registered
);
Parameter

punk

[in] Points to the object that is being registered as bound.

Return Values

S_OK

The object was successfully registered.

E_OUTOFMEMORY

Indicates insufficient memory.

Comments

Notes to Callers

If you are writing your own moniker class (that is, implementing the IMoniker interface), you should call this method whenever your implementation activates an object. This happens most often in the course of binding a moniker, but it can also happen while retrieving a moniker's display name, parsing a display name into a moniker, or retrieving the time an object was last modified.

Calling the IBindCtx::RegisterObjectBound creates an additional reference to the passed-in object (via IUnknown::AddRef ); you are still required to release your own copy of the pointer. Note that calling this method twice for the same object creates two references to that object; you can release a reference to an object using the IBindCtx::RevokeObjectBound method. All references held by the bind context are released when the bind context itself is released.

Registering an object with a bind context keeps the object active until the bind context is released. Reusing a bind context in a subsequent binding operation (either for another piece of the same composite moniker, or for a different moniker) can make the subsequent binding operation more efficient because it doesn't have to reload that object. This performance improvement is present only if the subsequent binding operation requires some of the same objects as the original one. This performance improvement should be balanced against the costs of keeping objects activated unnecessarily.

Note that IBindCtx does not provide a method to retrieve a pointer to an object registered using IBindCtx::RegisterObjectBound. Assuming the object has registered itself with the Running Object Table, moniker implementations can use the Running Object Table to retrieve a pointer to the object.

See Also

IBindCtx::ReleaseBoundObjects, IBindCtx::RevokeObjectBound, IRunningObjectTable::GetObject


IBindCtx::RegisterObjectParam

Stores a pointer to the specified object under the specified key in the bind context's string-keyed table of pointers. The method calls IUnknown::AddRef on the stored pointer.

HRESULT RegisterObjectParam(

LPOLESTR pszKey,	//Points to the key to be used
IUnknown *punk	//Points to the object to be associated with the key
);
Parameters

pszKey

[in] Points to a zero-terminated string containing the key under which the object is being registered. For Win32 applications, the LPOLESTR type indicates a wide character string (two bytes per character); otherwise, the string has one byte per character. Key string comparsion is case sensitive.

punk

[in] Points to the object that is to be registered.

Return Values

S_OK

The pointer was successfully registered under the specified string.

E_OUTOFMEMORY

Indicates insufficient memory.

Comments

A bind context maintains a table of interface pointers, each associated with a string key. This enables communication between a moniker implementation and the caller that initiated the binding operation. One party can store an interface pointer under a string known to both parties so that the other party can later retrieve it from the bind context.

Binding operations subsequent to the use of this method can use the IBindCtx::GetObjectParam method to retrieve the stored pointer.

Notes to Callers

You can call IBindCtx::RegisterObjectParam if you are either a moniker implementor or a sophisticated moniker client.

If you're a moniker implementor and an error occurs during moniker binding, you can use one of the keys predefined by OLE to inform the caller of the cause of an error. The following list describes the keys associated with various error conditions:

MK_E_EXCEEDEDDEADLINE

If a binding operation exceeds its deadline because a given object is not running, then you should register the object's moniker using the first unused key from the list: "ExceededDeadline", "ExceededDeadline1", "ExceededDeadline2", etc. If the caller later finds the moniker in the Running Object Table, the caller can retry the binding operation.

MK_E_CONNECTMANUALLY

The "ConnectManually" key indicates a moniker whose binding requires assistance from the end user. The caller can retry the binding operation after showing the moniker's display name to request that the end user manually connect to the object. The most common reasons for returning this value are that a password is needed or that a floppy needs to be mounted.

E_CLASSNOTFOUND

The "ClassNotFound" key indicates a moniker whose class could not be found (i.e., the server for the object identified by this moniker could not be located). If this key is used in an OLE compound-document situation, the caller can use IMoniker::BindToStorage to bind to the object, and then try to carry out a Treat As... or Convert To... operation to associate the object with a different server. If this is successful, the caller can retry the binding operation.

If you're a moniker client with detailed knowledge of the implementation of the moniker you're using, you can also call this method to pass private information to that implementation.

You can define new strings as keys for storing pointers. By convention, you should use key names that begin with the string form of the CLSID of the moniker class (see the StringFromCLSID API function).

If the pszKey parameter matches the name of an existing key in the bind context's table, the new object replaces the existing object in the table.

When you register an object using this method, the object is not released until one of the following occurs:

•	It is replaced in the table by another object with the same key.

•	It is removed from the table by a call to IBindCtx::RevokeObjectParam.

•	The bind context is released. All registered objects are released when the bind context is released.

See Also

IBindCtx::GetObjectParam, IBindCtx::RevokeObjectParam, IBindCtx::EnumObjectParam


IBindCtx::ReleaseBoundObjects

Releases all pointers to all objects that were previously registered by calls to IBindCtx::RegisterObjectBound.

HRESULT ReleaseBoundObjects(void);

Return Value

S_OK

The objects were released successfully.

Comments

You rarely call this method directly. This method is called the system's IBindCtx implementation when a bind context is released. If a bind context is not released, all of the registered objects remain active.

If the same object has been registered more than once, this method calls the IUnknown::Release method on the object the number of times it was registered.

See Also

IBindCtx::RegisterObjectBound


IBindCtx::RevokeObjectBound

Calls the IUnknown::Release method on the specified object and removes the pointer to that object from the bind context's internal list of pointers. This undoes a previous call to IBindCtx::RegisterObjectBound for the same object.

HRESULT RevokeObjectBound(

IUnknown *punk	//Pointer to the object whose registration is being revoked
);
Parameter

punk

[in] Points to the object to be released.

Return Values

S_OK

The object was released successfully.

MK_E_NOTBOUND

Indicates that punk was not previously registered with a call to IBindCtx::RegisterObjectBound.

Comments

You rarely call this method. This method is included for completeness.


IBindCtx::RevokeObjectParam

Removes the specified key and its associated pointer from the bind context's string-keyed table of objects. The key must have previously been inserted into the table using the IBindCtx::RegisterObjectParam method.

HRESULT RevokeObjectParam(

LPOLESTR pszKey	//Points to the key to be revoked
);
Parameter

pszKey

[in] Points to a zero-terminated string containing the key to remove. For Win32 applications, the LPOLESTR type indicates a wide character string (two bytes per character); otherwise, the string has one byte per character. Key string comparsion is case sensitive.

Return Values

S_OK

The specified key was successfully removed from the table.

S_FALSE

Indicates that no object has been registered with the specified key.

Comments

A bind context maintains a table of interface pointers, each associated with a string key. This enables communication between a moniker implementation and the caller that initiated the binding operation. One party can store an interface pointer under a string known to both parties so that the other party can later retrieve it from the bind context.

This method is used to remove an entry from the table. If the specified key is found, the bind context releases its reference to the object.

See Also

IBindCtx::RegisterObjectParam


IBindCtx::SetBindOptions

Specifies new values for the binding parameters stored in the bind context. Subsequent binding operations can call IBindCtx::GetBindOptions to retrieve the parameters.

HRESULT SetBindOptions(

BIND_OPTS *pbindopts	//Pointer to a BIND_OPTS structure
);
Parameter

pbindopts

[in] Points to a BIND_OPTS structure containing the binding parameters. For more information on the BIND_OPTS structure, see the "Data Structures" section.

Return Values

S_OK

The parameters were stored successfully.

E_OUTOFMEMORY

Indicates insufficient memory.

Comments

A bind context contains a block of parameters, stored in a BIND_OPTS structure, that are common to most IMoniker operations and that do not change as the operation moves from piece to piece of a composite moniker.

Notes to Callers

This method can be called by moniker clients, that is, those who use monikers to acquire interface pointers to objects.

When you first create a bind context using the CreateBindCtx API function, the fields of the BIND_OPTS structure are initialized to the following values:

cbStruct = sizeof(BINDOPTS);

grfFlags = 0;

grfMode = STGM_READWRITE;

dwTickCountDeadline = 0;

You can use the IBindCtx::SetBindOptions method to modify these values before using the bind context, if you want values other than the defaults. See BIND_OPTS for more information.

See Also

IBindCtx::GetBindOptions


IClassFactory

The IClassFactory interface manages the creation of new objects. This interface is supported by class objects associated with CLSIDs.

When to Implement

You must implement this interface for every object definition so objects of that type can be created.

When to Use

Call the methods of this interface when creating new objects through a class object. First, call the CoGetClassObject API function to get an IClassFactory interface pointer to the class object, and then call the CreateInstance method to create an uninitialized object.

It is, however, not always necessary to go through this process to create an object. To create a single uninitialized object, you can, instead, just call CoCreateInstance. OLE also provides numerous helper functions (with names of the form OleCreateXxx) to create compound document objects.

Methods in Vtable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments reference count.
Release	Decrements reference count.
IClassFactory Methods	Description
CreateInstance	Creates an uninitialized object.
LockServer	Locks object application open in memory.
See Also

CoGetClassObject, CoCreateInstance , OleCreate


IClassFactory::CreateInstance

Creates an uninitialized object.

HRESULT CreateInstance(

IUnknown * pUnkOuter,	//Object is or isn't part of an aggregate
REFIID riid,	//Interface identifier
void ** ppvObject	//On return, pointer to interface pointer location
);
Parameters

pUnkOuter

[in] Indicates whether the object is being created as part of an aggregate. If so, you should use pUnkOuter to supply a pointer to the controlling unknown of the aggregate that will use the newly created object. If not, pUnkOuter should be NULL.

riid

[in]Specifies the IID of the interface to be used to communicate with the newly created object. If pUnkOuter is NULL, this parameter is frequently the IID of the initializing interface; if pUnkOuter is non-NULL, riid must be IID_IUnknown.

ppvObject

[out]On return, points to the location of the requested interface pointer. If the object does not support the interface specified in riid, ppvObj is set to NULL.

Return Values

S_OK

The specified object was created.

CLASS_E_NOAGGREGATION

The pUnkOuter parameter was non-NULL and the object does not support aggregation.

E_NOINTERFACE

The object that ppvObj points to does not support the interface identified by riid.

E_UNEXPECTED

An unexpected error occurred.

E_OUTOFMEMORY

Out of memory.

E_INVALIDARG

One or more arguments are invalid.

Comments

The IClassFactory interface is always on a class object. The CreateInstance method creates an uninitialized object, which is defined in the code associated with the class object.

The pUnkOuter parameter indicates whether the object is being created as part of an aggregate. Object definitions are not required to support aggregation — they must be specifically designed and implemented to support it.

The riid parameter specifies the IID (interface ID) of the interface through which you communicate with the new object. If pUnkOuter is non-NULL (indicating aggregation), the value of the riid parameter must be IID_IUnknown. If the object is not part of an aggregate, riid often specifies the interface though which the object will be initialized.

For OLE embeddings, the initialization interface is IPersistStorage, but in other situations, other interfaces are used. To initialize the object, there must be a subsequent call to an appropriate method in the initializing interface. Common initialization functions include IPersistStorage::InitNew (for new, blank embeddable components), IPersistStorage::Load (for reloaded embeddable components), IPersistStream::Load, or IPersistFile::Load.

In general, if an application supports one object definition, and the class object is registered for single use, only one object can be created. The application must not create other objects, and a request to do so should return an error from IClassFactory::CreateInstance. The same is true for applications that support multiple classes, each with a class object registered for single use; a CreateInstance for one class followed by a CreateInstance for any of the classes should return an error.

To avoid returning an error, applications that support multiple object definitions with single-use class objects can revoke the registered class object of the first definition by calling CoRevokeClassObject when a request for instantiating a second is received. For example, suppose there are two classes, A and B. When IClassFactory::CreateInstance is called for class A, revoke the class object for B. When B is created, revoke the class object for A. This solution complicates shutdown because one of the class objects might have already been revoked (and cannot be revoked twice).


IClassFactory::LockServer

Called by the client of a class object to keep an open object application in memory, allowing instances to be created more quickly.

HRESULT LockServer(

BOOL fLock	//Increments or decrements the lock count
);
Parameter

fLock

If TRUE, increments the lock count; if FALSE, decrements the lock count.

Return Values

S_OK

The specified object was either locked ( fLock = TRUE) or unlocked from memory ( fLock = FALSE).

E_FAIL

Indicates an unspecified error.

E_OUTOFMEMORY

Out of memory.

E_UNEXPECTED

An unexpected error occurred.

Comments

IClassFactory::LockServer controls whether an object application is kept in memory. Keeping the application alive in memory allows instances to be created more quickly.

Notes to Callers

Most clients do not need to call this function. It is provided only for the benefit of sophisticated clients that require special performance in the creation of certain kinds of objects.

Notes to Implementors

If the lock count is zero, there are no more objects in use, and the application is not under user control, then the server can be closed. One way to implement IClassFactory::LockServer is to call CoLockObjectExternal.

The process that locks the object application is responsible for unlocking it. Once the class object is released, there is no mechanism that guarantees the caller connection to the same object definition later (as in the case where a class object is registered as single-use). It is important to count all calls, not just the last one, to IClassFactory::LockServer, because calls must be balanced before attempting to release the pointer to the class object or an error results. For every call to LockServer with fLock set to TRUE, there must be a call to LockServer with fLock set to FALSE. When the lock count and the class object reference count are both zero, the class object can be freed.

See Also

CoLockObjectExternal


IDataAdviseHolder

The IDataAdviseHolder interface creates and manages connections between an advise sink and a data object so that the advise sink can receive notification of changes in the data object. The IDataAdviseHolder interface also sends the notifications to the advise sinks it currently knows about when changes occur.

The object or container wishing to receive notification of changes in your data object creates an advise sink object with the IAdviseSink interface. The object or container application then calls your IDataObject::DAdvise method.

Typically, in your IDataObject implementation, you delegate handling of the advise sinks to the OLE-provided IDataAdviseHolder interface. This interface has methods to keep track of any IDataObject::DAdvise calls that your data object has received and to send notification back to the advise sinks as necessary when data has changed.

When to implement

Typically, you use the OLE-provided implementation of IDataAdviseHolder to simplify your implementation of the DAdvise, DUnadvise, and EnumDAdvise methods in the IDataObject interface.

When to use

Your implementation of IDataObject can call the methods in IDataAdviseHolder. The first time you receive a call to IDataObject::DAdvise, you call the API function CreateDataAdviseHolder to create an instance of the OLE-provided implementation of IDataAdviseHolder. Then, you delegate your IDataObject implementations of the DAdvise, DUnadvise, and EnumDAdvise methods to the corresponding methods in the OLE-provided IDataAdviseHolder.

When the data of interest to an advise sink actually changes, you call IDataAdviseHolder::SendOnDataChange from your data object to carry out the necessary notifications.

Methods in VTable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments reference count.
Release	Decrements reference count.
IDataAdviseHolder Methods	Description
Advise	Creates a connection between an advise sink and a data object so the advise sink can receive notification of change in the data object.
Unadvise	Destroys a notification connection previously set up with the Advise method.
EnumAdvise	Returns an object that can be used to enumerate the current advisory connections.
SendOnDataChange	Sends a change notification back to each advise sink that is currently being managed.
See Also

IDataObject, IAdviseSink


IDataAdviseHolder::Advise

Creates a connection between an advise sink and a data object for receiving notifications.

HRESULT Advise(

IDataObject * pDataObject,	//Specifies the data object for which notifications are requested
FORMATETC * pFormatetc,	//Description of data that is of interest to the advise sink
DWORD advf,	//Flags that specify how the notification takes place
IAdviseSink * pAdvSink,	//The advise sink requesting notification
DWORD * pdwConnection	//Identifies the connection for future calls to the Unadvise method
);
Parameters

pDataObject

[in]Points to the data object for which notifications are requested. If data in this object changes, a notification is sent to the advise sinks that have requested notification.

pFormatetc

[in]Points to the specified format, medium, and target device that is of interest to the advise sink requesting notification. For example, one sink may want to know only when the bitmap representation of the data in the the data object changes. Another sink may be interested in only the metafile format of the same object. Each advise sink is notified when the data of interest changes. This data is passed back to the advise sink when notification occurs.

advf

[in]Contains a group of flags for controlling the advisory connection. Valid values are from the enumeration ADVF. However, only some of the possible ADVF values are relevant for this method. The following table briefly describes the relevant values; a more detailed description can be found in the description of the ADVF enumeration.

ADVF Value	Description
ADVF_NODATA	Asks that no data be sent along with the notification.
ADVF_ONLYONCE	Causes the advisory connection to be destroyed after the first notification is sent. An implicit call to IDataAdviseHolder::Unadvise is made on behalf of the caller to remove the connection.
ADVF_PRIMEFIRST	Causes an initial notification to be sent  regardless of whether or not data has changed from its current state.
ADVF_DATAONSTOP	When specified with ADVF_NODATA, this flag causes a last notification with the data included to be sent before the data object is destroyed. When ADVF_NODATA is not specified, this flag has no effect.
pAdvSink

[in]Points to the advisory sink that receives the change notification.

pdwConnection

[in]Points to the location of a returned token that identifies this connection and can later be used to delete the advisory connection. It deletes the connection by passing it to IDataAdviseHolder::Unadvise. If this value is zero, the connection was not established.

Return Values

S_OK

The advisory connection was created.

E_INVALIDARG

One or more arguments are invalid.

Comments

Through the connection established through this method, the advisory sink can receive future notifications in a call to IAdviseSink::OnDataChange.

An object issues a call to IDataObject::DAdvise to request notification on changes to the format, medium, or target device of interest. This data is specified in the pFormatetc parameter. The DAdvise method in turn calls IDataAdviseHolder::Advise and delegates the task of setting up and tracking a connection to the advise holder. When the format, medium, or target device in question changes, the data object calls IDataAdviseHolder::SendOnDataChange to actually send the necessary notifications.

The established connection can be deleted by passing the value in pdwConnection to IDataAdviseHolder::Unadvise.

See also

ADVF, CreateDataAdviseHolder, FORMATETC, IDataAdviseHolder::Unadvise, IDataObject::DAdvise


IDataAdviseHolder::EnumAdvise

Returns an object that can be used to enumerate the current advisory connections.

HRESULT EnumAdvise(

IEnumSTATDATA ** ppenumAdvise	//Location for IEnumSTATDATA
);
Parameter

ppenumAdvise

[out]Points to the location where the new enumerator object should be returned. If this value is NULL, there are no connections to advise sinks at this time.

Return Values

S_OK

The enumerator object is successfully instantiated or there are no connections.

E_OUTOFMEMORY

The enumerator object could not be instantiated due to lack of memory.

Comments

The enumerator object returned by this method implements the IEnumSTATDATA interface, one of the standard enumerator interfaces that contain the Next, Reset, Clone, and Skip methods. IEnumSTATDATA enumerates the data stored in an array of STATDATA structures. IDataAdviseHolder::EnumAdvise is typically called from within IDataObject::DEnumAdvise.

Adding more advisory connections while the enumerator object is active has an undefined effect on the enumeration that results from this method.

See Also

IEnumXXXX, IEnumSTATDATA, IDataObject::EnumDAdvise


IDataAdviseHolder::SendOnDataChange

Sends notifications to each advise sink by calling the IAdviseSink::OnDataChange method for each advise sink currently being handled in this instance of IDataAdviseHolder.

HRESULT SendOnDataChange(

IDataObject * pDataObject,	//Points to the data object that has changed
DWORD dwReserved,	//Reserved
DWORD advf	//Advise flag that specifies how to send the notification
);
Parameters

pDataObject

[in]Points to the data object where the data has just changed. This data object is used in the subsequent calls to IAdviseSink::OnDataChange.

dwReserved

[in]Reserved for future use; must be zero.

advf

[in]Contains the advise flag values that specify how the call to IAdviseSink::OnDataChange is made. These flag values are from the enumeration ADVF. Typically, the value for advf is NULL. The only exception occurs when the data object is shutting down and must send a final notification that includes the actual data to sinks that have specified ADVF_DATAONSTOP and ADVF_NODATA in their call to IDataObject::DAdvise. In this case, advf contains ADVF_DATAONSTOP.

Return Values

S_OK

The call to IAdviseSink::OnDataChange was made.

E_OUTOFMEMORY

Ran out of memory and the notifications could not be sent.

Comments

The data object calls this method when it detects a change that would be of interest to an advise sink that has previously requested notification.

Most notifications include the actual data with them. The only exception is if the ADVF_NODATA flag was previously specified when the connection was initially set up in the IDataAdviseHolder::Advise method.

Before calling the IAdviseSink::OnDataChange method for each advise sink, this method obtains the actual data by calling the IDataObject::GetData method for the data object specified in the pDataObject parameter.

See Also

ADVF, IAdviseSink::OnDataChange


IDataAdviseHolder::Unadvise

Removes a connection between a data object and an advisory sink that was set up through a previous call to the IDataAdviseHolder::Advise method. IDataAdviseHolder::Unadvise is typically called in IDataObject::DUnadvise.

HRESULT Unadvise(

DWORD dwConnection	//Specifies the connection to remove
);
Parameter

dwConnection

Specifies the connection to remove. This value was returned by IDataAdviseHolder::Advise when the connection was originally established.

Return Values

S_OK

The specified connection was successfully deleted.

OLE_E_NOCONNECTION

The specified dwConnection is not a valid connection.

See Also

IDataAdviseHolder::Advise, IDataObject::DUnadvise


IDataObject

The IDataObject interface provides data transfer capabilities and notification of changes in data. The format of the transferred data is specified along with the medium through which OLE transfers the data. Optionally, the data can be rendered for a specific target device. In addition to retrieving and storing data, the IDataObject interface contains methods to enumerate available formats and to set up an advisory sink for handling change notifications.

A data object is an object that contains an IDataObject implementation. Data objects may support all or some of the functions available through the IDataObject interface. For example, some data objects do not allow callers to send them data. Other data objects do not support advisory connections and change notifications. However, for those data objects that do support change notifications, OLE provides an object called a data advise holder. Since a data object can have multiple connections, each with their own set of attributes, managing these connections and sending the appropriate notifications gets complex. The data advise holder exists to simplify this task.

When to Implement

You implement the IDataObject interface if you are developing a container or server application that is capable of transferring data. For example, if your application allows its data to be pasted or dropped into another application, you must implement the IDataObject interface.

OLE provides implementations for its default object handler and its cache.

When to Use

Any application that can receive data uses the methods in the IDataObject interface.

When you call the methods in the IDataObject interface, you specify a format, a medium, and, optionally, a target device for which the data should be rendered. If you want to be notified when the data changes, you can set up an advisory connection through which notifications can be sent.

Methods in VTable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments reference count.
Release	Decrements reference count.
IDataObject Methods	Description
GetData	Renders the data described in a FORMATETC structure and transfers it through the STGMEDIUM structure.
GetDataHere	Renders the data described in a FORMATETC structure and transfers it through the STGMEDIUM structure allocated by the caller.
QueryGetData	Determines whether the data object is capable of rendering the data described in the FORMATETC structure.
GetCanonicalFormatEtc	Provides a potentially different but logically equivalent FORMATETC structure.
SetData	Provides the source data object with data described by a FORMATETC structure and an STGMEDIUM structure.
EnumFormatEtc	Returns an object to enumerate the FORMATETC supported by the data object.
DAdvise	Creates a connection between a data object and an advise sink so the advise sink can receive notifications of changes in the data object.
DUnadvise	Destroys a notification previously set up with DAdvise.
EnumDAdvise	Returns an object to enumerate the current advisory connections.


IDataObject::DAdvise

Creates a connection between a data object and an advise sink so the advise sink can receive notifications of changes in the data object.

HRESULT DAdvise(

FORMATETC * pFormatetc,	//Description of data that is of interest to the advise sink
DWORD advf,	//Flags that specify how the notification takes place
IAdviseSink * pAdvSink,	//The advise sink that is requesting notification
DWORD * pdwConnection	//Identifies the connection for future calls to the Unadvise method
);
Parameters

pFormatetc

[in]Points to the particular format, target device, aspect, and medium that will be used for future notifications. For example, one sink may want to know only when the bitmap representation of the data in the the data object changes. Another sink may be interested in only the metafile format of the same object. Each advise sink is notified when the data of interest changes. This data is passed back to the advise sink when notification occurs.

advf

[in]Contains a group of flags for controlling the advisory connection. Valid values are from the enumeration ADVF. However, only some of the possible ADVF values are relevant for this method. The following table briefly describes the relevant values. You can find a more detailed description in ADVF.

ADVF Value	Description
ADVF_NODATA	Asks the data object to avoid sending data with the notifications. Typically data is sent. This flag is a way to override the default behavior. When ADVF_NODATA is used, the TYMED member of the STGMEDIUM structure that is passed to OnDataChange will usually contain TYMED_NULL. The caller can then retrieve the data with a subsequent IDataObject::GetData call.
ADVF_ONLYONCE	Causes the advisory connection to be destroyed after the first change notification is sent. An implicit call to IDataObject::DUnadvise is made on behalf of the caller to remove the connection.
ADVF_PRIMEFIRST	Asks for an additional initial notification. The combination of ADVF_ONLYONCE and ADVF_PRIMEFIRST provides, in effect, an asynchronous IDataObject::GetData call.
ADVF_DATAONSTOP	When specified with ADVF_NODATA, this flag causes a last notification with the data included to to be sent before the data object is destroyed. If used without ADVF_NODATA, IDataObject::DAdvise can be implemented in one of the following ways:
	•   the ADVF_DATAONSTOP can be ignored.
	•   the object can behave as if ADVF_NODATA was specified.
	•   a change notification is sent only in the shutdown case. Data changes prior to shutdown do not cause a notification to be sent.
pAdvSink

[in]Points to the advisory sink that will receive the change notification.

pdwConnection

[in]Points to the location of a returned token that identifies this connection. You can use this token later to delete the advisory connection (by passing it to IDataObject::DUnadvise). If this value is zero, the connection was not established.

Return Values

S_OK

The advisory connection was created.

E_INVALIDARG

One or more arguments are invalid.

E_UNEXPECTED

An unexpected error occurred.

E_OUTOFMEMORY

The connection was not created because the system ran out of memory.

E_NOTIMPL

This method is not implemented for the data object.

DV_E_LINDEX

Invalid value for lindex; currently, only -1 is supported.

DV_E_FORMATETC

Invalid value for pFormatetc.

OLE_E_ADVISENOTSUPPORTED

The data object does not support change notification.

Comments

The IDataObject::DAdvise method creates a connection between the data object and the caller. The caller provides an advisory sink through which the notifications can be sent when the object's data changes. The advise sink issues the call to IDataObject::DAdvise. Advisory connections are associated with a particular description of the data. Data clients specify the format, aspect, medium, and/or target device of interest in the FORMATETC structure passed in. If the data object does not support one or more of the requested attributes or the sending of notifications at all. It can refuse the connection by returning OLE_E_ADVISENOTSUPPORTED.

Objects used for data transfer typically do not support advisory notifications and return OLE_E_ADVISENOTSUPPORTED from IDataObject::DAdvise.

Containers of linked objects can set up advisory connections directly with the bound link source or indirectly via the standard OLE link object that manages the connection. Connections set up with the bound link source are not automatically deleted. The container must explicitly call IDataObject::DUnAdvise on the bound link source to delete it. Connections set up through the OLE link object are destroyed when the link object is deleted.

The OLE default link object creates a "wildcard advise" with the link source so OLE can maintain the time of last change. This advise is specifically used to note the time that anything changed. OLE ignores all data formats that may have changed, noting only the time of last change. To allow wildcard advises, set the FORMATETC members as follows before calling IDataObject::DAdvise:

cf == 0;

ptd == NULL;

dwAspect ==-1;

lindex == -1

tymed == -1;

The advise flags should also include ADVF_NODATA. Wildcard advises from OLE should always be accepted by applications.

For those data objects that support notifications, a data advise holder object can be used to simplify the implementation of DAdvise and the other notification methods in IDataObject (DUnadvise and EnumAdvise). The data advise holder is an object provided by OLE that manages the registration and sending of notifications. With the first invocation of DAdvise, the helper function CreateDataAdviseHolder can be called to create the data advise holder and provide the data object with a pointer to it. The data object then delegates to the IDataAdviseHolder::Advise method in the data advise holder to create the requested connection.

See also

ADVF, FORMATETC, CreateDataAdviseHolder, IAdviseSink::OnDataChange, IDataObject::DUnAdvise


IDataObject::DUnadvise

Destroys a previously set up notification

HRESULT DUnadvise(

DWORD dwConnection	//Specifies the connection to remove
);
Parameter

dwConnection

[in]Specifies the connection to remove. This value was returned by IDataObject::DAdvise when the connection was originally established.

Return Values

S_OK

The specified connection was successfully deleted.

OLE_E_NOCONNECTION

The specified dwConnection is not a valid connection.

OLE_E_ADVISENOTSUPPORTED

This IDataObject implementation does not support notification.

Comments

This methods destroys a notification created with a call to the IDataObject::DAdvise method.

If the advisory connection being deleted was initially set up using IDataAdviseHolder::Advise instead of IDataObject::DAdvise, you must call IDataAdviseHolder::Unadvise to delete it.

See Also

IDataObject::DAdvise


IDataObject::EnumDAdvise

Returns an object to enumerate the current advisory connections.

HRESULT EnumDAdvise(

IEnumSTATDATA ** ppenumAdvise	//Location for IEnumSTATDATA
);
Parameter

ppenumAdvise

[out]Points to the location where the new enumerator object should be returned. If the returned value is NULL, there are no connections to advise sinks at this time.

Return Values

S_OK

The enumerator object is successfully instantiated or there are no connections.

E_OUTOFMEMORY

The enumerator object could not be instantiated due to lack of memory.

OLE_E_ADVISENOTSUPPORTED

Advisory notifications are not supported by this object.

Comments

The enumerator object returned by this method implements the IEnumSTATDATA interface, one of the standard enumerator interfaces that contain the Next, Reset, Clone, and Skip methods. IEnumSTATDATA enumerates the data stored in an array of STATDATA structures.

While this enumeration is in progress, the effect of adding more advisory connections on the subsequent enumeration is undefined.

See Also

IEnumSTATDATA


IDataObject::EnumFormatEtc

Returns an object to enumerate the FORMATETC structures that can be used with IDataObject::GetData or IDataObject::SetData. You use this method when you want to enumerate the FORMATETC structures for a data object.

HRESULT EnumFormatEtc(

DWORD dwDirection,	//Specifies a value from the enumeration DATADIR
IEnumFORMATETC ** ppenumFormatetc	//Location for IEnumFORMATETC
);
Parameters

dwDirection

[in]Specifies a value from the enumeration DATADIR.

typedef enum tagDATADIR

{

    DATADIR_GET = 1,

    DATADIR_SET = 2,

} DATADIR;

The value DATADIR_GET enumerates the formats that can be passed in IDataObject::GetData. The value DATADIR_SET enumerates those formats that can be passed in IDataObject::SetData.

ppenumFormatetc

[out]Points to the location where the new enumerator object should be returned.

Return Values

S_OK

Enumerator object was successfully returned.

E_INVALIDARG

One or more arguments are invalid.

E_OUTOFMEMORY

Enumerator object was not returned because the system ran out of memory.

E_NOTIMPL

The direction specified by dwDirection is not supported.

OLE_S_USEREG

Requests that OLE enumerate the formats from the registry.

Comments

This method creates and returns an enumerator object that can be used to determine all of the ways the data object can describe data in a FORMATETC structure. The enumerator object implements IEnumFORMATETC, one of the standard enumerator interfaces. The caller is responsible for calling IEnumFormatEtc::Release when it is finished with the enumeration.

If a FORMATETC structure is enumerated by IDataObject::EnumFormatEtc, there is no guarantee that the format is supported because the formats can change over time. Accordingly, applications should treat the enumeration as a hint of the format types that can be passed.

IDataObject::EnumFormatEtc is called when one of the following actions occurs:

•	An application calls OleSetClipboard. OLE must determine what data to place on the Clipboard and whether it is necessary to put OLE 1 compatibility formats on the Clipboard.

•	Data is being pasted from the Clipboard or dropped. An application uses the first acceptable format.

•	The Paste Special dialog box is displayed. The target application builds the list of formats from the FORMATETC entries.

Formats can be registered statically in the registration database or dynamically during object initialization. If an object has an unchanging list of formats and these formats are registered in the registration database, it can ask OLE to perform the enumeration using the registration database by calling the helper function OleRegEnumFormatEtc or by returning OLE_S_USEREG.

OLE_S_USEREG instructs the default object handler to call OleRegEnumFormatEtc. Object applications that are implemented as DLL object applications cannot return OLE_S_USEREG. They must call OleRegEnumFormatEtc directly.

Private formats can be enumerated for OLE 1 objects, if they are registered with the RequestDataFormats or SetDataFormats keys in the registration database. Also, private formats can be enumerated for OLE 2 objects, if they are registered with the GetDataFormats or SetDataFormats keys.

For OLE 1 objects whose servers do not have RequestDataFormats or SetDataFormats information registered in the registration database, a call to EnumFormatEtc with DATADIR_GET only enumerates the Native and Metafile formats, regardless of whether they support these formats or others. Calling EnumFormatEtc with DATADIR_SET on such objects only enumerates Native, regardless of whether the object supports being set with other formats.

The FORMATETC structure returned by the enumeration usually indicates a NULL target device (ptd). This is appropriate because, unlike the other members of FORMATETC, the target device does not participate in the object's decision as to whether it can accept or provide the data in either a SetData or GetData call.

The TYMED member of FORMATETC often indicates that more than one kind of storage medium is acceptable. You should always mask and test for it by using a Boolean OR operator.

See Also

FORMATETC, OleRegEnumFormatEtc, IEnumFormatEtc, IDataObject::SetData, IDataObject::GetData


IDataObject::GetCanonicalFormatEtc

Provides a potentially different but logically equivalent FORMATETC structure. You use this method when you have different FORMATETC structures that may return the same data.

HRESULT GetCanonicalFormatEtc(

FORMATETC * pFormatetcIn,	//Points to the FORMATETC structure that the caller would like to use
FORMATETC * pFormatetcOut	//Points to the canonical equivalent FORMATETC structure
);
Parameters

pFormatetcIn

[in]Points to the format, media, and target device that the caller would like to use in a subsequent call to retrieve data, for example, IDataObject::GetData. The TYMED member is not significant and should be ignored.

pFormatetcOut

[out]Points to a FORMATETC structure that is canonically equivalent to pFormatetcIn. The caller allocates this structure and this method fills in the data. In a subsequent call to retrieve data, for example, IDataObject::GetData, the caller uses the pFormatetcOut value. This value is NULL if the method returns DATA_S_SAMEFORMATETC. The TYMED member is not significant and should be ignored.

Return Values

S_OK

The returned FORMATETC structure is different from the one that was passed.

E_INVALIDARG

One or more arguments are invalid.

E_UNEXPECTED

An unexpected error occurred.

E_OUTOFMEMORY

Structure was not created because the system ran out of memory.

DATA_S_SAMEFORMATETC

The FORMATETC structures are the same and NULL is returned in pFormatetcOut.

DV_E_LINDEX

Invalid value for lindex; currently, only -1 is supported.

DV_E_FORMATETC

Invalid value for pFormatetc.

OLE_E_NOTRUNNING

Object application is not running.

Comments

A data object can return exactly the same data even though you have specified different FORMATETC structures in subsequent requests to retrieve data. For example, the same data can be returned for different target devices if the data is not sensitive to the target devices.

The IDataObject::GetCanonicalFormatEtc method provides the canonical equivalent of a specified FORMATETC structure. By calling this function prior to retrieving the data object, you can use the canonical equivalent FORMATETC in your subsequent call to IDataObject::GetData. You can then eliminate unnecessary calls to retrieve data if two different FORMATETC structures have the same canonical equivalent.

If the data object never provides device-specific renderings, the implementation of IDataObject::GetCanonicalFormatEtc simply copies the input FORMATETC to the output FORMATETC, stores a NULL in the ptd field of the output FORMATETC, and returns DATA_S_SAMEFORMATETC.

See Also

IDataObject::GetData, FORMATETC


IDataObject::GetData

Renders the data described in the specified FORMATETC structure and transfers it through the specified STGMEDIUM structure. The caller then assumes responsibility for releasing the STGMEDIUM structure. You use this method when you want to transfer data from a source object to a target.

HRESULT GetData(

FORMATETC * pFormatetc,	//Points to the data and formats to be transferred
STGMEDIUM * pmedium	//Points to the storage medium in which the returned data is transferred
);
Parameters

pFormatetc

[in]Points to the format, media, and target device to use when passing the data. If you specify more than one medium by using the Boolean OR operator on the value specified in TYMED, IDataObject::GetData chooses the medium that best represents the data, does the allocation, and decides what is responsible for the release. The decision is indicated through the value returned in the IUnknown returned as part of pmedium.

pmedium

[out]Points to the storage medium containing the returned data. The medium is allocated and filled in by IDataObject::GetData. STGMEDIUM includes a value for the IUnknown to call for releasing the medium.

Return Values

S_OK

Data was successfully retrieved and placed in the storage medium provided.

E_INVALIDARG

One or more arguments are invalid.

E_UNEXPECTED

An unexpected error occurred.

E_OUTOFMEMORY

The system did not retrieve data because it ran out of memory.

DV_E_LINDEX

Invalid value for lindex; currently, only -1 is supported.

DV_E_FORMATETC

Invalid value for pFormatetc.

DV_E_TYMED

Invalid tymed value.

DV_E_DVASPECT

Invalid dwAspect value.

OLE_E_NOTRUNNING

Object application is not running.

STG_E_MEDIUMFULL

An error occurred when allocating the medium.

Comments

The IDataObject::GetData method must check all fields in the FORMATETC structure. It is important that IDataObject::GetData renders the requested aspect and, if possible, uses the requested medium. If the data object cannot comply with the information specified in the FORMATETC, DV_E_FORMATETC is returned. If an attempt to allocate the medium fails, STG_E_MEDIUMFULL is returned. It is important to fill in all of the fields in the STGMEDIUM.

Although the caller can specify more than one medium for returning the data, only one medium can actually be returned. The IDataObject::GetData method chooses which medium to return. If this initial transfer fails, this method can try one of the other media specified before returning an error.

Data transferred across a stream extends from position zero of the stream pointer through to the position immediately before the current stream pointer (that is, the stream pointer position upon exit).

See Also

IDataObject::GetDataHere, IDataObject::SetData, FORMATETC, STGMEDIUM


IDataObject::GetDataHere

Renders the data described in a FORMATETC structure and transfers it through the STGMEDIUM structure allocated by the caller. You use this method when you want to transfer data from a source object to a target.

HRESULT GetDataHere(

FORMATETC * pFormatetc,	//Points to the data and formats to be transferred
STGMEDIUM * pmedium	//Points to the storage medium in which the returned data is transferred
);
Parameters

pFormatetc

[in]Points to the format, media, and target device to use when passing the data. Only one medium can be specified in TYMED.

The only values valid for TYMED are TYMED_STORAGE, TYMED_STREAM, TYMED_HGLOBAL, or TYMED_FILE.

pmedium

[out]Points to the storage medium containing the the returned data. The medium is allocated by the caller and filled in by IDataObject::GetDataHere. Since the caller allocates the medium, the caller is responsible for freeing the medium. The caller will always get a return value of NULL for the IUnknown specified for releasing the medium.

Return Values

S_OK

Data was successfully retrieved and placed in the storage medium provided.

E_INVALIDARG

One or more arguments are invalid.

E_UNEXPECTED

An unexpected error occurred.

E_OUTOFMEMORY

The system didn't retrieve data because it ran out of memory.

DV_E_LINDEX

Invalid value for lindex; currently, only -1 is supported.

DV_E_FORMATETC

Invalid value for pFormatetc.

DV_E_TYMED

Invalid tymed value.

DV_E_DVASPECT

Invalid dwAspect value.

OLE_E_NOTRUNNING

Object application is not running.

STG_E_MEDIUMFULL

The medium provided by the caller is not large enough to contain the data.

Comments

The IDataObject::GetDataHere method is similar to IDataObject::GetData except that the caller allocates the medium specified in pmedium and is responsible for freeing it. This method copies the data into the actual medium provided by the caller. For example, if the medium is TYMED_HGLOBAL, this method cannot resize the medium or allocate a new hGlobal.

When the transfer medium is a stream, OLE makes assumptions about where the data is being returned and the position of the stream's seek pointer. In a GetData call, the data returned is from stream position zero through just before the current seek pointer of the stream (that is, the position on exit). For GetDataHere, the data returned is from the stream position on entry through just before the position on exit. Note that some media are not appropriate when you are using GetDataHere, including GDI types such as metafiles. The GetDataHere	 method cannot put data into a caller-provided metafile.

See Also

IDataObject::GetData, FORMATETC, STGMEDIUM


IDataObject::QueryGetData

Determines whether the data object is capable of rendering the data described in the FORMATETC structure. Objects attempting a paste or drop operation can call this method before beginning the process. In some cases, the subsequent paste or drop operation may still fail.

HRESULT QueryGetData(

FORMATETC * pFormatetc	//Points to the data and formats to be used for the query
);
Parameter

pFormatetc

[in]Points to the format, media, and target device to use for the query.

Return Values

S_OK

Indicates a subsequent call to IDataObject::GetData would probably be successful.

E_INVALIDARG

One or more arguments are invalid.

E_UNEXPECTED

An unexpected error occurred.

E_OUTOFMEMORY

The process didn't execute because the system ran out of memory.

DV_E_LINDEX

Invalid value for lindex; currently, only -1 is supported.

DV_E_FORMATETC

Invalid value for pFormatetc.

DV_E_TYMED

Invalid tymed value.

DV_E_DVASPECT

Invalid dwAspect value.

OLE_E_NOTRUNNING

Object application is not running.

See Also

IDataObject::GetData, FORMATETC


IDataObject::SetData

Transfers data to the source data object.

HRESULT SetData(

FORMATETC * pFormatetc,	//Points to the data and formats used to interpret the data
STGMEDIUM * pmedium,	//Points to the storage medium in which the data is transferred
BOOL fRelease	//Indicates what owns the storage medium after the call is completed
);
Parameters

pFormatetc

[in]Points to the format used by the data object when interpreting the data contained in the storage medium.

pmedium

[in]Points to the storage medium.

fRelease

[in]Indicates what has ownership of the storage medium after the call is complete. If fRelease is TRUE, IDataObject::SetData takes ownership, freeing the medium after it has been used by calling ReleaseStgMedium. If fRelease is FALSE, the caller retains ownership and the callee uses the storage medium for the duration of the call only.

Return Values

S_OK

Data was successfully transferred.

E_FAIL

The data was not transferred.

E_NOTIMPL

This method is not implemented for the data object.

E_INVALIDARG

One or more arguments are invalid.

E_UNEXPECTED

An unexpected error occurred.

E_OUTOFMEMORY

The data wasn't transferred because the system ran out of memory.

DV_E_LINDEX

Invalid value for lindex; currently, only -1 is supported.

DV_E_FORMATETC

Invalid value for pFormatetc.

DV_E_TYMED

Invalid tymed value.

DV_E_DVASPECT

Invalid dwAspect value.

OLE_E_NOTRUNNING

Object application is not running.

Comments

The callee does not take ownership of the data until it has successfully used it and no error code is returned.

The type of medium (TYMED) in the pformatetc and pmedium parameters must be equal. For example, one cannot be an hGlobal and the other a stream.

See Also

IDataObject::GetData, FORMATETC, STGMEDIUM


IDropSource

The IDropSource interface is one of the interfaces you implement to provide drag-and-drop operations in your application. It contains methods used in any application used as a data source in a drag-and-drop operation. The data source application in a drag-and-drop operation is responsible for:

•	Determining the data being dragged based on the user's selection.

•	Initiating the drag-and-drop operation based on the user's mouse actions.

•	Generating some of the visual feedback during the drag-and-drop operation, such as setting the cursor and highlighting the data selected for the drag-and-drop operation.

•	Canceling or completing the drag-and-drop operation based on the user's mouse actions.

•	Performing any action on the original data caused by the drop operation, such as deleting the data on a drag move.

The IDropSource interface contains the methods for generating visual feedback to the end user and for canceling or completing the drag-and-drop operation. The DoDragDrop function, RegisterDragDrop function, and RevokeDragDrop function are also used in drag-and-drop operations.

When to Implement

Implement the IDropSource interface if you are developing a container or server application that can act as a data source for a drag-and-drop operation. The IDropSource interface is only required during the drag-and-drop operation.

If you implement the IDropSource interface, you must also implement the IDataObject interface to represent the data being transferred.

The IDataObject interface can be the same as the data object offered to the clipboard. Once you have implemented clipboard operations in your application, you can add drag-and-drop operations with only a little extra work.

When to Use

Your IDropSource methods are called by the DoDragDrop function. Your application calls the DoDragDrop function when it detects that the user has initiated a drag-and-drop operation. Then, DoDragDrop calls your IDropSource methods during the drag-and-drop operation.

For example, DoDragDrop calls IDropSource::GiveFeedback when you need to change the cursor shape or when you need to provide some other visual feedback. DoDragDrop calls IDropSource::QueryContinueDrag when there is a change in the mouse button state to determine if the drag-and-drop operation canceled or completed.

Methods in Vtable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments reference count.
Release	Decrements reference count.
IDropSource Methods	Description
QueryContinueDrag	Determines whether a drag-and-drop operation should continue.
GiveFeedback	Gives visual feedback to an end user during a drag-and-drop operation.
See Also

DoDragDrop, IDataObject, IDropTarget


IDropSource::GiveFeedback

Enables a source application to give visual feedback to its end user during a drag-and-drop operation by providing the DoDragDrop function with an enumeration value specifying the visual effect.

HRESULT GiveFeedback(

DWORD dwEffect	//Effect of a drop operation
);
Parameter

dwEffect

[in] Specifies the DROPEFFECT value returned by the most recent call to IDropTarget::DragEnter, IDropTarget::DragOver, or IDropTarget::DragLeave. For a list of values, see the DROPEFFECT enumeration.

Return Values

S_OK

The function completed its task successfully using the cursor set by the source application.

DRAGDROP_S_USEDEFAULTCURSORS

The function completed successfully using the OLE-provided, default cursor.

E_INVALIDARG

One or more arguments are invalid.

E_OUTOFMEMORY

Out of memory.

E_UNEXPECTED

An unexpected error occurred.

Comments

When your application detects that the user has started a drag-and-drop operation, you call the DoDragDrop function. DoDragDrop enters a loop, calling IDropTarget::DragEnter when the mouse first enters a drop target window, IDropTarget::DragOver when the mouse changes its position within the target window, and IDropTarget::DragLeave when the mouse leaves the target window.

For every call to either IDropTarget::DragEnter or IDropTarget::DragOver, DoDragDrop calls IDropSource::GiveFeedback, passing it the DROPEFFECT value returned from the drop target call. IDropSource::GiveFeedback is responsible for changing the cursor shape or for changing the highlighted source based on the value of the dwEffect parameter.

DoDragDrop calls IDropTarget::DragLeave when the mouse has left the target window. Then, DoDragDrop calls IDropSource::GiveFeedback and passes the DROPEFFECT_NONE value in the dwEffect parameter.

The dwEffect parameter can include   DROPEFFECT_SCROLL, indicating the source should put up the drag-scrolling variation of the appropriate pointer.

OLE defines a recommended set of cursor shapes that your application should use. See the User Interface Guidelines for more information.

Notes to Implementors

This function is called frequently during the DoDragDrop loop so you can gain performance advantages if you optimize your implementation as much as possible.

See Also

DoDragDrop, IDropTarget


IDropSource::QueryContinueDrag

Determines whether a drag-and-drop operation should be continued, canceled, or completed. You do not call this method directly. The OLE DoDragDrop function calls this method during a drag-and-drop operation.

HRESULT QueryContinueDrag(

BOOL fEscapePressed,	//Status of escape key since previous call
DWORD grfKeyState	//Current state of keyboard modifier keys
);
Parameters

fEscapePressed

[in] Specifies whether the Esc key has been pressed since the previous call to IDropSource::QueryContinueDrag or to DoDragDrop if this is the first call to QueryContinueDrag. A TRUE value indicates the end user has pressed the escape key; a FALSE value indicates it has not been pressed.

grfKeyState

[in] Identifies the current state of the keyboard modifier keys on the keyboard. Valid values can be a combination of any of the flags MK_CONTROL, MK_SHIFT, MK_ALT, MK_BUTTON, MK_LBUTTON, MK_MBUTTON, and MK_RBUTTON.

Return Values

S_OK

The drag operation should continue. This result occurs if no errors are detected, the mouse button starting the drag-and-rop operation has not been released, and the Esc key has not been detected.

DRAGDROP_S_DROP

The drop operation should occur completing the drag operation. This result occurs if grfKeyState indicates that the key that started the drag-and-drop operation has been released.

DRAGDROP_S_CANCEL

The drag operation should be canceled with no drop operation occurring. This result occurs if fEscapePressed is true indicating the Esc key has been pressed.

E_OUTOFMEMORY

Out of memory.

E_UNEXPECTED

An unexpected error occurred.

Comments

The DoDragDrop function calls IDropSource::QueryContinueDrag whenever it detects a change in the keyboard or mouse button state during a drag-and-drop operation. IDropSource::QueryContinueDrag determines whether the drag-and-drop operation should be continued, canceled, or completed based on the contents of the parameters grfKeyState and fEscapePressed.

See Also

DoDragDrop


IDropTarget

The IDropTarget interface is one of the interfaces you implement to provide drag-and-drop operations in your application. It contains methods used in any application that can be a target for data during a drag-and-drop operation. A drop-target application is responsible for:

•	Determining the effect of the drop on the target application.

•	Incorporating any valid dropped data when the drop occurs.

•	Communicating target feedback to the source so the source application can provide appropriate visual feedback such as setting the cursor.

•	Implementing drag scrolling.

•	Registering and revoking its application windows as drop targets.

The IDropTarget interface contains methods that provide all these responsibilities except registering and revoking the application window as a drop target.

When to Implement

Implement the IDropTarget interface if you are developing a container or server application that can act as a target for a drag-and-drop operation. The IDropTarget interface is associated with your application windows and is instantiated whenever the window is registered as a target for dropped data. You must call the RegisterDragDrop function and the RevokeDragDrop function to register and remove your application's windows as drop targets.

When to Use

The DoDragDrop function calls your IDropTarget methods within a loop during the drag-and-drop operation.

For example, DoDragDrop calls IDropTarget::DragEnter when it detects the mouse has moved over a window that is registered as a drag target. Once the mouse has entered a drag-target window, DoDragDrop calls IDropTarget::DragOver as the mouse moves through the window and calls IDropTarget::DragLeave if the mouse leaves the target window or if the user cancels or completes the drag-and-drop operation. DoDragDrop calls IDropTarget::Drop when the drop finally occurs if it occurs at all.

Methods in Vtable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments reference count.
Release	Decrements reference count.
IDropTarget Methods	Description
DragEnter	Determines whether a drop can be accepted and its effect if it is accepted.
DragOver	Provides target feedback to the user through the DoDragDrop function.
DragLeave	Causes the drop target to suspend its feedback actions.
Drop	Drops the data into the target window.
See Also

DoDragDrop, IDropSource, RegisterDragDrop, RevokeDragDrop


IDropTarget::DragEnter

Indicates whether or not a drop can be accepted and the drop's effect if accepted.

HRESULT DragEnter(

IDataObject * pDataObject,	//IDataObject interface for the source data
DWORD grfKeyState,	//Current state of keyboard modifier keys
POINTL pt,	//Current cursor coordinates
DWORD * pdwEffect	//Effect of the drag-and-drop operation
);
Parameters

pDataObject

[in] Points to the data object being transferred in the drag-and-drop operation. The data is represented in the IDataObject interface. If the drop occurs, this data object will be incorporated into the target.

grfKeyState

[in] Identifies the current state of the keyboard modifier keys on the keyboard. Valid values can be a combination of any of the flags MK_CONTROL, MK_SHIFT, MK_ALT, MK_BUTTON, MK_LBUTTON, MK_MBUTTON, and MK_RBUTTON.

pt

[in] Points to the current cursor coordinates in the coordinate space of the drop target window.

pdwEffect

[in, out] Specifies the current effect flag. Valid values are from the DROPEFFECT enumeration.

Return Values

S_OK

The function completed its task successfully.

E_OUTOFMEMORY

Out of memory.

E_INVALIDARG

One or more arguments are invalid.

E_UNEXPECTED

An unexpected error occurred.

Comments

The DoDragDrop function calls this method the first time the user drags the mouse into the registered window of a drop target.

In the IDropTarget::DragEnter method, you must determine the effect of dropping the data on the target by examining the formats and medium specified for the data object along with the state of the modifier keys. The following modifier keys affect the result of the drop:

Key Combination	User-Visible Feedback	Drop Effect
CTRL + SHIFT	=	DROPEFFECT_LINK
CTRL	+	DROPEFFECT_COPY
No keys or SHIFT	None	DROPEFFECT_MOVE
You communicate the effect of the drop back to the source through DoDragDrop in the pdwEffect parameter. The DoDragDrop function then calls IDropSource::GiveFeedback so that the source application can display the appropriate visual feedback to the user.

On entry to IDropTarget::DragEnter, the pdwEffect parameter is set to the effects given to the DoDragDrop function. The IDropTarget::DragEnter method must choose one of these effects or disable the drop.

Upon return, pdwEffect is set to either DROPEFFECT_COPY to copy the dragged data to the target, DROPEFFECT_LINK to create a link to the source data, or DROPEFFECT_MOVE to allow the dragged data to be permanently moved from the source application to the target.

You may also wish to provide appropriate visual feedback in the target window.

See Also

DoDragDrop, IDropSource, IDropTarget, RegisterDragDrop, RevokeDragDrop


IDropTarget::DragLeave

Removes target feedback and releases the data object.

HRESULT DragLeave(void);

Return Values

S_OK

The function completed its task successfully.

E_OUTOFMEMORY

Out of memory.

Comments

The DoDragDrop function calls this method in either of the following cases:

•	When the user drags the cursor out of a given target window.

•	When the user cancels the current drag-and-drop operation.

In the IDropTarget::DragLeave method, you must remove any target feedback that is currently displayed. You must also release any references you hold to the data transfer object.

See Also

DoDragDrop, IDropSource, IDropTarget, RegisterDragDrop, RevokeDragDrop


IDropTarget::DragOver

Provides target feedback to the user and communicates the drop's effect to the DoDragDrop function so the effect of the drop can be communicated through the DoDragDrop function back to the source.

HRESULT DragOver(

DWORD grfKeyState,	//Current state of keyboard modifier keys
POINTL pt,	//Current cursor coordinates
DWORD * pdwEffect	//Effect of the drag-and-drop operation
);
Parameters

grfKeyState

[in] Identifies the current state of the keyboard modifier keys on the keyboard. Valid values can be a combination of any of the flags MK_CONTROL, MK_SHIFT, MK_ALT, MK_BUTTON, MK_LBUTTON, MK_MBUTTON, and MK_RBUTTON.

pt

[in] Points to the current cursor coordinates in the coordinate space of the drop target window.

pdwEffect

[in, out] Specifies the current effect flag. Valid values are from the enumeration DROPEFFECT.

Return Values

S_OK

The function completed its task successfully.

E_OUTOFMEMORY

Out of memory.

E_INVALIDARG

One or more arguments are invalid.

E_UNEXPECTED

An unexpected error occurred.

Comments

The DoDragDrop function calls this method each time the user moves the mouse across a given target window. DoDragDrop exits the loop if the drag-and-drop operation is canceled, if the user drags the mouse out of the target window, or if the drop is completed.

In IDropTarget::DragOver, you must provide features similar to IDropTarget::DragEnter. You must determine the effect of dropping the data on the target by examining the formats and medium specified for the data object along with the state of the modifier keys. The mouse position may also play a role in determining the effect of a drop. The following modifier keys affect the result of the drop:

Key Combination	User-Visible Feedback	Drop Effect
CTRL + SHIFT	=	DROPEFFECT_LINK
CTRL	+	DROPEFFECT_COPY
No keys or SHIFT	None	DROPEFFECT_MOVE
You communicate the effect of the drop back to the source through DoDragDrop in pdwEffect. The DoDragDrop function then calls IDropSource::GiveFeedback so the source application can display the appropriate visual feedback to the user.

On entry to IDropTarget::DragOver, the pdwEffect parameter is set to the effects given to the DoDragDrop function. The IDropTarget::DragOver method must choose one of these effects or disable the drop.

Upon return, pdwEffect is set to either DROPEFFECT_COPY to copy the dragged data to the target, DROPEFFECT_LINK to create a link to the source data, or DROPEFFECT_MOVE to allow the dragged data to be permanently moved from the source application to the target.

You may also wish to provide appropriate visual feedback in the target window. There may be some target feedback already displayed from a previous call to IDropTarget::DragOver or from the initial IDropTarget::DragEnter. If this feedback is no longer appropriate, you should remove it.

For efficiency reasons, a data object is not passed in IDropTarget::DragOver. The data object passed in the most recent call to IDropTarget::DragEnter is available and can be used.

Notes to Implementors

This function is called frequently during the DoDragDrop loop so it makes sense to optimize your implementation of the DragOver method as much as possible.

See Also

DoDragDrop, IDropSource, IDropTarget, RegisterDragDrop, RevokeDragDrop


IDropTarget::Drop

Incorporates the source data into the target window, removes target feedback, and releases the data object.

HRESULT Drop(

IDataObject * pDataObject,	//IDataObject interface for the source data
DWORD grfKeyState,	//Current state of keyboard modifier keys
POINTL pt,	//Current cursor coordinates
DWORD * pdwEffect	//Effect of the drag-and-drop operation
);
Parameters

pDataObject

[in] Points to the data object being transferred in the drag-and-drop operation. The data is represented in the IDataObject interface.

grfKeyState

[in] Identifies the current state of the keyboard modifier keys on the keyboard. Valid values can be a combination of any of the flags MK_CONTROL, MK_SHIFT, MK_ALT, MK_BUTTON, MK_LBUTTON, MK_MBUTTON, and MK_RBUTTON.

pt

[in] Points to the current cursor coordinates in the coordinate space of the drop target window.

pdwEffect

[in, out] Specifies the current effect flag. Valid values are from the enumeration DROPEFFECT.

Return Values

S_OK

The function completed its tasks successfully.

E_OUTOFMEMORY

Out of memory.

E_INVALIDARG

One or more arguments are invalid.

E_UNEXPECTED

An unexpected error occurred.

Comments

The DoDragDrop function calls this method when the user completes the drag-and-drop operation.

In IDropTarget::Drop, you must incorporate the data object into the target. You can use the formats available in IDataObject along with the current state of the modifier keys to determine how the data is to be incorporated. This can be, for example, linking the data or embedding it.

In addition to incorporating the data, you must also clean up as you do in the IDropTarget::DragLeave method:

•	Remove any target feedback that is currently displayed.

•	Release any references to the data object.

You also pass the effect of this operation back to the source application through DoDragDrop, so the source application can clean up after the drag-and-drop operation is complete:

•	Remove any source feedback that is currently displaying.

•	Make any necessary changes to the data, for example, removing the data if the operation was a move.

See Also

DoDragDrop, IDropSource, IDropTarget, RegisterDragDrop, RevokeDragDrop


IEnumXXXX

To allow you to count the number of items of a given type an object maintains, OLE provides a set of enumeration interfaces, one for each type of item.

To use these interfaces, the client asks an object that maintains a collection of items to create an enumerator object. The interface on the enumeration object is one of the enumeration interfaces, all of which have a name of the form IEnumItem_name. Enumeration interfaces are specific to the type of item. All have the same set of methods, and are used in the same way. For example, by repeatedly calling the Next method, the client gets successive pointers to each item in the collection.

The following table lists the set of enumeration interfaces that OLE defines, and the items enumerated.

Enumeration Interface Name	Item Enumerated
IEnumFORMATETC	An array of FORMATETC structures
IEnumMoniker	The components of a moniker, or the monikers in a table.
IEnumOLEVERB	The different verbs available for an object, in order of ascending verb number.
IEnumSTATDATA	An array of STATDATA structures which contain advisory connection information for a data object.
IEnumSTATSTG	An array of STATSTG structures,which contain statistical information about a storage, stream, or LockBytes object
IEnumString	Strings
IEnumUnknown	Enumerates IUnknown interface pointers
IEnumVARIANT	A collection of variants. It allows clients to enumerate heterogeneous collections of objects and intrinsic types when the clients cannot or do not know the specific type(s) of elements in the collection
Methods in Vtable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments reference count.
Release	Decrements reference count.
IEnumXXXX Methods	Description
Next	Retrieves a specified number of items in the enumeration sequence.
Skip	Skips over a specified number of items in the enumeration sequence.
Reset	Resets the enumeration sequence to the beginning.
Clone	Creates another enumerator that contains the same enumeration state as the current one.


IEnumXXXX::Clone

Creates another enumerator that contains the same enumeration state as the current one. Using this function, a client can record a particular point in the enumeration sequence, and then return to that point at a later time. The new enumerator has the same interface as the original one.

HRESULT Clone(

IEnum<ELT_T> ** ppenum
);
Parameter

ppenum

[out] On exit, contains the duplicate enumerator. If the function was unsuccessful, this parameter's value is undefined.

Return Values

E_OUTOFMEMORY

Out of memory.

E_INVALIDARG

Value of ppenum is invalid.

E_UNEXPECTED

An unexpected error occurred.


IEnumXXXX::Next

Retrieves the next celt items in the enumeration sequence. If there are fewer than the requested number of elements left in the sequence, it retrieves the remaining elements. The number of elements actually retrieved is returned through pceltFetched (unless the caller passed in NULL for that parameter).

HRESULT Next(

ULONG celt,
ELT_T[ ] rgelt,
ULONG * pceltFetched
);
Parameters

celt

[in]The number of elements being requested.

rgelt

[out]Receives an array of size celt (or larger) of the elements to be returned. The type of this parameter depends on the item being enumerated.

pceltFetched

[in, out]On return, contains the number of elements actually returned in rgelt. Caller can pass in NULL if celt is one.

Return Value

S_OK if the number of elements returned is celt; S_FALSE otherwise.


IEnumXXXX::Reset

Resets the enumeration sequence to the beginning.

HRESULT Reset(void);

Return Value

S_OK

Comments

There is no guarantee that the same set of objects will be enumerated after the reset, because it depends on the collection being enumerated. It can be too expensive for some collections (such as files in a directory) to guarantee this condition.


IEnumXXXX::Skip

Skips over the next specified number of elements in the enumeration sequence.

HRESULT Skip(

ULONG celt
);
Parameter

celt

[in]The number of elements that are to be skipped.

Return Value

S_OK if the number of elements skipped is celt; otherwise S_FALSE.


IEnumFORMATETC

The IEnumFORMATETC interface is used to enumerate an array of FORMATETC structures. IEnumFORMATETC shares the same methods as all enumerator interfaces: Next, Skip, Reset, and Clone.

IEnumFORMATETC is implemented by all data objects to support calls to IDataObject::EnumFormatEtc. If the data object supports a different set of FORMATETC information depending on whether a call is made to SetData or GetData, the implementation of IEnumFORMATETC must be able to operate on both.

The order of formats enumerated through the IEnumFORMATETC object should be the same as the order that the formats would be in when placed on the clipboard. Typically, this order starts with private data formats and ends with presentation formats such as CF_METAFILEPICT.

The prototypes of the member functions are as follows:

HRESULT Next(ULONG celt, FORMATETC * rgelt, ULONG * pceltFetched)

HRESULT Skip(ULONG celt)

HRESULT Reset(void)

HRESULT Clone(IEnumFORMATETC ** ppenum)

See Also

OleRegEnumFormatEtc, FORMATETC, IEnumXXXX


IEnumMoniker

The IEnumMoniker interface is used to enumerate the components of a moniker or to enumerate the monikers in a table of monikers.

When to Implement

You need to implement IEnumMoniker if you are writing a new type of moniker and your monikers have an internal structure that can be enumerated. Your implementation of IMoniker::Enum must return an enumerator that implements IEnumMoniker and can enumerate your moniker's components. If your moniker has no structure that can be enumerated, your IMoniker::Enum method can simply return a NULL pointer.

When to Use

Use the IEnumMoniker interface if you need to enumerate the components of a composite moniker, or to enumerate the monikers in a table.

OLE defines two interfaces that return an IEnumMoniker interface pointer:

•	The IMoniker::Enum method returns an IEnumMoniker implementation that can enumerate forwards or backwards through the components of the moniker. For a description of how two of the system-supplied types of monikers enumerate their components, see IMoniker − File Moniker Implementation and IMoniker − Generic Composite Moniker Implementation.

•	The IRunningObjectTable::EnumRunning method returns an IEnumMoniker implementation that can enumerate the monikers registered in a Running Object Table.

The prototypes of the member functions are as follows:

HRESULT Next(ULONG celt, IMoniker * rgelt, ULONG * pceltFetched)

HRESULT Skip(ULONG celt)

HRESULT Reset(void)

HRESULT Clone(IEnumMoniker ** ppenum)

See Also

IEnumXXXX, IMoniker::Enum, IRunningObjectTable::EnumRunning


IEnumOLEVERB

The IEnumOLEVERB interface enumerates the different verbs available for an object in order of ascending verb number. An enumerator that implements the IEnumOLEVERB interface is returned by the IOleObject::EnumVerbs member function.

When to Implement

You typically do not have to implement this interface. The OLE default handler provides an implementation which returns the entries in the registration database. Because calls to IOleObject::EnumVerb are always routed through the default handler; an OLE application can let the default handler do the work by implementing IOleObject::EnumVerb as a stub that simply returns OLE_S_USEREG. This informs the default handler that it should create the enumerator for you.

When to Use

Call this interface if you need to list the verbs than an OLE object supports.

The prototypes of the member functions are as follows:

HRESULT Next(ULONG celt, OLEVERB * rgelt, ULONG * pceltFetched)

HRESULT Skip(ULONG celt)

HRESULT Reset(void)

HRESULT Clone(IEnumOLEVERB ** ppenum)

See Also

OLEVERB, IEnumXXXX


IEnumSTATDATA

The IEnumSTATDATA interface is used to enumerate through an array of STATDATA structures which contain advisory connection information for a data object. IEnumSTATDATA shares the same methods as all enumerator interfaces: Next, Skip, Reset, and Clone.

IEnumSTATDATA is implemented to enumerate advisory connections. Containers usually call methods that return a pointer to IEnumSTATDATA so the container can instruct an object to release each of its advisory connections prior to closing down. Calls to IDataObject::EnumDAdvise, IDataAdviseHolder::EnumAdvise, and IOleCache::EnumCache methods all return a pointer to IEnumSTATDATA.

The prototypes of the member functions are as follows:

HRESULT Next(ULONG celt, STATDATA * rgelt, ULONG * pceltFetched)

HRESULT Skip(ULONG celt)

HRESULT Reset(void)

HRESULT Clone(IEnumSTATDATA ** ppenum)

See Also

STATDATA, IEnumXXXX, IOleCache::EnumCache, IDataObject::EnumDAdvise, IDataAdviseHolder::EnumAdvise, IOleObject::EnumAdvise


IEnumSTATSTG

The IEnumSTATSTG interface is used to enumerate through an array of STATSTG structures which contain statistical information about an open storage, stream, or byte array object. IEnumSTATSTG shares the same methods as all enumerator interfaces: Next, Skip, Reset, and Clone.

IEnumSTATSTG is implemented to enumerate the elements of a storage object. Containers usually call methods that return a pointer to IEnumSTATSTG so the container can manage its storage object and the elements within it. Calls to the IStorage::EnumElements method returns a pointer to IEnumSTATDATA. The caller allocates an array of STATSTG structures and the IEnumSTATSTG methods fill in each structure with the statistics about one of the nested elements in the storage object. If present, the lpszName member of the STATSTG structure requires additional memory allocations through the IMalloc interface, and the caller is responsible for freeing this memory, if it is allocated, by calling the IMalloc::Free method. If the lpszName member is NULL, no memory is allocated, and, therefore, no memory needs to be freed.

The prototypes of the member functions are as follows:

HRESULT Next(ULONG celt, STATSTG * rgelt, ULONG * pceltFetched)

HRESULT Skip(ULONG celt)

HRESULT Reset(void)

HRESULT Clone(IEnumSTATSTG ** ppenum)

See Also

CoGetMalloc, IEnumXXXX, IStorage::EnumElements, STATSTG


IEnumString

IEnumString is defined to enumerate strings. LPWSTR is the type that indicates a pointer to a zero-terminated string of wide, i.e., Unicode, characters.

The prototypes of the member functions are as follows:

HRESULT Next(ULONG celt, LPWSTR * rgelt, ULONG * pceltFetched)

HRESULT Skip(ULONG celt)

HRESULT Reset(void)

HRESULT Clone(IEnumString ** ppenum)


IEnumUnknown

This enumerator enumerates objects with interface IUnknown. This enumerator is used by the IOleContainer interface to enumerate the objects in a compound document.

The prototypes of the member functions are as follows:

HRESULT Next(ULONG celt, IUnknown ** reelt, ULONG * pceltFetched)

HRESULT Skip(ULONG celt)

HRESULT Reset(void)

HRESULT Clone(IEnumUnknown * ppenum)

See Also

IOleContainer


IExternalConnection

The IExternalConnection interface enables an embedded object to keep track of external locks on it, thereby enabling the safe and orderly shutdown of the object following silent updates. An object that supports links either to itself or to some portion of itself (a range of cells in a spreadsheet, for example) should implement this interface to prevent possible loss of data during shutdown.

Such data loss can occur when an object happens to have unsaved changes at a time when its stub manager's count of strong external references has reached zero. This situation would arise, for example, at the end of a silent update, when the final link client breaks its connection to the object. With the severing of this connection, the stub manager's count of strong external references would reach zero, causing it to release its pointers to the object and initiate shutdown of the object. When the object calls IOleClientSite::SaveObject, its container's return call to IPersistStorage::Save would fail because the stub manager would no longer have a pointer to the object. Any unsaved changes to the object would be lost.

If the object manages its own count of external locks, rather than relying on the stub manager to do so, it can save its data before the stub manager has a chance to release its pointers. An object can obtain a count of external connections by implementing the IExternalConnection interface. The stub manager calls this interface whenever a new strong external reference is added or deleted. The object combines this count with its own tally of strong internal references to maintain an accurate total of all locks.

When to Implement

All embeddable compound-document objects that support links to themselves or portions of themselves should implement IExternalConnection to prevent possible data loss during shutdown. In addition, an in-place container should call OleLockRunning to hold a strong lock on its embedded objects.

When to Use

An object's stub manager should call IExternalConnection whenever an external connection is added or released.

Methods in VTable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments reference count.
Release	Decrements reference count.
IExternalConnection Methods	Description
AddConnection	Increments count of external locks.
ReleaseConnection	Decrements count of external locks.


IExternalConnection::AddConnection

Increments an object's count of its strong external connections (links).

HRESULT AddConnection(

DWORD exconn,	//Type of external connection
DWORD dwreserved	//Used by OLE to pass connection information
);
Parameters

exconn

[out] Specifies the type of external connection to the object. The only type of external connection currently supported by this interface is strong, which means that the object must remain alive as long as this external connection exists. Strong external connections are represented by the value  EXTCONN_STRONG = 0x0001, which is defined in the enumeration EXTCONN.

dwreserved

Passes information about the connection. This parameter is reserved for use by OLE. Its value can be zero, but not necessarily. Therefore, implementations of AddConnection should not contain blocks of code whose execution depends on whether a zero value is returned.

Return Value

DWORD value

The number of reference counts on the object; used for debugging purposes only.

Comments

An object created by a EXE object application relies on its stub manager to call IExternalConnection::AddConnection whenever a link client activates and therefore creates an external lock on the object. When the link client breaks the connection, the stub manager calls IExternalConnection::ReleaseConnection to release the lock.

Since DLL object applications exist in the same process space as their objects, they do not utilize RPC (remote procedure calls) and therefore do not have stub managers to keep track of external connections. Therefore, DLL object applications that support external links to their objects must implement IExternalConnection so link clients can directly call the interface to inform them when connections are added or released.

The following is a typical implementation for the AddConnection method:

DWORD XX::AddConnection(DWORD extconn, DWORD dwReserved)
{
return extconn&EXTCONN_STRONG ? ++m_cStrong : 0;
}

See Also

IExternalConnection::ReleaseConnection, IRunnableObject::LockRunning, OleLockRunning


IExternalConnection::ReleaseConnection

Decrements an object's count of its strong external connections (links).

HRESULT ReleaseConnection(

DWORD extconn,	//Type of external connection
DWORD dwreserved,	//Used by OLE to pass connection information
BOOL fLastReleaseCloses	//Indicates whether connection is last one or not
);
Parameters

extconn

[out] Specifies the type of external connection to the object. The only type of external connection currently supported by this interface is strong, which means that the object must remain alive as long as this external connection exists. Strong external connections are represented by the value  EXTCONN_STRONG = 0x0001, which is defined in the enumeration EXTCONN.

dwreserved

Passes information about the connection. This parameter is reserved for use by OLE. Its value can be zero, but not necessarily. Therefore, implementations of ReleaseConnection should not contain blocks of code whose execution depends on whether a zero value is returned.

fLastReleaseCloses

TRUE specifies that if the connection being released is the last external lock on the object, the object should close. FALSE specifies that the object should remain open until closed by the user or another process.

Return Value

DWORD value

The number of connections to the object; used for debugging purposes only.

Comments

If fLastReleaseCloses equals TRUE, calling ReleaseConnection causes the object to shut itself down. Calling this method is the only way in which a DLL object, running in the same process space as the container application, will know when to close following a silent update.

See Also

IExternalConnection::AddConnection


ILockBytes

The ILockBytes interface provides a byte array object used by the OLE-provided implementation of compound files. Its methods manipulate the byte array object that provides the physical storage for the root storage object of a compound file. The byte array for an ILockBytes implementation is backed by some physical storage, such as a disk file, global memory, or a database; and the ILockBytes implementation hides the details of accessing the physical storage.

When to Implement

OLE provides an implementation of the ILockBytes interface for its compound files. The OLE-provided ILockBytes interface presents a byte array stored in a physical disk file.

Most applications will never implement the ILockBytes interface. Instead, applications will typically call the StgCreateDocfile function to create a root storage object (in this case, an IStorage instance backed by a specified disk file); and this function internally creates an instance of the OLE-provided, file-based ILockBytes implementation.

OLE also provides a memory-based ILockBytes implementation (see CreateILockBytesOnHGlobal).

It is possible for an application to provide its own ILockBytes implementation. For example, a database application might want to implement an ILockBytes backed by the storage of its relational tables. However, it is strongly recommended that you use the OLE-provided implementations. For a discussion of the advantages of using the OLE implementations rather than creating your own, see the StgCreateDocfileOnILockBytes API function.

If you choose to implement your own ILockBytes interface, you should consider providing custom marshaling by implementing the IMarshal interface as part of your byte array object. The reason for this is that when the OLE-provided implementations of IStorage and IStream are marshaled to another process, their ILockBytes interface pointers are also marshaled to the other process. The default marshaling mechanism creates a proxy ILockBytes that transmits method calls back to the original LockBytes object. Custom marshaling can improve efficiency by creating a remote LockBytes object that can access the byte array directly.

When to Use

The ILockBytes methods are called by the OLE-provided implementations of IStorage and IStream, so application programmers do not need to call ILockBytes methods. If you write your own ILockBytes implementation, you can use the StgCreateDocfileOnILockBytes function to create an IStorage backed by your ILockBytes.

Methods in Vtable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments the reference count.
Release	Decrements the reference count.
ILockBytes Methods	Description
ReadAt	Reads a specified number of bytes starting at a specified offset from the beginning of the byte array.
WriteAt	Writes a specified number of bytes to a specified location in the byte array.
Flush	Ensures that any internal buffers maintained by the ILockBytes implementation are written out to the backing storage.
SetSize	Changes the size of the byte array.
LockRegion	Restricts access to a specified range of bytes in the byte array.
UnlockRegion	Removes the access restriction on a range of bytes previously restricted with ILockBytes::LockRegion.
Stat	Retrieves a STATSTG structure for this byte array object.


ILockBytes::Flush

Ensures that any internal buffers maintained by the ILockBytes implementation are written out to the backing storage.

HRESULT Flush(void);

Return Values

S_OK

The flush operation was successful.

STG_E_ACCESSDENIED

The caller does not have permission to access the byte array.

STG_E_MEDIUMFULL

The flush operation is not completed because there is no space left on the storage device.

E_FAIL

General failure writing data.

STG_E_TOOMANYFILESOPEN

Under certain circumstances, Flush does a dump-and-close to flush. This can lead to STG_E_TOOMANYFILESOPEN if there are no file handles available.

STG_E_INVALIDHANDLE

An invalid floppy change has been made.

Comments

This method flushes internal buffers to the underlying storage device.

The OLE-provided implementation of compound files uses this method during a transacted commit operation to provide a two-phase commit process that protects against loss of data.

See Also

IStorage::Commit


ILockBytes::LockRegion

Restricts access to a specified range of bytes in the byte array.

HRESULT LockRegion(

ULARGE_INTEGER libOffset,	//Specifies the byte offset for the beginning of the range
ULARGE_INTEGER cb,	//Specifies the length of the range in bytes
DWORD dwLockType	//Specifies the type of restriction on accessing the specified range
);
Parameters

libOffset

[in]Specifies the byte offset for the beginning of the range.

cb

[in]Specifies, in bytes, the length of the range to be restricted.

dwLockType

[in]Specifies the type of restrictions being requested on accessing the range. This parameter uses one of the values from the LOCKTYPE enumeration.

Return Values

S_OK

The specified range of bytes was locked.

STG_E_INVALIDFUNCTION

Locking is not supported at all or the specific type of lock requested is not supported.

STG_E_LOCKVIOLATION

Requested lock is supported, but cannot be granted because of an existing lock.

Comments

This method restricts access to the specified range of bytes. Once a region is locked, attempts by others to perform the restricted access must fail with the STG_E_ACCESSDENIED error.

The byte range can extend past the current end of the current byte array. Locking beyond the end of an array is useful as a method of communication between different instances of the byte array object without changing data that is actually part of the byte array. For example, an implementation of compound files could rely on locking past the current end of the array as a means of access control, using specific locked regions to indicate permissions currently granted.

Three types of locking can be supported: locking to exclude other writers, locking to exclude other readers or writers, and locking that allows only one requestor to obtain a lock on the given range, which is usually an alias for one of the other two lock types. A given byte array might support either of the first two types, or both. The lock type is specified by dwLockType, using a value from the LOCKTYPE enumeration.

To determine the lock types supported by a particular ILockBytes implementation, you can examine the grfLocksSupported member of the STATSTG structure returned by a call to ILockBytes::Stat.

Any region locked with ILockBytes::LockRegion must later be explicitly unlocked by calling ILockBytes::UnlockRegion with exactly the same values for the libOffset, cb, and dwLockType parameters. The region must be unlocked before the stream is released. Two adjacent regions cannot be locked separately and then unlocked with a single unlock call.

Notes to Callers

Since the type of locking supported is optional and can vary in different implementations of ILockBytes, you must provide code to deal with the STG_E_INVALIDFUNCTION error.

Notes to Implementors

Support for this method depends on how the storage objects built on top of the ILockBytes implementation is used. If you know that, at any given time, only one storage object can be opened on the storage device that underlies the byte array, then your ILockBytes implementation does not need to support locking. However, if multiple simultaneous openings of a storage object are possible, then region locking is needed to coordinate them.

A LockRegion implementation can choose to support all, some, or none of the lock types. For unsupported lock types, the implementation should return STG_E_INVALIDFUNCTION.

See Also

ILockBytes::Stat, ILockBytes::UnlockRegion, IStream::LockRegion, LOCKTYPE


ILockBytes::ReadAt

Reads a specified number of bytes starting at a specified offset from the beginning of the byte array object.

HRESULT ReadAt(

ULARGE_INTEGER ulOffset,	//Specifies the starting point for reading data
void *pv,	//Points to the buffer into which the data is read
ULONG cb,	//Specifies the number of bytes to read
ULONG *pcbRead	//Pointer to location that contains actual number of bytes read
);
Parameters

ulOffset

[in]Specifies the starting point from the beginning of the byte array for reading data.

pv

[in]Points to the buffer into which the byte array is read.

cb

[in]Specifies the number of bytes of data to attempt to read from the byte array.

pcbRead

[out]Pointer to a location where this method writes the actual number of bytes read from the byte array. You can set this pointer to NULL to indicate that you are not interested in this value. In this case, this method does not provide the actual number of bytes read.

Return Values

S_OK

Indicates that the specified number of bytes were read, or the maximum number of bytes were read up to the end of the byte array.

E_FAIL

Data could not be read from the byte array.

STG_E_ACCESSDENIED

The caller does not have permission to access the byte array.

Comments

This method reads bytes from the byte array object. It reports the number of bytes that were actually read. This value may be less than the number of bytes requested if an error occurs or if the end of the byte array is reached during the read.

It is not an error to read less than the specified number of bytes if the operation encounters the end of the byte array. Note that this is the same end of file behavior as found in MS-DOS FAT file system files.

See Also

ILockBytes::WriteAt


ILockBytes::SetSize

Changes the size of the byte array.

HRESULT SetSize(

ULARGE_INTEGER cb	//Specifies the new size of the byte array in bytes
);
Parameter

cb

[in]Specifies the new size of the byte array as a number of bytes.

Return Values

S_OK

The size of the byte array was successfully changed.

STG_E_ACCESSDENIED

The caller does not have permission to access the byte array.

STG_E_MEDIUMFULL

The byte array size is not changed because there is no space left on the storage device.

Comments

This method changes the size of the byte array. If the cb parameter is larger than the current byte array, the byte array is extended to the indicated size by filling the intervening space with bytes of undefined value. This operation is similar to the ILockBytes::WriteAt method if the seek pointer is past the current end-of-stream.

If the cb parameter is smaller than the current byte array, then the byte array is truncated to the indicated size.

Notes to Callers

Callers cannot rely on STG_E_MEDIUMFULL being returned at the appropriate time because of cache buffering in the operating system or network. However, callers must be able to deal with this return code because some ILockBytes implementations might support it.

See Also

ILockBytes::ReadAt, ILockBytes::WriteAt


ILockBytes::Stat

Retrieves a STATSTG structure containing information for this byte array object.

HRESULT Stat(

STATSTG *pstatstg,	//Location for STATSTG structure
DWORD grfStatFlag	//Values taken from the STATFLAG enumeration
);
Parameters

pstatstg

[out]Points to a STATSTG structure where this method places information about this byte array object. The pointer is NULL if an error occurs.

grfStatFlag

[in]Specifies that this method not return some of the fields in the STATSTG structure, thus saving a memory allocation operation. Values are taken from the STATFLAG enumeration.

Return Values

S_OK

The STATSTG structure was successfully returned at the specified location.

E_OUTOFMEMORY

The STATSTG structure was not returned due to a lack of memory for the name field in the structure.

STG_E_ACCESSDENIED

The STATSTG structure was not returned because the caller did not have access to the byte array.

STG_E_INSUFFICIENTMEMORY

The STATSTG structure was not returned due to a lack of memory.

STG_E_INVALIDFLAG

The value for the grfStateFlag parameter is not valid.

STG_E_INVALIDPOINTER

The value for the pStatStg parameter is not valid.

Comments

The OLE-provided IStorage::Stat implementation calls the ILockBytes::Stat method to retrieve information about a root storage object. If there is no reasonable name for the byte array, then the OLE-provided ILockBytes::Stat method returns NULL in the pwcsName field of the STATSTG structure.

See Also

STATFLAG, STATSTG


ILockBytes::UnlockRegion

Removes the access restriction on a previously locked range of bytes.

HRESULT UnlockRegion(

ULARGE_INTEGER libOffset,	//Specifies the byte offset for the beginning of the range
ULARGE_INTEGER cb,	//Specifies the length of the range in bytes
DWORD dwLockType	//Specifies the access restriction previously placed on the range
);
Parameters

libOffset

[in]Specifies the byte offset for the beginning of the range.

cb

[in]Specifies, in bytes, the length of the range that is restricted.

dwLockType

[in]Specifies the type of access restrictions previously placed on the range. This parameter uses a value from the LOCKTYPE enumeration.

Return Values

S_OK

The byte range was unlocked.

STG_E_INVALIDFUNCTION

Locking is not supported at all or the specific type of lock requested is not supported.

STG_E_LOCKVIOLATION

The requested unlock cannot be granted.

Comments

This method unlocks a region previously locked with the ILockBytes::LockRegion method. Locked regions must later be explicitly unlocked by calling ILockBytes::UnlockRegion with exactly the same values for the libOffset, cb, and dwLockType parameters. Two adjacent regions cannot be locked separately and then unlocked with a single unlock call.

See Also

ILockBytes::LockRegion, LOCKTYPE


ILockBytes::WriteAt

Writes the specified number of bytes starting at a specified offset from the beginning of the byte array.

HRESULT WriteAt(

ULARGE_INTEGER ulOffset,	//Specifies the starting point for writing data
void const *pv,	//Points to the buffer containing the data to be written
ULONG cb,	//Specifies the number of bytes to write
ULONG *pcbWritten	//Pointer to location that contains actual number of bytes written
);
Parameters

ulOffset

[in]Specifies the starting point from the beginning of the byte array for the data to be written.

pv

[in]Points to the buffer containing the data to be written.

cb

[in]Specifies the number of bytes of data to attempt to write into the byte array.

pcbRead

[out]Pointer to a location where this method specifies the actual number of bytes written to the byte array. You can set this pointer to NULL to indicate that you are not interested in this value. In this case, this method does not provide the actual number of bytes written.

Return Values

S_OK

Indicates that the specified number of bytes were written.

E_FAIL

A general failure occurred during the write.

STG_E_ACCESSDENIED

The caller does not have sufficient permissions for writing this byte array.

STG_E_MEDIUMFULL

The write operation was not completed because there is no space left on the storage device. The actual number of bytes written is still returned in pcbWritten.

Comments

This method writes the specified data at the specified location in the byte array. The number of bytes actually written is always returned in pcbWritten, even if an error is returned. If the byte count is zero bytes, the write operation has no effect.

If ulOffset is past the end of the byte array and cb is greater than zero, ILockBytes::WriteAt increases the size of the byte array. The fill bytes written to the byte array are not initialized to any particular value.

See Also

ILockBytes::ReadAt, ILockBytes::SetSize


IMalloc

The OLE implementation of IMalloc allocates, frees, and manages memory.

The OLE libraries and object handlers call the methods of the IMalloc implementation to manage memory. Those implementing object handlers should call CoGetMalloc to get a pointer to the IMalloc implementation to handle task memory management needs.

The IMalloc methods Alloc, Free, and Realloc are similar to the C library functions malloc, free, and realloc. For debugging, refer to the functions CoRegisterMallocSpy and CoRevokeMallocSpy.

Methods in Vtable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments the reference count.
Release	Decrements the reference count.
IMalloc Methods	Description
Alloc	Allocates a block of memory.
Free	Frees a previously allocated block of memory.
Realloc	Changes the size of a previously allocated block of memory.
GetSize	Returns the size in bytes of a previously allocated block of memory
DidAlloc	Determines if this instance of IMalloc was used to allocate the specified block of memory.
HeapMinimize	Minimizes the heap by releasing unused memory to the operating system.
See Also

CoGetMalloc, CoRegisterMallocSpy, CoRevokeMallocSpy


IMalloc::Alloc

Allocates a block of memory.

void * Alloc(

ULONG cb	//The size of the requested memory block in bytes
);
Parameter

cb

[in] Specifies the size (in bytes) of the memory block to be allocated.

Return Values

Pointer to the allocated memory block

Memory block allocated successfully.

NULL

Insufficient memory available.

Comments

The IMalloc::Alloc method allocates a memory block in essentially the same way that the C Library malloc function does.

The initial contents of the returned memory block are undefined − there is no guarantee that the block has been initialized, so you should initialize it in your code. The allocated block may be larger than cb bytes because of the space required for alignment and for maintenance information.

If cb is zero, IMalloc::Alloc allocates a zero-length item and returns a valid pointer to that item. If there is insufficient memory available, IMalloc::Alloc returns NULL.

Note  Applications should always check the return value from this method, even when requesting small amounts of memory, because there is no guarantee the memory will be allocated.

See Also

IMalloc::Free, IMalloc::Realloc, CoTaskMemAlloc


IMalloc::DidAlloc

Determines if this allocator was used to allocate the specified block of memory.

int DidAlloc(

void *pv	//The pointer to the memory block
);
Parameter

pv

Specifies the pointer to the memory block; can be a NULL pointer, in which case, -1 is returned.

Return Values

1

The memory block was allocated by this IMalloc instance.

0

The memory block was not allocated by this IMalloc instance.

-1

DidAlloc is unable to determine whether or not it allocated the memory block.

Comments

Calling IMalloc::DidAlloc is useful if a application is using multiple allocations, and needs to know whether a previously allocated block of memory was allocated by a particular allocation.

See Also

IMalloc::Alloc, IMalloc::HeapMinimize, IMalloc::Realloc


IMalloc::Free

Frees a previously allocated block of memory.

void Free(

void * pv	//Pointer to the memory block to be freed
);
Parameter

pv

[in] Points to the memory block to be freed.

Comments

IMalloc:Free frees a block of memory previously allocated through a call to IMalloc::Alloc or IMalloc::Realloc. The number of bytes freed equals the number of bytes that were allocated. After the call, the memory block pointed to by pv is invalid and can no longer be used.

Note  The pv parameter can be NULL. If so, this method has no effect.

See Also

IMalloc::Alloc, IMalloc::Realloc, CoTaskMemFree


IMalloc::GetSize

Returns the size (in bytes) of a previously allocated memory block previously allocated with IMalloc::Alloc or IMalloc::Realloc.

ULONG GetSize(

void *pv	//Points to the memory block fo which the size is requested
);
Parameter

pv

[in] Points to the memory block for which the size is requested.

Return Value

Either the size of the allocated memory block in bytes or, if pv is a NULL pointer, -1.

Comments

Returns the size (in bytes) of a memory block previously allocated with IMalloc::Alloc or IMalloc::Realloc.The size returned is the actual size of the allocation; it may be greater than the size requested when the allocation was made.

See Also

IMalloc::Alloc, IMalloc::Realloc


IMalloc::HeapMinimize

Minimizes the heap as much as possible by releasing unused memory to the operating system, coalescing adjacent free blocks and committing free pages.

void HeapMinimize();

Comments

Calling IMalloc::HeapMinimize is useful when an application has been running for some time and the heap may be fragmented.

See Also

IMalloc::Alloc, IMalloc::Free, IMalloc::Realloc


IMalloc::Realloc

Changes the size of a previously allocated memory block.

void *Realloc(

void *pv,	//The memory block to be reallocated
ULONG cb	//The size of the memory block in bytes
);
Parameters

pv

[in] Points to the memory block to be reallocated. It can be a NULL pointer, as discussed in the following Comments section.

cb

[in] Specifies the size of the memory block (in bytes) to be reallocated. It can be zero, as discussed in the following remarks.

Return Values

Reallocated memory block

Memory block successfully reallocated.

NULL

Insufficient memory or cb is zero and pv is not NULL.

Comments

The initial contents of the returned memory block are undefined - there is no guarantee that the block has been initialized, so you should initialize it in your code. The allocated block may be larger than cb bytes because of the space required for alignment and for maintenance information.

The pv argument points to the beginning of the memory block. If pv is NULL, IMalloc::Realloc allocates a new memory block in the same way as IMalloc::Alloc. If pv is not NULL, it should be a pointer returned by a prior call to IMalloc::Alloc.

The cb argument specifies the size (in bytes) of the new block. The contents of the block are unchanged up to the shorter of the new and old sizes, although the new block can be in a different location. Because the new block can be in a different memory location, the pointer returned by IMalloc::Realloc is not guaranteed to be the pointer passed through the pv argument. If pv is not NULL and cb is zero, then the memory pointed to by pv is freed.

IMalloc::Realloc returns a void pointer to the reallocated (and possibly moved) memory block. The return value is NULL if the size is zero and the buffer argument is not NULL, or if there is not enough memory available to expand the block to the given size. In the first case, the original block is freed; in the second, the original block is unchanged.

The storage space pointed to by the return value is guaranteed to be suitably aligned for storage of any type of object. To get a pointer to a type other than void, use a type cast on the return value.

See Also

IMalloc::Alloc, IMalloc::Free


IMallocSpy

The IMallocSpy interface is a debugging interface that allows application developers to monitor (spy on) memory allocation, detect memory leaks and simulate memory failure.

Caution  The IMallocSpy interface is intended to be used only to debug application code under development. Do not ship this interface to retail customers of your application, because it causes severe performance degradation and could conflict with user-installed software to produce unpredictable results.

When to Implement

Implement this interface to debug memory allocation during application development.

When to Use

IMallocSpy methods are called only by OLE; applications do not call them. An application provides an implementation of IMallocSpy (see the OLE SDK for an example); OLE uses this implementation. When an implementation of IMallocSpy is registered with CoRegisterMallocSpy, OLE calls the pair of IMallocSpy methods around the corresponding IMalloc method. The call to the pre-method through the return from the corresponding post-method is guaranteed to be thread-safe.

Methods in Vtable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments reference count.
Release	Decrements reference count.
IMallocSpy Methods	Description
PreAlloc	Called before invoking IMalloc::Alloc.
PostAlloc	Called after invoking IMalloc::Alloc.
PreFree	Called before invoking IMalloc::Free.
PostFree	Called after invoking IMalloc::Free.
PreRealloc	Called before invoking IMalloc::Realloc.
PostRealloc	Called after invoking IMalloc::Realloc.
PreGetSize	Called before invoking IMalloc::GetSize.
PostGetSize	Called after invoking IMalloc::GetSize.
PreDidAlloc	Called before invoking IMalloc::DidAlloc.
PostDidAlloc	Called after invoking IMalloc::DidAlloc.
PreHeapMinimize	Called before invoking IMalloc::DidAlloc.
PostHeapMinimize	Called after invoking IMalloc::HeapMinimize.
See Also

IMalloc, CoGetMalloc, CoRegisterMallocSpy


IMallocSpy::PreAlloc

Called just prior to invoking IMalloc::Alloc.

ULONG PreAlloc(

ULONG cbRequest	//The byte count passed to IMalloc::Alloc
);
Parameter

cbRequest

The number of bytes in the allocation request the caller is passing to IMalloc::Alloc.

Return Value

The byte count actually passed to IMalloc::Alloc, which should be greater than or equal to the value of cbRequest.

Comments

The IMallocSpy::PreAlloc implementation may extend and/or modify the allocation to store debug-specific information with the allocation.

PreAlloc can force memory allocation failure by returning 0, allowing testing to ensure that the application handles allocation failure gracefully in all cases. In this case PostAlloc is not called and Alloc returns NULL. Forcing allocation failure is effective only if cbRequest is not equal to 0. If PreAlloc is forcing failure by returning NULL, PostAlloc is not called. However, if IMalloc::Alloc encounters a real memory failure and returns NULL, PostAlloc is called.

The call to PreAlloc through the return from PostAlloc is guaranteed to be thread safe.

See Also

IMalloc::Alloc, IMallocSpy::PostAlloc, CoRegisterMallocSpy, CoRevokeMallocSpy


IMallocSpy::PostAlloc

Called just after invoking IMalloc::Alloc.

void * PostAlloc(

void * pActual	//Points to the allocation actually done by IMalloc::Alloc
);
Parameter

pActual

Points to the allocation actually done by IMalloc::Alloc.

Return Value

The pointer returned to the IMalloc::Alloc caller. If debug information is written at the front of the caller's allocation, this should be a forward offset from pActual. The value is the same as pActual if debug information is appended or if no debug information is attached.

See Also

IMalloc::Alloc, IMallocSpy::PreAlloc, CoRegisterMallocSpy, CoRevokeMallocSpy


IMallocSpy::PreDidAlloc

Called just prior to invoking IMalloc::DidAlloc.

void * PreDidAlloc(

void * pRequest,	//The pointer the caller is passing to IMalloc::DidAlloc
BOOL fSpyed	//Indicates whether pRequest was allocated while this spy was active
);
Parameters

pRequest

The pointer the caller is passing to IMalloc::GetSize.

fSpyed

TRUE if the allocation was done while this spy was active.

Comments

This method is included for completeness; it is not anticipated that developers will implement significant functionality in this method.

Return Value

The pointer whose allocation status is actually determined. This pointer is passed to PostDidAlloc as the fActual parameter.

See Also

IMalloc::DidAlloc, IMallocSpy::PostDidAlloc, CoRegisterMallocSpy, CoRevokeMallocSpy


IMallocSpy::PostDidAlloc

Called just prior to invoking IMalloc::DidAlloc.

int PostDidAlloc(

void * pRequest	//The original pointer passed to IMalloc::DidAlloc
BOOL fSpyed	//Indicates whether the allocation was done while this spy was active
int fActual	//Indicates whether pRequest was actual value used in IMalloc call
);
Parameters

pRequest

The pointer specified in the original call to IMalloc::DidAlloc.

fSpyed

TRUE if the allocation was done while this spy was active.

fActual

The actual value returned by IMalloc::DidAlloc.

Return Value

The value returned to the caller of IMalloc::DidAlloc.

Comments

This method is included for completeness; it is not anticipated that developers will implement significant functionality in this method.

For convenience, pRequest, the original pointer specified in the the call to IMalloc::DidAlloc is passed to PostDidAlloc, along with fActual, which is the actual value returned by IMalloc::DidAlloc called with the value returned by IMallocSpy::PreDidAlloc.

See Also

IMalloc::DidAlloc, IMallocSpy::PreDidAlloc, CoRegisterMallocSpy, CoRevokeMallocSpy


IMallocSpy::PreFree

Called just before invoking IMalloc::Free.

void * PreFree(

void * pRequest,	//The pointer is passing to IMalloc::Free
BOOL fSpyed	//TRUE if this memory was allocated while the spy was active
);
Parameters

pRequest

The pointer to the block of memory that the caller is passing to IMalloc::Free.

fSpyed

The value is TRUE if the pRequest parameter of IMallocSpy::PreFree was allocated while the spy was installed. This value is also passed to IMallocSpy::PostFree.

Return Value

The actual pointer to pass to IMalloc::Free.

Comments

If the PreAlloc method modified the original allocation, PreFree needs to compute the actual pointer to be passed to IMalloc::Free. For example, if the PreAlloc/PostAlloc pair attached a header used to store debug information to the beginning of the user's allocation, then PreFree would return a pointer to this header so the true allocation block would be freed.

See Also

IMalloc::Free, IMallocSpy::PostFree, CoRegisterMallocSpy, CoRevokeMallocSpy


IMallocSpy::PostFree

Called just after invoking IMalloc::Free.

void PostFree(

BOOL fSpyed	//Indicates whether the memory block to be freed was allocated while the spy is active
);
Parameter

fSpyed

Boolean that is TRUE if the memory block to be freed was allocated while the current spy was active, otherwise FALSE.

See Also

IMalloc::Free, IMallocSpy::PreFree, CoRegisterMallocSpy, CoRevokeMallocSpy


IMallocSpy::PreGetSize

Called just prior to invoking IMalloc::GetSize.

void * PreGetSize(

void * pRequest,	//Pointer the caller is passing to IMalloc::GetSize
BOOL fSpyed	//TRUE if allocation done while this spy was active
);
Parameters

pRequest

The pointer the caller is passing to IMalloc::GetSize

fSpyed

TRUE if the allocation was done while the spy was active.

Return Value

Pointer to the actual allocation for which the size is to be determined.

Comments

The PreGetSize method receives as its pRequest parameter the pointer the caller is passing to IMalloc::GetSize. It must then return a pointer to the actual allocation, which is then passed to PostGetSize as the pRequest parameter.

The size determined by IMalloc::GetSize is then passed to IMallocSpy::PostGetSize as cbActual.

Note  The size determined by IMalloc::GetSize is the value returned by the Win32 API HeapSize. On Windows NT, this is the size originally requested. On Windows95, memory allocations are done on eight-byte boundaries. For example, a memory allocation request of 27 bytes on Windows NT would return an allocation of 32 bytes and GetSize would return 27. On Windows95, the same request would return an allocation of 28 bytes and GetSize would return 28. Implementors of IMallocSpy::PostGetSize cannot assume, for example, that if cbActual is sizeof(debug_header), that the value is the actual size of the user's allocation.

See Also

IMalloc::GetSize, IMallocSpy::PostGetSize, CoRegisterMallocSpy, CoRevokeMallocSpy


IMallocSpy::PostGetSize

Called just after invoking IMalloc::GetSize.

ULONG PostGetSize(

ULONG cbActual,	//Actual size of the allocation
BOOL fSpyed	//Indicates whether the allocation was done while a spy was active
);
Parameters

cbActual

The actual number of bytes in the allocation, as returned by IMalloc::GetSize.

fSpyed

TRUE if the allocation was done while a spy was active.

Return Values

The size of the allocated memory block in bytes, which is returned to the caller of IMalloc::GetSize.

Comments

The size determined by IMalloc::GetSize is the value returned by the Win32 API HeapSize. On Windows NT, this is the size originally requested. On Windows95, memory allocations are done on eight-byte boundaries. For example, a memory allocation request of 27 bytes on Windows NT would return an allocation of 32 bytes and GetSize would return 27. On Windows95, the same request would return an allocation of 28 bytes and GetSize would return 28. Implementors of IMallocSpy::PostGetSize cannot assume, for example, that if cbActual is sizeof(debug_header), that the value is the actual size of the user's allocation.

See Also

IMalloc::GetSize, IMallocSpy::PreGetSize, CoRegisterMallocSpy, CoRevokeMallocSpy


IMallocSpy::PreHeapMinimize

Called just prior to invoking IMalloc::HeapMinimize.

void PreHeapMinimize(void);

Comments

This method is included for completeness; it is not anticipated that developers will implement significant functionality in this method.

See Also

IMalloc::HeapMinimize, IMallocSpy::PostHeapMinimize, CoRegisterMallocSpy, CoRevokeMallocSpy


IMallocSpy::PostHeapMinimize

Called just after invoking IMalloc::HeapMinimize.

void PostHeapMinimize(void);

Comments

This method is included for completeness; it is not anticipated that developers will implement significant functionality in this method.

See Also

IMalloc::HeapMinimize, IMallocSpy::PreHeapMinimize, CoRegisterMallocSpy, CoRevokeMallocSpy


IMallocSpy::PreRealloc

Called just before invoking IMalloc::Alloc.

ULONG PreRealloc(

void * pRequest,	//The pointer the caller is passing to IMalloc::Realloc
ULONG cbRequest,	//The byte count the caller is passing to IMalloc::Realloc
void ** ppNewRequest,	//Points to the actual pointer to be reallocated
BOOL fSpyed	//Whether the original allocation was "spyed"
   );

Parameters

pRequest

The pointer the caller is passing to IMalloc::Realloc.

cbRequest

The byte count the caller is passing to IMalloc::Realloc.

ppNewRequest

[out] Points to the actual pointer to be reallocated. This may be different from the pointer in pRequest if the implementation of IMallocSpy::PreRealloc extends or modifies the reallocation. This is an out pointer and should always be stored by PreRealloc.

fSpyed

TRUE if the original allocation was done while the spy was active.

Return Value

The actual byte count to be passed to IMalloc::Realloc.

Comments

The IMallocSpy::PreRealloc implementation may extend and/or modify the allocation to store debug-specific information with the allocation. Thus, the ppNewRequest parameter may differ from pRequest, which the caller is passing to IMalloc::Realloc.

PreRealloc can force memory allocation failure by returning 0, allowing testing to ensure that the application handles allocation failure gracefully in all cases. In this case PostRealloc is not called and Realloc returns NULL. Forcing allocation failure is effective only if cbRequest is not equal to 0. Note that if PreRealloc is forcing failure by returning NULL, PostRealloc is not called. However, if IMalloc::Realloc encounters a real memory failure and returns NULL, PostRealloc is called.

See Also

IMalloc::Realloc, IMallocSpy::PostRealloc, CoRegisterMallocSpy, CoRevokeMallocSpy


IMallocSpy::PostRealloc

Called after invoking IMalloc::Realloc.

void * PostRealloc(

void * pActual,	//The pointer returned by IMalloc::Realloc
BOOL fSpyed	//Indicates whether the original allocation was "spyed"
);
Parameters

pActual

Points to the memory block reallocated by IMalloc::Realloc.

fSpyed

If TRUE, the original memory allocation was done while the spy was active.

Return Values

The pointer to be returned to the IMalloc::Realloc caller. If debug information is written at the front of the caller's allocation, it should be a forward offset from pActual. The value should be the same as pActual if debug information is appended or if no debug information is attached.

See Also

IMalloc::Realloc, IMallocSpy::PreRealloc, CoRegisterMallocSpy, CoRevokeMallocSpy


IMarshal

The IMarshal interface allows an object to perform custom marshaling of interface pointers.

"Marshaling" is the process of packaging function parameters into data packets in order to send them to a different process or machine. "Unmarshaling" is the process of recovering those parameters when they are received. When a remote function call passes an interface pointer as a function parameter, that pointer is marshaled in such a way that it becomes possible for a client in one process to use that interface pointer to call methods on an object in another process.

OLE marshals an interface pointer by creating a proxy object in the client's process. A client holds an interface pointer to the proxy object and calls methods using that pointer; the proxy marshals the method parameters and sends them to the original process, thus forwarding the method call to the original object. The IMarshal interface allows an object to control what kind of proxies are created.

When to Implement

You almost never need to implement this interface. OLE provides a default implementation of IMarshal that uses OLE-generated proxy objects; this is suitable for almost all situations. You implement the IMarshal interface only if you want to perform custom marshaling; this allows you to write your own proxy objects.

OLE uses your implementation of IMarshal in the following manner: When it's necessary to create a remote interface pointer to your object (that is, when a pointer to your object is passed as a parameter in a remote function call), OLE queries your object for the IMarshal interface. If your object implements it, OLE uses your IMarshal implementation to create the proxy object. If your object does not implement IMarshal, OLE uses its standard implementation.

Some situations in which you might want to perform custom marshaling are as follows:

•	The objects you are writing keep their state in shared memory. In this case, both the original process and the client process uses proxies that refer to the shared memory. This type of custom marshaling is possible only if the client process is on the same machine as the original process. The compound file implementations of IStorage and IStream are examples of this type of custom marshaling.

•	The objects you are writing are immutable, that is, their state does not change after creation. Instead of forwarding method calls to the original objects, you can simply create copies of those objects in the client process. This technique avoids the cost of context switches (switching from one process to another). Monikers are an example of immutable objects; if you are implementing your own moniker class, you should perform custom marshaling.

Note that these situations do not require you to create a separate class of proxy objects; the same objects are used by both the original process and the client process. In other situations, you may need to write a separate class of proxy objects (with its own CLSID) that forward calls to the original objects, in addition to implementing IMarshal on the original objects.

When to Use

You typically do not need to call this interface. OLE is the primary user of this interface.

Methods in VTable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments reference count.
Release	Decrements reference count.
IMarshal Methods	Description
GetUnmarshalClass	Returns CLSID of unmarshaling code.
GetMarshalSizeMax	Returns size of buffer needed during marshaling.
MarshalInterface	Marshals an interface pointer.
UnmarshalInterface	Unmarshals an interface pointer.
ReleaseMarshalData	Destroys a marshaled data packet.
DisconnectObject	Severs all connections.
See Also

IStdMarshalInfo


IMarshal::DisconnectObject

Severs remote connections (that is, connections from other processes) being maintained on behalf of any interface pointers on the current object.

HRESULT IMarshal::DisconnectObject(

DWORD dwReserved	//Reserved for future use
);
Parameter

dwReserved

[in] Reserved for future use; must be set to zero by the caller. To ensure compatibility with future use, the callee must not check for zero.

Return Values

S_OK

The object was disconnected successfully.

E_FAIL

Indicates an unspecified error.

E_OUTOFMEMORY

Out of memory.

E_INVALIDARG

One or more arguments were invalid.

E_UNEXPECTED

An unexpected error occured.

Comments

This method is called from the originating side (that is, the side doing the marshaling).

This method is called by the CoDisconnectObject API function if the object being disconnected implements the IMarshal interface. This is analogous to the way the CoMarshalInterface API function defers to the IMarshal::MarshalInterface method if the object supports IMarshal.

Notes to Implementors

If you are doing custom marshaling of immutable objects, your implementation doesn't need to do anything because there are no remote connections.

See Also

CoDisconnectObject


IMarshal::GetMarshalSizeMax

Returns an upper bound on the amount of data that would be written to the marshaling stream in a call to IMarshal::MarshalInterface.

HRESULT IMarshal::GetMarshalSizeMax(

REFIID riid,	//Identifies interface to be marshaled
void *pv,	//Points to interface pointer to be marshaled
DWORD dwDestContext,	//Identifies destination process
void * pvDestContext,	//Reserved for future use
DWORD mshlflags,	//Specifies reason for marshaling
ULONG * pSize	//Receives upper bound
);
Parameters

riid

[in]Specifies the IID of the interface pointer to be marshaled.

pv

[in]Points to the interface pointer to be marshaled; can be NULL.

dwDestContext

[in] Specifies the destination context, that is, the process in which the unmarshaling will be done. Different marshaling can be done depending on whether the unmarshaling will happen on the local workstation or on a workstation on the network; it's possible for an object to do custom marshaling in one case but not another. The legal values for dwDestContext are taken from the enumeration MSHCTX. For information on the MSHCTX enumeration, see the "Data Structures" section.

pvDestContext

[in] Reserved for use with future MSHCTX values.

mshlflags

[in] Specifies why marshaling is taking place. The legal values for mshlflags are taken from the enumeration MSHLFLAGS. For information on the MSHLFLAGS enumeration, see the "Data Structures" section.

pSize

[out]Receives the upper bound on the amount of data that would be written to the marshaling stream.

Return Values

S_OK

Maximum size was returned successfully.

E_FAIL

Indicates that the implementation failed.

E_NOINTERFACE

The specified interface was not supported.

Comments

This method is called from the originating side (that is, the side doing the marshaling). This method is used to preallocate the stream buffer that will be passed to IMarshal::MarshalInterface.

Notes to Implementors

The value your implementation returns must be an upper bound; a subsequent call to your implementation of IMarshal::MarshalInterface must use no more than the number of bytes returned by this method. The upper bound you return can be used by the caller to preallocate a stream buffer for using during marshaling.

See Also

IMarshal::MarshalInterface


IMarshal::GetUnmarshalClass

Returns the CLSID that should be used to create an uninitialized proxy on the receiving side (that is, the side doing the unmarshaling).

HRESULT IMarshal::GetUnmarshalClass(

REFIID riid,	//Identifies the interface being marshaled
void * pv,	//Points to the interface pointer being marshaled
DWORD dwDestContext,	//Identifies the destination process
void * pvDestContext,	//Reserved for future use
DWORD mshlflags,	//Specifies reason for marshaling
CLSID * pCid	//Receives CLSID of proxy
);
Parameters

riid

[in]Specifies the IID of the interface pointer to be marshaled.

pv

[in]Points to the interface pointer to be marshaled; can be NULL.

dwDestContext

[in] Specifies the destination context, that is, the process in which the unmarshaling will be done. Different marshaling can be done depending on whether the unmarshaling will happen on the local workstation or on a workstation on the network; it's possible for an object to do custom marshaling in one case but not another. The legal values for dwDestContext are taken from the enumeration MSHCTX. For information on the MSHCTX enumeration, see the "Data Structures" section.

pvDestContext

[in] Reserved for use with future MSHCTX values.

mshlflags

[in] Specifies why marshaling is taking place. Values for mshlflags are taken from the enumeration MSHLFLAGS. For information on the MSHLFLAGS enumeration, see the "Data Structures" section.

pCid

[out] Receives the CLSID to be used to create a proxy on the receiving side (that is, the side doing the unmarshaling).

Return Value

Returns S_OK if successful; otherwise, S_FALSE.

Comments

This method is called from the originating side (that is, the side doing the marshaling).

Notes to Implementors

The CLSID returned by this method identifies the class of the proxy object. This CLSID is typically written to a stream on the originating side and then read from the stream on the receiving side. Note that if you are creating a copy of the original object in the client process (that is, you are implementing custom marshaling for immutable objects), the CLSID returned is the same one as for the original object.

Your implementation can delegate some destination contexts to the standard marshaling implementation, available by calling the CoGetStandardMarshal API function. You should always delegate if the dwDestContext parameter contains a value that your implementation does not understand; this allows new destination contexts to be defined in the future.

You may want your implementation to use the pointer passed through the pv parameter, and, based on information retrieved from that pointer, determine the appropriate CLSID to return. If the pv parameter is NULL and your implementation needs that interface pointer, it can call IUnknown::QueryInterface on the current object to get it. The pv parameter exists merely to improve efficiency.


IMarshal::MarshalInterface

Marshals an interface pointer into the stream, that is, writes the appropriate data into the stream so that your IMarshal::UnmarshalInterface method can use that data to initialize a proxy object in another process.

HRESULT IMarshal::MarshalInterface(

IStream *pStm,	//Stream used for marshaling
REFIID riid,	//Identifies interface being marshaled
void *pv,	//Points to interface pointer being marshaled
DWORD dwDestContext,	//Identifies destination process
void *pvDestContext,	//Reserved for future use
DWORD mshlflags	//Specifies reason for marshaling
);
Parameters

pStm

[in]Points to the stream to be used during marshaling.

riid

[in]Specifies the IID of the interface pointer to be marshaled.

pv

[in]Points to the interface pointer to be marshaled; can be NULL.

dwDestContext

[in] Specifies the destination context, that is, the process in which the unmarshaling will be done. Different marshaling can be done depending on whether the unmarshaling will happen on the local workstation or on a workstation on the network; it's possible for an object to do custom marshaling in one case but not another. The legal values for dwDestContext are taken from the enumeration MSHCTX. For information on the MSHCTX enumeration, see the "Data Structures" section.

pvDestContext

[in] Reserved for use with future MSHCTX values.

mshlflags

[in]Specifies why marshaling is taking place. The legal values for mshlflags are taken from the MSHLFLAGS enumeration. For information on the MSHLFLAGS enumeration, see the "Data Structures" section.

Return Values

S_OK

The interface pointer was marshaled successfully.

E_FAIL

Indicates that the implementation failed.

E_NOINTERFACE

The specified interface was not supported.

STG_E_MEDIUMFULL

The stream was full.

Comments

This method is called from the originating side (that is, the side doing the marshaling). This method sends information to the receiving side by writing that information into the stream; on the receiving side, the information will be read from the stream and used to initialize a proxy object.

Notes to Implementors

Your implementation of IMarshal::MarshalInterface must write to the stream whatever data is needed to initialize the proxy on the receiving side. Your implementation can delegate some destination contexts to the standard marshaling implementation, which is available by calling the CoGetStandardMarshal API function. You should always delegate if the dwDestContext parameter contains a value that your implementation does not understand; this allows new destination contexts to be defined in the future.

Your implementation cannot assume the stream is large enough to hold all the data; it must still take into account the possibility that the stream may return STG_E_MEDIUMFULL errors. Just before exiting, your implementation should position the seek pointer in the stream immediately after the last byte of data written.

Note that the data marshaled by IMarshal::MarshalInterface can be unmarshaled zero or more times; this may happen if the marshaled data is stored in a global table, from which it may be unmarshaled many times by different client processes. Marshalers must be able to handle the result of multiple unmarshalings. For example, suppose the unmarshaling process creates a proxy that forwards calls to a stub interface in the server application; this stub interface must be able to deal with zero or more proxies being created from the same initialization data.

If the pv parameter is NULL and your implementation needs that interface pointer, it can call IUnknown::QueryInterface on the current object to get it. The pv parameter exists merely to improve efficiency.

See Also

CoGetStandardMarshal, IMarshal::GetMarshalSizeMax, IMarshal::GetUnmarshalClass, IMarshal::UnmarshalInterface


IMarshal::ReleaseMarshalData

Destroys a marshaled data packet.

HRESULT IMarshal::ReleaseMarshalData(

IStream * pStm	//Stream used for unmarshaling
);
Parameter

pStm

[in] Points to a stream that contains the data packet which is to be destroyed.

Return Values

S_OK

The data packet was released successfully.

E_FAIL

Indicates an unspecified error.

E_OUTOFMEMORY

Out of memory.

E_INVALIDARG

One or more arguments were invalid.

E_UNEXPECTED

An unexpected error occured.

IStream errors

See the IStream interface for information on possible stream access errors.

Comments

This method is typically called from the receiving side (that is, the side doing the unmarshaling), sometimes via the CoReleaseMarshalData or CoUnmarshalInterface API functions. However, if the data packet does not arrive on the receiving side or if the appropriate proxy object cannot be successfully created there, this method is called from the originating side (that is, the side doing the marshaling).

As an analogy, the data packet can be thought of as a reference to the original object, just as if it were another interface pointer being held on the object. Like a real interface pointer, that data packet must be released at some point. The use of IMarshal::ReleaseMarshalData to release data packets is analogous to the use of IUnknown::Release to release interface pointers.

Notes to Implementors

If your implementation stores state information about marshaled data packets, use this method to release the state information associated with the data packet found in pstm. Your implementation should also position the seek pointer in the stream past the last byte of data.

See Also

CoUnMarshalInterface, CoReleaseMarshalData


IMarshal::UnmarshalInterface

Initializes a newly created proxy and returns an interface pointer to that proxy.

HRESULT IMarshal::UnmarshalInterface(

IStream * pStm,	//Stream used for unmarshaling
REFIID riid,	//IID of interface pointer desired
void ** ppv	//Receives the interface pointer
);
Parameters

pStm

[in]Points to the stream from which the interface pointer is to be unmarshaled.

riid

[in]Specifies the IID of the interface pointer desired.

ppv

[out]Receives the interface pointer.

Return Values

S_OK

The interface pointer was unmarshaled successfully.

E_FAIL

Indicates that the implementation failed.

E_NOINTERFACE

The specified interface was not supported.

Comments

This method is called from the receiving side (that is; the side doing the unmarshaling). This method is called on the proxy object itself; that is; the object whose CLSID was returned by IMarshal::GetUnmarshalClass.

Notes to Implementors

Your implementation should read the data written to the stream by your implementation of IMarshal::MarshalInterface and use that data to initialize the proxy object.

To return the appropriate interface pointer; your implementation can simply call IUnknown::QueryInterface on itself, passing the riid and ppv parameters. However; your implementation is free to create a different object and return a pointer to that object; if you find it necessary.

Just before exiting; your implementation should position the seek pointer in the stream immediately after the last byte of data read. This should be done even if the method exits with an error.

See Also

IMarshal::GetUnmarshalClass, IMarshal::MarshalInterface


IMessageFilter

This IMessageFilter interface allows applications to handle incoming or outgoing messages selectively while waiting for responses from synchronous calls. The ability to filter messages is often useful when a dialog box is being displayed or a lengthy operation is in progress. Performance can be improved when applications handle some messages and defer others.

When to Implement

Implement IMessageFilter in place of OLE's default message handling when there is a need to selectively handle incoming or outgoing messages, while at the same time waiting for responses from synchronous calls.

Although not as significant an issue as with 16-bit applications, you may still need to implement IMessageFilter as a way of solving deadlocks. IMessageFilter is still needed to find out if an application is blocking, so that you can task-switch to that application and give the user an opportunity to deal with the blocking application. For example, if you have Word talking to Excel, with Excel running in the background in formula mode, Excel won't check all calls, thereby blocking further action. IMessageFilter would put up a dialog indicating which task is blocking and provide the user with an opportunity to deal with the deadlock.

For applications that do not implement IMessageFilter, incoming and outgoing calls to OLE are handled automatically by OLE's default message handling procedures. OLE provides default message handling for each of the conditions that would be handled by an IMessageFilter method. For incoming calls, OLE dispatches all calls, regardless of their logical thread ID. For incoming Windows messages or Macintosh events, the default behavior is as though IMessageFilter::MessagePending had returned PENDINGMSG_WAITDEFPROCESS. This means that task-switching and window-activation messages are dispatched, as well as WM_TIMER messages. Other input messages are discarded and OLE continues to wait for the reply.

When to Use

You don't call this interface directly. It's provided by the application and called by the system.

Methods in Vtable Order

IUnknown Methods	Description
QueryInterface	Returns a pointer to a specified interface.
AddRef	Increments the reference count.
Release	Decrements the reference count.
IMessageFilter Methods	Description
HandleIncomingCall	Provides a single entry point for incoming calls.
RetryRejectedCall	Provides application with opportunity to display dialog offering retry or cancel options or to switch tasks.
MessagePending	Indicates a Windows message has arrived while OLE is waiting to respond to a remote call.
See Also

In the WIN32 Programmer's Reference: "Messages and Message Queues"


IMessageFilter::HandleInComingCall

Provides an application with a single entry point for all incoming calls.

DWORD HandleInComingCall(

DWORD dwCallType,	//Type of incoming call
HTASK threadIDCaller,	//Task handle calling this task
DWORD dwTickCount,	//Elapsed tick count
LPINTERFACEINFO lpInterfaceInfo	//Points to INTERFACEINFO structure
);
Parameters

dwCallType

[in] Indicates the kind of incoming call that has been received; valid values are from the enumeration CALLTYPE. See the chapter on enumerations for details.

threadIDCaller

[in] Specifies the handle of the task is calling this task.

dwTickCount

[in] Specifies the elapsed tick count since the outgoing call was made if dwCallType is not CALLTYPE_TOPLEVEL. If dwCallType is CALLTYPE_TOPLEVEL, dwTickCount should be ignored.

lpInterfaceInfo

Points to an INTERFACEINFO structure that contains information about the incoming call. Can also be NULL.

Return Values

SERVERCALL_ISHANDLED

The application may be able to process the call.

SERVERCALL_REJECTED

The application cannot handle the call due to an unforeseen problem, such as network unavailability.

SERVERCALL_RETRYLATER

The application cannot handle the call at this time. For example, an application might return this value when it is in a user-controlled modal state.

Comments

If implemented, IMessageFilter::HandleInComingCall is called when an incoming OLE message is received.

Depending on the application's current state, the call can either be accepted and processed or rejected (permanently or temporarily). If SERVERCALL_ISHANDLED is returned, the application may be able to process the call. Success may depend on the interface for which the call is destined. If the call cannot be processed, OLE returns RPC_E_CALL_REJECTED.

Input-synchronized and asynchronous calls are dispatched even if the application returns SERVERCALL_REJECTED or SERVERCALL_RETRYLATER.

IMessageFilter::HandleInComingCall should not be used to hold off updates to objects during operations such as band printing. For that purpose, use IViewObject::Freeze.

You can also use IMessageFilter::HandleInComingCall to set up the application's state so the call can be processed in the future.

See Also

IViewObject::Freeze, CALLTYPE, INTERFACEINFO


IMessageFilter::MessagePending

Called if a Windows message or Macintosh event appears in the queue while OLE is waiting to reply to a remote call.

DWORD Create(

HTASK threadIDCallee,	//Called applications task handle
DWORD dwTickCount,	//Elapsed tick count
DWORD dwPendingType	//Call type
);
Parameters

threadIDCallee

[in] Specifies the task handle of the called application that has not yet responded.

dwTickCount

[in] Specifies the number of ticks since the call was made. It is calculated from the Windows GetTickCount function, or the Macintosh function, TickCount.

dwPendingType

[in] Indicates the type of call made during which a message or event was received. Valid values are from the enumeration PENDINGTYPE (where PENDINGTYPE_TOPLEVEL means the outgoing call was not nested within a call from another application and PENDINTGYPE_NESTED means the outgoing call was nested within a call from another application):

Return Values

PENDINGMSG_CANCELCALL

Cancel the outgoing call. This should be returned only under extreme conditions. Canceling a call that has not replied or been rejected can create orphan transactions and lose resources. OLE fails the original call and return RPC_E_CALL_CANCELLED.

PENDINGMSG_WAITNOPROCESS

Continue waiting for the reply and do not dispatch the message unless it is a task-switching or window-activation message. A subsequent message will trigger another call to IMessageFilter::MessagePending. Leaving messages or events in the queue enables them to be processed normally, if the outgoing call is completed.

PENDINGMSG_WAITDEFPROCESS

Because of the increased resources available in 32-bit systems, you are unlikely to get this return value. It now indicates the same state as PENDINGMSG_WAITNOPROCESS.

Keyboard and mouse messages are no longer dispatched, as was done with PENDINGMSG_WAITDEFPROCESS. However there are some cases where mouse and keyboard messages could cause the system to deadlock, and in these cases, mouse and keyboard messages are discarded. WM_PAINT messages are dispatched. Task-switching and activation messages are handled as before.

Comments

IMessageFilter::MessagePending is called by OLE after an application has made an OLE method call and, for example, while waiting for the reply, the user selects a menu command or double-clicks an object. Before OLE makes the IMessageFilter::MessagePending call, it calculates the elapsed time since the original OLE method call was made. OLE delivers the elapsed time in the dwTickCount parameter. In the meantime, OLE does not remove the message from the queue.

Windows messages or Macintosh events that appear in the caller's queue should remain in the queue until sufficient time has passed to ensure that the messages are probably not the result of typing ahead, but are, instead, an attempt to get attention. A two- or three-second delay is recommended. If that amount of time has passed and the call has not been completed, the messages should be flushed from the queue, and a dialog box should be displayed offering the user the choice of retrying (continue waiting) or switching to the task identified by the threadIDCallee parameter. This ensures that:

•	if calls are completed in a reasonable amount of time, type ahead will be treated correctly.

•	if the callee does not respond, type ahead is not misinterpreted and the user is able to act to solve the problem. For example, OLE 1 servers can queue up requests without responding when they are in modal dialogs.

Handling input while waiting for an outgoing call to finish can introduce complications. The application should determine whether to process the message without interrupting the call, continue waiting, or cancel the operation.

When there is no response to the original OLE call, the application can cancel the call and restore the OLE object to a consistent state by calling IStorage::Revert on its storage. The object can be released when the container can shut down. However, canceling a call can create orphaned operations and resource leaks. Canceling should be used only as a last resort. It is strongly recommended that applications not allow such calls to be canceled.

Caution  Returning PENDINGMSG_WAITNOPROCESS can cause the message queue to fill.

See Also

IStorage::Revert

GetTickCount in Win32


IMessageFilter::RetryRejectedCall

Gives the application an opportunity to display a dialog box so the user can retry or cancel the call, or switch to the task identified by threadIDCallee.

DWORD RetryRejectedCall(

HTASK threadIDCallee,	//Server task handle
DWORD dwTickCount,	//Elapsed tick count
DWORD dwRejectType	//Returned rejection message
);
Parameters

threadIDCallee

[in] Specifies the handle of the server task that rejected the call.

dwTickCount

[in] Specifies the number of elapsed ticks since the call was made.

dwRejectType

[in] Specifies either SERVERCALL_REJECTED or SERVERCALL_RETRYLATER, as returned by the object application.

Return Values

-1

The call should be canceled. OLE then returns RPC_E_CALL_REJECTED from the original method call.

Value >= 0 and <100

The call is to be retried immediately.

Value >= 100

OLE will wait for this many milliseconds and then retry the call.

Comments

OLE calls RetryRejectedCall immediately after receiving SERVERCALL_RETRYLATER or SERVERCALL_REJECTED from IMessageFilter::HandleInComingCall.

If an application task rejects a call, the application is probably in a state where it cannot handle such calls, possibly only temporarily. When this occurs, OLE calls IMessageFilter::RetryRejectedCall.

Applications should silently retry calls that have returned with SERVERCALL_RETRYLATER and show a dialog box only after a reasonable amount of time has passed, say about five seconds. The callee may momentarily be in a state where calls can be handled. The option to wait and retry is provided for special kinds of calling applications, such as background tasks executing macros or scripts, so that they can retry the calls in a nonintrusive way.

If, after a dialog box is displayed, the user chooses to cancel, the call will appear to fail with RPC_E_CALL_REJECTED.


IMoniker

The IMoniker interface is used for naming COM objects. An object that implements IMoniker is called a "moniker," which is a name that uniquely identifies a COM object.

You can think of a moniker as a generalization of a pathname; in the same way that a pathname identifies a file in the file system, a moniker identifies a COM object. For example, suppose you have an object representing a range of cells in a spreadsheet which is itself embedded in a text document. The moniker for this object would contain information like "c:\work\report.doc\embedobj1\A1:E7." Monikers are more widely applicable than pathnames; whereas pathnames can only identify files, monikers can identify any kind of object, whether it's a file, an embedding, a selection within a document, or something else.

Monikers have a number of useful properties:

•	Monikers can be saved to a persistent storage. When a moniker is loaded back into memory, it still identifies the same object it did before.

•	Monikers support an operation called "binding," which is the process of locating the object named by the moniker, activating it (loading it in memory) if it isn't already, and returning an interface pointer to it.

As a result of these characteristics, you can treat monikers as a persistent version of a pointer to an object. Suppose your object holds an ICellRange pointer to the cell-range object mentioned in the paragraph above. You'd like to save your object and the cell-range object to disk, reload them later, and still have your object hold a pointer to the cell-range object. It's no use saving the ICellRange pointer to a disk file, because you can't guarantee that the cell-range object will reside at the same address in memory the next time it's loaded. However, you can save a moniker in a file. Then you can re-read the moniker into memory and bind the moniker, which reloads the cell-range object into memory and returns an ICellRange pointer to it. You've thus reestablished a connection between two objects after writing them to persistent storage.

Monikers also form the basis for linking in OLE. A linked object contains a moniker that identifies its source. When the user activates the linked object to edit it, the moniker is bound; this loads the link source into memory.

When to Implement

You implement IMoniker only if you are writing your own moniker class; this is necessary only if you need to identify objects that cannot be identified using the system-supplied moniker classes.

The system supplies the following moniker classes:

•	File monikers — based on a path in the file system. File monikers can be used to identify objects that are saved in their own files.

•	Item monikers — based on a string that identifies an object in a container. Item monikers can be used to identify objects smaller than a file, including embedded objects in a compound document, or a pseudo-object (like a range of cells in a spreadsheet).

•	Generic composite monikers — consists of two or more monikers of arbitrary type that have been composed together. Generic composite monikers allow monikers of different classes to be used in combination.

•	Anti-monikers — the inverse of file, item, or pointer monikers. Anti-monikers are used primarily for constructing relative monikers, which are analogous to relative pathnames (such as "..\backup\report.old"), and which specifies a location of an object relative to the location of another object).

•	Pointer monikers — a non-persistent moniker that wraps an interface pointer to an object loaded in memory. Whereas most monikers identify objects that can be saved to persistent storage, pointer monikers identify objects that cannot; they allow such objects to participate in a moniker binding operation.

These system-supplied moniker classes are sufficient for most situations. Before considering writing your own moniker class, you should make sure that your requirements cannot be satisified by these system-supplied moniker classes. See the description for each moniker class for information on how each one implements the IMoniker interface.

If you decide you need to write your own implementation of IMoniker, you must also implement the IROTData interface on your moniker class. This interface allows your monikers to be registered with the Running Object Table (ROT).

When to Use

You can use monikers whenever you need to create persistent connections between objects. You can also use monikers if you need a naming mechanism more general than pathnames; for example, if you need to designate embedded objects as well as files.

You can use monikers in two ways:

•	As a moniker provider; that is, handing out monikers that identify your objects to make them accessible to other parties. When acting as a moniker provider, you need to understand the differences between the various system-supplied moniker classes in order to know which one(s) are appropriate for identifying your objects. You use certain API functions to create monikers, and you must implement other interfaces to allow the monikers you hand out to be bound.

•	As a moniker client; that is, using monikers to get interface pointers to objects managed by a moniker provider. When acting as a moniker client, you typically don't need to know the class of the moniker you're using; you simply call methods using an IMoniker interface pointer.

The most common example of moniker providers are applications that act as link sources; that is, server applications that support linking and container applications that support linking to the embedded objects in their documents. See the descriptions for the moniker classes and for the moniker creation API functions for information on when to use each class.

The most common example of moniker clients are applications that act as link containers; that is, container applications that allow their documents to contain linked objects. However, link containers are a special case in that they make only infrequent calls to IMoniker methods. Generally, they manipulate linked objects through the IOleLink interface; the default handler implements this interface and calls the appropriate IMoniker methods as needed.

Methods in Vtable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments reference count.
Release	Decrements reference count.
IPersist Methods	Description
GetClassID	Returns the object's CLSID.
IPersistStream Methods	Description
IsDirty	Checks whether object has been modified.
Load	Loads the object from a stream.
Save	Saves the object to a stream.
GetSizeMax	Returns the buffer size needed to save the object.
IMoniker Methods	Description
BindToObject	Binds to the object named by the moniker.
BindToStorage	Binds to the object's storage.
Reduce	Reduces the moniker to simplest form.
ComposeWith	Composes with another moniker.
Enum	Enumerates component monikers.
IsEqual	Compares with another moniker.
Hash	Returns a hash value.
IsRunning	Checks whether object is running.
GetTimeOfLastChange	Returns time the object was last changed.
Inverse	Returns the inverse of the moniker.
CommonPrefixWith	Finds the prefix that the moniker has in common with another moniker.
RelativePathTo	Constructs a relative moniker between the moniker and another.
GetDisplayName	Returns the display name.
ParseDisplayName	Converts a display name into a moniker.
IsSystemMoniker	Checks whether moniker is one of the system-supplied types.
See Also

BindMoniker, CreateBindCtx, CreateGenericComposite, CreateFileMoniker, CreateItemMoniker, CreateAntiMoniker, CreatePointerMoniker, IOleLink, IPersistStream, IROTData


IMoniker::BindToObject

"Binds" the moniker; that is, returns a pointer to the object identified by the moniker. The binding process involves finding the object, getting it into the running state if it's not already, and acquiring an interface pointer to it.

HRESULT BindToObject(

IBindCtx *pbc,	//Bind context to be used
IMoniker *pmkToLeft,	//Moniker that precedes this one in the composite
REFIID riidResult,	//IID of interface pointer requested
void **ppvResult	//Receives an interface pointer to the object
);
Parameters

pbc

[in] Points to the bind context to be used for this binding operation. The bind context caches objects bound during the binding process, contains parameters that apply to all operations using the bind context, and provides the means by which the moniker implementation should retrieve information about its environment. For more information, see IBindCtx.

pmkToLeft

[in] Points to the moniker to the left of this moniker, if this moniker is part of a composite. This parameter is primarily used by moniker implementors to enable cooperation between the various components of a composite moniker; moniker clients can usually pass NULL.

riidResult

[in] Specifies the IID of the interface pointer requested.

ppvResult

[out] Receives a pointer to the object identified by the moniker. If an error occurs, the implementation sets *ppvResult to NULL. If *ppvResult is non-NULL, the implementation must call IUnknown::AddRef on the parameter; it is the caller's responsibility to call IUnknown::Release.

Return Values

S_OK

The binding operation was successful.

MK_E_NOOBJECT

Indicates that the object identifed by this moniker, or some object identified by the composite moniker of which this moniker is a part, could not be found.

MK_E_EXCEEDEDDEADLINE

Indicates that the binding operation could not be completed within the time limit specified by the bind context's BIND_OPTS structure.

MK_E_CONNECTMANUALLY

Indicates a moniker whose binding requires assistance from the end user. You can retry the binding operation after showing the moniker's display name to request that the end user manually connect to the object. The most common reasons for returning this value are that a password is needed or that a floppy needs to be mounted. The caller should call IBindCtx::GetObjectParam with the key "ConnectManually" to retrieve the moniker that caused the error, get the display name, display a dialog box asking the user for a password, and so on.

MK_E_INTERMEDIATEINTERFACENOTSUPPORTED

An intermediate object was found but it did not support an interface required to complete the binding operation. For example, an item moniker returns this value if its container does not support the IOleItemContainer interface.

E_UNEXPECTED

Indicates an unexpected error.

E_OUTOFMEMORY

Indicates insufficient memory.

STG_E_ACCESSDENIED

Unable to access the storage object.

IOleItemContainer::GetObject errors

Binding to a moniker containing an item moniker can return any of the errors associated with this function.

Comments

The IMoniker::BindToObject method implements the primary function of a moniker: returning an interface pointer to the object identified by the moniker.

Notes to Callers

If you are using a moniker as persistent connection between two objects, you activate the connection by calling IMoniker::BindToObject.

You typically call IMoniker::BindToObject with the following steps:

1.	Create a bind context by calling the CreateBindCtx API function.

2.	Call the IMoniker::BindToObject method on the moniker, retrieving an interface pointer.

3.	Release the bind context.

4.	Use the interface pointer.

5.	Release the interface pointer.

Here's a code fragment that illustrates these steps:

// pMnk is an IMoniker * that points to a previously-acquired moniker

ICellRange *pCellRange;

IBindCtx *pbc;

CreateBindCtx( 0, &pbc );

pMnk->BindToObject( pbc, NULL, IID_ICellRange, &pCellRange );

pbc->Release();

// pCellRange now points to the object; safe to use pCellRange

pCellRange->Release();

You can also use the BindMoniker API function, which encapsulates the first three steps described above.

Note that link containers are a special case in that they typically don't need to call IMoniker::BindToObject directly. When a user activates a linked object, the link container can typically calls IOleObject::DoVerb. The link handler's implementation of IOleObject::DoVerb calls IMoniker::BindToObject on the moniker stored in the linked object (if it cannot handle the verb).

Notes to Implementors

What your implementation does depends on whether you expect your moniker to have a prefix, that is, whether you expect the pmkToLeft parameter to be NULL or not. For example, an item moniker, which identifies an object within a container, expects that pmkToLeft identifies the container. An item moniker consequently uses pmkToLeft to request services from that container. If you expect your moniker to have a prefix, you should use the pmkToLeft parameter (for instance, calling IMoniker::BindToObject on it) to request services from the object it identifies.

If you expect your moniker to have no prefix, your IMoniker::BindToObject implementation should first check the Running Object Table (ROT) to see if the object is already running. To acquire a pointer to the ROT, your implementation should call IBindCtx::GetRunningObjectTable on the pbc parameter. You can then call the IRunningObjectTable::GetObject method to see if the current moniker has been registered in the ROT. If so, you can immediately use IUnknown::QueryInterface to return the desired interface pointer.

When your IMoniker::BindToObject implementation binds to some object, it should call IBindCtx::RegisterObjectBound on the pbc parameter to store a reference to the bound object in the bind context. This ensures that the bound object remains running until the bind context is released, which can avoid the expense of having a subsequent binding operation load it again later.

If the bind context's BIND_OPTS structure specifies the BINDFLAGS_JUSTTESTEXISTENCE flag, your implementation has the option of returning NULL in *ppvResult (although you can also ignore the flag and perform the complete binding operation).

See Also

BindMoniker, IMoniker::BindToStorage


IMoniker::BindToStorage

Retrieves an interface pointer to the storage of the object identified by the moniker. Unlike the IMoniker::BindToObject method, this method does not run the object identified by the moniker.

HRESULT BindToStorage(

IBindCtx *pbc,	//Bind context to be used
IMoniker *pmkToLeft,	//Moniker to the left of this one in the composite
REFIID riid,	//IID of interface pointer requested
void **ppvObj	//Receives interface pointer to storage
);
Parameters

pbc

[in] Points to the bind context to be used during this binding operation. The bind context caches objects bound during the binding process, contains parameters that apply to all operations using the bind context, and provides the means by which the moniker implementation should retrieve information about its environment. For more information, see IBindCtx.

pmkToLeft

[in] Points to the moniker to the left of this moniker, if this moniker is part of a composite. This parameter is primarily used by moniker implementors to enable cooperation between the various components of a composite moniker; moniker clients can usually pass NULL.

riid

[in] Indicates the requested interface pointer to be returned in ppvObj. Common interfaces requested include IStorage, IStream, and ILockBytes.

ppvObj

[out] Receives a pointer to the interface identified by riid. If an error occurs, the implementation sets *ppvObj to NULL. If *ppvObj is non-NULL, the implementation must call IUnknown::AddRef on the parameter; it is the caller's responsibility to call IUnknown::Release.

Return Values

S_OK

The binding operation was successful.

MK_E_NOSTORAGE

Indicates that the object identified by this moniker does not have its own storage.

MK_E_EXCEEDEDDEADLINE

Indicates that the operation could not be completed within the time limit specified by the bind context's BIND_OPTS structure.

MK_E_CONNECTMANUALLY

Indicates that the operation was unable to connect to the storage, possibly because a network device could not be connected to. For more information, see IMoniker::BindToObject.

MK_E_INTERMEDIATEINTERFACENOTSUPPORTED

An intermediate object was found but it did not support an interface required for an operation. For example, an item moniker returns this value if its container does not support the IOleItemContainer interface.

E_OUTOFMEMORY

Indicates insufficient memory.

STG_E_ACCESSDENIED

Unable to access the storage object.

IOleItemContainer::GetObject errors

Binding to a moniker containing an item moniker can return any of the errors associated with this function.

Comments

There is an important difference between the IMoniker::BindToObject and IMoniker::BindToStorage methods. If, for example, you have a moniker that identifies a spreadsheet object; calling IMoniker::BindToObject provides access to the spreadsheet object itself, while calling IMoniker::BindToStorage provides access to the storage object in which the spreadsheet resides.

Notes to Callers

The most common reason for calling the IMoniker::BindToStorage method is if you are implementing your own moniker class. You would call this method if your implementation of IMoniker::BindToObject needs information from the object identified by their pmkToLeft parameter, but it doesn't need to activate that object; all it needs is access to the persistent storage of that object. For example, if your monikers are used to identify objects that can be activated without activating their containers, you may find this method useful. (Note that none of the system-supplied moniker classes use this method in their binding operations.)

You could also call this method if you're a moniker client and you know how to read the storage of the object identified by the moniker you're holding.

Notes to Implementors

Your implementation should locate the persistent storage for the object identified by the current moniker and return the desired interface pointer. Some types of monikers represent pseudo-objects; that is, objects that don't have their own piece of persistent storage. Such objects comprise some portion of the internal state of its container; e.g. a range of cells in a spreadsheet. If your moniker class is this type of moniker, your implementation of IMoniker::BindToStorage should return the error MK_E_NOSTORAGE.

If the bind context's BIND_OPTS structure specifies the BINDFLAGS_JUSTTESTEXISTENCE flag, your implementation has the option of returning NULL in *ppvObj (although it can also ignore the flag and perform the complete binding operation).

See Also

IMoniker::BindToObject


IMoniker::CommonPrefixWith

Creates a new moniker based on the common prefix that this moniker shares with the specified moniker.

HRESULT CommonPrefixWith(

IMoniker *pmkOther,	//Moniker to be used for comparison
IMoniker **ppmkPrefix	//Receives the prefix
);
Parameters

pmkOther

[in] Points to the moniker to be compared with this one for a common prefix.

ppmkPrefix

[out] Receives a pointer to the moniker that is the common prefix of the this moniker and pmkOther. If an error occurs or if there is no common prefix, the implementation sets *ppmkPrefix to NULL. If *ppmkPrefix is non-NULL, the implementation must call IUnknown::AddRef on the parameter; it is the caller's responsibility to call IUnknown::Release.

Return Values

S_OK

A common prefix exists that is neither this moniker nor pmkOther.

MK_S_NOPREFIX

No common prefix exists.

MK_S_HIM

The entire pmkOther moniker is a prefix of this moniker.

MK_S_US

The two monikers are identical.

MK_S_ME

This moniker is a prefix of the pmkOther moniker.

MK_E_NOTBINDABLE

This method was called on a relative moniker. It is not meaningful to take the common prefix on a relative moniker.

E_OUTOFMEMORY

Indicates insufficient memory.

Comments

If, for example, you have one moniker that represents the path "c:\projects\secret\art\pict1.bmp" and another moniker that represents the path "c:\projects\secret\docs\chap1.txt." In that case, the common prefix of these two monikers would be a moniker representing the path "c:\projects\secret."

Notes to Callers

The IMoniker::CommonPrefixWith method is primarily called by the implementation of the IMoniker::RelativePathTo method. Moniker clients rarely need to call this method.

Note that it is not meaningful to take the common prefix on relative monikers. Consequently, you should call this method only if pmkOther and this moniker are both absolute monikers (where an absolute moniker is either a file moniker or a generic composite whose left-most component is a file moniker, and where the file moniker represents an absolute path). Do not call this method on relative monikers.

Notes to Implementors

Your implementation should first determine whether pmkOther is a moniker of a class that you recognize and for which you can provide special handling (for example, if it is of the same class as this moniker). If so, your implementation should determine the common prefix of the two monikers. Otherwise, it should pass both monikers in a call to the MonikerCommonPrefixWith API function, which correctly handles the generic case.

See Also

IMoniker::RelativePathTo, MonikerCommonPrefixWith


IMoniker::ComposeWith

Combines the current moniker with another moniker, creating a new, composite moniker.

HRESULT ComposeWith(

IMoniker *pmkRight,	//Moniker to be composed onto this one
BOOL fOnlyIfNotGeneric,	//Indicates if generic composition permissible
IMoniker **ppmkComposite	//Receives the composite
);
Parameters

pmkRight

[in] Points to the moniker to compose onto the end of this moniker.

fOnlyIfNotGeneric

[in] Indicates whether the method must perform a non-generic composition. If TRUE, the caller requires a non-generic composition, so the operation should proceed only if pmkRight is a moniker class that this moniker can compose with in some way other than forming a generic composite. If FALSE, the method can create a generic composite if necessary.

ppmkComposite

[out] Receives a pointer to the resulting composite moniker. If an error occurs or if the monikers compose to nothing (e.g., composing an anti-moniker with an item moniker or a file moniker), the implementation sets *ppmkComposite to NULL. If *ppmkComposite is non-NULL, the implementation must call IUnknown::AddRef on the parameter; it is the caller's responsibility to call IUnknown::Release.

Return Values

S_OK

Indicates that the monikers were successfully combined.

MK_E_NEEDGENERIC

Indicates that fOnlyIfNotGeneric was TRUE, but the monikers could not be composed together without creating a generic composite moniker.

E_OUTOFMEMORY

Indicates insufficient memory.

E_UNEXPECTED

Indicates an unexpected error.

Comments

The process of joining two monikers together is called composition. Sometimes two monikers of specific classes can be combined in a special manner; for example, a file moniker representing an incomplete path and another file moniker representing a relative path can be combined to form a single file moniker representing the complete path. This is an example of "non-generic" composition. "Generic" composition, on the other hand, can connect any two monikers, no matter what their classes. Because a non-generic composition depends on the class of the monikers involved, it can be performed only by an particular class's implementation of the IMoniker::ComposeWith method. You can define new types of non-generic compositions if you write a new moniker class. By contrast, generic compositions are performed by the CreateGenericComposite API function.

Composition of monikers is an associative operation. That is, if A, B, and C are monikers, then

Comp( Comp( A, B ), C )

is always equal to

Comp( A, Comp( B, C ) )

where Comp() represents the composition operation.

Notes to Callers

If you want to combine two monikers, you should call the IMoniker::ComposeWith method rather than calling CreateGenericComposite API function; this gives the first moniker a chance to perform a non-generic composition.

A common situation in which you would combine two monikers is if you are a moniker provider using item monikers to identify your objects; for example, if your application is a server that supports linking to portions of a document, or if it's a container that supports linking to embedded objects within its documents. In such a situation, you would do the following:

1.	Create an item moniker identifying an object.

2.	Get a moniker that identifies the object's container.

3.	Call IMoniker::ComposeWith on the moniker identifying the container, passing the item moniker as the pmkRight parameter.

Most callers of IMoniker::ComposeWith should set the fOnlyIfNotGeneric parameter to FALSE.

Notes to Implementors

As described above, there are two ways to compose pmkRight to your moniker: by performing a generic composition, or by performing a non-generic composition. The latter means seeing if you recognize the pmkRight parameter's class and if so, using the contents of pmkRight to perform a more intelligent composition.

When writing your moniker class, you must decide if there are any kinds of monikers to which you want to give special treatment (as described above in the example of the file monikers); these don't have to be monikers of your own class. You then implement IMoniker::ComposeWith to examine pmkRight to check whether it is such a special moniker; possible ways of doing this are to ask pmkRight for its class or call IUnknown::QueryInterface on it. The most common case of a special moniker is the inverse for your moniker class (that is, whatever you return from your implementation of IMoniker::Inverse).

If the pmkRight parameter is a moniker of a class that you give special treatment, your implementation of IMoniker::ComposeWith should do whatever is appropriate for that special case. If pmkRight completely negates the receiver so that the resulting composite is empty, you should pass back NULL in ppmkComposite and return the status code S_OK.

If the pmkRight parameter is not of a class to which you give special treatment, examine fOnlyIfNotGeneric to determine what to do next. If fOnlyIfNotGeneric is TRUE, pass back NULL through ppmkComposite and return the status code MK_E_NEEDGENERIC. If fOnlyIfNotGeneric is FALSE, call the CreateGenericComposite API to perform the composition generically.

See Also

CreateGenericComposite, IMoniker::Inverse


IMoniker::Enum

Returns a pointer to an enumerator that can enumerate the components of the moniker.

HRESULT Enum(

BOOL fForward,	//Specifies direction of enumeration
IEnumMoniker **ppenumMoniker	//Receives the enumerator
);
Parameters

fForward

[in] Specifies the enumeration order. TRUE enumerates the monikers from left to right; FALSE enumerates from right to left.

ppenumMoniker

[out] Receives a pointer to an IEnumMoniker enumerator for this moniker. If an error occurs or if the moniker has no enumerable components, the implementation sets *ppenumMoniker to NULL. If *ppenumMoniker is non-NULL, the implementation must call IUnknown::AddRef on the parameter; it is the caller's responsibility to call IUnknown::Release.

Return Values

S_OK

Indicates success. This value is returned even if the moniker does not provide an enumerator (that is, if *ppenumMoniker equals NULL).

E_OUTOFMEMORY

Indicates insufficient memory.

E_UNEXPECTED

Indicates an unexpected error.

Comments

As examples of enumeration, the IMoniker::Enum method for a generic composite moniker creates an enumerator that returns the individual monikers that make up the composite, and the IMoniker::Enum method for a file moniker creates an enumerator that returns monikers representing each of the components in the pathname.

Notes to Callers

You would call this method if you want to examine the individual components that make up a composite moniker.

Notes to Implementors

If your monikers have no discernible internal structure, your implementation of this method can simply return S_OK and set *ppenumMoniker to NULL.

See Also

IEnumXXXX


IMoniker::GetDisplayName

Returns the display name — that is, the user-readable representation — of this moniker.

HRESULT GetDisplayName(

IBindCtx *pbc,	//Bind context to be used
IMoniker *pmkToLeft,	//Moniker to the left in the composite
LPOLESTR *ppszDisplayName	//Receives the display name
);
Parameters

pbc

[in] Points to the bind context to be used in this operation. The bind context caches objects bound during the binding process, contains parameters that apply to all operations using the bind context, and provides the means by which the moniker implementation should retrieve information about its environment. For more information, see IBindCtx.

pmkToLeft

[in] Points to the moniker to the left of this moniker, if this moniker is part of a composite. This parameter is primarily used by moniker implementors to enable cooperation between the various components of a composite moniker; moniker clients can usually pass NULL.

ppszDisplayName

[out] Receives a pointer to a zero-terminated string containing the display name of this moniker. If an error occurs, *ppszDisplayName is set to NULL; otherwise, the implementation must use IMalloc::Alloc to allocate the string returned in ppszDisplayName, and the caller is responsible for calling IMalloc::Free to free it. Both caller and callee use the allocator returned by CoGetMalloc(MEMCTX_TASK, ...). For Win32 applications, the LPOLESTR type indicates a wide character string (two bytes per character); otherwise, the string has one byte per character.

Return Values

S_OK

Indicates the display name was successfully returned.

MK_E_EXCEEDEDDEADLINE

Indicates that the binding operation could not be completed within the time limit specified by the bind context's BIND_OPTS structure.

E_OUTOFMEMORY

Indicates insufficient memory.

E_NOTIMPL

There is no display name.

Comments

As examples of display names, a file moniker's display name is the path the moniker represents, and an item moniker's display name is the string contained in the moniker. However, a display name is not necessarily a complete representation of a moniker's internal state; it is simply a form readable by users. As a result, it is possible (though rare) for two different monikers to have the same display name. There is also no guarantee that the display name of a moniker can be parsed back into that moniker when calling the MkParseDisplayName API function with it, though failure to do so is also rare.

Notes to Callers

It's possible that retrieving a moniker's display name may be an expensive operation. For efficiency, you may want to cache the results of the first successful call to IMoniker::GetDisplayName, rather than making repeated calls.

Notes to Implementors

If you are writing a moniker class in which the display name does not change, simply cache the display name and return that when requested. If the display name can change over time, getting the current display name might mean that the moniker has to access the object's storage or bind to the object, either of which can be expensive operations. If this is the case, your implementation of IMoniker::GetDisplayName should return MK_E_EXCEEDEDDEADLINE if the name cannot be retrieved by the time specified in the bind context's BIND_OPTS structure.

A moniker that is intended to be part of a generic composite moniker should include any preceding delimiter (such as '\') as part of its display name. For example, the display name returned by an item moniker includes the delimiter specified when it was created with the CreateItemMoniker API function. The display name for a file moniker does not include a delimiter because file monikers always expect to be the leftmost component of a composite.

See Also

IMoniker::ParseDisplayName, MkParseDisplayName


IMoniker::GetTimeOfLastChange

Returns a number representing the time the object identified by this moniker was last changed. To be precise, the time returned is the earliest one OLE can identify after which no change has occurred, so this time may be later than the actual time of the last change to the object.

HRESULT GetTimeOfLastChange(

IBindCtx *pbc,	//Bind context to be used
IMoniker *pmkToLeft,	//Moniker to the left in the composite
FILETIME *pFileTime	//Receives the time of last change
);
Parameters

pbc

[in] Points to the bind context to be used in this binding operation. The bind context caches objects bound during the binding process, contains parameters that apply to all operations using the bind context, and provides the means by which the moniker implementation should retrieve information about its environment. For more information, see IBindCtx.

pmkToLeft

[in] Points to the moniker to the left of this moniker, if this moniker is part of a composite. This parameter is primarily used by moniker implementors to enable cooperation between the various components of a composite moniker; moniker clients can usually pass NULL.

pFileTime

[out] Points to the FILETIME structure receiving the time of last change. A value of {0xFFFFFFFF,0x7FFFFFFF} indicates an error (for example, exceeded time limit, information not available).

Return Values

S_OK

Indicates the method returned a time successfully.

MK_E_EXCEEDEDDEADLINE

Indicates that the binding operation could not be completed within the time limit specified by the bind context's BIND_OPTS structure.

MK_E_CONNECTMANUALLY

Indicates that the operation was unable to connect to the storage for this object, possibly because a network device could not be connected to. For more information, see IMoniker::BindToObject.

MK_E_UNAVAILABLE

The time of the change is unavailable, and will not be available no matter what deadline is used.

E_UNEXPECTED

Indicates an unexpected error.

Comments

Notes to Callers

If you're caching information returned by the object identified by the moniker, you may want to ensure that your information is up-to-date. To do so, you would call IMoniker::GetTimeOfLastChange and compare the time returned with the time you last retrieved information from the object.

For the monikers stored within linked objects, IMoniker::GetTimeOfLastChange is primarily called by the default handler's implementation of IOleObject::IsUpToDate. Container applications call IOleObject::IsUpToDate to determine if a linked object (or an embedded object containing linked objects) is up-to-date without actually binding to the object. This enables an application to quickly determine which linked objects require updating when the end user opens a document. The application can then bind only those linked objects that need updating (after prompting the end user to determine whether they should be updated), instead of binding every linked object in the document.

Notes to Implementors

It is important to perform this operation quickly because, for linked objects, this method is called when a user first opens a compound document. Consequently, your IMoniker::GetTimeOfLastChange implementation should not bind to any objects. In addition, your implementation should check the deadline parameter in the bind context and return MK_E_EXCEEDEDDEADLINE if the operation cannot be completed by the specified time.

There are a number of strategies you can attempt in your implementations:

•	For many types of monikers, the pmkToLeft parameter identifies the container of the object identified by this moniker. If this is true of your moniker class, you can simply call IMoniker::GetTimeOfLastChange on the pmkToLeft parameter, since an object cannot have changed at a date later than its container.

•	You can get a pointer to the Running Object Table (ROT) by calling IBindCtx::GetRunningObjectTable on the pbc parameter, and then calling IRunningObjectTable::GetTimeOfLastChange, since the ROT generally records the time of last change.

•	You can get the storage associated with this moniker (or the pmkToLeft moniker) and return the storage's last modification time.

See Also

IBindCtx::GetRunningObjectTable, IRunningObjectTable::GetTimeOfLastChange


IMoniker::Hash

Calculates a 32-bit integer using the internal state of the moniker.

HRESULT Hash(

DWORD *pdwHash	//Receives the hash value
);
Parameter

pdwHash

[out] Receives the hash value.

Return Value

S_OK

Successfully received a 32-bit integer hash value.

Comments

Notes to Callers

You can use the value returned by this method to maintain a hash table of monikers. The hash value determines a hash bucket in the table. To search such a table for a specified moniker, calculate its hash value and then compare it to the monikers in that hash bucket using IMoniker::IsEqual.

Notes to Implementors

The hash value must be constant for the lifetime of the moniker. Two monikers that compare as equal using IMoniker::IsEqual must hash to the same value.

Marshaling and then unmarshaling a moniker should have no effect on its hash value. Consequently, your implementation of IMoniker::Hash should rely only on the internal state of the moniker, not on its memory address.

See Also

IMoniker::IsEqual


IMoniker::Inverse

Returns a moniker that, when composed to the right of this moniker or one of similar structure, will destroy it (that is, will compose to nothing).

HRESULT Inverse(

IMoniker **ppmk	//Receives the inverse of the moniker
);
Parameter

ppmk

[out] Receives a pointer to the inverse moniker. If an error occurs, the implementation sets *ppmk to NULL. If *ppmk is non-NULL, the implementation must call IUnknown::AddRef on the parameter; it is the caller's responsibility to call IUnknown::Release.

Return Values

S_OK

The inverse moniker has been returned successfully.

MK_E_NOINVERSE

Indicates that the moniker class does not have an inverse.

E_OUTOFMEMORY

Indicates insufficient memory.

Comments

The inverse of a moniker is analogous to the ".." directory in MS-DOS file systems; the ".." directory acts as the inverse to any other directory name, because appending ".." to a directory name results in an empty path. In the same way, the inverse of a moniker typically is also the inverse of all monikers in the same class. However, it is not necessarily the inverse of a moniker of a different class.

The inverse of a composite moniker is a composite consisting of the inverses of the components of the original moniker, arranged in reverse order. For example, if the inverse of A is Inv( A ) and the composite of A, B, and C is Comp( A, B, C ), then

Inv( Comp( A, B, C ) )

is equal to

Comp( Inv( C ), Inv( B ), Inv( A ) ).

Not all monikers have inverses. Most monikers that are themselves inverses do not have inverses; for example, anti-monikers do not have inverses. Monikers that have no inverse cannot have relative monikers formed from inside the objects they identify to other objects outside.

Notes to Callers

If you're a moniker client, you typically do not know the class of the moniker you're using. If you need to get the inverse of a moniker, you should always call IMoniker::Inverse rather than the CreateAntiMoniker API function, because you cannot be certain that the moniker you're using considers an anti-moniker to be its inverse.

The IMoniker::Inverse method is also called by the implementation of the IMoniker::RelativePathTo method, to assist in constructing a relative moniker.

Notes to Implementors

If your monikers have no internal structure, your implementation of IMoniker::Inverse can return an anti-moniker using the CreateAntiMoniker API function. Whatever you return from IMoniker::Inverse is what you must check for in your implementation of IMoniker::ComposeWith.

See Also

CreateAntiMoniker, IMoniker::ComposeWith, IMoniker::RelativePathTo


IMoniker::IsEqual

Compares the moniker with a specified moniker and indicates whether they are identical.

HRESULT IsEqual(

IMoniker *pmkOtherMoniker	//Moniker to be used for comparison
);
Parameter

pmkOtherMoniker

[in] Points to the moniker to be used for comparison.

Return Values

S_OK

The two monikers are identical.

S_FALSE

The two monikers are not identical.

Comments

Previous implementations of the Running Object Table (ROT) called this method. The current implementation of the ROT uses the IROTData interface instead.

Notes to Callers

Call this method to determine if two monikers are identical or not. Note that the reduced form of a moniker is considered different from the unreduced form. You should call the IMoniker::Reduce method before calling IMoniker::IsEqual, because a reduced moniker is in its most specific form. IMoniker::IsEqual may return S_FALSE on two monikers before they are reduced, and S_OK after they are reduced.

Notes to Implementors

Your implementation should not reduce the current moniker before performing the comparison. It is the caller's responsibility to call IMoniker::Reduce in order to compare reduced monikers.

Note that two monikers that compare as equal must hash to the same value using IMoniker::Hash.

See Also

IMoniker::Reduce, IMoniker::Hash, IROTData


IMoniker::IsRunning

Determines whether the object identified by this moniker is currently loaded and running.

HRESULT IsRunning(

IBindCtx *pbc,	//Bind context to be used
IMoniker *pmkToLeft,	//Moniker to the left in the composite
IMoniker *pmkNewlyRunning	//Moniker of a newly running object
);
Parameters

pbc

[in] Points to the bind context to be used in this binding operation. The bind context caches objects bound during the binding process, contains parameters that apply to all operations using the bind context, and provides the means by which the moniker implementation should retrieve information about its environment. For more information, see IBindCtx.

pmkToLeft

[in] Points to the moniker to the left of this moniker if this moniker is part of a composite. This parameter is primarily used by moniker implementors to enable cooperation between the various components of a composite moniker; moniker clients can usually pass NULL.

pmkNewlyRunning

[in] Points to the moniker most recently added to the Running Object Table (ROT). This can be NULL. If non-NULL, the implementation can return the results of calling IMoniker::IsEqual on the pmkNewlyRunning parameter, passing the current moniker. This parameter is intended to enable IMoniker::IsRunning implementations that are more efficient than just searching the ROT, but the implementation can choose to ignore pmkNewlyRunning without causing any harm.

Return Values

S_OK

The moniker is running.

S_FALSE

The moniker is not running.

E_UNEXPECTED

Indicates an unexpected error.

Comments

Notes to Callers

If speed is important when you're requesting services from the object identified by the moniker, you may want those services only if the object is already running (because loading an object into the running state may be time-consuming). In such a situation, you'd call IMoniker::IsRunning to determine if the object is running.

For the monikers stored within linked objects, IMoniker::IsRunning is primarily called by the default handler's implementation of IOleLink::BindIfRunning.

Notes to Implementors

To get a pointer to the Running Object Table (ROT), your implementation should call IBindCtx::GetRunningObjectTable on the pbc parameter. Your implementation can then call IRunningObjectTable::IsRunning to determine whether the object identified by the moniker is running. Note that the object identified by the moniker must have registered itself with the ROT when it first began running.

See Also

IOleLink::BindIfRunning, IBindCtx::GetRunningObjectTable, IRunningObjectTable::IsRunning


IMoniker::IsSystemMoniker

Indicates whether this moniker is one of the system-supplied moniker classes.

HRESULT IsSystemMoniker(

DWORD *pdwMksys	//Receives value from MKSYS enumeration
);
Parameter

pdwMksys

[out] Receives an integer that is one of the values from the MKSYS enumeration. This parameter cannot be NULL. For information on the MKSYS enumeration, see the "Data Structures" section.

Return Values

S_OK

The moniker is a system moniker.

S_FALSE

The moniker is not a system moniker.

Comments

Notes to Callers

New values of the MKSYS enumeration may be defined in the future; therefore you should explicitly test for each value you are interested in.

Notes to Implementors

Your implementation of this method must return MKSYS_NONE. You cannot use this function to identify your own monikers (for example, in your implementation if IMoniker::ComposeWith). Instead, you should use your moniker's implementation of IPersist::GetClassID or use IUnknown::QueryInterface to test for your own private interface.

See Also

IPersist::GetClassID, MKSYS


IMoniker::ParseDisplayName

Reads as many characters of the specified display name as it understands and builds a moniker corresponding to the portion read; this procedure is known as "parsing" the display name.

HRESULT ParseDisplayName(

IBindCtx *pbc,	//Bind context to be used
IMoniker *pmkToLeft,	//Moniker to the left in the composite
LPOLESTR pszDisplayName,	//Display name
ULONG *pchEaten,	//Receives number of characters consumed
IMoniker **ppmkOut	//Receives moniker built from display name
);
Parameters

pbc

[in] Points to the bind context to be used in this binding operation. The bind context caches objects bound during the binding process, contains parameters that apply to all operations using the bind context, and provides the means by which the moniker implementation should retrieve information about its environment. For more information, see IBindCtx.

pmkToLeft

[in] Points to the moniker that has been built out of the display name up to this point.

pszDisplayName

[in] Points to a zero-terminated string containing the remaining display name to be parsed. For Win32 applications, the LPOLESTR type indicates a wide character string (two bytes per character); otherwise, the string has one byte per character.

pchEaten

[out] Receives the number of characters in pszDisplayName that were consumed in this step.

ppmkOut

[out] Receives a pointer to the moniker that was built from pszDisplayName. If an error occurs, the implementation sets *ppmkOut to NULL. If *ppmkOut is non-NULL, the implementation must call IUnknown::AddRef on the parameter; it is the caller's responsibility to call IUnknown::Release.

Return Values

S_OK

The parsing operation was completed successfully.

MK_E_SYNTAX

Indicates an error in the syntax of the input components (pmkToLeft, this moniker, and pszDisplayName). For example, a file moniker returns this error if pmkToLeft is non-NULL, and an item moniker returns it if pmkToLeft is NULL.

E_OUTOFMEMORY

Indicates insufficient memory.

E_UNEXPECTED

Indicates an unexpected error.

IMoniker::BindToObject errors

Parsing display names may cause binding. Thus, any error associated with this function may be returned.

Comments

Notes to Callers

Moniker clients do not typically call IMoniker::ParseDisplayName directly. Instead, they call the MkParseDisplayName API function when they want to convert a display name into a moniker (for example, in implementing the Links dialog box for a container application, or for implementing a macro language that supports references to objects outside the document). That API function first parses the initial portion of the display name itself. It then calls IMoniker::ParseDisplayName on the moniker it has just created, passing the remainder of the display name and getting a new moniker in return; this step is repeated until the entire display name has been parsed.

Notes to Implementors

Your implementation may be able to perform this parsing by itself if your moniker class is designed to designate only certain kinds of objects. Otherwise, you must get an IParseDisplayName interface pointer for the object identified by the moniker-so-far (i.e., the composition of pmkToLeft and this moniker) and then return the results of calling IParseDisplayName::ParseDisplayName.

There are different strategies for getting an IParseDisplayName pointer:

•	You can try to get the object's CLSID (for example, by calling IPersist::GetClassID on the object), and then call the CoGetClassObject API function, requesting the IParseDisplayName interface on the class factory associated with that CLSID.

•	You can try to bind to the object itself to get an IParseDisplayName pointer.

•	You can try binding to the object identified by pmkToLeft to get an IOleItemContainer pointer, and then call IOleItemContainer::GetObject to get an IParseDisplayName pointer for the item.

Any objects that are bound should be registered with the bind context (see IBindCtx::RegisterObjectBound) to ensure that they remain running for the duration of the parsing operation.

See Also

IParseDisplayName, MkParseDisplayName


IMoniker::Reduce

Returns a reduced moniker; that is, another moniker that refers to the same object as this moniker but can be bound with equal or greater efficiency.

HRESULT Reduce(

IBindCtx *pbc,	//Bind context to be used
DWORD dwReduceHowFar,	//How much reduction should be done
IMoniker **ppmkToLeft,	//Moniker to the left in the composite
IMoniker **ppmkReduced	//Receives the reduced moniker
);
Parameters

pbc

[in] Points to the bind context to be used in this binding operation. The bind context caches objects bound during the binding process, contains parameters that apply to all operations using the bind context, and provides the means by which the moniker implementation should retrieve information about its environment. For more information, see IBindCtx.

dwReduceHowFar

[in] Specifies how far this moniker should be reduced. This parameter must be one of the values from the MKRREDUCE enumeration. For more information on the MKRREDUCE enumeration, see the "Data Structures" section.

ppmkToLeft

[in, out] On entry, *ppmkToLeft points to the moniker to the left of this moniker, if this moniker is part of a composite. This parameter is primarily used by moniker implementors to enable cooperation between the various components of a composite moniker; moniker clients can usually pass NULL.

On exit, *ppmkToLeft is usually set to NULL, indicating no change in the original moniker to the left. In rare situations *ppmkToLeft is set to non-NULL, indicating that the previous moniker to the left should be disregarded and the moniker returned through *ppmkToLeft is the replacement. In such a situation, the implementation must call IUnknown::Release on the passed-in pointer and call IUnknown::AddRef on the returned moniker; the caller must release it later. If an error occurs, the implementation can either leave the parameter unchanged or set it to NULL.

ppmkReduced

[out] Receives a pointer to the reduced form of this moniker, which can be NULL if an error occurs or if this moniker is reduced to nothing. If this moniker cannot be reduced, *ppmkReduced is simply set to this moniker and the return value is MK_S_REDUCED_TO_SELF. If ppmkReduced is non-NULL, the implementation must call IUnknown::AddRef on the parameter; it is the caller's responsibility to call IUnknown::Release. (This is true even if *ppmkReduced is set to this moniker.)

Return Values

S_OK

Indicates that this moniker was reduced.

MK_S_REDUCED_TO_SELF

Indicates that this moniker could not be reduced any further, in which case, *ppmkReduced is this moniker.

MK_E_EXCEEDEDDEADLINE

Indicates that the operation could not be completed within the time limit specified by the bind context's BIND_OPTS structure.

E_UNEXPECTED

Indicates an unexpected error.

E_OUTOFMEMORY

Indicates insufficient memory.

Comments

The IMoniker::Reduce method is intended for the following uses:

•	It enables the construction of user-defined macros or aliases as new kinds of moniker classes. When reduced, the moniker to which the macro evaluates is returned.

•	It enables the construction of a kind of moniker that tracks data as it moves about. When reduced, the moniker of the data in its current location is returned.

•	On file systems that support an ID-based method of accessing files which is independent of file names; a file moniker could be reduced to a moniker which contains one of these IDs.

The intent of the MKRREDUCE flags passed in the dwReduceHowFar parameter is to provide the ability to programmatically reduce a moniker to a form whose display name is recognizable to the user. For example, paths in the file system, bookmarks in word-processing documents, and range names in spreadsheets are all recognizable to users. In contrast, a macro or an alias encapsulated in a moniker are not recognizable to users.

Notes to Callers

The scenarios described above are not currently implemented by the system-supplied moniker classes.

You should call IMoniker::Reduce before comparing two monikers using the IMoniker::IsEqual method, because a reduced moniker is in its most specific form. IMoniker::IsEqual may return S_FALSE on two monikers before they are reduced and return S_OK after they are reduced.

Notes to Implementors

If the current moniker can be reduced, your implementation must not reduce the moniker in-place. Instead, it must return a new moniker that represents the reduced state of the current one. This way, the caller still has the option of using the non-reduced moniker (for example, enumerating its components). Your implementation should reduce the moniker at least as far as is requested.

See Also

IMoniker::IsEqual, MKRREDUCE


IMoniker::RelativePathTo

Returns a moniker that, when composed onto the end of this moniker (or one with a similar structure), yields the specified moniker.

HRESULT RelativePathTo(

IMoniker *pmkOther,	//Moniker to which a relative path should be taken
IMoniker **ppmkRelPath	//Receives the relative moniker
);
Parameters

pmkOther

[in] Points to the moniker to which a relative path should be taken.

ppmkRelPath

[out] Receives a pointer to the relative moniker. If an error occurs, the implementation sets *ppmkRelPath to NULL. If *ppmkRelPath is non-NULL, the implementation must call IUnknown::AddRef on the parameter; it is the caller's responsibility to call IUnknown::Release.

Return Values

S_OK

A meaningful relative path has been returned.

MK_S_HIM

Indicates that there is no common prefix shared by the two monikers and that the moniker returned in *ppmkRelPath is pmkOther.

MK_E_NOTBINDABLE

Indicates that this moniker is a relative moniker, such as an item moniker. This moniker must be composed with the moniker of its container before a relative path can be determined.

E_OUTOFMEMORY

Indicates insufficient memory.

E_UNEXPECTED

Indicates an unexpected error.

Comments

A relative moniker is analogous to a relative path (such as "..\backup"). For example, suppose you have one moniker that represents the path "c:\projects\secret\art\pict1.bmp" and another moniker that represents the path "c:\projects\secret\docs\chap1.txt." Calling IMoniker::RelativePathTo on the first moniker, passing the second one as the pmkOther parameter, would create a relative moniker representing the path "..\docs\chap1.txt."

Notes to Callers

Moniker clients typically do not need to call IMoniker::RelativePathTo. This method is primarily called by the default handler for linked objects. Linked objects contain both an absolute and a relative moniker to identify the link source (this enables link tracking if the user moves a directory tree containing both the container and source files). The default handler calls this method to create a relative moniker from the container document to the link source (that is, it calls IMoniker::RelativePathTo on the moniker identifying the container document, passing the moniker identifying the link source as the pmkOther parameter).

If you do call IMoniker::RelativePathTo, call it only on absolute monikers; for example, a file moniker or a composite moniker whose leftmost-component is a file moniker, where the file moniker represents an absolute path. Do not call this method on relative monikers.

Notes to Implementors

Your implementation of IMoniker::RelativePathTo should first determine whether pmkOther is a moniker of a class that you recognize and for which you can provide special handling (for example, if it is of the same class as this moniker). If so, your implementation should determine the relative path. Otherwise, it should pass both monikers in a call to the MonikerRelativePathTo API function, which correctly handles the generic case.

The first step in determining a relative path is determining the common prefix of this moniker and pmkOther. The next step is to break this moniker and pmkOther into two parts each, say (P, myTail) and (P, otherTail) respectively, where P is the common prefix. The correct relative path is then the inverse of myTail composed with otherTail:

Comp( Inv( myTail ), otherTail )

Where Comp() represents the composition operation and Inv() represents the inverse operation.

Note that for certain types of monikers, you cannot use your IMoniker::Inverse method to construct the inverse of myTail. For example, a file moniker returns an anti-moniker as an inverse, while its IMoniker::RelativePathTo method must use one or more file monikers that each represent the path ".." to construct the inverse of myTail.

See Also

IMoniker::Inverse, IMoniker::CommonPrefixWith, MonikerRelativePathTo


IMoniker - Anti-Moniker Implementation

Anti-monikers are the inverse of the system's implementations of file, item, and pointer monikers. That is, an anti-moniker composed to the right of a file moniker, item moniker, or pointer moniker composes to nothing.

When To Use

If you're a moniker client, you typically do not need to use anti-monikers. When you need the inverse of a moniker, you should call the IMoniker::Inverse method. For example, if you need an inverse to remove the last piece of a composite moniker, use IMoniker::Enum to enumerate the pieces of the moniker and call IMoniker::Inverse on the rightmost piece. You shouldn't use an anti-moniker for this purpose because you can't be sure that the rightmost piece of a composite considers an anti-moniker to be its inverse.

The only situation in which you should explicitly use an anti-moniker is if you are writing a new moniker class and if you have no special requirements for constructing inverses to your monikers. In that situation, you can return anti-monikers from your implementation of IMoniker::Inverse. In your implementation of IMoniker::ComposeWith, you should then annihilate one of your monikers for every anti-moniker you encounter.

See Also

CreateAntiMoniker, IMoniker

Comments

IMoniker::BindToObject

This method is not implemented (that is, it returns E_NOTIMPL).

IMoniker::BindToStorage

This method is not implemented (that is, it returns E_NOTIMPL).

IMoniker::Reduce

This method returns MK_S_REDUCED_TO_SELF and passes back the same moniker.

IMoniker::ComposeWith

If fOnlyIfNotGeneric is TRUE, this method sets *ppmkComposite to NULL moniker and returns MK_E_NEEDGENERIC; otherwise, the method returns the result of combining the two monikers into a generic composite. Note that composing a file, item, or pointer moniker to the right of an anti-moniker produces a generic composite rather than composing to nothing, as would be the case if the order of composition were reversed.

IMoniker::Enum

This method returns S_OK and sets *ppenumMoniker to NULL.

IMoniker::IsEqual

This method returns S_OK if both are anti-monikers; otherwise, it returns S_FALSE.

IMoniker::Hash

This method calculates a hash value for the moniker.

IMoniker::IsRunning

This method checks the ROT to see if the object is running.

IMoniker::GetTimeOfLastChange

This method is not implemented (that is, it returns E_NOTIMPL).

IMoniker::Inverse

This method returns MK_E_NOINVERSE and sets *ppmk to NULL.

IMoniker::CommonPrefixWith

If the other moniker is also an anti-moniker, the method returns MK_S_US and sets *ppmkPrefix to this moniker. Otherwise, the method calls the MonikerCommonPrefixWith API function. This API function correctly handles the case where the other moniker is a generic composite.

IMoniker::RelativePathTo

This method returns MK_S_HIM and sets *ppmkRelPath to the other moniker.

IMoniker::GetDisplayName

For each anti-moniker contained in this moniker, this method return one instance of "\.."

IMoniker::ParseDisplayName

This method is not implemented (that is, it returns E_NOTIMPL).

IMoniker::IsSystemMoniker

This method returns S_OK and indicates MKSYS_ANTIMONIKER.


IMoniker - File Moniker Implementation

File monikers are monikers that represent pathnames in the file system; a file moniker can identify any object that is saved in its own file. To identify objects contained within a file, you can compose monikers of other classes (for example, item monikers) to the right of a file moniker. However, the moniker to the left of a file moniker within a composite must be either another file moniker or an anti-moniker (it is illegal, for example, for an item moniker to appear to the left of a file moniker in a composite).

Note that an anti-moniker is the inverse of an entire file moniker, not the inverse of a component of the pathname that the moniker represents; that is, when you compose an anti-moniker to the right of a file moniker, the entire file moniker is removed. If you want to remove just the rightmost component of the pathname represented by a file moniker, you must create a separate file moniker based on the ".." pathname and then compose that to the end of the file moniker.

When to Use

If you're a moniker client (that is, you're using a moniker to get an interface pointer to an object), you typically don't need to know the class of the moniker you're using; you simply call methods using an IMoniker interface pointer.

If you're a moniker provider (that is, you're handing out monikers that identify your objects to make them accessible to moniker clients), you must use file monikers if the objects you're identifying are stored in files. If each object resides in its own file, file monikers are the only type you need. If the objects you're identifying are smaller than a file, you need to use another type of moniker (for example, item monikers) in addition to file monikers.

To use file monikers, you must use the CreateFileMoniker API function to create the monikers. In order to allow your objects to be loaded when a file moniker is bound, your objects must implement the IPersistFile interface.

The most common example of moniker providers are OLE server applications that support linking. If your OLE server application supports linking only to file-based documents in their entirety, file monikers are the only type of moniker you need. If your OLE server application supports linking to objects smaller than a document (such as sections of a document or embedded objects), you must use item monikers as well as file monikers.

See Also

CreateFileMoniker, IMoniker, IPersistFile

Comments

IMoniker::BindToObject

This method requires that pmkToLeft be NULL. The method looks for the moniker in the ROT, and if found, queries the retrieved object for the requested interface pointer. If the moniker is not found in the ROT, the method loads the object from the file system and retrieves the requested interface pointer.

IMoniker::BindToStorage

This method opens the file specified by the pathname represented by the moniker and returns an IStorage pointer to that file. The method supports binding to IStorage interface only; if IStream or ILockBytes is requested in riid, the method returns E_UNSPEC, and if other interfaces are requested, this method returns E_NOINTERFACE. IStream and ILockBytes will be supported in future releases.

IMoniker::Reduce

This method returns MK_S_REDUCED_TO_SELF and passes back the same moniker.

IMoniker::ComposeWith

If pmkRight is an anti-moniker, the returned moniker is NULL. If pmkRight is a composite whose leftmost component is an anti-moniker, the returned moniker is the composite with the leftmost anti-moniker removed. If pmkRight is a file moniker, this method collapses the two monikers into a single file moniker, if possible. If not possible (e.g., if both file monikers represent absolute paths, as in d:\work and e:\reports), then the returned moniker is NULL and the return value is MK_E_SYNTAX. If pmkRight is neither an anti-moniker nor a file moniker, then the method checks the fOnlyIfNotGeneric parameter; if it is FALSE, the method combines the two monikers into a generic composite; if it is TRUE, the method sets *ppmkComposite to NULL and returns MK_E_NEEDGENERIC.

IMoniker::Enum

This method returns S_OK and sets *ppenumMoniker to NULL. In a future release this method will pass back an enumerator that enumerates the components of the path on which the moniker is based.

IMoniker::IsEqual

This method returns S_OK if *pmkOther is a file moniker and the paths for both monikers are identical (using a case-insensitive comparison). Otherwise, the method returns S_FALSE.

IMoniker::Hash

This method calculates a hash value for the moniker.

IMoniker::IsRunning

If pmkNewlyRunning is non-NULL, this method returns TRUE if that moniker is equal to this moniker. Otherwise, the method asks the ROT whether this moniker is running. The method ignores pmkToLeft.

IMoniker::GetTimeOfLastChange

If this moniker is in the ROT, this method returns the last change time registered there; otherwise, it returns the last write time for the file. If the file cannot be found, this method returns MK_E_NOOBJECT.

IMoniker::Inverse

This method returns an anti-moniker (i.e., the results of calling CreateAntiMoniker).

IMoniker::CommonPrefixWith

If both monikers are file monikers, this method returns a file moniker that is based on the common components at the beginning of two file monikers. Components of a file moniker can be:

•	A machine name of the form \\server\share. A machine name is treated as a single component, so two monikers representing the paths "\\myserver\public\work" and "\\myserver\private\games" do not have "\\myserver" as a common prefix.

•	A drive designation (for example, "C:").

•	A directory or filename.

If the other moniker is not a file moniker, this method passes both monikers in a call to the MonikerCommonPrefixWith API function. This API function correctly handles the case where the other moniker is a generic composite.

This method returns MK_E_NOPREFIX if there is no common prefix.

IMoniker::RelativePathTo

This method computes a moniker which when composed to the right of this moniker yields the other moniker. For example, if the path of this moniker is "C:\work\docs\report.doc" and if the other moniker is "C:\work\art\picture.bmp," then the path of the computed moniker would be "..\..\art\picture.bmp."

IMoniker::GetDisplayName

This method returns the pathname that the moniker represents. If this method is called by a 16-bit application, the method checks to see whether the specified file exists and, if so, returns a short name for that file because 16-bit applications are not equipped to handle long filenames.

IMoniker::ParseDisplayName

This method tries to acquire an IParseDisplayName pointer, first by binding to the class factory for the object identified by the moniker, and then by binding to the object itself. If either of these binding operations is successful, the file moniker passes the unparsed portion of the display name to the IParseDisplayName::ParseDisplayName method.

This method returns MK_E_SYNTAX if pmkToLeft is non-NULL.

IMoniker::IsSystemMoniker

This method returns S_OK, and passes back MKSYS_FILEMONIKER.


IMoniker - Generic Composite Moniker Implementation

A generic composite moniker is a composite moniker whose components have no special knowledge of each other.

Composition is the process of joining two monikers together. Sometimes two monikers of specific classes can be combined in a special manner; for example, a file moniker representing an incomplete path and another file moniker representing a relative path can be combined to form a single file moniker representing the complete path. This is an example of "non-generic" composition. "Generic" composition, on the other hand, can connect any two monikers, no matter what their classes. Because a non-generic composition depends on the class of the monikers involved, it can be performed only by a particular class's implementation of the IMoniker::ComposeWith method. You can define new types of non-generic compositions if you write a new moniker class. By contrast, generic compositions are performed by the CreateGenericComposite API function.

When to Use

If you're a moniker client (that is, you're using a moniker to get an interface pointer to an object), you typically don't need to know the class of the moniker you're using, or whether it is a generic composite or a non-generic composite; you simply call methods using an IMoniker interface pointer.

If you're a moniker provider (that is, you're handing out monikers that identify your objects to make them accessible to moniker clients), you may have to compose two monikers together. (For example, if you are using an item moniker to identify an object, you must compose it with the moniker identifying the object's container before you hand it out.) You use the IMoniker::ComposeWith method to do this, calling the method on the first moniker and passing the second moniker as a parameter; this method may produce either a generic or a non-generic composite.

The only time you should explicitly create a generic composite moniker is if you are writing your own moniker class. In your implementation of IMoniker::ComposeWith, you should attempt to perform a non-generic composition whenever possible; if you cannot perform a non-generic composition and generic composition is acceptable, you can call the CreateGenericComposite API function to create a generic composite moniker.

See Also

CreateGenericComposite, IMoniker

Comments

IMoniker::BindToObject

If pmkToLeft is NULL, this method looks for the moniker in the ROT, and if found, queries the retrieved object for the requested interface pointer. If pmkToLeft is not NULL, the method recursively calls IMoniker::BindToObject on the rightmost component of the composite, passing the rest of the composite as the pmkToLeft parameter for that call.

IMoniker::BindToStorage

This method recursively calls BindToStorage on the rightmost component of the composite, passing the rest of the composite as the pmkToLeft parameter for that call.

IMoniker::Reduce

This method recursively calls Reduce for each of its component monikers. If any of the components reduces itself, the method returns S_OK and passes back a composite of the reduced components. If no reduction occurred, the method passes back the same moniker and returns MK_S_REDUCED_TO_SELF.

IMoniker::ComposeWith

If fOnlyIfNotGeneric is TRUE, this method sets *pmkComposite to NULL and returns MK_E_NEEDGENERIC; otherwise, the method returns the result of combining the two monikers by calling the CreateGenericComposite API function.

IMoniker::Enum

If successful, this method returns S_OK and passes back an enumerator that enumerates the component monikers that make up the composite; otherwise, the method returns E_OUTOFMEMORY.

IMoniker::IsEqual

This method returns S_OK if the components of both monikers are equal when compared in the left-to-right order.

IMoniker::Hash

This method calculates a hash value for the moniker.

IMoniker::IsRunning

If pmkToLeft is non-NULL, this method composes pmkToLeft with this moniker and calls IsRunning on the result.

If pmkToLeft is NULL, this method returns TRUE if pmkNewlyRunning is non-NULL and is equal to this moniker.

If pmkToLeft and pmkNewlyRunning are both NULL, this method checks the ROT to see whether the moniker is running. If so, the method returns S_OK; otherwise, it recursively calls IMoniker::IsRunning on the rightmost component of the composite, passing the remainder of the composite as the pmkToLeft parameter for that call. This handles the case where the moniker identifies a pseudo-object that is not registered as running; see the Item Moniker implementation of IMoniker::IsRunning.

IMoniker::GetTimeOfLastChange

This method creates a composite of pmkToLeft (if non-NULL) and this moniker and uses the ROT to retrieve the time of last change. If the object is not in the ROT, the method recursively call IMoniker::GetTimeOfLastChange on the rightmost component of the composite, passing the remainder of the composite as the pmkToLeft parameter for that call.

IMoniker::Inverse

This method returns a composite moniker that consists of the inverses of each of the components of the original composite, stored in reverse order. For example, if the inverse of A is A  (-1)  , then the inverse of the composite A  (°)  B  (°)  C is C  (-1)   (°)  B  (-1)   (°)  A  (-1) .

IMoniker::CommonPrefixWith

If the other moniker is a composite, this method compares the components of each composite from left to right. The returned common prefix moniker might also be a composite moniker, depending on how many of the leftmost components were common to both monikers. If the other moniker is not a composite, the method simply compares it to the leftmost component of this moniker.

If the monikers are equal, the method returns MK_S_US and sets *ppmkPrefix to this moniker. If the other moniker is a prefix of this moniker, the method returns MK_S_HIM and sets *ppmkPrefix to the other moniker. If this moniker is a prefix of the other, this method returns MK_S_ME and sets *ppmkPrefix to this moniker.

If there is no common prefix, this method returns MK_E_NOPREFIX and sets *ppmkPrefix to NULL.

IMoniker::RelativePathTo

This method finds the common prefix of the two monikers and creates two monikers that consist of the remainder when the common prefix is removed. Then it creates the inverse for the remainder of this moniker and composes the remainder of the other moniker on the right of it.

IMoniker::GetDisplayName

This method returns the concatenation of the display names returned by each component moniker of the composite.

IMoniker::ParseDisplayName

This method recursively calls IMoniker::ParseDisplayName on the rightmost component of the composite, passing everything else as the pmkToLeft parameter for that call.

IMoniker::IsSystemMoniker

This method returns S_OK and indicates MKSYS_GENERICCOMPOSITE.


IMoniker - Item Moniker Implementation

Item monikers are used to identify objects within containers, such as a portion of a document, an embedded object within a compound document, or a range of cells within a spreadsheet. Item monikers are often used in combination with file monikers; a file moniker is used to identify the container while an item moniker is used to identify the item within the container.

An item moniker contains a text string; this string is used by the container object to distinguish the contained item from the others. The container object must implement the IOleItemContainer interface; this interface enables the item moniker code to acquire a pointer to an object, given only the string that identifies the object.

When to Use

If you're a moniker client (that is, you're using a moniker to get an interface pointer to an object), you typically don't need to know the class of the moniker you're using; you simply call methods using an IMoniker interface pointer.

If you're a moniker provider (that is, you're handing out monikers that identify your objects to make them accessible to moniker clients), you must use item monikers if the objects you're identifying are contained within another object and can be individually identified using a string. You'll also need to use another type of moniker (for example, file monikers) in order to identify the container object.

To use item monikers, you must use the CreateItemMoniker API function to create the monikers. In order to allow your objects to be loaded when an item moniker is bound, the container of your objects must implement the IOleItemContainer interface.

The most common example of moniker providers are OLE applications that support linking. If your OLE application supports linking to objects smaller than a file-based documents, you need to use item monikers. For a server application that allows linking to a selection within a document, you use the item monikers to identify those objects. For a container application that allows linking to embedded objects, you use the item monikers to identify the embedded objects.

See Also

CreateItemMoniker, IMoniker, IOleItemContainer

Comments

IMoniker::BindToObject

If pmkToLeft is NULL, this method returns E_INVALIDARG. Otherwise, the method calls IMoniker::BindToObject on the pmkToLeft parameter, requesting an IOleItemContainer interface pointer. The method then calls IOleItemContainer::GetObject, passing the string contained within the moniker, and returns the requested interface pointer.

IMoniker::BindToStorage

If pmkToLeft is NULL, this method returns E_INVALIDARG. Otherwise, the method calls IMoniker::BindToObject on the pmkToLeft parameter, requesting an IOleItemContainer interface pointer. The method then calls IOleItemContainer::GetObjectStorage for the requested interface.

IMoniker::Reduce

This method returns MK_S_REDUCED_TO_SELF and passes back the same moniker.

IMoniker::ComposeWith

If pmkRight is an anti-moniker, the returned moniker is NULL; if pmkRight is a composite whose leftmost component is an anti-moniker, the returned moniker is the composite after the leftmost anti-moniker is removed. If pmkRight is not an anti-moniker, the method combines the two monikers into a generic composite if fOnlyIfNotGeneric is FALSE; if fOnlyIfNotGeneric is TRUE, the method returns a NULL moniker and a return value of MK_E_NEEDGENERIC.

IMoniker::Enum

This method returns S_OK and sets *ppenumMoniker to NULL.

IMoniker::IsEqual

This method returns S_OK if both monikers are item monikers and their display names are identical (using a case-insensitive comparison); otherwise, the method returns S_FALSE.

IMoniker::Hash

This method calculates a hash value for the moniker.

IMoniker::IsRunning

If pmkToLeft is NULL, this method returns TRUE if pmkNewlyRunning is non-NULL and is equal to this moniker. Otherwise, the method checks the ROT to see whether this moniker is running.

If pmkToLeft is non-NULL, the method calls IMoniker::BindToObject on the pmkToLeft parameter, requesting an IOleItemContainer interface pointer. The method then calls IOleItemContainer::IsRunning, passing the string contained within this moniker.

IMoniker::GetTimeOfLastChange

If pmkToLeft is NULL, this method returns MK_E_NOTBINDABLE. Otherwise, the method creates a composite of pmkToLeft and this moniker and uses the ROT to access the time of last change. If the object is not in the ROT, the method calls IMoniker::GetTimeOfLastChange on the pmkToLeft parameter.

IMoniker::Inverse

This method returns an anti-moniker (i.e., the results of calling CreateAntiMoniker).

IMoniker::CommonPrefixWith

If other moniker is an item moniker that is equal to this moniker, this method sets *ppmkPrefix to this moniker and returns MK_S_US; otherwise, the method calls the MonikerCommonPrefixWith API function. This API function correctly handles the case where the other moniker is a generic composite.

IMoniker::RelativePathTo

This method returns MK_E_NOTBINDABLE and sets *ppmkRelPath to NULL.

IMoniker::GetDisplayName

This method returns the concatenation of the delimiter and the item name that were specified when the item moniker was created.

IMoniker::ParseDisplayName

If pmkToLeft is NULL, this method returns MK_E_SYNTAX. Otherwise, the method calls IMoniker::BindToObject on the pmkToLeft parameter, requesting an IOleItemContainer interface pointer. The method then calls IOleItemContainer::GetObject, requesting an IParseDisplayName interface pointer to the object identified by the moniker, and passes the display name to IParseDisplayName::ParseDisplayName.

IMoniker::IsSystemMoniker

This method returns S_OK and indicates MKSYS_ITEMMONIKER.


IMoniker - Pointer Moniker Implementation

A pointer moniker essentially wraps an interface pointer so that it looks like a moniker and can be passed to those interfaces that require monikers. Binding a pointer moniker is done by calling the pointer's QueryInterface method.

Instances of pointer monikers refuse to be serialized, that is, IPersistStream::Save will return an error. These monikers can, however, be marshaled to a different process in an RPC call; internally, the system marshals and unmarshals the pointer using the standard paradigm for marshaling interface pointers.

When to Use

Pointer monikers are rarely needed. Use pointer monikers only if you need monikers to identify objects that have no persistent representation. Pointer monikers allow such objects to participate in a moniker-binding operation.

See Also

IMoniker, CreatePointerMoniker

Comments

IMoniker::BindToObject

This method queries the wrapped pointer for the requested interface.

IMoniker::BindToStorage

This method queries the wrapped pointer for the requested interface.

IMoniker::Reduce

This method returns MK_S_REDUCED_TO_SELF and passes back the same moniker.

IMoniker::ComposeWith

If pmkRight is an anti-moniker, the returned moniker is NULL; if pmkRight is a composite whose leftmost component is an anti-moniker, the returned moniker is the composite after the leftmost anti-moniker is removed. If fOnlyIfNotGeneric is FALSE, the returned moniker is a generic composite of the two monikers; otherwise, the method sets *ppmkComposite to NULL and returns MK_E_NEEDGENERIC.

IMoniker::Enum

This method is not implemented (that is, it returns E_NOTIMPL).

IMoniker::IsEqual

This method returns S_OK only if both are pointer monikers and the interface pointers that they wrap are identical.

IMoniker::Hash

This method calculates a hash value for the moniker.

IMoniker::IsRunning

This method always returns S_OK, because the object identified by a pointer moniker must always be running.

IMoniker::GetTimeOfLastChange

This method is not implemented (that is, it returns E_NOTIMPL).

IMoniker::Inverse

This method returns an anti-moniker (i.e., the results of calling CreateAntiMoniker).

IMoniker::CommonPrefixWith

If the two monikers are equal, this method returns MK_S_US and sets *ppmkPrefix to this moniker. Otherwise, the method returns MK_E_NOPREFIX and sets *ppmkPrefix to NULL.

IMoniker::RelativePathTo

This method is not implemented (that is, it returns E_NOTIMPL).

IMoniker::GetDisplayName

This method is not implemented (that is, it returns E_NOTIMPL).

IMoniker::ParseDisplayName

This method queries the wrapped pointer for the IParseDisplayName interface and passes the display name to IParseDisplayName::ParseDisplayName.

IMoniker::IsSystemMoniker

This method returns S_OK and indicates MKSYS_POINTERMONIKER.


IOleAdviseHolder

The IOleAdviseHolder interface enables object applications to delegate the management of compound document registration requests and notifications to a special object called the OLE advise holder. The OLE advise holder implements the IOleAdviseHolder interface, which provides methods for establishing and deleting advisory connections and for sending compound document notifications to advise sinks.

When an object application uses the OLE advise holder, it passes notifications directly to the IOleAdviseHolder interface. The advise holder keeps track of which advise sinks are interested in which notifications and passes along the notifications as appropriate.

When to Implement

OLE provides a default implementation of the OLE advise holder as a convenience to programmers. Use of the default implementation is optional because object applications can be written to manage notifications themselves. By using the default code, however, you save yourself the work of re-creating the advise holder's functionality from scratch as part of your implementation of IOleObject::Advise. Few applications will require notification capabilities beyond those which the default advise holder provides.

Applications instantiate an OLE advise holder by calling the OLE API function CreateOleAdviseHolder. (OLE also provides a data advise holder to manage data notifications. Applications create a data advise holder by calling the OLE API function CreateDataAdviseHolder.)

When to Use

Containers and other objects that wish to receive compound document notifications must implement the IAdviseSink interface to receive those notifications, and call the IOleAdviseHolder interface to establish an advisory connection and inform the object of what specific notifications it wishes to receive.

Methods in VTable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments reference count.
Release	Decrements reference count.
IOleAdviseHolder Methods	Description
Advise	Establishes advisory connection with sink.
Unadvise	Deletes advisory connection with sink.
EnumAdvise	Lists current advisory connections.
SendOnRename	Advises that name of object has changed.
SendOnSave	Advises that object has been saved.
SendOnClose	Advises that object has been closed.


IOleAdviseHolder::Advise

Establishes an advisory connection between an OLE object and the calling object's advise sink. Through that sink, the calling object can receive notification when the OLE object is renamed, saved, or closed.

HRESULT Advise(

IAdviseSink * pAdvise,	//Pointer to advise sink
DWORD * pdwConnection	//Pointer to a token
);
Parameters

pAdvise

[in] Points to the advisory sink that should be informed of changes.

pdwConnection

[out] Points to a token that can be passed to the IOleAdviseHolder::Unadvise method to delete the advisory connection. The calling object is responsible for calling both IUnknown::AddRef and IUnknown::Release on this pointer.

Return Values

S_OK

Advisory connections set up successfully.

E_INVALIDARG

pAdvise is NULL.

Comments

Containers, object handlers, and link objects all create advise sinks to receive compound-document notifications (OnSave, OnRename, and OnClose) for objects of interest. They also call IOleObject::Advise to establish advisory connections with those objects. Objects whose implementations of IOleObject::Advise include a call to CreateOleAdviseHolder delegate these calls to IOleAdviseHolder::Advise.

If the attempt to establish an advisory connection is successful, the object receiving the call returns a nonzero value through pdwConnection. If the attempt fails, the object returns a zero. To delete an advisory connection, the object with the advise sink passes this nonzero token back to the object by calling IOleAdviseHolder::Unadvise.

See Also

IOleAdviseHolder::UnAdvise, IOleAdviseHolder::EnumAdvise, IOleObject::Advise


IOleAdviseHolder::EnumAdvise

Enumerates the advisory connections currently established for an object.

HRESULT EnumAdvise(

IEnumSTATDATA ** ppenumAdvise	//A pointer to a pointer to the new enumerator
);
Parameter

ppenumAdvise

[out] Points to where the new enumerator should be returned. NULL is a legal return value indicating that there are presently no advisory connections on the object. If an error is returned; this parameter must be set to NULL. Each time an OLE advise holder receives a call to IOleAdviseHolder::EnumAdvise; it must increase the reference count on the pointer it returns. It is the caller's responsibility to call IUnknown::Release when it is done with the pointer.

Return Values

S_OK

Enumerator returned successfully.

E_FAIL

Enumerator could not be returned.

E_NOTIMPL

EnumAdvise is not implemented.

Comments

While an enumeration is in progress; the effect of registering or revoking advisory connections on what is to be enumerated is undefined. The returned enumerator is of type IEnumSTATDATA. It enumerates items of type STATDATA; which are defined as follows:

typedef struct tagSTATDATA {

FORMATETC         Formatetc;

DWORD             grfAdvf;

IAdviseSink *     pAdvise;

DWORD             dwConnection;

}STATDATA;

See Also

IOleAdviseHolder::Advise, IOleAdviseHolder::UnAdvise, IOleObject::EnumAdvise


IOleAdviseHolder::SendOnClose

Sends OnClose notifications to all advisory sinks currently registered with the advise holder.

HRESULT SendOnClose();

Return Value

S_OK

Advise sinks were sent OnClose notifications.

See Also

IAdviseSink::OnClose


IOleAdviseHolder::SendOnRename

Sends IAdviseSink::OnRename notifications to all advisory sinks currently registered with the advise holder.

HRESULT SendOnRename(

IMoniker *pmk	//Pointer to a IMoniker interface
);
Parameter

pmk

[in] Points to the new full moniker of the object.

Return Value

S_OK

Advise sinks were sent IAdviseSink::OnRename notifications.

See Also

IAdviseSink::OnRename


IOleAdviseHolder::SendOnSave

Sends IAdviseSink::OnSave notifications to all advisory sinks currently registered with the advise holder.

HRESULT SendOnSave();

Return Value

S_OK

Advise sinks were sent IAdviseSink::OnSave notifications.

See Also

IAdviseSink::OnSave


IOleAdviseHolder::Unadvise

Deletes a previously established advisory connection.

HRESULT Unadvise(

DWORD dwConnection	//A nonzero value
);
Parameter

dwConnection

[in] Contains a nonzero value previously returned by IOleAdviseHolder::Advise in pdwConnection.

Return Values

S_OK

Advisory connection deleted successfully.

OLE_E_NOCONNECTION

The dwConnection parameter does not represent a valid advisory connection.

Comments

Normally, containers call this method at shutdown or when an object is deleted. In certain cases, containers could choose to call this method on objects that are running but not currently visible, as a way of reducing the overhead of maintaining multiple advisory connections.

See Also

IOleAdviseHolder::Advise, IOleAdviseHolder::EnumAdvise, IOleObject::Unadvise


IOleCache

The IOleCache interface provides control of the presentation data that gets cached inside of an object. Cached presentation data is available to the container of the object even when server application is not running or is unavailable.

When to Implement

The IOleCache interface can be implemented by an object handler and an in-process server. However, you typically use or aggregate the OLE-provided implementation.

When to Use

The OLE-provided implementation creates a class node for each aspect and format of the data that it stores. In addition to the presentation data, the class node holds the sink pointer for the advisory connection and manages the sending of view notifications to the advise sink.

Methods in VTable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments the reference count.
Release	Decrements the reference count.
IOleCache Methods	Description
Cache	Adds a presentation to the data or view cache.
Uncache	Removes a presentation previously added with IOleCache::Cache.
EnumCache	Returns an object to enumerate the current cache connections.
InitCache	Fills the cache with all the presentation data from the data object.
SetData	Fills the cache with specified format of presentation data.


IOleCache::Cache

Specifies the format and other data to be cached inside an embedded object.

HRESULT Cache(

FORMATETC * pFormatetc,	//Points to the data and formats to be cached
DWORD advf,	//Flags that control the caching
DWORD * pdwConnection	//Identifies the connection for future calls to uncache
);
Parameters

pFormatetc

[in]Points to the format and other data to be cached. View caching is specified by passing a zero clipboard format in pFormatetc.

advf

[in]Contains a group of flags that control the caching. Valid values can be derived by using an OR operation on the values in the ADVF enumeration. However, only some of the possible ADVF values are relevant for this method. The following table briefly describes the relevant values and how they control caching. See the ADVF enumeration for a more detailed description.

ADVF Value	Description
ADVF_NODATA	Asks the data object to avoid sending data with the notifications. This flag is a way to override the default behavior of sending data with the notification. Typically, this flag is used when the iconic aspect of an object is cached. The cache can then be updated explicitly by calling IOleCache::SetData, IDataObject::SetData, or IOleCache2::UpdateCache.
ADVF_ONLYONCE	Causes the advisory connection to be destroyed after the first notification is sent.
ADVF_PRIMEFIRST	Causes an initial notification to be sent regardless of whether data has changed from its current state.
ADVFCACHE_NOHANDLER	Synonym for ADVFCACHE_FORCEBUILTIN.
ADVFCACHE_FORCEBUILTIN	For cache connections, this flag caches data that requires only code shipped with OLE or the underlying operating system to be present in order to produce it with IDataObject::GetData or IViewObject::Draw. By specifying this value, the container can ensure that the data can be retrieved even when the object or handler code is not available. This value is used by DLL object applications and object handlers that perform the drawing of their objects. ADVFCACHE_FORCEBUILTIN instructs OLE to cache presentation data to ensure that there is a presentation in the cache.
ADVFCACHE_ONSAVE	Updates the cached representation only when the object containing the cache is saved. The cache is also updated when the OLE object changes from the running state back to the loaded state (because a subsequent save operation would require running the object again).
pdwConnection

[out]Points to the location of a returned token that identifies this connection and can later be used to turn caching off (by passing it to IOleCache::Uncache). If this value is zero, the connection was not established. The OLE-provided implementation uses nonzero numbers for connection identifiers.

Return Values

S_OK

Requested data or view successfully cached.

E_INVALIDARG

One or more arguments are invalid.

E_OUTOFMEMORY

Ran out of memory.

E_UNEXPECTED

An unexpected error occurred.

CACHE_S_FORMATETC_NOTSUPPORTED

Indicates the cache was created, but the object application does not support the specified format. Cache creation succeeds even if the format is not supported, allowing the caller to fill the cache. If, however, the caller does not need to keep the cache, call IOleCache::UnCache.

CACHE_S_SAMECACHE

Indicates a cache already exists for the FORMATETC passed to IOleCache::Cache. In this case, the new advise flags are assigned to the cache, and the previously assigned connection identifier is returned.

DV_E_LINDEX

Invalid value for lindex; currently only -1 is supported.

DV_E_TYMED

The value is not valid for pFormatetc->tymed.

DV_E_DVASPECT

The value is not valid for pFormatetc->dwAspect.

DV_E_CLIPFORMAT

The value is not valid for pFormatetc->cfFormat.

CO_E_NOTINITIALIZED

The cache's storage is not initialized.

DV_E_DVTARGETDEVICE

The value is not valid for pFormatetc->ptd.

OLE_E_STATIC

The cache is for static object and it already has a cache node.

Comments

IOleCache::Cache can specify either data caching by passing a valid data format in pFormatetc or view (presentation) caching by passing a zero data format in pFormatetc as follows:

pFormatetc->cfFormat == 0

With view caching, the cache object itself decides on the format to cache.

A custom object handler can choose not to store data in a given format. Instead, it can synthesize it on demand when requested.

The advf value of ADVFCACHE_FORCEBUILTIN ensures that presentation data can be retrieved after the container document has been moved where the object application or object handler is not available.

When an IOleCache::Cache call is made to cache either CF_DIB or CF_BITMAP, the OLE cache implementation will implicitly cache the other format. Thus, the enumerator (IOleCache::EnumCache) will have two entries (CF_DIB and CF_BITMAP) for the one cached format. Both of these entries have the same connection ID, so one call to IOleCache::Uncache will remove both. CF_DIB and CFBITMAP may also be explicitly cached separately (by two calls to IOleCache::Cache).

See Also

ADVF, IOleCache::Uncache


IOleCache::EnumCache

Returns an object that can be used to enumerate the current cache connections.

HRESULT EnumCache(

IEnumSTATDATA ** ppenumSTATDATA	//Location for IEnumSTATDATA
);
Parameter

ppenumSTATDATA

[out]Points to the location where the new enumerator object should be returned. If this value is NULL, there are currently no cache connections at this time.

Return Values

S_OK

The enumerator object is successfully instantiated or there are no cache connections. Check the ppenumSTATDATA parameter to determine which result occurred. If the ppenumSTATDATA parameter is NULL, then there are no cache connections at this time.

E_OUTOFMEMORY

The cache enumerator could not be instantiated due to lack of memory.

Comments

The enumerator object returned by this method implements the IEnumSTATDATA interface, one of the standard enumerator interfaces that contain the Next, Reset, Clone, and Skip methods. IEnumSTATDATA enumerates the data stored in an array of STATDATA structures containing information about current cache connections.

See Also

IEnumXXXX, IEnumSTATDATA, IOleCache::Cache


IOleCache::InitCache

Fills the cache as needed using the data provided by the specified data object.

HRESULT InitCache(

IDataObject * pDataObject	//Points to the data object from which the cache is initialized
);
Parameter

pDataObject

[in]Points to the data object from which the cache is to be initialized.

Return Values

S_OK

The cache was filled using the data provided.

E_INVALIDARG

The value for pDataObject is not valid.

E_OUTOFMEMORY

The cache could not be initialized due to lack of memory.

OLE_E_NOTRUNNING

The cache is not running.

CACHE_E_NOCACHE_UPDATED

None of the caches were updated.

CACHE_S_SOMECACHES_NOTUPDATED

Only some of the existing caches were updated.

Comments

IOleCache::InitCache is usually used when creating an object from a drag-and-drop operation or from a clipboard paste operation. It fills the cache as needed with presentation data from all the data formats provided by the data object provided on the clipboard or in the drag-and-drop operation. Helper functions like OleCreateFromData or OleCreateLinkFromData call this method when needed. If a container does not use these helper functions to create compound document objects, it can use IOleCache::Cache to set up the cache entries which are then filled by IOleCache::InitCache.

See Also

IOleCache::Cache


IOleCache::SetData

Initializes the cache with data in a specified format and on a specified medium.

HRESULT SetData(

FORMATETC * pFormatetc,	//Points to the format of the presentation data to be placed in the cache
STGMEDIUM * pmedium,	//Points to the storage medium containing the data to be placed in the cache
BOOL fRelease	//Indicates ownership of the storage medium after this method is completed
);
Parameters

pFormatetc

[in] Points to the format of the presentation data being placed in the cache.

pmedium

[in] Points to the storage medium that contains the presentation data.

fRelease

[in] Indicates ownership of the storage medium after completion of the method. If fRelease is TRUE, the cache takes ownership, freeing the medium when it is finished using it. When fRelease is FALSE, the caller retains ownership and is responsible for freeing the medium. The cache can only use the storage medium for the duration of the call.

Return Values

S_OK

The cache was filled.

E_OUTOFMEMORY

The cache could not be filled due to a lack of memory.

DV_E_LINDEX

The value is not valid for pFormatetc->lindex. Currently, only -1 is supported.

DV_E_FORMATETC

The FORMATETC structure is invalid.

DV_E_TYMED

The value is not valid for pFormatetc->tymed.

DV_E_DVASPECT

The value is not valid for pFormatetc->dwAspect.

OLE_E_BLANK

Uninitialized object.

DV_E_TARGETDEVICE

The object is static and pFormatetc->ptd is non-NULL.

STG_E_MEDIUMFULL

The storage medium is full.

Comments

IOleCache::SetData is usually called when an object is created from the Clipboard or through a drag-and-drop operation and Embed Source data is used to create the object.

IOleCache::SetData and IOleCache::InitCache are very similar. There are two main differences. The first difference is that while IOleCache::InitCache initializes the cache with the any presentation format provided by the data object, IOleCache::SetData initializes it with a single format. Second, the IOleCache::SetData method ignores the ADVF_NODATA flag while IOleCache::InitCache obeys this flag.

A container can use this method to maintain a single aspect of an object, such as the icon aspect of the object.

See Also

IDataObject::SetData, IOleCache::Cache


IOleCache::Uncache

Removes a cache connection created in a prior call to IOleCache::Cache.

HRESULT Uncache(

DWORD dwConnection	//Specifies the cache connection to remove
);
Parameter

dwConnection

[in]Specifies the cache connection to remove. This non-zero value was returned by IOleCache::Cache when the cache was originally established.

Return Values

S_OK

The cache connection was deleted.

OLE_E_NOCONNECTION

No cache connection exists for dwConnection.

Comments

The IOleCache::Uncache method removes a cache connection that was created in a prior call to IOleCache::Cache. It uses the dwConnection parameter that was returned by the prior call to IOleCache::Cache.

See Also

IOleCache::Cache


IOleCache2

The IOleCache2 interface allows object clients to selectively update each cache that was created with IOleCache::Cache.

When to Implement

The IOleCache interface can be implemented by an object handler and an in-process server. However, you typically use or aggregate the OLE-provided implemention.

When to Use

The OLE-provided implementation is an extension to the IOleCache interface. The IOleCache2 interface is used by container applications, object handlers, or in process servers to update one or more of the caches that were created with the IOleCache::Cache method. This extended interface was added so client applications can exercise precise control over updates to the caches being maintained.

Methods in VTable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments the reference count.
Release	Decrements the reference count.
IOleCache2 Methods	Description
UpdateCache	Updates the specified cache(s).
DiscardCache	Discards cache(s) found in memory.


IOleCache2::DiscardCache

Discards the caches in memory.

HRESULT DiscardCache(

DWORD dwDiscardOptions	//Save data or discard it
);
Parameter

dwDiscardOptions

Indicates whether data is to be saved prior to the discard. Valid values are from the enumeration DISCARDCACHE. Containers that have drawn a large object and need to free up memory may want to specify DISCARDCACHE_SAVEIFDIRTY so that the newest presentation is saved for the next time the object must be drawn.

Containers that have activated an embedded object, made some changes, and then called IOleObject::Close(OLECLOSE_NOSAVE) to roll back the changes can specify DISCARDCACHE_NOSAVE to ensure that the native and presentation data are not out of synchronization.

Return Values

S_OK

The cache(s) were discarded according to the value specified in dwDiscardOptions.

E_INVALIDARG

One or more arguments are invalid.

E_UNEXPECTED

An unexpected error occurred.

OLE_E_NOSTORAGE

There is no storage available for saving the data in the cache.

STG_E_MEDIUMFULL

The storage medium is full.

Comments

The IOleCache2::DiscardCache method is commonly used to handle low memory conditions by freeing memory currently being used by presentation caches.

Once discarded, the cache will satisfy subsequent IDataObject::GetData calls by reverting to disk-based data.

See Also

DISCARDCACHE, IOleCache, IOleCacheControl


IOleCache2::UpdateCache

Updates specified cache(s). It updates the cache according to the value of a parameter. This method is used when the application needs precise control over caching.

HRESULT UpdateCache(

IDataObject * pDataObject,	//Points to the data object from which the cache is updated
DWORD grfUpdt,	//Specifies the type of cache to update
LPVOID pReserved	//Reserved, must be NULL
);
Parameters

pDataObject

[in]Points to the data object from which the cache is updated. Object handlers and in process servers typically pass a non-NULL value. A container application usually passes NULL, and the source is obtained from the currently running object.

grfUpdt

Specifies the type of cache to update. The value is obtained by combining values from the following table:

Cache Control Values	Description
UPDFCACHE_NODATACACHE	Updates caches created by using ADVF_NODATA in the call to IOleCache::Cache.
UPDFCACHE_ONSAVECACHE	Updates caches created by using ADVFCACHE_ONSAVE in the call to IOleCache::Cache.
UPDFCACHE_ONSTOPCACHE	Updates caches created by using ADVFCACHE_ONSTOP in the call to IOleCache::Cache.
UPDFCACHE_NORMALCACHE	Dynamically updates the caches (as is normally done when the object sends out OnDataChange notices).
UPDFCACHE_IFBLANK	Updates the cache if blank, regardless of any other flag specified.
UPDFCACHE_ONLYIFBLANK	Updates only caches that are blank.
UPDFCACHE_ IFBLANKORONSAVECACHE	The equivalent of using an OR operation to combine UPDFCACHE_IFBLANK and UPDFCACHE_ONSAVECACHE.
UPDFCACHE_ALL	Updates all caches.
UPDFCACHE_ ALLBUTNODATACACHE	Updates all caches except those created with ADVF_NODATA in the call to IOleCache::Cache.  Thus, you can control updates to the caches created with the ADVF_NODATA flag and only update these caches explicitly.
pReserved

Reserved for future use; must be NULL.

Return Values

S_OK

The cache(s) were updated according to the value specified in grfUpdt.

E_OUTOFMEMORY

The cache(s) were not updated due to a lack of memory.

E_INVALIDARG

One or more arguments are invalid.

E_UNEXPECTED

An unexpected error occurred.

OLE_E_NOTRUNNING

The specified pDataObject is not running.

CACHE_E_NOCACHE_UPDATED

None of the caches were updated.

CACHE_S_SOMECACHES_NOTUPDATED

Some of the caches were updated.

See Also

IOleCache, IOleCacheControl


IOleCacheControl

The IOleCacheControl interface provides proper maintenance of caches. It maintains the caches by connecting the running object's IDataObject implementation to the cache allowing the cache to receive notifications from the running object.

When to Implement

The OLE-provided implementation is used by most handlers and in process servers.

When to Use

Object handlers and in process servers use this interface internally to connect the cache part of the handler to the IDataObject implementation of the running object. Container applications have no need for this interface; they use IRunnableObject or OleRun instead.

Methods in VTable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments the reference count.
Release	Decrements the reference count.
IOleCacheControl Methods	Description
OnRun	Notifies the cache when the data object is running so the cache object can establish advise sinks as needed.
OnStop	Notifies the cache to terminate any existing advise sinks.


IOleCacheControl::OnRun

Notifies the cache that the data source object has now entered its running state.

HRESULT OnRun(

DATAOBJECT * pDataObject	//Points to the object that is now running
);
Parameter

pDataObject

[in]Points to the object that is entering the running state.

Return Values

S_OK

The cache was notified and pDataObject is valid.

E_OUTOFMEMORY

The cache was not notified because the system ran out of memory.

E_INVALIDARG

One or more invalid arguments.

E_UNEXPECTED

An unexpected error occurred.

Comments

When IOleCacheControl::OnRun is called, the cache sets up advisory connections as necessary with the source data object so it can receive notifications. The advise sink created between the running object and the cache is destroyed when IOleCacheControl::OnStop is called.

Some object handlers or in process servers might use the cache in a passive manner and not call IOleCacheControl::OnRun. These applications will need to call IOleCache2::UpdateCache, IOleCache::InitCache, or IOleCache::SetData to fill the cache when necessary to ensure the cache gets updated.

IOleCacheControl::OnRun does not create a reference count on pDataObject. It is the responsibility of the caller of OleRun to ensure that the lifetime of pDataObject lasts until OnStop is called. As a result, the caller must be holding a pointer to pDataObject.

See Also

IOleCache2::UpdateCache, IOleCacheControl::OnStop


IOleCacheControl::OnStop

Notifies the cache it should terminate any existing connection previously given to it by using IOleCacheControl::OnRun. No indication is given as to whether a connection existed or not.

HRESULT OnStop( );

Return Values

S_OK

The cache was notified and the advise sink was successfully removed.

E_OUTOFMEMORY

The advise sink was not removed because the system ran out of memory.

E_UNEXPECTED

An unexpected error occurred.

Comments

The data advisory sink between the running object and the cache is destroyed as part of calling IOleCacheControl::OnStop.

See Also

IOleCacheControl::OnRun


IOleClientSite

The IOleClientSite interface is the primary means by which an embedded object obtains information about the location and extent of its display site; its moniker; its user interface; and other resources provided by its container. An object application calls IOleClientSite to request services from the container. A container must provide one instance of IOleClientSite for every compound-document object it contains.

Methods in VTable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments reference count.
Release	Decrements reference count.
IOleClientSite Methods	Description
SaveObject	Saves embedded object.
GetMoniker	Requests object's moniker.
GetContainer	Requests pointer to object's container.
ShowObject	Asks container to display object.
OnShowWindow	Notifies container when object becomes visible or invisible
RequestNewObjectLayout	Asks container to resize display site.


IOleClientSite::GetContainer

Returns a pointer to the container's IOleContainer interface.

HRESULT GetContainer(

LPOLECONTAINER FAR* ppContainer	//Points to where the IOleContainer pointer should be returned
);
Parameter

ppContainer

[out] Points to where the object's IOleContainer interface pointer is to be returned. If an error is returned, this parameter must be set to NULL.

Return Values

S_OK

The pointer to the container's IOleContainer interface was successfully returned.

OLE_E_NOT_SUPPORTED

Client site is in OLE 1 container.

E_NOINTERFACE

The container does not implement the IOleContainer interface.

Comments

If a container supports links to its embedded objects, implementing IOleClientSite::GetContainer enables link clients to enumerate the container's objects and recursively traverse a containment hierarchy. This method is optional but recommended for all containers that expect to support links to their embedded objects.

Link clients can traverse a hierarchy of compound-document objects by recursively calling IOleClientSite::GetContainer to get a pointer to the link source's container; followed by IOleContainer::QueryInterface to get a pointer to the container's IOleObject interface and; finally, IOleObject::GetClientSite to get the container's client site in its container.

Simple containers that do not support links to their embedded objects probably do not need to implement this method. Instead, they can return E_NOINTERFACE and set ppContainer to NULL.


IOleClientSite::GetMoniker

Returns a moniker to an object's client site. An object can force the assignment of its own or its container's moniker by specifying a value for dwAssign.

HRESULT GetMoniker(

DWORD dwAssign,	//Value specifying how moniker is assigned
DWORD dwWhichMoniker,	//Value specifying which moniker is assigned
IMoniker ** ppmk	//Pointer to storage of returned moniker
);
Parameters

dwAssign

[in] Specifies whether to get a moniker only if one has already exists, force assignment of a moniker, create a temporary moniker, or remove a moniker that has been assigned. In practice you will usually request that the container force assignment of the moniker. Values defining these choices are contained in the enumeration OLEGETMONIKER.

dwWhichMoniker

[in] Specifies whether to return the container's moniker, the object's moniker relative to the container, or the object's full moniker. In practice, you will usually request the object's full moniker. Values defining these choices are contained in the enumeration OLEWHICHMK.

ppmk

[out] Points to where to return the object moniker. If an error is returned, this parameter must be set to NULL. Each time a container receives a call to IOleClientSite::GetMoniker, it must increase the reference count on the pointer it returns. It is the caller's responsibility to call Release when it is done with the pointer.

Return Values

S_OK

Requested moniker returned successfully.

E_FAIL

An unspecified error occurred.

E_UNEXPECTED

A serious, unexpected failure has occurred.

E_NOTIMPL

This container cannot assign monikers to objects. This is the case with OLE 1 containers.

Comments

Containers implement IOleClientSite::GetMoniker as a way of passing out monikers for their embedded objects to clients wishing to link to those objects.

When a link is made to an embedded object or to a pseudo-object within it (a range of cells in a spreadsheet; for example), the object needs a moniker to construct the composite moniker indicating the source of the link. If the embedded object does not already have a moniker, it can call IOleClientSite::GetMoniker to request one.

Every container that expects to contain links to embeddings should support IOleClientSite::GetMoniker to give out OLEWHICHMK_CONTAINER, thus enabling link tracking when the link client and link source files move, but maintain the same relative position.

An object must not persistently store its full moniker or its container's moniker, because these can change while the object is not loaded. For example, either the container or the object could be renamed, in which event, storing the container's moniker or the object's full moniker would make it impossible to for a client to track a link to the object.

In some very specialized cases, an object may no longer need a moniker previously assigned to it and may wish to have it removed as an optimization. In such cases, the object can call IOleClientSite::GetMoniker with OLEGETMONIKER_UNASSIGN to have the moniker removed.

See Also

IOleObject::GetMoniker, IOleObject::SetMoniker


IOleClientSite::OnShowWindow

Notifies a container when an embedded object's window is about to become visible or invisible. This method does not apply to an object that is activated in place and therefore has no window separate from that of its container.

HRESULT OnShowWindow(

BOOL fShow	//Value indicating if window is becoming visible
);
Parameter

fShow

[in] Indicates whether an object's window is open (TRUE) or closed (FALSE).

Return Value

S_OK

Shading or hatching has been successfully added or removed

Comments

An embedded object calls IOleClientSite::OnShowWindow to keep its container informed when the object is open in a window. This window may or may not be currently visible to the end user. The container uses this information to shade the object's client site when the object is displayed in a window, and to remove the shading when the object is not. A shaded object, having received this notification, knows that it already has an open window and therefore can respond to being double-clicked by bringing this window quickly to the top, instead of launching its application in order to obtain a new one.


IOleClientSite::RequestNewObjectLayout

Asks container to allocate more or less space for displaying an embedded object.

HRESULT RequestNewObjectLayout();

Return Values

S_OK

Request for new layout succeeded.

E_NOTIMPL

Client site does not support requests for new layout.

Comments

Currently, there is no standard mechanism by which a container can negotiate how much room an object would like. When such a negotiation is defined, responding to this method will be optional for containers.


IOleClientSite::SaveObject

Saves the object associated with the client site. This function is synchronous; by the time it returns, the save will be completed.

HRESULT SaveObject();

Parameter

HRESULT SaveObject(void)

Return Values

S_OK

The object was saved.

E_FAIL

The object was not saved.

Comments

An embedded object calls IOleClientSite::SaveObject to ask its container to save it to persistent storage when an end user chooses the File Update or Exit commands. The call is synchronous, meaning that by the time it returns, the save operation will be completed.

Calls to IOleClientSite::SaveObject occur in most implementations of IOleObject::Close. Normally, when a container tells an object to close, the container passes a flag specifying whether the object should save itself before closing, prompt the user for instructions, or close without saving itself. If an object is instructed to save itself, either by its container or an end user, it calls IOleClientSite::SaveObject to ask the container application to save the object's contents before the object closes itself. If a container instructs an object not to save itself, the object should not call SaveObject.

See Also

IOleObject::Close


IOleClientSite::ShowObject

Tells the container to position the object so it is visible to the user. This method ensures that the container itself is visible and not minimized.

HRESULT ShowObject();

Return Values

S_OK

Container has tried to make the object visible.

OLE_E_NOT_SUPPORTED

Client site is in an OLE 1 container.

Comments

After a link client binds to a link source, it commonly calls IOleObject::DoVerb on the link source, usually requesting the source to perform some action requiring that it display itself to the user. As part of its implementation of DoVerb, the link source can call IOleClientSite::ShowObject, which forces the client to show the link source as best it can. If the link source's container is itself an embedded object, it will recursively invoke IOleClientSite::ShowObject on its own container.

Having called the ShowObject method, a link source has no guarantee of being appropriately displayed because its container may not be able to do so at the time of the call. The ShowObject method does not guarantee visibility, only that the container will do the best it can.

See Also

IOleObject::DoVerb


IOleContainer

The IOleContainer interface is used to enumerate objects in a compound document or lock a container in the running state. Container and object applications both implement this interface.

When to Implement

Applications that support links and links to embedded objects implement this interface to provide object enumeration, name parsing, and silent updates of link sources. Simple, nonlinking containers do not need to implement IOleContainer if it is useful mainly to support links to embedded objects.

When to Use

Call IOleContainer to enumerate the objects in a compound document or to lock a container so that silent updates of link sources can be carried out safely.

Many applications inherit the functions of IOleContainer by implementing IOleItemContainer, which is used to bind item monikers.

Methods in VTable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments reference count.
Release	Decrements reference count.
IParseDisplayName Method	Description
ParseDisplayName	Parses object's display name to form moniker.
IOleContainer Methods	Description
EnumObjects	Enumerates objects in a container.
LockContainer	Keeps container running until explicitly released.
See Also

IOleItemContainer, IParseDisplayName


IOleContainer::EnumObjects

Enumerates objects in the current container.

HRESULT EnumObjects(

DWORD grfFlags,	//Value specifying what is to be enumerated
IEnumUnknown **ppenum	//Ptr to storage of enumeration
);
Parameters

grfFlags

[in] This value specifies which objects in a container are to be enumerated, as defined in the enumeration OLECONTF.

ppenum

[out] Points to an address where the enumerator, of type IEnumUnknown, should be returned. If an error is returned, this parameter must be set to NULL. Each time a container receives a call to EnumObjects, it must increase the reference count on the pointer the method returns. It is the caller's responsibility to call IUnknown::Release when it is done with the pointer.

Return Values

S_OK

Enumerator successfully returned.

E_FAIL

An unspecified error occurred.

E_NOTIMPL

Object enumeration not supported.

Comments

A container should implement EnumObjects to enable programmatic clients to find out what objects it holds. This method, however, is not called in standard linking scenarios.

See Also

IEnumUnknown, IOleItemContainer, OLECONTF


IOleContainer::LockContainer

Keeps an embedded object's container running.

HRESULT LockContainer(

BOOL fLock	//Value indicating lock or unlock
);
Parameter

fLock

[in] Specifies whether to lock (TRUE) or unlock (FALSE) a container.

Return Values

S_OK

Container was locked successfully.

E_FAIL

An unspecified error occurred.

E_OUTOFMEMORY

Container could not be locked due to lack of memory.

Comments

An embedded object calls IOleContainer::LockContainer to keep its container running when the object has link clients that require an update. If an end-user selects File Close from the container's menu, however, the container ignores all outstanding LockContainer locks and closes the document anyway.

Notes to Callers

When an embedded object changes from the loaded to the running state, it should call IOleContainer::LockContainer with the fLock parameter set to TRUE. When the embedded object shuts down (transitions from running to loaded), it should call IOleContainer::LockContainer with the fLock parameter set to FALSE.

Each call to LockContainer with fLock set to TRUE must be balanced by a call to LockContainer with fLock set to FALSE. Object applications typically need not call LockContainer; the default handler makes these calls automatically for object applications implemented as .EXEs as the object makes the transition to and from the running state. Object applications not using the default handler, such as DLL object applications, must make the calls directly.

An object should have no strong locks on it when it registers in the Running Object Table, but it should be locked as soon as the first external client connects to it. Therefore, following registration of the object in the Running Object Table, object handlers and DLL object applications, as part of their implementation of IRunnableObject::Run, should call IOleContainer::LockContainer(TRUE) to lock the object.

Notes to Implementors

The container must keep track of whether and how many calls to LockContainer(TRUE) have been made. To increment or decrement the reference count, IOleContainer::LockContainer calls CoLockObjectExternal with a flag set to match fLock.

See Also

CoLockObjectExternal, IRunnableObject::Run


IOleInPlaceActiveObject

The IOleInPlaceActiveObject interface provides a direct channel of communication between an in-place object and the associated application's outer-most frame window and the document window within the application that contains the embedded object. The communication involves the translation of messages, the state of the frame window (activated or deactivated), and the state of the document window (activated or deactivated). It also informs the object when its needs to resize its borders, and manages modeless dialog boxes.

When to Implement

This interface is implemented by object applications in order to provide support their objects while they are active in place.

When to Use

These methods are used by the in-place object's top-level container to manipulate objects while they are active.

Methods in VTable Order

IUnknown Methods	Description
QueryInterface	Returns a pointer to a specified interface.
AddRef	Increments the reference count.
Release	Decrements the reference count.
IOleWindow Methods	Description
GetWindow	Gets a window handle.
ContextSensitiveHelp	Controls enabling of context sensitive help.
IOleInPlaceActiveObject Methods	Description
TranslateAccelerator	Translates messages.
OnFrameWindowActivate	State of container's top-level frame.
OnDocWindowActivate	State of container document window.
ResizeBorder	Alert object of need to resize border space.
EnableModeless	Enable or disable modeless dialog boxes.
See Also

IOleWindow


IOleInPlaceActiveObject::EnableModeless

Enables or disables modeless dialog boxes when the container creates or destroys a modal dialog box.

HRESULT EnableModeless(

BOOL fEnable	//Enable or disable modeless
);
Parameter

fEnable

[in] Specifies TRUE to enable modeless dialog box windows; FALSE to disable them.

Return Value

S_OK

The method completed successfully.

Comments

Notes to Callers

IOleInPlaceActiveObject::EnableModeless is called by the top-level container to enable and disable modeless dialog boxes that the object displays. In order for the container to display a modal dialog box, it must first call the IOleInPlaceActiveObject::EnableModeless method, specifying FALSE to disable the object's modeless dialog box windows. When the container is through displaying its modal dialog box, it calls IOleInPlaceActiveObject::EnableModeless, specifying TRUE to reenable the object's modeless dialog boxes.

See Also

IOleInPlaceFrame::EnableModeless


IOleInPlaceActiveObject::OnDocWindowActivate

Notifies the active in-place object when the container's document window is activated or deactivated.

HRESULT OnDocWindowActivate(

BOOL fActivate	//State of MDI child document window
);
Parameter

fActivate

[in] Indicates the state of the MDI child document window. It is TRUE if the window is in the act of activating; FALSE if it is in the act of deactivating.

Return Value

S_OK

The method completed successfully.

Comments

Notes to Callers

Call IOleInPlaceActiveObject::OnDocWindowActivate when the MDI child document window is activated or deactivated and the object is currently the active object for the document.

Notes to Implementors

You should include code in this method that installs frame-level tools during object activation. These tools include the shared composite menu and/or optional toolbars and frame adornments. You should then take focus. When deactivating, the object should remove the frame-level tools. Note that if you do not call IOleInPlaceUIWindow::SetBorderSpace with pborderwidths set to NULL, you can avoid having to renegotiate border space.

Note  While executing IOleInPlaceActiveObject::OnDocWindowActivate, do not make calls to the Windows PeekMessage or GetMessage functions, or a dialog box. Doing so may cause the system to deadlock. There are further restrictions on which OLE interface methods and functions can be called from within OnDocWindowActivate.

See Also

PeekMessage, GetMessage in Win32


IOleInPlaceActiveObject::OnFrameWindowActivate

Notifies the object when the container's top-level frame window is activated or deactivated.

HRESULT OnFrameWindowActivate(

BOOL fActivate	//State of container's top-level window
);
Parameter

fActivate

[in] Indicates the state of the container's top-level frame window. TRUE if the window is activating; FALSE if it is deactivating.

Return Value

S_OK

The method notified the object successfully.

Comments

Notes to Callers

The container must call IOleInPlaceActiveObject::OnFrameWindowActivate when the container's top-level frame window is either being activated or deactivated and the object is the current, active object for the frame.

Note  While executing IOleInPlaceActiveObject::OnFrameWindowActivate, do not make calls to the Windows PeekMessage or GetMessage functions, or a dialog box. Doing so may cause the system to deadlock. There are further restrictions on which OLE interface methods and functions can be called from within OnFrameWindowActivate.

See Also

PeekMessage, GetMessage in Win32


IOleInPlaceActiveObject::ResizeBorder

Alerts the object that it needs to resize its border space.

HRESULT ResizeBorder(

LPCRECT prcBorder,	//New outer rectangle for border space
IOleInPlaceUIWindow pUIWindow,	//Frame or document window border change
BOOL fFrameWindow	//Frame window object is or isn't calling ResizeBorder
);
Parameters

prcBorder

[in] Points to a RECT structure containing the new outer rectangle within which the object can request border space for its tools.

pUIWindow

[in] Points to the frame or document window object whose border has changed.

fFrameWindow

[in] Specifies TRUE if the frame window object is calling ResizeBorder; otherwise, FALSE.

Return Values

S_OK

The method alerted the object successfully.

E_INVALIDARG

One or more arguments are invalid.

E_OUTOFMEMORY

Out of memory.

E_UNEXPECTED

An unexpected error occurred.

Comments

Notes to Callers

IOleInPlaceActiveObject::ResizeBorder is called by the top-level container's document or frame window object when the border space allocated to the object should change. Because the active in-place object is not informed about which window has changed (the frame- or document-level window), IOleInPlaceActiveObject::ResizeBorder must be passed the pointer to the window's IOleInPlaceUIWindow interface.

Notes to Implementors

In most cases, resizing only requires that you grow, shrink, or scale your ojbect's frame adornments. However, for more complicated adornments, you may be required to renegotiate for border space with calls to IOleInPlaceUIWindow::RequestBorderSpace and IOleInPlaceUIWindow::SetBorderSpace.

Note  While executing IOleInPlaceActiveObject::ResizeBorder, do not make calls to the Windows PeekMessage or GetMessage functions, or a dialog box. Doing so may cause the system to deadlock. There are further restrictions on which OLE interface mehtods and functions can be called from within ResizeBorder.

See Also

IOleInPlaceUIWindow::GetBorder

PeekMessage, GetMessage in Win32


IOleInPlaceActiveObject::TranslateAccelerator

Processes menu accelerator-key messages from the container's message queue. This method should only be used for objects created by a DLL object application.

HRESULT TranslateAccelerator(

LPMSG lpmsg	//Points to message that may need translating
);
Parameter

lpmsg

[in] Points to the message that might need to be translated.

Return Values

S_OK

The message was translated successfully.

S_FALSE

The message was not translated.

E_INVALIDARG

One or more arguments are invalid.

E_OUTOFMEMORY

Out of memory.

E_UNEXPECTED

An unexpected error occurred.

Comments

Notes to Callers

Active in-place objects must always be given the first chance at translating accelerator keystrokes. You can provide this opportunity by calling IOleInPlaceActiveObject::TranslateAccelerator from your container's message loop before doing any other translation. You should apply your own translation only when this method returns S_FALSE.

If you call IOleInPlaceActiveObject::TranslateAccelerator for an object that is not created by a DLL object application, the default object handler returns S_FALSE.

Notes to Implementors

An object created by an EXE object application gets keystrokes from its own message pump, so the container does not get those messages.

If you need to implement this method, you can do so by simply wrapping the call to the Window's TranslateAccelerator function.

See Also

OleTranslateAccelerator

TranslateAccelerator in Win32


IOleInPlaceFrame

The IOleInPlaceFrame interface controls the container's top-level frame window. This control involves allowing the container to insert its menu group into the composite menu, install the composite menu into the appropriate window frame, and remove the container's menu elements from the composite menu. It sets and displays status text relevant to the in-place object. It also enables or disables the frame's modeless dialog boxes, and translates accelerator keystrokes intended for the container's frame.

When to Implement

You will need to implement this interface if you are writing a container application that will be participating in in-place activation.

When to Use

This interface is used by object applications to control the display and placement of composite menus, keystroke accelerator translation, context-sensitive help mode, and modeless dialog boxes.

Methods in VTable Order

IUnknown Methods	Description
QueryInterface	Returns a pointer to a specified interface.
AddRef	Increments the reference count.
Release	Decrements the reference count.
IOleWindow Methods	Description
GetWindow	Gets a window handle.
ContextSensitiveHelp	Controls enabling of context-sensitive help.
IOleInPlaceUIWindow Methods	Description
GetBorder	Translates messages.
RequestBorderSpace	State of container's top-level frame.
SetBorderSpace	State of container document window.
SetActiveObject	Alert object of need to resize border space.
IOleInPlaceFrame Methods	Description
InsertMenus	Allows container to insert menus.
SetMenu	Adds a composite menu to window frame.
RemoveMenus	Removes a container's menu elements.
SetStatusText	Sets and displays status text about.
EnableModeless	Enables or disables modeless dialog.
TranslateAccelerator	Translates keystrokes.
See Also

IOleWindow, IOleInPlaceUIWindow


IOleInPlaceFrame::EnableModeless

Enables or disables a frame's modeless dialog boxes.

HRESULT EnableModeless(

BOOL fEnable	//Enable or disable modeless dialog
);
Parameter

fEnable

[in] Specifies whether the modeless dialog boxes are to be enabled by specifying TRUE or disabled by specifying FALSE.

Return Values

S_OK

The dialog box was either enabled or disabled successfully, depending on the value for fEnable.

E_UNEXPECTED

An unexpected error occurred.

Comments

Notes to Callers

The active in-place object calls IOleInPlaceFrame::EnableModeless to enable or disable modeless dialog boxes that the container might be displaying. To display a modal dialog box, the object first calls IOleInPlaceFrame::EnableModeless , specifying FALSE to disable the container's modeless dialog box windows. After completion, the object calls IOleInPlaceFrame::EnableModeless specifying TRUE to reenable them.

Notes to Implementors

You should track the value of EnableModeless and check it before displaying a dialog box.

See Also

IOleInPlaceActiveObject::EnableModeless


IOleInPlaceFrame::InsertMenus

Allows the container to insert its menu groups into the composite menu to be used during the in-place session.

HRESULT InsertMenus(

HMENU hmenuShared,	//Handle to empty menu
LPOLEMENUGROUPWIDTHS lpMenuWidths	//OLEMENUGROUPWIDTHS array
);
Parameters

hmenuShared

[in] Specifies a handle to an empty menu.

lpMenuWidths

[in, out] Points to an OLEMENUGROUPWIDTHS array of six LONG values. The container fills in elements 0, 2, and 4 to reflect the number of menu elements it provided in the File, View, and Window menu groups.

Return Values

S_OK

The menu groups were inserted successfully.

E_INVALIDARG

One or more arguments are invalid.

E_UNEXPECTED

An unexpected error occurred.

Comments

Notes to Callers

This method is called by object applications when they are first being activated. They call it in order to insert their menus into the frame-level user interface.

The object application asks the container to add its menus to the menu specified in hmenuShared and to set the group counts in the OLEMENUGROUPWIDTHS array pointed to by lpMenuWidths. The object application then adds its own menus and counts. Objects can call IOleInPlaceFrame::InsertMenus as many times as necessary to build up the composite menus. The container should use the initial menu handle associated with the composite menu for all menu items in the drop-down menus.


IOleInPlaceFrame::RemoveMenus

Gives the container a chance to remove its menu elements from the in-place composite menu.

HRESULT RemoveMenus(

HMENU hmenuShared	//Handle to in-place composite menu
);
Parameter

hmenuShared

[in] Specifies a handle to the in-place composite menu that was constructed by calls to IOleInPlaceFrame::InsertMenus and the Windows InsertMenu function.

Return Values

S_OK

The method completed successfully.

E_INVALIDARG

One or more arguments are invalid.

E_UNEXPECTED

An unexpected error occurred.

Comments

The object should always give the container a chance to remove its menu elements from the composite menu before deactivating the shared user interface.

Notes to Callers

Called by the object application while it is being UI-deactivated in order to remove its menus.

See Also

IOleInPlaceFrame::SetMenu

InsertMenu in Win32


IOleInPlaceFrame::SetMenu

Installs the composite menu in the window frame containing the object being activated in place.

HRESULT SetMenu(

HMENU hmenuShared,	//Handle to composite menu
HOLEMENU holemenu,	//Handle to menu descriptor
HWND hwndActiveObject	//Handle to object's window
);
Parameters

hmenuShared

[in] Specifies a handle to the composite menu constructed by calls to IOleInPlaceFrame::InsertMenus and the Windows InsertMenu function.

holemenu

[in] Specifies the handle to the menu descriptor returned by the OleCreateMenuDescriptor function.

hwndActiveObject

[in] Specifies a handle to a window owned by the object and to which menu messages, commands, and accelerators are to be sent.

Return Values

S_OK

The method completed successfully.

E_INVALIDARG

One or more arguments are invalid.

E_UNEXPECTED

An unexpected error occurred.

Comments

Notes to Callers

The object calls IOleInPlaceFrame::SetMenu to ask the container to install the composite menu structure set up by calls to IOleInPlaceFrame::InsertMenus.

Notes to Implementors

An SDI container's implementation of this method should call the Windows SetMenu function. An MDI container should send a WM_MDISETMENU message, using hmenuShared as the menu to install. The container should call OleSetMenuDescriptor to install the OLE dispatching code.

When deactivating, the container must call IOleInPlaceFrame::SetMenu specifying NULL to remove the shared menu. This is done to help minimize window repaints. The container should also call OleSetMenuDescriptor specifying NULL to unhook the dispatching code. Finally, the object application calls OleDestroyMenuDescriptor to free the data structure.

Note  While executing IOleInPlaceFrame::SetMenu, do not make calls to the Windows PeekMessage or GetMessage functions, or a dialog box. Doing so may cause the system to deadlock. There are further restrictions on which OLE interface methods and functions can be called from within SetMenu.

See Also

IOleInPlaceFrame::InsertMenus, OleSetMenuDescriptor, OleDestroyMenuDescriptor

PeekMessage, GetMessage in Win32


IOleInPlaceFrame::SetStatusText

Sets and displays status text about the in-place object in the container's frame window status line.

HRESULT SetStatusText(

LPCOLESTR pszStatusText	//Points to message to display
);
Parameter

pszStatusText

[in] Points to a null-terminated character string containing the message to display.

Return Values

S_OK

The text was displayed.

S_TRUNCATED

Some text was displayed but the message was too long and was truncated.

E_INVALIDARG

One or more arguments are invalid.

E_UNEXPECTED

An unexpected error occurred.

E_FAIL

The text could not be displayed.

Comments

Notes to Callers

You should call SetStatusText when you need to ask the container to display object text in its frame's status line, if it has one. Because the container's frame window owns the status line, calling IOleInPlaceFrame::SetStatusText is the only way an object can display status information in the container's frame window. If the container refuses the object's request, the object application can, however, negotiate for border space to display its own status window.

Note  When switching between menus owned by the container and the in-place active object, the status bar text is not reflected properly if the object does not call the container's IOleInPlaceFrame::SetStatusText method. For example, if, during an in-place session, the user were to select the File menu, the status bar would reflect the action that would occur if the user selected this menu. If the user then selects the Edit menu (which is owned by the in-place object), the status bar text would not change unless the IOleInPlaceFrame::SetStatusText happened to be called. This is because there is no way for the container to recognize that one of the object's menus has been made active because all the messages that the container would trap are now going to the object.

Notes to Implementors

To avoid potential problems, all objects being activated in place should process the WM_MENUSELECT message and call IOleInPlaceFrame::SetStatusText — even if the object does not usually provide status information (in which case the object can just pass a NULL string for the requested status text).

Note  While executing IOleInPlaceFrame::SetStatusText, do not make calls to the Windows PeekMessage or GetMessage functions, or a dialog box. Doing so may cause the system to deadlock. There are further restrictions on which OLE interface methods and functions can be called from within GerBorder.

See Also

PeekMessage, GetMessage in Win32


IOleInPlaceFrame::TranslateAccelerator

Translates accelerator keystrokes intended for the container's frame while an object is active in place.

HRESULT TranslateAccelerator(

LPMSG lpmsg,	//Points to MSG structure
WORD wID	//Command Identifier value
);
Parameters

lpmsg

[in] Points to an MSG structure containing the keystroke message.

wID

[in] Contains the command identifier value corresponding to the keystroke in the container-provided accelerator table. Containers should use this value instead of translating again.

Return Values

S_OK

The keystroke was used.

S_FALSE

The keystroke was not used.

E_INVALIDARG

One or more arguments are invalid.

E_UNEXPECTED

An unexpected error occurred.

Comments

Notes to Callers

The IOleInPlaceFrame::TranslateAccelerator method is called indirectly by OleTranslateAccelerator when a keystroke accelerator intended for the container (frame) is received.

Notes to Implementors

The container application should perform its usual accelerator processing, or use wID directly, and then return, indicating whether the keystroke accelerator was processed. If the container is an MDI application and the Windows TranslateAccelerator call fails, the container can call the Windows TranslateMDISysAccel function, just as it does for its usual message processing.

In-place objects should be given first chance at translating accelerator messages. However, because objects implemented by DLL object applications do not have their own message pump, they receive their messages from the container's message queue. To ensure that the object has first chance at translating messages, a container should always call IOleInPlaceActiveObject::TranslateAccelerator before doing its own accelerator translation. Conversely, an executable object application should call OleTranslateAccelerator after calling TranslateAccelerator, calling TranslateMessage and DispatchMessage only if both translation functions fail.

Note  You should define accelerator tables for containers so they will work properly with object applications that do their own accelerator keystroke translations. Tables should be defined  as follows:

"char", wID, VIRTKEY, CONTROL

This is the most common way to describe keyboard accelerators. Failure to do so can result in keystrokes being lost or sent to the wrong object during an in-place session.

See Also

OleTranslateAccelerator, IOleInPlaceActiveObject::TranslateAccelerator

TranslateAccelerator, TranslateMessage, DispatchMessage, TranslateMDISysAccel in Win32


IOleInPlaceObject

The IOleInPlaceObject interface manages the activation and deactivation of in-place objects, and determines how much of the in-place object should be visible.

You can obtain a pointer to IOleInPlaceObject by calling QueryInterface on IOleObject.

When to Implement

You must implement this interface if you are writing an object application that will participate in in-place activation.

When to Use

Used by an object's immediate container to activate or deactivate the object.

Methods in VTable Order

IUnknown Methods	Description
QueryInterface	Returns a pointer to a specified interface.
AddRef	Increments the reference count.
Release	Decrements the reference count.
IOleWindow Methods	Description
GetWindow	Gets a window handle.
ContextSensitiveHelp	Controls enabling of context sensitive help.
IOleInPlaceObject Methods	Description
InPlaceDeactivate	Deactivate active in-place object.
UIDeactivate	Deactivate and remove UI of active object.
SetObjectRects	Portion of in-place object to be visible.
ReactivateAndUndo	Reactivate previously deactivated object.
See Also

IOleObject, IOleWindow


IOleInPlaceObject::InPlaceDeactivate

Deactivates an active in-place object and discards the object's undo state.

HRESULT InPlaceDeactivate();

Return Values

S_OK

The object was successfully deactivated.

E_UNEXPECTED

An unexpected error occurred.

Comments

Notes to Callers

This method is called by an active object's immediate container to deactivate the active object and discard its undo state.

Notes to Implementors

On return from IOleInPlaceObject::InPlaceDeactivate, the object discards its undo state. The object application should not shut down immediately after this call. Instead, it should wait for an explicit call to IOleObject::Close or for the object's reference count to reach zero.

Before deactivating, the object application should give the container a chance to put its user interface back on the frame window by calling IOleInPlaceSite::OnUIDeactivate.

If the in-place user interface is still visible during the call to InPlaceDeactivate, the object application should call its own IOleInPlaceObject::UIDeactivate method to hide the user interface. The in-place user interface can be optionally destroyed during calls to IOleInPlaceObject::UIDeactivate and IOleInPlaceObject::InPlaceDeactivate. But if the user interface has not already been destroyed when the container calls IOleObject::Close, then it must be destroyed during the call to IOleObject::Close.

During the call to IOleObject::Close, the object should check to see whether it is still active in place. If so, it should call InPlaceDeactivate.

See Also

IOleInPlaceSite::OnInPlaceDeactivate, IOleInPlaceSite::OnUIDeactivate, IOleObject::Close


IOleInPlaceObject::ReactivateAndUndo

Reactivates a previously deactivated object, undoing the last state of the object.

HRESULT ReactivateAndUndo();

Return Values

S_OK

The object was successfully reactivated.

E_NOTUNDOABLE

Called when the Undo state is not available.

E_INVALIDARG

One or more arguments are invalid.

E_OUTOFMEMORY

Out of memory.

E_UNEXPECTED

An unexpected error occurred.

Comments

If the user chooses the Undo command before the Undo state of the object is lost, the object's immediate container calls IOleInPlaceObject::ReactivateAndUndo to activate the user interface, carry out the Undo operation, and return the object to the active state.


IOleInPlaceObject::SetObjectRects

Indicates how much of the in-place object is visible.

HRESULT SetObjectRects(

LPCRECT lprcPosRect,	//The position of the in-place object
LPCRECT lprcClipRect	//The outer rectangle containing the in-place object's position rectangle
);
Parameters

lprcPosRect

[in] Points to the rectangle containing the position of the in-place object using the client coordinates of its parent window.

lprcClipRect

[in] Points to the outer rectangle containing the in-place object's position rectangle (PosRect). This rectangle is relative to the client area of the object's parent window.

Return Values

S_OK

The operation successfully indicated the rectangle.

E_INVALIDARG

One or more arguments are invalid.

E_OUTOFMEMORY

Out of memory.

E_UNEXPECTED

An unexpected error occurred.

Comments

It is possible for lprcClipRect to change without lprcPosRect changing.

The size of an in-place object's rectangle is always calculated in pixels. This is different from other OLE object's visualizations, which are in HIMETRIC.

Note  While executing IOleInPlaceObject::SetObjectRects, do not make calls to the Windows PeekMessage or GetMessage functions, or a dialog box. Doing so may cause the system to deadlock. There are further restrictions on which OLE interface mehtods and functions can be called form within SetObjectRects.

Notes to Callers

The container should call IOleInPlaceObject::SetObjectRects whenever the window position of the in-place object and/or the visible part of the in-place object changes.

Notes to Implementors

The object must size its in-place window to match the intersection of lprcPosRect and lprcClipRect. The object must also draw its contents into the object's in-place window so that proper clipping takes place.

The object should compare its width and height with those provided by its container (conveyed through lprcPosRect). If the comparison does not result in a match, the container is applying scaling to the object. The object must then decide whether it should continue the in-place editing in the scale/zoom mode or deactivate.

See Also

IOleInPlaceSite::OnPosRectChange

PeekMessage, GetMessage in Win32


IOleInPlaceObject::UIDeactivate

Deactivates and removes the user interface that supports in-place activation.

HRESULT UIDeactivate();

Return Values

S_OK

The in-place UI was deactivated and removed.

E_UNEXPECTED

An unexpected error occurred.

Notes to Callers

This method is called by the object's immediate container when, for example, the user has clicked in the client area outside the object.

If the container has called IOleInPlaceObject::UIDeactivate, it should later call IOleInPlaceObject::InPlaceDeactivate to properly clean up resources. The container can assume that stopping or releasing the object cleans up resources if necessary. The object must be prepared to do so if IOleInPlaceObject::InPlaceDeactivate has not been called. but either IOleInPlaceObject::UIDeactivate or IOleObject::Close has been called.

Notes to Implementors

Resources such as menus and windows can be either cleaned up or kept in a hidden state until your object is completely deactivated by calls to either IOleInPlaceObject::InPlaceDeactivate or IOleObject::Close. The object application must call IOleInPlaceSite::OnUIDeactivate before doing anything with the composite menus so that the container can first be detached from the frame window. On deactivating the in-place object's user interface, the object is left in a ready state so it can be quickly reactivated. The object stays in this state until the undo state of the document changes. The container should then call IOleInPlaceObject::InPlaceDeactivate to tell the object to discard its undo state.

See Also

IOleInPlaceObject::InPlaceDeactivate, IOleInPlaceSite::OnUIDeactivate, IOleInPlaceObject::ReactivateAndUndo, IOleObject::Close


IOleInPlaceSite

The IOleInPlaceSite interface manages interaction between the container and the object's in-place client site. Recall that the client site is the display site for embedded objects, and provides position and conceptual information about the object.

This interface provides methods that manage in-place objects. With IOleInPlaceSite, you can determine if an object can be activated and manage its activation and deactivation. You can notify the container when one of its objects is being activated and inform the container that a composite menu will replace the container's regular menu. It provides methods that make it possible for the in-place object to retrieve the window object hierarchy, and the position in the parent window where the object should place its in-place activation window. And finally, it manages how the container scrolls the object, its undo state, and notifies the object when its borders have changed.

When to Implement

You must implement this interface if you are writing a container application that will participate in in-place activation.

When to Use

Use this interface to allow your object to control in-place activation from within the container.

The IOleInPlaceSite interface pointer is obtained by calling QueryInterface on the object's IOleClientSite interface.

Methods in VTable Order

IUnknown Methods	Description
QueryInterface	Returns a pointer to a specified interface.
AddRef	Increments the reference count.
Release	Decrements the reference count.
IOleWindow Methods	Description
GetWindow	Gets a window handle.
ContextSensitiveHelp	Controls enabling of context-sensitive help.
IOleInPlaceSite Methods	Description
CanInPlaceActivate	Determines if the container can activate the object in place.
OnInPlaceActivate	Notifies the container that one of its objects is being activated in place.
OnUIActivate	Notifies the container that the object is about to be activated in place, and that the main menu will be replaced by a composite menu.
GetWindowContext	Enables an in-place object to retrieve window interfaces that form at the window object hierarchy, and the position in the parent window to locate the object's in-place activation window.
Scroll	Specifies the number of pixels by which the container is to scroll the object.
OnUIDeactivate	Notifies the container to reinstall its user interface and take focus.
OnInPlaceDeactivate	Notifies the container that the object is no longer active in place.
DiscardUndoState	Instructs the container to discard its undo state.
DeactivateAndUndo	Deactivate the object and revert to undo state.
OnPosRectChange	Object's extents have changed.
See Also

IOleWindow, IOleClientSite


IOleInPlaceSite::CanInPlaceActivate

Determines whether or not the container can activate the object in place.

HRESULT CanInPlaceActivate();

Return Values

S_OK

The container allows in-place activation for this object.

S_FALSE

The container does not allow in-place activation for this object.

E_INVALIDARG

One or more arguments are invalid.

E_UNEXPECTED

An unexpected error occurred.

Comments

Only objects being displayed as DVASPECT_CONTENT can be activated in place.

Notes to Callers

IOleInPlaceSite::CanInPlaceActivate is called by the client site's immediate child object when this object must activate in place. This function allows the container application to accept or refuse the activation request.


IOleInPlaceSite::DeactivateAndUndo

Causes the container to end the in-place session, deactivates the object, and revert to its own saved undo state.

HRESULT IOleInPlaceSite::DeactivateAndUndo();

Return Values

S_OK

The method completed successfully.

E_UNEXPECTED

An unexpected error occurred.

Comments

Notes to Callers

Called by the active object when the user invokes undo just after activating the object.

Notes to Implementors

Upon completion of this call, the container should call IOleInPlaceObject::UIDeactivate to remove the user interface for the object, activate itself, and undo.


IOleInPlaceSite::DiscardUndoState

Tells the container that the object.no longer has any undo state and that the container should not call IOleInPlaceObject::ReActivateAndUndo.

HRESULT IOleInPlaceSite::DiscardUndoState();

Return Values

S_OK

The method completed successfully.

E_UNEXPECTED

An unexpected error occurred.

Comments

If an object is activated in place and the object's associated object application maintains only one level of undo, there is no need to have more than one entry on the undo stack. That is, once a change has been made to the active object that invalidates its undo state saved by the container, there is no need to maintain this undo state in the container.

Notes to Callers

IOleInPlaceSite::DiscardUndoState is called by the active object while performing some action that would discard the undo state of the object. The in-place object calls this method to notify the container to discard the object's last saved undo state.

See Also

IOleInPlaceSite::DeactivateAndUndo


IOleInPlaceSite::GetWindowContext

Enables the in-place object to retrieve the window interfaces that form the window object hierarchy, and the position in the parent window where the object's in-place activation window should be placed.

HRESULT GetWindowContext(

IOleInPlaceFrame **ppFrame,	//Location to return frame interface pointer
IOleInPlaceUIWindow **ppDoc,	//Location to return document window pointer
LPRECT lprcPosRect,	//Points to position of in-place object
LPRECT lprcClipRect,	//Points to in-place object's position rectangle
LPOLEINPLACEFRAMEINFO lpFrameInfo	//Points to OLEINPLACEFRAMEINFO structure
);
Parameters

ppFrame

[out] Points to where the pointer to the frame interface is to be returned. If an error is returned, this parameter must be set to NULL.

ppDoc

[out] Points to where the pointer to the document window interface is to be returned. NULL is returned through the ppDoc pointer if the document window is the same as the frame window. In this case, the object can only use ppFrame or border negotiation. If an error is returned, this parameter must be set to NULL.

lprcPosRect

[out] Points to the rectangle containing the position of the in-place object in the client coordinates of its parent window. If an error is returned, this parameter must be set to NULL.

lprcClipRect

[out] Points to the outer rectangle containing the in-place object's position rectangle (PosRect). This rectangle is relative to the client area of the object's parent window. If an error is returned, this parameter must be set to NULL.

lpFrameInfo

[out] Points to an OLEINPLACEFRAMEINFO structure the container is to fill in with appropriate data. If an error is returned, this parameter must be set to NULL.

Return Values

S_OK

The method completed successfully.

E_INVALIDARG

One or more arguments are invalid (for example, an invalid pointer or parameter).

E_UNEXPECTED

An unexpected error occurred.

Comments

The OLEINPLACEFRAMEINFO structure provides data needed by OLE to dispatch keystroke accelerators to a container frame while an object is active in place.

When an object is activated, it calls GetWindowContext from its container. The container returns the handle to its in-place accelerator table through the OLEINPLACEFRAMEINFO structure. Before calling GetWindowContext, the object must provide the size of the OLEINPLACEFRAMEINFO structure by filling in the cb member, pointed to by lpFrameInfo.


IOleInPlaceSite::OnInPlaceActivate

Notifies the container that one of its objects is being activated in place.

HRESULT OnInPlaceActivate();

Return Values

S_OK

The container allows the in-place activation.

E_UNEXPECTED

An unexpected error occurred.

Comments

Notes to Callers

IOleInPlaceSite::OnInPlaceActivate is called by the active, embedded object when it is activated in-place for the first time. The container should note that the object is becoming active.

Notes to Implementors

A container that supports linking to embedded objects must properly manage the running of its in-place objects when they are UI inactive and running in the hidden state. To reactivate the in-place object quickly, a container should not call IOleObject::Close until the container's IOleInPlaceSite::DeactivateAndUndo method is called. To safeguard against the object being left in an unstable state if a linking client updates silently, the container should call OleLockRunning to lock the object in the running state. This prevents the hidden in-place object from shutting down before it can be saved in its container.


IOleInPlaceSite::OnInPlaceDeactivate

Notifies the container that the object is no longer active in place.

HRESULT OnInPlaceDeactivate();

Return Values

S_OK

The method successfully notified the container.

E_UNEXPECTED

An unexpected error occurred.

Comments

Notes to Callers

IOleInPlaceSite::OnInPlaceDeactivate is called by an in-place object when it is fully deactivated. This function notifies the container that the object has been deactivated, and it gives the container a chance to run code pertinent to the object's deactivation. In particular, IOleInPlaceSite::OnInPlaceDeactivate is called as a result of IOleInPlaceObject::InPlaceDeactivate being called. Calling IOleInPlaceSite::OnInPlaceDeactivate indicates that the object can no longer support Undo.

Notes to Implementors

If the container is holding pointers to the IOleInPlaceObject and IOleInPlaceActiveObject interface implementations, it should release them after the IOleInPlaceSite::OnInPlaceDeactivate call.

See Also

IOleInPlaceObject::InPlaceDeactivate


IOleInPlaceSite::OnPosRectChange

Indicates the object's extents have changed.

HRESULT OnPosRectChange(

LPCRECT lprcPosRect	//Points to rectangle containing the position of in-place object
);
Parameter

lprcPosRect

[in] Points to the rectangle containing the position of the in-place object in the client coordinates of its parent window.

Return Values

S_OK

The method completed successfully.

E_INVALIDARG

One or more arguments are invalid.

E_UNEXPECTED

An unexpected error occurred.

Comments

Notes to Callers

The IOleInPlaceSite::OnPosRectChange method is called by the in-place object.

Notes to Implementors

When the in-place object calls IOleInPlaceSite::OnPosRectChange, the container must call IOleInPlaceObject::SetObjectRects to specify the new position of the in-place window and the ClipRect. Only then does the object resize its window.

In most cases, the object grows to the right and/or down. There could be cases where the object grows to the left and/or up, as conveyed through lprcPosRect. It is also possible to change the object's position without changing its size.

See Also

IOleInPlaceObject::SetObjectRects


IOleInPlaceSite::OnUIActivate

Notifies the container that the object is about to be activated in place and that the object is going to replace the container's main menu with an in-place composite menu.

HRESULT IOleInPlaceSite::OnUIActivate();

Return Values

S_OK

The container allows the in-place activation.

E_UNEXPECTED

An unexpected error occurred.

Comments

Notes to Callers

The in-place object calls IOleInPlaceSite::OnUIActivate just before activating its user interface.

Notes to Implementors

The container should remove any user interface associated with its own activation. If the container is itself an embedded object, it should remove its document-level user interface.

If there is already an object active in place in the same document, the container should call IOleInPlaceObject::UIDeactivate before calling OnUIDeactivate.

See Also

IOleInPlaceObject::UIDeactivate


IOleInPlaceSite::OnUIDeactivate

Notifies the container on deactivation that it should reinstall its user interface and take focus, and whether or not the object has an undoable state.

HRESULT OnUIDeactivate(

BOOL fUndoable	//Specifies if object can undo changes
);
Parameter

fUndoable

[in] Specifies whether the object can undo changes. It is TRUE if the object can undo, FALSE if it cannot.

Return Values

S_OK

The method completed successfully.

E_UNEXPECTED

An unexpected error occurred.

Comments

The object indicates whether it can undo changes through the fUndoable flag. If the object can undo changes, the container can (by the user invoking the Edit Undo command) call the IOleInPlaceObject::ReactivateAndUndo method to undo the changes.

Notes to Callers

IOleInPlaceSite::OnUIDeactivate is called by the site's immediate child object when it is deactivating to notify the container that it should reinstall its own user interface components and take focus. The container should wait for the call to IOleInPlaceSite::OnUIDeactivate to complete before fully cleaning up and destroying any composite submenus.

See Also

IOleInPlaceObject::ReactivateAndUndo


IOleInPlaceSite::Scroll

Tells the container to scroll the view of the object by a specified number of pixels.

HRESULT Scroll(

SIZE scrollExtent	//Number of pixels
);
Parameter

scrollExtent

[in] Contains the number of pixels by which to scroll in the X and Y directions.

Return Values

S_OK

The method successfully executed the view scroll instruction.

E_INVALIDARG

An invalid argument.

E_UNEXPECTED

An unexpected error occurred.

Comments

As a result of scrolling, the object's visible rectangle can change. If that happens, the container should give the new ClipRect to the object by calling IOleInPlaceObject::SetObjectRects. The intersection of the ClipRect and PosRect rectangles gives the new visible rectangle. See IOleInPlaceSite::GetWindowContext for a discussion of ClipRect and PosRect.

Notes to Callers

Called by an active, in-place object when it is asking the container to scroll.

See Also

IOleInPlaceObject::SetObjectRects


IOleInPlaceUIWindow

The IOleInPlaceUIWindow interface is implemented by container applications and used by object applications to negotiate border space on the document or frame window. The container provides a RECT structure in which the object can place toolbars and other similar controls, determines if tools can in fact be installed around the object's window frame, allocates space for the border, and establishes a communication channel between the object and each frame and document window.

The document window may not exist in all applications. When this is the case, IOleInPlaceSite::GetWindowContext returns NULL for IOleInPlaceUIWindow.

When to Implement

You must implement this interface if you are writing a container application that will participate in-place activation.

When to Use

Used by object applications to negotiate border space on the document or frame window when one of its objects is being activated or to renegotiate border space if the size of the object changes.

Methods in VTable Order

IUnknown Methods	Description
QueryInterface	Returns a pointer to a specified interface.
AddRef	Increments the reference count.
Release	Decrements the reference count.
IOleWindow Methods	Description
GetWindow	Gets a window handle.
ContextSensitiveHelp	Controls enabling of context sensitive help.
IOleInPlaceUIWindow Methods	Description
GetBorder	Specifies a RECT structure for toolbars and controls.
RequestBorderSpace	Determines if tools can be installed around object's window frame.
SetBorderSpace	Allocates space for the border.
SetActiveObject	Provides for direct communication between the object and each document and frame window.
See Also

IOleWindow


IOleInPlaceUIWindow::GetBorder

Returns a RECT structure in which the object can put toolbars and similar controls while active in place.

HRESULT GetBorder(

LPRECT lprectBorder	//Points to RECT structure
);
Parameter

lprectBorder

[out] Points to a RECT structure where the outer rectangle is to be returned. The RECT structure's coordinates are relative to the window being represented by the interface.

Return Values

S_OK

The rectangle was successfully returned.

E_NOTOOLSPACE

The object cannot install toolbars in this window object.

E_INVALIDARG

One or more arguments are invalid.

E_OUTOFMEMORY

Out of memory.

E_UNEXPECTED

An unexpected error occurred.

Comments

Notes to Callers

The IOleInPlaceUIWindow::GetBorder function, when called on a document or frame window object, returns the outer rectangle (relative to the window) where the object can put toolbars or similar controls.

If the object is to install these tools, it should negotiate space for the tools within this rectangle using IOleInPlaceUIWindow::RequestBorderSpace and then call IOleInPlaceUIWindow::SetBorderSpace to get this space allocated.

Note  While executing IOleInPlaceUIWindow::GetBorder, do not make calls to the Windows PeekMessage or GetMessage functions, or a dialog box. Doing so may cause the system to deadlock. There are further restrictions on which OLE interface mehtods and functions can be called from within GerBorder.

See Also

IOleInPlaceUIWindow::RequestBorderSpace, IOleInPlaceUIWindow::SetBorderSpace

PeekMessage, GetMessage in Win32


IOleInPlaceUIWindow::RequestBorderSpace

Determines if there is available space for tools to be installed around the object's window frame while the object is active in place.

HRESULT RequestBorderSpace(

LPCBORDERWIDTHS pborderwidths	//Points to a BORDERWIDTHS structure
);
Parameter

pborderwidths

[in] Points to a BORDERWIDTHS structure containing the requested widths (in pixels) needed on each side of the window for the tools.

Return Values

S_OK

The requested space could be allocated to the object.

E_NOTOOLSPACE

The object cannot install toolbars in this window object because the implementation does not support toolbars, or there is insufficient space to install the toolbars.

E_INVALIDARG

One or more invalid arguments (for example, an invalid pointer or parameter).

E_UNEXPECTED

An unexpected error occurred.

Comments

Notes to Callers

The active in-place object calls IOleInPlaceUIWindow::RequestBorderSpace to ask if tools can be installed inside the window frame. These tools would be allocated between the rectangle returned by IOleInPlaceUIWindow::GetBorder and the BORDERWIDTHS structure specified in the argument to this call.

The space for the tools is not actually allocated to the object until it calls IOleInPlaceUIWindow::SetBorderSpace, allowing the object to negotiate for space (such as while dragging toolbars around), but deferring the moving of tools until the action is completed.

The object can install these tools by passing the width in pixels that is to be used on each side. For example, if the object required 10 pixels on the top, 0 pixels on the bottom, and 5 pixels on the left and right sides, it would pass the following BORDERWIDTHS structure to IOleInPlaceUIWindow::RequestBorderSpace:

lpbw->top    = 10

lpbw->bottom =  0

lpbw->lLeft  =  5

lpbw->right  =  5

Note  While executing IOleInPlaceUIWindow::RequestBorderSpace, do not make calls to the Windows PeekMessage or GetMessage functions, or a dialog box. Doing so may cause the system to deadlock. There are further restrictions on which OLE interface methods and functions can be called from within RequestBorderSpace.

Notes to Implementors

If the amount of space an active object uses for its toolbars is irrelevant to the container, it can simply return NOERROR as shown in the following IOleInPlaceUIWindow::RequestBorderSpace example. Containers should not unduly restrict the display of tools by an active in-place object.

HRESULT InPlaceUIWindow_RequestBorderSpace(

    IOleInPlaceFrame *  lpThis,

    LPCBORDERWIDTHS     pborderwidths)

{

    /* Container allows the object to have as much border space as it

    ** wants.

    */

    return NOERROR;

}

See Also

IOleInPlaceUIWindow::GetBorder, IOleInPlaceUIWindow::SetBorderSpace

PeekMessage, GetMessage in Win32


IOleInPlaceUIWindow::SetActiveObject

Provides a direct channel of communication between the object and each of the frame and document windows.

HRESULT SetActiveObject(

IOleInPlaceActiveObject *pActiveObject,	//Points to active in-place object
LPCOLESTR pszObjName	//Points to name describing the object
);
Parameters

pActiveObject

[in] Points to the active in-place object's IOleInPlaceActiveObject interface.

pszObjName

[in] Points to a string containing a name that describes the object an embedding container can use in composing its window title. It can be NULL if the object does not require the container to change its window titles. The Microsoft Windows User Interface Design Guide recommends that containers ignore this parameter and always use their own name in the title bar.

Return Values

S_OK

The method completed successfully.

E_INVALIDARG

One or more arguments are invalid.

E_UNEXPECTED

An unexpected error occurred.

Comments

Generally, an embedded object should pass NULL for the pszObjName parameter (see "Notes to Implementors" below). However, if you are working in conjunction with a container that does display the name of the in-place active object in its title bar, then you should compose a string in the following form:

<application name> − <object short-type name>

Notes to Callers

IOleInPlaceUIWindow::SetActiveObject is called by the object to establish a direct communication link between itself and the document and frame windows.

When deactivating, the object calls IOleInPlaceUIWindow::SetActiveObject, passing NULL for the pActiveObject and pszObjName parameters.

An object must call IOleInPlaceUIWindow::SetActiveObject before calling IOleInPlaceFrame::SetMenu to give the container the pointer to the active object. The container then uses this pointer in processing IOleInPlaceFrame::SetMenu and to pass to OleSetMenuDescriptor.

Notes to Implementors

The Microsoft Windows User Interface Design Guide recommends that an in-place container ignore the pszObjName parameter passed in this method. The guide says "The title bar is not affected by in-place activation. It always displays the top-level container's name."

See Also

IOleInPlaceFrame::SetMenu, OleSetMenuDescriptor


IOleInPlaceUIWindow::SetBorderSpace

Allocates space for the border requested in the call to IOleInPlaceUIWindow::RequestBorderSpace.

HRESULT SetBorderSpace(

LPCBORDERWIDTHS pborderwidths	//Points to a BORDERWIDTHS structure
);
Parameter

pborderwidths

[in] Points to a BORDERWIDTHS structure containing the requested width (in pixels) of the tools. It can be NULL, indicating the object does not need any space.

Return Values

S_OK

The requested space has been allocated to the object.

OLE_E_INVALIDRECT

The rectangle does not lie within the specifications returned by IOleInPlaceUIWindow::GetBorder.

E_INVALIDARG

One or more arguments are invalid.

E_UNEXPECTED

An unexpected error occurred.

Comments

The object must call IOleInPlaceUIWindow::SetBorderSpace. It can do any of the following:

1.	Use its own toolbars, requesting border space of a specific size; or,

2.	Use no toolbars, but force the container to remove its toolbars by passing a valid BORDERWIDTHS structure containing nothing but zeros in the pborderwidths parameter; or,

3.	Use no toolbars but allow the in-place container to leave its toolbars up by passing NULL as the pborderwidths parameter.

The BORDERWIDTHS structure used in this call would generally have been passed in a previous call to IOleInPlaceUIWindow::RequestBorderSpace, which must have returned S_OK.

If an object must renegotiate space on the border, it can call SetBorderSpace again with the new widths. If the call to SetBorderSpace fails, the object can do a full negotiation for border space with calls to GetBorder, RequestBorderSpace, and SetBorderSpace.

Note  While executing IOleInPlaceUIWindow::SetBorderSpace, do not make calls to the Windows PeekMessage or GetMessage functions, or a dialog box. Doing so may cause the system to deadlock. There are further restrictions on which OLE interface methods and functions can be called from within SetBorderSpace.

See Also

IOleInPlaceUIWindow::GetBorder, IOleInPlaceUIWindow::RequestBorderSpace

PeekMessage, GetMessage in Win32


IOleItemContainer

The IOleItemContainer interface is used by item monikers when they are bound to the objects they identify.

When any container of objects uses item monikers to identify its objects, it must define a naming scheme for those objects. The container's IOleItemContainer implementation uses knowledge of that naming scheme to retrieve an object given a particular name. Item monikers use the container's IOleItemContainer implementation during binding.

When to Implement

You must implement IOleItemContainer if you're a moniker provider handing out item monikers. Being a moniker provider means handing out monikers that identify your objects to make them accessible to moniker clients. You must use item monikers if the objects you're identifying are contained within another object and can be individually identified using a string.

The most common example of moniker providers are OLE applications that support linking. If your OLE application supports linking to objects smaller than a file-based documents, you need to use item monikers. For a server application that allows linking to a portion of a document (such as selections within a document), you use the item monikers to identify those objects. For a container application that allows linking to embedded objects, you use the item monikers to identify the embedded objects.

You must define a naming scheme for identifying the objects within the container; for example, embedded objects in a document could be identified with names of the form "embedobj1," "embedobj2," and so forth, while ranges of cells in a spreadsheet could be identified with names of the form "A1:E7," "G5:M9," and so forth. (Ranges of cells in a spreadsheet are examples of as "pseudo-objects" because they do not have their own persistent storage, they simply represent a portion of the container's internal state.) You create an item moniker that represents an object's name using the CreateItemMoniker API function and hand it out to a moniker client. When an item moniker is bound, your implementation of IOleItemContainer must be able to take a name and retrieve the corresponding object.

When to Use

Applications typically do not call IOleItemContainer methods directly. The item moniker implementation of IMoniker is the primary caller of IOleItemContainer methods.

Methods in VTable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments the reference count.
Release	Decrements the reference count.
IParseDisplayName Method	Description
ParseDisplayName	Parses object's display name to form moniker.
IOleContainer Methods	Description
EnumObjects	Enumerates objects in a container.
LockContainer	Keeps container running until explicitly released.
IOleItemContainer Methods	Description
GetObject	Returns a pointer to a specified object.
GetObjectStorage	Returns a pointer to an object's storage.
IsRunning	Checks whether an object is running.
See Also

CreateItemMoniker, IMoniker − Item Moniker Implementation


IOleItemContainer::GetObject

Returns a pointer to the object identified by the specified name.

HRESULT GetObject(

LPOLESTR pszItem,	//Name of the object requested
DWORD dwSpeedNeeded,	//Speed requirements on binding
IBindCtx *pbc,	//Bind context to be used
REFIID riid,	//IID of interface pointer desired
void **ppvObject	//Receives interface pointer
);
Parameters

pszItem

[in] Points to a zero-terminated string containing the container's name for the requested object. For Win32 applications, the LPOLESTR type indicates a wide character string (two bytes per character); otherwise, the string has one byte per character.

dwSpeedNeeded

[in] Indicates approximately how long the caller will wait to get the object. The legal values for dwSpeedNeeded are taken from the enumeration BINDSPEED. For information on the BINDSPEED enumeration, see the "Data Structures" section.

pbc

[in] Points to the bind context to be used in this binding operation. The bind context caches objects bound during the binding process, contains parameters that apply to all operations using the bind context, and provides the means by which the binding implementation should retrieve information about its environment. For more information, see IBindCtx.

riid

[in] Specifies the type of interface pointer requested.

ppvObject

[out] Receives a pointer to the object named by pszItem. If an error occurs, the implementation sets *ppvObject to NULL. If *ppvObject is non-NULL, the implementation must call IUnknown::AddRef on the parameter; it is the caller's responsibility to call IUnknown::Release.

Return Values

S_OK

The specified object was successfully returned.

MK_E_EXCEEDEDDEADLINE

The binding operation could not be completed within the time limit specified by the bind context's BIND_OPTS structure, or with the speed indicated by the dwSpeedNeeded parameter.

MK_E_NOOBJECT

The parameter pszItem does not identify a object in this container.

E_NOINTERFACE

The requested interface was not available.

E_OUTOFMEMORY

Insufficient memory.

Comments

The item moniker implementation of IMoniker::BindToObject calls this method, passing the name stored within the item moniker as the pszItem parameter.

Notes to Implementors

Your implementation of IOleItemContainer::GetObject should first determine whether pszItem is a valid name for one of the container's objects. If not, you should return MK_E_NOOBJECT.

If pszItem names an embedded or linked object, your implementation must check the value of the dwSpeedNeeded parameter. If the value is BINDSPEED_IMMEDIATE and the object is not yet loaded, you should return MK_E_EXCEEDEDDEADLINE. If the object is loaded, your implementation should determine whether the object is running (for example, by calling the OleIsRunning API function). If it is not running and the dwSpeedNeeded value is BINDSPEED_MODERATE, your implementation should return MK_E_EXCEEDEDDEADLINE. If the object is not running and dwSpeedNeeded is BINDSPEED_INDEFINITE, your implementation should call the OleRun API function to put the object in the running state. Then it can query the object for the requested interface. Note that it is important the object be running before you query for the interface.

If pszItem names a pseudo-object, your implementation can ignore the dwSpeedNeeded parameter because a pseudo-object is running whenever its container is running. In this case, your implementation can simply query for the requested interface.

If you want more specific information about the time limit than is given by dwSpeedNeeded, you can call IBindCtx::GetBindOptions on the pbc parameter to get the actual deadline parameter.

See Also

IMoniker::BindToObject, IBindCtx::GetBindOptions, OleIsRunning, OleRun


IOleItemContainer::GetObjectStorage

Returns a pointer to the storage for the object identified by the specified name.

HRESULT GetObjectStorage(

LPOLESTR pszItem,	//Name of the object whose storage is requested
IBindCtx *pbc,	//Bind context to be used
REFIID riid,	//IID of interface pointer desired
void **ppvStorage	//Receives interface pointer
);
Parameters

pszItem

[in] Points to a zero-terminated string containing the compound document's name for the object whose storage is requested. For Win32 applications, the LPOLESTR type indicates a wide character string (two bytes per character); otherwise, the string has one byte per character.

pbc

[in] Points to the bind context to be used in this binding operation. The bind context caches objects bound during the binding process, contains parameters that apply to all operations using the bind context, and provides the means by which the binding implementation should retrieve information about its environment. For more information, see IBindCtx.

riid

[in] Identifies the type of interface pointer requested.

ppvStorage

[out] Receives a pointer to the storage of the object named by pszItem. If an error occurs, the implementation sets *ppvStorage to NULL. If *ppvStorage is non-NULL, the implementation must call IUnknown::AddRef on the parameter; it is the caller's responsibility to call IUnknown::Release.

Return Values

S_OK

The storage of the specified object was successfully returned.

MK_E_NOOBJECT

The parameter pszItem does not identify a object in this container.

MK_E_NOSTORAGE

The object does not have its own independent storage.

E_NOINTERFACE

The requested interface is not available.

E_OUTOFMEMORY

Insufficient memory.

Comments

The item moniker implementation of IMoniker::GetObjectStorage calls this method.

Notes to Implementors

If pszItem designates a pseudo-object, your implementation should return MK_E_NOSTORAGE, because pseudo-objects do not have their own independent storage. If pszItem designates an embedded object, or a portion of the document that has its own storage, your implementation should return the specified interface pointer on the appropriate storage object.

See Also

IOleItemContainer::GetObjectStorage


IOleItemContainer::IsRunning

Indicates whether the object identified by the specified name is running.

HRESULT IsRunning(

LPOLESTR pszItem	//Name of object whose status is being requested
);
Parameter

pszItem

[in] Points to a zero-terminated string containing the container's name for the object. For Win32 applications, the LPOLESTR type indicates a wide character string (two bytes per character); otherwise, the string has one byte per character.

Return Values

S_OK

The specified object is running.

S_FALSE

The object is not running.

MK_E_NOOBJECT

The parameter pszItem does not identify a object in this container.

Comments

The item moniker implementation of IMoniker::IsRunning calls this method.

Notes to Implementors

Your implementation of IOleItemContainer::IsRunning should first determine whether pszItem identifies one of the container's objects. If it does not, your implementation should return MK_E_NOOBJECT. If the object is not loaded, your implementation should return S_FALSE. If it is loaded, your implementation can call the OleIsRunning API function to determine whether it is running.

If pszItem names a pseudo-object, your implementation can simply return S_OK because a pseudo-object is running whenever its container is running.

See Also

IMoniker::IsRunning


IOleLink

The IOleLink interface is the means by which a linked object provides its container with functions pertaining to linking. The most important of these functions is binding to the link source, that is, activating the connection to the document that stores the linked object's native data. IOleLink also defines functions for managing information about the linked object, such as the location of the link source and the cached presentation data for the linked object.

A container application can distinguish between embedded objects and linked objects by querying for IOleLink; only linked objects implement IOleLink.

When to Implement

You do not have to implement this interface yourself; the system supplies an implementation of IOleLink that is suitable for all situations. This implementation is used automatically whenever you create or load a linked object.

When to Use

You must use IOleLink if you are writing a container application that allows its documents to contain linked objects. You primarily call IOleLink methods in order to implement the Links dialog box. If you use the OleUIEditLinks API function to display the Links dialog box, your calls to IOleLink methods take place in your implementation of the IOleUILinkContainer interface.

Some IOleLink methods don't have to be called directly. Instead, you call methods of IOleObject; the default linked object provides an implementation of IOleObject that often calls methods of IOleLink. For example, a container application typically activates a linked object by calling IOleObject::DoVerb, which in turn calls IOleLink::BindToSource.

Methods in VTable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments the reference count.
Release	Decrements the reference count.
IOleLink Methods	Description
SetUpdateOptions	Sets the update options.
GetUpdateOptions	Returns the update options.
SetSourceMoniker	Sets the moniker for the link source.
GetSourceMoniker	Returns the moniker for the link source.
SetSourceDisplayName	Sets the display name for the link source.
GetSourceDisplayName	Returns the display name for the link source.
BindToSource	Binds the moniker to the link source.
BindIfRunning	Binds the moniker if the source is running.
GetBoundSource	Returns a pointer to the link source if it's running.
UnbindSource	Break connection to the link source.
Update	Update the cached views of the link source.
See Also

IOleObject, IOleUILinkContainer, OleUIEditLinks


IOleLink::BindIfRunning

Activates the connection between the linked object and the link source if the link source is already running.

HRESULT BindIfRunning(void);

Return Values

S_OK

The link source was bound.

S_FALSE

The link source is not running.

CreateBindCtx, IMoniker::IsRunning, or IOleLink::BindToSource errors

Binding the moniker might require calling these functions; therefore, errors generated by these functions may be returned.

Comments

You typically do not need to call IOleLink::BindIfRunning. This method is primarily called by the linked object.

Notes on Provided Implementation

The linked object's implementation of IOleLink::BindIfRunning checks the Running Object Table (ROT) to determine whether the link source is already running. It checks both the relative and absolute monikers. If the link source is running, IOleLink::BindIfRunning calls IOleLink::BindToSource to connect the linked object to the link source.

See Also

IOleLink::BindToSource


IOleLink::BindToSource

Activates the connection to the link source by binding the moniker stored within the linked object.

HRESULT BindToSource(

DWORD bindflags,	//Flag in case CLSID of link source is different
IBindCtx *pbc	//Bind context to be used
);
Parameters

bindflags

[in] Specifies how to proceed if the link source has a different CLSID from the last time it was bound. If this parameter is zero and the CLSIDs are different, the method fails and returns OLE_E_CLASSDIFF. If the OLELINKBIND_EVENIFCLASSDIFF value from the OLELINKBIND enumeration is specified and the CLSIDs are different, the method binds successfully and updates the CLSID stored in the linked object.

pbc

[in] Points to the bind context to be used in this binding operation. This parameter can be NULL. The bind context caches objects bound during the binding process, contains parameters that apply to all operations using the bind context, and provides the means by which the binding implementation should retrieve information about its environment. For more information, see IBindCtx.

Return Values

S_OK

Indicates that the link source is bound.

OLE_E_CLASSDIFF

Indicates that the link source was not bound because its CLSID has changed. This error is returned only if the OLELINKBIND_EVENIFCLASSDIFF flag is not specified in the bindflags parameter.

MK_E_NOOBJECT

Indicates that the link source could not be found or (if the link source's moniker is a composite) some intermediate object identified in the composite could not be found.

E_UNSPEC

Indicates that the link's moniker is NULL.

CreateBindCtx errors

Binding the moniker might require calling this function; therefore, this method may return errors generated by this function.

Comments

Notes to Callers

Typically, your container application does not need to call the IOleLink::BindToSource method directly. When it's necessary to activate the connection to the link source, your container typically calls IOleObject::DoVerb, IOleObject::Update, or IOleLink::Update. The linked object's implementation of these methods calls IOleLink::BindToSource. Your container can also call the OleRun API function, which — when called on a linked object — calls IOleLink::BindToSource.

In each of the examples listed above, in which IOleLink::BindToSource is called indirectly, the bindflags parameter is set to zero. Consequently, these calls can fail with the OLE_E_CLASSDIFF error if the class of the link source is different from what it was the last time the linked object was bound. This could happen, for example, if the original link source was an embedded Lotus spreadsheet that an end user had subsequently converted (using the Change Type dialog box) to an Excel spreadsheet.

If you want your container to bind even though the link source now has a different CLSID, you can call IOleLink::BindToSource directly and specify OLELINKBIND_EVENIFCLASSDIFF for the bindflags parameter. This call binds to the link source and updates the link object's CLSID. Alternatively, your container can delete the existing link and use the OleCreateLink API function to create a new linked object.

Notes on Provided Implementation

The linked object caches the interface pointer to the link source acquired during binding.

The linked object's IOleLink::BindToSource implementation first tries to bind using a moniker consisting of the compound document's moniker composed with the link source's relative moniker. If successful, it updates the link's absolute moniker. Otherwise, it tries to bind using the absolute moniker, updating the relative moniker if successful.

If IOleLink::BindToSource binds to the link source, it calls the compound document's IOleContainer::LockContainer implementation to keep the containing compound document alive while the link source is running. IOleLink::BindToSource also calls the IOleObject::Advise and IDataObject::DAdvise implementations of the link source to set up advisory connections. The IOleLink::UnbindSource implementation unlocks the container and deletes the advisory connections.

See Also

IDataObject::DAdvise, IOleContainer::LockContainer, IOleLink::Update, IOleLink::UnbindSource, IOleObject::Advise, IOleObject::DoVerb, IOleObject::Update, OleRun


IOleLink::GetBoundSource

Returns an IUnknown pointer to the link source if the connection is currently active.

HRESULT GetBoundSource(

IUnknown **ppunk	//Receives pointer to link source
);
Parameter

ppunk

[out] Receives an IUnknown pointer to the link source. If an error occurs, the implementation sets *ppunk to NULL. If *ppunk is non-NULL, the implementation must call IUnknown::AddRef on the parameter; it is the caller's responsibility to call IUnknown::Release.

Return Values

S_OK

Indicates that a pointer was returned successfully.

E_FAIL

Indicates that the link source is not bound.

Comments

You typically do not need to call IOleLink::GetBoundSource.


IOleLink::GetSourceDisplayName

Retrieves the display name of the link source of the linked object.

HRESULT GetSourceDisplayName(

LPOLESTR *ppszDisplayName	//Receives display name of link source
);
Parameter

ppszDisplayName

[out] Receives a pointer to a zero-terminated string containing the display name of the link source. If an error occurs, *ppszDisplayName is set to NULL; otherwise, the implementation must use IMalloc::Alloc to allocate the string returned in ppszDisplayName, and the caller is responsible for calling IMalloc::Free to free it. Both caller and callee use the allocator returned by CoGetMalloc(MEMCTX_TASK, ...). For Win32 applications, the LPOLESTR type indicates a wide character string (two bytes per character); otherwise, the string has one byte per character.

Return Values

S_OK

The display name was successfully retrieved.

E_FAIL

The link's moniker is NULL.

CreateBindCtx and IMoniker::GetDisplayName errors

Retrieving the display name requires calling these functions; therefore, this method may return errors generated by these functions.

Comments

Notes to Callers

Your container application can call IOleLink::GetSourceDisplayName in order to display the current source of a link.

The current source of a link is displayed in the Links dialog box. If you use the OleUIEditLinks API function to display the Links dialog box, you must implement the IOleUILinkContainer interface. The dialog box calls your implementations of IOleUILinkContainer::GetLinkSource to get the string it should display. Your implementation of that method can call IOleLink::GetSourceDisplayName.

Notes on Provided Implementation

The linked object's implementation of IOleLink::GetSourceDisplayName calls IOleLink::GetSourceMoniker to get the link source moniker, and then calls IMoniker::GetDisplayName to get that moniker's display name. This operation is potentially expensive because it might require binding the moniker. All of the system-supplied monikers can return a display name without binding, but there is no guarantee that other moniker implementations can. Instead of making repeated calls to IOleLink::GetSourceDisplayName, your container application can cache the name and update it whenever the link source is bound.

See Also

IOleLink::SetSourceDisplayName, IOleUILinkContainer, IMoniker::GetDisplayName, OleUIEditLinks


IOleLink::GetSourceMoniker

Retrieves the moniker identifying the link source of a linked object.

HRESULT GetSourceMoniker(

IMoniker **ppmk	//Receives moniker identifying link source
);
Parameter

ppmk

[out] Receives a pointer to an absolute moniker that identifies the link source. May be NULL if an error occurs. If *ppmk is non-NULL, the implementation must call IUnknown::AddRef on the parameter; it is the caller's responsibility to call IUnknown::Release.

Return Values

S_OK

The moniker was returned successfully.

MK_E_UNAVAILABLE

No moniker is available.

Comments

Notes to Callers

Your container application can call IOleLink::GetSourceMoniker to display the current source of a link in the Links dialog box. Note that this requires your container to use the IMoniker::GetDisplayName method to get the display name of the moniker. If you'd rather get the display name directly, your container can call IOleLink::GetSourceDisplayName instead of IOleLink::GetSourceMoniker.

If you use the OleUIEditLinks API function to display the Links dialog box, you must implement the IOleUILinkContainer interface. The dialog box calls your implementations of IOleUILinkContainer::GetLinkSource to get the string it should display. Your implementation of that method can call IOleLink::GetSourceMoniker.

Notes on Provided Implementation

The linked object stores both an absolute and a relative moniker for the link source. If the relative moniker is non-NULL and a moniker is available for the compound document, IOleLink::GetSourceMoniker returns the moniker created by composing the relative moniker onto the end of the compound document's moniker. Otherwise, it returns the absolute moniker or, if an error occurs, NULL.

The container specifies the absolute moniker when it calls one of the OleCreateLink functions to create a link. The application can call IOleLink::SetSourceMoniker or IOleLink::SetSourceDisplayName to change the absolute moniker. In addition, the linked object automatically updates the monikers whenever it successfully binds to the link source, or when it is bound to the link source and it receives a rename notification through the IAdviseSink::OnRename method.

See Also

IOleLink::SetSourceDisplayName, IOleLink::SetSourceMoniker


IOleLink::GetUpdateOptions

Retrieves a value indicating how often the linked object updates its cached data.

HRESULT GetUpdateOptions(

DWORD *pdwUpdateOpt	//Receives update option
);
Parameter

pdwUpdateOpt

[out] Receives the current value for the linked object's update option, indicating how often the linked object updates the cached data for the linked object. The legal values for pdwUpdateOpt are taken from the enumeration OLEUPDATE. For information on the OLEUPDATE enumeration, see the "Data Structures" section.

Return Value

S_OK

The update option was retrieved successfully.

Comments

Notes to Callers

Your container application should call IOleLink::GetUpdateOptions to display the current update option for a linked object.

A linked object's current update option is displayed in the Links dialog box. If you use the OleUIEditLinks API function to display the Links dialog box, you must implement the IOleUILinkContainer interface. The dialog box calls your implementation of IOleUILinkContainer::GetLinkUpdateOptions to determine which update option it should display. Your implementation of that method should call IOleLink::GetUpdateOptions to retrieve the current update option.

See Also

IOleLink::SetUpdateOptions, IOleUILinkContainer, OleUIEditLinks


IOleLink::SetSourceDisplayName

Specifies the new link source of a linked object using a display name.

HRESULT SetSourceDisplayName(

LPCOLESTR pszStatusText	//Display name of new link source
);
Parameter

pszStatusText

[in] The display name of the new link source. It may not be NULL.

Return Values

S_OK

The display name was set successfully.

MkParseDisplayName errors

Setting the display name requires calling this function; therefore, this method may return errors generated by this function.

Comments

Notes to Callers

Your container application can call IOleLink::SetSourceDisplayName when the end user changes the source of a link or breaks a link. Note that this requires the linked object to create a moniker out of the display name. If you'd rather parse the display name into a moniker yourself, your container can call IOleLink::SetSourceMoniker instead of IOleLink::SetSourceDisplayName.

If you use the OleUIEditLinks API function to display the Links dialog box, you must implement the IOleUILinkContainer interface. The dialog box calls your implementations of IOleUILinkContainer::SetLinkSource and IOleUILinkContainer::CancelLink. Your implementation of these methods can call IOleLink::SetSourceDisplayName.

If your container application is immediately going to bind to a newly specified link source, you should call MkParseDisplayName and IOleLink::SetSourceMoniker instead, and then call IOleLink::BindToSource using the bind context from the parsing operation. By reusing the bind context, you can avoid redundant loading of objects that might otherwise occur.

Notes on Provided Implementation

The contract for IOleLink::SetSourceDisplayName does not specify when the linked object will parse the display name into a moniker. The parsing can occur before IOleLink::SetSourceDisplayName returns, or the linked object can store the display name and parse it only when it needs to bind to the link source. Note that parsing the display name is potentially an expensive operation because it might require binding to the link source. The provided implementation of IOleLink::SetSourceDisplayName parses the display name and then releases the bind context used in the parse operation. This can result in running and then stopping the link source server.

If the linked object is bound to the current link source, the implementation of IOleLink::SetSourceDisplayName breaks the connection.

For more information on how the linked object stores and uses the moniker to the link source, see IOleLink::SetSourceMoniker.

See Also

IOleLink::SetSourceMoniker, IOleUILinkContainer, MkParseDisplayName, OleUIEditLinks


IOleLink::SetSourceMoniker

Specifies the new link source of a linked object using a moniker.

HRESULT SetSourceMoniker(

IMoniker *pmk,	//Moniker identifying new link source
REFCLSID rclsid	//CLSID of link source
);
Parameters

pmk

[in] Points to a moniker that identifies the new link source of the linked object. A value of NULL breaks the link.

rclsid

[in] Specifies the CLSID of the link source that the linked object should use to access information about the linked object when it is not bound.

Return Value

S_OK

The moniker was set successfully.

Comments

Notes to Callers

Your container application can call IOleLink::SetSourceMoniker when the end user changes the source of a link or breaks a link. Note that this requires your container to use the MkParseDisplayName API function to create a moniker out of the display name that the end user enters. If you'd rather have the linked object perform the parsing, your container can call IOleLink::SetSourceDisplayName instead of IOleLink::SetSourceMoniker.

The end user changes the source of a link or breaks a link using the Links dialog box. If you use the OleUIEditLinks API function to display the Links dialog box, you must implement the IOleUILinkContainer interface. The dialog box calls your implementations of IOleUILinkContainer::SetLinkSource and IOleUILinkContainer::CancelLink; your implementation of these methods can call IOleLink::SetSourceMoniker.

If the linked object is currently bound to its link source, the linked object's implementation of IOleLink::SetSourceMoniker closes the link before changing the moniker.

Notes on Provided Implementation

The IOleLink contract does not specify how the linked object stores or uses the link source moniker. The provided implementation stores the absolute moniker specified when the link is created or when the moniker is changed; it then computes and stores a relative moniker. Future implementations might manage monikers differently to provide better moniker tracking. The absolute moniker provides the complete path to the link source. The linked object uses this absolute moniker and the moniker of the compound document to compute a relative moniker that identifies the link source relative to the compound document that contains the link.

pmkCompoundDoc->RelativePathTo(pmkAbsolute, ppmkRelative)

When binding to the link source, the linked object first tries to bind using the relative moniker. If that fails, it tries to bind the absolute moniker.

When the linked object successfully binds using either the relative or the absolute moniker, it automatically updates the other moniker. The linked object also updates both monikers when it is bound to the link source and it receives a rename notification through the IAdviseSink::OnRename method. A container application can also use the IOleLink::SetSourceDisplayName method to change a link's moniker.

The linked object's implementation of IPersistStorage::Save saves both the relative and the absolute moniker.

See Also

IOleLink::GetSourceMoniker, IOleLink::SetSourceDisplayName, IOleUILinkContainer, OleUIEditLinks


IOleLink::SetUpdateOptions

Specifies how often a linked object should update its cached data.

HRESULT SetUpdateOptions(

DWORD dwUpdateOpt	//Update option
);
Parameter

dwUpdateOpt

[in] Specifies how often a linked object should update its cached data. The legal values for dwUpdateOpt are taken from the enumeration OLEUPDATE. For information on the OLEUPDATE enumeration, see the "Data Structures" section.

Return Values

S_OK

The update option was successfully set.

E_INVALIDARG

The dwUpdateOpt value is invalid.

Comments

Notes to Callers

Your container application should call IOleLink::SetUpdateOptions when the end user changes the update option for a linked object.

The end user selects the update option for a linked object using the Links dialog box. If you use the OleUIEditLinks API function to display this dialog box, you must implement the IOleUILinkContainer interface. The dialog box calls your IOleUILinkContainer::SetLinkUpdateOptions method to specify the update option chosen by the end user. Your implementation of this method should call the IOleLink::SetUpdateOptions method to pass the selected option to the linked object.

Notes on Provided Implementation

The default update option is OLEUDPATE_ALWAYS. The linked object's implementation of IPersistStorage::Save saves the current update option.

If OLEUDPATE_ALWAYS is specified as the update option, the linked object updates the link's caches in the following situations:

•	When the update option is changed from manual to automatic, if the link source is running.

•	Whenever the linked object binds to the link source.

•	Whenever the link source is running and the linked object's IOleObject::Close, IPersistStorage::Save, or IAdviseSink::OnSave implementations are called.

For both manual and automatic links, the linked object updates the cache whenever the container application calls IOleObject::Update or IOleLink::Update.

See Also

IOleObject::Update, IOleLink::GetUpdateOptions, IOleLink::Update, IOleUILinkContainer, OleUIEditLinks


IOleLink::UnbindSource

Deactivates the connection between a linked object and its link source.

HRESULT UnbindSource(void);

Return Value

S_OK

Indicates the connection was deactivated.

Comments

You typically do not call IOleLink::UnbindSource directly. When it's necessary to deactivate the connection to the link source, your container typically calls IOleObject::Close or IUnknown::Release; the linked object's implementation of these methods calls IOleLink::UnbindSource. The linked object's IAdviseSink::OnClose implementation also calls IOleLink::UnbindSource.

Notes on Provided Implementation

The linked object's implementation of IOleLink::UnbindSource does nothing if the link source is not currently bound. If the link source is bound, IOleLink::UnbindSource calls the link source's IOleObject::Unadvise and IDataObject::DUnadvise implementations to delete the advisory connections to the link source. The IOleLink::UnbindSource method also calls the compound document's IOleClientSite::LockContainer implementation to unlock the containing compound document. This undoes the lock on the container and the advisory connections that were established in IOleLink::BindToSource. IOleLink::UnbindSource releases all the linked object's interface pointers to the link source.

See Also

IAdviseSink::OnClose, IDataObject::DUnadvise, IOleObject::Close, IOleObject::Unadvise, IOleLink::BindToSource


IOleLink::Update

Updates the compound document's cached data for a linked object. This involves binding to the link source, if it is not already bound.

HRESULT Update(

IBindCtx *pbc	//Bind context to be used
);
Parameter

pbc

[in] Points to the bind context to be used in binding the link source. This parameter can be NULL. The bind context caches objects bound during the binding process, contains parameters that apply to all operations using the bind context, and provides the means by which the binding implementation should retrieve information about its environment. For more information, see IBindCtx.

Return Values

S_OK

All caches were updated successfully.

CACHE_E_NOCACHE_UPDATED

The bind operation worked but no caches were updated.

CACHE_S_SOMECACHES_NOTUPDATED

The bind operation worked but not all caches were updated.

OLE_E_CANT_BINDTOSOURCE

Unable to bind to the link source.

Comments

Notes to Callers

Your container application should call IOleLink::Update if the end user updates the cached data for a linked object.

The end user can update the cached data for a linked object by choosing the Update Now button in the Links dialog box. If you use the OleUIEditLinks API function to display the Links dialog box, you must implement the IOleUILinkContainer interface. The dialog box calls your implementations of IOleUILinkContainer::UpdateLink when the end user chooses the Update Now button. Your implementation of that method can call IOleLink::Update.

Your container application can also call IOleObject::Update to update a linked object, because that method — when called on a linked object — calls IOleLink::Update.

This method updates both automatic links and manual links. For manual links, calling IOleLink::Update or IOleObject::Update is the only way to update the caches. For more information on automatic and manual links, see IOleLink::SetUpdateOptions.

Notes on Provided Implementation

If pbc is non-NULL, the linked object's implementation of IOleLink::Update calls IBindCtx::RegisterObjectBound to register the bound link source. This ensures that the link source remains running until the bind context is released.

The current caches are left intact if the link source cannot be bound.

See Also

IBindCtx::RegisterObjectBound, IOleLink::SetUpdateOptions, IOleObject::Update, IOleUILinkContainer, OleUIEditLinks


IOleObject

The IOleObject interface is the principal means by which an embedded object provides basic functionality to, and communicates with, its container.

When to Implement

An object application must implement this interface, along with at least IDataObject and IPersistStorage, for each type of embedded object that it supports. Although this interface contains 21 member functions, only three are both essential and nontrivial to implement: DoVerb, SetHostNames, and Close. Six of the member functions are optional: SetExtent, InitFromData, GetClipboardData, SetColorScheme, SetMoniker, and GetMoniker. The latter two member functions are useful mainly for enabling links to embedded objects.

When to Use

Call the methods of this interface to enable a container to communicate with an embedded object. A container must call DoVerb to activate an embedded object, SetHostNames to communicate the names of the container application and container document, and Close to move an object from a running to a loaded state. Calls to all other member functions are optional.

Methods in VTable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments reference count.
Release	Decrements reference count.
IOleObject Methods	Description
SetClientSite	Informs object of its client site in container.
GetClientSite	Retrieves object's client site.
SetHostNames	Communicates names of container application and container document.
Close	Moves object from running to loaded state.
SetMoniker	Informs object of its moniker.
GetMoniker	Retrieves object's moniker.
InitFromData	Initializes embedded object from selected data.
GetClipboardData	Retrieves a data transfer object from the Clipboard.
DoVerb	Invokes object to perform one of its enumerated actions ("verbs").
EnumVerbs	Enumerates actions ("verbs") for an object.
Update	Updates an object.
IsUpToDate	Checks if object is up to date.
GetUserClassID	Returns an object's class identifier.
GetUserType	Retrieves object's user-type name.
SetExtent	Sets extent of object's display area.
GetExtent	Retrieves extent of object's display area.
Advise	Establishes advisory connection with object.
Unadvise	Destroys advisory connection with object.
EnumAdvise	Enumerates object's advisory connections.
GetMiscStatus	Retrieves status of object.
SetColorScheme	Recommends color scheme to object application.


IOleObject::Advise

Establishes an advisory connection between a compound document object and the calling object's advise sink, through which the calling object receives notification when the compound document object is renamed, saved, or closed.

HRESULT Advise(

IAdviseSink *pAdvSink,	//Pointer to advisory sink
DWORD *pdwConnection	//Pointer to a token
);
Parameters

pAdvSink

[in] Points to the advise sink of the calling object.

pdwConnection

[out] Points to a token that can be passed to IOleObject::Unadvise to delete the advisory connection.

Return Values

S_OK

Advisory connection is successfully established.

E_OUTOFMEMORY

Attempt to establish advisory connection fails, owing to insufficient memory.

Comments

The Advise method sets up an advisory connection between an object and its container, through which the object informs the container's advise sink of close, save, rename, and link-source change events in the object. A container calls this method, normally as part of initializing an object, to register its advisory sink with the object. In return, the object sends the container compound-document notifications by calling IAdviseSink or IAdviseSink2.

If container and object successfully establish an advisory connection, the object receiving the call returns a nonzero value through pdwConnection to the container. If the attempt to establish an advisory connection fails, the object returns zero. To delete an advisory connection, the container calls IOleObject::Unadvise and passes this nonzero token back to the object.

An object can delegate the job of managing and tracking advisory events to an OLE advise holder, to which you obtain a pointer by calling CreateOleAdviseHolder. The returned IOleAdviseHolder interface has three methods for sending advisory notifications, as well as Advise, Unadvise, and EnumAdvise methods that are identical to those for IOleObject. Calls to IOleObject:Advise, Unadvise, or EnumAdvise are delegated to corresponding methods in the advise holder.

To destroy the advise holder, simply call Release on the IOleAdviseHolder interface.

See Also

CreateOleAdviseHolder, IOleObject::UnAdvise, IOleObject::EnumAdvise, IOleAdviseHolder::Advise


IOleObject::Close

Changes an embedded object from the running to the loaded state. Disconnects a linked object from its link source.

HRESULT Close(

DWORD dwSaveOption	//Indicates whether to save object before closing
);
Parameter

dwSaveOption

[in] Indicates whether the object is to be saved as part of the transition to the loaded state. Valid values are taken from the enumeration OLECLOSE.

Note  The OLE 2 user model recommends that object applications do not prompt users before saving linked or embedded objects, including those activated in place. This policy represents a change from the OLE 1 user model, in which object applications always prompt the user to decide whether to save changes.

Return Values

S_OK

The object closed successfully.

OLE_E_PROMPTSAVECANCELLED

The user was prompted to save but chose the Cancel button from the prompt message box.

Comments

Notes to Callers

A container application calls IOleObject::Close when it wants to move the object from a running to a loaded state. Following such a call, the object still appears in its container but is not open for editing. Calling IOleObject::Close on an object that is loaded but not running has no effect. Closing a linked object simply means disconnecting it.

Notes to Implementors

Upon receiving a call to IOleObject::Close, a running object should do the following:

•	If the object has been changed since it was last opened for editing, it should request to be saved, or not, according to instructions specified in dwSaveOption. If the option is to save the object, then it should call its container's IOleClientSite::SaveObject interface.

•	If the object has IDataObject::DAdvise connections with ADVF_DATAONSTOP flags, then it should send an OnDataChange notification. See IDataObject::DAdvise for details.

•	If the object currently owns the Clipboard, it should empty it by calling OleFlushClipboard.

•	If the object is currently visible, notify its container by calling IOleClientSite::OnShowWindow with the fshow argument set to FALSE.

•	Send IAdvise::OnClose notifications to appropriate advise sinks.

•	Finally, forcibly cut off all remoting clients by calling CoDisconnectObject.

If the object application is a local server (an EXE rather than a DLL), closing the object should also shut down the object application unless the latter is supporting other running objects or has another reason to remain in the running state. Such reasons might include the presence of IClassFactory::LockServer locks, end-user control of the application, or the existence of other open documents requiring access to the application.

Calling IOleObject::Close on a linked object disconnects it from, but does not shut down, its source application. A source application that is visible to the user when the object is closed remains visible and running after the disconnection and does not send an OnClose notification to the link container.

See Also

CoDisconnectObject, IAdviseSink::OnClose, IClassFactory::LockServer, IDataObject::DAdvise, IOleClientSite::OnShowWindow, IOleClientSite::SaveObject, OLECLOSE, OleFlushClipboard


IOleObject::DoVerb

Requests an object to perform an action in response to an end-user's action. The possible actions are enumerated for the object in IOleObject::EnumVerbs.

HRESULT DoVerb(

LONG iVerb,	//Value representing verb to be performed
LPMSG lpmsg,	//Ptr to Windows message
IOleClientSite *pActiveSite,	//Ptr to active client site
LONG lindex,	//Reserved for future use
HWND hwndParent,	//Handle of window containing the object
LPCRECT lprcPosRect	//Ptr to object's display rectangle
);
Parameters

iVerb

[in] The number assigned to the verb in the OLEVERB structure returned by IOleObject::EnumVerbs.

lpmsg

[in] Points to the MSG structure describing the event (such as a double-click) that invoked the verb.

pActiveSite

[in] Points to the object's active client site, where the event occurred that invoked the verb.

lindex

[in] Reserved for future use; should be zero.

hwndParent

[in] Handle of the document window containing the object. This and lprcPosRect together make it possible to open a temporary window for an object, where hwndParent is the parent window in which the object's window is to be displayed, and lprcPosRect defines the area available for displaying the object window within that parent. A temporary window is useful, for example, to a multimedia object that opens itself for playback but not for editing.

lprcPosRect

[in] Points to the RECT structure containing the coordinates, in pixels, that define an object's bounding rectangle in hwndParent. This and hwndParent together enable opening multimedia objects for playback but not for editing.

Return Values

S_OK

Object successfully invoked specified verb.

OLE_E_NOT_INPLACEACTIVE

iVerb set to OLEIVERB_UIACTIVATE or OLEIVERB_INPLACEACTIVATE and object is not already visible.

OLE_E_CANT_BINDTOSOURCE

The object handler or link object cannot connect to the link source.

DV_E_LINDEX

Invalid lindex.

OLEOBJ_S_CANNOT_DOVERB_NOW

The verb is valid, but in the object's current state it cannot carry out the corresponding action.

OLEOBJ_S_INVALIDHWND

DoVerb was successful but hwndParent is invalid.

OLEOBJ_E_NOVERBS

The object does not support any verbs.

OLEOBJ_S_INVALIDVERB

Object does not recognize a positive verb number. Verb is treated as OLEIVERB_PRIMARY.

MK_E_CONNECT

Link source is across a network that is not connected to a drive on this machine.

OLE_E_CLASSDIFF

Class for source of link has undergone a conversion.

E_NOTIMPL

Object does not support in-place activation or does not recognize a negative verb number.

Comments

A "verb" is an action that an OLE object takes in response to a message from its container. An object's container, or a client linked to the object, normally calls IOleObject::DoVerb in response to some end-user action, such as double-clicking on the object. The various actions that are available for a given object are enumerated in an OLEVERB structure, which the container obtains by calling IOleObject::EnumVerbs. IOleObject::DoVerb matches the value of iVerb against the iVerb member of the structure to determine which verb to invoke.

Through IOleObject::EnumVerbs, an object, rather than its container, determines which verbs (i.e., actions) it supports. OLE 2 defines seven verbs that are available, but not necessarily useful, to all objects. In addition, each object can define additional verbs that are unique to it. The following table describes the verbs defined by OLE:

Verb	Description
OLEIVERB_PRIMARY (0L)	Specifies the action that occurs when an end-user double-clicks the object in its container. The object, not the container, determines this action. If the object supports in-place activation, the primary verb usually activates the object in place.
OLEIVERB_SHOW (-1)	Instructs an object to show itself for editing or viewing. Called to display newly inserted objects for initial editing and to show link sources. Usually an alias for some other object-defined verb.
OLEIVERB_OPEN (-2)	Instructs an object, including one that otherwise supports in-place activation, to open itself for editing in a window separate from that of its container. If the object does not support in-place activation, this verb has the same semantics as OLEIVERB_SHOW.
OLEIVERB_HIDE (-3)	Causes an object to remove its user interface from the view. Applies only to objects that are activated in-place.
OLEIVERB_UIACTIVATE (-4)	Activates an object in place, along with its full set of user-interface tools, including menus, toolbars, and its name in the title bar of the container window. If the object does not support in-place activation, it should return E_NOTIMPL.
OLEIVERB_INPLACEACTIVATE (-5)	Activates an object in place without displaying tools, such as menus and toolbars, that end-users need to change the behavior or appearance of the object. Single-clicking such an object causes it to negotiate the display of its user-interface tools with its container. If the container refuses, the object remains active but without its tools displayed.
OLEIVERB_DISCARDUNDOSTATE (-6)	Used to tell objects to discard any undo state that they may be maintaining without deactivating the object.
Note to Callers

Containers call IOleObject::DoVerb as part of initializing a newly created object. Before making the call, containers should first call IOleObject::SetClientSite to inform the object of its display location and IOleObject::SetHostNames to alert the object that it is an embedded object and to trigger appropriate changes to the user interface of the object application in preparation for opening an editing window.

Like the OleActivate function in OLE 1, IOleObject::DoVerb automatically runs the OLE server application. If an error occurs during verb execution, the object application is shut down.

If an end-user invokes a verb by some means other than selecting a command from a menu (say, by double-clicking or, more rarely, single-clicking an object), the object's container should pass a pointer (lpmsg) to a Windows MSG structure containing the appropriate message. For example, if the end-user invokes a verb by double-clicking the object, the container should pass a MSG structure containing WM_LBUTTONDBLCLK, WM_MBUTTONDBLCLK, or WM_RBUTTONDBLCLK. If the container passes no message, lpmsg should be set to NULL. The object should ignore the hwnd member of the passed MSG structure, but can use all the other MSG members.

If the object's embedding container calls IOleObject::DoVerb, the client-site pointer (pClientSite) passed to DoVerb is the same as that of the embedding site. If the embedded object is a link source, the pointer passed to DoVerb is that of the linking client's client site.

When IOleObject::DoVerb is invoked on an OLE link, it may return OLE_E_CLASSDIFF or MK_CONNECTMANUALLY. The link object returns the former error when the link source has been subjected to some sort of conversion while the link was passive. The link object returns the latter error when the link source is located on a network drive that is not currently connected to the caller's computer. The only way to connect a link under these conditions is to first call QueryInterface, ask for IOleLink, allocate a bind context, and run the link source by calling IOleLink::BindToSource.

Container applications that do not support general in-place activation can still use the hwndParent and lprcPosRect parameters to support in-place playback of multimedia files. Containers must pass valid hwndParent and lprcPosRect parameters to IOleObject::DoVerb.

Some code samples pass a lindex value of -1 instead of zero. The value -1 works but should be avoided in favor of zero. The lindex parameter is a reserved parameter, and for reasons of consistency Microsoft recommends assigning a zero value to all reserved parameters.

Notes to Implementors

In addition to the above verbs, an object can define in its OLEVERB structure additional verbs that are specific to itself. Positive numbers designate these object-specific verbs. An object should treat any unknown positive verb number as if it were the primary verb and return OLE_S_INVALIDVERB to the calling function. The object should ignore verbs with negative numbers that it does not recognize and return E_NOTIMPL.

If the verb being executed places the object in the running state, you should register the object in the Running Object Table (ROT) even if its server application doesn't support linking. Registration is important because the object at some point may serve as the source of a link in a container that supports links to embeddings. Registering the object with the ROT enables the link client to get a pointer to the object directly, instead of having to go through the object's container. To perform the registration, call IOleClientSite::GetMoniker to get the full moniker of the object, call the GetRunningObjectTable API function to get a pointer to the ROT, and then call IRunningObjectTable::Register.

Note  When the object leaves the running state, remember to revoke the object's registration with the ROT by calling IOleObject::Close. If the object's container document is renamed while the object is running, you should revoke the object's registration and re-register it with the ROT, using its new name. The container should inform the object of its new moniker either by calling IOleObject::SetMoniker or by responding to the object's calling IOleClientSite::GetMoniker.

When showing a window as a result of DoVerb, it is very important for the object to explicitly call SetForegroundWindow on its editing window. This ensures that the object's window will be visible to the user even if another process originally obscured it. For more information about SetForegroundWindow and SetActiveWindow, see the Win32 SDK.

See Also

GetRunningObjectTable, IOleClientSite::GetMoniker, IOleLink::BindToSource, IOleObject::Close, IOleObject::EnumVerbs, IOleObject::GetMoniker, IOleObject::SetMoniker, IRunningObjectTable::Register, OleRun

SetForegroundWindow, SetActiveWindow in Win32


IOleObject::EnumAdvise

Enumerates the advisory connections registered for an object, so a container can know what to release prior to closing down.

HRESULT EnumAdvise(

IEnumSTATDATA **ppenumAdvise	//Pointer to storage of a struct
);
Parameter

ppenumAdvise

[out] Points to where the new enumerator should be returned. NULL is a legal return value, indicating that the object does not have any advisory connections. If an error is returned, this parameter must be set to NULL. Each time an object receives a call to EnumAdvise, it must increase the reference count on the pointer it returns. It is the caller's responsibility to call Release when it is done with the pointer.

Return Values

S_OK

Enumerator returned successfully.

E_FAIL

Unspecified error encountered.

E_NOTIMPL

EnumAdvise is not implemented.

Comments

The EnumAdvise method provides a way for containers to keep track of advisory connections registered for their objects. A container normally would call this function so that it can instruct an object to release each of its advisory connections prior to closing down.

IOleObject::EnumAdvise enumerates items of type STATDATA. Upon receiving the pointer, the container can then loop through STATDATA and call IOleObject::Unadvise for each enumerated connection.

The usual way to implement this function is to delegate the call to the IOleAdviseHolder interface. Only the pAdvise and dwConnection members of STATDATA are relevant for IOleObject::EnumAdvise.

See Also

IOleObject::Advise, IOleObject::UnAdvise


IOleObject::EnumVerbs

Exposes a pull-down menu listing the verbs available for an object in ascending order by verb number.

HRESULT EnumVerbs(

IEnumOleVerb **ppEnumOleVerb	//Ptr to storage of enumerator
);
Parameter

ppEnumOleVerb

[out] Points to where the new enumerator should be returned. If an error is returned, this parameter must be set to NULL. Each time an object receives a call to EnumVerbs, it must increase the reference count on the pointer the method returns. It is the caller's responsibility to call Release when it is done with the pointer.

Return Values

S_OK

Verb(s) enumerated successfully.

OLE_S_USEREG

Delegate to the default handler to use the entries in the registry to provide the enumeration.

OLEOBJ_E_NOVERBS

Object does not support any verbs.

Comments

Notes to Callers

Containers call this method to expose a pull-down menu of the verbs available for their embedded objects. You may want your container to call IOleObject::EnumVerbs each and every time such a menu is selected in order to enable such objects as media clips, whose verbs may change while they are running, to update their menus. The default verb for a media clip, for example, changes from "Play" before it is activated to "Stop" once it is running.

Notes to Implementors

The default handler's implementation of IOleObject::EnumVerbs uses the registry to enumerate an object's verbs. If an object application is to use the default handler's implementation, it should return OLE_S_USEREG.

The enumeration returned is of type IEnumOLEVERB:

typedef Enum < OLEVERB > IEnumOLEVERB;

where OLEVERB is defined as:

typedef struct tagOLEVERB

{

LONG    iVerb;

LPOLESTR   lpszVerbName;

DWORD   fuFlags;

DWORD   grfAttribs;

} OLEVERB;

The following table describes the members of the OLEVERB structure:

OLEVERB Member	Description
iVerb	Verb number being enumerated. If the object supports OLEIVERB_OPEN, OLEIVERB_SHOW and/or OLEIVERB_HIDE (or another predefined verb), these will be the first verbs enumerated, since they have the lowest verb numbers.
lpszVerbName	Name of the verb.  In Windows, this value, along with optional embedded ampersand characters to indicate accelerator keys, can be passed to the AppendMenu function. On the Macintosh, the following metacharacters may be passed along with this value:
	•   ! marks the menu item with the subsequent character
	•   < sets the character style of the item
	•   ( disables the item.
	The metacharacters / and ^ are not permitted.
fuFlags	In Windows, a group of flags taken from the flag constants beginning with MF_ defined in AppendMenu. Containers should use these flags in building an object's verb menu. All Flags defined in AppendMenu are supported except for:
	•   MF_BITMAP
	•   MF_OWNERDRAW
	•   MF_POPUP
grfAttribs	In Windows, a group of flag bits taken from the enumeration OLEVERBATTRIB. The flag OLEVERBATTRIB_NEVERDIRTIES indicates that executing this verb will not cause the object to become dirty and is therefore in need of saving to persistent storage. OLEVERBATTRIB_ONCONTAINERMENU indicates that this verb should be placed on the container's menu of object verbs when the object is selected. OLEIVERB_HIDE, OLEIVERB_SHOW, and OLEIVERB_OPEN never have this value set.
For more information on the Windows AppendMenu function, see the Microsoft Win32 SDK.

See Also

IOleObject::DoVerb, OleRegEnumVerbs


IOleObject::GetClientSite

Obtains a pointer to an embedded object's client site.

HRESULT GetClientSite(

IOleClientSite **ppClientSite	//Storage of pointer to object's client site
);
Parameter

ppClientSite

[out] Points to an address where the returned client-site pointer is stored. If an object does not yet know its client site, or an error has occurred, this parameter must be set to NULL. Each time an object receives a call to GetClientSite, it must increase the reference count on the pointer the method returns. It is the caller's responsibility to call Release when it is done with the pointer.

Return Value

S_OK

Client site pointer returned successfully.

Comments

Link clients most commonly call the IOleObject::GetClientSite method in conjunction with the IOleClientSite::GetContainer method to traverse a hierarchy of nested objects. A link client calls IOleObject::GetClientSite to get a pointer to the link source's client site. The client then calls IOleClientSite::GetContainer to get a pointer to the link source's container. Finally, the client calls IOleContainer::QueryInterface to get IOleObject and IOleObject::GetClientSite to get the container's client site within its container. By repeating this sequence of calls, the caller can eventually retrieve a pointer to the master container in which all the other objects are nested.

Notes to Callers

The returned client-site pointer will be NULL if an embedded object has not yet been informed of its client site. This will be the case with a newly loaded or created object when a container has passed a NULL client-site pointer to one of the object-creation helper functions but has not yet called IOleObject::SetClientSite as part of initializing the object.

See Also

IOleObject::SetClientSite


IOleObject::GetClipboardData

Retrieves a data object containing the current contents of the embedded object on which this method is called. Using the pointer to this data object, it is possible to create a new embedded object with the same data as the original.

HRESULT GetClipboardData(

DWORD dwReserved,	//Not currently implemented
IDataObject **ppDataObject	//Pointer to storage of interface pointer
);
Parameters

dwReserved

[in] Reserved for future use; must be zero.

ppDataObject

[out] Points to an interface pointer to the data object. If an error is returned, this parameter must be set to NULL. Each time an object receives a call to GetClipboardData, it must increase the reference count on the pointer that the method returns. It is the caller's responsibility to call Release when it is done with the pointer.

Return Values

S_OK

The data transfer object is successfully returned.

E_NOTIMPL

GetClipboardData is not supported.

OLE_E_NOTRUNNING

The object is not running.

Comments

You can use the GetClipboardData method to convert a linked object to an embedded object, in which case the container application would call IOleObject::GetClipboardData and then pass the data received to OleCreateFromData. This method returns a pointer to a data object that is identical to what would have been passed to the Clipboard by a standard copy operation.

Notes to Callers

If you want a stable snapshot of the current contents of an embedded object, call IOleObject::GetClipboardData. Should the data change, you will need to call the function again for an updated snapshot. If you want the caller to be informed of changes that occur to the data, call IDataObject::QueryInterface, then call IDataObject::DAdvise.

Notes to Implementors

If you implement this function, you must return an IDataObject pointer for an object whose data will not change.

See Also

IDataObject, IOleObject::InitFromData, IUnknown::QueryInterface, OleCreateFromData


IOleObject::GetExtent

Retrieves a running object's current display size.

HRESULT GetExtent(

DWORD dwDrawAspect,	//Value indicating object aspect
SIZEL *psizel	//Pointer to storage of object size limit
);
Parameters

dwDrawAspect

[in] Describes the aspect of the object whose limit is to be retrieved; the value is obtained from the enumeration DVASPECT. The most common value for this method is DVASPECT_CONTENT, which specifies a full rendering of the object within its container.

psizel

[out] Points to where the object's size is to be returned.

Return Values

S_OK

Extent information successfully returned.

E_INVALIDARG

Invalid value for dwAspect.

Comments

A container calls IOleObject::GetExtent on a running object to retrieve its current display size. If the container can accommodate that size, it will normally do so because the object, after all, knows what size it should be better than the container does. A container normally makes this call as part of initializing an object.

The display size returned by IOleObject::GetExtent may differ from the size last set by IOleObject::SetExtent because the latter method dictates the object's display space at the time the method is called but does not necessarily change the object's native size, as determined by its application.

Notes to Callers

Because a container can make this call only to a running object, the container must instead call IViewObject2::GetExtent if it wants to get the display size of a loaded object from its cache.

Notes to Implementors

Implementation consists of filling the sizel structure with an object's height and width.

See Also

IOleObject::SetExtent, IViewObject2::GetExtent


IOleObject::GetMiscStatus

Returns a value indicating the status of an object at creation and loading.

HRESULT GetMiscStatus(

DWORD dwAspect,	//Value indicating object aspect
DWORD *pdwStatus	//Pointer to storage of status information
);
Parameters

dwAspect

[in] The aspect of an object about which status information is being requested. The value is obtained from the enumeration DVASPECT (see "FORMATETC Data Structure").

pdwStatus

[out] Points to where the status information is returned. May not be NULL.

Return Values

S_OK

Status information returned successfully.

OLE_S_USEREG

Delegate the retrieval of miscellaneous status information to the default handler's implementation of this method.

CO_E_CLASSNOTREG

There is no CLSID registered for the object.

CO_E_READREGDB

Error accessing the registry.

Comments

A container normally calls IOleObject::GetMiscStatus when it creates or loads an object in order to determine how to display the object and what types of behaviors it supports.

Objects store status information in the registry. If the object is not running, the default handler's implementation of IOleObject::GetMiscStatus retrieves this information from the registry. If the object is running, the default handler invokes IOleObject::GetMiscStatus on the object itself.

The information that is actually stored in the registry varies with individual objects. The status values to be returned are defined in the enumeration OLEMISC.

Notes to Implementors

Implementation normally consists of delegating the call to the default handler.

See Also

DVASPECT, FORMATETC, OLEMISC


IOleObject::GetMoniker

Returns a embedded object's moniker, which the caller can use to link to the object.

HRESULT GetMoniker(

DWORD dwAssign,	//Specifies how moniker is assigned
DWORD dwWhichMoniker,	//Specifies which moniker is assigned
IMoniker **ppmk	//Storage of returned pointer
);
Parameters

dwAssign

[in] Determines how the moniker is assigned to the object. Depending on the value of dwAssign, IOleObject::GetMoniker does one of the following:

•	Obtains a moniker only if one has already been assigned,

•	Forces assignment of a moniker, if necessary, in order to satisfy the call, or

•	Obtains a temporary moniker.

Values for dwAssign are specified in the enumeration OLEGETMONIKER.

Note  	You cannot pass OLEGETMONIKER_UNASSIGN when calling IOleObject::GetMoniker. This value is valid only when calling IOleClientSite::GetMoniker.

dwWhichMoniker

[in] Specifies the form of the moniker being requested. Valid values are taken from the enumeration OLEWHICHMK.

ppmk

[out] Points to an address where to return the object's moniker. If an error is returned, this parameter must be set to NULL. Each time an object receives a call to GetMoniker, it must increase the reference count on the pointer the method returns. It is the caller's responsibility to call Release when it is done with the pointer.

Comments

The IOleObject::GetMoniker method returns an object's moniker. Like IOleObject::SetMoniker, this method is important only in the context of managing links to embedded objects and even in that case is optional. A potential link client that requires an object's moniker to bind to the object can call this method to obtain that moniker. The default implementation of IOleObject::GetMoniker calls the IOleClientSite::GetMoniker, returning E_UNEXPECTED if the object is not running or does not have a valid pointer to a client site.

See Also

CreateItemMoniker, IOleClientSite::GetMoniker, IOleObject::SetMoniker, OLEGETMONIKER, OLEWHICHMK


IOleObject::GetUserClassID

Returns an object's class identifier, the CLSID corresponding to the string identifying the object to an end user.

HRESULT GetUserClassID(

CLSID *pClsid	//Pointer to the class identifier
);
Parameter

pClsid

[out] Points to the class identifier (CLSID) to be returned. An object's CLSID is the binary equivalent of the user-type name returned by IOleObject::GetUserType.

Return Values

S_OK

CLSID returned successfully.

E_FAIL

An unspecified error occurred.

Comments

GetUserClassID returns the CLSID associated with the object in the registration database. Normally, this value is identical to the CLSID stored with the object, which is returned by IPersist::GetClassID. For linked objects, this is the CLSID of the last bound link source. If the object is running in an application different from the one in which it was created and for the purpose of being edited is emulating a class that the container application recognizes, the CLSID returned will be that of the class being emulated rather than that of the object's own class.

See Also

IOleObject::GetUserType, IPersist::GetClassID, OleDoAutoConvert, OleGetAutoConvert, OleSetAutoConvert, GetConvertStg, SetConvertStg


IOleObject::GetUserType

Retrieves the user-type name of an object for display in user-interface elements such as menus, list boxes, and dialog boxes.

HRESULT GetUserType(

DWORD dwFormOfType,	//Specifies form of type name
LPOLESTR *pszUserType	//Pointer to storage of string pointer
);
Parameters

dwFormOfType

[in] A value specifying the form of the user-type name to be presented to users. Valid values are obtained from the USERCLASSTYPE enumeration.

pszUserType

[out] Points to where a pointer to the user-type string will be placed. The caller must free lpszUserType using the current IMalloc instance. If an error is returned, this parameter must be set to NULL.

Return Values

S_OK

The object's user-type name is successfully returned.

OLE_S_USEREG

Delegate to the default handler's implementation using the registry to provide the requested information.

Comments

Containers call IOleObject::GetUserType in order to represent embedded objects in list boxes, menus, and dialog boxes by their normal, user-recognizable names. Examples include "Word Document," "Excel Chart," and "Paintbrush Object." The information returned by IOleObject::GetUserType is the user-readable equivalent of the binary class identifier returned by IOleObject::GetUserClassID.

Notes to Callers

The default handler's implementation of IOleObject::GetUserType uses the object's class identifier (the pClsid parameter returned by IOleObject::GetUserClassID) and the dwFormOfType parameter together as a key into the registry. If an entry is found that matches the key exactly, then the user type specified by that entry is returned. If only the CLSID part of the key matches, then the lowest-numbered entry available (usually the full name) is used. If the CLSID is not found, or there are no user types registered for the class, the user type currently found in the object's storage is used.

Notes to Implementors

You can use the implementation provided by the default handler by returning OLE_S_USEREG as your application's implementation of this method. If the user type name is an empty string, the message "Unknown Object" is returned.

You can call the OLE helper function OleRegGetUserType to return the appropriate user type.

See Also

IOleObject::SetHostNames, IOleObject::GetUserClassID, OleRegGetUserType, ReadFmtUserTypeStg, USERCLASSTYPE


IOleObject::InitFromData

Initializes a newly created object with data from a specified data object, which can reside either in the same container or on the Clipboard.

HRESULT InitFromData(

IDataObject *pDataObject,	//Pointer to data object
BOOL fCreation,	//Specifies how object is created
DWORD dwReserved	//Not used in OLE 2
);
Parameters

pDataObject

[in] Points to the data object from which the initialization data is to be obtained. This parameter can be NULL, which indicates that the caller wants to know if it is worthwhile trying to send data; that is, whether the container is capable of initializing an object from data passed to it. The data object to be passed can be based on either the current selection within the container document or on data transferred to the container from an external source.

fCreation

[in] TRUE indicates the container is inserting a new object inside itself and initializing that object with data from the current selection; FALSE indicates a more general programmatic data transfer, most likely from a source other than the current selection.

dwReserved

[in] Reserved for future use; must be zero.

Return Values

S_OK

If pDataObject is not NULL, the object successfully attempted to initialize itself from the provided data; if pDataObject is NULL, the object is able to attempt a successful initialization .

S_FALSE

If pDataObject is not NULL, the object made no attempt to initialize itself; if pDataObject is NULL, the object cannot attempt to initialize itself from the data provided.

E_NOTIMPL

The object does not support InitFromData.

OLE_E_NOTRUNNING

The object is not running and therefore cannot perform the operation.

Comments

This method enables a container document to insert within itself a new object whose content is based on a current data selection within the container. For example, a spreadsheet document may want to create a graph object based on data in a selected range of cells.

Using this method, a container can also replace the contents of an embedded object with data transferred from another source. This provides a convenient way of updating an embedded object.

Notes to Callers

Following initialization, the container should call IOleObject::GetMiscStatus to check the value of the OLEMISC_INSERTNOTREPLACE bit. If the bit is on, the new object inserts itself following the selected data. If the bit is off, the new object replaces the selected data.

Notes to Implementors

A container specifies whether to base a new object on the current selection by passing either TRUE or FALSE to the fCreation parameter.

If fCreation is TRUE, the container is attempting to create a new instance of an object, initializing it with the selected data specified by the data object.

If fCreation is FALSE, the caller is attempting to replace the object's current contents with that pointed to by pDataObject. The usual constraints that apply to an object during a paste operation should be applied here. For example, if the type of the data provided is unacceptable, the object should fail to initialize and return S_FALSE.

If the object returns S_FALSE, it cannot initialize itself from the provided data.

See Also

IOleObject::GetMiscStatus, IDataObject::SetData


IOleObject::IsUpToDate

Checks recursively whether or not an object is up to date.

HRESULT IsUpToDate();

Return Values

S_OK

Object is up to date.

S_FALSE

Object is not up to date.

OLE_E_UNAVAILABLE

Status of object cannot be determined in a timely manner.

Comments

The IsUpToDate method provides a way for containers to check recursively whether or not all objects are up to date.That is, when the container calls this method on the first object, the object in turn calls it for all its own objects, and they in turn for all of theirs, until all objects have been checked.

Notes to Implementors

Because of the recursive nature of IOleObject:IsUpToDate, determining whether an object is out-of-date, particularly one containing one or more other objects, can be as time-consuming as simply updating the object in the first place. If you would rather avoid lengthy queries of this type, make sure that IOleObject::IsUpToDate returns OLE_E_UNAVAILABLE. In cases where the object to be queried is small and contains no objects itself, thereby making an efficient query possible, this method can return either S_OK or S_FALSE.

See Also

IOleObject::UpDate


IOleObject::SetClientSite

Informs an embedded object of its display location, called a "client site," within its container.

HRESULT SetClientSite(

IOleClientSite *pClientSite	//Pointer to an embedded object's client site
);
Parameter

pClientSite

[in] Points to the container application's client-site interface.

Return Values

S_OK

Client site successfully set.

E_UNEXPECTED

Object is not embedded in a container.

Comments

Within a compound document, each embedded object has its own client site — the place where it is displayed and through which it receives information about its storage, user interface, and other resources. IOleObject::SetClientSite is the only method enabling an embedded object to obtain a pointer to its client site.

Notes to Callers

A container can notify an object of its client site either at the time the object is created or, subsequently, when the object is initialized.

When creating or loading an object, a container may pass a client-site pointer (along with other arguments) to one of the following helper functions: OleCreate, OleCreateFromFile, OleCreateFromData or OleLoad. These helper functions load an object handler for the new object and call IOleObject::SetClientSite on the container's behalf before returning a pointer to the new object.

Passing a client-site pointer informs the object handler that the client site is ready to process requests. If the client site is unlikely to be ready immediately after the handler is loaded, you may want your container to pass a NULL client-site pointer to the helper function. The NULL pointer says that that no client site is available and thereby defers notifying the object handler of the client site until the object is initialized. In response, the helper function returns a pointer to the object, but upon receiving that pointer the container must call SetClientSite as part of initializing the new object.

Notes to Implementors

Implementation consists simply of incrementing the reference count on, and storing, the pointer to the client site.

See Also

IOleClientSite, IOleObject::GetClientSite, OleCreate, OleCreateFromFile, OleCreateFromData, OleLoad


IOleObject::SetColorScheme

Specifies the color palette that the object application should use when it edits the specified object.

HRESULT SetColorScheme(

LOGPALETTE *pLogpal	//Pointer to a structure
);
Parameter

pLogpal

[in] Points to a LOGPALETTE structure that specifies the recommended palette.

Return Values

S_OK

Color palette received successfully.

E_NOTIMPL

Object does not support setting palettes.

OLE_E_PALETTE

Invalid LOGPALETTE structure pointed to by lpLogPal.

OLE_E_NOTRUNNING

Object must be running to perform this operation.

Comments

The IOleObject::SetColorScheme method sends the container application's recommended color palette to the object application, which is not obliged to use it.

Notes to Implementors

Upon receiving the palette, the object application should:

1.	Allocate and fill in its own LOGPALETTE structure with the colors specified in the container application's LOGPALETTE structure.

2.	Call CreatePalette to create a palette from the resulting LOGPALETTE structure. This palette can be used to render objects and color menus as the user edits objects in the document.

The first palette entry in the LOGPALETTE structure specifies the foreground color recommended by the container. The second palette entry specifies the recommended background color. The first half of the remaining palette entries are fill colors and the second half are colors for the lines and text.

Container applications typically specify an even number of palette entries. If a container specifies an odd number of entries, the object application should assume that the first half of the total entries plus one designate fill colors, while the remainder designate line and text colors. For example, if there are five entries, the first three should be interpreted as fill colors and the last two as line and text colors.


IOleObject::SetExtent

Informs an object of how much display space its container has assigned it.

HRESULT SetExtent(

DWORD dwDrawAspect,
SIZEL  *psizel
);
Parameters

dwDrawAspect

[in] Describes which form, or "aspect," of an object is to be displayed. The object's container obtains this value from the enumeration DVASPECT (see "FORMATETC Data Structure"). The most common aspect is DVASPECT_CONTENT, which specifies a full rendering of the object within its container. An object can also be rendered as an icon, a thumbnail version for display in a browsing tool, or a print version, which displays the object as it would be rendered using the File Print command.

psizel

[in] Specifies the size limit for the object.

Return Values

S_OK

The object has resized successfully.

E_FAIL

The object's size is fixed.

OLE_E_NOTRUNNING

The object is not running.

Comments

A container calls IOleObject::SetExtent when it needs to dictate to an embedded object the size at which it will be displayed. Often, this call occurs in response to an end user resizing the object window. Upon receiving the call, the object, if possible, should recompose itself gracefully to fit the new window.

Whenever possible, a container seeks to display an object at its finest resolution, sometimes called the object's native size. All objects, however, have a default display size specified by their applications, and in the absence of other constraints, this is the size they will use to display themselves. Since an object knows its optimum display size better than does its container, the latter normally requests that size from a running object by calling IOleObject::GetExtent. Only in cases where the container cannot accommodate the value returned by the object does it override the object's preference by calling IOleObject::SetExtent.

Notes to Callers

You can call SetExtent on an object only when the object is running. If a container resizes an object while an object is not running, the container should keep track of the object's new size but defer calling IOleObject::SetExtent until a user activates the object. If the OLEMISC_RECOMPOSEONRESIZE bit is set on an object, its container should force the object to run before calling OleObject::SetExtent.

As noted above, a container may want to delegate responsibility for setting the size of an object's display site to the object itself, by calling IOleObject::GetExtent.

Notes to Implementors

You may want to implement this method so that your object rescales itself to match as closely as possible the maximum space available to it in its container.

If an object's size is fixed, that is, if it cannot be set by its container, OleObject::SetExtent should return E_FAIL. This is always the case with linked objects, whose sizes are set by their link sources, not by their containers.

See Also

IAdviseSink::OnViewChange, IOleObject::GetExtent, IViewObject2::GetExtent


IOleObject::SetHostNames

Provides an object with the name of its container application and the compound document in which it is embedded.

HRESULT SetHostNames(

LPCOLESTR szContainerApp,	//Pointer to name of container application
LPCOLESTR szContainerObj	//Pointer to name of container document
);
Parameters

szContainerApp

[in] Points to the name of the container application in which the object is running.

szContainerObj

[in] Points to the name of the compound document that contains the object. If you do not wish to display the name of the compound document, you can set this parameter to NULL.

Return Value

S_OK

Window title information set successfully.

Comments

When a container initializes an embedded object, it calls this function to inform the object of the names of both the container application and container document. When the object is opened for editing, it displays these names in the title bar of its window.

Notes to Callers

Call SetHostNames only for embedded objects, because for linked objects, the link source supplies its own separate editing window and title bar information.

Notes to Implementors

An object's application of SetHostNames should include whatever modifications to its user interface may be appropriate to an object's embedded state. Such modifications typically will include adding and removing menu commands and altering the text displayed in the title bar of the editing window.

The complete window title for an embedded object in an SDI container application or an MDI application with a maximized child window should appear as follows:

<object application name> - <object short type> in <container document>

Otherwise, the title should be:

<object application name> − <container document>

The "object short type" refers to a form of an object's name short enough to be displayed in full in a list box.

Since these identifying strings are not stored as part of the persistent state of the object, IOleObject::SetHostNames must be called each time the object loads or runs.

See Also

IOleObject::GetUserType


IOleObject::SetMoniker

Notifies an object of its container's moniker, the object's own moniker relative to the container, or the object's full moniker.

HRESULT SetMoniker(

DWORD dwWhichMoniker,	//Value specifying moniker being set
IMoniker *pmk	//Pointer to moniker
);
Parameters

dwWhichMoniker

[in] Specifies which moniker is passed in pmk. Values are from the enumeration OLEWHICHMK.

pmk

[in] Points to where to return the moniker.

Return Values

S_OK

Moniker successfully set.

E_FAIL

No client site for object.

Comments

A container that supports links to embedded objects must be able to inform an embedded object when its moniker has changed. Otherwise, subsequent attempts by link clients to bind to the object will fail.The IOleObject::SetMoniker method provides one way for a container to communicate this information.

The container can pass either its own moniker, an object's moniker relative to the container, or an object's full moniker. In practice, if a container passes anything other than an object's full moniker, each object calls the container back to request assignment of the full moniker, which the object requires to register itself in the running object table.

The moniker of an object relative to its container is stored by the object handler as part of the object's persistent state. The moniker of the object's container, however, must not be persistently stored inside the object because the container can be renamed at any time.

Notes to Callers

A container calls IOleObject::SetMoniker when the container has been renamed, and the container's embedded objects currently or can potentially serve as link sources. Containers call SetMoniker mainly in the context of linking because an embedded object is already is aware of its moniker. Even in the context of linking, calling this method is optional because objects can call IOleClientSite::GetMoniker to force assignment of a new moniker.

Note to Implementors

Upon receiving a call to SetMoniker, an object should register its full moniker in the running object table and send OnRename notification to all advise sinks that exist for the object.

See Also

CreateItemMoniker, IAdviseSink::OnRename, IOleClientSite::GetMoniker, IOleObject::GetMoniker


IOleObject::Unadvise

Deletes a previously established advisory connection.

HRESULT Unadvise(

DWORD dwConnection	//A token
);
Parameter

dwConnection

[in] Contains a token of nonzero value, which was previously returned from IOleObject::Advise through its pdwConnection parameter.

Return Values

S_OK

Advisory connection deleted successfully.

E_FAIL

Unspecified error encountered.

OLE_E_NOCONNECTION

dwConnection is not represent a valid advisory connection.

Comments

Normally, containers call IOleObject::Unadvise at shutdown or when an object is deleted. In certain cases, containers can call this method on objects that are running but not currently visible as a way of reducing the overhead of maintaining multiple advisory connections. The easiest way to implement this method is to delegate the call to IOleAdviseHolder::Unadvise.

See Also

IOleObject::Advise, IOleObject::EnumAdvise, IOleAdviseHolder::Unadvise


IOleObject::Update

Updates an object handler's or link object's data or view caches.

HRESULT Update();

Return Values

S_OK

All caches are up to date.

E_FAIL

An unspecified error occurred.

OLE_E_CANT_BINDTOSOURCE

Cannot run object to get updated data. The object is for some reason unavailable to the caller.

CACHE_E_NOCACHE_UPDATED

No caches were updated.

CACHE_S_SOMECACHES_NOTUPDATED

Some caches were not updated.

Comments

The Update method provides a way for containers to keep data updated in their linked and embedded objects. A link object can become out-of-date if the link source has been updated. An embedded object that contains links to other objects can also become out of date. An embedded object that does not contain links cannot become out of date because its data is not linked to another source.

Notes to Implementors

When a container calls a link object's IOleObject::Update method, the link object finds the link source and gets a new presentation from it. This process may also involve running one or more object applications, which could be time-consuming.

When a container calls an embedded object's IOleObject::Update method, it is requesting the object to update all link objects it may contain. In response, the object handler recursively calls IOleObject::Update for each of its own linked objects, running each one as needed.

See Also

IOleObject::IsUpToDate


IOleUILinkContainer

The IOleUILinkContainer interface is implemented by containers and used by OLE common dialogs. It supports these dialogs by providing the methods needed to manage a container's links.

The IOleUILinkContainer methods enumerate the links associated with a container, and specify how they should be updated, automatically or manually. They change the source of a link and obtain information associated with a link. They also open a link's source document, update links, and break a link to the source.

When to Implement

You must implement this interface if you are creating a container application that will use the Links, Change Source, or Update Links dialogs, as well as the Object Properties dialog, which uses this interface indirectly. The Links dialog calls back to the container application to perform OLE functions that manipulate the links within the container.

When to Use

OLE common dialogs use only this interface to manage the properties of a container's links. They can also use it to manage non-OLE (DDE and other container-specific) links.

Methods in Vtable Order

IUnknown Methods	Description
QueryInterface	Returns a pointer to a specified interface.
AddRef	Increments the reference count.
Release	Decrements the reference count.
IOleUILinkContainer Methods	Description
GetNextLink	Enumerates the links in the container.
SetLinkUpdateOptions	Sets update options.
GetLinkUpdateOptions	Determines current update options for  the link.
SetLinkSource	Changes the source of the link.
GetLinkSource	Returns Links dialog information about the link.
OpenLinkSource	Opens a link's source.
UpdateLink	Forces a link to connect to its source and update.
CancelLink	Disconnects selected links.
See Also

OleUIEditLinks, OleUIChangeSource, OleUIUpdateLinks, OleUIObjectProperties, OLEUIEDITLINKS


IOleUILinkContainer::CancelLink

Disconnects the selected links.

HRESULT CancelLink(

DWORD dwLink	//Unique 32-bit link identifier
);
Parameter

dwLink

A container-defined unique 32-bit identifier for a single link. Containers can use the pointer to the link's container site for this value.

Return Values

S_OK

Successfully disconnected the selected links.

E_FAIL

Unable to disconnect the selected links.

E_INVALIDARG

One or more invalid arguments.

E_OUTOFMEMORY

Insufficient memory.

E_ACCESSDENIED

Insufficient access permissions.

Comments

Notes To Callers

Call CancelLink when the user selects the Break Link button from the Links dialog. The link should be converted to a picture. The Links dialog will not be dismissed for OLE links.

Notes To Implementors

For OLE links, OleCreateStaticFromData can be used to create a static picture object using the IDataObject interface of the link as the source.

See Also

IDataObject, OleCreateStaticFromData


IOleUILinkContainer::GetLinkSource

Returns information about a link that can be displayed in the UI.

HRESULT GetLinkSource(

DWORD dwLink,	//Unique 32-bit link identifier
LPTSTR FAR* lplpszDisplayName,	//Length of display name portion
ULONG FAR* lplenFileName,	//Length of filename portion
LPTSTR FAR* lplpszFullLinkType,	//Full link type string
LPTSTR FAR* lplpszShortLinkType,	//Short link type string
BOOL FAR* lpfSourceAvailable,	//Availability of link
BOOL FAR* lpfIsSelected	//Indicates that link entry should be selected in listbox
);
Parameters

dwLink

A container-defined unique 32-bit identifier for a single link. See IOleUILinkContainer::GetNextLink.

lplpszDisplayName

[out] Points to the allocated full link source display name string. The Links dialog will free this string.

lplenFileName

[out] Points to the length of the leading filename portion of the lplpszDisplayName string. If the link source is not stored in a file, then *lplenFileName should be 0. For OLE links, call IOleLink::GetSourceDisplayName.

lplpszFullLinkType

[out] Points to the allocated full link type string that is displayed at the bottom of the Links dialog. The Links dialog will free this string. For OLE links, this should be the full User Type name. Use IOleObject::GetUserType, specifying USERCLASSTYPE_FULL for dwFormOfType.

lplpszShortLinkType

[out] Points to the allocated short link type string that is displayed in the listbox of the Links dialog. The Links dialog will free this string. For OLE links, this should be the short User Type name. Use IOleObject::GetUserType, specifying USERCLASSTYPE_SHORT for dwFormOfType.

lpfSourceAvailable

Returns FALSE if it is known that a link is unavailable since the link is to some known but unavailable document. Certain options, such as Update Now, are disabled (grayed in the UI) for such cases.

lpfIsSelected

Used to tell the Edit Links dialog that this link's entry should be selected in the dialog's multi-slelection listbox. OleUIEditLinks calls this method at least once for each item to be placed in the links list. If none of them return TRUE, then none of them will be selected when the dialog is first displayed. If all of them return TRUE, then all will be displayed. That is, it returns TRUE if this link is currently part of the selection in the underlying document, FALSE if not. Any links that are selected in the underlying document are selected in the dialog; this way, the user can select a set of links and use the dialog to update them or change their source(s) simultaneously.

Return Values

S_OK

Successfully returned link information.

E_FAIL

Unable to return link information.

E_INVALIDARG

One or more invalid arguments.

E_OUTOFMEMORY

Insufficient memory.

E_ACCESSDENIED

Insufficient access permissions.

Comments

Notes To Callers

Call this method during dialog initialization, after returning from the Change Source dialog.

See Also

IOleLink::GetSourceDisplayName, IOleObject::GetUserType, USERCLASSTYPE, OleUIChangeSource, OLEUICHANGESOURCE


IOleUILinkContainer::GetLinkUpdateOptions

Determine the current update options for a link.

HRESULT GetNextLink(

DWORD dwLink,	//Unique 32-bit link identifier
DWORD FAR * lpdwUpdateOpt	//Address to return update option
);
Parameters

dwLink

A container-defined unique 32-bit identifier for a single link. See IOleUILinkContainer::GetNextLink.

lpdwUpdateOpt

The address to return the current update options.

Return Values

S_OK

Successfully determined update options.

E_FAIL

Unable to determine update options.

E_INVALIDARG

One or more invalid arguments.

E_OUTOFMEMORY

Insufficient memory.

E_ACCESSDENIED

Insufficient access permissions.

Comment

Notes To Implementors

Containers can implement this method for OLE links simply by calling IOleLink::SetUpdateOptions on the link object.

See Also

IOleUILinkContainer::GetNextLink, IOleUILinkContainer::SetLinkUpdateOptions, IOleLink::SetUpdateOptions


IOleUILinkContainer::GetNextLink

Enumerates the links in a container.

DWORD GetNextLink(

DWORD dwLink	//Unique 32-bit link-identifier, indicating the current link
);
Parameter

dwLink

A container-defined unique 32-bit identifier for a single link. This value is only passed to other methods on this interface, so it can be any value that uniquely identifies a link to the container. Containers frequently use the pointer to the link's container site object for this value.

Return Values

Returns a container's link identifiers in sequence; NULL if it has returned the last link.

Notes to Callers

Call this method to enumerate the links in a container. If the value passed in dwLink is NULL, then the container should return the first link's 32-bit identifier. If dwLink identifies the last link in the container, then the container should return NULL.

See Also

IOleUILinkContainer::SetLinkUpdateOptions, IOleUILinkContainer::GetLinkUpdateOptions


IOleUILinkContainer::OpenLinkSource

Opens the link's source.

HRESULT OpenLinkSource(

DWORD dwLink	//Unique 32-bit link identifier
);
Parameter

dwLink

A container-defined unique 32-bit identifier for a single link. Containers can use the pointer to the link's container site for this value.

Return Values

S_OK

Successfully opened the link's source.

E_FAIL

Unable to open the links source.

E_INVALIDARG

One or more invalid arguments.

E_OUTOFMEMORY

Insufficient memory.

E_ACCESSDENIED

Insufficient access permissions.

Comments

Notes To Callers

The OpenLinkSource method is called when the Open Source button is selected from the Links dialog. For OLE links, call IOleObject::DoVerb, specifying OLEIVERB_SHOW for iVerb.

See Also

IOleObject::DoVerb, OLEVERB


IOleUILinkContainer::SetLinkSource

Changes the source of a link.

HRESULT SetLinkSource(

DWORD dwLink,	//Unique 32-bit link identifier
LPTSTR lpszDisplayName,	//Source string to parse
ULONG FAR* lenFileName,	//The length of the filename portion
ULONG FAR* pchEaten,	//Number of characters successfully parsed
BOOL fValidateSource	//Specifies whether or not moniker should be validated
);
Parameters

dwLink

A container-defined unique 32-bit identifier for a single link. See IOleUILinkContainer::GetNextLink .

lpszDisplayName

Points to new source string to be parsed.

lenFileName

The length of the leading filename portion of the lpszDisplayName string. If the link source is not stored in a file, then lenFileName should be 0. For OLE links, call IOleLink::GetSourceDisplayName.

pchEaten

[out] Points to the number of characters successfully parsed in lpszDisplayName.

fValidateSource

TRUE if the moniker should be validated; for OLE links, MkParseDisplayName should be called. FALSE if the moniker should not be validated. If possible, the link should accept the unvalidated source, and mark itself as unavailable.

Return Values

S_OK

Successfully changed the links source.

E_FAIL

Unable to change the links source.

E_INVALIDARG

One or more invalid arguments.

E_OUTOFMEMORY

Insufficient memory.

E_ACCESSDENIED

Insufficient access permissions.

Comments

Notes To Callers

Call this method from the Change Source dialog, with fValidateSource initially set to TRUE. Change Source can be called directly or from the Links dialog. If this call to SetLinkSource returns an error (e.g., MkParseDisplayName failed because the source was unavailable), then you should display an Invalid Link Source message, and the user should be allowed to decide whether or not to fix the source. If the user chooses to fix the source, then the user should be returned to the Change Source dialog with the invalid portion of the input string highlighted. If the user chooses not to fix the source, then SetLinkSource should be called a second time with fValidateSource set to FALSE, and the user should be returned to the Links dialog with the link marked Unavailable.

See Also

MkParseDisplayName


IOleUILinkContainer::SetLinkUpdateOptions

Sets a link's update options to Automatic (OLEUPDATE_ALWAYS) or Manual (OLEUPDATE_ONCALL).

HRESULT SetLinkUpdate(

DWORD dwLink,	//Unique 32-bit link identifier
DWORD dwUpdateOpt	//Update options
);
Parameters

dwLink

A container-defined unique 32-bit identifier for a single link. See IOleUILinkContainer::GetNextLink.

dwUpdateOpt

Specifies the update options, which can be Automatic (OLEUPDATE_ALWAYS) or Manual (OLEUPDATE_ONCALL).

Return Values

S_OK

Successfully set the links update options.

E_FAIL

Unable to set the links update options.

E_INVALIDARG

One or more invalid arguments.

E_OUTOFMEMORY

Insufficient memory.

E_ACCESSDENIED

Insufficient access permissions.

Comments

The user selects update options from the Links dialog.

Notes To Implementors

Containers can implement this method for OLE links by simply calling IOleLink::SetUpdateOptions on the link object.

See Also

IOleUILinkContainer::GetNextLink, IOleUILinkContainer::GetLinkUpdateOptions, IOleLink::SetUpdateOptions


IOleUILinkContainer::UpdateLink

Forces selected links to connect to their source and retrieve current information.

HRESULT UpdateLink(

DWORD dwLink,	//Link identifier
DWORD fErrorMessage,	//Determines whether or not caller should display error message
DWORD fReserved	//Reserved for future use
);
Parameters

dwLink

A container-defined unique 32-bit identifier for a single link. Containers can use the pointer to the link's container site for this value.

fErrorMessage

Determines whether or not the caller (implementor of IOleUILinkContainer) should show an error message upon failure to update a link. The Update Links dialog sets this to FALSE. The Object Properties and Links dialogs set it to TRUE.

fReserved

Reserved for future use. Currently, this parameter should always be set to FALSE.

Return Values

S_OK

Successfully updated linked objects.

E_FAIL

Unable to update linked objects.

E_INVALIDARG

One or more invalid arguments.

E_OUTOFMEMORY

Insufficient memory.

E_ACCESSDENIED

Insufficient access permissions.

Comments

Notes To Callers

Call this method with fErrorMessage set to TRUE in cases where the user expressly presses a button to have a link updated, that is, presses the Links' Update Now button. Call it with FALSE in cases where the container should never display an error message, that is, where a large set of operations are being performed and the error should be propagated back to the user later, as might occur with the Update links progress meter. Rather than providing one message for each failure, assuming there are failures, provide a single message for all failures at the end of the operation.

Notes To Implementors

For OLE links, call IOleObject::Update.

See Also

IOleObject::Update


IOleUILinkInfo

IOleUILinkInfo is an extension of the IOleUILinkContainer interface. It returns the time that an object was last updated, which is link information that IOleUILinkContainer does not provide.

When To Implement

You must implement this interface so your container can support the "Link" page of the Object Properties dialog. If you are writing a container that does not implement links, you do not need to implement this interface.

Methods in Vtable Order

IUnknown Methods	Description
QueryInterface	Returns a pointer to a specified interface.
AddRef	Increments the reference count.
Release	Decrements the reference count.
IOleUILinkContainer Methods	Description
GetNextLink	Enumerates the links in the container.
SetLinkUpdateOptions	Sets update options.
GetLinkUpdateOptions	Determines current update options for  the link.
SetLinkSource	Changes the source of the link.
GetLinkSource	Returns Links dialog information about link.
OpenLinkSource	Opens a link's source.
UpdateLink	Forces a link to connect to its source and update.
CancelLink	Breaks the link.
IOleUILinkInfo Methods	Description
GetLastUpdate	Determines the last time the object was updated, whether automatically or manually.


IOleUILinkInfo::GetLastUpdate

Indicates when the object was last updated.

HRESULT GetLastUpdate(

DWORD dwLink,	//Object's identifier
FILETIME FAR * lpLastUpdate	//Time object was last updated
);
Parameters

dwLink

A container-defined unique 32-bit identifier for a single link. Containers can use the pointer to the link's container site for this value.

lpLastUpdate

Points to the time that the object was last updated.

Return Values

S_OK

Successfully returned link information.

E_FAIL

Unable to return link information.

E_INVALIDARG

One or more invalid arguments.

E_OUTOFMEMORY

Insufficient memory.

E_ACCESSDENIED

Insufficient access permissions.

Comment

Notes To Implementors

If the time that the object was last updated is known, copy it to *lpLastUpdate. If it is not known, then leave *lpLastUpdate unchanged and Unknown will be displayed in the link page.


IOleUIObjInfo

This interface is implemented by containers and used by the container's Object Properties dialog and by the Convert dialog. It provides information used by the General and View pages of the Object Properties dialog, which display information about the object's size, location, type, and name. It also allows the object to be converted via the Convert dialog. The View page allows the object's icon to be modified from its original form, and its display aspect to be changed (iconic versus content). Optionally, you can have your implementation of this interface allow the scale of the object to be changed.

When To Implement

You must implement this interface so your container application can support the OleUIObjectProperties function and the dialog that it implements.

When To Use

Use this interface when you need to get and set information required by the Object Properties dialog, and to support the Convert dialog.

Methods in Vtable Order

IUnknown Methods	Description
QueryInterface	Returns a pointer to a specified interface.
AddRef	Increments the reference count.
Release	Decrements the reference count.
IOleUILinkContainer Methods	Description
GetNextLink	Enumerates the links in the container.
SetLinkUpdateOptions	Sets update options.
GetLinkUpdateOptions	Determines current update options for the link.
SetLinkSource	Changes the source of the link.
GetLinkSource	Returns Links dialog information about link.
OpenLinkSource	Opens a link's source.
UpdateLink	Forces a link to connect to its source and update.
CancelLink	Breaks the link.
IOleUIObjInfo Methods	Description
GetObjectInfo	Gets general information about the object.
GetConvertInfo	Gets information that is used for the Convert dialog.
ConvertObject	Converts the object once the user selects a destination type.
GetViewInfo	Gets the current icon, aspect, and scale of the object.
SetViewInfo	Sets the current icon, aspect, and scale of the object.
See Also

OleUIObjectProperties


IOleUIObjInfo::ConvertObject

Converts the object to the type of the new CLSID.

HRESULT ConvertObject(

DWORD dwObject,	//32-bit object identifier
REFCLSID clsidNew	//CLSID to convert the object to
);
Parameters

dwObject

A unique 32-bit identifier for the object.

clsidNew

The CLSID to convert the object to.

Return Values

S_OK

Successfully returned link information.

E_FAIL

Unable to return link information.

E_INVALIDARG

One or more invalid arguments.

E_OUTOFMEMORY

Insufficient memory.

E_ACCESSDENIED

Insufficient access permissions.

Comment

Notes To Implementors

Your implementation of ConvertObject needs to convert the object to the CLSID specified. The actions taken by the convert operation are similar to the actions taken after calling OleUIConvert.

See Also

OleUIConvert


IOleUIObjInfo::GetConvertInfo

Gets the conversion information associated with the specified object.

HRESULT GetConvertInfo(

DWORD dwObject,	//32-bit object identifier
CLSID FAR * lpClassID,	//CLSID of the object
WORD FAR *lpwFormat,	//CLIPFORMAT of the object's storage
CLSID FAR * lpConvertDefaultClassID,	//Default class to convert to
LPCLSID FAR * lplpClsidExclude,	//Excluded CLSIDs
UINT FAR * lpcClsidExclude	//Number of CLSIDs in lplpClsidExclude
);
Parameters

dwObject

A unique 32-bit identifier for the object.

lpClassID

[out] Points to the location to return the object's CLSID.

lpwFormat

[out] Points to the clipboard format of the object.

lpConvertDefaultClassID

[out] Points to the default class, selected from the UI, to convert the object to.

lplpClsidExclude

[out] Points to to an array of CLSIDs that should be excluded from the UI for this object. May be NULL, if lplpClsidExclude is 0 (zero).

lpcClsidExclude

[out] The number of CLSIDs in lplpClsidExclude. May be 0 (zero).

Return Values

S_OK

Successfully returned link information.

E_FAIL

Unable to return link information.

E_INVALIDARG

One or more invalid arguments.

E_OUTOFMEMORY

Insufficient memory.

E_ACCESSDENIED

Insufficient access permissions.

Comment

Notes To Implementors

You must fill in the CLSID of the object at a minimum. lpwFormat may be left at zero if the format of the storage is unknown.


IOleUIObjInfo::GetObjectInfo

Gets size, type, name and location information about an object.

HRESULT GetObjectInfo(

DWORD dwObject,	//32-bit object identifier
DWORD FAR *lpdwObjSize,	//Points to object's size
LPTSTR FAR *lplpszLabel,	//Points to object's label.
LPTSTR FAR * lplpszType,	//Points to object's "long" type
LPTSTR FAR * lplpszShortType,	//Points to object's "short" type
LPTSTR FAR * lplpszLocation	//Points to the objects source
);
Parameters

dwObject

A unique 32-bit identifier for the object.

lpdwObjSize

[out] The object's size, in bytes, on disk. This may be an approximate value.

lplpszLabel

[out] Points to the object's label. May be NULL, which indicates that the implementation should not fill this in.

lplpszType

[out] Points to the object's "long" type. May be NULL, which indicates that the implementation should not fill this in.

lplpszShortType

[out] Points to the object's "short" type. May be NULL, which indicates that the implementation should not fill this in.

lplpszLocation

[out] Points to the object's source. May be NULL, which indicates that the implementation should not fill this in.

Return Values

S_OK

Successfully returned object information.

E_FAIL

Unable to get object information.

E_INVALIDARG

One or more invalid arguments.

E_OUTOFMEMORY

Insufficient memory.

Comment

The strings and the object's size are displayed in the object properties "General" page.

Notes To Implementors

Your implementation of GetObjectInfo should place each of the object's attributes in the out parameters provided. Set lpdwObjSize to (DWORD)-1 when the size of the object is unknown. Allocate all strings (the rest of the params) with the OLE task allocator obtained via CoGetMalloc, as is standard for all OLE interfaces with [out] string parameters, or you can simply use CoTaskMemAlloc.

See Also

CoGetMalloc, CoTaskMemAlloc


IOleUIObjInfo::GetViewInfo

Gets the view information associated with the object.

HRESULT GetViewInfo(

DWORD dwObject,	//32-bit object identifier
HGLOBAL FAR * phMetaPict,	//Object's current icon
DWORD * pdvAspect,	//Object's current aspect
int * pnCurrentScale	//Object's current scale
);
Parameters

dwObject

A 32-bit identifier for the object.

phMetaPict

The object's current icon. Could be NULL, indicating that the caller is not interested in the object's current presentation.

pdvAspect

The object's current aspect. Could be NULL, indicating that the caller is not interested in the object's current aspect, i.e., DVASPECT_ICONIC or DVASPECT_CONTENT.

pnCurrentScale

The object's current scale. Could be NULL, indicating that the caller is not interested in the current scaling factor applied to the object in the container's view.

Return Values

S_OK

Successfully returned link information.

E_FAIL

Unable to return link information.

E_INVALIDARG

One or more invalid arguments.

E_OUTOFMEMORY

Insufficient memory.

E_ACCESSDENIED

Insufficient access permissions.

Comment

Notes To Implementors

You must fill in the object's current icon, aspect, and scale.

See Also

OLEUIVIEWPROPS


IOleUIObjInfo::SetViewInfo

Sets the view information associated with the object.

HRESULT SetViewInfo(

DWORD dwObject,	//32-bit object identifier
HGLOBAL hMetaPict,	//New icon for the object
DWORD dvAspect,	//New display aspect
int nCurrentScale,	//New scale
BOOL bRelativeToOrig	//Scale relative to origin
);
Parameters

dwObject

A 32-bit identifier for the object.

hMetaPict

The new icon for the object.

dvAspect

The object's new display aspect or view.

nCurrentScale

The object's new scale.

bRelativeToOrig

The scale of the object, relative to the origin. This value is TRUE if the new scale should be relative to the original scale of the object. If FALSE, nCurrentScale applies to the object's current size.

Return Values

S_OK

Successfully returned link information.

E_FAIL

Unable to return link information.

E_INVALIDARG

One or more invalid arguments.

E_OUTOFMEMORY

Insufficient memory.

E_ACCESSDENIED

Insufficient access permissions.

Comment

Notes To Implementors

You should apply the new attributes (icon, aspect, and scale) to the object. If bRelativeToOrig is set to TRUE, nCurrentScale (in percentage units) applies to the original size of the object before it was scaled. If bRelativeToOrig is FALSE, nCurrentScale applies to the object's current size.

See Also

DVASPECT


IOleWindow

The IOleWindow interface methods allow an application to obtain the handle to the various windows that participate in in-place activation, and also to enter and exit context-sensitive help mode.

Five other in-place activation interfaces are derived from the IOleWindow interface. Containers and objects must implement and use these six interfaces in order to support in-place activation. The following table briefly summarizes each of these interfaces:

IOleWindow	The base interface. Implemented and used by containers and objects to window handles and manage context-sensitive help.
IOleInPlaceObject	Implemented by objects and used by an object's immediate container to activate and deactivate the object.
IOleInPlaceActiveObject	Implemented by objects and used by the top-level container to manipulate the object while it is active. Provides a direct channel of communication between an active object and its frame and document windows.
IOleInPlaceUIWindow	Implemented by containers and used by objects to manipulate the container's document window.
IOleInPlaceFrame	Implemented by containers and used by objects to control the container's frame window.
IOleInPlaceSite	Implemented by containers and used by objects to interact with the in-place client site.
These interfaces can be arranged in three hierarchical levels with various interfaces implemented at each level. Calls that install user-interface menus and frame adornments, activate and switch between windows, and dispatch menu and keystrokes take place between the top-level container and the active object. Calls that support activating, deactivating, scrolling, or clipping span the containment hierarchy, with each level performing the correct actions.

When to Implement

The inherited methods of this interface are implemented by all in-place objects and containers.

When to Use

Use this interface to obtain the window handle to the windows associated with in-place activation (frame, document, parent, and in-place object). It is also used to enter and exit context-sensitive help.

Methods in VTable Order

IUnknown Methods	Description
QueryInterface	Returns a pointer to a specified interface.
AddRef	Increments the reference count.
Release	Decrements the reference count.
IOleWindow Methods	Description
GetWindow	Gets a window handle.
ContextSensitiveHelp	Controls enabling of context sensitive help.
See Also

IOleInPlaceObject, IOleInPlaceActiveObject, IOleInPlaceUIWindow, IOleInPlaceFrame, IOleInPlaceSite, OleCreateMenuDescriptor, OleDestroyMenuDescriptor, OleTranslateAccelerator


IOleWindow::ContextSensitiveHelp

Determines whether context-sensitive help mode should be entered during an in-place activation session.

HRESULT ContextSensitiveHelp(

BOOL fEnterMode	//Specifies whether or not to enter help mode
);
Parameter

fEnterMode

[in] Specifies TRUE if help mode should be entered; FALSE if it should be exited.

Return Values

S_OK

The help mode was entered or exited successfully, depending on the value passed in fEnterMode.

E_OUTOFMEMORY

Out of memory.

E_INVALIDARG

The argument is invalid.

E_UNEXPECTED

An unexpected error occurred.

Comments

Applications can invoke context-sensitive help when the user

•	presses SHIFT+F1, then clicks a topic

•	presses F1 when a menu item is selected.

When SHIFT+F1 is pressed, either the frame or active object can receive the keystrokes. If the container's frame receives the keystrokes, it calls its containing document's IOleWindow::ContextSensitiveHelp method with fEnterMode set to TRUE. This propagates the help state to all of its in-place objects so they can correctly handle the mouse click or WM_COMMAND.

If an active object receives the SHIFT+F1 keystrokes, it calls the container's IOleInPlaceSite::ContextSensitiveHelp method with fEnterMode TRUE, which then recursively calls each of its in-place sites until there are no more to be notified. The container then calls its document's or frame's ContextSensitiveHelp method with fEnterMode TRUE.

When in context-sensitive help mode, an object that receives the mouse click can either:

1.	Ignore the click if it does not support context-sensitive help, or

2.	Tell all the other objects to exit context-sensitive help mode with ContextSensitiveHelp set to FALSE and then provide help for that context.

An object in context-sensitive help mode that receives a WM_COMMAND should tell all the other in-place objects to exit context-sensitive help mode and then provide help for the command.

If a container application is to support context-sensitive help on menu items, it must either provide its own message filter so that it can intercept the F1 key or ask the OLE library to add a message filter by calling OleSetMenuDescriptor, passing valid, non-NULL values for the lpFrame and lpActiveObj parameters.

See Also

OleSetMenuDescriptor


IOleWindow::GetWindow

Returns the window handle to one of the windows participating in in-place activation (frame, document, parent, or in-place object window).

HRESULT GetWindow(

HWND * phwind	//Where to return window handle
);
Parameter

phwnd

[out] Points to where to return the window handle.

Return Values

S_OK

The window handle was successfully returned.

E_INVALIDARG

One or more arguments are invalid.

E_OUTOFMEMORY

Out of memory.

E_UNEXPECTED

An unexpected error occurred.

E_FAIL

There is no window handle currently attached to this object.

Comments

Five types of windows comprise the windows hierarchy. When a object is active in place, it has access to some or all of these windows:

Window	Description
Frame	The outermost main window where the container application's main menu resides.
Document	The window that displays the compound document containing the embedded object to the user.
Pane	The subwindow of the document window that contains the object's view. Applicable only for applications with split-pane windows.
Parent	The container window that contains that object's view. The object application installs its window as a child of this window.
In-place	The window containing the active in-place object. The object application creates this window and installs it as a child of its hatch window, which is a child of the container's parent window.
Each type of window has a different role in the in-place activation architecture. However, it is not necessary to employ a separate physical window for each type. Many container applications use the same window for their frame, document, pane, and parent windows.


IParseDisplayName

The IParseDisplayName interface parses a human-readable display name string to convert it into a moniker. Display name parsing is necessary when the end user inputs a string to identify a component, as in the following situations:

•	A compound document application that supports linked components typically supports the Edit:Links... dialog. Through this dialog, the end user can enter a display name to specify a new link source for a specified linked component. The compound document needs to have this input string converted into a moniker.

•	A script language such as the macro language of a spreadsheet can allow textual references to a component. The language's interpreter needs to have such a reference converted into a moniker in order to execute the macro.

When to Implement

Compound document applications that support links to embedded components or to pseudo-objects within their documents must provide an implementation of the IOleItemContainer interface, which is derived indirectly from IParseDisplayName. In effect, such a compound document is providing a namespace for identifying its internal components; and its IOleItemContainer implementation (which includes the IParseDisplayName implementation) is the interface through which another application can access this namespace. Alternatively, the compound document application can implement IParseDisplayName as part of its class object, which is accessible through the CoGetClassObject function.

When to Use

If you are implementing your own moniker class, you might need to use this interface from your implementation of IMoniker::ParseDisplayName. If you call the MkParseDisplayName function, you are indirectly using IParseDisplayName.

Methods in VTable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments reference count.
Release	Decrements reference count.
IParseDisplayName Method	Description
ParseDisplayName
See Also

IMoniker::ParseDisplayName, IOleItemContainer, MkParseDisplayName


IParseDisplayName::ParseDisplayName

Parses the display name to extract a component of the string that it can convert into a moniker, using the maximum number of characters from the lefthand side of the string.

HRESULT ParseDisplayName(

IBindCtx *pbc,	//Pointer to bind context
LPOLESTR pszDisplayName,	//Pointer to string containing display name
ULONG *pchEaten,	//Length, in characters, of display name
IMoniker **ppmkOut	//Pointer to moniker that results
);
Parameters

pbc

[in] Points to the bind context to be used in this binding operation.

pszDisplayName

[in] Points to a zero-terminated string containing the display name to be parsed. For Win32 applications, the LPOLESTR type indicates a wide character string (two bytes per character); otherwise, the string has one byte per character.

pchEaten

[out] Receives the number of characters in the display name that correspond to the ppmkOut moniker.

ppmkOut

[out] Receives a pointer to the resulting moniker. If an error occurs, the implementation sets *ppmkOut to NULL. If *ppmkOut is non-NULL, the implementation must call (*ppmkOut)->IUnknown::AddRef; so it is the caller's responsibility to call (*ppmkOut)->IUnknown::Release.

Return Values

S_OK

Indicates success.

MK_E_SYNTAX

Indicates a syntax error in the display name.

MK_E_NOOBJECT

Indicates that the display name does not identify a component in this namespace.

E_UNEXPECTED

Indicates an unexpected error.

E_OUTOFMEMORY

Indicates insufficient memory.

See Also

MkParseDisplayName, IMoniker::ParseDisplayName


IPersist

The IPersist interface is the base interface for three other persistence-related interfaces: IPersistStorage, IPersistStream, and IPersistFile. These three interfaces are offered by objects that can serialize themselves to a storage, stream, or file. That is, they can save their state for later instantiations, and they can load their saved state, thus transitioning from a passive to a running state.

Typically, the persistence interfaces are implemented by an embedded or linked object. The container application or the default object handler calls the methods in one of the persistence interfaces to have the object save or load itself. Thus, the object that offers a persistence interface can change itself to an active or running state by request of its container application or its object handler.

The IPersist interface is the base from which the other persistence interfaces are derived. Its one method returns the class identifier (CLSID) of an object that implements one of the other persistence interfaces.

When to Implement

You must implement the IPersist interface whenever you implement any one of the other persistence interfaces: IPersistStorage, IPersistStream, or IPersistFile. Typically, embedded objects implement the IPersistStorage interface; linked objects implement the IPersistFile interface; and new moniker classes implement the IPersistStream interface.

When to Use

The IPersist interface is used primarily by the default object handler to get the class identifier of an embedded object. Typically, container applications would not call the IPersist interface unless they provide object handlers for specific classes of objects.

Methods in Vtable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments the reference count.
Release	Decrements the reference count.
IPersist Method	Description
GetClassID	Returns the class identifier (CLSID) for the component object.


IPersist::GetClassID

Returns the class identifier (CLSID) the component object. The CLSID is a unique value that identifies the application that can manipulate the component object data.

HRESULT GetClassID(

CLSID *pClassID	//Pointer to CLSID of component object
);
Parameter

pClassID

[out]Points to the location where the CLSID is returned. The CLSID is a globally unique identifier (GUID) that uniquely represents an object class.

Return Values

S_OK

The CLSID was successfully returned.

E_FAIL

The CLSID could not be returned.

Comments

This method returns the class identifier (CLSID) for an object, used in later operations to load object-specific code into the caller's context.

Notes to Callers

Most container applications have no need to call the IPersist::GetClassID method directly. A container application might use this method when the container needs to change the CLSID and save the new CLSID for the component object. For example, if the container is treating a component as a different class and an editing operation occurs so that the component object can no longer be edited by its original application. In this case, the container needs to change the CLSID for the component. Typically, in this case, the container calls the OleSave helper function which performs all the necessary steps.

The exception would be a container that provides an object handler for certain component objects. In particular, a container application should not get a component object CLSID and then use it to retrieve class specific information from the registry. Instead, the container should use IOleObject and IDataObject interfaces to retrieve such class-specific information directly from the object.

Notes to Implementors

Typically, a component object simply returns a constant CLSID in its implementation of this method. This is not the case, however, if your component object supports "Treat As" operations in which it edits other classes of components as if they were its own class. If your object is running a component of another class, your implementation of IPersist::GetClassID must return the CLSID stored in the component storage.

The implementation of IPersist::GetClassID in the default object handler passes the call to the implementation in the component object if the component object is running. Otherwise, the default handler calls the ReadClassStg function to read the CLSID that is saved in the component object storage.

If you are writing a custom object handler for your component, you might want to simply delegate this method to the default handler implementation (see OleCreateDefaultHandler).

See Also

IDataObject::EnumFormatEtc, IOleObject::EnumVerbs, IOleObject::GetMiscStatus, IOleObject::GetUserType, OleCreateDefaultHandler, ReadClassStg


IPersistFile

The IPersistFile interface provides methods for an object to load and save itself in a disk file, instead of saving itself to a storage object. Because the information needed to open a file varies greatly from one application to another, the object must be responsible for opening its disk file.

When to Implement

The IPersistFile interface is implemented by any object or container application that can be linked through a file moniker, including the following:

•	Any object that supports links to its files or to pseudo-objects within its files

•	A container application that supports links to component objects within its compound file

Typically, you implement the IPersistFile interface as part of an aggregate object that includes other interfaces that are appropriate for the type of moniker binding that is supported.

For example, in either of the cases mentioned above, the moniker for the linked object can be a composite moniker. In the first case, a composite moniker identifies the pseudo-object contained within the file. In the second case, a composite moniker identifies the embedded object contained within the compound file. In either case of composite monikers, you must implement the IPersistFile interface as part of same object that also implements the IOleItemContainer interface. Then, when the application for the linked object is run, OLE queries for the IOleItemContainer interface to locate the embedded object or the pseudo-object contained in the file.

As another example, if the moniker is a simple file moniker (i.e., the link is to the entire file), OLE queries for the interface that the initiator of the bind operation requested. Typically, this is one of the compound document interfaces, such as IOleObject, IDataObject, or IPersistStorage.

When to Use

You call methods in the IPersistFile interface to load or save a linked component object in a specified file.

When the application for the linked object is run, OLE calls the IPersistFile::Load method. Once the file is loaded, OLE calls IPersistFile::QueryInterface to get another interface pointer to the loaded object. The IPersistFile interface is typically part of an aggregate object that offers other interfaces.

Note that OLE calls only the IPersistFile::Load method. It does not call any of the other IPersistFile methods. Typically, applications do not call these methods either. The IPersistFile::Load method enables OLE to load a file on behalf of a container application when the container needs to run the application for the linked object. The other IPersistFile methods support saving a component to a file, but container applications do not tell a linked object to save itself. It is entirely up to the end user and the application for the linked object to decide when the component should be saved. This differs from the situation for an embedded component, in which the container application uses the IPersistStorage interface to provide the storage and to tell the component when to save itself.

Methods in Vtable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments the reference count.
Release	Decrements the reference count.
IPersistFile Methods	Description
IsDirty	Checks an object for changes since it was last saved to its current file.
Load	Opens the specified file and initializes an object from the file contents.
Save	Saves the object into the specified file.
SaveCompleted	Notifies the object that it can revert from NoScribble mode to Normal mode.
GetCurFile	Gets the current name of the file associated with the component.


IPersistFile::GetCurFile

Returns either the absolute path to the object's current working file or, if there is no current working file, the object's default save prompt .

HRESULT GetCurFile(

LPOLESTR *ppszFileName	//Pointer to the path for the current file or the default save prompt
);
Parameter

ppszFileName

[out]Points to a zero-terminated string containing the path for the current file or the default save prompt. If an error occurs, *ppszFileName is set to NULL.

Return Values

S_OK

A valid absolute path was successfully returned.

S_FALSE

The default save prompt was returned.

E_OUTOFMEMORY

The operation failed due to insufficient memory.

E_FAIL

The operation failed due to some reason other than insufficient memory.

Comments

This method returns the current filename or the default save prompt for the object.

This method allocates memory for the string returned in the ppszFileName parameter using the IMalloc::Alloc method. The caller is responsible for calling the IMalloc::Free method to free the string. Both the caller and this method use the allocator returned by CoGetMalloc(MEMCTX_TASK, ...).

The LPOLESTR type indicates a wide character string (two bytes per character); otherwise, the string has one byte per character.

The filename returned in ppszFileName is the name specified in the IPersistFile::Load method when the document was loaded; or in IPersistFile::SaveCompleted if the document was saved to a different file.

If the object does not have a current working file, it should return the default filename prompt that it would display in a "Save As" dialog. For example, the default save prompt for a word processor object could be:

*.txt

Notes to Callers

OLE does not call the IPersistFile::GetCurFile method. Typically, applications do not either.

If you want to perform a "Save" operation on the object, you can call this method before calling IPersistFile:Save to determine whether the object has an associated file. If this method returns S_OK, you can then call IPersistFile::Save with a NULL filename and a TRUE value for the fRemember parameter to tell the object to save itself to its current file. If this method returns S_FALSE, you can use the save prompt returned in the ppszFileName parameter to ask the end user to provide a filename. Then, you can call IPersistFile::Save with the filename that the user entered to perform a "Save As" operation.

See Also

IPersistFile::Load, IPersistFile::Save, IPersistFile::SaveCompleted


IPersistFile::IsDirty

Checks an object for changes since it was last saved to its current file.

HRESULT IsDirty(void);

Return Values

S_OK

The object has changed since it was last saved.

S_FALSE

The object has not changed since the last save.

Comments

This method checks whether an object has changed since it was last saved so you can avoid losing information in objects that have not yet been saved. The dirty flag for an object is conditionally cleared in the IPersistFile::Save method.

Notes to Callers

OLE does not call IPersistFile::IsDirty. Typically, applications do not either.

You should treat any error return codes as an indication that the object has changed. In other words, unless this method explicitly returns S_FALSE, you must assume that the object needs to be saved.

Notes to Implementors

An object with no contained objects simply checks its dirty flag to return the appropriate result.

A container object with one or more contained objects must maintain an internal dirty flag that reflects any one contained object being dirty. To do this, the container object should register for data change notifications with each link or embedding (see IDataObject::DAdvise). Then, the container can maintain its internal dirty flag that it sets when it receives an IAdviseSink::OnDataChange notification. If the container does not register for data change notifications, the IPersistFile::IsDirty implementation must call IPersistStorage::IsDirty for each of its contained objects to determine whether they have changed.

The container object can clear its dirty flag whenever it is saved, as long as the file saved to is the current working file after the save. In other words, the dirty flag is cleared after a successful "Save" or "Save As" operation, but not after a "Save A Copy As . . ." operation.

See Also

IAdviseSink::OnDataChange, IDataObject::DAdvise, IPersistStorage::IsDirty


IPersistFile::Load

Opens the specified file and initializes an object from the file contents.

HRESULT Load(

LPCOLESTR pszFileName,	//Pointer to absolute path of the file to open
DWORD dwMode	//Specifies the access mode from the STGM enumeration
);
Parameters

pszFileName

[in]Points to a zero-terminated string containing the absolute path of the file to open.

dwMode

[in]Specifies some combination of the values from the STGM enumeration to indicate the access mode to use when opening the file. The IPersistFile::Load method can treat this value as a suggestion, adding more restrictive permissions if necessary. If dwMode is zero, the implementation should open the file using whatever default permissions are used when a user opens the file.

Return Values

S_OK

The object was successfully loaded.

E_NOMEMORY

The object could not be loaded due to a lack of memory.

E_FAIL

The object could not be loaded for some reason other than a lack of memory.

IPersistFile::Load STG_E_* error codes.

Comments

This method loads the object from the specified file. This method is for initialization only and does not show the object to the end user; it is not equivalent to the end user selecting the File Open command.

Notes to Callers

The BindToObject method in file monikers calls this method to load an object during a moniker binding operation, that is, when the linked object is run.

Typically, applications do not call this method directly.

Notes to Implementors

Because the information needed to open a file varies greatly from one application to another, the object that implements this method must also open the file specified by the pszFileName parameter. Note that this differs from the IPersistStorage::Load and IPersistStream::Load in which the caller opens the storage or stream and then passes an open storage or stream pointer to the loaded object.

If your application normally uses the OLE-provided compound files, then your IPersistFile::Load implementation can simply call the StgOpenStorage helper API function to open the storage object in the specified file. Then, you can proceed with the normal document initialization. Applications that do not use storage objects can perform their normal file opening procedures.

When the document has been loaded, your implementation should register the document object in the Running Object Table (see IRunningObjectTable::Register).

See Also

IRunningObjectTable::Register, StgOpenStorage


IPersistFile::Save

Saves a copy of the object into the specified file.

HRESULT Save(

LPCOLESTR pszFileName,	//Pointer to absolute path of the file where the object is saved
BOOL fRemember	//Specifies whether the file is to be the current working file or not
);
Parameters

pszFileName

[in]Points to a zero-terminated string containing the absolute path of the file to which the object should be saved. If pszFileName is NULL, the object should save its data to the current file, if there is one.

fRemember

[in]Indicates whether the pszFileName parameter is to be used as the current working file. If TRUE, pszFileName becomes the current file and the object should clear its dirty flag after the save. If FALSE, this save operation is a "Save A Copy As ..." operation. In this case, the current file is unchanged and the object should not clear its dirty flag. If pszFileName is NULL, the implementation should ignore the fRemember flag.

Return Values

S_OK

The object was successfully saved.

E_FAIL

The file was not saved.

IPersistFile::Save STG_E_* errors.

Comments

This method saves the object to the specified file. There are three different save scenarios that can use this method:

Save

The caller calls the IPersistFile::GetCurFile method first to determine whether the object has an associated filename. If it does, the caller specifies NULL for the pszFileName parameter in this method to indicate that the object should "Save" to its current file. The caller must call the IPersistFile::SaveCompleted method to indicate completion.

Save As

The caller specifies TRUE in the fRemember parameter and a non-NULL value for the pszFileName parameter to indicate saving to a new file. The caller must call the IPersistFile::SaveCompleted method to indicate completion.

Save a Copy As

The caller specifies FALSE in the fRemember parameter and a non-NULL value for the pszFileName parameter to save a copy to the specified file.

The implementor must detect which save scenario is being requested by the caller. If the pszFileName parameter is NULL, the Save scenario is being requested. If the pszFileName parameter is not NULL, use the value of the fRemember parameter to distinguish between a Save As and a Save a Copy As call.

In the "Save" or "Save As" scenarios, the IPersistFile::Save method clears the internal dirty flag after the save and sends IAdviseSink::OnSave notifications to any advisory connections (see also IOleAdviseHolder::SendOnSave). Also, in these scenarios, the object is in NoScribble mode until it receives an IPersistFile::SaveCompleted call. In NoScribble mode, the object must not write to the file.

In the "Save As" scenario, the implementation should also send IAdviseSink::OnRename notifications to any advisory connections (see also IOleAdviseHolder::SendOnRename).

In the "Save a Copy As" scenario, the implementation does not clear the internal dirty flag after the save.

Notes to Callers

OLE does not call IPersistFile::Save. Typically, applications do not either.

See Also

IOleAdviseHolder::SendOnRename, IOleAdviseHolder::SendOnSave, IPersistFile::GetCurFile, IPersistFile::SaveCompleted


IPersistFile::SaveCompleted

Notifies the object that it can write to its file. It does this by notifying the object that it can revert from NoScribble mode (in which it must not write to its file), to Normal mode (in which it can). The component enters NoScribble mode when it receives an IPersistFile::Save call.

HRESULT SaveCompleted(

LPCOLESTR pszFileName	//Pointer to absolute path of the file where the object was saved
);
Parameter

pszFileName

[in]Points to the absolute path of the file where the object was previously saved.

Return Value

S_OK

Returned in all cases.

Comments

This method is called when a call to IPersistFile::Save is completed, and the file that was saved is now the current working file (that is, the "Save" or "Save As" scenarios). In these cases, the object has been placed into NoScribble mode so it cannot write to its file. When the save is completed, the object can revert to Normal mode and it is free to write to its file.

Notes to Callers

OLE does not call the IPersistFile::SaveCompleted method. Typically, applications do not either.

See Also

IPersistFile::Save


IPersistStorage

The IPersistStorage interface enables a container application to pass a storage object to one of its contained objects and to load and save the storage object. This interface supports the structured storage scheme in which each component object has its own storage that is nested within the container's storage.

When to Implement

Any object that can be embedded in a container object must implement the IPersistStorage interface. This interface is one of the primary interfaces for a compound document object. It is part of the aggregate object that includes the IOleObject and IDataObject interfaces.

The OLE default handler for embedded objects provides an implementation of the IPersistStorage interface that is used when the object is in the loaded state. Similarly, the OLE default link handler provides an IPersistStorage implementation that manages storage for a linked object. These default handlers both interact with the OLE default cache implementation, which has its own IPersistStorage implementation.

If you are providing a custom embedding or link handler for your objects, the handler must include an implementation of IPersistStorage. You can delegate calls to the default handler so you can take advantage of the default cache implementation.

When to Use

When an OLE container creates a new object, loads an existing object from storage, or inserts a new object in a clipboard or a drag-and-drop operation, the container uses the IPersistStorage interface to initialize the object and put it in the loaded or running state. When a component is loaded or running, an OLE container uses the other IPersistStorage methods to instruct the component to perform various save operations or to instruct the component to release its storage.

Typically, applications use helper functions such as OleLoad or OleCreate, rather than calling the IPersistStorage::Load or IPersistStorage::InitNew methods directly. Similarly, applications typically call the OleSave helper function rather than calling IPersistStorage::Save directly.

Methods in Vtable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments reference count.
Release	Decrements reference count.
IPersistStorage Methods	Description
IsDirty	Indicates whether the object has changed since it was last saved to its current storage.
InitNew	Initializes a new storage object.
Load	Initializes an object from its existing storage.
Save	Saves an object, and any nested objects that it contains, into the specified storage object. The object enters NoScribble mode.
SaveCompleted	Notifies the object that it can revert from NoScribble or HandsOff mode, in which in must not write to its storage object, to Normal mode in which it can.
HandsOffStorage	Instructs the object to release all storage objects that have been passed to it by its container and to enter HandsOffAfterSave or HandsOffFromNormal mode.
See Also

IDataObject, IOleObject, OleCreate, OleLoad, OleSave


IPersistStorage::HandsOffStorage

Instructs the object to release all storage objects that have been passed to it by its container and to enter HandsOff mode, in which the object cannot do anything and the only operation that works is a close operation.

HRESULT HandsOffStorage(void);

Return Value

S_OK

The object has successfully entered HandsOff mode.

Comments

This method causes an object to release any storage objects that it is holding and to enter the HandsOff mode until a subsequent IPersistStorage::SaveCompleted call. In HandsOff mode, the object cannot do anything and the only operation that works is a close operation.

A container application typically calls this method during a full save or low-memory full save operation to force the component object to release all pointers to its current storage. In these scenarios, the HandsOffStorage call comes after calling OleSave or IPersistStorage::Save for the component object; and it puts the component object in HandsOffAfterSave mode. Calling this method is necessary so the container application can delete the current file as part of a full save, or so it can call the IRootStorage::SwitchToFile method as part of a low-memory save.

A container application also calls this method when a component object is in Normal mode to put the component object in HandsOffFromNormal mode.

While the component object is in either HandsOff mode, most operations on the object will fail. Thus, the container should restore the component object to Normal mode as soon as possible. The container application does this by calling the IPersistStorage::SaveCompleted method, which passes a storage pointer back to the component object for the new storage object.

Notes to Implementors

This method must release all pointers to the component's current storage object, including pointers to any nested streams and storages. If the component object contains nested component objects, the container application must recursively call this method for any nested component objects that are loaded or running.

See Also

OleSave, IPersistStorage::Save, IPersistStorage::SaveCompleted, IRootStorage::SwitchToFile


IPersistStorage::InitNew

Initializes a new storage object.

HRESULT InitNew(

IStorage *pStg	//Points to the new storage object
);
Parameter

pStg

[in]Points to the new storage object to initialize and use. The container creates a nested storage object in its storage object (see IStorage::CreateStorage). Then, the container calls the WriteClassStg function to initialize the new storage object with the component object class identifier (CLSID).

Return Values

S_OK

The new storage object was successfully initialized.

CO_E_ALREADYINITIALIZED

The component object has already been initialized by a previous call to either the IPersistStorage::Load method or the IPersistStorage::InitNew method.

E_OUTOFMEMORY

The storage object was not initialized due to a lack of memory.

E_FAIL

The storage object was not initialized due to some reason besides a lack of memory.

Comments

A container application can call this method when it needs to create a new object, for example, with an InsertObject command.

An object that uses the IPersistStorage interface must have access to a valid IStorage instance at all times while it is running. This includes the time just after the object has been created but before it has been made persistent. The object's container must provide the object with access to an IStorage instance during this time by calling IPersistStorage::InitNew. Depending on the container's state, a temporary file might need to be created for this purpose.

If the object wants to retain the IStorage instance, it must call IUnknown::AddRef to increment its reference count.

After the call to IPersistStorage::InitNew, the component object is in either the loaded or running state. For example, if the object class has an in-process server, the object will be in the running state. However, if the object uses the default handler, the container's call to InitNew only invokes the handler's implementation which does not run the component object. Later if the container runs the component object, the handler calls the IPersistStorage::InitNew method for the object.

Notes to Callers

Rather than calling IPersistStorage::InitNew directly, you typically call the OleCreate helper function which performs the following steps:

1.	Calls the CoCreateInstance function to create an instance of the object class

2.	Queries the new instance for the IPersistStorage interface

3.	Calls the IPersistStorage::InitNew method to initialize the component object

The container application should cache the PersistStorage interface for the object for use in later operations on the object.

Notes to Implementors

An implementation of IPersistStorage::InitNew should initialize the component object to its default state. In particular, your implementation should perform the following steps to initialize the storage object:

1.	Pre-open and cache the pointers to any streams or storages that the component will need to save itself to this storage.

2.	Call IPersistStorage::AddRef and cache the passed in storage pointer.

3.	Call the WriteFmtUserTypeStg function to write the native clipboard format and user type string for the component object to the storage object.

4.	Set the dirty flag for the component object.

The first two steps are particularly important for ensuring that the component object can save itself in low memory situations. By pre-opening the necessary streams, the component object can guarantee that a save operation to this storage object will not fail due to insufficient memory.

Your implementation of this method should return the CO_E_ALREADYINITIALIZED error code if it receives a call to either the IPersistStorage::InitNew method or the IPersistStorage::Load method after it is already initialized.

See Also

IPersistStorage::Load, OleCreate, WriteFmtUserTypeStg


IPersistStorage::IsDirty

Indicates whether the object has changed since it was last saved to its current storage.

HRESULT IsDirty(void);

Return Values

S_OK

The object has changed since it was last saved.

S_FALSE

The object has not changed since the last save.

Comments

This method checks whether an object has changed since it was last saved so you can avoid losing information in the object that has not yet been saved. The dirty flag for an object is conditionally cleared in the IPersistFile::Save method.

For example, you could optimize a File:Save operation by calling the IPersistStorage::IsDirty method for each component object and then calling the IPersistStorage::Save method only for those component objects that are dirty.

Notes to Callers

You should treat any error return codes as an indication that the object has changed. In other words, unless this method explicitly returns S_FALSE, you must assume that the object needs to be saved.

Notes to Implementors

A container object with one or more contained objects must maintain an internal dirty flag that reflects any one contained object being dirty. To do this, the container object should register for data change notifications with each link or embedding (see IDataObject::DAdvise). Then, the container can maintain its internal dirty flag that it sets when it receives an IAdviseSink::OnDataChange notification. If the container does not register for data change notifications, the IPersistFile::IsDirty implementation must call IPersistStorage::IsDirty for each of its contained objects to determine whether they have changed.

A component object can clear its dirty flag whenever it is saved, as long as the storage saved to is the current working storage after the save. In other words, the dirty flag is cleared after a successful "Save" or "Save As" operation, but not after a "Save A Copy As . . ." operation.

See Also

IAdviseSink::OnDataChange, IDataObject::DAdvise, IPersistStorage::Save


IPersistStorage::Load

Initializes an object from its existing storage.

HRESULT Load(

IStorage *pStg	//Pointer to existing storage object for the component object
);
Parameter

pStg

[in]Points to the existing storage object from which the component object is to be loaded.

Return Values

S_OK

The object was successfully loaded.

CO_E_ALREADYINITIALIZED

The object has already been initialized by a previous call to the IPersistStorage::Load method or the IPersistStorage::InitNew method.

E_OUTOFMEMORY

The object was not loaded due to lack of memory.

E_FAIL

The object was not loaded due to some reason besides a lack of memory.

Comments

This method initializes a component object from an existing storage object. The component object is placed in the loaded state if this method is called by the container application. If called by the default handler, this method places the component object in the running state.

Either the default handler or the component object itself can hold onto the IStorage interface while the object is loaded or running.

Notes to Callers

Rather than calling IPersistStorage::Load directly, you typically call the OleLoad helper function which performs the following steps:

1.	Create an uninitialized instance of the component object class

2.	Query the new instance for the IPersistStorage interface

3.	Call the IPersistStorage::Load method to initialize the component from the existing storage

You also call this method indirectly when you call the OleCreateFromData function or the OleCreateFromFile function to insert a component object into a compound file (as in a drag-and-drop or clipboard paste operation).

The container should cache the IPersistStorage interface for use in later operations on the component object.

Notes to Implementors

Your implementation should perform the following steps to load a component object:

1.	Open the component object's streams in the storage object, and read the necessary data into the object's internal data structures.

2.	Clear the component object's dirty flag.

3.	Call the IPersistStorage::AddRef method and cache the passed in storage pointer.

4.	Keep open and cache the pointers to any streams or storages that the component object will need to save itself to this storage.

5.	Perform any other default initialization required for the component object.

Steps 3 and 4 are particularly important for ensuring that the component can save itself in low memory situations. By holding onto pointers to the storage and streams, the component can guarantee that a save operation to this storage will not fail due to insufficient memory.

Your implementation of this method should return the CO_E_ALREADYINITIALIZED error code if it receives a call to either the IPersistStorage::InitNew method or the IPersistStorage::Load method after it is already initialized.

See Also

GetConvertStg, IPersistStorage::InitNew, OleLoad, ReadFmtUserTypeStg, SetConvertStg, WriteFmtUserTypeStg


IPersistStorage::Save

Saves an object, and any nested objects that it contains, into the specified storage object. The object is placed in NoScribble mode, and it must not write to the specified storage until it receives a call to its IPersistStorage::SaveCompleted method.

HRESULT Save(

IStorage *pStgSave,	//Pointer to storage object
BOOL fSameAsLoad	//Indicates whether the specified storage object is the current one
);
Parameters

pStgSave

[in]Points to the storage object into which the component object is to be saved.

fSameAsLoad

[in]Indicates whether the specified storage object is the current one, which was passed to the object by one of the following calls:

•	IPersistStorage::InitNew when it was created.

•	IPersistStorage::Load when it was loaded.

•	IPersistStorage::SaveCompleted when it was saved to a storage different from its current storage.

This parameter is set to FALSE when performing a Save As or Save A Copy To operation or when performing a full save. In the latter case, this method saves to a temporary file, deletes the original file, and renames the temporary file.

This parameter is set to TRUE to perform a full save in a low-memory situation or to perform a fast incremental save in which only the dirty components are saved.

Return Values

S_OK

The object was successfully saved.

STG_E_MEDIUMFULL

The object was not saved because of a lack of space on the disk.

E_FAIL

The object could not be saved due to errors other than a lack of disk space.

Comments

This method saves an object, and any nested objects it contains, into the specified storage object. It also places the component object into NoScribble mode. Thus, the component object cannot write to its storage object until a subsequent call to the IPersistStorage::SaveCompleted method returns the object to Normal mode.

If the storage object is the same as the one it was loaded or created from, the save operation may be able to write incremental changes to the storage object. Otherwise, a full save must be done.

This method recursively calls the IPersistStorage::Save method, the OleSave function, or the IStorage::CopyTo method to save its nested objects.

This method does not call the IStorage::Commit method. Nor does it write the class identifier to the storage object. Both of these tasks are the responsibilities of the caller.

Notes to Callers

Rather than calling IPersistStorage::Load directly, you typically call the OleSave helper function which performs the following steps:

1.	Call the WriteClassStg function to write the class identifier for the object to the storage.

2.	Call the IPersistStorage::Save method.

3.	If needed, call the IStorage::Commit method on the storage object.

Then, a container application performs any other operations necessary to complete the save and calls the SaveCompleted method for each component object.

If an embedded object passed the IPersistStorage::Save method to its nested objects, it must wait until it receives a call to its IPersistStorage::SaveCompleted method before calling the IPersistStorage::SaveCompleted method for its nested objects.

See Also

IPersistStorage::InitNew, IPersistStorage::Load, IPersistStorage::SaveCompleted, IStorage::Commit, IStorage::CopyTo, OleSave, WriteClassStg, WriteFmtUserTypeStg


IPersistStorage::SaveCompleted

Notifies the object that it can revert from NoScribble or HandsOff mode, in which it must not write to its storage object, to Normal mode, in which it can. The component object enters NoScribble mode when it receives an IPersistStorage::Save call.

HRESULT SaveCompleted(

IStorage *pStgNew	//Pointer to the current storage object
);
Parameter

pStgNew

[in]Points to the new storage object, if different from the storage object prior to saving. This pointer can be NULL if the current storage object does not change during the save operation. If the object is in HandsOff mode, this parameter must be non-NULL.

Return Values

S_OK

The object was successfully returned to Normal mode.

E_OUTOFMEMORY

The object remained in HandsOff mode or NoScribble mode due to a lack of memory. Typically, this error occurs when the object is not able to open the necessary streams and storage objects in pStgNew.

E_INVALIDARG

The pStgNew parameter is not valid. Typically, this error occurs if pStgNew is NULL when the object is in HandsOff mode.

E_UNEXPECTED

The object is in Normal mode, and there was no previous call to IPersistStorage::Save or IPersistStorage::HandsOffStorage.

Comments

This method notifies an object that it can revert to Normal mode and can once again write to its storage object. The object exits NoScribble mode or HandsOff mode.

If the object is reverting from HandsOff mode, the pStgNew parameter must be non-NULL. In HandsOffFromNormal mode, this parameter is the new storage object that replaces the one that was revoked by the IPersistStorage::HandsOffStorage method. The data in the storage object is a copy of the data from the revoked storage object. In HandsOffAfterSave mode, the data is the same as the data that was most recently saved. It is not the same as the data in the revoked storage object.

If the object is reverting from NoScribble mode, the pStgNew parameter can be NULL or non-NULL. If NULL, the component object once again has access to its storage object. If it is not NULL, the component object should simulate receiving a call to its IPersistStorage::HandsOffStorage method. If the component object cannot simulate this call, its container must be prepared to actually call the IPersistStorage::HandsOffStorage method.

The IPersistStorage::SaveCompleted method must recursively call any nested objects that are loaded or running.

If this method returns with an error code, the object is not returned to Normal mode. Thus, the container object can attempt different save strategies.

See Also

IAdviseSink::OnSave, IOleObject::Close, IPersistStorage::HandsOffStorage, IPersistStorage::Save, IRootStorage::SwitchToFile, OleSave


IPersistStream

The IPersistStream interface provides methods for saving and loading objects that use a simple serial stream for their storage needs. The primary purpose of this interface is to support OLE moniker implementations. Each of the OLE-provided moniker interfaces provide an IPersistStream implementation through which the moniker saves or loads itself. An instance of the OLE generic composite moniker class calls the IPersistStream methods of its component monikers to load or save the components in the proper sequence in a single stream.

OLE containers with embedded and linked component objects do not use this interface; they use the IPersistStorage interface instead.

When to Implement

Typically, applications do not implement the IPersistStream interface. However, the IMoniker interface is derived from the IPersistStream interface, so you must implement the IPersistStream interface if you are implementing a new moniker class.

When to Use

Typically, applications do not use the IPersistStream interface directly. The default link handler uses the IPersistStream interface to save and load the monikers that identify the link source. These monikers are stored in a stream in the storage for the linked object. If you are writing a custom link handler for your class of components, you will need to use the IPersistStream interface to load and save these monikers.

Methods in Vtable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments the reference count.
Release	Decrements the reference count.
IPersistStream Methods	Description
IsDirty	Checks the object for changes since it was last saved.
Load	Initializes an object from the stream where it was previously saved.
Save	Saves an object into the specified stream and indicates whether the object should reset its dirty flag.
GetSizeMax	Return the size in bytes of the stream needed to save the object.
See Also

IMoniker


IPersistStream::GetSizeMax

Returns the size in bytes of the stream needed to save the object.

HRESULT GetSizeMax(

ULARGE_INTEGER *pcbSize	//Pointer to size of stream needed to save object
);
Parameter

pcbSize

[out]Points to a 64-bit unsigned integer value indicating the size in bytes of the stream needed to save this object.

Return Value

S_OK

The size was successfully returned.

Comments

This method returns the size needed to save an object. You can call this method to determine the size and set the necessary buffers before calling the IPersistStream::Save method.

Notes to Implementors

The GetSizeMax implementation should return a conservative estimate of the necessary size because the caller might call the IPersistStream::Save method with a non-growable stream.

See Also

IPersistStream::Save


IPersistStream::IsDirty

Checks the object for changes since it was last saved.

HRESULT IsDirty(void);

Return Values

S_OK

The object has changed since it was last saved.

S_FALSE

The object has not changed since the last save.

Comments

This method checks whether an object has changed since it was last saved so you can avoid losing information in objects that have not yet been saved. The dirty flag for an object is conditionally cleared in the IPersistStream::Save method.

Notes to Callers

You should treat any error return codes as an indication that the object has changed. In other words, unless this method explicitly returns S_FALSE, you must assume that the object needs to be saved.

Note that the OLE-provided implementations of the IPersistStream::IsDirty method in the OLE-provided moniker interfaces always return S_FALSE because their internal state never changes.

See Also

IPersistStream::Save


IPersistStream::Load

Initializes an object from the stream where it was previously saved.

HRESULT Load(

IStream *pStm	//Pointer to the stream from which the object should be loaded
);
Parameter

pStm

[in]Points to the stream from which the object should be loaded.

Return Values

S_OK

The object was successfully loaded.

E_OUTOFMEMORY

The object was not loaded due to a lack of memory.

E_FAIL

The object was not loaded due to some reason other than a lack of memory.

Comments

This method loads an object from its associated stream. The seek pointer is set as it was in the most recent IPersistStream::Save method. This method can seek and read from the stream, but cannot write to it.

On exit, the seek pointer must be in the same position it was in on entry, immediately past the end of the data.

Notes to Callers

Rather than calling IPersistStream::Load directly, you typically use the OleLoadFromStream function which performs the following steps:

1.	Calls the ReadClassStm function to get the class identifier from the stream.

2.	Calls the CoCreateInstance function to create an instance of the object.

3.	Queries the instance for IPersistStream.

4.	Calls IPersistStream::Load.

The OleLoadFromStream function assumes that objects are stored in the stream with a class identifier followed by the object data. This is the storage pattern used by the generic, composite-moniker implementation provided by OLE.

If the objects are not stored using this pattern, you must call the methods separately yourself.

See Also

CoCreateInstance, OleLoadFromStream, ReadClassStm


IPersistStream::Save

Saves an object to the specified stream.

HRESULT Save(

IStream *pStm,	//Pointer to the stream where the object is to be saved
BOOL fClearDirty	//Specifies whether to clear the dirty flag
);
Parameters

pStm

[in]Points to the stream into which the object should be saved.

fClearDirty

[in]Indicates whether to clear the dirty flag after the save is complete. If TRUE, the flag should be cleared. If FALSE, the flag should be left unchanged.

Return Values

S_OK

The object was successfully saved to the stream.

STG_E_CANTSAVE

The object could not save itself to the stream. This error could indicate, for example, that the object contains another object that is not serializable to a stream or that an IStream::Write call returned STG_E_CANTSAVE.

STG_E_MEDIUMFULL

The object could not be saved because there is no space left on the storage device.

Comments

This method saves an object into the specified stream and indicates whether the object should reset its dirty flag.

The seek pointer is positioned at the location in the stream at which the object should begin writing its data. The object calls the IStream::Write method to write its data.

On exit, the seek pointer must be positioned immediately past the object data. The position of the seek pointer is undefined if an error returns.

Notes to Callers

Rather than calling IPersistStream::Save directly, you typically use the OleSaveToStream helper function which performs the following steps:

1.	Calls IPersistStream::GetClassID to get the object's class identifier.

2.	Calls the WriteClassStm function to write the object's class identifier to the stream.

3.	Calls IPersistStream::Save.

If you call these methods directly, you can write other data into the stream after the class identifier before calling IPersistStream::Save.

The OLE-provided implementation of IPersistStream follows this same pattern.

Notes to Implementors

The IPersistStream::Save method does not write the class identifier to the stream. The caller is responsible for writing the class identifier.

The IPersistStream::Save method can read from, write to, and seek in the stream; but it must not seek to a location in the stream before that of the seek pointer on entry.

See Also

IPersist::GetClassID, IStream::Write, OleSaveToStream


IRootStorage

The IRootStorage interface contains a single method that switches a storage object to a different underlying file and saves the storage object to that file. The save operation occurs even with low memory conditions and uncommitted changes to the storage object. A subsequent call to IStorage::Commit is guaranteed to not consume any additional memory.

When to Implement

Storage objects that are based on a file should implement IRootStorage in addition to the IStorage interface. For storage objects that are not file-based, this interface is not necessary.

OLE provides an implementation of a storage object, including the IRootStorage interface, as part of its compound file implementation.

When to Use

The primary use for the IRootStorage interface is to save a storage object to a file during low memory conditions. Typically, the container application calls the IRootStorage interface to switch to a new file.

You can call IStorage::QueryInterface with IID_IRootStorage to obtain a pointer to the IRootStorage interface.

Methods in Vtable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments the reference count.
Release	Decrements the reference count.
IRootStorage Method	Description
SwitchToFile	Copy the file underlying this root storage object, then associate this storage with the copied file.
See Also

IStorage, StgCreateDocfile


IRootStorage::SwitchToFile

Copies the current file associated with the storage object to a new file. The new file is then used for the storage object and any uncommitted changes.

HRESULT SwitchToFile(

LPOLESTR pszFile	//Filename for the new file
);
Parameter

pszFile

Specifies the filename for the new file. It cannot be the name of an existing file. If NULL, this method creates a temporary file with a unique name, and you can call IStorage::Stat to retrieve the name of the temporary file.

Return Values

S_OK

The file was successfully copied.

STG_E_MEDIUMFULL

The file was not copied because of insufficient space on the storage device.

STG_E_ACCESSDENIED

The file was not copied because the caller does not have permission to access storage device.

STG_E_INVALIDPOINTER

The file was not copied because the pszFile pointer is invalid.

STG_E_FILEALREADYEXISTS

The file was not copied because the new filename (pszFile) points to an existing file.

Comments

The IRootStorage::SwitchToFile method copies the file associated with the storage object. An OLE container calls IRootStorage::SwitchToFile to perform a full save on a file in a low-memory situation. Typically, this is done only after a normal full save operation (i.e., save to temporary file, delete original file, rename temporary file) has failed with an E_OUTOFMEMORY error.

It is illegal to call IRootStorage::SwitchToFile if the storage object or anything contained within it has been marshalled to another process. As a consequence, the container must call the IPersistStorage::HandsOffStorage method for any element within the storage object that is loaded or running. The HandsOffStorage method forces the element to release its storage pointers and enter the hands-off storage mode. The container must also release all pointers to streams or storages that are contained in this root storage. After the full save operation is completed, the container returns the contained elements to normal storage mode.

Notes to Implementors

If you are implementing your own storage objects, the IRootStorage methods (including QueryInterface, IUnknown::AddRef, and IUnknown::Release) must not consume additional memory or file handles.

See Also

IPersistStorage::HandsOffStorage, IPersistStorage::SaveCompleted, IStorage::Commit, IStorage::Stat


IROTData

The IROTData interface is implemented by monikers to enable the Running Object Table (ROT) to compare monikers against each other.

The ROT uses the IROTData interface to test whether two monikers are equal. The ROT must do this when, for example, it checks whether a specified moniker is registered as running.

When to Implement

You must implement IROTData if you are writing your own moniker class (that is, writing your own implementation of the IMoniker interface), and if your monikers are meant to be registered in the ROT.

When to Use

You typically do not need to use this interface. This interface is used by the system's implementation of the ROT.

Methods in Vtable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments reference count.
Release	Decrements reference count.
IROTData Method	Description
GetComparisonData	Retrieve data to allow moniker to be compared with another.
See Also

IMoniker, IRunningObjectTable


IROTData::GetComparisonData

Retrieves data from a moniker that can be used to test the moniker for equality against another moniker.

HRESULT GetComparisonData(

PVOID *ppvData,	//Buffer that receives the comparison data
ULONG cbMax,	//Specifies length of buffer
PULONG pcbData	//Receives the length of the comparison data
);
Parameters

ppvData

[out] Points to a buffer that receives the comparison data.

cbMax

[in] Specifies the length of the buffer specified in ppvData.

pcbData

[out] Receives the length of the comparison data.

Return Values

S_OK

The comparison data was successfully returned.

E_OUTOFMEMORY

The buffer contained insufficient space to return the comparison data.

Comments

The IROTData::GetComparisonData method is primarily called by the Running Object Table (ROT). The comparison data returned by the method is tested for binary equality against the comparison data returned by another moniker. The pcbData parameter enables the ROT to locate the end of the data returned.

Notes to Implementors

The comparison data that you return must uniquely identify the moniker, while still being as short as possible. The comparison data should include information about the internal state of the moniker, as well as the moniker's CLSID. For example, the comparison data for a file moniker would include the pathname stored within the moniker as well as the CLSID of the file moniker implementation. This makes it possible to distinguish two monikers that happen to store similar state information but are instances of different moniker classes.

The comparison data for a moniker cannot exceed 2048 bytes in length. For composite monikers, the total length of the comparison data for all of its components cannot exceed 2048 bytes; consequently, if your moniker can be a component within a composite moniker, the comparison data you return must be significantly less than 2048 bytes.

If your comparison data is longer than the value specified by the cbMax parameter, you must return an error. Note that when IROTData::GetComparisionData is called on the components of a composite moniker, the value of cbMax becomes smaller for each moniker in sequence.

See Also

IMoniker, IRunningObjectTable


IRunnableObject

The IRunnableObject interface enables a container to control the running of its embedded objects. In the case of an object implemented with a local server, calling IRunnableObject::Run launches the server's .EXE file. In the case of an object implemented with an in-process server, calling the Run method causes the object .DLL file to transition into the running state.

When to Implement

Object handlers should implement IRunnableObject to provide their containers with a way to run them and manage their running state. DLL object applications should implement IRunnableObject to support silent updates of their objects.

When to Use

Containers call IRunnableObject to determine if an embedded object is running, to force an object to run, to lock an object into the running state, or to inform an object handler whether its object is being run as either a simple embedding or as a link source.

Methods VTable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments reference count.
Release	Decrements reference count.
IRunnableObject Methods	Description
GetRunningClass	Returns CLSID of a running object.
Run	Forces an object to run.
IsRunning	Determines if an object is running.
LockRunning	Locks an object into running state.
SetContainedObject	Indicates that an object is embedded.


IRunnableObject::GetRunningClass

Returns the CLSID of a running object.

HRESULT GetRunningClass(

LPCLSID lpClsid	//Pointer to an object's CLSID
);
Parameter

lpClsid

[out] Points to the object's class ID.

Return Values

S_OK

CLSID was returned successfully.

E_INVALIDARG

An argument is invalid.

E_UNEXPECTED

An unexpected error occurred.

Comments

If an embedded document was created by an application that is not available on the user's computer, the document, by a call to CoTreatAsClass, may be able to display itself for editing by emulating a class that is supported on the user's machine. In this case, the CLSID returned by a call to IRunnableObject::GetRunningClass will be that of the class being emulated, rather than the document's native class.

See Also

CoTreatAsClass


IRunnableObject::IsRunning

Determines whether an object is currently in the running state.

BOOL IsRunning();

Return Values

TRUE

The object is in the running state.

FALSE

The object is not in the running state.

Comments

A container application could call IRunnableObject::IsRunning when it needs to know if the server is immediately available. For example, a container's implementation of the IOleItemContainer::GetObject method would return an error if the server is not running and the bindspeed parameter specifies BINDSPEED_IMMEDIATE.

An object handler could call IRunnableObject::IsRunning when it wants to avoid conflicts with a running server or when the running server might have more up-to-date information. For example, a handler's implementation of IOleObject::GetExtent would delegate to the object server if it is running, because the server's information might be more current than that in the handler's cache.

OleIsRunning is a helper function that conveniently repackages the functionality offered by IRunnableObject::IsRunning. With the release of OLE 2.01, the implementation of OleIsRunning was changed so that it calls QueryInterface, asks for IRunnableObject, and then calls IRunnableObject::IsRunning. In other words, you can use the interface and the helper function interchangeably.

See Also

OleIsRunning


IRunnableObject::LockRunning

Locks an already-running object into its running state or unlocks it from its running state.

HRESULT LockRunning(

BOOL fLock,	//Flag indicating whether object is locked
BOOL fLastUnlockCloses	//Flag indicating whether to close object
);
Parameters

fLock

[in] TRUE locks the object into its running state. FALSE unlocks the object from its running state.

fLastUnlockCloses

[in] TRUE specifies that if the connection being released is the last external lock on the object, the object should close. FALSE specifies that the object should remain open until closed by the user or another process.

Return Values

S_OK

If the value of fLock is TRUE, the object was successfully locked; if the value of fLock is FALSE, the object was successfully unlocked.

E_FAIL

The object was not running.

E_OUTOFMEMORY

Out of memory.

E_INVALIDARG

One or more arguments are invalid.

E_UNEXPECTED

An unexpected error occurred.

Comments

Most implementations of IRunnableObject::LockRunning call CoLockObjectExternal.

OleLockRunning is a helper function that conveniently repackages the functionality offered by IRunnableObject::LockRunning. With the release of OLE 2.01, the implementation of OleLockRunning was changed to call QueryInterface, ask for IRunnableObject, and then call IRunnableObject::LockRunning. In other words, you can use the interface and the helper function interchangeably.

See Also

CoLockObjectExternal


IRunnableObject::Run

Runs an object.

HRESULT Run(

LPBC lpbc	//Pointer to binding context
);
Parameter

lpbc

Points to the binding context of the run operation. May be NULL.

Return Values

S_OK

The object was successfully placed in the running state.

E_OUTOFMEMORY

Out of memory.

E_UNEXPECTED

An unexpected error occurred.

Comments

Containers call IRunnableObject::Run to force their objects to enter the running state. If the object is not already running, calling IRunnableObject::Run can be an expensive operation, on the order of many seconds. If the object is already running, then this method has no effect on the object.

Notes to Callers

When called on a linked object that has been converted to a new class since the link was last activated, IRunnableObject::Run may return OLE_E_CLASSDIFF. In this case, the client should call IOleLink::BindToSource.

OleRun is a helper function that conveniently repackages the functionality offered by IRunnableObject::Run. With the release of OLE 2.01, the implementation of OleRun was changed so that it calls QueryInterface, asks for IRunnableObject, and then calls IRunnableObject::Run. In other words, you can use the interface and the helper function interchangeably.

Notes to Implementors

The object should register in the running object table if it has a moniker assigned. The object should not hold any strong locks on itself; instead, it should remain in the unstable, unlocked state. The object should be locked when the first external connection is made to the object.

An embedded object must hold a lock on its embedding container while it is in the running state. The Default handler provided by OLE 2 takes care of locking the embedding container on behalf of objects implemented by an EXE object application. Objects implemented by a DLL object application must explicitly put a lock on their embedding containers, which they do by first calling IOleClientSite::Getcontainer to get a pointer to the container, then calling IOleContainer::LockContainer to actually place the lock. This lock must be released when IOleObject::Close is called.

See Also

IOleLink::BindToSource, OleRun


IRunnableObject::SetContainedObject

Notifies an object that it is embedded in an OLE container, which ensures that reference counting is done correctly for containers that support links to embedded objects.

HRESULT SetContainedObject(

BOOL fContained	//Flag indicating whether object is embedded
);
Parameter

fContained

[in] TRUE specifies that the object is contained in an OLE container. FALSE indicates that it is not.

Return Values

S_OK

Object has been marked as a contained embedding.

E_OUTOFMEMORY

Out of memory.

E_INVALIDARG

The argument is invalid.

E_UNEXPECTED

An unexpected error occurred.

Comments

The IRunnableObject::SetContainedObject method enables a container to inform an object handler that it is embedded in the container, rather than acting as a link. This call changes the container's reference on the object from strong, the default for external connections, to weak. When the object is running visibly, this method is of little significance because the end-user has a lock on the object. During a silent update of an embedded link source, however, the container should not be able to hold an object in the running state after the link has been broken. For this reason, the container's reference to the object must be weak.

Notes to Callers

A container application must call IRunnableObject::SetContainedObject if it supports linking to embedded objects. It normally makes the call immediately after calling OleLoad or OleCreate and never calls the method again, even before it closes. Moreover, a container almost always calls this method with fContained set to TRUE. The use of this method with fContained set to FALSE is rare.

Calling IRunnableObject::SetContainedObject is optional only when you know that the embedded object will not be referenced by any client other than the container. If your container application does not support linking to embedded objects; it is preferable, but not necessary, to call IRunnableObject::SetContainedObject.

OleSetContainedObject is a helper function that conveniently repackages the functionality offered by IRunnableObject::SetContainedObject. With the release of OLE 2.01, the implementation of OleSetContainedObject was changed to call QueryInterface, ask for IRunnableObject, and then call IRunnableObject::SetContainedObject. In other words, you can use the interface and the helper function interchangeably.

See Also

OleSetContainedObject, OleNoteObjectVisible, CoLockObjectExternal


IRunningObjectTable

The IRunningObjectTable interface manages access to the Running Object Table (ROT), a globally accessible lookup table on each workstation. A workstation's ROT keeps track of those objects that can be identified by a moniker and that are currently running on the workstation. When a client tries to bind a moniker to an object, the moniker checks the ROT to see if the object is already running; this allows the moniker to bind to the current instance instead of loading a new one.

The ROT contains entries of the form:

(pmkObjectName, pUnkObject)

The pmkObjectName element is a pointer to the moniker that identifies the running object. The pUnkObject element is a pointer to the running object itself. During the binding process, monikers consult the pmkObjectName entries in the Running Object Table to see if an object is already running.

Objects that can be named by monikers must be registered with the ROT when they are loaded and their registration must be revoked when they are no longer running.

When to Implement

You do not need to implement this interface. The system provides an implementation of the Running Object Table that is suitable for all situations.

When to Use

You typically use the ROT if you're a moniker provider (that is, you hand out monikers identifying your objects to make them accessible to others) or if you're writing your own moniker class (that is, implementing the IMoniker interface).

If you are a moniker provider, you register your objects with the ROT when they begin running and revoke their registrations when they are no longer running. This enables the monikers that you hand out to be bound to running objects. You should also use the ROT to record the object's last modification time. You can get an IRunningObjectTable interface pointer to the local ROT by calling the GetRunningObjectTable API function.

The most common type of moniker provider is a compound-document link source. This includes server applications that support linking to their documents (or portions of a document) and container applications that support linking to embeddings within their documents. Server applications that do not support linking can also use the ROT to cooperate with container applications that support linking to embeddings.

If you are writing your own moniker class, you use the ROT to determine whether a object is running and to retrieve the object's last modification time. You can get an IRunningObjectTable interface pointer to the local ROT by calling the IBindCtx::GetRunningObjectTable method on the bind context for the current binding operation. Moniker implementations should always use the bind context to acquire a pointer to the ROT; this allows future implementations of IBindCtx to modify binding behavior. Note that you must also implement the IROTData interface on your moniker class in order to allow your monikers to be registered with the ROT.

Methods in VTable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments reference count.
Release	Decrements reference count.
IRunningObjectTable Methods	Description
Register	Registers an object with the ROT.
Revoke	Revokes an object's registration with the ROT.
IsRunning	Checks whether an object is running.
GetObject	Returns a pointer to an object given its moniker.
NoteChangeTime	Notifies the ROT that an object has changed.
GetTimeOfLastChange	Returns the time an object was last changed.
EnumRunning	Returns an enumerator for the ROT.
See Also

IBindCtx::GetRunningObjectTable, IROTData, GetRunningObjectTable


IRunningObjectTable::EnumRunning

Returns an enumerator that can list the monikers of all the objects currently registered in the Running Object Table (ROT).

HRESULT EnumRunning(

IEnumMoniker **ppenumMoniker	//Receives enumerator for ROT
);
Parameter

ppenumMoniker

[out] Receives a pointer to an IEnumMoniker interface to the enumerator. If an error occurs; the implementation sets *ppenumMoniker to NULL. If *ppenumMoniker is non-NULL, the implementation calls IUnknown::AddRef on the parameter; it is the caller's responsibility to call IUnknown::Release.

Return Values

S_OK

Indicates that an enumerator was successfully returned.

E_OUTOFMEMORY

Indicates insufficient memory.

Comments

The ppenumMoniker enumerator does not enumerate monikers that are registered in the ROT after the enumerator has been created.

The EnumRunning method is intended primarily for the use by the system in implementing the Alert Object Table. Note that OLE 2 does not include an implementation of the Alert Object Table.

See Also

IEnumXXXX


IRunningObjectTable::GetObject

Determines whether the object identified by the specified moniker is running, and if it is, retrieves a pointer to that object. This method looks for the moniker in the Running Object Table (ROT), and retrieves the pointer registered there.

HRESULT GetObject(

IMoniker *pmkObjectName,	//Moniker identifying object desired
IUnknown **ppunkObject	//Receives pointer to the object
);
Parameters

pmkObjectName

[in] Points to the moniker to search for in the Running Object Table.

ppunkObject

[out] Receives a pointer to the running object. If the object is not running or if an error occurs, the implementation sets *ppunkObject to NULL. If *ppunkObject is non-NULL, the implementation calls IUnknown::AddRef on the parameter; it is the caller's responsibility to call IUnknown::Release.

Return Values

S_OK

Indicates that pmkObjectName was found in the ROT and a pointer was returned.

S_FALSE

Indicates that there is no entry for pmkObjectName in the ROT, or that the object it identifies is no longer running (in which case, the entry is revoked).

Comments

This method checks the ROT for the moniker specified by pmkObjectName. If that moniker had previously been registered with a call to IRunningObjectTable::Register, this method returns the pointer that was registered at that time.

Notes to Callers

Generally, you call the IRunningObjectTable::GetObject method only if you are writing your own moniker class (that is, implementing the IMoniker interface). You typically call this method from your implementation of IMoniker::BindToObject.

However, note that not all implementations of IMoniker::BindToObject need to call this method. If you expect your moniker to have a prefix (indicated by a non-NULL pmkToLeft parameter to IMoniker::BindToObject), you should not check the ROT. The reason for this is that only complete monikers are registered with the ROT, and if your moniker has a prefix, your moniker is part of a composite and thus not complete. Instead, your moniker should request services from the object identified by the prefix (for example, the container of the object identified by your moniker).

See Also

IMoniker::BindToObject


IRunningObjectTable::GetTimeOfLastChange

Returns the time that an object was last modified. The object must have previously been registered with the Running Object Table (ROT). This method looks for the last change time recorded in the ROT.

HRESULT GetTimeOfLastChange(

IMoniker *pmkObjectName,	//Moniker identifying object whose status is desired
FILETIME *pfiletime	//Object's last change time
);
Parameters

pmkObjectName

[in] Points to the moniker to search for in the ROT.

pfiletime

[out] Points to a FILETIME structure that receives the object's last change time.

Return Values

S_OK

Indicates that the last change time was successfully retrieved.

S_FALSE

Indicates that there is no entry for pmkObjectName in the ROT, or that the object it identifies is no longer running (in which case, the entry is revoked).

Comments

This method returns the change time that was last reported for this object by a call to IRunningObjectTable::NoteChangeTime. If IRunningObjectTable::NoteChangeTime has not been called previously, the method returns the time that was recorded when the object was registered.

This method is provided to enable checking whether a connection between two objects (represented by one object holding a moniker that identifies the other) is up-to-date. For example, if one object is holding cached information about the other object, this method can be used to check whether the object has been modified since the cache was last updated. See IMoniker::GetTimeOfLastChange.

Notes to Callers

Generally, you call IRunningObjectTable::GetTimeOfLastChange only if you are writing your own moniker class (that is, implementing the IMoniker interface). You typically call this method from your implementation of IMoniker::GetTimeOfLastChange. However, you should do so only if the pmkToLeft parameter of IMoniker::GetTimeOfLastChange is NULL. Otherwise, you should call IMoniker::GetTimeOfLastChange on your pmkToLeft parameter instead.

See Also

IMoniker::GetTimeOfLastChange, IRunningObjectTable::NoteChangeTime


IRunningObjectTable::IsRunning

Determines whether the object identified by the specified moniker is currently running. This method looks for the moniker in the Running Object Table (ROT).

HRESULT IsRunning(

IMoniker *pmkObjectName	//Moniker identifying the object whose status is desired
);
Parameter

pmkObjectName

[in] Points to the moniker to search for in the Running Object Table.

Return Values

S_OK

Indicates that the object identified by pmkObjectName is running.

S_FALSE

Indicates that there is no entry for pmkObjectName in the ROT, or that the object it identifies is no longer running (in which case, the entry is revoked).

Comments

This method simply indicates whether a object is running. To retrieve a pointer to a running object, use the IRunningObjectTable::GetObject method.

Notes to Callers

Generally, you call the IRunningObjectTable::IsRunning method only if you are writing your own moniker class (that is, implementing the IMoniker interface). You typically call this method from your implementation of IMoniker::IsRunning. However, you should do so only if the pmkToLeft parameter of IMoniker::IsRunning is NULL. Otherwise, you should call IMoniker::IsRunning on your pmkToLeft parameter instead.

See Also

IMoniker::IsRunning


IRunningObjectTable::NoteChangeTime

Records the time that a running object was last modified. The object must have previously been registered with the Running Object Table (ROT). This method stores the time of last change in the ROT.

HRESULT NoteChangeTime(

DWORD dwRegister,	//Value identifying registration being updated
FILETIME *pfiletime	//Time containing object's last change time
);
Parameters

dwRegister

[in] Specifies a value identifying the ROT entry of the changed object. This value was previously returned by IRunningObjectTable::Register.

pfiletime

[in] Points to a FILETIME structure containing the object's last change time.

Return Values

S_OK

Indicates that the change time was recorded successfully.

E_INVALIDARG

Indicates that dwRegister is not a valid ROT entry or pfiletime is an invalid pointer.

Comments

The time recorded by this method can be retrieved by calling IRunningObjectTable::GetTimeOfLastChange.

This method is provided to enable a program to check whether a connection between two objects (represented by one object holding a moniker that identifies the other) is up-to-date. For example, if one object is holding cached information about the other object, this method can be used to check whether the object has been modified since the cache was last updated. See IMoniker::GetTimeOfLastChange.

Notes to Callers

If you're a moniker provider (that is, you hand out monikers identifying your objects to make them accessible to others), you must call the IRunningObjectTable::NoteChangeTime method whenever your objects are modified. You must have previously called IRunningObjectTable::Register and stored the identifier returned by that method; you use that identifier when calling IRunningObjectTable::NoteChangeTime.

The most common type of moniker provider is a compound-document link source. This includes server applications that support linking to their documents (or portions of a document) and container applications that support linking to embeddings within their documents. Server applications that do not support linking can also use the ROT to cooperate with container applications that support linking to embeddings.

When an object is first registered in the ROT, the ROT records its last change time as the value returned by calling IMoniker::GetTimeOfLastChange on the moniker being registered.

See Also

IRunningObjectTable::GetTimeOfLastChange, IMoniker::GetTimeOfLastChange


IRunningObjectTable::Register

Registers an object and its identifying moniker in the Running Object Table (ROT).

HRESULT Register(

DWORD grfFlags,	//Specifies a weak or a strong reference
IUnknown *punkObject,	//Pointer to the object being registered
IMoniker *pmkObjectName,	//Moniker that identifies the object being registered
DWORD *pdwRegister	//Receives value identifying the registration
);
Parameters

grfFlags

[in] Specifies whether the ROT's reference to punkObject is weak or strong. This value must be either zero, indicating a weak reference that does not call IUnknown::AddRef; or ROTFLAGS_REGISTRATIONKEEPSALIVE, indicating a strong reference that calls IUnknown::AddRef and can keep the object running. If a strong reference is registered, a strong reference is released when the object's registration is revoked. Most callers specify zero, indicating a weak reference.

punkObject

[in] Points to the object that is being registered as running.

pmkObjectName

[in] Points to the moniker that identifies punkObject.

pdwRegister

[out] Receives a 32-bit value that can be used to identify this ROT entry in subsequent calls to IRunningObjectTable::Revoke or IRunningObjectTable::NoteChangeTime. The caller cannot specify NULL for this parameter. If an error occurs, *pdwRegister is set to zero.

Return Values

S_OK

Indicates that the object was successfully registered.

MK_S_MONIKERALREADYREGISTERED

Indicates that the moniker/object pair was successfully registered, but that another object (possibly the same object) has already been registered with the same moniker.

E_INVALIDARG

Indicates one or more invalid arguments.

E_OUTOFMEMORY

Indicates failure due to insufficient memory.

Comments

This method registers a pointer to an object under a moniker that identifies the object. The moniker is used as the key when the table is searched with IRunningObjectTable::GetObject.

Registering a second object with the same moniker, or re-registering the same object with the same moniker, creates a second entry in the ROT. In this case, IRunningObjectTable::Register returns MK_S_MONIKERALREADYREGISTERED. Each call to IRunningObjectTable::Register must be matched by a call to IRunningObjectTable::Revoke because even duplicate entries have different pdwRegister identifiers. A problem with duplicate registrations is that there is no way to determine which object will be returned if the moniker is specified in a subsequent call to IRunningObjectTable::IsRunning.

Notes to Callers

If you're a moniker provider (that is, you hand out monikers identifying your objects to make them accessible to others), you must call the IRunningObjectTable::Register method to register your objects when they begin running. You must also call this method if you rename your objects while they are loaded.

The most common type of moniker provider is a compound-document link source. This includes server applications that support linking to their documents (or portions of a document) and container applications that support linking to embeddings within their documents. Server applications that do not support linking can also use the ROT to cooperate with container applications that support linking to embeddings.

If you're writing a server application, you should register an object with the ROT when it begins running, typically in your implementation of IOleObject::DoVerb. The object must be registered under its full moniker, which requires getting the moniker of its container document using IOleClientSite::GetMoniker. You should also revoke and re-register the object in your implementation of IOleObject::SetMoniker, which is called if the container document is renamed.

If you're writing a container application that supports linking to embeddings, you should register your document with the ROT when it is loaded. If your document is renamed, you should revoke and re-register it with the ROT and call IOleObject::SetMoniker for any embedded objects in the document to give them an opportunity to re-register themselves.

You must cache the identifier returned in pdwRegister, and use it in a call to IRunningObjectTable::Revoke to revoke the registration when the object is no longer running or when its moniker changes. This revocation is important because there is no way for the system to automatically remove entries from the ROT.

The system's implementation of IRunningObjectTable::Register calls IMoniker::Reduce on the pmkObjectName parameter to ensure that the moniker is fully reduced before registration. If a object is known by more than one fully reduced moniker, then it should be registered under all such monikers.

See Also

IMoniker::Reduce, IOleClientSite::GetMoniker, IOleObject::SetMoniker, IRunningObjectTable::IsRunning, IRunningObjectTable::Revoke


IRunningObjectTable::Revoke

Removes from the Running Object Table (ROT) an entry that was previously registered by a call to IRunningObjectTable::Register.

HRESULT Revoke(

DWORD dwRegister	//Value identifying registration to be revoked
);
Parameter

dwRegister

[in] Specifies a value identifying the ROT entry to revoke. This value was previously returned by IRunningObjectTable::Register.

Return Values

S_OK

Indicates that the object's registration was successfully revoked.

E_INVALIDARG

Indicates that dwRegister is not valid.

Comments

This method undoes the effect of a call to IRunningObjectTable::Register, removing both the moniker and the pointer to the object identified by that moniker.

Notes to Callers

If you're a moniker provider (that is, you hand out monikers identifying your objects to make them accessible to others), you must call the IRunningObjectTable::Revoke method to revoke the registration of your objects when they stop running. You must have previously called IRunningObjectTable::Register and stored the identifier returned by that method; you use that identifier when calling IRunningObjectTable::Revoke.

The most common type of moniker provider is a compound-document link source. This includes server applications that support linking to their documents (or portions of a document) and container applications that support linking to embeddings within their documents. Server applications that do not support linking can also use the ROT to cooperate with container applications that support linking to embeddings.

If you're writing a container application, you must revoke a document's registration when the document is closed. You must also revoke a document's registration before re-registering it when it is renamed.

If you're writing a server application, you must revoke an object's registration when the object is closed. You must also revoke an object's registration before re-registering it when its container document is renamed (see IOleObject::SetMoniker).

See Also

IOleObject::SetMoniker, IRunningObjectTable::Register


IStdMarshalInfo

The IStdMarshalInfo interface returns the CLSID identifying the handler to be used in the destination process during standard marshaling.

Even if an object uses standard marshaling instead of custom marshaling, it can still specify a handler that should be loaded in the client process. Such a handler would handle certain requests locally and delegate others back to the original object (using standard marshaling). To get the CLSID of the handler to be loaded, OLE queries the object for the IStdMarshalInfo interface and then the IPersist interface. If neither interface is supported, a standard handler is used.

When to Implement

If you are writing a server application that supports class emulation (that is, if your server can manipulate objects of another type in response to the Activate As option in the Convert dialog box), you must implement the IStdMarshalInfo interface

Note that your handler must aggregate the default handler.

When to Use

You typically don't call this interface yourself. OLE queries for this interface when performing standard marshaling.

Methods in VTable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments reference count.
Release	Decrements reference count.
IStdMarshalInfo Method	Description
GetClassForHandler
See Also

IMarshal


IStdMarshalInfo::GetClassForHandler

Retrieves the CLSID of the object handler to be used in the destination process during standard marshaling.

HRESULT GetClassForHandler(

DWORD dwDestContext,	//Specifies the destination process
void * pvDestContext,	//Reserved for future use
CLSID * pClsid	//Receives the CLSID
);
Parameters

dwDestContext

[in] Specifies the destination context, that is, the process in which the unmarshaling will be done. The legal values for dwDestContext are taken from the enumeration MSHCTX. For information on the MSHCTX enumeration, see the "Data Structures" section.

pvDestContext

[in] Reserved for use with future MSHCTX values.

pClsid

[out] On exit, contains the handler's CLSID.

Return Values

S_OK

The CLSID was retrieved successfully.

E_OUTOFMEMORY

Out of memory.

E_INVALIDARG

One or more arguments are invalid.

E_UNEXPECTED

An unexpected error occurred.

Comments

Notes to Implementors

Your implementation of IStdMarshalInfo::GetClassForHandler must return your own CLSID. This allows an object created by a different server to behave as one your server created.


IStorage

The IStorage interface supports the creation and management of structured storage objects. These storage objects provide hierarchical storage of information within a single file similar to a file system within a file. Storage objects are like the directories in a file system. They provide the structure in a structured storage object. They can contain other storage objects which can be nested indefinitely, or stream objects. Stream objects are like the files within a file system. They contain the actual data content in a storage object.

The IStorage interface provides methods for creating and managing the root storage object, child storage objects, and stream objects. These methods can create, open, enumerate, move, copy, rename, or delete the elements in the storage object.

An application must release its IStorage pointers when it is done with the storage object to deallocate memory used. The IStorage interface provides a IUnknown::Release method. There are also methods for changing the date and time of an element.

Storage objects can be opened in direct or transacted mode. In direct mode, changes are immediately reflected in the element that changed. In transacted mode, changes are not reflected in the element until explicitly committed. This feature allows you to revert to a previous version without committing the changes. The IStorage interface provides methods for committing changes and reverting to previous versions of the storage object.

Storage objects and their elements have a set of access flags that control how the elements can be used. For example, a stream can be opened in read only mode or read/write mode. See the STGM enumeration values for more information on these flags. Storage objects and their elements also have a set of statistics defined by the STATSTG structure.

When to Implement

OLE provides an implementation of the IStorage interface in compound files. The compound file implementation supports transacted access. OLE provides a set of helper APIs for using the compound file implementation of storage objects.

Container or object applications can implement their own storage objects instead of using the OLE-provided implementation.

When to Use

Container applications use storage objects for compound files. For example, a word processing document could contain a chart. The chart would be provided its own storage object within the root storage object of the containing application while document pages are stored in a separate storage object in the same root storage object.

Since storage object pointers can be marshaled to other processes, applications can share the data in storage objects without having to use global memory. For the OLE-provided implementation of compound files, the custom marshaling facilities in OLE create a remote version of the original object in the new process when the two processes have shared memory access. Thus, the remote version does not need to communicate with the original process to carry out its functions.

While the IStorage and IStream interfaces are used to deal with the storage object and its elements, the IPersistStorage interface actually serializes the storage object and its elements to a disk file.

Methods VTable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments the reference count.
Release	Decrements the reference count.
IStorage Methods	Description
CreateStream	Creates and opens a stream object with the specified name contained in this storage object.
OpenStream	Opens an existing stream object within this storage object using the specified access permissions in grfMode.
CreateStorage	Creates and opens a new storage object within this storage object.
OpenStorage	Opens an existing storage object with the specified name according to the specified access mode.
CopyTo	Copies the entire contents of this open storage object into another storage object. The layout of the destination storage object may differ.
MoveElementTo	Copies or moves a substorage or stream from this storage object to another storage object.
Commit	Reflects changes for a transacted storage object to the parent level.
Revert	Discards all changes that have been made to to the storage object since the last commit operation.
EnumElements	Returns an enumerator object that can be used to enumerate the storage and stream objects contained within this storage object.
DestroyElement	Removes the specified element from this storage object.
RenameElement	Renames the specified element in this storage object.
SetElementTimes	Sets the modification, access, and creation times of the indicated storage element, if supported by the underlying file system.
SetClass	Assigns the specified CLSID to this storage object.
SetStateBits	Stores up to 32 bits of state information in this storage object.
Stat	Returns the STATSTG structure for this open storage object.


IStorage::Commit

Ensures that any changes made to a storage object open in transacted mode are reflected in the parent storage. If the storage object is the root storage, the IStorage::Commit method reflects the changes in the actual device, for example, a file on disk. If the storage object is the root storage and is open in direct mode, this method has no effect except for flushing all memory buffers to the disk. For non-root storage objects in direct mode, this method has no effect.

HRESULT Commit(

DWORD grfCommitFlags	//Specifies how changes are to be committed
);
Parameter

grfCommitFlags

[in]Controls how the changes are committed to the storage object. See the STGC enumeration for a definition of these values.

Return Values

S_OK

Changes to the storage object were successfully committed to the parent level.

STG_E_INVALIDFLAG

The value for the grfCommitFlags parameter is not valid.

STG_E_INVALIDPARAMETER

One of the parameters was not valid.

STG_E_NOTCURRENT

Another open instance of the storage object has committed changes. Thus, the current commit operation may overwrite previous changes.

STG_E_MEDIUMFULL

No space left on device to commit.

STG_E_TOOMANYOPENFILES

The commit operation could not be completed because there are too many open files.

STG_E_REVERTED

The storage object has been invalidated by a revert operation above it in the transaction tree.

Comments

Storage objects can be opened in direct or transacted mode. In direct mode, changes are immediately reflected in the storage object. In transacted mode, changes are accumulated and are not reflected in the storage object until an explicit commit operation is done. The commit operation publishes the currently known changes in this storage object and its children to the next higher level in the storage hierarchy. Transacted mode allows an efficient way to revert to a previous version undoing changes prior to the commit operation.

Changes that have been made to this storage object since it was opened or since the last commit operation are reflected in the storage object. The changes are published to the next level of the storage hierarchy. If the parent is opened in transacted mode, the parent may still revert at a later time, rolling back the changes to this storage object.

Calling IStorage::Commit has no effect on currently-opened nested elements of this storage object. They are still valid and can be used. However, the IStorage::Commit method does not automatically commit changes to these nested elements. The commit operation publishes only known changes to the next higher level of the storage hierarchy. Thus, transactions to nested levels must be committed to this storage object before they can be committed to higher levels.

For storage objects opened in direct mode, the commit operation does nothing except in the case of a root storage object. In this case, the commit operation is similar to a flush buffer operation ensuring that changes in memory buffers are written to the underlying storage device.

In commit operations, steps must be taken to ensure the robustness of data during the commit process:

•	When committing changes to root storage objects, the caller must take care to ensure that the operation successfully completes or that, when failing, the old committed contents of the IStorage are still intact and can be restored.

•	If this storage object was opened with some of its items excluded, then the caller is responsible for rewriting them before calling commit. Write mode is required on the storage opening for the commit to succeed.

•	Unless they prohibit multiple simultaneous writers on the same storage object, applications will usually want to specify at least STGC_ONLYIFCURRENT in the grfCommitFlags parameter to prevent the changes made by one writer from inadvertently overwriting the changes made by another.

Note to Callers

The OLE-provided compound files use a two phase commit process unless STGC_OVERWRITE is specified in the grfCommitFlags parameter. This two-phase process ensures the robustness of data in case the commit operation fails. First, all new data is written to unused space in the underlying file. If necessary, new space is allocated to the file. Once this step has been successfully completed, a table in the file is updated using a single sector write to indicate that the new data is to be used in place of the old. The old data becomes free space to be used at the next commit. Thus, the old data is available and can be restored in case an error occurs when committing changes. If STGC_OVERWRITE is specified, a single phase commit operation is used.

See Also

STGC, IStorage::Revert


IStorage::CopyTo

Copies the entire contents of this open storage object into another storage object.

HRESULT CopyTo(

DWORD ciidExclude,	//Number of elements in rgiidExclude
IID const * rgiidExclude,	//Array of interface identifiers (IIDs)
SNB snbExclude,	//Points to a block of stream names in the storage object
IStorage * pstgDest	//Points to destination storage object
);
Parameters

ciidExclude

[in]The number of elements in the array pointed to by rgiidExclude. If rgiidExclude is NULL, then ciidExclude is ignored.

rgiidExclude

[in]Specifies an array of interface identifiers the caller takes responsibility for copying from the source to the destination. This array can include interfaces that this storage object does not support. It can be NULL, indicating that all other interfaces are to be copied. If non-NULL, an array length of zero indicates that no other interfaces are to be copied, only the state exposed by the IStorage object.

snbExclude

[in]Specifies a block of elements in this storage object that are not to be copied to the destination. These elements are not created in the destination. If IID_IStorage is in the rgiidExclude array, then this parameter is ignored. This parameter may be NULL.

pstgDest

[in]Points to the open storage object into which this storage object is to be copied. The destination storage object can be a different implementation of the IStorage interface from the source storage object. Thus, IStorage::CopyTo can only use publicly available methods of the destination storage object. If pstgDest is open in transacted mode, it can be reverted by calling its IStorage::Revert method.

Return Values

S_OK

The storage object was successfully copied.

STG_S_DESTLACKSINTERFACE

The destination lacks an interface that the source requested to be copied. The lack of an interface does not prevent other parts of the copy operation to be successfully completed.

STG_E_ACCESSDENIED

The destination storage object is a child of the source storage object.

STG_E_INSUFFICIENTMEMORY

The copy was not completed due to a lack of memory.

STG_E_INVALIDPOINTER

The pointer specified for the storage object was invalid.

STG_E_INVALIDPARAMETER

One of the parameters was invalid.

STG_E_TOOMANYOPENFILES

The copy was not completed because there are too many open files.

STG_E_MEDIUMFULL

The copy was not completed because the storage medium is full.

Comments

This method merges elements contained in the source storage object with those already present in the destination. The layout of the destination storage object may differ from the source storage object.

The copy process is recursive, invoking IStorage::CopyTo and IStream::CopyTo on the elements nested inside the source.

If an attempt is made to copy a stream on top of an existing stream with the same name, the existing destination stream is first removed and then replaced with the source stream. Attempting to copy a source storage object on top of an existing destination storage object does not remove the existing storage. Thus, after the copy operation, the destination IStorage contains older elements if they were not replaced by newer ones.

Note to Callers

The following example illustrates using the CopyTo method to copy everything possible from the source to the destination:

pstg->CopyTo(0, Null, Null, pstgDest)

This is the most commonly used form of this operation, used in most Full Save and SaveAs scenarios.

See Also

IStorage::MoveElementTo, IStorage::Revert


IStorage::CreateStorage

Creates and opens a new storage object nested within this storage object.

HRESULT CreateStorage(

const wchar_t * pwcsName,	//Points to the name of the new storage object
DWORD grfMode,	//Access mode for the new storage object
DWORD reserved1,	//Reserved; must be zero
DWORD reserved2,	//Reserved; must be zero
IStorage ** ppstg	//Points to new storage object
);
Parameters

pwcsName

[in]Points to the name of the newly created storage object. This name can be used later to open or reopen the storage object.

grfMode

[in]Specifies the access mode to use when opening the newly created storage object. See the STGM enumeration values for descriptions of the possible values.

reserved1

[in]Reserved for future use; must be zero.

reserved2

[in]Reserved for future use; must be zero.

ppstg

[out]Points to the location where the new IStorage interface pointer is returned; only valid if the operation is successful. This parameter is set to NULL if an error occurs.

Return Values

S_OK

The storage object was created successfully.

STG_E_ACCESSDENIED

Insufficient permissions to create storage object.

STG_E_FILEALREADYEXISTS

The name specified for the storage object already exists in the storage object and the grfmode flag includes the flag STGM_FAILIFTHERE.

STG_E_INSUFFICIENTMEMORY

The storage object was not created due to a lack of memory.

STG_E_INVALIDFLAG

The value specified for the grfMode flag is not a valid STGM enumeration value.

STG_E_INVALIDFUNCTION

The specified combination of grfMode flags is not supported.

STG_E_INVALIDNAME

Invalid value for pwcsName.

STG_E_INVALIDPOINTER

The pointer specified for the storage object was invalid.

STG_E_INVALIDPARAMETER

One of the parameters was invalid.

STG_E_REVERTED

The object has been invalidated by a revert operation above it in the transaction tree.

STG_E_TOOMANYOPENFILES

The storage object was not created because there are too many open files.

STG_S_CONVERTED

The existing stream with the specified name was replaced with a new storage object containing a single stream called CONTENTS. The new storage object will be added.

Comments

If an element with the name specified in the pwcsName parameter already exists and the grfMode parameter includes the STGM_CREATE flag, the existing element is replaced by the new storage object. If the grfMode parameter includes the STGM_CONVERT flag, the existing element is converted to a stream object named CONTENTS and the new storage object is created containing the CONTENTS stream object. The destruction of the old element and the creation of the new storage object are both subject to the transaction mode on the parent storage object.

If the storage object already exists and grfMode is set to STGM_FAILIFTHERE, this method fails with the return value STG_E-FILEALREADYEXISTS.

Note to Callers

The OLE-provided compound file implementation of the IStorage::CreateStorage method does not support the STGM_DELETEONRELEASE flag. Other implementations of IStorage might support this flag.

See Also

IStorage::OpenStorage


IStorage::CreateStream

Creates and opens a stream object with the specified name contained in this storage object. All elements within a storage object — including both streams and other storage objects — are kept in the same name space.

HRESULT CreateStream(

const wchar_t * pwcsName,	//Points to the name of the new stream
DWORD grfMode,	//Access mode for the new stream
DWORD reserved1,	//Reserved; must be zero
DWORD reserved2,	//Reserved; must be zero
IStream ** ppstm	//Points to new stream object
);
Parameters

pwcsName

[in]Points to the name of the newly created stream. This name can be used later to open or reopen the stream.

grfMode

[in]Specifies the access mode to use when opening the newly created stream. See the STGM enumeration values for descriptions of the possible values.

reserved1

[in]Reserved for future use; must be zero.

reserved2

[in]Reserved for future use; must be zero.

ppstm

[out]Points to the location where the new IStream interface pointer is returned; only valid if the operation is successful. This parameter is set to NULL if an error occurs.

Return Values

S_OK

The new stream was successfully created

STG_E_ACCESSDENIED

Insufficient permissions to create stream.

STG_E_FILEALREADYEXISTS

The name specified for the stream already exists in the storage object and the grfmode flag includes the flag STGM_FAILIFTHERE.

STG_E_INSUFFICIENTMEMORY

The stream was not created due to a lack of memory.

STG_E_INVALIDFLAG

The value specified for the grfMode flag is not a valid STGM enumeration value.

STG_E_INVALIDFUNCTION

The specified combination of grfMode flags is not supported. For example, if this method is called without the STGM_SHARE_EXCLUSIVE flag.

STG_E_INVALIDNAME

Invalid value for pwcsName.

STG_E_INVALIDPOINTER

The pointer specified for the stream object was invalid.

STG_E_INVALIDPARAMETER

One of the parameters was invalid.

STG_E_REVERTED

The object has been invalidated by a revert operation above it in the transaction tree.

STG_E_TOOMANYOPENFILES

The stream was not created because there are too many open files.

Comments

If a stream with the name specified in the pwcsName parameter already exists and the grfMode parameter includes the STGM_CREATE flag, the existing stream is replaced by a newly created one. The destruction of the old stream and the creation of the new stream object are both subject to the transaction mode on the parent storage object.

If the stream already exists and grfMode is set to STGM_FAILIFTHERE, this method fails with the return value STG_E_FILEALREADYEXISTS.

Note to Callers

The OLE-provided compound file implementation of the IStorage::CreateStream method does not support the following behaviors:

•	The STGM_DELETEONRELEASE flag is not supported.

•	Transacted mode is not supported for stream objects.

•	Opening the same stream more than once from the same storage is not supported. The STGM_SHARE_EXCLUSIVE flag must be specified.

Other implementations of IStorage might support these features.

See Also

IStorage::OpenStream, IStream


IStorage::DestroyElement

Removes the specified element from this storage object.

HRESULT DestroyElement(

const wchar_t * pwcsName	//Points to the name of the element to be removed
);
Parameter

pwcsName

[in]Points to the name of the element to be removed from this storage object.

Return Values

S_OK

The element was successfully removed.

STG_E_ACCESSDENIED

The caller does not have sufficient permissions for removing the element.

STG_E_FILENOTFOUND

The element with the specified name does not exist.

STG_E_INSUFFICIENTMEMORY

The element was not removed due to a lack of memory.

STG_E_INVALIDNAME

Invalid value for pwcsName.

STG_E_INVALIDPOINTER

The pointer specified for the element was invalid.

STG_E_INVALIDPARAMETER

One of the parameters was invalid.

STG_E_REVERTED

The object has been invalidated by a revert operation above it in the transaction tree.

STG_E_TOOMANYOPENFILES

The element was not removed because there are too many open files.

Comments

An existing open instance of this element from the parent becomes invalid after the IStorage::DestroyElement call completes.

The removal is subject to committing the changes if the storage object is opened in transacted mode.


IStorage::EnumElements

Returns an enumerator object that can be used to enumerate the storage and stream objects contained within this storage object.

HRESULT EnumElements(

DWORD reserved1,	//Reserved; must be zero
void * reserved2,	//Reserved; must be NULL
DWORD reserved3,	//Reserved; must be zero
IEnumSTATSTG ** ppenum	//Location for IEnumSTATSTG
);
Parameters

reserved1

[in]Reserved for future use; must be zero.

reserved2

[in]Reserved for future use; must be NULL.

reserved3

[in]Reserved for future use; must be zero.

ppenum

[out]Points to the location where the new enumerator object should be returned.

Return Values

S_OK

The enumerator object was successfully returned.

STG_E_INSUFFICIENTMEMORY

The enumerator object could not be created due to lack of memory.

STG_E_INVALIDPARAMETER

One of the parameters was not valid.

STG_E_REVERTED

The object has been invalidated by a revert operation above it in the transaction tree.

Comments

The enumerator object returned by this method implements the IEnumSTATSTG interface, one of the standard enumerator interfaces that contain the Next, Reset, Clone, and Skip methods. IEnumSTATSTG enumerates the data stored in an array of STATSTG structures.

The storage object must be open in read mode to allow the enumeration of its elements.

The order in which the elements are enumerated and whether the enumerator is a snapshot or always reflects the current state of the storage object, depends on the IStorage implementation. The OLE-provided compound file implementation takes a snapshot.

See Also

IEnumXXXX, IEnumSTATSTG, STATSTG


IStorage::MoveElementTo

Copies or moves a substorage or stream from this storage object to another storage object.

HRESULT MoveElementTo(

const wchar_t pwcsName,	//Name of the element to be moved
IStorage * pstgDest,	//Points to destination storage object
LPWSTR pwcsNewName,	//Points to new name of element in destination
DWORD grfFlags	//Specifies a copy or a move
);
Parameters

pwcsName

[in]Specifies the name of the element in this storage object to be moved or copied.

pstgDest

[in]Points to the destination storage object.

pwcsNewName

[in]Points to the new name for the element in its new storage object.

grfFlags

[in]Specifies whether the operation should be a move (STGMOVE_MOVE) or a copy (STGMOVE_COPY). See the STGMOVE enumeration.

Return Values

S_OK

The storage object was successfully copied or moved.

STG_E_ACCESSDENIED

The destination storage object is a child of the source storage object.

STG_E_FILENOTFOUND

The element with the specified name does not exist.

STG_E_FILEALREADYEXISTS

The specified file already exists.

STG_E_INSUFFICIENTMEMORY

The copy or move was not completed due to a lack of memory.

STG_E_INVALIDFLAG

The value for the grfFlags parameter is not valid.

STG_E_INVALIDNAME

Invalid value for pwcsName.

STG_E_INVALIDPOINTER

The pointer specified for the storage object was invalid.

STG_E_INVALIDPARAMETER

One of the parameters was invalid.

STG_E_REVERTED

The object has been invalidated by a revert operation above it in the transaction tree.

STG_E_TOOMANYOPENFILES

The copy or move was not completed because there are too many open files.

Comments

The IStorage::MoveElementTo method is typically the same as invoking the IStorage::CopyTo method on the indicated element and then removing the source element. In this case, the MoveElementTo method uses only the publicly available functions of the destination storage object to carry out the move.

If the source and destination storage objects have special knowledge about each other's implementation (for example, they could be different instances of the same implementation), this operation can be implemented efficiently.

See Also

STGMOVE, IStorage::CopyTo


IStorage::OpenStorage

Opens an existing storage object with the specified name according to the specified access mode.

HRESULT OpenStorage(

const wchar_t * pwcsName,	//Points to the name of the storage object to open
IStorage * pstgPriority,	//Points to previous opening of the storage object
DWORD grfMode,	//Access mode for the new storage object
SNB snbExclude,	//Points to a block of stream names in the storage object
DWORD reserved,	//Reserved; must be zero
IStorage ** ppstg	//Points to opened storage object
);
Parameters

pwcsName

[in]Points to the name of the storage object to open. It is ignored if pstgPriority is non-NULL.

pstgPriority

[in]If the pstgPriority parameter is not NULL, it is a pointer to a previous opening of an element of the storage object, usually one that was opened in priority mode. The storage object should be closed and re-opened according to grfMode. When the IStorage::OpenStorage method returns, pstgPriority is no longer valid. Use the value returned in the ppstg parameter. If the pstgPriority parameter is NULL, it is ignored.

grfMode

[in]Specifies the access mode to use when opening the storage object. See the STGM enumeration values for descriptions of the possible values.

snbExclude

[in]Either NULL or a non-NULL value that points to a block of stream names in this storage object that are to be emptied as the object is opened. This exclusion happens independent of whether a snapshot copy happens on the open.

reserved

[in]Reserved for future use; must be zero.

ppstg

[out]Points to the location where the IStorage interface pointer is returned; only valid if the operation is successful. This parameter is set to NULL if an error occurs.

Return Values

S_OK

The storage object was opened successfully.

STG_E_ACCESSDENIED

Insufficient permissions to open storage object.

STG_E_FILENOTFOUND

The storage object with the specified name does not exist.

STG_E_INSUFFICIENTMEMORY

The storage object was not opened due to a lack of memory.

STG_E_INVALIDFLAG

The value specified for the grfMode flag is not a valid STGM enumeration value.

STG_E_INVALIDFUNCTION

The specified combination of grfMode flags is not supported.

STG_E_INVALIDNAME

Invalid value for pwcsName.

STG_E_INVALIDPOINTER

The pointer specified for the storage object was invalid.

STG_E_INVALIDPARAMETER

One of the parameters was invalid.

STG_E_REVERTED

The object has been invalidated by a revert operation above it in the transaction tree.

STG_E_TOOMANYOPENFILES

The storage object was not created because there are too many open files.

STG_S_CONVERTED

The existing stream with the specified name was replaced with a new storage object containing a single stream called CONTENTS. The new storage object will be added.

Comments

Root storage objects can be opened with STGM_DELETEONRELEASE, in which case the object is destroyed when it receives its final release. This is useful for creating temporary storage objects.

Note to Callers

The OLE-provided compound file implementation of the IStorage::OpenStorage method does not support the following behaviors:

•	The STGM_PRIORITY flag is not supported for non-root storages.

•	Opening the same storage object more than once from the same parent storage is not supported. The STGM_SHARE_EXCLUSIVE flag must be specified.

Other implementations of IStorage might support these features.

See Also

IStorage::CreateStorage


IStorage::OpenStream

Opens an existing stream object within this storage object using the specified access permissions in grfMode.

HRESULT OpenStream(

const wchar_t * pwcsName,	//Points to name of stream to open
void * reserved1,	//Reserved; must be NULL
DWORD grfMode,	//Access mode for the new stream
DWORD reserved2,	//Reserved; must be zero
IStream ** ppstm	//Points to opened stream object
);
Parameters

pwcsName

[in]Points to the name of the stream to open.

reserved1

[in]Reserved for future use; must be NULL.

grfMode

[in]Specifies the access mode to use when opening the stream. See the STGM enumeration values for descriptions of the possible values.

reserved2

[in]Reserved for future use; must be zero.

ppstm

[out]Points to the location where the opened IStream interface pointer is returned; only valid if the operation is successful. This parameter is set to NULL if an error occurs.

Return Values

S_OK

The stream was successfully opened.

STG_E_ACCESSDENIED

Insufficient permissions to open stream.

STG_E_FILENOTFOUND

The stream with specified name does not exist.

STG_E_INSUFFICIENTMEMORY

The stream was not opened due to a lack of memory.

STG_E_INVALIDFLAG

The value specified for the grfMode flag is not a valid STGM enumeration value.

STG_E_INVALIDFUNCTION

The specified combination of grfMode flags is not supported. For example, if this method is called without the STGM_SHARE_EXCLUSIVE flag.

STG_E_INVALIDNAME

Invalid value for pwcsName.

STG_E_INVALIDPOINTER

The pointer specified for the stream object was invalid.

STG_E_INVALIDPARAMETER

One of the parameters was invalid.

STG_E_REVERTED

The object has been invalidated by a revert operation above it in the transaction tree.

STG_E_TOOMANYOPENFILES

The stream was not opened because there are too many open files.

Comments

There are restrictions on the permissions that can be given in grfMode. For example, the permissions on this storage object restrict the permissions on its streams.

Note to Callers

The OLE-provided compound file implementation of the IStorage::OpenStream method does not support the following behaviors:

•	The STGM_DELETEONRELEASE flag is not supported.

•	Transacted mode is not supported for stream objects.

•	Opening the same stream more than once from the same storage is not supported. The STGM_SHARE_EXCLUSIVE flag must be specified.

Other implementations of IStorage might support these features.

See Also

IStorage::CreateStream, IStream


IStorage::RenameElement

Renames the specified element in this storage object.

HRESULT RenameElement(

const wchar_t * pwcsOldName,	//Points to the name of the element to be changed
const wchar_t * pwcsNewName	//Points to the new name for the specified element
);
Parameters

pwcsOldName

[in]Points to the name of the element to be changed.

pwcsNewName

[in]Points to the new name for the specified element.

Return Values

S_OK

The element was successfully renamed.

STG_E_ACCESSDENIED

The caller does not have sufficient permissions for renaming the element.

STG_E_FILENOTFOUND

The element with the specified old name does not exist.

STG_E_FILEALREADYEXISTS

The element specified by the new name already exists.

STG_E_INSUFFICIENTMEMORY

The element was not renamed due to a lack of memory.

STG_E_INVALIDNAME

Invalid value for one of the names.

STG_E_INVALIDPOINTER

The pointer specified for the element was invalid.

STG_E_INVALIDPARAMETER

One of the parameters was invalid.

STG_E_REVERTED

The object has been invalidated by a revert operation above it in the transaction tree.

STG_E_TOOMANYOPENFILES

The element was not renamed because there are too many open files.

Comments

An element in a storage object cannot be renamed while it is open. The rename operation is subject to committing the changes if the storage is open in transacted mode.

The IStorage::RenameElement method is not guaranteed to work in low memory with storage objects open in transacted mode. It may work in direct mode.


IStorage::Revert

Discards all changes that have been made to the storage object since the last commit.

HRESULT Revert(void);

Return Values

S_OK

The revert operation was successful.

STG_E_INSUFFICIENTMEMORY

The revert operation could not be completed due to a lack of memory.

STG_E_TOOMANYOPENFILES

The revert operation could not be completed because there are too many open files.

STG_E_REVERTED

The object has been invalidated by a revert operation above it in the transaction tree.

Comments

For storage objects opened in transacted mode, the IStorage::Revert method discards any uncommitted changes to this storage object or changes that have been committed to this storage object from nested elements.

After this method finishes, any existing elements that were opened from the reverted storage object are invalid and can no longer be used. The error STG_E_REVERTED is returned on all calls except IStorage::Release using these openings.

For storage objects opened in direct mode, this method has no effect.

See Also

IStorage::Commit


IStorage::SetClass

Assigns the specified CLSID to this storage object.

HRESULT SetClass(

REFCLSID clsid	//Class identifier to be assigned to the storage object
);
Parameter

clsid

[in]The class identifier that is to be associated with the storage object.

Return Values

S_OK

The CLSID was successfully assigned.

STG_E_ACCESSDENIED

The caller does not have sufficient permissions for assigning a class identifier to the storage object.

STG_E_MEDIUMFULL

Not enough space was left on device to complete the operation.

STG_E_REVERTED

The object has been invalidated by a revert operation above it in the transaction tree.

Comments

When first created, a storage object has an associated CLSID of CLSID_NULL. You call this method to assign a class identifier to the storage object.

You can retrieve the current CLSID of a storage object with the IStorage::Stat method.

See Also

IStorage::Stat


IStorage::SetElementTimes

Sets the modification, access, and creation times of the specified storage element, if supported by the underlying file system.

HRESULT SetElementTimes(

const wchar_t * pwcsName,	//Points to name of element to be changed
FILETIME const * pctime,	//New creation time for element, or NULL
FILETIME const * patime,	//New access time for element, or NULL
FILETIME const * pmtime	//New modification time for element, or NULL
);
Parameters

pwcsName

[in]The name of the storage object element whose times are to be modified. If NULL, the time is set on the root storage rather than one of its elements.

pctime

[in]Either the new creation time for the element or NULL if the creation time is not to be modified.

patime

[in]Either the new access time for the element or NULL if the access time is not to be modified.

pmtime

[in]Either the new modification time for the element or NULL if the modification time is not to be modified.

Return Values

S_OK

The time values were successfully set.

STG_E_ACCESSDENIED

The caller does not have sufficient permissions for changing the element.

STG_E_FILENOTFOUND

The element with the specified name does not exist.

STG_E_INSUFFICIENTMEMORY

The element was not changed due to a lack of memory.

STG_E_INVALIDNAME

Invalid value for the element name.

STG_E_INVALIDPOINTER

The pointer specified for the element was invalid.

STG_E_INVALIDPARAMETER

One of the parameters was invalid.

STG_E_REVERTED

The object has been invalidated by a revert operation above it in the transaction tree.

STG_E_TOOMANYOPENFILES

The element was not changed because there are too many open files.

Comments

This method sets time statistics for the specified storage element within this storage object.

Not all file systems support all of the time values. This method sets those times that are supported and ignores the rest. Each of the time value parameters can be NULL; indicating that no modification should occur.

You can retrieve these time values with the IStorage::Stat method.

Note to Callers

The OLE-provided compound file implementation maintains modification and change times for internal storage objects. For root storage objects, whatever is supported by the underlying file system (or ILockBytes) is supported. The compound file implementation does not maintain any time stamps for internal streams. Unsupported time stamps are reported as zero, enabling the caller to test for support.

See Also

IStorage::Stat


IStorage::SetStateBits

Stores up to 32 bits of state information in this storage object.

HRESULT SetStateBits(

DWORD grfStateBits,	//Specifies new values of bits
DWORD grfMask	//Specifies mask that indicates which bits are significant
);
Parameters

grfStateBits

[in]Specifies the new values of the bits to set. No legal values are defined for these bits; they are all reserved for future use and must not be used by applications. See the STGSTATE enumeration for a definition of these values.

grfMask

[in]A binary mask indicating which bits in grfStateBits are significant in this call. See the STGSTATE enumeration for a definition of these values.

Return Values

S_OK

The state information was successfully set.

STG_E_ACCESSDENIED

The caller does not have sufficient permissions for changing this storage object.

STG_E_INVALIDFLAG

The value for the grfStateBits or grfMask parameters are not valid.

STG_E_INVALIDPARAMETER

One of the parameters was invalid.

Comments

You can retrieve the state information with the IStorage::Stat method. When a storage object is first created, the value of this state information is zero. The values for the state bits are not defined currently and should not be used by applications.

The state set by this method is for external use only. The OLE-provided compound file implementation does not perform any action based on the state.

See Also

STATSTATE, IStorage::Stat


IStorage::Stat

Returns the STATSTG structure for this open storage object.

HRESULT Stat(

STATSTG * pstatstg,	//Location for STATSTG structure
DWORD grfStatFlag	//Values taken from the STATFLAG enumeration
);
Parameters

pstatstg

[out]Points to a STATSTG structure where this method places information about the open storage object. This parameter is NULL if an error occurs.

grfStatFlag

[in]Specifies that some of the fields in the STATSTG structure are not returned, thus saving a memory allocation operation. Values are taken from the STATFLAG enumeration.

Return Values

S_OK

The STATSTG structure was successfully returned at the specified location.

STG_E_ACCESSDENIED

The caller does not have sufficient permissions for accessing statistics for this storage object.

STG_E_INSUFFICIENTMEMORY

The STATSTG structure was not returned due to a lack of memory.

STG_E_INVALIDFLAG

The value for the grfStateFlag parameter is not valid.

STG_E_INVALIDPARAMETER

One of the parameters was invalid.

See Also

STATFLAG, STATSTG, IStorage::SetClass, IStorage::SetElementTimes, IStorage::SetStateBits


IStream

The IStream interface supports reading and writing data to stream objects. Stream objects are elements nested within a storage object. They are similar to standard files. You use stream objects to store the data for your application.

The IStream interface provides methods similar to the MS-DOS FAT file functions. For example, each stream object has its own access rights and a seek pointer. The main difference between a stream object and a DOS file is that streams are not open using a file handle. Instead, you use the IStream interface pointer.

The methods in this interface present your object data as a contiguous sequence of bytes which you can read or write. There are also methods for committing and reverting changes on streams open in transacted mode and methods for restricting access to a range of bytes in the stream.

Streams can remain open for long periods of time without consuming file system resources. The IStream::Release method is similar to a close function on a file. Once released, the stream object is no longer valid and cannot be used.

When to Implement

OLE provides an implementation of the IStream interface that you can use for saving object data. The specification of IStream defines more functionality that the OLE implementation supports. For example, the IStream interface defines streams up to 2 (64)  bytes in length requiring a 64-bit seek pointer. However, the OLE implementation only supports streams up to 2 (32)  bytes in length and read and write operations are always limited to 2 (32)  bytes at a time. The OLE implementation also does not support stream transactioning or region locking.

Container or object applications can implement their own stream objects instead of using the OLE-provided implementation.

When to Use

If you are writing an object application, you can use the IStream interface to store the data for your object.

Since stream objects can be marshaled to other processes, applications can share the data in storage objects without having to use global memory. For the OLE-provided implementation of stream objects, the custom marshaling facilities in OLE create a remote version of the original object in the new process when the two processes have shared memory access. Thus, the remote version does not need to communicate with the original process to carry out its functions.

The remote version of the stream object shares the same seek pointer as the original stream. If you do not want to share the seek pointer, you should use the IStream::Clone method to provide a copy of the stream object for the remote process.

Note  If you are creating a stream object that is larger than the heap in your machine's memory and you are using an HGLOBAL, the stream object calls GlobalRealloc internally whenever it needs more memory. Because GlobalRealloc always copies data from the source to the destination, increasing a stream object from 20M to 25M, for example, consumes immense amounts of time. This is due to the size of the increments copied and is worsened if there is less than 45M of memory on the machine because of disk swapping.

The preferred solution is to implement an IStream that uses memory allocated by VirtualAlloc instead of GlobalAlloc. This can reserve a large chunk of virtual address space and then commit memory within that address space as required. No data copying occurs and memory is committed only as it is needed.

Another alternative is to call the IStream::SetSize method on the stream object to increase the memory allocation in advance. This is not, however, as efficient as using VirtualAlloc as described above.

Methods in Vtable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments the reference count.
Release	Decrements the reference count.
IStream Methods	Description
Read	Reads a specified number of bytes from the stream object into memory starting at the current seek pointer.
Write	Writes a specified number from bytes into the stream object starting at the current seek pointer.
Seek	Changes the seek pointer to a new location relative to the beginning of the stream, the end of the stream, or the current seek pointer.
SetSize	Changes the size of the stream object.
CopyTo	Copies a specified number of bytes from the current seek pointer in the stream to the current seek pointer in another stream.
Commit	Ensures that any changes made to a stream object open in transacted mode are reflected in the parent storage object.
Revert	Discards all changes that have been made to a transacted stream since the last IStream::Commit call.
LockRegion	Restricts access to a specified range of bytes in the stream. Supporting this functionality is optional since some file systems do not provide it.
UnlockRegion	Removes the access restriction on a range of bytes previously restricted with IStream::LockRegion.
Stat	Retrieves the STATSTG structure for this stream.
Clone	Creates a new stream object that references the same bytes as the original stream but provides a separate seek pointer to those bytes.


IStream::Clone

Creates a new stream object with its own seek pointer that references the same bytes as the original stream.

HRESULT Clone(

IStream ** ppstm	//Points to location for pointer to the new stream object
);
Parameter

ppstm

[out]Points to location for the pointer to the new stream object. If an error occurs, this parameter is NULL.

Return Values

S_OK

The stream was successfully cloned.

STG_E_INSUFFICIENT_MEMORY

The stream was not cloned due to a lack of memory.

STG_E_INVALIDPOINTER

The ppStm pointer is not valid.

Comments

This method creates a new stream object for accessing the same bytes but using a separate seek pointer. The new stream object sees the same data as the source stream object. Changes written to one object are immediately visible in the other. Range locking is shared between the stream objects.

The initial setting of the seek pointer in the cloned stream instance is the same as the current setting of the seek pointer in the original stream at the time of the clone operation.

See Also

IStream::CopyTo


IStream::Commit

Ensures that any changes made to a stream object open in transacted mode are reflected in the parent storage. If the stream object is open in direct mode, IStream::Commit has no effect other than flushing all memory buffers to the next level storage object. The OLE-provided implementation of streams does not support opening streams in transacted mode.

HRESULT Commit(

DWORD grfCommitFlags	//Specifies how changes are committed
);
Parameter

grfCommitFlags

[in]Controls how the changes for the stream object are committed. See the STGC enumeration for a definition of these values.

Return Values

S_OK

Changes to the stream object were successfully committed to the parent level.

STG_E_MEDIUMFULL

The commit operation failed due to lack of space on the storage device.

Comments

This method ensures that changes to a stream object opened in transacted mode are reflected in the parent storage. Changes that have been made to the stream since it was opened or last committed are reflected to the parent storage object. If the parent is opened in transacted mode, the parent may still revert at a later time rolling back the changes to this stream object.

If the stream is open in direct mode, this method ensures that any memory buffers have been flushed out to the underlying storage object. This is much like a flush in traditional file systems.

The IStream::Commit method is useful on a direct mode stream when the implementation of the IStream interface is a wrapper for underlying file system APIs. In this case, IStream::Commit would be connected to the file system's flush call.

Notes to Callers

The OLE-provided implementation of stream objects does not support transacted streams. Also, stream objects only exist within storage objects in this implementation. Thus, the OLE implementation of IStream::Commit has no effect other than flushing internal memory buffers to the parent storage object. With this implementation, it does not matter if you commit changes to streams. You can just commit changes for storage objects.

See Also

IStorage::Commit


IStream::CopyTo

Copies a specified number of bytes from the current seek pointer in the stream to the current seek pointer in another stream.

HRESULT CopyTo(

IStream * pstm,	//Points to the destination stream
ULARGE_INTEGER cb,	//Specifies the number of bytes to copy
ULARGE_INTEGER * pcbRead,	//Pointer to the actual number of bytes read from the source
ULARGE_INTEGER * pcbWritten	//Pointer to the actual number of bytes written to the destination
);
Parameters

pstm

[in]Points to the destination stream. The stream pointed to by pstm can be a new stream or a clone of the source stream.

cb

[in]Specifies the number of bytes to copy from the source stream.

pcbRead

[out]Pointer to the location where this method writes the actual number of bytes read from the source. You can set this pointer to NULL to indicate that you are not interested in this value. In this case, this method does not provide the actual number of bytes read.

pcbWritten

[out]Pointer to the location where this method writes the actual number of bytes written to the destination. You can set this pointer to NULL to indicate that you are not interested in this value. In this case, this method does not provide the actual number of bytes written.

Return Values

S_OK

The stream object was successfully copied.

STG_E_INVALIDPOINTER

The value of one of the pointer parameters is not valid.

STG_E_MEDIUMFULL

The stream is not copied because there is no space left on the storage device.

Comments

This method copies the specified bytes from one stream to another. The seek pointer in each stream instance is adjusted for the number of bytes read or written. This method is equivalent to reading cb bytes into memory using IStream::Read and then immediately writing them to the destination stream using IStream::Write, although IStream::CopyTo will be more efficient.

The destination stream can be a clone of the source stream created by calling the IStream::Clone method.

If IStream::CopyTo returns an error, you cannot assume that the seek pointers are valid for either the source or destination. Additionally, the values of pcbRead and pcbWritten are not meaningful even though they are returned.

If IStream::CopyTo returns successfully, the actual number of bytes read and written are the same.

To copy the remainder of the source from the current seek pointer, specify the maximum large integer value for the cb parameter. If the seek pointer is the beginning of the stream, this techniques copies the entire stream.

See Also

IStream::Read, IStream::Write, IStream::Clone


IStream::LockRegion

Restricts access to a specified range of bytes in the stream. Supporting this functionality is optional since some file systems do not provide it.

HRESULT LockRegion(

ULARGE_INTEGER libOffset,	//Specifies the byte offset for the beginning of the range
ULARGE_INTEGER cb,	//Specifies the length of the range in bytes
DWORD dwLockType	//Specifies the restriction on accessing the specified range
);
Parameters

libOffset

[in]Specifies the byte offset for the beginning of the range.

cb

[in]Specifies, in bytes, the length of the range to be restricted.

dwLockType

[in]Specifies the restrictions being requested on accessing the range.

Return Values

S_OK

The specified range of bytes was locked.

STG_E_INVALIDFUNCTION

Locking is not supported at all or the specific type of lock requested is not supported.

STG_E_LOCKVIOLATION

Requested lock is supported, but cannot be granted because of an existing lock.

Comments

The byte range can extend past the current end of the stream. Locking beyond the end of a stream is useful as a method of communication between different instances of the stream without changing data that is actually part of the stream.

Three types of locking can be supported: locking to exclude other writers, locking to exclude other readers or writers, and locking that allows only one requestor to obtain a lock on the given range, which is usually an alias for one of the other two lock types. A given stream instance might support either of the first two types, or both. The lock type is specified by dwLockType, using a value from the LOCKTYPE enumeration.

Any region locked with IStream::LockRegion must later be explicitly unlocked by calling IStream::UnlockRegion with exactly the same values for the libOffset, cb, and dwLockType parameters. The region must be unlocked before the stream is released. Two adjacent regions cannot be locked separately and then unlocked with a single unlock call.

Notes to Callers

Since range locking is not supported by the OLE-provided implementation of streams, calling IStream::LockRegion has no effect for this implementation.

Since the type of locking supported is optional and can vary in different implementations of IStream, you must provide code to deal with the STG_E_INVALIDFUNCTION error.

Notes to Implementors

Support for this method is optional for implementations of stream objects since it may not be supported by the underlying file system. The type of locking supported is also optional. The STG_E_INVALIDFUNCTION error is returned if the requested type of locking is not supported.

See Also

LOCKTYPE, IStream::UnlockRegion


IStream::Read

Reads a specified number of bytes from the stream object into memory starting at the current seek pointer.

HRESULT Read(

void * pv,	//Pointer to buffer into which the stream is read
ULONG cb,	//Specifies the number of bytes to read
ULONG * pcbRead	//Pointer to location that contains actual number of bytes read
);
Parameters

pv

[in]Points to the buffer into which the stream is read. If an error occurs, this value is NULL.

cb

[in]Specifies the number of bytes of data to attempt to read from the stream object.

pcbRead

[out]Pointer to a location where this method writes the actual number of bytes read from the stream object. You can set this pointer to NULL to indicate that you are not interested in this value. In this case, this method does not provide the actual number of bytes read.

Return Values

S_OK

Data was successfully read from the stream object.

S_FALSE

The data could not be read from the stream object.

STG_E_ACCESSDENIED

The caller does not have sufficient permissions for reading this stream object.

STG_E_INVALIDPOINTER

One of the pointer values is invalid.

STG_E_REVERTED

The object has been invalidated by a revert operation above it in the transaction tree.

Comments

This method reads bytes from this stream object into memory. The stream object must be opened in STGM_READ mode. This method adjusts the seek pointer by the actual number of bytes read.

The number of bytes actually read is returned in the pcbRead parameter.

Notes to Callers

The actual number of bytes read can be fewer than the number of bytes requested if an error occurs or if the end of the stream is reached during the read operation.

The OLE-provided implementation of IStream returns S_OK if the end of the stream was reached during the read. (This is the same as the "end of file" behavior found in the MS-DOS FAT file system.

Some implementations might return an error if the end of the stream is reached during the read. You must be prepared to deal with the error return or S_OK return values on end of stream reads.

See Also

STGMOVE, IStorage::OpenStream, IStream::Write


IStream::Revert

Discards all changes that have been made to a transacted stream since the last IStream::Commit call. For streams open in direct mode and streams using the OLE implementation of IStream::Revert, this method has no effect.

HRESULT Revert(void);

Return Values

S_OK

The stream was successfully reverted to its previous version.

STG_E_REVERTED

The object has been invalidated by a revert operation above it in the transaction tree.

Comments

This method discards changes made to a transacted stream since the last commit operation.

The OLE-provided implementation does not support transacted streams, and this method has no effect in that implementation.

See Also

IStream::Commit


IStream::Seek

Changes the seek pointer to a new location relative to the beginning of the stream, to the end of the stream, or to the current seek pointer.

HRESULT Seek(

LARGE_INTEGER dlibMove,	//Offset relative to dwOrigin
DWORD dwOrigin,	//Specifies the origin for the offset
ULARGE_INTEGER * plibNewPosition	//Pointer to location containing new seek pointer
);
Parameters

dlibMove

[in]Displacement to be added to the location indicated by dwOrigin. If dwOrigin is STREAM_SEEK_SET, then this is interpreted as an unsigned value rather than signed.

dwOrigin

[in]Specifies the origin for the displacement specified in dlibMove. The origin can the be beginning of the file, the current seek pointer, or the end of the file. See the STREAM_SEEK enumeration for the values.

plibNewPosition

[out]Pointer to the location where this method writes the value of the new seek pointer from the beginning of the stream. You can set this pointer to NULL to indicate that you are not interested in this value. In this case, this method does not provide the new seek pointer.

Return Values

S_OK

The seek pointer has been successfully adjusted.

STG_E_INVALIDPOINTER

The value of the plibNewPosition parameter is not valid.

STG_E_INVALIDFUNCTION

The value of the dwOrigin parameter is not valid.

Comments

This method changes the seek pointer so subsequent reads and writes can take place at a different location in the stream object. It is an error to seek before the beginning of the stream. However, it is not an error to seek past the end of the stream. Seeking past the end of the stream is useful for subsequent writes, as the stream will at that time be extended to the seek position immediately before the write is done.

You can also use this method to obtain the current value of the seek pointer by calling this method with the dwOrigin parameter set to STREAM_SEEK_CUR and the dlibMove parameter set to 0 so the seek pointer is not changed. The current seek pointer is returned in the plibNewPosition parameter.

See Also

STREAM_SEEK, IStream::Read, IStream::Write


IStream::SetSize

Changes the size of the stream object.

HRESULT SetSize(

ULARGE_INTEGER libNewSize	//Specifies the new size of the stream object
);
Parameter

libNewSize

[in]Specifies the new size of the stream as a number of bytes.

Return Values

S_OK

The size of the stream object was successfully changed.

STG_E_MEDIUMFULL

The stream size is not changed because there is no space left on the storage device.

STG_E_INVALIDFUNCTION

The value of the libNewSize parameter is not valid. Since streams cannot be greater than 2 (32)  bytes in the OLE-provided implementation, the high DWORD of libNewSize must be 0. If it is nonzero, this parameter is not valid.

Comments

This method changes the size of the stream object. You can use this method to preallocate space for the stream. If the libNewSize parameteris larger than the current stream size, the stream is extended to the indicated size by filling the intervening space with bytes of undefined value. This operation is similar to the IStream::Write method if the seek pointer is past the current end-of-stream.

If the libNewSize parameter is smaller than the current stream, then the stream is truncated to the indicated size.

The seek pointer is not affected by the change in stream size.

Calling IStream::SetSize is an effective way of trying to obtain a large chunk of contiguous space. However, in the OLE-provided implementation of streams, there is no guarantee that the space will be contiguous.

See Also

IStream::Write


IStream::Stat

Retrieves the STATSTG structure for this stream.

HRESULT Stat(

STATSTG * pstatstg,	//Location for STATSTG structure
DWORD grfStatFlag	//Values taken from the STATFLAG enumeration
);
Parameters

pstatstg

[out]Points to a STATSTG structure where this method places information about this stream object. This pointer is NULL if an error occurs.

grfStatFlag

[in]Specifies that this method does not return some of the fields in the STATSTG structure, thus saving a memory allocation operation. Values are taken from the STATFLAG enumeration.

Return Value

S_OK

The STATSTG structure was successfully returned at the specified location.

STG_E_ACCESSDENIED

The caller does not have sufficient permissions for accessing statistics for this storage object.

STG_E_INSUFFICIENTMEMORY

The STATSTG structure was not returned due to a lack of memory.

STG_E_INVALIDFLAG

The value for the grfStateFlag parameter is not valid.

STG_E_INVALIDPOINTER

The pStatStg pointer is not valid.

See Also

STATFLAG, STATSTG


IStream::UnlockRegion

Removes the access restriction on a range of bytes previously restricted with IStream::LockRegion.

HRESULT UnlockRegion(

ULARGE_INTEGER libOffset,	//Specifies the byte offset for the beginning of the range
ULARGE_INTEGER cb,	//Specifies the length of the range in bytes
DWORD dwLockType	//Specifies the access restriction previously placed on the range
);
Parameters

libOffset

[in]Specifies the byte offset for the beginning of the range.

cb

[in]Specifies, in bytes, the length of the range to be restricted.

dwLockType

[in]Specifies the access restrictions previously placed on the range.

Return Values

S_OK

The byte range was unlocked.

STG_E_INVALIDFUNCTION

Locking is not supported at all or the specific type of lock requested is not supported.

STG_E_LOCKVIOLATION

The requested unlock cannot be granted.

Comments

This method unlocks a region previously locked with the IStream::LockRegion method. Locked regions must later be explicitly unlocked by calling IStream::UnlockRegion with exactly the same values for the libOffset, cb, and dwLockType parameters. The region must be unlocked before the stream is released. Two adjacent regions cannot be locked separately and then unlocked with a single unlock call.

See Also

LOCKTYPE, IStream::LockRegion


IStream::Write

Writes a specified number from bytes into the stream object starting at the current seek pointer.

HRESULT Write(

void const* pv,	//Pointer to buffer from which stream is written
ULONG cb,	//Specifies the number of bytes to write
ULONG * pcbWritten	//Specifies the actual number of bytes written
);
Parameters

pv

[in]Points to the buffer from which the stream should be written.

cb

[in]Specifies the number of bytes of data to attempt to write into the stream.

pcbWritten

[out]Pointer to a location where this method writes the actual number of bytes written to the stream object. You can set this pointer to NULL to indicate that you are not interested in this value. In this case, this method does not provide the actual number of bytes written.

Return Values

S_OK

The data was successfully written into the stream object.

STG_E_MEDIUMFULL

The write operation was not completed because there is no space left on the storage device.

STG_E_ACCESSDENIED

The caller does not have sufficient permissions for writing this stream object.

STG_E_CANTSAVE

Data cannot be written for reasons other than no access or space.

STG_E_INVALIDPOINTER

One of the pointer values is invalid.

STG_E_REVERTED

The object has been invalidated by a revert operation above it in the transaction tree.

STG_E_WRITEFAULT

The write operation was not completed due to a disk error.

Comments

This method writes the specified data to a stream object. The seek pointer is adjusted for the number of bytes actually written. The number of bytes actually written is returned in the pcbWrite parameter. If the byte count is zero bytes, the write operation has no effect.

If the seek pointer is currently past the end of the stream and the byte count is non-zero, this method increases the size of the stream to the seek pointer and writes the specified bytes starting at the seek pointer. The fill bytes written to the stream are not initialized to any particular value. This is the same as the end-of-file behavior in the MS-DOS FAT file system.

With a zero byte count and a seek pointer past the end of the stream, this method does not create the fill bytes to increase the stream to the seek pointer. In this case, you must call the IStream::SetSize method to increase the size of the stream and write the fill bytes.

Notes to Callers

In the OLE-provided implementation, stream objects are not sparse. Any fill bytes are eventually allocated on the disk and assigned to the stream.

The pcbWrite parameter can have a value even if an error occurs.


IUnknown

The IUnknown interface lets clients get pointers to other interfaces on a given object through the QueryInterface method, and manage the existence of the object through the IUnknown::AddRef and IUnknown::Release methods. All other COM interfaces are inherited, directly or indirectly, from IUnknown. Therefore, the three methods in IUnknown are the first entries in the VTable for every interface.

When to Implement

You must implement IUnknown as part of every interface. If you are using C++ multiple inheritance to implement multiple interfaces, the various interfaces can share one implementation of IUnknown. If you are using nested classes to implement multiple interfaces, you must implement IUnknown once for each interface you implement.

When to Use

Use IUnknown methods to switch between interfaces on an object, add references, and release objects.

Methods in Vtable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments reference count.
Release	Decrements reference count.


IUnknown::AddRef

The IUnknown::AddRef method increments the reference count for a the calling interface on an object. It should be called for every new copy of a pointer to an interface on a given object.

ULONG AddRef(void);

Return Value

Returns an integer from 1 to n, the value of the new reference count. This information is meant to be used for diagnostic/testing purposes only, because, in certain situations, the value may be unstable.

Comments

Objects use a reference counting mechanism to ensure that the lifetime of the object includes the lifetime of references to it. You use IUnknown::AddRef to stabilize a copy of an interface pointer. It can also be called when the life of a cloned pointer must extend beyond the lifetime of the original pointer. The cloned pointer must be released by calling IUnknown::Release.

Objects must be able to maintain (2 (31) )-1 outstanding pointer references. Therefore, the internal reference counter that IUnknown::AddRef maintains must be a 32-bit unsigned integer.

Notes to Callers

Call this function for every new copy of an interface pointer that you make. For example, if you are passing a copy of a pointer back from a function, you must call IUnknown::AddRef on that pointer. You must also call IUnknown::AddRef on a pointer before passing it as an in-out parameter to a function; the function will call IUnknown::Release before copying the out-value on top of it.

See Also

IUnknown::Release


IUnknown::QueryInterface

Returns a pointer to a specified interface on a component to which a client currently holds an interface pointer. This function must call IUnknown::AddRef on the pointer it returns.

HRESULT QueryInterface(

REFIID iid,	//Specifies the requested interface's IID
void ** ppvObject	//Receives an indirect pointer to the object
);
Parameters

iid

[in] Specifies the IID of the interface being requested.

ppvObject

[out] Receives a pointer to an interface pointer to the object on return. If the interface specified in riid is not supported by the object, ppvObj is set to NULL.

Return Value

S_OK if the interface is supported, S_FALSE if not.

Comments

The QueryInterface method gives a client access to other interfaces on an object.

For any one object, a specific query for the IUnknown interface on any of the object's interfaces must always return the same pointer value. This allows a client to determine whether two pointers point to the same component by calling QueryInterface on both and comparing the results. It is specifically not the case that queries for interfaces (even the same interface through the same pointer) must return the same pointer value.

There are four requirements for implementations of QueryInterface (In these cases, "must succeed" means "must succeed barring catastrophic failure."):

•	The set of interfaces accessible on an object through IUnknown::QueryInterface must be static, not dynamic. This means that if a call to QueryInterface for a pointer to a specified interface succeeds the first time, it must succeed again, and if it fails the first time, it must fail on all subsequent queries.

•	It must be symmetric — if a client holds a pointer to an interface on an object, and queries for that interface, the call must succeed.

•	It must be reflexive — if a client holding a pointer to one interface queries successfully for another, a query through the obtained pointer for the first interface must succeed.

•	It must be transitive — if a client holding a pointer to one interface queries successfully for a second, and through that pointer queries successfully for a third interface, a query for the first interface through the pointer for the third interface must succeed.


IUnknown::Release

Decrements the reference count for the calling interface on a object. If the reference count on the object falls to 0, the object is freed from memory.

ULONG Release(void);

Return Value

Returns the resulting value of the reference count, which is used for diagnostic/testing purposes only. If you need to know that resources have been freed, use an interface with higher-level semantics.

Comments

If IUnknown::AddRef has been called on this object's interface n times and this is the n+1th call to IUnknown::Release, the implementation of IUnknown::AddRef must cause the interface pointer to free itself. When the released pointer is the only existing reference to an object (whether the object supports single or multiple interfaces), the implementation must free the object.

Note  Aggregation of objects restricts the ability to recover interface pointers.

Notes to Callers

Call this function when you no longer need to use an interface pointer. If you are writing a function that takes an in-out parameter, call IUnknown::Release on the pointer you are passing in before copying the out-value on top of it.

See Also

IUnknown::AddRef


IViewObject

The IViewObject interface enables an object to display itself directly without passing a data object to the caller. In addition, this interface can create and manage a connection with an advise sink so the caller can be notified of changes in the view object.

The caller can request specific representations and specific target devices. For example, a caller can ask for either an object's content or an iconic representation. Also, the caller can ask the object to compose a picture for a target device that is independent of the drawing device context. As a result, the picture can be composed for one target device and drawn on another device context. For example, to provide a print preview operation, you can compose the drawing for a printer target device but actually draw the representation on the display.

The IViewObject interface is similar to IDataObject; except that IViewObject places a representation of the data onto a device context while IDataObject places the representation onto a transfer medium.

Unlike most other interfaces, IViewObject cannot be marshaled to another process. This is because device contexts are only effective in the context of one process.

When to Implement

Object handlers and in-process servers that manage their own presentations implement IViewObject for use by compound document containers. OLE provides an IViewObject implementation for its default object handler's cache.

When to Use

You call IViewObject from a container application if you need to draw a contained object on a specific device context. For example, if you want to print the object to a printer, you call the Draw method in the IViewObject interface.

Methods in VTable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments the reference count.
Release	Decrements the reference count.
IViewObject Methods	Description
Draw	Draws a representation of the object onto a device context.
GetColorSet	Returns the logical palette the object uses for drawing.
Freeze	Freezes the drawn representation of an object so it will not change until a subsequent Unfreeze.
Unfreeze	Unfreezes the drawn representation of an object.
SetAdvise	Sets up a connection between the view object and an advise sink so that the advise sink can receive notifications of changes in the view object.
GetAdvise	Returns the information on the most recent SetAdvise.


IViewObject::Draw

Draws a representation of an object onto the specified device context.

HRESULT Draw(

DWORD dwAspect,	//Specifies how the object is to be represented
LONG lindex,	//Specifies the part of the object to draw
void * pvAspect,	//Always NULL
DVTARGETDEVICE * ptd,	//Specifies the target device in a structure
HDC hicTargetDev,	//Specifies the information context for the target device ptd
HDC hdcDraw,	//Identifies the device context on which to draw
const LPRECTL lprcBounds,	//Specifies the rectangle in which the object is drawn
const LPRECTL lprcWBounds,	//Specifies the window extent and window origin when drawing a metafile
BOOL (*) (DWORD) pfnContinue,	//Callback function for canceling or continuing the drawing
DWORD dwContinue	//Parameter to pass to the callback function pfnContinue
);
Parameters

dwAspect

[in]Specifies how the object is to be represented. Representations include content, an icon, a thumbnail, or a printed document. Valid values are taken from the enumeration DVASPECT. See the DVASPECT enumeration for more information.

lindex

[in]Indicates the portion of the object that is of interest for the draw operation. Its interpretation varies depending on the value in the dwAspect parameter. See the DVASPECT enumeration for more information.

pvAspect

[in]Provides more information about the view of the object specified in dwAspect. Since none of the current aspects support additional information; pvAspect must always be NULL.

ptd

[in]Points to the target device structure that describes the device for which the object is to be rendered. If NULL, the view should be rendered for the default target device (typically the display). A value other than NULL is interpreted in conjunction with hicTargetDev and hdcDraw. For example, if hdcDraw specifies a printer as the device context, the ptd parameter points to a structure describing that printer device. The data may actually be printed if hicTargetDev is a valid value or it may be displayed in print preview mode if hicTargetDev is NULL.

hicTargetDev

[in]Specifies the information context for the target device indicated by the ptd parameter from which the object can extract device metrics and test the device's capabilities. If ptd is NULL; the object should ignore the value in the hicTargetDev parameter.

hdcDraw

[in]Specifies the device context on which to draw.

lprcBounds

[in]Points to a RECTL structure specifying the rectangle on hdcDraw and in which the object should be drawn. This parameter controls the positioning and stretching of the object.

lprcWBounds

[in]If hdcDraw is a metafile device context, the lprcWBounds parameter points to a RECTL structure specifying the bounding rectangle in the underlying metafile. The rectangle structure contains the window extent and window origin. These values are useful for drawing metafiles. The rectangle indicated by lprcBounds is nested inside this lprcWBounds rectangle; they are in the same coordinate space.

If hdcDraw is not a metafile device context; lprcWBounds will be NULL.

pfnContinue

[in]Points to a callback function that the view object should call periodically during a lengthy drawing operation to determine whether the operation should continue or be canceled. This function returns TRUE to continue drawing. It returns FALSE to stop the drawing in which case IViewObject::Draw returns DRAW_E_ABORT.

dwContinue

[in]Contains a value to pass as a parameter to the function pointed to by the pfnContinue parameter. Typically, dwContinue is a pointer to an application-defined structure needed inside the callback function.

Return Values

S_OK

The object was drawn successfully.

E_INVALIDARG

Invalid window boundaries specified for metafile device context.

E_OUTOFMEMORY

Ran out of memory.

OLE_E_BLANK

No data to draw from.

DRAW_E_ABORT

Draw operation aborted.

VIEW_E_DRAW

Error in drawing.

DV_E_LINDEX

Invalid value for lindex; currently only -1 is supported.

DV_E_DVASPECT

Invalid value for dwAspect.

OLE_E_INVALIDRECT

Invalid rectangle.

Comments

A container application issues a call to IViewObject::Draw to create a representation of a contained object. This method draws the specified piece (lindex) of the specified view (dwAspect and pvAspect) on the specified device context (hdcDraw). Formatting, fonts, and other rendering decisions are made on the basis of the target device specified by the ptd parameter.

There is a relationship between the dwDrawAspect value and lprcbounds value. The lprcbounds value specifies the rectangle on hdcDraw into which the drawing is to be mapped. For DVASPECT_THUMBNAIL, DVASPECT_ICON, and DVASPECT_SMALLICON, the object draws whatever it wants to draw, and it maps it into the space given in the best way. Some objects might scale to fit while some might scale to fit but preserve aspect ratio. In addition; some might scale so the drawing appears at full width; but the bottom is cropped. The container can suggest a size via IOleObject::SetExtent, but it has no control over the rendering size. In the case of DVASPECT_CONTENT, the Draw implementation should either use the extents given by IOleObject::SetExtent or use the bounding rectangle given in the lprcBounds parameter.

Note to Callers

The value of hicTargetDevice is typically an information context for the target device. However, it may be a full device context instead.

Note to Implementors

If you are writing an object handler (such as the default handler) that implements IViewObject::Draw by playing a metafile, you have to treat SetPaletteEntries metafile records in a special way because of Windows' behavior. The Windows function PlayMetaFile sets these palette entries to the foreground. You must override this default by setting them to the background palette. Use EnumMetaFile to do this. Enhanced metafiles are always recorded with the background palette so there is no need to do it manually.

See Also

DVASPECT, OleDraw


IViewObject::Freeze

Freezes a certain aspect of the object's presentation so that it does not change until the IViewObject::Unfreeze method is called. The most common use of this method is for banded printing.

HRESULT Freeze(

DWORD dwAspect,	//Specifies how the object is to be represented
LONG lindex,	//Specifies the part of the object to draw
void * pvAspect,	//Always NULL
DWORD * pdwFreeze	//Points to location containing an identifier to be used in a subsequent call to Unfreeze
);
Parameters

dwAspect

[in]Specifies how the object is to be represented. Representations include content, an icon, a thumbnail, or a printed document. Valid values are taken from the enumeration DVASPECT. See the DVASPECT enumeration for more information.

lindex

[in]Indicates the portion of the object that is of interest for the draw operation. Its interpretation varies with dwAspect. See the DVASPECT enumeration for more information.

pvAspect

[in]Provides more information about the view of the object specified in dwAspect. Since none of the current aspects support additional information; pvAspect must always be NULL.

pdwFreeze

[out]Points to location where an identifying key is returned. This unique key is later used to cancel the freeze by calling IViewObject::Unfreeze. This key is an index that the default cache uses to keep track of which object is frozen.

Return Values

S_OK

The presentation was successfully frozen.

VIEW_S_ALREADYFROZEN

Presentation has already been frozen. The value of pdwFreeze is the identifying key of the already frozen object.

OLE_E_BLANK

Presentation not in cache.

DV_E_LINDEX

Invalid value for lindex; currently; only -1 is supported.

DV_E_DVASPECT

Invalid value for dwAspect.

Comments

The IViewObject::Freeze method causes the view object to freeze its drawn representation until a subsequent call to IViewObject::Unfreeze releases it. After calling IViewObject::Freeze; successive calls to IViewObject::Draw with the same parameters produce the same picture until IViewObject::Unfreeze is called.

IViewObject::Freeze is not part of the persistent state of the object and does not continue across unloads and reloads of the object.

The most common use of this method is for banded printing.

While in a frozen state; view notifications are not sent. Pending view notifications are deferred to the subsequent call to IViewObject::Unfreeze.

See Also

DVASPECT, IViewObject::Unfreeze


IViewObject::GetAdvise

Retrieves the existing advisory connection on the object if there is one. This method simply returns the parameters used in the most recent call to the IViewObject::SetAdvise method.

HRESULT GetAdvise(

DWORD * pdwAspect,	//Points to location of dwAspect parameter from previous SetAdvise
DWORD * padvf,	//Points to location of advf parameter from previous SetAdvise
IAdviseSink ** ppAdvSink	//Points to location of pAdvSink parameter from previous SetAdvise
);
Parameters

pdwAspect

[out]Points to location where the dwAspect parameter from the previous SetAdvise call is returned. If this pointer is NULL, the caller does not permit this value to be returned.

padvf

[out]Points to location where the advf parameter from the previous SetAdvise call is returned. If this pointer is NULL, the caller does not permit this value to be returned.

ppAdvSink

[out]Points to location where the pAdvSink parameter from the previous SetAdvise call is returned. If this pointer is NULL, the caller does not permit this value to be returned.

Return Values

S_OK

The existing advisory connection was retrieved.

E_INVALIDARG

An invalid advf flag was specified.

E_OUTOFMEMORY

Ran out of memory.

See Also

ADVF, IAdviseSink, IViewObject::SetAdvise


IViewObject::GetColorSet

Returns the logical palette that the object will use for drawing in its IViewObject::Draw method with the corresponding parameters.

HRESULT GetColorSet(

DWORD dwAspect,	//Specifies how the object is to be represented
LONG lindex,	//Specifies the part of the object to draw
void * pvAspect,	//Always NULL
DVTARGETDEVICE * ptd,	//Specifies the target device in a structure
HDC hicTargetDev,	//Specifies the information context for the target device ptd
LOGPALETTE ** ppColorSet	//Points to LOGPALETTE structure
);
Parameters

dwAspect

[in]Specifies how the object is to be represented. Representations include content, an icon, a thumbnail, or a printed document. Valid values are taken from the enumeration DVASPECT. See the DVASPECT enumeration for more information.

lindex

[in]Indicates the portion of the object that is of interest for the draw operation. Its interpretation varies with dwAspect. See the DVASPECT enumeration for more information.

pvAspect

[in]Provides more information about the view of the object specified in dwAspect. Since none of the current aspects support additional information; pvAspect must always be NULL.

ptd

[in]Points to the target device structure that describes the device for which the object is to be rendered. If NULL, the view should be rendered for the default target device (typically the display). A value other than NULL is interpreted in conjunction with hicTargetDev and hdcDraw. For example, if hdcDraw specifies a printer as the device context, ptd points to a structure describing that printer device. The data may actually be printed if hicTargetDev is a valid value or it may be displayed in print preview mode if hicTargetDev is NULL.

hicTargetDev

[in]Specifies the information context for the target device indicated by the ptd parameter from which the object can extract device metrics and test the device's capabilities. If ptd is NULL, the object should ignore the hicTargetDev parameter.

ppColorSet

[out]Points to location where a LOGPALETTE structure is returned. The LOGPALETTE structure contains the set of colors that would be used if IViewObject::Draw were called with the same parameters for dwAspect, lindex, pvAspect, ptd, and hicTargetDev. A NULL pointer to the LOGPALETTE structure means that the object does not use a palette.

Return Values

S_OK

The set of colors was returned successfully.

S_FALSE

Set of colors is empty or the object will not give out the information.

E_INVALIDARG

One or more arguments are invalid.

OLE_E_BLANK

No presentation data for object.

E_UNEXPECTED

An unexpected error occurred.

DV_E_LINDEX

Invalid value for lindex; currently only -1 is supported.

DV_E_DVASPECT

Invalid value for dwAspect.

Comments

The IViewObject::GetColorSet method recursively queries any nested objects and returns a color set that represents the union of all colors requested. The color set eventually percolates to the top-level container that owns the window frame. This container can call IViewObject::GetColorSet on each of its embedded objects to obtain all the colors needed to draw the embedded objects. The container can use the color sets obtained in conjunction with other colors it needs for itself to set the overall color palette.

The OLE-provided implementation of IViewObject::GetColorSet looks at the data it has on hand to draw the picture. If CF_DIB is the drawing format; the palette found in the bitmap is used. For a regular bitmap; no color information is returned. If the drawing format is a metafile, the object handler enumerates the metafile looking for a CreatePalette metafile record. If one is found; the handler uses it as the color set.

Note to Implementors

Object applications that rely on the default handler for drawing and that use metafiles for doing so should provide a SetPaletteEntries record when they generate their metafiles. If a SetPaletteEntries record is not found; the default object handler returns S_FALSE.

See Also

DVASPECT


IViewObject::SetAdvise

Sets up a connection between the view object and an advise sink so that the advise sink can be notified about changes in the object's view.

HRESULT SetAdvise(

DWORD dwAspect,	//Specifies the view object for which notification is being requested
DWORD advf,	//Specifies information about the advise sink
IAdviseSink * pAdvSink	//Points to the advise sink that is to receive change notifications
);
Parameters

dwAspect

[in]Specifies the view for which the advisory connection is being set up. Valid values are taken from the enumeration DVASPECT. See the DVASPECT enumeration for more information.

advf

[in]Contains a group of flags for controlling the advisory connection. Valid values are from the enumeration ADVF. However, only some of the possible ADVF values are relevant for this method. The following table briefly describes the relevant values. See the ADVF enumeration for a more detailed description.

ADVF Value	Description
ADVF_ONLYONCE	Causes the advisory connection to be destroyed after the first notification is sent.
ADVF_PRIMEFIRST	Causes an initial notification to be sent  regardless of whether data has changed from its current state.
Note that the ADVF_ONLYONCE and ADVF_PRIMEFIRST can be combined to provide an asynchronous call to IDataObject::GetData.

pAdvSink

Points to the advisory sink that is to be informed of changes. A NULL value deletes any existing advisory connection.

Return Values

S_OK

The advisory connection was successfully established.

E_INVALIDARG

An invalid advf flag was specified.

E_OUTOFMEMORY

Ran out of memory.

OLE_E_ADVISENOTSUPPORTED

Advisory notifications are not supported.

DV_E_DVASPECT

Invalid value for dwAspect.

Comments

A container application that is requesting a draw operation on a view object can also register with the IViewObject::SetAdvise method to be notified when the presentation of the view object changes. To find out about when an object's underlying data changes, you must call IDataObject::DAdvise separately.

To remove an existing advisory connection, call the IViewObject::SetAdvise method with pAdvSink set to NULL.

If the view object changes, a call is made to the appropriate advise sink through its IAdviseSink::OnViewChange method.

At any time; a given view object can support only one advisory connection. Therefore, when IViewObject::SetAdvise is called and the view object is already holding onto an advise sink pointer, OLE releases the existing pointer before the new one is registered.

See Also

ADVF, IAdviseSink, IViewObject::GetAdvise


IViewObject::Unfreeze

Releases a previously frozen drawing. The most common use of this method is for banded printing.

HRESULT Unfreeze(

DWORD dwFreeze	//Identifies the view object that is frozen
);
Parameter

dwFreeze

[in]Contains a key previously returned from IViewObject::Freeze. This key determines which object to unfreeze.

Return Values

S_OK

The drawing was unfrozen successfully.

OLE_E_NOCONNECTION

Error in the unfreezing process or the object is currently not frozen.

See Also

IViewObject::Freeze


IViewObject2

The IViewObject2 interface is an extension to the IViewObject interface which returns the size of the drawing for a given view of an object. You can prevent the object from being run if it isn't already running by calling this method instead of IOleObject::GetExtent.

Like the IViewObject interface, IViewObject2 cannot be marshaled to another process. This is because device contexts are only effective in the context of one process.

The OLE provided default implementation provides the size of the object in the cache.

When to Implement

Object handlers and in-process servers that manage their own presentations implement IViewObject2 for use by compound document containers.

When to Use

A container application or object handler calls the GetExtent method in the IViewObject2 interface to get the object's size from its cache.

Methods in Vtable Order

IUnknown Methods	Description
QueryInterface	Returns pointers to supported interfaces.
AddRef	Increments reference count.
Release	Decrements reference count.
IViewObject Methods	Description
Draw	Draws a representation of the object onto a device context.
GetColorSet	Returns the logical palette the object uses for drawing.
Freeze	Freezes the drawn representation of an object so it will not change until a subsequent Unfreeze.
Unfreeze	Unfreezes the drawn representation of an object.
SetAdvise	Sets up a connection between the view object and an advise sink so that the advise sink can receive notifications of changes in the view object.
GetAdvise	Returns the information on the most recent SetAdvise.
IViewObject2 Method	Description
GetExtent	Returns the size of the view object from the cache.


IViewObject2::GetExtent

Returns the size that the specified view object will be drawn on the specified target device.

HRESULT GetExtent(

DWORD dwAspect,	//Specifies the view object for which the size is being requested
DWORD lindex,	//Specifies the part of the object to draw
DVTARGETDEVICE ptd,	//Specifies the target device in a structure
LPSIZEL lpsizel	//Points to size of object
);
Parameters

dwAspect

[in]Specifies the requested view of the object whose size is of interest. Valid values are taken from the enumeration DVASPECT. See the DVASPECT enumeration for more information.

lindex

[in]Indicates the portion of the object that is of interest. Currently only -1 is valid.

ptd

[in]Points to the target device for which the object's size should be returned.

lpsizel

Points to location where the object's size is returned.

Return Values

S_OK

The object's extent was successfully returned.

OLE_E_BLANK

An appropriate cache is not available.

E_OUTOFMEMORY

Insufficient memory to execute this operation.

Comments

The OLE-provided implementation of IViewObject2::GetExtent searches the cache for the size of the view object.

The GetExtent method in the IOleObject interface provides some of the same information as IViewObject2::GetExtent.

Note to Callers

To prevent the object from being run if it isn't already running, you can call IViewObject2::GetExtent rather than IOleObject::GetExtent to determine the size of the presentation to be drawn.

See Also

IOleObject::GetExtent, IViewObject


BindMoniker
BindMoniker   QuickInfo

Binds the specified moniker, that is, locates the object identified by the moniker, which activates the object if it isn't active already, and retrieves the specified interface pointer to that object.

HRESULT BindMoniker(

LPMONIKER pmk,	//Pointer to the moniker to be bound
DWORD grfOpt,	//Reserved
REFIID iidResult,	//IID of interface pointer desired
LPVOID FAR *ppvResult	//Receives interface pointer
);
Parameters

pmk

Points to the moniker that is to be bound.

grfOpt

Reserved for future use; must be zero.

iidResult

Specifies the IID of the interface pointer desired.

ppvResult

Receives a pointer to the requested interface. If an error occurs, ppvResult is NULL; otherwise, the caller is responsible for calling IUnknown::Release.

Return Values

S_OK

Indicates that the moniker was successfully bound.

MK_E_NOOBJECT

Indicates that the object identifed by pmk could not be found. If pmk is a composite moniker, the object indicated is some intermediate object identified in the composite.

E_OUTOFMEMORY

Indicates insufficient memory.

E_INVALIDARG

Indicates one or more invalid arguments.

The return value can also be any of the error values returned by IMoniker::BindToObject.

Comments

The BindMoniker helper function packages the following functionality:

IBindCtx *pbc;

CreateBindCtx(0, &pbc);

pmk->BindToObject(pbc, NULL, riid, ppvObj);

pbc->Release();

BindMoniker is a helper function that is convenient for a moniker client to call to bind one moniker. A moniker client uses a moniker to acquire an interface pointer to the object that the moniker identifies. If you have several monikers to bind in quick succession, and if you know that those monikers will activate the same objects, it may be more efficient to call the IMoniker::BindToObject method directly so you can use the same bind context for all the monikers. See the IBindCtx interface for more information.

The most common examples of moniker clients are applications that act as link containers; that is, container applications that allow their documents to contain linked objects. However, link containers are a special case in that they generally do not need to make direct calls to IMoniker methods. Instead, they manipulate linked objects through the IOleLink interface; the default handler implements this interface and calls the appropriate IMoniker methods as needed.

See Also

CreateBindCtx, IMoniker::BindToObject


CLSIDFromProgID
CLSIDFromProgID   QuickInfo

Looks up a CLSID from a ProgID in the registry.

HRESULT CLSIDFromProgID(

LPCOLESTR lpszProgID,	//Points to the ProgID whose CLSID is requested
LPCLSID pclsid	//Receives a pointer to the created CLSID
);
Parameters

lpszProgID

Points to the ProgID whose CLSID is requested.

pclsid

Receives a pointer to the location of the created CLSID on return.

Return Values

S_OK

Indicates the CLSID was created successfully.

CO_E_CLASSSTRING

Indicates the registered CLSID for the ProgID is invalid.

REGDB_E_WRITEREGDB

Indicates an error occurred writing to the registry.

E_OUTOFMEMORY

Out of memory.

E_INVALIDARG

Indicates one or more arguments are invalid.

E_UNEXPECTED

Indicates an unexpected error occurred.

Comments

Given a ProgID, CLSIDFromProgID looks up its associated CLSID from a ProgID in the registry. If the ProgID cannot be found in the registry, CLSIDFromProgID creates an OLE 1 CLSID for it. Because of the restrictions placed on OLE 1 CLSID values, CLSIDFromProgID and CLSIDFromString are the only two functions that can be used to generate a CLSID for an OLE 1 object.

See Also

ProgIDFromCLSID


CLSIDFromString
CLSIDFromString   QuickInfo

Converts a string generated by the StringFromCLSID function back into the original CLSID.

HRESULT CLSIDFromString(

LPOLESTR lpsz,	//Points to the string representation of the CLSID
LPCLSID pclsid	//Receives a pointer to the CLSID on return
);
Parameters

lpsz

Points to the string representation of the CLSID.

pclsid

Receives a pointer to the CLSID on return.

Return Values

S_OK

Indicates the CLSID was returned successfully.

E_OUTOFMEMORY

Out of memory.

E_INVALIDARG

Indicates one or more arguments are invalid.

E_UNEXPECTED

Indicates an unexpected error occurred.

Comments

Because of the restrictions placed on OLE 1 CLSID values, CLSIDFromProgID and CLSIDFromString are the only two functions that can be used to generate a CLSID for an OLE 1 object.

See Also

CLSIDFromProgID, StringFromCLSID


CoBuildVersion
CoBuildVersion   QuickInfo

This function is obsolete.


CoCreateFreeThreadedMarshaler

Creates an object that implements special marshalling behavior. This is a helpler function that makes it easier to define objects with VTBLs that different apartment model threads can access directly.

HRESULT CoCreateFreeThreadedMarshaler(

LPUNKNOWN punkOuter,	//Points to the stream from which the object is to be marshaled
LPUNKNOWN punkMarshaler	//The interface requested from the unmarshaled object
);
Parameters

punkOuter

Specifies a pointer to the controlling IUnknown of the object that is going to have the special marshaling behavior specified by the object this function creates.

punkMarshaler

[out] On return, contains a pointer to the private IUnknown of an object that implements this special marshaling behavior.

Return Values

S_OK

Indicates the marshaler was created successfully.

E_OUTOFMEMORY

Indicates that the marshaler object could not be created.

Comments

CoCreateFreeThreadedMarshaler is a helper API that makes it easier to define an object that allows direct access to its VTBL from multiple apartment-model threads of execution, and uses standard marshaling if a reference to the object is sent to another process.

When there is a request for a pointer to an object, the marshal context of the request is determined by the specified member of the MSHCTX enumeration. When the marshal context is MSHCTX_INPROC, meaning that the pointer to the object need only be marshaled across different threads in the same process, the marshal code only has to copy the pointer to the interface being marshaled into the marshaling stream. For any other marshaling context, use standard marshaling to complete the operation.

CoCreateFreeThreadedMarshaler implements code that defines this context-dependent behavior, and, on return, writes to its punkMarshaler parameter a pointer to the private unknown for a object that does this standard type of marshaling. The function then aggregates this marshaler object with the object that should have this marshaling behavior.

See Also

CoMarshalInterThreadInterfaceInStream, CoGetInterfaceAndReleaseStream


CoCreateGuid
CoCreateGuid   QuickInfo

Creates a GUID, a unique 128-bit integer used for CLSIDs and interface identifiers.

HRESULT CoCreateGuid(

GUID  *pguid	//Receives a pointer to the GUID on return
);
Parameter

pguid

Receives a pointer to the requested GUID on return.

Return Value

S_OK

Indicates the GUID was successfully created.

Win32 errors are returned by UuidCreate but wrapped as an HRESULT.

Comments

The CoCreateGuid function calls UuidCreate (documented in the RPC Programmer's Guide and Reference), which creates a GUID, a globally unique 128-bit integer used for CLSIDs and interface IDs. To a very high degree of certainty, this function returns a unique value − no other invocation, on the same or any other system (networked or not) should return the same value.


CoCreateInstance
CoCreateInstance   QuickInfo

Creates a single uninitialized object of the kind associated with the specified CLSID and returns any requested interface pointer. Call CoCreateInstance when you want to create a single object based on a CLSID. If you want to create multiple objects from a single class object, refer to the CoGetClassObject function.

STDAPI CoCreateInstance(

REFCLSID rclsid,	//Class identifier
LPUNKNOWN pUnkOuter,	//Object is or isn't part of an aggregate
DWORD dwClsContext,	//Context for running executable code
REFIID riid,	//Interface identifier
LPVOID * ppv	//Pointer to storage of interface pointer
);
Parameters

rclsid

Specifies the CLSID that will associate the correct data and code.

pUnkOuter

If NULL, indicates that the object is not being created as part of an aggregate. If non-NULL, points to the controlling unknown of the aggregate that will use the newly created object.

dwClsContext

Specifies the context in which the executable is to be run. The values are taken from the enumeration CLSCTX.

riid

Specifies the interface to be used to communicate with the object.

ppv

Points to where to return the pointer to the requested interface.

Return Values

S_OK

Indicates that an instance of the specified object class was successfully created.

REGDB_E_CLASSNOTREG

Indicates that a specified class is not registered in the registration database.

E_OUTOFMEMORY

Out of memory.

E_INVALIDARG

Indicates one or more arguments are invalid.

E_UNEXPECTED

Indicates an unexpected error occurred.

CLASS_E_NOAGGREGATION

Indicates this class cannot be created as part of an aggregate.

Comments

The CoCreateInstance helper function connects to the class object associated with the specified CLSID, creates an uninitialized instance, and releases the class object. It encapsulates the following functionality:

CoGetClassObject(rclsid, dwClsContext, NULL, IID_IClassFactory,
 &pCF);

hresult = pCF->CreateInstance(pUnkOuter, riid, ppvObj)

pCF->Release();

It is convenient to use this function when you need to create only a single instance through a class object, and do not need to keep the class object around to create other instances. If you do, see the CoGetClassObject function.

See Also

CoGetClassObject, IClassFactory::CreateInstance


CoCreateStandardMalloc

This function is obsolete. The system-provided implementation is the only one available.


CoDisconnectObject
CoDisconnectObject   QuickInfo

Disconnects all remote process connections being maintained on behalf of all the interface pointers on a specified object. Only the process that actually manages the object should call CoDisconnectObject.

STDAPI CoDisconnectObject(

IUnknown * pUnk,	//Points to the object
DWORD dwReserved	//Reserved for future use
);
Parameters

pUnk

Points to the object to be disconnected. This does not necessarily have to be an IUnknown pointer. It can be a pointer to any interface supported by the object, as long as the interface is derived from IUnknown.

dwReserved

Reserved for future use; must be zero.

Return Values

S_OK

Indicates all connections to remote processes were successfully deleted.

E_OUTOFMEMORY

Out of memory.

E_INVALIDARG

Indicates one or more arguments are invalid.

E_UNEXPECTED

Indicates an unexpected error occurred.

E_FAIL

Indicates an unspecified error occurred.

Comments

The CoDisconnectObject function is not used in the typical course of processing (clients of interfaces should use IUnknown::Release). The primary purpose of CoDisconnectObject is to give an application control over connections from other processes that were made to objects managed by the application. For example, suppose an OLE container loads an embedded object and then links are established between the embedded object and outside containers. If the container application wants to exit, it is not appropriate for these remote connections to keep the object active beyond the lifetime of its container. When the object's container closes, such links should be disconnected. To forcefully close any existing connection(s), the object's container can call CoDisconnectObject.

Before calling CoDisconnectObject, the container should first call IOleObject::Close for all OLE objects. The objects will send OnClose notifications to inform all clients of the impending closure.

Calling this function is a privileged operation, to be invoked only by the process in which the object is actually managed.

See Also

IOleObject::Close


CoDosDateTimeToFileTime
CoDosDateTimeToFileTime   QuickInfo

Converts the MS-DOS representation of the time and date to a FILETIME structure, which Win32 uses to determine the date and time.

BOOL CoDosDateTimeToFileTime(

WORD nDosDate,	//The 16-bit MS-DOS date
WORD nDosTime,	//The 16-bit MS-DOS time
FILETIME * lpFileTime	//Pointer to the FILETIME structure
);
Parameters

nDosDate

Specifies the 16-bit MS-DOS date.

nDosTime

Specifies the 16-bit MS-DOS time.

lpFileTime

Points to the FILETIME structure.

Return Values

TRUE

Indicates the FILETIME structure was created successfully.

FALSE

Indicates the FILETIME structure was not created successfully, probably because of invalid arguments.

Comments

The FILETIME structure and the CoDosDateTimeToFileTime and CoFileTimeToDosDateTime functions are part of the Win32 API definition. They are provided for compatibility in all OLE implementations, but are redundant on Win32 platforms.

MS-DOS records file dates and times as packed 16-bit values. An MS-DOS date has the following format:

Bits	Contents
0-4	Days of the month (1-31).
5-8	Months (1 = January, 2 = February, and so forth).
9-15	Year offset from 1980 (add 1980 to get actual year).
An MS-DOS time has the following format:

Bits	Contents
0-4	Seconds divided by 2.
5-10	Minutes (0-59).
11-15	Hours (0-23 on a 24-hour clock).
See Also

CoFileTimeToDosDateTime, CoFileTimeNow


CoFileTimeNow
CoFileTimeNow   QuickInfo

Returns the current time as a FILETIME structure.

HRESULT CoFileTimeNow(

FILETIME  * lpFileTime	//Points to where to return the FILETIME structure
);
Parameter

lpFileTime

Points to where to return the FILETIME structure.

Return Values

S_OK

Indicates the current time was converted to a FILETIME structure.

E_OUTOFMEMORY

Out of memory.

E_INVALIDARG

Indicates lpFileTime is invalid.

E_UNEXPECTED

Indicates an unexpected error occurred.

E_FAIL

Indicates the current time was not converted to a FILETIME structure.

See Also

CoDosDateTimeToFileTime, CoFileTimeToDosDateTime


CoFileTimeToDosDateTime

Converts a FILETIME into MS-DOS date and time values.

BOOL CoFileTimeToDosDateTime(

FILETIME  * lpFileTime,	//Points to the FILETIME structure to be converted
LPWORD lpDosDate,	//Points to the 16-bit MS-DOS date
LPWORD lpDosTime	//Points to the 16-bit MS-DOS time
);
Parameters

lpFileTime

Points to the FILETIME structure to be converted.

lpDosDate

Points to the 16-bit MS-DOS date.

lpDosTime

Points to the 16-bit MS-DOS time.

Return Values

TRUE

Indicates the FILETIME structure was converted successfully.

FALSE

Indicates the FILETIME structure was not converted successfully.

Comments

This is the inverse of the operation provided by the CoDosDateTimeToFileTime function.

See Also

CoDosDateTimeToFileTime, CoFileTimeNow


CoFreeAllLibraries
CoFreeAllLibraries   QuickInfo

Frees all the DLLs that have been loaded with the CoLoadLibrary function, regardless of whether they are currently in use.

void CoFreeAllLibraries();

Comments

The OLE Component Object Model(COM) library maintains a list of loaded DLLs for each process that CoFreeAllLibraries uses to unload the libraries. The CoUninitialize function calls CoFreeAllLibraries internally, so OLE applications usually have no need to call this function directly.

See Also

CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries, CoUninitialize


CoFreeLibrary
CoFreeLibrary   QuickInfo

Frees a library that was previously loaded with the bAutoFree parameter of the CoLoadLibrary function set to FALSE.

void CoFreeLibrary(

HINSTANCE  hInst	//The handle of the library module to be freed
);
Parameter

hInst

Specifies the handle to the library module to be freed, as returned by CoLoadLibrary.

Comments

The CoFreeLibrary function should be called to free a library that is to be freed explicitly. This is established when the library is loaded with the bAutoFree parameter of CoLoadLibrary set to FALSE. It is illegal to free a library explicitly when the corresponding CoLoadLibrary call specifies that it be freed automatically (the bAutoFree parameter is set to TRUE).

See Also

CoFreeAllLibraries, CoFreeUnusedLibraries, CoLoadLibrary


CoFreeUnusedLibraries
CoFreeUnusedLibraries   QuickInfo

Unloads any DLLs that have been loaded with the bAutoFree parameter of the CoLoadLibrary function set to TRUE, but are no longer in use.

void CoFreeUnusedLibraries();

Comments

Applications can call CoFreeUnusedLibraries periodically to free resources. It is most efficient to call it either at the top of a message loop or in some idle-time task. CoFreeUnusedLibraries internally calls DllCanUnloadNow for DLLs that implement and export that function.

See Also

CoFreeLibrary, CoFreeUnusedLibraries, CoLoadLibrary, DLLCanUnloadNow


CoGetClassObject
CoGetClassObject   QuickInfo

Provides the caller with a pointer to an interface on a class object associated with a specified CLSID. The CoGetClassObject function transparently locates, and if necessary, dynamically loads the executable code required to do this.

Call CoGetClassObject when you want to create multiple objects through a class object for which there is a CLSID in the system registry. You would then call IClassFactory::CreateInstance to create an uninitialized object. It is not always necessary to go through this process. To create a single object, call instead the CoCreateInstance function, which encapsulates connecting to the class object, creating the instance, and releasing the class object. OLE also provides many other ways to create an object in the form of numerous helper functions and interface member functions whose function is to create objects of a single type and provide a pointer to an interface on that object.

STDAPI CoGetClassObject(

REFCLSID rclsid,	//CLSID associated with the class object
DWORD dwClsContext,	//Context for running executable code
LPVOID pvReserved,	//Must be NULL
REFIID riid,	//Interface identifier
LPVOID * ppv	//On return, pointer to location of interface pointer
);
Parameters

rclsid

Specifies the CLSID that will associate the correct data and code.

dwClsContext

Specifies the context in which the executable code is to be run. For information on the context values and their use, see the CLSCTX enumeration.

pvReserved

Reserved for future use. Must be NULL.

riid

Specifies the interface to be used to communicate with the class object. This interface is almost always IClassFactory (represented by the riid IID_IClassFactory).

ppv

Points to where the resulting interface pointer is to be stored.

Return Values

S_OK

Location and connection to the specified class object was successful.

REGDB_E_CLASSNOTREG

CLSID is not properly registered.

E_NOINTERFACE

The object pointed to by ppv does not support the interface identified by riid.

REGDB_E_READREGDB

Error reading the registration database.

CO_E_DLLNOTFOUND

In process DLL or handler DLL not found (depends on context).

CO_E_APPNOTFOUND

EXE not found (CLSCTX_LOCAL_SERVER only).

E_ACCESSDENIED

General access failure (returned from LoadLib/CreateProcess).

CO_E_ERRORINDLL

EXE has error in image.

CO_E_APPDIDNTREG

EXE was launched, but it didn't register class object (may or may not have shutdown).

E_OUTOFMEMORY

Out of memory.

E_INVALIDARG

One or more arguments are invalid.

E_UNEXPECTED

An unexpected error occurred.

E_NOINTERFACE

The QueryInterface on the class object returned E_NOINTERFACE.

Comments

A class object in OLE is an intermediate object that supports an interface that permits operations common to a group of objects. The objects in this group are instances derived from the same object definition represented by a single CLSID. Usually, the interface on a class object is IClassFactory, through which you can create object instances of a given definition (class).

A call to CoGetClassObject creates, initializes, and gives the caller access (through an interface specified with the riid parameter) to the class object. The class object is the one associated with the CLSID that you specify in the rclsid parameter. Details of how code and data are located and associated are transparent to the caller, as is the dynamic loading of associated code not already loaded. There are two places to find a CLSID for a given object definition:

•	The registry holds an association between CLSIDs and file suffixes, and between CLSIDs and file signatures for determining the class of an object.

•	When an object is saved to persistent storage, its CLSID is stored with its data.

To create and initialize embedded or linked OLE document objects, it is not necessary to call CoGetClassObject directly. Instead, call one of the OleCreate or OleCreateXxx helper functions. These functions encapsulate the entire object instantiation and initialization process, and call, among other functions, CoGetClassObject.

The riid parameter specifies the interface the client will use to communicate with the class object. In most cases, this interface is IClassFactory. This provides access to the IClassFactory::CreateInstance member function, through which the caller can then create an uninitialized object of the kind specified in its implementation. All object definitions registered in the system with a CLSID must implement IClassFactory.

In rare cases, however, you may want to specify some other interface that defines operations common to a set of objects. For example, in the way OLE implements monikers, the interface on the class object is IParseDisplayName, used to transform the display name of an object into a moniker.

The dwClsContext parameter specifies the execution context, allowing one CLSID to be associated with different pieces of code in different execution contexts. The CLSCTX enumeration , defined in COMPOBJ.H, specifies the available context flags. CoGetClassObject consults (as appropriate for the context indicated) both the registration database and the class objects that are currently registered by calling the CoRegisterClassObject function.

See Also

CoRegisterClassObject, CoRevokeClassObject, OleLoad, CLSCTX


CoGetCurrentProcess
CoGetCurrentProcess   QuickInfo

Returns a value that is unique to the current thread. It can be used to avoid PROCESSID reuse problems.

DWORD CoGetCurrentProcess();

Return Value

DWORD value

Indicates a unique value for the current thread that can be used to avoid PROCESSID reuse problems.

Comments

The CoGetCurrentProcess function returns a value that is effectively unique, because it is not used again until 2 (32 ) more threads have been created on the current workstation or until the workstation is rebooted.

Using the value returned from a call to CoGetCurrentProcess can help you maintain tables that are keyed by threads or in uniquely identifying a thread to other threads or processes.

Using the value returned by CoGetCurrentProcess is more robust than using the HTASK task handle value returned by the Win32 function GetCurrentTask, because Windows task handles can be reused relatively quickly when a window's task dies.


CoGetInterfaceAndReleaseStream

Unmarshals a buffer containing an interface pointer and releases the stream when an interface pointer has been marshalled from another thread to the calling thread.

HRESULT CoGetInterfaceAndReleaseStream(

LPSTREAM * ppStm,	//Points to the stream from which the object is to be marshalled
REFIID riid,	//The interface requested from the unmarshalled object
LPVOID * ppv	//On return, location of the interface pointer
);
Parameters

pstm

Points to the stream containing the interface to be unmarshaled.

riid

Specifies the interface requested from the unmarshaled object.

ppv

[Out] On return, points to the location of the unmarshaled interface pointer.

Return Values

S_OK

Indicates the output interface was unmarshaled and the stream was released.

E_INVALIDARG

Indicates that input arguments are invalid.

Other results from CoUnmarshalInterface

Comments

CoGetInterfaceAndReleaseStream is a companion helper API to CoMarshalInterThreadInterfaceInStream, reversing the result of the latter.  It unmarshals the buffer and releases the stream that contained the interface. If the unmarshaling fails, the stream is still released because there is no effective way to recover from a failure of this kind.

See Also

CoMarshalInterThreadInterfaceInStream


CoGetMalloc
CoGetMalloc   QuickInfo

Retrieves the default OLE task memory allocator (a pointer to the system implementation of the IMalloc interface) so applications can use it to manage memory.

HRESULT CoGetMalloc(

DWORD dwMemContext,	//Indicates if memory is private or shared
LPMALLOC * ppMalloc	//Receives pointer to memory allocator on return
);
Parameters

dwMemContext

Indicates this is reserved; the value must be 1.

ppMalloc

Receives a pointer to the memory allocator on return.

Return Values

S_OK

Indicates the allocator was retrieved successfully.

E_INVALIDARG

Indicates either dwMemContext is not equal to 1, or ppMalloc is an invalid out pointer.

E_OUTOFMEMORY

Inidcates pointer wasn't returned because the system is out of memory.

Comments

The pointer to the IMalloc interface pointer received through the ppMalloc parameter cannot be called from a remote process—each process must have its own allocator.

See Also

IMalloc, CoTaskMemAlloc


CoGetMarshalSizeMax
CoGetMarshalSizeMax   QuickInfo

Retrieves an upper bound on the number of bytes needed to marshal the specified interface pointer on the specified object.

STDAPI CoGetMarshalSizeMax(

ULONG *pulSize,	//Receives maximum size
REFIID riid,	//Identifies interface to be marshalled
IUnknown * pUnk,	//Interface pointer to be marshaled
DWORD dwDestContext,	//Specifies destination process
LPVOID pvDestContext,	//Reserved for future use
DWORD mshlflags	//Specifies reason for marshalling
);
Parameters

pulSize

Receives the maximum marshal size; a value of zero means that the size of the data is unknown.

riid

Specifies the IID of the interface pointer to be marshalled. This interface must be derived from the IUnknown interface.

pUnk

Indicates the interface pointer to be marshalled; can be NULL.

dwDestContext

Specifies the destination context, that is, the process in which the unmarshaling will be done. The legal values for dwDestContext are taken from the enumeration MSHCTX.

pvDestContext

Indicates reserved for use with future MSHCTX values. This must be set to NULL.

mshlflags

Specifies why marshalling is taking place. The legal values for mshlflags are taken from the enumeration MSHLFLAGS.

Return Values

S_OK

Indicates the upper bound was returned successfully.

CO_E_NOTINITIALIZED

Indicates the CoInitialize or OleInitialize function was not called on the current thread before this function was called.

E_UNEXPECTED

Indicates an unexpected error occurred.

Comments

You typically call this function before calling the CoMarshalInterface function. See the description of that function for information on calling these functions.

See Also

CoMarshalInterface, IMarshal::GetMarshalSizeMax


CoGetStandardMarshal
CoGetStandardMarshal   QuickInfo

Returns an IMarshal pointer to the system's default marshalling implementation. Use this implementation to create a proxy for the specified interface pointer in another process.

STDAPI CoGetStandardMarshal(

REFIID riid,	//Identifies interface being marshalled
IUnknown * pUnk,	//Interface pointer being marshalled
DWORD dwDestContext,	//Specifies destination process
LPVOID pvDestContext,	//Reserved for future use
DWORD mshlflags,	//Specifies reason for marshalling
LPMARSHAL * ppMarshal	//Receives pointer to standard marshaller
);
Parameters

riid

Specifies the IID of the interface pointer to be marshalled. This interface must be derived from the IUnknown interface.

pUnk

Indicates interface pointer to be marshalled. This interface pointer does not have to have the same IID specified by the riid parameter; it can be a pointer to any IUnknown-derived interface on the object. The standard marshaller will call the QueryInterface function on this pointer requesting the interface specified by riid.

dwDestContext

Specifies the destination context, that is, the process in which the unmarshalling will be done. The legal values for dwDestContext are taken from the enumeration MSHCTX.

pvDestContext

Reserved for use with future MSHCTX values.

mshlflags

Specifies why marshalling is taking place. The legal values for mshlflags are taken from the enumeration MSHLFLAGS.

ppMarshal

Receives the standard marshaller.

Return Values

S_OK

Indicates that the IMarshal instance was returned successfully.

CO_E_NOTINITIALIZED

Indicates that the CoInitialize or OleInitialize function was not called on the current thread before this function was called.

E_OUTOFMEMORY

Out of memory.

E_INVALIDARG

Indicates one or more arguments are invalid.

E_UNEXPECTED

Indicates an unexpected error occurred.

E_FAIL

Indicates an unspecified error.

Comments

You typically do not need to call this function. If you are performing custom marshalling (that is, writing your own implementation of IMarshal), you can delegate certain destination contexts to the standard marshaller. You should delegate any destination contexts that you don't fully understand or don't want to handle. The standard marshaller returned by this function is the one used by OLE when an object does not support the IMarshal interface.

See Also

IMarshal


CoGetTreatAsClass
CoGetTreatAsClass   QuickInfo

Returns the CLSID of an object that can emulate the specified object.

HRESULT CoGetTreatAsClass(

REFCLSID clsidOld,	//CLSID of object that is being emulated
LPCLSID pclsidNew	//Points to location of CLSID for object that can emulate clsidOld
);
Parameters

clsidOld

Specifies the CLSID of the object that can be emulated or treated as an object with a different CLSID.

pclsidNew

Points to the location where the CLSID that can emulate clsidOld objects is retrieved. This parameter cannot be NULL. If there is no emulation information for clsidOld objects, then the clsidOld parameter is returned.

Return Values

S_OK

Indicates that a new CLSID was successfully returned.

S_FALSE

Indicates that there is no emulation information for the clsidOld parameter and that the *pclsidNew parameter is set to clsidOld.

REGDB_E_READREGDB

Indicates an error reading the registration database.

See the CLSIDFromString function for other possible errors.

Comments

This function returns the TreatAs entry in the registration database for the specified object. If there is no TreatAs entry for the specfied object, this function returns the CLSID of the original object (clsidOld).

Use this function to obtain the CLSID of an object application that can emulate the specified object. The end-user can request that a specified object be treated as an object of a different class, or a setup program can register one class of objects to be treated as objects of a different class. For example, a spreadsheet application may be able to read and write spreadsheets from a different application. The first application can then emulate the objects of the second by treating them as its own.

In the first case, the end-user makes the request through the Convert To dialog box. For example, the end-user might wish to edit a spreadsheet created by one application using a different application that can read and write the spreadsheet format of the original application. In the second case, an application's setup program can specify to activate objects of one class as objects of a different class. For example, when the application is updated, the objects created with the earlier version can be activated and treated as objects of the new version.

In either case, the object application or the setup program calls the CoTreatAsClass function to set the TreatAs entry in the registration database. Subsequently, all objects of the original CLSID are activated and treated as objects of the second CLSID.

See Also

CoTreatAsClass


CoInitialize
CoInitialize   QuickInfo

The CoInitialize function initializes the Component Object Model(COM) library. You must initialize the library before you can call its functions. Applications must call CoInitialize before they make any other COM library calls with two exceptions: the CoGetMalloc function, and memory allocation calls.

HRESULT CoInitialize(

LPVOID pvReserved	//Reserved, must be NULL
);
Parameter

pvReserved

In 32-bit OLE, this parameter must be NULL. The 32-bit version of OLE does not support applications replacing OLE's allocator and if the parameter is not NULL, CoInitialize returns E_INVALIDARG.

Return Values

S_OK

Indicates the library was initialized successfully.

S_FALSE

Indicates that the library is already initialized or that it could not release default allocator.

E_OUTOFMEMORY

Indicates that it was unable to initialize because the system is out of memory.

E_INVALIDARG

Indicates the argument is invalid.

E_UNEXPECTED

Indicates an unexpected error occurred.

Comments

You need to call this before you call any of the OLE library functions unless you call the OleInitialize function, which calls CoInitialize internally.

Typically, CoInitialize is called only once in the process that uses the OLE library. There can be multiple calls, but subsequent calls return S_FALSE. To close the library gracefully, each successful call to CoInitialize, including those that return S_FALSE, must be balanced by a corresponding call to the CoUninitialize function.

See Also

CoInitialize, OleInitialize


CoIsHandlerConnected
CoIsHandlerConnected   QuickInfo

Determines if a remote object is connected to its corresponding object.

BOOL CoIsHandlerConnected(

LPUNKNOWN pUnk	//Points to the remoted object
);
Parameter

pUnk

Specifies the object in question.

Return Values

TRUE

Indicates the object either is not remote or is remote and is still valid (it is still connected to its remote handler).

FALSE

Indicates the object is remote and is invalid (no longer connected to its remote handler).

Comments

The CoIsHandlerConnected function determines the validity of a remote object specified by a pointer to its controlling unknown interface (the pUnk parameter). If the specified remote object is remote and is still connected to its remote handler, or is not a remote object, the function returns TRUE. If the specified object is still remote but is not connected to its remote handler, the function returns FALSE, and the caller should respond by releasing the object.


CoIsOle1Class
CoIsOle1Class   QuickInfo

Determines if a given CLSID represents an OLE 1 object. This is one of several OLE compatibility functions. You can use these functions to determine if an object class is from OLE 1 and to convert objects between OLE 1 and OLE 2 storage formats.

BOOL CoIsOle1Class(

REFCLSID rclsid,	//CLSID to check
);
Parameter

rclsid

Indicates the reference to the CLSID to check.

Return Values

S_TRUE

Indicates that the CLSID refers to an OLE 1 object.

S_FALSE

Indicates that the CLSID does not refer to an OLE 1 object.

Comments

The CoIsOle1Class function is useful for preventing linking to embedded OLE 1 objects within a container. Once a container has determined that copied data represents an embedded object, CoIsOle1Class can be called to determine whether the embedded object is an OLE 1 object. If CoIsOle1Class returns S_TRUE, the container does not offer Link Source.

See Also

OleConvertIStorageToOLESTREAM, OleConvertIStorageToOLESTREAMEx, OleConvertOLESTREAMToIStorage, OleConvertOLESTREAMToIStorageEx


CoLoadLibrary
CoLoadLibrary   QuickInfo

Loads a specific DLL into the caller's process. The CoGetClassObject function calls CoLoadLibrary internally; applications should not call it directly.

HINSTANCE CoLoadLibrary(

LPOLESTR lpszLibName,	//Points to the name of the library to be loaded
BOOL bAutoFree	//Indicates whether library is automatically freed
);
Parameters

lpszLibName

Points to the name of the library to be loaded. The use of this name is the same as in the Win32 function LoadLibrary.

bAutoFree

If TRUE, indicates that this library is freed when it is no longer needed, through a call to either the CoFreeUnusedLibraries or CoUninitialize functions. If FALSE, the library should be explicitly freed with the CoFreeLibrary function.

Return Values

Module Handle

Indicates handle of the loaded library.

NULL

Indicates library could not be loaded.

Comments

The CoLoadLibrary function is called internally by the CoGetClassObject function when the class context (CLSCTX) indicates a DLL. CoLoadLibrary loads a DLL specified by the lpszLibName parameter into the process that called CoGetClassObject. Containers should not call CoLoadLibrary directly.

Internally, a reference count is kept on the loaded DLL, by using CoLoadLibrary to increment the count and the CoFreeLibrary function to decrement it.

See Also

CoFreeAllLibraries, CoFreeLibrary, CoFreeUnusedLibraries, CoGetClassObject


CoLockObjectExternal
CoLockObjectExternal   QuickInfo

Called either to lock an object to ensure that it stays in memory, or to release such a lock. Call CoLockObjectExternal to place a strong lock on an object to ensure that it stays in memory.

STDAPI CoLockObjectExternal(

IUnknown * pUnk,	//Pointer to object to be locked or unlocked
BOOL fLock,	//TRUE = lock, FALSE = unlock
BOOL fLastUnlockReleases	//TRUE = release all pointers to object
);
Parameters

pUnk

Points to the object (through its IUnknown interface) to be locked or unlocked.

fLock

Specifies whether the object is to be locked or released. Specifying TRUE holds a reference to the object (keeping it in memory), locking it independently of external or internal AddRef/Release operations, registrations, or revocations. If fLock is TRUE, fLastLockReleases is ignored. FALSE releases a lock previously set with a call to this function.

fLastUnlockReleases

Specifies whether a given lock is the last reference that is supposed to keep an object alive. If it is, TRUE releases all pointers to the object (there may be other references that are not supposed to keep it alive).

Return Values

S_OK

Indicates the object was locked successfully.

E_OUTOFMEMORY

Out of memory.

E_INVALIDARG

Indicates one or more arguments are invalid.

E_UNEXPECTED

Indicates an unexpected error occurred.

Comments

The CoLockObjectExternal function prevents the reference count of an object from going to zero, thereby "locking" it into existence until the lock is released. The same function (with different parameters) releases the lock. The lock is implemented by having the system call IUnknown::AddRef on the object. The system then waits to call IUnknown::Release on the object until a later call to CoLockObjectExternal with fLock set to FALSE. This function can be used to maintain a reference count on the object on behalf of the end-user, because it acts outside of the object, as does the user.

The CoLockObjectExternal function must be called in the process in which the object actually resides (the EXE process, not the process in which handlers may be loaded).

Calling CoLockObjectExternal sets a strong lock on an object. A strong lock keeps an object in memory, while a weak lock does not. Strong locks are required, for example, during a silent update to an OLE embedding. The embedded object's container must remain in memory until the update process is complete. There must also be a strong lock on an application object to ensure that the application stays alive until it has finished providing services to its clients. All external references place a strong reference lock on an object.

The CoLockObjectExternal function is typically called in the following situations:

•	Object applications should call CoLockObjectExternal with both fLock and fLastLockReleases set to TRUE when they become visible. This call creates a strong lock on behalf of the user. When the application is closing, free the lock with a call to CoLockObjectExternal, setting fLock to FALSE and fLastLockReleases to TRUE.

•	A call to CoLockObjectExternal on the application object can also be used in the implementation of IOleContainer::LockContainer.

There are several things to be aware of when you use CoLockObjectExternal in the implementation of IOleContainer::LockContainer. An embedded object would call IOleContainer::LockContainer on its container to keep it running (to lock it) in the absence of other reasons to keep it running. When the embedded object becomes visible, the container must weaken its connection to the embedded object with a call to the OleSetContainedObject function, so other connections can affect the object.

Unless an application manages all aspects of its application and document shutdown completely with calls to CoLockObjectExternal, the container must keep a private lock count in IOleContainer::LockContainer so that it exits when the lock count reaches zero and the container is invisible. Maintaining all aspects of shutdown, and thereby avoiding keeping a private lock count, means that CoLockObjectExternal should be called whenever one of the following conditions occur:

•	A document is created and destroyed or made visible or invisible.

•	An application is started and shut down by the user.

•	A pseudo-object is created and destroyed.

For debugging purposes, it may be useful to keep a count of the number of external locks (and unlocks) set on the application.

Note  The end-user has explicit control over the lifetime of an application, even if there are external locks on it. That is, if a user decides to close the application (File, Exit), it must shut down. In the presence of external locks (such as the lock set by CoLockObjectExternal), the application can call the CoDisconnectObject function to force these connections to close prior to shutdown.

See Also

IOleContainer::LockContainer, OleSetContainedObject


CoMarshalHresult
CoMarshalHresult   QuickInfo

Marshals an HRESULT to the specified stream so it can be unmarshaled using the CoUnmarshalHresult function.

STDAPI CoMarshalHresult(

IStream * pStm,	//Stream to be used for marshalling
HRESULT hresult	//HRESULT to be marshalled
);
Parameters

pStm

Points to the stream used for marshalling.

hresult

Specifies the HRESULT in the originating process.

Return Values

S_OK

Indicates the HRESULT was marshalled successfully.

STG_E_INVALIDPOINTER

Indicates bad pointer passed in for pStm.

STG_E_MEDIUMFULL

Indicates the medium is full.

E_OUTOFMEMORY

Out of memory.

E_INVALIDARG

Indicates one or more arguments are invalid.

E_UNEXPECTED

Indicates an unexpected error occurred.

Comments

You typically do not need to call this function. If you are performing custom marshalling (that is, writing your own implementation of IMarshal) and you need to marshal an HRESULT from one process to another, either as a parameter or a return code, you must call this function. An HRESULT is process-specific, so an HRESULT valid in one process might not be valid in another.

Note that the HRESULT returned by CoMarshalHresult indicates the success or failure of the marshalling process and is unrelated to the HRESULT parameter.

See Also

CoUnmarshalHresult


CoMarshalInterface
CoMarshalInterface   QuickInfo

Marshals an interface pointer into the specified stream. Marshalling consists of writing the appropriate data into the stream so the CoUnmarshalInterface function can use that data to initialize a proxy object in another process. CoMarshalInterface can marshal only interfaces derived from IUnknown.

STDAPI CoMarshalInterface(

IStream *pStm,	//Stream used for marshalling
REFIID riid,	//Identifies interface being marshalled
IUnknown *pUnk,	//Interface pointer being marshalled
DWORD dwDestContext,	//Specifies destination process
void *pvDestContext,	//Reserved for future use
DWORD mshlflags	//Specifies reason for marshalling
);
Parameters

pStm

Points to the stream to be used during marshalling.

riid

Specifies the IID of the interface pointer being marshaled. This interface must be derived from the IUnknown interface.

pUnk

Points to the interface pointer to be marshalled.

dwDestContext

Specifies the destination context, which is the process in which the unmarshalling will be done. The legal values for dwDestContext are taken from the enumeration MSHCTX.

pvDestContext

Indicates reserved for future use; must be set to zero by the caller.

mshlflags

Specifies why marshalling is taking place. The legal values for mshlflags are taken from the MSHLFLAGS enumeration.

Return Values

S_OK

Indicates the interface pointer was marshalled successfully.

CO_E_NOTINITIALIZED

Indicates the CoInitialize or OleInitialize function was not called on the current thread before this function was called.

E_OUTOFMEMORY

Out of memory.

E_INVALIDARG

Indicates one or more arguments are invalid.

E_UNEXPECTED

Indicates an unexpected error occurred.

E_FAIL

Indicates an unspecified error.

IStream errors

See the IStream interface for information on possible stream access errors.

Comments

The main steps that CoMarshalInterface performs are the following:

1.	The function checks whether custom marshaling is supported by calling the QueryInterface function on pUnk and asking for an IMarshal interface pointer. If the object does not support custom marshalling, the function gets an IMarshal interface pointer to the system's standard marshalling implementation.

2.	Using whichever IMarshal interface pointer it has acquired, the function calls IMarshal::GetUnmarshalClass to get the CLSID of the unmarshaller (the proxy to be created). Then it writes the CLSID to the stream.

3.	The function calls IMarshal::MarshalInterface to marshal the interface pointer.

You typically do not need to call this function. OLE calls it from within interface proxies or stubs that marshal an interface pointer.

The only situation in which you might need to call this function is if you are performing custom marshalling (that is, writing your own implementation of IMarshal). Your implementation of IMarshal::MarshalInterface writes to a stream the data needed to initialize a custom proxy in the destination context. If your custom proxy will need access to a private object, you can include an interface pointer to that object as part of the data you write to the stream. In such situations, if you want to use standard marshalling when passing the interface pointer, you can call CoMarshalInterface to do so; this is an example of using standard marshaling within your implementation of custom marshaling.

See Also

CoUnmarshalInterface, IMarshal::MarshalInterface


CoMarshalInterThreadInterfaceInStream

Passes streams containing interfaces between different threads, and is a helper that allows you to pass interface pointers easily and correctly between threads.

HRESULT CoMarshalInterThreadInterfaceInStream(

REFIID riid,	//Interface exposed by the object to be marshaled
LPUNKNOWN pUnk,	//Points to the object to be marshaled
LPSTREAM * ppStm	//Output pointer to the stream interface
);
Parameters

riid

Specifies the interface that is to be marshalled.

pUnk

Points to the IUnknown of the object to be marshalled, thus specifying the object.

ppStm

[Out] On return, points to the stream containing the interface .

Return Values

S_OK

Output stream contains marshalled interface.

E_OUTOFMEMORY

There was not enough memory to complete the call.

E_INVALIDARG

One or more arguments are invalid.

Comments

CoMarshalInterThreadInterfaceInStream is a helper function that facilitates passing streams containing interfaces between threads, although you could implement it yourself from existing APIs if desired. It creates a stream and passes it to CoMarshalInterface, then passes the pointer to that stream back to the caller. The stream it returns is guaranteed to behave correctly when different threads access it. The receiving thread can then call the corresponding helper function CoGetInterfaceAndReleaseStream to get the interface pointer and release the stream object.

See Also

CoGetInterfaceAndReleaseStream


CoRegisterClassObject
CoRegisterClassObject   QuickInfo

Registers an EXE class object with OLE so that other applications can connect to it. EXE object applications should call CoRegisterClassObject on startup. It can also be used to register internal objects for use by the same EXE or other code (such as DLLs) that the EXE uses.

STDAPI CoRegisterClassObject(

REFCLSID rclsid,	//Class identifier to be registered
IUnknown * pUnk,	//Pointer to the class object
DWORD dwClsContext,	//Context for running executable code
DWORD flags,	//How to connect to the class object
LPDWORD * lpdwRegister	//Pointer to the value returned
);
Parameters

rclsid

Specifies the CLSID registered.

pUnk

Points to the class object whose availability is being published.

dwClsContext

Specifies the context in which the executable code is to be run. For information on these context values, see the CLSCTX enumeration.

flags

Determines how connections are made to the class object. For information on these flags, see the REGCLS enumeration.

lpdwRegister

Points to the value returned by CoRegisterClassObject that identifies the class object; later used by the CoRevokeClassObject function to revoke the registration.

Return Values

S_OK

Indicates the class object was registered successfully.

CO_E_OBJISREG

Indicates already registered in the class object table.

E_OUTOFMEMORY

Out of memory.

E_INVALIDARG

Indicates one or more arguments are invalid.

E_UNEXPECTED

Indicates an unexpected error occurred.

Comments

Only EXE object applications call CoRegisterClassObject. Servers that can create and support more than one kind of object (such as multiple types of embeddable objects) must also register each of class of object it supports. Object handlers or DLL object applications do not call this function; instead, they must implement and export the DllGetClassObject function.

When a multiple-use EXE object application is started, it must create a class object with the IClassFactory interface on it and register it with a call to CoRegisterClassObject. Object applications that support several different object definitions must allocate a different class object for each.

Multiple registrations of the same class object are independent and do not produce an error. Each subsequent registration yields a unique key in lpdwRegister.

Multiple document interface (MDI) applications must register their class objects. Single document interface (SDI) applications must register their class objects only if they can be started by means of the /Embedding switch.

The server for a class object should call CoRevokeClassObject to revoke the class object when all of the following are true:

•	There are no existing instances of the object definition

•	There are no locks on the class object

•	The application providing services to the class object is not under user control (not visible to the user on the display).

After the class object is revoked, when its reference count reaches zero, the class object can be destroyed, allowing the application to exit.

For information on the flags parameter, refer to the REGCLS enumeration.

See Also

CoGetClassObject, CoRevokeClassObject, DllGetClassObject, REGCLS, CLSCTX


CoRegisterMallocSpy

Registers an implementation of the IMallocSpy interface in OLE, thereafter requiring OLE to call its wrapper methods around every call to the corresponding IMalloc method. IMallocSpy is defined in OLE to allow debugging of memory allocations.

HRESULT CoRegisterMallocSpy(

LPMALLOCSPY pMallocSpy	//Pointer to an instance of IMallocSpy
);
Parameter

pMallocSpy

Points to an instance of the IMallocSpy implementation.

Return Values

S_OK

Indicates the IMallocSpy object is successfully registered.

CO_E_OBJISREG

Indicates there is already a registered spy.

E_INVALIDARG

Indicates the call to the QueryInterface function in pMallocSpy for IID_IMallocSpy is unsuccessful, or pMallocSpy is NULL.

Comments

The CoRegisterMallocSpy function registers the IMallocSpy object, which is used to debug calls to IMalloc methods. The function calls QueryInterface on the pointer pMallocSpy for the interface IID_IMallocSpy. This is to ensure that pMallocSpy really supports an implementation of IMallocSpy. By the rules of OLE, it is expected that a successful call to QueryInterface has added a reference (through the AddRef function) to the IMallocSpy object. That is, CoRegisterMallocSpy does not directly call AddRef on pMallocSpy, but fully expects that the QueryInterface call will.

When the IMallocSpy object is registered, whenever there is a call to one of the IMalloc methods, OLE first calls the corresponding IMallocSpy pre-method. Then, after executing the IMalloc method, OLE calls the corresponding IMallocSpy post-method. For example, whenever there is a call to IMalloc::Alloc, from whatever source, OLE calls IMallocSpy::PreAlloc, calls IMalloc::Alloc, and after that allocation is completed, calls IMallocSpy::PostAlloc.

See Also

IMallocSpy, CoRevokeMallocSpy, CoGetMalloc


CoRegisterMessageFilter
CoRegisterMessageFilter   QuickInfo

Registers with OLE the instance of an EXE application's IMessageFilter interface, which is to be used for handling concurrency issues. DLL object applications cannot register a message filter.

HRESULT CoRegisterMessageFilter(

LPMESSAGEFILTER lpMessageFilter,	//IMessageFilter interface supplied by app
LPMESSAGEFILTER * lplpMessageFilter	//Prior IMessageFilter instance if non-NULL
);
Parameters

lpMessageFilter

Points to an IMessageFilter interface supplied by the application. Can be NULL, indicating that the current IMessageFilter registration should be revoked.

lplpMessageFilter

If this parameter is non-NULL, returns a pointer to the previously registered IMessageFilter instance. If NULL, indicates no previous IMessageFilter instance was registered.

Return Values

S_OK

Indicates the IMessageFilter instance registered or revoked successfully.

S_FALSE

Indicates an error registering or revoking IMessageFilter instance.


CoReleaseMarshalData
CoReleaseMarshalData   QuickInfo

Destroys a previously marshalled data packet.

STDAPI CoReleaseMarshalData(

IStream * pStm	//Stream containing data packet
);
Parameter

pStm

Points to the stream that contains the data packet which is to be destroyed.

Return Values

S_OK

Indicates the data packet was successfully destroyed.

STG_E_INVALIDPOINTER

Indicates an IStream error dealing with the pStm parameter.

CO_E_NOTINITIALIZED

Indicates that the CoInitialize or OleInitialize  function was not called on the current thread before this function was called.

E_OUTOFMEMORY

Out of memory.

E_INVALIDARG

Indicates pStm is invalid.

E_UNEXPECTED

Indicates an unexpected error occurred.

E_FAIL

Indicates an unspecified error.

Comments

The main steps that CoReleaseMarshalData performs are the following:

1.	The function reads a CLSID from the stream.

2.	If standard marshalling is being used, the function gets an IMarshal pointer to an instance of the standard unmarshaller. If custom marshalling is being used, the function creates a proxy by calling the CoCreateInstance function, passing the CLSID it read from the stream, and requests an IMarshal interface pointer to the newly created proxy.

3.	Using whichever IMarshal interface pointer it has acquired, the function calls IMarshal::ReleaseMarshalData.

You typically do not call this function. The only situation in which you might need to call this function is if you use custom marshalling (write and use your own implementation of IMarshal). Examples of when CoReleaseMarshalData should be called include the following situations:

•	An attempt was made to unmarshal the data packet, but it failed.

•	A marshalled data packet was removed from a global table.

As an analogy, the data packet can be thought of as a reference to the original object, just as if it were another interface pointer being held on the object. Like a real interface pointer, that data packet must be released at some point. The use of IMarshal::ReleaseMarshalData to release data packets is analogous to the use of IUnknown::Release to release interface pointers.

Note that you do not need to call CoReleaseMarshalData after a successful call of the CoUnmarshalInterface function; that function releases the marshal data as part of the processing that it does.

See Also

IMarshal::ReleaseMarshalData


CoRevokeClassObject
CoRevokeClassObject   QuickInfo

Informs OLE that a class object, previously registered with the CoRegisterClassObject function, is no longer available for use.

HRESULT CoRevokeClassObject(

DWORD dwRegister	//Token on class object returned from call to CoRegisterClassObject
);
Parameter

dwRegister

Specifies the token previously returned from the CoRegisterClassObject function.

Return Values

S_OK

Indicates the class object was successfully revoked.

E_OUTOFMEMORY

Out of memory.

E_INVALIDARG

Indicates the dwRegister parameter does not map to a registered class object.

E_UNEXPECTED

Indicates an unexpected error occurred.

Comments

If a call to CoRevokeClassObject is successful, it means that the class object has been removed from the global class object table. However, if other clients still have pointers to the class object and have caused the reference count to be incremented by calls to IUnknown::AddRef, the reference count will not be zero. When this occurs, applications may benefit if subsequent calls (with the obvious exceptions of IUnknown::AddRef and IUnknown::Release) to the class object fail.

The object application must call CoRevokeClassObject to revoke registered class objects before exiting the program. Class object implementors should call CoRevokeClassObject as part of the release sequence. You must specifically revoke the class object even when you have specified the flags value REGCLS_SINGLEUSE in a call to CoRegisterClassObject, indicating that only one application can connect to the class object.

See Also

CoGetClassObject, CoRegisterClassObject


CoRevokeMallocSpy

Revokes a registered IMallocSpy object.

HRESULT CoRevokeMallocSpy();

Return Values

S_OK

Indicates the IMallocSpy object is successfully revoked.

CO_E_OBJNOTREG

Indicates no spy is currently registered.

E_ACCESSDENIED

Indicates a spy is registered but there are outstanding allocations (not yet freed) made while this spy was active.

Comments

The IMallocSpy object is released when it is revoked. This release corresponds to the call to IUnknown::AddRef in the implementation of the QueryInterface function by the CoRegisterMallocSpy function. The implementation of the IMallocSpy interface should then do any appropriate clean-up.

If the return code is E_ACCESSDENIED, there are still outstanding allocations that were done while the spy was active. The registered spy cannot be revoked at this time because it may have attached arbitrary headers and/or trailers to these allocations which only the spy knows about. Only the spy's PreFree (or PreRealloc) method knows how to account for these headers and trailers. Before returning E_ACCESSDENIED, CoRevokeMallocSpy notes internally that a revoke is pending. When the outstanding allocations have been freed, the revoke proceeds automatically, releasing the IMallocSpy object. This means that it is necessary to call CoRevokeMallocSpy only once for each call to CoRegisterMallocSpy, even if E_ACCESSDENIED is returned.

See Also

IMallocSpy, CoRegisterMallocSpy, CoGetMalloc


CoTaskMemAlloc
CoTaskMemAlloc   QuickInfo

Allocates a block of task memory in the same way that IMalloc::Alloc does.

LPVOID CoTaskMemAlloc(

ULONG cb	//Size in bytes of memory block to be allocated
);
Parameter

cb

Specifies the size (in bytes) of the memory block to be allocated.

Return Values

Allocated memory block

Indicates memory block allocated successfully.

NULL

Indicates insufficient memory available.

Comments

The CoTaskMemAlloc function uses the default allocator to allocate a memory block in the same way that IMalloc::Alloc does. It is not necessary to call the CoGetMalloc function before calling CoTaskMemAlloc.

The initial contents of the returned memory block are undefined − there is no guarantee that the block has been initialized. The allocated block may be larger than cb bytes because of the space required for alignment and for maintenance information.

If cb is zero, CoTaskMemAlloc allocates a zero-length item and returns a valid pointer to that item. If there is insufficient memory available, CoTaskMemAlloc returns NULL.

Note  Applications should always check the return value from this method, even when requesting small amounts of memory, because there is no guarantee the memory will be allocated.

See Also

IMalloc::Alloc, CoGetMalloc, CoTaskMemFree, CoTaskMemRealloc


CoTaskMemFree
CoTaskMemFree   QuickInfo

Frees a block of task memory previously allocated through a call to the CoTaskMemAlloc or CoTaskMemRealloc function.

void CoTaskMemFree(

void pv	//Points to memory block to be freed
);
Parameter

pv

Points to the memory block to be freed.

Comments

The CoTaskMemFree function, using the default OLE allocator, frees a block of memory previously allocated through a call to the CoTaskMemAlloc or CoTaskMemRealloc function.

The number of bytes freed equals the number of bytes that were originally allocated or reallocated. After the call, the memory block pointed to by pv is invalid and can no longer be used.

Note  The pv parameter can be NULL, in which case this method has no effect.

See Also

CoTaskMemAlloc, CoTaskMemRealloc, CoGetMalloc, IMalloc::Free


CoTaskMemRealloc
CoTaskMemRealloc   QuickInfo

Changes the size of a previously allocated block of task memory.

LPVOID CoTaskMemRealloc(

LPVOID pv,	//Points to memory block to be reallocated
ULONG cb	//Size in bytes of block to be reallocated
);
Parameters

pv

Points to the memory block to be reallocated. It can be a NULL pointer, as discussed in the Comments.

cb

Specifies the size in bytes of the memory block to be reallocated. It can be zero, as discussed in the following remarks.

Return Values

Reallocated memory block

Indicates memory block successfully reallocated.

NULL

Indicates insufficient memory or cb is zero and pv is not NULL.

Comments

The CoTaskMemRealloc function changes the size of a previously allocated memory block in the same way that IMalloc::Realloc does. It is not necessary to call the CoGetMalloc function to get a pointer to the OLE allocator before calling CoTaskMemRealloc.

The pv argument points to the beginning of the memory block. If pv is NULL, CoTaskMemRealloc allocates a new memory block in the same way as the CoTaskMemAlloc function. If pv is not NULL, it should be a pointer returned by a prior call to CoTaskMemAlloc.

The cb argument specifies the size (in bytes) of the new block. The contents of the block are unchanged up to the shorter of the new and old sizes, although the new block can be in a different location. Because the new block can be in a different memory location, the pointer returned by CoTaskMemRealloc is not guaranteed to be the pointer passed through the pv argument. If pv is not NULL and cb is zero, then the memory pointed to by pv is freed.

CoTaskMemRealloc returns a void pointer to the reallocated (and possibly moved) memory block. The return value is NULL if the size is zero and the buffer argument is not NULL, or if there is not enough memory available to expand the block to the given size. In the first case, the original block is freed; in the second, the original block is unchanged.

The storage space pointed to by the return value is guaranteed to be suitably aligned for storage of any type of object. To get a pointer to a type other than void, use a type cast on the return value.

See Also

CoTaskMemAlloc, CoTaskMemFree, CoGetMalloc, IMalloc::Realloc


CoTreatAsClass
CoTreatAsClass   QuickInfo

Establishes or removes an emulation so objects of one class are treated as objects of a different class.

STDAPI CoTreatAsClass(

REFCLSID clsidOld,	//CLSID for the original object to be emulated
REFCLSID clsidNew	//CLSID for the new object that emulates the original
);
Parameters

clsidOld

Specifies the CLSID of the object to be emulated.

clsidNew

Specifies the CLSID of the object that should emulate the original object. This replaces any existing emulation for clsidOld. Can be CLSID_NULL, in which case any existing emulation for clsidOld is removed.

Return Values

S_OK

Indicates the emulation was successfully established or removed.

REGDB_E_CLASSNOTREG

Indicates the clsidOld parameter is not properly registered in the registration database.

REGDB_E_READREGDB

Indicates error reading from registration database.

REGDB_E_WRITEREGDB

Indicates error writing to registration database.

E_INVALIDARG

Indicates the clsidOld parameter specifies an OLE 1 class.

Comments

This function sets the TreatAs entry in the registration database for the specified object. After this entry is set, the CoGetClassObject function and object handlers (including the default handler) are transparently forwarded to the new CLSID when they consult the registration database for the old CLSID. For example, launching the object application for clsidOld would actually launch the object application for clsidNew instead. The IOleObject::EnumVerbs method in the default handler enumerates the verbs from clsidNew instead of clsidOld.

During installation, setup programs should call CoTreatAsClass, setting the clsidNew parameter to CLSID_NULL to remove any existing emulation for the classes they install.

If you set a class to emulate itself, that is, the values for clsidNew and clsidOld are the same, this function has two possible results depending on the AutoTreatAs key in the registration database. If there is a CLSID assigned to the AutoTreatAs key, then the AutoTreatAs CLSID is assigned to the TreatAs key. If there is no value assigned to the AutoTreatAs key, then the TreatAs entry is removed.

The CoTreatAsClass function does not validate whether an appropriate registration database entry for clsidNew currently exists.

See Also

CoGetTreatAsClass


CoUninitialize
CoUninitialize   QuickInfo

Closes the OLE Component Object Model(COM) library, freeing any resources that it maintains and forcing all RPC connections to close.

void CoUninitialize();

Comments

The CoInitialize and CoUninitialize calls must be balanced − if there are multiple calls to the CoInitialize function, there must be the same number of calls to CoUninitialize: Only the CoUninitialize call corresponding to the CoInitialize call that initialized the library can close it.

The OleUninitialize function calls CoUninitialize internally, so applications that call OleUninitialize do not also need to call CoUninitialize.

The CoUninitialize function should be called on application shutdown, as the last call made to the COM library after the application hides its main windows and falls through its main message loop. If there are open conversations remaining, CoUninitialize starts a modal message loop and dispatches any pending messages from the containers or server for this OLE application. By dispatching the messages, CoUninitialize ensures that the application does not quit before receiving all of its pending messages. Non-OLE messages are discarded.

See Also

CoInitialize, OleUninitialize


CoUnmarshalHresult
CoUnmarshalHresult   QuickInfo

Unmarshals an HRESULT type from the specified stream.

STDAPI CoUnmarshalHresult(

LPSTREAM pStm,	//Stream used for unmarshalling
HRESULT * phresult	//Receives the HRESULT
);
Parameters

pStm

Points to the stream from which the HRESULT is to be unmarshalled.

phresult

Receives the unmarshalled HRESULT.

Return Values

S_OK

Indicates the HRESULT was unmarshalled successfully.

STG_E_INVALIDPOINTER

Indicates pStm is an invalid pointer.

E_OUTOFMEMORY

Out of memory.

E_INVALIDARG

Indicates one or more arguments are invalid.

E_UNEXPECTED

Indicates an unexpected error occurred.

Comments

You typically do not need to call this function. The only situation in which you would need to call this function is if you are performing custom marshalling (that is, writing your own implementation of IMarshal). You must use CoUnmarshalHresult to unmarshal HRESULTs previously marshalled by a call to the CoMarshalHresult function.

See Also

CoMarshalHresult


CoUnmarshalInterface
CoUnmarshalInterface   QuickInfo

Initializes a proxy object using data written into the stream by a previous call to the CoMarshalInterface function, and returns an interface pointer to that proxy object.

STDAPI CoUnmarshalInterface(

IStream * pStm,	//Stream used for unmarshalling
REFIID riid,	//IID of interface pointer desired
void ** ppv	//Receives the interface pointer
);
Parameters

pStm

Points to the stream from which the interface pointer is to be unmarshalled.

riid

Specifies the IID of the interface pointer desired.

ppv

Receives the interface pointer.

Return Values

S_OK

Indicates the interface was unmarshalled successfully.

STG_E_INVALIDPOINTER

Indicates pStm is an invalid pointer.

CO_E_NOTINITIALIZED

Indicates the CoInitialize or OleInitialize function was not called on the current thread before this function was called.

CO_E_OBJNOTCONNECTED

Indicates the object application has been disconnected from the remoting system (for example, as a result of a call to the CoDisconnectObject function).

REGDB_E_CLASSNOTREG

Indicates an error occurred reading the registration database.

E_OUTOFMEMORY

Out of memory.

E_INVALIDARG

Indicates one or more arguments are invalid.

E_UNEXPECTED

Indicates an unexpected error occurred.

E_NOINTERFACE

Indicates the final QueryInterface of this function for the requested interface returned E_NOINTERFACE.

E_FAIL

Indicates an unspecified error.

CoCreateInstance errors

Indicates an error occurred when creating the handler (standard or custom marshaling).

Comments

The main steps that CoUnmarshalInterface performs are the following:

1.	The function reads a CLSID from the stream.

2.	If standard marshalling is being used, the function gets an IMarshal pointer to an instance of the standard unmarshaller. If custom marshalling is being used, the function creates a proxy by calling the CoCreateInstance function, passing the CLSID it read from the stream, and requests an IMarshal interface pointer to the newly created proxy.

3.	Using whichever IMarshal interface pointer it has acquired, the function then calls IMarshal::UnmarshalInterface and, if appropriate, IMarshal::ReleaseMarshalData.

You typically do not need to call this function. The primary caller of this function is OLE, from within interface proxies or stubs that unmarshal an interface pointer.

The only place where you might need to call this function is from your implementation of IMarshal::UnmarshalInterface, if you are performing custom marshaling. If your implementation of IMarshal::MarshalInterface called the CoMarshalInterface function to marshal an interface pointer to the stream, you must call CoUnmarshalInterface to retrieve that interface pointer. The retrieved interface pointer is typically a pointer to a private object in the originating process.

See Also

CoMarshalInterface, IMarshal::UnmarshalInterface


CreateAntiMoniker
CreateAntiMoniker   QuickInfo

Creates and returns a new anti-moniker.

WINOLEAPI CreateAntiMoniker(

LPMONIKER FAR *ppmk	//Receives the anti-moniker
);
Parameter

ppmk

Receives an IMoniker interface pointer to the new anti-moniker. The returned pointer is NULL if an error occurs; if non-NULL, the function has called IUnknown::AddRef on the parameter and the caller is responsible for calling IUnknown::Release.

Return Values

S_OK

Indicates the anti-moniker was created successfully.

E_OUTOFMEMORY

Indicates insufficient memory.

Comments

You would call this function only if you are writing your own moniker class (implementing the IMoniker interface). If you want an anti-moniker to act as the inverse for your moniker class, you can call CreateAntiMoniker from your implementation of IMoniker::Inverse.

The inverse of a moniker is analogous to the ".." directory in MS-DOS file systems; the ".." directory acts as the inverse to any other directory name, because appending ".." to a directory name results in an empty path. In the same way, the inverse of a moniker typically is also the inverse of all monikers in the same class. However, it is not necessarily the inverse of a moniker of a different class.

An anti-moniker can be used as the inverse for certain classes of monikers. For example, the system-provided implementations of file monikers, item monikers, and pointer monikers all use anti-monikers as their inverse; consequently, an anti-moniker composed to the right of a file, item, or pointer moniker composes to nothing.

If you're a moniker client, you typically do not know the class of the moniker you're using. If you need to get the inverse of a moniker, you should always call IMoniker::Inverse rather that the CreateAntiMoniker function, because you cannot be certain that the moniker you're using considers an anti-moniker to be its inverse. For example, if you need to remove the last piece of a composite moniker, call IMoniker::Enum on the composite, specifying FALSE as the first parameter; this call creates an enumerator that returns the component monikers in reverse order. Use the enumerator to retrieve the last piece of the composite, and call IMoniker::Inverse on that moniker. The moniker returned by IMoniker::Inverse will remove the last piece of the composite.

If you are writing a new moniker class and you have no special requirements for its inverse, you can use CreateAntiMoniker in your implementation of the IMoniker::Inverse method, and then check for an anti-moniker in your implementation of IMoniker::ComposeWith.

See Also

IMoniker::Inverse, IMoniker::ComposeWith, IMoniker - Anti-Moniker Implementation


CreateBindCtx
CreateBindCtx   QuickInfo

Creates a bind context. A bind context is an object that stores information about a particular moniker-binding operation. A bind context is required as a parameter in many methods of the IMoniker interface and in certain functions related to monikers.

STDAPI CreateBindCtx(

DWORD reserved,	//Reserved for future use
LPBC FAR* ppbc	//Receives the pointer to the bind context
);
Parameters

reserved

Indicates reserved for future use; must be zero.

ppbc

Receives an IBindCtx interface pointer to the new bind context. The returned pointer is NULL if an error occurs; if non-NULL, the caller is responsible for calling IUnknown::Release on the parameter.

Return Values

S_OK

Indicates the bind context was allocated and initialized successfully.

E_OUTOFMEMORY

Indicates insufficient memory.

Comments

The most common use of CreateBindCtx is in binding a moniker (getting a pointer to an interface by ideintifying it through a moniker). This X typically takes the following steps:

1.	Create a bind context by calling the CreateBindCtx function.

2.	Call the IMoniker::BindToObject method on the moniker, retrieving an interface pointer.

3.	Release the bind context.

4.	Use the interface pointer.

5.	Release the interface pointer.

Here's a code fragment that illustrates these steps:

// pMnk is an IMoniker * that points to a previously-acquired moniker

IFoo *pFoo;

IBindCtx *pbc;

CreateBindCtx( 0, &pbc );

pMnk->BindToObject( pbc, NULL, IID_IFoo, &pFoo );

pbc->Release();

// pFoo now points to the object; safe to use pFoo

pFoo->Release();

Bind contexts are also used in other methods of the IMoniker interface besides IMoniker::BindToObject and in the MkParseDisplayName function.

A bind context retains references to the objects that are bound during the binding operation. This causes the bound objects to remain active until the bind context is released. This can improve performance in subsequent binding operations if they are trying to bind to the same objects. However, this potential performance enhancement should be balanced against the costs of keeping the objects activated unnecessarily (i.e., keeping the object's server running).

In general, you can benefit from reusing a bind context for a few sequential bind operations if those operations are likely to require the same objects, but you should release the bind context rather than holding onto it for a long period. If you don't release the bind context, objects registered with the bind context will remain active unnecessarily.

A bind context contains a BIND_OPTS structure, which contains parameters that apply to all steps in a binding operations. When you create a bind context using CreateBindCtx, the fields of the BIND_OPTS structure are initialized to the following values:

cbStruct = sizeof(BIND_OPTS)

grfFlags = 0

grfMode = STGM_READWRITE

dwTickCountDeadline = 0.

You can call the IBindCtx::SetBindOptions method to modify these values, if you want values other from the defaults.

See Also

BIND_OPTS, IBindCtx, IMoniker, MkParseDisplayName


CreateDataAdviseHolder
CreateDataAdviseHolder   QuickInfo

Returns a new instance of an OLE-provided implementation of the IDataAdviseHolder interface.

STDAPI CreateDataAdviseHolder(

IDataAdviseHolder **ppDAHolder	//Pointer to the new instance of IDataAdviseHolder
);
Parameter

ppDAHolder

Points to the location where the pointer to the new advise holder object should be returned.

Return Values

S_OK

The IDataAdviseHolder interface was instantiated and the pointer returned.

E_OUTOFMEMORY

Indicates that OLE ran out of memory and IDataAdviseHolder could not be instantiated.

Comments

The IDataAdviseHolder interface is called by your implementation of the IDataObject::DAdvise interface to keep track of connections to advise sinks and to send notifications when necessary.

See Also

IDataAdviseHolder


CreateDataCache
CreateDataCache   QuickInfo

Returns a new instance of an OLE-provided implementation of a cache.

HRESULT CreateDataCache(

LPUNKNOWN pUnkOuter,	//Pointer to controlling unknown of aggregate
REFCLSID rclsid,	//CLSID used to generate icon labels
REFIID riid,	//Interface used to communicate with cache
LPVOID FAR *ppvObj	//Pointer to returned cache object
);
Parameters

pUnkOuter

Points to the controlling unknown if the cache is to be created as part of an aggregate. This parameter may be NULL, indicating that there is no aggregate.

rclsid

Specifies the CLSID used to generate icon labels. This value is typically CLSID_NULL.

riid

Specifies the interface that will be used by the caller to communicate with the cache. This value is typically IID_IOleCache.

ppvObj

Points to the location of the returned cache object.

Return Values

S_OK

Indicates the OLE-provided cache was instantiated and the pointer returned.

E_INVALIDARG

Indicates one or more arguments are invalid.

E_OUTOFMEMORY

Indicates the interface could not be instantiated due to a lack of memory.

E_NOINTERFACE

Indicates the interface represented by riid is not supported by the object. The parameter ppvObj is set to NULL.

Comments

The cache created by CreateDataCache supports the IOleCache, IOleCache2, and IOleCacheControl interfaces for controlling the cache. It also supports the IPersistStorage, IDataObject (without advise sinks), IViewObject, and IViewObject2 interfaces.

See Also

IOleCache, IOleCache2, IOleCacheControl


CreateFileMoniker
CreateFileMoniker   QuickInfo

Creates a file moniker based on the specified path.

WINOLEAPI CreateFileMoniker(

LPCOLESTR lpszPathName,	//Pathname to be used
LPMONIKER FAR *ppmk	//Receives the file moniker
);
Parameters

lpszPathName

Points to a zero-terminated string containing the path on which this moniker is based. For Win32 applications, the LPCOLESTR type indicates a wide character string (two bytes per character); otherwise, the string has one byte per character.

ppmk

Receives an IMoniker interface pointer to the new file moniker. The returned pointer is NULL if an error occurs; if non-NULL, the function has called IUnknown::AddRef on the parameter and the caller is responsible for calling IUnknown::Release.

Return Values

S_OK

Indicates the moniker was created successfully.

MK_E_SYNTAX

Indicates an error in the syntax of a path was encountered while creating a moniker.

E_OUTOFMEMORY

Indicates insufficient memory.

Comments

CreateFileMoniker should be called by moniker providers, to create a file moniker when that is suitable for identifying its objects. Moniker providers hand out monikers to identify their objects so they are accessible to other parties. You must use file monikers if the objects being identified are stored in files. If each object resides in its own file, file monikers are the only type you need. For objects smaller than a file, you need to use another type of moniker (for example, item monikers) in addition to file monikers. Your objects must also implement the IPersistFile interface for them to be loaded when a file moniker is bound.

The most common example of moniker providers are OLE server applications that support linking. For OLE server applications that support linking only to file-based documents in their entirety, file monikers are the only type of moniker needed. OLE server applications that support linking to objects smaller than a document (such as sections of a document or embedded objects), must use item monikers as well as file monikers.

The lpszPathName can be a relative path, a UNC path (e.g., \\server\share\path), or a drive letter based path (e.g., c:\). If based on a relative path, the resulting moniker will need to be composed onto another file moniker before it can be bound.

A file moniker cannot be composed to the right of any other kind of moniker. It is possible to compose two file monikers together if the first moniker is based on an absolute path and the other is a relative path, resulting in a single file moniker based on the combination of the two paths. To identify objects stored within a file, it is necessary to compose other types of monikers (usually item monikers) to the right of a file moniker.

See Also

IMoniker - File Moniker Implementation


CreateGenericComposite
CreateGenericComposite   QuickInfo

Performs a generic composition of pmkFirst and pmkRest and returns the resulting moniker.

WINOLEAPI CreateGenericComposite(

LPMONIKER pmkFirst,	//First moniker
LPMONIKER pmkRest,	//Second moniker
LPMONIKER FAR *ppmkComposite	//Receives the composite
);
Parameters

pmkFirst

Points to the moniker to be composed to the left of the pmkRest moniker. Can point to any kind of moniker, including a generic composite.

pmkRest

Points to the moniker to be composed to the right of the pmkFirst moniker. Can point to any kind of moniker, including a generic composite.

ppmkComposite

Receives an IMoniker pointer to the moniker that is the result of composing pmkFirst and pmkRest. If either pmkFirst or pmkRest are NULL, the returned pointer is the one that is non-NULL. If both pmkFirst and pmkRest are NULL, or if an error occurs, the returned pointer is NULL. If the returned pointer is non-NULL, the function has called IUnknown::AddRef on the parameter and the caller is responsible for calling IUnknown::Release.

Return Values

S_OK

Indicates the two input monikers were successfully composed.

MK_E_SYNTAX

Indicates the two monikers could not be composed due to an error in the syntax of a path (for example, if both pmkFirst and pmkRest are file monikers based on absolute paths).

E_OUTOFMEMORY

Indicates insufficient memory.

Comments

You would call this function only if you are writing your own moniker class (implementing the IMoniker interface). If you want to perform a generic composition in your implementation of the IMoniker::ComposeWith method, call this function from there.

Composition is the process of joining two monikers together. Sometimes two monikers of specific classes can be combined; for example, a file moniker representing an incomplete path and another file moniker representing a relative path can be combined to form a single file moniker representing the complete path. This is an example of "non-generic" composition. "Generic" composition, on the other hand, can connect any two monikers, no matter what their classes. Because a non-generic composition depends on the class of the monikers involved, it can be done only in the implementation of the IMoniker::ComposeWith method for a particular class. You can define new types of non-generic compositions if you write a new moniker class. In contrast, it is only necessary to call the CreateGenericComposite for generic compositions.

If you are a moniker client and you need to compose two monikers together, you should call the IMoniker::ComposeWith method. This gives the first moniker a chance to perform a non-generic composition. The only time you should call CreateGenericComposite is if you are writing a new moniker class. In the implementation of IMoniker::ComposeWith, you should call CreateGenericComposite once you have determined that your implementation cannot do a non-generic composition.

During the process of composing the two monikers, CreateGenericComposite makes all possible simplifications. Consider the example where pmkFirst is the generic composite moniker, A  (°)  B  (°)  C, and pmkRest is the generic composite moniker, C  (-1)   (°)  B  (-1)   (°)  Z (where C  (-1)  is the inverse of C). The function first composes C to C  (-1) , which composes to nothing. Then it composes B and B  (-1)  to nothing. Finally, it composes A to Z, and returns a pointer to the generic composite moniker, A  (°)  Z.

See Also

IMoniker::ComposeWith, IMoniker - Generic Composite Moniker Implementation


CreateILockBytesOnHGlobal
CreateILockBytesOnHGlobal   QuickInfo

Returns an OLE-provided implementation of the ILockBytes interface which allows you to build a storage object in memory.

HRESULT CreateILockBytesOnHGlobal(

HGLOBAL hGlobal,	//Memory handle for the byte array object
BOOL fDeleteOnRelease,	//Indicates whether to free memory when the object is released
ILockBytes ** ppLkbyt	//Points to location for pointer to the new byte array object
);
Parameters

hGlobal

Contains the memory handle allocated by the GlobalAlloc function. The handle must be allocated as moveable and nondiscardable. If the handle is to be shared between processes, it must also be allocated as shared. New handles should be allocated with a size of zero. If hGlobal is NULL, the CreateILockBytesOnHGlobal function internally allocates a new shared memory block of size zero.

fDeleteOnRelease

Indicates whether the underlying handle for this byte array object should be automatically freed when the object is released.

ppLkbyt

Points to the location where this method places the pointer for the new byte array object, that is, the new instance of the ILockBytes interface.

Return Values

S_OK

Indicates the ILockBytes instance was created successfully.

E_INVALIDARG

Indicates an invalid value was specified for the hGlobal parameter.

E_OUTOFMEMORY

Indicates not enough memory to create an ILockBytes instance.

Comments

This function creates a byte array object in memory using the OLE-provided implementation of the ILockBytes interface. The returned byte array object can be the basis for a compound file. You can call the StgCreateDocfileOnILockBytes function to build a compound file on top of this byte array object. The ILockBytes instance calls the GlobalReAlloc function to grow the memory block as needed.

The current contents of the memory block are undisturbed by the creation of the new byte array object. After creating the ILockBytes instance, you can use the StgOpenStorageOnILockBytes function to reopen a previously existing storage object already contained in the memory block.

Note  If you free the hGlobal memory handle, the byte array object is no longer valid. You must call the ILockBytes::Release method before freeing the memory handle.

The value of the hGlobal parameter can be changed by a subsequent call to the GlobalReAlloc function; thus, you cannot rely on this value after the byte array object is created.

See Also

StgOpenStorageOnILockBytes


CreateItemMoniker
CreateItemMoniker   QuickInfo

Creates an item moniker based on a string that identifies an object within a container, typically a compound document.

WINOLEAPI CreateItemMoniker(

LPCOLESTR lpszDelim,	//Delimiter string
LPCOLESTR lpszItem,	//Item name
LPMONIKER FAR *ppmk	//Receives the item moniker
);
Parameters

lpszDelim

Points to a zero-terminated string containing the delimiter (typically "!") used to separate this item's display name from the display name of its container. For Win32 applications, the LPOLESTR type indicates a wide character string (two bytes per character); otherwise, the string has one byte per character.

lpszItem

Points to a zero-terminated string containing the container's name for the object being identified. This name can later be used to retrieve a pointer to the object in a call to IOleItemContainer::GetObject.

ppmk

Receives an IMoniker pointer to the new item moniker. The returned pointer is NULL if an error occurs; if non-NULL, the function has called IUnknown::AddRef on the parameter and the caller is responsible for calling IUnknown::Release.

Return Values

S_OK

Indicates the moniker was created successfully.

E_OUTOFMEMORY

Indicates insufficient memory.

Comments

A moniker providerthat can identify its objects with an item moniker would call CreateItemMoniker. A moniker provider hands out monikers to identify its objects so they are accessible to other parties. Item monikers identify objects that are contained within another object and can be individually identified using a string. The container of the object must also implement the IOleContainer interface so the objects can be loaded when a item moniker is bound.

The most common example of moniker providers are OLE applications that support linking. If your OLE application supports OLE linking to objects smaller than a file-based documents, you need to use item monikers. A server application that allows linking to a selection within a document, uses item monikers to identify those objects. Container applications that allow linking to embedded objects use item monikers to identify the embedded objects.

The lpszItem parameter is the name used by the document to uniquely identify the object. For example, if the object being identified is a cell range in a spreadsheet, an appropriate name might be something like "A1:E7." If the object being identified is an embedded object, an appropriate name might be something like "embedobj1." The document containing the object must provide an implementation of the IOleItemContainer interface that can interpret the name and locate the corresponding object. This allows the item moniker to be bound to the object it identifies.

Item monikers are typically not used in isolation; they must be composed with a moniker that identifies the document that contains the object. For example, if the object being identified is a cell range contained in a file-based document, the item moniker identifying that object must be composed with the file moniker identifying that document; this results in a composite moniker like "C:\work\sales.xls!A1:E7." It's also possible to have nested containers, for example, if an object is contained within an embedded object inside another document. The complete moniker of such an object would look like "C:\work\report.doc!embedobj1!A1:E7." In such a situation, each container object must call CreateItemMoniker and provide its own implementation of the IOleItemContainer interface.

See Also

IMoniker::ComposeWith, IOleItemContainer, IMoniker - Item Moniker Implementation


CreateOleAdviseHolder
CreateOleAdviseHolder   QuickInfo

Creates an advise holder for managing compound document notifications. It returns an instance of the OLE implementation of the IOleAdviseHolder interface.

HRESULT CreateOleAdviseHolder(

ppOAHolder	//Pointer to a pointer
);
Parameter

ppOAHolder

Points to where to return the new IOleAdviseHolder instance.

Return Values

S_OK

Indicates that the new OLE advise holder returned successfully.

E_OUTOFMEMORY

Indicates insufficient memory to create new advise holder.

Comments

The helper function CreateOleAdviseHolder is an OLE implementation of the IOleAdviseHolder interface. Anyone who wants to write their own implementation of this interface may do so; but the advise holder returned by CreateOleAdviseHolder will suffice for the great majority of applications. If your application has a need to implement IOleAdviseHolder::EnumAdvise; you will need to implement your own advise holder because the one provided by OLE does not support this method.

See Also

IOleAdviseHolder


CreatePointerMoniker
CreatePointerMoniker   QuickInfo

Creates a pointer moniker based on a specified interface pointer.

WINOLEAPI CreatePointerMoniker(

LPUNKNOWN punk,	//Interface pointer to be used
LPMONIKER FAR *ppmk	//Receives the pointer moniker
);
Parameters

punk

Points to an interface pointer to the object to be identified by the resulting moniker.

ppmk

Receives an IMoniker interface pointer to the new pointer moniker. The returned pointer is NULL if an error occurs; if non-NULL, the function has called IUnknown::AddRef on the parameter and the caller is responsible for calling IUnknown::Release.

Return Values

S_OK

Indicates the pointer moniker was created successfully.

E_UNEXPECTED

Indicates an unexpected error occurred.

E_OUTOFMEMORY

Indicates insufficient memory.

Comments

You rarely need to call this function.

A pointer moniker is essentially a wrapping of an interface pointer that allows it to be passed to those interfaces that require monikers. Pointer monikers allow an object that has no persistent representation to participate in a moniker binding operation. Binding a pointer moniker is done by calling the pointer's IUnknown::QueryInterface method.

See Also

IMoniker - Pointer Moniker Implementation


CreateStreamOnHGlobal
CreateStreamOnHGlobal   QuickInfo

Returns an OLE-provided implementation of the IStream interface with the stream object stored in global memory.

HRESULT CreateStreamOnHGlobal(

HGLOBAL hGlobal,	//Memory handle for the stream object
BOOL fDeleteOnRelease,	//Indicates whether to free memory when the object is released
LPSTREAM * ppstm	//Points to location for pointer to the new stream object
);
Parameters

hGlobal

Contains the memory handle allocated by the GlobalAlloc function. The handle must be allocated as moveable and nondiscardable. If the handle is to be shared between processes, it must also be allocated as shared. New handles should be allocated with a size of zero. If hGlobal is NULL, the CreateStreamOnHGlobal function internally allocates a new shared memory block of size zero.

fDeleteOnRelease

Indicates whether the underlying handle for this stream object should be automatically freed when the stream object is released.

ppstm

Points to the location where this method places a pointer to the new stream object, that is, the new IStream instance. It cannot be NULL.

Return Values

S_OK

Indicates the stream object was created successfully.

E_OUTOFMEMORY

Indicates the stream could not be created due to lack of memory.

E_INVALIDARG

Indicates invalid value for one of the parameters.

Comments

This function creates a stream object in memory using the OLE-provided implementation of the IStream interface. The returned stream object supports both reading and writing, is not transacted, and does not support locking.

The initial contents of the stream are the current contents of the memory block provided in the hGlobal parameter. If the hGlobal paramter is NULL, this function internally allocates memory.

The current contents of the memory block are undisturbed by the creation of the new stream object. Thus, you can use this function to open an existing stream in memory.

The initial size of the stream is the size of the memory handle returned by the Win32 GlobalSize function. Because of rounding, this is not necessarily the same size that was originally allocated for the handle. If the logical size of the stream is important, you should follow the call to this function with a call to the IStream::SetSize method.

See Also

CreateStreamOnHGlobal, IStream::SetSize

GlobalSize in Win32


DllCanUnloadNow

Determines whether the DLL that implements it is in use. It is called by OLE, not by the application. If the DLL is not in use, the calling function can safely unload it from memory.

Note  OLE does not provide this function. DLLs that support the OLE Component Object Model(COM) should implement and export DllCanUnloadNow.

HRESULT DllCanUnloadNow();

Return Values

S_OK

Indicates that the DLL can be unloaded.

S_FALSE

Indicates that the DLL cannot be unloaded now.

Comments

A call to DllCanUnloadNow determines whether the DLL from which it is exported is still in use. A DLL is no longer in use when it is not managing any existing objects (the reference count on all of its objects is 0).

Notes to Callers

You should not have to call DllCanUnloadNow directly. OLE calls it only through a call to the CoFreeUnusedLibraries function. When it returns S_OK, CoFreeUnusedLibraries safely frees the DLL.

Notes to Implementors

You need to implement DllCanUnloadNow in, and export it from, DLLs that are to be dynamically loaded through a call to the CoGetClassObject function. (You also need to implement and export the DllGetClassObject function in the same DLL).

If a DLL loaded by CoGetClassObject fails to export DllCanUnloadNow, the DLL will not be unloaded until the application calls the CoUninitialize function to release the OLE libraries.

If the DLL links to another DLL, returning S_OK from DllCanUnloadNow will also cause the second, dependent DLL to be unloaded. To eliminate the possibility of a crash, the DLL should call the CoLoadLibrary function(path_to_second DLL, TRUE), which forces the COM library to reload the second DLL and set it up for a call to CoFreeUnusedLibraries to free it separately when appropriate.

DllCanUnloadNow should return S_FALSE if there are any existing references to objects that the DLL manages.

See Also

DllGetClassObject


DllGetClassObject
DllGetClassObject   QuickInfo

Retrieves the class object from a DLL object handler or object application. It is called from within the CoGetClassObject function when the class context is a DLL.

Note  OLE does not provide this function. DLLs that support the OLE Component Object Model must implement DllGetClassObject in OLE object handlers or DLL applications.

HRESULT DllGetClassObject(

REFCLSID rclsid,	//CLSID for the class object
REFIID riid,	//Identifier that identifies the interface that communicates with the class object
LPVOID  * ppv	//Points to the pointer of the communicating interface
);
Parameters

rclsid

Specifies the CLSID that will associate the correct data and code.

riid

Specifies the interface that the caller is to use to communicate with the class object. Usually, this is IID_IClassFactory.

ppv

Points either to the pointer of the requested interface or, if an error occurs, to NULL.

Return Values

S_OK

Indicates that the object was retrieved successfully.

CLASS_E_CLASSNOTAVAILABLE

Indicates that the DLL does not support the class (object definition).

E_OUTOFMEMORY

Out of memory.

E_INVALIDARG

Indicates that one or more arguments are invalid.

E_UNEXPECTED

Indicates that an unexpected error occurred.

Comments

If a call to the CoGetClassObject function finds the class object that is to be loaded in a DLL, CoGetClassObject uses the DLL's exported DllGetClassObject function.

Notes to Callers

You should not call DllGetClassObject directly. When an object is defined in a DLL, CoGetClassObject calls the CoLoadLibrary function to load the DLL, which, in turn, calls DllGetClassObject.

Notes to Implementors

You need to implement DllGetClassObject in (and export it from) DLLs that support the OLE Component Object Model.

Example

Following is an example (in C++) of an implementation of DllGetClassObject. In this example, DllGetClassObject creates a class factory object and calls its QueryInterface method to retrieve a pointer to the interface requested in riid. The implementation safely releases the reference it holds to the IClassFactory interface because it returns a reference-counted pointer to IClassFactory to the caller.

HRESULT_export  PASCAL DllGetClassObject

  (REFCLSID rclsid, REFIID riid, LPVOID * ppvObj)

{

HRESULT hres = E_OUTOFMEMORY;

*ppvObj = NULL;

CClassFactory *pClassFactory = new CClassFactory(rclsid);

if (pClassFactory != NULL)   {

  hRes = pClassFactory->QueryInterface(riid, ppvObj);

  pClassFactory->Release();

}

return hRes;

}

See Also

CoGetClassObject, DllCanUnloadNow


DoDragDrop
DoDragDrop   QuickInfo

Carries out an OLE drag and drop operation.

HRESULT DoDragDrop(

IDataObject * pDataObject,	//Data object being dragged
IDropSource * pDropSource,	//Instance of IDropSource for source application
DWORD dwOKEffect,	//Specifies the effects allowed by the source
DWORD * pdwEffect	//Points to effects of the OLE drag and drop on the source
);
Parameters

pDataObject

Points to an instance of the IDataObject interface, which provides the data being dragged.

pDropSource

Points to an instance of the IDropSource interface, which is used to communicate with the source during the drag operation.

dwOKEffect

Specifies the effects the source allows in the OLE drag and drop operation. Most significant is whether it permits a move. The dwOKEffect and pdwEffect parameters obtain values from the DROPEFFECT enumeration. For a list of values, see DROPEFFECT.

pdwEffect

Points to a value that indicates how the OLE drag and drop operation affected the source data. The pdwEffect parameter is set only if the operation is not canceled.

Return Values

DRAGDROP_S_DROP

Indicates the OLE drag and drop operation was successful.

DRAGDROP_S_CANCEL

Indicates the OLE drag and drop operation was canceled.

E_OUTOFMEMORY

Out of memory.

E_UNSPEC

Indicates an unexpected error occurred.

Comments

If you are developing an application that can act as a data source for an OLE drag and drop operation, you must call DoDragDrop when you detect that the user has started an OLE drag and drop operation.

The DoDragDrop function enters a loop in which it calls various methods in the IDropSource and IDropTarget interfaces.

1.	The DoDragDrop function determines the window under the current cursor location. It then checks to see if this window is a valid drop target.

2.	If the window is a valid drop target, DoDragDrop calls IDropTarget::DragEnter. This method returns an effect code indicating what would happen if the drop actually occurred. For a list of valid drop effects, see the DROPEFFECT enumeration.

3.	DoDragDrop calls IDropSource::GiveFeedback with the effect code so that the drop source interface can provide appropriate visual feedback to the user. The pDropSource pointer passed into DoDragDrop specifies the appropriate IDropSource interface.

4.	DoDragDrop tracks mouse cursor movements and changes in the keyboard or mouse button state.

•	If the user moves out of a window, DoDragDrop calls IDropTarget::DragLeave.

•	If the mouse enters another window, DoDragDrop determines if that window is a valid drop target and then calls IDropTarget::DragEnter for that window.

•	If the mouse moves but stays within the same window, DoDragDrop calls IDropTarget::DragOver.

5.	If there is a change in the keyboard or mouse button state, DoDragDrop calls IDropSource::QueryContinueDrag and determines whether to continue the drag, to drop the data, or to cancel the operation based on the return value.

•	If the return value is S_OK, DoDragDrop first calls IDropTarget::DragOver to continue the operation. This method returns a new effect value and DoDragDrop then calls IDropSource::GiveFeedback with the new effect so appropriate visual feedback can be set. For a list of valid drop effects, see the DROPEFFECT enumeration. IDropTarget::DragOver and IDropSource::GiveFeedback are paired so that as the mouse moves across the drop target, the user is given the most up-to-date feedback on the mouse's position.

•	If the return value is DRAGDROP_S_DROP, DoDragDrop calls IDropTarget::Drop. The DoDragDrop function returns the last effect code to the source, so the source application can perform the appropriate operation on the source data, for example, cut the data if the operation was a move.

•	If the return value is DRAGDROP_S_CANCEL, the DoDragDrop function calls IDropTarget::DragLeave.

See Also

IDropSource::GiveFeedback


FACILITY_NT_BIT

#define FACILITY_NT_BIT 0x10000000

Defines bits so macros are guaranteed to work.


FAILED

#define FAILED(Status) ((HRESULT)(Status)<0)

Provides a generic test for failure on any status value. Negative numbers indicate failure.


GetClassFile
GetClassFile   QuickInfo

Returns the CLSID associated with the given filename.

HRESULT GetClassFile(

LPCWSTR szFileName,	//Pointer to filename for which you are requesting a CLSID
CLSID * pclsid	//Pointer to location for returning the CLSID
);
Parameters

szFileName

Points to the filename for which you are requesting the associated CLSID.

pclsid

Points to the location where the the associated CLSID is returned.

Return Values

S_OK

Indicates the CLSID was successfully returned.

MK_E_CANTOPENFILE

Indicates unable to open the specified filename.

MK_E_INVALIDEXTENSION

Indicates the specified extension in the registry is invalid.

Note  This function can also return any file system errors.

Comments

The CLSID returned by this function is used, for example, by File Monikers to locate the object application that can open the file. For example, when a link to a file-based document is activated, the file moniker uses the returned CLSID to locate the application for the link source.

The following strategies are used to determine an appropriate CLSID:

1.	If the file contains a storage object, as determined by a call to the StgIsStorageFile function, the GetClassFile function returns the CLSID that was written with the IStorage::SetClass method.

2.	If the file is not a storage object, the GetClassFile function attempts to match various bits in the file against a pattern in the registry. A pattern in the registry can contain a series of entries of the form:

regdb key = offset, cb, mask, value

The value of the offset item is an offset from the beginning or end of the file and the cb item is a length in bytes. These two values represent a particular byte range in the file. (A negative value for the offset item is interpreted from the end of the file). The mask value is a bit mask that is used to perform a logical AND operation with the byte range specifed by offset and cb. The result of the logical AND operation is compared with the value item. If the mask is omitted, it is assumed to be all ones.

Each pattern in the registry is compared to the file in the order of the patterns in the database. The first pattern where each of the value items matches the result of the AND operation determines the CLSID of the file. For example, the pattern contained in the following entries of the registry requires that the first four bytes be AB CD 12 34 and that the last four bytes be FE FE FE FE:

HKEY_CLASSES_ROOT

FileType

  {12345678-0000-0001-C000-000000000095}

    0 = 0, 4, FFFFFFFF, ABCD1234

    1 = -4, 4, , FEFEFEFE

If a file contains such a pattern, the CLSID {12345678-0000-0001-C000-000000000095} will be associated with this file.

3.	If the above strategies fail, the GetClassFile function searches for the File Extension key in the registry that corresponds to the .ext portion of the filename. If the database entry contains a valid CLSID, this function returns that CLSID.

4.	Otherwise, MK_E_INVALIDEXTENSION is returned.

See Also

WriteClassStg


GetConvertStg
GetConvertStg   QuickInfo

Returns the current value of the convert bit for the specifed storage object.

HRESULT GetConvertStg(

IStorage * pStg	//Points to the storage object
);
Parameter

pStg

Points to the storage object from which to retrieve the convert bit.

Return Values

S_OK

Indicates the convert bit is set to TRUE.

S_FALSE

Indicates the convert bit is cleared (FALSE).

STG_E_ACCESSDENIED

Indicates cannot access the storage object.

IStorage::OpenStream, IStorage::OpenStorage, and IStream::Read storage and stream access errors.

Comments

This function is used by object applications that support converting the object from one format to another. The object application must be able to read the storage object using the format of its previous CLSID and write the object using the format of its new CLSID to support converting the object. For example, a spreadsheet created by one application can be converted to the format used by a different application.

The convert bit is set by a call to the SetConvertStg function. A container application can call this function on the request of an end user, or a setup program can call it when installing a new version of an application. An end user requests converting an object through the Convert To dialog box. When an object is converted, the new CLSID is permanently assigned to the object, so the object is subsequently associated with the new CLSID.

Then, when the object is activated, the object application calls the GetConvertStg function to retrieve the value of the convert bit from the storage object. If the bit is set, the object's CLSID has been changed, and the object application must read the old format and write the new format for the storage object.

After retrieving the bit value, the object application should clear the convert bit by calling the SetConvertStg function with its fConvert parameter set to FALSE.

See Also

SetConvertStg


GetHGlobalFromILockBytes
GetHGlobalFromILockBytes   QuickInfo

Returns a global memory handle to a byte array object created using the CreateILockBytesOnHGlobal function.

HRESULT GetHGlobalFromILockBytes(

ILockBytes * pLkbyt,	//Points to the byte array object
HGLOBAL * phglobal	//Points to the current memory handle for the specified byte array
);
Parameters

pLkbyt

Points to the byte array object previously created by a call to the CreateILockBytesOnHGlobal function.

phglobal

Points to the current memory handle used by the specified byte array object.

Return Values

S_OK

Indicates the handle was returned successfully.

E_INVALIDARG

Indicates invalid value specified for the pLkbyt parameter. It can also indicate that the byte array object passed in is not one created by the CreateILockBytesOnHGlobal function.

Comments

The handle this function returns might be different from the original handle due to intervening calls to the GlobalRealloc function.

The contents of the returned memory handle can be written to a clean disk file, and then opened as a storage object using the StgOpenStorage function.

This function only works within the same process from which the byte array was created.

See Also

StgOpenStorage


GetHGlobalFromStream
GetHGlobalFromStream   QuickInfo

Returns the global memory handle to a stream that was created using the CreateStreamOnHGlobal function.

HRESULT GetHGlobalFromStream(

IStream * pstm,	//Points to the stream object
HGLOBAL * phglobal	//Points to the current memory handle for the specified stream
);
Parameters

pstm

Points to the stream object previously created by a call to the CreateStreamOnHGlobal function.

phglobal

Points to the current memory handle used by the specified stream object.

Return Values

S_OK

Indicates the handle was successfully returned.

E_INVALIDARG

Indicates invalid value specified for the pstm parameter. It can also indicate that the stream object passed in is not one created by a call to the CreateStreamOnHGlobal function.

Comments

The handle this function returns may be different from the original handle due to intervening GlobalRealloc calls.

This function only works within the same process from which the byte array was created.

See Also

CreateStreamOnHGlobal

GlobalRealloc in Win32


GetRunningObjectTable
GetRunningObjectTable   QuickInfo

Returns an IRunningObjectTable pointer to the local Running Object Table (ROT).

HRESULT GetRunningObjectTable(

DWORD reserved,	//Reserved
LPRUNNINGOBJECTTABLE *pprot	//Receives an IRunningObjectTable pointer
);
Parameters

reserved

Indicates reserved for future use.

pprot

Receives an IRunningObjectTable interface pointer to the local ROT. If an error occurs, *pprot is undefined; otherwise, the caller is responsible for calling IUnknown::Release on the parameter.

Return Values

S_OK

Indicates that an IRunningObjectTable pointer was successfully returned.

E_UNEXPECTED

Indicates an unexpected error.

Comments

Each workstation has a local ROT that maintains a table of the objects that have been registered as running on that machine. This function returns an IRunningObjectTable interface pointer, which provides access to that table.

Moniker providers, which hand out monikers identifying objects to make them accessible to others, should call GetRunningObjectTable. Use the interface pointer returned by this function to register your objects when they begin running, to record the times that those objects are modified, and to revoke their registrations when they stop running. See the IRunningObjectTable interface for more information.

The most common types of moniker provider are compound-document link sources. This includes server applications that support linking to their documents (or portions of a document) and container applications that support linking to embeddings within their documents. Server applications that do not support linking can also use the ROT to cooperate with container applications that support linking to embeddings.

If you're writing your own moniker class (implementing the IMoniker interface) and you need an interface pointer to the ROT, use the IBindCtx::GetRunningObjectTable method rather than the GetRunningObjectTable function. This allows future implementations of the IBindCtx interface to modify binding behavior.

See Also

IBindCtx::GetRunningObjectTable, IMoniker, IRunningObjectTable


GetScode

#define GetScode(hr) ((SCODE) (hr))

Extracts the SCODE from an HRESULT

This macro is obsolete and should not be used.


HRESULT_CODE

#define HRESULT_CODE(hr) ((hr) & 0xFFFF)

Returns the error code part of the HRESULT.


HRESULT_FACILITY

#define HRESULT_FACILITY(hr) (((hr) >> 16) & 0x1fff)

Returns the facility from the HRESULT.


HRESULT_FROM_NT

#define HRESULT_FROM_NT(x) ((HRESULT) ((x) | FACILITY_NT_BIT))

Maps an NT status value into an HRESULT.


HRESULT_FROM_WIN32

#define HRESULT_FROM_WIN32(x) (x ? ((HRESULT) (((x) & 0x0000FFFF) | (FACILITY_WIN32 << 16) | 0x80000000)) : 0 )

Maps a WIN32 error value into an HRESULT. Note that this assumes WIN32 errors fall in the range of -32k to 32k.


HRESULT_SEVERITY

#define HRESULT_SEVERITY(hr) (((hr) >> 31) & 0x1)

Returns the severity bit from the HRESULT.


IIDFromString
IIDFromString   QuickInfo

Converts a string generated by the StringFromIID function back into the original interface identifier.

HRESULT IIDFromString(

LPOLESTR lpsz,	//Points to the string representation of the IID
LPIID lpiid	//Receives a pointer to the requested IID on return
);
Parameters

lpsz

Points to the string representation of the IID.

lpiid

Receives a pointer to the requested IID on return.

Return Values

S_OK

Indicates that the string was successfully converted.

E_OUTOFMEMORY

Out of memory.

E_INVALIDARG

Indicates that one or more arguments are invalid.

Comments

The function converts the interface ID in a way that guarantees different interface IDs will always be converted to different strings.

See Also

StringFromIID


IsAccelerator
IsAccelerator   QuickInfo

Determines whether the keystroke maps to an accelerator in the given accelerator table.

BOOL IsAccelerator(

HACCEL hAccel,	//Handle to accelerator table
INT cAccelEntries,	//Number of entries in the accelerator table
LPMSG lpMsg,	//Points to the keystroke message to be translated
WORD * lpwCmd	//Where to return the corresponding command ID
);
Parameters

hAccel

Specifies the handle to the accelerator table.

cAccelEntries

Specifies the number of entries in the accelerator table.

lpMsg

Points to the keystroke message to be translated.

lpwCmd

Points to where to return the corresponding command ID if there is an accelerator for the keystroke. It may be NULL.

Return Values

TRUE

Indicates the message is for the object application.

FALSE

Indicates the message is not for the object and should be forwarded to the container.

Comments

While active in-place, the object always has first chance to translate the keystrokes into accelerators. If the keystroke corresponds to one of its accelerators, the object must not call the OleTranslateAccelerator  function— even if its call to the Windows TranslateAccelerator function fails. Failure to process keystrokes in this manner can lead to inconsistent behavior.

If the keystroke is not one of the object's accelerators, then the object must call OleTranslateAccelerator to let the container try its accelerator translation.

The object application can call IsAccelerator to determine if the accelerator message belongs to it. Some object applications do accelerator translation on their own and do not call TranslateAccelerator. Those applications will not call IsAccelerator, because they already have the information.

See Also

OleTranslateAccelerator

TranslateAccelerator in Win32


IS_ERROR

#define IS_ERROR(Status) ((unsigned long)(Status) >> 31 == SEVERITY_ERROR)

Provides a generic test for errors on any status value.


IsEqualGUID
IsEqualGUID   QuickInfo

Determines whether two GUIDs are equal.

BOOL IsEqualGUID(

REFGUID rguid1,	//The GUID to compare to rguid2
REFGUID rguid2	//The GUID to compare to rguid1
);
Parameters

rguid1

Specifies the GUID to compare to rguid2.

rguid2

Specifies the GUID to compare to rguid1.

Return Values

TRUE

Indicates the GUIDs are equal.

FALSE

Indicates the GUIDs are not equal.

Comments

IsEqualGUID is used by the IsEqualCLSID and IsEqualIID functions.

See Also

IsEqualCLSID, IsEqualIID


IsEqualCLSID

Determines whether two CLSIDs are equal.

BOOL IsEqualCLSID(

REFCLSID rclsid1,	//The CLSID to compare to rclsid2
REFCLSID rclsid2	//The CLSID to compare to rclsid1
);
Parameters

rclsid1

Specifies the CLSID to compare to rclsid2.

rclsid2

Specifies the CLSID to compare to rclsid1.

Return Values

TRUE

Indicates that the CLSIDs are equal.

FALSE

Indicates that the CLSIDs are not equal.

See Also

IsEqualGUID, IsEqualIID


IsEqualIID

Determines whether two interface IDs are equal.

BOOL IsEqualIID(

REFGUID riid1,	//The interface ID to compare to riid2
REFGUID riid2	//The interface ID to compare to riid1
);
Parameters

riid1

Specifies the interface ID to compare with riid2.

riid2

Specifies the interface IID to compare with riid1.

Return Values

TRUE

Indicates that the interface IDs are equal.

FALSE

Indicates that the interface IDs are not equal.

See Also

IsEqualGUID, IsEqualCLSID


IsValidIid

This function is obsolete.


IsValidInterface

This function is obsolete.


IsValidPtrIn

This function is obsolete.


IsValidPtrOut

This function is obsolete.


MAKE_HRESULT

#define MAKE_HRESULT(sev,fac,code) \HRESULT) (((unsigned long)(sev)<<31) | ((unsigned long)(fac)<<16) | ((unsigned long)(code))) )

Creates an HRESULT value from component pieces of the 32-bit value.


MAKE_SCODE

#define MAKE_SCODE(sev,fac,code) \((SCODE) (((unsigned long)(sev)<<31) | ((unsigned long)(fac)<<16) | ((unsigned long)(code))) )

Returns an SCODE given an HRESULT.


MkParseDisplayName
MkParseDisplayName   QuickInfo

Converts a string into a moniker that identifies the object named by the string. This is the inverse of the IMoniker::GetDisplayName operation, which retrieves the display name associated with a moniker.

WINOLEAPI MkParseDisplayName(

LPBC pbc,	//Bind context to be used
LPCOLESTR szUserName,	//Display name
ULONG FAR *pchEaten,	//Receives number of characters consumed
LPMONIKER FAR *ppmk	//Receives moniker built from display name
);
Parameters

pbc

Points to the binding context to be used in this binding operation.

szUserName

Points to a zero-terminated string containing the display name to be parsed. For Win32 applications, the LPOLESTR type indicates a wide character string (two bytes per character); otherwise, the string has one byte per character.

pchEaten

Receives the number of characters of szUserName that were consumed. If the function is successful, *pchEaten is the length of szUserName; otherwise, it is the number of characters successfully parsed.

ppmk

Receives a pointer to the moniker that was built from szUserName. The returned pointer is NULL if an error occurs; if non-NULL, the function has called IUnknown::AddRef on the parameter and the caller is responsible for calling IUnknown::Release.

Return Values

S_OK

Indicates the parse operation was successful and the moniker was created.

MK_E_SYNTAX

Indicates an error in the syntax of a filename or an error in the syntax of the resulting composite moniker.

E_OUTOFMEMORY

Indicates insufficient memory.

In addition, the return value can be any of the error return values from IMoniker::BindToObject, IOleItemContainer::GetObject, or IParseDisplayName::ParseDisplayName.

Comments

The MkParseDisplayName function parses a human-readable name into a moniker that can be used to identify a link source. The resulting moniker can be a simple moniker (such as a file moniker), or it can be a generic composite made up of the component moniker pieces. For example, the following display name:

"c:\mydir\somefile!item 1"

could be parsed into the following generic composite moniker:

(FileMoniker based on "c:\mydir\somefile")  (°)  (ItemMoniker based on "item 1")

The most common situation in which you need to call MkParseDisplayName is in the implementation of the standard Links dialog, which allows an end-user to specify the source of a linked object by typing in a string. You may also need to call MkParseDisplayName if your application supports a macro language that permits remote references (reference to elements outside of the document).

Note that parsing a display name often requires activating the same objects that would be activated during a binding operation. Therefore, parsing a display name can be as expensive as binding to the object that it refers. Objects that are bound during the parsing operation are cached in the passed-in bind context. If you plan to bind the moniker returned by MkParseDisplayName, the best time to do so is immediately after the function returns, using the same bind context; this removes the need to activate objects a second time.

The MkParseDisplayName function parses as much of the display name as it understands into a moniker. The function then calls IMoniker::ParseDisplayName on the newly created moniker, passing the remainder of the display name. The moniker returned by IMoniker::ParseDisplayName is composed onto the end of the existing moniker and, if any of the display name remains unparsed, IMoniker::ParseDisplayName is called on the result of the composition. This process is repeated until the entire display name has been parsed.

The MkParseDisplayName function attempts the following strategies to parse the beginning of the display name, using the first one that succeeds:

1.	The function looks in the Running Object Table for file monikers corresponding to all prefixes of szDisplayName that consist solely of valid filename characters. This strategy can identify documents that are as yet unsaved.

2.	The function checks the maximal prefix of szDisplayName, which consists solely of valid filename characters, to see if an OLE 1 document is registered by that name (this may require some DDE broadcasts). In this case, the returned moniker is an internal moniker provided by the OLE 1 compatibility layer of OLE 2.

3.	The function consults the file system to check whether a prefix of szDisplayName matches an existing file. The filename can be drive absolute, drive relative, working-directory relative, or begin with an explicit network share name. This is the common case.

4.	If the initial character of szDisplayName is an '@', the function finds the longest string immediately following it that conforms to the legal ProgID syntax. The function converts this string to a CLSID using the CLSIDFromProgID function. If the CLSID represents an OLE 2 class, the function loads the corresponding class object and asks for an IParseDisplayName interface pointer. The resulting IParseDisplayName interface is then given the whole string to parse, starting with the '@'. If the CLSID represents an OLE 1 class, then the function treats the string following the ProgID as an OLE1/DDE link designator having <filename>!<item> syntax.

See Also

IMoniker::ParseDisplayName, IMoniker::GetDisplayName, IParseDisplayName


MonikerCommonPrefixWith
MonikerCommonPrefixWith   QuickInfo

Returns a moniker based on the common prefix that the two monikers share. This function is intended for use only in IMoniker::CommonPrefixWith implementations.

WINOLEAPI MonikerCommonPrefixWith(

LPMONIKER pmkThis,	//First moniker being compared
LPMONIKER pmkOther,	//Second moniker being compared
LPMONIKER FAR *ppmkCommon	//Receives common prefix
);
Parameters

pmkThis

Points to one of the monikers to compare.

pmkOther

Points to the other moniker to compare.

ppmkCommon

Receives a pointer to a moniker based on the common prefix of pmkThis and pmkOther. The returned pointer is NULL if an error occurs; if non-NULL, the function has called IUnknown::AddRef on the parameter and the caller is responsible for calling IUnknown::Release.

Return Values

S_OK

Indicates a common prefix exists that is neither pmkThis nor pmkOther.

MK_S_HIM

Indicates the entire pmkOther moniker is a prefix of the pmkThis moniker.

MK_S_ME

Indicates the entire pmkThis moniker is a prefix of the pmkOther moniker.

MK_S_US

Indicates the pmkThis and pmkOther monikers are equal.

MK_E_NOPREFIX

Indicates the monikers have no common prefix.

MK_E_NOTBINDABLE

Indicates this function was called on a relative moniker. It is not meaningful to take the common prefix of relative monikers.

E_UNEXPECTED

Indicates an unexpected error occurred.

E_OUTOFMEMORY

Indicates insufficient memory.

Comments

Call MonikerCommonPrefixWith only if you are writing your own moniker class (implementing the IMoniker interface). Call this function from your implementation of the IMoniker::CommonPrefixWith method.

Your implementation of IMoniker::CommonPrefixWith should first check whether the other moniker is of a type you recognize and handle in a special way. If not, you should call MonikerCommonPrefixWith, passing itself as pmkThis and the other moniker as pmkOther. MonikerCommonPrefixWith correctly handles the cases where either moniker is a generic composite.

You should call this function only if pmkSrc and pmkDest are both absolute monikers (where an absolute moniker is either a file moniker or a generic composite whose left-most component is a file moniker, and where the file moniker represents an absolute path). Do not call this function on relative monikers.

See Also

IMoniker::CommonPrefixWith


MonikerRelativePathTo
MonikerRelativePathTo   QuickInfo

Returns a moniker that, when composed onto the end of the first specified moniker (or one with a similar structure), yields the second specified moniker. This function is intended for use only by IMoniker::RelativePathTo implementations.

WINOLEAPI MonikerRelativePathTo(

LPMONIKER pmkSrc,	//Moniker identifying source
LPMONIKER pmkDest,	//Moniker identifying destination
LPMONIKER FAR * ppmkRelPath,	//Receives relative moniker
BOOL dwReserved	//Reserved; must be non-zero
);
Parameters

pmkSrc

Points to the moniker that, when composed with the relative moniker to be created, produces pmkDest. This moniker identifies the "source" of the relative moniker to be created.

pmkDest

Points to the moniker to be expressed relative to pmkSrc. This moniker identifies the "destination" of the relative moniker to be created.

ppmkRelPath

Receives a pointer to the relative moniker. The returned pointer is NULL if an error occurs; if non-NULL, the function has called IUnknown::AddRef on the parameter and the caller is responsible for calling IUnknown::Release.

dwReserved

Reserved; must be non-zero.

Return Values

S_OK

Indicates a meaningful relative path has been returned.

MK_S_HIM

Indicates the only form of the relative path is the other moniker.

MK_E_NOTBINDABLE

Indicates that pmkSrc is a relative moniker, such as an item moniker. pmkSrc must be composed with the moniker of its container before a relative path can be determined.

E_INVALIDARG

Specifies the parameter dwReserved was set to zero.

E_UNEXPECTED

Indicates an unexpected error occurred.

E_OUTOFMEMORY

Indicates insufficient memory.

Comments

Call MonikerRelativePathTo only if you are writing your own moniker class (implementing the IMoniker interface). Call this function from your implementation of the IMoniker::RelativePathTo method.

Your implementation of IMoniker::RelativePathTo should first check whether the other moniker is of a type you recognize and handle in a special way. If not, you should call MonikerRelativePathTo, passing itself as pmkThis and the other moniker as pmkOther. MonikerRelativePathTo correctly handles the cases where either moniker is a generic composite.

You should call this function only if pmkSrc and pmkDest are both absolute monikers, where an absolute moniker is either a file moniker or a generic composite whose left-most component is a file moniker, and where the file moniker represents an absolute path. Do not call this function on relative monikers.

See Also

IMoniker::RelativePathTo


OleBuildVersion
OleBuildVersion   QuickInfo

This function is obsolete.


OleConvertIStorageToOLESTREAM
OleConvertIStorageToOLESTREAM   QuickInfo

Converts the specified storage object from OLE 2 structured storage to the OLE 1 storage model but does not include the presentation data. This is one of several compatibility functions. You can use these functions to determine if an object class is from OLE 1 and to convert objects between OLE 1 and OLE 2 storage formats.

HRESULT OleConvertIStorageToOLESTREAM(

IStorage * pStg,	//Points to the OLE 2 storage object to be converted
LPOLESTREAM lpolestm	//Points to the stream where the OLE1 storage is written
);
Parameters

pStg

Points to the storage object to be converted to an OLE 1 storage.

lpolestm

Points to a stream where the persistent representation of the object is saved using the OLE 1 storage model.

Return Values

S_OK

Indicates the storage object was successfully converted and the OLESTREAM structure contains the persistent representation of an OLE 1 object.

CONVERT10_E_STG_NO_STD_STREAM

Indicates object cannot be converted because its storage is missing a stream.

CONVERT10_S_NO_PRESENTATION

Indicates the specified storage object contains a Paintbrush object in DIB format and there is no presentation data in the OLESTREAM.

E_INVALIDARG

Indicates invalid value for the pstg or lpolestm parameters.

Comments

This function converts an OLE 2 storage object to OLE 1 format. The OLESTREAM code implemented for OLE 1 must be available.

On entry, the stream pointed to by lpolestm should be created and positioned just as it would be for an OleSaveToStream call. On exit, the stream contains the persistent representation of the object using OLE 1 storage.

Note  Paintbrush objects are dealt with differently from other objects because their native data is in DIB format. When Paintbrush objects are converted using OleConvertIStorageToOLESTREAM, no presentation data is added to the OLESTREAM. To include presentation data, use the OleConvertIStorageToOLESTREAMEx function instead.

See Also

CoIsOle1Class, OleConvertIStorageToOLESTREAMEx, OleConvertOLESTREAMToIStorage, OleConvertOLESTREAMToIStorageEx


OleConvertIStorageToOLESTREAMEx
OleConvertIStorageToOLESTREAMEx   QuickInfo

Converts the specified storage object from OLE 2 structured storage to the OLE 1 storage model, including the presentation data. This is one of several compatibility functions. You can use these functions to determine if an object class is from OLE 1 and to convert objects between OLE 1 and OLE 2 storage formats.

HRESULT OleConvertIStorageToOLESTREAMEx(

IStorage  * pStg,	//Points to the OLE 2 storage object to be converted
CLIPFORMAT  cfFormat,	//Presentation data format
LONG  lWidth,	//Width in HIMETRIC
LONG  lHeight,	//Height in HIMETRIC
DWORD  dwSize,	//Size of data in bytes
STGMEDIUM  pmedium,	//Points to STGMEDIUM of data
LPOLESTREAM  lpolestm	//Points to the stream where the OLE1 storage is written
);
Parameters

pStg

Points to the storage object to be converted to an OLE 1 storage.

cfFormat

Specifies the format of the presentation data. May be NULL, in which case the lWidth, lHeight, dwSize, and pmedium parameters are ignored. lWidth

Specifies the width of the object presentation data in HIMETRIC units.

lHeight

Specifies the height of the object presentation data in HIMETRIC units.

dwSize

Specifies the size of the data to be converted, in bytes.

pmedium

Points to the STGMEDIUM structure for the serialized data to be converted. See STGMEDIUM for more information.

lpolestm

Points to a stream where the persistent representation of the object is saved using the OLE 1 storage model.

Return Values

S_OK

Indicates the conversion was completed successfully.

DV_E_STGMEDIUM

Specifies the hGlobal member of STGMEDIUM is NULL.

E_INVALIDARG

Specifies the dwSize parameter is NULL; or the pstg parameter is invalid; or the lpolestm parameter is invalid.

DV_E_TYMED

Specifies the tymed member of the STGMEDIUM structure is not TYMED_HGOLBAL or TYMED_ISTREAM.

Comments

This function converts an OLE 2 storage object to OLE 1 format. It differs from the OleConvertIStorageToOLESTREAM function in that the presentation data to be written to the OLE 1 storage is passed in.

Because OleConvertIStorageToOLESTREAMEx can specify which presentation data to convert, it can be used by applications that do not use OLE default caching resources but do use OLE's conversion resources.

The value of the tymed member of STGMEDIUM must be either TYMED_HGLOBAL or TYMED_ISTREAM. The medium is not released by OleConvertIStorageToOLESTREAMEx.

See Also

CoIsOle1Class, OleConvertIStorageToOLESTREAM, OleConvertOLESTREAMToIStorage, OleConvertOLESTREAMToIStorageEx


OleConvertOLESTREAMToIStorage
OleConvertOLESTREAMToIStorage   QuickInfo

Converts the specified object from the OLE 1 storage model to an OLE 2 structured storage object without specifying presentation data. This is one of several compatibility functions. You can use these functions to determine if an object class is from OLE 1 and to convert objects between OLE 1 and OLE 2 storage formats.

HRESULT OleConvertOLESTREAMToIStorage(

LPOLESTREAM lpolestm,	//Points to the stream where the OLE 1 storage is written
IStorage * pstg,	//Points to OLE 2 storage object
const DVTARGETDEVICE * ptd	//Points to target device
);
Parameters

lpolestm

Points to a stream that contains the persistent representation of the object in the OLE 1 storage format.

pstg

Points to the OLE 2 structured storage object.

ptd

Points to the target device for which the OLE 1 object is rendered.

Return Values

S_OK

Indicates the object was successfully converted.

CONVERT10_S_NO_PRESENTATION

Indicates object either has no presentation data or uses native data for its presentation.

DV_E_DVTARGETDEVICE or DV_E_DVTARGETDEVICE_SIZE

Indicates invalid value for ptd.

E_INVALIDARG

Indicates invalid value for lpolestm.

Comments

This function converts an OLE 1 object to an OLE 2 structured storage object. You can use this function to update OLE 1 objects to OLE 2 objects when a new version of the object application supports OLE 2.

On entry, the lpolestm parameter should be created and positioned just as it would be for an OleLoadFromStream function call. On exit, the lpolestm parameter is positioned just as it would be on exit from an OleLoadFromStream function, and the pstg parameter contains the uncommitted persistent representation of the OLE 2 storage object.

For OLE 1 objects that use native data for their presentation, the OleConvertOLESTREAMToIStorage function returns CONVERT10_S_NO_PRESENTATION. On receiving this return value, callers should call IOleObject::Update to get the presentation data so that it can be written to storage.

The following steps describe the conversion process:

1.	Create a root IStorage object by calling the StgCreateDocfile function(..., &pstg).

2.	Open the OLE 1 file (using OpenFile or another OLE 1 technique).

3.	Using the OLE 1 procedure for reading files, read from the file until an OLE object is encountered.

4.	Allocate an IStorage object from the root IStorage created in step 1:

pstg->lpVtbl->CreateStorage(...&pStgChild);

hRes = OleConvertIStorageToOLESTREAM(polestm, pStgChild);

hRes = OleLoad(pStgChild, &IID_IOleObject, pClientSite, ppvObj);

5.	Repeat step 3 until the file is completely read.

See Also

CoIsOle1Class, OleConvertIStorageToOLESTREAM, OleConvertIStorageToOLESTREAMEx, OleConvertOLESTREAMToIStorageEx


OleConvertOLESTREAMToIStorageEx
OleConvertOLESTREAMToIStorageEx   QuickInfo

Converts the specified object from the OLE 1 storage model to an OLE 2 structured storage object including presentation data. This is one of several compatibility functions. You can use these functions to determine if an object class is from OLE 1 and to convert objects between OLE 1 and OLE 2 storage formats.

HRESULT OleConvertOLESTREAMToIStorageEx(

LPOLESTREAM lpolestm,	//Points to the a stream where the OLE1 storage is written
IStorage * pstg,	//Points to OLE 2 storage object
CLIPFORMAT * pcfFormat,	//Points to location where presentation data is returned
LONG * plWidth,	//Points to location where width value is returned
LONG * plHeight,	//Points to location where height value is returned
DWORD * pdwSize,	//Points to location where size is returned
STGMEDIUM pmedium	//Points to location where the STGMEDIUM structure is returned
);
Parameters

lpolestm

Points to a stream that contains the persistent representation of the object in the OLE 1 storage format.

pstg

Points to the OLE 2 structured storage object.

pcfFormat

Points to the location where the format of the presentation data is returned. May be NULL, indicating the absence of presentation data.

plWidth

Points to the location where the width value (in HIMETRIC) of the presentation data is returned.

plHeight

Points to the location where the height value (in HIMETRIC) of the presentation data is returned.

pdwSize

Points to the location where the size in bytes of the converted data is returned.

pmedium

Points to the location where the STGMEDIUM structure for the converted serialized data is returned.

Return Values

S_OK

Indicates the conversion was completed successfully.

DV_E_TYMED|

Specifies the value of the tymed member of STGMEDIUM is not TYMED_ISTREAM or TYMED_NULL.

Comments

This function converts an OLE 1 object to an OLE 2 structured storage object. You can use this function to update OLE 1 objects to OLE 2 objects when a new version of the object application supports OLE 2.

This function differs from the OleConvertOLESTREAMToIStorage function in that the presentation data read from the OLESTREAM structure is passed out and the newly created OLE 2 storage object does not contain a presentation stream.

Since this function can specify which presentation data to convert, it can be used by applications that do not use OLE's default caching resources but do use the conversion resources.

The tymed member of STGMEDIUM can only be TYMED_NULL or TYMED_ISTREAM. If TYMED_NULL, then the data will be returned in a global handle through the hGlobal member of STGMEDIUM, otherwise data will be written into the pstm member of this structure.

See Also

CoIsOle1Class, OleConvertIStorageToOLESTREAM, OleConvertIStorageToOLESTREAMEx, OleConvertOLESTREAMToIStorage


OleCreate
OleCreate   QuickInfo

Creates an embedded object identified by a CLSID. You use it typically to implement the menu item that allows the end user to insert a new object.

STDAPI OleCreate(

REFCLSID rclsid,	//CLSID of embedded object to be created
REFIID riid,	//Interface used to communicate with new object
DWORD renderopt,	//RENDEROPT value indicating cached capabilities
FORMATETC * pFormatEtc,	//FORMATETC value, depending upon RENDEROPT value
IOleClientSite * pClientSite,	//Client site pointer to request services from the container
IStorage * pStg,	//IStorage instance to be used as storage for the object
void ** ppvObject	//On return, pointer to new object
);
Parameters

rclsid

Specifies the CLSID of the embedded object that is to be created.

riid

Identifies the interface, usually IID_IOleObject, through which the caller will communicate with the new object.

renderopt

A value from the enumeration OLERENDER, indicating the locally cached drawing capabilities the newly created object is to have. The OLERENDER value chosen affects the possible values for the pFormatEtc parameter.

pFormatEtc

Depending on which of the OLERENDER flags is used as the value of renderopt, may be one of the FORMATETC enumeration values. Refer to the OLERENDER enumeration for restrictions. This parameter, along with the renderopt parameter, specifies what the new object can cache initially.

pClientSite

Points to an instance of IOleClientSite, the primary interface through which the object will request services from its container. Value may be NULL.

pStg

Points to an instance of the IStorage interface to be used as the storage for the object. This parameter may not be NULL.

ppvObject

Upon successful return, receives a pointer to the interface requested in riid on the newly created object.

Return Values

S_OK

Indicates embedded object created successfully.

E_OUTOFMEMORY

Indicates embedded object cannot be created due to lack of memory.

Comments

The OleCreate function creates a new embedded object, and is typically called to implement the menu item Insert New Object. When OleCreate returns, the object it has created is blank (contains no data), unless renderopt is OLERENDER_DRAW or OLERENDER_FORMAT, and is loaded. Containers typically then call the OleRun function or IOleObject::DoVerb to show the object for initial editing.

The rclsid parameter specifies the CLSID of the requested object. CLSIDs of registered objects are stored in the registry. When an application user selects Insert Object, a selection box allows the user to select the type of object desired from those in the system registry. When OleCreate is used to implement the Insert Object menu item, the CLSID associated with the selected item is assigned to the rclsid parameter of OleCreate.

The riid parameter specifies the interface the client will use to communicate with the new object. Upon successful return, the ppvObject parameter holds a pointer to the requested interface.

The created object's cache contains information that allows a presentation of a contained object when the container is opened. Information about what should be cached is passed in the renderopt and pFormatetc values. When OleCreate returns, the created object's cache is not necessarily filled. Instead, the cache is filled the first time the object enters the running state. The caller can add additional cache control with a call to IOleCache::Cache after the return of OleCreate and before the object is run. If renderopt is OLERENDER_DRAW or OLERENDER_FORMAT, OleCreate requires that the object support the IOleCache interface. There is no such requirement for any other value of renderopt.

If pClientSite is non-NULL, OleCreate calls IOleObject::SetClientSite with the pClientSite parameter. IOleClientSite is the primary interface by which an object requests services from its container.

If pClientSite is NULL, you must make a specific call to IOleObject::SetClientSite before attempting any operations.

See Also

OLERENDER, FORMATETC, IOleClientSite, IOleObject


OleCreateDefaultHandler
OleCreateDefaultHandler   QuickInfo

Creates a new instance of the default embedding handler. This instance is initialized so it creates a local server when the embedded object enters the running state.

HRESULT OleCreateDefaultHandler(

REFCLSID clsid,	//Identifies OLE server to be loaded
LPUNKNOWN pUnkOuter,	//Controlling unknown if aggregated; else NULL
REFIID riid,	//Interface for communicating with handler
LPVOID FAR *lplpvObj	//Receives pointer to interface on handler
);
Parameters

clsid

Specifies CLSID identifying the OLE server to be loaded when the embedded object enters the running state.

pUnkOuter

Points to the controlling IUnknown interface if the handler is to be aggregated; NULL if it is not to be aggregated.

riid

Specifies the interface, usually IID_IOleObject, through which the caller will communicate with the handler.

lplpObj

On return, receives a pointer to the interface requested in riid on the newly created handler.

Return Values

E_OUTOFMEMORY

Indicates a handler cannot be created because the system is out of memory

NOERROR

Indicates the creation operation was successful.

Comments

OleCreateDefaultHandler creates a new instance of the default embedding handler, initialized so it creates a local server identified by the clsid parameter when the embedded object enters the running state.

If the given object definition does not have a special handler, a call to OleCreateDefaultHandler produces the same results as a call to the CoCreateInstance function with the class context parameter assigned the value CLSCTX_INPROC_HANDLER.

When to Use

If you are writing a handler and want to use the services of the default handler, call OleCreateDefaultHandler. OLE also calls it internally when the CLSID specified in an object creation call is not registered.

See Also

CoCreateInstance, CLSCTX


OleCreateEmbeddingHelper
OleCreateEmbeddingHelper   QuickInfo

Creates an OLE embedding helper object using application-supplied code aggregated with pieces of the OLE default object handler. This helper object can be created and used in a specific context and role, as determined by the caller.

HRESULT OleCreateEmbeddingHelper(

REFCLSID clsid,	//The ID of the class to be helped
LPUNKNOWN pUnkOuter,	//Points to controlling IUnknown
DWORD flags,	//Specifies the purpose for the helper
LPCLASSFACTORY pCF,	//Points to IClassFactory instance
REFIID riid,	//The ID of the interface sought by caller
LPVOID * lplpvObj	//Points to return point for helper
);
Parameters

clsid

Specifies the CLSID of the class to be helped.

pUnkOuter

Points to the controlling IUnknown interface if the handler is to be aggregated; NULL if it is not to be aggregated.

flags

Specifies the role and creation context for the embedding helper; see the following comments for legal values.

pCF

Points to the application's IClassFactory instance; can be NULL.

riid

Specifies the interface ID desired by the caller.

lplpvObj

Points to where to return the newly created embedding helper.

Return Values

S_OK

Indicates that the OLE embedding helper was created successfully.

E_NOINTERFACE

Indicates that the interface is not supported by the object.

E_OUTOFMEMORY

Out of memory.

E_INVALIDARG

Indicates that one or more arguments are invalid.

E_UNEXPECTED

Indicates that an unexpected error occurred.

Comments

The OleCreateEmbeddingHelper function is used to create a new instance of the OLE default handler, which can be used to support objects in various roles. The caller passes a pointer to its IClassFactory implementation to OleCreateEmbeddingHelper. This object and the default handler are then aggregated to create the new embedding helper object.

The OleCreateEmbeddingHelper function is usually used to support one of the following implementations:

•	An object application that is being used as both a container and a server, and which supports inserting objects into itself. In this case, the application registers its CLSID for different contexts by calling the CoRegisterClassObject function and specifying CLSCTX_LOCAL_SERVER | CLSCTX_INPROC_SERVER as the dwClsctx parameter, and REGCLS_MULTI_SEPARATE as the flags parameter. The local class is used to create the object and the in-process class creates the embedding helper, passing in the pointer to the first object's class factory in pCF.

•	An in-process object handler, in which case, the DLL creates the embedding helper by passing in a pointer to a private implementation of IClassFactory in pCF.

The flags parameter indicates how the embedding helper is to be used and how and when the embedding helper is initialized. The values for flags are obtained by OR-ing together values from the following table:

Values for flags Parameter	Purpose
EMBDHLP_INPROC_HANDLER	Creates an embedding helper that can be used with DLL object applications; specifically, the helper exposes the caching features of the default object handler.
EMBDHLP_INPROC_SERVER	Creates an embedding helper that can be used with in-process servers.
EMBDHLP_CREATENOW	EMBDHLP_CREATENOW creates the application-supplied piece of the object immediately.
EMBDHLP_DELAYCREATE	EMBDHLP_DELAYCREATE delays creating the application-supplied piece of the object until the object is put into its running state.
Calling

OleCreateEmbeddingHelper
(clsid, pUnkOuter, EMBDHLP_INPROC_HANDLER | EMBDHLP_CREATENOW,
NULL, riid, ppvObj)

is the same as calling

OleCreateDefaultHandler(clsid, pUnkOuter, riid, ppvObj)

See Also

OleCreateDefaultHandler


OleCreateFromData
OleCreateFromData   QuickInfo

Creates an embedded object from a data transfer object retrieved either from the clipboard or as part of an OLE drag and drop operation. It is intended to be used to implement a paste from an OLE drag and drop operation.

HRESULT OleCreateFromData(

LPDATAOBJECT pSrcDataObj,	//Data transfer object holding data used to create new object
REFIID riid,	//Interface to be used to communicate with the new object
DWORD renderopt,	//Value from OLERENDER
LPFORMATETC pFormatEtc,	//Depending on renderopt, pointer to value from FORMATETC
LPOLECLIENTSITE pClientSite,	//Points to instance of IOleClientSite
LPSTORAGE pStg,	//Points to instance of IStorage used to store object
LPVOID FAR* ppvObj	//Receives a pointer to the interface requested in riid
);
Parameters

pSrcDataObj

Points to the data transfer object that holds the data from which the object is created.

riid

Identifies the interface the caller later uses to communicate with the new object (usually IID_IOleObject).

renderopt

A value from the enumeration OLERENDER that indicates the locally cached drawing or data retrieval capabilities the newly created object is to have. Additional considerations are described in the Comments section below.

pFormatEtc

A value from the enumeration OLERENDER that indicates the locally cached drawing or data retrieval capabilities the newly created object is to have. The OLERENDER value chosen affects the possible values for the pFormatEtc parameter.

pClientSite

Points to an instance of IOleClientSite, the primary interface through which the object will request services from its container. May be NULL.

pStg

Points to an instance of the IStorage interface to be used as the storage for the object. This parameter may not be NULL.

ppvObj

Receives a pointer to the interface requested in riid on the newly created object on return.

Return Values

S_OK

Indicates that the embedded object was created successfully.

OLE_E_STATIC

Indicates OLE can create only a static object.

DV_E_FORMATETC

Indicates no acceptable formats are available for object creation.

Comments

The OleCreateFromData function creates an embedded object from an instance of the IDataObject interface. The data object in this case is either the type retrieved from the clipboard with a call to the OleGetClipboard function or is part of an OLE drag and drop operation (the data object is passed to a call to IDropTarget::Drop).

If either the FileName or FileNameW clipboard format (CF_FILENAME) is present in the data transfer object, and CF_EMBEDDEDOBJECT or CF_EMBEDSOURCE do not exist, OleCreateFromData creates a package containing the indicated file. (Generally, it takes the first available format.) The Microsoft Windows NT File Manager places these formats on the clipboard when the user selects the File / Copy To Clipboard menu command.

If OleCreateFromData cannot create a package, it tries to create an object using the CF_EMBEDDEDOBJECT format. If that format is not available, OleCreateFromData tries to create it with the CF_EMBEDSOURCE format. If neither of these formats is available and the data transfer object supports the IPersistStorage interface, OleCreateFromData calls IPersistStorage::Save to have the object save itself.

If an existing linked object is selected, then copied, it appears on the clipboard as just another embeddable object. Consequently, a paste operation that invokes OleCreateFromData may create a linked object. After the paste operation, the container should call the QueryInterface function, requesting IID_IOleLink, to determine if a linked object was created.

Use the renderopt and pFormatetc parameters to control the caching capability of the newly created object. For information on how to determine what is to be cached, refer to the OLERENDER enumeration for a description of the interaction between renderopt and pFormatetc. However, values of renderopt also specifically affect the way OleCreateFromData initializes the cache.

When OleCreateFromData uses either the CF_EMBEDDEDOBJECT or the CF_EMBEDSOURCE clipboard format to create the embedded object, the main difference between the two is where the cache-initialization data is stored:

•	CF_EMBEDDEDOBJECT indicates that the source is an existing embedded object. It already has in its cache the appropriate data, and OLE uses this data to initialize the cache of the new object.

•	CF_EMBEDSOURCE indicates that the source data object contains the cache initialization information in formats other than CF_EMBEDSOURCE. OleCreateFromData uses these to initialize the cache of the newly embedded object.

The renderopt values affect cache initialization as follows:

Value	Description
OLERENDER_DRAW & OLERENDER_FORMAT	If the presentation information to be cached is currently present in the appropriate cache initialization pool, it is used. (Appropriate locations are in the source data object cache for CF_EMBEDDEDOBJECT, and in the other formats in the source data object for CF_EMBEDSOURCE.) If the information is not present, the cache is initially empty, but will be filled the first time the object is run. No other formats are cached in the newly created object.
OLERENDER_NONE	Nothing is to be cached in the newly created object. If the source has the CF_EMBEDDEDOBJECT format, any existing cached data that has been copied is removed.
OLERENDER_ASIS	If the source has the CF_EMBEDDEDOBJECT format, the cache of the new object is to contain the same cache data as the source object. For CF_EMBEDSOURCE, nothing is to be cached in the newly created object.  This option should be used by more sophisticated containers. After this call, such containers would call IOleCache::Cache and IOleCache::Uncache to set up exactly what is to be cached. For CF_EMBEDSOURCE, they would then also call IOleCache::InitCache.
See Also

OleCreate


OleCreateFromFile
OleCreateFromFile   QuickInfo

Creates an embedded object from the contents of a named file.

OleCreateFromFile(

REFCLSID rclsid,	//Reserved. Must be CLSID_NULL
LPCOLESTR lpszFileName,	//Points to full path name of file used ot create object
REFIID riid,	//Interface to be used to communicate with new object
DWORD renderopt,	//Value from OLERENDER
LPFORMATETC pFormatEtc,	//FORMATETC value depending on OLERENDER value
LPOLECLIENTSITE pClientSite,	//Pointer to an instance of IOleClientSite
LPSTORAGE pStg,	//Pointer to IStorage instance to be used as object storage
LPVOID FAR* ppvObj	//Receives a pointer to the interface requested in riid
);
Parameters

rclsid

Reserved. Must be CLSID_NULL.

lpszFileName

Points to the full path name specifying the file from which the object should be initialized.

riid

Identifies the interface the caller later uses to communicate with the new object (usually IID_IOleObject).

renderopt

A value from the enumeration OLERENDER that indicates the locally cached drawing or data-retrieval capabilities the newly created object is to have. The OLERENDER value chosen affects the possible values for the pFormatEtc parameter.

pFormatEtc

Depending on which of the OLERENDER flags is used as the value of renderopt, can be one of the FORMATETC enumeration values. Refer also to the OLERENDER enumeration for restrictions.

pClientSite

Points to an instance of IOleClientSite, the primary interface through which the object will request services from its container. May be NULL.

pStg

Points to an instance of the IStorage interface to be used as the storage for the object. This parameter may not be NULL.

ppvObj

Receives a pointer to the interface requested in riid on the newly created object on return.

Return Values

S_OK

Indicates embedded object successfully created.

STG_E_FILENOTFOUND

Indicates file not bound.

OLE_E_CANT_BINDTOSOURCE

Indicates not able to bind to source.

STG_E_MEDIUMFULL

Indicates the medium is full.

DV_E_TYMED

Indicates invalid TYMED.

DV_E_LINDEX

Indicates invalid LINDEX.

DV_E_FORMATETC

Indicates invalid FORMATETC structure.

E_OUTOFMEMORY

Indicates OLE libraries have not been properly initialized.

Comments

The OleCreateFromFile function creates a new embedded object from the contents of a named file. If the ProgID in the registration database contains the PackageOnFileDrop key, it creates a package. If not, the function calls the GetClassFile function to get the CLSID associated with the lpszFileName parameter, and then creates an OLE 2-embedded object associated with that CLSID. The rclsid parameter of OleCreateFromFile will always be ignored, and should be set to CLSID_NULL.

As for other OleCreateXxx functions, the newly created object is not shown to the user for editing, which requires a DoVerb operation. It is used in to implement insert file operations, such as the Create from File command in Word for Windows.

See Also

GetClassFile


OleCreateLink
OleCreateLink   QuickInfo

Creates an OLE compound-document linked object.

HRESULT OleCreateLink(

LPMONIKER pmkLinkSrc,	//Points to IMoniker instance indicating source of linked object
REFIID riid,	//Interface to be used to communicate with the new object
DWORD renderopt,	//Value from OLERENDER
LPFORMATETC pFormatEtc,	//FORMATETC value depending on renderopt value
LPOLECLIENTSITE pClientSite,	//Pointer to an instance of IOleClientSite
LPSTORAGE pStg,	//Pointer to an IStorage instance used as the object storage
LPVOID FAR* ppvObj	//Receives a pointer to the interface requested in riid
);
Parameters

pmkLinkSrc

Points to an IMoniker interface instance that indicates the source of the linked object.

riid

Identifies the interface the caller later uses to communicate with the new object (usually IID_IOleObject).

renderopt

Specifies a value from the enumeration OLERENDER that indicates the locally cached drawing or data-retrieval capabilities the newly created object is to have. Additional considerations are described in the Comments section below.

lpFormatEtc

Specifies a value from the enumeration OLERENDER that indicates the locally cached drawing or data retrieval capabilities the newly created object is to have. The OLERENDER value chosen affects the possible values for the pFormatEtc parameter.

pClientSite

Points to an instance of IOleClientSite, the primary interface through which the object will request services from its container. May be NULL.

pStg

Points to an instance of the IStorage interface to be used as the storage for the object. This parameter may not be NULL.

ppvObj

Receives a pointer to the interface requested in riid on the newly created object on return.

Return Values

S_OK

Indicates the compound-document linked object was created successfully.

OLE_E_CANT_BINDTOSOURCE

Indicates not able to bind to source. Binding is necessary to get the cache's initialization data.

Comments

Call OleCreateLink whenever a container creates a linked object within itself.

See Also

IOleObject::SetMoniker, IOleClientSite::GetMoniker


OleCreateLinkFromData
OleCreateLinkFromData   QuickInfo

Creates a linked object from a data transfer object retrieved either from the clipboard or as part of an OLE drag and drop operation.

HRESULT OleCreateLinkFromData(

LPDATAOBJECT pSrcDataObj,	//Points to data transfer object used to create linked object
REFIID riid,	//Interface to be used to communicate with the new object
DWORD renderopt,	//OLERENDER value
LPFORMATETC pFormatEtc,	//FORMATETC value, depends on OLERENDER value
LPOLECLIENTSITE pClientSite,	//Points to IOleClientSite instance
LPSTORAGE pStg,	//Pointer to an IStorage instance used as the object storage
LPVOID FAR* ppvObj	//On return, points to requested object
);
Parameters

pSrcDataObj

Points to the data transfer object from which the linked object is to be created.

riid

Identifies the interface the caller later uses to communicate with the new object (usually IID_IOleObject).

renderopt

Specifies a value from the enumeration OLERENDER that indicates the locally cached drawing or data-retrieval capabilities the newly created object is to have. Additional considerations are described in the Comments section below.

pFormatEtc

Specifies a value from the enumeration OLERENDER that indicates the locally cached drawing or data-retrieval capabilities the newly created object is to have. The OLERENDER value chosen affects the possible values for the pFormatEtc parameter.

pClientSite

Points to an instance of IOleClientSite, the primary interface through which the object will request services from its container. May be NULL.

pStg

Points to an instance of the IStorage interface to be used as the storage for the object. This parameter may not be NULL.

ppvObj

Receives a pointer to the interface requested in riid on the newly created object on return.

Return Values

S_OK

Indicates the linked object was created successfully.

CLIPBRD_E_CANT_OPEN

Indicates not able to open the clipboard.

OLE_E_CANT_GETMONIKER

Indicates not able to extract the object's moniker.

OLE_E_CANT_BINDTOSOURCE

Indicates not able to bind to source. Binding is necessary to get the cache's initialization data.

Comments

The OleCreateLinkFromData function is used to implement either a paste-link or a drag-link operation.

Its operation is similar to that of the OleCreateFromData function, except that it creates a link, and looks for different data formats. If the CF_LINKSOURCE format is not present, and either the FileName or FileNameW clipboard format is present in the data transfer object, OleCreateLinkFromData creates a package containing the link to the indicated file.

You use the renderopt and pFormatetc parameters to control the caching capability of the newly created object. For information on how to determine what is to be cached, refer to the OLERENDER enumeration for a description of the interaction between renderopt and pFormatetc. However, values of renderopt also specifically affect the way OleCreateLinkFromData initializes the cache as follows:

Value	Description
OLERENDER_DRAW, OLERENDER_FORMAT	If the presentation information is in the other formats in the source data object,this information is used. If the information is not present, the cache is initially empty, but will be filled the first time the object is run. No other formats are cached in the newly created object.
OLERENDER_NONE, OLERENDER_ASIS	Nothing is to be cached in the newly created object.
See Also

OleCreateLink


OleCreateLinkToFile
OleCreateLinkToFile   QuickInfo

Creates an object that is linked to a file.

STDAPI OleCreateLinkToFile(

LPWSTR lpszFileName,	//Points to source of linked object
REFIID riid,	//Interface to be used to communicate with the new object
DWORD renderopt,	//Value from OLERENDER
LPFORMATETC pFormatEtc,	//FORMATETC value depending on renderopt value
IOleClientSite * pClientSite,	//Pointer to an instance of IOleClientSite
IStorage * pStg,	//Pointer to an IStorage instance used as the object storage
void ** ppvObj	//Receives a pointer to the interface requested in riid
);
Parameters

lpszFileName

Points to the source file to be linked to.

riid

Identifies the interface the caller later uses to communicate with the new object (usually IID_IOleObject).

renderopt

Specifies a value from the enumeration OLERENDER that indicates the locally cached drawing or data-retrieval capabilities the newly created object is to have. Additional considerations are described in the Comments section below.

pFormatEtc

Specifies a value from the enumeration OLERENDER the indicates the locally cached drawing or data retrieval capabilities the newly created object is to have. The OLERENDER value chosen affects the possible values for the pFormatEtc parameter.

pClientSite

Points to an instance of IOleClientSite, the primary interface through which the object will request services from its container. May be NULL.

pStg

Points to an instance of the IStorage interface to be used as the storage for the object. This parameter may not be NULL.

ppvObj

Receives a pointer to the interface requested in riid on the newly created object on return.

Return Values

S_OK

Indicates the object was created successfully.

STG_E_FILENOTFOUND

Indicates file name is invalid.

OLE_E_CANT_BINDTOSOURCE

Indicates not able to bind to source.

Comments

The OleCreateLinkToFile function differs from the OleCreateLink function because it can create links to non-OLE aware files (as well as files that are OLE-aware) using the Windows Packager.

See Also

OleCreateLink


OleCreateMenuDescriptor
OleCreateMenuDescriptor   QuickInfo

Creates and returns an OLE menu descriptor (that is, an OLE-provided data structure that describes the menus) for OLE to use when dispatching menu messages and commands.

HOLEMENU OleCreateMenuDescriptor(

HMENU hmenuCombined,	//Specifies a handle to the combined menu
LPOLEMENUGROUPWIDTHS lpMenuWidths	//Number of menus in each group
);
Parameters

hmenuCombined

Specifies a handle to the combined menu created by the object.

lpMenuWidths

Points to an array of six LONG values giving the number of menus in each group.

Return Value

Returns the handle to the descriptor, or NULL if insufficient memory is available.

Comments

The OleCreateMenuDescriptor function can be called by the object to create a descriptor for the composite menu. OLE then uses this descriptor to dispatch menu messages and commands.

See Also

OleDestroyMenuDescriptor


OleCreateStaticFromData
OleCreateStaticFromData   QuickInfo

The OleCreateStaticFromData function creates a static object (containing only a representation, with no native data) from a data transfer object.

HRESULT OleCreateStaticFromData(

LPDATAOBJECT pSrcDataObj,	//Data transfer object holding data used to create new object
REFIID riid,	//Interface to be used to communicate with the new object
DWORD renderopt,	//Value from OLERENDER
LPFORMATETC pFormatEtc,	//Depending on renderopt, pointer to value from FORMATETC
LPOLECLIENTSITE pClientSite,	//Points to instance of IOleClientSite
LPSTORAGE pStg,	//Points to instance of IStorage used to store object
LPVOID FAR* ppvObj	//Receives a pointer to the interface requested in riid
);
Parameters

pSrcDataObj

Points to the data transfer object that holds the data from which the object will be created.

riid

Identifies the interface with which the caller is to communicate with the new object (usually IID_IOleObject).

renderopt

A value from the enumeration OLERENDER indicating the locally cached drawing or data-retrieval capabilities that the container wants in the newly created component. It is an error to pass the render options OLERENDER_NONE or OLERENDER_ASIS to this function.

pFormatEtc

Depending on which of the OLERENDER flags is used as the value of renderopt, may be one of the FORMATETC enumeration values. Refer to the OLERENDER enumeration for restrictions.

pClientSite

Points to an instance of IOleClientSite, the primary interface through which the object will request services from its container. May be NULL.

pStg

Points to an instance of the IStorage interface to be used as the storage for the object. This parameter may not be NULL.

ppvObj

When the function returns successfully, contains a pointer to the interface requested in riid on the newly created object.

Return Value

S_OK

Indicates that the object was successfully created.

Comments

The OleCreateStaticFromData function can convert any object that provides an IDataObject interface to a static object. It is useful in implementing the Convert To Picture option for OLE linking or embedding.

Static objects can be created only if the source supports one of the OLE-rendered clipboard formats: CF_METAFILEPICT, CF_DIB, or CF_ BITMAP, and CF_ENHMF.

Static objects can be pasted from the clipboard using OleCreateStaticFromData. The OleQueryCreateFromData function will return OLE_S_STATIC if one of CF_METAFILEPICT, CF_DIB, or CF_BITMAP is present and an OLE format is not present. But, in that case, the OleCreateFromData function does not automatically create the static object — if the container will be pasting a static object it should call OleCreateStaticFromData.

The new static object is of class CLSID_StaticMetafile (in the case of CF_METAFILEPICT) and CLSID_StaticDib (in the case of CF_DIB or CF_BITMAP). The static object sets the OLEMISC_STATIC and OLE_CANTLINKINSIDE bits returned from IOleObject::GetMiscStatus. The static object will have the aspect DVASPECT_CONTENT and a LINDEX of -1.

The pDataObject is still valid after OleCreateStaticFromData returns. It is the caller's responsibility to free pDataObject — OLE does not release it.

There cannot be more than one presentation stream in a static object.

Note  The OLESTREAM<->IStorage conversion functions also convert static objects.

See Also

OleCreateFromData


OleDestroyMenuDescriptor
OleDestroyMenuDescriptor   QuickInfo

Called by the container to free the shared menu descriptor allocated by the OleCreateMenuDescriptor function.

void OleDestroyMenuDescriptor(

HOLEMENU holemenu	//Handle to the shared menu descriptor
);
Parameter

holemenu

Specifies a handle to the shared menu descriptor that was returned by the OleCreateMenuDescriptor function.

Return Value

None. (This function does not indicate failure.)

See Also

OleCreateMenuDescriptor


OleDoAutoConvert
OleDoAutoConvert   QuickInfo

Automatically converts an object to a new class if conversion is needed.

HRESULT OleDoAutoConvert(

IStorage * pStg,	//Pointer to storage object to be converted
LPCLSID pClsidNew	//Points to new CLSID of converted object
);
Parameters

pStg

Points to the persistent storage of the object to be converted.

pClsidNew

Points to the new CLSID for the object being converted. If there was no automatic conversion, this may be the same as the original class.

Return Values

S_OK

Indicates no conversion is needed or a conversion was successfully completed.

REGDB_E_KEYMISSING

Indicates cannot read a key from the registration database.

E_OUTOFMEMORY

Indicates the conversion was not successful due to a lack of memory.

E_INVALIDARG

Indicates one or more arguments are invalid.

E_UNEXPECTED

Indicates an unexpected error occurred.

See also the OleGetAutoConvert function for other error return values.

See the IStorage::OpenStorage and IStorage::OpenStream methods for possible errors when accessing storage and stream objects.

See also the IStream interface for other error return values when it is not possible to determine the existing CLSID or when it is not possible to update the storage object with new information.

Comments

This function automatically converts an object if automatic conversion has previously been specified in the registry by the OleSetAutoConvert function. Object conversion means that the object is permanently associated with a new CLSID. Automatic conversion is typically specified by the setup program for a new version of an object application so that objects created by its older versions can be automatically updated.

A container application that supports object conversion should call the OleDoAutoConvert function each time it loads an object. If the container uses the OleLoad helper function, it need not call OleDoAutoConvert explicitly because OleLoad calls it internally.

The OleDoAutoConvert function first determines whether any conversion is required by calling the OleGetAutoConvert function. If no conversion is required, the function returns S_OK. Otherwise, the storage object is modified and converted by activating the new object application. The new object application reads the existing data format but when the object is saved, the new native format for the object application is saved.

If the object to be automatically converted is an OLE 1 object, the ItemName string is stored in a stream called "\1Ole10ItemName." If this stream does not exist, the object's item name is NULL.

The storage object must be in the unloaded state when OleDoAutoConvert is called.

See Also

OleSetAutoConvert


OleDraw
OleDraw   QuickInfo

The OleDraw helper function can be used to draw objects more easily. You can use it instead of calling IViewObject::Draw directly.

STDAPI OleDraw(

IUnknown * pUnk,	//Points to the view object to be drawn
DWORD dwAspect,	//Specifies how the object is to be represented
HDC hdcDraw,	//Identifies the device context on which to draw
LPCRECT lprcBounds	//Specifies the rectangle in which the object is drawn
);
Parameters

pUnk

Points to the view object that is to be drawn.

dwAspect

Specifies how the object is to be represented. Representations include content, an icon, a thumbnail, or a printed document. Valid values are taken from the enumeration DVASPECT. See DVASPECT for more information.

hdcDraw

Specifies the device context on which to draw. Cannot be a metafile device context.

lprcBounds

Points to a RECT structure specifying the rectangle in which the object should be drawn. This parameter is converted to a RECTL structure and passed to IViewObject::Draw.

Return Values

S_OK

Indicates object was successfully drawn.

E_INVALIDARG

Indicates one or more arguments are invalid.

E_OUTOFMEMORY

Indicates ran out of memory.

OLE_E_BLANK

Indicates there is no data to draw from.

E_ABORT

Indicates the draw operation was aborted.

VIEW_E_DRAW

Indicates an error occurred in drawing.

OLE_E_INVALIDRECT

Indicates the rectangle is invalid.

DV_E_NOIVIEWOBJECT

Indicates the object doesn't support the IViewObject interface.

Comments

The OleDraw helper function calls the QueryInterface method for the object specified (pUnk), asking for an IViewObject interface on that object. Then, OleDraw converts the RECT structure to a RECTL structure, and calls IViewObject::Draw as follows:

lpViewObj->Draw(dwAspect,-1,0,0,0,hdcDraw,&rectl,0,0,0);

Do not use OleDraw to draw into a metafile because it does not specify the lprcWBounds parameter required for drawing into metafiles.

See Also

IViewObject::Draw


OleDuplicateData
OleDuplicateData   QuickInfo

Duplicates the data found in the specified handle and returns a handle to the duplicated data. The source data is in a clipboard format. You use this function when implementing some of the data transfer interfaces such as IDataObject.

HANDLE OleDuplicateData(

HANDLE hSrc,	//Handle of the source data
CLIPFORMAT cfFormat,	//Clipboard format of the source data
UINT uiFlags	//Flags used in global memory allocation
);
Parameters

hSrc

Specifies the handle of the source data.

cfFormat

Specifies the clipboard format of the source data.

uiFlags

Specifies the flags to be used in allocate global memory for the copied data. These flags are passed to GlobalAlloc. If the value of uiFlags is NULL, GMEM_MOVEABLE is used as a default flag.

Return Values

HANDLE

Indicates data was successfully duplicated and the handle to the new data is the return value of the function.

NULL

Indicates error duplicating data.

Comments

The CF_METAFILEPICT, CF_PALETTE, or CF_BITMAP formats receive special handling. They are GDI handles and a new GDI object must be created instead of just copying the bytes. All other formats are duplicated byte-wise. For the formats that are duplicated byte-wise, hSrc must be a global memory handle.


OleFlushClipboard
OleFlushClipboard   QuickInfo

Carries out the clipboard shutdown sequence. It also releases the instance of the IDataObject interface that was placed on the clipboard by the OleSetClipboard function.

HRESULT OleFlushClipboard();

Return Values

S_OK

Indicates the clipboard has been flushed.

CLIPBRD_E_CANT_OPEN

Indicates the Windows OpenClipboard function used within OleFlushClipboard failed.

CLIPBRD_E_CANT_CLOSE

Indicates the Windows CloseClipboard function used within OleFlushClipboard failed.

Comments

If you are writing an application that can act as the source of a clipboard operation, you can call OleFlushClipboard to flush the clipboard and release the instance of IDataObject when your application is closed (e.g., if the user exits from your application). A call to the OleSetClipboard function using NULL will empty the clipboard.

The difference is that OleFlushClipboard leaves all formats offered by the data transfer object, including the OLE 1 compatibility formats, on the clipboard so they are available after application shutdown. In addition to OLE 1 compatibility formats, these include all formats offered on a global handle medium (all except for TYMED_FILE) and formatted with a NULL target device.

When your application closes, you should call OleSetClipboard using NULL if there is no need to leave data on the clipboard after shutdown or if data will be placed on the clipboard using the standard Windows clipboard functions. Applications should call OleFlushClipboard to enable pasting and paste-linking of OLE objects after shutdown.

Before calling OleFlushClipboard, it must be convenient to check the clipboard. You can call the OleIsCurrentClipboard function to determine if your data is still on the clipboard.

See Also

OleSetClipboard, OleIsCurrentClipboard, IDataObject,


OleGetAutoConvert
OleGetAutoConvert   QuickInfo

Returns the new CLSID to which the specified object can be automatically converted. This conversion CLSID is stored in the registration database.

HRESULT OleGetAutoConvert(

REFCLSID clsidOld,	//CLSID of the object to be converted
LPCLSID pClsidNew	//Pointer to new CLSID for object being converted
);
Parameters

clsidOld

Specifies the CLSID for an object that can be automatically converted.

pClsidNew

Points to location where the new CLSID, if any, is returned. The original object, clsidOld, is automatically converted to this new CLSID when the object is opened. If there is no auto-conversion CLSID stored in the registration database, the value clsidOld is returned; the pClsidNew parameter cannot be NULL.

Return Values

S_OK

Indicates that a value was successfully returned through the pclsidNew parameter.

REGDB_E_CLASSNOTREG

Indicates the clsidOld CLSID is not properly registered in the registration database.

REGDB_E_READREGDB

Indicates error reading the registration database.

REGDB_E_KEYMISSING

Indicates auto convert is not active or there was no registration entry for the clsidOld parameter.

E_OUTOFMEMORY

Indicates the value was not returned due to a lack of memory.

E_INVALIDARG

Indicates one or more arguments are invalid.

E_UNEXPECTED

Indicates an unexpected error occurred.

Comments

This function returns the AutoConvertTo entry in the registration database for the specified object, which specifies whether objects of a given CLSID are to be automatically converted to a new CLSID. This is usually set up to convert files created by older versions of an application to the current version. If there is no AutoConvertTo entry, this function returns the value of clsidOld. This function is typically called by the OleDoAutoConvert function to determine if the object specified needs to be converted. If the object has an AutoConvertTo entry, then it will be converted.

Automatic conversion is typically set up during the installation of an object application. The setup program can take advantage of the AutoConvertTo subkey to tag a class of objects for automatic conversion to a different class of objects.

For example, a new version of a spreadsheet application may need to convert spreadsheets that were created with earlier versions of the application. These earlier version spreadsheet objects have a different CLSID than the new version. The setup program for the new version of the spreadsheet application tags objects in the registration database that have the old CLSID so they are automatically updated when they are loaded.

To tag the old spreadsheet objects, the setup program calls the OleSetAutoConvert function and passes it to the CLSIDs of the source and destination object classes. The OleSetAutoConvert function creates the required entry in the registration database. These entries appear in the registration database as subkeys of the CLSID key:

CLSID\{clsid}=MainUserTypeName\AutoConvertTo = clsid

See Also

OleSetAutoConvert, OleDoAutoConvert


OleGetClipboard
OleGetClipboard   QuickInfo

Retrieves a data object that you can use to access the clipboard contents.

HRESULT OleGetClipboard(

IDataObject ** ppDataObj	//Points to location where a pointer to the data object is placed
);
Parameter

ppDataObj

Points to the location where a pointer to the retrieved data object can be placed.

Return Values

S_OK

Indicates the data object was successfully retrieved.

E_OUTOFMEMORY

Indicates the data object was not returned due to a lack of memory.

CLIPBRD_E_CANT_CLOSE

Indicates the Windows CloseClipboard function used within OleGetClipboard failed.

CLIPBRD_E_CANT_OPEN

Indicates the Windows OpenClipboard function used with OleGetClipboard failed.

Comments

If you are writing an application that can accept data from the clipboard, you call OleGetClipboard to get a pointer to a data object that you can use to retrieve the contents of the clipboard.

There are three cases that the OleGetClipboard function handles:

1.	The application that placed data on the clipboard with the OleSetClipboard function is still running.

2.	The application that placed data on the clipboard with the OleSetClipboard function has subsequently called the OleFlushClipboard function.

3.	There is data from a non-OLE application on the clipboard.

In the first case, the clipboard data object returned by the OleGetClipboard function may forward calls as necessary to the original data object placed on the clipboard and, thus, can potentially make RPC calls.

In the second case, OLE creates a default data object and returns it to the user. However, because the data on the Clipboard originated from an OleSetClipboard call, the OLE-provided data object contains more accurate information about the type of data on the Clipboard. In particular, the original medium (TYMED) on which the data was offered is known. Thus, if a data-source application offers a particular clipboard format, for example cfFOO, on an IStorage object and calls the OleFlushClipboard function, the storage object is copied into memory and the hglobal memory handle is put on the Clipboard. Then, when the OleGetClipboard function creates its default data object, the hglobal from the clipboard again becomes an IStorage object. Furthermore, the FORMATETC enumerator and the IDataObject::QueryGetData method would all correctly indicate that the original clipboard format (cfFOO) is again available on a TYMED_ISTORAGE.

In the third case, OLE still creates a default data object, but there is no special information about the data in the Clipboard formats (particularly for application-defined Clipboard formats). Thus, if an hGlobal-based storage medium were put on the Clipboard directly by a call to the SetClipboardData function, the FORMATETC enumerator and the IDataObject::QueryGetData method would not indicate that the data was available on a storage medium. A call to the IDataObject::GetData method for TYMED_ISTORAGE would succeed, however. Because of these limitations, it is strongly recommended that OLE-aware applications interact with the Clipboard using the OLE Clipboard functions.

The clipboard data object created by the OleGetClipboard function has a fairly extensive IDataObject implementation. The OLE-provided data object can convert OLE 1 clipboard format data into the representation expected by an OLE 2 caller. Also, any structured data is available on any structured or flat medium, and any flat data is available on any flat medium. However, GDI objects (such as metafiles and bitmaps) are only available on their respective mediums.

Note that the tymed member of the FORMATETC structure used in the FORMATETC enumerator contains the union of supported mediums. Applications looking for specific information (such as whether CF_TEXT is available on TYMED_HGLOBAL) should do the appropriate bit masking when checking this value.

If you call the OleGetClipboard function, you should only hold on to the returned IDataObject for a very short time. It consumes resources in the application that offered it.

See Also

OleSetClipboard


OleGetIconOfClass
OleGetIconOfClass   QuickInfo

Returns a handle to a metafile containing an icon and a string label for the specified CLSID.

HGLOBAL OleGetIconOfClass(

REFCLSID rclsid,	//CLSID for which information is requested
LPOLESTR lpszLabel,	//Points to string to use as label for icon
BOOL fUseTypeAsLabel	//Indicates whether to use CLSID's user type name as icon label
);
Parameters

rclsid

Specifies the CLSID for which the icon and string are requested.

lpszLabel

Points to a string to use as a label for the icon.

fUseTypeAsLabel

Indicates whether or not to use the user type string in the CLSID as the icon label.

Return Value

HGLOBAL

The hGlobal returned is a handle to a metafile that contains an icon and label for the specified CLSID. If the CLSID cannot be found in the registration database, NULL is returned.

See Also

OleGetIconOfFile, OleMetafilePictFromIconAndLabel


OleGetIconOfFile
OleGetIconOfFile   QuickInfo

Returns a handle to a metafile containing an icon and string label for the specified filename.

HGLOBAL OleGetIconOfFile(

LPOLESTR lpszPath,	//Points to string that specifies the file for which info is requested
BOOL fUseFileAsLabel	//Indicates whether to use the filename as the icon label
);
Parameters

lpszPath

Points to a file for which the icon and string are requested.

fUseFileAsLabel

Indicates whether or not to use the filename as the icon label.

Return Value

HGLOBAL

The hGlobal returned is a handle to a metafile that contains an icon and label for the specified file. If there is no CLSID in the registration database for the file, then the string "Document" is used. If the value of lpszPath is NULL, then NULL is returned.

See Also

OleGetIconOfClass, OleMetafilePictFromIconAndLabel


OleInitialize
OleInitialize   QuickInfo

The OleInitialize function initializes the OLE library. You must initialize the library before you can call OLE functions.

HRESULT OleInitialize(

LPVOID pvReserved	//Reserved, must be NULL
);
Parameter

pvReserved

In 32-bit OLE, this parameter must be NULL. The 32-bit version of OLE does not support applications replacing OLE's allocator and if the parameter is not NULL, OleInitialize returns E_INVALIDARG.

Return Values

S_OK

Indicates the library was initialized successfully.

S_FALSE

Indicates OLE library is already initialized; a pointer to the IMalloc implementation was not used.

OLE_E_WRONGCOMPOBJ

Indicates COMPOBJ.DLL is the wrong version for OLE2.DLL.

E_OUTOFMEMORY

Indicates the library was not initialized because the system was out of memory.

E_INVALIDARG

Indicates an argument was invalid.

E_UNEXPECTED

Indicates an unexpected error occurred.

Comments

Applications must call OleInitialize before calling any other function in the OLE library.

Typically, OleInitialize is called only once in the process that uses the OLE library. There can be multiple calls, but subsequent calls return S_FALSE. To close the library gracefully, each successful call to OleInitialize, including those that return S_FALSE, must be balanced by a corresponding call to the OleUninitialize function.

See Also

OleUninitialize, CoInitialize


OleIsCurrentClipboard
OleIsCurrentClipboard   QuickInfo

Determines whether the IDataObject interface previously placed on the clipboard by the OleSetClipboard function is still on the clipboard.

HRESULT OleIsCurrentClipboard(

IDataObject * pDataObj	//The data object previously copied or cut
);
Parameter

pDataObject

Points to the instance of IDataObject that the caller previously placed on the clipboard.

Return Values

S_OK

Indicates that IDataObject is currently on the clipboard and the caller is the owner of the clipboard.

S_FALSE

Indicates that IDataObject is not on the clipboard.

Notes to Callers

OleIsCurrentClipboard only works for the data object used in the OleSetClipboard function. It cannot be called by the consumer of the data object to determine if the object that was on the clipboard at the previous OleGetClipboard call is still on the clipboard.

See Also

OleFlushClipboard, OleSetClipboard


OleIsRunning
OleIsRunning   QuickInfo

Determines whether an object is currently in the running state.

BOOL OleIsRunning(

LPOLEOBJECT pObject	//Pointer to IOleObject interface
);
Parameter

pObject

Points to an the object's IOleObject interface.

Return Value

The return value is TRUE if the object is running; otherwise, it is FALSE.

Comments

You can use OleIsRunning and IRunnableObject::IsRunning interchangeably. OleIsRunning queries the object for a pointer to the IRunnableObject interface. If successful, the function returns the results of calling the IRunnableObject::IsRunning method.

Note  The implementation of OleIsRunning in earlier versions of OLE differs from that described here.

For more information on using this function, see IRunnableObject::IsRunning.

See Also

IRunnableObject::IsRunning


OleLoad
OleLoad   QuickInfo

Loads into memory an object nested within a specified storage object.

HRESULT OleLoad(

IStorage * pStg,	//Points to the storage object from which to load
REFIID riid,	//Interface to use for the object being loaded
IOleClientSite * pClientSite,	//Points to the client site for the object
LPVOID * ppvObj	//Points to the newly loaded object
);
Parameters

pStg

Points to the storage object from which to load the specified object.

riid

Specifies the interface that the caller wants to use when talking to the object once it is loaded.

pClientSite

Points to the client site for the object being loaded.

ppvObj

Points to the newly loaded object.

Return Values

S_OK

Indicates the object was loaded successfully.

E_OUTOFMEMORY

Indicates the object could not be loaded due to lack of memory.

E_NOINTERFACE

Indicates the object does not support the specified interface.

See also the IPersistStorage::Load method for other error return values.

Comments

OLE containers load objects into memory by calling this function. When calling the OleLoad function, the container application passes in a pointer to the open storage object in which the nested object is stored. Typically, the nested object to be loaded is a child storage object to the container's root storage object. Using the OLE information stored with the object, the object handler (usually, the default handler) attempts to load the object. On completion of the OleLoad function, the object is said to be in the loaded state with its object application not running.

Some applications load all of the object's native data. Containers often defer loading the contained objects until required to do so. For example, until an object is scrolled into view and needs to be drawn, it does not need to be loaded.

The OleLoad function performs the following steps:

1.	If necessary, performs an automatic conversion of the object (see the OleDoAutoConvert function).

2.	Gets the CLSID from the open storage object by calling the IStorage::Stat method.

3.	Calls the CoCreateInstance function to create an instance of the handler. If the handler code is not available, the default handler is used (see the OleCreateDefaultHandler function).

4.	Calls the IOleObject::SetClientSite method with the pClientSite parameter to inform the object of its client site.

5.	Calls the QueryInterface method for the IPersistStorage interface. If successful, the IPersistStorage::Load method is invoked for the object.

6.	Queries and returns the interface identified by the riid parameter.

See Also

ReadClassStg, IClassFactory::CreateInstance, IPersistStorage::Load


OleLoadFromStream
OleLoadFromStream   QuickInfo

Loads an object from the stream.

HRESULT OleLoadFromStream(

IStream * pStm,	//Points to stream from which object is to be loaded
REFIID iidInterface,	//Interface to use for the object being loaded
void ** ppvObj	//Points to the newly loaded object
);
Parameters

pStm

Points to the stream from which the object is to be loaded.

iidInterface

Specifies the interface the caller wants to use to talk to the object once it is loaded.

ppvObj

Points to the newly loaded object.

Return Values

S_OK

Indicates the object was successfully loaded.

E_OUTOFMEMORY

Indicates the object could not be loaded due to a lack of memory.

E_NOINTERFACE

Indicates the specified interface is not supported.

See also the ReadClassStm function for other error return values.

See also the CoCreateInstance function for other error return values.

See also the IPersistStorage::Load method for other error return values.

Comments

This function can be used to load an object that supports the IPersistStream interface. The CLSID of the object must immediately precede the object's data in the stream.

If the CLSID for the stream is CLSID_NULL, the ppvObj parameter is set to NULL.

See Also

OleSaveToStream


OleLockRunning
OleLockRunning   QuickInfo

Locks an already running object into its running state or unlocks it from its running state.

HRESULT OleLockRunning(

LPUNKNOWN pUnknown,	//Pointer to IUnknown interface
BOOL fLock,	//Flag indicating whether object is locked
BOOL fLastUnlockCloses	//Flag indicating whether to close object
);
Parameters

pUnknown

Points to an object's IUnknown interface in order to obtain a pointer to IRunnableObject::LockRunning.

fLock

TRUE locks the object into its running state. FALSE unlocks the object from its running state.

fLastUnlockCloses

TRUE specifies that if the connection being released is the last external lock on the object, the object should close. FALSE specifies that the object should remain open until closed by the user or another process.

Return Values

S_OK

Indicates that the object was successfully locked or unlocked.

E_OUTOFMEMORY

Out of memory.

E_INVALIDARG

Indicates one or more arguments are invalid .

E_UNEXPECTED

Indicates an unexpected error occurred.

Comments

The OleLockRunning function saves you the trouble of calling the IRunnableObject::LockRunning method. You can use OleLockRunning and IRunnableObject::LockRunning interchangeably. OleLockRunning queries for an IRunnableObject pointer. If successful, it returns the results of calling IRunnableObject::LockRunning.

Note  The implementation of OleLockRunning in earlier versions of OLE differs from that described here.

For more information on using this function, see IRunnableObject::LockRunning.

See Also

CoLockObjectExternal, IRunnableObject::LockRunning, OleNoteObjectVisible


OleMetafilePictFromIconAndLabel
OleMetafilePictFromIconAndLabel   QuickInfo

Creates a METAFILEPICT structure that contains a metafile in which the icon and label are drawn.

HGLOBAL OleMetafilePictFromIconAndLabel(

HICON hIcon,	//Handle to the icon to be drawn into the metafile
LPOLESTR lpszLabel,	//Points to the string to be used as the icon label
LPOLESTR lpszSourceFile,	//Points to the string that contains the path to the icon file
UINT iIconIndex	//Index of icon in lpszSourceFile
);
Parameters

hIcon

Handle to the icon that is to be drawn into the metafile.

lpszLabel

Points to the string to be used as the icon label.

lpszSourceFile

Points to the string that contains the path and filename of the icon file. This string can be obtained from the user or from the registration database.

iIconIndex

Provides the index to the icon within the lpszSourceFile file.

Return Value

HGLOBAL

Indicates the hGlobal returned is the handle to a METAFILEPICT structure containing the icon and label. The metafile uses the MM_ANISOTROPIC mapping mode.

See Also

OleGetIconOfClass, OleGetIconOfFile


OleNoteObjectVisible
OleNoteObjectVisible   QuickInfo

Increments or decrements an external reference that keeps the object in the running state.

STDAPI OleNoteObjectVisible(

LPUNKNOWN pUnknown,	//Points to an IUnknown instance
BOOL fVisible	//Indicates whether object is visible
);
Parameters

pUnknown

Points to an IUnknown instance for the object that is to be locked or unlocked.

fVisible

Indicates whether the object is visible. If TRUE, OLE holds the object visible and alive regardless of external or internal IUnknown::AddRef and IUnknown::Release operations; registrations; or revokes. If FALSE, OLE releases its hold and the object can be closed.

Return Values

S_OK

Indicates the object was successfully locked or unlocked.

E_OUTOFMEMORY

Indicates insufficient memory to perform the operation.

E_INVALIDARG

Indicates an invalid argument.

E_UNEXPECTED

Indicates an unexpected error.

Comments

The OleNoteObjectVisible function calls the CoLockObjectExternal function. It is provided as a separate function to reinforce the need to lock an object when it becomes visible to the user and to release the object when it becomes invisible. This creates a strong lock on behalf of the user to ensure that the object cannot be closed by its container while it is visible.

See Also

CoLockObjectExternal


OleQueryCreateFromData
OleQueryCreateFromData   QuickInfo

Checks whether a data object has one of the formats that would allow it to become an embedded object through a call to either the OleCreateFromData or OleCreateStaticFromData function.

STDAPI OleQueryCreateFromData(

IDataObject * pSrcDataObject	//Points to the data transfer object to be queried
);
Parameter

pSrcDataObject

Points to the data transfer object to be queried.

Return Values

S_OK

Indicates formats that support embedded-object creation are present.

S_FALSE

Indicates no formats are present that support either embedded- or static-object creation.

OLE_S_STATIC

Indicates formats that support static-object creation are present.

Comments

When an application retrieves a data transfer object through a call to the OleGetClipboard function, the application should call OleQueryCreateFromData as part of the process of deciding to enable or disable the Edit/Paste or Edit/Paste Special... commands. It tests for the presence of the following formats in the data object:

CF_EMBEDDEDOBJECT
CF_EMBEDSOURCE
cfFileName
CF_METAFILEPICT
CF_DIB
CF_BITMAP

Determining that the data object has one of these formats does not absolutely guarantee that the object creation will succeed, but is intended to help the process.

If OleQueryCreateFromData finds one of the CF_METAFILEPICT, CF_BITMAP, or CF_DIB formats and none of the other formats, it returns OLE_S_STATIC, indicating that you should call the OleCreateStaticFromData function to create the embedded object.

If OleQueryCreateFromData finds one of the other formats (CF_EMBEDDEDOBJECT, CF_EMBEDSOURCE, or cfFileName), even in combination with the static formats, it returns S_OK, indicating that you should call the OleCreateFromData function to create the embedded object.

See Also

OleCreateFromData, OleCreateStaticFromData, OleQueryLinkFromData


OleQueryLinkFromData
OleQueryLinkFromData   QuickInfo

The OleQueryLinkFromData function determines whether an OLE linked object (rather than an OLE embedded object) can be created from a clipboard data object.

STDAPI OleQueryLinkFromData(

IDataObject * pSrcDataObject	//Points to the clipboard data object to be used to create the new object
);
Parameter

pSrcDataObject

Points to the clipboard data object from which the object is to be created.

Return Value

Returns S_OK if the OleCreateLinkFromData function can be used to create the linked object; otherwise S_FALSE.

Comments

The OleQueryLinkFromData function is similar to the OleQueryCreateFromData function, but determines whether an OLE linked object (rather than an OLE embedded object) can be created from the clipboard data object. If the return value is S_OK, the application can then attempt to create the object with a call to OleCreateLinkFromData, although this is not guaranteed to create a link successfully.


OleRegGetUserType
OleRegGetUserType   QuickInfo

Returns from the registry the user type of the specified class. Developers of custom DLL object applications use this function to emulate the behavior of the OLE default handler.

HRESULT OleRegGetUserType(

REFCLSID clsid,	//Reference to the class identifier
DWORD dwFormOfType,	//Specifies form of type name
LPOLESTR * pszUserType	//Pointer to storage of string pointer
);
Parameters

clsid

Specifies the class whose user type is requested.

dwFormOfType

Specifies a value that describes the form of the user-presentable string from the enumeration USERCLASSTYPE.

pszUserType

Points to storage of the returned user type.

Return Values

S_OK

Indicates the user type was returned successfully.

E_OUTOFMEMORY

Indicates there is insufficient memory to complete the operation.

REGDB_E_CLASSNOTREG

Indicates there is no CLSID registered for the class object.

REGDB_E_READREGDB

Indicates there was an error reading the registry.

OLE_E_REGDB_KEY

Indicates the ProgID = MainUserTypeName and CLSID = MainUserTypeName keys are missing from the registry.

Comments

Object applications can ask OLE to get the user type name of a specified class in one of two ways. One way is to call OleRegGetUserType. The other is to return OLE_S_USEREG in response to calls by the default object handler to IOleObject::GetUserType. OLE_S_USEREG instructs the default handler to call OleRegGetUserType. Because DLL object applications cannot return OLE_S_USEREG, they must call OleRegGetUserType rather than delegating the job to the object handler.

The OleRegGetUserType function and its sibling functions, OleRegGetMiscStatus, OleRegEnumFormatEtc, and OleRegEnumVerbs, provide a way for developers of custom DLL object applications to emulate the behavior of OLE's default object handler in getting information about objects from the registry. By using these functions, you avoid the considerable work of writing your own, and the pitfalls inherent in working directly in the registry. In addition, you get future enhancements and optimizations of these functions without having to code them yourself.

See Also

IOleObject::GetUserType, OleRegGetMiscStatus, OleRegEnumFormatEtc, OleRegEnumVerbs, USERCLASSTYPE


OleRegGetMiscStatus
OleRegGetMiscStatus   QuickInfo

Returns from the registry miscellaneous information about the presentation and behaviors supported by the specified class. Used by developers of custom DLL object applications to emulate the behavior of the OLE default handler.

HRESULT OleRegGetMiscStatus(

REFCLSID clsid,	//Reference to class identifier
DWORD dwAspect,	//Value specifying aspect of requested class
DWORD * pdwStatus	//Pointer to returned status information
);
Parameters

clsid

Specifies the class whose status information is requested.

dwAspect

Specifies the aspect of the class whose information is requested.

pdwStatus

Points to storage of the returned status information.

Return Values

S_OK

Indicates the status information was returned successfully.

E_OUTOFMEMORY

Indicates there is insufficient memory to complete the operation.

REGDB_E_CLASSNOTREG

Indicates no CLSID is registered for the class object.

REGDB_E_READREGDB

Indicates an error occurred reading the registry.

OLE_E_REGDB_KEY

Indicates the GetMiscStatus key is missing from the registry.

Comments

Object applications can ask OLE to get miscellaneous status information in one of two ways. One way is to call OleRegGetMiscStatus. The other is to return OLE_S_USEREG in response to calls by the default object handler to IOleObject::GetMiscStatus. OLE_S_USEREG instructs the default handler to call OleRegGetMiscStatus. Because DLL object applications cannot return OLE_S_USEREG, they must call OleRegGetMiscStatus rather than delegating the job to the object handler.

OleRegGetMiscStatus and its sibling functions, OleRegGetUserType, OleRegEnumFormatEtc, and OleRegEnumVerbs, provide a way for developers of custom DLL object applications to emulate the behavior of OLE's default object handler in getting information about objects from the registry. By using these functions, you avoid the considerable work of writing your own, and the pitfalls inherent in working directly in the registry. In addition, you get future enhancements and optimizations of these functions without having to code them yourself.

See Also

DVASPECT, FORMATETC, OLEMISC, IOleObject::GetMiscStatus, OleRegEnumFormatEtc, OleRegEnumVerbs, OleRegGetUserType


OleRegEnumFormatEtc
OleRegEnumFormatEtc   QuickInfo

Enumerates data formats that an OLE object server has registered in the registration database. An object application or object handler calls this function to obtain an enumeration of those formats. Developers of custom DLL object applications use this function to emulate the behavior of the default object handler.

HRESULT OleRegEnumFormatEtc(

REFCLSID clsid,	//Reference to class identifier
DWORD dwDirection,	//Value specifying data formats
LPENUMFORMATETC * ppenumFormatetc	//Pointer to returned format information
);
Parameters

clsid

Specifies the class whose formats are being requested.

dwDirection

Specifies whether to enumerate formats that can be passed to IDataObject::GetData or formats that can be passed to IDataObject::SetData. Valid values are taken from the enumeration DATADIR.

ppenumFormatetc

Points to where to return the enumeration.

Return Values

S_OK

Indicates the enumerator was returned successfully.

E_OUTOFMEMORY

Indicates there is insufficient memory to complete the operation.

REGDB_E_CLASSNOTREG

Indicates there is no CLSID registered for the class object.

REGDB_E_READREGDB

Indicates there was an error reading the registry.

OLE_E_REGDB_KEY

Indicates the DataFormats/GetSet key is missing from the registry.

Comments

Object applications can ask OLE to enumerate supported data formats in one of two ways. One way is to call OleRegEnumFormatEtc. The other is to return OLE_S_USEREG in response to calls by the default object handler to IDataObject::EnumFormatEtc. OLE_S_USEREG instructs the default handler to call OleRegEnumFormatEtc. Because DLL object applications cannot return OLE_S_USEREG, they must call OleRegEnumFormatEtc rather than delegating the job to the object handler.

The OleRegEnumFormatEtc function and its sibling functions, OleRegGetUserType, OleRegGetMiscStatus, and OleRegEnumVerbs, provide a way for developers of custom DLL object applications to emulate the behavior of OLE's default object handler in getting information about objects from the registry. By using these functions, you avoid the considerable work of writing your own, and the pitfalls inherent in working directly in the registry. In addition, you get future enhancements and optimizations of these functions without having to code them yourself.

See Also

IDataObject::EnumFormatEtc


OleRegEnumVerbs
OleRegEnumVerbs   QuickInfo

Returns an enumeration of the registered verbs for the specified class. Developers of custom DLL object applications use this function to emulate the behavior of the default object handler.

HRESULT OleRegEnumVerbs(

REFCLSID clsid,	//Reference to class identifier
LPENUMOLEVERB * ppenumOleVerb	//Pointer to returned enumerator
);
Parameters

clsid

Specifies the class whose verbs are being requested.

ppenumOleVerb

Points to where to return the enumeration.

Return Values

S_OK

Indicates the enumerator was returned successfully.

E_OUTOFMEMORY

Indicates there is insufficient memory to complete the operation.

OLEOBJ_E_NOVERBS

Indicates no verbs are registered for the class.

REGDB_E_CLASSNOTREG

Indicates no CLSID is registered for the class object.

REGDB_E_READREGDB

Indicates an error occurred reading the registry.

OLE_E_REGDB_KEY

Indicates the DataFormats/GetSet key is missing from the registry.

Comments

Object applications can ask OLE to enumerate supported verbs in one of two ways. One way is to call OleRegEnumVerbs. The other way is to return OLE_S_USEREG in response to calls by the default object handler to IOleObject::EnumVerbs. OLE_S_USEREG instructs the default handler to call OleRegEnumVerbs. Because DLL object applications cannot return OLE_S_USEREG, they must call OleRegEnumVerbs rather than delegating the job to the object handler.

The OleRegEnumVerbs function and its sibling functions, OleRegGetUserType, OleRegGetMiscStatus, and OleRegEnumFormatEtc, provide a way for developers of custom DLL object applications to emulate the behavior of OLE's default object handler in getting information about objects from the registry. By using these functions, you avoid the considerable work of writing your own, and the pitfalls inherent in working directly in the registry. In addition, you get future enhancements and optimizations of these functions without having to code them yourself.

See Also

IOleObject::EnumVerbs


OleRun
OleRun   QuickInfo

Runs an object.

HRESULT OleRun(

LPUNKNOWN pUnknown	//Pointer to IUnknown interface
);
Parameter

pUnknown

Points to an object's IUnknown interface in order to obtain a pointer from the IRunnableObject interface in order to call Run.

Return Values

S_OK

Indicates the object was successfully placed in the running state.

OLE_E_CLASSDIFF

Indicates the source of an OLE link has been converted to a different class.

E_INVALIDARG

Indicates an argument is invalid.

E_UNEXPECTED

Indicates an unexpected error occurred.

Comments

The implementation of OleRun was changed in OLE 2.01 to coincide with the publication of the IRunnableObject interface. You can use OleRun and IRunnableObject::Run interchangeably. OleRun queries the object for a pointer to IRunnableObject. If successful, the function returns the results of calling the IRunnableObject::Run method.

Note  The implementation of OleRun in earlier versions of OLE differs from that described here.

For more information on using this function, see IRunnableObject::Run.

See Also

IOleLink::BindToSource, IRunnableObject::Run


OleSave
OleSave   QuickInfo

Saves an object opened in transacted mode into the specified storage object.

HRESULT OleSave(

IPersistStorage * pPS,	//Points to the object to be saved
IStorage * pStg,	//Points to the destination storage to which pPS is saved
BOOL fSameAsLoad	//Indicates whether the object was loaded from pstg or not
);
Parameters

pPS

Points to the object to be saved.

pStg

Points to the destination storage object to which pPS is to be saved.

fSameAsLoad

TRUE indicates that pStg is the same storage object from which the object was loaded or created; FALSE indicates that pstg was loaded or created from a different storage object.

Return Values

S_OK

Indicates the object was successfully saved.

STG_E_MEDIUMFULL

Indicates the object could not be saved due to lack of disk space.

See also the IPersistStorage::Save method for other error return values.

Comments

The OleSave helper function handles the common scenario in which an object is open in transacted mode and is to be saved into the specified storage object which uses the OLE-provided compound file implementation. Other scenarios can be handled with the IPersistStorage and IStorage interfaces directly.

The OleSave function does the following:

1.	Calls the IPersistStorage::GetClassID method to get the CLSID.

2.	Writes the CLSID to the storage object using the WriteClassStg function.

3.	Calls the IPersistStorage::Save method to save the object.

4.	If there were no errors on the save; calls the IPersistStorage::Commit method to commit the changes.

Note  Static objects are saved into a stream called CONTENTS. Static metafile objects get saved in "placeable metafile format" and static DIB data gets saved in "DIB file format." These formats are defined to be the OLE standards for metafile and DIB. All data transferred using an IStream interface or a file (that is; via IDataObject::GetDataHere) must be in these formats. Also; all objects whose default file format is a metafile or DIB must write their data into a CONTENTS stream using these standard formats.

See Also

IStorage, IPersistStorage


OleSaveToStream
OleSaveToStream   QuickInfo

Saves an IPersistStream object to the specified stream.

HRESULT OleSaveToStream(

IPersistStream * pPStm,	//Points to the object to be saved
IStream * pStm	//Points to the destination stream to which the object is saved
);
Parameters

pPStm

Points to the IPersistStorage object to be saved to the stream. Can be NULL, which has the effect of writing CLSID_NULL to the stream.

pStm

Points to the stream in which the object is to be saved.

Return Values

S_OK

Indicates the object was successfully saved.

STG_E_MEDIUMFULL

Indicates there is no space left on device to save the object.

See also the WriteClassStm function for other error return values.

See also the IPersistStream::Save method for other error return values.

Comments

This function simplifies saving an IPersistStream object to a stream. The object is saved preceded by its CLSID. The OleSaveToStream function performs the following steps:

1.	Calls the IPersistStream::GetClassID method to get the object's CLSID.

2.	Writes the CLSID to the stream with the WriteClassStm function.

3.	Calls the IPersistStream::Save method with fClearDirty set to TRUE. Note that this clears the dirty bit in the object.

See Also

OleLoadFromStream


OleSetAutoConvert
OleSetAutoConvert   QuickInfo

Tags an object for automatic conversion to a different class when the object is loaded.

HRESULT OleSetAutoConvert(

REFCLSID clsidOld,	//CLSID to be converted
REFCLSID clsidNew	//New CLSID after conversion
);
Parameters

clsidOld

Specifies the CLSID of the object class to be converted.

clsidNew

Specifies the CLSID of the object class that should replace clsidOld. This new CLSID replaces any existing auto-conversion information in the registration database for clsidOld. If this value is CLSID_NULL, any existing auto-conversion information for clsidOld is removed from the registration database.

Return Values

S_OK

Indicates the object was tagged successfully.

REGDB_E_CLASSNOTREG

Indicates the CLSID is not properly registered in the registration database.

REGDB_E_READREGDB

Indicates error reading from the registration database.

REGDB_E_WRITEREGDB

Indicates error writing to the registration database.

REGDB_E_KEYMISSING

Indicates cannot read a key from the registration database.

E_OUTOFMEMORY

Indicates the auto-conversion cannot be completed due to a lack of memory.

E_INVALIDARG

Indicates one or more arguments are invalid.

E_UNEXPECTED

Indicates an unexpected error occurred.

Comments

The OleSetAutoConvert function sets the entry for AutoConvertTo entry for clsidOld in the registration database. This function does no validation of whether an appropriate registration database entry for clsidNew currently exists. When it is called, the OleSetAutoConvert function records the new CLSID for the object under the AutoConvertTo subkey in the registration database for clsidOld.

Object conversion means that the object is permanently associated with a new CLSID. Automatic conversion is typically specified by the setup program for a new version of an object application, so that objects created by its older versions can be automatically updated. You can write the setup program to tag a class of objects for automatic conversion to a different class of objects.

For example, a new version of a spreadsheet application may need to convert spreadsheets that were created with earlier versions of the application. These earlier version spreadsheet objects have a different CLSID than the new version. The setup program for the new version of the spreadsheet application tags objects in the registration database that have the old CLSID so they are automatically updated when they are loaded.

When installing a new CLSID, setup programs may call OleSetAutoConvert for various clsidOld values for older versions of their applications. They also should call OleSetAutoConvert, specifying the new class as the clsidOld parameter, and setting the clsidNew parameter to CLSID_NULL to remove any existing conversion for the new class.

The OleSetAutoConvert function creates the required entry in the registration database. These entries appear in the registration database as subkeys of the CLSID key:

CLSID\{clsid}=MainUserTypeName\AutoConvertTo = clsid

See Also

OleDoAutoConvert


OleSetClipboard
OleSetClipboard   QuickInfo

Places the specified IDataObject instance on the clipboard making it accessible to the OleGetClipboard function.

HRESULT OleSetClipboard(

IDataObject * pDataObj	//The data object being copied or cut
);
Parameter

pDataObj

Points to an IDataObject instance from which the data to be placed on the clipboard can be obtained.  This parameter can be NULL; in which case the clipboard is emptied.

Return Values

S_OK

Indicates the IDataObject interface was placed on the clipboard.

CLIPBRD_E_CANT_OPEN

Indicates the Windows OpenClipboard function used within OleSetClipboard failed.

CLIPBRD_E_CANT_EMPTY

Indicates the Windows EmptyClipboard function used within OleSetClipboard failed.

CLIPBRD_E_CANT_CLOSE

Indicates the Windows CloseClipboard function used within OleSetClipboard failed.

Comments

If you are writing an application that can act as the source of a clipboard operation, you must:

1.	Create an instance of the IDataObject interface for the data being copied or cut to the clipboard. This IDataObject should be the same as the IDataObject used in OLE drag and drop operations.

2.	Call OleSetClipboard to place the IDataObject on the clipboard and make it accessible to the OleGetClipboard function. OleSetClipboard also calls the IUnknown::AddRef method on your data object.

3.	If you wish, release the IDataObject once you have placed it on the clipboard to free the IUnknown::AddRef counter in your application.

4.	If the user is cutting data to the clipboard, remove the data from the document.

All formats are offered on the clipboard using delayed rendering. The formats necessary for OLE 1 compatibility are synthesized from the OLE 2 formats that are present and are also put on the clipboard.

The OleSetClipboard function assigns ownership of the clipboard to an internal OLE window handle. The reference count of the data object is increased by 1.  This is done so that delayed rendering can be used. The reference count is decreased by a call to the OleFlushClipboard function or by a subsequent call to OleSetClipboard using NULL.

The OleSetClipboard function empties the current clipboard before any new data is made available. When an application opens the clipboard (either directly or indirectly by calling the Windows OpenClipboard function), the clipboard cannot be used by any other application until it is closed. If the clipboard is currently open by another application, OleSetClipboard fails. The internal OLE window handle satisfies WM_RENDERFORMAT messages by delegating them to the instance of IDataObject that is on the clipboard.

Passing NULL for IDataObject is legal and it empties the clipboard. If the contents of the clipboard are the result of a previous OleSetClipboard call and the clipboard is released; the IDataObject that was passed to the previous call is released.  The clipboard owner should use this as a signal that the data it previously offered is no longer on the clipboard.

If you need to leave the data on the clipboard after your application is closed, you can call OleFlushClipboard instead of OleSetClipboard using NULL.

See Also

OleGetClipboard, OleIsCurrentClipboard,


OleSetContainedObject
OleSetContainedObject   QuickInfo

Notifies an object that it is embedded in an OLE container, which ensures that reference counting is done correctly for containers that support links to embedded objects.

STDAPI OleSetContainedObject(

LPUNKNOWN pUnk	//Pointer to embedded object
BOOL fContained	//Indicates if the object is embedded
);
Parameters

pUnk

Specifies a pointer to the IUnknown interface of the object

fContained

Indicates TRUE if the object is an embedded object; FALSE otherwise.

Return Values

S_OK

Indicates object was notified successfully.

E_OUTOFMEMORY

Indicates insufficient memory to perform the operation.

E_INVALIDARG

Indicates an invalid argument.

E_UNEXPECTED

Indicates an unexpected error.

Comments

The implementation of OleSetContainedObject was changed in OLE 2.01 to coincide with the publication of the IRunnableObject interface. You can use OleSetContainedObject and the IRunnableObject::SetContainedObject method interchangeably. The OleSetContainedObject function queries the object for a pointer to the IRunnableObject interface. If successful, the function returns the results of calling IRunnableObject::SetContainedObject.

Note  The implementation of OleSetContainedObject in earlier versions of OLE differs from that described here.

See Also

IRunnableObject::SetContainedObject


OleSetMenuDescriptor
OleSetMenuDescriptor   QuickInfo

Installs or removes OLE dispatching code from the container's frame window.

HRESULT OleCreateMenuDescriptor(

HOLEMENU holemenu,	//Handle to the composite menu descriptor
HWND hwndFrame,	//Handle to the container's frame window
HWND hwndActiveObject,	//Handle to the object's in-place activation window
LPOLEINPLACEFRAME lpFrame,	//Container's frame window
LPOLEINPLACEACTIVEOBJECT lpActiveObj	//Active in-place object
);
Parameters

holemenu

Specifies the handle to the composite menu descriptor returned by the OleCreateMenuDescriptor function. If NULL, the dispatching code is unhooked.

hwndFrame

Specifies the handle to the container's frame window where the in-place composite menu is to be installed.

hwndActiveObject

Specifies the handle to the object's in-place activation window. OLE dispatches menu messages and commands to this window.

lpFrame

Points to the container's frame window.

lpActiveObj

Points to the active in-place object.

Return Values

S_OK

Indicates the menu was installed correctly.

E_INVALIDARG

Indicates one or more arguments are invalid.

E_UNEXPECTED

Indicates an unexpected error occurred.

E_FAIL

Indicates a Windows function call failed, indicating a resource allocation failure or improper arguments.

Comments

The container should call OleSetMenuDescriptor to install the dispatching code on hwndFrame when the object calls the IOleInPlaceFrame::SetMenu method, or to remove the dispatching code by passing NULL as the value for holemenu to OleSetMenuDescriptor.

OLE installs the context-sensitive help F1 message filter for the application if both the lpFrame and lpActiveObj parameters are non-NULL. Otherwise, the application must supply its own message filter.

See Also

OleCreateMenuDescriptor, IOleInPlaceFrame::SetMenu


OleTranslateAccelerator
OleTranslateAccelerator   QuickInfo

Called by the object application, allowing the container to translate its accelerators pointed to by lpFrameInfo.

HRESULT OleTranslateAccelertor(

LPOLEINPLACEFRAME lpFrame,	//Possible location to send keystrokes
LPOLEINPLACEFRAMEINFO lpFrameInfo,	//Accelerator table obtained from container
LPMSG lpmsg	//Structure containing the keystroke
);
Parameters

lpFrame

Points to the IOleInPlaceFrame interface where the keystroke might be sent.

lpFrameInfo

Points to an OLEINPLACEFRAMEINFO structure containing the accelerator table obtained from the container.

lpmsg

Points to an MSG structure containing the keystroke.

Return Values

S_OK

Indicates the keystroke was processed.

S_FALSE

Indicates the object should continue processing this message.

E_INVALIDARG

Indicates one of the arguments is invalid.

E_UNEXPECTED

Indicates an unexpected error occurred.

Comments

While an object is UI active, it always has first chance at translating any messages received. If the object does not want to translate the message, it calls OleTranslateAccelerator to give the container a chance. If the keyboard input matches an accelerator found in the container-provided accelerator table, OleTranslateAccelerator passes the message and its command identifier on to the container through the IOleInPlaceFrame::TranslateAccelerator method. This method returns S_OK if the keystroke is consumed; otherwise it returns S_FALSE.

The OleTranslateAccelerator function is intended to be called only by local server object applications and not by in-process server objects. In the case of a local server object application, keyboard input goes directly to the object application's message pump. If the object does not translate the key, OleTranslateAccelerator gives the container application an opportunity to do it. In the case of an in-process server object, the keyboard input goes directly to the container's message pump.

Note  Accelerator tables for containers should be defined so they will work properly with object applications that do their own accelerator keystroke translations. These tables should take the form:

"char", wID, VIRTKEY, CONTROL

This is the most common way to describe keyboard accelerators. Failure to do so can result in keystrokes being lost or sent to the wrong object during an in-place session.

Objects can call the IsAccelerator function to see whether the accelerator keystroke belongs to the object or the container.

See Also

IsAccelerator, IOleInPlaceFrame::TranslateAccelerator


OleUIAddVerbMenu

Adds the Verb menu for the specified object to the given menu.

BOOL OleUIAddVerbMenu(

LPOLEOBJECT *lpOleObj,	//Points to the selected object
LPCTSTR lpszShortType,	//The short name corresponding to the object
HMENU hMenu,	//The handle to the menu to modify
UINT uPos,	//The position of the menu item.
UINT uIDVerbMin,	//The value at which to start the verbs
UINT uIDVerbMax,	//The maximum ID value for object verbs
BOOL bAddConvert,	//Specifies whether to add convert item
UINT idConvert,	//The value to use for the convert item
HMENU FAR * lphMenu	//Points to the cascading verb menu, if created
);
Parameters

lpOleObj

The LPOLEOBJECT pointing to the selected object. If this is NULL, then a default disabled menu item is created.

lpszShortType

The LPTSTR with short type name (AuxName==2) corresponding to the lpOleObj. If the string is NOT known, then NULL may be passed. If NULL is passed, then IOleObject::GetUserType will be called to retrieve it. If the caller has easy access to the string, then it is faster to pass it in.

hMenu

The HMENU in which to make modifications.

uPos

The position of the menu item

iIDVerbMin

The UINT ID value at which to start the verbs.

uIDVerbMax

The UINT Maximum ID value to be used for object verbs. If uIDVerbMax is 0, then no maximum ID value is used.

bAddConvert

The BOOL specifying whether or not to add a Convert item to the bottom of the menu (preceded by a separator).

idConvert

The UINT ID value to use for the Convert menu item, if bAddConvert is TRUE.

lphMenu

The HMENU FAR * of the cascading verb menu if it's created. If there is only one verb, this will be filled with NULL.

Return Values

TRUE

Indicates lpOleObj was valid and at least one verb was added to the menu

FALSE

Indicates lpOleObj was NULL and a disabled default menu item was created.

Comments

If the object has one verb, the verb is added directly to the given menu. If the object has multiple verbs, a cascading sub-menu is created.


OleUIBusy

Invokes the standard Busy dialog box, allowing the user to manage concurrency.

UINT OleUIBusy(

LPOLEUIBUSY  lpBZ	//Points to the initialization structure
);
Parameter

lpBZ

Points to an OLEUIBUSY structure that contains information used to initialize the dialog box.

Return Values

Standard Success/Error Definitions

OLEUI_FALSE

Unknown failure (unused).

OLEUI_SUCCESS

No error, same as OLEUI_OK

OLEUI_OK

The user pressed theOK button.

OLEUI_CANCEL

Indicates that user has pressed the Cancel button and that the caller should cancel the operation.

OLEUI_BZ_SWITCHTOSELECTED

Indicates that the user has pressed Switch To and OleUIBusy was unable to determine how to switch to the blocking application. In this case, the caller should either take measures to attempt to resolve the conflict itself, if possible, or retry the operation. OleUIBusy will only return OLEUI_BZ_SWITCHTOSELECTED if the user has pressed the Switch To button, hTask is NULL and the BZ_NOTREESPONDING flag is set.

OLEUI_BZ_RETRYSELECTED

Indicates that the user has either pressed the Retry button or attempted to resolve the conflict (probably by switching to the blocking application). In this case, the caller should retry the operation.

OLEUI_BZ_CALLUNBLOCKED

Indicates that the dialog has been informed that the operation is no longer blocked.

Standard Field Validation Errors

OLEUI_ERR_STANDARDMIN

Errors common to all dialogs lie in the range OLEUI_ERR_STANDARDMIN to OLEUI_ERR_STANDARDMAX. This value allows the application to test for standard messages in order to display error messages to the user.

OLEUI_ERR_STRUCTURENULL

The pointer to an OLEUIXXX structure passed into the function was NULL.

OLEUI_ERR_STRUCTUREINVALID

Insufficient permissions for read or write access to an OLEUIXXX structure.

OLEUI_ERR_CBSTRUCTINCORRECT

The cbstruct value is incorrect.

OLEUI_ERR_HWNDOWNERINVALID

The hWndOwner value is invalid.

OLEUI_ERR_LPSZCAPTIONINVALID

The lpszCaption value is invalid.

OLEUI_ERR_LPFNHOOKINVALID

The lpfnHook value is invalid.

OLEUI_ERR_HINSTANCEINVALID

The hInstance value is invalid.

OLEUI_ERR_LPSZTEMPLATEINVALID

The lpszTemplate value is invalid.

OLEUI_ERR_HRESOURCEINVALID

The hResource value is invalid.

Initialization Errors

OLEUI_ERR_FINDTEMPLATEFAILURE

Unable to find the dialog template.

OLEUI_ERR_LOADTEMPLATEFAILURE

Unable to load the dialog template.

OLEUI_ERR_DIALOGFAILURE

Dialog initialization failed.

OLEUI_ERR_LOCALMEMALLOC

A call to LocalAlloc or the standard IMalloc allocator failed.

OLEUI_ERR_GLOBALMEMALLOC

A call to GlobalAlloc or the standard IMalloc allocator failed.

OLEUI_ERR_LOADSTRING

Unable to LoadString localized resources from the library.

OLEUI_ERR_OLEMEMALLOC

A call to the standard IMalloc allocator failed.

Function Specific Errors

OLEUI_ERR_STANDARDMAX

Errors common to all dialogs lie in the range OLEUI_ERR_STANDARDMIN to OLEUI_ERR_STANDARDMAX. This value allows the application to test for standard messages in order to display error messages to the user.

OLEUI_BZERR_HTASKINVALID

The hTask specified in the hTask member of the OLEUIBUSY structure is invalid.

Comments

The standard OLE Server Busy dialog box notifies the user that the server application is not receiving messages. The dialog then asks the user to either cancel the operation, switch to the task which is blocked, or continue waiting.

See Also

OLEUIBUSY


OleUICanConvertOrActivateAs

Determines if there are any OLE object classes in the registry that can be used to convert or activate the specified CLSID from.

BOOL OleUICanConvertOrActivateAs(

REFCLSID rClsid,	//CLSID of the specified class
BOOL fIsLinkedObject,	//Indicates whether the original object was a linked object
WORD wFormat	//The format of the original class
);
Parameters

rClsid

Points to the CLSID of the specified class.

fIsLinkedObject

TRUE if the original object is a linked object; FALSE otherwise.

wFormat

Specifies the format of the original class.

Return Values

TRUE

The specified class can be converted to or activated as another class.

FALSE

The specified class cannot be converted to or activated as another class.

Comments

Notes to Implementors

OleUICanConvertOrActivateAs searches the Registry for classes that include wFormat in their \Conversion\Readable\Main, \Conversion\ReadWriteable\Main, and \DataFormats\DefaultFile entries.

This function is useful for determining if a Convert... menu item should be disabled. If the CF_DISABLEDISPLAYASICON flag is specified in the call to OleUIConvert, then the Convert... menu item should be enabled only if OleUICanConvertOrActivateAs returns TRUE.

See Also

OleUIConvert


OleUIChangeIcon

Invokes the standard Change Icon dialog box, which allows the user to select an icon from an icon file, executable, or DLL.

UINT OleUIChangeIcon(

LPOLEUICHANGEICON lpCI	//Points to the in-out structure for this dialog
);
Parameter

lpCI

Points to the in-out structure for this dialog.

Return Values

Standard Success/Error Definitions

OLEUI_FALSE

Unknown failure (unused).

OLEUI_SUCCESS

No error, same as OLEUI_OK

OLEUI_OK

The user pressed the OK button.

OLEUI_CANCEL

The user pressed the Cancel button.

Standard Field Validation Errors

OLEUI_ERR_STANDARDMIN

Errors common to all dialogs lie in the range OLEUI_ERR_STANDARDMIN to OLEUI_ERR_STANDARDMAX. This value allows the application to test for standard messages in order to display error messages to the user.

OLEUI_ERR_STRUCTURENULL

The pointer to an OLEUIXXX structure passed into the function was NULL.

OLEUI_ERR_STRUCTUREINVALID

Insufficient permissions for read or write access to an OLEUIXXX structure.

OLEUI_ERR_CBSTRUCTINCORRECT

The cbstruct value is incorrect.

OLEUI_ERR_HWNDOWNERINVALID

The hWndOwner value is invalid.

OLEUI_ERR_LPSZCAPTIONINVALID

The lpszCaption value is invalid.

OLEUI_ERR_LPFNHOOKINVALID

The lpfnHook value is invalid.

OLEUI_ERR_HINSTANCEINVALID

The hInstance value is invalid.

OLEUI_ERR_LPSZTEMPLATEINVALID

The lpszTemplate value is invalid.

OLEUI_ERR_HRESOURCEINVALID

The hResource value is invalid.

Initialization Errors

OLEUI_ERR_FINDTEMPLATEFAILURE

Unable to find the dialog template.

OLEUI_ERR_LOADTEMPLATEFAILURE

Unable to load the dialog template.

OLEUI_ERR_DIALOGFAILURE

Dialog initialization failed.

OLEUI_ERR_LOCALMEMALLOC

A call to LocalAlloc or the standard IMalloc allocator failed.

OLEUI_ERR_GLOBALMEMALLOC

A call to GlobalAlloc or the standard IMalloc allocator failed.

OLEUI_ERR_LOADSTRING

Unable to LoadString localized resources from the library.

OLEUI_ERR_OLEMEMALLOC

A call to the standard IMalloc allocator failed.

Function Specific Errors

OLEUI_ERR_STANDARDMAX

Errors common to all dialogs lie in the range OLEUI_ERR_STANDARDMIN to OLEUI_ERR_STANDARDMAX. This value allows the application to test for standard messages in order to display error messages to the user.

OLEUI_CIERR_MUSTHAVECLSID

The clsid member was not the current CLSID.

OLEUI_CIERR_MUSTHAVECURRENTMETAFILE

The hMetaPict member was not the current metafile.

OLEUI_CIERR_SZICONEXEINVALID

The szIconExe value was invalid.

Comment

OleUIChangeIcon uses information contained in the OLEUICHANGEICON structure.

See Also

OLEUICHANGEICON


OleUIChangeSource

Invokes the Change Source dialog box, allowing the user to change the source of a link.

UINT OleUIChangeSource(

LPOLEUICHANGESOURCE lpCS	//Points to the in-out structure
);
Parameter

lpCS

Points to the in-out structure for this dialog.

Return Values

Standard Success/Error Definitions

OLEUI_FALSE

Unknown failure (unused).

OLEUI_SUCCESS

No error, same as OLEUI_OK.

OLEUI_OK

The user pressed the OK button.

OLEUI_CANCEL

The user pressed the Cancel button.

Standard Field Validation Errors

OLEUI_ERR_STANDARDMIN

Errors common to all dialogs lie in the range OLEUI_ERR_STANDARDMIN to OLEUI_ERR_STANDARDMAX. This value allows the application to test for standard messages in order to display error messages to the user.

OLEUI_ERR_STRUCTURENULL

The pointer to an OLEUIXXX structure passed into the function was NULL.

OLEUI_ERR_STRUCTUREINVALID

Insufficient permissions for read or write access to an OLEUIXXX structure.

OLEUI_ERR_CBSTRUCTINCORRECT

The cbstruct value is incorrect.

OLEUI_ERR_HWNDOWNERINVALID

The hWndOwner value is invalid.

OLEUI_ERR_LPSZCAPTIONINVALID

The lpszCaption value is invalid.

OLEUI_ERR_LPFNHOOKINVALID

The lpfnHook value is invalid.

OLEUI_ERR_HINSTANCEINVALID

The hInstance value is invalid.

OLEUI_ERR_LPSZTEMPLATEINVALID

The lpszTemplate value is invalid.

OLEUI_ERR_HRESOURCEINVALID

The hResource value is invalid.

Initialization Errors

OLEUI_ERR_FINDTEMPLATEFAILURE

Unable to find the dialog template.

OLEUI_ERR_LOADTEMPLATEFAILURE

Unable to load the dialog template.

OLEUI_ERR_DIALOGFAILURE

Dialog initialization failed.

OLEUI_ERR_LOCALMEMALLOC

A call to LocalAlloc or the standard IMalloc allocator failed.

OLEUI_ERR_GLOBALMEMALLOC

A call to GlobalAlloc or the standard IMalloc allocator failed.

OLEUI_ERR_LOADSTRING

Unable to LoadString localized resources from the library.

OLEUI_ERR_OLEMEMALLOC

A call to the standard IMalloc allocator failed.

Function Specific Errors

OLEUI_ERR_STANDARDMAX

Errors common to all dialogs lie in the range OLEUI_ERR_STANDARDMIN to OLEUI_ERR_STANDARDMAX. This value allows the application to test for standard messages in order to display error messages to the user.

OLEUI_CSERR_LINKCNTRNULL

The lpOleUILinkContainer value is NULL.

OLEUI_CSERR_LINKCNTRINVALID

The lpOleUILinkContainer value is invalid.

OLEUI_CSERR_FROMNOTNULL

The lpszFrom value is not NULL.

OLEUI_CSERR_TONOTNULL

The lpszTo value is not NULL.

OLEUI_CSERR_SOURCEINVALID

The lpszDisplayName or nFileLength value is invalid, or cannot retrieve the link source.

OLEUI_CSERR_SOURCEPARSEERROR

The nFilename value is wrong.

Comments

The link source is not changed by the Change Source dialog itself. Instead, it is up to the caller to change the link source using the returned file and item strings. The Edit Links dialog typically does this for the caller.

See Also

OLEUICHANGESOURCE, OleUIEditLinks, IOleUILinkContainer


OleUIConvert

Invokes the standard Convert dialog box, allowing the user to change the type of a single specified object, or the type of all OLE objects of the specified object's class.

UINT OleUIConvert(

LPOLEUICONVERT lpCV	//Points to initialization structure
);
Parameter

lpCV

Points to an OLEUICONVERT structure that contains information used to initialize the dialog box.

Return Values

Standard Success/Error Definitions

OLEUI_FALSE

Unknown failure (unused).

OLEUI_SUCCESS

No error, same as OLEUI_OK

OLEUI_OK

The user pressed the OK button.

OLEUI_CANCEL

The user pressed the Cancel button.

Standard Field Validation Errors

OLEUI_ERR_STANDARDMIN

Errors common to all dialogs lie in the range OLEUI_ERR_STANDARDMIN to OLEUI_ERR_STANDARDMAX. This value allows the application to test for standard messages in order to display error messages to the user.

OLEUI_ERR_STRUCTURENULL

The pointer to an OLEUIXXX structure passed into the function was NULL.

OLEUI_ERR_STRUCTUREINVALID

Insufficient permissions for read or write access to an OLEUIXXX structure.

OLEUI_ERR_CBSTRUCTINCORRECT

The cbstruct value is incorrect.

OLEUI_ERR_HWNDOWNERINVALID

The hWndOwner value is invalid.

OLEUI_ERR_LPSZCAPTIONINVALID

The lpszCaption value is invalid.

OLEUI_ERR_LPFNHOOKINVALID

The lpfnHook value is invalid.

OLEUI_ERR_HINSTANCEINVALID

The hInstance value is invalid.

OLEUI_ERR_LPSZTEMPLATEINVALID

The lpszTemplate value is invalid.

OLEUI_ERR_HRESOURCEINVALID

The hResource value is invalid.

Initialization Errors

OLEUI_ERR_FINDTEMPLATEFAILURE

Unable to find the dialog template.

OLEUI_ERR_LOADTEMPLATEFAILURE

Unable to load the dialog template.

OLEUI_ERR_DIALOGFAILURE

Dialog initialization failed.

OLEUI_ERR_LOCALMEMALLOC

A call to LocalAlloc or the standard IMalloc allocator failed.

OLEUI_ERR_GLOBALMEMALLOC

A call to GlobalAlloc or the standard IMalloc allocator failed.

OLEUI_ERR_LOADSTRING

Unable to LoadString localized resources from the library.

OLEUI_ERR_OLEMEMALLOC

A call to the standard IMalloc allocator failed.

Function Specific Errors

OLEUI_ERR_STANDARDMAX

Errors common to all dialogs lie in the range OLEUI_ERR_STANDARDMIN to OLEUI_ERR_STANDARDMAX. This value allows the application to test for standard messages in order to display error messages to the user.

OLEUI_CTERR_CLASSIDINVALID

A clsid value was invalid.

OLEUI_CTERR_DVASPECTINVALID

The dvAspect value was invalid. This member specifies the aspect of the object.

OLEUI_CTERR_CBFORMATINVALID

The wFormat value was invalid. This member specifies the data format of the object.

OLEUI_CTERR_STRINGINVALID

A string value (for example, lpszUserType or lpszDefLabel) was invalid.

Comments

OleUIConvert populates the Convert dialog's listbox with object classes by traversing the Registry and looking for entries in the Readable and ReadWritable keys. Every class that includes the original class' default file format in its Readable key is added to the Convert list, and every class that includes the original class' default file format in its ReadWritable key is added to the Activate As list. The Convert list is shown in the dialog's listbox when the Convert radio button is selected (the default selection), and the Activate As list is shown when Activate As is selected.

Note that you can change the type of all objects of a given class only when CF_CONVERTONLY is not specified.

The convert command, which invokes this function, should only be made available to the user if OleUIConvertOrActivateAs returns S_OK.

See Also

OLEUICONVERT, OleUICanConvertOrActivateAs


OleUIEditLinks

Invokes the standard Links dialog box, allowing the user to make modifications to a container's linked objects.

UINT OleUIEditLinks(

LPOLEUIEDITLINKS lpEL	//Points to the initialization structure
);
Parameter

lpEL

Points to an OLEUIEDITLINKS structure that contains information used to initialize the dialog box.

Return Value

Standard Success/Error Definitions

OLEUI_FALSE

Unknown failure (unused).

OLEUI_SUCCESS

No error, same as OLEUI_OK.

OLEUI_OK

The user pressed the OK button.

OLEUI_CANCEL

The user pressed the Cancel button.

Standard Field Validation Errors

OLEUI_ERR_STANDARDMIN

Errors common to all dialogs lie in the range OLEUI_ERR_STANDARDMIN to OLEUI_ERR_STANDARDMAX. This value allows the application to test for standard messages in order to display error messages to the user.

OLEUI_ERR_STRUCTURENULL

The pointer to an OLEUIXXX structure passed into the function was NULL.

OLEUI_ERR_STRUCTUREINVALID

Insufficient permissions for read or write access to an OLEUIXXX structure.

OLEUI_ERR_CBSTRUCTINCORRECT

The cbstruct value is incorrect.

OLEUI_ERR_HWNDOWNERINVALID

The hWndOwner value is invalid.

OLEUI_ERR_LPSZCAPTIONINVALID

The lpszCaption value is invalid.

OLEUI_ERR_LPFNHOOKINVALID

The lpfnHook value is invalid.

OLEUI_ERR_HINSTANCEINVALID

The hInstance value is invalid.

OLEUI_ERR_LPSZTEMPLATEINVALID

The lpszTemplate value is invalid.

OLEUI_ERR_HRESOURCEINVALID

The hResource value is invalid.

Initialization Errors

OLEUI_ERR_FINDTEMPLATEFAILURE

Unable to find the dialog template.

OLEUI_ERR_LOADTEMPLATEFAILURE

Unable to load the dialog template.

OLEUI_ERR_DIALOGFAILURE

Dialog initialization failed.

OLEUI_ERR_LOCALMEMALLOC

A call to LocalAlloc or the standard IMalloc allocator failed.

OLEUI_ERR_GLOBALMEMALLOC

A call to GlobalAlloc or the standard IMalloc allocator failed.

OLEUI_ERR_LOADSTRING

Unable to LoadString localized resources from the library.

OLEUI_ERR_OLEMEMALLOC

A call to the standard IMalloc allocator failed.

Function Specific Errors

OLEUI_ERR_STANDARDMAX

Errors common to all dialogs lie in the range OLEUI_ERR_STANDARDMIN to OLEUI_ERR_STANDARDMAX. This value allows the application to test for standard messages in order to display error messages to the user.

See Also

OLEUIEDITLINKS, IOleUILinkContainer


OleUIInsertObject

Invokes the standard Insert Object dialog box, which allows the user to select an object source and class name, as well as the option of displaying the object as itself or as an icon.

UINT OleUIInsertObject(

LPOLEUIINSERTOBJECT lpIO	//Points to the in-out structure
);
Parameter

lpIO

Points to the in-out structure for this dialog.

Return Values

Standard Success/Error Definitions

OLEUI_FALSE

Unknown failure (unused).

OLEUI_SUCCESS

No error, same as OLEUI_OK.

OLEUI_OK

The user pressed the OK button.

OLEUI_CANCEL

The user pressed the Cancel button.

Standard Field Validation Errors

OLEUI_ERR_STANDARDMIN

Errors common to all dialogs lie in the range OLEUI_ERR_STANDARDMIN to OLEUI_ERR_STANDARDMAX. This value allows the application to test for standard messages in order to display error messages to the user.

OLEUI_ERR_STRUCTURENULL

The pointer to an OLEUIXXX structure passed into the function was NULL.

OLEUI_ERR_STRUCTUREINVALID

Insufficient permissions for read or write access to an OLEUIXXX structure.

OLEUI_ERR_CBSTRUCTINCORRECT

The cbstruct value is incorrect.

OLEUI_ERR_HWNDOWNERINVALID

The hWndOwner value is invalid.

OLEUI_ERR_LPSZCAPTIONINVALID

The lpszCaption value is invalid.

OLEUI_ERR_LPFNHOOKINVALID

The lpfnHook value is invalid.

OLEUI_ERR_HINSTANCEINVALID

The hInstance value is invalid.

OLEUI_ERR_LPSZTEMPLATEINVALID

The lpszTemplate value is invalid.

OLEUI_ERR_HRESOURCEINVALID

The hResource value is invalid.

Initialization Errors

OLEUI_ERR_FINDTEMPLATEFAILURE

Unable to find the dialog template.

OLEUI_ERR_LOADTEMPLATEFAILURE

Unable to load the dialog template.

OLEUI_ERR_DIALOGFAILURE

Dialog initialization failed.

OLEUI_ERR_LOCALMEMALLOC

A call to LocalAlloc or the standard IMalloc allocator failed.

OLEUI_ERR_GLOBALMEMALLOC

A call to GlobalAlloc or the standard IMalloc allocator failed.

OLEUI_ERR_LOADSTRING

Unable to LoadString localized resources from the library.

OLEUI_ERR_OLEMEMALLOC

A call to the standard IMalloc allocator failed.

Function Specific Errors

OLEUI_ERR_STANDARDMAX

Errors common to all dialogs lie in the range OLEUI_ERR_STANDARDMIN to OLEUI_ERR_STANDARDMAX. This value allows the application to test for standard messages in order to display error messages to the user.

OLEUI_IOERR_LPSZFILEINVALID

The lpszFile value is invalid or user has insufficient write access permissions.. This lpszFile member points to the name of the file linked to or inserted.

OLEUI_IOERR_LPFORMATETCINVALID

The lpFormatEtc value is invalid. This member identifies the desired format.

OLEUI_IOERR_PPVOBJINVALID

The ppvOjb value is invalid. This member points to the location where the pointer for the object is returned.

OLEUI_IOERR_LPIOLECLIENTSITEINVALID

The lpIOleClientSite value is invalid. This member points to the client site for the object.

OLEUI_IOERR_LPISTORAGEINVALID

The lpIStorage value is invalid. This member points to the storage to be used for the object.

OLEUI_IOERR_SCODEHASERROR

The sc member of lpIO has additional error information.

OLEUI_IOERR_LPCLSIDEXCLUDEINVALID

The lpClsidExclude value is invalid. This member contains the list of CLSIDs to exclude.

OLEUI_IOERR_CCHFILEINVALID

The cchFile or lpszFile value is invalid. The cchFile member specifies the size of the lpszFile buffer. The lpszFile  member points to the name of the file linked to or inserted.

Comments

OleUIInsertObject allows the user to select the type of object to be inserted from a listbox containing the object applications registered on the user's system. To populate that listbox, OleUIInsertObject traverses the registry, adding every object server it finds that meets the following criteria:

•	The registry entry does not include the NotInsertable key.

•	The registry entry includes a OLE 1.0 style Protocol\\StdFileEditing\\Server key.

•	The registry entry includes the Insertable key.

•	The object's CLSID is not included in the list of objects to exclude (the lpClsidExclude member of OLEUIINSERTOBJECT).

By default, OleUIInsertObject does not validate object servers; however, if the IOF_VERIFYSERVEREXIST flag is included in the dwFlags member of the OLEUIINSERTOBJECT structure, then OleUIInsertObject verifies that the server exists. If it does not exist, then the server's object is not added to the list of available objects. Server validation is a time-extensive operation and is a significant performance factor.

To free an HMETAFILEPICT returned from the Insert Object or Paste Special dialog box, delete the attached metafile on the handle, as follows:

void FreeHmetafilepict(HMETAFILEPICT hmfp)

{

    if (hmfp != NULL)

        {

        LPMETAFILEPICT pmfp = GlobalLock(hmfp);

        DeleteMetaFile(pmfp->hMF);

        GlobalUnlock(hmfp);

        GlobalFree(hmfp);

        }

}  // FreeHmetafilepict

See Also

OLEUIINSERTOBJECT

OpenFile DeleteMetaFile, GlobalUnlock, GlobalFree in Win32


OleUIObjectProperties

Invokes the Object Properties dialog, which displays General, View, Link information about an object.

UINT OleUIObjectProperties(

LPOLEUIOBJECTPROPS lpOP	//Points to the OLEUIOBJECTPROPS structure
);
ParameterlpOP

Points to the OLEUIOBJECTPROPS structure.

Return Values

Standard Success/Error Definitions

OLEUI_FALSE

Unknown failure (unused).

OLEUI_SUCCESS

No error, same as OLEUI_OK.

OLEUI_OK

The user pressed the OK button.

OLEUI_CANCEL

The user pressed the Cancel button.

Standard Field Validation Errors

OLEUI_ERR_STANDARDMIN

Errors common to all dialogs lie in the range OLEUI_ERR_STANDARDMIN to OLEUI_ERR_STANDARDMAX. This value allows the application to test for standard messages in order to display error messages to the user.

OLEUI_ERR_STRUCTURENULL

The pointer to an OLEUIXXX structure passed into the function was NULL.

OLEUI_ERR_STRUCTUREINVALID

Insufficient permissions for read or write access to an OLEUIXXX structure.

OLEUI_ERR_CBSTRUCTINCORRECT

The cbstruct value is incorrect.

OLEUI_ERR_HWNDOWNERINVALID

The hWndOwner value is invalid.

OLEUI_ERR_LPSZCAPTIONINVALID

The lpszCaption value is invalid.

OLEUI_ERR_LPFNHOOKINVALID

The lpfnHook value is invalid.

OLEUI_ERR_HINSTANCEINVALID

The hInstance value is invalid.

OLEUI_ERR_LPSZTEMPLATEINVALID

The lpszTemplate value is invalid.

OLEUI_ERR_HRESOURCEINVALID

The hResource value is invalid.

Initialization Errors

OLEUI_ERR_FINDTEMPLATEFAILURE

Unable to find the dialog template.

OLEUI_ERR_LOADTEMPLATEFAILURE

Unable to load the dialog template.

OLEUI_ERR_DIALOGFAILURE

Dialog initialization failed.

OLEUI_ERR_LOCALMEMALLOC

A call to LocalAlloc or the standard IMalloc allocator failed.

OLEUI_ERR_GLOBALMEMALLOC

A call to GlobalAlloc or the standard IMalloc allocator failed.

OLEUI_ERR_LOADSTRING

Unable to LoadString localized resources from the library.

OLEUI_ERR_OLEMEMALLOC

A call to the standard IMalloc allocator failed.

Function Specific Errors

OLEUI_ERR_STANDARDMAX

Errors common to all dialogs lie in the range OLEUI_ERR_STANDARDMIN to OLEUI_ERR_STANDARDMAX. This value allows the application to test for standard messages in order to display error messages to the user.

OLEUI_OPERR_SUBPROPNULL

lpGP or lpVP is NULL, or dwFlags and OPF_OBJECTISLINK and lpLP are NULL.

OLEUI_OPERR_SUBPROPINVALID

Insufficient write-access permissions for the structures pointed to by lpGP, lpVP, or lpLP.

OLEUI_OPERR_PROPSHEETNULL

The lpLP value is NULL.

OLEUI_OPERR_PROPSHEETINVALID

Insufficient write-access for one or more of the structures used by OLEUIOBJECTPROPS.

OLEUI_OPERR_SUPPROP

The sub-link property pointer, lpLP, is NULL.

OLEUI_OPERR_PROPSINVALID

Insufficient write access for the sub-link property pointer, lpLP.

OLEUI_OPERR_PAGESINCORRECT

Some sub-link properties of the lpPS member are incorrect.

OLEUI_OPERR_INVALIDPAGES

Some sub-link properties of the lpPS member are incorrect.

OLEUI_OPERR_NOTSUPPORTED

A sub-link property of the lpPS member is incorrect.

OLEUI_OPERR_DLGPROCNOTNULL

A sub-link property of the lpPS member is incorrect.

OLEUI_OPERR_LPARAMNOTZERO

A sub-link property of the lpPS member is incorrect.

OLEUI_GPERR_STRINGINVALID

A string value (for example, lplpszLabel or lplpszType) is invalid.

OLEUI_GPERR_CLASSIDINVALID

The clsid value is invalid.

OLEUI_GPERR_LPCLSIDEXCLUDEINVALID

The ClsidExcluded value is invalid.

OLEUI_GPERR_CBFORMATINVALID

The wFormat value is invalid.

OLEUI_VPERR_METAPICTINVALID

The hMetaPict value is invalid.

OLEUI_VPERR_DVASPECTINVALID

The dvAspect value is invalid.

OLEUI_OPERR_PROPERTYSHEET

The lpPS value is incorrect.

OLEUI_OPERR_OBJINFOINVALID

The lpObjInfo value is NULL or the calling process doesn't have read access.

OLEUI_OPERR_LINKINFOINVALID

The lpLinkInfo value is NULL or the calling process doesn't have read access.

Comment

OleUIObjectProperties is passed an OLEUIOBJECTPROPS structure, which supplies the information needed to fill in the General, View, and Link tabs of the Object Properties dialog.

See Also

IOleUIObjInfo, IOleUILinkInfo, OLEUIOBJECTPROPS, OLEUIGNRLPROPS, OLEUIVIEWPROPS, OLEUILINKPROPS


OleUIPasteSpecial

Invokes the standard Paste Special dialog box, allowing the user to select the format of the clipboard object to be pasted or paste-linked.

UINT OleUIPasteSpecial(*

LPOLEUIPASTESPECIAL lpPS	//In-out structure for this dialog
);
Parameter

lpPS

LPOLEUIPASTESPECIAL pointing to the in-out structure for this dialog.

Return Values

Standard Success/Error Definitions

OLEUI_FALSE

Unknown failure (unused).

OLEUI_SUCCESS

No error, same as OLEUI_OK

OLEUI_OK

The user pressed the OK button.

OLEUI_CANCEL

The user pressed the Cancel button.

Standard Field Validation Errors

OLEUI_ERR_STANDARDMIN

Errors common to all dialogs lie in the range OLEUI_ERR_STANDARDMIN to OLEUI_ERR_STANDARDMAX. This value allows the application to test for standard messages in order to display error messages to the user.

OLEUI_ERR_STRUCTURENULL

The pointer to an OLEUIXXX structure passed into the function was NULL.

OLEUI_ERR_STRUCTUREINVALID

Insufficient permissions for read or write access to an OLEUIXXX structure.

OLEUI_ERR_CBSTRUCTINCORRECT

The cbstruct value is incorrect.

OLEUI_ERR_HWNDOWNERINVALID

The hWndOwner value is invalid.

OLEUI_ERR_LPSZCAPTIONINVALID

The lpszCaption value is invalid.

OLEUI_ERR_LPFNHOOKINVALID

The lpfnHook value is invalid.

OLEUI_ERR_HINSTANCEINVALID

The hInstance value is invalid.

OLEUI_ERR_LPSZTEMPLATEINVALID

The lpszTemplate value is invalid.

OLEUI_ERR_HRESOURCEINVALID

The hResource value is invalid.

Initialization Errors

OLEUI_ERR_FINDTEMPLATEFAILURE

Unable to find the dialog template.

OLEUI_ERR_LOADTEMPLATEFAILURE

Unable to load the dialog template.

OLEUI_ERR_DIALOGFAILURE

Dialog initialization failed.

OLEUI_ERR_LOCALMEMALLOC

A call to LocalAlloc or the standard IMalloc allocator failed.

OLEUI_ERR_GLOBALMEMALLOC

A call to GlobalAlloc or the standard IMalloc allocator failed.

OLEUI_ERR_LOADSTRING

Unable to LoadString localized resources from the library.

OLEUI_ERR_OLEMEMALLOC

A call to the standard IMalloc allocator failed.

Function Specific Errors

OLEUI_ERR_STANDARDMAX

Errors common to all dialogs lie in the range OLEUI_ERR_STANDARDMIN to OLEUI_ERR_STANDARDMAX. This value allows the application to test for standard messages in order to display error messages to the user.

OLEUI_IOERR_SRCDATAOBJECTINVALID

The lpSrcDataObject field of OLEUIPASTESPECIAL is invalid

OLEUI_IOERR_ARRPASTEENTRIESINVALID

The arrPasteEntries field of OLEUIPASTESPECIAL is invalid.

OLEUI_IOERR_ARRLINKTYPESINVALID

The arrLinkTypes field of OLEUIPASTESPECIAL is invalid

OLEUI_PSERR_CLIPBOARDCHANGED

The clipboard contents changed while the dialog was displayed.

OLEUI_PSERR_GETCLIPBOAARDFAILED

The lpSrcDataObj member is incorrect.

Comments

The design of the paste special dialog assumes the following: if you are willing to permit a user to link to an object, you are also willing to permit the user to embed that object. For this reason, if any of the OLEUIPASTE_LINKTYPE flags associated with the OLEUIPASTEFLAG enumeration are set, then the OLEUIPASTE_PASTE flag must also be set in order for the data formats to appear in the paste special box.

To free an HMETAFILEPICT returned from the Insert Object or Paste Special dialog box, delete the attached metafile on the handle, as follows:

void FreeHmetafilepict(HMETAFILEPICT hmfp)

{

    if (hmfp != NULL)

        {

        LPMETAFILEPICT pmfp = GlobalLock(hmfp);

        DeleteMetaFile(pmfp->hMF);

        GlobalUnlock(hmfp);

        GlobalFree(hmfp);

        }

}  // FreeHmetafilepict

See Also

OLEUIPASTESPECIAL, OLEUIPASTEFLAG

DeleteMetaFile, GlobalUnlock, GlobalFree in Win32


OleUIPromptUser

Displays a dialog box with the specified template and returns the response (button id) from the user. This function is used to display OLE warning messages, for example, Class Not Registered.

int __export FAR CDECLOleUIPromtUser(

int nTemplate,	//Resource number of dialog
HWND hwndParent	//Link identifier
);
Parameters

nTemplate

Specifies the resource number of the dialog to display. See Comments.

hwndParent

The parent of the dialog box. Specifies zero or more optional arguments. These parameters are passed to wsprintf to format the message string.

Return Value

Returns the button id selected by the user (template dependent).

Standard Success/Error Definitions

OLEUI_FALSE

Unknown failure (unused).

OLEUI_SUCCESS

No error, same as OLEUI_OK

OLEUI_OK

The user pressed the OK button.

OLEUI_CANCEL

The user pressed the Cancel button.

Standard Field Validation Errors

OLEUI_ERR_STANDARDMIN

Errors common to all dialogs lie in the range OLEUI_ERR_STANDARDMIN to OLEUI_ERR_STANDARDMAX. This value allows the application to test for standard messages in order to display error messages to the user.

OLEUI_ERR_STRUCTURENULL

The pointer to an OLEUIXXX structure passed into the function was NULL.

OLEUI_ERR_STRUCTUREINVALID

Insufficient permissions for read or write access to an OLEUIXXX structure.

OLEUI_ERR_CBSTRUCTINCORRECT

The cbstruct value is incorrect.

OLEUI_ERR_HWNDOWNERINVALID

The hWndOwner value is invalid.

OLEUI_ERR_LPSZCAPTIONINVALID

The lpszCaption value is invalid.

OLEUI_ERR_LPFNHOOKINVALID

The lpfnHook value is invalid.

OLEUI_ERR_HINSTANCEINVALID

The hInstance value is invalid.

OLEUI_ERR_LPSZTEMPLATEINVALID

The lpszTemplate value is invalid.

OLEUI_ERR_HRESOURCEINVALID

The hResource value is invalid.

Initialization Errors

OLEUI_ERR_FINDTEMPLATEFAILURE

Unable to find the dialog template.

OLEUI_ERR_LOADTEMPLATEFAILURE

Unable to load the dialog template.

OLEUI_ERR_DIALOGFAILURE

Dialog initialization failed.

OLEUI_ERR_LOCALMEMALLOC

A call to LocalAlloc or the standard IMalloc allocator failed.

OLEUI_ERR_GLOBALMEMALLOC

A call to GlobalAlloc or the standard IMalloc allocator failed.

OLEUI_ERR_LOADSTRING

Unable to LoadString localized resources from the library.

OLEUI_ERR_OLEMEMALLOC

A call to the standard IMalloc allocator failed.

Function Specific Errors

OLEUI_ERR_STANDARDMAX

Errors common to all dialogs lie in the range OLEUI_ERR_STANDARDMIN to OLEUI_ERR_STANDARDMAX. This value allows the application to test for standard messages in order to display error messages to the user.

Comments

The following dialog templates are defined in Windows Interface Guidelines--A Guide for Designing Software. The nTemplate parameter must be a currently defined resource; however, additional templates can be added to prompt.dlg.

IDD_LINKSOURCEUNAVAILABLE

IDD_CANNOTUPDATELINK

IDD_SERVERNOTREG

IDD_CANNOTRESPONDVERB

IDD_SERVERNOTFOUND

IDD_UPDATELINKS

See Also

wsprintf in Win32


OleUIUpdateLinks

Updates all links in the link container and displays a dialog box that shows the progress of the updating process. The process is stopped if the user presses the Stop button or when all links are processed.

BOOL OleUIUpdateLink(

LPOLEUILINKCONTAINER lpOleUILinkCntr,	//Points to the link container
HWND hwndParent,	//Dialog box's parent window
LPTSTR lpszTitle,	//Dialog box title
int cLinks	//Number of links
);
Parameters

lpOleUILinkCntr

The pointer to the Link Container.

hwndParent

The parent window of the dialog.

lpszTitle

The title of the dialog box.

cLinks

The total number of links.

Return Values

TRUE

The links were successfully updated.

FALSE

Unable to update the links.

See Also

IOleUILinkContainer::GetLinkUpdateOptions, IOleUILinkContainer::UpdateLink


OleUninitialize
OleUninitialize   QuickInfo

Closes the OLE library, freeing any resources that it maintains.

void OleUninitialize();

Comments

You should call this function on application shutdown, as the last call made to the OLE library. OleUninitialize calls the CoUninitialize function internally to shut down the OLE Component Object(COM) Library.

The OleInitialize and OleUninitialize calls must be balanced — if there are multiple calls to the OleInitialize function, there must be the same number of calls to OleUninitialize: Only the OleUninitialize call corresponding to the OleInitialize call that actually initialized the COM library can close it.

See Also

OleInitialize, CoUninitialize


ProgIDFromCLSID

Retrieves the ProgID for a given CLSID.

HRESULT ProgIDFromCLSID(

REFCLSID clsid,	//The CLSID for which the ProgID is requested
LPOLESTR * lplpszProgID	//Receives a pointer to the requested ProgID on return
);
Parameters

clsid

Specifies the CLSID for which the ProgID is requested.

lplpszProgID

Receives a pointer to the requested ProgID on return.

Return Values

S_OK

Indicates the ProgID was returned successfully.

REGDB_E_CLASSNOTREG

Indicates class not registered in the registry.

REGDB_E_READREGDB

Indicates error reading registry.

Comments

Every OLE 2 object class listed in the Insert Object dialog box must have a programmatic identifier (ProgID), a string that uniquely identifies a given class. In addition to determining the eligibility for the Insert Object dialog box, the ProgID can be used as an identifier in a macro programming language to identify a class. Finally, the ProgID is also the class name used for an OLE 2 class when placed in an OLE 1 container.

The ProgIDFromCLSID function uses entries in the registry to do the conversion. OLE 2 application authors are responsible for correctly configuring the registry at application installation time.

The ProgID string must be different than the class name of any OLE 1 application, including the OLE 1 version of the same application, if there is one. In addition, a ProgID string must not contain more than 39 characters or start with a digit. Except for a single period, it cannot contain any punctuation (including underscores).

The ProgID must never be shown to the user in the user interface. If you need a short human-readable string for an object, call IOleObject::GetUserType.

The CLSIDFromProgID function can be called to create a CLSID from a given ProgID. CLSIDs can be freed with the task allocator (refer to the CoGetMalloc function).

See Also

CLSIDFromProgID


PropagateResult

#define PropagateResult(hrPrevious, scBase) ((HRESULT) scBase)

PropagateResult is a no-op

This macro is obsolete and should not be used.


ReadClassStg
ReadClassStg   QuickInfo

Reads the CLSID from the storage object.

HRESULT ReadClassStg(

IStorage * pStg,	//Points to the storage containing the CLSID to be retrieved
CLSID * pclsid	//Points to location for returning the CLSID
);
Parameters

pStg

Points to the storage object containing the CLSID to be returned.

pclsid

Points to location where the CLSID is to be returned. May return CLSID_NULL.

Return Values

S_OK

Indicates the CLSID was returned successfully.

E_OUTOFMEMORY

Indicates the CLSID could not be returned due to lack of memory.

See also the IStorage::Stat method for other error return values.

See Also

This function is simply a helper function that calls the IStorage::Stat method and retrieves the CLSID from the resulting STATSTG structure.

See Also

OleLoad, WriteClassStg


ReadClassStm
ReadClassStm   QuickInfo

Reads the CLSID previously written to a stream object with the WriteClassStm method.

HRESULT ReadClassStm(

IStream * pStm,	//Points to the stream from which the CLSID is to be read
CLSID * pclsid	//Points to the location where the CLSID is returned
);
Parameters

pStm

Points to the stream object containing the CLSID to be read. This CLSID must have been previously written to the stream object using WriteClassStm.

pclsid

Points to the location where the CLSID is to be returned.

Return Values

S_OK

Indicates the CLSID was successfully returned.

STG_E_READFAULT

Indicates end of file was reached.

See also the IStream::Read method for other error return values.

Comments

Most applications do not call the ReadClassStm method. OLE calls it before making a call to an object's IPersistStream::Load implementation.

See Also

WriteClassStm, ReadClassStg, WriteClassStg


ReadFmtUserTypeStg
ReadFmtUserTypeStg   QuickInfo

Returns the clipboard format and user type previously saved with the WriteFmtUserTypeStg function.

HRESULT ReadFmtUserTypeStg(

IStorage * pStg,	//Points to storage object for which the values are to be retreived
CLIPFORMAT * pcf,	//Points to location for returning the clipboard format
LPWSTR * lplpszUserType	//Points to location for returning the user type string
);
Parameters

pStg

Points to the storage object from which the information is to be read.

pcf

Points to the location where the clipboard format is to be returned. It can be NULL, indicating the format is of no interest to the caller.

lplpszUserType

Points to the location where the user type string is to be returned. It can be NULL, indicating the user type is of no interest to the caller.

Return Values

S_OK

Indicates the requested information was read successfully.

E_OUTOFMEMORY

Indicates the information could not be retrieved due to a lack of memory.

E_FAIL

Indicates the WriteFmtUserTypeStg function was never called on the object.

See also the IStream::Read method for other error return values.

Comments

This function returns the clipboard format and the user type string from the specified storage object. The WriteClassStg function must have been called before calling the ReadFmtUserTypeStg function.

See Also

WriteFmtUserTypeStg


RegisterDragDrop
RegisterDragDrop   QuickInfo

Registers the specified window as a window that can be the target of an OLE drag and drop operation and specifies the IDropTarget instance to use for drop operations.

HRESULT RegisterDragDrop(

HWND hwnd,	//Window that can accept drops
IDropTarget * pDropTarget	//Points to the IDropTarget interface
);
Parameters

hwnd

Specifies the handle to a window that can be a target for an OLE drag and drop operation.

pDropTarget

Specifies the IDropTarget instance to use for communicating OLE drag and drop information for the specified window.

Return Values

S_OK

Indicates the application was registered successfully.

DRAGDROP_E_INVALIDHWND

Indicates invalid handle returned in the hwnd parameter.

DRAGDROP_E_ALREADYREGISTERED

Indicates the specified window has already been registered as a drop target.

E_OUTOFMEMORY

Indicates out of memory.

Comments

If your application can accept dropped objects during OLE drag and drop operations, you must call the RegisterDragDrop function. Do this whenever one of your application windows is available as a potential drop target, i.e., when the window appears unobscured on the screen.

The RegisterDragDrop function only registers one window at a time, so you must call it for each application window capable of accepting dropped objects.

As the mouse passes over unobscured portions of the target window during an OLE drag and drop operation, the DoDragDrop function calls the specified IDropTarget::DragOver method for the current window. When a drop operation actually occurs in a given window, the DoDragDrop function calls IDropTarget::Drop.

The RegisterDragDrop function also calls the IUnknown::AddRef method for your drop target interface.

See Also

RevokeDragDrop


ReleaseStgMedium
ReleaseStgMedium   QuickInfo

Frees the specified storage medium.

void ReleaseStgMedium(

STGMEDIUM * pmedium	//Storage medium to be freed
);
Parameter

pmedium

Points to the storage medium that is to be freed.

Return Value

None.

Comments

The ReleaseStgMedium function frees the specified storage medium. Use this function during data transfer operations where storage medium structures are parameters, such as IDataObject::GetData or IDataObject::SetData. This structure specifies the appropriate IUnknown::Release method for releasing the storage medium when it is no longer needed.

The ReleaseStgMedium function calls the appropriate method or function to release the specified storage medium. Either the original provider of the medium or the receiver of the medium can call ReleaseStgMedium.

In cases where the original provider of the medium is responsible for freeing the medium, the provider calls ReleaseStgMedium. The ReleaseStgMedium function first makes a call as described in the following table, depending on the type of storage medium being freed.

Medium	ReleaseStgMedium Action
TYMED_HGLOBAL	None.
TYMED_GDI	None.
TYMED_ENHMF	None.
TYMED_MFPICT	None.
TYMED_FILE	Frees the filename string using standard memory management mechanisms.
TYMED_ISTREAM	Calls IStream::Release.
TYMED_ISTORAGE	Calls IStorage::Release.
After making the call described in the preceding table, ReleaseStgMedium then calls the IUnknown::Release method for the specified storage medium. This method is specified in the storage medium structure.

In cases where the receiver of the medium is responsible for freeing the medium, the storage medium structure specifies NULL for the IUnknown::Release method. In this case, the receiver calls ReleaseStgMedium, which makes a call as described in the following table depending on the type of storage medium being freed.

Medium	ReleaseStgMedium Action
TYMED_HGLOBAL	Calls GlobalFree on the handle.
TYMED_GDI	Calls DeleteObject on the handle.
TYMED_ENHMF	Deletes the enhanced metafile.
TYMED_MFPICT	The hMF that it contains is deleted with DeleteMetaFile; then the handle itself is passed to GlobalFree.
TYMED_FILE	Frees the disk file by deleting it. Frees the file name string by using the standard memory management paradigm.
TYMED_ISTREAM	Calls IStream::Release.
TYMED_ISTORAGE	Calls IStorage::Release.
In either case after the call to ReleaseStgMedium, the specified storage medium is invalid and can no longer be used.


ResultFromScode

#define ResultFromScode(sc) ((HRESULT) (sc))

Converts an SCODE into an HRESULT.

This macro is obsolete and should not be used.


RevokeDragDrop
RevokeDragDrop   QuickInfo

Revokes the registration of the specified application window as a potential target for OLE drag and drop operations.

HRESULT RevokeDragDrop(

HWND hwnd	//Window that can accept drops
);
Parameter

hwnd

Specifies the handle to a window previously registered as a target for an OLE drag and drop operation.

Return Values

S_OK

Indicates registration as a target window was revoked successfully.

DRAGDROP_E_INVALIDHWND

Indicates invalid handle returned in the hwnd parameter.

DRAGDROP_E_NOTREGISTERED

Indicates an attempt was made to revoke a drop target that has not been registered.

E_OUTOFMEMORY

Out of memory.

Comments

When your application window is no longer available as a potential target for an OLE drag and drop operation, you must call RevokeDragDrop.

This function calls the IUnknown::Release method for your drop target interface.

See Also

RegisterDragDrop


SCODE_CODE

#define SCODE_CODE(sc) ((sc) & 0xFFFF)

Extracts the code part of the SCODE.


SCODE_FACILITY

#define SCODE_FACILITY(sc) (((sc) >> 16) & 0x1fff)

Extracts the facility from the SCODE.


SCODE_SEVERITY

#define SCODE_SEVERITY(sc) (((sc) >> 31) & 0x1)

Extracts the severity field from the SCODE.


SetConvertStg
SetConvertStg   QuickInfo

Indicates whether the object is to be automatically converted to a different CLSID. It does this by setting the conversion bit in a storage object. The setting can be retrieved with a call to the GetConvertStg function.

HRESULT SetConvertStg(

IStorage * pStg,	//Storage object where the conversion bit is to be set
BOOL fConvert	//Indicates whether an object is to be converted
);
Parameters

pStg

Specifies the storage object in which to set the conversion bit.

fConvert

If TRUE, sets the conversion bit for the object. If FALSE, clears the conversion bit.

Return Values

S_OK

Indicates the object's conversion bit was set successfully.

STG_E_ACCESSDENIED

Indicates access to the storage object is not available.

E_OUTOFMEMORY

Indicates the conversion bit was not set due to a lack of memory.

E_INVALIDARG

Indicates one or more arguments are invalid.

E_UNEXPECTED

Indicates an unexpected error occurred.

See the IStorage::CreateStream, IStorage::OpenStream, IStream::Read, and IStream::Write methods for possible storage and stream access errors.

Comments

As part of converting an object from one class to another, container applications call SetConvertStg to set the conversion bit in the storage object. The bit is set to TRUE, indicating that the object has been tagged for conversion to a new class the next time it is loaded.

To retrieve the value of the conversion bit, an object application calls the GetConvertStg function when it is loading the object. If the bit is set, the object application converts the object to the new CLSID. To reset an object's conversion bit, the object application calls the SetConvertStg function with the fConvert parameter set to FALSE.

See Also

GetConvertStg


StgCreateDocfile
StgCreateDocfile   QuickInfo

Creates a new storage object using the OLE-provided compound file implementation for the IStorage interface.

HRESULT StgCreateDocfile(

const WCHAR * pwcsName,	//Points to pathname of compound file to create
DWORD grfMode,	//Specifies the access mode for opening the storage object
DWORD reserved,	//Reserved; must be zero
IStorage ** ppstgOpen	//Points to location for returning the new storage object
);
Parameters

pwcsName

Points to the pathname of the compound file to create. Passed uninterpreted to the file system. This can be a relative name or NULL. If NULL, a temporary compound file is allocated with a unique name.

grfMode

Specifies the access mode to use when opening the new storage object. For more information, see the STGM enumeration.

reserved

Reserved for future use; must be zero.

ppstgOpen

Points to the location where the new storage object is placed.

Return Values

S_OK

Indicates the compound file was successfully created.

STG_E_ACCESSDENIED

Indicates the calling process does not have sufficient access. Attempt to open file with conflicting permissions to a simultaneous open.

STG_E_FILEALREADYEXISTS

Indicates the compound file already exists and grfMode is set to STGM_FAILIFTHERE.

STG_S_CONVERTED

Indicates the specified file was successfully converted to Storage format.

STG_E_INSUFFICIENTMEMORY

Indicates the compound file was not created due to a lack of memory.

STG_E_INVALIDNAME

Indicates bad name in the pwcsName parameter.

STG_E_INVALIDPOINTER

Indicates bad pointer in the pwcsName parameter or the ppStgOpen parameter.

STG_E_INVALIDFLAG

Indicates bad flag combination in the grfMode pointer.

STG_E_TOOMANYOPENFILES

Indicates the compound file was not created due to a lack of file handles.

See also any file system errors for other error return values.

Comments

This function creates a new storage object using the OLE-provided, compound-file implementation for the IStorage interface. The name of the open compound file can be retrieved by calling the IStorage::Stat method.

The StgCreateDocfile function creates the file if it does not exist. If it does exist, the use of the STGM_CREATE, STGM_CONVERT, and STGM_FAILIFTHERE flags in the grfMode parameter indicate how to proceed. See the STGM enumeration for more information on these values.

If the compound file is opened in transacted mode (the grfMode parameter specifies STGM_TRANSACTED) and a file with this name already exists, the existing file is not altered until all outstanding changes are committed. If the calling process lacks write access to the existing file (because of access control in the file system), the grfMode parameter can only specify STGM_READ and not STGM_WRITE or STGM_READWRITE. The resulting new open compound file can still be written to, but a commit operation will fail (in transacted mode, write permissions are enforced at commit time).

If the grfMode parameter specifies STGM_TRANSACTED and no file yet exists with the name specified by the pwcsName parameter, the file is created immediately. In an access-controlled file system, the caller must have write permissions in the file system directory in which the compound file is created.

The absence of STGM_TRANSACTED in the grfMode parameter indicates the file is to be created and opened in direct access mode. Any existing file with the same name is destroyed before creating the new file.

The StgCreateDocfile function can be used to create a temporary compound file by passing a NULL value for the pwcsName parameter. However, these files are temporary only in the sense that they have a system-provided unique name − likely one that is meaningless to the user. The caller is responsible for deleting the temporary file when finished with it, unless STGM_DELETEONRELEASE was specified for the grfMode parameter.

Note  By default, a Windows application can have 20 file handles open at one time. Each storage object opened in transacted mode uses three file handles. To increase the number of file handles the application has available, applications often call the Windows SetHandleCount function. However, the SetHandleCount function affects C run-time libraries (those statically linked to the application) that are hard-coded to expect only 20 file handles. There is no check on overflow, so if the application already has a few compound files open and it then uses a C run-time library (for example, fopen or sopen), the application corrupts memory past the end of the file-handle array (low in its data segment) if the library gets a file handle above 20.

To solve this problem, applications should reserve some number of file handles on start up, making them available to the components that might be based on C run-time libraries. If your application does not use any dynamic link libraries that use the C run-time libraries, there is no need for any special file-handle reservation code.

See Also

StgCreateDocFileOnILockBytes


StgCreateDocfileOnILockBytes
StgCreateDocfileOnILockBytes   QuickInfo

Creates and opens a new storage object on top of an ILockBytes instance provided by the caller. The storage object uses the OLE-provided, compound-file implementation for the IStorage interface.

HRESULT StgCreateDocfileOnILockBytes(

ILockBytes * plkbyt,	//Specifies the byte array object
DWORD grfMode,	//Specifies the access mode
DWORD reserved,	//Reserved; must be zero
IStorage ** ppstgOpen	//Points to location for returning the new storage object
);
Parameters

plkbyt

Points to the underlying byte array object on which to create a compound file.

grfMode

Specifies the access mode to use when opening the new compound file. For more information, see the STGM enumeration.

reserved

Reserved for future use; must be zero.

ppstgOpen

Points to the location where the new storage object is placed.

Return Values

S_OK

Indicates the compound file was successfully created.

STG_E_ACCESSDENIED

Indicates the calling process does not have sufficient access. Attempt was made to open an ILockBytes object with permissions that conflict with another current opening of the same object.

STG_E_FILEALREADYEXISTS

Indicates the compound file already exists and the grfMode parameter is set to STGM_FAILIFTHERE.

STG_S_CONVERTED

Indicates the compound file was successfully converted. The original byte array object was successfully converted to IStorage format.

STG_E_INSUFFICIENTMEMORY

Indicates the storage object was not created due to a lack of memory.

STG_E_INVALIDPOINTER

Indicates a bad pointer was in the pLkbyt parameter or the ppStgOpen parameter.

STG_E_INVALIDFLAG

Indicates a bad flag combination was in the grfMode parameter.

STG_E_TOOMANYOPENFILES

Indicates the storage object was not created due to a lack of file handles.

See also any file system errors for other error return values.

See also the ILockBytes interface for other error return values.

Comments

This function creates a storage object on top of a byte array object using the OLE-provided, compound-file implementation for the IStorage interface. The StgCreateDocfileOnILockBytes function can be used to store a document in a relational database. The byte array indicated by the pLkbyt parameter is used for the underlying storage in place of a disk file.

The StgCreateDocfileOnILockBytes function has almost exactly the same semantics as the StgCreateDocfile function. For more information, see the discussion of StgCreateDocfile.

The newly created compound file is opened according to the access modes in the grfMode parameter. For conversion purposes, the file is always considered to already exist. As a result, it is not useful to use the STGM_FAILIFTHERE value, because it always causes an error to be returned. However, STGM_CREATE and STGM_CONVERT are both still useful.

The ability to build a compound file on top of a byte array object is provided to support having the data (underneath an IStorage and IStream tree structure) live in persistent space, space that does not ultimately reside in the file system. Given this capability, there is nothing preventing a document that is stored in a file from using this facility. For example, a container might do this to minimize the impact on its file format caused by adopting OLE. However, it is recommended that OLE documents adopt the IStorage interface for their own outer-level storage. This has the following advantages:

•	The storage structure of the document is the same as its storage structure when it is an embedded object, reducing the number of cases the application needs to handle.

•	One can write tools to access the OLE embeddings and links within the document without special knowledge of the document's file format. An example of such a tool is a copy utility that copies all the documents included in a container containing linked objects. A copy utility like this needs access to the contained links to determine the extent of files to be copied.

•	The IStorage instance addresses the problem of how to commit the changes to the file. An application using the ILockBytes byte array must handle these issues itself.

•	Future file systems will likely implement the IStorage and IStream interfaces as their native abstractions, rather than layer on top of a byte array as is done in compound files. Such a file system could be built so documents using the IStorage interface as their outer level containment structure would get an automatic efficiency gain by having the layering flattened when files are saved on the new file system.

See Also

StgCreateDocfile


StgIsStorageFile
StgIsStorageFile   QuickInfo

Indicates whether a particular disk file contains a storage object.

HRESULT StgIsStorageFile(

const WCHAR * pwcsName	//Points to a pathname of the file to check
);
Parameter

pwcsName

Points to the name of the disk file to be examined. The pwcsName parameter is passed uninterpreted to the underlying file system.

Return Values

S_OK

Indicates the file contains a storage object.

S_FALSE

Indicates the file does not contain a storage object.

STG_E_INVALIDFILENAME

Indicates a bad filename was passed in the pwcsName parameter.

STG_E_FILENOTFOUND

Indicates the pwcsName parameter could not be determined.

See also any file system errors for other error return values.

Comments

At the beginning of the disk file underlying a storage object is a signature distinguishing a storage object from other file formats. The StgIsStorageFile function is useful to applications whose documents use a disk file format that might or might not use storage objects.

See Also

StgIsStorageILockBytes


StgIsStorageILockBytes
StgIsStorageILockBytes   QuickInfo

Indicates whether the specified byte array contains a storage object.

HRESULT StgIsStorageILockBytes(

ILockBytes * plkbyt	//Points to the byte array to be examined
);
Parameter

plkbyt

Points to the byte array to be examined.

Return Values

S_OK

Indicates the specified byte array contains a storage object.

S_FALSE

Indicates the specified byte array does not contain a storage object.

File system errors.

ILockBytes interface error return values.

Comments

At the beginning of the ILockBytes byte array underlying a storage object is a signature distinguishing an IStorage object from other file formats. The StgIsStorageILockBytes function is useful to applications whose documents use an ILockBytes byte array format that might or might not use storage objects.

See Also

StgIsStorageFile


StgOpenStorage
StgOpenStorage   QuickInfo

Opens an existing root storage object in the file system. You can use this function to open directories, files, compound files, and summary catalogs. Nested storage objects can only be opened using their parent's IStorage::OpenStorage method.

HRESULT StgOpenStorage(

const WCHAR * pwcsName,	//Points to the pathname of the file containing storage object
IStorage * pstgPriority,	//Points to a previous opening of a root storage object
DWORD grfMode,	//Specifies the access mode for the object
SNB snbExclude,	//Points to an SNB structure specifying elements to be excluded
DWORD reserved,	//Reserved; must be zero
IStorage ** ppstgOpen	//Points to location for returning the storage object
);
Parameters

pwcsName

Points to the pathname of the storage object to open. This parameter is ignored if the pStgPriority parameter is not NULL.

pstgPriority

Most often NULL. If not NULL, this parameter is used instead of the pwcsName parameter to specify the storage object to open. It points to a previous opening of a root storage object, most often one that was opened in priority mode.

After the StgOpenStorage function returns, the storage object specified in the pStgPriority parameter on function entry is invalid, and can no longer be used. Use the one specified in the ppStgOpen parameter instead.

grfMode

Specifies the access mode to use to open the storage object.

snbExclude

If not NULL, this parameter points to a block of elements in this storage that are to be excluded as the storage object is opened. This exclusion occurs independent of whether a snapshot copy happens on the open. May be NULL.

reserved

Indicates reserved for future use; must be zero.

ppstgOpen

Points to the location where the opened storage is placed.

Return Values

S_OK

Indicates the storage object was successfully opened.

STG_E_FILENOTFOUND

Indicates the specified file does not exist.

STG_E_ACCESSDENIED

Indicates insufficient access to open file. Exclusions specified without read-write permissions or attempt to open file with conflicting permissions to a simultaneous open.

STG_E_FILEALREADYEXISTS

Indicates the file exists but is not a storage object.

STG_E_TOOMANYOPENFILES

Indicates the storage object was not opened because there are too many open files.

STG_E_INSUFFICIENTMEMORY

Indicates the storage object was not opened due to a lack of memory.

STG_E_INVALIDNAME

Indicates bad name in the pwcsName parameter or the snbExclude parameter.

STG_E_INVALIDPOINTER

Indicates bad pointer in one of the parameters: snbExclude, pwcsName, pstgPriority, or ppStgOpen.

STG_E_INVALIDFLAG

Indicates bad flag combination in the grfMode parameter.

STG_E_INVALIDFUNCTION

Indicates STGM_DELETEONRELEASE specified in the grfMode parameter.

STG_E_OLDDLL

Indicates the DLL being used to open this storage object is a version prior to the one used to create it.

STG_E_OLDFORMAT

Indicates the storage object being opened was created by the Beta 1 storage provider. This format is no longer supported.

File system error return values.

Comments

This function opens the specified root storage object according to the access mode in the grfMode parameter. A pointer to the opened storage object is returned through the ppstgOpen parameter.

Note  Opening a storage object in read and/or write mode without denying writer permission to others (the grfMode parameter specifies STGM_SHARE_DENY_WRITE) can be be a time consuming operation since the StgOpenStorage call must make a snapshot of the entire storage object.

Applications will often try to open storage objects with the following access permissions:

STGM_READ_WRITE | STGM_SHARE_DENY_WRITE

// transacted vs. direct mode omitted for exposition

If the application succeeds, it will never need to do a snapshot copy. If it fails, the application can revert to using the permissions and make a snapshot copy:

STGM_READ_WRITE

// transacted vs. direct mode omitted for exposition

In this case, the application should prompt the user before doing a time consuming copy. Alternatively, if the document sharing semantics implied by the access modes are appropriate, the application could try to open the storage as follows:

STGM_READ | STGM_SHARE_DENY_WRITE

// transacted vs. direct mode omitted for exposition

In this case, if the application succeeds, a snapshot copy will not have been made (because STGM_SHARE_DENY_WRITE was specified, denying others write access).

To reduce the expense of making a snapshot copy, applications can open storage objects in priority mode (grfMode specifies STGM_PRIORITY).

The snbExclude parameter specifies a set of element names in this storage object that are to be emptied as the storage object is opened: streams are set to a length of zero; storage objects have all their elements removed. By excluding certain streams, the expense of making a snapshot copy can be significantly reduced. Almost always, this approach will be used after first opening the storage object in priority mode, then completely reading the now-excluded elements into memory. This earlier priority mode opening of the storage object should be passed through the pstgPriority parameter to remove the exclusion implied by priority mode. The calling application is responsible for rewriting the contents of excluded items before committing. Thus, this technique is most likely only useful to applications whose documents do not require constant access to their storage objects while they are active.


StgOpenStorageOnILockBytes
StgOpenStorageOnILockBytes   QuickInfo

Opens an existing storage object that does not reside in a disk file, but instead has an underlying byte array provided by the caller.

HRESULT StgOpenStorageOnILockBytes(

ILockBytes * plkbyt,	//Specifies the underlying byte array
IStorage * pStgPriority,	//Points to a previous opening of a root storage object
DWORD grfMode,	//Specifies the access mode for the object
SNB snbExclude,	//Points to an SNB structure specifying elements to be excluded
DWORD reserved,	//Reserved, must be zero
IStorage ** ppstgOpen	//Points to location for returning the storage object
);
Parameters

plkbyt

Points to the underlying byte array that contains the storage object to be opened.

pStgPriority

Most often NULL. If not NULL, this parameter is used instead of the plkbyt parameter to specify the storage object to open. It points to a previous opening of a root storage object, most often one that was opened in priority mode.

After the StgOpenStorageOnILockBytes function returns, the storage object specified in the pStgPriority parameter on function entry is invalid, and can no longer be used; use the one specified in the ppStgOpen parameter instead.

grfMode

Specifies the access mode to use to open the storage object.

snbExclude

May be NULL. If not NULL, this parameter points to a block of elements in this storage that are to be excluded as the storage object is opened. This exclusion occurs independent of whether a snapshot copy happens on the open. .

reserved

Indicates reserved for future use; must be zero.

ppstgOpen

Points to the location where the opened storage is placed.

Return Values

S_OK

Indicates the storage object was successfully opened.

STG_E_FILENOTFOUND

Indicates the specified byte array does not exist.

STG_E_ACCESSDENIED

Indicates insufficient access to open the byte array. Exclusions specified without read-write permissions or attempt to open the byte array with conflicting permissions to a simultaneous open.

STG_E_FILEALREADYEXISTS

Indicates the byte array exists but is not a storage object.

STG_E_TOOMANYOPENFILES

Indicates the storage object was not opened because there are too many open files.

STG_E_INSUFFICIENTMEMORY

Indicates the storage object was not opened due to a lack of memory.

STG_E_INVALIDNAME

Indicates bad name in the pwcsName parameter or the snbExclude parameter.

STG_E_INVALIDPOINTER

Indicates bad pointer in one of the parameters: snbExclude, pwcsName, pstgPriority, or ppStgOpen.

STG_E_INVALIDFLAG

Indicates bad flag combination in the grfMode parameter.

STG_E_INVALIDFUNCTION

Indicates STGM_DELETEONRELEASE specified in the grfMode parameter.

STG_E_OLDDLL

Indicates the DLL being used to open this storage object is a version prior to the one used to create it.

STG_E_OLDFORMAT

Indicates the storage object being opened was created by the Beta 1 storage provider. This format is no longer supported.

File system error return values.

ILockBytes interface error return values.

Comments

This function opens the specified root storage object. The storage object is opened according to the access mode in the grfMode parameter; a pointer to the opened storage object is returned through the ppstgOpen parameter.

The storage object must have been previously created by the StgCreateDocfileOnILockBytes function.

The semantics of the StgOpenStorageOnILockBytes function are almost exactly the same as those of the StgOpenStorage function. For more information, see the discussion of the StgOpenStorage function.

See Also

StgOpenStorage


StgSetTimes
StgSetTimes   QuickInfo

Sets the creation, access, and modification times of the indicated file, if supported by the underlying file system.

HRESULT StgSetTimes(

WCHAR const * lpszName,	//Points to the name of the file to be changed
FILETIME const * pctime,	//Points to the new value for the creation time
FILETIME const * patime,	//Points to the new value for the access time
FILETIME const * pmtime	//Points to the new value for the modification time
);
Parameters

lpszName

Points to the name of the file to be changed.

pctime

Points to the new value for the creation time.

patime

Points to the new value for the access time.

pmtime

Points to the new value for the modification time.

Return Values

S_OK

Indicates time values successfully set.

STG_E_FILENOTFOUND

Indicates element does not exist.

STG_E_INVALIDNAME

Indicates bad name passed in the lpszName parameter, or a file system error.

STG_E_ACCESSDENIED

Indicates insufficient permissions to access storage.

File system error return values.

Comments

This function sets the time values for the specified file. Each of the time value parameters can be NULL, indicating no modification should occur.

It is possible that one or more of these time values are not supported by the underlying file system. This function sets the times that can be set and ignores the rest.


StringFromCLSID
StringFromCLSID   QuickInfo

Converts the CLSID into a string of printable characters so different CLSIDs always convert to different strings.

HRESULT StringFromCLSID(

REFCLSID rclsid,	//The CLSID to be converted
LPOLESTR * lplpsz	//Receives the resulting string on return
);
Parameters

rclsid

Specifies the CLSID to be converted.

lplpsz

Receives the resulting string on return.

Return Values

S_OK

Indicates the CLSID was successfully converted and returned.

E_OUTOFMEMORY

Out of memory.

Comments

The StringFromCLSID function calls the StringFromGuid2 function to convert a globally unique identifier (GUID) into a string of printable characters.

See Also

CLSIDFromString, StringFromGuid2


StringFromGUID2
StringFromGUID2   QuickInfo

Converts a globally unique identifier (GUID) into a string of printable characters.

int StringFromGUID2(

REFGUID rguid,	//The interface ID to be converted
LPOLESTR lpsz,	//Receives the resulting string on return
int cbMax	//The maximum size the returned string is expected to be
);
Parameters

rguid

Specifies the interface ID to be converted.

lpsz

Receives the resulting string on return.

cbMax

Specifies the maximum size the returned string is expected to be.

Return Values

0 (zero)

Indicates buffer is too small for returned string.

Non-zero value

Specifies the number of characters in the returned string, including the null terminator.

Comments

The string that the lpsz parameter receives has a format like the following sample:

[c200e360-38c5-11ce-ae62-08002b2b79ef]

where the successive fields break the GUID into the form DWORD-WORD-WORD-WORD-WORD.DWORD covering the 128-bit GUID. The string includes enclosing braces, which are an OLE convention.

See Also

StringFromCLSID


StringFromIID
StringFromIID   QuickInfo

Converts an interface ID into a string of printable characters.

HRESULT StringFromIID(

REFIID rclsid	//The interface ID to be converted
LPOLESTR * lplpsz	//Receives a pointer to the resulting string on return
);
Parameters

rclsid

Specifies the interface ID to be converted.

lplpsz

Receives a pointer to the resulting string on return.

Return Values

S_OK

Indicates the character string was successfully returned.

E_OUTOFMEMORY

Out of memory.

Comments

The string returned by the function is freed in the standard way, using the task allocator (refer to the CoGetMallocfunction).

See Also

IIDFromString, CoGetMalloc


SUCCEDDED

#define SUCCEEDED(Status) ((HRESULT)(Status) >= 0)

Provides a generic test for success on any status value. Non-negative numbers indicate success.


WriteClassStg
WriteClassStg   QuickInfo

Stores the specified CLSID in a storage object.

HRESULT WriteClassStg(

IStorage * pStg,	//Points to the storage object
REFCLSID rclsid	//Specifies the CLSID to be stored in the storage object
);
Parameters

pStg

Points to the storage object that will get a new CLSID.

rclsid

Points to the CLSID to be stored with the object.

Return Values

S_OK

Indicates the CLSID was successfully written to the file.

STG_E_MEDIUMFULL

Indicates the CLSID could not be written due to lack of memory.

IStorage::SetClass method error return values.

Comments

This function writes a CLSID to the specified storage object so it can be read by the ReadClassStg function. Container applications typically call this function before calling the IPersistStorage::Save method.

See Also

OleSave, ReadClassStg


WriteClassStm
WriteClassStm   QuickInfo

Stores the specified CLSID in the stream.

HRESULT WriteClassStm(

IStream * pStm,	//Points to the stream object
REFCLSID rclsid	//Specifies the CLSID to be stored in the stream object
);
Parameters

pStm

Points to the stream into which the CLSID is to be written.

rclsid

Specifies the CLSID to write to the stream.

Return Values

S_OK

Indicates the CLSID was successfully written.

STG_E_MEDIUMFULL

The CLSID could not be written because there is no space left on device.

IStorage::SetClass method error return values.

Comments

This function writes a CLSID to the specified stream object so it can be read by the ReadClassStm function. Most applications do not call the WriteClassStm function. OLE calls it before making a call to an object's IPersistStream::Save method.

See Also

ReadClassStm, WriteClassStg, ReadClassStg


WriteFmtUserTypeStg
WriteFmtUserTypeStg   QuickInfo

Writes a clipboard format and user type to the storage object.

HRESULT WriteFmtUserTypeStg(

IStorage * pStg,	//Points to the storage object
CLIPFORMAT cf,	//Specifies the clipboard format
LPWSTR * lpszUserType	//Points to the current user type
);
Parameters

pStg

Points to the storage object where the information is to be written.

cf

Specifies the clipboard format that describes the structure of the native area of the storage object. The format tag includes the policy for the names of streams and substorages within this storage object and the rules for interpreting data within those streams.

lpszUserType

Points to the object's current user type. It cannot be NULL. This is the type returned by the IOleObject::GetUserType method. If this function is transported to a remote machine where the object class does not exist, this persistently stored user type can be shown to the user in dialog boxes.

Return Values

S_OK

Indicates the information was written successfully.

STG_E_MEDIUMFULL

Indicates information could not be written due to lack of space on the storage medium.

IStream::Write method error return values.

Comments

The WriteFmtUserTypeStg function must be called in an object's implementation of the IPersistStorage::Save method. It must also be called by document-level objects that use structured storage for their persistent representation in their save sequence.

To read the information saved, applications call the ReadFmtUserTypeStg function.

See Also

IPersistStorage::Save, ReadFmtUserTypeStg


BIND_OPTS

The BIND_OPTS structure contains parameters used during a moniker binding operation. A BIND_OPTS structure is stored in a bind context; the same bind context is used by each component of a composite moniker during binding, allowing the same parameters to be passed to all components of a composite moniker. See IBindCtx for more information about bind contexts.

If you're a moniker client (that is, you use a moniker to acquire an interface pointer to an object), you typically do not need to specify values for the fields of this structure. The CreateBindCtx API function creates a bind context with the bind options set to default values that are suitable for most situations; the BindMoniker API function does the same thing when creating a bind context for use in binding a moniker. If you want to modify the values of these bind options, you can do so by passing a BIND_OPTS structure to the IBindCtx::SetBindOptions method. Moniker implementors can pass a BIND_OPTS structure to the IBindCtx::GetBindOptions method to retrieve the values of these bind options.

The BIND_OPTS structure is defined in OBJIDL.IDL.

typedef struct tagBIND_OPTS
{
DWORD cbStruct;
DWORD grfFlags;
DWORD grfMode;
DWORD dwTickCountDeadline;
} BIND_OPTS, *LPBIND_OPTS;

Members

cbStruct

Specifies the size of this structure in bytes (that is, the size of the BIND_OPTS structure).

grfFlags

Specifies flags that control aspects of moniker binding operations. This value is any combination of the bit flags in the BINDFLAGS enumeration. New values may be defined in the future, so moniker implementations should ignore any bits in this field that they do not understand. The CreateBindCtx API function initializes this field to zero.

grfMode

Specifies flags that should be used when opening the file that contains the object identified by the moniker. The values are taken from the STGM enumeration. The binding operation uses these flags in the call to IPersistFile::Load when loading the file. If the object is already running, these flags are ignored by the binding operation. The CreateBindCtx API function initializes this field to STGM_READWRITE.

dwTickCountDeadline

Specifies the clock time (in milliseconds, as returned by the GetTickCount API function) by which the caller would like the binding operation to be completed. This member lets the caller limit the execution time of an operation when speed is of primary importance. A value of zero indicates that there is no deadline. Callers most often use this capability when calling the IMoniker::GetTimeOfLastChange method, though it can be usefully applied to other operations as well. The CreateBindCtx API function initializes this field to zero.

Typical deadlines allow for a few hundred milliseconds of execution. This deadline is a recommendation, not a requirement; however, operations that exceed their deadline by a large amount may cause delays for the end user. Each moniker implementation should try to complete its operation by the deadline, or fail with the error MK_E_EXCEEDEDDEADLINE.

If a binding operation exceeds its deadline because one or more objects that it needs are not running, the moniker implementation should register the objects responsible in the bind context using the IBindCtx::RegisterObjectParam. The objects should be registered under the parameter names "ExceededDeadline", "ExceededDeadline1", "ExceededDeadline2", and so on. If the caller later finds the object in the Running Object Table, the caller can retry the binding operation.

The GetTickCount API function indicates the number of milliseconds since system startup, and wraps back to zero after 2^31 milliseconds. Consequently, callers should be careful not to inadvertently pass a zero value (which indicates no deadline), and moniker implementations should be aware of clock wrapping problems (see the GetTickCount API function for more information).

See Also

BIND_FLAGS, CreateBindCtx, IBindCtx::SetBindOptions


DVTARGETDEVICE

Use the DVTARGETDEVICE structure to specify information about the target device for which data is being composed. DVTARGETDEVICE contains enough information about a Windows target device so a handle to a device context (hDC) can be created using the Windows CreateDC function.

typedef struct tagDVTARGETDEVICE
{
DWORD tdSize;
WORD  tdDriverNameOffset;
WORD  tdDeviceNameOffset;
WORD  tdPortNameOffset;
WORD  tdExtDevmodeOffset;
BYTE  tdData[1];
}DVTARGETDEVICE;

Members

tdSize

Specifies the size in bytes of the DVTARGETDEVICE structure. The initial size is included so the structure can be copied more easily.

tdDriverNameOffset

Specifies the offset in bytes from the beginning of the structure to the device driver name, which is stored as a NULL-terminated string in the tdData buffer.

tdDeviceNameOffset

Specifies the offset in bytes from the beginning of the structure to the device name, which is stored as a NULL-terminated string in the tdData buffer. This value can be zero to indicate no device name.

tdPortNameOffset

Specifies the offset in bytes from the beginning of the structure to the port name, which is stored as a NULL-terminated string in the tdData buffer. This value can be zero to indicate no port name.

tdExtDevmodeOffset

Specifies the offset in bytes from the beginning of the structure to the DEVMODE structure retrieved by the calling ExtDeviceMode.

tdData

Specifies an array of bytes containing data for the target device. It is not necessary to include empty strings in tdData (for names where the offset value is zero).

Comments

Some OLE 1 client applications incorrectly construct target devices by allocating too few bytes in the DEVMODE structure for the OLETARGETDEVICE. They typically only supply the number of bytes in the DEVMODE.dmSize member. The number of bytes to be allocated should be the sum of DEVMODE.dmSize + DEVMODE.dmDriverExtra. When a call is made to the CreateDC API function with an incorrect target device, the printer driver tries to access the additional bytes and unpredictable results can occur. To protect against a crash and make the additional bytes available, OLE pads the size of OLE 2 target devices created from OLE 1 target devices.

See Also

FORMATETC, IEnumFORMATETC, IViewObject, OleConvertOLESTREAMToIStorage


FILETIME

The FILETIME data structure is a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601. It is the means by which Win32 determines the date and time. FILETIME is used by the CoDosDateTimeToFileTime, CoFileTimeToDosDateTime, and CoFileTimeNow functions. It is defined as follows:

typedef struct STRUCT tagFILETIME
{

DWORD  dwLowDateTime;

DWORD  dwHighDateTime;

} FILETIME;

Members

dwLowDateTime

The low 32 bits of the Win32 date/time value.

dwHighDateTime

The upper 32 bits of the Win32 date/time value.

Comments

The FILETIME data structure is used in the time conversion functions between DOS and Win32.

See Also

CoDosDateTimeToFileTime, CoFileTimeNow, CoFileTimeToDosDateTime


FORMATETC

The FORMATETC structure is a generalized Clipboard format. It is enhanced to encompass a target device, the aspect or view of the data, and a storage medium indicator. Where one might expect to find a Clipboard format, OLE uses a FORMATETC data structure instead.

Defined in the IEnumFORMATETC interface.

typedef struct tagFORMATETC
{
CLIPFORMAT  cfFormat;
DVTARGETDEVICE  *ptd;
DWORD  dwAspect;
LONG  lindex;
DWORD  tymed;
}FORMATETC;  *LPFORMATETC;

Members

cfFormat

Indicates the particular clipboard format of interest. There are three types of formats recognized by OLE:

•	Standard interchange formats, such as CF_TEXT.

•	Private application formats understood only by the application offering the format, or by other applications offering similar features.

•	OLE formats, which are used to create linked or embedded objects.

ptd

Points to a DVTARGETDEVICE structure containing information about the target device for which the data is being composed. A NULL value is used whenever the specified data format is independent of the target device or when the caller doesn't care what device is used. In the latter case, if the data requires a target device, the object should pick an appropriate default device (often the display for visual components). Data obtained from an object with a NULL target device, such as most metafiles, is independent of the target device. The resulting data is usually the same as it would be if the user chose the Save As command from the File menu and selected an interchange format.

dwAspect

Specifies one of the DVASPECT enumeration constants that indicate how much detail should be contained in the rendering. A single clipboard format can support multiple aspects or views of the object. Most data and presentation transfer and caching methods pass aspect information. For example, a caller might request an object's iconic picture, using the metafile clipboard format to retrieve it. Note that only one DVASPECT value can be used in dwAspect. That is, dwAspect cannot be the result of a BOOLEAN OR operation on several DVASPECT values.

lindex

Identifies part of the aspect when the data must be split across page boundaries. The most common value is -1, which identifies all of the data. For the aspects DVASPECT_THUMBNAIL and DVASPECT_ICON, lindex is ignored.

tymed

Specifies one of the TYMED enumeration constants which indicate the type of storage medium used to transfer the object's data. Data can be transferred using whatever medium makes sense for the object. For example, data can be passed using global memory, a disk file, or structured storage objects. For more information, see the TYMED enumeration.

Comments

The FORMATETC structure is used by methods in the data transfer and presentation interfaces as a parameter specifying the data being transferred. For example, the IDataObject::GetData method uses the FORMATETC structure to indicate exactly what kind of data the caller is requesting.

See Also

DVASPECT, IDataAdviseHolder, IDataObject, IEnumFORMATETC, IOleCache, OleCreate, OleCreateFromData, OleCreateLinkFromData, OleCreateStaticFromData, OleCreateLink, OleCreateLinkToFile, OleCreateFromFile, STATDATA, STGMEDIUM, TYMED


INTERFACEINFO

The INTERFACEINFO structure contains information about incoming calls. The structure is defined as follows:

typedef struct tagINTERFACEINFO

{

    LPUNKNOWN  pUnk;

    IID  iid;

    WORD  wMethod;

} INTERFACEINFO,  * LPINTERFACEINFO;

Members

pUnk

Points to the object.

iid

Indicates the interface id (iid).

wMethod

Indicates the interface method.

See Also

IMessageFilter::HandleIncomingCall


OBJECTDESCRIPTOR

The OBJECTDESCRIPTOR structure is the data structure used for the CF_OBJECTDESRIPTOR and CF_LINKSRCDESCRIPTOR file formats. These formats provide user interface information during data transfer operations, for example, the Paste Special dialog box or target feedback information during drag and drop operations.

Defined in the IOLETypes pseudo-interface (oletyp.idl).

typedef struct tagOBJECTDESCRIPTOR
{
ULONG cbSize;
CLSID clsid;
DWORD dwDrawAspect;
SIZEL sizel;
POINTL pointl;
DWORD dwStatus;
DWORD dwFullUserTypeName;
DWORD dwSrcOfCopy;
/* variable sized string data may appear here */
} OBJECTDESCRIPTOR;

Members

cbSize

Specifies the size of structure in bytes

clsid

Specifies the CLSID of the object being transferred. The clsid is used to obtain the icon for the Display As Icon option in the Paste Special dialog box and is applicable only if the Embed Source or Embedded Object formats are offered. If neither is offered, the value of clsid should be CLSID_NULL. The clsid can be retrieved by the source by loading the object and calling the IOleObject::GetUserClassID method. Note that for link objects, this value is not the same as the value returned by the IPersist::GetClassID method.

dwDrawAspect

Specifies the display aspect of the object. Typically, this value is DVASPECT_CONTENT or DVASPECT_ICON. If the source application did not draw the object originally, the dwDrawAspect field contains a zero value (which is not the same as DVASPECT_CONTENT).

sizel

Specifies the true extents of the object (without cropping or scaling) in HIMETRIC units. Setting this field is optional. The value can be (0,0) for applications that do not draw the object being transferred. This field is used primarily by targets of drag-and-drop operations so they can give appropriate feedback to the user.

pointl

Specifies the offset in HIMETRIC units from the upper-left corner of the object where a drag-and-drop operation was initiated. This field is only meaningful for a drag-and-drop transfer operation since it corresponds to the point where the mouse was clicked to initiate the drag-and-drop operation. The value is (0,0) for other transfer situations, such as a Clipboard copy and paste.

dwStatus

Contains a copy of the status flags for the object. These flags are defined by the OLEMISC enumeration. If an embedded object is being transferred, they are returned by calling the IOleObject::GetMiscStatus method.

dwFullUserTypeName

Specifies the offset for finding the full user type name of the object being transferred. It specifies the offset, in bytes, from the beginning of the OBJECTDESCRIPTOR data structure to the null-terminated string that specifies the full user type name of the object being transferred. The value is zero if the string is not present. This string is used by the destination of a data transfer to create labels in the Paste Special dialog box. The destination application must be able to handle the cases when this string is omitted.

dwSrcOfCopy

Specifies the offset, in bytes, from the beginning of the data structure to the null-terminated string that specifies the source of the transfer. The dwSrcOfCopy field is typically implemented as the display name of the temporary moniker that identifies the data source. The value for dwSrcOfCopy is displayed in the Source line of the Paste Special dialog box. A zero value indicates that the string is not present. If dwSrcOfCopy is zero, the string "Unknown Source" is displayed in the Paste Special dialog box.

See Also

IDataObject, FORMATETC


OLEINPLACEFRAMEINFO

The OLEINPLACEFRAMEINFO structure contains information about the accelerators supported by a container during an in-place session. The structure is defined in the IOleInPlaceFrame interface (inplcf.idl), and it is used in the IOleInPlaceSite::GetWindowContext method and the OleTranslateAccelerator API function.

typedef struct tagOIFI
{
UINT cb;
BOOL fMDIApp;
HWND hwndFrame;
HACCEL haccel;
UINT cAccelEntries;
} OLEINPLACEFRAMEINFO, *LPOLEINPLACEFRAMEINFO;

Members

cb

Specifies the size in bytes of this structure. The object server must specify sizeof(OLEINPLACEFRAMEINFO) in the structure it passes to IOleInPlaceSite::GetWindowContext. The container can then use this size to determine the structure's version.

fMDIApp

Indicates whether the container is an MDI application.

hwndFrame

Specifies a handle to the container's top-level frame window.

haccel

Specifies the handle to the accelerator table that the container wants to use during an in-place editing session.

cAccelEntries

Specifies the number of accelerators in haccel.

Comments

When an object is being in-place activated, its server calls the container's IOleInPlaceSite::GetWindowContext method which fills in an OLEINPLACEFRAMEINFO structure. During an in-place session, the message loop of an EXE server passes a pointer to the OLEINPLACEFRAMEINFO structure to OleTranslateAccelerator. OLE uses the information in this structure to determine whether a message maps to one of the container's accelerators.

See Also

IOleInPlaceSite::GetWindowContext, OleTranslateAccelerator


OLEMENUGROUPWIDTHS

The OLEMENUGROUPWIDTHS structure is the mechanism for building a shared menu. It indicates the number of menu items in each of the six menu groups of a menu shared between a container and an object server during an in-place editing session.

The structure is defined in the IOleInPlaceFrame interface (inplcf.idl). It is used in the IOleInPlaceFrame::InsertMenus and ICDStandardForm::SetMenu methods, and the OleCreateMenuDescriptor API function.

typedef struct tagOleMenuGroupWidths
{
LONG width[6];
} OLEMENUGROUPWIDTHS, * LPOLEMENUGROUPWIDTHS;

Member

width

Specifies an array whose elements contain the number of menu items in each of the six menu groups of a shared in-place editing menu. Each menu group can have any number of menu items. The container uses elements 0, 2, and 4 to indicate the number of menu items in its File, View, and Window menu groups. The object server uses elements 1, 3, and 5 to indicate the number of menu items in its Edit, Object, and Help menu groups.

Comments

A container application and an object server use this structure to build a shared menu. The object server initializes to zeros the array elements in an OLEMENUGROUPWIDTHS structure and passes a pointer to it along with a menu handle to the container in a call to IOleInPlaceFrame::InsertMenus. The container adds its menu items to the menu, and fills in the structure with the number of items in each of its groups (indexes 0, 2, and 4). The server then uses the group width values returned by the container to insert its menu items in the appropriate position in the menu. The server fills in the structure with the number of items in each of its groups (indexes 1, 3, and 5), and then passes the structure to OLE in a call to the OleCreateMenuDescriptor API function. This enables OLE to intercept the container's menu messages and redirect the messages generated by the server's menus.

See Also

IOleInPlaceFrame::InsertMenus, OleCreateMenuDescriptor


OLEUIBUSY

The OLEUIBUSY structure contains information that the OLE 2.01 User Interface Library uses to initialize the Busy dialog box, and space for the library to return information when the dialog is dismissed.

typedef struct tagOLEUIBUSY

{

// These IN fields are standard across all OLEUI dialog functions.
DWORD  cbStruct;

DWORD  dwFlags;

HWND  hWndOwner;

LPCSTR  lpszCaption;

LPFNOLEUIHOOK  lpfnHook;

LPARAM  lCustData;

HINSTANCE  hInstance;

LPCSTR  lpszTemplate;

HRSRC  hResource;

// Specifics for OLEUIBUSY.

HTASK  hTask;

HWND FAR *  lphWndDialog;

} OLEUICHANGEICON, *POLEUICHANGEICON, FAR *LPOLEUICHANGEICON;

Members

cbStruct

The size of the structure in bytes. This field must be filled on input.

dwFlags

On input, dwFlags specifies the initialization and creation flags. On exit, it specifies the user's choices. It may be a combination of the following flags:

BZ_DISABLECANCELBUTTON

Input only: This flag disables the Cancel button.

BZ_DISABLESWITCHTOBUTTON

Input only: This flag disables the Switch To... button.

BZ_DISABLERETRYBUTTON

Input only: This flag disables the Retry button.

BZ_NOTRESPONDINGDIALOG

Input only: This flag generates a Not Responding dialog instead of a Busy dialog. The text is slightly different, and the Cancel button is disabled.

hWndOwner

Identifies the window that owns the dialog box. It should not be NULL.

lpszCaption

Points to a string to be used as the title of the dialog box. If NULL, then the library uses Busy.

lpfnHook

Points to a hook function that processes messages intended for the dialog box. The hook function must return zero to pass a message that it didn't process back to the dialog box procedure in the library. The hook function must return a non zero value to prevent the library's dialog box procedure from processing a message it has already processed.

lCustData

Specifies application-defined data that the library passes to the hook function pointed to by the lpfnHook member. The library passes a pointer to the OLEUIBUSY structure in the lParam parameter of the WM_INITDIALOG message; this pointer can be used to retrieve the lCustData member.

hInstance

Identifies an instance that contains a dialog box template specified by the lpTemplateName member.

lpszTemplate

Points to a null-terminated string that specifies the name of the resource file for the dialog box template that is to be substituted for the library's Busy dialog box template.

hResource

A customized template handle.

hTask Input only:

A handle to the task that is blocking.

lphWndDialog

The dialog box's HWND is placed here.

See Also

OleUIBusy


OLEUICHANGEICON

The OLEUICHANGEICON structure contains information that the OLE 2.01 User Interface Library uses to initialize the Change Icon dialog box, and it contains space for the library to return information when the dialog box is dismissed.

typedef struct tagOLEUICHANGEICON

{

// These IN fields are standard across all OLEUI dialog functions.
DWORD  cbStruct;

DWORD  dwFlags;

HWND  hWndOwner;

LPCSTR  lpszCaption;

LPFNOLEUIHOOK  lpfnHook;

LPARAM  lCustData;

HINSTANCE  hInstance;

LPCSTR  lpszTemplate;

HRSRC  hResource;

 // Specifics for OLEUICHANGEICON.

HGLOBAL  hMetaPict;

CLSID  clsid;

char  szIconExe[OLEUI_CCHPATHMAX];

int  cchIconExe;

} OLEUICHANGEICON, *POLEUICHANGEICON, FAR *LPOLEUICHANGEICON;

Members

cbStruct

The size of the structure in bytes. This field must be filled on input.

dwFlags

On input, dwFlags specifies the initialization and creation flags. On exit, it specifies the user's choices. It can be a combination of the following flags:

CIF_SHOWHELP

Specifies that the dialog box will display a Help button.

CIF_SELECTCURRENT

On input, selects the Current radio button on initialization. On exit, specifies that the user selected Current.

CIF_SELECTDEFAULT

On input, selects the Default radio button on initialization. On exit, specifies that the user selected Default.

CIF_SELECTFROMFILE

On input, selects the From File radio button on initialization. On exit, specifies that the user selected From File.

CIF_USEICONEXE

Input only. Extracts the icon from the executable specified in the szIconExe member, instead of retrieving it from the class. This is useful for OLE embedding or linking to non-OLE files.

hWndOwner

Identifies the window that owns the dialog box. It should not be NULL.

lpszCaption

Points to a string to be used as the title of the dialog box. If NULL, then the library uses Change Icon.

lpfnHook

Points to a hook function that processes messages intended for the dialog box. The hook function must return zero to pass a message that it didn't process back to the dialog box procedure in the library. The hook function must return a non-zero value to prevent the library's dialog box procedure from processing a message it has already processed.

lCustData

Specifies application-defined data that the library passes to the hook function pointed to by the lpfnHook member. The library passes a pointer to the OLEUICHANGEICON structure in the lParam parameter of the WM_INITDIALOG message; this pointer can be used to retrieve the lCustData member.

hInstance

Identifies an instance that contains a dialog box template specified by the lpTemplateName member.

lpszTemplate

Points to a null-terminated string that specifies the name of the resource file for the dialog box template that is to be substituted for the library's Change Icon dialog box template.

hResource

A customized template handle.

hMetaPict

The current and final image. The source of the icon is embedded in the metafile itself.

clsid

Input only. The class to use to get the Default icon.

szIconExe

Input only. The executable to extract the default icon from. This member is ignored unless CIF_USEICONEXE is included in the dwFlags parameter and an attempt to retrieve the class icon from the specified CLSID fails.

cchIconExe

Input only. The number of characters in szIconExe. This member is ignored unless CIF_USEICONEXE is included in the dwFlags member.

See Also

OleUIChangeIcon


OLEUICHANGESOURCE

This structure is used to initialize the standard Change Source dialog box. It allows the user to modify the destination or source of a link. This may simply entail selecting a different file name for the link, or possibly changing the item reference within the file, for example, changing the destination range of cells within spreadsheet that the link is to.

typedef struct tagOLEUICHANGESOURCEW

{

// These IN fields are standard across all OLEUI dialog functions.	DWORD  cbStruct;

DWORDT  dwFlags;

HWND    hWndOwner;

LPCWSTR  lpszCaption;

LPFNOLEUIHOOK  lpfnHook;

LPARAM  lCustData;

HINSTANCE  hInstance;

LPCWSTR  lpszTemplate;

HRSRC  hResource;

// INTERNAL ONLY: do not modify these members

OPENFILENAMEW*  lpOFN;

DWORD  dwReserved1[4];

// Specifics for OLEUICHANGESOURCE.

LPOLEUILINKCONTAINERW  lpOleUILinkContainer;

DWORD  dwLink;

LPTSTR  lpszDisplayName;

ULONG  nFileLength;

LPTSTR  lpszFrom;

LPTSTR  lpszTo;

} OLEUICHANGESOURCEW, *POLEUICHANGESOURCEW, FAR *LPOLEUICHANGESOURCEW;

Members

cbStruct

The size of the structure in bytes.

dwFlags

On input, this field specifies the initialization and creation flags. On exit, it specifies the user's choices. It may be a combination of the following flags:

CSF_SHOWHELP

Enables or shows the Help button.

CSF_VALIDSOURCE

Indicates that the link was validated.

CSF_ONLYGETSOURCE

Disables automatic validation of the link source when the user presses OK. If you specify this flag, you should validate the source when the dialog box returns OK.

hWndOwner

Identifies the window that owns the dialog box.

lpszCaption

Points to a string to be used as the title of the dialog box. If NULL, then the library uses Change Source.

lpfnHook

Points to a hook function that processes messages intended for the dialog box. The hook function must return zero to pass a message that it didn't process back to the dialog box procedure in the library. The hook function must return a non zero value to prevent the library's dialog box procedure from processing a message it has already processed.

lCustData

Specifies application-defined data that the library passes to the hook function pointed to by the lpfnHook member. The library passes a pointer to the OLEUICHANGEICON structure in the lParam parameter of the WM_INITDIALOG message; this pointer can be used to retrieve the lCustData member.

hInstance

Identifies a instance that contains a dialog box template specified by the lpszTemplate member. This member is ignored if the lpszTemplate member is NULL or invalid.

lpszTemplate

Points to a null-terminated string that specifies the name of the resource file for the dialog box template that is to be substituted for the library's Convert dialog box template.

hResource

The resource handle for a custom dialog. If this member is NULL, then the library uses the standard Convert dialog template, or if it is valid, the template named by the lpszTemplate member.

lpOFN

Points to the OPENFILENAME structure, which contains information used by the operating system to initialize the system-defined Open or Save As dialog boxes.

dwReserved1[4]

Reserved for future use.

lpOleUILinkContainer

Pointsto the container's implementation of the IOleUILinkContainer Interface; used to validate the link source. The Edit Links dialog uses this to allow the container to manipulate its links.

dwLink

A container-defined unique 32-bit link identifier used to validate link sources. Used by lpOleUILinkContainer.

lpszDisplayName

Points to the complete source display name.

nFileLength

This is the file moniker portion of lpszDisplayName.

lpszFrom

The prefix of the source that was changed from.

lpszTo

The prefix of the source to be changed to.

See Also

IOleUILinkContainer, OleUIChangeSource


OLEUICOINVERT
OLEUICONVERT

The OLEUICONVERT structure contains information that the OLE 2.01 User Interface Library uses to initialize the Convert dialog box, and space for the library to return information when the dialog is dismissed.

typedef struct tagOLEUICONVERT

{

// These IN fields are standard across all OLEUI dialog functions.
DWORD  cbStruct

DWORD  dwFlags

HWND  hWndOwner

LPCSTR  lpszCaption

LPFNOLEUIHOOK  lpfnHook

LPARAM  lCustData

HINSTANCE hInstance

LPCSTR  lpszTemplate

HRSRC  hResource

// Specifics for OLEUICONVERT.

CLSID  clsid;

CLSID  clsidConvertDefault;

CLSID  clsidActivateDefault;

CLSID  clsidNew;

DWORD  dvAspect;

WORD  wFormat;

BOOL  fIsLinkedObject;

HGLOBAL  hMetaPict;

LPTSTR  lpszUserType;

BOOL  fObjectsIconChanged;

LPTSTR  lpszDefLabel

UINT  cClsidExclude

LPCLSID  lpClsidExclude

} OLEUICONVERT, *POLEUICONVERT, FAR *LPOLEUICONVERT;

Members

cbStruct

The size of the structure, in bytes. This field must be filled on input.

dwFlags

On input, this field specifies the initialization and creation flags. On exit, it specifies the user's choices. It may be a combination of the following flags:

CF_SHOWHELPBUTTON

Specifies that the dialog will display a Help button. This flag is set on input.

CF_SETCONVERTDEFAULT

Specifies that the class whose CLSID is specified by clsidConvertDefault will be used as the default selection. This selection appears in the class listbox when the Convert To radio button is selected. This flag is set on input.

CF_SETACTIVATEDEFAULT

Specifies that the class whose CLSID is specified by clsidActivateDefault will be used as the default selection. This selection appears in the class listbox when the Activate As radio button is selected. This flag is set on input.

CF_SELECTCONVERTTO

On input, this flag specifies that Convert To will be initially selected (default behavior). This flag is set on output if Convert To was selected when the user dismissed the dialog.

CF_SELECTACTIVATEAS

On input, this flag specifies that Activate As will be initially selected. This flag is set on output if Activate As was selected when the user dismissed the dialog.

CF_DISABLEDISPLAYASICON

Specifies that the Display As Icon button will be disabled on initialization.

CF_DISABLEACTIVATEAS

Specifies that the Activate As radio button will be disabled on initialization.

CF_HIDECHANGEICON

Hides the Change Icon button in the Convert dialog.

CF_CONVERTONLY

Disables the Activate As radio button in the Convert dialog.

hWndOwner

Identifies the window that owns the dialog box. It should not be NULL.

lpszCaption

Points to a string to be used as the title of the dialog box. If NULL, then the library uses Convert.

lpfnHook

Points to a hook function that processes messages intended for the dialog box. The hook function must return zero to pass a message that it didn't process back to the dialog box procedure in the library. The hook function must return a non-zero value to prevent the library's dialog box procedure from processing a message it has already processed.

lCustData

Specifies application-defined data that the library passes to the hook function pointed to by the lpfnHook member. The library passes a pointer to the OLEUICONVERT structure in the lParam parameter of the WM_INITDIALOG message; this pointer can be used to retrieve the lCustData member.

hInstance

Identifies a instance that contains a dialog box template specified by the lpszTemplate member. This member is ignored if the lpszTemplate member is NULL or invalid.

lpszTemplate

Points to a null-terminated string that specifies the name of the resource file for the dialog box template that is to be substituted for the library's Convert dialog box template.

hResource

The resource handle for a custom dialog. If this member is NULL, then the library uses the standard Convert dialog template, or if it is valid, the template named by the lpszTemplate member.

clsid

The CLSID of the object to be converted or activated. This member is set on input.

clsidConvertDefault

The CLSID to use as the default class when Convert To is selected. This member is ignored if the dwFlags member does not include CF_SETCONVERTDEFAULT. This member is set on input.

clsidActivateDefault

The CLSID to use as the default class when Activate As is selected. This member is ignored if the dwFlags member does not include CF_SETACTIVATEDEFAULT. This member is set on input.

clsidNew

The CLSID of the selected class. This member is set on output.

dvAspect

The aspect of the object. This must be either DVASPECT_CONTENT or DVASPECT_ICON. If dvAspect is DVASPECT_ICON on input, then the Display As Icon box is checked and the object's icon is displayed. This member is set on input and output.

wFormat

The data format of the object to be converted or activated.

fIsLinkedObject

TRUE if the object is linked. This member is set on input.

hMetaPict

The METAFILEPICT containing the iconic aspect. This member is set on input and output.

lpszUserType

The User Type name of the object to be converted or activated. If this value is NULL, then the dialog will retrieve the User Type name from the registry. This string is freed on exit.

fObjectsIconChanged

TRUE if the object's icon changed. (that is, if OleUIChangeIcon was called and not canceled.). This member is set on output.

lpszDefLabel

The default label to use for the icon. If NULL, the short user type name will be used. If the object is a link, the caller should pass the Display Name of the link source. This is freed on exit.

cClsidExclude

The number of CLSIDs in lpClsidExclude.

lpClsidExclude

The list of CLSIDs to exclude from the list.

See Also

OleUIConvert, OleUIChangeIcon


OLEUIEDITLINKS

The OLEUIEDITLINKS structure contains information that the OLE 2.01 User Interface Library uses to initialize the Edit Links dialog box, and contains space for the library to return information when the dialog is dismissed.

typedef struct tagOLEUIEDITLINKS

{

// These IN fields are standard across all OLEUI dialog functions.
DWORD  cbStruct;

DWORD  dwFlags;

HWND  hWndOwner;

LPCSTR  lpszCaption;

LPFNOLEUIHOOK  lpfnHook;

LPARAM  lCustData;

HINSTANCE  hInstance;

LPCSTR  lpszTemplate;

HRSRC  hResource;

// Specifics for OLEUIEDITLINKS.

LPOLEUILINKCONTAINER  	lpOleUILinkContainer;

} OLEUIEDITLINKS, *POLEUIEDITLINKS, FAR *LPOLEUIEDITLINKS;

Members

cbStruct

The size of the structure in bytes. This field must be filled on input.

dwFlags

On input, dwFlags specifies the initialization and creation flags. It may be a combination of the following flags:

ELF_SHOWHELP

Specifies that the dialog will display a Help button.

ELF_DISABLEUPDATENOW

Specifies that the Update Now button will be disabled on initialization.

ELF_DISABLEOPENSOURCE

Specifies that the Open Source button will be disabled on initialization.

ELF_DISABLECHANGESOURCE

Specifies that the Change Source button will be disabled on initialization.

ELF_DISABLECANCELLINK

Specifies that the Cancel Link button will be disabled on initialization.

hWndOwner

Identifies the window that owns the dialog box. It should not be NULL.

lpszCaption

Points to a string to be used as the title of the dialog box. If NULL, then the library uses Links.

lpfnHook

Points to a hook function that processes messages intended for the dialog box. The hook function must return zero to pass a message that it didn't process back to the dialog box procedure in the library. The hook function must return a non-zero value to prevent the library's dialog box procedure from processing a message it has already processed.

lCustData

Specifies application-defined data that the library passes to the hook function pointed to by the lpfnHook member. The library passes a pointer to the OLEUIEDITLINKS structure in the lParam parameter of the WM_INITDIALOG message; this pointer can be used to retrieve the lCustData member.

hInstance

Identifies an instance that contains a dialog box template specified by the lpTemplateName member.

lpszTemplate

Points to a null-terminated string that specifies the name of the resource file for the dialog box template that is to be substituted for the library's Edit Links dialog box template.

hResource

A customized template handle.

lpOleUILinkContainer

Points to the container's implementation of the IOleUILinkContainer Interface. The Edit Links dialog uses this to allow the container to manipulate its links.

See Also

IOleUILinkContainer, OleUIEditLinks


OLEUIGNRLPROPS

This structure is used to initialize the General tab of the Object Properties dialog box. A reference to it is passed in as part of the OLEUIOBJECTPROPS structure to the OleUIObjectProperties function. This tab shows the type and size of an OLE embedding and allows it the user to tunnel to the convert dialog box. This tab also shows the link destination if the object is a link.

typedef struct tagOLEUIGNRLPROPS

{

// These IN fields are standard across all OLEUI property pages.	DWORD  cbStruct;

DWORD  dwFlags;

DWORD  dwReserved1[2];

LPFNOLEUIHOOK  lpfnHook;

LPARAM  lCustData;

DWORD  dwReserved2[3];

struct tagOLEUIOBJECTPROPSW* lpOP;

} OLEUIGNRLPROPSW, *POLEUIGNRLPROPSW, FAR* LPOLEUIGNRLPROPSW;

Members

cbStruct

The size of the structure in bytes. This field must be filled on input.

dwFlags

There are currently no flags associated with this member. It should be set to 0 (zero).

dwReserved1[2]

Reserved for future use.

lpfnHook

Points to a hook function that processes messages intended for the dialog box. The hook function must return zero to pass a message that it didn't process back to the dialog box procedure in the library. The hook function must return a non zero value to prevent the library's dialog box procedure from processing a message it has already processed.

lCustData

Specifies application-defined data that the library passes to the hook function pointed to by the lpfnHook member during WM_INITDIALOG.

dwReserved2[3]

Reserved for future use.

struct tagOLEUIOBJECTPROPSW* lpOP

Used internally.

See Also

OleUIObjectProperties, OLEUIOBJECTPROPS


OLEUIINSERTOBJECT

The OLEUIINSERTOBJECT structure contains information that the OLE 2.01 User Interface Library uses to initialize the Insert Object dialog box, and space for the library to return information when the dialog is dismissed.

typedef struct tagOLEUIINSERTOBJECT
{
// These IN fields are standard across all OLEUI dialog functions.
DWORD  cbStruct;
DWORD  dwFlags;
HWND  hWndOwner;
LPCSTR  lpszCaption;
LPFNOLEUIHOOK  lpfnHook;
LPARAM  lCustData;
HINSTANCE  hInstance;
LPCSTR  lpszTemplate;
HRSRC  hResource;
CLSID  clsid;

// Specifics for OLEUIINSERTOBJECT.
LPTSTR  lpszFile;
UINT  cchFile;
UINT  cClsidExclude;
LPCLSID  lpClsidExclude;
IID  iid;

// Specific to create objects if flags say so
DWORD  oleRender;
LPFORMATETC  lpFormatEtc;
LPOLECLIENTSITE  lpIOleClientSite;
LPSTORAGE  lpIStorage;
LPVOID FAR *  ppvObj;
SCODE  sc;
HGLOBAL  hMetaPict;
} OLEUIINSERTOBJECT, *POLEUIINSERTOBJECT, FAR *LPOLEUIINSERTOBJECT;

Members

cbStruct

Size of the structure in bytes. This field must be filled on input.

dwFlags

On input, specifies the initialization and creation flags. On exit, specifies the user's choices. It can be a combination of the following flags:

IOF_SHOWHELP

Specifies that the dialog will display a Help button.

IOF_SELECTCREATENEW

Specifies that the Create New radio button will initially be checked. This cannot be used with IOF_SELECTCREATEFROMFILE.

IOF_SELECTCREATEFROMFILE

Specifies that the Create From File radio button will initially be checked. This cannot be used with IOF_SELECTCREATENEW.

IOF_CHECKLINK

Specifies that the Link check box will initially be checked.

IOF_CHECKDISPLAYASICON

Specifies that the Display As Icon check box will initially be checked, the current icon will be displayed, and the Change Icon button will be enabled.

IOF_CREATENEWOBJECT

Specifies that a new object should be created when the user selects OK to dismiss the dialog box and the Create New radio button was selected.

IOF_CREATEFILEOBJECT

Specifies that a new object should be created from the specified file when the user selects OK to dismiss the dialog box and the Create From File radio button was selected.

IOF_CREATELINKOBJECT

Specifies that a new linked object should be created when the user selects OK to dismiss the dialog box and the user checked the Link check box.

IOF_DISABLELINK

Specifies that the Link check box will be disabled on initialization.

IOF_VERIFYSERVERSEXIST

Specifies that the dialog box should validate the classes it adds to the listbox by ensuring that the server specified in the registration database exists. This is a significant performance factor.

IOF_DISABLEDISPLAYASICON

Specifies that the Display As Icon check box will be disabled on initialization.

IOF_HIDECHANGEICON

Hides the Change Icon button in the Insert Object dialog.

IOF_SHOWINSERTCONTROL

Displays the Insert Control radio button.

IOF_SELECTCREATECONTROL

Displays the Create Control radio button.

hWndOwner

Identifies the window that owns the dialog box. It should not be NULL.

lpszCaption

Points to a string to be used as the title of the dialog box. If NULL, then the library uses Insert Object.

lpfnHook

Points to a hook function that processes messages intended for the dialog box. The hook function must return zero to pass a message that it didn't process back to the dialog box procedure in the library. The hook function must return a non zero value to prevent the library's dialog box procedure from processing a message it has already processed.

lCustData

Specifies application-defined data that the library passes to the hook function pointed to by the lpfnHook member. The library passes a pointer to the OLEUIINSERTOBJECT structure in the lParam parameter of the WM_INITDIALOG message; this pointer can be used to retrieve the lCustData member.

hInstance

Identifies an instance that contains a dialog box template specified by the lpTemplateName member.

lpszTemplate

Points to a null-terminated string that specifies the name of the resource file for the dialog box template that is to be substituted for the library's Insert Object dialog box template.

hResource

A customized template handle.

clsid

CLSID for class of the object to be inserted. Filled on output.

lpszFile

Points to the name of the file linked to or insert. Filled on output.

cchFile

The size of lpszFile buffer; will not exceed OLEUI_CCHPATHMAX.

cClsidExclude

The number of CLSIDs included in the lpClsidExclude list. Filled on input.

lpClsidExclude

A list of CLSIDs to exclude from listing.

iid

The identifier of the requested interface. If OleUIInsertObject creates the object, then it will return a pointer to this interface. This parameter is ignored if OleUIInsertObject does not create the object.

oleRender

The rendering option. If OleUIInsertObject creates the object, then it selects the rendering option when it creates the object. This parameter is ignored if OleUIInsertObject does not create the object.

lpFormatEtc

The desired format. If OleUIInsertObject creates the object, then it selects the format when it creates the object. This parameter is ignored if OleUIInsertObject does not create the object.

lpIOleClientSite

Points to the client site to be used for the object. This parameter is ignored if OleUIInsertObject does not create the object.

lpIStorage

Points to the storage to be used for the object This parameter is ignored if OleUIInsertObject does not create the object.

ppvObj

Points to the location where the pointer to the object is returned. This parameter is ignored if OleUIInsertObject does not create the object.

sc

The result of creation calls. This parameter is ignored if OleUIInsertObject does not create the object.

hMetaPict

MetafilePict structure containing the iconic aspect, if it wasn't placed in the object's cache.

See Also

OleUIInsertObject


OLEUILINKPROPS

This structure is used to initialize the Link tab of the Object Properties dialog box.  A reference to it is passed in as part of the OLEUIOBJECTPROPS structure to the OleUIObjectProperties function. This tab shows the location, update status, and update time for a link. It allows the user to change the source of the link, toggle its update status between automatic and manual update, open the source, force an update of the link, or break the link (convert it to a static picture).

// These IN fields are standard across all OLEUI property pages.

typedef struct tagOLEUILINKPROPSW

{

// These IN fields are standard across all OLEUI property pages.
DWORD  cbStruct;

DWORD  dwFlags;

DWORD  dwReserved1[2];

LPFNOLEUIHOOK  lpfnHook;

LPARAM  lCustData;

DWORD  dwReserved2[3];

struct tagOLEUIOBJECTPROPSW* lpOP;

} OLEUILINKPROPSW, *POLEUILINKPROPSW, FAR* LPOLEUILINKPROPSW;

cbStruct

Size of the structure in bytes.

dwFlags

Contains in-out flags specific to the links page.

dwReserved1[2];

Reserved for future use.

lpfnHook

Hook callback (not used in this dialog).

lCustData

Custom data to pass to hook (not used in this dialog).

dwReserved2[3]

Reserved for future use.

struct tagOLEUIOBJECTPROPS* lpOP;

Used internally.

See Also

OleUIObjectProperties, OLEUIOBJECTPROPS


OLEUIOBJECTPROPS

This structure is used to initialize the standard Object Properties dialog box. It contains references to interfaces used to gather information about the embedding or link, references to three structures that are used to initialize the default tabs—General (OLEUIGNRLPROPS), View (OLEUIVIEWPROPS), and Link (OLEUILINKPROPS), if appropriate—and a standard property-sheet extensibility interface that allows the caller to add additional custom property sheets to the dialog.

typedef struct tagOLEUIOBJECTPROPS

{

// These IN fields are standard across all OLEUI property sheets.

DWORD	cbStruct;

DWORD	dwFlags;

// Standard PROPSHEETHEADER used for extensibility

LPPROPSHEETHEADER	lpPS;

// Data which allows manipulation of the object

DWORD	dwObject;

LPOLEUIOBJINFO	lpObjInfo;

// Data which allows manipulation of the link

DWORD	dwLink;

LPOLEUILINKINFO	lpLinkInfo;

// Data specfic to each page

LPOLEUIGNRLPROPS	lpGP;

LPOLEUIVIEWPROPS	lpVP;

LPOLEUILINKPROPS	lpLP;

} OLEUIOBJECTPROPS, *POLEUIOBJECTPROPS, FAR* LPOLEUIOBJECTPROPS;

cbStruct

Size of the structure in bytes.

dwFlags

These are the in-out: global flags for the property sheet.

OPF_OBJECTISLINK

The object is a link object and therefore has a link property page.

OPF_NOFILLDEFAULT

Do not fill in default values for the object.

OPF_SHOWHELP

Specifies that the dialog box will display a Help button.

OPF_DISABLECONVERT

Disable the Convert button on the general property page.

lpPS

[in]The standard property sheet header (PROPSHEETHEADER), used for extensibility.

//Data which allows manipulation of the object

dwObject

[in] identifier for the object

lpObjInfo

[in] interface to manipulate object

//Data which allows manipulation of the link

dwLink;

[in] A container-defined unique 32-bit identifier for a single link. Containers can use the pointer to the link's container site for this value.

lpLinkInfo

[in] interface to manipulate link

// Data specific to each page

lpGP

[in] General page data.

lpVP

[in] View page data

lpLP

[in] Link page data.

See Also

OleUIObjectProperties, OLEUIGNRLPROPS, OLEUIVIEWPROPS, OLEUILINKPROPS


OLEUIPASTEENTRY

This structure is an array of OLEUIPASTEENTRY entries specified in the OLEUIPASTESPECIAL structure for the Paste Special dialog box. Each entry includes a FORMATETC which specifies the formats that are acceptable, a string that is to represent the format in the dialog box's listbox, a string to customize the result text of the dialog, and a set of flags from the OLEUIPASTEFLAG enumeration. The flags indicate if the entry is valid for pasting only, linking only or both pasting and linking. If the entry is valid for linking, the flags indicate which link types are acceptable by OR'ing together the appropriate OLEUIPASTE_LINKTYPE<#> values. These values correspond to the array of link types as follows:

OLEUIPASTE_LINKTYPE1=arrLinkTypes[0]
OLEUIPASTE_LINKTYPE2=arrLinkTypes[1]
OLEUIPASTE_LINKTYPE3=arrLinkTypes[2]
OLEUIPASTE_LINKTYPE4=arrLinkTypes[3]
OLEUIPASTE_LINKTYPE5=arrLinkTypes[4]
OLEUIPASTE_LINKTYPE6=arrLinkTypes[5]
OLEUIPASTE_LINKTYPE7=arrLinkTypes[6]
OLEUIPASTE_LINKTYPE8=arrLinkTypes[7]

arrLinkTypes[] is an array of registered clipboard formats for linking. A maximum of eight link types are allowed.

typedef struct tagOLEUIPASTEENTRY

{

FORMATETC   fmtetc;

LPCSTR  lpstrFormatName;

LPCSTR  lpstrResultText;

DWORD  dwFlags;

DWORD  dwScratchSpace;

} OLEUIPASTEENTRY, *POLEUIPASTEENTRY, FAR *LPOLEUIPASTEENTRY;

Members

fmtetc

The format that is acceptable. The Paste Special dialog checks if this format is offered by the object on the clipboard and if so, offers it for selection to the user.

lpstrFormatName

The string that represents the format to the user. Any %s in this string is replaced by the FullUserTypeName of the object on the clipboard and the resulting string is placed in the list box of the dialog. Only one %s is allowed. The presence or absence of %s specifies whether the result-text is to indicate that data is being pasted or that an object that can be activated by an application is being pasted. If %s is present, the resulting text says that an object is being pasted. Otherwise it says that data is being pasted.

lpstrResultText

The string used to customize the resulting text of the dialog when the user selects the format corresponding to this entry. Any %s in this string is replaced by the application name or FullUserTypeName of the object on the clipboard. Only one %s is allowed.

dwFlags

The values from OLEUIPASTEFLAG enumeration.

dScratchSpace

The scratch space available to routines that loop through an   IEnumFORMATETC* to mark if the PasteEntry format is available. This field CAN be left uninitialized.

See Also

OLEUIPASTEFLAG, OleUIPasteSpecial, OLEUIPASTESPECIAL


OLEUIPASTESPECIAL

The OLEUIPASTESPECIAL structure contains information that the OLE 2.01 User Interface Library uses to initialize the Paste Special dialog box, as well as space for the library to return information when the dialog is dismissed.

typedef struct tagOLEUIPASTESPECIAL

{

// These IN fields are standard across all OLEUI dialog functions.	DWORD  cbStruct;

DWORD  dwFlags;

HWND  hWndOwner;

LPCSTR  lpszCaption;

LPFNOLEUIHOOK  lpfnHook;

LPARAM  lCustData;

HINSTANCE  hInstance;

LPCSTR  lpszTemplate;

HRSRC  hResource;

// Specifics for OLEUIPASTESPECIAL.

LPDATAOBJECT  lpSrcDataObj;

LPOLEUIPASTEENTRY  arrPasteEntries;

int  cPasteEntries;

UINT FAR *  arrLinkTypes;

int  cLinkTypes;

UINT  cClsidExclude;

LPCLSID  lpClsidExclude;

int  nSelectedIndex;

BOOL	  fLink;

HGLOBAL	  hMetaPict;

SIZEL  sizel;

} OLEUIPASTESPECIAL, *POLEUIPASTESPECIAL, FAR *LPOLEUIPASTESPECIAL;

Members

cbStruct

The size of the structure, in bytes. This field must be filled on input.

dwFlags

On input, dwFlags specifies the initialization and creation flags. On exit, it specifies the user's choices. It may be a combination of the following flags:

PSF_SHOWHELP

Specifies that the dialog will display a Help button.

PSF_SELECTPASTE

Selects the Paste radio button at dialog startup. This is the default, if PSF_SELECTPASTE or PSF_SELECTPASTELINK are not specified. Also, it specifies the state of the button on dialog termination. IN/OUT flag.

PSF_SELECTPASTELINK

Selects the PasteLink radio button at dialog startup. Also, specifies the state of the button on dialog termination. IN/OUT flag.

PSF_CHECKDISPLAYASICON

Specifies whether the Display As Icon radio button was checked on dialog termination. OUT flag.

PSF_DISABLEDISPLAYASICON

Specifies that the Display As Icon check box will be disabled on initialization.

HIDECHANGEICON

Used to disable the change-icon button in the dialog, which is available to users when they're pasting an OLE object by default. See STAYONCLIPBOARDCHANGE otherwise.

STAYONCLIPBOARDCHANGE

Used to tell the dialog to stay up if the clipboard changes while the dialog is up. If the user switches to another application and copies or cuts something, the dialog will, by default, perform a cancel operation, which will remove the dialog since the options it's in the middle of presenting to the user are no longer up-to-date with respect to what's really on the clipboard.

NOREFRESHDATAOBJECT

Used in conjunction with STAYONCLIPBOARDCHANGE (it doesn't do anything otherwise). If the clipboard changes while the dialog box is up and STAYONCLIPBOARDCHANGE is specified, then NOREFRESHDATAOBJECT indicates that the dialog should NOT refresh the contents of the dialog to reflect the new contents of the clipboard. This is useful if the application is using the paste-special dialog on an IDataObject besides the one on the clipboard, for example, as part of right-mouse drag/drop operation.

hWndOwner

Identifies the window that owns the dialog box. It should not be NULL.

lpszCaption

Points to a string to be used as the title of the dialog box. If NULL, then the library uses Paste Special.

lpfnHook

Points to a hook function that processes messages intended for the dialog box. The hook function must return zero to pass a message that it didn't process back to the dialog box procedure in the library. The hook function must return a non zero value to prevent the library's dialog box procedure from processing a message it has already processed.

lCustData

Specifies application-defined data that the library passes to the hook function pointed to by the lpfnHook member. The library passes a pointer to the OLEUIPASTESPECIAL structure in the lParam parameter of the WM_INITDIALOG message; this pointer can be used to retrieve the lCustData member.

hInstance

Identifies a instance that contains a dialog box template specified by the lpTemplateName member.

lpszTemplate

Points to a null-terminated string that specifies the name of the resource file for the dialog box template that is to be substituted for the library's Paste Special dialog box template.

hResource

Customized template handle.

lpsrcDataObj

The source IDataObject* (on the clipboard) for data to paste. This field is filled on input. If lpSrcDataObj is NULL when OleUIPasteSpecial is called, then OleUIPasteSpecial will attempt to retrieve a pointer to an IDataObject from the clipboard. If OleUIPasteSpecial succeeds, it is the caller's responsibility to free the IDataObject returned in lpSrcDataObj.

arrPasteEntries

The OLEUIPASTEENTRY array which specifies acceptable formats. This field is filled on input.

cPasteEntries

The number of OLEUIPASTEENTRY array entries. This field is filled on input.

arrLinkTypes

A list of link types that are acceptable. Link types are referred to using OLEUIPASTEFLAG in arrPasteEntries. This field is filled on input.

cLinkTypes

The number of link types. This field is filled on input.

cClsidExclude

The number of CLSIDs in lpClsidExclude. This field is filled on input.

lpClsidExclude

An array of CLSIDs to exclude from the list of available server objects for a Paste operation. Note that this does not affect Paste Link. An application can prevent embedding into itself by listing its own CLSID in this list. This field is filled on input.

nSelectedIndex

Index of arrPasteEntries[] that the user selected. This field is filled on output.

fLink

Indicates whether Paste or Paste Link was selected by the user. This field is filled on output.

hMetaPict

The handle to the Metafile containing the icon and icon title selected by the user. This field is filled on output.

sizel

The size of object as displayed in its source, if the display aspect chosen by the user matches the aspect displayed in the source. If the user chooses a different aspect, then sizel.cx and sizel.cy are both set to zero. The size of the object as it is displayed in the source is retrieved from the ObjectDescriptor if fLink is FALSE and from the LinkSrcDescriptor if fLink is TRUE. This field is filled on output.

See Also

OleUIPasteSpecial, OLEUIPASTEENTRY, OLEUIPASTEFLAG


OLEUIVIEWPROPS

This structure is used to initialize the View tab of the Object properties dialog box. A reference to it is passed in as part of the OLEUIOBJECTPROPS structure to the OleUIObjectProperties function. This tab allows the user to toggle between "content" and "iconic" views of the object, and change its scaling within the container. It also allows the user to tunnel to the change icon dialog when the object is being displayed iconically.

// These IN fields are standard across all OLEUI property pages.

typedef struct tagOLEUIVIEWPROPSA

{

// These IN fields are standard across all OLEUI property pages.
DWORD  cbStruct;

DWORD  dwFlags;

DWORD  dwReserved1[2];

LPFNOLEUIHOOK  lpfnHook;

LPARAM  lCustData;

DWORD  dwReserved2[3];

struct tagOLEUIOBJECTPROPS* lpOP;

int   nScaleMin;

int   nScaleMax;

} OLEUIVIEWPROPSA, *POLEUIVIEWPROPSA, FAR* LPOLEUIVIEWPROPSA;

Members

cbStruct

Size of the structure in bytes.

dwFlags

IN-OUT: flags specific to view page

VPF_SELECTRELATIVE

[in] Relative to origin.

VPF_DISABLERELATIVE

[in] Disable relative to origin.

VPF_DISABLESCALE

[in] Disable scale option.

dwReserved1[2]

Reserved for future use.

lpfnHook

Hook callback (not used in this dialog).

lCustDataa

Custom data to pass to hook (not used in this dialog).

dwReserved2[3];

Reserved for future use.

struct tagOLEUIOBJECTPROPS* lpOP;

Used internally.

nScaleMin

Minimum value for the scale range.

nScaleMax

Maximum value for the scale range.

See Also

OleUIObjectProperties, OLEUIOBJECTPROPS


OLEVERB

The OLEVERB structure is used in the IEnumOLEVERB interface to return information describing a verb for an object. Defined in the IEnumOLEVERB interface (eoverb.idl).

typedef struct tagOLEVERB
{
LONG lVerb;
LPWSTR lpszVerbName;
DWORD fuFlags;
DWORD grfAttribs;
} OLEVERB, * LPOLEVERB;

Members

lVerb

Specifies the integer ID associated with this verb.

lpszVerbName

Points to a string that contains the verb's name.

fuFlags

grfAttribs

Specifies some combination of the verb attributes in the OLEVERBATTRIB enumeration.

See Also

IEnumOLEVERB, IOleObject


RemSNB

The RemSNB structure is used for marshaling the SNB data type.

Defined in the IStorage interface (storag.idl).

typedef struct tagRemSNB {
unsigned long ulCntStr;
unsigned long ulCntChar;
[size_is(ulCntChar)] wchar_t rgString[];
} RemSNB;
typedef [transmit_as(RemSNB)] wchar_t **SNB;

Members

ulCntStr

Specifies the number of strings in the rgString buffer.

ulCntChar

Specifies the size in bytes of the rgString buffer.

rgString

Points to an array of bytes containing the stream name strings from the SNB.

See Also

IStorage


SNB

A string name block (SNB) is a pointer to an array of pointers to strings, that ends in a NULL pointer. String name blocks are used the IStorage interface and API calls that open storage objects. The strings point to contained storage objects or streams that are to be excluded in the open calls.

typedef OLESTR **SNB

Comments

The SNB should be created by allocating a contiguous block of memory in which the pointers to strings are followed by a NULL pointer, which is then followed by the actual strings.

The marshalling of a string name block is based on the assumption that the SNB passed in was created this way. Although it could be stored in other ways, the SNB created in this manner has the advantage of requiring only one allocation operation and one freeing of memory for all the strings.

See Also

IStorage


STATDATA

The STATDATA structure is the data structure used to specify each advisory connection. It is used for enumerating current advisory connections. It holds data returned by the IEnumSTATDATA enumerator. This enumerator interface is returned by IDataObject:DAdvise. Each advisory connection is specified by a unique STATDATA structure.

Defined in com.h.

typedef struct tagSTATDATA
{
FORMATETC formatetc;
DWORD grfAdvf;
IAdviseSink* pAdvSink;
DWORD dwConnection;
} STATDATA;

Members

formatetc

Specifies the FORMATETC structure for the data of interest to the advise sink. The advise sink receives notification of changes to the data specified by this FORMATETC structure.

grfAdvf

Specifies the ADVF enumeration value that determines when the advisory sink is notified of changes in the data.

pAdvSink

Specifies the pointer for the IAdviseSink interface that will receive change notifications.

dwConnection

Specifies the token that uniquely identifies the advisory connection. This token is returned by the method that sets up the advisory connection.

See Also

IEnumSTATDATA


STATSTG

The STATSTG structure contains statistical information about an open storage, stream, or byte array object. This structure is used in the IEnumSTATSTG, ILockBytes, IStorage, and IStream interfaces.

Defined in the IStream interface (stream.idl).

typedef struct tagSTATSTG
{
LPWSTR pwcsName;
DWORD type;
ULARGE_INTEGER cbSize;
FILETIME mtime;
FILETIME ctime;
FILETIME atime;
DWORD grfMode;
DWORD grfLocksSupported;
CLSID clsid;
DWORD grfStateBits;
DWORD dwStgFmt;
} STATSTG;

Members

pwcsName

Points to a NULL-terminated string containing the name. Space for this string is allocated by the method called and freed by the caller. You can specify not to return this member by specifying the STATFLAG_NONAME value when you call a method that returns a STATSTG structure.

type

Indicates the type of storage object. This is one of the values from the STGTY enumeration.

cbSize

Specifies the size in bytes of the stream or byte array. Undefined for storage objects; zero is returned for storage objects.

mtime

Indicates the last modification time for this storage, stream, or byte array.

ctime

Indicates the creation time for this storage, stream, or byte array.

atime

Indicates the last access time for this storage, stream or byte array.

grfMode

Indicates the access mode specified when the object was opened. This member is only valid in calls to Stat methods.

grfLocksSupported

Indicates the types of region locking supported by the stream or byte array. See the LOCKTYPES enumeration for the values available. This member is not used for storage objects.

clsid

Indicates the class identifier for the storage object; set to CLSID_NULL for new storage objects. This member is not used for streams or byte arrays.

grfStateBits

Indicates the current state bits of the storage object, that is, the value most recently set by the IStorage::SetStateBits method. This member is not valid for streams or byte arrays.

dwStgFmt

Indicates the format of the storage object. This is one of the values from the STGFMT enumeration.

See Also

IStorage::SetElementTimes


STGMEDIUM

The STGMEDIUM structure is a generalized global memory handle used for data transfer operations by the IAdviseSink, IDataObject, and IOleCache interfaces.

Defined in the IAdviseSink interface (advsnk.idl).

typedef struct tagSTGMEDIUM
{
DWORD tymed;
[switch_type(DWORD), switch_is((DWORD) tymed)]
union {
[case(TYMED_GDI)] HBITMAP hBitmap;
[case(TYMED_MFPICT)] HMETAFILEPICT hMetafilePict;
[case(TYMED_ENHMF)] HENHMETAFILE hEnhMetaFile;
[case(TYMED_HGLOBAL)] HGLOBAL hGlobal;
[case(TYMED_FILE)] LPWSTR lpszFileName;
[case(TYMED_ISTREAM)] IStream *pstm;
[case(TYMED_ISTORAGE)] IStorage *pstg;
[default] ;
};
[unique] IUnknown *pUnkForRelease;
}STGMEDIUM;
typedef STGMEDIUM *LPSTGMEDIUM;

Members

tymed

Indicates the type of storage medium. The marshaling and unmarshaling routines use this value to determine which union member was used. This value must be one of the elements of the TYMED enumeration.

union member

Specifies a handle, string, or interface pointer that the receiving process can use to access the data being transferred. If tymed is TYMED_NULL, the union member is undefined; otherwise, it is one of the following:

hBitmap

Specifies a bitmap handle. The tymed member is TYMED_GDI.

hMetafilePict

Specifies a metafile handle. The tymed member is TYMED_MFPICT.

hEnhMetaFile

Specifies an enhanced metafile handle. The tymed member is TYMED_ENHMF.

hGlobal

Specifies a global memory handle. The tymed member is TYMED_HGLOBAL.

lpszFileName

Specifies the path of a disk file that contains the data. The tymed member is TYMED_FILE.

pstm

Specifies an IStream instance. The tymed member is TYMED_ISTREAM.

pstg

Specifies an IStorage instance. The tymed member is TYMED_ISTORAGE.

pUnkForRelease

Points to an interface instance that allows the sending process to control the way the storage is released when the receiving process calls the ReleaseStgMedium API function. If pUnkForRelease is NULL, ReleaseStgMedium uses default procedures to release the storage; otherwise, ReleaseStgMedium uses the specified IUnknown interface.

See Also

FORMATETC, IAdviseSink, IDataObject, IOleCache, ReleaseStgMedium


ADVF

The ADVF enumeration values are flags used by a container object to specify the requested behavior when setting up an advise sink or a caching connection with an object. These values have different meanings depending on the type of connection in which they are used, and each interface uses its own subset of the flags.

typedef enum tagADVF
{
ADVF_NODATA            = 1,
ADVF_PRIMEFIRST        = 4,
ADVF_ONLYONCE          = 2,
ADVF_DATAONSTOP        = 64,
ADVFCACHE_NOHANDLER    = 8,
ADVFCACHE_FORCEBUILTIN = 16,
ADVFCACHE_ONSAVE       = 32
} ADVF;

Elements

ADVF_NODATA

For data advisory connections (IDataObject::DAdvise or IDataAdviseHolder::Advise), this flag requests the data object not to send data when it calls IAdviseSink::OnDataChange. The recipient of the change notification can later request the data by calling IDataObject::GetData. The data object can honor the request by passing TYMED_NULL in the STGMEDIUM parameter, or it can provide the data anyway. For example, the data object might have multiple advisory connections, not all of which specified ADVF_NODATA, in which case the object might send the same notification to all connections. Regardless of the container's request, its IAdviseSink implementation must check the STGMEDIUM parameter because it is responsible for releasing the medium if it is not TYMED_NULL.

For cache connections (IOleCache::Cache), this flag requests that the cache not be updated by changes made to the running object. Instead, the container will update the cache by explicitly calling IOleCache::SetData. This situation typically occurs when the iconic aspect of an object is being cached.

ADVF_NODATA is not a valid flag for view advisory connections (IViewObject::SetAdvise) and it returns E_INVALIDARG.

ADVF_PRIMEFIRST

Requests that the object not wait for the data or view to change before making an initial call to IAdviseSink::OnDataChange (for data or view advisory connections) or updating the cache (for cache connections). Used with ADVF_ONLYONCE, this parameter provides an asynchronous GetData call.

ADVF_ONLYONCE

Requests that the object make only one change notification or cache update before deleting the connection.

ADVF_ONLYONCE automatically deletes the advisory connection after sending one data or view notification. The advisory sink receives only one IAdviseSink call. A nonzero connection ID is returned if the connection is established so the caller can use it to delete the connection prior to the first change notification.

For data change notifications, the combination of ADVF_ONLYONCE and ADVF_PRIMEFIRST provides, in effect, an asynchronous IDataObject::GetData call.

When used with caching, ADVF_ONLYONCE updates the cache one time only, on receipt of the first OnDataChange notification. After the update is complete, the advisory connection between the object and the cache is disconnected. The source object for the advisory connection calls the IAdviseSink::Release method.

ADVF_DATAONSTOP

For data advisory connections, assures accessibility to data. This flag indicates that when the data object is closing, it should call IAdviseSink::OnDataChange providing data with the call. Typically, this value is used in combination with ADVF_NODATA. Without this value, by the time an OnDataChange call without data reaches the sink, the source might have completed its shutdown and the data might not be accessible. Sinks that specify this value should accept data provided in OnDataChange if it is being passed, because they may not get another chance to retrieve it.

For cache connections, this flag indicates that the object should update the cache as part of object closure.

ADVF_DATAONSTOP is not a valid flag for view advisory connections.

ADVFCACHE_NOHANDLER

Synonym for ADVFCACHE_FORCEBUILTIN, which is used more often.

ADVFCACHE_FORCEBUILTIN

This value is used by DLL object applications and object handlers that perform the drawing of their objects. ADVFCACHE_FORCEBUILTIN instructs OLE to cache presentation data to ensure that there is a presentation in the cache. This value is not a valid flag for data or view advisory connections. For cache connections, this flag caches data that requires only code shipped with OLE (or the underlying operating system) to be present in order to produce it with IDataObject::GetData or IViewObject::Draw. By specifying this value, the container can ensure that the data can be retrieved even when the object or handler code is not available.

ADVFCACHE_ONSAVE

For cache connections, this flag updates the cached representation only when the object containing the cache is saved. The cache is also updated when the OLE object transitions from the running state back to the loaded state (because a subsequent save operation would require rerunning the object). This value is not a valid flag for data or view advisory connections.

Comments

For a data or view advisory connection, the container uses the ADVF constants when setting up a connection between an IAdviseSink instance and and either an IDataObject or IViewObject instance. These connections are set up using the IDataObject::DAdvise, IDataAdviseHolder::Advise, or IViewObject::SetAdvise methods.

For a caching connection, the constants are specified in the IOleCache::Cache method to indicate the container's requests on how the object should update its cache.

These constants are also used in the advf member of the STATDATA structure. This structure is used by IEnumSTATDATA to describe the enumerated connections, and the advf member indicates the flags that were specified when the advisory or cache connection was established. When STATDATA is used for an IOleObject::EnumAdvise enumerator, the advf member is indeterminate.

See Also

IDataAdviseHolder, IDataObject, IEnumSTATDATA, IOleCache, IViewObject


BIND_FLAGS

The BIND_FLAGS enumeration values are used to control aspects of moniker binding operations. The values are used in the BIND_OPTS structure . Callers of IMoniker methods can specify values from this enumeration, and implementors of IMoniker methods can use these values in determining what they should do.

The BIND_FLAGS enumeration is defined in OBJIDL.IDL.

typedef enum tagBIND_FLAGS
{
BIND_MAYBOTHERUSER     = 1,
BIND_JUSTTESTEXISTENCE = 2,
} BIND_FLAGS;

Elements

BIND_MAYBOTHERUSER

If this flag is specified, the moniker implementation can interact with the end user. If not present, the moniker implementation should not interact with the user in any way, such as by asking for a password for a network volume that needs mounting. If prohibited from interacting with the user when it otherwise would, a moniker implementation can use a different algorithm that does not require user interaction, or it can fail with the error MK_MUSTBOTHERUSER.

BIND_JUSTTESTEXISTENCE

If this flag is specified, the caller is not interested in having the operation carried out, but only in learning whether the operation could have been carried out had this flag not been specified. For example, this flag lets the caller indicate only an interest in finding out whether an object actually exists by using this flag in a IMoniker::BindToObject call. Moniker implementations can, however, ignore this possible optimization and carry out the operation in full. Callers must be able to deal with both cases.

See Also

BIND_OPTS, IBindCtx


BINDSPEED

The BINDSPEED enumeration values indicate approximately how long the caller will wait to bind to an object. Callers of the IOleItemContainer::GetObject method specify values from this enumeration, and implementors of that method use these values as a guideline for how quickly they must complete their operation.

The BINDSPEED enumeration is defined in OLEIDL.IDL.

typedef enum tagBINDSPEED
{
BINDSPEED_INDEFINITE   = 1,
BINDSPEED_MODERATE     = 2,
BINDSPEED_IMMEDIATE    = 3
} BINDSPEED;

Elements

BINDSPEED_INDEFINITE

Indicates that there is no time limit on the binding operation.

BINDSPEED_MODERATE

Indicates that the IOleItemContainer::GetObject operation must be completed in a moderate amount of time. If this flag is specified, the implementation of IOleItemContainer::GetObject should return MK_E_EXCEEEDEDDEADLINE unless the object is one of the following:

•	Already in the running state

•	A pseudo-object (i.e., an object internal to the item container, such as a cell-range in a spreadsheet or a character-range in a word processor).

•	An object supported by an in-process server (so it is always in the running state when it is loaded). In this case, IOleItemContainer::GetObject should load the designated object, and, if the OleIsRunning API function indicates that the object is running, return successfully.

BINDSPEED_IMMEDIATE

Indicates that the caller will wait only a short time. In this case, IOleItemContainer::GetObject should return MK_E_EXCEEEDEDDEADLINE unless the object is already in the running state or is a pseudo-object.

Comments

The system-supplied item moniker implementation is the primary caller of IOleItemContainer::GetObject. The BINDSPEED value that it specifies depends on the deadline specified by the caller of the moniker operation.

The deadline is stored in the dwTickCountDeadline field of the BIND_OPTS structure in the bind context passed to the moniker operation. This value is based on the return value of the GetTickCount API function. If dwTickCountDeadline is zero, indicating no deadline, the item moniker implementation specifies BINDSPEED_INDEFINITE. (This is the default dwTickCountDeadline value for a bind context returned by the CreateBindCtx API function.) If the difference between dwTickCountDeadline and the value returned by the GetTickCount API function is greater than 2500, the item moniker implementation specifies BINDSPEED_MODERATE. If the difference is less than 2500, the item moniker implementation specifies BINDSPEED_IMMEDIATE.

Implementations of IOleItemContainer::GetObject can use the BINDSPEED value as a shortcut approximation of the binding deadline, or they can use the IBindCtx instance parameter to determine the exact deadline.

See Also

BIND_OPTS, IBindCtx::GetBindOptions, IOleItemContainer::GetObject


CALLTYPE

The CALLTYPE enumeration constants are the call type used by IMessageFilter::HandleInComingCall.

Defined in the IMessageFilter interface (msgflt.idl).

typedef enum tagCALLTYPE
{
CALLTYPE_TOPLEVEL             = 1,
CALLTYPE_NESTED               = 2,
CALLTYPE_ASYNC                = 3,
CALLTYPE_TOPLEVEL_CALLPENDING = 4,
CALLTYPE_ASYNC_CALLPENDING    = 5
} CALLTYPE;

Elements

CALLTYPE_TOPLEVEL

toplevel call − no outgoing call

CALLTYPE_NESTED

callback on behalf of previous outgoing call − should always handle

CALLTYPE_ASYNC

aysnchronous call − can NOT be rejected

CALLTYPE_TOPLEVEL_CALLPENDING

new toplevel call with new LID

CALLTYPE_ASYNC_CALLPENDING

async call − can NOT be rejected

See Also

IMessageFilter::HandleInComingCall, IMessageFilter


CLSCTX

The CLSCTX enumeration constants specify the execution context for a class object. Different pieces of code can be associated with one CLSID for use in different execution contexts.

typedef enum tagCLSCTX
{
CLSCTX_INPROC_SERVER   = 1,
CLSCTX_INPROC_HANDLER  = 2,
CLSCTX_LOCAL_SERVER    = 4
} CLSCTX;

Elements

CLSCTX_INPROC_SERVER

The code that creates and manages objects of this class runs in the same process as the caller of the function specifying the class context.

CLSCTX_INPROC_HANDLER

The code that manages objects of this class is an in-process handler. This is a DLL that runs in the client process and implements client-side structures of this class when instances of the class are accessed remotely.

CLSCTX_LOCAL_SERVER

The EXE code that creates and manages objects of this class is loaded in a separate process space (runs on same machine but in a different process).

To indicate that multiple contexts are acceptable, you can string multiple values together with boolean ORs. The contexts are tried in the order in which they are listed.

The following table shows the use and reasons for CLSCTX values in calls to CoGetClassObject, which is used in the implementation of other OLE functions:

Function Called	Context Flag Used
OleLoad	CLSCTX_INPROC_HANDLER | CLSCTX_INPROC_SERVER Putting an OLE object into the loaded state requires in-process access; but, it doesn't matter if all of the object's function is presently available.
IRunnableObject::Run	CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER Running an OLE object requires connecting to the full code of the object wherever it is located.
CoUnMarshalInterface	CLSCTX_INPROC_HANDLER   Unmarshalling needs the form of the class designed for remote access.
See Also

CoCreateInstance, CoGetClassObject, CoRegisterClassObject


DATADIR

The DATADIR enumeration values specify the formats for which the IDataObject::EnumFormatEtc method supplies an enumerator. The values are used in the dwDirection parameter used in a call to the IDataObject::EnumFormatEtc method.

typedef enum tagDATADIR
{
DATADIR_GET = 1,
DATADIR_SET = 2
} DATADIR;

Elements

DATADIR_GET

Requests that IDataObject::EnumFormatEtc supply an enumerator for the formats that can be specified in IDataObject::GetData.

DATADIR_SET

Requests that IDataObject::EnumFormatEtc supply an enumerator for the formats that can be specified in IDataObject::SetData.

See Also

IDataObject


DISCARDCACHE

The DISCARDCACHE enumeration values are used in the IOleCache2::DiscardCache method to specify what to do with caches that are to be discarded from memory if their dirty bit has been set. The dwDiscardOptions parameter specifies whether or not to save these caches.

Defined in the

typedef enum tagDISCARDCACHE
{
DISCARDCACHE_SAVEIFDIRTY    = 0,
DISCARDCACHE_NOSAVE         = 1
} DISCARDCACHE;

Elements

DISCARDCACHE_SAVEIFDIRTY

Indicates that the cache is to be saved to disk.

DISCARDCACHE_NOSAVE

Indicates that the cache can be discarded without saving it.

See Also

IOleCache2::DiscardCache


DROPEFFECT

The DoDragDrop function and many of the methods in the IDropSource and IDropTarget interfaces pass information about the effects of a drag-and-drop operation in a DROPEFFECT enumeration.

Valid drop effect values are the result of applying the OR operation to the values contained in the DROPEFFECT enumeration:

typedef enum tagDROPEFFECT
{

DROPEFFECT_NONE   = 0,

DROPEFFECT_COPY   = 1,

DROPEFFECT_MOVE   = 2,

DROPEFFECT_LINK   = 4,

DROPEFFECT_SCROLL = 0x80000000,

}DROPEFFECT;

These values have the following meaning:

DROPEFFECT name	Value	Description
DROPEFFECT_NONE	0	Drop target cannot accept the data.
DROPEFFECT_COPY	1	Drop results in a copy. The original data is untouched by the drag source.
DROPEFFECT_MOVE	2	Drag source should remove the data.
DROPEFFECT_LINK	4	Drag source should create a link to the original data.
DROPEFFECT_SCROLL	0x80000000	Scrolling is about to start or is currently occurring in the target. This value is used in addition to the other values.
Note  Your application should always mask values from the DROPEFFECT enumeration to ensure compatibility with future implementations. Presently, only four of the 32 bit positions in a DROPEFFECT have meaning. In the future, more interpretations for the bits will be added. Drag sources and drop targets should carefully mask these values appropriately before comparing. They should never compare a DROPEFFECT against, say, DROPEFFECT_COPY by

if (dwDropEffect == DROPEFFECT_COPY)...

Instead, the application should always mask for the value or values being sought:

if (dwDropEffect & DROPEFFECT_COPY) == DROPEFFECT_COPY)...

or

if (dwDropEffect & DROPEFFECT_COPY)...

This allows for the definition of new drop effects, while preserving backwards compatibility with existing code.

See Also

DoDragDrop, IDropSource, IDropTarget


DVASPECT

The DVASPECT enumeration values specify the desired data or view aspect of the object when drawing or getting data.

typedef enum tagDVASPECT
{
DVASPECT_CONTENT    = 1,
DVASPECT_THUMBNAIL  = 2,
DVASPECT_ICON       = 4,
DVASPECT_DOCPRINT   = 8
} DVASPECT;

Elements

DVASPECT_CONTENT

Provide a representation of an object so it can be displayed as an embedded object inside of a container. This value is typically specified for compound document objects. The presentation can be provided for the screen or printer.

DVASPECT_THUMBNAIL

Provide a thumbnail representation of an object so it can be displayed in a browsing tool. The thumbnail is approximately a 120 by 120 pixel, 16-color (recommended) device-independent bitmap potentially wrapped in a metafile.

DVASPECT_ICON

Provide an iconic representation of an object.

DVASPECT_DOCPRINT

Provide a representation of the object on the screen as though it were printed to a printer using the Print command from the File menu. The described data may represent a sequence of pages.

Comments

This enumeration is used in the dwAspect field of the FORMATETC structure. Only one DVASPECT value can be used to specify a single presentation aspect in a FORMATETC structure. The FORMATETC structure is used in IDataObject, IAdviseSink, and IOleCache methods. The DVASPECT enumeration values are also used in IViewObject methods.

See Also

IAdviseSink, IDataObject, IOleObject, IViewObject, IViewObject2, OleDraw, FORMATETC, OBJECTDESCRIPTOR


EXTCONN

The EXTCONN enumeration specifies the type of external connection existing on an embedded object. Currently, the only supported type is EXTCONN_STRONG, meaning that the external connection is a link. This EXTCONN constant is used in the IExternalConnection::AddConnection and IExternalConnection::ReleaseConnection methods.

typedef enum tagEXTCONN
{
EXTCONN_STRONG  	= 0X0001,
EXTCONN_WEAK  	= 0X0002,
EXTCONN_CALLABLE	= 0X0004
} EXTCONN;

Elements

EXTCONN_STRONG

If this value is specified, the external connection must keep the object alive until all strong external connections are cleared through IExternalConnection::ReleaseConnection.

EXTCONN_WEAK

This value is currently not used.

EXTCONN_CALLABLE

This value is currently not used.


LOCKTYPE

The LOCKTYPE enumeration values indicate the type of locking requested for the specified range of bytes. The values are used in the ILockBytes::LockRegion and IStream::LockRegion methods.

Defined in the IStream interface (stream.idl).

typedef enum tagLOCKTYPE
{
LOCK_WRITE      = 1,
LOCK_EXCLUSIVE  = 2,
LOCK_ONLYONCE   = 4
} LOCKTYPE;

Elements

LOCK_WRITE

If this lock is granted, the specified range of bytes can be opened and read any number of times, but writing to the locked range is prohibited except for the owner that was granted this lock.

LOCK_EXCLUSIVE

If this lock is granted, writing to the specified range of bytes is prohibited except for the owner that was granted this lock.

LOCK_ONLYONCE

If this lock is granted, no other LOCK_ONLYONCE lock can be obtained on the range. Usually this lock type is an alias for some other lock type. Thus, specific implementations can have additional behavior associated with this lock type.


MKRREDUCE

The MKRREDUCE enumeration constants are used to specify how far the moniker should be reduced. They are used in the IMoniker::Reduce method. MKRREDUCE is defined in OBJIDL.IDL.

typedef enum tagMKRREDUCE
{
MKRREDUCE_ONE          = 3<<16,
MKRREDUCE_TOUSER       = 2<<16,
MKRREDUCE_THROUGHUSER  = 1<<16,
MKRREDUCE_ALL          = 0
} MKRREDUCE;

Elements

MKRREDUCE_ONE

Performs only one step of reducing the moniker. In general, the caller must have specific knowledge about the particular kind of moniker to take advantage of this option.

MKRREDUCE_TOUSER

Reduce the moniker to a form that the user identifies as a persistent object. If no such point exists, then this option should be treated as MKRREDUCE_ALL.

MKRREDUCE_THROUGHUSER

Reduce the moniker to where any further reduction would reduce it to a form that the user does not identify as a persistent object. Often, this is the same stage as MKRREDUCE_TOUSER.

MKRREDUCE_ALL

Reduce the moniker until it is in simplest form, that is, reduce it to itself.

See Also

IMoniker::Reduce


MKSYS

The MKSYS enumeration constants indicate the moniker's class. They are returned from the IMoniker::IsSystemMoniker method. MKSYS is defined in OBJIDL.IDL.

typedef enum tagMKSYS

{
MKSYS_NONE               = 0,
MKSYS_GENERICCOMPOSITE	   = 1,
MKSYS_FILEMONIKER        = 2,
MKSYS_ANTIMONIKER        = 3,
MKSYS_ITEMMONIKER        = 4,
MKSYS_POINTERMONIKER     = 5
} MKSYS;

Elements

MKSYS_NONE

Indicates a custom moniker implementation.

MKSYS_GENERICCOMPOSITE

Indicates the system's generic composite moniker class.

MKSYS_FILEMONIKER

Indicates the system's file moniker class.

MKSYS_ANTIMONIKER

Indicates the system's anti-moniker class.

MKSYS_ITEMMONIKER

Indicates the system's item moniker class.

MKSYS_POINTERMONIKER

Indicates the system's pointer moniker class.

See Also

IMoniker::IsSystemMoniker


MSHCTX

The MSHCTX enumeration constants specify the destination context, that is, the process in which the unmarshaling is to be done. These flags are used in the IMarshal and IStdMarshalInfo interfaces and in the CoMarshalInterface and CoGetStandardMarshal API functions.

MSHCTX is defined in WTYPES.IDL.

typedef enum tagMSHCTX
{
MSHCTX_LOCAL              = 0,
MSHCTX_NOSHAREDMEM        = 1,
MSHCTX_DIFFERENTMACHINE   = 2,
MSHCTX_INPROC             = 3
} MSHCTX;

Elements

MSHCTX_LOCAL

The unmarshaling process is local and has shared memory access with the marshaling process.

MSHCTX_NOSHAREDMEM

The unmarshaling process does not have shared memory access with the marshaling process.

MSHCTX_DIFFERENTMACHINE

The unmarshaling process is on a different machine. The marshaling code cannot assume that a particular piece of application code is installed on that machine.

MSHCTX_INPROC

The unmarshaling will be done in another apartment in the same process. If your object supports multiple threads, your custom marshaler can pass a direct pointer instead of creating a proxy object.

See Also

CoGetStandardMarshal, CoMarshalInterface, IMarshal, IStdMarshalInfo


MSHLFLAGS

The MSHLFLAGS enumeration constants determine why the marshaling is to be done. These flags are used in the IMarshal interface and the CoMarshalInterface and CoGetStandardMarshal API functions.

MSHFLAGS is defined in WTYPES.IDL.

typedef enum tagMSHLFLAGS
{
MSHLFLAGS_NORMAL          = 0,
MSHLFLAGS_TABLESTRONG     = 1,
MSHLFLAGS_TABLEWEAK       = 2
} MSHLFLAGS;

Elements

MSHLFLAGS_NORMAL

The marshaling is occurring because an interface pointer is being passed from one process to another. This is the normal case. The data packet produced by the marshaling process will be unmarshaled in the destination process. The marshaled data packet can be unmarshaled just once, or not at all. If the receiver unmarshals the data packet successfully, the CoReleaseMarshalData API function is automatically called on the data packet as part of the unmarshaling process. If the receiver does not or cannot unmarshal the data packet, the sender must call the CoReleaseMarshalData API function on the data packet.

MSHLFLAGS_TABLESTRONG

The marshaling is occurring because the data packet is to be stored in a globally-accessible table from which it can be unmarshaled one or more times, or not at all. The presence of the data packet in the table counts as a strong reference to the interface being marshaled, meaning that it is sufficient to keep the object alive. When the data packet is removed from the table, the table implementor must call the CoReleaseMarshalData API function on the data packet.

MSHLFLAGS_TABLESTRONG is used by the RegisterDragDrop API function when registering a window as a drop target. This keeps the window registered as a drop target no matter how many times the end-user drags across the window. The RevokeDragDrop API function calls CoReleaseMarshalData.

MSHLFLAGS_TABLEWEAK

The marshaling is occurring because the data packet is to be stored in a globally-accessible table from which it can be unmarshaled one or more times, or not at all. However, the presence of the data packet in the table acts as a weak reference to the interface being marshaled, meaning that it is not sufficient to keep the object alive. When the data packet is removed from the table, the table implementor must call the CoReleaseMarshalData API function on the data packet.

MSHLFLAGS_TABLEWEAK is typically used when registering an object in the Running Object Table (ROT). This prevents the object's entry in the ROT from keeping the object alive in the absence of any other connections. See IRunningObjectTable::Register for more information.

See Also

CoGetStandardMarshal, CoMarshalInterface, IMarshal


OLECLOSE

The OLECLOSE enumeration constants are used in the IOleObject::Close method to determine whether the object should be saved before closing. These are defined ole2.h and in the IOleObject interface (oleobj.idl).

typedef enum tagOLECLOSE
{
OLECLOSE_SAVEIFDIRTY  = 0,
OLECLOSE_NOSAVE       = 1,
OLECLOSE_PROMPTSAVE   = 2
} OLECLOSE;

Elements

OLECLOSE_SAVEIFDIRTY

Indicates that the object should be saved if it is dirty.

OLECLOSE_NOSAVE

Indicates that the object should not be saved, even if it is dirty. This flag is typically used when an object is being deleted.

OLECLOSE_PROMPTSAVE

Indicates that if the object is dirty, the IOleObject::Close implementation should display a dialog to let the end user determine whether to save the object. However, if the object is in the running state but its user interface is invisible, the the end user should not be prompted, and the close should be handled as if OLECLOSE_SAVEIFDIRTY had been specified.

See Also

IOleObject::Close


OLECONTF

The OLECONTF enumeration indicate the kind of objects to be enumerated by the returned IEnumUnknown interface. OLECONTF contains a set of bitwise constants used in the IOleContainer::EnumObjects method.

typedef enum tagOLECONTF
{
OLECONTF_EMBEDDINGS    = 1;
OLECONTF_LINKS         = 2;
OLECONTF_OTHERS        = 4;
OLECONTF_ONLYUSER      = 8;
OLECONTF_ONLYIFRUNNING = 16
} OLECONTF;

Elements

OLECONTF_EMBEDDINGS

Enumerate the embedded objects in the container.

OLECONTF_LINKS

Enumerate the linked objects in the container.

OLECONTF_OTHERS

Enumerate all objects in the container that are not OLE compound document objects (i.e.; objects other than linked or embedded objects). Use this flag to enumerate the container's pseudo-objects.

OLECONTF_ONLYUSER

Enumerate only those objects the user is aware of. For example; hidden named-ranges in Microsoft Excel would not be enumerated using this value.

OLECONTF_ONLYIFRUNNING

Enumerate only those linked or embedded objects that are currently in the running state for this container.

See Also

IEnumUnknown, IOleContainer::EnumObjects


OLEGETMONIKER

The OLEGETMONIKER enumeration constants indicate the requested behavior of the IOleObject::GetMoniker and IOleClientSite::GetMoniker methods. These constants are defined in ole2.h and in the IOleObject interface (oleobj.idl).

typedef enum tagOLEGETMONIKER
{
OLEGETMONIKER_ONLYIFTHERE = 1,
OLEGETMONIKER_FORCEASSIGN = 2,
OLEGETMONIKER_UNASSIGN    = 3,
OLEGETMONIKER_TEMPFORUSER = 4
} OLEGETMONIKER;

Elements

OLEGETMONIKER_ONLYIFTHERE

Indicates that if a moniker for the object or container does not exist, GetMoniker should return E_FAIL and not assign a moniker.

OLEGETMONIKER_FORCEASSIGN

Indicates that if a moniker for the object or container does not exist, GetMoniker should create one.

OLEGETMONIKER_UNASSIGN

Indicates that IOleClientSite::GetMoniker can release the object's moniker (although it is not required to do so). This constant is not valid in IOleObject::GetMoniker.

OLEGETMONIKER_TEMPFORUSER

Indicates that if a moniker for the object does not exist, IOleObject::GetMoniker can create a temporary moniker that can be used for display purposes (IMoniker::GetDisplayName) but not for binding. This is enables the object server to return a descriptive name for the object without incurring the overhead of creating and maintaining a moniker until a link is actually created.

Comments

If the OLEGETMONIKER_FORCEASSIGN flag causes a container to create a moniker for the object, the container should notify the object by calling the IOleObject::SetMoniker method.

See Also

IMoniker, IOleClientSite::GetMoniker, IOleObject::GetMoniker


OLELINKBIND

The OLELINKBIND enumeration constants control binding operations to a link source. They are used in the IOleLink::BindToSource method, and OLELINKBIND is defined in OLEIDL.IDL.

typedef enum tagOLELINKBIND
{
    OLELINKBIND_EVENIFCLASSDIFF = 1,
} OLELINKBIND;

Element

OLELINKBIND_EVENIFCLASSDIFF

Indicates that the binding operation should proceed even if the current class of the link source is different from the last time the link was bound. For example, the link source could be a Lotus spreadsheet that was converted to an Excel spreadsheet.

See Also

IOleLink::BindToSource


OLEMISC

The OLEMISC enumeration is a set of bitwise constants that can be combined to describe miscellaneous characteristics of an object or class of objects. A container can call the IOleObject::GetMiscStatus method to determine the OLEMISC bits set for an object. The values specified in an object server's CLSID\MiscStatus entry in the registration database are based on the OLEMISC enumeration. These constants are also used in the dwStatus member of the OBJECTDESCRIPTOR structure. OLEMISC is defined in ole2.h and in the IOleObject interface (oleobj.idl).

typedef enum tagOLEMISC // bitwise
{
OLEMISC_RECOMPOSEONRESIZE            = 1,
OLEMISC_ONLYICONIC                   = 2,
OLEMISC_INSERTNOTREPLACE             = 4,
OLEMISC_STATIC                       = 8,
OLEMISC_CANTLINKINSIDE               = 16,
OLEMISC_CANLINKBYOLE1                = 32,
OLEMISC_ISLINKOBJECT                 = 64,
OLEMISC_INSIDEOUT                    = 128,
OLEMISC_ACTIVATEWHENVISIBLE          = 256
OLEMISC_RENDERINGISDEVICEINDEPENDENT = 512
} OLEMISC;

Elements

OLEMISC_RECOMPOSEONRESIZE

Indicates that when the container resizes the space allocated to displaying one of the object's presentations, the object wants to recompose the presentation. This means that on resize, the object wants to do more than scale its picture. If this bit is set, the container should force the object to the running state and call IOleObject::SetExtent with the new size.

OLEMISC_ONLYICONIC

Indicates that the object has no useful content view other than its icon. From the user's perspective, the Display As Icon checkbox (in the Paste Special dialog box) for this object should always be checked, and should not be uncheckable. Note that such an object should still have a drawable content aspect; it will look the same as its icon view.

OLEMISC_INSERTNOTREPLACE

Indicates that the object has initialized itself from the data in the container's current selection. Containers should examine this bit after calling IOleObject::InitFromData to initialize an object from the current selection. If set, the container should insert the object beside the current selection rather than replacing the current selection. If this bit is not set, the object being inserted replaces the current selection.

OLEMISC_STATIC

Indicates that this object is a static object, which is an object that contains only a presentation; it contains no native data. See OleCreateStaticFromData.

OLEMISC_CANTLINKINSIDE

Indicates that this object cannot be the link source that when bound to activates (runs) the object. If the object is selected and copied to the clipboard, the object's container can offer a link in a clipboard data transfer that, when bound, must connect to the outside of the object. The user would see the object selected in its container, not open for editing. Rather than doing this, the container can simply refuse to offer a link source when transferring objects with this bit set. Examples of objects that have this bit set include OLE1 objects, static objects, and links.

OLEMISC_CANLINKBYOLE1

Indicates that this object can be linked to by OLE 1 containers. This bit is used in the dwStatus member of the OBJECTDESCRIPTOR structure transferred with the Object and Link Source Descriptor formats. An object can be linked to by OLE 1 containers if it is an untitled document, a file, or a selection of data within a file. Embedded objects or pseudo-objects that are contained within an embedded object cannot be linked to by OLE 1 containers (i.e., OLE 1 containers cannot link to link sources that, when bound, require more than one object server to be run.

OLEMISC_ISLINKOBJECT

This object is a link object. This bit is significant to OLE 1 and is set by the OLE 2 link object; object applications have no need to set this bit.

OLEMISC_INSIDEOUT

This object is capable of activating in-place, without requiring installation of menus and toolbars to run. Several such objects can be active concurrently. Some containers, such as forms, may choose to activate such objects automatically.

OLEMISC_ACTIVATEWHENVISIBLE

This bit is set only when OLEMISC_INSIDEOUT is set, and indicates that this object prefers to be activated whenever it is visible. Some containers may always ignore this hint.

OLEMISC_RENDERINGISDEVICEINDEPENDENT

This object does not pay any attention to target devices. Its presention data will be the same in all cases.

See Also

IOleObject::GetMiscStatus, OBJECTDESCRIPTOR


OLERENDER

The OLERENDER enumeration constants are used in the various object creation API functions to indicate the type of caching requested for the newly created object.

typedef enum tagOLERENDER
{
OLERENDER_NONE   = 0;
OLERENDER_DRAW   = 1;
OLERENDER_FORMAT = 2;
OLERENDER_ASIS   = 3
} OLERENDER;

Elements

OLERENDER_NONE

The client is not requesting any locally cached drawing or data retrieval capabilities in the object. pFormatEtc is ignored for this option.

OLERENDER_DRAW

The client will draw the content of the object on the screen (a NULL target device) using IViewObject:Draw. The object itself determines the data formats that need to be cached. With this render option, only the ptd and dwAspect members of pFormatEtc are significant, since the object may cache things differently depending on the parameter values. However, pFormatEtc can legally be NULL here, in which case the object is to assume the display target device and the DVASPECT_CONTENT aspect.

OLERENDER_FORMAT

The client will pull one format from the object using IDataObject::GetData(). The format of the data to be cached is passed in pFormatEtc, which may not in this case be NULL.

OLERENDER_ASIS

The client is not requesting any locally cached drawing or data retrieval capabilities in the object. pFormatEtc is ignored for this option. The difference between this and the OLERENDER_FORMAT value is important in such functions as OleCreateFromData() and OleCreateLinkFromData().

See Also

OleCreate, OleCreateFromData, OleCreateFromFile, OleCreateLink, OleCreateLinkFromData, OleCreateLinkToFile, OleCreateStaticFromData


OLEUIPASTEFLAG

This enumeration is used to indicate the user options that are available to the user when pasting this format, and within which group or list of choices (Paste, Paste Link, etc) this entry is to be available. OLEUIPASTEFLAG is used by the OLEUIPASTEENTRY structure. It

typedef enum tagOLEUIPASTEFLAG

{

OLEUIPASTE_ENABLEICON    = 2048,

OLEUIPASTE_PASTEONLY     = 0,

OLEUIPASTE_PASTE         = 512,

OLEUIPASTE_LINKANYTYPE   = 1024,

OLEUIPASTE_LINKTYPE1     = 1,

OLEUIPASTE_LINKTYPE2     = 2,

OLEUIPASTE_LINKTYPE3     = 4,

OLEUIPASTE_LINKTYPE4     = 8,

OLEUIPASTE_LINKTYPE5     = 16,

OLEUIPASTE_LINKTYPE6     = 32,

OLEUIPASTE_LINKTYPE7     = 64,

OLEUIPASTE_LINKTYPE8     = 128

} OLEUIPASTEFLAG;

OLEUIPASTE_ENABLEICON

If the container does not specify this flag for the entry in the OLEUIPASTEENTRYarray passed as input to OleUIPasteSpecial, the DisplayAsIcon button will be unchecked and disabled when the user selects the format that corresponds to the entry.

OLEUIPASTE_PASTEONLY

Indicates that the entry in the OLEUIPASTEENTRY array is valid for pasting only.

OLEUIPASTE_PASTE

Indicates that the entry in the OLEUIPASTEENTRYarray is valid for pasting. It may also be valid for linking if any of the following linking flags are specified. If it is valid for linking, then the following flags indicate which link types are acceptable by OR'ing together the appropriate OLEUIPASTE_LINKTYPE<#> values. These values correspond as follows to the array of link types passed to OleUIPasteSpecial:

OLEUIPASTE_LINKTYPE1=arrLinkTypes[0]

OLEUIPASTE_LINKTYPE2=arrLinkTypes[1]

OLEUIPASTE_LINKTYPE3=arrLinkTypes[2]

OLEUIPASTE_LINKTYPE4=arrLinkTypes[3]

OLEUIPASTE_LINKTYPE5=arrLinkTypes[4]

OLEUIPASTE_LINKTYPE6=arrLinkTypes[5]

OLEUIPASTE_LINKTYPE7=arrLinkTypes[6]

OLEUIPASTE_LINKTYPE8=arrLinkTypes[7]

where,

UINT arrLinkTypes[8] is an array of registered clipboard formats for linking. A maximum of 8 link types is allowed.


OLEUPDATE

The OLEUPDATE enumeration constants are used to indicate whether the linked object updates the cached data for the linked object automatically or only when the container calls either the IOleObject::Update or IOleLink::Update methods. The constants are used in the IOleLink interface.

The OLEUPDATE enumeration is defined in OLEIDL.IDL..

typedef enum tagOLEUPDATE
{
OLEUPDATE_ALWAYS = 1;
OLEUPDATE_ONCALL = 3
} OLEUPDATE;
typedef OLEUPDATE *LPOLEUPDATE;

Elements

OLEUPDATE_ALWAYS

Update the link object whenever possible, this option corresponds to the Automatic update option in the Links dialog box.

OLEUPDATE_ONCALL

Update the link object only when IOleObject::Update or IOleLink::Update is called, this option corresponds to the Manual update option in the Links dialog box.

See Also

IOleLink::SetUpdateOptions, IOleLink::GetUpdateOptions


OLEVERBATTRIB

The OLEVERBATTRIB enumeration constants are used in the OLEVERB structure to describe the attributes of a specified verb for an object. Defined in the IEnumOLEVERB interface (eoverb.idl).

typedef enum tagOLEVERBATTRIB
{
OLEVERBATTRIB_NEVERDIRTIES    = 1,
OLEVERBATTRIB_ONCONTAINERMENU = 2
} OLEVERBATTRIB;

Elements

OLEVERBATTRIB_NEVERDIRTIES

OLEVERBATTRIB_ONCONTAINERMENU

Indicates a verb that should appear in the container's menu of verbs for this object.

See Also

IEnumOLEVERB, OLEVERB


OLEWHICHMK

The OLEWHICHMK enumeration constants indicate which part of an object's moniker is being set or retrieved. These constants are used in the IOleObject and IOleClientSite interfaces, and are defined in ole2.h and in the IOleObject interface (oleobj.idl).

typedef enum tagOLEWHICHMK
{
OLEWHICHMK_CONTAINER = 1,
OLEWHICHMK_OBJREL    = 2,
OLEWHICHMK_OBJFULL   = 3
} OLEWHICHMK;

Elements

OLEWHICHMK_CONTAINER

Indicates the moniker of the object's container, Typically this is a file moniker. This moniker is not persistently stored inside the object, since the container can be renamed even while the object is not loaded.

OLEWHICHMK_OBJREL

Indicates the moniker of the object relative to its container. Typically this is an item moniker, and it is part of the persistent state of the object. If this moniker is composed on to the end of the container's moniker, the resulting moniker is the full moniker of the object.

OLEWHICHMK_OBJFULL

Indicates the full moniker of the object. Binding to this moniker results in a connection to the object. This moniker is not persistently stored inside the object, since the container can be renamed even while the object is not loaded.

See Also

IOleClientSite::GetMoniker, IOleObject::GetMoniker, IOleObject::SetMoniker


PENDINGMSG

The PENDINGMSG enumeration constants are return values of IMessageFilter::MessagePending.

Defined in the IMessageFilter interface (msgflt.idl).

typedef enum tagPENDINGMSG
{
PENDINGMSG_CANCELCALL     = 0,
PENDINGMSG_WAITNOPROCESS  = 1,
PENDINGMSG_WAITDEFPROCESS = 2
} PENDINGMSG;

Elements

PENDINGMSG_CANCELCALL

cancel the outgoing call

PENDINGMSG_WAITNOPROCESS

wait for the return and don't dispatch the message

PENDINGMSG_WAITDEFPROCESS

wait and dispatch the message

See Also

IMessageFilter::MessagePending


PENDINGTYPE

The PENDINGTYPE enumeration constants indicate the level of nesting in the IMessageFilter::MessagePending method.

Defined in the IMessageFilter interface (msgflt.idl).

typedef enum tagPENDINGTYPE
{
PENDINGTYPE_TOPLEVEL = 1,
PENDINGTYPE_NESTED   = 2
} PENDINGTYPE;

Elements

PENDINGTYPE_TOPLEVEL

toplevel call

PENDINGTYPE_NESTED

nested call

See Also

IMessageFilter::MessagePending


REGCLS

The REGCLS enumeration defines flags used in CoRegisterClassObject to control the type of connections to the class object. It is defined as follows:

typedef enum tagREGCLS
{

REGCLS_SINGLEUSE       = 0,

REGCLS_MULTIPLEUSE     = 1,

REGCLS_MULTI_SEPARATE  = 2,

} REGCLS;

Elements

REGCLS_SINGLEUSE

Specifies that once an application has connected to the class object with CoGetClassObject, the class object is removed from public view so that no other applications can connect to it. This flag is commonly used for single document interface (SDI) applications. Specifying this flag does not affect the responsibility of the object application to call CoRevokeClassObject; it must always call CoRevokeClassObject when it is finished with an object class.

REGCLS_MULTIPLEUSE

Specifies that multiple applications can connect to the class object through calls to CoGetClassObject.

REGCLS_MULTI_SEPARATE

Similar to REGCLS_MULTIPLEUSE, except that REGCLS_MULTI_SEPARATE does not automatically register the class object as CLSCTX_INPROC_SERVER for a local server. Instead, it provides separate control over each context. When a class is registered this way, if that server tries to bind to an object with its own class id, it will start another copy of the server.

Comments

In CoRegisterClassObject, members of both the REGCLS and the CLSCTX enumerations, taken together, determine how the class object is registered.

The following table summarizes the allowable flag combinations and the object registrations affected by the combinations:

	REGCLS_ SINGLEUSE	REGCLS_ MULTIPLEUSE	REGCLS_ MULTI_ SEPARATE	Other
CLSCTX_ INPROC_ SERVER	Error	Inproc	Inproc	Error
CLSCTX_ LOCAL_ SERVER	Local	Inproc/local	Local	Error
Both of the above	Error	Inproc/local	Inproc/local	Error
Other	Error	Error	Error	Error
REGCLS_MULTIPLEUSE in combination with CLSCTX_LOCAL_SERVER automatically registers the class object as an in-process server (CLSCTX_INPROC_SERVER). In contrast, registering a class object as a local server and specifying REGCLS_MULTIPLE_SEPARATE does not register the class object as an in-process server (registers the object with the CLSCTX_LOCAL_SERVER flag, but does not automatically add the CLSCTX_INPROC_SERVER flag as is the case when you specify the REGCLS_MULTIPLEUSE flag. This distinction is important in applications that are both OLE containers and OLE embeddings, allowing a container/server to be inserted into itself.

In general, the following two registrations have the same effect -- they register class objects as both multiple-use and as in-process servers:

CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE

(CLSCTX_INPROC_SERVER|CLSCTX_LOCAL_SERVER), REGCLS_MULTI_SEPARATE

The following registers the class object only as a multiple-use local server:

CLSCTX_LOCAL_SERVER, REGCLS_MULTI_SEPARATE

See Also

CoGetClassObject, CoRegisterClassObject, CoRevokeClassObject, DllGetClassObject


SERVERCALL

The SERVERCALL enumeration constants indicate the status of server call − returned by IMessageFilter::HandleInComingCall and passed to IMessageFilter::RetryRejectedCall.

Defined in the IMessageFilter interface (msgflt.idl).

typedef enum tagSERVERCALL
{
SERVERCALL_ISHANDLED  = 0,
SERVERCALL_REJECTED   = 1,
SERVERCALL_RETRYLATER = 2
} SERVERCALL;

Elements

SERVERCALL_ISHANDLED

SERVERCALL_REJECTED

SERVERCALL_RETRYLATER

See Also

IMessageFilter::HandleInComingCall, IMessageFilter::RetryRejectedCall


STATFLAG

The STATFLAG enumeration values indicate whether the method should try to return a name in the pwcsName member of the STATSTG structure. The values are used in the ILockBytes::Stat, IStorage::Stat, and IStream::Stat methods to save memory when the pwcsName member is not needed.

Defined in the IOLETypes pseudo-interface (oletyp.idl).

typedef enum tagSTATFLAG
{
STATFLAG_DEFAULT = 0,
STATFLAG_NONAME  = 1
} STATFLAG;

Elements

STATFLAG_DEFAULT

Requests that the statistics include the pwcsName member of the STATSTG structure.

STATFLAG_NONAME

Requests that the statistics not include the pwcsName member of the STATSTG structure. If the name is omitted, there is no need for the Stat methods to allocate and free memory for the string value for the name and the method can save an Alloc and Free operation.

See Also

ILockBytes::Stat, IStorage::Stat, IStream::Stat


STATSTATE

The STATSTATE enumeration values indicate state information about the storage object and are used as a mask. The values are used in the IStorage::SetStateBits method.

Defined in the ().

typedef enum tagSTATSTATE
{
STATSTATE_DOC = 1,
STATSTATE_CONVERT  = 2,
STATSTATE_FILESTGSAME  = 4
} STATSTATE;

Elements

STATSTATE_DOC

.

Indicates that the storage object is a document file. This bit is set on the root storage object as part of a normal File/Save sequence. With nested storage objects, the application manages the storage objects and sets or clears this bit as appropriate. If the nested object is an embedded object, this bit can be ignored. It is cleared in a newly created storage object. However, some applications might use this bit to enable editing an embedded storage object without first copying the object to the file system. For example, a mail application might set this bit for attachments so the attachments can be edited without copying them first to a file.

STATSTATE_CONVERT

Indicates that a convert operation was done on this storage object while it was in a passive state.

STATSTATE_FILESTGSAME

Indicates that the embedded object and document representations for the storage object are the same. Thus, the storage object can be saved in a document file simply by copying the storage object bits.

See Also

IStorage::SetStateBits.


STGC

The STGC enumeration constants specify the conditions for performing the commit operation in the IStorage::Commit and IStream::Commit methods.

Defined in the IOLETypes pseudo-interface (oletyp.idl).

typedef enum tagSTGC
{
STGC_DEFAULT                            = 0,
STGC_OVERWRITE                          = 1,
STGC_ONLYIFCURRENT                      = 2,
STGC_DANGEROUSLYCOMMITMERELYTODISKCACHE = 4
} STGC;

Elements

STGC_DEFAULT

Indicates that none of the other values apply. You can specify this condition or some combination of the other three. You would use this value mainly to make your code more readable.

STGC_OVERWRITE

Indicates that the commit operation can overwrite existing data to reduce overall space requirements. This value is not recommended for typical usage because it is not as robust as the default case. In this case, it is possible for the commit to fail after the old data is overwritten but before the new data is completely committed. Then, neither the old version nor the new version of the storage object will be intact.

You can use this value in cases where:

•	the user has indicated a willingness to risk losing the data

•	the low memory save sequence will be used to safely save the storage object to a smaller file

•	a previous commit returned STG_E_MEDIUMFULL but overwriting the existing data would provide enough space to commit changes to the storage object

Note that the commit operation checks for adequate space before any overwriting occurs. Thus, even with this value specified, if the commit operation fails due to space requirements, the old data will remain safe. The case where data loss can occur is when the commit operation fails due to some reason other than lack of space and the STGC_OVERWRITE value was specified.

STGC_ONLYIFCURRENT

Prevents multiple users of a storage object from overwriting one another's changes. The commit operation occurs only if there have been no changes to the saved storage object since the user most recently opened the storage object. Thus, the saved version of the storage object is the same version that the user has been editing. If other users have changed the storage object, the commit operation fails and returns the STG_E_NOTCURRENT value. You can override this behavior by calling the Commit method again using the STGC_DEFAULT value.

STGC_DANGEROUSLYCOMMITMERELYTODISKCACHE

Commits the changes to a write-behind disk cache, but does not save the cache to the disk. In a write-behind disk cache, the operation that writes to disk actually writes to a disk cache thus increasing performance. The cache is eventually written to the disk but usually not until after the write operation has already returned. The performance increase comes at the expense of an increased risk of losing data if a problem occurs before the cache is saved and the data in the cache is lost.

If you do not specify this value, then committing changes to root level storage objects is robust even if a disk cache is used. The two-phase commit process ensures that data is stored on the disk and not just to the disk cache.

Comments

You can specify STGC_DEFAULT or some combination of the other three values. Typically, you would use STGC_ONLYIFCURRENT to protect the storage object in cases where more than one user can edit the object simultaneously.

See Also

IStorage, IStream


STGFMT

The STGFMT enumeration values indicate the format of a storage object and are used in the STATSTG structure and in the StgCreateDocFile and StgIsStorageFile API functions.

Defined in the IOLETypes pseudo-interface (oletyp.idl).

typedef enum tagSTGFMT
{
STGFMT_DOCUMENT  = 0,
STGFMT_DIRECTORY = 1,
STGFMT_CATALOG   = 2,
STGFMT_FILE      = 3
} STGFMT;

Elements

STGFMT_DOCUMENT

Indicates a document format.

STGFMT_DIRECTORY

Indicates a directory format.

STGFMT_CATALOG

Indicates a catalog format.

STGFMT_FILE

Indicates a file format.

See Also

STATSTG, StgCreateDocFile, StgIsStorageFile


STGM

The STGM enumeration values are used in the storage and stream interfaces to indicate the conditions for creating and deleting the object and access modes for the object.

Defined in the ().

typedef enum tagSTGM
{
STGM_READ = OF_READ,            // 0x0000
STGM_WRITE = OF_WRITE,          // 0x0001
STGM_READWRITE = OF_READWRITE, // 0x0002

STGM_SHARE_DENY_NONE = OF_SHARE_DENY_NONE,    // 0x0040
STGM_SHARE_DENY_READ = OF_SHARE_DENY_READ,    // 0x0030
STGM_SHARE_DENY_WRITE = OF_SHARE_DENY_WRITE,  // 0x0020
STGM_SHARE_EXCLUSIVE = OF_SHARE_EXCLUSIVE,    // 0x0010

STGM_DIRECT = 0x00000000,
STGM_TRANSACTED = 0x00010000,

STGM_CREATE = OF_CREATE       // 0x1000,
STGM_CONVERT = 0x00020000,
STGM_FAILIFTHERE = 0x00000000,

STGM_PRIORITY = 0x00040000,

STGM_DELETEONRELEASE = 0x04000000,

} STGM;

Elements

STGM_READ, STGM_WRITE, STGM_READWRITE

For stream objects, STGM_READ allows you to call the IStream::Read method. For storage objects, you can enumerate the storage elements and open them for reading.

STGM_WRITE lets you save changes to the object.

STGM_READWRITE is the combination of STGM_READ and STGM_WRITE.

STGM_SHARE_DENY_NONE, STGM_SHARE_DENY_READ, STGM_SHARE_DENY_WRITE, STGM_SHARE_EXCLUSIVE

STGM_SHARE_DENY_NONE specifies that subsequent openings of the object are not denied read or write access.

STGM_SHARE_DENY_READ prevents others from subsequently opening the object in STGM_READ mode. It is typically used on a root storage object.

STGM_SHARE_DENY_WRITE prevents others from subsequently opening the object in STGM_WRITE mode. This value is typically used to prevent unnecessary copies made of an object opened by multiple users. If this value is not specified, a snapshot copy must be made for each subsequent opening. Thus, you can improve performance by specifying this value.

STGM_SHARE_EXCLUSIVE is the combination of STGM_SHARE_DENY_READ and STGM_SHARE_DENY_WRITE.

STGM_DIRECT, STGM_TRANSACTED

In direct mode, each change to a storage element is written as it occurs. This is the default.

In transacted mode, changes are buffered and are written only if an explicit commit operation is called. The changes can be ignored by calling the Revert method in the IStream or IStorage interfaces. Transacted mode is not supported in the OLE-provided implementation of compound files.

STGM_CREATE, STGM_CONVERT, STGM_FAILIFTHERE

STGM_CREATE indicates that an existing storage object or stream should be removed before the new one replaces it. A new object is created when this flag is specified only if the existing object has been successfully removed.

STGM_CONVERT flag is used in three situations:

•	when you are trying to create a storage object on disk but a file of that name already exists

•	when you are trying to create a stream inside a storage object but a stream with the specified name already exists

•	when you are creating a byte array object but one with the specified name already exists

STGM_CONVERT creates the new object while preserving existing data in a stream named CONTENTS. In the case of a storage object or a byte array, the old data is flattened to a stream regardless of whether the existing file or byte array currently contains a layered storage object.

STGM_FAILIFTHERE causes the create operation to fail if an existing object with the specified name exists. In this case, STG_E_FILEALREADYEXISTS is returned. STGM_FAILIFTHERE applies to both storage objects and streams.

STGM_PRIORITY

Opens the storage object with exclusive access to the most recently committed version. Thus, other users cannot commit changes to the object while you have it open in priority mode. You gain performance benefits for copy operations but you prevent others from committing changes. So you should limit the time you keep objects open in priority mode. You must specify STGM_DIRECT and STGM_READ with priority mode.

STGM_DELETEONRELEASE

Indicates that the underlying file is to be automatically destroyed when the root storage object is released. This capability is most useful for creating temporary files.

Comments

You can combine these flags but you can only choose one flag from each group of related flags.

See Also

IStream::Read.


STGMOVE

The STGMOVE enumeration values indicate whether a storage element is to be moved or copied. They are used in the IStorage::MoveElementTo method.

Defined in the IOLETypes pseudo-interface (oletyp.idl).

typedef enum tagSTGMOVE
{
STGMOVE_MOVE = 0,
STGMOVE_COPY = 1
} STGMOVE;

Elements

STGMOVE_MOVE

Indicates the method should move the data from the source to the destination.

STGMOVE_COPY

Indicates the method should copy the data from the source to the destination. A copy is the same as a move except the source element is not removed after copying the element to the destination. Copying an element on top of itself is undefined.

See Also

IStorage::MoveElementTo


STGTY

The STGTY enumeration values are used in the type member of the STATSTG structure to indicate the type of the storage element. A storage element is a storage object, a stream object, or a byte array object (LOCKBYTES).

Defined in the IStream interface (stream.idl).

typedef enum tagSTGTY
{
STGTY_STORAGE    = 1,
STGTY_STREAM     = 2,
STGTY_LOCKBYTES  = 3,
STGTY_PROPERTY   = 4
} STGTY;

Elements

STGTY_STORAGE

Indicates that the storage element is a storage object.

STGTY_STREAM

Indicates that the storage element is a stream object.

STGTY_LOCKBYTES

Indicates that the storage element is a byte array object.

STGTY_PROPERTY

Indicates that the storage element is a property storage object.

See Also

IStream, STATSTG


STREAM_SEEK

The STREAM_SEEK enumeration values specify the origin from which to calculate the new seek pointer location. They are used for the dworigin parameter in the IStream::Seek method. The new seek position is calculated using this value and the dlibMove parameter.

Defined in the IStream interface (stream.idl).

typedef enum tagSTREAM_SEEK
{
STREAM_SEEK_SET = 0,
STREAM_SEEK_CUR = 1,
STREAM_SEEK_END = 2
} STREAM_SEEK;

Elements

STREAM_SEEK_SET

Indicates that the new seek pointer is an offset relative to the beginning of the stream. In this case, the dlibMove parameter is the new seek position relative to the beginning of the stream.

STREAM_SEEK_CUR

Indicates that the new seek pointer is an offset relative to the current seek pointer location. In this case, the dlibMove parameter is the signed displacement from the current seek position.

STREAM_SEEK_END

Indicates that the new seek pointer is an offset relative to the end of the stream. In this case, the dlibMove parameter is the new seek position relative to the end of the stream.

See Also

IStream::Seek


TYMED

The TYMED enumeration values indicate the type of storage medium being used in a data transfer. They are used in the STGMEDIUM or FORMATETC structures.

typedef [transmit_as(long)] enum tagTYMED
{
TYMED_HGLOBAL   = 1;
TYMED_FILE      = 2;
TYMED_ISTREAM   = 4;
TYMED_ISTORAGE  = 8;
TYMED_GDI       = 16;
TYMED_MFPICT    = 32;
TYMED_ENHMF     = 64;
TYMED_NULL      = 0
} TYMED;

Elements

TYMED_HGLOBAL

The storage medium is a global memory handle (HGLOBAL). Allocate the global handle with the GMEM_SHARE flag. If the STGMEDIUM punkForRelease member is NULL, the destination process should use GlobalFree to release the memory.

TYMED_FILE

The storage medium is a disk file identified by a path. If the STGMEDIUM punkForRelease member is NULL, the destination process should use OpenFile to delete the file.

TYMED_ISTREAM

The storage medium is a stream object identified by an IStream pointer. Use IStream::Read to read the data. If the STGMEDIUM punkForRelease member is NULL, the destination process should use IStream::Release to release the stream component.

TYMED_ISTORAGE

The storage medium is a storage component identified by an IStorage pointer. The data is in the streams and storages contained by this IStorage instance. If the STGMEDIUM punkForRelease member is NULL, the destination process should use IStorage::Release to release the storage component.

TYMED_GDI

The storage medium is a GDI component (HBITMAP). If the STGMEDIUM punkForRelease member is NULL, the destination process should use DeleteObject to delete the bitmap.

TYMED_MFPICT

The storage medium is a metafile (HMETAFILE). Use the Windows or WIN32 API functions to access the metafile's data. If the STGMEDIUM punkForRelease member is NULL, the destination process should use DeleteMetaFile to delete the bitmap.

TYMED_ENHMF

The storage medium is an enhanced metafile. If the STGMEDIUM punkForRelease member is NULL, the destination process should use DeleteEnhMetaFile to delete the bitmap.

TYMED_NULL

Indicates that no data is being passed.

Comments

During data transfer operations, a storage medium is specified. This medium must be released after the data transfer operation. The provider of the medium indicates its choice of ownership scenarios in the value it provides in the STGMEDIUM structure. A NULL value for the IUNKNOWN field indicates that the receiving body of code owns and can free the medium. A non-NULL pointer specifies that ReleaseStgMedium can always be called to free the medium.

See Also

FORMATETC, IAdviseSink, IDataObject, IOleCache, ReleaseStgMedium, STGMEDIUM


USERCLASSTYPE

The USERCLASSTYPE enumeration constants indicate the different variants of the display name associated with a class of objects. They are used in the IOleObject::GetUserType method and the OleRegGetUserType function. These constants are defined in ole2.h and in the IOleObject interface (oleobj.idl).

typedef enum tagUSERCLASSTYPE
{
USERCLASSTYPE_FULL    = 1,
USERCLASSTYPE_SHORT   = 2,
USERCLASSTYPE_APPNAME = 3,
} USERCLASSTYPE;

Elements

USERCLASSTYPE_FULL

Indicates the full type name of the class.

USERCLASSTYPE_SHORT

Indicates a short name (maximum of 15 characters) that is used for popup menus and the Links dialog box.

USERCLASSTYPE_APPNAME

Indicates the name of the application servicing the class and is used in the Result text in dialogs.

See Also

IOleObject::GetUserType, OleRegGetUserType


OLE Glossary
Glossary

A

Activation

The process of binding an object in order to put it into its running state. Also refers to invoking a particular operation on an object. See also Binding.

Absolute moniker

A moniker that specifies the absolute location of an object. An absolute moniker is analogous to a full pathname. See also Moniker.

Advisory sink

An object that can receive notifications of changes in an embedded object or linked object because it implements the IAdviseSink interface (and possibly the IAdviseSink2 interface). Notifications originate in the object application, where they are cached in an advise holder, which passes them to advisory sinks implemented by object handlers. For an embedded object, the corresponding object handler forwards the notification to the object's container. For a linked object, the object handler forwards the notification to the link object, which in turn passes it on to the container. See also Object handler, Embedded object, Link object, Linked object, Container application.

Aggregate object

A component object that is made up of one or more other component objects. One object in the aggregate is designated the control object, which controls which interfaces in the aggregate are exposed and which are private. The control object has a special implementation of IUnknown called the controlling unknown. All non-controlling objects in the aggregate must pass calls to IUnknown methods through the controlling unknown.

Aggregation

A composition technique for implementing component objects. It allows you to build a new object with one or more existing objects that support some or all of the new object's required interfaces.

Anti-moniker

The inverse of a file, item, or pointer moniker. An anti-moniker is added to the end of a file-, item-, or pointer moniker to nullify it. This is analogous to the way that ".." nullifies a directory component of a pathname (that is, \work\art\.. equals \work). Anti-monikers are used in the construction of relative monikers. See also Relative Moniker.

Artificial reference counting

A technique used to safeguard an object before making a call that could result in its premature destruction by ensuring it won't be de-allocated. A process calls the AddRef method of IUnknown to increment the count before making the call that could otherwise free the object prematurely, and after the function returns, calls the IUnknown::Release method to decrement the count.

Asynchronous call

A function that allows the next instruction in the process to be executed as soon as the call is made, without waiting for the function to return. Most OLE functions and interface methods are synchronous; that is, the function must return before the next instruction is executed. OLE defines six asynchronous methods, five within the IAdviseSink interface — OnDataChange, OnViewChange, OnRename, OnSave, and OnClose — and one within the IAdviseSink2 interface — OnLinkSourceChange.

Automation

See OLE Automation

B

Bind context

An object that implements the IBindCtx interface. Bind contexts are used in moniker operations. A bind context holds references to the objects activated when a moniker is bound, contains parameters that apply to all operations during the binding of a generic composite moniker, and provides the means by which the moniker implementation should retrieve information about its environment. See Binding, Moniker.

Binding

Generically, binding is the process of associating a name to its referent. When referring to monikers specifically, binding is the process of locating the object named by the moniker, activating it (loading it in memory) if it isn't already, and returning an interface pointer to it. Binding puts an object into its running state, allowing the operations it supports to be invoked. Objects can be bound at run time (also called late binding or dynamic binding) or at compile time (also called static binding). In OLE Automation, vtable-based binding is referred to as "early binding" and IDispatch-based binding is referred to as "late binding."

C

Cache

Generally, a cache is a (usually temporary) local store of information. In OLE, the term cache is used in connection with linked or embedded objects, in which the cache contains information that defines the presentation of a contained object when the container is opened.

Cache initialization

The process of filling an embedded object's cache with data formats. The IOleCache interface provides methods that a container object can call to control the data that gets cached for embedded objects.. The IOleCache::InitCache method fills the cache using data provided by a transfer from the Clipboard or from a drag-and-drop operation. The IOleCache::SetData method fills the cache using data in a storage object.

Class

In object-oriented programming, a class is a set of objects whose behavior is defined by the same set of code (they share the same implementation).
A COM class is not necessarily the same as a class in an object-oriented language. A COM class can be identified by a CLSID, though for most COM operations, it is not necessary to know an object's class.

Class factory

A object that you use to create one or more instances of a an object identified by a given CLSID (class identifier). A class factory object implements the IClassFactory interface. A class factory is the most frequently used type of class object in OLE. See also CLSID.

Class identifier (CLSID)

A unique identification tag (UUID) associated with an OLE class object. A class object that is intended to create more than one object registers its CLSID in a task table in the registration database to enable clients to locate and load the executable code associated with the object(s). Every OLE object application (or container that allows linking to its embedded objects) must register a CLSID for each supported object definition.

Class object

In COM, class objects are called class factories, and typically have no behavior except to create new instances of the class. In object-oriented programming, an object whose state is shared by all the objects in a class, and whose behavior acts on that class-wide state data. See also Class factory.

Client

In referring to OLE objects, an object that requests services from another object. See also Container.

Client site

The display site for an embedded or linked object within a compound document. The client site is the principal means by which an object requests services from its container.

CLSID

See Class identifier

Component object

An object that conforms to the OLE component object model (COM). Clients deal with a component object only through a pointer to an interface (a related set of functions called methods). With the pointer, clients can call the methods that perform operations or manipulate the data associated with the object. Component objects are instances of an object definition, which specifies an implementation of the interfaces on the object.

Composite moniker

A moniker that consists of two or more monikers composed together. A composite moniker can be non-generic, meaning that its component monikers have special knowledge of each other, or generic, meaning that its component monikers know nothing about each other except that they are monikers. See Generic composite moniker.

Commit

The act of persistently saving any changes made to an object since its storage was opened or since the last time changes were saved. See also Revert.

Component object model (COM)

The OLE object-oriented programming model that defines how objects interact within a single application or between applications. In COM, clients have access to an OLE object through a pointer to an interface (a related set of functions called methods) on the object.

Composite menu

A shared menu bar composed of menu groups from both an in-place container and an in-place object application. The object application must install and remove the menu from the container's frame window.

Compound document

A document that contains data of different formats, created by different applications. Compound documents are created in a container application, such as Word, and information from other applications (such as spreadsheets, sound clips, and bitmaps) is either embedded in or linked to the container application. When the compound document is saved, the container application saves it.

Compound file

An OLE-provided implementation of structured storage which includes the IStorage, the IStream, and the ILockBytes interfaces. You use a set of StgXxx API functions to create and use a compound file.

Container

See Container application.

Container application

An application that supports compound documents. Container applications provide storage for the object, a site for display, access to the display site, and an advisory sink for receiving notifications of changes in the object. See also Compound document, Client site, and Advisory sink.

Container/Object

An application that has implemented OLE interfaces such that the application supports the features and capabilities of both a container and object application.

Container/Server

See Container/Object.

Control object

The object within an Aggregate object that controls which interfaces within the aggregate object are exposed and which are private.. The control object has a special implementation of IUnknown called the controlling unknown, and all other objects in the aggregate must pass calls to IUnknown methods through the controlling unknown. See Aggregate object.

D

Data transfer object

An object that supports the IDataObject interface and contains data to be transferred from one object to another either through the Clipboard or drag-and-drop operations.

Default object handler

A DLL provided with the OLE SDK that provides a partial implementation of basic interfaces. It is a surrogate in the processing space of the container application for the real object.

With the default object handler, it is possible to look at an object's stored data without actually activating the object. The default object handler performs other tasks on behalf of a loaded object, such as rendering an object from its cached state when the object is loaded into memory.

Direct access mode

One of two access modes in which a storage object can be opened. In direct mode, all changes are immediately committed to the root storage object. See also Transacted access mode.

Drag and drop

OLE specifies a set of data transfer and drag-and drop-interface-specific interfaces that allow applications to implement drag and drop, an operation in which the end-user uses the mouse or other pointing device to drag data from one window and drop it into another location in the same window or into another window.

E

Embedded object

A compound-document object that is stored with the container application, but when it is running, lives in the process space of the server application, which creates and subsequently edits it. The default handler provides a surrogate in the processing space of the container application for the real object.

Explicit caching

One of two ways an object can cache its presentation data. Explicit caching requires the physical creation of the cache nodes needed to save the data formats of the object. See also Implicit caching.

F

File moniker

A moniker based on a path in the file system. File monikers can be used to identify objects that are saved in their own files. A file moniker is an object that represents an implementation of the IMoniker interface for the file class. See also Item moniker and Generic composite moniker.

G

Global memory

See Shared application memory.

Generic composite moniker

The generic composite moniker is a sequenced collection of other types of monikers, starting with a file moniker to provide the document-level path and continuing with one or more item monikers. See also Item moniker and File moniker.

H

Handler

See Object handler.

Helper function

A function that encapsulates other functions and interface methods publicly available in the OLE SDK.

HRESULT

An opaque result handle defined to be zero for a successful return from a function and non-zero if error or status information is to be returned. To convert an HRESULT into the more detailed SCODE, applications call GetScode(). See SCODE.

I

Implicit caching

The "implied" caching of presentation data by an object that is capable of rendering itself using its native data. Cache nodes are not created with implicit caching. See also Explicit caching.

In parameter

A parameter that is allocated, set, and freed by the caller of a function.

In/Out parameter

A parameter that is initially allocated by the caller of a function and set, freed, and reallocated if necessary by that which is called.

In-process server

An object server or application implemented as a DLL that runs in the process space of the object's container. See also Local server, Remote server.

Instance

An object for which memory is allocated or which is persistent.

Instantiate

The process of creating an activating an obnect based on its definition.

Interface

A group of related functions that provide access to OLE objects. The set of OLE interfaces define a contract that allow objects to interact according to the Component Object Model (COM). While OLE provides many interface implementations, most interfaces can also be implemented by developers designing OLE applications.

Interface identifier (IID)

A unique identification tag associated with each interface. Some functions take IIDs as parameters to allow the callers to specify what type of interface pointer should be returned.

Item moniker

A moniker based on a string that identifies an object in a container. Item monikers can be used to identify objects smaller than a file, including embedded objects in a compound document, or a pseudo-object (like a range of cells in a spreadsheet). See also File moniker and Generic composite moniker.

L

Link object

A component object that is instantiated when a linked compound document object is created or loaded. The link object implements the IOleLink interface and is provided by OLE.

Linked object

A compound-document object whose source data physically resides where it was initially created. Only a moniker that represents the source data and the appropriate presentation data is kept with the compound document. Changes made to the link source are automatically reflected in the linked compound-document object in the container(s).

Link source

The data that is the source of a linked compound document object. A link source may be a file or a portion of a file, such as an embedded object or a selected range within a file (also called a pseudo object).

Loaded state

The state of a compound-document object after its data structures have been loaded into container memory. The data structures are created by the object handler. See also Passive state and Running state.

Local server

An server application implemented as an EXE running on the same machine as the client application using it. Because the server application is an EXE, it runs in its own process. See also In-Process server and Remote server.

Lock

OLE defines two types of locks that can be held on an object: strong and weak. A strong lock will keep an object in memory, a weak lock will not.

LRPC (Lightweight remote procedure call)

OLE's RPC-based protocol for interprocess communication. LRPC is "lightweight" in that it handles communication between processes on one machine only.

M

Marshaling

The process of packaging and sending interface parameters across process boundaries.

Moniker

An object that implements the IMoniker interface. A moniker acts as a name that uniquely identifies a COM object. You can think of a moniker as a generalization of a pathname; in the same way that a pathname identifies a file in the file system, a moniker identifies a COM object. Monikers support an operation known as "binding," which is the process of locating the object named by the moniker, activating it (loading it in memory) if it isn't already, and returning an interface pointer to it.

Moniker class

An implementation of the IMoniker interface. System-supplied moniker classes include file monikers, item monikers, generic composite monikers, anti-monikers, and pointer monikers.

Moniker client

An application that uses monikers to acquire interface pointers to objects managed by another application.

Moniker provider

An application that hands out monikers that identify  the objects it manages, so that they are accessible to other applications.

Multiple Document Interface (MDI) Application

An application that can support multiple documents from one application instance. MDI object applications can simultaneously serve a user and one or more embedding containers. See also Single Document Interface (SDI) application.

N

Native data

The data used by an OLE server application when editing an embedded object. See also Presentation data.

Nested object

An OLE object that is embedded within another OLE object through the use of a combination container/server application. OLE objects can be arbitrarily nested to any level.

O

Object

Generally, an instance of an entity that embodies both specific data and the functions that manipulate it.
Specifically in object-oriented programming, an object is an entity that has state, behavior and identity. An object's state consists of its attributes and and the attributes' current values. An object's behavior consists of the operations that can be performed on it and the accompanying state changes. An object's identity is what you use to distinguish it from other objects.
In contrast, COM objects' behavior is defined by the interfaces it supports. A COM object's state is not explicitly specified, but is implied by its interfaces. A COM object's identity is defined by the ability to use IUnknown::QueryInterface to move between interfaces.
A COM object follows a specific model in which clients (those using an object's services) gain access to the object's data only through a pointer to an interface consisting of a set of methods (related functions). The client can then call these methods to perform desired operations. There is no direct access to an OLE object's data.

Object application

An OLE-aware application that can create compound document objects. Containers can then embed or link to these objects.

Object handler

A piece of class-specific code that is dynamically loaded into the address space of its container. Object handlers process requests for specific classes of objects, so that much of the communication can be in-process. This is more efficient because it reduces the need for remote procedure calls.

Object state

One of three relationships between a compound document object in its container and the application responsible for the object's creation: passive, loaded, and running. Passive objects are stored (on disk or in a database), and the object is not selected or active. In the loaded state, its data structures have been loaded into memory, but is not yet available for operations such as editing. Running objects are both loaded and available for all operations.

Object type name

A unique identification string that is stored as part of the information available for an object in the registration database—for example, Acme Drawing.

OLE Automation

A way to manipulate an application's objects from outside the application. OLE automation is typically used to create applications that expose objects to programming tools and macro languages, create and manipulate one application's objects from another applications, or to create tools for accessing and manipulating objects. For information on OLE Automation, refer to the OLE Programmer's Reference, Volume 2.

Out parameter

A function parameter that is allocated and set by whatever a function calls, and must be freed by the caller.

P

Passive state

The state of an OLE object when it is stored (on disk or in a database). The object is not selected or active. See also Loaded state and Running state.

Persistent storage

Storage of a file or object in a medium such as a file system or database so that the file can be closed and then re-opened at a later time. Data can be retrieved from the file until the underlying file is deleted.

Pointer moniker

A moniker that wraps an interface pointer to an object in memory. Whereas most monikers identify objects that can be saved to persistent storage, pointer monikers identify objects that cannot. They allow such objects to participate in a moniker binding operation.

Presentation data

The data used by an OLE container applicationto display embedded or linked objects. See also Native data.

Primary verb

The action associated with the most common, preferred operation users perform on an object; the primary verb is always defined as verb zero in the system registration database. An object's primary verb is executed by double-clicking on the object.

Proxy

An interface-specific object that packages parameters for that interface in preparation for a remote method call. A proxy runs in the address space of the sender and communicates with a corresponding stub in the receiver's address space. See also Stub, Marshaling, and Unmarshaling.

Proxy manager

Manages all the proxies for a single object.

Pseudo object

A selection of data within a document or embedded object that can be the source for a compound-document object.

R

Reference counting

Keeping a count of each interface pointer instance to ensure that an object is not destroyed before all references to it are released.

Relative moniker

A moniker that specifies the location of an object  relative to the location of another object. A relative moniker is analogous to a relative pathname (such as "..\backup\report.old").

Remote Server

A server application, implemented as an EXE, running on a different machine from the client application using it. See also In-process server, Local server.

Revert

The act of discarding any change(s) made to an object since the last time the changes were committed or the object's storage was opened. See also Commit, Transacted access mode.

Root IStorage object

The outermost IStorage instance in a document; also called the root storage object. Compound-document objects are always saved as children of a root IStorage object.

Running state

The state of an OLE object when the object application is running and it is possible to edit the object, access its interfaces, and receive notification of changes. See also Loaded state and Passive state.

Running object table (ROT)

A globally-accessible table on each machine that keeps track of all the OLE objects that can be identified by a moniker and are currently running on the machine. Monikers use the Running Object Table. Registering an object in the running object table increments the object's reference count. Before the object can be destroyed, its moniker must be released from the running object table.

S

SCODE

A DWORD value that is used to pass detailed information to the caller of an interface method or function. See also HRESULT.

Server

See Object application.

Shared application memory

Memory that is primarily used between processes to optimize the data copying that occurs in LPRC calls.

Single Document Interface (SDI) Application

An application that can support only one document at a time. Multiple instances of an SDI application must be started to service both an embedded object and a user. See also Multiple Document Interface (MDI) application.

Single object application

An application that is capable of creating and manipulating one class of object. See also Multiple object application.

Stand-alone object application

An object application implemented as an executable (EXE) program, rather than as a DLL object application.

State

See Loaded state, Passive state, and Running state.

Static object

An object that contains only a presentation, with no native data. A container application can treat a static object as though it were a linked or embedded object, except that it is not possible to edit a static object.
A static object can result, for example, from the breaking of a link on a linked object; you don't want the linked object to be updated anymore.

Storage object

An object that implements the IStorage interface. A storage object contains nested storage objects or stream objects, resulting in a directory/file system within a single file. It provides the underlying storage for compound documents. Container applications provide a nested storage object for each of their embedded objects. The embedded object stores its data nested storage and stream objects within the storage object provided by its container. See also Root IStorage object and Stream object.

Stream object

An object that implements the IStream interface. A stream object is analogous to a file in a directory/file system. See also Storage object.

Structured storage model

A specification that defines a hierarchical method of storing objects. OLE provides an implementation of the structured storage model called Compound Files. See Compound file.

Stub

When a function's or interface method's parameters are marshaled across a process boundary, the stub is an interface-specific object that unpackages the marshaled parameters and calls the required method. The stub runs in the receiver's address space and communicates with a corresponding proxy in the sender's address space. See Proxy, Marshaling, and Unmarshaling.

Stub manager

Manages all of the stubs for a single object.

Synchronous call

A function that does not allow further instructions in the process to be executed until the function returns. Most OLE interface methods, except some of the IAdviseSink methods, are synchronous calls. See also Asychronous call.

T

Transacted access mode

One of two access modes in which a storage object can be opened. When opened in transacted mode, changes are stored in temporary buffers until the root IStorage object commits its changes. See also Direct access mode, Commit, Revert.

U

Uniform data transfer

A model for transferring data via the Clipboard, drag and drop, or through automation. Objects conforming to the model implement the IDataObject interface. This model replaces DDE (dynamic data exchange). See Data transfer object.

Unmarshaling

The processing of unpackaging parameters that have been sent across process boundaries.

V

Virtual Table (VTBL)

An array of pointers that point to interface method implementations.

Visual Editing

A term in end-user documents that refers to the user's ability to interact with a compound-document object in the context of its container. The term most often used by developers is in-place activation. See also In-place activation.


 HELLO

--------------------------------------- OLE Automation Sample Program: Hello ---------------------------------------

This is the "hello world" sample application.  It is an OLE object which is programmable via IDispatch.

The application has one window which contains a button and a text box. When the button is pressed, the string "Hello world." is displayed in the text box.
The hello application to the SayHello method by performing the same  action as when the "Say Hello" button in the user interface is pressed.   The SayHello method returns the same string.

This is the simplest OLE automation sample application and is a good place to start if you have not done any OLE Automation programming.

The ProgID for hello's only object is "Hello.Application".   An instance of this object can be created by executing the  following lines of code in Visual Basic or DispTest:

  Sub Foo
    Dim MyCalculator as Object

    Set MyCalculator = CreateObject("Hello.Application")
    . . .
  End Sub

----------------- Program Structure ----------------- Hello uses a type library and CreateStdDispatch in order to  implement the IDispatch interface.

------------------------- Properties for the object -------------------------

Name	Type	Description --------------------------------------------------------------------- HelloMessage	VT_BSTR	the message that is printed when the 	SayHello method is called or when the 	SayHello button is pressed.

----------------------------- Methods defined on the object -----------------------------

Name	Description -------------------------------------------------------------- SayHello() as String	Print the hello message and return it.


 MAKEFILE  (HELLO Sample)

####

#makefile - makefile for hello.exe

#

#       Copyright (C) 1992, Microsoft Corporation

#

#Purpose:

#  Builds the OLE 2.0 sample IDispatch server, hello.exe.

#

#

#  Usage: NMAKE                 ; build with defaults

#     or: NMAKE option          ; build with the given option(s)

#     or: NMAKE clean           ; erase all compiled files

#

#     option: dev = [win16 | win32]    ; dev=win32 is the default

#             DEBUG=[0|1]              ; DEBUG=1 is the default

#             HOST=[DOS | NT]          ; HOST=DOS (for win16)

#                                      ; HOST=NT (for win32)

#

#Notes:

#  This makefile assumes that the PATH, INCLUDE and LIB environment

#  variables are setup properly.

#

##############################################################################

##########################################################################

#

# Default Settings

#

!if "$(dev)" == ""

dev = win32

!endif

!if !("$(dev)" == "win16" || "$(dev)" == "win32")

!error Invalid dev option, choose from [win16 | win32]

!endif

!if "$(dev)" == "win16"

TARGET  = WIN16

!if "$(HOST)" == ""

HOST  = DOS

!endif

!endif

!if "$(dev)" == "win32"

TARGET  = WIN32

HOST  = NT

!endif

!ifdef NODEBUG

DEBUG = 0

!endif

!if "$(DEBUG)" == "0"

NODEBUG = 1

!endif

!if "$(DEBUG)" == ""

DEBUG = 1

!endif

##########################################################################

#

# WIN16 Settings

#

!if "$(TARGET)" == "WIN16"

CC   = cl

LINK = link

!if "$(HOST)" == "DOS"

WX   = wx /w

!else

WX   =

!endif

RCFLAGS = -dWIN16

CFLAGS = -c -W3 -AM -GA -GEs -DWIN16

LINKFLAGS = /NOD /NOI /BATCH /ONERROR:NOEXE

LIBS = libw.lib mlibcew.lib

!if "$(DEBUG)" == "1"

CFLAGS = $(CFLAGS) -Od -Zi -D_DEBUG $(CL)

LINKFLAGS = $(LINKFLAGS) /COD

!else

CFLAGS = $(CFLAGS) -Ox $(CL)

LINKFLAGS = $(LINKFLAGS) /FAR /PACKC

!endif

!endif

##########################################################################

#

# WIN32 Settings

#

!if "$(TARGET)" == "WIN32"

WX =

!include <$(MSTOOLS)\samples\ole\include\olesampl.mak>

CC = $(cc)

CFLAGS = $(cflags) $(cvarsmt) -DUNICODE $(cdebug)

!ifndef NODEBUG

CFLAGS = $(CFLAGS) -D_DEBUG

!endif

LINK = $(link)

LINKFLAGS = $(linkdebug) $(guilflags)

RCFLAGS = -DWIN32

!endif

##########################################################################

#

# Build rules

#

.cpp.obj:

    @echo Compiling $<...

    $(CC) $<

.c.obj:

    @echo Compiling $<...

    $(CC) $<

##########################################################################

#

# Application Settings

#

APPS = hello

!if "$(TARGET)" == "WIN16"

LIBS = ole2.lib compobj.lib ole2disp.lib typelib.lib $(LIBS)

!endif

!if "$(TARGET)" == "WIN32"

LIBS = $(olelibsmt)

!endif

OBJS = \

        main.obj     \

        hello.obj    \

        hellopro.obj \

        clsid.obj

##########################################################################

#

# Default Goal

#

goal : setflags $(APPS).exe

setflags :

        set CL=$(CFLAGS)

##########################################################################

#

# Clean (erase) generated files

#

clean :

    if exist *.obj       del *.obj

    if exist $(APPS).exe del $(APPS).exe

    if exist $(APPS).tlb del $(APPS).tlb

    if exist $(APPS).map del $(APPS).map

    if exist $(APPS).res del $(APPS).res

    if exist ihello.h    del ihello.h

    if exist *.log       del *.log

    if exist *.pdb       del *.pdb

##########################################################################

#

# Application Build (WIN16 Specific)

#

!if "$(TARGET)" == "WIN16"

$(APPS).exe : $(OBJS) $(APPS).def $(APPS).res $(APPS).ico

        link $(LINKFLAGS) @<<

$(OBJS),

$@,,

$(LIBS),

$(APPS).def

<<

        rc -k -t $(APPS).res $@

!endif

##########################################################################

#

# Application Build (WIN32 Specific)

#

!if "$(TARGET)" == "WIN32"

$(APPS).exe : $(OBJS) $(APPS).def $(APPS).res $(APPS).ico

      $(LINK) @<<

        $(LINKFLAGS)

        -out:$@

        -map:$*.map

        $(OBJS)

        $(APPS).res

        $(LIBS)

<<

!endif

##########################################################################

#

# Application Build (Common)

#

$(APPS).res : $(APPS).rc

        rc $(RCFLAGS) -r -fo$@ $?

##########################################################################

#

# Dependencies

#

ihello.h : hello.odl

        if exist ihello.h  del ihello.h

        if exist hello.tlb  del hello.tlb

        $(WX) mktyplib /D$(TARGET) /h ihello.h /o hello.log /tlb hello.tlb hello.odl

main.obj : main.cpp hello.h ihello.h

        $(CC) main.cpp

hello.obj : hello.cpp hello.h resource.h

        $(CC) hello.cpp

hellopro.obj : hellopro.cpp hello.h ihello.h

        $(CC) hellopro.cpp

clsid.obj : clsid.c clsid.h

        $(CC) clsid.c


 CLSID.H  (HELLO Sample)

/***

*clsid.h

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*  Information Contained Herein Is Proprietary and Confidential.

*

*Purpose:

*  This file defines the CLSIDs for the class which we

*  will register with OLE.

*

*  You can get a universally unique identifier (uuid) by running

*  the uuidgen tool supplied with OLE2.  When you run it, a huge

*  hex number comes out.  Do some pattern matching and stick the

*  numbers into this macro.  A long (l) is 8 he digits, a word (w)

*  is 4 hex digits and a byte is two hex digits.

*

*  You only have to do this once for each class you create and register

*  with OLE.

*

*Implementation Notes:

*

*****************************************************************************/

/*

 *

  IDispatch*	Hello.Application	{D3CE6D43-F1AF-1068-9FBB-08002B32372A}

  Type library:	Hello.tlb	{D3CE6D44-F1AF-1068-9FBB-08002B32372A}

  Interface:	_IHello	{D3CE6D45-F1AF-1068-9FBB-08002B32372A}

  DispInterface:_DHello	{D3CE6D46-F1AF-1068-9FBB-08002B32372A}

 *

 */

DEFINE_GUID(CLSID_CHello,

                0xD3CE6D43,

                0xF1AF,

                0x1068,

                0x9F,

                0xBB,

                0x08,

                0x00,

                0x2B,

                0x32,

                0x37,

                0x2A);

DEFINE_GUID(IID_IHello,

                0xD3CE6D45,

                0xF1AF,

                0x1068,

                0x9F,

                0xBB,

                0x08,

                0x00,

                0x2B,

                0x32,

                0x37,

                0x2A);

DEFINE_GUID(IID_DHello,

                0xD3CE6D46,

                0xF1AF,

                0x1068,

                0x9F,

                0xBB,

                0x08,

                0x00,

                0x2B,

                0x32,

                0x37,

                0x2A);

DEFINE_GUID(LIBID_HELLOTLB,

                0xD3CE6D44,

                0xF1AF,

                0x1068,

                0x9F,

                0xBB,

                0x08,

                0x00,

                0x2B,

                0x32,

                0x37,

                0x2A);


 CLSID.C  (HELLO Sample)

/***

*clsid.c

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*  Information Contained Herein Is Proprietary and Confidential.

*

*Purpose:

*  This file allocates and initializes the CLSIDs.

*

*****************************************************************************/

// initguid.h requires this.

//

#ifdef _MAC

# include <Types.h>

# include <Processes.h>

# include <AppleEvents.h>

#else

# include <windows.h>

#endif

#ifndef WIN32

#include <compobj.h>

#endif //!WIN32

// this redefines the DEFINE_GUID() macro to do allocation.

//

#include <initguid.h>

// due to the previous header, including this causes the DEFINE_GUID

// definitions in the following header(s) to actually allocate data.

//

#include "clsid.h"


 COMMON.H  (HELLO Sample)

/***

*

*  Copyright (C) 1993-1994, Microsoft Corporation.  All Rights Reserved.

*  Information Contained Herein Is Proprietary and Confidential.

*

*  File:

*    common.h

*

*  Purpose:

*

*    Common definitions across Win16/Win32

*

*****************************************************************************/

#ifndef __Common_h_

#define __Common_h_

#include <windows.h>

#include <ole2.h>

#ifndef WIN32

#include <olenls.h>

#include <dispatch.h>

#else

#include <oleauto.h>

#endif

#ifdef WIN32

# define STRLEN	strlen

# define STRICMP	_stricmp

# define MEMCPY	memcpy

# define MEMCMP	memcmp

# define MEMSET	memset

# define STRSTR	strstr

# if defined(UNICODE)

    #define TCHAR	WCHAR

    #define TSTR(str)	L##str

    #define STRING(str)	(str)

# else

    #define TCHAR	char

    #define TSTR(str)	str

    #define STRING(str)         AnsiString(str)

    extern "C" char FAR* AnsiString(OLECHAR FAR* strIn);

# endif

#else

# define STRLEN	_fstrlen

# define STRICMP	_fstricmp

# define MEMCPY	_fmemcpy

# define MEMCMP	_fmemcmp

# define MEMSET	_fmemset

# define STRSTR	_fstrstr

# define TCHAR	char

# define TSTR(str)	str

# define STRING(str)    (str)

#endif

#ifndef CLASS

# ifdef __TURBOC__

#  define CLASS class huge

# else

#  define CLASS class FAR

# endif

#endif

#endif // __Common_h_


 HELLO.DEF  (HELLO Sample)

NAME         HELLO

DESCRIPTION  'Hello world OLE object'

EXETYPE      WINDOWS

STUB         'WINSTUB.EXE'

CODE         PRELOAD MOVEABLE DISCARDABLE

DATA         PRELOAD MULTIPLE

HEAPSIZE     4096

STACKSIZE    8192


 HELLO.H  (HELLO Sample)

/***

*

*  Copyright (C) 1993-1994, Microsoft Corporation.  All Rights Reserved.

*  Information Contained Herein Is Proprietary and Confidential.

*

*  File:

*    hello.h

*

*  Purpose:

*	Contains the following:

*

*	* The CHello class

*	- Creation

*	- Creating the standard dispatch object

*	- Deletion

*	- Reference count maintenance

*	- IUnknown methods

*      * The CHelloCF class, which creates instances of CHello.

*	- Creation

*	- Deletion

*	- Reference count maintenance

*	- IUnknown methods

*

*****************************************************************************/

#include "common.h"

#include "clsid.h"

#include "hellopro.h"

#pragma warning(disable:4355)

/*	The CHello class.

 *

 */

CLASS CHello : public IUnknown

{

 public:

    CHello();

    ~CHello();

    static CHello FAR* Create();

    void ProcessCommand(WPARAM wparam); // Process a Windows WM_COMMAND message

    // Standard OLE stuff.

    STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppv);

    STDMETHOD_(ULONG, AddRef)(void);

    STDMETHOD_(ULONG, Release)(void);

    HWND m_hwnd;           	// The window to which we draw.

    BSTR m_bstrHelloMsg;

 private:

    ULONG m_refs;	// Reference count.

    IUnknown FAR* m_disp_interface;	// Pointer to the standard dispatch object.

    CHelloPro FAR* m_prog_interface;  // What a programmer sees.

};

/*	The class factory for CHello.

 *

 */

CLASS CHelloCF : public IClassFactory

{

  public:

    CHelloCF();

    static IClassFactory FAR* Create();

    STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppv);

    STDMETHOD_(ULONG, AddRef)(void);

    STDMETHOD_(ULONG, Release)(void);

    STDMETHOD(CreateInstance)(	IUnknown FAR* punkOuter,

REFIID riid,

void FAR* FAR* ppv);

    STDMETHOD(LockServer)(BOOL fLock);

  private:

    ULONG m_refs;

};


 HELLO.ODL  (HELLO Sample)

/*

 *	hello.odl

 *

 *

 *

  IDispatch*	Hello.Application	{D3CE6D43-F1AF-1068-9FBB-08002B32372A}

  Type library:	hello.tlb	{D3CE6D44-F1AF-1068-9FBB-08002B32372A}

  Interface:	IHello	{D3CE6D45-F1AF-1068-9FBB-08002B32372A}

 *

 *

 *

 */

[

  uuid(D3CE6D44-F1AF-1068-9FBB-08002B32372A),

  helpstring("OLE Automation Hello 1.0 Type Library"),

  lcid(0x0409),

  version(1.0)

]

library Hello

{

#ifdef WIN32

    importlib("stdole32.tlb");

#else

    importlib("stdole.tlb");

#endif

    [

     // The uuid for the interface IID_IHelloPro.

     odl,

     uuid(D3CE6D45-F1AF-1068-9FBB-08002B32372A),

     helpstring("Hello")

    ]

    interface _IHello : IUnknown

    {

[id(0), propput]

void HelloMessage([in] BSTR b);

      	[id (0), propget, helpstring("The message that will be displayed.")]

      	BSTR HelloMessage();

BSTR SayHello(void);

    }

    [

     uuid(D3CE6D46-F1AF-1068-9FBB-08002B32372A),

     helpstring("Hello DispInterface")

    ]

    dispinterface _DHello

    {

      interface _IHello;

    }

    [ // The uuid for the class we expose.  Same as registry

      // entry for hello.hello

      uuid(D3CE6D43-F1AF-1068-9FBB-08002B32372A),

      helpstring("Hello")

    ]

    coclass Hello

    {

      dispinterface _DHello;

      interface _IHello;

    }

};


 HELLO.RC  (HELLO Sample)

//Microsoft App Studio generated resource script.

//

#include "resource.h"

#define APSTUDIO_READONLY_SYMBOLS

/////////////////////////////////////////////////////////////////////////

//

// Generated from the TEXTINCLUDE 2 resource.

//

#define APSTUDIO_HIDDEN_SYMBOLS

#include "windows.h"

#undef APSTUDIO_HIDDEN_SYMBOLS

#include "resource.h"

/////////////////////////////////////////////////////////////////////////////////////

#undef APSTUDIO_READONLY_SYMBOLS

//////////////////////////////////////////////////////////////////////////////

//

// Icon

//

HELLO                   ICON    DISCARDABLE     "HELLO.ICO"

//////////////////////////////////////////////////////////////////////////////

//

// Dialog

//

HELLO DIALOG DISCARDABLE  20, 20, 214, 144

STYLE WS_MINIMIZEBOX | WS_CAPTION | WS_SYSMENU

CAPTION "Hello"

CLASS "Hello"

FONT 8, "MS Sans Serif"

BEGIN

    PUSHBUTTON      "Say Hello",IDC_SAYHELLO,7,6,52,15

    EDITTEXT        IDC_HELLOAREA,86,7,119,117,ES_MULTILINE | ES_AUTOHSCROLL |

                    ES_READONLY

END

#ifdef APSTUDIO_INVOKED

//////////////////////////////////////////////////////////////////////////////

//

// TEXTINCLUDE

//

1 TEXTINCLUDE DISCARDABLE

BEGIN

    "resrc1.h\0"

END

2 TEXTINCLUDE DISCARDABLE

BEGIN

    "#define APSTUDIO_HIDDEN_SYMBOLS\r\n"

    "#include ""windows.h""\r\n"

    "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"

    "#include ""resource.h""\r\n"

    "\0"

END

3 TEXTINCLUDE DISCARDABLE

BEGIN

    "\r\n"

    "\0"

END

/////////////////////////////////////////////////////////////////////////////////////

#endif    // APSTUDIO_INVOKED

#ifndef APSTUDIO_INVOKED

////////////////////////////////////////////////////////////////////////////////

//

// Generated from the TEXTINCLUDE 3 resource.

//

/////////////////////////////////////////////////////////////////////////////////////

#endif    // not APSTUDIO_INVOKED


 HELLO.REG  (HELLO Sample)

REGEDIT

; Registration information for the hello application

;

; IDispatch*	Hello.Application	{D3CE6D43-F1AF-1068-9FBB-08002B32372A}

; Type library:	hello.tlb	{D3CE6D44-F1AF-1068-9FBB-08002B32372A}

; Interface:	IHello	{D3CE6D45-F1AF-1068-9FBB-08002B32372A}

;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; registration info Hello.Application (defaults to Hello.Application.1)

HKEY_CLASSES_ROOT\Hello.Application = OLE Automation Hello Application

HKEY_CLASSES_ROOT\Hello.Application\Clsid = {D3CE6D43-F1AF-1068-9FBB-08002B32372A}

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; registration info Hello.Application.1

HKEY_CLASSES_ROOT\Hello.Application.1 = OLE Automation Hello 1.0 Application

HKEY_CLASSES_ROOT\Hello.Application.1\Clsid = {D3CE6D43-F1AF-1068-9FBB-08002B32372A}

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; registration info Hello 1.0

HKEY_CLASSES_ROOT\CLSID\{D3CE6D43-F1AF-1068-9FBB-08002B32372A} = IDispatch Hello Example

HKEY_CLASSES_ROOT\CLSID\{D3CE6D43-F1AF-1068-9FBB-08002B32372A}\ProgID = Hello.Application.1

HKEY_CLASSES_ROOT\CLSID\{D3CE6D43-F1AF-1068-9FBB-08002B32372A}\VersionIndependentProgID = Hello.Application

HKEY_CLASSES_ROOT\CLSID\{D3CE6D43-F1AF-1068-9FBB-08002B32372A}\LocalServer32 = hello.exe /Automation


 HELLO.CPP  (HELLO Sample)

/***

*

*  Copyright (C) 1993-1994, Microsoft Corporation.  All Rights Reserved.

*  Information Contained Herein Is Proprietary and Confidential.

*

*  File:

*    hello.cpp

*

*  Purpose:

*    See comment in hello.h

*

*****************************************************************************/

#include "common.h"

#include "resource.h"

#include "hello.h"

IUnknown FAR*

CreateDispatchInterface(

  IUnknown FAR*	punkController,

  void FAR* pProgInterface)

{

    HRESULT hresult;

    ITypeLib FAR* ptlib;

    ITypeInfo FAR* ptinfo;

    IUnknown FAR* punkStdDisp;

    // Load the the hellotlb type library.

    hresult = LoadRegTypeLib(LIBID_HELLOTLB, 1, 0, 0x0409, &ptlib);

    if (hresult != NOERROR) {

      #define TLB_NAME OLESTR("hello.tlb")

      // if it wasn't registered, try to load it from the path/current directory

      // if this succeeds, it will have registered the type library for us

      // for the next time.

      if((hresult = LoadTypeLib(TLB_NAME, &ptlib)) != NOERROR)

 return NULL;

    }

    // Get Dispatch TypeInfo from the type library.

    // Exit if an error occurs.

    hresult = ptlib->GetTypeInfoOfGuid(IID_IHello, &ptinfo);

    if (hresult != NOERROR)

return NULL;

    ptlib->Release();

    // Create a standard dispatch object.

    // Release the pointer to the previously created TypeInfo.

    // Exit if an error occurred.

    hresult = CreateStdDispatch(punkController,

    	pProgInterface,

ptinfo,

      	&punkStdDisp);

    ptinfo->Release();

    if (hresult != NOERROR)

return NULL;

    // If execution has reached this point, then no errors occurred.

    return punkStdDisp;

}

/*

 *	CHello::CHello(void)

 *

 */

CHello::CHello()

{

    m_refs = 1;

    m_disp_interface = NULL;

    m_prog_interface = new CHelloPro;

    m_prog_interface->m_phello = this;

    m_bstrHelloMsg = SysAllocString(OLESTR("Hello, world"));

}

/*

 *	CHello::~CHello(void)

 *

 */

CHello::~CHello()

{

    SysFreeString(m_bstrHelloMsg);

    delete m_prog_interface;

}

/*

 *	CHello *CHello::Create(void)

 *

 *	Creates a new instance of the CHello object.

 *

 *  	Returns a pointer to the newly created instance or

 *	NULL if the creation fails.

 *

 */

CHello FAR*

CHello::Create()

{

    CHello FAR* phello;

    IUnknown FAR* punkStdDisp;

    // Create an instance of CHello.  Exit if an error occurs.

    phello = new FAR CHello();

    if(phello == NULL)

      return NULL;

    punkStdDisp = CreateDispatchInterface((IUnknown FAR*) phello,

  phello->m_prog_interface);

    if (punkStdDisp == NULL) {

      phello->Release();

      return NULL;

    }

    // If execution has reached this point, then no errors have occurred.

    // Save the standard dispatch item and return the new instance.

    phello->m_disp_interface = punkStdDisp;

    return phello;

}

/*

 *	void CHello::ProcessCommand(WPARAM param)

 *

 *	Process a windows WM_COMMAND with the specified parameter.

 *

 */

void CHello::ProcessCommand(WPARAM wparam)

{

    switch(wparam) {

case IDC_SAYHELLO:

// The user pressed the "Say Hello" button.

m_prog_interface->SayHello();

break;

    }

}

//---------------------------------------------------------------------

//                        IUnknown methods

//---------------------------------------------------------------------

/* 	CHello::QueryInterface(...)

 *

 *	Someone wants to know if CHello support the interface identified

 *	by riid.  CHello supports IUnknown and we defer to a member

 *      (m_disp_interfaceatch) and thus support IDispatch.

 *

 *	CHello doesn't support any other interfaces.

 *

 */

STDMETHODIMP

CHello::QueryInterface(REFIID riid, void FAR* FAR* ppv)

{

    // riid identifies an interface type.  Do we support it?

    if (IsEqualIID(riid, IID_IUnknown))

// Someone is asking us for our controlling IUnknown.

// CHello is that IUnknown, so "this" is the answer.

*ppv = this;

    else if (IsEqualIID(riid, IID_IDispatch) ||

     IsEqualIID(riid, IID_DHello))

        // Someone is asking us for our IDispatch or dispinterface.

    	// We simply defer to the standard dispatch interface

    	// we created earlier.

    	return m_disp_interface->QueryInterface(IID_IDispatch, ppv);

    else if (IsEqualIID(riid, IID_IHello))

// Someone is asking us for our IHelloPro interface.

// We simply defer to the standard dispatch interface

// we created earlier.

*ppv = &m_prog_interface;

    else {

// They must have asked for another interface -- something

   	// we don't support.  Report the error.

  	*ppv = NULL;

return ResultFromScode(E_NOINTERFACE);

    }

    // If execution reached this point then no error occurred.

    AddRef();

    return NOERROR;

}

STDMETHODIMP_(ULONG)

CHello::AddRef()

{

    return ++m_refs;

}

STDMETHODIMP_(ULONG)

CHello::Release()

{

    if(--m_refs == 0)

    {

      if(m_disp_interface != NULL)

m_disp_interface->Release();

      PostQuitMessage(0);

      delete this;

      return 0;

    }

    return m_refs;

}

//---------------------------------------------------------------------

//                      The CHello Class Factory

//---------------------------------------------------------------------

CHelloCF::CHelloCF()

{

    m_refs = 1;

}

IClassFactory FAR*

CHelloCF::Create()

{

    return new FAR CHelloCF();

}

STDMETHODIMP

CHelloCF::QueryInterface(REFIID riid, void FAR* FAR* ppv)

{

    if(IsEqualIID(riid, IID_IUnknown) ||

       IsEqualIID(riid, IID_IClassFactory)) {

      AddRef();

      *ppv = this;

      return NOERROR;

    }

    *ppv = NULL;

    return ResultFromScode(E_NOINTERFACE);

}

STDMETHODIMP_(ULONG)

CHelloCF::AddRef()

{

    return ++m_refs;

}

STDMETHODIMP_(ULONG)

CHelloCF::Release()

{

    if(--m_refs == 0) {

       delete this;

       return 0;

    }

    return m_refs;

}

STDMETHODIMP

CHelloCF::CreateInstance(

    IUnknown FAR* punkOuter,

    REFIID riid,

    void FAR* FAR* ppv)

{

    extern CHello FAR* g_phello;

    return g_phello->QueryInterface(riid, ppv);

}

STDMETHODIMP

CHelloCF::LockServer(BOOL fLock)

{

    return NOERROR;

}


 HELLOPRO.H  (HELLO Sample)

/***

*

*  Copyright (C) 1993-1994, Microsoft Corporation.  All Rights Reserved.

*  Information Contained Herein Is Proprietary and Confidential.

*

*  File:

* 	hellopro.h

*

*  Purpose:

*	This is the header for CHelloProgrammability, which is the

*	programmability interface for CHello objects.

*

*	This is the user interface that a programmer who uses our

*	object will be using.

*

*****************************************************************************/

#include "common.h"

// Forward declaration.

CLASS CHello;

#include "ihello.h"	// Include MkTypLib-created interface

// description of _IHello.

CLASS CHelloPro : public _IHello

{

  public:

    // Standard OLE stuff.

    STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID FAR * ppvObj);

    STDMETHOD_(ULONG, AddRef)(THIS);

    STDMETHOD_(ULONG, Release)(THIS);

    STDMETHOD_(void, put_HelloMessage)(THIS_ BSTR b);

    STDMETHOD_(BSTR, get_HelloMessage)(THIS);

    STDMETHOD_(BSTR, SayHello)(THIS);

    CHello FAR*	m_phello;

};


 HELLOPRO.CPP  (HELLO Sample)

/***

*

*  Copyright (C) 1993-1994, Microsoft Corporation.  All Rights Reserved.

*  Information Contained Herein Is Proprietary and Confidential.

*

*  File:

* 	hellopro.cpp

*

*  Purpose:

*  	CHelloProgrammability is the programmability interface for

*	the CHello object.  it contains the implementation of every

*	member of the CHello class which is visible to a programmer

*	using the CHello object.

*

*****************************************************************************/

#include "common.h"

#include "resource.h"

#include "hello.h" // This also gets hellopro.h

/*      SetHelloMsg

 *

 *      SetHelloMsg sets the message that the hello object

 *      says when the SayHello method is called.

 *

 */

STDMETHODIMP_(void)

CHelloPro::put_HelloMessage(BSTR b)

{

SysReAllocString(&(m_phello->m_bstrHelloMsg), b);

}

/*      GetHelloMsg

 *

 *	GetHelloMsg gets the message that the hello object

 *	says when the SayHello method is called.

 *

 */

STDMETHODIMP_(BSTR)

CHelloPro::get_HelloMessage()

{

return SysAllocString(m_phello->m_bstrHelloMsg);

}

/*      SayHello

 *

 *	SayHello writes the string "Hello world." in the dialog's

 *	text box and returns the same string.

 *

 */

STDMETHODIMP_(BSTR)

CHelloPro::SayHello()

{

BSTR b;

b = SysAllocString(m_phello->m_bstrHelloMsg);

SetDlgItemText(m_phello->m_hwnd, IDC_HELLOAREA, STRING(b));

return b;

}

/*	IUnknown methods

 *

 * 	Simply defer to pur controlling IUnknown.

 *

 */

STDMETHODIMP

CHelloPro::QueryInterface(REFIID riid, void FAR* FAR* ppv)

{

return m_phello->QueryInterface(riid, ppv);

}

STDMETHODIMP_(ULONG)

CHelloPro::AddRef()

{

return m_phello->AddRef();

}

STDMETHODIMP_(ULONG)

CHelloPro::Release()

{

return m_phello->Release();

}


 MAIN.CPP  (HELLO Sample)

/***

*

*  Copyright (C) 1993-1994, Microsoft Corporation.  All Rights Reserved.

*  Information Contained Herein Is Proprietary and Confidential.

*

*  File:

* 	main.cpp

*

*  Purpose:

*    This file contains:

*

*      WinMain() and WndProc(), which are called by Windows when the app is run.

*      Code to initialize and uninitialize OLE.

*      Code to create and destroy the window for the application.

*

*****************************************************************************/

#include "common.h"

#include "resource.h"

#include "hello.h"

#include <string.h>

/*	Global variables.

 */

DWORD g_dwCHelloCF = 0;	  // Holds the return code for class factory creation.

CHello FAR* g_phello = NULL;	// Pointer to a CHello object.

TCHAR g_szAppName[] = TSTR("Hello"); // Name of the application.

/*	Forward declarations.

 */

HRESULT InitOle(void);

void UninitOle(void);

BOOL InitApplication(HANDLE);

BOOL InitInstance(HANDLE, int);

/*	Let Windows call WinMain and WndProc.

 */

extern "C"

{

long FAR PASCAL WndProc(HWND, UINT, WPARAM, LPARAM);

int PASCAL WinMain(HANDLE, HANDLE, LPSTR, int);

}

/*	WinMain

 *

 *	Windows calls WinMain when the application starts.

 *

 */

extern "C" int PASCAL

WinMain(

    HANDLE hinst,

    HANDLE hPrevInstance,

    LPSTR lpCmdLine,

    int nCmdShow)

{

    MSG msg;

    if(!hPrevInstance)

      if(!InitApplication(hinst))

return FALSE;

    if(InitOle() != NOERROR)

      return FALSE;

    if(!InitInstance(hinst, nCmdShow)){

      UninitOle();

      return FALSE;

    }

    while(GetMessage(&msg, NULL, NULL, NULL)) {

      TranslateMessage(&msg);

      DispatchMessage(&msg);

    }

    // Uninitialize OLE.

    UninitOle();

    return msg.wParam;

}

/*	InitApplication

 *

 *	Create a window and register it with Windows.

 *

 *	Return FALSE if an error occurs and TRUE otherwise.

 */

BOOL

InitApplication(HANDLE hinst)

{

    WNDCLASS  wc;

    wc.style	= CS_HREDRAW | CS_VREDRAW;

    wc.lpfnWndProc	= WndProc;

    wc.cbClsExtra	= 0;

    wc.cbWndExtra	= DLGWINDOWEXTRA;

    wc.hInstance	= hinst;

    wc.hIcon	= LoadIcon(hinst, g_szAppName);	// Loads hello.ico

    wc.hCursor	= LoadCursor(NULL, IDC_ARROW);	// Normal arrow pointer

    wc.hbrBackground    = (HBRUSH) (COLOR_APPWORKSPACE+1);

    wc.lpszMenuName	= NULL;	// No menus.

    wc.lpszClassName= g_szAppName;

    // Tell Windows about the window class we just created.

    // Exit if an error occurs.

    if(!RegisterClass(&wc))

      return FALSE;

    return TRUE;

}

/*	InitInstance

 *

 *	Create an instance of CHello and make g_phello

 *	point to it..

 *

 *	Return FALSE if an error occurs and TRUE otherwise.

 */

BOOL

InitInstance(HANDLE hinst, int nCmdShow)

{

    HWND hwnd;

    // Create the window and show it

    hwnd = CreateDialog(hinst, g_szAppName, 0, NULL);

    ShowWindow(hwnd, nCmdShow);

    g_phello->m_hwnd = hwnd;

    return TRUE;

}

extern "C" long FAR PASCAL

WndProc(

    HWND hwnd,

    UINT message,

    WPARAM wParam,

    LPARAM lParam)

{

    switch(message) {

      case WM_COMMAND:

  g_phello->ProcessCommand(wParam);

  return 0;

      case WM_DESTROY:

   PostQuitMessage(0);

      	   return 0;

    }

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

}

HRESULT

InitOle()

{

    HRESULT hresult;

    IClassFactory FAR* pcf;

    if((hresult = OleInitialize(NULL)) != NOERROR)

      return hresult;

    // create the single global instance of CHello

    if((g_phello = CHello::Create()) == NULL){

      hresult = ResultFromScode(E_OUTOFMEMORY);

      return hresult;

    }

    // Create an instance of the class factory for CHello.

    // Exit if an error occurs.

    pcf = CHelloCF::Create();

    if (pcf == NULL) {

      UninitOle();

      return hresult;

    }

    // Register the class factroy.  Exit if an error occurs.

    hresult = CoRegisterClassObject(CLSID_CHello,

    	    pcf,

   	    CLSCTX_LOCAL_SERVER,

   	    REGCLS_MULTIPLEUSE,

    &g_dwCHelloCF);

    if (hresult != NOERROR) {

      pcf->Release();

      UninitOle();

      return hresult;

    }

    pcf->Release();

    // If execution has reached this spot, then no errors have occurred.

    return NOERROR;

}

/*	UninitOLE

 *

 *	Tell OLE that we are going away.

 *

 */

void

UninitOle()

{

    // If a class factory was successfully created earlier then

    // tell OLE that the object is no longer available.

    if(g_dwCHelloCF != 0)

      CoRevokeClassObject(g_dwCHelloCF);

    // cause the remaining typeinfo to be released

    if (g_phello != NULL)

      g_phello->Release();

    // Tell OLE we are done using them.

    OleUninitialize();

}

#if defined(WIN32)

extern "C" char FAR*

ConvertStrWtoA(OLECHAR FAR* strIn, char FAR* buf, UINT size)

{

  int badConversion = FALSE;

  WideCharToMultiByte(CP_ACP, NULL,

              strIn, -1,

      buf, size,

      NULL, &badConversion);

  return buf;

}

extern "C" char FAR*

AnsiString(OLECHAR FAR* strIn)

{

  static char buf[256];

  return (ConvertStrWtoA(strIn, buf, 256));

}

#endif


 RESOURCE.H  (HELLO Sample)

//{{NO_DEPENDENCIES}}

// App Studio generated include file.

// Used by HELLO.RC

//

#define IDC_SAYHELLO    1000

#define IDC_HELLOAREA	1001

// Next default values for new objects

//

#ifdef APSTUDIO_INVOKED

#ifndef APSTUDIO_READONLY_SYMBOLS

#define _APS_NEXT_RESOURCE_VALUE        101

#define _APS_NEXT_COMMAND_VALUE         101

#define _APS_NEXT_CONTROL_VALUE         1000

#define _APS_NEXT_SYMED_VALUE           101

#endif

#endif


 SIMPCNTR

Simpcntr -------- This sample is the simplest OLE 2.0 container that can be written and still support the visual editing feature.  The sample has no native file format, and can only support one OLE object at a time.  The Insert Object command is used to create an object.

See the MAKEFILE for compilation instructions.


 MAKEFILE  (SIMPCNTR Sample)

!include <$(MSTOOLS)\samples\ole\include\olesampl.mak>

all: simpcntr.exe

simpcntr.exe:  app.obj         \

            doc.obj         \

            ias.obj         \

            iocs.obj        \

            ioipf.obj        \

            ioips.obj        \

            simpcntr.obj     \

            simpcntr.res     \

            site.obj

  $(link) $(linkdebug) $(guiflags) -machine:$(CPU) -out:$*.exe $** $(olelibs) ole2ui.lib

.cpp.obj:

    $(cc) $(cdebug) $(cflags) $(cvars) $*.cpp

simpcntr.res: simpcntr.rc simpcntr.h

    $(rc) -r -I..\ole2ui -I..\ole2ui\res\usa -I..\ole2ui\res\static simpcntr.rc


 APP.H  (SIMPCNTR Sample)

//**********************************************************************

// File name: app.h

//

//      Definition of CSimpleApp

//

// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#if !defined( _APP_H_)

#define _APP_H_

#include <ole2.h>

#include <stablize.h>

#include "ioipf.h"

class CSimpleDoc;

class CSimpleApp : public IUnknown, public CSafeRefCount

{

public:

        HWND m_hAppWnd;         // main window handle

        HINSTANCE m_hInst;          // application instance

        HMENU           m_hMainMenu;

        HMENU           m_hFileMenu;

        HMENU           m_hEditMenu;

        HMENU           m_hHelpMenu;

        HMENU           m_hCascadeMenu;

        COleInPlaceFrame m_OleInPlaceFrame; // IOleInPlaceFrame Implementation

        CSimpleDoc FAR * m_lpDoc;   // pointer to document object

        BOOL m_fInitialized;        // OLE initialization flag

        BOOL m_fCSHMode;

        BOOL m_fMenuMode;

        HWND m_hwndUIActiveObj; // HWND of UIActive Object

        HPALETTE m_hStdPal;     // Color palette used by container

        BOOL m_fAppActive;      // TRUE if app is active

        CSimpleApp();           // Constructor

        ~CSimpleApp();          // Destructor

        RECT nullRect;

        // IUnknown Interfaces

        STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj);

        STDMETHODIMP_(ULONG) AddRef();

        STDMETHODIMP_(ULONG) Release();

        // Initialization methods

        BOOL fInitApplication (HANDLE hInstance);

        BOOL fInitInstance (HANDLE hInstance, int nCmdShow);

        // Message handling methods

        long lCommandHandler (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

        long lSizeHandler (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

        long lCreateDoc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

        BOOL HandleAccelerators (LPMSG lpMsg);

        void PaintApp(HDC hDC);

        void DestroyDocs();

        // In-Place support functions

        void AddFrameLevelUI();

        void AddFrameLevelTools();

        void ContextSensitiveHelp (BOOL fEnterMode);

        LRESULT QueryNewPalette(void);

};

LRESULT wSelectPalette(HWND hWnd, HPALETTE hPal, BOOL fBackground);

#endif


 DOC.H  (SIMPCNTR Sample)

//**********************************************************************

// File name: doc.h

//

//      Definition of CSimpleDoc

//

// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#if !defined( _DOC_H_ )

#define _DOC_H_

#include <stablize.h>

class CSimpleSite;

class CSimpleApp;

class CSimpleDoc : public IUnknown, public CSafeRefCount

{

public:

        LPSTORAGE       m_lpStorage;

        LPOLEINPLACEACTIVEOBJECT m_lpActiveObject;

        BOOL            m_fInPlaceActive;

        BOOL            m_fAddMyUI;

        BOOL            m_fModifiedMenu;

        CSimpleSite FAR * m_lpSite;

        CSimpleApp FAR * m_lpApp;

        HWND m_hDocWnd;

        static CSimpleDoc FAR * Create(CSimpleApp FAR *lpApp, LPRECT lpRect,HWND hWnd);

        void Close(void);

        CSimpleDoc();

        CSimpleDoc(CSimpleApp FAR *lpApp, HWND hWnd);

        ~CSimpleDoc();

        // IUnknown Interface

        STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj);

        STDMETHODIMP_(ULONG) AddRef();

        STDMETHODIMP_(ULONG) Release();

        void InsertObject(void);

        void DisableInsertObject(void);

        long lResizeDoc(LPRECT lpRect);

        long lAddVerbs(void);

        void PaintDoc(HDC hDC);

};

#endif


 IAS.H  (SIMPCNTR Sample)

//**********************************************************************

// File name: IAS.H

//

//      Definition of CAdviseSink

//

// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#if !defined( _IAS_H_ )

#define _IAS_H_

#include <assert.h>

class CSimpleSite;

interface CAdviseSink : public IAdviseSink

{

int m_nCount;

CSimpleSite FAR * m_pSite;

CAdviseSink(CSimpleSite FAR * pSite) {

OutputDebugString("In IAS's constructor\r\n");

m_pSite = pSite;

m_nCount = 0;

};

~CAdviseSink() {

OutputDebugString("In IAS's destructor\r\n");

assert(m_nCount == 0);

} ;

STDMETHODIMP QueryInterface (REFIID riid, LPVOID FAR* ppv);

STDMETHODIMP_(ULONG) AddRef ();

STDMETHODIMP_(ULONG) Release ();

// *** IAdviseSink methods ***

STDMETHODIMP_(void) OnDataChange (FORMATETC FAR* pFormatetc, STGMEDIUM FAR* pStgmed);

STDMETHODIMP_(void) OnViewChange (DWORD dwAspect, LONG lindex);

STDMETHODIMP_(void) OnRename (LPMONIKER pmk);

STDMETHODIMP_(void) OnSave ();

STDMETHODIMP_(void) OnClose ();

};

#endif


 IOCS.H  (SIMPCNTR Sample)

//**********************************************************************

// File name: IOCS.H

//

//      Definition of COleClientSite

//

// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#if !defined( _IOCS_H_ )

#define _IOCS_H_

#include <assert.h>

class CSimpleSite;

interface COleClientSite : public IOleClientSite

{

int m_nCount;

CSimpleSite FAR * m_pSite;

COleClientSite(CSimpleSite FAR * pSite) {

OutputDebugString("In IOCS's constructor\r\n");

m_pSite = pSite;

m_nCount = 0;

}

~COleClientSite() {

OutputDebugString("In IOCS's destructor\r\n");

assert(m_nCount == 0);

}

STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj);

STDMETHODIMP_(ULONG) AddRef();

STDMETHODIMP_(ULONG) Release();

// *** IOleClientSite methods ***

STDMETHODIMP SaveObject();

STDMETHODIMP GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker, LPMONIKER FAR* ppmk);

STDMETHODIMP GetContainer(LPOLECONTAINER FAR* ppContainer);

STDMETHODIMP ShowObject();

STDMETHODIMP OnShowWindow(BOOL fShow);

STDMETHODIMP RequestNewObjectLayout();

};

#endif


 IOIPF.H  (SIMPCNTR Sample)

//**********************************************************************

// File name: IOIPF.H

//

//      Definition of COleInPlaceFrame

//

// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#if !defined( _IOIPF_H_ )

#define _IOIPF_H_

class CSimpleApp;

interface COleInPlaceFrame : public IOleInPlaceFrame

{

int m_nCount;

CSimpleApp FAR * m_pApp;

COleInPlaceFrame(CSimpleApp FAR * pApp) {

OutputDebugString("In IOIPF's constructor\r\n");

m_pApp = pApp;

m_nCount = 0;

};

~COleInPlaceFrame() {

OutputDebugString("In IOIPFS's destructor\r\n");

assert(m_nCount == 0);

};

STDMETHODIMP QueryInterface (REFIID riid, LPVOID FAR* ppv);

STDMETHODIMP_(ULONG) AddRef ();

STDMETHODIMP_(ULONG) Release ();

STDMETHODIMP GetWindow (HWND FAR* lphwnd);

STDMETHODIMP ContextSensitiveHelp (BOOL fEnterMode);

// *** IOleInPlaceUIWindow methods ***

STDMETHODIMP GetBorder (LPRECT lprectBorder);

STDMETHODIMP RequestBorderSpace (LPCBORDERWIDTHS lpborderwidths);

STDMETHODIMP SetBorderSpace (LPCBORDERWIDTHS lpborderwidths);

  //@@WTK WIN32, UNICODE

//STDMETHODIMP SetActiveObject (LPOLEINPLACEACTIVEOBJECT lpActiveObject,LPCSTR lpszObjName);

STDMETHODIMP SetActiveObject (LPOLEINPLACEACTIVEOBJECT lpActiveObject,LPCOLESTR lpszObjName);

// *** IOleInPlaceFrame methods ***

STDMETHODIMP InsertMenus (HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths);

STDMETHODIMP SetMenu (HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject);

STDMETHODIMP RemoveMenus (HMENU hmenuShared);

  //@@WTK WIN32, UNICODE

//STDMETHODIMP SetStatusText (LPCSTR lpszStatusText);

STDMETHODIMP SetStatusText (LPCOLESTR lpszStatusText);

STDMETHODIMP EnableModeless (BOOL fEnable);

STDMETHODIMP TranslateAccelerator (LPMSG lpmsg, WORD wID);

};

#endif


 IOIPS.H  (SIMPCNTR Sample)

//**********************************************************************

// File name: IOIPS.H

//

//      Definition of COleInPlaceSite

//

// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#if !defined( _IOIPS_H_ )

#define _IOIPS_H_

class CSimpleSite;

interface COleInPlaceSite : public IOleInPlaceSite

{

int m_nCount;

CSimpleSite FAR * m_pSite;

COleInPlaceSite(CSimpleSite FAR *pSite) {

OutputDebugString("In IOIPS's constructor\r\n");

m_pSite = pSite;

m_nCount = 0;

};

~COleInPlaceSite() {

OutputDebugString("In IOIPS;s destructor\r\n");

assert(m_nCount == 0);

};

STDMETHODIMP QueryInterface (REFIID riid, LPVOID FAR* ppv);

STDMETHODIMP_(ULONG) AddRef ();

STDMETHODIMP_(ULONG) Release ();

STDMETHODIMP GetWindow (HWND FAR* lphwnd);

STDMETHODIMP ContextSensitiveHelp (BOOL fEnterMode);

// *** IOleInPlaceSite methods ***

STDMETHODIMP CanInPlaceActivate ();

STDMETHODIMP OnInPlaceActivate ();

STDMETHODIMP OnUIActivate ();

STDMETHODIMP GetWindowContext (LPOLEINPLACEFRAME FAR* lplpFrame,

   LPOLEINPLACEUIWINDOW FAR* lplpDoc,

   LPRECT lprcPosRect,

   LPRECT lprcClipRect,

   LPOLEINPLACEFRAMEINFO lpFrameInfo);

STDMETHODIMP Scroll (SIZE scrollExtent);

STDMETHODIMP OnUIDeactivate (BOOL fUndoable);

STDMETHODIMP OnInPlaceDeactivate ();

STDMETHODIMP DiscardUndoState ();

STDMETHODIMP DeactivateAndUndo ();

STDMETHODIMP OnPosRectChange (LPCRECT lprcPosRect);

};

#endif


 PRE.H  (SIMPCNTR Sample)

//**********************************************************************

// File name: pre.h

//

//      Used for precompiled headers

//

// Copyright (c) 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#if !defined( _PRE_H_)

#define _PRE_H_

#include <windows.h>

#include <ole2.h>

#include <ole2ui.h>

#include <assert.h>

#include <string.h>

#include "simpcntr.h"

#include "resource.h"

#include <ole2ver.h>

#endif


 RESOURCE.H  (SIMPCNTR Sample)

//{{NO_DEPENDENCIES}}

// App Studio generated include file.

// Used by SIMPCNTR.RC

//

#define IDM_OPEN                        102

#define IDM_SAVE                        103

#define IDM_SAVEAS                      104

#define IDM_PRINT                       105

#define IDM_EXIT                        106

#define IDM_UNDO                        107

#define IDM_CUT                         108

#define IDM_COPY                        109

#define IDM_PASTE                       110

#define ID_EDIT_INSERTOBJECT            111

#define IDM_INSERTOBJECT                111

#define IDM_NEW                         112

// Next default values for new objects

//

#ifdef APSTUDIO_INVOKED

#ifndef APSTUDIO_READONLY_SYMBOLS

#define _APS_NEXT_RESOURCE_VALUE        101

#define _APS_NEXT_COMMAND_VALUE         113

#define _APS_NEXT_CONTROL_VALUE         1000

#define _APS_NEXT_SYMED_VALUE           101

#endif

#endif


 SIMPCNTR.H  (SIMPCNTR Sample)

//**********************************************************************

// File name: simple.h

//

// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#define IDM_ABOUT 100

#define IDM_INSERT  101

#define IDM_VERB0 1000

//@@WTK WIN32, UNICODE

#ifdef WIN32

#define EXPORT

#else

#define EXPORT __export

#endif

int PASCAL WinMain(HANDLE hInstance,HANDLE hPrevInstance,LPSTR lpCmdLine,int nCmdShow);

BOOL InitApplication(HANDLE hInstance);

BOOL InitInstance(HANDLE hInstance, int nCmdShow);

//@@WTK WIN32, UNICODE _export ==> EXPORT, portable params

long FAR PASCAL EXPORT MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

long FAR PASCAL EXPORT DocWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

BOOL FAR PASCAL EXPORT About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);


 SITE.H  (SIMPCNTR Sample)

//**********************************************************************

// File name: SITE.H

//

//      Definition of CSimpleSite

//

// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#if !defined( _SITE_H_ )

#define _SITE_H_

#include <ole2.h>

#include <stablize.h>

#include "ias.h"

#include "ioips.h"

#include "iocs.h"

class CSimpleDoc;

class CSimpleSite : public IUnknown, public CSafeRefCount

{

public:

        DWORD m_dwConnection;

        LPOLEOBJECT m_lpOleObject;

        LPOLEINPLACEOBJECT m_lpInPlaceObject;

        HWND m_hwndIPObj;

        DWORD m_dwDrawAspect;

        SIZEL m_sizel;

        BOOL m_fInPlaceActive;

        BOOL m_fObjectOpen;

        LPSTORAGE m_lpObjStorage;

        CAdviseSink m_AdviseSink;

        COleInPlaceSite m_OleInPlaceSite;

        COleClientSite m_OleClientSite;

        CSimpleDoc FAR * m_lpDoc;

        // IUnknown Interfaces

        STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj);

        STDMETHODIMP_(ULONG) AddRef();

        STDMETHODIMP_(ULONG) Release();

        void InitObject(BOOL fCreateNew);

        static CSimpleSite FAR * Create(CSimpleDoc FAR *lpDoc);

        CSimpleSite(CSimpleDoc FAR *lpDoc);

        ~CSimpleSite();

        void PaintObj(HDC hDC);

        void GetObjRect(LPRECT lpRect);

        void CloseOleObject(void);

        void UnloadOleObject(void);

};

#endif


 APP.CPP  (SIMPCNTR Sample)

//**********************************************************************

// File name: app.cpp

//

//    Implementation file for the CSimpleApp Class

//

// Functions:

//

//    See app.h for a list of member functions.

//

// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#include "pre.h"

#include "iocs.h"

#include "ias.h"

#include "ioipf.h"

#include "ioips.h"

#include "app.h"

#include "site.h"

#include "doc.h"


 CSimpleApp::CSimpleApp  (SIMPCNTR Sample)

//**********************************************************************

//

// CSimpleApp::CSimpleApp()

//

// Purpose:

//

//      Constructor for CSimpleApp

//

// Parameters:

//

//      None

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      SetRectEmpty                Windows API

//

// Comments:

//

//      CSimpleApp has a contained COleInPlaceFrame.  On construction

//      of CSimpleApp, we explicitly call the constructor of this

//      contained class and pass a copy of the this pointer, so that

//      COleInPlaceFrame can refer back to this class

//

//********************************************************************

#pragma warning(disable : 4355)  // turn off this warning.  This warning

                                                                // tells us that we are passing this in

                                                                // an initializer, before "this" is through

                                                                // initializing.  This is ok, because

                                                                // we just store the ptr in the other

                                                                // constructor

CSimpleApp::CSimpleApp() : m_OleInPlaceFrame(this)

#pragma warning (default : 4355)  // Turn the warning back on

{

        OutputDebugString("In CSimpleApp's Constructor \r\n");

        // clear members

        m_hAppWnd = NULL;

        m_hInst = NULL;

        m_lpDoc = NULL;

    m_hwndUIActiveObj = NULL;

        // clear flags

        m_fInitialized = FALSE;

        m_fCSHMode = FALSE;

        m_fMenuMode = FALSE;

        // used for inplace

        SetRectEmpty(&nullRect);

}


 CSimpleApp::~CSimpleApp  (SIMPCNTR Sample)

//**********************************************************************

//

// CSimpleApp::~CSimpleApp()

//

// Purpose:

//

//      Destructor for CSimpleApp Class.

//

// Parameters:

//

//      None

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      OleUninitialize             OLE API

//

// Comments:

//

//********************************************************************

CSimpleApp::~CSimpleApp()

{

        OutputDebugString("In CSimpleApp's Destructor\r\n");

        if (m_hStdPal)

                DeleteObject(m_hStdPal);

        // need to uninit the library...

        if (m_fInitialized)

                OleUninitialize();

}


 CSimpleApp::DestroyDocs  (SIMPCNTR Sample)

//**********************************************************************

//

// CSimpleApp::DestroyDocs()

//

// Purpose:

//

//      Destroys all of the open documents in the application (Only one

//      since this is an SDI app, but could easily be modified to

//      support MDI).

//

// Parameters:

//

//      None

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                    Location

//

// Comments:

//

//********************************************************************

void CSimpleApp::DestroyDocs()

{

        CStabilize stabilize(this);

        m_lpDoc->Close();   // we have only 1 document

}


 CSimpleApp::QueryInterface  (SIMPCNTR Sample)

//**********************************************************************

//

// CSimpleApp::QueryInterface

//

// Purpose:

//

//      Used for interface negotiation at the Frame level.

//

// Parameters:

//

//      REFIID riid         -   A reference to the interface that is

//                              being queried.

//

//      LPVOID FAR* ppvObj  -   An out parameter to return a pointer to

//                              the interface.

//

// Return Value:

//

//      S_OK    -   The interface is supported.

//      S_FALSE -   The interface is not supported

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      IsEqualIID                  OLE API

//      ResultFromScode             OLE API

//      COleInPlaceFrame::AddRef    IOIPF.CPP

//

// Comments:

//

//      Note that this QueryInterface is associated with the frame.

//      Since the application could potentially have multiple documents

//      and multiple objects, a lot of the interfaces are ambiguous.

//      (ie. which IOleObject is returned?).  For this reason, only

//      pointers to interfaces associated with the frame are returned.

//      In this implementation, Only IOleInPlaceFrame (or one of the

//      interfaces it is derived from) can be returned.

//

//********************************************************************

STDMETHODIMP CSimpleApp::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)

{

        OutputDebugString("In CSimpleApp::QueryInterface\r\n");

        *ppvObj = NULL;     // must set out pointer parameters to NULL

        // looking for IUnknown

        if ( riid == IID_IUnknown)

                {

                AddRef();

                *ppvObj = this;

                return ResultFromScode(S_OK);

                }

        // looking for IOleWindow

        if ( riid == IID_IOleWindow)

                {

                m_OleInPlaceFrame.AddRef();

                *ppvObj=&m_OleInPlaceFrame;

                return ResultFromScode(S_OK);

                }

        // looking for IOleInPlaceUIWindow

        if ( riid == IID_IOleInPlaceUIWindow)

                {

                m_OleInPlaceFrame.AddRef();

                *ppvObj=&m_OleInPlaceFrame;

                return ResultFromScode(S_OK);

                }

        // looking for IOleInPlaceFrame

        if ( riid == IID_IOleInPlaceFrame)

                {

                m_OleInPlaceFrame.AddRef();

                *ppvObj=&m_OleInPlaceFrame;

                return ResultFromScode(S_OK);

                }

        // Not a supported interface

        return ResultFromScode(E_NOINTERFACE);

}


 CSimpleApp::AddRef  (SIMPCNTR Sample)

//**********************************************************************

//

// CSimpleApp::AddRef

//

// Purpose:

//

//      Adds to the reference count at the Application level.

//

// Parameters:

//

//      None

//

// Return Value:

//

//      ULONG   -   The new reference count of the application.

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//      Due to the reference counting model that is used in this

//      implementation, this reference count is the sum of the

//      reference counts on all interfaces of all objects open

//      in the application.

//

//********************************************************************

STDMETHODIMP_(ULONG) CSimpleApp::AddRef()

{

        OutputDebugString("In CSimpleApp::AddRef\r\n");

        return SafeAddRef();

}


 CSimpleApp::Release  (SIMPCNTR Sample)

//**********************************************************************

//

// CSimpleApp::Release

//

// Purpose:

//

//      Decrements the reference count at this level

//

// Parameters:

//

//      None

//

// Return Value:

//

//      ULONG   -   The new reference count of the application.

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//********************************************************************

STDMETHODIMP_(ULONG) CSimpleApp::Release()

{

        OutputDebugString("In CSimpleApp::Release\r\n");

        return SafeRelease();

}


 CSimpleApp::fInitApplication  (SIMPCNTR Sample)

//**********************************************************************

//

// CSimpleApp::fInitApplication

//

// Purpose:

//

//      Initializes the application

//

// Parameters:

//

//      HANDLE hInstance    -   Instance handle of the application.

//

// Return Value:

//

//      TRUE    -   Application was successfully initialized.

//      FALSE   -   Application could not be initialized

//

// Function Calls:

//      Function                    Location

//

//      LoadIcon                    Windows API

//      LoadCursor                  Windows API

//      GetStockObject              Windows API

//      RegisterClass               Windows API

//

// Comments:

//

//********************************************************************

BOOL CSimpleApp::fInitApplication(HANDLE hInstance)

{

        WNDCLASS  wc;

        // Fill in window class structure with parameters that describe the

        // main window.

        wc.style = NULL;                    // Class style(s).

        wc.lpfnWndProc = MainWndProc;       // Function to retrieve messages for

                                                                                // windows of this class.

        wc.cbClsExtra = 0;                  // No per-class extra data.

        wc.cbWndExtra = 0;                  // No per-window extra data.

        wc.hInstance = hInstance;           // Application that owns the class.

        wc.hIcon = LoadIcon(hInstance, "SimpCntr");

        wc.hCursor = LoadCursor(NULL, IDC_ARROW);

        wc.hbrBackground = GetStockObject(WHITE_BRUSH);

        wc.lpszMenuName =  "SIMPLEMENU";    // Name of menu resource in .RC file.

        wc.lpszClassName = "SimpCntrAppWClass";  // Name used in CreateWindow call

        if (!RegisterClass(&wc))

                return FALSE;

        wc.style = CS_DBLCLKS;              // Class style(s). allow DBLCLK's

        wc.lpfnWndProc = DocWndProc;        // Function to retrieve messages for

                                                                                // windows of this class.

        wc.cbClsExtra = 0;                  // No per-class extra data.

        wc.cbWndExtra = 0;                  // No per-window extra data.

        wc.hInstance = hInstance;           // Application that owns the class.

        wc.hIcon = NULL;

        wc.hCursor = LoadCursor(NULL, IDC_ARROW);

        wc.hbrBackground = GetStockObject(WHITE_BRUSH);

        wc.lpszMenuName =  NULL;

        wc.lpszClassName = "SimpCntrDocWClass"; // Name used in CreateWindow call.

        // Register the window class and return success/failure code.

        return (RegisterClass(&wc));

}


 CSimpleApp::fInitInstance  (SIMPCNTR Sample)

//**********************************************************************

//

// CSimpleApp::fInitInstance

//

// Purpose:

//

//      Instance initialization.

//

// Parameters:

//

//      HANDLE hInstance    -   App. Instance Handle.

//

//      int nCmdShow        -   Show parameter from WinMain

//

// Return Value:

//

//      TRUE    -   Initialization Successful

//      FALSE   -   Initialization Failed.

//

//

// Function Calls:

//      Function                    Location

//

//      CreateWindow                Windows API

//      ShowWindow                  Windows API

//      UpdateWindow                Windows API

//      OleBuildVersion             OLE API

//      OleInitialize               OLE API

//

// Comments:

//

//      Note that successful Initalization of the OLE libraries

//      is remembered so the UnInit is only called if needed.

//

//********************************************************************

BOOL CSimpleApp::fInitInstance (HANDLE hInstance, int nCmdShow)

{

        DWORD dwVer = OleBuildVersion();

        LPMALLOC lpMalloc = NULL;

        // check to see if we are compatible with this version of the libraries

        if (HIWORD(dwVer) != rmm || LOWORD(dwVer) < rup) {

#ifdef _DEBUG

                OutputDebugString("WARNING: Incompatible OLE library version\r\n");

#else

                return FALSE;

#endif

        }

#if defined( _DEBUG )

        /* OLE2NOTE: Use a special debug allocator to help track down

        **    memory leaks.

        */

        OleStdCreateDbAlloc(0, &lpMalloc);

#endif

        if (SUCCEEDED(OleInitialize(lpMalloc)))

        {

                m_fInitialized = TRUE;

        }

        else

        {

            // Replacing the standard allocator may not be legal.

            // Try again using the default allocator.

            if (SUCCEEDED(OleInitialize(NULL)))

            {

                m_fInitialized = TRUE;

            }

        }

#if defined( _DEBUG )

        /* OLE2NOTE: release the special debug allocator so that only OLE is

        **    holding on to it. later when OleUninitialize is called, then

        **    the debug allocator object will be destroyed. when the debug

        **    allocator object is destoyed, it will report (to the Output

        **    Debug Terminal) whether there are any memory leaks.

        */

        if (lpMalloc) lpMalloc->Release();

#endif

        m_hInst = hInstance;

        // Create the "application" windows

        m_hAppWnd = CreateWindow ("SimpCntrAppWClass",

                                                          "Simple OLE 2.0 In-Place Container",

                                                          WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,

                                                          CW_USEDEFAULT,

                                                          CW_USEDEFAULT,

                                                          CW_USEDEFAULT,

                                                          CW_USEDEFAULT,

                                                          NULL,

                                                          NULL,

                                                          hInstance,

                                                          NULL);

        if (!m_hAppWnd)

                return FALSE;

        m_hStdPal = OleStdCreateStandardPalette();

        ShowWindow (m_hAppWnd, nCmdShow);

        UpdateWindow (m_hAppWnd);

        return m_fInitialized;

}


 CSimpleApp::lCommandHandler  (SIMPCNTR Sample)

//**********************************************************************

//

// CSimpleApp::lCommandHandler

//

// Purpose:

//

//      Handles the processing of WM_COMMAND.

//

// Parameters:

//

//      HWND hWnd       -   Handle to the application Window

//

//      UINT message    -   message (always WM_COMMAND)

//

//      WPARAM wParam   -   Same as passed to the WndProc

//

//      LPARAM lParam   -   Same as passed to the WndProc

//

// Return Value:

//

//      NULL

//

// Function Calls:

//      Function                                    Location

//

//      IOleInPlaceActiveObject::QueryInterface     Object

//      IOleInPlaceObject::ContextSensitiveHelp     Object

//      IOleInPlaceObject::Release                  Object

//      IOleObject::DoVerb                          Object

//      GetClientRect                               Windows API

//      MessageBox                                  Windows API

//      DialogBox                                   Windows API

//      MakeProcInstance                            Windows API

//      FreeProcInstance                            Windows API

//      SendMessage                                 Windows API

//      DefWindowProc                               Windows API

//      CSimpleDoc::InsertObject                    DOC.CPP

//

// Comments:

//

//********************************************************************

long CSimpleApp::lCommandHandler (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

{

        CStabilize stabilize(this);

        RECT rect;

        // context sensitive help...

        if (m_fMenuMode || m_fCSHMode)

                {

                if (m_fCSHMode)

                        {

                        // clear context sensitive help flag

                        m_fCSHMode = FALSE;

                        // if there is an InPlace active object, call its context sensitive help

                        // method with the FALSE parameter to bring the object out of the

                        // csh state.  See the technotes for details.

                        if (m_lpDoc->m_lpActiveObject)

                                {

                                LPOLEINPLACEOBJECT lpInPlaceObject;

                                m_lpDoc->m_lpActiveObject->QueryInterface(IID_IOleInPlaceObject, (LPVOID FAR *)&lpInPlaceObject);

                                lpInPlaceObject->ContextSensitiveHelp(FALSE);

                                lpInPlaceObject->Release();

                                }

                        }

                // see the technotes for details on implementing context sensitive

                // help

                if (m_fMenuMode)

                        {

                        m_fMenuMode = FALSE;

                        if (m_lpDoc->m_lpActiveObject)

                                m_lpDoc->m_lpActiveObject->ContextSensitiveHelp(FALSE);

                        }

                // if we provided help, we would do it here...

                MessageBox (hWnd, "Help", "Help", MB_OK);

                return NULL;

                }

        // see if the command is a verb selections

        //@@WTK WIN32, UNICODE

        //if (wParam >= IDM_VERB0)

        if (LOWORD(wParam) >= IDM_VERB0)

                {

                // get the rectangle of the object

                m_lpDoc->m_lpSite->GetObjRect(&rect);

                //@@WTK WIN32, UNICODE

                //m_lpDoc->m_lpSite->m_lpOleObject->DoVerb(wParam - IDM_VERB0, NULL, &m_lpDoc->m_lpSite->m_OleClientSite, -1, m_lpDoc->m_hDocWnd, &rect);

                m_lpDoc->m_lpSite->m_lpOleObject->DoVerb(LOWORD(wParam) - IDM_VERB0, NULL,

                                &m_lpDoc->m_lpSite->m_OleClientSite, -1, m_lpDoc->m_hDocWnd, &rect);

                }

        else

                {

                //@@WTK WIN32, UNICODE

                //switch (wParam) {

                switch (LOWORD(wParam)) {

                        // bring up the About box

                        case IDM_ABOUT:

                                {

                                FARPROC lpProcAbout = MakeProcInstance((FARPROC)About, m_hInst);

                                DialogBox(m_hInst,               // current instance

                                        "AboutBox",                  // resource to use

                                        m_hAppWnd,                   // parent handle

                                        lpProcAbout);                // About() instance address

                                FreeProcInstance(lpProcAbout);

                                break;

                                }

                        // bring up the InsertObject Dialog

                        case IDM_INSERTOBJECT:

                                m_lpDoc->InsertObject();

                                break;

                        // exit the application

                        case IDM_EXIT:

                                SendMessage(hWnd, WM_SYSCOMMAND, SC_CLOSE, 0L);

                                break;

                        case IDM_NEW:

                                m_lpDoc->Close();

                                m_lpDoc = NULL;

                                lCreateDoc(hWnd, 0, 0, 0);

                                break;

                        default:

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

                        }   // end of switch

                }  // end of else

        return NULL;

}


 CSimpleApp::lSizeHandler  (SIMPCNTR Sample)

//**********************************************************************

//

// CSimpleApp::lSizeHandler

//

// Purpose:

//

//      Handles the WM_SIZE message

//

// Parameters:

//

//      HWND hWnd       -   Handle to the application Window

//

//      UINT message    -   message (always WM_SIZE)

//

//      WPARAM wParam   -   Same as passed to the WndProc

//

//      LPARAM lParam   -   Same as passed to the WndProc

//

// Return Value:

//

//      LONG    -   returned from the "document" resizing

//

// Function Calls:

//      Function                    Location

//

//      GetClientRect               Windows API

//      CSimpleDoc::lResizeDoc      DOC.CPP

//

// Comments:

//

//********************************************************************

long CSimpleApp::lSizeHandler (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

{

        CStabilize stabilize(this);

        RECT rect;

        GetClientRect(m_hAppWnd, &rect);

        return m_lpDoc->lResizeDoc(&rect);

}


 CSimpleApp::lCreateDoc  (SIMPCNTR Sample)

//**********************************************************************

//

// CSimpleApp::lCreateDoc

//

// Purpose:

//

//      Handles the creation of a document.

//

// Parameters:

//

//      HWND hWnd       -   Handle to the application Window

//

//      UINT message    -   message (always WM_CREATE)

//

//      WPARAM wParam   -   Same as passed to the WndProc

//

//      LPARAM lParam   -   Same as passed to the WndProc

//

// Return Value:

//

//      NULL

//

// Function Calls:

//      Function                    Location

//

//      GetClientRect               Windows API

//      CSimpleDoc::CSimpleDoc      DOC.CPP

//

// Comments:

//

//********************************************************************

long CSimpleApp::lCreateDoc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

{

        CStabilize stabilize(this);

        RECT rect;

        GetClientRect(hWnd, &rect);

        m_lpDoc = CSimpleDoc::Create(this, &rect, hWnd);

        return NULL;

}


 CSimpleApp::AddFrameLevelUI  (SIMPCNTR Sample)

//**********************************************************************

//

// CSimpleApp::AddFrameLevelUI

//

// Purpose:

//

//      Used during InPlace negotiation.

//

// Parameters:

//

//      None

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                            Location

//

//      COleInPlaceFrame::SetMenu           IOIPF.CPP

//      CSimpleApp::AddFrameLevelTools      APP.CPP

//

// Comments:

//

//      Be sure to read the Technotes included in the OLE 2.0 toolkit

//

//********************************************************************

void CSimpleApp::AddFrameLevelUI()

{

        CStabilize stabilize(this);

        m_OleInPlaceFrame.SetMenu(NULL, NULL, NULL);

        AddFrameLevelTools();

}


 CSimpleApp::AddFrameLevelTools  (SIMPCNTR Sample)

//**********************************************************************

//

// CSimpleApp::AddFrameLevelTools

//

// Purpose:

//

//      Used during InPlace negotiation.

//

// Parameters:

//

//      None

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                              Location

//

//      COleInPlaceFrame::SetBorderSpace      IOIPF.CPP

//      InvalidateRect                        Windows API

//

// Comments:

//

//      Be sure to read the Technotes included in the OLE 2.0 toolkit

//

//********************************************************************

void CSimpleApp::AddFrameLevelTools()

{

        CStabilize stabilize(this);

        m_OleInPlaceFrame.SetBorderSpace(&nullRect);

        InvalidateRect(m_hAppWnd, NULL, TRUE);

}


 CSimpleApp::HandleAccelerators  (SIMPCNTR Sample)

//**********************************************************************

//

// CSimpleApp::HandleAccelerators

//

// Purpose:

//

//      To properly handle accelerators in the Message Loop

//

// Parameters:

//

//      LPMSG lpMsg -   A pointer to the message structure.

//

// Return Value:

//

//      TRUE    -   The accelerator was handled

//      FALSE   -   The accelerator was not handled

//

// Function Calls:

//      Function                                        Location

//

//      IOleInPlaceActiveObject::TranslateAccelerator   Object

//

// Comments:

//

//      If an object is InPlace active, it gets the first shot at

//      handling the accelerators.

//

//********************************************************************

BOOL CSimpleApp::HandleAccelerators(LPMSG lpMsg)

{

        CStabilize stabilize(this);

        HRESULT hResult;

        BOOL retval = FALSE;

        // if we have an InPlace Active Object

        if (m_lpDoc->m_lpActiveObject)

                {

                // Pass the accelerator on...

                hResult = m_lpDoc->m_lpActiveObject->TranslateAccelerator(lpMsg);

                if (hResult == NOERROR)

                        retval = TRUE;

                }

        return retval;

}


 CSimpleApp::PaintApp  (SIMPCNTR Sample)

//**********************************************************************

//

// CSimpleApp::PaintApp

//

// Purpose:

//

//      Handles the painting of the doc window.

//

//

// Parameters:

//

//      HDC hDC -   hDC to the Doc Window.

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                    Location

//

//      CSimpleDoc::PaintDoc        DOC.CPP

//

// Comments:

//

//      This is an app level function in case we want to do palette

//      management.

//

//********************************************************************

void CSimpleApp::PaintApp (HDC hDC)

{

        CStabilize stabilize(this);

        // at this level, we could enumerate through all of the

        // visible objects in the application, so that a palette

        // that best fits all of the objects can be built.

        // This app is designed to take on the same palette

        // functionality that was provided in OLE 1.0, the palette

        // of the last object drawn is realized.  Since we only

        // support one object at a time, it shouldn't be a big

        // deal.

        // if we supported multiple documents, we would enumerate

        // through each of the open documents and call paint.

        if (m_lpDoc)

                m_lpDoc->PaintDoc(hDC);

}


 CSimpleApp::ContextSensitiveHelp  (SIMPCNTR Sample)

//**********************************************************************

//

// CSimpleApp::ContextSensitiveHelp

//

// Purpose:

//      Used in supporting context sensitive haelp at the app level.

//

//

// Parameters:

//

//      BOOL fEnterMode    -   Entering/Exiting Context Sensitive

//                             help mode.

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                                    Location

//

//      IOleInPlaceActiveObject::QueryInterface     Object

//      IOleInPlaceObject::ContextSensitiveHelp     Object

//      IOleInPlaceObject::Release                  Object

//

// Comments:

//

//      This function isn't used because we don't support Shift+F1

//      context sensitive help.  Be sure to look at the technotes

//      in the OLE 2.0 toolkit.

//

//********************************************************************

void CSimpleApp::ContextSensitiveHelp (BOOL fEnterMode)

{

        CStabilize stabilize(this);

        if (m_fCSHMode != fEnterMode)

                {

                m_fCSHMode = fEnterMode;

                // this code "trickles" the context sensitive help via shift+f1

                // to the inplace active object.  See the technotes for implementation

                // details.

                if (m_lpDoc->m_lpActiveObject)

                        {

                        LPOLEINPLACEOBJECT lpInPlaceObject;

                        m_lpDoc->m_lpActiveObject->QueryInterface(IID_IOleInPlaceObject, (LPVOID FAR *)&lpInPlaceObject);

                        lpInPlaceObject->ContextSensitiveHelp(fEnterMode);

                        lpInPlaceObject->Release();

                        }

                }

}

/* OLE2NOTE: forward the WM_QUERYNEWPALETTE message (via

**    SendMessage) to UIActive in-place object if there is one.

**    this gives the UIActive object the opportunity to select

**    and realize its color palette as the FOREGROUND palette.

**    this is optional for in-place containers. if a container

**    prefers to force its color palette as the foreground

**    palette then it should NOT forward the this message. or

**    the container can give the UIActive object priority; if

**    the UIActive object returns 0 from the WM_QUERYNEWPALETTE

**    message (ie. it did not realize its own palette), then

**    the container can realize its palette.

**    (see ContainerDoc_ForwardPaletteChangedMsg for more info)

**

**    (It is a good idea for containers to use the standard

**    palette even if they do not use colors themselves. this

**    will allow embedded object to get a good distribution of

**    colors when they are being drawn by the container)

**

*/

LRESULT CSimpleApp::QueryNewPalette(void)

{

        if (m_hwndUIActiveObj) {

                if (SendMessage(m_hwndUIActiveObj, WM_QUERYNEWPALETTE,

                                (WPARAM)0, (LPARAM)0)) {

                        /* Object selected its palette as foreground palette */

                        return (LRESULT)1;

                }

        }

        return wSelectPalette(m_hAppWnd, m_hStdPal, FALSE/*fBackground*/);

}

/* This is just a helper routine */

LRESULT wSelectPalette(HWND hWnd, HPALETTE hPal, BOOL fBackground)

{

        HDC hdc;

        HPALETTE hOldPal;

        UINT iPalChg = 0;

        if (hPal == 0)

                return (LRESULT)0;

        hdc = GetDC(hWnd);

        hOldPal = SelectPalette(hdc, hPal, fBackground);

        iPalChg = RealizePalette(hdc);

        SelectPalette(hdc, hOldPal, TRUE /*fBackground*/);

        ReleaseDC(hWnd, hdc);

        if (iPalChg > 0)

                InvalidateRect(hWnd, NULL, TRUE);

        return (LRESULT)1;

}


 DOC.CPP  (SIMPCNTR Sample)

//**********************************************************************

// File name: DOC.CPP

//

//      Implementation file for CSimpleDoc.

//

// Functions:

//

//      See DOC.H for Class Definition

//

// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#include "pre.h"

#include "iocs.h"

#include "ias.h"

#include "ioipf.h"

#include "ioips.h"

#include "app.h"

#include "site.h"

#include "doc.h"


 CSimpleDoc::Create  (SIMPCNTR Sample)

//**********************************************************************

//

// CSimpleDoc::Create

//

// Purpose:

//

//      Creation for the CSimpleDoc Class

//

// Parameters:

//

//      CSimpleApp FAR * lpApp  -   Pointer to the CSimpleApp Class

//

//      LPRECT lpRect           -   Client area rect of "frame" window

//

//      HWND hWnd               -   Window Handle of "frame" window

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                    Location

//

//      StgCreateDocfile            OLE API

//      CreateWindow                Windows API

//      ShowWindow                  Windows API

//      UpdateWindow                Windows API

//

// Comments:

//

//      This routine was added so that failure could be returned

//      from object creation.

//

//********************************************************************

CSimpleDoc FAR * CSimpleDoc::Create(CSimpleApp FAR *lpApp, LPRECT lpRect,HWND hWnd)

{

        CSimpleDoc FAR * lpTemp = new CSimpleDoc(lpApp, hWnd);

        if (!lpTemp)

                return NULL;

        // create storage for the doc.

        HRESULT hErr = StgCreateDocfile (NULL, STGM_READWRITE | STGM_TRANSACTED | STGM_SHARE_EXCLUSIVE,

                                                                         0, &lpTemp->m_lpStorage);

        if (hErr != NOERROR)

                goto error;

        // create the document Window

        lpTemp->m_hDocWnd = CreateWindow(

                        "SimpCntrDocWClass",

                        NULL,

                        WS_CHILD | WS_CLIPCHILDREN,

                        lpRect->left,

                        lpRect->top,

                        lpRect->right,

                        lpRect->bottom,

                        hWnd,

                        NULL,

                        lpApp->m_hInst,

                        NULL);

        if (!lpTemp->m_hDocWnd)

                goto error;

        ShowWindow(lpTemp->m_hDocWnd, SW_SHOWNORMAL);  // Show the window

        UpdateWindow(lpTemp->m_hDocWnd);               // Sends WM_PAINT message

        // Ensable InsertObject menu choice

        EnableMenuItem( lpApp->m_hEditMenu, 0, MF_BYPOSITION | MF_ENABLED);

        // we will add one ref count on our document. later in CSimpleDoc::Close

        // we will release this  ref count. when the document's ref count goes

        // to 0, the document will be deleted.

        lpTemp->AddRef();

        return (lpTemp);

error:

        delete (lpTemp);

        return NULL;

}


 CSimpleDoc::Close  (SIMPCNTR Sample)

//**********************************************************************

//

// CSimpleDoc::Close

//

// Purpose:

//

//      Close CSimpleDoc object.

//      when the document's reference count goes to 0, the document

//      will be destroyed.

//

// Parameters:

//

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                    Location

//

//      RevokeDragDrop              OLE API

//      CoLockObjectExternal        OLE API

//      OleFlushClipboard           OLE API

//      ShowWindow                  Windows API

//

// Comments:

//

//********************************************************************

void CSimpleDoc::Close(void)

{

        OutputDebugString("In CSimpleDoc::Close\r\n");

        ShowWindow(m_hDocWnd, SW_HIDE);  // Hide the window

        // Close the OLE object in our document

        if (m_lpSite)

                m_lpSite->CloseOleObject();

        // Release the ref count added in CSimpleDoc::Create. this will make

        // the document's ref count go to 0, and the document will be deleted.

        Release();

}


 CSimpleDoc::CSimpleDoc  (SIMPCNTR Sample)

//**********************************************************************

//

// CSimpleDoc::CSimpleDoc

//

// Purpose:

//

//      Constructor for the CSimpleDoc Class

//

// Parameters:

//

//      CSimpleApp FAR * lpApp  -   Pointer to the CSimpleApp Class

//

//      HWND hWnd               -   Window Handle of "frame" window

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      GetMenu                     Windows API

//      GetSubMenu                  Windows API

//

// Comments:

//

//********************************************************************

CSimpleDoc::CSimpleDoc(CSimpleApp FAR * lpApp,HWND hWnd)

{

        OutputDebugString("In CSimpleDoc's Constructor\r\n");

        m_lpApp = lpApp;

        m_lpSite = NULL;

        // set up menu handles

        m_lpApp->m_hMainMenu = GetMenu(hWnd);

        m_lpApp->m_hFileMenu = GetSubMenu(m_lpApp->m_hMainMenu, 0);

        m_lpApp->m_hEditMenu = GetSubMenu(m_lpApp->m_hMainMenu, 1);

        m_lpApp->m_hHelpMenu = GetSubMenu(m_lpApp->m_hMainMenu, 2);

        m_lpApp->m_hCascadeMenu = NULL;

        m_lpActiveObject = NULL;

        // flags

        m_fInPlaceActive = FALSE;

        m_fAddMyUI = FALSE;

        m_fModifiedMenu = FALSE;

}


 CSimpleDoc::~CSimpleDoc  (SIMPCNTR Sample)

//**********************************************************************

//

// CSimpleDoc::~CSimpleDoc

//

// Purpose:

//

//      Destructor for CSimpleDoc

//

// Parameters:

//

//      None

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      CSimpleSite::Release        SITE.CPP

//      IStorage::Release           OLE API

//

// Comments:

//

//********************************************************************

CSimpleDoc::~CSimpleDoc()

{

        OutputDebugString("In CSimpleDoc's Destructor\r\n");

        // Release all pointers we hold to the OLE object. also release

        // the ref count added in CSimpleSite::Create. this will make

        // the Site's ref count go to 0, and the Site will be deleted.

        if (m_lpSite) {

                m_lpSite->UnloadOleObject();

                m_lpSite->Release();

                m_lpSite = NULL;

        }

        // Release the Storage

        if (m_lpStorage) {

                m_lpStorage->Release();

                m_lpStorage = NULL;

        }

        // if the edit menu was modified, remove the menu item and

        // destroy the popup if it exists

        if (m_fModifiedMenu)

                {

                int nCount = GetMenuItemCount(m_lpApp->m_hEditMenu);

                RemoveMenu(m_lpApp->m_hEditMenu, nCount-1, MF_BYPOSITION);

                if (m_lpApp->m_hCascadeMenu)

                        DestroyMenu(m_lpApp->m_hCascadeMenu);

                }

        DestroyWindow(m_hDocWnd);

}


 CSimpleDoc::QueryInterface  (SIMPCNTR Sample)

//**********************************************************************

//

// CSimpleDoc::QueryInterface

//

// Purpose:

//

//      Return a pointer to a requested interface

//

// Parameters:

//

//      REFIID riid         -   ID of interface to be returned

//      LPVOID FAR* ppvObj  -   Location to return the interface

//

// Return Value:

//

//      S_FALSE -   Always

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      ResultFromScode             OLE API

//

// Comments:

//

//      In this implementation, there are no doc level interfaces.

//      In an MDI application, there would be an IOleInPlaceUIWindow

//      associated with the document to provide document level tool

 //     space negotiation.

//

//********************************************************************

STDMETHODIMP CSimpleDoc::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)

{

        OutputDebugString("In CSimpleDoc::QueryInterface\r\n");

        *ppvObj = NULL;     // must set out pointer parameters to NULL

        // Not a supported interface

        return ResultFromScode(E_NOINTERFACE);

}


 CSimpleDoc::AddRef  (SIMPCNTR Sample)

//**********************************************************************

//

// CSimpleDoc::AddRef

//

// Purpose:

//

//      Increments the document reference count

//

// Parameters:

//

//      None

//

// Return Value:

//

//      UINT    -   The current reference count on the document

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      CSimpleApp::AddRef          APP.CPP

//

// Comments:

//

//********************************************************************

STDMETHODIMP_(ULONG) CSimpleDoc::AddRef()

{

        OutputDebugString("In CSimpleDoc::AddRef\r\n");

        return SafeAddRef();

}


 CSimpleDoc::Release  (SIMPCNTR Sample)

//**********************************************************************

//

// CSimpleDoc::Release

//

// Purpose:

//

//      Decrements the document reference count

//

// Parameters:

//

//      None

//

// Return Value:

//

//      UINT    -   The current reference count on the document

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//********************************************************************

STDMETHODIMP_(ULONG) CSimpleDoc::Release()

{

        OutputDebugString("In CSimpleDoc::Release\r\n");

        return SafeRelease();

}


 CSimpleDoc::InsertObject  (SIMPCNTR Sample)

//**********************************************************************

//

// CSimpleDoc::InsertObject

//

// Purpose:

//

//      Inserts a new object to this document

//

// Parameters:

//

//      None

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                    Location

//

//      CSimpleSite::CSimpleSite    SITE.CPP

//      CSimpleSite::InitObject     SITE.CPP

//      memset                      C Runtime

//      OleUIInsertObject           OUTLUI function

//      CSimpleDoc::DisableInsertObject DOC.CPP

//

// Comments:

//

//      This implementation only allows one object to be inserted

//      into a document.  Once the object has been inserted, then

//      the Insert Object menu choice is greyed out, to prevent

//      the user from inserting another.

//

//********************************************************************

void CSimpleDoc::InsertObject()

{

        CStabilize stabilize(this);

        OLEUIINSERTOBJECT io;

        UINT iret;

  //@@WTK WIN32, UNICODE

        //char szFile[OLEUI_CCHPATHMAX];

        OLECHAR szFile[OLEUI_CCHPATHMAX];

        m_lpSite = CSimpleSite::Create(this);

        // clear the structure

        _fmemset(&io, 0, sizeof(OLEUIINSERTOBJECT));

        // fill the structure

        io.cbStruct = sizeof(OLEUIINSERTOBJECT);

        io.dwFlags = IOF_SELECTCREATENEW |

                                        IOF_DISABLELINK | IOF_DISABLEDISPLAYASICON |

                                        IOF_CREATENEWOBJECT | IOF_CREATEFILEOBJECT;

        io.hWndOwner = m_hDocWnd;

  //@@WTK WIN32, UNICODE

        //io.lpszCaption = (LPSTR)"Insert Object";

        io.lpszCaption = OLESTR("Insert Object");

        io.iid = IID_IOleObject;

        io.oleRender = OLERENDER_DRAW;

        io.lpIOleClientSite = &m_lpSite->m_OleClientSite;

        io.lpIStorage = m_lpSite->m_lpObjStorage;

        io.ppvObj = (LPVOID FAR *)&m_lpSite->m_lpOleObject;

        io.lpszFile = szFile;

  //@@WTK WIN32, UNICODE

        //io.cchFile = sizeof(szFile);

        io.cchFile = sizeof(szFile) / sizeof *szFile;

  //@@WTK WIN32, UNICODE

        //_fmemset((LPSTR)szFile, 0, sizeof(szFile));

        _fmemset(szFile, 0, sizeof(szFile));

        // call OUTLUI to do all the hard work

        iret = OleUIInsertObject(&io);

        if (iret == OLEUI_OK)

                {

                m_lpSite->InitObject((BOOL)(io.dwFlags & IOF_SELECTCREATENEW));

                // disable Insert Object menu item

                DisableInsertObject();

                }

        else

                {

                m_lpSite->Release();

                m_lpSite = NULL;

                m_lpStorage->Revert();

                }

}


 CSimpleDoc::lResizeDoc  (SIMPCNTR Sample)

//**********************************************************************

//

// CSimpleDoc::lResizeDoc

//

// Purpose:

//

//      Resizes the document

//

// Parameters:

//

//      LPRECT lpRect   -   The size of the client are of the "frame"

//                          Window.

//

// Return Value:

//

//      NULL

//

// Function Calls:

//      Function                                Location

//

//      IOleInPlaceActiveObject::ResizeBorder   Object

//      MoveWindow                              Windows API

//

// Comments:

//

//********************************************************************

long CSimpleDoc::lResizeDoc(LPRECT lpRect)

{

        CStabilize stabilize(this);

        // if we are InPlace, then call ResizeBorder on the object, otherwise

        // just move the document window.

        if (m_fInPlaceActive)

                m_lpActiveObject->ResizeBorder(lpRect, &m_lpApp->m_OleInPlaceFrame, TRUE);

        else

                MoveWindow(m_hDocWnd, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom, TRUE);

        return NULL;

}


 CSimpleDoc::lAddVerbs  (SIMPCNTR Sample)

//**********************************************************************

//

// CSimpleDoc::lAddVerbs

//

// Purpose:

//

//      Adds the objects verbs to the edit menu.

//

// Parameters:

//

//      None

//

// Return Value:

//

//      NULL

//

// Function Calls:

//      Function                    Location

//

//      GetMenuItemCount            Windows API

//      OleUIAddVerbMenu            OUTLUI function

//

// Comments:

//

//********************************************************************

long CSimpleDoc::lAddVerbs(void)

{

        CStabilize stabilize(this);

        // m_fModifiedMenu is TRUE if the menu has already been modified

        // once.  Since we only support one obect every time the application

        // is run, then once the menu is modified, it doesn't have

        // to be done again.

        if (m_lpSite && !m_fInPlaceActive  && !m_fModifiedMenu)

                {

                int nCount = GetMenuItemCount(m_lpApp->m_hEditMenu);

                OleUIAddVerbMenu ( m_lpSite->m_lpOleObject,

                                                   NULL,

                                                   m_lpApp->m_hEditMenu,

                                                   nCount + 1,

                                                   IDM_VERB0,

                                                   0,           // no maximum verb IDM enforced

                                                   FALSE,

                                                   0,

                                                   &m_lpApp->m_hCascadeMenu);

                m_fModifiedMenu = TRUE;

                }

        return (NULL);

}


 CSimpleDoc::PaintDoc  (SIMPCNTR Sample)

//**********************************************************************

//

// CSimpleDoc::PaintDoc

//

// Purpose:

//

//      Paints the Document

//

// Parameters:

//

//      HDC hDC -   hDC of the document Window

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                    Location

//

//      CSimpleSite::PaintObj       SITE.CPP

//

// Comments:

//

//********************************************************************

void CSimpleDoc::PaintDoc (HDC hDC)

{

        CStabilize stabilize(this);

        // if we supported multiple objects, then we would enumerate

        // the objects and call paint on each of them from here.

        if (m_lpSite)

                m_lpSite->PaintObj(hDC);

}


 CSimpleDoc::DisableInsertObject  (SIMPCNTR Sample)

//**********************************************************************

//

// CSimpleDoc::DisableInsertObject

//

// Purpose:

//

//      Disable the ability to insert a new object in this document.

//

// Parameters:

//

//      None

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                    Location

//

//      EnableMenuItem              Windows API

//

// Comments:

//

//      This implementation only allows one object to be inserted

//      into a document.  Once the object has been inserted, then

//      the Insert Object menu choice is greyed out, to prevent

//      the user from inserting another.

//

//********************************************************************

void CSimpleDoc::DisableInsertObject(void)

{

        // Disable InsertObject menu choice

        EnableMenuItem( m_lpApp->m_hEditMenu, 0, MF_BYPOSITION | MF_DISABLED | MF_GRAYED);

}


 IAS.CPP  (SIMPCNTR Sample)

//**********************************************************************

// File name: IAS.CPP

//

//      Implementation file of CAdviseSink

//

//

// Functions:

//

//      See IAS.H for Class Definition

//

// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#include "pre.h"

#include "iocs.h"

#include "ias.h"

#include "ioipf.h"

#include "ioips.h"

#include "app.h"

#include "site.h"

#include "doc.h"


 CAdviseSink::QueryInterface  (SIMPCNTR Sample)

//**********************************************************************

//

// CAdviseSink::QueryInterface

//

// Purpose:

//

//      Returns a pointer to a requested interface.

//

// Parameters:

//

//      REFIID riid         - The requested interface

//

//      LPVOID FAR* ppvObj  - Place to return the interface

//

// Return Value:

//

//      HRESULT from CSimpleSite::QueryInterface

//

// Function Calls:

//      Function                    Location

//

//      CSimpleSite::QueryInterface SITE.CPP

//      OutputDebugString           Windows API

//

// Comments:

//

//      This function simply delegates to the Object class, which is

//      aware of the supported interfaces.

//

//********************************************************************

STDMETHODIMP CAdviseSink::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)

{

        OutputDebugString("In IAS::QueryInterface\r\n");

        // delegate to the document Object

        return m_pSite->QueryInterface(riid, ppvObj);

}


 CAdviseSink::AddRef  (SIMPCNTR Sample)

//**********************************************************************

//

// CAdviseSink::AddRef

//

// Purpose:

//

//      Increments the reference count on this interface

//

// Parameters:

//

//      None

//

// Return Value:

//

//      The current reference count on this interface.

//

// Function Calls:

//      Function                    Location

//

//      CSimpleSite::AddReff        SITE.CPP

//      OutputDebugString           Windows API

//

// Comments:

//

//      This function adds one to the ref count of the interface,

//      and calls then calls CSimpleSite to increment its ref.

//      count.

//

//********************************************************************

STDMETHODIMP_(ULONG) CAdviseSink::AddRef()

{

        OutputDebugString("In IAS::AddRef\r\n");

        // increment the interface reference count (for debugging only)

        ++m_nCount;

        // delegate to the container Site

        return m_pSite->AddRef();

}


 CAdviseSink::Release  (SIMPCNTR Sample)

//**********************************************************************

//

// CAdviseSink::Release

//

// Purpose:

//

//      Decrements the reference count on this interface

//

// Parameters:

//

//      None

//

// Return Value:

//

//      The current reference count on this interface.

//

// Function Calls:

//      Function                    Location

//

//      CSimpleSite::Release        SITE.CPP

//      OutputDebugString           Windows API

//

// Comments:

//

//      This function subtracts one from the ref count of the interface,

//      and calls then calls CSimpleSite to decrement its ref.

//      count.

//

//********************************************************************

STDMETHODIMP_(ULONG) CAdviseSink::Release()

{

        OutputDebugString("In IAS::Release\r\n");

        // decrement the interface reference count (for debugging only)

        m_nCount--;

        // delegate to the container Site

        return m_pSite->Release();

}


 CAdviseSink::OnDataChange  (SIMPCNTR Sample)

//**********************************************************************

//

// CAdviseSink::OnDataChange

//

// Purpose:

//

//      Not Implemented (needs to be stubbed out)

//

// Parameters:

//

//      Not Implemented (needs to be stubbed out)

//

// Return Value:

//

//      Not Implemented (needs to be stubbed out)

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//      Not Implemented (needs to be stubbed out)

//

//********************************************************************

STDMETHODIMP_(void) CAdviseSink::OnDataChange (FORMATETC FAR* pFormatetc, STGMEDIUM FAR* pStgmed)

{

        OutputDebugString("In IAS::OnDataChange\r\n");

}


 CAdviseSink::OnViewChange  (SIMPCNTR Sample)

//**********************************************************************

//

// CAdviseSink::OnViewChange

//

// Purpose:

//

//      Notifies us that the view has changed and needs to be updated.

//

// Parameters:

//

//      DWORD dwAspect  - Aspect that has changed

//

//      LONG lindex     - Index that has changed

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      InvalidateRect              Windows API

//      IViewObject2::GetExtent     Object

//

// Comments:

//

//********************************************************************

STDMETHODIMP_(void) CAdviseSink::OnViewChange (DWORD dwAspect, LONG lindex)

{

        CStabilize stabilize(m_pSite);

        LPVIEWOBJECT2 lpViewObject2;

        OutputDebugString("In IAS::OnViewChange\r\n");

        // get a pointer to IViewObject2

        HRESULT hErr = m_pSite->m_lpOleObject->QueryInterface(

                        IID_IViewObject2,(LPVOID FAR *)&lpViewObject2);

        if (hErr == NOERROR) {

                // get extent of the object

                // NOTE: this method will never be remoted; it can be called w/i this async method

                lpViewObject2->GetExtent(DVASPECT_CONTENT, -1 , NULL, &m_pSite->m_sizel);

                lpViewObject2->Release();

        }

        InvalidateRect(m_pSite->m_lpDoc->m_hDocWnd, NULL, TRUE);

}


 CAdviseSink::OnRename  (SIMPCNTR Sample)

//**********************************************************************

//

// CAdviseSink::OnRename

//

// Purpose:

//

//      Not Implemented (needs to be stubbed out)

//

// Parameters:

//

//      Not Implemented (needs to be stubbed out)

//

// Return Value:

//

//      Not Implemented (needs to be stubbed out)

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//      Not Implemented (needs to be stubbed out)

//

//********************************************************************

STDMETHODIMP_(void) CAdviseSink::OnRename (LPMONIKER pmk)

{

        OutputDebugString("In IAS::OnRename\r\n");

}


 CAdviseSink::OnSave  (SIMPCNTR Sample)

//**********************************************************************

//

// CAdviseSink::OnSave

//

// Purpose:

//

//      Not Implemented (needs to be stubbed out)

//

// Parameters:

//

//      Not Implemented (needs to be stubbed out)

//

// Return Value:

//

//      Not Implemented (needs to be stubbed out)

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//      Not Implemented (needs to be stubbed out)

//

//********************************************************************

STDMETHODIMP_(void) CAdviseSink::OnSave ()

{

        OutputDebugString("In IAS::OnSave\r\n");

}


 CAdviseSink::OnClose  (SIMPCNTR Sample)

//**********************************************************************

//

// CAdviseSink::OnClose

//

// Purpose:

//

//      Not Implemented (needs to be stubbed out)

//

// Parameters:

//

//      Not Implemented (needs to be stubbed out)

//

// Return Value:

//

//      Not Implemented (needs to be stubbed out)

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//      Not Implemented (needs to be stubbed out)

//

//********************************************************************

STDMETHODIMP_(void) CAdviseSink::OnClose()

{

        OutputDebugString("In IAS::OnClose\r\n");

}


 IOCS.CPP  (SIMPCNTR Sample)

//**********************************************************************

// File name: IOCS.CPP

//

//      Implementation file for COleClientSite

//

// Functions:

//

//      See IOCS.H for class definition

//

// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#include "pre.h"

#include "iocs.h"

#include "ias.h"

#include "ioipf.h"

#include "ioips.h"

#include "app.h"

#include "site.h"

#include "doc.h"


 COleClientSite::QueryInterface  (SIMPCNTR Sample)

//**********************************************************************

//

// COleClientSite::QueryInterface

//

// Purpose:

//

//      Used for interface negotiation at this interface

//

// Parameters:

//

//      REFIID riid         -   A reference to the interface that is

//                              being queried.

//

//      LPVOID FAR* ppvObj  -   An out parameter to return a pointer to

//                              the interface.

//

// Return Value:

//

//      S_OK                -   The interface is supported.

//      E_NOINTERFACE       -   The interface is not supported

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      CSimpleSite::QueryInterface SITE.CPP

//

// Comments:

//

//********************************************************************

STDMETHODIMP COleClientSite::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)

{

        OutputDebugString("In IOCS::QueryInterface\r\n");

        // delegate to the container Site

        return m_pSite->QueryInterface(riid, ppvObj);

}


 CSimpleApp::AddRef  (SIMPCNTR Sample)

//**********************************************************************

//

// CSimpleApp::AddRef

//

// Purpose:

//

//      Adds to the reference count at the interface level.

//

// Parameters:

//

//      None

//

// Return Value:

//

//      ULONG   -   The new reference count of the interface

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//********************************************************************

STDMETHODIMP_(ULONG) COleClientSite::AddRef()

{

        OutputDebugString("In IOCS::AddRef\r\n");

        // increment the interface reference count (for debugging only)

        ++m_nCount;

        // delegate to the container Site

        return m_pSite->AddRef();

}


 CSimpleApp::Release  (SIMPCNTR Sample)

//**********************************************************************

//

// CSimpleApp::Release

//

// Purpose:

//

//      Decrements the reference count at this level

//

// Parameters:

//

//      None

//

// Return Value:

//

//      ULONG   -   The new reference count of the interface.

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//********************************************************************

STDMETHODIMP_(ULONG) COleClientSite::Release()

{

        OutputDebugString("In IOCS::Release\r\n");

        // decrement the interface reference count (for debugging only)

        --m_nCount;

        // delegate to the container Site

        return m_pSite->Release();

}


 COleClientSite::SaveObject  (SIMPCNTR Sample)

//**********************************************************************

//

// COleClientSite::SaveObject

//

// Purpose:

//

//      Called by the object when it wants to be saved to persistant

//      storage

//

// Parameters:

//

//      None

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                            Location

//

//      OutputDebugString                   Windows API

//      IOleObject::QueryInterface          Object

//      IPersistStorage::SaveCompleted      Object

//      IPersistStorage::Release            Object

//      OleSave                             OLE API

//      ResultFromScode                     OLE API

//

// Comments:

//

//********************************************************************

STDMETHODIMP COleClientSite::SaveObject()

{

        CStabilize stabilize(m_pSite);

        LPPERSISTSTORAGE lpPS;

        SCODE sc = E_FAIL;

        OutputDebugString("In IOCS::SaveObject\r\n");

        // get a pointer to IPersistStorage

        HRESULT hErr = m_pSite->m_lpOleObject->QueryInterface(IID_IPersistStorage, (LPVOID FAR *)&lpPS);

        // save the object

        if (hErr == NOERROR)

                {

                sc = GetScode( OleSave(lpPS, m_pSite->m_lpObjStorage, TRUE) );

                lpPS->SaveCompleted(NULL);

                lpPS->Release();

                }

        return ResultFromScode(sc);

}


 COleClientSite::GetMoniker  (SIMPCNTR Sample)

//**********************************************************************

//

// COleClientSite::GetMoniker

//

// Purpose:

//

//      Not Implemented

//

// Parameters:

//

//      Not Implemented

//

// Return Value:

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//      This function is not implemented because we don't support

//      linking.

//

//********************************************************************

STDMETHODIMP COleClientSite::GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker, LPMONIKER FAR* ppmk)

{

        OutputDebugString("In IOCS::GetMoniker\r\n");

        // need to null the out pointer

        *ppmk = NULL;

        return ResultFromScode(E_NOTIMPL);

}


 COleClientSite::GetContainer  (SIMPCNTR Sample)

//**********************************************************************

//

// COleClientSite::GetContainer

//

// Purpose:

//

//      Not Implemented

//

// Parameters:

//

//      Not Implemented

//

// Return Value:

//

//      Not Implemented

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//      Not Implemented

//

//********************************************************************

STDMETHODIMP COleClientSite::GetContainer(LPOLECONTAINER FAR* ppContainer)

{

        OutputDebugString("In IOCS::GetContainer\r\n");

        // NULL the out pointer

        *ppContainer = NULL;

        return ResultFromScode(E_NOTIMPL);

}


 COleClientSite::ShowObject  (SIMPCNTR Sample)

//**********************************************************************

//

// COleClientSite::ShowObject

//

// Purpose:

//

//      Not Implemented

//

// Parameters:

//

//      Not Implemented

//

// Return Value:

//

//      Not Implemented

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//      This function is not implemented because we don't support

//      linking.

//

//********************************************************************

STDMETHODIMP COleClientSite::ShowObject()

{

        OutputDebugString("In IOCS::ShowObject\r\n");

        return NOERROR;

}


 COleClientSite::OnShowWindow  (SIMPCNTR Sample)

//**********************************************************************

//

// COleClientSite::OnShowWindow

//

// Purpose:

//

//      Object calls this method when it is opening/closing non-InPlace

//      Window

//

// Parameters:

//

//      BOOL fShow  - TRUE if Window is opening, FALSE if closing

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      InvalidateRect              Windows API

//      ResultFromScode             OLE API

//

// Comments:

//

//********************************************************************

STDMETHODIMP COleClientSite::OnShowWindow(BOOL fShow)

{

        CStabilize stabilize(m_pSite);

        OutputDebugString("In IOCS::OnShowWindow\r\n");

        m_pSite->m_fObjectOpen = fShow;

        InvalidateRect(m_pSite->m_lpDoc->m_hDocWnd, NULL, TRUE);

        // if object window is closing, then bring container window to top

        if (! fShow) {

                BringWindowToTop(m_pSite->m_lpDoc->m_hDocWnd);

                SetFocus(m_pSite->m_lpDoc->m_hDocWnd);

        }

        return ResultFromScode(S_OK);

}


 COleClientSite::RequestNewObjectLayout  (SIMPCNTR Sample)

//**********************************************************************

//

// COleClientSite::RequestNewObjectLayout

//

// Purpose:

//

//      Not Implemented

//

// Parameters:

//

//      Not Implemented

//

// Return Value:

//

//      Not Implemented

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//      Not Implemented

//

//********************************************************************

STDMETHODIMP COleClientSite::RequestNewObjectLayout()

{

        OutputDebugString("In IOCS::RequestNewObjectLayout\r\n");

        return ResultFromScode(E_NOTIMPL);

}


 IOIPF.CPP  (SIMPCNTR Sample)

//**********************************************************************

// File name: IOIPF.CPP

//

//      Implementation file for COleInPlaceFrame

//

// Functions:

//

//      See IOIPF.H for class definition

//

// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#include "pre.h"

#include "iocs.h"

#include "ias.h"

#include "ioipf.h"

#include "ioips.h"

#include "app.h"

#include "site.h"

#include "doc.h"


 CSimpleApp::QueryInterface  (SIMPCNTR Sample)

//**********************************************************************

//

// CSimpleApp::QueryInterface

//

// Purpose:

//

//      Used for interface negotiation at the Interface level.

//

// Parameters:

//

//      REFIID riid         -   A reference to the interface that is

//                              being queried.

//

//      LPVOID FAR* ppvObj  -   An out parameter to return a pointer to

//                              the interface.

//

// Return Value:

//

//      S_OK    -   The interface is supported.

//      S_FALSE -   The interface is not supported

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      CSimpleApp::QueryInterface  APP.CPP

//

// Comments:

//

//********************************************************************

STDMETHODIMP COleInPlaceFrame::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)

{

        OutputDebugString("In IOIPF::QueryInterface\r\n");

// delegate to the document Object

        return m_pApp->QueryInterface(riid, ppvObj);

}


 CSimpleApp::AddRef  (SIMPCNTR Sample)

//**********************************************************************

//

// CSimpleApp::AddRef

//

// Purpose:

//

//      Adds to the reference count at the interface level.

//

// Parameters:

//

//      None

//

// Return Value:

//

//      ULONG   -   The new reference count of the interface.

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//********************************************************************

STDMETHODIMP_(ULONG) COleInPlaceFrame::AddRef()

{

        OutputDebugString("In IOIPF::AddRef\r\n");

// delegate to the document Object

        m_pApp->AddRef();

// increment the interface reference count

        return ++m_nCount;

}


 CSimpleApp::Release  (SIMPCNTR Sample)

//**********************************************************************

//

// CSimpleApp::Release

//

// Purpose:

//

//      Decrements the reference count at this level

//

// Parameters:

//

//      None

//

// Return Value:

//

//      ULONG   -   The new reference count of the interface.

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      CSimpleApp::Release         APP.CPP

//

// Comments:

//

//********************************************************************

STDMETHODIMP_(ULONG) COleInPlaceFrame::Release()

{

        OutputDebugString("In IOIPF::Release\r\n");

// delegate to the document object

        m_pApp->Release();

// decrement the interface reference count

        return --m_nCount;

}


 COleInPlaceFrame::GetWindow  (SIMPCNTR Sample)

//**********************************************************************

//

// COleInPlaceFrame::GetWindow

//

// Purpose:

//

//      Returns the frame window handle

//

// Parameters:

//

//      HWND FAR* lphwnd    - Location to return the window handle

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      ResultFromScode             OLE API

//

// Comments:

//

//********************************************************************

STDMETHODIMP COleInPlaceFrame::GetWindow (HWND FAR* lphwnd)

{

        OutputDebugString("In IOIPF::GetWindow\r\n");

        CStabilize stabilize(m_pApp);

        *lphwnd = m_pApp->m_hAppWnd;

        return ResultFromScode(S_OK);

}


 COleInPlaceFrame::ContextSensitiveHelp  (SIMPCNTR Sample)

//**********************************************************************

//

// COleInPlaceFrame::ContextSensitiveHelp

//

// Purpose:

//

//      Used in implementing Context sensitive help

//

// Parameters:

//

//      BOOL fEnterMode -   TRUE if starting Context Sensitive help mode

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      ResultFromScode             OLE API

//

// Comments:

//

//      Be sure to read the technotes in the OLE toolkit.

//

//********************************************************************

STDMETHODIMP COleInPlaceFrame::ContextSensitiveHelp (BOOL fEnterMode)

{

        OutputDebugString("In IOIPF::ContextSensitiveHelp\r\n");

        CStabilize stabilize(m_pApp);

        m_pApp->m_fMenuMode = fEnterMode;

        return ResultFromScode(S_OK);


 COleInPlaceFrame::GetBorder  (SIMPCNTR Sample)}

//**********************************************************************

//

// COleInPlaceFrame::GetBorder

//

// Purpose:

//

//      Returns the outermost border that frame adornments can be attached

//      during InPlace Activation.

//

// Parameters:

//

//      LPRECT lprectBorder - return parameter to contain the outermost

//                            rect for frame adornments

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      GetClientRect               Windows API

//      CopyRect                    Windows API

//      ResultFromScode             OLE API

//

// Comments:

//

//********************************************************************

STDMETHODIMP COleInPlaceFrame::GetBorder (LPRECT lprectBorder)

{

        RECT rect;

        OutputDebugString("In IOIPF::GetBorder\r\n");

        // get the rect for the entire frame.

        GetClientRect(m_pApp->m_hAppWnd, &rect);

        CopyRect(lprectBorder, &rect);

        return ResultFromScode(S_OK);

}


 COleInPlaceFrame::RequestBorderSpace  (SIMPCNTR Sample)

//**********************************************************************

//

// COleInPlaceFrame::RequestBorderSpace

//

// Purpose:

//

//      Approves/Denies requests for border space during InPlace

//      negotiation.

//

// Parameters:

//

//      LPCBORDERWIDTHS lpborderwidths  - The width in pixels needed on

//                                        each side of the frame.

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      ResultFromScode             OLE API

//

// Comments:

//

//      This implementation doesn't care about how much border space

//      is used.  It always returns S_OK.

//

//********************************************************************

STDMETHODIMP COleInPlaceFrame::RequestBorderSpace (LPCBORDERWIDTHS lpborderwidths)

{

        OutputDebugString("In IOIPF::RequestBorderSpace\r\n");

        // always approve the request

        return ResultFromScode(S_OK);

}


 COleInPlaceFrame::SetBorderSpace  (SIMPCNTR Sample)

//**********************************************************************

//

// COleInPlaceFrame::SetBorderSpace

//

// Purpose:

//

//      The object calls this method when it is actually going to

//      start using the border space.

//

// Parameters:

//

//      LPCBORDERWIDTHS lpborderwidths  - Border space actually being used

//                                        by the object

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                        Location

//

//      CSimpleApp::AddFrameLevelTools  APP.CPP

//      OutputDebugString               Windows API

//      GetClientRect                   Windows API

//      MoveWindow                      Windows API

//      ResultFromScode                 Windows API

//

// Comments:

//

//      This routine could be a little smarter and check to see if

//      the object is requesting the entire client area of the

//      window.

//

//********************************************************************

STDMETHODIMP COleInPlaceFrame::SetBorderSpace (LPCBORDERWIDTHS lpborderwidths)

{

        OutputDebugString("In IOIPF::SetBorderSpace\r\n");

        CStabilize stabilize(m_pApp);

        if (lpborderwidths == NULL)

                m_pApp->AddFrameLevelTools();

        else

                {

                RECT rect;

                GetClientRect(m_pApp->m_hAppWnd, &rect);

                MoveWindow( m_pApp->m_lpDoc->m_hDocWnd,

                                        rect.left + lpborderwidths->left,

                                        rect.top + lpborderwidths->top,

                                        rect.right - lpborderwidths->right - lpborderwidths->left,

                                        rect.bottom - lpborderwidths->bottom - lpborderwidths->top,

                                        TRUE);

                }

        return ResultFromScode(S_OK);

}


 COleInPlaceFrame::SetActiveObject  (SIMPCNTR Sample)

//**********************************************************************

//

// COleInPlaceFrame::SetActiveObject

//

// Purpose:

//

//

// Parameters:

//

//      LPOLEINPLACEACTIVEOBJECT lpActiveObject     -   Pointer to the

//                                                      objects

//                                                      IOleInPlaceActiveObject

//                                                      interface

//

//@@WTK WIN32, UNICODE

//      //LPCSTR lpszObjName                          -   Name of the object

//      LPCOLESTR lpszObjName                          -   Name of the object

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                            Location

//

//      OutputDebugString                   Windows API

//      IOleInPlaceActiveObject::AddRef     Object

//      IOleInPlaceActiveObject::Release    Object

//      ResultFromScode                     OLE API

//

// Comments:

//

//********************************************************************

//@@WTK WIN32, UNICODE

//STDMETHODIMP COleInPlaceFrame::SetActiveObject (LPOLEINPLACEACTIVEOBJECT lpActiveObject,LPCSTR lpszObjName)

STDMETHODIMP COleInPlaceFrame::SetActiveObject (

LPOLEINPLACEACTIVEOBJECT lpActiveObject,

LPCOLESTR lpszObjName)

{

        OutputDebugString("In IOIPF::SetActiveObject\r\n");

        CStabilize stabilize(m_pApp);

        // AddRef() it and save it...

        if (lpActiveObject)

                {

                lpActiveObject->AddRef();

                lpActiveObject->GetWindow(&m_pApp->m_hwndUIActiveObj);

                if (m_pApp->m_hwndUIActiveObj)

                        SendMessage(m_pApp->m_hwndUIActiveObj, WM_QUERYNEWPALETTE, 0, 0L);

                }

        else

                {

                if (m_pApp->m_lpDoc->m_lpActiveObject)

                        m_pApp->m_lpDoc->m_lpActiveObject->Release();

                m_pApp->m_hwndUIActiveObj = NULL;

                }

        // in an MDI app, this method really shouldn't be called,

        // this method associated with the doc is called instead.

        m_pApp->m_lpDoc->m_lpActiveObject = lpActiveObject;

        // should set window title here

        return ResultFromScode(S_OK);

}


 COleInPlaceFrame::InsertMenus  (SIMPCNTR Sample)

//**********************************************************************

//

// COleInPlaceFrame::InsertMenus

//

// Purpose:

//

//      Inserts the container menu into the combined menu

//

// Parameters:

//

//      HMENU hmenuShared                   -   Menu Handle to be set.

//      LPOLEMENUGROUPWIDTHS lpMenuWidths   -   Width of menus

//

// Return Value:

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      AppendMenu                  Windows API

//      ResultFromScode             OLE API

//

// Comments:

//

//********************************************************************

STDMETHODIMP COleInPlaceFrame::InsertMenus (HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths)

{

        OutputDebugString("In IOIPF::InsertMenus\r\n");

        CStabilize stabilize(m_pApp);

  //@@WTK WIN32, UNICODE

        //AppendMenu(hmenuShared, MF_BYPOSITION | MF_POPUP, m_pApp->m_hFileMenu, "&File");

        //AppendMenu(hmenuShared, MF_BYPOSITION | MF_POPUP, m_pApp->m_hHelpMenu, "&Other");

        AppendMenu(hmenuShared, MF_BYPOSITION | MF_POPUP, (UINT)m_pApp->m_hFileMenu, "&File");

        AppendMenu(hmenuShared, MF_BYPOSITION | MF_POPUP, (UINT)m_pApp->m_hHelpMenu, "&Other");

        lpMenuWidths->width[0] = 1;

        lpMenuWidths->width[2] = 0;

        lpMenuWidths->width[4] = 1;

        return ResultFromScode(S_OK);

}


 COleInPlaceFrame::SetMenu  (SIMPCNTR Sample)

//**********************************************************************

//

// COleInPlaceFrame::SetMenu

//

// Purpose:

//

//      Sets the application menu to the combined menu

//

// Parameters:

//

//      HMENU hmenuShared       - The combined menu

//

//      HOLEMENU holemenu       - Used by OLE

//

//      HWND hwndActiveObject   - Used by OLE

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      SetMenu                     Windows API

//      OleSetMenuDescriptor        OLE API

//      ResultFromScode             OLE API

//

// Comments:

//

//********************************************************************

STDMETHODIMP COleInPlaceFrame::SetMenu (HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject)

{

        OutputDebugString("In IOIPF::SetMenu\r\n");

        CStabilize stabilize(m_pApp);

        HMENU hMenu = m_pApp->m_hMainMenu;

        if (holemenu)

                hMenu = hmenuShared;

        // call the windows api, not this method

        ::SetMenu (m_pApp->m_hAppWnd, hMenu);

        OleSetMenuDescriptor(holemenu, m_pApp->m_hAppWnd, hwndActiveObject, this, m_pApp->m_lpDoc->m_lpActiveObject);

        return ResultFromScode(S_OK);

}


 COleInPlaceFrame::RemoveMenus  (SIMPCNTR Sample)

//**********************************************************************

//

// COleInPlaceFrame::RemoveMenus

//

// Purpose:

//

//      Removes the container menus from the combined menu

//

// Parameters:

//

//      HMENU hmenuShared   - Handle to the combined menu.

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      GetMenuItemCount            Windows API

//      RemoveMenu                  Windows API

//      ResultFromScode             OLE API

//

// Comments:

//

//********************************************************************

STDMETHODIMP COleInPlaceFrame::RemoveMenus (HMENU hmenuShared)

{

        int retval;

        OutputDebugString("In IOIPF::RemoveMenus\r\n");

        while ((retval = GetMenuItemCount(hmenuShared)) && (retval != -1))

                RemoveMenu(hmenuShared, 0, MF_BYPOSITION);

        return ResultFromScode(S_OK);

}


 COleInPlaceFrame::SetStatusText  (SIMPCNTR Sample)

//**********************************************************************

//

// COleInPlaceFrame::SetStatusText

//

// Purpose:

//

//      Not Implemented

//

// Parameters:

//

//      Not Implemented

//

// Return Value:

//

//      Not Implemented

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//      This function is not implemented due to the fact

//      that this application does not have a status bar.

//

//********************************************************************

//@@WTK WIN32, UNICODE

//STDMETHODIMP COleInPlaceFrame::SetStatusText (LPCSTR lpszStatusText)

STDMETHODIMP COleInPlaceFrame::SetStatusText (LPCOLESTR lpszStatusText)

{

        OutputDebugString("In IOIPF::SetStatusText\r\n");

        return ResultFromScode(E_FAIL);

}


 COleInPlaceFrame::EnableModeless  (SIMPCNTR Sample)

//**********************************************************************

//

// COleInPlaceFrame::EnableModeless

//

// Purpose:

//

//      Enables/Disables container modeless dialogs

//

// Parameters:

//

//      BOOL fEnable    - Enable/Disable

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//      There are no modeless dialogs in this application, so the

//      implementation of this method is trivial.

//

//********************************************************************

STDMETHODIMP COleInPlaceFrame::EnableModeless (BOOL fEnable)

{

        OutputDebugString("In IOIPF::EnableModeless\r\n");

        return ResultFromScode(S_OK);

}


 COleInPlaceFrame::TranslateAccelerator  (SIMPCNTR Sample)

//**********************************************************************

//

// COleInPlaceFrame::TranslateAccelerator

//

// Purpose:

//

//      Not Implemented

//

// Parameters:

//

//      Not Implemented

//

// Return Value:

//

//      Not Implemented

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//      Not Implemented

//

//********************************************************************

STDMETHODIMP COleInPlaceFrame::TranslateAccelerator (LPMSG lpmsg, WORD wID)

{

        OutputDebugString("In IOIPF::TranslateAccelerator\r\n");

        return ResultFromScode(S_FALSE);

}


 IOIPS.CPP  (SIMPCNTR Sample)

//**********************************************************************

// File name: IOIPS.CPP

//

//      Implementation file for COleInPlaceSite

//

// Functions:

//

//      See IOIPS.H for class Definition

//

// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#include "pre.h"

#include "iocs.h"

#include "ias.h"

#include "ioipf.h"

#include "ioips.h"

#include "app.h"

#include "site.h"

#include "doc.h"


 CSimpleSite::COleInPlaceSite::QueryInterface  (SIMPCNTR Sample)

//**********************************************************************

//

// CSimpleSite::COleInPlaceSite::QueryInterface

//

// Purpose:

//

//      Used for interface negotiation at the interface level.

//

// Parameters:

//

//      REFIID riid         -   A reference to the interface that is

//                              being queried.

//

//      LPVOID FAR* ppvObj  -   An out parameter to return a pointer to

//                              the interface.

//

// Return Value:

//

//      S_OK    -   The interface is supported.

//      S_FALSE -   The interface is not supported

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      CSimpleSite::QueryInterface SITE.CPP

//

// Comments:

//

//********************************************************************

STDMETHODIMP COleInPlaceSite::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)

{

        OutputDebugString("In IOIPS::QueryInterface\r\n");

        CStabilize stabilize(m_pSite);

        // delegate to the container Site

        return m_pSite->QueryInterface(riid, ppvObj);

}


 CSimpleSite::COleInPlaceSite::AddRef  (SIMPCNTR Sample)

//**********************************************************************

//

// CSimpleSite::COleInPlaceSite::AddRef

//

// Purpose:

//

//      Adds to the reference count at the interface level.

//

// Parameters:

//

//      None

//

// Return Value:

//

//      ULONG   -   The new reference count of the interface.

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//********************************************************************

STDMETHODIMP_(ULONG) COleInPlaceSite::AddRef()

{

        OutputDebugString("In IOIPS::AddRef\r\n");

        // increment the interface reference count (for debugging only)

        ++m_nCount;

        // delegate to the container Site

        return m_pSite->AddRef();

}


 CSimpleSite::COleInPlaceSite::Release  (SIMPCNTR Sample)

//**********************************************************************

//

// CSimpleSite::COleInPlaceSite::Release

//

// Purpose:

//

//      Decrements the reference count at this level

//

// Parameters:

//

//      None

//

// Return Value:

//

//      ULONG   -   The new reference count of the interface.

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      CSimpleSite::Release        SITE.CPP

//

// Comments:

//

//********************************************************************

STDMETHODIMP_(ULONG) COleInPlaceSite::Release()

{

        OutputDebugString("In IOIPS::Release\r\n");

        // decrement the interface reference count (for debugging only)

        m_nCount--;

        // delegate to the container Site

        return m_pSite->Release();

}


 COleInPlaceSite::GetWindow  (SIMPCNTR Sample)

//**********************************************************************

//

// COleInPlaceSite::GetWindow

//

// Purpose:

//

//      Returns the Window Handle of the client site

//

// Parameters:

//

//      HWND FAR* lphwnd    - place to return the handle

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      ResultFromScode             OLE API

//

// Comments:

//

//********************************************************************

STDMETHODIMP COleInPlaceSite::GetWindow (HWND FAR* lphwnd)

{

        OutputDebugString("In IOIPS::GetWindow\r\n");

        CStabilize stabilize(m_pSite);

        // return the handle to our editing window.

        *lphwnd = m_pSite->m_lpDoc->m_hDocWnd;

        return ResultFromScode(S_OK);

}


 COleInPlaceSite::ContextSensitiveHelp  (SIMPCNTR Sample)

//**********************************************************************

//

// COleInPlaceSite::ContextSensitiveHelp

//

// Purpose:

//

//

// Parameters:

//

//      BOOL fEnterMode - TRUE for entering Context Sensitive help mode

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      ResultFromScode             OLE API

//

// Comments:

//

//      Be sure to read the technotes included with the OLE toolkit.

//

//********************************************************************

STDMETHODIMP COleInPlaceSite::ContextSensitiveHelp (BOOL fEnterMode)

{

        OutputDebugString("In IOIPS::ContextSensitiveHelp\r\n");

        if (m_pSite->m_lpDoc->m_lpApp->m_fCSHMode != fEnterMode)

                m_pSite->m_lpDoc->m_lpApp->m_fCSHMode = fEnterMode;

        return ResultFromScode(S_OK);

}


 COleInPlaceSite::CanInPlaceActivate  (SIMPCNTR Sample)

//**********************************************************************

//

// COleInPlaceSite::CanInPlaceActivate

//

// Purpose:

//

//      Object calls to find out if the container can InPlace activate

//

// Parameters:

//

//      None

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      ResultFromScode             OLE API

//

// Comments:

//

//********************************************************************

STDMETHODIMP COleInPlaceSite::CanInPlaceActivate ()

{

        OutputDebugString("In IOIPS::CanInPlaceActivate\r\n");

        // return S_OK to indicate we can in-place activate

        return ResultFromScode(S_OK);

}


 COleInPlaceSite::OnInPlaceActivate  (SIMPCNTR Sample)

//**********************************************************************

//

// COleInPlaceSite::OnInPlaceActivate

//

// Purpose:

//

//      Called by the object on InPlace Activation

//

// Parameters:

//

//      None

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      ResultFromScode             OLE API

//

// Comments:

//

//********************************************************************

STDMETHODIMP COleInPlaceSite::OnInPlaceActivate ()

{

        HRESULT hrErr;

        OutputDebugString("In IOIPS::OnInPlaceActivate\r\n");

        CStabilize stabilize(m_pSite);

        hrErr = m_pSite->m_lpOleObject->QueryInterface(

                        IID_IOleInPlaceObject, (LPVOID FAR *)&m_pSite->m_lpInPlaceObject);

        if (hrErr != NOERROR)

                return ResultFromScode(E_FAIL);

        // return S_OK to indicate we can in-place activate.

        return ResultFromScode(S_OK);

}


 COleInPlaceSite::OnUIActivate  (SIMPCNTR Sample)

//**********************************************************************

//

// COleInPlaceSite::OnUIActivate

//

// Purpose:

//

//      Object calls this method when it displays it's UI.

//

// Parameters:

//

//      None.

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      ResultFromScode             OLE API

//

// Comments:

//

//********************************************************************

STDMETHODIMP COleInPlaceSite::OnUIActivate ()

{

        OutputDebugString("In IOIPS::OnUIActivate\r\n");

        m_pSite->m_lpDoc->m_fAddMyUI=FALSE;

        m_pSite->m_lpDoc->m_fInPlaceActive = TRUE;

        m_pSite->m_fInPlaceActive = TRUE;

        m_pSite->m_lpInPlaceObject->GetWindow((HWND FAR*)&m_pSite->m_hwndIPObj);

        // return S_OK to continue in-place activation

        return ResultFromScode(S_OK);

}


 COleInPlaceSite::GetWindowContext  (SIMPCNTR Sample)

//**********************************************************************

//

// COleInPlaceSite::GetWindowContext

//

// Purpose:

//

//      Called by the object to get information for InPlace Negotiation.

//

// Parameters:

//

//      LPOLEINPLACEFRAME FAR* lplpFrame    - Location to return a pointer

//                                            to IOleInPlaceFrame.

//

//      LPOLEINPLACEUIWINDOW FAR* lplpDoc   - Location to return a pointer

//                                            to IOleInPlaceUIWindow.

//

//      LPRECT lprcPosRect                  - The rect that the object

//                                            occupies

//

//      LPRECT lprcClipRect                 - The clipping rect

//

//      LPOLEINPLACEFRAMEINFO lpFrameInfo   - Pointer to FRAMEINFO

//

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                    Location

//

//      COleInPlaceFrame::AddRef    IOIPF.CPP

//      CSimpleSite::GetObjRect     SITE.CPP

//      OutputDebugString           Windows API

//      SetMapMode                  Windows API

//      GetDC                       Windows API

//      ReleaseDC                   Windows API

//      CopyRect                    Windows API

//      GetClientRect               Windows API

//      ResultFromScode             OLE API

//

// Comments:

//

//********************************************************************

STDMETHODIMP COleInPlaceSite::GetWindowContext (LPOLEINPLACEFRAME FAR* lplpFrame,

                                                           LPOLEINPLACEUIWINDOW FAR* lplpDoc,

                                                           LPRECT lprcPosRect,

                                                           LPRECT lprcClipRect,

                                                           LPOLEINPLACEFRAMEINFO lpFrameInfo)

{

        RECT rect;

        CStabilize stabilize(m_pSite);

        OutputDebugString("In IOIPS::GetWindowContext\r\n");

        // the frame is associated with the application object.

        // need to AddRef() it...

        m_pSite->m_lpDoc->m_lpApp->m_OleInPlaceFrame.AddRef();

        *lplpFrame = &m_pSite->m_lpDoc->m_lpApp->m_OleInPlaceFrame;

        *lplpDoc = NULL;  // must be NULL, cause we're SDI.

        // get the size of the object in pixels

        m_pSite->GetObjRect(&rect);

        // Copy this to the passed buffer

        CopyRect(lprcPosRect, &rect);

        // fill the clipping region

        GetClientRect(m_pSite->m_lpDoc->m_hDocWnd, &rect);

        CopyRect(lprcClipRect, &rect);

        // fill the FRAMEINFO

        lpFrameInfo->fMDIApp = FALSE;

        lpFrameInfo->hwndFrame = m_pSite->m_lpDoc->m_lpApp->m_hAppWnd;

        lpFrameInfo->haccel = NULL;

        lpFrameInfo->cAccelEntries = 0;

        return ResultFromScode(S_OK);

}


 COleInPlaceSite::Scroll  (SIMPCNTR Sample)

//**********************************************************************

//

// COleInPlaceSite::Scroll

//

// Purpose:

//

//      Not Implemented

//

// Parameters:

//

//      Not Implemented

//

// Return Value:

//

//      Not Implemented

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//      Not Implemented

//

//********************************************************************

STDMETHODIMP COleInPlaceSite::Scroll (SIZE scrollExtent)

{

        OutputDebugString("In IOIPS::Scroll\r\n");

        return ResultFromScode(E_FAIL);

}


 COleInPlaceSite::OnUIDeactivate  (SIMPCNTR Sample)

//**********************************************************************

//

// COleInPlaceSite::OnUIDeactivate

//

// Purpose:

//

//      Called by the object when its UI goes away

//

// Parameters:

//

//       BOOL fUndoable

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      CSimpleAPP::AddFrameLevelUI APP.CPP

//      ResultFromScode             OLE API

//

// Comments:

//

//********************************************************************

STDMETHODIMP COleInPlaceSite::OnUIDeactivate (BOOL fUndoable)

{

        OutputDebugString("In IOIPS::OnUIDeactivate\r\n");

        CStabilize stabilize(m_pSite);

        // need to clear this flag first

        m_pSite->m_lpDoc->m_fInPlaceActive = FALSE;

        m_pSite->m_fInPlaceActive = FALSE;

        m_pSite->m_lpDoc->m_lpApp->QueryNewPalette();

        m_pSite->m_lpDoc->m_lpApp->AddFrameLevelUI();

        return ResultFromScode(S_OK);

}


 COleInPlaceSite::OnInPlaceDeactivate  (SIMPCNTR Sample)

//**********************************************************************

//

// COleInPlaceSite::OnInPlaceDeactivate

//

// Purpose:

//

//      Called when the inplace session is over

//

// Parameters:

//

//      None

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      ResultFromScode             OLE API

//

// Comments:

//

//********************************************************************

STDMETHODIMP COleInPlaceSite::OnInPlaceDeactivate ()

{

        OutputDebugString("In IOIPS::OnInPlaceDeactivate\r\n");

        if (m_pSite->m_lpInPlaceObject) {

                m_pSite->m_lpInPlaceObject->Release();

                m_pSite->m_lpInPlaceObject = NULL;

        }

        return ResultFromScode(S_OK);

}


 COleInPlaceSite::DiscardUndoState  (SIMPCNTR Sample)

//**********************************************************************

//

// COleInPlaceSite::DiscardUndoState

//

// Purpose:

//

//      Not Implemented

//

// Parameters:

//

//      Not Implemented

//

// Return Value:

//

//      Not Implemented

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//      Not Implemented

//

//********************************************************************

STDMETHODIMP COleInPlaceSite::DiscardUndoState ()

{

        OutputDebugString("In IOIPS::DiscardUndoState\r\n");

        return ResultFromScode(E_FAIL);

}


 COleInPlaceSite::DeactivateAndUndo  (SIMPCNTR Sample)

//**********************************************************************

//

// COleInPlaceSite::DeactivateAndUndo

//

// Purpose:

//

//      Not Implemented

//

// Parameters:

//

//      Not Implemented

//

// Return Value:

//

//      Not Implemented

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//      Not Implemented

//

//********************************************************************

STDMETHODIMP COleInPlaceSite::DeactivateAndUndo ()

{

        OutputDebugString("In IOIPS::DeactivateAndUndo\r\n");

        return ResultFromScode(E_FAIL);

}


 COleInPlaceSite::OnPosRectChange  (SIMPCNTR Sample)

//**********************************************************************

//

// COleInPlaceSite::OnPosRectChange

//

// Purpose:

//

//      The object calls this method when it's size changes during an

//      InPlace Session

//

// Parameters:

//

//      LPCRECT lprcPosRect -   The new object rect

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                            Location

//

//      OutputDebugString                   Windows API

//      GetClientRect                       Windows API

//      IOleObject::GetExtent               Object

//      IOleObject::QueryInterface          Object

//      IOleInPlaceObject::SetObjectRects   Object

//      IOleInPlaceObject::Release          Object

//      ResultFromScode                     OLE API

//

// Comments:

//

//********************************************************************

STDMETHODIMP COleInPlaceSite::OnPosRectChange (LPCRECT lprcPosRect)

{

        OutputDebugString("In IOIPS::OnPosRectChange\r\n");

        CStabilize stabilize(m_pSite);

        // update the size in the document object

        // NOTE: here we must call IOleObject::GetExtent to get actual extents

        //       of the running object. IViewObject2::GetExtent returns the

        //       last cached extents.

        m_pSite->m_lpOleObject->GetExtent(DVASPECT_CONTENT, &m_pSite->m_sizel);

        RECT rect;

        GetClientRect(m_pSite->m_lpDoc->m_hDocWnd, &rect);

        // tell the object its new size

        m_pSite->m_lpInPlaceObject->SetObjectRects(lprcPosRect, &rect);

        return ResultFromScode(S_OK);

}


 SIMPCNTR.CPP  (SIMPCNTR Sample)

//**********************************************************************

// File name: Simple.cpp

//

//      Main source file for the Simple OLE 2.0 object container

//

// Functions:

//

//      WinMain         - Program entry point

//      MainWndProc     - Processes messages for the frame window

//      About           - Processes messages for the about dialog

//      DocWndProc      - Processes messages for the doc window

//

// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#include "pre.h"

#include "iocs.h"

#include "ias.h"

#include "ioipf.h"

#include "ioips.h"

#include "app.h"

#include "site.h"

#include "doc.h"

// This line is needed for the debug utilities in OLE2UI

extern "C" {

        OLEDBGDATA_MAIN("SIMPCNTR")

}

CSimpleApp FAR * lpCSimpleApp;


 WinMain  (SIMPCNTR Sample)

//**********************************************************************

//

// WinMain

//

// Purpose:

//

//      Program entry point

//

// Parameters:

//

//      HANDLE hInstance        - Instance handle for this instance

//

//      HANDLE hPrevInstance    - Instance handle for the last instance

//

//      LPSTR lpCmdLine         - Pointer to the command line

//

//      int nCmdShow            - Window State

//

// Return Value:

//

//      msg.wParam

//

// Function Calls:

//      Function                        Location

//

//      CSimpleApp::CSimpleApp          APP.CPP

//      CSimpleApp::fInitApplication    APP.CPP

//      CSimpleApp::fInitInstance       APP.CPP

//      CSimpleApp::HandleAccelerators  APP.CPP

//      CSimpleApp::~CSimpleApp         APP.CPP

//      OleUIInitialize                 OLE2UI

//      OleUIUninitialize               OLE2UI

//      GetMessage                      Windows API

//      TranslateMessage                Windows API

//      DispatchMessage                 Windows API

//

// Comments:

//

//********************************************************************

int PASCAL WinMain(HANDLE hInstance,HANDLE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)

{

        MSG msg;

        // needed for LRPC to work properly...

        SetMessageQueue(96);

        lpCSimpleApp = new CSimpleApp;

        // we will add one ref count on our App. later when we want to destroy

        // the App object we will release this  ref count. when the App's ref

        // count goes to 0, it will be deleted.

        lpCSimpleApp->AddRef();

        // app initialization

        if (!hPrevInstance)

                if (!lpCSimpleApp->fInitApplication(hInstance))

                        return (FALSE);

        // instance initialization

        if (!lpCSimpleApp->fInitInstance(hInstance, nCmdShow))

                return (FALSE);

        /* Initialization required for OLE 2 UI library.  This call is

        **    needed ONLY if we are using the static link version of the UI

        **    library. If we are using the DLL version, we should NOT call

        **    this function in our application.

        */

#if 0

        if (!OleUIInitialize(hInstance, hPrevInstance))

                {

                OleDbgOut("Could not initialize OLEUI library\n");

                return FALSE;

                }

#endif

        // message loop

        while (GetMessage(&msg, NULL, NULL, NULL))

                if (!lpCSimpleApp->HandleAccelerators(&msg))

                        {

                        TranslateMessage(&msg);    /* Translates virtual key codes */

                        DispatchMessage(&msg);     /* Dispatches message to window */

                        }

        // De-initialization for UI libraries.  Just like OleUIInitialize, this

        // funciton is needed ONLY if we are using the static link version of the

        // OLE UI library.

#if 0

        OleUIUninitialize();

#endif

        // Release the ref count added on the App above. this will make

        // the App's ref count go to 0, and the App object will be deleted.

        lpCSimpleApp->Release();

        return (msg.wParam);          /* Returns the value from PostQuitMessage */

}


 MainWndProc  (SIMPCNTR Sample)

//**********************************************************************

//

// MainWndProc

//

// Purpose:

//

//      Processes messages for the frame window

//

// Parameters:

//

//      HWND hWnd       - Window handle for frame window

//

//      UINT message    - Message value

//

//      WPARAM wParam   - Message info

//

//      LPARAM lParam   - Message info

//

// Return Value:

//

//      long

//

// Function Calls:

//      Function                        Location

//

//      CSimpleApp::lCommandHandler     APP.CPP

//      CSimpleApp::DestroyDocs         APP.CPP

//      CSimpleApp::lCreateDoc          APP.CPP

//      CSimpleApp::lSizeHandler        APP.CPP

//      CSimpleDoc::lAddVerbs           DOC.CPP

//      PostQuitMessage                 Windows API

//      DefWindowProc                   Windows API

//

// Comments:

//

//********************************************************************

//@@WTK WIN32, UNICODE

//long FAR PASCAL _export MainWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)

long FAR PASCAL EXPORT MainWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)

{

        switch (message)

                {

                case WM_COMMAND:           // message: command from application menu

                        return lpCSimpleApp->lCommandHandler(hWnd, message, wParam, lParam);

                        break;

                case WM_CREATE:

                        return lpCSimpleApp->lCreateDoc(hWnd, message, wParam, lParam);

                        break;

                case WM_DESTROY:                  // message: window being destroyed

                        lpCSimpleApp->DestroyDocs();  // need to destroy the doc...

                        PostQuitMessage(0);

                        break;

                case WM_INITMENUPOPUP:

                        // is this the edit menu?

                        // Message packing is the same for WIN16 and 32

                        if ( LOWORD(lParam) == 1)

                                return lpCSimpleApp->m_lpDoc->lAddVerbs();

                        break;

                // this code is needed for 256 color objects to work properly.

                case WM_QUERYNEWPALETTE:

                        if (! lpCSimpleApp->m_fAppActive)

                                return 0L;

                        return lpCSimpleApp->QueryNewPalette();

                case WM_PALETTECHANGED:

                {

                        HWND hWndPalChg = (HWND) wParam;

                        if (hWnd != hWndPalChg)

                                wSelectPalette(hWnd, lpCSimpleApp->m_hStdPal, TRUE/*fBackground*/);

                        /* OLE2NOTE: always forward the WM_PALETTECHANGED message (via

                        **    SendMessage) to any in-place objects that currently have

                        **    their window visible. this gives these objects the chance

                        **    to select their palettes. this is

                        **    REQUIRED by all in-place containers independent of

                        **    whether they use color palettes themselves--their objects

                        **    may use color palettes.

                        **    (see ContainerDoc_ForwardPaletteChangedMsg for more info)

                        */

                        if (lpCSimpleApp->m_lpDoc && lpCSimpleApp->m_lpDoc->m_lpSite &&

                                lpCSimpleApp->m_lpDoc->m_lpSite->m_hwndIPObj)

                                SendMessage(lpCSimpleApp->m_lpDoc->m_lpSite->m_hwndIPObj,

                                                WM_PALETTECHANGED, wParam, lParam);

                        return 0L;

                }

                case WM_ACTIVATEAPP:

                        if ((lpCSimpleApp->m_fAppActive = (BOOL)wParam) == TRUE)

                                lpCSimpleApp->QueryNewPalette();

                        if (lpCSimpleApp->m_lpDoc->m_lpActiveObject) {

                                lpCSimpleApp->m_lpDoc->m_lpActiveObject->OnFrameWindowActivate(

                                                (BOOL)wParam);

                        }

                        break;

                case WM_SIZE:

                        return lpCSimpleApp->lSizeHandler(hWnd, message, wParam, lParam);

                default:                          // Passes it on if unproccessed

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

                }

                return (NULL);

}


 About  (SIMPCNTR Sample)

//**********************************************************************

//

// About

//

// Purpose:

//

//      Processes dialog box messages

//

// Parameters:

//

//      HWND hWnd       - Window handle for dialog box

//

//      UINT message    - Message value

//

//      WPARAM wParam   - Message info

//

//      LPARAM lParam   - Message info

//

// Return Value:

//

// Function Calls:

//      Function                    Location

//

//      EndDialog                   Windows API

//

// Comments:

//

//********************************************************************

//@@WTK WIN32, UNICODE

//BOOL FAR PASCAL _export About(HWND hDlg,unsigned message,WORD wParam,LONG lParam)

BOOL FAR PASCAL EXPORT About(HWND hDlg,UINT message,WPARAM wParam,LPARAM lParam)

{

        switch (message) {

        case WM_INITDIALOG:                /* message: initialize dialog box */

                return (TRUE);

        case WM_COMMAND:                      /* message: received a command */

                //@@WTK WIN32, UNICODE

                if (LOWORD(wParam) == IDOK                /* "OK" box selected?          */

                || LOWORD(wParam) == IDCANCEL) {      /* System menu close command? */

                        EndDialog(hDlg, TRUE);        /* Exits the dialog box        */

                        return (TRUE);

                }

                break;

        }

        return (FALSE);                           /* Didn't process a message    */

}


 DocWndProc  (SIMPCNTR Sample)

//**********************************************************************

//

// DocWndProc

//

// Purpose:

//

//      Processes dialog box messages

//

// Parameters:

//

//      HWND hWnd       - Window handle for doc window

//

//      UINT message    - Message value

//

//      WPARAM wParam   - Message info

//

//      LPARAM lParam   - Message info

//

// Return Value:

//

// Function Calls:

//      Function                            Location

//

//      CSimpleApp::PaintApp                APP.CPP

//      BeginPaint                          Windows API

//      EndPaint                            Windows API

//      DefWindowProc                       Windows API

//      IOleObject::QueryInterface          Object

//      IOleInPlaceObject::UIDeactivate     Object

//      IOleObject::DoVerb                  Object

//      IOleInPlaceObject::Release          Object

//

// Comments:

//

//********************************************************************

//@@WTK WIN32, UNICODE

//long FAR PASCAL _export DocWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)

long FAR PASCAL EXPORT DocWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)

{

        HDC hDC;

        PAINTSTRUCT ps;

        switch (message) {

                case WM_PAINT:

                        hDC = BeginPaint(hWnd, &ps);

                        if (lpCSimpleApp)

                                lpCSimpleApp->PaintApp (hDC);

                        EndPaint(hWnd, &ps);

                        break;

                case WM_LBUTTONDBLCLK:

                        {

                        POINT pt;

                        pt.x = (int)(short)LOWORD (lParam );

                        pt.y = (int)(short)HIWORD (lParam );

                        if (lpCSimpleApp->m_lpDoc->m_lpSite &&

                                lpCSimpleApp->m_lpDoc->m_lpSite->m_lpOleObject)

                                {

                                RECT rect;

                                lpCSimpleApp->m_lpDoc->m_lpSite->GetObjRect(&rect);

                                if ( PtInRect(&rect, pt) )

                                        {

                                        // Execute object's default verb

                                        lpCSimpleApp->m_lpDoc->m_lpSite->m_lpOleObject->DoVerb(

                                                        OLEIVERB_PRIMARY, (LPMSG)&message,

                                                        &lpCSimpleApp->m_lpDoc->m_lpSite->m_OleClientSite,

                                                        -1, hWnd, &rect);

                                        }

                                }

                        }

                        break;

        // no code is added to WM_LBUTTONDOWN for context sensitive help, because

        // this app does not do context sensitive help.

        case WM_LBUTTONDOWN:

                LPOLEINPLACEOBJECT lpObject;

                if (lpCSimpleApp->m_lpDoc->m_fInPlaceActive)

                        {

                        lpCSimpleApp->m_lpDoc->m_lpSite->m_lpOleObject->QueryInterface(IID_IOleInPlaceObject, (LPVOID FAR *)&lpObject);

                        lpObject->UIDeactivate();

                        // this code is needed because we don't support inside out.

                        RECT rect;

                        lpCSimpleApp->m_lpDoc->m_lpSite->GetObjRect(&rect);

                        lpCSimpleApp->m_lpDoc->m_lpSite->m_lpOleObject->DoVerb(OLEIVERB_HIDE, (LPMSG)&message, &lpCSimpleApp->m_lpDoc->m_lpSite->m_OleClientSite, -1, hWnd, &rect);

                        lpObject->Release();

                        }

                break;

                default:                          /* Passes it on if unproccessed */

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

        }

        return (NULL);

}


 SITE.CPP  (SIMPCNTR Sample)

//**********************************************************************

// File name: SITE.CPP

//

//      Implementation file for CSimpleSite

//

// Functions:

//

//      See SITE.H for class definition

//

// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#include "pre.h"

#include "iocs.h"

#include "ias.h"

#include "ioipf.h"

#include "ioips.h"

#include "app.h"

#include "site.h"

#include "doc.h"


 CSimpleSite::Create  (SIMPCNTR Sample)

//**********************************************************************

//

// CSimpleSite::Create

//

// Purpose:

//

//      Creation routine for CSimpleSite

//

// Parameters:

//

//      CSimpleDoc FAR *lpDoc   - Pointer to CSimpleDoc

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                    Location

//

//      IStorage::CreateStorage     OLE API

//      assert                      C Runtime

//

// Comments:

//

//********************************************************************

CSimpleSite FAR * CSimpleSite::Create(CSimpleDoc FAR *lpDoc)

{

        CSimpleSite FAR * lpTemp = new CSimpleSite(lpDoc);

        if (!lpTemp)

                return NULL;

        // create a sub-storage for the object

  //@@WTK WIN32, UNICODE

        //HRESULT hErr = lpDoc->m_lpStorage->CreateStorage( "Object",

        HRESULT hErr = lpDoc->m_lpStorage->CreateStorage( OLESTR("Object"),

                                STGM_READWRITE | STGM_TRANSACTED | STGM_SHARE_EXCLUSIVE,

                                0,

                                0,

                                &lpTemp->m_lpObjStorage);

        assert(hErr == NOERROR);

        if (hErr != NOERROR)

                {

                delete lpTemp;

                return NULL;

                }

        // we will add one ref count on our Site. later when we want to destroy

        // the Site object we will release this  ref count. when the Site's ref

        // count goes to 0, it will be deleted.

        lpTemp->AddRef();

        return lpTemp;

}


 CSimpleSite::CSimpleSite  (SIMPCNTR Sample)

//**********************************************************************

//

// CSimpleSite::CSimpleSite

//

// Purpose:

//

//      Constructor for CSimpleSite

//

// Parameters:

//

//      CSimpleDoc FAR *lpDoc   - Pointer to CSimpleDoc

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                    Location

//

// Comments:

//

//********************************************************************

#pragma warning(disable : 4355)  // turn off this warning.  This warning

                                                                // tells us that we are passing this in

                                                                // an initializer, before "this" is through

                                                                // initializing.  This is ok, because

                                                                // we just store the ptr in the other

                                                                // constructors

CSimpleSite::CSimpleSite (CSimpleDoc FAR *lpDoc) : m_OleClientSite(this),

                                                                                                 m_AdviseSink(this),

                                                                                                 m_OleInPlaceSite(this)

#pragma warning (default : 4355)  // Turn the warning back on

{

        // remember the pointer to the doc

        m_lpDoc = lpDoc;

        // clear the reference count

        m_dwDrawAspect = DVASPECT_CONTENT;

        m_lpOleObject = NULL;

        m_lpInPlaceObject = NULL;

        m_hwndIPObj = NULL;

        m_fInPlaceActive = FALSE;

        m_fObjectOpen = FALSE;

}


 CSimpleSite::~CSimpleSite  (SIMPCNTR Sample)

//**********************************************************************

//

// CSimpleSite::~CSimpleSite

//

// Purpose:

//

//      Destructor for CSimpleSite

//

// Parameters:

//

//      None

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                                Location

//

//      OutputDebugString                       Windows API

//      IOleObject::Release                     Object

//      IStorage::Release                       OLE API

//

// Comments:

//

//********************************************************************

CSimpleSite::~CSimpleSite ()

{

        OutputDebugString ("In CSimpleSite's Destructor \r\n");

        if (m_lpOleObject)

           m_lpOleObject->Release();

        if (m_lpObjStorage)

           m_lpObjStorage->Release();

}


 CSimpleSite::CloseOleObject  (SIMPCNTR Sample)

//**********************************************************************

//

// CSimpleSite::CloseOleObject

//

// Purpose:

//

//      Call IOleObject::Close on the object of the CSimpleSite

//

// Parameters:

//

//      None

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                                Location

//

//      OutputDebugString                       Windows API

//      IOleObject::QueryInterface              Object

//      IOleObject::Close                       Object

//      IOleInPlaceObject::UIDeactivate         Object

//      IOleInPlaceObject::InPlaceDeactivate    Object

//      IOleInPlaceObject::Release              Object

//

// Comments:

//

//********************************************************************

void CSimpleSite::CloseOleObject (void)

{

        CStabilize stabilize(this);

        LPOLEINPLACEOBJECT lpObject;

        LPVIEWOBJECT lpViewObject = NULL;

        OutputDebugString ("In CSimpleSite::CloseOleObject \r\n");

        if (m_lpOleObject)

           {

           if (m_fInPlaceActive)

                   {

                   m_lpOleObject->QueryInterface(IID_IOleInPlaceObject, (LPVOID FAR *)&lpObject);

                   lpObject->UIDeactivate();

                   // don't need to worry about inside-out because the object

                   // is going away.

                   lpObject->InPlaceDeactivate();

                   lpObject->Release();

                   }

           m_lpOleObject->Close(OLECLOSE_NOSAVE);

           }

}


 CSimpleSite::UnloadOleObject  (SIMPCNTR Sample)

//**********************************************************************

//

// CSimpleSite::UnloadOleObject

//

// Purpose:

//

//      Close and release all pointers to the object of the CSimpleSite

//

// Parameters:

//

//      None

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                                Location

//

//      OutputDebugString                       Windows API

//      CSimpleSite::CloseOleObject             SITE.CPP

//      IOleObject::QueryInterface              Object

//      IViewObject::SetAdvise                  Object

//      IViewObject::Release                    Object

//      IStorage::Release                       OLE API

//

// Comments:

//

//********************************************************************

void CSimpleSite::UnloadOleObject (void)

{

        CStabilize stabilize(this);

        OutputDebugString ("In CSimpleSite::UnloadOleObject \r\n");

        if (m_lpOleObject)

           {

           LPVIEWOBJECT lpViewObject;

           CloseOleObject();    // ensure object is closed; NOP if already closed

           m_lpOleObject->QueryInterface(IID_IViewObject, (LPVOID FAR *)&lpViewObject);

           if (lpViewObject)

                   {

                   // Remove the view advise

                   lpViewObject->SetAdvise(m_dwDrawAspect, 0, NULL);

                   lpViewObject->Release();

                   }

           m_lpOleObject->Release();

           m_lpOleObject = NULL;

           }

}


 CSimpleSite::QueryInterface  (SIMPCNTR Sample)

//**********************************************************************

//

// CSimpleSite::QueryInterface

//

// Purpose:

//

//      Used for interface negotiation of the container Site.

//

// Parameters:

//

//      REFIID riid         -   A reference to the interface that is

//                              being queried.

//

//      LPVOID FAR* ppvObj  -   An out parameter to return a pointer to

//                              the interface.

//

// Return Value:

//

//      S_OK    -   The interface is supported.

//      S_FALSE -   The interface is not supported

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      IsEqualIID                  OLE API

//      ResultFromScode             OLE API

//      CSimpleSite::AddRef          OBJ.CPP

//      COleClientSite::AddRef      IOCS.CPP

//      CAdviseSink::AddRef         IAS.CPP

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP CSimpleSite::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)

{

        CStabilize stabilize(this);

        OutputDebugString("In CSimpleSite::QueryInterface\r\n");

        *ppvObj = NULL;     // must set out pointer parameters to NULL

        if ( riid == IID_IUnknown)

                {

                AddRef();

                *ppvObj = this;

                return ResultFromScode(S_OK);

                }

        if ( riid == IID_IOleClientSite)

                {

                m_OleClientSite.AddRef();

                *ppvObj = &m_OleClientSite;

                return ResultFromScode(S_OK);

                }

        if ( riid == IID_IAdviseSink)

                {

                m_AdviseSink.AddRef();

                *ppvObj = &m_AdviseSink;

                return ResultFromScode(S_OK);

                }

        if ( riid == IID_IOleInPlaceSite)

                {

                m_OleInPlaceSite.AddRef();

                *ppvObj = &m_OleInPlaceSite;

                return ResultFromScode(S_OK);

                }

        // Not a supported interface

        return ResultFromScode(E_NOINTERFACE);

}


 CSimpleSite::AddRef  (SIMPCNTR Sample)

//**********************************************************************

//

// CSimpleSite::AddRef

//

// Purpose:

//

//      Increments the reference count of the container Site.

//

// Parameters:

//

//      None

//

// Return Value:

//

//      ULONG   -   The new reference count of the site.

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//********************************************************************

STDMETHODIMP_(ULONG) CSimpleSite::AddRef()

{

        OutputDebugString("In CSimpleSite::AddRef\r\n");

        return SafeAddRef();

}


 CSimpleSite::Release  (SIMPCNTR Sample)

//**********************************************************************

//

// CSimpleSite::Release

//

// Purpose:

//

//      Decrements the reference count of the container Site

//

// Parameters:

//

//      None

//

// Return Value:

//

//      ULONG   -   The new reference count of the Site.

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//********************************************************************

STDMETHODIMP_(ULONG) CSimpleSite::Release()

{

        OutputDebugString("In CSimpleSite::Release\r\n");

        return(SafeRelease());

}


 CSimpleSite::InitObject  (SIMPCNTR Sample)

//**********************************************************************

//

// CSimpleSite::InitObject

//

// Purpose:

//

//      Used to initialize a newly create object (can't be done in the

//      constructor).

//

// Parameters:

//

//      BOOL fCreateNew -   TRUE if insert NEW object

//                          FALSE if create object FROM FILE

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                        Location

//

//      IOleObject::SetHostNames        Object

//      IOleObject::QueryInterface      Object

//      IViewObject2::GetExtent         Object

//      IOleObject::DoVerb              Object

//      IViewObject::SetAdvise          Object

//      IViewObject::Release            Object

//      GetClientRect                   Windows API

//      OleSetContainedObject           OLE API

//

// Comments:

//

//********************************************************************

void CSimpleSite::InitObject(BOOL fCreateNew)

{

        CStabilize stabilize(this);

        LPVIEWOBJECT2 lpViewObject2;

        RECT rect;

        // Set a View Advise

        m_lpOleObject->QueryInterface(IID_IViewObject2,(LPVOID FAR *)&lpViewObject2);

        lpViewObject2->SetAdvise(m_dwDrawAspect, ADVF_PRIMEFIRST, &m_AdviseSink);

        // get the initial size of the object

        lpViewObject2->GetExtent(m_dwDrawAspect, -1 /*lindex*/, NULL /*ptd*/, &m_sizel);

        GetObjRect(&rect);  // get the rectangle of the object in pixels

        lpViewObject2->Release();

        // give the object the name of the container app/document

  //@@WTK WIN32, UNICODE

        //m_lpOleObject->SetHostNames("Simple Application", "Simple OLE 2.0 In-Place Container");

        m_lpOleObject->SetHostNames(OLESTR("Simple Application"),

                        OLESTR("Simple OLE 2.0 In-Place Container"));

        // inform object handler/DLL object that it is used in the embedding container's context

        OleSetContainedObject(m_lpOleObject, TRUE);

        if (fCreateNew) {

           // force new object to save to guarantee valid object in our storage.

           // OLE 1.0 objects may close w/o saving. this is NOT necessary if the

           // object is created FROM FILE; its data in storage is already valid.

           m_OleClientSite.SaveObject();

           // we only want to DoVerb(SHOW) if this is an InsertNew object.

           // we should NOT DoVerb(SHOW) if the object is created FromFile.

           m_lpOleObject->DoVerb(

                           OLEIVERB_SHOW,

                           NULL,

                           &m_OleClientSite,

                           -1,

                           m_lpDoc->m_hDocWnd,

                           &rect);

        }

}


 CSimpleSite::PaintObj  (SIMPCNTR Sample)

//**********************************************************************

//

// CSimpleSite::PaintObj

//

// Purpose:

//

//      Paints the object

//

// Parameters:

//

//      HDC hDC     - Device context of the document window

//

// Return Value:

//

// Function Calls:

//      Function                        Location

//

//      IOleObject::QueryInterface      Object

//      IViewObject::GetColorSet        Object

//      IViewObject::Release            Object

//      SetMapMode                      Windows API

//      LPtoDP                          Windows API

//      CreateHatchBrush                Windows API

//      SelectObject                    Windows API

//      DeleteObject                    Windows API

//      CreatePalette                   Windows API

//      SelectPalette                   Windows API

//      RealizePalette                  Windows API

//      OleStdFree                      OUTLUI Function

//      OleDraw                         OLE API

//

// Comments:

//

//********************************************************************

void CSimpleSite::PaintObj(HDC hDC)

{

RECT rect;

        CStabilize stabilize(this);

        // need to check to make sure there is a valid object

        // available.  This is needed if there is a paint msg

        // between the time that CSimpleSite is instantiated

        // and OleUIInsertObject returns.

        if (!m_lpOleObject)

                return;

        // convert it to pixels

        GetObjRect(&rect);

        LPLOGPALETTE pColorSet = NULL;

        LPVIEWOBJECT lpView = NULL;

        // get a pointer to IViewObject

        m_lpOleObject->QueryInterface(IID_IViewObject,(LPVOID FAR *) &lpView);

        // if the QI succeeds, get the LOGPALETTE for the object

        if (lpView)

                lpView->GetColorSet(m_dwDrawAspect, -1, NULL, NULL, NULL, &pColorSet);

        HPALETTE hPal=NULL;

        HPALETTE hOldPal=NULL;

        // if a LOGPALETTE was returned (not guarateed), create the palette and

        // realize it.  NOTE: A smarter application would want to get the LOGPALETTE

        // for each of its visible objects, and try to create a palette that

        // satisfies all of the visible objects.  ALSO: OleStdFree() is use to

        // free the returned LOGPALETTE.

        if ((pColorSet))

                {

                //@@WTK WIN32, UNICODE

                //hPal = CreatePalette((const LPLOGPALETTE) pColorSet);

                hPal = CreatePalette( pColorSet);

                hOldPal = SelectPalette(hDC, hPal, FALSE);

                RealizePalette(hDC);

                OleStdFree(pColorSet);

                }

        // draw the object

        OleDraw(m_lpOleObject, m_dwDrawAspect, hDC, &rect);

        // if the object is open, draw a hatch rect.

        if (m_fObjectOpen)

                {

                HBRUSH hBrush = CreateHatchBrush ( HS_BDIAGONAL, RGB(0,0,0) );

                HBRUSH hOldBrush = SelectObject (hDC, hBrush);

                SetROP2(hDC, R2_MASKPEN);

                Rectangle (hDC, rect.left, rect.top, rect.right, rect.bottom);

                SelectObject(hDC, hOldBrush);

                DeleteObject(hBrush);

                }

        // if we created a palette, restore the old one, and destroy

        // the object.

        if (hPal)

                {

                SelectPalette(hDC,hOldPal,FALSE);

                DeleteObject(hPal);

                }

        // if a view pointer was successfully returned, it needs to be released.

        if (lpView)

                lpView->Release();

}


 CSimpleSite::GetObjRect  (SIMPCNTR Sample)

//**********************************************************************

//

// CSimpleSite::GetObjRect

//

// Purpose:

//

//      Retrieves the rect of the object in pixels

//

// Parameters:

//

//      LPRECT lpRect - Rect structure filled with object's rect in pixels

//

// Return Value:

//

// Function Calls:

//      Function                        Location

//

//      XformWidthInHimetricToPixels    OUTLUI Function

//      XformHeightInHimetricToPixels   OUTLUI Function

//

// Comments:

//

//********************************************************************

void CSimpleSite::GetObjRect(LPRECT lpRect)

{

        // convert it to pixels

        lpRect->left = lpRect->top = 0;

        lpRect->right = XformWidthInHimetricToPixels(NULL,(int)m_sizel.cx);

        lpRect->bottom = XformHeightInHimetricToPixels(NULL,(int)m_sizel.cy);

}


 SIMPDND

Simple Drag and Drop Sample

This sample demonstrates an implementation of OLE 2 drag and drop. For information on compiling and building the sample, see the makefile in this directory.


 MAKEFILE  (SIMPDND Sample)

!include <$(MSTOOLS)\samples\ole\include\olesampl.mak>

all: simpdnd.exe

simpdnd.exe:  app.obj         \

            doc.obj         \

            dxferobj.obj    \

            ias.obj         \

            ids.obj         \

            idt.obj         \

            iocs.obj        \

            simpdnd.obj     \

            simpdnd.res     \

            site.obj

  $(link) $(linkdebug) $(guiflags) -machine:$(CPU) -out:$*.exe $** $(olelibs) ole2ui.lib

.cpp.obj:

    $(cc) $(cdebug) $(cflags) $(cvars) $*.cpp

simpdnd.res: simpdnd.rc simpdnd.h

    $(rc) -r -I..\ole2ui -I..\ole2ui\res\usa -I..\ole2ui\res\static simpdnd.rc


 APP.H  (SIMPDND Sample)

//**********************************************************************

// File name: app.h

//

//      Definition of CSimpleApp

//

// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#if !defined( _APP_H_)

#define _APP_H_

#include <ole2.h>

#include <stablize.h>

class CSimpleDoc;

class CSimpleApp : public IUnknown, public CSafeRefCount

{

public:

        HWND m_hAppWnd;         // main window handle

        HINSTANCE m_hInst;      // application instance

        CSimpleDoc FAR * m_lpDoc;   // pointer to document object

        BOOL m_fInitialized;    // OLE initialization flag

        HMENU           m_hMainMenu;

        HMENU           m_hFileMenu;

        HMENU           m_hEditMenu;

        HMENU           m_hHelpMenu;

        HMENU           m_hCascadeMenu;     // OLE object's verb

        // Drag/Drop related fields

        int m_nDragDelay;       // time delay (in msec) before drag should start

        int m_nDragMinDist;     // min. distance (radius) before drag should start

        int m_nScrollDelay;     // time delay (in msec) before scroll should start

        int m_nScrollInset;     // Border inset distance to start drag scroll

        int m_nScrollInterval;  // scroll interval time (in msec)

        CSimpleApp();           // Constructor

        ~CSimpleApp();          // Destructor

        // IUnknown Interfaces

        STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj);

        STDMETHODIMP_(ULONG) AddRef();

        STDMETHODIMP_(ULONG) Release();

        // Initialization methods

        BOOL fInitApplication (HANDLE hInstance);

        BOOL fInitInstance (HANDLE hInstance, int nCmdShow);

        // Message handling methods

        long lCommandHandler (HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam);

        long lSizeHandler (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

        long lCreateDoc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

        BOOL HandleAccelerators (LPMSG lpMsg);

        void PaintApp(HDC hDC);

        void DestroyDocs();

};

#endif  // _APP_H_


 DOC.H  (SIMPDND Sample)

//**********************************************************************

// File name: doc.h

//

//      Definition of CSimpleDoc

//

// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#if !defined( _DOC_H_ )

#define _DOC_H_

#include "idt.h"

#include "ids.h"

#include <stablize.h>

class CSimpleSite;

class CSimpleApp;

class CSimpleDoc : public IUnknown, public CSafeRefCount

{

public:

        LPSTORAGE       m_lpStorage;        // IStorage* pointer for Doc

        BOOL            m_fModifiedMenu;    // is object's verb menu on menu

        // Drag/Drop related fields

        BOOL            m_fRegDragDrop;     // is doc registered as drop target?

        BOOL            m_fLocalDrag;       // is doc source of the drag

        BOOL            m_fLocalDrop;       // was doc target of the drop

        BOOL            m_fCanDropCopy;     // is Drag/Drop copy/move possible?

        BOOL            m_fCanDropLink;     // is Drag/Drop link possible?

        BOOL            m_fDragLeave;       // has drag left

        BOOL            m_fPendingDrag;     // LButtonDown--possible drag pending

        POINT           m_ptButDown;        // LButtonDown coordinates

        CSimpleSite FAR * m_lpSite;

        CSimpleApp FAR * m_lpApp;

        HWND m_hDocWnd;

        CDropTarget m_DropTarget;

        CDropSource m_DropSource;

        static CSimpleDoc FAR* Create(CSimpleApp FAR *lpApp, LPRECT lpRect,

                        HWND hWnd);

        void Close(void);

        CSimpleDoc();

        CSimpleDoc(CSimpleApp FAR *lpApp, HWND hWnd);

        ~CSimpleDoc();

        // IUnknown Interface

        STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj);

        STDMETHODIMP_(ULONG) AddRef();

        STDMETHODIMP_(ULONG) Release();

        void InsertObject(void);

        void DisableInsertObject(void);

        long lResizeDoc(LPRECT lpRect);

        long lAddVerbs(void);

        void PaintDoc(HDC hDC);

        // Drag/Drop and clipboard support methods

        void CopyObjectToClip(void);

        BOOL QueryDrag(POINT pt);

        DWORD DoDragDrop(void);

        void Scroll(DWORD dwScrollDir) { /*...scroll Doc here...*/ }

};

#endif  // _DOC_H_


 DXFEROBJ.H  (SIMPDND Sample)

//**********************************************************************

// File name: dxferobj.h

//

//      Definition of CDataXferObj

//

// Copyright (c) 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#if !defined( _DATAXFEROBJ_H_)

#define _DATAXFEROBJ_H_

class CSimpleSite;

interface CDataObject;

class CDataXferObj : public IDataObject

{

private:

int m_nCount;                       // reference count

SIZEL m_sizel;

POINTL m_pointl;

LPSTORAGE m_lpObjStorage;

LPOLEOBJECT m_lpOleObject;

// construction/destruction

CDataXferObj();

~CDataXferObj();

public:

STDMETHODIMP QueryInterface (REFIID riid, LPVOID FAR* ppvObj);

STDMETHODIMP_(ULONG) AddRef ();

STDMETHODIMP_(ULONG) Release ();

STDMETHODIMP DAdvise  ( FORMATETC FAR* pFormatetc, DWORD advf,

LPADVISESINK pAdvSink, DWORD FAR* pdwConnection)

{ return ResultFromScode(OLE_E_ADVISENOTSUPPORTED); }

STDMETHODIMP DUnadvise  ( DWORD dwConnection)

{ return ResultFromScode(OLE_E_ADVISENOTSUPPORTED); }

STDMETHODIMP EnumDAdvise  ( LPENUMSTATDATA FAR* ppenumAdvise)

{ return ResultFromScode(OLE_E_ADVISENOTSUPPORTED); }

STDMETHODIMP EnumFormatEtc  ( DWORD dwDirection,

LPENUMFORMATETC FAR* ppenumFormatEtc);

STDMETHODIMP GetCanonicalFormatEtc  ( LPFORMATETC pformatetc,

LPFORMATETC pformatetcOut)

{ pformatetcOut->ptd = NULL; return ResultFromScode(E_NOTIMPL); }

STDMETHODIMP GetData  (LPFORMATETC pformatetcIn, LPSTGMEDIUM pmedium );

STDMETHODIMP GetDataHere  (LPFORMATETC pformatetc, LPSTGMEDIUM pmedium);

STDMETHODIMP QueryGetData  (LPFORMATETC pformatetc );

STDMETHODIMP SetData  (LPFORMATETC pformatetc, STGMEDIUM FAR * pmedium,

BOOL fRelease)

{ return ResultFromScode(E_NOTIMPL); }

static CDataXferObj FAR* Create(CSimpleSite FAR* lpSite,

POINTL FAR* pPointl);

};

#endif  // _DATAXFEROBJ_H_


 IAS.H  (SIMPDND Sample)

//**********************************************************************

// File name: IAS.H

//

//      Definition of CAdviseSink

//

// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#if !defined( _IAS_H_ )

#define _IAS_H_

#include <assert.h>

class CSimpleSite;

interface CAdviseSink : public IAdviseSink

{

int m_nCount;

CSimpleSite FAR * m_pSite;

CAdviseSink(CSimpleSite FAR * pSite) {

OutputDebugString("In IAS's constructor\r\n");

m_pSite = pSite;

m_nCount = 0;

};

~CAdviseSink() {

OutputDebugString("In IAS's destructor\r\n");

assert(m_nCount == 0);

} ;

STDMETHODIMP QueryInterface (REFIID riid, LPVOID FAR* ppv);

STDMETHODIMP_(ULONG) AddRef ();

STDMETHODIMP_(ULONG) Release ();

// *** IAdviseSink methods ***

STDMETHODIMP_(void) OnDataChange (FORMATETC FAR* pFormatetc, STGMEDIUM FAR* pStgmed);

STDMETHODIMP_(void) OnViewChange (DWORD dwAspect, LONG lindex);

STDMETHODIMP_(void) OnRename (LPMONIKER pmk);

STDMETHODIMP_(void) OnSave ();

STDMETHODIMP_(void) OnClose ();

};

#endif


 IDS.H  (SIMPDND Sample)

//**********************************************************************

// File name: ids.h

//

//      Definition of CDropSource

//

// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#if !defined( _IDS_H_ )

#define _IDS_H_

#include <assert.h>

class CSimpleDoc;

interface CDropSource : public IDropSource

{

int m_nCount;

CSimpleDoc FAR * m_pDoc;

CDropSource(CSimpleDoc FAR * pDoc) {

OutputDebugString("In IDS's constructor\r\n");

m_pDoc = pDoc;

m_nCount = 0;

};

~CDropSource() {

OutputDebugString("In IDS's destructor\r\n");

} ;

STDMETHODIMP QueryInterface (REFIID riid, LPVOID FAR* ppv);

STDMETHODIMP_(ULONG) AddRef ();

STDMETHODIMP_(ULONG) Release ();

   // *** IDropSource methods ***

STDMETHODIMP QueryContinueDrag (BOOL fEscapePressed, DWORD grfKeyState);

STDMETHODIMP GiveFeedback (DWORD dwEffect);

private:

};

#endif


 IDT.H  (SIMPDND Sample)

//**********************************************************************

// File name: idt.h

//

//      Definition of CDropTarget

//

// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#if !defined( _IDT_H_ )

#define _IDT_H_

#include <assert.h>

class CSimpleDoc;

/* Flags to control direction for drag scrolling */

typedef enum tagSCROLLDIR {

SCROLLDIR_NULL          = 0,

SCROLLDIR_UP            = 1,

SCROLLDIR_DOWN          = 2,

SCROLLDIR_RIGHT         = 3,

SCROLLDIR_LEFT          = 4

} SCROLLDIR;

interface CDropTarget : public IDropTarget

{

int   m_nCount;                 // reference count

CSimpleDoc FAR * m_pDoc;

BOOL  m_fCanDropCopy;

BOOL  m_fCanDropLink;

DWORD m_dwSrcAspect;

RECT  m_rcDragRect;

POINT m_ptLast;

BOOL  m_fDragFeedbackDrawn;

DWORD m_dwTimeEnterScrollArea;  // time of entering scroll border region

DWORD m_dwLastScrollDir;        // current dir for drag scroll

DWORD m_dwNextScrollTime;       // time for next scroll

CDropTarget(CSimpleDoc FAR * pDoc) {

OutputDebugString("In IDT's constructor\r\n");

m_pDoc = pDoc;

m_nCount = 0;

m_fCanDropCopy = FALSE;

m_fCanDropLink = FALSE;

m_fDragFeedbackDrawn = FALSE;

m_dwTimeEnterScrollArea = 0L;

m_dwNextScrollTime = 0L;

m_dwLastScrollDir = SCROLLDIR_NULL;

};

~CDropTarget() {

OutputDebugString("In IDT's destructor\r\n");

assert(m_nCount == 0);

} ;

STDMETHODIMP QueryInterface (REFIID riid, LPVOID FAR* ppv);

STDMETHODIMP_(ULONG) AddRef ();

STDMETHODIMP_(ULONG) Release ();

   // *** IDropTarget methods ***

STDMETHODIMP DragEnter (LPDATAOBJECT pDataObj, DWORD grfKeyState,

POINTL pt, LPDWORD pdwEffect);

STDMETHODIMP DragOver  (DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect);

STDMETHODIMP DragLeave ();

STDMETHODIMP Drop (LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt,

LPDWORD pdwEffect);

private:

// Drag/Drop support methods

BOOL QueryDrop (DWORD grfKeyState, POINTL pointl, BOOL fDragScroll,

LPDWORD lpdwEffect);

BOOL DoDragScroll( POINTL pointl );

void InitDragFeedback(LPDATAOBJECT pDataObj, POINTL pointl);

void DrawDragFeedback( POINTL pointl );

void UndrawDragFeedback( void );

};

#endif  // _IDT_H_


 IOCS.H  (SIMPDND Sample)

//**********************************************************************

// File name: IOCS.H

//

//      Definition of COleClientSite

//

// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#if !defined( _IOCS_H_ )

#define _IOCS_H_

#include <assert.h>

class CSimpleSite;

interface COleClientSite : public IOleClientSite

{

int m_nCount;

CSimpleSite FAR * m_pSite;

COleClientSite(CSimpleSite FAR * pSite) {

OutputDebugString("In IOCS's constructor\r\n");

m_pSite = pSite;

m_nCount = 0;

}

~COleClientSite() {

OutputDebugString("In IOCS's destructor\r\n");

assert(m_nCount == 0);

}

STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj);

STDMETHODIMP_(ULONG) AddRef();

STDMETHODIMP_(ULONG) Release();

// *** IOleClientSite methods ***

STDMETHODIMP SaveObject();

STDMETHODIMP GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker, LPMONIKER FAR* ppmk);

STDMETHODIMP GetContainer(LPOLECONTAINER FAR* ppContainer);

STDMETHODIMP ShowObject();

STDMETHODIMP OnShowWindow(BOOL fShow);

STDMETHODIMP RequestNewObjectLayout();

};

#endif


 PRE.H  (SIMPDND Sample)

//**********************************************************************

// File name: pre.h

//

//      Used for precompiled headers

//

// Copyright (c) 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#if !defined( _PRE_H_)

#define _PRE_H_

#include <windows.h>

#include <ole2.h>

#include <ole2ui.h>

#include <assert.h>

#include <string.h>

#include "simpdnd.h"

#include "resource.h"

#include <ole2ver.h>

#endif


 RESOURCE.H  (SIMPDND Sample)

//{{NO_DEPENDENCIES}}

// App Studio generated include file.

// Used by SIMPDND.RC

//

#define IDM_OPEN                        102

#define IDC_DRAGPENDING                 102

#define IDM_SAVE                        103

#define IDM_SAVEAS                      104

#define IDM_PRINT                       105

#define IDM_EXIT                        106

#define IDM_UNDO                        107

#define IDM_CUT                         108

#define IDM_COPY                        109

#define IDM_PASTE                       110

#define ID_EDIT_INSERTOBJECT            111

#define IDM_INSERTOBJECT                111

#define IDM_NEW                         112

// Next default values for new objects

//

#ifdef APSTUDIO_INVOKED

#ifndef APSTUDIO_READONLY_SYMBOLS

#define _APS_NEXT_RESOURCE_VALUE        103

#define _APS_NEXT_COMMAND_VALUE         113

#define _APS_NEXT_CONTROL_VALUE         1000

#define _APS_NEXT_SYMED_VALUE           101

#endif

#endif


 SIMPDND.H  (SIMPDND Sample)

//**********************************************************************

// File name: simpdnd.h

//

// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#define IDM_ABOUT 100

#define IDM_INSERT  101

#define IDM_VERB0 1000

int PASCAL WinMain(HANDLE hInstance,HANDLE hPrevInstance,LPSTR lpCmdLine,int nCmdShow);

BOOL InitApplication(HANDLE hInstance);

BOOL InitInstance(HANDLE hInstance, int nCmdShow);

//@@WTK WIN32, UNICODE

//long FAR PASCAL _export MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

long FAR PASCAL EXPORT MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

//@@WTK WIN32, UNICODE

//long FAR PASCAL _export DocWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

long FAR PASCAL EXPORT DocWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

//@@WTK WIN32, UNICODE

//BOOL FAR PASCAL _export About(HWND hDlg, unsigned message, WORD wParam, LONG lParam);

BOOL FAR PASCAL EXPORT About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);


 SITE.H  (SIMPDND Sample)

//**********************************************************************

// File name: SITE.H

//

//      Definition of CSimpleSite

//

// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#if !defined( _SITE_H_ )

#define _SITE_H_

#include <ole2.h>

#include "ias.h"

#include "iocs.h"

class CSimpleDoc;

class CSimpleSite : public IUnknown

{

public:

int m_nCount;

LPOLEOBJECT m_lpOleObject;

DWORD m_dwDrawAspect;

SIZEL m_sizel;

BOOL m_fObjectOpen;

LPSTORAGE m_lpObjStorage;

CAdviseSink m_AdviseSink;

COleClientSite m_OleClientSite;

CSimpleDoc FAR * m_lpDoc;

// IUnknown Interfaces

STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj);

STDMETHODIMP_(ULONG) AddRef();

STDMETHODIMP_(ULONG) Release();

void InitObject(BOOL fCreateNew);

static CSimpleSite FAR * Create(CSimpleDoc FAR *lpDoc);

CSimpleSite(CSimpleDoc FAR *lpDoc);

~CSimpleSite();

void PaintObj(HDC hDC);

void GetObjRect(LPRECT lpRect);

void CloseOleObject(void);

void UnloadOleObject(void);

};

#endif  // _SITE_H_


 APP.CPP  (SIMPDND Sample)

//**********************************************************************

// File name: app.cpp

//

//    Implementation file for the CSimpleApp Class

//

// Functions:

//

//    See app.h for a list of member functions.

//

// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#include "pre.h"

#include "iocs.h"

#include "ias.h"

#include "app.h"

#include "site.h"

#include "doc.h"


 CSimpleApp::CSimpleApp  (SIMPDND Sample)

//**********************************************************************

//

// CSimpleApp::CSimpleApp()

//

// Purpose:

//

//      Constructor for CSimpleApp

//

// Parameters:

//

//      None

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      SetRectEmpty                Windows API

//

// Comments:

//

//********************************************************************

CSimpleApp::CSimpleApp()

{

        OutputDebugString("In CSimpleApp's Constructor \r\n");

        // clear members

        m_hAppWnd = NULL;

        m_hInst = NULL;

        m_lpDoc = NULL;

        // clear flags

        m_fInitialized = FALSE;

}


 CSimpleApp::~CSimpleApp  (SIMPDND Sample)

//**********************************************************************

//

// CSimpleApp::~CSimpleApp()

//

// Purpose:

//

//      Destructor for CSimpleApp Class.

//

// Parameters:

//

//      None

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      OleUninitialize             OLE API

//

// Comments:

//

//********************************************************************

CSimpleApp::~CSimpleApp()

{

        OutputDebugString("In CSimpleApp's Destructor\r\n");

        // need to uninit the library...

        if (m_fInitialized)

                OleUninitialize();

}


 CSimpleApp::DestroyDocs  (SIMPDND Sample)

//**********************************************************************

//

// CSimpleApp::DestroyDocs()

//

// Purpose:

//

//      Destroys all of the open documents in the application (Only one

//      since this is an SDI app, but could easily be modified to

//      support MDI).

//

// Parameters:

//

//      None

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                    Location

//

// Comments:

//

//********************************************************************

void CSimpleApp::DestroyDocs()

{

        CStabilize stabilize(this);

        m_lpDoc->Close();   // we have only 1 document

}


 CSimpleApp::QueryInterface  (SIMPDND Sample)

//**********************************************************************

//

// CSimpleApp::QueryInterface

//

// Purpose:

//

//      Used for interface negotiation at the Frame level.

//

// Parameters:

//

//      REFIID riid         -   A reference to the interface that is

//                              being queried.

//

//      LPVOID FAR* ppvObj  -   An out parameter to return a pointer to

//                              the interface.

//

// Return Value:

//

//      S_OK    -   The interface is supported.

//      S_FALSE -   The interface is not supported

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      ResultFromScode             OLE API

//

// Comments:

//

//********************************************************************

STDMETHODIMP CSimpleApp::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)

{

        OutputDebugString("In CSimpleApp::QueryInterface\r\n");

        *ppvObj = NULL;     // must set out pointer parameters to NULL

        // Not a supported interface

        return ResultFromScode(E_NOINTERFACE);

}


 CSimpleApp::AddRef  (SIMPDND Sample)

//**********************************************************************

//

// CSimpleApp::AddRef

//

// Purpose:

//

//      Adds to the reference count at the Application level.

//

// Parameters:

//

//      None

//

// Return Value:

//

//      ULONG   -   The new reference count of the application.

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//      Due to the reference counting model that is used in this

//      implementation, this reference count is the sum of the

//      reference counts on all interfaces of all objects open

//      in the application.

//

//********************************************************************

STDMETHODIMP_(ULONG) CSimpleApp::AddRef()

{

        OutputDebugString("In CSimpleApp::AddRef\r\n");

        return SafeAddRef();

}


 CSimpleApp::Release  (SIMPDND Sample)

//**********************************************************************

//

// CSimpleApp::Release

//

// Purpose:

//

//      Decrements the reference count at this level

//

// Parameters:

//

//      None

//

// Return Value:

//

//      ULONG   -   The new reference count of the application.

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//********************************************************************

STDMETHODIMP_(ULONG) CSimpleApp::Release()

{

        OutputDebugString("In CSimpleApp::Release\r\n");

        return SafeRelease();

}


 CSimpleApp::fInitApplication  (SIMPDND Sample)

//**********************************************************************

//

// CSimpleApp::fInitApplication

//

// Purpose:

//

//      Initializes the application

//

// Parameters:

//

//      HANDLE hInstance    -   Instance handle of the application.

//

// Return Value:

//

//      TRUE    -   Application was successfully initialized.

//      FALSE   -   Application could not be initialized

//

// Function Calls:

//      Function                    Location

//

//      LoadIcon                    Windows API

//      LoadCursor                  Windows API

//      GetStockObject              Windows API

//      RegisterClass               Windows API

//

// Comments:

//

//********************************************************************

BOOL CSimpleApp::fInitApplication(HANDLE hInstance)

{

        WNDCLASS  wc;

        CStabilize stabilize(this);

        // Fill in window class structure with parameters that describe the

        // main window.

        wc.style = NULL;                    // Class style(s).

        wc.lpfnWndProc = MainWndProc;       // Function to retrieve messages for

                                                                                // windows of this class.

        wc.cbClsExtra = 0;                  // No per-class extra data.

        wc.cbWndExtra = 0;                  // No per-window extra data.

        wc.hInstance = hInstance;           // Application that owns the class.

        wc.hIcon = LoadIcon(hInstance,"SimpDnd");

        wc.hCursor = LoadCursor(NULL, IDC_ARROW);

        wc.hbrBackground = GetStockObject(WHITE_BRUSH);

        wc.lpszMenuName =  "SIMPLEMENU";    // Name of menu resource in .RC file.

        wc.lpszClassName = "SimpDndAppWClass";  // Name used in CreateWindow call.

        if (!RegisterClass(&wc))

                return FALSE;

        wc.style = CS_DBLCLKS;              // Class style(s). allow DBLCLK's

        wc.lpfnWndProc = DocWndProc;        // Function to retrieve messages for

                                                                                // windows of this class.

        wc.cbClsExtra = 0;                  // No per-class extra data.

        wc.cbWndExtra = 0;                  // No per-window extra data.

        wc.hInstance = hInstance;           // Application that owns the class.

        wc.hIcon = NULL;

        wc.hCursor = LoadCursor(NULL, IDC_ARROW);

        wc.hbrBackground = GetStockObject(WHITE_BRUSH);

        wc.lpszMenuName =  NULL;

        wc.lpszClassName = "SimpDndDocWClass"; // Name used in CreateWindow call.

        // Register the window class and return success/failure code.

        return (RegisterClass(&wc));

}


 CSimpleApp::fInitInstance  (SIMPDND Sample)

//**********************************************************************

//

// CSimpleApp::fInitInstance

//

// Purpose:

//

//      Instance initialization.

//

// Parameters:

//

//      HANDLE hInstance    -   App. Instance Handle.

//

//      int nCmdShow        -   Show parameter from WinMain

//

// Return Value:

//

//      TRUE    -   Initialization Successful

//      FALSE   -   Initialization Failed.

//

//

// Function Calls:

//      Function                    Location

//

//      CreateWindow                Windows API

//      ShowWindow                  Windows API

//      UpdateWindow                Windows API

//      OleBuildVersion             OLE API

//      OleInitialize               OLE API

//

// Comments:

//

//      Note that successful Initalization of the OLE libraries

//      is remembered so the UnInit is only called if needed.

//

//********************************************************************

BOOL CSimpleApp::fInitInstance (HANDLE hInstance, int nCmdShow)

{

        CStabilize stabilize(this);

        DWORD dwVer = OleBuildVersion();

        LPMALLOC lpMalloc = NULL;

        // check to see if we are compatible with this version of the libraries

        if (HIWORD(dwVer) != rmm || LOWORD(dwVer) < rup) {

#ifdef _DEBUG

                OutputDebugString("WARNING: Incompatible OLE library version\r\n");

#else

                return FALSE;

#endif

        }

#if defined( _DEBUG )

        /* OLE2NOTE: Use a special debug allocator to help track down

        **    memory leaks.

        */

        OleStdCreateDbAlloc(0, &lpMalloc);

#endif

        if (SUCCEEDED(OleInitialize(lpMalloc)))

        {

            m_fInitialized = TRUE;

        }

        else

        {

            // Replacing the allocator may not be legal.

            // Try again using the default allocator.

            if (SUCCEEDED(OleInitialize(NULL)))

            {

                m_fInitialized = TRUE;

            }

        }

#if defined( _DEBUG )

        /* OLE2NOTE: release the special debug allocator so that only OLE is

        **    holding on to it. later when OleUninitialize is called, then

        **    the debug allocator object will be destroyed. when the debug

        **    allocator object is destoyed, it will report (to the Output

        **    Debug Terminal) whether there are any memory leaks.

        */

        if (lpMalloc) lpMalloc->Release();

#endif

        m_hInst = hInstance;

        // Create the "application" windows

        m_hAppWnd = CreateWindow ("SimpDndAppWClass",

                                                          "Simple OLE 2.0 Drag/Drop Container",

                                                          WS_OVERLAPPEDWINDOW,

                                                          CW_USEDEFAULT,

                                                          CW_USEDEFAULT,

                                                          CW_USEDEFAULT,

                                                          CW_USEDEFAULT,

                                                          NULL,

                                                          NULL,

                                                          hInstance,

                                                          NULL);

        if (!m_hAppWnd)

                return FALSE;

        // delay before dragging should start, in milliseconds

        m_nDragDelay = GetProfileInt(

                        "windows",

                        "DragDelay",

                        DD_DEFDRAGDELAY

        );

        // minimum distance (radius) before drag should start, in pixels

        m_nDragMinDist = GetProfileInt(

                        "windows",

                        "DragMinDist",

                        DD_DEFDRAGMINDIST

        );

        // delay before scrolling, in milliseconds

        m_nScrollDelay = GetProfileInt(

                        "windows",

                        "DragScrollDelay",

                        DD_DEFSCROLLDELAY

        );

        // inset-width of the hot zone, in pixels

        m_nScrollInset = GetProfileInt(

                        "windows",

                        "DragScrollInset",

                        DD_DEFSCROLLINSET

        );

        // scroll interval, in milliseconds

        m_nScrollInterval = GetProfileInt(

                        "windows",

                        "DragScrollInterval",

                        DD_DEFSCROLLINTERVAL

        );

        ShowWindow (m_hAppWnd, nCmdShow);

        UpdateWindow (m_hAppWnd);

        return m_fInitialized;

}


 CSimpleApp::lCommandHandler  (SIMPDND Sample)

//**********************************************************************

//

// CSimpleApp::lCommandHandler

//

// Purpose:

//

//      Handles the processing of WM_COMMAND.

//

// Parameters:

//

//      HWND hWnd       -   Handle to the application Window

//

//      UINT message    -   message (always WM_COMMAND)

//

//      WPARAM wParam   -   Same as passed to the WndProc

//

//      LPARAM lParam   -   Same as passed to the WndProc

//

// Return Value:

//

//      NULL

//

// Function Calls:

//      Function                                    Location

//

//      IOleObject::DoVerb                          Object

//      GetClientRect                               Windows API

//      MessageBox                                  Windows API

//      DialogBox                                   Windows API

//      MakeProcInstance                            Windows API

//      FreeProcInstance                            Windows API

//      SendMessage                                 Windows API

//      DefWindowProc                               Windows API

//      CSimpleDoc::InsertObject                    DOC.CPP

//

// Comments:

//

//********************************************************************

long CSimpleApp::lCommandHandler (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

{

        RECT rect;

        CStabilize stabilize(this);

        // see if the command is a verb selections

        //@@WTK WIN32, UNICODE

        //if (wParam >= IDM_VERB0)

        if (LOWORD(wParam) >= IDM_VERB0)

                {

                // get the rectangle of the object

                m_lpDoc->m_lpSite->GetObjRect(&rect);

                m_lpDoc->m_lpSite->m_lpOleObject->DoVerb(

                                LOWORD(wParam) - IDM_VERB0, NULL,

                                &m_lpDoc->m_lpSite->m_OleClientSite, -1,

                                m_lpDoc->m_hDocWnd, &rect);

                }

        else

                {

                //@@WTK WIN32, UNICODE

                //switch (wParam) {

                switch (LOWORD(wParam)) {

                        // bring up the About box

                        case IDM_ABOUT:

                                {

                                FARPROC lpProcAbout = MakeProcInstance((FARPROC)About, m_hInst);

                                DialogBox(m_hInst,               // current instance

                                        "AboutBox",                  // resource to use

                                        m_hAppWnd,                   // parent handle

                                        lpProcAbout);                // About() instance address

                                FreeProcInstance(lpProcAbout);

                                break;

                                }

                        // bring up the InsertObject Dialog

                        case IDM_INSERTOBJECT:

                                m_lpDoc->InsertObject();

                                break;

                        // Copy the object to the Clipboard

                        case IDM_COPY:

                                m_lpDoc->CopyObjectToClip();

                                break;

                        // exit the application

                        case IDM_EXIT:

                                SendMessage(hWnd, WM_SYSCOMMAND, SC_CLOSE, 0L);

                                break;

                        case IDM_NEW:

                                m_lpDoc->Close();

                                m_lpDoc = NULL;

                                lCreateDoc(hWnd, 0, 0, 0);

                                break;

                        default:

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

                        }   // end of switch

                }  // end of else

        return NULL;

}


 CSimpleApp::lSizeHandler  (SIMPDND Sample)

//**********************************************************************

//

// CSimpleApp::lSizeHandler

//

// Purpose:

//

//      Handles the WM_SIZE message

//

// Parameters:

//

//      HWND hWnd       -   Handle to the application Window

//

//      UINT message    -   message (always WM_SIZE)

//

//      WPARAM wParam   -   Same as passed to the WndProc

//

//      LPARAM lParam   -   Same as passed to the WndProc

//

// Return Value:

//

//      LONG    -   returned from the "document" resizing

//

// Function Calls:

//      Function                    Location

//

//      GetClientRect               Windows API

//      CSimpleDoc::lResizeDoc      DOC.CPP

//

// Comments:

//

//********************************************************************

long CSimpleApp::lSizeHandler (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

{

        RECT rect;

        CStabilize stabilize(this);

        GetClientRect(m_hAppWnd, &rect);

        return m_lpDoc->lResizeDoc(&rect);

}


 CSimpleApp::lCreateDoc  (SIMPDND Sample)

//**********************************************************************

//

// CSimpleApp::lCreateDoc

//

// Purpose:

//

//      Handles the creation of a document.

//

// Parameters:

//

//      HWND hWnd       -   Handle to the application Window

//

//      UINT message    -   message (always WM_CREATE)

//

//      WPARAM wParam   -   Same as passed to the WndProc

//

//      LPARAM lParam   -   Same as passed to the WndProc

//

// Return Value:

//

//      NULL

//

// Function Calls:

//      Function                    Location

//

//      GetClientRect               Windows API

//      CSimpleDoc::CSimpleDoc      DOC.CPP

//

// Comments:

//

//********************************************************************

long CSimpleApp::lCreateDoc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

{

        RECT rect;

        CStabilize stabilize(this);

        GetClientRect(hWnd, &rect);

        m_lpDoc = CSimpleDoc::Create(this, &rect, hWnd);

        return NULL;

}


 CSimpleApp::HandleAccelerators  (SIMPDND Sample)

//**********************************************************************

//

// CSimpleApp::HandleAccelerators

//

// Purpose:

//

//      To properly handle accelerators in the Message Loop

//

// Parameters:

//

//      LPMSG lpMsg -   A pointer to the message structure.

//

// Return Value:

//

//      TRUE    -   The accelerator was handled

//      FALSE   -   The accelerator was not handled

//

// Function Calls:

//      Function                                        Location

//

// Comments:

//

//********************************************************************

BOOL CSimpleApp::HandleAccelerators(LPMSG lpMsg)

{

        BOOL retval = FALSE;

        // we do not have any accelerators

        return retval;

}


 CSimpleApp::PaintApp  (SIMPDND Sample)

//**********************************************************************

//

// CSimpleApp::PaintApp

//

// Purpose:

//

//      Handles the painting of the doc window.

//

//

// Parameters:

//

//      HDC hDC -   hDC to the Doc Window.

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                    Location

//

//      CSimpleDoc::PaintDoc        DOC.CPP

//

// Comments:

//

//      This is an app level function in case we want to do palette

//      management.

//

//********************************************************************

void CSimpleApp::PaintApp (HDC hDC)

{

        CStabilize stabilize(this);

        // at this level, we could enumerate through all of the

        // visible objects in the application, so that a palette

        // that best fits all of the objects can be built.

        // This app is designed to take on the same palette

        // functionality that was provided in OLE 1.0, the palette

        // of the last object drawn is realized.  Since we only

        // support one object at a time, it shouldn't be a big

        // deal.

        // if we supported multiple documents, we would enumerate

        // through each of the open documents and call paint.

        if (m_lpDoc)

                m_lpDoc->PaintDoc(hDC);

}


 DOC.CPP  (SIMPDND Sample)

//**********************************************************************

// File name: DOC.CPP

//

//      Implementation file for CSimpleDoc.

//

// Functions:

//

//      See DOC.H for Class Definition

//

// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#include "pre.h"

#include "iocs.h"

#include "ias.h"

#include "app.h"

#include "site.h"

#include "doc.h"

#include "idt.h"

#include "dxferobj.h"


 CSimpleDoc::Create  (SIMPDND Sample)

//**********************************************************************

//

// CSimpleDoc::Create

//

// Purpose:

//

//      Creation for the CSimpleDoc Class

//

// Parameters:

//

//      CSimpleApp FAR * lpApp  -   Pointer to the CSimpleApp Class

//

//      LPRECT lpRect           -   Client area rect of "frame" window

//

//      HWND hWnd               -   Window Handle of "frame" window

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                    Location

//

//      StgCreateDocfile            OLE API

//      RegisterDragDrop            OLE API

//      CoLockObjectExternal        OLE API

//      CreateWindow                Windows API

//      ShowWindow                  Windows API

//      UpdateWindow                Windows API

//

// Comments:

//

//      This routine was added so that failure could be returned

//      from object creation.

//

//********************************************************************

CSimpleDoc FAR * CSimpleDoc::Create(CSimpleApp FAR *lpApp, LPRECT lpRect,HWND hWnd)

{

        CSimpleDoc FAR * lpTemp = new CSimpleDoc(lpApp, hWnd);

        if (!lpTemp)

                return NULL;

        // create storage for the doc.

        HRESULT hErr = StgCreateDocfile (

                NULL,       // generate temp name

                STGM_READWRITE | STGM_TRANSACTED | STGM_SHARE_EXCLUSIVE,

                0, &lpTemp->m_lpStorage);

        if (hErr != NOERROR)

                goto error;

        // create the document Window

        lpTemp->m_hDocWnd = CreateWindow(

                        "SimpDndDocWClass",

                        NULL,

                        WS_CHILD | WS_CLIPCHILDREN,

                        lpRect->left,

                        lpRect->top,

                        lpRect->right,

                        lpRect->bottom,

                        hWnd,

                        NULL,

                        lpApp->m_hInst,

                        NULL);

        if (!lpTemp->m_hDocWnd)

                goto error;

        ShowWindow(lpTemp->m_hDocWnd, SW_SHOWNORMAL);  // Show the window

        UpdateWindow(lpTemp->m_hDocWnd);               // Sends WM_PAINT message

        // Ensable InsertObject menu choice

        EnableMenuItem( lpApp->m_hEditMenu, 1, MF_BYPOSITION | MF_ENABLED);

        // Disable Copy menu choice

        EnableMenuItem( lpApp->m_hEditMenu, 0, MF_BYPOSITION | MF_DISABLED | MF_GRAYED);

        // It is *REQUIRED* to hold a strong LOCK on the object that is

        // registered as drop target. this call will result in at least one

        // ref count held on our document. later in CSimpleDoc::Close we will

        // unlock this lock which will make our document's ref count go to 0.

        // when the document's ref count goes to 0, it will be deleted.

        CoLockObjectExternal (&lpTemp->m_DropTarget, TRUE, 0);

        // Register our window as a DropTarget

        RegisterDragDrop(lpTemp->m_hDocWnd, &lpTemp->m_DropTarget);

        lpTemp->m_fRegDragDrop = TRUE;

        return (lpTemp);

error:

        delete (lpTemp);

        return NULL;

}


 CSimpleDoc::Close  (SIMPDND Sample)

//**********************************************************************

//

// CSimpleDoc::Close

//

// Purpose:

//

//      Close CSimpleDoc object.

//      when the document's reference count goes to 0, the document

//      will be destroyed.

//

// Parameters:

//

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                    Location

//

//      RevokeDragDrop              OLE API

//      CoLockObjectExternal        OLE API

//      OleFlushClipboard           OLE API

//      ShowWindow                  Windows API

//

// Comments:

//

//********************************************************************

void CSimpleDoc::Close(void)

{

        OutputDebugString("In CSimpleDoc::Close\r\n");

        CStabilize stabilize(this);

        ShowWindow(m_hDocWnd, SW_HIDE);  // Hide the window

        // Remove our data transfer object from clipboard if it is there.

        //  this will leave HGLOBAL based data behind on the clipboard

        //  including OLE 1.0 compatibility formats.

        OleFlushClipboard();

        // Revoke our window as a DropTarget

        if (m_fRegDragDrop) {

                RevokeDragDrop(m_hDocWnd);

                m_fRegDragDrop = FALSE;

        }

        // Close the OLE object in our document

        if (m_lpSite)

                m_lpSite->CloseOleObject();

        // Unlock the lock added in CSimpleDoc::Create. this will make

        // the document's ref count go to 0, and the document will be deleted.

        CoLockObjectExternal (&m_DropTarget, FALSE, TRUE);

}


 CSimpleDoc::CSimpleDoc  (SIMPDND Sample)

//**********************************************************************

//

// CSimpleDoc::CSimpleDoc

//

// Purpose:

//

//      Constructor for the CSimpleDoc Class

//

// Parameters:

//

//      CSimpleApp FAR * lpApp  -   Pointer to the CSimpleApp Class

//

//      HWND hWnd               -   Window Handle of "frame" window

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      GetMenu                     Windows API

//      GetSubMenu                  Windows API

//

// Comments:

//

//********************************************************************

#pragma warning(disable : 4355)  // turn off this warning.  This warning

                                                                // tells us that we are passing this in

                                                                // an initializer, before "this" is through

                                                                // initializing.  This is ok, because

                                                                // we just store the ptr in the other

                                                                // constructor

CSimpleDoc::CSimpleDoc(CSimpleApp FAR * lpApp,HWND hWnd)

                : m_DropTarget(this), m_DropSource(this)

#pragma warning (default : 4355)  // Turn the warning back on

{

        OutputDebugString("In CSimpleDoc's Constructor\r\n");

        m_lpApp = lpApp;

        m_lpSite = NULL;

        // set up menu handles

        lpApp->m_hMainMenu = GetMenu(hWnd);

        lpApp->m_hFileMenu = GetSubMenu(lpApp->m_hMainMenu, 0);

        lpApp->m_hEditMenu = GetSubMenu(lpApp->m_hMainMenu, 1);

        lpApp->m_hHelpMenu = GetSubMenu(lpApp->m_hMainMenu, 2);

        lpApp->m_hCascadeMenu = NULL;

        m_fModifiedMenu = FALSE;

        // drag/drop related stuff

        m_fRegDragDrop = FALSE;       // is doc registered as drop target?

        m_fLocalDrag = FALSE;         // is doc source of the drag

        m_fLocalDrop = FALSE;         // was doc target of the drop

        m_fCanDropCopy = FALSE;       // is Drag/Drop copy/move possible?

        m_fCanDropLink = FALSE;       // is Drag/Drop link possible?

        m_fDragLeave = FALSE;         // has drag left

        m_fPendingDrag = FALSE;       // LButtonDown--possible drag pending

        m_ptButDown.x = m_ptButDown.y = 0; // LButtonDown coordinates

}


 CSimpleDoc::~CSimpleDoc  (SIMPDND Sample)

//**********************************************************************

//

// CSimpleDoc::~CSimpleDoc

//

// Purpose:

//

//      Destructor for CSimpleDoc

//

// Parameters:

//

//      None

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      CSimpleSite::Release        SITE.CPP

//      IStorage::Release           OLE API

//

// Comments:

//

//********************************************************************

CSimpleDoc::~CSimpleDoc()

{

        OutputDebugString("In CSimpleDoc's Destructor\r\n");

        // Release all pointers we hold to the OLE object. also release

        // the ref count added in CSimpleSite::Create. this will make

        // the Site's ref count go to 0, and the Site will be deleted.

        if (m_lpSite) {

                m_lpSite->UnloadOleObject();

                m_lpSite->Release();

                m_lpSite = NULL;

        }

        // Release the Storage

        if (m_lpStorage) {

                m_lpStorage->Release();

                m_lpStorage = NULL;

        }

        // if the edit menu was modified, remove the menu item and

        // destroy the popup if it exists

        if (m_fModifiedMenu)

                {

                int nCount = GetMenuItemCount(m_lpApp->m_hEditMenu);

                RemoveMenu(m_lpApp->m_hEditMenu, nCount-1, MF_BYPOSITION);

                if (m_lpApp->m_hCascadeMenu)

                        DestroyMenu(m_lpApp->m_hCascadeMenu);

                }

        DestroyWindow(m_hDocWnd);

}


 CSimpleDoc::QueryInterface  (SIMPDND Sample)

//**********************************************************************

//

// CSimpleDoc::QueryInterface

//

// Purpose:

//

//      Return a pointer to a requested interface

//

// Parameters:

//

//      REFIID riid         -   ID of interface to be returned

//      LPVOID FAR* ppvObj  -   Location to return the interface

//

// Return Value:

//

//      S_OK                -   Interface supported

//      E_NOINTERFACE       -   Interface NOT supported

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      ResultFromScode             OLE API

//

// Comments:

//

//********************************************************************

STDMETHODIMP CSimpleDoc::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)

{

        OutputDebugString("In CSimpleDoc::QueryInterface\r\n");

        *ppvObj = NULL;     // must set out pointer parameters to NULL

        // looking for IUnknown

        if ( riid == IID_IUnknown)

                {

                AddRef();

                *ppvObj = this;

                return ResultFromScode(S_OK);

                }

        // looking for IDropTarget

        if ( riid == IID_IDropTarget)

                {

                m_DropTarget.AddRef();

                *ppvObj=&m_DropTarget;

                return ResultFromScode(S_OK);

                }

        // looking for IDropSource

        if ( riid == IID_IDropSource)

                {

                m_DropSource.AddRef();

                *ppvObj=&m_DropSource;

                return ResultFromScode(S_OK);

                }

        // Not a supported interface

        return ResultFromScode(E_NOINTERFACE);

}


 CSimpleDoc::AddRef  (SIMPDND Sample)

//**********************************************************************

//

// CSimpleDoc::AddRef

//

// Purpose:

//

//      Increments the document reference count

//

// Parameters:

//

//      None

//

// Return Value:

//

//      UINT    -   The current reference count on the document

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      CSimpleApp::AddRef          APP.CPP

//

// Comments:

//

//********************************************************************

STDMETHODIMP_(ULONG) CSimpleDoc::AddRef()

{

        OutputDebugString("In CSimpleDoc::AddRef\r\n");

        return SafeAddRef();

}


 CSimpleDoc::Release  (SIMPDND Sample)

//**********************************************************************

//

// CSimpleDoc::Release

//

// Purpose:

//

//      Decrements the document reference count

//

// Parameters:

//

//      None

//

// Return Value:

//

//      UINT    -   The current reference count on the document

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//********************************************************************

STDMETHODIMP_(ULONG) CSimpleDoc::Release()

{

        OutputDebugString("In CSimpleDoc::Release\r\n");

        return SafeRelease();

}


 CSimpleDoc::InsertObject  (SIMPDND Sample)

//**********************************************************************

//

// CSimpleDoc::InsertObject

//

// Purpose:

//

//      Inserts a new object to this document

//

// Parameters:

//

//      None

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                    Location

//

//      CSimpleSite::CSimpleSite    SITE.CPP

//      CSimpleSite::InitObject     SITE.CPP

//      memset                      C Runtime

//      OleUIInsertObject           OUTLUI function

//      CSimpleDoc::DisableInsertObject DOC.CPP

//

// Comments:

//

//      This implementation only allows one object to be inserted

//      into a document.  Once the object has been inserted, then

//      the Insert Object menu choice is greyed out, to prevent

//      the user from inserting another.

//

//********************************************************************

void CSimpleDoc::InsertObject()

{

        OLEUIINSERTOBJECT io;

        CStabilize stabilize(this);

        UINT iret;

        //@@WTK WIN32, UNICODE

        //char szFile[OLEUI_CCHPATHMAX];

        OLECHAR szFile[OLEUI_CCHPATHMAX];

        m_lpSite = CSimpleSite::Create(this);

        // clear the structure

        _fmemset(&io, 0, sizeof(OLEUIINSERTOBJECT));

        // fill the structure

        io.cbStruct = sizeof(OLEUIINSERTOBJECT);

        io.dwFlags = IOF_SELECTCREATENEW |

                                        IOF_DISABLELINK | IOF_DISABLEDISPLAYASICON |

                                        IOF_CREATENEWOBJECT | IOF_CREATEFILEOBJECT;

        io.hWndOwner = m_hDocWnd;

        io.lpszCaption = OLESTR("Insert Object");

        io.iid = IID_IOleObject;

        io.oleRender = OLERENDER_DRAW;

        io.lpIOleClientSite = &m_lpSite->m_OleClientSite;

        io.lpIStorage = m_lpSite->m_lpObjStorage;

        io.ppvObj = (LPVOID FAR *)&m_lpSite->m_lpOleObject;

        io.lpszFile = szFile;

        //@@WTK WIN32, UNICODE

        //io.cchFile = sizeof(szFile);

        io.cchFile = sizeof(szFile) / sizeof *szFile;

        //@@WTK WIN32, UNICODE

        //_fmemset((LPSTR)szFile, 0, sizeof(szFile));

        _fmemset(szFile, 0, sizeof(szFile));

        // call OUTLUI to do all the hard work

        iret = OleUIInsertObject(&io);

        if (iret == OLEUI_OK)

                {

                m_lpSite->InitObject((BOOL)(io.dwFlags & IOF_SELECTCREATENEW));

                // disable Insert Object menu item

                DisableInsertObject();

                }

        else

                {

                m_lpSite->Release();

                m_lpSite = NULL;

                m_lpStorage->Revert();

                }

}


 CSimpleDoc::lResizeDoc  (SIMPDND Sample)

//**********************************************************************

//

// CSimpleDoc::lResizeDoc

//

// Purpose:

//

//      Resizes the document

//

// Parameters:

//

//      LPRECT lpRect   -   The size of the client are of the "frame"

//                          Window.

//

// Return Value:

//

//      NULL

//

// Function Calls:

//      Function                                Location

//

//      MoveWindow                              Windows API

//

// Comments:

//

//********************************************************************

long CSimpleDoc::lResizeDoc(LPRECT lpRect)

{

        MoveWindow(

                        m_hDocWnd,

                        lpRect->left, lpRect->top,

                        lpRect->right, lpRect->bottom, TRUE);

        return NULL;

}


 CSimpleDoc::lAddVerbs  (SIMPDND Sample)

//**********************************************************************

//

// CSimpleDoc::lAddVerbs

//

// Purpose:

//

//      Adds the objects verbs to the edit menu.

//

// Parameters:

//

//      None

//

// Return Value:

//

//      NULL

//

// Function Calls:

//      Function                    Location

//

//      GetMenuItemCount            Windows API

//      OleUIAddVerbMenu            OUTLUI function

//

// Comments:

//

//********************************************************************

long CSimpleDoc::lAddVerbs(void)

{

        CStabilize stabilize(this);

        // m_fModifiedMenu is TRUE if the menu has already been modified

        // once.  Since we only support one obect every time the application

        // is run, then once the menu is modified, it doesn't have

        // to be done again.

        if (m_lpSite && !m_fModifiedMenu)

                {

                int nCount = GetMenuItemCount(m_lpApp->m_hEditMenu);

                OleUIAddVerbMenu ( m_lpSite->m_lpOleObject,

                                                   NULL,

                                                   m_lpApp->m_hEditMenu,

                                                   nCount + 1,

                                                   IDM_VERB0,

                                                   0,           // no maximum verb IDM enforced

                                                   FALSE,

                                                   1,

                                                   &m_lpApp->m_hCascadeMenu);

                m_fModifiedMenu = TRUE;

                }

        return (NULL);

}


 CSimpleDoc::PaintDoc  (SIMPDND Sample)

//**********************************************************************

//

// CSimpleDoc::PaintDoc

//

// Purpose:

//

//      Paints the Document

//

// Parameters:

//

//      HDC hDC -   hDC of the document Window

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                    Location

//

//      CSimpleSite::PaintObj       SITE.CPP

//

// Comments:

//

//********************************************************************

void CSimpleDoc::PaintDoc (HDC hDC)

{

        CStabilize stabilize(this);

        // if we supported multiple objects, then we would enumerate

        // the objects and call paint on each of them from here.

        if (m_lpSite)

                m_lpSite->PaintObj(hDC);

}


 CSimpleDoc::DisableInsertObject  (SIMPDND Sample)

//**********************************************************************

//

// CSimpleDoc::DisableInsertObject

//

// Purpose:

//

//      Disable the ability to insert a new object in this document.

//

// Parameters:

//

//      None

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                    Location

//

//      RevokeDragDrop              OLE API

//      EnableMenuItem              Windows API

//

// Comments:

//

//      This implementation only allows one object to be inserted

//      into a document.  Once the object has been inserted, then

//      the Insert Object menu choice is greyed out, to prevent

//      the user from inserting another. Also we revoke ourself as

//      a potential drop target.

//

//********************************************************************

void CSimpleDoc::DisableInsertObject(void)

{

        // Disable InsertObject menu choice

        EnableMenuItem( m_lpApp->m_hEditMenu, 1, MF_BYPOSITION | MF_DISABLED | MF_GRAYED);

        // Enable Copy menu choice

        EnableMenuItem( m_lpApp->m_hEditMenu, 0, MF_BYPOSITION | MF_ENABLED);

        // We no longer accept dropping of objects

        if (m_fRegDragDrop) {

                RevokeDragDrop(m_hDocWnd);

                m_fRegDragDrop = FALSE;

        }

}


 CSimpleDoc::CopyObjectToClip  (SIMPDND Sample)

//**********************************************************************

//

// CSimpleDoc::CopyObjectToClip

//

// Purpose:

//

//      Copy the embedded OLE object to the clipboard

//

// Parameters:

//

//      None

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                    Location

//

//      CDataXferObj::Create        DXFEROBJ.CPP

//      CDataXferObj::QueryInterface DXFEROBJ.CPP

//      OleSetClipboard             OLE API

//

// Comments:

//

//      This implementation only allows one object to be inserted

//      into a document.  Once the object has been inserted, then

//      the Copy menu choice is enabled.

//

//********************************************************************

void CSimpleDoc::CopyObjectToClip(void)

{

        LPDATAOBJECT lpDataObj;

        // Create a data transfer object by cloning the existing OLE object

        CDataXferObj FAR* pDataXferObj = CDataXferObj::Create(m_lpSite,NULL);

        if (! pDataXferObj) {

                MessageBox(NULL,"Out-of-memory","SimpDnD",MB_SYSTEMMODAL|MB_ICONHAND);

                return;

        }

        // initially obj is created with 0 refcnt. this QI will make it go to 1.

        pDataXferObj->QueryInterface(IID_IDataObject, (LPVOID FAR*)&lpDataObj);

        // put out data transfer object on the clipboard. this API will AddRef.

        OleSetClipboard(lpDataObj);

        // Give ownership of data transfer object to clipboard

        pDataXferObj->Release();

}


 DXFEROBJ.CPP  (SIMPDND Sample)

//**********************************************************************

// File name: DXFEROBJ.CPP

//

//       Implementation file for CDataXferObj, data transfer object

//     implementation of IDataObject interface.

//

// Functions:

//

//      See DXFEROBJ.H for class definition

//

// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#include "pre.h"

//@@WTK WIN32, UNICODE

//#include "..\include\enumfetc.h"

#include <assert.h>

#include "dxferobj.h"

#include "site.h"

CLIPFORMAT g_cfEmbeddedObject = RegisterClipboardFormat(CF_EMBEDDEDOBJECT);

CLIPFORMAT g_cfObjectDescriptor =RegisterClipboardFormat(CF_OBJECTDESCRIPTOR);

// List of formats offered by our data transfer object via EnumFormatEtc

static FORMATETC s_arrGetFmtEtcs[] =

{

{ g_cfEmbeddedObject, NULL, DVASPECT_CONTENT, -1, TYMED_ISTORAGE},

{ g_cfObjectDescriptor, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL},

{ CF_METAFILEPICT, NULL, DVASPECT_CONTENT, -1, TYMED_MFPICT}

};


 CDataXferObj::Create  (SIMPDND Sample)

//**********************************************************************

//

// CDataXferObj::Create

//

// Purpose:

//

//      Creation routine for CDataXferObj

//

// Parameters:

//

//      CSimpleSite FAR *lpSite   - Pointer to source CSimpleSite

//                                  this is the container site of the

//                                  source OLE object to be transfered

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                    Location

//

//      StgCreateDocfile            OLE API

//      assert                      C Runtime

//

// Comments:

//      reference count of CDataXferObj will be 0 on return.

//

//********************************************************************

CDataXferObj FAR * CDataXferObj::Create(

CSimpleSite FAR *lpSite,

POINTL FAR* pPointl

)

{

CDataXferObj FAR * lpTemp = new CDataXferObj();

if (!lpTemp)

return NULL;

// create a sub-storage for the object

HRESULT hErr = StgCreateDocfile(

NULL,

STGM_READWRITE | STGM_DIRECT | STGM_SHARE_EXCLUSIVE |

STGM_DELETEONRELEASE,

0,

&lpTemp->m_lpObjStorage);

assert(hErr == NOERROR);

if (hErr != NOERROR)

{

delete lpTemp;

return NULL;

}

// Clone the source object

if (lpSite->m_lpOleObject) {

// Object is loaded; ask the object to save into the new storage

LPPERSISTSTORAGE pPersistStorage;

lpSite->m_lpOleObject->QueryInterface(IID_IPersistStorage,

(LPVOID FAR*)&pPersistStorage);

assert(pPersistStorage);

OleSave(pPersistStorage, lpTemp->m_lpObjStorage, FALSE);

// pass NULL so that object application won't forget the real stg

pPersistStorage->SaveCompleted(NULL);

pPersistStorage->Release();

} else {

// Object not loaded so use cheaper IStorage CopyTo operation

lpSite->m_lpObjStorage->CopyTo(0, NULL, NULL, lpTemp->m_lpObjStorage);

}

OleLoad(lpTemp->m_lpObjStorage, IID_IOleObject, NULL,

(LPVOID FAR*)&lpTemp->m_lpOleObject);

assert(lpTemp->m_lpOleObject);

lpTemp->m_sizel = lpSite->m_sizel;

if (pPointl)

lpTemp->m_pointl = *pPointl;

else

lpTemp->m_pointl.x = lpTemp->m_pointl.y = 0;

return lpTemp;

}


 CDataXferObj::CDataXferObj  (SIMPDND Sample)

//**********************************************************************

//

// CDataXferObj::CDataXferObj

//

// Purpose:

//

//      Constructor for CDataXferObj

//

// Parameters:

//

//      CSimpleDoc FAR *lpDoc   - Pointer to CSimpleDoc

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                    Location

//

// Comments:

//

//********************************************************************

CDataXferObj::CDataXferObj (void)

{

// clear the reference count

m_nCount = 0;

m_lpObjStorage = NULL;

m_lpOleObject = NULL;

m_sizel.cx = m_sizel.cy = 0;

m_pointl.x = m_pointl.y = 0;

}


 CDataXferObj::~CDataXferObj  (SIMPDND Sample)

//**********************************************************************

//

// CDataXferObj::~CDataXferObj

//

// Purpose:

//

//      Destructor for CDataXferObj

//

// Parameters:

//

//      None

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                                Location

//

//      OutputDebugString                       Windows API

//      IOleObject::Release                     Object

//      IStorage::Release                       OLE API

//

// Comments:

//

//********************************************************************

CDataXferObj::~CDataXferObj ()

{

OutputDebugString ("In CDataXferObj's Destructor \r\n");

if (m_lpOleObject)

   {

   m_lpOleObject->Release();

   m_lpOleObject = NULL;

   // Release the storage for this object

   m_lpObjStorage->Release();

   m_lpObjStorage = NULL;

   }

}


 CDataXferObj::QueryInterface  (SIMPDND Sample)

//**********************************************************************

//

// CDataXferObj::QueryInterface

//

// Purpose:

//

//      Used for interface negotiation of the CDataXferObj instance

//

// Parameters:

//

//      REFIID riid         -   A reference to the interface that is

//                              being queried.

//

//      LPVOID FAR* ppvObj  -   An out parameter to return a pointer to

//                              the interface.

//

// Return Value:

//

//      S_OK            -   The interface is supported.

//      E_NOINTERFACE   -   The interface is not supported

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      IsEqualIID                  OLE API

//      ResultFromScode             OLE API

//      CDataXferObj::AddRef        DXFEROBJ.CPP

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP CDataXferObj::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)

{

OutputDebugString("In CDataXferObj::QueryInterface\r\n");

if ( riid == IID_IUnknown || riid == IID_IDataObject)

{

AddRef();

*ppvObj = this;

return NOERROR;

}

// unknown interface requested

*ppvObj = NULL;     // must set out pointer parameters to NULL

return ResultFromScode(E_NOINTERFACE);

}


 CDataXferObj::AddRef  (SIMPDND Sample)

//**********************************************************************

//

// CDataXferObj::AddRef

//

// Purpose:

//

//      Increments the reference count of the CDataXferObj instance

//

// Parameters:

//

//      None

//

// Return Value:

//

//      ULONG   -   The new reference count of the object

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//********************************************************************

STDMETHODIMP_(ULONG) CDataXferObj::AddRef()

{

OutputDebugString("In CDataXferObj::AddRef\r\n");

return ++m_nCount;

}


 CDataXferObj::Release  (SIMPDND Sample)

//**********************************************************************

//

// CDataXferObj::Release

//

// Purpose:

//

//      Decrements the reference count of the CDataXferObj object

//

// Parameters:

//

//      None

//

// Return Value:

//

//      ULONG   -   The new reference count of the object.

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//********************************************************************

STDMETHODIMP_(ULONG) CDataXferObj::Release()

{

OutputDebugString("In CDataXferObj::Release\r\n");

if (--m_nCount == 0) {

delete this;

return 0;

}

return m_nCount;

}

/********************************************************************

** This IDataObject implementation is used for data transfer.

**

** The following methods are NOT supported for data transfer:

**      IDataObject::SetData    -- return E_NOTIMPL

**      IDataObject::DAdvise    -- return OLE_E_ADVISENOTSUPPORTED

**                 ::DUnadvise

**                 ::EnumDAdvise

**      IDataObject::GetCanonicalFormatEtc -- return E_NOTIMPL

**                      (NOTE: must set pformatetcOut->ptd = NULL)

*********************************************************************/


 CDataXferObj::QueryGetData  (SIMPDND Sample)

//**********************************************************************

//

// CDataXferObj::QueryGetData

//

// Purpose:

//

//      Called to determine if our object supports a particular

//      FORMATETC.

//

// Parameters:

//

//      LPFORMATETC pformatetc  - Pointer to the FORMATETC being queried for.

//

// Return Value:

//

//      DV_E_FORMATETC    - The FORMATETC is not supported

//      S_OK              - The FORMATETC is supported.

//

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      ResultFromScode             OLE API

//

// Comments:

//      we support the following formats:

//          "Embedded Object"

//          "Object Descriptor"

//          CF_METAFILEPICT

//

//********************************************************************

STDMETHODIMP CDataXferObj::QueryGetData (LPFORMATETC pformatetc)

{

SCODE sc = DV_E_FORMATETC;

OutputDebugString("In CDataXferObj::QueryGetData\r\n");

// check the validity of the formatetc.

if ( (pformatetc->cfFormat == g_cfEmbeddedObject) &&

 (pformatetc->dwAspect == DVASPECT_CONTENT) &&

 (pformatetc->tymed == TYMED_ISTORAGE) )

sc = S_OK;

else if ( (pformatetc->cfFormat == g_cfObjectDescriptor) &&

 (pformatetc->dwAspect == DVASPECT_CONTENT) &&

 (pformatetc->tymed == TYMED_HGLOBAL) )

sc = S_OK;

else if ( (pformatetc->cfFormat == CF_METAFILEPICT) &&

 (pformatetc->dwAspect == DVASPECT_CONTENT) &&

 (pformatetc->tymed == TYMED_MFPICT) )

sc = S_OK;

return ResultFromScode(sc);

}

STDMETHODIMP CDataXferObj::EnumFormatEtc(

DWORD dwDirection,

LPENUMFORMATETC FAR* ppenumFormatEtc

)

{

SCODE sc = E_NOTIMPL;

OutputDebugString("In CDataXferObj::EnumFormatEtc\r\n");

*ppenumFormatEtc = NULL;

if (dwDirection == DATADIR_GET) {

*ppenumFormatEtc = OleStdEnumFmtEtc_Create(

sizeof(s_arrGetFmtEtcs)/sizeof(s_arrGetFmtEtcs[0]),

s_arrGetFmtEtcs);

if (*ppenumFormatEtc == NULL)

sc = E_OUTOFMEMORY;

else

sc = S_OK;

}

return ResultFromScode(sc);

}


 CDataXferObj::GetData  (SIMPDND Sample)

//**********************************************************************

//

// CDataXferObj::GetData

//

// Purpose:

//

//      Returns the data in the format specified in pformatetcIn.

//

// Parameters:

//

//      LPFORMATETC pformatetcIn    -   The format requested by the caller

//

//      LPSTGMEDIUM pmedium         -   The medium requested by the caller

//

// Return Value:

//

//      DV_E_FORMATETC    - Format not supported

//      S_OK                - Success

//

// Function Calls:

//      Function                        Location

//

//      OutputDebugString               Windows API

//      OleStdGetOleObjectData          OLE2UI API

//      OleStdGetMetafilePictFromOleObject OLE2UI API

//      ResultFromScode                 OLE API

//

// Comments:

//      we support GetData for the following formats:

//          "Embedded Object"

//          "Object Descriptor"

//          CF_METAFILEPICT

//

//********************************************************************

STDMETHODIMP CDataXferObj::GetData (

LPFORMATETC pformatetcIn,

LPSTGMEDIUM pmedium

)

{

SCODE sc = DV_E_FORMATETC;

OutputDebugString("In CDataXferObj::GetData\r\n");

// we must set all out pointer parameters to NULL. */

pmedium->tymed = TYMED_NULL;

pmedium->pUnkForRelease = NULL;    // we transfer ownership to caller

pmedium->hGlobal = NULL;

// Check the FORMATETC and fill pmedium if valid.

if ( (pformatetcIn->cfFormat == g_cfEmbeddedObject) &&

 (pformatetcIn->dwAspect == DVASPECT_CONTENT) &&

 (pformatetcIn->tymed == TYMED_ISTORAGE) ) {

 LPPERSISTSTORAGE pPersistStorage;

 /* render CF_EMBEDDEDOBJECT by asking the object to save

 **    into a temporary, DELETEONRELEASE IStorage allocated by us.

 */

 m_lpOleObject->QueryInterface(

 IID_IPersistStorage, (LPVOID FAR*)&pPersistStorage);

 assert(pPersistStorage);

 HRESULT hrErr = OleStdGetOleObjectData(

pPersistStorage,

pformatetcIn,

pmedium,

FALSE   /* fUseMemory -- (use file-base stg) */

 );

 pPersistStorage->Release();

 sc = GetScode( hrErr );

} else if ( (pformatetcIn->cfFormat == g_cfObjectDescriptor) &&

 (pformatetcIn->dwAspect == DVASPECT_CONTENT) &&

 (pformatetcIn->tymed == TYMED_HGLOBAL) ) {

 // render CF_OBJECTDESCRIPTOR data

 pmedium->hGlobal = OleStdGetObjectDescriptorDataFromOleObject(

 m_lpOleObject,

 //@@WTK WIN32, UNICODE

 //"Simple OLE 2.0 Container",    // string to identify source

 OLESTR("Simple OLE 2.0 Container"),    // string to identify source

 DVASPECT_CONTENT,

 m_pointl,

 (LPSIZEL)&m_sizel

);

 if (! pmedium->hGlobal)

 sc = E_OUTOFMEMORY;

 else {

 pmedium->tymed = TYMED_HGLOBAL;

 sc = S_OK;

 }

} else if ( (pformatetcIn->cfFormat == CF_METAFILEPICT) &&

 (pformatetcIn->dwAspect == DVASPECT_CONTENT) &&

 (pformatetcIn->tymed == TYMED_MFPICT) ) {

 // render CF_METAFILEPICT by drawing the object into a metafile DC

 pmedium->hGlobal = OleStdGetMetafilePictFromOleObject(

 m_lpOleObject, DVASPECT_CONTENT, NULL, pformatetcIn->ptd);

 if (! pmedium->hGlobal)

 sc = E_OUTOFMEMORY;

 else {

 pmedium->tymed = TYMED_MFPICT;

 sc = S_OK;

 }

}

return ResultFromScode( sc );

}


 CDataXferObj::GetDataHere  (SIMPDND Sample)

//**********************************************************************

//

// CDataXferObj::GetDataHere

//

// Purpose:

//

//      Called to get a data format in a caller supplied location

//

// Parameters:

//

//      LPFORMATETC pformatetc  - FORMATETC requested

//

//      LPSTGMEDIUM pmedium     - Medium to return the data

//

// Return Value:

//

//      DATA_E_FORMATETC    - We don't support the requested format

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      OleStdGetOleObjectData      OLE2UI API

//

// Comments:

//

//********************************************************************

STDMETHODIMP CDataXferObj::GetDataHere (

LPFORMATETC pformatetc,

LPSTGMEDIUM pmedium

)

{

SCODE sc = DV_E_FORMATETC;

OutputDebugString("In CDataXferObj::GetDataHere\r\n");

// NOTE: pmedium is an IN parameter. we should NOT set

//           pmedium->pUnkForRelease to NULL

// Check the FORMATETC and fill pmedium if valid.

if ( (pformatetc->cfFormat == g_cfEmbeddedObject) &&

 (pformatetc->dwAspect == DVASPECT_CONTENT) &&

 (pformatetc->tymed == TYMED_ISTORAGE) ) {

 LPPERSISTSTORAGE pPersistStorage;

 /* render CF_EMBEDDEDOBJECT by asking the object to save

 **    into the IStorage allocated by the caller.

 */

 m_lpOleObject->QueryInterface(

 IID_IPersistStorage, (LPVOID FAR*)&pPersistStorage);

 assert(pPersistStorage);

 HRESULT hrErr = OleStdGetOleObjectData(

 pPersistStorage, pformatetc, pmedium,0 /*fUseMemory--N/A*/ );

 pPersistStorage->Release();

 sc = GetScode( hrErr );

}

return ResultFromScode( sc );

}


 IAS.CPP  (SIMPDND Sample)

//**********************************************************************

// File name: IAS.CPP

//

//      Implementation file of CAdviseSink

//

//

// Functions:

//

//      See IAS.H for Class Definition

//

// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#include "pre.h"

#include "iocs.h"

#include "ias.h"

#include "app.h"

#include "site.h"

#include "doc.h"


 CAdviseSink::QueryInterface  (SIMPDND Sample)

//**********************************************************************

//

// CAdviseSink::QueryInterface

//

// Purpose:

//

//      Returns a pointer to a requested interface.

//

// Parameters:

//

//      REFIID riid         - The requested interface

//

//      LPVOID FAR* ppvObj  - Place to return the interface

//

// Return Value:

//

//      HRESULT from CSimpleSite::QueryInterface

//

// Function Calls:

//      Function                    Location

//

//      CSimpleSite::QueryInterface SITE.CPP

//      OutputDebugString           Windows API

//

// Comments:

//

//      This function simply delegates to the Object class, which is

//      aware of the supported interfaces.

//

//********************************************************************

STDMETHODIMP CAdviseSink::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)

{

OutputDebugString("In IAS::QueryInterface\r\n");

// delegate to the document Object

return m_pSite->QueryInterface(riid, ppvObj);

}


 CAdviseSink::AddRef  (SIMPDND Sample)

//**********************************************************************

//

// CAdviseSink::AddRef

//

// Purpose:

//

//      Increments the reference count on this interface

//

// Parameters:

//

//      None

//

// Return Value:

//

//      The current reference count on this interface.

//

// Function Calls:

//      Function                    Location

//

//      CSimpleSite::AddReff        SITE.CPP

//      OutputDebugString           Windows API

//

// Comments:

//

//      This function adds one to the ref count of the interface,

//      and calls then calls CSimpleSite to increment its ref.

//      count.

//

//********************************************************************

STDMETHODIMP_(ULONG) CAdviseSink::AddRef()

{

OutputDebugString("In IAS::AddRef\r\n");

// increment the interface reference count (for debugging only)

++m_nCount;

// delegate to the container Site

return m_pSite->AddRef();

}


 CAdviseSink::Release  (SIMPDND Sample)

//**********************************************************************

//

// CAdviseSink::Release

//

// Purpose:

//

//      Decrements the reference count on this interface

//

// Parameters:

//

//      None

//

// Return Value:

//

//      The current reference count on this interface.

//

// Function Calls:

//      Function                    Location

//

//      CSimpleSite::Release        SITE.CPP

//      OutputDebugString           Windows API

//

// Comments:

//

//      This function subtracts one from the ref count of the interface,

//      and calls then calls CSimpleSite to decrement its ref.

//      count.

//

//********************************************************************

STDMETHODIMP_(ULONG) CAdviseSink::Release()

{

OutputDebugString("In IAS::Release\r\n");

// decrement the interface reference count (for debugging only)

m_nCount--;

// delegate to the container Site

return m_pSite->Release();

}


 CAdviseSink::OnDataChange  (SIMPDND Sample)

//**********************************************************************

//

// CAdviseSink::OnDataChange

//

// Purpose:

//

//      Not Implemented (needs to be stubbed out)

//

// Parameters:

//

//      Not Implemented (needs to be stubbed out)

//

// Return Value:

//

//      Not Implemented (needs to be stubbed out)

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//      Not Implemented (needs to be stubbed out)

//

//********************************************************************

STDMETHODIMP_(void) CAdviseSink::OnDataChange (FORMATETC FAR* pFormatetc, STGMEDIUM FAR* pStgmed)

{

OutputDebugString("In IAS::OnDataChange\r\n");

}


 CAdviseSink::OnViewChange  (SIMPDND Sample)

//**********************************************************************

//

// CAdviseSink::OnViewChange

//

// Purpose:

//

//      Notifies us that the view has changed and needs to be updated.

//

// Parameters:

//

//      DWORD dwAspect  - Aspect that has changed

//

//      LONG lindex     - Index that has changed

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      InvalidateRect              Windows API

//      IViewObject2::GetExtent     Object

//

// Comments:

//

//********************************************************************

STDMETHODIMP_(void) CAdviseSink::OnViewChange (DWORD dwAspect, LONG lindex)

{

LPVIEWOBJECT2 lpViewObject2;

OutputDebugString("In IAS::OnViewChange\r\n");

// get a pointer to IViewObject2

HRESULT hErr = m_pSite->m_lpOleObject->QueryInterface(

IID_IViewObject2,(LPVOID FAR *)&lpViewObject2);

if (hErr == NOERROR) {

// get extent of the object

// NOTE: this method will never be remoted; it can be called w/i this async method

lpViewObject2->GetExtent(DVASPECT_CONTENT, -1 , NULL, &m_pSite->m_sizel);

lpViewObject2->Release();

}

InvalidateRect(m_pSite->m_lpDoc->m_hDocWnd, NULL, TRUE);

}


 CAdviseSink::OnRename  (SIMPDND Sample)

//**********************************************************************

//

// CAdviseSink::OnRename

//

// Purpose:

//

//      Not Implemented (needs to be stubbed out)

//

// Parameters:

//

//      Not Implemented (needs to be stubbed out)

//

// Return Value:

//

//      Not Implemented (needs to be stubbed out)

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//      Not Implemented (needs to be stubbed out)

//

//********************************************************************

STDMETHODIMP_(void) CAdviseSink::OnRename (LPMONIKER pmk)

{

OutputDebugString("In IAS::OnRename\r\n");

}


 CAdviseSink::OnSave  (SIMPDND Sample)

//**********************************************************************

//

// CAdviseSink::OnSave

//

// Purpose:

//

//      Not Implemented (needs to be stubbed out)

//

// Parameters:

//

//      Not Implemented (needs to be stubbed out)

//

// Return Value:

//

//      Not Implemented (needs to be stubbed out)

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//      Not Implemented (needs to be stubbed out)

//

//********************************************************************

STDMETHODIMP_(void) CAdviseSink::OnSave ()

{

OutputDebugString("In IAS::OnSave\r\n");

}


 CAdviseSink::OnClose  (SIMPDND Sample)

//**********************************************************************

//

// CAdviseSink::OnClose

//

// Purpose:

//

//      Not Implemented (needs to be stubbed out)

//

// Parameters:

//

//      Not Implemented (needs to be stubbed out)

//

// Return Value:

//

//      Not Implemented (needs to be stubbed out)

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//      Not Implemented (needs to be stubbed out)

//

//********************************************************************

STDMETHODIMP_(void) CAdviseSink::OnClose()

{

OutputDebugString("In IAS::OnClose\r\n");

}


 IDS.CPP  (SIMPDND Sample)

//**********************************************************************

// File name: IDS.CPP

//

//      Implementation file for CDropSource

//

// Functions:

//

//      See IDS.H for class definition

//

// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#include "pre.h"

#include "doc.h"

#include "site.h"

#include "dxferobj.h"


 CSimpleDoc::QueryDrag  (SIMPDND Sample)

//**********************************************************************

//

// CSimpleDoc::QueryDrag

//

// Purpose:

//

//      Check to see if Drag operation should be initiated based on the

//      current position of the mouse.

//

// Parameters:

//

//      POINT pt                - position of mouse

//

// Return Value:

//

//      BOOL                    - TRUE if drag should take place,

//                                else FALSE

//

// Function Calls:

//      Function                    Location

//

//      CSimpleSite::GetObjRect     SITE.CPP

//      PtInRect                    Windows API

//

// Comments:

//

//********************************************************************

BOOL CSimpleDoc::QueryDrag(POINT pt)

{

// if pt is within rect of object, then start drag

if (m_lpSite)

{

RECT rect;

m_lpSite->GetObjRect(&rect);

return ( PtInRect(&rect, pt) ? TRUE : FALSE );

}

else

return FALSE;

}


 CSimpleDoc::DoDragDrop  (SIMPDND Sample)

//**********************************************************************

//

// CSimpleDoc::DoDragDrop

//

// Purpose:

//

//      Actually perform a drag/drop operation with the current

//      selection in the source document.

//

// Parameters:

//

//      none.

//

// Return Value:

//

//      DWORD                    - returns the result effect of the

//                                 drag/drop operation:

//                                      DROPEFFECT_NONE,

//                                      DROPEFFECT_COPY,

//                                      DROPEFFECT_MOVE, or

//                                      DROPEFFECT_LINK

//

// Function Calls:

//      Function                    Location

//

//      CDataXferObj::Create        DXFEROBJ.CPP

//      CDataXferObj::QueryInterface DXFEROBJ.CPP

//      CDataXferObj::Release       DXFEROBJ.CPP

//      DoDragDrop                  OLE API

//      OutputDebugString           Windows API

//

// Comments:

//

//********************************************************************

DWORD CSimpleDoc::DoDragDrop (void)

{

DWORD       dwEffect     = 0;

LPDATAOBJECT lpDataObj;

OutputDebugString("In CSimpleDoc::DoDragDrop\r\n");

// Create a data transfer object by cloning the existing OLE object

CDataXferObj FAR* pDataXferObj = CDataXferObj::Create(m_lpSite,NULL);

if (! pDataXferObj) {

MessageBox(NULL,"Out-of-memory","SimpDnD",MB_SYSTEMMODAL|MB_ICONHAND);

return DROPEFFECT_NONE;

}

// initially obj is created with 0 refcnt. this QI will make it go to 1.

pDataXferObj->QueryInterface(IID_IDataObject, (LPVOID FAR*)&lpDataObj);

assert(lpDataObj);

m_fLocalDrop     = FALSE;

m_fLocalDrag     = TRUE;

::DoDragDrop ( lpDataObj,

 &m_DropSource,

 DROPEFFECT_COPY,   // we only allow copy

 &dwEffect

);

m_fLocalDrag     = FALSE;

/* if after the Drag/Drop modal (mouse capture) loop is finished

**    and a drag MOVE operation was performed, then we must delete

**    the selection that was dragged.

*/

if ( (dwEffect & DROPEFFECT_MOVE) != 0 ) {

// ... delete source object here (we do NOT support MOVE)

}

pDataXferObj->Release();    // this should destroy the DataXferObj

return dwEffect;

}


 CDropSource::QueryInterface  (SIMPDND Sample)

//**********************************************************************

//

// CDropSource::QueryInterface

//

// Purpose:

//

//      Return a pointer to a requested interface

//

// Parameters:

//

//      REFIID riid         -   ID of interface to be returned

//      LPVOID FAR* ppvObj  -   Location to return the interface

//

// Return Value:

//

//      S_OK                -   Interface supported

//      E_NOINTERFACE       -   Interface NOT supported

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      CSimpleDoc::QueryInterface  DOC.CPP

//

// Comments:

//

//********************************************************************

STDMETHODIMP CDropSource::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)

{

OutputDebugString("In IDS::QueryInterface\r\n");

// delegate to the document

return m_pDoc->QueryInterface(riid, ppvObj);

}


 CDropSource::AddRef  (SIMPDND Sample)

//**********************************************************************

//

// CDropSource::AddRef

//

// Purpose:

//

//      Increments the reference count on this interface

//

// Parameters:

//

//      None

//

// Return Value:

//

//      The current reference count on this interface.

//

// Function Calls:

//      Function                    Location

//

//      CSimpleObj::AddReff         OBJ.CPP

//      OutputDebugString           Windows API

//

// Comments:

//

//      This function adds one to the ref count of the interface,

//      and calls then calls CSimpleDoc to increment its ref.

//      count.

//

//********************************************************************

STDMETHODIMP_(ULONG) CDropSource::AddRef()

{

OutputDebugString("In IDS::AddRef\r\n");

// increment the interface reference count (for debugging only)

++m_nCount;

// delegate to the document Object

return m_pDoc->AddRef();

}


 CDropSource::Release  (SIMPDND Sample)

//**********************************************************************

//

// CDropSource::Release

//

// Purpose:

//

//      Decrements the reference count on this interface

//

// Parameters:

//

//      None

//

// Return Value:

//

//      The current reference count on this interface.

//

// Function Calls:

//      Function                    Location

//

//      CSimpleObj::Release         OBJ.CPP

//      OutputDebugString           Windows API

//

// Comments:

//

//      This function subtracts one from the ref count of the interface,

//      and calls then calls CSimpleDoc to decrement its ref.

//      count.

//

//********************************************************************

STDMETHODIMP_(ULONG) CDropSource::Release()

{

OutputDebugString("In IDS::Release\r\n");

// decrement the interface reference count (for debugging only)

--m_nCount;

// delegate to the document object

return m_pDoc->Release();

}


 CDropSource::QueryContinueDrag  (SIMPDND Sample)

//**********************************************************************

//

// CDropSource::QueryContinueDrag

//

// Purpose:

//

//      Called to determine if a drop should take place or be canceled.

//

// Parameters:

//

//      BOOL fEscapePressed - TRUE if ESCAPE key has been pressed

//      DWORD grfKeyState   - key state

//

// Return Value:

//

//      DRAGDROP_S_CANCEL   - drag operation should be canceled

//      DRAGDROP_S_DROP     - drop operation should be performed

//      S_OK                - dragging should continue

//

//

// Function Calls:

//      Function                    Location

//

//      ResultFromScode             OLE API

//

// Comments:

//

//********************************************************************

STDMETHODIMP CDropSource::QueryContinueDrag (

BOOL    fEscapePressed,

DWORD   grfKeyState

)

{

if (fEscapePressed)

return ResultFromScode(DRAGDROP_S_CANCEL);

else if (!(grfKeyState & MK_LBUTTON))

return ResultFromScode(DRAGDROP_S_DROP);

else

return NOERROR;

}


 CDropSource::GiveFeedback  (SIMPDND Sample)

//**********************************************************************

//

// CDropSource::GiveFeedback

//

// Purpose:

//

//      Called to set cursor feedback

//

// Parameters:

//

//      DWORD dwEffect      - drop operation to give feedback for

//

// Return Value:

//

//      DRAGDROP_S_USEDEFAULTCURSORS  - tells OLE to use standard cursors

//

// Function Calls:

//      Function                    Location

//

//      ResultFromScode             OLE API

//

// Comments:

//

//********************************************************************

STDMETHODIMP CDropSource::GiveFeedback (DWORD dwEffect)

{

return ResultFromScode(DRAGDROP_S_USEDEFAULTCURSORS);

}


 IDT.CPP  (SIMPDND Sample)

//**********************************************************************

// File name: IDT.CPP

//

//      Implementation file for CDropTarget

//

// Functions:

//

//      See IDT.H for class definition

//

// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#include "pre.h"

#include "iocs.h"

#include "ias.h"

#include "app.h"

#include "site.h"

#include "doc.h"

#include "idt.h"

extern CLIPFORMAT g_cfObjectDescriptor;


 CDropTarget::QueryDrop  (SIMPDND Sample)

//**********************************************************************

//

// CDropTarget::QueryDrop

//

// Purpose:

//

//      Check if the desired drop operation (identified by the given key

//      state) is possible at the current mouse position (pointl).

//

// Parameters:

//

//      DWORD grfKeyState       - current key state

//      POINTL pointl           - position of mouse

//      BOOL fDragScroll        - TRUE if drag scrolling cursor should

//                                be shown.

//      LPDWORD pdwEffect       - (OUT) drag effect that should occur

//

// Return Value:

//

//      BOOL                    - TRUE if drop could take place,

//                                else FALSE

//

// Function Calls:

//      Function                    Location

//

//      OleStdGetDropEffect         OLE2UI API

//

// Comments:

//

//********************************************************************

BOOL CDropTarget::QueryDrop (

DWORD           grfKeyState,

POINTL          pointl,

BOOL            fDragScroll,

LPDWORD         pdwEffect

)

{

DWORD      dwScrollEffect = 0L;

DWORD      dwOKEffects = *pdwEffect;

/* check if the cursor is in the active scroll area, if so need the

**    special scroll cursor.

*/

if (fDragScroll)

dwScrollEffect = DROPEFFECT_SCROLL;

/* if we have already determined that the source does NOT have any

**    acceptable data for us, the return NO-DROP

*/

if (! m_fCanDropCopy && ! m_fCanDropLink)

goto dropeffect_none;

/* OLE2NOTE: determine what type of drop should be performed given

**    the current modifier key state. we rely on the standard

**    interpretation of the modifier keys:

**          no modifier -- DROPEFFECT_MOVE or whatever is allowed by src

**          SHIFT       -- DROPEFFECT_MOVE

**          CTRL        -- DROPEFFECT_COPY

**          CTRL-SHIFT  -- DROPEFFECT_LINK

*/

*pdwEffect = OleStdGetDropEffect(grfKeyState);

if (*pdwEffect == 0) {

// No modifier keys given. Try in order MOVE, COPY, LINK.

if ((DROPEFFECT_MOVE & dwOKEffects) && m_fCanDropCopy)

*pdwEffect = DROPEFFECT_MOVE;

else if ((DROPEFFECT_COPY & dwOKEffects) && m_fCanDropCopy)

*pdwEffect = DROPEFFECT_COPY;

else if ((DROPEFFECT_LINK & dwOKEffects) && m_fCanDropLink)

*pdwEffect = DROPEFFECT_LINK;

else

goto dropeffect_none;

} else {

/* OLE2NOTE: we should check if the drag source application allows

**    the desired drop effect.

*/

if (!(*pdwEffect & dwOKEffects))

goto dropeffect_none;

if ((*pdwEffect == DROPEFFECT_COPY || *pdwEffect == DROPEFFECT_MOVE)

&& ! m_fCanDropCopy)

goto dropeffect_none;

if (*pdwEffect == DROPEFFECT_LINK && ! m_fCanDropLink)

goto dropeffect_none;

}

*pdwEffect |= dwScrollEffect;

return TRUE;

dropeffect_none:

*pdwEffect = DROPEFFECT_NONE;

return FALSE;

}


 CDropTarget::QueryDrop  (SIMPDND Sample)

//**********************************************************************

//

// CDropTarget::QueryDrop

//

// Purpose:

//

//     Check to see if Drag scroll operation should be initiated.

//

// Parameters:

//

//      POINTL pointl           - position of mouse

//

// Return Value:

//

//      BOOL                    - TRUE if scroll cursor should be given

//                                else FALSE

//

// Function Calls:

//      Function                    Location

//

//      ScreenToClient              WINDOWS API

//      GetClientRect               WINDOWS API

//

// Comments:

//     A Drag scroll operation should be initiated when the mouse has

//     remained in the active scroll area (11 pixels frame around border

//     of window) for a specified amount of time (50ms).

//

//********************************************************************

BOOL CDropTarget::DoDragScroll (POINTL pointl)

{

DWORD dwScrollDir = SCROLLDIR_NULL;

DWORD dwTime = GetCurrentTime();

int nScrollInset = m_pDoc->m_lpApp->m_nScrollInset;

int nScrollDelay = m_pDoc->m_lpApp->m_nScrollDelay;

int nScrollInterval = m_pDoc->m_lpApp->m_nScrollInterval;

POINT point;

RECT rect;

point.x = (int)pointl.x;

point.y = (int)pointl.y;

ScreenToClient( m_pDoc->m_hDocWnd, &point);

GetClientRect ( m_pDoc->m_hDocWnd, (LPRECT) &rect );

if (rect.top <= point.y && point.y<=(rect.top+nScrollInset))

dwScrollDir = SCROLLDIR_UP;

else if ((rect.bottom-nScrollInset) <= point.y && point.y <= rect.bottom)

dwScrollDir = SCROLLDIR_DOWN;

else if (rect.left <= point.x && point.x <= (rect.left+nScrollInset))

dwScrollDir = SCROLLDIR_LEFT;

else if ((rect.right-nScrollInset) <= point.x && point.x <= rect.right)

dwScrollDir = SCROLLDIR_RIGHT;

if (m_dwTimeEnterScrollArea) {

/* cursor was already in Scroll Area */

if (! dwScrollDir) {

/* cusor moved OUT of scroll area.

**      clear "EnterScrollArea" time.

*/

m_dwTimeEnterScrollArea = 0L;

m_dwNextScrollTime = 0L;

m_dwLastScrollDir = SCROLLDIR_NULL;

} else if (dwScrollDir != m_dwLastScrollDir) {

/* cusor moved into a different direction scroll area.

**      reset "EnterScrollArea" time to start a new 50ms delay.

*/

m_dwTimeEnterScrollArea = dwTime;

m_dwNextScrollTime = dwTime + (DWORD)nScrollDelay;

m_dwLastScrollDir = dwScrollDir;

} else if (dwTime && dwTime >= m_dwNextScrollTime) {

m_pDoc->Scroll ( dwScrollDir );    // Scroll document now

m_dwNextScrollTime = dwTime + (DWORD)nScrollInterval;

}

} else {

if (dwScrollDir) {

/* cusor moved INTO a scroll area.

**      reset "EnterScrollArea" time to start a new 50ms delay.

*/

m_dwTimeEnterScrollArea = dwTime;

m_dwNextScrollTime = dwTime + (DWORD)nScrollDelay;

m_dwLastScrollDir = dwScrollDir;

}

}

return (dwScrollDir ? TRUE : FALSE);

}

// Support functions/macros

#define SetTopLeft(rc, pt)      \

((rc)->top = (pt)->y,(rc)->left = (pt)->x)

#define SetBottomRight(rc, pt)      \

((rc)->bottom = (pt)->y,(rc)->right = (pt)->x)

#define OffsetPoint(pt, dx, dy)     \

((pt)->x += dx, (pt)->y += dy)

/* HighlightRect

** -------------

**    Invert rectangle on screen. used for drop target feedback.

*/

static int HighlightRect(HWND hwnd, HDC hdc, LPRECT rc)

{

POINT pt1, pt2;

int old = SetROP2(hdc, R2_NOT);

HPEN hpen;

HGDIOBJ hold;

pt1.x = rc->left;

pt1.y = rc->top;

pt2.x = rc->right;

pt2.y = rc->bottom;

ScreenToClient(hwnd, &pt1);

ScreenToClient(hwnd, &pt2);

hold = SelectObject(hdc, GetStockObject(HOLLOW_BRUSH));

hpen = SelectObject(hdc, CreatePen(PS_SOLID, 2,

  GetSysColor(COLOR_ACTIVEBORDER)));

Rectangle(hdc, pt1.x, pt1.y, pt2.x, pt2.y);

SetROP2(hdc, old);

hold = SelectObject(hdc, hold);

hpen = SelectObject(hdc, hpen);

DeleteObject(hpen);

  return 0;

}


 CDropTarget::InitDragFeedback  (SIMPDND Sample)

//**********************************************************************

//

// CDropTarget::InitDragFeedback

//

// Purpose:

//

//      Initialize data used to draw drop target feedback.

//      As feedback we draw a rectangle the size of the object.

//

// Parameters:

//

//      LPDATAOBJECT pDataObj   - IDataObject from Drop source

//      POINTL pointl           - position of mouse

//

// Return Value:

//

//      none.

//

// Function Calls:

//      Function                    Location

//

//      IDataObject::GetData        Object

//      XformSizeInHimetricToPixels OLE2UI Library

//      GlobalLock                  WINDOWS API

//      GlobalUnlock                WINDOWS API

//      ReleaseStgMedium            OLE2 API

//      OffsetPoint                 IDT.CPP

//      SetTopLeft                  IDT.CPP

//      SetBottomRight              IDT.CPP

//

// Comments:

//      In order to known the size of the object before the object

//      is actually dropped, we render CF_OBJECTDESCRIPTOR format.

//      this data format tells us both the size of the object as

//      well as which aspect is the object is displayed as in the

//      source. if the object is currently displayed as DVASPECT_ICON

//      then we want to create the object also as DVASPECT_ICON.

//

//********************************************************************

void CDropTarget::InitDragFeedback(LPDATAOBJECT pDataObj, POINTL pointl)

{

FORMATETC fmtetc;

STGMEDIUM stgmed;

POINT pt;

int height, width;

HRESULT hrErr;

height = width = 100; // some default values

pt.x = (int)pointl.x;

pt.y = (int)pointl.y;

// do a GetData for CF_OBJECTDESCRIPTOR format to get the size of the

// object as displayed in the source. using this size, initialize the

// size for the drag feedback rectangle.

fmtetc.cfFormat = g_cfObjectDescriptor;

fmtetc.ptd = NULL;

fmtetc.lindex = -1;

fmtetc.dwAspect = DVASPECT_CONTENT;

fmtetc.tymed = TYMED_HGLOBAL;

hrErr = pDataObj->GetData(&fmtetc, &stgmed);

if (hrErr == NOERROR) {

LPOBJECTDESCRIPTOR pOD=(LPOBJECTDESCRIPTOR)GlobalLock(stgmed.hGlobal);

if (pOD != NULL) {

XformSizeInHimetricToPixels(NULL, &pOD->sizel, &pOD->sizel);

width = (int)pOD->sizel.cx;

height = (int)pOD->sizel.cy;

m_dwSrcAspect = pOD->dwDrawAspect;

}

GlobalUnlock(stgmed.hGlobal);

ReleaseStgMedium(&stgmed);

}

m_ptLast = pt;

m_fDragFeedbackDrawn = FALSE;

OffsetPoint(&pt, -(width/2), -(height/2));

SetTopLeft(&m_rcDragRect, &pt);

OffsetPoint(&pt, width, height);

SetBottomRight(&m_rcDragRect, &pt);

}


 CDropTarget::UndrawDragFeedback  (SIMPDND Sample)

//**********************************************************************

//

// CDropTarget::UndrawDragFeedback

//

// Purpose:

//

//      Erase any drop target feedback.

//      As feedback we draw a rectangle the size of the object.

//

// Parameters:

//

//      none.

//

// Return Value:

//

//      none.

//

// Function Calls:

//      Function                    Location

//

//      GetDC                       WINDOWS API

//      ReleaseDC                   WINDOWS API

//      GlobalUnlock                WINDOWS API

//      HighlightRect               IDT.CPP

//

// Comments:

//      In order to known the size of the object before the object

//      is actually dropped, we render CF_OBJECTDESCRIPTOR format.

//      this data format tells us both the size of the object as

//      well as which aspect is the object is displayed as in the

//      source. if the object is currently displayed as DVASPECT_ICON

//      then we want to create the object also as DVASPECT_ICON.

//

//********************************************************************

void CDropTarget::UndrawDragFeedback( void )

{

if (m_fDragFeedbackDrawn) {

m_fDragFeedbackDrawn = FALSE;

HDC hDC = GetDC(m_pDoc->m_hDocWnd);

HighlightRect(m_pDoc->m_hDocWnd, hDC, &m_rcDragRect);

ReleaseDC(m_pDoc->m_hDocWnd, hDC);

}

}


 CDropTarget::DrawDragFeedback  (SIMPDND Sample)

//**********************************************************************

//

// CDropTarget::DrawDragFeedback

//

// Purpose:

//

//      Compute new position of drop target feedback rectangle and

//      erase old rectangle and draw new rectangle.

//      As feedback we draw a rectangle the size of the object.

//

// Parameters:

//

//      POINTL pointl           - position of mouse

//

// Return Value:

//

//      none.

//

// Function Calls:

//      Function                    Location

//

//      OffsetPoint                 IDT.CPP

//      HighlightRect               IDT.CPP

//      GetDC                       WINDOWS API

//      ReleaseDC                   WINDOWS API

//

// Comments:

//

//********************************************************************

void CDropTarget::DrawDragFeedback( POINTL pointl )

{

POINT ptDiff;

ptDiff.x = (int)pointl.x - m_ptLast.x;

ptDiff.y = (int)pointl.y - m_ptLast.y;

if (m_fDragFeedbackDrawn && (ptDiff.x == 0 && ptDiff.y == 0))

return;     // mouse did not move; leave rectangle as drawn

HDC hDC = GetDC(m_pDoc->m_hDocWnd);

if (m_fDragFeedbackDrawn) {

m_fDragFeedbackDrawn = FALSE;

HighlightRect(m_pDoc->m_hDocWnd, hDC, &m_rcDragRect);

}

OffsetRect(&m_rcDragRect, ptDiff.x, ptDiff.y);

HighlightRect(m_pDoc->m_hDocWnd, hDC, &m_rcDragRect);

m_fDragFeedbackDrawn = TRUE;

m_ptLast.x = (int)pointl.x;

m_ptLast.y = (int)pointl.y;

ReleaseDC(m_pDoc->m_hDocWnd, hDC);

}


 CDropTarget::QueryInterface  (SIMPDND Sample)

//**********************************************************************

//

// CDropTarget::QueryInterface

//

// Purpose:

//

//      Return a pointer to a requested interface

//

// Parameters:

//

//      REFIID riid         -   ID of interface to be returned

//      LPVOID FAR* ppvObj  -   Location to return the interface

//

// Return Value:

//

//      S_OK                -   Interface supported

//      E_NOINTERFACE       -   Interface NOT supported

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      CSimpleDoc::QueryInterface  DOC.CPP

//

// Comments:

//

//********************************************************************

STDMETHODIMP CDropTarget::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)

{

OutputDebugString("In IDT::QueryInterface\r\n");

// delegate to the document

return m_pDoc->QueryInterface(riid, ppvObj);

}


 CDropTarget::AddRef  (SIMPDND Sample)

//**********************************************************************

//

// CDropTarget::AddRef

//

// Purpose:

//

//      Increments the reference count on this interface

//

// Parameters:

//

//      None

//

// Return Value:

//

//      The current reference count on this interface.

//

// Function Calls:

//      Function                    Location

//

//      CSimpleDoc::AddReff         DOC.CPP

//      OutputDebugString           Windows API

//

// Comments:

//

//      This function adds one to the ref count of the interface,

//      and calls then calls CSimpleObj to increment its ref.

//      count.

//

//********************************************************************

STDMETHODIMP_(ULONG) CDropTarget::AddRef()

{

OutputDebugString("In IDT::AddRef\r\n");

// increment the interface reference count (for debugging only)

++m_nCount;

// delegate to the document Object

return m_pDoc->AddRef();

}


 CDropTarget::Release  (SIMPDND Sample)

//**********************************************************************

//

// CDropTarget::Release

//

// Purpose:

//

//      Decrements the reference count on this interface

//

// Parameters:

//

//      None

//

// Return Value:

//

//      The current reference count on this interface.

//

// Function Calls:

//      Function                    Location

//

//      CSimpleDoc::Release         DOC.CPP

//      OutputDebugString           Windows API

//

// Comments:

//

//      This function subtracts one from the ref count of the interface,

//      and calls then calls CSimpleDoc to decrement its ref.

//      count.

//

//********************************************************************

STDMETHODIMP_(ULONG) CDropTarget::Release()

{

OutputDebugString("In IDT::Release\r\n");

// decrement the interface reference count (for debugging only)

--m_nCount;

// delegate to the document object

return m_pDoc->Release();

}


 CDropTarget::DragEnter  (SIMPDND Sample)

//**********************************************************************

//

// CDropTarget::DragEnter

//

// Purpose:

//

//      Called when the mouse first enters our DropTarget window

//

// Parameters:

//

//      LPDATAOBJECT pDataObj   - IDataObject from Drop source

//      DWORD grfKeyState       - current key state

//      POINTL pointl           - position of mouse

//      LPDWORD pdwEffect       - (IN-OUT) drag effect that should occur

//                                ON INPUT, this is dwOKEffects that source

//                                passed to DoDragDrop API.

//                                ON OUTPUT, this is the effect that we

//                                want to take effect (used to determine

//                                cursor feedback).

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      OleQueryCreateFromData      OLE2 API

//      DoDragScroll                IDT.CPP

//      QueryDrop                   IDT.CPP

//      InitDragFeedback            IDT.CPP

//      DrawDragFeedback            IDT.CPP

//      UndrawDragFeedback          IDT.CPP

//

// Comments:

//      Callee should honor the dwEffects as passed in to determine

//      if the caller allows DROPEFFECT_MOVE.

//

//********************************************************************

STDMETHODIMP CDropTarget::DragEnter (LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pointl, LPDWORD pdwEffect)

{

OutputDebugString("In IDT::DragEnter\r\n");

/* Determine if the drag source data object offers a data format

**  that we understand. we accept only creating embedded objects.

*/

m_fCanDropCopy = ((OleQueryCreateFromData(pDataObj) == NOERROR) ?

TRUE : FALSE);

m_fCanDropLink = FALSE; // linking NOT supported in this simple sample

if (m_fCanDropCopy || m_fCanDropLink)

InitDragFeedback(pDataObj, pointl);

BOOL fDragScroll = DoDragScroll ( pointl );

if (QueryDrop(grfKeyState,pointl,fDragScroll,pdwEffect))

DrawDragFeedback( pointl );

return NOERROR;

}


 CDropTarget::DragOver  (SIMPDND Sample)

//**********************************************************************

//

// CDropTarget::DragOver

//

// Purpose:

//

//      Called when the mouse moves, key state changes, or a time

//      interval passes while the mouse is still within our DropTarget

//      window.

//

// Parameters:

//

//      DWORD grfKeyState       - current key state

//      POINTL pointl           - position of mouse

//      LPDWORD pdwEffect       - (IN-OUT) drag effect that should occur

//                                ON INPUT, this is dwOKEffects that source

//                                passed to DoDragDrop API.

//                                ON OUTPUT, this is the effect that we

//                                want to take effect (used to determine

//                                cursor feedback).

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      DoDragScroll                IDT.CPP

//      QueryDrop                   IDT.CPP

//      DrawDragFeedback            IDT.CPP

//      UndrawDragFeedback          IDT.CPP

//

// Comments:

//      Callee should honor the dwEffects as passed in to determine

//      if the caller allows DROPEFFECT_MOVE. OLE pulses the DragOver

//      calls in order that the DropTarget can implement drag scrolling

//

//********************************************************************

STDMETHODIMP CDropTarget::DragOver  (DWORD grfKeyState, POINTL pointl, LPDWORD pdwEffect)

{

OutputDebugString("In IDT::DragOver\r\n");

BOOL fDragScroll = DoDragScroll ( pointl );

if (QueryDrop(grfKeyState,pointl,fDragScroll,pdwEffect))

DrawDragFeedback( pointl );

else

UndrawDragFeedback();

return NOERROR;

}


 CDropTarget::DragLeave  (SIMPDND Sample)

//**********************************************************************

//

// CDropTarget::DragLeave

//

// Purpose:

//

//      Called when the mouse leaves our DropTarget window

//

// Parameters:

//

//      none.

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      UndrawDragFeedback          IDT.CPP

//      ResultFromScode             OLE2 API

//

// Comments:

//

//********************************************************************

STDMETHODIMP CDropTarget::DragLeave ()

{

OutputDebugString("In IDT::DragLeave\r\n");

UndrawDragFeedback();

return ResultFromScode(S_OK);

}


 CDropTarget::Drop  (SIMPDND Sample)

//**********************************************************************

//

// CDropTarget::Drop

//

// Purpose:

//

//      Called when a Drop operation should take place.

//

// Parameters:

//

//      LPDATAOBJECT pDataObj   - IDataObject from Drop source

//      DWORD grfKeyState       - current key state

//      POINTL pointl           - position of mouse

//      LPDWORD pdwEffect       - (IN-OUT) drag effect that should occur

//                                ON INPUT, this is dwOKEffects that source

//                                passed to DoDragDrop API.

//                                ON OUTPUT, this is the effect that we

//                                want to take effect (used to determine

//                                cursor feedback).

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      CSimpleSite::Create         SITE.CPP

//      CSimpleSite::InitObject     SITE.CPP

//      OleCreateFromData           OLE2 API

//      DoDragScroll                IDT.CPP

//      QueryDrop                   IDT.CPP

//      InitDragFeedback            IDT.CPP

//      DrawDragFeedback            IDT.CPP

//      UndrawDragFeedback          IDT.CPP

//      GetScode                    OLE2 API

//      ResultFromScode             OLE2 API

//

// Comments:

//      Callee should honor the dwEffects as passed in to determine

//      if the caller allows DROPEFFECT_MOVE.

//

//********************************************************************

STDMETHODIMP CDropTarget::Drop (LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pointl, LPDWORD pdwEffect)

{

FORMATETC fmtetc;

SCODE sc = S_OK;

OutputDebugString("In IDT::Drop\r\n");

UndrawDragFeedback();

if (pDataObj && QueryDrop(grfKeyState,pointl,FALSE,pdwEffect))

{

m_pDoc->m_lpSite = CSimpleSite::Create(m_pDoc);

// keep same aspect as drop source

m_pDoc->m_lpSite->m_dwDrawAspect = m_dwSrcAspect;

// in order to specify a particular drawing Aspect we must

// pass a FORMATETC* to OleCreateFromData

fmtetc.cfFormat = NULL;             // use whatever for drawing

fmtetc.ptd = NULL;

fmtetc.lindex = -1;

fmtetc.dwAspect = m_dwSrcAspect;    // desired drawing aspect

fmtetc.tymed = TYMED_NULL;

HRESULT hrErr = OleCreateFromData (

pDataObj,

IID_IOleObject,

OLERENDER_DRAW,

&fmtetc,

&m_pDoc->m_lpSite->m_OleClientSite,

m_pDoc->m_lpSite->m_lpObjStorage,

(LPVOID FAR *)&m_pDoc->m_lpSite->m_lpOleObject);

if (hrErr == NOERROR)

{

m_pDoc->m_lpSite->InitObject(FALSE /* fCreateNew */);

m_pDoc->DisableInsertObject();

}

else

sc = GetScode(hrErr);

}

return ResultFromScode(sc);

}


 IOCS.CPP  (SIMPDND Sample)

//**********************************************************************

// File name: IOCS.CPP

//

//      Implementation file for COleClientSite

//

// Functions:

//

//      See IOCS.H for class definition

//

// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#include "pre.h"

#include "iocs.h"

#include "ias.h"

#include "app.h"

#include "site.h"

#include "doc.h"


 COleClientSite::QueryInterface  (SIMPDND Sample)

//**********************************************************************

//

// COleClientSite::QueryInterface

//

// Purpose:

//

//      Used for interface negotiation at this interface

//

// Parameters:

//

//      REFIID riid         -   A reference to the interface that is

//                              being queried.

//

//      LPVOID FAR* ppvObj  -   An out parameter to return a pointer to

//                              the interface.

//

// Return Value:

//

//      S_OK                -   The interface is supported.

//      E_NOINTERFACE       -   The interface is not supported

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      CSimpleSite::QueryInterface SITE.CPP

//

// Comments:

//

//********************************************************************

STDMETHODIMP COleClientSite::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)

{

OutputDebugString("In IOCS::QueryInterface\r\n");

// delegate to the container Site

return m_pSite->QueryInterface(riid, ppvObj);

}


 CSimpleApp::AddRef  (SIMPDND Sample)

//**********************************************************************

//

// CSimpleApp::AddRef

//

// Purpose:

//

//      Adds to the reference count at the interface level.

//

// Parameters:

//

//      None

//

// Return Value:

//

//      ULONG   -   The new reference count of the interface

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//********************************************************************

STDMETHODIMP_(ULONG) COleClientSite::AddRef()

{

OutputDebugString("In IOCS::AddRef\r\n");

// increment the interface reference count (for debugging only)

++m_nCount;

// delegate to the container Site

return m_pSite->AddRef();

}


 CSimpleApp::Release  (SIMPDND Sample)

//**********************************************************************

//

// CSimpleApp::Release

//

// Purpose:

//

//      Decrements the reference count at this level

//

// Parameters:

//

//      None

//

// Return Value:

//

//      ULONG   -   The new reference count of the interface.

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//********************************************************************

STDMETHODIMP_(ULONG) COleClientSite::Release()

{

OutputDebugString("In IOCS::Release\r\n");

// decrement the interface reference count (for debugging only)

--m_nCount;

// delegate to the container Site

return m_pSite->Release();

}


 COleClientSite::SaveObject  (SIMPDND Sample)

//**********************************************************************

//

// COleClientSite::SaveObject

//

// Purpose:

//

//      Called by the object when it wants to be saved to persistant

//      storage

//

// Parameters:

//

//      None

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                            Location

//

//      OutputDebugString                   Windows API

//      IOleObject::QueryInterface          Object

//      IPersistStorage::SaveCompleted      Object

//      IPersistStorage::Release            Object

//      OleSave                             OLE API

//      ResultFromScode                     OLE API

//

// Comments:

//

//********************************************************************

STDMETHODIMP COleClientSite::SaveObject()

{

LPPERSISTSTORAGE lpPS;

SCODE sc = E_FAIL;

OutputDebugString("In IOCS::SaveObject\r\n");

// get a pointer to IPersistStorage

HRESULT hErr = m_pSite->m_lpOleObject->QueryInterface(IID_IPersistStorage, (LPVOID FAR *)&lpPS);

// save the object

if (hErr == NOERROR)

{

sc = GetScode( OleSave(lpPS, m_pSite->m_lpObjStorage, TRUE) );

lpPS->SaveCompleted(NULL);

lpPS->Release();

}

return ResultFromScode(sc);

}


 COleClientSite::GetMoniker  (SIMPDND Sample)

//**********************************************************************

//

// COleClientSite::GetMoniker

//

// Purpose:

//

//      Not Implemented

//

// Parameters:

//

//      Not Implemented

//

// Return Value:

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//      This function is not implemented because we don't support

//      linking.

//

//********************************************************************

STDMETHODIMP COleClientSite::GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker, LPMONIKER FAR* ppmk)

{

OutputDebugString("In IOCS::GetMoniker\r\n");

// need to null the out pointer

*ppmk = NULL;

return ResultFromScode(E_NOTIMPL);

}


 COleClientSite::GetContainer  (SIMPDND Sample)

//**********************************************************************

//

// COleClientSite::GetContainer

//

// Purpose:

//

//      Not Implemented

//

// Parameters:

//

//      Not Implemented

//

// Return Value:

//

//      Not Implemented

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//      Not Implemented

//

//********************************************************************

STDMETHODIMP COleClientSite::GetContainer(LPOLECONTAINER FAR* ppContainer)

{

OutputDebugString("In IOCS::GetContainer\r\n");

// NULL the out pointer

*ppContainer = NULL;

return ResultFromScode(E_NOTIMPL);

}


 COleClientSite::ShowObject  (SIMPDND Sample)

//**********************************************************************

//

// COleClientSite::ShowObject

//

// Purpose:

//

//      Not Implemented

//

// Parameters:

//

//      Not Implemented

//

// Return Value:

//

//      Not Implemented

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//      This function is not implemented because we don't support

//      linking.

//

//********************************************************************

STDMETHODIMP COleClientSite::ShowObject()

{

OutputDebugString("In IOCS::ShowObject\r\n");

return NOERROR;

}


 COleClientSite::OnShowWindow  (SIMPDND Sample)

//**********************************************************************

//

// COleClientSite::OnShowWindow

//

// Purpose:

//

//      Object calls this method when it is opening/closing non-InPlace

//      Window

//

// Parameters:

//

//      BOOL fShow  - TRUE if Window is opening, FALSE if closing

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      InvalidateRect              Windows API

//      ResultFromScode             OLE API

//

// Comments:

//

//********************************************************************

STDMETHODIMP COleClientSite::OnShowWindow(BOOL fShow)

{

OutputDebugString("In IOCS::OnShowWindow\r\n");

m_pSite->m_fObjectOpen = fShow;

InvalidateRect(m_pSite->m_lpDoc->m_hDocWnd, NULL, TRUE);

// if object window is closing, then bring container window to top

if (! fShow) {

BringWindowToTop(m_pSite->m_lpDoc->m_hDocWnd);

SetFocus(m_pSite->m_lpDoc->m_hDocWnd);

}

return ResultFromScode(S_OK);

}


 COleClientSite::RequestNewObjectLayout  (SIMPDND Sample)

//**********************************************************************

//

// COleClientSite::RequestNewObjectLayout

//

// Purpose:

//

//      Not Implemented

//

// Parameters:

//

//      Not Implemented

//

// Return Value:

//

//      Not Implemented

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//      Not Implemented

//

//********************************************************************

STDMETHODIMP COleClientSite::RequestNewObjectLayout()

{

OutputDebugString("In IOCS::RequestNewObjectLayout\r\n");

return ResultFromScode(E_NOTIMPL);

}


 SIMPDND.CPP  (SIMPDND Sample)

//**********************************************************************

// File name: Simple.cpp

//

//      Main source file for the Simple OLE 2.0 object container

//

// Functions:

//

//      WinMain         - Program entry point

//      MainWndProc     - Processes messages for the frame window

//      About           - Processes messages for the about dialog

//      DocWndProc      - Processes messages for the doc window

//

// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#include "pre.h"

#include "iocs.h"

#include "ias.h"

#include "app.h"

#include "site.h"

#include "doc.h"

// This line is needed for the debug utilities in OLE2UI

extern "C" {

        OLEDBGDATA_MAIN("SIMPDND")

}

CSimpleApp FAR * lpCSimpleApp;


 WinMain  (SIMPDND Sample)

//**********************************************************************

//

// WinMain

//

// Purpose:

//

//      Program entry point

//

// Parameters:

//

//      HANDLE hInstance        - Instance handle for this instance

//

//      HANDLE hPrevInstance    - Instance handle for the last instance

//

//      LPSTR lpCmdLine         - Pointer to the command line

//

//      int nCmdShow            - Window State

//

// Return Value:

//

//      msg.wParam

//

// Function Calls:

//      Function                        Location

//

//      CSimpleApp::CSimpleApp          APP.CPP

//      CSimpleApp::fInitApplication    APP.CPP

//      CSimpleApp::fInitInstance       APP.CPP

//      CSimpleApp::HandleAccelerators  APP.CPP

//      CSimpleApp::~CSimpleApp         APP.CPP

//      OleUIInitialize                 OLE2UI

//      OleUIUninitialize               OLE2UI

//      GetMessage                      Windows API

//      TranslateMessage                Windows API

//      DispatchMessage                 Windows API

//

// Comments:

//

//********************************************************************

int PASCAL WinMain(HANDLE hInstance,HANDLE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)

{

        MSG msg;

        // needed for LRPC to work properly...

        SetMessageQueue(96);

        lpCSimpleApp = new CSimpleApp;

        // we will add one ref count on our App. later when we want to destroy

        // the App object we will release this  ref count. when the App's ref

        // count goes to 0, it will be deleted.

        lpCSimpleApp->AddRef();

        // app initialization

        if (!hPrevInstance)

                if (!lpCSimpleApp->fInitApplication(hInstance))

                        return (FALSE);

        // instance initialization

        if (!lpCSimpleApp->fInitInstance(hInstance, nCmdShow))

                return (FALSE);

        /* Initialization required for OLE 2 UI library.  This call is

        **    needed ONLY if we are using the static link version of the UI

        **    library. If we are using the DLL version, we should NOT call

        **    this function in our application.

        */

#if 0

        if (!OleUIInitialize(hInstance, hPrevInstance))

                {

                OleDbgOut("Could not initialize OLEUI library\n");

                return FALSE;

                }

#endif

        // message loop

        while (GetMessage(&msg, NULL, NULL, NULL))

                if (!lpCSimpleApp->HandleAccelerators(&msg))

                        {

                        TranslateMessage(&msg);    /* Translates virtual key codes */

                        DispatchMessage(&msg);     /* Dispatches message to window */

                        }

        // De-initialization for UI libraries.  Just like OleUIInitialize, this

        // funciton is needed ONLY if we are using the static link version of the

        // OLE UI library.

#if 0

        OleUIUninitialize();

#endif

        // Release the ref count added on the App above. this will make

        // the App's ref count go to 0, and the App object will be deleted.

        lpCSimpleApp->Release();

        return (msg.wParam);          /* Returns the value from PostQuitMessage */

}


 MainWndProc  (SIMPDND Sample)

//**********************************************************************

//

// MainWndProc

//

// Purpose:

//

//      Processes messages for the frame window

//

// Parameters:

//

//      HWND hWnd       - Window handle for frame window

//

//      UINT message    - Message value

//

//      WPARAM wParam   - Message info

//

//      LPARAM lParam   - Message info

//

// Return Value:

//

//      long

//

// Function Calls:

//      Function                        Location

//

//      CSimpleApp::lCommandHandler     APP.CPP

//      CSimpleApp::DestroyDocs         APP.CPP

//      CSimpleApp::lCreateDoc          APP.CPP

//      CSimpleApp::lSizeHandler        APP.CPP

//      CSimpleDoc::lAddVerbs           DOC.CPP

//      PostQuitMessage                 Windows API

//      DefWindowProc                   Windows API

//

// Comments:

//

//********************************************************************

//@@WTK WIN32, UNICODE

//long FAR PASCAL _export MainWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)

long FAR PASCAL EXPORT MainWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)

{

        switch (message)

                {

                case WM_COMMAND:           // message: command from application menu

                        return lpCSimpleApp->lCommandHandler(hWnd, message, wParam, lParam);

                        break;

                case WM_CREATE:

                        return lpCSimpleApp->lCreateDoc(hWnd, message, wParam, lParam);

                        break;

                case WM_DESTROY:                  // message: window being destroyed

                        lpCSimpleApp->DestroyDocs();  // need to destroy the doc...

                        PostQuitMessage(0);

                        break;

                case WM_INITMENUPOPUP:

                        // is this the edit menu?

                        if ( LOWORD(lParam) == 1)

                                return lpCSimpleApp->m_lpDoc->lAddVerbs();

                        break;

                case WM_SIZE:

                        return lpCSimpleApp->lSizeHandler(hWnd, message, wParam, lParam);

                default:                          // Passes it on if unproccessed

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

                }

                return (NULL);

}


 About  (SIMPDND Sample)

//**********************************************************************

//

// About

//

// Purpose:

//

//      Processes dialog box messages

//

// Parameters:

//

//      HWND hWnd       - Window handle for dialog box

//

//      UINT message    - Message value

//

//      WPARAM wParam   - Message info

//

//      LPARAM lParam   - Message info

//

// Return Value:

//

// Function Calls:

//      Function                    Location

//

//      EndDialog                   Windows API

//

// Comments:

//

//********************************************************************

//@@WTK WIN32, UNICODE

//BOOL FAR PASCAL _export About(HWND hDlg,unsigned message,WORD wParam,LONG lParam)

BOOL FAR PASCAL EXPORT About(HWND hDlg,UINT message,WPARAM wParam,LPARAM lParam)

{

        switch (message) {

        case WM_INITDIALOG:                /* message: initialize dialog box */

                return (TRUE);

        case WM_COMMAND:                      /* message: received a command */

                //@@WTK WIN32, UNICODE

                //if (wParam == IDOK                /* "OK" box selected?          */

                if (LOWORD(wParam) == IDOK                /* "OK" box selected?          */

                //@@WTK WIN32, UNICODE

                //|| wParam == IDCANCEL) {      /* System menu close command? */

                || LOWORD(wParam) == IDCANCEL) {      /* System menu close command? */

                EndDialog(hDlg, TRUE);        /* Exits the dialog box        */

                return (TRUE);

                }

                break;

        }

        return (FALSE);                           /* Didn't process a message    */

}


 DocWndProc  (SIMPDND Sample)

//**********************************************************************

//

// DocWndProc

//

// Purpose:

//

//      Processes dialog box messages

//

// Parameters:

//

//      HWND hWnd       - Window handle for doc window

//

//      UINT message    - Message value

//

//      WPARAM wParam   - Message info

//

//      LPARAM lParam   - Message info

//

// Return Value:

//

// Function Calls:

//      Function                            Location

//

//      CSimpleApp::PaintApp                APP.CPP

//      BeginPaint                          Windows API

//      EndPaint                            Windows API

//      DefWindowProc                       Windows API

//      IOleObject::QueryInterface          Object

//      IOleObject::DoVerb                  Object

//      CSimpleSite::GetObjRect             SITE.CPP

//      CSimpleDoc::QueryDrag               DOC.CPP

//      CSimpleDoc::DoDragDrop              DOC.CPP

//      SetTimer                            Windows API

//      KillTimer                           Windows API

//      SetCapture                          Windows API

//      ReleaseCapture                      Windows API

//

// Comments:

//

//********************************************************************

//@@WTK WIN32, UNICODE

//long FAR PASCAL _export DocWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)

long FAR PASCAL EXPORT DocWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)

{

        HDC hDC;

        PAINTSTRUCT ps;

        switch (message) {

                case WM_PAINT:

                        hDC = BeginPaint(hWnd, &ps);

                        if (lpCSimpleApp)

                                lpCSimpleApp->PaintApp (hDC);

                        EndPaint(hWnd, &ps);

                        break;

                case WM_LBUTTONDBLCLK:

                        {

                        POINT pt;

                        pt.x = (int)(short)LOWORD (lParam );

                        pt.y = (int)(short)HIWORD (lParam );

                        if (lpCSimpleApp->m_lpDoc->m_lpSite &&

                                lpCSimpleApp->m_lpDoc->m_lpSite->m_lpOleObject)

                                {

                                RECT rect;

                                lpCSimpleApp->m_lpDoc->m_lpSite->GetObjRect(&rect);

                                if ( PtInRect(&rect, pt) )

                                        {

                                        // Execute object's default verb

                                        lpCSimpleApp->m_lpDoc->m_lpSite->m_lpOleObject->DoVerb(

                                                        OLEIVERB_PRIMARY, (LPMSG)&message,

                                                        &lpCSimpleApp->m_lpDoc->m_lpSite->m_OleClientSite,

                                                        -1, hWnd, &rect);

                                        }

                                }

                        }

                        break;

                case WM_LBUTTONDOWN:

                        {

                        POINT pt;

                        pt.x = (int)(short)LOWORD (lParam );

                        pt.y = (int)(short)HIWORD (lParam );

                        /* OLE2NOTE: check if this is a button down on the region

                        **    that is a handle to start a drag operation. for us,

                        **    this this is any where in the window. we

                        **    do NOT want to start a drag immediately; we want to

                        **    wait until the mouse moves a certain threshold. or a

                        **    certain amount of time has elapsed. if

                        **    LButtonUp comes before the drag is started, then

                        **    the fPendingDrag state is cleared. we must capture

                        **    the mouse to ensure the modal state is handled

                        **    properly.

                        */

                        if (lpCSimpleApp->m_lpDoc->QueryDrag(pt) )

                                {

                                lpCSimpleApp->m_lpDoc->m_fPendingDrag = TRUE;

                                lpCSimpleApp->m_lpDoc->m_ptButDown = pt;

                                SetTimer(hWnd, 1, lpCSimpleApp->m_nDragDelay, NULL);

                                SetCapture(hWnd);

                                }

                        break;

                        }

                case WM_LBUTTONUP:

                        if (lpCSimpleApp->m_lpDoc->m_fPendingDrag)

                                {

                                /* ButtonUP came BEFORE distance/time threshholds were

                                **    exceeded. clear fPendingDrag state.

                                */

                                ReleaseCapture();

                                KillTimer(hWnd, 1);

                                lpCSimpleApp->m_lpDoc->m_fPendingDrag = FALSE;

                                }

                        break;

                case WM_MOUSEMOVE:

                        {

                        if (lpCSimpleApp->m_lpDoc->m_fPendingDrag)

                                {

                                int  x = (int)(short)LOWORD (lParam );

                                int  y = (int)(short)HIWORD (lParam );

                                POINT pt = lpCSimpleApp->m_lpDoc->m_ptButDown;

                                int nDragMinDist = lpCSimpleApp->m_nDragMinDist;

                                if (! ( ((pt.x - nDragMinDist) <= x)

                                                && (x <= (pt.x + nDragMinDist))

                                                && ((pt.y - nDragMinDist) <= y)

                                                && (y <= (pt.y + nDragMinDist)) ) )

                                        {

                                        // mouse moved beyond threshhold to start drag

                                        ReleaseCapture();

                                        KillTimer(hWnd, 1);

                                        lpCSimpleApp->m_lpDoc->m_fPendingDrag = FALSE;

                                        // perform the modal drag/drop operation.

                                        lpCSimpleApp->m_lpDoc->DoDragDrop( );

                                        }

                                }

                        break;

                        }

                case WM_TIMER:

                        {

                        // drag time delay threshhold exceeded -- start drag

                        ReleaseCapture();

                        KillTimer(hWnd, 1);

                        lpCSimpleApp->m_lpDoc->m_fPendingDrag = FALSE;

                        // perform the modal drag/drop operation.

                        lpCSimpleApp->m_lpDoc->DoDragDrop( );

                        break;

                        }

                default:                          /* Passes it on if unproccessed */

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

        }

        return (NULL);

}


 SITE.CPP  (SIMPDND Sample)

//**********************************************************************

// File name: SITE.CPP

//

//      Implementation file for CSimpleSite

//

// Functions:

//

//      See SITE.H for class definition

//

// Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#include "pre.h"

#include "iocs.h"

#include "ias.h"

#include "app.h"

#include "site.h"

#include "doc.h"


 CSimpleSite::Create  (SIMPDND Sample)

//**********************************************************************

//

// CSimpleSite::Create

//

// Purpose:

//

//      Creation routine for CSimpleSite

//

// Parameters:

//

//      CSimpleDoc FAR *lpDoc   - Pointer to CSimpleDoc

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                    Location

//

//      IStorage::CreateStorage     OLE API

//      assert                      C Runtime

//

// Comments:

//

//********************************************************************

CSimpleSite FAR * CSimpleSite::Create(CSimpleDoc FAR *lpDoc)

{

CSimpleSite FAR * lpTemp = new CSimpleSite(lpDoc);

if (!lpTemp)

return NULL;

// create a sub-storage for the object

//@@WTK WIN32, UNICODE

//HRESULT hErr = lpDoc->m_lpStorage->CreateStorage( "Object",

HRESULT hErr = lpDoc->m_lpStorage->CreateStorage( OLESTR("Object"),

STGM_READWRITE | STGM_TRANSACTED | STGM_SHARE_EXCLUSIVE,

0,

0,

&lpTemp->m_lpObjStorage);

assert(hErr == NOERROR);

if (hErr != NOERROR)

{

delete lpTemp;

return NULL;

}

// we will add one ref count on our Site. later when we want to destroy

// the Site object we will release this  ref count. when the Site's ref

// count goes to 0, it will be deleted.

lpTemp->AddRef();

return lpTemp;

}


 CSimpleSite::CSimpleSite  (SIMPDND Sample)

//**********************************************************************

//

// CSimpleSite::CSimpleSite

//

// Purpose:

//

//      Constructor for CSimpleSite

//

// Parameters:

//

//      CSimpleDoc FAR *lpDoc   - Pointer to CSimpleDoc

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                    Location

//

// Comments:

//

//********************************************************************

#pragma warning(disable : 4355)  // turn off this warning.  This warning

// tells us that we are passing this in

// an initializer, before "this" is through

// initializing.  This is ok, because

// we just store the ptr in the other

// constructors

CSimpleSite::CSimpleSite (CSimpleDoc FAR *lpDoc) : m_OleClientSite(this),

 m_AdviseSink(this)

#pragma warning (default : 4355)  // Turn the warning back on

{

// remember the pointer to the doc

m_lpDoc = lpDoc;

// clear the reference count

m_nCount = 0;

m_dwDrawAspect = DVASPECT_CONTENT;

m_lpOleObject = NULL;

m_fObjectOpen = FALSE;

}


 CSimpleSite::~CSimpleSite  (SIMPDND Sample)

//**********************************************************************

//

// CSimpleSite::~CSimpleSite

//

// Purpose:

//

//      Destructor for CSimpleSite

//

// Parameters:

//

//      None

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                                Location

//

//      OutputDebugString                       Windows API

//      IOleObject::Release                     Object

//      IStorage::Release                       OLE API

//

// Comments:

//

//********************************************************************

CSimpleSite::~CSimpleSite ()

{

OutputDebugString ("In CSimpleSite's Destructor \r\n");

if (m_lpOleObject)

   m_lpOleObject->Release();

if (m_lpObjStorage)

   m_lpObjStorage->Release();

}


 CSimpleSite::CloseOleObject  (SIMPDND Sample)

//**********************************************************************

//

// CSimpleSite::CloseOleObject

//

// Purpose:

//

//      Call IOleObject::Close on the object of the CSimpleSite

//

// Parameters:

//

//      None

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                                Location

//

//      OutputDebugString                       Windows API

//      IOleObject::Close                       Object

//

// Comments:

//

//********************************************************************

void CSimpleSite::CloseOleObject (void)

{

LPVIEWOBJECT lpViewObject = NULL;

OutputDebugString ("In CSimpleSite::CloseOleObject \r\n");

if (m_lpOleObject)

   {

   m_lpOleObject->Close(OLECLOSE_NOSAVE);

   }

}


 CSimpleSite::UnloadOleObject  (SIMPDND Sample)

//**********************************************************************

//

// CSimpleSite::UnloadOleObject

//

// Purpose:

//

//      Close and release all pointers to the object of the CSimpleSite

//

// Parameters:

//

//      None

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                                Location

//

//      OutputDebugString                       Windows API

//      CSimpleSite::CloseOleObject             SITE.CPP

//      IOleObject::QueryInterface              Object

//      IViewObject::SetAdvise                  Object

//      IViewObject::Release                    Object

//      IStorage::Release                       OLE API

//

// Comments:

//

//********************************************************************

void CSimpleSite::UnloadOleObject (void)

{

OutputDebugString ("In CSimpleSite::UnloadOleObject \r\n");

if (m_lpOleObject)

   {

   LPVIEWOBJECT lpViewObject;

   CloseOleObject();    // ensure object is closed; NOP if already closed

   m_lpOleObject->QueryInterface(IID_IViewObject, (LPVOID FAR *)&lpViewObject);

   if (lpViewObject)

   {

   // Remove the view advise

   lpViewObject->SetAdvise(m_dwDrawAspect, 0, NULL);

   lpViewObject->Release();

   }

   m_lpOleObject->Release();

   m_lpOleObject = NULL;

   }

}


 CSimpleSite::QueryInterface  (SIMPDND Sample)

//**********************************************************************

//

// CSimpleSite::QueryInterface

//

// Purpose:

//

//      Used for interface negotiation of the container Site.

//

// Parameters:

//

//      REFIID riid         -   A reference to the interface that is

//                              being queried.

//

//      LPVOID FAR* ppvObj  -   An out parameter to return a pointer to

//                              the interface.

//

// Return Value:

//

//      S_OK    -   The interface is supported.

//      S_FALSE -   The interface is not supported

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      IsEqualIID                  OLE API

//      ResultFromScode             OLE API

//      CSimpleSite::AddRef          OBJ.CPP

//      COleClientSite::AddRef      IOCS.CPP

//      CAdviseSink::AddRef         IAS.CPP

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP CSimpleSite::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)

{

OutputDebugString("In CSimpleSite::QueryInterface\r\n");

*ppvObj = NULL;     // must set out pointer parameters to NULL

if ( riid == IID_IUnknown)

{

AddRef();

*ppvObj = this;

return ResultFromScode(S_OK);

}

if ( riid == IID_IOleClientSite)

{

m_OleClientSite.AddRef();

*ppvObj = &m_OleClientSite;

return ResultFromScode(S_OK);

}

if ( riid == IID_IAdviseSink)

{

m_AdviseSink.AddRef();

*ppvObj = &m_AdviseSink;

return ResultFromScode(S_OK);

}

// Not a supported interface

return ResultFromScode(E_NOINTERFACE);

}


 CSimpleSite::AddRef  (SIMPDND Sample)

//**********************************************************************

//

// CSimpleSite::AddRef

//

// Purpose:

//

//      Increments the reference count of the container Site.

//

// Parameters:

//

//      None

//

// Return Value:

//

//      ULONG   -   The new reference count of the site.

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//********************************************************************

STDMETHODIMP_(ULONG) CSimpleSite::AddRef()

{

OutputDebugString("In CSimpleSite::AddRef\r\n");

return ++m_nCount;

}


 CSimpleSite::Release  (SIMPDND Sample)

//**********************************************************************

//

// CSimpleSite::Release

//

// Purpose:

//

//      Decrements the reference count of the container Site

//

// Parameters:

//

//      None

//

// Return Value:

//

//      ULONG   -   The new reference count of the Site.

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//********************************************************************

STDMETHODIMP_(ULONG) CSimpleSite::Release()

{

OutputDebugString("In CSimpleSite::Release\r\n");

if (--m_nCount == 0) {

delete this;

return 0;

}

return m_nCount;

}


 CSimpleSite::InitObject  (SIMPDND Sample)

//**********************************************************************

//

// CSimpleSite::InitObject

//

// Purpose:

//

//      Used to initialize a newly create object (can't be done in the

//      constructor).

//

// Parameters:

//

//      BOOL fCreateNew -   TRUE if insert NEW object

//                          FALSE if create object FROM FILE

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                        Location

//

//      IOleObject::SetHostNames        Object

//      IOleObject::QueryInterface      Object

//      IViewObject2::GetExtent         Object

//      IOleObject::DoVerb              Object

//      IViewObject::SetAdvise          Object

//      IViewObject::Release            Object

//      GetClientRect                   Windows API

//      OleSetContainedObject           OLE API

//

// Comments:

//

//********************************************************************

void CSimpleSite::InitObject(BOOL fCreateNew)

{

LPVIEWOBJECT2 lpViewObject2;

RECT rect;

// Set a View Advise

m_lpOleObject->QueryInterface(IID_IViewObject2,(LPVOID FAR *)&lpViewObject2);

lpViewObject2->SetAdvise(m_dwDrawAspect, ADVF_PRIMEFIRST, &m_AdviseSink);

// get the initial size of the object

lpViewObject2->GetExtent(m_dwDrawAspect, -1 /*lindex*/, NULL /*ptd*/, &m_sizel);

GetObjRect(&rect);  // get the rectangle of the object in pixels

lpViewObject2->Release();

// give the object the name of the container app/document

//@@WTK WIN32, UNICODE

//m_lpOleObject->SetHostNames("Simple Application", "Simple OLE 2.0 Drag/Drop Container");

m_lpOleObject->SetHostNames(OLESTR("Simple Application"), OLESTR("Simple OLE 2.0 Drag/Drop Container"));

// inform object handler/DLL object that it is used in the embedding container's context

OleSetContainedObject(m_lpOleObject, TRUE);

if (fCreateNew) {

   // force new object to save to guarantee valid object in our storage.

   // OLE 1.0 objects may close w/o saving. this is NOT necessary if the

   // object is created FROM FILE; its data in storage is already valid.

   m_OleClientSite.SaveObject();

   // we only want to DoVerb(SHOW) if this is an InsertNew object.

   // we should NOT DoVerb(SHOW) if the object is created FromFile.

   m_lpOleObject->DoVerb(

   OLEIVERB_SHOW,

   NULL,

   &m_OleClientSite,

   -1,

   m_lpDoc->m_hDocWnd,

   &rect);

}

}


 CSimpleSite::PaintObj  (SIMPDND Sample)

//**********************************************************************

//

// CSimpleSite::PaintObj

//

// Purpose:

//

//      Paints the object

//

// Parameters:

//

//      HDC hDC     - Device context of the document window

//

// Return Value:

//

// Function Calls:

//      Function                        Location

//

//      IOleObject::QueryInterface      Object

//      IViewObject::GetColorSet        Object

//      IViewObject::Release            Object

//      SetMapMode                      Windows API

//      LPtoDP                          Windows API

//      CreateHatchBrush                Windows API

//      SelectObject                    Windows API

//      DeleteObject                    Windows API

//      CreatePalette                   Windows API

//      SelectPalette                   Windows API

//      RealizePalette                  Windows API

//      OleStdFree                      OUTLUI Function

//      OleDraw                         OLE API

//

// Comments:

//

//********************************************************************

void CSimpleSite::PaintObj(HDC hDC)

{

RECT rect;

// need to check to make sure there is a valid object

// available.  This is needed if there is a paint msg

// between the time that CSimpleSite is instantiated

// and OleUIInsertObject returns.

if (!m_lpOleObject)

return;

// convert it to pixels

GetObjRect(&rect);

LPLOGPALETTE pColorSet = NULL;

LPVIEWOBJECT lpView = NULL;

// get a pointer to IViewObject

m_lpOleObject->QueryInterface(IID_IViewObject,(LPVOID FAR *) &lpView);

// if the QI succeeds, get the LOGPALETTE for the object

if (lpView)

lpView->GetColorSet(m_dwDrawAspect, -1, NULL, NULL, NULL, &pColorSet);

HPALETTE hPal=NULL;

HPALETTE hOldPal=NULL;

// if a LOGPALETTE was returned (not guarateed), create the palette and

// realize it.  NOTE: A smarter application would want to get the LOGPALETTE

// for each of its visible objects, and try to create a palette that

// satisfies all of the visible objects.  ALSO: OleStdFree() is use to

// free the returned LOGPALETTE.

if ((pColorSet))

{

hPal = CreatePalette((const LPLOGPALETTE) pColorSet);

hOldPal = SelectPalette(hDC, hPal, FALSE);

RealizePalette(hDC);

OleStdFree(pColorSet);

}

// draw the object

OleDraw(m_lpOleObject, m_dwDrawAspect, hDC, &rect);

// if the object is open, draw a hatch rect.

if (m_fObjectOpen)

{

HBRUSH hBrush = CreateHatchBrush ( HS_BDIAGONAL, RGB(0,0,0) );

HBRUSH hOldBrush = SelectObject (hDC, hBrush);

SetROP2(hDC, R2_MASKPEN);

Rectangle (hDC, rect.left, rect.top, rect.right, rect.bottom);

SelectObject(hDC, hOldBrush);

DeleteObject(hBrush);

}

// if we created a palette, restore the old one, and destroy

// the object.

if (hPal)

{

SelectPalette(hDC,hOldPal,FALSE);

DeleteObject(hPal);

}

// if a view pointer was successfully returned, it needs to be released.

if (lpView)

lpView->Release();

}


 CSimpleSite::GetObjRect  (SIMPDND Sample)

//**********************************************************************

//

// CSimpleSite::GetObjRect

//

// Purpose:

//

//      Retrieves the rect of the object in pixels

//

// Parameters:

//

//      LPRECT lpRect - Rect structure filled with object's rect in pixels

//

// Return Value:

//

// Function Calls:

//      Function                        Location

//

//      XformWidthInHimetricToPixels    OUTLUI Function

//      XformHeightInHimetricToPixels   OUTLUI Function

//

// Comments:

//

//********************************************************************

void CSimpleSite::GetObjRect(LPRECT lpRect)

{

// convert it to pixels

lpRect->left = lpRect->top = 0;

lpRect->right = XformWidthInHimetricToPixels(NULL,(int)m_sizel.cx);

lpRect->bottom = XformHeightInHimetricToPixels(NULL,(int)m_sizel.cy);

}


 SIMPSVR

Simpsvr -------- This sample is the simplest OLE 2.0 object that can be written and still support the visual editing feature.  The object that this server supports is a colored square with a black border.

See the MAKEFILE for compilation instructions.


 MAKEFILE  (SIMPSVR Sample)

!include <$(MSTOOLS)\samples\ole\include\olesampl.mak>

all: simpsvr.exe

simpsvr.exe:  app.obj         \

            doc.obj         \

            icf.obj         \

            ido.obj        \

            iec.obj        \

            ioipao.obj        \

            ioipo.obj        \

            ioo.obj        \

            ips.obj        \

            obj.obj         \

            simpsvr.obj     \

            simpsvr.res

  $(link) $(linkdebug) $(guiflags) -machine:$(CPU) -out:$*.exe $** $(olelibs) ole2ui.lib

.cpp.obj:

    $(cc) $(cdebug) $(cflags) $(cvars) $*.cpp

simpsvr.res: simpsvr.rc simpsvr.h

    $(rc) -r -I..\ole2ui -I..\ole2ui\res\usa -I..\ole2ui\res\static simpsvr.rc


 APP.H  (SIMPSVR Sample)

//**********************************************************************

// File name: app.h

//

//      Definition of CSimpSvrApp

//

// Copyright (c) 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#if !defined( _APP_H_)

#define _APP_H_

#include <stablize.h>

class CSimpSvrDoc;

interface CClassFactory;

class CSimpSvrApp : public IUnknown, public CSafeRefCount

{

private:

        HWND m_hAppWnd;             // main window handle

        HINSTANCE m_hInst;          // application instance

        BOOL m_fStartByOle;         // TRUE if app started by OLE

        DWORD m_dwRegisterClass;    // returned by RegisterClassFactory

        HMENU m_hMainMenu;

        HMENU m_hColorMenu;

        HMENU m_hHelpMenu;

        LPOLEOBJECT m_OleObject;    // pointer to "dummy" object

        CSimpSvrDoc FAR * m_lpDoc;   // pointer to document object

        BOOL m_fInitialized;         // OLE initialization flag

        RECT nullRect;               // used in inplace negotiation

public:

        // IUnknown Interfaces

        STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj);

        STDMETHODIMP_(ULONG) AddRef();

        STDMETHODIMP_(ULONG) Release();

        // Initialization methods

        CSimpSvrApp();           // Constructor

        ~CSimpSvrApp();          // Destructor

        BOOL fInitApplication (HANDLE hInstance);

        BOOL fInitInstance (HANDLE hInstance, int nCmdShow, CClassFactory FAR * lpClassFactory);

        // Message handling methods

        long lCommandHandler (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

        long lSizeHandler (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

        long lCreateDoc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

        void PaintApp(HDC hDC);

        //  Utility functions

        void ParseCmdLine(LPSTR lpCmdLine);

        void SetStatusText();

        BOOL IsInPlaceActive();

        void ShowAppWnd(int nCmdShow=SW_SHOWNORMAL);

        void HideAppWnd();

        // member variable access

        inline HWND GethAppWnd() { return m_hAppWnd; };

        inline HINSTANCE GethInst() { return m_hInst; };

        inline BOOL IsStartedByOle() { return m_fStartByOle; };

        inline BOOL IsInitialized() { return m_fInitialized; };

        inline DWORD GetRegisterClass() { return m_dwRegisterClass; };

        inline CSimpSvrDoc FAR * GetDoc() { return m_lpDoc; };

        inline void ClearDoc() { m_lpDoc = NULL; };

        inline LPOLEOBJECT GetOleObject() { return m_OleObject; };

                inline HMENU GetMainMenu() { return m_hMainMenu; };

        inline HMENU GetColorMenu() { return m_hColorMenu; };

        inline HMENU GetHelpMenu() { return m_hHelpMenu; } ;

        friend interface CClassFactory;  // make the contained class a friend

};

#endif


 DOC.H  (SIMPSVR Sample)

//**********************************************************************

// File name: doc.h

//

//      Definition of CSimpSvrDoc

//

// Copyright (c) 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#if !defined( _DOC_H_ )

#define _DOC_H_

#include <stablize.h>

class CSimpSvrApp;

class CSimpSvrObj;

class CSimpSvrDoc : IUnknown, public CSafeRefCount

{

private:

        CSimpSvrApp FAR * m_lpApp;

        CSimpSvrObj FAR * m_lpObj;

        HWND m_hDocWnd;

        HWND m_hHatchWnd;

        BOOL m_fClosing;

public:

        static CSimpSvrDoc FAR * Create(CSimpSvrApp FAR *lpApp, LPRECT lpRect,HWND hWnd);

        CSimpSvrDoc();

        CSimpSvrDoc(CSimpSvrApp FAR *lpApp, HWND hWnd);

        ~CSimpSvrDoc();

// IUnknown Interfaces

        STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppvObj);

        STDMETHODIMP_(ULONG) AddRef();

        STDMETHODIMP_(ULONG) Release();

        long lResizeDoc(LPRECT lpRect);

        long lAddVerbs();

        BOOL Load(LPSTR lpszFileName);

        void PaintDoc(HDC hDC);

        void lButtonDown(WPARAM wParam,LPARAM lParam);

        HRESULT CreateObject(REFIID riid, LPVOID FAR *ppvObject);

        void Close();

        void SetStatusText();

        void ShowDocWnd();

        void ShowHatchWnd();

        void CSimpSvrDoc::HideDocWnd();

        void CSimpSvrDoc::HideHatchWnd();

// member access

        inline HWND GethDocWnd() { return m_hDocWnd; };

        inline HWND GethHatchWnd() { return m_hHatchWnd; };

        inline HWND GethAppWnd() { return m_lpApp->GethAppWnd(); };

        inline CSimpSvrApp FAR * GetApp() { return m_lpApp; };

        inline CSimpSvrObj FAR * GetObj() { return m_lpObj; };

        inline void ClearObj() { m_lpObj = NULL; };

};

#endif


 ICF.H  (SIMPSVR Sample)

//**********************************************************************

// File name: icf.h

//

//      Definition of CClassFactory

//

// Copyright (c) 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#if !defined( _ICF_H_)

#define _ICF_H_

class CSimpSvrApp;

interface CClassFactory :  IClassFactory

{

private:

int m_nCount;               // reference count

CSimpSvrApp FAR * m_lpApp;

public:

CClassFactory::CClassFactory(CSimpSvrApp FAR * lpApp)

{

OutputDebugString("In CClassFactory's Constructor\r\n");

m_lpApp = lpApp;

m_nCount = 0;

};

CClassFactory::~CClassFactory()

   {

   OutputDebugString("In CClassFactory's Destructor\r\n");

   };

// IUnknown Methods

STDMETHODIMP QueryInterface (REFIID riid, LPVOID FAR* ppvObj);

STDMETHODIMP_(ULONG) AddRef ();

STDMETHODIMP_(ULONG) Release ();

STDMETHODIMP CreateInstance (LPUNKNOWN pUnkOuter,

  REFIID riid,

  LPVOID FAR* ppvObject);

STDMETHODIMP LockServer ( BOOL fLock);

};

#endif


 IDO.H  (SIMPSVR Sample)

//**********************************************************************

// File name: ido.h

//

//      Definition of CDataObject

//

// Copyright (c) 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#if !defined( _IDO_H_)

#define _IDO_H_

#include <ole2.h>

#include "obj.h"

class CSimpSvrObj;

interface CDataObject : public IDataObject

{

private:

CSimpSvrObj FAR * m_lpObj;

int m_nCount;

public:

CDataObject::CDataObject(CSimpSvrObj FAR * lpSimpSvrObj)

{

m_lpObj = lpSimpSvrObj;

m_nCount = 0;

};

CDataObject::~CDataObject() {};

STDMETHODIMP QueryInterface (REFIID riid, LPVOID FAR* ppvObj);

STDMETHODIMP_(ULONG) AddRef ();

STDMETHODIMP_(ULONG) Release ();

STDMETHODIMP DAdvise  ( FORMATETC FAR* pFormatetc, DWORD advf,

LPADVISESINK pAdvSink, DWORD FAR* pdwConnection);

STDMETHODIMP DUnadvise  ( DWORD dwConnection);

STDMETHODIMP EnumDAdvise  ( LPENUMSTATDATA FAR* ppenumAdvise);

STDMETHODIMP EnumFormatEtc  ( DWORD dwDirection,

  LPENUMFORMATETC FAR* ppenumFormatEtc);

STDMETHODIMP GetCanonicalFormatEtc  ( LPFORMATETC pformatetc,

  LPFORMATETC pformatetcOut);

STDMETHODIMP GetData  ( LPFORMATETC pformatetcIn, LPSTGMEDIUM pmedium );

STDMETHODIMP GetDataHere  ( LPFORMATETC pformatetc, LPSTGMEDIUM pmedium );

STDMETHODIMP QueryGetData  ( LPFORMATETC pformatetc );

STDMETHODIMP SetData  ( LPFORMATETC pformatetc, STGMEDIUM FAR * pmedium,

BOOL fRelease);

};

#endif


 IEC.H  (SIMPSVR Sample)

//**********************************************************************

// File name: iec.h

//

//      Definition of CExternalConnection

//

// Copyright (c) 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#if !defined( _IEC_H_)

#define _IEC_H_

#include <ole2.h>

#include "obj.h"

class CSimpSvrObj;

interface CExternalConnection : public IExternalConnection

{

private:

CSimpSvrObj FAR * m_lpObj;  // Ptr to object

int m_nCount;               // Ref count

DWORD m_dwStrong;           // Connection Count

public:

CExternalConnection::CExternalConnection(CSimpSvrObj FAR * lpSimpSvrObj)

{

m_lpObj = lpSimpSvrObj;

m_nCount = 0;

m_dwStrong = 0;

};

CExternalConnection::~CExternalConnection() {};

// *** IUnknown methods ***

STDMETHODIMP QueryInterface (REFIID riid, LPVOID FAR* ppvObj);

STDMETHODIMP_(ULONG) AddRef ();

STDMETHODIMP_(ULONG) Release ();

// *** IExternalConnection methods ***

STDMETHODIMP_(DWORD) AddConnection (DWORD extconn, DWORD reserved);

STDMETHODIMP_(DWORD) ReleaseConnection (DWORD extconn, DWORD reserved, BOOL fLastReleaseCloses);

};

#endif


 IOIPAO.H  (SIMPSVR Sample)

//**********************************************************************

// File name: IOIPAO.H

//

//      Definition of COleInPlaceActiveObject

//

// Copyright (c) 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#if !defined( _IOIPAO_H_)

#define _IOIPAO_H_

#include <ole2.h>

#include "obj.h"

class CSimpSvrObj;

interface COleInPlaceActiveObject : public IOleInPlaceActiveObject

{

private:

CSimpSvrObj FAR * m_lpObj;

int m_nCount;

public:

COleInPlaceActiveObject::COleInPlaceActiveObject(CSimpSvrObj FAR * lpSimpSvrObj)

{

m_lpObj = lpSimpSvrObj;     // set up the back ptr

m_nCount = 0;            // clear the ref count.

};

COleInPlaceActiveObject::~COleInPlaceActiveObject() {};   // destructor

// IUnknown Methods

STDMETHODIMP QueryInterface (REFIID riid, LPVOID FAR* ppvObj);

STDMETHODIMP_(ULONG) AddRef ();

STDMETHODIMP_(ULONG) Release ();

STDMETHODIMP OnDocWindowActivate  ( BOOL fActivate) ;

STDMETHODIMP OnFrameWindowActivate  ( BOOL fActivate) ;

STDMETHODIMP GetWindow  ( HWND FAR* lphwnd);

STDMETHODIMP ContextSensitiveHelp  ( BOOL fEnterMode);

STDMETHODIMP TranslateAccelerator  ( LPMSG lpmsg);

STDMETHODIMP ResizeBorder  ( LPCRECT lprectBorder,

 LPOLEINPLACEUIWINDOW lpUIWindow,

 BOOL fFrameWindow);

STDMETHODIMP EnableModeless  ( BOOL fEnable);

};

#endif


 IOIPO.H  (SIMPSVR Sample)

//**********************************************************************

// File name: ioipo.h

//

//      Definition of COleInPlaceObject

//

// Copyright (c) 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#if !defined( _IOIPO_H_)

#define _IOIPO_H_

#include <ole2.h>

#include "obj.h"

class CSimpSvrObj;

interface COleInPlaceObject : public IOleInPlaceObject

{

private:

CSimpSvrObj FAR * m_lpObj;

int m_nCount;

public:

COleInPlaceObject::COleInPlaceObject(CSimpSvrObj FAR * lpSimpSvrObj)

{

m_lpObj = lpSimpSvrObj;

m_nCount = 0;

};

COleInPlaceObject::~COleInPlaceObject() {};

//  IUnknown Methods

STDMETHODIMP QueryInterface (REFIID riid, LPVOID FAR* ppvObj);

STDMETHODIMP_(ULONG) AddRef ();

STDMETHODIMP_(ULONG) Release ();

STDMETHODIMP InPlaceDeactivate  ();

STDMETHODIMP UIDeactivate  () ;

STDMETHODIMP SetObjectRects  ( LPCRECT lprcPosRect, LPCRECT lprcClipRect);

STDMETHODIMP GetWindow  ( HWND FAR* lphwnd) ;

STDMETHODIMP ContextSensitiveHelp  ( BOOL fEnterMode);

STDMETHODIMP ReactivateAndUndo  ();

};

#endif


 IOO.H  (SIMPSVR Sample)

//**********************************************************************

// File name: ioo.h

//

//      Definition of COleObject

//

// Copyright (c) 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#if !defined( _IOO_H_)

#define _IOO_H_

#include <ole2.h>

#include "obj.h"

class CSimpSvrObj;

interface COleObject : public IOleObject

{

private:

CSimpSvrObj FAR * m_lpObj;

int m_nCount;

BOOL m_fOpen;

public:

COleObject::COleObject(CSimpSvrObj FAR * lpSimpSvrObj)

{

m_lpObj = lpSimpSvrObj;

m_nCount = 0;

m_fOpen = FALSE;

};

COleObject::~COleObject()

{

};

STDMETHODIMP QueryInterface (REFIID riid, LPVOID FAR* ppvObj);

STDMETHODIMP_(ULONG) AddRef ();

STDMETHODIMP_(ULONG) Release ();

STDMETHODIMP SetClientSite (LPOLECLIENTSITE pClientSite);

STDMETHODIMP Advise (LPADVISESINK pAdvSink, DWORD FAR* pdwConnection);

//@@WTK WIN32, UNICODE

//STDMETHODIMP SetHostNames  ( LPCSTR szContainerApp, LPCSTR szContainerObj);

STDMETHODIMP SetHostNames  ( LPCOLESTR szContainerApp, LPCOLESTR szContainerObj);

STDMETHODIMP DoVerb  (  LONG iVerb,

LPMSG lpmsg,

LPOLECLIENTSITE pActiveSite,

LONG lindex,

HWND hwndParent,

LPCRECT lprcPosRect);

STDMETHODIMP GetExtent  ( DWORD dwDrawAspect, LPSIZEL lpsizel);

STDMETHODIMP Update  () ;

STDMETHODIMP Close  ( DWORD dwSaveOption) ;

STDMETHODIMP Unadvise ( DWORD dwConnection);

STDMETHODIMP EnumVerbs  ( LPENUMOLEVERB FAR* ppenumOleVerb) ;

STDMETHODIMP GetClientSite  ( LPOLECLIENTSITE FAR* ppClientSite);

STDMETHODIMP SetMoniker  ( DWORD dwWhichMoniker, LPMONIKER pmk);

STDMETHODIMP GetMoniker  ( DWORD dwAssign, DWORD dwWhichMoniker,

   LPMONIKER FAR* ppmk);

STDMETHODIMP InitFromData  ( LPDATAOBJECT pDataObject,

 BOOL fCreation,

 DWORD dwReserved);

STDMETHODIMP GetClipboardData  ( DWORD dwReserved,

 LPDATAOBJECT FAR* ppDataObject);

STDMETHODIMP IsUpToDate  ();

STDMETHODIMP GetUserClassID  ( CLSID FAR* pClsid);

//@@WTK WIN32, UNICODE

//STDMETHODIMP GetUserType  ( DWORD dwFormOfType, LPSTR FAR* pszUserType);

STDMETHODIMP GetUserType  ( DWORD dwFormOfType, LPOLESTR FAR* pszUserType);

STDMETHODIMP SetExtent  ( DWORD dwDrawAspect, LPSIZEL lpsizel);

STDMETHODIMP EnumAdvise  ( LPENUMSTATDATA FAR* ppenumAdvise);

STDMETHODIMP GetMiscStatus  ( DWORD dwAspect, DWORD FAR* pdwStatus);

STDMETHODIMP SetColorScheme  ( LPLOGPALETTE lpLogpal);

void OpenEdit(LPOLECLIENTSITE pActiveSite);

};

#endif


 IPS.H  (SIMPSVR Sample)

//**********************************************************************

// File name: ips.h

//

//      Definition of CPersistStorage

//

// Copyright (c) 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#if !defined( _IPS_H_)

#define _IPS_H_

#include <ole2.h>

//@@WTK WIN32, UNICODE

//#include <storage.h>

#include "obj.h"

class CSimpSvrObj;

interface CPersistStorage : IPersistStorage

{

private:

CSimpSvrObj FAR * m_lpObj;

int m_nCount;

BOOL m_fSameAsLoad;

public:

CPersistStorage::CPersistStorage(CSimpSvrObj FAR * lpSimpSvrObj)

{

m_lpObj = lpSimpSvrObj;

m_nCount = 0;

};

CPersistStorage::~CPersistStorage() {};

STDMETHODIMP QueryInterface (REFIID riid, LPVOID FAR* ppvObj);

STDMETHODIMP_(ULONG) AddRef ();

STDMETHODIMP_(ULONG) Release ();

STDMETHODIMP InitNew (LPSTORAGE pStg);

STDMETHODIMP GetClassID  ( LPCLSID lpClassID) ;

STDMETHODIMP Save  ( LPSTORAGE pStgSave, BOOL fSameAsLoad) ;

STDMETHODIMP SaveCompleted  ( LPSTORAGE pStgNew);

STDMETHODIMP Load  ( LPSTORAGE pStg);

STDMETHODIMP IsDirty  ();

STDMETHODIMP HandsOffStorage  ();

void ReleaseStreamsAndStorage();

void OpenStreams(LPSTORAGE lpStg);

void CreateStreams(LPSTORAGE lpStg);

void CreateStreams(LPSTORAGE lpStg, LPSTREAM FAR *lpTempColor, LPSTREAM FAR *lpTempSize);

};

#endif


 OBJ.H  (SIMPSVR Sample)

//**********************************************************************

// File name: obj.h

//

//      Definition of CSimpSvrObj

//

// Copyright (c) 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#if !defined( _OBJ_H_)

#define _OBJ_H_

#include "ioipao.h"

#include "ioipo.h"

#include "ioo.h"

#include "ips.h"

#include "ido.h"

#include "iec.h"

class CSimpSvrDoc;

interface COleObject;

interface CPersistStorage;

interface CDataObject;

interface COleInPlaceActiveObject;

interface COleInPlaceObject;

interface CExternalConnection;

class CSimpSvrObj : public IUnknown

{

private:

CSimpSvrDoc FAR * m_lpDoc;      // Back pointer

int m_nCount;                   // reference count

BOOL m_fInPlaceActive;          // Used during InPlace Negotiation

BOOL m_fInPlaceVisible;         // "  "  "  "   "   "   "   "   "

BOOL m_fUIActive;               // "  "  "  "   "   "   "   "   "

HMENU m_hmenuShared;            // "  "  "  "   "   "   "   "   "

HOLEMENU m_hOleMenu;            // "  "  "  "   "   "   "   "   "

RECT m_posRect;                 // "  "  "  "   "   "   "   "   "

OLEINPLACEFRAMEINFO m_FrameInfo;

BOOL m_fSaveWithSameAsLoad;

BOOL m_fNoScribbleMode;

DWORD m_dwRegister;             // Registered in ROT

int m_red, m_green, m_blue;     // current color

POINT m_size;                   // current size

int m_xOffset;

int m_yOffset;

float m_scale;

HWND m_hWndParent;              // parent window handle

// interfaces used

LPSTORAGE m_lpStorage;

LPSTREAM m_lpColorStm, m_lpSizeStm;

LPOLECLIENTSITE m_lpOleClientSite;          // IOleClientSite

LPOLEADVISEHOLDER m_lpOleAdviseHolder;      // IOleAdviseHolder

LPDATAADVISEHOLDER m_lpDataAdviseHolder;    // IDataAdviseHolder

LPOLEINPLACEFRAME m_lpFrame;                // IOleInPlaceFrame

LPOLEINPLACEUIWINDOW m_lpCntrDoc;           // IOleInPlaceUIWindow

LPOLEINPLACESITE m_lpIPSite;                // IOleInPlaceSite

// interface implemented

COleObject m_OleObject;                             // IOleObject

CPersistStorage m_PersistStorage;                   // IPersistStorage

CDataObject m_DataObject;                           // IDataObject

COleInPlaceActiveObject m_OleInPlaceActiveObject;   // IOleInPlaceActiveObject

COleInPlaceObject m_OleInPlaceObject;               // IOleInPlaceObject

CExternalConnection m_ExternalConnection;

public:

STDMETHODIMP QueryInterface (REFIID riid, LPVOID FAR* ppvObj);

STDMETHODIMP_(ULONG) AddRef ();

STDMETHODIMP_(ULONG) Release ();

// construction/destruction

CSimpSvrObj(CSimpSvrDoc FAR * lpSimpSvrDoc);

~CSimpSvrObj();

// utility functions

void Draw(HDC hDC, BOOL fMetaDC = TRUE);

void PaintObj(HDC hDC);

void lButtonDown(WPARAM wParam,LPARAM lParam);

HANDLE GetMetaFilePict();

void SaveToStorage (LPSTORAGE lpStg, BOOL fSameAsLoad);

void LoadFromStorage ();

// visual editing helper functions

BOOL DoInPlaceActivate (LONG lVerb);

void AssembleMenus();

void AddFrameLevelUI();

void DoInPlaceHide();

void DisassembleMenus();

void SendOnDataChange();

void DeactivateUI();

// member variable access

inline BOOL IsInPlaceActive() { return m_fInPlaceActive; };

inline BOOL IsInPlaceVisible() { return m_fInPlaceVisible; };

inline BOOL IsUIActive() { return m_fUIActive; };

inline HWND GetParent() { return m_hWndParent; };

inline LPSTORAGE GetStorage() { return m_lpStorage; };

inline LPOLECLIENTSITE GetOleClientSite() { return m_lpOleClientSite; };

inline LPDATAADVISEHOLDER GetDataAdviseHolder() { return m_lpDataAdviseHolder; };

inline LPOLEADVISEHOLDER GetOleAdviseHolder() { return m_lpOleAdviseHolder; };

inline LPOLEINPLACEFRAME GetInPlaceFrame() { return m_lpFrame; };

inline LPOLEINPLACEUIWINDOW GetUIWindow() { return m_lpCntrDoc; };

inline LPOLEINPLACESITE GetInPlaceSite() { return m_lpIPSite; };

inline COleObject FAR * GetOleObject() { return &m_OleObject; };

inline CPersistStorage FAR * GetPersistStorage() { return &m_PersistStorage; };

inline CDataObject FAR * GetDataObject() { return &m_DataObject; };

inline COleInPlaceActiveObject FAR * GetOleInPlaceActiveObject() { return &m_OleInPlaceActiveObject; };

inline COleInPlaceObject FAR * GetOleInPlaceObject() { return &m_OleInPlaceObject; };

inline void ClearOleClientSite() { m_lpOleClientSite = NULL; };

inline void ClearDataAdviseHolder() { m_lpDataAdviseHolder = NULL; };

inline void ClearOleAdviseHolder() { m_lpOleAdviseHolder = NULL; };

inline LPRECT GetPosRect() { return &m_posRect; };

inline LPPOINT GetSize() { return &m_size; };

inline LPOLEINPLACEFRAMEINFO GetFrameInfo() {return &m_FrameInfo;};

inline DWORD GetRotRegister() { return m_dwRegister; };

// member manipulation

inline void SetColor (int nRed, int nGreen, int nBlue)

{ m_red = nRed; m_green = nGreen; m_blue = nBlue; };

inline void RotateColor()

{ m_red+=10; m_green+=10; m_blue+=10;};

// all of the interface implementations should be friends of this

// class

friend interface COleObject;

friend interface CPersistStorage;

friend interface CDataObject;

friend interface COleInPlaceActiveObject;

friend interface COleInPlaceObject;

friend interface CExternalConnection;

};

#endif


 PRE.H  (SIMPSVR Sample)

//**********************************************************************

// File name: pre.h

//

//      Used for precompiled headers

//

// Copyright (c) 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#if !defined( _PRE_H_)

#define _PRE_H_

#include <windows.h>

#include <ole2.h>

#include <ole2ui.h>

#include <assert.h>

#include <string.h>

#include "simpsvr.h"

#include "resource.h"

#include <ole2ver.h>

#endif


 RESOURCE.H  (SIMPSVR Sample)

//{{NO_DEPENDENCIES}}

// App Studio generated include file.

// Used by SIMPSVR.RC

//

#define IDM_OPEN                        102

#define IDM_SAVE                        103

#define IDM_SAVEAS                      104

#define IDM_PRINT                       105

#define IDM_EXIT                        106

#define IDM_UNDO                        107

#define IDM_CUT                         108

#define IDM_COPY                        109

#define IDM_PASTE                       110

#define ID_EDIT_INSERTOBJECT            111

#define IDM_INSERTOBJECT                111

#define IDM_NEW                         112

#define IDM_RED                         113

#define IDM_GREEN                       114

#define IDM_BLUE                        115

#define IDM_ROTATE                      116

// Next default values for new objects

//

#ifdef APSTUDIO_INVOKED

#ifndef APSTUDIO_READONLY_SYMBOLS

#define _APS_NEXT_RESOURCE_VALUE        102

#define _APS_NEXT_COMMAND_VALUE         117

#define _APS_NEXT_CONTROL_VALUE         1000

#define _APS_NEXT_SYMED_VALUE           101

#endif

#endif


 SIMPSVR.H  (SIMPSVR Sample)

//**********************************************************************

// File name: simpsvr.h

//

// Copyright (c) 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#define IDM_ABOUT 100

#define IDM_INSERT  101

#define IDM_VERB0 1000

int PASCAL WinMain(HANDLE hInstance,HANDLE hPrevInstance,LPSTR lpCmdLine,int nCmdShow);

BOOL InitApplication(HANDLE hInstance);

BOOL InitInstance(HANDLE hInstance, int nCmdShow);

//@@WTK WIN32, UNICODE _export EXPORT

long FAR PASCAL EXPORT MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

long FAR PASCAL EXPORT DocWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

//@@WTK WIN32, UNICODE

//BOOL FAR PASCAL export About(HWND hDlg, unsigned message, WORD wParam, LONG lParam);

BOOL FAR PASCAL EXPORT About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);


 APP.CPP  (SIMPSVR Sample)

//**********************************************************************

// File name: app.cpp

//

//    Implementation file for the CSimpSvrApp Class

//

// Functions:

//

//    See app.h for a list of member functions.

//

// Copyright (c) 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#include "pre.h"

#include "obj.h"

#include "app.h"

#include "doc.h"

#include "icf.h"

#include "initguid.h"

DEFINE_GUID(GUID_SIMPLE, 0xBCF6D4A0, 0xBE8C, 0x1068, 0xB6, 0xD4, 0x00, 0xDD, 0x01, 0x0C, 0x05, 0x09);


 CSimpSvrApp::CSimpSvrApp  (SIMPSVR Sample)

//**********************************************************************

//

// CSimpSvrApp::CSimpSvrApp()

//

// Purpose:

//

//      Constructor for CSimpSvrApp

//

// Parameters:

//

//      None

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      SetRectEmpty                Windows API

//

// Comments:

//

//

//********************************************************************

CSimpSvrApp::CSimpSvrApp()

{

        OutputDebugString("In CSimpSvrApp's Constructor \r\n");

        // clear members

        m_hAppWnd = NULL;

        m_hInst = NULL;

        m_lpDoc = NULL;

        // clear flags

        m_fInitialized = FALSE;

        // used for inplace

        SetRectEmpty(&nullRect);

}


 CSimpSvrApp::~CSimpSvrApp  (SIMPSVR Sample)

//**********************************************************************

//

// CSimpSvrApp::~CSimpSvrApp()

//

// Purpose:

//

//      Destructor for CSimpSvrApp Class.

//

// Parameters:

//

//      None

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      DestroyWindow               Windows API

//      CSimpSvrApp::IsInitialized  APP.H

//      OleUninitialize             OLE API

//

// Comments:

//

//********************************************************************

CSimpSvrApp::~CSimpSvrApp()

{

        OutputDebugString("In CSimpSvrApp's Destructor\r\n");

        // need to uninit the library...

        if (IsInitialized())

                OleUninitialize();

        DestroyWindow(m_hAppWnd);

}


 CSimpSvrApp::QueryInterface  (SIMPSVR Sample)

//**********************************************************************

//

// CSimpSvrApp::QueryInterface

//

// Purpose:

//

//      Used for interface negotiation at the Application level.

//

// Parameters:

//

//      REFIID riid         -   A reference to the interface that is

//                              being queried.

//

//      LPVOID FAR* ppvObj  -   An out parameter to return a pointer to

//                              the interface.

//

// Return Value:

//

//      S_OK          -   The interface is supported.

//      E_NOINTERFACE -   The interface is not supported

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      ResultFromScode             OLE API

//      IUnknown::AddRef            APP.CPP

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP CSimpSvrApp::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)

{

        OutputDebugString("In CSimpSvrApp::QueryInterface\r\n");

        SCODE sc = S_OK;

        if (riid == IID_IUnknown)

                *ppvObj = this;

        else

                {

                *ppvObj = NULL;

                sc = E_NOINTERFACE;

                }

        if (*ppvObj)

                ((LPUNKNOWN)*ppvObj)->AddRef();

        // asking for something we don't understand at this level.

        return ResultFromScode(sc);

}


 CSimpSvrApp::AddRef  (SIMPSVR Sample)

//**********************************************************************

//

// CSimpSvrApp::AddRef

//

// Purpose:

//

//      Adds to the reference count at the Application level.

//

// Parameters:

//

//      None

//

// Return Value:

//

//      ULONG   -   The new reference count of the application.

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//      Due to the reference counting model that is used in this

//      implementation, this reference count is the sum of the

//      reference counts on all interfaces of all objects open

//      in the application.

//

//********************************************************************

STDMETHODIMP_(ULONG) CSimpSvrApp::AddRef()

{

        OutputDebugString("In CSimpSvrApp::AddRef\r\n");

        return SafeAddRef();

}


 CSimpSvrApp::Release  (SIMPSVR Sample)

//**********************************************************************

//

// CSimpSvrApp::Release

//

// Purpose:

//

//      Decrements the reference count at this level

//

// Parameters:

//

//      None

//

// Return Value:

//

//      ULONG   -   The new reference count of the application.

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//      Due to the reference counting model that is used in this

//      implementation, this reference count is the sum of the

//      reference counts on all interfaces of all objects open

//      in the application.

//

//********************************************************************

STDMETHODIMP_(ULONG) CSimpSvrApp::Release()

{

        OutputDebugString("In CSimpSvrApp::Release\r\n");

        return SafeRelease();

}


 CSimpSvrApp::fInitApplication  (SIMPSVR Sample)

//**********************************************************************

//

// CSimpSvrApp::fInitApplication

//

// Purpose:

//

//      Initializes the application

//

// Parameters:

//

//      HANDLE hInstance    -   Instance handle of the application.

//

// Return Value:

//

//      TRUE    -   Application was successfully initialized.

//      FALSE   -   Application could not be initialized

//

// Function Calls:

//      Function                    Location

//

//      LoadIcon                    Windows API

//      LoadCursor                  Windows API

//      GetStockObject              Windows API

//      RegisterClass               Windows API

//      RegisterHatchWindowClass    OUTLUI.DLL

//

// Comments:

//

//********************************************************************

BOOL CSimpSvrApp::fInitApplication(HANDLE hInstance)

{

        CStabilize stabilize(this);

        WNDCLASS  wc;

        // Fill in window class structure with parameters that describe the

        // main window.

        wc.style = NULL;                    // Class style(s).

        wc.lpfnWndProc = MainWndProc;       // Function to retrieve messages for

                                                                                // windows of this class.

        wc.cbClsExtra = 0;                  // No per-class extra data.

        wc.cbWndExtra = 0;                  // No per-window extra data.

        wc.hInstance = hInstance;           // Application that owns the class.

        wc.hIcon = LoadIcon(hInstance, "SimpSvr");

        wc.hCursor = LoadCursor(NULL, IDC_ARROW);

        wc.hbrBackground = GetStockObject(WHITE_BRUSH);

        wc.lpszMenuName =  "SimpSvrMENU";    // Name of menu resource in .RC file.

        wc.lpszClassName = "SimpSvrWClass";  // Name used in call to CreateWindow.

        if (!RegisterClass(&wc))

                return FALSE;

        wc.style = CS_VREDRAW | CS_HREDRAW;                    // Class style(s).

        wc.lpfnWndProc = DocWndProc;        // Function to retrieve messages for

                                                                                // windows of this class.

        wc.cbClsExtra = 0;                  // No per-class extra data.

        wc.cbWndExtra = 0;                  // No per-window extra data.

        wc.hInstance = hInstance;           // Application that owns the class.

        wc.hIcon = NULL;

        wc.hCursor = LoadCursor(NULL, IDC_ARROW);

        wc.hbrBackground = GetStockObject(WHITE_BRUSH);

        wc.lpszMenuName =  NULL;

        wc.lpszClassName = "DocWClass";     // Name used in call to CreateWindow.

        // Register the window class and return success/failure code.

        if (!RegisterClass(&wc))

                return FALSE;

        return (RegisterHatchWindowClass(hInstance));

}


 CSimpSvrApp::fInitInstance  (SIMPSVR Sample)

//**********************************************************************

//

// CSimpSvrApp::fInitInstance

//

// Purpose:

//

//      Instance initialization.

//

// Parameters:

//

//      HANDLE hInstance    -   App. Instance Handle.

//

//      int nCmdShow        -   Show parameter from WinMain

//

// Return Value:

//

//      TRUE    -   Initialization Successful

//      FALSE   -   Initialization Failed.

//

//

// Function Calls:

//      Function                    Location

//

//      CreateWindow                Windows API

//      InvalidateRect              Windows API

//      ShowWindow                  Windows API

//      UpdateWindow                Windows API

//      CoRegisterClassObject       OLE API

//      OleBuildVersion             OLE API

//      OleInitialize               OLE API

//      CSimpSvrDoc::CreateObject   DOC.CPP

//

// Comments:

//

//      Note that successful Initalization of the OLE libraries

//      is remembered so the UnInit is only called if needed.

//

//********************************************************************

BOOL CSimpSvrApp::fInitInstance (HANDLE hInstance, int nCmdShow, CClassFactory FAR * lpClassFactory)

{

        CStabilize stabilize(this);

        m_hInst = hInstance;

                DWORD dwVer = OleBuildVersion();

        // check to see if we are compatible with this version of the libraries

        if (HIWORD(dwVer) != rmm || LOWORD(dwVer) < rup)

                OutputDebugString("*** WARNING:  Not compatible with current libs ***\r\n");

        // initialize the libraries

        if (OleInitialize(NULL) == NOERROR)

                m_fInitialized = TRUE;

        // Create the "application" windows

        m_hAppWnd = CreateWindow ("SimpSvrWClass",

                                                          "Simple OLE 2.0 Server",

                                                          WS_OVERLAPPEDWINDOW,

                                                          CW_USEDEFAULT,

                                                          CW_USEDEFAULT,

                                                          CW_USEDEFAULT,

                                                          CW_USEDEFAULT,

                                                          NULL,

                                                          NULL,

                                                          hInstance,

                                                          NULL);

        if (!m_hAppWnd)

                return FALSE;

        // if not started by OLE, then show the Window, and create a "fake" object, else

        // Register a pointer to IClassFactory so that OLE can instruct us to make an

        // object at the appropriate time.

        if (!m_fStartByOle)

                {

                ShowAppWnd(nCmdShow);

                m_lpDoc->CreateObject(IID_IOleObject, (LPVOID FAR *)&m_OleObject);

                InvalidateRect(m_lpDoc->GethDocWnd(), NULL, TRUE);

                }

        else

                {

                lpClassFactory = new CClassFactory(this);

                // shouldn't pass an API an object with a zero ref count

                lpClassFactory->AddRef();

                CoRegisterClassObject(GUID_SIMPLE,(IUnknown FAR *)lpClassFactory, CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE, &m_dwRegisterClass);

                // remove artificial Ref. count

                lpClassFactory->Release();

                }

        m_hMainMenu = GetMenu(m_hAppWnd);

        m_hColorMenu = GetSubMenu(m_hMainMenu, 1);

        m_hHelpMenu = GetSubMenu(m_hMainMenu, 2);

        return m_fInitialized;

}


 CSimpSvrApp::lCommandHandler  (SIMPSVR Sample)

//**********************************************************************

//

// CSimpSvrApp::lCommandHandler

//

// Purpose:

//

//      Handles the processing of WM_COMMAND.

//

// Parameters:

//

//      HWND hWnd       -   Handle to the application Window

//

//      UINT message    -   message (always WM_COMMAND)

//

//      WPARAM wParam   -   Same as passed to the WndProc

//

//      LPARAM lParam   -   Same as passed to the WndProc

//

// Return Value:

//

//      NULL

//

// Function Calls:

//      Function                                    Location

//

//      GetClientRect                               Windows API

//      MessageBox                                  Windows API

//      DialogBox                                   Windows API

//      MakeProcInstance                            Windows API

//      FreeProcInstance                            Windows API

//      SendMessage                                 Windows API

//      DefWindowProc                               Windows API

//      InvalidateRect                              Windows API

//      CSimpSvrDoc::InsertObject                   DOC.CPP

//      CSimpSvrObj::SetColor                       OBJ.CPP

//      CSimpSvrObj::RotateColor                    OBJ.CPP

//

// Comments:

//

//********************************************************************

long CSimpSvrApp::lCommandHandler (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

{

        CStabilize stabilize(this);

        //@@WTK WIN32, UNICODE

        //switch (wParam) {

        switch (LOWORD(wParam)) {

                // bring up the About box

                case IDM_ABOUT:

                        {

                        FARPROC lpProcAbout = MakeProcInstance((FARPROC)About, m_hInst);

                        DialogBox(m_hInst,               // current instance

                                        "AboutBox",                  // resource to use

                                        m_hAppWnd,                   // parent handle

                                        lpProcAbout);                // About() instance address

                        FreeProcInstance(lpProcAbout);

                        break;

                        }

                // exit the application

                case IDM_EXIT:

                        SendMessage(hWnd, WM_SYSCOMMAND, SC_CLOSE, 0L);

                        break;

                case IDM_RED:

                        m_lpDoc->GetObj()->SetColor (128, 0, 0);

                        InvalidateRect(m_lpDoc->GethDocWnd(), NULL, TRUE);

                        break;

                case IDM_GREEN:

                        m_lpDoc->GetObj()->SetColor (0,128, 0);

                        InvalidateRect(m_lpDoc->GethDocWnd(), NULL, TRUE);

                        break;

                case IDM_BLUE:

                        m_lpDoc->GetObj()->SetColor (0, 0, 128);

                        InvalidateRect(m_lpDoc->GethDocWnd(), NULL, TRUE);

                        break;

                case IDM_ROTATE:

                        m_lpDoc->GetObj()->RotateColor();

                        InvalidateRect(m_lpDoc->GethDocWnd(), NULL, TRUE);

                        break;

                default:

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

                   }   // end of switch

        return NULL;

}


 CSimpSvrApp::lSizeHandler  (SIMPSVR Sample)

//**********************************************************************

//

// CSimpSvrApp::lSizeHandler

//

// Purpose:

//

//      Handles the WM_SIZE message

//

// Parameters:

//

//      HWND hWnd       -   Handle to the application Window

//

//      UINT message    -   message (always WM_SIZE)

//

//      WPARAM wParam   -   Same as passed to the WndProc

//

//      LPARAM lParam   -   Same as passed to the WndProc

//

// Return Value:

//

//      LONG    -   returned from the "document" resizing

//

// Function Calls:

//      Function                    Location

//

//      GetClientRect               Windows API

//      CSimpSvrDoc::lResizeDoc      DOC.CPP

//

// Comments:

//

//********************************************************************

long CSimpSvrApp::lSizeHandler (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

{

        RECT rect;

        CStabilize stabilize(this);

        GetClientRect(m_hAppWnd, &rect);

        return m_lpDoc->lResizeDoc(&rect);

}


 CSimpSvrApp::lCreateDoc  (SIMPSVR Sample)

//**********************************************************************

//

// CSimpSvrApp::lCreateDoc

//                                                         d

// Purpose:

//

//      Handles the creation of a document.

//

// Parameters:

//

//      HWND hWnd       -   Handle to the application Window

//

//      UINT message    -   message (always WM_CREATE)

//

//      WPARAM wParam   -   Same as passed to the WndProc

//

//      LPARAM lParam   -   Same as passed to the WndProc

//

// Return Value:

//

//      NULL

//

// Function Calls:

//      Function                    Location

//

//      GetClientRect               Windows API

//      CSimpSvrDoc::Create         DOC.CPP

//

// Comments:

//

//********************************************************************

long CSimpSvrApp::lCreateDoc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

{

        RECT rect;

        CStabilize stabilize(this);

        GetClientRect(hWnd, &rect);

        m_lpDoc = CSimpSvrDoc::Create(this, &rect, hWnd);

        return NULL;

}


 CSimpSvrApp::PaintApp  (SIMPSVR Sample)

//**********************************************************************

//

// CSimpSvrApp::PaintApp

//

// Purpose:

//

//      Handles the painting of the doc window.

//

//

// Parameters:

//

//      HDC hDC -   hDC to the Doc Window.

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                    Location

//

//      CSimpSvrDoc::PaintDoc        DOC.CPP

//

// Comments:

//

//

//********************************************************************

void CSimpSvrApp::PaintApp (HDC hDC)

{

        CStabilize stabilize(this);

        // if we supported multiple documents, we would enumerate

        // through each of the open documents and call paint.

        if (m_lpDoc)

                m_lpDoc->PaintDoc(hDC);

}


 CSimpSvrApp::ParseCmdLine  (SIMPSVR Sample)

//**********************************************************************

//

// CSimpSvrApp::ParseCmdLine

//

// Purpose:

//

//      Determines if the app was started by OLE

//

//

// Parameters:

//

//      LPSTR lpCmdLine -   Pointer to the command line

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                    Location

//

//      lstrlen                     Windows API

//      lstrcmp                     Windows API

//

//

// Comments:

//

//      Parses the command line looking for the -Embedding or /Embedding

//      flag.

//

//********************************************************************

void CSimpSvrApp::ParseCmdLine(LPSTR lpCmdLine)

{

        char szTemp[255];

        m_fStartByOle = TRUE;

        ::ParseCmdLine (lpCmdLine, &m_fStartByOle, szTemp);

}


 CSimpSvrApp::SetStatusText  (SIMPSVR Sample)

//**********************************************************************

//

// CSimpSvrApp::SetStatusText

//

// Purpose:

//

//      Blanks out the text in the status bar

//

//

// Parameters:

//

//      None

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                    Location

//

//      CSimpSvrDoc::SetStatusText  DOC.CPP

//

//

// Comments:

//

//

//********************************************************************

void CSimpSvrApp::SetStatusText()

{

        CStabilize stabilize(this);

        m_lpDoc->SetStatusText();

}


 CSimpSvrApp::IsInPlaceActive  (SIMPSVR Sample)

//**********************************************************************

//

// CSimpSvrApp::IsInPlaceActive

//

// Purpose:

//

//      Safely determines from the app level if currently inplace active.

//

//

// Parameters:

//

//      None

//

// Return Value:

//

//      TRUE    - Inplace active

//      FALSE   - Not Inplace active

//

// Function Calls:

//      Function                    Location

//

//      CSimpSvrDoc::GetObject      OBJ.H

//      CSimpSvrObj:IsInPlaceActive OBJ.H

//

//

// Comments:

//

//

//********************************************************************

BOOL CSimpSvrApp::IsInPlaceActive()

{

        CStabilize stabilize(this);

        BOOL retval = FALSE;

        if (m_lpDoc)

                if (m_lpDoc->GetObj())

                        retval = m_lpDoc->GetObj()->IsInPlaceActive();

        return retval;

}


 CSimpSvrApp::ShowAppWnd  (SIMPSVR Sample)

//**********************************************************************

//

// CSimpSvrApp::ShowAppWnd

//

// Purpose:

//

//      Shows the Application Window

//

// Parameters:

//

//      int nCmdShow    - Window State

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                        Location

//

//      ShowWindow                      Windows API

//      UpdateWindow                    Windows API

//      CoLockObjectExternal            OLE API

//

// Comments:

//

//********************************************************************

void CSimpSvrApp::ShowAppWnd(int nCmdShow)

{

        CoLockObjectExternal(this, TRUE, FALSE);

        ShowWindow (m_hAppWnd, nCmdShow);

        UpdateWindow (m_hAppWnd);

}


 CSimpSvrApp::ShowAppWnd  (SIMPSVR Sample)

//**********************************************************************

//

// CSimpSvrApp::ShowAppWnd

//

// Purpose:

//

//      Hides the Application Window

//

// Parameters:

//

//      None

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                        Location

//

//      ShowWindow                      Windows API

//      CoLockObjectExternal            OLE API

//

// Comments:

//

//********************************************************************

void CSimpSvrApp::HideAppWnd()

{

        CoLockObjectExternal(this, FALSE, TRUE);

        ShowWindow (m_hAppWnd, SW_HIDE);

}


 DOC.CPP  (SIMPSVR Sample)

//**********************************************************************

// File name: DOC.CPP

//

//      Implementation file for CSimpSvrDoc.

//

// Functions:

//

//      See DOC.H for Class Definition

//

// Copyright (c) 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#include "pre.h"

#include "obj.h"

#include "app.h"

#include "doc.h"


 CSimpSvrDoc::Create  (SIMPSVR Sample)

//**********************************************************************

//

// CSimpSvrDoc::Create

//

// Purpose:

//

//      Creation for the CSimpSvrDoc Class

//

// Parameters:

//

//      CSimpSvrApp FAR * lpApp  -   Pointer to the CSimpSvrApp Class

//

//      LPRECT lpRect           -   Client area rect of "frame" window

//

//      HWND hWnd               -   Window Handle of "frame" window

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                    Location

//

//      StgCreateDocfile            OLE API

//      CreateWindow                Windows API

//      ShowWindow                  Windows API

//      UpdateWindow                Windows API

//      CSimpSvrDoc::CSimpSvrDoc    DOC.CPP

//      CreateHatchWindow           OLE2UI

//

// Comments:

//

//      This routine was added so that failure could be returned

//      from object creation.

//

//********************************************************************

CSimpSvrDoc FAR * CSimpSvrDoc::Create(CSimpSvrApp FAR *lpApp, LPRECT lpRect,HWND hWnd)

{

        CSimpSvrDoc FAR * lpTemp = new CSimpSvrDoc(lpApp, hWnd);

        if (!lpTemp)

                return NULL;

        // create the document Window

        lpTemp->m_hDocWnd = CreateWindow(

                        "DocWClass",

                        NULL,

                        WS_CHILD | WS_CLIPSIBLINGS,

                        lpRect->left,

                        lpRect->top,

                        lpRect->right,

                        lpRect->bottom,

                        hWnd,

                        NULL,

                        lpApp->GethInst(),

                        NULL);

        if (!lpTemp->m_hDocWnd)

                goto error;

        lpTemp->ShowDocWnd();

        lpTemp->m_hHatchWnd = CreateHatchWindow( lpTemp->m_hDocWnd, lpApp->GethInst());

        lpTemp->HideHatchWnd();

        return (lpTemp);

error:

        delete (lpTemp);

        return NULL;

}


 CSimpSvrDoc::CSimpSvrDoc  (SIMPSVR Sample)

//**********************************************************************

//

// CSimpSvrDoc::CSimpSvrDoc

//

// Purpose:

//

//      Constructor for the CSimpSvrDoc Class

//

// Parameters:

//

//      CSimpSvrApp FAR * lpApp  -   Pointer to the CSimpSvrApp Class

//

//      HWND hWnd               -   Window Handle of "frame" window

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      GetMenu                     Windows API

//      GetSubMenu                  Windows API

//

// Comments:

//

//********************************************************************

CSimpSvrDoc::CSimpSvrDoc(CSimpSvrApp FAR * lpApp,HWND hWnd)

{

        OutputDebugString("In CSimpSvrDoc's Constructor\r\n");

        m_lpApp = lpApp;

        m_lpObj = NULL;

        m_fClosing = FALSE;

        // set up menu handles

}


 CSimpSvrDoc::~CSimpSvrDoc  (SIMPSVR Sample)

//**********************************************************************

//

// CSimpSvrDoc::~CSimpSvrDoc

//

// Purpose:

//

//      Destructor for CSimpSvrDoc

//

// Parameters:

//

//      None

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      DestroyWindow               Windows API

//      CSimpSvrApp::ClearDoc       APP.CPP

//

// Comments:

//

//********************************************************************

CSimpSvrDoc::~CSimpSvrDoc()

{

        OutputDebugString("In CSimpSvrDoc's Destructor\r\n");

        m_lpApp->ClearDoc();

        DestroyWindow(m_hHatchWnd);

}


 CSimpSvrDoc::QueryInterface  (SIMPSVR Sample)

//**********************************************************************

//

// CSimpSvrDoc::QueryInterface

//

// Purpose:

//

//      Return a pointer to a requested interface

//

// Parameters:

//

//      REFIID riid         -   ID of interface to be returned

//      LPVOID FAR* ppvObj  -   Location to return the interface

//

// Return Value:

//

//      E_NOINTERFACE -   Always

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      CSimpSvrApp::QueryInterface APP.CPP

//

// Comments:

//

//      Since the document could contain multiple objects, all

//      interfaces except those associated with the document should

//      be returned.  In this implementation, there are no doc level

//      interfaces.

//

//********************************************************************

STDMETHODIMP CSimpSvrDoc::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)

{

        OutputDebugString("In CSimpSvrDoc::QueryInterface\r\n");

        SCODE sc = E_NOINTERFACE;

        if ( (riid == IID_IUnknown) )

           {

           AddRef();

           *ppvObj = this;

           sc = S_OK;

           }

        return ResultFromScode(sc);

}


 CSimpSvrDoc::AddRef  (SIMPSVR Sample)

//**********************************************************************

//

// CSimpSvrDoc::AddRef

//

// Purpose:

//

//      Increments the document level reference count

//

// Parameters:

//

//      None

//

// Return Value:

//

//      UINT    -   The current reference count on the document

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      CSimpSvrApp::AddRef         APP.CPP

//

// Comments:

//

//      The reference count at this level reflects the total ref.

//      count of all interfaces on all objects contained within

//      this document.  Note that it also "trickles up" the

//      ref count to the app level.

//

//********************************************************************

STDMETHODIMP_(ULONG) CSimpSvrDoc::AddRef()

{

        OutputDebugString("In CSimpSvrDoc::AddRef\r\n");

        // AddRef the app, but return the doc count

        m_lpApp->AddRef();

        return SafeAddRef();

}


 CSimpSvrDoc::Release  (SIMPSVR Sample)

//**********************************************************************

//

// CSimpSvrDoc::Release

//

// Purpose:

//

//      Decrements the document level reference count

//

// Parameters:

//

//      None

//

// Return Value:

//

//      UINT    -   The current reference count on the document

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      CSimpSvrApp::Release         APP.CPP

//

// Comments:

//

//      The reference count at this level reflects the total ref.

//      count of all interfaces on all objects contained within

//      this document.  Note that it also "trickles up" the

//      ref count to the app level.

//

//********************************************************************

STDMETHODIMP_(ULONG) CSimpSvrDoc::Release()

{

        OutputDebugString("In CSimpSvrDoc::Release\r\n");

        // Release the app, but return the app count

        m_lpApp->Release();

        return SafeRelease();

}


 CSimpSvrDoc::lResizeDoc  (SIMPSVR Sample)

//**********************************************************************

//

// CSimpSvrDoc::lResizeDoc

//

// Purpose:

//

//      Resizes the document

//

// Parameters:

//

//      LPRECT lpRect   -   The size of the client are of the "frame"

//                          Window.

//

// Return Value:

//

//      NULL

//

// Function Calls:

//      Function                                Location

//

//      MoveWindow                              Windows API

//

// Comments:

//

//********************************************************************

long CSimpSvrDoc::lResizeDoc(LPRECT lpRect)

{

        MoveWindow(m_hDocWnd, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom, TRUE);

        return NULL;

}


 CSimpSvrDoc::PaintDoc  (SIMPSVR Sample)

//**********************************************************************

//

// CSimpSvrDoc::PaintDoc

//

// Purpose:

//

//      Paints the Document

//

// Parameters:

//

//      HDC hDC -   hDC of the document Window

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                    Location

//

//      CSimpSvrObj::Draw                   OBJ.CPP

//      CSimpSvrObj::GetDataAdviseHolder    OBJ.H

//      CSimpSvrObj::GetDataObject          OBJ.H

//      CSimpAppObj::IsStartedByOle         APP.CPP

//      IDataAdviseHolder::SendOnDataChange OLE API

//

// Comments:

//

//********************************************************************

void CSimpSvrDoc::PaintDoc (HDC hDC)

{

        // i_f the object hasn't been created yet, then don't draw

        if (m_lpObj)

                m_lpObj->Draw(hDC,FALSE);

        else

                return;

        CStabilize stabilize(this);

        // Sending a data change every time we paint, but only if we

        // were started by OLE

        if (m_lpApp->IsStartedByOle())

                        m_lpObj->SendOnDataChange( );

}


 CSimpSvrDoc::CreateObject  (SIMPSVR Sample)

//**********************************************************************

//

// CSimpSvrDoc::CreateObject

//

// Purpose:

//

//

// Parameters:

//

//

// Return Value:

//

//      NOERROR if the function succeeds, otherwise E_FAIL

//

// Function Calls:

//      Function                    Location

//

//      CSimpSvrObj::CSimpSvrObj    OBJ.CPP

//      CSimpSvrOjb::QueryInterface OBJ.CPP

//

// Comments:

//

//********************************************************************

HRESULT CSimpSvrDoc::CreateObject(REFIID riid, LPVOID FAR *ppvObject)

{

        SCODE sc = E_FAIL;

        m_lpObj = new CSimpSvrObj(this);

        if (m_lpObj)

                {

                m_lpObj->QueryInterface(riid, ppvObject);

                sc = S_OK;

                }

        return ResultFromScode(sc);

}


 CSimpSvrDoc::Close  (SIMPSVR Sample)

//**********************************************************************

//

// CSimpSvrDoc::Close

//

// Purpose:

//

//      Closes the object

//

// Parameters:

//

//      None

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                                Location

//

//      OutputDebugString                       Windows API

//      CSimpSvrObj::AddRef                     OBJ.CPP

//      CSimpSvrObj::Release                    OBJ.CPP

//      CSimpSvrObj::IsInPlaceActive            OBJ.H

//      CSimpSvrObj::GetOleInPlaceObject        OBJ.H

//      CSimpSvrObj::ClearOleClientSite         OBJ.H

//      CSimpSvrObj::GetDataAdviseHolder        OBJ.H

//      CSimpSvrObj::GetOleClientSite           OBJ.H

//      CSimpSvrObj::ClearDataAdviseHolder      OBJ.H

//      CSimpSvrObj::GetOleAdviseHolder         OBJ.H

//      CSimpSvrObj::ClearOleAdviseHolder       OBJ.H

//      IOleInPlaceObject::InPlaceDeactivate    Container

//      IOleClientSite::SaveObject              Container

//      IOleClientSite::OnShowWindow            Container

//      IOleClientSite::Release                 Container

//      IDataAdviseHolder::SendOnDataChange     OLE

//      IDataAdviseHolder::Release              OLE

//      IOleAdviseHolder::SendOnClose           OLE

//      IOleAdviseHolder::Release               OLE

//

// Comments:

//

//********************************************************************

void CSimpSvrDoc::Close()

{

        OutputDebugString("In CSimpSvrDoc::Close() \r\n");

        CStabilize stabilize(this);

        m_lpObj->AddRef(); // hold object alive

        if (m_fClosing)

                return;

        m_fClosing = TRUE;

        // if the object is currently inplace active, then deactivate

        if (m_lpObj->IsInPlaceActive())

                m_lpObj->GetOleInPlaceObject()->InPlaceDeactivate();

        // unregister from the ROT...

        if (m_lpObj->GetRotRegister())

                {

                LPRUNNINGOBJECTTABLE lpRot;

                if (GetRunningObjectTable (0, &lpRot) == NOERROR )

                        {

                        lpRot->Revoke(m_lpObj->GetRotRegister());

                        lpRot->Release();

                        }

                }

        // if we have a clientsite, instruct it to save the object

        if (m_lpObj->GetOleClientSite())

                {

                m_lpObj->GetOleClientSite()->SaveObject();

                m_lpObj->GetOleClientSite()->OnShowWindow(FALSE);

                }

        // Do a final SendOnDataChange for those containers that have specified the

        // ADF_DATAONSTOP flag.

        if (m_lpObj->GetDataAdviseHolder())

                {

                m_lpObj->GetDataAdviseHolder()->SendOnDataChange( m_lpObj->GetDataObject(), 0, ADVF_DATAONSTOP);

                m_lpObj->GetDataAdviseHolder()->Release();

                m_lpObj->ClearDataAdviseHolder();

                }

        // Tell the container that we are shutting down.

        if (m_lpObj->GetOleAdviseHolder())

                {

                m_lpObj->GetOleAdviseHolder()->SendOnClose();

                m_lpObj->GetOleAdviseHolder()->Release();

                m_lpObj->ClearOleAdviseHolder();

                }

        if (m_lpObj->GetOleClientSite())

                {

                m_lpObj->GetOleClientSite()->Release();

                m_lpObj->ClearOleClientSite();

                }

        // release our streams and storage

        m_lpObj->GetPersistStorage()->ReleaseStreamsAndStorage();

        // Disconnect the object.  NOTE: This call should not do anything

        // unless the container has cause a GP Fault or some other problem

        // has occured...

        OutputDebugString("*** Before CoDisconnectObject *** \r\n");

        CoDisconnectObject((LPUNKNOWN)m_lpObj, 0);

        OutputDebugString("*** After CoDisconnectObject *** \r\n");

        m_lpObj->Release(); // let object close

}


 CSimpSvrDoc::SetStatusText  (SIMPSVR Sample)

//**********************************************************************

//

// CSimpSvrDoc::SetStatusText

//

// Purpose:

//

//      Sets the Container's status bar text

//

// Parameters:

//

//      None

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                        Location

//

//      CSimpSvrObj::IsInPlaceActive    OBJ.CPP

//      IOleInPlaceFrame::SetStatusText Container

//

// Comments:

//

//      Even though there is no status line in this sample, this

//      method must be called on WM_MENUSELECT to clear the last

//      message in the status line.

//

//********************************************************************

void CSimpSvrDoc::SetStatusText()

{

        CStabilize stabilize(this);

        if (m_lpObj->IsInPlaceActive())

                //@@WTK WIN32, UNICODE

                //m_lpObj->GetInPlaceFrame()->SetStatusText("\0");

                m_lpObj->GetInPlaceFrame()->SetStatusText(OLESTR("\0"));

}


 CSimpSvrDoc::ShowDocWnd  (SIMPSVR Sample)

//**********************************************************************

//

// CSimpSvrDoc::ShowDocWnd

//

// Purpose:

//

//      Shows the Document Window

//

// Parameters:

//

//      None

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                        Location

//

//      ShowWindow                      Windows API

//      UpdateWindow                    Windows API

//

// Comments:

//

//********************************************************************

void CSimpSvrDoc::ShowDocWnd()

{

        ShowWindow(m_hDocWnd, SW_SHOWNORMAL);  // Show the window

        UpdateWindow(m_hDocWnd);               // Sends WM_PAINT message

}


 CSimpSvrDoc::ShowHatchWnd  (SIMPSVR Sample)

//**********************************************************************

//

// CSimpSvrDoc::ShowHatchWnd

//

// Purpose:

//

//      Shows the hatch Window

//

// Parameters:

//

//      None

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                        Location

//

//      ShowWindow                      Windows API

//

// Comments:

//

//********************************************************************

void CSimpSvrDoc::ShowHatchWnd()

{

        ShowWindow(m_hHatchWnd, SW_SHOW);

}


 CSimpSvrDoc::HideDocWnd  (SIMPSVR Sample)

//**********************************************************************

//

// CSimpSvrDoc::HideDocWnd

//

// Purpose:

//

//      Hides the DocumentWindow

//

// Parameters:

//

//      None

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                        Location

//

//      ShowWindow                      Windows API

//

// Comments:

//

//********************************************************************

void CSimpSvrDoc::HideDocWnd()

{

        ShowWindow(m_hDocWnd, SW_HIDE);

}


 CSimpSvrDoc::HideHatchWnd  (SIMPSVR Sample)

//**********************************************************************

//

// CSimpSvrDoc::HideHatchWnd

//

// Purpose:

//

//      Hides the Hatch Window

//

// Parameters:

//

//      None

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                        Location

//

//      ShowWindow                      Windows API

//

// Comments:

//

//********************************************************************

void CSimpSvrDoc::HideHatchWnd()

{

        ShowWindow(m_hHatchWnd, SW_HIDE);

}


 ICF.CPP  (SIMPSVR Sample)

//**********************************************************************

// File name: ICF.CPP

//

//    Implementation file for the CClassFactory Class

//

// Functions:

//

//    See icf.h for a list of member functions.

//

// Copyright (c) 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#include "pre.h"

#include "app.h"

#include "doc.h"

#include "icf.h"


 CClassFactory::QueryInterface  (SIMPSVR Sample)

//**********************************************************************

//

// CClassFactory::QueryInterface

//

// Purpose:

//

//

// Parameters:

//

//      REFIID riid         -   Interface being queried for.

//

//      LPVOID FAR *ppvObj  -   Out pointer for the interface.

//

// Return Value:

//

//      S_OK            - Success

//      E_NOINTERFACE   - Failure

//

// Function Calls:

//      Function                    Location

//

//      CSimpSvrApp::QueryInterface APP.CPP

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP CClassFactory::QueryInterface  ( REFIID riid, LPVOID FAR* ppvObj)

{

OutputDebugString("In CClassFactory::QueryInterface\r\n");

SCODE sc = S_OK;

if ( (riid == IID_IUnknown) ||

 (riid == IID_IClassFactory) )

*ppvObj = this;

else

{

*ppvObj = NULL;

sc = E_NOINTERFACE;

}

if (*ppvObj)

((LPUNKNOWN)*ppvObj)->AddRef();

// pass it on to the Application object

return ResultFromScode(sc);

};


 CClassFactory::AddRef  (SIMPSVR Sample)

//**********************************************************************

//

// CClassFactory::AddRef

//

// Purpose:

//

//      Increments the reference count on CClassFactory and the application

//      object.

//

// Parameters:

//

//      None

//

// Return Value:

//

//      The Reference count on CClassFactory

//

// Function Calls:

//      Function                    Location

//

//      OuputDebugString            Windows API

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP_(ULONG) CClassFactory::AddRef ()

{

OutputDebugString("In CClassFactory::AddRef\r\n");

return ++m_nCount;

};


 CClassFactory::Release  (SIMPSVR Sample)

//**********************************************************************

//

// CClassFactory::Release

//

// Purpose:

//

//      Decrements the reference count of CClassFactory and the

//      application object.

//

// Parameters:

//

//      None

//

// Return Value:

//

//      The new reference count

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP_(ULONG) CClassFactory::Release ()

{

OutputDebugString("In CClassFactory::Release\r\n");

if (--m_nCount == 0) {

delete this;

        return 0;

    }

return m_nCount;

};


 CClassFactory::CreateInstance  (SIMPSVR Sample)

//**********************************************************************

//

// CClassFactory::CreateInstance

//

// Purpose:

//

//      Instantiates a new OLE object

//

// Parameters:

//

//      LPUNKNOWN pUnkOuter     - Pointer to the controlling unknown

//

//      REFIID riid             - The interface type to fill in ppvObject

//

//      LPVOID FAR* ppvObject   - Out pointer for the object

//

// Return Value:

//

//      S_OK                    - Creation was successful

//      CLASS_E_NOAGGREGATION   - Tried to be created as part of an aggregate

//

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      CSimpSvrDoc::CreateObject   DOC.CPP

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP CClassFactory::CreateInstance ( LPUNKNOWN pUnkOuter,

  REFIID riid,

  LPVOID FAR* ppvObject)

{

HRESULT hErr;

OutputDebugString("In CClassFactory::CreateInstance\r\n");

// need to NULL the out parameter

*ppvObject = NULL;

// we don't support aggregation...

if (pUnkOuter)

{

hErr = ResultFromScode(CLASS_E_NOAGGREGATION);

goto error;

}

hErr = m_lpApp->m_lpDoc->CreateObject(riid, ppvObject);

error:

return hErr;

};


 CClassFactory::LockServer  (SIMPSVR Sample)

//**********************************************************************

//

// CClassFactory::LockServer

//

// Purpose:

//

//

// Parameters:

//

//      BOOL fLock      - TRUE to lock the server, FALSE to unlock it

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      CoLockObjectExternal        OLE API

//      ResultFromScode             OLE API

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP CClassFactory::LockServer ( BOOL fLock)

{

OutputDebugString("In CClassFactory::LockServer\r\n");

CoLockObjectExternal(m_lpApp, fLock, TRUE);

return ResultFromScode( S_OK);

};


 IDO.CPP  (SIMPSVR Sample)

//**********************************************************************

// File name: IDO.CPP

//

//    Implementation file for the CDataObject Class

//

// Functions:

//

//    See ido.h for a list of member functions.

//

// Copyright (c) 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#include "pre.h"

#include "obj.h"

#include "ido.h"

#include "app.h"

#include "doc.h"


 CDataObject::QueryInterface  (SIMPSVR Sample)

//**********************************************************************

//

// CDataObject::QueryInterface

//

// Purpose:

//

//

// Parameters:

//

//      REFIID riid         -   Interface being queried for.

//

//      LPVOID FAR *ppvObj  -   Out pointer for the interface.

//

// Return Value:

//

//      S_OK            - Success

//      E_NOINTERFACE   - Failure

//

// Function Calls:

//      Function                    Location

//

//      CSimpSvrObj::QueryInterface OBJ.CPP

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP CDataObject::QueryInterface ( REFIID riid, LPVOID FAR* ppvObj)

{

OutputDebugString("In CDataObject::QueryInterface\r\n");

return m_lpObj->QueryInterface(riid, ppvObj);

};


 CDataObject::AddRef  (SIMPSVR Sample)

//**********************************************************************

//

// CDataObject::AddRef

//

// Purpose:

//

//      Increments the reference count on CClassFactory and the application

//      object.

//

// Parameters:

//

//      None

//

// Return Value:

//

//      The Reference count on CDataObject

//

// Function Calls:

//      Function                    Location

//

//      OuputDebugString            Windows API

//      CSimpSvrObj::AddRef         OBJ.CPP

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP_(ULONG) CDataObject::AddRef ()

{

OutputDebugString("In CDataObject::AddRef\r\n");

++m_nCount;

return m_lpObj->AddRef();

};


 CDataObject::Release  (SIMPSVR Sample)

//**********************************************************************

//

// CDataObject::Release

//

// Purpose:

//

//      Decrements the reference count of CDataObject

//

// Parameters:

//

//      None

//

// Return Value:

//

//      The new reference count

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      CSimpSvrObj::Release        OBJ.CPP

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP_(ULONG) CDataObject::Release ()

{

OutputDebugString("In CDataObject::Release\r\n");

--m_nCount;

return m_lpObj->Release();

};


 CDataObject::QueryGetData  (SIMPSVR Sample)

//**********************************************************************

//

// CDataObject::QueryGetData

//

// Purpose:

//

//      Called to determine if our object supports a particular

//      FORMATETC.

//

// Parameters:

//

//      LPFORMATETC pformatetc  - Pointer to the FORMATETC being queried for.

//

// Return Value:

//

//      DATA_E_FORMATETC    - The FORMATETC is not supported

//      S_OK                - The FORMATETC is supported.

//

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      ResultFromScode             OLE API

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP CDataObject::QueryGetData  ( LPFORMATETC pformatetc )

{

SCODE sc = DATA_E_FORMATETC;

OutputDebugString("In CDataObject::QueryGetData\r\n");

// check the validity of the formatetc.

if ( (pformatetc->cfFormat == CF_METAFILEPICT)  &&

 (pformatetc->dwAspect == DVASPECT_CONTENT) &&

 (pformatetc->tymed == TYMED_MFPICT) )

sc = S_OK;

return ResultFromScode(sc);

};


 CDataObject::DAdvise  (SIMPSVR Sample)

//**********************************************************************

//

// CDataObject::DAdvise

//

// Purpose:

//

//      Called by the container when it would like to be notified of

//      changes in the object data.

//

// Parameters:

//

//      FORMATETC FAR* pFormatetc   - The format the container is interested in.

//

//      DWORD advf                  - The type of advise to be set up.

//

//      LPADVISESINK pAdvSink       - Pointer to the containers IAdviseSink

//

//      DWORD FAR* pdwConnection    - Out parameter to return a unique connection id.

//

// Return Value:

//

//      passed on from IDataAdviseHolder

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      CreateDataAdviseHolder      OLE API

//      IDataAdviseHolder::Advise   OLE API

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP CDataObject::DAdvise  ( FORMATETC FAR* pFormatetc, DWORD advf,

 LPADVISESINK pAdvSink, DWORD FAR* pdwConnection)

{

OutputDebugString("In CDataObject::DAdvise\r\n");

// if no DataAdviseHolder has been created, then create one.

if (!m_lpObj->m_lpDataAdviseHolder)

CreateDataAdviseHolder(&m_lpObj->m_lpDataAdviseHolder);

// pass on to the DataAdviseHolder

return m_lpObj->m_lpDataAdviseHolder->Advise( this, pFormatetc, advf,

  pAdvSink, pdwConnection);

}


 CDataObject::GetData  (SIMPSVR Sample)

//**********************************************************************

//

// CDataObject::GetData

//

// Purpose:

//

//      Returns the data in the format specified in pformatetcIn.

//

// Parameters:

//

//      LPFORMATETC pformatetcIn    -   The format requested by the caller

//

//      LPSTGMEDIUM pmedium         -   The medium requested by the caller

//

// Return Value:

//

//      DATA_E_FORMATETC    - Format not supported

//      S_OK                - Success

//

// Function Calls:

//      Function                        Location

//

//      OutputDebugString               Windows API

//      CSimpSvrObj::GetMetaFilePict()  OBJ.CPP

//      ResultFromScode                 OLE API

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP CDataObject::GetData  ( LPFORMATETC pformatetcIn, LPSTGMEDIUM pmedium )

{

SCODE sc = DATA_E_FORMATETC;

OutputDebugString("In CDataObject::GetData\r\n");

// Check to the FORMATETC and fill pmedium if valid.

if ( (pformatetcIn->cfFormat == CF_METAFILEPICT)  &&

 (pformatetcIn->dwAspect == DVASPECT_CONTENT) &&

 (pformatetcIn->tymed & TYMED_MFPICT) )

{

HANDLE hmfPict = m_lpObj->GetMetaFilePict();

pmedium->tymed = TYMED_MFPICT;

pmedium->hGlobal = hmfPict;

pmedium->pUnkForRelease = NULL;

sc = S_OK;

}

return ResultFromScode( sc );

};


 CDataObject::DUnadvise  (SIMPSVR Sample)

//**********************************************************************

//

// CDataObject::DUnadvise

//

// Purpose:

//

//      Breaks down an Advise connection.

//

// Parameters:

//

//      DWORD dwConnection  - Advise connection ID.

//

// Return Value:

//

//      Returned from the DataAdviseHolder.

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      IDataAdviseHolder::Unadvise OLE

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP CDataObject::DUnadvise  ( DWORD dwConnection)

{

OutputDebugString("In CDataObject::DUnadvise\r\n");

return m_lpObj->m_lpDataAdviseHolder->Unadvise(dwConnection);

};


 CDataObject::GetDataHere  (SIMPSVR Sample)

//**********************************************************************

//

// CDataObject::GetDataHere

//

// Purpose:

//

//      Called to get a data format in a caller supplied location

//

// Parameters:

//

//      LPFORMATETC pformatetc  - FORMATETC requested

//

//      LPSTGMEDIUM pmedium     - Medium to return the data

//

// Return Value:

//

//      DATA_E_FORMATETC    - We don't support the requested format

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//      In this simple implementation, we don't really support this

//      method, we just always return DATA_E_FORMATETC.

//

//********************************************************************

STDMETHODIMP CDataObject::GetDataHere  ( LPFORMATETC pformatetc,

 LPSTGMEDIUM pmedium )

{

OutputDebugString("In CDataObject::GetDataHere\r\n");

return ResultFromScode( DATA_E_FORMATETC);

};


 CDataObject::GetCanonicalFormatEtc  (SIMPSVR Sample)

//**********************************************************************

//

// CDataObject::GetCanonicalFormatEtc

//

// Purpose:

//

//      Returns a FORMATETC that is equivalent to the one passed in.

//

// Parameters:

//

//      LPFORMATETC pformatetc      - FORMATETC to be tested.

//

//      LPFORMATETC pformatetcOut   - Out ptr for returned FORMATETC.

//

// Return Value:

//

//      DATA_S_SAMEFORMATETC    - Use the same formatetc as was passed.

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      CoGetMalloc                 OLE API

//      IMalloc::Alloc              OLE

//      IMalloc::Release            OLE

//      _fmemcpy                    C run-time

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP CDataObject::GetCanonicalFormatEtc  ( LPFORMATETC pformatetc,

   LPFORMATETC pformatetcOut)

{

HRESULT hresult;

OutputDebugString("In CDataObject::GetCanonicalFormatEtc\r\n");

if (!pformatetcOut)

return ResultFromScode(E_INVALIDARG);

/* OLE2NOTE: we must make sure to set all out parameters to NULL. */

pformatetcOut->ptd = NULL;

if (!pformatetc)

return ResultFromScode(E_INVALIDARG);

// OLE2NOTE: we must validate that the format requested is supported

if ((hresult = QueryGetData(pformatetc)) != NOERROR)

return hresult;

/* OLE2NOTE: an app that is insensitive to target device (as

**    SimpSvr is) should fill in the lpformatOut parameter

**    but NULL out the "ptd" field; it should return NOERROR if the

**    input formatetc->ptd what non-NULL. this tells the caller

**    that it is NOT necessary to maintain a separate screen

**    rendering and printer rendering. if should return

**    DATA_S_SAMEFORMATETC if the input and output formatetc's are

**    identical.

*/

*pformatetcOut = *pformatetc;

if (pformatetc->ptd == NULL)

return ResultFromScode(DATA_S_SAMEFORMATETC);

else

{

pformatetcOut->ptd = NULL;

return NOERROR;

}

};


 CDataObject::SetData  (SIMPSVR Sample)

//**********************************************************************

//

// CDataObject::SetData

//

// Purpose:

//

//      Called to set the data for the object.

//

// Parameters:

//

//      LPFORMATETC pformatetc      - the format of the data being passed

//

//      STGMEDIUM FAR * pmedium     - the location of the data.

//

//      BOOL fRelease               - Defines the ownership of the medium

//

// Return Value:

//

//      DATA_E_FORMATETC    - Not a valid FORMATETC for this object

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//      This simple object does not support having its data set, so an

//      error value is always returned.

//

//********************************************************************

STDMETHODIMP CDataObject::SetData  ( LPFORMATETC pformatetc, STGMEDIUM FAR * pmedium,

 BOOL fRelease)

{

OutputDebugString("In CDataObject::SetData\r\n");

return ResultFromScode( DATA_E_FORMATETC );

};


 CDataObject::EnumFormatEtc  (SIMPSVR Sample)

//**********************************************************************

//

// CDataObject::EnumFormatEtc

//

// Purpose:

//

//      Enumerates the formats supported by this object.

//

// Parameters:

//

//      DWORD dwDirection                       - Order of enumeration.

//

//      LPENUMFORMATETC FAR* ppenumFormatEtc    - Place to return a pointer

//                                                to the enumerator.

//

// Return Value:

//

//      OLE_S_USEREG    - Indicates that OLE should consult the REG DB

//                        to enumerate the formats.

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP CDataObject::EnumFormatEtc  ( DWORD dwDirection,

   LPENUMFORMATETC FAR* ppenumFormatEtc)

{

OutputDebugString("In CDataObject::EnumFormatEtc\r\n");

// need to NULL the out parameter

*ppenumFormatEtc = NULL;

return ResultFromScode( OLE_S_USEREG );

};


 CDataObject::EnumDAdvise  (SIMPSVR Sample)

//**********************************************************************

//

// CDataObject::EnumDAdvise

//

// Purpose:

//

//      Returns an enumerator that enumerates all of the advises

//      set up on this data object.

//

// Parameters:

//

//      LPENUMSTATDATA FAR* ppenumAdvise    - An out ptr in which to

//                                            return the enumerator.

//

// Return Value:

//

//      Passed back from IDataAdviseHolder::EnumAdvise

//

// Function Calls:

//      Function                        Location

//

//      OutputDebugString               Windows API

//      IDAtaAdviseHolder::EnumAdvise   OLE

//

// Comments:

//

//      This just delegates to the DataAdviseHolder.

//

//********************************************************************

STDMETHODIMP CDataObject::EnumDAdvise  ( LPENUMSTATDATA FAR* ppenumAdvise)

{

OutputDebugString("In CDataObject::EnumDAdvise\r\n");

// need to NULL the out parameter

*ppenumAdvise = NULL;

return m_lpObj->m_lpDataAdviseHolder->EnumAdvise(ppenumAdvise);

};


 IEC.CPP  (SIMPSVR Sample)

//**********************************************************************

// File name: IEC.CPP

//

//    Implementation file for the CExternalConnection Class

//

// Functions:

//

//    See iec.h for a list of member functions.

//

// Copyright (c) 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#include "pre.h"

#include "obj.h"

#include "iec.h"

#include "app.h"

#include "doc.h"


 CExternalConnection::QueryInterface  (SIMPSVR Sample)

//**********************************************************************

//

// CExternalConnection::QueryInterface

//

// Purpose:

//

//

// Parameters:

//

//      REFIID riid         -   Interface being queried for.

//

//      LPVOID FAR *ppvObj  -   Out pointer for the interface.

//

// Return Value:

//

//      S_OK            - Success

//      E_NOINTERFACE   - Failure

//

// Function Calls:

//      Function                    Location

//

//      CSimpSvrObj::QueryInterface OBJ.CPP

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP CExternalConnection::QueryInterface (REFIID riid, LPVOID FAR* ppvObj)

{

OutputDebugString("In CExternalConnection::QueryInterface\r\n");

return m_lpObj->QueryInterface(riid, ppvObj);

}


 CExternalConnection::AddRef  (SIMPSVR Sample)

//**********************************************************************

//

// CExternalConnection::AddRef

//

// Purpose:

//

//      Increments the reference count on CExternalConnection and the "object"

//      object.

//

// Parameters:

//

//      None

//

// Return Value:

//

//      The Reference count on the Object.

//

// Function Calls:

//      Function                    Location

//

//      OuputDebugString            Windows API

//      CSimpSvrObj::AddRef         OBJ.CPP

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP_(ULONG) CExternalConnection::AddRef ()

{

OutputDebugString("In CExternalConnection::AddRef\r\n");

++m_nCount;

return m_lpObj->AddRef();

};


 CExternalConnection::Release  (SIMPSVR Sample)

//**********************************************************************

//

// CExternalConnection::Release

//

// Purpose:

//

//      Decrements the reference count of COleObject and the

//      "object" object.

//

// Parameters:

//

//      None

//

// Return Value:

//

//      The new reference count

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      CSimpSvrObj::Release        OBJ.CPP

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP_(ULONG) CExternalConnection::Release ()

{

OutputDebugString("In CExternalConnection::Release\r\n");

--m_nCount;

return m_lpObj->Release();

};


 CExternalConnection::AddConnection  (SIMPSVR Sample)

//**********************************************************************

//

// CExternalConnection::AddConnection

//

// Purpose:

//

//      Called when another connection is made to the object.

//

// Parameters:

//

//      DWORD extconn   -   Type of connection

//

//      DWORD reserved  -   Reserved

//

// Return Value:

//

//      Strong connection count

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP_(DWORD) CExternalConnection::AddConnection (DWORD extconn, DWORD reserved)

{

OutputDebugString("In CExternalConnection::AddConnection\r\n");

if (extconn & EXTCONN_STRONG)

return ++m_dwStrong;

return 0;

}


 CExternalConnection::ReleaseConnection  (SIMPSVR Sample)

//**********************************************************************

//

// CExternalConnection::ReleaseConnection

//

// Purpose:

//

//      Called when a connection to the object is released.

//

// Parameters:

//

//      DWORD extconn               - Type of Connection

//

//      DWORD reserved              - Reserved

//

//      BOOL fLastReleaseCloses     - Close flag

//

// Return Value:

//

//      The new reference count

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      COleObject::Close           IOO.CPP

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP_(DWORD) CExternalConnection::ReleaseConnection (DWORD extconn, DWORD reserved, BOOL fLastReleaseCloses)

{

OutputDebugString("In CExternalConnection::ReleaseConnection\r\n");

if (extconn & EXTCONN_STRONG)

{

DWORD dwSave = --m_dwStrong;

if (!m_dwStrong && fLastReleaseCloses)

m_lpObj->m_OleObject.Close(OLECLOSE_SAVEIFDIRTY);

return dwSave;

}

return 0;

}


 IOIPAO.CPP  (SIMPSVR Sample)

//**********************************************************************

// File name: IOIPAO.CPP

//

//    Implementation file for the CClassFactory Class

//

// Functions:

//

//    See ioipao.h for a list of member functions.

//

// Copyright (c) 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#include "pre.h"

#include "obj.h"

#include "ioipao.h"

#include "app.h"

#include "doc.h"


 COleInPlaceActiveObject::QueryInterface  (SIMPSVR Sample)

//**********************************************************************

//

// COleInPlaceActiveObject::QueryInterface

//

// Purpose:

//

//

// Parameters:

//

//      REFIID riid         -   Interface being queried for.

//

//      LPVOID FAR *ppvObj  -   Out pointer for the interface.

//

// Return Value:

//

//      S_OK            - Success

//      E_NOINTERFACE   - Failure

//

// Function Calls:

//      Function                    Location

//

//      CSimpSvrObj::QueryInterface OBJ.CPP

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP COleInPlaceActiveObject::QueryInterface ( REFIID riid, LPVOID FAR* ppvObj)

{

OutputDebugString("In COleInPlaceActiveObject::QueryInterface\r\n");

// need to NULL the out parameter

return m_lpObj->QueryInterface(riid, ppvObj);

}


 COleInPlaceActiveObject::AddRef  (SIMPSVR Sample)

//**********************************************************************

//

// COleInPlaceActiveObject::AddRef

//

// Purpose:

//

//      Increments the reference count on COleInPlaceActiveObject and the

//      "object" object.

//

// Parameters:

//

//      None

//

// Return Value:

//

//      The Reference count on the "object" object.

//

// Function Calls:

//      Function                    Location

//

//      OuputDebugString            Windows API

//      CSimpSvrObj::AddRef         OBJ.CPP

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP_(ULONG) COleInPlaceActiveObject::AddRef ()

{

OutputDebugString("In COleInPlaceActiveObject::AddRef\r\n");

++m_nCount;

return m_lpObj->AddRef();

}


 COleInPlaceActiveObject::Release  (SIMPSVR Sample)

//**********************************************************************

//

// COleInPlaceActiveObject::Release

//

// Purpose:

//

//      Decrements the reference count of COleInPlaceActiveObject.

//

// Parameters:

//

//      None

//

// Return Value:

//

//      The new reference count

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      CSimpSvrObj::Release        OBJ.CPP

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP_(ULONG) COleInPlaceActiveObject::Release ()

{

OutputDebugString("In COleInPlaceActiveObject::Release\r\n");

--m_nCount;

return m_lpObj->Release();

}


 COleInPlaceActiveObject::OnDocWindowActivate  (SIMPSVR Sample)

//**********************************************************************

//

// COleInPlaceActiveObject::OnDocWindowActivate

//

// Purpose:

//

//      Called when the doc window (in an MDI App) is (de)activated.

//

// Parameters:

//

//      BOOL fActivate  - TRUE if activating, FALSE if deactivating

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                            Location

//

//      OutputDebugString                   Windows API

//      IOleInPlaceFrame::SetActiveObject   Container

//      CSimpSvrObject::AddFrameLevelUI     OBJ.CPP

//

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP COleInPlaceActiveObject::OnDocWindowActivate  ( BOOL fActivate )

{

OutputDebugString("In COleInPlaceActiveObject::OnDocWindowActivate\r\n");

// Activating?

if (fActivate)

m_lpObj->AddFrameLevelUI();

// No frame level tools to remove...

return ResultFromScode(S_OK);

};


 COleInPlaceActiveObject::OnFrameWindowActivate  (SIMPSVR Sample)

//**********************************************************************

//

// COleInPlaceActiveObject::OnFrameWindowActivate

//

// Purpose:

//

//      Called when the Frame window is (de)activating

//

// Parameters:

//

//      BOOL fActivate  - TRUE if activating, FALSE if Deactivating

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      SetFocus                    Windows API

//

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP COleInPlaceActiveObject::OnFrameWindowActivate  ( BOOL fActivate)

{

OutputDebugString("In COleInPlaceActiveObject::OnFrameWindowActivate\r\n");

// set the focus to the object window if we are activating.

/*    if (fActivate)

SetFocus(m_lpObj->m_lpDoc->GethDocWnd()); */

return ResultFromScode( S_OK );

};


 COleInPlaceActiveObject::GetWindow  (SIMPSVR Sample)

//**********************************************************************

//

// COleInPlaceActiveObject::GetWindow

//

// Purpose:

//

//      Gets the objects Window Handle.

//

// Parameters:

//

//      HWND FAR* lphwnd    - Location to return the window handle.

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      CSimpSvrDoc::GethDocWnd     DOC.H

//

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP COleInPlaceActiveObject::GetWindow  ( HWND FAR* lphwnd)

{

OutputDebugString("In COleInPlaceActiveObject::GetWindow\r\n");

// need to NULL the out parameter

*lphwnd = m_lpObj->m_lpDoc->GethDocWnd();

return ResultFromScode( S_OK );

};


 COleInPlaceActiveObject::ContextSensitiveHelp  (SIMPSVR Sample)

//**********************************************************************

//

// COleInPlaceActiveObject::ContextSensitiveHelp

//

// Purpose:

//

//      Used to implement Context Sensitive help

//

// Parameters:

//

//      None

//

// Return Value:

//

//      E_NOTIMPL

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

//

// Comments:

//

//      See TECHNOTES.WRI include with the OLE SDK for proper

//      implementation of this function.

//

//********************************************************************

STDMETHODIMP COleInPlaceActiveObject::ContextSensitiveHelp  ( BOOL fEnterMode )

{

OutputDebugString("In COleInPlaceActiveObject::ContextSensitiveHelp\r\n");

return ResultFromScode( E_NOTIMPL);

};


 COleInPlaceActiveObject::TranslateAccelerator  (SIMPSVR Sample)

//**********************************************************************

//

// COleInPlaceActiveObject::TranslateAccelerator

//

// Purpose:

//

//      Used for translating accelerators in .DLL objects.

//

// Parameters:

//

//      LPMSG lpmsg - Pointer to a message

//

// Return Value:

//

//      S_FALSE

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

//

// Comments:

//

//      This method should never be called since we are implemented

//      in an executable.

//

//********************************************************************

STDMETHODIMP COleInPlaceActiveObject::TranslateAccelerator  ( LPMSG lpmsg)

{

OutputDebugString("In COleInPlaceActiveObject::TranslateAccelerator\r\n");

// no accelerator table, return FALSE

return ResultFromScode( S_FALSE );

};


 COleInPlaceActiveObject::ResizeBorder  (SIMPSVR Sample)

//**********************************************************************

//

// COleInPlaceActiveObject::ResizeBorder

//

// Purpose:

//

//      Called when the border changes size.

//

// Parameters:

//

//      LPCRECT lprectBorder                - New Border

//

//      LPOLEINPLACEUIWINDOW lpUIWindow     - Pointer to UIWindow

//

//      BOOL fFrameWindow                   - True if lpUIWindow is the

//                                            frame window.

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

//

// Comments:

//

//      Need to call SetBorderSpace again...

//

//********************************************************************

STDMETHODIMP COleInPlaceActiveObject::ResizeBorder  ( LPCRECT lprectBorder,

  LPOLEINPLACEUIWINDOW lpUIWindow,

  BOOL fFrameWindow)

{

OutputDebugString("In COleInPlaceActiveObject::ResizeBorder\r\n");

// should always have an inplace frame...

m_lpObj->GetInPlaceFrame()->SetBorderSpace(NULL);

// There will only be a UIWindow if in an MDI container

if (m_lpObj->GetUIWindow())

m_lpObj->GetUIWindow()->SetBorderSpace(NULL);

return ResultFromScode( S_OK );

};


 COleInPlaceActiveObject::EnableModeless  (SIMPSVR Sample)

//**********************************************************************

//

// COleInPlaceActiveObject::EnableModeless

//

// Purpose:

//

//      Called to enable/disable modeless dialogs.

//

// Parameters:

//

//      BOOL fEnable    - TRUE to enable, FALSE to disable

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

//

// Comments:

//

//      Called by the container when a model dialog box is added/removed

//      from the screen.  The appropriate action for a server application

//      is to disable/enable any modeless dialogs currently being displayed.

//      Since this application doesn't display any modeless dialogs,

//      this method is essentially ignored.

//

//********************************************************************

STDMETHODIMP COleInPlaceActiveObject::EnableModeless  ( BOOL fEnable)

{

OutputDebugString("In COleInPlaceActiveObject::EnableModeless\r\n");

return ResultFromScode( S_OK );

};


 IOIPO.CPP  (SIMPSVR Sample)

//**********************************************************************

// File name: IOIPO.CPP

//

//    Implementation file for the CClassFactory Class

//

// Functions:

//

//    See ioipo.h for a list of member functions.

//

// Copyright (c) 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#include "pre.h"

#include "obj.h"

#include "ioipo.h"

#include "app.h"

#include "doc.h"

#include "math.h"


 COleInPlaceObject::QueryInterface  (SIMPSVR Sample)

//**********************************************************************

//

// COleInPlaceObject::QueryInterface

//

// Purpose:

//

//

// Parameters:

//

//      REFIID riid         -   Interface being queried for.

//

//      LPVOID FAR *ppvObj  -   Out pointer for the interface.

//

// Return Value:

//

//      S_OK            - Success

//      E_NOINTERFACE   - Failure

//

// Function Calls:

//      Function                    Location

//

//      CSimpSvrObj::QueryInterface OBJ.CPP

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP COleInPlaceObject::QueryInterface ( REFIID riid, LPVOID FAR* ppvObj)

{

OutputDebugString("In COleInPlaceObject::QueryInterface\r\n");

// need to NULL the out parameter

*ppvObj = NULL;

return m_lpObj->QueryInterface(riid, ppvObj);

}


 COleInPlaceObject::AddRef  (SIMPSVR Sample)

//**********************************************************************

//

// COleInPlaceObject::AddRef

//

// Purpose:

//

//      Increments the reference count on COleInPlaceObject and the "object"

//      object.

//

// Parameters:

//

//      None

//

// Return Value:

//

//      The Reference count on the Object

//

// Function Calls:

//      Function                    Location

//

//      OuputDebugString            Windows API

//      CSimpSvrObj::AddRef         OBJ.CPP

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP_(ULONG) COleInPlaceObject::AddRef ()

{

OutputDebugString("In COleInPlaceObject::AddRef\r\n");

++m_nCount;

return m_lpObj->AddRef();

}


 COleInPlaceObject::Release  (SIMPSVR Sample)

//**********************************************************************

//

// COleInPlaceObject::Release

//

// Purpose:

//

//      Decrements the reference count of COleInPlaceObject and the

//      object.

//

// Parameters:

//

//      None

//

// Return Value:

//

//      The new reference count

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      CSimpSvrObj::Release        OBJ.CPP

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP_(ULONG) COleInPlaceObject::Release ()

{

OutputDebugString("In COleInPlaceObject::Release\r\n");

--m_nCount;

return m_lpObj->Release();

}


 COleInPlaceObject::InPlaceDeactivate  (SIMPSVR Sample)

//**********************************************************************

//

// COleInPlaceObject::InPlaceDeactivate

//

// Purpose:

//

//      Called to deactivat the object

//

// Parameters:

//

//      None

//

// Return Value:

//

//

//

// Function Calls:

//      Function                                Location

//

//      OutputDebugString                       Windows API

//      IOleClientSite::QueryInterface          Container

//      IOleInPlaceSite::OnInPlaceDeactivate    Container

//      IOleInPlaceSite::Release                Container

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP COleInPlaceObject::InPlaceDeactivate()

{

 OutputDebugString("In COleInPlaceObject::InPlaceDeactivate\r\n");

 // if not inplace active, return NOERROR

 if (!m_lpObj->m_fInPlaceActive)

 return NOERROR;

 // clear inplace flag

 m_lpObj->m_fInPlaceActive = FALSE;

 // deactivate the UI

 m_lpObj->DeactivateUI();

 m_lpObj->DoInPlaceHide();

 // tell the container that we are deactivating.

 if (m_lpObj->m_lpIPSite)

 {

 m_lpObj->m_lpIPSite->OnInPlaceDeactivate();

 m_lpObj->m_lpIPSite->Release();

 m_lpObj->m_lpIPSite =NULL;

 }

return ResultFromScode(S_OK);

}


 COleInPlaceObject::UIDeactivate  (SIMPSVR Sample)

//**********************************************************************

//

// COleInPlaceObject::UIDeactivate

//

// Purpose:

//

//      Instructs us to remove our UI.

//

// Parameters:

//

//      None

//

// Return Value:

//

//      NOERROR

//

// Function Calls:

//      Function                                Location

//

//      OutputDebugString                       Windows API

//      IOleInPlaceUIWindow::SetActiveObject    Container

//      IOleInPlaceFrame::SetActiveObject       Container

//      IOleClientSite::QueryInterface          Container

//      IOleInPlaceSite::OnUIDeactivate         Container

//      IOleInPlaceSite::Release                Container

//      CSimpSvrObj::DoInPlaceHide              OBJ.H

//      IDataAdviseHolder::SendOnDataChange     OLE

//

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP COleInPlaceObject::UIDeactivate()

{

OutputDebugString("In COleInPlaceObject::UIDeactivate\r\n");

m_lpObj->DeactivateUI();

return ResultFromScode (S_OK);

}


 COleInPlaceObject::SetObjectRects  (SIMPSVR Sample)

//**********************************************************************

//

// COleInPlaceObject::SetObjectRects

//

// Purpose:

//

//      Called when the container clipping region or the object position

//      changes.

//

// Parameters:

//

//      LPCRECT lprcPosRect     - New Position Rect.

//

//      LPCRECT lprcClipRect    - New Clipping Rect.

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      IntersectRect               Windows API

//      OffsetRect                  Windows API

//      CopyRect                    Windows API

//      MoveWindow                  Windows API

//      CSimpSvrDoc::GethHatchWnd   DOC.H

//      CSimpSvrDoc::gethDocWnd     DOC.h

//      SetHatchWindowSize          OLE2UI

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP COleInPlaceObject::SetObjectRects  ( LPCRECT lprcPosRect, LPCRECT lprcClipRect)

{

OutputDebugString("In COleInPlaceObject::SetObjectRects\r\n");

RECT resRect;

POINT pt;

// Get the intersection of the clipping rect and the position rect.

IntersectRect(&resRect, lprcPosRect, lprcClipRect);

m_lpObj->m_xOffset = abs (resRect.left - lprcPosRect->left);

m_lpObj->m_yOffset = abs (resRect.top - lprcPosRect->top);

m_lpObj->m_scale = (float)(lprcPosRect->right - lprcPosRect->left)/m_lpObj->m_size.x;

if (m_lpObj->m_scale == 0)

m_lpObj->m_scale = (float) 1.0;

char szBuffer[255];

wsprintf(szBuffer,"New Scale %3d\r\n",m_lpObj->m_scale);

OutputDebugString(szBuffer);

// Adjust the size of the Hatch Window.

SetHatchWindowSize(m_lpObj->m_lpDoc->GethHatchWnd(),(LPRECT) lprcPosRect, (LPRECT) lprcClipRect, &pt);

// offset the rect

OffsetRect(&resRect, pt.x, pt.y);

CopyRect(&m_lpObj->m_posRect, lprcPosRect);

// Move the actual object window

MoveWindow(m_lpObj->m_lpDoc->GethDocWnd(),

   resRect.left,

   resRect.top,

   resRect.right - resRect.left,

   resRect.bottom - resRect.top,

   TRUE);

return ResultFromScode( S_OK );

};


 COleInPlaceObject::GetWindow  (SIMPSVR Sample)

//**********************************************************************

//

// COleInPlaceObject::GetWindow

//

// Purpose:

//

//      Returns the Window handle of the inplace object

//

// Parameters:

//

//      HWND FAR* lphwnd    - Out pointer in which to return the window

//                            Handle.

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      CSimpleDoc::GethDocWnd      DOC.H

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP COleInPlaceObject::GetWindow  ( HWND FAR* lphwnd)

{

OutputDebugString("In COleInPlaceObject::GetWindow\r\n");

*lphwnd = m_lpObj->m_lpDoc->GethDocWnd();

return ResultFromScode( S_OK );

};


 COleInPlaceObject::ContextSensitiveHelp  (SIMPSVR Sample)

//**********************************************************************

//

// COleInPlaceObject::ContextSensitiveHelp

//

// Purpose:

//

//      Used in performing Context Sensitive Help

//

// Parameters:

//

//      BOOL fEnterMode     - Flag to determine if enter or exiting

//                            Context Sensitive Help.

//

// Return Value:

//

//      E_NOTIMPL

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//      This function is not implemented due to the fact that it is

//      beyond the scope of a simple object.  All *real* applications

//      are going to want to implement this function, otherwise any

//      container that supports context sensitive help will not work

//      properly while the object is in place.

//

//      See TECHNOTES.WRI include with the OLE SDK for details on

//      Implementing this method.

//

//********************************************************************

STDMETHODIMP COleInPlaceObject::ContextSensitiveHelp  ( BOOL fEnterMode)

{

OutputDebugString("In COleInPlaceObject::ContextSensitiveHelp\r\n");

return ResultFromScode( E_NOTIMPL);

};


 COleInPlaceObject::ReactivateAndUndo  (SIMPSVR Sample)

//**********************************************************************

//

// COleInPlaceObject::ReactivateAndUndo

//

// Purpose:

//

//      Called when the container wants to undo the last edit made in

//      the object.

//

// Parameters:

//

//      None

//

// Return Value:

//

//      INPLACE_E_NOTUNDOABLE

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//      Since this server does not support undo, the value

//      INPLACE_E_NOTUNDOABLE is always returned.

//

//********************************************************************

STDMETHODIMP COleInPlaceObject::ReactivateAndUndo  ()

{

OutputDebugString("In COleInPlaceObject::ReactivateAndUndo\r\n");

return ResultFromScode( INPLACE_E_NOTUNDOABLE );

};


 IOO.CPP  (SIMPSVR Sample)

//**********************************************************************

// File name: IOO.CPP

//

//    Implementation file for the COleObject Class

//

// Functions:

//

//    See ioo.h for a list of member functions.

//

// Copyright (c) 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#include "pre.h"

#include "obj.h"

#include "ioo.h"

#include "app.h"

#include "doc.h"

#define VERB_OPEN 1


 COleObject::QueryInterface  (SIMPSVR Sample)

//**********************************************************************

//

// COleObject::QueryInterface

//

// Purpose:

//

//

// Parameters:

//

//      REFIID riid         -   Interface being queried for.

//

//      LPVOID FAR *ppvObj  -   Out pointer for the interface.

//

// Return Value:

//

//      S_OK            - Success

//      E_NOINTERFACE   - Failure

//

// Function Calls:

//      Function                    Location

//

//      CSimpSvrObj::QueryInterface OBJ.CPP

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP COleObject::QueryInterface ( REFIID riid, LPVOID FAR* ppvObj)

{

OutputDebugString("In COleObject::QueryInterface\r\n");

return m_lpObj->QueryInterface(riid, ppvObj);

}


 COleObject::AddRef  (SIMPSVR Sample)

//**********************************************************************

//

// COleObject::AddRef

//

// Purpose:

//

//      Increments the reference count on COleObject and the "object"

//      object.

//

// Parameters:

//

//      None

//

// Return Value:

//

//      The Reference count on the Object.

//

// Function Calls:

//      Function                    Location

//

//      OuputDebugString            Windows API

//      CSimpSvrObj::AddRef         OBJ.CPP

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP_(ULONG) COleObject::AddRef ()

{

OutputDebugString("In COleObject::AddRef\r\n");

++m_nCount;

return m_lpObj->AddRef();

}


 COleObject::Release  (SIMPSVR Sample)

//**********************************************************************

//

// COleObject::Release

//

// Purpose:

//

//      Decrements the reference count of COleObject and the

//      "object" object.

//

// Parameters:

//

//      None

//

// Return Value:

//

//      The new reference count

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      CSimpSvrObj::Release        OBJ.CPP

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP_(ULONG) COleObject::Release ()

{

OutputDebugString("In COleObject::Release\r\n");

--m_nCount;

return m_lpObj->Release();

}


 COleObject::SetClientSite  (SIMPSVR Sample)

//**********************************************************************

//

// COleObject::SetClientSite

//

// Purpose:

//

//      Called to notify the object of it's client site.

//

// Parameters:

//

//      LPOLECLIENTSITE pClientSite     - ptr to new client site

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      IOleClientSite::Release     Container

//      IOleClientSite::AddRef      Container

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP COleObject::SetClientSite  ( LPOLECLIENTSITE pClientSite)

{

OutputDebugString("In COleObject::SetClientSite\r\n");

// if we already have a client site, release it.

if (m_lpObj->m_lpOleClientSite)

{

m_lpObj->m_lpOleClientSite->Release();

m_lpObj->m_lpOleClientSite = NULL;

}

// store copy of the client site.

m_lpObj->m_lpOleClientSite = pClientSite;

// AddRef it so it doesn't go away.

if (m_lpObj->m_lpOleClientSite)

m_lpObj->m_lpOleClientSite->AddRef();

return ResultFromScode(S_OK);

}


 COleObject::Advise  (SIMPSVR Sample)

//**********************************************************************

//

// COleObject::Advise

//

// Purpose:

//

//      Called to set up an advise on the OLE object.

//

// Parameters:

//

//      LPADVISESINK pAdvSink       - ptr to the Advise Sink for notification

//

//      DWORD FAR* pdwConnection    - place to return the connection ID.

//

// Return Value:

//

//      Passed back from IOleAdviseHolder::Advise.

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      CreateOleAdviseHolder       OLE API

//      IOleAdviseHolder::Advise    OLE

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP COleObject::Advise ( LPADVISESINK pAdvSink, DWORD FAR* pdwConnection)

{

OutputDebugString("In COleObject::Advise\r\n");

// if we haven't made an OleAdviseHolder yet, make one.

if (!m_lpObj->m_lpOleAdviseHolder)

CreateOleAdviseHolder(&m_lpObj->m_lpOleAdviseHolder);

// pass this call onto the OleAdviseHolder.

return m_lpObj->m_lpOleAdviseHolder->Advise(pAdvSink, pdwConnection);

}


 COleObject::SetHostNames  (SIMPSVR Sample)

//**********************************************************************

//

// COleObject::SetHostNames

//

// Purpose:

//

//      Called to pass strings for Window titles.

//

// Parameters:

//

//      LPCSTR szContainerApp   -   ptr to string describing Container App

//

//      LPCSTR szContainerObj   -   ptr to string describing Object

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//      This routine is called so that the server application can

//      set the window title appropriately.

//

//********************************************************************

//@@WTK WIN32, UNICODE

//STDMETHODIMP COleObject::SetHostNames  ( LPCSTR szContainerApp, LPCSTR szContainerObj)

STDMETHODIMP COleObject::SetHostNames  ( LPCOLESTR szContainerApp, LPCOLESTR szContainerObj)

{

OutputDebugString("In COleObject::SetHostNames\r\n");

return ResultFromScode( S_OK);

};


 COleObject::DoVerb  (SIMPSVR Sample)

//**********************************************************************

//

// COleObject::DoVerb

//

// Purpose:

//

//      Called by the container application to invoke a verb.

//

// Parameters:

//

//      LONG iVerb                  - The value of the verb to be

//                                    invoked.

//

//      LPMSG lpmsg                 - The message that caused the

//                                    verb to be invoked.

//

//      LPOLECLIENTSITE pActiveSite - Ptr to the active client site.

//

//      LONG lindex                 - Used in extended layout

//

//      HWND hwndParent             - This should be the window handle of

//                                    the window in which we are contained.

//                                    This value could be used to "fake"

//                                    inplace activation in a manner similar

//                                    to Video for Windows in OLE 1.0.

//

//      LPCRECT lprcPosRect         - The rectangle that contains the object

//                                    within hwndParent.  Also used to

//                                    "fake" inplace activation.

//

// Return Value:

//

//      OLE_E_NOTINPLACEACTIVE      - Returned if attempted to undo while not

//                                    inplace active.

//      S_OK

//

// Function Calls:

//      Function                            Location

//

//      OutputDebugString                   Windows API

//      ShowWindow                          Windows API

//      CSimpSvrObj::DoInPlaceActivate      OBJ.CPP

//      CSimpSvrObj::DoInPlaceHide          OBJ.CPP

//      COleObject::OpenEdit                IOO.CPP

//      CSimpSvrDoc::GethDocWnd             DOC.H

//      COleInPlaceObj::InPlaceDeactivate   IOIPO.CPP

//

// Comments:

//

//      Be sure to look at TECHNOTES.WRI included with the OLE

//      SDK for a description of handling the inplace verbs

//      properly.

//

//********************************************************************

STDMETHODIMP COleObject::DoVerb  (  LONG iVerb,

LPMSG lpmsg,

LPOLECLIENTSITE pActiveSite,

LONG lindex,

HWND hwndParent,

LPCRECT lprcPosRect)

{

OutputDebugString("In COleObject::DoVerb\r\n");

switch (iVerb)

{

case OLEIVERB_SHOW:

case OLEIVERB_PRIMARY:

if (m_fOpen)

SetFocus(m_lpObj->m_lpDoc->GethAppWnd());

else if (m_lpObj->DoInPlaceActivate(iVerb) == FALSE)

OpenEdit(pActiveSite);

break;

case OLEIVERB_UIACTIVATE:

if (m_fOpen)

return ResultFromScode (E_FAIL);

// inplace activate

if (!m_lpObj->DoInPlaceActivate(iVerb))

return ResultFromScode (E_FAIL);

break;

case OLEIVERB_DISCARDUNDOSTATE:

// don't have to worry about this situation as we don't

// support an undo state.

if (!m_lpObj->m_fInPlaceActive)

return ResultFromScode(OLE_E_NOT_INPLACEACTIVE);

break;

case OLEIVERB_HIDE:

// if inplace active, do an "inplace" hide, otherwise

// just hide the app window.

if (m_lpObj->m_fInPlaceActive)

{

m_lpObj->DeactivateUI();

m_lpObj->DoInPlaceHide();

}

else

m_lpObj->m_lpDoc->GetApp()->HideAppWnd();

break;

case OLEIVERB_OPEN:

case VERB_OPEN:

// if inplace active, deactivate

if (m_lpObj->m_fInPlaceActive)

m_lpObj->m_OleInPlaceObject.InPlaceDeactivate();

// open into another window.

OpenEdit(pActiveSite);

break;

default:

if (iVerb < 0)

return ResultFromScode(E_FAIL);

}

return ResultFromScode( S_OK);

};


 COleObject::GetExtent  (SIMPSVR Sample)

//**********************************************************************

//

// COleObject::GetExtent

//

// Purpose:

//

//      Returns the extent of the object.

//

// Parameters:

//

//      DWORD dwDrawAspect  - The aspect in which to get the size.

//

//      LPSIZEL lpsizel     - Out ptr to return the size.

//

// Return Value:

//

//

//

// Function Calls:

//      Function                        Location

//

//      OutputDebugString               Windows API

//      XformWidthInPixelsToHimetric    OLE2UI

//      XformHeightInPixelsToHimetric   OLE2UI

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP COleObject::GetExtent  ( DWORD dwDrawAspect, LPSIZEL lpsizel)

{

OutputDebugString("In COleObject::GetExtent\r\n");

SCODE sc = E_FAIL;

// Only DVASPECT_CONTENT is supported....

if (dwDrawAspect == DVASPECT_CONTENT)

{

sc = S_OK;

// return the correct size in HIMETRIC...

lpsizel->cx = XformWidthInPixelsToHimetric(NULL, m_lpObj->m_size.x);

lpsizel->cy = XformHeightInPixelsToHimetric(NULL, m_lpObj->m_size.y);

}

return ResultFromScode( sc );

};


 COleObject::Update  (SIMPSVR Sample)

//**********************************************************************

//

// COleObject::Update

//

// Purpose:

//

//      Called to get the most up to date data

//

// Parameters:

//

//      None

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                            Location

//

//      OutputDebugString                   Windows API

//      IDataAdviseHolder::SendOnDataChange OLE

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP COleObject::Update()

{

OutputDebugString("In COleObject::Update\r\n");

// force an update

m_lpObj->SendOnDataChange();

return ResultFromScode( S_OK );

};


 COleObject::Close  (SIMPSVR Sample)

//**********************************************************************

//

// COleObject::Close

//

// Purpose:

//

//      Called when the OLE object needs to be closed

//

// Parameters:

//

//      DWORD dwSaveOption  - Flags to instruct the server how to prompt

//                            the user.

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      CSimpSvrDoc::Close          DOC.CPP

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP COleObject::Close  ( DWORD dwSaveOption)

{

OutputDebugString("In COleObject::Close\r\n");

// delegate to the document object.

m_lpObj->m_lpDoc->Close();

return ResultFromScode( S_OK );

};


 COleObject::Unadvise  (SIMPSVR Sample)

//**********************************************************************

//

// COleObject::Unadvise

//

// Purpose:

//

//      Breaks down an OLE advise that has been set up on this object.

//

// Parameters:

//

//      DWORD dwConnection  - Connection that needs to be broken down

//

// Return Value:

//

//      Passed back from IOleAdviseHolder::Unadvise

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      IOleAdviseHolder::Unadvise  OLE

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP COleObject::Unadvise ( DWORD dwConnection)

{

OutputDebugString("In COleObject::Unadvise\r\n");

// pass on to OleAdviseHolder.

return m_lpObj->m_lpOleAdviseHolder->Unadvise(dwConnection);

};


 COleObject::EnumVerbs  (SIMPSVR Sample)

//**********************************************************************

//

// COleObject::EnumVerbs

//

// Purpose:

//

//      Enumerates the verbs associated with this object.

//

// Parameters:

//

//      LPENUMOLEVERB FAR* ppenumOleVerb    - Out ptr in which to return

//                                            the enumerator

//

// Return Value:

//

//      OLE_S_USEREG    - Instructs OLE to use the verbs found in the

//                        REG DB for this server.

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//      In a .DLL, an application cannot return OLE_S_USEREG.  This is

//      due to the fact that the default object handler is not being

//      used, and the container is really making direct function calls

//      into the server .DLL.

//

//********************************************************************

STDMETHODIMP COleObject::EnumVerbs  ( LPENUMOLEVERB FAR* ppenumOleVerb)

{

OutputDebugString("In COleObject::EnumVerbs\r\n");

return ResultFromScode( OLE_S_USEREG );

};


 COleObject::GetClientSite  (SIMPSVR Sample)

//**********************************************************************

//

// COleObject::GetClientSite

//

// Purpose:

//

//      Called to get the current client site of the object.

//

// Parameters:

//

//      LPOLECLIENTSITE FAR* ppClientSite   - Out ptr in which to return the

//                                            client site.

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP COleObject::GetClientSite  ( LPOLECLIENTSITE FAR* ppClientSite)

{

OutputDebugString("In COleObject::GetClientSite\r\n");

*ppClientSite = m_lpObj->m_lpOleClientSite;

return ResultFromScode( S_OK );

}


 COleObject::SetMoniker  (SIMPSVR Sample)

//**********************************************************************

//

// COleObject::SetMoniker

//

// Purpose:

//

//      Used to set the objects moniker

//

// Parameters:

//

//      DWORD dwWhichMoniker    - Type of moniker being set

//

//      LPMONIKER pmk           - Pointer to the moniker

//

// Return Value:

//

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP COleObject::SetMoniker  ( DWORD dwWhichMoniker, LPMONIKER pmk)

{

OutputDebugString("In COleObject::SetMoniker\r\n");

LPMONIKER lpmk;

if (! m_lpObj->GetOleClientSite())

return ResultFromScode (E_FAIL);

if (m_lpObj->GetOleClientSite()->GetMoniker (OLEGETMONIKER_ONLYIFTHERE, OLEWHICHMK_OBJFULL, &lpmk) != NOERROR)

return ResultFromScode (E_FAIL);

if (m_lpObj->GetOleAdviseHolder())

m_lpObj->GetOleAdviseHolder()->SendOnRename(lpmk);

LPRUNNINGOBJECTTABLE lpRot;

if (GetRunningObjectTable(0, &lpRot) == NOERROR)

{

if (m_lpObj->m_dwRegister)

lpRot->Revoke(m_lpObj->m_dwRegister);

lpRot->Register(0, m_lpObj, lpmk, &m_lpObj->m_dwRegister);

lpRot->Release();

}

return ResultFromScode( S_OK );

};


 COleObject::GetMoniker  (SIMPSVR Sample)

//**********************************************************************

//

// COleObject::GetMoniker

//

// Purpose:

//

////

// Parameters:

//

//      DWORD dwAssign          - Assignment for the moniker

//

//      DWORD dwWhichMoniker    - Which moniker to return

//

//      LPMONIKER FAR* ppmk     - An out ptr to return the moniker

//

// Return Value:

//

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP COleObject::GetMoniker  (  DWORD dwAssign, DWORD dwWhichMoniker,

LPMONIKER FAR* ppmk)

{

OutputDebugString("In COleObject::GetMoniker\r\n");

// need to NULL the out parameter

*ppmk = NULL;

return m_lpObj->GetOleClientSite()->GetMoniker (OLEGETMONIKER_ONLYIFTHERE, OLEWHICHMK_OBJFULL, ppmk);

};


 COleObject::InitFromData  (SIMPSVR Sample)

//**********************************************************************

//

// COleObject::InitFromData

//

// Purpose:

//

//      Initialize the object from the passed pDataObject.

//

// Parameters:

//

//      LPDATAOBJECT pDataObject    - Pointer to data transfer object

//                                    to be used in the initialization

//

//      BOOL fCreation              - TRUE if the object is currently being

//                                    created.

//

//      DWORD dwReserved            - Reserved

//

// Return Value:

//

//      S_FALSE

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//      We don't support this functionality, so we will always return

//      error.

//

//********************************************************************

STDMETHODIMP COleObject::InitFromData  ( LPDATAOBJECT pDataObject,

 BOOL fCreation,

 DWORD dwReserved)

{

OutputDebugString("In COleObject::InitFromData\r\n");

return ResultFromScode( S_FALSE );

};


 COleObject::GetClipboardData  (SIMPSVR Sample)

//**********************************************************************

//

// COleObject::GetClipboardData

//

// Purpose:

//

//      Returns an IDataObject that is the same as doing an OleSetClipboard

//

// Parameters:

//

//      DWORD dwReserved                - Reserved

//

//      LPDATAOBJECT FAR* ppDataObject  - Out ptr for the Data Object.

//

// Return Value:

//

//      OLE_E_NOTSUPPORTED

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//      Support of this method is optional.

//

//********************************************************************

STDMETHODIMP COleObject::GetClipboardData  ( DWORD dwReserved,

 LPDATAOBJECT FAR* ppDataObject)

{

OutputDebugString("In COleObject::GetClipboardData\r\n");

// NULL the out ptr

*ppDataObject = NULL;

return ResultFromScode( E_NOTIMPL );

};


 COleObject::IsUpToDate  (SIMPSVR Sample)

//**********************************************************************

//

// COleObject::IsUpToDate

//

// Purpose:

//

//      Determines if an object is up to date

//

// Parameters:

//

//      None

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//      Our embedded object is always up to date.  This function is

//      particularly useful in linking situations.

//

//********************************************************************

STDMETHODIMP COleObject::IsUpToDate()

{

OutputDebugString("In COleObject::IsUpToDate\r\n");

return ResultFromScode( S_OK );

};


 COleObject::GetUserClassID  (SIMPSVR Sample)

//**********************************************************************

//

// COleObject::GetUserClassID

//

// Purpose:

//

//      Returns the applications CLSID

//

// Parameters:

//

//      CLSID FAR* pClsid   - Out ptr to return the CLSID

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      CPersistStorage::GetClassID IPS.CPP

//

// Comments:

//

//      This function is just delegated to IPS::GetClassID.

//

//********************************************************************

STDMETHODIMP COleObject::GetUserClassID  ( CLSID FAR* pClsid)

{

OutputDebugString("In COleObject::GetUserClassID\r\n");

m_lpObj->m_PersistStorage.GetClassID(pClsid);

return ResultFromScode( S_OK );

};


 COleObject::GetUserType  (SIMPSVR Sample)

//**********************************************************************

//

// COleObject::GetUserType

//

// Purpose:

//

//      Used to get a user presentable id for this object

//

// Parameters:

//

//      DWORD dwFormOfType      - The ID requested

//

//      LPSTR FAR* pszUserType  - Out ptr to return the string

//

// Return Value:

//

//      OLE_S_USEREG    - Use the reg db to get these entries.

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//

//********************************************************************

//@@WTK WIN32, UNICODE

//STDMETHODIMP COleObject::GetUserType  ( DWORD dwFormOfType, LPSTR FAR* pszUserType)

STDMETHODIMP COleObject::GetUserType  ( DWORD dwFormOfType, LPOLESTR FAR* pszUserType)

{

OutputDebugString("In COleObject::GetUserType\r\n");

return ResultFromScode( OLE_S_USEREG );

};


 COleObject::SetExtent  (SIMPSVR Sample)

//**********************************************************************

//

// COleObject::SetExtent

//

// Purpose:

//

//      Called to set the extent of the object.

//

// Parameters:

//

//      DWORD dwDrawAspect  - Aspect to have its size set

//

//      LPSIZEL lpsizel     - New size of the object.

//

// Return Value:

//

//      E_NOTIMPL   - This function is not curently implemented.

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP COleObject::SetExtent  ( DWORD dwDrawAspect, LPSIZEL lpsizel)

{

OutputDebugString("In COleObject::SetExtent\r\n");

return ResultFromScode( E_NOTIMPL);

};


 COleObject::EnumAdvise  (SIMPSVR Sample)

//**********************************************************************

//

// COleObject::EnumAdvise

//

// Purpose:

//

//      Returns an enumerate which enumerates the outstanding advises

//      associated with this OLE object.

//

// Parameters:

//

//      LPENUMSTATDATA FAR* ppenumAdvise - Out ptr in which to return

//                                         the enumerator.

//

// Return Value:

//

//      Passed on from IOleAdviseHolder::EnumAdvise.

//

// Function Calls:

//      Function                        Location

//

//      OutputDebugString               Windows API

//      IOleAdviseHolder::EnumAdvise    OLE

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP COleObject::EnumAdvise  ( LPENUMSTATDATA FAR* ppenumAdvise)

{

OutputDebugString("In COleObject::EnumAdvise\r\n");

// need to NULL the out parameter

*ppenumAdvise = NULL;

// pass on to the OLE Advise holder.

return m_lpObj->m_lpOleAdviseHolder->EnumAdvise(ppenumAdvise);

};


 COleObject::GetMiscStatus  (SIMPSVR Sample)

//**********************************************************************

//

// COleObject::GetMiscStatus

//

// Purpose:

//

//      Return status information about the object

//

// Parameters:

//

//      DWORD dwAspect          - Aspect interested in.

//

//      DWORD FAR* pdwStatus    - Out ptr in which to return the bits.

//

// Return Value:

//

//      CO_E_READREGDB  - Tell the library to use the reg DB.

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP COleObject::GetMiscStatus  ( DWORD dwAspect, DWORD FAR* pdwStatus)

{

OutputDebugString("In COleObject::GetMiscStatus\r\n");

// need to NULL the out parameter

*pdwStatus = NULL;

return ResultFromScode( OLE_S_USEREG );

};


 COleObject::SetColorScheme  (SIMPSVR Sample)

//**********************************************************************

//

// COleObject::SetColorScheme

//

// Purpose:

//

//      Used to set the palette for the object to use.

//

// Parameters:

//

//      LPLOGPALETTE lpLogpal   - Pointer to the LOGPALETTE to be used.

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//      This server ignores this method.

//

//********************************************************************

STDMETHODIMP COleObject::SetColorScheme  ( LPLOGPALETTE lpLogpal)

{

OutputDebugString("In COleObject::SetColorScheme\r\n");

return ResultFromScode( S_OK );

};


 COleObject::OpenEdit  (SIMPSVR Sample)

//**********************************************************************

//

// COleObject::OpenEdit

//

// Purpose:

//

//      Used to Open the object into a seperate window.

//

// Parameters:

//

//      LPOLECLIENTSITE pActiveSite - Pointer to the Active clientsite.

//

// Return Value:

//

//      None.

//

// Function Calls:

//      Function                        Location

//

//      IOleClientSite::OnShowWindow    Container

//      ShowWindow                      Windows API

//      UpdateWindow                    Windows API

//      OutputDebugString               Windows API

//      CSimpSvrDoc::GethAppWnd         DOC.H

//      CSimpSvrDoc::GethHatchWnd       DOC.H

//

// Comments:

//

//

//********************************************************************

void COleObject::OpenEdit(LPOLECLIENTSITE pActiveSite)

{

   if (m_lpObj->GetOleClientSite())

   m_lpObj->GetOleClientSite()->ShowObject();

m_fOpen = TRUE;

// tell the site we are opening so the object can be hatched out.

if (m_lpObj->GetOleClientSite())

m_lpObj->GetOleClientSite()->OnShowWindow(TRUE);

m_lpObj->m_lpDoc->ShowDocWnd();

m_lpObj->m_lpDoc->HideHatchWnd();

// Show app window.

m_lpObj->m_lpDoc->GetApp()->ShowAppWnd();

SetFocus(m_lpObj->m_lpDoc->GethAppWnd());

}


 IPS.CPP  (SIMPSVR Sample)

//**********************************************************************

// File name: ips.cpp

//

//    Implementation file for the CSimpSvrApp Class

//

// Functions:

//

//    See ips.h for a list of member functions.

//

// Copyright (c) 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#include "pre.h"

#include "obj.h"

#include "ips.h"

#include "app.h"

#include "doc.h"

//@@WTK WIN32, UNICODE

//#include <storage.h>

DEFINE_GUID(GUID_SIMPLE, 0xBCF6D4A0, 0xBE8C, 0x1068, 0xB6, 0xD4, 0x00, 0xDD, 0x01, 0x0C, 0x05, 0x09);


 CPersistStorage::QueryInterface  (SIMPSVR Sample)

//**********************************************************************

//

// CPersistStorage::QueryInterface

//

// Purpose:

//

//

// Parameters:

//

//      REFIID riid         -   Interface being queried for.

//

//      LPVOID FAR *ppvObj  -   Out pointer for the interface.

//

// Return Value:

//

//      S_OK            - Success

//      E_NOINTERFACE   - Failure

//

// Function Calls:

//      Function                    Location

//

//      CSimpSvrObj::QueryInterface OBJ.CPP

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP CPersistStorage::QueryInterface ( REFIID riid, LPVOID FAR* ppvObj)

{

OutputDebugString("In CPersistStorage::QueryInterface\r\n");

// need to NULL the out parameter

return m_lpObj->QueryInterface(riid, ppvObj);

};


 CPersistStorage::AddRef  (SIMPSVR Sample)

//**********************************************************************

//

// CPersistStorage::AddRef

//

// Purpose:

//

//      Increments the reference count on CPersistStorage and the "object"

//      object.

//

// Parameters:

//

//      None

//

// Return Value:

//

//      The Reference count on the Object.

//

// Function Calls:

//      Function                    Location

//

//      OuputDebugString            Windows API

//      CSimpSvrObj::AddRef         OBJ.CPP

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP_(ULONG) CPersistStorage::AddRef ()

{

OutputDebugString("In CPersistStorage::AddRef\r\n");

++m_nCount;

return m_lpObj->AddRef();

};


 CPersistStorage::Release  (SIMPSVR Sample)

//**********************************************************************

//

// CPersistStorage::Release

//

// Purpose:

//

//      Decrements the reference count of CPersistStorage and the

//      "object" object.

//

// Parameters:

//

//      None

//

// Return Value:

//

//      The new reference count

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      CSimpSvrObj::Release        OBJ.CPP

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP_(ULONG) CPersistStorage::Release ()

{

OutputDebugString("In CPersistStorage::Release\r\n");

--m_nCount;

return m_lpObj->Release();

};


 CPersistStorage::InitNew  (SIMPSVR Sample)

//**********************************************************************

//

// CPersistStorage::InitNew

//

// Purpose:

//

//      Used to give a new OLE object a ptr to its storage.

//

// Parameters:

//

//      LPSTORAGE pStg  - Pointer to the storage

//

// Return Value:

//

//

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      IStorage::Release           OLE

//      IStorage::AddRef            OLE

//

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP CPersistStorage::InitNew (LPSTORAGE pStg)

{

OutputDebugString("In CPersistStorage::InitNew\r\n");

// release any streams and storages that may be open

ReleaseStreamsAndStorage();

m_lpObj->m_lpStorage = pStg;

// AddRef the new Storage

if (m_lpObj->m_lpStorage)

m_lpObj->m_lpStorage->AddRef();

CreateStreams(m_lpObj->m_lpStorage);

return ResultFromScode(S_OK);

}


 CPersistStorage::GetClassID  (SIMPSVR Sample)

//**********************************************************************

//

// CPersistStorage::GetClassID

//

// Purpose:

//

//      Returns the CLSID of this object.

//

// Parameters:

//

//      LPCLSID lpClassID   - Out ptr in which to return the CLSID

//

// Return Value:

//

//       S_OK

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP CPersistStorage::GetClassID  ( LPCLSID lpClassID)

{

OutputDebugString("In CPersistStorage::GetClassID\r\n");

*lpClassID = GUID_SIMPLE;

return ResultFromScode( S_OK );

};


 CPersistStorage::Save  (SIMPSVR Sample)

//**********************************************************************

//

// CPersistStorage::Save

//

// Purpose:

//

//      Instructs the object to save itself into the storage.

//

// Parameters:

//

//      LPSTORAGE pStgSave  - Storage in which the object should be saved

//

//      BOOL fSameAsLoad    - TRUE if pStgSave is the same as the storage

//                            that the object was originally created with.

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      CPersistStorage::InitNew    IPS.CPP

//      CSimpSvrObj::SaveToStorage  OBJ.CPP

//

//

// Comments:

//

//      A real app will want better error checking in this method.

//

//********************************************************************

STDMETHODIMP CPersistStorage::Save  ( LPSTORAGE pStgSave, BOOL fSameAsLoad)

{

OutputDebugString("In CPersistStorage::Save\r\n");

// save the data

m_lpObj->SaveToStorage (pStgSave, fSameAsLoad);

m_lpObj->m_fSaveWithSameAsLoad = fSameAsLoad;

m_lpObj->m_fNoScribbleMode = TRUE;

return ResultFromScode( S_OK );

};


 CPersistStorage::SaveCompleted  (SIMPSVR Sample)

//**********************************************************************

//

// CPersistStorage::SaveCompleted

//

// Purpose:

//

//      Called when the container is finished saving the object

//

// Parameters:

//

//      LPSTORAGE pStgNew   - ptr to the new storage

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP CPersistStorage::SaveCompleted  ( LPSTORAGE pStgNew)

{

OutputDebugString("In CPersistStorage::SaveCompleted\r\n");

if (pStgNew)

{

ReleaseStreamsAndStorage();

m_lpObj->m_lpStorage = pStgNew;

m_lpObj->m_lpStorage->AddRef();

OpenStreams(pStgNew);

}

/* OLE2NOTE: it is only legal to perform a Save or SaveAs operation

**    on an embedded object. if the document is a file-based document

**    then we can not be changed to a IStorage-base object.

**

**      fSameAsLoad   lpStgNew     Type of Save     Send OnSave

**    ---------------------------------------------------------

**         TRUE        NULL        SAVE             YES

**         TRUE        ! NULL      SAVE *           YES

**         FALSE       ! NULL      SAVE AS          YES

**         FALSE       NULL        SAVE COPY AS     NO

**

**    * this is a strange case that is possible. it is inefficient

**    for the caller; it would be better to pass lpStgNew==NULL for

**    the Save operation.

*/

if ( pStgNew || m_lpObj->m_fSaveWithSameAsLoad)

{

if (m_lpObj->m_fNoScribbleMode)

m_lpObj->GetOleAdviseHolder()->SendOnSave();  // normally would clear a

  // dirty bit

m_lpObj->m_fSaveWithSameAsLoad = FALSE;

}

m_lpObj->m_fNoScribbleMode = FALSE;

return ResultFromScode( S_OK );

};


 CPersistStorage::Load  (SIMPSVR Sample)

//**********************************************************************

//

// CPersistStorage::Load

//

// Purpose:

//

//      Instructs the object to be loaded from storage.

//

// Parameters:

//

//      LPSTORAGE pStg  - Ptr to the storage in which to be loaded

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                        Location

//

//      OutputDebugString               Windows API

//      CSimpSvrObj::LoadFromStorage    OBJ.CPP

//

//

// Comments:

//

//      A real app will want better error checking in this method.

//

//********************************************************************

STDMETHODIMP CPersistStorage::Load  ( LPSTORAGE pStg)

{

OutputDebugString("In CPersistStorage::Load\r\n");

// remember the storage

if (m_lpObj->m_lpStorage)

{

m_lpObj->m_lpStorage->Release();

m_lpObj->m_lpStorage = NULL;

}

m_lpObj->m_lpStorage = pStg;

m_lpObj->m_lpStorage->AddRef();

OpenStreams(m_lpObj->m_lpStorage);

m_lpObj->LoadFromStorage();

return ResultFromScode( S_OK );

};


 CPersistStorage::IsDirty  (SIMPSVR Sample)

//**********************************************************************

//

// CPersistStorage::IsDirty

//

// Purpose:

//

//      Returns whether or not the object is dirty w/respect to its

//      Storage

//

// Parameters:

//

//      None

//

// Return Value:

//

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

//

// Comments:

//

//      This sample does not implement this function, although a

//      real application should.

//

//********************************************************************

STDMETHODIMP CPersistStorage::IsDirty()

{

OutputDebugString("In CPersistStorage::IsDirty\r\n");

return ResultFromScode( S_OK );

};


 CPersistStorage::HandsOffStorage  (SIMPSVR Sample)

//**********************************************************************

//

// CPersistStorage::HandsOffStorage

//

// Purpose:

//

//      Forces the object to release its handle to its storage.

//

// Parameters:

//

//      None

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      IStorage::Release           OLE

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP CPersistStorage::HandsOffStorage  ()

{

OutputDebugString("In CPersistStorage::HandsOffStorage\r\n");

ReleaseStreamsAndStorage();

return ResultFromScode( S_OK );

};


 CPersistStorage::CreateStreams  (SIMPSVR Sample)

//**********************************************************************

//

// CPersistStorage::CreateStreams

//

// Purpose:

//

//      Creates the streams that are held open for the object's lifetime.

//

// Parameters:

//

//      LPSTORAGE lpStg -   Storage in which to create the streams

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      IStorage::Release           OLE

//      IStream::Release            OLE

//      IStorage::CreateStream      OLE

//

// Comments:

//

//

//********************************************************************

void CPersistStorage::CreateStreams(LPSTORAGE lpStg)

{

if (m_lpObj->m_lpColorStm)

m_lpObj->m_lpColorStm->Release();

if (m_lpObj->m_lpSizeStm)

m_lpObj->m_lpSizeStm->Release();

// create a stream to save the colors

//@@WTK WIN32, UNICODE

//lpStg->CreateStream ( "RGB",

lpStg->CreateStream ( OLESTR("RGB"),

   STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE,

   0,

   0,

   &m_lpObj->m_lpColorStm);

// create a stream to save the size

//@@WTK WIN32, UNICODE

//lpStg->CreateStream ( "size",

lpStg->CreateStream ( OLESTR("size"),

   STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE,

   0,

   0,

   &m_lpObj->m_lpSizeStm);

}


 CPersistStorage::OpenStreams  (SIMPSVR Sample)

//**********************************************************************

//

// CPersistStorage::OpenStreams

//

// Purpose:

//

//      Opens the streams in a storage.

//

// Parameters:

//

//      LPSTORAGE lpStg -   Storage in which to open the streams.

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      IStorage::Release           OLE

//

// Comments:

//

//

//********************************************************************

void CPersistStorage::OpenStreams(LPSTORAGE lpStg)

{

if (m_lpObj->m_lpColorStm)

m_lpObj->m_lpColorStm->Release();

if (m_lpObj->m_lpSizeStm)

m_lpObj->m_lpSizeStm->Release();

// open the color stream

//@@WTK WIN32, UNICODE

//lpStg->OpenStream ( "RGB",

lpStg->OpenStream ( OLESTR("RGB"),

   0,

   STGM_READWRITE | STGM_SHARE_EXCLUSIVE,

   0,

   &m_lpObj->m_lpColorStm);

// open the color stream

//@@WTK WIN32, UNICODE

//lpStg->OpenStream ( "size",

lpStg->OpenStream ( OLESTR("size"),

   0,

   STGM_READWRITE | STGM_SHARE_EXCLUSIVE,

   0,

   &m_lpObj->m_lpSizeStm);

}


 CPersistStorage::ReleaseStreamsAndStorage  (SIMPSVR Sample)

//**********************************************************************

//

// CPersistStorage::ReleaseStreamsAndStorage

//

// Purpose:

//

//      Releases the stream and storage ptrs

//

// Parameters:

//

//      None

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      IStorage::Release           OLE

//

// Comments:

//

//

//********************************************************************

void CPersistStorage::ReleaseStreamsAndStorage()

{

if (m_lpObj->m_lpColorStm)

{

m_lpObj->m_lpColorStm->Release();

m_lpObj->m_lpColorStm = NULL;

}

if (m_lpObj->m_lpSizeStm)

{

m_lpObj->m_lpSizeStm->Release();

m_lpObj->m_lpSizeStm = NULL;

}

if (m_lpObj->m_lpStorage)

{

m_lpObj->m_lpStorage->Release();

m_lpObj->m_lpStorage = NULL;

}

}


 CPersistStorage::CreateStreams  (SIMPSVR Sample)

//**********************************************************************

//

// CPersistStorage::CreateStreams

//

// Purpose:

//

//      Creates temporary streams in a storage.

//

// Parameters:

//

//      LPSTORAGE lpStg                 - Pointer to the storage

//

//      LPSTREAM FAR* lplpTempColor     - Color Stream

//

//      LPSTREAM FAR* lplpTempSize      - Size Stream

//

// Return Value:

//

//      S_OK

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      IStorage::Release           OLE

//

// Comments:

//

//

//********************************************************************

void CPersistStorage::CreateStreams(LPSTORAGE lpStg, LPSTREAM FAR* lplpTempColor,LPSTREAM FAR* lplpTempSize)

{

// create a stream to save the colors

 //@@WTK WIN32, UNICODE

 //lpStg->CreateStream ( "RGB",

 lpStg->CreateStream ( OLESTR("RGB"),

   STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE,

   0,

   0,

   lplpTempColor);

// create a stream to save the size

//@@WTK WIN32, UNICODE

//lpStg->CreateStream ( "size",

lpStg->CreateStream ( OLESTR("size"),

   STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE,

   0,

   0,

   lplpTempSize);

}


 OBJ.CPP  (SIMPSVR Sample)

//**********************************************************************

// File name: obj.cpp

//

//    Implementation file for the CSimpSvrApp Class

//

// Functions:

//

//    See obj.h for a list of member functions.

//

// Copyright (c) 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#include "pre.h"

#include "obj.h"

#include "ioo.h"

#include "ido.h"

#include "ips.h"

#include "icf.h"

#include "ioipao.h"

#include "ioipo.h"

#include "app.h"

#include "doc.h"


 CSimpSvrObj::QueryInterface  (SIMPSVR Sample)

//**********************************************************************

//

// CSimpSvrObj::QueryInterface

//

// Purpose:

//

//      Used for interface negotiation at the "Object" level.

//

// Parameters:

//

//      REFIID riid         -   A reference to the interface that is

//                              being queried.

//

//      LPVOID FAR* ppvObj  -   An out parameter to return a pointer to

//                              the interface.

//

// Return Value:

//

//      S_OK          -   The interface is supported.

//      E_NOINTERFACE -   The interface is not supported

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      ResultFromScode             OLE API

//      IUnknown::AddRef            OBJ.CPP, IOO.CPP, IDO.CPP, IPS.CPP

//                                  IOIPO.CPP, IOIPAO.CPP

//

// Comments:

//

//

//********************************************************************

STDMETHODIMP CSimpSvrObj::QueryInterface ( REFIID riid, LPVOID FAR* ppvObj)

{

OutputDebugString("In CSimpSvrObj::QueryInterface\r\n");

SCODE sc = S_OK;

if (riid == IID_IUnknown)

*ppvObj = this;

else if (riid == IID_IOleObject)

*ppvObj = &m_OleObject;

else if (riid == IID_IDataObject)

*ppvObj = &m_DataObject;

else if ( (riid == IID_IPersistStorage) || (riid == IID_IPersist) )

*ppvObj = &m_PersistStorage;

else if (riid == IID_IOleInPlaceObject)

*ppvObj = &m_OleInPlaceObject;

else if (riid == IID_IOleInPlaceActiveObject)

*ppvObj = &m_OleInPlaceActiveObject;

else if (riid == IID_IExternalConnection)

 *ppvObj = &m_ExternalConnection;

else

{

*ppvObj = NULL;

sc = E_NOINTERFACE;

}

if (*ppvObj)

((LPUNKNOWN)*ppvObj)->AddRef();

return ResultFromScode( sc );

};


 CSimpSvrObj::AddRef  (SIMPSVR Sample)

//**********************************************************************

//

// CSimpSvrObj::AddRef

//

// Purpose:

//

//      Adds to the reference count at the Object level.

//

// Parameters:

//

//      None

//

// Return Value:

//

//      ULONG   -   The new reference count of the Object.

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//      Due to the reference counting model that is used in this

//      implementation, this reference count is the sum of the

//      reference counts on all interfaces

//

//********************************************************************

STDMETHODIMP_(ULONG) CSimpSvrObj::AddRef ()

{

OutputDebugString("In CSimpSvrObj::AddRef\r\n");

m_lpDoc->AddRef();

return ++m_nCount;

};


 CSimpSvrObj::Release  (SIMPSVR Sample)

//**********************************************************************

//

// CSimpSvrObj::Release

//

// Purpose:

//

//      Decrements the reference count at this level

//

// Parameters:

//

//      None

//

// Return Value:

//

//      ULONG   -   The new reference count of the object.

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//

// Comments:

//

//      Due to the reference counting model that is used in this

//      implementation, this reference count is the sum of the

//      reference counts on all interfaces

//

//********************************************************************

STDMETHODIMP_(ULONG) CSimpSvrObj::Release ()

{

OutputDebugString("In CSimpSvrObj::Release\r\n");

m_lpDoc->Release();

if (--m_nCount == 0) {

delete this;

        return 0;

    }

return m_nCount;

};


 CSimpSvrObj::CSimpSvrObj  (SIMPSVR Sample)

//**********************************************************************

//

// CSimpSvrObj::CSimpSvrObj

//

// Purpose:

//

//      Constructor for CSimpSvrObj

//

// Parameters:

//

//      CSimpSvrDoc FAR * lpSimpSvrDoc - ptr to the doc object

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                    Location

//

//

// Comments:

//

//

//********************************************************************

#pragma warning (disable : 4355) // "this" used in base initializer list warning.  This

 // can be disabled because we are not using "this" in

 // the constructor for these objects, rather we are

 // just storing it for future use...

CSimpSvrObj::CSimpSvrObj(CSimpSvrDoc FAR * lpSimpSvrDoc) : m_OleObject(this),

   m_DataObject(this),

   m_PersistStorage(this),

   m_OleInPlaceActiveObject(this),

   m_OleInPlaceObject(this),

   m_ExternalConnection(this)

#pragma warning (default : 4355) // Turn the warning back on

{

m_lpDoc = lpSimpSvrDoc;

m_nCount = 0;

m_fInPlaceActive = FALSE;

m_fInPlaceVisible = FALSE;

m_fUIActive = FALSE;

m_hmenuShared = NULL;

m_hOleMenu = NULL;

m_dwRegister = 0;

m_lpFrame = NULL;

m_lpCntrDoc = NULL;

m_lpStorage = NULL;

m_lpColorStm = NULL;

m_lpSizeStm = NULL;

m_lpOleClientSite = NULL;

m_lpOleAdviseHolder = NULL;

m_lpDataAdviseHolder = NULL;

m_lpIPSite = NULL;

m_red = 128;

m_green = 0;

m_blue = 0;

m_size.x = 100;

m_size.y = 100;

m_xOffset = 0;

m_yOffset = 0;

m_scale = (float) 1.0;

m_fSaveWithSameAsLoad = FALSE;

m_fNoScribbleMode = FALSE;

}


 CSimpSvrObj::~CSimpSvrObj  (SIMPSVR Sample)

//**********************************************************************

//

// CSimpSvrObj::~CSimpSvrObj

//

// Purpose:

//

//      Destructor for CSimpSvrObj

//

// Parameters:

//

//      None

//

// Return Value:

//

//

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      PostMessage                 Windows API

//      CSimpSvrDoc::GetApp         DOC.H

//      CSimpSvrDoc::GethAppWnd     DOC.H

//      CSimpSvrDoc::ClearObj       DOC.H

//      CSimpSvrApp::IsStartedByOle APP.CPP

//

// Comments:

//

//

//********************************************************************

CSimpSvrObj::~CSimpSvrObj()

{

OutputDebugString("In CSimpSvrObj's Destructor \r\n");

// if we were started by ole, post ourselves a close message

if (m_lpDoc->GetApp()->IsStartedByOle())

PostMessage(m_lpDoc->GethAppWnd(), WM_SYSCOMMAND, SC_CLOSE, 0L);

// clear the OBJ ptr in the doc class

m_lpDoc->ClearObj();

}


 CSimpSvrObj::Draw  (SIMPSVR Sample)

//**********************************************************************

//

// CSimpSvrObj::Draw

//

// Purpose:

//

//      Draws the object into an arbitrary DC

//

// Parameters:

//

//      HDC hDC - DC to draw into

//

// Return Value:

//

//      NONE

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      CreateBrushIndirect         Windows API

//      SelectObject                Windows API

//      Rectangle                   Windows API

//      DeleteObject                Windows API

//

// Comments:

//

//

//********************************************************************

void CSimpSvrObj::Draw (HDC hDC, BOOL m_fMeta)

{

LOGBRUSH lb;

OutputDebugString("In CSimpSvrObj::Draw\r\n");

char szBuffer[255];

wsprintf(szBuffer,"Drawing Scale %3d\r\n",m_scale);

OutputDebugString(szBuffer);

if (!m_fMeta)

{

SetMapMode(hDC, MM_ANISOTROPIC);

//@@WTK WIN32, UNICODE

//SetWindowOrg(hDC, (int)(m_xOffset/m_scale), (int)(m_yOffset/m_scale));

SetWindowOrgEx(hDC, (int)(m_xOffset/m_scale),

(int)(m_yOffset/m_scale), NULL);

//@@WTK WIN32, UNICODE

//SetWindowExt(hDC, m_size.x, m_size.y);

SetWindowExtEx(hDC, m_size.x, m_size.y, NULL);

//@@WTK WIN32, UNICODE

//SetViewportExt(hDC, (int)(m_size.x*m_scale), (int)(m_size.y*m_scale));

SetViewportExtEx(hDC, (int)(m_size.x*m_scale),

(int)(m_size.y*m_scale), NULL);

}

// fill out a LOGBRUSH

lb.lbStyle = BS_SOLID;

lb.lbColor = RGB(m_red, m_green, m_blue);

lb.lbHatch = 0;

// create the brush

HBRUSH hBrush = CreateBrushIndirect(&lb);

// select the brush

HBRUSH hOldBrush = SelectObject(hDC, hBrush);

HPEN hPen = CreatePen(PS_INSIDEFRAME, 6, RGB(0, 0, 0));

HPEN hOldPen = SelectObject(hDC, hPen);

// draw the rectangle

Rectangle (hDC, 0, 0, m_size.x, m_size.y);

// restore the pen

hPen = SelectObject(hDC, hOldPen);

// free the pen

DeleteObject(hPen);

// restore the old brush

hBrush = SelectObject(hDC, hOldBrush);

// free the brush

DeleteObject(hBrush);

}


 CSimpSvrObj::GetMetaFilePict  (SIMPSVR Sample)

//**********************************************************************

//

// CSimpSvrObj::GetMetaFilePict

//

// Purpose:

//

//      Returns a handle to a metafile representation of the object.

//

// Parameters:

//

//      None

//

// Return Value:

//

//      Handle to the metafile.

//

// Function Calls:

//      Function                        Location

//

//      OutputDebugString               Windows API

//      GlobalAlloc                     Windows API

//      GlobalLock                      Windows API

//      SetWindowOrg                    Windows API

//      SetWindowExt                    Windows API

//      CreateMetaFile                  Windows API

//      CloseMetaFile                   Windows API

//      GlobalUnlock                    Windows API

//      XformWidthInPixelsToHimetric    OLE2UI

//      XformHeightInPixelsToHimetric   OLE2UI

//      CSimpSvrObj::Draw               OBJ.CPP

//

// Comments:

//

//

//********************************************************************

HANDLE CSimpSvrObj::GetMetaFilePict()

{

HANDLE hMFP;

METAFILEPICT FAR * lpMFP;

POINT pt;

OutputDebugString("In CSimpSvrObj::GetMetaFilePict\r\n");

// allocate the memory for the METAFILEPICT structure

hMFP = GlobalAlloc (GMEM_SHARE | GHND, sizeof (METAFILEPICT) );

lpMFP = (METAFILEPICT FAR*) GlobalLock(hMFP);

// get the size of the object in HIMETRIC

pt.x = XformWidthInPixelsToHimetric(NULL, m_size.x);

pt.y = XformHeightInPixelsToHimetric(NULL, m_size.y);

// fill out the METAFILEPICT structure

lpMFP->mm = MM_ANISOTROPIC;

lpMFP->xExt = pt.x;

lpMFP->yExt = pt.y;

// Create the metafile

HDC hDC = CreateMetaFile(NULL);

//@@WTK WIN32, UNICODE

//SetWindowOrg (hDC, 0, 0);

SetWindowOrgEx (hDC, 0, 0, NULL);

//@@WTK WIN32, UNICODE

//SetWindowExt (hDC, m_size.x,

SetWindowExtEx (hDC, m_size.x,

   m_size.y, NULL);

Draw(hDC);

lpMFP->hMF = CloseMetaFile(hDC);

// unlock the metafilepict

GlobalUnlock(hMFP);

return hMFP;

}


 CSimpSvrObj::SaveToStorage  (SIMPSVR Sample)

//**********************************************************************

//

// CSimpSvrObj::SaveToStorage

//

// Purpose:

//

//      Saves the object to the passed storage

//

// Parameters:

//

//      LPSTORAGE lpStg - Storage in which to save the object

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      IStorage::CreateStream      OLE

//      IStream::Write              OLE

//      IStream::Release            OLE

//

// Comments:

//

//      A real app will want to do better error checking / returning

//

//********************************************************************

void CSimpSvrObj::SaveToStorage (LPSTORAGE lpStg, BOOL fSameAsLoad)

{

OutputDebugString("In CSimpSvrObj::SaveToStorage\r\n");

LPSTREAM lpTempColor, lpTempSize;

if (!fSameAsLoad)

m_PersistStorage.CreateStreams( lpStg, &lpTempColor, &lpTempSize);

else

{

lpTempColor = m_lpColorStm;

lpTempColor->AddRef();

lpTempSize = m_lpSizeStm;

lpTempSize->AddRef();

}

ULARGE_INTEGER uli;

uli.LowPart = 0;

uli.HighPart = 0;

lpTempColor->SetSize(uli);

lpTempSize->SetSize(uli);

LARGE_INTEGER li;

li.LowPart = 0;

li.HighPart = 0;

lpTempColor->Seek(li, STREAM_SEEK_SET, NULL);

lpTempSize->Seek(li, STREAM_SEEK_SET, NULL);

// write the colors to the stream

lpTempColor->Write(&m_red, sizeof(m_red), NULL);

lpTempColor->Write(&m_green, sizeof(m_green), NULL);

lpTempColor->Write(&m_blue, sizeof(m_blue), NULL);

// write the size to the stream

lpTempSize->Write(&m_size, sizeof(m_size), NULL);

lpTempColor->Release();

lpTempSize->Release();

}


 CSimpSvrObj::LoadFromStorage  (SIMPSVR Sample)

//**********************************************************************

//

// CSimpSvrObj::LoadFromStorage

//

// Purpose:

//

//      Loads the object from the passed storage

//

// Parameters:

//

//      LPSTORAGE lpStg     - Storage in which to load the object from

//

// Return Value:

//

//      None.

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString           Windows API

//      IStorage::OpenStream        OLE

//      IStream::Read               OLE

//      IStream::Release            OLE

//

// Comments:

//

//

//********************************************************************

void CSimpSvrObj::LoadFromStorage ()

{

OutputDebugString("In CSimpSvrObj::LoadFromStorage\r\n");

// Read the colors

m_lpColorStm->Read(&m_red, sizeof(m_red), NULL);

m_lpColorStm->Read(&m_green, sizeof(m_green), NULL);

m_lpColorStm->Read(&m_blue, sizeof(m_blue), NULL);

// read the size

m_lpSizeStm->Read(&m_size, sizeof(m_size), NULL);

}


 CSimpSvrObj::DoInPlaceActivate  (SIMPSVR Sample)

//**********************************************************************

//

// CSimpSvrObj::DoInPlaceActivate

//

// Purpose:

//

//      Does the inplace activation for the object

//

// Parameters:

//

//      LONG lVerb  - Verb that caused this function to be called

//

// Return Value:

//

//      TRUE/FALSE depending on success or failure.

//

// Function Calls:

//      Function                                Location

//

//      IOleClientSite::QueryInterface          Container

//      IOleClientSite::ShowObject              Container

//      IOleInPlaceSite::CanInPlaceActivate     Container

//      IOleInPlaceSite::Release                Container

//      IOleInPlaceSite::OnInPlaceActivate      Container

//      IOleInPlaceSite::GetWindow              Container

//      IOleInPlaceSite::GetWindowContext       Container

//      IOleInPlaceSite::OnUIActivate           Container

//      IOleInPlaceSite::Release                Container

//      IOleInPlaceFrame::SetActiveObject       Container

//      IOleInPlaceUIWindow::SetActiveObject    Container

//      OutputDebugString                       Windows API

//      ShowWindow                              Windows API

//      SetParent                               Windows API

//      IntersectRect                           Windows API

//      OffsetRect                              Windows API

//      MoveWindow                              Windows API

//      CopyRect                                Windows API

//      SetFocus                                Windows API

//      SetHatchWindowSize                      OLE2UI

//      CSimpSvrObj::AssembleMenus              OBJ.CPP

//      CSimpSvrObj::AddFrameLevelUI            OBJ.CPP

//

//

// Comments:

//

//      Be sure to read TECHNOTES.WRI included with the OLE SDK

//      for details on implementing inplace activation.

//

//********************************************************************

BOOL CSimpSvrObj::DoInPlaceActivate (LONG lVerb)

{

BOOL retval = FALSE;

RECT posRect, clipRect;

OutputDebugString("In CSimpSvrObj::DoInPlaceActivate\r\n");

// if not currently in place active

if (!m_fInPlaceActive)

{

// get the inplace site

if (m_lpOleClientSite->QueryInterface(IID_IOleInPlaceSite,

  (LPVOID FAR *)&m_lpIPSite) != NOERROR)

goto error;

// if the inplace site could not be obtained, or refuses to inplace

// activate then goto error.

if (m_lpIPSite == NULL || m_lpIPSite->CanInPlaceActivate() != NOERROR)

{

if (m_lpIPSite)

m_lpIPSite->Release();

m_lpIPSite == NULL;

goto error;

}

// tell the site that we are activating.

m_lpIPSite->OnInPlaceActivate();

m_fInPlaceActive = TRUE;

}

// if not currently inplace visibl

if (!m_fInPlaceVisible)

{

m_fInPlaceVisible = TRUE;

// get the window handle of the site

m_lpIPSite->GetWindow(&m_hWndParent);

// get window context from the container

m_lpIPSite->GetWindowContext ( &m_lpFrame,

 &m_lpCntrDoc,

 &posRect,

 &clipRect,

 &m_FrameInfo);

// show the hatch window

m_lpDoc->ShowHatchWnd();

// Set the parenting

SetParent (m_lpDoc->GethHatchWnd(), m_hWndParent);

SetParent (m_lpDoc->GethDocWnd(), m_lpDoc->GethHatchWnd());

// tell the client site to show the object

m_lpOleClientSite->ShowObject();

RECT resRect;

// figure out the "real" size of the object

IntersectRect(&resRect, &posRect, &clipRect);

CopyRect(&m_posRect, &posRect);

POINT pt;

// adjust our hatch window size

SetHatchWindowSize ( m_lpDoc->GethHatchWnd(),

 &resRect,

 &posRect,

 &pt);

// calculate the actual object rect inside the hatchwnd.

OffsetRect (&resRect, pt.x, pt.y);

// move the object window

MoveWindow(m_lpDoc->GethDocWnd(),

   resRect.left,

   resRect.top,

   resRect.right - resRect.left,

   resRect.bottom - resRect.top,

   FALSE);

// create the combined window

AssembleMenus();

}

// if not UIActive

if (!m_fUIActive)

{

m_fUIActive = TRUE;

// tell the inplace site that we are activating

m_lpIPSite->OnUIActivate();

// set the focus to our object window

SetFocus(m_lpDoc->GethDocWnd());

// set the active object on the frame

//@@WTK WIN32, UNICODE

//m_lpFrame->SetActiveObject(&m_OleInPlaceActiveObject, "Simple OLE 2.0 Server");

m_lpFrame->SetActiveObject(&m_OleInPlaceActiveObject, OLESTR("Simple OLE 2.0 Server"));

// set the active object on the Doc, if available.

if (m_lpCntrDoc)

//@@WTK WIN32, UNICODE

//m_lpCntrDoc->SetActiveObject(&m_OleInPlaceActiveObject, "Simple OLE 2.0 Server");

m_lpCntrDoc->SetActiveObject(&m_OleInPlaceActiveObject, OLESTR("Simple OLE 2.0 Server"));

// add the frame level UI.

AddFrameLevelUI();

}

retval = TRUE;

error:

return retval;

}


 CSimpSvrObj::AssembleMenus  (SIMPSVR Sample)

//**********************************************************************

//

// CSimpSvrObj::AssembleMenus

//

// Purpose:

//

//      Creates the combined menus used during inplace activation.

//

// Parameters:

//

//      None

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                        Location

//

//      OutputDebugString               Windows API

//      CreateMenu                      Windows API

//      IOleInPlaceFrame::InsertMenus   Container

//      InsertMenu                      Windows API

//      DestroyMenu                     Windows API

//      OleCreateMenuDescriptor         OLE API

//

// Comments:

//

//

//********************************************************************

void CSimpSvrObj::AssembleMenus()

{

OutputDebugString("In CSimpSvrObj::AssembleMenus\r\n");

OLEMENUGROUPWIDTHS menugroupwidths;

m_hmenuShared = NULL;

//  Create the menu resource

m_hmenuShared = CreateMenu();

// have the contaner insert its menus

if (m_lpFrame->InsertMenus (m_hmenuShared, &menugroupwidths) == NOERROR)

{

int nFirstGroup = (int) menugroupwidths.width[0];

// insert the server menus

//@@WTK WIN32, UNICODE

//InsertMenu( m_hmenuShared, nFirstGroup, MF_BYPOSITION | MF_POPUP, m_lpDoc->GetApp()->GetColorMenu(), "&Color");

InsertMenu( m_hmenuShared, nFirstGroup, MF_BYPOSITION | MF_POPUP,

(UINT)m_lpDoc->GetApp()->GetColorMenu(), "&Color");

menugroupwidths.width[1] = 1;

menugroupwidths.width[3] = 0;

menugroupwidths.width[5] = 0;

}

else

{

// Destroy the menu resource

DestroyMenu(m_hmenuShared);

m_hmenuShared = NULL;

}

// tell OLE to create the menu descriptor

m_hOleMenu = OleCreateMenuDescriptor(m_hmenuShared, &menugroupwidths);

}


 CSimpSvrObj::AddFrameLevelUI  (SIMPSVR Sample)

//**********************************************************************

//

// CSimpSvrObj::AddFrameLevelUI

//

// Purpose:

//

//      Adds the Frame level user interface

//

// Parameters:

//

//      None

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString                   Windows API

//      IOleInPlaceFrame::SetMenu           Container

//      IOleInPlaceFrame::SetBorderSpace    Container

//      IOleInPlaceUIWindow::SetBorderSpace Container

//      CSimpSvrDoc::GethDocWnd             DOC.H

//

// Comments:

//

//

//********************************************************************

void CSimpSvrObj::AddFrameLevelUI()

{

OutputDebugString("In CSimpSvrObj::AddFrameLevelUI\r\n");

// add the combined menu

m_lpFrame->SetMenu(m_hmenuShared, m_hOleMenu, m_lpDoc->GethDocWnd());

// do hatched border

SetParent (m_lpDoc->GethHatchWnd(), m_hWndParent);

SetParent (m_lpDoc->GethDocWnd(), m_lpDoc->GethHatchWnd());

// set the border space.  Normally we would negotiate for toolbar

// space at this point.  Since this server doesn't have a toolbar,

// this isn't needed...

if (m_lpFrame)

m_lpFrame->SetBorderSpace(NULL);

if (m_lpCntrDoc)

m_lpCntrDoc->SetBorderSpace(NULL);

}


 CSimpSvrObj::DoInPlaceHide  (SIMPSVR Sample)

//**********************************************************************

//

// CSimpSvrObj::DoInPlaceHide

//

// Purpose:

//

//      Hides the object while inplace actvie

//

// Parameters:

//

//      None

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                        Location

//

//      OutputDebugString               Windows API

//      SetParent                       Windows API

//      CSimpSvrDoc::GethDocWnd         DOC.H

//      CSimpSvrDoc::GethAppWnd         DOC.H

//      CSimpSvrDoc::GethHatchWnd       DOC.H

//      CSimpSvrObj::DisassembleMenus   OBJ.CPP

//      IOleInPlaceFrame::Release       Container

//      IOleInPlaceUIWindow::Release    Container

//

//

// Comments:

//

//      Be sure to read TECHNOTES.WRI included with the OLE SDK

//      for details on implementing inplace activation.

//

//********************************************************************

void CSimpSvrObj::DoInPlaceHide()

{

OutputDebugString("In CSimpSvrObj::DoInPlaceHide\r\n");

// if we aren't inplace visible, then this routine is a NOP,

if (!m_fInPlaceVisible)

return;

m_fInPlaceVisible = FALSE;

// change the parenting

SetParent (m_lpDoc->GethDocWnd(), m_lpDoc->GethAppWnd());

SetParent (m_lpDoc->GethHatchWnd(),m_lpDoc->GethDocWnd());

// rip down the combined menus

DisassembleMenus();

// release the inplace frame

m_lpFrame->Release();

m_lpFrame = NULL;  // only holding one ref. to frame.

// release the UIWindow if it is there.

if (m_lpCntrDoc)

m_lpCntrDoc->Release();

m_lpCntrDoc = NULL;

}


 CSimpSvrObj::DisassembleMenus  (SIMPSVR Sample)

//**********************************************************************

//

// CSimpSvrObj::DisassembleMenus

//

// Purpose:

//

//      Disassembles the combined menus used in inplace activation

//

// Parameters:

//

//      None

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                    Location

//

//      OutputDebugString               Windows API

//      OleDestroyMenuDescriptor        OLE API

//      RemoveMenu                      Windows API

//      IOleInPlaceFrame::RemoveMenus   Container

//      DestroyMenu                     Windows API

//

// Comments:

//

//      Be sure to read TECHNOTES.WRI included with the OLE SDK

//      for details on implementing inplace activation.

//

//********************************************************************

void CSimpSvrObj::DisassembleMenus()

{

// destroy the menu descriptor

OleDestroyMenuDescriptor(m_hOleMenu);

if (m_hmenuShared)

{

// remove the menus that we added

RemoveMenu( m_hmenuShared, 1, MF_BYPOSITION);

// have the container remove its menus

m_lpFrame->RemoveMenus(m_hmenuShared);

// Destroy the menu resource

DestroyMenu(m_hmenuShared);

m_hmenuShared = NULL;

}

}


 CSimpSvrObj::SendOnDataChange  (SIMPSVR Sample)

//**********************************************************************

//

// CSimpSvrObj::SendOnDataChange

//

// Purpose:

//

//      Uses the data advise holder to send a data change, then updates

//      the ROT to note the time of change.

//

// Parameters:

//

//      None

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                                Location

//

//      IDataAdviseHolder::SendOnDataChange     OLE API

//      GetRunningObjectTable                   OLE API

//      CoFileTimeNow                           OLE API

//      IRunningObjectTable::NoteChangeTime     OLE API

//

// Comments:

//

//

//********************************************************************

void CSimpSvrObj::SendOnDataChange()

{

if (m_lpDataAdviseHolder)

m_lpDataAdviseHolder->SendOnDataChange( (LPDATAOBJECT)&m_DataObject, 0, 0);

LPRUNNINGOBJECTTABLE lpRot;

GetRunningObjectTable(0, &lpRot);

if ( lpRot && m_dwRegister)

{

FILETIME ft;

CoFileTimeNow(&ft);

lpRot->NoteChangeTime(m_dwRegister, &ft);

lpRot->Release();

}

}


 CSimpSvrObj::DeactivateUI  (SIMPSVR Sample)

//**********************************************************************

//

// CSimpSvrObj::DeactivateUI

//

// Purpose:

//

//      Breaks down the inplace ui

//

// Parameters:

//

//      None

//

// Return Value:

//

//      None

//

// Function Calls:

//      Function                                Location

//

//      SetParent                               Windows API

//      IOleInPlaceUIWindow::SetActiveObject    Container

//      IOleInPlaceFrame::SetActiveObject       Container

//      IOleInPlaceSite::UIDeactivate           Container

//

// Comments:

//

//

//********************************************************************

void CSimpSvrObj::DeactivateUI()

{

// if not UI active, or no pointer to IOleInPlaceFrame, then

// return NOERROR

if (!(m_fUIActive || m_lpFrame))

return;

else

{

m_fUIActive = FALSE;

// remove hatching

SetParent (m_lpDoc->GethDocWnd(), m_lpDoc->GethAppWnd());

SetParent (m_lpDoc->GethHatchWnd(),m_lpDoc->GethDocWnd());

// if in an MDI container, call SetActiveObject on the DOC.

if (m_lpCntrDoc)

m_lpCntrDoc->SetActiveObject(NULL, NULL);

m_lpFrame->SetActiveObject(NULL, NULL);

// tell the container that our UI is going away.

if (m_lpIPSite)

m_lpIPSite->OnUIDeactivate(FALSE);

}

}


 SIMPSVR.CPP  (SIMPSVR Sample)

//**********************************************************************

// File name: simpsvr.cpp

//

//      Main source file for the simple OLE 2.0 server

//

// Functions:

//

//      WinMain         - Program entry point

//      MainWndProc     - Processes messages for the frame window

//      About           - Processes messages for the about dialog

//      DocWndProc      - Processes messages for the doc window

//

// Copyright (c) 1993 Microsoft Corporation. All rights reserved.

//**********************************************************************

#include "pre.h"

#include "obj.h"

#include "app.h"

#include "doc.h"

#include "icf.h"

// This line is needed for the debug utilities in OLE2UI

extern "C" {

        OLEDBGDATA_MAIN("SIMPSVR")

}

CSimpSvrApp FAR * lpCSimpSvrApp;

CClassFactory FAR * lpClassFactory;


 WinMain  (SIMPSVR Sample)

//**********************************************************************

//

// WinMain

//

// Purpose:

//

//      Program entry point

//

// Parameters:

//

//      HANDLE hInstance        - Instance handle for this instance

//

//      HANDLE hPrevInstance    - Instance handle for the last instance

//

//      LPSTR lpCmdLine         - Pointer to the command line

//

//      int nCmdShow            - Window State

//

// Return Value:

//

//      msg.wParam

//

// Function Calls:

//      Function                        Location

//

//      CSimpSvrApp::CSimpSvrApp          APP.CPP

//      CSimpSvrApp::fInitApplication    APP.CPP

//      CSimpSvrApp::fInitInstance       APP.CPP

//      CSimpSvrApp::HandleAccelerators  APP.CPP

//      CSimpSvrApp::~CSimpSvrApp         APP.CPP

//      OleUIInitialize                 OLE2UI

//      OleUIUninitialize               OLE2UI

//      GetMessage                      Windows API

//      TranslateMessage                Windows API

//      DispatchMessage                 Windows API

//

// Comments:

//

//********************************************************************

int PASCAL WinMain(HANDLE hInstance,HANDLE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)

{

        MSG msg;

        // recommended size for OLE apps

        SetMessageQueue(96);

        lpCSimpSvrApp = new CSimpSvrApp;

        lpCSimpSvrApp->AddRef();      // need the app ref. count at 1 to hold the

                                                                  // app alive.

        lpCSimpSvrApp->ParseCmdLine(lpCmdLine);

        // app initialization

        if (!hPrevInstance)

                if (!lpCSimpSvrApp->fInitApplication(hInstance))

                        return (FALSE);

        // instance initialization

        if (!lpCSimpSvrApp->fInitInstance(hInstance, nCmdShow, lpClassFactory))

                return (FALSE);

        /* Initialization required for OLE 2 UI library.  This call is

        **    needed ONLY if we are using the static link version of the UI

        **    library. If we are using the DLL version, we should NOT call

        **    this function in our application.

        */

#if 0

        if (!OleUIInitialize(hInstance, hPrevInstance))

                {

                OleDbgOut("Could not initialize OLEUI library\n");

                return FALSE;

                }

#endif

        // message loop

        while (GetMessage(&msg, NULL, NULL, NULL))

                {

                if (lpCSimpSvrApp->IsInPlaceActive())

                        // Only key messages need to be sent to OleTranslateAccelerator.  Any other message

                        // would result in an extra FAR call to occur for that message processing...

                        if ( (msg.message >= WM_KEYFIRST) && (msg.message <= WM_KEYLAST) )

                                // OleTranslateAccelerator MUST be called, even though this application does

                                // not have an accelerator table.  This has to be done in order for the

                                // mneumonics for the top level menu items to work properly.

                                if ( OleTranslateAccelerator ( lpCSimpSvrApp->GetDoc()->GetObj()->GetInPlaceFrame(),

                                                                                           lpCSimpSvrApp->GetDoc()->GetObj()->GetFrameInfo(),

                                                                                           &msg) == NOERROR)

                                        continue;

                TranslateMessage(&msg);    /* Translates virtual key codes           */

                DispatchMessage(&msg);     /* Dispatches message to window           */

                }

        // De-initialization for UI libraries.  Just like OleUIInitialize, this

        // funciton is needed ONLY if we are using the static link version of the

        // OLE UI library.

#if 0

        OleUIUninitialize();

#endif

        return (msg.wParam);           /* Returns the value from PostQuitMessage */

}


 MainWndProc  (SIMPSVR Sample)

//**********************************************************************

//

// MainWndProc

//

// Purpose:

//

//      Processes messages for the frame window

//

// Parameters:

//

//      HWND hWnd       - Window handle for frame window

//

//      UINT message    - Message value

//

//      WPARAM wParam   - Message info

//

//      LPARAM lParam   - Message info

//

// Return Value:

//

//      long

//

// Function Calls:

//      Function                        Location

//

//      CSimpSvrApp::lCommandHandler     APP.CPP

//      CSimpSvrApp::DestroyDocs         APP.CPP

//      CSimpSvrApp::lCreateDoc          APP.CPP

//      CSimpSvrApp::lSizeHandler        APP.CPP

//      CGameDoc::lAddVerbs           DOC.CPP

//      PostQuitMessage                 Windows API

//      DefWindowProc                   Windows API

//

// Comments:

//

//********************************************************************

//@@WTK WIN32, UNICODE

//long FAR PASCAL _export MainWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)

long FAR PASCAL EXPORT MainWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)

{

        switch (message)

                {

                case WM_CLOSE:

                        OutputDebugString("*** In WM_CLOSE *** \r\n");

                        // if there is still a document

                        if (lpCSimpSvrApp->GetDoc())

                                // if there is still an object within a document

                                if (lpCSimpSvrApp->GetDoc()->GetObj())   // this case occurs if there is still

                                                                                                                 // an outstanding Ref count on the object

                                                                                                                 // when the app is trying to go away.

                                                                                                                 // typically this case will occur in

                                                                                                                 // the "open" editing mode.

                                        //  Close the document

                                        lpCSimpSvrApp->GetDoc()->Close();

                        // hide the app window

                        lpCSimpSvrApp->HideAppWnd();

                        // if we were started by ole, unregister the class factory, otherwise

                        // remove the ref count on our dummy OLE object

                        if (lpCSimpSvrApp->IsStartedByOle())

                                CoRevokeClassObject(lpCSimpSvrApp->GetRegisterClass());

                        else

                                lpCSimpSvrApp->GetOleObject()->Release();

                        lpCSimpSvrApp->Release();  // This should close the app.

                        break;

                case WM_COMMAND:           // message: command from application menu

                        return lpCSimpSvrApp->lCommandHandler(hWnd, message, wParam, lParam);

                        break;

                case WM_CREATE:

                        return lpCSimpSvrApp->lCreateDoc(hWnd, message, wParam, lParam);

                        break;

                case WM_DESTROY:                  // message: window being destroyed

                        PostQuitMessage(0);

                        break;

                case WM_SIZE:

                        return lpCSimpSvrApp->lSizeHandler(hWnd, message, wParam, lParam);

                default:                          // Passes it on if unproccessed

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

                }

                return (NULL);

}


 About  (SIMPSVR Sample)

//**********************************************************************

//

// About

//

// Purpose:

//

//      Processes dialog box messages

//

// Parameters:

//

//      HWND hWnd       - Window handle for dialog box

//

//      UINT message    - Message value

//

//      WPARAM wParam   - Message info

//

//      LPARAM lParam   - Message info

//

// Return Value:

//

// Function Calls:

//      Function                    Location

//

//      EndDialog                   Windows API

//

// Comments:

//

//********************************************************************

//@@WTK WIN32, UNICODE

//BOOL FAR PASCAL _export About(HWND hDlg,unsigned message,WORD wParam,LONG lParam)

BOOL FAR PASCAL EXPORT About(HWND hDlg,UINT message,WPARAM wParam,LPARAM lParam)

{

        switch (message) {

        case WM_INITDIALOG:                /* message: initialize dialog box */

                return (TRUE);

        case WM_COMMAND:                      /* message: received a command */

                //@@WTK WIN32, UNICODE

                //if (wParam == IDOK                /* "OK" box selected?          */

                if (LOWORD(wParam) == IDOK                /* "OK" box selected?          */

                || LOWORD(wParam) == IDCANCEL) {      /* System menu close command? */

                        EndDialog(hDlg, TRUE);        /* Exits the dialog box        */

                        return (TRUE);

                }

                break;

        }

        return (FALSE);                           /* Didn't process a message    */

}


 DocWndProc  (SIMPSVR Sample)

//**********************************************************************

//

// DocWndProc

//

// Purpose:

//

//      Processes dialog box messages

//

// Parameters:

//

//      HWND hWnd       - Window handle for doc window

//

//      UINT message    - Message value

//

//      WPARAM wParam   - Message info

//

//      LPARAM lParam   - Message info

//

// Return Value:

//

// Function Calls:

//      Function                            Location

//

//      CSimpSvrApp::PaintApp                APP.CPP

//      BeginPaint                          Windows API

//      EndPaint                            Windows API

//      DefWindowProc                       Windows API

//      IOleObject::QueryInterface          Object

//      IOleInPlaceObject::UIDeactivate     Object

//      IOleObject::DoVerb                  Object

//      IOleInPlaceObject::Release          Object

//

// Comments:

//

//********************************************************************

//@@WTK WIN32, UNICODE

//long FAR PASCAL _export DocWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)

long FAR PASCAL EXPORT DocWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)

{

        HDC hDC;

        PAINTSTRUCT ps;

        switch (message) {

                case WM_COMMAND:           // message: command from application menu

                        return lpCSimpSvrApp->lCommandHandler(hWnd, message, wParam, lParam);

                        break;

                case WM_PAINT:

                        hDC = BeginPaint(hWnd, &ps);

                        // tell the app class to paint itself

                        if (lpCSimpSvrApp)

                                lpCSimpSvrApp->PaintApp (hDC);

                        EndPaint(hWnd, &ps);

                        break;

                case WM_MENUSELECT:

                        lpCSimpSvrApp->SetStatusText();

                        break;

        default:                          /* Passes it on if unproccessed    */

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

        }

        return (NULL);

}


BTTNCUR

This sample creates a DLL for generating standard Windows button images and cursors. For information on compiling and building the sample, see MAKEFILE  (BTTNCUR Sample).


MAKEFILE  (BTTNCUR Sample)

#

# Makefile

# Standard Button Images and Cursors DLL Version 1.1, March 1993

#

#

!include <$(MSTOOLS)\samples\ole\include\olesampl.mak>

all: bttncur.dll

OLE_FLAGS = -DWIN32S

!ifndef NO_DEBUG

OLE_FLAGS = $(OLE_FLAGS) /D_DEBUG /DDEBUG /D_DEBUGTRACE=0

!endif

.SUFFIXES: .h .c .obj .exe .res .rc

#

#

INCLS    = ..\include\bttncur.h bttncuri.h

OBJS     = bttncur.obj cursors.obj

RCFILES1 = bttncur.rcv res\harrows.cur res\help.cur res\larrows.cur

RCFILES2 = res\magnify.cur res\neswarrs.cur res\nodrop.cur res\nwsearrs.cur

RCFILES3 = res\rarrow.cur res\sarrows.cur res\sizebarh.cur res\sizebarv.cur

RCFILES4 = res\splith.cur res\splitv.cur res\tabletop.cur res\varrows.cur

RCFILES5 = res\stdim72.bmp res\stdim96.bmp res\stdim120.bmp

RCFILES  = $(RCFILES1) $(RCFILES2) $(RCFILES3) $(RCFILES4) $(RCFILES5)

#

# Tool Directives

#

.c.obj:

    $(cc) $(cflags) $(cvars) $(cdebug) $(OLE_FLAGS) $*.c

.rc.res:

    rc -r -DWIN32 -DDEBUG $*.rc

clean:

    -del *.obj

    -del *.dll

    -del *.res

    -del *.lib

    -del *.exp

    -del *.map

bttncur.dll: $(OBJS) bttncur.lib bttncur.def bttncur.res

    $(link) $(linkdebug) $(dlllflags) bttncur.exp $(OBJS) $*.res -out:$@ -map:$*.map $(guilibsdll) -base:0x76000000

    if not exist ..\bin mkdir ..\bin

    copy bttncur.dll ..\bin

bttncur.lib: $(OBJS) bttncur.def

    $(implib) $(OBJS) -out:bttncur.lib -def:bttncur.def -machine:$(CPU)

    if not exist ..\lib mkdir ..\lib

    copy bttncur.lib ..\lib

##### Dependencies #####

bttncur.obj  : bttncur.c    $(INCLS)

cursors.obj  : cursors.c    $(INCLS)

bttncur.res  : bttncur.rc   $(INCLS) $(RCFILES)


BTTNCUR.DEF  (BTTNCUR Sample)

LIBRARY     BTTNCUR

DESCRIPTION 'Windows Interface Buttons & Cursors 1.1, (c)1992-1993 Microsoft Corporation'

CODE        EXECUTE READ SHARED

EXPORTS     WEP                         @1 RESIDENTNAME

            UIToolButtonDraw            @2

            UICursorLoad                @3

            UIToolConfigureForDisplay   @4

            UIToolButtonDrawTDD         @5


BTTNCUR.RC  (BTTNCUR Sample)

/*

 * BTTNCUR.RC

 * Buttons & Cursors Version 1.1, March 1993

 *

 * Resource file for the Button Image & Cursors DLL, including cursors and

 * standard bitmaps.

 *

 * Copyright (c)1992-1993 Microsoft Corporation, All Rights Reserved,

 * as applied to redistribution of this source code in source form

 * License is granted to use of compiled code in shipped binaries.

 */

#define STRICT

#include <windows.h>

#include "bttncur.h"

#include "bttncuri.h"

IDB_STANDARDIMAGES72    BITMAP      res\stdim72.bmp

IDB_STANDARDIMAGES96    BITMAP      res\stdim96.bmp

IDB_STANDARDIMAGES120   BITMAP      res\stdim120.bmp

IDC_RIGHTARROW      CURSOR          res\rarrow.cur

IDC_CONTEXTHELP     CURSOR          res\help.cur

IDC_MAGNIFY         CURSOR          res\magnify.cur

IDC_NODROP          CURSOR          res\nodrop.cur

IDC_TABLETOP        CURSOR          res\tabletop.cur

IDC_HSIZEBAR        CURSOR          res\sizebarh.cur

IDC_VSIZEBAR        CURSOR          res\sizebarv.cur

IDC_HSPLITBAR       CURSOR          res\splith.cur

IDC_VSPLITBAR       CURSOR          res\splitv.cur

IDC_SMALLARROWS     CURSOR          res\sarrows.cur

IDC_LARGEARROWS     CURSOR          res\larrows.cur

IDC_HARROWS         CURSOR          res\harrows.cur

IDC_VARROWS         CURSOR          res\varrows.cur

IDC_NESWARROWS      CURSOR          res\neswarrs.cur

IDC_NWSEARROWS      CURSOR          res\nwsearrs.cur

//Include the version information

rcinclude bttncur.rcv


BTTNCUR.RCV  (BTTNCUR Sample)

/*

 * BTTNCUR.RCV

 * Buttons & Cursors Version 1.1, March 1993

 *

 * Version resource file for the Button Images and Cursors DLL.

 *

 * Copyright (c)1992-1993 Microsoft Corporation, All Rights Reserved,

 * as applied to redistribution of this source code in source form

 * License is granted to use of compiled code in shipped binaries.

 */

#ifndef WIN32

#include <ver.h>

#endif

//Default is nodebug

#ifndef DEBUG

#define VER_DEBUG                   0

#else

#define VER_DEBUG                   VS_FF_DEBUG

#endif

VS_VERSION_INFO VERSIONINFO

 FILEVERSION        1,1,0,0

 PRODUCTVERSION     1,1,0,0

 FILEFLAGSMASK      VS_FFI_FILEFLAGSMASK

 FILEFLAGS          VER_DEBUG

 FILEOS             VOS_DOS_WINDOWS16

 FILETYPE           VFT_DLL

 FILESUBTYPE        VFT_UNKNOWN

 BEGIN

   BLOCK "StringFileInfo"

BEGIN

 BLOCK "040904E4"

  BEGIN

   VALUE "CompanyName",     "Microsoft Corporation\0", "\0"

   VALUE "FileDescription", "Microsoft Windows(R) Standard Button Images and Cursors", "\0"

   VALUE "FileVersion",     "1.10\0", "\0"

   VALUE "InternalName",    "BTTNCUR.DLL", "\0"

   VALUE "LegalCopyright",  "Copyright \251 1993 Microsoft Corp.", "\0"

   VALUE "OriginalFilename","BTTNCUR.DLL", "\0"

   VALUE "ProductName",     "Microsoft Windows(TM) Standard Button Images and Cursors", "\0"

   VALUE "ProductVersion",  "1.10\0"

  END

   END

   BLOCK "VarFileInfo"

BEGIN

 VALUE "Translation", 0x0409, 0x04E4

END

 END


BTTNCUR.C  (BTTNCUR Sample)

/*

 * BTTNCUR.C

 * Buttons & Cursors Version 1.1, March 1993

 *

 * Public functions to generate different states of toolbar buttons from

 * a single bitmap.  States are normal, pressed, checked, and disabled.

 *

 * Copyright (c)1992-1993 Microsoft Corporation, All Rights Reserved,

 * as applied to redistribution of this source code in source form

 * License is granted to use of compiled code in shipped binaries.

 */

#define STRICT

#include <windows.h>

#include <memory.h>

#include "bttncur.h"

#include "bttncuri.h"

//Display sensitive information

TOOLDISPLAYDATA     tdd;

//Library instance

HINSTANCE           ghInst;

/*

23/1/94 (kerenm)

Add intance count for 32bit dll

*/

int                 cInstances = 0;

//Cache GDI objects to speed drawing.

HDC     hDCGlyphs    = NULL;

HDC     hDCMono      = NULL;

HBRUSH  hBrushDither = NULL;

//Standard images to use in case caller doesn't provide them

HBITMAP rghBmpStandardImages[3];

//Standard button colors.

const COLORREF crStandard[4]={ RGB(0, 0, 0)          //STDCOLOR_BLACK

                      , RGB(128, 128, 128)    //STDCOLOR_DKGRAY

                      , RGB(192, 192, 192)    //STDCOLOR_LTGRAY

                      , RGB(255, 255, 255)};  //STDCOLOR_WHITE

/*

 * Mapping from image identifier to button type (command/attribute).

 * Version 1.00 of this DLL has no attribute images defined, so

 * the code will only support three states for each command

 * button.  Any state is, however, valid for an application

 * defined image.

 */

UINT mpButtonType[TOOLIMAGE_MAX-TOOLIMAGE_MIN+1]=

      {

      BUTTONTYPE_COMMAND, BUTTONTYPE_COMMAND, BUTTONTYPE_COMMAND,

      BUTTONTYPE_COMMAND, BUTTONTYPE_COMMAND, BUTTONTYPE_COMMAND,

      BUTTONTYPE_COMMAND, BUTTONTYPE_COMMAND, BUTTONTYPE_COMMAND

      };

/*

 * LibMain

 *

 * Purpose:

 *  DLL-specific entry point called from LibEntry.  Initializes

 *  global variables and loads standard image bitmaps.

 *

 * Parameters:

 *  hInstance       HANDLE instance of the DLL.

 *  wDataSeg        WORD segment selector of the DLL's data segment.

 *  wHeapSize       WORD byte count of the heap.

 *  lpCmdLine       LPSTR to command line used to start the module.

 *

 * Return Value:

 *  HANDLE          Instance handle of the DLL.

 */

BOOL xxxLibMain(HINSTANCE hInstance)

   {

    int i;

/*

23/1/94 (kerenm)

For WIN32S - should done only once. On NT ghInst is instance dataso it will

always be zero.

*/

#ifdef WIN32

   if (ghInst) {

      return(TRUE);

   }

#endif

   ghInst=hInstance;

    tdd.uDPI     =96;

   tdd.cyBar    =CYBUTTONBAR96;

   tdd.cxButton =TOOLBUTTON_STD96WIDTH;

   tdd.cyButton =TOOLBUTTON_STD96HEIGHT;

   tdd.cxImage  =TOOLBUTTON_STD96IMAGEWIDTH;

   tdd.cyImage  =TOOLBUTTON_STD96IMAGEHEIGHT;

   tdd.uIDImages=IDB_STANDARDIMAGES96;

   for (i=0; i < 3; i++)

      {

      rghBmpStandardImages[i]=LoadBitmap(hInstance

         , MAKEINTRESOURCE(IDB_STANDARDIMAGESMIN+i));

      if (NULL==rghBmpStandardImages[i])

         return FALSE;

      }

   //Perform global initialization.

   if (ToolButtonInit())

      {

      CursorsCache(hInstance);

      return TRUE;

      }

   return FALSE;

   }

#ifdef WIN32

void FAR PASCAL WEP(int);

BOOL WINAPI DllMain

(

   HINSTANCE hInstance,

   ULONG     Reason,

   PCONTEXT  Context

)

{

   OutputDebugString("bttncur LibMain:  bttncur.dll loaded\r\n");

   UNREFERENCED_PARAMETER(Context);

   if (Reason == DLL_PROCESS_DETACH) {

#ifdef WIN32

     if (!--cInstances) {

        WEP(0);

     }

#else

      WEP(0);

#endif

      return TRUE;

   }

   else if (Reason != DLL_PROCESS_ATTACH)

      return TRUE;

/* 1/23/94   */

#ifdef WIN32

   cInstances++;

#endif

   return xxxLibMain(hInstance);

}

#else

HANDLE FAR PASCAL LibMain(HANDLE hInstance, WORD wDataSeg

                    , WORD cbHeapSize, LPSTR lpCmdLine)

   {

    //Perform global initialization.

   if (xxxLibMain(hInstance))

      if (0!=cbHeapSize)

         UnlockData(0);

   return hInstance;

   }

#endif

/*

 * WEP

 *

 * Purpose:

 *  Required DLL Exit function.  Does nothing.

 *

 * Parameters:

 *  bSystemExit     BOOL indicating if the system is being shut

 *                  down or the DLL has just been unloaded.

 *

 * Return Value:

 *  void

 *

 */

void FAR PASCAL WEP(int bSystemExit)

   {

   /*

    * **Developers:  Note that WEP is called AFTER Windows does any

    *                automatic task cleanup.  You may see warnings for

    *                that two DCs, a bitmap, and a brush, were not

    *                deleted before task termination.  THIS IS NOT A

    *                PROBLEM WITH THIS CODE AND IT IS NOT A BUG.  This

    *                WEP function is properly called and performs the

    *                cleanup as appropriate.  The fact that Windows is

    *                calling WEP after checking task cleanup is not

    *                something we can control.  Just to prove it, the

    *                OutputDebugStrings in this and ToolButtonFree

    *                show that the code is exercised.

    */

#ifdef DEBUG

   OutputDebugString ("BttnCur WEP Entry\r\n");

#endif

   CursorsFree();

   ToolButtonFree();

#ifdef DEBUG

   OutputDebugString ("BttnCur WEP Exit\r\n");

#endif

   return;

   }

/*

 * UIToolConfigureForDisplay

 * Public API

 *

 * Purpose:

 *  Initializes the library to scale button images for the display type.

 *  Without calling this function the library defaults to 96 DPI (VGA).

 *  By calling this function an application acknowledges that it must

 *  use the data returned from this function to configure itself for

 *  the display.

 *

 * Parameters:

 *  lpDD            LPTOOLDISPLAYDATA to fill with the display-sensitive

 *                  size values.

 *

 * Return Value:

 *  BOOL            TRUE if the sizes were obtained, FALSE otherwise.

 */

BOOL WINAPI UIToolConfigureForDisplay(LPTOOLDISPLAYDATA lpDD)

   {

   int         cy;

   HDC         hDC;

   if (NULL==lpDD || IsBadWritePtr(lpDD, sizeof(TOOLDISPLAYDATA)))

      return FALSE;

   /*

    * Determine the aspect ratio of the display we're currently

    * running on and calculate the necessary information.

    *

    * By retrieving the logical Y extent of the display driver, you

    * only have limited possibilities:

    *      LOGPIXELSY      Display

    *      ----------------------------------------

    *         48             CGA    (unsupported)

    *         72             EGA

    *         96             VGA

    *        120             8514/a (i.e. HiRes VGA)

    */

   hDC=GetDC(NULL);

   if (NULL==hDC)

      return FALSE;

   cy=GetDeviceCaps(hDC, LOGPIXELSY);

   ReleaseDC(NULL, hDC);

   /*

    * Instead of single comparisons, check ranges instead, so in case

    * we get something funky, we'll act reasonable.

    */

   if (72 >=cy)

      {

      lpDD->uDPI     =72;

      lpDD->cyBar    =CYBUTTONBAR72;

      lpDD->cxButton =TOOLBUTTON_STD72WIDTH;

      lpDD->cyButton =TOOLBUTTON_STD72HEIGHT;

      lpDD->cxImage  =TOOLBUTTON_STD72IMAGEWIDTH;

      lpDD->cyImage  =TOOLBUTTON_STD72IMAGEHEIGHT;

      lpDD->uIDImages=IDB_STANDARDIMAGES72;

      }

   else

      {

      if (72 < cy && 120 > cy)

         {

         lpDD->uDPI     =96;

         lpDD->cyBar    =CYBUTTONBAR96;

         lpDD->cxButton =TOOLBUTTON_STD96WIDTH;

         lpDD->cyButton =TOOLBUTTON_STD96HEIGHT;

         lpDD->cxImage  =TOOLBUTTON_STD96IMAGEWIDTH;

         lpDD->cyImage  =TOOLBUTTON_STD96IMAGEHEIGHT;

         lpDD->uIDImages=IDB_STANDARDIMAGES96;

         }

      else

         {

         lpDD->uDPI     =120;

         lpDD->cyBar    =CYBUTTONBAR120;

         lpDD->cxButton =TOOLBUTTON_STD120WIDTH;

         lpDD->cyButton =TOOLBUTTON_STD120HEIGHT;

         lpDD->cxImage  =TOOLBUTTON_STD120IMAGEWIDTH;

         lpDD->cyImage  =TOOLBUTTON_STD120IMAGEHEIGHT;

         lpDD->uIDImages=IDB_STANDARDIMAGES120;

         }

      }

   return TRUE;

   }

/*

 * ToolButtonInit

 * Internal

 *

 * Purpose:

 *  Initializes GDI objects for drawing images through UIToolButtonDraw.

 *  If the function fails, the function has already performed proper

 *  cleanup.

 *

 * Parameters:

 *  None

 *

 * Return Value:

 *  BOOL            TRUE if initialization succeeded.  FALSE otherwise.

 */

static BOOL ToolButtonInit(void)

   {

   COLORREF        rgbHi;

   //DC for BitBltting the image (the glyph)

   hDCGlyphs=CreateCompatibleDC(NULL);

   //Create a monochrome DC and a brush for doing pattern dithering.

   hDCMono=CreateCompatibleDC(NULL);

   //Windows 3.0 doesn't support COLOR_BTNHIGHLIGHT, so leave it white.

   if (0x0300 < (UINT)GetVersion())

      rgbHi=GetSysColor(COLOR_BTNHIGHLIGHT);

   else

      rgbHi=crStandard[STDCOLOR_WHITE];

   hBrushDither=HBrushDitherCreate(GetSysColor(COLOR_BTNFACE), rgbHi);

   if (NULL==hDCGlyphs || NULL==hDCMono || NULL==hBrushDither)

      {

      //On failure, cleanup whatever might have been allocated.

      ToolButtonFree();

      return FALSE;

      }

   return TRUE;

   }

/*

 * ToolButtonFree

 * Internal

 *

 * Purpose:

 *  Free all GDI allocations made during initialization.  Note that the

 *  DEBUG output included here shows that WEP is called and cleanup actually

 *  occurs.  However, if you watch debug output in DBWIN or on a terminal,

 *  the debugging version of Windows does automatic app cleanup before WEP

 *  is called, leading some to believe that this code is buggy.  The

 *  debug output below shows that we do perform all necessary cleanup.

 *

 * Parameters:

 *  None

 *

 * Return Value:

 *  None

 */

static void ToolButtonFree(void)

   {

   UINT        i;

   if (NULL!=hDCMono)

      DeleteDC(hDCMono);

   hDCMono=NULL;

   if (NULL!=hDCGlyphs)

      DeleteDC(hDCGlyphs);

   hDCGlyphs=NULL;

   if (NULL!=hBrushDither)

      DeleteObject(hBrushDither);

   hBrushDither=NULL;

   for (i=0; i < 3; i++)

      {

      if (NULL!=rghBmpStandardImages[i])

         DeleteObject(rghBmpStandardImages[i]);

      rghBmpStandardImages[i]=NULL;

      }

   return;

   }

/*

 * HBrushDitherCreate

 * Internal

 *

 * Purpose:

 *  Creates and returns a handle to a pattern brush created from

 *  an 8*8 monochrome pattern bitmap.  We use the button face and

 *  highlight colors to indicate the resulting colors of a PatBlt

 *  using this brush.

 *

 * Parameters:

 *  rgbFace         COLORREF of the button face color.

 *  rgbHilight      COLORREF of the button highlight color.

 *

 * Return Value:

 *  HBITMAP         Handle to the dither bitmap.

 */

static HBRUSH HBrushDitherCreate(COLORREF rgbFace, COLORREF rgbHilight)

   {

   struct  //BITMAPINFO with 16 colors

      {

      BITMAPINFOHEADER    bmiHeader;

      RGBQUAD             bmiColors[16];

      } bmi;

   HBRUSH          hBrush=NULL;

   DWORD           patGray[8];

   HDC             hDC;

   HBITMAP         hBmp;

   static COLORREF rgbFaceOld   =0xFFFFFFFF;  //Initially an impossible color

   static COLORREF rgbHilightOld=0xFFFFFFFF;  //so at first we always create

   /*

    * If the colors haven't changed from last time, just return the

    * existing brush.

    */

   if (rgbFace==rgbFaceOld && rgbHilight==rgbHilightOld)

      return hBrushDither;

   rgbFaceOld=rgbFace;

   rgbHilightOld=rgbHilight;

   /*

    * We're going to create an 8*8 brush for PatBlt using the

    * button face color and button highlight color.  We use this

    * brush to affect the pressed state and the disabled state.

    */

   bmi.bmiHeader.biSize         = sizeof(BITMAPINFOHEADER);

   bmi.bmiHeader.biWidth        = 8;

   bmi.bmiHeader.biHeight       = 8;

   bmi.bmiHeader.biPlanes       = 1;

   bmi.bmiHeader.biBitCount     = 1;

   bmi.bmiHeader.biCompression  = BI_RGB;

   bmi.bmiHeader.biSizeImage    = 0;

   bmi.bmiHeader.biXPelsPerMeter= 0;

   bmi.bmiHeader.biYPelsPerMeter= 0;

   bmi.bmiHeader.biClrUsed      = 0;

   bmi.bmiHeader.biClrImportant = 0;

   bmi.bmiColors[0].rgbBlue     = GetBValue(rgbFace);

   bmi.bmiColors[0].rgbGreen    = GetGValue(rgbFace);

   bmi.bmiColors[0].rgbRed      = GetRValue(rgbFace);

   bmi.bmiColors[0].rgbReserved = 0;

   bmi.bmiColors[1].rgbBlue     = GetBValue(rgbHilight);

   bmi.bmiColors[1].rgbGreen    = GetGValue(rgbHilight);

   bmi.bmiColors[1].rgbRed      = GetRValue(rgbHilight);

   bmi.bmiColors[1].rgbReserved = 0;

   //Create the byte array for CreateDIBitmap.

   patGray[6]=patGray[4]=patGray[2]=patGray[0]=0x5555AAAAL;

   patGray[7]=patGray[5]=patGray[3]=patGray[1]=0xAAAA5555L;

   //Create the bitmap

   hDC=GetDC(NULL);

   hBmp=CreateDIBitmap(hDC, &bmi.bmiHeader, CBM_INIT, patGray

                  , (LPBITMAPINFO)&bmi, DIB_RGB_COLORS);

   ReleaseDC(NULL, hDC);

   //Create the brush from the bitmap

   if (NULL!=hBmp)

      {

      hBrush=CreatePatternBrush(hBmp);

      DeleteObject(hBmp);

      }

   /*

    * If we could recreate a brush, clean up and make it the current

    * pattern.  Otherwise the best we can do it return the old one,

    * which will be colored wrong, but at least it works.

    */

   if (NULL!=hBrush)

      {

      if (NULL!=hBrushDither)

         DeleteObject(hBrushDither);

      hBrushDither=hBrush;

      }

   return hBrushDither;

   }

/*

 * UIToolButtonDraw

 * Public API

 *

 * Purpose:

 *  Draws the complete image of a toolbar-style button with a given

 *  image in the center and in a specific state.  The button is drawn

 *  on a specified hDC at a given location, so this function is useful

 *  on standard owner-draw buttons as well as on toolbar controls that

 *  have only one window but show images of multiple buttons.

 *

 * Parameters:

 *  hDC             HDC on which to draw.

 *  x, y            int coordinates at which to draw.

 *  dx, dy          int dimensions of the *button*, not necessarily the image.

 *  hBmp            HBITMAP from which to draw the image.

 *  bmx, bmy        int dimensions of each bitmap in hBmp.  If hBmp is NULL

 *                  then these are forced to the standard sizes.

 *  iImage          int index to the image to draw in the button

 *  uStateIn        UINT containing the state index for the button and the

 *                  color control bits.

 *

 * Return Value:

 *  BOOL            TRUE if drawing succeeded, FALSE otherwise meaning that

 *                  hDC is NULL or hBmp is NULL and iImage is not a valid

 *                  index for a standard image.

 */

BOOL WINAPI UIToolButtonDraw(HDC hDC, int x, int y, int dx, int dy

   , HBITMAP hBmp, int bmx, int bmy, int iImage, UINT uStateIn)

   {

   return UIToolButtonDrawTDD(hDC, x, y, dx, dy, hBmp, bmx, bmy, iImage

      , uStateIn, &tdd);

   }

/*

 * UIToolButtonDrawTDD

 * Public API

 *

 * Purpose:

 *  Draws the complete image of a toolbar-style button with a given

 *  image in the center and in a specific state.  The button is drawn

 *  on a specified hDC at a given location, so this function is useful

 *  on standard owner-draw buttons as well as on toolbar controls that

 *  have only one window but show images of multiple buttons.

 *

 *  This is the same as UIToolButtonDraw but adds the pTDD configuration

 *  structure.  UIToolButtonDraw calls us with that pointing to the

 *  default 96dpi structure.

 *

 * Parameters:

 *  hDC             HDC on which to draw.

 *  x, y            int coordinates at which to draw.

 *  dx, dy          int dimensions of the *button*, not necessarily the image.

 *  hBmp            HBITMAP from which to draw the image.

 *  bmx, bmy        int dimensions of each bitmap in hBmp.  If hBmp is NULL

 *                  then these are forced to the standard sizes.

 *  iImage          int index to the image to draw in the button

 *  uStateIn        UINT containing the state index for the button and the

 *                  color control bits.

 *  pTDD            LPTOOLDISPLAYDATA containing display configuration.

 *                  Can be NULL if hBmp is non-NULL.

 *

 * Return Value:

 *  BOOL            TRUE if drawing succeeded, FALSE otherwise meaning that

 *                  hDC is NULL or hBmp is NULL and iImage is not a valid

 *                  index for a standard image.

 */

BOOL WINAPI UIToolButtonDrawTDD(HDC hDC, int x, int y, int dx, int dy

   , HBITMAP hBmp, int bmx, int bmy, int iImage, UINT uStateIn

   , LPTOOLDISPLAYDATA pTDD)

   {

   static COLORREF crSys[5];  //Avoid stack arrays in DLLs: use static

   UINT            uState=(UINT)LOBYTE((WORD)uStateIn);

   UINT            uColors=(UINT)HIBYTE((WORD)uStateIn & PRESERVE_ALL);

   int             xOffsetGlyph, yOffsetGlyph;

   int             i, iSaveDC;

   HDC             hMemDC;

   HGDIOBJ         hObj;

   HBRUSH          hBR;

   HBITMAP         hBmpT;

   HBITMAP         hBmpMono;

   HBITMAP         hBmpMonoOrg;

   HBITMAP         hBmpSave=NULL;

   if (NULL==hDC)

      return FALSE;

   /*

    * If we're given no image bitmap, then use the standard and validate the

    * image index.  We also enforce the standard bitmap size and the size of

    * the button (as requested by User Interface designers).

    */

   if (NULL==hBmp && !(uState & BUTTONGROUP_BLANK))

      {

      hBmp=rghBmpStandardImages[pTDD->uIDImages-IDB_STANDARDIMAGESMIN];

      bmx=pTDD->cxImage;            //Force bitmap dimensions

      bmy=pTDD->cyImage;

      dx=pTDD->cxButton;            //Force button dimensions

      dy=pTDD->cyButton;

      if (iImage > TOOLIMAGE_MAX)

         return FALSE;

      /*

       * If we are using a standard command button, verify that the state

       * does not contain the LIGHTFACE group which only applies to

       * attribute buttons.

       */

      if (BUTTONTYPE_COMMAND==mpButtonType[iImage]

         && (uState & BUTTONGROUP_LIGHTFACE))

         return FALSE;

      }

   //Create a dithered bitmap.

   hBmpMono=CreateBitmap(dx-2, dy-2, 1, 1, NULL);

   if (NULL==hBmpMono)

      return FALSE;

   hBmpMonoOrg=(HBITMAP)SelectObject(hDCMono,  hBmpMono);

   //Save the DC state before we munge on it.

   iSaveDC=SaveDC(hDC);

   /*

    * Draw a button sans image.  This also fills crSys with the system

    * colors for us which has space for five colors.  We don't use the

    * fifth, the frame color, in this function.

    */

   DrawBlankButton(hDC, x, y, dx, dy, (BOOL)(uState & BUTTONGROUP_DOWN), crSys);

   //Shift coordinates to account for the button's border

   x++;

   y++;

   dx-=2;

   dy-=2;

   /*

    * Determine the offset necessary to center the image but also reflect

    * the pushed-in state, which means just adding 1 to the up state.

    */

   i=(uState & BUTTONGROUP_DOWN) ? 1 : 0;

   xOffsetGlyph=((dx-bmx) >> 1)+i;

   yOffsetGlyph=((dy-bmy) >> 1)+i;

   //Select the given image bitmap into the glyph DC before calling MaskCreate

   if (NULL!=hBmp)

      hBmpSave=(HBITMAP)SelectObject(hDCGlyphs, hBmp);

   /*

    * Draw the face on the button.  If we have an up or [mouse]down

    * button then we can just draw it as-is.  For indeterminate,

    * disabled, or down disabled we have to gray the image and possibly

    * add a white shadow to it (disabled/down disabled).

    *

    * Also note that for the intermediate state we first draw the normal

    * up state, then proceed to add disabling looking highlights.

    */

   //Up, mouse down, down, indeterminate

   if ((uState & BUTTONGROUP_ACTIVE) && !(uState & BUTTONGROUP_BLANK))

      {

      BOOL            fColorsSame=TRUE;

      /*

       * In here we pay close attention to the system colors.  Where

       * the source image is black, we paint COLOR_BTNTEXT.  Where

       * light gray, we paint COLOR_BTNFACE.  Where dark gray we paint

       * COLOR_BTNSHADOW, and where white we paint COLOR_BTNHILIGHT.

       *

       * The uColors variable contains flags to prevent color

       * conversion.  To do a little optimization, we just do a

       * single BitBlt if we're preserving all colors or if no colors

       * are different than the standards, which is by far the most

       * common case.  Otherwise, cycle through the four colors we can

       * convert and do a BitBlt that converts it to the system color.

       */

      //See what colors are different.

      for (i=STDCOLOR_BLACK; i<=STDCOLOR_WHITE; i++)

         fColorsSame &= (crSys[i]==crStandard[i]);

      if (PRESERVE_ALL==uColors || fColorsSame)

         {

         BitBlt(hDC, x+xOffsetGlyph, y+yOffsetGlyph, bmx, bmy

               , hDCGlyphs, iImage*bmx, 0, SRCCOPY);

         }

      else

         {

         /*

          * Cycle through hard-coded colors and create a mask that has all

          * regions of that color in white and all other regions black.

          * Then we select a pattern brush of the color to convert to:

          * if we aren't converting the color then we use a brush of

          * the standard hard-coded color, otherwise we use the actual

          * system color.  The ROP_DSPDxax means that anything that's

          * 1's in the mask get the pattern, anything that's 0 is unchanged

          * in the destination.

          *

          * To prevent too many Blts to the screen, we use an intermediate

          * bitmap and DC.

          */

         hMemDC=CreateCompatibleDC(hDC);

         //Make sure conversion of monochrome to color stays B&W

         SetTextColor(hMemDC, 0L);                     //0's in mono -> 0

         SetBkColor(hMemDC, (COLORREF)0x00FFFFFF);     //1's in mono -> 1

         hBmpT=CreateCompatibleBitmap(hDC, bmx, bmy);

         SelectObject(hMemDC, hBmpT);

         //Copy the unmodified bitmap to the temporary bitmap

         BitBlt(hMemDC, 0, 0, bmx, bmy, hDCGlyphs, iImage*bmx, 0, SRCCOPY);

         for (i=STDCOLOR_BLACK; i<=STDCOLOR_WHITE; i++)

            {

            //Convert pixels of the color to convert to 1's in the mask

            SetBkColor(hDCGlyphs, crStandard[i]);

            BitBlt(hDCMono, 0, 0, bmx, bmy, hDCGlyphs, iImage*bmx, 0, SRCCOPY);

            //Preserve or modify the color depending on the flag.

            hBR=CreateSolidBrush((uColors & (1 << i))

                            ? crStandard[i] : crSys[i]);

            if (NULL!=hBR)

               {

               hObj=SelectObject(hMemDC, hBR);

               if (NULL!=hObj)

                  {

                  BitBlt(hMemDC, 0, 0, dx-1, dy-1, hDCMono, 0, 0, ROP_DSPDxax);

                  SelectObject(hMemDC, hObj);

                  }

               DeleteObject(hBR);

               }

            }

         //Now put the final version on the display and clean up

         BitBlt(hDC, x+xOffsetGlyph, y+yOffsetGlyph, dx-1, dy-1

               , hMemDC, 0, 0, SRCCOPY);

         DeleteDC(hMemDC);

         DeleteObject(hBmpT);

         }

      }

   //Disabled and indeterminate states (unless we're blank)

   if ((uState & BUTTONGROUP_DISABLED || ATTRIBUTEBUTTON_INDETERMINATE==uState)

      && !(uState & BUTTONGROUP_BLANK))

      {

      //Grayed state (up or down, no difference)

      MaskCreate(iImage, dx, dy, bmx, bmy, xOffsetGlyph, yOffsetGlyph, 0);

      //Make sure conversion of monochrome to color stays B&W

      SetTextColor(hDC, 0L);                     //0's in mono -> 0

      SetBkColor(hDC, (COLORREF)0x00FFFFFF);     //1's in mono -> 1

      //If we're disabled, up or down, draw the highlighted shadow.

      if (uState & BUTTONGROUP_DISABLED)

         {

         hBR=CreateSolidBrush(crSys[SYSCOLOR_HILIGHT]);

         if (NULL!=hBR)

            {

            hObj=SelectObject(hDC, hBR);

            if (NULL!=hObj)

               {

               //Draw hilight color where we have 0's in the mask

               BitBlt(hDC, x+1, y+1, dx-2, dy-2, hDCMono, 0, 0, ROP_PSDPxax);

               SelectObject(hDC, hObj);

               }

            DeleteObject(hBR);

            }

         }

      //Draw the gray image.

      hBR=CreateSolidBrush(crSys[SYSCOLOR_SHADOW]);

      if (NULL!=hBR)

         {

         hObj=SelectObject(hDC, hBR);

         if (NULL!=hObj)

            {

            //Draw the shadow color where we have 0's in the mask

            BitBlt(hDC, x, y, dx-2, dy-2, hDCMono, 0, 0, ROP_PSDPxax);

            SelectObject(hDC, hObj);

            }

         DeleteObject(hBR);

         }

      }

   //If the button is selected do the dither brush avoiding the glyph

   if (uState & BUTTONGROUP_LIGHTFACE)

      {

      HBRUSH      hBRDither;

      /*

       * Get the dither brush.  This function will recreate it if

       * necessary or return the global one if the colors already match.

       */

      hBRDither=HBrushDitherCreate(crSys[SYSCOLOR_FACE], crSys[SYSCOLOR_HILIGHT]);

      hObj=SelectObject(hDC, hBRDither);

      if (NULL!=hObj)

         {

         /*

          * The mask we create now determines where the dithering

          * ends up.  In the down disabled state, we have to preserve

          * the highlighted shadow, so the mask we create must have

          * two masks of the original glyph, one of them offset by

          * one pixel in both x & y.  For the indeterminate state,

          * we have to mask all highlighted areas.  The state passed

          * to MaskCreate matters here (we've used zero before).

          */

         MaskCreate(iImage, dx, dy, bmx, bmy

                  , xOffsetGlyph-1, yOffsetGlyph-1, uState);

         //Convert monochrome masks to B&W color bitmap in the BitBlt.

         SetTextColor(hDC, 0L);

         SetBkColor(hDC, (COLORREF)0x00FFFFFF);

         /*

          * Only draw the dither brush where the mask is 1's.  For

          * the indeterminate state we have to not overdraw the

          * shadow highlight so we use dx-3, dy-3 instead of dx-1

          * and dy-1.  We do this whether or not we're blank.

          */

         i=(ATTRIBUTEBUTTON_INDETERMINATE==uState

            || BLANKBUTTON_INDETERMINATE==uState) ? 3 : 1;

         BitBlt(hDC, x+1, y+1, dx-i, dy-i, hDCMono, 0, 0, ROP_DSPDxax);

         SelectObject(hDC, hObj);

         }

      //DO NOT delete hBRDither!  It's a reference to a shared global.

      }

   //Cleanup hDCGlyphs:  Must do AFTER calling MaskCreate

   if (NULL!=hBmpSave)

      SelectObject(hDCGlyphs, hBmpSave);

   SelectObject(hDCMono,   hBmpMonoOrg);

   DeleteObject(hBmpMono);

   //Restore everything in the DC.

   RestoreDC(hDC, iSaveDC);

   return TRUE;

   }

/*

 * DrawBlankButton

 *

 * Purpose:

 *  Draws a button with no face using the current system colors in either

 *  an up or down state.

 *

 * Parameters:

 *  hDC             HDC on which to draw

 *  x, y            int coordinates where we start drawing

 *  dx,dy           int size of the button

 *  fDown           BOOL indicating the up or down state of the button

 *  pcr             COLORREF FAR * to five colors in which we store text,

 *                  shadow, face, highlight, and frame colors.  This is

 *                  a matter of convenience for the caller, since we have

 *                  to load these colors anyway we might as well send them

 *                  back.

 *

 * Return Value:

 *  None

 */

static void DrawBlankButton(HDC hDC, int x, int y, int dx, int dy

   , BOOL fDown, COLORREF FAR *pcr)

   {

   //Get the current system colors for buttons.

   pcr[0]=GetSysColor(COLOR_BTNTEXT);

   pcr[1]=GetSysColor(COLOR_BTNSHADOW);

   pcr[2]=GetSysColor(COLOR_BTNFACE);

   //Windows 3.0 doesn't support COLOR_BTNHIGHLIGHT, so leave it white.

   if (0x0300 < (UINT)GetVersion())

      pcr[3]=GetSysColor(COLOR_BTNHIGHLIGHT);

   else

      pcr[3]=crStandard[STDCOLOR_WHITE];

   pcr[4]=GetSysColor(COLOR_WINDOWFRAME);

   //Draw the border around the button.

   PatB(hDC, x+1,    y,      dx-2, 1,    pcr[4]);

   PatB(hDC, x+1,    y+dy-1, dx-2, 1,    pcr[4]);

   PatB(hDC, x,      y+1,    1,    dy-2, pcr[4]);

   PatB(hDC, x+dx-1, y+1,    1,    dy-2, pcr[4]);

   //Shift coordinates to account for the border we just drew

   x++;

   y++;

   dx-=2;

   dy-=2;

   //Paint the interior grey as a default.

   PatB(hDC, x, y, dx, dy, pcr[2]);

   /*

    * Draw shadows and highlights.  The DOWN grouping that contains

    * down, mouse down, and down disabled are drawn depressed.  Up,

    * indeterminate, and disabled are drawn up.

    */

   if (fDown)

      {

      PatB(hDC, x, y, 1,  dy, pcr[1]);

      PatB(hDC, x, y, dx, 1,  pcr[1]);

      }

   else

      {

      //Normal button look.

      PatB(hDC, x, y, 1,    dy-1, pcr[3]);

      PatB(hDC, x, y, dx-1, 1,    pcr[3]);

      PatB(hDC, x+dx-1, y,      1,  dy, pcr[1]);

      PatB(hDC, x,      y+dy-1, dx, 1,  pcr[1]);

      PatB(hDC, x+1+dx-3, y+1,    1,    dy-2, pcr[1]);

      PatB(hDC, x+1,      y+dy-2, dx-2, 1,    pcr[1]);

      }

   return;

   }

/*

 * PatB

 * Internal

 *

 * Purpose:

 *  A more convenient PatBlt operation for drawing button borders and

 *  highlights.

 *

 * Parameters:

 *  hDC             HDC on which to paint.

 *  x, y            int coordinates at which to paint.

 *  dx, dy          int dimensions of rectangle to paint.

 *  rgb             COLORREF to use as the background color.

 *

 * Return Value:

 *  None

 */

static void PatB(HDC hDC, int x, int y, int dx, int dy, COLORREF rgb)

   {

   RECT        rc;

   SetBkColor(hDC, rgb);

   SetRect(&rc, x, y, x+dx, y+dy);

   ExtTextOut(hDC, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);

   }

/*

 * MaskCreate

 * Internal

 *

 * Purpose:

 *  Creates a monochrome mask bitmap of the given image at the given offset

 *  in the global hDCMono.  Anywhere in the image that you have the light

 *  gray (STDCOLOR_LTGRAY) or the white highlight (STDCOLOR_WHITE) you get

 *  get 1's.  All other pixels are 0's

 *

 * Parameters:

 *  iImage          UINT index of the image for which to create a mask.

 *  dx, dy          int dimensions of the button.

 *  bmx, bmy        int dimensions of the bitmap to use.

 *  xOffset         int offset for x inside hDCMono where we paint.

 *  yOffset         int offset for y inside hDCMono where we paint.

 *  uState          UINT state of the image.  Special cases are made

 *                  for ATTRIBUTEBUTTON_DOWNDISABLED and

 *                  ATTRIBUTEBUTTON_INDETERMINATE.  In any case where you

 *                  do not want a special case, pass zero here, regardless

 *                  of the true button state.

 *

 * Return Value:

 *  None

 */

static void MaskCreate(UINT iImage, int dx, int dy, int bmx, int bmy

   ,int xOffset, int yOffset, UINT uState)

   {

   //Initalize whole area with zeros

   PatBlt(hDCMono, 0, 0, dx, dy, WHITENESS);

   if (uState & BUTTONGROUP_BLANK)

      return;

   //Convert face colored pixels to 1's. all others to black.

   SetBkColor(hDCGlyphs, crStandard[STDCOLOR_LTGRAY]);

   BitBlt(hDCMono, xOffset, yOffset, bmx, bmy, hDCGlyphs, iImage*bmx, 0, SRCCOPY);

   //In the indeterminate state, don't turn highlight's to 1's. Leave black.

   if (ATTRIBUTEBUTTON_INDETERMINATE!=uState)

      {

      //Convert highlight colored pixels to 1's and OR them with the previous.

      SetBkColor(hDCGlyphs, crStandard[STDCOLOR_WHITE]);

      BitBlt(hDCMono, xOffset, yOffset, bmx, bmy, hDCGlyphs, iImage*bmx, 0, SRCPAINT);

      }

   /*

    * For the down disabled state, AND this same mask with itself at an

    * offset of 1, which accounts for the highlight shadow.

    */

   if (ATTRIBUTEBUTTON_DOWNDISABLED==uState)

      BitBlt(hDCMono, 1, 1, dx-1, dy-1, hDCMono,  0, 0, SRCAND);

   return;

   }


BTTNCURI.H  (BTTNCUR Sample)

/*

 * BTTNCURI.H

 *

 * Private include file for the Button Images and Cursors DLL.

 *

 * Copyright (c)1992-1993 Microsoft Corporation, All Right Reserved,

 * as applied to redistribution of this source code in source form

 * License is granted to use of compiled code in shipped binaries.

 */

#ifdef __cplusplus

extern "C"

{

#endif

//Function prototypes.

//BTTNCUR.C

//HANDLE FAR  PASCAL LibMain(HANDLE, WORD, WORD, LPSTR);

//void   FAR  PASCAL WEP(int);

static BOOL        ToolButtonInit(void);

static void        ToolButtonFree(void);

static HBRUSH      HBrushDitherCreate(COLORREF, COLORREF);

static void        DrawBlankButton(HDC, int, int, int, int, BOOL, COLORREF FAR *);

static void        PatB(HDC, int, int, int, int, COLORREF);

static void        MaskCreate(UINT, int, int, int, int, int, int, UINT);

//CURSORS.C

void               CursorsCache(HINSTANCE);

void               CursorsFree(void);

/*

 * Wierd Wild Wooly Waster (raster) Ops for special bltting.  See the

 * Windows SDK reference on Raster Operation Codes for explanation of

 * these.  The DSPDxax and PSDPxax is a reverse-polish notation for

 * operations where D==Destination, S==Source, P==Patterm, a==AND,

 * x==XOR.  Both of these codes are actually described in Programming

 * Windows by Charles Petzold, Second Edition, pages 622-624.

 */

#define ROP_DSPDxax  0x00E20746

#define ROP_PSDPxax  0x00B8074A

/*

 * Color indices into an array of standard hard-coded black, white, and

 * gray colors.

 */

#define STDCOLOR_BLACK      0

#define STDCOLOR_DKGRAY     1

#define STDCOLOR_LTGRAY     2

#define STDCOLOR_WHITE      3

/*

 * Color indices into an array of system colors, matching those in

 * the hard-coded array for the colors they replace.

 */

#define SYSCOLOR_TEXT       0

#define SYSCOLOR_SHADOW     1

#define SYSCOLOR_FACE       2

#define SYSCOLOR_HILIGHT    3

/*

 * Button types, used internally to distinguish command buttons from

 * attribute buttons to enforce three-state or six-state possibilities.

 * Command buttons can only have three states (up, mouse down, disabled)

 * while attribute buttons add (down, down disabled, and indeterminate).

 */

#define BUTTONTYPE_COMMAND      0

#define BUTTONTYPE_ATTRIBUTE    1

#ifdef __cplusplus

}

#endif


CHANGES.TXT  (BTTNCUR Sample)

Changes in BTTNCUR.DLL Source Code and Documentation from Version 1.00b

to Version 1.1.  See also below for 1.00 to 1.00b changes.

BTTNCUR.DLL version 1.1 is now fully compatible and tested under Windows

3.0.  Previously the demo application crashed under Windows 3.0 on calls

to the non-existent MoveToEx (Win32 compatible).  Version 1.1 only

uses MoveToEx for builds where the symbol WINVER < 0x030a.

The images have been updated slightly and are now provided for 72dpi

(ega), 96dpi (vga), and 120dpi (super vga)

Version 1.1 completely handles system color changes unlike version 1.00x.

This new version will dynamically convert black, light gray, dark gray,

and white pixels in the image bitmap into system colors set for the

button text, button shadow, button face, and button highlight, respectively.

If you have blue, red, yellow, and green button colors, BTTNCUR.DLL will

now work perfectly with all of them.

BTTNCUR.DLL Version 1.1 also supports color images better by allowing

you to control which colors in the image bitmap are converted to system

colors.  By default, any black, gray, or white colors are converted

into system button colors as decribed in the last paragraph.  BTTNCUR.H

defines new PRESERVE_* flags for each of the four colors that are liable

to be converted.  By specifing one or more flags you prevent BTTNCUR

from changing that color to a system color.  For example, if you

want to preserve all black pixels in your image, specify PRESERVE_BLACK

when calling UIToolButtonDraw.

Applications should obtain configuration data for the current display

through UIToolConfigureForDisplay.  With this data the application can

configure itself for the correct toolbar size and button sizes and load

the appropriate application supplied bitmaps.

Applications using UIToolConfigureForDisplay should now use

UIToolButtonDrawTDD instead of UIToolButtonDraw, passing one extra

parameter, a pointer to the TOOLDISPLAYDATA.  Applications that

still call UIToolButtonDraw will always use 96dpi.

NOTE:  BTTNCUR.WRI has not been updated to reflect the new APIs.

------------------------

BTTNCUR.H changes

    Added PRESERVE_ flags to allow application to control color conversions

    from black, dark gray, light gray, and white into the

    file compatible with C++.

    Added prototype for UIToolConfigureForDisplay, TOOLDISPLAYDATA structure,

    and definitions for button and image sizes on 72dpi, 96dpi, and 120dpi.

------------------------

BTTNCUR.RCV version changes

    FILEVERSION and PRODUCTVERSION changed from 1,0,0,2 to 1,0,1,0

    VALUE "FileVersion" and VALUE "ProductVersion" changed from

        "1.00b\0","\0" to "1.1\0","\0"

------------------------

BTTNCURI.H changes

    Defined STDCOLOR_* values as indices into an array in BTTNCUR.C

    that holds hard-coded default button color that never change

    regardless of the system colors.  Also defined SYSCOLOR_*

    flags that matched STDCOLOR_* flags for uniform array indices.

    Removed NEAR, FAR, and PASCAL from any function that didn't need it

    so we can port to Windows NT cleanly.

------------------------

BTTNCUR.C source code changes.  There are significant modifications.

Overall:

    Updated header comment

    Removed NEAR, FAR, and PASCAL from any function that didn't need it

    so we can port to Windows NT cleanly.

    #define STRICT at top of file

Globals:

    Eliminated the COLORREFs prefixed with RGB.  Only a few are needed

    statically and were moved to HBrushDitherCreate.

    Also added an array of standard colors used in the standard images:

    static const

    COLORREF crStandard[4]={ RGB(0, 0, 0)         //STDCOLOR_BLACK

                           , RGB(128, 128, 128)   //STDCOLOR_DKGRAY

                           , RGB(192, 192, 192)   //STDCOLOR_LTGRAY

                           , RGB(255, 255, 255)}; //STDCOLOR_WHITE

    Added an array of standard images instead of just 96dpi versions.

UIToolConfigureForDisplay:

    Added function to return the resolution of the display and

    size information about button and image sizes.

ToolButtonInit():

    Call to CreatePatternBrush moved into HBrushDitherCreate.

    Conditionally sets the highlight color for HDitherBrushCreate

    depending on Windows 3.x or Windows 3.0 (3.0 did not support

    COLOR_BTNHIGHLIGHT).

ToolButtonFree():

    Removed some old debug output no longer useful.

HDitherBitmapCreate()

    Renamed to HBrushDitherCreate.

    Moved CreatePatterBrush code from ToolButtonInit into this

    function.

    To support changing system colors, this function maintains

    static variables for the face and highlight colors that we

    use to create the brush.  If the function is called and the

    current colors in the global hBrushDither are different than

    the system colors, we recreate the brush and update the global

    hBrushDither, deleting the old brush.  Otherwise we just return

    hBrushDither.

    Note that if we fail to create the new brush we just maintain

    the old.  We'll paint something, albeit not in the right colors,

    but something nontheless.

UIToolButtonDraw():

    Calls UIToolButtonDrawTDD with default display configuration.

UIToolButtonDrawTDD():

    This is the function that was overhauled the most, specifically

    to handle variable colors.

    First, we added several local variables of which two are important.

    crSys is an array of system colors for the text, shadow, face,

    highlight, and frame, declared as static to keep references to

    it off DS instead of SS; if it's in SS things will crash.  The second

    important variable is uColor, which receives the color preservation

    flags passed in the hibyte of the uState parameter to UIToolButtonDraw.

    All the code to draw a blank button outline was moved into a separate

    function DrawBlankButton.  Since this procedure needs all the system

    colors to do it's thing, I've set it up to take an array of five

    COLORREFs (exactly crSys) in which it stores those color (it also

    uses it as its color variables).  This way we only have to call

    GetSysColor once for each system color.

    Anything dealing with the dithered brush is moved to the

    BUTTONGROUP_LIGHTFACE case where we just get the current brush

    by calling HBrushDitherCreate, passing it the current face

    and highlight colors.  Remember that is these colors match those

    used in the currently held global hBrushDither, this function just

    returns that global, so it's quite fast.  We have to be very careful

    not to delete this brush where we're done with it since it is global.

    The largest amount of new code is under the line:

    if ((uState & BUTTONGROUP_ACTIVE) && !(uState & BUTTONGROUP_BLANK))

    This has changed from a single BitBlt call to a much more complex

    operation to handle specific color conversions and preservations.

    A little optimization was done to detect when the system colors

    for buttons match the defaults, that is, black, dark gray, light gray,

    and white for text, shadow, face, and highlight.  If these colors

    all match, or if the caller requested preservation of all colors,

    the we just do the single BitBlt of old.

    Otherwise we loop through each of the black/white/gray colors

    that need possible conversion.  For each one we create a mask

    that contains 1's where the converting color exists in the image

    and 0's everywhere else.  For each color then we BitBlt the

    mask, a brush matching the system color we're converting to,

    and the destination bitmap (which we initialize with the unmodified

    image itself) using ROP_DSPDxax.  This leaves any color but the

    one under conversion alone and replaces the converted color with

    the system color.

    If the caller set a specific flag to preserve one or more specific

    colors, then we replace the standard color with the standard color,

    resulting in a no-op.

    Finally, to reduce flicker for this four Blt operation we create

    and build the final image in a temporary bitmap, making it 6 total

    Blts to handle the color changes.  But since we optimized for the

    99% case where the system colors are the standard colors, this isn't

    too much of a consideration.

    color conversions.

DrawBlankButton():

    New internal function.  Moved code from UIToolButtonDraw here.

------------------------

CURSORS.C

    Updated header comment

    #define STRICT at top of file

    Removed PASCAL on both internal functions.

    CursorsFree

        Eliminated all the code inside this function as it was unnecessary.

    UICursorLoad

        Eliminated code to revalidate a cursor in the array.  Unnecessary.

------------------------

BCDEMO.C

    Tested for running under Windows 3.0 and avoided MoveToEx calls,

    using MoveTo instead.  Calling MoveToEx in a Windows 3.1 app

    marked as 3.0 compatible under 3.0 causes an unknown GP fault.

    Uses UIToolButtonConfigureForDisplay and UIToolButtonDrawTDD.

------------------------

BTTNCUR.WRI

    Updated to document PRESERVE_ flags and new capabilities of the library

    with the exception of display configuration (no time).

    Corrected two typos.

------------------------------------------------------------------------------

Changes in BTTNCUR.DLL Source Code and Documentation from Version 1.00

to Version 1.00b

------------------------

BTTNCUR.H changes

    Added #ifdef __cplusplus to include extern "C" making the

    file compatible with C++.

------------------------

BTTNCURI.H changes

    Added #ifdef __cplusplus to include extern "C" making the

    file compatible with C++.

    Removed code contained between a #ifdef NEVER that is unused.

------------------------

BTTNCUR.RCV version changes

    FILEVERSION and PRODUCTVERSION changed from 1,0,0,0 to 1,0,0,2

    VALUE "FileVersion" and VALUE "ProductVersion" changed from

        "1.00\0","\0" to "1.00b\0","\0"

------------------------

BTTNCUR.C source code changes.

    Added a global for the frame color

    static COLORREF rgbFrame   =RGB(0, 0, 0);

WEP():

    Added comment about resource cleanup messages in DEBUG mode.

ToolButtonInit():

    Added the line below just before the assignment of hDCGlyphs:

        rgbFrame=GetSysColor(COLOR_WINDOWFRAME);

    This insures that the frame color is properly shown on plasma

    displays.

ToolButtonFree():

    Added the following lines just before return:

        if (NULL!=hBmpStandardImages)

            DeleteObject(hBmpStandardImages);

        hBmpStandardImages=NULL;

UIToolButtonDraw():

    The image centering is one too high.  The line

        yOffsetGlyph=((dy-bmy) >> 1)-1;

    now reads:

        yOffsetGlyph=(dy-bmy) >> 1;

    The declaration HBITMAP hBmp; now read HBITMAP hBmp=NULL;

    The line hBmpT=SelectObject(hDCGlyphs, hBmp); is now two:

        if (NULL!=hBmp)

            SelectObject(hDCGlyphs, hBmp);

    The line SelectObject(hDCGlyphs, hBmpT); is now two:

        if (NULL!=hBmpT)

            SelectObject(hDCGlyphs, hBmpT);

------------------------

BTTNCUR.BMP

    Fixed the images to be 16*15 (the standard) instead of 16*16

    as they originally were.  Changed the label "16x16" to "16x15".

    Copied an image of the disabled state of Context-Sensitive Help

    to this bitmap as it was previously missing.

------------------------

BTTNCUR.WRI

    Corrected a few typos.  Added comment about application termination

    and erroneous debug warnings.


CURSORS.C  (BTTNCUR Sample)

/*

 * CURSORS.C

 * Buttons & Cursors Version 1.1, March 1993

 *

 * Public functions to retrieve new cursors from the BTTNCUR DLL based

 * on ordinal to prevent applications from necessarily calling LoadCursor

 * directly on the DLL.

 *

 * Copyright (c)1992-1993 Microsoft Corporation, All Rights Reserved,

 * as applied to redistribution of this source code in source form

 * License is granted to use of compiled code in shipped binaries.

 */

#define STRICT

#include <windows.h>

#include "bttncur.h"

#include "bttncuri.h"

/*

 * The +1 is because MAX is the highest allowable number and MIN is not

 * necessarily zero.

 */

HCURSOR rgHCursors[IDC_NEWUICURSORMAX-IDC_NEWUICURSORMIN+1];

/*

 * CursorsCache

 * Internal

 *

 * Purpose:

 *  Loads all the cursors available through NewUICursorLoad into

 *  a global array.  This way we can clean up all the cursors without

 *  placing the burden on the application.

 *

 * Parameters:

 *  hInst           HANDLE of the DLL instance.

 *

 * Return Value:

 *  None.  If any of the LoadCursor calls fail, then the corresponding

 *  array entry is NULL and NewUICursorLoad will fail.  Better to fail

 *  an app getting a cursor than failing to load the app just for that

 *  reason; and app can attempt to load the cursor on startup if it's

 *  that important, and fail itself.

 */

void CursorsCache(HINSTANCE hInst)

{

UINT            i;

for (i=IDC_NEWUICURSORMIN; i<=IDC_NEWUICURSORMAX; i++)

rgHCursors[i-IDC_NEWUICURSORMIN]=LoadCursor(hInst, MAKEINTRESOURCE(i));

return;

}

/*

 * CursorsFree

 * Internal

 *

 * Purpose:

 *  Frees all the cursors previously loaded through CursorsCache.

 *

 * Parameters:

 *  None

 *

 * Return Value:

 *  None

 */

void CursorsFree(void)

{

/*

 * Note that since cursors are discardable resources and should

 * not be used with DestroyCursor, there's nothing to do here.

 * We still provide this API for compatibility and to maintain

 * symmetry.

 */

return;

}

/*

 * UICursorLoad

 * Public API

 *

 * Purpose:

 *  Loads and returns a handle to one of the new standard UI cursors

 *  contained in UITOOLS.DLL.  The application must not call DestroyCursor

 *  on this cursor as it is managed by the DLL.

 *

 * Parameters:

 *  iCursor         UINT index to the cursor to load which must be one

 *                  of the following values:

 *

 *                      IDC_RIGHTARROW    Right pointing standard arrow

 *                      IDC_CONTEXTHELP   Arrow with a ? (context help)

 *                      IDC_MAGNIFY       Magnifying glass for zooming

 *                      IDC_NODROP        Circle with a slash

 *                      IDC_TABLETOP      Small arrow pointing down

 *

 *                      IDC_SMALLARROWS   Thin four-headed arrow

 *                      IDC_LARGEARROWS   Wide four-headed arrow

 *                      IDC_HARROWS       Horizontal two-headed arrow

 *                      IDC_VARROWS       Vertical two-headed arrow

 *                      IDC_NESWARROWS    Two-headed arrow pointing NE<->SW

 *                      IDC_NWSEHARROWS   Two-headed arrow pointing NW<->SE

 *

 *                      IDC_HSIZEBAR      Horizontal two-headed arrow with

 *                                        a single vertical bar down the

 *                                        middle

 *

 *                      IDC_VSIZEBAR      Vertical two-headed arrow with a

 *                                        single horizontal bar down the

 *                                        middle

 *

 *                      IDC_HSPLITBAR     Horizontal two-headed arrow with

 *                                        split double vertical bars down the

 *                                        middle

 *

 *                      IDC_VSPLITBAR     Vertical two-headed arrow with split

 *                                        double horizontal bars down the

 *                                        middle

 *

 * Return Value:

 *  HCURSOR         Handle to the loaded cursor if successful, NULL

 *                  if iCursor is out of range or the function could not

 *                  load the cursor.

 */

HCURSOR WINAPI UICursorLoad(UINT iCursor)

{

HCURSOR     hCur=NULL;

if ((iCursor >= IDC_NEWUICURSORMIN) && (iCursor <= IDC_NEWUICURSORMAX))

hCur=rgHCursors[iCursor-IDC_NEWUICURSORMIN];

return hCur;

}


COMMON

This sample builds the SDKUTIL.LIB, which keeps track of how many times an object is re-entered and keeps the object alive until the first call finally is returned. For information on compiling and building the sample, see MAKEFILE  (COMMON Sample).


MAKEFILE  (COMMON Sample)

#+---------------------------------------------------------------------------

#

#  Microsoft Windows

#  Copyright (C) Microsoft Corporation, 1994.

#

#  File:        makefile

#

#----------------------------------------------------------------------------

!include <$(MSTOOLS)\samples\ole\include\olesampl.mak>

#

#       builds the sdkutil.LIB library

#

OLEFLAGS =

all: sdkutil.lib

clean:

    -del *.lib

    -del *.obj

stablize.obj: stablize.cxx

    $(cc) $(cvars) $(cflags) $(UFLAGS) $(cdebug) $(OLEFLAGS) stablize.cxx

altassrt.obj: altassrt.cxx

    $(cc) $(cvars) $(cflags) $(UFLAGS) $(cdebug) $(OLEFLAGS) altassrt.cxx

sdkutil.lib: altassrt.obj stablize.obj

    lib -out:sdkutil.lib altassrt.obj stablize.obj

    if not exist ..\lib mkdir ..\lib

    copy sdkutil.lib ..\lib


ALTASSRT.CXX  (COMMON Sample)

//+---------------------------------------------------------------------------

//

//  Microsoft Windows

//  Copyright (C) Microsoft Corporation, 1992 - 1994.

//

//  File:       altassrt.cxx

//

//  Contents:   Assertion routines for the SDK

//

//  Functions:  NTSDKAssert

//              PopUpError

//

//  History:    8-19-94   stevebl   Created

//

//----------------------------------------------------------------------------

#include <stdarg.h>

#include <stdio.h>

// ensure that this module always compiles with DEBUG settings.

#undef  NDEBUG

#include "assert.h"

int

PopUpError(

    char const *szMsg,

    int iLine,

    char const *szFile);

extern "C"

{

# ifdef WIN32

#  undef FAR

#  undef NEAR

# else

#  define MessageBoxA MessageBox

# endif

# include <windows.h>

}

//+---------------------------------------------------------------------------

//

//  Function:   PopUpAssert

//

//  Synopsis:   Display assertion information

//

//  Effects:    Called when an assertion is hit.

//

//  History:    8-19-94   stevebl   Created

//

//----------------------------------------------------------------------------

void _CRTAPI1

PopUpAssert(

    void * szFile,

    int iLine,

    void * szMessage)

{

    int id = PopUpError((char const *)szMessage,iLine, (char const *) szFile);

    if (id == IDCANCEL)

    {

#ifdef WIN32

        DebugBreak();

#else

        _asm int 3;

#endif

    }

}

//+------------------------------------------------------------

// Function:    PopUpError

//

// Synopsis:    Displays a dialog box using provided text,

//              and presents the user with the option to

//              continue or cancel.

//

// Arguments:

//      szMsg --        The string to display in main body of dialog

//      iLine --        Line number of file in error

//      szFile --       Filename of file in error

//

// Returns:

//      IDCANCEL --     User selected the CANCEL button

//      IDOK     --     User selected the OK button

//-------------------------------------------------------------

int

PopUpError(

    char const *szMsg,

    int iLine,

    char const *szFile)

{

    int id;

    static char szAssertCaption[128];

    static char szModuleName[128];

    DWORD tid = GetCurrentThreadId();

    DWORD pid = GetCurrentProcessId();

    char * pszModuleName;

    if (GetModuleFileNameA(NULL, szModuleName, 128))

    {

        pszModuleName = strrchr(szModuleName, '\\');

        if (!pszModuleName)

        {

            pszModuleName = szModuleName;

        }

        else

        {

            pszModuleName++;

        }

    }

    else

    {

        pszModuleName = "Unknown";

    }

    sprintf(szAssertCaption,"Process: %s File: %s line %u, thread id %d.%d",

        pszModuleName, szFile, iLine, pid, tid);

    DWORD dwMessageFlags = MB_SETFOREGROUND | MB_TASKMODAL |

                           MB_ICONEXCLAMATION | MB_OKCANCEL;

    id = MessageBoxA(NULL,

                     (char *) szMsg,

                     (LPSTR) szAssertCaption,

                     dwMessageFlags);

    // If id == 0, then an error occurred.  There are two possibilities

    // that can cause the error:  Access Denied, which means that this

    // process does not have access to the default desktop, and everything

    // else (usually out of memory).  Oh well.

    return id;

}


STABLIZE.CXX  (COMMON Sample)

//+---------------------------------------------------------------------------

//

//  Microsoft Windows

//  Copyright (C) Microsoft Corporation, 1992 - 1994.

//

//  File:       stablize.cxx

//

//  Contents:   Stabilization Classes used to stabilize objects during

//              re-entrant calls.

//

//  Classes:    CSafeRefCount

//              CStabilize

//

//  History:    8-26-94   stevebl   Modified from code written by AlexGo

//

//----------------------------------------------------------------------------

#include <windows.h>

#include <ole2.h>

#include <stablize.h>

#include <assert.h>

//+-------------------------------------------------------------------------

//

//  Member:     CSafeRefCount::CSafeRefCount

//

//  Synopsis:   constructor for the safe ref count class

//

//  History:    dd-mmm-yy Author    Comment

//              28-Jul-94 alexgo    author

//              8-26-94   stevebl   modified for use by SDK samples

//

//--------------------------------------------------------------------------

CSafeRefCount::CSafeRefCount()

{

        m_cRefs = 0;

        m_cNest = 0;

        m_fInDelete = FALSE;

}

//+-------------------------------------------------------------------------

//

//  Member:     CSafeRefCount::~CSafeRefCount (virtual)

//

//  History:    dd-mmm-yy Author    Comment

//              28-Jul-94 alexgo    author

//              8-26-94   stevebl   modified for use by SDK samples

//

//--------------------------------------------------------------------------

CSafeRefCount::~CSafeRefCount()

{

        assert(m_cRefs == 0 && m_cNest == 0 && m_fInDelete == TRUE);

}

//+-------------------------------------------------------------------------

//

//  Member:     CSafeRefCount::SafeAddRef

//

//  Synopsis:   increments the reference count on the object

//

//  Returns:    ULONG -- the reference count after the increment

//

//  History:    dd-mmm-yy Author    Comment

//              28-Jul-94 alexgo    author

//              8-26-94   stevebl   modified for use by SDK samples

//

//--------------------------------------------------------------------------

ULONG CSafeRefCount::SafeAddRef()

{

        m_cRefs++;

        return m_cRefs;

}

//+-------------------------------------------------------------------------

//

//  Member:     CSafeRefCount::SafeRelease

//

//  Synopsis:   decrements the reference count on the object

//

//  Effects:    May delete the object!

//

//  Returns:    ULONG -- the reference count after decrement

//

//  Algorithm:  decrements the reference count.  If the reference count

//              is zero AND the nest count is zero AND we are not currently

//              trying to delete our object, then it is safe to delete.

//

//  History:    dd-mmm-yy Author    Comment

//              28-Jul-94 alexgo    author

//              8-26-94   stevebl   modified for use by SDK samples

//

//--------------------------------------------------------------------------

ULONG CSafeRefCount::SafeRelease()

{

        ULONG   cRefs;

        if( m_cRefs > 0 )

        {

                cRefs = --m_cRefs;

                if( m_cRefs == 0 && m_cNest == 0 && m_fInDelete == FALSE )

                {

                        m_fInDelete = TRUE;

                        delete this;

                }

        }

        else

        {

                // somebody is releasing a non-addrefed pointer!!

                assert(NULL == "Release called on a non-addref'ed pointer!\n");

                cRefs = 0;

        }

        return cRefs;

}

//+-------------------------------------------------------------------------

//

//  Member:     CSafeRefCount::IncrementNestCount

//

//  Synopsis:   increments the nesting count of the object

//

//  Arguments:  none

//

//  Returns:    ULONG; the nesting count after increment

//

//  History:    dd-mmm-yy Author    Comment

//              28-Jul-94 alexgo    author

//              8-26-94   stevebl   modified for use by SDK samples

//

//  Notes:      The nesting count is the count of how many times an

//              an object has been re-entered.  For example, suppose

//              somebody calls pFoo->Bar1(), which makes some calls that

//              eventually call pFoo->Bar2();.  On entrace to Bar2, the

//              nest count of the object should be 2 (since the invocation

//              of Bar1 is still on the stack above us).

//

//              It is important to keep track of the nest count so we do

//              not accidentally delete ourselves during a nested invocation.

//              If we did, then when the stack unwinds to the original

//              top level call, it could try to access a non-existent member

//              variable and crash.

//

//--------------------------------------------------------------------------

ULONG CSafeRefCount::IncrementNestCount()

{

        m_cNest++;

        return m_cNest;

}

//+-------------------------------------------------------------------------

//

//  Member:     CSafeRefCount::DecrementNestCount

//

//  Synopsis:   decrements the nesting count and deletes the object

//              (if necessary)

//

//  Effects:    may delete 'this' object!

//

//  Arguments:  none

//

//  Returns:    ULONG, the nesting count after decrement

//

//  Algorithm:  decrements the nesting count.  If the nesting count is zero

//              AND the reference count is zero AND we are not currently

//              trying to delete ourselves, then delete 'this' object

//

//  History:    dd-mmm-yy Author    Comment

//              28-Jul-94 alexgo    author

//              8-26-94   stevebl   modified for use by SDK samples

//

//  Notes:

//

//--------------------------------------------------------------------------

ULONG CSafeRefCount::DecrementNestCount()

{

        ULONG   cNest;

        if( m_cNest > 0 )

        {

                cNest = --m_cNest;

                if( m_cRefs == 0 && m_cNest == 0 && m_fInDelete == FALSE )

                {

                        m_fInDelete = TRUE;

                        delete this;

                }

        }

        else

        {

                // somebody forget to increment the nest count!!

                assert(NULL == "Unbalanced nest count!!");

                cNest = 0;

        }

        return cNest;

}


DEFO2V

This sample creates the DLL used by the OLE 2 Interface Viewer. For information on compiling and building the sample, see MAKEFILE  (DEFO2V Sample).


MAKEFILE  (DEFO2V Sample)

#+---------------------------------------------------------------------------

#

#  Microsoft Windows

#  Copyright (C) Microsoft Corporation, 1994.

#

#  File:        makefile

#

#----------------------------------------------------------------------------

!include <$(MSTOOLS)\samples\ole\include\olesampl.mak>

#

#       Makefile for OLE Sample DEFO2V32.DLL

#

#       builds DEFO2V32.DLL: viewer DLL used by the OLE2VIEW tool.

#

OLEFLAGS = -I ..\..\idl -I ..\..\winhlprs

LINK = $(link)

LINKFLAGS = $(linkdebug)

RCFLAGS = -DWIN32

OBJS = iadvsi_a.obj     \

       iadvsink.obj     \

       idatao_a.obj     \

       idataobj.obj     \

       idisp_a.obj      \

       idisp.obj        \

       tofile_a.obj     \

       tofile.obj       \

       util_a.obj       \

       util.obj

LIBS = $(olelibsdll)

cflags = $(cflags) -DUNICODE -D_UNICODE

all: defo2v32.dll

clean:

    -del *.obj

    -del *.exp

    -del *.res

    -del *.dll

    -del *.lib

iadvsi_a.obj: iadvsi_a.cpp      \

              iadvsink.cpp      \

              precompa.h        \

              precomp.h         \

              defo2v.h          \

              resource.h        \

              util.h            \

              idataobj.h        \

              iadvsink.h

    $(cc) $(cvarsdll) $(cflags) $(cdebug) $(OLEFLAGS) iadvsi_a.cpp

iadvsink.obj: iadvsink.cpp      \

              precomp.h         \

              defo2v.h          \

              resource.h        \

              util.h            \

              idataobj.h        \

              iadvsink.h

    $(cc) $(cvarsdll) $(cflags) $(cdebug) $(OLEFLAGS) iadvsink.cpp

idatao_a.obj: idatao_a.cpp      \

              idataobj.cpp      \

              precompa.h        \

              precomp.h         \

              defo2v.h          \

              resource.h        \

              util.h            \

              idataobj.h        \

              iadvsink.h

    $(cc) $(cvarsdll) $(cflags) $(cdebug) $(OLEFLAGS) idatao_a.cpp

idataobj.obj: idataobj.cpp       \

              precomp.h          \

              defo2v.h           \

              resource.h         \

              util.h             \

              idataobj.h         \

              iadvsink.h

    $(cc) $(cvarsdll) $(cflags) $(cdebug) $(OLEFLAGS) idataobj.cpp

idisp_a.obj: idisp_a.cpp        \

             idisp.cpp          \

             precompa.h         \

             precomp.h          \

             defo2v.h           \

             resource.h         \

             util.h             \

             idisp.h            \

             tofile.h

    $(cc) $(cvarsdll) $(cflags) $(cdebug) $(OLEFLAGS) idisp_a.cpp

idisp.obj:   idisp.cpp          \

             precomp.h          \

             defo2v.h           \

             resource.h         \

             util.h             \

             idisp.h            \

             tofile.h

    $(cc) $(cvarsdll) $(cflags) $(cdebug) $(OLEFLAGS) idisp.cpp

tofile_a.obj: tofile_a.cpp      \

              tofile.cpp        \

              precompa.h        \

              precomp.h         \

              defo2v.h          \

              resource.h        \

              util.h            \

              idisp.h           \

              tofile.h

    $(cc) $(cvarsdll) $(cflags) $(cdebug) $(OLEFLAGS) tofile_a.cpp

tofile.obj:   tofile.cpp        \

              precomp.h         \

              defo2v.h          \

              resource.h        \

              util.h            \

              idisp.h           \

              tofile.h

    $(cc) $(cvarsdll) $(cflags) $(cdebug) $(OLEFLAGS) tofile.cpp

util_a.obj: util_a.cpp  \

            util.cpp    \

            precompa.h  \

            precomp.h   \

            defo2v.h    \

            resource.h  \

            util.h

    $(cc) $(cvarsdll) $(cflags) $(cdebug) $(OLEFLAGS) util_a.cpp

util.obj:   util.cpp    \

            precomp.h   \

            defo2v.h    \

            resource.h  \

            util.h

    $(cc) $(cvarsdll) $(cflags) $(cdebug) $(OLEFLAGS) util.cpp

defo2v.res: defo2v.rc defo2v.h

    rc $(RCFLAGS) -r -fo$@ defo2v.rc

defo2v32.dll: $(OBJS) defo2v.res

    $(LINK) @<<

        $(LINKFLAGS)

        -dll

        -out:$@

        -def:defo2v32.def

        -noentry

        -MERGE:.CRT=.data

        -MERGE:_PAGE=PAGE

        -MERGE:_TEXT=.text

        -SECTION:INIT,d

        -OPT:REF

        -INCREMENTAL:NO

        -IGNORE:4037,4065

        -PDB:NONE

        -NODEFAULTLIB

        -subsystem:native

        $(OBJS)

        defo2v.res

        $(LIBS)

<<


DEFO2V.DEF  (DEFO2V Sample)

LIBRARY   DEFO2V

EXETYPE   WINDOWS

CODE      PRELOAD MOVEABLE DISCARDABLE

DATA      PRELOAD MOVEABLE SINGLE

HEAPSIZE  4096

SEGMENTS

            WEP_SEG    PRELOAD FIXED

EXPORTS

            WEP PRIVATE

            fnEnumReallyEx          @5

            fnIDispDlg              @10

            fnIDataObjectDlg        @11

            DisplayIDataObject      @100

            DisplayIDispatch        @101

            DisplayITypeLib         @102

            DisplayITypeInfo        @103


DEFO2V.H  (DEFO2V Sample)

// defo2v.h

//

// Header file for OLE 2.0 Object Viewer auxillary DLL (DEFO2V.O2V).

//

// Copyright (c) 1993 Microsoft Corporation, All Rights Reserved.

//

// Charlie Kindel, Program Manager

// Microsoft Vertical Developer Relations

// August 6, 1993

//

// InterNet   :  ckindel@microsoft.com

// CompuServe :  >INTERNET:ckindel@microsoft.com

//

// Revisions:

//  August 6, 1993  cek     First implementation.

//  August 7, 1993  cek     Rewrote without using MFC 2.0.

//

// An O2V module is a DLL that exports the following function

// at:

//

//      HRESULT WINAPI DisplayInterface

//      (

//          HWND        hwndParent, // Ole2View's main frame window handle

//          LPUNKNOWN   lpunk,      // Pointer to interface

//          LPIID       lpiid,      // Pointer to IDD for this interface

//          LPSTR       lpszName    // Name of this interface (i.e. IUnknown)

//      ) ;

//

// Ole2View finds O2V modules by lookin in the [Interface Viewers] section in the

// OLE2VIEW.INI file:

//

//  [Interface Viewers]

//  <iid>=filename.o2v,<fn name>

//

// Examples:

//

//  [Interface Viewers]

//  {0000011B-0000-0000-C000-000000000046}=contain.o2v,DisplayIOleContainer

//

// By default, the following entries are assumed (entires are not actually

// in the INI file):

//

//  [Interface Viewers]

//  {0000010E-0000-0000-C000-000000000046}=defo2v.o2v,DisplayIDataObject

//  {00020400-0000-0000-C000-000000000046}=defo2v.o2v,DisplayIDispatch

//

// These 'default' implementations can be overriden by placing entries in

// the ini file.

//

#ifndef _DEFO2V_H_

#define _DEFO2V_H_

#if WIN32!=300

//#include <oleguid.h>

//#include <coguid.h>

#endif

//#include <dispatch.h>

#include "resource.h"

#include "util.h"

#ifndef WIN32

extern HINSTANCE g_hInst ;

#else

#define g_hInst GetModuleHandle(_T("DEFO2V32.DLL"))

#endif

// Ownerdraw listbox stuff

#define I_NORMAL        0x0000

#define I_LABEL         0x0001

#define I_COLUMNHEAD    0x0002

#define I_COLUMNENTRY   0x0003

typedef struct FAR tagITEMDATA

{

    UINT            nLevel ;

    UINT            uiType ;

    int             cColumns ;

    LPCOLUMNSTRUCT  rgCol ;

    LPVOID          lpData ;

} ITEMDATA, *PITEMDATA, FAR*LPITEMDATA ;

#endif // _DEFO2V_H_


DEFO2V.RC  (DEFO2V Sample)

//

// DEFO2V.RC2 - resources App Studio does not edit directly

//

#ifdef APSTUDIO_INVOKED

    #error this file is not editable by App Studio

#endif //APSTUDIO_INVOKED

/////////////////////////////////////////////////////////////////////////////

// Version stamp for this .EXE

#ifndef WIN32

#include "ver.h"

#else

#include "winver.h"

#endif

VS_VERSION_INFO     VERSIONINFO

  FILEVERSION       1,20,20,0

  PRODUCTVERSION    1,20,20,0

  FILEFLAGSMASK     VS_FFI_FILEFLAGSMASK

#ifdef _DEBUG

  FILEFLAGS         VS_FF_DEBUG|VS_FF_PRIVATEBUILD|VS_FF_PRERELEASE

#else

  FILEFLAGS         0 // final version

#endif

  FILEOS            VOS_DOS_WINDOWS16

  FILETYPE          VFT_DLL

  FILESUBTYPE       0   // not used

BEGIN

    BLOCK "StringFileInfo"

    BEGIN

        BLOCK "040904E4" // Lang=US English, CharSet=Windows Multilingual

        BEGIN

            VALUE "CompanyName",     "Microsoft Corporation\0"

            VALUE "FileDescription", "Default Ole2View iface Viewers\0"

            VALUE "FileVersion",     "1.20.000\0"

            VALUE "InternalName",    "DEFO2V.DLL\0"

            VALUE "LegalCopyright",  "Copyright \251 1993 Microsoft Corp. All Rights Reserved.\0"

            VALUE "LegalTrademarks", "By Charlie Kindel\0"

            VALUE "OriginalFilename","DEFO2V.DLL\0"

            VALUE "ProductName",     "OLE 2.0 Object Viewer\0"

            VALUE "ProductVersion",  "1.20\0"

        END

    END

    BLOCK "VarFileInfo"

    BEGIN

        VALUE "Translation", 0x409, 1252

            // English language (0x409) and the Windows ANSI codepage (1252)

    END

END

/////////////////////////////////////////////////////////////////////////////

// Add additional manually edited resources here...

/////////////////////////////////////////////////////////////////////////////


DEFO2V.CPP  (DEFO2V Sample)

// defo2v.cpp

//

// Implementation file for DEFO2V.O2V (LibMain, WEP).

//

// Copyright (c) 1993 Microsoft Corporation, All Rights Reserved.

//

// Charlie Kindel, Program Manager

// Microsoft Vertical Developer Relations

// August 7, 1993

//

// InterNet   :  ckindel@microsoft.com

// CompuServe :  >INTERNET:ckindel@microsoft.com

//

// Revisions:

//  August 6, 1993  cek     First implementation.

//  August 7, 1993  cek     Rewrote without using MFC 2.0.

//

#include "precomp.h"

#include <initguid.h>

#include "defo2v.h"

HINSTANCE   g_hInst = NULL ;

extern "C"

HANDLE FAR PASCAL LibMain(HINSTANCE hInst, WORD wDataSeg, WORD cbHeapSize, LPSTR lpCmdLine)

{

    if (0!=cbHeapSize)

        UnlockData(0);

    g_hInst=hInst;

    return hInst;

}

#pragma code_seg("WEP_SEG")

extern "C"

void FAR PASCAL WEP(int bSystemExit)

{

    return;

}


DEFO2V32.DEF  (DEFO2V Sample)

LIBRARY   DEFO2V32

EXPORTS

; Unicode versions

    fnEnumReallyEx       @100

    fnIDispDlg           @101

    fnIDataObjectDlg     @102

    DisplayIDataObject   @103

    DisplayIDispatch     @104

    DisplayITypeLib      @105

    DisplayITypeInfo     @106

; ANSI versions

    fnEnumReallyExA      @200

    fnIDispDlgA          @201

    fnIDataObjectDlgA    @202

    DisplayIDataObjectA  @203

    DisplayIDispatchA    @204

    DisplayITypeLibA     @205

    DisplayITypeInfoA    @206


IADVSINK.H  (DEFO2V Sample)

#ifndef _IADVSINK_H_

#define _IADVSINK_H_

#if defined(WIN32) && !defined(_UNICODE)

    #define CImpIAdviseSink CImpIAdviseSinkA

    #define CIDataObjectDlg CIDataObjectDlgA

#endif

class FAR CImpIAdviseSink : public IAdviseSink

{

protected:

    ULONG               m_cRef;      //Interface reference count.

    CIDataObjectDlg FAR* m_pIDOD ;       //Back pointer to the application

public:

    CImpIAdviseSink(CIDataObjectDlg FAR*);

    ~CImpIAdviseSink(void);

    STDMETHODIMP QueryInterface(REFIID, LPVOID FAR *);

    STDMETHODIMP_(ULONG) AddRef(void);

    STDMETHODIMP_(ULONG) Release(void);

    //We only implement OnDataChange for now.

    STDMETHODIMP_(void)  OnDataChange(LPFORMATETC, LPSTGMEDIUM);

    STDMETHODIMP_(void)  OnViewChange(DWORD, LONG);

    STDMETHODIMP_(void)  OnRename(LPMONIKER);

    STDMETHODIMP_(void)  OnSave(void);

    STDMETHODIMP_(void)  OnClose(void);

};

#endif //_IADVSINK_H_


IADVSINK.CPP  (DEFO2V Sample)

/*

 * IADVSINK.CPP

 *

 * Implementation of the IAdviseSink interface for the Data User, Chapter 6

 *

 * Copyright (c)1993 Microsoft Corporation, All Rights Reserved

 *

 * Kraig Brockschmidt, Software Design Engineer

 * Microsoft Systems Developer Relations

 *

 * Internet  :  kraigb@microsoft.com

 * Compuserve:  >INTERNET:kraigb@microsoft.com

 */

#include "precomp.h"

#include "defo2v.h"

#include "idataobj.h"

#include "iadvsink.h"

#if defined(WIN32) && !defined(_UNICODE)

    #pragma message("Building ANSI version of " __FILE__)

#endif

/*

 * CImpIAdviseSink::CImpIAdviseSink

 * CImpIAdviseSink::~CImpIAdviseSink

 *

 * Parameters (Constructor):

 *  pAV             LPAPPVARS to the application

 *

 */

CImpIAdviseSink::CImpIAdviseSink( CIDataObjectDlg FAR* lpIDOD )

    {

    m_cRef=0;

    m_pIDOD=lpIDOD;

    return;

    }

CImpIAdviseSink::~CImpIAdviseSink(void)

    {

    m_pIDOD->m_pSink = NULL; // make sure the container knows I've been deleted. SteveBl

    return;

    }

/*

 * CImpIAdviseSink::QueryInterface

 * CImpIAdviseSink::AddRef

 * CImpIAdviseSink::Release

 *

 * Purpose:

 *  IUnknown members for CImpIAdviseSink object.

 */

STDMETHODIMP CImpIAdviseSink::QueryInterface(REFIID riid, LPVOID FAR *ppv)

    {

    *ppv=NULL;

    //Any interface on this object is the object pointer.

    if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IAdviseSink))

        *ppv=(LPVOID)this;

    /*

     * If we actually assign an interface to ppv we need to AddRef it

     * since we're returning a new pointer.

     */

    if (NULL!=*ppv)

        {

        ((LPUNKNOWN)*ppv)->AddRef();

        return NOERROR;

        }

    return ResultFromScode(E_NOINTERFACE);

    }

STDMETHODIMP_(ULONG) CImpIAdviseSink::AddRef(void)

    {

    return ++m_cRef;

    }

STDMETHODIMP_(ULONG) CImpIAdviseSink::Release(void)

    {

    ULONG   cRefT;

    cRefT=--m_cRef;

    if (0==cRefT)

        delete this;

    return cRefT;

    }

/*

 * IAdviseSink::OnDataChange

 *

 * Purpose:

 *  Notifes the advise sink that data changed in a data object.  On

 *  this message you may request a new data rendering and update your

 *  displays as necessary.  Any data sent to this function is owned

 *  by the caller, not by this advise sink!

 *

 *  All Advise Sink methods should be considered asynchronous and therefore

 *  we should attempt no synchronous calls from within them to an EXE

 *  object.  If we do, we'll get RPC_E_CALLREJECTED as shown below.

 *

 * Parameters:

 *  pFE             LPFORMATETC describing format that changed

 *  pSTM            LPSTGMEDIUM providing the medium in which the data

 *                  is provided.

 *

 * Return Value:

 *  None

 */

STDMETHODIMP_(void) CImpIAdviseSink::OnDataChange(LPFORMATETC pFE, LPSTGMEDIUM pSTM)

{

    BOOL        fUsable=TRUE;

    UINT        cf;

    //See if we're interested

    cf=pFE->cfFormat;

    if (!(DVASPECT_CONTENT & pFE->dwAspect))

        return;

/*

    //Check media types

    switch (cf)

    {

    #ifdef UNICODE

        case CF_UNICODETEXT:

    #else

        case CF_TEXT:

    #endif

            fUsable=(BOOL)(TYMED_HGLOBAL & pFE->tymed);

        break;

        case CF_BITMAP:

            fUsable=(BOOL)(TYMED_GDI & pFE->tymed);

        break;

        case CF_METAFILEPICT:

            fUsable=(BOOL)(TYMED_MFPICT & pFE->tymed);

        break;

        default:

        break;

    }

    if (!fUsable)

        return;

*/

    if (NULL==m_pIDOD->m_lpDO)

        return;

    // If we are doing a 'warm link' then the data does not come with the

    // OnDataChange.   Post a message back to ourselves so that we can

    // call GetData when it's convienient

    //

    if (m_pIDOD->m_advf & ADVF_NODATA)

    {

        if (m_pIDOD->m_fDoOnGetDataPosted == FALSE)

        {

            m_pIDOD->m_fDoOnGetDataPosted = TRUE ;

            PostMessage( m_pIDOD->m_hDlg, WM_COMMAND,  IDC_DOGETDATA, 0L ) ;

        }

        return ;

    }

    // for Hot links the data comes with the OnDataChange

    m_pIDOD->GotData( pFE, pSTM ) ;

    return ;

}

/*

 * IAdviseSink::OnViewChange

 *

 * Purpose:

 *  Notifes the advise sink that presentation data changed in the data

 *  object to which we're connected providing the right time to update

 *  displays using such presentations.

 *

 * Parameters:

 *  dwAspect        DWORD indicating which aspect has changed.

 *  lindex          LONG indicating the piece that changed.

 *

 * Return Value:

 *  None

 */

STDMETHODIMP_(void) CImpIAdviseSink::OnViewChange(DWORD dwAspect, LONG lindex)

    {

    return;

    }

/*

 * IAdviseSink::OnRename

 *

 * Purpose:

 *  Informs the advise sink that an IOleObject has been renamed, primarily

 *  when its linked.

 *

 * Parameters:

 *  pmk             LPMONIKER providing the new name of the object

 *

 * Return Value:

 *  None

 */

STDMETHODIMP_(void) CImpIAdviseSink::OnRename(LPMONIKER pmk)

    {

    return;

    }

/*

 * IAdviseSink::OnSave

 *

 * Purpose:

 *  Informs the advise sink that the OLE object has been saved

 *  persistently.  The primary purpose of this is for containers that

 *  want to make optimizations for objects that are not in a saved

 *  state, so on this you have to disable such optimizations.

 *

 * Parameters:

 *  None

 *

 * Return Value:

 *  None

 */

STDMETHODIMP_(void) CImpIAdviseSink::OnSave(void)

    {

    return;

    }

/*

 * IAdviseSink::OnClose

 *

 * Purpose:

 *  Informs the advise sink that the OLE object has closed and is

 *  no longer bound in any way.  On this you typically change state

 *  variables and redraw shading, etc.

 *

 * Parameters:

 *  None

 *

 * Return Value:

 *  None

 */

STDMETHODIMP_(void) CImpIAdviseSink::OnClose(void)

    {

    return;

    }


IADVSI_A.CPP  (DEFO2V Sample)

// iadvsi_a.cpp

//

// Creates ANSI versions of all modules.  Any exported function get's "A"

// appended.

//

//

#ifdef UNICODE

#undef UNICODE

#endif

#ifdef _UNICODE

#undef _UNICODE

#endif

#include "precompa.h"

#include "iadvsink.cpp"


IDATAOBJ.H  (DEFO2V Sample)

// idataobj.h

//

// Header file for the IDataObject interface viewer.

//

// Copyright (c) 1993 Microsoft Corporation, All Rights Reserved.

//

// Charlie Kindel, Program Manager

// Microsoft Vertical Developer Relations

// August 6, 1993

//

// InterNet   :  ckindel@microsoft.com

// CompuServe :  >INTERNET:ckindel@microsoft.com

//

// Revisions:

//  August 6, 1993  cek     First implementation.

//

#ifndef _IDATAOBJ_H_

#define _IDATAOBJ_H_

#if defined(WIN32) && !defined(_UNICODE)

    #define CImpIAdviseSink CImpIAdviseSinkA

    #define fnIDataObjectDlg fnIDataObjectDlgA

    #define fnEditSubclass fnEditSubclassA

    #define CIDataObjectDlg CIDataObjectDlgA

    #define DisplayIDataObject DisplayIDataObjectA

#endif

STDAPI DisplayIDataObject( HWND hwndParent, LPDATAOBJECT lpDO, LPIID lpiid, LPTSTR lpszName ) ;

class CImpIAdviseSink ;

#define CCHOUTPUTMAX        8192

#define CLINESMAX           500

#define WM_OUTPUTBUFFERHASDATA      (WM_USER+1000)

/////////////////////////////////////////////////////////////////////////////

// CIDataObjectDlg dialog

//

extern "C"

BOOL CALLBACK fnIDataObjectDlg( HWND hDlg, UINT uiMsg, WPARAM wParam, LPARAM lParam ) ;

class FAR CIDataObjectDlg

{

    friend BOOL CALLBACK fnIDataObjectDlg( HWND hDlg, UINT uiMsg, WPARAM wParam, LPARAM lParam ) ;

    friend class CImpIAdviseSink ;

public:

    CIDataObjectDlg( HWND hwnd, LPDATAOBJECT lpDO, LPIID lpiid, LPTSTR lpszName ) ;

    ~CIDataObjectDlg() ;

    int DoModal( void ) ;

    LPDATAOBJECT    m_lpDO ;

    LPIID           m_lpiid ;

    LPTSTR          m_lpszName ;

    FORMATETC       m_fetc ;

    DWORD           m_advf ;

    BOOL            m_fDoOnGetDataPosted ;

    HWND        m_hWndParent ;

    HWND        m_hDlg ;

    HWND        m_btnDoGetData ;

    HWND        m_btnSetupAdvise ;

    HWND        m_lbGetData ;

    HWND        m_edtAdvise ;

    TCHAR       m_szOutput[CCHOUTPUTMAX] ;

    METAFILEPICT m_MetaFile ;

    UINT        m_cchOutput ;

    UINT        m_cLinesOutput ;

    HWND        m_chkUpdateDisplay ;

    BOOL        m_fUpdateDisplay ;

    HWND        m_chkPrimeFirst ;

    HWND        m_lbFmtEtc ;

    HWND        m_chkDump ;

    DWORD       m_dwTime ;

    DWORD       m_cOnDataChanges ;

    CImpIAdviseSink FAR* m_pSink ;

    DWORD               m_dwConn ;

// Implementation

protected:

    BOOL DoIDataObject( UINT nLevel, LPDATAOBJECT pI ) ;

    BOOL DoIEnumFormatEtc( UINT nLevel, LPENUMFORMATETC pI ) ;

    int AddItem( UINT nLevel, LPTSTR sz, LPVOID lpData, UINT uiType, int cColumns, LPCOLUMNSTRUCT  rgCol ) ;

    int AddItem( UINT nLevel, LPTSTR sz, LPVOID lpData, UINT uiType ) ;

    int AddItem( UINT nLevel, LPTSTR sz, LPVOID lpData ) ;

    BOOL OnInitDialog();

    void OnDoGetData() ;

    HRESULT GotData( LPFORMATETC lpfetc, LPSTGMEDIUM lpstm ) ;

    void OnSetupAdvise() ;

    void OnKillAdvise() ;

    void OnSize(UINT nType, int cx, int cy);

    void OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct);

    void OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct);

    void OnDblClkFormatEtc();

    void OnSelChangeFormatEtc();

    void OnDestroy();

    BOOL  WriteToOutput( LPTSTR lpsz ) ;

    void OnOutputBufferHasData() ;

};

#endif // _IDATAOBJ_H_


IDATAOBJ.CPP  (DEFO2V Sample)

// idataobj.cpp

//

// Implementation file for the IDataObject interface viewer.

//

// Copyright (c) 1993 Microsoft Corporation, All Rights Reserved.

//

// Revisions:

//  August 7, 1993  cek     First implementation.

//  February 19, 1994 cek   Removed XRT stuff.  Fixed minor bugs.

//  April 9, 1994 cek       Pulled from XRTView and genericized again.

//

#include "precomp.h"

#include "defo2v.h"

#include "idataobj.h"

#include "iadvsink.h"

#if defined(WIN32) && !defined(_UNICODE)

    #pragma message("Building ANSI version of " __FILE__)

#endif

static HFONT       g_hFont ;

static HFONT       g_hFontBold ;

static UINT        g_cyFont ;

static WNDPROC     g_pfnEdit = NULL ;

extern "C"

LRESULT EXPORT CALLBACK fnEditSubclass( HWND hwnd, UINT uiMsg, WPARAM wP, LPARAM lP ) ;

LPCTSTR MyGetClipboardFormatName( UINT cf ) ;

// DisplayIDataObject

//

// This is the "DisplayInterface" or "Interface Viewer" function for the

// IDataObject interface.   This implementation simply pops up a dialog

// box that has an ownerdraw listbox in it.

//

// It is expected that this function will be called from the Ole2View

// tool.   See the Ole2View helpfile in the OLE 2.01 and MSVC++ 1.5 kits

// for details on Ole2View interface viewers.

//

// The listbox is filled with the FORMATETCs that are enumerated through

// the IEnumFORMATETC interface that is retrieved from IDataObject::EnumFormatEtc

//

extern "C"

HRESULT CALLBACK DisplayIDataObject( HWND hwndParent, LPDATAOBJECT lpDO, LPIID lpiid, LPTSTR lpszName )

{

    HRESULT hr = NULL ;

    CIDataObjectDlg FAR* pdlg ;

    pdlg = new FAR CIDataObjectDlg( hwndParent, lpDO, lpiid, lpszName ) ;

    if (pdlg)

    {

        pdlg->DoModal() ;

        delete pdlg ;

    }

    return hr ;

}

/////////////////////////////////////////////////////////////////////////////

// CIDataObjectDlg dialog

//

CIDataObjectDlg::CIDataObjectDlg( HWND hwnd, LPDATAOBJECT lpDO, LPIID lpiid, LPTSTR lpszName )

{

    m_lbFmtEtc = NULL ;

    m_edtAdvise = NULL ;

    m_MetaFile.hMF = NULL ;

    m_hWndParent = hwnd ;

    m_lpDO = lpDO ;

    m_lpiid = lpiid ;

    m_lpszName = lpszName ;

    m_pSink = NULL ;

    m_dwConn = 0 ;

    m_advf = ADVF_PRIMEFIRST ;

#ifdef _UNICODE

    m_fetc.cfFormat = CF_UNICODETEXT ;

#else

    m_fetc.cfFormat = CF_TEXT ;

#endif

    m_fetc.dwAspect = DVASPECT_CONTENT ;

    m_fetc.ptd = NULL ;

    m_fetc.tymed = TYMED_HGLOBAL ;

    m_fetc.lindex = - 1 ;

    m_fDoOnGetDataPosted = FALSE ;

    m_cchOutput = 0 ;

    m_cLinesOutput = 0 ;

}

CIDataObjectDlg::~CIDataObjectDlg()

{

    if (m_MetaFile.hMF != NULL)

        DeleteMetaFile( m_MetaFile.hMF ) ;

}

int CIDataObjectDlg::DoModal( void )

{

    return DialogBoxParam( g_hInst, MAKEINTRESOURCE( IDD_IDATAOBJDLG ), m_hWndParent, (DLGPROC)fnIDataObjectDlg, (LONG)this ) ;

}

extern "C"

BOOL EXPORT CALLBACK fnIDataObjectDlg( HWND hDlg, UINT uiMsg, WPARAM wParam, LPARAM lParam )

{

    static BOOL fInErrSpace = FALSE ;

    CIDataObjectDlg FAR* pIDOD =(CIDataObjectDlg FAR*)GetWindowLong( hDlg, DWL_USER ) ;

    switch (uiMsg)

    {

        case WM_INITDIALOG:

            pIDOD=(CIDataObjectDlg FAR*)lParam ;

            if (pIDOD==NULL)

            {

                EndDialog( hDlg, 0 ) ;

                return TRUE ;

            }

            SetWindowLong( hDlg, DWL_USER, (LONG)pIDOD ) ;

            pIDOD->m_hDlg = hDlg ;

            return pIDOD->OnInitDialog() ;

        break ;

        case WM_DESTROY:

            if (pIDOD)

                pIDOD->OnDestroy() ;

        break ;

        case WM_SIZE:

            if (pIDOD)

                pIDOD->OnSize( (UINT)wParam, LOWORD( lParam ), HIWORD( lParam ) ) ;

        break ;

        case WM_COMMAND:

        {

            #ifdef WIN32

            WORD wNotifyCode = HIWORD(wParam);

            WORD wID = LOWORD(wParam);

            HWND hwndCtl = (HWND) lParam;

            #else

            WORD wNotifyCode = HIWORD(lParam) ;

            WORD wID = wParam ;

            HWND hwndCtl = (HWND)LOWORD(lParam) ;

            #endif

            switch (wID)

            {

                case IDCANCEL:

                    EndDialog( hDlg, IDCANCEL ) ;

                break ;

                case IDC_DOGETDATA:

                    pIDOD->OnDoGetData() ;

                break ;

                case IDC_SETUPADVISE:

                    if (pIDOD->m_dwConn != 0)

                        pIDOD->OnKillAdvise() ;

                    else

                        pIDOD->OnSetupAdvise() ;

                break ;

                case IDC_CLEAROUTPUT:

                    if (pIDOD)

                    {

                        pIDOD->m_cchOutput = 0 ;

                        pIDOD->m_cLinesOutput = 0 ;

                        if (pIDOD->m_MetaFile.hMF != NULL)

                        {

                            DeleteMetaFile( pIDOD->m_MetaFile.hMF ) ;

                            pIDOD->m_MetaFile.hMF = NULL ;

                        }

                        SetWindowText( pIDOD->m_edtAdvise, _T("") ) ;

                        InvalidateRect( pIDOD->m_edtAdvise, NULL, TRUE ) ;

                        UpdateWindow( pIDOD->m_edtAdvise ) ;

                    }

                break ;

                case IDC_FORMATETC:

                    if (wNotifyCode == LBN_SELCHANGE)

                        pIDOD->OnSelChangeFormatEtc() ;

                break ;

                case IDC_UPDATEDISPLAY:

                    pIDOD->m_fUpdateDisplay = Button_GetCheck( pIDOD->m_chkUpdateDisplay ) ;

                break ;

                case IDC_PRIMEFIRST:

                    if (Button_GetCheck( pIDOD->m_chkPrimeFirst ))

                        pIDOD->m_advf = ADVF_PRIMEFIRST ;

                    else

                        pIDOD->m_advf = ADVF_NODATA ;

                break ;

                case IDC_ADVISEDATA:

                    if (wNotifyCode == EN_ERRSPACE)

                    {

                        #ifdef _DEBUG

                        OutputDebugString(_T("Output Edit Control reports EN_ERRSPACE\r\n")) ;

                        #endif

                    }

                break ;

            }

        }

        break ;

        case WM_DRAWITEM:

            if (pIDOD)

                pIDOD->OnDrawItem( wParam, (LPDRAWITEMSTRUCT)lParam ) ;

        break ;

        case WM_MEASUREITEM:

            if (pIDOD)

                pIDOD->OnMeasureItem( wParam, (LPMEASUREITEMSTRUCT)lParam ) ;

        break ;

        case WM_OUTPUTBUFFERHASDATA:

            if (pIDOD)

                pIDOD->OnOutputBufferHasData() ;

        break ;

        default:

           return FALSE ;

    }

    return TRUE ;

}

/////////////////////////////////////////////////////////////////////////////

// CIDataObjectDlg message handlers

BOOL CIDataObjectDlg::OnInitDialog()

{

    m_btnDoGetData = GetDlgItem( m_hDlg, IDC_DOGETDATA ) ;

    m_btnSetupAdvise = GetDlgItem( m_hDlg, IDC_SETUPADVISE ) ;

    m_lbGetData = GetDlgItem( m_hDlg, IDC_GETDATA ) ;

    m_lbFmtEtc = GetDlgItem( m_hDlg, IDC_FORMATETC ) ;

    m_edtAdvise = GetDlgItem( m_hDlg, IDC_ADVISEDATA ) ;

    // Sublcass the edit so we can override it's WM_PAINT and

    // draw a metafile if we want to...

    if (g_pfnEdit == NULL)

        g_pfnEdit = SubclassWindow( m_edtAdvise, fnEditSubclass) ;

    m_chkUpdateDisplay = GetDlgItem( m_hDlg, IDC_UPDATEDISPLAY );

    m_fUpdateDisplay = TRUE ;

    Button_SetCheck( m_chkUpdateDisplay, m_fUpdateDisplay ) ;

    m_chkPrimeFirst = GetDlgItem( m_hDlg, IDC_PRIMEFIRST );

    Button_SetCheck( m_chkPrimeFirst, m_advf == ADVF_PRIMEFIRST ) ;

    //m_chkDump = GetDlgItem( m_hDlg, IDC_DUMPTOFILE ) ;

    //EnableWindow( m_chkDump, FALSE ) ;

    TEXTMETRIC  tm ;

    HDC hdc = GetDC(NULL);

    g_hFont = ReallyCreateFont( hdc, _T( "MS Sans Serif" ), _T( "Regular" ), 8, 0 ) ;

    g_hFontBold = ReallyCreateFont( hdc, _T( "MS Sans Serif" ), _T( "Bold" ), 8, 0 ) ;

    g_hFont = (HFONT)SelectObject( hdc, g_hFont ) ;

    GetTextMetrics( hdc, &tm ) ;

    g_hFont = (HFONT)SelectObject( hdc, g_hFont ) ;

    ReleaseDC( NULL, hdc ) ;

    g_cyFont = tm.tmHeight + tm.tmExternalLeading ;

    SetWindowFont( m_lbFmtEtc, g_hFont, TRUE ) ;

    SetWindowFont( m_lbGetData, g_hFont, TRUE ) ;

    SetWindowFont( m_edtAdvise, g_hFont, TRUE ) ;

    if (IsEqualCLSID( IID_IEnumFORMATETC, *m_lpiid ))

        DoIEnumFormatEtc( 0, (LPENUMFORMATETC)m_lpDO) ;

    else if (IsEqualCLSID( IID_IDataObject, *m_lpiid ))

    {

        DoIDataObject( 0, (LPDATAOBJECT)m_lpDO ) ;

    }

    else

    {

        MessageBox( m_hDlg, _T( "Wrong IID" ), _T( "Error" ), MB_OK ) ;

    }

    DlgCenter( m_hDlg, m_hWndParent, FALSE ) ;

    RECT rc ;

    GetWindowRect( m_hDlg, &rc ) ;

    SetWindowPos( m_hDlg, NULL, rc.left, rc.top, rc.right - rc.left + 1,

                  rc.bottom - rc.top +1, SWP_NOMOVE|SWP_NOZORDER | SWP_NOACTIVATE ) ;

    SetWindowText( m_hDlg, m_lpszName ) ;

    return TRUE;  // return TRUE  unless you set the focus to a control

}

void CIDataObjectDlg::OnDestroy()

{

    OnKillAdvise() ;

    if (g_pfnEdit != NULL && m_edtAdvise && IsWindow(m_edtAdvise))

    {

        SubclassWindow(m_edtAdvise, g_pfnEdit) ;

        g_pfnEdit = NULL ;

    }

    int c = ListBox_GetCount( m_lbFmtEtc ) ;

    for (int i = 0 ; i < c ; i++)

    {

        LPITEMDATA lpID = (LPITEMDATA)ListBox_GetItemData( m_lbFmtEtc, i ) ;

        if (lpID)

        {

            if (lpID->uiType == I_COLUMNHEAD)

                delete lpID->rgCol ;

            if (lpID->lpData != NULL)

                delete (LPFORMATETC)lpID->lpData ;

            delete lpID ;

        }

    }

    if (g_hFont)

        DeleteObject( g_hFont );

    if (g_hFontBold)

        DeleteObject (g_hFontBold) ;

}

void CIDataObjectDlg::OnSize(UINT nType, int cx, int cy)

{

    if (m_edtAdvise && !IsWindow( m_edtAdvise ) )

        return ;

    RECT    rc ;

    RECT    rcWnd ;

    GetClientRect( m_hDlg, &rcWnd ) ;

    GetWindowRect( m_edtAdvise, &rc ) ;

    MapWindowPoints( NULL, m_hDlg, (POINT FAR*)&rc, 2 ) ;

    SetWindowPos( m_edtAdvise, NULL, -1, rc.top, cx+2, cy - rc.top + 1,

                SWP_NOZORDER | SWP_NOACTIVATE ) ;

}

void CIDataObjectDlg::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDIS )

{

    if (lpDIS->itemID == LB_ERR)

        return ;

    LPITEMDATA      lpID ;

    COLORREF        rgbBack ;

    RECT            rcFocus ;

    BOOL            fSelected ;

    int             x, y, cy ;

    TCHAR           szItem[128] ;

    lpID = (LPITEMDATA)lpDIS->itemData ;

    rcFocus = lpDIS->rcItem ;

    ListBox_GetText( m_lbFmtEtc, lpDIS->itemID, szItem ) ;

    if (fSelected = (lpDIS->itemState & ODS_SELECTED) ? TRUE : FALSE)

    {

        SetTextColor( lpDIS->hDC, GetSysColor( COLOR_HIGHLIGHTTEXT ) ) ;

        SetBkColor( lpDIS->hDC, rgbBack = GetSysColor( COLOR_HIGHLIGHT ) ) ;

    }

    else

    {

        SetTextColor( lpDIS->hDC, GetSysColor( COLOR_WINDOWTEXT ) ) ;

        SetBkColor( lpDIS->hDC, rgbBack = GetSysColor( COLOR_WINDOW ) ) ;

    }

    // if we are loosing focus, remove the focus rect before

    // drawing.

    //

    if ((lpDIS->itemAction) & (ODA_FOCUS))

        if (!((lpDIS->itemState) & (ODS_FOCUS)))

            DrawFocusRect( lpDIS->hDC, &rcFocus ) ;

    y = lpDIS->rcItem.top ;

    x = lpDIS->rcItem.left ;

    int cxChar = GetTextMetricsCorrectly( lpDIS->hDC, NULL ) ;

    if (lpID && (lpID->uiType == I_COLUMNHEAD || lpID->uiType == I_LABEL))

        g_hFontBold = (HFONT)SelectObject( lpDIS->hDC, g_hFontBold ) ;

    cy = (rcFocus.bottom - rcFocus.top - g_cyFont) / 2 ;

    ExtTextOut( lpDIS->hDC, x+2, y + cy, ETO_OPAQUE, &lpDIS->rcItem, NULL, 0, NULL ) ;

    if (lpID)

        ColumnTextOut( lpDIS->hDC, x + 2 + ((cxChar*3) * lpID->nLevel), y + cy, szItem, lpID->cColumns, lpID->rgCol ) ;

    if (lpID && lpID->uiType == I_COLUMNHEAD )

    {

        COLORREF    rgb ;

        RECT        rc = rcFocus ;

        rgb = SetBkColor( lpDIS->hDC, GetTextColor( lpDIS->hDC ) ) ;

        rc.top = rc.bottom - 1 ;

        rc.left = x + 2 + ((cxChar*3) * lpID->nLevel) ;

        ExtTextOut( lpDIS->hDC, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL ) ;

        SetBkColor( lpDIS->hDC, rgb ) ;

    }

    if (lpID && (lpID->uiType == I_COLUMNHEAD || lpID->uiType == I_LABEL))

        g_hFontBold = (HFONT)SelectObject( lpDIS->hDC, g_hFontBold ) ;

    // if we are gaining focus draw the focus rect after drawing

    // the text.

    if ((lpDIS->itemAction) & (ODA_FOCUS))

        if ((lpDIS->itemState) & (ODS_FOCUS))

             DrawFocusRect( lpDIS->hDC, &rcFocus ) ;

    if (fSelected)

    {

        SetTextColor( lpDIS->hDC, GetSysColor( COLOR_WINDOWTEXT ) ) ;

        SetBkColor( lpDIS->hDC, GetSysColor( COLOR_WINDOW ) ) ;

    }

}

void CIDataObjectDlg::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct)

{

    lpMeasureItemStruct->itemHeight = g_cyFont ;

}

void CIDataObjectDlg::OnDblClkFormatEtc()

{

}

void CIDataObjectDlg::OnSelChangeFormatEtc()

{

    if (m_MetaFile.hMF != NULL)

    {

        DeleteMetaFile( m_MetaFile.hMF ) ;

        m_MetaFile.hMF = NULL ;

    }

    InvalidateRect( m_edtAdvise, NULL, TRUE ) ;

    SetWindowText( m_edtAdvise, _T("") ) ;

    int i = ListBox_GetCurSel( m_lbFmtEtc ) ;

    if (i != LB_ERR)

    {

        LPITEMDATA lpid = (LPITEMDATA)ListBox_GetItemData( m_lbFmtEtc, i ) ;

        if (lpid && lpid->lpData)

        {

            m_fetc = *(LPFORMATETC)lpid->lpData ;

            return ;

        }

    }

#ifdef UNICODE

    m_fetc.cfFormat = CF_UNICODETEXT ;

#else

    m_fetc.cfFormat = CF_TEXT ;

#endif

    m_fetc.dwAspect = DVASPECT_CONTENT ;

    m_fetc.ptd = NULL ;

    m_fetc.tymed = TYMED_HGLOBAL ;

    m_fetc.lindex = - 1 ;

}

void CIDataObjectDlg::OnDoGetData()

{

    HRESULT     hr ;

    STGMEDIUM   stm ;

    TCHAR       szBuf[256] ;

    if (m_lpDO == NULL)

    {

        ListBox_AddString( m_lbGetData, _T( "IDataObject viewer internal error: m_lpDO == NULL" ) ) ;

        return ;

    }

    wsprintf( szBuf, _T( "Calling GetData for %s" ), (LPCTSTR)MyGetClipboardFormatName( m_fetc.cfFormat ) ) ;

    ListBox_AddString( m_lbGetData, szBuf ) ;

    hr = m_lpDO->QueryGetData( &m_fetc ) ;

    if (FAILED( hr ))

    {

        wsprintf( szBuf, _T( "QueryGetData() failed:  %s" ),

                    (LPTSTR)HRtoString( hr ) ) ;

        ListBox_AddString( m_lbGetData, szBuf ) ;

        return ;

    }

    stm.tymed = m_fetc.tymed ;

    hr = m_lpDO->GetData( &m_fetc, &stm ) ;

    if (FAILED( hr ))

    {

        wsprintf( szBuf, _T( "GetData() failed:  %s" ),

                    (LPTSTR)HRtoString( hr ) ) ;

        ListBox_AddString( m_lbGetData, szBuf ) ;

        return ;

    }

    if (FAILED( hr = GotData( &m_fetc, &stm ) ))

    {

        wsprintf( szBuf, _T( "IDataDlg::GotData() failed:  %s" ),

                    (LPTSTR)HRtoString( hr ) ) ;

        ListBox_AddString( m_lbGetData, szBuf ) ;

        return ;

    }

    // If we're warm linked, then don't let the queue overfill.  Allow only one

    // message at a time.  This is similar to the way Excel handles it's DDE Links.

    //

    m_fDoOnGetDataPosted = FALSE ;

}

HRESULT CIDataObjectDlg::GotData( LPFORMATETC lpfetc, LPSTGMEDIUM lpstm )

{

    HRESULT hr = NOERROR ;

    BOOL    fHandled = FALSE ;

#ifdef WIN32

    if ((lpfetc->cfFormat == CF_TEXT  || lpfetc->cfFormat == CF_UNICODETEXT)

            && lpstm->tymed & TYMED_HGLOBAL)

#else

    if (lpfetc->cfFormat == CF_TEXT && lpstm->tymed & TYMED_HGLOBAL)

#endif

    {

        LPTSTR lpsz = (LPTSTR)GlobalLock( lpstm->hGlobal ) ;

        if (lpsz == NULL)

        {

            ListBox_AddString( m_lbGetData, _T( "hGlobal returned by GetData is NULL!" ) ) ;

            ReleaseStgMedium( lpstm );

            return ResultFromScode( E_FAIL ) ;

        }

        if (m_fUpdateDisplay == TRUE)

            WriteToOutput( lpsz ) ;

        GlobalUnlock( lpstm->hGlobal ) ;

        fHandled = TRUE ;

    }

    if (lpfetc->cfFormat == CF_METAFILEPICT && lpstm->tymed & TYMED_MFPICT)

    {

        LPMETAFILEPICT pMF = (LPMETAFILEPICT)GlobalLock(lpstm->hGlobal) ;

        if (pMF)

        {

            if (m_MetaFile.hMF)

            {

                DeleteMetaFile( m_MetaFile.hMF ) ;

                m_MetaFile.hMF = NULL ;

            }

            if (m_fUpdateDisplay)

            {

                m_MetaFile = *pMF ;

                m_MetaFile.hMF = CopyMetaFile( pMF->hMF, NULL ) ;

                InvalidateRect( m_edtAdvise, NULL, FALSE ) ;

            }

        }

        fHandled = TRUE ;

    }

    m_cOnDataChanges++ ;

    ReleaseStgMedium( lpstm );

    if (fHandled == FALSE)

    {

        ListBox_AddString( m_lbGetData, _T( "The IDataObject viewer does not know how to decode this FORMATETC" ) ) ;

    }

    return  hr;

}

void CIDataObjectDlg::OnSetupAdvise()

{

    TCHAR szBuf[128] ;

    OnKillAdvise() ;

    m_pSink = new CImpIAdviseSink( this ) ;

    if (m_pSink == NULL)

    {

        ListBox_AddString( m_lbGetData, _T( "CImpIAdviseSink constructor failed" ) ) ;

        return ;

    }

    SetWindowText( m_btnSetupAdvise, _T( "&Kill Advise" ) ) ;

    wsprintf( szBuf, _T( "Advise started with a cfFormat of %s" ),

                (LPCTSTR)MyGetClipboardFormatName( m_fetc.cfFormat ) ) ;

    ListBox_AddString( m_lbGetData, szBuf ) ;

    m_dwTime = GetTickCount() ;

    m_cOnDataChanges = 0 ;

    HRESULT hr = m_lpDO->DAdvise( &m_fetc, m_advf, m_pSink, &m_dwConn ) ;

    if (FAILED( hr ))

    {

        wsprintf( szBuf, _T( "DAdvise() failed:  %s" ), (LPTSTR)HRtoString( hr ) ) ;

        ListBox_AddString( m_lbGetData, szBuf ) ;

        SetWindowText( m_btnSetupAdvise, _T( "&DAdvise" ) ) ;

        return ;

    }

}

void CIDataObjectDlg::OnKillAdvise()

{

    if (m_dwConn != 0)

    {

        TCHAR szBuf[128] ;

        DWORD dwTime = max( 1000, GetTickCount() - m_dwTime ) ;    // avoid div by zero

        m_lpDO->DUnadvise( m_dwConn ) ;

        m_dwConn = 0 ;

        wsprintf( szBuf, _T( "  Advise Killed after %lu milliseconds, and %lu OnDataChanges;" ), dwTime, m_cOnDataChanges ) ;

        ListBox_AddString( m_lbGetData, szBuf ) ;

        wsprintf( szBuf, _T( "  That's %lu.%lu OnDataChange calls per second." ),

                        m_cOnDataChanges / (dwTime / 1000L),

                        m_cOnDataChanges % (dwTime / 1000L) ) ;

        ListBox_AddString( m_lbGetData, szBuf ) ;

    }

    if (m_pSink != NULL)

    {

        m_pSink->Release() ;

        m_pSink = NULL ;

    }

    SetWindowText( m_btnSetupAdvise, _T( "&DAdvise" ) ) ;

}

// DoIDataObject

//

// This is where we start doing IDataObject dirty work.

// This function calls pIDataObject->EnumFormatEtc twice, once

// each for DATADIR_GET and DATADIR_SET, to get a pIEnumFORMATETC.

//

// We then call DoIEnumFormatEtc() with this pointer to actually

// perform the enumaration.

//

BOOL CIDataObjectDlg::DoIDataObject( UINT nLevel, LPDATAOBJECT pIDataObject )

{

    LPENUMFORMATETC pEFE ;

    HRESULT     hr1 ;

    hr1 = pIDataObject->EnumFormatEtc( DATADIR_GET, &pEFE ) ;

    if (SUCCEEDED( hr1 ))

    {

        DoIEnumFormatEtc( nLevel, pEFE ) ;

        pEFE->Release() ;

    }

    else

        AddItem( nLevel, _T( "<<DATA_DIRGET failed>>" ), NULL, I_LABEL ) ;

    if (SUCCEEDED(hr1))

    {

        ListBox_SetCurSel( m_lbFmtEtc, 0 ) ;

        OnSelChangeFormatEtc() ;

    }

    return TRUE ;

}

// This member takes a pointer to an IEnumFORMATETC and enumerates

// the FORMATETC structures avaialbe, inserting them into our

// listbox.

//

BOOL CIDataObjectDlg::DoIEnumFormatEtc( UINT nLevel, LPENUMFORMATETC pIFormatEtc )

{

    LPCOLUMNSTRUCT  rgCol = new COLUMNSTRUCT[5] ;

    UINT    cxChar ;

    HDC     hdc  = GetDC( NULL) ;

    // We use the "ColumnTextOut" code in util.c to create nice

    // columns in our list box.

    //

    g_hFontBold = (HFONT)SelectObject( hdc, g_hFontBold ) ;

    cxChar = GetTextMetricsCorrectly( hdc, NULL ) ;

    rgCol[0].nLeft = 0 ;

    rgCol[0].nRight = cxChar * lstrlen( _T( "CF_METAFILEPICT_" ) ) ;

    rgCol[0].uiFlags = DT_LEFT ;

    rgCol[1].nLeft = rgCol[0].nRight + cxChar ;

    rgCol[1].nRight = rgCol[1].nLeft + cxChar * lstrlen( _T( "0000:0000_" ) ) ;

    rgCol[1].uiFlags = DT_LEFT ;

    rgCol[2].nLeft = rgCol[1].nRight + cxChar ;

    rgCol[2].nRight = rgCol[2].nLeft + cxChar * lstrlen( _T( "THUMBNAIL_" ) ) ;

    rgCol[2].uiFlags = DT_LEFT ;

    rgCol[3].nLeft = rgCol[2].nRight + cxChar ;

    rgCol[3].nRight = rgCol[3].nLeft + cxChar * lstrlen( _T( "0000:0000_" ) ) ;

    rgCol[3].uiFlags = DT_LEFT ;

    rgCol[4].nLeft = rgCol[3].nRight + cxChar ;

    rgCol[4].nRight = rgCol[4].nLeft + cxChar * lstrlen( _T( "_HGLOBAL_" ) ) ;

    rgCol[4].uiFlags = DT_LEFT ;

    g_hFontBold = (HFONT)SelectObject( hdc, g_hFontBold ) ;

    ReleaseDC( NULL, hdc ) ;

    AddItem( nLevel, _T( "cfFormat\tptd\tdwAspect\tlindex\ttymed" ), NULL, I_COLUMNHEAD, 5, rgCol ) ;

    LPFORMATETC     pfetc ;

    FORMATETC       fetc ;

    TCHAR           sz[512] ;

    ULONG           ulFE ; // number returned

    while (pIFormatEtc->Next( 1, &fetc, &ulFE ) == S_OK)

    {

        // now insert into list

        pfetc = new FORMATETC ;

        *pfetc = fetc ;

        lstrcpy( sz, MyGetClipboardFormatName( (UINT)fetc.cfFormat ) ) ;

        lstrcat( sz, _T("\t") ) ;

        TCHAR szTemp[32] ;

        wsprintf( szTemp, _T( "%04lX:%04lX\t" ), (DWORD)HIWORD( (DWORD)fetc.ptd ), (DWORD)LOWORD( (DWORD)fetc.ptd ) ) ;

        lstrcat( sz, szTemp ) ;

        switch( fetc.dwAspect )

        {

            case DVASPECT_CONTENT: lstrcat( sz, _T( "CONTENT\t" ) ) ; break ;

            case DVASPECT_THUMBNAIL: lstrcat( sz, _T( "THUMBNAIL\t" ) ) ; break ;

            case DVASPECT_ICON: lstrcat( sz, _T( "ICON\t" ) ) ; break ;

            case DVASPECT_DOCPRINT: lstrcat( sz, _T( "DOCPRINT\t" ) ) ; break ;

            default:

                wsprintf( szTemp, _T( "%08lX\t" ), (DWORD)fetc.dwAspect ) ;

                lstrcat( sz, szTemp ) ;

            break ;

        }

        wsprintf( szTemp, _T( "%04lX:%04lX\t" ), (DWORD)HIWORD( fetc.lindex ), (DWORD)LOWORD( fetc.lindex ) ) ;

        lstrcat( sz, szTemp ) ;

        switch( fetc.tymed )

        {

            case TYMED_HGLOBAL: lstrcat( sz, _T( "HGLOBAL\t" ) ) ; break ;

            case TYMED_FILE: lstrcat( sz, _T( "FILE\t" ) ) ; break ;

            case TYMED_ISTREAM: lstrcat( sz, _T( "ISTREAM\t" ) ) ; break ;

            case TYMED_ISTORAGE: lstrcat( sz, _T( "ISTORAGE\t" ) ) ; break ;

            case TYMED_GDI: lstrcat( sz, _T( "GDI\t" ) ) ; break ;

            case TYMED_MFPICT: lstrcat( sz, _T( "MFPICT\t" ) ) ; break ;

            case TYMED_NULL: lstrcat( sz, _T( "NULL\t" ) ) ; break ;

            default:

                wsprintf( szTemp, _T( "%08lX\t" ), (DWORD)fetc.tymed ) ;

                lstrcat( sz, szTemp ) ;

            break ;

        }

        AddItem( nLevel, sz,

                 pfetc, I_COLUMNENTRY, 5, rgCol ) ;

    }

    return TRUE ;

}

LPCTSTR MyGetClipboardFormatName( UINT cf )

{

    static TCHAR sz[256] ;

    switch( cf )

    {

#ifdef WIN32

        case CF_UNICODETEXT: lstrcpy( sz, _T( "CF_UNICODETEXT" ) ) ; break ;

        case CF_ENHMETAFILE: lstrcpy( sz, _T( "CF_ENHMETAFILE" ) ) ; break ;

#endif

        case CF_TEXT: lstrcpy( sz, _T( "CF_TEXT" ) ) ; break ;

        case CF_BITMAP: lstrcpy( sz, _T( "CF_BITMAP" ) ) ; break ;

        case CF_METAFILEPICT: lstrcpy( sz, _T( "CF_METAFILEPICT" ) ) ; break ;

        case CF_SYLK: lstrcpy( sz, _T( "CF_SYLK" ) ) ; break ;

        case CF_DIF: lstrcpy( sz, _T( "CF_DIF" ) ) ; break ;

        case CF_TIFF: lstrcpy( sz, _T( "CF_TIFF" ) ) ; break ;

        case CF_OEMTEXT: lstrcpy( sz, _T( "CF_OEMTEXT" ) ) ; break ;

        case CF_DIB: lstrcpy( sz, _T( "CF_DIB" ) ) ; break ;

        case CF_PALETTE: lstrcpy( sz, _T( "CF_PALETTE" ) ) ; break ;

        case CF_PENDATA: lstrcpy( sz, _T( "CF_PENDATA" ) ) ; break ;

        case CF_RIFF: lstrcpy( sz, _T( "CF_RIFF" ) ) ; break ;

        case CF_WAVE: lstrcpy( sz, _T( "CF_WAVE" ) ) ; break ;

        case 0: lstrcpy( sz, _T( "\"Wildcard Advise\"" ) ) ; break ;

        default:

            if (!GetClipboardFormatName( (UINT)cf, sz, 254 ))

                wsprintf( sz, _T( "%#08lX" ), (DWORD)cf ) ;

        break ;

    }

    return sz ;

}

UINT DBStrCpy(LPTSTR pszDst, LPCTSTR pszSrc, int far* pcLines) ;

BOOL  CIDataObjectDlg::WriteToOutput( LPTSTR lpsz )

{

    UINT cch;

    int cLines;

    cch = DBStrCpy(NULL, lpsz, &cLines);

    if (cch > (CCHOUTPUTMAX - m_cchOutput))

    {

        MessageBeep(0);

        return FALSE;

    }

    DBStrCpy(&m_szOutput[m_cchOutput], lpsz, NULL);

    m_cchOutput += cch;

    m_cLinesOutput += cLines;

    // If buffer was originally empty, wake up the main loop.

    //

    if (m_cchOutput == cch)

        PostMessage( m_hDlg, WM_OUTPUTBUFFERHASDATA, 0, 0L);

    return TRUE;

}

// This function performs a string copy (or string length if pszDst is NULL)

// It also ensures the destination string is properly formatted for the

// edit controls: line terminators must be CR followed by LF, in that orderc.

// If pcLines != NULL, returns number of lines in the string in *pcLines

//

// (pulled from the dbwin sample)

//

UINT DBStrCpy(LPTSTR pszDst, LPCTSTR pszSrc, int far* pcLines)

{

    TCHAR ch;

    UINT cch = 0;

    int cLines = 0;

    while (ch = *pszSrc++)

    {

        // If we find a CR or LF, then store a CR/LF in

        // the output string.

        //

        if (ch == 0x0d || ch == 0x0a)

        {

            cch += 2;

            cLines++;

            if (pszDst)

            {

                *pszDst++ = 0x0d;

                *pszDst++ = 0x0a;

            }

            // Skip any other CRs or LFs we find.

            //

            while ((ch = *pszSrc) && (ch == 0x0d || ch == 0x0a))

                ++pszSrc;

        }

        else

        {

            cch++;

            if (pszDst)

                *pszDst++ = ch;

        }

    }

    if (pszDst)

        *pszDst = 0;

    if (pcLines)

        *pcLines = cLines;

    return cch;

}

// Whenever something happens that causes output, it calls the WriteToOutput function

// which puts the data into a buffer (m_szOutput) and posts a message.  This is

// the message handler.

//

void CIDataObjectDlg::OnOutputBufferHasData()

{

    if (m_szOutput != NULL && m_cchOutput != 0)

    {

        int cLines = Edit_GetLineCount(m_edtAdvise) + m_cLinesOutput ;

        if (cLines > CLINESMAX)

        {

            SetWindowRedraw( m_edtAdvise, FALSE ) ;

            // If the total # of lines is greater than our arbitrary max lines

            // remove some from the top.

            //

            Edit_SetSel( m_edtAdvise, 0, Edit_LineIndex( m_edtAdvise, cLines - CLINESMAX));

            Edit_ReplaceSel( m_edtAdvise, _T(""));

        }

        // Put current output buffer at the end of the edit control

        //

        Edit_SetSel( m_edtAdvise, (UINT)-1, (UINT)-1 )  ;   // select the end

        Edit_ReplaceSel( m_edtAdvise, m_szOutput ) ;

        Edit_SetSel( m_edtAdvise, (UINT)-1, (UINT)-1 )  ;   // select the end

        if (cLines > CLINESMAX)

            SetWindowRedraw( m_edtAdvise, TRUE ) ;

        // Reset the output buffer

        m_cLinesOutput = 0 ;

        m_cchOutput = 0 ;

    }

}

// AddItem does a ListBox_AddString() plus a ListBox_SetItemData().  The

// item data that is set tells our owner-draw code what 'level' this

// item is at (indentation) and whether it is a label (bold), column

// head (column info is stored), or column entry (no column info is

// stored, but previous column head is used in WM_DRAWITEM).

//

int CIDataObjectDlg::AddItem( UINT nLevel, LPTSTR sz, LPVOID lpData, UINT uiType, int cColumns, LPCOLUMNSTRUCT  rgCol )

{

    int i ;

    LPITEMDATA      lpID ;

    i = ListBox_AddString( m_lbFmtEtc,  sz ) ;

    lpID = new ITEMDATA ;

    lpID->uiType = uiType ;

    lpID->cColumns = cColumns ;

    lpID->rgCol = rgCol ;

    lpID->nLevel = nLevel ;

    lpID->lpData = lpData ;

    ListBox_SetItemData( m_lbFmtEtc, i, (DWORD)lpID ) ;

    return i ;

}

int CIDataObjectDlg::AddItem( UINT nLevel, LPTSTR sz, LPVOID lpData, UINT uiType )

{

    return AddItem( nLevel, sz, lpData, uiType, 0, NULL ) ;

}

int CIDataObjectDlg::AddItem( UINT nLevel, LPTSTR sz, LPVOID lpData )

{

    return AddItem( nLevel, sz, lpData, I_NORMAL, 0, NULL ) ;

}

extern "C"

LRESULT EXPORT CALLBACK fnEditSubclass( HWND hwnd, UINT uiMsg, WPARAM wP, LPARAM lP )

{

    if (uiMsg == WM_PAINT)

    {

        HWND hwndParent = GetParent(hwnd) ;

        CIDataObjectDlg FAR* pIDOD =(CIDataObjectDlg FAR*)GetWindowLong( hwndParent, DWL_USER ) ;

        if (pIDOD && pIDOD->m_MetaFile.hMF != NULL)

        {

            PAINTSTRUCT ps ;

            BeginPaint( hwnd, &ps ) ;

/*

            if (pIDOD->m_MetaFile.mm == MM_ISOTROPIC || pIDOD->m_MetaFile.mm == MM_ANISOTROPIC)

            {

                if (pIDOD->m_MetaFile.xExt != 0 && pIDOD->m_MetaFile.yExt != 0)

                {

                }

            }

            else

            {

                SetMapMode( ps.hdc, MM_ANISOTROPIC ) ;

                SetWindowOrg( ps.hdc, 0, 0 ) ;

                SetWindowExt( ps.hdc, pIDOD->m_MetaFile.xExt, pIDOD->m_MetaFile.yExt ) ;

                SetViewportExt( ps.hdc, pIDOD->m_MetaFile.xExt, pIDOD->m_MetaFile.yExt ) ;

            }

*/

            PlayMetaFile( ps.hdc, pIDOD->m_MetaFile.hMF ) ;

            EndPaint( hwnd, &ps ) ;

            return 0L ;

        }

    }

    return CallWindowProc( g_pfnEdit, hwnd, uiMsg, wP, lP ) ;

}


IDATAO_A.CPP  (DEFO2V Sample)

// ansiwrap.cpp

//

// Creates ANSI versions of all modules.  Any exported function get's "A"

// appended.

//

//

#ifdef UNICODE

#undef UNICODE

#endif

#ifdef _UNICODE

#undef _UNICODE

#endif

#include "precompa.h"

#include "idataobj.cpp"


IDISP.H  (DEFO2V Sample)

// idataobj.h

//

// Header file for the IDispatch interface viewer.

//

// Copyright (c) 1993 Microsoft Corporation, All Rights Reserved.

//

// Charlie Kindel, Program Manager

// Microsoft Vertical Developer Relations

// August 7, 1993

//

// InterNet   :  ckindel@microsoft.com

// CompuServe :  >INTERNET:ckindel@microsoft.com

//

// Revisions:

//  August 7, 1993  cek     First implementation.

//

#ifndef _IDISP_H_

#define _IDISP_H_

#if defined(WIN32) && !defined(_UNICODE)

    #define DisplayIDispatch DisplayIDispatchA

    #define DisplayITypeLib DisplayITypeLibA

    #define DisplayITypeInfo DisplayITypeInfoA

    #define TYPEKINDtoString TYPEKINDtoStringA

    #define fnIDispDlg  fnIDispDlgA

    #define IDispDlg    IDispDlgA

#endif

LPTSTR TYPEKINDtoString( TYPEKIND tk );

/////////////////////////////////////////////////////////////////////////////

// IDispDlg dialog

extern "C"

BOOL WINAPI fnIDispDlg( HWND hDlg, UINT uiMsg, WPARAM wParam, LPARAM lParam ) ;

class FAR IDispDlg

{

    friend BOOL WINAPI fnIDispDlg( HWND hDlg, UINT uiMsg, WPARAM wParam, LPARAM lParam ) ;

// Construction

public:

    IDispDlg( HWND hwnd, LPUNKNOWN lpUnk, LPIID lpiid, LPTSTR lpszName ) ;

    ~IDispDlg() ;

    int DoModal( void ) ;

    // Input parameters (caller allocated)

    LPIID       m_piid ;

    LPTSTR       m_pszName ;

    LPDISPATCH  m_pDispatch ;

    LPTYPEINFO  m_pTypeInfo ;

    LPTYPELIB   m_pTypeLib ;

    // Dialog management

    HWND        m_hWndParent ;

    HWND        m_hDlg ;

    HWND        m_hwndTypeInfoCount;

    HWND        m_hwndTypeInfo;

    HWND        m_hwndTypeAttr;

    HWND        m_hwndFunctionsLbl;

    HWND        m_hwndFunctions;

    HWND        m_hwndVariablesLbl;

    HWND        m_hwndVariables;

    HWND        m_hwndFuncProto ;

    HWND        m_hwndFuncProtoLbl ;

    HWND        m_hwndInfo;

    HWND        m_hwndInfoLbl;

    HWND        m_hwndTypeInfoInfo ;

    HWND        m_btnToFile ;

    BOOL        m_fImplType;

// Implementation

protected:

    void DoGetInfo( ) ;

    BOOL DoTypeAttr( LPTYPEINFO  pTI ) ;

    void DoGetFunctions( LPTYPEINFO lpTI, WORD cFuncs ) ;

    void DoGetVars( LPTYPEINFO lpTI, WORD cVars ) ;

    void DoGetImplTypes( LPTYPEINFO lpTI, WORD cImplTypes );

    BOOL OnInitDialog();

    void OnSize(UINT nType, int cx, int cy);

    void OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct);

    void OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct);

    void OnDestroy();

    void OnSelChangeTypeInfo();

    void OnSelChangeFunctions();

    void OnSelChangeVariables();

    void OnToFile() ;

    BOOL GetImplFlag();

    void SetImplFlag( BOOL fVal );

};

#endif // _IDISP_H_


IDISP.CPP  (DEFO2V Sample)

// idisp.cpp

//

// Implementation file for the IDispatch interface viewer.

//

// Copyright (c) 1993 Microsoft Corporation, All Rights Reserved.

//

// Charlie Kindel, Program Manager

// Microsoft Vertical Developer Relations

// August 7, 1993

//

// Internet   :  ckindel@microsoft.com

// CompuServe :  >INTERNET:ckindel@microsoft.com

//

// Revisions:

//  August 7, 1993  cek     First implementation.

//

//

// This module contains the Interface Viewer functions for the

// IDispatch, ITypeInfo, and ITypeLib interfaces.

// This implementation displays all of the

// type information that can be retrieved from an arbitrary IDispatch,

// ITypeInfo, or ITypeLib pointer.

//

// NOTE:  This module exports the following interface viewers:

//

//      DisplayIDispatch()

//      DisplayITypeInfo()

//      DisplayITypeLib()

//

// Each of these functions boils down to the same dialog and code.

//

// Note that attempting to 'look at' an arbitrary ITypeInfo pointer

// which was received from QueryInterface() is a somewhat bogus thing

// to do.   We provide DisplayITypeInfo here only for completeness.

//

//

// ANOTHER NOTE:

// Since this viewer can take an ITypeLib, it makes a great Type Library

// viewer.  That is why it is used by Ole2View for the File.View Type Libary

// command...

//

#include "precomp.h"

#include "defo2v.h"

#include "idisp.h"

#include "tofile.h"

#if defined(WIN32) && !defined(_UNICODE)

    #pragma message("Building ANSI version of " __FILE__)

#endif

static HFONT        g_hFont ;

static UINT         g_cyFont ;

// These functions take a hwnd of a listbox, an IDispatch related structure,

// and string and dump the contents of the structure to the listbox.

// All structure members are prefixed by szLabel in the listbox.

//

void DumpTYPEDESC( HWND hwnd, TYPEDESC FAR* lptdesc, LPTSTR szLabel ) ;

void DumpARRAYDESC( HWND hwnd, ARRAYDESC FAR* lpadesc, LPTSTR szLabel ) ;

void DumpIDLDESC( HWND hwnd, LPIDLDESC lp, LPTSTR szLabel ) ;

void DumpELEMDESC( HWND hwnd, LPELEMDESC lp, LPTSTR szLabel ) ;

void DumpFUNCDESC( HWND hwnd, LPFUNCDESC lpfndesc, LPTSTR szLabel ) ;

void DumpVARDESC( HWND hwnd, LPVARDESC lpvardesc, LPTSTR szLabel ) ;

static TCHAR * g_rgszTYPEKIND[] =

{

    _T("enum"),         /* TKIND_ENUM */

    _T("Struct"),       /* TKIND_RECORD */

    _T("Module"),       /* TKIND_MODULE */

    _T("Interface"),    /* TKIND_INTERFACE */

    _T("Dispinterface"),    /* TKIND_DISPATCH */

    _T("CoClass"),      /* TKIND_COCLASS */

    _T("Alias"),        /* TKIND_ALIAS */

    /* NOTE: the following aren't supported in typeinfo yet */

    _T("Union"),        /* TKIND_UNION */

    _T("Encap Union"),   /* TKIND_ENCUNION */

    _T("Class"),        // TKIND_Class

    _T("CoType"),       // TKIND_COOTYPE

#if WIN32==300

    _T("unused"),

    _T("PropSet"),

    _T("EnventSet"),

    _T("CmdSet"),

#endif

    _T("<error!>"),     // dummy entries just in case the ole spec changes

    _T("<error!>"),     // and new enum's are added!

    _T("<error!>"),

    _T("<error!>"),

    _T("<error!>"),

};

LPTSTR TYPEKINDtoString( TYPEKIND tk )

{

    return (LPTSTR)g_rgszTYPEKIND[tk] ;

}

static TCHAR * g_rgszIDLFLAGS[] =

{

    _T(""),         //IDLFLAG_NONE = 0,

    _T("IN"),       //IDLFLAG_FIN = 1,

    _T("OUT"),      //IDLFLAG_FOUT = 2,

    _T("IN OUT"),   //IDLFLAF_FIN | IDLFLAG_FOUT

    _T("<error!>"),     // dummy entries just in case the ole spec changes

    _T("<error!>"),     // and new enum's are added!

    _T("<error!>"),

    _T("<error!>"),

    _T("<error!>"),

};

static TCHAR * g_rgszFUNCKIND[] =

{

    _T("VIRUTAL"),

    _T("PUREVIRTUAL"),

    _T("NONVIRTUAL"),

    _T("STATIC"),

    _T("DISPATCH"),

    _T("<error!>"),     // dummy entries just in case the ole spec changes

    _T("<error!>"),     // and new enum's are added!

    _T("<error!>"),

    _T("<error!>"),

    _T("<error!>"),

} ;

static TCHAR * g_rgszCALLCONV[] =

{

    _T("0"),

    _T("CDECL"),        // CC_CDECL, = 1,

    _T("PASCAL"),       // CC_MSCPASCAL and CC_PASCAL

    _T("MACPASCAL"),     // CC_MACPASCAL,

    _T("STDCALL"),       // CC_STDCALL,

    _T("THISCALL"),      // CC_THISCALL,

    _T("MAX"),           // end of enum marker

    _T("<error!>"),     // dummy entries just in case the ole spec changes

    _T("<error!>"),     // and new enum's are added!

    _T("<error!>"),

    _T("<error!>"),

    _T("<error!>"),

};

static TCHAR * g_rgszVARKIND[] =

{

    _T("PERINSTANCE"),  //VAR_PERINSTANCE,

    _T("STATIC"),       //VAR_STATIC

    _T("CONST"),        //VAR_CONST

    _T("DISPATCH"),      //VAR_DISPATCH

    _T("<error!>"),     // dummy entries just in case the ole spec changes

    _T("<error!>"),     // and new enum's are added!

    _T("<error!>"),

    _T("<error!>"),

    _T("<error!>"),

} ;

//ASSERTDATA

// DisplayIDispatch

//

// This

STDAPI DisplayIDispatch( HWND hwndParent, LPDISPATCH lpDisp, LPIID lpiid, LPTSTR lpszName )

{

    HRESULT hr = NULL ;

//    Assert( hwndParent ) ;

//    Assert( lpDisp ) ;

//    Assert( lpiid ) ;

    IDispDlg    dispdlg( hwndParent, (LPUNKNOWN)lpDisp, lpiid, lpszName ) ;

    dispdlg.DoModal() ;

    return hr ;

}

// DisplayITypeInfo

//

// This

STDAPI DisplayITypeInfo( HWND hwndParent, LPTYPEINFO lpTypeInfo, LPIID lpiid, LPTSTR lpszName )

{

    HRESULT hr = NULL ;

//    Assert( hwndParent ) ;

//    Assert( lpTypeInfo ) ;

//    Assert( lpiid ) ;

    IDispDlg    dispdlg( hwndParent, (LPUNKNOWN)lpTypeInfo,lpiid, lpszName ) ;

    dispdlg.DoModal() ;

    return hr ;

}

STDAPI DisplayITypeLib( HWND hwndParent, LPTYPELIB lpTypeLib, LPIID lpiid, LPTSTR lpszName )

{

    HRESULT hr = NULL ;

    int     rc;

//    Assert( hwndParent ) ;

//    Assert( lpTypeLib ) ;

//    Assert( lpiid ) ;

    IDispDlg    dispdlg( hwndParent, (LPUNKNOWN)lpTypeLib, lpiid, lpszName ) ;

    rc = dispdlg.DoModal() ;

    return hr ;

}

/////////////////////////////////////////////////////////////////////////////

// IDispDlg dialog

//

// The constructor is where we begin to descern between the three possible

// interfaces that could be passed in.

//

IDispDlg::IDispDlg(HWND hwnd, LPUNKNOWN lpUnk, LPIID lpiid, LPTSTR lpszName )

{

    m_hWndParent = hwnd ;

    m_piid = lpiid ;

    m_pszName = lpszName ;

    m_pDispatch = NULL ;

    m_pTypeInfo = NULL ;

    m_pTypeLib = NULL ;

    m_fImplType = FALSE;

    if (IsEqualIID( *m_piid, IID_IDispatch ))

    {

        m_pDispatch = (LPDISPATCH)lpUnk ;

        m_pDispatch->AddRef() ;

    }

#ifdef OB32BUG

    else if (IsEqualIID( *m_piid, IID_IMyTypeInfo ))

#else

    else if (IsEqualIID( *m_piid, IID_ITypeInfo ))

#endif

    {

        m_pTypeInfo = (LPTYPEINFO)lpUnk ;

        m_pTypeInfo->AddRef() ;

    }

#ifdef OB32BUG

    else if (IsEqualIID( *m_piid, IID_IMyTypeLib ))

#else

    else if (IsEqualIID( *m_piid, IID_ITypeLib ))

#endif

    {

        m_pTypeLib = (LPTYPELIB)lpUnk ;

        m_pTypeLib->AddRef() ;

    }

    else

    {

//        AssertSz(0, _T("Some Thing is wrong\n") ) ;

    }

}

IDispDlg::~IDispDlg( )

{

}

int IDispDlg::DoModal( void )

{

    return DialogBoxParam( g_hInst, MAKEINTRESOURCE( IDD_IDISPDLG ), m_hWndParent, (DLGPROC)fnIDispDlg, (LONG)this ) ;

}

extern "C"

BOOL EXPORT WINAPI fnIDispDlg( HWND hDlg, UINT uiMsg, WPARAM wParam, LPARAM lParam )

{

    IDispDlg FAR* pIDD =(IDispDlg FAR*)GetWindowLong( hDlg, DWL_USER ) ;

    switch (uiMsg)

    {

        case WM_INITDIALOG:

            pIDD=(IDispDlg FAR*)lParam ;

            if (pIDD==NULL)

            {

                EndDialog( hDlg, 0 ) ;

                return TRUE ;

            }

            pIDD->m_hDlg = hDlg ;

            SetWindowLong( hDlg, DWL_USER, (LONG)pIDD ) ;

            pIDD->OnInitDialog() ;

            PostMessage( hDlg, WM_USER+1, 0, 0 ) ;

        break ;

        // It's nice to let the dialog appear before we

        // do a lengthy operation.

        case WM_USER+1:

        {

            HCURSOR hcur = SetCursor( LoadCursor( NULL, IDC_WAIT ) ) ;

            pIDD->DoGetInfo() ;

            SetCursor( hcur ) ;

        }

        break ;

        case WM_DESTROY:

            if (pIDD)

                pIDD->OnDestroy() ;

        break ;

        case WM_SIZE:

            if (pIDD)

                pIDD->OnSize( (UINT)wParam, LOWORD( lParam ), HIWORD( lParam ) ) ;

        break ;

        case WM_COMMAND:

        {

#ifdef WIN32

            WORD wNotifyCode = HIWORD(wParam);

            WORD wID = LOWORD(wParam);

            HWND hwndCtl = (HWND) lParam;

#else

            WORD wNotifyCode = HIWORD(lParam) ;

            WORD wID = wParam ;

            HWND hwndCtl = (HWND)LOWORD(lParam) ;

#endif

            switch (wID)

            {

                case IDCANCEL:

                    EndDialog( hDlg, IDCANCEL ) ;

                break ;

                case IDC_TOFILE:

                    pIDD->OnToFile() ;

                break ;

                case IDC_TYPEINFO:

                    if (wNotifyCode == LBN_SELCHANGE)

                        pIDD->OnSelChangeTypeInfo() ;

                break ;

                case IDC_TYPEATTR:

                break ;

                case IDC_FUNCTIONS:

                    switch(wNotifyCode)

                    {

                        case LBN_SELCHANGE:

                            pIDD->OnSelChangeFunctions() ;

                        break;

                    }

                break ;

                case IDC_VARIABLES:

                    switch(wNotifyCode)

                    {

                        case LBN_SELCHANGE:

                            pIDD->OnSelChangeVariables() ;

                        break;

                    }

                break ;

            }

        }

        break ;

        default:

           return FALSE ;

    }

    return TRUE ;

}

void IDispDlg::SetImplFlag( BOOL fVal )

{

    m_fImplType= fVal;

}

BOOL IDispDlg::GetImplFlag( )

{

    return m_fImplType;

}

BOOL IDispDlg::OnInitDialog()

{

    // Setup member vars, so we have easy access to

    // dialog items.

    //

    m_hwndTypeInfoCount = GetDlgItem( m_hDlg, IDC_TYPEINFOCOUNT ) ;

    m_hwndTypeInfo = GetDlgItem( m_hDlg, IDC_TYPEINFO ) ;

    m_hwndTypeAttr = GetDlgItem( m_hDlg, IDC_TYPEATTR ) ;

    m_hwndFunctionsLbl = GetDlgItem( m_hDlg, IDC_FUNCTIONS_LBL ) ;

    m_hwndFunctions = GetDlgItem( m_hDlg, IDC_FUNCTIONS ) ;

    m_hwndVariablesLbl = GetDlgItem( m_hDlg, IDC_VARIABLES_LBL ) ;

    m_hwndVariables = GetDlgItem( m_hDlg, IDC_VARIABLES ) ;

    m_hwndFuncProtoLbl = GetDlgItem( m_hDlg, IDC_FUNCPROTO_LBL ) ;

    m_hwndFuncProto = GetDlgItem( m_hDlg, IDC_FUNCPROTO ) ;

    m_hwndInfo = GetDlgItem( m_hDlg, IDC_FUNCVARDESC ) ;

    m_hwndInfoLbl = GetDlgItem( m_hDlg, IDC_FUNCVARDESC_LBL ) ;

    m_hwndTypeInfoInfo = GetDlgItem( m_hDlg, IDC_TYPEINFOINFO ) ;

    m_btnToFile = GetDlgItem( m_hDlg, IDC_TOFILE ) ;

    // Create fonts we may use..

    //

    TEXTMETRIC  tm ;

    HDC hdc = GetDC(NULL);

    g_hFont = ReallyCreateFont( hdc, _T("MS Sans Serif"), _T("Regular"), 8, 0 ) ;

    g_hFont = (HFONT) SelectObject( hdc, g_hFont ) ;

    GetTextMetrics( hdc, &tm ) ;

    g_hFont = (HFONT) SelectObject( hdc, g_hFont ) ;

    ReleaseDC( NULL, hdc ) ;

    g_cyFont = tm.tmHeight + tm.tmExternalLeading ;

    SetWindowFont( m_hwndTypeInfoCount, g_hFont, TRUE ) ;

    SetWindowFont( m_hwndVariables, g_hFont, TRUE ) ;

    SetWindowFont( m_hwndTypeAttr, g_hFont, TRUE ) ;

    SetWindowFont( m_hwndInfo, g_hFont, TRUE ) ;

    SetWindowFont( m_hwndTypeInfoInfo, g_hFont, TRUE ) ;

    SetWindowFont( m_hwndFunctions, g_hFont, TRUE ) ;

    SetWindowFont( m_hwndFuncProto, g_hFont, TRUE ) ;

    DlgCenter( m_hDlg, m_hWndParent, FALSE ) ;

    RECT rc ;

    GetWindowRect( m_hDlg, &rc ) ;

    SetWindowPos( m_hDlg, NULL, rc.left, rc.top, rc.right - rc.left + 1,

                  rc.bottom - rc.top +1, SWP_NOMOVE|SWP_NOZORDER | SWP_NOACTIVATE ) ;

    SetWindowText( m_hDlg, m_pszName ) ;

    return TRUE;  // return TRUE  unless you set the focus to a control

}

void IDispDlg::OnDestroy()

{

    if (g_hFont)

        DeleteObject( g_hFont );

    if (m_pDispatch != NULL)

    {

        m_pDispatch->Release() ;

        m_pDispatch = NULL ;

    }

    if (m_pTypeInfo != NULL)

    {

        m_pTypeInfo->Release() ;

        m_pTypeInfo = NULL ;

    }

    if (m_pTypeLib != NULL)

    {

        m_pTypeLib->Release() ;

        m_pTypeLib = NULL ;

    }

}

void IDispDlg::OnSize(UINT nType, int cx, int cy)

{

//    if (m_hwndTypeAttr && !IsWindow( m_hwndTypeAttr ) )

        return ;

    RECT    rc ;

    RECT    rcWnd ;

    GetClientRect( m_hDlg, &rcWnd ) ;

    GetWindowRect( m_hwndTypeAttr, &rc ) ;

    MapWindowPoints( NULL, m_hDlg, (POINT FAR*)&rc, 2 ) ;

    rc.left = rcWnd.left + 5 ;

    SetWindowPos( m_hwndTypeAttr, NULL, rcWnd.left + 5, rc.top, cx - 10, rc.bottom - rc.top,

                SWP_NOZORDER | SWP_NOACTIVATE ) ;

}

void IDispDlg::OnToFile()

{

    if (m_pTypeInfo == NULL && m_pTypeLib == NULL)

    {

        MessageBeep( 0 ) ;

        return ;

    }

    if (m_pTypeLib)

        DoTypeLibToFile( m_hDlg, m_pTypeLib ) ;

    else

        DoTypeInfoToFile( m_hDlg, m_pTypeInfo ) ;

}

// This starts our gathering of information.

// Here, we figure out which interface we were called for, get as

// much info as we can from it, including the other two

// interfaces if possible.   We fill the typeinfo listbox

// with all type infos found.

//

void IDispDlg::DoGetInfo()

{

    TCHAR        szTemp[128] ;

    UINT        uiTypeInfoCount = 0;

    HRESULT hr ;

    ComboBox_ResetContent( m_hwndTypeInfo ) ;

    if (m_pDispatch != NULL)

    {

        // If we were called for IDispatch we need to get at least the typelib.

        //

        // This whole thing is done somewhat roundabout:

        //

        // 1) Call GetTypeInfo to get the typeinfo for the programmability interface.

        // 2) Try to get the "containing TypeLib" for the typeinfo.

        // 3a) If we get m_pTypeLib back then this object was implemented using a Type Library

        //     and will probably have more than one typeinfo.

        // 3b) If the call to GetContainingTypeLib fails then this object does not

        //     use typelibs and thus probably has only one typeinfo.

        // 4) In either case we eventually get a count of typeinfos and we

        //    use either IDispatch::GetTypeInfo or ITypeLib::GetTypeInfo to get the

        //    type information for the object.

        //

        hr = m_pDispatch->GetTypeInfoCount( &uiTypeInfoCount ) ;

        if (FAILED( hr ))

        {

            wsprintf( szTemp, _T("IDispatch::GetTypeInfoCount( ) FAILED: %s"), (LPTSTR)HRtoString( hr ) ) ;

            MessageBox( m_hDlg, szTemp, _T("Could not get type information"), MB_OK ) ;

            return ;

        }

        if (uiTypeInfoCount <= 0)

        {

            wsprintf( szTemp, _T("This object reports zero TypeInfos.  There is no programmability information available.") ) ;

            MessageBox( m_hDlg, szTemp, _T("Could not get type information"), MB_OK ) ;

            return ;

        }

        hr = m_pDispatch->GetTypeInfo( 0, LOCALE_SYSTEM_DEFAULT, &m_pTypeInfo ) ;

        if (FAILED( hr ))

        {

            wsprintf( szTemp, _T("IDispatch::GetTypeInfo( 0 ) FAILED: %s"), (LPTSTR)HRtoString( hr ) ) ;

            MessageBox( m_hDlg, szTemp, _T("Could not get type information"), MB_OK ) ;

            return ;

        }

        UINT    ui ;

        hr = m_pTypeInfo->GetContainingTypeLib( &m_pTypeLib, &ui ) ;

        if (SUCCEEDED( hr ))

        {

            // We no longer need the typeinfo ptr

            //

            m_pTypeInfo->Release() ;

            m_pTypeInfo = NULL ;

            uiTypeInfoCount = m_pTypeLib->GetTypeInfoCount( ) ;

            SetWindowText( m_hwndTypeInfoInfo, _T("This object uses a Type Library.") ) ;

        }

        else

        {

            // We no longer need the typeinfo ptr.

            //

            m_pTypeInfo->Release() ;

            m_pTypeInfo = NULL ;

            // Bogus.  The app does not support TypeLib (i.e. WinWord 6.0).   Therefore we must

            // use IDispatch::GetTypeInfoCount...

            //

            hr = m_pDispatch->GetTypeInfoCount( &uiTypeInfoCount ) ;

            if (FAILED( hr ))

            {

                wsprintf( szTemp, _T("IDispatch::GetTypeInfoCount FAILED: %s"), (LPTSTR)HRtoString( hr ) ) ;

                MessageBox(  m_hDlg, szTemp, _T("Could not get count of typeinfos"), MB_OK ) ;

                return ;

            }

            SetWindowText( m_hwndTypeInfoInfo, _T("This object does not use a Type Library.") ) ;

        }

    }

    else if (m_pTypeLib != NULL)

    {

        // If we were called with a typelib we are in great shape

        //

        uiTypeInfoCount = m_pTypeLib->GetTypeInfoCount() ;

        SetWindowText( m_hwndTypeInfoInfo, _T("Browsing a TypeLibrary." )) ;

    }

    else if (m_pTypeInfo != NULL)

    {

        // We were called with at TypeInfo.  This is the specialist of cases.

        UINT    ui ;

        hr = m_pTypeInfo->GetContainingTypeLib( &m_pTypeLib, &ui ) ;

        if (SUCCEEDED( hr ))

        {

            // We no longer need the typeinfo ptr

            //

            m_pTypeInfo->Release() ;

            m_pTypeInfo = NULL ;

            uiTypeInfoCount = m_pTypeLib->GetTypeInfoCount( ) ;

            SetWindowText( m_hwndTypeInfoInfo, _T("This object uses a Type Library.") ) ;

        }

        else

        {

            // If we get here then we assume that there is only one

            // typeinfo and we're looking at it.

            //

            uiTypeInfoCount = 1 ;

            SetWindowText( m_hwndTypeInfoInfo, _T("Browsing a TypeInfo") ) ;

        }

    }

    wsprintf( szTemp, _T("%u"), (UINT)uiTypeInfoCount ) ;

    SetWindowText( m_hwndTypeInfoCount, szTemp ) ;

    // Fill combo box with all typeinfos

    //

    //

    for (UINT n = 1 ; n <= uiTypeInfoCount ; n++)

    {

        if (m_pTypeLib != NULL || m_pDispatch != NULL)

        {

            if (m_pTypeInfo != NULL)

            {

                m_pTypeInfo->Release() ;

                m_pTypeInfo = NULL ;

            }

            if (m_pTypeLib != NULL)

            {

                hr = m_pTypeLib->GetTypeInfo( n-1, &m_pTypeInfo ) ;

            }

            else if (m_pDispatch != NULL)

                hr = m_pDispatch->GetTypeInfo( n-1, LOCALE_SYSTEM_DEFAULT, &m_pTypeInfo ) ;

        }

        else if (m_pTypeInfo != NULL)

            hr = ResultFromScode( S_OK ) ;

        else

            hr = ResultFromScode( E_FAIL ) ;

        if (SUCCEEDED(hr))

        {

            // Note:  Early OLE2 samples (IDispatch Calculator #2)

            // would crash on a GetDocumentation( MEMBERID_NIL... ) call

            // it is commented out for now until we are sure that

            // it is working in OLE 2.01.

            //

#if 1

            BSTR    bstrName ;

            hr = m_pTypeInfo->GetDocumentation( MEMBERID_NIL, &bstrName, NULL, NULL, NULL ) ;

            if (SUCCEEDED(hr))

            {

                UINT ui ;

#if defined(WIN32) && !defined (OLE2ANSI)

                wsprintf( szTemp, _T("%ws (%u)"), bstrName ? bstrName : OLESTR("(null name)"), n-1 ) ;

#else

                wsprintf( szTemp, _T("%s (%u)"), bstrName ? bstrName : _T("(null name)"), n-1 ) ;

#endif

                ui = ComboBox_AddString( m_hwndTypeInfo, szTemp ) ;

                ComboBox_SetItemData( m_hwndTypeInfo, ui, (DWORD)n-1 ) ;

                SysFreeString( bstrName ) ;

            }

            else

#else

            BSTR            rgbstrNames[2] ;

            UINT            cNames ;

            hr = m_pTypeInfo->GetNames( MEMBERID_NIL, rgbstrNames, 1, &cNames );

            if (SUCCEEDED( hr ))

            {

                UINT ui ;

#if defined(WIN32) && !defined(OLE2ANSI)

                wsprintf( szTemp, _T("%ws (%u)"), (LPOLESTR)rgbstrNames[0], n-1 ) ;

#else

                wsprintf( szTemp, _T("%s (%u)"), (LPTSTR)rgbstrNames[0], n-1 ) ;

#endif

                ui = ComboBox_AddString( m_hwndTypeInfo, szTemp ) ;

                ComboBox_SetItemData( m_hwndTypeInfo, ui, (DWORD)n ) ;

                SysFreeString( rgbstrNames[0] ) ;

            }

            else

#endif

            {

                UINT ui ;

                wsprintf( szTemp, _T("%u (no name)"), n-1 ) ;

                ui = ComboBox_AddString( m_hwndTypeInfo, szTemp ) ;

                ComboBox_SetItemData( m_hwndTypeInfo, ui, (DWORD)n-1 ) ;

            }

        }

        else

        {

            wsprintf(szTemp, _T("%s::GetTypeInfo(#%u) FAILED: %s"),

                        (LPTSTR)(m_pTypeLib == NULL ? _T("IDispatch") :

                            _T("ITypeLib") ), n-1, (LPTSTR)HRtoString( hr ) ) ;

            MessageBox( m_hDlg, szTemp, _T("Error"), MB_OK ) ;

        }

    }

    ComboBox_SetCurSel( m_hwndTypeInfo, 0 ) ;

    // kick start

    OnSelChangeTypeInfo() ;

    return ;

}

// When the selection changes in the combo, we first make sure

// our current TypeInfo pointer is Released.

// Then get the pTypeInfo for the newly selected item.

// Use that pointer to populate the typeinfo listbox (actually

// m_pTypeAttr).

//

void IDispDlg::OnSelChangeTypeInfo()

{

    HRESULT     hr ;

    UINT        uiTinfo ;

    int         uiItem = ComboBox_GetCurSel( m_hwndTypeInfo );

    TCHAR        szTemp[128] ;

    if (uiItem == CB_ERR)

        return ;

    ListBox_ResetContent( m_hwndTypeAttr ) ;

    ListBox_ResetContent( m_hwndFunctions ) ;

    ListBox_ResetContent( m_hwndVariables ) ;

    ListBox_ResetContent( m_hwndInfo ) ;

    SetWindowText( m_hwndFuncProto, _T("") ) ;

    SetWindowText( m_hwndInfoLbl, _T("F&UNCDESC/VARDESC:") ) ;

    hr = ResultFromScode( E_FAIL ) ;

    if ((m_pDispatch != NULL || m_pTypeLib != NULL) && m_pTypeInfo != NULL)

    {

        m_pTypeInfo->Release() ;

        m_pTypeInfo = NULL ;

        // Get memid from item

        uiTinfo = (UINT)ComboBox_GetItemData( m_hwndTypeInfo, uiItem ) ;

        // Get typeinfo pointer

        if (m_pTypeLib != NULL)

            hr = m_pTypeLib->GetTypeInfo( uiTinfo, &m_pTypeInfo ) ;

        else

            hr = m_pDispatch->GetTypeInfo( uiTinfo, LOCALE_SYSTEM_DEFAULT, &m_pTypeInfo ) ;

    }

    else if (m_pTypeInfo != NULL)

        hr = ResultFromScode( S_OK ) ;

    if (SUCCEEDED(hr))

    {

        DWORD   dwHelp ;

        BSTR    bstrName, bstrDoc, bstrHelpFile ;

        hr = m_pTypeInfo->GetDocumentation( MEMBERID_NIL, &bstrName, &bstrDoc,  &dwHelp, &bstrHelpFile ) ;

        if (SUCCEEDED(hr))

        {

#if defined(WIN32) && !defined(OLE2ANSI)

            wsprintf( szTemp, _T("Name = %ws"), (LPOLESTR)(bstrName == NULL ? OLESTR("n/a") : bstrName) ) ;

#else

            wsprintf( szTemp, _T("Name = %s"), (LPTSTR)(bstrName == NULL ? _T("n/a") : bstrName) ) ;

#endif

            ListBox_AddString( m_hwndTypeAttr, szTemp ) ;

#if defined(WIN32) && !defined(OLE2ANSI)

            wsprintf( szTemp, _T("DocString = %ws"), (bstrDoc == NULL ? OLESTR("n/a") : bstrDoc) ) ;

#else

            wsprintf( szTemp, _T("DocString = %s"), (bstrDoc == NULL ? _T("n/a") : bstrDoc) ) ;

#endif

            ListBox_AddString( m_hwndTypeAttr, szTemp ) ;

            wsprintf( szTemp, _T("Help Context ID = %#08lX"), (DWORD)dwHelp ) ;

            ListBox_AddString( m_hwndTypeAttr, szTemp ) ;

#if defined(WIN32) && !defined(OLE2ANSI)

            wsprintf( szTemp, _T("Help File = %ws"), (LPOLESTR)(bstrHelpFile == NULL ? OLESTR("n/a") : bstrHelpFile) ) ;

#else

            wsprintf( szTemp, _T("Help File = %s"), (LPTSTR)(bstrHelpFile == NULL ? _T("n/a") : bstrHelpFile) ) ;

#endif

            ListBox_AddString( m_hwndTypeAttr, szTemp ) ;

            SysFreeString( bstrName ) ;

            SysFreeString( bstrDoc) ;

            SysFreeString( bstrHelpFile ) ;

        }

        else

        {

            wsprintf( szTemp, _T("GetDocumentation FAILED: %s"), HRtoString( hr ) ) ;

            ListBox_AddString( m_hwndTypeAttr, szTemp ) ;

        }

        // Get the containing typelib for this typeinfo.

        //

        UINT ui ;

        LPTYPELIB   pTL ;

        hr = m_pTypeInfo->GetContainingTypeLib( &pTL, &ui ) ;

        if (SUCCEEDED( hr ))

        {

            wsprintf( szTemp, _T("GetContainingTypeLib returned valid pTypelib (%#08lX, %u)"),

                        (LONG)pTL, ui ) ;

            pTL->Release() ;

        }

        else

            wsprintf( szTemp, _T("GetContainingTypeLib FAILED:  %s"), HRtoString( hr ) ) ;

        ListBox_AddString( m_hwndTypeAttr, szTemp ) ;

        // Call DoTypeAttr to get the TypeAttr info and to

        // fill the functions and variables listboxes.

        //

        DoTypeAttr( m_pTypeInfo ) ;

        // NEED: What other information can we put in this listbox?

        // what else is available, given ITypeInfo  pointer?

        //

        //

    }

    else

    {

        wsprintf( szTemp, _T("GetTypeInfo(#%u) FAILED: %s"), uiTinfo, HRtoString( hr ) ) ;

        ListBox_AddString( m_hwndTypeAttr, szTemp ) ;

    }

}

BOOL IDispDlg::DoTypeAttr( LPTYPEINFO  pTI )

{

    HRESULT hr ;

    TCHAR    szTemp[64] ;

    LPTYPEATTR  pTA = NULL ;

    hr = pTI->GetTypeAttr( &pTA ) ;

    if (FAILED( hr ))

    {

        wsprintf( szTemp, _T("GetTypeAttr FAILED: %s"), HRtoString( hr ) ) ;

        ListBox_AddString( m_hwndTypeAttr, szTemp ) ;

        return FALSE ;

    }

    if (pTA->typekind > TKIND_MAX)

        wsprintf( szTemp, _T("typekind = <invalid!> (%u)"), pTA->typekind ) ;

    else

        wsprintf( szTemp, _T("typekind = %s"), (LPSTR)g_rgszTYPEKIND[pTA->typekind] ) ;

    ListBox_AddString( m_hwndTypeAttr, szTemp ) ;

    wsprintf( szTemp, _T("Version =  %u.%03d"), pTA->wMajorVerNum, pTA->wMajorVerNum ) ;

    ListBox_AddString( m_hwndTypeAttr, szTemp ) ;

    wsprintf( szTemp, _T("lcid = %u"),  pTA->lcid ) ;

    ListBox_AddString( m_hwndTypeAttr, szTemp ) ;

    wsprintf( szTemp, _T("cFuncs = %d"), pTA->cFuncs ) ;

    ListBox_AddString( m_hwndTypeAttr, szTemp ) ;

    wsprintf( szTemp, _T("cVars = %u"), pTA->cVars ) ;

    ListBox_AddString( m_hwndTypeAttr, szTemp ) ;

    wsprintf( szTemp, _T("cImplTypes = %u"), pTA->cImplTypes ) ;

    ListBox_AddString( m_hwndTypeAttr, szTemp ) ;

    // DumpTYPEDESC will completely decode the tdescAlias for us...

    //

    DumpTYPEDESC( m_hwndTypeAttr, &pTA->tdescAlias, _T("tdescAlias." )) ;

    wsprintf(szTemp, _T("guid = {%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}"),

        pTA->guid.Data1, pTA->guid.Data2, pTA->guid.Data3,

        pTA->guid.Data4[0], pTA->guid.Data4[1],

        pTA->guid.Data4[2], pTA->guid.Data4[3],

        pTA->guid.Data4[4], pTA->guid.Data4[5],

        pTA->guid.Data4[6], pTA->guid.Data4[7]);

    ListBox_AddString( m_hwndTypeAttr, szTemp ) ;

    wsprintf(szTemp, _T("wTypeFlags = %04X"), pTA->wTypeFlags ) ;

    ListBox_AddString( m_hwndTypeAttr, szTemp ) ;

    wsprintf(szTemp, _T("dwReserved = %#08lX"), pTA->dwReserved ) ;

    ListBox_AddString( m_hwndTypeAttr, szTemp ) ;

    wsprintf(szTemp, _T("cbAlignment = %u"), pTA->cbAlignment ) ;

    ListBox_AddString( m_hwndTypeAttr, szTemp ) ;

    wsprintf(szTemp, _T("cbSizeInstance = %u"), pTA->cbSizeInstance ) ;

    ListBox_AddString( m_hwndTypeAttr, szTemp ) ;

    wsprintf(szTemp, _T("cbSizeVft = %u"), pTA->cbSizeVft ) ;

    ListBox_AddString( m_hwndTypeAttr, szTemp ) ;

    DumpIDLDESC( m_hwndTypeAttr, &pTA->idldescType, _T("idldescType.") ) ;

    wsprintf(szTemp, _T("memidConstructor = %#08lX"), (DWORD)pTA->memidConstructor ) ;

    ListBox_AddString( m_hwndTypeAttr, szTemp ) ;

    wsprintf(szTemp, _T("memidDestructor = %#08lX"), (DWORD)pTA->memidDestructor ) ;

    ListBox_AddString( m_hwndTypeAttr, szTemp ) ;

    // Get functions

    DoGetFunctions( pTI, pTA->cFuncs ) ;

    // Get variables

    DoGetVars( pTI, pTA->cVars ) ;

#if WIN32==300

    // GetImpl Types

    if ( pTA->typekind == TKIND_COTYPE)

    {

        DoGetImplTypes( pTI, pTA->cImplTypes );

    }

#endif

    if (pTI != NULL)

        pTI->ReleaseTypeAttr( pTA ) ;

    return TRUE ;

}

// Fill the function listbox with a list of all functions.

// The entries in the listbox show just the name of the function and

// when the selection changes, the static box below the list is

// updated to show the return value and parameters (OnFunctionsSelChange()).

//

void IDispDlg::DoGetFunctions( LPTYPEINFO lpTI, WORD cFuncs )

{

    TCHAR    szBuf[128] ;

    HRESULT hr ;

    TCHAR            szTemp[80] ;

    BSTR           rgbstrNames[2] ;

    UINT            cNames ;

    LPFUNCDESC      pFuncDesc ;

    WORD iIndex ;

    ListBox_ResetContent( m_hwndFunctions ) ;

    for ( iIndex = 0 ; iIndex < cFuncs ; iIndex++)

    {

        hr = lpTI->GetFuncDesc( iIndex, &pFuncDesc ) ;

        if (FAILED(hr))

        {

            wsprintf( szBuf, _T("GetFuncDesc FAILED for function #%u (%s)"), iIndex, (LPTSTR)HRtoString( hr ) ) ;

            ListBox_AddString( m_hwndFunctions, szBuf ) ;

            continue ;

        }

        // We could get the function name from either GetDocumentation or from

        // GetNames...we do it from GetNames...

        // (I had some problems getting GetDocumentation() to work with some

        // of the automation examples lying around)

        //

        // We AddString each function name into the list box, then

        // SetItemData 'i' so that we know the memberid of the function

        // for OnFunctionSelChange()

        //

        hr = lpTI->GetNames( pFuncDesc->memid, rgbstrNames, 1, &cNames );

        if (SUCCEEDED( hr ))

        {

            // rgbstrNames[0] is the name of the function

#if defined(WIN32) && !defined(UNICODE)

            char * szName = NULL;

            if (rgbstrNames[0])

            {

                szName = new char [wcslen(rgbstrNames[0]) + 1];

                if (szName)

                {

                    wcstombs(szName, rgbstrNames[0], wcslen(rgbstrNames[0]) + 1);

                }

            }

            ListBox_SetItemData( m_hwndFunctions,

                             ListBox_AddString( m_hwndFunctions, szName ),

                             (LONG)iIndex ) ;

            delete [] szName;

#else

            ListBox_SetItemData( m_hwndFunctions,

                             ListBox_AddString( m_hwndFunctions, rgbstrNames[0] ),

                             (LONG)iIndex ) ;

#endif

            SysFreeString( rgbstrNames[0] ) ;

        }

        else

        {

            wsprintf( szTemp, _T("GetNames (%lu) FAILED: %s"), pFuncDesc->memid, HRtoString( hr ) ) ;

            ListBox_AddString( m_hwndFunctions, szTemp ) ;

        }

        lpTI->ReleaseFuncDesc( pFuncDesc ) ;

    }

    ListBox_SetCurSel( m_hwndFunctions, 0 ) ;

    OnSelChangeFunctions() ;

}

// Set the text of m_hwndFuncProto so that it looks like this:

//

//    RetType FuncName ( Type Param1, Type Param2, ... )

//

// where RetType is a string associated with a VARTYPE (VTtoString())

// FuncName is bstrName.

void IDispDlg::OnSelChangeFunctions()

{

    int     iIndex = ListBox_GetCurSel( m_hwndFunctions ) ;

    #define MAX_NAMES   100

    BSTR    rgbstrNames[MAX_NAMES] ;

    UINT    cNames ;

    if (iIndex == LB_ERR || m_pTypeInfo == NULL)

    {

        SetWindowText( m_hwndFuncProto, _T("") ) ;

        return ;

    }

    TCHAR            szRet[128] ;

    TCHAR            szFuncName[64] ;

    lstrcpy( szFuncName, _T("<???>") ) ;

    LPTSTR           szfn = NULL ;

    LPFUNCDESC      pFuncDesc = NULL;

    HRESULT         hr ;

    UINT            cParams ;

    // the index of the FUNCDESC is stored as itemdata

    iIndex = (int)ListBox_GetItemData( m_hwndFunctions, iIndex ) ;

    // Get the FUNCDESC for this function.

    // Save off cParams and get the return value type

    //

    hr = m_pTypeInfo->GetFuncDesc( iIndex, &pFuncDesc ) ;

    if (SUCCEEDED(hr))

    {

        cParams = pFuncDesc->cParams ;

        lstrcpy( szRet, TYPEDESCtoString( &pFuncDesc->elemdescFunc.tdesc ) ) ;

        lstrcat( szRet, _T(" ") ) ;

        // Get the names of the function and it's parameters into rgbstrNames.

        // cNames gets the number of parameters + 1.

        //

        // Note:  T3 (2004 - 8/5/93) is really weird here.  It sometimes

        // returns cNames - 1 == pFuncDesc->cParams, sometimes it's < and

        // sometimes is >.   There is no sense to it.

        //

        hr = m_pTypeInfo->GetNames( pFuncDesc->memid, rgbstrNames, MAX_NAMES, &cNames );

        if (SUCCEEDED( hr ))

        {

            // Allocate a string buffer that should be able to hold

            // all of our parameter types and names.

            //

            if ((szfn = (LPTSTR) GlobalAllocPtr( GPTR, max(cNames,cParams) * (64) )) == NULL )

            {

                MessageBox( m_hDlg, _T("GlobalAlloc Failed!"), _T("Yikes!"), MB_OK ) ;

                return ;

            }

            // put the return value first

            lstrcpy( szfn, szRet ) ;

            // rgbstrNames[0] is the name of the function

            if (cNames > 0)

            {

#if defined(WIN32) && !defined(UNICODE)

                wcstombs(szFuncName, rgbstrNames[0], wcslen(rgbstrNames[0]) + 1);

#else

                lstrcpy( szFuncName, rgbstrNames[0] ) ;

#endif

                lstrcat( szfn, szFuncName) ;

                lstrcat( szfn, _T("(") ) ;

                SysFreeString( rgbstrNames[0] ) ;

            }

            // For each parameter get the type and name.

            // The "max(cNames-1,cParams)" should handle the case

            // where a function has optional parameters (i.e. cParamsOpt is

            // non-zero).

            //

            for ( UINT n = 0 ; n < max(cNames-1,cParams) ; n++ )

            {

                if (n == 0)

                    lstrcat( szfn, _T("\r\n    ") ) ;

                if (n < cParams)    // safety check

                {

                    lstrcat( szfn, g_rgszIDLFLAGS[pFuncDesc->lprgelemdescParam[n].idldesc.wIDLFlags] ) ;

                    lstrcat( szfn, _T(" ") ) ;

                    lstrcat( szfn, TYPEDESCtoString( &pFuncDesc->lprgelemdescParam[n].tdesc ) ) ;

                }

                if (n+1 < cNames)   // saftey check

                {

                    if (n < cParams)

                        lstrcat( szfn, _T(" ") ) ;

#if defined(WIN32) && !defined(UNICODE)

                    wcstombs(&szfn[strlen(szfn) + 1], rgbstrNames[n+1], wcslen(rgbstrNames[n+1]) + 1);

#else

                    lstrcat( szfn, rgbstrNames[n+1] ) ;

#endif

                    SysFreeString( rgbstrNames[n+1] ) ;

                }

                if (n + 1 == max(cNames-1,cParams))

                    lstrcat( szfn, _T("\r\n    ") );

                else

                    lstrcat( szfn, _T(",\r\n    ") ) ;

            }

            lstrcat( szfn , _T(")")  );

        }

        else

        {

            lstrcat( szRet, _T("GetNames FAILED: ") ) ;

            lstrcat( szRet, HRtoString( hr ) ) ;

        }

        if (szfn)

        {

            SetWindowText( m_hwndFuncProto, szfn ) ;

            GlobalFreePtr( szfn );

        }

        else

            SetWindowText( m_hwndFuncProto, szRet ) ;

    }

    else

    {

        wsprintf( szRet, _T("GetFuncDesc FAILED: %s "), HRtoString( hr ) ) ;

        SetWindowText( m_hwndFuncProto, szRet ) ;

        pFuncDesc = NULL ;

    }

    if (pFuncDesc != NULL)

    {

        TCHAR szTemp[256] ;

        wsprintf( szTemp, _T("FUNC&DESC for %s:"), (LPSTR)szFuncName ) ;

        SetWindowText( m_hwndInfoLbl, szTemp ) ;

        ListBox_ResetContent( m_hwndInfo ) ;

        DWORD    dwHelp ;

        BSTR    bstrName, bstrDoc, bstrHelpFile ;

        hr = m_pTypeInfo->GetDocumentation( pFuncDesc->memid, &bstrName, &bstrDoc,  &dwHelp, &bstrHelpFile ) ;

        if (SUCCEEDED(hr))

        {

#if defined(WIN32) && !defined(OLE2ANSI)

            wsprintf( szTemp, _T("Name = %ws"), (LPOLESTR)(bstrName == NULL ? OLESTR("n/a") : bstrName) ) ;

#else

            wsprintf( szTemp, _T("Name = %s"), (LPTSTR)(bstrName == NULL ? _T("n/a") : bstrName) ) ;

#endif

            ListBox_AddString( m_hwndInfo, szTemp ) ;

//            ListBox_AddString( m_hwndInfo, bstrName ) ;    stevebl - this lookes like it was a bug

#if defined(WIN32) && !defined(OLE2ANSI)

            wsprintf( szTemp, _T("DocString = %ws"), (bstrDoc == NULL ? OLESTR("n/a") : bstrDoc) ) ;

#else

            wsprintf( szTemp, _T("DocString = %s"), (bstrDoc == NULL ? _T("n/a") : bstrDoc) ) ;

#endif

            ListBox_AddString( m_hwndInfo, szTemp ) ;

            wsprintf( szTemp, _T("Help Context ID = %#08lX"), (DWORD)dwHelp ) ;

            ListBox_AddString( m_hwndInfo, szTemp ) ;

#if defined(WIN32) && !defined(OLE2ANSI)

            wsprintf( szTemp, _T("Help File = %ws"), (LPOLESTR)(bstrHelpFile == NULL ? OLESTR("n/a") : bstrHelpFile) ) ;

#else

            wsprintf( szTemp, _T("Help File = %s"), (LPTSTR)(bstrHelpFile == NULL ? _T("n/a") : bstrHelpFile) ) ;

#endif

            ListBox_AddString( m_hwndInfo, szTemp ) ;

            SysFreeString( bstrName ) ;

            SysFreeString( bstrDoc) ;

            SysFreeString( bstrHelpFile ) ;

        }

        else

        {

            wsprintf( szTemp, _T("GetDocumentation FAILED: %s"), HRtoString( hr ) ) ;

            ListBox_AddString( m_hwndInfo, szTemp ) ;

        }

        DumpFUNCDESC( m_hwndInfo, pFuncDesc, _T("") ) ;

        m_pTypeInfo->ReleaseFuncDesc( pFuncDesc ) ;

    }

}

void IDispDlg::DoGetImplTypes( LPTYPEINFO lpTI, WORD cImplTypes )

{

    HRESULT     hr;

#ifdef WIN32

    ULONG       iIndex;

#else

    UINT        iIndex ;

#endif

    HREFTYPE    hRefType;

    ITypeInfo   *lpitihRef;

    BSTR       bstrName;

    ListBox_ResetContent( m_hwndVariables);

    SetImplFlag( TRUE );

    for ( iIndex  = 0 ; iIndex < cImplTypes ; iIndex++ )

    {

        hr = lpTI->GetRefTypeOfImplType( iIndex, &hRefType );

        if ( SUCCEEDED(hr))

        {

           hr = lpTI->GetRefTypeInfo( hRefType, &lpitihRef);

           if (SUCCEEDED(hr))

           {

                hr = lpitihRef->GetDocumentation( MEMBERID_NIL,

                                                  &bstrName,

                                                  NULL,

                                                  NULL,

                                                  NULL);

                if (SUCCEEDED(hr))

                {

#if defined(WIN32) && !defined(UNICODE)

                    char * szName = NULL;

                    if (bstrName)

                    {

                        szName = new char [wcslen(bstrName) + 1];

                        if (szName)

                        {

                            wcstombs(szName, bstrName, wcslen(bstrName) + 1);

                        }

                    }

                    ListBox_AddString( m_hwndVariables, szName ) ;

                    delete [] szName;

#else

                    ListBox_AddString( m_hwndVariables, bstrName ) ;

#endif

                }

                SysFreeString( bstrName );

           }

           lpitihRef->Release();

        }

    }

}

void IDispDlg::DoGetVars( LPTYPEINFO lpTI, WORD cVars )

{

    TCHAR    szBuf[128] ;

    WORD    iIndex ;

    TCHAR    szTemp[80] ;

    HRESULT hr ;

    BSTR    rgbstrNames[2] ;

    UINT    cNames ;

    ListBox_ResetContent( m_hwndVariables) ;

    for (iIndex = 0 ; iIndex < cVars ; iIndex++)

    {

        LPVARDESC      pVarDesc ;

        hr = lpTI->GetVarDesc( iIndex, &pVarDesc ) ;

        if (FAILED(hr))

        {

            wsprintf( szBuf, _T("GetVarDesc FAILED for variable #%u (%s)"), iIndex, HRtoString( hr ) ) ;

            ListBox_AddString( m_hwndVariables, szBuf ) ;

            continue ;

        }

        else

        {

            // memid\tname

            hr = lpTI->GetNames( pVarDesc->memid, rgbstrNames, 1, &cNames );

            if (SUCCEEDED( hr ))

            {

#if defined(WIN32) && !defined(OLE2ANSI)

                wsprintf( szBuf, _T("%ws (%s"), rgbstrNames[0],

                            TYPEDESCtoString( &pVarDesc->elemdescVar.tdesc ) ) ;

#else

                wsprintf( szBuf, _T("%s (%s"), rgbstrNames[0],

                            TYPEDESCtoString( &pVarDesc->elemdescVar.tdesc ) ) ;

#endif

                lstrcat( szBuf, _T(")") ) ;

                SysFreeString( rgbstrNames[0] ) ;

                if (pVarDesc->varkind == VAR_CONST)

                {

                    // NEED:  This just prints out the type.  We can get the value

                    // too.  Need to write at VARIANTtoString() function.

                    //

                    VARIANT varValue ;

                    VariantInit( &varValue ) ;

                    hr = VariantChangeType( &varValue, pVarDesc->lpvarValue, 0, VT_BSTR ) ;

                    if (FAILED(hr))

                        wsprintf( szTemp, _T(" = %s"), HRtoString( hr ) ) ;

                    else

                    {

                        wsprintf( szTemp, _T(" = %s"), varValue.bstrVal ) ;

                        SysFreeString( varValue.bstrVal ) ;

                    }

                    lstrcat( szBuf, szTemp ) ;

                }

                // rgbstrNames[0] is the name of the function

                ListBox_SetItemData( m_hwndVariables,

                                 ListBox_AddString( m_hwndVariables, szBuf ),

                                 (LONG)iIndex ) ;

            }

            else

            {

                wsprintf( szTemp, _T("GetNames (%lu) FAILED: %s"), pVarDesc->memid, HRtoString( hr ) ) ;

                ListBox_AddString( m_hwndVariables, szTemp ) ;

            }

            lpTI->ReleaseVarDesc( pVarDesc ) ;

        }

    }

    ListBox_SetCurSel( m_hwndVariables, 0 ) ;

    OnSelChangeVariables() ;

}

void IDispDlg::OnSelChangeVariables()

{

    // we are overloading the m_hwndVariables to have

    // contain impltype info, which don't have an list

    // box item data.

    if (GetImplFlag())

    {

        return;

    }

    int         iIndex = ListBox_GetCurSel( m_hwndVariables ) ;

    LPVARDESC   pVarDesc = NULL;

    HRESULT     hr ;

    BSTR        rgbstrNames[2] ;

    UINT        cNames ;

    TCHAR        szTemp[256] ;

    if (iIndex == LB_ERR || m_pTypeInfo == NULL)

        return ;

    ListBox_ResetContent( m_hwndInfo ) ;

    // the index of the VARDESC is stored as itemdata

    iIndex = (int)ListBox_GetItemData( m_hwndVariables, iIndex ) ;

    // Get the VARDESC for this Vartion.

    // Save off cParams and get the return value type

    //

    hr = m_pTypeInfo->GetVarDesc( iIndex, &pVarDesc ) ;

    if (SUCCEEDED(hr))

    {

        hr = m_pTypeInfo->GetNames( pVarDesc->memid, rgbstrNames, 1, &cNames );

        if (SUCCEEDED(hr))

        {

#if defined(WIN32) && !defined(OLE2ANSI)

            wsprintf( szTemp, _T("Var&DESC for %ws:"), rgbstrNames[0] ) ;

#else

            wsprintf( szTemp, _T("Var&DESC for %s:"), rgbstrNames[0] ) ;

#endif

            SysFreeString( rgbstrNames[0] ) ;

        }

        else

            lstrcpy( szTemp, _T("Var&DESC:") ) ;

        SetWindowText( m_hwndInfoLbl, szTemp ) ;

        DWORD   dwHelp ;

        BSTR    bstrName, bstrDoc, bstrHelpFile ;

        hr = m_pTypeInfo->GetDocumentation( pVarDesc->memid, &bstrName, &bstrDoc,  &dwHelp, &bstrHelpFile ) ;

        if (SUCCEEDED(hr))

        {

#if defined(WIN32) && !defined(OLE2ANSI)

            wsprintf( szTemp, _T("Name = %ws"), (LPOLESTR)(bstrName == NULL ? OLESTR("n/a") : bstrName) ) ;

#else

            wsprintf( szTemp, _T("Name = %s"), (LPTSTR)(bstrName == NULL ? _T("n/a") : bstrName) ) ;

#endif

            ListBox_AddString( m_hwndInfo, szTemp ) ;

//            ListBox_AddString( m_hwndInfo, bstrName ) ;    stevebl - this lookes like it was a bug

#if defined(WIN32) && !defined(OLE2ANSI)

            wsprintf( szTemp, _T("DocString = %ws"), (bstrDoc == NULL ? OLESTR("n/a") : bstrDoc) ) ;

#else

            wsprintf( szTemp, _T("DocString = %s"), (bstrDoc == NULL ? _T("n/a") : bstrDoc) ) ;

#endif

            ListBox_AddString( m_hwndInfo, szTemp ) ;

            wsprintf( szTemp, _T("Help Context ID = %#08lX"), (DWORD)dwHelp ) ;

            ListBox_AddString( m_hwndInfo, szTemp ) ;

#if defined(WIN32) && !defined(OLE2ANSI)

            wsprintf( szTemp, _T("Help File = %ws"), (LPOLESTR)(bstrHelpFile == NULL ? OLESTR("n/a") : bstrHelpFile) ) ;

#else

            wsprintf( szTemp, _T("Help File = %s"), (LPTSTR)(bstrHelpFile == NULL ? _T("n/a") : bstrHelpFile) ) ;

#endif

            ListBox_AddString( m_hwndInfo, szTemp ) ;

            SysFreeString( bstrName ) ;

            SysFreeString( bstrDoc) ;

            SysFreeString( bstrHelpFile ) ;

        }

        else

        {

            wsprintf( szTemp, _T("GetDocumentation FAILED: %s"), HRtoString( hr ) ) ;

            ListBox_AddString( m_hwndInfo, szTemp ) ;

        }

        DumpVARDESC( m_hwndInfo, pVarDesc, _T("") ) ;

        m_pTypeInfo->ReleaseVarDesc( pVarDesc ) ;

    }

    else

    {

        wsprintf( szTemp, _T("GetVarDesc FAILED: %s "), (LPTSTR)HRtoString( hr ) ) ;

        ListBox_AddString( m_hwndInfo, szTemp ) ;

    }

}

void DumpTYPEDESC( HWND hwnd, TYPEDESC FAR* lptdesc, LPTSTR szLabel )

{

    TCHAR szTemp[128] ;

    if (lptdesc == NULL)

    {

        wsprintf( szTemp, _T("%slptdesc is NULL (this is an error)"), (LPTSTR)szLabel ) ;

        ListBox_AddString( hwnd, szTemp ) ;

        return ;

    }

    // Dump a TYPEDESC

    wsprintf( szTemp, _T("%svt = %s"), (LPTSTR)szLabel, (LPTSTR)VTtoString( lptdesc->vt ) ) ;

    ListBox_AddString( hwnd, szTemp ) ;

    if ((lptdesc->vt & 0x0FFF) == VT_PTR)

    {

        // lptdesc points to a TYPEDESC that specifies the thing pointed to

        wsprintf( szTemp, _T("%slptdesc->"), (LPTSTR)szLabel ) ;

        DumpTYPEDESC( hwnd, lptdesc->lptdesc, szTemp ) ;

        return ;

    }

    if ((lptdesc->vt & 0x0FFF) == VT_USERDEFINED)

    {

        wsprintf( szTemp, _T("%shreftype = %#08lX"), (LPTSTR)szLabel, (DWORD)lptdesc->hreftype ) ;

        ListBox_AddString( hwnd, szTemp ) ;

        return ;

    }

    if ((lptdesc->vt & 0x0FFF) == VT_CARRAY)

    {

        wsprintf( szTemp, _T("%slpadesc->"), (LPTSTR)szLabel ) ;

        DumpARRAYDESC( hwnd, lptdesc->lpadesc, szTemp ) ;

        return ;

    }

#ifdef _VT_FUNCPTR_DEFINED

    if ((lptdesc->vt & 0x0FFF) == VT_FUNCPTR)

    {

        wsprintf( szTemp, "%slpfdesc->", szLabel ) ;

        DumpFUNCDESC( hwnd, lptdesc->lpadesc, szTemp ) ;

        return ;

    }

#endif

}

void DumpARRAYDESC( HWND hwnd, ARRAYDESC FAR* lpadesc, LPTSTR szLabel )

{

    TCHAR szTemp[128] ;

    if (lpadesc == NULL)

    {

        wsprintf( szTemp, _T("%slpadesc is NULL (this is an error)"), szLabel ) ;

        ListBox_AddString( hwnd, szTemp ) ;

        return ;

    }

    wsprintf( szTemp, _T("%stdescElem."), szLabel ) ;

    DumpTYPEDESC( hwnd, &lpadesc->tdescElem, szTemp ) ;

    wsprintf( szTemp, _T("%scDims = %u"),  szLabel, lpadesc->cDims ) ;

    ListBox_AddString( hwnd, szTemp ) ;

}

void DumpIDLDESC( HWND hwnd, LPIDLDESC lpidldesc, LPTSTR szLabel )

{

    TCHAR szTemp[128] ;

    wsprintf(szTemp, _T("%swIDLFlags = %s"), szLabel,

            g_rgszIDLFLAGS[lpidldesc->wIDLFlags] ) ;

    ListBox_AddString( hwnd, szTemp ) ;

#ifndef WIN32

    if (lpidldesc->bstrIDLInfo != NULL)

        wsprintf( szTemp, "%sbstrIDLInfo = %s", szLabel,

                    lpidldesc->bstrIDLInfo ) ;

    else

        wsprintf( szTemp, "%sbstrIDLInfo = NULL", szLabel ) ;

#else

    wsprintf( szTemp, _T("%sdwReserved = %#08lX"), szLabel,

              lpidldesc->dwReserved ) ;

#endif

    ListBox_AddString( hwnd, szTemp ) ;

}

void DumpELEMDESC( HWND hwnd, LPELEMDESC lpelemdesc, LPTSTR szLabel )

{

    TCHAR szTemp[128] ;

    wsprintf( szTemp, _T("%stdesc."), szLabel ) ;

    DumpTYPEDESC( hwnd, &lpelemdesc->tdesc, szTemp ) ;

    wsprintf( szTemp, _T("%sidldesc."), szLabel ) ;

    DumpIDLDESC( hwnd, &lpelemdesc->idldesc, szTemp ) ;

}

void DumpFUNCDESC( HWND hwnd, LPFUNCDESC lpfndesc, LPTSTR szLabel )

{

    TCHAR szTemp[128] ;

    // MEMBERID  memid ;

    wsprintf( szTemp, _T("%smemid = %#08lX"), szLabel, (DWORD)lpfndesc->memid ) ;

    ListBox_AddString( hwnd, szTemp ) ;

    // FUNCKIND  funckind ;

    wsprintf( szTemp, _T("%sfunckind = %s"), szLabel, g_rgszFUNCKIND[lpfndesc->funckind] ) ;

    ListBox_AddString( hwnd, szTemp ) ;

    // INVOKEKIND   invkind ;

    if (lpfndesc->invkind == INVOKE_FUNC)

        wsprintf( szTemp, _T("%sinvkind = FUNC"), szLabel ) ;

    else if (lpfndesc->invkind == INVOKE_PROPERTYGET)

        wsprintf( szTemp, _T("%sinvkind = PROPERTYGET"), szLabel ) ;

    else if (lpfndesc->invkind == INVOKE_PROPERTYPUT)

        wsprintf( szTemp, _T("%sinvkind = PROPERTYPUT"), szLabel ) ;

    else if (lpfndesc->invkind == INVOKE_PROPERTYPUTREF)

        wsprintf( szTemp, _T("%sinvkind = PROPERTYPUTREF"), szLabel ) ;

    ListBox_AddString( hwnd, szTemp ) ;

    // CALLCONV callconv;

    wsprintf( szTemp, _T("%scallconv = %s"), szLabel, g_rgszCALLCONV[lpfndesc->callconv] ) ;

    ListBox_AddString( hwnd, szTemp ) ;

    // SHORT cParams;

    wsprintf( szTemp, _T("%scParams = %d"), szLabel, lpfndesc->cParams ) ;

    ListBox_AddString( hwnd, szTemp ) ;

    // SHORT cParamsOpt;

    wsprintf( szTemp, _T("%scParamsOpt = %d"), szLabel, lpfndesc->cParamsOpt ) ;

    ListBox_AddString( hwnd, szTemp ) ;

    // SHORT oVft;

    wsprintf( szTemp, _T("%soVft = %d"), (LPTSTR)szLabel, lpfndesc->oVft ) ;

    ListBox_AddString( hwnd, szTemp ) ;

    // WORD wFuncFlags;

    wsprintf( szTemp, _T("%swFuncFlags = %u"), szLabel, lpfndesc->wFuncFlags ) ;

    ListBox_AddString( hwnd, szTemp ) ;

    // ELEMDESC elemdescFunc;

    wsprintf( szTemp, _T("%selemdescFunc."), szLabel ) ;

    DumpELEMDESC( hwnd, &lpfndesc->elemdescFunc, szTemp ) ;

    // ELEMDESC FAR* lprgelemdescParam;  /* array of parameter types */

    for (SHORT s = 0 ; s < lpfndesc->cParams ; s++)

    {

        wsprintf( szTemp, _T("%slprgelemdescParam[%u]."), szLabel, s ) ;

        DumpELEMDESC( hwnd, &lpfndesc->lprgelemdescParam[s], szTemp ) ;

    }

    // SHORT cScodes;

    wsprintf( szTemp, _T("%scScodes = %d"), szLabel, lpfndesc->cScodes ) ;

    ListBox_AddString( hwnd, szTemp ) ;

#if 1

// BUGBUG:  Run Ole2View, invoke IDispatch Calc #2, double click on it's

// IDispatch, close the viewer.   Invoke Word Basic, double click on it's

// IDispatch.  All calls to GetFuncDesc return a FUNCDESC where cScodes is

// some bogus # like 0x0778.   Note that if we invoke Word Basic right

// after Ole2View starts up this problem does not occur.

    // SCODE FAR* lprgscode;

    if (lpfndesc->cScodes > 0)

    {

        //AssertSz( lpfndesc->lprgscode, "lpfndesc->sCodes > 0 when it shouldn't be" ) ;

        for (s = 0 ; s < lpfndesc->cScodes ; s++)

        {

            if (lpfndesc->lprgscode == NULL)

                wsprintf( szTemp, _T("%slprgscode = NULL (this is an error)"), szLabel ) ;

            else

                wsprintf( szTemp, _T("%slprgscode[%u] = %s"), szLabel, s,

                        HRtoString( ResultFromScode( lpfndesc->lprgscode[s] ) ) ) ;

            ListBox_AddString( hwnd, szTemp ) ;

        }

    }

    //AssertSz( !(lpfndesc->cScodes < -1), "lpfndesc->sCodes < -1 when it shouldn't be" ) ;

#endif

}

void DumpVARDESC( HWND hwnd, LPVARDESC lpvardesc, LPTSTR szLabel )

{

    TCHAR szTemp[128] ;

    // MEMBERID memid;

    wsprintf( szTemp, _T("%smemid = %#08lX"), szLabel, (DWORD)lpvardesc->memid ) ;

    ListBox_AddString( hwnd, szTemp ) ;

    // WORD wVarFlags;

    wsprintf( szTemp, _T("%swVarFlags = %s"), szLabel,

              lpvardesc->wVarFlags == VARFLAG_FREADONLY ? _T("READONLY") :  _T("NOT READONLY") ) ;

    ListBox_AddString( hwnd, szTemp ) ;

    // VARKIND varkind;

    wsprintf( szTemp, _T("%svarkind = %s"), szLabel, g_rgszVARKIND[lpvardesc->varkind] ) ;

    ListBox_AddString( hwnd, szTemp ) ;

    // ELEMDESC elemdescVar;

    wsprintf( szTemp, _T("%selemdescVar."), szLabel ) ;

    DumpELEMDESC( hwnd, &lpvardesc->elemdescVar, szTemp ) ;

    // union { ULONG oInst;  VARIANT FAR* lpvarValue;  }

    if (lpvardesc->varkind == VAR_PERINSTANCE)

    {

        wsprintf( szTemp, _T("%soInst = %lu"), szLabel, lpvardesc->oInst ) ;

    }

    else if (lpvardesc->varkind == VAR_CONST)

    {

        // NEED:  This just prints out the type.  We can get the value

        // too.  Need to write at VARIANTtoString() function.

        //

        //

        VARIANT varValue ;

        VariantInit( &varValue ) ;

        HRESULT hr = VariantChangeType( &varValue, lpvardesc->lpvarValue, 0, VT_BSTR ) ;

        if (FAILED(hr))

            wsprintf( szTemp, _T("%slpvarValue = %s = %s"), szLabel,

                        VTtoString( lpvardesc->lpvarValue->vt ), HRtoString( hr ) ) ;

        else

        {

            wsprintf( szTemp, _T("%slpvarValue = %s = %s"),  szLabel,

                    VTtoString( lpvardesc->lpvarValue->vt ), varValue.bstrVal ) ;

            SysFreeString( varValue.bstrVal ) ;

        }

        ListBox_AddString( hwnd, szTemp ) ;

    }

}

// end of idisp.cpp


IDISP_A.CPP  (DEFO2V Sample)

// ansiwrap.cpp

//

// Creates ANSI versions of all modules.  Any exported function get's "A"

// appended.

//

//

#ifdef UNICODE

#undef UNICODE

#endif

#ifdef _UNICODE

#undef _UNICODE

#endif

#include "precompa.h"

#include "idisp.cpp"


PRECOMP.H  (DEFO2V Sample)

#ifndef _PRECOMP_H_

#define _PRECOMP_H_

#define STRICT

// Disable "unrefereced formal parameter"

#pragma warning( disable : 4100 )

// Disable "Note: Creating new precompiled header"

#pragma warning( disable : 4699 )

// Disable "4706: assignment within conditional expression"

#pragma warning( disable : 4706 )

// Disable "4201: nonstandard...nameless struct/union"

#pragma warning( disable : 4201 )

// DIsable "C4514: unreferenced inline function has been removed

#pragma warning( disable : 4514 )

#ifdef WIN32

#define EXPORT

#else

#define EXPORT __export

#endif

#ifdef _UNICODE

#ifndef UNICODE

#define UNICODE         // UNICODE is used by Windows headers

#endif

#endif

#ifdef WIN32

    #ifndef WIN32_LEAN_AND_MEAN

    #define WIN32_LEAN_AND_MEAN

    #endif

    #ifndef INC_OLE2

    #define INC_OLE2

    #endif

#else

    #include <memory.h>

#endif

#include <windows.h>

#include <windowsx.h>

#include <ole2.h>

#ifdef WIN32

    #include <tchar.h>

#endif

#ifdef _UNICODE

#else

#ifndef WIN32

 #define LPTSTR      LPSTR

 #define LPCTSTR     LPCSTR

 #define _T(a_)      a_

 #define _T(a_)      a_

#endif

#endif

#ifndef WIN32

#include <ole2.h>

#include <olenls.h>

#include <ver.h>

#include <compobj.h>

#include <variant.h>

#include <dispatch.h>

#else

#include <oleauto.h>

#endif

#endif // _PRECOMP_H_


PRECOMPA.H  (DEFO2V Sample)

// OLEANSI Precompiled header

//

#if defined(_UNICODE) || defined(UNICODE)

#error UNICODE and _UNICODE must not be defined for ANSIWRAP.CPP

#endif

#include "precomp.h"


RESOURCE.H  (DEFO2V Sample)

//{{NO_DEPENDENCIES}}

// Microsoft Visual C++ generated include file.

// Used by DEFO2V.RC

//

#define IDC_IFACE_PROPS                 102

#define IDC_FORMATETC                   102

#define IDD_IDATAOBJDLG                 103

#define IDC_GETDATA                     103

#define IDD_IDISPDLG                    104

#define IDC_TYPEINFO                    1000

#define IDC_TYPEATTR                    1007

#define IDC_VARIABLES                   1008

#define IDC_FUNCTIONS                   1009

#define IDC_INFO                        1010

#define IDC_FUNCTIONS_LBL               1011

#define IDC_VARIABLES_LBL               1012

#define IDC_TYPEINFOCOUNT               1013

#define IDC_FUNCPROTO_LBL               1014

#define IDC_FUNCPROTO                   1015

#define IDC_FUNCVARDESC                 1016

#define IDC_FUNCVARDESC_LBL             1018

#define IDC_TYPEINFOINFO                1019

#define IDC_TOFILE                      1020

#define IDC_DOGETDATA                   1021

#define IDC_SETUPADVISE                 1022

#define IDC_ADVISEDATA                  1023

#define IDC_UPDATEDISPLAY               1024

#define IDC_PRIMEFIRST                  1025

#define IDC_CLEAROUTPUT                 1027

// Next default values for new objects

//

#ifdef APSTUDIO_INVOKED

#ifndef APSTUDIO_READONLY_SYMBOLS

#define _APS_NEXT_RESOURCE_VALUE        101

#define _APS_NEXT_COMMAND_VALUE         40001

#define _APS_NEXT_CONTROL_VALUE         1027

#define _APS_NEXT_SYMED_VALUE           101

#endif

#endif


TOFILE.H  (DEFO2V Sample)

#ifndef _TOFILE_H_

#define _TOFILE_H_

#if defined(WIN32) && !defined(_UNICODE)

    #define DoTypeInfoToFile    DoTypeInfoToFileA

    #define DoTypeLibToFile     DoTypeLibToFileA

#endif

BOOL DoTypeInfoToFile( HWND hwnd, LPTYPEINFO lpTypeInfo )  ;

BOOL DoTypeLibToFile( HWND hwnd, LPTYPELIB lpTypeLib ) ;

#endif // _TOFILE_H_


TOFILE.CPP  (DEFO2V Sample)

// tofile.cpp

//

// Dumps a TypeLib or a TypeInfo to a file

//

#include "precomp.h"

#include "defo2v.h"

#include "idisp.h"

#include "tofile.h"

#include <stdlib.h>

#include <commdlg.h>

#include <math.h>

#if defined(WIN32) && !defined(_UNICODE)

    #pragma message("Building ANSI version of " __FILE__)

#endif

static BOOL StringToFile( HFILE hf, LPCTSTR psz )

{

    int cc = lstrlen(psz) ;

#ifndef WIN32

    return _lwrite( hf, psz, cc ) != HFILE_ERROR ;

#else

    DWORD   dw ;

    #ifdef _UNICODE

    char*   sz = new char[cc+1] ;

    cc = WideCharToMultiByte( CP_ACP, 0, psz, cc, sz, cc, NULL, NULL ) ;

    BOOL f = WriteFile((HANDLE)hf, sz, cc, &dw, NULL ) ;

    delete [] sz ;

    return f ;

    #else

    return WriteFile((HANDLE)hf, psz, cc, &dw, NULL ) ;

    #endif

#endif

}

#ifdef WIN32

#define CLOSEFILE(h)      CloseHandle((HANDLE)h)

#else

#define CLOSEFILE(h)      _lclose(h)

#endif

static OLECHAR szNotAvail[] = OLESTR("(not available)") ;

#define BSTR_PRT(bstr) (LPOLESTR)((bstr != NULL && SysStringLen(bstr)) ? (LPOLESTR)bstr : (LPOLESTR)szNotAvail)

static BOOL TypeInfoToFile( HFILE  hfile, LPTYPEINFO lpTypeInfo ) ;

static LPTSTR BuildParam( LPTSTR sz, LPELEMDESC lpelemdesc, LPTSTR lpszName, BOOL fOptional ) ;

static HFILE GetFileToSave( HWND hwnd, LPTSTR szTitle )

{

    OPENFILENAME ofn;

    TCHAR szFile[256], szFileTitle[256];

    UINT  i, cbString;

    TCHAR  chReplace;    /* string separator for szFilter */

    HFILE hf = HFILE_ERROR ;

    static TCHAR  szFilter[] = _T("Text Files (*.txt)|*.txt|") ;

    cbString = lstrlen( szFilter ) ;

    chReplace = szFilter[cbString - 1]; /* retrieve wildcard */

    for (i = 0; szFilter[i] != _T('\0'); i++)

    {

        if (szFilter[i] == chReplace)

           szFilter[i] = _T('\0');

    }

    /* Set all structure members to zero. */

    _fmemset(&ofn, 0, sizeof(OPENFILENAME));

    /* Initialize the OPENFILENAME members. */

    szFile[0] = '\0';

    ofn.lStructSize = sizeof(OPENFILENAME);

    ofn.hwndOwner = hwnd;

    ofn.lpstrFilter = szFilter;

    ofn.lpstrFile= szFile;

    ofn.nMaxFile = sizeof(szFile);

    ofn.lpstrFileTitle = szFileTitle;

    ofn.lpstrTitle = szTitle ;

    ofn.nMaxFileTitle = sizeof(szFileTitle);

    ofn.lpstrInitialDir = NULL ;

    ofn.Flags =     OFN_SHOWHELP |

                    OFN_OVERWRITEPROMPT |

                    OFN_HIDEREADONLY ;

    if (GetSaveFileName(&ofn))

    {

        #ifndef WIN32

        OFSTRUCT of ;

        hf = OpenFile( ofn.lpstrFile, &of, OF_CREATE ) ;

        #else

        hf = (HFILE)CreateFile( ofn.lpstrFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ) ;

        #endif

    }

    return hf ;

}

BOOL DoTypeInfoToFile( HWND hwnd, LPTYPEINFO lpTypeInfo )

{

    HFILE hf = GetFileToSave( hwnd, _T("Save TypeInfo to File") ) ;

    if (hf == HFILE_ERROR)

        return FALSE ;

    HCURSOR hcur = SetCursor(LoadCursor( NULL, IDC_WAIT )) ;

    TypeInfoToFile( hf, lpTypeInfo ) ;

    SetCursor( hcur ) ;

    CLOSEFILE( hf ) ;

    return TRUE ;

}

BOOL DoTypeLibToFile( HWND hwnd, LPTYPELIB lpTypeLib )

{

    HRESULT     hr ;

    LPTYPEINFO  lpTypeInfo ;

    HFILE       hf ;

    hf = GetFileToSave( hwnd, _T("Save TypeLib to File") ) ;

    #ifdef WIN32

    if (hf == 0)

        return FALSE ;

    #else

    if (hf == HFILE_ERROR)

        return FALSE ;

    #endif

    HCURSOR hcur = SetCursor(LoadCursor( NULL, IDC_WAIT )) ;

    TLIBATTR FAR* pTlibAttr ;

    lpTypeLib->GetLibAttr(&pTlibAttr ) ;

    BSTR           bstrName = NULL ;

    BSTR           bstrDoc = NULL ;

    BSTR           bstrHelp = NULL ;

    DWORD           dwHelpID ;

    hr = lpTypeLib->GetDocumentation( MEMBERID_NIL, &bstrName, &bstrDoc, &dwHelpID, &bstrHelp ) ;

    if (SUCCEEDED(hr))

    {

        TCHAR           szBuf[256] ;

        wsprintf( szBuf,    _T("'===============================================================\r\n") ) ;

        StringToFile( hf, szBuf ) ;

#if defined (WIN32) && !defined (OLE2ANSI)

        wsprintf( szBuf,    _T("' Type Library: %ws, Library Version %d.%03d\r\n"),

                            BSTR_PRT(bstrName), pTlibAttr->wMajorVerNum, pTlibAttr->wMinorVerNum ) ;

#else

        wsprintf( szBuf,    _T("' Type Library: %s, Library Version %d.%03d\r\n"),

                            BSTR_PRT(bstrName), pTlibAttr->wMajorVerNum, pTlibAttr->wMinorVerNum ) ;

#endif

        StringToFile( hf, szBuf ) ;

        wsprintf( szBuf,    _T("' GUID: {%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}\r\n"),

                            pTlibAttr->guid.Data1, pTlibAttr->guid.Data2, pTlibAttr->guid.Data3,

                            pTlibAttr->guid.Data4[0], pTlibAttr->guid.Data4[1],

                            pTlibAttr->guid.Data4[2], pTlibAttr->guid.Data4[3],

                            pTlibAttr->guid.Data4[4], pTlibAttr->guid.Data4[5],

                            pTlibAttr->guid.Data4[6], pTlibAttr->guid.Data4[7]) ;

        StringToFile( hf, szBuf ) ;

        wsprintf( szBuf,    _T("' LCID: %#08X\r\n"), (DWORD)pTlibAttr->lcid ) ;

        StringToFile( hf, szBuf ) ;

#if defined (WIN32) && !defined (OLE2ANSI)

        wsprintf( szBuf,    _T("' Documentation: %ws\r\n"), BSTR_PRT(bstrDoc) ) ;

#else

        wsprintf( szBuf,    _T("' Documentation: %s\r\n"), BSTR_PRT(bstrDoc) ) ;

#endif

        StringToFile( hf, szBuf ) ;

#if defined (WIN32) && !defined (OLE2ANSI)

        wsprintf( szBuf,    _T("' Help: %ws (Help ID: %#08lX)\r\n"), BSTR_PRT(bstrHelp), (DWORD)dwHelpID ) ;

#else

        wsprintf( szBuf,    _T("' Help: %s (Help ID: %#08lX)\r\n"), BSTR_PRT(bstrHelp), (DWORD)dwHelpID ) ;

#endif

        StringToFile( hf, szBuf ) ;

        wsprintf( szBuf,    _T("'===============================================================\r\n\r\n") ) ;

        StringToFile( hf, szBuf ) ;

        SysFreeString( bstrName ) ;

        SysFreeString( bstrDoc ) ;

        SysFreeString( bstrHelp ) ;

        lpTypeLib->ReleaseTLibAttr( pTlibAttr ) ;

    }

    else

    {

        lpTypeLib->ReleaseTLibAttr( pTlibAttr ) ;

        TCHAR szBuf[128] ;

        wsprintf( szBuf, _T("GetDocumentation for TypeInfo FAILED: %s"), HRtoString( hr ) ) ;

        StringToFile( hf, szBuf ) ;

        return FALSE ;

    }

    UINT uiTypeInfoCount = lpTypeLib->GetTypeInfoCount() ;

    for (UINT n = 0 ; n < uiTypeInfoCount ; n++)

    {

        hr = lpTypeLib->GetTypeInfo( n, &lpTypeInfo ) ;

        if (SUCCEEDED(hr))

        {

            TypeInfoToFile( hf, lpTypeInfo ) ;

            lpTypeInfo->Release() ;

        }

        else

        {

            TCHAR szBuf[128] ;

            wsprintf( szBuf, _T("ERROR: Could not get TypeInfo %d: %s\r\n"), n, (LPTSTR)HRtoString(hr) ) ;

            StringToFile( hf, szBuf) ;

        }

    }

    SetCursor( hcur ) ;

    CLOSEFILE( hf ) ;

    return TRUE ;

}

// Given a pointer to a TypeInfo and a handle to an open file, write

// all functions, variables, and constants.   The file is written in

// a form such that it looks like a VBA "include" file.

//

// A header is written first:

//

// '

// ' Type Information for the <wordbasic> TypeInfo

// ' Documentation: <docstring>

// ' Help for this TypeInfo can be found in <helpfile>

// ' The help ID for this TypeInfo is <helpid>

//

// Functions appear in the following form:

//

// '

// ' <funcname>

// ' Documentation: <docstring>

// ' Help for this function can be found in <helpfile>

// ' The help ID for this function is <helpid>

// Declare Function <funcname>(<arglist>) As <returntype>

//

// Subroutines (functions without return types) appear as:

// '

// ' <funcname>

// ' Documentation: <docstring>

// ' Help for this subroutine can be found in <helpfile>

// ' The help ID for this subroutine is <helpid>

// Declare Sub <funcname>(<arglist>)

//

// Properties/Variables appear as:

//

// '

// ' <varname>

// ' Documentation: <docstring>

// ' Help for this property can be found in <helpfile>

// ' The help ID for this property is <helpid>

// Dim <varname> As <vartype>

//

// Constants appear as:

//

// '

// ' <varname>

// ' Documentation: <docstring>

// ' Help for this property can be found in <helpfile>

// ' The help ID for this property is <helpid>

// Const <varname> As <vartype> = <value>

//

static BOOL TypeInfoToFile( HFILE  hfile, LPTYPEINFO lpTypeInfo )

{

    TCHAR szBuf[512] ;

//    Assert( hfile != HFILE_ERROR ) ;

//    Assert( lpTypeInfo ) ;

    #define MAX_NAMES   128

    HRESULT         hr ;

    BSTR           bstrName = NULL ;

    BSTR           bstrDoc = NULL ;

    BSTR           bstrHelp = NULL ;

    BSTR           rgbstrNames[MAX_NAMES] ;

    DWORD           dwHelpID ;

    int             cNames ;

    WORD            cFuncs, cVars ;

    LPFUNCDESC      pFuncDesc ;

    WORD            iIndex ;

    LPTYPEATTR  pTA = NULL ;

    hr = lpTypeInfo->GetTypeAttr( &pTA ) ;

    if (FAILED( hr ))

    {

        wsprintf( szBuf, _T("GetTypeAttr FAILED: %s"), (LPTSTR)HRtoString( hr ) ) ;

        StringToFile( hfile, szBuf ) ;

        return FALSE ;

    }

    hr = lpTypeInfo->GetDocumentation( MEMBERID_NIL, &bstrName, &bstrDoc, &dwHelpID, &bstrHelp ) ;

    if (SUCCEEDED(hr))

    {

        wsprintf( szBuf,    _T("'===============================================================\r\n") ) ;

        StringToFile( hfile, szBuf ) ;

#if defined (WIN32) && !defined (OLE2ANSI)

        wsprintf( szBuf,    _T("' Type Info: %ws, TypeInfo Version %d.%03d\r\n"),

                            BSTR_PRT(bstrName), pTA->wMajorVerNum, pTA->wMinorVerNum ) ;

#else

        wsprintf( szBuf,    _T("' Type Info: %s, TypeInfo Version %d.%03d\r\n"),

                            BSTR_PRT(bstrName), pTA->wMajorVerNum, pTA->wMinorVerNum ) ;

#endif

        StringToFile( hfile, szBuf ) ;

        wsprintf( szBuf,    _T("' GUID: {%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}\r\n"),

                            pTA->guid.Data1, pTA->guid.Data2, pTA->guid.Data3,

                            pTA->guid.Data4[0], pTA->guid.Data4[1],

                            pTA->guid.Data4[2], pTA->guid.Data4[3],

                            pTA->guid.Data4[4], pTA->guid.Data4[5],

                            pTA->guid.Data4[6], pTA->guid.Data4[7]);

        StringToFile( hfile, szBuf ) ;

        wsprintf( szBuf,    _T("' LCID: %#08X\r\n"), (DWORD)pTA->lcid ) ;

        StringToFile( hfile, szBuf ) ;

        wsprintf( szBuf,    _T("' TypeKind: %s\r\n"), (LPTSTR)TYPEKINDtoString(pTA->typekind) ) ;

        StringToFile( hfile, szBuf ) ;

        if (bstrDoc && SysStringLen(bstrDoc))

        {

#if defined (WIN32) && !defined (OLE2ANSI)

            wsprintf( szBuf,    _T("' Documentation: %ws\r\n"), (LPOLESTR)bstrDoc ) ;

#else

            wsprintf( szBuf,    _T("' Documentation: %s\r\n"), (LPTSTR)bstrDoc ) ;

#endif

            StringToFile( hfile, szBuf ) ;

        }

        if (bstrHelp && SysStringLen(bstrHelp))

        {

#if defined (WIN32) && !defined (OLE2ANSI)

            wsprintf( szBuf,    _T("' Help: %ws (Help ID: %#08lX)\r\n"), (LPOLESTR)bstrHelp,  (DWORD)dwHelpID ) ;

#else

            wsprintf( szBuf,    _T("' Help: %s (Help ID: %#08lX)\r\n"), (LPTSTR)bstrHelp,  (DWORD)dwHelpID ) ;

#endif

            StringToFile( hfile, szBuf ) ;

        }

        wsprintf( szBuf,    _T("'---------------------------------------------------------------\r\n\r\n") ) ;

        StringToFile( hfile, szBuf ) ;

        SysFreeString( bstrName ) ;

        SysFreeString( bstrDoc ) ;

        SysFreeString( bstrHelp ) ;

    }

    else

    {

        wsprintf( szBuf, _T("GetDocumentation for TypeInfo FAILED: %s"), (LPTSTR)HRtoString( hr ) ) ;

        StringToFile( hfile, szBuf ) ;

        return FALSE ;

    }

    cVars = pTA->cVars ;

    cFuncs = pTA->cFuncs ;

    lpTypeInfo->ReleaseTypeAttr( pTA ) ;

    int      cParams ;

    int      cParamsOpt ;

    TCHAR    szFunc[128] ;   // Function/Sub name

    LPTSTR   szParams ;

    LPTSTR   lpsz ;

    //

    // Enumerate through all FUNCDESCS

    for ( iIndex = 0 ; iIndex < cFuncs ; iIndex++)

    {

        hr = lpTypeInfo->GetFuncDesc( iIndex, &pFuncDesc ) ;

        if (FAILED(hr))

        {

            wsprintf( szBuf, _T("GetFuncDesc FAILED for function #%u (%s)\r\n"), iIndex, (LPTSTR)HRtoString( hr ) ) ;

            StringToFile( hfile, szBuf ) ;

            continue ;

        }

        hr = lpTypeInfo->GetDocumentation( pFuncDesc->memid, &bstrName, &bstrDoc, &dwHelpID, &bstrHelp ) ;

        if (SUCCEEDED(hr))

        {

#if defined (WIN32) && !defined (OLE2ANSI)

            wsprintf( szBuf, _T("' Function: %ws\r\n"), BSTR_PRT(bstrName) ) ;

#else

            wsprintf( szBuf, _T("' Function: %s\r\n"), BSTR_PRT(bstrName) ) ;

#endif

            StringToFile( hfile, szBuf ) ;

            if (bstrDoc && SysStringLen(bstrDoc))

            {

#if defined (WIN32) && !defined (OLE2ANSI)

                wsprintf( szBuf, _T("' Documentation: %ws\r\n"), (LPOLESTR)bstrDoc ) ;

#else

                wsprintf( szBuf, _T("' Documentation: %s\r\n"), (LPTSTR)bstrDoc ) ;

#endif

                StringToFile( hfile, szBuf ) ;

            }

            if (bstrHelp && SysStringLen(bstrHelp))

            {

#if defined (WIN32) && !defined (OLE2ANSI)

                wsprintf( szBuf, _T("' Help: %ws (Help ID: %#08lX)\r\n"), (LPOLESTR)bstrHelp, (DWORD)dwHelpID ) ;

#else

                wsprintf( szBuf, _T("' Help: %s (Help ID: %#08lX)\r\n"), (LPTSTR)bstrHelp, (DWORD)dwHelpID ) ;

#endif

                StringToFile( hfile, szBuf ) ;

            }

            lstrcpy( szBuf, _T("' \r\n") ) ;

            StringToFile( hfile, szBuf ) ;

            SysFreeString( bstrName ) ;

            SysFreeString( bstrDoc ) ;

            SysFreeString( bstrHelp ) ;

        }

        cParams = pFuncDesc->cParams ;

        cParamsOpt = abs(pFuncDesc->cParamsOpt) ;

        // Get the names of the function and it's parameters into rgbstrNames.

        // cNames gets the number of parameters + 1.

        //

        hr = lpTypeInfo->GetNames( pFuncDesc->memid, rgbstrNames, MAX_NAMES, (UINT FAR*)&cNames );

        if (SUCCEEDED( hr ))

        {

            // rgbstrNames[0] is the name of the function

            if (cNames > 0)

            {

#if defined(WIN32) && !defined(UNICODE)

                wcstombs(szFunc, rgbstrNames[0], wcslen(rgbstrNames[0]) + 1);

#else

                lstrcpy( szFunc, rgbstrNames[0] ) ;

#endif

                SysFreeString( rgbstrNames[0] ) ;

            }

            // Allocate a string buffer that should be able to hold

            // all of our parameter types and names.

            //

            if ((szParams = (LPTSTR) GlobalAllocPtr( GPTR, max(cNames,cParams) * (64) )) == NULL )

            {

                MessageBox( NULL, _T("GlobalAlloc Failed!"), _T("Yikes!"), MB_OK ) ;

                wsprintf( szBuf, _T("GlobalAlloc failed!\r\n") ) ;

                StringToFile( hfile, szBuf ) ;

                return FALSE ;

            }

            // For each parameter get the type and name.

            // The "max(cNames-1,cParams)" should handle the case

            // where a function has optional parameters (i.e. cParamsOpt is

            // non-zero).

            //

            lstrcpy( szParams, _T("(") ) ;

            // For each required parameter

            //

            for ( int n = 0 ; n < cParams - cParamsOpt ; n++ )

            {

                if (n+1 < cNames)

                {

#if defined(WIN32) && !defined(UNICODE)

                    lpsz = new char [wcslen(rgbstrNames[n+1]) + 1];

                    wcstombs(lpsz, rgbstrNames[n+1], wcslen(rgbstrNames[n+1]) + 1);

#else

                    lpsz = rgbstrNames[n+1] ;

#endif

                }

                else

                    lpsz = NULL ;

                BuildParam( szParams+lstrlen(szParams),

                            &pFuncDesc->lprgelemdescParam[n], lpsz , FALSE ) ;

#if defined(WIN32) && !defined(UNICODE)

                delete [] lpsz;

#endif

                if (n+1 < cNames)

                    SysFreeString( rgbstrNames[n+1] ) ;

                // If it's the last one then no comma

                if (n + 1 != max(cNames-1,cParams))

                    lstrcat( szParams, _T(", ") ) ;

            }

            // For each optional parameter

            //

            for (n = cParams - cParamsOpt ; n < cParams ; n++)

            {

                if (n+1 < cNames)

                {

#if defined(WIN32) && !defined(UNICODE)

                    lpsz = new char [wcslen(rgbstrNames[n+1]) + 1];

                    wcstombs(lpsz, rgbstrNames[n+1], wcslen(rgbstrNames[n+1]) + 1);

#else

                    lpsz = rgbstrNames[n+1] ;

#endif

                }

                else

                    lpsz = NULL ;

                BuildParam( szParams+lstrlen(szParams),

                            &pFuncDesc->lprgelemdescParam[n], lpsz , FALSE ) ;

#if defined(WIN32) && !defined(UNICODE)

                delete [] lpsz;

#endif

                if (n+1 < cNames)

                    SysFreeString( rgbstrNames[n+1] ) ;

                // If it's the last one then no comma

                if (n + 1 != max(cNames-1,cParams))

                    lstrcat( szParams,  _T(", ") ) ;

            }

            lstrcat( szParams , _T(")")  );

            // Is it a function or sub?

            //

            if (pFuncDesc->elemdescFunc.tdesc.vt == VT_EMPTY ||

                pFuncDesc->elemdescFunc.tdesc.vt == VT_NULL ||

                pFuncDesc->elemdescFunc.tdesc.vt == VT_VOID)

            {

                // Declare Sub <subname>(<arglist>)

                wsprintf( szBuf, _T("Declare Sub %s "), (LPTSTR)szFunc ) ;

                StringToFile( hfile, szBuf) ;

                StringToFile( hfile, szParams) ;

                StringToFile( hfile, _T("\r\n\r\n") ) ;

            }

            else

            {

                // Declare Function <funcname>(<arglist>) As <returntype>

                wsprintf( szBuf, _T("Declare Function %s "), (LPTSTR)szFunc ) ;

                StringToFile( hfile, szBuf) ;

                StringToFile( hfile, szParams) ;

                wsprintf( szBuf, _T(" As %s\r\n\r\n"), (LPTSTR)VTtoString2( pFuncDesc->elemdescFunc.tdesc.vt ) ) ;

                StringToFile( hfile, szBuf) ;

            }

            GlobalFreePtr( szParams ) ;

        }

        else

        {

            wsprintf( szBuf, _T("GetNames (%lu) FAILED: %s"), pFuncDesc->memid, (LPTSTR)HRtoString( hr ) ) ;

            StringToFile( hfile, szBuf ) ;

        }

        lpTypeInfo->ReleaseFuncDesc( pFuncDesc ) ;

    }

    // '

    // ' <varname>

    // ' Documentation: <docstring>

    // ' Help for this property can be found in <helpfile>

    // ' The help ID for this property is <helpid>

    // Dim <varname> As <vartype>

    // '

    // ' <varname>

    // ' Documentation: <docstring>

    // ' Help for this property can be found in <helpfile>

    // ' The help ID for this property is <helpid>

    // Const <varname> As <vartype> = <value>

    LPVARDESC pVarDesc ;

    for (iIndex = 0 ; iIndex < cVars ; iIndex++)

    {

        hr = lpTypeInfo->GetVarDesc( iIndex, &pVarDesc ) ;

        if (FAILED(hr))

        {

            wsprintf( szBuf, _T("GetVarDesc FAILED for variable #%u (%s)\r\n"), iIndex, (LPTSTR)HRtoString( hr ) ) ;

            StringToFile( hfile, szBuf ) ;

            continue ;

        }

        else

        {

            hr = lpTypeInfo->GetDocumentation( pVarDesc->memid, &bstrName, &bstrDoc, &dwHelpID, &bstrHelp ) ;

            if (SUCCEEDED(hr))

            {

#if defined (WIN32) && !defined (OLE2ANSI)

                wsprintf( szBuf,     _T("' Variable/Constant: %ws\r\n"), BSTR_PRT(bstrName) ) ;

#else

                wsprintf( szBuf,     _T("' Variable/Constant: %s\r\n"), BSTR_PRT(bstrName) ) ;

#endif

                StringToFile( hfile, szBuf ) ;

                if (bstrDoc && SysStringLen(bstrDoc))

                {

#if defined (WIN32) && !defined (OLE2ANSI)

                    wsprintf( szBuf, _T("' Documentation: %ws\r\n"), (LPOLESTR)bstrDoc ) ;

#else

                    wsprintf( szBuf, _T("' Documentation: %s\r\n"), (LPTSTR)bstrDoc ) ;

#endif

                    StringToFile( hfile, szBuf ) ;

                }

                if (bstrHelp && SysStringLen(bstrHelp))

                {

#if defined (WIN32) && !defined (OLE2ANSI)

                    wsprintf( szBuf, _T("' Help: %ws (Help ID: %#08lX)\r\n"), (LPOLESTR)bstrHelp, (DWORD)dwHelpID ) ;

#else

                    wsprintf( szBuf, _T("' Help: %s (Help ID: %#08lX)\r\n"), (LPTSTR)bstrHelp, (DWORD)dwHelpID ) ;

#endif

                    StringToFile( hfile, szBuf ) ;

                }

                lstrcpy( szBuf, _T("' \r\n") ) ;

                StringToFile( hfile, szBuf ) ;

                SysFreeString( bstrName ) ;

                SysFreeString( bstrDoc ) ;

                SysFreeString( bstrHelp ) ;

            }

            hr = lpTypeInfo->GetNames( pVarDesc->memid, rgbstrNames, 1, (UINT FAR*)&cNames );

            if (SUCCEEDED( hr ))

            {

                if (pVarDesc->varkind == VAR_CONST)

                {

                    // Const constname [As type] = expression

#if defined (WIN32) && !defined (OLE2ANSI)

                    wsprintf( szBuf, _T("Const %ws As %s = "),

                                        (LPOLESTR)rgbstrNames[0],

                                        (LPTSTR)TYPEDESCtoString( &pVarDesc->elemdescVar.tdesc )

                                     ) ;

#else

                    wsprintf( szBuf, _T("Const %s As %s = "),

                                        (LPTSTR)rgbstrNames[0],

                                        (LPTSTR)TYPEDESCtoString( &pVarDesc->elemdescVar.tdesc )

                                     ) ;

#endif

                    VARIANT varValue ;

                    VariantInit( &varValue ) ;

                    hr = VariantChangeType( &varValue, pVarDesc->lpvarValue, 0, VT_BSTR ) ;

                    if (FAILED(hr))

                        lstrcat( szBuf, (LPTSTR)HRtoString( hr ) ) ;

                    else

                    {

#if defined (WIN32) && !defined (UNICODE)

                        wcstombs(&(szBuf[strlen(szBuf)+1]), varValue.bstrVal, wcslen(varValue.bstrVal)+1);

#else

                        lstrcat( szBuf, varValue.bstrVal ) ;

#endif

                        SysFreeString( varValue.bstrVal ) ;

                    }

                }

                else

                {

                    // Dim varname[([subscripts])][As type]

#if defined (WIN32) && !defined (OLE2ANSI)

                    wsprintf( szBuf, _T("Dim %ws "), (LPOLESTR)(rgbstrNames[0] ? rgbstrNames[0]: OLESTR("(name less)")) ) ;

#else

                    wsprintf( szBuf, _T("Dim %s "), (LPTSTR)(rgbstrNames[0] ? rgbstrNames[0]: _T("(name less)")) ) ;

#endif

                    if ((pVarDesc->elemdescVar.tdesc.vt & 0x0FFF) == VT_PTR &&

                        (pVarDesc->elemdescVar.tdesc.lptdesc->vt & 0x0FFF) == VT_SAFEARRAY)

                    {

                        lstrcat( szBuf, _T("() As ") ) ;

                        lstrcat( szBuf, VTtoString2( pVarDesc->elemdescVar.tdesc.vt ) ) ;

                    }

                    else

                    {

                        lstrcat( szBuf, _T("As ") ) ;

                        lstrcat( szBuf, TYPEDESCtoString( &pVarDesc->elemdescVar.tdesc ) ) ;

                    }

                }

                SysFreeString( rgbstrNames[0] ) ;

                lstrcat( szBuf, _T("\r\n\r\n") ) ;

                StringToFile( hfile, szBuf ) ;

            }

            else

            {

                wsprintf( szBuf, _T("GetNames (%lu) FAILED: %s\r\n"), pVarDesc->memid, (LPTSTR)HRtoString( hr ) ) ;

                StringToFile( hfile, szBuf ) ;

            }

            lpTypeInfo->ReleaseVarDesc( pVarDesc ) ;

        }

    }

    return TRUE ;

}

static LPTSTR BuildParam( LPTSTR sz, LPELEMDESC lpelemdesc, LPTSTR lpszName, BOOL fOptional )

{

    // [Optional][ByVal|ByRef][ParamArray] varname [()] As type

    if ((lpelemdesc->tdesc.vt & 0x0FFF) == VT_PTR &&

        (lpelemdesc->tdesc.lptdesc->vt & 0x0FFF) == VT_SAFEARRAY)

    {

        lstrcat( sz, _T("ParamArray ") ) ;

    }

    else

    {

        if (fOptional)

            lstrcpy( sz, _T("Optional ") ) ;

        if ((lpelemdesc->tdesc.vt & 0x0FFF) == VT_PTR)

            lstrcat( sz, _T("ByRef ") ) ;

        else

            lstrcat( sz, _T("ByVal ") ) ;

    }

    if (lpszName != NULL)

        lstrcat( sz, lpszName ) ;

    if (lpszName != NULL)

        lstrcat( sz, _T(" As ") ) ;

    else

        lstrcat( sz, _T(" ") ) ;

    if ((lpelemdesc->tdesc.vt & 0x0FFF) == VT_PTR)

        lstrcat( sz, _T("Variant") ) ;

    else

    {

        lstrcat( sz, TYPEDESCtoString( &lpelemdesc->tdesc ) ) ;

    }

    return sz ;

}


TOFILE_A.CPP  (DEFO2V Sample)

// ansiwrap.cpp

//

// Creates ANSI versions of all modules.  Any exported function get's "A"

// appended.

//

//

#ifdef UNICODE

#undef UNICODE

#endif

#ifdef _UNICODE

#undef _UNICODE

#endif

#include "precompa.h"

#include "tofile.cpp"


UTIL.H  (DEFO2V Sample)

// util.h

//

// Header file for utiltiy functions used by DEFO2V

//

// Copyright (c) 1993 Microsoft Corporation, All Rights Reserved.

//

// Charlie Kindel, Program Manager

// Microsoft Vertical Developer Relations

// August 6, 1993

//

// InterNet   :  ckindel@microsoft.com

// CompuServe :  >INTERNET:ckindel@microsoft.com

//

// Revisions:

//  August 6, 1993  cek     First implementation.

//

#ifndef _UTIL_H_

#define _UTIL_H_

#if defined(WIN32) && !defined(_UNICODE)

    #define ReallyCreateFont ReallyCreateFontA

    #define GetTextMetricsCorrectly GetTextMetricsCorrectlyA

    #define ColumnTextOut ColumnTextOutA

    #define HRtoString HRtoStringA

    #define VTtoString VTtoStringA

    #define VTtoString2 VTtoString2A

    #define TYPEDESCtoString TYPEDESCtoStringA

    #define fnEnumReallyEx fnEnumReallyExA

    #define DlgCenter  DlgCenterA

#endif

/// Utilities

#define RCF_NORMAL      0x0000

#define RCF_ITALIC      0x0001

#define RCF_UNDERLINE   0x0002

#define RCF_STRIKEOUT   0x0004

#define RCF_BOLD        0x0008

#define RCF_NODEFAULT   0x0010

#define RCF_TRUETYPEONLY 0x0011

HFONT WINAPI ReallyCreateFont( HDC hDC, LPTSTR lpszFace, LPTSTR lpszStyle, UINT nPointSize, UINT uiFlags ) ;

void WINAPI DlgCenter( HWND hwndCenter, HWND hwndWithin, BOOL fClient ) ;

int WINAPI GetTextMetricsCorrectly( HDC hDC, LPTEXTMETRIC lpTM ) ;

typedef struct FAR tagCOLUMNSTRUCT

{

   int   nLeft ;       // starting x position of the column

   int   nRight ;      // ending x position of the column

   UINT  uiFlags ;      // format flags

} COLUMNSTRUCT, *PCOLUMNSTRUCT, FAR *LPCOLUMNSTRUCT ;

void WINAPI ColumnTextOut( HDC hdc, int nX, int nY, LPTSTR lpszIN, int cColumns, LPCOLUMNSTRUCT rgColumns ) ;

LPTSTR HRtoString( HRESULT hr ) ;

LPTSTR VTtoString( VARTYPE vt ) ;

LPTSTR VTtoString2( VARTYPE vt ) ;

LPTSTR TYPEDESCtoString( TYPEDESC FAR* lptdesc ) ;

#endif


UTIL.CPP  (DEFO2V Sample)

// utixl.cpp

//

// Implementation file for utility functions.

//

// Copyright (c) 1993 Microsoft Corporation, All Rights Reserved.

//

// Charlie Kindel, Program Manager

// Microsoft Vertical Developer Relations

// August 7, 1993

//

// InterNet   :  ckindel@microsoft.com

// CompuServe :  >INTERNET:ckindel@microsoft.com

//

// Revisions:

//  August 7, 1993  cek     First implementation.

//

#include "precomp.h"

#include "defo2v.h"

#include "util.h"

#if defined(WIN32) && !defined(_UNICODE)

    #pragma message("Building ANSI version of " __FILE__)

#endif

/////

// Utility functions

//

static TCHAR szBold[]        = _T("Bold") ;

static TCHAR szItalic[]      = _T("Italic") ;

static TCHAR szBoldItalic[]  = _T("Bold Italic") ;

static TCHAR szRegular[]     = _T("Regular") ;

extern "C"

int EXPORT WINAPI

    fnEnumReallyEx( LPENUMLOGFONT lpLogFont,

                LPNEWTEXTMETRIC lpTextMetrics,

                int nFontType,

                LPENUMLOGFONT lpELF ) ;

 /****************************************************************

 *  HFONT WINAPI

 *    ReallyCreateFontEx( HDC hDC, LPTSTR lpszFace,

 *                        LPTSTR lpszStyle, int nPointSize, UINT uiFlags )

 *

 *  Description:

 *

 *    Creates a font based on facename, pointsize, and style.

 *

 *    Uses 3.1 API's to correctly select TT fonts.

 *

 *    HDC   hDC         the target DC (optional)

 *

 *    LPTSTR lpszFace    pointer the facename (required)

 *

 *    LPTSTR lpszStyle   pointer to the style (like "Demibold Italic")

 *                      (optional).

 *

 *    int nPointSize  size in points (required)

 *

 *    UINT  uiFlags      Flags, same as for ReallyCreateFont() except

 *                      RCF_BOLD and RCF_ITALIC are ignored if lpszStyle

 *                      is not NULL.

 *

 *  Comments:

 *

 ****************************************************************/

HFONT WINAPI

   ReallyCreateFont( HDC hDC, LPTSTR lpszFace, LPTSTR lpszStyle, UINT nPointSize, UINT uiFlags )

{

   ENUMLOGFONT  elf ;

   FONTENUMPROC lpfn ;

   HDC          hdcCur ;

   lpfn = (FONTENUMPROC)fnEnumReallyEx ;

   // if the DC wasn't specified then use the display...

   //

   if (!hDC)

   {

      if (!(hdcCur = GetDC( NULL )))

         return FALSE ;

   }

   else

      hdcCur = hDC ;

   if (hdcCur)

   {

      /*

       * EnumFontFamilies takes the family name as the second param.

       * For example the family name might be "Lucida Sans" and the

       * style might be "Demibold Roman".

       *

       * The last parameter is app. defined.  In our case we pass a

       * structure that has a LOGFONT and a TCHAR array as it's members.

       * We put the style in the char array, and when this function

       * returns the LOGFONT has the logfont for the font we want to create.

       */

      if (lpszStyle)

         lstrcpy( (LPTSTR) elf.elfStyle, lpszStyle ) ;

      else

        switch( uiFlags & ~(RCF_NODEFAULT | RCF_STRIKEOUT | RCF_UNDERLINE) )

        {

            case RCF_BOLD:

                lstrcpy( (LPTSTR) elf.elfStyle, szBold ) ;

            break ;

            case RCF_ITALIC:

                lstrcpy( (LPTSTR) elf.elfStyle, szItalic ) ;

            break ;

            case RCF_BOLD | RCF_ITALIC:

                lstrcpy( (LPTSTR) elf.elfStyle, szBold ) ;

                lstrcat( (LPTSTR) elf.elfStyle, _T(" ") ) ;

                lstrcat( (LPTSTR) elf.elfStyle, szItalic ) ;

            break ;

            default:

                lstrcpy( (LPTSTR) elf.elfStyle, szRegular ) ;

                lpszStyle = (LPTSTR) elf.elfStyle ;

            break ;

        }

      if (lpszFace)

#ifndef WIN32

         EnumFontFamilies( hdcCur, lpszFace, lpfn, (LONG)(LPVOID) &elf ) ;

#else

         EnumFontFamilies( hdcCur, lpszFace, lpfn, (LPARAM)(LPTSTR) &elf ) ;

#endif

      if (!lpszFace || lstrcmpi( elf.elfLogFont.lfFaceName, lpszFace))

      {

         if ((uiFlags & RCF_NODEFAULT) == RCF_NODEFAULT)

         {

            if (hdcCur != hDC)

               ReleaseDC( NULL, hdcCur ) ;

            return NULL ;

         }

         else

            GetObject( GetStockObject( ANSI_VAR_FONT ),

                       sizeof( LOGFONT ), (LPTSTR)&elf.elfLogFont ) ;

      }

      // See pages 4-48, 4-49, of Reference Vol. 1 for explaination

      // of why we set lfWidth to 0

      //

      elf.elfLogFont.lfWidth = 0 ;

      // The equation for calculating point size based on font

      // height (a point is 1/72 of an inch) is:

      //

      //

      //    pt = (height * 72) / number of pixels in the Y direction

      //

      // Using GetTextMetrics() you should calculate height as:

      //

      //    height = tm.tmHeight - tm.tmInternalLeading

      //

      // This is because Windows' interpretation of a font height

      // is different from everyone else's.

      //

      //

      elf.elfLogFont.lfHeight = -MulDiv( nPointSize,

                             GetDeviceCaps( hdcCur, LOGPIXELSY),

                             72 )  ;

      elf.elfLogFont.lfStrikeOut = (BYTE)((uiFlags & RCF_STRIKEOUT) == RCF_STRIKEOUT) ;

      elf.elfLogFont.lfUnderline = (BYTE)((uiFlags & RCF_UNDERLINE) == RCF_UNDERLINE) ;

      if (!lpszStyle)

      {

         elf.elfLogFont.lfWeight    = (uiFlags & RCF_BOLD) ? FW_BOLD : FW_NORMAL ;

         elf.elfLogFont.lfItalic    = (BYTE)((uiFlags & RCF_ITALIC) == RCF_ITALIC) ;

      }

   }

   if (hdcCur != hDC)

      ReleaseDC( NULL, hdcCur ) ;

   return CreateFontIndirect( &elf.elfLogFont ) ;

} /* ReallyCreateFontEx()  */

/****************************************************************

 *  int CALLBACK

 *    fnEnumReallyEx( LPLOGFONT lpLogFont,

 *                  LPTEXTMETRIC lpTextMetrics,

 *                  int nFontType, LPLOGFONT lpLF )

 *

 *  Description:

 *

 *    Call back for EnumFonts and ReallySelectFontEx().

 *

 *    DO NOT FORGET TO EXPORT!!!!!!!!!!!!!!!!!!!!!!!!!!!!

 *

 *  Comments:

 *

 ****************************************************************/

extern "C"

int EXPORT WINAPI

fnEnumReallyEx( LPENUMLOGFONT lpELFin,

                LPNEWTEXTMETRIC lpTextMetrics,

                int nFontType,

                LPENUMLOGFONT lpELF )

{

   /* If we are not true type, then we will only be called once,

    * in in this case we need to compare the weight and italic

    * members of the TM struct to some strings.

    */

   if (!(nFontType & TRUETYPE_FONTTYPE))

   {

      lpELF->elfLogFont = lpELFin->elfLogFont ;

      /* Parse szStyle.  It may be something like "Bold Italic" or

       * "Demibold Italic".  Let's be somewhat smart about this.

       *

       * If "Demibold Italic" is passed in then he wants bold and

       * italic.

       *

       * We want to search szStyle for the word "bold".  Got a better

       * search strategy, go ahead and put it here (but tell me about it!).

       *

       * WARNING!!!

       *   The style string is language dependent.

       */

      if (lpELF->elfStyle)

      {

         /*

          * Assume "Regular"

          */

         lpELF->elfLogFont.lfWeight = FW_NORMAL ;

         lpELF->elfLogFont.lfItalic = FALSE ;

         if (!lstrcmpi( (LPTSTR) lpELF->elfStyle, szBold ))

         {

            lpELF->elfLogFont.lfWeight = FW_BOLD ;

            return 0 ;

         }

         if (!lstrcmpi( (LPTSTR) lpELF->elfStyle, szItalic))

         {

            lpELF->elfLogFont.lfItalic = TRUE ;

            return 0 ;

         }

         if (!lstrcmpi( (LPTSTR) lpELF->elfStyle, szBoldItalic ))

         {

            lpELF->elfLogFont.lfWeight = FW_BOLD ;

            lpELF->elfLogFont.lfItalic = TRUE ;

            return 0 ;

         }

      }

      return 0 ;  /* stop the enumeration */

   }

   /* We now know we have a TT font.  For each style in the

    * family passed in, we will get here.

    *

    * If we get an exact match copy it into lpELF and return.

    * Otherwise get as close as possible.

    */

   if (0==lstrcmpi( (LPTSTR) lpELF->elfStyle, (LPTSTR)lpELFin->elfStyle ))

   {

      *lpELF = *lpELFin;

      return 0;

   }

   lpELF->elfLogFont = lpELFin->elfLogFont ;

   return 1 ;

}/* fnEnumReallyEx() */

/*************************************************************************

 *  void WINAPI

 *  DlgCenter( HWND hwndCenter, HWND hwndWithin, BOOL fClient )

 *

 *  Description:

 *

 *    Centers a window within another window.

 *

 *  Type/Parameter

 *          Description

 *

 *    HWND  hwndCenter

 *          Window to center.  This does not have to be a child of

 *          hwndWithin.

 *

 *    HWND  hwndWithin

 *          Window to center the above window within.  Can be NULL.

 *

 *    BOOL  fClient

 *          If TRUE the window is centered within the available client

 *          area.  Otherwise it's centered within the entire window area.

 *

 *  Comments:

 *

 *************************************************************************/

void WINAPI

DlgCenter( HWND hwndCenter, HWND hwndWithin, BOOL fClient )

{

   RECT rcWithin ;

   RECT rcCenter ;

   int   x, y ;

   int   dxCenter, dyCenter ;

   int   dxScreen, dyScreen ;

   dxScreen = GetSystemMetrics( SM_CXSCREEN ) ;

   dyScreen = GetSystemMetrics( SM_CYSCREEN ) ;

   if (!IsWindow(hwndCenter))

      return ;

   if (hwndWithin && !IsWindow(hwndWithin))

      return ;

   if (hwndWithin == NULL)

   {

      rcWithin.left = rcWithin.top = 0 ;

      rcWithin.right = dxScreen ;

      rcWithin.bottom = dyScreen ;

   }

   else

   {

      if (fClient)

      {

         /*

          * First get screen coords of rectangle we're going to be

          * centered within.

          */

         GetClientRect( hwndWithin, (LPRECT)&rcWithin ) ;

         ClientToScreen( hwndWithin, (LPPOINT)&rcWithin.left ) ;

         ClientToScreen( hwndWithin, (LPPOINT)&rcWithin.right ) ;

      }

      else

         GetWindowRect( hwndWithin, (LPRECT)&rcWithin ) ;

   }

   GetWindowRect( hwndCenter, (LPRECT)&rcCenter ) ;

   dxCenter = rcCenter.right - rcCenter.left ;

   dyCenter = rcCenter.bottom - rcCenter.top ;

   /*

    * Now we have both the within and center rects in screen coords.

    *

    * SetWindowPos behaves differently for Non child windows

    * than for child windows.  For popups it's coordinates

    * are relative to the upper left corner of the screen.  For

    * children it's coords are relative to the upper left corner

    * of the client area of the parent.

    */

   x = ((rcWithin.right - rcWithin.left) - dxCenter) / 2 ;

   y = ((rcWithin.bottom - rcWithin.top) - dyCenter) / 2 ;

   if (hwndWithin == GetParent( hwndCenter ) &&

       !(GetWindowLong( hwndCenter, GWL_STYLE ) & WS_CHILD ))

   {

      x += rcWithin.left ;

      y += rcWithin.top ;

      if (x + dxCenter > dxScreen )

         x = dxScreen - dxCenter ;

      if (y + dyCenter > dyScreen )

         y = dyScreen - dyCenter ;

      SetWindowPos( hwndCenter, NULL,

                    max(x,0),

                    max(y,0),

                    0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER ) ;

      return ;

   }

   SetWindowPos( hwndCenter, NULL,

                 max(x,0),

                 max(y,0),

                 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER ) ;

   return ;

}/* DlgCenter() */

// column text out

/****************************************************************

 *  int WINAPI

 *    GetTextMetricsCorrectly( HDC hDC, LPTEXTMETRIC lpTextMetrics )

 *

 *  Description:

 *

 *    This function gets the textmetrics of the font currently

 *    selected into the hDC.  It returns the average char width as

 *    the return value.

 *

 *    This function computes the average character width correctly

 *    by using GetTextExtent() on the string "abc...xzyABC...XYZ"

 *    which works out much better for proportional fonts.

 *

 *    Note that this function returns the same TEXTMETRIC

 *    values that GetTextMetrics() does, it simply has a different

 *    return value.

 *

 *  Comments:

 *

 ****************************************************************/

int WINAPI

   GetTextMetricsCorrectly( HDC hDC, LPTEXTMETRIC lpTM )

{

   int    nAveWidth ;

   TCHAR   rgchAlphabet[52] ;

   int  i ;

   SIZE size ;

   // Get the TM of the current font.  Note that GetTextMetrics

   // gets the incorrect AveCharWidth value for proportional fonts.

   // This is the whole poshort in this exercise.

   //

   if (lpTM)

    GetTextMetrics(hDC, lpTM);

   // If it's not a variable pitch font GetTextMetrics was correct

   // so just return.

   //

   if (lpTM && !(lpTM->tmPitchAndFamily & FIXED_PITCH))

      return lpTM->tmAveCharWidth ;

   else

   {

      for ( i = 0 ; i <= 25 ; i++)

         rgchAlphabet[i] = (TCHAR)(i+(int)'a') ;

      for ( i = 0 ; i<=25 ; i++)

         rgchAlphabet[i+25] = (TCHAR)(i+(int)'A') ;

      GetTextExtentPoint( hDC, (LPTSTR)rgchAlphabet, 52, &size ) ;

      nAveWidth = size.cx / 26 ;

      nAveWidth = (nAveWidth + 1) / 2 ;

   }

   // Return the calculated average char width

   //

   return nAveWidth ;

} /* GetTextMetricsCorrectly()  */

/****************************************************************

 *

 *  Description:

 *

 *    The ColumntTextOut function writes a character string at

 *    the specified location, using tabs to identify column breaks.  Each

 *    column is aligned according to the array of COLUMNSTRUCTs.

 *

 *    A COLUMNSTRUCT looks like this:

 *

 *    {

 *       int   nLeft ;       // starting x position of the column

 *       int   nRight ;      // ending x position of the column

 *       UINT  uiFlags ;      // format flags

 *    }

 *

 *    If a column has another column to the left of it, it's nLeft member

 *    is ignored.

 *

 *    uiFlags can be any of the following:

 *

 *          #define DT_LEFT      0x0000

 *          #define DT_CENTER    0x0001

 *          #define DT_RIGHT     0x0002

 *

 *  Comments:

 *

 ****************************************************************/

void WINAPI ColumnTextOut( HDC hdc, int nX, int nY, LPTSTR lpszIN,

                            int cColumns, LPCOLUMNSTRUCT rgColumns )

{

#define ETOFLAGS ETO_CLIPPED

    COLUMNSTRUCT   CS ;              // local copy for speed

    RECT           rc ;              // current cell rect

    int            cIteration = 0 ;  // what column

    LPTSTR          lpNext ;          // next string (current is lpsz)

    int            cch ;             // count of chars in current string

    SIZE           size ;            // extent of current string

    #ifdef WIN32

    LONG          dx ;              // column width

    #else

    int             dx ;

    #endif

    rc.left = nX ;

    rc.top = nY ;

    rc.right = 0 ;

    if (rgColumns == NULL || cColumns <= 1)

    {

        int Tab = 15 ;

        TabbedTextOut( hdc, nX, nY, lpszIN, lstrlen(lpszIN), 1, &Tab, nX ) ;

        return ;

    }

    // For each sub string (bracketed by a tab)

    //

    LPTSTR lpsz = lpszIN ;

    while (*lpsz)

    {

        if (cIteration >= cColumns)

            return ;

        for (cch = 0, lpNext = lpsz ;

             *lpNext != '\t' && *lpNext ;

             lpNext++, cch++)

            ;

        CS = rgColumns[cIteration] ;

        // If it's the leftmost column use

        //

        if (cIteration == 0)

        {

            rc.left = nX + CS.nLeft ;

            rc.right = nX + CS.nRight ;

        }

        else

            rc.right = nX + CS.nRight ;

        GetTextExtentPoint( hdc, lpsz, cch, &size ) ;

        rc.bottom = rc.top + size.cy ;

        // If the width of the column is 0 do nothing

        //

        if ((dx = (rc.right - rc.left)) > 0)

        {

            switch(CS.uiFlags)

            {

                case DT_CENTER:

                    ExtTextOut( hdc, rc.left + ((dx - size.cx) / (int)2),

                    rc.top, ETOFLAGS, &rc, lpsz, cch, NULL ) ;

                break ;

                case DT_RIGHT:

                    // If it's right justified then make the left border 0

                    //

                    //rc.left = nX + rgColumns[0].nLeft ;

                    ExtTextOut( hdc, rc.left + (dx - size.cx),

                    rc.top, ETOFLAGS, &rc, lpsz, cch, NULL ) ;

                break ;

                case DT_LEFT:

                default:

                    ExtTextOut( hdc, rc.left, rc.top, ETOFLAGS, &rc, lpsz, cch, NULL ) ;

                break ;

            }

        }

        rc.left = rc.right ;

        cIteration++ ;

        lpsz = lpNext + 1 ;

    }

} // ColumnTextOut()

LPTSTR HRtoString( HRESULT hr )

{

    static  TCHAR sz[256] ;

    LPTSTR  szErrName ;

    SCODE   sc ;

#define CASE_SCODE(sc)  case sc: szErrName = (LPTSTR)_T(#sc) ; break ;

    sc = GetScode( hr ) ;

    switch (sc) {

        /* SCODE's defined in SCODE.H */

        CASE_SCODE(S_OK)

 // same value as S_OK      CASE_SCODE(S_TRUE)

        CASE_SCODE(S_FALSE)

        CASE_SCODE(E_UNEXPECTED)

        CASE_SCODE(E_NOTIMPL)

        CASE_SCODE(E_OUTOFMEMORY)

        CASE_SCODE(E_INVALIDARG)

        CASE_SCODE(E_NOINTERFACE)

        CASE_SCODE(E_POINTER)

        CASE_SCODE(E_HANDLE)

        CASE_SCODE(E_ABORT)

        CASE_SCODE(E_FAIL)

        CASE_SCODE(E_ACCESSDENIED)

        /* SCODE's defined in DVOBJ.H */

        CASE_SCODE(DATA_E_FORMATETC)

// same as DATA_E_FORMATETC     CASE_SCODE(DV_E_FORMATETC)

        CASE_SCODE(DATA_S_SAMEFORMATETC)

        CASE_SCODE(VIEW_E_DRAW)

//  same as VIEW_E_DRAW         CASE_SCODE(E_DRAW)

        CASE_SCODE(VIEW_S_ALREADY_FROZEN)

        CASE_SCODE(CACHE_E_NOCACHE_UPDATED)

        CASE_SCODE(CACHE_S_FORMATETC_NOTSUPPORTED)

        CASE_SCODE(CACHE_S_SAMECACHE)

        CASE_SCODE(CACHE_S_SOMECACHES_NOTUPDATED)

        /* SCODE's defined in OLE2.H */

        CASE_SCODE(OLE_E_OLEVERB)

        CASE_SCODE(OLE_E_ADVF)

        CASE_SCODE(OLE_E_ENUM_NOMORE)

        CASE_SCODE(OLE_E_ADVISENOTSUPPORTED)

        CASE_SCODE(OLE_E_NOCONNECTION)

        CASE_SCODE(OLE_E_NOTRUNNING)

        CASE_SCODE(OLE_E_NOCACHE)

        CASE_SCODE(OLE_E_BLANK)

        CASE_SCODE(OLE_E_CLASSDIFF)

        CASE_SCODE(OLE_E_CANT_GETMONIKER)

        CASE_SCODE(OLE_E_CANT_BINDTOSOURCE)

        CASE_SCODE(OLE_E_STATIC)

        CASE_SCODE(OLE_E_PROMPTSAVECANCELLED)

        CASE_SCODE(OLE_E_INVALIDRECT)

        CASE_SCODE(OLE_E_WRONGCOMPOBJ)

        CASE_SCODE(OLE_E_INVALIDHWND)

        CASE_SCODE(DV_E_DVTARGETDEVICE)

        CASE_SCODE(DV_E_STGMEDIUM)

        CASE_SCODE(DV_E_STATDATA)

        CASE_SCODE(DV_E_LINDEX)

        CASE_SCODE(DV_E_TYMED)

        CASE_SCODE(DV_E_CLIPFORMAT)

        CASE_SCODE(DV_E_DVASPECT)

        CASE_SCODE(DV_E_DVTARGETDEVICE_SIZE)

        CASE_SCODE(DV_E_NOIVIEWOBJECT)

        CASE_SCODE(OLE_S_USEREG)

        CASE_SCODE(OLE_S_STATIC)

        CASE_SCODE(OLE_S_MAC_CLIPFORMAT)

        CASE_SCODE(CONVERT10_E_OLESTREAM_GET)

        CASE_SCODE(CONVERT10_E_OLESTREAM_PUT)

        CASE_SCODE(CONVERT10_E_OLESTREAM_FMT)

        CASE_SCODE(CONVERT10_E_OLESTREAM_BITMAP_TO_DIB)

        CASE_SCODE(CONVERT10_E_STG_FMT)

        CASE_SCODE(CONVERT10_E_STG_NO_STD_STREAM)

        CASE_SCODE(CONVERT10_E_STG_DIB_TO_BITMAP)

        CASE_SCODE(CONVERT10_S_NO_PRESENTATION)

        CASE_SCODE(CLIPBRD_E_CANT_OPEN)

        CASE_SCODE(CLIPBRD_E_CANT_EMPTY)

        CASE_SCODE(CLIPBRD_E_CANT_SET)

        CASE_SCODE(CLIPBRD_E_BAD_DATA)

        CASE_SCODE(CLIPBRD_E_CANT_CLOSE)

        CASE_SCODE(DRAGDROP_E_NOTREGISTERED)

        CASE_SCODE(DRAGDROP_E_ALREADYREGISTERED)

        CASE_SCODE(DRAGDROP_E_INVALIDHWND)

        CASE_SCODE(DRAGDROP_S_DROP)

        CASE_SCODE(DRAGDROP_S_CANCEL)

        CASE_SCODE(DRAGDROP_S_USEDEFAULTCURSORS)

        CASE_SCODE(OLEOBJ_E_NOVERBS)

        CASE_SCODE(OLEOBJ_S_INVALIDVERB)

        CASE_SCODE(OLEOBJ_S_CANNOT_DOVERB_NOW)

        CASE_SCODE(OLEOBJ_S_INVALIDHWND)

        CASE_SCODE(INPLACE_E_NOTUNDOABLE)

        CASE_SCODE(INPLACE_E_NOTOOLSPACE)

        CASE_SCODE(INPLACE_S_TRUNCATED)

        /* SCODE's defined in STORAGE.H */

        CASE_SCODE(STG_E_INVALIDFUNCTION)

        CASE_SCODE(STG_E_FILENOTFOUND)

        CASE_SCODE(STG_E_PATHNOTFOUND)

        CASE_SCODE(STG_E_TOOMANYOPENFILES)

        CASE_SCODE(STG_E_ACCESSDENIED)

        CASE_SCODE(STG_E_INVALIDHANDLE)

        CASE_SCODE(STG_E_INSUFFICIENTMEMORY)

        CASE_SCODE(STG_E_INVALIDPOINTER)

        CASE_SCODE(STG_E_NOMOREFILES)

        CASE_SCODE(STG_E_DISKISWRITEPROTECTED)

        CASE_SCODE(STG_E_SEEKERROR)

        CASE_SCODE(STG_E_WRITEFAULT)

        CASE_SCODE(STG_E_READFAULT)

        CASE_SCODE(STG_E_LOCKVIOLATION)

        CASE_SCODE(STG_E_FILEALREADYEXISTS)

        CASE_SCODE(STG_E_INVALIDPARAMETER)

        CASE_SCODE(STG_E_MEDIUMFULL)

        CASE_SCODE(STG_E_ABNORMALAPIEXIT)

        CASE_SCODE(STG_E_INVALIDHEADER)

        CASE_SCODE(STG_E_INVALIDNAME)

        CASE_SCODE(STG_E_UNKNOWN)

        CASE_SCODE(STG_E_UNIMPLEMENTEDFUNCTION)

        CASE_SCODE(STG_E_INVALIDFLAG)

        CASE_SCODE(STG_E_INUSE)

        CASE_SCODE(STG_E_NOTCURRENT)

        CASE_SCODE(STG_E_REVERTED)

        CASE_SCODE(STG_E_CANTSAVE)

        CASE_SCODE(STG_E_OLDFORMAT)

        CASE_SCODE(STG_E_OLDDLL)

        CASE_SCODE(STG_E_SHAREREQUIRED)

        CASE_SCODE(STG_S_CONVERTED)

//        CASE_SCODE(STG_S_BUFFEROVERFLOW)

//        CASE_SCODE(STG_S_TRYOVERWRITE)

        /* SCODE's defined in COMPOBJ.H */

        CASE_SCODE(CO_E_NOTINITIALIZED)

        CASE_SCODE(CO_E_ALREADYINITIALIZED)

        CASE_SCODE(CO_E_CANTDETERMINECLASS)

        CASE_SCODE(CO_E_CLASSSTRING)

        CASE_SCODE(CO_E_IIDSTRING)

        CASE_SCODE(CO_E_APPNOTFOUND)

        CASE_SCODE(CO_E_APPSINGLEUSE)

        CASE_SCODE(CO_E_ERRORINAPP)

        CASE_SCODE(CO_E_DLLNOTFOUND)

        CASE_SCODE(CO_E_ERRORINDLL)

        CASE_SCODE(CO_E_WRONGOSFORAPP)

        CASE_SCODE(CO_E_OBJNOTREG)

        CASE_SCODE(CO_E_OBJISREG)

        CASE_SCODE(CO_E_OBJNOTCONNECTED)

        CASE_SCODE(CO_E_APPDIDNTREG)

        CASE_SCODE(CLASS_E_NOAGGREGATION)

        CASE_SCODE(REGDB_E_READREGDB)

        CASE_SCODE(REGDB_E_WRITEREGDB)

        CASE_SCODE(REGDB_E_KEYMISSING)

        CASE_SCODE(REGDB_E_INVALIDVALUE)

        CASE_SCODE(REGDB_E_CLASSNOTREG)

        CASE_SCODE(REGDB_E_IIDNOTREG)

#if WIN32!=300

//        CASE_SCODE(RPC_E_FIRST)

        CASE_SCODE(RPC_E_CALL_REJECTED)

        CASE_SCODE(RPC_E_CALL_CANCELED)

        CASE_SCODE(RPC_E_CANTPOST_INSENDCALL)

        CASE_SCODE(RPC_E_CANTCALLOUT_INASYNCCALL)

        CASE_SCODE(RPC_E_CANTCALLOUT_INEXTERNALCALL)

        CASE_SCODE(RPC_E_CONNECTION_TERMINATED)

        CASE_SCODE(RPC_E_SERVER_DIED)

        CASE_SCODE(RPC_E_CLIENT_DIED)

        CASE_SCODE(RPC_E_INVALID_DATAPACKET)

        CASE_SCODE(RPC_E_CANTTRANSMIT_CALL)

        CASE_SCODE(RPC_E_CLIENT_CANTMARSHAL_DATA)

        CASE_SCODE(RPC_E_CLIENT_CANTUNMARSHAL_DATA)

        CASE_SCODE(RPC_E_SERVER_CANTMARSHAL_DATA)

        CASE_SCODE(RPC_E_SERVER_CANTUNMARSHAL_DATA)

        CASE_SCODE(RPC_E_INVALID_DATA)

        CASE_SCODE(RPC_E_INVALID_PARAMETER)

        CASE_SCODE(RPC_E_UNEXPECTED)

#endif

        /* SCODE's defined in MONIKER.H */

        CASE_SCODE(MK_E_CONNECTMANUALLY)

        CASE_SCODE(MK_E_EXCEEDEDDEADLINE)

        CASE_SCODE(MK_E_NEEDGENERIC)

        CASE_SCODE(MK_E_UNAVAILABLE)

        CASE_SCODE(MK_E_SYNTAX)

        CASE_SCODE(MK_E_NOOBJECT)

        CASE_SCODE(MK_E_INVALIDEXTENSION)

        CASE_SCODE(MK_E_INTERMEDIATEINTERFACENOTSUPPORTED)

        CASE_SCODE(MK_E_NOTBINDABLE)

        CASE_SCODE(MK_E_NOTBOUND)

        CASE_SCODE(MK_E_CANTOPENFILE)

        CASE_SCODE(MK_E_MUSTBOTHERUSER)

        CASE_SCODE(MK_E_NOINVERSE)

        CASE_SCODE(MK_E_NOSTORAGE)

        CASE_SCODE(MK_S_REDUCED_TO_SELF)

        CASE_SCODE(MK_S_ME)

        CASE_SCODE(MK_S_HIM)

        CASE_SCODE(MK_S_US)

        CASE_SCODE(MK_S_MONIKERALREADYREGISTERED)

/* SCODE's defined in DISPATCH.H */

        CASE_SCODE(DISP_E_UNKNOWNINTERFACE)

        CASE_SCODE(DISP_E_MEMBERNOTFOUND)

        CASE_SCODE(DISP_E_PARAMNOTFOUND)

        CASE_SCODE(DISP_E_TYPEMISMATCH)

        CASE_SCODE(DISP_E_UNKNOWNNAME)

        CASE_SCODE(DISP_E_NONAMEDARGS)

        CASE_SCODE(DISP_E_BADVARTYPE)

        CASE_SCODE(DISP_E_EXCEPTION)

        CASE_SCODE(DISP_E_OVERFLOW)

        CASE_SCODE(DISP_E_BADINDEX)

        CASE_SCODE(DISP_E_UNKNOWNLCID)

        CASE_SCODE(DISP_E_ARRAYISLOCKED)

        CASE_SCODE(DISP_E_BADPARAMCOUNT)

#if WIN32!=300

        CASE_SCODE(DISP_E_PARAMNOTOPTIONAL)

        CASE_SCODE(DISP_E_BADCALLEE)

        CASE_SCODE(DISP_E_NOTACOLLECTION)

        CASE_SCODE(TYPE_E_BADMODULEKIND)

#endif

        CASE_SCODE(TYPE_E_IOERROR)

//        CASE_SCODE(TYPE_E_COMPILEERROR)

        CASE_SCODE(TYPE_E_CANTCREATETMPFILE)

//        CASE_SCODE(TYPE_E_ILLEGALINDEX)

//        CASE_SCODE(TYPE_E_IDNOTFOUND)

        CASE_SCODE(TYPE_E_BUFFERTOOSMALL)

//        CASE_SCODE(TYPE_E_READONLY)

        CASE_SCODE(TYPE_E_INVDATAREAD)

        CASE_SCODE(TYPE_E_UNSUPFORMAT)

//        CASE_SCODE(TYPE_E_ALREADYCONTAINSNAME)

//        CASE_SCODE(TYPE_E_NOMATCHINGARITY)

        CASE_SCODE(TYPE_E_REGISTRYACCESS)

        CASE_SCODE(TYPE_E_LIBNOTREGISTERED)

//        CASE_SCODE(TYPE_E_DUPLICATEDEFINITION)

//        CASE_SCODE(TYPE_E_DESTNOTKNOWN)

        CASE_SCODE(TYPE_E_UNDEFINEDTYPE)

        CASE_SCODE(TYPE_E_QUALIFIEDNAMEDISALLOWED)

        CASE_SCODE(TYPE_E_INVALIDSTATE)

        CASE_SCODE(TYPE_E_WRONGTYPEKIND)

        CASE_SCODE(TYPE_E_ELEMENTNOTFOUND)

        CASE_SCODE(TYPE_E_AMBIGUOUSNAME)

//        CASE_SCODE(TYPE_E_INVOKEFUNCTIONMISMATCH)

        CASE_SCODE(TYPE_E_DLLFUNCTIONNOTFOUND)

//        CASE_SCODE(TYPE_E_WRONGPLATFORM)

//        CASE_SCODE(TYPE_E_ALREADYBEINGLAIDOUT)

        CASE_SCODE(TYPE_E_CANTLOADLIBRARY)

        default:

            szErrName = _T("UNKNOWN SCODE") ;

    }

    wsprintf( sz, _T("%s (0x%lx)"), (LPTSTR)szErrName, sc);

    return (LPTSTR)sz ;

}

static TCHAR * g_rgszVT[] =

{

    _T("Void"),             //VT_EMPTY           = 0,   /* [V]   [P]  nothing                     */

    _T("Null"),             //VT_NULL            = 1,   /* [V]        SQL style Null              */

    _T("Integer"),          //VT_I2              = 2,   /* [V][T][P]  2 byte signed int           */

    _T("Long"),             //VT_I4              = 3,   /* [V][T][P]  4 byte signed int           */

    _T("Single"),           //VT_R4              = 4,   /* [V][T][P]  4 byte real                 */

    _T("Double"),           //VT_R8              = 5,   /* [V][T][P]  8 byte real                 */

    _T("Currency"),         //VT_CY              = 6,   /* [V][T][P]  currency                    */

    _T("Date"),             //VT_DATE            = 7,   /* [V][T][P]  date                        */

    _T("String"),           //VT_BSTR            = 8,   /* [V][T][P]  binary string               */

    _T("Object"),           //VT_DISPATCH        = 9,   /* [V][T]     IDispatch FAR*              */

    _T("SCODE"),            //VT_ERROR           = 10,  /* [V][T]     SCODE                       */

    _T("Boolean"),          //VT_BOOL            = 11,  /* [V][T][P]  True=-1, False=0            */

    _T("Variant"),          //VT_VARIANT         = 12,  /* [V][T][P]  VARIANT FAR*                */

    _T("pIUnknown"),        //VT_UNKNOWN         = 13,  /* [V][T]     IUnknown FAR*               */

    _T("Unicode"),          //VT_WBSTR           = 14,  /* [V][T]     wide binary string          */

    _T(""),                 //                   = 15,

    _T("BYTE"),             //VT_I1              = 16,  /*    [T]     signed char                 */

    _T("char"),             //VT_UI1             = 17,  /*    [T]     unsigned char               */

    _T("USHORT"),           //VT_UI2             = 18,  /*    [T]     unsigned short              */

    _T("ULONG"),            //VT_UI4             = 19,  /*    [T]     unsigned short              */

    _T("int64"),            //VT_I8              = 20,  /*    [T][P]  signed 64-bit int           */

    _T("uint64"),           //VT_UI8             = 21,  /*    [T]     unsigned 64-bit int         */

    _T("int"),              //VT_INT             = 22,  /*    [T]     signed machine int          */

    _T("UINT"),             //VT_UINT            = 23,  /*    [T]     unsigned machine int        */

    _T("VOID"),             //VT_VOID            = 24,  /*    [T]     C style void                */

    _T("HRESULT"),          //VT_HRESULT         = 25,  /*    [T]                                 */

    _T("PTR"),              //VT_PTR             = 26,  /*    [T]     pointer type                */

    _T("SAFEARRAY"),        //VT_SAFEARRAY       = 27,  /*    [T]     (use VT_ARRAY in VARIANT)   */

    _T("CARRAY"),           //VT_CARRAY          = 28,  /*    [T]     C style array               */

    _T("USERDEFINED"),      //VT_USERDEFINED     = 29,  /*    [T]     user defined type         */

    _T("LPSTR"),            //VT_LPSTR           = 30,  /*    [T][P]  null terminated string      */

    _T("LPWSTR"),           //VT_LPWSTR          = 31,  /*    [T][P]  wide null terminated string */

    _T(""),                 //                   = 32,

    _T(""),                 //                   = 33,

    _T(""),                 //                   = 34,

    _T(""),                 //                   = 35,

    _T(""),                 //                   = 36,

    _T(""),                 //                   = 37,

    _T(""),                 //                   = 38,

    _T(""),                 //                   = 39,

    _T(""),                 //                   = 40,

    _T(""),                 //                   = 41,

    _T(""),                 //                   = 42,

    _T(""),                 //                   = 43,

    _T(""),                 //                   = 44,

    _T(""),                 //                   = 45,

    _T(""),                 //                   = 46,

    _T(""),                 //                   = 47,

    _T(""),                 //                   = 48,

    _T(""),                 //                   = 49,

    _T(""),                 //                   = 50,

    _T(""),                 //                   = 51,

    _T(""),                 //                   = 52,

    _T(""),                 //                   = 53,

    _T(""),                 //                   = 54,

    _T(""),                 //                   = 55,

    _T(""),                 //                   = 56,

    _T(""),                 //                   = 57,

    _T(""),                 //                   = 58,

    _T(""),                 //                   = 59,

    _T(""),                 //                   = 60,

    _T(""),                 //                   = 61,

    _T(""),                 //                   = 62,

    _T(""),                 //                   = 63,

    _T("FILETIME"),         //VT_FILETIME        = 64,  /*       [P]  FILETIME                    */

    _T("BLOB"),             //VT_BLOB            = 65,  /*       [P]  Length prefixed bytes       */

    _T("STREAM"),           //VT_STREAM          = 66,  /*       [P]  Name of the stream follows  */

    _T("STORAGE"),          //VT_STORAGE         = 67,  /*       [P]  Name of the storage follows */

    _T("STREAMED_OBJECT"),  //VT_STREAMED_OBJECT = 68,  /*       [P]  Stream contains an object   */

    _T("STORED_OBJECT"),    //VT_STORED_OBJECT   = 69,  /*       [P]  Storage contains an object  */

    _T("BLOB_OBJECT"),      //VT_BLOB_OBJECT     = 70,  /*       [P]  Blob contains an object     */

    _T("CF"),               //VT_CF              = 71,  /*       [P]  Clipboard format            */

    _T("CLSID"),            //VT_CLSID           = 72   /*       [P]  A Class ID                  */

};

LPTSTR VTtoString( VARTYPE vt )

{

    static TCHAR szBuf[64];

    if (vt <= VT_CLSID)

        return (LPTSTR)g_rgszVT[vt] ;

    if (vt & VT_VECTOR)

    {

        vt &= ~VT_VECTOR ;

        if (vt <= VT_CLSID)

            wsprintf( szBuf, _T("VECTOR of %s"), (LPTSTR)g_rgszVT[vt] ) ;

        else

            wsprintf( szBuf, _T("<Unknown %08lX>"), vt & VT_VECTOR ) ;

        return (LPTSTR)szBuf ;

    }

    if (vt & VT_ARRAY)

    {

        vt &= ~VT_ARRAY ;

        if (vt <= VT_CLSID)

            wsprintf( szBuf, _T("Array of %s"), (LPTSTR)g_rgszVT[vt] ) ;

        else

            wsprintf( szBuf, _T("<Unknown %08lX>"), vt & VT_ARRAY ) ;

        return (LPTSTR)szBuf ;

    }

    if (vt & VT_BYREF)

    {

        vt &= ~VT_BYREF ;

        if (vt <= VT_CLSID)

            wsprintf( szBuf, _T("%s BYREF "), (LPTSTR)g_rgszVT[vt] ) ;

        else

            wsprintf( szBuf, _T("<Unknown %08lX>"), vt & VT_BYREF ) ;

        return (LPTSTR)szBuf ;

    }

    if (vt & VT_RESERVED)

    {

        vt &= ~VT_RESERVED ;

        if (vt <= VT_CLSID)

            wsprintf( szBuf, _T("RESERVED (%s)"), (LPTSTR)g_rgszVT[vt] ) ;

        else

            wsprintf( szBuf, _T("<Unknown %08lX>"), vt & VT_RESERVED ) ;

        return (LPTSTR)szBuf ;

    }

    wsprintf( szBuf, _T("<Unknown %08lX>"), vt ) ;

    return (LPTSTR)szBuf ;

}

LPTSTR VTtoString2( VARTYPE vt )

{

    static TCHAR szBuf[64];

    vt &= ~0xF000 ;

    if (vt <= VT_CLSID)

        return (LPTSTR)g_rgszVT[vt] ;

    wsprintf( szBuf, _T("<Unknown %08lX>"), vt ) ;

    return (LPTSTR)szBuf ;

}

LPTSTR TYPEDESCtoString( TYPEDESC FAR* lptdesc )

{

    static TCHAR sz[64] ;

    lstrcpy( sz, VTtoString( lptdesc->vt ) ) ;

    if ((lptdesc->vt & 0x0FFF) == VT_PTR)

    {

        // lptdesc points to a TYPEDESC that specifies the thing pointed to

        lstrcat( sz, _T(" to ") ) ;

        lstrcat( sz, VTtoString( lptdesc->lptdesc->vt ) ) ;

        if ((lptdesc->lptdesc->vt & 0x0FFF) == VT_CARRAY)

        {

            lstrcat( sz,  _T(" of ") ) ;

            lstrcat( sz,  VTtoString( lptdesc->lptdesc->lpadesc->tdescElem.vt ) ) ;

            TCHAR szNum[16] ;

            wsprintf( szNum, _T("[%u]"), lptdesc->lptdesc->lpadesc->cDims ) ;

            lstrcat( sz, szNum ) ;

        }

    }

    if ((lptdesc->vt & 0x0FFF) == VT_CARRAY)

    {

        lstrcat( sz,  _T(" of ") ) ;

        lstrcat( sz,  VTtoString( lptdesc->lpadesc->tdescElem.vt ) ) ;

        TCHAR szNum[16] ;

        wsprintf( szNum, _T("[%u]"), lptdesc->lpadesc->cDims ) ;

        lstrcat( sz, szNum ) ;

    }

    return sz ;

}

int _lwriteT( int handle, TCHAR *taBuf, unsigned int count )

{

#ifdef _UNICODE

    char   achBuf[256];

    wcstombs( achBuf, taBuf, 256 );

    return (_lwrite( handle,  achBuf, count ));

#else

    return (_lwrite( handle, taBuf, count ));

#endif

}

HFILE WINAPI OpenFileT( LPTSTR tszFileName, LPOFSTRUCT lpReOpenBuf, UINT uStyle )

{

#ifdef _UNICODE

    char   achName[MAX_PATH];

    wcstombs( achName, tszFileName, MAX_PATH );

    return OpenFile( achName, lpReOpenBuf, uStyle );

#else

    return OpenFile( tszFileName, lpReOpenBuf, uStyle );

#endif

}


UTIL_A.CPP  (DEFO2V Sample)

// ansiwrap.cpp

//

// Creates ANSI versions of all modules.  Any exported function get's "A"

// appended.

//

//

#ifdef UNICODE

#undef UNICODE

#endif

#ifdef _UNICODE

#undef _UNICODE

#endif

#include "precompa.h"

#include "util.cpp"


DFVIEW

This sample creates a tool for viewing OLE's implementation of structured storage. For information on compiling and building the program, see MAKEFILE (DFVIEW Sample).


MAKEFILE  (DFVIEW Sample)

#+---------------------------------------------------------------------------

#

#  Microsoft Windows

#  Copyright (C) Microsoft Corporation, 1994.

#

#  File:        makefile

#

#----------------------------------------------------------------------------

!include <$(MSTOOLS)\samples\ole\include\olesampl.mak>

#

#       Makefile for OLE Sample DFView

#

#       builds DFView.EXE

#

OLEFLAGS = -I ..\idl -I ..\winhlprs

LINK = $(link)

LINKFLAGS = $(linkdebug) $(guilflags)

RCFLAGS = -DWIN32

OBJS = winmain.obj mwclass.obj strmvwr.obj about.obj bitmaps.obj message.obj

LIBS = $(olelibsmt) ..\winhlprs\winhlprs.lib

all: DFView.exe

clean:

    -del *.obj

    -del dfv.res

    -del DFView.map

    -del DFView.exe

winmain.obj: winmain.cxx        \

        dfv.h                   \

        mwclass.h               \

        message.h               \

        ..\winhlprs\cwindow.h

    $(cc) $(cvars) $(cflags) $(UFLAGS) $(cdebug) $(OLEFLAGS) $*.cxx

mwclass.obj: mwclass.cxx        \

        dfv.h                   \

        mwclass.h               \

        about.h                 \

        strmvwr.h               \

        bitmaps.h               \

        message.h               \

        ..\winhlprs\cdialog.h   \

        ..\winhlprs\cwindow.h

    $(cc) $(cvars) $(cflags) $(UFLAGS) $(cdebug) $(OLEFLAGS) $*.cxx

strmvwr.obj: strmvwr.cxx        \

        dfv.h                   \

        strmvwr.h               \

        message.h               \

        mwclass.h               \

        ..\winhlprs\cwindow.h

    $(cc) $(cvars) $(cflags) $(UFLAGS) $(cdebug) $(OLEFLAGS) $*.cxx

about.obj: about.cxx            \

        about.h                 \

        ..\winhlprs\cdialog.h

    $(cc) $(cvars) $(cflags) $(UFLAGS) $(cdebug) $(OLEFLAGS) $*.cxx

bitmaps.obj: bitmaps.cxx        \

        bitmaps.h

    $(cc) $(cvars) $(cflags) $(UFLAGS) $(cdebug) $(OLEFLAGS) $*.cxx

message.obj: message.cxx        \

        message.h

    $(cc) $(cvars) $(cflags) $(UFLAGS) $(cdebug) $(OLEFLAGS) $*.cxx

dfv.res: dfv.rc dfv.ico dfv.dlg document.bmp folder.bmp dfv.h

    rc $(RCFLAGS) -r -fo$@ $*.rc

DFView.exe: $(OBJS) dfv.res

    $(LINK) @<<

        $(LINKFLAGS)

        -out:$@

        -map:$*.map

        $(OBJS)

        dfv.res

        $(LIBS)

<<


ABOUT.H  (DFVIEW Sample)

//+---------------------------------------------------------------------------

//

//  Microsoft Windows

//  Copyright (C) Microsoft Corporation, 1992 - 1994.

//

//  File:       about.h

//

//  Contents:   definition for an about dialog box class

//

//  Classes:    CAbout

//

//  Functions:

//

//  History:    6-08-94   stevebl   Created

//

//----------------------------------------------------------------------------

#ifndef __ABOUT_H__

#define __ABOUT_H__

#include <cdialog.h>

#ifdef __cplusplus

//+---------------------------------------------------------------------------

//

//  Class:      CAbout

//

//  Purpose:    implements the about dialog box

//

//  Interface:  DialogProc -- dialog procedure

//

//  History:    6-08-94   stevebl   Created

//

//----------------------------------------------------------------------------

class CAbout: public CHlprDialog

{

public:

    BOOL DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);

};

#endif //__cplusplus

#endif //__ABOUT_H__


ABOUT.CXX  (DFVIEW Sample)

//+---------------------------------------------------------------------------

//

//  Microsoft Windows

//  Copyright (C) Microsoft Corporation, 1992 - 1994.

//

//  File:       about.cxx

//

//  Contents:   implementation for a simple about dialog box

//

//  Classes:    CAbout

//

//  Functions:

//

//  History:    6-08-94   stevebl   Created

//

//----------------------------------------------------------------------------

#include <windows.h>

#include "about.h"

//+---------------------------------------------------------------------------

//

//  Member:     CAbout::DialogProc

//

//  Synopsis:   dialog proc for the About dialog box

//

//  Arguments:  [uMsg]   - message

//              [wParam] - first message parameter

//              [lParam] - second message parameter

//

//  History:    4-12-94   stevebl   Created for MFract

//              6-08-94   stevebl   Stolen from MFract

//

//----------------------------------------------------------------------------

BOOL CAbout::DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)

{

    switch (uMsg)

    {

    case WM_INITDIALOG:

        return(TRUE);

    case WM_COMMAND:

        if (LOWORD(wParam) == IDOK

            || LOWORD(wParam) == IDCANCEL)

        {

            EndDialog(hwndDlg, TRUE);

            return(TRUE);

        }

    }

    return(FALSE);

}


BITMAPS.H  (DFVIEW Sample)

//+---------------------------------------------------------------------------

//

//  Microsoft Windows

//  Copyright (C) Microsoft Corporation, 1992 - 1994.

//

//  File:       bitmaps.h

//

//  Contents:   bitmap helper functions

//

//  Classes:

//

//  Functions:  DDBChangeColor

//              LoadAndStretch

//

//  History:    6-24-94   stevebl   Created

//

//----------------------------------------------------------------------------

#ifndef __BITMAPS_H__

#define __BITMAPS_H__

#define DSPDxax 0x00E20746L

BOOL DDBChangeColor (

    HBITMAP hBitmap,

    COLORREF crFrom,

    COLORREF crTo);

BOOL LoadAndStretch (

    HINSTANCE hinst,

    HBITMAP hbmpDest,

    LPTSTR lpszResource,

    UINT cxBitmap,

    UINT cyBitmap,

    COLORREF crHigh,

    COLORREF crNorm);

#endif //__BITMAPS_H__


BITMAPS.CXX  (DFVIEW Sample)

//+---------------------------------------------------------------------------

//

//  Microsoft Windows

//  Copyright (C) Microsoft Corporation, 1992 - 1994.

//

//  File:       bitmaps.cxx

//

//  Contents:   bitmap helper functions

//

//  Classes:

//

//  Functions:  DDBChangeColor

//              LoadAndStretch

//

//  History:    6-24-94   stevebl   Created

//

//----------------------------------------------------------------------------

#include <windows.h>

#include "bitmaps.h"

//+---------------------------------------------------------------------------

//

//  Function:   LoadAndStretch

//

//  Synopsis:   Loads a bitmap from our resources, and creates a bitmap

//              "array."  The red portions of the bitmap are considered

//              clear.  Each resource consists of two bitmaps side by

//              side:  an "open folder" and a "closed folder".  These

//              bitmaps are turned into 4 bitmaps:  two selected, and

//              two unselected bitmaps.

//

//  Arguments:  [hinst]        - instance containing the bitmap

//              [hbmpDest]     - destination bitmap array

//              [lpszResource] - name of the bitmap resource

//              [cxBitmap]     - width to stretch to

//              [cyBitmap]     - height to stretch to

//              [crHigh]       - color of the highlighted background

//              [crNorm]       - color of the normal background

//

//  Returns:    TRUE on success.

//              FALSE on failure.

//

//  History:    6-24-94   stevebl   Stolen and modified from original DFView

//

//----------------------------------------------------------------------------

BOOL LoadAndStretch (

    HINSTANCE hinst,

    HBITMAP hbmpDest,

    LPTSTR lpszResource,

    UINT cxBitmap,

    UINT cyBitmap,

    COLORREF crHigh,

    COLORREF crNorm)

{

    HBITMAP hbmpOld1, hbmpOld2, hbmp;

    BITMAP bm;

    int i;

    HDC hdcDest = CreateCompatibleDC(NULL);

    HDC hdcSrc = CreateCompatibleDC(NULL);

    if (NULL == hdcDest || NULL == hdcSrc)

    {

        DeleteDC(hdcSrc);

        DeleteDC(hdcDest);

        return(FALSE);

    }

    for (i=0;  i < 2;  i++)

    {

        hbmp = LoadBitmap(hinst, lpszResource);

        if (NULL == hbmp)

        {

            DeleteDC(hdcSrc);

            DeleteDC(hdcDest);

            return FALSE;

        }

        DDBChangeColor(hbmp, RGB (255,0,0), ((i == 0) ? crHigh : crNorm));

        GetObject(hbmp, sizeof (bm), &bm);

        hbmpOld1 = (HBITMAP) SelectObject(hdcDest, hbmpDest);

        hbmpOld2 = (HBITMAP) SelectObject(hdcSrc, hbmp);

        SetStretchBltMode(hdcDest, COLORONCOLOR);

        StretchBlt(

            hdcDest,

            i * cxBitmap * 2,

            0,

            cxBitmap * 2,

            cyBitmap,

            hdcSrc,

            0,

            0,

            bm.bmWidth,

            bm.bmHeight,

            SRCCOPY);

        SelectObject(hdcDest, hbmpOld1);

        SelectObject(hdcSrc,  hbmpOld2);

        DeleteObject(hbmp);

    }

    DeleteDC(hdcSrc);

    DeleteDC(hdcDest);

    return TRUE;

}

//+---------------------------------------------------------------------------

//

//  Function:   DDBChangeColor

//

//  Synopsis:   Change a particular color in a bitmap to another color.

//              Strategy is to create a monochrome mask, where each pixel

//              in the source bitmap that matches the color we're converting

//              from is set to white (1), and all other colors to black.

//              We then Blt this mask into the original bitmap, with a ROP

//              code that does:

//

//                (~Mask&Source) | (~Mask&Pattern)

//

//              where Pattern is the color we're changing to.

//

//              In other words, wherever the Mask is 1, we want to put the pattern;

//              wherever the Mask is 0, we want to leave the source alone.  By

//              using a Truth Table, you'll find that this ROP code is equivalent

//              to DSPDxax or ROP code 0x00E20746.

//

//              For info on figuring out ROP codes given a set of boolean ops,

//              check out the Windows 3.0 SDK, Reference Volume 2, chapter 11.

//

//  Arguments:  [hBitmap] - bitmap handle

//              [crFrom]  - color to change

//              [crTo]    - new color

//

//  Returns:    TRUE on success.  FALSE on failur

//

//  History:    6-24-94   stevebl   Stolen from original DFView code

//

//----------------------------------------------------------------------------

BOOL DDBChangeColor (HBITMAP hBitmap, COLORREF crFrom, COLORREF crTo)

{

    register int cx, cy;

    BITMAP       bm;

    HDC          hdcBmp, hdcMask;

    HBITMAP      hbmMask, hbmOld1, hbmOld2;

    HBRUSH       hBrush, hbrOld;

    if (!hBitmap)

          return FALSE;

    GetObject (hBitmap, sizeof (bm), &bm);

    cx = bm.bmWidth;

    cy = bm.bmHeight;

    hbmMask = CreateBitmap(cx, cy, 1, 1, NULL);

    hdcMask = CreateCompatibleDC(NULL);

    hdcBmp = CreateCompatibleDC(NULL);

    hBrush = CreateSolidBrush(crTo);

    if (!hdcMask || !hdcBmp || !hBrush || !hbmMask)

    {

        DeleteObject(hbmMask);

        DeleteObject(hBrush);

        DeleteDC(hdcMask);

        DeleteDC(hdcBmp);

        return FALSE;

    }

    hbmOld1 = (HBITMAP) SelectObject (hdcBmp,  hBitmap);

    hbmOld2 = (HBITMAP) SelectObject (hdcMask, hbmMask);

    hbrOld  = (HBRUSH) SelectObject (hdcBmp, hBrush);

    SetBkColor(hdcBmp, crFrom);

    BitBlt(hdcMask, 0, 0, cx, cy, hdcBmp,  0, 0, SRCCOPY);

    SetBkColor(hdcBmp, RGB(255,255,255));

    BitBlt(hdcBmp,  0, 0, cx, cy, hdcMask, 0, 0, DSPDxax);

    SelectObject(hdcBmp,  hbrOld);

    SelectObject(hdcBmp,  hbmOld1);

    SelectObject(hdcMask, hbmOld2);

    DeleteDC(hdcBmp);

    DeleteDC(hdcMask);

    DeleteObject(hBrush);

    DeleteObject(hbmMask);

    return TRUE;

}


DFV.DLG  (DFVIEW Sample)

1 DLGINCLUDE "dfv.h"

IDM_ABOUT DIALOG 67, 46, 173, 53

LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US

STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU

CAPTION "About DocFile Viewer"

FONT 8, "MS Sans Serif"

BEGIN

    ICON            "AppIcon", -1, 8, 6, 18, 20

    LTEXT           "Windows NT DocFile Viewer - Version 2.0", -1, 32, 7,

                    139, 8, NOT WS_GROUP

    LTEXT           "Copyright 1994 Microsoft Corporation", -1, 32, 18, 139,

                    8, NOT WS_GROUP

    PUSHBUTTON      "OK", IDOK, 66, 33, 40, 14

END


DFV.H  (DFVIEW Sample)

//+---------------------------------------------------------------------------

//

//  Microsoft Windows

//  Copyright (C) Microsoft Corporation, 1992 - 1994.

//

//  File:       DFV.h

//

//  Contents:   globally defined constants, IDs and structures

//

//  History:    6-08-94   stevebl   Created

//

//----------------------------------------------------------------------------

#ifndef __DFV_H__

#define __DFV_H__

#include <windows.h>

#include <ole2.h>

#include "message.h"

// String Constants

#define VER_FILEDESCRIPTION_STR     "Windows NT Docfile Viewer"

#define VER_INTERNALNAME_STR        "DocFile Viewer"

#define VER_ORIGINALFILENAME_STR    "DFVIEW.exe"

#define HELPFILE_STR                "OLETools.hlp"

#define MAIN_WINDOW_CLASS_NAME      "MainDFVWindow"

#define MAIN_WINDOW_CLASS_MENU      MainDFVMenu

#define MAIN_WINDOW_CLASS_MENU_STR  "MainDFVMenu"

#define STREAM_VIEW_CLASS_NAME      "Stream Viewer"

// Menu Command Identifiers

#define IDM_EXIT                    1000

#define IDM_OPEN                    1001

#define IDM_CLOSE                   1002

#define IDM_EXPAND                  1100

#define IDM_EXPANDBRANCH            1101

#define IDM_EXPANDALL               1102

#define IDM_COLLAPSE                1103

#define IDM_COLLAPSEALL             1104

#define IDM_TOGGLE                  1105

#define IDM_HELP                    1200

#define IDM_ABOUT                   1201

// Listbox Identifiers

#define IDC_LISTBOX                 4000

#define IDC_STREAMVIEW              4001

// Bitmap Identifiers

#define BMP_STREAM                  3000

#define BMP_STORAGE                 3001

// String Identifiers

#define IDS_ERROR                   2000

#define IDS_NOHELPFILE              2001

#define IDS_OLEINCOMPATIBLE         2002

#define IDS_OLEINITFAILED           2003

#define IDS_ENUMSTATSTGFAILED       2004

#define IDS_OPENSTORAGEFAILED       2005

#define IDS_OPENSTREAMFAILED        2006

#define IDS_ENUMELEMENTSFAILED      2007

#define IDS_INSERTSTRINGFAILED      2008

#define IDS_LOADBITMAPSFAILED       2009

#define IDS_STGOPENSTORAGEFAILED    2010

#define IDS_STMSTATFAILED           2011

#define IDS_STMSEEKFAILED           2012

#define IDS_STMREADFAILED           2013

#define IDS_STMTITLETEXT            2014

#define IDS_OUTOFMEMORY             2015

#endif // __DFV_H__


DFV.RC  (DFVIEW Sample)

//+---------------------------------------------------------------------------

//

//  Microsoft Windows

//  Copyright (C) Microsoft Corporation, 1992 - 1994.

//

//  File:       DFV.rc

//

//  Contents:   resources for Stereo Shop

//

//  History:    6-08-94   stevebl   Created

//

//----------------------------------------------------------------------------

#include "dfv.h"

#define VER_PRODUCTVERSION_STR      "3.50"

#define VER_COMPANYNAME_STR         "Microsoft Corporation"

#define VER_PRODUCTNAME_STR         "Microsoft\256 Windows NT(TM) Operating System"

#define VER_LEGALCOPYRIGHT_YEARS    "1981-1994"

#define VER_LEGALCOPYRIGHT_STR "Copyright \251 Microsoft Corp. " VER_LEGALCOPYRIGHT_YEARS

#define VER_PRODUCTNAME_STR "Microsoft\256 Windows NT(TM) Operating System"

#define VER_PRODUCTVERSION 3,50,01,001

VS_VERSION_INFO VERSIONINFO

FILEVERSION    VER_PRODUCTVERSION

PRODUCTVERSION VER_PRODUCTVERSION

FILEFLAGSMASK  VS_FFI_FILEFLAGSMASK

FILEFLAGS      0

FILEOS         VOS_NT_WINDOWS32

FILETYPE       VFT_APP

FILESUBTYPE    VFT2_UNKNOWN

BEGIN

    BLOCK "StringFileInfo"

    BEGIN

        BLOCK "040904B0"   /* LANG_ENGLISH/SUBLANG_ENGLISH_US, Unicode CP */

        BEGIN

            VALUE "CompanyName",     VER_COMPANYNAME_STR

            VALUE "FileDescription", VER_FILEDESCRIPTION_STR

            VALUE "FileVersion",     VER_PRODUCTVERSION

            VALUE "InternalName",    VER_INTERNALNAME_STR

            VALUE "LegalCopyright",  VER_LEGALCOPYRIGHT_STR

            VALUE "OriginalFilename",VER_ORIGINALFILENAME_STR

            VALUE "ProductName",     VER_PRODUCTNAME_STR

            VALUE "ProductVersion",  VER_PRODUCTVERSION_STR

        END

    END

    BLOCK "VarFileInfo"

    BEGIN

        VALUE "Translation", 0x0409, 0x04B0

    END

END

AppIcon ICON DFV.ico

StreamIcon ICON stream.ico

BMP_STORAGE     BITMAP  DISCARDABLE "FOLDER.BMP"

BMP_STREAM      BITMAP  DISCARDABLE "DOCUMENT.BMP"

MAIN_WINDOW_CLASS_MENU MENU

BEGIN

    POPUP "&File"

    BEGIN

        MENUITEM "&Open DocFile...", IDM_OPEN

        MENUITEM "&Close", IDM_CLOSE

        MENUITEM SEPARATOR

        MENUITEM "E&xit",IDM_EXIT

    END

    POPUP "&Tree"

    BEGIN

        MENUITEM "E&xpand  \a+", IDM_EXPAND

        MENUITEM "Expand &Branch  \a*", IDM_EXPANDBRANCH

        MENUITEM "Expand &All  \aCtrl+*", IDM_EXPANDALL

        MENUITEM "&Collapse Branch  \a-", IDM_COLLAPSE

        MENUITEM "C&ollapse All \aCtrl+-", IDM_COLLAPSEALL

    END

    POPUP "&Help"

    BEGIN

        MENUITEM "&Index...  \aF1", IDM_HELP

        MENUITEM SEPARATOR

        MENUITEM "&About DocFile Viewer...", IDM_ABOUT

    END

END

#include "DFV.dlg"

STRINGTABLE

BEGIN

    IDS_ERROR                   "Error"

    IDS_NOHELPFILE              "Can't find help file."

    IDS_OLEINCOMPATIBLE         "This program is incompatible with the version of OLE installed on this system.  This program requires at least OLE2 version %i - %i"

    IDS_OLEINITFAILED           "OLE initizlization failed."

    IDS_ENUMSTATSTGFAILED       "IStorage::EnumSTATSTG failed with HRESULT: 0x%08X"

    IDS_OPENSTORAGEFAILED       "IStorage::OpenStorage failed with HRESULT: 0x%08X"

    IDS_OPENSTREAMFAILED        "IStorage::OpenStream failed with HRESULT: 0x%08X"

    IDS_ENUMELEMENTSFAILED      "IStorage::EnumElements failed with HRESULT: 0x%08X"

    IDS_INSERTSTRINGFAILED      "Tree is too large.  Collapse some branches."

    IDS_LOADBITMAPSFAILED       "Couldn't load folder and document bitmaps."

    IDS_STGOPENSTORAGEFAILED    "Unable to open %ws as a DocFile."

    IDS_STMSTATFAILED           "IStream::Stat failed with HRESULT: 0x%08X"

    IDS_STMSEEKFAILED           "IStream::Seek failed with HRESULT: 0x%08X"

    IDS_STMREADFAILED           "IStream::Read failed with HRESULT: 0x%08X"

    IDS_STMTITLETEXT            "Stream:"

    IDS_OUTOFMEMORY             "DFView ran out of memory.  Free up more resources."

END

AppAccel ACCELERATORS

BEGIN

    VK_F1,          IDM_HELP,           VIRTKEY

    VK_ADD,         IDM_EXPAND,         VIRTKEY

    VK_SUBTRACT,    IDM_COLLAPSE,       VIRTKEY

    VK_SUBTRACT,    IDM_COLLAPSEALL,    CONTROL,    VIRTKEY

    VK_MULTIPLY,    IDM_EXPANDALL,      CONTROL,    VIRTKEY

    VK_MULTIPLY,    IDM_EXPANDBRANCH,   VIRTKEY

    "+",            IDM_EXPAND

    "-",            IDM_COLLAPSE

    "*",            IDM_EXPANDBRANCH

END


MESSAGE.H  (DFVIEW Sample)

//+---------------------------------------------------------------------------

//

//  Microsoft Windows

//  Copyright (C) Microsoft Corporation, 1992 - 1994.

//

//  File:       message.h

//

//  Contents:   Helper functions for popup message boxes.

//

//  Classes:

//

//  Functions:  MessageBoxFromStringIds

//

//  History:    6-24-94   stevebl   Created

//

//----------------------------------------------------------------------------

#ifndef __MESSAGE_H__

#define __MESSAGE_H__

#define MAX_STRING_LENGTH           256

int MessageBoxFromStringIds(

    const HWND hwndOwner,

    const HINSTANCE hinst,

    const UINT idText,

    const UINT idTitle,

    const UINT fuStyle);

int MessageBoxFromStringIdsAndArgs(

    const HWND hwndOwner,

    const HINSTANCE hinst,

    const UINT idText,

    const UINT idTitle,

    const UINT fuStyle,

    ...);

#endif //__MESSAGE_H__


MESSAGE.CXX  (DFVIEW Sample)

//+---------------------------------------------------------------------------

//

//  Microsoft Windows

//  Copyright (C) Microsoft Corporation, 1992 - 1994.

//

//  File:       message.cxx

//

//  Contents:   Helper functions for popup message boxes.

//

//  Classes:

//

//  Functions:  MessageBoxFromSringIds

//

//  History:    6-24-94   stevebl   Created

//

//----------------------------------------------------------------------------

#include <windows.h>

#include "message.h"

//+---------------------------------------------------------------------------

//

//  Function:   MessageBoxFromStringIds

//

//  Synopsis:   Displays a simple message box taking its text from a string

//              table instead of from user allocated strings.

//

//  Arguments:  [hwndOwner]      - window handle for the message box's owner

//              [hinst]          - instance associated with the string table

//              [idText]         - string id for the box's text string

//              [idTitle]        - string id for the box's title string

//              [fuStyle]        - style of message box

//                                 (see Windows function MessageBox for styles)

//

//  Returns:    result from MessageBox

//

//  History:    6-24-94   stevebl   Created

//

//  Notes:      Each string is limited to MAX_STRING_LENGTH characters.

//

//----------------------------------------------------------------------------

int MessageBoxFromStringIds(

    const HWND hwndOwner,

    const HINSTANCE hinst,

    const UINT idText,

    const UINT idTitle,

    const UINT fuStyle)

{

    int iReturn = 0;

    TCHAR szTitle[MAX_STRING_LENGTH];

    TCHAR szText[MAX_STRING_LENGTH];

    if (LoadString(hinst, idTitle, szTitle, MAX_STRING_LENGTH))

    {

        if (LoadString(hinst, idText, szText, MAX_STRING_LENGTH))

        {

            iReturn = MessageBox(

                hwndOwner,

                szText,

                szTitle,

                fuStyle);

        }

    }

    return(iReturn);

}

//+---------------------------------------------------------------------------

//

//  Function:   MessageBoxFromStringIdsAndArgs

//

//  Synopsis:   Creates a message box from a pair of string IDs similar

//              to MessageBoxFromStringIds.  The principle difference

//              is that idFormat is an ID for a string which is a printf

//              format string suitable for passing to wsprintf.

//              The variable argument list is combined with the format

//              string to create the text of the message box.

//

//  Arguments:  [hwndOwner] - window handle for the message box's owner

//              [hinst]     - instance associated with the string table

//              [idFormat]  - string id for the format of the box's text

//              [idTitle]   - string id for the box's title string

//              [fuStyle]   - style of the dialog box

//              [...]       - argument list for text format string

//

//  Returns:    result from MessageBox

//

//  History:    6-24-94   stevebl   Created

//

//  Notes:      Neither the composed text string nor the title must be

//              longer than MAX_STRING_LENGTH characters.

//

//----------------------------------------------------------------------------

int MessageBoxFromStringIdsAndArgs(

    const HWND hwndOwner,

    const HINSTANCE hinst,

    const UINT idFormat,

    const UINT idTitle,

    const UINT fuStyle, ...)

{

    int iReturn = 0;

    va_list arglist;

    va_start(arglist, fuStyle);

    TCHAR szTitle[MAX_STRING_LENGTH];

    TCHAR szText[MAX_STRING_LENGTH];

    TCHAR szFormat[MAX_STRING_LENGTH];

    if (LoadString(hinst, idTitle, szTitle, MAX_STRING_LENGTH))

    {

        if (LoadString(hinst, idFormat, szFormat, MAX_STRING_LENGTH))

        {

            wvsprintf(szText, szFormat, arglist);

            iReturn = MessageBox(

                hwndOwner,

                szText,

                szTitle,

                fuStyle);

        }

    }

    return(iReturn);

}


MWCLASS.H  (DFVIEW Sample)

//+---------------------------------------------------------------------------

//

//  Microsoft Windows

//  Copyright (C) Microsoft Corporation, 1992 - 1994.

//

//  File:       mwclass.h

//

//  Contents:   definition of the main window class

//

//  Classes:    CMainWindow

//

//  Functions:  Exists

//

//  History:    6-08-94   stevebl   Created

//

//----------------------------------------------------------------------------

#ifndef __MWCLASS_H__

#define __MWCLASS_H__

#include <cwindow.h>

#include <commdlg.h>

#ifdef __cplusplus

int Exists(TCHAR *sz);

// List Box Element Structure

struct TAG_LISTBOXELEMENT

{

#define LBE_STORAGE     STGTY_STORAGE

#define LBE_STREAM      STGTY_STREAM

    unsigned uType;

    BOOL fOpen;

    void * pInterface;

    union {

        ULONG nChildren;

        HWND hwndView;

    };

    unsigned uIndent;

    LPOLESTR pwcsName;

};

typedef struct TAG_LISTBOXELEMENT LISTBOXELEMENT;

//+---------------------------------------------------------------------------

//

//  Class:      CMainWindow

//

//  Purpose:    Code for the main docfile viewer window and the main menu.

//

//  Interface:  CMainWindow          -- constructor

//              InitInstance         -- instantiates the docfile viewer window

//              Toggle               -- toggles a selection

//              Expand               -- expands a selection

//              Collapse             -- collapses a selection

//              ExpandAll            -- expands an entire tree

//              OpenFile             -- trys to load the docfile in _szFileName

//

//  History:    6-27-94   stevebl   Created

//

//  Notes:      only the public interface is listed here

//

//----------------------------------------------------------------------------

class CMainWindow: public CHlprWindow

{

public:

    CMainWindow();

    BOOL InitInstance(HINSTANCE, int);

    void Toggle(long lIndex);

    void Expand(long lIndex);

    void Collapse(long lIndex);

    void ExpandAll(long lIndex);

    void OpenFile(void);

    TCHAR _szFileName[MAX_PATH];

protected:

    ~CMainWindow();

    LRESULT WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam);

private:

    LRESULT DoMenu(WPARAM wParam, LPARAM lParam);

    LISTBOXELEMENT * CreateStreamElement(IStream * pstm);

    LISTBOXELEMENT * CreateStorageElement(IStorage * pstg);

    void DeleteElement(LISTBOXELEMENT * plbe);

    BOOL LoadBitmaps(void);

    HWND _hlb;

    HBITMAP _hbmpStorage;

    HBITMAP _hbmpStream;

    COLORREF _crTextHigh;

    COLORREF _crBkHigh;

    COLORREF _crTextNorm;

    COLORREF _crBkNorm;

    WORD _wWidth;

    OPENFILENAME _ofnFile;

    TCHAR _szFileTitle[MAX_PATH];

    TEXTMETRIC _tm;

    UINT _cyBitmap;

    TCHAR _szHelpFile[MAX_PATH];

};

#endif // __cplusplus

#endif // __MWCLASS_H__


MWCLASS.CXX  (DFVIEW Sample)

//+---------------------------------------------------------------------------

//

//  Microsoft Windows

//  Copyright (C) Microsoft Corporation, 1992 - 1994.

//

//  File:       mwclass.cxx

//

//  Contents:   implementation for the main window class

//

//  Classes:    CMainWindow

//

//  Functions:  Exists

//

//  History:    6-08-94   stevebl   Created

//

//----------------------------------------------------------------------------

#include "dfv.h"

#include "mwclass.h"

#include "about.h"

#include "bitmaps.h"

#include "strmvwr.h"

#include <assert.h>

#define BITMAPWIDTH 16

#define BITMAPHEIGHT 16

#define INDENT BITMAPWIDTH

#define ROOTSTGSTR OLESTR(" \\ - ")

//+---------------------------------------------------------------------------

//

//  Member:     CMainWindow::CMainWindow

//

//  Synopsis:   constructor

//

//  History:    6-27-94   stevebl   Created

//

//----------------------------------------------------------------------------

CMainWindow::CMainWindow()

{

    _hlb = NULL;

    _hbmpStorage = _hbmpStream = NULL;

}

//+---------------------------------------------------------------------------

//

//  Member:     CMainWindow::~CMainWindow

//

//  Synopsis:   destructor

//

//  History:    6-27-94   stevebl   Created

//

//  Notes:      Destruction of the main window indicates that the app should

//              quit.

//

//----------------------------------------------------------------------------

CMainWindow::~CMainWindow()

{

    DeleteObject(_hbmpStorage);

    DeleteObject(_hbmpStream);

    PostQuitMessage(0);

}

//+---------------------------------------------------------------------------

//

//  Member:     CMainWindow::InitInstance

//

//  Synopsis:   Instantiates an instance of the docfile viewer window.

//

//  Arguments:  [hInstance] - instance of the app

//              [nCmdShow]  - command to pass to ShowWindow

//

//  Returns:    TRUE on success

//              FALSE on failure

//

//  History:    6-27-94   stevebl   Created

//

//  Notes:      This method must be called only once, immediately after

//              class construction.

//

//----------------------------------------------------------------------------

BOOL CMainWindow::InitInstance(HINSTANCE hInstance, int nCmdShow)

{

    // Note, the Create method sets the _hwnd member for me so I don't

    // need to set it myself.

    if (!Create(

        TEXT(MAIN_WINDOW_CLASS_NAME),

        TEXT(VER_INTERNALNAME_STR),

        WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX

            | WS_MAXIMIZEBOX | WS_THICKFRAME,

        CW_USEDEFAULT,

        CW_USEDEFAULT,

        CW_USEDEFAULT,

        CW_USEDEFAULT,

        NULL,

        NULL,

        hInstance))

    {

        return(FALSE);

    }

    ShowWindow(_hwnd, nCmdShow);

    UpdateWindow(_hwnd);

    // build a path to where the help file should be

    // (it should be in the same directory as the .EXE)

    // first get the exe's path

    DWORD cch = GetModuleFileName(hInstance, _szHelpFile, MAX_PATH);

    // then back up past the name of the application

    while (cch > 0 &&

        _szHelpFile[cch - 1] != TEXT('\\') &&

        _szHelpFile[cch - 1] != TEXT('/') &&

        _szHelpFile[cch - 1] != TEXT(':'))

    {

        cch--;

    }

    // finally copy the help file's name at the end of the path

    lstrcpy(&_szHelpFile[cch], TEXT(HELPFILE_STR));

    return(TRUE);

}

//+---------------------------------------------------------------------------

//

//  Member:     CMainWindow::WindowProc

//

//  Synopsis:   main window procedure

//

//  Arguments:  [uMsg]   - Windows message

//              [wParam] - first message parameter

//              [lParam] - second message parameter

//

//  History:    6-27-94   stevebl   Created

//

//  Notes:      See CHlprWindow for a description of how this method gets

//              called by the global WinProc.

//

//----------------------------------------------------------------------------

LRESULT CMainWindow::WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam)

{

    switch (uMsg)

    {

    case WM_CREATE:

        {

            RECT rc;

            GetClientRect(_hwnd, &rc);

            // record the width before we create the list box

            _wWidth = (WORD) rc.right;

            HDC hdc = GetDC(_hwnd);

            GetTextMetrics(hdc, &_tm);

            ReleaseDC(_hwnd, hdc);

            // create the child listbox

            _hlb = CreateWindow(

                TEXT("listbox"),

                TEXT(""),

                LBS_OWNERDRAWFIXED |

                    WS_CHILD |

                    WS_VISIBLE |

                    WS_VSCROLL |

                    LBS_NOTIFY |

                    LBS_NOINTEGRALHEIGHT |

                    LBS_WANTKEYBOARDINPUT,

                0,

                0,

                rc.right,

                rc.bottom,

                _hwnd,

                (HMENU) IDC_LISTBOX,

                _hInstance,

                NULL);

            if (NULL == _hlb)

            {

                // abort window creation

                return(-1);

            }

            SetFocus(_hlb);

            if (!LoadBitmaps())

            {

                MessageBoxFromStringIds(

                    _hwnd,

                    _hInstance,

                    IDS_LOADBITMAPSFAILED,

                    IDS_ERROR,

                    MB_OK | MB_ICONEXCLAMATION);

                return(-1);

            }

            _crTextHigh = GetSysColor(COLOR_HIGHLIGHTTEXT);

            _crTextNorm = GetSysColor(COLOR_WINDOWTEXT);

            _crBkHigh = GetSysColor(COLOR_HIGHLIGHT);

            _crBkNorm = GetSysColor(COLOR_WINDOW);

            // Fill in the File's OPENFILENAME structure

            _szFileName[0] = 0;

            _szFileTitle[0] = 0;

            _ofnFile.lStructSize = sizeof(OPENFILENAME);

            _ofnFile.hwndOwner = _hwnd;

            _ofnFile.lpstrFilter = TEXT("All Files (*.*)\0*.*\0Doc Files (*.DFL;*.OL?)\0*.DFL;*.OL;\0");

            _ofnFile.lpstrCustomFilter = NULL;

            _ofnFile.nMaxCustFilter = 0;

            _ofnFile.nFilterIndex = 1;

            _ofnFile.lpstrFile = _szFileName;

            _ofnFile.nMaxFile = MAX_PATH;

            _ofnFile.lpstrInitialDir = NULL;

            _ofnFile.lpstrFileTitle = _szFileTitle;

            _ofnFile.nMaxFileTitle = MAX_PATH;

            _ofnFile.lpstrTitle = TEXT("Open DocFile");

            _ofnFile.lpstrDefExt = NULL;

            _ofnFile.Flags = OFN_HIDEREADONLY;

        }

        break;

    case WM_SETFOCUS:

        {

            if (_hlb)

            {

                SetFocus(_hlb);

            }

        break;

        }

    case WM_MEASUREITEM:

        {

            LPMEASUREITEMSTRUCT lpmis = (LPMEASUREITEMSTRUCT) lParam;

            if (BITMAPHEIGHT < _tm.tmHeight + _tm.tmExternalLeading)

            {

                lpmis->itemHeight = _tm.tmHeight + _tm.tmExternalLeading;

            }

            else

            {

                lpmis->itemHeight = BITMAPHEIGHT;

            }

            lpmis->itemWidth = _wWidth;

            return(TRUE);

        }

    case WM_DELETEITEM:

        if (IDC_LISTBOX == wParam)

        {

            DeleteElement((LISTBOXELEMENT *)((LPDELETEITEMSTRUCT)lParam)->itemData);

        }

        break;

    case WM_DRAWITEM:

        {

            LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT) lParam;

            if (-1 == lpdis->itemID)

            {

                // no items in the listbox

                break;

            }

            // draw the item

            switch (lpdis->itemAction)

            {

            case ODA_SELECT:

            case ODA_DRAWENTIRE:

                {

                    // draw the listbox item

                    LISTBOXELEMENT * plbe = (LISTBOXELEMENT *) lpdis->itemData;

                    assert(plbe);

                    // compute the starting point

                    int x = lpdis->rcItem.left + plbe->uIndent * INDENT;

                    int y = lpdis->rcItem.top;

                    // paint the bitmap

                    HDC hMemDC = CreateCompatibleDC(lpdis->hDC);

                    HBITMAP hbmp;

                    switch (plbe->uType)

                    {

                    case LBE_STORAGE:

                        hbmp = _hbmpStorage;

                        break;

                    case LBE_STREAM:

                        hbmp = _hbmpStream;

                        break;

                    default:

                        assert(NULL == "Unsupported type");

                        hbmp = _hbmpStream;

                        break;

                    }

                    HBITMAP hbmpOld = (HBITMAP) SelectObject(hMemDC, hbmp);

                    int nBitmap = ((lpdis->itemState & ODS_SELECTED) ? 0 : 2) +

                        plbe->fOpen;

                    BitBlt(

                        lpdis->hDC,

                        x,

                        y,

                        BITMAPWIDTH,

                        _cyBitmap,

                        hMemDC,

                        nBitmap * BITMAPWIDTH, 0, SRCCOPY);

                    SelectObject(hMemDC, hbmpOld);

                    DeleteDC(hMemDC);

                    x += BITMAPWIDTH;

                    // paint the text

                    SIZE sizeText;

                    RECT rcItem = lpdis->rcItem;

                    rcItem.left = x;

                    // Note that pwcsName is an OLEStr and

                    // is therefore always wide under WIN32.

                    GetTextExtentPoint32W(

                        lpdis->hDC,

                        plbe->pwcsName,

                        wcslen(plbe->pwcsName),

                        &sizeText);

                    rcItem.right = x + sizeText.cx;

                    COLORREF crOldText = SetTextColor(

                        lpdis->hDC,

                        (lpdis->itemState & ODS_SELECTED) ? _crTextHigh : _crTextNorm);

                    COLORREF crOldBack = SetBkColor(

                        lpdis->hDC,

                        (lpdis->itemState & ODS_SELECTED) ? _crBkHigh : _crBkNorm);

                    ExtTextOutW(

                        lpdis->hDC,

                        x,

                        y,

                        ETO_OPAQUE | ETO_CLIPPED,

                        &rcItem,

                        plbe->pwcsName,

                        wcslen(plbe->pwcsName),

                        NULL);

                    SetTextColor(lpdis->hDC, crOldText);

                    SetBkColor(lpdis->hDC, crOldBack);

                }

                break;

            case ODA_FOCUS:

                break;

            }

            return(TRUE);

        }

    case WM_VKEYTOITEM:

        if ((HWND)lParam == _hlb)

        {

            if (LOWORD(wParam) == VK_RETURN)

            {

                if(SendMessage(_hlb, LB_GETCOUNT, 0, 0))

                {

                    Toggle(SendMessage(_hlb, LB_GETCURSEL, 0, 0));

                    InvalidateRect(_hlb, NULL, FALSE);

                }

                return(-2);

            }

            return(-1);

        }

        break;

    case WM_SIZE:

        {

            _wWidth = LOWORD(lParam);

            WORD wHeight = HIWORD(lParam);

            if (_hlb)

            {

                SetWindowPos(_hlb, NULL, 0, 0, _wWidth, wHeight, SWP_NOMOVE | SWP_NOZORDER);

            }

            break;

        }

    case WM_COMMAND:

        if ((LOWORD(wParam) == IDC_LISTBOX) && ((HWND) lParam == _hlb))

        {

            switch (HIWORD(wParam))

            {

                case LBN_DBLCLK:

                    {

                        if(SendMessage(_hlb, LB_GETCOUNT, 0, 0))

                        {

                            Toggle(SendMessage(_hlb, LB_GETCURSEL, 0, 0));

                            InvalidateRect(_hlb, NULL, FALSE);

                        }

                    }

                    break;

                default:

                    break;

            }

        }

        return DoMenu(wParam, lParam);

    case WM_QUIT:

    case WM_CLOSE:

    default:

        return(DefWindowProc(_hwnd, uMsg, wParam, lParam));

    }

    return(FALSE);

}

//+---------------------------------------------------------------------------

//

//  Member:     CMainWindow::DoMenu

//

//  Synopsis:   implements the main menu commands

//

//  Arguments:  [wParam] - first window parameter

//              [lParam] - second window parameter

//

//  History:    6-23-94   stevebl   Created

//

//----------------------------------------------------------------------------

LRESULT CMainWindow::DoMenu(WPARAM wParam, LPARAM lParam)

{

    switch (LOWORD(wParam))

    {

    case IDM_OPEN:

        if (!GetOpenFileName((LPOPENFILENAME)&_ofnFile))

        {

            return(FALSE);

        }

        OpenFile();

        break;

    case IDM_CLOSE:

        SendMessage(_hlb, LB_RESETCONTENT, 0, 0);

        break;

    case IDM_EXPAND:

        if(SendMessage(_hlb, LB_GETCOUNT, 0, 0))

        {

            Expand(SendMessage(_hlb, LB_GETCURSEL, 0, 0));

            InvalidateRect(_hlb, NULL, FALSE);

        }

        break;

    case IDM_EXPANDBRANCH:

        if(SendMessage(_hlb, LB_GETCOUNT, 0, 0))

        {

            ExpandAll(SendMessage(_hlb, LB_GETCURSEL, 0, 0));

            InvalidateRect(_hlb, NULL, FALSE);

        }

        break;

    case IDM_EXPANDALL:

        if(SendMessage(_hlb, LB_GETCOUNT, 0, 0))

        {

            ExpandAll(0);

            InvalidateRect(_hlb, NULL, FALSE);

        }

        break;

    case IDM_COLLAPSE:

        if(SendMessage(_hlb, LB_GETCOUNT, 0, 0))

        {

            Collapse(SendMessage(_hlb, LB_GETCURSEL, 0, 0));

            InvalidateRect(_hlb, NULL, FALSE);

        }

        break;

    case IDM_COLLAPSEALL:

        if(SendMessage(_hlb, LB_GETCOUNT, 0, 0))

        {

            Collapse(0);

            SendMessage(_hlb, LB_SETCURSEL, 0, 0);

            InvalidateRect(_hlb, NULL, FALSE);

        }

        break;

    case IDM_TOGGLE:

        if (SendMessage(_hlb, LB_GETCOUNT, 0, 0))

        {

            Toggle(SendMessage(_hlb, LB_GETCURSEL, 0, 0));

            InvalidateRect(_hlb, NULL, FALSE);

        }

    case IDM_EXIT:

        SendMessage(_hwnd, WM_CLOSE, 0, 0);

        break;

    case IDM_HELP:

        if (!Exists(_szHelpFile))

        {

            MessageBoxFromStringIds(

                _hwnd,

                _hInstance,

                IDS_NOHELPFILE,

                IDS_ERROR,

                MB_OK | MB_ICONEXCLAMATION);

        }

        else

        {

            WinHelp(_hwnd, _szHelpFile, HELP_CONTEXT, 3);

        }

        break;

    case IDM_ABOUT:

        {

            CAbout dlgAbout;

            dlgAbout.ShowDialog(_hInstance, MAKEINTRESOURCE(IDM_ABOUT), _hwnd);

        }

        break;

    default:

        return(DefWindowProc(_hwnd, WM_COMMAND, wParam, lParam));

    }

    return(FALSE);

}

//+---------------------------------------------------------------------------

//

//  Member:     CMainWindow::Expand

//

//  Synopsis:   Expands a level of the tree.

//

//  Arguments:  [lIndex] - index of the item that needs to be expanded

//

//  History:    6-23-94   stevebl   Created

//

//----------------------------------------------------------------------------

void CMainWindow::Expand(long lIndex)

{

    LISTBOXELEMENT * pElement = (LISTBOXELEMENT *) SendMessage(_hlb, LB_GETITEMDATA, lIndex, 0);

    if (pElement->fOpen)

    {

        // this element has already been expanded

        return;

    }

    SendMessage(_hlb, WM_SETREDRAW, FALSE, 0);

    switch (pElement->uType)

    {

    case LBE_STORAGE:

        {

            // create entries for all of its children

            IStorage * pstg = (IStorage *) pElement->pInterface;

            IEnumSTATSTG * penumStatStg;

            STATSTG statstg;

            HRESULT hr = pstg->EnumElements(0, NULL, 0, &penumStatStg);

            if (SUCCEEDED(hr))

            {

                pElement->fOpen = TRUE;

                pElement->nChildren = 0;

                while (hr != S_FALSE)

                {

                    hr = penumStatStg->Next(1, &statstg, NULL);

                    if (FAILED(hr))

                    {

                        MessageBoxFromStringIdsAndArgs(

                            _hwnd,

                            _hInstance,

                            IDS_ENUMSTATSTGFAILED,

                            IDS_ERROR,

                            MB_OK | MB_ICONEXCLAMATION,

                            hr);

                    }

                    else if (S_OK == hr)

                    {

                        // retrieved another member from the list

                        LISTBOXELEMENT * plbe;

                        switch (statstg.type)

                        {

                        case STGTY_STORAGE:

                            {

                                IStorage * pstg2;

                                hr = pstg->OpenStorage(

                                    statstg.pwcsName,

                                    NULL,

                                    STGM_READWRITE | STGM_SHARE_EXCLUSIVE,

                                    NULL,

                                    0,

                                    &pstg2);

                                if (SUCCEEDED(hr))

                                {

                                    plbe = CreateStorageElement(pstg2);

                                }

                                else

                                {

                                    MessageBoxFromStringIdsAndArgs(

                                        _hwnd,

                                        _hInstance,

                                        IDS_OPENSTORAGEFAILED,

                                        IDS_ERROR,

                                        MB_OK | MB_ICONEXCLAMATION,

                                        hr);

                                    plbe = NULL;

                                }

                            }

                            break;

                        case STGTY_STREAM:

                            {

                                IStream * pstm;

                                hr = pstg->OpenStream(

                                    statstg.pwcsName,

                                    0,

                                    STGM_READWRITE | STGM_SHARE_EXCLUSIVE,

                                    0,

                                    &pstm);

                                if (SUCCEEDED(hr))

                                {

                                    plbe = CreateStreamElement(pstm);

                                }

                                else

                                {

                                    MessageBoxFromStringIdsAndArgs(

                                        _hwnd,

                                        _hInstance,

                                        IDS_OPENSTREAMFAILED,

                                        IDS_ERROR,

                                        MB_OK | MB_ICONEXCLAMATION,

                                        hr);

                                    plbe = NULL;

                                }

                            }

                            break;

                        }

                        if (plbe)

                        {

                            plbe->pwcsName = statstg.pwcsName;

                            plbe->uIndent = pElement->uIndent + 1;

                            pElement->nChildren++;

                            if (SendMessage(_hlb, LB_INSERTSTRING, lIndex + pElement->nChildren, (LPARAM) plbe) == LB_ERRSPACE)

                            {

                                MessageBoxFromStringIds(

                                    _hwnd,

                                    _hInstance,

                                    IDS_INSERTSTRINGFAILED,

                                    IDS_ERROR,

                                    MB_OK | MB_ICONEXCLAMATION);

                                DeleteElement(plbe);

                                pElement->nChildren--;

                            }

                        }

                    }

                }

                penumStatStg->Release();

            }

            else

            {

                MessageBoxFromStringIdsAndArgs(

                    _hwnd,

                    _hInstance,

                    IDS_ENUMELEMENTSFAILED,

                    IDS_ERROR,

                    MB_OK | MB_ICONEXCLAMATION,

                    hr);

            }

        }

        break;

    case LBE_STREAM:

        // streams are only expanded if they are the currently selected list item

        if (SendMessage(_hlb, LB_GETCURSEL, 0, 0) == lIndex)

        {

            // open stream

            CStreamView * psv = new CStreamView(_hlb, pElement);

            if (psv)

            {

                pElement->fOpen = psv->InitInstance(_hInstance, SW_SHOWNORMAL);

                if (pElement->fOpen)

                {

                    pElement->hwndView = psv->GetHwnd();

                    SetFocus(pElement->hwndView);

                }

            }

        }

        break;

    }

    SendMessage(_hlb, WM_SETREDRAW, TRUE, 0);

}

//+---------------------------------------------------------------------------

//

//  Member:     CMainWindow::Collapse

//

//  Synopsis:   collapses a level of the tree

//

//  Arguments:  [lIndex] - index of the item to be collapsed

//

//  History:    6-23-94   stevebl   Created

//

//----------------------------------------------------------------------------

void CMainWindow::Collapse(long lIndex)

{

    LISTBOXELEMENT * pElement = (LISTBOXELEMENT *) SendMessage(_hlb, LB_GETITEMDATA, lIndex, 0);

    if (pElement->fOpen)

    {

        switch (pElement->uType)

        {

        case LBE_STORAGE:

            while (pElement->nChildren--)

            {

                Collapse(lIndex + 1);

                SendMessage(_hlb, LB_DELETESTRING, lIndex + 1, 0);

            }

            break;

        case LBE_STREAM:

            if (pElement->fOpen)

            {

                DestroyWindow(pElement->hwndView);

            }

            break;

        }

        pElement->fOpen = FALSE;

    }

}

//+---------------------------------------------------------------------------

//

//  Member:     CMainWindow::ExpandAll

//

//  Synopsis:   expands the current item and all its children

//

//  Arguments:  [lIndex] - index of the item to be expanded

//

//  History:    6-23-94   stevebl   Created

//

//----------------------------------------------------------------------------

void CMainWindow::ExpandAll(long lIndex)

{

    LISTBOXELEMENT * pElement = (LISTBOXELEMENT *) SendMessage(_hlb, LB_GETITEMDATA, lIndex, 0);

    Expand(lIndex);

    if (pElement->uType == LBE_STORAGE)

    {

        unsigned nChildren = pElement->nChildren;

        while (nChildren--)

        {

            ExpandAll(lIndex + 1 + nChildren);

        }

    }

}

//+---------------------------------------------------------------------------

//

//  Member:     CMainWindow::Toggle

//

//  Synopsis:   toggles a node - expanding or collapsing as appropriate

//

//  Arguments:  [lIndex] - index of the node

//

//  History:    6-25-94   stevebl   Created

//

//----------------------------------------------------------------------------

void CMainWindow::Toggle(long lIndex)

{

    LISTBOXELEMENT * pElement = (LISTBOXELEMENT *) SendMessage(_hlb, LB_GETITEMDATA, lIndex, 0);

    if (pElement->fOpen)

    {

        Collapse(lIndex);

    }

    else

    {

        Expand(lIndex);

    }

}

//+---------------------------------------------------------------------------

//

//  Member:     CMainWindow::CreateStreamElement

//

//  Synopsis:   turns an IStream pointer into a listbox element

//

//  Arguments:  [pstm] - IStream pointer

//

//  Returns:    pointer to the newly created element

//              (NULL on failure)

//

//  History:    6-23-94   stevebl   Created

//

//----------------------------------------------------------------------------

LISTBOXELEMENT * CMainWindow::CreateStreamElement(IStream * pstm)

{

    LISTBOXELEMENT * plbe = new LISTBOXELEMENT;

    if (plbe)

    {

        plbe->uType = LBE_STREAM;

        plbe->fOpen = FALSE;

        plbe->pInterface = (void *) pstm;

        plbe->uIndent = 0;

        plbe->hwndView = NULL;

    }

    else

    {

        MessageBoxFromStringIds(

            _hwnd,

            _hInstance,

            IDS_OUTOFMEMORY,

            IDS_ERROR,

            MB_OK | MB_ICONEXCLAMATION);

    }

    return(plbe);

}

//+---------------------------------------------------------------------------

//

//  Member:     CMainWindow::CreateStorageElement

//

//  Synopsis:   turns an IStorage pointer into a listbox element

//

//  Arguments:  [pstg] - IStorage pointer

//

//  Returns:    pointer to the newly created element

//              (NULL on failure)

//

//  History:    6-23-94   stevebl   Created

//

//----------------------------------------------------------------------------

LISTBOXELEMENT * CMainWindow::CreateStorageElement(IStorage * pstg)

{

    LISTBOXELEMENT * plbe = new LISTBOXELEMENT;

    if (plbe)

    {

        plbe->uType = LBE_STORAGE;

        plbe->fOpen = FALSE;

        plbe->pInterface = (void *) pstg;

        plbe->uIndent = 0;

        plbe->nChildren = 0;

    }

    else

    {

        MessageBoxFromStringIds(

            _hwnd,

            _hInstance,

            IDS_OUTOFMEMORY,

            IDS_ERROR,

            MB_OK | MB_ICONEXCLAMATION);

    }

    return(plbe);

}

//+---------------------------------------------------------------------------

//

//  Member:     CMainWindow::DeleteElement

//

//  Synopsis:   deletes a listbox element and it's associated data

//

//  Arguments:  [plbe] - pointer to the element

//

//  History:    6-23-94   stevebl   Created

//

//  Notes:      This doesn't remove it from the list, it just frees up

//              the LISTBOXELEMENT pointer and it's data.

//

//----------------------------------------------------------------------------

void CMainWindow::DeleteElement(LISTBOXELEMENT * plbe)

{

    switch (plbe->uType)

    {

    case LBE_STORAGE:

        ((IStorage *) plbe->pInterface)->Release();

        break;

    case LBE_STREAM:

        if (plbe->fOpen)

        {

            DestroyWindow(plbe->hwndView);

        }

        ((IStream *) plbe->pInterface)->Release();

        break;

    }

    LPMALLOC pMalloc;

    CoGetMalloc(MEMCTX_TASK, &pMalloc);

    pMalloc->Free(plbe->pwcsName);

    pMalloc->Release();

    delete(plbe);

}

//+---------------------------------------------------------------------------

//

//  Member:     CMainWindow::LoadBitmaps

//

//  Synopsis:   loads the Storage and Stream bitmap arrays

//

//  Returns:    TRUE on success

//              FALSE on failure

//

//  Modifies:   _hbmpStorage and _hbmpStream

//

//  History:    6-24-94   stevebl   Created from code used in original DFView

//

//----------------------------------------------------------------------------

BOOL CMainWindow::LoadBitmaps(void)

{

    //

    // Get some metrics/info

    //

    UINT cxBitmap = BITMAPWIDTH;

    _cyBitmap = BITMAPHEIGHT;

    if (_cyBitmap < (UINT) _tm.tmHeight + _tm.tmExternalLeading)

    {

        _cyBitmap = _tm.tmHeight + _tm.tmExternalLeading;

    }

    UINT crHigh   = (COLORREF) GetSysColor(COLOR_HIGHLIGHT);

    UINT crNorm   = (COLORREF) GetSysColor(COLOR_WINDOW);

    HDC hdc = CreateCompatibleDC(NULL);

    if (!hdc)

    {

        goto ERRLOADBITMAP;

    }

    _hbmpStorage = CreateBitmap(

        4 * cxBitmap,

        _cyBitmap,

        GetDeviceCaps(hdc, PLANES),

        GetDeviceCaps(hdc, BITSPIXEL),

        NULL);

    _hbmpStream = CreateBitmap(

        4 * cxBitmap,

        _cyBitmap,

        GetDeviceCaps(hdc, PLANES),

        GetDeviceCaps (hdc, BITSPIXEL),

        NULL);

   DeleteDC(hdc);

   if (!_hbmpStorage || !_hbmpStream)

   {

        goto ERRLOADBITMAP;

   }

    //

    //  Load our bitmaps, and munge them to create

    //  our 4-bitmap "arrays".  Anything RED in the loaded

    //  bitmap will be considered clear.

    //

    if (!LoadAndStretch(

        _hInstance,

        _hbmpStorage,

        MAKEINTRESOURCE(BMP_STORAGE),

        cxBitmap,

        _cyBitmap,

        crHigh,

        crNorm))

    {

        goto ERRLOADBITMAP;

    }

    if (!LoadAndStretch(

        _hInstance,

        _hbmpStream,

        MAKEINTRESOURCE(BMP_STREAM),

        cxBitmap,

        _cyBitmap,

        crHigh,

        crNorm))

    {

        goto ERRLOADBITMAP;

    }

    return TRUE;

ERRLOADBITMAP:

    //

    // Bitmap loading error.

    //

    DeleteObject(_hbmpStorage);

    DeleteObject(_hbmpStream);

    _hbmpStorage = NULL;

    _hbmpStream = NULL;

    return FALSE;

}

//+---------------------------------------------------------------------------

//

//  Member:     CMainWindow::OpenFile

//

//  Synopsis:   attempts to open whatever docfile is named by _szFileName;

//

//  History:    6-24-94   stevebl   Created

//

//----------------------------------------------------------------------------

void CMainWindow::OpenFile(void)

{

    SendMessage(_hlb, LB_RESETCONTENT, 0, 0);

    IStorage * pstg;

#ifndef UNICODE

    // convert file name to a wide string

    OLECHAR wszFileName[MAX_PATH];

    mbstowcs(wszFileName, _szFileName, MAX_PATH);

#endif

    // get IStorage

    HRESULT hr = StgOpenStorage(

#ifdef UNICODE

        _szFileName,

#else

        wszFileName,

#endif

        NULL,

        STGM_TRANSACTED | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,

        NULL,

        0,

        &pstg);

    if (FAILED(hr))

    {

        MessageBoxFromStringIdsAndArgs(

            _hwnd,

            _hInstance,

            IDS_STGOPENSTORAGEFAILED,

            IDS_ERROR,

            MB_OK | MB_ICONEXCLAMATION,

#ifdef UNICODE

            _szFileName

#else

            wszFileName

#endif

            );

        return;

    }

    // Storage was opened successfully.

    LISTBOXELEMENT * plbe = CreateStorageElement(pstg);

    if (plbe)

    {

        IMalloc * pMalloc;

        CoGetMalloc(MEMCTX_TASK, &pMalloc);

        plbe->pwcsName = (LPOLESTR) pMalloc->Alloc(sizeof(OLECHAR) *  (lstrlen(_szFileName) + wcslen(ROOTSTGSTR) + 1));

        pMalloc->Release();

        if (plbe->pwcsName)

        {

            wcscpy(plbe->pwcsName, ROOTSTGSTR);

#ifdef UNICODE

            wcscpy(&plbe->pwcsName[wcslen(ROOTSTGSTR)], _szFileName);

#else

            mbstowcs(&plbe->pwcsName[wcslen(ROOTSTGSTR)], _szFileName, strlen(_szFileName) + 1);

#endif

        }

        if (SendMessage(_hlb, LB_INSERTSTRING, 0, (LPARAM) plbe) == LB_ERRSPACE)

        {

            MessageBoxFromStringIds(

                _hwnd,

                _hInstance,

                IDS_INSERTSTRINGFAILED,

                IDS_ERROR,

                MB_OK | MB_ICONEXCLAMATION);

            DeleteElement(plbe);

        }

        else

        {

            SendMessage(_hlb, LB_SETCURSEL, 0, 0);

        }

    }

}

//+---------------------------------------------------------------------------

//

//  Function:   Exists

//

//  Synopsis:   simple function to test for the existance of a file

//

//  History:    6-16-93   stevebl   Created

//

//----------------------------------------------------------------------------

int Exists(TCHAR *sz)

{

    HANDLE h;

    h = CreateFile(sz,

        GENERIC_READ,

        FILE_SHARE_READ | FILE_SHARE_WRITE,

        NULL,

        OPEN_EXISTING,

        0,

        0);

    if (h != INVALID_HANDLE_VALUE)

    {

        CloseHandle(h);

        return(1);

    }

    return (0);

}


STRMVWR.H  (DFVIEW Sample)

//+---------------------------------------------------------------------------

//

//  Microsoft Windows

//  Copyright (C) Microsoft Corporation, 1992 - 1994.

//

//  File:       strmvwr.h

//

//  Contents:   Stream viewer window class definition.

//

//  Classes:    CStreamView

//

//  Functions:

//

//  History:    6-27-94   stevebl   Created

//

//----------------------------------------------------------------------------

#ifndef __STRMVWR_H__

#define __STRMVWR_H__

#include <cwindow.h>

#include "dfv.h"

#include "mwclass.h"

#ifdef __cplusplus

//+---------------------------------------------------------------------------

//

//  Class:      CStreamView

//

//  Purpose:    implements a stream viewer window

//

//  Interface:  CStreamView  -- constructor

//              InitInstance -- instantiates an instance of the viewer

//

//  History:    6-27-94   stevebl   Created

//

//  Notes:      only the public interface is described by this comment

//

//----------------------------------------------------------------------------

class CStreamView: public CHlprWindow

{

public:

    CStreamView(HWND hlb, LISTBOXELEMENT * ple);

    BOOL InitInstance(HINSTANCE hInst, int nCmdShow);

protected:

    ~CStreamView();

    LRESULT WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam);

private:

    HWND _hlbParent;

    HWND _hlb;

    LONG _lIndex;

    LISTBOXELEMENT * _ple;

    COLORREF _crTextHigh;

    COLORREF _crBkHigh;

    COLORREF _crTextNorm;

    COLORREF _crBkNorm;

    WORD _wWidth;

    DWORD _cbSize;

    TEXTMETRIC _tm;

    HFONT _hfListBox;

};

#endif // __cplusplus

#endif // __STRMVWR_H__


STRMVWR.CXX  (DFVIEW Sample)

//+---------------------------------------------------------------------------

//

//  Microsoft Windows

//  Copyright (C) Microsoft Corporation, 1992 - 1994.

//

//  File:       stmvwr.cxx

//

//  Contents:   implementation for the stream viewer window class

//

//  Classes:    CStreamView

//

//  Functions:

//

//  History:    6-27-94   stevebl   Created

//

//----------------------------------------------------------------------------

#include <windows.h>

#include <ole2.h>

#include "strmvwr.h"

#define BYTESPERLINE 16

#define DIVISIONPOINTS 8

//+---------------------------------------------------------------------------

//

//  Member:     CStreamView::CStreamView

//

//  Synopsis:   constructor

//

//  Arguments:  [hlb]    - handle to CMainWindow's listbox

//              [ple]    - pointer to the LISTBOXELEMENT structure for this

//                         stream

//

//  History:    6-27-94   stevebl   Created

//

//----------------------------------------------------------------------------

CStreamView::CStreamView(HWND hlb, LISTBOXELEMENT * ple)

{

    _hlbParent = hlb;

    _ple = ple;

    _hfListBox = NULL;

}

//+---------------------------------------------------------------------------

//

//  Member:     CStreamView::~CStreamView

//

//  Synopsis:   destructor

//

//  History:    6-27-94   stevebl   Created

//

//----------------------------------------------------------------------------

CStreamView::~CStreamView()

{

    _ple->fOpen = FALSE;

    if (_hfListBox)

    {

        DeleteObject(_hfListBox);

    }

    InvalidateRect(_hlbParent, NULL, FALSE);

}

//+---------------------------------------------------------------------------

//

//  Member:     CStreamView::InitInstance

//

//  Synopsis:   creates and shows the stream viewer window

//

//  Arguments:  [hInstance] - the application's instance handle

//              [nCmdShow]  - command to pass to ShowWindow

//

//  Returns:    TRUE on success

//              FALSE on failure

//

//  History:    6-27-94   stevebl   Created

//

//  Notes:      must only be called once immediately after class construction

//

//----------------------------------------------------------------------------

BOOL CStreamView::InitInstance(HINSTANCE hInstance, int nCmdShow)

{

    IStream * pstm = (IStream * ) _ple->pInterface;

    STATSTG statstg;

    HRESULT hr = pstm->Stat(&statstg, STATFLAG_NONAME);

    if (FAILED(hr))

    {

        MessageBoxFromStringIdsAndArgs(

            _hwnd,

            _hInstance,

            IDS_STMSTATFAILED,

            IDS_ERROR,

            MB_OK | MB_ICONEXCLAMATION,

            hr

            );

        return(FALSE);

    }

    _cbSize = statstg.cbSize.LowPart;

    TCHAR szStreamTitleText[MAX_STRING_LENGTH];

    if (!LoadString(_hInstance, IDS_STMTITLETEXT, szStreamTitleText, MAX_STRING_LENGTH))

    {

        lstrcpy(szStreamTitleText, TEXT(""));

    }

    TCHAR * szTitle = new TCHAR[lstrlen(TEXT("  [0x00000000 bytes]"))

        + lstrlen(szStreamTitleText) + wcslen(_ple->pwcsName) + 1];

    if (szTitle)

    {

        wsprintf(szTitle, TEXT("%s %ws [0x%08X bytes]"), szStreamTitleText, _ple->pwcsName, _cbSize);

    }

    // Note, the Create method sets the _hwnd member for me so I don't

    // need to set it myself.

    HWND hwnd = Create(

        TEXT(STREAM_VIEW_CLASS_NAME),

        szTitle,

        WS_OVERLAPPED

            | WS_MINIMIZEBOX

            | WS_MAXIMIZEBOX

            | WS_SYSMENU

            | WS_THICKFRAME,

        CW_USEDEFAULT,

        CW_USEDEFAULT,

        CW_USEDEFAULT,

        CW_USEDEFAULT,

        NULL,

        NULL,

        hInstance);

    delete[] szTitle;

    if (!hwnd)

    {

        return(FALSE);

    }

    ShowWindow(hwnd, nCmdShow);

    UpdateWindow(hwnd);

    return(TRUE);

}

//+---------------------------------------------------------------------------

//

//  Member:     CStreamView::WindowProc

//

//  Synopsis:   window procedure for the stream viewer window

//

//  Arguments:  [uMsg]   - Window's message

//              [wParam] - first message parameter

//              [lParam] - second message parameter

//

//  History:    6-27-94   stevebl   Created

//

//----------------------------------------------------------------------------

LRESULT CStreamView::WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam)

{

    switch (uMsg)

    {

    case WM_CREATE:

        {

            RECT rc;

            GetClientRect(_hwnd, &rc);

            // record the width before we create the list box

            _wWidth = (WORD) rc.right;

            HDC hdc = GetDC(_hwnd);

            LOGFONT lf;

            memset(&lf, 0, sizeof(LOGFONT));

            // Get an 8 point Courier font.

            lf.lfHeight = -MulDiv(8, GetDeviceCaps(hdc, LOGPIXELSY), 72);

            lstrcpy(lf.lfFaceName, TEXT("Courier"));

            _hfListBox = CreateFontIndirect(&lf);

            HFONT hfOld = (HFONT) SelectObject(hdc, _hfListBox);

            GetTextMetrics(hdc, &_tm);

            SelectObject(hdc, hfOld);

            ReleaseDC(_hwnd, hdc);

            // create the child listbox

            _hlb = CreateWindow(

                TEXT("listbox"),

                TEXT(""),

                LBS_OWNERDRAWFIXED |

                    WS_CHILD |

                    WS_VISIBLE |

                    WS_VSCROLL |

                    LBS_NOINTEGRALHEIGHT |

                    LBS_NODATA,

                0,

                0,

                rc.right,

                rc.bottom,

                _hwnd,

                (HMENU) IDC_LISTBOX,

                _hInstance,

                NULL);

            if (NULL == _hlb)

            {

                // abort window creation

                return(-1);

            }

            SetFocus(_hlb);

            SendMessage(

                _hlb,

                LB_SETCOUNT,

                (WPARAM)((_cbSize / BYTESPERLINE) + (_cbSize % BYTESPERLINE ? 1 : 0)),

                0);

            SendMessage(_hlb, WM_SETFONT, (WPARAM) _hfListBox, 0);

            SendMessage(_hlb, LB_SETCURSEL, 0, 0);

            _crTextHigh = GetSysColor(COLOR_HIGHLIGHTTEXT);

            _crTextNorm = GetSysColor(COLOR_WINDOWTEXT);

            _crBkHigh = GetSysColor(COLOR_HIGHLIGHT);

            _crBkNorm = GetSysColor(COLOR_WINDOW);

        }

        break;

    case WM_SETFOCUS:

        {

            if (_hlb)

            {

                SetFocus(_hlb);

            }

        break;

        }

    case WM_MEASUREITEM:

        {

            LPMEASUREITEMSTRUCT lpmis = (LPMEASUREITEMSTRUCT) lParam;

            lpmis->itemHeight = _tm.tmHeight + _tm.tmExternalLeading;

            lpmis->itemWidth = _wWidth;

            return(TRUE);

        }

    case WM_DRAWITEM:

        {

            LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT) lParam;

            if (-1 == lpdis->itemID)

            {

                // no items in the listbox

                break;

            }

            // draw the item

            switch (lpdis->itemAction)

            {

            case ODA_SELECT:

            case ODA_DRAWENTIRE:

                {

                    // draw the listbox item

                    LONG lStartByte = lpdis->itemID * BYTESPERLINE;

                    // NOTE:  The following string is actually a bit larger

                    // than it has to be.  The minimum size for this string

                    // is acutally somewhere between 5 and 6 bytes for each

                    // byte (plus 12) in the stream that is to be displayed.

                    // Doing it this way wastes a little space but it's much

                    // simpler, it's faster, and it's less prone to error

                    // than dynamically computing it each time.

                    TCHAR szLine[BYTESPERLINE * 6 + 12];

                    unsigned cch;

                    wsprintf(szLine, TEXT("0x%08X:"), lStartByte);

                    for (cch = BYTESPERLINE * 6 + 12; (unsigned) lstrlen(TEXT("0x12345678:")) < cch--; )

                    {

                        szLine[cch] = TEXT(' ');

                    }

                    IStream * pstm = (IStream *) _ple->pInterface;

                    BYTE rgb[BYTESPERLINE];

                    LARGE_INTEGER dlibMove;

                    dlibMove.HighPart = 0;

                    // If we ever get a stream that's big enough to require

                    // that the HiPart get set, then nobody would want to

                    // browse that much data anyway!

                    dlibMove.LowPart = lStartByte;

                    HRESULT hr = pstm->Seek(dlibMove, STREAM_SEEK_SET, NULL);

                    if (FAILED(hr))

                    {

                        MessageBoxFromStringIdsAndArgs(

                            _hwnd,

                            _hInstance,

                            IDS_STMSEEKFAILED,

                            IDS_ERROR,

                            MB_OK | MB_ICONEXCLAMATION,

                            hr

                            );

                        return(FALSE);

                    }

                    ULONG cbRead;

                    hr = pstm->Read(rgb, BYTESPERLINE, &cbRead);

                    if (FAILED(hr))

                    {

                        MessageBoxFromStringIdsAndArgs(

                            _hwnd,

                            _hInstance,

                            IDS_STMREADFAILED,

                            IDS_ERROR,

                            MB_OK | MB_ICONEXCLAMATION,

                            hr

                            );

                        return(FALSE);

                    }

                    for (cch = 0; cch < cbRead; cch++)

                    {

                        TCHAR szTemp[3];

                        wsprintf(szTemp, TEXT("%02X"), rgb[cch]);

                        szLine[cch * 3 + cch / DIVISIONPOINTS + 12] = szTemp[0];

                        szLine[cch * 3 + cch / DIVISIONPOINTS + 13] = szTemp[1];

                        char ch = rgb[cch];

                        if (ch < ' ')

                        {

                            ch = '.';

                        }

                        // this is a little trick to get the character in the

                        // correct type of string (UNICODE or not)

                        wsprintf(szTemp, TEXT("%c"), ch);

                        szLine[cch + 13 + cch / DIVISIONPOINTS + 3 * BYTESPERLINE + BYTESPERLINE / DIVISIONPOINTS] = szTemp[0];

                    }

                    szLine[cch + 13 + cch / DIVISIONPOINTS + 3 * BYTESPERLINE + BYTESPERLINE / DIVISIONPOINTS] = 0;

                    SIZE sizeText;

                    RECT rcItem = lpdis->rcItem;

                    GetTextExtentPoint32(

                        lpdis->hDC,

                        szLine,

                        lstrlen(szLine),

                        &sizeText);

                    rcItem.right = rcItem.left + sizeText.cx;

                    COLORREF crOldText = SetTextColor(

                        lpdis->hDC,

                        (lpdis->itemState & ODS_SELECTED) ? _crTextHigh : _crTextNorm);

                    COLORREF crOldBack = SetBkColor(

                        lpdis->hDC,

                        (lpdis->itemState & ODS_SELECTED) ? _crBkHigh : _crBkNorm);

                    ExtTextOut(

                        lpdis->hDC,

                        rcItem.left,

                        rcItem.top,

                        ETO_OPAQUE | ETO_CLIPPED,

                        &rcItem,

                        szLine,

                        lstrlen(szLine),

                        NULL);

                    SetTextColor(lpdis->hDC, crOldText);

                    SetBkColor(lpdis->hDC, crOldBack);

                }

                break;

            case ODA_FOCUS:

                break;

            }

            return(TRUE);

        }

    case WM_SIZE:

        {

            _wWidth = LOWORD(lParam);

            WORD wHeight = HIWORD(lParam);

            if (_hlb)

            {

                SetWindowPos(_hlb, NULL, 0, 0, _wWidth, wHeight, SWP_NOMOVE | SWP_NOZORDER);

            }

            break;

        }

    case WM_COMMAND:

    case WM_QUIT:

    case WM_CLOSE:

    default:

        return(DefWindowProc(_hwnd, uMsg, wParam, lParam));

    }

    return(FALSE);

}


WINMAIN.CXX  (DFVIEW Sample)

//+---------------------------------------------------------------------------

//

//  Microsoft Windows

//  Copyright (C) Microsoft Corporation, 1992 - 1994.

//

//  File:       winmain.cxx

//

//  Contents:   main entry point for Stereo Shop

//

//  Classes:

//

//  Functions:  WinMain

//

//  History:    6-08-94   stevebl   Created

//

//----------------------------------------------------------------------------

#include "dfv.h"

#include "mwclass.h"

#include <ole2ver.h>

//+---------------------------------------------------------------------------

//

//  Function:   InitApplication

//

//  Synopsis:   initializes the application and registers its window class

//              (called once for all instances)

//

//  Arguments:  [hInstance] - handle to the first instance

//

//  Returns:    TRUE on success

//

//  History:    4-11-94   stevebl   Created for MFract

//              6-08-94   stevebl   Stolen from MFract

//

//----------------------------------------------------------------------------

BOOL InitApplication(HINSTANCE hInstance)

{

    WNDCLASS wc;

    wc.style = 0;

    wc.lpfnWndProc = &WindowProc;

    wc.cbClsExtra = 0;

    wc.cbWndExtra = 0;

    wc.hInstance = hInstance;

    wc.hIcon = LoadIcon(hInstance, TEXT("StreamIcon"));

    wc.hCursor = (HCURSOR) LoadCursor(NULL, IDC_ARROW);

    wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);

    wc.lpszMenuName = NULL;

    wc.lpszClassName = TEXT(STREAM_VIEW_CLASS_NAME);

    ATOM aReturn = RegisterClass(&wc);

    if (!aReturn)

    {

        return(aReturn);

    }

    wc.style = CS_DBLCLKS;

    wc.hIcon = LoadIcon(hInstance, TEXT("AppIcon"));

    wc.lpszMenuName = TEXT(MAIN_WINDOW_CLASS_MENU_STR);

    wc.lpszClassName = TEXT(MAIN_WINDOW_CLASS_NAME);

    return(RegisterClass(&wc));

}

//+---------------------------------------------------------------------------

//

//  Function:   WinMain

//

//  Synopsis:   main window proceedure

//

//  Arguments:  [hInstance]     - instance handle

//              [hPrevInstance] - handle of the previous instance (if any)

//              [lpCmdLine]     - pointer to the command line

//              [nCmdShow]      - show state

//

//  History:    4-11-94   stevebl   Created for MFract

//              6-08-94   stevebl   Stolen from MFract

//

//  Notes:      initializes application and starts message loop

//

//----------------------------------------------------------------------------

extern "C" int PASCAL WinMain(HINSTANCE hInstance,

            HINSTANCE hPrevInstance,

            LPSTR lpCmdLine,

            int nCmdShow)

{

    DWORD dwBuildVersion = CoBuildVersion();

    if (HIWORD(dwBuildVersion) != rmm || LOWORD(dwBuildVersion) < rup)

    {

        // alert the caller that the OLE version is incompatible

        // with this build.

        MessageBoxFromStringIdsAndArgs(

            NULL,

            hInstance,

            IDS_OLEINCOMPATIBLE,

            IDS_ERROR,

            MB_OK | MB_ICONEXCLAMATION,

            rmm, rup);

        return(FALSE);

    }

    if (FAILED(CoInitialize(NULL)))

    {

        // alert the caller that OLE couldn't be initialized

        MessageBoxFromStringIds(

            NULL,

            hInstance,

            IDS_OLEINITFAILED,

            IDS_ERROR,

            MB_OK | MB_ICONEXCLAMATION);

        return(FALSE);

    }

    if (!hPrevInstance)

    {

        if (!InitApplication(hInstance))

        {

            CoUninitialize();

            return(FALSE);

        }

    }

    CMainWindow * pw = new CMainWindow;

    if (pw == NULL)

    {

        CoUninitialize();

        return(FALSE);

    }

    if (!pw->InitInstance(hInstance, nCmdShow))

    {

        // Note, if InitInstance has failed then it would have

        // already deleted pw for me so I don't delete it here.

        // This is because when WM_CREATE returns -1 (failure)

        // Windows sends the WM_DESTROY message to the window

        // and the the CHlprWindow class destroys itself whenever

        // it receives this message.

        CoUninitialize();

        return(FALSE);

    }

    // check command line and try and load as a file

    if (strlen(lpCmdLine) > 0)

    {

#ifdef UNICODE

        mbstowcs(pw->_szFileName, lpCmdLine, MAX_PATH - 1);

#else

        strncpy(pw->_szFileName, lpCmdLine, MAX_PATH - 1);

#endif

        pw->OpenFile();

    }

    MSG msg;

    HACCEL haccel = LoadAccelerators(hInstance, TEXT("AppAccel"));

    if (haccel == NULL)

    {

        CoUninitialize();

        return(FALSE);

    }

    while (GetMessage(&msg, NULL, 0, 0))

    {

        if (!TranslateAccelerator(

            pw->GetHwnd(),

            haccel,

            &msg))

        {

            TranslateMessage(&msg);

            DispatchMessage(&msg);

        }

    }

    CoUninitialize();

    return(msg.wParam);

}


 DISPCALC

--------------------------------------- OLE Automation Sample Program: Dispcalc ---------------------------------------

DispCalc is a simple accumulator-based calculator.  Its user interface consists of buttons for the numbers (0-9),  the operators (+, -, *, /), and some other necessary buttons (C for Clear, = for evaluation).  Its programmability interface consists of one object, which is described below.

The ProgID for dispcalc's only object is "DispCalc.Application".   An instance of this object can be created by executing the  following lines of code in Visual Basic or DispTest:

  Sub Foo
    Dim MyCalculator as Object

    Set MyCalculator = CreateObject("DispCalc.Application")
    . . .
  End Sub

----------------- Program Structure ----------------- Dispcalc uses INTERFACEDATA and CreateStdDispatch in order to  implement the IDispatch interface.

------------------------- Properties for the object -------------------------

Name	Type	Description --------------------------- Value	VT_I4	Same as the value for the accumulator.

Accum	VT_I4	The value that is in the accumulator of the 	calculator.

Opnd	VT_I4	The operand.  This is the number which is 	currently being entered.

Op	VT_I2	The operator that is currently being used. 	This is an enumeration: 	const OP_NONE = 0 	const OP_PLUS = 1 	const OP_MINUS = 2 	const OP_MULT = 3

----------------------------- Methods defined on the object -----------------------------

Name	Description --------------------------- Eval() as Boolean	If there is an operator, apply it to 	accumulator and the operand, placing the 	result in the accumulator.

The return value indicates success or 	failure.

Clear()	Resets the calculator.  This sets 	Op to OP_NONE, and both Accum and 	Opnd to 0. Display()	Updates the display of the calculator. 	(Other operations do not do this.)

Quit()	Close the calculator.

Button(b as string) as Boolean 	Press the indicated button and return 	success or failure. 	 	Valid string values are: 	+, -, *, + 	0-9 	c, C 	= 	 	Note that you may also pass the numbers 	0-9 and these will be converted to strings 	automatically.

--------------------------- Shortcomings of this sample --------------------------- 1. Property and method names should not be abbreviated. For example, the "Opnd" property should be the "Operand"  property.

2. Since the object is the application object, it should have Name and Version properties, which are read-only.


 MAKEFILE  (DISPCALC Sample)

##############################################################################

#

#  (c) Copyright Microsoft Corp. 1992-1993 All Rights Reserved

#

#  File:

#

#    makefile - makefile for spoly2.exe

#

#  Purpose:

#

#    Builds the OLE 2.0 sample IDispatch server, dispcalc.exe.

#

#

#  Usage:

#

#     NMAKE                     ; build with defaults

#     or: NMAKE option          ; build with the given option(s)

#     or: NMAKE clean           ; erase all compiled files

#

#     option:

#         dev = [win16 | win32] ; dev=win32 is the default

#         DEBUG=[0|1]           ; DEBUG=1 is the default

#

#  Notes:

#

#    This makefile assumes that the PATH, INCLUDE and LIB environment

#    variables are setup properly.

#

##############################################################################

##########################################################################

#

# Default Settings

#

!if "$(dev)" == ""

dev = win32

!endif

!if !("$(dev)" == "win16" || "$(dev)" == "win32")

!error Invalid dev option, choose from [win16 | win32]

!endif

!if "$(dev)" == "win16"

TARGET  = WIN16

!endif

!if "$(dev)" == "win32"

TARGET  = WIN32

!endif

!ifdef NODEBUG

DEBUG = 0

!endif

!if "$(DEBUG)" == "0"

NODEBUG = 1

!endif

!if "$(DEBUG)" == ""

DEBUG = 1

!endif

##########################################################################

#

# WIN16 Settings

#

!if "$(TARGET)" == "WIN16"

CC   = cl

LINK = link

RCFLAGS = -dWIN16

CFLAGS = -c -W3 -AM -GA -GEs -DWIN16

LINKFLAGS = /NOD /NOI /BATCH /ONERROR:NOEXE

LIBS = libw.lib mlibcew.lib

!if "$(DEBUG)" == "1"

CFLAGS = $(CFLAGS) -Od -Zi -D_DEBUG $(CL)

LINKFLAGS = $(LINKFLAGS) /COD

!else

CFLAGS = $(CFLAGS) -Ox $(CL)

LINKFLAGS = $(LINKFLAGS) /FAR /PACKC

!endif

!endif

##########################################################################

#

# WIN32 Settings

#

!if "$(TARGET)" == "WIN32"

!include <$(MSTOOLS)\samples\ole\include\olesampl.mak>

CC = $(cc)

CFLAGS = $(cflags) $(cvarsmt) -DINC_OLE2 -DUNICODE $(cdebug)

!ifndef NODEBUG

CFLAGS = $(CFLAGS) -D_DEBUG

!endif

LINK = $(link)

LINKFLAGS = $(linkdebug) $(guilflags)

RCFLAGS = -DWIN32

!endif

##########################################################################

#

# Build rules

#

.cpp.obj:

    @echo Compiling $<...

    $(CC) $<

.c.obj:

    @echo Compiling $<...

    $(CC) $<

##########################################################################

#

# Application Settings

#

APPS = dispcalc

!if "$(TARGET)" == "WIN16"

LIBS = ole2.lib compobj.lib ole2disp.lib $(LIBS)

!else

!if "$(TARGET)" == "WIN32"

LIBS = $(olelibsmt)

!endif

!endif

OBJS = \

        winmain.obj     \

        idata.obj       \

        dispcalc.obj    \

        clsid.obj

##########################################################################

#

# Default Goal

#

goal : setflags $(APPS).exe

setflags :

        set CL=$(CFLAGS)

##########################################################################

#

# Clean (erase) generated files

#

clean :

    if exist *.obj       del *.obj

    if exist $(APPS).exe del $(APPS).exe

    if exist $(APPS).map del $(APPS).map

    if exist $(APPS).res del $(APPS).res

##########################################################################

#

# Application Build (WIN16 Specific)

#

!if "$(TARGET)" == "WIN16"

$(APPS).exe : $(OBJS) $(APPS).def $(APPS).res $(APPS).ico

        link $(LINKFLAGS) @<<

$(OBJS),

$@,,

$(LIBS),

$(APPS).def

<<

        rc -k -t $(APPS).res $@

!endif

##########################################################################

#

# Application Build (WIN32 Specific)

#

!if "$(TARGET)" == "WIN32"

$(APPS).exe : $(OBJS) $(APPS).def $(APPS).res $(APPS).ico

      $(LINK) @<<

        $(LINKFLAGS)

        -out:$@

        -map:$*.map

        $(OBJS)

        $(APPS).res

        $(LIBS)

<<

!endif

##########################################################################

#

# Application Build (Common)

#

$(APPS).res : $(APPS).rc

        rc  $(RCFLAGS) -r -fo$@ $?

##########################################################################

#

# Dependencies

#

winmain.obj: winmain.cpp dispcalc.h

    $(CC) winmain.cpp

idata.obj: idata.cpp dispcalc.h

    $(CC) idata.cpp

dispcalc.obj: dispcalc.cpp dispcalc.h

    $(CC) dispcalc.cpp

clsid.obj: clsid.c clsid.h

    $(CC) clsid.c


 CLSID.H  (DISPCALC Sample)

/***

*clsid.h

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*  Information Contained Herein Is Proprietary and Confidential.

*

*Purpose:

*  This file defines the CLSIDs

*

*Implementation Notes:

*

*****************************************************************************/

DEFINE_GUID(CLSID_CCalc, 0x00020467, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46);

#ifdef INITGUID

# ifdef _MAC

DEFINE_GUID(GUID_NULL, 0L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);

DEFINE_GUID(IID_IDispatch, 0x00020400, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46);

DEFINE_GUID(IID_IEnumVARIANT, 0x00020404, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46);

DEFINE_GUID(IID_IUnknown, 0x00000000, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46);

DEFINE_GUID(IID_IClassFactory, 0x00000001, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46);

# endif

#endif


 CLSID.C  (DISPCALC Sample)

/***

*clsid.c

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*  Information Contained Herein Is Proprietary and Confidential.

*

*Purpose:

*  This file allocates and initializes the CLSIDs.

*

*****************************************************************************/

#ifdef _PPCMAC

#pragma data_seg ("_FAR_DATA")

#pragma data_seg ( )

#endif //_PPCMAC

#ifdef _MAC

# include <Types.h>

#ifdef _MSC_VER

# include <Processe.h>

# include <AppleEve.h>

#else //_MSC_VER

# include <Processes.h>

# include <AppleEvents.h>

#endif //_MSC_VER

#else

# include <windows.h>

#endif

#ifndef WIN32

#include <compobj.h>

#endif //!WIN32

// this redefines the DEFINE_GUID() macro to do allocation.

//

#include <initguid.h>

#ifndef INITGUID

# define INITGUID

#endif

// due to the previous header, including this causes the DEFINE_GUID

// definitions in the following header(s) to actually allocate data.

//

#include "clsid.h"


 DISPCALC.DEF  (DISPCALC Sample)

NAME         DISPCALC

DESCRIPTION  'IDispatch Calculator'

EXETYPE      WINDOWS

STUB         'WINSTUB.EXE'

CODE         PRELOAD MOVEABLE DISCARDABLE

DATA         PRELOAD MULTIPLE

HEAPSIZE     4096

STACKSIZE    8192


 DISPCALC.H  (DISPCALC Sample)

/***

*dispcalc.h

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*  Information Contained Herein Is Proprietary and Confidential.

*

*Purpose:

*  UNDONE

*

*

*Implementation Notes:

*

*****************************************************************************/

#include "hostenv.h"

#include "resource.h"

#include "clsid.h"

#ifndef CLASS

# ifdef __TURBOC__

#  define CLASS class huge

# else

#  define CLASS class FAR

# endif

#endif

#pragma warning(disable:4355)

#ifdef _MAC

# define NEARDATA

#else

# ifdef WIN32

#  define NEARDATA

# else

#  define NEARDATA __near

# endif

#endif

#ifdef _MAC

# define UNUSED(X) ((void)(void*)&(X))

#else

# define UNUSED(X) (X)

#endif

#define DIM(X) (sizeof(X)/sizeof(X[0]))

// forward decl

CLASS CCalc;

// Introduced "calculator" interface

//

// This class implementes core arithmetic functionality

// (such as it is) *and* is the interface that will be

// exposed via IDispatch for external programmability.

#if defined(_MAC) && !(!defined(applec) || defined(__SC__) || defined(_MSC_VER))

// Mac Note: The default implementation of IDispatch places

// a couple of requirements on the layout of an instance that

// in can invoke on.

//

//   1. It assumes that the vtable pointer is at offset 0

//      from the beginning of the instance. This appears

//      to always be the case if the class derives from

//      an interface, and hence the games I play below

//      creating a stub _CArith interface containing a

//      single pure virtual function. The only reason for

//      this is to ensure that the vtable ptr is at offset

//      0 when this class is a member of CCalc. If your

//      class derives from an Ole interface, then you are ok.

//

//   2. It assumes that the vtable is a simple array of

//      function pointers, with index zero reserved. In

//      order to ensure this, the class must derive from

//      SingleObject. Note that IUnknown derives from SingleObject,

//      so if your class derives from any Ole interface, then

//      you are also ok - otherwise you need to explicitly

//      derive from SingleObject as I have done below.

//

//  (The above comments apply to MPW C++ v3.3)

//

interface _CArith : public SingleObject

{

    STDMETHOD_(void,  put_Accum)(long l) PURE;

};

CLASS CArith : public _CArith

#else

CLASS CArith

#endif

{

public:

#if defined(_MAC)

    BEGIN_INTERFACE

#endif //_MAC

    STDMETHOD_(void,  put_Accum)(long l);

    STDMETHOD_(long,  get_Accum)(void);

    STDMETHOD_(void,  put_Opnd)(long l);

    STDMETHOD_(long,  get_Opnd)(void);

    STDMETHOD_(void,  put_Op)(short op);

    STDMETHOD_(short, get_Op)(void);

    STDMETHOD_(short, Eval)(void);

    STDMETHOD_(void,  Clear)(void);

    STDMETHOD_(void,  Display)(void);

    STDMETHOD_(void,  Quit)(void);

    STDMETHOD_(short, Button)(BSTR button);

    // the following method is internal, and not exposed for programmability

    int ButtonPush(int button);

    CArith::CArith(CCalc FAR* pcalc){

      m_pcalc = pcalc;

      Clear();

    }

    enum states { STATE_LOPND, STATE_OP, STATE_ROPND, STATE_EVAL };

private:

    CCalc FAR*  m_pcalc;

    short	m_op;

    long	m_opnd;

    long	m_accum;

    enum states m_state;

};

CLASS CCalc : public IUnknown {

public:

    friend CArith;

    static CCalc FAR* Create();

    STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppv);

    STDMETHOD_(unsigned long, AddRef)(void);

    STDMETHOD_(unsigned long, Release)(void);

    CCalc::CCalc();

#ifdef _MAC

    DialogPtr m_pdlg;

#else

    HWND m_hwnd;

#endif

    CArith m_arith;

private:

    unsigned long m_refs;

    IUnknown FAR* m_punkStdDisp;

};

enum operators {

    OP_NONE = 0,

    OP_PLUS,

    OP_MINUS,

    OP_MULT,

    OP_DIV

};

// the following enum defines method indices used by the

// default IDispatch implementation - DispInvoke().

//

// Note: these must match the order of the preceeding declarations

//

enum IMETH_CARITH {

    IMETH_PUTACCUM = 0,

    IMETH_GETACCUM,

    IMETH_PUTOPERAND,

    IMETH_GETOPERAND,

    IMETH_PUTOPERATOR,

    IMETH_GETOPERATOR,

    IMETH_EVAL,

    IMETH_CLEAR,

    IMETH_DISPLAY,

    IMETH_QUIT,

    IMETH_BUTTON,

    // Define the "property" indices. these are defined to be

    // the first index in a set/get property method pair. These

    // definitions are used to build the METHODDATA that drives

    // our implementation of IDispatch. see cdisp.cpp.

    //

    IMETH_ACCUM    = IMETH_PUTACCUM,

    IMETH_OPERAND  = IMETH_PUTOPERAND,

    IMETH_OPERATOR = IMETH_PUTOPERATOR

};

// the following enum defines the IDs used by IDispatch

//

// Note: these values do *not* depend on order of declaration,

// but are sensitive to the kind of the method - ie, if a get/set

// method pair implements a property, then they need to share

// an ID.

//

// Note: by assigning "accum" the ID 'DISPID_VALUE', we are

// choosing to expose it as the default "value" property.

//

enum IDMEMBER_CARITH {

    IDMEMBER_ACCUM = DISPID_VALUE,	// the default property

    IDMEMBER_OPERAND,

    IDMEMBER_OPERATOR,

    IDMEMBER_EVAL,

    IDMEMBER_CLEAR,

    IDMEMBER_DISPLAY,

    IDMEMBER_QUIT,

    IDMEMBER_BUTTON

};

// the CCalc Class Factory

//

CLASS CCalcCF : public IClassFactory {

public:

    static IClassFactory FAR* Create();

    STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppv);

    STDMETHOD_(unsigned long, AddRef)(void);

    STDMETHOD_(unsigned long, Release)(void);

    STDMETHOD(CreateInstance)(

      IUnknown FAR* punkOuter, REFIID riid, void FAR* FAR* ppv);

#ifdef _MAC

    STDMETHOD(LockServer)(unsigned long fLock);

#else

    STDMETHOD(LockServer)(BOOL fLock);

#endif

    CCalcCF() { m_refs = 1; }

private:

    unsigned long m_refs;

};

extern HRESULT InitOle(void);

extern HRESULT UninitOle(void);

extern CCalc FAR* g_pcalc;


 DISPCALC.RC  (DISPCALC Sample)

#include <windows.h>

#include "resource.h"

DispCalc ICON dispcalc.ico

DispCalc DIALOG DISCARDABLE  0, 0, 92, 114

STYLE    WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX

CLASS    "DispCalc"

#ifdef WIN32

CAPTION  "DispCalc (32-bit)"

#else //WIN32

CAPTION  "DispCalc"

#endif //WIN32

BEGIN

    PUSHBUTTON "0", IDC_ZERO,          9, 90, 14, 15

    PUSHBUTTON "1", IDC_ONE,           9, 70, 15, 16

    PUSHBUTTON "2", IDC_TWO,          29, 70, 16, 15

    PUSHBUTTON "3", IDC_THREE,        49, 70, 15, 15

    PUSHBUTTON "4", IDC_FOUR,          9, 50, 15, 14

    PUSHBUTTON "5", IDC_FIVE,         29, 50, 15, 15

    PUSHBUTTON "6", IDC_SIX,          49, 50, 15, 15

    PUSHBUTTON "7", IDC_SEVEN,         9, 30, 15, 15

    PUSHBUTTON "8", IDC_EIGHT,        29, 30, 15, 15

    PUSHBUTTON "9", IDC_NINE,         49, 30, 15, 15

    PUSHBUTTON "=", IDC_EQUALS,       49, 90, 14, 15

    PUSHBUTTON "+", IDC_PLUS,         69, 30, 15, 15

    PUSHBUTTON "-", IDC_MINUS,        69, 50, 14, 15

    PUSHBUTTON "*", IDC_MULT,         69, 70, 15, 15

    PUSHBUTTON "/", IDC_DIV,          69, 90, 15, 15

    PUSHBUTTON "C", IDC_CLEAR,        29, 90, 16, 15

    EDITTEXT        IDC_DISPLAY,       9,  6, 76, 15, ES_MULTILINE | ES_RIGHT | ES_AUTOHSCROLL | ES_READONLY

END


 DISPCALC.REG  (DISPCALC Sample)

REGEDIT

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; registration info DispCalc.Application (defaults to DispCalc.Application.1

HKEY_CLASSES_ROOT\Dispcalc.Application = OLE Automation Dispcalc Application

HKEY_CLASSES_ROOT\Dispcalc.Application\Clsid = {00020467-0000-0000-C000-000000000046}

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; registration info DispCalc 1.0

HKEY_CLASSES_ROOT\Dispcalc.Application.1 = OLE Automation Dispcalc 1.0 Application

HKEY_CLASSES_ROOT\Dispcalc.Application.1\Clsid = {00020467-0000-0000-C000-000000000046}

HKEY_CLASSES_ROOT\CLSID\{00020467-0000-0000-C000-000000000046} = OLE Automation Dispcalc 1.0 Application

HKEY_CLASSES_ROOT\CLSID\{00020467-0000-0000-C000-000000000046}\ProgID = Dispcalc.Application.1

HKEY_CLASSES_ROOT\CLSID\{00020467-0000-0000-C000-000000000046}\VersionIndependentProgID = Dispcalc.Application

HKEY_CLASSES_ROOT\CLSID\{00020467-0000-0000-C000-000000000046}\LocalServer32 = dispcalc.exe /Automation


 DISPCALC.CPP  (DISPCALC Sample)

/***

*dispcalc.cpp

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*  Information Contained Herein Is Proprietary and Confidential.

*

*Purpose:

*  This module implements the basic user interface and arithmetic

*  functionality of the IDispatch calculator.

*

*  The implementation of IDispatch it via aggregation with an

*  instance of the "standard" IDispatch implementation, which is

*  initialized with a DispTypeInfo constructed from an INTERFACEDATA

*  description.

*

*Implementation Notes:

*

*****************************************************************************/

#include "dispcalc.h"

CCalc FAR* g_pcalc = NULL;

unsigned long g_dwCCalcCF = 0;

unsigned long g_dwRegisterCCalc = 0;

#ifdef _MAC

extern Boolean g_fQuit;

#endif //_MAC

CCalc::CCalc() : m_arith(this)

{

    m_refs = 0;

#ifdef _MAC

    m_pdlg = nil;

#else

    m_hwnd = NULL;

#endif

    m_punkStdDisp = NULL;

}

/***

*CCalc *CCalc::Create(void)

*Purpose:

*  Create an instance of the IDispatch calculator, build a

*  TypeInfo that describes the exposed functionality and

*  aggregate with an instance of CStdDispatch that has been

*  initialized with this TypeInfo.

*

*Entry:

*  None

*

*Exit:

*  return value = CCalc*, NULL if the creation failed.

*

***********************************************************************/

CCalc FAR*

CCalc::Create()

{

    HRESULT hresult;

    CCalc FAR* pcalc;

    CArith FAR* parith;

    ITypeInfo FAR* ptinfo;

    IUnknown FAR* punkStdDisp;

extern INTERFACEDATA NEARDATA g_idataCCalc;

    if((pcalc = new FAR CCalc()) == NULL)

      return NULL;

    pcalc->AddRef();

    parith = &(pcalc->m_arith);

    // Build a TypeInfo for the functionality on this object that

    // is being exposing for external programmability.

    //

    hresult = CreateDispTypeInfo(

      &g_idataCCalc, LOCALE_SYSTEM_DEFAULT, &ptinfo);

    if(hresult != NOERROR)

      goto LError0;

    // Create and aggregate with an instance of the default

    // implementation of IDispatch that is initialized with our

    // TypeInfo.

    //

    hresult = CreateStdDispatch(

      pcalc,                    // controlling unknown

      parith,                   // instance to dispatch on

      ptinfo,                   // typeinfo describing the instance

      &punkStdDisp);

    ptinfo->Release();

    if(hresult != NOERROR)

      goto LError0;

    pcalc->m_punkStdDisp = punkStdDisp;

    return pcalc;

LError0:;

    pcalc->Release();

    return NULL;

}

//---------------------------------------------------------------------

//                        IUnknown methods

//---------------------------------------------------------------------

STDMETHODIMP

CCalc::QueryInterface(REFIID riid, void FAR* FAR* ppv)

{

    if(IsEqualIID(riid, IID_IUnknown)){

      *ppv = this;

    }else

    if(IsEqualIID(riid, IID_IDispatch)){

      return m_punkStdDisp->QueryInterface(riid, ppv);

    }else {

      *ppv = NULL;

      return ResultFromScode(E_NOINTERFACE);

    }

    AddRef();

    return NOERROR;

}

STDMETHODIMP_(unsigned long)

CCalc::AddRef()

{

    return ++m_refs;

}

STDMETHODIMP_(unsigned long)

CCalc::Release()

{

    if(--m_refs == 0){

      if(m_punkStdDisp != NULL)

        m_punkStdDisp->Release();

#ifndef _MAC

      UninitOle();

      PostQuitMessage(0);

#endif

      delete this;

      return 0;

    }

    return m_refs;

}

//---------------------------------------------------------------------

//                       Arithmetic features

//---------------------------------------------------------------------

STDMETHODIMP_(void)

CArith::Clear()

{

    m_opnd = 0;

    m_accum = 0;

    m_op = OP_NONE;

    m_state = STATE_LOPND;

}

STDMETHODIMP_(void)

CArith::put_Accum(long l)

{

    m_accum = l;

}

STDMETHODIMP_(long)

CArith::get_Accum()

{

    return m_accum;

}

STDMETHODIMP_(void)

CArith::put_Opnd(long l)

{

    m_opnd = l;

}

STDMETHODIMP_(long)

CArith::get_Opnd()

{

    return m_opnd;

}

STDMETHODIMP_(void)

CArith::put_Op(short op)

{

    m_op = op;

}

STDMETHODIMP_(short)

CArith::get_Op()

{

    return m_op;

}

STDMETHODIMP_(short)

CArith::Eval()

{

    if(m_op == OP_NONE)

      return 0;

    switch(m_op){

    case OP_PLUS:

      m_accum += m_opnd;

      break;

    case OP_MINUS:

      m_accum -= m_opnd;

      break;

    case OP_MULT:

      m_accum *= m_opnd;

      break;

    case OP_DIV:

      m_accum = (m_opnd == 0) ? 0 : (m_accum / m_opnd);

      break;

    default:

      // ASSERT(UNREACHED);

      return 0;

    }

    m_state = STATE_EVAL;

    return 1;

}

//---------------------------------------------------------------------

//                       User Interface features

//---------------------------------------------------------------------

/***

*void CArith::Display()

*Purpose:

*  Display the contents of the register currently being edited.

*

*Entry:

*  None

*

*Exit:

*  None

*

***********************************************************************/

STDMETHODIMP_(void)

CArith::Display()

{

    VARIANT var;

    VariantInit(&var);

    V_VT(&var) = VT_I4;

    V_I4(&var) = (m_state == STATE_ROPND) ? m_opnd : m_accum;

    VariantChangeType(&var, &var, 0, VT_BSTR);

#ifdef _MAC

    {

      Rect rcItem;

      Handle hItem;

      char str[255];

      short sItemKind;

      strcpy(str, V_BSTR(&var));

      GetDItem(m_pcalc->m_pdlg, IDC_DISPLAY, &sItemKind, &hItem, &rcItem);

      SetIText(hItem, c2pstr(str));

    }

#else

    SetDlgItemText(m_pcalc->m_hwnd, IDC_DISPLAY, STRING(V_BSTR(&var)));

#endif

    VariantClear(&var);

}

STDMETHODIMP_(short)

CArith::Button(BSTR bstrButton)

{

    int i, button;

static struct {

    OLECHAR ch;

    int idc;

} NEARDATA rgIdcOfCh[] = {

      { OLESTR('+'), IDC_PLUS   }

    , { OLESTR('-'), IDC_MINUS  }

    , { OLESTR('*'), IDC_MULT   }

    , { OLESTR('/'), IDC_DIV    }

    , { OLESTR('C'), IDC_CLEAR  }

    , { OLESTR('c'), IDC_CLEAR  }

    , { OLESTR('='), IDC_EQUALS }

    , { OLESTR('0'), IDC_ZERO   }

    , { OLESTR('1'), IDC_ONE    }

    , { OLESTR('2'), IDC_TWO    }

    , { OLESTR('3'), IDC_THREE  }

    , { OLESTR('4'), IDC_FOUR   }

    , { OLESTR('5'), IDC_FIVE   }

    , { OLESTR('6'), IDC_SIX    }

    , { OLESTR('7'), IDC_SEVEN  }

    , { OLESTR('8'), IDC_EIGHT  }

    , { OLESTR('9'), IDC_NINE   }

    , { (OLECHAR)-1 , -1         }

};

    // if the string is more that 1 character long, then we know its wrong.

    if(SysStringLen(bstrButton) > 1)

      return 0;

    // translate button string into control ID

    for(i = 0;; ++i){

      if(rgIdcOfCh[i].ch == -1)

        return 0;

      if(rgIdcOfCh[i].ch == bstrButton[0]){

        button = rgIdcOfCh[i].idc;

        break;

      }

    }

    return ButtonPush(button);

}

// the following method is internal, and not exposed for programmability

int

CArith::ButtonPush(int button)

{

    if(button >= IDC_ZERO && button <= IDC_NINE){

      long lVal = button - IDC_ZERO;

      switch(m_state){

      case STATE_EVAL:

        m_accum = lVal;

        m_state = STATE_LOPND;

        break;

      case STATE_OP:

        m_opnd = lVal;

        m_state = STATE_ROPND;

        break;

      case STATE_LOPND:

        m_accum = (m_accum * 10) + lVal;

        break;

      case STATE_ROPND:

        m_opnd  = (m_opnd * 10) + lVal;

        break;

      }

    }else if(button >= IDC_PLUS && button <= IDC_DIV){

      if(m_state == STATE_LOPND){

        m_opnd  = m_accum;

        m_state = STATE_OP;

        m_op    = button - IDC_PLUS + OP_PLUS;

      }

    }else if(button == IDC_EQUALS){

      if(m_state > STATE_LOPND)

        Eval();

    }else if (button == IDC_CLEAR){

      Clear();

    }else{

      return 0; // unknown button

    }

    // Flash the button

#ifdef _MAC

    {

      Rect rcItem;

      long lDummy;

      Handle hItem;

      short sItemKind;

      GetDItem(m_pcalc->m_pdlg, button, &sItemKind, &hItem, &rcItem);

      HiliteControl((ControlHandle)hItem, 1);

      Delay(6, &lDummy);

      HiliteControl((ControlHandle)hItem, 0);

    }

#else

    SendMessage(m_pcalc->m_hwnd, BM_SETSTATE, 1, 0L);

    SendMessage(m_pcalc->m_hwnd, BM_SETSTATE, 0, 0L);

#endif

    // Update the calculator display

    Display();

    return 1;

}

/***

*void CArith::Quit()

*Purpose:

*

*Entry:

*  None

*

*Exit:

*  None

*

***********************************************************************/

STDMETHODIMP_(void)

CArith::Quit()

{

#ifndef _MAC

    UninitOle();

    PostQuitMessage(0);

#else

    g_fQuit = 1;

#endif

}

//---------------------------------------------------------------------

//                      The CCalc Class Factory

//---------------------------------------------------------------------

IClassFactory FAR*

CCalcCF::Create()

{

    return new FAR CCalcCF();

}

STDMETHODIMP

CCalcCF::QueryInterface(REFIID riid, void FAR* FAR* ppv)

{

    if(IsEqualIID(riid, IID_IUnknown) ||

       IsEqualIID(riid, IID_IClassFactory)){

      AddRef();

      *ppv = this;

      return NOERROR;

    }

    *ppv = NULL;

    return ResultFromScode(E_NOINTERFACE);

}

STDMETHODIMP_(unsigned long)

CCalcCF::AddRef()

{

    return ++m_refs;

}

STDMETHODIMP_(unsigned long)

CCalcCF::Release()

{

    if(--m_refs == 0){

      delete this;

      return 0;

    }

    return m_refs;

}

STDMETHODIMP

CCalcCF::CreateInstance(

    IUnknown FAR* punkOuter,

    REFIID riid,

    void FAR* FAR* ppv)

{

    if(punkOuter != NULL)

      return ResultFromScode(CLASS_E_NOAGGREGATION);

    return g_pcalc->QueryInterface(riid, ppv);

}

STDMETHODIMP

#ifdef _MAC

CCalcCF::LockServer(unsigned long fLock)

#else

CCalcCF::LockServer(BOOL fLock)

#endif

{

    UNUSED(fLock);

    return NOERROR;

}

//---------------------------------------------------------------------

//                        Ole Init/Uninit

//---------------------------------------------------------------------

HRESULT

UninitOle()

{

    if(g_dwRegisterCCalc != 0)

      RevokeActiveObject(g_dwRegisterCCalc, NULL);

    if(g_dwCCalcCF != 0)

      CoRevokeClassObject(g_dwCCalcCF);

    if(g_pcalc != NULL)

      g_pcalc->Release();

    OleUninitialize();

    return NOERROR;

}

#ifdef _MAC

struct regentry{

    char *szKey;

    char *szValue;

} g_rgregentry[] = {

      { "CLSID\\{00020467-0000-0000-C000-000000000046}",

        "OLE Automation DispCalc 1.0 Application" }

    , { "CLSID\\{00020467-0000-0000-C000-000000000046}\\LocalServer",

        "DCLC" }

    , { "CLSID\\{00020467-0000-0000-C000-000000000046}\\ProgID",

        "Dispcalc.Application" }

    , { "CLSID\\{00020467-0000-0000-C000-000000000046}\\InprocHandler",

        "OLE2:Def$DefFSet" }

    , { "DCLC", "{00020467-0000-0000-C000-000000000046}" }

    , { "Dispcalc.Application\\CLSID",

        "{00020467-0000-0000-C000-000000000046}" }

};

HRESULT

EnsureRegistration()

{

    HKEY hkey;

    if(RegOpenKey(HKEY_CLASSES_ROOT, "DCLC", &hkey) == NOERROR){

      RegCloseKey(hkey);

      return NOERROR;

    }

    for(int i = 0; i < DIM(g_rgregentry); ++i){

      if(RegSetValue(HKEY_CLASSES_ROOT, g_rgregentry[i].szKey, REG_SZ, g_rgregentry[i].szValue, 0) != ERROR_SUCCESS)

        return ResultFromScode(E_FAIL);

    }

    return NOERROR;

}

#endif

/***

*HRESULT InitOle(void)

*Purpose:

*  Initialize Ole, and register our class factories.

*

*Entry:

*  None

*

*Exit:

*  None

*

***********************************************************************/

HRESULT

InitOle()

{

    HRESULT hresult;

    IClassFactory FAR* pcf;

    if((hresult = OleInitialize(NULL)) != NOERROR)

      goto LError0;

#ifdef _MAC

    if((hresult = EnsureRegistration()) != NOERROR)

      goto LError0;

#endif

    // create the single global instance of CCalc

    if((g_pcalc = CCalc::Create()) == NULL){

      hresult = ResultFromScode(E_OUTOFMEMORY);

      goto LError0;

    }

    if((pcf = CCalcCF::Create()) == NULL)

      goto LError1;

    hresult = CoRegisterClassObject(

      CLSID_CCalc,

      pcf,

      CLSCTX_LOCAL_SERVER,

      REGCLS_MULTIPLEUSE,

      &g_dwCCalcCF);

    if(hresult != NOERROR)

      goto LError2;

    hresult = RegisterActiveObject(

      g_pcalc, CLSID_CCalc, NULL, &g_dwRegisterCCalc);

    if(hresult != NOERROR)

      goto LError2;

    pcf->Release();

    return NOERROR;

LError2:;

    pcf->Release();

LError1:;

    UninitOle();

LError0:;

    return hresult;

}


 HOSTENV.H  (DISPCALC Sample)

/***

*hostenv.h

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*

*Purpose:

*  Generic host specific includes.

*

*Implementation Notes:

*

*****************************************************************************/

#if defined(_MAC)

#if defined(_PPCMAC)

#pragma data_seg("_FAR_DATA")

#pragma data_seg( )

#define MAXLONG 0x7fffffff

#define EventHandlerProcPtr AEEventHandlerUPP

#else //_PPCMAC

#define  GetMenuItemText(mApple,menuItem,daName)  GetItem(mApple,menuItem,daName)

#endif //_PPCMAC

#endif //_MAC

#if defined(_MAC)

#if defined(_MSC_VER)

# include <values.h>

# include <types.h>

# include <string.h>

# include <quickdra.h>

# include <fonts.h>

# include <events.h>

# include <resource.h>

# include <menus.h>

# include <textedit.h>

# include <dialogs.h>

# include <desk.h>

# include <toolutil.h>

# include <memory.h>

# include <files.h>

# include <osutils.h>

# include <osevents.h>

# include <diskinit.h>

# include <packages.h>

# include <traps.h>

# include <AppleEve.h>

#else //_MSC_VER

# include <values.h>

# include <types.h>

# include <strings.h>

# include <quickdraw.h>

# include <fonts.h>

# include <events.h>

# include <resources.h>

# include <windows.h>

# include <menus.h>

# include <textedit.h>

# include <dialogs.h>

# include <desk.h>

# include <toolutils.h>

# include <memory.h>

# include <files.h>

# include <osutils.h>

# include <osevents.h>

# include <diskinit.h>

# include <packages.h>

# include <traps.h>

# include <AppleEvents.h>

#endif //_MSC_VER

# include <ole2.h>

# include <olenls.h>

# include <dispatch.h>

# define TCHAR	char

# define TSTR(str)	str

# define STRING(str)	        (str)

# define WIDESTRING(str)        (str)

#elif defined(WIN32)

# include <windows.h>

# include <ole2.h>

# include <oleauto.h>

# if defined(UNICODE)

    #define TCHAR	WCHAR

    #define TSTR(str)	L##str

    #define STRING(str)	        (str)

    #define WIDESTRING(str)	(str)

# else

    #define TCHAR	char

    #define TSTR(str)	str

    #define STRING(str)	        AnsiString(str)

    #define WIDESTRING(str)	WideString(str)

    extern "C" char FAR* AnsiString(OLECHAR FAR* strIn);

    extern "C" OLECHAR FAR* WideString(char FAR* strIn);

# endif

#else /* WIN16 */

# include <windows.h>

# include <ole2.h>

# include <olenls.h>

# include <dispatch.h>

# define TCHAR	char

# define TSTR(str)	str

# define STRING(str)	        (str)

# define WIDESTRING(str)        (str)

#endif


 IDATA.CPP  (DISPCALC Sample)

/***

*idata.cpp

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*  Information Contained Herein Is Proprietary and Confidential.

*

*Purpose:

*  This file contains the INTERFACEDATA definitions for the methods

*  and properties on the CCalc object that are exposed for external

*  programmability via IDispatch.

*

*

*Implementation Notes:

*

*****************************************************************************/

#include "dispcalc.h"

//---------------------------------------------------------------------

//                   INTERFACEDATA definitions

//---------------------------------------------------------------------

/* The INTERFACEDATA table describes the methods and properties that

 * are being exposed for external programmability via IDispatch.

 * This table is used to construct a CDispTypeInfo for this interface,

 * and that TypeInfo is in turn used to initialize and drive the

 * default implementation of IDispatch.

 */

// PDATA1() declares the PARAMDATA for a methods that takes a single param

//

#define PDATA1(NAME, TYPE) \

    static PARAMDATA NEARDATA rgpdata ## NAME = {OLESTR(#NAME), TYPE}

// MDATA() declares a single METHODDATA entry

//

#define MDATA(NAME, PDATA, IDMEMBER, IMETH, CARGS, KIND, TYPE) \

    { OLESTR(#NAME), PDATA, IDMEMBER, IMETH, CC_CDECL, CARGS, KIND, TYPE }

// The following macro defines the METHODDATA entries for a

// property Put/Get method pair.

//

// Note: this macro *assumes* that the Put/Get pair are adjacent

// in the vtable, and that the Put method comes first.

//

#define PROPERTY(NAME, IMETH, ID, TYPE) \

    MDATA(NAME, &rgpdata ## NAME, ID, IMETH, 1,DISPATCH_PROPERTYPUT,VT_EMPTY), \

    MDATA(NAME, NULL, ID, IMETH+1, 0, DISPATCH_PROPERTYGET, TYPE)

// The following macro is used to define a METHODDATA entry for

// a method that takes zero parameters.

//

#define METHOD0(NAME, IMETH, ID, TYPE) \

    MDATA(NAME, NULL, ID, IMETH, 0, DISPATCH_METHOD, TYPE)

// and for one param

#define METHOD1(NAME, IMETH, ID, TYPE) \

    MDATA(NAME, &rgpdata ## NAME, ID, IMETH, 1, DISPATCH_METHOD, TYPE)

PDATA1(VALUE,  VT_I4);

PDATA1(ACCUM,  VT_I4);

PDATA1(OPND,   VT_I4);

PDATA1(OP,     VT_I2);

PDATA1(BUTTON, VT_BSTR);

static METHODDATA NEARDATA rgmdataCCalc[] =

{

      PROPERTY(VALUE,   IMETH_ACCUM,    IDMEMBER_ACCUM,    VT_I4)

    , PROPERTY(ACCUM,   IMETH_ACCUM,    IDMEMBER_ACCUM,    VT_I4)

    , PROPERTY(OPND,    IMETH_OPERAND,  IDMEMBER_OPERAND,  VT_I4)

    , PROPERTY(OP,      IMETH_OPERATOR, IDMEMBER_OPERATOR, VT_I2)

    ,  METHOD0(EVAL,    IMETH_EVAL,     IDMEMBER_EVAL,     VT_BOOL)

    ,  METHOD0(CLEAR,   IMETH_CLEAR,    IDMEMBER_CLEAR,    VT_EMPTY)

    ,  METHOD0(DISPLAY, IMETH_DISPLAY,  IDMEMBER_DISPLAY,  VT_EMPTY)

    ,  METHOD0(QUIT,    IMETH_QUIT,     IDMEMBER_QUIT,     VT_EMPTY)

    ,  METHOD1(BUTTON,  IMETH_BUTTON,   IDMEMBER_BUTTON,   VT_BOOL)

};

INTERFACEDATA NEARDATA g_idataCCalc =

{

    rgmdataCCalc, DIM(rgmdataCCalc)

};


 RESOURCE.H  (DISPCALC Sample)

/***

*resource.h

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*

*Purpose:

*

*Implementation Notes:

*

*****************************************************************************/

#ifdef _MAC

#define kMinSize	500	/* minimum size (in K) */

#define kPrefSize	500	/* preferred size (in K) */

#define kMinHeap	21 * 1024

#define kMinSpace	8 * 1024

#define	rMenuBar	128	/* menu bar */

#define	rAboutAlert	128	/* about alert */

#define	rUserAlert	129	/* error alert */

#define	rCalc	130

#define	mApple	128	/* Apple menu */

#define	iAbout	1

#define	mFile	129	/* File menu */

#define iClose	4

#define	iQuit	12

#define	mEdit	130	/* Edit menu */

#define	iUndo	1

#define	iCut	3

#define	iCopy	4

#define	iPaste	5

#define	iClear	6

#endif

// Note: there is code that depends on all of the digits being contiguous

// and in the following order.

// Mac Note: On the mac these IDs correspond to the control indices

// in the DITL array.

#define IDC_ZERO     1

#define IDC_ONE      2

#define IDC_TWO      3

#define IDC_THREE    4

#define IDC_FOUR     5

#define IDC_FIVE     6

#define IDC_SIX      7

#define IDC_SEVEN    8

#define IDC_EIGHT    9

#define IDC_NINE     10

// Note: there is code that depends on the operators being contiguous

// and in the following order.

//

#define IDC_PLUS     11

#define IDC_MINUS    12

#define IDC_MULT     13

#define IDC_DIV      14

#define IDC_CLEAR    15

#define IDC_EQUALS   16

#define IDC_DISPLAY  17


 WINMAIN.CPP  (DISPCALC Sample)

/***

*main.cpp

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*  Information Contained Herein Is Proprietary and Confidential.

*

*Purpose:

*  This module is the main entry point of the sample IDispatch

*  calculator, dispcalc.exe

*

*  This program is intended to demonstrate an implementation of

*  the IDispatch interface.

*

*Implementation Notes:

*

*****************************************************************************/

#include "dispcalc.h"

TCHAR g_szAppName[] = TSTR("DispCalc");

BOOL InitApplication(HANDLE);

BOOL InitInstance(HANDLE, int);

extern "C" {

long FAR PASCAL WndProc(HWND, UINT, WPARAM, LPARAM);

int PASCAL WinMain(HANDLE, HANDLE, LPSTR, int);

}

extern "C" int PASCAL

WinMain(

    HANDLE hinst,

    HANDLE hinstPrev,

    LPSTR lpCmdLine,

    int nCmdShow)

{

    MSG msg;

    if(!hinstPrev)

      if(!InitApplication(hinst))

        return FALSE;

    if(InitOle() != NOERROR)

      return FALSE;

    if(!InitInstance(hinst, nCmdShow)){

      UninitOle();

      return FALSE;

    }

    while(GetMessage(&msg, NULL, NULL, NULL)) {

      TranslateMessage(&msg);

      DispatchMessage(&msg);

    }

    return msg.wParam;

}

BOOL

InitApplication(HANDLE hinst)

{

    WNDCLASS  wc;

    wc.style            = CS_HREDRAW | CS_VREDRAW;

    wc.lpfnWndProc      = WndProc;

    wc.cbClsExtra       = 0;

    wc.cbWndExtra       = DLGWINDOWEXTRA;

    wc.hInstance        = hinst;

    wc.hIcon            = LoadIcon(hinst, g_szAppName);

    wc.hCursor          = LoadCursor(NULL, IDC_ARROW);

    wc.hbrBackground    = (HBRUSH)(COLOR_APPWORKSPACE+1);

    wc.lpszMenuName     = NULL;

    wc.lpszClassName    = g_szAppName;

    if(!RegisterClass(&wc))

      return FALSE;

    return TRUE;

}

BOOL

InitInstance(HANDLE hinst, int nCmdShow)

{

    g_pcalc->m_hwnd = CreateDialog(hinst, g_szAppName, 0, NULL);

    ShowWindow(g_pcalc->m_hwnd, nCmdShow);

    g_pcalc->m_arith.Display();

    return TRUE;

}

extern "C" long FAR PASCAL

WndProc(

    HWND hwnd,

    UINT message,

    WPARAM wParam,

    LPARAM lParam)

{

    switch(message){

    case WM_COMMAND:

      switch(wParam){

      case IDC_ZERO:

      case IDC_ONE:

      case IDC_TWO:

      case IDC_THREE:

      case IDC_FOUR:

      case IDC_FIVE:

      case IDC_SIX:

      case IDC_SEVEN:

      case IDC_EIGHT:

      case IDC_NINE:

      case IDC_PLUS:

      case IDC_MINUS:

      case IDC_MULT:

      case IDC_DIV:

      case IDC_CLEAR:

      case IDC_EQUALS:

        g_pcalc->m_arith.ButtonPush(wParam);

        return 0;

      }

      break;

    case WM_DESTROY:

      UninitOle();

      PostQuitMessage(0);

      return 0;

    }

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

}

#if defined(WIN32)

extern "C" char FAR*

ConvertStrWtoA(OLECHAR FAR* strIn, char FAR* buf, UINT size)

{

  int badConversion = FALSE;

  WideCharToMultiByte(CP_ACP, NULL,

                      strIn, -1,

                      buf, size,

                      NULL, &badConversion);

  return buf;

}

extern "C" char FAR*

AnsiString(OLECHAR FAR* strIn)

{

  static char buf[256];

  return (ConvertStrWtoA(strIn, buf, 256));

}

#endif


 DSPCALC2

--------------------------------------- OLE Automation Sample Program: Dispcalc ---------------------------------------

DspCalc2 is a simple accumulator-based calculator.  Its user interface consists of buttons for the numbers (0-9),  the operators (+, -, *, /), and some other necessary buttons (C for Clear, = for evaluation).  Its programmability interface consists of one object, which is described below.

The ProgID for dspcalc2's only object is "DspCalc2.Application".   An instance of this object can be created by executing the  following lines of code in Visual Basic or DispTest:

  Sub Foo
    Dim MyCalculator as Object

    Set MyCalculator = CreateObject("DspCalc2.Application")
    . . .
  End Sub

----------------- Program Structure ----------------- DspCalc2 uses a type library and CreateStdDispatch in order to  implement the IDispatch interface.

------------------------- Properties for the object -------------------------

Name	Type	Description --------------------------- Value	VT_I4	Same as the value for the accumulator.

Accum	VT_I4	The value that is in the accumulator of the 	calculator.

Opnd	VT_I4	The operand.  This is the number which is 	currently being entered.

Op	VT_I2	The operator that is currently being used. 	This is an enumeration: 	const OP_NONE = 0 	const OP_PLUS = 1 	const OP_MINUS = 2 	const OP_MULT = 3

----------------------------- Methods defined on the object -----------------------------

Name	Description --------------------------- Eval() as Boolean	If there is an operator, apply it to 	accumulator and the operand, placing the 	result in the accumulator.

The return value indicates success or 	failure.

Clear()	Resets the calculator.  This sets 	Op to OP_NONE, and both Accum and 	Opnd to 0. Display()	Updates the display of the calculator. 	(Other operations do not do this.)

Quit()	Close the calculator.

Button(b as string) as Boolean 	Press the indicated button and return 	success or failure. 	 	Valid string values are: 	+, -, *, + 	0-9 	c, C 	= 	 	Note that you may also pass the numbers 	0-9 and these will be converted to strings 	automatically.

--------------------------- Shortcomings of this sample --------------------------- 1. Property and method names should not be abbreviated. For example, the "Opnd" property should be the "Operand"  property.

2. Since the object is the application object, it should have Name and Version properties, which are read-only.


 MAKEFILE  (DSPCALC2 Sample)

####

#makefile - makefile for dspcalc2.exe

#

#       Copyright (C) 1992, Microsoft Corporation

#

#Purpose:

#  Builds the OLE 2.0 sample IDispatch server, dspcalc2.exe.

#

#

#  Usage: NMAKE                 ; build with defaults

#     or: NMAKE option          ; build with the given option(s)

#     or: NMAKE clean           ; erase all compiled files

#

#     option: dev = [win16 | win32]    ; dev=win32 is the default

#             DEBUG=[0|1]              ; DEBUG=1 is the default

#             HOST=[DOS | NT]          ; HOST=DOS (for win16)

#                                      ; HOST=NT  (for win32)

#

#Notes:

#  This makefile assumes that the PATH, INCLUDE and LIB environment

#  variables are setup properly.

#

##############################################################################

##########################################################################

#

# Default Settings

#

!if "$(dev)" == ""

dev = win32

!endif

!if !("$(dev)" == "win16" || "$(dev)" == "win32")

!error Invalid dev option, choose from [win16 | win32]

!endif

!if "$(dev)" == "win16"

TARGET  = WIN16

!if "$(HOST)" == ""

HOST  = DOS

!endif

!endif

!if "$(dev)" == "win32"

TARGET  = WIN32

HOST  = NT

!endif

!ifdef NODEBUG

DEBUG = 0

!endif

!if "$(DEBUG)" == "0"

NODEBUG = 1

!endif

!if "$(DEBUG)" == ""

DEBUG = 1

!endif

##########################################################################

#

# WIN16 Settings

#

!if "$(TARGET)" == "WIN16"

CC   = cl

LINK = link

!if "$(HOST)" == "DOS"

WX   = wx /w

!else

WX   =

!endif

RCFLAGS = -dWIN16

CFLAGS = -c -W3 -AM -GA -GEs -DWIN16

LINKFLAGS = /NOD /NOI /BATCH /ONERROR:NOEXE

LIBS = libw.lib mlibcew.lib

!if "$(DEBUG)" == "1"

CFLAGS = $(CFLAGS) -Od -Zi -D_DEBUG $(CL)

LINKFLAGS = $(LINKFLAGS) /COD

!else

CFLAGS = $(CFLAGS) -Ox $(CL)

LINKFLAGS = $(LINKFLAGS) /FAR /PACKC

!endif

!endif

##########################################################################

#

# WIN32 Settings

#

!if "$(TARGET)" == "WIN32"

!include <$(MSTOOLS)\samples\ole\include\olesampl.mak>

CC = $(cc)

CFLAGS = $(cflags) $(cvarsmt) -DUNICODE $(cdebug)

!ifndef NODEBUG

CFLAGS = $(CFLAGS) -D_DEBUG

!endif

LINK = $(link)

LINKFLAGS = $(linkdebug) $(guilflags)

RCFLAGS = -DWIN32

WX =

!endif

##########################################################################

#

# Build rules

#

.cpp.obj:

    @echo Compiling $<...

    $(CC) $<

.c.obj:

    @echo Compiling $<...

    $(CC) $<

##########################################################################

#

# Application Settings

#

APPS = dspcalc2

!if "$(TARGET)" == "WIN16"

LIBS = ole2.lib compobj.lib ole2disp.lib typelib.lib $(LIBS)

!endif

!if "$(TARGET)" == "WIN32"

LIBS = $(olelibsmt)

!endif

OBJS = \

        main.obj        \

        dspcalc2.obj    \

        clsid.obj

##########################################################################

#

# Default Goal

#

goal : setflags $(APPS).exe

setflags :

        set CL=$(CFLAGS)

##########################################################################

#

# Clean (erase) generated files

#

clean :

    if exist *.obj       del *.obj

    if exist $(APPS).exe del $(APPS).exe

    if exist $(APPS).tlb del $(APPS).tlb

    if exist $(APPS).map del $(APPS).map

    if exist $(APPS).res del $(APPS).res

    if exist calctype.h  del calctype.h

    if exist *.log       del *.log

    if exist *.pdb       del *.pdb

##########################################################################

#

# Application Build (WIN16 Specific)

#

!if "$(TARGET)" == "WIN16"

$(APPS).exe : $(OBJS) $(APPS).def $(APPS).res $(APPS).ico

        link $(LINKFLAGS) @<<

$(OBJS),

$@,,

$(LIBS),

$(APPS).def

<<

        rc -k -t $(APPS).res $@

!endif

##########################################################################

#

# Application Build (WIN32 Specific)

#

!if "$(TARGET)" == "WIN32"

$(APPS).exe : $(OBJS) $(APPS).def $(APPS).res $(APPS).ico

      $(LINK) @<<

        $(LINKFLAGS)

        -out:$@

        -map:$*.map

        $(OBJS)

        $(APPS).res

        $(LIBS)

<<

!endif

##########################################################################

#

# Application Build (Common)

#

$(APPS).res : $(APPS).rc

        rc $(RCFLAGS) -r -fo$@ $?

##########################################################################

#

# Dependencies

#

calctype.h : calctype.odl

        if exist calctype.h  del calctype.h

        if exist dspcalc2.tlb  del dspcalc2.tlb

        $(WX) mktyplib /D$(TARGET) /h calctype.h /o calctype.log /tlb dspcalc2.tlb calctype.odl

main.obj : main.cpp dspcalc2.h calctype.h

        $(CC) main.cpp

dspcalc2.obj : dspcalc2.cpp dspcalc2.h calctype.h

        $(CC) dspcalc2.cpp

clsid.obj : clsid.c clsid.h

        $(CC) clsid.c


 CALCTYPE.ODL  (DSPCALC2 Sample)

/***

*calctype.odl

*

*  Copyright (C) 1993-1994, Microsoft Corporation.  All Rights Reserved.

*  Information Contained Herein Is Proprietary and Confidential.

*

*Purpose:

*  This file contains the definitions of the objects exposed for OLE Automation

*  by the dspcalc2

*  example program. MkTypLib uses this file to produce a type library and

*  a header file. The header file is then used in compiling dspcalc2.

*

*Implementation Notes:

*

*****************************************************************************/

[

  uuid(00020470-0000-0000-C000-000000000046),

  helpstring("OLE Automation DspCalc2 1.0 Type Library"),

  lcid(0x0409),

  version(1.0)

]

library DspCalc2

{

#if defined(WIN32)

    importlib("stdole32.tlb");

#else

#if defined(MAC) && !defined(_PPCMAC)

    importlib("Standard OLE Types");

#else

    importlib("stdole.tlb");

#endif

#endif

    typedef enum operators {

      OP_NONE = 0,

      OP_PLUS,

      OP_MINUS,

      OP_MULT,

      OP_DIV

    } OPERATORS;

    [

      uuid(00020441-0000-0000-C000-000000000046),

      helpstring("DspCalc2"),

      odl

    ]

    interface _ICalculator : IUnknown

    {

      [propput]

      void Accum([in] long l);

      [propget, helpstring("The value stored in the calculator")]

      long Accum();

      [propput]

      void Opnd([in] long l);

      [propget]

      long Opnd();

      [propput]

      void Op([in] OPERATORS op);

      [propget]

      OPERATORS Op();

      boolean Eval(void);

      void Clear(void);

      void Display(void);

      void Quit(void);

      [vararg] boolean Button([in]SAFEARRAY(VARIANT) psa);

    }

    [

      uuid(00020442-0000-0000-C000-000000000046),

      helpstring("DspCalc2")

    ]

    dispinterface _DCalculator

    {

      interface _ICalculator;

    }

    [

      uuid(00020469-0000-0000-C000-000000000046),

      helpstring("DspCalc2"),

      appobject

    ]

    coclass Calculator

    {

      dispinterface _DCalculator;

      interface _ICalculator;

    }

}


 CLSID.H  (DSPCALC2 Sample)

/***

*clsid.h

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*  Information Contained Herein Is Proprietary and Confidential.

*

*Purpose:

*  This file defines the CLSIDs

*

*Implementation Notes:

*

*****************************************************************************/

DEFINE_GUID(CLSID_CCalc2,    0x00020469, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46);

DEFINE_GUID(LIBID_DspCalc2,  0x00020470, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46);

DEFINE_GUID(IID_ICalculator, 0x00020441, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46);

DEFINE_GUID(IID_DCalculator, 0x00020442, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46);

#ifdef INITGUID

# ifdef _MAC

DEFINE_GUID(GUID_NULL, 0L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);

DEFINE_GUID(IID_IDispatch, 0x00020400, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46);

DEFINE_GUID(IID_IEnumVARIANT, 0x00020404, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46);

DEFINE_GUID(IID_IUnknown, 0x00000000, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46);

DEFINE_GUID(IID_IClassFactory, 0x00000001, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46);

# endif

#endif


 CLSID.C  (DSPCALC2 Sample)

/***

*clsid.c

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*  Information Contained Herein Is Proprietary and Confidential.

*

*Purpose:

*  This file allocates and initializes the CLSIDs.

*

*****************************************************************************/

#ifdef _PPCMAC

#pragma data_seg ("_FAR_DATA")

#pragma data_seg ( )

#endif //_PPCMAC

#ifdef _MAC

# include <Types.h>

#ifdef _MSC_VER

# include <Processe.h>

# include <AppleEve.h>

#else //_MSC_VER

# include <Processes.h>

# include <AppleEvents.h>

#endif //_MSC_VER

#else

# include <windows.h>

#endif

#ifndef WIN32

#include <compobj.h>

#endif //!WIN32

// this redefines the DEFINE_GUID() macro to do allocation.

//

#include <initguid.h>

#ifndef INITGUID

# define INITGUID

#endif

// due to the previous header, including this causes the DEFINE_GUID

// definitions in the following header(s) to actually allocate data.

//

#include "clsid.h"


 DSPCALC2.DEF  (DSPCALC2 Sample)

NAME         DSPCALC2

DESCRIPTION  'IDispatch Calculator w/ Type Library'

EXETYPE      WINDOWS

STUB         'WINSTUB.EXE'

CODE         PRELOAD MOVEABLE DISCARDABLE

DATA         PRELOAD MULTIPLE

HEAPSIZE     4096

STACKSIZE    8192


 DSPCALC2.H  (DSPCALC2 Sample)

/***

*dspcalc2.h

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*  Information Contained Herein Is Proprietary and Confidential.

*

*Purpose:

*

*

*Implementation Notes:

*

*****************************************************************************/

#include "hostenv.h"

#include "resource.h"

#include "clsid.h"

#ifndef CLASS

# ifdef __TURBOC__

#  define CLASS class huge

# else

#  define CLASS class FAR

# endif

#endif

#pragma warning(disable:4355)

#ifdef _MAC

typedef void * LPVOID;

typedef unsigned long ULONG;

typedef int BOOL;

typedef unsigned int UINT;

typedef unsigned short WORD;

typedef unsigned char BYTE;

typedef unsigned long DWORD;

typedef long LONG;

#define FALSE 0

#define TRUE  1

#define NEAR

#endif

#ifdef _MAC

# define UNUSED(X) ((void)(void*)&(X))

#else

# define UNUSED(X) (X)

#endif

/*

 * The .h file included below is created via MkTypLib

 */

#include "calctype.h"

#pragma warning(disable:4355)

#define DIM(X) (sizeof(X)/sizeof(X[0]))

// forward decl

CLASS CCalc;

// Introduced "calculator" interface

//

// This nested class implementes core arithmetic functionality

// (such as it is) *and* is the interface that will be exposed via

// IDispatch for external programmability.

//

CLASS CArith : public _ICalculator {

 public:

  /* IUnknown methods */

  STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID FAR * ppvObj);

  STDMETHOD_(ULONG, AddRef)(THIS);

  STDMETHOD_(ULONG, Release)(THIS);

  /* ICalculator methods */

  STDMETHOD_(void, put_Accum)(long l);

  STDMETHOD_(long, get_Accum)(void);

  STDMETHOD_(void, put_Opnd)(long l);

  STDMETHOD_(long, get_Opnd)(void);

  STDMETHOD_(void, put_Op)(OPERATORS op);

  STDMETHOD_(OPERATORS, get_Op)(void);

  STDMETHOD_(VARIANT_BOOL, Eval)(void);

  STDMETHOD_(void, Clear)(void);

  STDMETHOD_(void, Display)(void);

  STDMETHOD_(void, Quit)(void);

  STDMETHOD_(VARIANT_BOOL, Button)(SAFEARRAY FAR* psa);

  // the following method is internal, and not exposed for programmability

  BOOL ButtonPush(int button);

  CArith(CCalc FAR* pcalc){

     m_pcalc = pcalc;

     Clear();

  }

  enum states { STATE_LOPND, STATE_OP, STATE_ROPND, STATE_EVAL };

 private:

  CCalc FAR* m_pcalc;

  OPERATORS	m_op;

  long	m_opnd;

  long	m_accum;

  enum states m_state;

};

CLASS CCalc : public IUnknown {

public:

    friend CArith;

    static CCalc FAR* Create();

    STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppv);

    STDMETHOD_(ULONG, AddRef)(void);

    STDMETHOD_(ULONG, Release)(void);

    CCalc() : m_arith(this)

    {

      m_refs = 0;

#ifdef _MAC

      m_pdlg = nil;

#else

      m_hwnd = 0;

#endif

      m_punkStdDisp = NULL;

    }

#ifdef _MAC

    DialogPtr m_pdlg;

#else

    HWND m_hwnd;

#endif

    CArith m_arith;

private:

    ULONG m_refs;

    IUnknown FAR* m_punkStdDisp;

};

// the CCalc Class Factory

//

CLASS CCalcCF : public IClassFactory {

public:

    static IClassFactory FAR* Create();

    STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppv);

    STDMETHOD_(ULONG, AddRef)(void);

    STDMETHOD_(ULONG, Release)(void);

    STDMETHOD(CreateInstance)(

      IUnknown FAR* punkOuter, REFIID riid, void FAR* FAR* ppv);

#ifdef _MAC

    STDMETHOD(LockServer)(unsigned long fLock);

#else

    STDMETHOD(LockServer)(BOOL fLock);

#endif

    CCalcCF() { m_refs = 1; }

private:

    ULONG m_refs;

};

extern HRESULT InitOle(void);

extern HRESULT UninitOle(void);

extern CCalc FAR* g_pcalc;


 DSPCALC2.RC  (DSPCALC2 Sample)

#include <windows.h>

#include "resource.h"

DspCalc2 ICON dspcalc2.ico

DspCalc2 DIALOG DISCARDABLE  0, 0, 92, 114

STYLE    WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX

CLASS    "DspCalc2"

#ifdef WIN32

CAPTION  "DspCalc2 (32-bit)"

#else //WIN32

CAPTION  "DspCalc2"

#endif //WIN32

BEGIN

    PUSHBUTTON "0", IDC_ZERO,          9, 90, 14, 15

    PUSHBUTTON "1", IDC_ONE,           9, 70, 15, 16

    PUSHBUTTON "2", IDC_TWO,          29, 70, 16, 15

    PUSHBUTTON "3", IDC_THREE,        49, 70, 15, 15

    PUSHBUTTON "4", IDC_FOUR,          9, 50, 15, 14

    PUSHBUTTON "5", IDC_FIVE,         29, 50, 15, 15

    PUSHBUTTON "6", IDC_SIX,          49, 50, 15, 15

    PUSHBUTTON "7", IDC_SEVEN,         9, 30, 15, 15

    PUSHBUTTON "8", IDC_EIGHT,        29, 30, 15, 15

    PUSHBUTTON "9", IDC_NINE,         49, 30, 15, 15

    PUSHBUTTON "=", IDC_EQUALS,       49, 90, 14, 15

    PUSHBUTTON "+", IDC_PLUS,         69, 30, 15, 15

    PUSHBUTTON "-", IDC_MINUS,        69, 50, 14, 15

    PUSHBUTTON "*", IDC_MULT,         69, 70, 15, 15

    PUSHBUTTON "/", IDC_DIV,          69, 90, 15, 15

    PUSHBUTTON "C", IDC_CLEAR,        29, 90, 16, 15

    EDITTEXT        IDC_DISPLAY,       9,  6, 76, 15, ES_MULTILINE | ES_RIGHT | ES_AUTOHSCROLL | ES_READONLY

END


 DSPCALC2.REG  (DSPCALC2 Sample)

REGEDIT

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; registration info DspCalc2.Application (defaults to DspCalc2.Application.1

HKEY_CLASSES_ROOT\Dspcalc2.Application = OLE Automation Dspcalc2 Application

HKEY_CLASSES_ROOT\Dspcalc2.Application\Clsid = {00020469-0000-0000-C000-000000000046}

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; registration info DspCalc2.Application.1

HKEY_CLASSES_ROOT\Dspcalc2.Application.1 = OLE Automation Dspcalc2 1.0 Application

HKEY_CLASSES_ROOT\Dspcalc2.Application.1\Clsid = {00020469-0000-0000-C000-000000000046}

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; registration info DspCalc2 1.0

HKEY_CLASSES_ROOT\CLSID\{00020469-0000-0000-C000-000000000046} = OLE Automation Dspcalc2 1.0 Application

HKEY_CLASSES_ROOT\CLSID\{00020469-0000-0000-C000-000000000046}\ProgID = Dspcalc2.Application.1

HKEY_CLASSES_ROOT\CLSID\{00020469-0000-0000-C000-000000000046}\VersionIndependentProgID = Dspcalc2.Application

HKEY_CLASSES_ROOT\CLSID\{00020469-0000-0000-C000-000000000046}\LocalServer32 = dspcalc2.exe /Automation


 DSPCALC2.CPP  (DSPCALC2 Sample)

/***

*dspcalc2.cpp

*

*  Copyright (C) 1993-1994, Microsoft Corporation.  All Rights Reserved.

*  Information Contained Herein Is Proprietary and Confidential.

*

*Purpose:

*  This module implements the basic user interface and arithmetic

*  functionality of the IDispatch calculator.

*

*  The implementation of IDispatch is via aggregation with an

*  instance of the "standard" IDispatch implementation, which is

*  initialized with a TypeInfo loaded from the TypeLib that was

*  constructed from the ODL description of the calculator.

*

*Implementation Notes:

*

*****************************************************************************/

#include "dspcalc2.h"

CCalc FAR* g_pcalc = NULL;

unsigned long g_dwCCalcCF = 0;

unsigned long g_dwRegisterCCalc = 0;

#ifdef _MAC

extern Boolean g_fQuit;

#endif //_MAC

/***

*CCalc *CCalc::Create(void)

*Purpose:

*  Create an instance of the IDispatch calculator, load the

*  TypeInfo that describes the exposed functionality and

*  aggregate with an instance of CStdDispatch that has been

*  initialized with this TypeInfo.

*

*Entry:

*  None

*

*Exit:

*  return value = CCalc*, NULL if the creation failed.

*

***********************************************************************/

CCalc FAR*

CCalc::Create()

{

    HRESULT hresult;

    CCalc FAR* pcalc;

    ITypeLib FAR* ptlib;

    ITypeInfo FAR* ptinfo;

    IUnknown FAR* punkStdDisp;

    ptlib = NULL;

    ptinfo = NULL;

    if((pcalc = new FAR CCalc()) == NULL)

      return NULL;

    pcalc->AddRef();

    // first try to load the type library from the information in the registry

    if((hresult = LoadRegTypeLib(LIBID_DspCalc2, 1, 0, 0x0409, &ptlib)) != NOERROR){

      #define TLB_NAME OLESTR("dspcalc2.tlb")

      // if it wasn't registered, try to load it from the path/current directory

      // if this succeeds, it will have registered the type library for us

      // for the next time.

      if((hresult = LoadTypeLib(TLB_NAME, &ptlib)) != NOERROR){

#ifndef _MAC

        MessageBox(NULL, TSTR("error loading TypeLib"),

   TSTR("dspcalc2"), MB_OK);

#endif

        goto LError0;

      }

    }

    if((hresult = ptlib->GetTypeInfoOfGuid(IID_ICalculator, &ptinfo)) != NOERROR){

#ifndef _MAC

      MessageBox(NULL, TSTR("error accessing TypeInfo"),

         TSTR("dspcalc2"), MB_OK);

#endif

      goto LError0;

    }

    // Create and aggregate with an instance of the default

    // implementation of IDispatch that is initialized with our

    // TypeInfo.

    //

    hresult = CreateStdDispatch(

      pcalc,                            // controlling unknown

      &(pcalc->m_arith),                // vtable* to dispatch on

      ptinfo,

      &punkStdDisp);

    if(hresult != NOERROR)

      goto LError0;

    pcalc->m_punkStdDisp = punkStdDisp;

    ptinfo->Release();

    ptlib->Release();

    return pcalc;

LError0:;

    pcalc->Release();

    if(ptinfo != NULL)

      ptinfo->Release();

    if(ptlib != NULL)

      ptlib->Release();

    return NULL;

}

//---------------------------------------------------------------------

//                        IUnknown methods

//---------------------------------------------------------------------

STDMETHODIMP

CCalc::QueryInterface(REFIID riid, void FAR* FAR* ppv)

{

    if(IsEqualIID(riid, IID_IUnknown)){

      *ppv = this;

    }else

    if(IsEqualIID(riid, IID_IDispatch) ||

       IsEqualIID(riid, IID_DCalculator)){

      return m_punkStdDisp->QueryInterface(IID_IDispatch, ppv);

    }else

    if(IsEqualIID(riid, IID_ICalculator)){

      *ppv = &m_arith;

    }else {

      *ppv = NULL;

      return ResultFromScode(E_NOINTERFACE);

    }

    AddRef();

    return NOERROR;

}

STDMETHODIMP_(ULONG)

CCalc::AddRef()

{

    return ++m_refs;

}

STDMETHODIMP_(ULONG)

CCalc::Release()

{

    if(--m_refs == 0){

      if(m_punkStdDisp != NULL)

m_punkStdDisp->Release();

#ifndef _MAC

      PostQuitMessage(0);

#endif

      delete this;

      return 0;

    }

    return m_refs;

}

STDMETHODIMP

CArith::QueryInterface(REFIID riid, void FAR* FAR* ppv)

{

    return m_pcalc->QueryInterface(riid, ppv);

}

STDMETHODIMP_(ULONG)

CArith::AddRef()

{

    return m_pcalc->AddRef();

}

STDMETHODIMP_(ULONG)

CArith::Release()

{

    return m_pcalc->Release();

}

//---------------------------------------------------------------------

//                       Arithmetic features

//---------------------------------------------------------------------

STDMETHODIMP_(void)

CArith::Clear()

{

    m_opnd = 0;

    m_accum = 0;

    m_op = OP_NONE;

    m_state = STATE_LOPND;

}

STDMETHODIMP_(void)

CArith::put_Accum(long l)

{

    m_accum = l;

}

STDMETHODIMP_(long)

CArith::get_Accum()

{

    return m_accum;

}

STDMETHODIMP_(void)

CArith::put_Opnd(long l)

{

    m_opnd = l;

}

STDMETHODIMP_(long)

CArith::get_Opnd()

{

    return m_opnd;

}

STDMETHODIMP_(void)

CArith::put_Op(OPERATORS op)

{

    m_op = op;

}

STDMETHODIMP_(OPERATORS)

CArith::get_Op()

{

    return m_op;

}

STDMETHODIMP_(VARIANT_BOOL)

CArith::Eval()

{

    if(m_op == OP_NONE)

      return FALSE;

    switch(m_op){

    case OP_PLUS:

      m_accum += m_opnd;

      break;

    case OP_MINUS:

      m_accum -= m_opnd;

      break;

    case OP_MULT:

      m_accum *= m_opnd;

      break;

    case OP_DIV:

      m_accum = (m_opnd == 0) ? 0 : (m_accum / m_opnd);

      break;

    default:

      // ASSERT(UNREACHED);

      return FALSE;

    }

    m_state = STATE_EVAL;

    return TRUE;

}

//---------------------------------------------------------------------

//                       User Interface features

//---------------------------------------------------------------------

/***

*void CArith::Display()

*Purpose:

*  Display the contents of the register currently being edited.

*

*Entry:

*  None

*

*Exit:

*  None

*

***********************************************************************/

STDMETHODIMP_(void)

CArith::Display()

{

    VARIANT var;

    VariantInit(&var);

    V_VT(&var) = VT_I4;

    V_I4(&var) = (m_state == STATE_ROPND) ? m_opnd : m_accum;

    VariantChangeType(&var, &var, 0, VT_BSTR);

    #ifdef _MAC

    {

      Rect rcItem;

      Handle hItem;

      char str[255];

      short sItemKind;

      strcpy(str, V_BSTR(&var));

      GetDItem(m_pcalc->m_pdlg, IDC_DISPLAY, &sItemKind, &hItem, &rcItem);

      SetIText(hItem, c2pstr(str));

    }

#else

    SetDlgItemText(m_pcalc->m_hwnd, IDC_DISPLAY, STRING(V_BSTR(&var)));

#endif

    VariantClear(&var);

}

STDMETHODIMP_(VARIANT_BOOL)

CArith::Button(SAFEARRAY FAR * psa)

{

    int i, button;

static struct {

    OLECHAR ch;

    int idc;

} NEAR rgIdcOfCh[] = {

      { OLESTR('+'), IDC_PLUS   }

    , { OLESTR('-'), IDC_MINUS  }

    , { OLESTR('*'), IDC_MULT   }

    , { OLESTR('/'), IDC_DIV    }

    , { OLESTR('C'), IDC_CLEAR  }

    , { OLESTR('c'), IDC_CLEAR  }

    , { OLESTR('='), IDC_EQUALS }

    , { OLESTR('0'), IDC_ZERO   }

    , { OLESTR('1'), IDC_ONE    }

    , { OLESTR('2'), IDC_TWO    }

    , { OLESTR('3'), IDC_THREE  }

    , { OLESTR('4'), IDC_FOUR   }

    , { OLESTR('5'), IDC_FIVE   }

    , { OLESTR('6'), IDC_SIX    }

    , { OLESTR('7'), IDC_SEVEN  }

    , { OLESTR('8'), IDC_EIGHT  }

    , { OLESTR('9'), IDC_NINE   }

    , { (OLECHAR)-1 , -1         }

};

    LONG saIndex, saUbound;

    VARIANT varButton;

    // Since this is a vararg function, we should be given a 1-dimensional

    // array with 0 for the lower bound. The array could be uninitialized

    // if 0 args were passed to us -- this call will give an error in this case.

    if (SafeArrayGetUBound(psa, 1, &saUbound) != NOERROR)

      return FALSE;	// most likely 0 args were passed to us

    for (saIndex = 0; saIndex <= saUbound; saIndex++) {

      // get next parameter

      if (SafeArrayGetElement(psa, &saIndex, &varButton) != NOERROR)

return FALSE;

      // convert it to a string in-place

      if (VariantChangeType(&varButton, &varButton, 0, VT_BSTR) != NOERROR)

goto Error;

      // if the string is more that 1 character long, then we know its wrong.

      if(SysStringLen(varButton.bstrVal) > 1)

        goto Error;

      // translate button string into control ID

      for(i = 0;; ++i){

        if(rgIdcOfCh[i].ch == -1)

  goto Error;

        if(rgIdcOfCh[i].ch == varButton.bstrVal[0]){

  button = rgIdcOfCh[i].idc;

  break;

        }

      }

      VariantClear(&varButton);	// done with the parameter

      if (!ButtonPush(button))

return FALSE;

    } // for

    return TRUE;	// success

Error:

    VariantClear(&varButton);

    return FALSE;	// failure

}

// the following method is internal, and not exposed for programmability

BOOL

CArith::ButtonPush(int button)

{

    if(button >= IDC_ZERO && button <= IDC_NINE){

      long lVal = button - IDC_ZERO;

      switch(m_state){

      case STATE_EVAL:

m_accum = lVal;

m_state = STATE_LOPND;

break;

      case STATE_OP:

m_opnd = lVal;

m_state = STATE_ROPND;

break;

      case STATE_LOPND:

m_accum = (m_accum * 10) + lVal;

break;

      case STATE_ROPND:

m_opnd  = (m_opnd * 10) + lVal;

break;

      }

    }else if(button >= IDC_PLUS && button <= IDC_DIV){

      if(m_state == STATE_LOPND){

m_opnd  = m_accum;

m_state = STATE_OP;

m_op    = (OPERATORS)(button - IDC_PLUS + OP_PLUS);

      }

    }else if(button == IDC_EQUALS){

      if(m_state > STATE_LOPND)

        Eval();

    }else if (button == IDC_CLEAR){

      Clear();

    } else {

      return 0; // unknown button

    }

    // Flash the button

#ifdef _MAC

    {

      Rect rcItem;

      long lDummy;

      Handle hItem;

      short sItemKind;

      GetDItem(m_pcalc->m_pdlg, button, &sItemKind, &hItem, &rcItem);

      HiliteControl((ControlHandle)hItem, 1);

      Delay(6, &lDummy);

      HiliteControl((ControlHandle)hItem, 0);

    }

#else

    SendMessage(m_pcalc->m_hwnd, BM_SETSTATE, 1, 0L);

    SendMessage(m_pcalc->m_hwnd, BM_SETSTATE, 0, 0L);

#endif

    // Update the calculator display

    Display();

    return TRUE;

}

/***

*void CArith::Quit()

*Purpose:

*

*Entry:

*  None

*

*Exit:

*  None

*

***********************************************************************/

STDMETHODIMP_(void)

CArith::Quit()

{

#ifndef _MAC

    PostQuitMessage(0);

#else

    g_fQuit = TRUE;

#endif

}

//---------------------------------------------------------------------

//                      The CCalc Class Factory

//---------------------------------------------------------------------

IClassFactory FAR*

CCalcCF::Create()

{

    return new FAR CCalcCF();

}

STDMETHODIMP

CCalcCF::QueryInterface(REFIID riid, void FAR* FAR* ppv)

{

    if(IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IClassFactory)){

      AddRef();

      *ppv = this;

      return NOERROR;

    }

    *ppv = NULL;

    return ResultFromScode(E_NOINTERFACE);

}

STDMETHODIMP_(ULONG)

CCalcCF::AddRef()

{

    return ++m_refs;

}

STDMETHODIMP_(ULONG)

CCalcCF::Release()

{

    if(--m_refs == 0){

      delete this;

      return 0;

    }

    return m_refs;

}

STDMETHODIMP

CCalcCF::CreateInstance(

    IUnknown FAR* punkOuter,

    REFIID riid,

    void FAR* FAR* ppv)

{

extern CCalc FAR* g_pcalc;

    UNUSED(punkOuter);

    return g_pcalc->QueryInterface(riid, ppv);

}

STDMETHODIMP

#ifdef _MAC

CCalcCF::LockServer(unsigned long fLock)

#else

CCalcCF::LockServer(BOOL fLock)

#endif

{

    UNUSED(fLock);

    return NOERROR;

}

#ifdef _MAC

struct regentry{

    char *szKey;

    char *szValue;

} g_rgregentry[] = {

      { "CLSID\\{00020469-0000-0000-C000-000000000046}",

"OLE Automation DspCalc2 1.0 Application" }

    , { "CLSID\\{00020469-0000-0000-C000-000000000046}\\LocalServer",

"DCL2" }

    , { "CLSID\\{00020469-0000-0000-C000-000000000046}\\ProgID",

"Dspcalc2.Application" }

    , { "CLSID\\{00020469-0000-0000-C000-000000000046}\\InprocHandler",

"OLE2:Def$DefFSet" }

    , { "DCL2", "{00020469-0000-0000-C000-000000000046}" }

    , { "Dspcalc2.Application\\CLSID",

"{00020469-0000-0000-C000-000000000046}" }

};

HRESULT

EnsureRegistration()

{

    HKEY hkey;

    if(RegOpenKey(HKEY_CLASSES_ROOT, "DCL2", &hkey) == NOERROR){

      RegCloseKey(hkey);

      return NOERROR;

    }

    for(int i = 0; i < DIM(g_rgregentry); ++i){

      if(RegSetValue(HKEY_CLASSES_ROOT, g_rgregentry[i].szKey, REG_SZ, g_rgregentry[i].szValue, 0) != ERROR_SUCCESS)

        return ResultFromScode(E_FAIL);

    }

    return NOERROR;

}

#endif //_MAC

/***

*HRESULT InitOle(void)

*Purpose:

*  Initialize Ole, and register our class factories.

*

*Entry:

*  None

*

*Exit:

*  None

*

***********************************************************************/

HRESULT

InitOle()

{

    HRESULT hresult;

    IClassFactory FAR* pcf;

    if((hresult = OleInitialize(NULL)) != NOERROR)

      goto LError0;

#ifdef _MAC

    if((hresult = EnsureRegistration()) != NOERROR)

      goto LError0;

#endif

    // create the single global instance of CCalc

    if((g_pcalc = CCalc::Create()) == NULL){

      hresult = ResultFromScode(E_OUTOFMEMORY);

      goto LError0;

    }

    if((pcf = CCalcCF::Create()) == NULL)

      goto LError1;

    hresult = CoRegisterClassObject(

      CLSID_CCalc2,

      pcf,

      CLSCTX_LOCAL_SERVER,

      REGCLS_MULTIPLEUSE,

      &g_dwCCalcCF);

    if(hresult != NOERROR)

      goto LError2;

    hresult = RegisterActiveObject(

      g_pcalc, CLSID_CCalc2, NULL, &g_dwRegisterCCalc);

    if(hresult != NOERROR)

      goto LError2;

    pcf->Release();

    return NOERROR;

LError2:;

    pcf->Release();

LError1:;

    UninitOle();

LError0:;

    return hresult;

}

HRESULT

UninitOle()

{

    if(g_dwRegisterCCalc != 0)

      RevokeActiveObject(g_dwRegisterCCalc, NULL);

    if(g_dwCCalcCF != 0)

      CoRevokeClassObject(g_dwCCalcCF);

    // cause the remaining typeinfo to be released

    if(g_pcalc != NULL)

      g_pcalc->Release();

    OleUninitialize();

    return NOERROR;

}


 HOSTENV.H  (DSPCALC2 Sample)

/***

*hostenv.h

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*

*Purpose:

*  Generic host specific includes.

*

*Implementation Notes:

*

*****************************************************************************/

#if defined(_MAC)

#if defined(_PPCMAC)

#pragma data_seg("_FAR_DATA")

#pragma data_seg( )

#define MAXLONG 0x7fffffff

#define EventHandlerProcPtr AEEventHandlerUPP

#else //_PPCMAC

#define  GetMenuItemText(mApple,menuItem,daName)  GetItem(mApple,menuItem,daName)

#endif //_PPCMAC

#endif //_MAC

#if defined(_MAC)

#if defined(_MSC_VER)

# include <values.h>

# include <types.h>

# include <string.h>

# include <quickdra.h>

# include <fonts.h>

# include <events.h>

# include <resource.h>

# include <menus.h>

# include <textedit.h>

# include <dialogs.h>

# include <desk.h>

# include <toolutil.h>

# include <memory.h>

# include <files.h>

# include <osutils.h>

# include <osevents.h>

# include <diskinit.h>

# include <packages.h>

# include <traps.h>

# include <AppleEve.h>

#else //_MSC_VER

# include <values.h>

# include <types.h>

# include <strings.h>

# include <quickdraw.h>

# include <fonts.h>

# include <events.h>

# include <resources.h>

# include <windows.h>

# include <menus.h>

# include <textedit.h>

# include <dialogs.h>

# include <desk.h>

# include <toolutils.h>

# include <memory.h>

# include <files.h>

# include <osutils.h>

# include <osevents.h>

# include <diskinit.h>

# include <packages.h>

# include <traps.h>

# include <AppleEvents.h>

#endif //_MSC_VER

# include <ole2.h>

# include <olenls.h>

# include <dispatch.h>

# define TCHAR	char

# define TSTR(str)	str

# define STRING(str)	        (str)

# define WIDESTRING(str)        (str)

#elif defined(WIN32)

# include <windows.h>

# include <ole2.h>

# include <oleauto.h>

# if defined(UNICODE)

    #define TCHAR	WCHAR

    #define TSTR(str)	L##str

    #define STRING(str)	        (str)

    #define WIDESTRING(str)	(str)

# else

    #define TCHAR	char

    #define TSTR(str)	str

    #define STRING(str)	        AnsiString(str)

    #define WIDESTRING(str)	WideString(str)

    extern "C" char FAR* AnsiString(OLECHAR FAR* strIn);

    extern "C" OLECHAR FAR* WideString(char FAR* strIn);

# endif

#else /* WIN16 */

# include <windows.h>

# include <ole2.h>

# include <olenls.h>

# include <dispatch.h>

# define TCHAR	char

# define TSTR(str)	str

# define STRING(str)	        (str)

# define WIDESTRING(str)        (str)

#endif


 MAIN.CPP  (DSPCALC2 Sample)

/***

*main.cpp

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*  Information Contained Herein Is Proprietary and Confidential.

*

*Purpose:

*  This module is the main entry point of the sample IDispatch

*  calculator, dspcalc2.exe.

*

*  This program is intended to demonstrate an implementation of

*  the IDispatch interface.

*

*Implementation Notes:

*

*****************************************************************************/

#include "dspcalc2.h"

TCHAR g_szAppName[] = TSTR("DspCalc2");

BOOL InitApplication(HANDLE);

BOOL InitInstance(HANDLE, int);

extern "C" {

long FAR PASCAL WndProc(HWND, UINT, WPARAM, LPARAM);

int PASCAL WinMain(HANDLE, HANDLE, LPSTR, int);

}

extern "C" int PASCAL

WinMain(

    HANDLE hinst,

    HANDLE hPrevInstance,

    LPSTR lpCmdLine,

    int nCmdShow)

{

    MSG msg;

    if(!hPrevInstance)

      if(!InitApplication(hinst))

return FALSE;

    if(InitOle() != NOERROR)

      return FALSE;

    if(!InitInstance(hinst, nCmdShow)){

      UninitOle();

      return FALSE;

    }

    while(GetMessage(&msg, NULL, NULL, NULL)) {

      TranslateMessage(&msg);

      DispatchMessage(&msg);

    }

    UninitOle();

    return msg.wParam;

}

BOOL

InitApplication(HANDLE hinst)

{

    WNDCLASS  wc;

    wc.style	= CS_HREDRAW | CS_VREDRAW;

    wc.lpfnWndProc	= WndProc;

    wc.cbClsExtra	= 0;

    wc.cbWndExtra	= DLGWINDOWEXTRA;

    wc.hInstance	= hinst;

    wc.hIcon	= LoadIcon(hinst, g_szAppName);

    wc.hCursor	= LoadCursor(NULL, IDC_ARROW);

    wc.hbrBackground	= (HBRUSH)(COLOR_APPWORKSPACE+1);

    wc.lpszMenuName	= NULL;

    wc.lpszClassName	= g_szAppName;

    if(!RegisterClass(&wc))

      return FALSE;

    return TRUE;

}

BOOL

InitInstance(HANDLE hinst, int nCmdShow)

{

    g_pcalc->m_hwnd = CreateDialog(hinst, g_szAppName, 0, NULL);

    ShowWindow(g_pcalc->m_hwnd, nCmdShow);

    g_pcalc->m_arith.Display();

    return TRUE;

}

extern "C" long FAR PASCAL

WndProc(

    HWND hwnd,

    UINT message,

    WPARAM wParam,

    LPARAM lParam)

{

    switch(message){

    case WM_COMMAND:

      switch(wParam){

      case IDC_ZERO:

      case IDC_ONE:

      case IDC_TWO:

      case IDC_THREE:

      case IDC_FOUR:

      case IDC_FIVE:

      case IDC_SIX:

      case IDC_SEVEN:

      case IDC_EIGHT:

      case IDC_NINE:

      case IDC_PLUS:

      case IDC_MINUS:

      case IDC_MULT:

      case IDC_DIV:

      case IDC_CLEAR:

      case IDC_EQUALS:

g_pcalc->m_arith.ButtonPush(wParam);

return 0;

      }

      break;

    case WM_DESTROY:

      PostQuitMessage(0);

      return 0;

    }

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

}

#if defined(WIN32)

extern "C" char FAR*

ConvertStrWtoA(OLECHAR FAR* strIn, char FAR* buf, UINT size)

{

  int badConversion = FALSE;

  WideCharToMultiByte(CP_ACP, NULL,

              strIn, -1,

      buf, size,

      NULL, &badConversion);

  return buf;

}

extern "C" char FAR*

AnsiString(OLECHAR FAR* strIn)

{

  static char buf[256];

  return (ConvertStrWtoA(strIn, buf, 256));

}

#endif


 RESOURCE.H  (DSPCALC2 Sample)

/***

*resource.h

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*

*Purpose:

*

*Implementation Notes:

*

*****************************************************************************/

#ifdef _MAC

#define kMinSize	500	/* minimum size (in K) */

#define kPrefSize	500	/* preferred size (in K) */

#define kMinHeap	21 * 1024

#define kMinSpace	8 * 1024

#define	rMenuBar	128	/* menu bar */

#define	rAboutAlert	128	/* about alert */

#define	rUserAlert	129	/* error alert */

#define	rCalc	130

#define	mApple	128	/* Apple menu */

#define	iAbout	1

#define	mFile	129	/* File menu */

#define iClose	4

#define	iQuit	12

#define	mEdit	130	/* Edit menu */

#define	iUndo	1

#define	iCut	3

#define	iCopy	4

#define	iPaste	5

#define	iClear	6

#endif

// Note: there is code that depends on all of the digits being contiguous

// and in the following order.

// Mac Note: On the mac these IDs correspond to the control indices

// in the DITL array.

#define IDC_ZERO     1

#define IDC_ONE      2

#define IDC_TWO      3

#define IDC_THREE    4

#define IDC_FOUR     5

#define IDC_FIVE     6

#define IDC_SIX      7

#define IDC_SEVEN    8

#define IDC_EIGHT    9

#define IDC_NINE     10

// Note: there is code that depends on the operators being contiguous

// and in the following order.

//

#define IDC_PLUS     11

#define IDC_MINUS    12

#define IDC_MULT     13

#define IDC_DIV      14

#define IDC_CLEAR    15

#define IDC_EQUALS   16

#define IDC_DISPLAY  17


 DISPDEMO

--------------------------------------- OLE Automation Sample Program: DispDemo ---------------------------------------

DispDemo is a sample OLE Automation controller.  DispDemo drives the two polygon servers which are also provided as samples.

----------------- Program Structure ----------------- The interesting part of DispDemo is in the remote polygon class.  The remote polygon class was constructed so that  the IDispatch members could be accessed conveniently from  C++.  The remote polygon class does this by transforming the C++ calls into IDispatch calls.  The code that calls these routines has no idea that it is going through IDispatch.


 MAKEFILE  (DISPDEMO Sample)

##############################################################################

#

#  (c) Copyright Microsoft Corp. 1992-1993 All Rights Reserved

#

#  File:

#

#    makefile - makefile for dispdemo.exe

#

#  Purpose:

#

#    Builds the OLE 2.0 IDispatch sample client application, dispdemo.exe.

#

#

#  Usage:

#

#     NMAKE                     ; build with defaults

#     or: NMAKE option          ; build with the given option(s)

#     or: NMAKE clean           ; erase all compiled files

#

#     option:

#         dev = [win16 | win32] ; dev=win32 is the default

#         DEBUG=[0|1]           ; DEBUG=1 is the default

#

#

#  Notes:

#

#    This makefile assumes that the PATH, INCLUDE and LIB environment

#    variables are setup properly.

#

##############################################################################

##########################################################################

#

# Default Settings

#

!if "$(dev)" == ""

dev = win32

!endif

!if !("$(dev)" == "win16" || "$(dev)" == "win32")

!error Invalid dev option, choose from [win16 | win32]

!endif

!if "$(dev)" == "win16"

TARGET  = WIN16

!endif

!if "$(dev)" == "win32"

TARGET  = WIN32

!endif

!ifdef NODEBUG

DEBUG = 0

!endif

!if "$(DEBUG)" == "0"

NODEBUG = 1

!endif

!if "$(DEBUG)" == ""

DEBUG = 1

!endif

##########################################################################

#

# WIN16 Settings

#

!if "$(TARGET)" == "WIN16"

CC   = cl

LINK = link

RCFLAGS = -dWIN16

CFLAGS = -W3 -AM -GA -GEs -DWIN16 -c

LINKFLAGS = /NOD /NOI /BATCH /ONERROR:NOEXE

LIBS = libw.lib mlibcew.lib

!if "$(DEBUG)" == "1"

CFLAGS = $(CFLAGS) -Od -Zi -D_DEBUG $(CL)

LINKFLAGS = $(LINKFLAGS) /COD

!else

CFLAGS = $(CFLAGS) -Ox $(CL)

LINKFLAGS = $(LINKFLAGS) /FAR /PACKC

!endif

!endif

##########################################################################

#

# WIN32 Settings

#

!if "$(TARGET)" == "WIN32"

!include <$(MSTOOLS)\samples\ole\include\olesampl.mak>

CC = $(cc)

CFLAGS = $(cflags) $(cvarsmt) -DINC_OLE2 -DUNICODE $(cdebug)

!ifndef NODEBUG

CFLAGS = $(CFLAGS) -D_DEBUG

!endif

LINK = $(link)

LINKFLAGS = $(linkdebug) $(guilflags)

RCFLAGS = -DWIN32

!endif

##########################################################################

#

# Build rules

#

.cpp.obj:

    @echo Compiling $<...

    $(CC) $<

.c.obj:

    @echo Compiling $<...

    $(CC) $<

##########################################################################

#

# Application Settings

#

APPS = dispdemo

!if "$(TARGET)" == "WIN16"

LIBS = ole2.lib compobj.lib ole2disp.lib $(LIBS)

!endif

!if "$(TARGET)" == "WIN32"

LIBS = $(olelibsmt)

!endif

OBJS = \

         winmain.obj \

         misc.obj \

         crempoly.obj \

         clsid.obj

##########################################################################

#

# Default Goal

#

goal : setflags $(APPS).exe

setflags :

        set CL=$(CFLAGS)

##########################################################################

#

# Clean (erase) generated files

#

clean :

    if exist *.obj       del *.obj

    if exist $(APPS).exe del $(APPS).exe

    if exist $(APPS).map del $(APPS).map

    if exist $(APPS).res del $(APPS).res

##########################################################################

#

# Application Build (WIN16 Specific)

#

!if "$(TARGET)" == "WIN16"

$(APPS).exe : $(OBJS) $(APPS).def $(APPS).res $(APPS).ico

        link $(LINKFLAGS) @<<

$(OBJS),

$@,,

$(LIBS),

$(APPS).def

<<

        rc -k -t $(APPS).res $@

!endif

##########################################################################

#

# Application Build (WIN32 Specific)

#

!if "$(TARGET)" == "WIN32"

$(APPS).exe : $(OBJS) $(APPS).def $(APPS).res $(APPS).ico

      $(LINK) @<<

        $(LINKFLAGS)

        -out:$@

        -map:$*.map

        $(OBJS)

        $(APPS).res

        $(LIBS)

<<

!endif

##########################################################################

#

# Application Build (Common)

#

$(APPS).res : $(APPS).rc

        rc $(RCFLAGS) -r -fo$@ $?

##########################################################################

#

# Dependencies

#

winmain.obj: winmain.cpp dispdemo.h

    $(CC) winmain.cpp

misc.obj: misc.cpp dispdemo.h

    $(CC) misc.cpp

crempoly.obj: crempoly.cpp crempoly.h

    $(CC) crempoly.cpp

clsid.obj: clsid.c clsid.h

    $(CC) clsid.c


 CLSID.H  (DISPDEMO Sample)

/***

*clsid.h

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*  Information Contained Herein Is Proprietary and Confidential.

*

*Purpose:

*  This file defines the CLSIDs referenced by the IDispatch demo app.

*

*Implementation Notes:

*

*****************************************************************************/

DEFINE_GUID(CLSID_CPoly,  0x00020462, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46);

DEFINE_GUID(CLSID_CPoly2, 0x00020464, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46);

#ifdef INITGUID

# ifdef _MAC

DEFINE_GUID(GUID_NULL, 0L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);

DEFINE_GUID(IID_IDispatch, 0x00020400, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46);

DEFINE_GUID(IID_IEnumVARIANT, 0x00020404, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46);

DEFINE_GUID(IID_IUnknown, 0x00000000, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46);

DEFINE_GUID(IID_IClassFactory, 0x00000001, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46);

# endif

#endif


 CLSID.C  (DISPDEMO Sample)

/***

*clsid.c

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*  Information Contained Herein Is Proprietary and Confidential.

*

*Purpose:

*  This file allocates and initializes the CLSIDs.

*

*****************************************************************************/

#ifdef _PPCMAC

#pragma data_seg ("_FAR_DATA")

#pragma data_seg ( )

#endif

#ifdef _MAC

# include <Types.h>

#ifdef _MSC_VER

# include <Processe.h>

# include <AppleEve.h>

#else //_MSC_VER

# include <Processes.h>

# include <AppleEvents.h>

#endif //_MSC_VER

#else

# include <windows.h>

#endif

#ifndef WIN32

#include <compobj.h>

#endif //!WIN32

// this redefines the DEFINE_GUID() macro to do allocation.

//

#include <initguid.h>

#ifndef INITGUID

# define INITGUID

#endif

// due to the previous header, including this causes the DEFINE_GUID

// definitions in the following header(s) to actually allocate data.

//

#include "clsid.h"


 CREMPOLY.H  (DISPDEMO Sample)

/***

*crempoly.h

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*  Information Contained Herein Is Proprietary and Confidential.

*

*Purpose:

*  This file defines the CRemPoly remote polygon object.

*

*Implementation Notes:

*

*****************************************************************************/

class CRemPoly : public IUnknown {

public:

    static HRESULT Create(CLSID clsid, CRemPoly FAR* FAR*);

    // IUnknown methods

    //

    STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppvObj);

    STDMETHOD_(unsigned long, AddRef)(void);

    STDMETHOD_(unsigned long, Release)(void);

    // Introduced methods

    //

    HRESULT Draw(void);

    HRESULT Dump(void);

    HRESULT Reset(void);

    HRESULT AddPoint(short x, short y);

    HRESULT EnumPoints(IEnumVARIANT FAR* FAR* ppenum);

    HRESULT GetXOrigin(short FAR* pxorg);

    HRESULT SetXOrigin(short xorg);

    HRESULT GetYOrigin(short FAR* pyorg);

    HRESULT SetYOrigin(short yorg);

    HRESULT GetWidth(short FAR* pwidth);

    HRESULT SetWidth(short width);

    HRESULT get_red(short FAR* psRed);

    HRESULT set_red(short sRed);

    HRESULT get_green(short FAR* psGreen);

    HRESULT set_green(short sGreen);

    HRESULT get_blue(short FAR* psBlue);

    HRESULT set_blue(short sBlue);

private:

    CRemPoly();

    HRESULT get_i2(DISPID dispid, short FAR* ps);

    HRESULT set_i2(DISPID dispid, short s);

    unsigned long m_refs;

    IDispatch FAR* m_pdisp;

    // NOTE: this enumeration exists simply to allow us to symbolicly

    // index the member name and id arrays (m_rgid and m_rgszMethods).

    // This doesn't (necessarrily) have any connection to the vtable

    // indices, it *only* needs to correspond correctly to the m_rgid

    // and m_rgszMethods arrays.

    //

    enum CREMPOLY_METHODS {

IMETH_CREMPOLY_DRAW = 0,

IMETH_CREMPOLY_DUMP,

IMETH_CREMPOLY_RESET,

IMETH_CREMPOLY_ADDPOINT,

IMETH_CREMPOLY_ENUMPOINTS,

IMETH_CREMPOLY_GETXORIGIN,

IMETH_CREMPOLY_SETXORIGIN,

IMETH_CREMPOLY_GETYORIGIN,

IMETH_CREMPOLY_SETYORIGIN,

IMETH_CREMPOLY_GETWIDTH,

IMETH_CREMPOLY_SETWIDTH,

IMETH_CREMPOLY_GETRED,

IMETH_CREMPOLY_SETRED,

IMETH_CREMPOLY_GETGREEN,

IMETH_CREMPOLY_SETGREEN,

IMETH_CREMPOLY_GETBLUE,

IMETH_CREMPOLY_SETBLUE,

IMETH_CREMPOLY_MAX

    };

    // member IDs - these are used by IDispatch::Invoke to identify the

    // method or property on the remote object we accessing.

    //

    DISPID m_rgdispid[IMETH_CREMPOLY_MAX];

    // member names - these are used to learn the member IDs when we

    // connect to the remote object.

    //

    static OLECHAR FAR* m_rgszMethods[IMETH_CREMPOLY_MAX];

};


 CREMPOLY.CPP  (DISPDEMO Sample)

/***

*crempoly.cpp

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*  Information Contained Herein Is Proprietary and Confidential.

*

*Purpose:

*  This file contains the implementation of CRemPoly, the remote polygon

*  class. This class presents a standard C++ vtable interface to the

*  rest of the application, and hides the details of talking to the

*  actual remote CPoly class exposed by the SPoly server. Each of

*  the introduced methods is simply a cover for an IDispatch invocation

*  of the actual method on the remote object.

*

*Implementation Notes:

*

*****************************************************************************/

#include "dispdemo.h"

#include "crempoly.h"

extern int g_fTrace;

// method names on the CPoly class.

//

OLECHAR FAR* CRemPoly::m_rgszMethods[] = {

    OLESTR("draw"),

    OLESTR("dump"),

    OLESTR("reset"),

    OLESTR("addpoint"),

    OLESTR("enumpoints"),

    OLESTR("getxorigin"),

    OLESTR("setxorigin"),

    OLESTR("getyorigin"),

    OLESTR("setyorigin"),

    OLESTR("getwidth"),

    OLESTR("setwidth"),

    OLESTR("get_red"),

    OLESTR("set_red"),

    OLESTR("get_green"),

    OLESTR("set_green"),

    OLESTR("get_blue"),

    OLESTR("set_blue")

};

#ifdef _MAC

# define IfMac(X) (X)

# define IfWin(X)

#else

# define IfMac(X)

# define IfWin(X) (X)

#endif

CRemPoly::CRemPoly()

{

    m_refs = 0;

    m_pdisp = (IDispatch FAR*)NULL;

}

// A useful pre-initialized DISPATCHPARAMS, used on all the methods that

// take 0 arguments.

//

DISPPARAMS NEAR g_dispparamsNoArgs = {NULL, NULL, 0, 0};

/***

*HRESULT CRemPoly::Create(clsid, CRemPoly**)

*

*Purpose:

*  This function creates an instance of the CRemPoly class, connects

*  it to the IDispatch interface of the remote CPoly class, and learns

*  the DISPIDs for the members (that we know about) exposed by that

*  class.

*

*Entry:

*  clsid = The CLSID of the CPoly we are to create. (taking this as a

*    param is a bit weird, but allows us to connect to several remote

*    versions.

*

*Exit:

*  return value = HRESULT

*

*  *pprempoly = pointer to the newly created CRemPoly, if successfyl.

*

***********************************************************************/

HRESULT

CRemPoly::Create(CLSID clsid, CRemPoly FAR* FAR* pprempoly)

{

    int i;

    HRESULT hresult;

    IUnknown FAR* punk;

    CRemPoly FAR* prempoly;

    prempoly = new FAR CRemPoly();

    if(prempoly == (CRemPoly FAR*)NULL){

      hresult = ResultFromScode(E_OUTOFMEMORY);

      goto LError;

    }

    prempoly->AddRef();

    // create an instance of the remote CPoly class.

    //

    IfMac(DbPrintf("CoCreateInstance(CLSID_CPoly)"));

    hresult = CoCreateInstance(

      clsid, NULL, CLSCTX_LOCAL_SERVER, IID_IUnknown, (void FAR* FAR*)&punk);

    if(hresult != NOERROR){

      IfMac(DbPrintf("CoCreateInstance() = 0x%x", hresult));

      IfWin(MessageBox(NULL, TSTR("Unable to create polygon object"),

               NULL, MB_OK));

      goto LFreeCRemPoly;

    }

    // were going to talk to this remote instance via IDispatch.

    //

    IfMac(DbPrintf("QueryInterface(IID_IDispatch)"));

    hresult = punk->QueryInterface(

      IID_IDispatch, (void FAR* FAR*)&prempoly->m_pdisp);

    if(hresult != NOERROR){

      IfMac(DbPrintf("QueryInterface(IID_IDispatch) = 0x%x", hresult));

      IfWin(MessageBox(NULL, TSTR("Unable to QueryInterface to IDispatch"),

               NULL, MB_OK));

      goto LReleaseUnk;

    }

    // We learn *all* the member IDs up front. A more sophisticated

    // implementation might defer learning about the IDs for a given

    // method until the first time the method is invoked, thereby

    // amortizing the creation costs.

    //

    IfMac(DbPrintf("GetIDsOfNames()"));

    for(i = 0; i < IMETH_CREMPOLY_MAX; ++i){

      hresult = prempoly->m_pdisp->GetIDsOfNames(

IID_NULL,

        &prempoly->m_rgszMethods[i],

1, LOCALE_USER_DEFAULT,

&prempoly->m_rgdispid[i]);

      if(hresult != NOERROR){

IfMac(DbPrintf("GetIDsOfNames() = 0x%x", hresult));

IfWin(MessageBox(NULL, TSTR("Unrecognized member name"),

         NULL, MB_OK));

goto LReleaseUnk;

      }

    }

    punk->Release();

    *pprempoly = prempoly;

    IfMac(DbPrintf("Object created."));

    return NOERROR;

LReleaseUnk:;

    punk->Release();

LFreeCRemPoly:;

    prempoly->Release();

LError:;

    return hresult;

}

//---------------------------------------------------------------------

//                     IUnknown methods

//---------------------------------------------------------------------

/***

*HRESULT CRemPoly::QueryInterface(REFIID, void**)

*

*Purpose:

*  Standard Ole2 implementation of QueryInterface. This class

*  supports the IUnknown interface, and introduces a number of

*  nonvirtual members.

*

*Entry:

*  riid = reference to the requested interface id

*

*Exit:

*  return value = HRESULT

*  *ppv = pointer to the requested interface, if successful.

*

***********************************************************************/

STDMETHODIMP

CRemPoly::QueryInterface(REFIID riid, void FAR* FAR* ppv)

{

    if(IsEqualIID(riid, IID_IUnknown)){

      *ppv = this;

      AddRef();

      return NOERROR;

    }

    *ppv = NULL;

    return ResultFromScode(E_NOINTERFACE);

}

/***

*unsigned long CRemPoly::AddRef(void)

*

*Purpose:

*  Add a reference to the instance.

*

*Entry:

*  None

*

*Exit:

*  return value = unsigned long. The resulting reference count.

*

***********************************************************************/

STDMETHODIMP_(unsigned long)

CRemPoly::AddRef(void)

{

    return ++m_refs;

}

/***

*unsigned long CRemPoly::Release(void)

*

*Purpose:

*  Release a reference to the instance. If the reference count goes

*  to zero, delete the instance.

*

*Entry:

*  None

*

*Exit:

*  return value = unsigned long. The resulting reference count.

*

***********************************************************************/

STDMETHODIMP_(unsigned long)

CRemPoly::Release(void)

{

    if(--m_refs == 0){

      if(m_pdisp != (IDispatch FAR*)NULL){

        m_pdisp->Release();

      }

      delete this;

      return 0;

    }

    return m_refs;

}

//---------------------------------------------------------------------

//                    Introduced methods

//---------------------------------------------------------------------

/*

 * Each of these methods is simply a cover for an IDispatch Invocation

 * of the actual method on the remote CPoly class. This allows CRemPoly

 * to present an interface that looks and acts just like the CPoly

 * object, even though the actual work is being done in another process.

 *

 */

/***

*HRESULT CRemPoly::Draw(void)

*

*Purpose:

*  Invoke the Draw method on the remote CPoly instance.

*

*Entry:

*  None

*

*Exit:

*  return value = HRESULT

*

***********************************************************************/

HRESULT

CRemPoly::Draw()

{

    return m_pdisp->Invoke(

      m_rgdispid[IMETH_CREMPOLY_DRAW],

      IID_NULL,

      LOCALE_USER_DEFAULT,

      DISPATCH_METHOD,

      &g_dispparamsNoArgs, NULL, NULL, NULL);

}

/***

*HRESULT CRemPoly::Dump(void)

*

*Purpose:

*  Invoke the Dump() method on the remote CPoly instance. This method

*  dumps the contained CPoints and writes the properties of the remote

*  CPoly instance to the debug window.

*

*Entry:

*  None

*

*Exit:

*  return value = HRESULT

*

***********************************************************************/

HRESULT

CRemPoly::Dump()

{

    return m_pdisp->Invoke(

      m_rgdispid[IMETH_CREMPOLY_DUMP],

      IID_NULL,

      LOCALE_USER_DEFAULT,

      DISPATCH_METHOD,

      &g_dispparamsNoArgs, NULL, NULL, NULL);

}

/***

*HRESULT CRemPoly::Reset(void)

*

*Purpose:

*  Invoke the Reset() method on the remote CPoly instance. The Reset()

*  method causes the remote CPoly to release all contained CPoints.

*

*Entry:

*  None

*

*Exit:

*  return value = HRESULT

*

***********************************************************************/

HRESULT

CRemPoly::Reset()

{

    return m_pdisp->Invoke(

      m_rgdispid[IMETH_CREMPOLY_RESET],

      IID_NULL,

      LOCALE_USER_DEFAULT,

      DISPATCH_METHOD,

      &g_dispparamsNoArgs, NULL, NULL, NULL);

}

/***

*HRESULT CRemPoly::AddPoint(short, short)

*

*Purpose:

*  Invoke the AddPoint method in the remote CPoly object to add a

*  new point with the given coordinates to this instance.

*

*Entry:

*  x,y = the x and y coordinates of the new point.

*

*Exit:

*  return value = HRESULT

*

***********************************************************************/

HRESULT

CRemPoly::AddPoint(short x, short y)

{

    HRESULT hresult;

    VARIANTARG varg[2];

    DISPPARAMS dispparams;

    V_VT(&varg[0]) = VT_I2;

    V_I2(&varg[0]) = y;

    V_VT(&varg[1]) = VT_I2;

    V_I2(&varg[1]) = x;

    dispparams.cArgs = 2;

    dispparams.rgvarg = varg;

    dispparams.cNamedArgs = 0;

    dispparams.rgdispidNamedArgs = NULL;

    hresult = m_pdisp->Invoke(

      m_rgdispid[IMETH_CREMPOLY_ADDPOINT],

      IID_NULL,

      LOCALE_USER_DEFAULT,

      DISPATCH_METHOD,

      &dispparams, NULL, NULL, NULL);

    return hresult;

}

/***

*HRESULT CRemPoly::EnumPoints(IEnumVARIANT**)

*Purpose:

*  Inoke the EnumPoints() method in the remote object to

*  get a enumerator for the points contained in the current poly.

*

*Entry:

*  None

*

*Exit:

*  return value = HRESULT

*

*  *ppenum = pointer to the point enumerator

*

***********************************************************************/

HRESULT

CRemPoly::EnumPoints(IEnumVARIANT FAR* FAR* ppenum)

{

    HRESULT hresult;

    IEnumVARIANT FAR* penum;

    VARIANT varResult, FAR* pvarResult;

    pvarResult = &varResult;

    VariantInit(pvarResult);

    hresult = m_pdisp->Invoke(

      m_rgdispid[IMETH_CREMPOLY_ENUMPOINTS],

      IID_NULL,

      LOCALE_USER_DEFAULT,

      DISPATCH_METHOD,

      &g_dispparamsNoArgs, pvarResult, NULL, NULL);

    if(hresult != NOERROR)

      return hresult;

    if(V_VT(pvarResult) != VT_UNKNOWN)

      return ResultFromScode(E_FAIL);

    hresult = V_UNKNOWN(pvarResult)->QueryInterface(

      IID_IEnumVARIANT, (void FAR* FAR*)&penum);

    if(hresult == NOERROR)

      *ppenum = penum;

    VariantClear(pvarResult);

    return NOERROR;

}

/***

*HRESULT CRemPoly::GetXOrigin(short*)

*

*Purpose:

*  Invoke the GetXOrigin() method on the remote object to extract

*  the current value of the XOrigin property.

*

*Entry:

*  None

*

*Exit:

*  return value = HRESULT

*

*  *pxorg = the current X origin of the polygon.

*

***********************************************************************/

HRESULT

CRemPoly::GetXOrigin(short FAR* pxorg)

{

    HRESULT hresult;

    VARIANT varResult;

    VariantInit(&varResult);

    hresult = m_pdisp->Invoke(

      m_rgdispid[IMETH_CREMPOLY_GETXORIGIN],

      IID_NULL,

      LOCALE_USER_DEFAULT,

      DISPATCH_METHOD,

      &g_dispparamsNoArgs, &varResult, NULL, NULL);

    if(hresult != NOERROR)

      return hresult;

    *pxorg = V_I2(&varResult);

    VariantClear(&varResult);

    return NOERROR;

}

/***

*HRESULT CRemPoly::SetXOrigin(short)

*

*Purpose:

*  Invoke the SetXOrigin method on the remote object to set the

*  XOrigin property of the polygon to the given value.

*

*Entry:

*  xorg = the new X origin

*

*Exit:

*  return value = HRESULT

*

***********************************************************************/

HRESULT

CRemPoly::SetXOrigin(short xorg)

{

    VARIANTARG varg;

    DISPPARAMS dispparams;

    V_VT(&varg) = VT_I2;

    V_I2(&varg) = xorg;

    dispparams.cArgs = 1;

    dispparams.cNamedArgs = 0;

    dispparams.rgvarg = &varg;

    return m_pdisp->Invoke(

      m_rgdispid[IMETH_CREMPOLY_SETXORIGIN],

      IID_NULL,

      LOCALE_USER_DEFAULT,

      DISPATCH_METHOD,

      &dispparams, NULL, NULL, NULL);

}

/***

*HRESULT CRemPoly::GetYOrigin(short*)

*

*Purpose:

*  Invoke the GetYOrigin() method on the remote object to extract

*  the current value of the YOrigin property.

*

*Entry:

*  None

*

*Exit:

*  return value = HRESULT

*

*  *pyorg = the current Y origin of the polygon

*

***********************************************************************/

HRESULT

CRemPoly::GetYOrigin(short FAR* pyorg)

{

    HRESULT hresult;

    VARIANT varResult;

    VariantInit(&varResult);

    hresult = m_pdisp->Invoke(

      m_rgdispid[IMETH_CREMPOLY_GETYORIGIN],

      IID_NULL,

      LOCALE_USER_DEFAULT,

      DISPATCH_METHOD,

      &g_dispparamsNoArgs, &varResult, NULL, NULL);

    if(hresult != NOERROR)

      return hresult;

    *pyorg = V_I2(&varResult);

    VariantClear(&varResult);

    return hresult;

}

/***

*HRESULT CRemPoly::SetYOrigin(short)

*

*Purpose:

*  Invoke the SetYOrigin method on the remote object to set the

*  YOrigin property of the polygon to the given value.

*

*Entry:

*  yorg = the new Y origin

*

*Exit:

*  return value = HRESULT

*

***********************************************************************/

HRESULT

CRemPoly::SetYOrigin(short yorg)

{

    VARIANTARG varg;

    DISPPARAMS dispparams;

    V_VT(&varg) = VT_I2;

    V_I2(&varg) = yorg;

    dispparams.cArgs = 1;

    dispparams.cNamedArgs = 0;

    dispparams.rgvarg = &varg;

    return m_pdisp->Invoke(

      m_rgdispid[IMETH_CREMPOLY_SETYORIGIN],

      IID_NULL,

      LOCALE_USER_DEFAULT,

      DISPATCH_METHOD,

      &dispparams, NULL, NULL, NULL);

}

/***

*HRESULT CRemPoly::GetWidth(short*)

*

*Purpose:

*  Invoke the GetWidth() method on the remote object to extract

*  the current value of the line width property.

*

*Entry:

*  None

*

*Exit:

*  return value = HRESULT

*

*  *pwidth = short, the current line width of the polygon

*

***********************************************************************/

HRESULT

CRemPoly::GetWidth(short FAR* pwidth)

{

    HRESULT hresult;

    VARIANT varResult;

    VariantInit(&varResult);

    hresult = m_pdisp->Invoke(

      m_rgdispid[IMETH_CREMPOLY_GETWIDTH],

      IID_NULL,

      LOCALE_USER_DEFAULT,

      DISPATCH_METHOD,

      &g_dispparamsNoArgs, &varResult, NULL, NULL);

    if(hresult != NOERROR)

      return hresult;

    *pwidth = V_I2(&varResult);

    VariantClear(&varResult);

    return NOERROR;

}

/***

*HRESULT CRemPoly::SetWidth(short)

*

*Purpose:

*  Invoke the SetWidth method on the remote object to set the

*  line width property of the polygon to the given value.

*

*Entry:

*  width = the new value for the line width property.

*

*Exit:

*  return value = HRESULT

*

***********************************************************************/

HRESULT

CRemPoly::SetWidth(short width)

{

    VARIANTARG varg;

    DISPPARAMS dispparams;

    V_VT(&varg) = VT_I2;

    V_I2(&varg) = width;

    dispparams.cArgs = 1;

    dispparams.cNamedArgs = 0;

    dispparams.rgvarg = &varg;

    return m_pdisp->Invoke(

      m_rgdispid[IMETH_CREMPOLY_SETWIDTH],

      IID_NULL,

      LOCALE_USER_DEFAULT,

      DISPATCH_METHOD,

      &dispparams, NULL, NULL, NULL);

}

HRESULT CRemPoly::get_red(short FAR* psRed)

{

    return get_i2(m_rgdispid[IMETH_CREMPOLY_GETRED], psRed);

}

HRESULT CRemPoly::set_red(short sRed)

{

    return set_i2(m_rgdispid[IMETH_CREMPOLY_SETRED], sRed);

}

HRESULT CRemPoly::get_green(short FAR* psGreen)

{

    return get_i2(m_rgdispid[IMETH_CREMPOLY_GETGREEN], psGreen);

}

HRESULT CRemPoly::set_green(short sGreen)

{

    return set_i2(m_rgdispid[IMETH_CREMPOLY_SETGREEN], sGreen);

}

HRESULT CRemPoly::get_blue(short FAR* psBlue)

{

    return get_i2(m_rgdispid[IMETH_CREMPOLY_GETBLUE], psBlue);

}

HRESULT CRemPoly::set_blue(short sBlue)

{

    return set_i2(m_rgdispid[IMETH_CREMPOLY_SETBLUE], sBlue);

}

HRESULT

CRemPoly::get_i2(DISPID dispid, short FAR* ps)

{

    HRESULT hresult;

    VARIANT varResult;

    VariantInit(&varResult);

    hresult = m_pdisp->Invoke(

      dispid,

      IID_NULL,

      LOCALE_SYSTEM_DEFAULT,

      DISPATCH_METHOD,

      &g_dispparamsNoArgs,

      &varResult, NULL, NULL);

    if(hresult != NOERROR)

      return hresult;

    hresult = VariantChangeType(&varResult, &varResult, 0, VT_I2);

    if(hresult != NOERROR){

      VariantClear(&varResult);

      return hresult;

    }

    *ps = V_I2(&varResult);

    VariantClear(&varResult);

    return NOERROR;

}

HRESULT

CRemPoly::set_i2(DISPID dispid, short s)

{

    VARIANTARG varg;

    DISPPARAMS dispparams;

    V_VT(&varg) = VT_I2;

    V_I2(&varg) = s;

    dispparams.cArgs = 1;

    dispparams.cNamedArgs = 0;

    dispparams.rgvarg = &varg;

    return m_pdisp->Invoke(

      dispid,

      IID_NULL,

      LOCALE_SYSTEM_DEFAULT,

      DISPATCH_METHOD,

      &dispparams, NULL, NULL, NULL);

}

/***

*void DoPoly(CLSID)

*

*Purpose:

*  This function simply exercises our CRemPoly class by creating an

*  instance and invoking a number of its methods.

*

*Entry:

*  None

*

*Exit:

*  None

*

***********************************************************************/

STDAPI

DoPoly(CLSID clsid)

{

    HRESULT hr;

    int numpoly, i, j;

static struct {

    short x;

    short y;

} rgptPoly[] = {

      { 25,   0}

    , { 75,   0}

    , {100,  25}

    , {100,  75}

    , { 75, 100}

    , { 25, 100}

    , {  0,  75}

    , {  0,  25}

};

static struct {

    short red;

    short green;

    short blue;

} rgrgbColors[] = {

#ifdef _MAC

      {     0,      0,      0}

    , {     0,      0, 0x7fff}

    , {     0, 0x7fff,      0}

    , {0x7fff,      0,      0}

    , {0x7fff,      0, 0x7fff}

    , {0x7fff, 0x7fff,      0}

    , {0x7fff, 0x7fff, 0x7fff}

#else

      {  0,   0,   0}

    , {  0,   0, 127}

    , {  0, 127,   0}

    , {127,   0,   0}

    , {127,   0, 127}

    , {127, 127,   0}

    , {127, 127, 127}

#endif

};

    CRemPoly FAR* rgprempoly[DIM(rgrgbColors)];

    numpoly = DIM(rgprempoly);

    // init

    for(i = 0; i < numpoly; ++i)

      rgprempoly[i] = (CRemPoly FAR*)NULL;

    for(i = 0; i < numpoly; ++i){

      hr = CRemPoly::Create(clsid, &rgprempoly[i]);

      if(hr != NOERROR)

        goto LError0;

      IfMac(DbPrintf("CRemPoly::Create()"));

      for(j = 0; j < DIM(rgptPoly); ++j){

        short x = rgptPoly[j].x;

short y = rgptPoly[j].y;

        IfMac(DbPrintf("CRemPoly::AddPoint(%d,%d)", x, y));

        hr = rgprempoly[i]->AddPoint(x, y);

ASSERT(hr == NOERROR);

      }

      for(j = 0; j < DIM(rgrgbColors); ++j){

        hr = rgprempoly[i]->SetWidth(i + j);

ASSERT(hr == NOERROR);

IfMac(DbPrintf("CRemPoly::SetWidth()"));

        hr = rgprempoly[i]->set_red(rgrgbColors[j].red);

ASSERT(hr == NOERROR);

IfMac(DbPrintf("CRemPoly::set_red()"));

        hr = rgprempoly[i]->set_green(rgrgbColors[j].green);

ASSERT(hr == NOERROR);

IfMac(DbPrintf("CRemPoly::set_green()"));

        hr = rgprempoly[i]->set_blue(rgrgbColors[j].blue);

ASSERT(hr == NOERROR);

IfMac(DbPrintf("CRemPoly::set_blue()"));

        hr = rgprempoly[i]->SetXOrigin((2*i) + j << 4);

ASSERT(hr == NOERROR);

IfMac(DbPrintf("CRemPoly::SetXOrigin()"));

        hr = rgprempoly[i]->SetYOrigin(j << 4);

ASSERT(hr == NOERROR);

IfMac(DbPrintf("CRemPoly::SetYOrigin()"));

        hr = rgprempoly[i]->Draw();

ASSERT(hr == NOERROR);

IfMac(DbPrintf("CRemPoly::Draw()"));

      }

    }

    hr = NOERROR;

LError0:;

    for(i = 0; i < numpoly; ++i){

      if(rgprempoly[i] != (CRemPoly FAR*)NULL){

rgprempoly[i]->Release();

      }

    }

    return hr;

}


 DISPDEMO.DEF  (DISPDEMO Sample)

NAME         DispDemo

DESCRIPTION  'IDispatch Demo Application'

EXETYPE      WINDOWS

STUB         'WINSTUB.EXE'

CODE         PRELOAD MOVEABLE DISCARDABLE

DATA         PRELOAD MULTIPLE

HEAPSIZE     1024

STACKSIZE    5120


 DISPDEMO.H  (DISPDEMO Sample)

/***

*dispdemo.h

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*  Information Contained Herein Is Proprietary and Confidential.

*

*Purpose:

*  IDispatch Demo App definitions.

*

*Implementation Notes:

*

*****************************************************************************/

#include "hostenv.h"

#include "resource.h"

#include "clsid.h"

#ifdef _MAC

# define UNUSED(X) ((void)(void*)&(X))

#else

# define UNUSED(X) (X)

#endif

#ifndef NEAR

# define NEAR

#endif

#define DIM(X) (sizeof(X) / sizeof(X[0]))

#define ASSERT(X) Assert(X, __FILE__, __LINE__)

#ifdef __cplusplus

extern "C" {

#endif

STDAPI InitOle(void);

STDAPI UninitOle(void);

STDAPI DoPoly(CLSID);

void   Assert(int, char FAR*, int);

#ifdef _MAC

void DbPrintf(char*, ...);

#endif

#ifdef __cplusplus

}

#endif


 DISPDEMO.RC  (DISPDEMO Sample)

#define NOKERNEL

#define NOGDI

#define NOSOUND

#define NOCOMM

#define NODRIVERS

#include "windows.h"

#include "dispdemo.h"

DISPDEMO ICON dispdemo.ico

DispDemoMenu MENU

BEGIN

    MENUITEM	"&CPoly",	IDM_POLY

    MENUITEM	"CPoly&2",	IDM_POLY2

    POPUP        "&Options"

    BEGIN

        MENUITEM "&Trace",	IDM_TRACE

    END

    POPUP        "&Help"

    BEGIN

        MENUITEM "&About IDispatch Demo...",	IDM_ABOUT

    END

END

AboutBox DIALOG 22, 17, 144, 75

STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU

CAPTION "About IDispatch Demo App"

BEGIN

    CTEXT "Microsoft Windows"	  -1,  0,  5, 144,  8

    CTEXT "IDispatch Demo Application"	  -1,  0, 14, 144,  8

    CTEXT "Version 2.0"	  -1,  0, 34, 144,  8

    DEFPUSHBUTTON "OK"	IDOK, 53, 59,  32, 14, WS_GROUP

END


 HOSTENV.H  (DISPDEMO Sample)

/***

*hostenv.h

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*

*Purpose:

*  Generic host specific includes.

*

*Implementation Notes:

*

*****************************************************************************/

#if defined(_MAC)

#if defined(_PPCMAC)

#pragma data_seg("_FAR_DATA")

#pragma data_seg( )

#define MAXLONG 0x7fffffff

#define EventHandlerProcPtr AEEventHandlerUPP

#else //_PPCMAC

#define  GetMenuItemText(mApple,menuItem,daName)  GetItem(mApple,menuItem,daName)

#endif //_PPCMAC

#endif //_MAC

#if defined(_MAC)

#if defined(_MSC_VER)

# include <values.h>

# include <types.h>

# include <string.h>

# include <quickdra.h>

# include <fonts.h>

# include <events.h>

# include <resource.h>

# include <menus.h>

# include <textedit.h>

# include <dialogs.h>

# include <desk.h>

# include <toolutil.h>

# include <memory.h>

# include <files.h>

# include <osutils.h>

# include <osevents.h>

# include <diskinit.h>

# include <packages.h>

# include <traps.h>

# include <AppleEve.h>

#else //_MSC_VER

# include <values.h>

# include <types.h>

# include <strings.h>

# include <quickdraw.h>

# include <fonts.h>

# include <events.h>

# include <resources.h>

# include <windows.h>

# include <menus.h>

# include <textedit.h>

# include <dialogs.h>

# include <desk.h>

# include <toolutils.h>

# include <memory.h>

# include <files.h>

# include <osutils.h>

# include <osevents.h>

# include <diskinit.h>

# include <packages.h>

# include <traps.h>

# include <AppleEvents.h>

#endif //_MSC_VER

# include <ole2.h>

# include <olenls.h>

# include <dispatch.h>

# define TCHAR	char

# define TSTR(str)	str

# define STRING(str)	        (str)

# define WIDESTRING(str)        (str)

#elif defined(WIN32)

# include <windows.h>

# include <ole2.h>

# include <oleauto.h>

# if defined(UNICODE)

    #define TCHAR	WCHAR

    #define TSTR(str)	L##str

    #define STRING(str)	        (str)

    #define WIDESTRING(str)	(str)

# else

    #define TCHAR	char

    #define TSTR(str)	str

    #define STRING(str)	        AnsiString(str)

    #define WIDESTRING(str)	WideString(str)

    extern "C" char FAR* AnsiString(OLECHAR FAR* strIn);

    extern "C" OLECHAR FAR* WideString(char FAR* strIn);

# endif

#else /* WIN16 */

# include <windows.h>

# include <ole2.h>

# include <olenls.h>

# include <dispatch.h>

# define TCHAR	char

# define TSTR(str)	str

# define STRING(str)	        (str)

# define WIDESTRING(str)        (str)

#endif


 MISC.CPP  (DISPDEMO Sample)

/***

*misc.cpp

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*  Information Contained Herein Is Proprietary and Confidential.

*

*Purpose:

*

*Implementation Notes:

*

*****************************************************************************/

// Use ANSI strings for assertions

#ifdef UNICODE

#  undef UNICODE

#endif

#include "dispdemo.h"

#include <stdio.h>

#include <stdarg.h>

int g_fTrace = 0;

STDAPI

InitOle(void)

{

    HRESULT hresult;

    if((hresult = OleInitialize(NULL)) != NOERROR)

      return hresult;

// UNDONE: temporary to try to get symbols for the DLL

    VARIANT var;

    VariantInit(&var);

    return NOERROR;

}

STDAPI

UninitOle()

{

    OleUninitialize();

    return NOERROR;

}

extern "C" void

Assert(int fCond, char FAR* file, int line)

{

    char buf[128];

    if(fCond)

      return;

    sprintf(buf, "Assertion failed: %s(%d)\n", file, line);

#ifdef _MAC

    DebugStr(c2pstr(buf));

#else

    OutputDebugString(buf);

    DebugBreak();

#endif

}

#ifdef _MAC

extern "C" {

extern WindowPtr g_pwndDebug;

void

DbPrintf(char *sz, ...)

{

    va_list args;

    WindowPtr pwndSaved;

static char rgchOut[256];

    if(g_pwndDebug == nil)

      return;

    GetPort(&pwndSaved);

    SetPort(g_pwndDebug);

    va_start(args, sz);

    vsprintf(rgchOut, sz, args);

    rgchOut[79] = '\0';

    EraseRect(&g_pwndDebug->portRect);

    TextFont(systemFont);

    MoveTo(10,20);

    DrawString(c2pstr(rgchOut));

    SetPort(pwndSaved);

}

}

#endif


 RESOURCE.H  (DISPDEMO Sample)

/***

*resource.h

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*

*Purpose:

*

*Implementation Notes:

*

*****************************************************************************/

#ifdef _MAC

#define kMinSize	500	/* minimum size (in K) */

#define kPrefSize	500	/* preferred size (in K) */

#define	rMenuBar	128	/* menu bar */

#define	rAboutAlert	128	/* about alert */

#define	rUserAlert	129	/* error alert */

#define	rWindow	128	/* application's window */

#define	rDebugWindow	129	/* debug window */

#define	mApple	128	/* Apple menu */

#define	iAbout	1

#define	mFile	129	/* File menu */

#define	iNew	1

#define	iClose	4

#define	iQuit	12

#define	mEdit	130	/* Edit menu */

#define	iUndo	1

#define	iCut	3

#define	iCopy	4

#define	iPaste	5

#define	iClear	6

#define mSpoly	131

#define iSpoly	1

#define mSpoly2	132

#define iSpoly2	1

#define kMinHeap	21 * 1024

#define kMinSpace	8 * 1024

#else /* WIN16 || WIN32 */

# define IDM_ABOUT	1

# define IDM_POLY	2

# define IDM_POLY2	3

# define IDM_TRACE	4

# define IDM_MAX	5

#endif


 WINMAIN.CPP  (DISPDEMO Sample)

/***

*dispdemo.c - IDespatch demo/sample client application.

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*  Information Contained Herein Is Proprietary and Confidential.

*

*Purpose:

*  This module is the main entry point for the sample IDispatch client,

*  dispdemo.exe.

*

*  This program is intended to demonstrate a client invoking methods

*  and referencing properties on a remote object via the IDispatch

*  interface.

*

*  The bulk of the sample can be found in the file crempoly.cpp, which

*  implements CRemPoly, the remote polygon class.

*

*Implementation Notes:

*

*****************************************************************************/

#include "dispdemo.h"

extern BOOL g_fTrace;

BOOL InitApplication(HANDLE);

BOOL InitInstance(HANDLE, int);

BOOL FAR PASCAL About(HWND, unsigned, WORD, LONG);

extern "C" {

int PASCAL WinMain(HANDLE, HANDLE, LPSTR, int);

LRESULT FAR PASCAL MainWndProc(HWND, UINT, WPARAM, LPARAM);

}

HANDLE g_hInst;

TCHAR g_szDispDemoWClass[] = TSTR("DispDemoWClass");

extern "C" int PASCAL

WinMain(

    HANDLE hinst,

    HANDLE hPrevInstance,

    LPSTR lpCmdLine,

    int nCmdShow)

{

    MSG msg;

    (lpCmdLine); // UNUSED

    if(!hPrevInstance)

      if(!InitApplication(hinst))

        return FALSE;

    if(InitOle() != NOERROR)

      return FALSE;

    if(!InitInstance(hinst, nCmdShow))

      return FALSE;

    while(GetMessage(&msg, NULL, 0, 0)) {

      TranslateMessage(&msg);

      DispatchMessage(&msg);

    }

    return msg.wParam;

}

BOOL

InitApplication(HANDLE hinst)

{

    WNDCLASS  wc;

    wc.style            = NULL;

    wc.lpfnWndProc      = MainWndProc;

    wc.cbClsExtra       = 0;

    wc.cbWndExtra       = 0;

    wc.hInstance        = hinst;

    wc.hIcon            = LoadIcon(hinst, TSTR("DISPDEMO"));

    wc.hCursor          = LoadCursor(NULL, IDC_ARROW);

    wc.hbrBackground    = GetStockObject(WHITE_BRUSH);

    wc.lpszMenuName     = TSTR("DispDemoMenu");

    wc.lpszClassName    = g_szDispDemoWClass;

    if(!RegisterClass(&wc))

      return FALSE;

    return TRUE;

}

#ifdef WIN32

#define szAppTitle TSTR("IDispatch Demo App (32-bit)")

#else //WIN32

#define szAppTitle TSTR("IDispatch Demo App")

#endif //WIN32

BOOL

InitInstance(HANDLE hinst, int nCmdShow)

{

    HWND hWnd;

    g_hInst = hinst;

    hWnd = CreateWindow(

      g_szDispDemoWClass,

      szAppTitle,

      WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX,

      CW_USEDEFAULT, CW_USEDEFAULT, 300, 100,

      NULL, NULL, hinst, NULL);

    if(!hWnd)

      return FALSE;

    ShowWindow(hWnd, nCmdShow);

    UpdateWindow(hWnd);

    return TRUE;

}

BOOL FAR PASCAL

About(HWND hDlg, unsigned message, WORD wParam, LONG lParam)

{

    switch(message){

    case WM_INITDIALOG:

      return TRUE;

    case WM_COMMAND:

      switch(wParam){

      case IDOK:

      case IDCANCEL:

        EndDialog(hDlg, TRUE);

        return TRUE;

      }

      break;

    }

    return FALSE;

}

extern "C" LRESULT FAR PASCAL

MainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)

{

    HMENU hmenu;

static FARPROC pfnAbout;

    switch(message){

    case WM_COMMAND:

      switch(wParam){

      case IDM_TRACE:

        /* enable/disable trace */

        g_fTrace = (g_fTrace) ? FALSE : TRUE;

        hmenu = GetMenu(hwnd);

        CheckMenuItem(hmenu, IDM_TRACE, g_fTrace ? MF_CHECKED : MF_UNCHECKED);

        return 0;

      case IDM_POLY:

        DoPoly(CLSID_CPoly);

        return 0;

      case IDM_POLY2:

        DoPoly(CLSID_CPoly2);

        return 0;

      case IDM_ABOUT:

        pfnAbout = (FARPROC)MakeProcInstance((FARPROC)About, g_hInst);

        DialogBox(g_hInst, TSTR("AboutBox"), hwnd, pfnAbout);

        FreeProcInstance(pfnAbout);

        return 0;

      }

      break;

    case WM_CLOSE:

      DestroyWindow(hwnd);

      return 0;

    case WM_DESTROY:

      UninitOle();

      PostQuitMessage(0);

      return 0;

    }

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

}


GIZMOBAR

This sample demonstrates an implementation of the GizmoBar custom control. For information on compiling and building the sample, see MAKEFILE (GIZMOBAR Sample).


MAKEFILE  (GIZMOBAR Sample)

#

# MAKEFILE

# GizmoBar Version 1.00, March 1993

#

#

!include <$(MSTOOLS)\samples\ole\include\olesampl.mak>

APP=gizmobar

all: $(APP).dll

OLE_FLAGS = -DUNICODE

!ifndef NO_DEBUG

OLE_FLAGS = $(OLE_FLAGS) /D_DEBUG /DDEBUG /D_DEBUGTRACE=0

!endif

.SUFFIXES: .h .c .obj .exe .dll .cpp .res .rc

INCLS    = ..\include\$(APP).h gizmoint.h gizmo.h win1632.h

OBJS1    = $(APP).obj init.obj

OBJS2    = api.obj paint.obj gizmo.obj

OBJS     = $(OBJS1) $(OBJS2)

RCFILES1 = $(APP).rcv

RCFILES  = $(RCFILES1)

#

# Tool Directives

#

.c.obj:

    $(cc) $(cvars) $(cflags) $(cdebug) $(OLE_FLAGS) $*.c

.rc.res:

    rc -r -DWIN32 -DDEBUG $*.rc

clean:

    -del *.obj

    -del *.dll

    -del *.res

    -del *.lib

    -del *.map

    -del *.exp

$(APP).dll: $(OBJS) $(APP).lib $(APP).def $(APP).res

    $(link) $(linkdebug) $(dlllflags) $(APP).exp $(OBJS) $*.res -out:$@ -map:$*.map $(guilibsdll)  bttncur.lib

    if not exist ..\bin mkdir ..\bin

    copy $(APP).dll ..\bin

$(APP).lib: $(OBJS) $(APP).def

    $(implib) $(OBJS) -out:$(APP).lib -def:$(APP).def -machine:$(CPU)

    if not exist ..\lib mkdir ..\lib

    copy $(APP).lib ..\lib

##### Dependencies #####

$(APP).obj     : $(APP).c       $(INCLS)

paint.obj      : paint.c        $(INCLS)

init.obj       : init.c         $(INCLS)

api.obj        : api.c          $(INCLS)

gizmo.obj      : gizmo.c        $(INCLS)

$(APP).res  : $(APP).rc   $(INCLS) $(RCFILES)


API.C  (GIZMOBAR Sample)

/*

 * API.C

 * GizmoBar Version 1.01

 *

 * API functions affecting a GizmoBar and a message processing

 * function to handle the equivalent called through messages.

 *

 * Copyright (c)1993-1994 Microsoft Corporation, All Rights Reserved

 *

 * Kraig Brockschmidt, Software Design Engineer

 * Microsoft Systems Developer Relations

 *

 * Internet  :  kraigb@microsoft.com

 * Compuserve:  >INTERNET:kraigb@microsoft.com

 */

#include <windows.h>

#include <malloc.h>

#include "gizmoint.h"

/*

 * GBMessageHandler

 *

 * Purpose:

 *  Processes control messages that are equivalents of available

 *  control API.  The data passed with these messages is simply

 *  extracted from structures and passed as parameters to their

 *  equivalent function.

 *

 * Parameters:

 *  <Standard Message Parameters> plus

 *  pGB             PGIZMOBAR providing control-specific data.

 *

 * Return Value:

 *  LRESULT         Return value from equivalent API function.

 */

LRESULT GBMessageHandler(HWND hWnd, UINT iMsg, WPARAM wParam

    , LPARAM lParam, PGIZMOBAR pGB)

    {

    LRESULT         lRet=0L;

    LPCREATEGIZMOW   pCGW;

    LPCREATEGIZMOA   pCGA;

    LPGBMSG         pMsg;

    LPGBGETTEXTW    pGTW;

    LPGBGETTEXTA    pGTA;

    LPGBGETINT      pGI;

    LPGBSETINT      pSI;

    if (NULL==pGB)

        return 0L;

    switch (iMsg)

        {

        case GBM_HWNDASSOCIATESET:

            lRet=(LRESULT)(UINT)GBHwndAssociateSet(hWnd

                , (HWND)wParam);

            break;

        case GBM_HWNDASSOCIATEGET:

            lRet=(LRESULT)(UINT)GBHwndAssociateGet(hWnd);

            break;

        case GBM_GIZMOADDW:

            pCGW=(LPCREATEGIZMOW)lParam;

            lRet=(LRESULT)GBGizmoAddW(pCGW->hWndParent, pCGW->iType

                , pCGW->iGizmo, pCGW->uID, pCGW->dx, pCGW->dy

                , pCGW->pszText, pCGW->hBmp, pCGW->iImage, pCGW->uState);

            break;

        case GBM_GIZMOADDA:

            pCGA=(LPCREATEGIZMOA)lParam;

            lRet=(LRESULT)GBGizmoAddA(pCGA->hWndParent, pCGA->iType

                , pCGA->iGizmo, pCGA->uID, pCGA->dx, pCGA->dy

                , pCGA->pszText, pCGA->hBmp, pCGA->iImage, pCGA->uState);

            break;

        case GBM_GIZMOREMOVE:

            lRet=(LRESULT)GBGizmoRemove(hWnd, wParam);

            break;

        case GBM_GIZMOSENDMESSAGE:

            pMsg=(LPGBMSG)lParam;

            lRet=GBGizmoSendMessage(hWnd, wParam, pMsg->iMsg

                , pMsg->wParam, pMsg->lParam);

            break;

        case GBM_GIZMOSHOW:

            lRet=(LRESULT)GBGizmoShow(hWnd, wParam

                , (BOOL)LOWORD(lParam));

            break;

        case GBM_GIZMOENABLE:

            lRet=(LRESULT)GBGizmoEnable(hWnd, wParam

                , (BOOL)LOWORD(lParam));

            break;

        case GBM_GIZMOCHECK:

            lRet=(LRESULT)GBGizmoCheck(hWnd, wParam

                , (BOOL)LOWORD(lParam));

            break;

        case GBM_GIZMOFOCUSSET:

            lRet=(LRESULT)GBGizmoFocusSet(hWnd, wParam);

            break;

        case GBM_GIZMOEXIST:

            lRet=(LRESULT)GBGizmoExist(hWnd, wParam);

            break;

        case GBM_GIZMOTYPEGET:

            lRet=(LRESULT)GBGizmoTypeGet(hWnd, wParam);

            break;

        case GBM_GIZMODATASET:

            lRet=(LRESULT)GBGizmoDataSet(hWnd, wParam

                , (DWORD)lParam);

            break;

        case GBM_GIZMODATAGET:

            lRet=(LRESULT)GBGizmoDataGet(hWnd, wParam);

            break;

        case GBM_GIZMONOTIFYSET:

            lRet=(LRESULT)GBGizmoNotifySet(hWnd, wParam

                , (BOOL)LOWORD(lParam));

            break;

        case GBM_GIZMONOTIFYGET:

            lRet=(LRESULT)GBGizmoNotifyGet(hWnd, wParam);

            break;

        case GBM_GIZMOTEXTGETW:

            pGTW=(LPGBGETTEXTW)lParam;

            lRet=(LRESULT)GBGizmoTextGetW(hWnd, wParam, pGTW->psz

                , pGTW->cch);

            break;

        case GBM_GIZMOTEXTGETA:

            pGTA=(LPGBGETTEXTA)lParam;

            lRet=(LRESULT)GBGizmoTextGetA(hWnd, wParam, pGTA->psz

                , pGTA->cch);

            break;

        case GBM_GIZMOTEXTSETW:

            GBGizmoTextSetW(hWnd, wParam, (LPWSTR)lParam);

            break;

        case GBM_GIZMOTEXTSETA:

            GBGizmoTextSetA(hWnd, wParam, (LPSTR)lParam);

            break;

        case GBM_GIZMOINTGET:

            pGI=(LPGBGETINT)lParam;

            lRet=(LRESULT)GBGizmoIntGet(hWnd, wParam, &pGI->fSuccess

                , pGI->fSigned);

            break;

        case GBM_GIZMOINTSET:

            pSI=(LPGBSETINT)lParam;

            GBGizmoIntSet(hWnd, wParam, pSI->uValue, pSI->fSigned);

            break;

        default:

            break;

        }

    return lRet;

    }

/*

 * PGizmoFromHwndID

 *

 * Purpose:

 *  Retrieves the pGizmo for the given GizmoBar and the gizmo ID.

 *

 * Parameters:

 *  hWnd            HWND of a GizmoBar.

 *  uID             UINT gizmo identifier.

 *

 * Return Value:

 *  PGIZMO          NULL if the gizmo does not exist or hWnd is

 *                  invalid.  Non-NULL PGIZMO otherwise.

 */

PGIZMO PGizmoFromHwndID(HWND hWnd, UINT uID)

    {

    PGIZMOBAR     pGB;

    if (!IsWindow(hWnd))

        return FALSE;

    pGB=(PGIZMOBAR)GetWindowLong(hWnd, GBWL_STRUCTURE);

    if (NULL==pGB)

        return FALSE;

    return GizmoPFind(&pGB->pGizmos, uID);

    }

/*

 * GBHwndAssociateSet

 *

 * Purpose:

 *  Changes the associate window of a GizmoBar.

 *

 * Parameters:

 *  hWnd            HWND of the control window.

 *

 * Set Parameters:

 *  hWndAssociate   HWND of new associate.

 *

 * Return Value:

 *  HWND            Handle of previous associate.

 */

HWND WINAPI GBHwndAssociateSet(HWND hWnd, HWND hWndNew)

    {

    HWND        hWndOld=NULL;

    PGIZMOBAR   pGB;

    pGB=(PGIZMOBAR)GetWindowLong(hWnd, GBWL_STRUCTURE);

    if (NULL!=pGB)

        {

        hWndOld=pGB->hWndAssociate;

        pGB->hWndAssociate=hWndNew;

        if (NULL!=hWndOld)

            SendCommand(hWndOld, pGB->uID, GBN_ASSOCIATELOSS, hWnd);

        if (NULL!=hWndNew)

            SendCommand(hWndNew, pGB->uID, GBN_ASSOCIATEGAIN, hWnd);

        }

    return hWndOld;

    }

/*

 * GBHwndAssociateGet

 *

 * Purpose:

 *  Retrieves the associate window of a GizmoBar

 *

 * Parameters:

 *  hWnd            HWND of the control window.

 *

 * Set Parameters:

 *  hWndAssociate   HWND of new associate.

 *

 * Return Value:

 *  HWND            Handle of current associate.

 */

HWND WINAPI GBHwndAssociateGet(HWND hWnd)

    {

    HWND        hWndOld=NULL;

    PGIZMOBAR   pGB;

    pGB=(PGIZMOBAR)GetWindowLong(hWnd, GBWL_STRUCTURE);

    if (NULL!=pGB)

        hWndOld=pGB->hWndAssociate;

    return hWndOld;

    }

/*

 * GBGizmoAdd

 *

 * Purpose:

 *  Creates a new gizmo on the GizmoBar.  Subsequent operations

 *  should be done using the identifier, uID, for this gizmo.

 *

 * Parameters:

 *  hWnd            HWND of the GizmoBar.

 *  iType           UINT type of the gizmo to create.

 *  iGizmo          UINT position (zero-based) at which to place the

 *                  gizmo.

 *  uID             UINT identifier for WM_COMMAND from this gizmo.

 *  dx, dy          UINT dimensions of the gizmo.

 *  pszText         LPTSTR initial text for edit, list, combo, and

 *                  text gizmos.

 *  hBitmap         HBITMAP for gizmos of the button types (COMMAND

 *                  or ATTRIBUTE) specifies a source bitmap from

 *                  which the button image is taken.

 *  iImage          UINT index into hBitmap for the image for this

 *                  button.

 *  uState          UINT initial state of the gizmo.

 *

 * Return Value:

 *  BOOL            TRUE if creation succeeded, FALSE otherwise.

 */

BOOL WINAPI GBGizmoAddW(HWND hWnd, UINT iType, UINT iGizmo, UINT uID

    , UINT dx, UINT dy, LPWSTR pszText, HBITMAP hBmp, UINT iImage

    , UINT uState)

    {

    BOOL        fSuccess;

    PGIZMOBAR   pGB;

    PGIZMO      pGizmo;

    if (!IsWindow(hWnd))

        return FALSE;

    pGB=(PGIZMOBAR)GetWindowLong(hWnd, GBWL_STRUCTURE);

    if (NULL==pGB)

        return FALSE;

    /*

     * This automatically creates the windows, allocates structures,

     * includes the gizmo in pGB->pGizmos, and so forth.

     */

    pGizmo=GizmoPAllocate(&fSuccess, &pGB->pGizmos, hWnd, iType

        , iGizmo, uID, dx, dy, pszText, hBmp, iImage, uState);

    if (fSuccess)

        {

        if (NULL!=pGB->hWndAssociate)

            {

            SendCommand(pGB->hWndAssociate,GBN_GIZMOADDED, pGB->uID

                , hWnd);

            }

        InvalidateRect(hWnd, NULL, TRUE);

        UpdateWindow(hWnd);

        }

    else

        GizmoPFree(&pGB->pGizmos, pGizmo);

    return fSuccess;

    }

BOOL WINAPI GBGizmoAddA(HWND hWnd, UINT iType, UINT iGizmo, UINT uID

    , UINT dx, UINT dy, LPSTR pszText, HBITMAP hBmp, UINT iImage

    , UINT uState)

{

    LPWSTR  pszTemp;

    BOOL    retVal;

    if(pszText != NULL)

    {

        pszTemp = malloc((1+strlen(pszText))*sizeof(WCHAR));

        if (pszTemp)

        {

            MultiByteToWideChar(CP_ACP, 0, pszText, -1, pszTemp, strlen(pszText)+1);

            retVal=GBGizmoAddW(hWnd, iType, iGizmo, uID, dx, dy, pszTemp, hBmp, iImage, uState);

            free(pszTemp);

            return retVal;

        }

    }

    else

        return GBGizmoAddW(hWnd, iType, iGizmo, uID, dx, dy, NULL, hBmp, iImage, uState);

}

/*

 * GBGizmoRemove

 *

 * Purpose:

 *  Removes an existing gizmo from the GizmoBar.

 *

 * Parameters:

 *  hWnd            HWND of the GizmoBar.

 *  uID             UINT identifier for this gizmo.

 *

 * Return Value:

 *  BOOL            TRUE if deletion succeeded, FALSE otherwise.

 */

BOOL WINAPI GBGizmoRemove(HWND hWnd, UINT uID)

    {

    PGIZMOBAR   pGB;

    PGIZMO      pGizmo;

    if (!IsWindow(hWnd))

        return FALSE;

    pGB=(PGIZMOBAR)GetWindowLong(hWnd, GBWL_STRUCTURE);

    if (NULL==pGB)

        return FALSE;

    pGizmo=GizmoPFind(&pGB->pGizmos, uID);

    if (NULL==pGizmo)

        return FALSE;

    GizmoPFree(&pGB->pGizmos, pGizmo);

    if (NULL!=pGB->hWndAssociate)

        {

        SendCommand(pGB->hWndAssociate, GBN_GIZMOREMOVED, pGB->uID

            , hWnd);

        }

    InvalidateRect(hWnd, NULL, TRUE);

    UpdateWindow(hWnd);

    return TRUE;

    }

/*

 * GBGizmoSendMessage

 *

 * Purpose:

 *  Implements the equivalent of SendMessage to a gizmo in the

 *  GizmoBar.  Separators, command buttons, and attribute buttons

 *  do not accept messages.

 *

 * Parameters:

 *  hWnd            HWND of the GizmoBar.

 *  uID             UINT identifier of the gizmo to affect.

 *  iMsg            UINT message to send.

 *  wParam          WPARAM of the message.

 *  lParam          LPARAM of the message.

 *

 * Return Value:

 *  LRESULT         Return value from the message.  0L if the

 *                  gizmo does not accept messages.

 */

LRESULT WINAPI GBGizmoSendMessage(HWND hWnd, UINT uID, UINT iMsg

    , WPARAM wParam, LPARAM lParam)

    {

    PGIZMO      pGizmo;

    LONG        lRet=0L;

    pGizmo=PGizmoFromHwndID(hWnd, uID);

    if (NULL!=pGizmo && NULL!=pGizmo->hWnd)

        lRet=SendMessage(pGizmo->hWnd, iMsg, wParam, lParam);

    return lRet;

    }

/*

 * GBGizmoShow

 *

 * Purpose:

 *  Shows or hides a control, adjusting the positions of all others

 *  to make room for or reuse the space for this control.

 *

 * Parameters:

 *  hWnd            HWND of the GizmoBar.

 *  uID             UINT identifier of the gizmo to affect.

 *  fShow           BOOL TRUE to show the gizmo, FALSE to hide it.

 *

 * Return Value:

 *  BOOL            TRUE if the function was successful, FALSE

 *                  otherwise.

 */

BOOL WINAPI GBGizmoShow(HWND hWnd, UINT uID, BOOL fShow)

    {

    BOOL        fRet=FALSE;

    PGIZMO      pGizmo;

    pGizmo=PGizmoFromHwndID(hWnd, uID);

    if (NULL!=pGizmo)

        {

        if (fShow && pGizmo->fHidden)

            {

            if (NULL!=pGizmo->hWnd)

                ShowWindow(pGizmo->hWnd, SW_SHOWNORMAL);

            GizmosExpand(pGizmo);

            }

        if (!fShow && !pGizmo->fHidden)

            {

            if (NULL!=pGizmo->hWnd)

                ShowWindow(pGizmo->hWnd, SW_HIDE);

            GizmosCompact(pGizmo);

            }

        //This will be right even if we didn't change anything.

        pGizmo->fHidden=!fShow;

        }

    InvalidateRect(hWnd, NULL, TRUE);

    UpdateWindow(hWnd);

    return fRet;

    }

/*

 * GBGizmoEnable

 *

 * Purpose:

 *  Enables or disables a control on the GizmoBar.

 *

 * Parameters:

 *  hWnd            HWND of the GizmoBar.

 *  uID             UINT identifier of the gizmo to affect.

 *  fEnable         BOOL TRUE to enable the gizmo, FALSE otherwise.

 *

 * Return Value:

 *  BOOL            TRUE if the gizmo was previously disabled, FALSE

 *                  otherwise.

 */

BOOL WINAPI GBGizmoEnable(HWND hWnd, UINT uID, BOOL fEnable)

    {

    PGIZMO      pGizmo;

    BOOL        fRet=FALSE;

    pGizmo=PGizmoFromHwndID(hWnd, uID);

    if (NULL==pGizmo)

        return FALSE;

    fRet=(BOOL)(BUTTONGROUP_DISABLED & pGizmo->uState);

    //Use windows to enable or disable window gizmos

    if (NULL!=pGizmo->hWnd)

        EnableWindow(pGizmo->hWnd, fEnable);

    else

        {

        /*

         * If we're not down, command and attribute buttons act

         * the same.

         */

        if (!(BUTTONGROUP_DOWN & pGizmo->uState))

            {

            GizmoPStateSet(hWnd, pGizmo, fEnable

                ? COMMANDBUTTON_UP : COMMANDBUTTON_DISABLED);

            }

        else

            {

            /*

             * Attribute buttons are a little more sensitive with

             * DOWNDISABLED

             */

            GizmoPStateSet(hWnd, pGizmo, fEnable

                ? ATTRIBUTEBUTTON_DOWN

                : ATTRIBUTEBUTTON_DOWNDISABLED);

            }

        }

    return fRet;

    }

/*

 * GBGizmoCheck

 *

 * Purpose:

 *  Checks or unchecks an attribute button in the GizmoBar.  If the

 *  gizmo is part of a group of mutually exclusive attributes, then

 *  other gizmos are unchecked when this one is checked.  If this is

 *  the only one checked in these circumstances, this function is a

 *  NOP.

 *

 * Parameters:

 *  hWnd            HWND of the GizmoBar.

 *  uID             UINT identifier of the gizmo to affect.

 *  fCheck          BOOL TRUE to check this gizmo, FALSE to uncheck.

 *

 * Return Value:

 *  BOOL            TRUE if the change took place.  FALSE otherwise.

 */

BOOL WINAPI GBGizmoCheck(HWND hWnd, UINT uID, BOOL fCheck)

    {

    PGIZMOBAR   pGB;

    PGIZMO      pGizmo;

    if (!IsWindow(hWnd))

        return FALSE;

    pGB=(PGIZMOBAR)GetWindowLong(hWnd, GBWL_STRUCTURE);

    if (NULL==pGB)

        return FALSE;

    pGizmo=GizmoPFind(&pGB->pGizmos, uID);

    if (NULL!=pGizmo)

        GizmoPCheck(hWnd, pGizmo, fCheck);

    return TRUE;

    }

/*

 * GBGizmoFocusSet

 *

 * Purpose:

 *  Sets the focus to a partuclar gizmo in the gizmo if that gizmo

 *  can accept the focus.  Separators, attribute buttons, text,

 *  and command buttons cannot have the focus.

 *

 * Parameters:

 *  hWnd            HWND of the GizmoBar.

 *  uID             UINT identifier of the gizmo to affect.

 *

 * Return Value:

 *  BOOL            TRUE if the focus was set.  FALSE otherwise,

 *                  such as when uID identifies a control that cannot

 *                  have focus.

 */

UINT WINAPI GBGizmoFocusSet(HWND hWnd, UINT uID)

    {

    PGIZMO      pGizmo;

    BOOL        fRet=FALSE;

    pGizmo=PGizmoFromHwndID(hWnd, uID);

    if (NULL!=pGizmo && NULL!=pGizmo->hWnd)

        {

        fRet=TRUE;

        SetFocus(pGizmo->hWnd);

        }

    return fRet;

    }

/*

 * GBGizmoExist

 *

 * Purpose:

 *  Determines if a gizmo of a given identifier exists in the

 *  GizmoBar.

 *

 * Parameters:

 *  hWnd            HWND of the GizmoBar.

 *  uID             UINT identifier to verify.

 *

 * Return Value:

 *  BOOL            TRUE if the gizmo exists, FALSE otherwise.

 */

BOOL WINAPI GBGizmoExist(HWND hWnd, UINT uID)

    {

    return (NULL!=PGizmoFromHwndID(hWnd, uID));

    }

/*

 * GBGizmoTypeGet

 *

 * Purpose:

 *  Returns the type of the gizmo specified by the given identifer.

 *

 * Parameters:

 *  hWnd            HWND of the GizmoBar.

 *  uID             UINT identifier to find.

 *

 * Return Value:

 *  int             A GIZMOTYPE_* value if the function is

 *                  successful, otherwise -1.

 */

int WINAPI GBGizmoTypeGet(HWND hWnd, UINT uID)

    {

    int         iRet=-1;

    PGIZMO      pGizmo;

    pGizmo=PGizmoFromHwndID(hWnd, uID);

    if (NULL!=pGizmo)

        iRet=pGizmo->iType;

    return iRet;

    }

/*

 * GBGizmoDataSet

 * GBGizmoDataGet

 *

 * Purpose:

 *  Sets or retrieves an extra DWORD value associated with the given

 *  gizmo.  Applications can store any information here they please.

 *

 * Parameters:

 *  hWnd            HWND of the GizmoBar.

 *  uID             UINT identifier of the gizmo.

 *  dwData          (Set only) DWORD data to store with the gizmo.

 *

 * Return Value:

 *  DWORD           Set:  Previous value

 *                  Get:  Current value

 */

DWORD WINAPI GBGizmoDataSet(HWND hWnd, UINT uID, DWORD dwData)

    {

    PGIZMO      pGizmo;

    DWORD       dw=0L;

    pGizmo=PGizmoFromHwndID(hWnd, uID);

    if (NULL!=pGizmo)

        {

        dw=pGizmo->dwData;

        pGizmo->dwData=dwData;

        }

    return dw;

    }

DWORD WINAPI GBGizmoDataGet(HWND hWnd, UINT uID)

    {

    PGIZMO      pGizmo;

    DWORD       dw=0L;

    pGizmo=PGizmoFromHwndID(hWnd, uID);

    if (NULL!=pGizmo)

        dw=pGizmo->dwData;

    return dw;

    }

/*

 * GBGizmoNotifySet

 * GBGizmoNotifyGet

 *

 * Purpose:

 *  Sets or retrieves the notify status of a gizmo.  If notify is

 *  FALSE, the no WM_COMMAND messages are sent from the GizmoBar to

 *  the parent window when this gizmo is used.

 *

 * Parameters:

 *  hWnd            HWND of the GizmoBar.

 *  uID             UINT identifier of the gizmo.

 *  fNotify         (Set only) BOOL new notify status to set.

 *

 * Return Value:

 *  BOOL            Set:  Previous value of the notify flag.

 *                  Get:  Current value of the notify flag.

 */

BOOL WINAPI GBGizmoNotifySet(HWND hWnd, UINT uID, BOOL fNotify)

    {

    PGIZMO      pGizmo;

    BOOL        fRet=FALSE;

    pGizmo=PGizmoFromHwndID(hWnd, uID);

    if (NULL!=pGizmo)

        {

        fRet=pGizmo->fNotify;

        pGizmo->fNotify=fNotify;

        }

    return fRet;

    }

BOOL WINAPI GBGizmoNotifyGet(HWND hWnd, UINT uID)

    {

    PGIZMO      pGizmo;

    BOOL        fRet=FALSE;

    pGizmo=PGizmoFromHwndID(hWnd, uID);

    if (NULL!=pGizmo)

        fRet=pGizmo->fNotify;

    return fRet;

    }

/*

 * GBGizmoTextSet

 * GBGizmoTextGet

 *

 * Purpose:

 *  Retrieves or sets text in a GizmoBar gizmo.  Separators, command

 *  buttons, and attribute buttons are not affected by this call.

 *

 * Parameters:

 *  hWnd            HWND of the GizmoBar.

 *  uID             UINT identifying the gizmo.

 *  psz             LPTSTR (Set) providing the text to show in the

 *                  window or (Get) pointing to a buffer to receive

 *                  the text.

 *  cch             (Get only) UINT maximum number of chars to copy

 *                  to psz.

 *

 * Return Value:

 *  int             Number of characters copied to psz.

 */

void WINAPI GBGizmoTextSetW(HWND hWnd, UINT uID, LPWSTR psz)

    {

    //This fails on non-windowed gizmos anyway, so we don't check.

    SetDlgItemTextW(hWnd, uID, psz);

    return;

    }

void WINAPI GBGizmoTextSetA(HWND hWnd, UINT uID, LPSTR psz)

    {

    //This fails on non-windowed gizmos anyway, so we don't check.

    SetDlgItemTextA(hWnd, uID, psz);

    return;

    }

int WINAPI GBGizmoTextGetW(HWND hWnd, UINT uID, LPWSTR psz, UINT cch)

    {

    //This fails on non-windowed gizmos anyway, so we don't check.

    return GetDlgItemTextW(hWnd, uID, psz, cch);

    }

int WINAPI GBGizmoTextGetA(HWND hWnd, UINT uID, LPSTR psz, UINT cch)

    {

    //This fails on non-windowed gizmos anyway, so we don't check.

    return GetDlgItemTextA(hWnd, uID, psz, cch);

    }

/*

 * GBGizmoIntSet

 * GBGizmoIntGet

 *

 * Purpose:

 *  Retrieves or sets an integer in a GizmoBar gizmo.  Separators,

 *  command buttons, and attribute buttons are not affected by this

 *  call.

 *

 * Parameters:

 *  hWnd            HWND of the GizmoBar.

 *  uID             UINT identifying the gizmo.

 *

 *  (Set only)

 *  u               UINT value to set in the gizmo.

 *  fSigned         BOOL TRUE to indicate if the value is signed.

 *

 *  (Get only)

 *  pfTrans         BOOL FAR * in which the success of the function

 *                  is returned.

 *  fSigned         BOOL TRUE to indicate if the value is signed.

 *

 * Return Value:

 *  (Set): None

 *  (Get): UINT     Integer translation of the gizmo's text.

 */

void WINAPI GBGizmoIntSet(HWND hWnd, UINT uID, UINT u, BOOL fSigned)

    {

    //This fails on non-windowed gizmos anyway, so we don't check.

    SetDlgItemInt(hWnd, uID, u, fSigned);

    return;

    }

UINT WINAPI GBGizmoIntGet(HWND hWnd, UINT uID, BOOL FAR *pfTrans

    , BOOL fSigned)

    {

    //This fails on non-windowed gizmos anyway, so we don't check.

    return GetDlgItemInt(hWnd, uID, pfTrans, fSigned);

    }


GIZMO.H  (GIZMOBAR Sample)

/*

 * GIZMO.H

 * GizmoBar Version 1.01

 *

 * Data structure and type definitions for the GIZMO data structure.

 * Each gizmo on a gizmobar has one of these structures associated

 * with it.

 *

 * Copyright (c)1993-1994 Microsoft Corporation, All Rights Reserved

 *

 * Kraig Brockschmidt, Software Design Engineer

 * Microsoft Systems Developer Relations

 *

 * Internet  :  kraigb@microsoft.com

 * Compuserve:  >INTERNET:kraigb@microsoft.com

 */

#ifndef _GIZMO_H_

#define _GIZMO_H_

#ifdef __cplusplus

extern "C"

    {

#endif

typedef struct tagGIZMO

    {

    struct tagGIZMO     *pPrev;

    struct tagGIZMO     *pNext;

    UINT                 iType;

    HWND                 hWnd;       //Texts, edits, lists, combos

    UINT                 uID;

    UINT                 x, y;

    UINT                 dx, dy;

    UINT                 cxImage;    //From UIToolConfigureForDisplay

    UINT                 cyImage;

    HBITMAP              hBmp;       //Buttons only.

    UINT                 iBmp;

    BOOL                 fNotify;    //Send WM_COMMANDs?

    BOOL                 fHidden;    //Independent of state

    BOOL                 fDisabled;

    UINT                 uState;

    UINT                 uStateOrg;

    DWORD                dwData;     //Application-supplied data.

    } GIZMO, * PGIZMO;

typedef PGIZMO *PPGIZMO;

#define CBGIZMO sizeof(GIZMO)

//Property name we attach to controls in a gizmo to identify type

#define SZTYPEPROP      TEXT("iType")

//Number of controls we subclass

#define CSUBGIZMOS       4

//ID of edit controls in comboboxes

#define ID_COMBOEDIT     1001

/*

 * Conversion of iType (a positioned bit) into its position.

 * The BITPOSITION macro does not need to be fast because we only

 * use it once when creating a gizmo.  POSITIONBIT does, however,

 * since we use it in subclass procedures.

 */

#define BITPOSITION(i, j)  {int k=i; for (j=0; k>>=1; j++);}

#define POSITIONBIT(i)     (1 << i)

//Control classifications.  GIZMOBAR.H must be included first.

#define GIZMOTYPE_WINDOWS   (GIZMOTYPE_TEXT | GIZMOTYPE_EDIT \

                            | GIZMOTYPE_LISTBOX              \

                            | GIZMOTYPE_COMBOBOX             \

                            | GIZMOTYPE_BUTTONNORMAL)

#define GIZMOTYPE_BUTTONS   (GIZMOTYPE_BUTTONATTRIBUTEIN     \

                            | GIZMOTYPE_BUTTONATTRIBUTEEX    \

                            | GIZMOTYPE_BUTTONCOMMAND        \

                            | GIZMOTYPE_BUTTONNORMAL)

#define GIZMOTYPE_DRAWN     (GIZMOTYPE_BUTTONATTRIBUTEIN     \

                            | GIZMOTYPE_BUTTONATTRIBUTEEX    \

                            | GIZMOTYPE_BUTTONCOMMAND)

//These must stay in sync with GIZMOBAR.H

#define GIZMOTYPE_MIN               GIZMOTYPE_EDIT

#define GIZMOTYPE_MAX               GIZMOTYPE_BUTTONCOMMAND

//Enumeration callback

typedef BOOL (CALLBACK *PFNGIZMOENUM)(PGIZMO, UINT, DWORD);

//GIZMO.C

PGIZMO   GizmoPAllocate(int *, PPGIZMO, HWND, UINT, UINT, UINT

             , UINT, UINT, LPTSTR, HBITMAP, UINT, UINT);

void     GizmosExpand(PGIZMO);

PGIZMO   GizmoPFree(PPGIZMO, PGIZMO);

void     GizmosCompact(PGIZMO);

PGIZMO   GizmoPFind(PPGIZMO, UINT);

PGIZMO   GizmoPEnum(PPGIZMO, PFNGIZMOENUM, DWORD);

UINT     GizmoPStateSet(HWND, PGIZMO, UINT);

BOOL     GizmoPCheck(HWND, PGIZMO, BOOL);

LRESULT APIENTRY GenericSubProc(HWND, UINT, WPARAM, LPARAM);

#ifdef __cplusplus

    }

#endif

#endif //_GIZMO_H_


GIZMO.C  (GIZMOBAR Sample)

/*

 * GIZMO.C

 * GizmoBar Version 1.01

 *

 * Allocate, free, find, and enumerate functions for the GIZMO

 * structure and a generic subclass procedure to handle tabbing

 * between gizmos.

 *

 * Copyright (c)1993-1994 Microsoft Corporation, All Rights Reserved

 *

 * Kraig Brockschmidt, Software Design Engineer

 * Microsoft Systems Developer Relations

 *

 * Internet  :  kraigb@microsoft.com

 * Compuserve:  >INTERNET:kraigb@microsoft.com

 */

#include <windows.h>

#include "gizmoint.h"

/*

 * In order to control tabbing in the gizmos, we need to subclass

 * real pushbuttons, edit controls, listboxes, and comboboxes.  So

 * we keep an array of the four original procs for such controls.

 */

WNDPROC     pfnOrg[CSUBGIZMOS]={NULL, NULL, NULL, NULL};

TCHAR szStatic[]=TEXT("static");

TCHAR szEdit[]=TEXT("edit");

TCHAR szCombobox[]=TEXT("combobox");

TCHAR szListbox[]=TEXT("listbox");

TCHAR szButton[]=TEXT("button");

//Here so PAINT.C can get at it.

TOOLDISPLAYDATA tdd;

/*

 * GizmoPAllocate

 *

 * Purpose:

 *  Allocates and initializes a GIZMO data structure.

 *

 * Parameters:

 *  pfSuccess       int * flag indicating success of failure.

 *  ppFirst         PPGIZMO providing the first gizmo in this list.

 *  hWndParent      HWND of the parent of this gizmo.  Can be NULL

 *                  for iType==GIZMOTYPE_BUTTON* or

 *                  GIZMOTYPE_SEPARATOR.

 *  iType           UINT gizmo control type.

 *  iGizmo          UINT index of this gizmo in the GizmoBar.

 *  uID             UINT identifier to send with WM_COMMAND for this

 *                  control.

 *  dx, dy          UINT width and height of the gizmo.

 *  pszText         LPTSTR to the text for edits, listboxes, combobox,

 *                  and text.

 *  dwStyle         DWORD style for edits, lists, and combos, and

 *                  texts.

 *  hBmp            HBITMAP for button gizmos, is applicable.

 *  iImage          UINT index into hBmp for the button image, if

 *                  applicable.

 *  uState          UINT initial state of the control.

 *

 * Return Value:

 *  PGIZMO          If NULL returned then GizmoPAllocate could not

 *                  allocate memory.  If a non-NULL pointer is

 *                  returned with *pfSuccess, then call GizmoPFree

 *                  immediately.  If you get a non-NULL pointer and

 *                  *pfSuccess==TRUE then the function succeeded.

 */

PGIZMO GizmoPAllocate(int *pfSuccess, PPGIZMO ppFirst

    , HWND hWndParent, UINT iType, UINT iGizmo, UINT uID, UINT dx

    , UINT dy, LPWSTR pszText, HBITMAP hBmp, UINT iImage, UINT uState)

    {

    PGIZMO          pGizmo;

    PGIZMO          pCur, pPrev;

    LPTSTR          pszClass;

    HINSTANCE       hInst;

    UINT            i;

    DWORD           dwStyle;

    HWND            hWndE;

    if (NULL==pfSuccess)

        return NULL;

    //Make sure we know of this gizmo type.

    if (GIZMOTYPE_MIN > iType || GIZMOTYPE_MAX < iType)

        return NULL;

    *pfSuccess=FALSE;

    //Allocate the structure

    pGizmo=(PGIZMO)(TCHAR *)LocalAlloc(LPTR, CBGIZMO);

    if (NULL==pGizmo)

        return NULL;

    //Store the necessary information for this gizmo.

    pGizmo->iType   =iType;

    pGizmo->uID     =uID;

    pGizmo->hBmp    =hBmp;

    pGizmo->iBmp    =iImage;

    pGizmo->uState  =uState;

    pGizmo->fNotify =TRUE;

    /*

     * Insert this structure into our gizmo list.  Each time we scan

     * we increment the index counter (starting at zero) comparing it

     * to the desired index of insertion.  We then know exactly where

     * to insert this new gizmo.  Note that we insert the new gizmo

     * in the list appropriately for the given owner, so enumerations

     * will come out ordered in the same way for that owner.

     */

    i=0;

    pCur=*ppFirst;

    pPrev=NULL;

    while (NULL!=pCur && i++ < iGizmo)

        {

        pPrev=pCur;

        pCur =pCur->pNext;

        }

    //Point to our neighbors

    pGizmo->pPrev=pPrev;

    pGizmo->pNext=pCur;

    //Point out neighbors to us.

    if (NULL==pPrev)

        *ppFirst=pGizmo;

    else

        pPrev->pNext=pGizmo;

    if (NULL!=pCur)

        pCur->pPrev=pGizmo;

    //Our x-coordinate is the x of the previous gizmo plus its width.

    if (NULL!=pPrev)

        pGizmo->x=pGizmo->pPrev->x+pGizmo->pPrev->dx;

    else

        pGizmo->x=4;    //First gizmo is at x=4

    //If we're a separator or image button, force standards on dx.

    UIToolConfigureForDisplay(&tdd);

    pGizmo->cxImage=tdd.cxImage;

    pGizmo->cyImage=tdd.cyImage;

    if ((GIZMOTYPE_DRAWN & iType) && NULL==hBmp)

        dx=tdd.cxButton;

    if (GIZMOTYPE_SEPARATOR==iType)

        dx=6;

    /*

     * Now create windows for edits, texts, lists, and comboboxes.

     * First calculate the most often defaults used in the switch.

     */

    pGizmo->dx=dx+6;

    pGizmo->dy=min(dy, tdd.cyButton);

    pGizmo->y=2;

    pszClass=NULL;

    //If this is new gizmo is a window, create it.

    switch (iType)

            {

            case GIZMOTYPE_TEXT:

                pGizmo->dx=dx;

                //Center vertically.

                pGizmo->y=(tdd.cyBar-1-pGizmo->dy) >> 1;

                pszClass=szStatic;

                dwStyle=SS_LEFT;

                break;

            case GIZMOTYPE_EDIT:

                //Center vertically.

                pGizmo->y=(tdd.cyBar-1-pGizmo->dy) >> 1;

                pszClass=szEdit;

                dwStyle=ES_LEFT | WS_BORDER | WS_TABSTOP;

                break;

            case GIZMOTYPE_LISTBOX:

                pGizmo->dy=dy;

                pszClass=szCombobox;

                dwStyle=CBS_DROPDOWNLIST | WS_TABSTOP;

                break;

            case GIZMOTYPE_COMBOBOX:

                pGizmo->dy=dy;

                pszClass=szCombobox;

                dwStyle=CBS_DROPDOWN | WS_TABSTOP;

                break;

            case GIZMOTYPE_BUTTONNORMAL:

                pGizmo->dy=dy;

                pszClass=szButton;

                dwStyle=BS_PUSHBUTTON | WS_TABSTOP;

                break;

            case GIZMOTYPE_SEPARATOR:

                pGizmo->dx=dx;

                pGizmo->y=3;

                break;

            case GIZMOTYPE_BUTTONATTRIBUTEIN:

            case GIZMOTYPE_BUTTONATTRIBUTEEX:

            case GIZMOTYPE_BUTTONCOMMAND:

                pGizmo->dx=dx;

                pGizmo->y=3;

                break;

            }

    //If we matched a classname, create a window.

    if (GIZMOTYPE_WINDOWS & iType)

        {

        if (!IsWindow(hWndParent))

            return pGizmo;

        hInst=GETWINDOWINSTANCE(hWndParent);    //Macro in book1632.h

        pGizmo->hWnd=CreateWindowW(pszClass, pszText

            , dwStyle | WS_CHILD | WS_VISIBLE, pGizmo->x, pGizmo->y

            , dx, pGizmo->dy, hWndParent, (HMENU)uID, hInst, NULL);

        if (NULL==pGizmo->hWnd)

            return pGizmo;

        /*

         * Subclass comboboxes, listboxes, edits, and windowed

         * buttons.  We use iType to index the original proc array

         * so we can use a single subclass procedure for all

         * controls.  If you mess with the gizmo type definitions,

         * this is going to break.

         */

        if (GIZMOTYPE_WINDOWS & iType && GIZMOTYPE_TEXT!=iType)

            {

            //Give the window its type.

            BITPOSITION(iType, i);

            SetProp(pGizmo->hWnd, SZTYPEPROP, (HANDLE)i);

            if (NULL==pfnOrg[i])

                {

                pfnOrg[i]=(WNDPROC)GetWindowLong(pGizmo->hWnd

                    , GWL_WNDPROC);

                }

            SetWindowLong(pGizmo->hWnd, GWL_WNDPROC

                , (LONG)GenericSubProc);

            //If we're a combobox, subclass edit control

            if (GIZMOTYPE_COMBOBOX==iType)

                {

                hWndE=GetDlgItem(pGizmo->hWnd, ID_COMBOEDIT);

                SetProp(hWndE, SZTYPEPROP, (HANDLE)-1);

                if (NULL==pfnOrg[0])

                    {

                    pfnOrg[0]=(WNDPROC)GetWindowLong(pGizmo->hWnd

                        , GWL_WNDPROC);

                    }

                SetWindowLong(hWndE, GWL_WNDPROC

                    , (LONG)GenericSubProc);

                }

            }

        }

    //Finally, move all our neighbors to the right to accomodate us.

    GizmosExpand(pGizmo);

    *pfSuccess=TRUE;

    return pGizmo;

    }

/*

 * GizmoPFree

 *

 * Purpose:

 *  Reverses all initialization done by GizmoPAllocate, cleaning up

 *  any allocations including the application structure itself.

 *

 * Parameters:

 *  ppFirst         PPGIZMO providing the first gizmo in this list.

 *  pGizmo          PGIZMO to the structure

 *

 * Return Value:

 *  PGIZMO          NULL if successful, pGizmo if not, meaning we

 *                  couldn't free something.

 */

PGIZMO GizmoPFree(PPGIZMO ppFirst, PGIZMO pGizmo)

    {

    int     i;

    if (NULL==pGizmo)

        return NULL;

    //Move other gizmos to fill in this gap.

    GizmosCompact(pGizmo);

    //Unsubclass

    if (GIZMOTYPE_WINDOWS & pGizmo->iType

        && GIZMOTYPE_TEXT!=pGizmo->iType)

        {

        i=(int)GetProp(pGizmo->hWnd, SZTYPEPROP);

        RemoveProp(pGizmo->hWnd, SZTYPEPROP);

        if (GIZMOTYPE_COMBOBOX==pGizmo->iType)

            {

            HWND        hWndE;

            hWndE=GetDlgItem(pGizmo->hWnd, ID_COMBOEDIT);

            RemoveProp(hWndE, SZTYPEPROP);

            }

        SetWindowLong(pGizmo->hWnd, GWL_WNDPROC, (LONG)pfnOrg[i]);

        }

    //If this was a window gizmo, destroy the window.

    if (NULL!=pGizmo->hWnd && IsWindow(pGizmo->hWnd))

        DestroyWindow(pGizmo->hWnd);

    //Unlink ourselves.

    if (NULL!=pGizmo->pNext)

        pGizmo->pNext->pPrev=pGizmo->pPrev;

    if (NULL!=pGizmo->pPrev)

        pGizmo->pPrev->pNext=pGizmo->pNext;

    else

        *ppFirst=pGizmo->pNext;

    return (PGIZMO)LocalFree((HLOCAL)(UINT)(LONG)pGizmo);

    }

/*

 * GizmosExpand

 *

 * Purpose:

 *  Given a starting gizmo and a width, moves it and all gizmos to

 *  its right to the right by the width to make space for showing

 *  or creating a new gizmo.

 *

 * Parameters:

 *  pGizmo          PGIZMO specifying the gizmo that was inserted.

 *

 * Return Value:

 *  None

 */

void GizmosExpand(PGIZMO pGizmo)

    {

    int         cx;

    cx=(int)pGizmo->dx;

    /*

     * If we and the next control are buttons, use our width-1 to

     * expand so we overlap borders with our neighboring button.

     */

    if (NULL!=pGizmo->pNext)

        {

        if ((GIZMOTYPE_BUTTONS & pGizmo->pNext->iType)

            && (GIZMOTYPE_BUTTONS & pGizmo->iType))

            cx-=1;

        }

    //Walk the gizmo list moving them right by our width.

    pGizmo=pGizmo->pNext;

    while (NULL!=pGizmo)

        {

        pGizmo->x+=cx;

        //hWnd is NULL for buttons and separators.

        if (NULL!=pGizmo->hWnd)

            {

            SetWindowPos(pGizmo->hWnd, NULL, pGizmo->x, pGizmo->y

                , 0, 0, SWP_NOZORDER | SWP_NOSIZE);

            }

        pGizmo=pGizmo->pNext;

        }

    return;

    }

/*

 * GizmosCompact

 *

 * Purpose:

 *  Given a gizmo, moves all other gizmos to the right of it to the

 *  left by its width on the GizmoBar.  Used when removing or hiding

 *  the gizmo.

 *

 * Parameters:

 *  pGizmo          PGIZMO that is going away, visibly or physically.

 *

 * Return Value:

 *  None

 */

void GizmosCompact(PGIZMO pGizmo)

    {

    UINT        cx;

    PGIZMO      pCur;

    //Move all the gizmos beyond us back by our width.

    if (NULL!=pGizmo->pNext)

        {

        cx=pGizmo->pNext->x - pGizmo->x;

        pCur=pGizmo->pNext;

        while (NULL!=pCur)

            {

            pCur->x-=cx;

            if (NULL!=pCur->hWnd)

                {

                SetWindowPos(pCur->hWnd, NULL, pCur->x, pCur->y

                             , 0, 0, SWP_NOZORDER | SWP_NOSIZE);

                }

            pCur=pCur->pNext;

            }

        }

    return;

    }

/*

 * GizmoPFind

 *

 * Purpose:

 *  Given a GIZMO identifier, locates and returns a pointer to the

 *  structure for that position.

 *

 * Parameters:

 *  ppFirst         PPGIZMO providing the first gizmo in this list.

 *  uID             UINT identifier to find.

 *

 * Return Value:

 *  PGIZMO          A pointer to a GIZMO structure allocated through

 *                  GizmoPAllocate, NULL if iGizmo is out of range.

 */

PGIZMO GizmoPFind(PPGIZMO ppFirst, UINT uID)

    {

    PGIZMO       pGizmo;

    pGizmo=*ppFirst;

    /*

     * Yep, linear search, but a better search algorithm won't

     * improve things appreciably.  The better thing to optimize

     * is what the caller passes as ppFirst.

     */

    while (NULL!=pGizmo && uID!=pGizmo->uID)

        pGizmo=pGizmo->pNext;

    return pGizmo;

    }

/*

 * GizmoFEnum

 *

 * Purpose:

 *  Enumerates the list of GIZMO structures, passing each one to

 *  an application-defined callback.

 *

 * Parameters:

 *  ppFirst         PPGIZMO providing the first gizmo in this list.

 *  pfnEnum         PFNGIZMOENUM to call for each enumerated

 *                  structure.

 *  dw              DWORD extra data to pass to the enumeration

 *                  function.

 *

 * Return Value:

 *  PGIZMO          NULL if the enumeration completed.  Otherwise a

 *                  pointer to the gizmo that enumeration stopped on.

 */

PGIZMO GizmoPEnum(PPGIZMO ppFirst, PFNGIZMOENUM pfnEnum, DWORD dw)

    {

    PGIZMO  pGizmo;

    UINT    i=0;

    pGizmo=*ppFirst;

    while (NULL!=pGizmo)

        {

        if (!(*pfnEnum)(pGizmo, i++, dw))

            break;

        pGizmo=pGizmo->pNext;

        }

    return pGizmo;

    }

/*

 * GizmoPStateSet

 *

 * Purpose:

 *  State maniuplation functions.  Set and Clear also invalidate

 *  this gizmo's rectangle on the given window and forces a repaint.

 *

 * Parameters:

 *  hWnd            HWND of the window to repaint.

 *  pGizmo          PGIZMO affected.

 *  dwNew           DWORD new state flags.

 *

 * Return Value:

 *  UINT            Previous state.

 */

UINT  GizmoPStateSet(HWND hWnd, PGIZMO pGizmo, UINT uNew)

    {

    UINT        uRet;

    RECT        rc;

    if (GIZMOTYPE_SEPARATOR==pGizmo->iType)

        return pGizmo->uState;

    //Preserve the color conversion flags across this state change.

    uRet=pGizmo->uState;

    pGizmo->uState=(uNew & 0x00FF) | (uRet & 0xFF00);

    //Adjust the rectangle by  one to avoid repainting  borders.

    SetRect(&rc, pGizmo->x+1, pGizmo->y+1, pGizmo->x+pGizmo->dx-1

        , pGizmo->y+pGizmo->dy-1);

    InvalidateRect(hWnd, &rc, FALSE);

    UpdateWindow(hWnd);

    return uRet;

    }

/*

 * GizmoPCheck

 *

 * Purpose:

 *  Handles checking a single button in a group of attribute buttons.

 *  If the gizmo belongs to a group of mutually exclusive buttons

 *  then the others surrounding it are unchecked appropriately.

 *

 * Parameters:

 *  hWnd            HWND of the GizmoBar.

 *  pGizmo          PGIZMO of the gizmo affected.

 *  fCheck          BOOL TRUE to check the button, FALSE to uncheck.

 *

 * Return Value:

 *  BOOL            TRUE if the gizmo was previously checked, FALSE

 *                  otherwise.

 */

BOOL GizmoPCheck(HWND hWnd, PGIZMO pGizmo, BOOL fCheck)

    {

    BOOL        fPrevCheck;

    PGIZMO      pCur;

    //Ignore command buttons.

    if (GIZMOTYPE_BUTTONCOMMAND==pGizmo->iType)

        return FALSE;

    //Get the previous state

    fPrevCheck=(BOOL)(BUTTONGROUP_DOWN & pGizmo->uState);

    //Simply set the state for inclusive attribute buttons.

    if (GIZMOTYPE_BUTTONATTRIBUTEIN==pGizmo->iType)

        {

        if (pGizmo->fDisabled)

            {

            GizmoPStateSet(hWnd, pGizmo

                , fCheck ? ATTRIBUTEBUTTON_DOWNDISABLED

                : ATTRIBUTEBUTTON_DISABLED);

            }

        else

            {

            GizmoPStateSet(hWnd, pGizmo, fCheck

                ? ATTRIBUTEBUTTON_DOWN : ATTRIBUTEBUTTON_UP);

            }

        }

    if (GIZMOTYPE_BUTTONATTRIBUTEEX==pGizmo->iType)

        {

        //We cannot uncheck an exclusive attribute

        if (!fCheck)

            return fPrevCheck;

        /*

         * For exclusive buttons we have to do more work.  First, if

         * we're already checked (incliding DOWN and MOUSEDOWN) then

         * we set DOWN and exit.  If we're not already checked, then

         * we look for the gizmo around us, backwards and forwards,

         * that is checked and uncheck him.

         */

        //Search  backwards.

        pCur=pGizmo->pPrev;

        while (NULL!=pCur)

            {

            //Stop at any non-exclusive attribute.

            if (GIZMOTYPE_BUTTONATTRIBUTEEX!=pCur->iType)

                {

                pCur=NULL;

                break;

                }

            //If it's down, set it up and we've finished.

            if (BUTTONGROUP_DOWN & pCur->uState)

                break;

            pCur=pCur->pPrev;

            }

        //If we didn't find a previous one, pCur is NULL, look ahead.

        if (NULL==pCur)

            {

            pCur=pGizmo->pNext;

            while (NULL!=pCur)

                {

                //Stop at any non-exclusive attribute.

                if (GIZMOTYPE_BUTTONATTRIBUTEEX!=pCur->iType)

                    {

                    pCur=NULL;

                    break;

                    }

                //If it's down, set it up and we've finished.

                if (BUTTONGROUP_DOWN & pCur->uState)

                    break;

                pCur=pCur->pNext;

                }

            }

        //If pCur is non-NULL, we found a neighbor, so uncheck it

        if (NULL!=pCur)

            {

            GizmoPStateSet(hWnd, pCur, (pGizmo->fDisabled)

                ? ATTRIBUTEBUTTON_DISABLED : ATTRIBUTEBUTTON_UP);

            }

        //Always set ourselves down

        GizmoPStateSet(hWnd, pGizmo, (pGizmo->fDisabled)

            ? ATTRIBUTEBUTTON_DOWNDISABLED : ATTRIBUTEBUTTON_DOWN);

        }

    return fPrevCheck;

    }

/*

 * GenericSubProc

 *

 * Purpose:

 *  Subclasses window controls in Gizmos so we can trap the tab key

 *  and tab to the next control.  We can have one shared generic

 *  subclass procedure because we save the type index for this

 *  control in the property "iType."  This allows us to look up the

 *  original procedure in the pfnOrg array.

 *

 * Parameters:

 *  Standard

 *

 * Return Value:

 *  Standard

 */

LRESULT APIENTRY GenericSubProc(HWND hWnd, UINT iMsg

    , WPARAM wParam, LPARAM lParam)

    {

    LONG        lRet;

    RECT        rc;

    RECT        rcE;

    HWND        hWndE;

    HBRUSH      hBr;

    HDC         hDC;

    UINT        dx;

    UINT        iType, i;

    i=(int)GetProp(hWnd, SZTYPEPROP);

    iType=POSITIONBIT(i);

    //Special:  paint the gap in drop-down comboboxes.

    if (GIZMOTYPE_COMBOBOX==iType && WM_PAINT==iMsg)

        {

        //Do default painting.

        lRet=(*pfnOrg[i])(hWnd, iMsg, wParam, lParam);

        hWndE=GetDlgItem(hWnd, ID_COMBOEDIT);

        GetClientRect(hWnd, &rc);

        GetClientRect(hWndE, &rcE);

        //The width of the button is the scroll bar width.

        dx=GetSystemMetrics(SM_CXVSCROLL);

        //Calculate the rectangle

        rc.right -=dx;

        rc.left   =rcE.right;

        rc.bottom+=1;

        //Paint the gap

        hDC=GetDC(hWnd);   //Already did BeginPaint and EndPaint

        hBr=CreateSolidBrush(GetSysColor(COLOR_BTNFACE));

        FillRect(hDC, &rc, hBr);

        DeleteObject(hBr);

        ReleaseDC(hWnd, hDC);

        return lRet;

        }

    //Control tabbing to the next or previous control

    if (WM_KEYDOWN==iMsg && VK_TAB==wParam)

        {

        hWndE=hWnd;

        if (-1==i)

            hWndE=GetParent(hWnd);

        hWndE=GetNextDlgTabItem(GetParent(hWndE), hWnd

            , (BOOL)(GetKeyState(VK_SHIFT)));

        SetFocus(hWndE);

        return 0L;

        }

    if (-1==i) i=0;

    //Eat tab chars in edit controls to prevent beeping.

    if (0==i && WM_CHAR==iMsg && VK_TAB==wParam)

        return 0L;

    //Do this or edit controls bomb big-time.

    return CallWindowProc(pfnOrg[i], hWnd, iMsg, wParam, lParam);

    }


GIZMOBAR.DEF  (GIZMOBAR Sample)

LIBRARY     GIZMOBAR

DESCRIPTION 'GizmoBar 1.00, By Kraig Brockschmidt, (c)1993 Microsoft Corporation'

CODE        EXECUTE READ SHARED

EXPORTS     GizmoBarWndProc         @2

            GBHwndAssociateSet      @3

            GBHwndAssociateGet      @4

            GBGizmoAddA             @5

            GBGizmoAddW             @12

            GBGizmoRemove           @6

            GBGizmoSendMessage      @7

            GBGizmoShow             @8

            GBGizmoEnable           @9

            GBGizmoCheck            @10

            GBGizmoFocusSet         @11

            GBGizmoTypeGet          @13

            GBGizmoDataSet          @14

            GBGizmoDataGet          @15

            GBGizmoNotifySet        @16

            GBGizmoNotifyGet        @17

            GBGizmoTextGetA         @18

            GBGizmoTextGetW         @19

            GBGizmoTextSetA         @20

            GBGizmoTextSetW         @21

            GBGizmoIntGet           @22

            GBGizmoIntSet           @23

            GBGizmoExist            @24


GIZMOBAR.RC  (GIZMOBAR Sample)

/*

 * GIZMOBAR.RC

 * GizmoBar Version 1.01

 *

 * Strings and other resources for the GizmoBar.

 *

 * Copyright (c)1993-1994 Microsoft Corporation, All Rights Reserved

 *

 * Kraig Brockschmidt, Software Design Engineer

 * Microsoft Systems Developer Relations

 *

 * Internet  :  kraigb@microsoft.com

 * Compuserve:  >INTERNET:kraigb@microsoft.com

 */

#include <windows.h>

#include "gizmoint.h"

rcinclude gizmobar.rcv


GIZMOBAR.RCV  (GIZMOBAR Sample)

/*

 * GIZMOBAR.RCV

 * GizmoBar Version 1.01

 *

 * Version resource file for the GizmoBar Control DLL

 *

 * Copyright (c)1993-1994 Microsoft Corporation, All Rights Reserved

 *

 * Kraig Brockschmidt, Software Design Engineer

 * Microsoft Systems Developer Relations

 *

 * Internet  :  kraigb@microsoft.com

 * Compuserve:  >INTERNET:kraigb@microsoft.com

 */

#ifdef WIN32

#include <winver.h>

#else

#include <ver.h>

#endif

//Default is nodebug

#ifndef DEBUG

#define VER_DEBUG                   0

#else

#define VER_DEBUG                   VS_FF_DEBUG

#endif

VS_VERSION_INFO VERSIONINFO

 FILEVERSION        1,0,1,0

 PRODUCTVERSION     1,0,1,0

 FILEFLAGSMASK      VS_FFI_FILEFLAGSMASK

 FILEFLAGS          VER_DEBUG

#ifdef WIN32

 FILEOS             VOS_NT_WINDOWS32

#else

 FILEOS             VOS_DOS_WINDOWS16

#endif

 FILETYPE           VFT_DLL

 FILESUBTYPE        VFT_UNKNOWN

 BEGIN

   BLOCK "StringFileInfo"

    BEGIN

     BLOCK "040904E4"

      BEGIN

       VALUE "CompanyName",     "Microsoft Corporation\0", "\0"

       VALUE "FileDescription", "Kraig Brockschmidt's GizmoBar", "\0"

       VALUE "FileVersion",     "1.01\0", "\0"

       VALUE "InternalName",    "GIZMOBAR.DLL", "\0"

       VALUE "LegalCopyright",  "Copyright \2511993-1994osoft Corp.", "\0"

       VALUE "OriginalFilename","GIZMOBAR.DLL", "\0"

       VALUE "ProductName",     "Kraig Brockschmidt's GizmoBar", "\0"

       VALUE "ProductVersion",  "1.01\0"

      END

   END

   BLOCK "VarFileInfo"

    BEGIN

     VALUE "Translation", 0x0409, 0x04E4

    END

 END


GIZMOBAR.C  (GIZMOBAR Sample)

/*

 * GIZMOBAR.C

 * GizmoBar Version 1.01

 *

 * Contains the main window procedure of the GizmoBar control

 * that handles mouse logic and Windows messages.

 *

 * Copyright (c)1993-1994 Microsoft Corporation, All Rights Reserved

 *

 * Kraig Brockschmidt, Software Design Engineer

 * Microsoft Systems Developer Relations

 *

 * Internet  :  kraigb@microsoft.com

 * Compuserve:  >INTERNET:kraigb@microsoft.com

 */

#include <windows.h>

#include "gizmoint.h"

/*

 * GizmoBarWndProc

 *

 * Purpose:

 *  Window Procedure for the GizmoBar custom control.  Handles all

 *  messages like WM_PAINT just as a normal application window would.

 *  Any message not processed here should go to DefWindowProc.

 *

 * Parameters:

 *  Standard

 *

 * Return Value:

 *  Standard

 */

LRESULT WINAPI GizmoBarWndProc(HWND hWnd, UINT iMsg

    , WPARAM wParam, LPARAM lParam)

    {

    BOOL            fSuccess;

    BOOL            fTemp;

    LPCREATESTRUCT  pCreate;

    PGIZMOBAR       pGB;

    PGIZMO          pGizmo;

    RECT            rc;

    POINT           pt;

    short           x, y;

    COLORREF        cr;

    COMMANDPARAMS(wID, wCode, hWndMsg);

    pGB=(PGIZMOBAR)GetWindowLong(hWnd, GBWL_STRUCTURE);

    //Pass control messages onto another function for processing.

    if (iMsg >= WM_USER)

        return GBMessageHandler(hWnd, iMsg, wParam, lParam, pGB);

    switch (iMsg)

        {

        case WM_NCCREATE:

            pCreate=(LPCREATESTRUCT)lParam;

            pGB=GizmoBarPAllocate(&fSuccess, hWnd

                , pCreate->hInstance, pCreate->hwndParent

                , pCreate->style, 0, (UINT)pCreate->hMenu);

            if (!fSuccess)

                {

                GizmoBarPFree(pGB);

                return -1L;

                }

            else

                SetWindowLong(hWnd, GBWL_STRUCTURE, (LONG)pGB);

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

        case WM_DESTROY:

            /*

             * We want to clean up before DestroyWindow nukes all the

             * children, so WM_DESTROY is a better to do it than

             * WM_NCDESTROY.

             */

            GizmoBarPFree(pGB);

            break;

        case WM_ERASEBKGND:

            /*

             * Eat this message to avoid erasing portions that

             * we are going to repaint in WM_PAINT.  Part of a

             * change-state-and-repaint strategy is to rely on

             * WM_PAINT to do anything visual, which includes

             * erasing invalid portions.  Letting WM_ERASEBKGND

             * erase the background is redundant.

             */

            return TRUE;

       #ifdef WIN32

        case WM_CTLCOLORBTN:

        case WM_CTLCOLORSTATIC:

            fTemp=TRUE;

       #else

        case WM_CTLCOLOR:

            //Change the color of static text on the GizmoBar.

            fTemp=(HIWORD(lParam)==CTLCOLOR_STATIC

                || HIWORD(lParam)==CTLCOLOR_BTN);

       #endif

            if (fTemp)

                {

                cr=GetSysColor(COLOR_BTNFACE);

                SetTextColor((HDC)wParam

                    , GetSysColor(COLOR_BTNTEXT));

                SetBkColor((HDC)wParam, cr);

                /*

                 * If the system colors have changed, then crFace

                 * will not be equal to COLOR_BTNFACE, so we

                 * reinitialize the background brush.  This scheme

                 * handles system color changes appropriately

                 * without processing WM_WININICHANGE and without

                 * blindly creating a new brush on every WM_CTLCOLOR

                 * message.

                 */

                if (cr!=pGB->crFace)

                    {

                    pGB->crFace=cr;

                    if (NULL!=pGB->hBrFace)

                        DeleteObject(pGB->hBrFace);

                    pGB->hBrFace=CreateSolidBrush(pGB->crFace);

                    }

                return (LONG)(UINT)pGB->hBrFace;

                }

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

        case WM_PAINT:

            GizmoBarPaint(hWnd, pGB);

            break;

        case WM_SETFONT:

            /*

             * wParam has the new font that we now send to all other

             * windows controls in us.  We control repaints here to

             * prevent a lot of repainting for each control.

             */

            DefWindowProc(hWnd, WM_SETREDRAW, FALSE, 0L);

            if ((WPARAM)NULL!=wParam)

                {

                pGB->hFont=(HFONT)wParam;

                GizmoPEnum(&pGB->pGizmos, FEnumChangeFont

                    , (DWORD)(LPTSTR)pGB);

                DefWindowProc(hWnd, WM_SETREDRAW, TRUE, 0L);

                InvalidateRect(hWnd, NULL, FALSE);

                UpdateWindow(hWnd);

                }

            break;

        case WM_GETFONT:

            return (LRESULT)(UINT)pGB->hFont;

        case WM_ENABLE:

            /*

             * wParam has the new enable flag that we use to enable

             * or disable ALL controls in us at one time.  We also

             * turn the redraw off to prevent a lot of flicker.

             */

            DefWindowProc(hWnd, WM_SETREDRAW, FALSE, 0L);

            pGB->fEnabled=(BOOL)wParam;

            GizmoPEnum(&pGB->pGizmos, FEnumEnable

                , (DWORD)(LPTSTR)pGB);

            DefWindowProc(hWnd, WM_SETREDRAW, TRUE, 0L);

            InvalidateRect(hWnd, NULL, FALSE);

            UpdateWindow(hWnd);

            break;

        case WM_CANCELMODE:

            pGizmo=pGB->pGizmoTrack;

            pGB->fTracking=FALSE;

            pGB->fMouseOut=FALSE;

            if (NULL!=pGizmo)

                GizmoPStateSet(hWnd, pGizmo, COMMANDBUTTON_UP);

            ReleaseCapture();

            break;

        case WM_LBUTTONDBLCLK:

        case WM_LBUTTONDOWN:

            //Get the mouse coordinates.

            x=LOWORD(lParam);

            y=HIWORD(lParam);

            /*

             * See if we hit a command or attribute gizmo or not.

             * Anything else that is a control will get the message

             * instead of us anyway, so we don't have to check.

             * FEnumHitTest also validates drawn gizmos, enabled, and

             * visible, so we don't.

             */

            pGizmo=GizmoPEnum(&pGB->pGizmos, FEnumHitTest, lParam);

            if (NULL==pGizmo)

                break;          //Didn't hit one matching our needs.

            /*

             * Inform the associate that a command was hit like a

             * menu item.

             */

            if (NULL!=pGB->hWndAssociate)

                {

                if (pGizmo->fNotify)

                    {

                    SendMenuSelect(pGB->hWndAssociate, pGizmo->uID

                        , 0, 0);

                    }

                }

            /*

             * We hit a button.  If it's a command or attribute,

             * then change the state and start tracking.

             */

            pGB->fTracking=TRUE;

            pGB->pGizmoTrack=pGizmo;

            pGB->fMouseOut=FALSE;

            SetCapture(hWnd);

            pGizmo->uStateOrg=pGizmo->uState;

            GizmoPStateSet(hWnd, pGizmo, ATTRIBUTEBUTTON_MOUSEDOWN);

            break;

        case WM_MOUSEMOVE:

            POINTFROMLPARAM(pt, lParam);

            if (!pGB->fTracking)

                break;

            pGizmo=pGB->pGizmoTrack;

            SetRect(&rc, pGizmo->x, pGizmo->y, pGizmo->x+pGizmo->dx

                , pGizmo->y+pGizmo->dy);

            fTemp=pGB->fMouseOut;

            pGB->fMouseOut=!PtInRect(&rc, pt);

            //If the mouse went out, change state to the original.

            if (!fTemp && pGB->fMouseOut)

                {

                GizmoPStateSet(hWnd, pGizmo, pGizmo->uStateOrg);

                if (NULL!=pGB->hWndAssociate)

                    {

                    //Notify that we left the button

                    if (pGizmo->fNotify)

                        SendMenuSelect(pGB->hWndAssociate, 0, ~0, 0);

                    }

                }

            if (fTemp && !pGB->fMouseOut)

                {

                GizmoPStateSet(hWnd, pGizmo

                    , ATTRIBUTEBUTTON_MOUSEDOWN);

                if (NULL!=pGB->hWndAssociate)

                    {

                    //Notify that we pressed down again

                    if (pGizmo->fNotify)

                        {

                        SendMenuSelect(pGB->hWndAssociate

                            , pGizmo->uID , 0, 0);

                        }

                    }

                }

            break;

        case WM_LBUTTONUP:

            if (!pGB->fTracking)

                break;

            pGB->fTracking=FALSE;

            pGizmo=pGB->pGizmoTrack;

            ReleaseCapture();

            /*

             * Repaint if we were actually below the mouse when this

             * occurred.  For command buttons, pop the button up.

             * For attributes, either toggle the state (inclusive

             * buttons) or check the selected one (exclusive buttons)

             */

            if (!pGB->fMouseOut)

                {

                //Command buttons always come up.

                if (GIZMOTYPE_BUTTONCOMMAND==pGizmo->iType)

                    GizmoPStateSet(hWnd, pGizmo, COMMANDBUTTON_UP);

                //Attribute inclusive buttons toggle

                if (GIZMOTYPE_BUTTONATTRIBUTEIN==pGizmo->iType)

                    {

                    GizmoPCheck(hWnd, pGizmo, !(BUTTONGROUP_DOWN

                        & pGizmo->uStateOrg));

                    }

                //Attribure exclusive buttons are always checked.

                if (GIZMOTYPE_BUTTONATTRIBUTEEX==pGizmo->iType)

                    GizmoPCheck(hWnd, pGizmo, TRUE);

                //Only send messages if notify is ON.

                if (NULL!=pGB->hWndAssociate && pGizmo->fNotify)

                    {

                    SendMenuSelect(pGB->hWndAssociate, 0, ~0, 0);

                    SendCommand(pGB->hWndAssociate, pGizmo->uID

                        , BN_CLICKED, hWnd);

                    }

                }

            break;

        case WM_COMMAND:

            //Pass control messages on if the gizmo's notify is ON.

            if (NULL!=pGB->hWndAssociate)

                {

                pGizmo=PGizmoFromHwndID(hWnd, wID);

                if (NULL!=pGizmo)

                    {

                    if (pGizmo->fNotify)

                        {

                        SendMessage(pGB->hWndAssociate, iMsg, wParam

                            , lParam);

                        }

                    }

                }

            break;

        default:

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

        }

    return 0L;

    }

/*

 * FEnumChangeFont

 *

 * Purpose:

 *  Enumeration callback for all the gizmos we know about in order to

 *  send a new font to them that's stored in PGIZMOBAR in dw.

 *

 * Parameters:

 *  pGizmo          PGIZMO to draw.

 *  iGizmo          UINT index on the GizmoBar of this gizmo.

 *  dw              DWORD extra data passed to GizmoPEnum, in our

 *                  case the GizmoBar's pGB.

 *

 * Return Value:

 *  BOOL            TRUE to continue the enumeration, FALSE otherwise.

 */

BOOL WINAPI FEnumChangeFont(PGIZMO pGizmo, UINT iGizmo, DWORD dw)

    {

    PGIZMOBAR   pGB=(PGIZMOBAR)dw;

    //Only need to change fonts in windowed controls using WM_SETFONT

    if (NULL!=pGizmo->hWnd)

        {

        SendMessage(pGizmo->hWnd, WM_SETFONT

            , (WPARAM)pGB->hFont, 1L);

        }

    return TRUE;

    }

/*

 * FEnumEnable

 *

 * Purpose:

 *  Enumeration callback for all the gizmos we know about in order to

 *  enable or disable them from the WM_ENABLE message.

 *

 * Parameters:

 *  pGizmo          PGIZMO to draw.

 *  iGizmo          UINT index on the GizmoBar of this gizmo.

 *  dw              DWORD extra data passed to GizmoPEnum, in our

 *                  case the GizmoBar's pGB.

 *

 * Return Value:

 *  BOOL            TRUE to continue the enumeration, FALSE

 *                  otherwise.

 */

BOOL WINAPI FEnumEnable(PGIZMO pGizmo, UINT iGizmo, DWORD dw)

    {

    PGIZMOBAR   pGB=(PGIZMOBAR)dw;

    BOOL        fEnable=pGB->fEnabled;

    //NOTE:  This code is duplicated in GBGizmoEnable in API.C

    if (NULL!=pGizmo->hWnd)

        EnableWindow(pGizmo->hWnd, fEnable);

    else

        {

        //If we're not down, command and attribute buttons act same.

        if (!(BUTTONGROUP_DOWN & pGizmo->uState))

            {

            GizmoPStateSet(pGB->hWnd, pGizmo, fEnable

                ? COMMANDBUTTON_UP : COMMANDBUTTON_DISABLED);

            }

        else

            {

            /*

             * Attribute buttons are a little more sensitive

             * with DOWNDISABLED

             */

            GizmoPStateSet(pGB->hWnd, pGizmo, fEnable

                ? ATTRIBUTEBUTTON_DOWN

                : ATTRIBUTEBUTTON_DOWNDISABLED);

            }

        }

    return TRUE;

    }

/*

 * FEnumHitTest

 *

 * Purpose:

 *  Enumeration callback for all the gizmos we know about in order to

 *  hit-test them.

 *

 * Parameters:

 *  pGizmo          PGIZMO to draw.

 *  iGizmo          UINT index on the GizmoBar of this gizmo.

 *  dw              DWORD extra data passed to GizmoPEnum, in our

 *                  case the hDC on which to draw.

 *

 * Return Value:

 *  BOOL            TRUE to continue the enumeration, FALSE

 *                  otherwise.

 */

BOOL WINAPI FEnumHitTest(PGIZMO pGizmo, UINT iGizmo, DWORD dw)

    {

    RECT  rc;

    POINT pt;

    POINTFROMLPARAM(pt, dw);

    /*

     * Hit tests have to happen on visible, enabled, and drawn

     * controls only.

     */

    if (GIZMOTYPE_DRAWN & pGizmo->iType && !pGizmo->fHidden

        && !(BUTTONGROUP_DISABLED & pGizmo->uState))

        {

        SetRect(&rc, pGizmo->x, pGizmo->y

            , pGizmo->x+pGizmo->dx, pGizmo->y+pGizmo->dy);

        //Stop enumeration if we have a hit.

        return !PtInRect(&rc, pt);

        }

    return TRUE;

    }


GIZMOINT.H  (GIZMOBAR Sample)

/*

 * GIZMOINT.H

 * GizmoBar Version 1.01

 *

 * Internal definitions for the GizmoBar DLL

 *

 * Copyright (c)1993-1994 Microsoft Corporation, All Rights Reserved

 *

 * Kraig Brockschmidt, Software Design Engineer

 * Microsoft Systems Developer Relations

 *

 * Internet  :  kraigb@microsoft.com

 * Compuserve:  >INTERNET:kraigb@microsoft.com

 */

#ifndef _GIZMOINT_H_

#define _GIZMOINT_H_

#include "gizmobar.h"

#include "win1632.h"

#include "gizmo.h"

#ifdef __cplusplus

extern "C"

    {

#endif

/*

 * The main gizmobar structure itself.  There's only one of these,

 * but it references the first GIZMO in the list.

 */

typedef struct tagGIZMOBAR

    {

    PGIZMO      pGizmos;            //List of gizmos we own.

    HWND        hWnd;               //Window handle of ourselves.

    HINSTANCE   hInst;

    HWND        hWndAssociate;      //Associate who gets messages.

    DWORD       dwStyle;            //Copy of GWL_STYLE

    UINT        uState;             //State flags

    UINT        uID;                //Control ID.

    HBRUSH      hBrFace;            //Static control background color

    COLORREF    crFace;             //Color of hBrFace

    HFONT       hFont;              //Font in use

    BOOL        fEnabled;           //Are we enabled?

    PGIZMO      pGizmoTrack;        //Current pressed button.

    BOOL        fTracking;

    BOOL        fMouseOut;

    } GIZMOBAR, * PGIZMOBAR;

#define CBGIZMOBAR sizeof(GIZMOBAR)

//Extra bytes for the window if the size of a local handle.

#define CBWINDOWEXTRA       sizeof(PGIZMOBAR)

#define GBWL_STRUCTURE      0

//Structure for passing paint info to a gizmo enumeration callback.

typedef struct

    {

    HDC     hDC;

    BOOL    fPaint;

    } PAINTGIZMO, * PPAINTGIZMO;

//Private functions specific to the control.

//INIT.C

BOOL              FRegisterControl(HINSTANCE);

PGIZMOBAR         GizmoBarPAllocate(int *, HWND, HINSTANCE, HWND

                      , DWORD, UINT, UINT);

PGIZMOBAR         GizmoBarPFree(PGIZMOBAR);

//PAINT.C

void              GizmoBarPaint(HWND, PGIZMOBAR);

BOOL WINAPI       FEnumPaintGizmos(PGIZMO, UINT, DWORD);

//GIZMOBAR.C

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

BOOL    WINAPI    FEnumChangeFont(PGIZMO, UINT, DWORD);

BOOL    WINAPI    FEnumEnable(PGIZMO, UINT, DWORD);

BOOL    WINAPI    FEnumHitTest(PGIZMO, UINT, DWORD);

//API.C  Also see GIZMOBAR.H for others

LRESULT    GBMessageHandler(HWND, UINT, WPARAM, LPARAM, PGIZMOBAR);

PGIZMO     PGizmoFromHwndID(HWND, UINT);

#endif //_GIZMOINT_H_


INIT.C  (GIZMOBAR Sample)

/*

 * INIT.C

 * GizmoBar Version 1.01

 *

 * LibMain entry point and initialization code for the GizmoBar

 * DLL that is likely to be used once or very infrequently.

 *

 * Copyright (c)1993-1994 Microsoft Corporation, All Rights Reserved

 *

 * Kraig Brockschmidt, Software Design Engineer

 * Microsoft Systems Developer Relations

 *

 * Internet  :  kraigb@microsoft.com

 * Compuserve:  >INTERNET:kraigb@microsoft.com

 */

#include <windows.h>

#include "gizmoint.h"

/*

 * LibMain(32)

 *

 * Purpose:

 *  Entry point conditionally compiled for Windows NT and Windows

 *  3.1.  Provides the proper structure for each environment.

 */

#ifdef WIN32

BOOL WINAPI DllMain(HINSTANCE hInstance, ULONG ulReason

    , PCONTEXT pContext)

    {

    UNREFERENCED_PARAMETER(pContext);

    if (DLL_PROCESS_ATTACH==ulReason)

        return FRegisterControl(hInstance);

    return TRUE;

    }

#else

int WINAPI LibMain(HANDLE hInstance, WORD wDataSeg

    , WORD cbHeapSize, LPTSTR lpCmdLine)

    {

     //Perform global initialization.

    if (FRegisterControl(hInstance))

        {

        if (0!=cbHeapSize)

            UnlockData(0);

        }

    return (int)hInstance;

    }

#endif

/*

 * FRegisterControl

 *

 * Purpose:

 *  Registers the GizmoBar control class, including CS_GLOBALCLASS

 *  to make the control available to all applications in the system.

 *

 * Parameters:

 *  hInst           HINSTANCE of the DLL that will own this class.

 *

 * Return Value:

 *  BOOL            TRUE if the class is registered, FALSE otherwise.

 */

BOOL FRegisterControl(HINSTANCE hInst)

    {

    static BOOL     fRegistered=FALSE;

    WNDCLASS        wc;

    if (!fRegistered)

        {

        wc.lpfnWndProc   =GizmoBarWndProc;

        wc.cbClsExtra    =0;

        wc.cbWndExtra    =CBWINDOWEXTRA;

        wc.hInstance     =hInst;

        wc.hIcon         =NULL;

        wc.hCursor       =LoadCursor(NULL, IDC_ARROW);

        wc.hbrBackground =(HBRUSH)(COLOR_BTNFACE+1);

        wc.lpszMenuName  =NULL;

        wc.lpszClassName =CLASS_GIZMOBAR;

        wc.style         =CS_DBLCLKS | CS_GLOBALCLASS

                          | CS_VREDRAW | CS_HREDRAW;

        fRegistered=RegisterClass(&wc);

        }

    return fRegistered;

    }

/*

 * GizmoBarPAllocate

 *

 * Purpose:

 *  Allocates and initializes the control's primary data structure

 *  for each window that gets created.

 *

 * Parameters:

 *  pfSuccess       int * indicating success of the function.

 *  hWnd            HWND that is tied to this structure.

 *  hInst           HINSTANCE of the DLL.

 *  hWndAssociate   HWND to which we send messages.

 *  dwStyle         DWORD initial style.

 *  uState          UINT initial state.

 *  uID             UINT identifier for this window.

 *

 * Return Value:

 *  PGIZMOBAR       If NULL returned then GizmoBarPAllocate could not

 *                  allocate memory.  If a non-NULL pointer is

 *                  returned with *pfSuccess, then call GizmoBarPFree

 *                  immediately.  If you get a non-NULL pointer and

 *                  *pfSuccess==TRUE then the function succeeded.

 */

PGIZMOBAR GizmoBarPAllocate(int *pfSuccess, HWND hWnd

    , HINSTANCE hInst, HWND hWndAssociate, DWORD dwStyle

    , UINT uState , UINT uID)

    {

    PGIZMOBAR     pGB;

    if (NULL==pfSuccess)

        return NULL;

    *pfSuccess=FALSE;

    //Allocate the structure

    pGB=(PGIZMOBAR)(void *)LocalAlloc(LPTR, CBGIZMOBAR);

    if (NULL==pGB)

        return NULL;

    //Initialize LibMain parameter holders.

    pGB->hWnd         =hWnd;

    pGB->hInst        =hInst;

    pGB->hWndAssociate=hWndAssociate;

    pGB->dwStyle      =dwStyle;

    pGB->uState       =uState;

    pGB->uID          =uID;

    pGB->fEnabled     =TRUE;

    pGB->crFace=GetSysColor(COLOR_BTNFACE);

    pGB->hBrFace=CreateSolidBrush(pGB->crFace);

    if (NULL==pGB->hBrFace)

        return pGB;

    pGB->hFont=GetStockObject(SYSTEM_FONT);

    *pfSuccess=TRUE;

    return pGB;

    }

/*

 * GizmoBarPFree

 *

 * Purpose:

 *  Reverses all initialization done by GizmoBarPAllocate, cleaning

 *  up any allocations including the application structure itself.

 *

 * Parameters:

 *  pGB             PGIZMOBAR to the control's structure

 *

 * Return Value:

 *  PGIZMOBAR       NULL if successful, pGB if not, meaning we

 *                  couldn't free some allocation.

 */

PGIZMOBAR GizmoBarPFree(PGIZMOBAR pGB)

    {

    if (NULL==pGB)

        return NULL;

    /*

     * Free all the gizmos we own.  When we call GizmoPFree we always

     * free the first one in the list which updates pGB->pGizmos for

     * us, so we just have to keep going until pGizmos is NULL,

     * meaning we're at the end of the list.

     */

    while (NULL!=pGB->pGizmos)

        GizmoPFree(&pGB->pGizmos, pGB->pGizmos);

    if (NULL!=pGB->hBrFace)

        DeleteObject(pGB->hBrFace);

    /*

     * Notice that since we never create a font, we aren't

     * responsible for our hFont member.

     */

    return (PGIZMOBAR)(void *)LocalFree((HLOCAL)(UINT)(LONG)pGB);

    }


PAINT.C  (GIZMOBAR Sample)

/*

 * PAINT.C

 * GizmoBar Version 1.01

 *

 * Contains any code related to GizmoBar visuals, primarily

 * the WM_PAINT handler.

 *

 * Copyright (c)1993-1994 Microsoft Corporation, All Rights Reserved

 *

 * Kraig Brockschmidt, Software Design Engineer

 * Microsoft Systems Developer Relations

 *

 * Internet  :  kraigb@microsoft.com

 * Compuserve:  >INTERNET:kraigb@microsoft.com

 */

#include <windows.h>

#include "gizmoint.h"

//In GIZMO.C

extern TOOLDISPLAYDATA tdd;

/*

 * GizmoBarPaint

 *

 * Purpose:

 *  Handles all WM_PAINT messages for the control and paints either

 *  the entire thing or just one GizmoBar button if pGB->pGizmoPaint

 *  is non-NULL.

 *

 * Parameters:

 *  hWnd            HWND Handle to the control.

 *  pGB             PGIZMOBAR control data pointer.

 *

 * Return Value:

 *  None

 */

void GizmoBarPaint(HWND hWnd, PGIZMOBAR pGB)

    {

    PAINTSTRUCT ps;

    RECT        rc;

    HDC         hDC;

    HBRUSH      hBr=NULL;

    HPEN        hPen=NULL;

    hDC=BeginPaint(hWnd, &ps);

    GetClientRect(hWnd, &rc);

    /*

     * The only part of the frame we need to draw is the bottom line,

     * so we inflate the rectangle such that all other parts are

     * outside the visible region.

     */

    hBr =CreateSolidBrush(GetSysColor(COLOR_BTNFACE));

    if (NULL!=hBr)

        SelectObject(hDC, hBr);

    hPen=CreatePen(PS_SOLID, 1, GetSysColor(COLOR_WINDOWFRAME));

    if (NULL!=hPen)

        SelectObject(hDC, hPen);

    Rectangle(hDC, rc.left-1, rc.top-1, rc.right+1, rc.bottom);

    /*

     * All that we have to do to draw the controls is start through

     * the list, ignoring anything but buttons, and calling BTTNCUR's

     * UIToolButtonDraw for buttons.  Since we don't even have to

     * track positions of things, we can just use an enum.

     */

    GizmoPEnum(&pGB->pGizmos, FEnumPaintGizmos, (DWORD)(LPTSTR)&ps);

    //Clean up

    EndPaint(hWnd, &ps);

    if (NULL!=hBr)

        DeleteObject(hBr);

    if (NULL!=hPen)

        DeleteObject(hPen);

    return;

    }

/*

 * FEnumPaintGizmos

 *

 * Purpose:

 *  Enumeration callback for all the gizmos we know about in order to

 *  draw them.

 *

 * Parameters:

 *  pGizmo          PGIZMO to draw.

 *  iGizmo          UINT index on the GizmoBar of this gizmo.

 *  dw              DWORD extra data passed to GizmoPEnum, in our

 *                  case a pointer to the PAINTSTRUCT.

 *

 * Return Value:

 *  BOOL            TRUE to continue the enumeration, FALSE

 *                  otherwise.

 */

BOOL WINAPI FEnumPaintGizmos(PGIZMO pGizmo, UINT iGizmo, DWORD dw)

    {

    LPPAINTSTRUCT   pps=(LPPAINTSTRUCT)dw;

    RECT            rc, rcI;

    //Only draw those marked for repaint.

    if ((GIZMOTYPE_DRAWN & pGizmo->iType))

        {

        SetRect(&rc, pGizmo->x, pGizmo->y

            , pGizmo->x+pGizmo->dx, pGizmo->y+pGizmo->dy);

        //Only draw gizmos in the repaint area

        if (IntersectRect(&rcI, &rc, &pps->rcPaint))

            {

            UIToolButtonDrawTDD(pps->hdc, pGizmo->x, pGizmo->y

                , pGizmo->dx, pGizmo->dy, pGizmo->hBmp

                , pGizmo->cxImage, pGizmo->cyImage, pGizmo->iBmp

                , (UINT)pGizmo->uState, &tdd);

            }

        }

    return TRUE;

    }


WIN1632.H  (GIZMOBAR Sample)

/*

 * BOOK1632.H

 *

 * Macros and other definitions that assist in porting between Win16

 * and Win32 applications.  Defines WIN32 to enable 32-bit versions.

 *

 * Copyright (c)1993-1994 Microsoft Corporation, All Rights Reserved

 *

 * Kraig Brockschmidt, Software Design Engineer

 * Microsoft Systems Developer Relations

 *

 * Internet  :  kraigb@microsoft.com

 * Compuserve:  INTERNET>kraigb@microsoft.com

 */

#ifndef _BOOK1632_H_

#define _BOOK1632_H_

#ifdef WIN32

#ifndef COMMANDPARAMS

#define COMMANDPARAMS(wID, wCode, hWndMsg)                          \

    WORD        wID     = LOWORD(wParam);                           \

    WORD        wCode   = HIWORD(wParam);                           \

    HWND        hWndMsg = (HWND)(UINT)lParam;

#endif  //COMMANDPARAMS

#ifndef SendCommand

#define SendCommand(hWnd, wID, wCode, hControl)                     \

            SendMessage(hWnd, WM_COMMAND, MAKEWPARAM(wID, wCode)    \

                        , (LPARAM)hControl)

#endif  //SendCommand

#ifndef MENUSELECTPARAMS

#define MENUSELECTPARAMS(wID, wFlags, hMenu)                        \

    WORD        wID     = LOWORD(wParam);                           \

    WORD        wFlags  = HIWORD(wParam);                           \

    HMENU       hMenu   = (HMENU)lParam;

#endif  //MENUSELECTPARAMS

#ifndef SendMenuSelect

#define SendMenuSelect(hWnd, wID, wFlags, hMenu)                    \

            SendMessage(hWnd, WM_MENUSELECT                         \

                , MAKEWPARAM((WORD)wID, (WORD)wFlags), (LPARAM)hMenu)

#endif  //SendMenuSelect

#ifndef SendScrollPosition

#define SendScrollPosition(hWnd, iMsg, iPos)                        \

            SendMessage(hWnd, iMsg, MAKEWPARAM(SB_THUMBPOSITION, iPos), 0)

#endif //SendScrollPosition

#ifndef ScrollThumbPosition

#define ScrollThumbPosition(w, l) HIWORD(w)

#endif //ScrollThumbPosition

#ifndef GETWINDOWINSTANCE

#define GETWINDOWINSTANCE(h) (HINSTANCE)GetWindowLong(h, GWL_HINSTANCE)

#endif  //GETWINDOWINSTANCE

#ifndef GETWINDOWID

#define GETWINDOWID(h) (UINT)GetWindowLong(h, GWW_ID)

#endif  //GETWINDOWID

#ifndef POINTFROMLPARAM

#define POINTFROMLPARAM(p, l) {p.x=(LONG)(SHORT)LOWORD(l); \

                               p.y=(LONG)(SHORT)HIWORD(l);}

#endif  //POINTEFROMLPARAM

#ifndef MDIREFRESHMENU

#define MDIREFRESHMENU(h) SendMessage(h, WM_MDIREFRESHMENU, 0, 0L)

#endif  //MDIREFRESHMENU

//Activated child window in WM_MDIACTIVATE

#ifndef NEWMDIACTIVE

#define NEWMDIACTIVE lParam

#endif  //NEWMDIACTIVE

#ifndef UNICODETOANSI

#ifdef UNICODE

#define UNICODETOANSI(s, d, cch) WideCharToMultiByte(CP_ACP \

            , 0, s, -1, d, cch, NULL, NULL)

#else  //ANSI

#define UNICODETOANSI(s, d, cch) lstrcpy(d, (LPTSTR)s)

#endif

#endif //UNICODETOANSI

//****END WIN32

#else

//****START !WIN32

#ifndef POINTS

typedef POINT POINTS;

#endif  //POINTS

#ifndef LPPOINTS

typedef POINTS FAR *LPPOINTS;

#endif  //LPPOINTS

#ifndef MAKEPOINTS

#define MAKEPOINTS MAKEPOINT

#endif  //MAKEPOINTS

#ifndef COMMANDPARAMS

#define COMMANDPARAMS(wID, wCode, hWndMsg)                          \

    WORD        wID     = LOWORD(wParam);                           \

    WORD        wCode   = HIWORD(lParam);                           \

    HWND        hWndMsg = (HWND)(UINT)lParam;

#endif  //COMMANDPARAMS

#ifndef SendCommand

#define SendCommand(hWnd, wID, wCode, hControl)                     \

            SendMessage(hWnd, WM_COMMAND, wID                       \

                        , MAKELONG(hControl, wCode))

#endif  //SendCommand

#ifndef MENUSELECTPARAMS

#define MENUSELECTPARAMS(wID, wFlags, hMenu)                        \

    WORD        wID     = LOWORD(wParam);                           \

    WORD        wFlags  = LOWORD(lParam);                           \

    HMENU       hMenu   = (HMENU)HIWORD(lParam);

#endif  //MENUSELECTPARAMS

#ifndef SendMenuSelect

#define SendMenuSelect(hWnd, wID, wFlags, hMenu)                    \

            SendMessage(hWnd, WM_MENUSELECT, wID                    \

                        , MAKELONG((WORD)wFlags, (WORD)hMenu))

#endif  //SendMenuSelect

#ifndef SendScrollPosition

#define SendScrollPosition(hWnd, iMsg, iPos)                        \

            SendMessage(hWnd, iMsg, SB_THUMBPOSITION, MAKELONG(iPos, 0))

#endif //Send ScrollPosition

#ifndef ScrollThumbPosition

#define ScrollThumbPosition(w, l) LOWORD(l)

#endif //ScrollThumbPosition

#ifndef GETWINDOWINSTANCE

#define GETWINDOWINSTANCE(h) (HINSTANCE)GetWindowWord(h, GWW_HINSTANCE)

#endif  //GETWINDOWINSTANCE

#ifndef GETWINDOWID

#define GETWINDOWID(h) (UINT)GetWindowWord(h, GWW_ID)

#endif  //GETWINDOWID

#ifndef POINTFROMLPARAM

#define POINTFROMLPARAM(p, l) {p.x=LOWORD(l); p.y=HIWORD(l);}

#endif  //POINTEFROMLPARAM

#ifndef MDIREFRESHMENU

#define MDIREFRESHMENU(h) SendMessage(h, WM_MDISETMENU, TRUE, 0L)

#endif  //MDIREFRESHMENU

//Activated child window in WM_MDIACTIVATE

#ifndef NEWMDIACTIVE

#define NEWMDIACTIVE wParam

#endif  //NEWMDIACTIVE

//Things not present in Win3.1 SDK but present in Win32 SDK.

#ifndef APIENTRY

#define APIENTRY __export FAR PASCAL

#endif  //APIENTRY

#ifndef USHORT

typedef unsigned short USHORT;

#endif  //USHORT

//These are so we can write ANSI/UNICODE portable code.

#ifndef TCHAR

typedef char TCHAR;

#endif  //TCHAR

#ifndef LPTSTR

typedef TCHAR *LPTSTR;

#endif  //LPTSTR

#ifndef LPCTSTR

typedef const TCHAR *LPCTSTR;

#endif  //LPCTSTR

#ifndef _tcsncpy

#define _tcsncpy strncpy

#endif  //_tcsncpy

#ifndef lstrcpyA

#define lstrcpyA lstrcpy

#endif  //lstrcpyA

#ifndef lstrcmpiA

#define lstrcmpiA lstrcmpi

#endif  //lstrcmpiA

#ifndef TEXT

#define TEXT(a) a

#endif  //TEXT

#ifndef DeleteFile

#define DeleteFile(f)                       \

            {                               \

            OFSTRUCT    of;                 \

            OpenFile(f, &of, OF_DELETE);    \

            }

#endif  //DeleteFile

#ifndef UNICODETOANSI

#define UNICODETOANSI(s, d, cch) lstrcpy(d, (LPTSTR)s)

#endif  //UNICODETOANSI

#ifndef SetForegroundWindow

#define SetForegroundWindow(w) SetActiveWindow(w)

#endif  //SetForegroundWindow

#endif  //!WIN32

//These definitions we need regardless of Win16 or Win32

typedef struct

    {

    short   left;

    short   top;

    short   right;

    short   bottom;

    } RECTS, FAR *LPRECTS;

#define RECTSTORECT(rs, r) {(r).left=(rs).left;(r).top=(rs).top; \

    (r).right=(rs).right;(r).bottom=(rs).bottom;};

#define RECTTORECTS(r, rs) {(rs).left=(short)(r).left;   \

    (rs).top=(short)(r).top;(rs).right=(short)(r).right; \

    (rs).bottom=(short)(r).bottom;};

#endif  //_BOOK1632_H_


INCLUDE

These topics contain header files included in the various other OLE code samples.


ANSIAPI.H  (INCLUDE Sample)

/*

 * ansiapi.h

 * This file contains prototypes of ANSI version of OLE apis

 * and mapping fooA to foo

 */

#ifndef _ANSIAPI_INCL

#define _ANSIAPI_INCL

#define UNICODEOLE32

#ifdef WIN32S

#if !defined(UNICODEOLE32)

#pragma message("Compiling for 32bit ANSI Ole!\n");

#endif

#endif

#define WASANSI() {                                                           \

                   OutputDebugString("\n\r\t\tUnicode string was ANSI!\r\n"); \

                   Assert(0);                                                 \

                   _asm { int 3 }                                             \

                  }

#ifndef UNICODEOLE32

#define W2A(w, a, cb)     lstrcpy (a, w)

#define A2W(a, w, cb)     lstrcpy (w, a)

#define FREELOCALSTRING(p)

#define MAKE_STR_LOCAL_COPYW2A(s, l)  l = s

#define MAKE_STR_LOCAL_COPYA2W(s, l)  l = s

#define OLESTRCPY                lstrcpy

#define OLESTRCAT                lstrcat

#define OLESTRLEN                lstrlen

#define OLESTRCMP                lstrcmp

#define OLESTRCMPI               lstrcmpi

#define DeleteFile_AW            DeleteFile

#define _lopen_AW                _lopen

#define _lcreat_AW               _lcreat

#define GlobalAddAtom_AW         GlobalAddAtom

#define GlobalGetAtomName_AW     GlobalGetAtomName

#define RegOpenKey_AW            RegOpenKey

#define CoLoadLibraryA   CoLoadLibrary

#define StringFromCLSID2A    StringFromCLSID2

#define StringFromIID2A      StringFromIID2

#define StringFromGUID2A     StringFromGUID2

#define CLSIDFromProgIDA     CLSIDFromProgID

#define CLSIDFromStringA     CLSIDFromString

#define ProgIDFromCLSIDA     ProgIDFromCLSID

#define StringFromCLSIDA     StringFromCLSID

#define UtDupStringA2W       UtDupString

// Storage APIs

#define StgOpenStorageA      StgOpenStorage

// IPersistFile ansi translation

#define IPersistFile_LoadA(pf, file, mode) (pf)->Load(file, mode)

// IMoniker ansi translation

#define IMoniker_GetDisplayNameA(pm, p1, p2, p3) (pm)->GetDisplayName(p1,p2,p3)

#define CreateFileMonikerA   CreateFileMoniker

#else  // UNICODEOLE32

#define W2A(w, a, cb)     WideCharToMultiByte(                              \

                                               CP_ACP,                      \

                                               0,                           \

                                               w,                           \

                                               -1,                          \

                                               a,                           \

                                               cb,                          \

                                               NULL,                        \

                                               NULL)

#define A2W(a, w, cb)     MultiByteToWideChar(                              \

                                               CP_ACP,                      \

                                               0,                           \

                                               a,                           \

                                               -1,                          \

                                               w,                           \

                                               cb)

#define FREELOCALSTRING(p)      delete (p)

#define MAKE_STR_LOCAL_COPYW2A(s, l)  {                                   \

                                      l = UtDupStringW2A(s);              \

                                      if (!l) {                           \

                                         return ResultFromScode(S_OOM);   \

                                      }                                   \

                                   }

#define MAKE_STR_LOCAL_COPYA2W(s, l)  {                                   \

                                      l = UtDupStringA2W(s);              \

                                      if (!l) {                           \

                                         return ResultFromScode(S_OOM);   \

                                      }                                   \

                                   }

#define OLESTRCPY                lstrcpyW

#define OLESTRCAT                lstrcatW

#define OLESTRLEN                lstrlenW

#define OLESTRCMP                lstrcmpW

#define OLESTRCMPI               lstrcmpiW

#define DeleteFile_AW            DeleteFileW

#define _lopen_AW                _lopenW

#define _lcreat_AW               _lcreatW

#define GlobalAddAtom_AW         GlobalAddAtomW

#define GlobalGetAtomName_AW     GlobalGetAtomNameW

#define RegOpenKey_AW            RegOpenKeyW

STDAPI_(HINSTANCE) CoLoadLibraryA(LPSTR lpszLibName, BOOL bAutoFree);

#define StringFromCLSID2A(rclsid, lpsz, cbMax) \

    StringFromGUID2A(rclsid, lpsz, cbMax)

#define StringFromIID2A(riid, lpsz, cbMax) \

    StringFromGUID2A(riid, lpsz, cbMax)

STDAPI_(int)  StringFromGUID2A(REFGUID rguid, LPSTR lpsz, int cbMax);

STDAPI        CLSIDFromProgIDA(LPCSTR szProgID, LPCLSID pclsid);

STDAPI        CLSIDFromStringA(LPSTR lpsz, LPCLSID lpclsid);

STDAPI        StringFromCLSIDA(REFCLSID rclsid, LPSTR FAR* lplpsz);

STDAPI        ProgIDFromCLSIDA (REFCLSID clsid, LPSTR FAR* lplpszProgID);

LPWSTR UtDupStringA2W(LPCSTR pSrc);

LPSTR  UtDupStringW2A(LPCWSTR pSrc);

// Storage APIs

STDAPI StgOpenStorageA(LPCSTR pwcsName,IStorage FAR *pstgPriority, DWORD grfMode, SNB snbExclude, DWORD reserved, IStorage FAR * FAR *ppstgOpen);

// IPersistFile ansi translation

HRESULT IPersistFile_LoadA(LPPERSISTFILE pIPF, LPSTR szFile, DWORD dwMode);

// IMoniker ansi translation

HRESULT IMoniker_GetDisplayNameA(LPMONIKER pm, LPBC p1, LPMONIKER p2, LPSTR FAR *p3);

//OLEAPI CreateFileMonikerA ( LPSTR lpszPathName, LPMONIKER FAR * ppmk );

#endif // !UNICODEOLE32

#endif //  _ANSIAPI_INCL


ASSERT.H  (INCLUDE Sample)

//+---------------------------------------------------------------------------

//

//  Microsoft Windows

//  Copyright (C) Microsoft Corporation, 1992 - 1994.

//

//  File:       assert.h

//

//  Contents:   private definition of assert, used by NT SDK OLE2 samples

//

//  History:    8-19-94   stevebl   Created

//

//----------------------------------------------------------------------------

/*

 * Conditional macro definition for function calling type and variable type

 * qualifiers.

 */

#if   ( (_MSC_VER >= 800) && (_M_IX86 >= 300) )

/*

 * Definitions for MS C8-32 (386/486) compiler

 */

#define _CRTAPI1 __cdecl

#define _CRTAPI2 __cdecl

#else

/*

 * Other compilers (e.g., MIPS)

 */

#define _CRTAPI1

#define _CRTAPI2

#endif

#undef  assert

#ifdef NDEBUG

#define assert(exp)     ((void)0)

#else

#ifdef __cplusplus

extern "C" {

#endif

void _CRTAPI1

PopUpAssert(

    void * szFile,

    int iLine,

    void * szMessage);

#ifdef __cplusplus

}

#endif

#define assert(exp) (void)( (exp) || (PopUpAssert(__FILE__, __LINE__, #exp), 0) )

#define _assert(exp, file, line) PopUpAssert(file, line, exp)

#endif  /* NDEBUG */


BTTNCUR.H  (INCLUDE Sample)

/*

 * BTTNCUR.H

 * Buttons & Cursors Version 1.1, March 1993

 *

 * Public include file for the Button Images and Cursor DLL, including

 * structures, definitions, and function prototypes.

 *

 * Copyright (c)1992-1993 Microsoft Corporation, All Rights Reserved,

 * as applied to redistribution of this source code in source form

 * License is granted to use of compiled code in shipped binaries.

 */

#ifndef _BTTNCUR_H_

#define _BTTNCUR_H_

#ifdef __cplusplus

extern "C"

{

#endif

//Standard image bitmap

//WARNING:  Obsolete.  Use the return from UIToolDisplayData

#define IDB_STANDARDIMAGES              400

//New values for display types

#define IDB_STANDARDIMAGESMIN           400

#define IDB_STANDARDIMAGES96            400

#define IDB_STANDARDIMAGES72            401

#define IDB_STANDARDIMAGES120           402

//Image indices inside the standard bitmap.

#define TOOLIMAGE_MIN                   0

#define TOOLIMAGE_EDITCUT               0

#define TOOLIMAGE_EDITCOPY              1

#define TOOLIMAGE_EDITPASTE             2

#define TOOLIMAGE_FILENEW               3

#define TOOLIMAGE_FILEOPEN              4

#define TOOLIMAGE_FILESAVE              5

#define TOOLIMAGE_FILEPRINT             6

#define TOOLIMAGE_HELP                  7

#define TOOLIMAGE_HELPCONTEXT           8

#define TOOLIMAGE_MAX                   8

//Additional Standard Cursors as defined in the UI Design Guide.

#define IDC_NEWUICURSORMIN              500

#define IDC_RIGHTARROW                  500

#define IDC_CONTEXTHELP                 501

#define IDC_MAGNIFY                     502

#define IDC_NODROP                      503

#define IDC_TABLETOP                    504

#define IDC_HSIZEBAR                    505

#define IDC_VSIZEBAR                    506

#define IDC_HSPLITBAR                   507

#define IDC_VSPLITBAR                   508

#define IDC_SMALLARROWS                 509

#define IDC_LARGEARROWS                 510

#define IDC_HARROWS                     511

#define IDC_VARROWS                     512

#define IDC_NESWARROWS                  513

#define IDC_NWSEARROWS                  514

#define IDC_NEWUICURSORMAX              514

//Standard sizes for toolbar buttons and bitmaps on display types

//WARNING:  These are obsolete for version 1.0 compatibility/

#define TOOLBUTTON_STDWIDTH             24

#define TOOLBUTTON_STDHEIGHT            22

#define TOOLBUTTON_STDIMAGEWIDTH        16

#define TOOLBUTTON_STDIMAGEHEIGHT       15

/*

 * Applications can call UIToolDisplayData to get the particular

 * values to use for the current display instead of using these values

 * directly.  However, if the application has the aspect ratio already

 * then these are available for them.

 */

//Sizes for 72 DPI (EGA)

#define TOOLBUTTON_STD72WIDTH           24

#define TOOLBUTTON_STD72HEIGHT          16

#define TOOLBUTTON_STD72IMAGEWIDTH      16

#define TOOLBUTTON_STD72IMAGEHEIGHT     11

//Sizes for 96 DPI (VGA)

#define TOOLBUTTON_STD96WIDTH           24

#define TOOLBUTTON_STD96HEIGHT          22

#define TOOLBUTTON_STD96IMAGEWIDTH      16

#define TOOLBUTTON_STD96IMAGEHEIGHT     15

//Sizes for 120 DPI (8514/a)

#define TOOLBUTTON_STD120WIDTH          32

#define TOOLBUTTON_STD120HEIGHT         31

#define TOOLBUTTON_STD120IMAGEWIDTH     24

#define TOOLBUTTON_STD120IMAGEHEIGHT    23

//Sizes of a standard button bar depending on the display

#define CYBUTTONBAR72                   23

#define CYBUTTONBAR96                   29

#define CYBUTTONBAR120                  38

/*

 * The low-word of the state contains the display state where each

 * value is mutually exclusive and contains one or more grouping bits.

 * Each group represents buttons that share some sub-state in common.

 *

 * The high-order byte controls which colors in the source bitmap,

 * black, white, gray, and dark gray, are to be converted into the

 * system colors COLOR_BTNTEXT, COLOR_HILIGHT, COLOR_BTNFACE, and

 * COLOR_BTNSHADOW.  Any or all of these bits may be set to allow

 * the application control over specific colors.

 *

 * The actual state values are split into a command group and an

 * attribute group.  Up, mouse down, and disabled states are identical,

 * but only attributes can have down, down disabled, and indeterminate

 * states.

 *

 * BUTTONGROUP_BLANK is defined so an application can draw only the button

 * without an image in the up, down, mouse down, or indeterminate

 * state, that is, BUTTONGROUP_BLANK is inclusive with BUTTONGROUP_DOWN

 * and BUTTONGROUP_LIGHTFACE.

 */

#define BUTTONGROUP_DOWN                0x0001

#define BUTTONGROUP_ACTIVE              0x0002

#define BUTTONGROUP_DISABLED            0x0004

#define BUTTONGROUP_LIGHTFACE           0x0008

#define BUTTONGROUP_BLANK               0x0010

//Command buttons only

#define COMMANDBUTTON_UP                (BUTTONGROUP_ACTIVE)

#define COMMANDBUTTON_MOUSEDOWN         (BUTTONGROUP_ACTIVE | BUTTONGROUP_DOWN)

#define COMMANDBUTTON_DISABLED          (BUTTONGROUP_DISABLED)

//Attribute buttons only

#define ATTRIBUTEBUTTON_UP              (BUTTONGROUP_ACTIVE)

#define ATTRIBUTEBUTTON_MOUSEDOWN       (BUTTONGROUP_ACTIVE | BUTTONGROUP_DOWN)

#define ATTRIBUTEBUTTON_DISABLED        (BUTTONGROUP_DISABLED)

#define ATTRIBUTEBUTTON_DOWN            (BUTTONGROUP_ACTIVE | BUTTONGROUP_DOWN | BUTTONGROUP_LIGHTFACE)

#define ATTRIBUTEBUTTON_INDETERMINATE   (BUTTONGROUP_ACTIVE | BUTTONGROUP_LIGHTFACE)

#define ATTRIBUTEBUTTON_DOWNDISABLED    (BUTTONGROUP_DISABLED | BUTTONGROUP_DOWN | BUTTONGROUP_LIGHTFACE)

//Blank buttons only

#define BLANKBUTTON_UP                  (BUTTONGROUP_ACTIVE | BUTTONGROUP_BLANK)

#define BLANKBUTTON_DOWN                (BUTTONGROUP_ACTIVE | BUTTONGROUP_BLANK | BUTTONGROUP_DOWN | BUTTONGROUP_LIGHTFACE)

#define BLANKBUTTON_MOUSEDOWN           (BUTTONGROUP_ACTIVE | BUTTONGROUP_BLANK | BUTTONGROUP_DOWN)

#define BLANKBUTTON_INDETERMINATE       (BUTTONGROUP_ACTIVE | BUTTONGROUP_BLANK | BUTTONGROUP_LIGHTFACE)

/*

 * Specific bits to prevent conversions of specific colors to system

 * colors.  If an application uses this newer library and never specified

 * any bits, then they benefit from color conversion automatically.

 */

#define PRESERVE_BLACK                  0x0100

#define PRESERVE_DKGRAY                 0x0200

#define PRESERVE_LTGRAY                 0x0400

#define PRESERVE_WHITE                  0x0800

#define PRESERVE_ALL                    (PRESERVE_BLACK | PRESERVE_DKGRAY | PRESERVE_LTGRAY | PRESERVE_WHITE)

#define PRESERVE_NONE                   0   //Backwards compatible

//Structure for UIToolConfigureForDisplay

typedef struct tagTOOLDISPLAYDATA

{

UINT        uDPI;       //Display driver DPI

UINT        cyBar;      //Vertical size for a bar containing buttons.

UINT        cxButton;   //Dimensions of a button.

UINT        cyButton;

UINT        cxImage;    //Dimensions of bitmap image

UINT        cyImage;

UINT        uIDImages;  //Standard resource ID for display-sensitive images

} TOOLDISPLAYDATA, FAR *LPTOOLDISPLAYDATA;

//Public functions in BTTNCUR.DLL

HCURSOR WINAPI UICursorLoad(UINT);

BOOL    WINAPI UIToolConfigureForDisplay(LPTOOLDISPLAYDATA);

BOOL    WINAPI UIToolButtonDraw(HDC, int, int, int, int, HBITMAP, int, int, int, UINT);

BOOL    WINAPI UIToolButtonDrawTDD(HDC, int, int, int, int, HBITMAP, int, int, int, UINT, LPTOOLDISPLAYDATA);

#ifdef __cplusplus

}

#endif

#endif //_BTTNCUR_H_


GIZMOBAR.H  (INCLUDE Sample)

/*

 * GIZMOBAR.H

 * GizmoBar Version 1.01

 *

 * Public definitions for application that use the GizmoBar such as

 * messages, prototypes for API functions, notification codes, and

 * control styles.

 *

 * Copyright (c)1993-1994 Microsoft Corporation, All Rights Reserved

 *

 * Kraig Brockschmidt, Software Design Engineer

 * Microsoft Systems Developer Relations

 *

 * Internet  :  kraigb@microsoft.com

 * Compuserve:  >INTERNET:kraigb@microsoft.com

 */

#ifndef _GIZMOBAR_H_

#define _GIZMOBAR_H_

#include <bttncur.h>

#ifdef __cplusplus

extern "C"

    {

#endif

//Classname

#define CLASS_GIZMOBAR  TEXT("gizmobar")

//Message API Functions

HWND    WINAPI GBHwndAssociateSet(HWND, HWND);

HWND    WINAPI GBHwndAssociateGet(HWND);

BOOL    WINAPI GBGizmoAddW(HWND, UINT, UINT, UINT, UINT, UINT, LPWSTR , HBITMAP, UINT, UINT);

BOOL    WINAPI GBGizmoAddA(HWND, UINT, UINT, UINT, UINT, UINT, LPSTR , HBITMAP, UINT, UINT);

int     WINAPI GBGizmoTextGetW(HWND, UINT, LPWSTR, UINT);

int     WINAPI GBGizmoTextGetA(HWND, UINT, LPSTR, UINT);

void    WINAPI GBGizmoTextSetW(HWND, UINT, LPWSTR);

void    WINAPI GBGizmoTextSetA(HWND, UINT, LPSTR);

#ifdef UNICODE

#define GBGizmoAdd      GBGizmoAddW

#define GBGizmoTextGet  GBGizmoTextGetW

#define GBGizmoTextSet  GBGizmoTextSetW

#else

#define GBGizmoAdd      GBGizmoAddA

#define GBGizmoTextGet  GBGizmoTextGetA

#define GBGizmoTextSet  GBGizmoTextSetA

#endif

BOOL    WINAPI GBGizmoRemove(HWND, UINT);

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

BOOL    WINAPI GBGizmoShow(HWND, UINT, BOOL);

BOOL    WINAPI GBGizmoEnable(HWND, UINT, BOOL);

BOOL    WINAPI GBGizmoCheck(HWND, UINT, BOOL);

UINT    WINAPI GBGizmoFocusSet(HWND, UINT);

BOOL    WINAPI GBGizmoExist(HWND, UINT);

int     WINAPI GBGizmoTypeGet(HWND, UINT);

DWORD   WINAPI GBGizmoDataSet(HWND, UINT, DWORD);

DWORD   WINAPI GBGizmoDataGet(HWND, UINT);

BOOL    WINAPI GBGizmoNotifySet(HWND, UINT, BOOL);

BOOL    WINAPI GBGizmoNotifyGet(HWND, UINT);

UINT    WINAPI GBGizmoIntGet(HWND, UINT, BOOL FAR *, BOOL);

void    WINAPI GBGizmoIntSet(HWND, UINT, UINT, BOOL);

//Notification codes sent via WM_COMMAND from GBHwndAssociateSet

#define GBN_ASSOCIATEGAIN               1

#define GBN_ASSOCIATELOSS               2

#define GBN_GIZMOADDED                  3

#define GBN_GIZMOREMOVED                4

//Message equivalents for functions.

#define GBM_HWNDASSOCIATESET            (WM_USER+0)

#define GBM_HWNDASSOCIATEGET            (WM_USER+1)

#define GBM_GIZMOADDW                   (WM_USER+2)

#define GBM_GIZMOADDA                   (WM_USER+3)

#define GBM_GIZMOREMOVE                 (WM_USER+4)

#define GBM_GIZMOSENDMESSAGE            (WM_USER+5)

#define GBM_GIZMOSHOW                   (WM_USER+6)

#define GBM_GIZMOENABLE                 (WM_USER+7)

#define GBM_GIZMOCHECK                  (WM_USER+8)

#define GBM_GIZMOFOCUSSET               (WM_USER+9)

#define GBM_GIZMOEXIST                  (WM_USER+10)

#define GBM_GIZMOTYPEGET                (WM_USER+11)

#define GBM_GIZMODATASET                (WM_USER+12)

#define GBM_GIZMODATAGET                (WM_USER+13)

#define GBM_GIZMONOTIFYSET              (WM_USER+14)

#define GBM_GIZMONOTIFYGET              (WM_USER+15)

#define GBM_GIZMOTEXTGETA               (WM_USER+16)

#define GBM_GIZMOTEXTGETW               (WM_USER+17)

#define GBM_GIZMOTEXTSETA               (WM_USER+18)

#define GBM_GIZMOTEXTSETW               (WM_USER+19)

#define GBM_GIZMOINTGET                 (WM_USER+20)

#define GBM_GIZMOINTSET                 (WM_USER+21)

#ifdef UNICODE

#define GBM_GIZMOTEXTGET GBM_GIZMOTEXTGETW

#define GBM_GIZMOTEXTSET GBM_GIZMOTEXTSETW

#define GBM_GIZMOADD GBM_GIZMOADDW

#else

#define GBM_GIZMOTEXTGET GBM_GIZMOTEXTGETA

#define GBM_GIZMOTEXTSET GBM_GIZMOTEXTSETA

#define GBM_GIZMOADD GBM_GIZMOADDA

#endif

/*

 * Structure passed in lParam of GBM_GIZMOADD that mirrors the

 * parameters to GBGizmoAdd.

 */

typedef struct

    {

    HWND        hWndParent;         //Parent window

    UINT        iType;              //Type of gizmo

    UINT        iGizmo;             //Position to create gizmo

    UINT        uID;                //Identifier of gizmo

    UINT        dx;                 //Dimensions of gizmo

    UINT        dy;

    LPSTR       pszText;            //Gizmo text

    HBITMAP     hBmp;               //Source of gizmo button image.

    UINT        iImage;             //Index of image from hBmp

    UINT        uState;             //Initial state of the gizmo.

    } CREATEGIZMOA, FAR *LPCREATEGIZMOA;

typedef struct

    {

    HWND        hWndParent;         //Parent window

    UINT        iType;              //Type of gizmo

    UINT        iGizmo;             //Position to create gizmo

    UINT        uID;                //Identifier of gizmo

    UINT        dx;                 //Dimensions of gizmo

    UINT        dy;

    LPWSTR      pszText;            //Gizmo text

    HBITMAP     hBmp;               //Source of gizmo button image.

    UINT        iImage;             //Index of image from hBmp

    UINT        uState;             //Initial state of the gizmo.

    } CREATEGIZMOW, FAR *LPCREATEGIZMOW;

#ifdef UNICODE

typedef CREATEGIZMOW    CREATEGIZMO;

typedef LPCREATEGIZMOW  LPCREATEGIZMO;

#define CBCREATEGIZMO sizeof(CREATEGIZMOW)

#else

typedef CREATEGIZMOA    CREATEGIZMO;

typedef LPCREATEGIZMOA  LPCREATEGIZMO;

#define CBCREATEGIZMO sizeof(CREATEGIZMOA)

#endif

//For GBM_GIZMOSENDMESSAGE

typedef struct

    {

    UINT        iMsg;

    WPARAM      wParam;

    LPARAM      lParam;

    } GBMSG, FAR * LPGBMSG;

#define CBGBMSG sizeof(GBMSG);

//For GBM_GIZMOGETTEXT

typedef struct

    {

    LPSTR       psz;

    UINT        cch;

    } GBGETTEXTA, FAR * LPGBGETTEXTA;

typedef struct

    {

    LPWSTR      psz;

    UINT        cch;

    } GBGETTEXTW, FAR * LPGBGETTEXTW;

#ifdef UNICODE

typedef GBGETTEXTW  GBGETTEXT;

typedef LPGBGETTEXTW  LPGBGETTEXT;

#define CBGBGETTEXT sizeof(GBGETTEXTW);

#else

typedef GBGETTEXTA  GBGETTEXT;

typedef LPGBGETTEXTA  LPGBGETTEXT;

#define CBGBGETTEXT sizeof(GBGETTEXTA);

#endif

//For GBM_GIZMOGETINT

typedef struct

    {

    BOOL        fSigned;

    BOOL        fSuccess;

    } GBGETINT, FAR * LPGBGETINT;

#define CBGBGETINT sizeof(GBGETINT);

//For GBM_GIZMOSETINT

typedef struct

    {

    UINT        uValue;

    BOOL        fSigned;

    } GBSETINT, FAR * LPGBSETINT;

#define CBGBSETINT sizeof(GBSETINT);

//Gizmo control types.  DO NOT CHANGE THESE!

#define GIZMOTYPE_EDIT                  0x0001

#define GIZMOTYPE_LISTBOX               0x0002

#define GIZMOTYPE_COMBOBOX              0x0004

#define GIZMOTYPE_BUTTONNORMAL          0x0008

#define GIZMOTYPE_TEXT                  0x0010

#define GIZMOTYPE_SEPARATOR             0x0020

#define GIZMOTYPE_BUTTONATTRIBUTEIN     0x0040

#define GIZMOTYPE_BUTTONATTRIBUTEEX     0x0080

#define GIZMOTYPE_BUTTONCOMMAND         0x0100

//Generic state flags for non-buttons based on BTTNCUR.H's groups.

#define GIZMO_NORMAL                    (BUTTONGROUP_ACTIVE)

#define GIZMO_DISABLED                  (BUTTONGROUP_DISABLED)

#ifdef __cplusplus

    }   //Match with extern "C" above.

#endif

#endif //_GIZMOBAR_H_


MSGFILTR.H  (INCLUDE Sample)

/*************************************************************************

**

**    OLE 2 Utility Code

**

**    msgfiltr.h

**

**    This file contains Private definitions, structures, types, and

**    function prototypes for the OleStdMessageFilter implementation of

**    the IMessageFilter interface.

**    This file is part of the OLE 2.0 User Interface support library.

**

**    (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved

**

*************************************************************************/

#if !defined( _MSGFILTR_H_ )

#define _MSGFILTR_H_

#ifndef RC_INVOKED

#pragma message ("INCLUDING MSGFILTR.H from " __FILE__)

#endif  /* RC_INVOKED */

#include "ansiapi.h"

// Message Pending callback procedure

typedef BOOL (CALLBACK* MSGPENDINGPROC)(MSG FAR *);

// HandleInComingCall callback procedure

typedef DWORD (CALLBACK* HANDLEINCOMINGCALLBACKPROC)

   (

      DWORD               dwCallType,

      HTASK               htaskCaller,

      DWORD               dwTickCount,

      LPINTERFACEINFO     lpInterfaceInfo

   );

/* PUBLIC FUNCTIONS */

STDAPI_(LPMESSAGEFILTER) OleStdMsgFilter_Create(

      HWND hWndParent,

      LPOLESTR szAppName,

      MSGPENDINGPROC lpfnCallback,

      LPFNOLEUIHOOK  lpfnOleUIHook         // Busy dialog hook callback

);

STDAPI_(void) OleStdMsgFilter_SetInComingCallStatus(

      LPMESSAGEFILTER lpThis, DWORD dwInComingCallStatus);

STDAPI_(DWORD) OleStdMsgFilter_GetInComingCallStatus(

      LPMESSAGEFILTER lpThis);

STDAPI_(HANDLEINCOMINGCALLBACKPROC)

   OleStdMsgFilter_SetHandleInComingCallbackProc(

      LPMESSAGEFILTER             lpThis,

      HANDLEINCOMINGCALLBACKPROC  lpfnHandleInComingCallback);

STDAPI_(BOOL) OleStdMsgFilter_EnableBusyDialog(

      LPMESSAGEFILTER lpThis, BOOL fEnable);

STDAPI_(BOOL) OleStdMsgFilter_EnableNotRespondingDialog(

      LPMESSAGEFILTER lpThis, BOOL fEnable);

STDAPI_(HWND) OleStdMsgFilter_SetParentWindow(

      LPMESSAGEFILTER lpThis, HWND hWndParent);

#endif // _MSGFILTR_H_


OLE2UI.H  (INCLUDE Sample)

/*

 * OLE2UI.H

 *

 * Published definitions, structures, types, and function prototypes for the

 * OLE 2.0 User Interface support library.

 *

 * Copyright (c)1993 Microsoft Corporation, All Rights Reserved

 */

/* NOTE: All dialog and string resource ID's defined in this file are

 *    in the range:

 *          32248 - 32504   (0x7DF8 - 0x7EF8)

*/

#ifndef _OLE2UI_H_

#define _OLE2UI_H_

#if !defined(__cplusplus) && !defined( __TURBOC__)

#define NONAMELESSUNION     // use strict ANSI standard (for DVOBJ.H)

#endif

#include <windows.h>

#include <shellapi.h>

#include <ole2.h>

#include <string.h>

#include <dlgs.h>           //For fileopen dlg; standard include

#include "ansiapi.h"

/*************************************************************************

** DEBUG ASSERTION ROUTINES

*************************************************************************/

#if DBG

#include <assert.h>

#define FnAssert(lpstrExpr, lpstrMsg, lpstrFileName, iLine)     \

        (_assert(lpstrMsg ? lpstrMsg : lpstrExpr,               \

                 lpstrFileName,                                 \

                 iLine), NOERROR)

#endif //DBG

#include "olestd.h"

#ifdef __TURBOC__

#define _getcwd getcwd

#define _itoa   itoa

#define __max   max

#define _find_t find_t

#endif // __TURBOC__

#ifdef WIN32

#define _fmemset memset

#define _fmemcpy memcpy

#define _fmemcmp memcmp

#define _fstrcpy strcpy

#define _fstrncpy strncpy

#define _fstrlen strlen

#define _fstrrchr strrchr

#define _fstrtok strtok

// BUGBUG32: isspace function does not seem to work properly

#undef isspace

#define isspace(j) (j==' ' || j=='\t' || j=='\n')

#endif  // WIN32

#if !defined( EXPORT )

#ifdef WIN32

#define EXPORT

#else

#define EXPORT  __export

#endif  // WIN32

#endif  // !EXPORT

/*

 * Initialization / Uninitialization routines.  OleUIInitialize

 * must be called prior to using any functions in OLE2UI, and OleUIUnInitialize

 * must be called before you app shuts down and when you are done using the

 * library.

 *

 * NOTE:  If you are using the DLL version of this library, these functions

 * are automatically called in the DLL's LibMain and WEP, so you should

 * not call them directly from your application.

 */

// Backward compatibility with older library

#define OleUIUninitialize OleUIUnInitialize

STDAPI_(BOOL) OleUIInitialize(HINSTANCE hInstance, HINSTANCE hPrevInst);

STDAPI_(BOOL) OleUIUninitialize(void);

#if !defined( SZCLASSICONBOX )

#define SZCLASSICONBOX  "ole2uiIBCls"

#endif

#if !defined( SZCLASSRESULTIMAGE )

#define SZCLASSRESULTIMAGE  "ole2uiRICls"

#endif

// object count, used to support DllCanUnloadNow and OleUICanUnloadNow

extern DWORD g_dwObjectCount;

STDAPI OleUICanUnloadNow(void);

STDAPI OleUILockLibrary(BOOL fLock);

//Dialog Identifiers as passed in Help messages to identify the source.

#define IDD_INSERTOBJECT        32248

#define IDD_CHANGEICON          32249

#define IDD_CONVERT             32250

#define IDD_PASTESPECIAL        32251

#define IDD_EDITLINKS           32252

#define IDD_FILEOPEN            32253

#define IDD_BUSY                32254

#define IDD_UPDATELINKS         32255

#define IDD_CANNOTUPDATELINK    32256

#define IDD_CHANGESOURCE        32257

#define IDD_INSERTFILEBROWSE    32258

#define IDD_CHANGEICONBROWSE    32259

// The following Dialogs are message dialogs used by OleUIPromptUser API

#define IDD_LINKSOURCEUNAVAILABLE   32260

#define IDD_SERVERNOTREG        32261

#define IDD_LINKTYPECHANGED     32262

#define IDD_SERVERNOTFOUND      32263

#define IDD_OUTOFMEMORY         32264

// Stringtable identifers

#define IDS_OLE2UIUNKNOWN       32300

#define IDS_OLE2UILINK          32301

#define IDS_OLE2UIOBJECT        32302

#define IDS_OLE2UIEDIT          32303

#define IDS_OLE2UICONVERT       32304

#define IDS_OLE2UIEDITLINKCMD_1VERB     32305

#define IDS_OLE2UIEDITOBJECTCMD_1VERB   32306

#define IDS_OLE2UIEDITLINKCMD_NVERB     32307

#define IDS_OLE2UIEDITOBJECTCMD_NVERB   32308

#define IDS_OLE2UIEDITNOOBJCMD  32309

// def. icon label (usu. "Document")

#define IDS_DEFICONLABEL        32310

#define IDS_OLE2UIPASTELINKEDTYPE  32311

#define IDS_FILTERS             32320

#define IDS_ICONFILTERS         32321

#define IDS_BROWSE              32322

//Resource identifiers for bitmaps

#define IDB_RESULTSEGA                  32325

#define IDB_RESULTSVGA                  32326

#define IDB_RESULTSHIRESVGA             32327

//Missing from windows.h

#ifndef PVOID

typedef VOID *PVOID;

#endif

//Hook type used in all structures.

typedef UINT (CALLBACK *LPFNOLEUIHOOK)(HWND, UINT, WPARAM, LPARAM);

//Strings for registered messages

#define SZOLEUI_MSG_HELP                "OLEUI_MSG_HELP"

#define SZOLEUI_MSG_ENDDIALOG           "OLEUI_MSG_ENDDIALOG"

#define SZOLEUI_MSG_BROWSE              "OLEUI_MSG_BROWSE"

#define SZOLEUI_MSG_CHANGEICON          "OLEUI_MSG_CHANGEICON"

#define SZOLEUI_MSG_CLOSEBUSYDIALOG     "OLEUI_MSG_CLOSEBUSYDIALOG"

#define SZOLEUI_MSG_FILEOKSTRING        "OLEUI_MSG_FILEOKSTRING"

//Standard error definitions

#define OLEUI_FALSE                     0

#define OLEUI_SUCCESS                   1     //No error, same as OLEUI_OK

#define OLEUI_OK                        1     //OK button pressed

#define OLEUI_CANCEL                    2     //Cancel button pressed

#define OLEUI_ERR_STANDARDMIN           100

#define OLEUI_ERR_STRUCTURENULL         101   //Standard field validation

#define OLEUI_ERR_STRUCTUREINVALID      102

#define OLEUI_ERR_CBSTRUCTINCORRECT     103

#define OLEUI_ERR_HWNDOWNERINVALID      104

#define OLEUI_ERR_LPSZCAPTIONINVALID    105

#define OLEUI_ERR_LPFNHOOKINVALID       106

#define OLEUI_ERR_HINSTANCEINVALID      107

#define OLEUI_ERR_LPSZTEMPLATEINVALID   108

#define OLEUI_ERR_HRESOURCEINVALID      109

#define OLEUI_ERR_FINDTEMPLATEFAILURE   110   //Initialization errors

#define OLEUI_ERR_LOADTEMPLATEFAILURE   111

#define OLEUI_ERR_DIALOGFAILURE         112

#define OLEUI_ERR_LOCALMEMALLOC         113

#define OLEUI_ERR_GLOBALMEMALLOC        114

#define OLEUI_ERR_LOADSTRING            115

#define OLEUI_ERR_STANDARDMAX           116   //Start here for specific errors.

//Help Button Identifier

#define ID_OLEUIHELP                    99

// Help button for fileopen.dlg  (need this for resizing) 1038 is pshHelp

#define IDHELP  1038

// Static text control (use this instead of -1 so things work correctly for

// localization

#define  ID_STATIC                      98

//Maximum key size we read from the RegDB.

#define OLEUI_CCHKEYMAX                 256  // make any changes to this in geticon.c too

//Maximum verb length and length of Object menu

#define OLEUI_CCHVERBMAX                32

#define OLEUI_OBJECTMENUMAX             256

//Maximum MS-DOS pathname.

#define OLEUI_CCHPATHMAX                256 // make any changes to this in geticon.c too

#define OLEUI_CCHFILEMAX                13

//Icon label length

#define OLEUI_CCHLABELMAX               40  // make any changes to this in geticon.c too

//Length of the CLSID string

#define OLEUI_CCHCLSIDSTRING            39

/*

 * What follows here are first function prototypes for general utility

 * functions, then sections laid out by dialog.  Each dialog section

 * defines the dialog structure, the API prototype, flags for the dwFlags

 * field, the dialog-specific error values, and dialog control IDs (for

 * hooks and custom templates.

 */

//Miscellaneous utility functions.

STDAPI_(BOOL) OleUIAddVerbMenu(LPOLEOBJECT lpOleObj,

                      LPOLESTR lpszShortType,

                      HMENU hMenu,

                      UINT uPos,

                      UINT uIDVerbMin,

                      UINT uIDVerbMax,

                      BOOL bAddConvert,

                      UINT idConvert,

                      HMENU FAR *lphMenu);

//Metafile utility functions

WINOLEAPI_(HGLOBAL) OleUIMetafilePictFromIconAndLabel(HICON, LPOLESTR, LPOLESTR, UINT);

STDAPI_(void)    OleUIMetafilePictIconFree(HGLOBAL);

STDAPI_(BOOL)    OleUIMetafilePictIconDraw(HDC, LPRECT, HGLOBAL, BOOL);

STDAPI_(UINT)    OleUIMetafilePictExtractLabel(HGLOBAL, LPOLESTR, UINT, LPDWORD);

STDAPI_(HICON)   OleUIMetafilePictExtractIcon(HGLOBAL);

STDAPI_(BOOL)    OleUIMetafilePictExtractIconSource(HGLOBAL,LPOLESTR,UINT FAR *);

/*************************************************************************

** INSERT OBJECT DIALOG

*************************************************************************/

typedef struct tagOLEUIINSERTOBJECT

   {

   //These IN fields are standard across all OLEUI dialog functions.

   DWORD           cbStruct;         //Structure Size

   DWORD           dwFlags;          //IN-OUT:  Flags

   HWND            hWndOwner;        //Owning window

   LPCOLESTR       lpszCaption;      //Dialog caption bar contents

   LPFNOLEUIHOOK   lpfnHook;         //Hook callback

   LPARAM          lCustData;        //Custom data to pass to hook

   HINSTANCE       hInstance;        //Instance for customized template name

   LPCOLESTR       lpszTemplate;     //Customized template name

   HRSRC           hResource;        //Customized template handle

   //Specifics for OLEUIINSERTOBJECT.  All are IN-OUT unless otherwise spec.

   CLSID           clsid;            //Return space for class ID

   LPOLESTR        lpszFile;         //Filename for inserts or links

   UINT            cchFile;          //Size of lpszFile buffer: OLEUI_CCHPATHMAX

   UINT            cClsidExclude;    //IN only:  CLSIDs in lpClsidExclude

   LPCLSID         lpClsidExclude;   //List of CLSIDs to exclude from listing.

   //Specific to create objects if flags say so

   IID             iid;              //Requested interface on creation.

   DWORD           oleRender;        //Rendering option

   LPFORMATETC     lpFormatEtc;      //Desired format

   LPOLECLIENTSITE lpIOleClientSite; //Site to be use for the object.

   LPSTORAGE       lpIStorage;       //Storage used for the object

   LPVOID FAR     *ppvObj;           //Where the object is returned.

   SCODE           sc;               //Result of creation calls.

   HGLOBAL         hMetaPict;        //OUT: METAFILEPICT containing iconic aspect.

                             //IFF we couldn't stuff it in the cache.

   } OLEUIINSERTOBJECT, *POLEUIINSERTOBJECT, FAR *LPOLEUIINSERTOBJECT;

//API prototype

STDAPI_(UINT) OleUIInsertObject(LPOLEUIINSERTOBJECT);

//Insert Object flags

#define IOF_SHOWHELP                0x00000001L

#define IOF_SELECTCREATENEW         0x00000002L

#define IOF_SELECTCREATEFROMFILE    0x00000004L

#define IOF_CHECKLINK               0x00000008L

#define IOF_CHECKDISPLAYASICON      0x00000010L

#define IOF_CREATENEWOBJECT         0x00000020L

#define IOF_CREATEFILEOBJECT        0x00000040L

#define IOF_CREATELINKOBJECT        0x00000080L

#define IOF_DISABLELINK             0x00000100L

#define IOF_VERIFYSERVERSEXIST      0x00000200L

#define IOF_DISABLEDISPLAYASICON    0x00000400L

//Insert Object specific error codes

#define OLEUI_IOERR_LPSZFILEINVALID         (OLEUI_ERR_STANDARDMAX+0)

#define OLEUI_IOERR_LPSZLABELINVALID        (OLEUI_ERR_STANDARDMAX+1)

#define OLEUI_IOERR_HICONINVALID            (OLEUI_ERR_STANDARDMAX+2)

#define OLEUI_IOERR_LPFORMATETCINVALID      (OLEUI_ERR_STANDARDMAX+3)

#define OLEUI_IOERR_PPVOBJINVALID           (OLEUI_ERR_STANDARDMAX+4)

#define OLEUI_IOERR_LPIOLECLIENTSITEINVALID (OLEUI_ERR_STANDARDMAX+5)

#define OLEUI_IOERR_LPISTORAGEINVALID       (OLEUI_ERR_STANDARDMAX+6)

#define OLEUI_IOERR_SCODEHASERROR           (OLEUI_ERR_STANDARDMAX+7)

#define OLEUI_IOERR_LPCLSIDEXCLUDEINVALID   (OLEUI_ERR_STANDARDMAX+8)

#define OLEUI_IOERR_CCHFILEINVALID          (OLEUI_ERR_STANDARDMAX+9)

//Insert Object Dialog identifiers

#define ID_IO_CREATENEW                 2100

#define ID_IO_CREATEFROMFILE            2101

#define ID_IO_LINKFILE                  2102

#define ID_IO_OBJECTTYPELIST            2103

#define ID_IO_DISPLAYASICON             2104

#define ID_IO_CHANGEICON                2105

#define ID_IO_FILE                      2106

#define ID_IO_FILEDISPLAY               2107

#define ID_IO_RESULTIMAGE               2108

#define ID_IO_RESULTTEXT                2109

#define ID_IO_ICONDISPLAY               2110

#define ID_IO_OBJECTTYPETEXT            2111

#define ID_IO_FILETEXT                  2112

#define ID_IO_FILETYPE                  2113

// Strings in OLE2UI resources

#define IDS_IORESULTNEW                 32400

#define IDS_IORESULTNEWICON             32401

#define IDS_IORESULTFROMFILE1           32402

#define IDS_IORESULTFROMFILE2           32403

#define IDS_IORESULTFROMFILEICON2       32404

#define IDS_IORESULTLINKFILE1           32405

#define IDS_IORESULTLINKFILE2           32406

#define IDS_IORESULTLINKFILEICON1       32407

#define IDS_IORESULTLINKFILEICON2       32408

/*************************************************************************

** PASTE SPECIAL DIALOG

*************************************************************************/

// Maximum number of link types

#define     PS_MAXLINKTYPES  8

//NOTE: OLEUIPASTEENTRY and OLEUIPASTEFLAG structs are defined in OLESTD.H

typedef struct tagOLEUIPASTESPECIAL

   {

   //These IN fields are standard across all OLEUI dialog functions.

   DWORD           cbStruct;       //Structure Size

   DWORD           dwFlags;        //IN-OUT:  Flags

   HWND            hWndOwner;      //Owning window

   LPCOLESTR       lpszCaption;    //Dialog caption bar contents

   LPFNOLEUIHOOK   lpfnHook;       //Hook callback

   LPARAM          lCustData;      //Custom data to pass to hook

   HINSTANCE       hInstance;      //Instance for customized template name

   LPCOLESTR       lpszTemplate;   //Customized template name

   HRSRC           hResource;      //Customized template handle

   //Specifics for OLEUIPASTESPECIAL.

   //IN  fields

   LPDATAOBJECT    lpSrcDataObj;       //Source IDataObject* (on the

                              // clipboard) for data to paste

   LPOLEUIPASTEENTRY arrPasteEntries;  //OLEUIPASTEENTRY array which

                              // specifies acceptable formats. See

                              // OLEUIPASTEENTRY for more info.

   int             cPasteEntries;      //No. of OLEUIPASTEENTRY array entries

   UINT        FAR *arrLinkTypes;      //List of link types that are

                              // acceptable. Link types are referred

                              // to using OLEUIPASTEFLAGS in

                              // arrPasteEntries

   int             cLinkTypes;         //Number of link types

   UINT            cClsidExclude;      //Number of CLSIDs in lpClsidExclude

   LPCLSID         lpClsidExclude;     //List of CLSIDs to exclude from list.

   //OUT fields

   int             nSelectedIndex;     //Index of arrPasteEntries[] that the

                              // user selected

   BOOL            fLink;              //Indicates if Paste or Paste Link was

                              // selected by the user

   HGLOBAL         hMetaPict;          //Handle to Metafile containing icon

                              // and icon title selected by the user

                              // Use the Metafile utility functions

                              // defined in this header to

                              // manipulate hMetaPict

   SIZEL           sizel;              // size of object/link in its source

                              //  if the display aspect chosen by

                              //  the user matches the aspect

                              //  displayed in the source. if

                              //  different aspect is chosen then

                              //  sizel.cx=sizel.cy=0 is returned.

                              //  sizel displayed in source is

                              //  retrieved from the

                              //  ObjectDescriptor if fLink is FALSE

                              //  LinkSrcDescriptor if fLink is TRUE

   } OLEUIPASTESPECIAL, *POLEUIPASTESPECIAL, FAR *LPOLEUIPASTESPECIAL;

//API to bring up PasteSpecial dialog

STDAPI_(UINT) OleUIPasteSpecial(LPOLEUIPASTESPECIAL);

//Paste Special flags

// Show Help button. IN flag.

#define PSF_SHOWHELP                0x00000001L

//Select Paste radio button at dialog startup. This is the default if

// PSF_SELECTPASTE or PSF_SELECTPASTELINK are not specified. Also specifies

// state of button on dialog termination. IN/OUT flag.

#define PSF_SELECTPASTE             0x00000002L

//Select PasteLink radio button at dialog startup. Also specifies state of

// button on dialog termination. IN/OUT flag.

#define PSF_SELECTPASTELINK         0x00000004L

//Specfies if DisplayAsIcon button was checked on dialog termination. OUT flag

#define PSF_CHECKDISPLAYASICON      0x00000008L

#define PSF_DISABLEDISPLAYASICON    0x00000010L

//Paste Special specific error codes

#define OLEUI_IOERR_SRCDATAOBJECTINVALID      (OLEUI_ERR_STANDARDMAX+0)

#define OLEUI_IOERR_ARRPASTEENTRIESINVALID    (OLEUI_ERR_STANDARDMAX+1)

#define OLEUI_IOERR_ARRLINKTYPESINVALID       (OLEUI_ERR_STANDARDMAX+2)

#define OLEUI_PSERR_CLIPBOARDCHANGED          (OLEUI_ERR_STANDARDMAX+3)

//Paste Special Dialog identifiers

#define ID_PS_PASTE                    500

#define ID_PS_PASTELINK                501

#define ID_PS_SOURCETEXT               502

#define ID_PS_PASTELIST                503

#define ID_PS_PASTELINKLIST            504

#define ID_PS_DISPLAYLIST              505

#define ID_PS_DISPLAYASICON            506

#define ID_PS_ICONDISPLAY              507

#define ID_PS_CHANGEICON               508

#define ID_PS_RESULTIMAGE              509

#define ID_PS_RESULTTEXT               510

#define ID_PS_RESULTGROUP              511

#define ID_PS_STXSOURCE                512

#define ID_PS_STXAS                    513

// Paste Special String IDs

#define IDS_PSPASTEDATA                32410

#define IDS_PSPASTEOBJECT              32411

#define IDS_PSPASTEOBJECTASICON        32412

#define IDS_PSPASTELINKDATA            32413

#define IDS_PSPASTELINKOBJECT          32414

#define IDS_PSPASTELINKOBJECTASICON    32415

#define IDS_PSNONOLE                   32416

#define IDS_PSUNKNOWNTYPE              32417

#define IDS_PSUNKNOWNSRC               32418

#define IDS_PSUNKNOWNAPP               32419

/*************************************************************************

** EDIT LINKS DIALOG

*************************************************************************/

/* IOleUILinkContainer Interface

** -----------------------------

**    This interface must be implemented by container applications that

**    want to use the EditLinks dialog. the EditLinks dialog calls back

**    to the container app to perform the OLE functions to manipulate

**    the links within the container.

*/

#define LPOLEUILINKCONTAINER     IOleUILinkContainer FAR*

#undef  INTERFACE

#define INTERFACE   IOleUILinkContainer

DECLARE_INTERFACE_(IOleUILinkContainer, IUnknown)

{

   //*** IUnknown methods ***/

   STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE;

   STDMETHOD_(ULONG,AddRef) (THIS) PURE;

   STDMETHOD_(ULONG,Release) (THIS) PURE;

   STDMETHOD_(DWORD,GetNextLink) (THIS_ DWORD dwLink) PURE;

   STDMETHOD(SetLinkUpdateOptions) (THIS_ DWORD dwLink, DWORD dwUpdateOpt) PURE;

   STDMETHOD(GetLinkUpdateOptions) (THIS_ DWORD dwLink, DWORD FAR* lpdwUpdateOpt) PURE;

   STDMETHOD(SetLinkSource) (THIS_

         DWORD       dwLink,

         LPOLESTR    lpszDisplayName,

         ULONG       lenFileName,

         ULONG FAR*  pchEaten,

         BOOL        fValidateSource) PURE;

   STDMETHOD(GetLinkSource) (THIS_

         DWORD       dwLink,

         LPOLESTR FAR*  lplpszDisplayName,

         ULONG FAR*  lplenFileName,

         LPOLESTR FAR*  lplpszFullLinkType,

         LPOLESTR FAR*  lplpszShortLinkType,

         BOOL FAR*   lpfSourceAvailable,

         BOOL FAR*   lpfIsSelected) PURE;

   STDMETHOD(OpenLinkSource) (THIS_ DWORD dwLink) PURE;

   STDMETHOD(UpdateLink) (THIS_

         DWORD dwLink,

         BOOL fErrorMessage,

         BOOL fErrorAction) PURE;

   STDMETHOD(CancelLink) (THIS_ DWORD dwLink) PURE;

};

typedef struct tagOLEUIEDITLINKS

   {

   //These IN fields are standard across all OLEUI dialog functions.

   DWORD           cbStruct;       //Structure Size

   DWORD           dwFlags;        //IN-OUT:  Flags

   HWND            hWndOwner;      //Owning window

   LPCOLESTR       lpszCaption;    //Dialog caption bar contents

   LPFNOLEUIHOOK   lpfnHook;       //Hook callback

   LPARAM          lCustData;      //Custom data to pass to hook

   HINSTANCE       hInstance;      //Instance for customized template name

   LPCOLESTR       lpszTemplate;   //Customized template name

   HRSRC           hResource;      //Customized template handle

   //Specifics for OLEUI<STRUCT>.  All are IN-OUT unless otherwise spec.

   LPOLEUILINKCONTAINER lpOleUILinkContainer;  //IN: Interface to manipulate

                                    //links in the container

   } OLEUIEDITLINKS, *POLEUIEDITLINKS, FAR *LPOLEUIEDITLINKS;

//API Prototype

STDAPI_(UINT) OleUIEditLinks(LPOLEUIEDITLINKS);

// Edit Links flags

#define ELF_SHOWHELP                0x00000001L

#define ELF_DISABLEUPDATENOW        0x00000002L

#define ELF_DISABLEOPENSOURCE       0x00000004L

#define ELF_DISABLECHANGESOURCE     0x00000008L

#define ELF_DISABLECANCELLINK       0x00000010L

// Edit Links Dialog identifiers

#define ID_EL_CHANGESOURCE             201

#define ID_EL_AUTOMATIC                202

#define ID_EL_CLOSE                    208

#define ID_EL_CANCELLINK               209

#define ID_EL_UPDATENOW                210

#define ID_EL_OPENSOURCE               211

#define ID_EL_MANUAL                   212

#define ID_EL_LINKSOURCE               216

#define ID_EL_LINKTYPE                 217

#define ID_EL_UPDATE                   218

#define ID_EL_NULL                     -1

#define ID_EL_LINKSLISTBOX             206

#define ID_EL_COL1                     220

#define ID_EL_COL2                     221

#define ID_EL_COL3                     222

/*************************************************************************

** CHANGE ICON DIALOG

*************************************************************************/

typedef struct tagOLEUICHANGEICON

   {

   //These IN fields are standard across all OLEUI dialog functions.

   DWORD           cbStruct;       //Structure Size

   DWORD           dwFlags;        //IN-OUT:  Flags

   HWND            hWndOwner;      //Owning window

   LPCOLESTR       lpszCaption;    //Dialog caption bar contents

   LPFNOLEUIHOOK   lpfnHook;       //Hook callback

   LPARAM          lCustData;      //Custom data to pass to hook

   HINSTANCE       hInstance;      //Instance for customized template name

   LPCOLESTR       lpszTemplate;   //Customized template name

   HRSRC           hResource;      //Customized template handle

   //Specifics for OLEUICHANGEICON.  All are IN-OUT unless otherwise spec.

   HGLOBAL         hMetaPict;      //Current and final image.  Source of the

                           //icon is embedded in the metafile itself.

   CLSID           clsid;          //IN only: class used to get Default icon

   OLECHAR         szIconExe[OLEUI_CCHPATHMAX];

   int             cchIconExe;

   } OLEUICHANGEICON, *POLEUICHANGEICON, FAR *LPOLEUICHANGEICON;

//API prototype

STDAPI_(UINT) OleUIChangeIcon(LPOLEUICHANGEICON);

//Change Icon flags

#define CIF_SHOWHELP                0x00000001L

#define CIF_SELECTCURRENT           0x00000002L

#define CIF_SELECTDEFAULT           0x00000004L

#define CIF_SELECTFROMFILE          0x00000008L

#define CIF_USEICONEXE              0x0000000aL

//Change Icon specific error codes

#define OLEUI_CIERR_MUSTHAVECLSID           (OLEUI_ERR_STANDARDMAX+0)

#define OLEUI_CIERR_MUSTHAVECURRENTMETAFILE (OLEUI_ERR_STANDARDMAX+1)

#define OLEUI_CIERR_SZICONEXEINVALID        (OLEUI_ERR_STANDARDMAX+2)

//Change Icon Dialog identifiers

#define ID_GROUP                    120

#define ID_CURRENT                  121

#define ID_CURRENTICON              122

#define ID_DEFAULT                  123

#define ID_DEFAULTICON              124

#define ID_FROMFILE                 125

#define ID_FROMFILEEDIT             126

#define ID_ICONLIST                 127

#define ID_LABEL                    128

#define ID_LABELEDIT                129

#define ID_BROWSE                   130

#define ID_RESULTICON               132

#define ID_RESULTLABEL              133

// Stringtable defines for Change Icon

#define IDS_CINOICONSINFILE         32430

#define IDS_CIINVALIDFILE           32431

#define IDS_CIFILEACCESS            32432

#define IDS_CIFILESHARE             32433

#define IDS_CIFILEOPENFAIL          32434

/*************************************************************************

** CONVERT DIALOG

*************************************************************************/

typedef struct tagOLEUICONVERT

   {

   //These IN fields are standard across all OLEUI dialog functions.

   DWORD           cbStruct;         //Structure Size

   DWORD           dwFlags;          //IN-OUT:  Flags

   HWND            hWndOwner;        //Owning window

   LPCOLESTR       lpszCaption;      //Dialog caption bar contents

   LPFNOLEUIHOOK   lpfnHook;         //Hook callback

   LPARAM          lCustData;        //Custom data to pass to hook

   HINSTANCE       hInstance;        //Instance for customized template name

   LPCOLESTR       lpszTemplate;     //Customized template name

   HRSRC           hResource;        //Customized template handle

   //Specifics for OLEUICONVERT.  All are IN-OUT unless otherwise spec.

   CLSID           clsid;            //Class ID sent in to dialog: IN only

   CLSID           clsidConvertDefault;  //Class ID to use as convert default: IN only

   CLSID           clsidActivateDefault;  //Class ID to use as activate default: IN only

   CLSID           clsidNew;         //Selected Class ID: OUT only

   DWORD           dvAspect;         //IN-OUT, either DVASPECT_CONTENT or

                             //DVASPECT_ICON

   WORD            wFormat;          //Original data format

   BOOL            fIsLinkedObject;  //IN only; true if object is linked

   HGLOBAL         hMetaPict;        //IN-OUT: METAFILEPICT containing iconic aspect.

   LPOLESTR        lpszUserType;     //IN-OUT: user type name of original class.

                             //  We'll do lookup if it's NULL.

                             //  This gets freed on exit.

   BOOL            fObjectsIconChanged;  // OUT; TRUE if ChangeIcon was called (and not cancelled)

   LPOLESTR        lpszDefLabel;     //IN-OUT: default label to use for icon.

                             //  if NULL, the short user type name

                             //  will be used. if the object is a

                             //  link, the caller should pass the

                             //  DisplayName of the link source

                             //  This gets freed on exit.

   UINT            cClsidExclude;    //IN: No. of CLSIDs in lpClsidExclude

   LPCLSID         lpClsidExclude;   //IN: List of CLSIDs to exclude from list

   } OLEUICONVERT, *POLEUICONVERT, FAR *LPOLEUICONVERT;

//API prototype

STDAPI_(UINT) OleUIConvert(LPOLEUICONVERT);

// Determine if there is at least one class that can Convert or ActivateAs

// the given clsid.

STDAPI_(BOOL) OleUICanConvertOrActivateAs(

      REFCLSID    rClsid,

      BOOL        fIsLinkedObject,

      WORD        wFormat

);

//Convert Dialog flags

// IN only: Shows "HELP" button

#define CF_SHOWHELPBUTTON          0x00000001L

// IN only: lets you set the convert default object - the one that is

// selected as default in the convert listbox.

#define CF_SETCONVERTDEFAULT       0x00000002L

// IN only: lets you set the activate default object - the one that is

// selected as default in the activate listbox.

#define CF_SETACTIVATEDEFAULT       0x00000004L

// IN/OUT: Selects the "Convert To" radio button, is set on exit if

// this button was selected

#define CF_SELECTCONVERTTO         0x00000008L

// IN/OUT: Selects the "Activate As" radio button, is set on exit if

// this button was selected

#define CF_SELECTACTIVATEAS        0x00000010L

#define CF_DISABLEDISPLAYASICON    0x00000020L

#define CF_DISABLEACTIVATEAS       0x00000040L

//Convert specific error codes

#define OLEUI_CTERR_CLASSIDINVALID      (OLEUI_ERR_STANDARDMAX+1)

#define OLEUI_CTERR_DVASPECTINVALID     (OLEUI_ERR_STANDARDMAX+2)

#define OLEUI_CTERR_CBFORMATINVALID     (OLEUI_ERR_STANDARDMAX+3)

#define OLEUI_CTERR_HMETAPICTINVALID    (OLEUI_ERR_STANDARDMAX+4)

#define OLEUI_CTERR_STRINGINVALID       (OLEUI_ERR_STANDARDMAX+5)

//Convert Dialog identifiers

#define IDCV_OBJECTTYPE             150

#define IDCV_DISPLAYASICON          152

#define IDCV_CHANGEICON             153

#define IDCV_ACTIVATELIST           154

#define IDCV_CONVERTTO              155

#define IDCV_ACTIVATEAS             156

#define IDCV_RESULTTEXT             157

#define IDCV_CONVERTLIST            158

#define IDCV_ICON                   159

#define IDCV_ICONLABEL1             160

#define IDCV_ICONLABEL2             161

#define IDCV_STXCURTYPE             162

#define IDCV_GRPRESULT              163

#define IDCV_STXCONVERTTO           164

// String IDs for Convert dialog

#define IDS_CVRESULTCONVERTLINK     32440

#define IDS_CVRESULTCONVERTTO       32441

#define IDS_CVRESULTNOCHANGE        32442

#define IDS_CVRESULTDISPLAYASICON   32443

#define IDS_CVRESULTACTIVATEAS      32444

#define IDS_CVRESULTACTIVATEDIFF    32445

/*************************************************************************

** BUSY DIALOG

*************************************************************************/

typedef struct tagOLEUIBUSY

   {

   //These IN fields are standard across all OLEUI dialog functions.

   DWORD           cbStruct;         //Structure Size

   DWORD           dwFlags;          //IN-OUT:  Flags ** NOTE ** this dialog has no flags

   HWND            hWndOwner;        //Owning window

   LPCOLESTR       lpszCaption;      //Dialog caption bar contents

   LPFNOLEUIHOOK   lpfnHook;         //Hook callback

   LPARAM          lCustData;        //Custom data to pass to hook

   HINSTANCE       hInstance;        //Instance for customized template name

   LPCOLESTR       lpszTemplate;     //Customized template name

   HRSRC           hResource;        //Customized template handle

   //Specifics for OLEUIBUSY.

   HTASK           hTask;            //IN: HTask which is blocking

   HWND FAR *      lphWndDialog;     //IN: Dialog's HWND is placed here

   } OLEUIBUSY, *POLEUIBUSY, FAR *LPOLEUIBUSY;

//API prototype

STDAPI_(UINT) OleUIBusy(LPOLEUIBUSY);

// Flags for this dialog

// IN only: Disables "Cancel" button

#define BZ_DISABLECANCELBUTTON          0x00000001L

// IN only: Disables "Switch To..." button

#define BZ_DISABLESWITCHTOBUTTON        0x00000002L

// IN only: Disables "Retry" button

#define BZ_DISABLERETRYBUTTON           0x00000004L

// IN only: Generates a "Not Responding" dialog as opposed to the

// "Busy" dialog.  The wording in the text is slightly different, and

// the "Cancel" button is grayed out if you set this flag.

#define BZ_NOTRESPONDINGDIALOG          0x00000008L

// Busy specific error/return codes

#define OLEUI_BZERR_HTASKINVALID     (OLEUI_ERR_STANDARDMAX+0)

// SWITCHTOSELECTED is returned when user hit "switch to"

#define OLEUI_BZ_SWITCHTOSELECTED    (OLEUI_ERR_STANDARDMAX+1)

// RETRYSELECTED is returned when user hit "retry"

#define OLEUI_BZ_RETRYSELECTED       (OLEUI_ERR_STANDARDMAX+2)

// CALLUNBLOCKED is returned when call has been unblocked

#define OLEUI_BZ_CALLUNBLOCKED       (OLEUI_ERR_STANDARDMAX+3)

// Busy dialog identifiers

#define IDBZ_RETRY                      600

#define IDBZ_ICON                       601

#define IDBZ_MESSAGE1                   602

#define IDBZ_SWITCHTO                   604

// Busy dialog stringtable defines

#define IDS_BZRESULTTEXTBUSY            32447

#define IDS_BZRESULTTEXTNOTRESPONDING   32448

// Links dialog stringtable defines

#define IDS_LINK_AUTO           32450

#define IDS_LINK_MANUAL         32451

#define IDS_LINK_UNKNOWN        32452

#define IDS_LINKS               32453

#define IDS_FAILED              32454

#define IDS_CHANGESOURCE        32455

#define IDS_INVALIDSOURCE       32456

#define IDS_ERR_GETLINKSOURCE   32457

#define IDS_ERR_GETLINKUPDATEOPTIONS    32458

#define IDS_ERR_ADDSTRING       32459

#define IDS_CHANGEADDITIONALLINKS   32460

#define IDS_CLOSE               32461

/*************************************************************************

** PROMPT USER DIALOGS

*************************************************************************/

#define ID_PU_LINKS             900

#define ID_PU_TEXT              901

#define ID_PU_CONVERT           902

#define ID_PU_BROWSE            904

#define ID_PU_METER             905

#define ID_PU_PERCENT           906

#define ID_PU_STOP              907

// used for -1 ids in dialogs:

#define ID_DUMMY    999

/* inside ole2ui.c */

#ifdef __cplusplus

extern "C"

#endif

int EXPORT FAR CDECL OleUIPromptUser(WORD nTemplate, HWND hwndParent, ...);

#define UPDATELINKS_STARTDELAY  2000    // Delay before 1st link updates

                              //  to give the user a chance to

                              //  dismiss the dialog before any

                              //  links update.

STDAPI_(BOOL) OleUIUpdateLinks(

      LPOLEUILINKCONTAINER lpOleUILinkCntr,

      HWND hwndParent,

      LPOLESTR lpszTitle,

      int cLinks);

/*************************************************************************

** OLE OBJECT FEEDBACK EFFECTS

*************************************************************************/

#define OLEUI_HANDLES_USEINVERSE    0x00000001L

#define OLEUI_HANDLES_NOBORDER      0x00000002L

#define OLEUI_HANDLES_INSIDE        0x00000004L

#define OLEUI_HANDLES_OUTSIDE       0x00000008L

#define OLEUI_SHADE_FULLRECT        1

#define OLEUI_SHADE_BORDERIN        2

#define OLEUI_SHADE_BORDEROUT       3

/* objfdbk.c function prototypes */

STDAPI_(void) OleUIDrawHandles(LPRECT lpRect, HDC hdc, DWORD dwFlags, UINT cSize, BOOL fDraw);

STDAPI_(void) OleUIDrawShading(LPRECT lpRect, HDC hdc, DWORD dwFlags, UINT cWidth);

STDAPI_(void) OleUIShowObject(LPCRECT lprc, HDC hdc, BOOL fIsLink);

/*************************************************************************

** Hatch window definitions and prototypes                              **

*************************************************************************/

#define DEFAULT_HATCHBORDER_WIDTH   4

STDAPI_(BOOL) RegisterHatchWindowClass(HINSTANCE hInst);

STDAPI_(HWND) CreateHatchWindow(HWND hWndParent, HINSTANCE hInst);

STDAPI_(UINT) GetHatchWidth(HWND hWndHatch);

STDAPI_(void) GetHatchRect(HWND hWndHatch, LPRECT lpHatchRect);

STDAPI_(void) SetHatchRect(HWND hWndHatch, LPRECT lprcHatchRect);

STDAPI_(void) SetHatchWindowSize(

      HWND        hWndHatch,

      LPRECT      lprcIPObjRect,

      LPRECT      lprcClipRect,

      LPPOINT     lpptOffset

);

/*************************************************************************

** VERSION VERIFICATION INFORMATION

*************************************************************************/

// The following magic number is used to verify that the resources we bind

// to our EXE are the same "version" as the LIB (or DLL) file which

// contains these routines.  This is not the same as the Version information

// resource that we place in OLE2UI.RC, this is a special ID that we will

// have compiled in to our EXE.  Upon initialization of OLE2UI, we will

// look in our resources for an RCDATA called "VERIFICATION" (see OLE2UI.RC),

// and make sure that the magic number there equals the magic number below.

#define OLEUI_VERSION_MAGIC 0x4D42

#endif  //_OLE2UI_H_


OLESAMPL.MAK  (INCLUDE Sample)

#+---------------------------------------------------------------------------

#

#  Microsoft Windows

#  Copyright (C) Microsoft Corporation, 1992 - 1994.

#

#  File:       olesampl.mak

#

#  Contents:   common makefile for use by the SDK OLE samples

#

#              This makefile is included in place of ntwin32.mak

#              at the top of all the OLE samples.

#

#  History:     8-23-94   stevebl   Created

#

#----------------------------------------------------------------------------

!include <ntwin32.mak>

INCLUDE=$(MSTOOLS)\samples\ole\include;$(INCLUDE)

LIB=$(MSTOOLS)\samples\ole\lib;$(LIB)

olelibs = $(olelibs) sdkutil.lib

olelibsmt = $(olelibsmt) sdkutil.lib

olelibsdll = $(olelibsdll) sdkutil.lib

guilibs = $(guilibs) sdkutil.lib

guilibsmt = $(guilibsmt) sdkutil.lib

guilibsdll = $(guilibsdll) sdkutil.lib


OLESTD.H  (INCLUDE Sample)

/*************************************************************************

**

**    OLE 2.0 Standard Utilities

**

**    olestd.h

**

**    This file contains file contains data structure defintions,

**    function prototypes, constants, etc. for the common OLE 2.0

**    utilities.

**    These utilities include the following:

**          Debuging Assert/Verify macros

**          HIMETRIC conversion routines

**          reference counting debug support

**          OleStd API's for common compound-document app support

**

**    (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved

**

*************************************************************************/

#if !defined( _OLESTD_H_ )

#define _OLESTD_H_

#if defined( __TURBOC__ ) || defined( WIN32 )

#define _based(a)

#endif

#ifndef RC_INVOKED

#include <dos.h>        // needed for filetime

#endif  /* RC_INVOKED */

#include <commdlg.h>    // needed for LPPRINTDLG

#include <shellapi.h>   // needed for HKEY

#include "ansiapi.h"

// String table defines...

#define  IDS_OLESTDNOCREATEFILE   700

#define  IDS_OLESTDNOOPENFILE     701

#define  IDS_OLESTDDISKFULL       702

/*

 * Some C interface declaration stuff

 */

#if ! defined(__cplusplus)

typedef struct tagINTERFACEIMPL {

      IUnknownVtbl FAR*       lpVtbl;

      LPVOID                  lpBack;

      int                     cRef;   // interface specific ref count.

} INTERFACEIMPL, FAR* LPINTERFACEIMPL;

#define INIT_INTERFACEIMPL(lpIFace, pVtbl, pBack)   \

      ((lpIFace)->lpVtbl = pVtbl, \

         ((LPINTERFACEIMPL)(lpIFace))->lpBack = (LPVOID)pBack,   \

         ((LPINTERFACEIMPL)(lpIFace))->cRef = 0  \

      )

#if defined( _DEBUG )

#define OleDbgQueryInterfaceMethod(lpUnk)   \

      ((lpUnk) != NULL ? ((LPINTERFACEIMPL)(lpUnk))->cRef++ : 0)

#define OleDbgAddRefMethod(lpThis, iface)   \

      ((LPINTERFACEIMPL)(lpThis))->cRef++

#if _DEBUGLEVEL >= 2

#define OleDbgReleaseMethod(lpThis, iface) \

      (--((LPINTERFACEIMPL)(lpThis))->cRef == 0 ? \

         OleDbgOut("\t" iface "* RELEASED (cRef == 0)\r\n"),1 : \

          (((LPINTERFACEIMPL)(lpThis))->cRef < 0) ? \

            ( \

               DebugBreak(), \

               OleDbgOut(  \

                  "\tERROR: " iface "* RELEASED TOO MANY TIMES\r\n") \

            ),1 : \

            1)

#else       // if _DEBUGLEVEL < 2

#define OleDbgReleaseMethod(lpThis, iface) \

      (--((LPINTERFACEIMPL)(lpThis))->cRef == 0 ? \

         1 : \

          (((LPINTERFACEIMPL)(lpThis))->cRef < 0) ? \

            ( \

               OleDbgOut(  \

                  "\tERROR: " iface "* RELEASED TOO MANY TIMES\r\n") \

      ),1 : \

            1)

#endif      // if _DEBUGLEVEL < 2

#else       // ! defined (_DEBUG)

#define OleDbgQueryInterfaceMethod(lpUnk)

#define OleDbgAddRefMethod(lpThis, iface)

#define OleDbgReleaseMethod(lpThis, iface)

#endif      // if defined( _DEBUG )

#endif      // ! defined(__cplusplus)

/*

 * Some docfiles stuff

 */

#define STGM_DFRALL (STGM_READWRITE | STGM_TRANSACTED | STGM_SHARE_DENY_WRITE)

#define STGM_DFALL (STGM_READWRITE | STGM_TRANSACTED | STGM_SHARE_EXCLUSIVE)

#define STGM_SALL (STGM_READWRITE | STGM_SHARE_EXCLUSIVE)

/*

 * Some moniker stuff

 */

// Delimeter used to separate ItemMoniker pieces of a composite moniker

#if defined( _MAC )

#define OLESTDDELIM OLESTR(":")

#else

#define OLESTDDELIM OLESTR("\\")

#endif

/*

 * Some Concurrency stuff

 */

/* standard Delay (in msec) to wait before retrying an LRPC call.

**    this value is returned from IMessageFilter::RetryRejectedCall

*/

#define OLESTDRETRYDELAY    (DWORD)5000

/* Cancel the pending outgoing LRPC call.

**    this value is returned from IMessageFilter::RetryRejectedCall

*/

#define OLESTDCANCELRETRY   (DWORD)-1

/*

 * Some Icon support stuff.

 *

 * The following API's are now OBSOLETE because equivalent API's have been

 * added to the OLE2.DLL library

 *      GetIconOfFile       superceeded by OleGetIconOfFile

 *      GetIconOfClass      superceeded by OleGetIconOfClass

 *      OleUIMetafilePictFromIconAndLabel

 *                          superceeded by OleMetafilePictFromIconAndLabel

 *

 * The following macros are defined for backward compatibility with previous

 * versions of the OLE2UI library. It is recommended that the new Ole* API's

 * should be used instead.

 */

#define GetIconOfFile(hInst, lpszFileName, fUseFileAsLabel) \

   OleGetIconOfFile(lpszFileName, fUseFileAsLabel)

#define GetIconOfClass(hInst, rclsid, lpszLabel, fUseTypeAsLabel) \

   OleGetIconOfClass(rclsid, lpszLabel, fUseTypeAsLabel)

#define OleUIMetafilePictFromIconAndLabel(hIcon,pszLabel,pszSourceFile,iIcon)\

   OleMetafilePictFromIconAndLabel(hIcon, pszLabel, pszSourceFile, iIcon)

/*

 * Some Clipboard Copy/Paste & Drag/Drop support stuff

 */

//Macro to set all FormatEtc fields

#define SETFORMATETC(fe, cf, asp, td, med, li)   \

   ((fe).cfFormat=cf, \

    (fe).dwAspect=asp, \

    (fe).ptd=td, \

    (fe).tymed=med, \

    (fe).lindex=li)

//Macro to set interesting FormatEtc fields defaulting the others.

#define SETDEFAULTFORMATETC(fe, cf, med)  \

   ((fe).cfFormat=cf, \

    (fe).dwAspect=DVASPECT_CONTENT, \

    (fe).ptd=NULL, \

    (fe).tymed=med, \

    (fe).lindex=-1)

// Macro to test if two FormatEtc structures are an exact match

#define IsEqualFORMATETC(fe1, fe2)  \

   (OleStdCompareFormatEtc(&(fe1), &(fe2))==0)

// Clipboard format strings

#define CF_EMBEDSOURCE      TEXT("Embed Source")

#define CF_EMBEDDEDOBJECT   TEXT("Embedded Object")

#define CF_LINKSOURCE       TEXT("Link Source")

#define CF_CUSTOMLINKSOURCE TEXT("Custom Link Source")

#define CF_OBJECTDESCRIPTOR TEXT("Object Descriptor")

#define CF_LINKSRCDESCRIPTOR TEXT("Link Source Descriptor")

#define CF_OWNERLINK        TEXT("OwnerLink")

#define CF_FILENAME         TEXT("FileName")

#define OleStdQueryOleObjectData(lpformatetc)   \

   (((lpformatetc)->tymed & TYMED_ISTORAGE) ?    \

         NOERROR : ResultFromScode(DV_E_FORMATETC))

#define OleStdQueryLinkSourceData(lpformatetc)   \

   (((lpformatetc)->tymed & TYMED_ISTREAM) ?    \

         NOERROR : ResultFromScode(DV_E_FORMATETC))

#define OleStdQueryObjectDescriptorData(lpformatetc)    \

   (((lpformatetc)->tymed & TYMED_HGLOBAL) ?    \

         NOERROR : ResultFromScode(DV_E_FORMATETC))

#define OleStdQueryFormatMedium(lpformatetc, tymd)  \

   (((lpformatetc)->tymed & tymd) ?    \

         NOERROR : ResultFromScode(DV_E_FORMATETC))

// Make an independent copy of a MetafilePict

#define OleStdCopyMetafilePict(hpictin, phpictout)  \

   (*(phpictout) = OleDuplicateData(hpictin,CF_METAFILEPICT,GHND|GMEM_SHARE))

// REVIEW: these need to be added to OLE2.H

#if !defined( DD_DEFSCROLLINTERVAL )

#define DD_DEFSCROLLINTERVAL    50

#endif

#if !defined( DD_DEFDRAGDELAY )

#define DD_DEFDRAGDELAY         200

#endif

#if !defined( DD_DEFDRAGMINDIST )

#define DD_DEFDRAGMINDIST       2

#endif

/* OleStdGetDropEffect

** -------------------

**

** Convert a keyboard state into a DROPEFFECT.

**

** returns the DROPEFFECT value derived from the key state.

**    the following is the standard interpretation:

**          no modifier -- Default Drop     (NULL is returned)

**          CTRL        -- DROPEFFECT_COPY

**          SHIFT       -- DROPEFFECT_MOVE

**          CTRL-SHIFT  -- DROPEFFECT_LINK

**

**    Default Drop: this depends on the type of the target application.

**    this is re-interpretable by each target application. a typical

**    interpretation is if the drag is local to the same document

**    (which is source of the drag) then a MOVE operation is

**    performed. if the drag is not local, then a COPY operation is

**    performed.

*/

#define OleStdGetDropEffect(grfKeyState)    \

   ( (grfKeyState & MK_CONTROL) ?          \

      ( (grfKeyState & MK_SHIFT) ? DROPEFFECT_LINK : DROPEFFECT_COPY ) :  \

      ( (grfKeyState & MK_SHIFT) ? DROPEFFECT_MOVE : 0 ) )

/* The OLEUIPASTEFLAG enumeration is used by the OLEUIPASTEENTRY structure.

 *

 * OLEUIPASTE_ENABLEICON    If the container does not specify this flag for the entry in the

 *   OLEUIPASTEENTRY array passed as input to OleUIPasteSpecial, the DisplayAsIcon button will be

 *   unchecked and disabled when the the user selects the format that corresponds to the entry.

 *

 * OLEUIPASTE_PASTEONLY     Indicates that the entry in the OLEUIPASTEENTRY array is valid for pasting only.

 * OLEUIPASTE_PASTE         Indicates that the entry in the OLEUIPASTEENTRY array is valid for pasting. It

 *   may also be valid for linking if any of the following linking flags are specified.

 *

 * If the entry in the OLEUIPASTEENTRY array is valid for linking, the following flags indicate which link

 * types are acceptable by OR'ing together the appropriate OLEUIPASTE_LINKTYPE<#> values.

 * These values correspond as follows to the array of link types passed to OleUIPasteSpecial:

 *   OLEUIPASTE_LINKTYPE1=arrLinkTypes[0]

 *   OLEUIPASTE_LINKTYPE2=arrLinkTypes[1]

 *   OLEUIPASTE_LINKTYPE3=arrLinkTypes[2]

 *   OLEUIPASTE_LINKTYPE4=arrLinkTypes[3]

 *   OLEUIPASTE_LINKTYPE5=arrLinkTypes[4]

 *   OLEUIPASTE_LINKTYPE6=arrLinkTypes[5]

 *   OLEUIPASTE_LINKTYPE7=arrLinkTypes[6]

 *  OLEUIPASTE_LINKTYPE8=arrLinkTypes[7]

 *

 * where,

 *   UINT arrLinkTypes[8] is an array of registered clipboard formats for linking. A maximium of 8 link

 *   types are allowed.

 */

typedef enum tagOLEUIPASTEFLAG

{

   OLEUIPASTE_ENABLEICON    = 2048,     // enable display as icon

   OLEUIPASTE_PASTEONLY     = 0,

   OLEUIPASTE_PASTE         = 512,

   OLEUIPASTE_LINKANYTYPE   = 1024,

   OLEUIPASTE_LINKTYPE1     = 1,

   OLEUIPASTE_LINKTYPE2     = 2,

   OLEUIPASTE_LINKTYPE3     = 4,

   OLEUIPASTE_LINKTYPE4     = 8,

   OLEUIPASTE_LINKTYPE5     = 16,

   OLEUIPASTE_LINKTYPE6     = 32,

   OLEUIPASTE_LINKTYPE7     = 64,

   OLEUIPASTE_LINKTYPE8     = 128

} OLEUIPASTEFLAG;

/*

 * PasteEntry structure

 * --------------------

 * An array of OLEUIPASTEENTRY entries is specified for the PasteSpecial dialog

 * box. Each entry includes a FORMATETC which specifies the formats that are

 * acceptable, a string that is to represent the format in the  dialog's list

 * box, a string to customize the result text of the dialog and a set of flags

 * from the OLEUIPASTEFLAG enumeration.  The flags indicate if the entry is

 * valid for pasting only, linking only or both pasting and linking. If the

 * entry is valid for linking, the flags indicate which link types are

 * acceptable by OR'ing together the appropriate OLEUIPASTE_LINKTYPE<#> values.

 * These values correspond to the array of link types as follows:

 *   OLEUIPASTE_LINKTYPE1=arrLinkTypes[0]

 *   OLEUIPASTE_LINKTYPE2=arrLinkTypes[1]

 *   OLEUIPASTE_LINKTYPE3=arrLinkTypes[2]

 *   OLEUIPASTE_LINKTYPE4=arrLinkTypes[3]

 *   OLEUIPASTE_LINKTYPE5=arrLinkTypes[4]

 *   OLEUIPASTE_LINKTYPE6=arrLinkTypes[5]

 *   OLEUIPASTE_LINKTYPE7=arrLinkTypes[6]

 *   OLEUIPASTE_LINKTYPE8=arrLinkTypes[7]

 *   UINT arrLinkTypes[8]; is an array of registered clipboard formats

 *                        for linking. A maximium of 8 link types are allowed.

 */

typedef struct tagOLEUIPASTEENTRYA

{

   FORMATETC        fmtetc;            // Format that is acceptable. The paste

                              //   dialog checks if this format is

                              //   offered by the object on the

                              //   clipboard and if so offers it for

                              //   selection to the user.

   LPCSTR           lpstrFormatName;   // String that represents the format to the user. Any %s

                              //   in this string is replaced by the FullUserTypeName

                              //   of the object on the clipboard and the resulting string

                              //   is placed in the list box of the dialog. Atmost

                              //   one %s is allowed. The presence or absence of %s indicates

                              //   if the result text is to indicate that data is

                              //   being pasted or that an object that can be activated by

                              //   an application is being pasted. If %s is

                              //   present, the result-text says that an object is being pasted.

                              //   Otherwise it says that data is being pasted.

   LPCSTR           lpstrResultText;   // String to customize the result text of the dialog when

                              //  the user selects the format correspoding to this

                              //  entry. Any %s in this string is replaced by the the application

                              //  name or FullUserTypeName of the object on

                              //  the clipboard. Atmost one %s is allowed.

   DWORD            dwFlags;           // Values from OLEUIPASTEFLAG enum

   DWORD            dwScratchSpace;    // Scratch space available to be used

                              //   by routines which loop through an

                              //   IEnumFORMATETC* to mark if the

                              //   PasteEntry format is available.

                              //   this field CAN be left uninitialized.

} OLEUIPASTEENTRYA, *POLEUIPASTEENTRYA, FAR *LPOLEUIPASTEENTRYA;

typedef struct tagOLEUIPASTEENTRYW

{

   FORMATETC        fmtetc;            // Format that is acceptable. The paste

                              //   dialog checks if this format is

                              //   offered by the object on the

                              //   clipboard and if so offers it for

                              //   selection to the user.

   LPCWSTR           lpstrFormatName;   // String that represents the format to the user. Any %s

                              //   in this string is replaced by the FullUserTypeName

                              //   of the object on the clipboard and the resulting string

                              //   is placed in the list box of the dialog. Atmost

                              //   one %s is allowed. The presence or absence of %s indicates

                              //   if the result text is to indicate that data is

                              //   being pasted or that an object that can be activated by

                              //   an application is being pasted. If %s is

                              //   present, the result-text says that an object is being pasted.

                              //   Otherwise it says that data is being pasted.

   LPCWSTR           lpstrResultText;   // String to customize the result text of the dialog when

                              //  the user selects the format correspoding to this

                              //  entry. Any %s in this string is replaced by the the application

                              //  name or FullUserTypeName of the object on

                              //  the clipboard. Atmost one %s is allowed.

   DWORD            dwFlags;           // Values from OLEUIPASTEFLAG enum

   DWORD            dwScratchSpace;    // Scratch space available to be used

                              //   by routines which loop through an

                              //   IEnumFORMATETC* to mark if the

                              //   PasteEntry format is available.

                              //   this field CAN be left uninitialized.

} OLEUIPASTEENTRYW, *POLEUIPASTEENTRYW, FAR *LPOLEUIPASTEENTRYW;

#ifdef UNICODE

typedef OLEUIPASTEENTRYW OLEUIPASTEENTRY;

typedef POLEUIPASTEENTRYW POLEUIPASTEENTRY;

typedef LPOLEUIPASTEENTRYW LPOLEUIPASTEENTRY;

#else

typedef OLEUIPASTEENTRYA OLEUIPASTEENTRY;

typedef POLEUIPASTEENTRYA POLEUIPASTEENTRY;

typedef LPOLEUIPASTEENTRYA LPOLEUIPASTEENTRY;

#endif

#define OLESTDDROP_NONE         0

#define OLESTDDROP_DEFAULT      1

#define OLESTDDROP_NONDEFAULT   2

/*

 * Some misc stuff

 */

#define EMBEDDINGFLAG "Embedding"     // Cmd line switch for launching a srvr

#define HIMETRIC_PER_INCH   2540      // number HIMETRIC units per inch

#define PTS_PER_INCH        72        // number points (font size) per inch

#define MAP_PIX_TO_LOGHIM(x,ppli)   MulDiv(HIMETRIC_PER_INCH, (x), (ppli))

#define MAP_LOGHIM_TO_PIX(x,ppli)   MulDiv((ppli), (x), HIMETRIC_PER_INCH)

// Returns TRUE if all fields of the two Rect's are equal, else FALSE.

#define AreRectsEqual(lprc1, lprc2)     \

   (((lprc1->top == lprc2->top) &&     \

     (lprc1->left == lprc2->left) &&   \

     (lprc1->right == lprc2->right) && \

     (lprc1->bottom == lprc2->bottom)) ? TRUE : FALSE)

#define LSTRCPYN(lpdst, lpsrc, cch) \

(\

   (lpdst)[(cch)-1] = '\0', \

   ((cch)>1 ? _fstrncpy(lpdst, lpsrc, (cch)-1) : 0)\

)

/****** DEBUG Stuff *****************************************************/

#ifdef _DEBUG

#if !defined( _DBGTRACE )

#define _DEBUGLEVEL 2

#else

#define _DEBUGLEVEL _DBGTRACE

#endif

#if defined( NOASSERT )

#define OLEDBGASSERTDATA

#define OleDbgAssert(a)

#define OleDbgAssertSz(a, b)

#define OleDbgVerify(a)

#define OleDbgVerifySz(a, b)

#else   // ! NOASSERT

#define OLEDBGASSERTDATA    \

      static char _based(_segname("_CODE")) _szAssertFile[]= __FILE__;

#define OleDbgAssert(a) \

      (!(a) ? FnAssert(#a, NULL, _szAssertFile, __LINE__) : (HRESULT)1)

#define OleDbgAssertSz(a, b)    \

      (!(a) ? FnAssert(#a, b, _szAssertFile, __LINE__) : (HRESULT)1)

#define OleDbgVerify(a) \

      OleDbgAssert(a)

#define OleDbgVerifySz(a, b)    \

      OleDbgAssertSz(a, b)

#endif  // ! NOASSERT

#define OLEDBGDATA_MAIN(szPrefix)   \

      char near g_szDbgPrefix[] = szPrefix;    \

      OLEDBGASSERTDATA

#define OLEDBGDATA  \

      extern char near g_szDbgPrefix[];    \

      OLEDBGASSERTDATA

#define OLEDBG_BEGIN(lpsz) \

      OleDbgPrintAlways(g_szDbgPrefix,lpsz,1);

#define OLEDBG_END  \

      OleDbgPrintAlways(g_szDbgPrefix,"End\r\n",-1);

#define OleDbgOut(lpsz) \

      OleDbgPrintAlways(g_szDbgPrefix,lpsz,0)

#define OleDbgOutNoPrefix(lpsz) \

      OleDbgPrintAlways("",lpsz,0)

#define OleDbgOutRefCnt(lpsz,lpObj,refcnt)      \

      OleDbgPrintRefCntAlways(g_szDbgPrefix,lpsz,lpObj,(ULONG)refcnt)

#define OleDbgOutRect(lpsz,lpRect)      \

      OleDbgPrintRectAlways(g_szDbgPrefix,lpsz,lpRect)

#define OleDbgOutHResult(lpsz,hr)   \

      OleDbgPrintScodeAlways(g_szDbgPrefix,lpsz,GetScode(hr))

#define OleDbgOutScode(lpsz,sc) \

      OleDbgPrintScodeAlways(g_szDbgPrefix,lpsz,sc)

#define OleDbgOut1(lpsz)    \

      OleDbgPrint(1,g_szDbgPrefix,lpsz,0)

#define OleDbgOutNoPrefix1(lpsz)    \

      OleDbgPrint(1,"",lpsz,0)

#define OLEDBG_BEGIN1(lpsz)    \

      OleDbgPrint(1,g_szDbgPrefix,lpsz,1);

#define OLEDBG_END1 \

      OleDbgPrint(1,g_szDbgPrefix,"End\r\n",-1);

#define OleDbgOutRefCnt1(lpsz,lpObj,refcnt)     \

      OleDbgPrintRefCnt(1,g_szDbgPrefix,lpsz,lpObj,(ULONG)refcnt)

#define OleDbgOutRect1(lpsz,lpRect)     \

      OleDbgPrintRect(1,g_szDbgPrefix,lpsz,lpRect)

#define OleDbgOut2(lpsz)    \

      OleDbgPrint(2,g_szDbgPrefix,lpsz,0)

#define OleDbgOutNoPrefix2(lpsz)    \

      OleDbgPrint(2,"",lpsz,0)

#define OLEDBG_BEGIN2(lpsz)    \

      OleDbgPrint(2,g_szDbgPrefix,lpsz,1);

#define OLEDBG_END2 \

      OleDbgPrint(2,g_szDbgPrefix,"End\r\n",-1);

#define OleDbgOutRefCnt2(lpsz,lpObj,refcnt)     \

      OleDbgPrintRefCnt(2,g_szDbgPrefix,lpsz,lpObj,(ULONG)refcnt)

#define OleDbgOutRect2(lpsz,lpRect)     \

      OleDbgPrintRect(2,g_szDbgPrefix,lpsz,lpRect)

#define OleDbgOut3(lpsz)    \

      OleDbgPrint(3,g_szDbgPrefix,lpsz,0)

#define OleDbgOutNoPrefix3(lpsz)    \

      OleDbgPrint(3,"",lpsz,0)

#define OLEDBG_BEGIN3(lpsz)    \

      OleDbgPrint(3,g_szDbgPrefix,lpsz,1);

#define OLEDBG_END3 \

      OleDbgPrint(3,g_szDbgPrefix,"End\r\n",-1);

#define OleDbgOutRefCnt3(lpsz,lpObj,refcnt)     \

      OleDbgPrintRefCnt(3,g_szDbgPrefix,lpsz,lpObj,(ULONG)refcnt)

#define OleDbgOutRect3(lpsz,lpRect)     \

      OleDbgPrintRect(3,g_szDbgPrefix,lpsz,lpRect)

#define OleDbgOut4(lpsz)    \

      OleDbgPrint(4,g_szDbgPrefix,lpsz,0)

#define OleDbgOutNoPrefix4(lpsz)    \

      OleDbgPrint(4,"",lpsz,0)

#define OLEDBG_BEGIN4(lpsz)    \

      OleDbgPrint(4,g_szDbgPrefix,lpsz,1);

#define OLEDBG_END4 \

      OleDbgPrint(4,g_szDbgPrefix,"End\r\n",-1);

#define OleDbgOutRefCnt4(lpsz,lpObj,refcnt)     \

      OleDbgPrintRefCnt(4,g_szDbgPrefix,lpsz,lpObj,(ULONG)refcnt)

#define OleDbgOutRect4(lpsz,lpRect)     \

      OleDbgPrintRect(4,g_szDbgPrefix,lpsz,lpRect)

#else   //  !_DEBUG

#define OLEDBGDATA_MAIN(szPrefix)

#define OLEDBGDATA

#define OleDbgAssert(a)

#define OleDbgAssertSz(a, b)

#define OleDbgVerify(a)         (a)

#define OleDbgVerifySz(a, b)    (a)

#define OleDbgOutHResult(lpsz,hr)

#define OleDbgOutScode(lpsz,sc)

#define OLEDBG_BEGIN(lpsz)

#define OLEDBG_END

#define OleDbgOut(lpsz)

#define OleDbgOut1(lpsz)

#define OleDbgOut2(lpsz)

#define OleDbgOut3(lpsz)

#define OleDbgOut4(lpsz)

#define OleDbgOutNoPrefix(lpsz)

#define OleDbgOutNoPrefix1(lpsz)

#define OleDbgOutNoPrefix2(lpsz)

#define OleDbgOutNoPrefix3(lpsz)

#define OleDbgOutNoPrefix4(lpsz)

#define OLEDBG_BEGIN1(lpsz)

#define OLEDBG_BEGIN2(lpsz)

#define OLEDBG_BEGIN3(lpsz)

#define OLEDBG_BEGIN4(lpsz)

#define OLEDBG_END1

#define OLEDBG_END2

#define OLEDBG_END3

#define OLEDBG_END4

#define OleDbgOutRefCnt(lpsz,lpObj,refcnt)

#define OleDbgOutRefCnt1(lpsz,lpObj,refcnt)

#define OleDbgOutRefCnt2(lpsz,lpObj,refcnt)

#define OleDbgOutRefCnt3(lpsz,lpObj,refcnt)

#define OleDbgOutRefCnt4(lpsz,lpObj,refcnt)

#define OleDbgOutRect(lpsz,lpRect)

#define OleDbgOutRect1(lpsz,lpRect)

#define OleDbgOutRect2(lpsz,lpRect)

#define OleDbgOutRect3(lpsz,lpRect)

#define OleDbgOutRect4(lpsz,lpRect)

#endif  //  _DEBUG

/*************************************************************************

** Function prototypes

*************************************************************************/

//OLESTD.C

STDAPI_(int) SetDCToAnisotropic(HDC hDC, LPRECT lprcPhysical, LPRECT lprcLogical, LPRECT lprcWindowOld, LPRECT lprcViewportOld);

STDAPI_(int) SetDCToDrawInHimetricRect(HDC, LPRECT, LPRECT, LPRECT, LPRECT);

STDAPI_(int) ResetOrigDC(HDC, int, LPRECT, LPRECT);

STDAPI_(int)        XformWidthInHimetricToPixels(HDC, int);

STDAPI_(int)        XformWidthInPixelsToHimetric(HDC, int);

STDAPI_(int)        XformHeightInHimetricToPixels(HDC, int);

STDAPI_(int)        XformHeightInPixelsToHimetric(HDC, int);

STDAPI_(void) XformRectInPixelsToHimetric(HDC, LPRECT, LPRECT);

STDAPI_(void) XformRectInHimetricToPixels(HDC, LPRECT, LPRECT);

STDAPI_(void) XformSizeInPixelsToHimetric(HDC, LPSIZEL, LPSIZEL);

STDAPI_(void) XformSizeInHimetricToPixels(HDC, LPSIZEL, LPSIZEL);

STDAPI_(int) XformWidthInHimetricToPixels(HDC, int);

STDAPI_(int) XformWidthInPixelsToHimetric(HDC, int);

STDAPI_(int) XformHeightInHimetricToPixels(HDC, int);

STDAPI_(int) XformHeightInPixelsToHimetric(HDC, int);

STDAPI_(void) ParseCmdLine(LPSTR, BOOL FAR *, LPSTR);

STDAPI_(BOOL) OleStdIsOleLink(LPUNKNOWN lpUnk);

STDAPI_(LPUNKNOWN) OleStdQueryInterface(LPUNKNOWN lpUnk, REFIID riid);

STDAPI_(LPSTORAGE) OleStdCreateRootStorage(LPOLESTR lpszStgName, DWORD grfMode);

STDAPI_(LPSTORAGE) OleStdOpenRootStorage(LPOLESTR lpszStgName, DWORD grfMode);

STDAPI_(LPSTORAGE) OleStdOpenOrCreateRootStorage(LPOLESTR lpszStgName, DWORD grfMode);

STDAPI_(LPSTORAGE) OleStdCreateChildStorage(LPSTORAGE lpStg, LPOLESTR lpszStgName);

STDAPI_(LPSTORAGE) OleStdOpenChildStorage(LPSTORAGE lpStg, LPOLESTR lpszStgName, DWORD grfMode);

STDAPI_(BOOL) OleStdCommitStorage(LPSTORAGE lpStg);

STDAPI OleStdDestroyAllElements(LPSTORAGE lpStg);

STDAPI_(LPSTORAGE) OleStdCreateStorageOnHGlobal(

      HANDLE hGlobal,

      BOOL fDeleteOnRelease,

      DWORD dwgrfMode

);

STDAPI_(LPSTORAGE) OleStdCreateTempStorage(BOOL fUseMemory, DWORD grfMode);

STDAPI OleStdDoConvert(LPSTORAGE lpStg, REFCLSID rClsidNew);

STDAPI_(BOOL) OleStdGetTreatAsFmtUserType(

      REFCLSID        rClsidApp,

      LPSTORAGE       lpStg,

      CLSID FAR*      lpclsid,

      CLIPFORMAT FAR* lpcfFmt,

      LPOLESTR FAR*      lplpszType

);

STDAPI OleStdDoTreatAsClass(LPOLESTR lpszUserType, REFCLSID rclsid, REFCLSID rclsidNew);

STDAPI_(BOOL) OleStdSetupAdvises(LPOLEOBJECT lpOleObject, DWORD dwDrawAspect,

               LPOLESTR lpszContainerApp, LPOLESTR lpszContainerObj,

               LPADVISESINK lpAdviseSink, BOOL fCreate);

STDAPI OleStdSwitchDisplayAspect(

      LPOLEOBJECT             lpOleObj,

      LPDWORD                 lpdwCurAspect,

      DWORD                   dwNewAspect,

      HGLOBAL                 hMetaPict,

      BOOL                    fDeleteOldAspect,

      BOOL                    fSetupViewAdvise,

      LPADVISESINK            lpAdviseSink,

      BOOL FAR*               lpfMustUpdate

);

STDAPI OleStdSetIconInCache(LPOLEOBJECT lpOleObj, HGLOBAL hMetaPict);

STDAPI_(HGLOBAL) OleStdGetData(

      LPDATAOBJECT        lpDataObj,

      CLIPFORMAT          cfFormat,

      DVTARGETDEVICE FAR* lpTargetDevice,

      DWORD               dwAspect,

      LPSTGMEDIUM         lpMedium

);

STDAPI_(void) OleStdMarkPasteEntryList(

      LPDATAOBJECT        lpSrcDataObj,

      LPOLEUIPASTEENTRY   lpPriorityList,

      int                 cEntries

);

STDAPI_(int) OleStdGetPriorityClipboardFormat(

      LPDATAOBJECT        lpSrcDataObj,

      LPOLEUIPASTEENTRY   lpPriorityList,

      int                 cEntries

);

STDAPI_(BOOL) OleStdIsDuplicateFormat(

      LPFORMATETC         lpFmtEtc,

      LPFORMATETC         arrFmtEtc,

      int                 nFmtEtc

);

STDAPI_(void) OleStdRegisterAsRunning(LPUNKNOWN lpUnk, LPMONIKER lpmkFull, DWORD FAR* lpdwRegister);

STDAPI_(void) OleStdRevokeAsRunning(DWORD FAR* lpdwRegister);

STDAPI_(void) OleStdNoteFileChangeTime(LPOLESTR lpszFileName, DWORD dwRegister);

STDAPI_(void) OleStdNoteObjectChangeTime(DWORD dwRegister);

STDAPI OleStdGetOleObjectData(

      LPPERSISTSTORAGE    lpPStg,

      LPFORMATETC         lpformatetc,

      LPSTGMEDIUM         lpMedium,

      BOOL                fUseMemory

);

STDAPI OleStdGetLinkSourceData(

      LPMONIKER           lpmk,

      LPCLSID             lpClsID,

      LPFORMATETC         lpformatetc,

      LPSTGMEDIUM         lpMedium

);

STDAPI_(HGLOBAL) OleStdGetObjectDescriptorData(

      CLSID               clsid,

      DWORD               dwAspect,

      SIZEL               sizel,

      POINTL              pointl,

      DWORD               dwStatus,

      LPOLESTR            lpszFullUserTypeName,

      LPOLESTR            lpszSrcOfCopy

);

STDAPI_(HGLOBAL) OleStdGetObjectDescriptorDataFromOleObject(

      LPOLEOBJECT         lpOleObj,

      LPOLESTR            lpszSrcOfCopy,

      DWORD               dwAspect,

      POINTL              pointl,

      LPSIZEL             lpSizelHim

);

STDAPI_(HGLOBAL) OleStdFillObjectDescriptorFromData(

      LPDATAOBJECT       lpDataObject,

      LPSTGMEDIUM        lpmedium,

      CLIPFORMAT FAR*    lpcfFmt

);

STDAPI_(HANDLE) OleStdGetMetafilePictFromOleObject(

      LPOLEOBJECT         lpOleObj,

      DWORD               dwDrawAspect,

      LPSIZEL             lpSizelHim,

      DVTARGETDEVICE FAR* ptd

);

STDAPI_(void) OleStdCreateTempFileMoniker(LPOLESTR lpszPrefixString, UINT FAR* lpuUnique, LPOLESTR lpszName, LPMONIKER FAR* lplpmk);

STDAPI_(LPMONIKER) OleStdGetFirstMoniker(LPMONIKER lpmk);

STDAPI_(ULONG) OleStdGetLenFilePrefixOfMoniker(LPMONIKER lpmk);

STDAPI OleStdMkParseDisplayName(

      REFCLSID        rClsid,

      LPBC            lpbc,

      LPOLESTR        lpszUserName,

      ULONG FAR*      lpchEaten,

      LPMONIKER FAR*  lplpmk

);

STDAPI_(LPVOID) OleStdMalloc(ULONG ulSize);

STDAPI_(LPVOID) OleStdRealloc(LPVOID pmem, ULONG ulSize);

STDAPI_(void) OleStdFree(LPVOID pmem);

STDAPI_(ULONG) OleStdGetSize(LPVOID pmem);

STDAPI_(void) OleStdFreeString(LPOLESTR lpsz, LPMALLOC lpMalloc);

STDAPI_(LPOLESTR) OleStdCopyString(LPOLESTR lpszSrc, LPMALLOC lpMalloc);

STDAPI_(ULONG) OleStdGetItemToken(LPOLESTR lpszSrc, LPOLESTR lpszDst,int nMaxChars);

STDAPI_(UINT)     OleStdIconLabelTextOut(HDC        hDC,

                               HFONT      hFont,

                               int        nXStart,

                               int        nYStart,

                               UINT       fuOptions,

                               RECT FAR * lpRect,

                               LPOLESTR   lpszString,

                               UINT       cchString,

                               int FAR *  lpDX);

// registration database query functions

STDAPI_(UINT)     OleStdGetAuxUserType(REFCLSID rclsid,

                             WORD   wAuxUserType,

                             LPOLESTR  lpszAuxUserType,

                             int    cch,

                             HKEY   hKey);

STDAPI_(UINT)     OleStdGetUserTypeOfClass(REFCLSID rclsid,

                                 LPOLESTR lpszUserType,

                                 UINT cch,

                                 HKEY hKey);

STDAPI_(BOOL) OleStdGetMiscStatusOfClass(REFCLSID, HKEY, DWORD FAR *);

STDAPI_(CLIPFORMAT) OleStdGetDefaultFileFormatOfClass(

      REFCLSID        rclsid,

      HKEY            hKey

);

STDAPI_(void) OleStdInitVtbl(LPVOID lpVtbl, UINT nSizeOfVtbl);

STDMETHODIMP OleStdNullMethod(LPUNKNOWN lpThis);

STDAPI_(BOOL) OleStdCheckVtbl(LPVOID lpVtbl, UINT nSizeOfVtbl, LPOLESTR lpszIface);

STDAPI_(ULONG) OleStdVerifyRelease(LPUNKNOWN lpUnk, LPOLESTR lpszMsg);

STDAPI_(ULONG) OleStdRelease(LPUNKNOWN lpUnk);

STDAPI_(HDC) OleStdCreateDC(DVTARGETDEVICE FAR* ptd);

STDAPI_(HDC) OleStdCreateIC(DVTARGETDEVICE FAR* ptd);

STDAPI_(DVTARGETDEVICE FAR*) OleStdCreateTargetDevice(LPPRINTDLG lpPrintDlg);

STDAPI_(BOOL) OleStdDeleteTargetDevice(DVTARGETDEVICE FAR* ptd);

STDAPI_(DVTARGETDEVICE FAR*) OleStdCopyTargetDevice(DVTARGETDEVICE FAR* ptdSrc);

STDAPI_(BOOL) OleStdCopyFormatEtc(LPFORMATETC petcDest, LPFORMATETC petcSrc);

STDAPI_(int) OleStdCompareFormatEtc(FORMATETC FAR* pFetcLeft, FORMATETC FAR* pFetcRight);

STDAPI_(BOOL) OleStdCompareTargetDevice

   (DVTARGETDEVICE FAR* ptdLeft, DVTARGETDEVICE FAR* ptdRight);

STDAPI_(void) OleDbgPrint(

      int     nDbgLvl,

      LPSTR   lpszPrefix,

      LPSTR   lpszMsg,

      int     nIndent

);

STDAPI_(void) OleDbgPrintAlways(LPSTR lpszPrefix, LPSTR lpszMsg, int nIndent);

STDAPI_(void) OleDbgSetDbgLevel(int nDbgLvl);

STDAPI_(int) OleDbgGetDbgLevel( void );

STDAPI_(void) OleDbgIndent(int n);

STDAPI_(void) OleDbgPrintRefCnt(

      int         nDbgLvl,

      LPSTR       lpszPrefix,

      LPSTR       lpszMsg,

      LPVOID      lpObj,

      ULONG       refcnt

);

STDAPI_(void) OleDbgPrintRefCntAlways(

      LPSTR       lpszPrefix,

      LPSTR       lpszMsg,

      LPVOID      lpObj,

      ULONG       refcnt

);

STDAPI_(void) OleDbgPrintRect(

      int         nDbgLvl,

      LPSTR       lpszPrefix,

      LPSTR       lpszMsg,

      LPRECT      lpRect

);

STDAPI_(void) OleDbgPrintRectAlways(

      LPSTR       lpszPrefix,

      LPSTR       lpszMsg,

      LPRECT      lpRect

);

STDAPI_(void) OleDbgPrintScodeAlways(LPSTR lpszPrefix, LPSTR lpszMsg, SCODE sc);

// debug implementation of the IMalloc interface.

STDAPI OleStdCreateDbAlloc(ULONG reserved, IMalloc FAR* FAR* ppmalloc);

STDAPI_(LPENUMFORMATETC)

  OleStdEnumFmtEtc_Create(ULONG nCount, LPFORMATETC lpEtc);

STDAPI_(LPENUMSTATDATA)

  OleStdEnumStatData_Create(ULONG nCount, LPSTATDATA lpStat);

STDAPI_(BOOL)

  OleStdCopyStatData(LPSTATDATA pDest, LPSTATDATA pSrc);

STDAPI_(HPALETTE)

  OleStdCreateStandardPalette(void);

#if defined( OBSOLETE )

/*************************************************************************

** The following API's have been converted into macros:

**          OleStdQueryOleObjectData

**          OleStdQueryLinkSourceData

**          OleStdQueryObjectDescriptorData

**          OleStdQueryFormatMedium

**          OleStdCopyMetafilePict

**          AreRectsEqual

**          OleStdGetDropEffect

**

**    These macros are defined above

*************************************************************************/

STDAPI_(BOOL) AreRectsEqual(LPRECT lprc1, LPRECT lprc2);

STDAPI_(BOOL) OleStdCopyMetafilePict(HANDLE hpictin, HANDLE FAR* phpictout);

STDAPI OleStdQueryOleObjectData(LPFORMATETC lpformatetc);

STDAPI OleStdQueryLinkSourceData(LPFORMATETC lpformatetc);

STDAPI OleStdQueryObjectDescriptorData(LPFORMATETC lpformatetc);

STDAPI OleStdQueryFormatMedium(LPFORMATETC lpformatetc, TYMED tymed);

STDAPI_(DWORD) OleStdGetDropEffect ( DWORD grfKeyState );

#endif  // OBSOLETE

#endif // _OLESTD_H_


STABLIZE.H  (INCLUDE Sample)

//+---------------------------------------------------------------------------

//

//  Microsoft Windows

//  Copyright (C) Microsoft Corporation, 1992 - 1994.

//

//  File:       stablize.h

//

//  Contents:   Stabilization Classes used to stabilize objects during

//              re-entrant calls.

//

//  Classes:    CSafeRefCount

//              CStabilize

//

//  History:    8-26-94   stevebl   Modified from code written by AlexGo

//

//----------------------------------------------------------------------------

#ifndef __STABLIZE__

#define __STABLIZE__

//+-------------------------------------------------------------------------

//

//  Class:      CSafeRefCount

//

//  Purpose:    A concrete class for objects to inherit from.

//              CSafeRefCount will keep track of reference counts,

//              nesting counts, and zombie states, allowing objects

//              to easily manage the liveness of their memory images.

//

//  Interface:

//

//  History:    dd-mmm-yy Author    Comment

//              01-Aug-94 alexgo    author

//

//  Notes:      inherits CPrivAlloc

//

//--------------------------------------------------------------------------

class CSafeRefCount

{

public:

        ULONG   SafeAddRef();

        ULONG   SafeRelease();

        ULONG   IncrementNestCount();

        ULONG   DecrementNestCount();

                CSafeRefCount();

        virtual ~CSafeRefCount();

private:

        ULONG   m_cRefs;

        ULONG   m_cNest;

        BOOL    m_fInDelete;

};

//+-------------------------------------------------------------------------

//

//  Class:      CStabilize

//

//  Purpose:    An instance of this class should be allocated on the

//              stack of every object method that makes an outgoing call.

//              The contstructor takes a pointer to the object's base

//              CSafeRefCount class.

//

//  Interface:

//

//  History:    dd-mmm-yy Author    Comment

//              01-Aug-94 alexgo    author

//

//  Notes:      The constructor will increment the nest count of the

//              object while the destructor will decrement it.

//

//--------------------------------------------------------------------------

class CStabilize

{

public:

        inline CStabilize( CSafeRefCount *pObjSafeRefCount );

        inline ~CStabilize();

private:

        CSafeRefCount * m_pObjSafeRefCount;

};

inline CStabilize::CStabilize( CSafeRefCount *pObjSafeRefCount )

{

        pObjSafeRefCount->IncrementNestCount();

        m_pObjSafeRefCount = pObjSafeRefCount;

}

inline CStabilize::~CStabilize()

{

        m_pObjSafeRefCount->DecrementNestCount();

}

#endif  // __STABLIZE__


INOLE2

These topics contain bug fixes and Win32 update information for the sample code included with Kraig Brockschmidt's Inside OLE 2, 1st ed., Microsoft Press, 1994.


MAKEFILE  (INOLE2 Sample)

DIRLIST  =  stastrip    \

            classlib    \

            bcdemo      \

            gbdemo      \

            chap02      \

            chap03      \

            chap04      \

            chap05      \

            chap06      \

            chap07      \

            chap08      \

            chap09      \

            chap10      \

            chap11      \

            chap12      \

            chap13      \

            chap14      \

            chap15      \

            chap16

all: lib $(DIRLIST)

INCLUDE=$(INCLUDE);$(MSTOOLS)\samples\ole\inole2\inc

$(DIRLIST):

        cd $@

        @echo *** ole\inole2\$@ *** >>$(MSTOOLS)\samples\inole2.tmp

        @nmake -a -i 1>>$(MSTOOLS)\samples\inole2.tmp 2>&1

        cd ..

lib:

        cd $@

        @echo *** ole\inole2\$@ *** >>$(MSTOOLS)\samples\inole2.tmp

        @nmake -i 1>>$(MSTOOLS)\samples\inole2.tmp 2>&1

        cd ..


NOTES.TXT  (INOLE2 Sample)

Additional Notes Concerning the Win32 version of Inside OLE 2 samples.

These notes are intended to supplement changes described in UPDATE.TXT.

That text file describes earlier changes to these samples from the

printed versions in Inside OLE 2.  These notes will not be as detailed

as those in UPDATE.TXT and are intended to point out some of the changes

in the Win32 port.

The process of porting exposed numerous minute bugs in various

samples.  Many of these are fixed by adding a parameter here or there

to some function, or slightly modifying the behavior of a function.

This file doesn't document all such changes, but will highlight

some of the more important ones.

General Changes:

---------------------------------------------

All the samples will compile for either Win16 or Win32 targets.

Most of the differences between the two environments are isolated

in the macros in inc\book1632.h.  Occasionally there will be

a #ifdef WIN32 or a #ifdef UNICODE in a sample where a macro wasn't

practical.

In order to make a single Win16/Win32 code base, all the code

compiled for Win16 is large model.  Therefore you will find no

"FAR" keywords anywhere, and an effort has been made to remove

"LP" pointer types and simply use "P", especially for sample-specific

types.

The makefile system has been overhauled to centralize all the rules

and compiler options into the files inole2a.mak and inole2b.mak.

All individual sample makefiles define their specific parameters

and include these two files to perform the compilation.  In addition,

all the samples (Cosmo, Patron, CoCosmo, etc.) that used to compile

into separate MDI and SDI directories now compile into just one.

There was little use of having both versions co-exist, and since

the same sort of provision was not made for Win16/Win32, Unicode/Ansi,

and Debug/Non-Debug, the MDI/SDI provision has been removed.

Running any MAKEALL.BAT will build whatever version is set by

the environment variables as described in BUILD.TXT.

Chapter 2

--------------------------------------------------

Due to differences in structure packing and alignment, files

written by a 16-bit version of Cosmo are not interchangeable

with the 32-bit version and vice-versa.  Cosmo will report

a failure in such cases.  This applies to all later chapters

as well.

Chapter 4

--------------------------------------------------

The MALLOC sample does not allow access to shared memory under

Win32.  This is a restriction of OLE 32-bits as the CoGetMalloc

function fails when passed MEMCTX_SHARED.  All applications should

use MEMCTX_TASK for all memory allocation purposes under Win32, and

should also do so under Win16 for portability.

OLE 32-bit uses registry entries of InProcServer32, LocalServer32,

and InProcHandler32.  This doesn't affect object users, like the

OBJUSER sample, but does affect the registation files.  It is very

important that your own applications register themselves appropriately

depending on whether they are 16- or 32-bits.  The new registry

keys allow you to register both types of modules together.

The EKOALA sample in this chapter has the IExternalConnection

interface implemented on the object.  This will demonstrate how

the AddConnection and RemoveConnection members of this interface

are called when LRPC stubs connect to the object.  More information

about stubs is found in the OLE 2 SDK document REMOTING.DOC.

Chapter 5

--------------------------------------------------

Due to differences in structure packing and alignment as well as

the differences between Win16 and Win32 DEVMODE structures, files

written by a 16-bit version of Patron are not interchangeable

with the 32-bit version and vice-versa.  Patron will report

a failure in such cases.

When the Smasher sample attempts to copy a compressed file back

over it's original, it used StgOpenStorage on the original file

and calls IStorage::CopyTo from the compressed file to copy

back to the original file.  This operation, however, doesn't

overwrite the original file, and as a result the individual streams

are not laid out sequentially as they are in the compressed file.

In order to get the fully defragmented file back to the original

filename, you need to copy the defragmented file back over the

original file not using the IStorage interface at all.  In order

to demonstrate the difference, a new sample is added to Chapter 5

called Fragmenter, which is found in CHAP05\FRAGMENT.

Chapter 8

--------------------------------------------------

This chapter's Patron example (and all those in later chapters) now

pay attention to the "Drag Delay" and "Drag Distance" values to

"debounce" the mouse before starting a drag & drop operation.  The

drag delay is the amount of time the mouse has to be held down in

the same position (defined as the mouse down point plus or minus

the "Drag Distance" value) before drag & drop starts.  This is so

a brief unwanted click in the pick region doesn't start the operation

right away.  The drag distance is the number of pixels around the

original mouse down point where the delay is meaningful, but if the

mouse moves ourside this rectangle before the delay has expired,

and the button is still held down, then a drag & drop operation

is started.

Chapters 9 & 10

--------------------------------------------------

Patron in this and all later chapters now pays attention to the

OLEMISC_RECOMPOSEONRESIZE flag.  Cosmo in Chapter 10 sets this

flag as a test for Patron.  When Patron resizes and embedded

object and this flag is set, it explicitly runs the server

(with OleRun) and requests a new rendering (see CTenant::SizeSet

in TENANT.CPP).

Note that if you attempt to use the Create From File feature

in Patron's Insert Object dialog with a Cosmo object, the creation

will fail.  Cosmo requires the IPersistFile interface in order

to support Create From File, so you need to use the Chapter 13

Cosmo for this feature to work.

Chapter 11

--------------------------------------------------

Polyline has the IRunnableObject interface added and has changed

the handling of the editing dialog box significantly.  A problem

arose where Polyline was depending on the existence of its editing

window for determining the size of the object.  When a container

opened a document with a Polyline object therein and asked Polyline

for its extents, there wasn't much on which to base the answer.

To correct this, Polyline implements IRunnableObject which allows

it to know when the object is "running" but not active.  When

Polyline is now run, it creates the dialog but leaves it hidden.

Only on IOleObject::DoVerb (PRIMARY) or (SHOW) will Polyline

show the dialog.  Closing the dialog then only hides it, and it

isn't actually destroyed until the Polyline object itself is

destroyed.

Chapter 12

--------------------------------------------------

Reconnecting a link that was already running when Patron opened a

file with a linked object didn't work.  The reason is that OleLoad

will not attempt to reconnect an already running object on loading

if OleLoad is not given an IOleClientSite pointer.  Since Patron

doesn't provide this pointer to OleLoad, it must call

IOleLink::BindIfRunning after loading the object to perform the

reconnect.

Chapter 13

--------------------------------------------------

General improvements have been made to Patron to handle linkings

to embeddings better and more consistently.  There were a number of

bugs fixed in functions like IOleClientSite::GetMoniker and in

moniker handling overall.

There is a version of Polyline added to this chapter to handle

linking to embeddings as well.  Objects that support this feature

must implement IOleObject::GetMoniker and IOleObject::SetMoniker

and must be registered without OLEMISC_CANTLINKINSIDE (which is set

for Polyline and Cosmo prior to Chapter 13).  Polyline also implements

the IExternalConnection interface to provide for proper shutdown of

the intermediate container that is running in linking to embedding

cases.

Chapters 15 & 16

--------------------------------------------------

Improvements have been made to Patron and Polyline for more robust

handling of inside-out objects as well as multiple active objects.

True handling of many such objects really requires some of the

features available in OLE Controls, but that's another whole topic...


UPDATE.TXT  (INOLE2 Sample)

Updates to Inside OLE 2 Book and Sample Code, January 1994

Pre-Release Win32 versions (through Chapter 2)

This file lists describe bugs found in the sample code of the

book Inside OLE 2 and corrections for those problems.  Updated

code is found on Compuserve, Internet, and the MSDN CD (this also

contains the book text).

There are three sections to this file:

    Compiler Errors:    Changes to the OLE 2 SDK that caused

                        compiler errors with original Inside OLE 2

                        samples.  Also some considerations for

                        different compilers.

    Bug Fixes:          Other changes to the source code to fix

                        a few major and a number of minor problems.

    Other Topics:       List of typographical errors in the book

                        text (MSDN CD version includes most

                        corrections already, but do double-check)

                        and other topics of interest, such as Win32

                        version information.

NOTE:  To operate properly with OLE 2.01 after updating the sources

to compile it is necessary to rebuild an OLE 2.01 version of the

OLE2UI library for the Inside OLE 2 samples.  Build a library named

"BOOKUI.DLL" according to the instructions in the SDK.  With this

new file replace the INOLE2\BUILD\BOOKUI.DLL file included with the

book.  A new version of the library is included with this revision

of the samples.

NOTE:  To compile Win16 versions of the code, do "SET WIN16=1" from

your command prompt (or put it in AUTOEXEC.BAT).  This only affects

the samples that have so far been ported, but is crucial to building

them properly for the Windows 3.1 target environment.

Please send additional bug reports and problems to the author at

kraigb@microsft.com on Internet.  CompuServe users must prefix the

address with ">INTERNET:"

---------------------------

Section 1:  Compiler Errors

---------------------------

The sample code of the book Inside OLE 2 was originally written

for the OLE 2.00 libraries.  The OLE 2.01 libraries included

a few minor changes that cause compilation errors with the original

book samples.

1.  Errors concerning IViewObject::Draw.  The OLE 2.01 SDK

    changed the prototype of IViewObject::Draw from using

    "const LPRECTL" to "LPCRECTL."  This affects HCOSMO and

    Polyline samples of chapter 11 and Poltilne sample of

    chapter 16, causing them to fail compiling.

    To correct the error, replace all occurances of

    "const LPRECTL" in declaration of CImpIViewObject::Draw

    to "LPCRECTL" to match OLE 2.01.  This occurs in the

    HCOSMO.H and IVIEWOBJ.CPP files of HCOSMO in chapter 11,

    and the POLYLINE.H and IVIEWOBJ.CPP files of Polyline in

    chapters 11 and 16.  Note that there are also affected

    files in the INTERFAC directory, IVIEWOBJ.H and IVIEWOBJ.CPP,

    although these will not show in compilations.

2.  Errors concerning OleUIAddVerbMenu in Patron samples of

    chapters 9, 12, 13, 14, and 15.

    The OLE 2.01 UI library added a parameter to this function,

    an added "idVerbMax" that indicates the largest number the

    container allows for a verb menu item identifier.  This

    new parameter occurs immediately after the "idVerbMin" parameter.

    In the Patron directories of chapters 9, 12, 13, 14, and 15

    in the files PAGE.CPP and TENANT.CPP, the parameter IDM_VERBMAX

    is added after the IDM_VERBMIN parameter (both are defined

    in resource.h).  The functions affected are CTenant::AddVerbMenu

    (TENANT.CPP) and CPage::FQueryObjectSelected (PAGE.CPP).

3.  Errors concerning OleGetObjectDescriptorFromOleObject affecting

    Patron samples in chapters 9, 12, 13, 14, and 15.

    The OLE 2.01 UI library added a parameter to the end of

    this function: an LPSIZEL that contains the extents of the

    object.  The OLE 2.00 code appeared as follows:

        stm.hGlobal=OleStdGetObjectDescriptorDataFromOleObject

            (m_pIOleObject, NULL, m_fe.dwAspect, ptl);

    The corrections for OLE 2.01 require the declaration and

    initialization of a new SIZEL variable for the last parameter:

        //Declare new variable

        SIZEL   szl;

        ...

        //Initialze

        SETSIZEL(szl, (10*(m_rcl.right-m_rcl.left))

            , (10 * (m_rcl.bottom-m_rcl.top)));

        //Add to parameter list.

        stm.hGlobal=OleStdGetObjectDescriptorDataFromOleObject

            (m_pIOleObject, NULL, m_fe.dwAspect, ptl, &szl);

    This correctly computes the size of the object in question

    and stores those extents in szl and in the object descriptor.

    The changes affect the function CTenant::CopyEmbeddedObject

    in chapters 9, 12, 13, 14, and 15.  The function is found

    in all the TENANT.CPP files in the PATRON directories

    of these chapters.  Note that it also affects the function

    CTenant::CopyLinkedObject.in chapters 12, 13, 14, and 15,

4.  Errors concerning IDS_CLOSE in Cosmo samples of chapters 10, 13,

    14, and 16.  The OLE2UI library of OLE 2.01 declared an IDS_CLOSE

    symbol that conflicts with one of the same name declared in Cosmo's

    RESOURCE.H file.

    To correct the problem the IDS_CLOSE in RESOURCE.H is renamed

    to "IDS_CLOSE2" and occurances of that symbol in COSMO.RC are

    changed to match.  This affects these two files in chapters

    10, 13, 14, and 16.

5.  Errors concerning GETICON.H in Patron samples of chapters

    14 and 15.  This file was necessary to include in container

    applications that supports the Convert dialog in OLE 2.00.

    The OLE 2.01 SDK removed the dependency on this file, so it

    no longer has to be included.  Therefore the #include statement

    in the TENANT.CPP files of Patron in chapters 14 and 15

    have been commented out.

    To correct the problem, the line "#include <geticon.h>"

    is commented out at the top of the TENANT.CPP files of

    Patron in chapters 14 and 15.

6.  Linker errors on Windows NT hosted development environments

    concerning the CLASSLIB library.  A filename in the FILES.LST

    of CLASSLIB has an extra character causing it to appear as a

    long filename, which on a Windows NT system is valid but does

    not exist.

    The first file in FILES.LST is changed from "cstrtable.obj"

    to "cstrtabl.obj" to correct the problem, that is, remove the

    extra 'e'.

7.  The function declarations for LibMain and WEP in all DLLs

    are slightly incorrect and have been updated.  These can

    ause compiler errors on non-Microsoft compilers.  LibMain should

    return an int (not a HANDLE) and take an HINSTANCE as the first

    parameter (not a HANDLE either).  WEP should return an int rather

    than void.  WEP should always return a zero to provide some return

    value although that value is not used.

---------------------------------

Section 2:  Sample Code Bug Fixes

---------------------------------

1.  GP Fault with Patron sample during Activate As,

    chapters 14 and 15.

    The problem lies in the function CTenant::Close with the fReopen

    flag.  When this function determines that there are no references

    to the tenant IStorage, it normally resets the internal state of

    the tenant to defaults, including setting the member m_pIStorage

    to NULL.  However, if fReopen is TRUE, this NULL assignment is

    skipped.

    The crash occurs when m_pIStorage is left non-NULL but the

    storage itself has been destroyed.  Thus m_pIStorage is an

    invalid pointer.

    To correct this problem it is necessary to insure that the

    m_pIStorage variable is set to NULL any time the actual

    reference count on it is zero

    A condition in the function CTenant::Close in TENANT.CPP of

    both chapters is removed to correct the problem:

    The lines:

        if (!fReopen)

            m_pIStorage=NULL;

    are replaced with just:

        m_pIStorage=NULL;

    The fReopen flag was used in an attempt to provide some

    optimization when performing Activate As, but is not

    necessary.  The updated sample code has removed the flag

    entirely.  This affects PAGE.CPP, TENANT.CPP, and TENANT.H

    files in Patron of chapters 14 and 15.

2.  Convert To function doesn't seem to work in Patron samples

    of chapters 14 and 15.  The problem occurs in the function

    CPage::FConvertObject in the PAGE.CPP file of both chapters.

     The problem is that CPage::FConvertObject is releasing the

     page's IStorage pointer without commiting it.  Since Patron

     uses transacted storage, this discards all changes including

     the conversion that just happened.

     The code in error is as follows:

         if ((CF_SELECTCONVERTTO & ct.dwFlags)

             && !IsEqualCLSID(ct.clsid, ct.clsidNew))

             {

             LPSTORAGE   pIStorage;

             //This should be the only close necessary.

             m_pTenantCur->RectGet(&rcl, FALSE);

             m_pTenantCur->StorageGet(&pIStorage);

             m_pTenantCur->Close(FALSE, FALSE);

             hr=OleStdDoConvert(pIStorage, ct.clsidNew);

             pIStorage->Release();

         ...

     This code does not commit the changes to the storage affected

     by OleStdDoConvert before releasing pIStorage.  To correct this

     problem, include a call to pIStorage->Commit:

         if ((CF_SELECTCONVERTTO & ct.dwFlags)

             && !IsEqualCLSID(ct.clsid, ct.clsidNew))

             {

             LPSTORAGE   pIStorage;

             //This should be the only close necessary.

             m_pTenantCur->RectGet(&rcl, FALSE);

             m_pTenantCur->StorageGet(&pIStorage);

             m_pTenantCur->Close(FALSE);

             hr=OleStdDoConvert(pIStorage, ct.clsidNew);

             pIStorage->Commit(STGC_ONLYIFCURRENT);

             pIStorage->Release();

         ...

    Note that the second parameter to CTenant::Close has also been

    removed reflecting Bug Fix #1.

3.  Unitialized variable in CLASSLIB causes string allocation

    failure with non-Microsoft compilers.  In the file

    CSTRTABL.CPP, function CStringTable::FInit, initialize the

    variable cchUsed to zero:

        UINT        cchUsed=0;

4.  The CImpIPolyline::WriteToFile function in PolyLine chapter 4

    returns an incorrect value.  In this function in the file

    IPOLYLIN.CPP, the line:

        return (m_pObj->m_fDirty) ?

    is changed to read:

        return (!m_pObj->m_fDirty) ?

5.  The Polyline samples of chapters 5, 6, 11, and 16 attempt to

    initialize a clipboard format with an invalid string.  The

    following line is found in the CPolyline::CPolyline function

    in the POLYLINE.CPP file of chapters 5, 6, 11, and 16:

        m_cf=RegisterClipboardFormat(PSZ(IDS_STORAGEFORMAT));

    This call is incorrectly made before the stringtable used

    by the PSZ macro is initialized.  To correct the problem,

    the call is moved into CPolyline::FInit after the stringtable

    is initialized:

        ...

        if (!m_pST->FInit(IDS_POLYLINEMIN, IDS_POLYLINEMAX))

            return FALSE;

        m_cf=RegisterClipboardFormat(PSZ(IDS_STORAGEFORMAT));

        ...

    In chapter 6 it also requires movement of lines that depend on

    m_cf from the constructor until after the code above in

    CPolyline::FInit.  This affects code that initializes the

    FORMATETC arrays elements m_rgfeGet[0] and m_rgfeSet[0].

6.  The return value from CImpIOleObject::GetClientSite in the

    IOLEOBJ.CPP file of Cosmo, chapters 10, 13, 14, and 16 is changed

    to NOERROR from ResultFromScode(E_NOTIMPL).

7.  Component Cosmo, Chapter 6, fails to release the Polyline's

    IDataObject interface in the destructor CCosmoDoc::~CCosmoDoc

    after calling IDataObject::DUnadvise.  In DOCUMENT.CPP the

    lines below:

        if (SUCCEEDED(hr))

            pIDataObject->DUnadvise(m_dwConn);

    are changed to read:

        if (SUCCEEDED(hr))

            {

            pIDataObject->DUnadvise(m_dwConn);

            pIDataObject->Release();

            }

8.  The Data Transfer Object of Chapter 7 does not call AddRef on

    IStorage and IStream objects returned from CImpIDataObject::GetData

    (IDATAOBJ.CPP).  In this function the following lines are added

    after the line "*pSTM=pRen->stm;":

        /*

         * Must remember to AddRef any other objects

         * in the STGMEDIUM:  storages and streams.

         */

        if (TYMED_ISTORAGE==pSTM->tymed)

            pSTM->pstg->AddRef();

        if (TYMED_ISTREAM==pSTM->tymed)

            pSTM->pstm->AddRef();

    This will correctly insure that multiple copies of a STGMEDIUM

    containing a storage element are each counted such that the

    storage element does not become invalid prematurely.

9.  The Patron samples of chapters 5 and beyond do not work correctly

    with some printer drivers.  The problem is that Patron is not

    sensitive to drivers that store driver-specific information at the

    end of the DEVMODE structure.  In making copies of the DEVMODE

    structure, Patron truncates that driver-specific data.

    This will cause the CreateDC and CreateIC functions to fail, which

    manifests in Patron as a blank document window with no visible

    pages.  It will also cause the PrintDlg function to GP Fault inside

    the printer driver when that driver attempts to access driver-

    specific data that does not exist.  The problems only appear on

    some printer drivers because other use no driver-specific data and

    are thus unaffected by the truncation.

    The correction identically affects the implementation of the CPages

    class of Patron in chapters 2, 5, 7, 8, 9, 12, 13, 14, and 15.  CPages

    is defined in PAGES.H and implemented in PAGES.CPP.  The functions of

    interest are CPages::DevModeSet, CPages::DevModeGet in all chapters,

    CPages::ConfigureForDevice in chapter 5, and CPages::DevReadConfig

    in all chapters except 5.  These functions are modified to be

    sensitive to the variable-length nature of DEVMODE in order to work

    with all printer drivers, and the changes are too complex to be

    listed here.  The listings of these functions on pages 257-259 of

    Inside OLE 2 are thus incorrect as well.

    NOTE:  the changes render files generated by previous versions of

    Patron unreadable by a new version.  This is, after all, a sample

    not meant for production work.  Files may, however, be converted

    by running an old version of Patron from chapter 14 or 15, loading the

    file, and transferring all objects to a new document opened in another

    version of Patron from chapter 15 or 14 (opposite of the old version

    you are running), and saving that new document.

    On a related not, printing page ranges from Patron always prints

    the range offset by one.  Corrections to this problem have been

    made in the CPages::Print function of the PAGEWIN.CPP file in all

    chapters.

10. The Cosmo application will fail to load an object when activated

    if used in conjunction with the custom object handler HCOSMO

    from chapter 11.  This will occur when either reloading an object

    from a save container file or reactivating the object after it has

    been created and deactivated once already.

    The problem is that HCOSMO imcorrectly keeps the object stream open

    in the object's IStorage so it can perform low-memory saves without

    having to open the stream again.  However, the OLE 2 implementation

    of STORAGE.DLL only allows one process to open any one particular

    stream using the same IStorage pointer as a parent.  Therefore when

    the Cosmo application receives the IStorage pointer and attempts

    to open the same stream, it fails.  This shows up in HCOSMO's

    implementation of IOleObject::DoVerb where it delegates the call

    to the default handler.  In this case the default handler passes

    back Cosmo's error code, which is STG_E_READFAULT.

    Since the HCOSMO handler never makes changes to the object, it will

    never have to save anything in a low-memory situation.  Specifically,

    it will never have to save any changes to the storage when its

    IPersistStorage::Save is called with the fSameAsLoad flag set to TRUE.

    Since this is the only case where an IPersistStorage implementation

    should not attempt to allocate memory, it is totally unnecessary

    for HCOSMO to cache any pointers to the stream.

    To correct the problem, remove the m_pIStorage and m_pIStream

    members from the CFigure class defined in HCOSMO.H and FIGURE.CPP.

    Then remove any code that deals with them in HCOSMO's implementation

    of IPersistStorage found in IPERSTOR.CPP:

        a.  In CImpIPersistStorage::InitNew,  remove the "HRESULT hr;"

            local variable and the NULL check on m_pObj->m_pIStorage

            at the top of the function.  Then remove all code between

            and including the lines:

                hr=pIStorage->CreateStream("CONTENTS", STGM_DIRECT

            and

                m_pObj->m_pIStorage=pIStorage;

            The remainder of the code is still important to initailize

            the handler's internal storage.

        b.  In CImpIPersistStorage::Load, remove the NULL check on

            m_pObj->m_pIStorage.  After the call to pIStream->Read,

            add the line:

                pIStream->Release();

            Then remove the lines that hold the IStorage:

                pIStorage->AddRef();

                m_pObj->m_pIStorage=pIStorage;

        c.  In CImpIPersistStorage::Save, replace the "if (fSameAsLoad)"

            condition with:

                if (fSameAsLoad)

                    {

                    m_pObj->m_pDefIPersistStorage->Save(pIStorage

                        , fSameAsLoad);

                    return NOERROR;

                    }

            Move all the remaining code in the "else" condition

            out of the condition completely and add the following

            line just before the call to WriteFmtUserTypeStg:

                WriteClassStg(pIStorage, CLSID_Cosmo2Figure);

        d.  In CImpIPersistStorage::SaveCompleted, remove all code

            except for:

                m_pObj->m_pDefIPersistStorage->SaveCompleted(pIStorage);

                return NOERROR;

        e.  In CImpIPersistStorage::HandsOffStorage, remove all code

            except for:

                m_pObj->m_pDefIPersistStorage->HandsOffStorage();

                return NOERROR;

11. The "(c)" in all ABOUT.DLG files is replaced with the ANSI 169

    copyright character.

12. The CClient::QueryCloseAllDocuments function in the CCLIENT.CPP

    file of CLASSLIB may cause a GP Fault when closing an application

    with one or more documents iconized.  The problem may be corrected

    by adding the line "hPrevClose=NULL" in the code below:

    BOOL CClient::QueryCloseAllDocuments(BOOL fClose)

        {

        ...

        for ( ; hWndT; hWndT=GetWindow(hWndT, GW_HWNDNEXT))

            {

            if (NULL!=hPrevClose)

                {

                pDoc=(LPCDocument)SendMessage(hPrevClose

                    , DOCM_PDOCUMENT, 0, 0L);

                CloseDocument(pDoc);

                hPrevClose=NULL;

                }

        ...

        //Close the last window as necessary.

        if (fClose && NULL!=hPrevClose)

            {

            pDoc=(LPCDocument)SendMessage(hPrevClose, DOCM_PDOCUMENT, 0, 0L);

            CloseDocument(pDoc);

            hPrevClose=NULL;

            }

        ...

13. STASTRIP, file INIT.C, contains a call to LocalAlloc where the

    return value is incorrectly cast immediately into a far pointer:

        pST->ppsz=(LPSTR *)LocalAlloc(...)

    This is changed to first cast the return value into a near pointer

    then into a far pointer to insure the conversion happens properly:

        pST->ppsz=(LPSTR *)(char *)LocalAlloc(...)

14. The implementation of IEnumRECT::Next in both CHAP03\ENUMCPP and

    CHAP03\ENUMC samples, file IENUM.C[PP] is incorrect on two counts.

    First, an enumerator can accept a NULL in the last parameter

    to Next (called pceltFetched in the OLE 2 documentation, pdwRects

    in these samples) if the first parameter (celt in docs, cRects

    in samples) is one.  Therefore the code:

        if (NULL==pdwRects)

            return FALSE;

        *pdwRects=0L;

    is changed to read:

        if (NULL==pdwRects)

            {

            if (1L!=cRect)

                return FALSE;

            }

        else

            *pdwRects=0L;

    Second, the value stored in pceltFetched (pdwRects) is incorrect.

    The line:

        *pdwRects=(cRectReturn-cRect);

    is changed to:

        if (NULL!=pdwRects)

            *pdwRects=cRectReturn;

    The same changes affect the IENUM.CPP files in the INTERFACE,

    CHAP06\POLYLINE, CHAP06\DDATAOBJ, CHAP06\EDATAOBJ, and

    CHAP07\DATATRAN directories as well.

15. The CStringTable in CLASSLIB file CSTRTABL.CPP will create an

    array of invalid string pointers in CStringTable::FInit if the

    call to _frealloc returns a different memory block.  To avoid

    this problem simply delete the following lines:

        //Now reallocate the string memory to however much we used, plus 1

        psz=(LPSTR)_frealloc(m_pszStrings, cchUsed+1);

        if (NULL!=psz)

            m_pszStrings=psz;

    This wastes a little memory, but is simpler than trying to recompute

    all the string pointers.  CLASSLIB is, after all, meant to be simple

    for the purposes of sample code.

------------------------

Section 3:  Other Topics

------------------------

1.  Corrections to Inside OLE 2 printed text.

    Page 82-:  The exact implementations of CImpIEnumRECT::Next are

    Page 83;   incorrect according to Bug Fix #14 above.  Also, on page

    Page 92-   83 there should be no space between "book" and "1632"

    Page 93    in the "#include <book 1632.h>"

    Page 105:  The second use of QueryInterface in the Transitive

               property should read

                   "pInterface2->QueryInterface(IInterface3)"

               The book has IInterface2 as the parameter to

               QueryInterface, which is incorrect.

    Page 157:  A space is missing between "LPLPVOID" and "ppv" in the

               last parameter of the declaration CKoala::QueryInterface.

    Page 161:  The prototype for WEP should return an int and not VOID.

    Page 197:  The line of code under "if (IsEqual(riid, IID_IAnimal))"

               should read "*ppv=(LPVOID)m_pAnimal".  In the text the

               underscore is mistakenly a space, dash, and space.

    Page 199:  A space is missing between "LPLPVOID" and "ppv" in the

               last parameter of the declaration CKoala::QueryInterface.

    Page 243:  The second sentence in the second paragraph should read:

               "The Structured Storage definition of IStream allows

               streams to contain up to 2^64 (2 raised to the 64th power)

               addressable bytes of data."  The text incorrectly reads

               "264" instead of "2^64."

    Page 257-: The code listing of CPages::DevModeSet, CPages::DevModeGet,

    Page 259   and CPages::ConfigureForDevice will change according to

               Bug Fix #9 above.

    Page 331:  The description of IDataObject::GetCanonicalFormatEtc

               is incorrect.  For correct details, see the OLE 2

               Programmer's Reference.

    Page 289-: Both LibMain and WEP functions should return an int as

    Page 290   described in Compile Fix #7.

    Page 316:  The implementation of CImpIEnumFormatEtc::Next is

               incorrect according to Bug fix #14 above.

    Page 365:  The "const LPRECTL" parameters in IViewObject::Draw

               should be of type "LPCRECTL" to match OLE 2.01 as

               described in Compiler Error #1 above.

    Page 544-: In OLE 2.01 there is an additional parameter to

    Page 546   OleUIAddVerbMenu called "idVerbMax" which comes immediately

               after "idVerbMin."  This was an addition to OLE 2.01 which

               is not present in OLE 2.00 as described in Compiler Error

               #2 above.

    Page 554:  Under OLE 2.01 the OleStdGetObjectDescriptorFromOleObject

               function used in the code sample requires an additional

               LPSIZEL as the last parameter as described in Compiler

               Error #3 above.

    Page 630:  The right curly brace just above the "else" at the bottom

               of the page should be indented to align with the call

               to ModifyMenu above it.

    Page 663-: The bottom of page 663 mentions how a handler should

    Page 665   hold onto open streams for low-memory save situations.

               This is ONLY important for elements that are entirely

               manipulated by the handler and never touched by the server.

               The handler should not cache or hold pointers to the

               same elements the server must access as described

               in Bug Fix #10 above.  If a handler manipulates and

               changes data unaffected by the server, it must fulfill

               the IPersistStorage contract for only those formats.  The

               server is responsible for all others that it modifies.

    Page 668:  The "const LPRECTL" parameters in IViewObject::Draw

               should be of type "LPCRECTL" to match OLE 2.01 as

               described in Compiler Error #1 above.

    Page 687:  There should not be "//" before the large bold

               "IOLEOBJ.CPP" in this code listing.  The label is not

               part of the code.

    Page 788:  Same problem with OleStdGetObjectDescriptorFromOleObject

               as described above for page 554.

    Page 814:  Same problem with OleUIAddVerbMenu as described above for

               pages 544-546.

    Page 817:  Remove the second parameter to pTenantCur->Close.  It should

               read "pTenantCur->Close(FALSE);"  This matches the change

               necessary for Bug Fix #1 above.

    Page 817:  There should be a call to

               pIStorage->Commit(STGC_ONLYIFCURRENT) immediately after

               the call to OleStdDoConvert and before the call to

               pIStorage->Release, as described in Bug Fix #2 above.

    Page 819:  Remove the second parameter to pTenantCur->Close.  It should

               read "pTenantCur->Close(FALSE);"  This matches the change

               necessary for Bug Fix #1 above.

    Page 861:  The second sentence of the third paragraph under "Active

               vs. UI Active and Inside-Out Objects" should read:  "The

               answer...as they are visible-end users DO NOT have to

               double-click..."  The DO NOT is important.

2.  Clarification of 64K limit on IMalloc allocations

    Inside OLE 2 states on page 127 that any single allocation

    done through the default shared or task allocators in OLE 2

    are limited to 64K.  This is true for both OLE 2.00 and OLE 2.01.

    The OLE 2 specifications and Programmer's Refernece state that

    "If the allocation is greater than 64K, a huge pointer is

    returned."  This seems to contradict the actual allocators

    implemented in OLE 2.

    The reason is that the specs and documentation provide the

    standard definition of the IMalloc interface, not the specs

    nor the documenation for OLE 2's implementation of that

    interface on its standard shared and task allocators.  While

    IMalloc is not inherently limited to 64K in the specifications,

    OLE 2's default implementation is limited.

    An application can implement its own allocator and provide an

    IMalloc interface that can allocate blocks larger than 64K, in

    which case that custom allocator must return a huge pointer for

    that allocation.

3.  HCOSMO handler limitations.  The sample handler HCOSMO from chapter

    11 of Inside OLE 2 is meant to be used with the version of Cosmo

    from Chapter 10.  There are no provisions for using this handler

    with any other version of Cosmo, specifically those in chapters 13,

    14, and 16.  With those later versions, you may encounter GP Faults.

    To bypass problems, be sure that OLE2.DLL is registered for Cosmo's

    InProcHandler instead of HCOSMO.DLL.  The .REG files in the CHAP13,

    CHAP14, and CHAP16 directories will make this change.  Be sure to

    merge those files with your registration database before using any

    sample from the corresponding chapter.

4.  Information on Windows NT ports of Inside OLE 2 Samples

    This revision of the sample code in the following directories

    contain full pre-release Win32 ports of their respective samples:

        INC

        BTTNCUR

        GIZMOBAR

        STASTRIP

        CLASSLIB

        CHAP02\SKEL

        CHAP02\COSMO10

        CHAP02\COSMO

        CHAP02\PATRON

    These are intended to serve as examples of how the remainder of

    the code would be ported.  Mostly there are changes to remove

    "FAR PASCAL" function types, change functions like "MoveTo" to

    "MoveToEx" and correcting minor oversights in parameter packing

    and so forth.  Note that several new macros and definitions have

    been added to the file \INC\BOOK1632.H to handle the updated

    sources that compile for both Win3.1 and Windows NT target

    environments.  If you encounter a strange function or macro in

    the sources that you don't recognize, check in this file.

    The samples above have been compiled with Visual C++ 1.1 for

    Windows NT and run under Windows NT version 3.1.  There is, however,

    no guarantee for perfect compilations or execution of these

    pre-release samples.

    Note that the .LIB files in the LIB directory and the .DLL files

    in the BUILD directory are Win16 versions.

    These samples are currently ANSI.  A final Unicode Win32 port of

    the sample code will be available after OLE 2 on Windows NT has

    shipped final.  Other interim releases may be available before

    then, but no guarantees.


 OLEANSI

Developer's Notes.

[Overview]

    Welcome to the world of UNICODE!  32bit OLE2 is now a native UNICODE
    subsystem for Microsoft's Win32 platforms.  OLE2ANSI is a .DLL that will
    'thunk' existing ANSI OLE2 APIs and Interfaces in your current application
    to/from UNICODE.

    While this sample code does make converting existing ANSI OLE2 application
    to UNICODE OLE2 almost painless; it does exact some overhead.  If at all
    possible, ANSI applications should be ported to UNICODE.

    OLE2ANSI is NOT part of the OLE2 subsystem, it's sample code of how a
    generic ANSI <--> UNICODE thunk for OLE2 could be written.  Feel free to
    use fragments of code for you development needs.

[Using Ole2Ansi.Dll]

    1. Change the "TARGET = ole2ansi" value in the file 'makefile' to an
        unique name to avoid conflicts.  Any references to "OLE2ANSI" in
        this 'readme.txt' file actually refers to your unique target name.

    2. Build the Ole2Ansi sample code with the provided 'makefile'.

    3. Add -DOLE2ANSI to your application's compiler option list.

    4. Add OLE2ANSI.LIB to your application's link library list.  OLE2ANSI.LIB
        must be placed before OLE32.LIB and OLEAUT32.LIB.

    5. Recompile/link your application.

[Suggestions for performance enhancements]

    1. Use UNICODE strings where possible to avoid some (or all) wrapped API's and

        interfaces.

    2. Manually wrap interfaces via Ole2AnsiWFromA and retain for the life of the
        ANSI object.   Pass the wrapped interface (which are now UNICODE) directly

        to OLE2's APIs and methods.

    3. Merge the Ole2Ansi source in your application.  Note that you will need to
        rename some of the OLE2 APIs in your source code.   For example, if your
        application calls CLSIDFromString(), it will need to be changed to
        CLSIDFromStringA().

[Release Notes]

1. Ole2Ansi will now detect bad applications that do the following and recover. 	CreateObject(&pObj); 	pObj->QI(IID_IUnknown, &pUnk); 	pUnk->Release(); 	pUnk->Release();

     A message will be displayed to the debugger.

        2. Added two new API's to permit convertion of Interfaces to/from ANSI/UNICODE: 	HRESULT Ole2AnsiAFromW(REFIID iid, LPUNKNOWN pWide, LPUNKNOWN * pANSI); 	HRESULT Ole2AnsiWFromA(REFIID iid, LPUNKNOWN pANSI, LPUNKNOWN * pWide);

        3. Must set HKEY_CURRENT_USER\Software\Microsoft\Ole2Ansi\Trace to DWORD Hex FFFF to 	    enable Ole2Ansi tracing.


 MAKEFILE  (OLEANSI Sample)

!include <$(MSTOOLS)\samples\ole\include\olesampl.mak>

#

#  This makefile will build the library Ole2Ansi.Dll.

#

#

#  To Build:

#

#    Make sure the environment variables Include and Lib are defined and

#    a C++ compiler is in the current path.

#

#    Then just type "nmake"

#

#

#Add '#' to the next line for 'noisy' operation

!CMDSWITCHES +s

#

#Compiler flags

#Use "SET NODEBUG=1" to compile non-debug version.

#

!IFDEF NODEBUG

DEFS = -DMAKEDLL -DWIN32 -D_WIN32

!ELSE

DEFS = -DMAKEDLL -DDBG -DWIN32 -D_WIN32

!ENDIF

.SUFFIXES: .h .obj .exe .cpp .rc .def

TARGET  = ole2ansi

goal:   $(TARGET).dll

clean:

    del *.obj

    del *.exp

    del *.lib

    del *.dll

    del *.pch

#  String pooling ok for Ole2Ansi.

cflags = -Gf $(cflags)

PCHFLAGS= -Yuole2ansi.h -Fpole2ansi.pch

INCLS    = ole2ansi.h

PRECOMPOBJ = ole2ansi.obj

OBJS1    = AnsiComp.obj WideComp.obj AnsiStor.obj WideStor.obj

OBJS2    = AnsiDvOb.obj WideDvOb.obj AnsiMoni.obj WideMoni.obj

OBJS3    = AnsiOle1.obj WideOle1.obj AnsiOle2.obj WideOle2.obj AnsiOle3.obj

OBJS4    = AnsiCtl.obj WideCtl.obj ConvCtl.obj WrapCtl.obj

OBJS5    = AnsiDisp.obj WideDisp.obj Thunk.obj Globals.obj

OBJS6    = AnsiOA.obj Convert.obj Convert2.obj Wrapper.obj Trace.obj Debug.obj

OBJS     = $(OBJS1) $(OBJS2) $(OBJS3) $(OBJS4) $(OBJS5) $(OBJS6)

LIBS     = ole32.lib oleaut32.lib kernel32.lib user32.lib uuid.lib advapi32.lib $(libcdll)

#####

ole2ansi.pch: ole2ansi.h ole2ansi.cpp

    echo +++++++++

    echo Precompiling ole2ansi.h

    $(cc) $(cflags) $(cdebug) $(DEFS) -Ycole2ansi.h -Fpole2ansi.pch -Foole2ansi ole2ansi.cpp

.cpp.obj:

    echo ++++++++++

    echo Compiling $*.cpp

    $(cc) $(cflags) $(cdebug) $(DEFS) $(PCHFLAGS) $*.cpp

.c.obj:

    echo ++++++++++

    echo Compiling $*.c

    $(cc) $(cflags) $(cdebug) $(DEFS) $*.c

#Build import library

$(TARGET).lib: ole2ansi.pch $(OBJS) ole2ansi.def

    echo ++++++++++

    echo Building Import Library

!IF "$(CPU)" != "i386"

    @copy ole2ansi.rsc ole2ansi.def

!ENDIF

    $(implib) -machine:$(CPU)   \

    -def:ole2ansi.def           \

    $(OBJS)                     \

    $(PRECOMPOBJ)               \

    -out:$(TARGET).lib

    if not exist ..\lib mkdir ..\lib

    copy $(TARGET).lib ..\lib

#Build a linker response file depending on build flags

$(TARGET).dll: ole2ansi.pch $(TARGET).lib $(OBJS) ole2ansi.def

    echo ++++++++++

    echo Linking $@

    $(link) $(ldebug) $(dlllflags) \

        /Out:$(TARGET).dll      \

        $(OBJS)                 \

        $(PRECOMPOBJ)           \

        $(OLELIBS)              \

        $(TARGET).exp           \

        $(LIBS)

    if not exist ..\bin mkdir ..\bin

    copy $(TARGET).dll ..\bin


 ANSICOMP.H  (OLEANSI Sample)

//+--------------------------------------------------------------------------

//

//  Copyright (C) 1994, Microsoft Corporation.  All Rights Reserved.

//

//  File:       AnsiComp.cpp

//

//  Contents:   ANSI Wrappers for Unicode CompObj Interfaces and APIs.

//

//  Classes:    CEnumStringA - ANSI wrapper object for IEnumString.

//

//  History:    01-Nov-93   v-kentc     Created.

//

//---------------------------------------------------------------------------

interface IStreamA;

typedef IStreamA * LPSTREAMA;

typedef char FAR* BSTRA;

/*---------------------------------------------------------------------*/

/*                            IEnumStringA                             */

/*---------------------------------------------------------------------*/

#undef  INTERFACE

#define INTERFACE   IEnumStringA

DECLARE_INTERFACE_(IEnumStringA, IUnknown)

{

// *** IUnknown methods ***

STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppvObj) PURE;

STDMETHOD_(ULONG,AddRef) (THIS)  PURE;

STDMETHOD_(ULONG,Release) (THIS) PURE;

// *** IEnumString methods ***

STDMETHOD(Next) (THIS_ ULONG celt,

   char * * rgelt,

   ULONG * pceltFetched) PURE;

STDMETHOD(Skip) (THIS_ ULONG celt) PURE;

STDMETHOD(Reset) (THIS) PURE;

STDMETHOD(Clone) (THIS_ IEnumStringA * * ppenm) PURE;

};

typedef IEnumStringA * LPENUMSTRINGA;

/*---------------------------------------------------------------------*/

/*                            IMarshalA                                */

/*---------------------------------------------------------------------*/

#undef  INTERFACE

#define INTERFACE   IMarshalA

DECLARE_INTERFACE_(IMarshalA, IUnknown)

{

// *** IUnknown methods ***

STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE;

STDMETHOD_(ULONG,AddRef) (THIS)  PURE;

STDMETHOD_(ULONG,Release) (THIS) PURE;

// *** IMarshal methods ***

STDMETHOD(GetUnmarshalClass)(THIS_ REFIID riid, LPVOID pv,

DWORD dwDestContext, LPVOID pvDestContext,

DWORD mshlflags, LPCLSID pCid) PURE;

STDMETHOD(GetMarshalSizeMax)(THIS_ REFIID riid, LPVOID pv,

DWORD dwDestContext, LPVOID pvDestContext,

DWORD mshlflags, LPDWORD pSize) PURE;

STDMETHOD(MarshalInterface)(THIS_ LPSTREAMA pStm, REFIID riid,

LPVOID pv, DWORD dwDestContext, LPVOID pvDestContext,

DWORD mshlflags) PURE;

STDMETHOD(UnmarshalInterface)(THIS_ LPSTREAMA pStm, REFIID riid,

LPVOID FAR* ppv) PURE;

STDMETHOD(ReleaseMarshalData)(THIS_ LPSTREAMA pStm) PURE;

STDMETHOD(DisconnectObject)(THIS_ DWORD dwReserved) PURE;

};

typedef IMarshalA * LPMARSHALA;

/*---------------------------------------------------------------------*/

/*                            IStdMarshalInfoA                                */

/*---------------------------------------------------------------------*/

#undef  INTERFACE

#define INTERFACE   IStdMarshalInfoA

DECLARE_INTERFACE_(IStdMarshalInfoA, IUnknown)

{

// *** IUnknown methods ***

STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE;

STDMETHOD_(ULONG,AddRef) (THIS)  PURE;

STDMETHOD_(ULONG,Release) (THIS) PURE;

// *** IStdMarshalInfo methods ***

STDMETHOD(GetClassForHandler)(THIS_ DWORD dwMemctx, LPVOID pvMemctx,

LPCLSID pclsid) PURE;

};

typedef IStdMarshalInfoA * LPSTDMARSHALINFOA;

#ifndef NOERRORINFO

/*---------------------------------------------------------------------*/

/*                     IErrorInfoA/ICreateErrorInfoA                   */

/*---------------------------------------------------------------------*/

#undef  INTERFACE

#define INTERFACE   IErrorInfoA

DECLARE_INTERFACE_(IErrorInfoA, IUnknown)

{

// *** IUnknown methods ***

STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE;

STDMETHOD_(ULONG,AddRef) (THIS)  PURE;

STDMETHOD_(ULONG,Release) (THIS) PURE;

// *** IErrorInfo methods ***

STDMETHOD(GetGUID)(THIS_ GUID *pguid) PURE;

STDMETHOD(GetSource)(THIS_ BSTRA *pbstrSource) PURE;

STDMETHOD(GetDescription)(THIS_ BSTRA *pbstrDescription) PURE;

STDMETHOD(GetHelpFile)(THIS_ BSTRA *pbstrHelpFile) PURE;

STDMETHOD(GetHelpContext)(THIS_ DWORD *pdwHelpContext) PURE;

};

typedef IErrorInfoA * LPERRORINFOA;

#undef  INTERFACE

#define INTERFACE  ICreateErrorInfoA

DECLARE_INTERFACE_(ICreateErrorInfoA, IUnknown)

{

// *** IUnknown methods ***

STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE;

STDMETHOD_(ULONG,AddRef) (THIS)  PURE;

STDMETHOD_(ULONG,Release) (THIS) PURE;

// *** ICreateErrorInfo methods ***

STDMETHOD(SetGUID)(THIS_ REFGUID rguid) PURE;

STDMETHOD(SetSource)(THIS_ LPSTR szSource) PURE;

STDMETHOD(SetDescription)(THIS_ LPSTR szDescription) PURE;

STDMETHOD(SetHelpFile)(THIS_ LPSTR szHelpFile) PURE;

STDMETHOD(SetHelpContext)(THIS_ DWORD dwHelpContext) PURE;

};

typedef ICreateErrorInfoA * LPCREATEERRORINFOA;

#endif //!NOERRORINFO

//+--------------------------------------------------------------------------

//

//  Class:      CUnknownA

//

//  Synopsis:   Class definition of IUnknownA

//

//---------------------------------------------------------------------------

class CUnknownA : public CInterface

{

public:

// *** IUnknown methods ***

STDMETHOD(QueryInterface)(REFIID riid, LPVOID * ppvObj);

STDMETHOD_(unsigned long, AddRef)(void);

STDMETHOD_(unsigned long, Release)(void);

CUnknownA(LPUNKNOWN punk, IDINTERFACE idRef = ID_NULL);

void AddInterface(IDINTERFACE idInterface, LPUNKNOWN pUnk);

long FreeInterface(IDINTERFACE idInterface);

public:

UINT        m_idPrimary;

LPUNKNOWN   m_pInterfaces[ID_SIZE];

};

//+--------------------------------------------------------------------------

//

//  Class:      CEnumStringA

//

//  Synopsis:   Class definition of IEnumStringA

//

//---------------------------------------------------------------------------

class CEnumStringA : CAnsiInterface

{

public:

// *** IEnumStringA methods ***

STDMETHOD(Next) (ULONG celt,

   char * * rgelt,

   ULONG FAR* pceltFetched);

STDMETHOD(Skip) (ULONG celt);

STDMETHOD(Reset) (VOID);

STDMETHOD(Clone) (IEnumStringA * * ppenm);

inline CEnumStringA(LPUNKNOWN pUnk, IEnumString * pObj) :

CAnsiInterface(ID_IEnumString, pUnk, (LPUNKNOWN)pObj) {};

inline IEnumString * GetWide() const

{ return (IEnumString *)m_pObj; };

};

//+--------------------------------------------------------------------------

//

//  Class:      CClassFactoryA

//

//  Synopsis:   Class definition of IClassFactoryA

//

//---------------------------------------------------------------------------

class CClassFactoryA : CAnsiInterface

{

public:

// *** IClassFactory methods ***

STDMETHOD(CreateInstance) (LPUNKNOWN pUnkOuter,

  REFIID riid,

  LPVOID FAR* ppvObject);

STDMETHOD(LockServer) (BOOL fLock);

inline CClassFactoryA(LPUNKNOWN pUnk, IClassFactory * pObj) :

CAnsiInterface(ID_IClassFactory, pUnk, (LPUNKNOWN)pObj) {};

inline IClassFactory * GetWide() const

{ return (IClassFactory *)m_pObj; };

};

typedef IClassFactory * LPCLASSFACTORYA;

//+--------------------------------------------------------------------------

//

//  Class:      CMarshalA

//

//  Synopsis:   Class definition of IMarshalA

//

//---------------------------------------------------------------------------

class CMarshalA : CAnsiInterface

{

public:

// *** IMarshal methods ***

STDMETHOD(GetUnmarshalClass)(REFIID riid, LPVOID pv,

DWORD dwDestContext, LPVOID pvDestContext,

DWORD mshlflags, LPCLSID pCid);

STDMETHOD(GetMarshalSizeMax)(REFIID riid, LPVOID pv,

DWORD dwDestContext, LPVOID pvDestContext,

DWORD mshlflags, LPDWORD pSize);

STDMETHOD(MarshalInterface)(LPSTREAMA pStm, REFIID riid,

LPVOID pv, DWORD dwDestContext, LPVOID pvDestContext,

DWORD mshlflags);

STDMETHOD(UnmarshalInterface)(LPSTREAMA pStm, REFIID riid,

LPVOID FAR* ppv);

STDMETHOD(ReleaseMarshalData)(LPSTREAMA pStm);

STDMETHOD(DisconnectObject)(DWORD dwReserved);

inline CMarshalA(LPUNKNOWN pUnk, IMarshal * pObj) :

CAnsiInterface(ID_IMarshal, pUnk, (LPUNKNOWN)pObj) {};

inline IMarshal * GetWide() const

{ return (IMarshal *)m_pObj; };

};

//+--------------------------------------------------------------------------

//

//  Class:      CStdMarshalInfoA

//

//  Synopsis:   Class definition of IStdMarshalInfoA

//

//---------------------------------------------------------------------------

class CStdMarshalInfoA : CAnsiInterface

{

public:

// *** IStdMarshalInfo methods ***

STDMETHOD(GetClassForHandler)(DWORD dwMemctx, LPVOID pvMemctx,

LPCLSID pclsid);

inline CStdMarshalInfoA(LPUNKNOWN pUnk, IStdMarshalInfo * pObj) :

CAnsiInterface(ID_IStdMarshalInfo, pUnk, (LPUNKNOWN)pObj) {};

inline IStdMarshalInfo * GetWide() const

{ return (IStdMarshalInfo *)m_pObj; };

};


 ANSICOMP.CPP  (OLEANSI Sample)

//+--------------------------------------------------------------------------

//

//  Copyright (C) 1994, Microsoft Corporation.  All Rights Reserved.

//

//  File:       ansicomp.cpp

//

//  Contents:   ANSI Wrappers for Unicode CompObj Interfaces and APIs.

//

//  Classes:    CUnknownA      - ANSI wrapper object for IUnknown.

//              CEnumStringA   - ANSI wrapper object for IEnumString.

//              CClassFactoryA - ANSI wrapper object for IClassFactory.

//

//  Functions:  CLSIDFromProgIDA

//              CLSIDFromProgIDA

//              CLSIDFromStringA

//              CoLoadLibraryA

//              CoCreateInstanceA

//              CoGetClassObjectA

//              IIDFromStringA

//              ProgIDFromCLSIDA

//              CoRegisterClassObjectA

//              StringFromCLSIDA

//              StringFromGUID2A

//              StringFromIIDA

//

//  History:    01-Nov-93   v-kentc     Created.

//

//---------------------------------------------------------------------------

#include "Ole2Ansi.h"


 IUnknownA Implementation  (OLEANSI Sample)

//***************************************************************************

//

//                   IUnknownA Implementation

//

//***************************************************************************

//+--------------------------------------------------------------------------

//

//  Member:     CUnknownA::CUnknownA, public

//

//  Synopsis:   Constructor.

//

//  Arguments:  [pestr] -- Unicode CUnknown object.

//

//  Returns:    OLE2 result code.

//

//---------------------------------------------------------------------------

CUnknownA::CUnknownA(IUnknown * pWide, IDINTERFACE idRef) :

CInterface(ID_IUnknown | ID_ANSIINTERFACE, NULL, (LPUNKNOWN)pWide)

{

m_idPrimary    = idRef;

memset(m_pInterfaces, 0, sizeof(m_pInterfaces));

TraceAddRef("CUnknownA::CUnknownA", pWide, pWide->AddRef());

}

void CUnknownA::AddInterface(IDINTERFACE idInterface, LPUNKNOWN pUnk)

{

m_pInterfaces[idInterface] = pUnk;

}

long CUnknownA::FreeInterface(IDINTERFACE idInterface)

{

WrapDeleteWrapper(m_pInterfaces[idInterface]);

m_pInterfaces[idInterface] = NULL;

TraceRelease("CUnknownA::FreeInterface", this, Release());

return 0;

}

//+--------------------------------------------------------------------------

//

//  Member:     CUnknownA::QueryInterface, public

//

//  Synopsis:   IUnknown::QueryInterface method implementation.

//

//  Arguments:  [riid] -- Interface ID.

//              [ppv]  -- Pointer to query results.

//

//  Returns:    OLE2 result code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CUnknownA::QueryInterface(REFIID riid, void * * ppv)

{

TraceMethodEnter("CUnknownA::QueryInterface", this);

IDINTERFACE      idRef;

LPUNKNOWN pUnk;

HRESULT   hResult;

*ppv = NULL;

if (riid == IID_IUnknown)

{

*ppv = this;

TraceAddRef("CUnknownA::QueryInterface", this, AddRef());

return ResultFromScode(S_OK);

}

idRef = WrapTranslateIID(riid);

//

//  If the id is NULL then this is not a thunked interface.

//

if (idRef == ID_NULL)

{

hResult = m_pObj->QueryInterface(riid, ppv);

if (SUCCEEDED(hResult))

TraceWarning("Interface not handled");

return hResult;

}

//

//  If the requested interface has already been wrapped then use the

//  original wrapped object.

//

if (m_pInterfaces[idRef])

{

*ppv = m_pInterfaces[idRef];

TraceAddRef("CUnknownA::QueryInterface", m_pInterfaces[idRef], m_pInterfaces[idRef]->AddRef());

return ResultFromScode(S_OK);

}

//

//  Query the Unicode interface and then wrap it.

//

hResult = m_pObj->QueryInterface(riid, (LPVOID *)&pUnk);

if (FAILED(hResult))

return hResult;

*ppv = m_pInterfaces[idRef] = WrapAnyAFromW(this, idRef, pUnk);

if (m_pInterfaces[idRef] == NULL)

return ResultFromScode(E_OUTOFMEMORY);

TraceAddRef("CUnknownA::QueryInterface", this, AddRef());

return ResultFromScode(S_OK);

}

//+--------------------------------------------------------------------------

//

//  Member:     CUnknownA::AddRef, public

//

//  Synopsis:   IUnknown::AddRef method implementation.

//

//  Returns:    Current reference count.

//

//---------------------------------------------------------------------------

STDMETHODIMP_(unsigned long) CUnknownA::AddRef()

{

TraceMethodEnter("CUnknownA::AddRef", this);

LONG lRet;

lRet = InterlockedIncrement(&m_refs);

TraceAddRef("CUnknownA::AddRef", this, m_refs);

m_pObj->AddRef();

return lRet;

}

//+--------------------------------------------------------------------------

//

//  Member:     CUnknownA::Release, public

//

//  Synopsis:   IUnknown::Release method implementation.

//

//  Returns:    Current reference count.

//

//---------------------------------------------------------------------------

STDMETHODIMP_(unsigned long) CUnknownA::Release()

{

TraceMethodEnter("CUnknownA::Release", this);

LONG lRet;

lRet = InterlockedDecrement(&m_refs);

TraceRelease("CUnknownA::Release", this, m_refs);

if (m_pInterfaces[m_idPrimary] != NULL)

{

if (m_refs < ((CUnknownA *)m_pInterfaces[m_idPrimary])->m_refs)

{

((CUnknownA *)m_pInterfaces[m_idPrimary])->m_refs--;

if (((CUnknownA *)m_pInterfaces[m_idPrimary])->m_refs == 0)

{

((CUnknownA *)m_pInterfaces[m_idPrimary])->m_pObj->Release();

WrapDeleteWrapper(m_pInterfaces[m_idPrimary]);

m_pInterfaces[m_idPrimary] = NULL;

}

TraceWarning("Had to adjust primary interface.");

}

}

if (lRet == 0)

{

for (UINT i = 0; i < ID_SIZE; i++)

{

if (m_pInterfaces[i])

{

TraceWarning("Interfaces not properly released.");

if (i != m_idPrimary)

((CUnknownA *)m_pInterfaces[i])->m_pObj->Release();

WrapDeleteWrapper(m_pInterfaces[i]);

}

}

++m_refs;

TraceRelease("CUnknownA::Release", m_pObj, m_pObj->Release());

--m_refs;

//

//  The thunked routine CreateDispTypeInfoA creates an UNICODE image

//  of the InterfaceData structure which must be kept around until

//  the TypeInfo is released.   So if we got it, time to free it.

//

if (m_pInterfaceData)

ConvertInterfaceDataFree(m_pInterfaceData);

WrapDeleteWrapper(this);

return 0;

}

m_pObj->Release();

return lRet;

}


 IEnumStringA Implementation  (OLEANSI Sample)

//***************************************************************************

//

//                   IEnumStringA Implementation

//

//***************************************************************************

//+--------------------------------------------------------------------------

//

//  Member:     CEnumStringA::Next, public

//

//  Synopsis:   Thunks Next to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CEnumStringA::Next(

ULONG celt,

LPSTR * rgelt,

ULONG * pceltFetched)

{

TraceNotify("CEnumStringA::Next");

ULONG   celtFetched;

HRESULT hReturn;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IEnumString, Next));

if (pceltFetched == NULL)

pceltFetched = &celtFetched;

hReturn = GetWide()->Next(celt, (OLECHAR * *)rgelt, pceltFetched);

if (FAILED(hReturn))

return (hReturn);

hResult = ConvertStringArrayToA(rgelt, *pceltFetched);

if (FAILED(hResult))

return (hResult);

return hReturn;

}

//+--------------------------------------------------------------------------

//

//  Member:     CEnumStringA::Skip, public

//

//  Synopsis:   Thunks Skip to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CEnumStringA::Skip(ULONG celt)

{

TraceNotify("CEnumStringA::Skip");

_DebugHook(GetWide(), MEMBER_PTR(IEnumString, Skip));

return GetWide()->Skip(celt);

}

//+--------------------------------------------------------------------------

//

//  Member:     CEnumStringA::Reset, public

//

//  Synopsis:   Thunks Reset to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CEnumStringA::Reset(VOID)

{

TraceNotify("CEnumStringA::Reset");

_DebugHook(GetWide(), MEMBER_PTR(IEnumString, Reset));

return GetWide()->Reset();

}

//+--------------------------------------------------------------------------

//

//  Member:     CEnumStringA::Clone, public

//

//  Synopsis:   Thunks Clone to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CEnumStringA::Clone(IEnumStringA * * ppenmA)

{

TraceNotify("CEnumStringA::Clone");

IEnumString * penm;

_DebugHook(GetWide(), MEMBER_PTR(IEnumString, Clone));

*ppenmA = NULL;

HRESULT hResult = GetWide()->Clone(&penm);

if (FAILED(hResult))

return (hResult);

hResult = WrapIEnumStringAFromW(penm, ppenmA);

if (penm)

penm->Release();

return hResult;

}


 IClassFactoryA Implementation  (OLEANSI Sample)

//***************************************************************************

//

//                   IClassFactoryA Implementation

//

//***************************************************************************

//+--------------------------------------------------------------------------

//

//  Member:     CClassFactoryA::CreateInstance, public

//

//  Synopsis:   Thunks Skip to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CClassFactoryA::CreateInstance(LPUNKNOWN pUnkOuterA,

  REFIID riid, LPVOID FAR* ppvObject)

{

TraceNotify("CClassFactoryA::CreateInstance");

LPUNKNOWN pUnk;

IDINTERFACE      idRef;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IClassFactory, CreateInstance));

hResult = GetWide()->CreateInstance(pUnkOuterA, riid, (LPVOID *)&pUnk);

if (FAILED(hResult))

return hResult;

//

//  Convert the 16 bytes GUID into an internal integer for speed.

//

idRef = WrapTranslateIID(riid);

hResult = WrapInterfaceAFromW(idRef, pUnk, (LPUNKNOWN *)ppvObject);

pUnk->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CClassFactoryA::LockServer, public

//

//  Synopsis:   Thunks Reset to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CClassFactoryA::LockServer(BOOL fLock)

{

TraceNotify("CClassFactoryA::LockServer");

_DebugHook(GetWide(), MEMBER_PTR(IClassFactory, LockServer));

return GetWide()->LockServer(fLock);

}


 IMarshalA Implementation  (OLEANSI Sample)

//***************************************************************************

//

//                   IMarshalA Implementation

//

//***************************************************************************

//+--------------------------------------------------------------------------

//

//  Member:     CMarshalA::GetUnmarshalClass, public

//

//  Synopsis:   Thunks GetUnmarshalClass to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CMarshalA::GetUnmarshalClass(REFIID riid, LPVOID pv,

DWORD dwDestContext, LPVOID pvDestContext,

DWORD mshlflags, LPCLSID pCid)

{

TraceNotify("CMarshalA::GetUnmarshalClass");

_DebugHook(GetWide(), MEMBER_PTR(IMarshal, GetUnmarshalClass));

return GetWide()->GetUnmarshalClass(riid, pv, dwDestContext, pvDestContext,

mshlflags, pCid);

}

//+--------------------------------------------------------------------------

//

//  Member:     CMarshalA::GetMarshalSizeMax, public

//

//  Synopsis:   Thunks GetMarshalSizeMax to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CMarshalA::GetMarshalSizeMax(REFIID riid, LPVOID pv,

DWORD dwDestContext, LPVOID pvDestContext,

DWORD mshlflags, LPDWORD pSize)

{

TraceNotify("CMarshalA::GetMarshalSizeMax");

_DebugHook(GetWide(), MEMBER_PTR(IMarshal, GetMarshalSizeMax));

return GetWide()->GetMarshalSizeMax(riid, pv, dwDestContext, pvDestContext,

mshlflags, pSize);

}

//+--------------------------------------------------------------------------

//

//  Member:     CMarshalA::MarshalInterface, public

//

//  Synopsis:   Thunks MarshalInterface to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CMarshalA::MarshalInterface(LPSTREAMA pStmA, REFIID riid,

LPVOID pv, DWORD dwDestContext, LPVOID pvDestContext,

DWORD mshlflags)

{

TraceNotify("CMarshalA::MarshalInterface");

LPSTREAM pStm;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IMarshal, MarshalInterface));

hResult = WrapIStreamWFromA(pStmA, &pStm);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->MarshalInterface(pStm, riid, pv, dwDestContext,

pvDestContext, mshlflags);

if (pStm)

pStm->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CMarshalA::UnmarshalInterface, public

//

//  Synopsis:   Thunks UnmarshalInterface to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CMarshalA::UnmarshalInterface(LPSTREAMA pStmA, REFIID riid,

LPVOID FAR* ppv)

{

TraceNotify("CMarshalA::UnmarshalInterface");

LPSTREAM pStm;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IMarshal, UnmarshalInterface));

hResult = WrapIStreamWFromA(pStmA, &pStm);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->UnmarshalInterface(pStm, riid, ppv);

if (pStm)

pStm->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CMarshalA::ReleaseMarshalData, public

//

//  Synopsis:   Thunks ReleaseMarshalData to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CMarshalA::ReleaseMarshalData(LPSTREAMA pStmA)

{

TraceNotify("CMarshalA::ReleaseMarshalData");

LPSTREAM pStm;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IMarshal, ReleaseMarshalData));

hResult = WrapIStreamWFromA(pStmA, &pStm);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->ReleaseMarshalData(pStm);

if (pStm)

pStm->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CMarshalA::DisconnectObject, public

//

//  Synopsis:   Thunks DisconnectObject to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CMarshalA::DisconnectObject(DWORD dwReserved)

{

TraceNotify("CMarshalA::DisconnectObject");

_DebugHook(GetWide(), MEMBER_PTR(IMarshal, DisconnectObject));

return GetWide()->DisconnectObject(dwReserved);

}


 CompObj API Thunks.  (OLEANSI Sample)

//***************************************************************************

//

//                          CompObj API Thunks.

//

//***************************************************************************

//+--------------------------------------------------------------------------

//

//  Routine:    CLSIDFromProgIDA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Returns:    See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI CLSIDFromProgIDA(LPCSTR lpszProgIDA, LPCLSID lpclsid)

{

TraceSTDAPIEnter("CLSIDFromProgIDA");

WCHAR  szProgID[MAX_STRING];

ConvertStringToW(lpszProgIDA, szProgID);

return CLSIDFromProgID(szProgID, lpclsid);

}

//+--------------------------------------------------------------------------

//

//  Routine:    CLSIDFromStringA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Returns:    See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI CLSIDFromStringA(LPSTR lpszA, LPCLSID pclsid)

{

TraceSTDAPIEnter("CLSIDFromStringA");

WCHAR sz[MAX_STRING];

ConvertStringToW(lpszA, sz);

return CLSIDFromString(sz, pclsid);

}

//+--------------------------------------------------------------------------

//

//  Routine:    CoCreateInstanceA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Returns:    See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI CoCreateInstanceA(REFCLSID rclsid, LPUNKNOWN pUnkOuterA,

DWORD dwClsContext, REFIID riid, LPVOID FAR* ppv)

{

TraceSTDAPIEnter("CoCreateInstanceA");

LPUNKNOWN pUnk;

IDINTERFACE      idRef;

HRESULT hResult;

hResult = CoCreateInstance(rclsid, pUnkOuterA, dwClsContext, riid, (LPVOID *)&pUnk);

if (FAILED(hResult))

goto Error;

//

//  Convert the 16 bytes GUID into an internal integer for speed.

//

idRef = WrapTranslateIID(riid);

hResult = WrapInterfaceAFromW(idRef, pUnk, (LPUNKNOWN *)ppv);

if (pUnk)

pUnk->Release();

Error:

TraceSTDAPIExit("CoCreateInstanceA", hResult);

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    CoGetClassObjectA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Returns:    See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI CoGetClassObjectA(REFCLSID rclsid, DWORD dwClsContext, LPVOID pvReserved,

REFIID riid, LPVOID FAR* ppv)

{

TraceSTDAPIEnter("CoGetClassObjectA");

LPUNKNOWN pUnk;

IDINTERFACE      idRef;

HRESULT hResult;

hResult =  CoGetClassObject(rclsid, dwClsContext, pvReserved, riid, (LPVOID *)&pUnk);

if (FAILED(hResult))

return hResult;

//

//  Convert the 16 bytes GUID into an internal integer for speed.

//

idRef = WrapTranslateIID(riid);

hResult = WrapInterfaceAFromW(idRef, pUnk, (LPUNKNOWN *)ppv);

if (pUnk)

pUnk->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    CoRegisterClassObjectA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Returns:    See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI CoRegisterClassObjectA(REFCLSID rclsid, LPUNKNOWN pUnk,

DWORD dwClsContext, DWORD flags, LPDWORD lpdwRegister)

{

TraceSTDAPIEnter("CoRegisterClassObjectA");

LPUNKNOWN lpCF;

HRESULT hResult;

hResult = WrapIUnknownWFromA(pUnk, &lpCF);

if (FAILED(hResult))

return hResult;

hResult = CoRegisterClassObject(rclsid, lpCF, dwClsContext, flags,

lpdwRegister);

if (lpCF)

lpCF->Release();

TraceSTDAPIExit("CoRegisterClassObjectA", hResult);

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    CoRevokeClassObjectA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Returns:    See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI CoRevokeClassObjectA(DWORD dwRegister)

{

TraceSTDAPIEnter("CoRevokeClassObjectA");

HRESULT hResult;

hResult = CoRevokeClassObject(dwRegister);

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    CoLoadLibraryA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Returns:    See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI_(HINSTANCE) CoLoadLibraryA(LPSTR pszLibNameA, BOOL bAutoFree)

{

TraceSTDAPIEnter("CoLoadLibraryA");

WCHAR szLibName[MAX_STRING];

ConvertStringToW(pszLibNameA, szLibName);

return CoLoadLibrary(szLibName, bAutoFree);

}

//+--------------------------------------------------------------------------

//

//  Routine:    CoLockObjectExternalA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Returns:    See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI CoLockObjectExternalA(LPUNKNOWN pUnkA, BOOL fLock,

BOOL fLastUnlockReleases)

{

TraceSTDAPIEnter("CoLockObjectExternalA");

LPUNKNOWN pUnk;

HRESULT hResult;

hResult = WrapIUnknownWFromA(pUnkA, &pUnk);

if (FAILED(hResult))

return hResult;

hResult = CoLockObjectExternal(pUnk, fLock, fLastUnlockReleases);

if (pUnk)

pUnk->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    CoDisconnectObjectA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Returns:    See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI CoDisconnectObjectA(LPUNKNOWN pUnkA, DWORD dwReserved)

{

TraceSTDAPIEnter("CoDisconnectObjectA");

LPUNKNOWN pUnk;

HRESULT hResult;

hResult = WrapIUnknownWFromA(pUnkA, &pUnk);

if (FAILED(hResult))

return hResult;

hResult = CoDisconnectObject(pUnk, dwReserved);

if (pUnk)

pUnk->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    IIDFromStringA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Returns:    See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI IIDFromStringA(LPSTR lpszA, LPIID lpiid)

{

TraceSTDAPIEnter("IIDFromStringA");

WCHAR sz[MAX_STRING];

ConvertStringToW(lpszA, sz);

return IIDFromString(sz, lpiid);

}

//+--------------------------------------------------------------------------

//

//  Routine:    ProgIDFromCLSIDA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Returns:    See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI ProgIDFromCLSIDA(REFCLSID clsid, LPSTR * lplpszProgIDA)

{

TraceSTDAPIEnter("ProgIDFromCLSIDA");

LPWSTR lpszProgID;

HRESULT hResult;

if (lplpszProgIDA == NULL)

return ResultFromScode(E_INVALIDARG);

hResult = ProgIDFromCLSID(clsid, &lpszProgID);

if (FAILED(hResult))

return (hResult);

hResult = ConvertStringToA(lpszProgID, lplpszProgIDA);

ConvertStringFree(lpszProgID);

return (hResult);

}

//+--------------------------------------------------------------------------

//

//  Routine:    StringFromCLSIDA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Returns:    See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI StringFromCLSIDA(REFCLSID rclsid, LPSTR * lplpszA)

{

TraceSTDAPIEnter("StringFromCLSIDA");

LPWSTR lpsz;

HRESULT hResult;

hResult = StringFromCLSID(rclsid, &lpsz);

if (FAILED(hResult))

return (hResult);

hResult = ConvertStringToA(lpsz, lplpszA);

ConvertStringFree(lpsz);

return (hResult);

}

//+--------------------------------------------------------------------------

//

//  Routine:    StringFromGUID2A

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Returns:    See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI_(int) StringFromGUID2A(REFGUID rguid, LPSTR szGuid, int cbMax)

{

TraceSTDAPIEnter("StringFromGUID2A");

   int cchRet;

#ifndef CCH_SZGUID0

// char count of a guid in ansi/unicode form (including trailing null)

#define CCH_SZGUID0 39

#endif

   OLECHAR szGuidW[CCH_SZGUID0];

   cchRet = StringFromGUID2(rguid, szGuidW, CCH_SZGUID0);

   // convert szGuidW from unicode to Ansi.  Can't just convert in place.

   WideCharToMultiByte(CP_ACP,

   0,

   szGuidW,

   CCH_SZGUID0,

   szGuid,

   cbMax,

   NULL,

   NULL);

   return cchRet;

}

//+--------------------------------------------------------------------------

//

//  Routine:    StringFromIIDA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Returns:    See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI StringFromIIDA(REFIID rclsid, LPSTR * lplpszA)

{

TraceSTDAPIEnter("StringFromIIDA");

LPWSTR lpsz;

HRESULT hResult;

hResult = StringFromIID(rclsid, &lpsz);

if (FAILED(hResult))

return (hResult);

hResult = ConvertStringToA(lpsz, lplpszA);

ConvertStringFree(lpsz);

return (hResult);

}


 IStdMarshalInfoA Implementation  (OLEANSI Sample)

//***************************************************************************

//

//                   IStdMarshalInfoA Implementation

//

//***************************************************************************

//+--------------------------------------------------------------------------

//

//  Member:     CStdMarshalInfoA::GetClassForHandler, public

//

//  Synopsis:   Thunks GetClassForHandler to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CStdMarshalInfoA::GetClassForHandler(DWORD dwMemctx,

LPVOID pvMemctx, LPCLSID pclsid)

{

TraceMethodEnter("CStdMarshalInfoA::GetClassForHandler", this);

_DebugHook(GetWide(), MEMBER_PTR(IStdMarshalInfo, GetClassForHandler));

return GetWide()->GetClassForHandler(dwMemctx, pvMemctx, pclsid);

}


 ANSICTL.H  (OLEANSI Sample)

//+--------------------------------------------------------------------------

//

//  Copyright (C) 1994, Microsoft Corporation.  All Rights Reserved.

//

//  File:       AnsiCtl.h

//

//  Contents:   ANSI Wrappers for OLE Control Interfaces and APIs.

//

//  History:    27-May-94   johnels     Created.

//

//---------------------------------------------------------------------------

typedef interface IOleControlA FAR* LPOLECONTROLA;

typedef interface IOleControlSiteA FAR* LPOLECONTROLSITEA;

typedef interface ISimpleFrameSiteA FAR* LPSIMPLEFRAMESITEA;

typedef interface IPersistStreamInitA FAR* LPPERSISTSTREAMINITA;

typedef interface IPropertyNotifySinkA FAR* LPPROPERTYNOTIFYSINKA;

typedef interface IProvideClassInfoA FAR* LPPROVIDECLASSINFOA;

typedef interface IConnectionPointContainerA FAR* LPCONNECTIONPOINTCONTAINERA;

typedef interface IEnumConnectionPointsA FAR* LPENUMCONNECTIONPOINTSA;

typedef interface IConnectionPointA FAR* LPCONNECTIONPOINTA;

typedef interface IEnumConnectionsA FAR* LPENUMCONNECTIONSA;

typedef struct tagCONNECTDATAA FAR* LPCONNECTDATAA;

typedef interface IClassFactory2A FAR* LPCLASSFACTORY2A;

typedef interface ISpecifyPropertyPagesA FAR* LPSPECIFYPROPERTYPAGESA;

typedef interface IPerPropertyBrowsingA FAR* LPPERPROPERTYBROWSINGA;

typedef interface IPropertyPageSiteA FAR* LPPROPERTYPAGESITEA;

typedef struct tagPROPPAGEINFOA FAR* LPPROPPAGEINFOA;

typedef interface IPropertyPageA FAR* LPPROPERTYPAGEA;

typedef interface IPropertyPage2A FAR* LPPROPERTYPAGE2A;

typedef struct tagOCPFIPARAMSA FAR* LPOCPFIPARAMSA;

typedef struct tagFONTDESCA FAR* LPFONTDESCA;

typedef interface IFontA FAR* LPFONTA;

typedef interface IFontDispA FAR* LPFONTDISPA;

typedef interface IPictureA FAR* LPPICTUREA;

typedef interface IPictureDispA FAR* LPPICTUREDISPA;

//////////////////////////////////////////////////////////////////////////////

// IPropertyNotifySinkA interface

#undef  INTERFACE

#define INTERFACE IPropertyNotifySinkA

DECLARE_INTERFACE_(IPropertyNotifySinkA, IUnknown)

{

// IUnknown methods

STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE;

STDMETHOD_(ULONG,AddRef)(THIS) PURE;

STDMETHOD_(ULONG,Release)(THIS) PURE;

// IPropertyNotifySinkA methods

STDMETHOD(OnChanged)(THIS_ DISPID dispid) PURE;

STDMETHOD(OnRequestEdit)(THIS_ DISPID dispid) PURE;

};

//////////////////////////////////////////////////////////////////////////////

// IProvideClassInfoA interface

#undef  INTERFACE

#define INTERFACE IProvideClassInfoA

DECLARE_INTERFACE_(IProvideClassInfoA, IUnknown)

{

// IUnknown methods

STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE;

STDMETHOD_(ULONG,AddRef)(THIS) PURE;

STDMETHOD_(ULONG,Release)(THIS) PURE;

// IProvideClassInfoA methods

STDMETHOD(GetClassInfo)(THIS_ LPTYPEINFOA FAR* ppTI) PURE;

};

//////////////////////////////////////////////////////////////////////////////

// IConnectionPointContainerA interface

#undef  INTERFACE

#define INTERFACE IConnectionPointContainerA

DECLARE_INTERFACE_(IConnectionPointContainerA, IUnknown)

{

// IUnknown methods

STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE;

STDMETHOD_(ULONG,AddRef)(THIS) PURE;

STDMETHOD_(ULONG,Release)(THIS) PURE;

// IConnectionPointContainerA methods

STDMETHOD(EnumConnectionPoints)(

THIS_ LPENUMCONNECTIONPOINTSA FAR* ppEnum) PURE;

STDMETHOD(FindConnectionPoint)(

THIS_ REFIID iid, LPCONNECTIONPOINTA FAR* ppCP) PURE;

};

//////////////////////////////////////////////////////////////////////////////

// IEnumConnectionPointsA interface

#undef  INTERFACE

#define INTERFACE IEnumConnectionPointsA

DECLARE_INTERFACE_(IEnumConnectionPointsA, IUnknown)

{

// IUnknown methods

STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE;

STDMETHOD_(ULONG,AddRef)(THIS) PURE;

STDMETHOD_(ULONG,Release)(THIS) PURE;

// IEnumConnectionPointsA methods

STDMETHOD(Next)(

THIS_ ULONG cConnections,

LPCONNECTIONPOINTA FAR* rgpcn, ULONG FAR* lpcFetched) PURE;

STDMETHOD(Skip)(THIS_ ULONG cConnections) PURE;

STDMETHOD(Reset)(THIS) PURE;

STDMETHOD(Clone)(THIS_ LPENUMCONNECTIONPOINTSA FAR* ppEnum) PURE;

};

//////////////////////////////////////////////////////////////////////////////

// IConnectionPointA interface

#undef  INTERFACE

#define INTERFACE IConnectionPointA

DECLARE_INTERFACE_(IConnectionPointA, IUnknown)

{

// IUnknown methods

STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE;

STDMETHOD_(ULONG,AddRef)(THIS) PURE;

STDMETHOD_(ULONG,Release)(THIS) PURE;

// IConnectionPointA methods

STDMETHOD(GetConnectionInterface)(THIS_ IID FAR* pIID) PURE;

STDMETHOD(GetConnectionPointContainer)(

THIS_ LPCONNECTIONPOINTCONTAINERA FAR* ppCPC) PURE;

STDMETHOD(Advise)(THIS_ LPUNKNOWN pUnkSink, DWORD FAR* pdwCookie) PURE;

STDMETHOD(Unadvise)(THIS_ DWORD dwCookie) PURE;

STDMETHOD(EnumConnections)(THIS_ LPENUMCONNECTIONSA FAR* ppEnum) PURE;

};

//////////////////////////////////////////////////////////////////////////////

// CONNECTDATAA structure

typedef struct tagCONNECTDATAA

{

LPUNKNOWN pUnk;

DWORD dwCookie;

} CONNECTDATAA;

//////////////////////////////////////////////////////////////////////////////

// IEnumConnectionsA interface

#undef  INTERFACE

#define INTERFACE IEnumConnectionsA

DECLARE_INTERFACE_(IEnumConnectionsA, IUnknown)

{

// IUnknown methods

STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE;

STDMETHOD_(ULONG,AddRef)(THIS) PURE;

STDMETHOD_(ULONG,Release)(THIS) PURE;

// IEnumConnectionsA methods

STDMETHOD(Next)(

THIS_ ULONG cConnections,

LPCONNECTDATAA rgcd, ULONG FAR* lpcFetched) PURE;

STDMETHOD(Skip)(THIS_ ULONG cConnections) PURE;

STDMETHOD(Reset)(THIS) PURE;

STDMETHOD(Clone)(THIS_ LPENUMCONNECTIONSA FAR* ppecn) PURE;

};

//////////////////////////////////////////////////////////////////////////////

// IOleControlA interface

#undef  INTERFACE

#define INTERFACE IOleControlA

DECLARE_INTERFACE_(IOleControlA, IUnknown)

{

// IUnknown methods

STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE;

STDMETHOD_(ULONG,AddRef)(THIS) PURE;

STDMETHOD_(ULONG,Release)(THIS) PURE;

// IOleControlA methods

STDMETHOD(GetControlInfo)(THIS_ LPCONTROLINFO pCI) PURE;

STDMETHOD(OnMnemonic)(THIS_ LPMSG pMsg) PURE;

STDMETHOD(OnAmbientPropertyChange)(THIS_ DISPID dispid) PURE;

STDMETHOD(FreezeEvents)(THIS_ BOOL bFreeze) PURE;

};

//////////////////////////////////////////////////////////////////////////////

// IOleControlSiteA interface

#undef  INTERFACE

#define INTERFACE IOleControlSiteA

DECLARE_INTERFACE_(IOleControlSiteA, IUnknown)

{

// IUnknown methods

STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE;

STDMETHOD_(ULONG,AddRef)(THIS) PURE;

STDMETHOD_(ULONG,Release)(THIS) PURE;

// IOleControlSiteA methods

STDMETHOD(OnControlInfoChanged)(THIS) PURE;

STDMETHOD(LockInPlaceActive)(THIS_ BOOL fLock) PURE;

STDMETHOD(GetExtendedControl)(THIS_ LPDISPATCHA FAR* ppDisp) PURE;

STDMETHOD(TransformCoords)(THIS_ POINTL FAR* lpptlHimetric,

POINTF FAR* lpptfContainer, DWORD flags) PURE;

STDMETHOD(TranslateAccelerator)(THIS_ LPMSG lpMsg, DWORD grfModifiers) PURE;

STDMETHOD(OnFocus)(THIS_ BOOL fGotFocus) PURE;

STDMETHOD(ShowPropertyFrame)(THIS) PURE;

};

#define XFORMCOORDS_POSITION            0x1

#define XFORMCOORDS_SIZE                0x2

#define XFORMCOORDS_HIMETRICTOCONTAINER 0x4

#define XFORMCOORDS_CONTAINERTOHIMETRIC 0x8

//////////////////////////////////////////////////////////////////////////////

// ISimpleFrameSiteA interface

#undef  INTERFACE

#define INTERFACE ISimpleFrameSiteA

DECLARE_INTERFACE_(ISimpleFrameSiteA, IUnknown)

{

// IUnknown methods

STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE;

STDMETHOD_(ULONG,AddRef)(THIS) PURE;

STDMETHOD_(ULONG,Release)(THIS) PURE;

// ISimpleFrameSite methods

STDMETHOD(PreMessageFilter)(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp,

LRESULT FAR* lplResult, DWORD FAR * lpdwCookie) PURE;

STDMETHOD(PostMessageFilter)(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp,

LRESULT FAR* lplResult, DWORD dwCookie) PURE;

};

//////////////////////////////////////////////////////////////////////////////

// IPersistStreamInitA interface

#undef  INTERFACE

#define INTERFACE IPersistStreamInitA

DECLARE_INTERFACE_(IPersistStreamInitA, IPersist)

{

// IUnknown methods

STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE;

STDMETHOD_(ULONG,AddRef)(THIS) PURE;

STDMETHOD_(ULONG,Release)(THIS) PURE;

// IPersistA methods

STDMETHOD(GetClassID)(THIS_ LPCLSID lpClassID) PURE;

// IPersistStreamInitA methods

STDMETHOD(IsDirty)(THIS) PURE;

STDMETHOD(Load)(THIS_ LPSTREAMA pStm) PURE;

STDMETHOD(Save)(THIS_ LPSTREAMA pStm, BOOL fClearDirty) PURE;

STDMETHOD(GetSizeMax)(THIS_ ULARGE_INTEGER FAR* pcbSize) PURE;

STDMETHOD(InitNew)(THIS) PURE;

};

//////////////////////////////////////////////////////////////////////////////

// IClassFactory2A interface

#undef  INTERFACE

#define INTERFACE IClassFactory2A

DECLARE_INTERFACE_(IClassFactory2A, IClassFactory)

{

//  IUnknown methods

STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE;

STDMETHOD_(ULONG,AddRef)(THIS) PURE;

STDMETHOD_(ULONG,Release)(THIS) PURE;

// IClassFactoryA methods

STDMETHOD(CreateInstance)(THIS_ LPUNKNOWN pUnkOuter, REFIID riid,

LPVOID FAR* ppvObject) PURE;

STDMETHOD(LockServer)(THIS_ BOOL fLock) PURE;

//  IClassFactory2A methods

STDMETHOD(GetLicInfo)(THIS_ LPLICINFO pLicInfo) PURE;

STDMETHOD(RequestLicKey)(THIS_ DWORD dwReserved, BSTRA FAR* pbstrKey) PURE;

STDMETHOD(CreateInstanceLic)(THIS_ LPUNKNOWN pUnkOuter,

LPUNKNOWN pUnkReserved, REFIID riid, BSTRA bstrKey,

LPVOID FAR* ppvObject) PURE;

};

//////////////////////////////////////////////////////////////////////////////

// ISpecifyPropertyPagesA interface

#undef  INTERFACE

#define INTERFACE ISpecifyPropertyPagesA

DECLARE_INTERFACE_(ISpecifyPropertyPagesA, IUnknown)

{

// IUnknown methods

STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE;

STDMETHOD_(ULONG,AddRef)(THIS) PURE;

STDMETHOD_(ULONG,Release)(THIS) PURE;

// ISpecifyPropertyPagesA interface

STDMETHOD(GetPages)(THIS_ CAUUID FAR* pPages) PURE;

};

//////////////////////////////////////////////////////////////////////////////

// CALPSTR structure

typedef struct tagCALPSTR

{

ULONG cElems;

LPSTR FAR* pElems;

} CALPSTR;

//////////////////////////////////////////////////////////////////////////////

// IPerPropertyBrowsingA interface

#undef  INTERFACE

#define INTERFACE IPerPropertyBrowsingA

DECLARE_INTERFACE_(IPerPropertyBrowsingA, IUnknown)

{

// IUnknown methods

STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE;

STDMETHOD_(ULONG,AddRef)(THIS) PURE;

STDMETHOD_(ULONG,Release)(THIS) PURE;

// IPerPropertyBrowsingA interface

STDMETHOD(GetDisplayString)(THIS_ DISPID dispid, BSTRA FAR* lpbstr) PURE;

STDMETHOD(MapPropertyToPage)(THIS_ DISPID dispid, LPCLSID lpclsid) PURE;

STDMETHOD(GetPredefinedStrings)(THIS_ DISPID dispid,

CALPSTR FAR* lpcaStringsOut, CADWORD FAR* lpcaCookiesOut) PURE;

STDMETHOD(GetPredefinedValue)(THIS_ DISPID dispid, DWORD dwCookie,

VARIANTA FAR* pvarOut) PURE;

};

//////////////////////////////////////////////////////////////////////////////

// IPropertyPageSiteA interface

#undef  INTERFACE

#define INTERFACE IPropertyPageSiteA

DECLARE_INTERFACE_(IPropertyPageSiteA, IUnknown)

{

// IUnknown methods

STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE;

STDMETHOD_(ULONG,AddRef)(THIS) PURE;

STDMETHOD_(ULONG,Release)(THIS) PURE;

// IPropertyPageSiteA methods

STDMETHOD(OnStatusChange)(THIS_ DWORD flags) PURE;

STDMETHOD(GetLocaleID)(THIS_ LCID FAR* pLocaleID) PURE;

STDMETHOD(GetPageContainer)(THIS_ LPUNKNOWN FAR* ppUnk) PURE;

STDMETHOD(TranslateAccelerator)(THIS_ LPMSG lpMsg) PURE;

};

//////////////////////////////////////////////////////////////////////////////

// PROPPAGEINFOA structure

typedef struct tagPROPPAGEINFOA

{

size_t cb;

LPSTR pszTitle;

SIZE size;

LPSTR pszDocString;

LPSTR pszHelpFile;

DWORD dwHelpContext;

} PROPPAGEINFOA;

//////////////////////////////////////////////////////////////////////////////

// IPropertyPageA interface

#undef  INTERFACE

#define INTERFACE IPropertyPageA

DECLARE_INTERFACE_(IPropertyPageA, IUnknown)

{

// IUnknown methods

STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE;

STDMETHOD_(ULONG,AddRef)(THIS) PURE;

STDMETHOD_(ULONG,Release)(THIS) PURE;

// IPropertyPageA methods

STDMETHOD(SetPageSite)(THIS_ LPPROPERTYPAGESITEA pPageSite) PURE;

STDMETHOD(Activate)(THIS_ HWND hwndParent, LPCRECT rect,

BOOL bModal) PURE;

STDMETHOD(Deactivate)(THIS) PURE;

STDMETHOD(GetPageInfo)(THIS_ LPPROPPAGEINFOA pPageInfo) PURE;

STDMETHOD(SetObjects)(THIS_ ULONG cObjects, LPUNKNOWN FAR* ppunk) PURE;

STDMETHOD(Show)(THIS_ UINT nCmdShow) PURE;

STDMETHOD(Move)(LPCRECT prect) PURE;

STDMETHOD(IsPageDirty)(THIS) PURE;

STDMETHOD(Apply)(THIS) PURE;

STDMETHOD(Help)(THIS_ LPCSTR lpszHelpDir) PURE;

STDMETHOD(TranslateAccelerator)(THIS_ LPMSG lpMsg) PURE;

};

//////////////////////////////////////////////////////////////////////////////

// IPropertyPage2A interface

#undef  INTERFACE

#define INTERFACE IPropertyPage2A

DECLARE_INTERFACE_(IPropertyPage2A, IPropertyPageA)

{

// IUnknown methods

STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE;

STDMETHOD_(ULONG,AddRef)(THIS) PURE;

STDMETHOD_(ULONG,Release)(THIS) PURE;

// IPropertyPageA methods

STDMETHOD(SetPageSite)(THIS_ LPPROPERTYPAGESITEA pPageSite) PURE;

STDMETHOD(Activate)(THIS_ HWND hwndParent, LPCRECT rect,

BOOL bModal) PURE;

STDMETHOD(Deactivate)(THIS) PURE;

STDMETHOD(GetPageInfo)(THIS_ LPPROPPAGEINFOA pPageInfo) PURE;

STDMETHOD(SetObjects)(THIS_ ULONG cObjects, LPUNKNOWN FAR* ppunk) PURE;

STDMETHOD(Show)(THIS_ UINT nCmdShow) PURE;

STDMETHOD(Move)(LPCRECT prect) PURE;

STDMETHOD(IsPageDirty)(THIS) PURE;

STDMETHOD(Apply)(THIS) PURE;

STDMETHOD(Help)(THIS_ LPCSTR lpszHelpDir) PURE;

STDMETHOD(TranslateAccelerator)(THIS_ LPMSG lpMsg) PURE;

// IPropertyPage2A methods

STDMETHOD(EditProperty)(THIS_ DISPID dispid) PURE;

};

/////////////////////////////////////////////////////////////////////////////

// OCPFIPARAMSA structure (parameters for OleCreatePropertyFrameIndirectA)

typedef struct tagOCPFIPARAMSA

{

ULONG cbStructSize;

HWND hWndOwner;

int x;

int y;

LPSTR lpszCaption;

ULONG cObjects;

LPUNKNOWN FAR* lplpUnk;

ULONG cPages;

CLSID FAR* lpPages;

LCID lcid;

DISPID dispidInitialProperty;

} OCPFIPARAMSA;

/////////////////////////////////////////////////////////////////////////////

// IFontA interface

#undef INTERFACE

#define INTERFACE IFontA

DECLARE_INTERFACE_(IFontA, IUnknown)

{

// IUnknown methods

STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE;

STDMETHOD_(ULONG, AddRef)(THIS) PURE;

STDMETHOD_(ULONG, Release)(THIS) PURE;

// IFontA methods

STDMETHOD(get_Name)(THIS_ BSTRA FAR* pname) PURE;

STDMETHOD(put_Name)(THIS_ BSTRA name) PURE;

STDMETHOD(get_Size)(THIS_ CY FAR* psize) PURE;

STDMETHOD(put_Size)(THIS_ CY size) PURE;

STDMETHOD(get_Bold)(THIS_ BOOL FAR* pbold) PURE;

STDMETHOD(put_Bold)(THIS_ BOOL bold) PURE;

STDMETHOD(get_Italic)(THIS_ BOOL FAR* pitalic) PURE;

STDMETHOD(put_Italic)(THIS_ BOOL italic) PURE;

STDMETHOD(get_Underline)(THIS_ BOOL FAR* punderline) PURE;

STDMETHOD(put_Underline)(THIS_ BOOL underline) PURE;

STDMETHOD(get_Strikethrough)(THIS_ BOOL FAR* pstrikethrough) PURE;

STDMETHOD(put_Strikethrough)(THIS_ BOOL strikethrough) PURE;

STDMETHOD(get_Weight)(THIS_ short FAR* pweight) PURE;

STDMETHOD(put_Weight)(THIS_ short weight) PURE;

STDMETHOD(get_Charset)(THIS_ short FAR* pcharset) PURE;

STDMETHOD(put_Charset)(THIS_ short charset) PURE;

STDMETHOD(get_hFont)(THIS_ HFONT FAR* phfont) PURE;

STDMETHOD(Clone)(THIS_ IFontA FAR* FAR* lplpfont) PURE;

STDMETHOD(IsEqual)(THIS_ IFontA FAR * lpFontOther) PURE;

STDMETHOD(SetRatio)(THIS_ long cyLogical, long cyHimetric) PURE;

STDMETHOD(QueryTextMetrics)(THIS_ LPTEXTMETRIC lptm) PURE;

STDMETHOD(AddRefHfont)(THIS_ HFONT hfont) PURE;

STDMETHOD(ReleaseHfont)(THIS_ HFONT hfont) PURE;

};

/////////////////////////////////////////////////////////////////////////////

// IFontDispA interface

#undef INTERFACE

#define INTERFACE IFontDispA

DECLARE_INTERFACE_(IFontDispA, IDispatchA)

{

// IUnknown methods

STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE;

STDMETHOD_(ULONG, AddRef)(THIS) PURE;

STDMETHOD_(ULONG, Release)(THIS) PURE;

// IDispatch methods

STDMETHOD(GetTypeInfoCount)(THIS_ UINT FAR* pctinfo) PURE;

STDMETHOD(GetTypeInfo)(

  THIS_

  UINT itinfo,

  LCID lcid,

  ITypeInfoA FAR* FAR* pptinfo) PURE;

STDMETHOD(GetIDsOfNames)(

  THIS_

  REFIID riid,

  LPSTR FAR* rgszNames,

  UINT cNames,

  LCID lcid,

  DISPID FAR* rgdispid) PURE;

STDMETHOD(Invoke)(

  THIS_

  DISPID dispidMember,

  REFIID riid,

  LCID lcid,

  WORD wFlags,

  DISPPARAMSA FAR* pdispparams,

  VARIANTA FAR* pvarResult,

  EXCEPINFOA FAR* pexcepinfo,

  UINT FAR* puArgErr) PURE;

};

/////////////////////////////////////////////////////////////////////////////

// FONTDESCA structure

typedef struct tagFONTDESCA

{

UINT  cbSizeofstruct;

LPSTR lpstrName;

CY    cySize;

SHORT sWeight;

SHORT sCharset;

BOOL  fItalic;

BOOL  fUnderline;

BOOL  fStrikethrough;

} FONTDESCA;

/////////////////////////////////////////////////////////////////////////////

// IPictureA interface

DECLARE_INTERFACE_(IPictureA, IUnknown)

{

// IUnknown methods

STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE;

STDMETHOD_(ULONG, AddRef)(THIS) PURE;

STDMETHOD_(ULONG, Release)(THIS) PURE;

// IPictureA methods

STDMETHOD(get_Handle)(THIS_ OLE_HANDLE FAR* phandle) PURE;

STDMETHOD(get_hPal)(THIS_ OLE_HANDLE FAR* phpal) PURE;

STDMETHOD(get_Type)(THIS_ short FAR* ptype) PURE;

STDMETHOD(get_Width)(THIS_ OLE_XSIZE_HIMETRIC FAR* pwidth) PURE;

STDMETHOD(get_Height)(THIS_ OLE_YSIZE_HIMETRIC FAR* pheight) PURE;

STDMETHOD(Render)(THIS_ HDC hdc, long x, long y, long cx, long cy,

OLE_XPOS_HIMETRIC xSrc, OLE_YPOS_HIMETRIC ySrc,

OLE_XSIZE_HIMETRIC cxSrc, OLE_YSIZE_HIMETRIC cySrc,

LPRECT lprcWBounds) PURE;

STDMETHOD(set_hPal)(THIS_ OLE_HANDLE hpal) PURE;

STDMETHOD(get_CurDC)(THIS_ HDC FAR * phdcOut) PURE;

STDMETHOD(SelectPicture)(THIS_

HDC hdcIn, HDC FAR * phdcOut, OLE_HANDLE FAR * phbmpOut) PURE;

STDMETHOD(get_KeepOriginalFormat)(THIS_ BOOL * pfkeep) PURE;

STDMETHOD(put_KeepOriginalFormat)(THIS_ BOOL fkeep) PURE;

STDMETHOD(PictureChanged)(THIS) PURE;

STDMETHOD(SaveAsFile)(THIS_ LPSTREAMA lpstream, BOOL fSaveMemCopy,

LONG FAR * lpcbSize) PURE;

STDMETHOD(get_Attributes)(THIS_ DWORD FAR * lpdwAttr) PURE;

};

/////////////////////////////////////////////////////////////////////////////

// IPictureDispA interface

DECLARE_INTERFACE_(IPictureDispA, IDispatchA)

{

// IUnknown methods

STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE;

STDMETHOD_(ULONG, AddRef)(THIS) PURE;

STDMETHOD_(ULONG, Release)(THIS) PURE;

// IDispatchA methods

STDMETHOD(GetTypeInfoCount)(THIS_ UINT FAR* pctinfo) PURE;

STDMETHOD(GetTypeInfo)(

  THIS_

  UINT itinfo,

  LCID lcid,

  ITypeInfoA FAR* FAR* pptinfo) PURE;

STDMETHOD(GetIDsOfNames)(

  THIS_

  REFIID riid,

  LPSTR FAR* rgszNames,

  UINT cNames,

  LCID lcid,

  DISPID FAR* rgdispid) PURE;

STDMETHOD(Invoke)(

  THIS_

  DISPID dispidMember,

  REFIID riid,

  LCID lcid,

  WORD wFlags,

  DISPPARAMSA FAR* pdispparams,

  VARIANTA FAR* pvarResult,

  EXCEPINFOA FAR* pexcepinfo,

  UINT FAR* puArgErr) PURE;

};

/////////////////////////////////////////////////////////////////////////////

// Property sheet APIs

STDAPI OleCreatePropertyFrameA(HWND hwndOwner, UINT x, UINT y,

LPCSTR lpszCaption, ULONG cObjects, LPUNKNOWN FAR* ppUnk,

ULONG cPages, LPCLSID pPageClsID, LCID lcid,

DWORD dwReserved, LPVOID pvReserved);

STDAPI OleCreatePropertyFrameIndirectA(LPOCPFIPARAMSA lpParams);

/////////////////////////////////////////////////////////////////////////////

// Font APIs

STDAPI OleCreateFontIndirectA(LPFONTDESCA lpfd,

REFIID riid, LPVOID FAR* lplpvObj);

/////////////////////////////////////////////////////////////////////////////

// CPropertyNotifySinkA class

class CPropertyNotifySinkA : CAnsiInterface

{

public:

// IPropertyNotifySinkA methods

STDMETHOD(OnChanged)(DISPID dispid);

STDMETHOD(OnRequestEdit)(DISPID dispid);

inline CPropertyNotifySinkA(LPUNKNOWN pUnk, IPropertyNotifySink* pWide) :

CAnsiInterface(ID_IPropertyNotifySink, pUnk, (LPUNKNOWN)pWide) {};

inline IPropertyNotifySink* GetWide() const

{ return (IPropertyNotifySink*)m_pObj; };

};

/////////////////////////////////////////////////////////////////////////////

// CProvideClassInfoA class

class CProvideClassInfoA : CAnsiInterface

{

public:

// IProvideClassInfoA methods

STDMETHOD(GetClassInfo)(LPTYPEINFOA FAR* ppTI);

inline CProvideClassInfoA(LPUNKNOWN pUnk, IProvideClassInfo* pWide) :

CAnsiInterface(ID_IProvideClassInfo, pUnk, (LPUNKNOWN)pWide) {};

inline IProvideClassInfo* GetWide() const

{ return (IProvideClassInfo*)m_pObj; };

};

/////////////////////////////////////////////////////////////////////////////

// CConnectionPointContainerA class

class CConnectionPointContainerA : CAnsiInterface

{

public:

// IConnectionPointContainerA methods

STDMETHOD(EnumConnectionPoints)(

LPENUMCONNECTIONPOINTSA FAR* ppEnum);

STDMETHOD(FindConnectionPoint)(

REFIID iid, LPCONNECTIONPOINTA FAR* ppCP);

inline CConnectionPointContainerA(LPUNKNOWN pUnk, IConnectionPointContainer* pWide) :

CAnsiInterface(ID_IConnectionPointContainer, pUnk, (LPUNKNOWN)pWide) {};

inline IConnectionPointContainer* GetWide() const

{ return (IConnectionPointContainer*)m_pObj; };

};

/////////////////////////////////////////////////////////////////////////////

// CEnumConnectionPointsA class

class CEnumConnectionPointsA : CAnsiInterface

{

public:

// IEnumConnectionPointsA methods

STDMETHOD(Next)(

ULONG cConnections,

LPCONNECTIONPOINTA FAR* rgpcn, ULONG FAR* lpcFetched);

STDMETHOD(Skip)(ULONG cConnections);

STDMETHOD(Reset)();

STDMETHOD(Clone)(LPENUMCONNECTIONPOINTSA FAR* ppEnum);

inline CEnumConnectionPointsA(LPUNKNOWN pUnk, IEnumConnectionPoints* pWide) :

CAnsiInterface(ID_IEnumConnectionPoints, pUnk, (LPUNKNOWN)pWide) {};

inline IEnumConnectionPoints* GetWide() const

{ return (IEnumConnectionPoints*)m_pObj; };

};

/////////////////////////////////////////////////////////////////////////////

// CConnectionPointA class

class CConnectionPointA : CAnsiInterface

{

public:

// IConnectionPointA methods

STDMETHOD(GetConnectionInterface)(IID FAR* pIID);

STDMETHOD(GetConnectionPointContainer)(

LPCONNECTIONPOINTCONTAINERA FAR* ppCPC);

STDMETHOD(Advise)(LPUNKNOWN pUnkSink, DWORD FAR* pdwCookie);

STDMETHOD(Unadvise)(DWORD dwCookie);

STDMETHOD(EnumConnections)(LPENUMCONNECTIONSA FAR* ppEnum);

inline CConnectionPointA(LPUNKNOWN pUnk, IConnectionPoint* pWide) :

CAnsiInterface(ID_IConnectionPoint, pUnk, (LPUNKNOWN)pWide) {};

inline IConnectionPoint* GetWide() const

{ return (IConnectionPoint*)m_pObj; };

};

/////////////////////////////////////////////////////////////////////////////

// CEnumConnectionsA class

class CEnumConnectionsA : CAnsiInterface

{

public:

// IEnumConnectionsA methods

STDMETHOD(Next)(

ULONG cConnections,

LPCONNECTDATAA rgcd, ULONG FAR* lpcFetched);

STDMETHOD(Skip)(ULONG cConnections);

STDMETHOD(Reset)();

STDMETHOD(Clone)(LPENUMCONNECTIONSA FAR* ppecn);

inline CEnumConnectionsA(LPUNKNOWN pUnk, IEnumConnections* pWide) :

CAnsiInterface(ID_IEnumConnections, pUnk, (LPUNKNOWN)pWide) {};

inline IEnumConnections* GetWide() const

{ return (IEnumConnections*)m_pObj; };

};

/////////////////////////////////////////////////////////////////////////////

// COleControlA class

class COleControlA : CAnsiInterface

{

public:

// IOleControlA methods

STDMETHOD(GetControlInfo)(LPCONTROLINFO pCI);

STDMETHOD(OnMnemonic)(LPMSG pMsg);

STDMETHOD(OnAmbientPropertyChange)(DISPID dispid);

STDMETHOD(FreezeEvents)(BOOL bFreeze);

inline COleControlA(LPUNKNOWN pUnk, IOleControl* pWide) :

CAnsiInterface(ID_IOleControl, pUnk, (LPUNKNOWN)pWide) {};

inline IOleControl* GetWide() const

{ return (IOleControl*)m_pObj; };

};

/////////////////////////////////////////////////////////////////////////////

// COleControlSiteA class

class COleControlSiteA : CAnsiInterface

{

public:

// IOleControlSiteA methods

STDMETHOD(OnControlInfoChanged)();

STDMETHOD(LockInPlaceActive)(BOOL fLock);

STDMETHOD(GetExtendedControl)(LPDISPATCHA FAR* ppDisp);

STDMETHOD(TransformCoords)(POINTL FAR* lpptlHimetric,

POINTF FAR* lpptfContainer, DWORD flags);

STDMETHOD(TranslateAccelerator)(LPMSG lpMsg, DWORD grfModifiers);

STDMETHOD(OnFocus)(BOOL fGotFocus);

STDMETHOD(ShowPropertyFrame)();

inline COleControlSiteA(LPUNKNOWN pUnk, IOleControlSite* pWide) :

CAnsiInterface(ID_IOleControlSite, pUnk, (LPUNKNOWN)pWide) {};

inline IOleControlSite* GetWide() const

{ return (IOleControlSite*)m_pObj; };

};

/////////////////////////////////////////////////////////////////////////////

// CSimpleFrameSiteA class

class CSimpleFrameSiteA : CAnsiInterface

{

public:

// ISimpleFrameSite methods

STDMETHOD(PreMessageFilter)(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp,

LRESULT FAR* lplResult, DWORD FAR * lpdwCookie);

STDMETHOD(PostMessageFilter)(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp,

LRESULT FAR* lplResult, DWORD dwCookie);

inline CSimpleFrameSiteA(LPUNKNOWN pUnk, ISimpleFrameSite* pWide) :

CAnsiInterface(ID_ISimpleFrameSite, pUnk, (LPUNKNOWN)pWide) {};

inline ISimpleFrameSite* GetWide() const

{ return (ISimpleFrameSite*)m_pObj; };

};

/////////////////////////////////////////////////////////////////////////////

// CPersistStreamInitA class

class CPersistStreamInitA : CAnsiInterface

{

public:

// IPersistA methods

STDMETHOD(GetClassID)(LPCLSID lpClassID);

// IPersistStreamInitA methods

STDMETHOD(IsDirty)();

STDMETHOD(Load)(LPSTREAMA pStm);

STDMETHOD(Save)(LPSTREAMA pStm, BOOL fClearDirty);

STDMETHOD(GetSizeMax)(ULARGE_INTEGER FAR* pcbSize);

STDMETHOD(InitNew)();

inline CPersistStreamInitA(LPUNKNOWN pUnk, IPersistStreamInit* pWide) :

CAnsiInterface(ID_IPersistStreamInit, pUnk, (LPUNKNOWN)pWide) {};

inline IPersistStreamInit* GetWide() const

{ return (IPersistStreamInit*)m_pObj; };

};

/////////////////////////////////////////////////////////////////////////////

// CClassFactory2A class

class CClassFactory2A : CAnsiInterface

{

public:

//  IClassFactoryA methods

STDMETHOD(CreateInstance) (LPUNKNOWN pUnkOuter,

  REFIID riid, LPVOID FAR* ppvObject);

STDMETHOD(LockServer) (BOOL fLock);

//  IClassFactory2A methods

STDMETHOD(GetLicInfo)(LPLICINFO pLicInfo);

STDMETHOD(RequestLicKey)(DWORD dwReserved, BSTRA FAR* pbstrKey);

STDMETHOD(CreateInstanceLic)(LPUNKNOWN pUnkOuter,

LPUNKNOWN pUnkReserved, REFIID riid, BSTRA bstrKey,

LPVOID FAR* ppvObject);

inline CClassFactory2A(LPUNKNOWN pUnk, IClassFactory2* pWide) :

CAnsiInterface(ID_IClassFactory2, pUnk, (LPUNKNOWN)pWide) {};

inline IClassFactory2* GetWide() const

{ return (IClassFactory2*)m_pObj; };

};

/////////////////////////////////////////////////////////////////////////////

// CSpecifyPropertyPagesA class

class CSpecifyPropertyPagesA : CAnsiInterface

{

public:

// ISpecifyPropertyPagesA interface

STDMETHOD(GetPages)(CAUUID FAR* pPages);

inline CSpecifyPropertyPagesA(LPUNKNOWN pUnk, ISpecifyPropertyPages* pWide) :

CAnsiInterface(ID_ISpecifyPropertyPages, pUnk, (LPUNKNOWN)pWide) {};

inline ISpecifyPropertyPages* GetWide() const

{ return (ISpecifyPropertyPages*)m_pObj; };

};

/////////////////////////////////////////////////////////////////////////////

// CPerPropertyBrowsingA class

class CPerPropertyBrowsingA : CAnsiInterface

{

public:

// IPerPropertyBrowsingA interface

STDMETHOD(GetDisplayString)(DISPID dispid, BSTRA FAR* lpbstr);

STDMETHOD(MapPropertyToPage)(DISPID dispid, LPCLSID lpclsid);

STDMETHOD(GetPredefinedStrings)(DISPID dispid,

CALPSTR FAR* lpcaStringsOut, CADWORD FAR* lpcaCookiesOut);

STDMETHOD(GetPredefinedValue)(DISPID dispid, DWORD dwCookie,

VARIANTA FAR* pvarOut);

inline CPerPropertyBrowsingA(LPUNKNOWN pUnk, IPerPropertyBrowsing* pWide) :

CAnsiInterface(ID_IPerPropertyBrowsing, pUnk, (LPUNKNOWN)pWide) {};

inline IPerPropertyBrowsing* GetWide() const

{ return (IPerPropertyBrowsing*)m_pObj; };

};

/////////////////////////////////////////////////////////////////////////////

// CPropertyPageSiteA class

class CPropertyPageSiteA : CAnsiInterface

{

public:

// IPropertyPageSiteA methods

STDMETHOD(OnStatusChange)(DWORD flags);

STDMETHOD(GetLocaleID)(LCID FAR* pLocaleID);

STDMETHOD(GetPageContainer)(LPUNKNOWN FAR* ppUnk);

STDMETHOD(TranslateAccelerator)(LPMSG lpMsg);

inline CPropertyPageSiteA(LPUNKNOWN pUnk, IPropertyPageSite* pWide) :

CAnsiInterface(ID_IPropertyPageSite, pUnk, (LPUNKNOWN)pWide) {};

inline IPropertyPageSite* GetWide() const

{ return (IPropertyPageSite*)m_pObj; };

};

/////////////////////////////////////////////////////////////////////////////

// CPropertyPage2A class

class CPropertyPage2A : CAnsiInterface

{

public:

// IPropertyPageA methods

STDMETHOD(SetPageSite)(LPPROPERTYPAGESITEA pPageSite);

STDMETHOD(Activate)(HWND hwndParent, LPCRECT rect,

BOOL bModal);

STDMETHOD(Deactivate)();

STDMETHOD(GetPageInfo)(LPPROPPAGEINFOA pPageInfo);

STDMETHOD(SetObjects)(ULONG cObjects, LPUNKNOWN FAR* ppunk);

STDMETHOD(Show)(UINT nCmdShow);

STDMETHOD(Move)(LPCRECT prect);

STDMETHOD(IsPageDirty)();

STDMETHOD(Apply)();

STDMETHOD(Help)(LPCSTR lpszHelpDir);

STDMETHOD(TranslateAccelerator)(LPMSG lpMsg);

// IPropertyPage2A methods

STDMETHOD(EditProperty)(DISPID dispid);

inline CPropertyPage2A(LPUNKNOWN pUnk, IPropertyPage2* pWide) :

CAnsiInterface(ID_IPropertyPage2, pUnk, (LPUNKNOWN)pWide) {};

inline IPropertyPage2* GetWide() const

{ return (IPropertyPage2*)m_pObj; };

};

/////////////////////////////////////////////////////////////////////////////

// CFontA class

class CFontA : CAnsiInterface

{

public:

// IFontA methods

STDMETHOD(get_Name)(BSTRA FAR* pname);

STDMETHOD(put_Name)(BSTRA name);

STDMETHOD(get_Size)(CY FAR* psize);

STDMETHOD(put_Size)(CY size);

STDMETHOD(get_Bold)(BOOL FAR* pbold);

STDMETHOD(put_Bold)(BOOL bold);

STDMETHOD(get_Italic)(BOOL FAR* pitalic);

STDMETHOD(put_Italic)(BOOL italic);

STDMETHOD(get_Underline)(BOOL FAR* punderline);

STDMETHOD(put_Underline)(BOOL underline);

STDMETHOD(get_Strikethrough)(BOOL FAR* pstrikethrough);

STDMETHOD(put_Strikethrough)(BOOL strikethrough);

STDMETHOD(get_Weight)(short FAR* pweight);

STDMETHOD(put_Weight)(short weight);

STDMETHOD(get_Charset)(short FAR* pcharset);

STDMETHOD(put_Charset)(short charset);

STDMETHOD(get_hFont)(HFONT FAR* phfont);

STDMETHOD(Clone)(IFontA FAR* FAR* lplpfont);

STDMETHOD(IsEqual)(IFontA FAR * lpFontOther);

STDMETHOD(SetRatio)(long cyLogical, long cyHimetric);

STDMETHOD(QueryTextMetrics)(LPTEXTMETRIC lptm);

STDMETHOD(AddRefHfont)(HFONT hfont);

STDMETHOD(ReleaseHfont)(HFONT hfont);

inline CFontA(LPUNKNOWN pUnk, IFont* pWide) :

CAnsiInterface(ID_IFont, pUnk, (LPUNKNOWN)pWide) {};

inline IFont* GetWide() const

{ return (IFont*)m_pObj; };

};

/////////////////////////////////////////////////////////////////////////////

// CPictureA class

class CPictureA : CAnsiInterface

{

public:

// IPictureA methods

STDMETHOD(get_Handle)(OLE_HANDLE FAR* phandle);

STDMETHOD(get_hPal)(OLE_HANDLE FAR* phpal);

STDMETHOD(get_Type)(short FAR* ptype);

STDMETHOD(get_Width)(OLE_XSIZE_HIMETRIC FAR* pwidth);

STDMETHOD(get_Height)(OLE_YSIZE_HIMETRIC FAR* pheight);

STDMETHOD(Render)(HDC hdc, long x, long y, long cx, long cy,

OLE_XPOS_HIMETRIC xSrc, OLE_YPOS_HIMETRIC ySrc,

OLE_XSIZE_HIMETRIC cxSrc, OLE_YSIZE_HIMETRIC cySrc,

LPRECT lprcWBounds);

STDMETHOD(set_hPal)(OLE_HANDLE hpal);

STDMETHOD(get_CurDC)(HDC FAR * phdcOut);

STDMETHOD(SelectPicture)(

HDC hdcIn, HDC FAR * phdcOut, OLE_HANDLE FAR * phbmpOut);

STDMETHOD(get_KeepOriginalFormat)(BOOL * pfkeep);

STDMETHOD(put_KeepOriginalFormat)(BOOL fkeep);

STDMETHOD(PictureChanged)();

STDMETHOD(SaveAsFile)(LPSTREAMA lpstream, BOOL fSaveMemCopy,

LONG FAR * lpcbSize);

STDMETHOD(get_Attributes)(DWORD FAR * lpdwAttr);

inline CPictureA(LPUNKNOWN pUnk, IPicture* pWide) :

CAnsiInterface(ID_IPicture, pUnk, (LPUNKNOWN)pWide) {};

inline IPicture* GetWide() const

{ return (IPicture*)m_pObj; };

};


 ANSICTL.CPP  (OLEANSI Sample)

//+--------------------------------------------------------------------------

//

//  Copyright (C) 1994, Microsoft Corporation.  All Rights Reserved.

//

//  File:       AnsiCtl.cpp

//

//  Contents:   ANSI Wrappers for OLE Control Interfaces and APIs.

//

//  History:    01-Jun-94   johnels     Created.

//

//---------------------------------------------------------------------------

#include "Ole2Ansi.h"

/////////////////////////////////////////////////////////////////////////////

// Get an entry point for the OLE Controls DLL

HINSTANCE _hOleControlDll = (HINSTANCE)-1;

#ifdef _DEBUG

#define OC_DLL "oc30d.dll"

#else

#define OC_DLL "oc30.dll"

#endif

HRESULT GetEntryPoint(FARPROC* lplpfn, LPSTR pszFunction)

{

if (*lplpfn == NULL)

{

if (_hOleControlDll == (HINSTANCE)-1)

_hOleControlDll = LoadLibrary(OC_DLL);

if (_hOleControlDll != NULL)

*lplpfn = GetProcAddress(_hOleControlDll, pszFunction);

#ifdef _DEBUG

if (*lplpfn == NULL)

{

char buf[MAX_STRING];

wsprintf(buf, "%s: Entry point not found!", pszFunction);

}

#endif

}

return (*lplpfn != NULL) ? NOERROR : ResultFromScode(E_UNEXPECTED);

}

/////////////////////////////////////////////////////////////////////////////

// Property sheet APIs

STDAPI OleCreatePropertyFrameA(HWND hwndOwner, UINT x, UINT y,

LPCSTR lpszCaptionA, ULONG cObjects, LPUNKNOWN FAR* ppUnkA,

ULONG cPages, LPCLSID pPageClsID, LCID lcid,

DWORD dwReserved, LPVOID pvReserved)

{

TraceSTDAPIEnter("OleCreatePropertyFrameA");

OCPFIPARAMSA ocpfiA;

ocpfiA.cbStructSize = sizeof(OCPFIPARAMSA);

ocpfiA.hWndOwner = hwndOwner;

ocpfiA.x = x;

ocpfiA.y = y;

ocpfiA.lpszCaption = (LPSTR)lpszCaptionA;

ocpfiA.cObjects = cObjects;

ocpfiA.lplpUnk = ppUnkA;

ocpfiA.cPages = cPages;

ocpfiA.lpPages = pPageClsID;

ocpfiA.lcid = lcid;

ocpfiA.dispidInitialProperty = DISPID_UNKNOWN;

return OleCreatePropertyFrameIndirectA(&ocpfiA);

}

STDAPI OleCreatePropertyFrameIndirectA(LPOCPFIPARAMSA lpParams)

{

static HRESULT (FAR STDAPICALLTYPE * _lpfnOleCreatePropertyFrameIndirect)(

LPOCPFIPARAMS) = NULL;

TraceSTDAPIEnter("OleCreatePropertyFrameIndirectA");

HRESULT hResult;

WCHAR szCaption[MAX_STRING];

if (lpParams->lpszCaption != NULL)

ConvertStringToW(lpParams->lpszCaption, szCaption);

else

szCaption[0] = L'\0';

ULONG cObjects = lpParams->cObjects;

LPUNKNOWN FAR* ppUnk = new LPUNKNOWN[cObjects];

ULONG i;

for (i = 0; i < cObjects; i++)

ppUnk[i] = NULL;

for (i = 0; i < cObjects; i++)

{

hResult = WrapIUnknownWFromA(lpParams->lplpUnk[i], &ppUnk[i]);

if (FAILED(hResult))

goto Error;

}

OCPFIPARAMS ocpfi;

memcpy(&ocpfi, lpParams, lpParams->cbStructSize);

ocpfi.lpszCaption = szCaption;

ocpfi.lplpUnk = ppUnk;

hResult = GetEntryPoint((FARPROC*)&_lpfnOleCreatePropertyFrameIndirect,

"OleCreatePropertyFrameIndirect");

if (FAILED(hResult))

goto Error;

hResult = (*_lpfnOleCreatePropertyFrameIndirect)(&ocpfi);

Error:

for (i = 0; i < cObjects; i++)

if (ppUnk[i] != NULL)

ppUnk[i]->Release();

delete [] ppUnk;

return hResult;

}

/////////////////////////////////////////////////////////////////////////////

// Font APIs

STDAPI OleCreateFontIndirectA(LPFONTDESCA lpfd,

REFIID riid, LPVOID FAR* lplpvObj)

{

static HRESULT (FAR STDAPICALLTYPE * _lpfnOleCreateFontIndirect)(

LPFONTDESC, REFIID, LPVOID FAR*) = NULL;

TraceSTDAPIEnter("OleCreateFontIndirectA");

HRESULT hResult;

LPUNKNOWN pUnk;

IDINTERFACE idRef;

WCHAR szName[MAX_STRING];

if (lpfd->lpstrName != NULL)

ConvertStringToW(lpfd->lpstrName, szName);

else

szName[0] = L'\0';

FONTDESC fontDesc;

memcpy(&fontDesc, lpfd, lpfd->cbSizeofstruct);

fontDesc.lpstrName = szName;

hResult = GetEntryPoint((FARPROC*)&_lpfnOleCreateFontIndirect,

"OleCreateFontIndirect");

if (FAILED(hResult))

return hResult;

hResult = (*_lpfnOleCreateFontIndirect)(&fontDesc, riid,

(LPVOID FAR*)&pUnk);

if (FAILED(hResult))

return hResult;

//

//  Convert the 16 bytes GUID into an internal integer for speed.

//

idRef = WrapTranslateIID(riid);

hResult = WrapInterfaceAFromW(idRef, pUnk, (LPUNKNOWN *)lplpvObj);

pUnk->Release();

return hResult;

}

/////////////////////////////////////////////////////////////////////////////

// CPropertyNotifySinkA class

STDMETHODIMP CPropertyNotifySinkA::OnChanged(DISPID dispid)

{

TraceMethodEnter("CPropertyNotifySinkA::OnChanged", this);

_DebugHook(GetWide(), MEMBER_PTR(IPropertyNotifySink, OnChanged));

return GetWide()->OnChanged(dispid);

}

STDMETHODIMP CPropertyNotifySinkA::OnRequestEdit(DISPID dispid)

{

TraceMethodEnter("CPropertyNotifySinkA::OnRequestEdit", this);

_DebugHook(GetWide(), MEMBER_PTR(IPropertyNotifySink, OnRequestEdit));

return GetWide()->OnRequestEdit(dispid);

}

/////////////////////////////////////////////////////////////////////////////

// CProvideClassInfoA class

STDMETHODIMP CProvideClassInfoA::GetClassInfo(LPTYPEINFOA FAR* ppTI)

{

TraceMethodEnter("CProvideClassInfoA::GetClassInfo", this);

_DebugHook(GetWide(), MEMBER_PTR(IProvideClassInfo, GetClassInfo));

LPTYPEINFO pTypeInfo;

HRESULT hResult;

hResult = GetWide()->GetClassInfo(&pTypeInfo);

if (FAILED(hResult))

return hResult;

hResult = WrapITypeInfoAFromW(pTypeInfo, ppTI);

pTypeInfo->Release();

return hResult;

}

/////////////////////////////////////////////////////////////////////////////

// CConnectionPointContainerA class

STDMETHODIMP CConnectionPointContainerA::EnumConnectionPoints(

LPENUMCONNECTIONPOINTSA FAR* ppEnum)

{

TraceMethodEnter("CConnectionPointContainerA::EnumConnectionPoints", this);

_DebugHook(GetWide(), MEMBER_PTR(IConnectionPointContainer, EnumConnectionPoints));

LPENUMCONNECTIONPOINTS pEnumConnPts;

HRESULT hResult;

hResult = GetWide()->EnumConnectionPoints(&pEnumConnPts);

if (FAILED(hResult))

return hResult;

hResult = WrapIEnumConnectionPointsAFromW(pEnumConnPts, ppEnum);

pEnumConnPts->Release();

return hResult;

}

STDMETHODIMP CConnectionPointContainerA::FindConnectionPoint(

REFIID iid, LPCONNECTIONPOINTA FAR* ppCP)

{

TraceMethodEnter("CConnectionPointContainerA::FindConnectionPoint", this);

_DebugHook(GetWide(), MEMBER_PTR(IConnectionPointContainer, FindConnectionPoint));

LPCONNECTIONPOINT pConnPt;

HRESULT hResult;

hResult = GetWide()->FindConnectionPoint(iid, &pConnPt);

if (FAILED(hResult))

return hResult;

hResult = WrapIConnectionPointAFromW(pConnPt, ppCP);

pConnPt->Release();

return hResult;

}

/////////////////////////////////////////////////////////////////////////////

// CEnumConnectionPointsA class

STDMETHODIMP CEnumConnectionPointsA::Next(

ULONG cConnections,

LPCONNECTIONPOINTA FAR* rgpcn, ULONG FAR* lpcFetched)

{

TraceMethodEnter("CEnumConnectionPointsA::Next", this);

_DebugHook(GetWide(), MEMBER_PTR(IEnumConnectionPoints, Next));

LPCONNECTIONPOINT FAR* rgpConnPt = new LPCONNECTIONPOINT[cConnections];

HRESULT hResult;

hResult = GetWide()->Next(cConnections, rgpConnPt, lpcFetched);

if (FAILED(hResult))

{

delete [] rgpConnPt;

return hResult;

}

ULONG i;

for (i = 0; i < *lpcFetched; i++)   // Wrap each pointer in array

{

hResult = WrapIConnectionPointAFromW(rgpConnPt[i], &rgpcn[i]);

rgpConnPt[i]->Release();

}

delete [] rgpConnPt;

return hResult;

}

STDMETHODIMP CEnumConnectionPointsA::Skip(ULONG cConnections)

{

TraceMethodEnter("CEnumConnectionPointsA::Skip", this);

_DebugHook(GetWide(), MEMBER_PTR(IEnumConnectionPoints, Skip));

return GetWide()->Skip(cConnections);

}

STDMETHODIMP CEnumConnectionPointsA::Reset()

{

TraceMethodEnter("CEnumConnectionPointsA::Reset", this);

_DebugHook(GetWide(), MEMBER_PTR(IEnumConnectionPoints, Reset));

return GetWide()->Reset();

}

STDMETHODIMP CEnumConnectionPointsA::Clone(LPENUMCONNECTIONPOINTSA FAR* ppEnum)

{

TraceMethodEnter("CEnumConnectionPointsA::Clone", this);

_DebugHook(GetWide(), MEMBER_PTR(IEnumConnectionPoints, Clone));

LPENUMCONNECTIONPOINTS pEnumConnPts;

HRESULT hResult;

hResult = GetWide()->Clone(&pEnumConnPts);

if (FAILED(hResult))

return hResult;

hResult = WrapIEnumConnectionPointsAFromW(pEnumConnPts, ppEnum);

pEnumConnPts->Release();

return hResult;

}

/////////////////////////////////////////////////////////////////////////////

// CConnectionPointA class

STDMETHODIMP CConnectionPointA::GetConnectionInterface(IID FAR* pIID)

{

TraceMethodEnter("CConnectionPointA::GetConnectionInterface", this);

_DebugHook(GetWide(), MEMBER_PTR(IConnectionPoint, GetConnectionInterface));

return GetWide()->GetConnectionInterface(pIID);

}

STDMETHODIMP CConnectionPointA::GetConnectionPointContainer(

LPCONNECTIONPOINTCONTAINERA FAR* ppCPC)

{

TraceMethodEnter("CConnectionPointA::GetConnectionPointContainer", this);

_DebugHook(GetWide(), MEMBER_PTR(IConnectionPoint, GetConnectionPointContainer));

LPCONNECTIONPOINTCONTAINER pConnPtCont;

HRESULT hResult;

hResult = GetWide()->GetConnectionPointContainer(&pConnPtCont);

if (FAILED(hResult))

return hResult;

hResult = WrapIConnectionPointContainerAFromW(pConnPtCont, ppCPC);

pConnPtCont->Release();

return hResult;

}

STDMETHODIMP CConnectionPointA::Advise(LPUNKNOWN pUnkSinkA, DWORD FAR* pdwCookie)

{

TraceMethodEnter("CConnectionPointA::Advise", this);

_DebugHook(GetWide(), MEMBER_PTR(IConnectionPoint, Advise));

LPUNKNOWN pUnkSink;

HRESULT hResult;

hResult = WrapIUnknownWFromA(pUnkSinkA, &pUnkSink);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->Advise(pUnkSink, pdwCookie);

pUnkSink->Release();

return hResult;

}

STDMETHODIMP CConnectionPointA::Unadvise(DWORD dwCookie)

{

TraceMethodEnter("CConnectionPointA::Unadvise", this);

_DebugHook(GetWide(), MEMBER_PTR(IConnectionPoint, Unadvise));

return GetWide()->Unadvise(dwCookie);

}

STDMETHODIMP CConnectionPointA::EnumConnections(LPENUMCONNECTIONSA FAR* ppEnum)

{

TraceMethodEnter("CConnectionPointA::EnumConnections", this);

_DebugHook(GetWide(), MEMBER_PTR(IConnectionPoint, EnumConnections));

LPENUMCONNECTIONS pEnumConns;

HRESULT hResult;

hResult = GetWide()->EnumConnections(&pEnumConns);

if (FAILED(hResult))

return hResult;

hResult = WrapIEnumConnectionsAFromW(pEnumConns, ppEnum);

pEnumConns->Release();

return hResult;

}

/////////////////////////////////////////////////////////////////////////////

// CEnumConnectionsA class

STDMETHODIMP CEnumConnectionsA::Next(

ULONG cConnections,

LPCONNECTDATAA rgcd, ULONG FAR* lpcFetched)

{

TraceMethodEnter("CEnumConnectionsA::Next", this);

_DebugHook(GetWide(), MEMBER_PTR(IEnumConnections, Next));

LPCONNECTDATA rgConnData = new CONNECTDATA[cConnections];

HRESULT hResult;

hResult = GetWide()->Next(cConnections, rgConnData, lpcFetched);

if (FAILED(hResult))

{

delete [] rgConnData;

return hResult;

}

ULONG i;

for (i = 0; i < *lpcFetched; i++)   // Wrap each pointer in array

{

rgcd[i].dwCookie = rgConnData[i].dwCookie;

hResult = WrapIUnknownAFromW(rgConnData[i].pUnk, &rgcd[i].pUnk);

rgConnData[i].pUnk->Release();

}

delete [] rgConnData;

return hResult;

}

STDMETHODIMP CEnumConnectionsA::Skip(ULONG cConnections)

{

TraceMethodEnter("CEnumConnectionPointsA::Skip", this);

_DebugHook(GetWide(), MEMBER_PTR(IEnumConnectionPoints, Skip));

return GetWide()->Skip(cConnections);

}

STDMETHODIMP CEnumConnectionsA::Reset()

{

TraceMethodEnter("CEnumConnectionPointsA::Reset", this);

_DebugHook(GetWide(), MEMBER_PTR(IEnumConnectionPoints, Reset));

return GetWide()->Reset();

}

STDMETHODIMP CEnumConnectionsA::Clone(LPENUMCONNECTIONSA FAR* ppEnum)

{

TraceMethodEnter("CEnumConnectionsA::Clone", this);

_DebugHook(GetWide(), MEMBER_PTR(IEnumConnections, Clone));

LPENUMCONNECTIONS pEnumConns;

HRESULT hResult;

hResult = GetWide()->Clone(&pEnumConns);

if (FAILED(hResult))

return hResult;

hResult = WrapIEnumConnectionsAFromW(pEnumConns, ppEnum);

pEnumConns->Release();

return hResult;

}

/////////////////////////////////////////////////////////////////////////////

// COleControlA class

STDMETHODIMP COleControlA::GetControlInfo(LPCONTROLINFO pCI)

{

TraceMethodEnter("COleControlA::GetControlInfo", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleControl, GetControlInfo));

return GetWide()->GetControlInfo(pCI);

}

STDMETHODIMP COleControlA::OnMnemonic(LPMSG pMsg)

{

TraceMethodEnter("COleControlA::OnMnemonic", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleControl, OnMnemonic));

return GetWide()->OnMnemonic(pMsg);

}

STDMETHODIMP COleControlA::OnAmbientPropertyChange(DISPID dispid)

{

TraceMethodEnter("COleControlA::OnAmbientPropertyChange", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleControl, OnAmbientPropertyChange));

return GetWide()->OnAmbientPropertyChange(dispid);

}

STDMETHODIMP COleControlA::FreezeEvents(BOOL bFreeze)

{

TraceMethodEnter("COleControlA::FreezeEvents", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleControl, FreezeEvents));

return GetWide()->FreezeEvents(bFreeze);

}

/////////////////////////////////////////////////////////////////////////////

// COleControlSiteA class

STDMETHODIMP COleControlSiteA::OnControlInfoChanged()

{

TraceMethodEnter("COleControlSiteA::OnControlInfoChanged", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleControlSite, OnControlInfoChanged));

return GetWide()->OnControlInfoChanged();

}

STDMETHODIMP COleControlSiteA::LockInPlaceActive(BOOL fLock)

{

TraceMethodEnter("COleControlSiteA::LockInPlaceActive", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleControlSite, LockInPlaceActive));

return GetWide()->LockInPlaceActive(fLock);

}

STDMETHODIMP COleControlSiteA::GetExtendedControl(LPDISPATCHA FAR* ppDisp)

{

TraceMethodEnter("COleControlSiteA::GetExtendedControl", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleControlSite, GetExtendedControl));

LPDISPATCH pDisp;

HRESULT hResult;

hResult = GetWide()->GetExtendedControl(&pDisp);

if (FAILED(hResult))

return hResult;

hResult = WrapIDispatchAFromW(pDisp, ppDisp);

pDisp->Release();

return hResult;

}

STDMETHODIMP COleControlSiteA::TransformCoords(POINTL FAR* lpptlHimetric,

POINTF FAR* lpptfContainer, DWORD flags)

{

TraceMethodEnter("COleControlSiteA::TransformCoords", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleControlSite, TransformCoords));

return GetWide()->TransformCoords(lpptlHimetric, lpptfContainer, flags);

}

STDMETHODIMP COleControlSiteA::TranslateAccelerator(LPMSG lpMsg,

DWORD grfModifiers)

{

TraceMethodEnter("COleControlSiteA::TranslateAccelerator", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleControlSite, TranslateAccelerator));

return GetWide()->TranslateAccelerator(lpMsg, grfModifiers);

}

STDMETHODIMP COleControlSiteA::OnFocus(BOOL fGotFocus)

{

TraceMethodEnter("COleControlSiteA::OnFocus", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleControlSite, OnFocus));

return GetWide()->OnFocus(fGotFocus);

}

STDMETHODIMP COleControlSiteA::ShowPropertyFrame()

{

TraceMethodEnter("COleControlSiteA::ShowPropertyFrame", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleControlSite, ShowPropertyFrame));

return GetWide()->ShowPropertyFrame();

}

/////////////////////////////////////////////////////////////////////////////

// CSimpleFrameSiteA class

STDMETHODIMP CSimpleFrameSiteA::PreMessageFilter(HWND hwnd, UINT msg,

WPARAM wp, LPARAM lp, LRESULT FAR* lplResult, DWORD FAR * lpdwCookie)

{

TraceMethodEnter("CSimpleFrameSiteA::PreMessageFilter", this);

_DebugHook(GetWide(), MEMBER_PTR(ISimpleFrameSite, PreMessageFilter));

return GetWide()->PreMessageFilter(hwnd, msg, wp, lp, lplResult, lpdwCookie);

}

STDMETHODIMP CSimpleFrameSiteA::PostMessageFilter(HWND hwnd, UINT msg,

WPARAM wp, LPARAM lp, LRESULT FAR* lplResult, DWORD dwCookie)

{

TraceMethodEnter("CSimpleFrameSiteA::PostMessageFilter", this);

_DebugHook(GetWide(), MEMBER_PTR(ISimpleFrameSite, PostMessageFilter));

return GetWide()->PostMessageFilter(hwnd, msg, wp, lp, lplResult, dwCookie);

}

/////////////////////////////////////////////////////////////////////////////

// CPersistStreamInitA class

STDMETHODIMP CPersistStreamInitA::GetClassID(LPCLSID lpClassID)

{

TraceMethodEnter("CPersistStreamInitA::GetClassID", this);

_DebugHook(GetWide(), MEMBER_PTR(IPersistStreamInit, GetClassID));

return GetWide()->GetClassID(lpClassID);

}

STDMETHODIMP CPersistStreamInitA::IsDirty()

{

TraceMethodEnter("CPersistStreamInitA::IsDirty", this);

_DebugHook(GetWide(), MEMBER_PTR(IPersistStreamInit, IsDirty));

return GetWide()->IsDirty();

}

STDMETHODIMP CPersistStreamInitA::Load(LPSTREAMA pStmA)

{

TraceMethodEnter("CPersistStreamInitA::Load", this);

_DebugHook(GetWide(), MEMBER_PTR(IPersistStreamInit, Load));

LPSTREAM pStm;

HRESULT hResult;

hResult = WrapIStreamWFromA(pStmA, &pStm);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->Load(pStm);

pStm->Release();

return hResult;

}

STDMETHODIMP CPersistStreamInitA::Save(LPSTREAMA pStmA, BOOL fClearDirty)

{

TraceMethodEnter("CPersistStreamInitA::Save", this);

_DebugHook(GetWide(), MEMBER_PTR(IPersistStreamInit, Save));

LPSTREAM pStm;

HRESULT hResult;

hResult = WrapIStreamWFromA(pStmA, &pStm);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->Save(pStm, fClearDirty);

pStm->Release();

return hResult;

}

STDMETHODIMP CPersistStreamInitA::GetSizeMax(ULARGE_INTEGER FAR* pcbSize)

{

TraceMethodEnter("CPersistStreamInitA::GetSizeMax", this);

_DebugHook(GetWide(), MEMBER_PTR(IPersistStreamInit, GetSizeMax));

return GetWide()->GetSizeMax(pcbSize);

}

STDMETHODIMP CPersistStreamInitA::InitNew()

{

TraceMethodEnter("CPersistStreamInitA::InitNew", this);

_DebugHook(GetWide(), MEMBER_PTR(IPersistStreamInit, InitNew));

return GetWide()->InitNew();

}

/////////////////////////////////////////////////////////////////////////////

// CClassFactory2A class

STDMETHODIMP CClassFactory2A::CreateInstance(LPUNKNOWN pUnkOuterA,

  REFIID riid, LPVOID FAR* ppvObject)

{

TraceMethodEnter("CClassFactory2A::CreateInstance", this);

_DebugHook(GetWide(), MEMBER_PTR(IClassFactory2, CreateInstance));

LPUNKNOWN pUnkOuter;

LPUNKNOWN pUnk;

IDINTERFACE idRef;

HRESULT hResult;

hResult = WrapIUnknownWFromA(pUnkOuterA, &pUnkOuter);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->CreateInstance(pUnkOuter, riid, (LPVOID *)&pUnk);

if (FAILED(hResult))

goto Error;

//

//  Convert the 16 bytes GUID into an internal integer for speed.

//

idRef = WrapTranslateIID(riid);

hResult = WrapInterfaceAFromW(idRef, pUnk, (LPUNKNOWN *)ppvObject);

pUnk->Release();

Error:

if (pUnkOuter)

pUnkOuter->Release();

return hResult;

}

STDMETHODIMP CClassFactory2A::LockServer(BOOL fLock)

{

TraceNotify("CClassFactory2A::LockServer");

_DebugHook(GetWide(), MEMBER_PTR(IClassFactory2, LockServer));

return GetWide()->LockServer(fLock);

}

STDMETHODIMP CClassFactory2A::GetLicInfo(LPLICINFO pLicInfo)

{

TraceMethodEnter("COleClassFactory2A::GetLicInfo", this);

_DebugHook(GetWide(), MEMBER_PTR(IClassFactory2, GetLicInfo));

return GetWide()->GetLicInfo(pLicInfo);

}

STDMETHODIMP CClassFactory2A::RequestLicKey(DWORD dwReserved, BSTRA FAR* pbstrKeyA)

{

TraceMethodEnter("COleClassFactory2A::RequestLicKey", this);

_DebugHook(GetWide(), MEMBER_PTR(IClassFactory2, RequestLicKey));

HRESULT hResult;

BSTR bstrKey, *pbstrKey;

pbstrKey = (pbstrKeyA ? &bstrKey : NULL);

hResult = GetWide()->RequestLicKey(dwReserved, pbstrKey);

if (FAILED(hResult))

return hResult;

if (pbstrKey)

{

hResult = ConvertDispStringToA(bstrKey, pbstrKeyA);

SysFreeString(bstrKey);

}

return hResult;

}

STDMETHODIMP CClassFactory2A::CreateInstanceLic(LPUNKNOWN pUnkOuterA,

LPUNKNOWN pUnkReservedA, REFIID riid, BSTRA bstrKeyA,

LPVOID FAR* ppvObject)

{

TraceMethodEnter("COleClassFactory2A::CreateInstanceLic", this);

_DebugHook(GetWide(), MEMBER_PTR(IClassFactory2, CreateInstanceLic));

LPUNKNOWN pUnkOuter;

LPUNKNOWN pUnkReserved;

LPUNKNOWN pUnk;

IDINTERFACE idRef;

BSTR bstrKey;

HRESULT hResult;

hResult = WrapIUnknownWFromA(pUnkOuterA, &pUnkOuter);

if (FAILED(hResult))

return hResult;

hResult = WrapIUnknownWFromA(pUnkReservedA, &pUnkReserved);

if (FAILED(hResult))

return hResult;

hResult = ConvertDispStringToW(bstrKeyA, &bstrKey);

if (FAILED(hResult))

goto Error;

hResult = GetWide()->CreateInstanceLic(pUnkOuter, pUnkReserved, riid,

bstrKey, (LPVOID *)&pUnk);

if (FAILED(hResult))

goto Error;

//

//  Convert the 16 bytes GUID into an internal integer for speed.

//

idRef = WrapTranslateIID(riid);

hResult = WrapInterfaceAFromW(idRef, pUnk, (LPUNKNOWN *)ppvObject);

pUnk->Release();

Error:

if (bstrKey)

ConvertDispStringFreeW(bstrKey);

if (pUnkReserved)

pUnkReserved->Release();

if (pUnkOuter)

pUnkOuter->Release();

return hResult;

}

/////////////////////////////////////////////////////////////////////////////

// CSpecifyPropertyPagesA class

STDMETHODIMP CSpecifyPropertyPagesA::GetPages(CAUUID FAR* pPages)

{

TraceMethodEnter("CSpecifyPropertyPagesA::GetPages", this);

_DebugHook(GetWide(), MEMBER_PTR(ISpecifyPropertyPages, GetPages));

return GetWide()->GetPages(pPages);

}

/////////////////////////////////////////////////////////////////////////////

// CPerPropertyBrowsingA class

STDMETHODIMP CPerPropertyBrowsingA::GetDisplayString(DISPID dispid,

BSTRA FAR* pbstrA)

{

TraceMethodEnter("CPerPropertyBrowsingA::GetDisplayString", this);

_DebugHook(GetWide(), MEMBER_PTR(IPerPropertyBrowsing, GetDisplayString));

HRESULT hResult;

BSTR bstr, *pbstr;

pbstr = (pbstrA ? &bstr : NULL);

hResult = GetWide()->GetDisplayString(dispid, pbstr);

if (hResult != NOERROR)

{

if (pbstrA)

*pbstrA = NULL;

return hResult;

}

HRESULT hResultConvert = NOERROR;

if (pbstr)

{

hResultConvert = ConvertDispStringToA(bstr, pbstrA);

SysFreeString(bstr);

}

return SUCCEEDED(hResultConvert) ? hResult : hResultConvert;

}

STDMETHODIMP CPerPropertyBrowsingA::MapPropertyToPage(DISPID dispid, LPCLSID lpclsid)

{

TraceMethodEnter("CPerPropertyBrowsingA::MapPropertyToPage", this);

_DebugHook(GetWide(), MEMBER_PTR(IPerPropertyBrowsing, MapPropertyToPage));

return GetWide()->MapPropertyToPage(dispid, lpclsid);

}

STDMETHODIMP CPerPropertyBrowsingA::GetPredefinedStrings(DISPID dispid,

CALPSTR FAR* lpcaStringsOut, CADWORD FAR* lpcaCookiesOut)

{

TraceMethodEnter("CPerPropertyBrowsingA::GetPredefinedStrings", this);

_DebugHook(GetWide(), MEMBER_PTR(IPerPropertyBrowsing, GetPredefinedStrings));

HRESULT hResult;

CALPOLESTR caStringsOut;

hResult = GetWide()->GetPredefinedStrings(dispid, &caStringsOut, lpcaCookiesOut);

if (hResult != NOERROR)

return hResult;

// Convert string array

lpcaStringsOut->cElems = caStringsOut.cElems;

hResult = ConvertStringArrayToA(caStringsOut.pElems, &lpcaStringsOut->pElems,

caStringsOut.cElems);

if (FAILED(hResult))

delete lpcaCookiesOut->pElems;

ConvertStringArrayFree(caStringsOut.pElems, caStringsOut.cElems);

return hResult;

}

STDMETHODIMP CPerPropertyBrowsingA::GetPredefinedValue(DISPID dispid,

DWORD dwCookie, VARIANTA FAR* lpvarOut)

{

TraceMethodEnter("CPerPropertyBrowsingA::GetPredefinedValue", this);

_DebugHook(GetWide(), MEMBER_PTR(IPerPropertyBrowsing, GetPredefinedValue));

HRESULT hResult;

hResult = GetWide()->GetPredefinedValue(dispid, dwCookie, (LPVARIANT)&lpvarOut);

if (FAILED(hResult))

return hResult;

return ConvertVariantToA(lpvarOut);

}

/////////////////////////////////////////////////////////////////////////////

// CPropertyPageSiteA class

STDMETHODIMP CPropertyPageSiteA::OnStatusChange(DWORD flags)

{

TraceMethodEnter("CPropertyPageSiteA::OnStatusChange", this);

_DebugHook(GetWide(), MEMBER_PTR(IPropertyPageSite, OnStatusChange));

return GetWide()->OnStatusChange(flags);

}

STDMETHODIMP CPropertyPageSiteA::GetLocaleID(LCID FAR* pLocaleID)

{

TraceMethodEnter("CPropertyPageSiteA::GetLocaleID", this);

_DebugHook(GetWide(), MEMBER_PTR(IPropertyPageSite, GetLocaleID));

return GetWide()->GetLocaleID(pLocaleID);

}

STDMETHODIMP CPropertyPageSiteA::GetPageContainer(LPUNKNOWN FAR* ppUnk)

{

TraceMethodEnter("CPropertyPageSiteA::GetPageContainer", this);

_DebugHook(GetWide(), MEMBER_PTR(IPropertyPageSite, GetPageContainer));

LPUNKNOWN pUnk;

HRESULT hResult;

hResult = GetWide()->GetPageContainer(&pUnk);

if (FAILED(hResult))

return hResult;

hResult = WrapIUnknownAFromW(pUnk, ppUnk);

pUnk->Release();

return hResult;

}

STDMETHODIMP CPropertyPageSiteA::TranslateAccelerator(LPMSG lpMsg)

{

TraceMethodEnter("CPropertyPageSiteA::TranslateAccelerator", this);

_DebugHook(GetWide(), MEMBER_PTR(IPropertyPageSite, TranslateAccelerator));

return GetWide()->TranslateAccelerator(lpMsg);

}

/////////////////////////////////////////////////////////////////////////////

// CPropertyPage2A class

STDMETHODIMP CPropertyPage2A::SetPageSite(LPPROPERTYPAGESITEA pPageSiteA)

{

TraceMethodEnter("CPropertyPage2A::SetPageSite", this);

_DebugHook(GetWide(), MEMBER_PTR(IPropertyPage2, SetPageSite));

LPPROPERTYPAGESITE pPageSite;

HRESULT hResult;

WrapIPropertyPageSiteWFromA(pPageSiteA, &pPageSite);

hResult = GetWide()->SetPageSite(pPageSite);

pPageSite->Release();

return hResult;

}

STDMETHODIMP CPropertyPage2A::Activate(HWND hwndParent, LPCRECT rect,

BOOL bModal)

{

TraceMethodEnter("CPropertyPage2A::Activate", this);

_DebugHook(GetWide(), MEMBER_PTR(IPropertyPage2, Activate));

return GetWide()->Activate(hwndParent, rect, bModal);

}

STDMETHODIMP CPropertyPage2A::Deactivate()

{

TraceMethodEnter("CPropertyPage2A::Deactivate", this);

_DebugHook(GetWide(), MEMBER_PTR(IPropertyPage2, Deactivate));

return GetWide()->Deactivate();

}

STDMETHODIMP CPropertyPage2A::GetPageInfo(LPPROPPAGEINFOA pPageInfoA)

{

TraceMethodEnter("CPropertyPage2A::GetPageInfo", this);

_DebugHook(GetWide(), MEMBER_PTR(IPropertyPage2, GetPageInfo));

HRESULT hResult;

PROPPAGEINFO pageInfo;

hResult = GetWide()->GetPageInfo(&pageInfo);

if (FAILED(hResult))

return hResult;

hResult = ConvertPROPPAGEINFOToA(&pageInfo, pPageInfoA);

ConvertPROPPAGEINFOFree(&pageInfo);

return hResult;

}

STDMETHODIMP CPropertyPage2A::SetObjects(ULONG cObjects, LPUNKNOWN FAR* ppUnkA)

{

TraceMethodEnter("CPropertyPage2A::SetObjects", this);

_DebugHook(GetWide(), MEMBER_PTR(IPropertyPage2, SetObjects));

HRESULT hResult;

LPUNKNOWN FAR* ppUnk = new LPUNKNOWN[cObjects];

ULONG i;

for (i = 0; i < cObjects; i++)

ppUnk[i] = NULL;

for (i = 0; i < cObjects; i++)

{

hResult = WrapIUnknownWFromA(ppUnkA[i], &ppUnk[i]);

if (FAILED(hResult))

goto Error;

}

hResult = GetWide()->SetObjects(cObjects, ppUnk);

Error:

for (i = 0; i < cObjects; i++)

if (ppUnk[i] != NULL)

ppUnk[i]->Release();

delete [] ppUnk;

return hResult;

}

STDMETHODIMP CPropertyPage2A::Show(UINT nCmdShow)

{

TraceMethodEnter("CPropertyPage2A::Show", this);

_DebugHook(GetWide(), MEMBER_PTR(IPropertyPage2, Show));

return GetWide()->Show(nCmdShow);

}

STDMETHODIMP CPropertyPage2A::Move(LPCRECT prect)

{

TraceMethodEnter("CPropertyPage2A::Move", this);

_DebugHook(GetWide(), MEMBER_PTR(IPropertyPage2, Move));

return GetWide()->Move(prect);

}

STDMETHODIMP CPropertyPage2A::IsPageDirty()

{

TraceMethodEnter("CPropertyPage2A::IsPageDirty", this);

_DebugHook(GetWide(), MEMBER_PTR(IPropertyPage2, IsPageDirty));

return GetWide()->IsPageDirty();

}

STDMETHODIMP CPropertyPage2A::Apply()

{

TraceMethodEnter("CPropertyPage2A::Apply", this);

_DebugHook(GetWide(), MEMBER_PTR(IPropertyPage2, Apply));

return GetWide()->Apply();

}

STDMETHODIMP CPropertyPage2A::Help(LPCSTR lpszHelpDirA)

{

TraceMethodEnter("CPropertyPage2A::Help", this);

_DebugHook(GetWide(), MEMBER_PTR(IPropertyPage2, Help));

WCHAR  szHelpDir[MAX_STRING];

if (lpszHelpDirA != NULL)

ConvertStringToW(lpszHelpDirA, szHelpDir);

else

szHelpDir[0] = L'\0';

return GetWide()->Help(szHelpDir);

}

STDMETHODIMP CPropertyPage2A::TranslateAccelerator(LPMSG lpMsg)

{

TraceMethodEnter("CPropertyPage2A::TranslateAccelerator", this);

_DebugHook(GetWide(), MEMBER_PTR(IPropertyPage2, TranslateAccelerator));

return GetWide()->TranslateAccelerator(lpMsg);

}

STDMETHODIMP CPropertyPage2A::EditProperty(DISPID dispid)

{

TraceMethodEnter("CPropertyPage2A::EditProperty", this);

_DebugHook(GetWide(), MEMBER_PTR(IPropertyPage2, EditProperty));

return GetWide()->EditProperty(dispid);

}

/////////////////////////////////////////////////////////////////////////////

// CFontA class

STDMETHODIMP CFontA::get_Name(BSTRA FAR* pname)

{

TraceMethodEnter("CFontA::get_Name", this);

_DebugHook(GetWide(), MEMBER_PTR(IFont, get_Name));

HRESULT hResult;

BSTR bstr, *pbstr;

pbstr = (pname ? &bstr : NULL);

hResult = GetWide()->get_Name(pbstr);

if (FAILED(hResult))

return hResult;

if (pbstr)

{

hResult = ConvertDispStringToA(bstr, pname);

SysFreeString(bstr);

}

return hResult;

}

STDMETHODIMP CFontA::put_Name(BSTRA name)

{

TraceMethodEnter("CFontA::put_Name", this);

_DebugHook(GetWide(), MEMBER_PTR(IFont, put_Name));

HRESULT hResult;

BSTR bstr;

hResult = ConvertDispStringToW(name, &bstr);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->put_Name(bstr);

ConvertDispStringFreeW(bstr);

return hResult;

}

STDMETHODIMP CFontA::get_Size(CY FAR* psize)

{

TraceMethodEnter("CFontA::get_Size", this);

_DebugHook(GetWide(), MEMBER_PTR(IFont, get_Size));

return GetWide()->get_Size(psize);

}

STDMETHODIMP CFontA::put_Size(CY size)

{

TraceMethodEnter("CFontA::put_Size", this);

_DebugHook(GetWide(), MEMBER_PTR(IFont, put_Size));

return GetWide()->put_Size(size);

}

STDMETHODIMP CFontA::get_Bold(BOOL FAR* pbold)

{

TraceMethodEnter("CFontA::get_Bold", this);

_DebugHook(GetWide(), MEMBER_PTR(IFont, get_Bold));

return GetWide()->get_Bold(pbold);

}

STDMETHODIMP CFontA::put_Bold(BOOL bold)

{

TraceMethodEnter("CFontA::put_Bold", this);

_DebugHook(GetWide(), MEMBER_PTR(IFont, put_Bold));

return GetWide()->put_Bold(bold);

}

STDMETHODIMP CFontA::get_Italic(BOOL FAR* pitalic)

{

TraceMethodEnter("CFontA::get_Italic", this);

_DebugHook(GetWide(), MEMBER_PTR(IFont, get_Italic));

return GetWide()->get_Italic(pitalic);

}

STDMETHODIMP CFontA::put_Italic(BOOL italic)

{

TraceMethodEnter("CFontA::put_Italic", this);

_DebugHook(GetWide(), MEMBER_PTR(IFont, put_Italic));

return GetWide()->put_Italic(italic);

}

STDMETHODIMP CFontA::get_Underline(BOOL FAR* punderline)

{

TraceMethodEnter("CFontA::get_Underline", this);

_DebugHook(GetWide(), MEMBER_PTR(IFont, get_Underline));

return GetWide()->get_Underline(punderline);

}

STDMETHODIMP CFontA::put_Underline(BOOL underline)

{

TraceMethodEnter("CFontA::put_Underline", this);

_DebugHook(GetWide(), MEMBER_PTR(IFont, put_Underline));

return GetWide()->put_Underline(underline);

}

STDMETHODIMP CFontA::get_Strikethrough(BOOL FAR* pstrikethrough)

{

TraceMethodEnter("CFontA::get_Strikethrough", this);

_DebugHook(GetWide(), MEMBER_PTR(IFont, get_Strikethrough));

return GetWide()->get_Strikethrough(pstrikethrough);

}

STDMETHODIMP CFontA::put_Strikethrough(BOOL strikethrough)

{

TraceMethodEnter("CFontA::put_Strikethrough", this);

_DebugHook(GetWide(), MEMBER_PTR(IFont, put_Strikethrough));

return GetWide()->put_Strikethrough(strikethrough);

}

STDMETHODIMP CFontA::get_Weight(short FAR* pweight)

{

TraceMethodEnter("CFontA::get_Weight", this);

_DebugHook(GetWide(), MEMBER_PTR(IFont, get_Weight));

return GetWide()->get_Weight(pweight);

}

STDMETHODIMP CFontA::put_Weight(short weight)

{

TraceMethodEnter("CFontA::put_Weight", this);

_DebugHook(GetWide(), MEMBER_PTR(IFont, put_Weight));

return GetWide()->put_Weight(weight);

}

STDMETHODIMP CFontA::get_Charset(short FAR* pcharset)

{

TraceMethodEnter("CFontA::get_Charset", this);

_DebugHook(GetWide(), MEMBER_PTR(IFont, get_Charset));

return GetWide()->get_Charset(pcharset);

}

STDMETHODIMP CFontA::put_Charset(short charset)

{

TraceMethodEnter("CFontA::put_Charset", this);

_DebugHook(GetWide(), MEMBER_PTR(IFont, put_Charset));

return GetWide()->put_Charset(charset);

}

STDMETHODIMP CFontA::get_hFont(HFONT FAR* phfont)

{

TraceMethodEnter("CFontA::get_hFont", this);

_DebugHook(GetWide(), MEMBER_PTR(IFont, get_hFont));

return GetWide()->get_hFont(phfont);

}

STDMETHODIMP CFontA::Clone(IFontA FAR* FAR* lplpFont)

{

TraceMethodEnter("CFontA::Clone", this);

_DebugHook(GetWide(), MEMBER_PTR(IFont, Clone));

LPFONT lpFont;

HRESULT hResult;

hResult = GetWide()->Clone(&lpFont);

if (FAILED(hResult))

return hResult;

hResult = WrapIFontAFromW(lpFont, lplpFont);

lpFont->Release();

return hResult;

}

STDMETHODIMP CFontA::IsEqual(IFontA FAR* lpFontOtherA)

{

TraceMethodEnter("CFontA::IsEqual", this);

_DebugHook(GetWide(), MEMBER_PTR(IFont, IsEqual));

HRESULT hResult;

LPFONT lpFontOther;

hResult = WrapIFontWFromA(lpFontOtherA, &lpFontOther);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->IsEqual(lpFontOther);

lpFontOther->Release();

return hResult;

}

STDMETHODIMP CFontA::SetRatio(long cyLogical, long cyHimetric)

{

TraceMethodEnter("CFontA::SetRatio", this);

_DebugHook(GetWide(), MEMBER_PTR(IFont, SetRatio));

return GetWide()->SetRatio(cyLogical, cyHimetric);

}

STDMETHODIMP CFontA::QueryTextMetrics(LPTEXTMETRIC lptm)

{

TraceMethodEnter("CFontA::QueryTextMetrics", this);

_DebugHook(GetWide(), MEMBER_PTR(IFont, QueryTextMetrics));

return GetWide()->QueryTextMetrics(lptm);

}

STDMETHODIMP CFontA::AddRefHfont(HFONT hfont)

{

TraceMethodEnter("CFontA::AddRefHfont", this);

_DebugHook(GetWide(), MEMBER_PTR(IFont, AddRefHfont));

return GetWide()->AddRefHfont(hfont);

}

STDMETHODIMP CFontA::ReleaseHfont(HFONT hfont)

{

TraceMethodEnter("CFontA::ReleaseHfont", this);

_DebugHook(GetWide(), MEMBER_PTR(IFont, ReleaseHfont));

return GetWide()->ReleaseHfont(hfont);

}

/////////////////////////////////////////////////////////////////////////////

// CPictureA class

STDMETHODIMP CPictureA::get_Handle(OLE_HANDLE FAR* phandle)

{

TraceMethodEnter("CPictureA::get_Handle", this);

_DebugHook(GetWide(), MEMBER_PTR(IPicture, get_Handle));

return GetWide()->get_Handle(phandle);

}

STDMETHODIMP CPictureA::get_hPal(OLE_HANDLE FAR* phpal)

{

TraceMethodEnter("CPictureA::get_hPal", this);

_DebugHook(GetWide(), MEMBER_PTR(IPicture, get_hPal));

return GetWide()->get_hPal(phpal);

}

STDMETHODIMP CPictureA::get_Type(short FAR* ptype)

{

TraceMethodEnter("CPictureA::get_Type", this);

_DebugHook(GetWide(), MEMBER_PTR(IPicture, get_Type));

return GetWide()->get_Type(ptype);

}

STDMETHODIMP CPictureA::get_Width(OLE_XSIZE_HIMETRIC FAR* pwidth)

{

TraceMethodEnter("CPictureA::get_Width", this);

_DebugHook(GetWide(), MEMBER_PTR(IPicture, get_Width));

return GetWide()->get_Width(pwidth);

}

STDMETHODIMP CPictureA::get_Height(OLE_YSIZE_HIMETRIC FAR* pheight)

{

TraceMethodEnter("CPictureA::get_Height", this);

_DebugHook(GetWide(), MEMBER_PTR(IPicture, get_Height));

return GetWide()->get_Height(pheight);

}

STDMETHODIMP CPictureA::Render(HDC hdc, long x, long y, long cx, long cy,

OLE_XPOS_HIMETRIC xSrc, OLE_YPOS_HIMETRIC ySrc,

OLE_XSIZE_HIMETRIC cxSrc, OLE_YSIZE_HIMETRIC cySrc,

LPRECT lprcWBounds)

{

TraceMethodEnter("CPictureA::Render", this);

_DebugHook(GetWide(), MEMBER_PTR(IPicture, Render));

return GetWide()->Render(hdc, x, y, cx, cy, xSrc, ySrc, cxSrc, cySrc,

lprcWBounds);

}

STDMETHODIMP CPictureA::set_hPal(OLE_HANDLE hpal)

{

TraceMethodEnter("CPictureA::set_hPal", this);

_DebugHook(GetWide(), MEMBER_PTR(IPicture, set_hPal));

return GetWide()->set_hPal(hpal);

}

STDMETHODIMP CPictureA::get_CurDC(HDC FAR * phdcOut)

{

TraceMethodEnter("CPictureA::get_CurDC", this);

_DebugHook(GetWide(), MEMBER_PTR(IPicture, get_CurDC));

return GetWide()->get_CurDC(phdcOut);

}

STDMETHODIMP CPictureA::SelectPicture(

HDC hdcIn, HDC FAR * phdcOut, OLE_HANDLE FAR * phbmpOut)

{

TraceMethodEnter("CPictureA::SelectPicture", this);

_DebugHook(GetWide(), MEMBER_PTR(IPicture, SelectPicture));

return GetWide()->SelectPicture(hdcIn, phdcOut, phbmpOut);

}

STDMETHODIMP CPictureA::get_KeepOriginalFormat(BOOL * pfkeep)

{

TraceMethodEnter("CPictureA::get_KeepOriginalFormat", this);

_DebugHook(GetWide(), MEMBER_PTR(IPicture, get_KeepOriginalFormat));

return GetWide()->get_KeepOriginalFormat(pfkeep);

}

STDMETHODIMP CPictureA::put_KeepOriginalFormat(BOOL fkeep)

{

TraceMethodEnter("CPictureA::put_KeepOriginalFormat", this);

_DebugHook(GetWide(), MEMBER_PTR(IPicture, put_KeepOriginalFormat));

return GetWide()->put_KeepOriginalFormat(fkeep);

}

STDMETHODIMP CPictureA::PictureChanged()

{

TraceMethodEnter("CPictureA::PictureChanged", this);

_DebugHook(GetWide(), MEMBER_PTR(IPicture, PictureChanged));

return GetWide()->PictureChanged();

}

STDMETHODIMP CPictureA::SaveAsFile(LPSTREAMA pStmA, BOOL fSaveMemCopy,

LONG FAR * lpcbSize)

{

TraceMethodEnter("CPictureA::SaveAsFile", this);

_DebugHook(GetWide(), MEMBER_PTR(IPicture, SaveAsFile));

LPSTREAM pStm;

HRESULT hResult;

hResult = WrapIStreamWFromA(pStmA, &pStm);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->SaveAsFile(pStm, fSaveMemCopy, lpcbSize);

pStm->Release();

return hResult;

}

STDMETHODIMP CPictureA::get_Attributes(DWORD FAR * lpdwAttr)

{

TraceMethodEnter("CPictureA::get_Attributes", this);

_DebugHook(GetWide(), MEMBER_PTR(IPicture, get_Attributes));

return GetWide()->get_Attributes(lpdwAttr);

}


 ANSIDISP.H  (OLEANSI Sample)

//+--------------------------------------------------------------------------

//

//  Copyright (C) 1994, Microsoft Corporation.  All Rights Reserved.

//

//  File:       ansidisp.h

//

//  Contents:   ANSI Wrappers for Unicode Dispatch Interfaces and APIs.

//

//  Classes:    CTypeLibA        - ANSI wrapper object for ITypeLib.

//              CTypeInfoA       - ANSI wrapper object for TypeInfo.

//              CTypeCompA       - ANSI wrapper object for TypeComp.

//              CCreateTypeLibA  - ANSI wrapper object for CreateTypeLib.

//              CCreateTypeInfoA - ANSI wrapper object for CreateTypeInfo.

//              CEnumVARIANTA    - ANSI wrapper object for EnumVARIANT.

//              CDispatchA       - ANSI wrapper object for Dispatch.

//

//  History:    01-Nov-93   v-kentc     Created.

//

//---------------------------------------------------------------------------

#if defined(__cplusplus)

interface ITypeLibA;

interface ITypeInfoA;

interface ITypeCompA;

interface ICreateTypeLibA;

interface ICreateTypeInfoA;

interface IEnumVARIANTA;

interface IDispatchA;

#else

typedef interface ITypeLibA ITypeLibA;

typedef interface ITypeInfoA ITypeInfoA;

typedef interface ITypeCompA ITypeCompA;

typedef interface ICreateTypeLibA ICreateTypeLibA;

typedef interface ICreateTypeInfoA ICreateTypeInfoA;

typedef interface IEnumVARIANTA IEnumVARIANTA;

typedef interface IDispatchA IDispatchA;

#endif

typedef ITypeLibA * LPTYPELIBA;

typedef ITypeInfoA * LPTYPEINFOA;

typedef ITypeCompA * LPTYPECOMPA;

typedef ICreateTypeLibA * LPCREATETYPELIBA;

typedef ICreateTypeInfoA * LPCREATETYPEINFOA;

typedef IEnumVARIANTA * LPENUMVARIANTA;

typedef IDispatchA * LPDISPATCHA;

/*---------------------------------------------------------------------*/

/*                         ANSI BSTR API                               */

/*---------------------------------------------------------------------*/

typedef char FAR* BSTRA;

typedef BSTRA * LPBSTRA;

STDAPI_(BSTRA) SysAllocStringA(const char FAR*);

STDAPI_(BSTRA) SysAllocStringLenA(const char FAR*, unsigned int);

STDAPI_(int)   SysReAllocStringA(BSTRA FAR*, const char FAR*);

STDAPI_(int)   SysReAllocStringLenA(BSTRA FAR*, const char FAR*, unsigned int);

STDAPI_(unsigned int) SysStringLenA(BSTRA);

STDAPI_(void)  SysFreeStringA(BSTRA);

/*---------------------------------------------------------------------*/

/*                         ANSI SafeArray API                          */

/*---------------------------------------------------------------------*/

typedef SAFEARRAY SAFEARRAYA;

STDAPI

SafeArrayAllocDescriptorA(unsigned int cDims, SAFEARRAYA FAR* FAR* ppsaOut);

STDAPI SafeArrayAllocDataA(SAFEARRAYA FAR* psa);

STDAPI_(SAFEARRAYA FAR*)

SafeArrayCreateA(

VARTYPE vt,

unsigned int cDims,

SAFEARRAYBOUND FAR* rgsabound);

STDAPI SafeArrayDestroyDescriptorA(SAFEARRAYA FAR* psa);

STDAPI SafeArrayDestroyDataA(SAFEARRAYA FAR* psa);

STDAPI SafeArrayDestroyA(SAFEARRAYA FAR* psa);

STDAPI SafeArrayRedimA(SAFEARRAYA FAR* psa, SAFEARRAYBOUND FAR* psaboundNew);

STDAPI_(unsigned int) SafeArrayGetDimA(SAFEARRAYA FAR* psa);

STDAPI_(unsigned int) SafeArrayGetElemsizeA(SAFEARRAYA FAR* psa);

STDAPI

SafeArrayGetUBoundA(

SAFEARRAYA FAR* psa,

unsigned int nDim,

long FAR* plUbound);

STDAPI

SafeArrayGetLBoundA(

SAFEARRAYA FAR* psa,

unsigned int nDim,

long FAR* plLbound);

STDAPI SafeArrayLockA(SAFEARRAYA FAR* psa);

STDAPI SafeArrayUnlockA(SAFEARRAYA FAR* psa);

STDAPI SafeArrayAccessDataA(SAFEARRAYA FAR* psa, void HUGEP* FAR* ppvData);

STDAPI SafeArrayUnaccessDataA(SAFEARRAYA FAR* psa);

STDAPI

SafeArrayGetElementA(

SAFEARRAYA FAR* psa,

long FAR* rgIndices,

void FAR* pv);

STDAPI

SafeArrayPutElementA(

SAFEARRAYA FAR* psa,

long FAR* rgIndices,

void FAR* pv);

STDAPI

SafeArrayCopyA(

SAFEARRAYA FAR* psa,

SAFEARRAYA FAR* FAR* ppsaOut);

/*---------------------------------------------------------------------*/

/*                         ANSI VARIANT API                            */

/*---------------------------------------------------------------------*/

typedef struct FARSTRUCT tagVARIANTA VARIANTA;

typedef struct FARSTRUCT tagVARIANTA FAR* LPVARIANTA;

typedef struct FARSTRUCT tagVARIANTA VARIANTARGA;

typedef struct FARSTRUCT tagVARIANTA FAR* LPVARIANTARGA;

struct FARSTRUCT tagVARIANTA{

VARTYPE vt;

unsigned short wReserved1;

unsigned short wReserved2;

unsigned short wReserved3;

union {

  unsigned char bVal;              /* VT_UI1                */

  short    iVal;              /* VT_I2                */

  long     lVal;              /* VT_I4                */

  float    fltVal;            /* VT_R4                */

  double       dblVal;            /* VT_R8                */

  VARIANT_BOOL bool;              /* VT_BOOL              */

  SCODE    scode;             /* VT_ERROR             */

  CY       cyVal;             /* VT_CY                */

  DATE     date;              /* VT_DATE              */

  BSTRA    bstrVal;           /* VT_BSTR              */

  IUnknown     FAR* punkVal;      /* VT_UNKNOWN           */

  IDispatchA   FAR* pdispVal;     /* VT_DISPATCH          */

  SAFEARRAYA   FAR* parray;       /* VT_ARRAY|*           */

  unsigned char    FAR* pbVal;        /* VT_BYREF|VT_UI1       */

  short    FAR* piVal;        /* VT_BYREF|VT_I2       */

  long     FAR* plVal;        /* VT_BYREF|VT_I4       */

  float    FAR* pfltVal;      /* VT_BYREF|VT_R4       */

  double       FAR* pdblVal;      /* VT_BYREF|VT_R8       */

  VARIANT_BOOL FAR* pbool;        /* VT_BYREF|VT_BOOL     */

  SCODE    FAR* pscode;       /* VT_BYREF|VT_ERROR    */

  CY       FAR* pcyVal;       /* VT_BYREF|VT_CY       */

  DATE     FAR* pdate;        /* VT_BYREF|VT_DATE     */

  BSTRA    FAR* pbstrVal;     /* VT_BYREF|VT_BSTR     */

  IUnknown   FAR* FAR* ppunkVal;  /* VT_BYREF|VT_UNKNOWN  */

  IDispatchA FAR* FAR* ppdispVal; /* VT_BYREF|VT_DISPATCH */

  SAFEARRAYA FAR* FAR* pparray;   /* VT_BYREF|VT_ARRAY|*  */

  VARIANTA     FAR* pvarVal;      /* VT_BYREF|VT_VARIANT  */

  void     FAR* byref;        /* Generic ByRef        */

}

#if defined(NONAMELESSUNION) || (defined(_MAC) && !defined(__cplusplus) && !defined(_MSC_VER))

u

#endif

;

};

STDAPI_(void)

VariantInitA(VARIANTARGA FAR* pvarg);

STDAPI

VariantClearA(VARIANTARGA FAR* pvarg);

STDAPI

VariantCopyA(

VARIANTARGA FAR* pvargDest,

VARIANTARGA FAR* pvargSrc);

STDAPI

VariantCopyIndA(

VARIANTA FAR* pvarDest,

VARIANTARGA FAR* pvargSrc);

STDAPI

VariantChangeTypeA(

VARIANTARGA FAR* pvargDest,

VARIANTARGA FAR* pvarSrc,

unsigned short wFlags,

VARTYPE vt);

STDAPI

VariantChangeTypeExA(

VARIANTARGA FAR* pvargDest,

VARIANTARGA FAR* pvarSrc,

LCID lcid,

unsigned short wFlags,

VARTYPE vt);

/*---------------------------------------------------------------------*/

/*                   ANSI VARIANT Coercion API                         */

/*---------------------------------------------------------------------*/

#ifndef NOI1

STDAPI VarUI1FromStrA(char FAR* strIn, LCID lcid,

 unsigned long dwFlags, unsigned char FAR* pbOut);

STDAPI VarUI1FromDispA(IDispatchA FAR* pdispIn, LCID lcid, unsigned char FAR* pbOut);

#endif //!NOI1

STDAPI VarI2FromStrA(char FAR* strIn, LCID lcid,

 unsigned long dwFlags, short FAR* psOut);

STDAPI VarI2FromDispA(IDispatchA FAR* pdispIn, LCID lcid, short FAR* psOut);

STDAPI VarI4FromStrA(char FAR* strIn, LCID lcid,

 unsigned long dwFlags, long FAR* plOut);

STDAPI VarI4FromDispA(IDispatchA FAR* pdispIn, LCID lcid, long FAR* plOut);

STDAPI VarR4FromStrA(char FAR* strIn, LCID lcid,

 unsigned long dwFlags, float FAR* pfltOut);

STDAPI VarR4FromDispA(IDispatchA FAR* pdispIn, LCID lcid, float FAR* pfltOut);

STDAPI VarR8FromStrA(char FAR* strIn, LCID lcid,

 unsigned long dwFlags, double FAR* pdblOut);

STDAPI VarR8FromDispA(IDispatchA FAR* pdispIn, LCID lcid, double FAR* pdblOut);

STDAPI VarDateFromStrA(char FAR* strIn, LCID lcid,

   unsigned long dwFlags, DATE FAR* pdateOut);

STDAPI VarDateFromDispA(IDispatchA FAR* pdispIn, LCID lcid, DATE FAR* pdateOut);

STDAPI VarCyFromStrA(char FAR* strIn, LCID lcid,

 unsigned long dwFlags, CY FAR* pcyOut);

STDAPI VarCyFromDispA(IDispatchA FAR* pdispIn, LCID lcid, CY FAR* pcyOut);

#ifndef NOI1

STDAPI VarBstrFromUI1A(unsigned char bVal, LCID lcid,

  unsigned long dwFlags, BSTRA FAR* pbstrOut);

#endif //!NOI1

STDAPI VarBstrFromI2A(short iVal, LCID lcid,

  unsigned long dwFlags, BSTRA FAR* pbstrOut);

STDAPI VarBstrFromI4A(long lIn, LCID lcid,

  unsigned long dwFlags, BSTRA FAR* pbstrOut);

STDAPI VarBstrFromR4A(float fltIn, LCID lcid,

  unsigned long dwFlags, BSTRA FAR* pbstrOut);

STDAPI VarBstrFromR8A(double dblIn, LCID lcid,

  unsigned long dwFlags, BSTRA FAR* pbstrOut);

STDAPI VarBstrFromCyA(CY cyIn, LCID lcid,

  unsigned long dwFlags, BSTRA FAR* pbstrOut);

STDAPI VarBstrFromDateA(DATE dateIn, LCID lcid,

unsigned long dwFlags, BSTRA FAR* pbstrOut);

STDAPI VarBstrFromDispA(IDispatchA FAR* pdispIn, LCID lcid,

unsigned long dwFlags, BSTRA FAR* pbstrOut);

STDAPI VarBstrFromBoolA(VARIANT_BOOL boolIn, LCID lcid,

unsigned long dwFlags, BSTRA FAR* pbstrOut);

STDAPI VarBoolFromStrA(char FAR* strIn, LCID lcid,

   unsigned long dwFlags, VARIANT_BOOL FAR* pboolOut);

STDAPI VarBoolFromDispA(IDispatchA FAR* pdispIn, LCID lcid,

VARIANT_BOOL FAR* pboolOut);

/***********************************************************************/

/*                                                                     */

/*                  ANSI Support for Dispatch.h Elements               */

/*                                                                     */

/***********************************************************************/

/*---------------------------------------------------------------------*/

/*                       ANSI Dispatch Typedefs                        */

/*---------------------------------------------------------------------*/

/*---------------------------------------------------------------------*/

/*                       ANSI Dispatch Typedefs                        */

/*---------------------------------------------------------------------*/

typedef struct tagEXCEPINFOA {

unsigned short wCode;             /* An error code describing the error. */

  /* Either (but not both) the wCode or */

  /* scode fields must be set */

unsigned short wReserved;

BSTRA bstrSource;       /* A textual, human readable name of the

   source of the exception. It is up to the

   IDispatch implementor to fill this in.

   Typically this will be an application name. */

BSTRA bstrDescription;   /* A textual, human readable description of the

   error. If no description is available, NULL

   should be used. */

BSTRA bstrHelpFile;      /* Fully qualified drive, path, and file name

   of a help file with more information about

   the error.  If no help is available, NULL

   should be used. */

unsigned long dwHelpContext;

/* help context of topic within the help file. */

void * pvReserved;

/* Use of this field allows an application to defer filling in

   the bstrDescription, bstrHelpFile, and dwHelpContext fields

   until they are needed.  This field might be used, for example,

   if loading the string for the error is a time-consuming

   operation. If deferred fill-in is not desired, this field should

   be set to NULL. */

#ifdef _MAC

# ifdef _MSC_VER

HRESULT (STDAPICALLTYPE * pfnDeferredFillIn)(struct tagEXCEPINFOA *);

# else

STDAPICALLTYPE HRESULT (* pfnDeferredFillIn)(struct tagEXCEPINFOA *);

# endif

#else

HRESULT (STDAPICALLTYPE * pfnDeferredFillIn)(struct tagEXCEPINFOA *);

#endif

SCODE scode;        /* An SCODE describing the error. */

} EXCEPINFOA, * LPEXCEPINFOA;

typedef struct tagVARDESCA {

MEMBERID memid;

CHAR * lpstrSchema;     /* reserved for future use */

union {

  /* VAR_PERINSTANCE - the offset of this variable within the instance */

  unsigned long oInst;

  /* VAR_CONST - the value of the constant */

  VARIANTA * lpvarValue;

};

ELEMDESC elemdescVar;

unsigned short wVarFlags;

VARKIND varkind;

} VARDESCA, * LPVARDESCA;

typedef struct tagPARAMDATAA {

CHAR * szName;      /* parameter name */

VARTYPE vt;         /* parameter type */

} PARAMDATAA, * LPPARAMDATAA;

typedef struct tagMETHODDATAA {

CHAR * szName;      /* method name */

PARAMDATAA * ppdata;    /* pointer to an array of PARAMDATAs */

DISPID dispid;      /* method ID */

unsigned int iMeth;     /* method index */

CALLCONV cc;        /* calling convention */

unsigned int cArgs;     /* count of arguments */

unsigned short wFlags;  /* same wFlags as on IDispatch::Invoke() */

VARTYPE vtReturn;

} METHODDATAA, * LPMETHODDATAA;

typedef struct tagINTERFACEDATAA {

METHODDATAA * pmethdata;    /* pointer to an array of METHODDATAs */

unsigned int cMembers;  /* count of members */

} INTERFACEDATAA, * LPINTERFACEDATAA;

typedef union tagBINDPTRA {

FUNCDESC * lpfuncdesc;

VARDESCA * lpvardesc;

ITypeCompA * lptcomp;

} BINDPTRA, * LPBINDPTRA;

typedef struct tagDISPPARAMSA{

VARIANTARGA * rgvarg;

DISPID * rgdispidNamedArgs;

unsigned int cArgs;

unsigned int cNamedArgs;

} DISPPARAMSA, * LPDISPPARAMSA;

typedef DISPPARAMS * LPDISPPARAMS;

/*---------------------------------------------------------------------*/

/*                             ITypeLibA                               */

/*---------------------------------------------------------------------*/

#undef  INTERFACE

#define INTERFACE ITypeLibA

DECLARE_INTERFACE_(ITypeLibA, IUnknown)

{

//BEGIN_INTERFACE

/* IUnknown methods */

STDMETHOD(QueryInterface)(THIS_ REFIID riid, void FAR* FAR* ppvObj) PURE;

STDMETHOD_(unsigned long, AddRef)(THIS) PURE;

STDMETHOD_(unsigned long, Release)(THIS) PURE;

/* ITypeLib methods */

STDMETHOD_(unsigned int,GetTypeInfoCount)(THIS) PURE;

STDMETHOD(GetTypeInfo)(THIS_

  unsigned int index, ITypeInfoA FAR* FAR* pptinfo) PURE;

STDMETHOD(GetTypeInfoType)(THIS_

  unsigned int index, TYPEKIND FAR* ptypekind) PURE;

STDMETHOD(GetTypeInfoOfGuid)(THIS_

  REFGUID guid, ITypeInfoA FAR* FAR* pptinfo) PURE;

STDMETHOD(GetLibAttr)(THIS_

  TLIBATTR FAR* FAR* pptlibattr) PURE;

STDMETHOD(GetTypeComp)(THIS_

  ITypeCompA FAR* FAR* pptcomp) PURE;

STDMETHOD(GetDocumentation)(THIS_

  int index,

  BSTRA FAR* pbstrName,

  BSTRA FAR* pbstrDocString,

  unsigned long FAR* pdwHelpContext,

  BSTRA FAR* pbstrHelpFile) PURE;

STDMETHOD(IsName)(THIS_

  CHAR FAR* szNameBuf,

  unsigned long lHashVal,

  int FAR* lpfName) PURE;

STDMETHOD(FindName)(THIS_

  CHAR FAR* szNameBuf,

  unsigned long lHashVal,

  ITypeInfoA FAR* FAR* rgptinfo,

  MEMBERID FAR* rgmemid,

  unsigned short FAR* pcFound) PURE;

STDMETHOD_(void, ReleaseTLibAttr)(THIS_ TLIBATTR FAR* ptlibattr) PURE;

};

typedef ITypeLibA FAR* LPTYPELIBA;

/*---------------------------------------------------------------------*/

/*                            ITypeInfoA                               */

/*---------------------------------------------------------------------*/

#undef  INTERFACE

#define INTERFACE ITypeInfoA

DECLARE_INTERFACE_(ITypeInfoA, IUnknown)

{

//BEGIN_INTERFACE

/* IUnknown methods */

STDMETHOD(QueryInterface)(THIS_ REFIID riid, void FAR* FAR* ppvObj) PURE;

STDMETHOD_(unsigned long, AddRef)(THIS) PURE;

STDMETHOD_(unsigned long, Release)(THIS) PURE;

/* ITypeInfo methods */

STDMETHOD(GetTypeAttr)(THIS_ TYPEATTR FAR* FAR* pptypeattr) PURE;

STDMETHOD(GetTypeComp)(THIS_ ITypeCompA FAR* FAR* pptcomp) PURE;

STDMETHOD(GetFuncDesc)(THIS_

  unsigned int index, FUNCDESC FAR* FAR* ppfuncdesc) PURE;

STDMETHOD(GetVarDesc)(THIS_

  unsigned int index, VARDESCA FAR* FAR* ppvardesc) PURE;

STDMETHOD(GetNames)(THIS_

  MEMBERID memid,

  BSTRA FAR* rgbstrNames,

  unsigned int cMaxNames,

  unsigned int FAR* pcNames) PURE;

STDMETHOD(GetRefTypeOfImplType)(THIS_

  unsigned int index, HREFTYPE FAR* phreftype) PURE;

STDMETHOD(GetImplTypeFlags)(THIS_

  unsigned int index, int FAR* pimpltypeflags) PURE;

STDMETHOD(GetIDsOfNames)(THIS_

  char FAR* FAR* rgszNames,

  unsigned int cNames,

  MEMBERID FAR* rgmemid) PURE;

STDMETHOD(Invoke)(THIS_

  void FAR* pvInstance,

  MEMBERID memid,

  unsigned short wFlags,

  DISPPARAMSA FAR *pdispparamsA,

  VARIANTA FAR *pvarResult,

  EXCEPINFOA FAR *pexcepinfo,

  unsigned int FAR *puArgErr) PURE;

STDMETHOD(GetDocumentation)(THIS_

  MEMBERID memid,

  BSTRA FAR* pbstrName,

  BSTRA FAR* pbstrDocString,

  unsigned long FAR* pdwHelpContext,

  BSTRA FAR* pbstrHelpFile) PURE;

STDMETHOD(GetDllEntry)(THIS_

  MEMBERID memid,

  INVOKEKIND invkind,

  BSTRA FAR* pbstrDllName,

  BSTRA FAR* pbstrName,

  unsigned short FAR* pwOrdinal) PURE;

STDMETHOD(GetRefTypeInfo)(THIS_

  HREFTYPE hreftype, ITypeInfoA FAR* FAR* pptinfo) PURE;

STDMETHOD(AddressOfMember)(THIS_

  MEMBERID memid, INVOKEKIND invkind, void FAR* FAR* ppv) PURE;

STDMETHOD(CreateInstance)(THIS_

  IUnknown FAR* punkOuter,

  REFIID riid,

  void FAR* FAR* ppvObj) PURE;

STDMETHOD(GetMops)(THIS_ MEMBERID memid, BSTRA FAR* pbstrMops) PURE;

STDMETHOD(GetContainingTypeLib)(THIS_

  ITypeLibA FAR* FAR* pptlib, unsigned int FAR* pindex) PURE;

STDMETHOD_(void, ReleaseTypeAttr)(THIS_ TYPEATTR FAR* ptypeattr) PURE;

STDMETHOD_(void, ReleaseFuncDesc)(THIS_ FUNCDESC FAR* pfuncdesc) PURE;

STDMETHOD_(void, ReleaseVarDesc)(THIS_ VARDESCA FAR* pvardesc) PURE;

};

typedef ITypeInfoA FAR* LPTYPEINFOA;

/*---------------------------------------------------------------------*/

/*                            ITypeCompA                               */

/*---------------------------------------------------------------------*/

#undef  INTERFACE

#define INTERFACE ITypeCompA

DECLARE_INTERFACE_(ITypeCompA, IUnknown)

{

//BEGIN_INTERFACE

/* IUnknown methods */

STDMETHOD(QueryInterface)(THIS_ REFIID riid, void FAR* FAR* ppvObj) PURE;

STDMETHOD_(unsigned long, AddRef)(THIS) PURE;

STDMETHOD_(unsigned long, Release)(THIS) PURE;

/* ITypeComp methods */

STDMETHOD(Bind)(THIS_

  CHAR FAR* szName,

  unsigned long lHashVal,

  unsigned short wflags,

  ITypeInfoA FAR* FAR* pptinfo,

  DESCKIND FAR* pdesckind,

  BINDPTRA FAR* pbindptr) PURE;

STDMETHOD(BindType)(THIS_

  CHAR FAR* szName,

  unsigned long lHashVal,

  ITypeInfoA FAR* FAR* pptinfoA,

  ITypeCompA FAR* FAR* pptcompA) PURE;

};

typedef ITypeCompA FAR* LPTYPECOMPA;

/*---------------------------------------------------------------------*/

/*                         ICreateTypeLibA                             */

/*---------------------------------------------------------------------*/

#undef  INTERFACE

#define INTERFACE ICreateTypeLibA

DECLARE_INTERFACE_(ICreateTypeLibA, IUnknown)

{

//BEGIN_INTERFACE

/* IUnknown methods */

STDMETHOD(QueryInterface)(THIS_ REFIID riid, void FAR* FAR* ppvObj) PURE;

STDMETHOD_(unsigned long, AddRef)(THIS) PURE;

STDMETHOD_(unsigned long, Release)(THIS) PURE;

/* ICreateTypeLib methods */

STDMETHOD(CreateTypeInfo)(THIS_

  CHAR FAR* szName,

  TYPEKIND tkind,

  ICreateTypeInfoA FAR* FAR* lplpictinfo) PURE;

STDMETHOD(SetName)(THIS_ CHAR FAR* szName) PURE;

STDMETHOD(SetVersion)(THIS_

  unsigned short wMajorVerNum, unsigned short wMinorVerNum) PURE;

STDMETHOD(SetGuid) (THIS_ REFGUID guid) PURE;

STDMETHOD(SetDocString)(THIS_ CHAR FAR* szDoc) PURE;

STDMETHOD(SetHelpFileName)(THIS_ CHAR FAR* szHelpFileName) PURE;

STDMETHOD(SetHelpContext)(THIS_ unsigned long dwHelpContext) PURE;

STDMETHOD(SetLcid)(THIS_ LCID lcid) PURE;

STDMETHOD(SetLibFlags)(THIS_ unsigned int uLibFlags) PURE;

STDMETHOD(SaveAllChanges)(THIS) PURE;

};

typedef ICreateTypeLibA FAR* LPCREATETYPELIBA;

/*---------------------------------------------------------------------*/

/*                         ICreateTypeInfoA                            */

/*---------------------------------------------------------------------*/

#undef  INTERFACE

#define INTERFACE ICreateTypeInfoA

DECLARE_INTERFACE_(ICreateTypeInfoA, IUnknown)

{

//BEGIN_INTERFACE

/* IUnknown methods */

STDMETHOD(QueryInterface)(THIS_ REFIID riid, void FAR* FAR* ppvObj) PURE;

STDMETHOD_(unsigned long, AddRef)(THIS) PURE;

STDMETHOD_(unsigned long, Release)(THIS) PURE;

/* ICreateTypeInfo methods */

STDMETHOD(SetGuid)(THIS_ REFGUID guid) PURE;

STDMETHOD(SetTypeFlags)(THIS_ unsigned int uTypeFlags) PURE;

STDMETHOD(SetDocString)(THIS_ CHAR FAR* pstrDoc) PURE;

STDMETHOD(SetHelpContext)(THIS_ unsigned long dwHelpContext) PURE;

STDMETHOD(SetVersion)(THIS_

  unsigned short wMajorVerNum, unsigned short wMinorVerNum) PURE;

STDMETHOD(AddRefTypeInfo)(THIS_

  ITypeInfoA FAR* ptinfo, HREFTYPE FAR* phreftype) PURE;

STDMETHOD(AddFuncDesc)(THIS_

  unsigned int index, FUNCDESC FAR* pfuncdesc) PURE;

STDMETHOD(AddImplType)(THIS_

  unsigned int index, HREFTYPE hreftype) PURE;

STDMETHOD(SetImplTypeFlags)(THIS_

  unsigned int index, int impltypeflags) PURE;

STDMETHOD(SetAlignment)(THIS_ unsigned short cbAlignment) PURE;

STDMETHOD(SetSchema)(THIS_ CHAR FAR* lpstrSchema) PURE;

STDMETHOD(AddVarDesc)(THIS_

  unsigned int index, VARDESCA FAR* pvardesc) PURE;

STDMETHOD(SetFuncAndParamNames)(THIS_

  unsigned int index, CHAR FAR* FAR* rgszNames, unsigned int cNames) PURE;

STDMETHOD(SetVarName)(THIS_

  unsigned int index, CHAR FAR* szName) PURE;

STDMETHOD(SetTypeDescAlias)(THIS_

  TYPEDESC FAR* ptdescAlias) PURE;

STDMETHOD(DefineFuncAsDllEntry)(THIS_

  unsigned int index, CHAR FAR* szDllName, CHAR FAR* szProcName) PURE;

STDMETHOD(SetFuncDocString)(THIS_

  unsigned int index, CHAR FAR* szDocString) PURE;

STDMETHOD(SetVarDocString)(THIS_

  unsigned int index, CHAR FAR* szDocString) PURE;

STDMETHOD(SetFuncHelpContext)(THIS_

  unsigned int index, unsigned long dwHelpContext) PURE;

STDMETHOD(SetVarHelpContext)(THIS_

  unsigned int index, unsigned long dwHelpContext) PURE;

STDMETHOD(SetMops)(THIS_

  unsigned int index, BSTRA bstrMops) PURE;

STDMETHOD(SetTypeIdldesc)(THIS_

  IDLDESC FAR* pidldesc) PURE;

STDMETHOD(LayOut)(THIS) PURE;

};

typedef ICreateTypeInfoA FAR* LPCREATETYPEINFOA;

/*---------------------------------------------------------------------*/

/*                          IEnumVARIANTA                              */

/*---------------------------------------------------------------------*/

#undef  INTERFACE

#define INTERFACE IEnumVARIANTA

DECLARE_INTERFACE_(IEnumVARIANTA, IUnknown)

{

//BEGIN_INTERFACE

/* IUnknown methods */

STDMETHOD(QueryInterface)(THIS_ REFIID riid, void FAR* FAR* ppvObj) PURE;

STDMETHOD_(unsigned long, AddRef)(THIS) PURE;

STDMETHOD_(unsigned long, Release)(THIS) PURE;

/* IEnumVARIANT methods */

STDMETHOD(Next)(

  THIS_ unsigned long celt, VARIANTA FAR* rgvar, unsigned long FAR* pceltFetched) PURE;

STDMETHOD(Skip)(THIS_ unsigned long celt) PURE;

STDMETHOD(Reset)(THIS) PURE;

STDMETHOD(Clone)(THIS_ IEnumVARIANTA FAR* FAR* ppenum) PURE;

};

typedef IEnumVARIANTA FAR* LPENUMVARIANTA;

/*---------------------------------------------------------------------*/

/*                             IDispatchA                              */

/*---------------------------------------------------------------------*/

#undef  INTERFACE

#define INTERFACE IDispatchA

DECLARE_INTERFACE_(IDispatchA, IUnknown)

{

//BEGIN_INTERFACE

/* IUnknown methods */

STDMETHOD(QueryInterface)(THIS_ REFIID riid, void * * ppvObj) PURE;

STDMETHOD_(unsigned long, AddRef)(THIS) PURE;

STDMETHOD_(unsigned long, Release)(THIS) PURE;

/* IDispatch methods */

STDMETHOD(GetTypeInfoCount)(THIS_ unsigned int * pctinfo) PURE;

STDMETHOD(GetTypeInfo)(

  THIS_

  unsigned int itinfo,

  LCID lcid,

  ITypeInfoA * * pptinfo) PURE;

STDMETHOD(GetIDsOfNames)(

  THIS_

  REFIID riid,

  char * * rgszNames,

  unsigned int cNames,

  LCID lcid,

  DISPID * rgdispid) PURE;

STDMETHOD(Invoke)(

  THIS_

  DISPID dispidMember,

  REFIID riid,

  LCID lcid,

  unsigned short wFlags,

  DISPPARAMSA * pdispparamsA,

  VARIANTA * pvarResult,

  EXCEPINFOA * pexcepinfo,

  unsigned int * puArgErr) PURE;

};

typedef IDispatchA * LPDISPATCHA;

/*---------------------------------------------------------------------*/

/*                         ANSI Dispatch API                           */

/*---------------------------------------------------------------------*/

#define LHashValOfNameA(lcid, szName) \

LHashValOfNameSysA(SYS_WIN32, lcid, szName)

STDAPI

LoadTypeLibA(const char * szFile, ITypeLibA * * pptlib);

STDAPI

LoadRegTypeLibA(

REFGUID rguid,

unsigned short wVerMajor,

unsigned short wVerMinor,

LCID lcid,

ITypeLibA * * pptlib);

STDAPI

QueryPathOfRegTypeLibA(

REFGUID guid,

unsigned short wMaj,

unsigned short wMin,

LCID lcid,

LPBSTRA lpbstrPathName);

STDAPI

RegisterTypeLibA(

ITypeLibA * ptlib,

char * szFullPath,

char * szHelpDir);

STDAPI

CreateTypeLibA(SYSKIND syskind, const char * szFile, ICreateTypeLibA * * ppctlib);

/*---------------------------------------------------------------------*/

/*                         ANSI Dispatch API                           */

/*---------------------------------------------------------------------*/

STDAPI

DispGetParamA(

DISPPARAMSA * pdispparamsA,

unsigned int position,

VARTYPE vtTarg,

VARIANTA * pvarResult,

unsigned int * puArgErr);

STDAPI

DispGetIDsOfNamesA(

ITypeInfoA * ptinfo,

char * * rgszNames,

unsigned int cNames,

DISPID * rgdispid);

STDAPI

DispInvokeA(

void * _this,

ITypeInfoA * ptinfo,

DISPID dispidMember,

unsigned short wFlags,

DISPPARAMSA * pparamsA,

VARIANTA * pvarResult,

EXCEPINFOA * pexcepinfo,

unsigned int * puArgErr);

STDAPI

CreateDispTypeInfoA(

INTERFACEDATAA * pidata,

LCID lcid,

ITypeInfoA * * pptinfo);

STDAPI

CreateStdDispatchA(

IUnknown * punkOuter,

void * pvThis,

ITypeInfoA * ptinfo,

IUnknown * * ppunkStdDisp);

//

//  Forward declarations

//

class CTypeLibA;

class CTypeInfoA;

class CTypeCompA;

class CCreateTypeLibA;

class CCreateTypeInfoA;

class CEnumVARIANTA;

class CDispatchA;

//+--------------------------------------------------------------------------

//

//  Class:      CTypeLibA

//

//  Synopsis:   Class definition of ITypeLibA

//

//---------------------------------------------------------------------------

class CTypeLibA : CAnsiInterface

{

public:

// *** ITypeLibA methods ***

STDMETHOD_(unsigned int,GetTypeInfoCount)(VOID);

STDMETHOD(GetTypeInfo)(

  unsigned int index, ITypeInfoA * * pptinfo);

STDMETHOD(GetTypeInfoType)(

  unsigned int index, TYPEKIND * ptypekind);

STDMETHOD(GetTypeInfoOfGuid)(

  REFGUID guid, ITypeInfoA * * pptinfo);

STDMETHOD(GetLibAttr)(

  TLIBATTR * * pptlibattr);

STDMETHOD(GetTypeComp)(

  ITypeCompA * * pptcomp);

STDMETHOD(GetDocumentation)(

  int index,

  BSTRA * pbstrName,

  BSTRA * pbstrDocString,

  unsigned long * pdwHelpContext,

  BSTRA * pbstrHelpFile);

STDMETHOD(IsName)(

  CHAR * szNameBuf,

  unsigned long lHashVal,

  int * lpfName);

STDMETHOD(FindName)(

  CHAR * szNameBuf,

  unsigned long lHashVal,

  ITypeInfoA * * rgptinfo,

  MEMBERID * rgmemid,

  unsigned short * pcFound);

STDMETHOD_(void, ReleaseTLibAttr)( TLIBATTR * ptlibattr);

inline CTypeLibA(LPUNKNOWN pUnk, ITypeLib * pWide) :

CAnsiInterface(ID_ITypeLib, pUnk, (LPUNKNOWN)pWide) {};

inline ITypeLib * GetWide() const

{ return (ITypeLib *)m_pObj; };

};

//+--------------------------------------------------------------------------

//

//  Class:      CTypeInfoA

//

//  Synopsis:   Class definition of ITypeInfoA

//

//---------------------------------------------------------------------------

class CTypeInfoA : CAnsiInterface

{

public:

// *** ITypeInfoA methods ***

STDMETHOD(GetTypeAttr)(TYPEATTR FAR* FAR* pptypeattr);

STDMETHOD(GetTypeComp)(ITypeCompA FAR* FAR* pptcomp);

STDMETHOD(GetFuncDesc)(

  unsigned int index, FUNCDESC FAR* FAR* ppfuncdesc);

STDMETHOD(GetVarDesc)(

  unsigned int index, VARDESCA FAR* FAR* ppvardesc);

STDMETHOD(GetNames)(

  MEMBERID memid,

  BSTRA FAR* rgbstrNames,

  unsigned int cMaxNames,

  unsigned int FAR* pcNames);

STDMETHOD(GetRefTypeOfImplType)(

  unsigned int index, HREFTYPE FAR* phreftype);

STDMETHOD(GetImplTypeFlags)(

  unsigned int index, int FAR* pimpltypeflags);

STDMETHOD(GetIDsOfNames)(

  char FAR* FAR* rgszNames,

  unsigned int cNames,

  MEMBERID FAR* rgmemid);

STDMETHOD(Invoke)(

  void FAR* pvInstance,

  MEMBERID memid,

  unsigned short wFlags,

  DISPPARAMSA FAR *pdispparamsA,

  VARIANTA FAR *pvarResult,

  EXCEPINFOA FAR *pexcepinfo,

  unsigned int FAR *puArgErr);

STDMETHOD(GetDocumentation)(

  MEMBERID memid,

  BSTRA FAR* pbstrName,

  BSTRA FAR* pbstrDocString,

  unsigned long FAR* pdwHelpContext,

  BSTRA FAR* pbstrHelpFile);

STDMETHOD(GetDllEntry)(

  MEMBERID memid,

  INVOKEKIND invkind,

  BSTRA FAR* pbstrDllName,

  BSTRA FAR* pbstrName,

  unsigned short FAR* pwOrdinal);

STDMETHOD(GetRefTypeInfo)(

  HREFTYPE hreftype, ITypeInfoA FAR* FAR* pptinfo);

STDMETHOD(AddressOfMember)(

  MEMBERID memid, INVOKEKIND invkind, void FAR* FAR* ppv);

STDMETHOD(CreateInstance)(

  IUnknown FAR* punkOuter,

  REFIID riid,

  void FAR* FAR* ppvObj);

STDMETHOD(GetMops)(MEMBERID memid, BSTRA FAR* pbstrMops);

STDMETHOD(GetContainingTypeLib)(

  ITypeLibA FAR* FAR* pptlib, unsigned int FAR* pindex);

STDMETHOD_(void, ReleaseTypeAttr)(TYPEATTR FAR* ptypeattr);

STDMETHOD_(void, ReleaseFuncDesc)(FUNCDESC FAR* pfuncdesc);

STDMETHOD_(void, ReleaseVarDesc)(VARDESCA FAR* pvardesc);

inline CTypeInfoA(LPUNKNOWN pUnk, ITypeInfo * pWide) :

CAnsiInterface(ID_ITypeInfo, pUnk, (LPUNKNOWN)pWide) {};

inline ITypeInfo * GetWide() const

{ return (ITypeInfo *)m_pObj; };

};

//+--------------------------------------------------------------------------

//

//  Class:      CTypeCompA

//

//  Synopsis:   Class definition of ITypeCompA

//

//---------------------------------------------------------------------------

class CTypeCompA : CAnsiInterface

{

public:

// *** ITypeCompA methods ***

STDMETHOD(Bind)(

  CHAR * szName,

  unsigned long lHashVal,

  unsigned short wflags,

  ITypeInfoA * * pptinfo,

  DESCKIND * pdesckind,

  BINDPTRA * pbindptr);

STDMETHOD(BindType)(

  CHAR * szName,

  unsigned long lHashVal,

  ITypeInfoA * * pptinfoA,

  ITypeCompA * * pptcompA);

inline CTypeCompA(LPUNKNOWN pUnk, ITypeComp * pWide) :

CAnsiInterface(ID_ITypeComp, pUnk, (LPUNKNOWN)pWide) {};

inline ITypeComp * GetWide() const

{ return (ITypeComp *)m_pObj; };

};

//+--------------------------------------------------------------------------

//

//  Class:      CCreateTypeLibA

//

//  Synopsis:   Class definition of ICreateTypeLibA

//

//---------------------------------------------------------------------------

class CCreateTypeLibA : CAnsiInterface

{

public:

// *** ICreateTypeLibA methods ***

STDMETHOD(CreateTypeInfo)(

  CHAR * szName,

  TYPEKIND tkind,

  ICreateTypeInfoA * * lplpictinfo);

STDMETHOD(SetName)( CHAR * szName);

STDMETHOD(SetVersion)(

  unsigned short wMajorVerNum, unsigned short wMinorVerNum);

STDMETHOD(SetGuid) ( REFGUID guid);

STDMETHOD(SetDocString)( CHAR * szDoc);

STDMETHOD(SetHelpFileName)( CHAR * szHelpFileName);

STDMETHOD(SetHelpContext)( unsigned long dwHelpContext);

STDMETHOD(SetLcid)( LCID lcid);

STDMETHOD(SetLibFlags)( unsigned int uLibFlags);

STDMETHOD(SaveAllChanges)(VOID);

inline CCreateTypeLibA(LPUNKNOWN pUnk, ICreateTypeLib * pWide) :

CAnsiInterface(ID_ICreateTypeLib, pUnk, (LPUNKNOWN)pWide) {};

inline ICreateTypeLib * GetWide() const

{ return (ICreateTypeLib *)m_pObj; };

};

//+--------------------------------------------------------------------------

//

//  Class:      CCreateTypeInfoA

//

//  Synopsis:   Class definition of ICreateTypeInfoA

//

//---------------------------------------------------------------------------

class CCreateTypeInfoA : CAnsiInterface

{

public:

// *** ICreateTypeInfoA methods ***

STDMETHOD(SetGuid)( REFGUID guid);

STDMETHOD(SetTypeFlags)( unsigned int uTypeFlags);

STDMETHOD(SetDocString)( CHAR * pstrDoc);

STDMETHOD(SetHelpContext)( unsigned long dwHelpContext);

STDMETHOD(SetVersion)(

  unsigned short wMajorVerNum, unsigned short wMinorVerNum);

STDMETHOD(AddRefTypeInfo)(

  ITypeInfoA * ptinfo, HREFTYPE * phreftype);

STDMETHOD(AddFuncDesc)(

  unsigned int index, FUNCDESC * pfuncdesc);

STDMETHOD(AddImplType)(

  unsigned int index, HREFTYPE hreftype);

STDMETHOD(SetImplTypeFlags)(

  unsigned int index, int impltypeflags);

STDMETHOD(SetAlignment)( unsigned short cbAlignment);

STDMETHOD(SetSchema)( CHAR * lpstrSchema);

STDMETHOD(AddVarDesc)(

  unsigned int index, VARDESCA * pvardesc);

STDMETHOD(SetFuncAndParamNames)(

  unsigned int index, CHAR * * rgszNames, unsigned int cNames);

STDMETHOD(SetVarName)(

  unsigned int index, CHAR * szName);

STDMETHOD(SetTypeDescAlias)(

  TYPEDESC * ptdescAlias);

STDMETHOD(DefineFuncAsDllEntry)(

  unsigned int index, CHAR * szDllName, CHAR * szProcName);

STDMETHOD(SetFuncDocString)(

  unsigned int index, CHAR * szDocString);

STDMETHOD(SetVarDocString)(

  unsigned int index, CHAR * szDocString);

STDMETHOD(SetFuncHelpContext)(

  unsigned int index, unsigned long dwHelpContext);

STDMETHOD(SetVarHelpContext)(

  unsigned int index, unsigned long dwHelpContext);

STDMETHOD(SetMops)(

  unsigned int index, BSTRA bstrMops);

STDMETHOD(SetTypeIdldesc)(

  IDLDESC * pidldesc);

STDMETHOD(LayOut)(VOID);

inline CCreateTypeInfoA(LPUNKNOWN pUnk, ICreateTypeInfo * pWide) :

CAnsiInterface(ID_ICreateTypeInfo, pUnk, (LPUNKNOWN)pWide) {};

inline ICreateTypeInfo * GetWide() const

{ return (ICreateTypeInfo *)m_pObj; };

};

//+--------------------------------------------------------------------------

//

//  Class:      CEnumVARIANTA

//

//  Synopsis:   Class definition of IEnumVARIANTA

//

//---------------------------------------------------------------------------

class CEnumVARIANTA : CAnsiInterface

{

public:

// *** IEnumVARIANTA methods ***

STDMETHOD(Next)(

   unsigned long celt, VARIANTA * rgvar, unsigned long * pceltFetched);

STDMETHOD(Skip)( unsigned long celt);

STDMETHOD(Reset)(VOID);

STDMETHOD(Clone)( IEnumVARIANTA * * ppenum);

inline CEnumVARIANTA(LPUNKNOWN pUnk, IEnumVARIANT * pWide) :

CAnsiInterface(ID_IEnumVARIANT, pUnk, (LPUNKNOWN)pWide) {};

inline IEnumVARIANT * GetWide() const

{ return (IEnumVARIANT *)m_pObj; };

};

//+--------------------------------------------------------------------------

//

//  Class:      CDispatchA

//

//  Synopsis:   Class definition of IDispatchA

//

//---------------------------------------------------------------------------

class CDispatchA : CAnsiInterface

{

public:

// *** IDispatchA methods ***

STDMETHOD(GetTypeInfoCount)(unsigned int * pctinfo);

STDMETHOD(GetTypeInfo)(

  unsigned int itinfo,

  LCID lcid,

  ITypeInfoA * * pptinfo);

STDMETHOD(GetIDsOfNames)(

  REFIID riid,

  char * * rgszNames,

  unsigned int cNames,

  LCID lcid,

  DISPID * rgdispid);

STDMETHOD(Invoke)(

  DISPID dispidMember,

  REFIID riid,

  LCID lcid,

  unsigned short wFlags,

  DISPPARAMSA * pdispparamsA,

  VARIANTA * pvarResult,

  EXCEPINFOA * pexcepinfo,

  unsigned int * puArgErr);

inline CDispatchA(LPUNKNOWN pUnk, IDispatch * pWide) :

CAnsiInterface(ID_IDispatch, pUnk, (LPUNKNOWN)pWide) {};

inline IDispatch * GetWide() const

{ return (IDispatch *)m_pObj; };

};

#ifndef NOERRORINFO

//+--------------------------------------------------------------------------

//

//  Class:      CErrorInfoA

//

//  Synopsis:   Class definition of IErrorInfoA

//

//---------------------------------------------------------------------------

class CErrorInfoA : CAnsiInterface

{

public:

// *** IErrorInfoA methods ***

STDMETHOD(GetGUID)(GUID *pguid);

STDMETHOD(GetSource)(BSTRA *pbstrSource);

STDMETHOD(GetDescription)(BSTRA *pbstrDescription);

STDMETHOD(GetHelpFile)(BSTRA *pbstrHelpFile);

STDMETHOD(GetHelpContext)(DWORD *pdwHelpContext);

inline CErrorInfoA(LPUNKNOWN pUnk, IErrorInfo * pObj) :

CAnsiInterface(ID_IErrorInfo, pUnk, (LPUNKNOWN)pObj) {};

inline IErrorInfo * GetWide() const

{ return (IErrorInfo *)m_pObj; };

};

//+--------------------------------------------------------------------------

//

//  Class:      CCreateErrorInfoA

//

//  Synopsis:   Class definition of ICreateErrorInfoA

//

//---------------------------------------------------------------------------

class CCreateErrorInfoA : CAnsiInterface

{

public:

// *** ICreateErrorInfoA methods ***

STDMETHOD(SetGUID)(REFGUID rguid);

STDMETHOD(SetSource)(LPSTR szSource);

STDMETHOD(SetDescription)(LPSTR szDescription);

STDMETHOD(SetHelpFile)(LPSTR szHelpFile);

STDMETHOD(SetHelpContext)(DWORD dwHelpContext);

inline CCreateErrorInfoA(LPUNKNOWN pUnk, ICreateErrorInfo * pObj) :

CAnsiInterface(ID_ICreateErrorInfo, pUnk, (LPUNKNOWN)pObj) {};

inline ICreateErrorInfo * GetWide() const

{ return (ICreateErrorInfo *)m_pObj; };

};

#endif //!NOERRORINFO


 ANSIDISP.CPP  (OLEANSI Sample)

//+--------------------------------------------------------------------------

//

//  Copyright (C) 1994, Microsoft Corporation.  All Rights Reserved.

//

//  File:       ansidisp.cpp

//

//  Contents:   ANSI Wrappers for Dispatch Interfaces and APIs.

//

//  Classes:    CTypeLibA        - ANSI wrapper object for ITypeLib.

//              CTypeInfoA       - ANSI wrapper object for ITypeInfo.

//              CTypeCompA       - ANSI wrapper object for ITypeComp.

//              CCreateTypeLibA  - ANSI wrapper object for ICreateTypeLib.

//              CCreateTypeInfoA - ANSI wrapper object for ICreateTypeInfo.

//              CEnumVARIANTA    - ANSI wrapper object for IEnumVARIANT.

//              CDispatchA       - ANSI wrapper object for IDispatch.

//

//  History:    01-Nov-93   v-kentc     Created.

//              31-Mar-94   v-kentc     Result return fix ::AddRefTypeInfo.

//

//---------------------------------------------------------------------------

#include "Ole2Ansi.h"


 ITypeLibA Implementation  (OLEANSI Sample)

//***************************************************************************

//

//                   ITypeLibA Implementation

//

//***************************************************************************

//+--------------------------------------------------------------------------

//

//  Member:     CTypeLibA::GetTypeInfoCount, public

//

//  Synopsis:   Thunks GetTypeInfoCount to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP_(unsigned int) CTypeLibA::GetTypeInfoCount(VOID)

{

TraceMethodEnter("CTypeLibA::GetTypeInfoCount", this);

_DebugHook(GetWide(), MEMBER_PTR(ITypeLib, GetTypeInfoCount));

return GetWide()->GetTypeInfoCount();

}

//+--------------------------------------------------------------------------

//

//  Member:     CTypeLibA::GetTypeInfo, public

//

//  Synopsis:   Thunks GetTypeInfo to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CTypeLibA::GetTypeInfo(unsigned int index,

ITypeInfoA * * pptinfo)

{

TraceMethodEnter("CTypeLibA::GetTypeInfo", this);

LPTYPEINFO pTypeInfo;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(ITypeLib, GetTypeInfo));

hResult = GetWide()->GetTypeInfo(index, &pTypeInfo);

if (FAILED(hResult))

return (hResult);

hResult = WrapITypeInfoAFromW(pTypeInfo, pptinfo);

pTypeInfo->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CTypeLibA::GetTypeInfoType, public

//

//  Synopsis:   Thunks GetTypeInfoType to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CTypeLibA::GetTypeInfoType(unsigned int index,

TYPEKIND * ptypekind)

{

TraceMethodEnter("CTypeLibA::GetTypeInfoType", this);

_DebugHook(GetWide(), MEMBER_PTR(ITypeLib, GetTypeInfoType));

return GetWide()->GetTypeInfoType(index, ptypekind);

}

//+--------------------------------------------------------------------------

//

//  Member:     CTypeLibA::GetTypeInfoOfGuid, public

//

//  Synopsis:   Thunks GetTypeInfoOfGuid to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CTypeLibA::GetTypeInfoOfGuid(

  REFGUID guid, ITypeInfoA * * pptinfo)

{

TraceMethodEnter("CTypeLibA::GetTypeInfoOfGuid", this);

LPTYPEINFO pTypeInfo;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(ITypeLib, GetTypeInfoOfGuid));

hResult = GetWide()->GetTypeInfoOfGuid(guid, &pTypeInfo);

if (FAILED(hResult))

return (hResult);

hResult = WrapITypeInfoAFromW(pTypeInfo, pptinfo);

pTypeInfo->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CTypeLibA::GetLibAttr, public

//

//  Synopsis:   Thunks GetLibAttr to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CTypeLibA::GetLibAttr(TLIBATTR * * pptlibattr)

{

TraceMethodEnter("CTypeLibA::GetLibAttr", this);

_DebugHook(GetWide(), MEMBER_PTR(ITypeLib, GetLibAttr));

return GetWide()->GetLibAttr(pptlibattr);

}

//+--------------------------------------------------------------------------

//

//  Member:     CTypeLibA::GetTypeComp, public

//

//  Synopsis:   Thunks GetTypeComp to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CTypeLibA::GetTypeComp(ITypeCompA * * pptcomp)

{

TraceMethodEnter("CTypeLibA::GetTypeComp", this);

LPTYPECOMP pTypeComp;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(ITypeLib, GetTypeComp));

hResult = GetWide()->GetTypeComp(&pTypeComp);

if (FAILED(hResult))

return (hResult);

hResult = WrapITypeCompAFromW(pTypeComp, pptcomp);

pTypeComp->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CTypeLibA::GetDocumentation, public

//

//  Synopsis:   Thunks GetDocumentation to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CTypeLibA::GetDocumentation(int index, BSTRA * pbstrNameA,

BSTRA * pbstrDocStringA, unsigned long * pdwHelpContext,

BSTRA * pbstrHelpFileA)

{

TraceMethodEnter("CTypeLibA::GetDocumentation", this);

BSTR pstrName, *ppstrName;

BSTR pstrDocString, *ppstrDocString;

BSTR pstrHelpFile, *ppstrHelpFile;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(ITypeLib, GetDocumentation));

if (pbstrNameA)

ppstrName = &pstrName;

else

ppstrName = NULL;

if (pbstrDocStringA)

ppstrDocString = &pstrDocString;

else

ppstrDocString = NULL;

if (pbstrHelpFileA)

ppstrHelpFile = &pstrHelpFile;

else

ppstrHelpFile = NULL;

hResult = GetWide()->GetDocumentation(index, ppstrName, ppstrDocString,

pdwHelpContext, ppstrHelpFile);

if (FAILED(hResult))

return (hResult);

if (ppstrName)

{

hResult = ConvertDispStringToA(pstrName, pbstrNameA);

if (FAILED(hResult))

goto Error;

SysFreeString(pstrName);

}

if (ppstrDocString)

{

hResult = ConvertDispStringToA(pstrDocString, pbstrDocStringA);

if (FAILED(hResult))

goto Error1;

SysFreeString(pstrDocString);

}

if (ppstrHelpFile)

{

hResult = ConvertDispStringToA(pstrHelpFile, pbstrHelpFileA);

if (FAILED(hResult))

goto Error2;

SysFreeString(pstrHelpFile);

}

return NOERROR;

Error2:

if (pbstrDocStringA)

ConvertDispStringFreeA(*pbstrDocStringA);

Error1:

if (pbstrNameA)

ConvertDispStringFreeA(*pbstrNameA);

Error:

if (ppstrName)

SysFreeString(pstrName);

if (ppstrDocString)

SysFreeString(pstrDocString);

if (ppstrHelpFile)

SysFreeString(pstrHelpFile);

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CTypeLibA::IsName, public

//

//  Synopsis:   Thunks IsName to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CTypeLibA::IsName(CHAR * szNameBufA, unsigned long lHashVal,

int * lpfName)

{

TraceMethodEnter("CTypeLibA::IsName", this);

OLECHAR szNameBuf[MAX_STRING];

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(ITypeLib, IsName));

ConvertStringToW(szNameBufA, szNameBuf);

hResult = GetWide()->IsName(szNameBuf, lHashVal, lpfName);

// copy back result into original string (guaranteed to be same length)

if (hResult == NOERROR && *lpfName != 0)

{

int Count = lstrlen(szNameBufA);

WideCharToMultiByte(CP_ACP, 0, szNameBuf, Count, szNameBufA, Count, NULL, NULL);

}

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CTypeLibA::FindName, public

//

//  Synopsis:   Thunks FindName to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CTypeLibA::FindName(CHAR * szNameBufA, unsigned long lHashVal,

ITypeInfoA * * rgptinfo, MEMBERID * rgmemid, unsigned short * pcFound)

{

TraceMethodEnter("CTypeLibA::FindName", this);

OLECHAR       szNameBuf[MAX_STRING];

LPTYPEINFO    pTypeInfo;

LPTYPEINFOA   pTypeInfoA;

HRESULT       hResult;

_DebugHook(GetWide(), MEMBER_PTR(ITypeLib, FindName));

ConvertStringToW(szNameBufA, szNameBuf);

hResult = GetWide()->FindName(szNameBuf, lHashVal,

(LPTYPEINFO *)rgptinfo,

rgmemid,

pcFound);

if (SUCCEEDED(hResult))

{

// now convert the array of ITypeInfo's to ITypeInfoA's in-place

for (USHORT i = 0; i < *pcFound; i++)

{

pTypeInfo = (LPTYPEINFO)rgptinfo[i];

if (SUCCEEDED(hResult))   // if we haven't failed already

{

hResult = WrapITypeInfoAFromW((LPTYPEINFO)rgptinfo[i], &pTypeInfoA);

if (FAILED(hResult))  // release any Ansi wrappers we've made so far

{

for (USHORT j = 0; j < i; j++)

{

rgptinfo[j]->Release();

}

}

else

{

rgptinfo[i] = pTypeInfoA;

}

}

pTypeInfo->Release();

}

}

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CTypeLibA::ReleaseTLibAttr, public

//

//  Synopsis:   Thunks ReleaseTLibAttr to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP_(void) CTypeLibA::ReleaseTLibAttr(TLIBATTR * ptlibattr)

{

TraceMethodEnter("CTypeLibA::ReleaseTLibAttr", this);

_DebugHook(GetWide(), MEMBER_PTR(ITypeLib, ReleaseTLibAttr));

GetWide()->ReleaseTLibAttr(ptlibattr);

}


 ITypeInfoA Implementation  (OLEANSI Sample)

//***************************************************************************

//

//                   ITypeInfoA Implementation

//

//***************************************************************************

//+--------------------------------------------------------------------------

//

//  Member:     CTypeInfoA::GetTypeAttr, public

//

//  Synopsis:   Thunks GetTypeAttr to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CTypeInfoA::GetTypeAttr(TYPEATTR * * pptypeattr)

{

TraceMethodEnter("CTypeInfoA::GetTypeAttr", this);

_DebugHook(GetWide(), MEMBER_PTR(ITypeInfo, GetTypeAttr));

return GetWide()->GetTypeAttr(pptypeattr);

}

//+--------------------------------------------------------------------------

//

//  Member:     CTypeInfoA::GetTypeComp, public

//

//  Synopsis:   Thunks GetTypeComp to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CTypeInfoA::GetTypeComp(ITypeCompA * * pptcomp)

{

TraceMethodEnter("CTypeInfoA::GetTypeComp", this);

LPTYPECOMP pTypeComp;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(ITypeInfo, GetTypeComp));

hResult = GetWide()->GetTypeComp(&pTypeComp);

if (FAILED(hResult))

return (hResult);

hResult = WrapITypeCompAFromW(pTypeComp, pptcomp);

pTypeComp->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CTypeInfoA::GetFuncDesc, public

//

//  Synopsis:   Thunks GetFuncDesc to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CTypeInfoA::GetFuncDesc(unsigned int index,

FUNCDESC * * ppfuncdesc)

{

TraceMethodEnter("CTypeInfoA::GetFuncDesc", this);

_DebugHook(GetWide(), MEMBER_PTR(ITypeInfo, GetFuncDesc));

return GetWide()->GetFuncDesc(index, ppfuncdesc);

}

//+--------------------------------------------------------------------------

//

//  Member:     CTypeInfoA::GetVarDesc, public

//

//  Synopsis:   Thunks GetVarDesc to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CTypeInfoA::GetVarDesc(unsigned int index,

VARDESCA * * ppvardescA)

{

TraceMethodEnter("CTypeInfoA::GetVarDesc", this);

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(ITypeInfo, GetVarDesc));

hResult = GetWide()->GetVarDesc(index, (VARDESC * *)ppvardescA);

if (FAILED(hResult))

return (hResult);

hResult = ConvertVARDESCToA(*ppvardescA);

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CTypeInfoA::GetNames, public

//

//  Synopsis:   Thunks GetNames to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CTypeInfoA::GetNames(MEMBERID memid, BSTRA * rgbstrNames,

unsigned int cMaxNames, unsigned int * pcNames)

{

TraceMethodEnter("CTypeInfoA::GetNames", this);

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(ITypeInfo, GetNames));

hResult = GetWide()->GetNames(memid, (BSTR *)rgbstrNames, cMaxNames,

pcNames);

if (FAILED(hResult))

return (hResult);

return ConvertDispStringArrayToA(rgbstrNames, *pcNames);

}

//+--------------------------------------------------------------------------

//

//  Member:     CTypeInfoA::GetRefTypeOfImplType, public

//

//  Synopsis:   Thunks GetRefTypeOfImplType to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CTypeInfoA::GetRefTypeOfImplType(unsigned int index,

HREFTYPE * phreftype)

{

TraceMethodEnter("CTypeInfoA::GetRefTypeOfImplType", this);

_DebugHook(GetWide(), MEMBER_PTR(ITypeInfo, GetRefTypeOfImplType));

return GetWide()->GetRefTypeOfImplType(index, phreftype);

}

//+--------------------------------------------------------------------------

//

//  Member:     CTypeInfoA::GetImplTypeFlags, public

//

//  Synopsis:   Thunks GetImplTypeFlags to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CTypeInfoA::GetImplTypeFlags(unsigned int index,

int * pimpltypeflags)

{

TraceMethodEnter("CTypeInfoA::GetImplTypeFlags", this);

_DebugHook(GetWide(), MEMBER_PTR(ITypeInfo, GetImplTypeFlags));

return GetWide()->GetImplTypeFlags(index, pimpltypeflags);

}

//+--------------------------------------------------------------------------

//

//  Member:     CTypeInfoA::GetIDsOfNames, public

//

//  Synopsis:   Thunks GetIDsOfNames to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CTypeInfoA::GetIDsOfNames(CHAR * * rgszNamesA,

unsigned int cNames, MEMBERID * rgmemid)

{

TraceMethodEnter("CTypeInfoA::GetIDsOfNames", this);

LPWSTR * rgszNames;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(ITypeInfo, GetIDsOfNames));

hResult = ConvertStringArrayToW(rgszNamesA, &rgszNames, cNames);

if (FAILED(hResult))

return (hResult);

hResult = GetWide()->GetIDsOfNames(rgszNames, cNames, rgmemid);

ConvertStringArrayFree(rgszNames, cNames);

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CTypeInfoA::Invoke, public

//

//  Synopsis:   Thunks Invoke to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CTypeInfoA::Invoke(void * pvInstance, MEMBERID memid,

unsigned short wFlags, DISPPARAMSA *pdispparamsA,

VARIANTA *pvarResultA, EXCEPINFOA *pexcepinfoA,

unsigned int *puArgErr)

{

TraceMethodEnter("CTypeInfoA::Invoke", this);

LPDISPPARAMS pDispParams;

LPVARIANT pByrefTemp;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(ITypeInfo, Invoke));

hResult = ConvertDispParamsToW(pdispparamsA, &pDispParams, &pByrefTemp);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->Invoke(pvInstance, memid, wFlags, pDispParams,

(LPVARIANT)pvarResultA, (EXCEPINFO *)pexcepinfoA, puArgErr);

if (hResult == DISP_E_EXCEPTION)

ConvertExcepInfoToA(pexcepinfoA);

if (FAILED(hResult))

goto Error;

if (pByrefTemp)

{

hResult = ConvertDispParamsCopyBack(pdispparamsA, pByrefTemp);

if (FAILED(hResult))

goto Error;

}

hResult = ConvertVariantToA(pvarResultA);

if (FAILED(hResult))

goto Error;

Error:

ConvertDispParamsFree(pDispParams, pByrefTemp);

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CTypeInfoA::GetDocumentation, public

//

//  Synopsis:   Thunks GetDocumentation to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CTypeInfoA::GetDocumentation(MEMBERID memid, BSTRA * pbstrNameA,

BSTRA * pbstrDocStringA, unsigned long * pdwHelpContext,

BSTRA * pbstrHelpFileA)

{

TraceMethodEnter("CTypeInfoA::GetDocumentation", this);

BSTR pstrName, *ppstrName;

BSTR pstrDocString, *ppstrDocString;

BSTR pstrHelpFile, *ppstrHelpFile;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(ITypeInfo, GetDocumentation));

if (pbstrNameA)

ppstrName = &pstrName;

else

ppstrName = NULL;

if (pbstrDocStringA)

ppstrDocString = &pstrDocString;

else

ppstrDocString = NULL;

if (pbstrHelpFileA)

ppstrHelpFile = &pstrHelpFile;

else

ppstrHelpFile = NULL;

hResult = GetWide()->GetDocumentation(memid, ppstrName, ppstrDocString,

pdwHelpContext, ppstrHelpFile);

if (FAILED(hResult))

return (hResult);

if (ppstrName)

{

hResult = ConvertDispStringToA(pstrName, pbstrNameA);

if (FAILED(hResult))

goto Error;

SysFreeString(pstrName);

}

if (ppstrDocString)

{

hResult = ConvertDispStringToA(pstrDocString, pbstrDocStringA);

if (FAILED(hResult))

goto Error1;

SysFreeString(pstrDocString);

}

if (ppstrHelpFile)

{

hResult = ConvertDispStringToA(pstrHelpFile, pbstrHelpFileA);

if (FAILED(hResult))

goto Error2;

SysFreeString(pstrHelpFile);

}

return NOERROR;

Error2:

if (pbstrDocStringA)

ConvertDispStringFreeA(*pbstrDocStringA);

Error1:

if (pbstrNameA)

ConvertDispStringFreeA(*pbstrNameA);

Error:

if (ppstrName)

SysFreeString(pstrName);

if (ppstrDocString)

SysFreeString(pstrDocString);

if (ppstrHelpFile)

SysFreeString(pstrHelpFile);

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CTypeInfoA::GetDllEntry, public

//

//  Synopsis:   Thunks GetDllEntry to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CTypeInfoA::GetDllEntry(MEMBERID memid, INVOKEKIND invkind,

BSTRA * pbstrDllNameA, BSTRA * pbstrNameA,

unsigned short * pwOrdinal)

{

TraceMethodEnter("CTypeInfoA::GetDllEntry", this);

BSTR pstrDllName, *ppstrDllName;

BSTR pstrName, *ppstrName;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(ITypeInfo, GetDllEntry));

if (pbstrDllNameA)

ppstrDllName = &pstrDllName;

else

ppstrDllName = NULL;

if (pbstrNameA)

ppstrName = &pstrName;

else

ppstrName = NULL;

hResult = GetWide()->GetDllEntry(memid, invkind, ppstrDllName, ppstrName,

pwOrdinal);

if (FAILED(hResult))

return (hResult);

if (pbstrDllNameA)

{

hResult = ConvertDispStringToA(pstrDllName, pbstrDllNameA);

if (FAILED(hResult))

goto Error;

SysFreeString(pstrDllName);

}

if (pbstrNameA)

{

hResult = ConvertDispStringToA(pstrName, pbstrNameA);

if (FAILED(hResult))

goto Error1;

SysFreeString(pstrName);

}

return NOERROR;

Error1:

if (pbstrNameA)

ConvertDispStringFreeA(*pbstrNameA);

Error:

SysFreeString(pstrDllName);

SysFreeString(pstrName);

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CTypeInfoA::GetRefTypeInfo, public

//

//  Synopsis:   Thunks GetRefTypeInfo to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CTypeInfoA::GetRefTypeInfo(HREFTYPE hreftype,

ITypeInfoA * * pptinfo)

{

TraceMethodEnter("CTypeInfoA::GetRefTypeInfo", this);

LPTYPEINFO pTypeInfo;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(ITypeInfo, GetRefTypeInfo));

hResult = GetWide()->GetRefTypeInfo(hreftype, &pTypeInfo);

if (FAILED(hResult))

return (hResult);

hResult = WrapITypeInfoAFromW(pTypeInfo, pptinfo);

pTypeInfo->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CTypeInfoA::AddressOfMember, public

//

//  Synopsis:   Thunks AddressOfMember to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CTypeInfoA::AddressOfMember(MEMBERID memid, INVOKEKIND invkind,

void * * ppv)

{

TraceMethodEnter("CTypeInfoA::AddressOfMember", this);

_DebugHook(GetWide(), MEMBER_PTR(ITypeInfo, AddressOfMember));

return GetWide()->AddressOfMember(memid, invkind, ppv);

}

//+--------------------------------------------------------------------------

//

//  Member:     CTypeInfoA::CreateInstance, public

//

//  Synopsis:   Thunks CreateInstance to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CTypeInfoA::CreateInstance(IUnknown * punkOuter, REFIID riid,

void * * ppvObj)

{

HRESULT hResult;

IUnknown * pvObjW;

TraceMethodEnter("CTypeInfoA::CreateInstance", this);

_DebugHook(GetWide(), MEMBER_PTR(ITypeInfo, CreateInstance));

hResult = GetWide()->CreateInstance(punkOuter, riid, (void **)&pvObjW);

if (SUCCEEDED(hResult))

{

hResult = WrapInterfaceAFromW(WrapTranslateIID(riid), pvObjW, (IUnknown**)ppvObj);

pvObjW->Release();

}

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CTypeInfoA::GetMops, public

//

//  Synopsis:   Thunks GetMops to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CTypeInfoA::GetMops(MEMBERID memid, BSTRA * pbstrMopsA)

{

TraceMethodEnter("CTypeInfoA::GetMops", this);

BSTR bstrMops;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(ITypeInfo, GetMops));

hResult = GetWide()->GetMops(memid, &bstrMops);

if (FAILED(hResult))

return hResult;

hResult = ConvertDispStringToA(bstrMops, pbstrMopsA);

ConvertDispStringFreeW(bstrMops);

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CTypeInfoA::GetContainingTypeLib, public

//

//  Synopsis:   Thunks GetContainingTypeLib to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CTypeInfoA::GetContainingTypeLib(ITypeLibA * * pptlib,

unsigned int * pindex)

{

TraceMethodEnter("CTypeInfoA::GetContainingTypeLib", this);

LPTYPELIB pTypeLib;

LPTYPELIB *ppTypeLib;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(ITypeInfo, GetContainingTypeLib));

if (pptlib)

ppTypeLib = &pTypeLib;

else

ppTypeLib = NULL;

hResult = GetWide()->GetContainingTypeLib(ppTypeLib, pindex);

if (FAILED(hResult))

return (hResult);

if (pptlib)

{

hResult = WrapITypeLibAFromW(pTypeLib, pptlib);

pTypeLib->Release();

}

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CTypeInfoA::ReleaseTypeAttr, public

//

//  Synopsis:   Thunks ReleaseTypeAttr to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP_(void) CTypeInfoA::ReleaseTypeAttr(TYPEATTR * ptypeattr)

{

TraceMethodEnter("CTypeInfoA::ReleaseTypeAttr", this);

_DebugHook(GetWide(), MEMBER_PTR(ITypeInfo, ReleaseTypeAttr));

GetWide()->ReleaseTypeAttr(ptypeattr);

}

//+--------------------------------------------------------------------------

//

//  Member:     CTypeInfoA::ReleaseFuncDesc, public

//

//  Synopsis:   Thunks ReleaseFuncDesc to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP_(void) CTypeInfoA::ReleaseFuncDesc(FUNCDESC * pfuncdesc)

{

TraceMethodEnter("CTypeInfoA::ReleaseFuncDesc", this);

_DebugHook(GetWide(), MEMBER_PTR(ITypeInfo, ReleaseFuncDesc));

GetWide()->ReleaseFuncDesc(pfuncdesc);

}

//+--------------------------------------------------------------------------

//

//  Member:     CTypeInfoA::ReleaseVarDesc, public

//

//  Synopsis:   Thunks ReleaseVarDesc to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP_(void) CTypeInfoA::ReleaseVarDesc(VARDESCA * pvardesc)

{

TraceMethodEnter("CTypeInfoA::ReleaseVarDesc", this);

_DebugHook(GetWide(), MEMBER_PTR(ITypeInfo, ReleaseVarDesc));

GetWide()->ReleaseVarDesc((VARDESC *)pvardesc);

}


 ITypeCompA Implementation  (OLEANSI Sample)

//***************************************************************************

//

//                   ITypeCompA Implementation

//

//***************************************************************************

//+--------------------------------------------------------------------------

//

//  Member:     CTypeCompA::Bind, public

//

//  Synopsis:   Thunks Bind to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CTypeCompA::Bind(CHAR * szNameA, unsigned long lHashVal,

unsigned short wflags, ITypeInfoA * * pptinfo, DESCKIND * pdesckind,

BINDPTRA * pbindptr)

{

TraceMethodEnter("CTypeCompA::Bind", this);

OLECHAR    szName[MAX_STRING];

LPTYPEINFO pTypeInfo;

HRESULT    hResult;

_DebugHook(GetWide(), MEMBER_PTR(ITypeComp, Bind));

ConvertStringToW(szNameA, szName);

hResult = GetWide()->Bind(szName, lHashVal, wflags, &pTypeInfo,

pdesckind, (BINDPTR *)pbindptr);

// NOTE: if *pdesckind == DESKIND_NONE, then *pTypeInfo and *pbindptr

// are indeterminate.

if (FAILED(hResult) || *pdesckind == DESCKIND_NONE)

return hResult;

if (pTypeInfo == NULL)

{

*pptinfo = NULL;

}

else

{

hResult = WrapITypeInfoAFromW(pTypeInfo, pptinfo);

if (FAILED(hResult))

goto Error;

}

// convert *pbindptr from BINDPTR to BINDPTRA

switch (*pdesckind)

{

case DESCKIND_VARDESC:

case DESCKIND_IMPLICITAPPOBJ:

hResult = ConvertVARDESCToA(pbindptr->lpvardesc);

break;

case DESCKIND_TYPECOMP:

{

LPTYPECOMP pTypeComp;

pTypeComp = (LPTYPECOMP)pbindptr->lptcomp;

hResult = WrapITypeCompAFromW(pTypeComp, &pbindptr->lptcomp);

pTypeComp->Release();

break;

}

//case DESCKIND_NONE:

//case DESCKIND_FUNCDESC:

// nothing to do

}

Error:

if (pTypeInfo)

pTypeInfo->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CTypeCompA::BindType, public

//

//  Synopsis:   Thunks BindType to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CTypeCompA::BindType(CHAR * szNameA, unsigned long lHashVal,

ITypeInfoA * * pptinfoA, ITypeCompA * * pptcompA)

{

TraceMethodEnter("CTypeCompA::BindType", this);

OLECHAR    szName[MAX_STRING];

LPTYPEINFO pTypeInfo;

LPTYPECOMP pTypeComp;

HRESULT    hResult;

_DebugHook(GetWide(), MEMBER_PTR(ITypeComp, BindType));

ConvertStringToW(szNameA, szName);

hResult = GetWide()->BindType(szName, lHashVal,  &pTypeInfo, &pTypeComp);

if (FAILED(hResult))

return hResult;

if (pTypeInfo == NULL)

{

*pptinfoA = NULL;

}

else

{

hResult = WrapITypeInfoAFromW(pTypeInfo, pptinfoA);

if (FAILED(hResult))

goto Error;

}

if (pTypeComp == NULL)

{

*pptcompA = NULL;

}

else

{

hResult = WrapITypeCompAFromW(pTypeComp, pptcompA);

pTypeComp->Release();

}

Error:

if (pTypeInfo)

pTypeInfo->Release();

return hResult;

}


 ICreateTypeLibA Implementation  (OLEANSI Sample)

//***************************************************************************

//

//                   ICreateTypeLibA Implementation

//

//***************************************************************************

//+--------------------------------------------------------------------------

//

//  Member:     CCreateTypeLibA::CreateTypeInfo, public

//

//  Synopsis:   Thunks CreateTypeInfo to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CCreateTypeLibA::CreateTypeInfo(CHAR * szNameA, TYPEKIND tkind,

ICreateTypeInfoA * * lplpictinfo)

{

TraceMethodEnter("CCreateTypeLibA::CreateTypeInfo", this);

OLECHAR    szName[MAX_STRING];

LPCREATETYPEINFO pTypeInfo;

HRESULT    hResult;

_DebugHook(GetWide(), MEMBER_PTR(ICreateTypeLib, CreateTypeInfo));

ConvertStringToW(szNameA, szName);

hResult = GetWide()->CreateTypeInfo(szName, tkind,  &pTypeInfo);

if (FAILED(hResult))

return hResult;

hResult = WrapICreateTypeInfoAFromW(pTypeInfo, lplpictinfo);

if (pTypeInfo)

pTypeInfo->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CCreateTypeLibA::SetName, public

//

//  Synopsis:   Thunks SetName to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CCreateTypeLibA::SetName(CHAR * szNameA)

{

TraceMethodEnter("CCreateTypeLibA::SetName", this);

OLECHAR szName[MAX_STRING];

_DebugHook(GetWide(), MEMBER_PTR(ICreateTypeLib, SetName));

ConvertStringToW(szNameA, szName);

return GetWide()->SetName(szName);

}

//+--------------------------------------------------------------------------

//

//  Member:     CCreateTypeLibA::SetVersion, public

//

//  Synopsis:   Thunks SetVersion to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CCreateTypeLibA::SetVersion(unsigned short wMajorVerNum,

unsigned short wMinorVerNum)

{

TraceMethodEnter("CCreateTypeLibA::SetVersion", this);

_DebugHook(GetWide(), MEMBER_PTR(ICreateTypeLib, SetVersion));

return GetWide()->SetVersion(wMajorVerNum, wMinorVerNum);

}

//+--------------------------------------------------------------------------

//

//  Member:     CCreateTypeLibA::SetGuid, public

//

//  Synopsis:   Thunks SetGuid to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CCreateTypeLibA::SetGuid(REFGUID guid)

{

TraceMethodEnter("CCreateTypeLibA::SetGuid", this);

_DebugHook(GetWide(), MEMBER_PTR(ICreateTypeLib, SetGuid));

return GetWide()->SetGuid(guid);

}

//+--------------------------------------------------------------------------

//

//  Member:     CCreateTypeLibA::SetDocString, public

//

//  Synopsis:   Thunks SetDocString to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CCreateTypeLibA::SetDocString(CHAR * szDocA)

{

TraceMethodEnter("CCreateTypeLibA::SetDocString", this);

LPWSTR     lpszDoc;

HRESULT    hResult;

_DebugHook(GetWide(), MEMBER_PTR(ICreateTypeLib, SetDocString));

hResult = ConvertStringToW(szDocA, &lpszDoc);

if (FAILED(hResult))

return (hResult);

hResult = GetWide()->SetDocString(lpszDoc);

ConvertStringFree(lpszDoc);

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CCreateTypeLibA::SetHelpFileName, public

//

//  Synopsis:   Thunks SetHelpFileName to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CCreateTypeLibA::SetHelpFileName(CHAR * szHelpFileNameA)

{

TraceMethodEnter("CCreateTypeLibA::SetHelpFileName", this);

OLECHAR szHelpFileName[MAX_STRING];

_DebugHook(GetWide(), MEMBER_PTR(ICreateTypeLib, SetHelpFileName));

ConvertStringToW(szHelpFileNameA, szHelpFileName);

return GetWide()->SetHelpFileName(szHelpFileName);

}

//+--------------------------------------------------------------------------

//

//  Member:     CCreateTypeLibA::SetHelpContext, public

//

//  Synopsis:   Thunks SetHelpContext to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CCreateTypeLibA::SetHelpContext(unsigned long dwHelpContext)

{

TraceMethodEnter("CCreateTypeLibA::SetHelpContext", this);

_DebugHook(GetWide(), MEMBER_PTR(ICreateTypeLib, SetHelpContext));

return GetWide()->SetHelpContext(dwHelpContext);

}

//+--------------------------------------------------------------------------

//

//  Member:     CCreateTypeLibA::SetLcid, public

//

//  Synopsis:   Thunks SetLcid to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CCreateTypeLibA::SetLcid(LCID lcid)

{

TraceMethodEnter("CCreateTypeLibA::SetLcid", this);

_DebugHook(GetWide(), MEMBER_PTR(ICreateTypeLib, SetLcid));

return GetWide()->SetLcid(lcid);

}

//+--------------------------------------------------------------------------

//

//  Member:     CCreateTypeLibA::SetLibFlags, public

//

//  Synopsis:   Thunks SetLibFlags to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CCreateTypeLibA::SetLibFlags(unsigned int uLibFlags)

{

TraceMethodEnter("CCreateTypeLibA::SetLibFlags", this);

_DebugHook(GetWide(), MEMBER_PTR(ICreateTypeLib, SetLibFlags));

return GetWide()->SetLibFlags(uLibFlags);

}

//+--------------------------------------------------------------------------

//

//  Member:     CCreateTypeLibA::SaveAllChanges, public

//

//  Synopsis:   Thunks SaveAllChanges to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CCreateTypeLibA::SaveAllChanges(VOID)

{

TraceMethodEnter("CCreateTypeLibA::SaveAllChanges", this);

_DebugHook(GetWide(), MEMBER_PTR(ICreateTypeLib, SaveAllChanges));

return GetWide()->SaveAllChanges();

}


 ICreateTypeInfoA Implementation  (OLEANSI Sample)

//***************************************************************************

//

//                   ICreateTypeInfoA Implementation

//

//***************************************************************************

//+--------------------------------------------------------------------------

//

//  Member:     CCreateTypeInfoA::SetGuid, public

//

//  Synopsis:   Thunks SetGuid to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CCreateTypeInfoA::SetGuid(REFGUID guid)

{

TraceMethodEnter("CCreateTypeInfoA::SetGuid", this);

_DebugHook(GetWide(), MEMBER_PTR(ICreateTypeInfo, SetGuid));

return GetWide()->SetGuid(guid);

}

//+--------------------------------------------------------------------------

//

//  Member:     CCreateTypeInfoA::SetTypeFlags, public

//

//  Synopsis:   Thunks SetTypeFlags to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CCreateTypeInfoA::SetTypeFlags(unsigned int uTypeFlags)

{

TraceMethodEnter("CCreateTypeInfoA::SetTypeFlags", this);

_DebugHook(GetWide(), MEMBER_PTR(ICreateTypeInfo, SetTypeFlags));

return GetWide()->SetTypeFlags(uTypeFlags);

}

//+--------------------------------------------------------------------------

//

//  Member:     CCreateTypeInfoA::SetDocString, public

//

//  Synopsis:   Thunks SetDocString to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CCreateTypeInfoA::SetDocString(CHAR * pstrDocA)

{

TraceMethodEnter("CCreateTypeInfoA::SetDocString", this);

LPWSTR   lpszDoc;

HRESULT    hResult;

_DebugHook(GetWide(), MEMBER_PTR(ICreateTypeInfo, SetDocString));

hResult = ConvertStringToW(pstrDocA, &lpszDoc);

if (FAILED(hResult))

return (hResult);

hResult = GetWide()->SetDocString(lpszDoc);

ConvertStringFree(lpszDoc);

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CCreateTypeInfoA::SetHelpContext, public

//

//  Synopsis:   Thunks SetHelpContext to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CCreateTypeInfoA::SetHelpContext(unsigned long dwHelpContext)

{

TraceMethodEnter("CCreateTypeInfoA::SetHelpContext", this);

_DebugHook(GetWide(), MEMBER_PTR(ICreateTypeInfo, SetHelpContext));

return GetWide()->SetHelpContext(dwHelpContext);

}

//+--------------------------------------------------------------------------

//

//  Member:     CCreateTypeInfoA::SetVersion, public

//

//  Synopsis:   Thunks SetVersion to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CCreateTypeInfoA::SetVersion(unsigned short wMajorVerNum,

unsigned short wMinorVerNum)

{

TraceMethodEnter("CCreateTypeInfoA::SetVersion", this);

_DebugHook(GetWide(), MEMBER_PTR(ICreateTypeInfo, SetVersion));

return GetWide()->SetVersion(wMajorVerNum, wMinorVerNum);

}

//+--------------------------------------------------------------------------

//

//  Member:     CCreateTypeInfoA::AddRefTypeInfo, public

//

//  Synopsis:   Thunks AddRefTypeInfo to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CCreateTypeInfoA::AddRefTypeInfo(ITypeInfoA * ptinfo,

HREFTYPE * phreftype)

{

TraceMethodEnter("CCreateTypeInfoA::AddRefTypeInfo", this);

ITypeInfo * pTypeInfo;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(ICreateTypeInfo, AddRefTypeInfo));

// ptinfo->QueryInterface(IID_ITypeInfo, (PVOID *)&pTypeInfo);

if( FAILED( hResult = WrapITypeInfoWFromA( ptinfo, &pTypeInfo )))

  return hResult;

hResult = GetWide()->AddRefTypeInfo(pTypeInfo, phreftype);

pTypeInfo->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CCreateTypeInfoA::AddFuncDesc, public

//

//  Synopsis:   Thunks AddFuncDesc to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CCreateTypeInfoA::AddFuncDesc(unsigned int index,

FUNCDESC * pfuncdesc)

{

TraceMethodEnter("CCreateTypeInfoA::AddFuncDesc", this);

_DebugHook(GetWide(), MEMBER_PTR(ICreateTypeInfo, AddFuncDesc));

return GetWide()->AddFuncDesc(index, pfuncdesc);

}

//+--------------------------------------------------------------------------

//

//  Member:     CCreateTypeInfoA::AddImplType, public

//

//  Synopsis:   Thunks AddImplType to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CCreateTypeInfoA::AddImplType(unsigned int index,

HREFTYPE hreftype)

{

TraceMethodEnter("CCreateTypeInfoA::AddImplType", this);

_DebugHook(GetWide(), MEMBER_PTR(ICreateTypeInfo, AddImplType));

return GetWide()->AddImplType(index, hreftype);

}

//+--------------------------------------------------------------------------

//

//  Member:     CCreateTypeInfoA::SetImplTypeFlags, public

//

//  Synopsis:   Thunks SetImplTypeFlags to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CCreateTypeInfoA::SetImplTypeFlags(unsigned int index,

int impltypeflags)

{

TraceMethodEnter("CCreateTypeInfoA::SetImplTypeFlags", this);

_DebugHook(GetWide(), MEMBER_PTR(ICreateTypeInfo, SetImplTypeFlags));

return GetWide()->SetImplTypeFlags(index, impltypeflags);

}

//+--------------------------------------------------------------------------

//

//  Member:     CCreateTypeInfoA::SetAlignment, public

//

//  Synopsis:   Thunks SetAlignment to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CCreateTypeInfoA::SetAlignment(unsigned short cbAlignment)

{

TraceMethodEnter("CCreateTypeInfoA::SetAlignment", this);

_DebugHook(GetWide(), MEMBER_PTR(ICreateTypeInfo, SetAlignment));

return GetWide()->SetAlignment(cbAlignment);

}

//+--------------------------------------------------------------------------

//

//  Member:     CCreateTypeInfoA::SetSchema, public

//

//  Synopsis:   Thunks SetSchema to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CCreateTypeInfoA::SetSchema(CHAR * lpstrSchemaA)

{

TraceMethodEnter("CCreateTypeInfoA::SetSchema", this);

LPWSTR   lpszSchema;

HRESULT    hResult;

_DebugHook(GetWide(), MEMBER_PTR(ICreateTypeInfo, SetSchema));

hResult = ConvertStringToW(lpstrSchemaA, &lpszSchema);

if (FAILED(hResult))

return (hResult);

hResult = GetWide()->SetSchema(lpszSchema);

ConvertStringFree(lpszSchema);

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CCreateTypeInfoA::AddVarDesc, public

//

//  Synopsis:   Thunks AddVarDesc to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CCreateTypeInfoA::AddVarDesc(unsigned int index,

VARDESCA * pvardescA)

{

TraceMethodEnter("CCreateTypeInfoA::AddVarDesc", this);

LPVARDESC pVarDesc;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(ICreateTypeInfo, AddVarDesc));

hResult = ConvertVARDESCToW(pvardescA, &pVarDesc);

if (FAILED(hResult))

return (hResult);

hResult = GetWide()->AddVarDesc(index, pVarDesc);

ConvertVARDESCFree(pVarDesc);

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CCreateTypeInfoA::SetFuncAndParamNames, public

//

//  Synopsis:   Thunks SetFuncAndParamNames to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CCreateTypeInfoA::SetFuncAndParamNames(unsigned int index,

CHAR * * rgszNamesA, unsigned int cNames)

{

TraceMethodEnter("CCreateTypeInfoA::SetFuncAndParamNames", this);

LPWSTR * rgszNames;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(ICreateTypeInfo, SetFuncAndParamNames));

hResult = ConvertStringArrayToW(rgszNamesA, &rgszNames, cNames);

if (FAILED(hResult))

return (hResult);

hResult = GetWide()->SetFuncAndParamNames(index, rgszNames, cNames);

ConvertStringArrayFree(rgszNames, cNames);

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CCreateTypeInfoA::SetVarName, public

//

//  Synopsis:   Thunks SetVarName to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CCreateTypeInfoA::SetVarName(unsigned int index, CHAR * szNameA)

{

TraceMethodEnter("CCreateTypeInfoA::SetVarName", this);

OLECHAR szName[MAX_STRING];

_DebugHook(GetWide(), MEMBER_PTR(ICreateTypeInfo, SetVarName));

ConvertStringToW(szNameA, szName);

return GetWide()->SetVarName(index, szName);

}

//+--------------------------------------------------------------------------

//

//  Member:     CCreateTypeInfoA::SetTypeDescAlias, public

//

//  Synopsis:   Thunks SetTypeDescAlias to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CCreateTypeInfoA::SetTypeDescAlias(TYPEDESC * ptdescAlias)

{

TraceMethodEnter("CCreateTypeInfoA::SetTypeDescAlias", this);

_DebugHook(GetWide(), MEMBER_PTR(ICreateTypeInfo, SetTypeDescAlias));

return GetWide()->SetTypeDescAlias(ptdescAlias);

}

//+--------------------------------------------------------------------------

//

//  Member:     CCreateTypeInfoA::DefineFuncAsDllEntry, public

//

//  Synopsis:   Thunks DefineFuncAsDllEntry to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CCreateTypeInfoA::DefineFuncAsDllEntry(unsigned int index,

CHAR * szDllNameA, CHAR * szProcNameA)

{

TraceMethodEnter("CCreateTypeInfoA::DefineFuncAsDllEntry", this);

OLECHAR szDllName[MAX_STRING];

LPWSTR  lpszProcName;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(ICreateTypeInfo, DefineFuncAsDllEntry));

ConvertStringToW(szDllNameA, szDllName);

if (HIWORD(szProcNameA))

{

// not an ordinal

hResult = ConvertStringToW(szProcNameA, &lpszProcName);

if (FAILED(hResult))

goto Error;

}

else

{

// really an ordinal

lpszProcName = (LPWSTR)szProcNameA;

}

hResult = GetWide()->DefineFuncAsDllEntry(index, szDllName, lpszProcName);

if (HIWORD(szProcNameA))

{

// not an ordinal

ConvertStringFree(lpszProcName);

}

Error:

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CCreateTypeInfoA::SetFuncDocString, public

//

//  Synopsis:   Thunks SetFuncDocString to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CCreateTypeInfoA::SetFuncDocString(unsigned int index,

CHAR * szDocStringA)

{

TraceMethodEnter("CCreateTypeInfoA::SetFuncDocString", this);

LPWSTR   lpszDocString;

HRESULT    hResult;

_DebugHook(GetWide(), MEMBER_PTR(ICreateTypeInfo, SetFuncDocString));

hResult = ConvertStringToW(szDocStringA, &lpszDocString);

if (FAILED(hResult))

return (hResult);

hResult = GetWide()->SetFuncDocString(index, lpszDocString);

ConvertStringFree(lpszDocString);

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CCreateTypeInfoA::SetVarDocString, public

//

//  Synopsis:   Thunks SetVarDocString to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CCreateTypeInfoA::SetVarDocString(unsigned int index,

CHAR * szDocStringA)

{

TraceMethodEnter("CCreateTypeInfoA::SetVarDocString", this);

LPWSTR   lpszDocString;

HRESULT    hResult;

_DebugHook(GetWide(), MEMBER_PTR(ICreateTypeInfo, SetVarDocString));

hResult = ConvertStringToW(szDocStringA, &lpszDocString);

if (FAILED(hResult))

return (hResult);

hResult = GetWide()->SetVarDocString(index, lpszDocString);

ConvertStringFree(lpszDocString);

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CCreateTypeInfoA::SetFuncHelpContext, public

//

//  Synopsis:   Thunks SetFuncHelpContext to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CCreateTypeInfoA::SetFuncHelpContext(unsigned int index,

unsigned long dwHelpContext)

{

TraceMethodEnter("CCreateTypeInfoA::SetFuncHelpContext", this);

_DebugHook(GetWide(), MEMBER_PTR(ICreateTypeInfo, SetFuncHelpContext));

return GetWide()->SetFuncHelpContext(index, dwHelpContext);

}

//+--------------------------------------------------------------------------

//

//  Member:     CCreateTypeInfoA::SetVarHelpContext, public

//

//  Synopsis:   Thunks SetVarHelpContext to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CCreateTypeInfoA::SetVarHelpContext(unsigned int index,

unsigned long dwHelpContext)

{

TraceMethodEnter("CCreateTypeInfoA::SetVarHelpContext", this);

_DebugHook(GetWide(), MEMBER_PTR(ICreateTypeInfo, SetVarHelpContext));

return GetWide()->SetVarHelpContext(index, dwHelpContext);

}

//+--------------------------------------------------------------------------

//

//  Member:     CCreateTypeInfoA::SetMops, public

//

//  Synopsis:   Thunks SetMops to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CCreateTypeInfoA::SetMops(unsigned int index, BSTRA bstrMopsA)

{

TraceMethodEnter("CCreateTypeInfoA::SetMops", this);

BSTR bstrMops;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(ICreateTypeInfo, SetMops));

hResult = ConvertStringToW(bstrMopsA, &bstrMops);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->SetMops(index, bstrMops);

ConvertStringFree(bstrMops);

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CCreateTypeInfoA::SetTypeIdldesc, public

//

//  Synopsis:   Thunks SetTypeIdldesc to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CCreateTypeInfoA::SetTypeIdldesc(IDLDESC * pidldesc)

{

TraceMethodEnter("CCreateTypeInfoA::SetTypeIdldesc", this);

_DebugHook(GetWide(), MEMBER_PTR(ICreateTypeInfo, SetTypeIdldesc));

return GetWide()->SetTypeIdldesc(pidldesc);

}

//+--------------------------------------------------------------------------

//

//  Member:     CCreateTypeInfoA::LayOut, public

//

//  Synopsis:   Thunks LayOut to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CCreateTypeInfoA::LayOut(VOID)

{

TraceMethodEnter("CCreateTypeInfoA::LayOut", this);

_DebugHook(GetWide(), MEMBER_PTR(ICreateTypeInfo, LayOut));

return GetWide()->LayOut();

}


 IEnumVARIANTA Implementation  (OLEANSI Sample)

//***************************************************************************

//

//                   IEnumVARIANTA Implementation

//

//***************************************************************************

//+--------------------------------------------------------------------------

//

//  Member:     CEnumVARIANTA::Next, public

//

//  Synopsis:   Thunks Next to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CEnumVARIANTA::Next(unsigned long celt, VARIANTA * rgvar,

unsigned long * pceltFetched)

{

TraceMethodEnter("CEnumVARIANTA::Next", this);

ULONG   celtFetched;

HRESULT hReturn;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IEnumVARIANT, Next));

if (pceltFetched == NULL)

pceltFetched = &celtFetched;

hReturn = GetWide()->Next(celt, (VARIANT *)rgvar, pceltFetched);

if (FAILED(hReturn))

return (hReturn);

hResult = ConvertVariantArrayToA(rgvar, *pceltFetched);

if (FAILED(hResult))

return (hResult);

return hReturn;

}

//+--------------------------------------------------------------------------

//

//  Member:     CEnumVARIANTA::Skip, public

//

//  Synopsis:   Thunks Skip to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CEnumVARIANTA::Skip(unsigned long celt)

{

TraceMethodEnter("CEnumVARIANTA::Skip", this);

_DebugHook(GetWide(), MEMBER_PTR(IEnumVARIANT, Skip));

return GetWide()->Skip(celt);

}

//+--------------------------------------------------------------------------

//

//  Member:     CEnumVARIANTA::Reset, public

//

//  Synopsis:   Thunks Reset to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CEnumVARIANTA::Reset(VOID)

{

TraceMethodEnter("CEnumVARIANTA::Reset", this);

_DebugHook(GetWide(), MEMBER_PTR(IEnumVARIANT, Reset));

return GetWide()->Reset();

}

//+--------------------------------------------------------------------------

//

//  Member:     CEnumVARIANTA::Clone, public

//

//  Synopsis:   Thunks Clone to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CEnumVARIANTA::Clone(IEnumVARIANTA * * ppenmA)

{

TraceMethodEnter("CEnumVARIANTA::Clone", this);

IEnumVARIANT * penm;

_DebugHook(GetWide(), MEMBER_PTR(IEnumVARIANT, Clone));

HRESULT hResult = GetWide()->Clone(&penm);

if (FAILED(hResult))

return (hResult);

hResult = WrapIEnumVARIANTAFromW(penm, ppenmA);

penm->Release();

return hResult;

}


 IDispatchA Implementation  (OLEANSI Sample)

//***************************************************************************

//

//                   IDispatchA Implementation

//

//***************************************************************************

//+--------------------------------------------------------------------------

//

//  Member:     CDispatchA::GetTypeInfoCount, public

//

//  Synopsis:   Thunks GetTypeInfoCount to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CDispatchA::GetTypeInfoCount(unsigned int * pctinfo)

{

TraceMethodEnter("CDispatchA::GetTypeInfoCount", this);

_DebugHook(GetWide(), MEMBER_PTR(IDispatch, GetTypeInfoCount));

return GetWide()->GetTypeInfoCount(pctinfo);

}

//+--------------------------------------------------------------------------

//

//  Member:     CDispatchA::GetTypeInfo, public

//

//  Synopsis:   Thunks GetTypeInfo to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CDispatchA::GetTypeInfo(unsigned int itinfo, LCID lcid,

ITypeInfoA * * pptinfo)

{

TraceMethodEnter("CDispatchA::GetTypeInfo", this);

LPTYPEINFO pTypeInfo;

HRESULT    hResult;

_DebugHook(GetWide(), MEMBER_PTR(IDispatch, GetTypeInfo));

hResult = GetWide()->GetTypeInfo(itinfo, lcid, &pTypeInfo);

if (FAILED(hResult))

return hResult;

hResult = WrapITypeInfoAFromW(pTypeInfo, pptinfo);

pTypeInfo->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CDispatchA::GetIDsOfNames, public

//

//  Synopsis:   Thunks GetIDsOfNames to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CDispatchA::GetIDsOfNames(REFIID riid, char * * rgszNamesA,

unsigned int cNames, LCID lcid, DISPID * rgdispid)

{

TraceMethodEnter("CDispatchA::GetIDsOfNames", this);

LPWSTR * rgszNames;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IDispatch, GetIDsOfNames));

hResult = ConvertStringArrayToW(rgszNamesA, lcid, &rgszNames, cNames);

if (FAILED(hResult))

return (hResult);

hResult = GetWide()->GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);

ConvertStringArrayFree(rgszNames, cNames);

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CDispatchA::Invoke, public

//

//  Synopsis:   Thunks Invoke to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//  History:    24-Jun-94   patl    Fixed case where GetWide->Invoke

//                  returns an error, and an exception.

//                  Previously, the exception would be

//                  left wide, not converted to ANSI.

//

//---------------------------------------------------------------------------

STDMETHODIMP CDispatchA::Invoke(DISPID dispidMember, REFIID riid, LCID lcid,

unsigned short wFlags, DISPPARAMSA * pdispparamsA,

VARIANTA * pvarResultA, EXCEPINFOA * pexcepinfoA,

unsigned int * puArgErr)

{

TraceMethodEnter("CDispatchA::Invoke", this);

LPDISPPARAMS pDispParams;

LPVARIANT    pByrefTemp;

HRESULT      hResult;

_DebugHook(GetWide(), MEMBER_PTR(IDispatch, Invoke));

hResult = ConvertDispParamsToW(pdispparamsA, &pDispParams, &pByrefTemp);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->Invoke(dispidMember, riid, lcid, wFlags, pDispParams,

(LPVARIANT)pvarResultA, (EXCEPINFO *)pexcepinfoA, puArgErr);

if (hResult == DISP_E_EXCEPTION)

ConvertExcepInfoToA(pexcepinfoA);

if (FAILED(hResult))

goto Error;

if (pByrefTemp)

{

hResult = ConvertDispParamsCopyBack(pdispparamsA, pByrefTemp);

if (FAILED(hResult))

goto Error;

}

hResult = ConvertVariantToA(pvarResultA);

if (FAILED(hResult))

goto Error;

Error:

ConvertDispParamsFree(pDispParams, pByrefTemp);

return hResult;

}


 IErrorInfoA Implementation  (OLEANSI Sample)#ifndef NOERRORINFO

//***************************************************************************

//

//                       IErrorInfoA Implementation

//

//***************************************************************************

STDMETHODIMP

CErrorInfoA::GetGUID(GUID *pguid)

{

TraceMethodEnter("CErrorInfoA::GetGUID", this);

_DebugHook(GetWide(), MEMBER_PTR(IErrorInfo, GetGUID));

return GetWide()->GetGUID(pguid);

}

STDMETHODIMP

CErrorInfoA::GetSource(BSTRA *pbstraSource)

{

TraceMethodEnter("CErrorInfoA::GetSource", this);

HRESULT hresult;

BSTR bstrSource;

bstrSource = NULL;

_DebugHook(GetWide(), MEMBER_PTR(IErrorInfo, GetSource));

hresult = GetWide()->GetSource(&bstrSource);

if(FAILED(hresult))

return hresult;

hresult = ConvertDispStringToA(bstrSource, pbstraSource);

SysFreeString(bstrSource);

return hresult;

}

STDMETHODIMP

CErrorInfoA::GetDescription(BSTRA *pbstraDescription)

{

TraceMethodEnter("CErrorInfoA::GetDescription", this);

HRESULT hresult;

BSTR bstrDescription;

bstrDescription = NULL;

_DebugHook(GetWide(), MEMBER_PTR(IErrorInfo, GetDescription));

hresult = GetWide()->GetDescription(&bstrDescription);

if(FAILED(hresult))

return hresult;

hresult = ConvertDispStringToA(bstrDescription, pbstraDescription);

SysFreeString(bstrDescription);

return hresult;

}

STDMETHODIMP

CErrorInfoA::GetHelpFile(BSTRA *pbstraHelpFile)

{

TraceMethodEnter("CErrorInfoA::GetHelpFile", this);

HRESULT hresult;

BSTR bstrHelpFile;

bstrHelpFile = NULL;

_DebugHook(GetWide(), MEMBER_PTR(IErrorInfo, GetHelpFile));

hresult = GetWide()->GetHelpFile(&bstrHelpFile);

if(FAILED(hresult))

return hresult;

hresult = ConvertDispStringToA(bstrHelpFile, pbstraHelpFile);

SysFreeString(bstrHelpFile);

return hresult;

}

STDMETHODIMP

CErrorInfoA::GetHelpContext(DWORD *pdwHelpContext)

{

TraceMethodEnter("CErrorInfoA::GetHelpContext", this);

_DebugHook(GetWide(), MEMBER_PTR(IErrorInfo, GetHelpContext));

return GetWide()->GetHelpContext(pdwHelpContext);

}


 ICreateErrorInfo Implementation  (OLEANSI Sample)

//***************************************************************************

//

//                      ICreateErrorInfo Implementation

//

//***************************************************************************

STDMETHODIMP

CCreateErrorInfoA::SetGUID(REFGUID rguid)

{

TraceMethodEnter("CCreateErrorInfoA::SetGUID", this);

_DebugHook(GetWide(), MEMBER_PTR(ICreateErrorInfo, SetGUID));

return GetWide()->SetGUID(rguid);

}

STDMETHODIMP

CCreateErrorInfoA::SetSource(LPSTR szSource)

{

TraceMethodEnter("CCreateErrorInfoA::SetSource", this);

HRESULT hresult;

LPWSTR szwSource;

szwSource = NULL;

_DebugHook(GetWide(), MEMBER_PTR(ICreateErrorInfo, SetSource));

if(szSource != NULL){

hresult = ConvertStringToW(szSource, &szwSource);

if(FAILED(hresult))

return hresult;

}

hresult = GetWide()->SetSource(szwSource);

if(szwSource != NULL)

  ConvertStringFree(szwSource);

return hresult;

}

STDMETHODIMP

CCreateErrorInfoA::SetDescription(LPSTR szDescription)

{

TraceMethodEnter("CCreateErrorInfoA::SetDescription", this);

HRESULT hresult;

LPWSTR szwDescription;

szwDescription = NULL;

_DebugHook(GetWide(), MEMBER_PTR(ICreateErrorInfo, SetDescription));

if(szDescription != NULL){

hresult = ConvertStringToW(szDescription, &szwDescription);

if(FAILED(hresult))

return hresult;

}

hresult = GetWide()->SetDescription(szwDescription);

if(szwDescription != NULL)

ConvertStringFree(szwDescription);

return hresult;

}

STDMETHODIMP

CCreateErrorInfoA::SetHelpFile(LPSTR szHelpFile)

{

TraceMethodEnter("CCreateErrorInfoA::SetHelpFile", this);

HRESULT hresult;

LPWSTR szwHelpFile;

szwHelpFile = NULL;

_DebugHook(GetWide(), MEMBER_PTR(ICreateErrorInfo, SetHelpFile));

if(szHelpFile != NULL){

hresult = ConvertStringToW(szHelpFile, &szwHelpFile);

if(FAILED(hresult))

return hresult;

}

hresult = GetWide()->SetHelpFile(szwHelpFile);

if(szwHelpFile != NULL)

ConvertStringFree(szwHelpFile);

return hresult;

}

STDMETHODIMP

CCreateErrorInfoA::SetHelpContext(DWORD dwHelpContext)

{

TraceMethodEnter("CCreateErrorInfoA::SetHelpContext", this);

_DebugHook(GetWide(), MEMBER_PTR(ICreateErrorInfo, SetHelpContext));

return GetWide()->SetHelpContext(dwHelpContext);

}

STDAPI

SetErrorInfoA(DWORD dwReserved, IErrorInfoA *perrinfoA)

{

TraceSTDAPIEnter("SetErrorInfo");

HRESULT hresult;

IErrorInfo *perrinfoW;

hresult = WrapIErrorInfoWFromA(perrinfoA, &perrinfoW);

if(FAILED(hresult))

return hresult;

hresult = SetErrorInfo(dwReserved, perrinfoW);

perrinfoW->Release(); // ownership has transferred to the system.

return hresult;

}

STDAPI

GetErrorInfoA(DWORD dwReserved, IErrorInfoA **pperrinfoA)

{

TraceSTDAPIEnter("GetErrorInfo");

HRESULT hresult;

IErrorInfo *perrinfoW;

hresult = GetErrorInfo(dwReserved, &perrinfoW);

if(hresult != NOERROR) // S_FALSE means no Error Info obj available

return hresult;

hresult = WrapIErrorInfoAFromW(perrinfoW, pperrinfoA);

if(FAILED(hresult))

return hresult;

perrinfoW->Release(); // now held by perrinfoA

return NOERROR;

}

STDAPI

CreateErrorInfoA(ICreateErrorInfoA **pperrinfoA)

{

TraceSTDAPIEnter("CreateErrorInfo");

HRESULT hresult;

ICreateErrorInfo *perrinfoW;

hresult = CreateErrorInfo(&perrinfoW);

if(FAILED(hresult))

return hresult;

hresult = WrapICreateErrorInfoAFromW(perrinfoW, pperrinfoA);

if(FAILED(hresult))

return hresult;

perrinfoW->Release(); // now held by pperrinfoA

return NOERROR;

}

#endif  //!NOERRORINFO


 ANSIDVOB.H  (OLEANSI Sample)

//+--------------------------------------------------------------------------

//

//  Copyright (C) 1994, Microsoft Corporation.  All Rights Reserved.

//

//  File:       ansidvob.h

//

//  Contents:   ANSI Wrappers for Unicode DvObj Interfaces and APIs.

//

//  Classes:    CEnumSTATDATAA

//              CDataObjectA

//              CViewObject2A

//              CAdviseSink2A

//              CDataAdviseHolder

//              COleCache2

//              COleCacheControl

//

//  Functions:  None.

//

//  History:    01-Nov-93   v-kentc     Created.

//

//---------------------------------------------------------------------------

#if defined(__cplusplus)

interface IAdviseSink2A;

#else

typedef interface IAdviseSink2A IAdviseSink2A;

#endif

typedef IAdviseSink2A * LPADVISESINKA;

// Data/View target device; determines the device for drawing or gettting data

typedef struct FARSTRUCT tagDVTARGETDEVICEA

{

DWORD tdSize;

WORD tdDeviceNameOffset;

WORD tdDriverNameOffset;

WORD tdPortNameOffset;

WORD tdExtDevmodeOffset;

BYTE tdData[1];

} DVTARGETDEVICEA, * LPDVTARGETDEVICEA;

typedef DVTARGETDEVICE * LPDVTARGETDEVICE;

// Format, etc.; completely specifices the kind of data desired, including tymed

typedef struct FARSTRUCT tagFORMATETCA

{

CLIPFORMAT          cfFormat;

DVTARGETDEVICEA FAR* ptd;

DWORD               dwAspect;

LONG                lindex;

DWORD               tymed;

} FORMATETCA, FAR* LPFORMATETCA;

typedef struct tagSTGMEDIUMA

{

DWORD   tymed;

union

{

HANDLE  hGlobal;

LPSTR   lpszFileName;

IStreamA * pstm;

IStorageA * pstg;

}

#ifndef __cplusplus

#ifdef NONAMELESSUNION

u       // add a tag when name less unions not supported

#endif

#endif

;

IUnknown * pUnkForRelease;

} STGMEDIUMA, * LPSTGMEDIUMA;

typedef struct tagSTATDATAA

{                                   // field used by:

FORMATETCA formatetc;           // EnumAdvise, EnumData (cache), EnumFormats

DWORD advf;                     // EnumAdvise, EnumData (cache)

LPADVISESINKA pAdvSink;         // EnumAdvise

DWORD dwConnection;             // EnumAdvise

} STATDATAA;

typedef  STATDATAA * LPSTATDATAA;

/*---------------------------------------------------------------------*/

/*                IEnumSTATDATAA                                       */

/*---------------------------------------------------------------------*/

#undef  INTERFACE

#define INTERFACE   IEnumSTATDATAA

DECLARE_INTERFACE_(IEnumSTATDATAA, IUnknown)

{

// *** IUnknown methods ***

STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppv) PURE;

STDMETHOD_(ULONG, AddRef) (THIS)  PURE;

STDMETHOD_(ULONG, Release) (THIS) PURE;

// *** IEnumSTATDATA methods ***

STDMETHOD(Next) (THIS_ ULONG celt, STATDATAA  * rgelt, ULONG * pceltFetched) PURE;

STDMETHOD(Skip) (THIS_ ULONG celt) PURE;

STDMETHOD(Reset) (THIS) PURE;

STDMETHOD(Clone) (THIS_ IEnumSTATDATAA * * ppenum) PURE;

};

typedef        IEnumSTATDATAA * LPENUMSTATDATAA;

/*---------------------------------------------------------------------*/

/*                            IEnumFORMATETCA                          */

/*---------------------------------------------------------------------*/

#undef  INTERFACE

#define INTERFACE   IEnumFORMATETCA

DECLARE_INTERFACE_(IEnumFORMATETCA, IUnknown)

{

// *** IUnknown methods ***

STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppvObj) PURE;

STDMETHOD_(ULONG,AddRef) (THIS)  PURE;

STDMETHOD_(ULONG,Release) (THIS) PURE;

// *** IEnumFORMATETC methods ***

STDMETHOD(Next) (THIS_ ULONG celt,

   FORMATETCA * rgelt,

   ULONG * pceltFetched) PURE;

STDMETHOD(Skip) (THIS_ ULONG celt) PURE;

STDMETHOD(Reset) (THIS) PURE;

STDMETHOD(Clone) (THIS_ IEnumFORMATETCA * * ppenm) PURE;

};

typedef IEnumFORMATETCA * LPENUMFORMATETCA;

/*---------------------------------------------------------------------*/

/*                IDataObjectA                                         */

/*---------------------------------------------------------------------*/

#undef  INTERFACE

#define INTERFACE   IDataObjectA

DECLARE_INTERFACE_(IDataObjectA, IUnknown)

{

// *** IUnknown methods ***

STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppvObj) PURE;

STDMETHOD_(ULONG,AddRef) (THIS)  PURE;

STDMETHOD_(ULONG, Release) (THIS) PURE;

// *** IDataObject methods ***

STDMETHOD(GetData) (THIS_ LPFORMATETCA pformatetcIn,

LPSTGMEDIUMA pmediumA ) PURE;

STDMETHOD(GetDataHere) (THIS_ LPFORMATETCA pformatetc,

LPSTGMEDIUMA pmediumA ) PURE;

STDMETHOD(QueryGetData) (THIS_ LPFORMATETCA pformatetc ) PURE;

STDMETHOD(GetCanonicalFormatEtc) (THIS_ LPFORMATETCA pformatetc,

LPFORMATETCA pformatetcOut) PURE;

STDMETHOD(SetData) (THIS_ LPFORMATETCA pformatetc, STGMEDIUMA  * pmediumA,

BOOL fRelease) PURE;

STDMETHOD(EnumFormatEtc) (THIS_ DWORD dwDirection,

LPENUMFORMATETCA * ppenumFormatEtc) PURE;

STDMETHOD(DAdvise) (THIS_ FORMATETCA * pFormatetc, DWORD advf,

LPADVISESINKA pAdvSinkA, DWORD * pdwConnection) PURE;

STDMETHOD(DUnadvise) (THIS_ DWORD dwConnection) PURE;

STDMETHOD(EnumDAdvise) (THIS_ LPENUMSTATDATAA * ppenumAdviseA) PURE;

};

typedef      IDataObjectA * LPDATAOBJECTA;

/*---------------------------------------------------------------------*/

/*                             IViewObject2A                           */

/*---------------------------------------------------------------------*/

#undef  INTERFACE

#define INTERFACE   IViewObject2A

DECLARE_INTERFACE_(IViewObject2A, IUnknown)

{

// *** IUnknown methods ***

STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppvObj) PURE;

STDMETHOD_(ULONG,AddRef) (THIS)  PURE;

STDMETHOD_(ULONG,Release) (THIS) PURE;

// *** IViewObject methods ***

STDMETHOD(Draw) (THIS_ DWORD dwDrawAspect, LONG lindex,

void * pvAspect, DVTARGETDEVICEA  * ptd,

HDC hicTargetDev,

HDC hdcDraw,

LPCRECTL lprcBounds,

LPCRECTL lprcWBounds,

BOOL (CALLBACK * pfnContinue) (DWORD),

DWORD dwContinue) PURE;

STDMETHOD(GetColorSet) (THIS_ DWORD dwDrawAspect, LONG lindex,

void * pvAspect, DVTARGETDEVICEA  * ptd,

HDC hicTargetDev,

LPLOGPALETTE * ppColorSet) PURE;

STDMETHOD(Freeze)(THIS_ DWORD dwDrawAspect, LONG lindex,

void * pvAspect,

DWORD * pdwFreeze) PURE;

STDMETHOD(Unfreeze) (THIS_ DWORD dwFreeze) PURE;

STDMETHOD(SetAdvise) (THIS_ DWORD aspects, DWORD advf,

LPADVISESINKA pAdvSinkA) PURE;

STDMETHOD(GetAdvise) (THIS_ DWORD * pAspects, DWORD * pAdvf,

LPADVISESINKA * ppAdvSinkA) PURE;

// *** IViewObject2 methods ***

STDMETHOD(GetExtent) (THIS_ DWORD dwDrawAspect, LONG lindex,

DVTARGETDEVICEA  * ptd, LPSIZEL lpsizel) PURE;

};

typedef      IViewObject2A * LPVIEWOBJECTA;

typedef      IViewObject2A * LPVIEWOBJECT2A;

/*---------------------------------------------------------------------*/

/*                           IAdviseSink2A                             */

/*---------------------------------------------------------------------*/

#undef  INTERFACE

#define INTERFACE   IAdviseSink2A

DECLARE_INTERFACE_(IAdviseSink2A, IUnknown)

{

// *** IUnknown methods ***

STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppv) PURE;

STDMETHOD_(ULONG,AddRef) (THIS)  PURE;

STDMETHOD_(ULONG,Release) (THIS) PURE;

// *** IAdviseSink methods ***

STDMETHOD_(void,OnDataChange)(THIS_ FORMATETCA * pFormatetc,

STGMEDIUMA * pStgmedA) PURE;

STDMETHOD_(void,OnViewChange)(THIS_ DWORD dwAspect, LONG lindex) PURE;

STDMETHOD_(void,OnRename)(THIS_ LPMONIKERA pmkA) PURE;

STDMETHOD_(void,OnSave)(THIS) PURE;

STDMETHOD_(void,OnClose)(THIS) PURE;

// *** IAdviseSink2 methods ***

STDMETHOD_(void,OnLinkSrcChange)(THIS_ LPMONIKERA pmkA) PURE;

};

typedef      IAdviseSink2A * LPADVISESINK2A;

/*---------------------------------------------------------------------*/

/*                IDataAdviseHolderA               */

/*---------------------------------------------------------------------*/

#undef  INTERFACE

#define INTERFACE   IDataAdviseHolderA

DECLARE_INTERFACE_(IDataAdviseHolderA, IUnknown)

{

// *** IUnknown methods ***

STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppv) PURE;

STDMETHOD_(ULONG,AddRef) (THIS)  PURE;

STDMETHOD_(ULONG,Release) (THIS) PURE;

// *** IDataAdviseHolder methods ***

STDMETHOD(Advise)(THIS_ LPDATAOBJECTA pDataObjectA, FORMATETCA * pFetc,

DWORD advf, LPADVISESINKA pAdviseA, DWORD * pdwConnection) PURE;

STDMETHOD(Unadvise)(THIS_ DWORD dwConnection) PURE;

STDMETHOD(EnumAdvise)(THIS_ LPENUMSTATDATAA * ppenumAdviseA) PURE;

STDMETHOD(SendOnDataChange)(THIS_ LPDATAOBJECTA pDataObjectA, DWORD dwReserved, DWORD advf) PURE;

};

typedef      IDataAdviseHolderA * LPDATAADVISEHOLDERA;

/*---------------------------------------------------------------------*/

/*                IOleCache2A                  */

/*---------------------------------------------------------------------*/

#undef  INTERFACE

#define INTERFACE   IOleCache2A

DECLARE_INTERFACE_(IOleCache2A, IUnknown)

{

// *** IUnknown methods ***

STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppvObj) PURE;

STDMETHOD_(ULONG,AddRef) (THIS)  PURE;

STDMETHOD_(ULONG, Release) (THIS) PURE;

// *** IOleCache methods ***

STDMETHOD(Cache) (THIS_ LPFORMATETCA lpFormatetc, DWORD advf, LPDWORD lpdwConnection) PURE;

STDMETHOD(Uncache) (THIS_ DWORD dwConnection) PURE;

STDMETHOD(EnumCache) (THIS_ LPENUMSTATDATAA * ppenumStatDataA) PURE;

STDMETHOD(InitCache) (THIS_ LPDATAOBJECTA pDataObjectA) PURE;

STDMETHOD(SetData) (THIS_ LPFORMATETCA pformatetc, STGMEDIUMA  * pmediumA,

BOOL fRelease) PURE;

// *** IOleCache2 methods ***

STDMETHOD(UpdateCache) (THIS_ LPDATAOBJECTA pDataObjectA, DWORD grfUpdf,

LPVOID pReserved) PURE;

STDMETHOD(DiscardCache) (THIS_ DWORD dwDiscardOptions) PURE;

};

typedef      IOleCache2A * LPOLECACHEA;

typedef      IOleCache2A * LPOLECACHE2A;

/*---------------------------------------------------------------------*/

/*                IOleCacheControlA                */

/*---------------------------------------------------------------------*/

#undef  INTERFACE

#define INTERFACE   IOleCacheControlA

DECLARE_INTERFACE_(IOleCacheControlA, IUnknown)

{

// *** IUnknown methods ***

STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppvObj) PURE;

STDMETHOD_(ULONG,AddRef) (THIS)  PURE;

STDMETHOD_(ULONG, Release) (THIS) PURE;

// *** IDataObject methods ***

STDMETHOD(OnRun) (THIS_ LPDATAOBJECTA pDataObjectA) PURE;

STDMETHOD(OnStop) (THIS) PURE;

};

typedef      IOleCacheControlA * LPOLECACHECONTROLA;

//

//  Forward declarations

//

class CEnumSTATDATAA;

class CDataObjectA;

class CViewObject2A;

class CAdviseSink2A;

class COleCache2A;

class COleCacheControlA;

class CDataAdviseHolderA;

//+--------------------------------------------------------------------------

//

//  Class:      CEnumSTATDATAA

//

//  Synopsis:   Class definition of IEnumSTATDATAA

//

//---------------------------------------------------------------------------

class CEnumSTATDATAA : CAnsiInterface

{

public:

// *** IEnumSTATDATAA methods ***

STDMETHOD(Next) (ULONG celt,

   STATDATAA * rgelt,

   ULONG * pceltFetched);

STDMETHOD(Skip) (ULONG celt);

STDMETHOD(Reset) (VOID);

STDMETHOD(Clone) (IEnumSTATDATAA * * ppenm);

inline CEnumSTATDATAA(LPUNKNOWN pUnk, IEnumSTATDATA * pWide) :

CAnsiInterface(ID_IEnumSTATDATA, pUnk, (LPUNKNOWN)pWide) {};

inline IEnumSTATDATA * GetWide() const

{ return (IEnumSTATDATA *)m_pObj; };

};

//+--------------------------------------------------------------------------

//

//  Class:      CEnumFORMATETCA

//

//  Synopsis:   Class definition of IEnumFORMATETCA

//

//---------------------------------------------------------------------------

class CEnumFORMATETCA : CAnsiInterface

{

public:

// *** IEnumFORMATETCA methods ***

STDMETHOD(Next) (ULONG celt,

   FORMATETCA* rgelt,

   ULONG FAR* pceltFetched);

STDMETHOD(Skip) (ULONG celt);

STDMETHOD(Reset) (VOID);

STDMETHOD(Clone) (IEnumFORMATETCA * * ppenm);

inline CEnumFORMATETCA(LPUNKNOWN pUnk, IEnumFORMATETC * pObj) :

CAnsiInterface(ID_IEnumFORMATETC, pUnk, (LPUNKNOWN)pObj) {};

inline IEnumFORMATETC * GetWide() const

{ return (IEnumFORMATETC *)m_pObj; };

};

//+--------------------------------------------------------------------------

//

//  Class:      CDataObjectA

//

//  Synopsis:   Class definition of IDataObjectA

//

//---------------------------------------------------------------------------

class CDataObjectA : CAnsiInterface

{

public:

// *** IDataObject methods ***

STDMETHOD(GetData) (LPFORMATETCA pformatetcIn,

LPSTGMEDIUMA pmediumA );

STDMETHOD(GetDataHere) (LPFORMATETCA pformatetc,

LPSTGMEDIUMA pmediumA );

STDMETHOD(QueryGetData) (LPFORMATETCA pformatetc );

STDMETHOD(GetCanonicalFormatEtc) (LPFORMATETCA pformatetc,

LPFORMATETCA pformatetcOut);

STDMETHOD(SetData) (LPFORMATETCA pformatetc, STGMEDIUMA * pmediumA,

BOOL fRelease);

STDMETHOD(EnumFormatEtc) (DWORD dwDirection,

LPENUMFORMATETCA * ppenumFormatEtc);

STDMETHOD(DAdvise) (FORMATETCA * pFormatetc, DWORD advf,

LPADVISESINKA pAdvSinkA, DWORD * pdwConnection);

STDMETHOD(DUnadvise) (DWORD dwConnection);

STDMETHOD(EnumDAdvise) (LPENUMSTATDATAA * ppenumAdviseA);

inline CDataObjectA(LPUNKNOWN pUnk, IDataObject * pWide) :

CAnsiInterface(ID_IDataObject, pUnk, (LPUNKNOWN)pWide) {};

inline IDataObject * GetWide() const

{ return (IDataObject *)m_pObj; };

};

//+--------------------------------------------------------------------------

//

//  Class:      CViewObject2A

//

//  Synopsis:   Class definition of IViewObject2A

//

//---------------------------------------------------------------------------

class CViewObject2A : CAnsiInterface

{

public:

// *** IViewObject methods ***

STDMETHOD(Draw) (DWORD dwDrawAspect, LONG lindex,

void * pvAspect, DVTARGETDEVICEA * ptd,

HDC hicTargetDev,

HDC hdcDraw,

LPCRECTL lprcBounds,

LPCRECTL lprcWBounds,

BOOL (CALLBACK * pfnContinue) (DWORD),

DWORD dwContinue);

STDMETHOD(GetColorSet) (DWORD dwDrawAspect, LONG lindex,

void * pvAspect, DVTARGETDEVICEA * ptd,

HDC hicTargetDev,

LPLOGPALETTE * ppColorSet);

STDMETHOD(Freeze)(DWORD dwDrawAspect, LONG lindex,

void * pvAspect,

DWORD * pdwFreeze);

STDMETHOD(Unfreeze) (DWORD dwFreeze);

STDMETHOD(SetAdvise) (DWORD aspects, DWORD advf,

LPADVISESINKA pAdvSinkA);

STDMETHOD(GetAdvise) (DWORD * pAspects, DWORD * pAdvf,

LPADVISESINKA * ppAdvSinkA);

// *** IViewObject2 methods ***

STDMETHOD(GetExtent) (DWORD dwDrawAspect, LONG lindex,

DVTARGETDEVICEA * ptd, LPSIZEL lpsizel);

inline CViewObject2A(LPUNKNOWN pUnk, IViewObject2 * pWide) :

CAnsiInterface(ID_IViewObject2, pUnk, (LPUNKNOWN)pWide) {};

inline IViewObject2 * GetWide() const

{ return (IViewObject2 *)m_pObj; };

};

//+--------------------------------------------------------------------------

//

//  Class:      CAdviseSink2A

//

//  Synopsis:   Class definition of IAdviseSink2A

//

//---------------------------------------------------------------------------

class CAdviseSink2A : CAnsiInterface

{

public:

// *** IAdviseSink methods ***

STDMETHOD_(void,OnDataChange)(FORMATETCA * pFormatetc,

STGMEDIUMA * pStgmedA);

STDMETHOD_(void,OnViewChange)(DWORD dwAspect, LONG lindex);

STDMETHOD_(void,OnRename)(LPMONIKERA pmkA);

STDMETHOD_(void,OnSave)(VOID);

STDMETHOD_(void,OnClose)(VOID);

// *** IAdviseSink2 methods ***

STDMETHOD_(void,OnLinkSrcChange)(LPMONIKERA pmkA);

inline CAdviseSink2A(LPUNKNOWN pUnk, IAdviseSink2 * pWide) :

CAnsiInterface(ID_IAdviseSink2, pUnk, (LPUNKNOWN)pWide) {};

inline IAdviseSink2 * GetWide() const

{ return (IAdviseSink2 *)m_pObj; };

};

//+--------------------------------------------------------------------------

//

//  Class:      CDataAdviseHolderA

//

//  Synopsis:   Class definition of IDataAdviseHolderA

//

//---------------------------------------------------------------------------

class CDataAdviseHolderA : CAnsiInterface

{

public:

// *** IDataAdviseHolder methods ***

STDMETHOD(Advise)(LPDATAOBJECTA pDataObjectA, FORMATETCA * pFetc,

DWORD advf, LPADVISESINKA pAdviseA, DWORD * pdwConnection);

STDMETHOD(Unadvise)(DWORD dwConnection);

STDMETHOD(EnumAdvise)(LPENUMSTATDATAA * ppenumAdviseA);

STDMETHOD(SendOnDataChange)(LPDATAOBJECTA pDataObjectA, DWORD dwReserved, DWORD advf);

inline CDataAdviseHolderA(LPUNKNOWN pUnk, IDataAdviseHolder * pWide) :

CAnsiInterface(ID_IDataAdviseHolder, pUnk, (LPUNKNOWN)pWide) {};

inline IDataAdviseHolder * GetWide() const

{ return (IDataAdviseHolder *)m_pObj; };

};

//+--------------------------------------------------------------------------

//

//  Class:      COleCache2A

//

//  Synopsis:   Class definition of IOleCache2A

//

//---------------------------------------------------------------------------

class COleCache2A : CAnsiInterface

{

public:

// *** IOleCache methods ***

STDMETHOD(Cache) (LPFORMATETCA lpFormatetc, DWORD advf, LPDWORD lpdwConnection);

STDMETHOD(Uncache) (DWORD dwConnection);

STDMETHOD(EnumCache) (LPENUMSTATDATAA * ppenumStatDataA);

STDMETHOD(InitCache) (LPDATAOBJECTA pDataObjectA);

STDMETHOD(SetData) (LPFORMATETCA pformatetc, STGMEDIUMA * pmediumA,

BOOL fRelease);

// *** IOleCache2 methods ***

STDMETHOD(UpdateCache) (LPDATAOBJECTA pDataObjectA, DWORD grfUpdf,

LPVOID pReserved);

STDMETHOD(DiscardCache) (DWORD dwDiscardOptions);

inline COleCache2A(LPUNKNOWN pUnk, IOleCache2 * pWide) :

CAnsiInterface(ID_IOleCache2, pUnk, (LPUNKNOWN)pWide) {};

inline IOleCache2 * GetWide() const

{ return (IOleCache2 *)m_pObj; };

};

//+--------------------------------------------------------------------------

//

//  Class:      COleCacheControlA

//

//  Synopsis:   Class definition of IOleCacheControlA

//

//---------------------------------------------------------------------------

class COleCacheControlA : CAnsiInterface

{

public:

// *** IDataObject methods ***

STDMETHOD(OnRun) (LPDATAOBJECTA pDataObjectA);

STDMETHOD(OnStop) (VOID);

inline COleCacheControlA(LPUNKNOWN pUnk, IOleCacheControl * pWide) :

CAnsiInterface(ID_IOleCacheControl, pUnk, (LPUNKNOWN)pWide) {};

inline IOleCacheControl * GetWide() const

{ return (IOleCacheControl *)m_pObj; };

};


 ANSIDVOB.CPP  (OLEANSI Sample)

//+--------------------------------------------------------------------------

//

//  Copyright (C) 1994, Microsoft Corporation.  All Rights Reserved.

//

//  File:       ansidvob.h

//

//  Contents:   ANSI Wrappers for Unicode DvObj Interfaces and APIs.

//

//  Classes:    CEnumSTATDATAA

//              CDataObjectA

//              CViewObject2A

//              CAdviseSink2A

//              CDataAdviseHolder

//              COleCache2

//              COleCacheControl

//

//  Functions:  CreateDataAdviseHolderA

//              CreateDataCacheA

//              IEnumSTATDATAAFromW

//              IDataObjectAFromW

//              IViewObjectAFromW

//              IViewObject2AFromW

//              IAdviseSinkAFromW

//              IAdviseSink2AFromW

//              IDataAdviseHolderAFromW

//              IOleCacheAFromW

//              IOleCache2AFromW

//              IOleCacheControlAFromW

//

//  History:    01-Nov-93   v-kentc     Created.

//

//---------------------------------------------------------------------------

#include "Ole2Ansi.h"


 IEnumSTATDATAA Implementation  (OLEANSI Sample)

//***************************************************************************

//

//                   IEnumSTATDATAA Implementation

//

//***************************************************************************

//+--------------------------------------------------------------------------

//

//  Member:     CEnumSTATDATAA::Next, public

//

//  Synopsis:   Thunks Next to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CEnumSTATDATAA::Next(

ULONG celt,

STATDATAA * rgelt,

ULONG * pceltFetched)

{

TraceMethodEnter("CEnumSTATDATAA::Next", this);

ULONG   celtFetched;

HRESULT hReturn;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IEnumSTATDATA, Next));

if (pceltFetched == NULL)

pceltFetched = &celtFetched;

hReturn = GetWide()->Next(celt, (STATDATA *)rgelt, pceltFetched);

if (FAILED(hReturn))

return (hReturn);

hResult = ConvertSTATDATAArrayToA(rgelt, *pceltFetched);

if (FAILED(hResult))

return (hResult);

return hReturn;

}

//+--------------------------------------------------------------------------

//

//  Member:     CEnumSTATDATAA::Skip, public

//

//  Synopsis:   Thunks Skip to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CEnumSTATDATAA::Skip(ULONG celt)

{

_DebugHook(GetWide(), MEMBER_PTR(IEnumSTATDATA, Skip));

return (GetWide()->Skip(celt));

}

//+--------------------------------------------------------------------------

//

//  Member:     CEnumSTATDATAA::Reset, public

//

//  Synopsis:   Thunks Reset to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CEnumSTATDATAA::Reset(VOID)

{

_DebugHook(GetWide(), MEMBER_PTR(IEnumSTATDATA, Reset));

return (GetWide()->Reset());

}

//+--------------------------------------------------------------------------

//

//  Member:     CEnumSTATDATAA::Clone, public

//

//  Synopsis:   Thunks Clone to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CEnumSTATDATAA::Clone(IEnumSTATDATAA * * ppstatA)

{

TraceMethodEnter("CEnumSTATDATAA::Clone", this);

IEnumSTATDATA * pwide;

_DebugHook(GetWide(), MEMBER_PTR(IEnumSTATDATA, Clone));

*ppstatA = NULL;

HRESULT hResult = GetWide()->Clone(&pwide);

if (FAILED(hResult))

return (hResult);

hResult = WrapIEnumSTATDATAAFromW(pwide, ppstatA);

if (pwide)

pwide->Release();

return hResult;

}


 IEnumFORMATETCA Implementation  (OLEANSI Sample)

//***************************************************************************

//

//                   IEnumFORMATETCA Implementation

//

//***************************************************************************

//+--------------------------------------------------------------------------

//

//  Member:     CEnumFORMATETCA::Next, public

//

//  Synopsis:   Thunks Next to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CEnumFORMATETCA::Next(

ULONG celt,

FORMATETCA * rgelt,

ULONG * pceltFetched)

{

TraceNotify("CEnumFORMATETCA::Next");

ULONG   celtFetched;

HRESULT hReturn;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IEnumFORMATETC, Next));

if (pceltFetched == NULL)

pceltFetched = &celtFetched;

hReturn = GetWide()->Next(celt, (FORMATETC *)rgelt, pceltFetched);

if (FAILED(hReturn))

return (hReturn);

hResult = ConvertFORMATETCArrayToA(rgelt, *pceltFetched);

if (FAILED(hResult))

return (hResult);

return hReturn;

}

//+--------------------------------------------------------------------------

//

//  Member:     CEnumFORMATETCA::Skip, public

//

//  Synopsis:   Thunks Skip to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CEnumFORMATETCA::Skip(ULONG celt)

{

TraceNotify("CEnumFORMATETCA::Skip");

_DebugHook(GetWide(), MEMBER_PTR(IEnumFORMATETC, Skip));

return GetWide()->Skip(celt);

}

//+--------------------------------------------------------------------------

//

//  Member:     CEnumFORMATETCA::Reset, public

//

//  Synopsis:   Thunks Reset to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CEnumFORMATETCA::Reset(VOID)

{

TraceNotify("CEnumFORMATETCA::Reset");

_DebugHook(GetWide(), MEMBER_PTR(IEnumFORMATETC, Reset));

return GetWide()->Reset();

}

//+--------------------------------------------------------------------------

//

//  Member:     CEnumFORMATETCA::Clone, public

//

//  Synopsis:   Thunks Clone to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CEnumFORMATETCA::Clone(IEnumFORMATETCA * * ppenmA)

{

TraceNotify("CEnumFORMATETCA::Clone");

IEnumFORMATETC * penm;

_DebugHook(GetWide(), MEMBER_PTR(IEnumFORMATETC, Clone));

*ppenmA = NULL;

HRESULT hResult = GetWide()->Clone(&penm);

if (FAILED(hResult))

return (hResult);

hResult = WrapIEnumFORMATETCAFromW(penm, ppenmA);

if (penm)

penm->Release();

return hResult;

}


 IDataObjectA Implementation  (OLEANSI Sample)

//***************************************************************************

//

//                   IDataObjectA Implementation

//

//***************************************************************************

//+--------------------------------------------------------------------------

//

//  Member:     CDataObjectA::GetData, public

//

//  Synopsis:   Thunks GetData to Unicode method.

//

//  Returns:    OLE result code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CDataObjectA::GetData(LPFORMATETCA pformatetcIn,

LPSTGMEDIUMA pmediumA)

{

TraceMethodEnter("CDataObjectA::GetData", this);

FORMATETC FormatEtc;

HRESULT   hResult;

_DebugHook(GetWide(), MEMBER_PTR(IDataObject, GetData));

hResult = ConvertFORMATETCToW(pformatetcIn, &FormatEtc);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->GetData(&FormatEtc, (LPSTGMEDIUM)pmediumA);

ConvertFORMATETCFree(&FormatEtc);

if (FAILED(hResult))

return hResult;

return ConvertSTGMEDIUMToA(pformatetcIn->cfFormat, pmediumA);

}

//+--------------------------------------------------------------------------

//

//  Member:     CDataObjectA::GetDataHere, public

//

//  Synopsis:   Thunks GetDataHere to Unicode method.

//

//  Returns:    OLE result code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CDataObjectA::GetDataHere(LPFORMATETCA pformatetc,

LPSTGMEDIUMA pmediumA)

{

TraceMethodEnter("CDataObjectA::GetDataHere", this);

FORMATETC FormatEtc;

STGMEDIUM Medium;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IDataObject, GetDataHere));

hResult = ConvertFORMATETCToW(pformatetc, &FormatEtc);

if (FAILED(hResult))

return hResult;

hResult = ConvertSTGMEDIUMToW(pformatetc->cfFormat, pmediumA, &Medium);

if (FAILED(hResult))

goto Error;

hResult = GetWide()->GetDataHere(&FormatEtc, &Medium);

ConvertSTGMEDIUMFree(pformatetc->cfFormat, &Medium);

Error:

ConvertFORMATETCFree(&FormatEtc);

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CDataObjectA::QueryGetData, public

//

//  Synopsis:   Thunks QueryGetData to Unicode method.

//

//  Returns:    OLE result code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CDataObjectA::QueryGetData(LPFORMATETCA pformatetc)

{

TraceMethodEnter("CDataObjectA::QueryGetData", this);

FORMATETC FormatEtc;

HRESULT   hResult;

_DebugHook(GetWide(), MEMBER_PTR(IDataObject, QueryGetData));

hResult = ConvertFORMATETCToW(pformatetc, &FormatEtc);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->QueryGetData(&FormatEtc);

ConvertFORMATETCFree(&FormatEtc);

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CDataObjectA::GetCanonicalFormatEtc, public

//

//  Synopsis:   Thunks GetCanonicalFormatEtc to Unicode method.

//

//  Returns:    OLE result code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CDataObjectA::GetCanonicalFormatEtc(LPFORMATETCA pformatetc,

LPFORMATETCA pformatetcOut)

{

TraceMethodEnter("CDataObjectA::GetCanonicalFormatEtc", this);

FORMATETC FormatEtc;

FORMATETC FormatEtcOut;

HRESULT   hResult;

_DebugHook(GetWide(), MEMBER_PTR(IDataObject, GetCanonicalFormatEtc));

hResult = ConvertFORMATETCToW(pformatetc, &FormatEtc);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->GetCanonicalFormatEtc(&FormatEtc, &FormatEtcOut);

ConvertFORMATETCFree(&FormatEtc);

        if (hResult != S_OK)

return hResult;

hResult = ConvertFORMATETCToA(&FormatEtcOut, pformatetcOut);

ConvertFORMATETCFree(&FormatEtcOut);

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CDataObjectA::SetData, public

//

//  Synopsis:   Thunks SetData to Unicode method.

//

//  Returns:    OLE result code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CDataObjectA::SetData(LPFORMATETCA pformatetc,

STGMEDIUMA * pmediumA, BOOL fRelease)

{

TraceMethodEnter("CDataObjectA::SetData", this);

FORMATETC FormatEtc;

STGMEDIUM Medium;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IDataObject, SetData));

hResult = ConvertFORMATETCToW(pformatetc, &FormatEtc);

if (FAILED(hResult))

return hResult;

hResult = ConvertSTGMEDIUMToW(pformatetc->cfFormat, pmediumA, &Medium);

if (FAILED(hResult))

goto Error;

hResult = GetWide()->SetData(&FormatEtc, &Medium, fRelease);

ConvertSTGMEDIUMFree(pformatetc->cfFormat, &Medium);

Error:

ConvertFORMATETCFree(&FormatEtc);

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CDataObjectA::EnumFormatEtc, public

//

//  Synopsis:   Thunks EnumFormatEtc to Unicode method.

//

//  Returns:    OLE result code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CDataObjectA::EnumFormatEtc(DWORD dwDirection,

LPENUMFORMATETCA * ppenumFormatEtcA)

{

TraceMethodEnter("CDataObjectA::EnumFormatEtc", this);

LPENUMFORMATETC pEnumFormatEtc;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IDataObject, EnumFormatEtc));

hResult = GetWide()->EnumFormatEtc(dwDirection, &pEnumFormatEtc);

if (FAILED(hResult))

return hResult;

hResult = WrapIEnumFORMATETCAFromW(pEnumFormatEtc, ppenumFormatEtcA);

if (pEnumFormatEtc)

pEnumFormatEtc->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CDataObjectA::DAdvise, public

//

//  Synopsis:   Thunks DAdvise to Unicode method.

//

//  Returns:    OLE result code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CDataObjectA::DAdvise(FORMATETCA * pFormatetc, DWORD advf,

LPADVISESINKA pAdvSinkA, DWORD * pdwConnection)

{

TraceMethodEnter("CDataObjectA::DAdvise", this);

FORMATETC FormatEtc;

LPADVISESINK pAdvSink;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IDataObject, DAdvise));

hResult = ConvertFORMATETCToW(pFormatetc, &FormatEtc);

if (FAILED(hResult))

return hResult;

hResult = WrapIAdviseSinkWFromA(pAdvSinkA, &pAdvSink);

if (FAILED(hResult))

goto Error;

hResult = GetWide()->DAdvise(&FormatEtc, advf, pAdvSink, pdwConnection);

if (pAdvSink)

pAdvSink->Release();

Error:

ConvertFORMATETCFree(&FormatEtc);

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CDataObjectA::DUnadvise, public

//

//  Synopsis:   Thunks DUnadvise to Unicode method.

//

//  Returns:    OLE result code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CDataObjectA::DUnadvise(DWORD dwConnection)

{

_DebugHook(GetWide(), MEMBER_PTR(IDataObject, DUnadvise));

return GetWide()->DUnadvise(dwConnection);

}

//+--------------------------------------------------------------------------

//

//  Member:     CDataObjectA::EnumDAdvise, public

//

//  Synopsis:   Thunks EnumDAdvise to Unicode method.

//

//  Returns:    OLE result code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CDataObjectA::EnumDAdvise(LPENUMSTATDATAA * ppenumAdviseA)

{

TraceMethodEnter("CDataObjectA::EnumDAdvise", this);

LPENUMSTATDATA penumAdvise = NULL;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IDataObject, EnumDAdvise));

hResult = GetWide()->EnumDAdvise(&penumAdvise);

if (FAILED(hResult))

return hResult;

if (penumAdvise)

{

hResult = WrapIEnumSTATDATAAFromW(penumAdvise, ppenumAdviseA);

penumAdvise->Release();

}

else

*ppenumAdviseA = NULL;

return hResult;

}


 IViewObject2A Implementation  (OLEANSI Sample)

//***************************************************************************

//

//                   IViewObject2A Implementation

//

//***************************************************************************

//+--------------------------------------------------------------------------

//

//  Member:     CViewObject2A::Draw, public

//

//  Synopsis:   Thunks Draw to Unicode method.

//

//  Returns:    OLE result code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CViewObject2A::Draw(DWORD dwDrawAspect, LONG lindex,

void * pvAspect, DVTARGETDEVICEA * ptd, HDC hicTargetDev, HDC hdcDraw,

LPCRECTL lprcBounds, LPCRECTL lprcWBounds,

BOOL (CALLBACK * pfnContinue)(DWORD), DWORD dwContinue)

{

TraceMethodEnter("CViewObject2A::Draw", this);

LPDVTARGETDEVICE pDevice;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IViewObject, Draw));

if (ptd)

{

hResult = ConvertDVTARGETDEVICEToW(ptd, &pDevice);

if (FAILED(hResult))

return hResult;

}

else

pDevice = NULL;

hResult = GetWide()->Draw(dwDrawAspect, lindex, pvAspect, pDevice,

hicTargetDev, hdcDraw, lprcBounds, lprcWBounds, pfnContinue,

dwContinue);

ConvertDVTARGETDEVICEFree(pDevice);

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CViewObject2A::GetColorSet, public

//

//  Synopsis:   Thunks GetColorSet to Unicode method.

//

//  Returns:    OLE result code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CViewObject2A::GetColorSet(DWORD dwDrawAspect, LONG lindex,

void * pvAspect, DVTARGETDEVICEA * ptd, HDC hicTargetDev,

LPLOGPALETTE * ppColorSet)

{

TraceMethodEnter("CViewObject2A::GetColorSet", this);

LPDVTARGETDEVICE pDevice;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IViewObject, GetColorSet));

if (ptd)

{

hResult = ConvertDVTARGETDEVICEToW(ptd, &pDevice);

if (FAILED(hResult))

return hResult;

}

else

pDevice = NULL;

hResult = GetWide()->GetColorSet(dwDrawAspect, lindex, pvAspect, pDevice,

hicTargetDev, ppColorSet);

ConvertDVTARGETDEVICEFree(pDevice);

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CViewObject2A::Freeze, public

//

//  Synopsis:   Thunks Freeze to Unicode method.

//

//  Returns:    OLE result code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CViewObject2A::Freeze(DWORD dwDrawAspect, LONG lindex,

void * pvAspect, DWORD * pdwFreeze)

{

_DebugHook(GetWide(), MEMBER_PTR(IViewObject, Freeze));

return GetWide()->Freeze(dwDrawAspect, lindex, pvAspect, pdwFreeze);

}

//+--------------------------------------------------------------------------

//

//  Member:     CViewObject2A::Unfreeze, public

//

//  Synopsis:   Thunks Unfreeze to Unicode method.

//

//  Returns:    OLE result code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CViewObject2A::Unfreeze(DWORD dwFreeze)

{

_DebugHook(GetWide(), MEMBER_PTR(IViewObject, Unfreeze));

return GetWide()->Unfreeze(dwFreeze);

}

//+--------------------------------------------------------------------------

//

//  Member:     CViewObject2A::SetAdvise, public

//

//  Synopsis:   Thunks SetAdvise to Unicode method.

//

//  Returns:    OLE result code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CViewObject2A::SetAdvise(DWORD aspects, DWORD advf,

LPADVISESINKA pAdvSinkA)

{

TraceMethodEnter("CViewObject2A::SetAdvise", this);

LPADVISESINK pAdvSink;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IViewObject, SetAdvise));

hResult = WrapIAdviseSinkWFromA(pAdvSinkA, &pAdvSink);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->SetAdvise(aspects, advf, pAdvSink);

if (pAdvSink)

pAdvSink->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CViewObject2A::GetAdvise, public

//

//  Synopsis:   Thunks GetAdvise to Unicode method.

//

//  Returns:    OLE result code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CViewObject2A::GetAdvise(DWORD * pAspects, DWORD * pAdvf,

LPADVISESINKA * ppAdvSinkA)

{

TraceMethodEnter("CViewObject2A::GetAdvise", this);

LPADVISESINK pAdvSink, * ppAdvSink;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IViewObject, GetAdvise));

if (ppAdvSinkA)

{

ppAdvSink = &pAdvSink;

pAdvSink = NULL;

}

else

ppAdvSink = NULL;

hResult = GetWide()->GetAdvise(pAspects, pAdvf, ppAdvSink);

if (FAILED(hResult))

return hResult;

if (ppAdvSinkA)

{

hResult = WrapIAdviseSinkAFromW(pAdvSink, ppAdvSinkA);

if (pAdvSink)

pAdvSink->Release();

}

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CViewObject2A::GetExtent, public

//

//  Synopsis:   Thunks GetExtent to Unicode method.

//

//  Returns:    OLE result code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CViewObject2A::GetExtent(DWORD dwDrawAspect, LONG lindex,

DVTARGETDEVICEA * ptd, LPSIZEL lpsizel)

{

TraceMethodEnter("CViewObject2A::GetExtent", this);

LPDVTARGETDEVICE pDevice;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IViewObject2, GetExtent));

if (ptd)

{

hResult = ConvertDVTARGETDEVICEToW(ptd, &pDevice);

if (FAILED(hResult))

return hResult;

}

else

pDevice = NULL;

hResult = GetWide()->GetExtent(dwDrawAspect, lindex, pDevice, lpsizel);

ConvertDVTARGETDEVICEFree(pDevice);

return hResult;

}


 IAdviseSink2A Implementation  (OLEANSI Sample)

//***************************************************************************

//

//                   IAdviseSink2A Implementation

//

//***************************************************************************

//+--------------------------------------------------------------------------

//

//  Member:     CAdviseSink2A::OnDataChange, public

//

//  Synopsis:   Thunks OnDataChange to Unicode method.

//

//  Returns:    None.

//

//---------------------------------------------------------------------------

STDMETHODIMP_(void) CAdviseSink2A::OnDataChange(FORMATETCA * pFormatetc,

STGMEDIUMA * pStgmedA)

{

TraceMethodEnter("CAdviseSink2A::OnDataChange", this);

FORMATETC FormatEtc;

STGMEDIUM Medium;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IAdviseSink, OnDataChange));

hResult = ConvertFORMATETCToW(pFormatetc, &FormatEtc);

if (FAILED(hResult))

return;

hResult = ConvertSTGMEDIUMToW(pFormatetc->cfFormat, pStgmedA, &Medium);

if (FAILED(hResult))

goto Error;

GetWide()->OnDataChange(&FormatEtc, &Medium);

ConvertSTGMEDIUMFree(pFormatetc->cfFormat, &Medium);

Error:

ConvertFORMATETCFree(&FormatEtc);

}

//+--------------------------------------------------------------------------

//

//  Member:     CAdviseSink2A::OnViewChange, public

//

//  Synopsis:   Thunks OnViewChange to Unicode method.

//

//  Returns:    None.

//

//---------------------------------------------------------------------------

STDMETHODIMP_(void) CAdviseSink2A::OnViewChange(DWORD dwAspect, LONG lindex)

{

_DebugHook(GetWide(), MEMBER_PTR(IAdviseSink, OnViewChange));

GetWide()->OnViewChange(dwAspect, lindex);

}

//+--------------------------------------------------------------------------

//

//  Member:     CAdviseSink2A::OnRename, public

//

//  Synopsis:   Thunks OnRename to Unicode method.

//

//  Returns:    None.

//

//---------------------------------------------------------------------------

STDMETHODIMP_(void) CAdviseSink2A::OnRename(LPMONIKERA pmkA)

{

TraceMethodEnter("CAdviseSink2A::OnRename", this);

LPMONIKER pmk;

_DebugHook(GetWide(), MEMBER_PTR(IAdviseSink, OnRename));

WrapIMonikerWFromA(pmkA, &pmk);

GetWide()->OnRename(pmk);

if (pmk)

pmk->Release();

}

//+--------------------------------------------------------------------------

//

//  Member:     CAdviseSink2A::OnSave, public

//

//  Synopsis:   Thunks OnSave to Unicode method.

//

//  Returns:    None.

//

//---------------------------------------------------------------------------

STDMETHODIMP_(void) CAdviseSink2A::OnSave(VOID)

{

_DebugHook(GetWide(), MEMBER_PTR(IAdviseSink2, OnSave));

GetWide()->OnSave();

}

//+--------------------------------------------------------------------------

//

//  Member:     CAdviseSink2A::OnClose, public

//

//  Synopsis:   Thunks OnClose to Unicode method.

//

//  Returns:    None.

//

//---------------------------------------------------------------------------

STDMETHODIMP_(void) CAdviseSink2A::OnClose(VOID)

{

_DebugHook(GetWide(), MEMBER_PTR(IAdviseSink2, OnClose));

GetWide()->OnClose();

}

//+--------------------------------------------------------------------------

//

//  Member:     CAdviseSink2A::OnLinkSrcChange, public

//

//  Synopsis:   Thunks OnLinkSrcChange to Unicode method.

//

//  Returns:    None.

//

//---------------------------------------------------------------------------

STDMETHODIMP_(void) CAdviseSink2A::OnLinkSrcChange(LPMONIKERA pmkA)

{

TraceMethodEnter("CAdviseSink2A::OnLinkSrcChange", this);

LPMONIKER pmk;

_DebugHook(GetWide(), MEMBER_PTR(IAdviseSink2, OnLinkSrcChange));

WrapIMonikerWFromA(pmkA, &pmk);

GetWide()->OnLinkSrcChange(pmk);

if (pmk)

pmk->Release();

}


 IDataAdviseHolderA Implementation  (OLEANSI Sample)

//***************************************************************************

//

//                   IDataAdviseHolderA Implementation

//

//***************************************************************************

//+--------------------------------------------------------------------------

//

//  Member:     CDataAdviseHolderA::Advise, public

//

//  Synopsis:   Thunks Advise to Unicode method.

//

//  Returns:    OLE result code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CDataAdviseHolderA::Advise(LPDATAOBJECTA pDataObjectA,

FORMATETCA * pFetc, DWORD advf, LPADVISESINKA pAdviseA,

DWORD * pdwConnection)

{

TraceMethodEnter("CDataAdviseHolderA::Advise", this);

LPDATAOBJECT pDataObject;

FORMATETC    FormatEtc;

LPADVISESINK pAdvise;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IDataAdviseHolder, Advise));

hResult = WrapIDataObjectWFromA(pDataObjectA, &pDataObject);

if (FAILED(hResult))

return hResult;

hResult = ConvertFORMATETCToW(pFetc, &FormatEtc);

if (FAILED(hResult))

goto Error;

hResult = WrapIAdviseSinkWFromA(pAdviseA, &pAdvise);

if (FAILED(hResult))

goto Error1;

hResult = GetWide()->Advise(pDataObject, &FormatEtc, advf, pAdvise, pdwConnection);

if (pAdvise)

pAdvise->Release();

Error1:

if (pDataObject)

pDataObject->Release();

Error:

ConvertFORMATETCFree(&FormatEtc);

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CDataAdviseHolderA::Unadvise, public

//

//  Synopsis:   Thunks Unadvise to Unicode method.

//

//  Returns:    OLE result code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CDataAdviseHolderA::Unadvise(DWORD dwConnection)

{

_DebugHook(GetWide(), MEMBER_PTR(IDataAdviseHolder, Unadvise));

return GetWide()->Unadvise(dwConnection);

}

//+--------------------------------------------------------------------------

//

//  Member:     CDataAdviseHolderA::EnumAdvise, public

//

//  Synopsis:   Thunks EnumAdvise to Unicode method.

//

//  Returns:    OLE result code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CDataAdviseHolderA::EnumAdvise(

LPENUMSTATDATAA * ppenumAdviseA)

{

TraceMethodEnter("CDataAdviseHolderA::EnumAdvise", this);

LPENUMSTATDATA penumAdvise = NULL;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IDataAdviseHolder, EnumAdvise));

hResult = GetWide()->EnumAdvise(&penumAdvise);

if (FAILED(hResult))

return hResult;

if (penumAdvise)

{

hResult = WrapIEnumSTATDATAAFromW(penumAdvise, ppenumAdviseA);

penumAdvise->Release();

}

else

*ppenumAdviseA = NULL;

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CDataAdviseHolderA::SendOnDataChange, public

//

//  Synopsis:   Thunks SendOnDataChange to Unicode method.

//

//  Returns:    OLE result code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CDataAdviseHolderA::SendOnDataChange(LPDATAOBJECTA pDataObjectA,

DWORD dwReserved, DWORD advf)

{

TraceMethodEnter("CDataAdviseHolderA::SendOnDataChange", this);

LPDATAOBJECT pDataObject;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IDataAdviseHolder, SendOnDataChange));

hResult = WrapIDataObjectWFromA(pDataObjectA, &pDataObject);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->SendOnDataChange(pDataObject, dwReserved, advf);

if (pDataObject)

pDataObject->Release();

return hResult;

}


 IOleCache2A Implementation  (OLEANSI Sample)

//***************************************************************************

//

//                   IOleCache2A Implementation

//

//***************************************************************************

//+--------------------------------------------------------------------------

//

//  Member:     COleCache2A::Cache, public

//

//  Synopsis:   Thunks Cache to Unicode method.

//

//  Returns:    OLE result code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleCache2A::Cache(LPFORMATETCA lpFormatetc, DWORD advf,

LPDWORD lpdwConnection)

{

TraceMethodEnter("COleCache2A::Cache", this);

FORMATETC FormatEtc;

HRESULT   hResult;

_DebugHook(GetWide(), MEMBER_PTR(IOleCache, Cache));

hResult = ConvertFORMATETCToW(lpFormatetc, &FormatEtc);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->Cache(&FormatEtc, advf, lpdwConnection);

ConvertFORMATETCFree(&FormatEtc);

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     COleCache2A::Uncache, public

//

//  Synopsis:   Thunks Uncache to Unicode method.

//

//  Returns:    OLE result code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleCache2A::Uncache(DWORD dwConnection)

{

_DebugHook(GetWide(), MEMBER_PTR(IOleCache, Uncache));

return GetWide()->Uncache(dwConnection);

}

//+--------------------------------------------------------------------------

//

//  Member:     COleCache2A::EnumCache, public

//

//  Synopsis:   Thunks EnumCache to Unicode method.

//

//  Returns:    OLE result code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleCache2A::EnumCache(LPENUMSTATDATAA * ppenumStatDataA)

{

TraceMethodEnter("COleCache2A::EnumCache", this);

LPENUMSTATDATA penumStatData = NULL;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IOleCache, EnumCache));

hResult = GetWide()->EnumCache(&penumStatData);

if (FAILED(hResult))

return hResult;

if (penumStatData)

{

hResult = WrapIEnumSTATDATAAFromW(penumStatData, ppenumStatDataA);

penumStatData->Release();

}

else

*ppenumStatDataA = NULL;

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     COleCache2A::InitCache, public

//

//  Synopsis:   Thunks InitCache to Unicode method.

//

//  Returns:    OLE result code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleCache2A::InitCache(LPDATAOBJECTA pDataObjectA)

{

TraceMethodEnter("COleCache2A::InitCache", this);

LPDATAOBJECT pDataObject;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IOleCache, InitCache));

hResult = WrapIDataObjectWFromA(pDataObjectA, &pDataObject);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->InitCache(pDataObject);

if (pDataObject)

pDataObject->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     COleCache2A::SetData, public

//

//  Synopsis:   Thunks SetData to Unicode method.

//

//  Returns:    OLE result code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleCache2A::SetData(LPFORMATETCA pformatetc,

STGMEDIUMA * pmediumA, BOOL fRelease)

{

TraceMethodEnter("COleCache2A::SetData", this);

FORMATETC FormatEtc;

STGMEDIUM Medium;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IOleCache, SetData));

hResult = ConvertFORMATETCToW(pformatetc, &FormatEtc);

if (FAILED(hResult))

return hResult;

hResult = ConvertSTGMEDIUMToW(pformatetc->cfFormat, pmediumA, &Medium);

if (FAILED(hResult))

goto Error;

hResult = GetWide()->SetData(&FormatEtc, &Medium, fRelease);

ConvertSTGMEDIUMFree(pformatetc->cfFormat, &Medium);

Error:

ConvertFORMATETCFree(&FormatEtc);

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     COleCache2A::UpdateCache, public

//

//  Synopsis:   Thunks UpdateCache to Unicode method.

//

//  Returns:    OLE result code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleCache2A::UpdateCache(LPDATAOBJECTA pDataObjectA,

DWORD grfUpdf, LPVOID pReserved)

{

TraceMethodEnter("COleCache2A::UpdateCache", this);

LPDATAOBJECT pDataObject;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IOleCache2, UpdateCache));

hResult = WrapIDataObjectWFromA(pDataObjectA, &pDataObject);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->UpdateCache(pDataObject, grfUpdf, pReserved);

if (pDataObject)

pDataObject->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     COleCache2A::DiscardCache, public

//

//  Synopsis:   Thunks DiscardCache to Unicode method.

//

//  Returns:    OLE result code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleCache2A::DiscardCache(DWORD dwDiscardOptions)

{

_DebugHook(GetWide(), MEMBER_PTR(IOleCache2, DiscardCache));

return GetWide()->DiscardCache(dwDiscardOptions);

}


 IOleCacheControlA Implementation  (OLEANSI Sample)

//***************************************************************************

//

//                   IOleCacheControlA Implementation

//

//***************************************************************************

//+--------------------------------------------------------------------------

//

//  Member:     COleCacheControlA::OnRun, public

//

//  Synopsis:   Thunks OnRun to Unicode method.

//

//  Returns:    OLE result code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleCacheControlA::OnRun(LPDATAOBJECTA pDataObjectA)

{

TraceMethodEnter("COleCacheControlA::OnRun", this);

LPDATAOBJECT pDataObject;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IOleCacheControl, OnRun));

hResult = WrapIDataObjectWFromA(pDataObjectA, &pDataObject);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->OnRun(pDataObject);

if (pDataObject)

pDataObject->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     COleCacheControlA::OnStop, public

//

//  Synopsis:   Thunks OnStop to Unicode method.

//

//  Returns:    OLE result code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleCacheControlA::OnStop(VOID)

{

_DebugHook(GetWide(), MEMBER_PTR(IOleCacheControl, OnStop));

return GetWide()->OnStop();

}


 DvObj API Thunks.  (OLEANSI Sample)

//***************************************************************************

//

//                          DvObj API Thunks.

//

//***************************************************************************

STDAPI CreateDataAdviseHolderA(LPDATAADVISEHOLDERA * ppDAHolder)

{

TraceSTDAPIEnter("CreateDataAdviseHolderA");

LPDATAADVISEHOLDER pDAHolder;

HRESULT hResult;

*ppDAHolder = NULL;

hResult = CreateDataAdviseHolder(&pDAHolder);

if (FAILED(hResult))

return hResult;

hResult = WrapIDataAdviseHolderAFromW(pDAHolder, ppDAHolder);

if (pDAHolder)

pDAHolder->Release();

return hResult;

}


 ANSIMONI.H  (OLEANSI Sample)

//+--------------------------------------------------------------------------

//

//  Copyright (C) 1994, Microsoft Corporation.  All Rights Reserved.

//

//  File:       ansimoni.h

//

//  Contents:   ANSI Wrappers for Unicode Moniker Interfaces and APIs.

//

//  Classes:    CBindCtxA

//              CMonikerA

//              CRunningObjectTableA

//              CEnumMonikerA

//

//  Functions:  BindMonikerA

//              MkParseDisplayNameA

//              MonikerRelativePathToA

//              MonikerCommonPrefixWithA

//              CreateBindCtxA

//              CreateGenericCompositeA

//              GetClassFileA

//              CreateFileMonikerA

//              CreateItemMonikerA

//              CreateAntiMonikerA

//              CreatePointerMonikerA

//              GetRunningObjectTableA

//              IBindCtxAFromW

//              IMonikerAFromW

//              IRunningObjectTableAFromW

//              IEnumMonikerAFromW

//

//  History:    01-Nov-93   v-kentc     Created.

//

//---------------------------------------------------------------------------

#if defined(__cplusplus)

interface IDataObjectA;

#else

typedef interface IDataObjectA IDataObjectA;

#endif

typedef IDataObjectA * LPDATAOBJECTA;

typedef struct tagOLEVERBA

{

LONG    lVerb;

LPSTR   lpszVerbName;

DWORD   fuFlags;

DWORD   grfAttribs;

} OLEVERBA, * LPOLEVERBA;

/*---------------------------------------------------------------------*/

/*                          IDropTargetA                               */

/*---------------------------------------------------------------------*/

#undef INTERFACE

#define INTERFACE   IDropTargetA

DECLARE_INTERFACE_(IDropTargetA, IUnknown)

{

// *** IUnknown methods ***

STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppvObj) PURE;

STDMETHOD_(ULONG,AddRef) (THIS)  PURE;

STDMETHOD_(ULONG,Release) (THIS) PURE;

// *** IDropTarget methods ***

STDMETHOD(DragEnter) (THIS_ LPDATAOBJECTA pDataObjA, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect) PURE;

STDMETHOD(DragOver) (THIS_ DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect) PURE;

STDMETHOD(DragLeave) (THIS) PURE;

STDMETHOD(Drop) (THIS_ LPDATAOBJECTA pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect) PURE;

};

typedef IDropTargetA * LPDROPTARGETA;

/*---------------------------------------------------------------------*/

/*                        IPersistStorageA                             */

/*---------------------------------------------------------------------*/

#undef INTERFACE

#define INTERFACE   IPersistStorageA

DECLARE_INTERFACE_(IPersistStorageA, IPersist)

{

// *** IUnknown methods ***

STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppvObj) PURE;

STDMETHOD_(ULONG,AddRef) (THIS)  PURE;

STDMETHOD_(ULONG,Release) (THIS) PURE;

// *** IPersist methods ***

STDMETHOD(GetClassID) (THIS_ LPCLSID lpClassID) PURE;

// *** IPersistStorage methods ***

STDMETHOD(IsDirty) (THIS) PURE;

STDMETHOD(InitNew) (THIS_ LPSTORAGEA pStgA) PURE;

STDMETHOD(Load) (THIS_ LPSTORAGEA pStgA) PURE;

STDMETHOD(Save) (THIS_ LPSTORAGEA pStgSaveA, BOOL fSameAsLoad) PURE;

STDMETHOD(SaveCompleted) (THIS_ LPSTORAGEA pStgNewA) PURE;

STDMETHOD(HandsOffStorage) (THIS) PURE;

};

typedef IPersistStorageA * LPPERSISTSTORAGEA;

/*---------------------------------------------------------------------*/

/*                          IPersistStreamA                            */

/*---------------------------------------------------------------------*/

#undef INTERFACE

#define INTERFACE   IPersistStreamA

DECLARE_INTERFACE_(IPersistStreamA, IPersist)

{

// *** IUnknown methods ***

STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppvObj) PURE;

STDMETHOD_(ULONG,AddRef) (THIS)  PURE;

STDMETHOD_(ULONG,Release) (THIS) PURE;

// *** IPersist methods ***

STDMETHOD(GetClassID) (THIS_ LPCLSID lpClassID) PURE;

// *** IPersistStream methods ***

STDMETHOD(IsDirty) (THIS) PURE;

STDMETHOD(Load) (THIS_ LPSTREAMA pStmA) PURE;

STDMETHOD(Save) (THIS_ LPSTREAMA pStmA,

BOOL fClearDirty) PURE;

STDMETHOD(GetSizeMax) (THIS_ ULARGE_INTEGER * pcbSize) PURE;

};

typedef IPersistStreamA * LPPERSISTSTREAMA;

/*---------------------------------------------------------------------*/

/*                          IPersistFileA                              */

/*---------------------------------------------------------------------*/

#undef INTERFACE

#define INTERFACE   IPersistFileA

DECLARE_INTERFACE_(IPersistFileA, IPersist)

{

// *** IUnknown methods ***

STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppvObj) PURE;

STDMETHOD_(ULONG,AddRef) (THIS)  PURE;

STDMETHOD_(ULONG,Release) (THIS) PURE;

// *** IPersist methods ***

STDMETHOD(GetClassID) (THIS_ LPCLSID lpClassID) PURE;

// *** IPersistFile methods ***

STDMETHOD(IsDirty) (THIS) PURE;

STDMETHOD(Load) (THIS_ LPCSTR lpszFileName, DWORD grfMode) PURE;

STDMETHOD(Save) (THIS_ LPCSTR lpszFileName, BOOL fRemember) PURE;

STDMETHOD(SaveCompleted) (THIS_ LPCSTR lpszFileName) PURE;

STDMETHOD(GetCurFile) (THIS_ LPSTR * lplpszFileName) PURE;

};

typedef IPersistFileA * LPPERSISTFILEA;

#if defined(__cplusplus)

interface IMonikerA;

interface IEnumMonikerA;

interface IRunningObjectTableA;

#else

typedef interface IMonikerA IMonikerA;

typedef interface IEnumMonikerA IEnumMonikerA;

typedef interface IRunningObjectTableA IRunningObjectTableA;

#endif

typedef IMonikerA * LPMONIKERA;

typedef IEnumMonikerA * LPENUMMONIKERA;

typedef IRunningObjectTableA * LPRUNNINGOBJECTTABLEA;

/*---------------------------------------------------------------------*/

/*                          IBindCtxA                                  */

/*---------------------------------------------------------------------*/

#undef  INTERFACE

#define INTERFACE   IBindCtxA

DECLARE_INTERFACE_(IBindCtxA, IUnknown)

{

// *** IUnknown methods ***

STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppvObj) PURE;

STDMETHOD_(ULONG,AddRef) (THIS)  PURE;

STDMETHOD_(ULONG,Release) (THIS) PURE;

// *** IBindCtx methods ***

STDMETHOD(RegisterObjectBound) (THIS_ LPUNKNOWN punk) PURE;

STDMETHOD(RevokeObjectBound) (THIS_ LPUNKNOWN punk) PURE;

STDMETHOD(ReleaseBoundObjects) (THIS) PURE;

STDMETHOD(SetBindOptions) (THIS_ LPBIND_OPTS pbindopts) PURE;

STDMETHOD(GetBindOptions) (THIS_ LPBIND_OPTS pbindopts) PURE;

STDMETHOD(GetRunningObjectTable) (THIS_ LPRUNNINGOBJECTTABLEA  *

pprotA) PURE;

STDMETHOD(RegisterObjectParam) (THIS_ LPSTR lpszKey, LPUNKNOWN punk) PURE;

STDMETHOD(GetObjectParam) (THIS_ LPSTR lpszKey, LPUNKNOWN * ppunk) PURE;

STDMETHOD(EnumObjectParam) (THIS_ LPENUMSTRINGA * ppenumA) PURE;

STDMETHOD(RevokeObjectParam) (THIS_ LPSTR lpszKey) PURE;

};

typedef IBindCtxA * LPBCA;

typedef IBindCtxA * LPBINDCTXA;

/*---------------------------------------------------------------------*/

/*                          IMonikerA                                  */

/*---------------------------------------------------------------------*/

#undef  INTERFACE

#define INTERFACE   IMonikerA

DECLARE_INTERFACE_(IMonikerA, IPersistStreamA)

{

// *** IUnknown methods ***

STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppvObj) PURE;

STDMETHOD_(ULONG,AddRef) (THIS)  PURE;

STDMETHOD_(ULONG,Release) (THIS) PURE;

// *** IPersist methods ***

STDMETHOD(GetClassID) (THIS_ LPCLSID lpClassID) PURE;

// *** IPersistStream methods ***

STDMETHOD(IsDirty) (THIS) PURE;

STDMETHOD(Load) (THIS_ LPSTREAMA pStmA) PURE;

STDMETHOD(Save) (THIS_ LPSTREAMA pStmA,

BOOL fClearDirty) PURE;

STDMETHOD(GetSizeMax) (THIS_ ULARGE_INTEGER * pcbSize) PURE;

// *** IMoniker methods ***

STDMETHOD(BindToObject) (THIS_ LPBCA pbca, LPMONIKERA pmkToLeftA,

REFIID riidResult, LPVOID * ppvResult) PURE;

STDMETHOD(BindToStorage) (THIS_ LPBCA pbca, LPMONIKERA pmkToLeftA,

REFIID riid, LPVOID * ppvObj) PURE;

STDMETHOD(Reduce) (THIS_ LPBCA pbca, DWORD dwReduceHow, LPMONIKERA *

ppmkToLeft, LPMONIKERA * ppmkReducedA) PURE;

STDMETHOD(ComposeWith) (THIS_ LPMONIKERA pmkRightA, BOOL fOnlyIfNotGeneric,

LPMONIKERA * ppmkCompositeA) PURE;

STDMETHOD(Enum) (THIS_ BOOL fForward, LPENUMMONIKERA * ppenumMonikerA)

PURE;

STDMETHOD(IsEqual) (THIS_ LPMONIKERA pmkOtherMonikerA) PURE;

STDMETHOD(Hash) (THIS_ LPDWORD pdwHash) PURE;

STDMETHOD(IsRunning) (THIS_ LPBCA pbca, LPMONIKERA pmkToLeft, LPMONIKERA

pmkNewlyRunning) PURE;

STDMETHOD(GetTimeOfLastChange) (THIS_ LPBCA pbca, LPMONIKERA pmkToLeftA,

FILETIME * pfiletime) PURE;

STDMETHOD(Inverse) (THIS_ LPMONIKERA * ppmkA) PURE;

STDMETHOD(CommonPrefixWith) (THIS_ LPMONIKERA pmkOther, LPMONIKERA *

ppmkPrefix) PURE;

STDMETHOD(RelativePathTo) (THIS_ LPMONIKERA pmkOther, LPMONIKERA *

ppmkRelPath) PURE;

STDMETHOD(GetDisplayName) (THIS_ LPBCA pbca, LPMONIKERA pmkToLeftA,

LPSTR * lplpszDisplayName) PURE;

STDMETHOD(ParseDisplayName) (THIS_ LPBCA pbca, LPMONIKERA pmkToLeftA,

LPSTR lpszDisplayName, ULONG * pchEaten,

LPMONIKERA * ppmkOutA) PURE;

STDMETHOD(IsSystemMoniker) (THIS_ LPDWORD pdwMksys) PURE;

};

/*---------------------------------------------------------------------*/

/*                        IRunningObjectTableA                         */

/*---------------------------------------------------------------------*/

#undef  INTERFACE

#define INTERFACE   IRunningObjectTableA

DECLARE_INTERFACE_(IRunningObjectTableA, IUnknown)

{

// *** IUnknown methods ***

STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppvObj) PURE;

STDMETHOD_(ULONG,AddRef) (THIS)  PURE;

STDMETHOD_(ULONG,Release) (THIS) PURE;

// *** IRunningObjectTable methods ***

STDMETHOD(Register) (THIS_ DWORD grfFlags, LPUNKNOWN punkObject,

LPMONIKERA pmkObjectNameA, DWORD * pdwRegister) PURE;

STDMETHOD(Revoke) (THIS_ DWORD dwRegister) PURE;

STDMETHOD(IsRunning) (THIS_ LPMONIKERA pmkObjectNameA) PURE;

STDMETHOD(GetObject) (THIS_ LPMONIKERA pmkObjectNameA,

LPUNKNOWN * ppunkObject) PURE;

STDMETHOD(NoteChangeTime) (THIS_ DWORD dwRegister, FILETIME * pfiletime) PURE;

STDMETHOD(GetTimeOfLastChange) (THIS_ LPMONIKERA pmkObjectNameA, FILETIME * pfiletime) PURE;

STDMETHOD(EnumRunning) (THIS_ LPENUMMONIKERA * ppenumMonikerA ) PURE;

};

typedef IRunningObjectTableA * LPRUNNINGOBJECTTABLEA;

/*---------------------------------------------------------------------*/

/*                          IEnumMonikerA                              */

/*---------------------------------------------------------------------*/

#undef  INTERFACE

#define INTERFACE   IEnumMonikerA

DECLARE_INTERFACE_(IEnumMonikerA, IUnknown)

{

// *** IUnknown methods ***

STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppvObj) PURE;

STDMETHOD_(ULONG,AddRef) (THIS)  PURE;

STDMETHOD_(ULONG,Release) (THIS) PURE;

// *** IEnumOleDataObject methods ***

STDMETHOD(Next) (THIS_ ULONG celt, LPMONIKERA * rgeltA, ULONG * pceltFetched) PURE;

STDMETHOD(Skip) (THIS_ ULONG celt) PURE;

STDMETHOD(Reset) (THIS) PURE;

STDMETHOD(Clone) (THIS_ IEnumMonikerA * * ppenmA) PURE;

};

typedef IEnumMonikerA * LPENUMMONIKERA;

//

//  Forward declarations

//

class CBindCtxA;

class CMonikerA;

class CRunningObjectTableA;

class CEnumMonikerA;

//+--------------------------------------------------------------------------

//

//  Class:      CBindCtxA

//

//  Synopsis:   Class definition of IBindCtxA

//

//---------------------------------------------------------------------------

class CBindCtxA : CAnsiInterface

{

public:

// *** IBindCtx methods ***

STDMETHOD(RegisterObjectBound) (LPUNKNOWN punk);

STDMETHOD(RevokeObjectBound) (LPUNKNOWN punk);

STDMETHOD(ReleaseBoundObjects) (VOID);

STDMETHOD(SetBindOptions) (LPBIND_OPTS pbindopts);

STDMETHOD(GetBindOptions) (LPBIND_OPTS pbindopts);

STDMETHOD(GetRunningObjectTable) (LPRUNNINGOBJECTTABLEA  *

pprotA);

STDMETHOD(RegisterObjectParam) (LPSTR lpszKey, LPUNKNOWN punk);

STDMETHOD(GetObjectParam) (LPSTR lpszKey, LPUNKNOWN * ppunk);

STDMETHOD(EnumObjectParam) (LPENUMSTRINGA * ppenumA);

STDMETHOD(RevokeObjectParam) (LPSTR lpszKey);

inline CBindCtxA(LPUNKNOWN pUnk, IBindCtx * pWide) :

CAnsiInterface(ID_IBindCtx, pUnk, (LPUNKNOWN)pWide) {};

inline IBindCtx * GetWide() const

{ return (IBindCtx *)m_pObj; };

};

//+--------------------------------------------------------------------------

//

//  Class:      CMonikerA

//

//  Synopsis:   Class definition of IMonikerA

//

//---------------------------------------------------------------------------

class CMonikerA : CAnsiInterface

{

public:

// *** IPersist methods ***

STDMETHOD(GetClassID) (LPCLSID lpClassID);

// *** IPersistStream methods ***

STDMETHOD(IsDirty) (VOID);

STDMETHOD(Load) (LPSTREAMA pStmA);

STDMETHOD(Save) (LPSTREAMA pStmA,

BOOL fClearDirty);

STDMETHOD(GetSizeMax) (ULARGE_INTEGER * pcbSize);

// *** IMoniker methods ***

STDMETHOD(BindToObject) (LPBCA pbca, LPMONIKERA pmkToLeftA,

REFIID riidResult, LPVOID * ppvResult);

STDMETHOD(BindToStorage) (LPBCA pbca, LPMONIKERA pmkToLeftA,

REFIID riid, LPVOID * ppvObj);

STDMETHOD(Reduce) (LPBCA pbca, DWORD dwReduceHowFar, LPMONIKERA *

ppmkToLeft, LPMONIKERA * ppmkReducedA);

STDMETHOD(ComposeWith) (LPMONIKERA pmkRightA, BOOL fOnlyIfNotGeneric,

LPMONIKERA * ppmkCompositeA);

STDMETHOD(Enum) (BOOL fForward, LPENUMMONIKERA * ppenumMonikerA);

STDMETHOD(IsEqual) (LPMONIKERA pmkOtherMonikerA);

STDMETHOD(Hash) (LPDWORD pdwHash);

STDMETHOD(IsRunning) (LPBCA pbca, LPMONIKERA pmkToLeft, LPMONIKERA

pmkNewlyRunning);

STDMETHOD(GetTimeOfLastChange) (LPBCA pbca, LPMONIKERA pmkToLeftA,

FILETIME * pfiletime);

STDMETHOD(Inverse) (LPMONIKERA * ppmkA);

STDMETHOD(CommonPrefixWith) (LPMONIKERA pmkOther, LPMONIKERA *

ppmkPrefix);

STDMETHOD(RelativePathTo) (LPMONIKERA pmkOther, LPMONIKERA *

ppmkRelPath);

STDMETHOD(GetDisplayName) (LPBCA pbca, LPMONIKERA pmkToLeftA,

LPSTR * lplpszDisplayName);

STDMETHOD(ParseDisplayName) (LPBCA pbca, LPMONIKERA pmkToLeftA,

LPSTR lpszDisplayName, ULONG * pchEaten,

LPMONIKERA * ppmkOutA);

STDMETHOD(IsSystemMoniker) (LPDWORD pdwMksys);

inline CMonikerA(LPUNKNOWN pUnk, IMoniker * pWide) :

CAnsiInterface(ID_IMoniker, pUnk, (LPUNKNOWN)pWide) {};

inline IMoniker * GetWide() const

{ return (IMoniker *)m_pObj; };

};

//+--------------------------------------------------------------------------

//

//  Class:      CRunningObjectTableA

//

//  Synopsis:   Class definition of IRunningObjectTableA

//

//---------------------------------------------------------------------------

class CRunningObjectTableA : CAnsiInterface

{

public:

// *** IRunningObjectTable methods ***

STDMETHOD(Register) (DWORD grfFlags, LPUNKNOWN punkObject,

LPMONIKERA pmkObjectNameA, DWORD * pdwRegister);

STDMETHOD(Revoke) (DWORD dwRegister);

STDMETHOD(IsRunning) (LPMONIKERA pmkObjectNameA);

STDMETHOD(GetObject) (LPMONIKERA pmkObjectNameA,

LPUNKNOWN * ppunkObject);

STDMETHOD(NoteChangeTime) (DWORD dwRegister, FILETIME * pfiletime);

STDMETHOD(GetTimeOfLastChange) (LPMONIKERA pmkObjectNameA, FILETIME * pfiletime);

STDMETHOD(EnumRunning) (LPENUMMONIKERA * ppenumMonikerA );

inline CRunningObjectTableA(LPUNKNOWN pUnk, IRunningObjectTable * pWide) :

CAnsiInterface(ID_IRunningObjectTable, pUnk, (LPUNKNOWN)pWide) {};

inline IRunningObjectTable * GetWide() const

{ return (IRunningObjectTable *)m_pObj; };

};

//+--------------------------------------------------------------------------

//

//  Class:      CEnumMonikerA

//

//  Synopsis:   Class definition of IEnumMonikerA

//

//---------------------------------------------------------------------------

class CEnumMonikerA : CAnsiInterface

{

public:

// *** IEnumOleDataObject methods ***

STDMETHOD(Next) (ULONG celt, LPMONIKERA * rgeltA, ULONG * pceltFetched);

STDMETHOD(Skip) (ULONG celt);

STDMETHOD(Reset) (VOID);

STDMETHOD(Clone) (IEnumMonikerA * * ppenmA);

inline CEnumMonikerA(LPUNKNOWN pUnk, IEnumMoniker * pWide) :

CAnsiInterface(ID_IEnumMoniker, pUnk, (LPUNKNOWN)pWide) {};

inline IEnumMoniker * GetWide() const

{ return (IEnumMoniker *)m_pObj; };

};


 ANSIMONI.CPP  (OLEANSI Sample)

//+--------------------------------------------------------------------------

//

//  Copyright (C) 1994, Microsoft Corporation.  All Rights Reserved.

//

//  File:       ansimoni.h

//

//  Contents:   ANSI Wrappers for Unicode Moniker Interfaces and APIs.

//

//  Classes:    CBindCtxA

//              CMonikerA

//              CRunningObjectTableA

//              CEnumMonikerA

//

//  Functions:  BindMonikerA

//              MkParseDisplayNameA

//              MonikerRelativePathToA

//              MonikerCommonPrefixWithA

//              CreateBindCtxA

//              CreateGenericCompositeA

//              GetClassFileA

//              CreateFileMonikerA

//              CreateItemMonikerA

//              CreateAntiMonikerA

//              CreatePointerMonikerA

//              GetRunningObjectTableA

//              IBindCtxAFromW

//              IMonikerAFromW

//              IRunningObjectTableAFromW

//              IEnumMonikerAFromW

//

//  History:    01-Nov-93   v-kentc     Created.

//                      28-Mar-94   v-kentc     Wrap all IUnknowns.

//

//---------------------------------------------------------------------------

#include "Ole2Ansi.h"


 IBindCtxA Implementation  (OLEANSI Sample)

//***************************************************************************

//

//                   IBindCtxA Implementation

//

//***************************************************************************

//+--------------------------------------------------------------------------

//

//  Member:     CBindCtxA::RegisterObjectBound, public

//

//  Synopsis:   Thunks RegisterObjectBound to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CBindCtxA::RegisterObjectBound(LPUNKNOWN punkA)

{

TraceMethodEnter("CBindCtxA::RegisterObjectBound", this);

LPUNKNOWN punk;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IBindCtx, RegisterObjectBound));

hResult = WrapIUnknownWFromA(punkA, &punk);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->RegisterObjectBound(punk);

punk->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CBindCtxA::RevokeObjectBound, public

//

//  Synopsis:   Thunks RevokeObjectBound to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CBindCtxA::RevokeObjectBound(LPUNKNOWN punkA)

{

TraceMethodEnter("CBindCtxA::RevokeObjectBound", this);

LPUNKNOWN punk;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IBindCtx, RevokeObjectBound));

hResult = WrapIUnknownWFromA(punkA, &punk);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->RevokeObjectBound(punk);

punk->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CBindCtxA::ReleaseBoundObjects, public

//

//  Synopsis:   Thunks ReleaseBoundObjects to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CBindCtxA::ReleaseBoundObjects()

{

_DebugHook(GetWide(), MEMBER_PTR(IBindCtx, ReleaseBoundObjects));

return GetWide()->ReleaseBoundObjects();

}

//+--------------------------------------------------------------------------

//

//  Member:     CBindCtxA::SetBindOptions, public

//

//  Synopsis:   Thunks SetBindOptions to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CBindCtxA::SetBindOptions(LPBIND_OPTS pbindopts)

{

_DebugHook(GetWide(), MEMBER_PTR(IBindCtx, SetBindOptions));

return GetWide()->SetBindOptions(pbindopts);

}

//+--------------------------------------------------------------------------

//

//  Member:     CBindCtxA::GetBindOptions, public

//

//  Synopsis:   Thunks GetBindOptions to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CBindCtxA::GetBindOptions(LPBIND_OPTS pbindopts)

{

_DebugHook(GetWide(), MEMBER_PTR(IBindCtx, GetBindOptions));

return GetWide()->GetBindOptions(pbindopts);

}

//+--------------------------------------------------------------------------

//

//  Member:     CBindCtxA::GetRunningObjectTable, public

//

//  Synopsis:   Thunks GetRunningObjectTable to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CBindCtxA::GetRunningObjectTable(LPRUNNINGOBJECTTABLEA * pprotA)

{

TraceMethodEnter("CBindCtxA::GetRunningObjectTable", this);

LPRUNNINGOBJECTTABLE prot;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IBindCtx, GetRunningObjectTable));

*pprotA = NULL;

hResult = GetWide()->GetRunningObjectTable(&prot);

if (FAILED(hResult))

return hResult;

hResult = WrapIRunningObjectTableAFromW(prot, pprotA);

if (prot)

prot->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CBindCtxA::RegisterObjectParam, public

//

//  Synopsis:   Thunks RegisterObjectParam to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CBindCtxA::RegisterObjectParam(LPSTR lpszKeyA, LPUNKNOWN punkA)

{

TraceMethodEnter("CBindCtxA::RegisterObjectParam", this);

LPOLESTR lpszKey;

LPUNKNOWN punk;

HRESULT  hResult;

_DebugHook(GetWide(), MEMBER_PTR(IBindCtx, RegisterObjectParam));

hResult = ConvertStringToW(lpszKeyA, &lpszKey);

if (FAILED(hResult))

return (hResult);

hResult = WrapIUnknownWFromA(punkA, &punk);

if (FAILED(hResult))

goto Error;

hResult = GetWide()->RegisterObjectParam(lpszKey, punk);

punk->Release();

Error:

ConvertStringFree(lpszKey);

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CBindCtxA::GetObjectParam, public

//

//  Synopsis:   Thunks GetObjectParam to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CBindCtxA::GetObjectParam(LPSTR lpszKeyA, LPUNKNOWN * ppunkA)

{

TraceMethodEnter("CBindCtxA::GetObjectParam", this);

LPOLESTR  lpszKey;

LPUNKNOWN punk;

HRESULT   hResult;

_DebugHook(GetWide(), MEMBER_PTR(IBindCtx, GetObjectParam));

*ppunkA = NULL;

hResult = ConvertStringToW(lpszKeyA, &lpszKey);

if (FAILED(hResult))

return (hResult);

hResult = GetWide()->GetObjectParam(lpszKey, &punk);

if (FAILED(hResult))

goto Error;

hResult = WrapIUnknownAFromW(punk, ppunkA);

punk->Release();

Error:

ConvertStringFree(lpszKey);

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CBindCtxA::EnumObjectParam, public

//

//  Synopsis:   Thunks EnumObjectParam to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CBindCtxA::EnumObjectParam(LPENUMSTRINGA * ppenumA)

{

TraceMethodEnter("CBindCtxA::EnumObjectParam", this);

LPENUMSTRING penum;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IBindCtx, EnumObjectParam));

*ppenumA = NULL;

hResult = GetWide()->EnumObjectParam(&penum);

if (FAILED(hResult))

return hResult;

if (penum)

{

hResult = WrapIEnumStringAFromW(penum, ppenumA);

penum->Release();

}

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CBindCtxA::RevokeObjectParam, public

//

//  Synopsis:   Thunks RevokeObjectParam to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CBindCtxA::RevokeObjectParam(LPSTR lpszKeyA)

{

TraceMethodEnter("CBindCtxA::RevokeObjectParam", this);

LPOLESTR lpszKey;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IBindCtx, RevokeObjectParam));

hResult = ConvertStringToW(lpszKeyA, &lpszKey);

if (FAILED(hResult))

return (hResult);

hResult = GetWide()->RevokeObjectParam(lpszKey);

ConvertStringFree(lpszKey);

return hResult;

}


 IMonikerA Implementation  (OLEANSI Sample)

//***************************************************************************

//

//                   IMonikerA Implementation

//

//***************************************************************************

//+--------------------------------------------------------------------------

//

//  Member:     CMonikerA::GetClassID, public

//

//  Synopsis:   Thunks GetClassID to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CMonikerA::GetClassID(LPCLSID lpClassID)

{

_DebugHook(GetWide(), MEMBER_PTR(IPersist, GetClassID));

return GetWide()->GetClassID(lpClassID);

}

//+--------------------------------------------------------------------------

//

//  Member:     CMonikerA::IsDirty, public

//

//  Synopsis:   Thunks IsDirty to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CMonikerA::IsDirty(VOID)

{

_DebugHook(GetWide(), MEMBER_PTR(IPersistStream, IsDirty));

return GetWide()->IsDirty();

}

//+--------------------------------------------------------------------------

//

//  Member:     CMonikerA::Load, public

//

//  Synopsis:   Thunks Load to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CMonikerA::Load(LPSTREAMA pStrmA)

{

TraceMethodEnter("CMonikerA::Load", this);

LPSTREAM pStrm;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IPersistStream, Load));

hResult = WrapIStreamWFromA(pStrmA, &pStrm);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->Load(pStrm);

if (pStrm)

pStrm->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CMonikerA::Save, public

//

//  Synopsis:   Thunks Save to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CMonikerA::Save(LPSTREAMA pStrmA, BOOL fClearDirty)

{

TraceMethodEnter("CMonikerA::Save", this);

LPSTREAM pStrm;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IPersistStream, Save));

hResult = WrapIStreamWFromA(pStrmA, &pStrm);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->Save(pStrm, fClearDirty);

if (pStrm)

pStrm->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CMonikerA::GetSizeMax, public

//

//  Synopsis:   Thunks GetSizeMax to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CMonikerA::GetSizeMax(ULARGE_INTEGER * pcbSize)

{

_DebugHook(GetWide(), MEMBER_PTR(IPersistStream, GetSizeMax));

return GetWide()->GetSizeMax(pcbSize);

}

//+--------------------------------------------------------------------------

//

//  Member:     CMonikerA::BindToObject, public

//

//  Synopsis:   Thunks BindToObject to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CMonikerA::BindToObject(LPBCA pbcA, LPMONIKERA pmkToLeftA,

REFIID riidResult, LPVOID * ppvResult)

{

TraceMethodEnter("CMonikerA::BindToObject", this);

LPBC        pbc;

LPMONIKER   pmk;

LPUNKNOWN   punk;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IMoniker, BindToObject));

*ppvResult = NULL;

hResult = WrapIBindCtxWFromA(pbcA, &pbc);

if (FAILED(hResult))

return hResult;

hResult = WrapIMonikerWFromA(pmkToLeftA, &pmk);

if (FAILED(hResult))

goto Error;

hResult = GetWide()->BindToObject(pbc, pmk, riidResult, (LPVOID *)&punk);

if (FAILED(hResult))

goto Error1;

if (punk)

{

IDINTERFACE idRef = WrapTranslateIID(riidResult);

hResult = WrapInterfaceAFromW(idRef, punk, (LPUNKNOWN *)ppvResult);

punk->Release();

}

Error1:

if (pmk)

pmk->Release();

Error:

if (pbc)

pbc->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CMonikerA::BindToStorage, public

//

//  Synopsis:   Thunks BindToStorage to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CMonikerA::BindToStorage(LPBCA pbcA, LPMONIKERA pmkToLeftA,

REFIID riid, LPVOID * ppvObj)

{

TraceMethodEnter("CMonikerA::BindToStorage", this);

LPBC pbc;

LPMONIKER pmk;

LPUNKNOWN punk;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IMoniker, BindToStorage));

*ppvObj = NULL;

hResult = WrapIBindCtxWFromA(pbcA, &pbc);

if (FAILED(hResult))

return hResult;

hResult = WrapIMonikerWFromA(pmkToLeftA, &pmk);

if (FAILED(hResult))

goto Error;

hResult = GetWide()->BindToStorage(pbc, pmk, riid, (LPVOID *)&punk);

if (FAILED(hResult))

goto Error1;

if (punk)

{

IDINTERFACE idRef = WrapTranslateIID(riid);

hResult = WrapInterfaceAFromW(idRef, punk, (LPUNKNOWN *)ppvObj);

punk->Release();

}

Error1:

if (pmk)

pmk->Release();

Error:

if (pbc)

pbc->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CMonikerA::Reduce, public

//

//  Synopsis:   Thunks Reduce to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CMonikerA::Reduce(LPBCA pbcA, DWORD dwReduceHowFar,

LPMONIKERA * ppmkToLeftA, LPMONIKERA * ppmkReducedA)

{

TraceMethodEnter("CMonikerA::Reduce", this);

LPBC pbc;

LPMONIKER pmkToLeft, * ppmkToLeft;

LPMONIKER pmkReduced, * ppmkReduced;

HRESULT hReturn;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IMoniker, Reduce));

if (ppmkToLeftA)

*ppmkToLeftA = NULL;

if (ppmkReducedA)

*ppmkReducedA = NULL;

hResult = WrapIBindCtxWFromA(pbcA, &pbc);

if (FAILED(hResult))

return hResult;

if (ppmkToLeftA)

ppmkToLeft = &pmkToLeft;

else

ppmkToLeft = NULL;

if (ppmkReducedA)

ppmkReduced = &pmkReduced;

else

ppmkReduced = NULL;

hReturn = GetWide()->Reduce(pbc, dwReduceHowFar, ppmkToLeft,

ppmkReduced);

if (FAILED(hReturn))

goto Error;

if (ppmkToLeft)

{

hResult = WrapIMonikerAFromW(pmkToLeft, ppmkToLeftA);

if (FAILED(hResult))

goto Error1;

}

if (ppmkReduced)

{

hResult = WrapIMonikerAFromW(pmkReduced, ppmkReducedA);

if (FAILED(hResult))

goto Error1;

}

Error1:

if (ppmkToLeft && *ppmkToLeft)

pmkToLeft->Release();

if (ppmkReduced && *ppmkReduced)

pmkReduced->Release();

Error:

if (pbc)

pbc->Release();

if (FAILED(hResult))

hReturn = hResult;

return hReturn;

}

//+--------------------------------------------------------------------------

//

//  Member:     CMonikerA::ComposeWith, public

//

//  Synopsis:   Thunks ComposeWith to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CMonikerA::ComposeWith(LPMONIKERA pmkRightA,

BOOL fOnlyIfNotGeneric, LPMONIKERA * ppmkCompositeA)

{

TraceMethodEnter("CMonikerA::ComposeWith", this);

LPMONIKER pmk;

LPMONIKER pmkComposite;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IMoniker, ComposeWith));

*ppmkCompositeA = NULL;

hResult = WrapIMonikerWFromA(pmkRightA, &pmk);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->ComposeWith(pmk, fOnlyIfNotGeneric, &pmkComposite);

if (FAILED(hResult))

goto Error;

hResult = WrapIMonikerAFromW(pmkComposite, ppmkCompositeA);

if (pmkComposite)

pmkComposite->Release();

Error:

if (pmk)

pmk->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CMonikerA::Enum, public

//

//  Synopsis:   Thunks Enum to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CMonikerA::Enum(BOOL fForward, LPENUMMONIKERA * ppenumMonikerA)

{

TraceMethodEnter("CMonikerA::Enum", this);

LPENUMMONIKER penum;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IMoniker, Enum));

*ppenumMonikerA = NULL;

hResult = GetWide()->Enum(fForward, &penum);

if (FAILED(hResult))

return hResult;

if (penum)

{

hResult = WrapIEnumMonikerAFromW(penum, ppenumMonikerA);

penum->Release();

}

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CMonikerA::IsEqual, public

//

//  Synopsis:   Thunks IsEqual to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CMonikerA::IsEqual(LPMONIKERA pmkOtherMonikerA)

{

TraceMethodEnter("CMonikerA::IsEqual", this);

LPMONIKER pmk;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IMoniker, IsEqual));

hResult = WrapIMonikerWFromA(pmkOtherMonikerA, &pmk);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->IsEqual(pmk);

pmk->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CMonikerA::Hash, public

///

//  Synopsis:   Thunks Hash to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CMonikerA::Hash(LPDWORD pdwHash)

{

_DebugHook(GetWide(), MEMBER_PTR(IMoniker, Hash));

return GetWide()->Hash(pdwHash);

}

//+--------------------------------------------------------------------------

//

//  Member:     CMonikerA::IsRunning, public

//

//  Synopsis:   Thunks IsRunning to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CMonikerA::IsRunning(LPBCA pbcA, LPMONIKERA pmkToLeftA,

LPMONIKERA pmkNewlyRunningA)

{

TraceMethodEnter("CMonikerA::IsRunning", this);

LPBC pbc;

LPMONIKER pmk;

LPMONIKER pmkRunning;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IMoniker, IsRunning));

hResult = WrapIBindCtxWFromA(pbcA, &pbc);

if (FAILED(hResult))

return hResult;

hResult = WrapIMonikerWFromA(pmkToLeftA, &pmk);

if (FAILED(hResult))

goto Error;

hResult = WrapIMonikerWFromA(pmkNewlyRunningA, &pmkRunning);

if (FAILED(hResult))

goto Error1;

hResult = GetWide()->IsRunning(pbc, pmk, pmkRunning);

if (pmkRunning)

pmkRunning->Release();

Error1:

if (pmk)

pmk->Release();

Error:

if (pbc)

pbc->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CMonikerA::GetTimeOfLastChange, public

//

//  Synopsis:   Thunks GetTimeOfLastChange to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CMonikerA::GetTimeOfLastChange(LPBCA pbcA,

LPMONIKERA pmkToLeftA, FILETIME * pfiletime)

{

TraceMethodEnter("CMonikerA::GetTimeOfLastChange", this);

LPBC pbc;

LPMONIKER pmk;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IMoniker, GetTimeOfLastChange));

hResult = WrapIBindCtxWFromA(pbcA, &pbc);

if (FAILED(hResult))

return hResult;

hResult = WrapIMonikerWFromA(pmkToLeftA, &pmk);

if (FAILED(hResult))

goto Error;

hResult = GetWide()->GetTimeOfLastChange(pbc, pmk, pfiletime);

if (pmk)

pmk->Release();

Error:

if (pbc)

pbc->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CMonikerA::Inverse, public

//

//  Synopsis:   Thunks Inverse to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CMonikerA::Inverse(LPMONIKERA * ppmkA)

{

TraceMethodEnter("CMonikerA::Inverse", this);

LPMONIKER pmk;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IMoniker, Inverse));

*ppmkA = NULL;

hResult = GetWide()->Inverse(&pmk);

if (FAILED(hResult))

return hResult;

hResult = WrapIMonikerAFromW(pmk, ppmkA);

if (pmk)

pmk->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CMonikerA::CommonPrefixWith, public

//

//  Synopsis:   Thunks CommonPrefixWith to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CMonikerA::CommonPrefixWith(LPMONIKERA pmkOtherA,

LPMONIKERA * ppmkPrefixA)

{

TraceMethodEnter("CMonikerA::CommonPrefixWith", this);

LPMONIKER pmkOther;

LPMONIKER pmkPrefix;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IMoniker, CommonPrefixWith));

*ppmkPrefixA = NULL;

hResult = WrapIMonikerWFromA(pmkOtherA, &pmkOther);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->CommonPrefixWith(pmkOther, &pmkPrefix);

if (FAILED(hResult))

goto Error;

hResult = WrapIMonikerAFromW(pmkPrefix, ppmkPrefixA);

if (pmkPrefix)

pmkPrefix->Release();

Error:

if (pmkOther)

pmkOther->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CMonikerA::RelativePathTo, public

//

//  Synopsis:   Thunks RelativePathTo to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CMonikerA::RelativePathTo(LPMONIKERA pmkOtherA,

LPMONIKERA * ppmkRelPathA)

{

TraceMethodEnter("CMonikerA::RelativePathTo", this);

LPMONIKER pmkOther;

LPMONIKER pmkRelPath;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IMoniker, RelativePathTo));

*ppmkRelPathA = NULL;

hResult = WrapIMonikerWFromA(pmkOtherA, &pmkOther);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->RelativePathTo(pmkOther, &pmkRelPath);

if (FAILED(hResult))

goto Error;

hResult = WrapIMonikerAFromW(pmkRelPath, ppmkRelPathA);

if (pmkRelPath)

pmkRelPath->Release();

Error:

pmkOther->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CMonikerA::GetDisplayName, public

//

//  Synopsis:   Thunks GetDisplayName to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CMonikerA::GetDisplayName(LPBCA pbcA, LPMONIKERA pmkToLeftA,

LPSTR * lplpszDisplayNameA)

{

TraceMethodEnter("CMonikerA::GetDisplayName", this);

LPBC pbc;

LPMONIKER pmkToLeft;

LPOLESTR lpszDisplayName;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IMoniker, GetDisplayName));

*lplpszDisplayNameA = NULL;

hResult = WrapIBindCtxWFromA(pbcA, &pbc);

if (FAILED(hResult))

return hResult;

hResult = WrapIMonikerWFromA(pmkToLeftA, &pmkToLeft);

if (FAILED(hResult))

goto Error;

hResult = GetWide()->GetDisplayName(pbc, pmkToLeft, &lpszDisplayName);

if (FAILED(hResult))

goto Error1;

hResult = ConvertStringToA(lpszDisplayName, lplpszDisplayNameA);

ConvertStringFree(lpszDisplayName);

Error1:

if (pmkToLeft)

pmkToLeft->Release();

Error:

if (pbc)

pbc->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CMonikerA::ParseDisplayName, public

//

//  Synopsis:   Thunks ParseDisplayName to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CMonikerA::ParseDisplayName(LPBCA pbcA, LPMONIKERA pmkToLeftA,

LPSTR lpszDisplayNameA, ULONG * pchEaten, LPMONIKERA * ppmkOutA)

{

TraceMethodEnter("CMonikerA::ParseDisplayName", this);

LPBC pbc;

LPMONIKER pmkToLeft;

LPOLESTR lpszDisplayName;

LPMONIKER pmkOut;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IMoniker, ParseDisplayName));

*ppmkOutA = NULL;

hResult = WrapIBindCtxWFromA(pbcA, &pbc);

if (FAILED(hResult))

return hResult;

hResult = WrapIMonikerWFromA(pmkToLeftA, &pmkToLeft);

if (FAILED(hResult))

goto Error;

hResult = ConvertStringToW(lpszDisplayNameA, &lpszDisplayName);

if (FAILED(hResult))

goto Error1;

hResult = GetWide()->ParseDisplayName(pbc, pmkToLeft, lpszDisplayName,

pchEaten, &pmkOut);

if (FAILED(hResult))

goto Error2;

hResult = WrapIMonikerAFromW(pmkOut, ppmkOutA);

if (pmkOut)

pmkOut->Release();

Error2:

ConvertStringFree(lpszDisplayName);

Error1:

if (pmkToLeft)

pmkToLeft->Release();

Error:

if (pbc)

pbc->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CMonikerA::IsSystemMoniker, public

//

//  Synopsis:   Thunks IsSystemMoniker to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CMonikerA::IsSystemMoniker(LPDWORD pdwMksys)

{

_DebugHook(GetWide(), MEMBER_PTR(IMoniker, IsSystemMoniker));

return GetWide()->IsSystemMoniker(pdwMksys);

}


 IRunningObjectTableA Implementation  (OLEANSI Sample)

//***************************************************************************

//

//                   IRunningObjectTableA Implementation

//

//***************************************************************************

//+--------------------------------------------------------------------------

//

//  Member:     CRunningObjectTableA::Register, public

//

//  Synopsis:   Thunks Register to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CRunningObjectTableA::Register(DWORD grfFlags,

LPUNKNOWN punkObjectA, LPMONIKERA pmkObjectNameA, DWORD * pdwRegister)

{

TraceMethodEnter("CRunningObjectTableA::Register", this);

LPMONIKER pmkObjectName;

LPUNKNOWN punk;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IRunningObjectTable, Register));

hResult = WrapIMonikerWFromA(pmkObjectNameA, &pmkObjectName);

if (FAILED(hResult))

return hResult;

hResult = WrapIUnknownWFromA(punkObjectA, &punk);

if (FAILED(hResult))

goto Error;

hResult = GetWide()->Register(grfFlags, punk, pmkObjectName,

pdwRegister);

punk->Release();

Error:

if (pmkObjectName)

pmkObjectName->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CRunningObjectTableA::Revoke, public

//

//  Synopsis:   Thunks Revoke to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CRunningObjectTableA::Revoke(DWORD dwRegister)

{

TraceMethodEnter("CRunningObjectTableA::Revoke", this);

_DebugHook(GetWide(), MEMBER_PTR(IRunningObjectTable, Revoke));

return GetWide()->Revoke(dwRegister);

}

//+--------------------------------------------------------------------------

//

//  Member:     CRunningObjectTableA::IsRunning, public

//

//  Synopsis:   Thunks IsRunning to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CRunningObjectTableA::IsRunning(LPMONIKERA pmkObjectNameA)

{

TraceMethodEnter("CRunningObjectTableA::IsRunning", this);

LPMONIKER pmkObjectName;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IRunningObjectTable, IsRunning));

hResult = WrapIMonikerWFromA(pmkObjectNameA, &pmkObjectName);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->IsRunning(pmkObjectName);

if (pmkObjectName)

pmkObjectName->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CRunningObjectTableA::GetObject, public

//

//  Synopsis:   Thunks GetObject to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CRunningObjectTableA::GetObject(LPMONIKERA pmkObjectNameA,

LPUNKNOWN * ppunkObjectA)

{

TraceMethodEnter("CRunningObjectTableA::GetObject", this);

LPMONIKER pmkObjectName;

LPUNKNOWN punk;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IRunningObjectTable, GetObject));

*ppunkObjectA = NULL;

hResult = WrapIMonikerWFromA(pmkObjectNameA, &pmkObjectName);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->GetObject(pmkObjectName, &punk);

if (FAILED(hResult))

goto Error;

hResult = WrapIUnknownAFromW(punk, ppunkObjectA);

punk->Release();

Error:

if (pmkObjectName)

pmkObjectName->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CRunningObjectTableA::NoteChangeTime, public

//

//  Synopsis:   Thunks NoteChangeTime to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CRunningObjectTableA::NoteChangeTime(DWORD dwRegister,

FILETIME * pfiletime)

{

_DebugHook(GetWide(), MEMBER_PTR(IRunningObjectTable, NoteChangeTime));

return GetWide()->NoteChangeTime(dwRegister, pfiletime);

}

//+--------------------------------------------------------------------------

//

//  Member:     CRunningObjectTableA::GetTimeOfLastChange, public

//

//  Synopsis:   Thunks GetTimeOfLastChange to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CRunningObjectTableA::GetTimeOfLastChange(

LPMONIKERA pmkObjectNameA, FILETIME * pfiletime)

{

TraceMethodEnter("CRunningObjectTableA::GetTimeOfLastChange", this);

LPMONIKER pmkObjectName;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IRunningObjectTable, GetTimeOfLastChange));

hResult = WrapIMonikerWFromA(pmkObjectNameA, &pmkObjectName);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->GetTimeOfLastChange(pmkObjectName, pfiletime);

if (pmkObjectName)

pmkObjectName->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CRunningObjectTableA::EnumRunning, public

//

//  Synopsis:   Thunks EnumRunning to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CRunningObjectTableA::EnumRunning(

LPENUMMONIKERA * ppenumMonikerA)

{

TraceMethodEnter("CRunningObjectTableA::EnumRunning", this);

LPENUMMONIKER penumMoniker;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IRunningObjectTable, EnumRunning));

*ppenumMonikerA = NULL;

hResult = GetWide()->EnumRunning(&penumMoniker);

if (FAILED(hResult))

return hResult;

if (penumMoniker)

{

hResult = WrapIEnumMonikerAFromW(penumMoniker, ppenumMonikerA);

penumMoniker->Release();

}

return hResult;

}


 IEnumMonikerA Implementation  (OLEANSI Sample)

//***************************************************************************

//

//                   IEnumMonikerA Implementation

//

//***************************************************************************

//+--------------------------------------------------------------------------

//

//  Member:     CEnumMonikerA::Next, public

//

//  Synopsis:   Thunks Next to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CEnumMonikerA::Next(

ULONG celt,

LPMONIKERA * rgelt,

ULONG * pceltFetched)

{

TraceMethodEnter("CEnumMonikerA::Next", this);

ULONG   celtFetched;

HRESULT hReturn;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IEnumMoniker, Next));

if (pceltFetched == NULL)

pceltFetched = &celtFetched;

hReturn = GetWide()->Next(celt, (LPMONIKER *)rgelt, pceltFetched);

if (FAILED(hReturn))

return hReturn;

hResult = ConvertMonikerArrayToA(rgelt, *pceltFetched);

if (FAILED(hResult))

return hResult;

return hReturn;

}

//+--------------------------------------------------------------------------

//

//  Member:     CEnumMonikerA::Skip, public

//

//  Synopsis:   Thunks Skip to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CEnumMonikerA::Skip(ULONG celt)

{

_DebugHook(GetWide(), MEMBER_PTR(IEnumMoniker, Skip));

return GetWide()->Skip(celt);

}

//+--------------------------------------------------------------------------

//

//  Member:     CEnumMonikerA::Reset, public

//

//  Synopsis:   Thunks Reset to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CEnumMonikerA::Reset(VOID)

{

_DebugHook(GetWide(), MEMBER_PTR(IEnumMoniker, Reset));

return GetWide()->Reset();

}

//+--------------------------------------------------------------------------

//

//  Member:     CEnumMonikerA::Clone, public

//

//  Synopsis:   Thunks Clone to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CEnumMonikerA::Clone(IEnumMonikerA * * ppenmA)

{

TraceMethodEnter("CEnumMonikerA::Clone", this);

IEnumMoniker * penm;

_DebugHook(GetWide(), MEMBER_PTR(IEnumMoniker, Clone));

*ppenmA = NULL;

HRESULT hResult = GetWide()->Clone(&penm);

if (FAILED(hResult))

return (hResult);

hResult = WrapIEnumMonikerAFromW(penm, ppenmA);

if (penm)

penm->Release();

return hResult;

}


 Moniker API Thunks.  (OLEANSI Sample)

//***************************************************************************

//

//                          Moniker API Thunks.

//

//***************************************************************************

//+--------------------------------------------------------------------------

//

//  Routine:    BindMonikerA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Returns:    See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI BindMonikerA(LPMONIKERA pmkA, DWORD grfOpt, REFIID iidResult,

LPVOID * ppvResult)

{

TraceSTDAPIEnter("BindMonikerA");

LPMONIKER pmk;

LPUNKNOWN punk;

HRESULT hResult;

*ppvResult = NULL;

hResult = WrapIMonikerWFromA(pmkA, &pmk);

if (FAILED(hResult))

return hResult;

hResult = BindMoniker(pmk, grfOpt, iidResult, (LPVOID *)&punk);

if (FAILED(hResult))

goto Error;

if (punk)

{

IDINTERFACE idRef = WrapTranslateIID(iidResult);

hResult = WrapInterfaceAFromW(idRef, punk, (LPUNKNOWN *)ppvResult);

punk->Release();

}

Error:

if (pmk)

pmk->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    MkParseDisplayNameA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Returns:    See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI MkParseDisplayNameA(LPBCA pbcA, LPSTR szUserNameA, ULONG * pchEaten,

LPMONIKERA * ppmkA)

{

TraceSTDAPIEnter("MkParseDisplayNameA");

LPBC  pbc;

LPOLESTR lpszUserName;

LPMONIKER pmk;

HRESULT hResult;

*ppmkA = NULL;

hResult = WrapIBindCtxWFromA(pbcA, &pbc);

if (FAILED(hResult))

return hResult;

hResult = ConvertStringToW(szUserNameA, &lpszUserName);

if (FAILED(hResult))

goto Error;

hResult = MkParseDisplayName(pbc, lpszUserName, pchEaten, &pmk);

if (FAILED(hResult))

goto Error1;

hResult = WrapIMonikerAFromW(pmk, ppmkA);

if (pmk)

pmk->Release();

Error1:

ConvertStringFree(lpszUserName);

Error:

if (pbc)

pbc->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    MonikerRelativePathToA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Returns:    See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI MonikerRelativePathToA(LPMONIKERA pmkSrcA, LPMONIKERA pmkDestA,

LPMONIKERA * ppmkRelPathA, BOOL fCalledFromMethod)

{

TraceSTDAPIEnter("MonikerRelativePathToA");

LPMONIKER pmkSrc;

LPMONIKER pmkDest;

LPMONIKER pmkRelPath;

HRESULT hReturn;

HRESULT hResult;

*ppmkRelPathA = NULL;

hResult = WrapIMonikerWFromA(pmkSrcA, &pmkSrc);

if (FAILED(hResult))

return hResult;

hResult = WrapIMonikerWFromA(pmkDestA, &pmkDest);

if (FAILED(hResult))

goto Error;

hReturn = MonikerRelativePathTo(pmkSrc, pmkDest, &pmkRelPath, fCalledFromMethod);

if (FAILED(hReturn))

goto Error1;

hResult = WrapIMonikerAFromW(pmkRelPath, ppmkRelPathA);

if (pmkRelPath)

pmkRelPath->Release();

Error1:

if (pmkDest)

pmkDest->Release();

Error:

if (pmkSrc)

pmkSrc->Release();

if (FAILED(hResult))

hReturn = hResult;

return hReturn;

}

//+--------------------------------------------------------------------------

//

//  Routine:    MonikerCommonPrefixWithA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Returns:    See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI MonikerCommonPrefixWithA(LPMONIKERA pmkThisA, LPMONIKERA pmkOtherA,

LPMONIKERA * ppmkCommonA)

{

TraceSTDAPIEnter("MonikerCommonPrefixWithA");

LPMONIKER pmkThis;

LPMONIKER pmkOther;

LPMONIKER pmkCommon;

HRESULT hReturn;

HRESULT hResult;

*ppmkCommonA = NULL;

hResult = WrapIMonikerWFromA(pmkThisA, &pmkThis);

if (FAILED(hResult))

return hResult;

hResult = WrapIMonikerWFromA(pmkOtherA, &pmkOther);

if (FAILED(hResult))

goto Error;

hReturn = MonikerCommonPrefixWith(pmkThis, pmkOther, &pmkCommon);

if (FAILED(hReturn))

goto Error1;

hResult = WrapIMonikerAFromW(pmkCommon, ppmkCommonA);

if (pmkCommon)

pmkCommon->Release();

Error1:

if (pmkOther)

pmkOther->Release();

Error:

if (pmkThis)

pmkThis->Release();

if (FAILED(hResult))

hReturn = hResult;

return hReturn;

}

//+--------------------------------------------------------------------------

//

//  Routine:    CreateBindCtxA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Returns:    See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI CreateBindCtxA(DWORD reserved, LPBCA * ppbcA)

{

TraceSTDAPIEnter("CreateBindCtxA");

LPBC pbc;

HRESULT hResult;

*ppbcA = NULL;

hResult = CreateBindCtx(reserved, &pbc);

if (FAILED(hResult))

return hResult;

hResult = WrapIBindCtxAFromW(pbc, ppbcA);

if (pbc)

pbc->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    CreateGenericCompositeA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Returns:    See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI CreateGenericCompositeA(LPMONIKERA pmkFirstA, LPMONIKERA pmkRestA,

LPMONIKERA * ppmkCompositeA)

{

TraceSTDAPIEnter("CreateGenericCompositeA");

LPMONIKER pmkFirst;

LPMONIKER pmkRest;

LPMONIKER pmkComposite;

HRESULT hResult;

*ppmkCompositeA = NULL;

hResult = WrapIMonikerWFromA(pmkFirstA, &pmkFirst);

if (FAILED(hResult))

return hResult;

hResult = WrapIMonikerWFromA(pmkRestA, &pmkRest);

if (FAILED(hResult))

goto Error;

hResult = CreateGenericComposite(pmkFirst, pmkRest, &pmkComposite);

if (FAILED(hResult))

goto Error1;

hResult = WrapIMonikerAFromW(pmkComposite, ppmkCompositeA);

if (pmkComposite)

pmkComposite->Release();

Error1:

if (pmkRest)

pmkRest->Release();

Error:

if (pmkFirst)

pmkFirst->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    GetClassFileA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Returns:    See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI GetClassFileA(LPCSTR szFilenameA, CLSID * pclsid)

{

TraceSTDAPIEnter("GetClassFileA");

LPOLESTR lpszFilename;

HRESULT hResult;

hResult = ConvertStringToW(szFilenameA, &lpszFilename);

if (FAILED(hResult))

return hResult;

hResult = GetClassFile(lpszFilename, pclsid);

ConvertStringFree(lpszFilename);

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    CreateFileMonikerA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Returns:    See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI CreateFileMonikerA(LPSTR lpszPathNameA, LPMONIKERA * ppmkA)

{

TraceSTDAPIEnter("CreateFileMonikerA");

LPOLESTR lpszPathName;

LPMONIKER pmk;

HRESULT hReturn;

HRESULT hResult;

*ppmkA = NULL;

hResult = ConvertStringToW(lpszPathNameA, &lpszPathName);

if (FAILED(hResult))

return hResult;

hReturn = CreateFileMoniker(lpszPathName, &pmk);

if (FAILED(hReturn))

goto Error;

hResult = WrapIMonikerAFromW(pmk, ppmkA);

if (pmk)

pmk->Release();

Error:

ConvertStringFree(lpszPathName);

if (FAILED(hResult))

hReturn = hResult;

return hReturn;

}

//+--------------------------------------------------------------------------

//

//  Routine:    CreateItemMonikerA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Returns:    See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI CreateItemMonikerA(LPSTR lpszDelimA, LPSTR lpszItemA,

LPMONIKERA * ppmkA)

{

TraceSTDAPIEnter("CreateItemMonikerA");

LPOLESTR lpszDelim;

LPOLESTR lpszItem;

LPMONIKER pmk;

HRESULT hResult;

*ppmkA = NULL;

hResult = ConvertStringToW(lpszDelimA, &lpszDelim);

if (FAILED(hResult))

return hResult;

hResult = ConvertStringToW(lpszItemA, &lpszItem);

if (FAILED(hResult))

goto Error;

hResult = CreateItemMoniker(lpszDelim, lpszItem, &pmk);

if (FAILED(hResult))

goto Error1;

hResult = WrapIMonikerAFromW(pmk, ppmkA);

if (pmk)

pmk->Release();

Error1:

ConvertStringFree(lpszItem);

Error:

ConvertStringFree(lpszDelim);

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    CreateAntiMonikerA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Returns:    See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI CreateAntiMonikerA(LPMONIKERA * ppmkA)

{

TraceSTDAPIEnter("CreateAntiMonikerA");

LPMONIKER pmk;

HRESULT hResult;

*ppmkA = NULL;

hResult = CreateAntiMoniker(&pmk);

if (FAILED(hResult))

return hResult;

hResult = WrapIMonikerAFromW(pmk, ppmkA);

if (pmk)

pmk->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    CreatePointerMonikerA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Returns:    See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI CreatePointerMonikerA(LPUNKNOWN punkA, LPMONIKERA * ppmkA)

{

TraceSTDAPIEnter("CreatePointerMonikerA");

LPUNKNOWN punk;

LPMONIKER pmk;

HRESULT hResult;

*ppmkA = NULL;

hResult = WrapIUnknownWFromA(punkA, &punk);

if (FAILED(hResult))

return hResult;

hResult = CreatePointerMoniker(punk, &pmk);

if (FAILED(hResult))

goto Error;

hResult = WrapIMonikerAFromW(pmk, ppmkA);

if (pmk)

pmk->Release();

Error:

punk->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    GetRunningObjectTableA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Returns:    See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI GetRunningObjectTableA(DWORD reserved, LPRUNNINGOBJECTTABLEA * pprotA)

{

TraceSTDAPIEnter("GetRunningObjectTableA");

LPRUNNINGOBJECTTABLE prot;

HRESULT hResult;

*pprotA = NULL;

hResult = GetRunningObjectTable(reserved, &prot);

if (FAILED(hResult))

return hResult;

hResult = WrapIRunningObjectTableAFromW(prot, pprotA);

if (prot)

prot->Release();

return hResult;

}


 ANSIOA.CPP  (OLEANSI Sample)

//+--------------------------------------------------------------------------

//

//  Copyright (C) 1994, Microsoft Corporation.  All Rights Reserved.

//  Information Contained Herein Is Proprietary and Confidential.

//

//  File:       ansioa.cpp

//

//  Contents:   ANSI version of OLE Automation APIs.

//              See OLE2 docs for details of Unicode equalivent APIs.

//

//  Functions:  SysAllocStringA

//              SysAllocStringLenA

//              SysStringLenA

//              SysReAllocStringA

//              SysReAllocStringLenA

//              SysFreeStringA

//

//              SafeArrayAllocDescriptorA

//              SafeArrayAllocDataA

//              SafeArrayCreateA

//              SafeArrayDestroyDescriptorA

//              SafeArrayDestroyDataA

//              SafeArrayDestroyA

//              SafeArrayRedimA

//              SafeArrayGetDimA

//              SafeArrayGetElemsizeA

//              SafeArrayGetUBoundA

//              SafeArrayGetLBoundA

//              SafeArrayLockA

//              SafeArrayUnlockA

//              SafeArrayAccessDataA

//              SafeArrayUnaccessDataA

//              SafeArrayGetElement

//              SafeArrayPutElementA

//              SafeArrayCopyA

//

//              VariantInitA

//              VariantClearA

//              VariantCopyA

//              VariantCopyIndA

//              VariantChangeTypeA

//              VariantChangeTypeExA

//

//              VarUI1FromStrA

//              VarUI1FromDispA

//              VarI2FromStrA

//              VarI2FromDispA

//              VarI4FromStrA

//              VarI4FromDispA

//              VarR4FromStrA

//              VarR4FromDispA

//              VarR8FromStrA

//              VarR8FromDispA

//              VarDateFromStrA

//              VarDateFromDispA

//              VarCyFromStrA

//              VarCyFromDispA

//              VarBstrFromUI1A

//              VarBstrFromI2A

//              VarBstrFromI4A

//              VarBstrFromR4A

//              VarBstrFromR8A

//              VarBstrFromCyA

//              VarBstrFromDateA

//              VarBstrFromDispA

//              VarBstrFromBoolA

//              VarBoolFromStrA

//              VarBoolFromDispA

//

//              LHashValOfNameSysA

//              LoadTypeLibA

//              LoadRegTypeLibA

//              QueryPathOfRegTypeLibA

//              RegisterTypeLibA

//              CreateTypeLibA

//

//              DispGetParamA

//              DispGetIDsOfNamesA

//              DispInvokeA

//              CreateDispTypeInfoA

//              CreateStdDispatchA

//

//  History:    12-Jan-94   tomteng     Created.

//

//---------------------------------------------------------------------------

#include "Ole2Ansi.h"

extern "C" int __cdecl _fltused = 1; // avoid dragging in C-runtime

/*---------------------------------------------------------------------*/

/*                         ANSI BSTR API                               */

/*---------------------------------------------------------------------*/

STDAPI_(BSTRA) SysAllocStringA(const char * psz)

{

TraceSTDAPIEnter("SysAllocStringA");

if (psz == NULL)

return NULL;

return (BSTRA)SysAllocStringByteLen(psz, lstrlen(psz));

}

STDAPI_(BSTRA) SysAllocStringLenA(const char * psz, unsigned int len)

{

TraceSTDAPIEnter("SysAllocStringLenA");

BSTRA bstr = (BSTRA)SysAllocStringByteLen(psz, len);

return bstr;

}

STDAPI_(int) SysReAllocStringA(BSTRA * pbstr, const char * psz)

{

TraceSTDAPIEnter("SysReAllocStringA");

return SysReAllocStringLenA(pbstr, psz, (psz ? lstrlen(psz) : 0));

}

STDAPI_(int) SysReAllocStringLenA(BSTRA * pbstr, const char * psz, unsigned int len)

{

TraceSTDAPIEnter("SysReAllocStringLenA");

BSTRA bstrNew = (BSTRA) SysAllocStringLenA(psz, len);

if (bstrNew == NULL)

return FALSE;

SysFreeString((BSTR) *pbstr);

*pbstr = bstrNew;

return TRUE;

}

STDAPI_(unsigned int) SysStringLenA(BSTRA bstr)

{

TraceSTDAPIEnter("int");

return SysStringByteLen((BSTR)bstr);

}

STDAPI_(void) SysFreeStringA(BSTRA bstr)

{

TraceSTDAPIEnter("SysFreeStringA");

SysFreeString((BSTR)bstr);

}

/*---------------------------------------------------------------------*/

/*                         ANSI SafeArray API                          */

/*---------------------------------------------------------------------*/

STDAPI SafeArrayAllocDescriptorA(unsigned int cDims, SAFEARRAYA * * ppsaOut)

{

TraceSTDAPIEnter("SafeArrayAllocDescriptorA");

return (SafeArrayAllocDescriptor(cDims, (SAFEARRAY * *) ppsaOut));

}

STDAPI SafeArrayAllocDataA(SAFEARRAYA * psa)

{

TraceSTDAPIEnter("SafeArrayAllocDataA");

return (SafeArrayAllocData((SAFEARRAY *) psa));

}

STDAPI_(SAFEARRAYA *) SafeArrayCreateA(

VARTYPE vt,

unsigned int cDims,

SAFEARRAYBOUND * rgsabound)

{

TraceSTDAPIEnter("SafeArrayCreateA");

return ((SAFEARRAYA *) SafeArrayCreate(vt, cDims, rgsabound));

}

STDAPI SafeArrayDestroyDescriptorA(SAFEARRAYA * psa)

{

TraceSTDAPIEnter("SafeArrayDestroyDescriptorA");

return (SafeArrayDestroyDescriptor((SAFEARRAY *) psa));

}

STDAPI SafeArrayDestroyDataA(SAFEARRAYA * psa)

{

TraceSTDAPIEnter("SafeArrayDestroyDataA");

return (SafeArrayDestroyData((SAFEARRAY *) psa));

}

STDAPI SafeArrayDestroyA(SAFEARRAYA * psa)

{

TraceSTDAPIEnter("SafeArrayDestroyA");

  return (SafeArrayDestroy((SAFEARRAY *) psa));

}

STDAPI SafeArrayRedimA(SAFEARRAYA * psa, SAFEARRAYBOUND * psaboundNew)

{

TraceSTDAPIEnter("SafeArrayRedimA");

return (SafeArrayRedim((SAFEARRAY *) psa, psaboundNew));

}

STDAPI_(UINT) SafeArrayGetDimA(SAFEARRAYA * psa)

{

TraceSTDAPIEnter("SafeArrayGetDimA");

return (SafeArrayGetDim((SAFEARRAY *) psa));

}

STDAPI_(UINT) SafeArrayGetElemsizeA(SAFEARRAYA * psa)

{

TraceSTDAPIEnter("SafeArrayGetElemsizeA");

return (SafeArrayGetElemsize((SAFEARRAY *) psa));

}

STDAPI SafeArrayGetUBoundA(

SAFEARRAYA * psa,

UINT nDim,

long * plUbound)

{

TraceSTDAPIEnter("SafeArrayGetUBoundA");

return (SafeArrayGetUBound((SAFEARRAY *) psa, nDim, plUbound));

}

STDAPI SafeArrayGetLBoundA(

SAFEARRAYA * psa,

UINT nDim,

long * plLbound)

{

TraceSTDAPIEnter("SafeArrayGetLBoundA");

return (SafeArrayGetLBound((SAFEARRAY *) psa, nDim, plLbound));

}

STDAPI SafeArrayLockA(SAFEARRAYA * psa)

{

TraceSTDAPIEnter("SafeArrayLockA");

return (SafeArrayLock((SAFEARRAY *) psa));

}

STDAPI SafeArrayUnlockA(SAFEARRAYA * psa)

{

TraceSTDAPIEnter("SafeArrayUnlockA");

return (SafeArrayUnlock((SAFEARRAY *) psa));

}

STDAPI SafeArrayAccessDataA(SAFEARRAYA * psa, void HUGEP* * ppvData)

{

TraceSTDAPIEnter("SafeArrayAccessDataA");

return (SafeArrayAccessData((SAFEARRAY *) psa, ppvData));

}

STDAPI SafeArrayUnaccessDataA(SAFEARRAYA * psa)

{

TraceSTDAPIEnter("SafeArrayUnaccessDataA");

return (SafeArrayUnaccessData((SAFEARRAY *) psa));

}

STDAPI SafeArrayGetElementA(

SAFEARRAYA * psa,

long * rgIndices,

void * pv)

{

TraceSTDAPIEnter("SafeArrayGetElementA");

return (SafeArrayGetElement((SAFEARRAY *) psa, rgIndices, pv));

}

STDAPI SafeArrayPutElementA(

SAFEARRAYA * psa,

long * rgIndices,

void * pv)

{

TraceSTDAPIEnter("SafeArrayPutElementA");

return (SafeArrayPutElement((SAFEARRAY *) psa, rgIndices, pv));

}

STDAPI SafeArrayCopyA(

SAFEARRAYA * psa,

SAFEARRAYA * * ppsaOut)

{

TraceSTDAPIEnter("SafeArrayCopyA");

return (SafeArrayCopy((SAFEARRAY *) psa, (SAFEARRAY * *) ppsaOut));

}

/*---------------------------------------------------------------------*/

/*                         ANSI VARIANT API                            */

/*---------------------------------------------------------------------*/

STDAPI_(void) VariantInitA(VARIANTARGA * pvarg)

{

TraceSTDAPIEnter("VariantInitA");

VariantInit((VARIANTARG *)  pvarg);

}

STDAPI VariantClearA(VARIANTARGA * pvarg)

{

TraceSTDAPIEnter("VariantClearA");

return VariantClear((VARIANTARG *) pvarg);

}

STDAPI VariantCopyA(

VARIANTARGA * pvargDest,

VARIANTARGA * pvargSrc)

{

TraceSTDAPIEnter("VariantCopyA");

return VariantCopy((VARIANTARG *) pvargDest, (VARIANTARG *) pvargSrc);

}

STDAPI VariantCopyIndA(

VARIANTA * pvargDest,

VARIANTARGA * pvargSrc)

{

TraceSTDAPIEnter("VariantCopyIndA");

return VariantCopyInd((VARIANT *) pvargDest, (VARIANTARG *) pvargSrc);

}

STDAPI VariantChangeTypeA(

VARIANTARGA * pvargDestA,

VARIANTARGA * pvargSrcA,

unsigned short wFlags,

VARTYPE vt)

{

TraceSTDAPIEnter("VariantChangeTypeA");

HRESULT hResult;

VARIANT varTempW;

// CONSIDER: optimize this for the case of simple Variants (src, dest,

// CONSIDER: and vt all non-string, non-array, non-object variants)

VariantInit(&varTempW);

hResult = VariantCopy((VARIANT *) &varTempW, (VARIANTARG *) pvargSrcA);

if (hResult == NOERROR)

{

hResult = ConvertVariantToW(&varTempW);

if (hResult == NOERROR)

{

  hResult = VariantChangeType(&varTempW, &varTempW, wFlags, vt);

if (hResult == NOERROR)

{

hResult = ConvertVariantToA((VARIANTA *)&varTempW);

if (hResult == NOERROR)

hResult = VariantCopy((VARIANT *)pvargDestA, &varTempW);

}

}

}

VariantClear(&varTempW);

return hResult;

}

STDAPI VariantChangeTypeExA(

VARIANTARGA * pvargDestA,

VARIANTARGA * pvargSrcA,

LCID lcid,

unsigned short wFlags,

VARTYPE vt)

{

TraceSTDAPIEnter("VariantChangeTypeExA");

HRESULT hResult;

VARIANT varTempW;

// CONSIDER: optimize this for the case of simple Variants (src, dest,

// CONSIDER: and vt all non-string, non-array, non-object variants)

VariantInit(&varTempW);

hResult = VariantCopy((VARIANT *) &varTempW, (VARIANTARG *) pvargSrcA);

if (hResult == NOERROR)

{

hResult = ConvertVariantToW(&varTempW);

if (hResult == NOERROR)

{

hResult = VariantChangeTypeEx(&varTempW, &varTempW, lcid, wFlags, vt);

if (hResult == NOERROR)

{

hResult = ConvertVariantToA((VARIANTA *)&varTempW);

if (hResult == NOERROR)

hResult = VariantCopy((VARIANT *)pvargDestA, &varTempW);

}

}

}

VariantClear(&varTempW);

return hResult;

}

/*---------------------------------------------------------------------*/

/*                   ANSI VARIANT Coercion API                         */

/*---------------------------------------------------------------------*/

#ifndef NOI1

STDAPI VarUI1FromStrA(char * strIn, LCID lcid,

  unsigned long dwFlags, unsigned char * pbOut)

{

TraceSTDAPIEnter("VarUI1FromStrA");

LPOLESTR   lpwStrIn;

HRESULT    hResult;

hResult = ConvertStringToW(strIn, &lpwStrIn);

if (FAILED(hResult))

return (hResult);

hResult = VarUI1FromStr(lpwStrIn, lcid, dwFlags, pbOut);

ConvertStringFree(lpwStrIn);

return hResult;

}

STDAPI VarUI1FromDispA(IDispatchA * pdispIn, LCID lcid, unsigned char * pbOut)

{

TraceSTDAPIEnter("VarUI1FromDispA");

HRESULT    hResult;

IDispatch* pDisp;

hResult = WrapIDispatchWFromA(pdispIn, &pDisp);

if (FAILED(hResult))

return (hResult);

hResult = VarUI1FromDisp(pDisp, lcid, pbOut);

pDisp->Release();

return hResult;

}

#endif //!NOI1

STDAPI VarI2FromStrA(char * strIn, LCID lcid,

  unsigned long dwFlags, short * psOut)

{

TraceSTDAPIEnter("VarI2FromStrA");

LPOLESTR   lpwStrIn;

HRESULT    hResult;

hResult = ConvertStringToW(strIn, &lpwStrIn);

if (FAILED(hResult))

return (hResult);

hResult = VarI2FromStr(lpwStrIn, lcid, dwFlags, psOut);

ConvertStringFree(lpwStrIn);

return hResult;

}

STDAPI VarI2FromDispA(IDispatchA * pdispIn, LCID lcid, short * psOut)

{

TraceSTDAPIEnter("VarI2FromDispA");

HRESULT    hResult;

IDispatch* pDisp;

hResult = WrapIDispatchWFromA(pdispIn, &pDisp);

if (FAILED(hResult))

return (hResult);

hResult = VarI2FromDisp(pDisp, lcid, psOut);

pDisp->Release();

return hResult;

}

STDAPI VarI4FromStrA(char * strIn, LCID lcid,

  unsigned long dwFlags, long * plOut)

{

TraceSTDAPIEnter("VarI4FromStrA");

LPOLESTR   lpwStrIn;

HRESULT    hResult;

hResult = ConvertStringToW(strIn, &lpwStrIn);

if (FAILED(hResult))

return (hResult);

hResult = VarI4FromStr(lpwStrIn, lcid, dwFlags, plOut);

ConvertStringFree(lpwStrIn);

return hResult;

}

STDAPI VarI4FromDispA(IDispatchA * pdispIn, LCID lcid, long * plOut)

{

TraceSTDAPIEnter("VarI4FromDispA");

HRESULT    hResult;

IDispatch* pDisp;

hResult = WrapIDispatchWFromA(pdispIn, &pDisp);

if (FAILED(hResult))

return (hResult);

hResult = VarI4FromDisp(pDisp, lcid, plOut);

pDisp->Release();

return hResult;

}

STDAPI VarR4FromStrA(char * strIn, LCID lcid,

 unsigned long dwFlags, float * pfltOut)

{

TraceSTDAPIEnter("VarR4FromStrA");

LPOLESTR   lpwStrIn;

HRESULT    hResult;

hResult = ConvertStringToW(strIn, &lpwStrIn);

if (FAILED(hResult))

return (hResult);

hResult = VarR4FromStr(lpwStrIn, lcid, dwFlags, pfltOut);

ConvertStringFree(lpwStrIn);

return hResult;

}

STDAPI VarR4FromDispA(IDispatchA * pdispIn, LCID lcid, float * pfltOut)

{

TraceSTDAPIEnter("VarR4FromDispA");

HRESULT    hResult;

IDispatch* pDisp;

hResult = WrapIDispatchWFromA(pdispIn, &pDisp);

if (FAILED(hResult))

return (hResult);

hResult = VarR4FromDisp(pDisp, lcid, pfltOut);

pDisp->Release();

return hResult;

}

STDAPI VarR8FromStrA(char * strIn, LCID lcid,

  unsigned long dwFlags, double * pdblOut)

{

TraceSTDAPIEnter("VarR8FromStrA");

LPOLESTR   lpwStrIn;

HRESULT    hResult;

hResult = ConvertStringToW(strIn, &lpwStrIn);

if (FAILED(hResult))

return (hResult);

hResult = VarR8FromStr(lpwStrIn, lcid, dwFlags, pdblOut);

ConvertStringFree(lpwStrIn);

return hResult;

}

STDAPI VarR8FromDispA(IDispatchA * pdispIn, LCID lcid, double * pdblOut)

{

TraceSTDAPIEnter("VarR8FromDispA");

HRESULT    hResult;

IDispatch* pDisp;

hResult = WrapIDispatchWFromA(pdispIn, &pDisp);

if (FAILED(hResult))

return (hResult);

hResult = VarR8FromDisp(pDisp, lcid, pdblOut);

pDisp->Release();

return hResult;

}

STDAPI VarDateFromStrA(char * strIn, LCID lcid,

unsigned long dwFlags, DATE * pdateOut)

{

TraceSTDAPIEnter("VarDateFromStrA");

LPOLESTR   lpwStrIn;

HRESULT    hResult;

hResult = ConvertStringToW(strIn, &lpwStrIn);

if (FAILED(hResult))

return (hResult);

hResult = VarDateFromStr(lpwStrIn, lcid, dwFlags, pdateOut);

ConvertStringFree(lpwStrIn);

return hResult;

}

STDAPI VarDateFromDispA(IDispatchA * pdispIn, LCID lcid, DATE * pdateOut)

{

TraceSTDAPIEnter("VarDateFromDispA");

HRESULT    hResult;

IDispatch* pDisp;

hResult = WrapIDispatchWFromA(pdispIn, &pDisp);

if (FAILED(hResult))

return (hResult);

hResult = VarDateFromDisp(pDisp, lcid, pdateOut);

pDisp->Release();

return hResult;

}

STDAPI VarCyFromStrA(char * strIn, LCID lcid,

  unsigned long dwFlags, CY * pcyOut)

{

TraceSTDAPIEnter("VarCyFromStrA");

LPOLESTR   lpwStrIn;

HRESULT    hResult;

hResult = ConvertStringToW(strIn, &lpwStrIn);

if (FAILED(hResult))

return (hResult);

hResult = VarCyFromStr(lpwStrIn, lcid, dwFlags, pcyOut);

ConvertStringFree(lpwStrIn);

return hResult;

}

STDAPI VarCyFromDispA(IDispatchA * pdispIn, LCID lcid, CY * pcyOut)

{

TraceSTDAPIEnter("VarCyFromDispA");

HRESULT    hResult;

IDispatch* pDisp;

hResult = WrapIDispatchWFromA(pdispIn, &pDisp);

if (FAILED(hResult))

return (hResult);

hResult = VarCyFromDisp(pDisp, lcid, pcyOut);

pDisp->Release();

return hResult;

}

#ifndef NOI1

STDAPI VarBstrFromUI1A(unsigned char bVal, LCID lcid,

   unsigned long dwFlags, BSTRA * pbstrOut)

{

TraceSTDAPIEnter("VarBstrFromUI1A");

HRESULT    hResult;

BSTR       bstr;

hResult = VarBstrFromUI1(bVal, lcid, dwFlags, &bstr);

if (FAILED(hResult))

return (hResult);

hResult = ConvertDispStringToA(bstr, pbstrOut);

SysFreeString(bstr);

return hResult;

}

#endif //!NOI1

STDAPI VarBstrFromI2A(short iVal, LCID lcid,

   unsigned long dwFlags, BSTRA * pbstrOut)

{

TraceSTDAPIEnter("VarBstrFromI2A");

HRESULT    hResult;

BSTR       bstr;

hResult = VarBstrFromI2(iVal, lcid, dwFlags, &bstr);

if (FAILED(hResult))

return (hResult);

hResult = ConvertDispStringToA(bstr, pbstrOut);

SysFreeString(bstr);

return hResult;

}

STDAPI VarBstrFromI4A(long lIn, LCID lcid,

   unsigned long dwFlags, BSTRA * pbstrOut)

{

TraceSTDAPIEnter("VarBstrFromI4A");

HRESULT    hResult;

BSTR       bstr;

hResult = VarBstrFromI4(lIn, lcid, dwFlags, &bstr);

if (FAILED(hResult))

return (hResult);

hResult = ConvertDispStringToA(bstr, pbstrOut);

SysFreeString(bstr);

return hResult;

}

STDAPI VarBstrFromR4A(float fltIn, LCID lcid,

   unsigned long dwFlags, BSTRA * pbstrOut)

{

TraceSTDAPIEnter("VarBstrFromR4A");

HRESULT    hResult;

BSTR       bstr;

hResult = VarBstrFromR4(fltIn, lcid, dwFlags, &bstr);

if (FAILED(hResult))

return (hResult);

hResult = ConvertDispStringToA(bstr, pbstrOut);

SysFreeString(bstr);

return hResult;

}

STDAPI VarBstrFromR8A(double dblIn, LCID lcid,

   unsigned long dwFlags, BSTRA * pbstrOut)

{

TraceSTDAPIEnter("VarBstrFromR8A");

HRESULT    hResult;

BSTR       bstr;

hResult = VarBstrFromR8(dblIn, lcid, dwFlags, &bstr);

if (FAILED(hResult))

return (hResult);

hResult = ConvertDispStringToA(bstr, pbstrOut);

SysFreeString(bstr);

return hResult;

}

STDAPI VarBstrFromCyA(CY cyIn, LCID lcid,

  unsigned long dwFlags, BSTRA * pbstrOut)

{

TraceSTDAPIEnter("VarBstrFromCyA");

HRESULT    hResult;

BSTR       bstr;

hResult = VarBstrFromCy(cyIn, lcid, dwFlags, &bstr);

if (FAILED(hResult))

return (hResult);

hResult = ConvertDispStringToA(bstr, pbstrOut);

SysFreeString(bstr);

return hResult;

}

STDAPI VarBstrFromDateA(DATE dateIn, LCID lcid,

 unsigned long dwFlags, BSTRA * pbstrOut)

{

TraceSTDAPIEnter("VarBstrFromDateA");

HRESULT    hResult;

BSTR       bstr;

hResult = VarBstrFromDate(dateIn, lcid, dwFlags, &bstr);

if (FAILED(hResult))

return (hResult);

hResult = ConvertDispStringToA(bstr, pbstrOut);

SysFreeString(bstr);

return hResult;

}

STDAPI VarBstrFromDispA(IDispatchA * pdispIn, LCID lcid,

 unsigned long dwFlags, BSTRA * pbstrOut)

{

TraceSTDAPIEnter("VarBstrFromDispA");

HRESULT    hResult;

BSTR       bstr;

IDispatch* pDisp;

hResult = WrapIDispatchWFromA(pdispIn, &pDisp);

if (FAILED(hResult))

return (hResult);

hResult = VarBstrFromDisp(pDisp, lcid, dwFlags, &bstr);

if (FAILED(hResult))

return (hResult);

pDisp->Release();

hResult = ConvertDispStringToA(bstr, pbstrOut);

SysFreeString(bstr);

return hResult;

}

STDAPI VarBstrFromBoolA(VARIANT_BOOL boolIn, LCID lcid,

 unsigned long dwFlags, BSTRA * pbstrOut)

{

TraceSTDAPIEnter("VarBstrFromBoolA");

HRESULT    hResult;

BSTR       bstr;

hResult = VarBstrFromBool(boolIn, lcid, dwFlags, &bstr);

if (FAILED(hResult))

return (hResult);

hResult = ConvertDispStringToA(bstr, pbstrOut);

SysFreeString(bstr);

return hResult;

}

STDAPI VarBoolFromStrA(char * strIn, LCID lcid,

unsigned long dwFlags, VARIANT_BOOL * pboolOut)

{

TraceSTDAPIEnter("VarBoolFromStrA");

LPOLESTR   lpwStrIn;

HRESULT    hResult;

hResult = ConvertStringToW(strIn, &lpwStrIn);

if (FAILED(hResult))

return (hResult);

hResult = VarBoolFromStr(lpwStrIn, lcid, dwFlags, pboolOut);

ConvertStringFree(lpwStrIn);

return hResult;

}

STDAPI VarBoolFromDispA(IDispatchA * pdispIn, LCID lcid,

 VARIANT_BOOL * pboolOut)

{

TraceSTDAPIEnter("VarBoolFromDispA");

HRESULT    hResult;

IDispatch* pDisp;

hResult = WrapIDispatchWFromA(pdispIn, &pDisp);

if (FAILED(hResult))

return (hResult);

hResult = VarBoolFromDisp(pDisp, lcid, pboolOut);

pDisp->Release();

return hResult;

}

/*---------------------------------------------------------------------*/

/*                         ANSI Typelib API                            */

/*---------------------------------------------------------------------*/

STDAPI LoadTypeLibA(const char * szFileA, ITypeLibA * * pptlib)

{

TraceSTDAPIEnter("LoadTypeLibA");

LPOLESTR   lpszFile;

LPTYPELIB  pTypeLib;

HRESULT    hResult;

hResult = ConvertStringToW(szFileA, &lpszFile);

if (FAILED(hResult))

return (hResult);

hResult = LoadTypeLib(lpszFile, &pTypeLib);

if (FAILED(hResult))

goto Error;

hResult = WrapITypeLibAFromW(pTypeLib, pptlib);

pTypeLib->Release();

Error:

ConvertStringFree(lpszFile);

return hResult;

}

STDAPI LoadRegTypeLibA(REFGUID rguid, unsigned short wVerMajor,

unsigned short wVerMinor, LCID lcid, ITypeLibA * * pptlibA)

{

TraceSTDAPIEnter("LoadRegTypeLibA");

LPTYPELIB  pTypeLib;

HRESULT    hResult;

hResult = LoadRegTypeLib(rguid, wVerMajor, wVerMinor, lcid, &pTypeLib);

if (FAILED(hResult))

return (hResult);

hResult = WrapITypeLibAFromW(pTypeLib, pptlibA);

pTypeLib->Release();

return hResult;

}

STDAPI QueryPathOfRegTypeLibA(REFGUID guid, unsigned short wMaj,

unsigned short wMin, LCID lcid, LPBSTRA lpbstrPathNameA)

{

TraceSTDAPIEnter("QueryPathOfRegTypeLibA");

BSTR       bstrPathName;

HRESULT    hResult;

hResult = QueryPathOfRegTypeLib(guid, wMaj, wMin, lcid,

&bstrPathName);

if (FAILED(hResult))

return (hResult);

hResult = ConvertDispStringToA(bstrPathName, lpbstrPathNameA);

SysFreeString(bstrPathName);

return hResult;

}

STDAPI RegisterTypeLibA(ITypeLibA * ptlibA, char * szFullPathA,

char * szHelpDirA)

{

TraceSTDAPIEnter("RegisterTypeLibA");

LPTYPELIB pTypeLib;

LPOLESTR  lpszFullPath;

LPOLESTR  lpszHelpDir;

HRESULT   hResult;

hResult = WrapITypeLibWFromA(ptlibA, &pTypeLib);

if (FAILED(hResult))

return (hResult);

hResult = ConvertStringToW(szFullPathA, &lpszFullPath);

if (FAILED(hResult))

goto Error;

hResult = ConvertStringToW(szHelpDirA, &lpszHelpDir);

if (FAILED(hResult))

goto Error1;

hResult = RegisterTypeLib(pTypeLib, lpszFullPath, lpszHelpDir);

ConvertStringFree(lpszHelpDir);

Error1:

ConvertStringFree(lpszFullPath);

Error:

pTypeLib->Release();

return hResult;

}

STDAPI CreateTypeLibA(SYSKIND syskind, const char * szFileA,

ICreateTypeLibA * * ppctlibA)

{

TraceSTDAPIEnter("CreateTypeLibA");

LPOLESTR         lpszFile;

LPCREATETYPELIB  pCreateTypeLib;

HRESULT          hResult;

hResult = ConvertStringToW(szFileA, &lpszFile);

if (FAILED(hResult))

return (hResult);

hResult = CreateTypeLib(syskind, lpszFile, &pCreateTypeLib);

if (FAILED(hResult))

goto Error;

hResult = WrapICreateTypeLibAFromW(pCreateTypeLib, ppctlibA);

pCreateTypeLib->Release();

Error:

ConvertStringFree(lpszFile);

return hResult;

}

STDAPI_(unsigned long) LHashValOfNameSysHACK(SYSKIND syskind, LCID lcid, const char FAR* szName)

{

TraceSTDAPIEnter("LHashValOfNameSysHACK");

return LHashValOfNameSysA(syskind, lcid, szName);

}

/*---------------------------------------------------------------------*/

/*                         ANSI Dispatch API                           */

/*---------------------------------------------------------------------*/

STDAPI DispGetParamA(DISPPARAMSA * pdispparamsA, UINT position,

VARTYPE vtTarg, VARIANTA * pvarResult, UINT * puArgErr)

{

TraceSTDAPIEnter("DispGetParamA");

LPDISPPARAMS pDispParams;

LPVARIANT    pByrefTemp;

HRESULT hResult;

hResult = ConvertDispParamsToW(pdispparamsA, &pDispParams, &pByrefTemp);

if (FAILED(hResult))

return hResult;

hResult = DispGetParam(pDispParams, position, vtTarg,

  (LPVARIANT)pvarResult, puArgErr);

if (FAILED(hResult))

goto Error;

hResult = ConvertVariantToA(pvarResult);

Error:

ConvertDispParamsFree(pDispParams, pByrefTemp);

return hResult;

}

STDAPI DispGetIDsOfNamesA(ITypeInfoA * ptinfoA, char * * rgszNamesA,

UINT cNames, DISPID * rgdispid)

{

TraceSTDAPIEnter("DispGetIDsOfNamesA");

LPTYPEINFO pTypeInfo;

LPOLESTR * rgszNames;

HRESULT    hResult;

hResult = WrapITypeInfoWFromA(ptinfoA, &pTypeInfo);

if (FAILED(hResult))

return (hResult);

hResult = ConvertStringArrayToW(rgszNamesA, &rgszNames, cNames);

if (FAILED(hResult))

goto Error;

hResult = DispGetIDsOfNames(pTypeInfo, rgszNames, cNames, rgdispid);

ConvertStringArrayFree(rgszNames, cNames);

Error:

pTypeInfo->Release();

return hResult;

}

STDAPI DispInvokeA(void * _this, ITypeInfoA * ptinfoA, DISPID dispidMember,

unsigned short wFlags, DISPPARAMSA * pparamsA, VARIANTA * pvarResultA,

EXCEPINFOA * pexcepinfoA, UINT * puArgErr)

{

TraceSTDAPIEnter("DispInvokeA");

LPTYPEINFO   pTypeInfo;

LPDISPPARAMS pDispParams;

LPVARIANT    pByrefTemp;

HRESULT      hResult;

hResult = WrapITypeInfoWFromA(ptinfoA, &pTypeInfo);

if (FAILED(hResult))

return (hResult);

hResult = ConvertDispParamsToW(pparamsA, &pDispParams, &pByrefTemp);

if (FAILED(hResult))

goto Error;

hResult = DispInvoke(_this, pTypeInfo, dispidMember, wFlags, pDispParams,

 (LPVARIANT)pvarResultA, (EXCEPINFO *)pexcepinfoA, puArgErr);

        if (hResult == DISP_E_EXCEPTION)

            ConvertExcepInfoToA(pexcepinfoA);

if (FAILED(hResult))

goto Error1;

if (pByrefTemp)

{

hResult = ConvertDispParamsCopyBack(pparamsA, pByrefTemp);

if (FAILED(hResult))

goto Error1;

}

hResult = ConvertVariantToA(pvarResultA);

Error1:

ConvertDispParamsFree(pDispParams, pByrefTemp);

Error:

pTypeInfo->Release();

return hResult;

}

STDAPI CreateDispTypeInfoA(INTERFACEDATAA * pidataA, LCID lcid,

ITypeInfoA * * pptinfoA)

{

TraceSTDAPIEnter("CreateDispTypeInfoA");

INTERFACEDATA * pData;

LPTYPEINFO  pTypeInfo;

HRESULT    hResult;

hResult = ConvertInterfaceDataToW(pidataA, lcid, &pData);

if (FAILED(hResult))

return (hResult);

hResult = CreateDispTypeInfo(pData, lcid, &pTypeInfo);

if (FAILED(hResult))

goto Error;

hResult = WrapITypeInfoAFromW(pTypeInfo, pptinfoA);

pTypeInfo->Release();

if (FAILED(hResult))

goto Error;

//

//  Save the Unicode InterfaceData structure in the TypeInfo wrapper,

//  to be delete on pTypeInfo is released.

//

((CInterface *)*pptinfoA)->SetInterfaceData(pData);

return hResult;

Error:

ConvertInterfaceDataFree(pData);

return hResult;

}

STDAPI CreateStdDispatchA(IUnknown * punkOuterA, void * pvThis,

ITypeInfoA * ptinfoA, IUnknown * * ppunkStdDisp)

{

TraceSTDAPIEnter("CreateStdDispatchA");

LPTYPEINFO pTypeInfo;

LPUNKNOWN  punkDisp;

IDispatch* pDispatch;

LPINTERFACEDATA pidata;

HRESULT    hResult;

hResult = WrapITypeInfoWFromA(ptinfoA, &pTypeInfo);

if (FAILED(hResult))

return hResult;

hResult = CreateStdDispatch(punkOuterA, pvThis, pTypeInfo,

&punkDisp);

if (FAILED(hResult))

goto Error;

punkDisp->QueryInterface( IID_IDispatch, (LPVOID *)&pDispatch );

punkDisp->Release();

if (FAILED(hResult))

goto Error;

hResult = WrapIDispatchAFromW(pDispatch, (IDispatchA **)ppunkStdDisp);

pDispatch->Release();

if (FAILED(hResult))

goto Error;

//

//  Move any interface data from the TypeInto to the Dispatch wrapper.

//  This solves the problem of the TypeInfo wrapper being deleted

//  before the Dispatch wrapper.

//

pidata = ((CInterface *)ptinfoA)->GetInterfaceData();

((CInterface *)ptinfoA)->SetInterfaceData(0);

((CInterface *)*ppunkStdDisp)->SetInterfaceData(pidata);

Error:

pTypeInfo->Release();

return hResult;

}

/*---------------------------------------------------------------------*/

/*                    Active Object Registration API                   */

/*---------------------------------------------------------------------*/

STDAPI RegisterActiveObjectA(IUnknown * punkA, REFCLSID rclsid,

unsigned long dwFlags, unsigned long * pdwRegister)

{

TraceSTDAPIEnter("RegisterActiveObjectA");

LPUNKNOWN pUnk;

HRESULT hResult;

hResult = WrapIUnknownWFromA(punkA, &pUnk);

if (FAILED(hResult))

return hResult;

hResult = RegisterActiveObject(pUnk, rclsid, dwFlags, pdwRegister);

pUnk->Release();

return hResult;

}

STDAPI GetActiveObjectA(REFCLSID rclsid, void * pvReserved,

IUnknown * FAR* ppunkA)

{

TraceSTDAPIEnter("GetActiveObjectA");

LPUNKNOWN pUnk;

HRESULT hResult;

hResult = GetActiveObject(rclsid, pvReserved, &pUnk);

if (FAILED(hResult))

return hResult;

hResult = WrapIUnknownAFromW(pUnk, ppunkA);

pUnk->Release();

return hResult;

}

// only required for Chicago support, since Chicago doesn't support forwarders

// but available on all platforms

STDAPI DispGetIDsOfNamesX(ITypeInfo * ptinfo, OLECHAR * * rgszNames,

UINT cNames, DISPID * rgdispid)

{

return DispGetIDsOfNames(ptinfo, rgszNames, cNames, rgdispid);

}

STDAPI LoadTypeLibX(OLECHAR * szFile, ITypeLib * * pptlib)

{

return LoadTypeLib(szFile, pptlib);

}

STDAPI RegisterTypeLibX(ITypeLib * ptlib, OLECHAR * szFullPath,

OLECHAR * szHelpDir)

{

return RegisterTypeLib(ptlib, szFullPath, szHelpDir);

}

STDAPI VariantChangeTypeX(

VARIANTARG * pvargDest,

VARIANTARG * pvargSrc,

unsigned short wFlags,

VARTYPE vt)

{

return VariantChangeType(pvargDest, pvargSrc, wFlags, vt);

}

STDAPI_(unsigned long) LHashValOfNameSysX(SYSKIND syskind, LCID lcid, const OLECHAR * szName)

{

return LHashValOfNameSys(syskind, lcid, szName);

}

STDAPI DispInvokeX(void * _this, ITypeInfo * ptinfo, DISPID dispidMember,

unsigned short wFlags, DISPPARAMS * pparams, VARIANT * pvarResult,

EXCEPINFO * pexcepinfo, UINT * puArgErr)

{

return DispInvoke(_this, ptinfo, dispidMember, wFlags, pparams, pvarResult, pexcepinfo, puArgErr);

}

STDAPI_(BSTR) SysAllocStringLenW(const OLECHAR FAR* sz, unsigned int len)

{

return SysAllocStringLen(sz, len);

}


 ANSIOLE.H  (OLEANSI Sample)

//+--------------------------------------------------------------------------

//

//  Copyright (C) 1994, Microsoft Corporation.  All Rights Reserved.

//

//  File:       ansiole1.h

//

//  Contents:   ANSI Wrappers for Unicode Ole2 Interfaces and APIs.

//

//  Classes:    CDropTargetA

//              CPersistStorageA

//              CPersistStreamA

//              CPersistFileA

//              CEnumOLEVERBA

//              COleObjectA

//              COleClientSiteA

//              CRunnableObjectA

//              COleItemCOntainerA

//              COleAdviseHolderA

//              COleLinkA

//              COleInPlaceObjectA

//              COleInPlaceActiveObjectA

//              COleInPlaceFrameA

//              COleInPlaceSiteA

//

//  History:    01-Nov-93   v-kentc     Created.

//

//---------------------------------------------------------------------------

#if defined(__cplusplus)

interface IOleClientSiteA;

interface IOleItemContainerA;

interface IOleInPlaceFrameA;

#else

typedef interface IOleClientSiteA IOleClientSiteA;

typedef interface IOleItemContainerA IOleItemContainerA;

typedef interface IOleInPlaceFrameA IOleInPlaceFrameA;

#endif

typedef IOleClientSiteA * LPOLECLIENTSITEA;

typedef IOleItemContainerA * LPOLEITEMCONTAINERA;

typedef IOleInPlaceFrameA * LPOLEINPLACEFRAMEA;

#define LPPARSEDISPLAYNAMEA     LPOLEITEMCONTAINERA

#define LPOLECONTAINERA         LPOLEITEMCONTAINERA

#define LPOLEWINDOWA            LPOLEINPLACEFRAMEA

#define LPOLEINPLACEUIWINDOWA   LPOLEINPLACEFRAMEA

#define LPPERSISTSTREAMA        LPMONIKERA

/*---------------------------------------------------------------------*/

/*                         IEnumOLEVERBA                               */

/*---------------------------------------------------------------------*/

#undef  INTERFACE

#define INTERFACE   IEnumOLEVERBA

DECLARE_INTERFACE_(IEnumOLEVERBA, IUnknown)

{

// *** IUnknown methods ***

STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppvObj) PURE;

STDMETHOD_(ULONG,AddRef) (THIS)  PURE;

STDMETHOD_(ULONG,Release) (THIS) PURE;

// *** IEnumOLEVERB methods ***

STDMETHOD(Next) (THIS_ ULONG celt, LPOLEVERBA rgelt, ULONG * pceltFetched) PURE;

STDMETHOD(Skip) (THIS_ ULONG celt) PURE;

STDMETHOD(Reset) (THIS) PURE;

STDMETHOD(Clone) (THIS_ IEnumOLEVERBA * * ppenm) PURE;

};

typedef IEnumOLEVERBA * LPENUMOLEVERBA;

/*---------------------------------------------------------------------*/

/*                         IOleObjectA                                 */

/*---------------------------------------------------------------------*/

#undef  INTERFACE

#define INTERFACE   IOleObjectA

DECLARE_INTERFACE_(IOleObjectA, IUnknown)

{

// *** IUnknown methods ***

STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppvObj) PURE;

STDMETHOD_(ULONG,AddRef) (THIS)  PURE;

STDMETHOD_(ULONG,Release) (THIS) PURE;

// *** IOleObject methods ***

STDMETHOD(SetClientSite) (THIS_ LPOLECLIENTSITEA pClientSiteA) PURE;

STDMETHOD(GetClientSite) (THIS_ LPOLECLIENTSITEA * ppCLientSiteA) PURE;

STDMETHOD(SetHostNames) (THIS_ LPCSTR szContainerApp, LPCSTR szContainerObj) PURE;

STDMETHOD(Close) (THIS_ DWORD dwSaveOption) PURE;

STDMETHOD(SetMoniker) (THIS_ DWORD dwWhichMoniker, LPMONIKERA pmkA) PURE;

STDMETHOD(GetMoniker) (THIS_ DWORD dwAssign, DWORD dwWhichMoniker,

LPMONIKERA * ppmkA) PURE;

STDMETHOD(InitFromData) (THIS_ LPDATAOBJECTA pDataObjectA,

BOOL fCreation,

DWORD dwReserved) PURE;

STDMETHOD(GetClipboardData) (THIS_ DWORD dwReserved,

LPDATAOBJECTA * ppDataObjectA) PURE;

STDMETHOD(DoVerb) (THIS_ LONG iVerb,

LPMSG lpmsg,

LPOLECLIENTSITEA pActiveSiteA,

LONG lindex,

HWND hwndParent,

LPCRECT lprcPosRect) PURE;

STDMETHOD(EnumVerbs) (THIS_ LPENUMOLEVERBA * ppenumOleVerbA) PURE;

STDMETHOD(Update) (THIS) PURE;

STDMETHOD(IsUpToDate) (THIS) PURE;

STDMETHOD(GetUserClassID) (THIS_ CLSID * pClsid) PURE;

STDMETHOD(GetUserType) (THIS_ DWORD dwFormOfType, LPSTR * pszUserType) PURE;

STDMETHOD(SetExtent) (THIS_ DWORD dwDrawAspect, LPSIZEL lpsizel) PURE;

STDMETHOD(GetExtent) (THIS_ DWORD dwDrawAspect, LPSIZEL lpsizel) PURE;

STDMETHOD(Advise)(THIS_ LPADVISESINKA pAdvSinkA, DWORD * pdwConnection) PURE;

STDMETHOD(Unadvise)(THIS_ DWORD dwConnection) PURE;

STDMETHOD(EnumAdvise) (THIS_ LPENUMSTATDATAA * ppenumAdviseA) PURE;

STDMETHOD(GetMiscStatus) (THIS_ DWORD dwAspect, DWORD * pdwStatus) PURE;

STDMETHOD(SetColorScheme) (THIS_ LPLOGPALETTE lpLogpal) PURE;

};

typedef IOleObjectA * LPOLEOBJECTA;

/*---------------------------------------------------------------------*/

/*                         IOleClientSiteA                             */

/*---------------------------------------------------------------------*/

#undef  INTERFACE

#define INTERFACE   IOleClientSiteA

DECLARE_INTERFACE_(IOleClientSiteA, IUnknown)

{

// *** IUnknown methods ***

STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppvObj) PURE;

STDMETHOD_(ULONG,AddRef) (THIS)  PURE;

STDMETHOD_(ULONG,Release) (THIS) PURE;

// *** IOleClientSite methods ***

STDMETHOD(SaveObject) (THIS) PURE;

STDMETHOD(GetMoniker) (THIS_ DWORD dwAssign, DWORD dwWhichMoniker,

LPMONIKERA * ppmkA) PURE;

STDMETHOD(GetContainer) (THIS_ LPOLECONTAINERA * ppContainerA) PURE;

STDMETHOD(ShowObject) (THIS) PURE;

STDMETHOD(OnShowWindow) (THIS_ BOOL fShow) PURE;

STDMETHOD(RequestNewObjectLayout) (THIS) PURE;

};

typedef IOleClientSiteA * LPOLECLIENTSITEA;

/*---------------------------------------------------------------------*/

/*                         IRunnableObjectA                            */

/*---------------------------------------------------------------------*/

#undef  INTERFACE

#define INTERFACE   IRunnableObjectA

DECLARE_INTERFACE_(IRunnableObjectA, IUnknown)

{

// *** IUnknown methods ***

STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppvObj) PURE;

STDMETHOD_(ULONG,AddRef) (THIS)  PURE;

STDMETHOD_(ULONG,Release) (THIS) PURE;

// *** IRunnableObject methods ***

STDMETHOD(GetRunningClass) (THIS_ LPCLSID lpClsid) PURE;

STDMETHOD(Run) (THIS_ LPBINDCTXA pbcA) PURE;

STDMETHOD_(BOOL, IsRunning) (THIS) PURE;

STDMETHOD(LockRunning)(THIS_ BOOL fLock, BOOL fLastUnlockCloses) PURE;

STDMETHOD(SetContainedObject)(THIS_ BOOL fContained) PURE;

};

typedef IRunnableObjectA * LPRUNNABLEOBJECTA;

/*---------------------------------------------------------------------*/

/*                         IOleItemContainerA                          */

/*---------------------------------------------------------------------*/

#undef  INTERFACE

#define INTERFACE   IOleItemContainerA

DECLARE_INTERFACE_(IOleItemContainerA, IUnknown)

{

// *** IUnknown methods ***

STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppvObj) PURE;

STDMETHOD_(ULONG,AddRef) (THIS)  PURE;

STDMETHOD_(ULONG,Release) (THIS) PURE;

// *** IParseDisplayName method ***

STDMETHOD(ParseDisplayName) (THIS_ LPBCA pbcA, LPSTR lpszDisplayName,

ULONG * pchEaten, LPMONIKERA * ppmkOutA) PURE;

// *** IOleContainer methods ***

STDMETHOD(EnumObjects) (THIS_ DWORD grfFlags, LPENUMUNKNOWN * ppenumUnknown) PURE;

STDMETHOD(LockContainer) (THIS_ BOOL fLock) PURE;

// *** IOleItemContainer methods ***

STDMETHOD(GetObject) (THIS_ LPSTR lpszItem, DWORD dwSpeedNeeded,

LPBINDCTXA pbcA, REFIID riid, LPVOID * ppvObject) PURE;

STDMETHOD(GetObjectStorage) (THIS_ LPSTR lpszItem, LPBINDCTXA pbcA,

REFIID riid, LPVOID * ppvStorage) PURE;

STDMETHOD(IsRunning) (THIS_ LPSTR lpszItem) PURE;

};

typedef IOleItemContainerA * LPOLEITEMCONTAINERA;

/*---------------------------------------------------------------------*/

/*                         IOleAdviseHolderA                           */

/*---------------------------------------------------------------------*/

#undef  INTERFACE

#define INTERFACE   IOleAdviseHolderA

DECLARE_INTERFACE_(IOleAdviseHolderA, IUnknown)

{

// *** IUnknown methods ***

STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppv) PURE;

STDMETHOD_(ULONG,AddRef) (THIS)  PURE;

STDMETHOD_(ULONG,Release) (THIS) PURE;

// *** IOleAdviseHolder methods ***

STDMETHOD(Advise)(THIS_ LPADVISESINKA pAdviseA, DWORD * pdwConnection) PURE;

STDMETHOD(Unadvise)(THIS_ DWORD dwConnection) PURE;

STDMETHOD(EnumAdvise)(THIS_ LPENUMSTATDATAA * ppenumAdviseA) PURE;

STDMETHOD(SendOnRename)(THIS_ LPMONIKERA pmkA) PURE;

STDMETHOD(SendOnSave)(THIS) PURE;

STDMETHOD(SendOnClose)(THIS) PURE;

};

typedef IOleAdviseHolderA * LPOLEADVISEHOLDERA;

/*---------------------------------------------------------------------*/

/*                            IOleLinkA                                */

/*---------------------------------------------------------------------*/

#undef  INTERFACE

#define INTERFACE   IOleLinkA

DECLARE_INTERFACE_(IOleLinkA, IUnknown)

{

// *** IUnknown methods ***

STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppvObj) PURE;

STDMETHOD_(ULONG,AddRef) (THIS)  PURE;

STDMETHOD_(ULONG,Release) (THIS) PURE;

// *** IOleLink methods ***

STDMETHOD(SetUpdateOptions) (THIS_ DWORD dwUpdateOpt) PURE;

STDMETHOD(GetUpdateOptions) (THIS_ LPDWORD pdwUpdateOpt) PURE;

STDMETHOD(SetSourceMoniker) (THIS_ LPMONIKERA pmkA, REFCLSID rclsid) PURE;

STDMETHOD(GetSourceMoniker) (THIS_ LPMONIKERA * ppmkA) PURE;

STDMETHOD(SetSourceDisplayName) (THIS_ LPCSTR lpszDisplayName) PURE;

STDMETHOD(GetSourceDisplayName) (THIS_ LPSTR * lplpszDisplayName) PURE;

STDMETHOD(BindToSource) (THIS_ DWORD bindflags, LPBINDCTXA pbcA) PURE;

STDMETHOD(BindIfRunning) (THIS) PURE;

STDMETHOD(GetBoundSource) (THIS_ LPUNKNOWN * ppUnk) PURE;

STDMETHOD(UnbindSource) (THIS) PURE;

STDMETHOD(Update) (THIS_ LPBINDCTXA pbcA) PURE;

};

typedef IOleLinkA * LPOLELINKA;

/*---------------------------------------------------------------------*/

/*                        IOleInPlaceObjectA                           */

/*---------------------------------------------------------------------*/

#undef  INTERFACE

#define INTERFACE   IOleInPlaceObjectA

DECLARE_INTERFACE_(IOleInPlaceObjectA, IOleWindow)

{

   // *** IUnknown methods ***

STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppvObj) PURE;

STDMETHOD_(ULONG,AddRef) (THIS)  PURE;

STDMETHOD_(ULONG,Release) (THIS) PURE;

// *** IOleWindow methods ***

STDMETHOD(GetWindow) (THIS_ HWND * lphwnd) PURE;

STDMETHOD(ContextSensitiveHelp) (THIS_ BOOL fEnterMode) PURE;

// *** IOleInPlaceObject methods ***

STDMETHOD(InPlaceDeactivate) (THIS) PURE;

STDMETHOD(UIDeactivate) (THIS) PURE;

STDMETHOD(SetObjectRects) (THIS_ LPCRECT lprcPosRect, LPCRECT lprcClipRect) PURE;

STDMETHOD(ReactivateAndUndo) (THIS) PURE;

};

typedef IOleInPlaceObjectA * LPOLEINPLACEOBJECTA;

/*---------------------------------------------------------------------*/

/*                        IOleInPlaceActiveObjectA                     */

/*---------------------------------------------------------------------*/

#undef  INTERFACE

#define INTERFACE   IOleInPlaceActiveObjectA

DECLARE_INTERFACE_(IOleInPlaceActiveObjectA, IOleWindow)

{

   // *** IUnknown methods ***

STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppvObj) PURE;

STDMETHOD_(ULONG,AddRef) (THIS)  PURE;

STDMETHOD_(ULONG,Release) (THIS) PURE;

// *** IOleWindow methods ***

STDMETHOD(GetWindow) (THIS_ HWND * lphwnd) PURE;

STDMETHOD(ContextSensitiveHelp) (THIS_ BOOL fEnterMode) PURE;

// *** IOleInPlaceActiveObject methods ***

STDMETHOD(TranslateAccelerator) (THIS_ LPMSG lpmsg) PURE;

STDMETHOD(OnFrameWindowActivate) (THIS_ BOOL fActivate) PURE;

STDMETHOD(OnDocWindowActivate) (THIS_ BOOL fActivate) PURE;

STDMETHOD(ResizeBorder) (THIS_ LPCRECT lprectBorder, LPOLEINPLACEUIWINDOWA lpUIWindowA, BOOL fFrameWindow) PURE;

STDMETHOD(EnableModeless) (THIS_ BOOL fEnable) PURE;

};

typedef IOleInPlaceActiveObjectA * LPOLEINPLACEACTIVEOBJECTA;

/*---------------------------------------------------------------------*/

/*                         IOleInPlaceFrameA                           */

/*---------------------------------------------------------------------*/

#undef  INTERFACE

#define INTERFACE   IOleInPlaceFrameA

DECLARE_INTERFACE_(IOleInPlaceFrameA, IOleWindow)

{

   // *** IUnknown methods ***

STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppvObj) PURE;

STDMETHOD_(ULONG,AddRef) (THIS)  PURE;

STDMETHOD_(ULONG,Release) (THIS) PURE;

// *** IOleWindow methods ***

STDMETHOD(GetWindow) (THIS_ HWND * lphwnd) PURE;

STDMETHOD(ContextSensitiveHelp) (THIS_ BOOL fEnterMode) PURE;

// *** IOleInPlaceUIWindow methods ***

STDMETHOD(GetBorder) (THIS_ LPRECT lprectBorder) PURE;

STDMETHOD(RequestBorderSpace) (THIS_ LPCBORDERWIDTHS lpborderwidths) PURE;

STDMETHOD(SetBorderSpace) (THIS_ LPCBORDERWIDTHS lpborderwidths) PURE;

STDMETHOD(SetActiveObject) (THIS_ LPOLEINPLACEACTIVEOBJECTA lpActiveObjectA,

LPCSTR lpszObjName) PURE;

// *** IOleInPlaceFrame methods ***

STDMETHOD(InsertMenus) (THIS_ HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths) PURE;

STDMETHOD(SetMenu) (THIS_ HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject) PURE;

STDMETHOD(RemoveMenus) (THIS_ HMENU hmenuShared) PURE;

STDMETHOD(SetStatusText) (THIS_ LPCSTR lpszStatusText) PURE;

STDMETHOD(EnableModeless) (THIS_ BOOL fEnable) PURE;

STDMETHOD(TranslateAccelerator) (THIS_ LPMSG lpmsg, WORD wID) PURE;

};

typedef IOleInPlaceFrameA * LPOLEINPLACEFRAMEA;

/*---------------------------------------------------------------------*/

/*                         IOleInPlaceSiteA                            */

/*---------------------------------------------------------------------*/

#undef  INTERFACE

#define INTERFACE   IOleInPlaceSiteA

DECLARE_INTERFACE_(IOleInPlaceSiteA, IOleWindow)

{

   // *** IUnknown methods ***

STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppvObj) PURE;

STDMETHOD_(ULONG,AddRef) (THIS)  PURE;

STDMETHOD_(ULONG,Release) (THIS) PURE;

// *** IOleWindow methods ***

STDMETHOD(GetWindow) (THIS_ HWND * lphwnd) PURE;

STDMETHOD(ContextSensitiveHelp) (THIS_ BOOL fEnterMode) PURE;

// *** IOleInPlaceSite methods ***

STDMETHOD(CanInPlaceActivate) (THIS) PURE;

STDMETHOD(OnInPlaceActivate) (THIS) PURE;

STDMETHOD(OnUIActivate) (THIS) PURE;

STDMETHOD(GetWindowContext) (THIS_ LPOLEINPLACEFRAMEA * lplpFrameA,

LPOLEINPLACEUIWINDOWA * lplpDocA,

LPRECT lprcPosRect,

LPRECT lprcClipRect,

LPOLEINPLACEFRAMEINFO lpFrameInfo) PURE;

STDMETHOD(Scroll) (THIS_ SIZE scrollExtent) PURE;

STDMETHOD(OnUIDeactivate) (THIS_ BOOL fUndoable) PURE;

STDMETHOD(OnInPlaceDeactivate) (THIS) PURE;

STDMETHOD(DiscardUndoState) (THIS) PURE;

STDMETHOD(DeactivateAndUndo) (THIS) PURE;

STDMETHOD(OnPosRectChange) (THIS_ LPCRECT lprcPosRect) PURE;

};

typedef IOleInPlaceSiteA * LPOLEINPLACESITEA;

//

//  Forward declarations

//

class CDropTargetA;

class CPersistStorageA;

class CPersistFileA;

class CEnumOLEVERBA;

class COleObjectA;

class COleClientSiteA;

class CRunnableObjectA;

class COleItemContainerA;

class COleAdviseHolderA;

class COleLinkA;

class COleInPlaceObjectA;

class COleInPlaceActiveObjectA;

class COleInPlaceFrameA;

class COleInPlaceSiteA;

//+--------------------------------------------------------------------------

//

//  Class:      CDropTargetA

//

//  Synopsis:   Class definition of IDropTargetA

//

//---------------------------------------------------------------------------

class CDropTargetA : CAnsiInterface

{

public:

// *** IDropTarget methods ***

STDMETHOD(DragEnter) (LPDATAOBJECTA pDataObjA, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect);

STDMETHOD(DragOver) (DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect);

STDMETHOD(DragLeave) (VOID);

STDMETHOD(Drop) (LPDATAOBJECTA pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect);

inline CDropTargetA(LPUNKNOWN pUnk, IDropTarget * pWide) :

CAnsiInterface(ID_IDropTarget, pUnk, (LPUNKNOWN)pWide) {};

inline IDropTarget * GetWide() const

{ return (IDropTarget *)m_pObj; };

};

//+--------------------------------------------------------------------------

//

//  Class:      CPersistStorageA

//

//  Synopsis:   Class definition of IPersistStorageA

//

//---------------------------------------------------------------------------

class CPersistStorageA : CAnsiInterface

{

public:

// *** IPersist methods ***

STDMETHOD(GetClassID) (LPCLSID lpClassID);

// *** IPersistStorage methods ***

STDMETHOD(IsDirty) (VOID);

STDMETHOD(InitNew) (LPSTORAGEA pStgA);

STDMETHOD(Load) (LPSTORAGEA pStgA);

STDMETHOD(Save) (LPSTORAGEA pStgSaveA, BOOL fSameAsLoad);

STDMETHOD(SaveCompleted) (LPSTORAGEA pStgNewA);

STDMETHOD(HandsOffStorage) (VOID);

inline CPersistStorageA(LPUNKNOWN pUnk, IPersistStorage * pWide) :

CAnsiInterface(ID_IPersistStorage, pUnk, (LPUNKNOWN)pWide) {};

inline IPersistStorage * GetWide() const

{ return (IPersistStorage *)m_pObj; };

};

//+--------------------------------------------------------------------------

//

//  Class:      CPersistFileA

//

//  Synopsis:   Class definition of IPersistFileA

//

//---------------------------------------------------------------------------

class CPersistFileA : CAnsiInterface

{

public:

// *** IPersist methods ***

STDMETHOD(GetClassID) (LPCLSID lpClassID);

// *** IPersistFile methods ***

STDMETHOD(IsDirty) (VOID);

STDMETHOD(Load) (LPCSTR lpszFileName, DWORD grfMode);

STDMETHOD(Save) (LPCSTR lpszFileName, BOOL fRemember);

STDMETHOD(SaveCompleted) (LPCSTR lpszFileName);

STDMETHOD(GetCurFile) (LPSTR FAR* lplpszFileName);

inline CPersistFileA(LPUNKNOWN pUnk, IPersistFile * pWide) :

CAnsiInterface(ID_IPersistFile, pUnk, (LPUNKNOWN)pWide) {};

inline IPersistFile * GetWide() const

{ return (IPersistFile *)m_pObj; };

};

//+--------------------------------------------------------------------------

//

//  Class:      CEnumOLEVERBA

//

//  Synopsis:   Class definition of IEnumOLEVERBA

//

//---------------------------------------------------------------------------

class CEnumOLEVERBA : CAnsiInterface

{

public:

// *** IEnumOLEVERB methods ***

STDMETHOD(Next) (ULONG celt, LPOLEVERBA rgelt, ULONG * pceltFetched);

STDMETHOD(Skip) (ULONG celt);

STDMETHOD(Reset) (VOID);

STDMETHOD(Clone) (IEnumOLEVERBA * * ppenm);

inline CEnumOLEVERBA(LPUNKNOWN pUnk, IEnumOLEVERB * pWide) :

CAnsiInterface(ID_IEnumOLEVERB, pUnk, (LPUNKNOWN)pWide) {};

inline IEnumOLEVERB * GetWide() const

{ return (IEnumOLEVERB *)m_pObj; };

};

//+--------------------------------------------------------------------------

//

//  Class:      COleObjectA

//

//  Synopsis:   Class definition of IOleObjectA

//

//---------------------------------------------------------------------------

class COleObjectA : CAnsiInterface

{

public:

// *** IOleObject methods ***

STDMETHOD(SetClientSite) (LPOLECLIENTSITEA pClientSiteA);

STDMETHOD(GetClientSite) (LPOLECLIENTSITEA * ppCLientSiteA);

STDMETHOD(SetHostNames) (LPCSTR szContainerApp, LPCSTR szContainerObj);

STDMETHOD(Close) (DWORD dwSaveOption);

STDMETHOD(SetMoniker) (DWORD dwWhichMoniker, LPMONIKERA pmkA);

STDMETHOD(GetMoniker) (DWORD dwAssign, DWORD dwWhichMoniker,

LPMONIKERA * ppmkA);

STDMETHOD(InitFromData) (LPDATAOBJECTA pDataObjectA,

BOOL fCreation,

DWORD dwReserved);

STDMETHOD(GetClipboardData) (DWORD dwReserved,

LPDATAOBJECTA * ppDataObjectA);

STDMETHOD(DoVerb) (LONG iVerb,

LPMSG lpmsg,

LPOLECLIENTSITEA pActiveSiteA,

LONG lindex,

HWND hwndParent,

LPCRECT lprcPosRect);

STDMETHOD(EnumVerbs) (LPENUMOLEVERBA * ppenumOleVerbA);

STDMETHOD(Update) (VOID);

STDMETHOD(IsUpToDate) (VOID);

STDMETHOD(GetUserClassID) (CLSID * pClsid);

STDMETHOD(GetUserType) (DWORD dwFormOfType, LPSTR * pszUserType);

STDMETHOD(SetExtent) (DWORD dwDrawAspect, LPSIZEL lpsizel);

STDMETHOD(GetExtent) (DWORD dwDrawAspect, LPSIZEL lpsizel);

STDMETHOD(Advise)(LPADVISESINKA pAdvSinkA, DWORD * pdwConnection);

STDMETHOD(Unadvise)(DWORD dwConnection);

STDMETHOD(EnumAdvise) (LPENUMSTATDATAA * ppenumAdviseA);

STDMETHOD(GetMiscStatus) (DWORD dwAspect, DWORD * pdwStatus);

STDMETHOD(SetColorScheme) (LPLOGPALETTE lpLogpal);

inline COleObjectA(LPUNKNOWN pUnk, IOleObject * pWide) :

CAnsiInterface(ID_IOleObject, pUnk, (LPUNKNOWN)pWide) {};

inline IOleObject * GetWide() const

{ return (IOleObject *)m_pObj; };

};

//+--------------------------------------------------------------------------

//

//  Class:      COleClientSiteA

//

//  Synopsis:   Class definition of IOleClientSiteA

//

//---------------------------------------------------------------------------

class COleClientSiteA : CAnsiInterface

{

public:

// *** IOleClientSite methods ***

STDMETHOD(SaveObject) (VOID);

STDMETHOD(GetMoniker) (DWORD dwAssign, DWORD dwWhichMoniker,

LPMONIKERA * ppmkA);

STDMETHOD(GetContainer) (LPOLECONTAINERA * ppContainerA);

STDMETHOD(ShowObject) (VOID);

STDMETHOD(OnShowWindow) (BOOL fShow);

STDMETHOD(RequestNewObjectLayout) (VOID);

inline COleClientSiteA(LPUNKNOWN pUnk, IOleClientSite * pWide) :

CAnsiInterface(ID_IOleClientSite, pUnk, (LPUNKNOWN)pWide) {};

inline IOleClientSite * GetWide() const

{ return (IOleClientSite *)m_pObj; };

};

//+--------------------------------------------------------------------------

//

//  Class:      CRunnableObjectA

//

//  Synopsis:   Class definition of IRunnableObjectA

//

//---------------------------------------------------------------------------

class CRunnableObjectA : CAnsiInterface

{

public:

// *** IRunnableObject methods ***

STDMETHOD(GetRunningClass) (LPCLSID lpClsid);

STDMETHOD(Run) (LPBINDCTXA pbcA);

STDMETHOD_(BOOL, IsRunning) (VOID);

STDMETHOD(LockRunning)(BOOL fLock, BOOL fLastUnlockCloses);

STDMETHOD(SetContainedObject)(BOOL fContained);

inline CRunnableObjectA(LPUNKNOWN pUnk, IRunnableObject * pWide) :

CAnsiInterface(ID_IRunnableObject, pUnk, (LPUNKNOWN)pWide) {};

inline IRunnableObject * GetWide() const

{ return (IRunnableObject *)m_pObj; };

};

//+--------------------------------------------------------------------------

//

//  Class:      COleItemContainerA

//

//  Synopsis:   Class definition of IOleItemContainerA

//

//---------------------------------------------------------------------------

class COleItemContainerA : CAnsiInterface

{

public:

// *** IParseDisplayName method ***

STDMETHOD(ParseDisplayName) (LPBCA pbcA, LPSTR lpszDisplayName,

ULONG * pchEaten, LPMONIKERA * ppmkAOut);

// *** IOleContainer methods ***

STDMETHOD(EnumObjects) (DWORD grfFlags, LPENUMUNKNOWN * ppenumUnknown);

STDMETHOD(LockContainer) (BOOL fLock);

// *** IOleItemContainer methods ***

STDMETHOD(GetObject) (LPSTR lpszItem, DWORD dwSpeedNeeded,

LPBINDCTXA pbcA, REFIID riid, LPVOID * ppvObject);

STDMETHOD(GetObjectStorage) (LPSTR lpszItem, LPBINDCTXA pbcA,

REFIID riid, LPVOID * ppvStorage);

STDMETHOD(IsRunning) (LPSTR lpszItem);

inline COleItemContainerA(LPUNKNOWN pUnk, IOleItemContainer * pWide) :

CAnsiInterface(ID_IOleItemContainer, pUnk, (LPUNKNOWN)pWide) {};

inline IOleItemContainer * GetWide() const

{ return (IOleItemContainer *)m_pObj; };

};

//+--------------------------------------------------------------------------

//

//  Class:      COleAdviseHolderA

//

//  Synopsis:   Class definition of IOleAdviseHolderA

//

//---------------------------------------------------------------------------

class COleAdviseHolderA : CAnsiInterface

{

public:

// *** IOleAdviseHolder methods ***

STDMETHOD(Advise)(LPADVISESINKA pAdviseA, DWORD * pdwConnection);

STDMETHOD(Unadvise)(DWORD dwConnection);

STDMETHOD(EnumAdvise)(LPENUMSTATDATAA * ppenumAdviseA);

STDMETHOD(SendOnRename)(LPMONIKERA pmkA);

STDMETHOD(SendOnSave)(VOID);

STDMETHOD(SendOnClose)(VOID);

inline COleAdviseHolderA(LPUNKNOWN pUnk, IOleAdviseHolder * pWide) :

CAnsiInterface(ID_IOleAdviseHolder, pUnk, (LPUNKNOWN)pWide) {};

inline IOleAdviseHolder * GetWide() const

{ return (IOleAdviseHolder *)m_pObj; };

};

//+--------------------------------------------------------------------------

//

//  Class:      COleLinkA

//

//  Synopsis:   Class definition of IOleLinkA

//

//---------------------------------------------------------------------------

class COleLinkA : CAnsiInterface

{

public:

// *** IOleLink methods ***

STDMETHOD(SetUpdateOptions) (DWORD dwUpdateOpt);

STDMETHOD(GetUpdateOptions) (LPDWORD pdwUpdateOpt);

STDMETHOD(SetSourceMoniker) (LPMONIKERA pmkA, REFCLSID rclsid);

STDMETHOD(GetSourceMoniker) (LPMONIKERA * ppmkA);

STDMETHOD(SetSourceDisplayName) (LPCSTR lpszDisplayName);

STDMETHOD(GetSourceDisplayName) (LPSTR * lplpszDisplayName);

STDMETHOD(BindToSource) (DWORD bindflags, LPBINDCTXA pbcA);

STDMETHOD(BindIfRunning) (VOID);

STDMETHOD(GetBoundSource) (LPUNKNOWN * ppUnk);

STDMETHOD(UnbindSource) (VOID);

STDMETHOD(Update) (LPBINDCTXA pbcA);

inline COleLinkA(LPUNKNOWN pUnk, IOleLink * pWide) :

CAnsiInterface(ID_IOleLink, pUnk, (LPUNKNOWN)pWide) {};

inline IOleLink * GetWide() const

{ return (IOleLink *)m_pObj; };

};

//+--------------------------------------------------------------------------

//

//  Class:      COleInPlaceObjectA

//

//  Synopsis:   Class definition of IOleInPlaceObjectA

//

//---------------------------------------------------------------------------

class COleInPlaceObjectA : CAnsiInterface

{

public:

// *** IOleWindow methods ***

STDMETHOD(GetWindow) (HWND * lphwnd);

STDMETHOD(ContextSensitiveHelp) (BOOL fEnterMode);

// *** IOleInPlaceObject methods ***

STDMETHOD(InPlaceDeactivate) (VOID);

STDMETHOD(UIDeactivate) (VOID);

STDMETHOD(SetObjectRects) (LPCRECT lprcPosRect, LPCRECT lprcClipRect);

STDMETHOD(ReactivateAndUndo) (VOID);

inline COleInPlaceObjectA(LPUNKNOWN pUnk, IOleInPlaceObject * pWide) :

CAnsiInterface(ID_IOleInPlaceObject, pUnk, (LPUNKNOWN)pWide) {};

inline IOleInPlaceObject * GetWide() const

{ return (IOleInPlaceObject *)m_pObj; };

};

//+--------------------------------------------------------------------------

//

//  Class:      COleInPlaceActiveObjectA

//

//  Synopsis:   Class definition of IOleInPlaceActiveObjectA

//

//---------------------------------------------------------------------------

class COleInPlaceActiveObjectA : CAnsiInterface

{

public:

// *** IOleWindow methods ***

STDMETHOD(GetWindow) (HWND * lphwnd);

STDMETHOD(ContextSensitiveHelp) (BOOL fEnterMode);

// *** IOleInPlaceActiveObject methods ***

STDMETHOD(TranslateAccelerator) (LPMSG lpmsg);

STDMETHOD(OnFrameWindowActivate) (BOOL fActivate);

STDMETHOD(OnDocWindowActivate) (BOOL fActivate);

STDMETHOD(ResizeBorder) (LPCRECT lprectBorder, LPOLEINPLACEUIWINDOWA lpUIWindowA, BOOL fFrameWindow);

STDMETHOD(EnableModeless) (BOOL fEnable);

inline COleInPlaceActiveObjectA(LPUNKNOWN pUnk, IOleInPlaceActiveObject * pWide) :

CAnsiInterface(ID_IOleInPlaceActiveObject, pUnk, (LPUNKNOWN)pWide) {};

inline IOleInPlaceActiveObject * GetWide() const

{ return (IOleInPlaceActiveObject *)m_pObj; };

};

//+--------------------------------------------------------------------------

//

//  Class:      COleInPlaceFrameA

//

//  Synopsis:   Class definition of IOleInPlaceFrameA

//

//---------------------------------------------------------------------------

class COleInPlaceFrameA : CAnsiInterface

{

public:

// *** IOleWindow methods ***

STDMETHOD(GetWindow) (HWND * lphwnd);

STDMETHOD(ContextSensitiveHelp) (BOOL fEnterMode);

// *** IOleInPlaceUIWindow methods ***

STDMETHOD(GetBorder) (LPRECT lprectBorder);

STDMETHOD(RequestBorderSpace) (LPCBORDERWIDTHS lpborderwidths);

STDMETHOD(SetBorderSpace) (LPCBORDERWIDTHS lpborderwidths);

STDMETHOD(SetActiveObject) (LPOLEINPLACEACTIVEOBJECTA lpActiveObjectA,

LPCSTR lpszObjName);

// *** IOleInPlaceFrame methods ***

STDMETHOD(InsertMenus) (HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths);

STDMETHOD(SetMenu) (HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject);

STDMETHOD(RemoveMenus) (HMENU hmenuShared);

STDMETHOD(SetStatusText) (LPCSTR lpszStatusText);

STDMETHOD(EnableModeless) (BOOL fEnable);

STDMETHOD(TranslateAccelerator) (LPMSG lpmsg, WORD wID);

inline COleInPlaceFrameA(LPUNKNOWN pUnk, IOleInPlaceFrame * pWide) :

CAnsiInterface(ID_IOleInPlaceFrame, pUnk, (LPUNKNOWN)pWide) {};

inline IOleInPlaceFrame * GetWide() const

{ return (IOleInPlaceFrame *)m_pObj; };

};

//+--------------------------------------------------------------------------

//

//  Class:      COleInPlaceSiteA

//

//  Synopsis:   Class definition of IOleInPlaceSiteA

//

//---------------------------------------------------------------------------

class COleInPlaceSiteA : CAnsiInterface

{

public:

// *** IOleWindow methods ***

STDMETHOD(GetWindow) (HWND * lphwnd);

STDMETHOD(ContextSensitiveHelp) (BOOL fEnterMode);

// *** IOleInPlaceSite methods ***

STDMETHOD(CanInPlaceActivate) (VOID);

STDMETHOD(OnInPlaceActivate) (VOID);

STDMETHOD(OnUIActivate) (VOID);

STDMETHOD(GetWindowContext) (LPOLEINPLACEFRAMEA * lplpFrameA,

LPOLEINPLACEUIWINDOWA * lplpDocA,

LPRECT lprcPosRect,

LPRECT lprcClipRect,

LPOLEINPLACEFRAMEINFO lpFrameInfo);

STDMETHOD(Scroll) (SIZE scrollExtent);

STDMETHOD(OnUIDeactivate) (BOOL fUndoable);

STDMETHOD(OnInPlaceDeactivate) (VOID);

STDMETHOD(DiscardUndoState) (VOID);

STDMETHOD(DeactivateAndUndo) (VOID);

STDMETHOD(OnPosRectChange) (LPCRECT lprcPosRect);

inline COleInPlaceSiteA(LPUNKNOWN pUnk, IOleInPlaceSite * pWide) :

CAnsiInterface(ID_IOleInPlaceSite, pUnk, (LPUNKNOWN)pWide) {};

inline IOleInPlaceSite * GetWide() const

{ return (IOleInPlaceSite *)m_pObj; };

};


 ANSIOLE1.CPP  (OLEANSI Sample)

//+--------------------------------------------------------------------------

//

//  Copyright (C) 1994, Microsoft Corporation.  All Rights Reserved.

//

//  File:       ansiole1.cpp

//

//  Contents:   ANSI Wrappers for Unicode Ole2 Interfaces and APIs.

//

//  Classes:    CDropTargetA

//              CPersistStorageA

//              CPersistFileA

//              CEnumOLEVERBA

//              COleObjectA

//              CRunnableObjectA

//

//  Functions:  IDropTargetAFromW

//              IPersistStorageAFromW

//              IPersistFileAFromW

//              IEnumOLEVERBAFromW

//              IOleObjectAFromW

//              IRunnableObjectAFromW

//

//  History:    01-Nov-93   v-kentc     Created.

//

//---------------------------------------------------------------------------

#include "Ole2Ansi.h"


 IDropTargetA Implementation  (OLEANSI Sample)

//***************************************************************************

//

//                   IDropTargetA Implementation

//

//***************************************************************************

//+--------------------------------------------------------------------------

//

//  Member:     CDropTargetA::DragEnter, public

//

//  Synopsis:   Thunks DragEnter to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CDropTargetA::DragEnter(LPDATAOBJECTA pDataObjA,

DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)

{

TraceMethodEnter("CDropTargetA::DragEnter", this);

LPDATAOBJECT pDataObj;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IDropTarget, DragEnter));

hResult = WrapIDataObjectWFromA(pDataObjA, &pDataObj);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->DragEnter(pDataObj, grfKeyState, pt, pdwEffect);

if (pDataObj)

pDataObj->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CDropTargetA::DragOver, public

//

//  Synopsis:   Thunks DragOver to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CDropTargetA::DragOver(DWORD grfKeyState, POINTL pt,

LPDWORD pdwEffect)

{

TraceMethodEnter("CDropTargetA::DragOver", this);

_DebugHook(GetWide(), MEMBER_PTR(IDropTarget, DragOver));

return GetWide()->DragOver(grfKeyState, pt, pdwEffect);

}

//+--------------------------------------------------------------------------

//

//  Member:     CDropTargetA::DragLeave, public

//

//  Synopsis:   Thunks DragLeave to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CDropTargetA::DragLeave(VOID)

{

TraceMethodEnter("CDropTargetA::DragLeave", this);

_DebugHook(GetWide(), MEMBER_PTR(IDropTarget, DragLeave));

return GetWide()->DragLeave();

}

//+--------------------------------------------------------------------------

//

//  Member:     CDropTargetA::Drop, public

//

//  Synopsis:   Thunks Drop to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CDropTargetA::Drop(LPDATAOBJECTA pDataObjA, DWORD grfKeyState,

POINTL pt, LPDWORD pdwEffect)

{

TraceMethodEnter("CDropTargetA::Drop", this);

LPDATAOBJECT pDataObj;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IDropTarget, Drop));

hResult = WrapIDataObjectWFromA(pDataObjA, &pDataObj);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->Drop(pDataObj, grfKeyState, pt, pdwEffect);

if (pDataObj)

pDataObj->Release();

return hResult;

}


 IPersistStorageA Implementation  (OLEANSI Sample)

//***************************************************************************

//

//                   IPersistStorageA Implementation

//

//***************************************************************************

//+--------------------------------------------------------------------------

//

//  Member:     CPersistStorageA::GetClassID, public

//

//  Synopsis:   Thunks GetClassID to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CPersistStorageA::GetClassID(LPCLSID lpClassID)

{

TraceMethodEnter("CPersistStorageA::GetClassID", this);

_DebugHook(GetWide(), MEMBER_PTR(IPersist, GetClassID));

return GetWide()->GetClassID(lpClassID);

}

//+--------------------------------------------------------------------------

//

//  Member:     CPersistStorageA::IsDirty, public

//

//  Synopsis:   Thunks IsDirty to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CPersistStorageA::IsDirty(VOID)

{

TraceMethodEnter("CPersistStorageA::IsDirty", this);

_DebugHook(GetWide(), MEMBER_PTR(IPersistStorage, IsDirty));

return GetWide()->IsDirty();

}

//+--------------------------------------------------------------------------

//

//  Member:     CPersistStorageA::InitNew, public

//

//  Synopsis:   Thunks InitNew to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CPersistStorageA::InitNew(LPSTORAGEA pStgA)

{

TraceMethodEnter("CPersistStorageA::InitNew", this);

LPSTORAGE pStg;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IPersistStorage, InitNew));

hResult = WrapIStorageWFromA(pStgA, &pStg);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->InitNew(pStg);

if (pStg)

pStg->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CPersistStorageA::Load, public

//

//  Synopsis:   Thunks Load to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CPersistStorageA::Load(LPSTORAGEA pStgA)

{

TraceMethodEnter("CPersistStorageA::Load", this);

LPSTORAGE pStg;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IPersistStorage, Load));

hResult = WrapIStorageWFromA(pStgA, &pStg);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->Load(pStg);

if (pStg)

pStg->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CPersistStreamA::Save, public

//

//  Synopsis:   Thunks Save to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CPersistStorageA::Save(LPSTORAGEA pStgSaveA, BOOL fSameAsLoad)

{

TraceMethodEnter("CPersistStorageA::Save", this);

LPSTORAGE pStgSave;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IPersistStorage, Save));

hResult = WrapIStorageWFromA(pStgSaveA, &pStgSave);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->Save(pStgSave, fSameAsLoad);

if (pStgSave)

pStgSave->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CPersistStreamA::SaveCompleted, public

//

//  Synopsis:   Thunks SaveCompleted to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CPersistStorageA::SaveCompleted(LPSTORAGEA pStgNewA)

{

TraceMethodEnter("CPersistStorageA::SaveCompleted", this);

LPSTORAGE pStgNew;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IPersistStorage, SaveCompleted));

hResult = WrapIStorageWFromA(pStgNewA, &pStgNew);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->SaveCompleted(pStgNew);

if (pStgNew)

pStgNew->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CPersistStreamA::HandsOffStorage, public

//

//  Synopsis:   Thunks HandsOffStorage to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CPersistStorageA::HandsOffStorage(VOID)

{

TraceMethodEnter("CPersistStorageA::HandsOffStorage", this);

_DebugHook(GetWide(), MEMBER_PTR(IPersistStorage, HandsOffStorage));

return GetWide()->HandsOffStorage();

}


 IPersistFileA Implementation  (OLEANSI Sample)

//***************************************************************************

//

//                   IPersistFileA Implementation

//

//***************************************************************************

//+--------------------------------------------------------------------------

//

//  Member:     CPersistFileA::GetClassID, public

//

//  Synopsis:   Thunks GetClassID to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CPersistFileA::GetClassID(LPCLSID lpClassID)

{

TraceMethodEnter("CPersistFileA::GetClassID", this);

_DebugHook(GetWide(), MEMBER_PTR(IPersist, GetClassID));

return GetWide()->GetClassID(lpClassID);

}

//+--------------------------------------------------------------------------

//

//  Member:     CPersistFileA::IsDirty, public

//

//  Synopsis:   Thunks IsDirty to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CPersistFileA::IsDirty(VOID)

{

TraceMethodEnter("CPersistFileA::IsDirty", this);

_DebugHook(GetWide(), MEMBER_PTR(IPersistFile, IsDirty));

return GetWide()->IsDirty();

}

//+--------------------------------------------------------------------------

//

//  Member:     CPersistFileA::Load, public

//

//  Synopsis:   Thunks Load to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CPersistFileA::Load(LPCSTR lpszFileNameA, DWORD grfMode)

{

TraceMethodEnter("CPersistFileA::Load", this);

LPOLESTR lpszFileName;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IPersistFile, Load));

hResult = ConvertStringToW(lpszFileNameA, &lpszFileName);

if (FAILED(hResult))

return (hResult);

hResult = GetWide()->Load(lpszFileName, grfMode);

ConvertStringFree(lpszFileName);

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CPersistFileA::Save, public

//

//  Synopsis:   Thunks Save to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CPersistFileA::Save(LPCSTR lpszFileNameA, BOOL fRemember)

{

TraceMethodEnter("CPersistFileA::Save", this);

LPOLESTR lpszFileName;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IPersistFile, Save));

hResult = ConvertStringToW(lpszFileNameA, &lpszFileName);

if (FAILED(hResult))

return (hResult);

hResult = GetWide()->Save(lpszFileName, fRemember);

ConvertStringFree(lpszFileName);

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CPersistFileA::SaveCompleted, public

//

//  Synopsis:   Thunks SaveCompleted to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CPersistFileA::SaveCompleted(LPCSTR lpszFileNameA)

{

TraceMethodEnter("CPersistFileA::SaveCompleted", this);

LPOLESTR lpszFileName;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IPersistFile, SaveCompleted));

hResult = ConvertStringToW(lpszFileNameA, &lpszFileName);

if (FAILED(hResult))

return (hResult);

hResult = GetWide()->SaveCompleted(lpszFileName);

ConvertStringFree(lpszFileName);

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CPersistFileA::GetCurFile, public

//

//  Synopsis:   Thunks GetCurFile to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CPersistFileA::GetCurFile(LPSTR FAR* lplpszFileNameA)

{

TraceMethodEnter("CPersistFileA::GetCurFile", this);

LPOLESTR lpszFileName;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IPersistFile, GetCurFile));

hResult = GetWide()->GetCurFile(&lpszFileName);

if (FAILED(hResult))

return (hResult);

hResult = ConvertStringToA(lpszFileName, lplpszFileNameA);

ConvertStringFree(lpszFileName);

return hResult;

}


 IEnumOLEVERBA Implementation  (OLEANSI Sample)

//***************************************************************************

//

//                   IEnumOLEVERBA Implementation

//

//***************************************************************************

//+--------------------------------------------------------------------------

//

//  Member:     CEnumOLEVERBA::Next, public

//

//  Synopsis:   Thunks Next to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CEnumOLEVERBA::Next(

ULONG celt,

OLEVERBA * rgelt,

ULONG * pceltFetched)

{

TraceMethodEnter("CEnumOLEVERBA::Next", this);

ULONG   celtFetched;

HRESULT hReturn;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IEnumOLEVERB, Next));

if (pceltFetched == NULL)

pceltFetched = &celtFetched;

hReturn = GetWide()->Next(celt, (OLEVERB *)rgelt, pceltFetched);

if (FAILED(hReturn))

return (hReturn);

hResult = ConvertOLEVERBArrayToA(rgelt, *pceltFetched);

if (FAILED(hResult))

return (hResult);

return hReturn;

}

//+--------------------------------------------------------------------------

//

//  Member:     CEnumOLEVERBA::Skip, public

//

//  Synopsis:   Thunks Skip to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CEnumOLEVERBA::Skip(ULONG celt)

{

TraceMethodEnter("CEnumOLEVERBA::Skip", this);

_DebugHook(GetWide(), MEMBER_PTR(IEnumOLEVERB, Skip));

return GetWide()->Skip(celt);

}

//+--------------------------------------------------------------------------

//

//  Member:     CEnumOLEVERBA::Reset, public

//

//  Synopsis:   Thunks Reset to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CEnumOLEVERBA::Reset(VOID)

{

TraceMethodEnter("CEnumOLEVERBA::Reset", this);

_DebugHook(GetWide(), MEMBER_PTR(IEnumOLEVERB, Reset));

return GetWide()->Reset();

}

//+--------------------------------------------------------------------------

//

//  Member:     CEnumOLEVERBA::Clone, public

//

//  Synopsis:   Thunks Clone to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CEnumOLEVERBA::Clone(IEnumOLEVERBA * * ppobjA)

{

TraceMethodEnter("CEnumOLEVERBA::Clone", this);

IEnumOLEVERB * pobj;

_DebugHook(GetWide(), MEMBER_PTR(IEnumOLEVERB, Clone));

*ppobjA = NULL;

HRESULT hResult = GetWide()->Clone(&pobj);

if (FAILED(hResult))

return (hResult);

hResult = WrapIEnumOLEVERBAFromW(pobj, ppobjA);

if (pobj)

pobj->Release();

return hResult;

}


 IOleObjectA Implementation  (OLEANSI Sample)

//***************************************************************************

//

//                   IOleObjectA Implementation

//

//***************************************************************************

//+--------------------------------------------------------------------------

//

//  Member:     COleObjectA::SetClientSite, public

//

//  Synopsis:   Thunks SetClientSite to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleObjectA::SetClientSite(LPOLECLIENTSITEA pClientSiteA)

{

TraceMethodEnter("COleObjectA::SetClientSite", this);

LPOLECLIENTSITE pClientSite;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IOleObject, SetClientSite));

hResult = WrapIOleClientSiteWFromA(pClientSiteA, &pClientSite);

if (FAILED(hResult))

return (hResult);

hResult = GetWide()->SetClientSite(pClientSite);

if (pClientSite)

   pClientSite->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     COleObjectA::GetClientSite, public

//

//  Synopsis:   Thunks GetClientSite to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleObjectA::GetClientSite(LPOLECLIENTSITEA * ppClientSiteA)

{

TraceMethodEnter("COleObjectA::GetClientSite", this);

LPOLECLIENTSITE pClientSite;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IOleObject, GetClientSite));

*ppClientSiteA = NULL;

hResult = GetWide()->GetClientSite(&pClientSite);

if (FAILED(hResult))

return (hResult);

hResult = WrapIOleClientSiteAFromW(pClientSite, ppClientSiteA);

if (pClientSite)

pClientSite->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     COleObjectA::SetHostNames, public

//

//  Synopsis:   Thunks SetHostNames to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleObjectA::SetHostNames(LPCSTR szContainerAppA,

LPCSTR szContainerObjA)

{

TraceMethodEnter("COleObjectA::SetHostNames", this);

LPOLESTR szContainerApp;

LPOLESTR szContainerObj = 0;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IOleObject, SetHostNames));

hResult = ConvertStringToW(szContainerAppA, &szContainerApp);

if (FAILED(hResult))

return (hResult);

hResult = ConvertStringToW(szContainerObjA, &szContainerObj);

if (FAILED(hResult))

goto Error;

hResult = GetWide()->SetHostNames(szContainerApp, szContainerObj);

Error:

ConvertStringFree(szContainerApp);

ConvertStringFree(szContainerObj);

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     COleObjectA::Close, public

//

//  Synopsis:   Thunks Close to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleObjectA::Close(DWORD dwSaveOption)

{

TraceMethodEnter("COleObjectA::Close", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleObject, Close));

return GetWide()->Close(dwSaveOption);

}

//+--------------------------------------------------------------------------

//

//  Member:     COleObjectA::SetMoniker, public

//

//  Synopsis:   Thunks SetMoniker to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleObjectA::SetMoniker(DWORD dwWhichMoniker, LPMONIKERA pmkA)

{

TraceMethodEnter("COleObjectA::SetMoniker", this);

LPMONIKER pmk;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IOleObject, SetMoniker));

hResult = WrapIMonikerWFromA(pmkA, &pmk);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->SetMoniker(dwWhichMoniker, pmk);

if (pmk)

pmk->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     COleObjectA::GetMoniker, public

//

//  Synopsis:   Thunks GetMoniker to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleObjectA::GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker,

LPMONIKERA * ppmkA)

{

TraceMethodEnter("COleObjectA::GetMoniker", this);

LPMONIKER pmk;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IOleObject, GetMoniker));

*ppmkA = NULL;

hResult = GetWide()->GetMoniker(dwAssign, dwWhichMoniker, &pmk);

if (FAILED(hResult))

return (hResult);

hResult = WrapIMonikerAFromW(pmk, ppmkA);

if (pmk)

pmk->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     COleObjectA::InitFromData, public

//

//  Synopsis:   Thunks InitFromData to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleObjectA::InitFromData(LPDATAOBJECTA pDataObjectA,

BOOL fCreation, DWORD dwReserved)

{

TraceMethodEnter("COleObjectA::InitFromData", this);

LPDATAOBJECT pDataObject;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IOleObject, InitFromData));

hResult = WrapIDataObjectWFromA(pDataObjectA, &pDataObject);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->InitFromData(pDataObject, fCreation, dwReserved);

if (pDataObject)

pDataObject->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     COleObjectA::GetClipboardData, public

//

//  Synopsis:   Thunks GetClipboardData to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleObjectA::GetClipboardData(DWORD dwReserved,

LPDATAOBJECTA * ppDataObjectA)

{

TraceMethodEnter("COleObjectA::GetClipboardData", this);

LPDATAOBJECT pDataObject;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IOleObject, GetClipboardData));

*ppDataObjectA = NULL;

hResult = GetWide()->GetClipboardData(dwReserved, &pDataObject);

if (FAILED(hResult))

return (hResult);

hResult = WrapIDataObjectAFromW(pDataObject, ppDataObjectA);

if (pDataObject)

pDataObject->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     COleObjectA::DoVerb, public

//

//  Synopsis:   Thunks DoVerb to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleObjectA::DoVerb(LONG iVerb, LPMSG lpmsg,

LPOLECLIENTSITEA pActiveSiteA, LONG lindex, HWND hwndParent,

LPCRECT lprcPosRect)

{

TraceMethodEnter("COleObjectA::DoVerb", this);

LPOLECLIENTSITE pActiveSite;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IOleObject, DoVerb));

hResult = WrapIOleClientSiteWFromA(pActiveSiteA, &pActiveSite);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->DoVerb(iVerb, lpmsg, pActiveSite, lindex, hwndParent,

lprcPosRect);

if (pActiveSite)

pActiveSite->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     COleObjectA::EnumVerbs, public

//

//  Synopsis:   Thunks EnumVerbs to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleObjectA::EnumVerbs(LPENUMOLEVERBA * ppenumOleVerbA)

{

TraceMethodEnter("COleObjectA::EnumVerbs", this);

LPENUMOLEVERB penumOleVerb = NULL;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IOleObject, EnumVerbs));

hResult = GetWide()->EnumVerbs(&penumOleVerb);

if (FAILED(hResult) || hResult == OLE_S_USEREG)

return (hResult);

if (penumOleVerb)

{

hResult = WrapIEnumOLEVERBAFromW(penumOleVerb, ppenumOleVerbA);

penumOleVerb->Release();

}

else

*ppenumOleVerbA = NULL;

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     COleObjectA::Update, public

//

//  Synopsis:   Thunks Update to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleObjectA::Update(VOID)

{

TraceMethodEnter("COleObjectA::Update", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleObject, Update));

return GetWide()->Update();

}

//+--------------------------------------------------------------------------

//

//  Member:     COleObjectA::IsUpToDate, public

//

//  Synopsis:   Thunks IsUpToDate to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleObjectA::IsUpToDate(VOID)

{

TraceMethodEnter("COleObjectA::IsUpToDate", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleObject, IsUpToDate));

return GetWide()->IsUpToDate();

}

//+--------------------------------------------------------------------------

//

//  Member:     COleObjectA::GetUserClassID, public

//

//  Synopsis:   Thunks GetUserClassID to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleObjectA::GetUserClassID(CLSID * pClsid)

{

TraceMethodEnter("COleObjectA::GetUserClassID", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleObject, GetUserClassID));

return GetWide()->GetUserClassID(pClsid);

}

//+--------------------------------------------------------------------------

//

//  Member:     COleObjectA::GetUserType, public

//

//  Synopsis:   Thunks GetUserType to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleObjectA::GetUserType(DWORD dwFormOfType,

LPSTR * pszUserTypeA)

{

TraceMethodEnter("COleObjectA::GetUserType", this);

LPOLESTR lpszUserType;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IOleObject, GetUserType));

hResult = GetWide()->GetUserType(dwFormOfType, &lpszUserType);

if (FAILED(hResult) || hResult == OLE_S_USEREG)

return (hResult);

hResult = ConvertStringToA(lpszUserType, pszUserTypeA);

ConvertStringFree(lpszUserType);

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     COleObjectA::SetExtent, public

//

//  Synopsis:   Thunks SetExtent to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleObjectA::SetExtent(DWORD dwDrawAspect, LPSIZEL lpsizel)

{

TraceMethodEnter("COleObjectA::SetExtent", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleObject, SetExtent));

return GetWide()->SetExtent(dwDrawAspect, lpsizel);

}

//+--------------------------------------------------------------------------

//

//  Member:     COleObjectA::GetExtent, public

//

//  Synopsis:   Thunks GetExtent to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleObjectA::GetExtent(DWORD dwDrawAspect, LPSIZEL lpsizel)

{

TraceMethodEnter("COleObjectA::GetExtent", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleObject, GetExtent));

return GetWide()->GetExtent(dwDrawAspect, lpsizel);

}

//+--------------------------------------------------------------------------

//

//  Member:     COleObjectA::Advise, public

//

//  Synopsis:   Thunks Advise to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleObjectA::Advise(LPADVISESINKA pAdvSinkA,

DWORD * pdwConnection)

{

TraceMethodEnter("COleObjectA::Advise", this);

LPADVISESINK pAdvSink;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IOleObject, Advise));

hResult = WrapIAdviseSinkWFromA(pAdvSinkA, &pAdvSink);

if (FAILED(hResult))

return (hResult);

hResult = GetWide()->Advise(pAdvSink, pdwConnection);

if (pAdvSink)

pAdvSink->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     COleObjectA::Unadvise, public

//

//  Synopsis:   Thunks Unadvise to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleObjectA::Unadvise(DWORD dwConnection)

{

TraceMethodEnter("COleObjectA::Unadvise", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleObject, Unadvise));

return GetWide()->Unadvise(dwConnection);

}

//+--------------------------------------------------------------------------

//

//  Member:     COleObjectA::EnumAdvise, public

//

//  Synopsis:   Thunks EnumAdvise to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleObjectA::EnumAdvise(LPENUMSTATDATAA * ppenumAdviseA)

{

TraceMethodEnter("COleObjectA::EnumAdvise", this);

LPENUMSTATDATA penumAdvise = NULL;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IOleObject, EnumAdvise));

hResult = GetWide()->EnumAdvise(&penumAdvise);

if (FAILED(hResult))

return (hResult);

if (penumAdvise)

{

hResult = WrapIEnumSTATDATAAFromW(penumAdvise, ppenumAdviseA);

penumAdvise->Release();

}

else

*ppenumAdviseA = NULL;

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     COleObjectA::GetMiscStatus, public

//

//  Synopsis:   Thunks GetMiscStatus to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleObjectA::GetMiscStatus(DWORD dwAspect, DWORD * pdwStatus)

{

TraceMethodEnter("COleObjectA::GetMiscStatus", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleObject, GetMiscStatus));

return GetWide()->GetMiscStatus(dwAspect, pdwStatus);

}

//+--------------------------------------------------------------------------

//

//  Member:     COleObjectA::SetColorScheme, public

//

//  Synopsis:   Thunks SetColorScheme to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleObjectA::SetColorScheme(LPLOGPALETTE lpLogpal)

{

TraceMethodEnter("COleObjectA::SetColorScheme", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleObject, SetColorScheme));

return GetWide()->SetColorScheme(lpLogpal);

}


 IOleClientSiteA Implementation  (OLEANSI Sample)

//***************************************************************************

//

//                   IOleClientSiteA Implementation

//

//***************************************************************************

//+--------------------------------------------------------------------------

//

//  Member:     COleClientSiteA::SaveObject, public

//

//  Synopsis:   Thunks SaveObject to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleClientSiteA::SaveObject(VOID)

{

TraceMethodEnter("COleClientSiteA::SaveObject", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleClientSite, SaveObject));

return GetWide()->SaveObject();

}

//+--------------------------------------------------------------------------

//

//  Member:     COleClientSiteA::GetMoniker, public

//

//  Synopsis:   Thunks GetMoniker to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleClientSiteA::GetMoniker(DWORD dwAssign,

DWORD dwWhichMoniker, LPMONIKERA * ppmkA)

{

TraceMethodEnter("COleClientSiteA::GetMoniker", this);

LPMONIKER pmk;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IOleClientSite, GetMoniker));

*ppmkA = NULL;

hResult = GetWide()->GetMoniker(dwAssign, dwWhichMoniker, &pmk);

if (FAILED(hResult))

return (hResult);

hResult = WrapIMonikerAFromW(pmk, ppmkA);

if (pmk)

pmk->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     COleClientSiteA::GetContainer, public

//

//  Synopsis:   Thunks GetContainer to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleClientSiteA::GetContainer(LPOLECONTAINERA * ppContainerA)

{

TraceMethodEnter("COleClientSiteA::GetContainer", this);

LPOLECONTAINER pContainer;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IOleClientSite, GetContainer));

*ppContainerA = NULL;

hResult = GetWide()->GetContainer(&pContainer);

if (FAILED(hResult))

{

*ppContainerA = NULL;

return (hResult);

}

hResult = WrapIOleContainerAFromW(pContainer, ppContainerA);

if (pContainer)

pContainer->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     COleClientSiteA::ShowObject, public

//

//  Synopsis:   Thunks ShowObject to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleClientSiteA::ShowObject(VOID)

{

TraceMethodEnter("COleClientSiteA::ShowObject", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleClientSite, ShowObject));

return GetWide()->ShowObject();

}

//+--------------------------------------------------------------------------

//

//  Member:     COleClientSiteA::OnShowWindow, public

//

//  Synopsis:   Thunks OnShowWindow to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleClientSiteA::OnShowWindow(BOOL fShow)

{

TraceMethodEnter("COleClientSiteA::OnShowWindow", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleClientSite, OnShowWindow));

return GetWide()->OnShowWindow(fShow);

}

//+--------------------------------------------------------------------------

//

//  Member:     COleClientSiteA::RequestNewObjectLayout, public

//

//  Synopsis:   Thunks RequestNewObjectLayout to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleClientSiteA::RequestNewObjectLayout(VOID)

{

TraceMethodEnter("COleClientSiteA::RequestNewObjectLayout", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleClientSite, RequestNewObjectLayout));

return GetWide()->RequestNewObjectLayout();

}


 IRunnableObjectA Implementation  (OLEANSI Sample)

//***************************************************************************

//

//                   IRunnableObjectA Implementation

//

//***************************************************************************

//+--------------------------------------------------------------------------

//

//  Member:     CRunnableObjectA::GetRunningClass, public

//

//  Synopsis:   Thunks GetRunningClass to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CRunnableObjectA::GetRunningClass(LPCLSID lpClsid)

{

_DebugHook(GetWide(), MEMBER_PTR(IRunnableObject, GetRunningClass));

return GetWide()->GetRunningClass(lpClsid);

}

//+--------------------------------------------------------------------------

//

//  Member:     CRunnableObjectA::Run, public

//

//  Synopsis:   Thunks Run to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CRunnableObjectA::Run(LPBINDCTXA pbcA)

{

TraceMethodEnter("CRunnableObjectA::Run", this);

LPBINDCTX pbc;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IRunnableObject, Run));

hResult = WrapIBindCtxWFromA(pbcA, &pbc);

if (FAILED(hResult))

return (hResult);

hResult = GetWide()->Run(pbc);

if (pbc)

pbc->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CRunnableObjectA::IsRunning, public

//

//  Synopsis:   Thunks IsRunning to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP_(BOOL) CRunnableObjectA::IsRunning(VOID)

{

_DebugHook(GetWide(), MEMBER_PTR(IRunnableObject, IsRunning));

return GetWide()->IsRunning();

}

//+--------------------------------------------------------------------------

//

//  Member:     CRunnableObjectA::LockRunning, public

//

//  Synopsis:   Thunks LockRunning to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CRunnableObjectA::LockRunning(BOOL fLock,

BOOL fLastUnlockCloses)

{

_DebugHook(GetWide(), MEMBER_PTR(IRunnableObject, LockRunning));

return GetWide()->LockRunning(fLock, fLastUnlockCloses);

}

//+--------------------------------------------------------------------------

//

//  Member:     CRunnableObjectA::SetContainedObject, public

//

//  Synopsis:   Thunks SetContainedObject to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CRunnableObjectA::SetContainedObject(BOOL fContained)

{

_DebugHook(GetWide(), MEMBER_PTR(IRunnableObject, SetContainedObject));

return GetWide()->SetContainedObject(fContained);

}


 ANSIOLE2.CPP  (OLEANSI Sample)

//+--------------------------------------------------------------------------

//

//  Copyright (C) 1994, Microsoft Corporation.  All Rights Reserved.

//

//  File:       ansiole1.cpp

//

//  Contents:   ANSI Wrappers for Unicode Ole2 Interfaces and APIs.

//

//  Classes:    COleItemContainerA

//              COleAdviseHolderA

//              COleLinkA

//              COleInPlaceObjectA

//              COleInPlaceActiveObjectA

//              COleInPlaceFrameA

//              COleInPlaceSiteA

//

//  History:    01-Nov-93   v-kentc     Created.

//

//---------------------------------------------------------------------------

#include "Ole2Ansi.h"


 IOleItemContainerA Implementation  (OLEANSI Sample)

//***************************************************************************

//

//                   IOleItemContainerA Implementation

//

//***************************************************************************

//+--------------------------------------------------------------------------

//

//  Member:     COleItemContainerA::ParseDisplayName, public

//

//  Synopsis:   Thunks ParseDisplayName to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleItemContainerA::ParseDisplayName(LPBCA pbcA,

LPSTR lpszDisplayNameA, ULONG * pchEaten, LPMONIKERA * ppmkOutA)

{

TraceMethodEnter("COleItemContainerA::ParseDisplayName", this);

LPBC pbc;

LPOLESTR lpszDisplayName;

LPMONIKER pmk;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IParseDisplayName, ParseDisplayName));

*ppmkOutA = NULL;

hResult = WrapIBindCtxWFromA(pbcA, &pbc);

if (FAILED(hResult))

return (hResult);

hResult = ConvertStringToW(lpszDisplayNameA, &lpszDisplayName);

if (FAILED(hResult))

goto Error;

hResult = GetWide()->ParseDisplayName(pbc, lpszDisplayName, pchEaten, &pmk);

if (FAILED(hResult))

goto Error1;

hResult = WrapIMonikerAFromW(pmk, ppmkOutA);

if (pmk)

pmk->Release();

Error1:

ConvertStringFree(lpszDisplayName);

Error:

if (pbc)

pbc->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     COleItemContainerA::EnumObjects, public

//

//  Synopsis:   Thunks EnumObjects to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleItemContainerA::EnumObjects(DWORD grfFlags,

LPENUMUNKNOWN * ppenumUnknown)

{

TraceMethodEnter("COleItemContainerA::EnumObjects", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleContainer, EnumObjects));

return GetWide()->EnumObjects(grfFlags, ppenumUnknown);

}

//+--------------------------------------------------------------------------

//

//  Member:     COleItemContainerA::LockContainer, public

//

//  Synopsis:   Thunks LockContainer to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleItemContainerA::LockContainer(BOOL fLock)

{

TraceMethodEnter("COleItemContainerA::LockContainer", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleContainer, LockContainer));

return GetWide()->LockContainer(fLock);

}

//+--------------------------------------------------------------------------

//

//  Member:     COleItemContainerA::GetObject, public

//

//  Synopsis:   Thunks GetObject to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleItemContainerA::GetObject(LPSTR lpszItemA,

DWORD dwSpeedNeeded, LPBINDCTXA pbcA, REFIID riid,

LPVOID * ppvObject)

{

TraceMethodEnter("COleItemContainerA::GetObject", this);

LPOLESTR lpszItem;

LPBINDCTX   pbc;

LPUNKNOWN   punk;

IDINTERFACE idRef;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IOleItemContainer, GetObject));

hResult = ConvertStringToW(lpszItemA, &lpszItem);

if (FAILED(hResult))

return (hResult);

hResult = WrapIBindCtxWFromA(pbcA, &pbc);

if (FAILED(hResult))

goto Error;

hResult = GetWide()->GetObject(lpszItem, dwSpeedNeeded, pbc, riid,

(LPVOID *)&punk);

if (FAILED(hResult))

goto Error1;

idRef = WrapTranslateIID(riid);

hResult = WrapInterfaceAFromW(idRef, punk, (LPUNKNOWN *)ppvObject);

if (punk)

punk->Release();

Error1:

if (pbc)

pbc->Release();

Error:

ConvertStringFree(lpszItem);

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     COleItemContainerA::GetObjectStorage, public

//

//  Synopsis:   Thunks GetObjectStorage to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleItemContainerA::GetObjectStorage(LPSTR lpszItemA,

LPBINDCTXA pbcA, REFIID riid, LPVOID * ppvStorage)

{

TraceMethodEnter("COleItemContainerA::GetObjectStorage", this);

LPOLESTR lpszItem;

LPBINDCTX   pbc;

LPUNKNOWN   punk;

IDINTERFACE idRef;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IOleItemContainer, GetObjectStorage));

hResult = ConvertStringToW(lpszItemA, &lpszItem);

if (FAILED(hResult))

return (hResult);

hResult = WrapIBindCtxWFromA(pbcA, &pbc);

if (FAILED(hResult))

goto Error;

hResult = GetWide()->GetObjectStorage(lpszItem, pbc, riid, (LPVOID *)&punk);

if (FAILED(hResult))

goto Error1;

idRef = WrapTranslateIID(riid);

hResult = WrapInterfaceAFromW(idRef, punk, (LPUNKNOWN *)ppvStorage);

if (punk)

punk->Release();

Error1:

if (pbc)

pbc->Release();

Error:

ConvertStringFree(lpszItem);

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     COleItemContainerA::IsRunning, public

//

//  Synopsis:   Thunks IsRunning to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleItemContainerA::IsRunning(LPSTR lpszItemA)

{

TraceMethodEnter("COleItemContainerA::IsRunning", this);

LPOLESTR lpszItem;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IOleItemContainer, IsRunning));

hResult = ConvertStringToW(lpszItemA, &lpszItem);

if (FAILED(hResult))

return (hResult);

hResult = GetWide()->IsRunning(lpszItem);

ConvertStringFree(lpszItem);

return hResult;

}


 IOleAdviseHolderA Implementation  (OLEANSI Sample)

//***************************************************************************

//

//                   IOleAdviseHolderA Implementation

//

//***************************************************************************

//+--------------------------------------------------------------------------

//

//  Member:     COleAdviseHolderA::Advise, public

//

//  Synopsis:   Thunks Advise to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleAdviseHolderA::Advise(LPADVISESINKA pAdviseA,

DWORD * pdwConnection)

{

TraceMethodEnter("COleAdviseHolderA::Advise", this);

LPADVISESINK pAdvise;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IOleAdviseHolder, Advise));

hResult = WrapIAdviseSinkWFromA(pAdviseA, &pAdvise);

if (FAILED(hResult))

return hResult;

hResult =  GetWide()->Advise(pAdvise, pdwConnection);

if (pAdvise)

pAdvise->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     COleAdviseHolderA::Unadvise, public

//

//  Synopsis:   Thunks Unadvise to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleAdviseHolderA::Unadvise(DWORD dwConnection)

{

TraceMethodEnter("COleAdviseHolderA::Unadvise", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleAdviseHolder, Unadvise));

return GetWide()->Unadvise(dwConnection);

}

//+--------------------------------------------------------------------------

//

//  Member:     COleAdviseHolderA::EnumAdvise, public

//

//  Synopsis:   Thunks EnumAdvise to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleAdviseHolderA::EnumAdvise(LPENUMSTATDATAA * ppenumAdviseA)

{

TraceMethodEnter("COleAdviseHolderA::EnumAdvise", this);

LPENUMSTATDATA penumAdvise = NULL;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IOleAdviseHolder, EnumAdvise));

hResult = GetWide()->EnumAdvise(&penumAdvise);

if (FAILED(hResult))

return (hResult);

if (penumAdvise)

{

hResult = WrapIEnumSTATDATAAFromW(penumAdvise, ppenumAdviseA);

penumAdvise->Release();

}

else

*ppenumAdviseA = NULL;

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     COleAdviseHolderA::SendOnRename, public

//

//  Synopsis:   Thunks SendOnRename to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleAdviseHolderA::SendOnRename(LPMONIKERA pmkA)

{

TraceMethodEnter("COleAdviseHolderA::SendOnRename", this);

LPMONIKER pmk;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IOleAdviseHolder, SendOnRename));

hResult = WrapIMonikerWFromA(pmkA, &pmk);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->SendOnRename(pmk);

if (pmk)

pmk->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     COleAdviseHolderA::SendOnSave, public

//

//  Synopsis:   Thunks SendOnSave to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleAdviseHolderA::SendOnSave(VOID)

{

TraceMethodEnter("COleAdviseHolderA::SendOnSave", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleAdviseHolder, SendOnSave));

return GetWide()->SendOnSave();

}

//+--------------------------------------------------------------------------

//

//  Member:     COleAdviseHolderA::SendOnClose, public

//

//  Synopsis:   Thunks SendOnClose to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleAdviseHolderA::SendOnClose(VOID)

{

TraceMethodEnter("COleAdviseHolderA::SendOnClose", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleAdviseHolder, SendOnClose));

return GetWide()->SendOnClose();

}


 IOleLinkA Implementation  (OLEANSI Sample)

//***************************************************************************

//

//                   IOleLinkA Implementation

//

//***************************************************************************

//+--------------------------------------------------------------------------

//

//  Member:     COleLinkA::SetUpdateOptions, public

//

//  Synopsis:   Thunks SetUpdateOptions to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleLinkA::SetUpdateOptions(DWORD dwUpdateOpt)

{

TraceMethodEnter("COleLinkA::SetUpdateOptions", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleLink, SetUpdateOptions));

return GetWide()->SetUpdateOptions(dwUpdateOpt);

}

//+--------------------------------------------------------------------------

//

//  Member:     COleLinkA::GetUpdateOptions, public

//

//  Synopsis:   Thunks GetUpdateOptions to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleLinkA::GetUpdateOptions(LPDWORD pdwUpdateOpt)

{

TraceMethodEnter("COleLinkA::GetUpdateOptions", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleLink, GetUpdateOptions));

return GetWide()->GetUpdateOptions(pdwUpdateOpt);

}

//+--------------------------------------------------------------------------

//

//  Member:     COleLinkA::SetSourceMoniker, public

//

//  Synopsis:   Thunks SetSourceMoniker to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleLinkA::SetSourceMoniker(LPMONIKERA pmkA, REFCLSID rclsid)

{

TraceMethodEnter("COleLinkA::SetSourceMoniker", this);

LPMONIKER pmk;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IOleLink, SetSourceMoniker));

hResult = WrapIMonikerWFromA(pmkA, &pmk);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->SetSourceMoniker(pmk, rclsid);

if (pmk)

pmk->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     COleLinkA::GetSourceMoniker, public

//

//  Synopsis:   Thunks GetSourceMoniker to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleLinkA::GetSourceMoniker(LPMONIKERA * ppmkA)

{

TraceMethodEnter("COleLinkA::GetSourceMoniker", this);

LPMONIKER pmk;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IOleLink, GetSourceMoniker));

*ppmkA = NULL;

hResult = GetWide()->GetSourceMoniker(&pmk);

if (FAILED(hResult))

return (hResult);

hResult = WrapIMonikerAFromW(pmk, ppmkA);

if (pmk)

pmk->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     COleLinkA::SetSourceDisplayName, public

//

//  Synopsis:   Thunks SetSourceDisplayName to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleLinkA::SetSourceDisplayName(LPCSTR lpszDisplayNameA)

{

TraceMethodEnter("COleLinkA::SetSourceDisplayName", this);

LPOLESTR lpszDisplayName;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IOleLink, SetSourceDisplayName));

hResult = ConvertStringToW(lpszDisplayNameA, &lpszDisplayName);

if (FAILED(hResult))

return (hResult);

hResult = GetWide()->SetSourceDisplayName(lpszDisplayName);

ConvertStringFree(lpszDisplayName);

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     COleLinkA::GetSourceDisplayName, public

//

//  Synopsis:   Thunks GetSourceDisplayName to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleLinkA::GetSourceDisplayName(LPSTR * lplpszDisplayNameA)

{

TraceMethodEnter("COleLinkA::GetSourceDisplayName", this);

LPOLESTR lpszDisplayName;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IOleLink, GetSourceDisplayName));

hResult = GetWide()->GetSourceDisplayName(&lpszDisplayName);

if (FAILED(hResult))

return (hResult);

hResult = ConvertStringToA(lpszDisplayName, lplpszDisplayNameA);

ConvertStringFree(lpszDisplayName);

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     COleLinkA::BindToSource, public

//

//  Synopsis:   Thunks BindToSource to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleLinkA::BindToSource(DWORD bindflags, LPBINDCTXA pbcA)

{

TraceMethodEnter("COleLinkA::BindToSource", this);

LPBINDCTX pbc;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IOleLink, BindToSource));

hResult = WrapIBindCtxWFromA(pbcA, &pbc);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->BindToSource(bindflags, pbc);

if (pbc)

pbc->Release();

TraceMethodExit("COleLinkA::BindToSource", this, hResult);

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     COleLinkA::BindIfRunning, public

//

//  Synopsis:   Thunks BindIfRunning to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleLinkA::BindIfRunning(VOID)

{

TraceMethodEnter("COleLinkA::BindIfRunning", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleLink, BindIfRunning));

return GetWide()->BindIfRunning();

}

//+--------------------------------------------------------------------------

//

//  Member:     COleLinkA::GetBoundSource, public

//

//  Synopsis:   Thunks GetBoundSource to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleLinkA::GetBoundSource(LPUNKNOWN * ppUnk)

{

TraceMethodEnter("COleLinkA::GetBoundSource", this);

LPUNKNOWN punk;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IOleLink, GetBoundSource));

hResult = GetWide()->GetBoundSource(&punk);

if (FAILED(hResult))

return hResult;

hResult = WrapIUnknownAFromW(punk, ppUnk);

punk->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     COleLinkA::UnbindSource, public

//

//  Synopsis:   Thunks UnbindSource to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleLinkA::UnbindSource(VOID)

{

TraceMethodEnter("COleLinkA::UnbindSource", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleLink, UnbindSource));

return GetWide()->UnbindSource();

}

//+--------------------------------------------------------------------------

//

//  Member:     COleLinkA::Update, public

//

//  Synopsis:   Thunks Update to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleLinkA::Update(LPBINDCTXA pbcA)

{

TraceMethodEnter("COleLinkA::Update", this);

LPBINDCTX pbc;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IOleLink, Update));

hResult = WrapIBindCtxWFromA(pbcA, &pbc);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->Update(pbc);

if (pbc)

pbc->Release();

return hResult;

}


 IOleInPlaceObjectA Implementation  (OLEANSI Sample)

//***************************************************************************

//

//                   IOleInPlaceObjectA Implementation

//

//***************************************************************************

//+--------------------------------------------------------------------------

//

//  Member:     COleInPlaceObjectA::GetWindow, public

//

//  Synopsis:   Thunks GetWindow to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleInPlaceObjectA::GetWindow(HWND * lphwnd)

{

TraceMethodEnter("COleInPlaceObjectA::GetWindow", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleWindow, GetWindow));

return GetWide()->GetWindow(lphwnd);

}

//+--------------------------------------------------------------------------

//

//  Member:     COleInPlaceObjectA::ContextSensitiveHelp, public

//

//  Synopsis:   Thunks ContextSensitiveHelp to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleInPlaceObjectA::ContextSensitiveHelp(BOOL fEnterMode)

{

TraceMethodEnter("COleInPlaceObjectA::ContextSensitiveHelp", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleWindow, ContextSensitiveHelp));

return GetWide()->ContextSensitiveHelp(fEnterMode);

}

//+--------------------------------------------------------------------------

//

//  Member:     COleInPlaceObjectA::InPlaceDeactivate, public

//

//  Synopsis:   Thunks InPlaceDeactivate to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleInPlaceObjectA::InPlaceDeactivate(VOID)

{

TraceMethodEnter("COleInPlaceObjectA::InPlaceDeactivate", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleInPlaceObject, InPlaceDeactivate));

return GetWide()->InPlaceDeactivate();

}

//+--------------------------------------------------------------------------

//

//  Member:     COleInPlaceObjectA::UIDeactivate, public

//

//  Synopsis:   Thunks UIDeactivate to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleInPlaceObjectA::UIDeactivate(VOID)

{

TraceMethodEnter("COleInPlaceObjectA::UIDeactivate", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleInPlaceObject, UIDeactivate));

return GetWide()->UIDeactivate();

}

//+--------------------------------------------------------------------------

//

//  Member:     COleInPlaceObjectA::SetObjectRects, public

//

//  Synopsis:   Thunks SetObjectRects to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleInPlaceObjectA::SetObjectRects(LPCRECT lprcPosRect,

LPCRECT lprcClipRect)

{

TraceMethodEnter("COleInPlaceObjectA::SetObjectRects", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleInPlaceObject, SetObjectRects));

return GetWide()->SetObjectRects(lprcPosRect, lprcClipRect);

}

//+--------------------------------------------------------------------------

//

//  Member:     COleInPlaceObjectA::ReactivateAndUndo, public

//

//  Synopsis:   Thunks ReactivateAndUndo to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleInPlaceObjectA::ReactivateAndUndo(VOID)

{

TraceMethodEnter("COleInPlaceObjectA::ReactivateAndUndo", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleInPlaceObject, ReactivateAndUndo));

return GetWide()->ReactivateAndUndo();

}


 IOleInPlaceActiveObjectA Implementation  (OLEANSI Sample)

//***************************************************************************

//

//                   IOleInPlaceActiveObjectA Implementation

//

//***************************************************************************

//+--------------------------------------------------------------------------

//

//  Member:     COleInPlaceActiveObjectA::GetWindow, public

//

//  Synopsis:   Thunks GetWindow to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleInPlaceActiveObjectA::GetWindow(HWND * lphwnd)

{

TraceMethodEnter("COleInPlaceActiveObjectA::GetWindow", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleWindow, GetWindow));

return GetWide()->GetWindow(lphwnd);

}

//+--------------------------------------------------------------------------

//

//  Member:     COleInPlaceActiveObjectA::ContextSensitiveHelp, public

//

//  Synopsis:   Thunks ContextSensitiveHelp to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleInPlaceActiveObjectA::ContextSensitiveHelp(BOOL fEnterMode)

{

TraceMethodEnter("COleInPlaceActiveObjectA::ContextSensitiveHelp", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleWindow, ContextSensitiveHelp));

return GetWide()->ContextSensitiveHelp(fEnterMode);

}

//+--------------------------------------------------------------------------

//

//  Member:     COleInPlaceActiveObjectA::TranslateAccelerator, public

//

//  Synopsis:   Thunks TranslateAccelerator to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleInPlaceActiveObjectA::TranslateAccelerator(LPMSG lpmsg)

{

TraceMethodEnter("COleInPlaceActiveObjectA::TranslateAccelerator", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleInPlaceActiveObject, TranslateAccelerator));

return GetWide()->TranslateAccelerator(lpmsg);

}

//+--------------------------------------------------------------------------

//

//  Member:     COleInPlaceActiveObjectA::OnFrameWindowActivate, public

//

//  Synopsis:   Thunks OnFrameWindowActivate to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleInPlaceActiveObjectA::OnFrameWindowActivate(BOOL fActivate)

{

TraceMethodEnter("COleInPlaceActiveObjectA::OnFrameWindowActivate", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleInPlaceActiveObject, OnFrameWindowActivate));

return GetWide()->OnFrameWindowActivate(fActivate);

}

//+--------------------------------------------------------------------------

//

//  Member:     COleInPlaceActiveObjectA::OnDocWindowActivate, public

//

//  Synopsis:   Thunks OnDocWindowActivate to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleInPlaceActiveObjectA::OnDocWindowActivate(BOOL fActivate)

{

TraceMethodEnter("COleInPlaceActiveObjectA::OnDocWindowActivate", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleInPlaceActiveObject, OnDocWindowActivate));

return GetWide()->OnDocWindowActivate(fActivate);

}

//+--------------------------------------------------------------------------

//

//  Member:     COleInPlaceActiveObjectA::ResizeBorder, public

//

//  Synopsis:   Thunks ResizeBorder to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleInPlaceActiveObjectA::ResizeBorder(LPCRECT lprectBorder,

LPOLEINPLACEUIWINDOWA lpUIWindowA, BOOL fFrameWindow)

{

TraceMethodEnter("COleInPlaceActiveObjectA::ResizeBorder", this);

LPOLEINPLACEUIWINDOW lpUIWindow;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IOleInPlaceActiveObject, ResizeBorder));

hResult = WrapIOleInPlaceUIWindowWFromA(lpUIWindowA, &lpUIWindow);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->ResizeBorder(lprectBorder, lpUIWindow, fFrameWindow);

if (lpUIWindow)

lpUIWindow->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     COleInPlaceActiveObjectA::EnableModeless, public

//

//  Synopsis:   Thunks EnableModeless to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleInPlaceActiveObjectA::EnableModeless(BOOL fEnable)

{

TraceMethodEnter("COleInPlaceActiveObjectA::EnableModeless", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleInPlaceActiveObject, EnableModeless));

return GetWide()->EnableModeless(fEnable);

}


 IOleInPlaceFrameA Implementation  (OLEANSI Sample)

//***************************************************************************

//

//                   IOleInPlaceFrameA Implementation

//

//***************************************************************************

//+--------------------------------------------------------------------------

//

//  Member:     COleInPlaceFrameA::GetWindow, public

//

//  Synopsis:   Thunks GetWindow to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleInPlaceFrameA::GetWindow(HWND * lphwnd)

{

TraceMethodEnter("COleInPlaceFrameA::GetWindow", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleWindow, GetWindow));

return GetWide()->GetWindow(lphwnd);

}

//+--------------------------------------------------------------------------

//

//  Member:     COleInPlaceFrameA::ContextSensitiveHelp, public

//

//  Synopsis:   Thunks ContextSensitiveHelp to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleInPlaceFrameA::ContextSensitiveHelp(BOOL fEnterMode)

{

TraceMethodEnter("COleInPlaceFrameA::ContextSensitiveHelp", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleWindow, ContextSensitiveHelp));

return GetWide()->ContextSensitiveHelp(fEnterMode);

}

//+--------------------------------------------------------------------------

//

//  Member:     COleInPlaceFrameA::GetBorder, public

//

//  Synopsis:   Thunks GetBorder to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleInPlaceFrameA::GetBorder(LPRECT lprectBorder)

{

TraceMethodEnter("COleInPlaceFrameA::GetBorder", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleInPlaceUIWindow, GetBorder));

return GetWide()->GetBorder(lprectBorder);

}

//+--------------------------------------------------------------------------

//

//  Member:     COleInPlaceFrameA::RequestBorderSpace, public

//

//  Synopsis:   Thunks RequestBorderSpace to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleInPlaceFrameA::RequestBorderSpace(

LPCBORDERWIDTHS lpborderwidths)

{

TraceMethodEnter("COleInPlaceFrameA::RequestBorderSpace", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleInPlaceUIWindow, RequestBorderSpace));

return GetWide()->RequestBorderSpace(lpborderwidths);

}

//+--------------------------------------------------------------------------

//

//  Member:     COleInPlaceFrameA::SetBorderSpace, public

//

//  Synopsis:   Thunks SetBorderSpace to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleInPlaceFrameA::SetBorderSpace(

LPCBORDERWIDTHS lpborderwidths)

{

TraceMethodEnter("COleInPlaceFrameA::SetBorderSpace", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleInPlaceUIWindow, SetBorderSpace));

return GetWide()->SetBorderSpace(lpborderwidths);

}

//+--------------------------------------------------------------------------

//

//  Member:     COleInPlaceFrameA::SetActiveObject, public

//

//  Synopsis:   Thunks SetActiveObject to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleInPlaceFrameA::SetActiveObject(

LPOLEINPLACEACTIVEOBJECTA lpActiveObjectA, LPCSTR lpszObjNameA)

{

TraceMethodEnter("COleInPlaceFrameA::SetActiveObject", this);

LPOLEINPLACEACTIVEOBJECT lpActiveObject;

LPOLESTR lpszObjName;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IOleInPlaceUIWindow, SetActiveObject));

hResult = WrapIOleInPlaceActiveObjectWFromA(lpActiveObjectA, &lpActiveObject);

if (FAILED(hResult))

return hResult;

hResult = ConvertStringToW(lpszObjNameA, &lpszObjName);

if (FAILED(hResult))

goto Error;

hResult = GetWide()->SetActiveObject(lpActiveObject, lpszObjName);

ConvertStringFree(lpszObjName);

Error:

if (lpActiveObject)

lpActiveObject->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     COleInPlaceFrameA::InsertMenus, public

//

//  Synopsis:   Thunks InsertMenus to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleInPlaceFrameA::InsertMenus(HMENU hmenuShared,

LPOLEMENUGROUPWIDTHS lpMenuWidths)

{

TraceMethodEnter("COleInPlaceFrameA::InsertMenus", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleInPlaceFrame, InsertMenus));

return GetWide()->InsertMenus(hmenuShared, lpMenuWidths);

}

//+--------------------------------------------------------------------------

//

//  Member:     COleInPlaceFrameA::SetMenu, public

//

//  Synopsis:   Thunks SetMenu to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleInPlaceFrameA::SetMenu(HMENU hmenuShared, HOLEMENU holemenu,

HWND hwndActiveObject)

{

TraceMethodEnter("COleInPlaceFrameA::SetMenu", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleInPlaceFrame, SetMenu));

return GetWide()->SetMenu(hmenuShared, holemenu, hwndActiveObject);

}

//+--------------------------------------------------------------------------

//

//  Member:     COleInPlaceFrameA::RemoveMenus, public

//

//  Synopsis:   Thunks RemoveMenus to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleInPlaceFrameA::RemoveMenus(HMENU hmenuShared)

{

TraceMethodEnter("COleInPlaceFrameA::RemoveMenus", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleInPlaceFrame, RemoveMenus));

return GetWide()->RemoveMenus(hmenuShared);

}

//+--------------------------------------------------------------------------

//

//  Member:     COleInPlaceFrameA::SetStatusText, public

//

//  Synopsis:   Thunks SetStatusText to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleInPlaceFrameA::SetStatusText(LPCSTR lpszStatusTextA)

{

TraceMethodEnter("COleInPlaceFrameA::SetStatusText", this);

LPOLESTR lpszStatusText;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IOleInPlaceFrame, SetStatusText));

hResult = ConvertStringToW(lpszStatusTextA, &lpszStatusText);

if (FAILED(hResult))

return (hResult);

hResult = GetWide()->SetStatusText(lpszStatusText);

ConvertStringFree(lpszStatusText);

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     COleInPlaceFrameA::EnableModeless, public

//

//  Synopsis:   Thunks EnableModeless to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleInPlaceFrameA::EnableModeless(BOOL fEnable)

{

TraceMethodEnter("COleInPlaceFrameA::EnableModeless", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleInPlaceFrame, EnableModeless));

return GetWide()->EnableModeless(fEnable);

}

//+--------------------------------------------------------------------------

//

//  Member:     COleInPlaceFrameA::TranslateAccelerator, public

//

//  Synopsis:   Thunks TranslateAccelerator to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleInPlaceFrameA::TranslateAccelerator(LPMSG lpmsg, WORD wID)

{

TraceMethodEnter("COleInPlaceFrameA::TranslateAccelerator", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleInPlaceFrame, TranslateAccelerator));

return GetWide()->TranslateAccelerator(lpmsg, wID);

}


 IOleInPlaceSiteA Implementation  (OLEANSI Sample)

//***************************************************************************

//

//                   IOleInPlaceSiteA Implementation

//

//***************************************************************************

//+--------------------------------------------------------------------------

//

//  Member:     COleInPlaceSiteA::GetWindow, public

//

//  Synopsis:   Thunks GetWindow to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleInPlaceSiteA::GetWindow(HWND * lphwnd)

{

TraceMethodEnter("COleInPlaceSiteA::GetWindow", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleWindow, GetWindow));

return GetWide()->GetWindow(lphwnd);

}

//+--------------------------------------------------------------------------

//

//  Member:     COleInPlaceSiteA::ContextSensitiveHelp, public

//

//  Synopsis:   Thunks ContextSensitiveHelp to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleInPlaceSiteA::ContextSensitiveHelp(BOOL fEnterMode)

{

TraceMethodEnter("COleInPlaceSiteA::ContextSensitiveHelp", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleWindow, ContextSensitiveHelp));

return GetWide()->ContextSensitiveHelp(fEnterMode);

}

//+--------------------------------------------------------------------------

//

//  Member:     COleInPlaceSiteA::CanInPlaceActivate, public

//

//  Synopsis:   Thunks CanInPlaceActivate to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleInPlaceSiteA::CanInPlaceActivate(VOID)

{

TraceMethodEnter("COleInPlaceSiteA::CanInPlaceActivate", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleInPlaceSite, CanInPlaceActivate));

return GetWide()->CanInPlaceActivate();

}

//+--------------------------------------------------------------------------

//

//  Member:     COleInPlaceSiteA::OnInPlaceActivate, public

//

//  Synopsis:   Thunks OnInPlaceActivate to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleInPlaceSiteA::OnInPlaceActivate(VOID)

{

TraceMethodEnter("COleInPlaceSiteA::OnInPlaceActivate", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleInPlaceSite, OnInPlaceActivate));

return GetWide()->OnInPlaceActivate();

}

//+--------------------------------------------------------------------------

//

//  Member:     COleInPlaceSiteA::OnUIActivate, public

//

//  Synopsis:   Thunks OnUIActivate to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleInPlaceSiteA::OnUIActivate(VOID)

{

TraceMethodEnter("COleInPlaceSiteA::OnUIActivate", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleInPlaceSite, OnUIActivate));

return GetWide()->OnUIActivate();

}

//+--------------------------------------------------------------------------

//

//  Member:     COleInPlaceSiteA::GetWindowContext, public

//

//  Synopsis:   Thunks GetWindowContext to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleInPlaceSiteA::GetWindowContext(

LPOLEINPLACEFRAMEA * lplpFrameA, LPOLEINPLACEUIWINDOWA * lplpDocA,

LPRECT lprcPosRect, LPRECT lprcClipRect,

LPOLEINPLACEFRAMEINFO lpFrameInfo)

{

TraceMethodEnter("COleInPlaceSiteA::GetWindowContext", this);

LPOLEINPLACEFRAME lpFrame;

LPOLEINPLACEUIWINDOW lpDoc;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IOleInPlaceSite, GetWindowContext));

*lplpFrameA = NULL;

*lplpDocA = NULL;

hResult = GetWide()->GetWindowContext(&lpFrame, &lpDoc, lprcPosRect,

lprcClipRect, lpFrameInfo);

if (FAILED(hResult))

goto Error;

hResult = WrapIOleInPlaceFrameAFromW(lpFrame, lplpFrameA);

if (FAILED(hResult))

goto Error1;

hResult = WrapIOleInPlaceUIWindowAFromW(lpDoc, lplpDocA);

Error:

if (lpFrame)

lpFrame->Release();

Error1:

if (lpDoc)

lpDoc->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     COleInPlaceSiteA::Scroll, public

//

//  Synopsis:   Thunks Scroll to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleInPlaceSiteA::Scroll(SIZE scrollExtent)

{

TraceMethodEnter("COleInPlaceSiteA::Scroll", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleInPlaceSite, Scroll));

return GetWide()->Scroll(scrollExtent);

}

//+--------------------------------------------------------------------------

//

//  Member:     COleInPlaceSiteA::OnUIDeactivate, public

//

//  Synopsis:   Thunks OnUIDeactivate to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleInPlaceSiteA::OnUIDeactivate(BOOL fUndoable)

{

TraceMethodEnter("COleInPlaceSiteA::OnUIDeactivate", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleInPlaceSite, OnUIDeactivate));

return GetWide()->OnUIDeactivate(fUndoable);

}

//+--------------------------------------------------------------------------

//

//  Member:     COleInPlaceSiteA::OnInPlaceDeactivate, public

//

//  Synopsis:   Thunks OnInPlaceDeactivate to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleInPlaceSiteA::OnInPlaceDeactivate(VOID)

{

TraceMethodEnter("COleInPlaceSiteA::OnInPlaceDeactivate", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleInPlaceSite, OnInPlaceDeactivate));

return GetWide()->OnInPlaceDeactivate();

}

//+--------------------------------------------------------------------------

//

//  Member:     COleInPlaceSiteA::DiscardUndoState, public

//

//  Synopsis:   Thunks DiscardUndoState to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleInPlaceSiteA::DiscardUndoState(VOID)

{

TraceMethodEnter("COleInPlaceSiteA::DiscardUndoState", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleInPlaceSite, DiscardUndoState));

return GetWide()->DiscardUndoState();

}

//+--------------------------------------------------------------------------

//

//  Member:     COleInPlaceSiteA::DeactivateAndUndo, public

//

//  Synopsis:   Thunks DeactivateAndUndo to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleInPlaceSiteA::DeactivateAndUndo(VOID)

{

TraceMethodEnter("COleInPlaceSiteA::DeactivateAndUndo", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleInPlaceSite, DeactivateAndUndo));

return GetWide()->DeactivateAndUndo();

}

//+--------------------------------------------------------------------------

//

//  Member:     COleInPlaceSiteA::OnPosRectChange, public

//

//  Synopsis:   Thunks OnPosRectChange to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP COleInPlaceSiteA::OnPosRectChange(LPCRECT lprcPosRect)

{

TraceMethodEnter("COleInPlaceSiteA::OnPosRectChange", this);

_DebugHook(GetWide(), MEMBER_PTR(IOleInPlaceSite, OnPosRectChange));

return GetWide()->OnPosRectChange(lprcPosRect);

}


 ANSIOLE3.CPP  (OLEANSI Sample)

//+--------------------------------------------------------------------------

//

//  Copyright (C) 1994, Microsoft Corporation.  All Rights Reserved.

//

//  File:       ansiole3.cpp

//

//  Contents:   ANSI Wrappers for Unicode Ole2 Interfaces and APIs.

//

//  Functions:  ReadClassStgA

//

//  History:    01-Nov-93   v-kentc     Created.

//

//---------------------------------------------------------------------------

#include "Ole2Ansi.h"

//+--------------------------------------------------------------------------

//

//  Routine:    CreateDataCacheA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI CreateDataCacheA(LPUNKNOWN pUnkOuterA, REFCLSID rclsid,

REFIID iid, LPVOID FAR* ppv)

{

TraceSTDAPIEnter("CreateDataCacheA");

LPUNKNOWN pUnkOuter;

LPUNKNOWN pUnk;

IDINTERFACE      idRef;

HRESULT hResult;

hResult = WrapIUnknownWFromA(pUnkOuterA, &pUnkOuter);

if (FAILED(hResult))

return hResult;

hResult = CreateDataCache(pUnkOuter, rclsid, iid, (LPVOID *)&pUnk);

if (FAILED(hResult))

goto Error;

//

//  Convert the 16 bytes GUID into an internal integer for speed.

//

idRef = WrapTranslateIID(iid);

hResult = WrapInterfaceAFromW(idRef, pUnk, (LPUNKNOWN *)ppv);

if (pUnk)

pUnk->Release();

Error:

if (pUnkOuter)

pUnkOuter->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    OleCreateDefaultHandlerA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI OleCreateDefaultHandlerA(REFCLSID clsid, LPUNKNOWN pUnkOuter,

REFIID riid, LPVOID FAR* lplpObj)

{

TraceSTDAPIEnter("OleCreateDefaultHandlerA");

LPUNKNOWN pUnk;

IDINTERFACE      idRef;

HRESULT hResult;

// Note: Since OleCreateDefaultHandler doesn't increase pUnkOuter's

// reference count, we can't create a wrapper for it here and then

// release it, because we'd leave the default handler with a pointer

// to garbage.  Instead, we insist on having pUnkOuter "pre-wrapped"

// by the caller.

hResult = OleCreateDefaultHandler(clsid, pUnkOuter, riid, (LPVOID *)&pUnk);

if (FAILED(hResult))

goto Error;

//

//  Convert the 16 bytes GUID into an internal integer for speed.

//

idRef = WrapTranslateIID(riid);

hResult = WrapInterfaceAFromW(idRef, pUnk, (LPUNKNOWN *)lplpObj);

if (pUnk)

 pUnk->Release();

Error:

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    OleDrawA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI OleDrawA(LPUNKNOWN pUnknownA, DWORD dwAspect, HDC hdcDraw,

LPCRECT lprcBounds)

{

TraceSTDAPIEnter("OleDrawA");

LPUNKNOWN pUnk;

HRESULT hResult;

hResult = WrapIUnknownWFromA(pUnknownA, &pUnk);

if (FAILED(hResult))

return hResult;

hResult = OleDraw(pUnk, dwAspect, hdcDraw, lprcBounds);

if (pUnk)

pUnk->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    OleNoteObjectVisibleA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI OleNoteObjectVisibleA(LPUNKNOWN pUnknown, BOOL fVisible)

{

TraceSTDAPIEnter("OleNoteObjectVisibleA");

LPUNKNOWN pUnk;

HRESULT hResult;

hResult = WrapIUnknownWFromA(pUnknown, &pUnk);

if (FAILED(hResult))

return hResult;

hResult = OleNoteObjectVisible(pUnk, fVisible);

if (pUnk)

pUnk->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    OleRunA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI OleRunA(LPUNKNOWN pUnknown)

{

TraceSTDAPIEnter("OleRunA");

LPUNKNOWN pUnk;

HRESULT hResult;

hResult = WrapIUnknownWFromA(pUnknown, &pUnk);

if (FAILED(hResult))

return hResult;

hResult = OleRun(pUnk);

if (pUnk)

pUnk->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    OleSetContainedObjectA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI OleSetContainedObjectA(LPUNKNOWN pUnknown, BOOL fContained)

{

TraceSTDAPIEnter("OleSetContainedObjectA");

LPUNKNOWN pUnk;

HRESULT hResult;

hResult = WrapIUnknownWFromA(pUnknown, &pUnk);

if (FAILED(hResult))

return hResult;

hResult = OleSetContainedObject(pUnk, fContained);

if (pUnk)

pUnk->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    ReadClassStgA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI ReadClassStgA(LPSTORAGEA pStgA, CLSID * pclsid)

{

TraceSTDAPIEnter("ReadClassStgA");

LPSTORAGE pStg;

HRESULT hResult;

hResult = WrapIStorageWFromA(pStgA, &pStg);

if (FAILED(hResult))

return hResult;

hResult = ReadClassStg(pStg, pclsid);

if (pStg)

pStg->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    WriteClassStgA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI WriteClassStgA(LPSTORAGEA pStgA, REFCLSID rclsid)

{

TraceSTDAPIEnter("WriteClassStgA");

LPSTORAGE pStg;

HRESULT hResult;

hResult = WrapIStorageWFromA(pStgA, &pStg);

if (FAILED(hResult))

return hResult;

hResult = WriteClassStg(pStg, rclsid);

if (pStg)

pStg->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    ReadClassStmA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI ReadClassStmA(LPSTREAMA pStmA, CLSID * pclsid)

{

TraceSTDAPIEnter("ReadClassStmA");

LPSTREAM pStm;

HRESULT hResult;

hResult = WrapIStreamWFromA(pStmA, &pStm);

if (FAILED(hResult))

return hResult;

hResult = ReadClassStm(pStm, pclsid);

if (pStm)

pStm->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    WriteClassStmA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI WriteClassStmA(LPSTREAMA pStmA, REFCLSID rclsid)

{

TraceSTDAPIEnter("WriteClassStmA");

LPSTREAM pStm;

HRESULT hResult;

hResult = WrapIStreamWFromA(pStmA, &pStm);

if (FAILED(hResult))

return hResult;

hResult = WriteClassStm(pStm, rclsid);

if (pStm)

pStm->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    WriteFmtUserTypeStgA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI WriteFmtUserTypeStgA(LPSTORAGEA pStgA, CLIPFORMAT cf,

LPSTR lpszUserTypeA)

{

TraceSTDAPIEnter("WriteFmtUserTypeStgA");

LPSTORAGE pStg;

OLECHAR szUserType[MAX_STRING], * pszUserType;

HRESULT hResult;

hResult = WrapIStorageWFromA(pStgA, &pStg);

if (FAILED(hResult))

return hResult;

if (lpszUserTypeA)

{

ConvertStringToW(lpszUserTypeA, szUserType);

pszUserType = szUserType;

}

else

pszUserType = NULL;

hResult = WriteFmtUserTypeStg(pStg, cf, pszUserType);

if (pStg)

pStg->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    ReadFmtUserTypeStgA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI ReadFmtUserTypeStgA(LPSTORAGEA pStgA, CLIPFORMAT * pcf,

LPSTR * lplpszUserTypeA)

{

TraceSTDAPIEnter("ReadFmtUserTypeStgA");

LPSTORAGE pStg;

LPOLESTR *lplpszUserType;

LPOLESTR lpszUserType;

HRESULT hResult;

hResult = WrapIStorageWFromA(pStgA, &pStg);

if (FAILED(hResult))

return hResult;

if (lplpszUserTypeA)

lplpszUserType = &lpszUserType;

else

lplpszUserType = NULL;

hResult = ReadFmtUserTypeStg(pStg, pcf, lplpszUserType);

if (FAILED(hResult))

goto Error;

if (lplpszUserType)

{

hResult = ConvertStringToA(lpszUserType, lplpszUserTypeA);

ConvertStringFree(lpszUserType);

}

Error:

if (pStg)

pStg->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    OleQueryLinkFromDataA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI OleQueryLinkFromDataA(LPDATAOBJECTA pSrcDataObjectA)

{

TraceSTDAPIEnter("OleQueryLinkFromDataA");

LPDATAOBJECT pSrcDataObject;

HRESULT hResult;

hResult = WrapIDataObjectWFromA(pSrcDataObjectA, &pSrcDataObject);

if (FAILED(hResult))

return (hResult);

hResult = OleQueryLinkFromData(pSrcDataObject);

if (pSrcDataObject)

pSrcDataObject->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    OleQueryCreateFromDataA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI OleQueryCreateFromDataA(LPDATAOBJECTA pSrcDataObjectA)

{

TraceSTDAPIEnter("OleQueryCreateFromDataA");

LPDATAOBJECT pSrcDataObject;

HRESULT hResult;

hResult = WrapIDataObjectWFromA(pSrcDataObjectA, &pSrcDataObject);

if (FAILED(hResult))

return (hResult);

hResult = OleQueryCreateFromData(pSrcDataObject);

if (pSrcDataObject)

pSrcDataObject->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    OleCreateA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI OleCreateA(REFCLSID rclsid, REFIID riid, DWORD renderopt,

LPFORMATETC pFormatEtc, LPOLECLIENTSITEA pClientSiteA,

LPSTORAGEA pStgA, LPVOID * ppvObj)

{

TraceSTDAPIEnter("OleCreateA");

LPOLECLIENTSITE pClientSite;

LPSTORAGE pStg;

LPUNKNOWN pUnk;

IDINTERFACE      idRef;

HRESULT hResult;

hResult = WrapIOleClientSiteWFromA(pClientSiteA, &pClientSite);

if (FAILED(hResult))

return (hResult);

hResult = WrapIStorageWFromA(pStgA, &pStg);

if (FAILED(hResult))

goto Error;

hResult = OleCreate(rclsid, riid, renderopt, pFormatEtc, pClientSite,

pStg, (LPVOID *)&pUnk);

if (FAILED(hResult))

goto Error;

//

//  Convert the 16 bytes GUID into an internal integer for speed.

//

idRef = WrapTranslateIID(riid);

hResult = WrapInterfaceAFromW(idRef, pUnk, (LPUNKNOWN *)ppvObj);

if (pStg)

pStg->Release();

if (pUnk)

pUnk->Release();

Error:

if (pClientSite)

pClientSite->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    OleCreateFromDataA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI OleCreateFromDataA(LPDATAOBJECTA pSrcDataObjA, REFIID riid,

DWORD renderopt, LPFORMATETC pFormatEtc,

LPOLECLIENTSITEA pClientSiteA, LPSTORAGEA pStgA, LPVOID * ppvObj)

{

TraceSTDAPIEnter("OleCreateFromDataA");

LPDATAOBJECT pSrcDataObj;

LPOLECLIENTSITE pClientSite;

LPSTORAGE pStg;

LPUNKNOWN pUnk;

IDINTERFACE      idRef;

HRESULT hResult;

hResult = WrapIDataObjectWFromA(pSrcDataObjA, &pSrcDataObj);

if (FAILED(hResult))

return (hResult);

hResult = WrapIOleClientSiteWFromA(pClientSiteA, &pClientSite);

if (FAILED(hResult))

goto Error;

hResult = WrapIStorageWFromA(pStgA, &pStg);

if (FAILED(hResult))

goto Error1;

hResult = OleCreateFromData(pSrcDataObj, riid, renderopt, pFormatEtc,

pClientSite, pStg, (LPVOID *)&pUnk);

if (FAILED(hResult))

goto Error1;

//

//  Convert the 16 bytes GUID into an internal integer for speed.

//

idRef = WrapTranslateIID(riid);

hResult = WrapInterfaceAFromW(idRef, pUnk, (LPUNKNOWN *)ppvObj);

if (pStg)

pStg->Release();

if (pUnk)

pUnk->Release();

Error1:

if (pClientSite)

pClientSite->Release();

Error:

if (pSrcDataObj)

pSrcDataObj->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    OleCreateLinkFromDataA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI OleCreateLinkFromDataA(LPDATAOBJECTA pSrcDataObjA, REFIID riid,

DWORD renderopt, LPFORMATETC pFormatEtc,

LPOLECLIENTSITEA pClientSiteA, LPSTORAGEA pStgA, LPVOID * ppvObj)

{

TraceSTDAPIEnter("OleCreateLinkFromDataA");

LPDATAOBJECT pSrcDataObj;

LPOLECLIENTSITE pClientSite;

LPSTORAGE pStg;

LPUNKNOWN pUnk;

IDINTERFACE      idRef;

HRESULT hResult;

hResult = WrapIDataObjectWFromA(pSrcDataObjA, &pSrcDataObj);

if (FAILED(hResult))

return (hResult);

hResult = WrapIOleClientSiteWFromA(pClientSiteA, &pClientSite);

if (FAILED(hResult))

goto Error;

hResult = WrapIStorageWFromA(pStgA, &pStg);

if (FAILED(hResult))

goto Error1;

hResult = OleCreateLinkFromData(pSrcDataObj, riid, renderopt, pFormatEtc,

pClientSite, pStg, (LPVOID *)&pUnk);

if (FAILED(hResult))

goto Error1;

//

//  Convert the 16 bytes GUID into an internal integer for speed.

//

idRef = WrapTranslateIID(riid);

hResult = WrapInterfaceAFromW(idRef, pUnk, (LPUNKNOWN *)ppvObj);

if (pStg)

pStg->Release();

if (pUnk)

pUnk->Release();

Error1:

if (pClientSite)

pClientSite->Release();

Error:

if (pSrcDataObj)

pSrcDataObj->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    OleCreateStaticFromDataA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI OleCreateStaticFromDataA(LPDATAOBJECTA pSrcDataObjA, REFIID iid,

DWORD renderopt, LPFORMATETC pFormatEtc,

LPOLECLIENTSITEA pClientSiteA, LPSTORAGEA pStgA, LPVOID * ppvObj)

{

TraceSTDAPIEnter("OleCreateStaticFromDataA");

LPDATAOBJECT pSrcDataObj;

LPOLECLIENTSITE pClientSite;

LPSTORAGE pStg;

LPUNKNOWN pUnk;

IDINTERFACE      idRef;

HRESULT hResult;

hResult = WrapIDataObjectWFromA(pSrcDataObjA, &pSrcDataObj);

if (FAILED(hResult))

return (hResult);

hResult = WrapIOleClientSiteWFromA(pClientSiteA, &pClientSite);

if (FAILED(hResult))

goto Error;

hResult = WrapIStorageWFromA(pStgA, &pStg);

if (FAILED(hResult))

goto Error1;

hResult = OleCreateStaticFromData(pSrcDataObj, iid, renderopt, pFormatEtc,

pClientSite, pStg, (LPVOID *)&pUnk);

if (FAILED(hResult))

goto Error1;

//

//  Convert the 16 bytes GUID into an internal integer for speed.

//

idRef = WrapTranslateIID(iid);

hResult = WrapInterfaceAFromW(idRef, pUnk, (LPUNKNOWN *)ppvObj);

if (pStg)

pStg->Release();

if (pUnk)

pUnk->Release();

Error1:

if (pClientSite)

pClientSite->Release();

Error:

if (pSrcDataObj)

pSrcDataObj->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    OleCreateLinkA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI OleCreateLinkA(LPMONIKERA pmkLinkSrcA, REFIID riid, DWORD renderopt,

LPFORMATETC lpFormatEtc, LPOLECLIENTSITEA pClientSiteA,

LPSTORAGEA pStgA, LPVOID * ppvObj)

{

TraceSTDAPIEnter("OleCreateLinkA");

LPMONIKER pmkLinkSrc;

LPOLECLIENTSITE pClientSite;

LPSTORAGE pStg;

LPUNKNOWN pUnk;

IDINTERFACE      idRef;

HRESULT hResult;

hResult = WrapIMonikerWFromA(pmkLinkSrcA, &pmkLinkSrc);

if (FAILED(hResult))

return (hResult);

hResult = WrapIOleClientSiteWFromA(pClientSiteA, &pClientSite);

if (FAILED(hResult))

goto Error;

hResult = WrapIStorageWFromA(pStgA, &pStg);

if (FAILED(hResult))

goto Error1;

hResult = OleCreateLink(pmkLinkSrc, riid, renderopt, lpFormatEtc,

pClientSite, pStg, (LPVOID *)&pUnk);

if (FAILED(hResult))

goto Error1;

//

//  Convert the 16 bytes GUID into an internal integer for speed.

//

idRef = WrapTranslateIID(riid);

hResult = WrapInterfaceAFromW(idRef, pUnk, (LPUNKNOWN *)ppvObj);

if (pStg)

pStg->Release();

if (pUnk)

pUnk->Release();

Error1:

if (pClientSite)

pClientSite->Release();

Error:

if (pmkLinkSrc)

pmkLinkSrc->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    OleCreateLinkToFileA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI OleCreateLinkToFileA(LPCSTR lpszFileNameA, REFIID riid,

DWORD renderopt, LPFORMATETC lpFormatEtc,

LPOLECLIENTSITEA pClientSiteA, LPSTORAGEA pStgA, LPVOID * ppvObj)

{

TraceSTDAPIEnter("OleCreateLinkToFileA");

OLECHAR szFileName[MAX_STRING], * pszFileName;

LPOLECLIENTSITE pClientSite;

LPSTORAGE pStg;

LPUNKNOWN pUnk;

IDINTERFACE      idRef;

HRESULT hResult;

if (lpszFileNameA)

{

ConvertStringToW(lpszFileNameA, szFileName);

pszFileName = szFileName;

}

else

pszFileName = NULL;

hResult = WrapIOleClientSiteWFromA(pClientSiteA, &pClientSite);

if (FAILED(hResult))

return hResult;

hResult = WrapIStorageWFromA(pStgA, &pStg);

if (FAILED(hResult))

goto Error;

hResult = OleCreateLinkToFile(pszFileName, riid, renderopt, lpFormatEtc,

pClientSite, pStg, (LPVOID *)&pUnk);

if (FAILED(hResult))

goto Error;

//

//  Convert the 16 bytes GUID into an internal integer for speed.

//

idRef = WrapTranslateIID(riid);

hResult = WrapInterfaceAFromW(idRef, pUnk, (LPUNKNOWN *)ppvObj);

if (pStg)

pStg->Release();

if (pUnk)

pUnk->Release();

Error:

if (pClientSite)

pClientSite->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    OleCreateFromFileA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI OleCreateFromFileA(REFCLSID rclsid, LPCSTR lpszFileNameA, REFIID riid,

DWORD renderopt, LPFORMATETC lpFormatEtc,

LPOLECLIENTSITEA pClientSiteA, LPSTORAGEA pStgA, LPVOID * ppvObj)

{

TraceSTDAPIEnter("OleCreateFromFileA");

OLECHAR szFileName[MAX_PATH], *pszFileName;

LPOLECLIENTSITE pClientSite;

LPSTORAGE pStg;

LPUNKNOWN pUnk;

IDINTERFACE      idRef;

HRESULT hResult;

if (lpszFileNameA != NULL)

{

pszFileName = szFileName;

ConvertStringToW(lpszFileNameA, pszFileName);

}

else

pszFileName = NULL;

hResult = WrapIOleClientSiteWFromA(pClientSiteA, &pClientSite);

if (FAILED(hResult))

return hResult;

hResult = WrapIStorageWFromA(pStgA, &pStg);

if (FAILED(hResult))

goto Error;

hResult = OleCreateFromFile(rclsid, pszFileName, riid, renderopt,

lpFormatEtc, pClientSite, pStg, (LPVOID *)&pUnk);

if (FAILED(hResult))

goto Error;

//

//  Convert the 16 bytes GUID into an internal integer for speed.

//

idRef = WrapTranslateIID(riid);

hResult = WrapInterfaceAFromW(idRef, pUnk, (LPUNKNOWN *)ppvObj);

if (pStg)

pStg->Release();

if (pUnk)

pUnk->Release();

Error:

if (pClientSite)

pClientSite->Release();

TraceSTDAPIExit("OleCreateFromFileA", hResult);

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    OleLoadA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI OleLoadA(LPSTORAGEA pStgA, REFIID riid, LPOLECLIENTSITEA pClientSiteA,

LPVOID * ppvObj)

{

TraceSTDAPIEnter("OleLoadA");

LPSTORAGE pStg;

LPOLECLIENTSITE pClientSite;

LPUNKNOWN pUnk;

IDINTERFACE      idRef;

HRESULT hResult;

hResult = WrapIStorageWFromA(pStgA, &pStg);

if (FAILED(hResult))

return hResult;

hResult = WrapIOleClientSiteWFromA(pClientSiteA, &pClientSite);

if (FAILED(hResult))

goto Error;

hResult = OleLoad(pStg, riid, pClientSite, (LPVOID *)&pUnk);

if (FAILED(hResult))

goto Error;

//

//  Convert the 16 bytes GUID into an internal integer for speed.

//

idRef = WrapTranslateIID(riid);

hResult = WrapInterfaceAFromW(idRef, pUnk, (LPUNKNOWN *)ppvObj);

if (pUnk)

pUnk->Release();

if (pClientSite)

pClientSite->Release();

Error:

if (pStg)

pStg->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    OleSaveA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI OleSaveA(LPPERSISTSTORAGEA pPSA, LPSTORAGEA pStgA, BOOL fSameAsLoad)

{

TraceSTDAPIEnter("OleSaveA");

LPPERSISTSTORAGE pPS;

LPSTORAGE pStg;

HRESULT hResult;

hResult = WrapIPersistStorageWFromA(pPSA, &pPS);

if (FAILED(hResult))

return hResult;

hResult = WrapIStorageWFromA(pStgA, &pStg);

if (FAILED(hResult))

goto Error;

hResult = OleSave(pPS, pStg, fSameAsLoad);

if (pStg)

pStg->Release();

Error:

if (pPS)

pPS->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    OleLoadFromStreamA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI OleLoadFromStreamA(LPSTREAMA pStmA, REFIID iidInterface,

LPVOID * ppvObj)

{

TraceSTDAPIEnter("OleLoadFromStreamA");

LPSTREAM pStm;

LPUNKNOWN pUnk;

IDINTERFACE      idRef;

HRESULT hResult;

hResult = WrapIStreamWFromA(pStmA, &pStm);

if (FAILED(hResult))

return hResult;

hResult = OleLoadFromStream(pStm, iidInterface, (LPVOID *)&pUnk);

if (FAILED(hResult))

return hResult;

//

//  Convert the 16 bytes GUID into an internal integer for speed.

//

idRef = WrapTranslateIID(iidInterface);

hResult = WrapInterfaceAFromW(idRef, pUnk, (LPUNKNOWN *)ppvObj);

if (pStm)

pStm->Release();

if (pUnk)

pUnk->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    OleSaveToStreamA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI OleSaveToStreamA(LPPERSISTSTREAMA pPStmA, LPSTREAMA pStmA)

{

TraceSTDAPIEnter("OleSaveToStreamA");

LPPERSISTSTREAM pPStm;

LPSTREAM pStm;

HRESULT hResult;

hResult = WrapIPersistStreamWFromA(pPStmA, &pPStm);

if (FAILED(hResult))

return hResult;

hResult = WrapIStreamWFromA(pStmA, &pStm);

if (FAILED(hResult))

goto Error;

hResult = OleSaveToStream(pPStm, pStm);

if (pStm)

pStm->Release();

Error:

if (pPStm)

pPStm->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    RegisterDragDropA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI RegisterDragDropA(HWND hwnd, LPDROPTARGETA pDropTargetA)

{

TraceSTDAPIEnter("RegisterDragDropA");

LPDROPTARGET pDropTarget;

HRESULT hResult;

hResult = WrapIDropTargetWFromA(pDropTargetA, &pDropTarget);

if (FAILED(hResult))

return hResult;

hResult = RegisterDragDrop(hwnd, pDropTarget);

if (FAILED(hResult))

{

if (pDropTarget)

pDropTarget->Release();

return hResult;

}

if (!SetProp(hwnd, "Ole2AnsiProp", (HANDLE)pDropTarget))

{

RevokeDragDrop(hwnd);

if (pDropTarget)

pDropTarget->Release();

return ResultFromScode(E_FAIL);

}

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    DoDragDropA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI DoDragDropA(LPDATAOBJECTA pDataObjA, LPDROPSOURCE pDropSource,

DWORD dwOKEffects, LPDWORD pdwEffect)

{

TraceSTDAPIEnter("DoDragDropA");

LPDATAOBJECT pDataObj;

HRESULT hResult;

hResult = WrapIDataObjectWFromA(pDataObjA, &pDataObj);

if (FAILED(hResult))

return hResult;

hResult = DoDragDrop(pDataObj, pDropSource, dwOKEffects, pdwEffect);

if (pDataObj)

pDataObj->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    RevokeDragDropA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI RevokeDragDropA(HWND hwnd)

{

TraceSTDAPIEnter("RevokeDragDropA");

LPDROPTARGET pDropTarget;

HRESULT hResult;

hResult = RevokeDragDrop(hwnd);

if (FAILED(hResult))

return hResult;

pDropTarget = (LPDROPTARGET)GetProp(hwnd, "Ole2AnsiProp");

if (pDropTarget)

pDropTarget->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    OleSetClipboardA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI OleSetClipboardA(LPDATAOBJECTA pDataObjA)

{

TraceSTDAPIEnter("OleSetClipboardA");

LPDATAOBJECT pDataObj;

HRESULT hResult;

hResult = WrapIDataObjectWFromA(pDataObjA, &pDataObj);

if (FAILED(hResult))

return hResult;

hResult = OleSetClipboard(pDataObj);

if (pDataObj)

pDataObj->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    OleGetClipboardA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI OleGetClipboardA(LPDATAOBJECTA * ppDataObjA)

{

TraceSTDAPIEnter("OleGetClipboardA");

LPDATAOBJECT pDataObj;

HRESULT hReturn;

HRESULT hResult;

*ppDataObjA = NULL;

hReturn = OleGetClipboard(&pDataObj);

if (FAILED(hReturn))

return hReturn;

hResult = WrapIDataObjectAFromW(pDataObj, ppDataObjA);

if (FAILED(hResult))

hReturn = hResult;

if (pDataObj)

pDataObj->Release();

return hReturn;

}

//+--------------------------------------------------------------------------

//

//  Routine:    OleIsCurrentClipboardA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI OleIsCurrentClipboardA(LPDATAOBJECTA pDataObjA)

{

TraceSTDAPIEnter("OleIsCurrentClipboardA");

LPDATAOBJECT pDataObj;

HRESULT hResult;

hResult = WrapIDataObjectWFromA(pDataObjA, &pDataObj);

if (FAILED(hResult))

return hResult;

hResult = OleIsCurrentClipboard(pDataObj);

if (pDataObj)

pDataObj->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    OleSetMenuDescriptorA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI OleSetMenuDescriptorA(HOLEMENU holemenu, HWND hwndFrame,

HWND hwndActiveObject, LPOLEINPLACEFRAMEA lpFrameA,

LPOLEINPLACEACTIVEOBJECTA lpActiveObjectA)

{

TraceSTDAPIEnter("OleSetMenuDescriptorA");

LPOLEINPLACEFRAME lpFrame;

LPOLEINPLACEACTIVEOBJECT lpActiveObject;

HRESULT hResult;

hResult = WrapIOleInPlaceFrameWFromA(lpFrameA, &lpFrame);

if (FAILED(hResult))

return hResult;

hResult = WrapIOleInPlaceActiveObjectWFromA(lpActiveObjectA, &lpActiveObject);

if (FAILED(hResult))

goto Error;

hResult = OleSetMenuDescriptor(holemenu, hwndFrame, hwndActiveObject,

lpFrame, lpActiveObject);

if (lpActiveObject)

lpActiveObject->Release();

Error:

if (lpFrame)

lpFrame->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    OleTranslateAcceleratorA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI OleTranslateAcceleratorA(LPOLEINPLACEFRAMEA lpFrameA,

LPOLEINPLACEFRAMEINFO lpFrameInfo, LPMSG lpmsg)

{

TraceSTDAPIEnter("OleTranslateAcceleratorA");

LPOLEINPLACEFRAME lpFrame;

HRESULT hResult;

hResult = WrapIOleInPlaceFrameWFromA(lpFrameA, &lpFrame);

if (FAILED(hResult))

return hResult;

hResult = OleTranslateAccelerator(lpFrame, lpFrameInfo, lpmsg);

if (lpFrame)

lpFrame->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    OleIsRunningA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI_(BOOL) OleIsRunningA(LPOLEOBJECTA pObjectA)

{

TraceSTDAPIEnter("OleIsRunningA");

LPOLEOBJECT pObject;

HRESULT hResult;

   BOOL    fResult;

hResult = WrapIOleObjectWFromA(pObjectA, &pObject);

if (FAILED(hResult))

return FALSE;

fResult = OleIsRunning(pObject);

if (pObject)

pObject->Release();

return fResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    ReleaseStgMediumA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI_(void) ReleaseStgMediumA(LPSTGMEDIUMA pStgMediumA)

{

TraceSTDAPIEnter("ReleaseStgMediumA");

ConvertSTGMEDIUMFree(0, pStgMediumA);

}

//+--------------------------------------------------------------------------

//

//  Routine:    CreateOleAdviseHolderA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI CreateOleAdviseHolderA(LPOLEADVISEHOLDERA * ppOAHolderA)

{

TraceSTDAPIEnter("CreateOleAdviseHolderA");

LPOLEADVISEHOLDER pOAHolder;

HRESULT hResult;

*ppOAHolderA = NULL;

hResult = CreateOleAdviseHolder(&pOAHolder);

if (FAILED(hResult))

return hResult;

hResult = WrapIOleAdviseHolderAFromW(pOAHolder, ppOAHolderA);

if (pOAHolder)

pOAHolder->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    OleGetIconOfFileA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI_(HGLOBAL) OleGetIconOfFileA(LPSTR lpszPathA, BOOL fUseFileAsLabel)

{

TraceSTDAPIEnter("OleGetIconOfFileA");

OLECHAR szPath[MAX_PATH];

OLECHAR *pPath;

if (lpszPathA)

{

ConvertStringToW(lpszPathA, szPath);

pPath = szPath;

}

else

pPath = NULL;

return OleGetIconOfFile(pPath, fUseFileAsLabel);

}

//+--------------------------------------------------------------------------

//

//  Routine:    OleGetIconOfClassA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI_(HGLOBAL) OleGetIconOfClassA(REFCLSID rclsid, LPSTR lpszLabelA,

BOOL fUseTypeAsLabel)

{

TraceSTDAPIEnter("OleGetIconOfClassA");

OLECHAR szLabel[MAX_PATH];

OLECHAR *pLabel;

if (lpszLabelA != NULL)

{

ConvertStringToW(lpszLabelA, szLabel);

pLabel = szLabel;

}

else

pLabel = NULL;

return OleGetIconOfClass(rclsid, pLabel, fUseTypeAsLabel);

}

//+--------------------------------------------------------------------------

//

//  Routine:    OleMetafilePictFromIconAndLabelA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI_(HGLOBAL) OleMetafilePictFromIconAndLabelA(HICON hIcon,

LPSTR lpszLabelA, LPSTR lpszSourceFileA, UINT iIconIndex)

{

TraceSTDAPIEnter("OleMetafilePictFromIconAndLabelA");

LPOLESTR lpszLabel;

LPOLESTR lpszSourceFile;

HGLOBAL hGlobal;

HRESULT hResult;

hGlobal = NULL;

hResult = ConvertStringToW(lpszLabelA, &lpszLabel);

if (FAILED(hResult))

return NULL;

hResult = ConvertStringToW(lpszSourceFileA, &lpszSourceFile);

if (FAILED(hResult))

goto Error;

hGlobal = OleMetafilePictFromIconAndLabel(hIcon, lpszLabel,

lpszSourceFile, iIconIndex);

ConvertStringFree(lpszSourceFile);

Error:

ConvertStringFree(lpszLabel);

return hGlobal;

}

//+--------------------------------------------------------------------------

//

//  Routine:    OleRegGetUserTypeA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI OleRegGetUserTypeA(REFCLSID clsid, DWORD dwFormOfType,

LPSTR * pszUserTypeA)

{

TraceSTDAPIEnter("OleRegGetUserTypeA");

LPOLESTR pszUserType;

   HRESULT hResult;

hResult = OleRegGetUserType(clsid, dwFormOfType, &pszUserType);

if (FAILED(hResult))

return hResult;

hResult = ConvertStringToA(pszUserType, pszUserTypeA);

ConvertStringFree(pszUserType);

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    OleRegEnumFormatEtcA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI OleRegEnumFormatEtcA(REFCLSID clsid, DWORD dwDirection,

LPENUMFORMATETCA * ppenumA)

{

TraceSTDAPIEnter("OleRegEnumFormatEtcA");

LPENUMFORMATETC penum;

HRESULT hResult;

*ppenumA = NULL;

hResult = OleRegEnumFormatEtc(clsid, dwDirection, &penum);

if (FAILED(hResult))

return hResult;

hResult = WrapIEnumFORMATETCAFromW(penum, ppenumA);

if (penum)

penum->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    OleRegEnumVerbsA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI OleRegEnumVerbsA(REFCLSID clsid, LPENUMOLEVERBA * ppenumA)

{

TraceSTDAPIEnter("OleRegEnumVerbsA");

LPENUMOLEVERB penum;

HRESULT hResult;

*ppenumA = NULL;

hResult = OleRegEnumVerbs(clsid, &penum);

if (FAILED(hResult))

return hResult;

hResult = WrapIEnumOLEVERBAFromW(penum, ppenumA);

if (penum)

penum->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    GetHGlobalFromILockBytesA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI GetHGlobalFromILockBytesA(LPLOCKBYTESA plkbytA, HGLOBAL * phglobal)

{

TraceSTDAPIEnter("GetHGlobalFromILockBytesA");

LPLOCKBYTES plkbyt;

HRESULT hResult;

hResult = WrapILockBytesWFromA(plkbytA, &plkbyt);

if (FAILED(hResult))

return hResult;

hResult = GetHGlobalFromILockBytes(plkbyt, phglobal);

if (plkbyt)

plkbyt->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    CreateILockBytesOnHGlobalA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI CreateILockBytesOnHGlobalA(HGLOBAL hGlobal, BOOL fDeleteOnRelease,

LPLOCKBYTESA * pplkbytA)

{

TraceSTDAPIEnter("CreateILockBytesOnHGlobalA");

LPLOCKBYTES plkbyt;

HRESULT hResult;

*pplkbytA = NULL;

hResult = CreateILockBytesOnHGlobal(hGlobal, fDeleteOnRelease, &plkbyt);

if (FAILED(hResult))

return hResult;

hResult = WrapILockBytesAFromW(plkbyt, pplkbytA);

if (plkbyt)

plkbyt->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    GetHGlobalFromStreamA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI GetHGlobalFromStreamA(LPSTREAMA pStmA, HGLOBAL * phglobal)

{

TraceSTDAPIEnter("GetHGlobalFromStreamA");

LPSTREAM pStm;

HRESULT hResult;

hResult = WrapIStreamWFromA(pStmA, &pStm);

if (FAILED(hResult))

return hResult;

hResult = GetHGlobalFromStream(pStm, phglobal);

if (pStm)

pStm->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    CreateStreamOnHGlobalA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI CreateStreamOnHGlobalA(HGLOBAL hGlobal, BOOL fDeleteOnRelease,

LPSTREAMA * ppstmA)

{

TraceSTDAPIEnter("CreateStreamOnHGlobalA");

LPSTREAM pstm;

HRESULT hResult;

*ppstmA = NULL;

hResult = CreateStreamOnHGlobal(hGlobal, fDeleteOnRelease, &pstm);

if (FAILED(hResult))

return hResult;

hResult = WrapIStreamAFromW(pstm, ppstmA);

if (pstm)

pstm->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    OleDoAutoConvertA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI OleDoAutoConvertA(LPSTORAGEA pStgA, LPCLSID pClsidNew)

{

TraceSTDAPIEnter("OleDoAutoConvertA");

LPSTORAGE pStg;

HRESULT hResult;

hResult = WrapIStorageWFromA(pStgA, &pStg);

if (FAILED(hResult))

return hResult;

hResult = OleDoAutoConvert(pStg, pClsidNew);

if (pStg)

pStg->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    GetConvertStgA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI GetConvertStgA(LPSTORAGEA pStgA)

{

TraceSTDAPIEnter("GetConvertStgA");

LPSTORAGE pStg;

HRESULT hResult;

hResult = WrapIStorageWFromA(pStgA, &pStg);

if (FAILED(hResult))

return hResult;

hResult = GetConvertStg(pStg);

if (pStg)

pStg->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    SetConvertStgA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI SetConvertStgA(LPSTORAGEA pStgA, BOOL fConvert)

{

TraceSTDAPIEnter("SetConvertStgA");

LPSTORAGE pStg;

HRESULT hResult;

hResult = WrapIStorageWFromA(pStgA, &pStg);

if (FAILED(hResult))

return hResult;

hResult = SetConvertStg(pStg, fConvert);

if (pStg)

pStg->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    OleConvertOLESTREAMToIStorageA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI OleConvertOLESTREAMToIStorageA(LPOLESTREAM lpolestream,

LPSTORAGEA pStgA, const DVTARGETDEVICE * ptd)

{

TraceSTDAPIEnter("OleConvertOLESTREAMToIStorageA");

LPSTORAGE pStg;

HRESULT hResult;

hResult = WrapIStorageWFromA(pStgA, &pStg);

if (FAILED(hResult))

return hResult;

hResult = OleConvertOLESTREAMToIStorage(lpolestream, pStg, ptd);

if (pStg)

pStg->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    OleConvertIStorageToOLESTREAMA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI OleConvertIStorageToOLESTREAMA(LPSTORAGEA pStgA,

LPOLESTREAM lpolestream)

{

TraceSTDAPIEnter("OleConvertIStorageToOLESTREAMA");

LPSTORAGE pStg;

HRESULT hResult;

hResult = WrapIStorageWFromA(pStgA, &pStg);

if (FAILED(hResult))

return hResult;

hResult = OleConvertIStorageToOLESTREAM(pStg, lpolestream);

if (pStg)

pStg->Release();

return hResult;

}


 ANSISTOR.H  (OLEANSI Sample)

//+--------------------------------------------------------------------------

//

//  Copyright (C) 1994, Microsoft Corporation.  All Rights Reserved.

//

//  File:       ansistor.h

//

//  Contents:   ANSI Wrappers for Unicode Storage Interfaces and APIs.

//

//  Classes:    CEnumSTATSTGA - ANSI wrapper object for IEnumSTATSTG.

//              CLockBytesA   - ANSI wrapper object for ILockBytes.

//              CStreamA      - ANSI wrapper object for IStream.

//              CStorageA     - ANSI wrapper object for IStorage.

//              CRootStorageA - ANSI wrapper object for IRootStorage.

//

//  Functions:  StgCreateDocfileA

//              StgCreateDocfileOnILockBytesA

//              StgOpenStorageA

//              StgOpenStorageOnILockBytesA

//              StgIsStorageFileA

//              StgIsStorageILockBytesA

//              StgSetTimesA

//

//  History:    01-Nov-93   v-kentc     Created.

//

//---------------------------------------------------------------------------

//

//  Forward declarations

//

class CEnumSTATSTGA;

class CLockBytesA;

class CStreamA;

class CStorageA;

class CRootStorageA;

typedef LPSTR * SNBA;

typedef struct tagSTATSTGA

{

LPSTR pwcsName;

DWORD type;

ULARGE_INTEGER cbSize;

FILETIME mtime;

FILETIME ctime;

FILETIME atime;

DWORD grfMode;

DWORD grfLocksSupported;

CLSID clsid;

DWORD grfStateBits;

DWORD reserved;

} STATSTGA;

/*---------------------------------------------------------------------*/

/*                            IEnumSTATSTGA                            */

/*---------------------------------------------------------------------*/

#undef  INTERFACE

#define INTERFACE   IEnumSTATSTGA

DECLARE_INTERFACE_(IEnumSTATSTGA, IUnknown)

{

// *** IUnknown methods ***

STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppvObj) PURE;

STDMETHOD_(ULONG,AddRef) (THIS)  PURE;

STDMETHOD_(ULONG,Release) (THIS) PURE;

// *** IENUMSTATSTGA methods ***

STDMETHOD(Next) (THIS_ ULONG celt, STATSTGA * rgelt, ULONG *pceltFetched) PURE;

STDMETHOD(Skip) (THIS_ ULONG celt) PURE;

STDMETHOD(Reset) (THIS) PURE;

STDMETHOD(Clone) (THIS_ IEnumSTATSTGA **ppenm) PURE;

};

typedef IEnumSTATSTGA * LPENUMSTATSTGA;

/*---------------------------------------------------------------------*/

/*                             ILockBytesA                             */

/*---------------------------------------------------------------------*/

#undef  INTERFACE

#define INTERFACE   ILockBytesA

DECLARE_INTERFACE_(ILockBytesA, IUnknown)

{

// *** IUnknown methods ***

STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppvObj) PURE;

STDMETHOD_(ULONG,AddRef) (THIS)  PURE;

STDMETHOD_(ULONG,Release) (THIS) PURE;

// *** ILockBytes methods ***

STDMETHOD(ReadAt) (THIS_ ULARGE_INTEGER ulOffset,

 VOID HUGEP *pv,

 ULONG cb,

 ULONG *pcbRead) PURE;

STDMETHOD(WriteAt) (THIS_ ULARGE_INTEGER ulOffset,

  VOID const HUGEP *pv,

  ULONG cb,

  ULONG *pcbWritten) PURE;

STDMETHOD(Flush) (THIS) PURE;

STDMETHOD(SetSize) (THIS_ ULARGE_INTEGER cb) PURE;

STDMETHOD(LockRegion) (THIS_ ULARGE_INTEGER libOffset,

 ULARGE_INTEGER cb,

 DWORD dwLockType) PURE;

STDMETHOD(UnlockRegion) (THIS_ ULARGE_INTEGER libOffset,

   ULARGE_INTEGER cb,

 DWORD dwLockType) PURE;

STDMETHOD(Stat) (THIS_ STATSTGA *pstatstg, DWORD grfStatFlag) PURE;

};

typedef ILockBytesA * LPLOCKBYTESA;

/*---------------------------------------------------------------------*/

/*                              IStreamA                               */

/*---------------------------------------------------------------------*/

#undef  INTERFACE

#define INTERFACE   IStreamA

DECLARE_INTERFACE_(IStreamA, IUnknown)

{

// *** IUnknown methods ***

STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppvObj) PURE;

STDMETHOD_(ULONG,AddRef) (THIS)  PURE;

STDMETHOD_(ULONG,Release) (THIS) PURE;

// *** IStreamA methods ***

STDMETHOD(Read) (THIS_ VOID HUGEP *pv,

 ULONG cb, ULONG *pcbRead) PURE;

STDMETHOD(Write) (THIS_ VOID const HUGEP *pv,

  ULONG cb,

  ULONG *pcbWritten) PURE;

STDMETHOD(Seek) (THIS_ LARGE_INTEGER dlibMove,

   DWORD dwOrigin,

   ULARGE_INTEGER *plibNewPosition) PURE;

STDMETHOD(SetSize) (THIS_ ULARGE_INTEGER libNewSize) PURE;

STDMETHOD(CopyTo) (THIS_ IStreamA *pstm,

 ULARGE_INTEGER cb,

 ULARGE_INTEGER *pcbRead,

 ULARGE_INTEGER *pcbWritten) PURE;

STDMETHOD(Commit) (THIS_ DWORD grfCommitFlags) PURE;

STDMETHOD(Revert) (THIS) PURE;

STDMETHOD(LockRegion) (THIS_ ULARGE_INTEGER libOffset,

 ULARGE_INTEGER cb,

 DWORD dwLockType) PURE;

STDMETHOD(UnlockRegion) (THIS_ ULARGE_INTEGER libOffset,

 ULARGE_INTEGER cb,

 DWORD dwLockType) PURE;

STDMETHOD(Stat) (THIS_ STATSTGA *pstatstg, DWORD grfStatFlag) PURE;

STDMETHOD(Clone)(THIS_ IStreamA * *ppstm) PURE;

};

typedef IStreamA * LPSTREAMA;

/*---------------------------------------------------------------------*/

/*                              IStorageA                              */

/*---------------------------------------------------------------------*/

#undef  INTERFACE

#define INTERFACE   IStorageA

DECLARE_INTERFACE_(IStorageA, IUnknown)

{

// *** IUnknown methods ***

STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppvObj) PURE;

STDMETHOD_(ULONG,AddRef) (THIS)  PURE;

STDMETHOD_(ULONG,Release) (THIS) PURE;

// *** IStorage methods ***

STDMETHOD(CreateStream) (THIS_ LPCSTR pwcsName,

   DWORD grfMode,

   DWORD reserved1,

   DWORD reserved2,

   IStreamA **ppstm) PURE;

STDMETHOD(OpenStream) (THIS_ LPCSTR pwcsName,

 void *reserved1,

 DWORD grfMode,

 DWORD reserved2,

 IStreamA **ppstm) PURE;

STDMETHOD(CreateStorage) (THIS_ LPCSTR pwcsName,

DWORD grfMode,

DWORD reserved1,

DWORD reserved2,

IStorageA **ppstg) PURE;

STDMETHOD(OpenStorage) (THIS_ LPCSTR pwcsName,

  IStorageA *pstgPriority,

  DWORD grfMode,

  SNBA snbExclude,

  DWORD reserved,

  IStorageA **ppstg) PURE;

STDMETHOD(CopyTo) (THIS_ DWORD ciidExclude,

   IID const *rgiidExclude,

   SNBA snbExclude,

   IStorageA *pstgDest) PURE;

STDMETHOD(MoveElementTo) (THIS_ LPCSTR lpszName,

  IStorageA *pstgDest,

  LPCSTR lpszNewName,

  DWORD grfFlags) PURE;

STDMETHOD(Commit) (THIS_ DWORD grfCommitFlags) PURE;

STDMETHOD(Revert) (THIS) PURE;

STDMETHOD(EnumElements) (THIS_ DWORD reserved1,

 void *reserved2,

 DWORD reserved3,

 IEnumSTATSTGA **ppenm) PURE;

STDMETHOD(DestroyElement) (THIS_ LPCSTR pwcsName) PURE;

STDMETHOD(RenameElement) (THIS_ LPCSTR pcsOldName,

LPCSTR pcsNewName) PURE;

STDMETHOD(SetElementTimes) (THIS_ LPCSTR lpszName,

FILETIME const *pctime,

FILETIME const *patime,

FILETIME const *pmtime) PURE;

STDMETHOD(SetClass) (THIS_ REFCLSID clsid) PURE;

STDMETHOD(SetStateBits) (THIS_ DWORD grfStateBits, DWORD grfMask) PURE;

STDMETHOD(Stat) (THIS_ STATSTGA *pstatstgA, DWORD grfStatFlag) PURE;

};

typedef IStorageA * LPSTORAGEA;

/*---------------------------------------------------------------------*/

/*                            IRootStorageA                            */

/*---------------------------------------------------------------------*/

#undef  INTERFACE

#define INTERFACE   IRootStorageA

DECLARE_INTERFACE_(IRootStorageA, IUnknown)

{

// *** IUnknown methods ***

STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppvObj) PURE;

STDMETHOD_(ULONG,AddRef) (THIS)  PURE;

STDMETHOD_(ULONG,Release) (THIS) PURE;

// *** IRootStorage methods ***

STDMETHOD(SwitchToFile) (THIS_ LPSTR lpstrFile) PURE;

};

typedef IRootStorageA * LPROOTSTORAGEA;

/*---------------------------------------------------------------------*/

/*                         ANSI Storage API's                          */

/*---------------------------------------------------------------------*/

STDAPI StgCreateDocfileA(LPCSTR pwcsName,

DWORD grfMode,

DWORD reserved,

IStorageA * *ppstgOpenA);

STDAPI StgCreateDocfileOnILockBytesA(ILockBytesA *plkbyt,

DWORD grfMode,

DWORD reserved,

IStorageA * *ppstgOpen);

STDAPI StgOpenStorageA(LPCSTR pwcsName,

  IStorageA *pstgPriority,

  DWORD grfMode,

  SNBA snbExclude,

  DWORD reserved,

  IStorageA * *ppstgOpenA);

STDAPI StgOpenStorageOnILockBytesA(ILockBytesA *plkbyt,

  IStorageA *pstgPriority,

  DWORD grfMode,

  SNBA snbExclude,

  DWORD reserved,

  IStorageA * *ppstgOpen);

STDAPI StgIsStorageFileA(LPCSTR pwcsName);

STDAPI StgIsStorageILockBytesA(ILockBytesA * plkbyt);

STDAPI StgSetTimesA(LPCSTR lpszName,

  FILETIME const * pctime,

  FILETIME const * patime,

  FILETIME const * pmtime);

//+--------------------------------------------------------------------------

//

//  Class:      CEnumSTATSTGA

//

//  Synopsis:   Class definition of IEnumSTATSTGA

//

//---------------------------------------------------------------------------

class CEnumSTATSTGA : CAnsiInterface

{

public:

// *** IEnumSTATSTGA methods ***

STDMETHOD(Next) (ULONG celt,

   STATSTGA * rgelt,

   ULONG * pceltFetched);

STDMETHOD(Skip) (ULONG celt);

STDMETHOD(Reset) (VOID);

STDMETHOD(Clone) (IEnumSTATSTGA * * ppenm);

inline CEnumSTATSTGA(LPUNKNOWN pUnk, IEnumSTATSTG * pObj) :

CAnsiInterface(ID_IEnumSTATSTG, pUnk, (LPUNKNOWN)pObj) {};

inline IEnumSTATSTG * GetWide() const

{ return (IEnumSTATSTG *)m_pObj; };

};

//+--------------------------------------------------------------------------

//

//  Class:      CLockBytesA

//

//  Synopsis:   Class definition of ILockBytesA

//

//---------------------------------------------------------------------------

class CLockBytesA : CAnsiInterface

{

public:

// *** ILockBytes methods ***

STDMETHOD(ReadAt) (ULARGE_INTEGER ulOffset,

 VOID HUGEP *pv,

 ULONG cb,

 ULONG *pcbRead);

STDMETHOD(WriteAt) (ULARGE_INTEGER ulOffset,

  VOID const HUGEP *pv,

  ULONG cb,

  ULONG *pcbWritten);

STDMETHOD(Flush) (VOID);

STDMETHOD(SetSize) (ULARGE_INTEGER cb);

STDMETHOD(LockRegion) (ULARGE_INTEGER libOffset,

 ULARGE_INTEGER cb,

 DWORD dwLockType);

STDMETHOD(UnlockRegion) (ULARGE_INTEGER libOffset,

   ULARGE_INTEGER cb,

 DWORD dwLockType);

STDMETHOD(Stat) (STATSTGA *pstatstg, DWORD grfStatFlag);

inline CLockBytesA(LPUNKNOWN pUnk, ILockBytes * pObj) :

CAnsiInterface(ID_ILockBytes, pUnk, (LPUNKNOWN)pObj) {};

inline ILockBytes * GetWide() const

{ return (ILockBytes *)m_pObj; };

};

//+--------------------------------------------------------------------------

//

//  Class:      CStreamA

//

//  Synopsis:   Class definition of IStreamA

//

//---------------------------------------------------------------------------

class CStreamA : public CAnsiInterface

{

public:

// *** IStream methods ***

STDMETHOD(Read) (VOID HUGEP *pv,

 ULONG cb, ULONG *pcbRead);

STDMETHOD(Write) (VOID const HUGEP *pv,

ULONG cb,

ULONG *pcbWritten);

STDMETHOD(Seek) (LARGE_INTEGER dlibMove,

   DWORD dwOrigin,

   ULARGE_INTEGER *plibNewPosition);

STDMETHOD(SetSize) (ULARGE_INTEGER libNewSize);

STDMETHOD(CopyTo) (IStreamA *pstm,

 ULARGE_INTEGER cb,

 ULARGE_INTEGER *pcbRead,

 ULARGE_INTEGER *pcbWritten);

STDMETHOD(Commit) (DWORD grfCommitFlags);

STDMETHOD(Revert) (VOID);

STDMETHOD(LockRegion) (ULARGE_INTEGER libOffset,

 ULARGE_INTEGER cb,

 DWORD dwLockType);

STDMETHOD(UnlockRegion) (ULARGE_INTEGER libOffset,

 ULARGE_INTEGER cb,

 DWORD dwLockType);

STDMETHOD(Stat) (STATSTGA *pstatstg, DWORD grfStatFlag);

STDMETHOD(Clone)(IStreamA * *ppstm);

inline CStreamA(LPUNKNOWN pUnk, IStream * pObj) :

CAnsiInterface(ID_IStream, pUnk, (LPUNKNOWN)pObj) {};

inline IStream * GetWide() const

{ return (IStream *)m_pObj; };

};

//+--------------------------------------------------------------------------

//

//  Class:      CStorageA

//

//  Synopsis:   Class definition of IStorageA

//

//---------------------------------------------------------------------------

class CStorageA : public CAnsiInterface

{

public:

// *** IStorage methods ***

STDMETHOD(CreateStream) (LPCSTR psName,

   DWORD grfMode,

   DWORD reserved1,

   DWORD reserved2,

   IStreamA **ppstm);

STDMETHOD(OpenStream) (LPCSTR psName,

 void *reserved1,

 DWORD grfMode,

 DWORD reserved2,

 IStreamA **ppstm);

STDMETHOD(CreateStorage) (LPCSTR psName,

DWORD grfMode,

DWORD reserved1,

DWORD reserved2,

IStorageA **ppstg);

STDMETHOD(OpenStorage) (LPCSTR psName,

  IStorageA *pstgPriority,

  DWORD grfMode,

  SNBA snbExclude,

  DWORD reserved,

  IStorageA **ppstg);

STDMETHOD(CopyTo) (DWORD ciidExclude,

   IID const *rgiidExclude,

   SNBA snbExclude,

   IStorageA *pstgDest);

STDMETHOD(MoveElementTo) (LPCSTR lpszName,

  IStorageA *pstgDest,

  LPCSTR lpszNewName,

  DWORD grfFlags);

STDMETHOD(Commit) (DWORD grfCommitFlags);

STDMETHOD(Revert) (VOID);

STDMETHOD(EnumElements) (DWORD reserved1,

 void *reserved2,

 DWORD reserved3,

 IEnumSTATSTGA **ppenm);

STDMETHOD(DestroyElement) (LPCSTR psName);

STDMETHOD(RenameElement) (LPCSTR pcsOldName,

LPCSTR pcsNewName);

STDMETHOD(SetElementTimes) (LPCSTR lpszName,

FILETIME const *pctime,

FILETIME const *patime,

FILETIME const *pmtime);

STDMETHOD(SetClass) (REFCLSID clsid);

STDMETHOD(SetStateBits) (DWORD grfStateBits, DWORD grfMask);

STDMETHOD(Stat) (STATSTGA *pstatstg, DWORD grfStatFlag);

inline CStorageA(LPUNKNOWN pUnk, IStorage * pObj) :

CAnsiInterface(ID_IStorage, pUnk, (LPUNKNOWN)pObj) {};

inline IStorage * GetWide() const

{ return (IStorage *)m_pObj; };

};

//+--------------------------------------------------------------------------

//

//  Class:      CRootStorageA

//

//  Synopsis:   Class definition of IRootStorageA

//

//---------------------------------------------------------------------------

class CRootStorageA : public CAnsiInterface

{

public:

// *** IRootStorage methods ***

STDMETHOD(SwitchToFile) (LPSTR lpstrFile);

inline CRootStorageA(LPUNKNOWN pUnk, IRootStorage * pObj) :

CAnsiInterface(ID_IRootStorage, pUnk, (LPUNKNOWN)pObj) {};

inline IRootStorage * GetWide() const

{ return (IRootStorage *)m_pObj; };

};


 ANSISTOR.CPP  (OLEANSI Sample)

//+--------------------------------------------------------------------------

//

//  Copyright (C) 1994, Microsoft Corporation.  All Rights Reserved.

//

//  File:       ansistor.cpp

//

//  Contents:   ANSI Wrappers for Unicode Storage Interfaces and APIs.

//

//  Classes:    CEnumSTATSTGA - ANSI wrapper object for IEnumSTATSTG.

//              CLockBytesA   - ANSI wrapper object for ILockBytes.

//              CStreamA      - ANSI wrapper object for IStream.

//              CStorageA     - ANSI wrapper object for IStorage.

//              CRootStorageA - ANSI wrapper object for IRootStorage.

//

//  Functions:  StgCreateDocfileA

//              StgCreateDocfileOnILockBytesA

//              StgOpenStorageA

//              StgOpenStorageOnILockBytesA

//              StgIsStorageFileA

//              StgIsStorageILockBytesA

//              StgSetTimesA

//

//  History:    01-Nov-93   v-kentc     Created.

//

//---------------------------------------------------------------------------

#include "Ole2Ansi.h"


 IEnumSTATSTGA Implementation  (OLEANSI Sample)

//***************************************************************************

//

//                   IEnumSTATSTGA Implementation

//

//***************************************************************************

//+--------------------------------------------------------------------------

//

//  Member:     CEnumSTATSTGA::Next, public

//

//  Synopsis:   Thunks Next to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CEnumSTATSTGA::Next(

ULONG celt,

STATSTGA * rgelt,

ULONG * pceltFetched)

{

TraceMethodEnter("CEnumSTATSTGA::Next", this);

ULONG   celtFetched;

HRESULT hReturn;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IEnumSTATSTG, Next));

if (pceltFetched == NULL)

pceltFetched = &celtFetched;

hReturn = GetWide()->Next(celt, (STATSTG *)rgelt, pceltFetched);

if (FAILED(hReturn))

return (hReturn);

hResult = ConvertSTATSTGArrayToA(rgelt, *pceltFetched);

if (FAILED(hResult))

return (hResult);

return hReturn;

}

//+--------------------------------------------------------------------------

//

//  Member:     CEnumSTATSTGA::Skip, public

//

//  Synopsis:   Thunks Skip to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CEnumSTATSTGA::Skip(ULONG celt)

{

_DebugHook(GetWide(), MEMBER_PTR(IEnumSTATSTG, Skip));

return GetWide()->Skip(celt);

}

//+--------------------------------------------------------------------------

//

//  Member:     CEnumSTATSTGA::Reset, public

//

//  Synopsis:   Thunks Reset to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CEnumSTATSTGA::Reset(VOID)

{

_DebugHook(GetWide(), MEMBER_PTR(IEnumSTATSTG, Reset));

return GetWide()->Reset();

}

//+--------------------------------------------------------------------------

//

//  Member:     CEnumSTATSTGA::Clone, public

//

//  Synopsis:   Thunks Clone to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CEnumSTATSTGA::Clone(IEnumSTATSTGA * * ppstatA)

{

TraceMethodEnter("CEnumSTATSTGA::Clone", this);

IEnumSTATSTG * pstat;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IEnumSTATSTG, Clone));

*ppstatA = NULL;

hResult = GetWide()->Clone(&pstat);

if (FAILED(hResult))

return (hResult);

hResult = WrapIEnumSTATSTGAFromW(pstat, ppstatA);

if (pstat)

pstat->Release();

return hResult;

}


 ILockBytesA Implementation  (OLEANSI Sample)

//***************************************************************************

//

//                   ILockBytesA Implementation

//

//***************************************************************************

//+--------------------------------------------------------------------------

//

//  Member:     CLockBytesA::ReadAt, public

//

//  Synopsis:   Thunks ReadAt to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CLockBytesA::ReadAt(

ULARGE_INTEGER ulOffset,

VOID HUGEP *pv,

ULONG cb,

ULONG *pcbRead)

{

_DebugHook(GetWide(), MEMBER_PTR(ILockBytes, ReadAt));

return GetWide()->ReadAt(ulOffset, pv, cb, pcbRead);

}

//+--------------------------------------------------------------------------

//

//  Member:     CLockBytesA::WriteAt, public

//

//  Synopsis:   Thunks WriteAt to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CLockBytesA::WriteAt(

ULARGE_INTEGER ulOffset,

VOID const HUGEP *pv,

ULONG cb,

ULONG *pcbWritten)

{

_DebugHook(GetWide(), MEMBER_PTR(ILockBytes, WriteAt));

return GetWide()->WriteAt(ulOffset, pv, cb, pcbWritten);

}

//+--------------------------------------------------------------------------

//

//  Member:     CLockBytesA::Flush, public

//

//  Synopsis:   Thunks Flush to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CLockBytesA::Flush(VOID)

{

_DebugHook(GetWide(), MEMBER_PTR(ILockBytes, Flush));

return GetWide()->Flush();

}

//+--------------------------------------------------------------------------

//

//  Member:     CLockBytesA::SetSize, public

//

//  Synopsis:   Thunks SetSize to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CLockBytesA::SetSize(ULARGE_INTEGER cb)

{

_DebugHook(GetWide(), MEMBER_PTR(ILockBytes, SetSize));

return GetWide()->SetSize(cb);

}

//+--------------------------------------------------------------------------

//

//  Member:     CLockBytesA::LockRegion, public

//

//  Synopsis:   Thunks LockRegion to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CLockBytesA::LockRegion(

ULARGE_INTEGER libOffset,

ULARGE_INTEGER cb,

DWORD dwLockType)

{

_DebugHook(GetWide(), MEMBER_PTR(ILockBytes, LockRegion));

return GetWide()->LockRegion(libOffset, cb, dwLockType);

}

//+--------------------------------------------------------------------------

//

//  Member:     CLockBytesA::UnlockRegion, public

//

//  Synopsis:   Thunks UnlockRegion to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CLockBytesA::UnlockRegion(

ULARGE_INTEGER libOffset,

ULARGE_INTEGER cb,

DWORD dwLockType)

{

_DebugHook(GetWide(), MEMBER_PTR(ILockBytes, UnlockRegion));

return GetWide()->UnlockRegion(libOffset, cb, dwLockType);

}

//+--------------------------------------------------------------------------

//

//  Member:     CLockBytesA::Stat, public

//

//  Synopsis:   Thunks Stat to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CLockBytesA::Stat(STATSTGA *pstatstg, DWORD grfStatFlag)

{

TraceMethodEnter("CLockBytesA::Stat", this);

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(ILockBytes, Stat));

hResult = GetWide()->Stat((STATSTG *)pstatstg, grfStatFlag);

if (FAILED(hResult))

return (hResult);

return ConvertSTATSTGToA(pstatstg);

}


 IStreamA Implementation  (OLEANSI Sample)

//***************************************************************************

//

//                   IStreamA Implementation

//

//***************************************************************************

//+--------------------------------------------------------------------------

//

//  Member:     CStreamA::Read, public

//

//  Synopsis:   Thunks Read to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CStreamA::Read(

VOID HUGEP *pv,

ULONG cb,

ULONG *pcbRead)

{

_DebugHook(GetWide(), MEMBER_PTR(IStream, Read));

return GetWide()->Read(pv, cb, pcbRead);

}

//+--------------------------------------------------------------------------

//

//  Member:     CStreamA::Write, public

//

//  Synopsis:   Thunks Write to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CStreamA::Write(

VOID const HUGEP *pv,

ULONG cb,

ULONG *pcbWritten)

{

_DebugHook(GetWide(), MEMBER_PTR(IStream, Write));

return GetWide()->Write(pv, cb, pcbWritten);

}

//+--------------------------------------------------------------------------

//

//  Member:     CStreamA::Seek, public

//

//  Synopsis:   Thunks Seek to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CStreamA::Seek(

LARGE_INTEGER dlibMove,

DWORD dwOrigin,

ULARGE_INTEGER *plibNewPosition)

{

_DebugHook(GetWide(), MEMBER_PTR(IStream, Seek));

return GetWide()->Seek(dlibMove, dwOrigin, plibNewPosition);

}

//+--------------------------------------------------------------------------

//

//  Member:     CStreamA::SetSize, public

//

//  Synopsis:   Thunks SetSize to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CStreamA::SetSize(ULARGE_INTEGER libNewSize)

{

_DebugHook(GetWide(), MEMBER_PTR(IStream, SetSize));

return GetWide()->SetSize(libNewSize);

}

//+--------------------------------------------------------------------------

//

//  Member:     CStreamA::CopyTo, public

//

//  Synopsis:   Thunks CopyTo to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CStreamA::CopyTo(

IStreamA *pstrmA,

ULARGE_INTEGER cb,

ULARGE_INTEGER *pcbRead,

ULARGE_INTEGER *pcbWritten)

{

TraceMethodEnter("CStreamA::CopyTo", this);

IStream * pstrm;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IStream, CopyTo));

hResult = WrapIStreamWFromA(pstrmA, &pstrm);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->CopyTo(pstrm, cb, pcbRead, pcbWritten);

if (pstrm)

pstrm->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CStreamA::Commit, public

//

//  Synopsis:   Thunks Commit to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CStreamA::Commit(DWORD grfCommitFlags)

{

_DebugHook(GetWide(), MEMBER_PTR(IStream, Commit));

return GetWide()->Commit(grfCommitFlags);

}

//+--------------------------------------------------------------------------

//

//  Member:     CStreamA::Revert, public

//

//  Synopsis:   Thunks Revert to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CStreamA::Revert(VOID)

{

_DebugHook(GetWide(), MEMBER_PTR(IStream, Revert));

return GetWide()->Revert();

}

//+--------------------------------------------------------------------------

//

//  Member:     CStreamA::LockRegion, public

//

//  Synopsis:   Thunks LockRegion to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CStreamA::LockRegion(

ULARGE_INTEGER libOffset,

ULARGE_INTEGER cb,

DWORD dwLockType)

{

_DebugHook(GetWide(), MEMBER_PTR(IStream, LockRegion));

return GetWide()->LockRegion(libOffset, cb, dwLockType);

}

//+--------------------------------------------------------------------------

//

//  Member:     CStreamA::UnlockRegion, public

//

//  Synopsis:   Thunks UnlockRegion to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CStreamA::UnlockRegion(

ULARGE_INTEGER libOffset,

ULARGE_INTEGER cb,

DWORD dwLockType)

{

_DebugHook(GetWide(), MEMBER_PTR(IStream, UnlockRegion));

return GetWide()->UnlockRegion(libOffset, cb, dwLockType);

}

//+--------------------------------------------------------------------------

//

//  Member:     CStreamA::Stat, public

//

//  Synopsis:   Thunks Stat to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CStreamA::Stat(STATSTGA *pstatstg, DWORD grfStatFlag)

{

TraceMethodEnter("CStreamA::Stat", this);

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IStream, Stat));

hResult = GetWide()->Stat((STATSTG *)pstatstg, grfStatFlag);

if (FAILED(hResult))

return (hResult);

return ConvertSTATSTGToA(pstatstg);

}

//+--------------------------------------------------------------------------

//

//  Member:     CStreamA::Clone, public

//

//  Synopsis:   Thunks Clone to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CStreamA::Clone(IStreamA * * ppstrmA)

{

TraceMethodEnter("CStreamA::Clone", this);

IStream * pstrm;

_DebugHook(GetWide(), MEMBER_PTR(IStream, Clone));

*ppstrmA = NULL;

HRESULT hResult = GetWide()->Clone(&pstrm);

if (FAILED(hResult))

return (hResult);

hResult = WrapIStreamAFromW(pstrm, ppstrmA);

if (pstrm)

pstrm->Release();

return hResult;

}


 IStorageA Implementation  (OLEANSI Sample)

//***************************************************************************

//

//                   IStorageA Implementation

//

//***************************************************************************

//+--------------------------------------------------------------------------

//

//  Member:     CStorageA::CreateStream, public

//

//  Synopsis:   Thunks CreateStream to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CStorageA::CreateStream(

LPCSTR pstrNameA,

DWORD grfMode,

DWORD reserved1,

DWORD reserved2,

IStreamA **ppstrmA)

{

TraceMethodEnter("CStorageA::CreateStream", this);

OLECHAR strName[MAX_PATH];

IStream * pstrm;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IStorage, CreateStream));

*ppstrmA = NULL;

ConvertStringToW(pstrNameA, strName);

hResult = GetWide()->CreateStream(strName, grfMode, reserved1, reserved2, &pstrm);

if (FAILED(hResult))

return (hResult);

hResult = WrapIStreamAFromW(pstrm, ppstrmA);

if (pstrm)

pstrm->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CStorageA::OpenStream, public

//

//  Synopsis:   Thunks OpenStream to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CStorageA::OpenStream(

LPCSTR pstrNameA,

void *reserved1,

DWORD grfMode,

DWORD reserved2,

IStreamA **ppstrmA)

{

TraceMethodEnter("CStorageA::OpenStream", this);

OLECHAR strName[MAX_PATH];

LPSTREAM pstrm;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IStorage, OpenStream));

*ppstrmA = NULL;

ConvertStringToW(pstrNameA, strName);

hResult = GetWide()->OpenStream(strName, reserved1, grfMode, reserved2, &pstrm);

if (FAILED(hResult))

return (hResult);

hResult = WrapIStreamAFromW(pstrm, ppstrmA);

if (pstrm)

pstrm->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CStorageA::CreateStorage, public

//

//  Synopsis:   Thunks CreateStorage to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CStorageA::CreateStorage(

LPCSTR pstrNameA,

DWORD grfMode,

DWORD reserved1,

DWORD reserved2,

IStorageA **ppstgA)

{

TraceMethodEnter("CStorageA::CreateStorage", this);

OLECHAR strName[MAX_PATH];

IStorage * pstg;

HRESULT hResult;

HRESULT hReturn;

_DebugHook(GetWide(), MEMBER_PTR(IStorage, CreateStorage));

*ppstgA = NULL;

ConvertStringToW(pstrNameA, strName);

hReturn = GetWide()->CreateStorage(strName, grfMode, reserved1, reserved2, &pstg);

if (FAILED(hReturn))

return (hReturn);

hResult = WrapIStorageAFromW(pstg, ppstgA);

if (SUCCEEDED(hResult))

hResult = hReturn;

if (pstg)

pstg->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CStorageA::OpenStorage, public

//

//  Synopsis:   Thunks OpenStorage to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CStorageA::OpenStorage(

LPCSTR pstrNameA,

IStorageA *pstgPriorityA,

DWORD grfMode,

SNBA snbExcludeA,

DWORD reserved,

IStorageA **ppstgA)

{

TraceMethodEnter("CStorageA::OpenStorage", this);

OLECHAR strName[MAX_PATH];

SNB      snbExclude;

IStorage * pstgPriority;

IStorage * pstg;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IStorage, OpenStorage));

*ppstgA = NULL;

ConvertStringToW(pstrNameA, strName);

hResult = ConvertSNBToW(snbExcludeA, &snbExclude);

if (FAILED(hResult))

return hResult;

hResult = WrapIStorageWFromA(pstgPriorityA, &pstgPriority);

if (FAILED(hResult))

goto Error;

hResult = GetWide()->OpenStorage(strName, pstgPriority, grfMode, snbExclude, reserved, &pstg);

if (FAILED(hResult))

goto Error1;

hResult = WrapIStorageAFromW(pstg, ppstgA);

if (pstg)

pstg->Release();

Error1:

if (pstgPriority)

pstgPriority->Release();

Error:

ConvertSNBFree(snbExclude);

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CStorageA::CopyTo, public

//

//  Synopsis:   Thunks CopyTo to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CStorageA::CopyTo(

DWORD ciidExclude,

IID const *rgiidExclude,

SNBA snbExcludeA,

IStorageA *pstgDestA)

{

TraceMethodEnter("CStorageA::CopyTo", this);

SNB      snbExclude;

IStorage * pstgDest;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IStorage, CopyTo));

hResult = ConvertSNBToW(snbExcludeA, &snbExclude);

if (FAILED(hResult))

return (hResult);

hResult = WrapIStorageWFromA(pstgDestA, &pstgDest);

if (FAILED(hResult))

goto Error;

hResult = GetWide()->CopyTo(ciidExclude, rgiidExclude, snbExclude, pstgDest);

if (pstgDest)

pstgDest->Release();

Error:

ConvertSNBFree(snbExclude);

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CStorageA::MoveElementTo, public

//

//  Synopsis:   Thunks MoveElementTo to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CStorageA::MoveElementTo(

LPCSTR pstrNameA,

IStorageA *pstgDestA,

LPCSTR pstrNewNameA,

DWORD grfFlags)

{

TraceMethodEnter("CStorageA::MoveElementTo", this);

OLECHAR strName[MAX_PATH];

OLECHAR strNewName[MAX_PATH];

IStorage * pstgDest;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IStorage, MoveElementTo));

ConvertStringToW(pstrNameA, strName);

ConvertStringToW(pstrNewNameA, strNewName);

hResult = WrapIStorageWFromA(pstgDestA, &pstgDest);

if (FAILED(hResult))

return hResult;

hResult = GetWide()->MoveElementTo(strName, pstgDest, strNewName, grfFlags);

if (pstgDest)

pstgDest->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CStorageA::Commit, public

//

//  Synopsis:   Thunks Commit to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CStorageA::Commit(DWORD grfCommitFlags)

{

_DebugHook(GetWide(), MEMBER_PTR(IStorage, Commit));

return GetWide()->Commit(grfCommitFlags);

}

//+--------------------------------------------------------------------------

//

//  Member:     CStorageA::Revert, public

//

//  Synopsis:   Thunks Revert to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CStorageA::Revert(VOID)

{

_DebugHook(GetWide(), MEMBER_PTR(IStorage, Revert));

return GetWide()->Revert();

}

//+--------------------------------------------------------------------------

//

//  Member:     CStorageA::EnumElements, public

//

//  Synopsis:   Thunks EnumElements to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CStorageA::EnumElements(

DWORD reserved1,

void *reserved2,

DWORD reserved3,

IEnumSTATSTGA **ppenmA)

{

TraceMethodEnter("CStorageA::EnumElements", this);

IEnumSTATSTG * penm = NULL;

HRESULT hResult;

_DebugHook(GetWide(), MEMBER_PTR(IStorage, EnumElements));

hResult = GetWide()->EnumElements(reserved1, reserved2, reserved3, &penm);

if (FAILED(hResult))

return (hResult);

if (penm)

{

hResult = WrapIEnumSTATSTGAFromW(penm, ppenmA);

penm->Release();

}

else

*ppenmA = NULL;

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Member:     CStorageA::DestroyElement, public

//

//  Synopsis:   Thunks DestroyElement to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CStorageA::DestroyElement(LPCSTR pstrNameA)

{

TraceMethodEnter("CStorageA::DestroyElement", this);

OLECHAR strName[MAX_PATH];

_DebugHook(GetWide(), MEMBER_PTR(IStorage, DestroyElement));

ConvertStringToW(pstrNameA, strName);

return GetWide()->DestroyElement(strName);

}

//+--------------------------------------------------------------------------

//

//  Member:     CStorageA::RenameElement, public

//

//  Synopsis:   Thunks RenameElement to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CStorageA::RenameElement(

LPCSTR pstrOldNameA,

LPCSTR pstrNewNameA)

{

TraceMethodEnter("CStorageA::RenameElement", this);

OLECHAR strOldName[MAX_PATH];

OLECHAR strNewName[MAX_PATH];

_DebugHook(GetWide(), MEMBER_PTR(IStorage, RenameElement));

ConvertStringToW(pstrOldNameA, strOldName);

ConvertStringToW(pstrNewNameA, strNewName);

return GetWide()->RenameElement(strOldName, strNewName);

}

//+--------------------------------------------------------------------------

//

//  Member:     CStorageA::SetElementTimes, public

//

//  Synopsis:   Thunks SetElementTimes to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CStorageA::SetElementTimes(

LPCSTR pstrNameA,

FILETIME const *pctime,

FILETIME const *patime,

FILETIME const *pmtime)

{

TraceMethodEnter("CStorageA::SetElementTimes", this);

OLECHAR strName[MAX_PATH];

_DebugHook(GetWide(), MEMBER_PTR(IStorage, SetElementTimes));

ConvertStringToW(pstrNameA, strName);

return GetWide()->SetElementTimes(strName, pctime, patime, pmtime);

}

//+--------------------------------------------------------------------------

//

//  Member:     CStorageA::SetClass, public

//

//  Synopsis:   Thunks SetClass to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CStorageA::SetClass(REFCLSID clsid)

{

_DebugHook(GetWide(), MEMBER_PTR(IStorage, SetClass));

return GetWide()->SetClass(clsid);

}

//+--------------------------------------------------------------------------

//

//  Member:     CStorageA::SetStateBits, public

//

//  Synopsis:   Thunks SetStateBits to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CStorageA::SetStateBits(DWORD grfCommitFlags, DWORD grfMask)

{

_DebugHook(GetWide(), MEMBER_PTR(IStorage, SetStateBits));

return GetWide()->SetStateBits(grfCommitFlags, grfMask);

}

//+--------------------------------------------------------------------------

//

//  Member:     CStorageA::Stat, public

//

//  Synopsis:   Thunks Stat to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CStorageA::Stat(STATSTGA *pstatstg, DWORD grfStatFlag)

{

TraceMethodEnter("CStorageA::Stat", this);

_DebugHook(GetWide(), MEMBER_PTR(IStorage, Stat));

HRESULT hResult = GetWide()->Stat((STATSTG *)pstatstg, grfStatFlag);

if (FAILED(hResult))

return (hResult);

return ConvertSTATSTGToA(pstatstg);

}


 IRootStorageA Implementation  (OLEANSI Sample)

//***************************************************************************

//

//                   IRootStorageA Implementation

//

//***************************************************************************

//+--------------------------------------------------------------------------

//

//  Member:     CRootStorageA::SwitchToFile, public

//

//  Synopsis:   Thunks SwitchToFile to Unicode method.

//

//  Returns:    OLE2 Result Code.

//

//---------------------------------------------------------------------------

STDMETHODIMP CRootStorageA::SwitchToFile(LPSTR pstrFileA)

{

TraceMethodEnter("CRootStorageA::SwitchToFile", this);

OLECHAR strFile[MAX_PATH];

_DebugHook(GetWide(), MEMBER_PTR(IRootStorage, SwitchToFile));

ConvertStringToW(pstrFileA, strFile);

return GetWide()->SwitchToFile(strFile);

}


 Storage API Thunks.  (OLEANSI Sample)

//***************************************************************************

//

//                          Storage API Thunks.

//

//***************************************************************************

//+--------------------------------------------------------------------------

//

//  Routine:    StgCreateDocfileA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI StgCreateDocfileA(LPCSTR pcsNameA,

DWORD grfMode,

DWORD reserved,

IStorageA * *ppstgOpenA)

{

TraceSTDAPIEnter("StgCreateDocfileA");

OLECHAR  csName[MAX_PATH];

LPOLESTR pcsName;

IStorage * pstg;

HRESULT  hResult;

HRESULT  hReturn;

*ppstgOpenA = NULL;

if (pcsNameA)

{

ConvertStringToW(pcsNameA, csName);

pcsName = csName;

}

else

pcsName = NULL;

hReturn = StgCreateDocfile(pcsName, grfMode, reserved, &pstg);

if (FAILED(hReturn))

return (hReturn);

hResult = WrapIStorageAFromW(pstg, ppstgOpenA);

if (SUCCEEDED(hResult))

hResult = hReturn;

if (pstg)

pstg->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    StgCreateDocfileOnILockBytesA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI StgCreateDocfileOnILockBytesA(ILockBytesA *plckbytA,

DWORD grfMode,

DWORD reserved,

IStorageA * *ppstgOpenA)

{

TraceSTDAPIEnter("StgCreateDocfileOnILockBytesA");

ILockBytes * plckbyt;

IStorage * pstg;

HRESULT hResult;

HRESULT hReturn;

*ppstgOpenA = NULL;

hReturn = WrapILockBytesWFromA(plckbytA, &plckbyt);

if (FAILED(hReturn))

return (hReturn);

hReturn = StgCreateDocfileOnILockBytes(plckbyt, grfMode, reserved, &pstg);

if (FAILED(hReturn))

goto Error;

hResult = WrapIStorageAFromW(pstg, ppstgOpenA);

if (FAILED(hResult))

hReturn = hResult;

if (pstg)

pstg->Release();

Error:

if (plckbyt)

plckbyt->Release();

return hReturn;

}

//+--------------------------------------------------------------------------

//

//  Routine:    StgOpenStorageA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI StgOpenStorageA(LPCSTR pcsNameA,

  IStorageA *pstgPriorityA,

  DWORD grfMode,

  SNBA snbExcludeA,

  DWORD reserved,

  IStorageA * *ppstgOpenA)

{

TraceSTDAPIEnter("StgOpenStorageA");

OLECHAR   csName[MAX_PATH];

LPOLESTR  pcsName;

LPSTORAGE pstgPriority;

SNB       snbExclude;

LPSTORAGE pstg;

HRESULT   hResult;

*ppstgOpenA = NULL;

if (pcsNameA)

{

ConvertStringToW(pcsNameA, csName);

pcsName= csName;

}

else

pcsName = NULL;

hResult = WrapIStorageWFromA(pstgPriorityA, &pstgPriority);

if (FAILED(hResult))

return hResult;

hResult = ConvertSNBToW(snbExcludeA, &snbExclude);

if (FAILED(hResult))

goto Error;

hResult = StgOpenStorage(pcsName, pstgPriority, grfMode, snbExclude, reserved, &pstg);

if (FAILED(hResult))

goto Error1;

hResult = WrapIStorageAFromW(pstg, ppstgOpenA);

if (pstg)

pstg->Release();

Error1:

ConvertSNBFree(snbExclude);

Error:

if (pstgPriority)

pstgPriority->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    StgOpenStorageOnILockBytesA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI StgOpenStorageOnILockBytesA(ILockBytesA *plckbytA,

  IStorageA *pstgPriorityA,

  DWORD grfMode,

  SNBA snbExcludeA,

  DWORD reserved,

  IStorageA * *ppstgOpenA)

{

TraceSTDAPIEnter("StgOpenStorageOnILockBytesA");

ILockBytes * plckbyt;

IStorage * pstgPriority;

IStorage * pstg;

SNB        snbExclude;

HRESULT hResult;

*ppstgOpenA = NULL;

hResult = WrapILockBytesWFromA(plckbytA, &plckbyt);

if (FAILED(hResult))

return (hResult);

hResult = WrapIStorageWFromA(pstgPriorityA, &pstgPriority);

if (FAILED(hResult))

goto Error;

hResult = ConvertSNBToW(snbExcludeA, &snbExclude);

if (FAILED(hResult))

goto Error1;

hResult = StgOpenStorageOnILockBytes(plckbyt, pstgPriority, grfMode, snbExclude, reserved, &pstg);

if (FAILED(hResult))

goto Error2;

hResult = WrapIStorageAFromW(pstg, ppstgOpenA);

if (pstg)

pstg->Release();

Error2:

ConvertSNBFree(snbExclude);

Error1:

if (pstgPriority)

pstgPriority->Release();

Error:

if (plckbyt)

plckbyt->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    StgIsStorageFileA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI StgIsStorageFileA(LPCSTR pcsNameA)

{

TraceSTDAPIEnter("StgIsStorageFileA");

OLECHAR csName[MAX_PATH];

ConvertStringToW(pcsNameA, csName);

return StgIsStorageFile(csName);

}

//+--------------------------------------------------------------------------

//

//  Routine:    StgIsStorageILockBytesA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI StgIsStorageILockBytesA(ILockBytesA * plckbytA)

{

TraceSTDAPIEnter("StgIsStorageILockBytesA");

ILockBytes * plckbyt;

HRESULT hResult;

hResult = WrapILockBytesWFromA(plckbytA, &plckbyt);

if (FAILED(hResult))

return (hResult);

hResult = StgIsStorageILockBytes(plckbyt);

if (plckbyt)

plckbyt->Release();

return hResult;

}

//+--------------------------------------------------------------------------

//

//  Routine:    StgSetTimesA

//

//  Synopsis:   Creates an ANSI wrapper of an Unicode OLE2 routine.

//

//  Note:       See OLE2 docs for details on this API.

//

//---------------------------------------------------------------------------

STDAPI StgSetTimesA(LPCSTR lpszNameA,

  FILETIME const FAR* pctime,

  FILETIME const FAR* patime,

  FILETIME const FAR* pmtime)

{

TraceSTDAPIEnter("StgSetTimesA");

OLECHAR szName[MAX_PATH];

ConvertStringToW(lpszNameA, szName);

return StgSetTimes(szName, pctime, patime, pmtime);

}


 CONVCTL.H  (OLEANSI Sample)

//+--------------------------------------------------------------------------

//

//  Copyright (C) 1994, Microsoft Corporation.  All Rights Reserved.

//

//  File:       ConvCtl.h

//

//  Contents:   ANSI Wrappers for OLE Control Interfaces and APIs.

//

//  History:    01-Jun-94   johnels     Created.

//

//---------------------------------------------------------------------------

HRESULT ConvertPROPPAGEINFOToA(LPPROPPAGEINFO, LPPROPPAGEINFOA);

HRESULT ConvertPROPPAGEINFOToW(LPPROPPAGEINFOA, LPPROPPAGEINFO);

void ConvertPROPPAGEINFOFree(LPPROPPAGEINFO);

void ConvertPROPPAGEINFOFree(LPPROPPAGEINFOA);


 CONVCTL.CPP  (OLEANSI Sample)

//+--------------------------------------------------------------------------

//

//  Copyright (C) 1994, Microsoft Corporation.  All Rights Reserved.

//

//  File:       ConvCtl.cpp

//

//  Contents:   ANSI Wrappers for OLE Control Interfaces and APIs.

//

//  History:    01-Jun-94   johnels     Created.

//

//---------------------------------------------------------------------------

#include "Ole2Ansi.h"

HRESULT ConvertPROPPAGEINFOToA(LPPROPPAGEINFO pPageInfo,

LPPROPPAGEINFOA pPageInfoA)

{

HRESULT hResult;

memcpy((LPVOID)pPageInfoA, (LPVOID)pPageInfo, sizeof(PROPPAGEINFO));

hResult = ConvertStringToA(pPageInfo->pszTitle, &pPageInfoA->pszTitle);

if (FAILED(hResult))

return hResult;

hResult = ConvertStringToA(pPageInfo->pszDocString, &pPageInfoA->pszDocString);

if (FAILED(hResult))

goto Error1;

hResult = ConvertStringToA(pPageInfo->pszHelpFile, &pPageInfoA->pszHelpFile);

if (FAILED(hResult))

goto Error2;

return hResult;

Error2:

ConvertStringFree(pPageInfoA->pszDocString);

pPageInfoA->pszDocString = NULL;

Error1:

ConvertStringFree(pPageInfoA->pszTitle);

pPageInfoA->pszTitle = NULL;

return hResult;

}

HRESULT ConvertPROPPAGEINFOToW(LPPROPPAGEINFOA pPageInfoA,

LPPROPPAGEINFO pPageInfo)

{

HRESULT hResult;

memcpy((LPVOID)pPageInfo, (LPVOID)pPageInfoA, sizeof(PROPPAGEINFO));

hResult = ConvertStringToW(pPageInfoA->pszTitle, &pPageInfo->pszTitle);

if (FAILED(hResult))

return hResult;

hResult = ConvertStringToW(pPageInfoA->pszDocString, &pPageInfo->pszDocString);

if (FAILED(hResult))

goto Error1;

hResult = ConvertStringToW(pPageInfoA->pszHelpFile, &pPageInfo->pszHelpFile);

if (FAILED(hResult))

goto Error2;

return hResult;

Error2:

ConvertStringFree(pPageInfo->pszDocString);

pPageInfo->pszDocString = NULL;

Error1:

ConvertStringFree(pPageInfo->pszTitle);

pPageInfo->pszTitle = NULL;

return hResult;

}

void ConvertPROPPAGEINFOFree(LPPROPPAGEINFO pPageInfo)

{

ConvertStringFree(pPageInfo->pszTitle);

ConvertStringFree(pPageInfo->pszDocString);

ConvertStringFree(pPageInfo->pszHelpFile);

}

void ConvertPROPPAGEINFOFree(LPPROPPAGEINFOA pPageInfoA)

{

ConvertStringFree(pPageInfoA->pszTitle);

ConvertStringFree(pPageInfoA->pszDocString);

ConvertStringFree(pPageInfoA->pszHelpFile);

}


OUTLINE

TOPIC: OLE 2.0 Outline Sample Code FILE: readme.txt DATE: 11/11/93

OUTLINE SERIES --------------

This sample application set demonstrates taking a 'base' application (in this case OUTLINE.EXE) and extending it into an OLE 2 server and container (SVROUTL and CNTROUTL respectively) and into OLE 2 in-place  (aka visual editing) container (ICNTROTL).

These applications attempt to implement the complete OLE 2 functionality and recommended user model. For example, these  applications implement all of the OLE 2 User Interface dialogs. As such this is not a trivial sample application set.

All OUTLINE applications support loading/saving files; they all use  docfiles for storage.

DIRECTORY STRUCTURE -------------------

The OUTLINE sample uses the following directory structure:

                           OUTLINE

                              |

       +--------------+------------+--------+--------+
       |              |            |        |        |
    OUTLINE        OLE2UI        WRAPUI  BTTNCUR    GIZMOBAR

    OUTLINE     -- source directory for OUTLINE sample app series
    OLE2UI      -- source directory for common OLE 2 UI library using
                   Unicode OLE.
    WRAPUI      -- source directory for common OLE 2 UI library using
                   OLE2ANSI wrappers for the OLE 2 calls.

All five variations of the OUTLINE applications are built from common sources.  All of the common source code (*.C and *.H files) is in the OUTLINE directory. Each variant of the application builds in the same directory for this release.

Files that begin with OUTL comprise the base version of the  application. They are also used by OLE versions of the applicaton. Files  that begin with CNTR are specific to the container version and files that begin with SVR are specific to the server version.  Files that begin with OLE are common to both the container and server versions. This series of sample applications highlights the changes necessary to implement OLE into an existing application.  The container version has the same functionality as the base (OUTLINE) and also allows you to embed objects.

Some of the major OLE features are organized into special files in order to group related code across the application variants:

    DRAGDROP.C  -- Drag/Drop implementation
    CLIPBRD.C   -- OLE 2 style copy/paste implementation (data transfer)
    LINKING.C   -- Linking and Moniker support implementation
    CNTRINPL.C  -- In-place container implementation
    SVRINPL.C   -- In-place server implementation
    CLASSFAC.C  -- IClassFactory implementation

Conditional compilation is used to control what code is used with which version. The following defines are used to control the compilation:

    OLE_VERSION         -- code common to all OLE versions
    OLE_SERVER          -- code used by both SVROUTL and ISVROTL
    OLE_CNTR            -- code used by both CNTROUTL and ICNTROTL
    INPLACE_CNTR        -- code used by ICNTROTL only

The following defines are used to identify code specific for a particular feature (NOTE: it is not really intended that these symbols should be  turned of):

    USE_DRAGDROP        -- drag/drop code
    USE_FRAMETOOLS      -- formula bar and tool bar
    USE_HEADING         -- row/column headings code
    USE_STATUSBAR       -- status bar code
    USE_CTL3D           -- use CTL3D.DLL to have 3D effect for dialogs
    USE_MSGFILTER       -- IMessageFilter code
    _DEBUG              -- debug code

HOW TO BUILD ------------

To build, simple do an nmake -a -i from the root of the outline directory.

This will first build a version of the OLE2UI library, using it's own ANSI to UNICODE translations. This library is a private version of the OLE2UI  library to be used exclusively by the OUTLINE samples applications.

NO OTHER APPLICATION MAY SHIP A DLL CALLED "OUTLUI.DLL".

Every application that builds the OLE2UI library as a DLL must build it with a unique name for that application. See the  OLE2UI\README.TXT for instructions on how to build the OLE2UI library.

NOTES ON WRAPUI ---------------

WRAPUI builds a dll with the same functionality as OLE2UI, except that it uses the OLE2ANSI wrappers provided in the ole2\ole2ansi directory instead of doing its own ANSI to UNICODE translation.  In general we recommend that ISVs actually provide their own translation since it will improve the performance and reduce the size of your application.  However we realize that for a large project this may not be a feasible solution, so we have provided WRAPUI to illustrate how you may use the OLE2ANSI wrappers in your own application.  Please see the ole2\ole2ansi\readme.txt for further info- rmation regarding the wrappers.


MAKEFILE  (OUTLINE Sample)

#

# (c) Copyright Microsoft Corp. 1992 All Rights Reserved

#

# Makefile : Builds the OLE 2.0 Outline series sample apps

#        The Outline series includes:

#           Outline.exe -- base version of app (w/o OLE functionality)

#           SvrOutl.exe -- OLE 2.0 Server sample app

#           CntrOutl.exe -- OLE 2.0 Containter (Container) sample app

#        NOTE: apps are built in a subdir of same name as app.

#

# Usage:     NMAKE              (builds all executables)

#    or:     NMAKE APP=outline  (build outline.exe--non-OLE version)

#    or:     NMAKE APP=svroutl  (build svroutl.exe--server-only version)

#    or:     NMAKE APP=cntroutl (build cntroutl.exe--container-only version)

#    or:     NMAKE APP=icntrotl (build icntrotl.exe--InPlace container ver.)

#    or:     NMAKE APP=isvrotl  (build isvrotl.exe--InPlace server ver.)

#    or:     NMAKE clean        (erase all compiled files)

#

!include <$(MSTOOLS)\samples\ole\include\olesampl.mak>

!if "$(APP)" == ""

APPS = outline.exe svroutl.exe cntroutl.exe icntrotl.exe isvrotl.exe

!else

APPS = $(APP).exe

!endif

all: $(APPS)

$(APPS):

    nmake -a -f outline.mk APP=$*

##########################################################################

#

# clean (erase) generated files

clean:

    -del *.obj

    -del *.res

    -del *.exe

    -del *.map

    -del *.pch


ANSIAPI.H  (OUTLINE Sample)

/*

 * ansiapi.h

 * This file contains prototypes of ANSI version of OLE apis

 * and mapping fooA to foo

 */

#ifndef _ANSIAPI_INCL

#define _ANSIAPI_INCL

#define UNICODEOLE32

#ifdef WIN32S

#if !defined(UNICODEOLE32)

#pragma message("Compiling for 32bit ANSI Ole!\n");

#endif

#endif

#define WASANSI() {                                                           \

                   OutputDebugString("\n\r\t\tUnicode string was ANSI!\r\n"); \

                   Assert(0);                                                 \

                   _asm { int 3 }                                             \

                  }

#ifndef UNICODEOLE32

#define W2A(w, a, cb)     lstrcpy (a, w)

#define A2W(a, w, cb)     lstrcpy (w, a)

#define FREELOCALSTRING(p)

#define MAKE_STR_LOCAL_COPYW2A(s, l)  l = s

#define MAKE_STR_LOCAL_COPYA2W(s, l)  l = s

#define OLESTRCPY                lstrcpy

#define OLESTRCAT                lstrcat

#define OLESTRLEN                lstrlen

#define OLESTRCMP                lstrcmp

#define DeleteFile_AW            DeleteFile

#define _lopen_AW                _lopen

#define _lcreat_AW               _lcreat

#define GlobalAddAtom_AW         GlobalAddAtom

#define GlobalGetAtomName_AW     GlobalGetAtomName

#define RegOpenKey_AW            RegOpenKey

#define CoLoadLibraryA   CoLoadLibrary

#define StringFromCLSID2A    StringFromCLSID2

#define StringFromIID2A      StringFromIID2

#define StringFromGUID2A     StringFromGUID2

#define CLSIDFromProgIDA     CLSIDFromProgID

#define CLSIDFromStringA     CLSIDFromString

#define ProgIDFromCLSIDA     ProgIDFromCLSID

#define StringFromCLSIDA     StringFromCLSID

#define UtDupStringA2W       UtDupString

// Storage APIs

#define StgOpenStorageA      StgOpenStorage

// IPersistFile ansi translation

#define IPersistFile_LoadA(pf, file, mode) (pf)->Load(file, mode)

// IMoniker ansi translation

#define IMoniker_GetDisplayNameA(pm, p1, p2, p3) (pm)->GetDisplayName(p1,p2,p3)

#define CreateFileMonikerA   CreateFileMoniker

#else  // UNICODEOLE32

#define W2A(w, a, cb)     WideCharToMultiByte(                              \

                                               CP_ACP,                      \

                                               0,                           \

                                               w,                           \

                                               -1,                          \

                                               a,                           \

                                               cb,                          \

                                               NULL,                        \

                                               NULL)

#define A2W(a, w, cb)     MultiByteToWideChar(                              \

                                               CP_ACP,                      \

                                               0,                           \

                                               a,                           \

                                               -1,                          \

                                               w,                           \

                                               cb)

#define FREELOCALSTRING(p)      delete (p)

#define MAKE_STR_LOCAL_COPYW2A(s, l)  {                                   \

                                      l = UtDupStringW2A(s);              \

                                      if (!l) {                           \

                                         return ResultFromScode(S_OOM);   \

                                      }                                   \

                                   }

#define MAKE_STR_LOCAL_COPYA2W(s, l)  {                                   \

                                      l = UtDupStringA2W(s);              \

                                      if (!l) {                           \

                                         return ResultFromScode(S_OOM);   \

                                      }                                   \

                                   }

#define OLESTRCPY                lstrcpyW

#define OLESTRCAT                lstrcatW

#define OLESTRLEN                lstrlenW

#define OLESTRCMP                lstrcmpW

#define DeleteFile_AW            DeleteFileW

#define _lopen_AW                _lopenW

#define _lcreat_AW               _lcreatW

#define GlobalAddAtom_AW         GlobalAddAtomW

#define GlobalGetAtomName_AW     GlobalGetAtomNameW

#define RegOpenKey_AW            RegOpenKeyW

//STDAPI_(HINSTANCE) CoLoadLibraryA(LPSTR lpszLibName, BOOL bAutoFree);

#define StringFromCLSID2A(rclsid, lpsz, cbMax) \

    StringFromGUID2A(rclsid, lpsz, cbMax)

#define StringFromIID2A(riid, lpsz, cbMax) \

    StringFromGUID2A(riid, lpsz, cbMax)

//STDAPI_(int)  StringFromGUID2A(REFGUID rguid, LPSTR lpsz, int cbMax);

//STDAPI        CLSIDFromProgIDA(LPCSTR szProgID, LPCLSID pclsid);

//STDAPI        CLSIDFromStringA(LPSTR lpsz, LPCLSID lpclsid);

//STDAPI        StringFromCLSIDA(REFCLSID rclsid, LPSTR FAR* lplpsz);

//STDAPI        ProgIDFromCLSIDA (REFCLSID clsid, LPSTR FAR* lplpszProgID);

//LPWSTR UtDupStringA2W(LPCSTR pSrc);

//LPSTR  UtDupStringW2A(LPCWSTR pSrc);

// Storage APIs

//STDAPI StgOpenStorageA(LPCSTR pwcsName,IStorage FAR *pstgPriority, DWORD grfMode, SNB snbExclude, DWORD reserved, IStorage FAR * FAR *ppstgOpen);

// IPersistFile ansi translation

//HRESULT IPersistFile_LoadA(LPPERSISTFILE pIPF, LPSTR szFile, DWORD dwMode);

// IMoniker ansi translation

//HRESULT IMoniker_GetDisplayNameA(LPMONIKER pm, LPBC p1, LPMONIKER p2, LPSTR FAR *p3);

//OLEAPI CreateFileMonikerA ( LPSTR lpszPathName, LPMONIKER FAR * ppmk );

#endif // !UNICODEOLE32

#endif //  _ANSIAPI_INCL


CLASSFAC.C  (OUTLINE Sample)

/*************************************************************************

**

**    OLE 2 Sample Code

**

**    classfac.c

**

**    This file contains the implementation for IClassFactory for both the

**    server and the client version of the OUTLINE app.

**

**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

**

*************************************************************************/

#include "outline.h"

OLEDBGDATA

extern LPOUTLINEAPP             g_lpApp;

/* OLE2NOTE: this object illustrates the manner in which to statically

**    (compile-time) initialize an interface VTBL.

*/

static IClassFactoryVtbl g_AppClassFactoryVtbl = {

AppClassFactory_QueryInterface,

AppClassFactory_AddRef,

AppClassFactory_Release,

AppClassFactory_CreateInstance,

AppClassFactory_LockServer

};

/* AppClassFactory_Create

** ----------------------

**    create an instance of APPCLASSFACTORY.

**    NOTE: type of pointer returned is an IClassFactory* interface ptr.

**          the returned pointer can be directly passed to

**          CoRegisterClassObject and released later by calling the

**          Release method of the interface.

*/

LPCLASSFACTORY WINAPI AppClassFactory_Create(void)

{

LPAPPCLASSFACTORY lpAppClassFactory;

LPMALLOC lpMalloc;

if (CoGetMalloc(MEMCTX_TASK, (LPMALLOC FAR*)&lpMalloc) != NOERROR)

return NULL;

lpAppClassFactory = (LPAPPCLASSFACTORY)lpMalloc->lpVtbl->Alloc(

lpMalloc, (sizeof(APPCLASSFACTORY)));

lpMalloc->lpVtbl->Release(lpMalloc);

if (! lpAppClassFactory) return NULL;

lpAppClassFactory->m_lpVtbl = &g_AppClassFactoryVtbl;

lpAppClassFactory->m_cRef   = 1;

#if defined( _DEBUG )

lpAppClassFactory->m_cSvrLock = 0;

#endif

return (LPCLASSFACTORY)lpAppClassFactory;

}

/*************************************************************************

** OleApp::IClassFactory interface implementation

*************************************************************************/

STDMETHODIMP AppClassFactory_QueryInterface(

LPCLASSFACTORY lpThis, REFIID riid, LPVOID FAR* ppvObj)

{

LPAPPCLASSFACTORY lpAppClassFactory = (LPAPPCLASSFACTORY)lpThis;

SCODE scode;

// Two interfaces supported: IUnknown, IClassFactory

if (IsEqualIID(riid, &IID_IClassFactory) ||

IsEqualIID(riid, &IID_IUnknown)) {

lpAppClassFactory->m_cRef++;   // A pointer to this object is returned

*ppvObj = lpThis;

scode = S_OK;

}

else {                 // unsupported interface

*ppvObj = NULL;

scode = E_NOINTERFACE;

}

return ResultFromScode(scode);

}

STDMETHODIMP_(ULONG) AppClassFactory_AddRef(LPCLASSFACTORY lpThis)

{

LPAPPCLASSFACTORY lpAppClassFactory = (LPAPPCLASSFACTORY)lpThis;

return ++lpAppClassFactory->m_cRef;

}

STDMETHODIMP_(ULONG) AppClassFactory_Release(LPCLASSFACTORY lpThis)

{

LPAPPCLASSFACTORY lpAppClassFactory = (LPAPPCLASSFACTORY)lpThis;

LPMALLOC lpMalloc;

if (--lpAppClassFactory->m_cRef != 0) // Still used by others

return lpAppClassFactory->m_cRef;

// Free storage

if (CoGetMalloc(MEMCTX_TASK, (LPMALLOC FAR*)&lpMalloc) != NOERROR)

return 0;

lpMalloc->lpVtbl->Free(lpMalloc, lpAppClassFactory);

lpMalloc->lpVtbl->Release(lpMalloc);

return 0;

}

STDMETHODIMP AppClassFactory_CreateInstance (

LPCLASSFACTORY      lpThis,

LPUNKNOWN           lpUnkOuter,

REFIID              riid,

LPVOID FAR*         lplpvObj

)

{

LPOUTLINEAPP    lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

LPOLEDOC        lpOleDoc;

HRESULT         hrErr;

OLEDBG_BEGIN2("AppClassFactory_CreateInstance\r\n")

/* OLE2NOTE: we must make sure to set all out parameters to NULL. */

*lplpvObj = NULL;

/*********************************************************************

** OLE2NOTE: this is an SDI app; it can only create and support one

**    instance. After the instance is created, the OLE libraries

**    should not call CreateInstance again. it is a good practise

**    to specifically guard against this.

*********************************************************************/

if (lpOutlineApp->m_lpDoc != NULL)

return ResultFromScode(E_UNEXPECTED);

/* OLE2NOTE: create a new document instance. by the time we return

**    from this method the document's refcnt must be 1.

*/

lpOutlineApp->m_lpDoc = OutlineApp_CreateDoc(lpOutlineApp, FALSE);

lpOleDoc = (LPOLEDOC)lpOutlineApp->m_lpDoc;

if (! lpOleDoc) {

OLEDBG_END2

return ResultFromScode(E_OUTOFMEMORY);

}

/* OLE2NOTE: retrieve pointer to requested interface. the ref cnt

**    of the object after OutlineApp_CreateDoc is 0. this call to

**    QueryInterface will increment the refcnt to 1. the object

**    returned from IClassFactory::CreateInstance should have a

**    refcnt of 1 and be controlled by the caller. If the caller

**    releases the document, the document should be destroyed.

*/

hrErr = OleDoc_QueryInterface(lpOleDoc, riid, lplpvObj);

OLEDBG_END2

return hrErr;

}

STDMETHODIMP AppClassFactory_LockServer (

LPCLASSFACTORY      lpThis,

BOOL                fLock

)

{

LPAPPCLASSFACTORY lpAppClassFactory = (LPAPPCLASSFACTORY)lpThis;

LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp;

HRESULT hrErr;

OLEDBG_BEGIN2("AppClassFactory_LockServer\r\n")

#if defined( _DEBUG )

if (fLock) {

++lpAppClassFactory->m_cSvrLock;

OleDbgOutRefCnt3(

"AppClassFactory_LockServer: cLock++\r\n",

lpAppClassFactory, lpAppClassFactory->m_cSvrLock);

} else {

/* OLE2NOTE: when there are no open documents and the app is not

**    under the control of the user and there are no outstanding

**    locks on the app, then revoke our ClassFactory to enable the

**    app to shut down.

*/

--lpAppClassFactory->m_cSvrLock;

OleDbgAssertSz (lpAppClassFactory->m_cSvrLock >= 0,

"AppClassFactory_LockServer(FALSE) called with cLock == 0"

);

if (lpAppClassFactory->m_cSvrLock == 0) {

OleDbgOutRefCnt2(

"AppClassFactory_LockServer: UNLOCKED\r\n",

lpAppClassFactory, lpAppClassFactory->m_cSvrLock);

} else {

OleDbgOutRefCnt3(

"AppClassFactory_LockServer: cLock--\r\n",

lpAppClassFactory, lpAppClassFactory->m_cSvrLock);

}

}

#endif  // _DEBUG

/* OLE2NOTE: in order to hold the application alive we call

**    CoLockObjectExternal to add a strong reference to our app

**    object. this will keep the app alive when all other external

**    references release us. if the user issues File.Exit the

**    application will shut down in any case ignoring any

**    outstanding LockServer locks because CoDisconnectObject is

**    called in OleApp_CloseAllDocsAndExitCommand. this will

**    forceably break any existing strong reference counts

**    including counts that we add ourselves by calling

**    CoLockObjectExternal and guarantee that the App object gets

**    its final release (ie. cRefs goes to 0).

*/

hrErr = OleApp_Lock(lpOleApp, fLock, TRUE /* fLastUnlockReleases */);

OLEDBG_END2

return hrErr;

}


CLIPBRD.C  (OUTLINE Sample)

/*************************************************************************

**

**    OLE 2 Sample Code

**

**    clipbrd.c

**

**    This file contains the major interfaces, methods and related support

**    functions for implementing clipboard data transfer. The code

**    contained in this file is used by BOTH the Container and Server

**    (Object) versions of the Outline sample code.

**    (see file dragdrop.c for Drag/Drop support implementation)

**

**    OleDoc Object

**      exposed interfaces:

**          IDataObject

**

**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

**

*************************************************************************/

#include "outline.h"

OLEDBGDATA

extern LPOUTLINEAPP             g_lpApp;

// REVIEW: should use string resource for messages

OLECHAR ErrMsgPasting[] = OLESTR("Could not paste data from clipboard!");

OLECHAR ErrMsgBadFmt[] = OLESTR("Invalid format selected!");

OLECHAR ErrMsgPasteFailed[] = OLESTR("Could not paste data from clipboard!");

OLECHAR ErrMsgClipboardChanged[] = OLESTR("Contents of clipboard have changed!\r\nNo paste performed.");

#ifdef WIN32S

#define GALLOCFLG (GMEM_SHARE | GMEM_ZEROINIT | GMEM_MOVEABLE)

#else

#define GALLOCFLG (GMEM_SHARE | GMEM_ZEROINIT)

#endif

/*************************************************************************

** OleDoc::IDataObject interface implementation

*************************************************************************/

// IDataObject::QueryInterface

STDMETHODIMP OleDoc_DataObj_QueryInterface (

      LPDATAOBJECT        lpThis,

      REFIID              riid,

      LPVOID FAR*         lplpvObj

)

{

   LPOLEDOC lpOleDoc = ((struct CDocDataObjectImpl FAR*)lpThis)->lpOleDoc;

   return OleDoc_QueryInterface((LPOLEDOC)lpOleDoc, riid, lplpvObj);

}

// IDataObject::AddRef

STDMETHODIMP_(ULONG) OleDoc_DataObj_AddRef(LPDATAOBJECT lpThis)

{

   LPOLEDOC lpOleDoc = ((struct CDocDataObjectImpl FAR*)lpThis)->lpOleDoc;

   OleDbgAddRefMethod(lpThis, "IDataObject");

   return OleDoc_AddRef((LPOLEDOC)lpOleDoc);

}

// IDataObject::Release

STDMETHODIMP_(ULONG) OleDoc_DataObj_Release (LPDATAOBJECT lpThis)

{

   LPOLEDOC lpOleDoc = ((struct CDocDataObjectImpl FAR*)lpThis)->lpOleDoc;

   OleDbgReleaseMethod(lpThis, "IDataObject");

   return OleDoc_Release((LPOLEDOC)lpOleDoc);

}

// IDataObject::GetData

STDMETHODIMP OleDoc_DataObj_GetData (

      LPDATAOBJECT        lpThis,

      LPFORMATETC         lpFormatetc,

      LPSTGMEDIUM         lpMedium

)

{

   LPOLEDOC lpOleDoc = ((struct CDocDataObjectImpl FAR*)lpThis)->lpOleDoc;

   HRESULT hrErr;

   OLEDBG_BEGIN2("OleDoc_DataObj_GetData\r\n")

#if defined( OLE_SERVER )

   // Call OLE Server specific version of this function

   hrErr = ServerDoc_GetData((LPSERVERDOC)lpOleDoc, lpFormatetc, lpMedium);

#endif

#if defined( OLE_CNTR )

   // Call OLE Container specific version of this function

   hrErr = ContainerDoc_GetData(

         (LPCONTAINERDOC)lpOleDoc,

         lpFormatetc,

         lpMedium

   );

#endif

   OLEDBG_END2

   return hrErr;

}

// IDataObject::GetDataHere

STDMETHODIMP OleDoc_DataObj_GetDataHere (

      LPDATAOBJECT        lpThis,

      LPFORMATETC         lpFormatetc,

      LPSTGMEDIUM         lpMedium

)

{

   LPOLEDOC lpOleDoc = ((struct CDocDataObjectImpl FAR*)lpThis)->lpOleDoc;

   HRESULT hrErr;

   OLEDBG_BEGIN2("OleDoc_DataObj_GetDataHere\r\n")

#if defined( OLE_SERVER )

   // Call OLE Server specific version of this function

   hrErr = ServerDoc_GetDataHere(

         (LPSERVERDOC)lpOleDoc,

         lpFormatetc,

         lpMedium

   );

#endif

#if defined( OLE_CNTR )

   // Call OLE Container specific version of this function

   hrErr = ContainerDoc_GetDataHere(

         (LPCONTAINERDOC)lpOleDoc,

         lpFormatetc,

         lpMedium

   );

#endif

   OLEDBG_END2

   return hrErr;

}

// IDataObject::QueryGetData

STDMETHODIMP OleDoc_DataObj_QueryGetData (

      LPDATAOBJECT        lpThis,

      LPFORMATETC         lpFormatetc

)

{

   LPOLEDOC lpOleDoc = ((struct CDocDataObjectImpl FAR*)lpThis)->lpOleDoc;

   HRESULT hrErr;

   OLEDBG_BEGIN2("OleDoc_DataObj_QueryGetData\r\n");

#if defined( OLE_SERVER )

   // Call OLE Server specific version of this function

   hrErr = ServerDoc_QueryGetData((LPSERVERDOC)lpOleDoc, lpFormatetc);

#endif

#if defined( OLE_CNTR )

   // Call OLE Container specific version of this function

   hrErr = ContainerDoc_QueryGetData((LPCONTAINERDOC)lpOleDoc, lpFormatetc);

#endif

   OLEDBG_END2

   return hrErr;

}

// IDataObject::GetCanonicalFormatEtc

STDMETHODIMP OleDoc_DataObj_GetCanonicalFormatEtc(

      LPDATAOBJECT        lpThis,

      LPFORMATETC         lpformatetc,

      LPFORMATETC         lpformatetcOut

)

{

   HRESULT hrErr;

   OleDbgOut2("OleDoc_DataObj_GetCanonicalFormatEtc\r\n");

   if (!lpformatetcOut)

      return ResultFromScode(E_INVALIDARG);

   /* OLE2NOTE: we must make sure to set all out parameters to NULL. */

   lpformatetcOut->ptd = NULL;

   if (!lpformatetc)

      return ResultFromScode(E_INVALIDARG);

   // OLE2NOTE: we must validate that the format requested is supported

   if ((hrErr=lpThis->lpVtbl->QueryGetData(lpThis,lpformatetc)) != NOERROR)

      return hrErr;

   /* OLE2NOTE: an app that is insensitive to target device (as the

   **    Outline Sample is) should fill in the lpformatOut parameter

   **    but NULL out the "ptd" field; it should return NOERROR if the

   **    input formatetc->ptd what non-NULL. this tells the caller

   **    that it is NOT necessary to maintain a separate screen

   **    rendering and printer rendering. if should return

   **    DATA_S_SAMEFORMATETC if the input and output formatetc's are

   **    identical.

   */

   *lpformatetcOut = *lpformatetc;

   if (lpformatetc->ptd == NULL)

      return ResultFromScode(DATA_S_SAMEFORMATETC);

   else {

      lpformatetcOut->ptd = NULL;

      return NOERROR;

   }

}

// IDataObject::SetData

STDMETHODIMP OleDoc_DataObj_SetData (

      LPDATAOBJECT    lpThis,

      LPFORMATETC     lpFormatetc,

      LPSTGMEDIUM     lpMedium,

      BOOL            fRelease

)

{

   LPOLEDOC lpOleDoc = ((struct CDocDataObjectImpl FAR*)lpThis)->lpOleDoc;

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc;

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   SCODE sc = S_OK;

   OLEDBG_BEGIN2("OleDoc_DataObj_SetData\r\n")

   /* OLE2NOTE: a document that is used to transfer data (either via

   **    the clipboard or drag/drop) does NOT accept SetData on ANY

   **    format!

   */

   if (lpOutlineDoc->m_fDataTransferDoc) {

      sc = E_FAIL;

      goto error;

   }

#if defined( OLE_SERVER )

   if (lpFormatetc->cfFormat == lpOutlineApp->m_cfOutline) {

      OLEDBG_BEGIN2("ServerDoc_SetData: CF_OUTLINE\r\n")

      OutlineDoc_SetRedraw ( lpOutlineDoc, FALSE );

      OutlineDoc_ClearAllLines(lpOutlineDoc);

      OutlineDoc_PasteOutlineData(lpOutlineDoc,lpMedium->u.hGlobal,-1);

      OutlineDoc_SetRedraw ( lpOutlineDoc, TRUE );

      OLEDBG_END3

   } else if (lpFormatetc->cfFormat == CF_TEXT) {

      OLEDBG_BEGIN2("ServerDoc_SetData: CF_TEXT\r\n")

      OutlineDoc_SetRedraw ( lpOutlineDoc, FALSE );

      OutlineDoc_ClearAllLines(lpOutlineDoc);

      OutlineDoc_PasteTextData(lpOutlineDoc,lpMedium->u.hGlobal,-1);

      OutlineDoc_SetRedraw ( lpOutlineDoc, TRUE );

      OLEDBG_END3

   } else {

      sc = DV_E_FORMATETC;

   }

#endif  // OLE_SERVER

#if defined( OLE_CNTR )

   /* the Container-Only version of Outline does NOT offer

   **    IDataObject interface from its User documents. this is

   **    required by objects which can be embedded or linked. the

   **    Container-only app only allows linking to its contained

   **    objects, NOT the data of the container itself.

   */

   OleDbgAssertSz(0, "User documents do NOT support IDataObject\r\n");

   sc = E_NOTIMPL;

#endif  // OLE_CNTR

error:

   /* OLE2NOTE: if fRelease==TRUE, then we must take

   **    responsibility to release the lpMedium. we should only do

   **    this if we are going to return NOERROR. if we do NOT

   **    accept the data, then we should NOT release the lpMedium.

   **    if fRelease==FALSE, then the caller retains ownership of

   **    the data.

   */

   if (sc == S_OK && fRelease)

      ReleaseStgMedium(lpMedium);

   OLEDBG_END2

   return ResultFromScode(sc);

}

// IDataObject::EnumFormatEtc

STDMETHODIMP OleDoc_DataObj_EnumFormatEtc(

      LPDATAOBJECT            lpThis,

      DWORD                   dwDirection,

      LPENUMFORMATETC FAR*    lplpenumFormatEtc

)

{

   LPOLEDOC lpOleDoc=((struct CDocDataObjectImpl FAR*)lpThis)->lpOleDoc;

   HRESULT hrErr;

   OLEDBG_BEGIN2("OleDoc_DataObj_EnumFormatEtc\r\n")

   /* OLE2NOTE: we must make sure to set all out parameters to NULL. */

   *lplpenumFormatEtc = NULL;

#if defined( OLE_SERVER )

   /* OLE2NOTE: a user document only needs to enumerate the static list

   **    of formats that are registered for our app in the

   **    registration database. OLE provides a default enumerator

   **    which enumerates from the registration database. this default

   **    enumerator is requested by returning OLE_S_USEREG. it is NOT

   **    required that a user document (ie. non-DataTransferDoc)

   **    enumerate the OLE formats: CF_LINKSOURCE, CF_EMBEDSOURCE, or

   **    CF_EMBEDDEDOBJECT.

   **

   **    An object implemented as a server EXE (as this sample

   **    is) may simply return OLE_S_USEREG to instruct the OLE

   **    DefHandler to call the OleReg* helper API which uses info in

   **    the registration database. Alternatively, the OleRegEnumFormatEtc

   **    API may be called directly. Objects implemented as a server

   **    DLL may NOT return OLE_S_USEREG; they must call the OleReg*

   **    API or provide their own implementation. For EXE based

   **    objects it is more efficient to return OLE_S_USEREG, because

   **    in then the enumerator is instantiated in the callers

   **    process space and no LRPC remoting is required.

   */

   if (! ((LPOUTLINEDOC)lpOleDoc)->m_fDataTransferDoc)

      return ResultFromScode(OLE_S_USEREG);

   // Call OLE Server specific version of this function

   hrErr = ServerDoc_EnumFormatEtc(

         (LPSERVERDOC)lpOleDoc,

         dwDirection,

         lplpenumFormatEtc

   );

#endif

#if defined( OLE_CNTR )

   // Call OLE Container specific version of this function

   hrErr = ContainerDoc_EnumFormatEtc(

         (LPCONTAINERDOC)lpOleDoc,

         dwDirection,

         lplpenumFormatEtc

   );

#endif

   OLEDBG_END2

   return hrErr;

}

// IDataObject::DAdvise

STDMETHODIMP OleDoc_DataObj_DAdvise(

      LPDATAOBJECT        lpThis,

      FORMATETC FAR*      lpFormatetc,

      DWORD               advf,

      LPADVISESINK        lpAdvSink,

      DWORD FAR*          lpdwConnection

)

{

   LPOLEDOC lpOleDoc=((struct CDocDataObjectImpl FAR*)lpThis)->lpOleDoc;

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc;

   SCODE sc;

   OLEDBG_BEGIN2("OleDoc_DataObj_DAdvise\r\n")

   /* OLE2NOTE: we must make sure to set all out parameters to NULL. */

   *lpdwConnection = 0;

   /* OLE2NOTE: a document that is used to transfer data (either via

   **    the clipboard or drag/drop) does NOT support Advise notifications.

   */

   if (lpOutlineDoc->m_fDataTransferDoc) {

      sc = OLE_E_ADVISENOTSUPPORTED;

      goto error;

   }

#if defined( OLE_SERVER )

   {

      HRESULT hrErr;

      LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOleDoc;

      /* OLE2NOTE: we should validate if the caller is setting up an

      **    Advise for a data type that we support. we must

      **    explicitly allow an advise for the "wildcard" advise.

      */

#ifdef WIN32

      if ( !( lpFormatetc->cfFormat == 0 &&

            lpFormatetc->ptd == 0 &&

#else

      if ( !( lpFormatetc->cfFormat == NULL &&

            lpFormatetc->ptd == NULL &&

#endif

            lpFormatetc->dwAspect == -1L &&

            lpFormatetc->lindex == -1L &&

            lpFormatetc->tymed == -1L) &&

          (hrErr = OleDoc_DataObj_QueryGetData(lpThis, lpFormatetc))

                                                != NOERROR) {

         sc = GetScode(hrErr);

         goto error;

      }

      if (lpServerDoc->m_OleDoc.m_fObjIsClosing)

      {

          // We don't accept any more Advies's once we're closing

          sc = OLE_E_ADVISENOTSUPPORTED;

          goto error;

      }

      if (lpServerDoc->m_lpDataAdviseHldr == NULL &&

         CreateDataAdviseHolder(&lpServerDoc->m_lpDataAdviseHldr)

                                                != NOERROR) {

            sc = E_OUTOFMEMORY;

            goto error;

      }

      // artificial AddRef in case someone releases this object

      // during the next call

      OleDoc_DataObj_AddRef(lpThis);

      OLEDBG_BEGIN2("IDataAdviseHolder::Advise called\r\n");

      hrErr = lpServerDoc->m_lpDataAdviseHldr->lpVtbl->Advise(

            lpServerDoc->m_lpDataAdviseHldr,

            (LPDATAOBJECT)&lpOleDoc->m_DataObject,

            lpFormatetc,

            advf,

            lpAdvSink,

            lpdwConnection

      );

      OLEDBG_END2

      // release artificial AddRef above

      OleDoc_DataObj_Release(lpThis);

      OLEDBG_END2

      return hrErr;

   }

#endif  // OLE_SVR

#if defined( OLE_CNTR )

   {

      /* the Container-Only version of Outline does NOT offer

      **    IDataObject interface from its User documents. this is

      **    required by objects which can be embedded or linked. the

      **    Container-only app only allows linking to its contained

      **    objects, NOT the data of the container itself.

      */

      OleDbgAssertSz(0, "User documents do NOT support IDataObject\r\n");

      sc = E_NOTIMPL;

      goto error;

   }

#endif  // OLE_CNTR

error:

   OLEDBG_END2

   return ResultFromScode(sc);

}

// IDataObject::DUnadvise

STDMETHODIMP OleDoc_DataObj_DUnadvise(LPDATAOBJECT lpThis, DWORD dwConnection)

{

   LPOLEDOC lpOleDoc=((struct CDocDataObjectImpl FAR*)lpThis)->lpOleDoc;

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc;

   SCODE sc;

   OLEDBG_BEGIN2("OleDoc_DataObj_DUnadvise\r\n")

   /* OLE2NOTE: a document that is used to transfer data (either via

   **    the clipboard or drag/drop) does NOT support Advise notifications.

   */

   if (lpOutlineDoc->m_fDataTransferDoc) {

      sc = OLE_E_ADVISENOTSUPPORTED;

      goto error;

   }

#if defined( OLE_SERVER )

   {

      LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOleDoc;

      HRESULT hrErr;

      if (lpServerDoc->m_lpDataAdviseHldr == NULL) {

         sc = E_FAIL;

         goto error;

      }

      // artificial AddRef in case someone releases this object

      // during the next call

      OleDoc_DataObj_AddRef(lpThis);

      OLEDBG_BEGIN2("IDataAdviseHolder::Unadvise called\r\n");

      hrErr = lpServerDoc->m_lpDataAdviseHldr->lpVtbl->Unadvise(

            lpServerDoc->m_lpDataAdviseHldr,

            dwConnection

      );

      OLEDBG_END2

      // release artifical AddRef

      OleDoc_DataObj_Release(lpThis);

      OLEDBG_END2

      return hrErr;

   }

#endif

#if defined( OLE_CNTR )

   {

      /* the Container-Only version of Outline does NOT offer

      **    IDataObject interface from its User documents. this is

      **    required by objects which can be embedded or linked. the

      **    Container-only app only allows linking to its contained

      **    objects, NOT the data of the container itself.

      */

      OleDbgAssertSz(0, "User documents do NOT support IDataObject\r\n");

      sc = E_NOTIMPL;

      goto error;

   }

#endif

error:

   OLEDBG_END2

   return ResultFromScode(sc);

}

// IDataObject::EnumDAdvise

STDMETHODIMP OleDoc_DataObj_EnumDAdvise(

      LPDATAOBJECT        lpThis,

      LPENUMSTATDATA FAR* lplpenumAdvise

)

{

   LPOLEDOC lpOleDoc=((struct CDocDataObjectImpl FAR*)lpThis)->lpOleDoc;

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc;

   SCODE sc;

   OLEDBG_BEGIN2("OleDoc_DataObj_EnumDAdvise\r\n")

   /* OLE2NOTE: we must make sure to set all out parameters to NULL. */

   *lplpenumAdvise = NULL;

   /* OLE2NOTE: a document that is used to transfer data (either via

   **    the clipboard or drag/drop) does NOT support Advise notifications.

   */

   if (lpOutlineDoc->m_fDataTransferDoc) {

      sc = OLE_E_ADVISENOTSUPPORTED;

      goto error;

   }

#if defined( OLE_SERVER )

   {

      LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOleDoc;

      HRESULT hrErr;

      if (lpServerDoc->m_lpDataAdviseHldr == NULL) {

         sc = E_FAIL;

         goto error;

      }

      // artificial AddRef in case someone releases this

      // object during the next call

      OleDoc_DataObj_AddRef(lpThis);

      OLEDBG_BEGIN2("IDataAdviseHolder::EnumAdvise called\r\n");

      hrErr = lpServerDoc->m_lpDataAdviseHldr->lpVtbl->EnumAdvise(

            lpServerDoc->m_lpDataAdviseHldr,

            lplpenumAdvise

      );

      OLEDBG_END2

      // release artifical AddRef

      OleDoc_DataObj_Release(lpThis);

      OLEDBG_END2

      return hrErr;

   }

#endif

#if defined( OLE_CNTR )

   {

      /* the Container-Only version of Outline does NOT offer

      **    IDataObject interface from its User documents. this is

      **    required by objects which can be embedded or linked. the

      **    Container-only app only allows linking to its contained

      **    objects, NOT the data of the container itself.

      */

      OleDbgAssertSz(0, "User documents do NOT support IDataObject\r\n");

      sc = E_NOTIMPL;

      goto error;

   }

#endif

error:

   OLEDBG_END2

   return ResultFromScode(sc);

}

/*************************************************************************

** OleDoc Supprt Functions common to both Container and Server versions

*************************************************************************/

/* OleDoc_CopyCommand

 * ------------------

 *  Copy selection to clipboard.

 *  Post to the clipboard the formats that the app can render.

 *  the actual data is not rendered at this time. using the

 *  delayed rendering technique, Windows will send the clipboard

 *  owner window either a WM_RENDERALLFORMATS or a WM_RENDERFORMAT

 *  message when the actual data is requested.

 *

 *    OLE2NOTE: the normal delayed rendering technique where Windows

 *    sends the clipboard owner window either a WM_RENDERALLFORMATS or

 *    a WM_RENDERFORMAT message when the actual data is requested is

 *    NOT exposed to the app calling OleSetClipboard. OLE internally

 *    creates its own window as the clipboard owner and thus our app

 *    will NOT get these WM_RENDER messages.

 */

void OleDoc_CopyCommand(LPOLEDOC lpSrcOleDoc)

{

   LPOUTLINEDOC lpSrcOutlineDoc = (LPOUTLINEDOC)lpSrcOleDoc;

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   LPOUTLINEDOC lpClipboardDoc;

   /* squirrel away a copy of the current selection to the ClipboardDoc */

   lpClipboardDoc = OutlineDoc_CreateDataTransferDoc(lpSrcOutlineDoc);

   if (! lpClipboardDoc)

      return;     // Error: could not create DataTransferDoc

   lpOutlineApp->m_lpClipboardDoc = (LPOUTLINEDOC)lpClipboardDoc;

   /* OLE2NOTE: initially the Doc object is created with a 0 ref

   **    count. in order to have a stable Doc object during the

   **    process of initializing the Doc instance and transfering it

   **    to the clipboard, we intially AddRef the Doc ref cnt and later

   **    Release it. This initial AddRef is artificial; it is simply

   **    done to guarantee that a harmless QueryInterface followed by

   **    a Release does not inadvertantly force our object to destroy

   **    itself prematurely.

   */

   OleDoc_AddRef((LPOLEDOC)lpClipboardDoc);

   /* OLE2NOTE: the OLE 2.0 style to put data onto the clipboard is to

   **    give the clipboard a pointer to an IDataObject interface that

   **    is able to statisfy IDataObject::GetData calls to render

   **    data. in our case we give the pointer to the ClipboardDoc

   **    which holds a cloned copy of the current user's selection.

   */

   OLEDBG_BEGIN2("OleSetClipboard called\r\n")

   OleSetClipboard((LPDATAOBJECT)&((LPOLEDOC)lpClipboardDoc)->m_DataObject);

   OLEDBG_END2

   OleDoc_Release((LPOLEDOC)lpClipboardDoc);   // rel artificial AddRef above

}

/* OleDoc_PasteCommand

** -------------------

**    Paste default format data from the clipboard.

**    In this function we choose the highest fidelity format that the

**    source clipboard IDataObject* offers that we understand.

**

**    OLE2NOTE: clipboard handling in an OLE 2.0 application is

**    different than normal Windows clipboard handling. Data from the

**    clipboard is retieved by getting the IDataObject* pointer

**    returned by calling OleGetClipboard.

*/

void OleDoc_PasteCommand(LPOLEDOC lpOleDoc)

{

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc;

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   LPDATAOBJECT lpClipboardDataObj = NULL;

   BOOL fLink = FALSE;

   BOOL fLocalDataObj = FALSE;

   BOOL fStatus;

   HRESULT hrErr;

   hrErr = OleGetClipboard((LPDATAOBJECT FAR*)&lpClipboardDataObj);

   if (hrErr != NOERROR)

      return;     // Clipboard seems to be empty or can't be accessed

   OutlineDoc_SetRedraw ( lpOutlineDoc, FALSE );

   /* check if the data on the clipboard is local to our application

   **    instance.

   */

   if (lpOutlineApp->m_lpClipboardDoc) {

      LPOLEDOC lpOleDoc = (LPOLEDOC)lpOutlineApp->m_lpClipboardDoc;

      if (lpClipboardDataObj == (LPDATAOBJECT)&lpOleDoc->m_DataObject)

         fLocalDataObj = TRUE;

   }

   fStatus = OleDoc_PasteFromData(

         lpOleDoc,

         lpClipboardDataObj,

         fLocalDataObj,

         fLink

   );

   OutlineDoc_SetRedraw ( lpOutlineDoc, TRUE );

   if (! fStatus)

      OutlineApp_ErrorMessage(g_lpApp,OLESTR("Could not paste data from clipboard!"));

   if (lpClipboardDataObj)

      OleStdRelease((LPUNKNOWN)lpClipboardDataObj);

}

/* OleDoc_PasteSpecialCommand

** --------------------------

**    Allow the user to paste data in a particular format from the

**    clipboard. The paste special command displays a dialog to the

**    user that allows him to choose the format to be pasted from the

**    list of formats available.

**

**    OLE2NOTE: the PasteSpecial dialog is one of the standard OLE 2.0

**    UI dialogs for which the dialog is implemented and in the OLE2UI

**    library.

**

**    OLE2NOTE: clipboard handling in an OLE 2.0 application is

**    different than normal Windows clipboard handling. Data from the

**    clipboard is retieved by getting the IDataObject* pointer

**    returned by calling OleGetClipboard.

*/

void OleDoc_PasteSpecialCommand(LPOLEDOC lpOleDoc)

{

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc;

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp;

   LPDATAOBJECT lpClipboardDataObj = NULL;

   CLIPFORMAT cfFormat;

   int nFmtEtc;

   UINT uInt;

   BOOL fLink = FALSE;

   BOOL fLocalDataObj = FALSE;

   BOOL fStatus;

   HRESULT hrErr;

   OLEUIPASTESPECIAL ouiPasteSpl;

   BOOL fDisplayAsIcon;

   hrErr = OleGetClipboard((LPDATAOBJECT FAR*)&lpClipboardDataObj);

   if (hrErr != NOERROR)

      return;     // Clipboard seems to be empty or can't be accessed

   /* check if the data on the clipboard is local to our application

   **    instance.

   */

   if (lpOutlineApp->m_lpClipboardDoc) {

      LPOLEDOC lpOleDoc = (LPOLEDOC)lpOutlineApp->m_lpClipboardDoc;

      if (lpClipboardDataObj == (LPDATAOBJECT)&lpOleDoc->m_DataObject)

         fLocalDataObj = TRUE;

   }

   /* Display the PasteSpecial dialog and allow the user to select the

   **    format to paste.

   */

   _fmemset((LPOLEUIPASTESPECIAL)&ouiPasteSpl, 0, sizeof(OLEUIPASTESPECIAL));

   ouiPasteSpl.cbStruct = sizeof(OLEUIPASTESPECIAL);       //Structure Size

   ouiPasteSpl.dwFlags =  PSF_SELECTPASTE | PSF_SHOWHELP;  //IN-OUT:  Flags

   ouiPasteSpl.hWndOwner = lpOutlineApp->m_lpDoc->m_hWndDoc; //Owning window

   ouiPasteSpl.lpszCaption = OLESTR("Paste Special");    //Dialog caption bar contents

   ouiPasteSpl.lpfnHook = NULL;       //Hook callback

   ouiPasteSpl.lCustData = 0;         //Custom data to pass to hook

   ouiPasteSpl.hInstance = NULL;      //Instance for customized template name

   ouiPasteSpl.lpszTemplate = NULL;   //Customized template name

   ouiPasteSpl.hResource = NULL;      //Customized template handle

   ouiPasteSpl.arrPasteEntries = lpOleApp->m_arrPasteEntries;

   ouiPasteSpl.cPasteEntries = lpOleApp->m_nPasteEntries;

   ouiPasteSpl.lpSrcDataObj = lpClipboardDataObj;

   ouiPasteSpl.arrLinkTypes = lpOleApp->m_arrLinkTypes;

   ouiPasteSpl.cLinkTypes = lpOleApp->m_nLinkTypes;

   ouiPasteSpl.cClsidExclude = 0;

   OLEDBG_BEGIN3("OleUIPasteSpecial called\r\n")

   uInt = OleUIPasteSpecial(&ouiPasteSpl);

   OLEDBG_END3

   fDisplayAsIcon =

         (ouiPasteSpl.dwFlags & PSF_CHECKDISPLAYASICON ? TRUE : FALSE);

   if (uInt == OLEUI_OK) {

      nFmtEtc = ouiPasteSpl.nSelectedIndex;

      fLink =  ouiPasteSpl.fLink;

      if (nFmtEtc < 0 || nFmtEtc >= lpOleApp->m_nPasteEntries) {

         OutlineApp_ErrorMessage(lpOutlineApp, ErrMsgBadFmt);

         goto error;

      }

      OutlineDoc_SetRedraw ( lpOutlineDoc, FALSE );

      cfFormat = lpOleApp->m_arrPasteEntries[nFmtEtc].fmtetc.cfFormat;

      fStatus = OleDoc_PasteFormatFromData(

            lpOleDoc,

            cfFormat,

            lpClipboardDataObj,

            fLocalDataObj,

            fLink,

            fDisplayAsIcon,

            ouiPasteSpl.hMetaPict,

            (LPSIZEL)&ouiPasteSpl.sizel

      );

      OutlineDoc_SetRedraw ( lpOutlineDoc, TRUE );

      if (! fStatus) {

         OutlineApp_ErrorMessage(lpOutlineApp, ErrMsgPasteFailed);

         goto error;

      }

   } else if (uInt == OLEUI_PSERR_CLIPBOARDCHANGED) {

      /* OLE2NOTE: this error code is returned when the contents of

      **    the clipboard change while the PasteSpecial dialog is up.

      **    in this situation the PasteSpecial dialog automatically

      **    brings itself down and NO paste operation should be performed.

      */

      OutlineApp_ErrorMessage(lpOutlineApp, ErrMsgClipboardChanged);

   }

error:

   if (lpClipboardDataObj)

      OleStdRelease((LPUNKNOWN)lpClipboardDataObj);

   if (uInt == OLEUI_OK && ouiPasteSpl.hMetaPict)

      // clean up metafile

      OleUIMetafilePictIconFree(ouiPasteSpl.hMetaPict);

}

/* OleDoc_CreateDataTransferDoc

 * ----------------------------

 *

 *      Create a document to be use to transfer data (either via a

 *  drag/drop operation of the clipboard). Copy the selection of the

 *  source doc to the data transfer document. A data transfer document is

 *  the same as a document that is created by the user except that it is

 *  NOT made visible to the user. it is specially used to hold a copy of

 *  data that the user should not be able to change.

 *

 *  OLE2NOTE: in the OLE version the data transfer document is used

 *      specifically to provide an IDataObject* that renders the data copied.

 */

LPOUTLINEDOC OleDoc_CreateDataTransferDoc(LPOLEDOC lpSrcOleDoc)

{

   LPOUTLINEDOC lpSrcOutlineDoc = (LPOUTLINEDOC)lpSrcOleDoc;

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   LPOUTLINEDOC lpDestOutlineDoc;

   LPLINELIST lpSrcLL = &lpSrcOutlineDoc->m_LineList;

   LINERANGE lrSel;

   int nCopied;

   lpDestOutlineDoc = OutlineApp_CreateDoc(lpOutlineApp, TRUE);

   if (! lpDestOutlineDoc) return NULL;

   // set the ClipboardDoc to an (Untitled) doc.

   if (! OutlineDoc_InitNewFile(lpDestOutlineDoc))

      goto error;

   LineList_GetSel(lpSrcLL, (LPLINERANGE)&lrSel);

   nCopied = LineList_CopySelToDoc(

         lpSrcLL,

         (LPLINERANGE)&lrSel,

         lpDestOutlineDoc

   );

   if (nCopied != (lrSel.m_nEndLine - lrSel.m_nStartLine + 1)) {

      OleDbgAssertSz(FALSE,"OleDoc_CreateDataTransferDoc: entire selection NOT copied\r\n");

      goto error;     // ERROR: all lines could NOT be copied

   }

#if defined( OLE_SERVER )

   {

      LPOLEDOC lpSrcOleDoc = (LPOLEDOC)lpSrcOutlineDoc;

      LPOLEDOC lpDestOleDoc = (LPOLEDOC)lpDestOutlineDoc;

      LPSERVERDOC lpDestServerDoc = (LPSERVERDOC)lpDestOutlineDoc;

      LPMONIKER lpmkDoc = NULL;

      LPMONIKER lpmkItem = NULL;

      /* If source document is able to provide a moniker, then the

      **    destination document (lpDestOutlineDoc) should offer

      **    CF_LINKSOURCE via its IDataObject interface that it gives

      **    to the clipboard or the drag/drop operation.

      **

      **    OLE2NOTE: we want to ask the source document if it can

      **    produce a moniker, but we do NOT want to FORCE moniker

      **    assignment at this point. we only want to FORCE moniker

      **    assignment later if a Paste Link occurs (ie. GetData for

      **    CF_LINKSOURCE). if the source document is able to give

      **    a moniker, then we store a pointer to the source document

      **    so we can ask it at a later time to get the moniker. we

      **    also save the range of the current selection so we can

      **    generate a proper item name later when Paste Link occurs.

      **    Also we need to give a string which identifies the source

      **    of the copy in the CF_OBJECTDESCRIPTOR format. this

      **    string is used to display in the PasteSpecial dialog. we

      **    get and store a TEMPFORUSER moniker which identifies the

      **    source of copy.

      */

      lpDestOleDoc->m_lpSrcDocOfCopy = lpSrcOleDoc;

      lpmkDoc = OleDoc_GetFullMoniker(lpSrcOleDoc, GETMONIKER_TEMPFORUSER);

      if (lpmkDoc != NULL) {

         lpDestOleDoc->m_fLinkSourceAvail = TRUE;

         lpDestServerDoc->m_lrSrcSelOfCopy = lrSel;

         OleStdRelease((LPUNKNOWN)lpmkDoc);

      }

   }

#endif

#if defined( OLE_CNTR )

   {

      LPOLEDOC lpSrcOleDoc = (LPOLEDOC)lpSrcOutlineDoc;

      LPOLEDOC lpDestOleDoc = (LPOLEDOC)lpDestOutlineDoc;

      LPCONTAINERDOC lpDestContainerDoc = (LPCONTAINERDOC)lpDestOutlineDoc;

      /* If one line was copied from the source document, and it was a

      **    single OLE object, then the destination document should

      **    offer additional data formats to allow the transfer of

      **    the OLE object via IDataObject::GetData. Specifically, the

      **    following additional data formats are offered if a single

      **    OLE object is copied:

      **          CF_EMBEDDEDOBJECT

      **          CF_OBJECTDESCRIPTOR     (should be given even w/o object)

      **          CF_METAFILEPICT         (note: dwAspect depends on object)

      **          CF_LINKSOURCE           -- if linking is possible

      **          CF_LINKSOURCEDESCRIPTOR -- if linking is possible

      **

      **    optionally the container may give

      **          <data format available in OLE object's cache>

      */

      if (nCopied == 1) {

         LPOLEOBJECT lpSrcOleObj;

         LPCONTAINERLINE lpSrcContainerLine;

         DWORD dwStatus;

         lpSrcContainerLine = (LPCONTAINERLINE)LineList_GetLine(

               lpSrcLL,

               lrSel.m_nStartLine

         );

         if (! lpSrcContainerLine)

            goto error;

         lpDestOleDoc->m_lpSrcDocOfCopy = lpSrcOleDoc;

         if ((((LPLINE)lpSrcContainerLine)->m_lineType==CONTAINERLINETYPE)

               && ((lpSrcOleObj=lpSrcContainerLine->m_lpOleObj)!=NULL)) {

            lpDestContainerDoc->m_fEmbeddedObjectAvail = TRUE;

            lpSrcOleObj->lpVtbl->GetUserClassID(

                  lpSrcOleObj,

                  &lpDestContainerDoc->m_clsidOleObjCopied

            );

            lpDestContainerDoc->m_dwAspectOleObjCopied =

                     lpSrcContainerLine->m_dwDrawAspect;

            /* OLE2NOTE: if the object is allowed to be linked

            **    to from the inside (ie. we are allowed to

            **    give out a moniker which binds to the running

            **    OLE object), then we want to offer

            **    CF_LINKSOURCE format. if the object is an OLE

            **    2.0 embedded object then it is allowed to be

            **    linked to from the inside. if the object is

            **    either an OleLink or an OLE 1.0 embedding

            **    then it can not be linked to from the inside.

            **    if we were a container/server app then we

            **    could offer linking to the outside of the

            **    object (ie. a pseudo object within our

            **    document). we are a container only app that

            **    does not support linking to ranges of its data.

            */

            lpSrcOleObj->lpVtbl->GetMiscStatus(

                  lpSrcOleObj,

                  DVASPECT_CONTENT, /* aspect is not important */

                  (LPDWORD)&dwStatus

            );

            if (! (dwStatus & OLEMISC_CANTLINKINSIDE)) {

               /* Our container supports linking to an embedded

               **    object. We want the lpDestContainerDoc to

               **    offer CF_LINKSOURCE via the IDataObject

               **    interface that it gives to the clipboard or

               **    the drag/drop operation. The link source will

               **    be identified by a composite moniker

               **    comprised of the FileMoniker of the source

               **    document and an ItemMoniker which identifies

               **    the OLE object inside the container. we do

               **    NOT want to force moniker assignment to the

               **    OLE object now (at copy time); we only want

               **    to FORCE moniker assignment later if a Paste

               **    Link occurs (ie. GetData for CF_LINKSOURCE).

               **    thus we store a pointer to the source document

               **    and the source ContainerLine so we can

               **    generate a proper ItemMoniker later when

               **    Paste Link occurs.

               */

               lpDestOleDoc->m_fLinkSourceAvail = TRUE;

               lpDestContainerDoc->m_lpSrcContainerLine =

                     lpSrcContainerLine;

            }

         }

      }

   }

#endif  // OLE_CNTR

   return lpDestOutlineDoc;

error:

   if (lpDestOutlineDoc)

      OutlineDoc_Destroy(lpDestOutlineDoc);

   return NULL;

}

/* OleDoc_PasteFromData

** --------------------

**

**    Paste data from an IDataObject*. The IDataObject* may come from

**    the clipboard (GetClipboard) or from a drag/drop operation.

**    In this function we choose the best format that we prefer.

**

**    Returns TRUE if data was successfully pasted.

**            FALSE if data could not be pasted.

*/

BOOL OleDoc_PasteFromData(

      LPOLEDOC            lpOleDoc,

      LPDATAOBJECT        lpSrcDataObj,

      BOOL                fLocalDataObj,

      BOOL                fLink

)

{

   LPOLEAPP        lpOleApp = (LPOLEAPP)g_lpApp;

   CLIPFORMAT      cfFormat;

   BOOL            fDisplayAsIcon = FALSE;

   SIZEL           sizelInSrc = {0, 0};

   HGLOBAL         hMem = NULL;

   HGLOBAL         hMetaPict = NULL;

   STGMEDIUM       medium;

   if (fLink) {

#if defined( OLE_SERVER )

      return FALSE;       // server version of app does NOT support links

#endif

#if defined( OLE_CNTR )

      // container version of app only supports OLE object type links

      cfFormat = lpOleApp->m_cfLinkSource;

#endif

   } else {

      int nFmtEtc;

      nFmtEtc = OleStdGetPriorityClipboardFormat(

            lpSrcDataObj,

            lpOleApp->m_arrPasteEntries,

            lpOleApp->m_nPasteEntries

      );

      if (nFmtEtc < 0)

         return FALSE;   // there is no format we like

      cfFormat = lpOleApp->m_arrPasteEntries[nFmtEtc].fmtetc.cfFormat;

   }

   /* OLE2NOTE: we need to check what dwDrawAspect is being

   **    transfered. if the data is an object that is displayed as an

   **    icon in the source, then we want to keep it as an icon. the

   **    aspect the object is displayed in at the source is transfered

   **    via the CF_OBJECTDESCRIPTOR format for a Paste operation.

   */

   if (hMem = OleStdGetData(

         lpSrcDataObj,

         (CLIPFORMAT)lpOleApp->m_cfObjectDescriptor,

         NULL,

         DVASPECT_CONTENT,

         (LPSTGMEDIUM)&medium)) {

      LPOBJECTDESCRIPTOR lpOD = GlobalLock(hMem);

      fDisplayAsIcon = (lpOD->dwDrawAspect == DVASPECT_ICON ? TRUE : FALSE);

      sizelInSrc = lpOD->sizel;   // size of object/picture in source (opt.)

      GlobalUnlock(hMem);

      ReleaseStgMedium((LPSTGMEDIUM)&medium);     // equiv to GlobalFree

      if (fDisplayAsIcon) {

         hMetaPict = OleStdGetData(

               lpSrcDataObj,

               CF_METAFILEPICT,

               NULL,

               DVASPECT_ICON,

               (LPSTGMEDIUM)&medium

         );

         if (hMetaPict == NULL)

            fDisplayAsIcon = FALSE; // give up; failed to get icon MFP

      }

   }

   return OleDoc_PasteFormatFromData(

         lpOleDoc,

         cfFormat,

         lpSrcDataObj,

         fLocalDataObj,

         fLink,

         fDisplayAsIcon,

         hMetaPict,

         (LPSIZEL)&sizelInSrc

   );

   if (hMetaPict)

      ReleaseStgMedium((LPSTGMEDIUM)&medium);  // properly free METAFILEPICT

}

/* OleDoc_PasteFormatFromData

** --------------------------

**

**    Paste a particular data format from a IDataObject*. The

**    IDataObject* may come from the clipboard (GetClipboard) or from a

**    drag/drop operation.

**

**    Returns TRUE if data was successfully pasted.

**            FALSE if data could not be pasted.

*/

BOOL OleDoc_PasteFormatFromData(

      LPOLEDOC            lpOleDoc,

      CLIPFORMAT          cfFormat,

      LPDATAOBJECT        lpSrcDataObj,

      BOOL                fLocalDataObj,

      BOOL                fLink,

      BOOL                fDisplayAsIcon,

      HGLOBAL             hMetaPict,

      LPSIZEL             lpSizelInSrc

)

{

#if defined( OLE_SERVER )

   /* call server specific version of the function. */

   return ServerDoc_PasteFormatFromData(

         (LPSERVERDOC)lpOleDoc,

         cfFormat,

         lpSrcDataObj,

         fLocalDataObj,

         fLink

   );

#endif

#if defined( OLE_CNTR )

   /* call container specific version of the function. */

   return ContainerDoc_PasteFormatFromData(

         (LPCONTAINERDOC)lpOleDoc,

         cfFormat,

         lpSrcDataObj,

         fLocalDataObj,

         fLink,

         fDisplayAsIcon,

         hMetaPict,

         lpSizelInSrc

   );

#endif

}

/* OleDoc_QueryPasteFromData

** -------------------------

**

**    Check if the IDataObject* offers data in a format that we can

**    paste. The IDataObject* may come from the clipboard

**    (GetClipboard) or from a drag/drop operation.

**

**    Returns TRUE if paste can be performed

**            FALSE if paste is not possible.

*/

BOOL OleDoc_QueryPasteFromData(

      LPOLEDOC            lpOleDoc,

      LPDATAOBJECT        lpSrcDataObj,

      BOOL                fLink

)

{

#if defined( OLE_SERVER )

   return ServerDoc_QueryPasteFromData(

         (LPSERVERDOC) lpOleDoc,

         lpSrcDataObj,

         fLink

   );

#endif

#if defined( OLE_CNTR )

   return ContainerDoc_QueryPasteFromData(

         (LPCONTAINERDOC) lpOleDoc,

         lpSrcDataObj,

         fLink

   );

#endif

}

/* OleDoc_GetExtent

 * ----------------

 *

 *      Get the extent (width, height) of the entire document in Himetric.

 */

void OleDoc_GetExtent(LPOLEDOC lpOleDoc, LPSIZEL lpsizel)

{

   LPLINELIST lpLL = (LPLINELIST)&((LPOUTLINEDOC)lpOleDoc)->m_LineList;

   LineList_CalcSelExtentInHimetric(lpLL, NULL, lpsizel);

}

/* OleDoc_GetObjectDescriptorData

 * ------------------------------

 *

 * Return a handle to an object's data in CF_OBJECTDESCRIPTOR form

 *

 */

HGLOBAL OleDoc_GetObjectDescriptorData(LPOLEDOC lpOleDoc, LPLINERANGE lplrSel)

{

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc;

   /* Only our data transfer doc renders CF_OBJECTDESCRIPTOR */

   OleDbgAssert(lpOutlineDoc->m_fDataTransferDoc);

#if defined( OLE_SERVER )

   {

      LPSERVERDOC   lpServerDoc = (LPSERVERDOC)lpOleDoc;

      SIZEL         sizel;

      POINTL        pointl;

      LPOLESTR      lpszSrcOfCopy = NULL;

      IBindCtx  FAR *pbc = NULL;

      HGLOBAL       hObjDesc;

      DWORD         dwStatus = 0;

      LPOUTLINEDOC  lpSrcDocOfCopy=(LPOUTLINEDOC)lpOleDoc->m_lpSrcDocOfCopy;

      LPMONIKER lpSrcMonikerOfCopy = ServerDoc_GetSelFullMoniker(

            (LPSERVERDOC)lpOleDoc->m_lpSrcDocOfCopy,

            &lpServerDoc->m_lrSrcSelOfCopy,

            GETMONIKER_TEMPFORUSER

      );

      SvrDoc_OleObj_GetMiscStatus(

            (LPOLEOBJECT)&lpServerDoc->m_OleObject,

            DVASPECT_CONTENT,

            &dwStatus

      );

      OleDoc_GetExtent(lpOleDoc, &sizel);

      pointl.x = pointl.y = 0;

      if (lpSrcMonikerOfCopy) {

         CreateBindCtx(0, (LPBC FAR*)&pbc);

         lpSrcMonikerOfCopy->lpVtbl->GetDisplayName(

            lpSrcMonikerOfCopy, pbc, NULL, &lpszSrcOfCopy);

         pbc->lpVtbl->Release(pbc);

         lpSrcMonikerOfCopy->lpVtbl->Release(lpSrcMonikerOfCopy);

      } else {

         /* this document has no moniker; use our FullUserTypeName

         **    as the description of the source of copy.

         */

         lpszSrcOfCopy = FULLUSERTYPENAME;

      }

      hObjDesc =  OleStdGetObjectDescriptorData(

            CLSID_APP,

            DVASPECT_CONTENT,

            sizel,

            pointl,

            dwStatus,

            FULLUSERTYPENAME,

            lpszSrcOfCopy

      );

      if (lpSrcMonikerOfCopy && lpszSrcOfCopy)

         OleStdFreeString(lpszSrcOfCopy, NULL);

      return hObjDesc;

   }

#endif

#if defined( OLE_CNTR )

   {

      LPCONTAINERDOC lpContainerDoc = (LPCONTAINERDOC)lpOleDoc;

      LPLINELIST lpLL = (LPLINELIST)&((LPOUTLINEDOC)lpOleDoc)->m_LineList;

      LPCONTAINERLINE lpContainerLine;

      HGLOBAL hObjDesc;

      BOOL fSelIsOleObject = FALSE;

      LPOLEOBJECT lpOleObj;

      SIZEL sizel;

      POINTL pointl;

      if ( lpLL->m_nNumLines == 1 ) {

         fSelIsOleObject = ContainerDoc_IsSelAnOleObject(

               lpContainerDoc,

               &IID_IOleObject,

               (LPUNKNOWN FAR*)&lpOleObj,

               NULL,    /* we don't need the line index */

               (LPCONTAINERLINE FAR*)&lpContainerLine

         );

      }

      pointl.x = pointl.y = 0;

      if (fSelIsOleObject) {

         /* OLE2NOTE: a single OLE object is being transfered via

         **    this DataTransferDoc. we need to generate the

         **    CF_ObjectDescrioptor which describes the OLE object.

         */

         LPOUTLINEDOC lpSrcOutlineDoc =

               (LPOUTLINEDOC)lpOleDoc->m_lpSrcDocOfCopy;

         LPOLESTR lpszSrcOfCopy = lpSrcOutlineDoc->m_szFileName;

         BOOL fFreeSrcOfCopy = FALSE;

         SIZEL sizelOleObject;

         LPLINE lpLine = (LPLINE)lpContainerLine;

         /* if the object copied can be linked to then get a

         **    TEMPFORUSER form of the moniker which identifies the

         **    source of copy. we do not want to force the

         **    assignment of the moniker until CF_LINKSOURCE is

         **    rendered.

         **    if the object copied can not be a link source then use

         **    the source filename to identify the source of copy.

         **    there is no need to generate a moniker for the object

         **    copied.

         */

         if (lpOleDoc->m_fLinkSourceAvail &&

               lpContainerDoc->m_lpSrcContainerLine) {

            LPBINDCTX pbc = NULL;

            LPMONIKER lpSrcMonikerOfCopy = ContainerLine_GetFullMoniker(

                  lpContainerDoc->m_lpSrcContainerLine,

                  GETMONIKER_TEMPFORUSER

            );

            if (lpSrcMonikerOfCopy) {

               CreateBindCtx(0, (LPBC FAR*)&pbc);

               if (pbc != NULL) {

                  lpSrcMonikerOfCopy->lpVtbl->GetDisplayName(

                        lpSrcMonikerOfCopy, pbc, NULL,&lpszSrcOfCopy);

                  pbc->lpVtbl->Release(pbc);

                  fFreeSrcOfCopy = TRUE;

               }

               lpSrcMonikerOfCopy->lpVtbl->Release(lpSrcMonikerOfCopy);

            }

         }

         /* OLE2NOTE: Get size that object is being drawn. If the

         **    object has been scaled because the user resized the

         **    object, then we want to pass the scaled size of the

         **    object in the ObjectDescriptor rather than the size

         **    that the object would return via

         **    IOleObject::GetExtent and IViewObject2::GetExtent. in

         **    this way if the object is transfered to another container

         **    (via clipboard or drag/drop), then the object will

         **    remain the scaled size.

         */

         sizelOleObject.cx = lpLine->m_nWidthInHimetric;

         sizelOleObject.cy = lpLine->m_nHeightInHimetric;

         hObjDesc = OleStdGetObjectDescriptorDataFromOleObject(

               lpOleObj,

               lpszSrcOfCopy,

               lpContainerLine->m_dwDrawAspect,

               pointl,

               (LPSIZEL)&sizelOleObject

         );

         if (fFreeSrcOfCopy && lpszSrcOfCopy)

            OleStdFreeString(lpszSrcOfCopy, NULL);

         OleStdRelease((LPUNKNOWN)lpOleObj);

         return hObjDesc;

      } else {

         /* OLE2NOTE: the data being transfered via this

         **    DataTransferDoc is NOT a single OLE object. thus in

         **    this case the CF_ObjectDescriptor data should

         **    describe our container app itself.

         */

         OleDoc_GetExtent(lpOleDoc, &sizel);

         return OleStdGetObjectDescriptorData(

               CLSID_NULL, /* not used if no object formats */

               DVASPECT_CONTENT,

               sizel,

               pointl,

               0,

               NULL,       /* UserTypeName not used if no obj fmt's */

               FULLUSERTYPENAME   /* string to identify source of copy */

         );

      }

   }

#endif  // OLE_CNTR

}

#if defined( OLE_SERVER )

/*************************************************************************

** ServerDoc Supprt Functions Used by Server versions

*************************************************************************/

/* ServerDoc_PasteFormatFromData

** -----------------------------

**

**    Paste a particular data format from a IDataObject*. The

**    IDataObject* may come from the clipboard (GetClipboard) or from a

**    drag/drop operation.

**

**    NOTE: fLink is specified then FALSE if returned because the

**    Server only version of the app can not support links.

**

**    Returns TRUE if data was successfully pasted.

**            FALSE if data could not be pasted.

*/

BOOL ServerDoc_PasteFormatFromData(

      LPSERVERDOC             lpServerDoc,

      CLIPFORMAT              cfFormat,

      LPDATAOBJECT            lpSrcDataObj,

      BOOL                    fLocalDataObj,

      BOOL                    fLink

)

{

   LPLINELIST   lpLL = (LPLINELIST)&((LPOUTLINEDOC)lpServerDoc)->m_LineList;

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   LPOLEAPP     lpOleApp = (LPOLEAPP)g_lpApp;

   int          nIndex;

   int          nCount = 0;

   HGLOBAL      hData;

   STGMEDIUM    medium;

   LINERANGE    lrSel;

   if (LineList_GetCount(lpLL) == 0)

      nIndex = -1;    // pasting to empty list

   else

      nIndex=LineList_GetFocusLineIndex(lpLL);

   if (fLink) {

      /* We should paste a Link to the data, but we do not support links */

      return FALSE;

   } else {

      if (cfFormat == lpOutlineApp->m_cfOutline) {

         hData = OleStdGetData(

               lpSrcDataObj,

               (CLIPFORMAT)lpOutlineApp->m_cfOutline,

               NULL,

               DVASPECT_CONTENT,

               (LPSTGMEDIUM)&medium

         );

         if (hData == NULL)

            return FALSE;

         nCount = OutlineDoc_PasteOutlineData(

               (LPOUTLINEDOC)lpServerDoc,

               hData,

               nIndex

         );

         // OLE2NOTE: we must free data handle by releasing the medium

         ReleaseStgMedium((LPSTGMEDIUM)&medium);

      } else if(cfFormat == CF_TEXT) {

         hData = OleStdGetData(

               lpSrcDataObj,

               CF_TEXT,

               NULL,

               DVASPECT_CONTENT,

               (LPSTGMEDIUM)&medium

         );

         if (hData == NULL)

            return FALSE;

         nCount = OutlineDoc_PasteTextData(

               (LPOUTLINEDOC)lpServerDoc,

               hData,

               nIndex

         );

         // OLE2NOTE: we must free data handle by releasing the medium

         ReleaseStgMedium((LPSTGMEDIUM)&medium);

      }

   }

   lrSel.m_nEndLine   = nIndex + 1;

   lrSel.m_nStartLine = nIndex + nCount;

   LineList_SetSel(lpLL, &lrSel);

   return TRUE;

}

/* ServerDoc_QueryPasteFromData

** ----------------------------

**

**    Check if the IDataObject* offers data in a format that we can

**    paste. The IDataObject* may come from the clipboard

**    (GetClipboard) or from a drag/drop operation.

**    In this function we look if one of the following formats is

**    offered:

**              CF_OUTLINE

**              CF_TEXT

**

**    NOTE: fLink is specified then FALSE if returned because the

**    Server only version of the app can not support links.

**

**    Returns TRUE if paste can be performed

**            FALSE if paste is not possible.

*/

BOOL ServerDoc_QueryPasteFromData(

      LPSERVERDOC             lpServerDoc,

      LPDATAOBJECT            lpSrcDataObj,

      BOOL                    fLink

)

{

   LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp;

   if (fLink) {

      /* we do not support links */

      return FALSE;

   } else {

      int nFmtEtc;

      nFmtEtc = OleStdGetPriorityClipboardFormat(

            lpSrcDataObj,

            lpOleApp->m_arrPasteEntries,

            lpOleApp->m_nPasteEntries

         );

      if (nFmtEtc < 0)

         return FALSE;   // there is no format we like

   }

   return TRUE;

}

/* ServerDoc_GetData

 * -----------------

 *

 * Render data from the document on a CALLEE allocated STGMEDIUM.

 *      This routine is called via IDataObject::GetData.

 */

HRESULT ServerDoc_GetData (

      LPSERVERDOC             lpServerDoc,

      LPFORMATETC             lpformatetc,

      LPSTGMEDIUM             lpMedium

)

{

   LPOLEDOC  lpOleDoc = (LPOLEDOC)lpServerDoc;

   LPOUTLINEDOC  lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;

   LPSERVERAPP lpServerApp = (LPSERVERAPP)g_lpApp;

   LPOLEAPP  lpOleApp = (LPOLEAPP)lpServerApp;

   LPOUTLINEAPP  lpOutlineApp = (LPOUTLINEAPP)lpServerApp;

   HRESULT hrErr;

   SCODE sc;

   // OLE2NOTE: we must set out pointer parameters to NULL

   lpMedium->pUnkForRelease = NULL;

   /* OLE2NOTE: we must make sure to set all out parameters to NULL. */

   lpMedium->tymed = TYMED_NULL;

   lpMedium->pUnkForRelease = NULL;    // we transfer ownership to caller

   lpMedium->u.hGlobal = NULL;

   if(lpformatetc->cfFormat == lpOutlineApp->m_cfOutline) {

      // Verify caller asked for correct medium

      if (!(lpformatetc->tymed & TYMED_HGLOBAL)) {

         sc = DV_E_FORMATETC;

         goto error;

      }

      lpMedium->u.hGlobal = OutlineDoc_GetOutlineData (lpOutlineDoc,NULL);

      if (! lpMedium->u.hGlobal) {

         sc = E_OUTOFMEMORY;

         goto error;

      }

      lpMedium->tymed = TYMED_HGLOBAL;

      OleDbgOut3("ServerDoc_GetData: rendered CF_OUTLINE\r\n");

      return NOERROR;

   } else if (lpformatetc->cfFormat == CF_METAFILEPICT &&

      (lpformatetc->dwAspect & DVASPECT_CONTENT) ) {

      // Verify caller asked for correct medium

      if (!(lpformatetc->tymed & TYMED_MFPICT)) {

         sc = DV_E_FORMATETC;

         goto error;

      }

      lpMedium->u.hGlobal = ServerDoc_GetMetafilePictData(lpServerDoc,NULL);

      if (! lpMedium->u.hGlobal) {

         sc = E_OUTOFMEMORY;

         goto error;

      }

      lpMedium->tymed = TYMED_MFPICT;

      OleDbgOut3("ServerDoc_GetData: rendered CF_METAFILEPICT\r\n");

      return NOERROR;

   } else if (lpformatetc->cfFormat == CF_METAFILEPICT &&

      (lpformatetc->dwAspect & DVASPECT_ICON) ) {

      CLSID clsid;

      // Verify caller asked for correct medium

      if (!(lpformatetc->tymed & TYMED_MFPICT)) {

         sc = DV_E_FORMATETC;

         goto error;

      }

      /* OLE2NOTE: we should return the default icon for our class.

      **    we must be carefull to use the correct CLSID here.

      **    if we are currently preforming a "TreatAs (aka. ActivateAs)"

      **    operation then we need to use the class of the object

      **    written in the storage of the object. otherwise we would

      **    use our own class id.

      */

      if (ServerDoc_GetClassID(lpServerDoc, (LPCLSID)&clsid) != NOERROR) {

         sc = DV_E_FORMATETC;

         goto error;

      }

      lpMedium->u.hGlobal=GetIconOfClass(g_lpApp->m_hInst,(REFCLSID)&clsid, NULL, FALSE);

      if (! lpMedium->u.hGlobal) {

         sc = E_OUTOFMEMORY;

         goto error;

      }

      lpMedium->tymed = TYMED_MFPICT;

      OleDbgOut3("ServerDoc_GetData: rendered CF_METAFILEPICT (icon)\r\n");

      return NOERROR;

   } else if (lpformatetc->cfFormat == CF_TEXT) {

      // Verify caller asked for correct medium

      if (!(lpformatetc->tymed & TYMED_HGLOBAL)) {

         sc = DV_E_FORMATETC;

         goto error;

      }

      lpMedium->u.hGlobal = OutlineDoc_GetTextData (

            (LPOUTLINEDOC)lpServerDoc,

            NULL

      );

      if (! lpMedium->u.hGlobal) {

         sc = E_OUTOFMEMORY;

         goto error;

      }

      lpMedium->tymed = TYMED_HGLOBAL;

      OleDbgOut3("ServerDoc_GetData: rendered CF_TEXT\r\n");

      return NOERROR;

   }

   /* the above are the only formats supports by a user document (ie.

   **    a non-data transfer doc). if the document is used for

   **    purposes of data transfer, then additional formats are offered.

   */

   if (! lpOutlineDoc->m_fDataTransferDoc) {

      sc = DV_E_FORMATETC;

      goto error;

   }

   /* OLE2NOTE: ObjectDescriptor and LinkSrcDescriptor will

   **    contain the same data for the pure container and pure server

   **    type applications. only a container/server application may

   **    have different content for ObjectDescriptor and

   **    LinkSrcDescriptor. if a container/server copies a link for

   **    example, then the ObjectDescriptor would give the class

   **    of the link source but the LinkSrcDescriptor would give the

   **    class of the container/server itself. in this situation if a

   **    paste operation occurs, an equivalent link is pasted, but if

   **    a pastelink operation occurs, then a link to a pseudo object

   **    in the container/server is created.

   */

   if (lpformatetc->cfFormat == lpOleApp->m_cfObjectDescriptor ||

      (lpformatetc->cfFormat == lpOleApp->m_cfLinkSrcDescriptor &&

            lpOleDoc->m_fLinkSourceAvail)) {

      // Verify caller asked for correct medium

      if (!(lpformatetc->tymed & TYMED_HGLOBAL)) {

         sc = DV_E_FORMATETC;

         goto error;

      }

      lpMedium->u.hGlobal = OleDoc_GetObjectDescriptorData (

            (LPOLEDOC)lpServerDoc,

            NULL

      );

      if (! lpMedium->u.hGlobal) {

         sc = E_OUTOFMEMORY;

         goto error;

      }

      lpMedium->tymed = TYMED_HGLOBAL;

      OleDbgOut3("ServerDoc_GetData: rendered CF_OBJECTDESCRIPTOR\r\n");

      return NOERROR;

   } else if (lpformatetc->cfFormat == lpOleApp->m_cfEmbedSource) {

      hrErr = OleStdGetOleObjectData(

            (LPPERSISTSTORAGE)&lpServerDoc->m_PersistStorage,

            lpformatetc,

            lpMedium,

            FALSE   /* fUseMemory -- (use file-base stg) */

      );

      if (hrErr != NOERROR) {

         sc = GetScode(hrErr);

         goto error;

      }

      OleDbgOut3("ServerDoc_GetData: rendered CF_EMBEDSOURCE\r\n");

      return NOERROR;

   } else if (lpformatetc->cfFormat == lpOleApp->m_cfLinkSource) {

      if (lpOleDoc->m_fLinkSourceAvail) {

         LPMONIKER lpmk;

         lpmk = ServerDoc_GetSelFullMoniker(

               (LPSERVERDOC)lpOleDoc->m_lpSrcDocOfCopy,

               &lpServerDoc->m_lrSrcSelOfCopy,

               GETMONIKER_FORCEASSIGN

         );

         if (lpmk) {

            hrErr = OleStdGetLinkSourceData(

                  lpmk,

                  (LPCLSID)&CLSID_APP,

                  lpformatetc,

                  lpMedium

            );

            OleStdRelease((LPUNKNOWN)lpmk);

            if (hrErr != NOERROR) {

               sc = GetScode(hrErr);

               goto error;

            }

            OleDbgOut3("ServerDoc_GetData: rendered CF_LINKSOURCE\r\n");

            return NOERROR;

         } else {

            sc = E_FAIL;

            goto error;

         }

      } else {

         sc = DV_E_FORMATETC;

         goto error;

      }

   } else {

      sc = DV_E_FORMATETC;

      goto error;

   }

   return NOERROR;

error:

   return ResultFromScode(sc);

}

/* ServerDoc_GetDataHere

 * ---------------------

 *

 * Render data from the document on a CALLER allocated STGMEDIUM.

 *      This routine is called via IDataObject::GetDataHere.

 */

HRESULT ServerDoc_GetDataHere (

      LPSERVERDOC             lpServerDoc,

      LPFORMATETC             lpformatetc,

      LPSTGMEDIUM             lpMedium

)

{

   LPOLEDOC        lpOleDoc = (LPOLEDOC)lpServerDoc;

   LPOUTLINEDOC    lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;

   LPSERVERAPP     lpServerApp = (LPSERVERAPP)g_lpApp;

   LPOLEAPP        lpOleApp = (LPOLEAPP)lpServerApp;

   LPOUTLINEAPP    lpOutlineApp = (LPOUTLINEAPP)lpServerApp;

   HRESULT         hrErr;

   SCODE           sc;

   // OLE2NOTE: lpMedium is an IN parameter. we should NOT set

   //           lpMedium->pUnkForRelease to NULL

   /* our user document does not support any formats for GetDataHere.

   **    if the document is used for

   **    purposes of data transfer, then additional formats are offered.

   */

   if (! lpOutlineDoc->m_fDataTransferDoc) {

      sc = DV_E_FORMATETC;

      goto error;

   }

   if (lpformatetc->cfFormat == lpOleApp->m_cfEmbedSource) {

      hrErr = OleStdGetOleObjectData(

            (LPPERSISTSTORAGE)&lpServerDoc->m_PersistStorage,

            lpformatetc,

            lpMedium,

            FALSE   /* fUseMemory -- (use file-base stg) */

      );

      if (hrErr != NOERROR) {

         sc = GetScode(hrErr);

         goto error;

      }

      OleDbgOut3("ServerDoc_GetDataHere: rendered CF_EMBEDSOURCE\r\n");

      return NOERROR;

   } else if (lpformatetc->cfFormat == lpOleApp->m_cfLinkSource) {

      if (lpOleDoc->m_fLinkSourceAvail) {

         LPMONIKER lpmk;

         lpmk = ServerDoc_GetSelFullMoniker(

               (LPSERVERDOC)lpOleDoc->m_lpSrcDocOfCopy,

               &lpServerDoc->m_lrSrcSelOfCopy,

               GETMONIKER_FORCEASSIGN

         );

         if (lpmk) {

            hrErr = OleStdGetLinkSourceData(

                  lpmk,

                  (LPCLSID)&CLSID_APP,

                  lpformatetc,

                  lpMedium

            );

            OleStdRelease((LPUNKNOWN)lpmk);

            if (hrErr != NOERROR) {

               sc = GetScode(hrErr);

               goto error;

            }

            OleDbgOut3("ServerDoc_GetDataHere: rendered CF_LINKSOURCE\r\n");

            return NOERROR;

         } else {

            sc = E_FAIL;

            goto error;

         }

      } else {

         sc = DV_E_FORMATETC;

         goto error;

      }

   } else {

      /* Caller is requesting data to be returned in Caller allocated

      **    medium, but we do NOT support this. we only support

      **    global memory blocks that WE allocate for the caller.

      */

      sc = DV_E_FORMATETC;

      goto error;

   }

   return NOERROR;

error:

   return ResultFromScode(sc);

}

/* ServerDoc_QueryGetData

 * ----------------------

 *

 * Answer if a particular data format is supported via GetData/GetDataHere.

 *      This routine is called via IDataObject::QueryGetData.

 */

HRESULT ServerDoc_QueryGetData (LPSERVERDOC lpServerDoc,LPFORMATETC lpformatetc)

{

   LPOLEDOC        lpOleDoc = (LPOLEDOC)lpServerDoc;

   LPOUTLINEDOC    lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;

   LPSERVERAPP     lpServerApp = (LPSERVERAPP)g_lpApp;

   LPOLEAPP        lpOleApp = (LPOLEAPP)lpServerApp;

   LPOUTLINEAPP    lpOutlineApp = (LPOUTLINEAPP)lpServerApp;

   /* Caller is querying if we support certain format but does not

   **    want any data actually returned.

   */

   if (lpformatetc->cfFormat == lpOutlineApp->m_cfOutline ||

         lpformatetc->cfFormat == CF_TEXT) {

      // we only support HGLOBAL

      return OleStdQueryFormatMedium(lpformatetc, TYMED_HGLOBAL);

   } else if (lpformatetc->cfFormat == CF_METAFILEPICT &&

      (lpformatetc->dwAspect &

         (DVASPECT_CONTENT | DVASPECT_ICON)) ) {

      return OleStdQueryFormatMedium(lpformatetc, TYMED_MFPICT);

   }

   /* the above are the only formats supports by a user document (ie.

   **    a non-data transfer doc). if the document is used for

   **    purposes of data transfer, then additional formats are offered.

   */

   if (! lpOutlineDoc->m_fDataTransferDoc)

      return ResultFromScode(DV_E_FORMATETC);

   if (lpformatetc->cfFormat == lpOleApp->m_cfEmbedSource) {

      return OleStdQueryOleObjectData(lpformatetc);

   } else if (lpformatetc->cfFormat == lpOleApp->m_cfLinkSource &&

      lpOleDoc->m_fLinkSourceAvail) {

      return OleStdQueryLinkSourceData(lpformatetc);

   } else if (lpformatetc->cfFormat == lpOleApp->m_cfObjectDescriptor) {

      return OleStdQueryObjectDescriptorData(lpformatetc);

   } else if (lpformatetc->cfFormat == lpOleApp->m_cfLinkSrcDescriptor &&

            lpOleDoc->m_fLinkSourceAvail) {

      return OleStdQueryObjectDescriptorData(lpformatetc);

   }

   return ResultFromScode(DV_E_FORMATETC);

}

/* ServerDoc_EnumFormatEtc

 * -----------------------

 *

 * Return an enumerator which enumerates the data accepted/offered by

 *      the document.

 *      This routine is called via IDataObject::EnumFormatEtc.

 */

HRESULT ServerDoc_EnumFormatEtc(

      LPSERVERDOC             lpServerDoc,

      DWORD                   dwDirection,

      LPENUMFORMATETC FAR*    lplpenumFormatEtc

)

{

   LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc;

   LPOLEAPP  lpOleApp = (LPOLEAPP)g_lpApp;

   int nActualFmts;

   SCODE sc = S_OK;

   /* OLE2NOTE: the enumeration of formats for a data transfer

   **    document is not a static list. the list of formats offered

   **    may or may not include CF_LINKSOURCE depending on whether a

   **    moniker is available for our document. thus we can NOT use

   **    the default OLE enumerator which enumerates the formats that

   **    are registered for our app in the registration database.

   */

   if (dwDirection == DATADIR_GET) {

      nActualFmts = lpOleApp->m_nDocGetFmts;

      /* If the document does not have a Moniker, then exclude

      **    CF_LINKSOURCE and CF_LINKSRCDESCRIPTOR from the list of

      **    formats available. these formats are deliberately listed

      **    last in the array of possible "Get" formats.

      */

      if (! lpOleDoc->m_fLinkSourceAvail)

         nActualFmts -= 2;

      *lplpenumFormatEtc = OleStdEnumFmtEtc_Create(

            nActualFmts, lpOleApp->m_arrDocGetFmts);

      if (*lplpenumFormatEtc == NULL)

         sc = E_OUTOFMEMORY;

   } else if (dwDirection == DATADIR_SET) {

      /* OLE2NOTE: a document that is used to transfer data

      **    (either via the clipboard or drag/drop does NOT

      **    accept SetData on ANY format!

      */

      sc = E_NOTIMPL;

      goto error;

   } else {

      sc = E_INVALIDARG;

      goto error;

   }

error:

   return ResultFromScode(sc);

}

/* ServerDoc_GetMetafilePictData

 * -----------------------------

 *

 * Return a handle to an object's picture data in metafile format.

 *

 *

 * RETURNS: A handle to the object's data in metafile format.

 *

 */

HGLOBAL ServerDoc_GetMetafilePictData(

      LPSERVERDOC         lpServerDoc,

      LPLINERANGE         lplrSel

)

{

   LPOUTLINEAPP    lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   LPOUTLINEDOC    lpOutlineDoc=(LPOUTLINEDOC)lpServerDoc;

   LPLINELIST      lpLL=(LPLINELIST)&lpOutlineDoc->m_LineList;

   LPLINE          lpLine;

   LPMETAFILEPICT  lppict = NULL;

   HGLOBAL         hMFPict = NULL;

   HMETAFILE       hMF = NULL;

   RECT            rect;

   RECT            rectWBounds;

   HDC             hDC;

   int             i;

   int             nWidth;

   int     nStart = (lplrSel ? lplrSel->m_nStartLine : 0);

   int     nEnd =(lplrSel ? lplrSel->m_nEndLine : LineList_GetCount(lpLL)-1);

   int     nLines = nEnd - nStart + 1;

   UINT    fuAlign;

   POINT point;

   SIZE  size;

   hDC = CreateMetaFile(NULL);

   rect.left = 0;

   rect.right = 0;

   rect.bottom = 0;

   if (nLines > 0) {

   // calculate the total height/width of LineList in HIMETRIC

      for(i = nStart; i <= nEnd; i++) {

         lpLine = LineList_GetLine(lpLL,i);

         if (! lpLine)

            continue;

         nWidth = Line_GetTotalWidthInHimetric(lpLine);

         rect.right = max(rect.right, nWidth);

         rect.bottom -= Line_GetHeightInHimetric(lpLine);

      }

      SetMapMode(hDC, MM_ANISOTROPIC);

      SetWindowOrgEx(hDC, 0, 0, &point);

      SetWindowExtEx(hDC, rect.right, rect.bottom, &size);

      rectWBounds = rect;

      // Set the default font size, and font face name

      SelectObject(hDC, OutlineApp_GetActiveFont(lpOutlineApp));

      FillRect(hDC, (LPRECT) &rect, GetStockObject(WHITE_BRUSH));

      rect.bottom = 0;

      fuAlign = SetTextAlign(hDC, TA_LEFT | TA_TOP | TA_NOUPDATECP);

      /* While more lines print out the text */

      for(i = nStart; i <= nEnd; i++) {

         lpLine = LineList_GetLine(lpLL,i);

         if (! lpLine)

            continue;

         rect.top = rect.bottom;

         rect.bottom -= Line_GetHeightInHimetric(lpLine);

         /* Draw the line */

         Line_Draw(lpLine, hDC, &rect, &rectWBounds, FALSE /*fHighlight*/);

      }

      SetTextAlign(hDC, fuAlign);

   }

   // Get handle to the metafile.

   if (!(hMF = CloseMetaFile (hDC)))

      return NULL;

   if (!(hMFPict = GlobalAlloc (GALLOCFLG, sizeof (METAFILEPICT)))) {

      DeleteMetaFile (hMF);

      return NULL;

   }

   if (!(lppict = (LPMETAFILEPICT)GlobalLock(hMFPict))) {

      DeleteMetaFile (hMF);

      GlobalFree (hMFPict);

      return NULL;

   }

   lppict->mm   =  MM_ANISOTROPIC;

   lppict->hMF  =  hMF;

   lppict->xExt =  rect.right;

   lppict->yExt =  - rect.bottom;  // add minus sign to make it +ve

   GlobalUnlock (hMFPict);

   return hMFPict;

}

#endif  // OLE_SERVER

#if defined( OLE_CNTR )

/*************************************************************************

** ContainerDoc Supprt Functions Used by Container versions

*************************************************************************/

/* Paste OLE Link from clipboard */

void ContainerDoc_PasteLinkCommand(LPCONTAINERDOC lpContainerDoc)

{

   LPOUTLINEAPP    lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   LPOLEAPP        lpOleApp = (LPOLEAPP)g_lpApp;

   LPDATAOBJECT    lpClipboardDataObj = NULL;

   BOOL            fLink = TRUE;

   BOOL            fLocalDataObj = FALSE;

   BOOL            fDisplayAsIcon = FALSE;

   SIZEL           sizelInSrc;

   HCURSOR         hPrevCursor;

   HGLOBAL         hMem = NULL;

   HGLOBAL         hMetaPict = NULL;

   STGMEDIUM       medium;

   BOOL            fStatus;

   HRESULT         hrErr;

   hrErr = OleGetClipboard((LPDATAOBJECT FAR*)&lpClipboardDataObj);

   if (hrErr != NOERROR)

      return;     // Clipboard seems to be empty or can't be accessed

   // this may take a while, put up hourglass cursor

   hPrevCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));

   /* check if the data on the clipboard is local to our application

   **    instance.

   */

   if (lpOutlineApp->m_lpClipboardDoc) {

      LPOLEDOC lpOleDoc = (LPOLEDOC)lpOutlineApp->m_lpClipboardDoc;

      if (lpClipboardDataObj == (LPDATAOBJECT)&lpOleDoc->m_DataObject)

         fLocalDataObj = TRUE;

   }

   /* OLE2NOTE: we need to check what dwDrawAspect is being

   **    transfered. if the data is an object that is displayed as an

   **    icon in the source, then we want to keep it as an icon. the

   **    aspect the object is displayed in at the source is transfered

   **    via the CF_LINKSOURCEDESCRIPTOR format for a PasteLink

   **    operation.

   */

   if (hMem = OleStdGetData(

         lpClipboardDataObj,

         (CLIPFORMAT)lpOleApp->m_cfLinkSrcDescriptor,

         NULL,

         DVASPECT_CONTENT,

         (LPSTGMEDIUM)&medium)) {

      LPOBJECTDESCRIPTOR lpOD = GlobalLock(hMem);

      fDisplayAsIcon = (lpOD->dwDrawAspect == DVASPECT_ICON ? TRUE : FALSE);

      sizelInSrc = lpOD->sizel;   // size of object/picture in source (opt.)

      GlobalUnlock(hMem);

      ReleaseStgMedium((LPSTGMEDIUM)&medium);     // equiv to GlobalFree

      if (fDisplayAsIcon) {

         hMetaPict = OleStdGetData(

               lpClipboardDataObj,

               CF_METAFILEPICT,

               NULL,

               DVASPECT_ICON,

               (LPSTGMEDIUM)&medium

         );

         if (hMetaPict == NULL)

            fDisplayAsIcon = FALSE; // give up; failed to get icon MFP

      }

   }

   fStatus = ContainerDoc_PasteFormatFromData(

         lpContainerDoc,

         (CLIPFORMAT)lpOleApp->m_cfLinkSource,

         lpClipboardDataObj,

         fLocalDataObj,

         fLink,

         fDisplayAsIcon,

         hMetaPict,

         (LPSIZEL)&sizelInSrc

   );

   if (!fStatus)

      OutlineApp_ErrorMessage(g_lpApp, ErrMsgPasting);

   if (hMetaPict)

      ReleaseStgMedium((LPSTGMEDIUM)&medium);  // properly free METAFILEPICT

   if (lpClipboardDataObj)

      OleStdRelease((LPUNKNOWN)lpClipboardDataObj);

   SetCursor(hPrevCursor);     // restore original cursor

}

/* ContainerDoc_PasteFormatFromData

** --------------------------------

**

**    Paste a particular data format from a IDataObject*. The

**    IDataObject* may come from the clipboard (GetClipboard) or from a

**    drag/drop operation.

**

**    Returns TRUE if data was successfully pasted.

**            FALSE if data could not be pasted.

*/

BOOL ContainerDoc_PasteFormatFromData(

      LPCONTAINERDOC          lpContainerDoc,

      CLIPFORMAT              cfFormat,

      LPDATAOBJECT            lpSrcDataObj,

      BOOL                    fLocalDataObj,

      BOOL                    fLink,

      BOOL                    fDisplayAsIcon,

      HGLOBAL                 hMetaPict,

      LPSIZEL                 lpSizelInSrc

)

{

   LPLINELIST lpLL = (LPLINELIST)&((LPOUTLINEDOC)lpContainerDoc)->m_LineList;

   LPOUTLINEAPP    lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   LPOLEAPP        lpOleApp = (LPOLEAPP)g_lpApp;

   LPCONTAINERAPP  lpContainerApp = (LPCONTAINERAPP)g_lpApp;

   int             nIndex;

   int             nCount = 0;

   HGLOBAL         hData;

   STGMEDIUM       medium;

   FORMATETC       formatetc;

   HRESULT         hrErr;

   LINERANGE       lrSel;

   if (LineList_GetCount(lpLL) == 0)

      nIndex = -1;    // pasting to empty list

   else

      nIndex=LineList_GetFocusLineIndex(lpLL);

   if (fLink) {

      /* We should paste a Link to the data */

      if (cfFormat != lpOleApp->m_cfLinkSource)

         return FALSE;   // we only support OLE object type links

      nCount = ContainerDoc_PasteOleObject(

            lpContainerDoc,

            lpSrcDataObj,

            OLECREATEFROMDATA_LINK,

            cfFormat,

            nIndex,

            fDisplayAsIcon,

            hMetaPict,

            lpSizelInSrc

         );

      return (nCount > 0 ? TRUE : FALSE);

   } else {

      if (cfFormat == lpContainerApp->m_cfCntrOutl) {

         if (fLocalDataObj) {

            /* CASE I: IDataObject* is local to our app

            **

            **    if the source of the data is local to our

            **    application instance, then we can get direct

            **    access to the original OleDoc object that

            **    corresponds to the IDataObject* given.

            **    CF_CNTROUTL data is passed through a LPSTORAGE.

            **    if we call OleGetData asking for CF_CNTROUTL, we

            **    will be returned a copy of the existing open pStg

            **    of the original source document. we can NOT open

            **    streams and sub-storages again via this pStg

            **    since it is already open within our same

            **    application instance. we must copy the data from

            **    the original OleDoc source document.

            */

            LPLINELIST lpSrcLL;

            LPOLEDOC lpLocalSrcDoc =

               ((struct CDocDataObjectImpl FAR*)lpSrcDataObj)->lpOleDoc;

            /* copy all lines from SrcDoc to DestDoc. */

            lpSrcLL = &((LPOUTLINEDOC)lpLocalSrcDoc)->m_LineList;

            nCount = LineList_CopySelToDoc(

                  lpSrcLL,

                  NULL,

                  (LPOUTLINEDOC)lpContainerDoc

            );

         } else {

            /* CASE II: IDataObject* is NOT local to our app

            **

            **    if the source of the data comes from another

            **    application instance. we can call GetDataHere to

            **    retrieve the CF_CNTROUTL data. CF_CNTROUTL data

            **    is passed through a LPSTORAGE. we MUST use

            **    IDataObject::GetDataHere. calling

            **    IDataObject::GetData does NOT work because OLE

            **    currently does NOT support remoting of a callee

            **    allocated root storage back to the caller. this

            **    hopefully will be supported in a future version.

            **    in order to call GetDataHere we must allocate an

            **    IStorage instance for the callee to write into.

            **    we will allocate an IStorage docfile that will

            **    delete-on-release. we could use either a

            **    memory-based storage or a file-based storage.

            */

            LPSTORAGE lpTmpStg = OleStdCreateTempStorage(

                  FALSE /*fUseMemory*/,

                  STGM_READWRITE | STGM_TRANSACTED |STGM_SHARE_EXCLUSIVE

            );

            if (! lpTmpStg)

               return FALSE;

            formatetc.cfFormat = cfFormat;

            formatetc.ptd = NULL;

            formatetc.dwAspect = DVASPECT_CONTENT;

            formatetc.tymed = TYMED_ISTORAGE;

            formatetc.lindex = -1;

            medium.tymed = TYMED_ISTORAGE;

            medium.u.pstg = lpTmpStg;

            medium.pUnkForRelease = NULL;

            OLEDBG_BEGIN2("IDataObject::GetDataHere called\r\n")

            hrErr = lpSrcDataObj->lpVtbl->GetDataHere(

                  lpSrcDataObj,

                  (LPFORMATETC)&formatetc,

                  (LPSTGMEDIUM)&medium

            );

            OLEDBG_END2

            if (hrErr == NOERROR) {

               nCount = ContainerDoc_PasteCntrOutlData(

                     lpContainerDoc,

                     lpTmpStg,

                     nIndex

               );

            }

            OleStdVerifyRelease(

               (LPUNKNOWN)lpTmpStg, OLESTR("Temp stg NOT released!\r\n"));

            return ((hrErr == NOERROR) ? TRUE : FALSE);

         }

      } else if (cfFormat == lpOutlineApp->m_cfOutline) {

         hData = OleStdGetData(

               lpSrcDataObj,

               (CLIPFORMAT)lpOutlineApp->m_cfOutline,

               NULL,

               DVASPECT_CONTENT,

               (LPSTGMEDIUM)&medium

         );

         nCount = OutlineDoc_PasteOutlineData(

               (LPOUTLINEDOC)lpContainerDoc,

               hData,

               nIndex

            );

         // OLE2NOTE: we must free data handle by releasing the medium

         ReleaseStgMedium((LPSTGMEDIUM)&medium);

      } else if (cfFormat == lpOleApp->m_cfEmbedSource ||

         cfFormat == lpOleApp->m_cfEmbeddedObject ||

         cfFormat == lpOleApp->m_cfFileName) {

         /* OLE2NOTE: OleCreateFromData API creates an OLE object if

         **    CF_EMBEDDEDOBJECT, CF_EMBEDSOURCE, or CF_FILENAME are

         **    available from the source data object. the

         **    CF_FILENAME case arises when a file is copied to the

         **    clipboard from the FileManager. if the file has an

         **    associated class (see GetClassFile API), then an

         **    object of that class is created. otherwise an OLE 1.0

         **    Packaged object is created.

         */

         nCount = ContainerDoc_PasteOleObject(

               lpContainerDoc,

               lpSrcDataObj,

               OLECREATEFROMDATA_OBJECT,

               0,   /* N/A -- cfFormat */

               nIndex,

               fDisplayAsIcon,

               hMetaPict,

               lpSizelInSrc

         );

         return (nCount > 0 ? TRUE : FALSE);

      } else if (cfFormat == CF_METAFILEPICT

               || cfFormat == CF_DIB

               || cfFormat == CF_BITMAP) {

         /* OLE2NOTE: OleCreateStaticFromData API creates an static

         **    OLE object if CF_METAFILEPICT, CF_DIB, or CF_BITMAP is

         **    CF_EMBEDDEDOBJECT, CF_EMBEDSOURCE, or CF_FILENAME are

         **    available from the source data object.

         */

         nCount = ContainerDoc_PasteOleObject(

               lpContainerDoc,

               lpSrcDataObj,

               OLECREATEFROMDATA_STATIC,

               cfFormat,

               nIndex,

               fDisplayAsIcon,

               hMetaPict,

               lpSizelInSrc

         );

         return (nCount > 0 ? TRUE : FALSE);

      } else if(cfFormat == CF_TEXT) {

         hData = OleStdGetData(

               lpSrcDataObj,

               CF_TEXT,

               NULL,

               DVASPECT_CONTENT,

               (LPSTGMEDIUM)&medium

         );

         nCount = OutlineDoc_PasteTextData(

               (LPOUTLINEDOC)lpContainerDoc,

               hData,

               nIndex

            );

         // OLE2NOTE: we must free data handle by releasing the medium

         ReleaseStgMedium((LPSTGMEDIUM)&medium);

      } else {

         return FALSE;   // no acceptable format available to paste

      }

   }

   lrSel.m_nStartLine = nIndex + nCount;

   lrSel.m_nEndLine = nIndex + 1;

   LineList_SetSel(lpLL, &lrSel);

   return TRUE;

}

/* ContainerDoc_PasteCntrOutlData

 * -------------------------------

 *

 *      Load the lines stored in a lpSrcStg (stored in CF_CNTROUTL format)

 *  into the document.

 *

 * Return the number of items added

 */

int ContainerDoc_PasteCntrOutlData(

      LPCONTAINERDOC          lpDestContainerDoc,

      LPSTORAGE               lpSrcStg,

      int                     nStartIndex

)

{

   int nCount;

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   LPOUTLINEDOC lpDestOutlineDoc = (LPOUTLINEDOC)lpDestContainerDoc;

   LPOUTLINEDOC lpSrcOutlineDoc;

   LPLINELIST   lpSrcLL;

   // create a temp document that will be used to load the lpSrcStg data.

   lpSrcOutlineDoc = (LPOUTLINEDOC)OutlineApp_CreateDoc(lpOutlineApp, FALSE);

   if ( ! lpSrcOutlineDoc )

      return 0;

   if (! OutlineDoc_LoadFromStg(lpSrcOutlineDoc, lpSrcStg))

      goto error;

   /* copy all lines from the SrcDoc to the DestDoc. */

   lpSrcLL = &lpSrcOutlineDoc->m_LineList;

   nCount = LineList_CopySelToDoc(lpSrcLL, NULL, lpDestOutlineDoc);

   if (lpSrcOutlineDoc)            // destroy temporary document.

      OutlineDoc_Close(lpSrcOutlineDoc, OLECLOSE_NOSAVE);

   return nCount;

error:

   if (lpSrcOutlineDoc)            // destroy temporary document.

      OutlineDoc_Close(lpSrcOutlineDoc, OLECLOSE_NOSAVE);

   return 0;

}

/* ContainerDoc_QueryPasteFromData

** -------------------------------

**

**    Check if the IDataObject* offers data in a format that we can

**    paste. The IDataObject* may come from the clipboard

**    (GetClipboard) or from a drag/drop operation.

**    In this function we look if one of the following formats is

**    offered:

**              CF_OUTLINE

**              <OLE object -- CF_EMBEDSOURCE or CF_EMBEDDEDOBJECT>

**              CF_TEXT

**

**    NOTE: fLink is specified and CF_LINKSOURCE is available then TRUE

**    is returned, else FALSE.

**

**    Returns TRUE if paste can be performed

**            FALSE if paste is not possible.

*/

BOOL ContainerDoc_QueryPasteFromData(

      LPCONTAINERDOC          lpContainerDoc,

      LPDATAOBJECT            lpSrcDataObj,

      BOOL                    fLink

)

{

   LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp;

   if (fLink) {

      /* check if we can paste a Link to the data */

      if (OleQueryLinkFromData(lpSrcDataObj) != NOERROR)

         return FALSE;   // linking is NOT possible

   } else {

      int nFmtEtc;

      nFmtEtc = OleStdGetPriorityClipboardFormat(

            lpSrcDataObj,

            lpOleApp->m_arrPasteEntries,

            lpOleApp->m_nPasteEntries

         );

      if (nFmtEtc < 0)

         return FALSE;   // there is no format we like

   }

   return TRUE;

}

/* ContainerDoc_PasteOleObject

** ---------------------------

**

**    Embed or link an OLE object. the source of the data is a pointer

**    to an IDataObject. normally this lpSrcDataObj comes from the

**    clipboard after call OleGetClipboard.

**

**    dwCreateType controls what type of object will created:

**    OLECREATEFROMDATA_LINK -- OleCreateLinkFromData will be called

**    OLECREATEFROMDATA_OBJECT -- OleCreateFromData will be called

**    OLECREATEFROMDATA_STATIC -- OleCreateStaticFromData will be called

**                                  cfFormat controls the type of static

**    a CONTAINERLINE object is created to manage the OLE object. this

**    CONTAINERLINE is added to the ContainerDoc after line nIndex.

**

*/

int ContainerDoc_PasteOleObject(

      LPCONTAINERDOC          lpContainerDoc,

      LPDATAOBJECT            lpSrcDataObj,

      DWORD                   dwCreateType,

      CLIPFORMAT              cfFormat,

      int                     nIndex,

      BOOL                    fDisplayAsIcon,

      HGLOBAL                 hMetaPict,

      LPSIZEL                 lpSizelInSrc

)

{

   LPLINELIST          lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;

   LPLINE              lpLine = NULL;

   HDC                 hDC;

   int                 nTab = 0;

   OLECHAR             szStgName[CWCSTORAGENAME];

   LPCONTAINERLINE     lpContainerLine = NULL;

   ContainerDoc_GetNextStgName(lpContainerDoc, szStgName, CWCSTORAGENAME);

   /* default the new line to have the same indent as previous line */

   lpLine = LineList_GetLine(lpLL, nIndex);

   if (lpLine)

      nTab = Line_GetTabLevel(lpLine);

   hDC = LineList_GetDC(lpLL);

   lpContainerLine = ContainerLine_CreateFromData(

         hDC,

         nTab,

         lpContainerDoc,

         lpSrcDataObj,

         dwCreateType,

         cfFormat,

         fDisplayAsIcon,

         hMetaPict,

         szStgName

      );

   LineList_ReleaseDC(lpLL, hDC);

   if (! lpContainerLine)

      goto error;

   /* add a ContainerLine object to the document's LineList. The

   **    ContainerLine manages the rectangle on the screen occupied by

   **    the OLE object. later when the app is updated to support

   **    extended layout, there could be more than one Line associated

   **    with the OLE object.

   */

   LineList_AddLine(lpLL, (LPLINE)lpContainerLine, nIndex);

   /* OLE2NOTE: if the source of the OLE object just pasted, passed a

   **    non-zero sizel in the ObjectDescriptor, then we will try to

   **    keep the object the same size as it is in the source. this

   **    may be a scaled size if the object had been resized in the

   **    source container. if the source did not give a valid sizel,

   **    then we will retrieve the size of the object by calling

   **    IViewObject2::GetExtent.

   */

   if (lpSizelInSrc && (lpSizelInSrc->cx != 0 || lpSizelInSrc->cy != 0)) {

      ContainerLine_UpdateExtent(lpContainerLine, lpSizelInSrc);

   } else

      ContainerLine_UpdateExtent(lpContainerLine, NULL);

   OutlineDoc_SetModified((LPOUTLINEDOC)lpContainerDoc, TRUE, TRUE, TRUE);

   return 1;   // one line added to LineList

error:

   // NOTE: if ContainerLine_CreateFromClip failed

   OutlineApp_ErrorMessage(g_lpApp, OLESTR("Paste Object failed!"));

   return 0;       // no lines added to line list

}

/* ContainerDoc_GetData

 * --------------------

 *

 * Render data from the document on a CALLEE allocated STGMEDIUM.

 *      This routine is called via IDataObject::GetData.

 */

HRESULT ContainerDoc_GetData (

      LPCONTAINERDOC          lpContainerDoc,

      LPFORMATETC             lpformatetc,

      LPSTGMEDIUM             lpMedium

)

{

   LPOLEDOC  lpOleDoc = (LPOLEDOC)lpContainerDoc;

   LPOUTLINEDOC  lpOutlineDoc = (LPOUTLINEDOC)lpContainerDoc;

   LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)g_lpApp;

   LPOLEAPP  lpOleApp = (LPOLEAPP)lpContainerApp;

   LPOUTLINEAPP  lpOutlineApp = (LPOUTLINEAPP)lpContainerApp;

   HRESULT hrErr;

   SCODE sc;

   // OLE2NOTE: we must set out pointer parameters to NULL

   lpMedium->pUnkForRelease = NULL;

   /* OLE2NOTE: we must set all out pointer parameters to NULL. */

   lpMedium->tymed = TYMED_NULL;

   lpMedium->pUnkForRelease = NULL;    // we transfer ownership to caller

   lpMedium->u.hGlobal = NULL;

   if (lpformatetc->cfFormat == lpContainerApp->m_cfCntrOutl) {

      /* OLE2NOTE: currently OLE does NOT support remoting a root

      **    level IStorage (either memory or file based) as an OUT

      **    parameter. thus, we can NOT support GetData for this

      **    TYMED_ISTORAGE based format. the caller MUST call GetDataHere.

      */

      sc = DV_E_FORMATETC;

      goto error;

   } else if (!lpContainerDoc->m_fEmbeddedObjectAvail &&

         lpformatetc->cfFormat == lpOutlineApp->m_cfOutline) {

      // Verify caller asked for correct medium

      if (!(lpformatetc->tymed & TYMED_HGLOBAL)) {

         sc = DV_E_FORMATETC;

         goto error;

      }

      lpMedium->u.hGlobal = OutlineDoc_GetOutlineData(lpOutlineDoc, NULL);

      if (! lpMedium->u.hGlobal) {

         sc = E_OUTOFMEMORY;

         goto error;

      }

      lpMedium->tymed = TYMED_HGLOBAL;

      OleDbgOut3("ContainerDoc_GetData: rendered CF_OUTLINE\r\n");

      return NOERROR;

   } else if (!lpContainerDoc->m_fEmbeddedObjectAvail &&

         lpformatetc->cfFormat == CF_TEXT) {

      // Verify caller asked for correct medium

      if (!(lpformatetc->tymed & TYMED_HGLOBAL)) {

         sc = DV_E_FORMATETC;

         goto error;

      }

      lpMedium->u.hGlobal = OutlineDoc_GetTextData (

            (LPOUTLINEDOC)lpContainerDoc,

            NULL

      );

      if (! lpMedium->u.hGlobal) {

         sc = E_OUTOFMEMORY;

         goto error;

      }

      lpMedium->tymed = TYMED_HGLOBAL;

      OleDbgOut3("ContainerDoc_GetData: rendered CF_TEXT\r\n");

      return NOERROR;

   } else if ( lpformatetc->cfFormat == lpOleApp->m_cfObjectDescriptor ||

      (lpformatetc->cfFormat == lpOleApp->m_cfLinkSrcDescriptor &&

         lpOleDoc->m_fLinkSourceAvail) ) {

      // Verify caller asked for correct medium

      if (!(lpformatetc->tymed & TYMED_HGLOBAL)) {

         sc = DV_E_FORMATETC;

         goto error;

      }

      lpMedium->u.hGlobal = OleDoc_GetObjectDescriptorData (

            (LPOLEDOC)lpContainerDoc,

            NULL

      );

      if (! lpMedium->u.hGlobal) {

         sc = E_OUTOFMEMORY;

         goto error;

      }

      lpMedium->tymed = TYMED_HGLOBAL;

#if defined( _DEBUG )

      if (lpformatetc->cfFormat == lpOleApp->m_cfObjectDescriptor)

         OleDbgOut3(

            "ContainerDoc_GetData: rendered CF_OBJECTDESCRIPTOR\r\n");

      else

         OleDbgOut3(

            "ContainerDoc_GetData: rendered CF_LINKSRCDESCRIPTOR\r\n");

#endif

      return NOERROR;

   } else if (lpContainerDoc->m_fEmbeddedObjectAvail) {

      /* OLE2NOTE: if this document contains a single OLE object

      **    (ie. cfEmbeddedObject data format is available), then

      **    the formats offered via our IDataObject must include

      **    the formats available from the OLE object itself.

      **    thus, we delegate this call to the IDataObject* of the

      **    OLE object.

      */

      if (lpformatetc->cfFormat == lpOleApp->m_cfEmbeddedObject) {

         LPPERSISTSTORAGE lpPersistStg =

               (LPPERSISTSTORAGE)ContainerDoc_GetSingleOleObject(

                     lpContainerDoc,

                     &IID_IPersistStorage,

                     NULL

         );

         if (! lpPersistStg)

            return ResultFromScode(DV_E_FORMATETC);

         /* render CF_EMBEDDEDOBJECT by asking the object to save

         **    into a temporary, DELETEONRELEASE pStg allocated by us.

         */

         hrErr = OleStdGetOleObjectData(

               lpPersistStg,

               lpformatetc,

               lpMedium,

               FALSE   /* fUseMemory -- (use file-base stg) */

         );

         OleStdRelease((LPUNKNOWN)lpPersistStg);

         if (hrErr != NOERROR) {

            sc = GetScode(hrErr);

            goto error;

         }

         OleDbgOut3("ContainerDoc_GetData: rendered CF_EMBEDDEDOBJECT\r\n");

         return hrErr;

      } else if (lpformatetc->cfFormat == CF_METAFILEPICT) {

         /* OLE2NOTE: as a container which draws objects, when a single

         **    OLE object is copied, we can give the Metafile picture of

         **    the object.

         */

         LPCONTAINERLINE lpContainerLine;

         LPOLEOBJECT lpOleObj;

         SIZEL sizelOleObject;

         // Verify caller asked for correct medium

         if (!(lpformatetc->tymed & TYMED_MFPICT)) {

            sc = DV_E_FORMATETC;

            goto error;

         }

         lpOleObj = (LPOLEOBJECT)ContainerDoc_GetSingleOleObject(

               lpContainerDoc,

               &IID_IOleObject,

               (LPCONTAINERLINE FAR*)&lpContainerLine

         );

         if (! lpOleObj) {

            sc = E_OUTOFMEMORY;     // could not load object

            goto error;

         }

         if (lpformatetc->dwAspect & lpContainerLine->m_dwDrawAspect) {

            LPLINE lpLine = (LPLINE)lpContainerLine;

            /* render CF_METAFILEPICT by drawing the object into

            **    a metafile DC

            */

            /* OLE2NOTE: Get size that object is being drawn. If the

            **    object has been scaled because the user resized the

            **    object, then we want to render a metafile with the

            **    scaled size.

            */

            sizelOleObject.cx = lpLine->m_nWidthInHimetric;

            sizelOleObject.cy = lpLine->m_nHeightInHimetric;

            lpMedium->u.hGlobal = OleStdGetMetafilePictFromOleObject(

                  lpOleObj,

                  lpContainerLine->m_dwDrawAspect,

                  (LPSIZEL)&sizelOleObject,

                  lpformatetc->ptd

            );

            OleStdRelease((LPUNKNOWN)lpOleObj);

            if (! lpMedium->u.hGlobal) {

               sc = E_OUTOFMEMORY;

               goto error;

            }

            lpMedium->tymed = TYMED_MFPICT;

            OleDbgOut3("ContainerDoc_GetData: rendered CF_METAFILEPICT\r\n");

            return NOERROR;

         } else {

            // improper aspect requested

            OleStdRelease((LPUNKNOWN)lpOleObj);

            return ResultFromScode(DV_E_FORMATETC);

         }

      } else if (lpformatetc->cfFormat == lpOleApp->m_cfLinkSource) {

         if (lpOleDoc->m_fLinkSourceAvail) {

            LPMONIKER lpmk;

            lpmk = ContainerLine_GetFullMoniker(

                  lpContainerDoc->m_lpSrcContainerLine,

                  GETMONIKER_FORCEASSIGN

            );

            if (lpmk) {

               hrErr = OleStdGetLinkSourceData(

                     lpmk,

                     &lpContainerDoc->m_clsidOleObjCopied,

                     lpformatetc,

                     lpMedium

               );

               OleStdRelease((LPUNKNOWN)lpmk);

               if (hrErr != NOERROR) {

                  sc = GetScode(hrErr);

                  goto error;

               }

               OleDbgOut3("ContainerDoc_GetData: rendered CF_LINKSOURCE\r\n");

               return hrErr;

            } else {

               sc = DV_E_FORMATETC;

               goto error;

            }

         } else {

            sc = DV_E_FORMATETC;

            goto error;

         }

      }

#if defined( OPTIONAL_ADVANCED_DATA_TRANSFER )

      /* OLE2NOTE: optionally, a container that wants to have a

      **    potentially richer data transfer, can enumerate the data

      **    formats from the OLE object's cache and offer them too. if

      **    the object has a special handler, then it might be able to

      **    render additional data formats. in this case, the

      **    container must delegate the GetData call to the object if

      **    it does not directly support the format.

      **

      **    CNTROUTL does NOT enumerate the cache; it implements the

      **    simpler strategy of offering a static list of formats.

      **    thus the delegation is NOT required.

      */

     else {

         /* OLE2NOTE: we delegate this call to the IDataObject* of the

         **    OLE object.

         */

         LPDATAOBJECT lpDataObj;

         lpDataObj = (LPDATAOBJECT)ContainerDoc_GetSingleOleObject(

               lpContainerDoc,

               &IID_IDataObject,

               NULL

         );

         if (! lpDataObj) {

            sc = DV_E_FORMATETC;

            goto error;

         }

         OLEDBG_BEGIN2("ContainerDoc_GetData: delegate to OLE obj\r\n")

         hrErr=lpDataObj->lpVtbl->GetData(lpDataObj,lpformatetc,lpMedium);

         OLEDBG_END2

         OleStdRelease((LPUNKNOWN)lpDataObj);

         return hrErr;

      }

#endif  // ! OPTIONAL_ADVANCED_DATA_TRANSFER

   }

   // if we get here then we do NOT support the requested format

   sc = DV_E_FORMATETC;

error:

   return ResultFromScode(sc);

}

/* ContainerDoc_GetDataHere

 * ------------------------

 *

 * Render data from the document on a CALLER allocated STGMEDIUM.

 *      This routine is called via IDataObject::GetDataHere.

 */

HRESULT ContainerDoc_GetDataHere (

      LPCONTAINERDOC          lpContainerDoc,

      LPFORMATETC             lpformatetc,

      LPSTGMEDIUM             lpMedium

)

{

   LPOLEDOC  lpOleDoc = (LPOLEDOC)lpContainerDoc;

   LPOUTLINEDOC  lpOutlineDoc = (LPOUTLINEDOC)lpContainerDoc;

   LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)g_lpApp;

   LPOLEAPP  lpOleApp = (LPOLEAPP)lpContainerApp;

   LPOUTLINEAPP  lpOutlineApp = (LPOUTLINEAPP)lpContainerApp;

   HRESULT hrErr;

   // OLE2NOTE: lpMedium is an IN parameter. we should NOT set

   //           lpMedium->pUnkForRelease to NULL

   // we only support  IStorage medium

   if (lpformatetc->cfFormat == lpContainerApp->m_cfCntrOutl) {

      if (!(lpformatetc->tymed & TYMED_ISTORAGE))

         return ResultFromScode(DV_E_FORMATETC);

      if (lpMedium->tymed == TYMED_ISTORAGE) {

         /* Caller has allocated the storage. we must copy all of our

         **    data into his storage.

         */

         /*  OLE2NOTE: we must be sure to write our class ID into our

         **    storage. this information is used by OLE to determine the

         **    class of the data stored in our storage.

         */

         if((hrErr=WriteClassStg(lpMedium->u.pstg,&CLSID_APP)) != NOERROR)

            return hrErr;

         OutlineDoc_SaveSelToStg(

               (LPOUTLINEDOC)lpContainerDoc,

               NULL,   /* entire doc */

               lpContainerApp->m_cfCntrOutl,

               lpMedium->u.pstg,

               FALSE,  /* fSameAsLoad */

               FALSE   /* fRemember */

         );

         OleStdCommitStorage(lpMedium->u.pstg);

         OleDbgOut3("ContainerDoc_GetDataHere: rendered CF_CNTROUTL\r\n");

         return NOERROR;

      } else {

         // we only support IStorage medium

         return ResultFromScode(DV_E_FORMATETC);

      }

   } else if (lpContainerDoc->m_fEmbeddedObjectAvail) {

      /* OLE2NOTE: if this document contains a single OLE object

      **    (ie. cfEmbeddedObject data format is available), then

      **    the formats offered via our IDataObject must include

      **    CF_EMBEDDEDOBJECT and the formats available from the OLE

      **    object itself.

      */

      if (lpformatetc->cfFormat == lpOleApp->m_cfEmbeddedObject) {

         LPPERSISTSTORAGE lpPersistStg =

               (LPPERSISTSTORAGE)ContainerDoc_GetSingleOleObject(

                     lpContainerDoc,

                     &IID_IPersistStorage,

                     NULL

         );

         if (! lpPersistStg) {

            return ResultFromScode(E_OUTOFMEMORY);

         }

         /* render CF_EMBEDDEDOBJECT by asking the object to save

         **    into the IStorage allocated by the caller.

         */

         hrErr = OleStdGetOleObjectData(

               lpPersistStg,

               lpformatetc,

               lpMedium,

               FALSE   /* fUseMemory -- N/A */

         );

         OleStdRelease((LPUNKNOWN)lpPersistStg);

         if (hrErr != NOERROR) {

            return hrErr;

         }

         OleDbgOut3("ContainerDoc_GetDataHere: rendered CF_EMBEDDEDOBJECT\r\n");

         return hrErr;

      } else if (lpformatetc->cfFormat == lpOleApp->m_cfLinkSource) {

         if (lpOleDoc->m_fLinkSourceAvail) {

            LPMONIKER lpmk;

            lpmk = ContainerLine_GetFullMoniker(

                  lpContainerDoc->m_lpSrcContainerLine,

                  GETMONIKER_FORCEASSIGN

            );

            if (lpmk) {

               hrErr = OleStdGetLinkSourceData(

                     lpmk,

                     &lpContainerDoc->m_clsidOleObjCopied,

                     lpformatetc,

                     lpMedium

               );

               OleStdRelease((LPUNKNOWN)lpmk);

               OleDbgOut3("ContainerDoc_GetDataHere: rendered CF_LINKSOURCE\r\n");

               return hrErr;

            } else {

               return ResultFromScode(E_FAIL);

            }

         } else {

            return ResultFromScode(DV_E_FORMATETC);

         }

      } else {

#if !defined( OPTIONAL_ADVANCED_DATA_TRANSFER )

         return ResultFromScode(DV_E_FORMATETC);

#endif

#if defined( OPTIONAL_ADVANCED_DATA_TRANSFER )

         /* OLE2NOTE: optionally, a container that wants to have a

         **    potentially richer data transfer, can enumerate the data

         **    formats from the OLE object's cache and offer them too. if

         **    the object has a special handler, then it might be able to

         **    render additional data formats. in this case, the

         **    container must delegate the GetData call to the object if

         **    it does not directly support the format.

         **

         **    CNTROUTL does NOT enumerate the cache; it implements the

         **    simpler strategy of offering a static list of formats.

         **    thus the delegation is NOT required.

         */

         /* OLE2NOTE: we delegate this call to the IDataObject* of the

         **    OLE object.

         */

         LPDATAOBJECT lpDataObj;

         lpDataObj = (LPDATAOBJECT)ContainerDoc_GetSingleOleObject(

               lpContainerDoc,

               &IID_IDataObject,

               NULL

         );

         if (! lpDataObj)

            return ResultFromScode(DV_E_FORMATETC);

         OLEDBG_BEGIN2("ContainerDoc_GetDataHere: delegate to OLE obj\r\n")

         hrErr = lpDataObj->lpVtbl->GetDataHere(

               lpDataObj,

               lpformatetc,

               lpMedium

         );

         OLEDBG_END2

         OleStdRelease((LPUNKNOWN)lpDataObj);

         return hrErr;

#endif  // OPTIONAL_ADVANCED_DATA_TRANSFER

      }

   } else {

      return ResultFromScode(DV_E_FORMATETC);

   }

}

/* ContainerDoc_QueryGetData

 * -------------------------

 *

 * Answer if a particular data format is supported via GetData/GetDataHere.

 *      This routine is called via IDataObject::QueryGetData.

 */

HRESULT ContainerDoc_QueryGetData (

      LPCONTAINERDOC          lpContainerDoc,

      LPFORMATETC             lpformatetc

)

{

   LPOLEDOC  lpOleDoc = (LPOLEDOC)lpContainerDoc;

   LPOUTLINEDOC  lpOutlineDoc = (LPOUTLINEDOC)lpContainerDoc;

   LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)g_lpApp;

   LPOLEAPP  lpOleApp = (LPOLEAPP)lpContainerApp;

   LPOUTLINEAPP  lpOutlineApp = (LPOUTLINEAPP)lpContainerApp;

   LPDATAOBJECT  lpDataObj = NULL;

   LPCONTAINERLINE lpContainerLine = NULL;

   SCODE sc;

   HRESULT hrErr;

   if (lpContainerDoc->m_fEmbeddedObjectAvail) {

      lpDataObj = (LPDATAOBJECT)ContainerDoc_GetSingleOleObject(

               lpContainerDoc,

               &IID_IDataObject,

               (LPCONTAINERLINE FAR*)&lpContainerLine

      );

   }

   /* Caller is querying if we support certain format but does not

   **    want any data actually returned.

   */

   if (lpformatetc->cfFormat == lpContainerApp->m_cfCntrOutl) {

      // we only support ISTORAGE medium

      sc = GetScode( OleStdQueryFormatMedium(lpformatetc, TYMED_ISTORAGE) );

   } else if (lpformatetc->cfFormat == lpOleApp->m_cfEmbeddedObject &&

         lpContainerDoc->m_fEmbeddedObjectAvail ) {

      sc = GetScode( OleStdQueryOleObjectData(lpformatetc) );

   } else if (lpformatetc->cfFormat == lpOleApp->m_cfLinkSource &&

         lpOleDoc->m_fLinkSourceAvail) {

      sc = GetScode( OleStdQueryLinkSourceData(lpformatetc) );

   // CF_TEXT and CF_OUTLINE are NOT supported when single object is copied

   } else if (!lpContainerDoc->m_fEmbeddedObjectAvail &&

         (lpformatetc->cfFormat == (lpOutlineApp)->m_cfOutline ||

          lpformatetc->cfFormat == CF_TEXT) ) {

      // we only support HGLOBAL medium

      sc = GetScode( OleStdQueryFormatMedium(lpformatetc, TYMED_HGLOBAL) );

   } else if ( lpformatetc->cfFormat == lpOleApp->m_cfObjectDescriptor ||

      (lpformatetc->cfFormat == lpOleApp->m_cfLinkSrcDescriptor &&

         lpOleDoc->m_fLinkSourceAvail) ) {

      sc = GetScode( OleStdQueryObjectDescriptorData(lpformatetc) );

   } else if (lpformatetc->cfFormat == CF_METAFILEPICT &&

         lpContainerDoc->m_fEmbeddedObjectAvail && lpContainerLine &&

         (lpformatetc->dwAspect & lpContainerLine->m_dwDrawAspect)) {

      /* OLE2NOTE: as a container which draws objects, when a single

      **    OLE object is copied, we can give the Metafile picture of

      **    the object.

      */

      // we only support MFPICT medium

      sc = GetScode( OleStdQueryFormatMedium(lpformatetc, TYMED_MFPICT) );

   } else if (lpDataObj) {

      /* OLE2NOTE: if this document contains a single OLE object

      **    (ie. cfEmbeddedObject data format is available), then

      **    the formats offered via our IDataObject must include

      **    the formats available from the OLE object itself.

      **    thus we delegate this call to the IDataObject* of the

      **    OLE object.

      */

      OLEDBG_BEGIN2("ContainerDoc_QueryGetData: delegate to OLE obj\r\n")

      hrErr = lpDataObj->lpVtbl->QueryGetData(lpDataObj, lpformatetc);

      OLEDBG_END2

      sc = GetScode(hrErr);

   } else {

      sc = DV_E_FORMATETC;

   }

   if (lpDataObj)

      OleStdRelease((LPUNKNOWN)lpDataObj);

   return ResultFromScode(sc);

}

/* ContainerDoc_SetData

 * --------------------

 *

 * Set (modify) data of the document.

 *      This routine is called via IDataObject::SetData.

 */

HRESULT ContainerDoc_SetData (

      LPCONTAINERDOC          lpContainerDoc,

      LPFORMATETC             lpformatetc,

      LPSTGMEDIUM             lpmedium,

      BOOL                    fRelease

)

{

   /* in the container version of Outline, only DataTransferDoc's support

   **    IDataObject interface; the user documents do not support

   **    IDataObject. DataTransferDoc's do not accept SetData calls.

   */

   return ResultFromScode(DV_E_FORMATETC);

}

/* ContainerDoc_EnumFormatEtc

 * --------------------------

 *

 * Return an enumerator which enumerates the data accepted/offered by

 *      the document.

 *      This routine is called via IDataObject::SetData.

 */

HRESULT ContainerDoc_EnumFormatEtc(

      LPCONTAINERDOC          lpContainerDoc,

      DWORD                   dwDirection,

      LPENUMFORMATETC FAR*    lplpenumFormatEtc

)

{

   LPOLEDOC lpOleDoc = (LPOLEDOC)lpContainerDoc;

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerDoc;

   LPOLEAPP  lpOleApp = (LPOLEAPP)g_lpApp;

   LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)lpOleApp;

   int nActualFmts;

   int i;

   SCODE sc = S_OK;

   /* the Container-Only version of Outline does NOT offer

   **    IDataObject interface from its User documents.

   */

   if (! lpOutlineDoc->m_fDataTransferDoc)

      return ResultFromScode(E_FAIL);

   if (dwDirection == DATADIR_GET) {

      if (lpContainerDoc->m_fEmbeddedObjectAvail) {

         /* OLE2NOTE: if this document contains a single OLE object

         **    (ie. cfEmbeddedObject data format is available), then

         **    the formats offered via our enumerator must include

         **    the formats available from the OLE object itself. we

         **    have previously set up a special array of FORMATETC's

         **    in OutlineDoc_CreateDataTransferDoc routine which includes

         **    the combination of data we offer directly and data

         **    offered by the OLE object.

         */

         /* If the document does not have a Moniker, then exclude

         **    CF_LINKSOURCE CF_LINKSRCDESCRIPTOR from the list of

         **    formats available. these formats are deliberately

         **    listed last in the array of possible "Get" formats.

         */

         nActualFmts = lpContainerApp->m_nSingleObjGetFmts;

         if (! lpOleDoc->m_fLinkSourceAvail)

            nActualFmts -= 2;

         // set correct dwDrawAspect for METAFILEPICT of object copied

         for (i = 0; i < nActualFmts; i++) {

            if (lpContainerApp->m_arrSingleObjGetFmts[i].cfFormat ==

                                             CF_METAFILEPICT) {

               lpContainerApp->m_arrSingleObjGetFmts[i].dwAspect =

                     lpContainerDoc->m_dwAspectOleObjCopied;

               break;  // DONE

            }

         }

         *lplpenumFormatEtc = OleStdEnumFmtEtc_Create(

               nActualFmts, lpContainerApp->m_arrSingleObjGetFmts);

         if (*lplpenumFormatEtc == NULL)

            sc = E_OUTOFMEMORY;

      } else {

         /* This document does NOT offer cfEmbeddedObject,

         **    therefore we can simply enumerate the

         **    static list of formats that we handle directly.

         */

         *lplpenumFormatEtc = OleStdEnumFmtEtc_Create(

               lpOleApp->m_nDocGetFmts, lpOleApp->m_arrDocGetFmts);

         if (*lplpenumFormatEtc == NULL)

            sc = E_OUTOFMEMORY;

      }

   } else if (dwDirection == DATADIR_SET) {

      /* OLE2NOTE: a document that is used to transfer data

      **    (either via the clipboard or drag/drop does NOT

      **    accept SetData on ANY format!

      */

      sc = E_NOTIMPL;

   } else {

      sc = E_NOTIMPL;

   }

   return ResultFromScode(sc);

}

#if defined( OPTIONAL_ADVANCED_DATA_TRANSFER )

/* OLE2NOTE: optionally, a container that wants to have a

**    potentially richer data transfer, can enumerate the data

**    formats from the OLE object's cache and offer them too. if

**    the object has a special handler, then it might be able to

**    render additional data formats.

**

**    CNTROUTL does NOT enumerate the cache; it implements the simpler

**    strategy of offering a static list of formats. the following

**    function is included in order to illustrates how enumerating the

**    cache could be done. CNTROUTL does NOT call this function.

**

*/

/* ContainerDoc_SetupDocGetFmts

** ----------------------------

**    Setup the combined list of formats that this data transfer

**    ContainerDoc which contains a single OLE object should offer.

**

**    OLE2NOTE: The list of formats that should be offered when a

**    single OLE object is being transfered include the following:

**          * any formats the container app wants to give

**          * CF_EMBEDDEDOBJECT

**          * CF_METAFILEPICT

**          * any formats that the OLE object's cache can offer directly

**

**    We will offer the following formats in the order given:

**                  1. CF_CNTROUTL

**                  2. CF_EMBEDDEDOBJECT

**                  3. CF_OBJECTDESCRIPTOR

**                  4. CF_METAFILEPICT

**                  5. <data formats from OLE object's cache>

**                  6. CF_LINKSOURCE

**                  7. CF_LINKSRCDESCRIPTOR

*/

BOOL ContainerDoc_SetupDocGetFmts(

      LPCONTAINERDOC          lpContainerDoc,

      LPCONTAINERLINE         lpContainerLine

)

{

   LPOLEDOC lpOleDoc = (LPOLEDOC)lpContainerDoc;

   LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp;

   LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)g_lpApp;

   LPOLECACHE lpOleCache;

   HRESULT hrErr;

   STATDATA        StatData;

   LPENUMSTATDATA  lpEnumStatData = NULL;

   LPFORMATETC lparrDocGetFmts = NULL;

   UINT nOleObjFmts = 0;

   UINT nTotalFmts;

   UINT i;

   UINT iFmt;

   lpOleCache = (LPOLECACHE)OleStdQueryInterface(

         (LPUNKNOWN)lpContainerLine->m_lpOleObj,

         &IID_IOleCache

   );

   if (lpOleCache) {

      OLEDBG_BEGIN2("IOleCache::EnumCache called\r\n")

      hrErr = lpOleCache->lpVtbl->EnumCache(

            lpOleCache,

            (LPENUMSTATDATA FAR*)&lpEnumStatData

      );

      OLEDBG_END2

   }

   if (lpEnumStatData) {

      /* Cache enumerator is available. count the number of

      **    formats that the OLE object's cache offers.

      */

      while(lpEnumStatData->lpVtbl->Next(

               lpEnumStatData,

               1,

               (LPSTATDATA)&StatData,

               NULL) == NOERROR) {

         nOleObjFmts++;

         // OLE2NOTE: we MUST free the TargetDevice

         OleStdFree(StatData.formatetc.ptd);

      }

      lpEnumStatData->lpVtbl->Reset(lpEnumStatData);  // reset for next loop

   }

   /* OLE2NOTE: the maximum total number of formats that our IDataObject

   **    could offer equals the sum of the following:

   **          n offered by the OLE object's cache

   **       +  n normally offered by our app

   **       +  1 CF_EMBEDDEDOBJECT

   **       +  1 CF_METAFILEPICT

   **       +  1 CF_LINKSOURCE

   **       +  1 CF_LINKSRCDESCRIPTOR

   **    the actual number of formats that we can offer could be less

   **    than this total if there is any clash between the formats

   **    that we offer directly and those offered by the cache. if

   **    there is a clash, the container's rendering overrides that of

   **    the object. eg.: as a container transfering an OLE object we

   **    should directly offer CF_METAFILEPICT to guarantee that this

   **    format is always available. thus, if the cache offers

   **    CF_METAFILEPICT then it is skipped.

   */

   nTotalFmts = nOleObjFmts + lpOleApp->m_nDocGetFmts + 4;

   lparrDocGetFmts = (LPFORMATETC)New (nTotalFmts * sizeof(FORMATETC));

   OleDbgAssertSz(lparrDocGetFmts != NULL,"Error allocating arrDocGetFmts");

   if (lparrDocGetFmts == NULL)

         return FALSE;

   for (i = 0, iFmt = 0; i < lpOleApp->m_nDocGetFmts; i++) {

      _fmemcpy((LPFORMATETC)&lparrDocGetFmts[iFmt++],

            (LPFORMATETC)&lpOleApp->m_arrDocGetFmts[i],

            sizeof(FORMATETC)

      );

      if (lpOleApp->m_arrDocGetFmts[i].cfFormat ==

         lpContainerApp->m_cfCntrOutl) {

         /* insert CF_EMBEDDEDOBJECT, CF_METAFILEPICT, and formats

         **    available from the OLE object's cache following

         **    CF_CNTROUTL.

         */

         lparrDocGetFmts[iFmt].cfFormat = lpOleApp->m_cfEmbeddedObject;

         lparrDocGetFmts[iFmt].ptd      = NULL;

         lparrDocGetFmts[iFmt].dwAspect = DVASPECT_CONTENT;

         lparrDocGetFmts[iFmt].tymed    = TYMED_ISTORAGE;

         lparrDocGetFmts[iFmt].lindex   = -1;

         iFmt++;

         lparrDocGetFmts[iFmt].cfFormat = CF_METAFILEPICT;

         lparrDocGetFmts[iFmt].ptd      = NULL;

         lparrDocGetFmts[iFmt].dwAspect = lpContainerLine->m_dwDrawAspect;

         lparrDocGetFmts[iFmt].tymed    = TYMED_MFPICT;

         lparrDocGetFmts[iFmt].lindex   = -1;

         iFmt++;

         if (lpEnumStatData) {

            /* Cache enumerator is available. enumerate all of

            **    the formats that the OLE object's cache offers.

            */

            while(lpEnumStatData->lpVtbl->Next(

                  lpEnumStatData,

                  1,

                  (LPSTATDATA)&StatData,

                  NULL) == NOERROR) {

               /* check if the format clashes with one of our fmts */

               if (StatData.formatetc.cfFormat != CF_METAFILEPICT

                  && ! OleStdIsDuplicateFormat(

                        (LPFORMATETC)&StatData.formatetc,

                        lpOleApp->m_arrDocGetFmts,

                        lpOleApp->m_nDocGetFmts)) {

                  OleStdCopyFormatEtc(

                        &(lparrDocGetFmts[iFmt]),&StatData.formatetc);

                  iFmt++;

               }

               // OLE2NOTE: we MUST free the TargetDevice

               OleStdFree(StatData.formatetc.ptd);

            }

         }

      }

   }

   if (lpOleCache)

      OleStdRelease((LPUNKNOWN)lpOleCache);

   /* append CF_LINKSOURCE format */

   lparrDocGetFmts[iFmt].cfFormat = lpOleApp->m_cfLinkSource;

   lparrDocGetFmts[iFmt].ptd      = NULL;

   lparrDocGetFmts[iFmt].dwAspect = DVASPECT_CONTENT;

   lparrDocGetFmts[iFmt].tymed    = TYMED_ISTREAM;

   lparrDocGetFmts[iFmt].lindex   = -1;

   iFmt++;

   /* append CF_LINKSRCDESCRIPTOR format */

   lparrDocGetFmts[iFmt].cfFormat = lpOleApp->m_cfLinkSrcDescriptor;

   lparrDocGetFmts[iFmt].ptd      = NULL;

   lparrDocGetFmts[iFmt].dwAspect = DVASPECT_CONTENT;

   lparrDocGetFmts[iFmt].tymed    = TYMED_HGLOBAL;

   lparrDocGetFmts[iFmt].lindex   = -1;

   iFmt++;

   lpContainerDoc->m_lparrDocGetFmts = lparrDocGetFmts;

   lpContainerDoc->m_nDocGetFmts = iFmt;

   if (lpEnumStatData)

      OleStdVerifyRelease(

            (LPUNKNOWN)lpEnumStatData,

            "Cache enumerator not released properly"

      );

   return TRUE;

}

#endif  // OPTIONAL_ADVANCED_DATA_TRANSFER

#endif  // OLE_CNTR


CNTRBASE.C  (OUTLINE Sample)

/*************************************************************************

**

**    OLE 2 Container Sample Code

**

**    cntrbase.c

**

**    This file contains all interfaces, methods and related support

**    functions for the basic OLE Container application. The

**    basic OLE Container application supports being a container for

**    embedded and linked objects.

**    The basic Container application includes the following

**    implementation objects:

**

**    ContainerDoc Object

**      no required interfaces for basic functionality

**      (see linking.c for linking related support)

**      (see clipbrd.c for clipboard related support)

**      (see dragdrop.c for drag/drop related support)

**

**    ContainerLine Object

**    (see cntrline.c for all ContainerLine functions and interfaces)

**      exposed interfaces:

**          IOleClientSite

**          IAdviseSink

**

**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

**

*************************************************************************/

#include "outline.h"

OLEDBGDATA

extern LPOUTLINEAPP             g_lpApp;

extern IOleUILinkContainerVtbl  g_CntrDoc_OleUILinkContainerVtbl;

#if defined( INPLACE_CNTR )

extern BOOL g_fInsideOutContainer;

#endif  // INPLACE_CNTR

// REVIEW: should use string resource for messages

OLECHAR ErrMsgShowObj[] = OLESTR("Could not show object server!");

OLECHAR ErrMsgInsertObj[] = OLESTR("Insert Object failed!");

OLECHAR ErrMsgConvertObj[] = OLESTR("Convert Object failed!");

OLECHAR ErrMsgCantConvert[] = OLESTR("Unable to convert the selection!");

OLECHAR ErrMsgActivateAsObj[] = OLESTR("Activate As Object failed!");

extern OLECHAR ErrMsgSaving[];

extern OLECHAR ErrMsgOpening[];

/* ContainerDoc_Init

 * -----------------

 *

 *  Initialize the fields of a new ContainerDoc object. The doc is initially

 *  not associated with a file or an (Untitled) document. This function sets

 *  the docInitType to DOCTYPE_UNKNOWN. After calling this function the

 *  caller should call:

 *      1.) Doc_InitNewFile to set the ContainerDoc to (Untitled)

 *      2.) Doc_LoadFromFile to associate the ContainerDoc with a file.

 *  This function creates a new window for the document.

 *

 *  NOTE: the window is initially created with a NIL size. it must be

 *        sized and positioned by the caller. also the document is initially

 *        created invisible. the caller must call Doc_ShowWindow

 *        after sizing it to make the document window visible.

 */

BOOL ContainerDoc_Init(LPCONTAINERDOC lpContainerDoc, BOOL fDataTransferDoc)

{

   LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)g_lpApp;

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerDoc;

   lpOutlineDoc->m_cfSaveFormat             = lpContainerApp->m_cfCntrOutl;

   lpContainerDoc->m_nNextObjNo            = 0L;

   lpContainerDoc->m_lpNewStg              = NULL;

   lpContainerDoc->m_fEmbeddedObjectAvail  = FALSE;

   lpContainerDoc->m_clsidOleObjCopied     = CLSID_NULL;

   lpContainerDoc->m_dwAspectOleObjCopied  = DVASPECT_CONTENT;

   lpContainerDoc->m_lpSrcContainerLine    = NULL;

   lpContainerDoc->m_fShowObject           = TRUE;

#if defined( INPLACE_CNTR )

   lpContainerDoc->m_lpLastIpActiveLine    = NULL;

   lpContainerDoc->m_lpLastUIActiveLine    = NULL;

   lpContainerDoc->m_hWndUIActiveObj       = NULL;

   lpContainerDoc->m_fAddMyUI              = TRUE; // UI needs to be added

   lpContainerDoc->m_cIPActiveObjects      = 0;

   lpContainerApp->m_fMenuHelpMode         = FALSE; // F1 pressed in menu

#if defined( INPLACE_CNTRSVR )

   lpContainerDoc->m_lpTopIPFrame          =

               (LPOLEINPLACEUIWINDOW)&lpContainerDoc->m_OleInPlaceFrame;

   lpContainerDoc->m_lpTopIPDoc            =

               (LPOLEINPLACEUIWINDOW)&lpContainerDoc->m_OleInPlaceDoc;

   lpContainerDoc->m_hSharedMenu           = NULL;

   lpContainerDoc->m_hOleMenu              = NULL;

#endif  // INPLACE_CNTRSVR

#endif  // INPLACE_CNTR

   INIT_INTERFACEIMPL(

         &lpContainerDoc->m_OleUILinkContainer,

         &g_CntrDoc_OleUILinkContainerVtbl,

         lpContainerDoc

   );

   return TRUE;

}

/* ContainerDoc_GetNextLink

 * ------------------------

 *

 *  Update all links in the document. A dialog box will be popped up showing

 *  the progress of the update and allow the user to quit by pushing the

 *  stop button

 */

LPCONTAINERLINE ContainerDoc_GetNextLink(

      LPCONTAINERDOC lpContainerDoc,

      LPCONTAINERLINE lpContainerLine

)

{

   LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;

   DWORD dwNextLink = 0;

   LPLINE lpLine;

   static int nIndex = 0;

   if (lpContainerLine==NULL)

      nIndex = 0;

   for ( ; nIndex < lpLL->m_nNumLines; nIndex++) {

      lpLine = LineList_GetLine(lpLL, nIndex);

      if (lpLine

         && (Line_GetLineType(lpLine) == CONTAINERLINETYPE)

         && ContainerLine_IsOleLink((LPCONTAINERLINE)lpLine)) {

         nIndex++;

         ContainerLine_LoadOleObject((LPCONTAINERLINE)lpLine);

         return (LPCONTAINERLINE)lpLine;

      }

   }

   return NULL;

}

/* ContainerDoc_UpdateLinks

 * ------------------------

 *

 *  Update all links in the document. A dialog box will be popped up showing

 *  the progress of the update and allow the user to quit by pushing the

 *  stop button

 */

void ContainerDoc_UpdateLinks(LPCONTAINERDOC lpContainerDoc)

{

   int             cLinks;

   BOOL            fAllLinksUpToDate = TRUE;

   HWND            hwndDoc = ((LPOUTLINEDOC)lpContainerDoc)->m_hWndDoc;

   HCURSOR         hCursor;

   LPCONTAINERLINE lpContainerLine = NULL;

   HRESULT         hrErr;

   DWORD           dwUpdateOpt;

   LPOLEAPP        lpOleApp = (LPOLEAPP)g_lpApp;

   BOOL            fPrevEnable1;

   BOOL            fPrevEnable2;

   hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));

   /* OLE2NOTE: we do not want to ever give the Busy/NotResponding

   **    dialogs when we are updating automatic links as part of

   **    opening a document.  even if the link source of data is busy,

   **    we do not want put up the busy dialog. thus we will disable

   **    the dialog and later re-enable them

   */

   OleApp_DisableBusyDialogs(lpOleApp, &fPrevEnable1, &fPrevEnable2);

   /* get total number of automatic links */

   cLinks = 0;

   while (lpContainerLine = ContainerDoc_GetNextLink(

                           lpContainerDoc,

                           lpContainerLine)) {

      hrErr = CntrDoc_LinkCont_GetLinkUpdateOptions(

            (LPOLEUILINKCONTAINER)&lpContainerDoc->m_OleUILinkContainer,

            (DWORD)lpContainerLine,

            (LPDWORD)&dwUpdateOpt

      );

      if (hrErr == NOERROR) {

         if (dwUpdateOpt==OLEUPDATE_ALWAYS) {

            cLinks++;

            if (fAllLinksUpToDate) {

               OLEDBG_BEGIN2("IOleObject::IsUpToDate called\r\n")

               hrErr = lpContainerLine->m_lpOleObj->lpVtbl->IsUpToDate(

                     lpContainerLine->m_lpOleObj);

               OLEDBG_END2

               if (hrErr != NOERROR)

                  fAllLinksUpToDate = FALSE;

            }

         }

      }

#if defined( _DEBUG )

      else

         OleDbgOutHResult("IOleUILinkContainer::GetLinkUpdateOptions returned",hrErr);

#endif

   }

   if (fAllLinksUpToDate)

      goto done; // don't bother user if all links are up-to-date

   SetCursor(hCursor);

   if ((cLinks > 0) && !OleUIUpdateLinks(

         (LPOLEUILINKCONTAINER)&lpContainerDoc->m_OleUILinkContainer,

         hwndDoc,

         (LPOLESTR)APPNAME,

         cLinks))

      {

      char szTemp[256];

      wcstombs(szTemp, APPNAME, 255);

      if (ID_PU_LINKS == OleUIPromptUser(

            (WORD)IDD_CANNOTUPDATELINK,

            hwndDoc,

            szTemp)) {

         ContainerDoc_EditLinksCommand(lpContainerDoc);

      }

   }

done:

   // re-enable the Busy/NotResponding dialogs

   OleApp_EnableBusyDialogs(lpOleApp, fPrevEnable1, fPrevEnable2);

}

/* ContainerDoc_SetShowObjectFlag

 * ------------------------------

 *

 *  Set/Clear the ShowObject flag of ContainerDoc

 */

void ContainerDoc_SetShowObjectFlag(LPCONTAINERDOC lpContainerDoc, BOOL fShow)

{

   if (!lpContainerDoc)

      return;

   lpContainerDoc->m_fShowObject = fShow;

}

/* ContainerDoc_GetShowObjectFlag

 * ------------------------------

 *

 *  Get the ShowObject flag of ContainerDoc

 */

BOOL ContainerDoc_GetShowObjectFlag(LPCONTAINERDOC lpContainerDoc)

{

   if (!lpContainerDoc)

      return FALSE;

   return lpContainerDoc->m_fShowObject;

}

/* ContainerDoc_InsertOleObjectCommand

 * -----------------------------------

 *

 * Insert a new OLE object in the ContainerDoc.

 */

void ContainerDoc_InsertOleObjectCommand(LPCONTAINERDOC lpContainerDoc)

{

   LPLINELIST              lpLL =&((LPOUTLINEDOC)lpContainerDoc)->m_LineList;

   LPLINE                  lpLine = NULL;

   HDC                     hDC;

   int                     nTab = 0;

   int                     nIndex = LineList_GetFocusLineIndex(lpLL);

   LPCONTAINERLINE         lpContainerLine=NULL;

   OLECHAR                 szStgName[CWCSTORAGENAME];

   UINT                    uRet;

   OLEUIINSERTOBJECT       io;

   OLECHAR                 szFile[OLEUI_CCHPATHMAX];

   DWORD                   dwOleCreateType;

   BOOL                    fDisplayAsIcon;

   HCURSOR                 hPrevCursor;

   _fmemset((LPOLEUIINSERTOBJECT)&io, 0, sizeof(OLEUIINSERTOBJECT));

   io.cbStruct=sizeof(OLEUIINSERTOBJECT);

   io.dwFlags=IOF_SELECTCREATENEW | IOF_SHOWHELP;

   io.hWndOwner=((LPOUTLINEDOC)lpContainerDoc)->m_hWndDoc;

   io.lpszFile=(LPOLESTR)szFile;

   io.cchFile=OLEUI_CCHPATHMAX;

//   _fmemset((LPOLESTR)szFile, 0, OLEUI_CCHPATHMAX);

   _fmemset((LPOLESTR)szFile, 0, OLEUI_CCHPATHMAX*sizeof(OLECHAR));

#if defined( OLE_VERSION )

   OleApp_PreModalDialog((LPOLEAPP)g_lpApp, (LPOLEDOC)lpContainerDoc);

#endif

   OLEDBG_BEGIN3("OleUIInsertObject called\r\n")

   uRet=OleUIInsertObject((LPOLEUIINSERTOBJECT)&io);

   OLEDBG_END3

#if defined( OLE_VERSION )

   OleApp_PostModalDialog((LPOLEAPP)g_lpApp, (LPOLEDOC)lpContainerDoc);

#endif

   if (OLEUI_OK != uRet)

      return;     // user canceled dialog

   // this may take a while, put up hourglass cursor

   hPrevCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));

   fDisplayAsIcon = (io.dwFlags & IOF_CHECKDISPLAYASICON ? TRUE : FALSE);

   // make up a storage name for the OLE object

   ContainerDoc_GetNextStgName(lpContainerDoc, szStgName, CWCSTORAGENAME);

   /* default the new line to have the same indent as previous line */

   lpLine = LineList_GetLine(lpLL, nIndex);

   if (lpLine)

      nTab = Line_GetTabLevel(lpLine);

   hDC = LineList_GetDC(lpLL);

   if ((io.dwFlags & IOF_SELECTCREATENEW))

      dwOleCreateType = IOF_SELECTCREATENEW;

   else if ((io.dwFlags & IOF_CHECKLINK))

      dwOleCreateType = IOF_CHECKLINK;

   else

      dwOleCreateType = IOF_SELECTCREATEFROMFILE;

   lpContainerLine = ContainerLine_Create(

         dwOleCreateType,

         hDC,

         nTab,

         lpContainerDoc,

         &io.clsid,

         (LPOLESTR)szFile,

         fDisplayAsIcon,

         io.hMetaPict,

         szStgName

   );

   if (!lpContainerLine)

      goto error;         // creation of OLE object FAILED

   if (io.hMetaPict) {

      OleUIMetafilePictIconFree(io.hMetaPict);    // clean up metafile

   }

   /* add a ContainerLine object to the document's LineList. The

   **    ContainerLine manages the rectangle on the screen occupied by

   **    the OLE object.

   */

   LineList_AddLine(lpLL, (LPLINE)lpContainerLine, nIndex);

   /* before calling DoVerb(OLEIVERB_SHOW), check to see if the object

   **    has any initial extents.

   */

   ContainerLine_UpdateExtent(lpContainerLine, NULL);

   /* If a new embedded object was created, tell the object server to

   **    make itself visible (show itself).

   **    OLE2NOTE: the standard OLE 2 User Model is to only call

   **    IOleObject::DoVerb(OLEIVERB_SHOW...) if a new object is

   **    created. specifically, it should NOT be calld if the object

   **    is created from file or link to file.

   */

   if (dwOleCreateType == IOF_SELECTCREATENEW) {

      if (! ContainerLine_DoVerb(

            lpContainerLine, OLEIVERB_SHOW, NULL, TRUE, TRUE)) {

         OutlineApp_ErrorMessage(g_lpApp, ErrMsgShowObj);

      }

      /* OLE2NOTE: we will immediately force a save of the object

      **    to guarantee that a valid initial object is saved

      **    with our document. if the object is a OLE 1.0 object,

      **    then it may exit without update. by forcing this

      **    initial save we consistently always have a valid

      **    object even if it is a OLE 1.0 object that exited

      **    without saving. if we did NOT do this save here, then

      **    we would have to worry about deleting the object if

      **    it was a OLE 1.0 object that closed without saving.

      **    the OLE 2.0 User Model dictates that the object

      **    should always be valid after CreateNew performed. the

      **    user must explicitly delete it.

      */

      ContainerLine_SaveOleObjectToStg(

            lpContainerLine,

            lpContainerLine->m_lpStg,

            lpContainerLine->m_lpStg,

            TRUE    /* fRemember */

      );

   }

#if defined( INPLACE_CNTR )

   else if (dwOleCreateType == IOF_SELECTCREATEFROMFILE) {

      /* OLE2NOTE: an inside-out container should check if the object

      **    created from file is an inside-out and prefers to be

      **    activated when visible type of object. if so, the object

      **    should be immediately activated in-place, BUT NOT UIActived.

      */

      if (g_fInsideOutContainer &&

            lpContainerLine->m_dwDrawAspect == DVASPECT_CONTENT &&

            lpContainerLine->m_fInsideOutObj ) {

         HWND hWndDoc = OutlineDoc_GetWindow((LPOUTLINEDOC)lpContainerDoc);

         ContainerLine_DoVerb(

               lpContainerLine,OLEIVERB_INPLACEACTIVATE,NULL,FALSE,FALSE);

         /* OLE2NOTE: following this DoVerb(INPLACEACTIVATE) the

         **    object may have taken focus. but because the

         **    object is NOT UIActive it should NOT have focus.

         **    we will make sure our document has focus.

         */

         SetFocus(hWndDoc);

      }

   }

#endif  // INPLACE_CNTR

   OutlineDoc_SetModified((LPOUTLINEDOC)lpContainerDoc, TRUE, TRUE, TRUE);

   LineList_ReleaseDC(lpLL, hDC);

   SetCursor(hPrevCursor);     // restore original cursor

   return;

error:

   // NOTE: if ContainerLine_Create failed

   LineList_ReleaseDC(lpLL, hDC);

   if (OLEUI_OK == uRet && io.hMetaPict)

      OleUIMetafilePictIconFree(io.hMetaPict);    // clean up metafile

   SetCursor(hPrevCursor);     // restore original cursor

   OutlineApp_ErrorMessage(g_lpApp, ErrMsgInsertObj);

}

void ContainerDoc_EditLinksCommand(LPCONTAINERDOC lpContainerDoc)

{

   UINT        uRet;

   OLEUIEDITLINKS      el;

   LPCONTAINERLINE lpContainerLine = NULL;

   LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;

   _fmemset((LPOLEUIEDITLINKS)&el,0,sizeof(OLEUIEDITLINKS));

   el.cbStruct=sizeof(OLEUIEDITLINKS);

   el.dwFlags=ELF_SHOWHELP;

   el.hWndOwner=((LPOUTLINEDOC)lpContainerDoc)->m_hWndDoc;

   el.lpOleUILinkContainer =

         (LPOLEUILINKCONTAINER)&lpContainerDoc->m_OleUILinkContainer;

#if defined( OLE_VERSION )

   OleApp_PreModalDialog((LPOLEAPP)g_lpApp, (LPOLEDOC)lpContainerDoc);

#endif

   OLEDBG_BEGIN3("OleUIEditLinks called\r\n")

   uRet=OleUIEditLinks((LPOLEUIEDITLINKS)&el);

   OLEDBG_END3

#if defined( OLE_VERSION )

   OleApp_PostModalDialog((LPOLEAPP)g_lpApp, (LPOLEDOC)lpContainerDoc);

#endif

   OleDbgAssert((uRet==1) || (uRet==OLEUI_CANCEL));

}

/* Convert command - brings up the "Convert" dialog

 */

void ContainerDoc_ConvertCommand(

      LPCONTAINERDOC      lpContainerDoc,

      BOOL                fServerNotRegistered

)

{

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerDoc;

   OLEUICONVERT ct;

   UINT         uRet;

   LPDATAOBJECT  lpDataObj;

   LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;

   LPCONTAINERLINE lpContainerLine = NULL;

   BOOL         fSelIsOleObject;

   int          nIndex;

   STGMEDIUM    medium;

   LPOLESTR     lpErrMsg = NULL;

   HRESULT      hrErr;

   HCURSOR      hPrevCursor;

   BOOL         fMustRun = FALSE;

   BOOL         fMustClose = FALSE;

   BOOL         fObjConverted = FALSE;

   BOOL         fDisplayChanged = FALSE;

   BOOL         fHaveCLSID = FALSE;

   BOOL         fHaveFmtUserType = FALSE;

   OLECHAR      szUserType[128];

   BOOL         fMustActivate;

   /* OLE2NOTE: if we came to the Convert dialog because the user

   **    activated a non-registered object, then we should activate

   **    the object after the user has converted it or setup an

   **    ActivateAs server.

   */

   fMustActivate = fServerNotRegistered;

   _fmemset((LPOLEUICONVERT)&ct,0,sizeof(OLEUICONVERT));

   fSelIsOleObject = ContainerDoc_IsSelAnOleObject(

         (LPCONTAINERDOC)lpContainerDoc,

         &IID_IDataObject,

         (LPUNKNOWN FAR*)&lpDataObj,

         &nIndex,

         (LPCONTAINERLINE FAR*)&lpContainerLine

   );

   lpErrMsg = ErrMsgCantConvert;

   if (! fSelIsOleObject)

      goto error;     // can NOT do Convert.

   if (! lpContainerLine) {

      OleStdRelease((LPUNKNOWN)lpDataObj);

      goto error;     // can NOT do Convert.

   }

   ct.cbStruct  = sizeof(OLEUICONVERT);

   ct.dwFlags   = CF_SHOWHELPBUTTON;

   ct.hWndOwner = lpContainerDoc->m_OleDoc.m_OutlineDoc.m_hWndDoc;

   ct.lpszCaption = (LPOLESTR)NULL;

   ct.lpfnHook  = NULL;

   ct.lCustData = 0;

   ct.hInstance = NULL;

   ct.lpszTemplate = NULL;

   ct.hResource = 0;

   ct.fIsLinkedObject = ContainerLine_IsOleLink(lpContainerLine);

   ct.dvAspect = lpContainerLine->m_dwDrawAspect;

   ct.cClsidExclude = 0;

   ct.lpClsidExclude = NULL;

   if (! ct.fIsLinkedObject || !lpContainerLine->m_lpOleLink) {

      /* OLE2NOTE: the object is an embedded object. we should first

      **    attempt to read the actual object CLSID, file data

      **    format, and full user type name that is written inside of

      **    the object's storage as this should be the most

      **    definitive information. if this fails we will ask the

      **    object what its class is and attempt to get the rest of

      **    the information out of the REGDB.

      */

      hrErr=ReadClassStg(lpContainerLine->m_lpStg,(CLSID FAR*)&(ct.clsid));

      if (hrErr == NOERROR)

         fHaveCLSID = TRUE;

      else {

         OleDbgOutHResult("ReadClassStg returned", hrErr);

      }

      hrErr = ReadFmtUserTypeStg(

            lpContainerLine->m_lpStg,

            (CLIPFORMAT FAR*)&ct.wFormat,

            (LPOLESTR FAR*)&ct.lpszUserType);

      if (hrErr == NOERROR)

         fHaveFmtUserType = TRUE;

      else {

         OleDbgOutHResult("ReadFmtUserTypeStg returned", hrErr);

      }

   } else {

      /* OLE2NOTE: the object is a linked object. we should give the

      **    DisplayName of the link source as the default icon label.

      */

      OLEDBG_BEGIN2("IOleLink::GetSourceDisplayName called\r\n")

      hrErr = lpContainerLine->m_lpOleLink->lpVtbl->GetSourceDisplayName(

            lpContainerLine->m_lpOleLink, &ct.lpszDefLabel);

      OLEDBG_END2

   }

   if (! fHaveCLSID) {

      hrErr = lpContainerLine->m_lpOleObj->lpVtbl->GetUserClassID(

            lpContainerLine->m_lpOleObj,

            (CLSID FAR*)&ct.clsid

      );

      if (hrErr != NOERROR)

         ct.clsid = CLSID_NULL;

   }

   if (! fHaveFmtUserType) {

      ct.wFormat = 0;

      if (OleStdGetUserTypeOfClass(

            (CLSID FAR*)&ct.clsid,szUserType,128,NULL)) {

         ct.lpszUserType = OleStdCopyString(szUserType, NULL);

      } else {

         ct.lpszUserType = NULL;

      }

   }

   if (lpContainerLine->m_dwDrawAspect == DVASPECT_ICON) {

      ct.hMetaPict = OleStdGetData(

            lpDataObj,

            CF_METAFILEPICT,

            NULL,

            DVASPECT_ICON,

            (LPSTGMEDIUM)&medium

      );

   } else {

      ct.hMetaPict = NULL;

   }

   OleStdRelease((LPUNKNOWN)lpDataObj);

#if defined( OLE_VERSION )

   OleApp_PreModalDialog((LPOLEAPP)g_lpApp, (LPOLEDOC)lpContainerDoc);

#endif

   OLEDBG_BEGIN3("OleUIConvert called\r\n")

   uRet = OleUIConvert(&ct);

   OLEDBG_END3

#if defined( OLE_VERSION )

   OleApp_PostModalDialog((LPOLEAPP)g_lpApp, (LPOLEDOC)lpContainerDoc);

#endif

   // this may take a while, put up hourglass cursor

   hPrevCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));

   if (uRet == OLEUI_OK) {

      /*****************************************************************

      **  OLE2NOTE: the convert dialog actually allows the user to

      **    change two orthogonal properties of the object: the

      **    object's type/server and the object's display aspect.

      **    first we will execute the ConvertTo/ActivateAs action and

      **    then we will deal with any display aspect change. we want

      **    to be careful to only call IOleObject::Update once

      **    because this is an expensive operation; it results in

      **    launching the object's server.

      *****************************************************************/

      if (ct.dwFlags & CF_SELECTCONVERTTO &&

            ! IsEqualCLSID(&ct.clsid, &ct.clsidNew)) {

         /* user selected CONVERT.

         **

         ** OLE2NOTE: to achieve the "Convert To" at this point we

         **    need to take the following steps:

         **    1. unload the object.

         **    2. write the NEW CLSID and NEW user type name

         **       string into the storage of the object,

         **       BUT write the OLD format tag.

         **    3. force an update to force the actual conversion of

         **       the data bits.

         */

         lpErrMsg = ErrMsgConvertObj; // setup correct msg in case of error

         ContainerLine_UnloadOleObject(lpContainerLine, OLECLOSE_SAVEIFDIRTY);

         OLEDBG_BEGIN2("OleStdDoConvert called \r\n")

         hrErr = OleStdDoConvert(

               lpContainerLine->m_lpStg, (REFCLSID)&ct.clsidNew);

         OLEDBG_END2

         if (hrErr != NOERROR)

            goto error;

         // Reload the object

         ContainerLine_LoadOleObject(lpContainerLine);

         /* we need to force the object to run to complete the

         **    conversion. set flag to force OleRun to be called at

         **    end of function.

         */

         fMustRun = TRUE;

         fObjConverted = TRUE;

      } else if (ct.dwFlags & CF_SELECTACTIVATEAS) {

         /* user selected ACTIVATE AS.

         **

         ** OLE2NOTE: to achieve the "Activate As" at this point we

         **    need to take the following steps:

         **    1. unload ALL objects of the OLD class that app knows about

         **    2. add the TreatAs tag in the registration database

         **    by calling CoTreatAsClass().

         **    3. lazily it can reload the objects; when the objects

         **    are reloaded the TreatAs will take effect.

         */

         lpErrMsg = ErrMsgActivateAsObj; // setup msg in case of error

         ContainerDoc_UnloadAllOleObjectsOfClass(

               lpContainerDoc,

               (REFCLSID)&ct.clsid,

               OLECLOSE_SAVEIFDIRTY

         );

         OLEDBG_BEGIN2("OleStdDoTreatAsClass called \r\n")

         hrErr = OleStdDoTreatAsClass(ct.lpszUserType, (REFCLSID)&ct.clsid,

               (REFCLSID)&ct.clsidNew);

         OLEDBG_END2

         // Reload the object

         ContainerLine_LoadOleObject(lpContainerLine);

         fMustActivate = TRUE;   // we should activate this object

      }

      /*****************************************************************

      **  OLE2NOTE: now we will try to change the display if

      **    necessary.

      *****************************************************************/

      if (lpContainerLine->m_lpOleObj &&

            ct.dvAspect != lpContainerLine->m_dwDrawAspect) {

         /* user has selected to change display aspect between icon

         **    aspect and content aspect.

         **

         ** OLE2NOTE: if we got here because the server was not

         **    registered, then we will NOT delete the object's

         **    original display aspect. because we do not have the

         **    original server, we can NEVER get it back. this is a

         **    safety precaution.

         */

         hrErr = OleStdSwitchDisplayAspect(

               lpContainerLine->m_lpOleObj,

               &lpContainerLine->m_dwDrawAspect,

               ct.dvAspect,

               ct.hMetaPict,

               !fServerNotRegistered,   /* fDeleteOldAspect */

               TRUE,                    /* fSetupViewAdvise */

               (LPADVISESINK)&lpContainerLine->m_AdviseSink,

               (BOOL FAR*)&fMustRun

         );

         if (hrErr == NOERROR)

            fDisplayChanged = TRUE;

#if defined( INPLACE_CNTR )

            ContainerDoc_UpdateInPlaceObjectRects(

                  lpContainerLine->m_lpDoc, nIndex);

#endif

      } else if (ct.dvAspect == DVASPECT_ICON && ct.fObjectsIconChanged) {

         hrErr = OleStdSetIconInCache(

               lpContainerLine->m_lpOleObj,

               ct.hMetaPict

         );

         if (hrErr == NOERROR)

            fDisplayChanged = TRUE;

      }

      /* we deliberately run the object so that the update won't shut

      ** the server down.

      */

      if (fMustActivate || fMustRun) {

         /* if we force the object to run, then shut it down after

         **    the update. do NOT force the object to close if we

         **    want to activate the object or if the object was

         **    already running.

         */

         if (!fMustActivate && !OleIsRunning(lpContainerLine->m_lpOleObj))

            fMustClose = TRUE;  // shutdown after update

         hrErr = ContainerLine_RunOleObject(lpContainerLine);

         if (fObjConverted &&

            FAILED(hrErr) && GetScode(hrErr)!=OLE_E_STATIC) {

            // ERROR: convert of the object failed.

            // revert the storage to restore the original link.

            // (OLE2NOTE: static object always return OLE_E_STATIC

            //        when told to run; this is NOT an error here.

            //        the OLE2 libraries have built in handlers for

            //        the static objects that do the conversion.

            ContainerLine_UnloadOleObject(

                  lpContainerLine, OLECLOSE_NOSAVE);

            lpContainerLine->m_lpStg->lpVtbl->Revert(

                  lpContainerLine->m_lpStg);

            goto error;

         } else if (fObjConverted) {

            FORMATETC  FmtEtc;

            DWORD      dwNewConnection;

            LPOLECACHE lpOleCache = (LPOLECACHE)OleStdQueryInterface

                 ((LPUNKNOWN)lpContainerLine->m_lpOleObj,&IID_IOleCache);

            /* OLE2NOTE: we need to force the converted object to

            **    setup a new OLERENDER_DRAW cache. it is possible

            **    that the new object needs to cache different data

            **    in order to support drawing than the old object.

            */

            if (lpOleCache &&

                  lpContainerLine->m_dwDrawAspect == DVASPECT_CONTENT) {

               FmtEtc.cfFormat = 0; //NULL; // whatever is needed for Draw

               FmtEtc.ptd      = NULL;

               FmtEtc.dwAspect = DVASPECT_CONTENT;

               FmtEtc.lindex   = -1;

               FmtEtc.tymed    = TYMED_NULL;

               OLEDBG_BEGIN2("IOleCache::Cache called\r\n")

               hrErr = lpOleCache->lpVtbl->Cache(

                     lpOleCache,

                     (LPFORMATETC)&FmtEtc,

                     ADVF_PRIMEFIRST,

                     (LPDWORD)&dwNewConnection

               );

               OLEDBG_END2

#if defined( _DEBUG )

               if (! SUCCEEDED(hrErr))

                  OleDbgOutHResult("IOleCache::Cache returned", hrErr);

#endif

               OleStdRelease((LPUNKNOWN)lpOleCache);

            }

            // Close and force object to save; this will commit the stg

            ContainerLine_CloseOleObject(

               lpContainerLine, OLECLOSE_SAVEIFDIRTY);

            fMustClose = FALSE;     // we already closed the object

         }

         if (fMustClose)

            ContainerLine_CloseOleObject(lpContainerLine,OLECLOSE_NOSAVE);

      }

      if (fDisplayChanged) {

         /* the Object's display was changed, force a repaint of

         **    the line. note the extents of the object may have

         **    changed.

         */

         ContainerLine_UpdateExtent(lpContainerLine, NULL);

         LineList_ForceLineRedraw(lpLL, nIndex, TRUE);

      }

      if (fDisplayChanged || fObjConverted) {

         /* mark ContainerDoc as now dirty. if display changed, then

         **    the extents of the object may have changed.

         */

         OutlineDoc_SetModified(lpOutlineDoc, TRUE, TRUE, fDisplayChanged);

      }

      if (fMustActivate) {

         ContainerLine_DoVerb(

               lpContainerLine, OLEIVERB_PRIMARY, NULL, FALSE,FALSE);

      }

   }

   if (ct.lpszUserType)

      OleStdFreeString(ct.lpszUserType, NULL);

   if (ct.lpszDefLabel)

      OleStdFreeString(ct.lpszDefLabel, NULL);

   if (ct.hMetaPict)

      OleUIMetafilePictIconFree(ct.hMetaPict);    // clean up metafile

   SetCursor(hPrevCursor);     // restore original cursor

   return;

error:

   if (ct.lpszUserType)

      OleStdFreeString(ct.lpszUserType, NULL);

   if (ct.hMetaPict)

      OleUIMetafilePictIconFree(ct.hMetaPict);    // clean up metafile

   SetCursor(hPrevCursor);     // restore original cursor

   if (lpErrMsg)

      OutlineApp_ErrorMessage(g_lpApp, lpErrMsg);

}

/* ContainerDoc_CloseAllOleObjects

** -------------------------------

**    Close all OLE objects. This forces all OLE objects to transition

**    from the running state to the loaded state.

**

**    Returns TRUE if all objects closed successfully

**            FALSE if any object could not be closed.

*/

BOOL ContainerDoc_CloseAllOleObjects(

      LPCONTAINERDOC          lpContainerDoc,

      DWORD                   dwSaveOption

)

{

   LPLINELIST  lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;

   int         i;

   LPLINE      lpLine;

   BOOL        fStatus = TRUE;

   for (i = 0; i < lpLL->m_nNumLines; i++) {

      lpLine=LineList_GetLine(lpLL, i);

      if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE))

         if (! ContainerLine_CloseOleObject(

                              (LPCONTAINERLINE)lpLine,dwSaveOption))

            fStatus = FALSE;

   }

   return fStatus;

}

/* ContainerDoc_UnloadAllOleObjectsOfClass

** ---------------------------------------

**    Unload all OLE objects of a particular class. this is necessary

**    when a class level "ActivateAs" (aka. TreatAs) is setup. the user

**    can do this with the Convert dialog. for the TreatAs to take

**    effect, all objects of the class have to loaded and reloaded.

*/

void ContainerDoc_UnloadAllOleObjectsOfClass(

      LPCONTAINERDOC      lpContainerDoc,

      REFCLSID            rClsid,

      DWORD               dwSaveOption

)

{

   LPLINELIST  lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;

   int         i;

   LPLINE      lpLine;

   CLSID       clsid;

   HRESULT     hrErr;

   for (i = 0; i < lpLL->m_nNumLines; i++) {

      lpLine=LineList_GetLine(lpLL, i);

      if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE)) {

         LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)lpLine;

         if (! lpContainerLine->m_lpOleObj)

            continue;       // this object is NOT loaded

         hrErr = lpContainerLine->m_lpOleObj->lpVtbl->GetUserClassID(

               lpContainerLine->m_lpOleObj,

               (CLSID FAR*)&clsid

         );

         if (hrErr == NOERROR &&

               ( IsEqualCLSID((CLSID FAR*)&clsid,rClsid)

                 || IsEqualCLSID(rClsid,&CLSID_NULL) ) ) {

            ContainerLine_UnloadOleObject(lpContainerLine, dwSaveOption);

         }

      }

   }

}

/* ContainerDoc_UpdateExtentOfAllOleObjects

** ----------------------------------------

**    Update the extents of any OLE object that is marked that its size

**    may  have changed. when an IAdviseSink::OnViewChange notification

**    is received, the corresponding ContainerLine is marked

**    (m_fDoGetExtent==TRUE) and a message (WM_U_UPDATEOBJECTEXTENT) is

**    posted to the document indicating that there are dirty objects.

**    when this message is received, this function is called.

*/

void ContainerDoc_UpdateExtentOfAllOleObjects(LPCONTAINERDOC lpContainerDoc)

{

   LPLINELIST  lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;

   int         i;

   LPLINE      lpLine;

   BOOL        fStatus = TRUE;

#if defined( INPLACE_CNTR )

   int         nFirstUpdate = -1;

#endif

   for (i = 0; i < lpLL->m_nNumLines; i++) {

      lpLine=LineList_GetLine(lpLL, i);

      if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE)) {

         LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)lpLine;

         if (lpContainerLine->m_fDoGetExtent) {

            ContainerLine_UpdateExtent(lpContainerLine, NULL);

#if defined( INPLACE_CNTR )

            if (nFirstUpdate == -1)

               nFirstUpdate = i;

#endif

         }

      }

   }

#if defined( INPLACE_CNTR )

   /* OLE2NOTE: after changing the extents of any line, we need to

   **    update the PosRect of the In-Place active

   **    objects (if any) that follow the first modified line.

   */

   if (nFirstUpdate != -1)

      ContainerDoc_UpdateInPlaceObjectRects(lpContainerDoc, nFirstUpdate+1);

#endif

}

BOOL ContainerDoc_SaveToFile(

      LPCONTAINERDOC          lpContainerDoc,

      LPCOLESTR               lpszFileName,

      UINT                    uFormat,

      BOOL                    fRemember

)

{

   LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp;

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerDoc;

   LPOLEDOC lpOleDoc = (LPOLEDOC)lpContainerDoc;

   LPSTORAGE lpDestStg;

   BOOL fStatus;

   BOOL fMustRelDestStg = FALSE;

   HRESULT hrErr;

#if defined( OPTIONAL )

   FILETIME filetimeBeforeSave;

#endif

   if (fRemember) {

      if (lpszFileName) {

         fStatus = OutlineDoc_SetFileName(

               lpOutlineDoc, (LPOLESTR)lpszFileName, NULL);

         if (! fStatus) goto error;

      }

      /* The ContainerDoc keeps its storage open at all times. it is not

      **    necessary to reopen the file.

      ** if SaveAs is pending, then lpNewStg is the new destination for

      **    the save operation, else the existing storage is the dest.

      */

      lpDestStg = (lpContainerDoc->m_lpNewStg ?

                  lpContainerDoc->m_lpNewStg : lpOleDoc->m_lpStg);

#if defined( OPTIONAL )

      /* OLE2NOTE: an automatic link to an embedded object within the

      **    same container document (that uses ItemMonikers) will

      **    always be considered "out-of-date' by OLE. if a container

      **    application REALLY wants to fix this it can do one of the

      **    following:

      **      1. implement a new moniker better than ItemMonikers

      **    that look into the objects storage to find the real last

      **    change time (rather then defaulting to that of the outer

      **    container file).

      ** or   2. using item monikers it is possible to fix the case

      **    where the container document is saved while the embedded

      **    object is running but it will NOT fix the case when the

      **    document is saved when the embedded object was only

      **    loaded. the fix is to:

      **      a. remember the time (T) before the save operation starts

      **      b. call IRunningObjectTable::NoteChangeTime(lpDoc, T)

      **      c. do the saving and commit the file

      **      d. call StgSetTimes to reset the file time to T

      **      e. remember time T in document structure and when the

      **         root storage is finally released reset the file time

      **         again to T (closing the file on DOS sets the time).

      */

      CoFileTimeNow( &filetimeBeforeSave );

      if (lpOleDoc->m_dwRegROT != 0) {

         LPRUNNINGOBJECTTABLE lprot;

         if (GetRunningObjectTable(0,&lprot) == NOERROR)

         {

            OleDbgOut2("IRunningObjectTable::NoteChangeTime called\r\n");

            lprot->lpVtbl->NoteChangeTime(

                  lprot, lpOleDoc->m_dwRegROT, &filetimeBeforeSave );

            lprot->lpVtbl->Release(lprot);

         }

      }

#endif

   } else {

      if (! lpszFileName)

         goto error;

      /* OLE2NOTE: since we are preforming a SaveCopyAs operation, we

      **    do not need to have the DocFile open in STGM_TRANSACTED mode.

      **    there is less overhead to use STGM_DIRECT mode.

      */

      hrErr = StgCreateDocfile(

            lpszFileName,

            STGM_READWRITE|STGM_DIRECT|STGM_SHARE_EXCLUSIVE|STGM_CREATE,

            0,

            &lpDestStg

      );

      OleDbgAssertSz(hrErr == NOERROR, "Could not create Docfile");

      if (hrErr != NOERROR) {

            OleDbgOutHResult("StgCreateDocfile returned", hrErr);

         goto error;

        }

      fMustRelDestStg = TRUE;

   }

   /*  OLE2NOTE: we must be sure to write our class ID into our

   **    storage. this information is used by OLE to determine the

   **    class of the data stored in our storage. Even for top

   **    "file-level" objects this information should be written to

   **    the file.

   */

   hrErr = WriteClassStg(lpDestStg, &CLSID_APP);

   if(hrErr != NOERROR) goto error;

   fStatus = OutlineDoc_SaveSelToStg(

         lpOutlineDoc,

         NULL,           // save all lines

         uFormat,

         lpDestStg,

         FALSE,          // fSameAsLoad

         TRUE            // remember this stg

      );

   if (fStatus)

      fStatus = OleStdCommitStorage(lpDestStg);

   if (fRemember) {

      /* if SaveAs was pending, then release the old storage and remember

      **    the new storage as the active current storage. all data from

      **    the old storage has been copied into the new storage.

      */

      if (lpContainerDoc->m_lpNewStg) {

         OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpStg);  // free old stg

         lpOleDoc->m_lpStg = lpContainerDoc->m_lpNewStg;   // save new stg

         lpContainerDoc->m_lpNewStg = NULL;

      }

      if (! fStatus) goto error;

      OutlineDoc_SetModified(lpOutlineDoc, FALSE, FALSE, FALSE);

#if defined( OPTIONAL )

      /* reset time of file on disk to be time just prior to saving.

      ** NOTE: it would also be necessary to remember

      **    filetimeBeforeSave in the document structure and when the

      **    root storage is finally released reset the file time

      **    again to this value (closing the file on DOS sets the time).

      */

      StgSetTimes(

            lpOutlineDoc->m_szFileName, NULL, NULL, &filetimeBeforeSave);

#endif

   }

   if (fMustRelDestStg)

      OleStdRelease((LPUNKNOWN)lpDestStg);

   return TRUE;

error:

   if (fMustRelDestStg)

      OleStdRelease((LPUNKNOWN)lpDestStg);

   OutlineApp_ErrorMessage(g_lpApp, ErrMsgSaving);

   return FALSE;

}

/* ContainerDoc_ContainerLineDoVerbCommand

** ---------------------------------------

**    Execute a verb of the OLE object in the current focus line.

*/

void ContainerDoc_ContainerLineDoVerbCommand(

      LPCONTAINERDOC          lpContainerDoc,

      LONG                    iVerb

)

{

   LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;

   int nIndex = LineList_GetFocusLineIndex(lpLL);

   LPLINE lpLine = LineList_GetLine(lpLL, nIndex);

   HCURSOR                 hPrevCursor;

   if (! lpLine || (Line_GetLineType(lpLine) != CONTAINERLINETYPE) ) return;

   // this may take a while, put up hourglass cursor

   hPrevCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));

   ContainerLine_DoVerb((LPCONTAINERLINE) lpLine, iVerb, NULL, TRUE, TRUE);

   SetCursor(hPrevCursor);     // restore original cursor

}

/* ContainerDoc_GetNextStgName

** ---------------------------

**    Generate the next unused name for a sub-storage to be used by an

**    OLE object. The ContainerDoc keeps a counter. The storages for

**    OLE objects are simply numbered (eg. Obj 0, Obj 1). A "long"

**    integer worth of storage names should be more than enough than we

**    will ever need.

**

**    NOTE: when an OLE object is transfered via drag/drop or the

**    clipboard, we attempt to keep the currently assigned name for the

**    object (if not currently in use). thus it is possible that an

**    object with a the next default name (eg. "Obj 5") already exists

**    in the current document if an object with this name was privously

**    transfered (pasted or dropped). we therefore loop until we find

**    the next lowest unused name.

*/

void ContainerDoc_GetNextStgName(

      LPCONTAINERDOC          lpContainerDoc,

      LPOLESTR                lpszStgName,

      int                     nLen

)

{

   char szAnsiStgName[256];

   wsprintf(szAnsiStgName, "%s %ld",

         (LPSTR)DEFOBJNAMEPREFIX,

         ++(lpContainerDoc->m_nNextObjNo)

   );

   while (ContainerDoc_IsStgNameUsed(lpContainerDoc, lpszStgName) == TRUE) {

      wsprintf(szAnsiStgName, "%s %ld",

            (LPSTR)DEFOBJNAMEPREFIX,

            ++(lpContainerDoc->m_nNextObjNo)

      );

   }

   A2W (szAnsiStgName, lpszStgName, nLen);

}

/* ContainerDoc_IsStgNameUsed

** --------------------------

**    Check if a given StgName is already in use.

*/

BOOL ContainerDoc_IsStgNameUsed(

      LPCONTAINERDOC          lpContainerDoc,

      LPOLESTR                lpszStgName

)

{

   LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;

   int i;

   LPLINE lpLine;

   for (i = 0; i < lpLL->m_nNumLines; i++) {

      lpLine=LineList_GetLine(lpLL, i);

      if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE)) {

         if (OLESTRCMP(lpszStgName,

               ((LPCONTAINERLINE)lpLine)->m_szStgName) == 0) {

            return TRUE;    // Match FOUND!

         }

      }

   }

   return FALSE;   // if we get here, then NO match was found.

}

LPSTORAGE ContainerDoc_GetStg(LPCONTAINERDOC lpContainerDoc)

{

   return ((LPOLEDOC)lpContainerDoc)->m_lpStg;

}

/* ContainerDoc_GetSingleOleObject

** -------------------------------

**    If the entire document contains a single OLE object, then

**    return the desired interface of the object.

**

**    Returns NULL if there is are multiple lines in the document or

**    the single line is not a ContainerLine.

*/

LPUNKNOWN ContainerDoc_GetSingleOleObject(

      LPCONTAINERDOC          lpContainerDoc,

      REFIID                  riid,

      LPCONTAINERLINE FAR*    lplpContainerLine

)

{

   LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;

   LPLINE lpLine;

   LPUNKNOWN lpObj = NULL;

   if (lplpContainerLine)

      *lplpContainerLine = NULL;

   if (lpLL->m_nNumLines != 1)

   {

      return NULL;    // doc does NOT contain a single line

   }

   lpLine=LineList_GetLine(lpLL, 0);

   if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE))

      lpObj = ContainerLine_GetOleObject((LPCONTAINERLINE)lpLine, riid);

   if (lplpContainerLine)

      *lplpContainerLine = (LPCONTAINERLINE)lpLine;

   return lpObj;

}

/* ContainerDoc_IsSelAnOleObject

** -----------------------------

**    Check if the selection is a single selection of an OLE object.

**    if so, then optionally return the desired interface of the object

**    and/or index of the ContainerLine containing the OLE object.

**

**    Returns FALSE if there is a multiple selection or the single

**    selection is not a ContainerLine.

*/

BOOL ContainerDoc_IsSelAnOleObject(

      LPCONTAINERDOC          lpContainerDoc,

      REFIID                  riid,

      LPUNKNOWN FAR*          lplpvObj,

      int FAR*                lpnIndex,

      LPCONTAINERLINE FAR*    lplpContainerLine

)

{

   LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;

   LINERANGE lrSel;

   int nNumSel;

   LPLINE lpLine;

   if (lplpvObj) *lplpvObj = NULL;

   if (lpnIndex) *lpnIndex = -1;

   if (lplpContainerLine) *lplpContainerLine = NULL;

   nNumSel = LineList_GetSel(lpLL, (LPLINERANGE)&lrSel);

   if (nNumSel != 1)

   {

      return FALSE;   // selection is not a single line

   }

   lpLine = LineList_GetLine(lpLL, lrSel.m_nStartLine);

   if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE)) {

      if (lpnIndex)

         *lpnIndex = lrSel.m_nStartLine;

      if (lplpContainerLine)

         *lplpContainerLine = (LPCONTAINERLINE)lpLine;

      if (riid) {

         *lplpvObj = ContainerLine_GetOleObject(

               (LPCONTAINERLINE)lpLine,

               riid

         );

      }

      return (*lplpvObj ? TRUE : FALSE);

   }

   return FALSE;

}

/*************************************************************************

** ContainerDoc::IOleUILinkContainer interface implementation

*************************************************************************/

STDMETHODIMP CntrDoc_LinkCont_QueryInterface(

      LPOLEUILINKCONTAINER    lpThis,

      REFIID                  riid,

      LPVOID FAR*             lplpvObj

)

{

   LPOLEDOC lpOleDoc = (LPOLEDOC)

         ((struct CDocOleUILinkContainerImpl FAR*)lpThis)->lpContainerDoc;

   return OleDoc_QueryInterface(lpOleDoc, riid, lplpvObj);

}

STDMETHODIMP_(ULONG) CntrDoc_LinkCont_AddRef(LPOLEUILINKCONTAINER lpThis)

{

   LPOLEDOC lpOleDoc = (LPOLEDOC)

         ((struct CDocOleUILinkContainerImpl FAR*)lpThis)->lpContainerDoc;

   OleDbgAddRefMethod(lpThis, OLESTR("IOleUILinkContainer"));

   return OleDoc_AddRef(lpOleDoc);

}

STDMETHODIMP_(ULONG) CntrDoc_LinkCont_Release(LPOLEUILINKCONTAINER lpThis)

{

   LPOLEDOC lpOleDoc = (LPOLEDOC)

         ((struct CDocOleUILinkContainerImpl FAR*)lpThis)->lpContainerDoc;

   OleDbgReleaseMethod(lpThis, "IOleUILinkContainer");

   return OleDoc_Release(lpOleDoc);

}

STDMETHODIMP_(DWORD) CntrDoc_LinkCont_GetNextLink(

      LPOLEUILINKCONTAINER    lpThis,

      DWORD                   dwLink

)

{

   LPCONTAINERDOC lpContainerDoc =

         ((struct CDocOleUILinkContainerImpl FAR*)lpThis)->lpContainerDoc;

   LPCONTAINERLINE lpContainerLine = NULL;

    // artificial AddRef in case object is released

    // during this call

    CntrDoc_LinkCont_AddRef(lpThis);

   OLEDBG_BEGIN2("CntrDoc_LinkCont_GetNextLink\r\n")

   lpContainerLine = ContainerDoc_GetNextLink(

         lpContainerDoc,

         (LPCONTAINERLINE)dwLink

   );

   OLEDBG_END2

   // release artificial AddRef

   CntrDoc_LinkCont_Release(lpThis);

   return (DWORD)lpContainerLine;

}

STDMETHODIMP CntrDoc_LinkCont_SetLinkUpdateOptions(

      LPOLEUILINKCONTAINER    lpThis,

      DWORD                   dwLink,

      DWORD                   dwUpdateOpt

)

{

   LPCONTAINERDOC lpContainerDoc =

         ((struct CDocOleUILinkContainerImpl FAR*)lpThis)->lpContainerDoc;

   LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)dwLink;

   LPOLELINK lpOleLink = lpContainerLine->m_lpOleLink;

   SCODE sc = S_OK;

   HRESULT hrErr;

   // artificial AddRef in case object is released during call

   CntrDoc_LinkCont_AddRef(lpThis);

   OLEDBG_BEGIN2("CntrDoc_LinkCont_SetLinkUpdateOptions\r\n")

   OleDbgAssert(lpContainerLine);

   if (! lpOleLink) {

      sc = E_FAIL;

      goto error;

   }

   OLEDBG_BEGIN2("IOleLink::SetUpdateOptions called\r\n")

   hrErr = lpOleLink->lpVtbl->SetUpdateOptions(

         lpOleLink,

         dwUpdateOpt

   );

   OLEDBG_END2

   // save new link type update option

   lpContainerLine->m_dwLinkType = dwUpdateOpt;

   if (hrErr != NOERROR) {

      OleDbgOutHResult("IOleLink::SetUpdateOptions returned", hrErr);

      sc = GetScode(hrErr);

      goto error;

   }

error:

   // release artificial AddRef

   CntrDoc_LinkCont_Release(lpThis);

   OLEDBG_END2

   return ResultFromScode(sc);

}

STDMETHODIMP CntrDoc_LinkCont_GetLinkUpdateOptions(

      LPOLEUILINKCONTAINER    lpThis,

      DWORD                   dwLink,

      DWORD FAR*              lpdwUpdateOpt

)

{

   LPCONTAINERDOC lpContainerDoc =

         ((struct CDocOleUILinkContainerImpl FAR*)lpThis)->lpContainerDoc;

   LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)dwLink;

   LPOLELINK lpOleLink = lpContainerLine->m_lpOleLink;

   SCODE sc = S_OK;

   HRESULT hrErr;

   // artificial AddRef in case object is released during call

   CntrDoc_LinkCont_AddRef(lpThis);

   OLEDBG_BEGIN2("CntrDoc_LinkCont_GetLinkUpdateOptions\r\n")

   OleDbgAssert(lpContainerLine);

   if (! lpOleLink) {

      sc = E_FAIL;

      goto error;

   }

   OLEDBG_BEGIN2("IOleLink::GetUpdateOptions called\r\n")

   hrErr = lpOleLink->lpVtbl->GetUpdateOptions(

         lpOleLink,

         lpdwUpdateOpt

   );

   OLEDBG_END2

   // reset saved link type to ensure it is correct

   lpContainerLine->m_dwLinkType = *lpdwUpdateOpt;

   if (hrErr != NOERROR) {

      OleDbgOutHResult("IOleLink::GetUpdateOptions returned", hrErr);

      sc = GetScode(hrErr);

      goto error;

   }

error:

   OLEDBG_END2

   // release artificial AddRef

   CntrDoc_LinkCont_Release(lpThis);

   return ResultFromScode(sc);

}

STDMETHODIMP CntrDoc_LinkCont_SetLinkSource(

      LPOLEUILINKCONTAINER    lpThis,

      DWORD                   dwLink,

      LPOLESTR                lpszDisplayName,

      ULONG                   lenFileName,

      ULONG FAR*              lpchEaten,

      BOOL                    fValidateSource

)

{

   LPCONTAINERDOC lpContainerDoc =

         ((struct CDocOleUILinkContainerImpl FAR*)lpThis)->lpContainerDoc;

   LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)dwLink;

   SCODE       sc = S_OK;

   HRESULT     hrErr;

   LPOLELINK   lpOleLink = lpContainerLine->m_lpOleLink;

   LPBC        lpbc = NULL;

   LPMONIKER   lpmk = NULL;

   LPOLEOBJECT lpLinkSrcOleObj = NULL;

   CLSID       clsid = CLSID_NULL;

   CLSID       clsidOld = CLSID_NULL;

   // artificial AddRef in case object is released during call

   CntrDoc_LinkCont_AddRef(lpThis);

   OLEDBG_BEGIN2("CntrDoc_LinkCont_SetLinkSource\r\n")

   OleDbgAssert(lpContainerLine);

   lpContainerLine->m_fLinkUnavailable = TRUE;

   if (fValidateSource) {

      /* OLE2NOTE: validate the link source by parsing the string

      **    into a Moniker. if this is successful, then the string is

      **    valid.

      */

      hrErr = CreateBindCtx(0, (LPBC FAR*)&lpbc);

      if (hrErr != NOERROR) {

         sc = GetScode(hrErr);   // ERROR: OOM

         goto cleanup;

      }

      // Get class of orignial link source if it is available

      if (lpContainerLine->m_lpOleObj) {

         OLEDBG_BEGIN2("IOleObject::GetUserClassID called\r\n")

         hrErr = lpContainerLine->m_lpOleObj->lpVtbl->GetUserClassID(

               lpContainerLine->m_lpOleObj, (CLSID FAR*)&clsidOld);

         OLEDBG_END2

         if (hrErr != NOERROR) clsidOld = CLSID_NULL;

      }

      hrErr = OleStdMkParseDisplayName(

           &clsidOld,lpbc,lpszDisplayName,lpchEaten,(LPMONIKER FAR*)&lpmk);

      if (hrErr != NOERROR) {

         sc = GetScode(hrErr);   // ERROR in parsing moniker!

         goto cleanup;

      }

      /* OLE2NOTE: the link source was validated; it successfully

      **    parsed into a Moniker. we can set the source of the link

      **    directly with this Moniker. if we want the link to be

      **    able to know the correct class for the new link source,

      **    we must bind to the moniker and get the CLSID. if we do

      **    not do this then methods like IOleObject::GetUserType

      **    will return nothing (NULL strings).

      */

      hrErr = lpmk->lpVtbl->BindToObject(

            lpmk,lpbc,NULL,&IID_IOleObject,(LPVOID FAR*)&lpLinkSrcOleObj);

      if (hrErr == NOERROR) {

         OLEDBG_BEGIN2("IOleObject::GetUserClassID called\r\n")

         hrErr = lpLinkSrcOleObj->lpVtbl->GetUserClassID(

                     lpLinkSrcOleObj, (CLSID FAR*)&clsid);

         OLEDBG_END2

         lpContainerLine->m_fLinkUnavailable = FALSE;

         /* get the short user type name of the link because it may

         **    have changed. we cache this name and must update our

         **    cache. this name is used all the time when we have to

         **    build the object verb menu. we cache this information

         **    to make it quicker to build the verb menu.

         */

         if (lpContainerLine->m_lpszShortType) {

            OleStdFree(lpContainerLine->m_lpszShortType);

            lpContainerLine->m_lpszShortType = NULL;

         }

         OLEDBG_BEGIN2("IOleObject::GetUserType called\r\n")

         lpContainerLine->m_lpOleObj->lpVtbl->GetUserType(

               lpContainerLine->m_lpOleObj,

               USERCLASSTYPE_SHORT,

               (LPOLESTR FAR*)&lpContainerLine->m_lpszShortType

         );

         OLEDBG_END2

      }

      else

         lpContainerLine->m_fLinkUnavailable = TRUE;

   }

   else {

      LPMONIKER   lpmkFile = NULL;

      LPMONIKER   lpmkItem = NULL;

      OLECHAR     szDelim[2];

      LPOLESTR    lpszName;

      szDelim[0] = lpszDisplayName[(int)lenFileName];

      szDelim[1] = '\0';

      lpszDisplayName[(int)lenFileName] = '\0';

      OLEDBG_BEGIN2("CreateFileMoniker called\r\n")

      CreateFileMoniker((LPOLESTR)lpszDisplayName, (LPMONIKER FAR*)&lpmkFile);

      OLEDBG_END2

      lpszDisplayName[(int)lenFileName] = szDelim[0];

      if (!lpmkFile)

         goto cleanup;

      if (OLESTRLEN(lpszDisplayName) > (int)lenFileName) {  // have item name

         lpszName = lpszDisplayName + lenFileName + 1;

         OLEDBG_BEGIN2("CreateItemMoniker called\r\n")

         CreateItemMoniker(

               szDelim, lpszName, (LPMONIKER FAR*)&lpmkItem);

         OLEDBG_END2

         if (!lpmkItem) {

            OleStdRelease((LPUNKNOWN)lpmkFile);

            goto cleanup;

         }

         OLEDBG_BEGIN2("CreateGenericComposite called\r\n")

         CreateGenericComposite(lpmkFile, lpmkItem, (LPMONIKER FAR*)&lpmk);

         OLEDBG_END2

         if (lpmkFile)

            OleStdRelease((LPUNKNOWN)lpmkFile);

         if (lpmkItem)

            OleStdRelease((LPUNKNOWN)lpmkItem);

         if (!lpmk)

            goto cleanup;

      }

      else

         lpmk = lpmkFile;

   }

   if (! lpOleLink) {

      OleDbgAssert(lpOleLink != NULL);

      sc = E_FAIL;

      goto cleanup;

   }

   if (lpmk) {

      OLEDBG_BEGIN2("IOleLink::SetSourceMoniker called\r\n")

      hrErr = lpOleLink->lpVtbl->SetSourceMoniker(

            lpOleLink, lpmk, (REFCLSID)&clsid);

      OLEDBG_END2

      if (FAILED(GetScode(hrErr))) {

         OleDbgOutHResult("IOleLink::SetSourceMoniker returned",hrErr);

         sc = GetScode(hrErr);

         goto cleanup;

      }

      /* OLE2NOTE: above we forced the link source moniker to bind.

      **    because we deliberately hold on to the bind context

      **    (lpbc) the link source object will not shut down. during

      **    the call to IOleLink::SetSourceMoniker, the link will

      **    connect to the running link source (the link internally

      **    calls BindIfRunning). it is important to initially allow

      **    the link to bind to the running object so that it can get

      **    an update of the presentation for its cache. we do not

      **    want the connection from our link to the link source be

      **    the only reason the link source stays running. thus we

      **    deliberately for the link to release (unbind) the source

      **    object, we then release the bind context, and then we

      **    allow the link to rebind to the link source if it is

      **    running anyway.

      */

      if (lpbc && lpmk->lpVtbl->IsRunning(lpmk,lpbc,NULL,NULL) == NOERROR) {

         OLEDBG_BEGIN2("IOleLink::Update called\r\n")

         hrErr = lpOleLink->lpVtbl->Update(lpOleLink, NULL);

         OLEDBG_END2

#if defined( _DEBUG )

         if (FAILED(GetScode(hrErr)))

            OleDbgOutHResult("IOleLink::Update returned",hrErr);

#endif

         OLEDBG_BEGIN2("IOleLink::UnbindSource called\r\n")

         hrErr = lpOleLink->lpVtbl->UnbindSource(lpOleLink);

         OLEDBG_END2

#if defined( _DEBUG )

         if (FAILED(GetScode(hrErr)))

            OleDbgOutHResult("IOleLink::UnbindSource returned",hrErr);

#endif

         if (lpLinkSrcOleObj) {

            OleStdRelease((LPUNKNOWN)lpLinkSrcOleObj);

            lpLinkSrcOleObj = NULL;

         }

         if (lpbc) {

            OleStdRelease((LPUNKNOWN)lpbc);

            lpbc = NULL;

         }

         OLEDBG_BEGIN2("IOleLink::BindIfRunning called\r\n")

         hrErr = lpOleLink->lpVtbl->BindIfRunning(lpOleLink);

         OLEDBG_END2

#if defined( _DEBUG )

         if (FAILED(GetScode(hrErr)))

            OleDbgOutHResult("IOleLink::BindIfRunning returned",hrErr);

#endif

      }

   } else {

      /* OLE2NOTE: the link source was NOT validated; it was NOT

      **    successfully parsed into a Moniker. we can only set the

      **    display name string as the source of the link. this link

      **    is not able to bind.

      */

      OLEDBG_BEGIN2("IOleLink::SetSourceDisplayName called\r\n")

      hrErr = lpOleLink->lpVtbl->SetSourceDisplayName(

            lpOleLink, (LPCOLESTR)lpszDisplayName);

      OLEDBG_END2

      if (hrErr != NOERROR) {

         OleDbgOutHResult("IOleLink::SetSourceDisplayName returned",hrErr);

         sc = GetScode(hrErr);

         goto cleanup;

      }

   }

cleanup:

   if (lpLinkSrcOleObj)

      OleStdRelease((LPUNKNOWN)lpLinkSrcOleObj);

   if (lpmk)

      OleStdRelease((LPUNKNOWN)lpmk);

   if (lpbc)

      OleStdRelease((LPUNKNOWN)lpbc);

   OLEDBG_END2

   // release artificial AddRef

   CntrDoc_LinkCont_Release(lpThis);

   return ResultFromScode(sc);

}

STDMETHODIMP CntrDoc_LinkCont_GetLinkSource(

      LPOLEUILINKCONTAINER    lpThis,

      DWORD                   dwLink,

      LPOLESTR FAR*           lplpszDisplayName,

      ULONG FAR*              lplenFileName,

      LPOLESTR FAR*           lplpszFullLinkType,

      LPOLESTR FAR*           lplpszShortLinkType,

      BOOL FAR*               lpfSourceAvailable,

      BOOL FAR*               lpfIsSelected

)

{

   LPCONTAINERDOC lpContainerDoc =

         ((struct CDocOleUILinkContainerImpl FAR*)lpThis)->lpContainerDoc;

   LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)dwLink;

   LPOLELINK       lpOleLink = lpContainerLine->m_lpOleLink;

   LPOLEOBJECT     lpOleObj = NULL;

   LPMONIKER       lpmk = NULL;

   LPMONIKER       lpmkFirst = NULL;

   LPBC            lpbc = NULL;

   SCODE           sc = S_OK;

   HRESULT         hrErr;

   // artificial AddRef in case object is released during call

   CntrDoc_LinkCont_AddRef(lpThis);

   OLEDBG_BEGIN2("CntrDoc_LinkCont_GetLinkSource\r\n")

   /* OLE2NOTE: we must make sure to set all out parameters to NULL. */

   *lplpszDisplayName  = NULL;

   *lplpszFullLinkType = NULL;

   *lplpszShortLinkType= NULL;

   *lplenFileName      = 0;

   *lpfSourceAvailable = !lpContainerLine->m_fLinkUnavailable;

   OleDbgAssert(lpContainerLine);

   if (! lpOleLink) {

      OLEDBG_END2

      sc = E_FAIL;

      goto cleanup;

   }

   OLEDBG_BEGIN2("IOleLink::GetSourceMoniker called\r\n")

   hrErr = lpOleLink->lpVtbl->GetSourceMoniker(

         lpOleLink,

         (LPMONIKER FAR*)&lpmk

   );

   OLEDBG_END2

   if (hrErr == NOERROR) {

      /* OLE2NOTE: the link has the Moniker form of the link source;

      **    this is therefore a validated link source. if the first

      **    part of the Moniker is a FileMoniker, then we need to

      **    return the length of the filename string. we need to

      **    return the ProgID associated with the link source as the

      **    "lpszShortLinkType". we need to return the

      **    FullUserTypeName associated with the link source as the

      **    "lpszFullLinkType".

      */

      lpOleObj = (LPOLEOBJECT)OleStdQueryInterface(

            (LPUNKNOWN)lpOleLink, &IID_IOleObject);

      if (lpOleObj) {

         lpOleObj->lpVtbl->GetUserType(

               lpOleObj,

               USERCLASSTYPE_FULL,

               lplpszFullLinkType

         );

         lpOleObj->lpVtbl->GetUserType(

               lpOleObj,

               USERCLASSTYPE_SHORT,

               lplpszShortLinkType

         );

         OleStdRelease((LPUNKNOWN)lpOleObj);

      }

      *lplenFileName = OleStdGetLenFilePrefixOfMoniker(lpmk);

      lpmk->lpVtbl->Release(lpmk);

   }

   OLEDBG_BEGIN2("IOleLink::GetSourceDisplayName called\r\n")

   hrErr = lpOleLink->lpVtbl->GetSourceDisplayName(

         lpOleLink,

         lplpszDisplayName

   );

   OLEDBG_END2

   if (hrErr != NOERROR) {

      OleDbgOutHResult("IOleLink::GetSourceDisplayName returned", hrErr);

      OLEDBG_END2

      sc = hrErr;

      goto cleanup;

   }

   OLEDBG_END2

   if (lpfIsSelected)

      *lpfIsSelected = Line_IsSelected((LPLINE)lpContainerLine);

   sc = NOERROR;

cleanup:

   // release artificial AddRef

   CntrDoc_LinkCont_Release(lpThis);

   return sc;

}

STDMETHODIMP CntrDoc_LinkCont_OpenLinkSource(

      LPOLEUILINKCONTAINER    lpThis,

      DWORD                   dwLink

)

{

   LPCONTAINERDOC lpContainerDoc =

         ((struct CDocOleUILinkContainerImpl FAR*)lpThis)->lpContainerDoc;

   LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)dwLink;

   SCODE sc = S_OK;

   // artificial AddRef in case object is destroyed during call

   CntrDoc_LinkCont_AddRef(lpThis);

   OLEDBG_BEGIN2("CntrDoc_LinkCont_OpenLinkSource\r\n")

   OleDbgAssert(lpContainerLine);

   if (! ContainerLine_DoVerb(

         lpContainerLine, OLEIVERB_SHOW, NULL, TRUE, FALSE)) {

      sc = E_FAIL;

   }

   lpContainerLine->m_fLinkUnavailable = (sc != S_OK);

   OLEDBG_END2

   // release artificial AddRef

   CntrDoc_LinkCont_Release(lpThis);

   return ResultFromScode(sc);

}

STDMETHODIMP CntrDoc_LinkCont_UpdateLink(

      LPOLEUILINKCONTAINER    lpThis,

      DWORD                   dwLink,

      BOOL                    fErrorMessage,

      BOOL                    fErrorAction        // ignore if fErrorMessage

                                       //      is FALSE

)

{

   LPCONTAINERDOC lpContainerDoc =

         ((struct CDocOleUILinkContainerImpl FAR*)lpThis)->lpContainerDoc;

   LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)dwLink;

   SCODE sc = S_OK;

   // default to update of the link

   HRESULT hrErr = S_FALSE;

   // artificial AddRef in case object is destroyed during call

   CntrDoc_LinkCont_AddRef(lpThis);

   OLEDBG_BEGIN2("CntrDoc_LinkCont_UpdateLink\r\n")

   OleDbgAssert(lpContainerLine);

   if (! lpContainerLine->m_lpOleObj)

      ContainerLine_LoadOleObject(lpContainerLine);

   if (!fErrorMessage) {

      OLEDBG_BEGIN2("IOleObject::IsUpToDate called\r\n")

      hrErr = lpContainerLine->m_lpOleObj->lpVtbl->IsUpToDate(

            lpContainerLine->m_lpOleObj

      );

      OLEDBG_END2

   }

   if (hrErr != NOERROR) {

      OLEDBG_BEGIN2("IOleObject::Update called\r\n")

      hrErr = lpContainerLine->m_lpOleObj->lpVtbl->Update(

            lpContainerLine->m_lpOleObj

      );

      OLEDBG_END2

   }

   /* OLE2NOTE: If IOleObject::Update on the Link object returned

   **    OLE_E_CLASSDIFF because the link source is no longer

   **    the expected class, then the link should be re-created with

   **    the new link source. thus the link will be updated with the

   **    new link source.

   */

   if (GetScode(hrErr) == OLE_E_CLASSDIFF)

      hrErr = ContainerLine_ReCreateLinkBecauseClassDiff(lpContainerLine);

   lpContainerLine->m_fLinkUnavailable = (hrErr != NOERROR);

   if (hrErr != NOERROR) {

      OleDbgOutHResult("IOleObject::Update returned", hrErr);

      sc = GetScode(hrErr);

      if (fErrorMessage) {

         ContainerLine_ProcessOleRunError(

               lpContainerLine,hrErr,fErrorAction,FALSE/*fMenuInvoked*/);

      }

   }

   /* OLE2NOTE: if the update of the object requires us to update our

   **    display, then we will automatically be sent a OnViewChange

   **    advise. thus we do not need to take any action here to force

   **    a repaint.

   */

   OLEDBG_END2

   // release artificial AddRef

   CntrDoc_LinkCont_Release(lpThis);

   return ResultFromScode(sc);

}

/* CntrDoc_LinkCont_CancelLink

** ---------------------------

**    Convert the link to a static picture.

**

**    OLE2NOTE: OleCreateStaticFromData can be used to create a static

**    picture object.

*/

STDMETHODIMP CntrDoc_LinkCont_CancelLink(

      LPOLEUILINKCONTAINER    lpThis,

      DWORD                   dwLink

)

{

   LPCONTAINERDOC lpContainerDoc =

         ((struct CDocOleUILinkContainerImpl FAR*)lpThis)->lpContainerDoc;

   LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)dwLink;

   LPLINELIST          lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;

   LPLINE              lpLine = NULL;

   HDC                 hDC;

   int                 nTab = 0;

   OLECHAR             szStgName[CWCSTORAGENAME];

   LPCONTAINERLINE     lpNewContainerLine = NULL;

   LPDATAOBJECT        lpSrcDataObj;

   LPOLELINK           lpOleLink = lpContainerLine->m_lpOleLink;

   int nIndex = LineList_GetLineIndex(lpLL, (LPLINE)lpContainerLine);

   // artificial AddRef in case object is destroyed during call

   CntrDoc_LinkCont_AddRef(lpThis);

   OLEDBG_BEGIN2("CntrDoc_LinkCont_CancelLink\r\n")

   /* we will first break the connection of the link to its source. */

   if (lpOleLink) {

      lpContainerLine->m_dwLinkType = 0;

      OLEDBG_BEGIN2("IOleLink::SetSourceMoniker called\r\n")

      lpOleLink->lpVtbl->SetSourceMoniker(

            lpOleLink, NULL, (REFCLSID)&CLSID_NULL);

      OLEDBG_END2

   }

   lpSrcDataObj = (LPDATAOBJECT)ContainerLine_GetOleObject(

         lpContainerLine,&IID_IDataObject);

   if (! lpSrcDataObj)

      goto error;

   ContainerDoc_GetNextStgName(lpContainerDoc, szStgName, CWCSTORAGENAME);

   nTab = Line_GetTabLevel((LPLINE)lpContainerLine);

   hDC = LineList_GetDC(lpLL);

   lpNewContainerLine = ContainerLine_CreateFromData(

         hDC,

         nTab,

         lpContainerDoc,

         lpSrcDataObj,

         OLECREATEFROMDATA_STATIC,

         0,   /* no special cfFormat required */

         (lpContainerLine->m_dwDrawAspect == DVASPECT_ICON),

         NULL,   /* hMetaPict */

         szStgName

   );

   LineList_ReleaseDC(lpLL, hDC);

   OleStdRelease((LPUNKNOWN)lpSrcDataObj);

   if (! lpNewContainerLine)

      goto error;

   OutlineDoc_SetModified((LPOUTLINEDOC)lpContainerDoc, TRUE, TRUE, FALSE);

   LineList_ReplaceLine(lpLL, (LPLINE)lpNewContainerLine, nIndex);

   OLEDBG_END2

   // release artificial AddRef

   CntrDoc_LinkCont_Release(lpThis);

   return ResultFromScode(NOERROR);

error:

   OutlineApp_ErrorMessage(g_lpApp, OLESTR("Could not break the link."));

   OLEDBG_END2

   // release artificial AddRef

   CntrDoc_LinkCont_Release(lpThis);

   return ResultFromScode(E_FAIL);

}


CNTRINPL.C  (OUTLINE Sample)

/*************************************************************************

**

**    OLE 2 Container Sample Code

**

**    cntrinpl.c

**

**    This file contains all interfaces, methods and related support

**    functions for an In-Place Container application (aka. Visual

**    Editing). The in-place Container application includes the following

**    implementation objects:

**

**    ContainerApp Object

**      exposed interfaces:

**          IOleInPlaceFrame

**

**    ContainerDoc Object

**      support functions only

**      (ICntrOtl is an SDI app; it doesn't support a Doc level IOleUIWindow)

**

**    ContainerLin Object

**      exposed interfaces:

**          IOleInPlaceSite

**

**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

**

*************************************************************************/

#include "outline.h"

#if defined( USE_STATUSBAR )

#include "status.h"

#endif

OLEDBGDATA

extern LPOUTLINEAPP g_lpApp;

extern BOOL g_fInsideOutContainer;

extern RECT g_rectNull;

/*************************************************************************

** ContainerApp::IOleInPlaceFrame interface implementation

*************************************************************************/

// IOleInPlaceFrame::QueryInterface

STDMETHODIMP CntrApp_IPFrame_QueryInterface(

      LPOLEINPLACEFRAME   lpThis,

      REFIID              riid,

      LPVOID FAR*         lplpvObj

)

{

   SCODE sc = E_NOINTERFACE;

   LPCONTAINERAPP lpContainerApp =

         ((struct COleInPlaceFrameImpl FAR*)lpThis)->lpContainerApp;

   /* The object should not be able to access the other interfaces

   ** of our App object by doing QI on this interface.

   */

   *lplpvObj = NULL;

   if (IsEqualIID(riid, &IID_IUnknown) ||

      IsEqualIID(riid, &IID_IOleWindow) ||

      IsEqualIID(riid, &IID_IOleInPlaceUIWindow) ||

      IsEqualIID(riid, &IID_IOleInPlaceFrame)) {

      OleDbgOut4("CntrApp_IPFrame_QueryInterface: IOleInPlaceFrame* RETURNED\r\n");

      *lplpvObj = (LPVOID) &lpContainerApp->m_OleInPlaceFrame;

      OleApp_AddRef((LPOLEAPP)lpContainerApp);

      sc = S_OK;

   }

   OleDbgQueryInterfaceMethod(*lplpvObj);

   return ResultFromScode(sc);

}

// IOleInPlaceFrame::AddRef

STDMETHODIMP_(ULONG) CntrApp_IPFrame_AddRef(LPOLEINPLACEFRAME lpThis)

{

   OleDbgAddRefMethod(lpThis, "IOleInPlaceFrame");

   return OleApp_AddRef((LPOLEAPP)g_lpApp);

}

// IOleInPlaceFrame::Release

STDMETHODIMP_(ULONG) CntrApp_IPFrame_Release(LPOLEINPLACEFRAME lpThis)

{

   OleDbgReleaseMethod(lpThis, "IOleInPlaceFrame");

   return OleApp_Release((LPOLEAPP)g_lpApp);

}

// IOleInPlaceFrame::GetWindow

STDMETHODIMP CntrApp_IPFrame_GetWindow(

   LPOLEINPLACEFRAME   lpThis,

   HWND FAR*           lphwnd

)

{

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   OLEDBG_BEGIN2("CntrApp_IPFrame_GetWindow\r\n")

   *lphwnd = lpOutlineApp->m_hWndApp;

   OLEDBG_END2

   return NOERROR;

}

// IOleInPlaceFrame::ContextSensitiveHelp

STDMETHODIMP CntrApp_IPFrame_ContextSensitiveHelp(

   LPOLEINPLACEFRAME   lpThis,

   BOOL                fEnterMode

)

{

   LPCONTAINERAPP lpContainerApp =

         ((struct COleInPlaceFrameImpl FAR*)lpThis)->lpContainerApp;

   // artificial AddRef in case object is destroyed during call

   CntrApp_IPFrame_AddRef(lpThis);

   OleDbgOut("CntrApp_IPFrame_ContextSensitiveHelp\r\n");

   /* OLE2NOTE: see context sensitive help technote (CSHELP.DOC)

   **    This method is called when F1 is pressed when a menu item is

   **    selected. We set the frame's m_fMenuMode flag here. later,

   **    in WM_COMMAND processing in the AppWndProc, if this flag is

   **    set then the command is NOT executed and help is given

   **    instead.

   */

   lpContainerApp->m_fMenuHelpMode = fEnterMode;

   // release artificial AddRef

   CntrApp_IPFrame_Release(lpThis);

   return NOERROR;

}

// IOleInPlaceFrame::GetBorder

STDMETHODIMP CntrApp_IPFrame_GetBorder(

   LPOLEINPLACEFRAME   lpThis,

   LPRECT              lprectBorder

)

{

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   // artificial AddRef in case object is destroyed during call

   CntrApp_IPFrame_AddRef(lpThis);

   OLEDBG_BEGIN2("CntrApp_IPFrame_GetBorder\r\n")

   OutlineApp_GetFrameRect(lpOutlineApp, lprectBorder);

   OLEDBG_END2

   // release artificial AddRef

   CntrApp_IPFrame_Release(lpThis);

   return NOERROR;

}

// IOleInPlaceFrame::RequestBorderSpace

STDMETHODIMP CntrApp_IPFrame_RequestBorderSpace(

   LPOLEINPLACEFRAME   lpThis,

   LPCBORDERWIDTHS     lpWidths

)

{

#if defined( _DEBUG )

   OleDbgOut2("CntrApp_IPFrame_RequestBorderSpace\r\n");

   {

      /* FOR DEBUGING PURPOSES ONLY -- we will fail to allow to an

      **    object to get any frame border space for frame tools if

      **    our own frame tools are poped up in the tool pallet. this

      **    is NOT recommended UI behavior but it allows us to test

      **    in the condition when the frame does not give border

      **    space for the object. an object in this situation must

      **    then either popup its tools in a floating pallet, do

      **    without the tools, or fail to in-place activate.

      */

      LPCONTAINERAPP lpContainerApp =

            ((struct COleInPlaceFrameImpl FAR*)lpThis)->lpContainerApp;

      LPFRAMETOOLS lpft = OutlineApp_GetFrameTools(

            (LPOUTLINEAPP)lpContainerApp);

      if (lpft->m_ButtonBar.m_nState == BARSTATE_POPUP &&

         lpft->m_FormulaBar.m_nState == BARSTATE_POPUP) {

         OleDbgOut3(

               "CntrApp_IPFrame_RequestBorderSpace: allow NO SPACE\r\n");

         return ResultFromScode(E_FAIL);

      }

   }

#endif  // _DEBUG

   /* OLE2NOTE: we allow the object to have as much border space as it

   **    wants.

   */

   return NOERROR;

}

// IOleInPlaceFrame::SetBorderSpace

STDMETHODIMP CntrApp_IPFrame_SetBorderSpace(

   LPOLEINPLACEFRAME   lpThis,

   LPCBORDERWIDTHS     lpWidths

)

{

   LPCONTAINERAPP lpContainerApp =

         ((struct COleInPlaceFrameImpl FAR*)lpThis)->lpContainerApp;

   // artificial AddRef in case object is destroyed during call

   CntrApp_IPFrame_AddRef(lpThis);

   OLEDBG_BEGIN2("CntrApp_IPFrame_SetBorderSpace\r\n")

   /* OLE2NOTE: this fMustResizeClientArea flag is used as part of our

   **    defensive programming for frame window resizing. when the

   **    frame window is resized,IOleInPlaceActiveObject::ResizeBorder

   **    is called the object should normally call back to renegotiate

   **    for frame-level tools space. if SetBorderSpace is called then

   **    our client area windows are properly resized. if the in-place

   **    active object does NOT call SetBorderSpace, then the

   **    container must take care to resize its client area windows

   **    itself (see ContainerDoc_FrameWindowResized)

   */

   if (lpContainerApp->m_fMustResizeClientArea)

      lpContainerApp->m_fMustResizeClientArea = FALSE;

   if (lpWidths == NULL) {

      /* OLE2NOTE: IOleInPlaceSite::SetBorderSpace(NULL) is called

      **    when the in-place active object does NOT want any tool

      **    space. in this situation the in-place container should

      **    put up its tools.

      */

      LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)lpContainerApp;

      LPCONTAINERDOC lpContainerDoc;

      lpContainerDoc =(LPCONTAINERDOC)OutlineApp_GetActiveDoc(lpOutlineApp);

      ContainerDoc_AddFrameLevelTools(lpContainerDoc);

   } else {

      // OLE2NOTE: you could do validation of borderwidths here

#if defined( _DEBUG )

      /* FOR DEBUGING PURPOSES ONLY -- we will fail to allow to an

      **    object to get any frame border space for frame tools if

      **    our own frame tools are poped up in the tool pallet. this

      **    is NOT recommended UI behavior but it allows us to test

      **    in the condition when the frame does not give border

      **    space for the object. an object in this situation must

      **    then either popup its tools in a floating pallet, do

      **    without the tools, or fail to in-place activate.

      */

      LPFRAMETOOLS lpft = OutlineApp_GetFrameTools(

            (LPOUTLINEAPP)lpContainerApp);

      if ((lpft->m_ButtonBar.m_nState == BARSTATE_POPUP &&

         lpft->m_FormulaBar.m_nState == BARSTATE_POPUP) &&

         (lpWidths->top || lpWidths->bottom ||

            lpWidths->left || lpWidths->right) ) {

         OleDbgOut3("CntrApp_IPFrame_SetBorderSpace: allow NO SPACE\r\n");

         OLEDBG_END2

         OutlineApp_SetBorderSpace(

               (LPOUTLINEAPP) lpContainerApp,

               (LPBORDERWIDTHS)&g_rectNull

         );

         OLEDBG_END2

         // release artificial AddRef

         CntrApp_IPFrame_Release(lpThis);

         return ResultFromScode(E_FAIL);

      }

#endif  // _DEBUG

      OutlineApp_SetBorderSpace(

            (LPOUTLINEAPP) lpContainerApp,

            (LPBORDERWIDTHS)lpWidths

      );

   }

   OLEDBG_END2

   // release artificial AddRef

   CntrApp_IPFrame_Release(lpThis);

   return NOERROR;

}

// IOleInPlaceFrame::SetActiveObject

STDMETHODIMP CntrApp_IPFrame_SetActiveObject(

   LPOLEINPLACEFRAME           lpThis,

   LPOLEINPLACEACTIVEOBJECT    lpActiveObject,

   LPCOLESTR                   lpszObjName

)

{

   LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)g_lpApp;

   // artificial AddRef in case object is destroyed during call

   CntrApp_IPFrame_AddRef(lpThis);

   OLEDBG_BEGIN2("CntrApp_IPFrame_SetActiveObject\r\n")

   lpContainerApp->m_hWndUIActiveObj = NULL;

   if (lpContainerApp->m_lpIPActiveObj)

      lpContainerApp->m_lpIPActiveObj->lpVtbl->Release(lpContainerApp->m_lpIPActiveObj);

   if ((lpContainerApp->m_lpIPActiveObj = lpActiveObject) != NULL) {

      lpContainerApp->m_lpIPActiveObj->lpVtbl->AddRef(

            lpContainerApp->m_lpIPActiveObj);

      OLEDBG_BEGIN2("IOleInPlaceActiveObject::GetWindow called\r\n")

      lpActiveObject->lpVtbl->GetWindow(

            lpActiveObject,

            (HWND FAR*)&lpContainerApp->m_hWndUIActiveObj

      );

      OLEDBG_END2

      /* OLE2NOTE: see comment for ContainerDoc_ForwardPaletteChangedMsg */

      /* No need to do this if you don't allow object to own the palette */

      OleApp_QueryNewPalette((LPOLEAPP)lpContainerApp);

   }

   /* OLE2NOTE: the new UI Guidelines recommend that in-place

   **    containers do NOT change their window titles when an object

   **    becomes in-place (UI) active.

   */

   OLEDBG_END2

   // release artificial AddRef

   CntrApp_IPFrame_Release(lpThis);

   return NOERROR;

}

// IOleInPlaceFrame::InsertMenus

STDMETHODIMP CntrApp_IPFrame_InsertMenus(

   LPOLEINPLACEFRAME       lpThis,

   HMENU                   hMenu,

   LPOLEMENUGROUPWIDTHS    lpMenuWidths

)

{

   LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)g_lpApp;

   BOOL    fNoError = TRUE;

   OLEDBG_BEGIN2("CntrApp_IPFrame_InsertMenus\r\n")

   fNoError &= AppendMenu(hMenu, MF_POPUP, (UINT)lpContainerApp->m_hMenuFile,

                  "&File");

   fNoError &= AppendMenu(hMenu, MF_POPUP, (UINT)lpContainerApp->m_hMenuView,

                  "O&utline");

   fNoError &= AppendMenu(hMenu, MF_POPUP,(UINT)lpContainerApp->m_hMenuDebug,

                  "DbgI&Cntr");

   lpMenuWidths->width[0] = 1;

   lpMenuWidths->width[2] = 1;

   lpMenuWidths->width[4] = 1;

   OLEDBG_END2

   return (fNoError ? NOERROR : ResultFromScode(E_FAIL));

}

// IOleInPlaceFrame::SetMenu

STDMETHODIMP CntrApp_IPFrame_SetMenu(

   LPOLEINPLACEFRAME   lpThis,

   HMENU               hMenuShared,

   HOLEMENU            hOleMenu,

   HWND                hwndActiveObject

)

{

   LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)g_lpApp;

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   HMENU   hMenu;

   HRESULT hrErr;

   OLEDBG_BEGIN2("CntrApp_IPFrame_InsertMenus\r\n")

   /* OLE2NOTE: either put up the shared menu (combined menu from

   **    in-place server and in-place container) or our container's

   **    normal menu as directed.

   */

   if (hOleMenu && hMenuShared)

      hMenu = hMenuShared;

   else

      hMenu = lpOutlineApp->m_hMenuApp;

   /* OLE2NOTE: SDI apps put menu on frame by calling SetMenu.

   **    MDI apps would send WM_MDISETMENU message instead.

   */

   SetMenu (lpOutlineApp->m_hWndApp, hMenu);

   OLEDBG_BEGIN2("OleSetMenuDescriptor called\r\n")

   hrErr = OleSetMenuDescriptor (hOleMenu, lpOutlineApp->m_hWndApp,

               hwndActiveObject, NULL, NULL);

   OLEDBG_END2

   OLEDBG_END2

   return hrErr;

}

// IOleInPlaceFrame::RemoveMenus

STDMETHODIMP CntrApp_IPFrame_RemoveMenus(

   LPOLEINPLACEFRAME   lpThis,

   HMENU               hMenu

)

{

   LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)g_lpApp;

   BOOL fNoError = TRUE;

   OLEDBG_BEGIN2("CntrApp_IPFrame_RemoveMenus\r\n")

   /* Remove container group menus */

   while (GetMenuItemCount(hMenu))

      fNoError &= RemoveMenu(hMenu, 0, MF_BYPOSITION);

   OleDbgAssert(fNoError == TRUE);

   OLEDBG_END2

   return (fNoError ? NOERROR : ResultFromScode(E_FAIL));

}

// IOleInPlaceFrame::SetStatusText

STDMETHODIMP CntrApp_IPFrame_SetStatusText(

   LPOLEINPLACEFRAME   lpThis,

   LPCOLESTR           lpszStatusText

)

{

#if defined( USE_STATUSBAR )

   LPOUTLINEAPP   lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   OLECHAR         szMessageHold[128];

   OleDbgOut2("CntrApp_IPFrame_SetStatusText\r\n");

   /* OLE2NOTE: it is important to save a private copy of status text.

   **    lpszStatusText is only valid for the duration of this call.

   */

   OLESTRCPY(szMessageHold, lpszStatusText);

   OutlineApp_SetStatusText(lpOutlineApp, (LPOLESTR)szMessageHold);

   return ResultFromScode(S_OK);

#else

   return ResultFromScode(E_NOTIMPL);

#endif  // USE_STATUSBAR

}

// IOleInPlaceFrame::EnableModeless

STDMETHODIMP CntrApp_IPFrame_EnableModeless(

   LPOLEINPLACEFRAME   lpThis,

   BOOL                fEnable

)

{

   LPOLEAPP lpOleApp = (LPOLEAPP)

         ((struct COleInPlaceFrameImpl FAR*)lpThis)->lpContainerApp;

#if defined( _DEBUG )

   if (fEnable)

      OleDbgOut2("CntrApp_IPFrame_EnableModeless(TRUE)\r\n");

   else

      OleDbgOut2("CntrApp_IPFrame_EnableModeless(FALSE)\r\n");

#endif  // _DEBUG

   /* OLE2NOTE: this method is called when an object puts up a modal

   **    dialog. it tells the top-level in-place container to disable

   **    it modeless dialogs for the duration that the object is

   **    displaying a modal dialog.

   **

   **    ICNTROTL does not use any modeless dialogs, thus we can

   **    ignore this method.

   */

   return NOERROR;

}

// IOleInPlaceFrame::TranslateAccelerator

STDMETHODIMP CntrApp_IPFrame_TranslateAccelerator(

   LPOLEINPLACEFRAME   lpThis,

   LPMSG               lpmsg,

   WORD                wID

)

{

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)g_lpApp;

   SCODE sc;

   if (TranslateAccelerator (lpOutlineApp->m_hWndApp,

                  lpContainerApp->m_hAccelIPCntr, lpmsg))

      sc = S_OK;

#if defined (MDI_VERSION)

   else if (TranslateMDISysAccel(lpOutlineApp->m_hWndMDIClient, lpmsg))

      sc = S_OK;

#endif  // MDI_VERSION

   else

      sc = S_FALSE;

   return ResultFromScode(sc);

}

/*************************************************************************

** ContainerDoc Support Functions

*************************************************************************/

/* ContainerDoc_UpdateInPlaceObjectRects

** -------------------------------------

**    Update the PosRect and ClipRect of the currently in-place active

**    object. if there is no object active in-place, then do nothing.

**

**    OLE2NOTE: this function should be called when an action occurs

**    that changes either the position of the object in the document

**    (eg. changing document margins changes PosRect) or the clipRect

**    changes (eg. resizing the document window changes the ClipRect).

*/

void ContainerDoc_UpdateInPlaceObjectRects(LPCONTAINERDOC lpContainerDoc, int nIndex)

{

   LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;

   int i;

   LPLINE lpLine;

   RECT rcClipRect;

   if (g_fInsideOutContainer) {

      if (lpContainerDoc->m_cIPActiveObjects) {

         /* OLE2NOTE: (INSIDE-OUT CONTAINER) we must update the

         **    PosRect/ClipRect for all in-place active objects

         **    starting from line "nIndex".

         */

         ContainerDoc_GetClipRect(lpContainerDoc, (LPRECT)&rcClipRect);

#if defined( _DEBUG )

         OleDbgOutRect3(

               "ContainerDoc_UpdateInPlaceObjectRects (ClipRect)",

               (LPRECT)&rcClipRect

         );

#endif

         for (i = nIndex; i < lpLL->m_nNumLines; i++) {

            lpLine=LineList_GetLine(lpLL, i);

            if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE)) {

               LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)lpLine;

               ContainerLine_UpdateInPlaceObjectRects(

                     lpContainerLine, &rcClipRect);

            }

         }

      }

   }

   else {

      /* OLE2NOTE: (OUTSIDE-IN CONTAINER) if there is a currently

      **    UIActive object, we must inform it that the

      **    PosRect/ClipRect has now changed.

      */

      LPCONTAINERLINE lpLastUIActiveLine =

            lpContainerDoc->m_lpLastUIActiveLine;

      if (lpLastUIActiveLine && lpLastUIActiveLine->m_fUIActive) {

         ContainerDoc_GetClipRect(lpContainerDoc, (LPRECT)&rcClipRect);

         OleDbgOutRect3("OutlineDoc_Resize (ClipRect)",(LPRECT)&rcClipRect);

         ContainerLine_UpdateInPlaceObjectRects(

               lpLastUIActiveLine, &rcClipRect);

      }

   }

}

/* ContainerDoc_IsUIDeactivateNeeded

** ---------------------------------

**    Check if it is necessary to UIDeactivate an in-place active

**    object upon a mouse LBUTTONDOWN event. The position of the button

**    down click is given by "pt".

**    If there is not currently an in-place active line, then

**    UIDeactivate is NOT needed.

**    If there is a current in-place active line, then check if the

**    point position is outside of the object extents on the screen. If

**    so, then the object should be UIDeactivated, otherwise not.

*/

BOOL ContainerDoc_IsUIDeactivateNeeded(

      LPCONTAINERDOC  lpContainerDoc,

      POINT           pt

)

{

   LPCONTAINERLINE lpUIActiveLine=lpContainerDoc->m_lpLastUIActiveLine;

   RECT rect;

   if (! lpUIActiveLine || ! lpUIActiveLine->m_fUIActive)

      return FALSE;

   ContainerLine_GetPosRect(

         lpUIActiveLine,

         (LPRECT) &rect

   );

   if (! PtInRect((LPRECT) &rect, pt))

      return TRUE;

   return FALSE;

}

/* ContainerDoc_ShutDownLastInPlaceServerIfNotNeeded

** -------------------------------------------------

**    OLE2NOTE: this function ONLY applies for OUTSIDE-IN containers

**

**    If there is a previous in-place active server still running and

**    this server will not be needed to support the next OLE object

**    about to be activated, then shut it down.

**    in this way we manage a policy of having at most one in-place

**    server running at a time. we do not imediately shut down the

**    in-place server when the object is UIDeactivated because we want

**    it to be fast if the server decides to re-activate the object

**    in-place.

**

**    shutting down the server is achieved by forcing the object to

**    transition from running to loaded by calling IOleObject::Close.

*/

void ContainerDoc_ShutDownLastInPlaceServerIfNotNeeded(

      LPCONTAINERDOC          lpContainerDoc,

      LPCONTAINERLINE         lpNextActiveLine

)

{

   LPCONTAINERLINE lpLastIpActiveLine = lpContainerDoc->m_lpLastIpActiveLine;

   BOOL fEnableServerShutDown = TRUE;

   LPMONIKER lpmkLinkSrc;

   LPMONIKER lpmkLastActiveObj;

   LPMONIKER lpmkCommonPrefix;

   LPOLELINK lpOleLink;

   HRESULT hrErr;

   /* OLE2NOTE: an inside-out style container can NOT use this scheme

   **    to shut down in-place servers. it would have to have a more

   **    sophistocated mechanism by which it keeps track of which

   **    objects are on screen and which were the last recently used.

   */

   if (g_fInsideOutContainer)

      return;

   if (lpLastIpActiveLine != lpNextActiveLine) {

      if (lpLastIpActiveLine) {

         /* OLE2NOTE: if the object which is about to be activated is

         **    actually a link to the OLE object in last activated line,

         **    then we do NOT want to shut down the last activated

         **    server because it is about to be used. when activating a

         **    linked object, the source of the link gets activated.

         */

         lpOleLink = (LPOLELINK)ContainerLine_GetOleObject(

               lpNextActiveLine,

               &IID_IOleLink

         );

         if (lpOleLink) {

            OLEDBG_BEGIN2("IOleObject::GetSourceMoniker called\r\n")

            lpOleLink->lpVtbl->GetSourceMoniker(

                  lpOleLink,

                  (LPMONIKER FAR*)&lpmkLinkSrc

            );

            OLEDBG_END2

            if (lpmkLinkSrc) {

               lpmkLastActiveObj = ContainerLine_GetFullMoniker(

                     lpLastIpActiveLine,

                     GETMONIKER_ONLYIFTHERE

               );

               if (lpmkLastActiveObj) {

                  hrErr = lpmkLinkSrc->lpVtbl->CommonPrefixWith(

                        lpmkLinkSrc,

                        lpmkLastActiveObj,

                        &lpmkCommonPrefix

                  );

                  if (GetScode(hrErr) == MK_S_HIM ||

                                hrErr == NOERROR ||

                        GetScode(hrErr) == MK_S_US) {

                     /* the link source IS to the object

                     **    contained in the last activated

                     **    line of the document; disable the

                     **    attempt to shut down the last

                     **    running in-place server.

                     */

                     fEnableServerShutDown = FALSE;

                  }

                  if (lpmkCommonPrefix)

                     OleStdRelease((LPUNKNOWN)lpmkCommonPrefix);

                  OleStdRelease((LPUNKNOWN)lpmkLastActiveObj);

               }

               OleStdRelease((LPUNKNOWN)lpmkLinkSrc);

            }

            OleStdRelease((LPUNKNOWN)lpOleLink);

         }

         /* if it is OK to shut down the previous in-place server

         **    and one is still running, then shut it down. shutting

         **    down the server is accomplished by forcing the OLE

         **    object to close. this forces the object to transition

         **    from running to loaded. if the object is actually

         **    only loaded then this is a NOP.

         */

         if (fEnableServerShutDown &&

               lpLastIpActiveLine->m_fIpServerRunning) {

            OleDbgOut1("@@@ previous in-place server SHUT DOWN\r\n");

            ContainerLine_CloseOleObject(

                  lpLastIpActiveLine, OLECLOSE_SAVEIFDIRTY);

            // we can now forget this last in-place active line.

            lpContainerDoc->m_lpLastIpActiveLine = NULL;

         }

      }

   }

}

/* ContainerDoc_GetUIActiveWindow

** ------------------------------

**    If there is an UIActive object, then return its HWND.

*/

HWND ContainerDoc_GetUIActiveWindow(LPCONTAINERDOC lpContainerDoc)

{

   return lpContainerDoc->m_hWndUIActiveObj;

}

/* ContainerDoc_GetClipRect

** ------------------------

**    Get the ClipRect in client coordinates.

**

** OLE2NOTE: the ClipRect is defined as the maximum window rectangle

**    that the in-place active object must be clipped to. this

**    rectangle MUST be described in Client Coordinates of the window

**    that is used as the Parent of the in-place active object's

**    window. in our case, the LineList ListBox window is both the

**    parent of the in-place active object AND defines precisely the

**    clipping rectangle.

*/

void ContainerDoc_GetClipRect(

      LPCONTAINERDOC      lpContainerDoc,

      LPRECT              lprcClipRect

)

{

   /* OLE2NOTE: the ClipRect can be used to ensure that the in-place

   **    server does not overwrite areas of the window that the

   **    container paints into but which should never be overwritten

   **    (eg. if an app were to paint row and col headings directly in

   **    the same window that is the parent of the in-place window.

   **    whenever the window size changes or gets scrolled, in-place

   **    active object must be informed of the new clip rect.

   **

   **    normally an app would pass the rect returned from GetClientRect.

   **    but because CntrOutl uses separate windows for row/column

   **    headings, status line, formula/tool bars, etc. it is NOT

   **    necessary to pass a constrained clip rect. Windows standard

   **    window clipping will automatically take care of all clipping

   **    that is necessary. thus we can take a short cut of passing an

   **    "infinite" clip rect, and then we do NOT need to call

   **    IOleInPlaceObject::SetObjectRects when our document is scrolled.

   */

   lprcClipRect->top = -32767;

   lprcClipRect->left = -32767;

   lprcClipRect->right = 32767;

   lprcClipRect->bottom = 32767;

}

/* ContainerDoc_GetTopInPlaceFrame

** -------------------------------

**    returns NON-AddRef'ed pointer to Top In-Place Frame interface

*/

LPOLEINPLACEFRAME ContainerDoc_GetTopInPlaceFrame(

      LPCONTAINERDOC      lpContainerDoc

)

{

#if defined( INPLACE_CNTRSVR )

   return lpContainerDoc->m_lpTopIPFrame;

#else

   return (LPOLEINPLACEFRAME)&((LPCONTAINERAPP)g_lpApp)->m_OleInPlaceFrame;

#endif

}

void ContainerDoc_GetSharedMenuHandles(

      LPCONTAINERDOC  lpContainerDoc,

      HMENU FAR*      lphSharedMenu,

      HOLEMENU FAR*   lphOleMenu

)

{

#if defined( INPLACE_CNTRSVR )

   if (lpContainerDoc->m_DocType == DOCTYPE_EMEBEDDEDOBJECT) {

      *lphSharedMenu = lpContainerDoc->m_hSharedMenu;

      *lphOleMenu = lpContainerDoc->m_hOleMenu;

      return;

   }

#endif

   *lphSharedMenu = NULL;

   *lphOleMenu = NULL;

}

#if defined( USE_FRAMETOOLS )

void ContainerDoc_RemoveFrameLevelTools(LPCONTAINERDOC lpContainerDoc)

{

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerDoc;

   OleDbgAssert(lpOutlineDoc->m_lpFrameTools != NULL);

   FrameTools_Enable(lpOutlineDoc->m_lpFrameTools, FALSE);

}

#endif

void ContainerDoc_AddFrameLevelUI(LPCONTAINERDOC lpContainerDoc)

{

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerDoc;

   LPOLEINPLACEFRAME lpTopIPFrame = ContainerDoc_GetTopInPlaceFrame(

         lpContainerDoc);

   HMENU           hSharedMenu;            // combined obj/cntr menu

   HOLEMENU        hOleMenu;               // returned by OleCreateMenuDesc.

   ContainerDoc_GetSharedMenuHandles(

         lpContainerDoc,

         &hSharedMenu,

         &hOleMenu

   );

   lpTopIPFrame->lpVtbl->SetMenu(

         lpTopIPFrame,

         hSharedMenu,

         hOleMenu,

         lpOutlineDoc->m_hWndDoc

   );

   /* OLE2NOTE: even if our app does NOT use FrameTools, we must still

   **    call IOleInPlaceFrame::SetBorderSpace.

   */

   ContainerDoc_AddFrameLevelTools(lpContainerDoc);

}

void ContainerDoc_AddFrameLevelTools(LPCONTAINERDOC lpContainerDoc)

{

   LPOLEINPLACEFRAME lpTopIPFrame = ContainerDoc_GetTopInPlaceFrame(

         lpContainerDoc);

   LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)g_lpApp;

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerDoc;

   OleDbgAssert(lpTopIPFrame != NULL);

#if defined( USE_FRAMETOOLS )

   FrameTools_Enable(lpOutlineDoc->m_lpFrameTools, TRUE);

   OutlineDoc_UpdateFrameToolButtons(lpOutlineDoc);

   FrameTools_NegotiateForSpaceAndShow(

         lpOutlineDoc->m_lpFrameTools,

         NULL,

         lpTopIPFrame

   );

#else   // ! USE_FRAMETOOLS

#if defined( INPLACE_CNTRSVR )

   if (lpContainerDoc->m_DocType == DOCTYPE_EMBEDDEDOBJECT) {

      /* this says i do not need space, so the top Frame should

      **    leave its tools behind

      */

      OLEDBG_BEGIN2("IOleInPlaceFrame::SetBorderSpace(NULL) called\r\n")

      lpTopIPFrame->lpVtbl->SetBorderSpace(lpTopIPFrame, NULL);

      OLEDBG_END2

      return;

   }

#else   // INPLACE_CNTR && ! USE_FRAMETOOLS

   OLEDBG_BEGIN2("IOleInPlaceFrame::SetBorderSpace(0,0,0,0) called\r\n")

   lpTopIPFrame->lpVtbl->SetBorderSpace(

         lpTopIPFrame,

         (LPCBORDERWIDTHS)&g_rectNull

   );

   OLEDBG_END2

#endif  // INPLACE_CNTR && ! USE_FRAMETOOLS

#endif  // ! USE_FRAMETOOLS

}

void ContainerDoc_FrameWindowResized(LPCONTAINERDOC lpContainerDoc)

{

   LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)g_lpApp;

   if (lpContainerApp->m_lpIPActiveObj) {

      RECT rcFrameRect;

      /* OLE2NOTE: this fMustResizeClientArea flag is used as part of

      **    our defensive programming for frame window resizing. when

      **    the frame window is

      **    resized, IOleInPlaceActiveObject::ResizeBorder is called

      **    the object should normally call back to renegotiate

      **    for frame-level tools space. if SetBorderSpace is called

      **    then our client area windows are properly resized.

      **    CntrApp_IPFrame_SetBorderSpace clears this flag. if the

      **    in-place active object does NOT call SetBorderSpace, then

      **    the container must take care to resize its client area

      **    windows itself.

      */

      lpContainerApp->m_fMustResizeClientArea = TRUE;

      OutlineApp_GetFrameRect(g_lpApp, (LPRECT)&rcFrameRect);

      OLEDBG_BEGIN2("IOleInPlaceActiveObject::ResizeBorder called\r\n")

      lpContainerApp->m_lpIPActiveObj->lpVtbl->ResizeBorder(

            lpContainerApp->m_lpIPActiveObj,

            (LPCRECT)&rcFrameRect,

            (LPOLEINPLACEUIWINDOW)&lpContainerApp->m_OleInPlaceFrame,

            TRUE    /* fFrameWindow */

      );

      OLEDBG_END2

      /* the object did NOT call IOleInPlaceUIWindow::SetBorderSpace

      **    therefore we must resize our client area windows ourself.

      */

      if (lpContainerApp->m_fMustResizeClientArea) {

         lpContainerApp->m_fMustResizeClientArea = FALSE;

         OutlineApp_ResizeClientArea(g_lpApp);

      }

   }

#if defined( USE_FRAMETOOLS )

   else {

      ContainerDoc_AddFrameLevelTools(lpContainerDoc);

   }

#endif

}

#if defined( INPLACE_CNTRSVR ) || defined( INPLACE_MDICNTR )

/* ContainerDoc_GetTopInPlaceDoc

**    returns NON-AddRef'ed pointer to Top In-Place Doc interface

*/

LPOLEINPLACEUIWINDOW ContainerDoc_GetTopInPlaceDoc(

      LPCONTAINERDOC      lpContainerDoc

)

{

#if defined( INPLACE_CNTRSVR )

   return lpContainerDoc->m_lpTopIPDoc;

#else

   return (LPOLEINPLACEUIWINDOW)&lpContainerDoc->m_OleInPlaceDoc;

#endif

}

void ContainerDoc_RemoveDocLevelTools(LPCONTAINERDOC lpContainerDoc);

{

   LPOLEINPLACEUIWINDOW lpTopIPDoc = ContainerDoc_GetTopInPlaceDoc(

         lpContainerDoc);

   if (lpTopIPDoc && lpContainerDoc->m_fMyToolsOnDoc) {

      lpContainerDoc->m_fMyToolsOnDoc = FALSE;

      // if we had doc tools we would HIDE them here;

      //   but NOT call SetBorderSpace(NULL)

   }

}

void ContainerDoc_AddDocLevelTools(LPCONTAINERDOC lpContainerDoc)

{

   LPOLEINPLACEUIWINDOW lpTopIPDoc = ContainerDoc_GetTopInPlaceDoc(

         lpContainerDoc);

   if (! lpTopIPDoc)

      return;

#if defined( USE_DOCTOOLS )

   if (lpTopIPDoc && ! lpContainerDoc->m_fMyToolsOnDoc) {

      /* if we had doc tools we would negotiate for toolbar space at

      **    doc level and SHOW them.

      */

      /* we do NOT have doc level tools, so we just call

      **    SetBorderSpace() to indicate to the top doc that

      **    our object does not need tool space.

      */

      lpContainerDoc->m_fMyToolsOnDoc = TRUE;

      return;

   }

#else   // ! USE_DOCTOOLS

#if defined( INPLACE_CNTRSVR )

   if (lpContainerDoc->m_DocType == DOCTYPE_EMBEDDEDOBJECT) {

      /* this says i do not need space, so the top doc should

      **    leave its tools behind

      */

      lpTopIPDoc->lpVtbl->SetBorderSpace(lpTopIPDoc, NULL);

      return;

   }

#else

   lpTopIPDoc->lpVtbl->SetBorderSpace(

         lpTopIPDoc,

         (LPCBORDERWIDTHS)&g_rectNull

   );

#endif

#endif  // ! USE_DOCTOOLS

}

#endif  // INPLACE_CNTRSVR || INPLACE_MDICNTR

/* ContainerDoc_ContextSensitiveHelp

** ---------------------------------

**    forward the ContextSensitiveHelp mode on to any in-place objects

**    that currently have their window visible. this informs the

**    objects whether to give help or take action on subsequent mouse

**    clicks and menu commands. this function is called from our

**    IOleInPlaceSite::ContextSensitiveHelp implementation.

**

** OLE2NOTE: see context sensitive help technote (CSHELP.DOC).

**    This function is called when SHIFT-F1 context sensitive help is

**    entered. the cursor should then change to a question mark

**    cursor and the app should enter a modal state where the next

**    mouse click does not perform its normal action but rather

**    gives help corresponding to the location clicked. if the app

**    does not implement a help system, it should at least eat the

**    click and do nothing.

*/

void ContainerDoc_ContextSensitiveHelp(

      LPCONTAINERDOC  lpContainerDoc,

      BOOL            fEnterMode,

      BOOL            fInitiatedByObj

)

{

   LPOLEDOC lpOleDoc = (LPOLEDOC)lpContainerDoc;

   LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;

   int i;

   LPLINE lpLine;

   lpOleDoc->m_fCSHelpMode = fEnterMode;

   if (g_fInsideOutContainer) {

      if (lpContainerDoc->m_cIPActiveObjects) {

         for (i = 0; i < lpLL->m_nNumLines; i++) {

            lpLine=LineList_GetLine(lpLL, i);

            if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE)) {

               LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)lpLine;

               ContainerLine_ContextSensitiveHelp(

                     lpContainerLine, fEnterMode);

            }

         }

      }

   }

   else if (! fInitiatedByObj) {

      /* OLE2NOTE: (OUTSIDE-IN CONTAINER) if there is a currently

      **    UIActive object (ie. its window is visible), we must

      **    forward the ContextSensitiveHelp mode on to the

      **    object--assuming it was not the object that initiated the

      **    context sensitve help mode.

      */

      LPCONTAINERLINE lpLastUIActiveLine =

            lpContainerDoc->m_lpLastUIActiveLine;

      if (lpLastUIActiveLine && lpLastUIActiveLine->m_fUIActive) {

         ContainerLine_ContextSensitiveHelp(lpLastUIActiveLine,fEnterMode);

      }

   }

}

/* ContainerDoc_ForwardPaletteChangedMsg

** -------------------------------------

**    forward the WM_PALETTECHANGED message (via SendMessage) to any

**    in-place objects that currently have their window visible. this

**    gives these objects the chance to select their palette as a

**    BACKGROUND palette.

**

**    SEE THE TECHNOTE FOR DETAILED INFORMATION ON PALETTE COORDINATION

**

**    OLE2NOTE: For containers and objects to manage palettes properly

**    (when objects are getting inplace edited) they should follow a

**    set of rules.

**

**    Rule 1: The Container can decide if it wants to own the palette or

**    it wants to allow its UIActive object to own the palette.

**    a) If the container wants to let its UIActive object own the

**    palette then it should forward WM_QUERYNEWPALETTE to the object

**    when it is received to the top frame window. also it should send

**    WM_QUERYNEWPALETTE to the object in its

**    IOleInPlaceFrame::SetActiveObject implementation. if the object

**    is given ownership of the palette, then it owns the palette until

**    it is UIDeactivated.

**    b) If the container wants to own the palette it should NOT send

**    WM_QUERYNEWPALETTE to the UIActive object.

**

**    Rule 2: Whether the container wants to own the palette or not, it

**    should forward the WM_PALETTECHANGED to the immediate child

**    inplace active objects in its documents. if it is an inside-out

**    style container then it must forward it to ALL objects that

**    currently have their windows visible. When the object recives the

**    WM_PALETTECHANGED message it must select its color palette as the

**    background palette. When the objects are in loaded state they will be

**    drawn by (OLE) by selecting their palettes as background palettes

**    anyway.

**

**    Note: IOleObject::SetColorScheme is not related to the palette

**    issue.

*/

void ContainerDoc_ForwardPaletteChangedMsg(

      LPCONTAINERDOC  lpContainerDoc,

      HWND            hwndPalChg

)

{

   LPLINELIST lpLL;

   int i;

   LPLINE lpLine;

   if (!lpContainerDoc)

      return;

   lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;

   if (g_fInsideOutContainer) {

      if (lpContainerDoc->m_cIPActiveObjects) {

         for (i = 0; i < lpLL->m_nNumLines; i++) {

            lpLine=LineList_GetLine(lpLL, i);

            if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE)) {

               LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)lpLine;

               ContainerLine_ForwardPaletteChangedMsg(

                     lpContainerLine, hwndPalChg);

            }

         }

      }

   }

   else {

      /* OLE2NOTE: (OUTSIDE-IN CONTAINER) if there is a currently

      **    UIActive object (ie. its window is visible), we must

      **    forward it the WM_PALETTECHANGED message.

      */

      LPCONTAINERLINE lpLastUIActiveLine =

            lpContainerDoc->m_lpLastUIActiveLine;

      if (lpLastUIActiveLine && lpLastUIActiveLine->m_fUIActive) {

         ContainerLine_ForwardPaletteChangedMsg(

               lpLastUIActiveLine, hwndPalChg);

      }

   }

}

/*************************************************************************

** ContainerLine Support Functions and Interfaces

*************************************************************************/

/* ContainerLine_UIDeactivate

** --------------------------

**    tell the OLE object associated with the ContainerLine to

**    UIDeactivate. this informs the in-place server to tear down

**    the UI and window that it put up for the object. it will remove

**    its active editor menus and any frame and object adornments

**    (eg. toolbars, rulers, etc.).

*/

void ContainerLine_UIDeactivate(LPCONTAINERLINE lpContainerLine)

{

   HRESULT hrErr;

   if (!lpContainerLine || !lpContainerLine->m_fUIActive)

      return;

   OLEDBG_BEGIN2("IOleInPlaceObject::UIDeactivate called\r\n")

   hrErr = lpContainerLine->m_lpOleIPObj->lpVtbl->UIDeactivate(

         lpContainerLine->m_lpOleIPObj);

   OLEDBG_END2

   if (hrErr != NOERROR) {

      OleDbgOutHResult("IOleInPlaceObject::UIDeactivate returned", hrErr);

   }

}

/* ContainerLine_UpdateInPlaceObjectRects

** -------------------------------------

**    Update the PosRect and ClipRect of the given line

**    currently in-place active

**    object. if there is no object active in-place, then do nothing.

**

**    OLE2NOTE: this function should be called when an action occurs

**    that changes either the position of the object in the document

**    (eg. changing document margins changes PosRect) or the clipRect

**    changes (eg. resizing the document window changes the ClipRect).

*/

void ContainerLine_UpdateInPlaceObjectRects(

      LPCONTAINERLINE lpContainerLine,

      LPRECT          lprcClipRect

)

{

   LPCONTAINERDOC lpContainerDoc = lpContainerLine->m_lpDoc;

   RECT rcClipRect;

   RECT rcPosRect;

   if (! lpContainerLine->m_fIpVisible)

      return;

   if (! lprcClipRect) {

      ContainerDoc_GetClipRect(lpContainerDoc, (LPRECT)&rcClipRect);

      lprcClipRect = (LPRECT)&rcClipRect;

   }

#if defined( _DEBUG )

   OleDbgOutRect3(

         "ContainerLine_UpdateInPlaceObjectRects (ClipRect)",

         (LPRECT)&rcClipRect

   );

#endif

   ContainerLine_GetPosRect(lpContainerLine,(LPRECT)&rcPosRect);

#if defined( _DEBUG )

   OleDbgOutRect3(

      "ContainerLine_UpdateInPlaceObjectRects (PosRect)",(LPRECT)&rcPosRect);

#endif

   OLEDBG_BEGIN2("IOleInPlaceObject::SetObjectRects called\r\n")

   lpContainerLine->m_lpOleIPObj->lpVtbl->SetObjectRects(

         lpContainerLine->m_lpOleIPObj,

         (LPRECT)&rcPosRect,

         lprcClipRect

   );

   OLEDBG_END2

}

/* ContainerLine_ContextSensitveHelp

** ---------------------------------

**    forward the ContextSensitiveHelp mode on to the in-place object

**    if it currently has its window visible. this informs the

**    object whether to give help or take action on subsequent mouse

**    clicks and menu commands.

**

**    this function is called from ContainerDoc_ContextSensitiveHelp

**    function as a result of a call to

**    IOleInPlaceSite::ContextSensitiveHelp if the in-place container

**    is operating as an in-side out container.

*/

void ContainerLine_ContextSensitiveHelp(

      LPCONTAINERLINE lpContainerLine,

      BOOL            fEnterMode

)

{

   if (! lpContainerLine->m_fIpVisible)

      return;

   OLEDBG_BEGIN2("IOleInPlaceObject::ContextSensitiveHelp called\r\n")

   lpContainerLine->m_lpOleIPObj->lpVtbl->ContextSensitiveHelp(

         lpContainerLine->m_lpOleIPObj, fEnterMode);

   OLEDBG_END2

}

/* ContainerLine_ForwardPaletteChangedMsg

** --------------------------------------

**    forward it the WM_PALETTECHANGED message (via SendMessage) to the

**    in-place object if it currently has its window visible. this

**    gives the object the chance to select its palette as a BACKGROUND

**    palette if it doesn't own the palette--or as the

**    foreground palette if it currently DOES own the palette.

**

**    SEE THE TECHNOTE FOR DETAILED INFORMATION ON PALETTE COORDINATION

*/

void ContainerLine_ForwardPaletteChangedMsg(

      LPCONTAINERLINE lpContainerLine,

      HWND             hwndPalChg

)

{

   if (! lpContainerLine->m_fIpVisible)

      return;

   if (lpContainerLine->m_hWndIpObject)

   {

       SendMessage(

             lpContainerLine->m_hWndIpObject,

             WM_PALETTECHANGED,

             (WPARAM)hwndPalChg,

             0L

       );

   }

}

/*************************************************************************

** ContainerLine::IOleInPlaceSite interface implementation

*************************************************************************/

STDMETHODIMP CntrLine_IPSite_QueryInterface(

      LPOLEINPLACESITE    lpThis,

      REFIID              riid,

      LPVOID FAR*         lplpvObj

)

{

   LPCONTAINERLINE lpContainerLine =

         ((struct COleInPlaceSiteImpl FAR*)lpThis)->lpContainerLine;

   return ContainerLine_QueryInterface(lpContainerLine, riid, lplpvObj);

}

STDMETHODIMP_(ULONG) CntrLine_IPSite_AddRef(LPOLEINPLACESITE lpThis)

{

   LPCONTAINERLINE lpContainerLine =

         ((struct COleInPlaceSiteImpl FAR*)lpThis)->lpContainerLine;

   OleDbgAddRefMethod(lpThis, "IOleInPlaceSite");

   return ContainerLine_AddRef(lpContainerLine);

}

STDMETHODIMP_(ULONG) CntrLine_IPSite_Release(LPOLEINPLACESITE lpThis)

{

   LPCONTAINERLINE lpContainerLine =

         ((struct COleInPlaceSiteImpl FAR*)lpThis)->lpContainerLine;

   OleDbgReleaseMethod(lpThis, "IOleInPlaceSite");

   return ContainerLine_Release(lpContainerLine);

}

STDMETHODIMP CntrLine_IPSite_GetWindow(

   LPOLEINPLACESITE    lpThis,

   HWND FAR*           lphwnd

)

{

   LPCONTAINERLINE lpContainerLine =

         ((struct COleInPlaceSiteImpl FAR*)lpThis)->lpContainerLine;

   // artificial AddRef in case object is destroyed during call

   CntrLine_IPSite_AddRef(lpThis);

   OleDbgOut2("CntrLine_IPSite_GetWindow\r\n");

   *lphwnd = LineList_GetWindow(

         &((LPOUTLINEDOC)lpContainerLine->m_lpDoc)->m_LineList);

   // release artificial AddRef

   CntrLine_IPSite_Release(lpThis);

   return NOERROR;

}

// IOleInPlaceSite::ContextSensitiveHelp

STDMETHODIMP CntrLine_IPSite_ContextSensitiveHelp(

   LPOLEINPLACESITE    lpThis,

   BOOL                fEnterMode

)

{

   LPCONTAINERLINE lpContainerLine =

         ((struct COleInPlaceSiteImpl FAR*)lpThis)->lpContainerLine;

   LPOLEDOC lpOleDoc = (LPOLEDOC)lpContainerLine->m_lpDoc;

   // artificial AddRef in case object is destroyed during call

   CntrLine_IPSite_AddRef(lpThis);

   OleDbgOut2("CntrLine_IPSite_ContextSensitiveHelp\r\n");

   /* OLE2NOTE: see context sensitive help technote (CSHELP.DOC).

   **    This method is called when SHIFT-F1 context sensitive help is

   **    entered. the cursor should then change to a question mark

   **    cursor and the app should enter a modal state where the next

   **    mouse click does not perform its normal action but rather

   **    gives help corresponding to the location clicked. if the app

   **    does not implement a help system, it should at least eat the

   **    click and do nothing.

   **

   **    NOTE: the implementation here is specific to an SDI simple

   **    container. an MDI container or container/server application

   **    would have additional work to do (see the technote).

   **

   **    NOTE: (INSIDE-OUT CONTAINER) if there are currently

   **    any in-place objects active with their windows visible

   **    (ie. fIpVisible), we must forward the

   **    ContextSensitiveHelp mode on to these objects.

   */

   ContainerDoc_ContextSensitiveHelp(

            lpContainerLine->m_lpDoc,fEnterMode,TRUE /*InitiatedByObj*/);

   // release artificial AddRef

   CntrLine_IPSite_Release(lpThis);

   return NOERROR;

}

STDMETHODIMP CntrLine_IPSite_CanInPlaceActivate(LPOLEINPLACESITE lpThis)

{

   LPCONTAINERLINE lpContainerLine =

         ((struct COleInPlaceSiteImpl FAR*)lpThis)->lpContainerLine;

   OleDbgOut2("CntrLine_IPSite_CanInPlaceActivate\r\n");

   /* OLE2NOTE: the container can NOT allow in-place activation if it

   **    is currently displaying the object as an ICON

   **    (DVASPECT_ICON). it can ONLY do in-place activation if it is

   **    displaying the DVASPECT_CONTENT of the OLE object.

   */

   if (lpContainerLine->m_dwDrawAspect == DVASPECT_CONTENT)

      return NOERROR;

   else

      return ResultFromScode(S_FALSE);

}

STDMETHODIMP CntrLine_IPSite_OnInPlaceActivate(LPOLEINPLACESITE lpThis)

{

   LPCONTAINERLINE lpContainerLine =

         ((struct COleInPlaceSiteImpl FAR*)lpThis)->lpContainerLine;

   LPCONTAINERDOC lpContainerDoc = lpContainerLine->m_lpDoc;

   SCODE sc = S_OK;

   // artificial AddRef in case object is destroyed during call

   CntrLine_IPSite_AddRef(lpThis);

   OLEDBG_BEGIN2("CntrLine_IPSite_OnInPlaceActivate\r\n");

   /* OLE2NOTE: (OUTSIDE-IN CONTAINER) as a policy for managing

   **    running in-place servers, we will keep only 1 inplace server

   **    active at any given time. so when we start to inp-place activate

   **    another line, then we want to shut down the previously

   **    activated server. in this way we keep at most one inplace

   **    server active at a time. this is NOT a required policy. apps

   **    may choose to have a more sophisticated strategy. inside-out

   **    containers will HAVE to have a more sophisticated strategy,

   **    because they need (at a minimum) to keep all visible object

   **    servers running.

   **

   **    if the in-place activation is the result of activating a

   **    linked object in another container, then we may arrive at

   **    this method while another object is currently active.

   **    normally, if the object is in-place activated by

   **    double-clicking or Edit.<verb> from our own container, then

   **    the previous in-place object would have been de-activated in

   **    ContainerLine_DoVerb method.

   */

   if (!g_fInsideOutContainer) {

      if (lpContainerDoc->m_lpLastIpActiveLine) {

         ContainerDoc_ShutDownLastInPlaceServerIfNotNeeded(

               lpContainerDoc, lpContainerLine);

      }

      lpContainerDoc->m_lpLastIpActiveLine = lpContainerLine;

   }

   /* OLE2NOTE: to avoid LRPC problems it is important to cache the

   **    IOleInPlaceObject* pointer and NOT to call QueryInterface

   **    each time it is needed.

   */

   lpContainerLine->m_lpOleIPObj = (LPOLEINPLACEOBJECT)

         ContainerLine_GetOleObject(lpContainerLine,&IID_IOleInPlaceObject);

   if (! lpContainerLine->m_lpOleIPObj) {

#if defined( _DEBUG )

      OleDbgAssertSz(

            lpContainerLine->m_lpOleIPObj!=NULL,

            "OLE object must support IOleInPlaceObject"

      );

#endif

      // release artificial AddRef

      CntrLine_IPSite_Release(lpThis);

      return ResultFromScode(E_FAIL); // ERROR: refuse to in-place activate

   }

   lpContainerLine->m_fIpActive        = TRUE;

   lpContainerLine->m_fIpVisible       = TRUE;

   OLEDBG_BEGIN2("IOleInPlaceObject::GetWindow called\r\n")

   lpContainerLine->m_lpOleIPObj->lpVtbl->GetWindow(

         lpContainerLine->m_lpOleIPObj,

         (HWND FAR*)&lpContainerLine->m_hWndIpObject

   );

   OLEDBG_END2

   if (! lpContainerLine->m_fIpServerRunning) {

      /* OLE2NOTE: it is VERY important that an in-place container

      **    that also support linking to embeddings properly manage

      **    the running of its in-place objects. in an outside-in

      **    style in-place container, when the user clicks

      **    outside of the in-place active object, the object gets

      **    UIDeactivated and the object hides its window. in order

      **    to make the object fast to reactivate, the container

      **    deliberately does not call IOleObject::Close. the object

      **    stays running in the invisible unlocked state. the idea

      **    here is if the user simply clicks outside of the object

      **    and then wants to double click again to re-activate the

      **    object, we do not want this to be slow. if we want to

      **    keep the object running, however, we MUST Lock it

      **    running. otherwise the object will be in an unstable

      **    state where if a linking client does a "silent-update"

      **    (eg. UpdateNow from the Links dialog), then the in-place

      **    server will shut down even before the object has a chance

      **    to be saved back in its container. this saving normally

      **    occurs when the in-place container closes the object. also

      **    keeping the object in the unstable, hidden, running,

      **    not-locked state can cause problems in some scenarios.

      **    ICntrOtl keeps only one object running. if the user

      **    intiates a DoVerb on another object, then that last

      **    running in-place active object is closed. a more

      **    sophistocated in-place container may keep more object running.

      **    this lock gets unlocked in ContainerLine_CloseOleObject.

      */

      lpContainerLine->m_fIpServerRunning = TRUE;

      OLEDBG_BEGIN2("OleLockRunning(TRUE, 0) called\r\n")

      OleLockRunning((LPUNKNOWN)lpContainerLine->m_lpOleIPObj, TRUE, 0);

      OLEDBG_END2

   }

   lpContainerLine->m_lpDoc->m_cIPActiveObjects++;

   OLEDBG_END2

   // release artificial AddRef

   CntrLine_IPSite_Release(lpThis);

   return NOERROR;

}

STDMETHODIMP CntrLine_IPSite_OnUIActivate (LPOLEINPLACESITE lpThis)

{

   LPCONTAINERLINE lpContainerLine =

         ((struct COleInPlaceSiteImpl FAR*)lpThis)->lpContainerLine;

   LPCONTAINERDOC lpContainerDoc = lpContainerLine->m_lpDoc;

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerLine->m_lpDoc;

   LPCONTAINERLINE lpLastUIActiveLine = lpContainerDoc->m_lpLastUIActiveLine;

   // artificial AddRef in case object is destroyed during call

   CntrLine_IPSite_AddRef(lpThis);

   OLEDBG_BEGIN2("CntrLine_IPSite_OnUIActivate\r\n");

   lpContainerLine->m_fUIActive        = TRUE;

   lpContainerDoc->m_fAddMyUI          = FALSE;

   lpContainerDoc->m_lpLastUIActiveLine = lpContainerLine;

   if (g_fInsideOutContainer) {

      /* OLE2NOTE: (INSIDE-OUT CONTAINER) an inside-out style

      **    container must UIDeactivate the previous UIActive object

      **    when a new object is going UIActive. since the inside-out

      **    objects have their own windows visible, it is possible

      **    that a click directly in an another server window will

      **    cause it to UIActivate. OnUIActivate is the containers

      **    notification that such has occured. it must then

      **    UIDeactivate the other because at most one object can be

      **    UIActive at a time.

      */

      if (lpLastUIActiveLine && (lpLastUIActiveLine!=lpContainerLine)) {

         ContainerLine_UIDeactivate(lpLastUIActiveLine);

         // Make sure new UIActive window is on top of all others

         SetWindowPos(

               lpContainerLine->m_hWndIpObject,

               HWND_TOPMOST,

               0,0,0,0,

               SWP_NOMOVE | SWP_NOSIZE

         );

         OLEDBG_END2

         goto cleanup;

      }

   }

   lpContainerDoc->m_hWndUIActiveObj = lpContainerLine->m_hWndIpObject;

#if defined( USE_FRAMETOOLS )

   ContainerDoc_RemoveFrameLevelTools(lpContainerDoc);

#endif

#if defined( USE_DOCTOOLS )

   ContainerDoc_RemoveDocLevelTools(lpContainerDoc);

#endif

   OLEDBG_END2

cleanup:

   // release artificial AddRef

   CntrLine_IPSite_Release(lpThis);

   return NOERROR;

}

STDMETHODIMP CntrLine_IPSite_GetWindowContext(

   LPOLEINPLACESITE            lpThis,

   LPOLEINPLACEFRAME FAR*      lplpFrame,

   LPOLEINPLACEUIWINDOW FAR*   lplpDoc,

   LPRECT                      lprcPosRect,

   LPRECT                      lprcClipRect,

   LPOLEINPLACEFRAMEINFO       lpFrameInfo

)

{

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)g_lpApp;

   LPCONTAINERLINE lpContainerLine =

         ((struct COleInPlaceSiteImpl FAR*)lpThis)->lpContainerLine;

   // artificial AddRef in case object is destroyed during call

   CntrLine_IPSite_AddRef(lpThis);

   OLEDBG_BEGIN2("CntrLine_IPSite_GetWindowContext\r\n")

   /* OLE2NOTE: The server should fill in the "cb" field so that the

   **    container can tell what size structure the server is

   **    expecting. this enables this structure to be easily extended

   **    in future releases of OLE. the container should check this

   **    field so that it doesn't try to use fields that do not exist

   **    since the server may be using an old structure definition.

   **    Since this is the first release of OLE2.0, the structure is

   **    guaranteed to be at least large enough for the current

   **    definition of OLEINPLACEFRAMEINFO struct. thus we do NOT need

   **    to consider this an error if the server did not fill in this

   **    field correctly. this server may have trouble in the future,

   **    however, when the structure is extended.

   */

   *lplpFrame = (LPOLEINPLACEFRAME)&lpContainerApp->m_OleInPlaceFrame;

   (*lplpFrame)->lpVtbl->AddRef(*lplpFrame);   // must return AddRef'ed ptr

   // OLE2NOTE: an MDI app would have to provide *lplpDoc

   *lplpDoc  = NULL;

   ContainerLine_GetPosRect(lpContainerLine, lprcPosRect);

   ContainerDoc_GetClipRect(lpContainerLine->m_lpDoc, lprcClipRect);

   OleDbgOutRect3("CntrLine_IPSite_GetWindowContext (PosRect)", lprcPosRect);

   OleDbgOutRect3("CntrLine_IPSite_GetWindowContext (ClipRect)",lprcClipRect);

   lpFrameInfo->hwndFrame      = lpOutlineApp->m_hWndApp;

#if defined( MDI_VERSION )

   lpFrameInfo->fMDIApp        = TRUE;

#else

   lpFrameInfo->fMDIApp        = FALSE;

#endif

   lpFrameInfo->haccel         = lpContainerApp->m_hAccelIPCntr;

   lpFrameInfo->cAccelEntries  =

      GetAccelItemCount(lpContainerApp->m_hAccelIPCntr);

   OLEDBG_END2

   // release artificial AddRef

   CntrLine_IPSite_Release(lpThis);

   return NOERROR;

}

STDMETHODIMP CntrLine_IPSite_Scroll(

   LPOLEINPLACESITE    lpThis,

   SIZE                scrollExtent

)

{

   OleDbgOut2("CntrLine_IPSite_Scroll\r\n");

   return ResultFromScode(E_FAIL);

}

STDMETHODIMP CntrLine_IPSite_OnUIDeactivate(

   LPOLEINPLACESITE    lpThis,

   BOOL                fUndoable

)

{

   LPCONTAINERLINE lpContainerLine =

         ((struct COleInPlaceSiteImpl FAR*)lpThis)->lpContainerLine;

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerLine->m_lpDoc;

   LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP) g_lpApp;

   LPLINELIST lpLL;

   int nIndex;

   MSG msg;

   HRESULT hrErr;

   // artificial AddRef in case object is destroyed during call

   CntrLine_IPSite_AddRef(lpThis);

   OLEDBG_BEGIN2("CntrLine_IPSite_OnUIDeactivate\r\n")

   lpContainerLine->m_fUIActive = FALSE;

   lpContainerLine->m_fIpChangesUndoable = fUndoable;

   lpContainerLine->m_lpDoc->m_hWndUIActiveObj = NULL;

   if (lpContainerLine == lpContainerLine->m_lpDoc->m_lpLastUIActiveLine) {

      lpContainerLine->m_lpDoc->m_lpLastUIActiveLine = NULL;

      /* OLE2NOTE: here we look ahead if there is a DBLCLK sitting in our

      **    message queue. if so, it could result in in-place activating

      **    another object. we want to avoid placing our tools and

      **    repainting if immediately another object is going to do the

      **    same. SO, if there is a DBLCLK in the queue for this document

      **    we will only set the fAddMyUI flag to indicate that this work

      **    is still to be done. if another object actually in-place

      **    activates then this flag will be cleared in

      **    IOleInPlaceSite::OnUIActivate. if it does NOT get cleared,

      **    then at the end of processing the DBLCLK message in our

      **    OutlineDocWndProc we will put our tools back.

      */

      if (! PeekMessage(&msg, lpOutlineDoc->m_hWndDoc,

            WM_LBUTTONDBLCLK, WM_LBUTTONDBLCLK,

            PM_NOREMOVE | PM_NOYIELD)) {

         /* OLE2NOTE: You need to generate QueryNewPalette only if

         **    you own the top level frame (ie. you are a top-level

         **    inplace container).

         */

         OleApp_QueryNewPalette((LPOLEAPP)g_lpApp);

#if defined( USE_DOCTOOLS )

         ContainerDoc_AddDocLevelTools(lpContainerLine->m_lpDoc);

#endif

#if defined( USE_FRAMETOOLS )

         ContainerDoc_AddFrameLevelUI(lpContainerLine->m_lpDoc);

#endif

      } else {

         lpContainerLine->m_lpDoc->m_fAddMyUI = TRUE;

      }

      /* OLE2NOTE: we should re-take focus. the in-place server window

      **    previously had the focus; this window has just been removed.

      */

      SetFocus(OutlineDoc_GetWindow((LPOUTLINEDOC)lpContainerLine->m_lpDoc));

      // force the line to redraw to remove in-place active hatch

      lpLL = OutlineDoc_GetLineList(lpOutlineDoc);

      nIndex = LineList_GetLineIndex(lpLL, (LPLINE)lpContainerLine);

      LineList_ForceLineRedraw(lpLL, nIndex, TRUE);

   }

#if defined( UNDOSUPPORTED )

   /* OLE2NOTE: an outside-in style container that supports UNDO would

   **    call IOleObject::DoVerb(OLEIVERB_HIDE) to make the in-place

   **    object go invisible. when it wants the in-place active object

   **    to discard its undo state, it would call

   **    IOleInPlaceObject::InPlaceDeactivate when it wants the object

   **    to discard its undo state. there is no need for an outside-in

   **    style container to call

   **    IOleObject::DoVerb(OLEIVERB_DISCARDUNDOSTATE). if either the

   **    container or the object do not support UNDO, then the

   **    container might as well immediately call InPlaceDeactivate

   **    instead of calling DoVerb(HIDE).

   **

   **    an inside-out style container that supports UNDO would simply

   **    UIDeactivate the object. it would call

   **    IOleObject::DoVerb(OLEIVERB_DISCARDUNDOSTATE) when it wants

   **    the object discard its undo state. it would call

   **    IOleInPlaceObject::InPlaceDeactivate if it wants the object

   **    to take down its window.

   */

   if (! g_fInsideOutContainer || !lpContainerLine->m_fInsideOutObj) {

      if (lpContainerLine->m_fIpChangesUndoable) {

         ContainerLine_DoVerb(

               lpContainerLine,OLEIVERB_HIDE,NULL,FALSE,FALSE);

      } else {

         lpContainerLine->m_lpOleIPObj->lpVtbl->InPlaceDeactivate(

               lpContainerLine->m_lpOleIPObj);

      }

      lpContainerLine->m_fIpVisible = FALSE;

      lpContainerLine->m_hWndIpObject = NULL;

   }

#else

   /* OLE2NOTE: an outside-in style container that does NOT support

   **    UNDO would immediately tell the UIDeactivated server (UI

   **    removed) to IOleInPlaceObject::InPlaceDeactivate.

   **

   **    an inside-out style container that does NOT support UNDO

   **    would call IOleObject::DoVerb(OLEIVERB_DISCARDUNDOSTATE) to

   **    tell the object to discard its undo state. it would call

   **    IOleInPlaceObject::InPlaceDeactivate if it wants the object

   **    to take down its window.

   */

   if (g_fInsideOutContainer) {

      if (lpContainerLine->m_fInsideOutObj) {

         if (lpContainerLine->m_fIpChangesUndoable) {

            OLEDBG_BEGIN3("ContainerLine_DoVerb(OLEIVERB_DISCARDUNDOSTATE) called!\r\n")

            ContainerLine_DoVerb(lpContainerLine,

                  OLEIVERB_DISCARDUNDOSTATE,NULL,FALSE,FALSE);

            OLEDBG_END3

         }

      } else {    // !fInsideOutObj

         /* OLE2NOTE: (INSIDEOUT CONTAINER) if the object is not

         **    registered OLEMISC_ACTIVATEWHENVISIBLE, then we will

         **    make the object behave in an outside-in manner. since

         **    we do NOT deal with UNDO we can simply

         **    InPlaceDeactivate the object. it should NOT be

         **    allowed to leave its window visible when

         **    UIDeactivated.

         */

         OLEDBG_BEGIN2("IOleInPlaceObject::InPlaceDeactivate called\r\n")

         hrErr = lpContainerLine->m_lpOleIPObj->lpVtbl->InPlaceDeactivate(

                  lpContainerLine->m_lpOleIPObj);

         OLEDBG_END2

         if (hrErr != NOERROR) {

            OleDbgOutHResult("IOleInPlaceObject::InPlaceDeactivate returned", hrErr);

         }

      }

   } else {

      /* OLE2NOTE: (OUTSIDE-IN CONTAINER) since we do NOT deal with

      **    UNDO we can simply InPlaceDeactivate the object. it

      **    should NOT be allowed to leave its window visible when

      **    UIDeactivated.

        **

        **    NOTE: In-place servers must handle InPlaceDeactivate

        **    being called before its call to

        **    IOleInPlaceSite::OnUIDeactivate returns. in case there

        **    are misbehaving servers out there, one way to work around

        **    this problem is to call

        **    IOleObject::DoVerb(OLEIVERB_HIDE...) here.

      */

      OLEDBG_BEGIN2("IOleInPlaceObject::InPlaceDeactivate called\r\n")

      hrErr = lpContainerLine->m_lpOleIPObj->lpVtbl->InPlaceDeactivate(

            lpContainerLine->m_lpOleIPObj);

      OLEDBG_END2

      if (hrErr != NOERROR) {

         OleDbgOutHResult("IOleInPlaceObject::InPlaceDeactivate returned", hrErr);

      }

   }

#endif // ! UNDOSUPPORTED

   OLEDBG_END2

   // release artificial AddRef

   CntrLine_IPSite_Release(lpThis);

   return NOERROR;

}

STDMETHODIMP CntrLine_IPSite_OnInPlaceDeactivate(LPOLEINPLACESITE lpThis)

{

   LPCONTAINERLINE lpContainerLine =

         ((struct COleInPlaceSiteImpl FAR*)lpThis)->lpContainerLine;

   // artificial AddRef in case object is destroyed during call

   CntrLine_IPSite_AddRef(lpThis);

   OLEDBG_BEGIN2("CntrLine_IPSite_OnInPlaceDeactivate\r\n");

   lpContainerLine->m_fIpActive            = FALSE;

   lpContainerLine->m_fIpVisible           = FALSE;

   lpContainerLine->m_fIpChangesUndoable   = FALSE;

   lpContainerLine->m_hWndIpObject         = NULL;

   OleStdRelease((LPUNKNOWN) lpContainerLine->m_lpOleIPObj);

   lpContainerLine->m_lpOleIPObj = NULL;

   lpContainerLine->m_lpDoc->m_cIPActiveObjects--;

   OLEDBG_END2

   // release artificial AddRef

   CntrLine_IPSite_Release(lpThis);

   return NOERROR;

}

STDMETHODIMP CntrLine_IPSite_DiscardUndoState(LPOLEINPLACESITE lpThis)

{

   OleDbgOut2("CntrLine_IPSite_DiscardUndoState\r\n");

   return NOERROR;

}

STDMETHODIMP CntrLine_IPSite_DeactivateAndUndo(LPOLEINPLACESITE lpThis)

{

   OleDbgOut2("CntrLine_IPSite_DeactivateAndUndo\r\n");

   return NOERROR;

}

STDMETHODIMP CntrLine_IPSite_OnPosRectChange(

   LPOLEINPLACESITE    lpThis,

   LPCRECT             lprcPosRect

)

{

   LPCONTAINERLINE lpContainerLine =

         ((struct COleInPlaceSiteImpl FAR*)lpThis)->lpContainerLine;

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerLine->m_lpDoc;

   LPSCALEFACTOR lpscale = OutlineDoc_GetScaleFactor(lpOutlineDoc);

   LPLINE lpLine = (LPLINE)lpContainerLine;

   LPLINELIST lpLL;

   int nIndex;

   RECT rcClipRect;

   RECT rcNewPosRect;

   SIZEL sizelPix;

   SIZEL sizelHim;

   int nIPObjHeight = lprcPosRect->bottom - lprcPosRect->top;

   int nIPObjWidth = lprcPosRect->right - lprcPosRect->left;

   // artificial AddRef in case object is destroyed during call

   CntrLine_IPSite_AddRef(lpThis);

   OLEDBG_BEGIN2("CntrLine_IPSite_OnPosRectChange\r\n")

   OleDbgOutRect3("CntrLine_IPSite_OnPosRectChange (PosRect --IN)", (LPRECT)lprcPosRect);

   /* OLE2NOTE: if the in-place container does NOT impose any

   **    size contraints on its in-place active objects, then it may

   **    simply grant the size requested by the object by immediately

   **    calling IOleInPlaceObject::SetObjectRects with the

   **    lprcPosRect passed by the in-place object.

   **

   **    Container Outline, however, imposes a size constraint on its

   **    embedded objects (see comment in ContainerLine_UpdateExtent),

   **    thus it is necessary to calculate the size that the in-place

   **    active object is allowed to be.

   **

   **    Here we need to know the new extents of the in-place object.

   **    We can NOT directly ask the object via IOleObject::GetExtent

   **    because this method will retreive the extents of the last

   **    cached metafile. the cache has not yet been updated by this

   **    point. We can not reliably call IOleObject::GetExtent

   **    because, despite the fact that will be delegated to the

   **    object properly, some objects may not have reformated their

   **    object and computed the new extents at the time of calling

   **    OnPosRectChange.

   **

   **    the best we can do to get the new extents of the object is

   **    to determine the scale factor that the object was operating at

   **    prior to the OnPosRect call and scale the new lprcPosRect

   **    using this scale factor back to HIMETRIC units.

   */

   if (lpContainerLine->m_sizeInHimetric.cx > 0 &&

      lpContainerLine->m_sizeInHimetric.cy > 0) {

      sizelHim.cx = lpLine->m_nWidthInHimetric;

      sizelHim.cy = lpLine->m_nHeightInHimetric;

      XformSizeInHimetricToPixels(NULL, &sizelHim, &sizelPix);

      sizelHim.cx = lpContainerLine->m_sizeInHimetric.cx *

               nIPObjWidth / sizelPix.cx;

      sizelHim.cy = lpContainerLine->m_sizeInHimetric.cy *

               nIPObjHeight / sizelPix.cy;

      // Convert size back to 100% zoom

      sizelHim.cx = sizelHim.cx * lpscale->dwSxD / lpscale->dwSxN;

      sizelHim.cy = sizelHim.cy * lpscale->dwSyD / lpscale->dwSyN;

   } else {

      sizelHim.cx = (long)DEFOBJWIDTH;

      sizelHim.cy = (long)DEFOBJHEIGHT;

      XformSizeInHimetricToPixels(NULL, &sizelHim, &sizelPix);

      sizelHim.cx = sizelHim.cx * nIPObjWidth / sizelPix.cx;

      sizelHim.cy = sizelHim.cy * nIPObjHeight / sizelPix.cy;

   }

   ContainerLine_UpdateExtent(lpContainerLine, &sizelHim);

   ContainerLine_GetPosRect(lpContainerLine, (LPRECT)&rcNewPosRect);

   ContainerDoc_GetClipRect(lpContainerLine->m_lpDoc, (LPRECT)&rcClipRect);

#if defined( _DEBUG )

   OleDbgOutRect3("CntrLine_IPSite_OnPosRectChange (PosRect --OUT)",

         (LPRECT)&rcNewPosRect);

   OleDbgOutRect3("CntrLine_IPSite_OnPosRectChange (ClipRect--OUT)",

         (LPRECT)&rcClipRect);

#endif

   OLEDBG_BEGIN2("IOleInPlaceObject::SetObjectRects called\r\n")

   lpContainerLine->m_lpOleIPObj->lpVtbl->SetObjectRects(

         lpContainerLine->m_lpOleIPObj,

         (LPRECT)&rcNewPosRect,

         (LPRECT)&rcClipRect

   );

   OLEDBG_END2

   /* OLE2NOTE: (INSIDEOUT CONTAINER) Because this object just changed

   **    size, this may cause other in-place active objects in the

   **    document to move. in ICNTROTL's case any object below this

   **    object would be affected. in this case it would be necessary

   **    to call SetObjectRects to each affected in-place active object.

   */

   if (g_fInsideOutContainer) {

      lpLL = OutlineDoc_GetLineList(lpOutlineDoc);

      nIndex = LineList_GetLineIndex(lpLL, (LPLINE)lpContainerLine);

      ContainerDoc_UpdateInPlaceObjectRects(

            lpContainerLine->m_lpDoc, nIndex);

   }

   OLEDBG_END2

   // release artificial AddRef

   CntrLine_IPSite_Release(lpThis);

   return NOERROR;

}


CNTRLINE.C  (OUTLINE Sample)

/*************************************************************************

**

**    OLE 2 Container Sample Code

**

**    cntrline.c

**

**    This file contains ContainerLine methods.

**

**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

**

*************************************************************************/

#include "outline.h"

OLEDBGDATA

extern LPOUTLINEAPP         g_lpApp;

extern IUnknownVtbl         g_CntrLine_UnknownVtbl;

extern IOleClientSiteVtbl   g_CntrLine_OleClientSiteVtbl;

extern IAdviseSinkVtbl      g_CntrLine_AdviseSinkVtbl;

#if defined( INPLACE_CNTR )

extern IOleInPlaceSiteVtbl  g_CntrLine_OleInPlaceSiteVtbl;

extern BOOL g_fInsideOutContainer;

#endif  // INPLACE_CNTR

// REVIEW: should use string resource for messages

OLECHAR ErrMsgDoVerb[] = OLESTR("OLE object action failed!");

/* prototype for static functions */

static void InvertDiffRect(LPRECT lprcPix, LPRECT lprcObj, HDC hDC);

/*************************************************************************

** ContainerLine

**    This object represents the location within the container where

**    the embedded/linked object lives. It exposes interfaces to the

**    object that allow the object to get information about its

**    embedding site and to announce notifications of important events

**    (changed, closed, saved)

**

**    The ContainerLine exposes the following interfaces:

**      IUnknown

**      IOleClientSite

**      IAdviseSink

*************************************************************************/

/*************************************************************************

** ContainerLine::IUnknown interface implementation

*************************************************************************/

// IUnknown::QueryInterface

STDMETHODIMP CntrLine_Unk_QueryInterface(

      LPUNKNOWN           lpThis,

      REFIID              riid,

      LPVOID FAR*         lplpvObj

)

{

   LPCONTAINERLINE lpContainerLine =

         ((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine;

   return ContainerLine_QueryInterface(lpContainerLine, riid, lplpvObj);

}

// IUnknown::AddRef

STDMETHODIMP_(ULONG) CntrLine_Unk_AddRef(LPUNKNOWN lpThis)

{

   LPCONTAINERLINE lpContainerLine =

         ((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine;

   OleDbgAddRefMethod(lpThis, "IUnknown");

   return ContainerLine_AddRef(lpContainerLine);

}

// IUnknown::Release

STDMETHODIMP_(ULONG) CntrLine_Unk_Release(LPUNKNOWN lpThis)

{

   LPCONTAINERLINE lpContainerLine =

         ((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine;

   OleDbgReleaseMethod(lpThis, "IUnknown");

   return ContainerLine_Release(lpContainerLine);

}

/*************************************************************************

** ContainerLine::IOleClientSite interface implementation

*************************************************************************/

// IOleClientSite::QueryInterface

STDMETHODIMP CntrLine_CliSite_QueryInterface(

      LPOLECLIENTSITE     lpThis,

      REFIID              riid,

      LPVOID FAR*         lplpvObj

)

{

   LPCONTAINERLINE lpContainerLine =

         ((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine;

   return ContainerLine_QueryInterface(lpContainerLine, riid, lplpvObj);

}

// IOleClientSite::AddRef

STDMETHODIMP_(ULONG) CntrLine_CliSite_AddRef(LPOLECLIENTSITE lpThis)

{

   LPCONTAINERLINE lpContainerLine =

         ((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine;

   OleDbgAddRefMethod(lpThis, "IOleClientSite");

   return ContainerLine_AddRef(lpContainerLine);

}

// IOleClientSite::Release

STDMETHODIMP_(ULONG) CntrLine_CliSite_Release(LPOLECLIENTSITE lpThis)

{

   LPCONTAINERLINE lpContainerLine =

         ((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine;

   OleDbgReleaseMethod(lpThis, "IOleClientSite");

   return ContainerLine_Release(lpContainerLine);

}

// IOleClientSite::SaveObject

STDMETHODIMP CntrLine_CliSite_SaveObject(LPOLECLIENTSITE lpThis)

{

   LPCONTAINERLINE lpContainerLine =

         ((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine;

   LPPERSISTSTORAGE lpPersistStg = lpContainerLine->m_lpPersistStg;

   SCODE sc = S_OK;

   HRESULT hrErr;

   OLEDBG_BEGIN2("CntrLine_CliSite_SaveObject\r\n")

   if (! lpPersistStg) {

      /* OLE2NOTE: The object is NOT loaded. a container must be

      **    prepared for the fact that an object that it thinks it

      **    has unloaded may still call IOleClientSite::SaveObject.

      **    in this case the container should fail the save call and

      **    NOT try to reload the object. this scenario arises if you

      **    have a in-process server (DLL object) which has a

      **    connected linking client. even after the embedding

      **    container unloads the DLL object, the link connection

      **    keeps the object alive. it may then as part of its

      **    shutdown try to call IOCS::SaveObject, but then it is too

      **    late.

      */

      OLEDBG_END2

      return ResultFromScode(E_FAIL);

   }

   // mark ContainerDoc as now dirty

   OutlineDoc_SetModified(

         (LPOUTLINEDOC)lpContainerLine->m_lpDoc, TRUE, TRUE, FALSE);

   /* Tell OLE object to save itself

   ** OLE2NOTE: it is NOT sufficient to ONLY call

   **    IPersistStorage::Save method. it is also necessary to call

   **    WriteClassStg. the helper API OleSave does this automatically.

   */

   OLEDBG_BEGIN2("OleSave called\r\n")

   hrErr=OleSave(lpPersistStg,lpContainerLine->m_lpStg, TRUE/*fSameAsLoad*/);

   OLEDBG_END2

   if (hrErr != NOERROR) {

      OleDbgOutHResult("WARNING: OleSave returned", hrErr);

      sc = GetScode(hrErr);

   }

   // OLE2NOTE: even if OleSave fails, SaveCompleted must be called.

   OLEDBG_BEGIN2("IPersistStorage::SaveCompleted called\r\n")

   hrErr = lpPersistStg->lpVtbl->SaveCompleted(lpPersistStg, NULL);

   OLEDBG_END2

   if (hrErr != NOERROR) {

      OleDbgOutHResult("WARNING: SaveCompleted returned",hrErr);

      if (sc == S_OK)

         sc = GetScode(hrErr);

   }

   OLEDBG_END2

   return ResultFromScode(sc);

}

// IOleClientSite::GetMoniker

STDMETHODIMP CntrLine_CliSite_GetMoniker(

      LPOLECLIENTSITE     lpThis,

      DWORD               dwAssign,

      DWORD               dwWhichMoniker,

      LPMONIKER FAR*      lplpmk

)

{

   LPCONTAINERLINE lpContainerLine;

   lpContainerLine=((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine;

   OLEDBG_BEGIN2("CntrLine_CliSite_GetMoniker\r\n")

   // OLE2NOTE: we must make sure to set output pointer parameters to NULL

   *lplpmk = NULL;

   switch (dwWhichMoniker) {

      case OLEWHICHMK_CONTAINER:

         /* OLE2NOTE: create a FileMoniker which identifies the

         **    entire container document.

         */

         *lplpmk = OleDoc_GetFullMoniker(

               (LPOLEDOC)lpContainerLine->m_lpDoc,

               dwAssign

         );

         break;

      case OLEWHICHMK_OBJREL:

         /* OLE2NOTE: create an ItemMoniker which identifies the

         **    OLE object relative to the container document.

         */

         *lplpmk = ContainerLine_GetRelMoniker(lpContainerLine, dwAssign);

         break;

      case OLEWHICHMK_OBJFULL:

      {

         /* OLE2NOTE: create an absolute moniker which identifies the

         **    OLE object in the container document. this moniker is

         **    created as a composite of the absolute moniker for the

         **    entire document appended with an item moniker which

         **    identifies the OLE object relative to the document.

         */

         *lplpmk = ContainerLine_GetFullMoniker(lpContainerLine, dwAssign);

         break;

      }

   }

   OLEDBG_END2

   if (*lplpmk != NULL)

      return NOERROR;

   else

      return ResultFromScode(E_FAIL);

}

// IOleClientSite::GetContainer

STDMETHODIMP CntrLine_CliSite_GetContainer(

      LPOLECLIENTSITE     lpThis,

      LPOLECONTAINER FAR* lplpContainer

)

{

   LPCONTAINERLINE lpContainerLine;

   HRESULT hrErr;

   // artificial AddRef in case object is deleted during call

   CntrLine_CliSite_AddRef(lpThis);

   OLEDBG_BEGIN2("CntrLine_CliSite_GetContainer\r\n")

   lpContainerLine=((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine;

   hrErr = OleDoc_QueryInterface(

         (LPOLEDOC)lpContainerLine->m_lpDoc,

         &IID_IOleContainer,

         (LPVOID FAR*)lplpContainer

   );

   OLEDBG_END2

   // release artificial AddRef

   CntrLine_CliSite_Release(lpThis);

   return hrErr;

}

// IOleClientSite::ShowObject

STDMETHODIMP CntrLine_CliSite_ShowObject(LPOLECLIENTSITE lpThis)

{

   LPCONTAINERLINE lpContainerLine =

         ((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine;

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerLine->m_lpDoc;

   LPLINELIST lpLL = OutlineDoc_GetLineList(lpOutlineDoc);

   int nIndex = LineList_GetLineIndex(lpLL, (LPLINE)lpContainerLine);

   HWND hWndFrame = OutlineApp_GetFrameWindow(g_lpApp);

   // artificial AddRef in case object is deleted during call

   CntrLine_CliSite_AddRef(lpThis);

   OLEDBG_BEGIN2("CntrLine_CliSite_ShowObject\r\n")

   /* make sure our doc window is visible and not minimized.

   **    the OutlineDoc_ShowWindow function will cause the app window

   **    to show itself SW_SHOWNORMAL.

   */

   if (! IsWindowVisible(hWndFrame) || IsIconic(hWndFrame))

      OutlineDoc_ShowWindow(lpOutlineDoc);

   BringWindowToTop(hWndFrame);

   /* make sure that the OLE object is currently in view. if necessary

   **    scroll the document in order to bring it into view.

   */

   LineList_ScrollLineIntoView(lpLL, nIndex);

#if defined( INPLACE_CNTR )

   /* after the in-place object is scrolled into view, we need to ask

   **    it to update its rect for the new clip rect coordinates

   */

   ContainerDoc_UpdateInPlaceObjectRects((LPCONTAINERDOC)lpOutlineDoc, 0);

#endif

   OLEDBG_END2

   // release artificial AddRef

   CntrLine_CliSite_Release(lpThis);

   return NOERROR;

}

// IOleClientSite::OnShowWindow

STDMETHODIMP CntrLine_CliSite_OnShowWindow(LPOLECLIENTSITE lpThis, BOOL fShow)

{

   LPCONTAINERLINE lpContainerLine =

         ((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine;

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerLine->m_lpDoc;

   LPLINELIST lpLL = OutlineDoc_GetLineList(lpOutlineDoc);

   int nIndex = LineList_GetLineIndex(lpLL, (LPLINE)lpContainerLine);

   // artificial AddRef in case object is deleted during call

   CntrLine_CliSite_AddRef(lpThis);

   if (fShow) {

      OLEDBG_BEGIN2("CntrLine_CliSite_OnShowWindow(TRUE)\r\n")

      /* OLE2NOTE: we need to hatch out the OLE object now; it has

      **    just been opened in a window elsewhere (open editing as

      **    opposed to in-place activation).

      **    force the line to re-draw with the hatch.

      */

      lpContainerLine->m_fObjWinOpen = TRUE;

      LineList_ForceLineRedraw(lpLL, nIndex, FALSE /*fErase*/);

   } else {

      OLEDBG_BEGIN2("CntrLine_CliSite_OnShowWindow(FALSE)\r\n")

      /* OLE2NOTE: the object associated with this container site has

      **    just closed its server window. we should now remove the

      **    hatching that indicates that the object is open

      **    elsewhere. also our window should now come to the top.

      **    force the line to re-draw without the hatch.

      */

      lpContainerLine->m_fObjWinOpen = FALSE;

      LineList_ForceLineRedraw(lpLL, nIndex, TRUE /*fErase*/);

      BringWindowToTop(lpOutlineDoc->m_hWndDoc);

      SetFocus(lpOutlineDoc->m_hWndDoc);

   }

   OLEDBG_END2

   // release artificial AddRef

   CntrLine_CliSite_Release(lpThis);

   return NOERROR;

}

// IOleClientSite::RequestNewObjectLayout

STDMETHODIMP CntrLine_CliSite_RequestNewObjectLayout(LPOLECLIENTSITE lpThis)

{

   OleDbgOut2("CntrLine_CliSite_RequestNewObjectLayout\r\n");

   /* OLE2NOTE: this method is NOT yet used. it is for future layout

   **    negotiation support.

   */

   return ResultFromScode(E_NOTIMPL);

}

/*************************************************************************

** ContainerLine::IAdviseSink interface implementation

*************************************************************************/

// IAdviseSink::QueryInterface

STDMETHODIMP CntrLine_AdvSink_QueryInterface(

      LPADVISESINK        lpThis,

      REFIID              riid,

      LPVOID FAR*         lplpvObj

)

{

   LPCONTAINERLINE lpContainerLine =

         ((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine;

   return ContainerLine_QueryInterface(lpContainerLine, riid, lplpvObj);

}

// IAdviseSink::AddRef

STDMETHODIMP_(ULONG) CntrLine_AdvSink_AddRef(LPADVISESINK lpThis)

{

   LPCONTAINERLINE lpContainerLine =

         ((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine;

   OleDbgAddRefMethod(lpThis, "IAdviseSink");

   return ContainerLine_AddRef(lpContainerLine);

}

// IAdviseSink::Release

STDMETHODIMP_(ULONG) CntrLine_AdvSink_Release (LPADVISESINK lpThis)

{

   LPCONTAINERLINE lpContainerLine =

         ((struct COleClientSiteImpl FAR*)lpThis)->lpContainerLine;

   OleDbgReleaseMethod(lpThis, "IAdviseSink");

   return ContainerLine_Release(lpContainerLine);

}

// IAdviseSink::OnDataChange

STDMETHODIMP_(void) CntrLine_AdvSink_OnDataChange(

      LPADVISESINK        lpThis,

      FORMATETC FAR*      lpFormatetc,

      STGMEDIUM FAR*      lpStgmed

)

{

   OleDbgOut2("CntrLine_AdvSink_OnDataChange\r\n");

   // We are not interested in data changes (only view changes)

   //      (ie. nothing to do)

}

STDMETHODIMP_(void) CntrLine_AdvSink_OnViewChange(

      LPADVISESINK        lpThis,

      DWORD               aspects,

      LONG                lindex

)

{

   LPCONTAINERLINE lpContainerLine;

   LPOUTLINEDOC lpOutlineDoc;

   HWND hWndDoc;

   LPLINELIST lpLL;

   MSG msg;

   int nIndex;

   // artificial AddRef in case object is destroyed during call

   CntrLine_AdvSink_AddRef(lpThis);

   OLEDBG_BEGIN2("CntrLine_AdvSink_OnViewChange\r\n")

   lpContainerLine = ((struct CAdviseSinkImpl FAR*)lpThis)->lpContainerLine;

   lpOutlineDoc = (LPOUTLINEDOC)lpContainerLine->m_lpDoc;

   /* OLE2NOTE: at this point we simply invalidate the rectangle of

   **    the object to force a repaint in the future, we mark

   **    that the extents of the object may have changed

   **    (m_fDoGetExtent=TRUE), and we post a message

   **    (WM_U_UPDATEOBJECTEXTENT) to our document that one or more

   **    OLE objects may need to have their extents updated. later

   **    when this message is processed, the document loops through

   **    all lines to see if any are marked as needing an extent update.

   **    if infact the extents did change. this can be done by calling

   **    IViewObject2::GetExtent to retreive the object's current

   **    extents and comparing with the last known extents for the

   **    object. if the extents changed, then relayout space for the

   **    object before drawing. we postpone the check to get

   **    the extents now because OnViewChange is an asyncronis method,

   **    and we have to careful not to call any syncronis methods back

   **    to the object. while it WOULD be OK to call the

   **    IViewObject2::GetExtent method within the asyncronis

   **    OnViewChange method (because this method is handled by the

   **    object handler and never remoted), it is good practise to not

   **    call any object methods from within an asyncronis

   **    notification method.

   **    if there is already WM_U_UPDATEOBJECTEXTENT message waiting

   **    in our message queue, there is no need to post another one.

   **    in this way, if the server is updating quicker than we can

   **    keep up, we do not make unneccsary GetExtent calls. also if

   **    drawing is disabled, we postpone updating the extents of any

   **    objects until drawing is re-enabled.

   */

   lpContainerLine->m_fDoGetExtent = TRUE;

   hWndDoc = OutlineDoc_GetWindow((LPOUTLINEDOC)lpContainerLine->m_lpDoc);

   if (lpOutlineDoc->m_nDisableDraw == 0 &&

      ! PeekMessage(&msg, hWndDoc,

         WM_U_UPDATEOBJECTEXTENT, WM_U_UPDATEOBJECTEXTENT,

         PM_NOREMOVE | PM_NOYIELD)) {

      PostMessage(hWndDoc, WM_U_UPDATEOBJECTEXTENT, 0, 0L);

   }

   // force the modified line to redraw.

   lpLL = OutlineDoc_GetLineList(lpOutlineDoc);

   nIndex = LineList_GetLineIndex(lpLL, (LPLINE)lpContainerLine);

   LineList_ForceLineRedraw(lpLL, nIndex, TRUE /*fErase*/);

   OLEDBG_END2

   // release artificial AddRef

   CntrLine_AdvSink_Release(lpThis);

}

// IAdviseSink::OnRename

STDMETHODIMP_(void) CntrLine_AdvSink_OnRename(

      LPADVISESINK        lpThis,

      LPMONIKER           lpmk

)

{

   OleDbgOut2("CntrLine_AdvSink_OnRename\r\n");

   /* OLE2NOTE: the Embedding Container has nothing to do here. this

   **    notification is important for linking situations. it tells

   **    the OleLink objects to update their moniker because the

   **    source object has been renamed (track the link source).

   */

}

// IAdviseSink::OnSave

STDMETHODIMP_(void) CntrLine_AdvSink_OnSave(LPADVISESINK lpThis)

{

   OleDbgOut2("CntrLine_AdvSink_OnSave\r\n");

   /* OLE2NOTE: the Embedding Container has nothing to do here. this

   **    notification is only useful to clients which have set up a

   **    data cache with the ADVFCACHE_ONSAVE flag.

   */

}

// IAdviseSink::OnClose

STDMETHODIMP_(void) CntrLine_AdvSink_OnClose(LPADVISESINK lpThis)

{

   OleDbgOut2("CntrLine_AdvSink_OnClose\r\n");

   /* OLE2NOTE: the Embedding Container has nothing to do here. this

   **    notification is important for the OLE's default object handler

   **    and the OleLink object. it tells them the remote object is

   **    shutting down.

   */

}

/*************************************************************************

** ContainerLine Support Functions

*************************************************************************/

/* ContainerLine_Init

** ------------------

**  Initialize fields in a newly constructed ContainerLine line object.

**  NOTE: ref cnt of ContainerLine initialized to 0

*/

void ContainerLine_Init(LPCONTAINERLINE lpContainerLine, int nTab, HDC hDC)

{

   Line_Init((LPLINE)lpContainerLine, nTab, hDC);  // init base class fields

   ((LPLINE)lpContainerLine)->m_lineType           = CONTAINERLINETYPE;

   ((LPLINE)lpContainerLine)->m_nWidthInHimetric   = DEFOBJWIDTH;

   ((LPLINE)lpContainerLine)->m_nHeightInHimetric  = DEFOBJHEIGHT;

   lpContainerLine->m_cRef                         = 0;

   lpContainerLine->m_szStgName[0]                 = '\0';

   lpContainerLine->m_fObjWinOpen                  = FALSE;

   lpContainerLine->m_fMonikerAssigned             = FALSE;

   lpContainerLine->m_dwDrawAspect                 = DVASPECT_CONTENT;

   lpContainerLine->m_fGuardObj                    = FALSE;

   lpContainerLine->m_fDoGetExtent                 = FALSE;

   lpContainerLine->m_fDoSetExtent                 = FALSE;

   lpContainerLine->m_sizeInHimetric.cx            = -1;

   lpContainerLine->m_sizeInHimetric.cy            = -1;

   lpContainerLine->m_lpStg                        = NULL;

   lpContainerLine->m_lpDoc                        = NULL;

   lpContainerLine->m_lpOleObj                     = NULL;

   lpContainerLine->m_lpViewObj2                   = NULL;

   lpContainerLine->m_lpPersistStg                 = NULL;

   lpContainerLine->m_lpOleLink                    = NULL;

   lpContainerLine->m_dwLinkType                   = 0;

   lpContainerLine->m_fLinkUnavailable             = FALSE;

   lpContainerLine->m_lpszShortType                = NULL;

#if defined( INPLACE_CNTR )

   lpContainerLine->m_fIpActive                    = FALSE;

   lpContainerLine->m_fUIActive                    = FALSE;

   lpContainerLine->m_fIpVisible                   = FALSE;

   lpContainerLine->m_lpOleIPObj                   = NULL;

   lpContainerLine->m_fInsideOutObj                = FALSE;

   lpContainerLine->m_fIpChangesUndoable           = FALSE;

   lpContainerLine->m_fIpServerRunning             = FALSE;

   lpContainerLine->m_hWndIpObject                 = NULL;

   lpContainerLine->m_nHorizScrollShift            = 0;

#endif  // INPLACE_CNTR

   INIT_INTERFACEIMPL(

         &lpContainerLine->m_Unknown,

         &g_CntrLine_UnknownVtbl,

         lpContainerLine

   );

   INIT_INTERFACEIMPL(

         &lpContainerLine->m_OleClientSite,

         &g_CntrLine_OleClientSiteVtbl,

         lpContainerLine

   );

   INIT_INTERFACEIMPL(

         &lpContainerLine->m_AdviseSink,

         &g_CntrLine_AdviseSinkVtbl,

         lpContainerLine

   );

#if defined( INPLACE_CNTR )

   INIT_INTERFACEIMPL(

         &lpContainerLine->m_OleInPlaceSite,

         &g_CntrLine_OleInPlaceSiteVtbl,

         lpContainerLine

   );

#endif  // INPLACE_CNTR

}

/* Setup the OLE object associated with the ContainerLine */

BOOL ContainerLine_SetupOleObject(

      LPCONTAINERLINE         lpContainerLine,

      BOOL                    fDisplayAsIcon,

      HGLOBAL                 hMetaPict

)

{

   DWORD dwDrawAspect = (fDisplayAsIcon ? DVASPECT_ICON : DVASPECT_CONTENT);

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerLine->m_lpDoc;

   /* Cache a pointer to the IViewObject2* interface. *Required*

   **      we need this everytime we draw the object.

   **

   ** OLE2NOTE: We require the object to support IViewObject2

   **    interface. this is an extension to the IViewObject interface

   **    that was added with the OLE 2.01 release. This interface must

   **    be supported by all object handlers and DLL-based objects.

   */

   lpContainerLine->m_lpViewObj2 = (LPVIEWOBJECT2)OleStdQueryInterface(

         (LPUNKNOWN)lpContainerLine->m_lpOleObj, &IID_IViewObject2);

   if (! lpContainerLine->m_lpViewObj2) {

#if defined( _DEBUG )

      OleDbgAssertSz(

         lpContainerLine->m_lpViewObj2,"IViewObject2 NOT supported\r\n");

#endif

      return FALSE;

   }

   // Cache a pointer to the IPersistStorage* interface. *Required*

   //      we need this everytime we save the object.

   lpContainerLine->m_lpPersistStg = (LPPERSISTSTORAGE)OleStdQueryInterface(

         (LPUNKNOWN)lpContainerLine->m_lpOleObj, &IID_IPersistStorage);

   if (! lpContainerLine->m_lpPersistStg) {

      OleDbgAssert(lpContainerLine->m_lpPersistStg);

      return FALSE;

   }

   // Cache a pointer to the IOleLink* interface if supported. *Optional*

   //      if supported the object is a link. we need this to manage the link

   lpContainerLine->m_lpOleLink = (LPOLELINK)OleStdQueryInterface(

         (LPUNKNOWN)lpContainerLine->m_lpOleObj, &IID_IOleLink);

   if (lpContainerLine->m_lpOleLink) {

      OLEDBG_BEGIN2("IOleLink::GetUpdateOptions called\r\n")

      lpContainerLine->m_lpOleLink->lpVtbl->GetUpdateOptions(

            lpContainerLine->m_lpOleLink, &lpContainerLine->m_dwLinkType);

      OLEDBG_END2

   } else

      lpContainerLine->m_dwLinkType = 0;  // NOT a link

   /* get the short user type name of the object. this

   **    is used all the time when we have to build the object

   **    verb menu. we will cache this information to make it

   **    quicker to build the verb menu.

   */

   OleDbgAssert(lpContainerLine->m_lpszShortType == NULL);

   OLEDBG_BEGIN2("IOleObject::GetUserType called\r\n")

   lpContainerLine->m_lpOleObj->lpVtbl->GetUserType(

         lpContainerLine->m_lpOleObj,

         USERCLASSTYPE_SHORT,

         (LPOLESTR FAR*)&lpContainerLine->m_lpszShortType

   );

   OLEDBG_END2

   /* Perform that standard setup for the OLE object. this includes:

   **      setup View advise

   **      Call IOleObject::SetHostNames

   **      Call OleSetContainedObject

   */

   OleStdSetupAdvises(

         lpContainerLine->m_lpOleObj,

         dwDrawAspect,

         (LPOLESTR)APPNAME,

         lpOutlineDoc->m_lpszDocTitle,

         (LPADVISESINK)&lpContainerLine->m_AdviseSink,

         TRUE    /*fCreate*/

   );

#if defined( INPLACE_CNTR )

   /* OLE2NOTE: (INSIDE-OUT CONTAINER) An inside-out container should

   **    check if the object is an inside-out and prefers to be

   **    activated when visible type of object. if not the object

   **    should not be allowed to keep its window up after it gets

   **    UIDeactivated.

   */

   if (g_fInsideOutContainer) {

      DWORD mstat;

      OLEDBG_BEGIN2("IOleObject::GetMiscStatus called\r\n")

      lpContainerLine->m_lpOleObj->lpVtbl->GetMiscStatus(

            lpContainerLine->m_lpOleObj,

            DVASPECT_CONTENT,

            (DWORD FAR*)&mstat

      );

      OLEDBG_END2

      lpContainerLine->m_fInsideOutObj = (BOOL)

            (mstat & (OLEMISC_INSIDEOUT|OLEMISC_ACTIVATEWHENVISIBLE));

   }

#endif  // INPLACE_CNTR

   if (fDisplayAsIcon) {

      /* user has requested to display icon aspect instead of content

      **    aspect.

      **    NOTE: we do not have to delete the previous aspect cache

      **    because one did not get set up.

      */

      OleStdSwitchDisplayAspect(

            lpContainerLine->m_lpOleObj,

            &lpContainerLine->m_dwDrawAspect,

            dwDrawAspect,

            hMetaPict,

            FALSE,  /* fDeleteOldAspect */

            TRUE,   /* fSetupViewAdvise */

            (LPADVISESINK)&lpContainerLine->m_AdviseSink,

            NULL /*fMustUpdate*/        // this can be ignored; update

                                 // for switch to icon not req'd

      );

   }

   return TRUE;

}

/* Create an ContainerLine object and return the pointer */

LPCONTAINERLINE ContainerLine_Create(

      DWORD                   dwOleCreateType,

      HDC                     hDC,

      UINT                    nTab,

      LPCONTAINERDOC          lpContainerDoc,

      LPCLSID                 lpclsid,

      LPOLESTR                lpszFileName,

      BOOL                    fDisplayAsIcon,

      HGLOBAL                 hMetaPict,

      LPOLESTR                lpszStgName

)

{

   LPCONTAINERLINE lpContainerLine = NULL;

   LPOLEOBJECT     lpObj = NULL;

   LPSTORAGE       lpDocStg = ContainerDoc_GetStg(lpContainerDoc);

   DWORD           dwDrawAspect =

                  (fDisplayAsIcon ? DVASPECT_ICON : DVASPECT_CONTENT);

   DWORD           dwOleRenderOpt =

                  (fDisplayAsIcon ? OLERENDER_NONE : OLERENDER_DRAW);

   HRESULT         hrErr;

   OLEDBG_BEGIN3("ContainerLine_Create\r\n")

   if (lpDocStg == NULL) {

      OleDbgAssertSz(lpDocStg != NULL, "Doc storage is NULL");

      goto error;

   }

   lpContainerLine=(LPCONTAINERLINE) New((DWORD)sizeof(CONTAINERLINE));

   if (lpContainerLine == NULL) {

      OleDbgAssertSz(lpContainerLine!=NULL,"Error allocating ContainerLine");

      goto error;

   }

   ContainerLine_Init(lpContainerLine, nTab, hDC);

   /* OLE2NOTE: in order to avoid re-entrancy we will set a flag to

   **    guard our object. if this guard is set, then the object is

   **    not ready to have any OLE interface methods called. it is

   **    necessary to guard the object this way while it is being

   **    created or loaded.

   */

   lpContainerLine->m_fGuardObj = TRUE;

   /* OLE2NOTE: In order to have a stable ContainerLine object we must

   **    AddRef the object's refcnt. this will be later released when

   **    the ContainerLine is deleted.

   */

   ContainerLine_AddRef(lpContainerLine);

   OLESTRCPY(lpContainerLine->m_szStgName, lpszStgName);

   lpContainerLine->m_lpDoc = lpContainerDoc;

   /* Create a new storage for the object inside the doc's storage */

   lpContainerLine->m_lpStg = OleStdCreateChildStorage(lpDocStg,lpszStgName);

   if (lpContainerLine->m_lpStg == NULL) {

      OleDbgAssert(lpContainerLine->m_lpStg != NULL);

      goto error;

   }

   lpContainerLine->m_dwLinkType = 0;

   switch (dwOleCreateType) {

      case IOF_SELECTCREATENEW:

         OLEDBG_BEGIN2("OleCreate called\r\n")

         hrErr = OleCreate (

               lpclsid,

               &IID_IOleObject,

               dwOleRenderOpt,

               NULL,

               (LPOLECLIENTSITE)&lpContainerLine->m_OleClientSite,

               lpContainerLine->m_lpStg,

               (LPVOID FAR*)&lpContainerLine->m_lpOleObj

         );

         OLEDBG_END2

#if defined( _DEBUG )

         if (hrErr != NOERROR)

            OleDbgOutHResult("OleCreate returned", hrErr);

#endif

         break;

      case IOF_SELECTCREATEFROMFILE:

         OLEDBG_BEGIN2("OleCreateFromFile called\r\n")

         hrErr = OleCreateFromFile (

               &CLSID_NULL,

               lpszFileName,

               &IID_IOleObject,

               dwOleRenderOpt,

               NULL,

               (LPOLECLIENTSITE)&lpContainerLine->m_OleClientSite,

               lpContainerLine->m_lpStg,

               (LPVOID FAR*)&lpContainerLine->m_lpOleObj

         );

         OLEDBG_END2

#if defined( _DEBUG )

         if (hrErr != NOERROR)

            OleDbgOutHResult("OleCreateFromFile returned", hrErr);

#endif

         break;

      case IOF_CHECKLINK:

         OLEDBG_BEGIN2("OleCreateLinkToFile called\r\n")

         hrErr = OleCreateLinkToFile (

               lpszFileName,

               &IID_IOleObject,

               dwOleRenderOpt,

               NULL,

               (LPOLECLIENTSITE)&lpContainerLine->m_OleClientSite,

               lpContainerLine->m_lpStg,

               (LPVOID FAR*)&lpContainerLine->m_lpOleObj

         );

         OLEDBG_END2

#if defined( _DEBUG )

         if (hrErr != NOERROR)

            OleDbgOutHResult("OleCreateLinkToFile returned", hrErr);

#endif

         break;

   }

   if (hrErr != NOERROR)

      goto error;

   if (! ContainerLine_SetupOleObject(

                        lpContainerLine, fDisplayAsIcon, hMetaPict)) {

      goto error;

   }

   /* OLE2NOTE: clear our re-entrancy guard. the object is now ready

   **    to have interface methods called.

   */

   lpContainerLine->m_fGuardObj = FALSE;

   OLEDBG_END3

   return lpContainerLine;

error:

   OutlineApp_ErrorMessage(g_lpApp, OLESTR("Could not create object!"));

   // Destroy partially created OLE object

   if (lpContainerLine)

      ContainerLine_Delete(lpContainerLine);

   OLEDBG_END3

   return NULL;

}

LPCONTAINERLINE ContainerLine_CreateFromData(

      HDC                     hDC,

      UINT                    nTab,

      LPCONTAINERDOC          lpContainerDoc,

      LPDATAOBJECT            lpSrcDataObj,

      DWORD                   dwCreateType,

      CLIPFORMAT              cfFormat,

      BOOL                    fDisplayAsIcon,

      HGLOBAL                 hMetaPict,

      LPOLESTR                lpszStgName

)

{

   HGLOBAL         hData = NULL;

   LPCONTAINERLINE lpContainerLine = NULL;

   LPOLEOBJECT     lpObj = NULL;

   LPSTORAGE       lpDocStg = ContainerDoc_GetStg(lpContainerDoc);

   DWORD           dwDrawAspect =

                  (fDisplayAsIcon ? DVASPECT_ICON : DVASPECT_CONTENT);

   DWORD           dwOleRenderOpt;

   FORMATETC       renderFmtEtc;

   LPFORMATETC     lpRenderFmtEtc = NULL;

   HRESULT         hrErr;

   LPUNKNOWN       lpUnk = NULL;

   OLEDBG_BEGIN3("ContainerLine_CreateFromData\r\n")

   if (dwCreateType == OLECREATEFROMDATA_STATIC && cfFormat != 0) {

      // a particular type of static object should be created

      dwOleRenderOpt = OLERENDER_FORMAT;

      lpRenderFmtEtc = (LPFORMATETC)&renderFmtEtc;

      if (cfFormat == CF_METAFILEPICT)

         SETDEFAULTFORMATETC(renderFmtEtc, cfFormat, TYMED_MFPICT);

      else if (cfFormat == CF_BITMAP)

         SETDEFAULTFORMATETC(renderFmtEtc, cfFormat, TYMED_GDI);

      else

         SETDEFAULTFORMATETC(renderFmtEtc, cfFormat, TYMED_HGLOBAL);

   } else if (dwCreateType == OLECREATEFROMDATA_STATIC && fDisplayAsIcon) {

      // a link that currently displayed as an icon needs to be

      // converted to a STATIC picture object. this case is driven

      // from "BreakLink" in the "Links" dialog. because the current

      // data in the source object's cache is DVASPECT_ICON we need

      // to tell the OleCreateStaticFromData API to look for

      // DVASPECT_ICON data. the static object that results however,

      // is considered to be displayed in the DVASPECT_CONTENT view.

      dwOleRenderOpt = OLERENDER_DRAW;

      lpRenderFmtEtc = (LPFORMATETC)&renderFmtEtc;

      SETFORMATETC(renderFmtEtc,0,DVASPECT_ICON,NULL,TYMED_NULL,-1);

      dwDrawAspect = DVASPECT_CONTENT;   // static obj displays only CONTENT

   } else if (fDisplayAsIcon && hMetaPict) {

      // a special icon should be used. first we create the object

      // OLERENDER_NONE and then we stuff the special icon into the cache.

      dwOleRenderOpt = OLERENDER_NONE;

   } else if (fDisplayAsIcon && hMetaPict == NULL) {

      // the object's default icon should be used

      dwOleRenderOpt = OLERENDER_DRAW;

      lpRenderFmtEtc = (LPFORMATETC)&renderFmtEtc;

      SETFORMATETC(renderFmtEtc,0,DVASPECT_ICON,NULL,TYMED_NULL,-1);

   } else {

      // create standard DVASPECT_CONTENT/OLERENDER_DRAW object

      dwOleRenderOpt = OLERENDER_DRAW;

   }

   if (lpDocStg == NULL) {

      OleDbgAssertSz(lpDocStg != NULL, "Doc storage is NULL");

      goto error;

   }

   lpContainerLine=(LPCONTAINERLINE) New((DWORD)sizeof(CONTAINERLINE));

   if (lpContainerLine == NULL) {

      OleDbgAssertSz(lpContainerLine!=NULL,"Error allocating ContainerLine");

      goto error;

   }

   ContainerLine_Init(lpContainerLine, nTab, hDC);

   /* OLE2NOTE: in order to avoid re-entrancy we will set a flag to

   **    guard our object. if this guard is set, then the object is

   **    not ready to have any OLE interface methods called. it is

   **    necessary to guard the object this way while it is being

   **    created or loaded.

   */

   lpContainerLine->m_fGuardObj = TRUE;

   /* OLE2NOTE: In order to have a stable ContainerLine object we must

   **    AddRef the object's refcnt. this will be later released when

   **    the ContainerLine is deleted.

   */

   ContainerLine_AddRef(lpContainerLine);

   OLESTRCPY(lpContainerLine->m_szStgName, lpszStgName);

   lpContainerLine->m_lpDoc = lpContainerDoc;

   /* Create a new storage for the object inside the doc's storage */

   lpContainerLine->m_lpStg = OleStdCreateChildStorage(lpDocStg,lpszStgName);

   if (lpContainerLine->m_lpStg == NULL) {

      OleDbgAssert(lpContainerLine->m_lpStg != NULL);

      goto error;

   }

   switch (dwCreateType) {

      case OLECREATEFROMDATA_LINK:

         OLEDBG_BEGIN2("OleCreateLinkFromData called\r\n")

         hrErr = OleCreateLinkFromData (

               lpSrcDataObj,

               &IID_IOleObject,

               dwOleRenderOpt,

               lpRenderFmtEtc,

               (LPOLECLIENTSITE)&lpContainerLine->m_OleClientSite,

               lpContainerLine->m_lpStg,

               (LPVOID FAR*)&lpContainerLine->m_lpOleObj

         );

         OLEDBG_END2

#if defined( _DEBUG )

         if (hrErr != NOERROR)

            OleDbgOutHResult("OleCreateLinkFromData returned", hrErr);

#endif

         break;

      case OLECREATEFROMDATA_OBJECT:

         OLEDBG_BEGIN2("OleCreateFromData called\r\n")

         hrErr = OleCreateFromData (

               lpSrcDataObj,

               &IID_IOleObject,

               dwOleRenderOpt,

               lpRenderFmtEtc,

               (LPOLECLIENTSITE)&lpContainerLine->m_OleClientSite,

               lpContainerLine->m_lpStg,

               (LPVOID FAR*)&lpContainerLine->m_lpOleObj

         );

         OLEDBG_END2

#if defined( _DEBUG )

         if (hrErr != NOERROR)

            OleDbgOutHResult("OleCreateFromData returned", hrErr);

#endif

         break;

      case OLECREATEFROMDATA_STATIC:

         OLEDBG_BEGIN2("OleCreateStaticFromData called\r\n")

         hrErr = OleCreateStaticFromData (

               lpSrcDataObj,

               &IID_IOleObject,

               dwOleRenderOpt,

               lpRenderFmtEtc,

               (LPOLECLIENTSITE)&lpContainerLine->m_OleClientSite,

               lpContainerLine->m_lpStg,

               (LPVOID FAR*)&lpContainerLine->m_lpOleObj

         );

         OLEDBG_END2

#if defined( _DEBUG )

         if (hrErr != NOERROR)

            OleDbgOutHResult("OleCreateStaticFromData returned", hrErr);

#endif

         break;

   }

   if (hrErr != NOERROR)

      goto error;

   if (! ContainerLine_SetupOleObject(

                        lpContainerLine, fDisplayAsIcon, hMetaPict)) {

      goto error;

   }

   /* OLE2NOTE: clear our re-entrancy guard. the object is now ready

   **    to have interface methods called.

   */

   lpContainerLine->m_fGuardObj = FALSE;

   OLEDBG_END3

   return lpContainerLine;

error:

   OutlineApp_ErrorMessage(g_lpApp, OLESTR("Could not create object!"));

   // Destroy partially created OLE object

   if (lpContainerLine)

      ContainerLine_Delete(lpContainerLine);

   OLEDBG_END3

   return NULL;

}

/* ContainerLine_AddRef

** --------------------

**

**  increment the ref count of the line object.

**

**    Returns the new ref count on the object

*/

ULONG ContainerLine_AddRef(LPCONTAINERLINE lpContainerLine)

{

   ++lpContainerLine->m_cRef;

#if defined( _DEBUG )

   OleDbgOutRefCnt4(

         "ContainerLine_AddRef: cRef++\r\n",

         lpContainerLine,

         lpContainerLine->m_cRef

   );

#endif

   return lpContainerLine->m_cRef;

}

/* ContainerLine_Release

** ---------------------

**

**  decrement the ref count of the line object.

**    if the ref count goes to 0, then the line is destroyed.

**

**    Returns the remaining ref count on the object

*/

ULONG ContainerLine_Release(LPCONTAINERLINE lpContainerLine)

{

   ULONG cRef;

   /*********************************************************************

   ** OLE2NOTE: when the obj refcnt == 0, then destroy the object.     **

   **     otherwise the object is still in use.                        **

   *********************************************************************/

   cRef = --lpContainerLine->m_cRef;

#if defined( _DEBUG )

   OleDbgAssertSz(

         lpContainerLine->m_cRef >= 0,"Release called with cRef == 0");

   OleDbgOutRefCnt4(

         "ContainerLine_Release: cRef--\r\n",

         lpContainerLine,

         cRef

   );

#endif

   if (cRef == 0)

      ContainerLine_Destroy(lpContainerLine);

   return cRef;

}

/* ContainerLine_QueryInterface

** ----------------------------

**

** Retrieve a pointer to an interface on the ContainerLine object.

**

**    Returns NOERROR if interface is successfully retrieved.

**            E_NOINTERFACE if the interface is not supported

*/

HRESULT ContainerLine_QueryInterface(

      LPCONTAINERLINE         lpContainerLine,

      REFIID                  riid,

      LPVOID FAR*             lplpvObj

)

{

   SCODE sc = E_NOINTERFACE;

   /* OLE2NOTE: we must make sure to set all out ptr parameters to NULL. */

   *lplpvObj = NULL;

   if (IsEqualIID(riid, &IID_IUnknown)) {

      OleDbgOut4("ContainerLine_QueryInterface: IUnknown* RETURNED\r\n");

      *lplpvObj = (LPVOID) &lpContainerLine->m_Unknown;

      ContainerLine_AddRef(lpContainerLine);

      sc = S_OK;

   }

   else if (IsEqualIID(riid, &IID_IOleClientSite)) {

      OleDbgOut4("ContainerLine_QueryInterface: IOleClientSite* RETURNED\r\n");

      *lplpvObj = (LPVOID) &lpContainerLine->m_OleClientSite;

      ContainerLine_AddRef(lpContainerLine);

      sc = S_OK;

   }

   else if (IsEqualIID(riid, &IID_IAdviseSink)) {

      OleDbgOut4("ContainerLine_QueryInterface: IAdviseSink* RETURNED\r\n");

      *lplpvObj = (LPVOID) &lpContainerLine->m_AdviseSink;

      ContainerLine_AddRef(lpContainerLine);

      sc = S_OK;

   }

#if defined( INPLACE_CNTR )

   else if (IsEqualIID(riid, &IID_IOleWindow)

          || IsEqualIID(riid, &IID_IOleInPlaceSite)) {

      OleDbgOut4("ContainerLine_QueryInterface: IOleInPlaceSite* RETURNED\r\n");

      *lplpvObj = (LPVOID) &lpContainerLine->m_OleInPlaceSite;

      ContainerLine_AddRef(lpContainerLine);

      sc = S_OK;

   }

#endif  // INPLACE_CNTR

   OleDbgQueryInterfaceMethod(*lplpvObj);

   return ResultFromScode(sc);

}

BOOL ContainerLine_LoadOleObject(LPCONTAINERLINE lpContainerLine)

{

   LPOUTLINEDOC    lpOutlineDoc = (LPOUTLINEDOC)lpContainerLine->m_lpDoc;

   LPSTORAGE       lpDocStg = ContainerDoc_GetStg(lpContainerLine->m_lpDoc);

   LPOLECLIENTSITE lpOleClientSite;

   LPMONIKER       lpmkObj;

   LPOLEAPP        lpOleApp = (LPOLEAPP)g_lpApp;

   BOOL            fPrevEnable1;

   BOOL            fPrevEnable2;

   HRESULT         hrErr;

   if (lpContainerLine->m_fGuardObj)

      return FALSE;                // object in process of creation

   if (lpContainerLine->m_lpOleObj)

      return TRUE;                // object already loaded

   OLEDBG_BEGIN3("ContainerLine_LoadOleObject\r\n")

   /* OLE2NOTE: in order to avoid re-entrancy we will set a flag to

   **    guard our object. if this guard is set, then the object is

   **    not ready to have any OLE interface methods called. it is

   **    necessary to guard the object this way while it is being

   **    created or loaded.

   */

   lpContainerLine->m_fGuardObj = TRUE;

   /* if object storage is not already open, then open it */

   if (! lpContainerLine->m_lpStg) {

      lpContainerLine->m_lpStg = OleStdOpenChildStorage(

            lpDocStg,

            lpContainerLine->m_szStgName,

            STGM_READWRITE

      );

      if (lpContainerLine->m_lpStg == NULL) {

         OleDbgAssert(lpContainerLine->m_lpStg != NULL);

         goto error;

      }

   }

   /* OLE2NOTE: if the OLE object being loaded is in a data transfer

   **    document, then we should NOT pass a IOleClientSite* pointer

   **    to the OleLoad call. This particularly critical if the OLE

   **    object is an OleLink object. If a non-NULL client site is

   **    passed to the OleLoad function, then the link will bind to

   **    the source if its is running. in the situation that we are

   **    loading the object as part of a data transfer document we do

   **    not want this connection to be established. even worse, if

   **    the link source is currently blocked or busy, then this could

   **    hang the system. it is simplest to never pass a

   **    IOleClientSite* when loading an object in a data transfer

   **    document.

   */

   lpOleClientSite = (lpOutlineDoc->m_fDataTransferDoc ?

         NULL : (LPOLECLIENTSITE)&lpContainerLine->m_OleClientSite);

   /* OLE2NOTE: we do not want to ever give the Busy/NotResponding

   **    dialogs when we are loading an object. if the object is a

   **    link, it will attempt to BindIfRunning to the link source. if

   **    the link source is currently busy, this could cause the Busy

   **    dialog to come up. even if the link source is busy,

   **    we do not want put up the busy dialog. thus we will disable

   **    the dialog and later re-enable them

   */

   OleApp_DisableBusyDialogs(lpOleApp, &fPrevEnable1, &fPrevEnable2);

   OLEDBG_BEGIN2("OleLoad called\r\n")

   hrErr = OleLoad (

         lpContainerLine->m_lpStg,

         &IID_IOleObject,

         lpOleClientSite,

         (LPVOID FAR*)&lpContainerLine->m_lpOleObj

   );

   OLEDBG_END2

   // re-enable the Busy/NotResponding dialogs

   OleApp_EnableBusyDialogs(lpOleApp, fPrevEnable1, fPrevEnable2);

   if (hrErr != NOERROR) {

      OleDbgAssertSz(hrErr == NOERROR, "Could not load object!");

      OleDbgOutHResult("OleLoad returned", hrErr);

      goto error;

   }

   /* Cache a pointer to the IViewObject2* interface. *Required*

   **      we need this everytime we draw the object.

   **

   ** OLE2NOTE: We require the object to support IViewObject2

   **    interface. this is an extension to the IViewObject interface

   **    that was added with the OLE 2.01 release. This interface must

   **    be supported by all object handlers and DLL-based objects.

   */

   lpContainerLine->m_lpViewObj2 = (LPVIEWOBJECT2)OleStdQueryInterface(

         (LPUNKNOWN)lpContainerLine->m_lpOleObj, &IID_IViewObject2);

   if (! lpContainerLine->m_lpViewObj2) {

#if defined( _DEBUG )

      OleDbgAssertSz(

         lpContainerLine->m_lpViewObj2,"IViewObject2 NOT supported\r\n");

#endif

      goto error;

   }

   // Cache a pointer to the IPersistStorage* interface. *Required*

   //      we need this everytime we save the object.

   lpContainerLine->m_lpPersistStg = (LPPERSISTSTORAGE)OleStdQueryInterface(

         (LPUNKNOWN)lpContainerLine->m_lpOleObj, &IID_IPersistStorage);

   if (! lpContainerLine->m_lpPersistStg) {

      OleDbgAssert(lpContainerLine->m_lpPersistStg);

      goto error;

   }

   // Cache a pointer to the IOleLink* interface if supported. *Optional*

   //      if supported the object is a link. we need this to manage the link

   if (lpContainerLine->m_dwLinkType != 0) {

      lpContainerLine->m_lpOleLink = (LPOLELINK)OleStdQueryInterface(

            (LPUNKNOWN)lpContainerLine->m_lpOleObj, &IID_IOleLink);

      if (! lpContainerLine->m_lpOleLink) {

         OleDbgAssert(lpContainerLine->m_lpOleLink);

         goto error;

      }

   }

   /* OLE2NOTE: clear our re-entrancy guard. the object is now ready

   **    to have interface methods called.

   */

   lpContainerLine->m_fGuardObj = FALSE;

   /* OLE2NOTE: similarly, if the OLE object being loaded is in a data

   **    transfer document, then we do NOT need to setup any advises,

   **    call SetHostNames, SetMoniker, etc.

   */

   if (lpOleClientSite) {

      /* Setup the Advises (OLE notifications) that we are interested

      ** in receiving.

      */

      OleStdSetupAdvises(

            lpContainerLine->m_lpOleObj,

            lpContainerLine->m_dwDrawAspect,

            (LPOLESTR)APPNAME,

            lpOutlineDoc->m_lpszDocTitle,

            (LPADVISESINK)&lpContainerLine->m_AdviseSink,

            FALSE   /*fCreate*/

      );

      /* OLE2NOTE: if the OLE object has a moniker assigned, we need to

      **    inform the object by calling IOleObject::SetMoniker. this

      **    will force the OLE object to register in the

      **    RunningObjectTable when it enters the running state.

      */

      if (lpContainerLine->m_fMonikerAssigned) {

         lpmkObj = ContainerLine_GetRelMoniker(

               lpContainerLine,

               GETMONIKER_ONLYIFTHERE

         );

         if (lpmkObj) {

            OLEDBG_BEGIN2("IOleObject::SetMoniker called\r\n")

            lpContainerLine->m_lpOleObj->lpVtbl->SetMoniker(

                  lpContainerLine->m_lpOleObj,

                  OLEWHICHMK_OBJREL,

                  lpmkObj

            );

            OLEDBG_END2

            OleStdRelease((LPUNKNOWN)lpmkObj);

         }

      }

      /* get the Short form of the user type name of the object. this

      **    is used all the time when we have to build the object

      **    verb menu. we will cache this information to make it

      **    quicker to build the verb menu.

      */

      OLEDBG_BEGIN2("IOleObject::GetUserType called\r\n")

      lpContainerLine->m_lpOleObj->lpVtbl->GetUserType(

            lpContainerLine->m_lpOleObj,

            USERCLASSTYPE_SHORT,

            (LPOLESTR FAR*)&lpContainerLine->m_lpszShortType

      );

      OLEDBG_END2

#if defined( INPLACE_CNTR )

      /* OLE2NOTE: an inside-out container should check if the object

      **    is an inside-out and prefers to be activated when visible

      **    type of object. if so, the object should be immediately

      **    activated in-place, BUT NOT UIActived.

      */

      if (g_fInsideOutContainer &&

            lpContainerLine->m_dwDrawAspect == DVASPECT_CONTENT) {

         DWORD mstat;

         OLEDBG_BEGIN2("IOleObject::GetMiscStatus called\r\n")

         lpContainerLine->m_lpOleObj->lpVtbl->GetMiscStatus(

               lpContainerLine->m_lpOleObj,

               DVASPECT_CONTENT,

               (DWORD FAR*)&mstat

         );

         OLEDBG_END2

         lpContainerLine->m_fInsideOutObj = (BOOL)

               (mstat & (OLEMISC_INSIDEOUT|OLEMISC_ACTIVATEWHENVISIBLE));

         if ( lpContainerLine->m_fInsideOutObj ) {

            HWND hWndDoc = OutlineDoc_GetWindow(lpOutlineDoc);

            ContainerLine_DoVerb(

                  lpContainerLine,

                  OLEIVERB_INPLACEACTIVATE,

                  NULL,

                  FALSE,

                  FALSE

            );

            /* OLE2NOTE: following this DoVerb(INPLACEACTIVATE) the

            **    object may have taken focus. but because the

            **    object is NOT UIActive it should NOT have focus.

            **    we will make sure our document has focus.

            */

            SetFocus(hWndDoc);

         }

      }

#endif  // INPLACE_CNTR

      OLEDBG_END2

   }

   OLEDBG_END2

   return TRUE;

error:

   OLEDBG_END2

   return FALSE;

}

/* ContainerLine_CloseOleObject

** ----------------------------

**    Close the OLE object associated with the ContainerLine.

**

**    Closing the object forces the object to transition from the

**    running state to the loaded state. if the object was not running,

**    then there is no effect. it is necessary to close the OLE object

**    before releasing the pointers to the OLE object.

**

**    Returns TRUE if successfully closed,

**            FALSE if closing was aborted.

*/

BOOL ContainerLine_CloseOleObject(

      LPCONTAINERLINE         lpContainerLine,

      DWORD                   dwSaveOption

)

{

   HRESULT hrErr;

   SCODE   sc;

   if (lpContainerLine->m_fGuardObj)

      return FALSE;                // object in process of creation

   if (! lpContainerLine->m_lpOleObj)

      return TRUE;    // object is NOT loaded

   OLEDBG_BEGIN2("IOleObject::Close called\r\n")

   hrErr = lpContainerLine->m_lpOleObj->lpVtbl->Close(

         lpContainerLine->m_lpOleObj,

         (dwSaveOption == OLECLOSE_NOSAVE ?

               OLECLOSE_NOSAVE : OLECLOSE_SAVEIFDIRTY)

   );

   OLEDBG_END2

#if defined( INPLACE_CNTR )

   if (lpContainerLine->m_fIpServerRunning) {

      /* OLE2NOTE: unlock the lock held on the in-place object.

      **    it is VERY important that an in-place container

      **    that also support linking to embeddings properly manage

      **    the running of its in-place objects. in an outside-in

      **    style in-place container, when the user clicks

      **    outside of the in-place active object, the object gets

      **    UIDeactivated and the object hides its window. in order

      **    to make the object fast to reactivate, the container

      **    deliberately does not call IOleObject::Close. the object

      **    stays running in the invisible unlocked state. the idea

      **    here is if the user simply clicks outside of the object

      **    and then wants to double click again to re-activate the

      **    object, we do not want this to be slow. if we want to

      **    keep the object running, however, we MUST Lock it

      **    running. otherwise the object will be in an unstable

      **    state where if a linking client does a "silent-update"

      **    (eg. UpdateNow from the Links dialog), then the in-place

      **    server will shut down even before the object has a chance

      **    to be saved back in its container. this saving normally

      **    occurs when the in-place container closes the object. also

      **    keeping the object in the unstable, hidden, running,

      **    not-locked state can cause problems in some scenarios.

      **    ICntrOtl keeps only one object running. if the user

      **    intiates a DoVerb on another object, then that last

      **    running in-place active object is closed. a more

      **    sophistocated in-place container may keep more object running.

      **    (see CntrLine_IPSite_OnInPlaceActivate)

      */

      lpContainerLine->m_fIpServerRunning = FALSE;

      OLEDBG_BEGIN2("OleLockRunning(FALSE,TRUE) called\r\n")

      OleLockRunning((LPUNKNOWN)lpContainerLine->m_lpOleObj, FALSE, TRUE);

      OLEDBG_END2

   }

#endif

   if (hrErr != NOERROR) {

      OleDbgOutHResult("IOleObject::Close returned", hrErr);

      sc = GetScode(hrErr);

      if (sc == RPC_E_CALL_REJECTED || sc==OLE_E_PROMPTSAVECANCELLED)

         return FALSE;   // object aborted shutdown

   }

   return TRUE;

}

/* ContainerLine_UnloadOleObject

** -----------------------------

**    Close the OLE object associated with the ContainerLine and

**    release all pointer held to the object.

**

**    Closing the object forces the object to transition from the

**    running state to the loaded state. if the object was not running,

**    then there is no effect. it is necessary to close the OLE object

**    before releasing the pointers to the OLE object. releasing all

**    pointers to the object allows the object to transition from

**    loaded to unloaded (or passive).

*/

void ContainerLine_UnloadOleObject(

      LPCONTAINERLINE         lpContainerLine,

      DWORD                   dwSaveOption

)

{

   if (lpContainerLine->m_lpOleObj) {

      OLEDBG_BEGIN2("IOleObject::Close called\r\n")

      lpContainerLine->m_lpOleObj->lpVtbl->Close(

            lpContainerLine->m_lpOleObj, dwSaveOption);

      OLEDBG_END2

      /* OLE2NOTE: we will take our IOleClientSite* pointer away from

      **    the object before we release all pointers to the object.

      **    in the scenario where the object is implemented as an

      **    in-proc server (DLL object), then, if there are link

      **    connections to the DLL object, it is possible that the

      **    object will not be destroyed when we release our pointers

      **    to the object. the existance of the remote link

      **    connections will hold the object alive. later when these

      **    strong connections are released, then the object may

      **    attempt to call IOleClientSite::Save if we had not taken

      **    away the client site pointer.

      */

      OLEDBG_BEGIN2("IOleObject::SetClientSite(NULL) called\r\n")

      lpContainerLine->m_lpOleObj->lpVtbl->SetClientSite(

            lpContainerLine->m_lpOleObj, NULL);

      OLEDBG_END2

      OleStdRelease((LPUNKNOWN)lpContainerLine->m_lpOleObj);

      lpContainerLine->m_lpOleObj = NULL;

      if (lpContainerLine->m_lpViewObj2) {

         OleStdRelease((LPUNKNOWN)lpContainerLine->m_lpViewObj2);

         lpContainerLine->m_lpViewObj2 = NULL;

      }

      if (lpContainerLine->m_lpPersistStg) {

         OleStdRelease((LPUNKNOWN)lpContainerLine->m_lpPersistStg);

         lpContainerLine->m_lpPersistStg = NULL;

      }

      if (lpContainerLine->m_lpOleLink) {

         OleStdRelease((LPUNKNOWN)lpContainerLine->m_lpOleLink);

         lpContainerLine->m_lpOleLink = NULL;

      }

   }

   if (lpContainerLine->m_lpszShortType) {

      OleStdFreeString(lpContainerLine->m_lpszShortType, NULL);

      lpContainerLine->m_lpszShortType = NULL;

   }

}

/* ContainerLine_Delete

** --------------------

**    Delete the ContainerLine.

**

**    NOTE: we can NOT directly destroy the memory for the

**    ContainerLine; the ContainerLine maintains a reference count. a

**    non-zero reference count indicates that the object is still

**    in-use. The OleObject keeps a reference-counted pointer to the

**    ClientLine object. we must take the actions necessary so that the

**    ContainerLine object receives Releases for outstanding

**    references. when the reference count of the ContainerLine reaches

**    zero, then the memory for the object will actually be destroyed

**    (ContainerLine_Destroy called).

**

*/

void ContainerLine_Delete(LPCONTAINERLINE lpContainerLine)

{

   OLEDBG_BEGIN2("ContainerLine_Delete\r\n")

#if defined( INPLACE_CNTR )

   if (lpContainerLine == lpContainerLine->m_lpDoc->m_lpLastIpActiveLine)

      lpContainerLine->m_lpDoc->m_lpLastIpActiveLine = NULL;

   if (lpContainerLine == lpContainerLine->m_lpDoc->m_lpLastUIActiveLine)

      lpContainerLine->m_lpDoc->m_lpLastUIActiveLine = NULL;

#endif

   /* OLE2NOTE: in order to have a stable line object during the

   **    process of deleting, we intially AddRef the line ref cnt and

   **    later Release it. This initial AddRef is artificial; it is

   **    simply done to guarantee that our object does not destroy

   **    itself until the END of this routine.

   */

   ContainerLine_AddRef(lpContainerLine);

   // Unload the loaded OLE object

   if (lpContainerLine->m_lpOleObj)

      ContainerLine_UnloadOleObject(lpContainerLine, OLECLOSE_NOSAVE);

   /* OLE2NOTE: we can NOT directly free the memory for the ContainerLine

   **    data structure until everyone holding on to a pointer to our

   **    ClientSite interface and IAdviseSink interface has released

   **    their pointers. There is one refcnt on the ContainerLine object

   **    which is held by the container itself. we will release this

   **    refcnt here.

   */

   ContainerLine_Release(lpContainerLine);

   /* OLE2NOTE: this call forces all external connections to our

   **    ContainerLine to close down and therefore guarantees that

   **    we receive all releases associated with those external

   **    connections. Strictly this call should NOT be necessary, but

   **    it is defensive coding to make this call.

   */

   OLEDBG_BEGIN2("CoDisconnectObject(lpContainerLine) called\r\n")

   CoDisconnectObject((LPUNKNOWN)&lpContainerLine->m_Unknown, 0);

   OLEDBG_END2

#if defined( _DEBUG )

   /* at this point the object all references from the OLE object to

   **    our ContainerLine object should have been released. there

   **    should only be 1 remaining reference that will be released below.

   */

   if (lpContainerLine->m_cRef != 1) {

      OleDbgOutRefCnt(

         "WARNING: ContainerLine_Delete: cRef != 1\r\n",

         lpContainerLine,

         lpContainerLine->m_cRef

      );

   }

#endif

   ContainerLine_Release(lpContainerLine); // release artificial AddRef above

   OLEDBG_END2

}

/* ContainerLine_Destroy

** ---------------------

**    Destroy (Free) the memory used by a ContainerLine structure.

**    This function is called when the ref count of the ContainerLine goes

**    to zero. the ref cnt goes to zero after ContainerLine_Delete forces

**    the OleObject to unload and release its pointers to the

**    ContainerLine IOleClientSite and IAdviseSink interfaces.

*/

void ContainerLine_Destroy(LPCONTAINERLINE lpContainerLine)

{

   LPUNKNOWN lpTmpObj;

   OLEDBG_BEGIN2("ContainerLine_Destroy\r\n")

   // Release the storage opened for the OLE object

   if (lpContainerLine->m_lpStg) {

      lpTmpObj = (LPUNKNOWN)lpContainerLine->m_lpStg;

      lpContainerLine->m_lpStg = NULL;

      OleStdRelease(lpTmpObj);

   }

   if (lpContainerLine->m_lpszShortType) {

      OleStdFreeString(lpContainerLine->m_lpszShortType, NULL);

      lpContainerLine->m_lpszShortType = NULL;

   }

   Delete(lpContainerLine);        // Free the memory for the structure itself

   OLEDBG_END2

}

/* ContainerLine_CopyToDoc

 * -----------------------

 *

 *      Copy a ContainerLine to another Document (usually ClipboardDoc)

 */

BOOL ContainerLine_CopyToDoc(

      LPCONTAINERLINE         lpSrcLine,

      LPOUTLINEDOC            lpDestDoc,

      int                     nIndex

)

{

   LPCONTAINERLINE lpDestLine = NULL;

   LPLINELIST  lpDestLL = &lpDestDoc->m_LineList;

   HDC         hDC;

   HRESULT     hrErr;

   BOOL        fStatus;

   LPSTORAGE   lpDestDocStg = ((LPOLEDOC)lpDestDoc)->m_lpStg;

   LPSTORAGE   lpDestObjStg = NULL;

   lpDestLine = (LPCONTAINERLINE) New((DWORD)sizeof(CONTAINERLINE));

   if (lpDestLine == NULL) {

      OleDbgAssertSz(lpDestLine!=NULL, "Error allocating ContainerLine");

      return FALSE;

   }

   hDC = LineList_GetDC(lpDestLL);

   ContainerLine_Init(lpDestLine, ((LPLINE)lpSrcLine)->m_nTabLevel, hDC);

   LineList_ReleaseDC(lpDestLL, hDC);

   /* OLE2NOTE: In order to have a stable ContainerLine object we must

   **    AddRef the object's refcnt. this will be later released when

   **    the ContainerLine is deleted.

   */

   ContainerLine_AddRef(lpDestLine);

   lpDestLine->m_lpDoc = (LPCONTAINERDOC)lpDestDoc;

   // Copy data of the original source ContainerLine.

   ((LPLINE)lpDestLine)->m_nWidthInHimetric =

         ((LPLINE)lpSrcLine)->m_nWidthInHimetric;

   ((LPLINE)lpDestLine)->m_nHeightInHimetric =

         ((LPLINE)lpSrcLine)->m_nHeightInHimetric;

   lpDestLine->m_fMonikerAssigned = lpSrcLine->m_fMonikerAssigned;

   lpDestLine->m_dwDrawAspect = lpSrcLine->m_dwDrawAspect;

   lpDestLine->m_sizeInHimetric = lpSrcLine->m_sizeInHimetric;

   lpDestLine->m_dwLinkType = lpSrcLine->m_dwLinkType;

   /* We must create a new sub-storage for the embedded object within

   **    the destination document's storage. We will first attempt to

   **    use the same storage name as the source line. if this name is

   **    in use, then we will allocate a new name. in this way we try

   **    to keep the name associated with the OLE object unchanged

   **    through a Cut/Paste operation.

   */

   lpDestObjStg = OleStdCreateChildStorage(

         lpDestDocStg,

         lpSrcLine->m_szStgName

   );

   if (lpDestObjStg) {

      OLESTRCPY(lpDestLine->m_szStgName, lpSrcLine->m_szStgName);

   } else {

      /* the original name was in use, make up a new name. */

      ContainerDoc_GetNextStgName(

            (LPCONTAINERDOC)lpDestDoc,

            lpDestLine->m_szStgName,

            OLESTRLEN(lpDestLine->m_szStgName)

      );

      lpDestObjStg = OleStdCreateChildStorage(

            lpDestDocStg,

            lpDestLine->m_szStgName

      );

   }

   if (lpDestObjStg == NULL) {

      OleDbgAssertSz(lpDestObjStg != NULL, "Error creating child stg");

      goto error;

   }

   // Copy over storage of the embedded object itself

   if (! lpSrcLine->m_lpOleObj) {

      /*****************************************************************

      ** CASE 1: object is NOT loaded.

      **    because the object is not loaded, we can simply copy the

      **    object's current storage to the new storage.

      *****************************************************************/

      /* if current object storage is not already open, then open it */

      if (! lpSrcLine->m_lpStg) {

         LPSTORAGE lpSrcDocStg = ((LPOLEDOC)lpSrcLine->m_lpDoc)->m_lpStg;

         if (! lpSrcDocStg) goto error;

         // open object storage.

         lpSrcLine->m_lpStg = OleStdOpenChildStorage(

               lpSrcDocStg,

               lpSrcLine->m_szStgName,

               STGM_READWRITE

         );

         if (lpSrcLine->m_lpStg == NULL) {

#if defined( _DEBUG )

            OleDbgAssertSz(

                  lpSrcLine->m_lpStg != NULL,

                  "Error opening child stg"

            );

#endif

            goto error;

         }

      }

      hrErr = lpSrcLine->m_lpStg->lpVtbl->CopyTo(

            lpSrcLine->m_lpStg,

            0,

            NULL,

            NULL,

            lpDestObjStg

      );

      if (hrErr != NOERROR) {

         OleDbgOutHResult("WARNING: lpSrcObjStg->CopyTo returned", hrErr);

         goto error;

      }

      fStatus = OleStdCommitStorage(lpDestObjStg);

   } else {

      /*****************************************************************

      ** CASE 2: object IS loaded.

      **    we must tell the object to save into the new storage.

      *****************************************************************/

      SCODE sc = S_OK;

      LPPERSISTSTORAGE lpPersistStg = lpSrcLine->m_lpPersistStg;

      OleDbgAssert(lpPersistStg);

      OLEDBG_BEGIN2("OleSave called\r\n")

      hrErr = OleSave(lpPersistStg, lpDestObjStg, FALSE /*fSameAsLoad*/);

      OLEDBG_END2

      if (hrErr != NOERROR) {

         OleDbgOutHResult("WARNING: OleSave returned", hrErr);

         sc = GetScode(hrErr);

      }

      // OLE2NOTE: even if OleSave fails, SaveCompleted must be called.

      OLEDBG_BEGIN2("IPersistStorage::SaveCompleted called\r\n")

      hrErr=lpPersistStg->lpVtbl->SaveCompleted(lpPersistStg,NULL);

      OLEDBG_END2

      if (hrErr != NOERROR) {

         OleDbgOutHResult("WARNING: SaveCompleted returned",hrErr);

         if (sc == S_OK)

            sc = GetScode(hrErr);

      }

      if (sc != S_OK)

         goto error;

   }

   OutlineDoc_AddLine(lpDestDoc, (LPLINE)lpDestLine, nIndex);

   OleStdVerifyRelease(

         (LPUNKNOWN)lpDestObjStg,

         OLESTR("Copied object stg not released")

   );

   return TRUE;

error:

   // Delete any partially created storage.

   if (lpDestObjStg) {

      OleStdVerifyRelease(

            (LPUNKNOWN)lpDestObjStg,

            OLESTR("Copied object stg not released")

      );

      lpDestDocStg->lpVtbl->DestroyElement(

            lpDestDocStg,

            lpDestLine->m_szStgName

      );

      lpDestLine->m_szStgName[0] = '\0';

   }

   // destroy partially created ContainerLine

   if (lpDestLine)

      ContainerLine_Delete(lpDestLine);

   return FALSE;

}

/* ContainerLine_UpdateExtent

** --------------------------

**   Update the size of the ContainerLine because the extents of the

**    object may have changed.

**

**    NOTE: because we are using a Windows OwnerDraw ListBox, we must

**    constrain the maximum possible height of a line. the ListBox has

**    a limitation (unfortunately) that no line can become larger than

**    255 pixels. thus we force the object to scale maintaining its

**    aspect ratio if this maximum line height limit is reached. the

**    actual maximum size for an object at 100% Zoom is

**    255

**

**    RETURNS TRUE -- if the extents of the object changed

**            FALSE -- if the extents did NOT change

*/

BOOL ContainerLine_UpdateExtent(

      LPCONTAINERLINE     lpContainerLine,

      LPSIZEL             lpsizelHim

)

{

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerLine->m_lpDoc;

   LPLINELIST lpLL = OutlineDoc_GetLineList(lpOutlineDoc);

   LPLINE lpLine = (LPLINE)lpContainerLine;

   int nIndex = LineList_GetLineIndex(lpLL, lpLine);

   UINT nOrgWidthInHimetric = lpLine->m_nWidthInHimetric;

   UINT nOrgHeightInHimetric = lpLine->m_nHeightInHimetric;

   BOOL fWidthChanged = FALSE;

   BOOL fHeightChanged = FALSE;

   SIZEL sizelHim;

   HRESULT hrErr;

   if (!lpContainerLine || !lpContainerLine->m_lpOleObj)

      return FALSE;

   if (lpContainerLine->m_fGuardObj)

      return FALSE;                // object in process of creation

   OLEDBG_BEGIN3("ContainerLine_UpdateExtent\r\n");

   lpContainerLine->m_fDoGetExtent = FALSE;

   if (! lpsizelHim) {

      /* OLE2NOTE: We want to call IViewObject2::GetExtent instead of

      **    IOleObject::GetExtent. IViewObject2::GetExtent method was

      **    added in OLE 2.01 release. It always retrieves the

      **    extents of the object corresponding to that which will be

      **    drawn by calling IViewObject::Draw. Normally, this is

      **    determined by the data stored in the data cache. This

      **    call will never result in a remoted (LRPC) call.

      */

      OLEDBG_BEGIN2("IViewObject2::GetExtent called\r\n")

      hrErr = lpContainerLine->m_lpViewObj2->lpVtbl->GetExtent(

            lpContainerLine->m_lpViewObj2,

            lpContainerLine->m_dwDrawAspect,

            -1,     /*lindex*/

            NULL,   /*ptd*/

            (LPSIZEL)&sizelHim

      );

      OLEDBG_END2

      if (hrErr != NOERROR)

         sizelHim.cx = sizelHim.cy = 0;

      lpsizelHim = (LPSIZEL)&sizelHim;

   }

   if (lpsizelHim->cx == lpContainerLine->m_sizeInHimetric.cx &&

      lpsizelHim->cy == lpContainerLine->m_sizeInHimetric.cy) {

      goto noupdate;

   }

   if (lpsizelHim->cx > 0 || lpsizelHim->cy > 0) {

      lpContainerLine->m_sizeInHimetric = *lpsizelHim;

   } else {

      /* object does not have any extents; let's use our container

      **    chosen arbitrary size for OLE objects.

      */

      lpContainerLine->m_sizeInHimetric.cx = (long)DEFOBJWIDTH;

      lpContainerLine->m_sizeInHimetric.cy = (long)DEFOBJHEIGHT;

   }

   ContainerLine_SetLineHeightFromObjectExtent(

         lpContainerLine,

         (LPSIZEL)&lpContainerLine->m_sizeInHimetric);

   // if height of object changed, then reset the height of line in LineList

   if (nOrgHeightInHimetric != lpLine->m_nHeightInHimetric) {

      LineList_SetLineHeight(lpLL, nIndex, lpLine->m_nHeightInHimetric);

      fHeightChanged = TRUE;

   }

   fWidthChanged = LineList_RecalcMaxLineWidthInHimetric(

         lpLL,

         nOrgWidthInHimetric

   );

   fWidthChanged |= (nOrgWidthInHimetric != lpLine->m_nWidthInHimetric);

   if (fHeightChanged || fWidthChanged) {

      OutlineDoc_ForceRedraw(lpOutlineDoc, TRUE);

      // mark ContainerDoc as now dirty

      OutlineDoc_SetModified(lpOutlineDoc, TRUE, TRUE, TRUE);

   }

   OLEDBG_END3

   return TRUE;

noupdate:

   OLEDBG_END3

   return FALSE;   // No UPDATE necessary

}

/* ContainerLine_DoVerb

** --------------------

**    Activate the OLE object and perform a specific verb.

*/

BOOL ContainerLine_DoVerb(

      LPCONTAINERLINE lpContainerLine,

      LONG            iVerb,

      LPMSG           lpMsg,

      BOOL            fMessage,

      BOOL            fAction

)

{

   HRESULT hrErr;

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpContainerLine->m_lpDoc;

   RECT rcPosRect;

   OLEDBG_BEGIN3("ContainerLine_DoVerb\r\n")

   if (lpContainerLine->m_fGuardObj) {

      // object in process of creation--Fail the DoVerb call

      hrErr = ResultFromScode(E_FAIL);

      goto error;

   }

   /* if object is not already loaded, then load it now. objects are

   **    loaded lazily in this manner.

   */

   if (! lpContainerLine->m_lpOleObj)

      ContainerLine_LoadOleObject(lpContainerLine);

   if (! lpContainerLine->m_lpOleObj) {

#if defined( _DEBUG )

      OleDbgAssertSz(

            lpContainerLine->m_lpOleObj != NULL,

            "OLE object not loaded"

      );

#endif

      goto error;

   }

ExecuteDoVerb:

   ContainerLine_GetPosRect(lpContainerLine, (LPRECT)&rcPosRect);

   // run the object

   hrErr = ContainerLine_RunOleObject(lpContainerLine);

   if (hrErr != NOERROR)

      goto error;

   /* Tell object server to perform a "verb". */

   OLEDBG_BEGIN2("IOleObject::DoVerb called\r\n")

   hrErr = lpContainerLine->m_lpOleObj->lpVtbl->DoVerb (

         lpContainerLine->m_lpOleObj,

         iVerb,

         lpMsg,

         (LPOLECLIENTSITE)&lpContainerLine->m_OleClientSite,

         -1,

         OutlineDoc_GetWindow(lpOutlineDoc),

         (LPCRECT)&rcPosRect

   );

   OLEDBG_END2

   /* OLE2NOTE: IOleObject::DoVerb may return a success code

   **    OLE_S_INVALIDVERB. this SCODE should NOT be considered an

   **    error; thus it is important to use the "FAILED" macro to

   **    check for an error SCODE.

   */

   if (FAILED(GetScode(hrErr))) {

      OleDbgOutHResult("WARNING: lpOleObj->DoVerb returned", hrErr);

      goto error;

   }

#if defined( INPLACE_CNTR )

   /* OLE2NOTE: we want to keep only 1 inplace server active at any

   **    given time. so when we start to do a DoVerb on another line,

   **    then we want to shut down the previously activated server. in

   **    this way we keep at most one inplace server active at a time.

   **    because it is possible that the object we want to do DoVerb

   **    on is handled by the same EXE as that of the previously

   **    activated server, then we do not want the EXE to be shut down

   **    only to be launched again. in order to avoid this we will do

   **    the DoVerb BEFORE trying to shutdown the previous object.

   */

   if (!g_fInsideOutContainer) {

      ContainerDoc_ShutDownLastInPlaceServerIfNotNeeded(

            lpContainerLine->m_lpDoc, lpContainerLine);

   }

#endif  // INPLACE_CNTR

   OLEDBG_END3

   return TRUE;

error:

   if (lpContainerLine->m_dwLinkType != 0)

      lpContainerLine->m_fLinkUnavailable = TRUE;

#if defined( INPLACE_CNTR )

   /* OLE2NOTE: we want to keep only 1 inplace server active at any

   **    given time. so when we start to do a DoVerb on another line,

   **    then we want to shut down the previously activated server. in

   **    this way we keep at most one inplace server active at a time.

   **    even though the DoVerb failed, we will still shutdown the

   **    previous server. it is possible that we ran out of memory and

   **    that the DoVerb will succeed next time after shutting down

   **    the pervious server.

   */

   if (!g_fInsideOutContainer) {

      ContainerDoc_ShutDownLastInPlaceServerIfNotNeeded(

            lpContainerLine->m_lpDoc, lpContainerLine);

   }

#endif  // INPLACE_CNTR

   /* OLE2NOTE: if an error occurs we must give the appropriate error

   **    message box. there are many potential errors that can occur.

   **    the OLE2.0 user model has specific guidelines as to the

   **    dialogs that should be displayed given the various potential

   **    errors (eg. server not registered, unavailable link source.

   **    the OLE2UI library includes support for most of the

   **    recommended message dialogs. (see OleUIPrompUser function)

   */

   if (fMessage) {

      BOOL fReDoVerb = ContainerLine_ProcessOleRunError(

            lpContainerLine,

            hrErr,

            fAction,

            (lpMsg==NULL && iVerb>=0)   /* fMenuInvoked */

      );

      if (fReDoVerb) {

         goto ExecuteDoVerb;

      }

   }

   OLEDBG_END3

   return FALSE;

}

/* ContainerLine_ProcessOleRunError

 * --------------------------------

 *

 *  Handle the various errors possible when attempting OleRun of an object.

 *  Popup up appropriate message according to the error and/or take action

 *  specified button pressed by the user.

 *

 *  OLE2NOTE: The OLE 2.0 User Interface Guidelines specify the messages

 *            that should be given for the following situations:

 *                  1. Link Source Unavailable...goto Links dialog

 *                  2. Server Not Registered...goto Convert dialog

 *                  3. Link Type Changed

 *                  4. Server Not Found

 *

 *  Returns:    TRUE -- repeat IOleObject::DoVerb call.

 *              FALSE -- do NOT repeat IOleObject::DoVerb call.

 *

 *  Comments:

 *      (see LinkTypeChanged case)

 */

BOOL ContainerLine_ProcessOleRunError(

      LPCONTAINERLINE         lpContainerLine,

      HRESULT                 hrErr,

      BOOL                    fAction,

      BOOL                    fMenuInvoked

)

{

   LPOUTLINEDOC    lpOutlineDoc = (LPOUTLINEDOC)lpContainerLine->m_lpDoc;

   HWND            hwndParent = OutlineDoc_GetWindow(lpOutlineDoc);

   SCODE           sc = GetScode(hrErr);

   BOOL            fReDoVerb = FALSE;

   char szTemp[256];

   char szTemp2[256];

   OleDbgOutHResult("ProcessError", hrErr);

   if ((sc >= MK_E_FIRST) && (sc <= MK_E_LAST))

      goto LinkSourceUnavailable;

   if (sc == OLE_E_CANT_BINDTOSOURCE)

      goto LinkSourceUnavailable;

   if (sc == STG_E_PATHNOTFOUND)

      goto LinkSourceUnavailable;

   if (sc == REGDB_E_CLASSNOTREG)

      goto ServerNotReg;

   if (sc == OLE_E_STATIC)

      goto ServerNotReg;  // user dblclk'ed a static object w/ no svr reg'd

   if (sc == OLE_E_CLASSDIFF)

      goto LinkTypeChanged;

   if (sc == CO_E_APPDIDNTREG)

      goto ServerNotFound;

   if (sc == CO_E_APPNOTFOUND)

      goto ServerNotFound;

   if (sc == E_OUTOFMEMORY)

      goto OutOfMemory;

   if (ContainerLine_IsOleLink(lpContainerLine))

      goto LinkSourceUnavailable;

   else

      goto ServerNotFound;

/*************************************************************************

** Error handling routines                                              **

*************************************************************************/

LinkSourceUnavailable:

   wcstombs(szTemp, APPNAME, 255);

   if (ID_PU_LINKS == OleUIPromptUser(

            (WORD)IDD_LINKSOURCEUNAVAILABLE,

            hwndParent,

            szTemp)) {

      if (fAction) {

         ContainerDoc_EditLinksCommand(lpContainerLine->m_lpDoc);

      }

   }

   return fReDoVerb;

ServerNotReg:

   {

   LPOLESTR lpszUserType = NULL;

   CLIPFORMAT  cfFormat;       // not used

   hrErr = ReadFmtUserTypeStg(

         lpContainerLine->m_lpStg, &cfFormat, &lpszUserType);

   wcstombs(szTemp, APPNAME, 255);

   wcstombs(szTemp2, lpszUserType, 255);

   if (ID_PU_CONVERT == OleUIPromptUser(

         (WORD)IDD_SERVERNOTREG,

         hwndParent,

         szTemp,

         (hrErr == NOERROR) ? szTemp2 : "Unknown Object")) {

      if (fAction) {

         ContainerDoc_ConvertCommand(

               lpContainerLine->m_lpDoc,

               TRUE        // fMustActivate

         );

      }

   }

   if (lpszUserType)

      OleStdFreeString(lpszUserType, NULL);

   return fReDoVerb;

   }

LinkTypeChanged:

   {

   /* OLE2NOTE: If IOleObject::DoVerb is executed on a Link object and it

   **    returns OLE_E_CLASSDIFF because the link source is no longer

   **    the expected class, then if the verb is a semantically

   **    defined verb (eg. OLEIVERB_PRIMARY, OLEIVERB_SHOW,

   **    OLEIVERB_OPEN, etc.), then the link should be re-created with

   **    the new link source and the same verb executed on the new

   **    link. there is no need to give a message to the user. if the

   **    user had selected a verb from the object's verb menu

   **    (fMenuInvoked==TRUE), then we can not be certain of the

   **    semantics of the verb and whether the new link can still

   **    support the verb. in this case the user is given a prompt

   **    telling him to "choose a different command offered by the new

   **    type".

   */

   LPOLESTR       lpszUserType = NULL;

   if (fMenuInvoked) {

      hrErr = lpContainerLine->m_lpOleObj->lpVtbl->GetUserType(

            lpContainerLine->m_lpOleObj,USERCLASSTYPE_FULL,&lpszUserType);

      wcstombs(szTemp, APPNAME, 255);

      wcstombs(szTemp2, lpszUserType, 255);

      OleUIPromptUser(

            (WORD)IDD_LINKTYPECHANGED,

            hwndParent,

            szTemp,

            (hrErr == NOERROR) ? szTemp2 : "Unknown Object"

      );

   } else {

      fReDoVerb = TRUE;

   }

   ContainerLine_ReCreateLinkBecauseClassDiff(lpContainerLine);

   if (lpszUserType)

      OleStdFreeString(lpszUserType, NULL);

   return fReDoVerb;

   }

ServerNotFound:

   wcstombs(szTemp, APPNAME, 255);

   OleUIPromptUser(

         (WORD)IDD_SERVERNOTFOUND,

         hwndParent,

         (LPOLESTR)szTemp);

   return fReDoVerb;

OutOfMemory:

   wcstombs(szTemp, APPNAME, 255);

   OleUIPromptUser(

         (WORD)IDD_OUTOFMEMORY,

         hwndParent,

         szTemp);

   return fReDoVerb;

}

/* ContainerLine_ReCreateLinkBecauseClassDiff

** ------------------------------------------

**    Re-create the link. The existing link was created when

**    the moniker binds to a link source bound of a different class

**    than the same moniker currently binds to. the link may be a

**    special link object specifically used with the old link

**    source class. thus the link object needs to be re-created to

**    give the new link source the opportunity to create its own

**    special link object. (see description "Custom Link Source")

*/

HRESULT ContainerLine_ReCreateLinkBecauseClassDiff(

      LPCONTAINERLINE lpContainerLine

)

{

   LPOLELINK   lpOleLink = lpContainerLine->m_lpOleLink;

   HGLOBAL     hMetaPict = NULL;

   LPMONIKER   lpmkLinkSrc = NULL;

   SCODE       sc = E_FAIL;

   HRESULT     hrErr;

   if (lpOleLink &&

      lpOleLink->lpVtbl->GetSourceMoniker(

            lpOleLink, (LPMONIKER FAR*)&lpmkLinkSrc) == NOERROR) {

      BOOL            fDisplayAsIcon =

                     (lpContainerLine->m_dwDrawAspect==DVASPECT_ICON);

      STGMEDIUM       medium;

      LPDATAOBJECT    lpDataObj = NULL;

      DWORD           dwOleRenderOpt;

      FORMATETC       renderFmtEtc;

      LPFORMATETC     lpRenderFmtEtc = NULL;

      // get the current icon if object is displayed as icon

      if (fDisplayAsIcon &&

         (lpDataObj = (LPDATAOBJECT)OleStdQueryInterface( (LPUNKNOWN)

               lpContainerLine->m_lpOleObj,&IID_IDataObject)) != NULL ) {

         hMetaPict = OleStdGetData(

               lpDataObj, CF_METAFILEPICT, NULL, DVASPECT_ICON, &medium);

         OleStdRelease((LPUNKNOWN)lpDataObj);

      }

      if (fDisplayAsIcon && hMetaPict) {

         // a special icon should be used. first we create the object

         // OLERENDER_NONE. then we stuff the special icon into the cache.

         dwOleRenderOpt = OLERENDER_NONE;

      } else if (fDisplayAsIcon && hMetaPict == NULL) {

         // the object's default icon should be used

         dwOleRenderOpt = OLERENDER_DRAW;

         lpRenderFmtEtc = (LPFORMATETC)&renderFmtEtc;

         SETFORMATETC(renderFmtEtc,0,DVASPECT_ICON,NULL,TYMED_NULL,-1);

      } else {

         // create standard DVASPECT_CONTENT/OLERENDER_DRAW object

         dwOleRenderOpt = OLERENDER_DRAW;

      }

      // unload original link object

      ContainerLine_UnloadOleObject(lpContainerLine, OLECLOSE_SAVEIFDIRTY);

      // delete entire contents of the current object's storage

      OleStdDestroyAllElements(lpContainerLine->m_lpStg);

      OLEDBG_BEGIN2("OleCreateLink called\r\n")

      hrErr = OleCreateLink (

            lpmkLinkSrc,

            &IID_IOleObject,

            dwOleRenderOpt,

            lpRenderFmtEtc,

            (LPOLECLIENTSITE)&lpContainerLine->m_OleClientSite,

            lpContainerLine->m_lpStg,

            (LPVOID FAR*)&lpContainerLine->m_lpOleObj

      );

      OLEDBG_END2

      if (hrErr == NOERROR) {

         if (! ContainerLine_SetupOleObject(

               lpContainerLine, fDisplayAsIcon, hMetaPict) ) {

            // ERROR: setup of the new link failed.

            // revert the storage to restore the original link.

            ContainerLine_UnloadOleObject(

                  lpContainerLine, OLECLOSE_NOSAVE);

            lpContainerLine->m_lpStg->lpVtbl->Revert(

                  lpContainerLine->m_lpStg);

            sc = E_FAIL;

         } else {

            sc = S_OK;  // IT WORKED!

         }

      }

      else {

         sc = GetScode(hrErr);

         OleDbgOutHResult("OleCreateLink returned", hrErr);

         // ERROR: Re-creating the link failed.

         // revert the storage to restore the original link.

         lpContainerLine->m_lpStg->lpVtbl->Revert(

               lpContainerLine->m_lpStg);

      }

   }

   if (hMetaPict)

      OleUIMetafilePictIconFree(hMetaPict); // clean up metafile

   return ResultFromScode(sc);

}

/* ContainerLine_GetOleObject

** --------------------------

**    return pointer to desired interface of embedded/linked object.

**

**    NOTE: this function causes an AddRef to the object. when the caller is

**          finished with the object, it must call Release.

**          this function does not AddRef the ContainerLine object.

*/

LPUNKNOWN ContainerLine_GetOleObject(

      LPCONTAINERLINE         lpContainerLine,

      REFIID                  riid

)

{

   /* if object is not already loaded, then load it now. objects are

   **    loaded lazily in this manner.

   */

   if (! lpContainerLine->m_lpOleObj)

      ContainerLine_LoadOleObject(lpContainerLine);

   if (lpContainerLine->m_lpOleObj)

      return OleStdQueryInterface(

            (LPUNKNOWN)lpContainerLine->m_lpOleObj,

            riid

      );

   else

      return NULL;

}

/* ContainerLine_RunOleObject

** --------------------------

**    Load and run the object. Upon running and if size of object has changed,

**    use SetExtent to change to new size.

**

*/

HRESULT ContainerLine_RunOleObject(LPCONTAINERLINE lpContainerLine)

{

   LPLINE lpLine = (LPLINE)lpContainerLine;

   SIZEL   sizelNew;

   HRESULT hrErr;

   HCURSOR  hPrevCursor;

   if (! lpContainerLine)

      return NOERROR;

   if (lpContainerLine->m_fGuardObj) {

      // object in process of creation--Fail to Run the object

      return ResultFromScode(E_FAIL);

   }

   if (lpContainerLine->m_lpOleObj &&

      OleIsRunning(lpContainerLine->m_lpOleObj))

      return NOERROR;     // object already running

   // this may take a while, put up hourglass cursor

   hPrevCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));

   OLEDBG_BEGIN3("ContainerLine_RunOleObject\r\n")

   if (! lpContainerLine->m_lpOleObj) {

      if (! ContainerLine_LoadOleObject(lpContainerLine))

      {

         SetCursor(hPrevCursor);

         return ResultFromScode(E_OUTOFMEMORY); // Error: couldn't load obj

      }

   }

   OLEDBG_BEGIN2("OleRun called\r\n")

   hrErr = OleRun((LPUNKNOWN)lpContainerLine->m_lpOleObj);

   OLEDBG_END2

   if (hrErr != NOERROR) {

      SetCursor(hPrevCursor);     // restore original cursor

      OleDbgOutHResult("OleRun returned", hrErr);

      OLEDBG_END3

      return hrErr;

   }

   if (lpContainerLine->m_fDoSetExtent) {

      /* OLE2NOTE: the OLE object was resized when it was not running

      **    and the object did not have the OLEMISC_RECOMPOSEONRESIZE

      **    bit set. if it had, the object would have been run

      **    immediately when it was resized. this flag indicates that

      **    the object does something other than simple scaling when

      **    it is resized. because the object is being run now, we

      **    will call IOleObject::SetExtent.

      */

      lpContainerLine->m_fDoSetExtent = FALSE;

      // the size stored in our Line includes the border around the object.

      // we must subtract the border to get the size of the object itself.

      sizelNew.cx = lpLine->m_nWidthInHimetric;

      sizelNew.cy = lpLine->m_nHeightInHimetric;

      if ((sizelNew.cx != lpContainerLine->m_sizeInHimetric.cx) ||

         (sizelNew.cy != lpContainerLine->m_sizeInHimetric.cy)) {

         OLEDBG_BEGIN2("IOleObject::SetExtent called\r\n")

         lpContainerLine->m_lpOleObj->lpVtbl->SetExtent(

               lpContainerLine->m_lpOleObj,

               lpContainerLine->m_dwDrawAspect,

               (LPSIZEL)&sizelNew

         );

         OLEDBG_END2

      }

   }

   SetCursor(hPrevCursor);     // restore original cursor

   OLEDBG_END3

   return NOERROR;

}

/* ContainerLine_IsOleLink

** -----------------------

**

**    return TRUE if the ContainerLine has an OleLink.

**           FALSE if the ContainerLine has an embedding

*/

BOOL ContainerLine_IsOleLink(LPCONTAINERLINE lpContainerLine)

{

   if (!lpContainerLine)

      return FALSE;

   return (lpContainerLine->m_dwLinkType != 0);

}

/*  ContainerLine_Draw

**  ------------------

**

**      Draw a ContainerLine object on a DC.

**

**  Parameters:

**      hDC     - DC to which the line will be drawn

**      lpRect  - the object rect in logical coordinates

**      lpRectWBounds - bounding rect of the metafile underneath hDC

**                      (NULL if hDC is not a metafile DC)

**      fHighlight    - TRUE if line has selection highlight

*/

void ContainerLine_Draw(

      LPCONTAINERLINE         lpContainerLine,

      HDC                     hDC,

      LPRECT                  lpRect,

      LPRECT                  lpRectWBounds,

      BOOL                    fHighlight

)

{

   LPLINE  lpLine = (LPLINE) lpContainerLine;

   HRESULT hrErr = NOERROR;

   RECTL   rclHim;

   RECTL   rclHimWBounds;

   RECT    rcHim;

   if (lpContainerLine->m_fGuardObj) {

      // object in process of creation--do NOT try to draw

      return;

   }

   /* if object is not already loaded, then load it now. objects are

   **    loaded lazily in this manner.

   */

   if (! lpContainerLine->m_lpViewObj2) {

      if (! ContainerLine_LoadOleObject(lpContainerLine))

      {

         return;     // Error: could not load object

      }

   }

   if (lpRectWBounds) {

      rclHimWBounds.left      = (long) lpRectWBounds->left;

      rclHimWBounds.bottom    = (long) lpRectWBounds->bottom;

      rclHimWBounds.top       = (long) lpRectWBounds->top;

      rclHimWBounds.right     = (long) lpRectWBounds->right;

   }

   /* construct bounds rectangle for the object.

   **  offset origin for object to correct tab indentation

   */

   rclHim.left     = (long) lpRect->left;

   rclHim.bottom   = (long) lpRect->bottom;

   rclHim.top      = (long) lpRect->top;

   rclHim.right    = (long) lpRect->right;

   rclHim.left += (long) ((LPLINE)lpContainerLine)->m_nTabWidthInHimetric;

   rclHim.right += (long) ((LPLINE)lpContainerLine)->m_nTabWidthInHimetric;

#if defined( INPLACE_CNTR )

   /* OLE2NOTE: if the OLE object currently has a visible in-place

   **    window, then we do NOT want to draw on top of its window.

   **    this could interfere with the object's display.

   */

   if ( !lpContainerLine->m_fIpVisible )

#endif

   {

   hrErr = lpContainerLine->m_lpViewObj2->lpVtbl->Draw(

         lpContainerLine->m_lpViewObj2,

         lpContainerLine->m_dwDrawAspect,

         -1,

         NULL,

         NULL,

         NULL,

         hDC,

         (LPRECTL)&rclHim,

         (lpRectWBounds ? (LPRECTL)&rclHimWBounds : NULL),

         NULL,

         0

   );

   if (hrErr != NOERROR)

      OleDbgOutHResult("IViewObject::Draw returned", hrErr);

   if (lpContainerLine->m_fObjWinOpen)

      {

      rcHim.left      = (int) rclHim.left;

      rcHim.top       = (int) rclHim.top;

      rcHim.right     = (int) rclHim.right;

      rcHim.bottom    = (int) rclHim.bottom;

      /* OLE2NOTE: if the object servers window is Open (ie. not active

      **    in-place) then we must shade the object in our document to

      **    indicate to the user that the object is open elsewhere.

      */

      OleUIDrawShading((LPRECT)&rcHim, hDC, OLEUI_SHADE_FULLRECT, 0);

      }

   }

   /* if the object associated with the ContainerLine is an automatic

   **    link then try to connect it with its LinkSource if the

   **    LinkSource is already running. we do not want to force the

   **    LinkSource to run.

   **

   **    OLE2NOTE: a sophistocated container will want to continually

   **    attempt to connect its automatic links. OLE does NOT

   **    automatically connect links when link sources become

   **    available. some containers will want to attempt to connect

   **    its links as part of idle time processing. another strategy

   **    is to attempt to connect an automatic link every time it is

   **    drawn on the screen. (this is the strategy used by this

   **    CntrOutl sample application.)

   */

   if (lpContainerLine->m_dwLinkType == OLEUPDATE_ALWAYS)

      ContainerLine_BindLinkIfLinkSrcIsRunning(lpContainerLine);

   return;

}

void ContainerLine_DrawSelHilight(

      LPCONTAINERLINE lpContainerLine,

      HDC             hDC,            // MM_TEXT mode

      LPRECT          lprcPix,        // listbox rect

      UINT            itemAction,

      UINT            itemState

)

{

   LPLINE  lpLine = (LPLINE)lpContainerLine;

   RECT    rcObj;

   DWORD   dwFlags = OLEUI_HANDLES_INSIDE | OLEUI_HANDLES_USEINVERSE;

   int     nHandleSize;

   LPCONTAINERDOC lpContainerDoc;

   if (!lpContainerLine || !hDC || !lprcPix)

      return;

   lpContainerDoc = lpContainerLine->m_lpDoc;

   // Get size of OLE object

   ContainerLine_GetOleObjectRectInPixels(lpContainerLine, (LPRECT)&rcObj);

   nHandleSize = GetProfileInt("windows", "oleinplaceborderwidth",

         DEFAULT_HATCHBORDER_WIDTH) + 1;

   OleUIDrawHandles((LPRECT)&rcObj, hDC, dwFlags, nHandleSize, TRUE);

}

/* InvertDiffRect

** --------------

**

**    Paint the surrounding of the Obj rect black but within lprcPix

**      (similar to the lprcPix minus lprcObj)

*/

static void InvertDiffRect(LPRECT lprcPix, LPRECT lprcObj, HDC hDC)

{

   RECT rcBlack;

   // draw black in all space outside of object's rectangle

   rcBlack.top = lprcPix->top;

   rcBlack.bottom = lprcPix->bottom;

   rcBlack.left = lprcPix->left + 1;

   rcBlack.right = lprcObj->left - 1;

   InvertRect(hDC, (LPRECT)&rcBlack);

   rcBlack.left = lprcObj->right + 1;

   rcBlack.right = lprcPix->right - 1;

   InvertRect(hDC, (LPRECT)&rcBlack);

   rcBlack.top = lprcPix->top;

   rcBlack.bottom = lprcPix->top + 1;

   rcBlack.left = lprcObj->left - 1;

   rcBlack.right = lprcObj->right + 1;

   InvertRect(hDC, (LPRECT)&rcBlack);

   rcBlack.top = lprcPix->bottom;

   rcBlack.bottom = lprcPix->bottom - 1;

   rcBlack.left = lprcObj->left - 1;

   rcBlack.right = lprcObj->right + 1;

   InvertRect(hDC, (LPRECT)&rcBlack);

}

/* Edit the ContainerLine line object.

**      returns TRUE if line was changed

**              FALSE if the line was NOT changed

*/

BOOL ContainerLine_Edit(LPCONTAINERLINE lpContainerLine, HWND hWndDoc,HDC hDC)

{

   ContainerLine_DoVerb(lpContainerLine, OLEIVERB_PRIMARY, NULL, TRUE, TRUE);

   /* assume object was NOT changed, if it was obj will send Changed

   **    or Saved notification.

   */

   return FALSE;

}

/* ContainerLine_SetHeightInHimetric

** ---------------------------------

**

** Set the height of a ContainerLine object. The widht will be changed

** to keep the aspect ratio

*/

void ContainerLine_SetHeightInHimetric(LPCONTAINERLINE lpContainerLine, int nHeight)

{

   LPLINE  lpLine = (LPLINE)lpContainerLine;

   SIZEL   sizelOleObject;

   HRESULT hrErr;

   if (!lpContainerLine)

      return;

   if (lpContainerLine->m_fGuardObj) {

      // object in process of creation--Fail to set the Height

      return;

   }

   if (nHeight != -1) {

      BOOL    fMustClose = FALSE;

      BOOL    fMustRun   = FALSE;

      /* if object is not already loaded, then load it now. objects are

      **    loaded lazily in this manner.

      */

      if (! lpContainerLine->m_lpOleObj)

         ContainerLine_LoadOleObject(lpContainerLine);

      // the height argument specifies the desired height for the Line.

      sizelOleObject.cy = nHeight;

      // we will calculate the corresponding width for the object by

      // maintaining the current aspect ratio of the object.

      sizelOleObject.cx = (int)(sizelOleObject.cy *

            lpContainerLine->m_sizeInHimetric.cx /

            lpContainerLine->m_sizeInHimetric.cy);

      /* OLE2NOTE: if the OLE object is already running then we can

      **    immediately call SetExtent. But, if the object is NOT

      **    currently running then we will check if the object

      **    indicates that it is normally recomposes itself on

      **    resizing. ie. that the object does not simply scale its

      **    display when it it resized. if so then we will force the

      **    object to run so that we can call IOleObject::SetExtent.

      **    SetExtent does not have any effect if the object is only

      **    loaded. if the object does NOT indicate that it

      **    recomposes on resize (OLEMISC_RECOMPOSEONRESIZE) then we

      **    will wait till the next time that the object is run to

      **    call SetExtent. we will store a flag in the ContainerLine

      **    to indicate that a SetExtent is necessary. It is

      **    necessary to persist this flag.

      */

      if (! OleIsRunning(lpContainerLine->m_lpOleObj)) {

         DWORD dwStatus;

         OLEDBG_BEGIN2("IOleObject::GetMiscStatus called\r\n")

         hrErr = lpContainerLine->m_lpOleObj->lpVtbl->GetMiscStatus(

               lpContainerLine->m_lpOleObj,

               lpContainerLine->m_dwDrawAspect,

               (LPDWORD)&dwStatus

         );

         OLEDBG_END2

         if (hrErr == NOERROR && (dwStatus & OLEMISC_RECOMPOSEONRESIZE)) {

            // force the object to run

            ContainerLine_RunOleObject(lpContainerLine);

            fMustClose = TRUE;

         } else {

            /*  the OLE object is NOT running and does NOT

            **    recompose on resize. simply scale the object now

            **    and do the SetExtent the next time the object is

            **    run. we set the Line to the new size even though

            **    the object's extents have not been changed.

            **    this has the result of scaling the object's

            **    display to the new size.

            */

            lpContainerLine->m_fDoSetExtent = TRUE;

            ContainerLine_SetLineHeightFromObjectExtent(

                  lpContainerLine, (LPSIZEL)&sizelOleObject);

            return;

         }

      }

      OLEDBG_BEGIN2("IOleObject::SetExtent called\r\n")

      hrErr = lpContainerLine->m_lpOleObj->lpVtbl->SetExtent(

            lpContainerLine->m_lpOleObj,

            lpContainerLine->m_dwDrawAspect,

            (LPSIZEL)&sizelOleObject);

      OLEDBG_END2

      if (hrErr != NOERROR) {

         /* OLE Object refuses to take on the new extents. Set the

         **    Line to the new size even though the object refused

         **    the new extents. this has the result of scaling the

         **    object's display to the new size.

         **

         **    if the object HAD accepted the new extents, then it

         **    will send out an OnViewChange/OnDataChange

         **    notification. this results in our container receiving

         **    an OnViewChange notification; the line height will be

         **    reset when this notification is received.

         */

         ContainerLine_SetLineHeightFromObjectExtent(

               lpContainerLine, (LPSIZEL)&sizelOleObject);

      }

      if (fMustClose)

         ContainerLine_CloseOleObject(

               lpContainerLine, OLECLOSE_SAVEIFDIRTY);

   }

   else {

      /* Set the line to default height given the natural (unscaled)

      **    extents of the OLE object.

      */

      ContainerLine_SetLineHeightFromObjectExtent(

            lpContainerLine,(LPSIZEL)&lpContainerLine->m_sizeInHimetric);

   }

}

/*  ContainerLine_SetLineHeightFromObjectExtent

 *

 *  Purpose:

 *      Calculate the corresponding line height from the OleObject size

 *      Scale the line height to fit the limit if necessary

 *

 *  Parameters:

 *      lpsizelOleObject        pointer to size of OLE Object

 *

 *  Returns:

 *      nil

 */

void ContainerLine_SetLineHeightFromObjectExtent(

      LPCONTAINERLINE         lpContainerLine,

      LPSIZEL                 lpsizelOleObject

)

{

   LPLINE lpLine = (LPLINE)lpContainerLine;

   UINT uMaxObjectHeight = XformHeightInPixelsToHimetric(NULL,

         LISTBOX_HEIGHT_LIMIT);

   if (!lpContainerLine || !lpsizelOleObject)

      return;

   if (lpContainerLine->m_fGuardObj) {

      // object in process of creation--Fail to set the Height

      return;

   }

   lpLine->m_nWidthInHimetric = (int)lpsizelOleObject->cx;

   lpLine->m_nHeightInHimetric = (int)lpsizelOleObject->cy;

   // Rescale the object if height is greater than the limit

   if (lpLine->m_nHeightInHimetric > (UINT)uMaxObjectHeight) {

      lpLine->m_nWidthInHimetric = (UINT)

            ((long)lpLine->m_nWidthInHimetric *

            (long)uMaxObjectHeight /

            (long)lpLine->m_nHeightInHimetric);

      lpLine->m_nHeightInHimetric = uMaxObjectHeight;

   }

}

/* ContainerLine_SaveToStg

** -----------------------

**    Save a given ContainerLine and associated OLE object to an IStorage*.

*/

BOOL ContainerLine_SaveToStm(

      LPCONTAINERLINE         lpContainerLine,

      LPSTREAM                lpLLStm

)

{

   CONTAINERLINERECORD_ONDISK objLineRecord;

   ULONG nWritten;

   HRESULT hrErr;

   //  Compilers should handle alignment correctly

   OLESTRCPY(objLineRecord.m_szStgName, lpContainerLine->m_szStgName);

   objLineRecord.m_fMonikerAssigned = (USHORT)lpContainerLine->m_fMonikerAssigned;

   objLineRecord.m_dwDrawAspect = lpContainerLine->m_dwDrawAspect;

   objLineRecord.m_sizeInHimetric = lpContainerLine->m_sizeInHimetric;

   objLineRecord.m_dwLinkType = lpContainerLine->m_dwLinkType;

   objLineRecord.m_fDoSetExtent = (USHORT) lpContainerLine->m_fDoSetExtent;

   /* write line record */

   hrErr = lpLLStm->lpVtbl->Write(

         lpLLStm,

         (LPVOID)&objLineRecord,

         sizeof(objLineRecord),

         &nWritten

   );

   if (hrErr != NOERROR) {

      OleDbgAssertSz(hrErr == NOERROR,"Could not write to LineList stream");

    {

      return FALSE;

    }

   }

   return TRUE;

}

/* ContainerLine_SaveOleObjectToStg

** --------------------------------

**    Save the OLE object associated with the ContainerLine to an IStorage*.

*/

BOOL ContainerLine_SaveOleObjectToStg(

      LPCONTAINERLINE         lpContainerLine,

      LPSTORAGE               lpSrcStg,

      LPSTORAGE               lpDestStg,

      BOOL                    fRemember

)

{

   HRESULT         hrErr;

   SCODE           sc = S_OK;

   BOOL            fStatus;

   BOOL            fSameAsLoad = (lpSrcStg==lpDestStg ? TRUE : FALSE);

   LPSTORAGE       lpObjDestStg;

   if (lpContainerLine->m_fGuardObj) {

      // object in process of creation--Fail to save

      return FALSE;

   }

   if (! lpContainerLine->m_lpOleObj) {

      /*****************************************************************

      ** CASE 1: object is NOT loaded.

      *****************************************************************/

      if (fSameAsLoad) {

         /*************************************************************

         ** CASE 1A: we are saving to the current storage. because

         **    the object is not loaded, it is up-to-date

         **    (ie. nothing to do).

         *************************************************************/

         ;

      } else {

         /*************************************************************

         ** CASE 1B: we are saving to a new storage. because

         **    the object is not loaded, we can simply copy the

         **    object's current storage to the new storage.

         *************************************************************/

         /* if current object storage is not already open, then open it */

         if (! lpContainerLine->m_lpStg) {

            lpContainerLine->m_lpStg = OleStdOpenChildStorage(

                  lpSrcStg,

                  lpContainerLine->m_szStgName,

                  STGM_READWRITE

               );

            if (lpContainerLine->m_lpStg == NULL) {

#if defined( _DEBUG )

               OleDbgAssertSz(

                     lpContainerLine->m_lpStg != NULL,

                     "Error opening child stg"

               );

#endif

               return FALSE;

            }

         }

         /* Create a child storage inside the destination storage. */

         lpObjDestStg = OleStdCreateChildStorage(

               lpDestStg,

               lpContainerLine->m_szStgName

         );

         if (lpObjDestStg == NULL) {

#if defined( _DEBUG )

            OleDbgAssertSz(

                  lpObjDestStg != NULL,

                  "Could not create obj storage!"

            );

#endif

            return FALSE;

         }

         hrErr = lpContainerLine->m_lpStg->lpVtbl->CopyTo(

               lpContainerLine->m_lpStg,

               0,

               NULL,

               NULL,

               lpObjDestStg

         );

         // REVIEW: should we handle error here?

         fStatus = OleStdCommitStorage(lpObjDestStg);

         /* if we are supposed to remember this storage as the new

         **    storage for the object, then release the old one and

         **    save the new one. else, throw away the new one.

         */

         if (fRemember) {

            OleStdVerifyRelease(

                  (LPUNKNOWN)lpContainerLine->m_lpStg,

                  OLESTR("Original object stg not released")

            );

            lpContainerLine->m_lpStg = lpObjDestStg;

         } else {

            OleStdVerifyRelease(

                  (LPUNKNOWN)lpObjDestStg,

                  OLESTR("Copied object stg not released")

            );

         }

      }

   } else {

      /*****************************************************************

      ** CASE 2: object IS loaded.

      *****************************************************************/

      if (fSameAsLoad) {

         /*************************************************************

         ** CASE 2A: we are saving to the current storage. if the object

         **    is not dirty, then the current storage is up-to-date

         **    (ie. nothing to do).

         *************************************************************/

         LPPERSISTSTORAGE lpPersistStg = lpContainerLine->m_lpPersistStg;

         OleDbgAssert(lpPersistStg);

         hrErr = lpPersistStg->lpVtbl->IsDirty(lpPersistStg);

         /* OLE2NOTE: we will only accept an explicit "no i

         **    am NOT dirty statement" (ie. S_FALSE) as an

         **    indication that the object is clean. eg. if

         **    the object returns E_NOTIMPL we must

         **    interpret it as the object IS dirty.

         */

         if (GetScode(hrErr) != S_FALSE) {

            /* OLE object IS dirty */

            OLEDBG_BEGIN2("OleSave called\r\n")

            hrErr = OleSave(

                  lpPersistStg, lpContainerLine->m_lpStg, fSameAsLoad);

            OLEDBG_END2

            if (hrErr != NOERROR) {

               OleDbgOutHResult("WARNING: OleSave returned", hrErr);

               sc = GetScode(hrErr);

            }

            // OLE2NOTE: if OleSave fails, SaveCompleted must be called.

            OLEDBG_BEGIN2("IPersistStorage::SaveCompleted called\r\n")

            hrErr=lpPersistStg->lpVtbl->SaveCompleted(lpPersistStg,NULL);

            OLEDBG_END2

            if (hrErr != NOERROR) {

               OleDbgOutHResult("WARNING: SaveCompleted returned",hrErr);

               if (sc == S_OK)

                  sc = GetScode(hrErr);

            }

            if (sc != S_OK)

            {

               return FALSE;

            }

         }

      } else {

         /*************************************************************

         ** CASE 2B: we are saving to a new storage. we must

         **    tell the object to save into the new storage.

         *************************************************************/

         LPPERSISTSTORAGE lpPersistStg = lpContainerLine->m_lpPersistStg;

         if (! lpPersistStg) return FALSE;

         /* Create a child storage inside the destination storage. */

         lpObjDestStg = OleStdCreateChildStorage(

               lpDestStg,

               lpContainerLine->m_szStgName

         );

         if (lpObjDestStg == NULL) {

#if defined( _DEBUG )

            OleDbgAssertSz(

                  lpObjDestStg != NULL,

                  "Could not create object storage!"

            );

#endif

            return FALSE;

         }

         OLEDBG_BEGIN2("OleSave called\r\n")

         hrErr = OleSave(lpPersistStg, lpObjDestStg, fSameAsLoad);

         OLEDBG_END2

         // OLE2NOTE: even if OleSave fails, must still call SaveCompleted

         if (hrErr != NOERROR) {

            OleDbgOutHResult("WARNING: OleSave returned", hrErr);

            sc = GetScode(hrErr);

         }

         /* OLE2NOTE: a root level container should immediately

         **    call IPersistStorage::SaveCompleted after calling

         **    OleSave. a nested level container should not call

         **    SaveCompleted now, but must wait until SaveCompleted

         **    is call on it by its container. since our container

         **    is not a container/server, then we always call

         **    SaveComplete here.

         **

         **    if this is a SaveAs operation, then we need to pass

         **    the lpStg back in SaveCompleted to inform the object

         **    of its new storage that it may hold on to. if this is

         **    a Save or a SaveCopyAs operation, then we simply pass

         **    NULL in SaveCompleted; the object can continue to hold

         **    its current storage. if an error occurs during the

         **    OleSave call we must still call SaveCompleted but we

         **    must pass NULL.

         */

         OLEDBG_BEGIN2("IPersistStorage::SaveCompleted called\r\n")

         hrErr = lpPersistStg->lpVtbl->SaveCompleted(

               lpPersistStg,

               ((FAILED(sc) || !fRemember) ? NULL : lpObjDestStg)

         );

         OLEDBG_END2

         if (hrErr != NOERROR) {

            OleDbgOutHResult("WARNING: SaveCompleted returned",hrErr);

            if (sc == S_OK)

               sc = GetScode(hrErr);

         }

         if (sc != S_OK) {

            OleStdVerifyRelease(

                  (LPUNKNOWN)lpObjDestStg,

                  OLESTR("Copied object stg not released")

            );

            return FALSE;

         }

         /* if we are supposed to remember this storage as the new

         **    storage for the object, then release the old one and

         **    save the new one. else, throw away the new one.

         */

         if (fRemember) {

            OleStdVerifyRelease(

                  (LPUNKNOWN)lpContainerLine->m_lpStg,

                  OLESTR("Original object stg not released")

            );

            lpContainerLine->m_lpStg = lpObjDestStg;

         } else {

            OleStdVerifyRelease(

                  (LPUNKNOWN)lpObjDestStg,

                  OLESTR("Copied object stg not released")

            );

         }

      }

   }

   /* OLE2NOTE: after saving an OLE object it is possible that it sent

   **    an OnViewChange notification because it had been modified. in

   **    this situation it is possible that the extents of the object

   **    have changed. if so we want to relayout the space for the

   **    object immediately so that the extent information saved with

   **    the ContainerLine match the data saved with the OLE object

   **    itself.

   */

   if (lpContainerLine->m_fDoGetExtent) {

      BOOL fSizeChanged = ContainerLine_UpdateExtent(lpContainerLine, NULL);

#if defined( INPLACE_CNTR )

      /* if the extents of this ContainerLine have changed, then we

      **    need to reset the fDoGetExtent flag to TRUE so that later

      **    when ContainerDoc_UpdateExtentOfAllOleObjects is called

      **    (when the WM_U_UPDATEOBJECTEXTENT message is processed),

      **    it is recognized that the extents of this line have

      **    changed. if any line changes size, then any in-place

      **    active object below this line must be told to update the

      **    position of their windows (via SetObjectRects -- see

      **    ContainerDoc_UpdateInPlaceObjectRects function).

      */

      lpContainerLine->m_fDoGetExtent = fSizeChanged;

#endif

   }

   return TRUE;

}

/* ContainerLine_LoadFromStg

** -------------------------

**    Create a ContainerLine object and initialize it with data that

**    was previously writen to an IStorage*. this function does not

**    immediately OleLoad the associated OLE object, only the data of

**    the ContainerLine object itself is loaded from the IStorage*.

*/

LPLINE ContainerLine_LoadFromStg(

      LPSTORAGE               lpSrcStg,

      LPSTREAM                lpLLStm,

      LPOUTLINEDOC            lpDestDoc

)

{

   HDC         hDC;

   LPLINELIST  lpDestLL = &lpDestDoc->m_LineList;

   ULONG nRead;

   HRESULT hrErr;

   LPCONTAINERLINE lpContainerLine;

   CONTAINERLINERECORD_ONDISK objLineRecord;

   lpContainerLine=(LPCONTAINERLINE) New((DWORD)sizeof(objLineRecord));

   if (lpContainerLine == NULL) {

      OleDbgAssertSz(lpContainerLine!=NULL,"Error allocating ContainerLine");

      return NULL;

   }

   hDC = LineList_GetDC(lpDestLL);

   ContainerLine_Init(lpContainerLine, 0, hDC);

   LineList_ReleaseDC(lpDestLL, hDC);

   /* OLE2NOTE: In order to have a stable ContainerLine object we must

   **    AddRef the object's refcnt. this will be later released when

   **    the ContainerLine is deleted.

   */

   ContainerLine_AddRef(lpContainerLine);

   lpContainerLine->m_lpDoc = (LPCONTAINERDOC) lpDestDoc;

   /* read line record */

   hrErr = lpLLStm->lpVtbl->Read(

         lpLLStm,

         (LPVOID)&objLineRecord,

         sizeof(CONTAINERLINERECORD),

         &nRead

   );

   if (hrErr != NOERROR) {

      OleDbgAssertSz(hrErr==NOERROR, "Could not read from LineList stream");

      goto error;

   }

   //  Compilers should handle alignment correctly

   OLESTRCPY(lpContainerLine->m_szStgName, objLineRecord.m_szStgName);

   lpContainerLine->m_fMonikerAssigned = (BOOL) objLineRecord.m_fMonikerAssigned;

   lpContainerLine->m_dwDrawAspect = objLineRecord.m_dwDrawAspect;

   lpContainerLine->m_sizeInHimetric = objLineRecord.m_sizeInHimetric;

   lpContainerLine->m_dwLinkType = objLineRecord.m_dwLinkType;

   lpContainerLine->m_fDoSetExtent = (BOOL) objLineRecord.m_fDoSetExtent;

   return (LPLINE)lpContainerLine;

error:

   // destroy partially created ContainerLine

   if (lpContainerLine)

      ContainerLine_Delete(lpContainerLine);

   return NULL;

}

/* ContainerLine_GetTextLen

 * ------------------------

 *

 * Return length of the string representation of the ContainerLine

 *  (not considering the tab level). we will use the following as the

 *  string representation of a ContainerLine:

 *      "<" + user type name of OLE object + ">"

 *  eg:

 *      <Microsoft Excel Worksheet>

 */

int ContainerLine_GetTextLen(LPCONTAINERLINE lpContainerLine)

{

   LPOLESTR   lpszUserType = NULL;

   HRESULT hrErr;

   int     nLen;

   BOOL    fIsLink = ContainerLine_IsOleLink(lpContainerLine);

   /* if object is not already loaded, then load it now. objects are

   **    loaded lazily in this manner.

   */

   if (! lpContainerLine->m_lpOleObj)

      ContainerLine_LoadOleObject(lpContainerLine);

   OLEDBG_BEGIN2("IOleObject::GetUserType called\r\n")

   hrErr = lpContainerLine->m_lpOleObj->lpVtbl->GetUserType(

         lpContainerLine->m_lpOleObj,

         USERCLASSTYPE_FULL,

         &lpszUserType

   );

   OLEDBG_END2

   if (hrErr != NOERROR)   {

      // user type is NOT available

      nLen = sizeof(UNKNOWN_OLEOBJ_TYPE) + 2; // allow space for '<' + '>'

      nLen += lstrlen((LPSTR)(fIsLink ? szOLELINK : szOLEOBJECT)) + 1;

   } else {

      nLen = OLESTRLEN(lpszUserType) + 2;   // allow space for '<' + '>'

      nLen += OLESTRLEN((LPOLESTR)(fIsLink ? szOLELINK : szOLEOBJECT)) + 1;

      /* OLE2NOTE: we must free the string that was allocated by the

      **    IOleObject::GetUserType method.

      */

      OleStdFreeString(lpszUserType, NULL);

   }

   return nLen;

}

/* ContainerLine_GetTextData

 * -------------------------

 *

 * Return the string representation of the ContainerLine

 *  (not considering the tab level). we will use the following as the

 *  string representation of a ContainerLine:

 *      "<" + user type name of OLE object + ">"

 *  eg:

 *      <Microsoft Excel Worksheet>

 */

void ContainerLine_GetTextData(LPCONTAINERLINE lpContainerLine, LPOLESTR lpszBuf)

{

   LPOLESTR   lpszUserType = NULL;

   BOOL    fIsLink = ContainerLine_IsOleLink(lpContainerLine);

   HRESULT hrErr;

   char    szAnsiBuf[256], szAnsiUserType[256], szAnsiString[256];

   LPOLESTR lpszUniStr;

   /* if object is not already loaded, then load it now. objects are

   **    loaded lazily in this manner.

   */

   if (! lpContainerLine->m_lpOleObj)

      ContainerLine_LoadOleObject(lpContainerLine);

   hrErr = lpContainerLine->m_lpOleObj->lpVtbl->GetUserType(

         lpContainerLine->m_lpOleObj,

         USERCLASSTYPE_FULL,

         &lpszUserType

   );

   W2A (lpszBuf, szAnsiBuf, 256);

   W2A (lpszUserType, szAnsiUserType, 256);

   lpszUniStr = (fIsLink ? szOLELINK : szOLEOBJECT);

   W2A (lpszUniStr, szAnsiString, 256);

   if (hrErr != NOERROR)   {

      // user type is NOT available

      wsprintf(

            szAnsiBuf,

            "<%s %s>",

            UNKNOWN_OLEOBJ_TYPE,

            (LPSTR)szAnsiString

      );

   } else {

      wsprintf(

            szAnsiBuf,

            "<%s %s>",

            szAnsiUserType,

            (LPSTR)szAnsiString

      );

      /* OLE2NOTE: we must free the string that was allocated by the

      **    IOleObject::GetUserType method.

      */

      OleStdFreeString(lpszUserType, NULL);

   }

}

/* ContainerLine_GetOutlineData

 * ----------------------------

 *

 * Return the CF_OUTLINE format data for the ContainerLine.

 */

BOOL ContainerLine_GetOutlineData(

      LPCONTAINERLINE         lpContainerLine,

      LPTEXTLINE              lpBuf

)

{

   LPLINE      lpLine = (LPLINE)lpContainerLine;

   LPLINELIST  lpLL = &((LPOUTLINEDOC)lpContainerLine->m_lpDoc)->m_LineList;

   HDC         hDC;

   OLECHAR     szTmpBuf[MAXSTRLEN+1];

   char        szAnsiStr[256];

   LPTEXTLINE  lpTmpTextLine;

   // Create a TextLine with the Text representation of the ContainerLine.

   ContainerLine_GetTextData(lpContainerLine, (LPOLESTR)szTmpBuf);

   hDC = LineList_GetDC(lpLL);

   W2A (szTmpBuf, szAnsiStr, 256);

   lpTmpTextLine = TextLine_Create(hDC, lpLine->m_nTabLevel, szAnsiStr);

   LineList_ReleaseDC(lpLL, hDC);

   TextLine_Copy(lpTmpTextLine, lpBuf);

   // Delete the temporary TextLine

   TextLine_Delete(lpTmpTextLine);

   return TRUE;

}

/* ContainerLine_GetPosRect

** -----------------------

**    Get the PosRect in client coordinates for the OLE object's window.

**

** OLE2NOTE: the PosRect must take into account the scroll postion of

**    the document window.

*/

void ContainerLine_GetPosRect(

      LPCONTAINERLINE     lpContainerLine,

      LPRECT              lprcPosRect

)

{

   ContainerLine_GetOleObjectRectInPixels(lpContainerLine,lprcPosRect);

   // shift rect for left margin

   lprcPosRect->left += lpContainerLine->m_nHorizScrollShift;

   lprcPosRect->right += lpContainerLine->m_nHorizScrollShift;

}

/* ContainerLine_GetOleObjectRectInPixels

** --------------------------------------

**    Get the extent of the OLE Object contained in the given Line in

**    client coordinates after scaling.

*/

void ContainerLine_GetOleObjectRectInPixels(LPCONTAINERLINE lpContainerLine, LPRECT lprc)

{

   LPOUTLINEDOC lpOutlineDoc;

   LPSCALEFACTOR lpscale;

   LPLINELIST lpLL;

   LPLINE lpLine;

   int nIndex;

   HDC hdcLL;

   if (!lpContainerLine || !lprc)

      return;

   lpOutlineDoc = (LPOUTLINEDOC)lpContainerLine->m_lpDoc;

   lpscale = OutlineDoc_GetScaleFactor(lpOutlineDoc);

   lpLL = OutlineDoc_GetLineList(lpOutlineDoc);

   lpLine = (LPLINE)lpContainerLine;

   nIndex = LineList_GetLineIndex(lpLL, lpLine);

   LineList_GetLineRect(lpLL, nIndex, lprc);

   hdcLL = GetDC(lpLL->m_hWndListBox);

   /* lprc is set to be size of Line Object (including the boundary) */

   lprc->left += (int)(

         (long)XformWidthInHimetricToPixels(hdcLL,

               lpLine->m_nTabWidthInHimetric +

               LOWORD(OutlineDoc_GetMargin(lpOutlineDoc))) *

         lpscale->dwSxN / lpscale->dwSxD);

   lprc->right = (int)(

         lprc->left + (long)

         XformWidthInHimetricToPixels(hdcLL, lpLine->m_nWidthInHimetric) *

         lpscale->dwSxN / lpscale->dwSxD);

   ReleaseDC(lpLL->m_hWndListBox, hdcLL);

}

/* ContainerLine_GetOleObjectSizeInHimetric

** ----------------------------------------

**    Get the size of the OLE Object contained in the given Line

*/

void ContainerLine_GetOleObjectSizeInHimetric(LPCONTAINERLINE lpContainerLine, LPSIZEL lpsizel)

{

   if (!lpContainerLine || !lpsizel)

      return;

   *lpsizel = lpContainerLine->m_sizeInHimetric;

}

/* ContainerLine_BindLinkIfLinkSrcIsRunning

** ----------------------------------------

**    Try to connect the OLE link object associated with the

**    ContainerLine with its LinkSource if the LinkSource is already

**    running and the link is an automatic link. we do not want to

**    force the LinkSource to run.

**

**    OLE2NOTE: a sophistocated container will want to continually

**    attempt to connect its automatic links. OLE does NOT

**    automatically connect links when link source become available. some

**    containers will want to attempt to connect its links as part of

**    idle time processing. another strategy is to attempt to connect

**    an automatic link every time it is drawn on the screen. (this is

**    the strategy used by this CntrOutl sample application.)

*/

void ContainerLine_BindLinkIfLinkSrcIsRunning(LPCONTAINERLINE lpContainerLine)

{

   LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp;

   HRESULT hrErr;

   BOOL fPrevEnable1;

   BOOL fPrevEnable2;

   // if the link source is known to be un-bindable, then don't even try

   if (lpContainerLine->m_fLinkUnavailable)

      return;

   /* OLE2NOTE: we do not want to ever give the Busy/NotResponding

   **    dialogs when we are attempting to BindIfRunning to the link

   **    source. if the link source is currently busy, this could

   **    cause the Busy dialog to come up. even if the link source is

   **    busy, we do not want put up the busy dialog. thus we will

   **    disable the dialog and later re-enable them

   */

   OleApp_DisableBusyDialogs(lpOleApp, &fPrevEnable1, &fPrevEnable2);

   OLEDBG_BEGIN2("IOleLink::BindIfRunning called\r\n")

   hrErr = lpContainerLine->m_lpOleLink->lpVtbl->BindIfRunning(

         lpContainerLine->m_lpOleLink);

   OLEDBG_END2

   // re-enable the Busy/NotResponding dialogs

   OleApp_EnableBusyDialogs(lpOleApp, fPrevEnable1, fPrevEnable2);

}


CNTROUTL.DEF  (OUTLINE Sample)

;;

;;

;;    OLE 2.0 Container Sample Code

;;

;;    cntroutl.def

;;

;;    Definition file for cntroutl.exe

;;

;;    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

;;

;;

NAME            CntrOutl

DESCRIPTION     'Microsoft OLE 2.0 Container Sample code'

EXETYPE         WINDOWS

STUB            'WINSTUB.EXE'

CODE            PRELOAD MOVEABLE

DATA            PRELOAD MOVEABLE MULTIPLE

HEAPSIZE        4096

;; NOTE: Do not add exports to this file.  Use __export

;; in your function prototype and definition instead.


CNTROUTL.H  (OUTLINE Sample)

/*************************************************************************

**

**    OLE 2.0 Container Sample Code

**

**    cntroutl.h

**

**    This file contains file contains data structure defintions,

**    function prototypes, constants, etc. used by the OLE 2.0 container

**    app version of the Outline series of sample applications:

**          Outline -- base version of the app (without OLE functionality)

**          SvrOutl -- OLE 2.0 Server sample app

**          CntrOutl -- OLE 2.0 Containter (Container) sample app

**

**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

**

*************************************************************************/

#if !defined( _CNTROUTL_H_ )

#define _CNTROUTL_H_

#ifndef RC_INVOKED

#pragma message ("INCLUDING CNTROUTL.H from " __FILE__)

#endif  /* RC_INVOKED */

#include "oleoutl.h"

#include "cntrrc.h"

#include "ansiapi.h"

// REVIEW: should load from string resource

#define DEFOBJNAMEPREFIX    "Obj"   // Prefix for auto-generated stg names

#define DEFOBJWIDTH         5000    // default size for embedded obj.

#define DEFOBJHEIGHT        5000    // default size for embedded obj.

#define UNKNOWN_OLEOBJ_TYPE "Unknown OLE Object Type"

#define szOLEOBJECT OLESTR("Object")

#define szOLELINK   OLESTR("Link")

#ifdef TEST32

#define CONTAINERDOCFORMAT  OLESTR("CntrOu32")      // CF_CntrOutl format name

#else

#define CONTAINERDOCFORMAT  OLESTR("CntrOutl")      // CF_CntrOutl format name

#endif //TEST32

/* Forward definition of types */

typedef struct tagCONTAINERDOC FAR* LPCONTAINERDOC;

typedef struct tagCONTAINERLINE FAR* LPCONTAINERLINE;

// Flags to specify type of OLECREATE???FROMDATA call required

typedef enum tagOLECREATEFROMDATATYPE {

   OLECREATEFROMDATA_LINK    = 1,

   OLECREATEFROMDATA_OBJECT  = 2,

   OLECREATEFROMDATA_STATIC  = 3

} OLECREATEFROMDATATYPE;

/*************************************************************************

** class CONTAINERLINE : LINE

**    The class CONTAINERLINE is a concrete subclass of the abstract base

**    class LINE. The CONTAINERLINE maintains all information about the

**    place within the CONTAINERDOC that an OLE object is embedded. This

**    object implements the following OLE 2.0 interfaces:

**          IOleClientSite

**          IAdviseSink

**    In the CntrOutl client app either CONTAINERLINE objects or TEXTLINE

**    objects can be created. The CONTAINERLINE class inherits all fields

**    from the LINE class. This inheritance is achieved by including a

**    member variable of type LINE as the first field in the CONTAINERLINE

**    structure. Thus a pointer to a CONTAINERLINE object can be cast to be

**    a pointer to a LINE object.

**    Each CONTAINERLINE object that is created in added to the LINELIST of

**    the associated OUTLINEDOC document.

*************************************************************************/

typedef struct tagCONTAINERLINE {

   LINE            m_Line;         // ContainerLine inherits fields of Line

   ULONG           m_cRef;         // total ref count for line

   OLECHAR         m_szStgName[CWCSTORAGENAME]; // stg name w/i cntr stg

   BOOL            m_fObjWinOpen;  // is obj window open? if so, shade obj.

   BOOL            m_fMonikerAssigned; // has a moniker been assigned to obj

   DWORD           m_dwDrawAspect; // current display aspect for obj

                           //      (either DVASPECT_CONTENT or

                           //      DVASPECT_ICON)

   BOOL            m_fGuardObj;    // Guard against re-entrancy while

                           //  loading or creating an OLE object

   BOOL            m_fDoGetExtent; // indicates extents may have changed

   BOOL            m_fDoSetExtent; // obj was resized when not running

                           //  IOO::SetExtent needed on next run

   SIZEL           m_sizeInHimetric; // extents of obj in himetric units

   LPSTORAGE       m_lpStg;        // open pstg when obj is loaded

   LPCONTAINERDOC  m_lpDoc;        // ptr to associated client doc

   LPOLEOBJECT     m_lpOleObj;     // ptr to IOleObject* when obj is loaded

   LPVIEWOBJECT2   m_lpViewObj2;   // ptr to IViewObject2* when obj is loaded

   LPPERSISTSTORAGE m_lpPersistStg;// ptr to IPersistStorage* when obj loaded

   LPOLELINK       m_lpOleLink;    // ptr to IOleLink* if link is loaded

   DWORD           m_dwLinkType;   // is it a linked object?

                           //   0 -- NOT a link

                           //   OLEUPDATE_ALWAYS (1) -- auto link

                           //   OLEUPDATE_ONCALL (3) -- man. link

   BOOL            m_fLinkUnavailable;     // is the link unavailable?

   LPOLESTR        m_lpszShortType;// short type name of OLE object needed

                           //  to make the Edit.Object.Verb menu

   int             m_nHorizScrollShift;    // horiz scroll shift required

                           // for object's inplace window.

                           // (note: this is ICNTROTL specific)

#if defined( INPLACE_CNTR )

   BOOL            m_fIpActive;    // is object in-place active (undo valid)

   BOOL            m_fUIActive;    // is object UIActive

   BOOL            m_fIpVisible;   // is object's in-place window visible

   BOOL            m_fInsideOutObj;// is obj inside-out (visible when loaded)

   LPOLEINPLACEOBJECT m_lpOleIPObj; // IOleInPlaceObject* of in-place obj

   BOOL            m_fIpChangesUndoable;   // can in-place object do undo

   BOOL            m_fIpServerRunning; // is in-place server running

   HWND            m_hWndIpObject;

   struct COleInPlaceSiteImpl {

      IOleInPlaceSiteVtbl FAR* lpVtbl;

      LPCONTAINERLINE         lpContainerLine;

      int                     cRef;   // interface specific ref count.

   } m_OleInPlaceSite;

#endif  // INPLACE_CNTR

   struct CUnknownImpl {

      IUnknownVtbl FAR*       lpVtbl;

      LPCONTAINERLINE         lpContainerLine;

      int                     cRef;   // interface specific ref count.

   } m_Unknown;

   struct COleClientSiteImpl {

      IOleClientSiteVtbl FAR* lpVtbl;

      LPCONTAINERLINE         lpContainerLine;

      int                 cRef;   // interface specific ref count.

   } m_OleClientSite;

   struct CAdviseSinkImpl {

      IAdviseSinkVtbl FAR*    lpVtbl;

      LPCONTAINERLINE         lpContainerLine;

      int                     cRef;   // interface specific ref count.

   } m_AdviseSink;

} CONTAINERLINE;

/* ContainerLine methods (functions) */

void ContainerLine_Init(LPCONTAINERLINE lpContainerLine, int nTab, HDC hDC);

BOOL ContainerLine_SetupOleObject(

      LPCONTAINERLINE         lpContainerLine,

      BOOL                    fDisplayAsIcon,

      HGLOBAL                 hMetaPict

);

LPCONTAINERLINE ContainerLine_Create(

      DWORD                   dwOleCreateType,

      HDC                     hDC,

      UINT                    nTab,

      LPCONTAINERDOC          lpContainerDoc,

      LPCLSID                 lpclsid,

      LPOLESTR                lpszFileName,

      BOOL                    fDisplayAsIcon,

      HGLOBAL                 hMetaPict,

      LPOLESTR                lpszStgName

);

LPCONTAINERLINE ContainerLine_CreateFromData(

      HDC                     hDC,

      UINT                    nTab,

      LPCONTAINERDOC          lpContainerDoc,

      LPDATAOBJECT            lpSrcDataObj,

      DWORD                   dwCreateType,

      CLIPFORMAT              cfFormat,

      BOOL                    fDisplayAsIcon,

      HGLOBAL                 hMetaPict,

      LPOLESTR                lpszStgName

);

ULONG ContainerLine_AddRef(LPCONTAINERLINE lpContainerLine);

ULONG ContainerLine_Release(LPCONTAINERLINE lpContainerLine);

HRESULT ContainerLine_QueryInterface(

      LPCONTAINERLINE         lpContainerLine,

      REFIID                  riid,

      LPVOID FAR*             lplpUnk

);

BOOL ContainerLine_CloseOleObject(

      LPCONTAINERLINE         lpContainerLine,

      DWORD                   dwSaveOption

);

void ContainerLine_UnloadOleObject(

      LPCONTAINERLINE         lpContainerLine,

      DWORD                   dwSaveOption

);

void ContainerLine_Delete(LPCONTAINERLINE lpContainerLine);

void ContainerLine_Destroy(LPCONTAINERLINE lpContainerLine);

BOOL ContainerLine_CopyToDoc(

      LPCONTAINERLINE         lpSrcLine,

      LPOUTLINEDOC            lpDestDoc,

      int                     nIndex

);

BOOL ContainerLine_LoadOleObject(LPCONTAINERLINE lpContainerLine);

BOOL ContainerLine_UpdateExtent(

      LPCONTAINERLINE     lpContainerLine,

      LPSIZEL             lpsizelHim

);

BOOL ContainerLine_DoVerb(

      LPCONTAINERLINE lpContainerLine,

      LONG iVerb,

      LPMSG lpMsg,

      BOOL fMessage,

      BOOL fAction

);

LPUNKNOWN ContainerLine_GetOleObject(

      LPCONTAINERLINE         lpContainerLine,

      REFIID                  riid

);

HRESULT ContainerLine_RunOleObject(LPCONTAINERLINE lpContainerLine);

BOOL ContainerLine_ProcessOleRunError(

      LPCONTAINERLINE         lpContainerLine,

      HRESULT                 hrErr,

      BOOL                    fAction,

      BOOL                    fMenuInvoked

);

HRESULT ContainerLine_ReCreateLinkBecauseClassDiff(

      LPCONTAINERLINE lpContainerLine

);

BOOL ContainerLine_IsOleLink(LPCONTAINERLINE lpContainerLine);

void ContainerLine_BindLinkIfLinkSrcIsRunning(LPCONTAINERLINE lpContainerLine);

void ContainerLine_Draw(

      LPCONTAINERLINE         lpContainerLine,

      HDC                     hDC,

      LPRECT                  lpRect,

      LPRECT                  lpRectWBounds,

      BOOL                    fHighlight

);

void ContainerLine_DrawSelHilight(

      LPCONTAINERLINE lpContainerLine,

      HDC             hDC,

      LPRECT          lpRect,

      UINT            itemAction,

      UINT            itemState

);

BOOL ContainerLine_Edit(LPCONTAINERLINE lpContainerLine,HWND hWndDoc,HDC hDC);

void ContainerLine_SetHeightInHimetric(LPCONTAINERLINE lpContainerLine, int nHeight);

void ContainerLine_SetLineHeightFromObjectExtent(

      LPCONTAINERLINE         lpContainerLine,

      LPSIZEL                 lpsizelOleObject

);

BOOL ContainerLine_SaveToStm(

      LPCONTAINERLINE         lpContainerLine,

      LPSTREAM                lpLLStm

);

BOOL ContainerLine_SaveOleObjectToStg(

      LPCONTAINERLINE         lpContainerLine,

      LPSTORAGE               lpSrcStg,

      LPSTORAGE               lpDestStg,

      BOOL                    fRemember

);

LPLINE ContainerLine_LoadFromStg(

      LPSTORAGE               lpSrcStg,

      LPSTREAM                lpLLStm,

      LPOUTLINEDOC            lpDestDoc

);

LPMONIKER ContainerLine_GetRelMoniker(

      LPCONTAINERLINE         lpContainerLine,

      DWORD                   dwAssign

);

LPMONIKER ContainerLine_GetFullMoniker(

      LPCONTAINERLINE         lpContainerLine,

      DWORD                   dwAssign

);

int ContainerLine_GetTextLen(LPCONTAINERLINE lpContainerLine);

void ContainerLine_GetTextData(LPCONTAINERLINE lpContainerLine,LPOLESTR lpszBuf);

BOOL ContainerLine_GetOutlineData(

      LPCONTAINERLINE         lpContainerLine,

      LPTEXTLINE              lpBuf

);

void ContainerLine_GetOleObjectRectInPixels(

      LPCONTAINERLINE lpContainerLine,

      LPRECT lprc

);

void ContainerLine_GetPosRect(

      LPCONTAINERLINE     lpContainerLine,

      LPRECT              lprcPosRect

);

void ContainerLine_GetOleObjectSizeInHimetric(

      LPCONTAINERLINE lpContainerLine,

      LPSIZEL lpsizel

);

#if defined( INPLACE_CNTR )

void ContainerLine_UIDeactivate(LPCONTAINERLINE lpContainerLine);

void ContainerLine_InPlaceDeactivate(LPCONTAINERLINE lpContainerLine);

void ContainerLine_UpdateInPlaceObjectRects(

   LPCONTAINERLINE lpContainerLine,

   LPRECT          lprcClipRect

);

void ContainerLine_ContextSensitiveHelp(

      LPCONTAINERLINE lpContainerLine,

      BOOL            fEnterMode

);

void ContainerLine_ForwardPaletteChangedMsg(

      LPCONTAINERLINE lpContainerLine,

      HWND             hwndPalChg

);

void ContainerDoc_ContextSensitiveHelp(

      LPCONTAINERDOC  lpContainerDoc,

      BOOL            fEnterMode,

      BOOL            fInitiatedByObj

);

void ContainerDoc_ForwardPaletteChangedMsg(

      LPCONTAINERDOC  lpContainerDoc,

      HWND            hwndPalChg

);

#endif  // INPLACE_CNTR

/* ContainerLine::IUnknown methods (functions) */

STDMETHODIMP CntrLine_Unk_QueryInterface(

      LPUNKNOWN           lpThis,

      REFIID              riid,

      LPVOID FAR*         lplpvObj

);

STDMETHODIMP_(ULONG) CntrLine_Unk_AddRef(LPUNKNOWN lpThis);

STDMETHODIMP_(ULONG) CntrLine_Unk_Release(LPUNKNOWN lpThis);

/* ContainerLine::IOleClientSite methods (functions) */

STDMETHODIMP CntrLine_CliSite_QueryInterface(

      LPOLECLIENTSITE     lpThis,

      REFIID              riid,

      LPVOID FAR*         lplpvObj

);

STDMETHODIMP_(ULONG) CntrLine_CliSite_AddRef(LPOLECLIENTSITE lpThis);

STDMETHODIMP_(ULONG) CntrLine_CliSite_Release(LPOLECLIENTSITE lpThis);

STDMETHODIMP CntrLine_CliSite_SaveObject(LPOLECLIENTSITE lpThis);

STDMETHODIMP CntrLine_CliSite_GetMoniker(

      LPOLECLIENTSITE     lpThis,

      DWORD               dwAssign,

      DWORD               dwWhichMoniker,

      LPMONIKER FAR*      lplpmk

);

STDMETHODIMP CntrLine_CliSite_GetContainer(

      LPOLECLIENTSITE     lpThis,

      LPOLECONTAINER FAR* lplpContainer

);

STDMETHODIMP CntrLine_CliSite_ShowObject(LPOLECLIENTSITE lpThis);

STDMETHODIMP CntrLine_CliSite_OnShowWindow(LPOLECLIENTSITE lpThis,BOOL fShow);

STDMETHODIMP CntrLine_CliSite_RequestNewObjectLayout(LPOLECLIENTSITE lpThis);

/* ContainerLine::IAdviseSink methods (functions) */

STDMETHODIMP CntrLine_AdvSink_QueryInterface(

      LPADVISESINK        lpThis,

      REFIID              riid,

      LPVOID FAR*         lplpvObj

);

STDMETHODIMP_(ULONG) CntrLine_AdvSink_AddRef(LPADVISESINK lpThis);

STDMETHODIMP_(ULONG) CntrLine_AdvSink_Release (LPADVISESINK lpThis);

STDMETHODIMP_(void) CntrLine_AdvSink_OnDataChange(

      LPADVISESINK        lpThis,

      FORMATETC FAR*      lpFormatetc,

      STGMEDIUM FAR*      lpStgmed

);

STDMETHODIMP_(void) CntrLine_AdvSink_OnViewChange(

      LPADVISESINK        lpThis,

      DWORD               aspects,

      LONG                lindex

);

STDMETHODIMP_(void) CntrLine_AdvSink_OnRename(

      LPADVISESINK        lpThis,

      LPMONIKER           lpmk

);

STDMETHODIMP_(void) CntrLine_AdvSink_OnSave(LPADVISESINK lpThis);

STDMETHODIMP_(void) CntrLine_AdvSink_OnClose(LPADVISESINK lpThis);

#if defined( INPLACE_CNTR )

/* ContainerLine::IOleInPlaceSite methods (functions) */

STDMETHODIMP CntrLine_IPSite_QueryInterface(

      LPOLEINPLACESITE    lpThis,

      REFIID              riid,

      LPVOID FAR*         lplpvObj

);

STDMETHODIMP_(ULONG) CntrLine_IPSite_AddRef(LPOLEINPLACESITE lpThis);

STDMETHODIMP_(ULONG) CntrLine_IPSite_Release(LPOLEINPLACESITE lpThis);

STDMETHODIMP CntrLine_IPSite_GetWindow(

      LPOLEINPLACESITE    lpThis,

      HWND FAR*           lphwnd

);

STDMETHODIMP CntrLine_IPSite_ContextSensitiveHelp(

   LPOLEINPLACESITE    lpThis,

   BOOL                fEnterMode

);

STDMETHODIMP CntrLine_IPSite_CanInPlaceActivate(LPOLEINPLACESITE lpThis);

STDMETHODIMP CntrLine_IPSite_OnInPlaceActivate(LPOLEINPLACESITE lpThis);

STDMETHODIMP CntrLine_IPSite_OnUIActivate (LPOLEINPLACESITE lpThis);

STDMETHODIMP CntrLine_IPSite_GetWindowContext(

   LPOLEINPLACESITE            lpThis,

   LPOLEINPLACEFRAME FAR*      lplpFrame,

   LPOLEINPLACEUIWINDOW FAR*   lplpDoc,

   LPRECT                      lprcPosRect,

   LPRECT                      lprcClipRect,

   LPOLEINPLACEFRAMEINFO       lpFrameInfo

);

STDMETHODIMP CntrLine_IPSite_Scroll(

   LPOLEINPLACESITE    lpThis,

   SIZE                scrollExtent

);

STDMETHODIMP CntrLine_IPSite_OnUIDeactivate(

   LPOLEINPLACESITE    lpThis,

   BOOL                fUndoable

);

STDMETHODIMP CntrLine_IPSite_OnInPlaceDeactivate(LPOLEINPLACESITE lpThis);

STDMETHODIMP CntrLine_IPSite_DiscardUndoState(LPOLEINPLACESITE lpThis);

STDMETHODIMP CntrLine_IPSite_DeactivateAndUndo(LPOLEINPLACESITE lpThis);

STDMETHODIMP CntrLine_IPSite_OnPosRectChange(

   LPOLEINPLACESITE    lpThis,

   LPCRECT             lprcPosRect

);

#endif  // INPLACE_CNTR

/* struct definition for persistant data storage of ContainerLine */

#pragma pack(push, 2)

typedef struct tagCONTAINERLINERECORD_ONDISK

{

      OLECHAR m_szStgName[CWCSTORAGENAME]; // stg name w/i cntr stg

      USHORT  m_fMonikerAssigned;          // has a moniker been assigned to obj

      DWORD   m_dwDrawAspect;              // current display aspect for obj

                                                                               //     (either DVASPECT_CONTENT or

                                                                               //     DVASPECT_ICON)

      SIZEL   m_sizeInHimetric;            // extents of obj in himetric units

      DWORD   m_dwLinkType;                // is it a linked object?

                                                                               //  0 -- NOT a link

                                                                               //  OLEUPDATE_ALWAYS (1) -- auto link

                                                                               //  OLEUPDATE_ONCALL (3) -- man. link

      USHORT  m_fDoSetExtent;              // obj was resized when not running

                                                                               //  IOO::SetExtent needed on next run

} CONTAINERLINERECORD_ONDISK, FAR* LPCONTAINERLINERECORD_ONDISK;

#pragma pack(pop)

typedef struct tagCONTAINERLINERECORD {

   OLECHAR m_szStgName[CWCSTORAGENAME]; // stg name w/i cntr stg

   BOOL    m_fMonikerAssigned;          // has a moniker been assigned to obj

   DWORD   m_dwDrawAspect;              // current display aspect for obj

                               //     (either DVASPECT_CONTENT or

                               //     DVASPECT_ICON)

   SIZEL   m_sizeInHimetric;            // extents of obj in himetric units

   DWORD   m_dwLinkType;                // is it a linked object?

                               //  0 -- NOT a link

                               //  OLEUPDATE_ALWAYS (1) -- auto link

                               //  OLEUPDATE_ONCALL (3) -- man. link

   BOOL    m_fDoSetExtent;              // obj was resized when not running

                               //  IOO::SetExtent needed on next run

} CONTAINERLINERECORD, FAR* LPCONTAINERLINERECORD;

/*************************************************************************

** class CONTAINERDOC : OUTLINEDOC

**    CONTAINERDOC is an extention to the base OUTLINEDOC object (structure)

**    that adds OLE 2.0 Container functionality. There is one instance of

**    CONTAINERDOC object created per document open in the app. The SDI

**    version of the app supports one CONTAINERDOC at a time. The MDI

**    version of the app can manage multiple documents at one time.

**    The CONTAINERDOC class inherits all fields

**    from the OUTLINEDOC class. This inheritance is achieved by including a

**    member variable of type OUTLINEDOC as the first field in the

**    CONTAINERDOC structure. Thus a pointer to a CONTAINERDOC object

**    can be cast to be a pointer to a OUTLINEDOC object.

*************************************************************************/

typedef struct tagCONTAINERDOC {

   OLEDOC      m_OleDoc;       // ContainerDoc inherits all fields of OleDoc

   ULONG       m_nNextObjNo;   // next available obj no. for stg name

   LPSTORAGE   m_lpNewStg;     // holds new pStg when SaveAs is pending

   BOOL        m_fEmbeddedObjectAvail; // is single OLE embed copied to doc

   CLSID       m_clsidOleObjCopied;    // if obj copied, CLSID of obj

   DWORD       m_dwAspectOleObjCopied; // if obj copied, draw aspect of obj

   LPCONTAINERLINE m_lpSrcContainerLine;  // src line if doc created for copy

   BOOL        m_fShowObject;          // show object flag

#if defined( INPLACE_CNTR )

   LPCONTAINERLINE m_lpLastIpActiveLine;   // last in-place active line

   LPCONTAINERLINE m_lpLastUIActiveLine;   // last UIActive line

   HWND            m_hWndUIActiveObj;      // HWND of UIActive obj.

   BOOL            m_fAddMyUI;             // if adding tools/menu postponed

   int             m_cIPActiveObjects;

#if defined( INPLACE_CNTRSVR )

   LPOLEINPLACEFRAME m_lpTopIPFrame;       // ptr to Top In-place frame.

   LPOLEINPLACEFRAME m_lpTopIPDoc;         // ptr to Top In-place Doc window.

   HMENU             m_hSharedMenu;        // combined obj/cntr menu

                                 // NULL if we are top container

   HOLEMENU        m_hOleMenu;             // returned by OleCreateMenuDesc.

                                 // NULL if we are top container

#endif  // INPLACE_CNTRSVR

#endif  // INPLACE_CNTR

   struct CDocOleUILinkContainerImpl {

      IOleUILinkContainerVtbl FAR*  lpVtbl;

      LPCONTAINERDOC                lpContainerDoc;

      int                           cRef;   // interface specific ref count.

   } m_OleUILinkContainer;

} CONTAINERDOC;

/* ContainerDoc methods (functions) */

BOOL ContainerDoc_Init(LPCONTAINERDOC lpContainerDoc, BOOL fDataTransferDoc);

LPCONTAINERLINE ContainerDoc_GetNextLink(

      LPCONTAINERDOC lpContainerDoc,

      LPCONTAINERLINE lpContainerLine

);

void ContainerDoc_UpdateLinks(LPCONTAINERDOC lpContainerDoc);

void ContainerDoc_SetShowObjectFlag(LPCONTAINERDOC lpContainerDoc, BOOL fShow);

BOOL ContainerDoc_GetShowObjectFlag(LPCONTAINERDOC lpContainerDoc);

void ContainerDoc_InsertOleObjectCommand(LPCONTAINERDOC lpContainerDoc);

void ContainerDoc_EditLinksCommand(LPCONTAINERDOC lpContainerDoc);

void ContainerDoc_PasteLinkCommand(LPCONTAINERDOC lpContainerDoc);

void ContainerDoc_ConvertCommand(

      LPCONTAINERDOC      lpContainerDoc,

      BOOL                fServerNotRegistered

);

BOOL ContainerDoc_PasteFormatFromData(

      LPCONTAINERDOC          lpContainerDoc,

      CLIPFORMAT              cfFormat,

      LPDATAOBJECT            lpSrcDataObj,

      BOOL                    fLocalDataObj,

      BOOL                    fLink,

      BOOL                    fDisplayAsIcon,

      HGLOBAL                 hMetaPict,

      LPSIZEL                 lpSizelInSrc

);

int ContainerDoc_PasteCntrOutlData(

      LPCONTAINERDOC          lpDestContainerDoc,

      LPSTORAGE               lpSrcStg,

      int                     nStartIndex

);

BOOL ContainerDoc_QueryPasteFromData(

      LPCONTAINERDOC          lpContainerDoc,

      LPDATAOBJECT            lpSrcDataObj,

      BOOL                    fLink

);

int ContainerDoc_PasteOleObject(

      LPCONTAINERDOC          lpContainerDoc,

      LPDATAOBJECT            lpSrcDataObj,

      DWORD                   dwCreateType,

      CLIPFORMAT              cfFormat,

      int                     nIndex,

      BOOL                    fDisplayAsIcon,

      HGLOBAL                 hMetaPict,

      LPSIZEL                 lpSizelInSrc

);

BOOL ContainerDoc_CloseAllOleObjects(

      LPCONTAINERDOC          lpContainerDoc,

      DWORD                   dwSaveOption

);

void ContainerDoc_UnloadAllOleObjectsOfClass(

      LPCONTAINERDOC      lpContainerDoc,

      REFCLSID            rClsid,

      DWORD               dwSaveOption

);

void ContainerDoc_InformAllOleObjectsDocRenamed(

      LPCONTAINERDOC          lpContainerDoc,

      LPMONIKER               lpmkDoc

);

void ContainerDoc_UpdateExtentOfAllOleObjects(LPCONTAINERDOC lpContainerDoc);

BOOL ContainerDoc_SaveToFile(

      LPCONTAINERDOC          lpContainerDoc,

      LPCOLESTR               lpszFileName,

      UINT                    uFormat,

      BOOL                    fRemember

);

void ContainerDoc_ContainerLineDoVerbCommand(

      LPCONTAINERDOC          lpContainerDoc,

      LONG                    iVerb

);

void ContainerDoc_GetNextStgName(

      LPCONTAINERDOC          lpContainerDoc,

      LPOLESTR                lpszStgName,

      int                     nLen

);

BOOL ContainerDoc_IsStgNameUsed(

      LPCONTAINERDOC          lpContainerDoc,

      LPOLESTR                lpszStgName

);

LPSTORAGE ContainerDoc_GetStg(LPCONTAINERDOC lpContainerDoc);

HRESULT ContainerDoc_GetObject(

      LPCONTAINERDOC          lpContainerDoc,

      LPOLESTR                lpszItem,

      DWORD                   dwSpeedNeeded,

      REFIID                  riid,

      LPVOID FAR*             lplpvObject

);

HRESULT ContainerDoc_GetObjectStorage(

      LPCONTAINERDOC          lpContainerDoc,

      LPOLESTR                lpszItem,

      LPSTORAGE FAR*          lplpStg

);

HRESULT ContainerDoc_IsRunning(LPCONTAINERDOC   lpContainerDoc, LPOLESTR lpszItem);

LPUNKNOWN ContainerDoc_GetSingleOleObject(

      LPCONTAINERDOC          lpContainerDoc,

      REFIID                  riid,

      LPCONTAINERLINE FAR*    lplpContainerLine

);

BOOL ContainerDoc_IsSelAnOleObject(

      LPCONTAINERDOC          lpContainerDoc,

      REFIID                  riid,

      LPUNKNOWN FAR*          lplpvObj,

      int FAR*                lpnIndex,

      LPCONTAINERLINE FAR*    lplpContainerLine

);

HRESULT ContainerDoc_GetData (

      LPCONTAINERDOC          lpContainerDoc,

      LPFORMATETC             lpformatetc,

      LPSTGMEDIUM             lpMedium

);

HRESULT ContainerDoc_GetDataHere (

      LPCONTAINERDOC          lpContainerDoc,

      LPFORMATETC             lpformatetc,

      LPSTGMEDIUM             lpMedium

);

HRESULT ContainerDoc_QueryGetData (

      LPCONTAINERDOC          lpContainerDoc,

      LPFORMATETC             lpformatetc

);

HRESULT ContainerDoc_SetData (

      LPCONTAINERDOC          lpContainerDoc,

      LPFORMATETC             lpformatetc,

      LPSTGMEDIUM             lpmedium,

      BOOL                    fRelease

);

HRESULT ContainerDoc_EnumFormatEtc(

      LPCONTAINERDOC          lpContainerDoc,

      DWORD                   dwDirection,

      LPENUMFORMATETC FAR*    lplpenumFormatEtc

);

BOOL ContainerDoc_SetupDocGetFmts(

      LPCONTAINERDOC          lpContainerDoc,

      LPCONTAINERLINE         lpContainerLine

);

#if defined( INPLACE_CNTR )

void ContainerDoc_ShutDownLastInPlaceServerIfNotNeeded(

      LPCONTAINERDOC          lpContainerDoc,

      LPCONTAINERLINE         lpNextActiveLine

);

BOOL ContainerDoc_IsUIDeactivateNeeded(

      LPCONTAINERDOC  lpContainerDoc,

      POINT           pt

);

HWND ContainerDoc_GetUIActiveWindow(LPCONTAINERDOC lpContainerDoc);

void ContainerDoc_UpdateInPlaceObjectRects(LPCONTAINERDOC lpContainerDoc, int nIndex);

void ContainerDoc_GetClipRect(

      LPCONTAINERDOC      lpContainerDoc,

      LPRECT              lprcClipRect

);

void ContainerDoc_FrameWindowResized(LPCONTAINERDOC lpContainerDoc);

LPOLEINPLACEFRAME ContainerDoc_GetTopInPlaceFrame(

      LPCONTAINERDOC      lpContainerDoc

);

void ContainerDoc_GetSharedMenuHandles(

      LPCONTAINERDOC  lpContainerDoc,

      HMENU FAR*      lphSharedMenu,

      HOLEMENU FAR*   lphOleMenu

);

void ContainerDoc_RemoveFrameLevelTools(LPCONTAINERDOC lpContainerDoc);

void ContainerDoc_AddFrameLevelUI(LPCONTAINERDOC lpContainerDoc);

void ContainerDoc_AddFrameLevelTools(LPCONTAINERDOC lpContainerDoc);

#if defined( INPLACE_CNTRSVR ) || defined( INPLACE_MDICNTR )

LPOLEINPLACEUIWINDOW ContainerDoc_GetTopInPlaceDoc(

      LPCONTAINERDOC      lpContainerDoc

);

void ContainerDoc_RemoveDocLevelTools(LPCONTAINERDOC lpContainerDoc);

void ContainerDoc_AddDocLevelTools(LPCONTAINERDOC lpContainerDoc);

#endif  // INPLACE_CNTRSVR || INPLACE_MDICNTR

#endif  // INPLACE_CNTR

/* ContainerDoc::IOleUILinkContainer methods (functions) */

STDMETHODIMP CntrDoc_LinkCont_QueryInterface(

      LPOLEUILINKCONTAINER    lpThis,

      REFIID                  riid,

      LPVOID FAR*             lplpvObj

);

STDMETHODIMP_(ULONG) CntrDoc_LinkCont_AddRef(LPOLEUILINKCONTAINER lpThis);

STDMETHODIMP_(ULONG) CntrDoc_LinkCont_Release(LPOLEUILINKCONTAINER lpThis);

STDMETHODIMP_(DWORD) CntrDoc_LinkCont_GetNextLink(

      LPOLEUILINKCONTAINER    lpThis,

      DWORD                   dwLink

);

STDMETHODIMP CntrDoc_LinkCont_SetLinkUpdateOptions(

      LPOLEUILINKCONTAINER    lpThis,

      DWORD                   dwLink,

      DWORD                   dwUpdateOpt

);

STDMETHODIMP CntrDoc_LinkCont_GetLinkUpdateOptions(

      LPOLEUILINKCONTAINER    lpThis,

      DWORD                   dwLink,

      DWORD FAR*              dwUpdateOpt

);

STDMETHODIMP CntrDoc_LinkCont_SetLinkSource(

      LPOLEUILINKCONTAINER    lpThis,

      DWORD                   dwLink,

      LPOLESTR                lpszDisplayName,

      ULONG                   clenFileName,

      ULONG FAR*              lpchEaten,

      BOOL                    fValidateSource

);

STDMETHODIMP CntrDoc_LinkCont_GetLinkSource(

      LPOLEUILINKCONTAINER    lpThis,

      DWORD                   dwLink,

      LPOLESTR FAR*           lplpszDisplayName,

      ULONG FAR*              lplenFileName,

      LPOLESTR FAR*           lplpszFullLinkType,

      LPOLESTR FAR*           lplpszShortLinkType,

      BOOL FAR*               lpfSourceAvailable,

      BOOL FAR*               lpfIsSelected

);

STDMETHODIMP CntrDoc_LinkCont_OpenLinkSource(

      LPOLEUILINKCONTAINER    lpThis,

      DWORD                   dwLink

);

STDMETHODIMP CntrDoc_LinkCont_UpdateLink(

      LPOLEUILINKCONTAINER    lpThis,

      DWORD                   dwLink,

      BOOL                    fErrorMessage,

      BOOL                    fErrorAction

);

STDMETHODIMP CntrDoc_LinkCont_CancelLink(

      LPOLEUILINKCONTAINER    lpThis,

      DWORD                   dwLink

);

/*************************************************************************

** class CONTAINERAPP : OLEAPP

**    CONTAINERAPP is an extention to the base OLEAPP object (structure)

**    that adds special Container functionality. There is one instance of

**    CONTAINERApp object created per running application instance. This

**    object holds many fields that could otherwise be organized as

**    global variables. The CONTAINERAPP class inherits all fields

**    from the OLEAPP class. This inheritance is achieved by including a

**    member variable of type OLEAPP as the first field in the CONTAINERAPP

**    structure. OLEAPP inherits from OUTLINEAPP. This inheritance is

**    achieved in the same manner. Thus a pointer to a CONTAINERAPP object

**    can be cast to be a pointer to an OLEAPP or an OUTLINEAPP object

*************************************************************************/

/* Forward definition of types */

typedef struct tagCONTAINERAPP FAR* LPCONTAINERAPP;

typedef struct tagCONTAINERAPP {

   OLEAPP  m_OleApp;       // ContainerApp inherits all fields of OleApp

   UINT    m_cfCntrOutl;   // clipboard format for CntrOutl (client ver) data

   int     m_nSingleObjGetFmts; // no. formats avail when single obj copied

   FORMATETC m_arrSingleObjGetFmts[MAXNOFMTS];

                              // array of FormatEtc's available via

                              // IDataObject::GetData when a single

                              // OLE object is copied.

#if defined( INPLACE_CNTR )

   HACCEL  m_hAccelIPCntr; // accelerators for container's workspace commands

   HMENU   m_hMenuFile;    // handle to File menu of container app

   HMENU   m_hMenuView;    // handle to View menu of container app

   HMENU   m_hMenuDebug;   // handle to Debug menu of container app

   LPOLEINPLACEACTIVEOBJECT m_lpIPActiveObj; // ptr to inplace active OLE obj

   HWND    m_hWndUIActiveObj;      // HWND of UIActive obj.

   BOOL    m_fPendingUIDeactivate; // should app UIDeactivate on LBUTTONUP

   BOOL    m_fMustResizeClientArea;// if client area resize pending

                           //  (see Doc_FrameWindowResized)

   BOOL    m_fMenuHelpMode;// is F1 pressed in menu, if so give help

#ifdef _DEBUG

   BOOL    m_fOutSideIn;

#endif

   struct COleInPlaceFrameImpl {

      IOleInPlaceFrameVtbl FAR* lpVtbl;

      LPCONTAINERAPP          lpContainerApp;

      int                     cRef;   // interface specific ref count.

   } m_OleInPlaceFrame;

#endif  // INPLACE_CNTR

} CONTAINERAPP;

/* ContainerApp methods (functions) */

BOOL ContainerApp_InitInstance(

      LPCONTAINERAPP          lpContainerApp,

      HINSTANCE               hInst,

      int                     nCmdShow

);

BOOL ContainerApp_InitVtbls(LPCONTAINERAPP lpApp);

#if defined( INPLACE_CNTR )

/* ContainerApp::IOleInPlaceFrame methods (functions) */

STDMETHODIMP CntrApp_IPFrame_QueryInterface(

      LPOLEINPLACEFRAME   lpThis,

      REFIID              riid,

      LPVOID FAR*         lplpvObj

);

STDMETHODIMP_(ULONG) CntrApp_IPFrame_AddRef(LPOLEINPLACEFRAME lpThis);

STDMETHODIMP_(ULONG) CntrApp_IPFrame_Release(LPOLEINPLACEFRAME lpThis);

STDMETHODIMP CntrApp_IPFrame_GetWindow(

   LPOLEINPLACEFRAME   lpThis,

   HWND FAR*           lphwnd

);

STDMETHODIMP CntrApp_IPFrame_ContextSensitiveHelp(

   LPOLEINPLACEFRAME   lpThis,

   BOOL                fEnterMode

);

STDMETHODIMP CntrApp_IPFrame_GetBorder(

   LPOLEINPLACEFRAME   lpThis,

   LPRECT              lprectBorder

);

STDMETHODIMP CntrApp_IPFrame_RequestBorderSpace(

   LPOLEINPLACEFRAME   lpThis,

   LPCBORDERWIDTHS     lpWidths

);

STDMETHODIMP CntrApp_IPFrame_SetBorderSpace(

   LPOLEINPLACEFRAME   lpThis,

   LPCBORDERWIDTHS     lpWidths

);

STDMETHODIMP CntrApp_IPFrame_SetActiveObject(

   LPOLEINPLACEFRAME           lpThis,

   LPOLEINPLACEACTIVEOBJECT    lpActiveObject,

   LPCOLESTR                   lpszObjName

);

STDMETHODIMP CntrApp_IPFrame_InsertMenus(

   LPOLEINPLACEFRAME       lpThis,

   HMENU                   hmenu,

   LPOLEMENUGROUPWIDTHS    lpMenuWidths

);

STDMETHODIMP CntrApp_IPFrame_SetMenu(

   LPOLEINPLACEFRAME   lpThis,

   HMENU               hmenuShared,

   HOLEMENU            holemenu,

   HWND                hwndActiveObject

);

STDMETHODIMP CntrApp_IPFrame_RemoveMenus(

   LPOLEINPLACEFRAME   lpThis,

   HMENU               hmenu

);

STDMETHODIMP CntrApp_IPFrame_SetStatusText(

   LPOLEINPLACEFRAME   lpThis,

   LPCOLESTR           lpszStatusText

);

STDMETHODIMP CntrApp_IPFrame_EnableModeless(

   LPOLEINPLACEFRAME   lpThis,

   BOOL                fEnable

);

STDMETHODIMP CntrApp_IPFrame_TranslateAccelerator(

   LPOLEINPLACEFRAME   lpThis,

   LPMSG               lpmsg,

   WORD                wID

);

#endif  // INPLACE_CNTR

#endif // _CNTROUTL_H_


CNTROUTL.RC  (OUTLINE Sample)

/*************************************************************************

**

**    OLE 2.0 Container Sample Code

**

**    cntroutl.rc

**

**    Resource file for cntroutl.exe

**

**	  (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

**

*************************************************************************/

#include "windows.h"

#include "outlrc.h"

#include "cntrrc.h"

SelCur      CURSOR selcross.cur

DragMoveCur CURSOR dragmove.cur

#if defined( IF_SPECIAL_DD_CURSORS_NEEDED )

DragNoneCur CURSOR dragnone.cur

DragCopyCur CURSOR dragcopy.cur

DragLinkCur CURSOR draglink.cur

#endif  // IF_SPECIAL_DD_CURSORS_NEEDED

CntrOutlMenu MENU

  BEGIN

    POPUP  "&File"

      BEGIN

        MENUITEM "&New", IDM_F_NEW

        MENUITEM "&Open...\t  Ctrl+F12", IDM_F_OPEN

        MENUITEM "&Save\t  Shift+F12", IDM_F_SAVE

        MENUITEM "Save &As...\t  F12", IDM_F_SAVEAS

        MENUITEM SEPARATOR

        MENUITEM "&Print...\t  Ctrl+Shift+F12", IDM_F_PRINT

        MENUITEM "Printer Se&tup...", IDM_F_PRINTERSETUP

        MENUITEM SEPARATOR

        MENUITEM "E&xit\t  Alt+F4", IDM_F_EXIT

      END

    POPUP  "&Edit"

      BEGIN

        MENUITEM "&Undo", IDM_E_UNDO

        MENUITEM SEPARATOR

MENUITEM "Cu&t\t  Ctrl+X", IDM_E_CUT

MENUITEM "&Copy\t  Ctrl+C", IDM_E_COPY

MENUITEM "&Paste\t  Ctrl+V", IDM_E_PASTE

MENUITEM "Paste &Special...", IDM_E_PASTESPECIAL

MENUITEM "Paste &Link", IDM_E_PASTELINK

MENUITEM "Cl&ear\t  Del", IDM_E_CLEAR

MENUITEM SEPARATOR

MENUITEM "&Insert Object...", IDM_E_INSERTOBJECT

MENUITEM "Li&nks...", IDM_E_EDITLINKS

MENUITEM "&Object", IDM_E_OBJECTVERBMIN

MENUITEM SEPARATOR

MENUITEM "Select &All\t  Ctrl+A", IDM_E_SELECTALL

      END

POPUP  "O&utline"

  BEGIN

        POPUP  "&Zoom"

          BEGIN

            MENUITEM "&100%", IDM_V_ZOOM_100

            MENUITEM "&75%", IDM_V_ZOOM_75

            MENUITEM "&50%", IDM_V_ZOOM_50

            MENUITEM "&25%", IDM_V_ZOOM_25

          END

        POPUP  "&Left and Right margins"

          BEGIN

            MENUITEM "&nil", IDM_V_SETMARGIN_0

            MENUITEM "&1 cm", IDM_V_SETMARGIN_1

            MENUITEM "&2 cm", IDM_V_SETMARGIN_2

            MENUITEM "&3 cm", IDM_V_SETMARGIN_3

            MENUITEM "&4 cm", IDM_V_SETMARGIN_4

          END

        POPUP "Add &Top Line"

  BEGIN

    MENUITEM "&1 cm", IDM_V_ADDTOP_1

    MENUITEM "&2 cm", IDM_V_ADDTOP_2

    MENUITEM "&3 cm", IDM_V_ADDTOP_3

    MENUITEM "&4 cm", IDM_V_ADDTOP_4

  END

  END

    POPUP  "&Line"

      BEGIN

        MENUITEM "&Add Line\t  Enter", IDM_L_ADDLINE

        MENUITEM "E&dit Line\t  Alt+Enter", IDM_L_EDITLINE

        MENUITEM SEPARATOR

        MENUITEM "&Indent Line\t  Tab", IDM_L_INDENTLINE

        MENUITEM "U&nindent Line\t  Shift+Tab", IDM_L_UNINDENTLINE

MENUITEM SEPARATOR

MENUITEM "&Set Line Height...", IDM_L_SETLINEHEIGHT

      END

    POPUP  "&Name"

      BEGIN

        MENUITEM "&Define Name...", IDM_N_DEFINENAME

        MENUITEM "&Goto Name...", IDM_N_GOTONAME

      END

    POPUP  "&Options"

      BEGIN

        POPUP  "&Button Bar Display"

          BEGIN

            MENUITEM "At &Top", IDM_O_BB_TOP

            MENUITEM "At &Bottom", IDM_O_BB_BOTTOM

            MENUITEM "&Popup", IDM_O_BB_POPUP

            MENUITEM "&Hide", IDM_O_BB_HIDE

          END

        POPUP  "&Formula Bar Display"

          BEGIN

            MENUITEM "At &Top", IDM_O_FB_TOP

            MENUITEM "At &Bottom", IDM_O_FB_BOTTOM

            MENUITEM "&Popup", IDM_O_FB_POPUP

          END

        POPUP  "&Row and Column Heading"

          BEGIN

            MENUITEM "&Show", IDM_O_HEAD_SHOW

            MENUITEM "&Hide", IDM_O_HEAD_HIDE

          END

    MENUITEM "&Show Object", IDM_O_SHOWOBJECT

      END

    POPUP  "Dbg&Cntr"

      BEGIN

        MENUITEM "&Debug Level...", IDM_D_DEBUGLEVEL

        MENUITEM "Register Message &Filter", IDM_D_INSTALLMSGFILTER

        MENUITEM "&Reject Incoming Messages", IDM_D_REJECTINCOMING

      END

    POPUP  "&Help"

      BEGIN

        MENUITEM "&About...", IDM_H_ABOUT

      END

  END

CntrOutlAccel ACCELERATORS

  BEGIN

    VK_F12, IDM_F_OPEN, VIRTKEY, CONTROL

    VK_F12, IDM_F_SAVE, VIRTKEY, SHIFT

    VK_F12, IDM_F_SAVEAS, VIRTKEY

    VK_F12, IDM_F_PRINT, VIRTKEY, CONTROL, SHIFT

    "x", IDM_E_CUT, VIRTKEY, CONTROL

    "c", IDM_E_COPY, VIRTKEY, CONTROL

    "v", IDM_E_PASTE, VIRTKEY, CONTROL

    VK_DELETE, IDM_E_CLEAR, VIRTKEY

    VK_RETURN, IDM_L_ADDLINE, VIRTKEY

    VK_RETURN, IDM_L_EDITLINE, VIRTKEY, ALT

    VK_TAB, IDM_L_INDENTLINE, VIRTKEY

    VK_TAB, IDM_L_UNINDENTLINE, VIRTKEY, SHIFT

    "a", IDM_E_SELECTALL, VIRTKEY, CONTROL

    ; old conventions for editing

    VK_INSERT, IDM_E_COPY, VIRTKEY, CONTROL

    VK_DELETE, IDM_E_CUT, VIRTKEY, SHIFT

    VK_INSERT, IDM_E_PASTE, VIRTKEY, SHIFT

    VK_F2, IDM_F2, VIRTKEY

  END

; Same as CntrOutlAccel but without Delete and Backspace

; used when edit control of Formula Bar in focus

;

CntrOutlAccelFocusEdit ACCELERATORS

  BEGIN

    VK_F12, IDM_F_OPEN, VIRTKEY, CONTROL

    VK_F12, IDM_F_SAVE, VIRTKEY, SHIFT

    VK_F12, IDM_F_SAVEAS, VIRTKEY

    VK_F12, IDM_F_PRINT, VIRTKEY, CONTROL, SHIFT

    VK_RETURN, IDM_L_ADDLINE, VIRTKEY

    VK_RETURN, IDM_L_EDITLINE, VIRTKEY, ALT

VK_ESCAPE, IDM_FB_CANCEL, VIRTKEY

  END

CntrOutlIcon ICON cntroutl.ico

Image72     BITMAP      image72.bmp

Image96     BITMAP      image96.bmp

Image120    BITMAP      image120.bmp

LogoBitmap  BITMAP      ole2.bmp

#include "DIALOGS.DLG"


CNTROUTL.C  (OUTLINE Sample)

/*************************************************************************

**

**    OLE 2.0 Sample Code

**

**    precomp.c

**

**    This file is used to precompile the OUTLINE.H header file

**

**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

**

*************************************************************************/

#include "outline.h"


CNTRRC.H  (OUTLINE Sample)

/*************************************************************************

**

**    OLE 2.0 Container Sample Code

**

**    cntrrc.h

**

**    This file contains constants used in rc file for CNTROUTL.EXE

**

**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

**

*************************************************************************/

#if !defined( _CNTRRC_H_ )

#define _CNTRRC_H_

#ifndef RC_INVOKED

#pragma message ("INCLUDING CNTRRC.H from " __FILE__)

#endif  /* RC_INVOKED */

#define IDM_E_INSERTOBJECT          2700

#define IDM_E_EDITLINKS             3300

#define IDM_E_PASTELINK             2750

#define IDM_E_CONVERTVERB           9000

#define IDM_E_OBJECTVERBMIN         10000

#define IDM_D_INSIDEOUT             2755

#define WM_U_UPDATEOBJECTEXTENT     WM_USER+1

#endif // _CNTRRC_H_


DEBUG.RC  (OUTLINE Sample)

9999 RCDATA LOADONCALL DISCARDABLE

{

"\327\324\335\270\252\270\313\371\365\350\364\375\270\333\367\374\375\270\334\375\356\375\364\367\350\365\375\366\354\270\314\375\371\365\0",

"\265\265\270\324\375\374\270\372\341\270\265\265\0",

"\333\266\270\334\367\355\377\364\371\353\270\320\367\374\377\375\353\0",

"\270\0",

"\325\371\352\363\270\332\371\374\375\352\0",

"\323\352\371\361\377\270\332\352\367\373\363\353\373\360\365\361\374\354\0",

"\326\371\354\270\332\352\367\357\366\0",

"\316\361\366\367\367\270\333\360\375\352\361\371\366\0",

"\312\367\372\375\352\354\270\333\367\367\363\0",

"\333\364\371\352\363\270\333\341\352\0",

"\314\375\352\352\375\366\373\375\270\320\355\371\366\377\0",

"\310\375\354\375\352\270\324\361\0",

"\312\361\373\360\371\352\374\270\325\373\334\371\366\361\375\364\0",

"\312\375\372\375\373\373\371\270\326\367\352\364\371\366\374\375\352\0",

"\313\373\367\354\354\270\313\363\367\352\355\350\371\0",

"\313\371\352\371\270\317\361\364\364\361\371\365\353\0",

"\334\371\356\361\374\270\317\367\352\354\375\366\374\341\363\375\0",

"\270\0",

"\270\0",

"\327\324\335\270\252\270\324\361\372\352\371\352\341\270\334\375\356\375\364\367\350\365\375\366\354\270\314\375\371\365\0",

"\265\265\270\324\375\374\270\372\341\270\265\265\265\0",

"\312\371\367\270\312\375\365\371\364\371\0",

"\270\0",

"\332\371\352\352\341\270\332\367\366\374\0",

"\334\352\375\357\270\332\364\361\353\353\0",

"\321\364\371\366\270\333\371\352\367\366\0",

"\331\364\371\366\270\333\371\352\354\375\352\0",

"\334\367\355\377\270\336\352\371\366\363\364\361\366\0",

"\322\371\353\367\366\270\336\355\364\364\375\352\0",

"\333\364\371\352\375\366\373\375\270\337\364\371\353\353\375\0",

"\310\375\354\375\352\270\337\367\364\374\375\0",

"\331\364\375\340\371\366\374\375\352\270\337\367\355\366\371\352\375\353\0",

"\310\360\361\364\361\350\270\324\371\376\367\352\366\371\352\371\0",

"\332\352\371\374\270\324\367\356\375\352\361\366\377\0",

"\313\371\365\270\323\360\367\0",

"\313\352\361\366\361\270\323\367\350\350\367\364\355\0",

"\312\371\362\361\356\270\323\355\365\371\352\0",

"\332\371\352\352\341\270\325\371\373\323\361\373\360\371\366\0",

"\313\354\375\356\375\366\270\326\367\352\371\364\364\0",

"\337\361\364\371\374\270\327\374\361\366\371\363\0",

"\335\352\361\373\270\327\375\365\361\377\0",

"\325\371\354\354\270\310\375\371\352\353\367\366\0",

"\322\367\360\371\366\366\270\310\367\353\373\360\0",

"\333\355\352\354\270\313\354\375\375\372\0",

"\314\367\365\270\314\375\366\377\0",

"\331\364\375\340\270\314\361\364\364\375\353\0",

"\333\352\371\361\377\270\317\361\354\354\375\366\372\375\352\377\0",

"\325\361\373\360\371\375\364\270\317\367\367\364\376\0",

"\270\0",

"\270\0",

"\327\324\335\270\252\270\314\375\353\354\361\366\377\270\314\375\371\365\0",

"\265\265\270\324\375\374\270\372\341\270\265\265\0",

"\322\375\376\376\270\310\371\373\363\0",

"\270\0",

"\334\371\366\361\375\364\270\332\367\367\366\375\0",

"\332\352\371\366\374\367\366\270\332\341\366\355\365\0",

"\331\366\377\375\364\371\270\333\360\371\366\0",

"\312\361\373\360\270\335\361\342\375\366\360\367\375\376\375\352\0",

"\312\367\377\375\352\270\337\352\371\365\372\361\360\364\375\352\0",

"\333\360\352\361\353\270\323\371\355\376\376\365\371\366\0",

"\313\371\366\362\371\341\270\323\367\360\364\361\0",

"\334\357\361\377\360\354\270\323\352\355\377\375\352\0",

"\314\367\365\270\324\371\341\353\367\366\0",

"\312\367\366\371\364\374\270\324\367\366\377\0",

"\331\364\364\371\366\270\325\373\334\371\366\361\375\364\0",

"\323\375\366\354\270\325\355\352\374\367\373\360\0",

"\314\352\371\356\361\353\270\310\352\355\361\354\354\0",

"\322\371\365\375\353\270\312\367\374\352\361\377\355\375\353\0",

"\312\367\353\353\270\313\365\361\354\360\0",

"\270\0",

"\270\0",

"\327\324\335\270\252\270\310\352\367\377\352\371\365\270\325\371\366\371\377\375\365\375\366\354\0",

"\265\265\270\324\375\374\270\372\341\270\265\265\0",

"\320\375\361\363\363\361\270\323\371\366\375\352\356\371\0",

"\270\0",

"\333\341\270\333\375\374\371\352\0",

"\335\374\374\361\375\270\337\361\364\372\375\352\354\0",

"\325\371\352\363\270\321\377\352\371\0",

"\334\371\356\361\374\270\324\371\366\361\366\377\0",

"\322\367\360\366\270\324\375\376\367\352\0",

"\313\373\367\354\354\270\317\361\364\354\371\365\355\354\360\0",

"\270\0",

"\270\0",

"\327\324\335\270\252\270\334\367\373\355\365\375\366\354\371\354\361\367\366\270\314\375\371\365\0",

"\265\265\270\324\375\374\270\372\341\270\265\265\0",

"\325\361\363\375\270\325\373\337\375\375\0",

"\270\0",

"\322\367\360\366\270\332\355\352\363\375\0",

"\334\361\373\363\270\325\367\353\375\364\375\341\0",

"\332\371\352\352\341\270\310\367\354\354\375\352\0",

"\324\341\366\366\375\270\317\371\353\353\367\366\0",

"\322\375\376\376\270\317\375\372\372\0",

"\270\0",

"\270\0",

"\327\324\335\270\252\270\334\375\356\375\364\367\350\375\352\270\312\375\364\371\354\361\367\366\353\270\337\352\367\355\350\0",

"\270\0",

"\331\364\361\353\354\371\361\352\270\332\371\366\363\353\0",

"\325\361\363\375\270\336\352\361\354\342\0",

"\316\361\363\354\367\352\270\337\352\371\372\366\375\352\0",

"\312\367\372\375\352\354\270\320\375\353\353\0",

"\314\361\365\270\325\373\333\371\376\376\352\375\341\0",

"\322\367\366\270\326\361\373\350\367\366\353\363\361\0",

"\322\371\365\375\353\270\310\364\371\365\367\366\374\367\366\0",

"\317\361\365\270\316\371\366\270\334\375\270\332\367\353\350\367\367\352\354\0",

"\331\374\371\365\270\317\371\371\364\363\375\353\0",

"\270\0",

"\270\0",

"\327\324\335\270\252\270\331\352\373\360\361\354\375\373\354\353\0",

"\270\0",

"\332\367\372\270\331\354\363\361\366\353\367\366\0",

"\314\367\366\341\270\317\361\364\364\361\371\365\353\0",

"\270\0",

"\270\0",

"\327\324\335\270\252\270\310\352\367\374\355\373\354\270\325\371\366\371\377\375\352\0",

"\270\0",

"\334\371\356\375\270\313\375\352\375\353\0",

"\270\0",

"\270\0",

"\327\324\335\270\252\270\337\352\367\355\350\270\325\371\366\371\377\375\352\0",

"\270\0",

"\320\371\352\375\364\270\323\367\374\375\353\360\0",

"\270\0",

"\270\0",

"\313\350\375\373\361\371\364\270\314\360\371\366\363\353\270\314\367\242\0",

"\270\0",

"\313\360\371\355\366\371\270\332\352\371\355\366\0",

"\334\371\366\270\334\375\376\376\375\0",

"\322\361\365\270\334\367\353\373\360\0",

"\332\375\356\375\352\364\375\341\270\336\364\367\357\375\352\0",

"\332\361\364\364\270\337\371\354\375\353\0",

"\322\367\366\361\270\320\371\366\353\367\366\0",

"\324\341\366\366\270\320\361\373\363\353\0",

"\326\367\352\365\371\366\270\320\367\374\366\375\0",

"\333\360\371\352\364\361\375\270\323\361\366\374\375\364\0",

"\331\366\374\341\270\324\375\375\0",

"\326\371\366\373\341\270\313\350\375\375\352\0",

"\310\371\355\364\270\313\354\371\376\376\367\352\374\0",

"\313\354\375\350\360\375\366\270\314\355\352\354\367\366\0",

    0x0000

}


DEBUG.C  (OUTLINE Sample)

/*************************************************************************

**

**    OLE 2 Sample Code

**

**    debug.c

**

**    This file contains some functions for debugging support

**

**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

**

*************************************************************************/

#include "outline.h"

OLEDBGDATA

extern LPOUTLINEAPP g_lpApp;

void SetDebugLevelCommand(void)

{

   char szBuf[80];

   HWND hWndFrame = OutlineApp_GetFrameWindow(g_lpApp);

   wsprintf(szBuf, "%d", OleDbgGetDbgLevel());

   if (InputTextDlg(hWndFrame, szBuf, "Debug Level [0-4]")) {

      switch (szBuf[0]) {

         case '0':

            OleDbgSetDbgLevel(0);

            break;

         case '1':

            OleDbgSetDbgLevel(1);

            break;

         case '2':

            OleDbgSetDbgLevel(2);

            break;

         case '3':

            OleDbgSetDbgLevel(3);

            break;

         case '4':

            OleDbgSetDbgLevel(4);

            break;

         default:

            OutlineApp_ErrorMessage(g_lpApp, OLESTR("Valid Debug Level Range: 0-4"));

            break;

      }

   }

}

#if defined( OLE_VERSION )

/* InstallMessageFilterCommand

 * ---------------------------

 *

 * Handles the "Install Message Filter" menu item.  If a message filter is

 * already installed, this function de-installs it.  If there is not one

 * already installed, this function installs one.

 *

 */

void InstallMessageFilterCommand(void)

{

   LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp;

   /*

   ** Check to see if we've already installed a MessageFilter.

   ** If so, uninstall it.

   */

   if (lpOleApp->m_lpMsgFilter != NULL)

      OleApp_RevokeMessageFilter(lpOleApp);

   else

      OleApp_RegisterMessageFilter(lpOleApp);

}

/* RejectIncomingCommand

 * ---------------------

 *

 * Toggles between rejecting and not-handling in coming LRPC calls

 *

 */

void RejectIncomingCommand(void)

{

   DWORD dwOldStatus;

   DWORD dwNewStatus;

   LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp;

   dwOldStatus = OleStdMsgFilter_GetInComingCallStatus(lpOleApp->m_lpMsgFilter);

   if (dwOldStatus == SERVERCALL_RETRYLATER)

      dwNewStatus = SERVERCALL_ISHANDLED;

   else

      dwNewStatus = SERVERCALL_RETRYLATER;

   OleStdMsgFilter_SetInComingCallStatus(lpOleApp->m_lpMsgFilter, dwNewStatus);

}

#endif  // OLE_VERSION


DEBUG2.C  (OUTLINE Sample)

/*************************************************************************

**

**    OLE 2 Sample Code

**

**    debug2.c

**

**    This file contains various debug / subclass routines for the

**    ABOUT dialog

**

**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

**

*************************************************************************/

#include "outline.h"

#include <stdlib.h>

#include <time.h>

extern LPOUTLINEAPP g_lpApp;

LONG CALLBACK EXPORT DebugAbout(HWND hWnd, unsigned uMsg, WORD wParam, LONG lParam);

void RandomizeStars(HDC hDC);

BOOL InitStrings(void);

BOOL DrawString(int iCount, HDC hDC, LPRECT rcDrawIn);

static FARPROC lpRealAboutProc = 0L;

static int width, height;

static RECT rc;

static HANDLE hStrBlock = NULL;

static LPSTR lpStrings = NULL;

static WORD       wLineHeight;

/* TraceDebug

 * ----------

 *

 * Called once when our About Box's gets the INITDIALOG message.  Subclasses

 * dialog.

 */

void TraceDebug(HWND hDlg, int iControl)

{

// Load strings, if the strings aren't there, then don't subclass

// the dialog

if (InitStrings() != TRUE)

return;

// Subclass the dialog

lpRealAboutProc = (FARPROC)(LONG)GetWindowLong(hDlg, GWL_WNDPROC);

SetWindowLong(hDlg, GWL_WNDPROC, (LONG)(FARPROC)DebugAbout);

// Get rect of control in screen coords, and translate to our dialog

// box's coordinates

GetWindowRect(GetDlgItem(hDlg, iControl), &rc);

MapWindowPoints(NULL, hDlg, (LPPOINT)&rc, 2);

width  = rc.right - rc.left;

height = rc.bottom - rc.top;

}

/* DebugAbout

 * ----------

 *

 * The subclassed About dialog's main window proc.

 */

LONG CALLBACK EXPORT DebugAbout(HWND hWnd, unsigned uMsg, WORD wParam, LONG lParam)

{

RECT              rcOut;

static BOOL       bTimerStarted = FALSE;

static int        iTopLocation;

HDC               hDCScr;

static HDC        hDCMem;

static HBITMAP    hBitmap;

static HBITMAP    hBitmapOld;

static RECT       rcMem;

static HFONT      hFont;

switch (uMsg)

{

/*

 * If we get a LBUTTONDBLCLICK in the upper left of

 * the dialog, fire off the about box effects

 */

case WM_LBUTTONDBLCLK:

if ((wParam & MK_CONTROL) && (wParam & MK_SHIFT)

&& LOWORD(lParam) < 10 && HIWORD(lParam) < 10 &&

bTimerStarted == FALSE)

{

if (SetTimer ( hWnd, 1, 10, NULL ))

{

LOGFONT lf;

int i;

bTimerStarted = TRUE;

// "Open up" the window

hDCScr = GetDC ( hWnd );

hDCMem = CreateCompatibleDC     ( hDCScr );

hBitmap = CreateCompatibleBitmap(hDCScr, width, height);

hBitmapOld = SelectObject(hDCMem, hBitmap);

// Blt from dialog to memDC

BitBlt(hDCMem, 0, 0, width, height,

hDCScr, rc.left, rc.top, SRCCOPY);

for (i=0;i<height;i+=1)

{

BitBlt(hDCScr, rc.left, rc.top + i + 1, width, height-i-1, hDCMem, 0, 0, SRCCOPY);

PatBlt(hDCScr, rc.left, rc.top + i, width, 1, BLACKNESS);

}

SelectObject(hDCMem, hBitmapOld);

DeleteObject(hBitmap);

// Set up memory DC with default attributes

hBitmap   = CreateCompatibleBitmap(hDCScr, width, height);

ReleaseDC(hWnd, hDCScr);

hBitmapOld = SelectObject(hDCMem, hBitmap);

SetBkMode(hDCMem, TRANSPARENT);

SetBkColor(hDCMem, RGB(0,0,0));

// Create font

memset(&lf, 0, sizeof(LOGFONT));

lf.lfHeight = -(height / 7); // Fit 7 lines of text in box

lf.lfWeight = FW_BOLD;

strcpy(lf.lfFaceName, "Arial");

hFont = CreateFontIndirect(&lf);

// If we can't create the font, revert and use the standard

// system font.

if (!hFont)

GetObject(GetStockObject(SYSTEM_FONT), sizeof(LOGFONT), &lf);

wLineHeight = abs(lf.lfHeight) + 5; // 5 pixels between lines

// Set location of top of banner at bottom of the window

iTopLocation = height + 50;

SetRect(&rcMem, 0, 0, width, height);

}

}

// Call our real window procedure in case they want to

// handle LBUTTONDOWN messages also

goto Default;

case WM_TIMER:

{

int iCount;

HFONT hfold;

/*

 * On each timer message, we are going to construct the next image

 * in the animation sequence, then bitblt this to our dialog.

 */

// Clear out old bitmap and place random star image on background

PatBlt(hDCMem, rcMem.left, rcMem.top, rcMem.right, rcMem.bottom, BLACKNESS);

RandomizeStars(hDCMem);

// Set initial location to draw text

rcOut = rcMem;

rcOut.top = 0 + iTopLocation;

rcOut.bottom = rcOut.top + wLineHeight;

iCount = 0;

if (hFont) hfold = SelectObject(hDCMem, hFont);

SetTextColor(hDCMem, RGB(0,255,0));

while (DrawString(iCount, hDCMem, &rcOut) == TRUE)

{

rcOut.top    += wLineHeight;

rcOut.bottom += wLineHeight;

iCount++;

}

if (hFont) SelectObject(hDCMem, hfold);

// Now blt the memory dc that we have just constructed

// to the screen

hDCScr = GetDC(hWnd);

BitBlt(hDCScr, rc.left, rc.top, rc.right, rc.bottom,

hDCMem, 0, 0, SRCCOPY);

ReleaseDC(hWnd, hDCScr);

// For the next animation sequence, we want to move the

// whole thing up, so decrement the location of the top

// of the banner

iTopLocation -= 2;

// If we've gone through the banner once, reset it

if (iTopLocation < -(int)(wLineHeight * iCount))

iTopLocation = height + 50;

}

// Goto default

goto Default;

case WM_NCDESTROY:

{

LONG defReturn;

/*

 * We're being destroyed.  Clean up what we created.

 */

if (bTimerStarted)

{

KillTimer(hWnd, 1);

SelectObject (hDCMem, hBitmapOld);

DeleteObject (hBitmap);

DeleteDC (hDCMem);

if (hFont) DeleteObject(hFont);

bTimerStarted = FALSE;

}

if (lpStrings)

UnlockResource(hStrBlock), lpStrings = NULL;

if (hStrBlock)

FreeResource(hStrBlock), hStrBlock = NULL;

// Pass the NCDESTROY on to our real window procedure.  Since

// this is the last message that we are going to be getting,

// we can go ahead and free the proc instance here.

defReturn = CallWindowProc((WNDPROC)lpRealAboutProc, hWnd,

   uMsg, wParam, lParam);

return defReturn;

}

Default:

default:

return CallWindowProc(

(WNDPROC)lpRealAboutProc, hWnd, uMsg, wParam, lParam);

}

return 0L;

}

/* RandomizeStars

 * --------------

 *

 * Paints random stars on the specified hDC

 *

 */

void RandomizeStars(HDC hDC)

{

int             i;

// Seed the random number generator with current time.  This will,

// in effect, only change the seed every second, so our

// starfield will change only every second.

srand((unsigned)time(NULL));

// Generate random white stars

for (i=0;i<20;i++)

PatBlt(hDC, getrandom(0,width), getrandom(0,height), 2, 2, WHITENESS);

}

/* InitStrings

 * --------------

 *

 * Reads strings from stringtable.  Returns TRUE if it worked OK.

 *

 */

BOOL InitStrings()

{

HRSRC hResStrings;

LPSTR lpWalk;

// Load the block of strings

if ((hResStrings = FindResource(

g_lpApp->m_hInst,

MAKEINTRESOURCE(9999),

RT_RCDATA)) == NULL)

return FALSE;

if ((hStrBlock = LoadResource(g_lpApp->m_hInst, hResStrings)) == NULL)

return FALSE;

if ((lpStrings = LockResource(hStrBlock)) == NULL)

return FALSE;

if (lpStrings && *(lpStrings+2)!=0x45)

{

lpWalk = lpStrings;

while (*(LPWORD)lpWalk != (WORD)0x0000)

{

if (*lpWalk != (char)0x00)

*lpWalk ^= 0x98;

lpWalk++;

}

}

return TRUE;

}

/* DrawString

 * ----------

 *

 * Draws the next string on the specified hDC using the

 * output rectangle.  If iCount == 0, reset to start of list.

 *

 * Returns: TRUE to contine, FALSE if we're done

 */

BOOL DrawString(int iCount, HDC hDC, LPRECT rcDrawIn)

{

static LPSTR lpPtr = NULL;

if (iCount == 0)

// First time, reset pointer

lpPtr = lpStrings;

if (*lpPtr == '\0') // If we've hit a NULL string, we're done

return FALSE;

// If we're drawing outside of visible box, don't call DrawText

if ((rcDrawIn->bottom > 0) && (rcDrawIn->top < height))

DrawText(hDC, lpPtr, -1, rcDrawIn, DT_CENTER);

// Advance pointer to next string

lpPtr += lstrlen(lpPtr) + 1;

return TRUE;

}


DEFGUID.H  (OUTLINE Sample)

/*************************************************************************

**

**    OLE 2.0 Sample Code

**

**    clsid.h

**

**    This file contains file contains GUID definitions used for the

**    OLE versions of OUTLINE.

**

**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

**

*************************************************************************/

#if defined( OLE_SERVER ) || defined( OLE_CNTR )

// OLE2NOTE: We need access to these GUIDs in modules other than

//  where they are defined (MAIN.C).  Even though the values of the

//  GUIDs are duplicated here, they are not used.  Refer to MAIN.C

//  for the definition of these GUIDs.

/* CLASS ID CONSTANTS (GUID's)

**    OLE2NOTE: these class id values are allocated out of a private pool

**    of GUID's allocated to the OLE 2.0 development team. GUID's of

**    the following range have been allocated to OLE 2.0 sample code:

**         00000400-0000-0000-C000-000000000046

**         000004FF-0000-0000-C000-000000000046

**

**    values reserved thus far:

**          00000400                -- Ole 2.0 Server Sample Outline

**          00000401                -- Ole 2.0 Container Sample Outline

**          00000402                -- Ole 2.0 In-Place Server Outline

**          00000403                -- Ole 2.0 In-Place Container Outline

**          00000404 : 000004FE     -- reserved for OLE Sample code

**          000004FF                -- IID_IOleUILinkContainer

*/

#ifdef TEST32

DEFINE_GUID(CLSID_SvrOut32, 0x00000600, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);

DEFINE_GUID(CLSID_CntrOu32, 0x00000601, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);

DEFINE_GUID(CLSID_ISvrOu32, 0x00000602, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);

DEFINE_GUID(CLSID_ICntrO32, 0x00000603, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);

#else

DEFINE_GUID(CLSID_SvrOutl, 0x00000400, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);

DEFINE_GUID(CLSID_CntrOutl, 0x00000401, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);

DEFINE_GUID(CLSID_ISvrOtl, 0x00000402, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);

DEFINE_GUID(CLSID_ICntrOtl, 0x00000403, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);

#endif  //TEST32

#if defined( OLE_CNTR )

DEFINE_GUID(IID_IOleUILinkContainer, 0x000004FF, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);

#endif

#endif


DIALOGS.DLG  (OUTLINE Sample)

/*************************************************************************

**

**    OLE 2.0 Sample Code

**

**    dialogs.dlg

**

**    Resource file for dialogs

**

**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

**

*************************************************************************/

ADDEDITLINE DIALOG 6, 18, 225, 53

STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU

FONT 8, "Helv"

BEGIN

    EDITTEXT        IDD_EDIT, 5, 16, 212, 13, ES_AUTOHSCROLL

    LTEXT           "Enter text for the line", -1, 5, 4, 72, 8

    PUSHBUTTON      "Cancel", IDCANCEL, 177, 35, 40, 14

    DEFPUSHBUTTON   "OK", IDOK, 5, 35, 40, 14

END

DEFINENAME DIALOG 6, 18, 160, 100

STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU

CAPTION "Define Name"

FONT 8, "Helv"

BEGIN

    COMBOBOX        IDD_COMBO, 5, 17, 98, 49, CBS_SIMPLE | CBS_AUTOHSCROLL |

                    CBS_SORT | WS_VSCROLL | WS_TABSTOP

    DEFPUSHBUTTON   "OK", IDOK, 114, 11, 40, 14

    PUSHBUTTON      "Close", IDD_CLOSE, 114, 31, 40, 14

    PUSHBUTTON      "Delete", IDD_DELETE, 114, 51, 40, 14

    LTEXT           "Defined Names", -1, 5, 6, 57, 8

    LTEXT           "Line Range : ", -1, 5, 76, 44, 8

    LTEXT           "to", -1, 86, 76, 10, 8

    EDITTEXT        IDD_FROM, 50, 75, 32, 12, ES_AUTOHSCROLL

    EDITTEXT        IDD_TO, 99, 75, 32, 12, ES_AUTOHSCROLL

END

GOTONAME DIALOG 6, 18, 160, 93

STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU

CAPTION "Goto Name"

FONT 8, "Helv"

BEGIN

    LISTBOX         IDD_LINELISTBOX, 5, 18, 99, 49, LBS_SORT | WS_VSCROLL |

                    WS_TABSTOP

    LTEXT           "Goto:", -1, 5, 7, 20, 8

    DEFPUSHBUTTON   "OK", IDOK, 115, 18, 40, 14

    PUSHBUTTON      "Cancel", IDCANCEL, 115, 38, 40, 14

    LTEXT           "Line Range : ", -1, 5, 79, 44, 8

    LTEXT           "to", -1, 79, 79, 10, 8

    LTEXT           "", IDD_FROM, 55, 79, 19, 8

    LTEXT           "", IDD_TO, 93, 79, 20, 8

END

PRINT DIALOG 69, 41, 109, 48

STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION

CAPTION "Outline"

FONT 8, "MS Sans Serif"

BEGIN

    PUSHBUTTON      "Cancel", IDCANCEL, 34, 28, 40, 14

    LTEXT           "Printing...", -1, 17, 8, 72, 10

END

SETLINEHEIGHT DIALOG 52, 52, 160, 80

STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU

CAPTION "Set Line Height"

FONT 8, "MS Sans Serif"

BEGIN

    EDITTEXT        IDD_EDIT, 34, 42, 50, 12, ES_AUTOHSCROLL

    LTEXT           "Height:", IDD_TEXT, 6, 43, 28, 12

    CONTROL         "Use Standard Height", IDD_CHECK, "Button",

                    BS_AUTOCHECKBOX | WS_TABSTOP, 6, 64, 80, 10

    LTEXT           "Enter Line Height (100 units = 1mm)", -1, 6, 10, 121,

                    10

    DEFPUSHBUTTON   "OK", IDOK, 110, 40, 40, 14

    PUSHBUTTON      "Cancel", IDCANCEL, 110, 62, 40, 14

    LTEXT           "", IDD_LIMIT, 6, 24, 89, 8

END

ABOUT DIALOG DISCARDABLE  17, 21, 205, 138

STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU

FONT 8, "MS Sans Serif"

BEGIN

    CTEXT           "",IDD_APPTEXT,5,90,195,10

    DEFPUSHBUTTON   "OK",IDOK,81,117,45,15

    CTEXT           "Copyright \2511992 - 1993, Microsoft Corporation", -1,

    	    25,103,156,8

    CONTROL         "",IDD_BITMAPLOCATION,"Static",SS_BLACKFRAME,11,10,184,

                    68

    CONTROL         "",-1,"Static",SS_BLACKFRAME,6,5,194,78

END


DIALOGS.C  (OUTLINE Sample)

/*************************************************************************

**

**    OLE 2 Sample Code

**

**    dialogs.c

**

**    This file contains dialog functions and support function

**

**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

**

*************************************************************************/

#include "outline.h"

OLEDBGDATA

extern LPOUTLINEAPP g_lpApp;

static OLECHAR  g_szBuf[MAXSTRLEN+1];

static LPSTR g_lpszDlgTitle;

// REVIEW: should use string resource for messages

static OLECHAR ErrMsgInvalidRange[] = OLESTR("Invalid Range entered!");

static OLECHAR ErrMsgInvalidValue[] = OLESTR("Invalid Value entered!");

static OLECHAR ErrMsgInvalidName[] = OLESTR("Invalid Name entered!");

static OLECHAR ErrMsgNullName[] = OLESTR("NULL string disallowed!");

static OLECHAR ErrMsgNameNotFound[] = OLESTR("Name doesn't exist!");

/* InputTextDlg

 * ------------

 *

 *      Put up a dialog box to allow the user to edit text

 */

BOOL InputTextDlg(HWND hWnd, LPSTR lpszText, LPSTR lpszDlgTitle)

{

   int nResult;

   g_lpszDlgTitle = lpszDlgTitle;

   A2W (lpszText, g_szBuf, MAXSTRLEN+1);  // preload dialog with input text

   nResult = DialogBox(g_lpApp->m_hInst, (LPSTR)"AddEditLine", hWnd,

                  (DLGPROC)AddEditDlgProc);

   if (nResult) {

      W2A(g_szBuf, lpszText, MAXSTRLEN+1);

      return TRUE;

   } else {

      return FALSE;

   }

}

/* AddEditDlgProc

 * --------------

 *

 * This procedure is associated with the dialog box that is included in

 * the function name of the procedure. It provides the service routines

 * for the events (messages) that occur because the end user operates

 * one of the dialog box's buttons, entry fields, or controls.

 */

BOOL CALLBACK EXPORT AddEditDlgProc(HWND hDlg, UINT Message, WPARAM wParam, LPARAM lParam)

{

   HWND hEdit;

   char szAnsiString[256];

   switch(Message) {

      case WM_INITDIALOG:

         /* initialize working variables */

         hEdit=GetDlgItem(hDlg,IDD_EDIT);

         SendMessage(hEdit,EM_LIMITTEXT,(WPARAM)MAXSTRLEN,0L);

         SetWindowText(hDlg, g_lpszDlgTitle);

         W2A (g_szBuf, szAnsiString, 256);

         SetDlgItemText(hDlg,IDD_EDIT, szAnsiString);

         break; /* End of WM_INITDIALOG */

      case WM_CLOSE:

         /* Closing the Dialog behaves the same as Cancel */

         PostMessage(hDlg, WM_COMMAND, IDCANCEL, 0L);

         break; /* End of WM_CLOSE */

      case WM_COMMAND:

         switch (wParam) {

            case IDOK:

               /* save data values entered into the controls

               ** and dismiss the dialog box returning TRUE

               */

               GetDlgItemText(hDlg,IDD_EDIT,(LPSTR)g_szBuf,MAXSTRLEN+1);

               EndDialog(hDlg, TRUE);

               break;

            case IDCANCEL:

               /* ignore data values entered into the controls

               ** and dismiss the dialog box returning FALSE

               */

               EndDialog(hDlg, FALSE);

               break;

         }

         break;    /* End of WM_COMMAND */

      default:

         return FALSE;

   }

   return TRUE;

} /* End of AddEditDlgProc */

/* SetLineHeightDlgProc

 * --------------------

 *

 *      Dialog procedure for set line height

 */

BOOL CALLBACK EXPORT SetLineHeightDlgProc(HWND hDlg, UINT Message, WPARAM wParam, LPARAM lParam)

{

   BOOL    fTranslated;

   BOOL    fEnable;

   static LPINT    lpint;

   int     nHeight;

   static int nMaxHeight;

   switch (Message) {

      case WM_INITDIALOG:

      {

         char cBuf[80];

         nMaxHeight = XformHeightInPixelsToHimetric(NULL,

                        LISTBOX_HEIGHT_LIMIT);

         lpint = (LPINT)lParam;

         SetDlgItemInt(hDlg, IDD_EDIT, *lpint, FALSE);

         wsprintf(cBuf, "Maximum value is %d units", nMaxHeight);

         SetDlgItemText(hDlg, IDD_LIMIT, (LPSTR)cBuf);

         break;

      }

      case WM_COMMAND:

         switch (wParam) {

            case IDOK:

               if (IsDlgButtonChecked(hDlg, IDD_CHECK)) {

                  *lpint = -1;

               }

               else {

                  /* save the value in the edit control */

                  nHeight = GetDlgItemInt(hDlg, IDD_EDIT,

                        (BOOL FAR*)&fTranslated, FALSE);

                  if (!fTranslated || !nHeight || (nHeight>nMaxHeight)){

                     OutlineApp_ErrorMessage(g_lpApp,

                           ErrMsgInvalidValue);

                     break;

                  }

                  *lpint = nHeight;

               }

               EndDialog(hDlg, TRUE);

               break;

            case IDCANCEL:

               *lpint = 0;

               EndDialog(hDlg, FALSE);

               break;

            case IDD_CHECK:

               fEnable = !IsDlgButtonChecked(hDlg, IDD_CHECK);

               EnableWindow(GetDlgItem(hDlg, IDD_EDIT), fEnable);

               EnableWindow(GetDlgItem(hDlg, IDD_TEXT), fEnable);

               break;

         }

         break;  /* WM_COMMAND */

      case WM_CLOSE:  /* Closing the Dialog behaves the same as Cancel */

         PostMessage(hDlg, WM_COMMAND, IDCANCEL, 0L);

         break; /* End of WM_CLOSE */

      default:

         return FALSE;

   }

   return TRUE;

} /* end of SetLineHeightProc */

/* DefineNameDlgProc

 * -----------------

 *

 *      Dialog procedure for define name

 */

BOOL CALLBACK EXPORT DefineNameDlgProc(HWND hDlg, UINT Message, WPARAM wParam, LPARAM lParam)

{

   static HWND hCombo;

   static LPOUTLINEDOC lpOutlineDoc = NULL;

   static LPOUTLINENAMETABLE lpOutlineNameTable = NULL;

   LPOUTLINENAME lpOutlineName = NULL;

   UINT nIndex;

   LINERANGE lrSel;

   BOOL fTranslated;

   char szAnsiString[256];

   switch(Message) {

      case WM_INITDIALOG:

      /* initialize working variables */

         hCombo=GetDlgItem(hDlg,IDD_COMBO);

         lpOutlineDoc = (LPOUTLINEDOC) lParam;

         lpOutlineNameTable = OutlineDoc_GetNameTable(lpOutlineDoc);

         SendMessage(hCombo,CB_LIMITTEXT,(WPARAM)MAXNAMESIZE,0L);

         NameDlg_LoadComboBox(lpOutlineNameTable, hCombo);

         OutlineDoc_GetSel(lpOutlineDoc, (LPLINERANGE)&lrSel);

         lpOutlineName = OutlineNameTable_FindNamedRange(

               lpOutlineNameTable,

               &lrSel

         );

         /* if current selection already has a name, hilight it */

         if (lpOutlineName) {

            nIndex = (int) SendMessage(

                  hCombo,

                  CB_FINDSTRINGEXACT,

                  (WPARAM)0xffff,

                  (LPARAM)(LPCSTR)lpOutlineName->m_szName

            );

            if (nIndex != CB_ERR) {

               SendMessage(hCombo, CB_SETCURSEL, (WPARAM)nIndex, 0L);

            }

         }

         SetDlgItemInt(hDlg, IDD_FROM, (UINT)lrSel.m_nStartLine+1,FALSE);

         SetDlgItemInt(hDlg, IDD_TO, (UINT)lrSel.m_nEndLine+1, FALSE);

         break; /* End of WM_INITDIALOG */

      case WM_CLOSE:

      /* Closing the Dialog behaves the same as Cancel */

         PostMessage(hDlg, WM_COMMAND, IDD_CLOSE, 0L);

         break; /* End of WM_CLOSE */

      case WM_COMMAND:

         switch(wParam) {

            case IDOK:

               GetDlgItemText(hDlg,IDD_COMBO,(LPSTR)g_szBuf,MAXNAMESIZE);

               if(! SendMessage(hCombo,WM_GETTEXTLENGTH,0,0L)) {

                  W2A (ErrMsgNullName, szAnsiString, 256);

                  MessageBox(

                        hDlg,

                        szAnsiString,

                        NULL,

                        MB_ICONEXCLAMATION

                  );

                  break;

               } else if(SendMessage(hCombo,CB_GETCURSEL,0,0L)==CB_ERR &&

                     wcschr(g_szBuf, ' ')) {

                  W2A (ErrMsgInvalidName, szAnsiString, 256);

                  MessageBox(

                        hDlg,

                        szAnsiString,

                        NULL,

                        MB_ICONEXCLAMATION

                  );

                  break;

               } else {

                  nIndex = (int) SendMessage(hCombo,CB_FINDSTRINGEXACT,

                     (WPARAM)0xffff,(LPARAM)(LPCSTR)g_szBuf);

                  /* Line indices are 1 less than the number in

                  **    the row heading

                  */

                  lrSel.m_nStartLine = GetDlgItemInt(hDlg, IDD_FROM,

                        (BOOL FAR*)&fTranslated, FALSE) - 1;

                  if(! fTranslated) {

                     OutlineApp_ErrorMessage(g_lpApp,

                           ErrMsgInvalidRange);

                     break;

                  }

                  lrSel.m_nEndLine = GetDlgItemInt(hDlg, IDD_TO,

                        (BOOL FAR*)&fTranslated, FALSE) - 1;

                  if (!fTranslated ||

                     (lrSel.m_nStartLine < 0) ||

                     (lrSel.m_nEndLine < lrSel.m_nStartLine) ||

                     (lrSel.m_nEndLine >= OutlineDoc_GetLineCount(

                           lpOutlineDoc))) {

                     OutlineApp_ErrorMessage(g_lpApp,

                           ErrMsgInvalidRange);

                     break;

                  }

                  if(nIndex != CB_ERR) {

                     NameDlg_UpdateName(

                           hCombo,

                           lpOutlineDoc,

                           nIndex,

                           g_szBuf,

                           &lrSel

                     );

                  } else {

                     NameDlg_AddName(

                           hCombo,

                           lpOutlineDoc,

                           g_szBuf,

                           &lrSel

                     );

                  }

               }

               // fall through

            case IDD_CLOSE:

               /* Ignore data values entered into the controls */

               /* and dismiss the dialog window returning FALSE */

               EndDialog(hDlg,0);

               break;

            case IDD_DELETE:

               GetDlgItemText(hDlg,IDD_COMBO,(LPSTR)szAnsiString,MAXNAMESIZE);

               if((nIndex=(int)SendMessage(hCombo,CB_FINDSTRINGEXACT,

               (WPARAM)0xffff,(LPARAM)(LPCSTR)szAnsiString))==CB_ERR) {

                  W2A (ErrMsgNameNotFound, szAnsiString, 256);

                  MessageBox(hDlg, szAnsiString, NULL, MB_ICONEXCLAMATION);

               }

               else {

                  NameDlg_DeleteName(hCombo, lpOutlineDoc, nIndex);

               }

               break;

            case IDD_COMBO:

               if(HIWORD(lParam) == CBN_SELCHANGE) {

                  nIndex=(int)SendMessage(hCombo, CB_GETCURSEL, 0, 0L);

                  lpOutlineName = (LPOUTLINENAME)SendMessage(

                        hCombo,

                        CB_GETITEMDATA,

                        (WPARAM)nIndex,

                        0L

                  );

                  SetDlgItemInt(

                        hDlg,

                        IDD_FROM,

                        (UINT) lpOutlineName->m_nStartLine + 1,

                        FALSE

                  );

                  SetDlgItemInt(

                        hDlg,

                        IDD_TO,

                        (UINT) lpOutlineName->m_nEndLine + 1,

                        FALSE

                  );

               }

         }

         break;    /* End of WM_COMMAND */

      default:

         return FALSE;

   }

   return TRUE;

} /* End of DefineNameDlgProc */

/* GotoNameDlgProc

 * ---------------

 *

 *      Dialog procedure for goto name

 */

BOOL CALLBACK EXPORT GotoNameDlgProc(HWND hDlg, UINT Message, WPARAM wParam, LPARAM lParam)

{

   static HWND hLBName;

   static LPOUTLINEDOC lpOutlineDoc = NULL;

   static LPOUTLINENAMETABLE lpOutlineNameTable = NULL;

   UINT nIndex;

   LINERANGE lrLineRange;

   LPOUTLINENAME lpOutlineName;

   switch(Message) {

      case WM_INITDIALOG:

      /* initialize working variables */

         lpOutlineDoc = (LPOUTLINEDOC) lParam;

         lpOutlineNameTable = OutlineDoc_GetNameTable(lpOutlineDoc);

         hLBName=GetDlgItem(hDlg,IDD_LINELISTBOX);

         NameDlg_LoadListBox(lpOutlineNameTable, hLBName);

         // highlight 1st item

         SendMessage(hLBName, LB_SETCURSEL, 0, 0L);

         // trigger to initialize edit control

         SendMessage(hDlg, WM_COMMAND, (WPARAM)IDD_LINELISTBOX,

            MAKELONG(hLBName, LBN_SELCHANGE));

         break; /* End of WM_INITDIALOG */

      case WM_CLOSE:

      /* Closing the Dialog behaves the same as Cancel */

         PostMessage(hDlg, WM_COMMAND, IDCANCEL, 0L);

         break; /* End of WM_CLOSE */

      case WM_COMMAND:

         switch(wParam) {

            case IDD_LINELISTBOX:

               if(HIWORD(lParam) == LBN_SELCHANGE) {

                  // update the line range display

                  nIndex=(int)SendMessage(hLBName, LB_GETCURSEL, 0, 0L);

                  lpOutlineName = (LPOUTLINENAME)SendMessage(hLBName, LB_GETITEMDATA,

                                 (WPARAM)nIndex,0L);

                  if (lpOutlineName) {

                     SetDlgItemInt(

                           hDlg,

                           IDD_FROM,

                           (UINT) lpOutlineName->m_nStartLine + 1,

                           FALSE

                     );

                     SetDlgItemInt(

                           hDlg,

                           IDD_TO,

                           (UINT) lpOutlineName->m_nEndLine + 1,

                           FALSE

                     );

                  }

                  break;

               }

               // double click will fall through

               else if(HIWORD(lParam) != LBN_DBLCLK)

                  break;

            case IDOK:

               nIndex=(int)SendMessage(hLBName,LB_GETCURSEL,0,0L);

               if(nIndex!=LB_ERR) {

                  lpOutlineName = (LPOUTLINENAME)SendMessage(hLBName,

                        LB_GETITEMDATA, (WPARAM)nIndex, 0L);

                  lrLineRange.m_nStartLine=lpOutlineName->m_nStartLine;

                  lrLineRange.m_nEndLine = lpOutlineName->m_nEndLine;

                  OutlineDoc_SetSel(lpOutlineDoc, &lrLineRange);

               }   // fall through

            case IDCANCEL:

            /* Ignore data values entered into the controls */

            /* and dismiss the dialog window returning FALSE */

               EndDialog(hDlg,0);

               break;

         }

         break;    /* End of WM_COMMAND */

      default:

         return FALSE;

   }

   return TRUE;

} /* End of GotoNameDlgProc */

/* NameDlg_LoadComboBox

 * --------------------

 *

 *      Load defined names into combo box

 */

void NameDlg_LoadComboBox(LPOUTLINENAMETABLE lpOutlineNameTable,HWND hCombo)

{

   LPOUTLINENAME lpOutlineName;

   int i, nIndex;

   int nCount;

   nCount=OutlineNameTable_GetCount((LPOUTLINENAMETABLE)lpOutlineNameTable);

   if(!nCount) return;

   SendMessage(hCombo,WM_SETREDRAW,(WPARAM)FALSE,0L);

   for(i=0; i<nCount; i++) {

      lpOutlineName=OutlineNameTable_GetName((LPOUTLINENAMETABLE)lpOutlineNameTable,i);

      nIndex = (int)SendMessage(

            hCombo,

            CB_ADDSTRING,

            0,

            (LPARAM)(LPCSTR)lpOutlineName->m_szName

      );

      SendMessage(hCombo,CB_SETITEMDATA,(WPARAM)nIndex,(LPARAM)lpOutlineName);

   }

   SendMessage(hCombo,WM_SETREDRAW,(WPARAM)TRUE,0L);

}

/* NameDlg_LoadListBox

 * -------------------

 *

 *      Load defined names into list box

 */

void NameDlg_LoadListBox(LPOUTLINENAMETABLE lpOutlineNameTable,HWND hListBox)

{

   int i;

   int nCount;

   int nIndex;

   LPOUTLINENAME lpOutlineName;

   nCount=OutlineNameTable_GetCount((LPOUTLINENAMETABLE)lpOutlineNameTable);

   SendMessage(hListBox,WM_SETREDRAW,(WPARAM)FALSE,0L);

   for(i=0; i<nCount; i++) {

      lpOutlineName=OutlineNameTable_GetName((LPOUTLINENAMETABLE)lpOutlineNameTable,i);

      nIndex = (int)SendMessage(

            hListBox,

            LB_ADDSTRING,

            0,

            (LPARAM)(LPCSTR)lpOutlineName->m_szName

      );

      SendMessage(hListBox,LB_SETITEMDATA,(WPARAM)nIndex,(LPARAM)lpOutlineName);

   }

   SendMessage(hListBox,WM_SETREDRAW,(WPARAM)TRUE,0L);

}

/* NameDlg_AddName

 * ---------------

 *

 *      Add a name to the name table corresponding to the name dialog

 *      combo box.

 */

void NameDlg_AddName(HWND hCombo, LPOUTLINEDOC lpOutlineDoc, LPOLESTR lpszName, LPLINERANGE lplrSel)

{

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   LPOUTLINENAME lpOutlineName;

   lpOutlineName = OutlineApp_CreateName(lpOutlineApp);

   if (lpOutlineName) {

      OLESTRCPY(lpOutlineName->m_szName, lpszName);

      lpOutlineName->m_nStartLine = lplrSel->m_nStartLine;

      lpOutlineName->m_nEndLine = lplrSel->m_nEndLine;

      OutlineDoc_AddName(lpOutlineDoc, lpOutlineName);

   } else {

      // REVIEW: do we need error message here?

   }

}

/* NameDlg_UpdateName

 * ------------------

 *

 *      Update a name in the name table corresponding to a name in

 *      the name dialog combo box.

 */

void NameDlg_UpdateName(HWND hCombo, LPOUTLINEDOC lpOutlineDoc, int nIndex, LPOLESTR lpszName, LPLINERANGE lplrSel)

{

   LPOUTLINENAME lpOutlineName;

   lpOutlineName = (LPOUTLINENAME)SendMessage(

         hCombo,

         CB_GETITEMDATA,

         (WPARAM)nIndex,

         0L

   );

   OutlineName_SetName(lpOutlineName, lpszName);

   OutlineName_SetSel(lpOutlineName, lplrSel, TRUE /* name modified */);

   OutlineDoc_SetModified(lpOutlineDoc, TRUE, FALSE, FALSE);

}

/* NameDlg_DeleteName

 * ------------------

 *

 *      Delete a name from the name dialog combo box and corresponding

 *      name table.

 */

void NameDlg_DeleteName(HWND hCombo, LPOUTLINEDOC lpOutlineDoc, UINT nIndex)

{

   SendMessage(hCombo,CB_DELETESTRING,(WPARAM)nIndex,0L);

   OutlineDoc_DeleteName(lpOutlineDoc, nIndex);

}

/* PlaceBitmap

 * -----------

 *

 *      Places a bitmap centered in the specified control in the dialog on the

 *      specified DC.

 *

 */

PlaceBitmap(HWND hDlg, int control, HDC hDC, HBITMAP hBitmap)

{

   BITMAP bm;

   HDC hdcmem;

   HBITMAP hbmOld;

   RECT rcControl;     // Rect of dialog control

   int width, height;

   GetObject(hBitmap, sizeof(BITMAP), &bm);

   hdcmem= CreateCompatibleDC(hDC);

   hbmOld = SelectObject(hdcmem, hBitmap);

   // Get rect of control in screen coords, and translate to our dialog

   // box's coordinates

   GetWindowRect(GetDlgItem(hDlg, control), &rcControl);

   MapWindowPoints(NULL, hDlg, (LPPOINT)&rcControl, 2);

   width  = rcControl.right - rcControl.left;

   height = rcControl.bottom - rcControl.top;

   BitBlt(hDC, rcControl.left + (width - bm.bmWidth) / 2,

            rcControl.top + (height - bm.bmHeight) /2,

            bm.bmWidth, bm.bmHeight,

            hdcmem, 0, 0, SRCCOPY);

   SelectObject(hdcmem, hbmOld);

   DeleteDC(hdcmem);

   return 1;

}

/* AboutDlgProc

 * ------------

 *

 *      Dialog procedure for the About function

 */

BOOL CALLBACK EXPORT AboutDlgProc(HWND hDlg, UINT Message, WPARAM wParam, LPARAM lParam)

{

   int  narrVersion[2];

   static HBITMAP hbmLogo;

   char   szAnsiString[256];

   switch(Message) {

      case WM_INITDIALOG:

         // get version number of app

         W2A (APPNAME, szAnsiString, 256);

         wsprintf(szAnsiString, "About %s", (LPCSTR)szAnsiString);

         SetWindowText(hDlg, (LPCSTR)szAnsiString);

         OutlineApp_GetAppVersionNo(g_lpApp, narrVersion);

         wsprintf(szAnsiString, "%s version %d.%d", (LPSTR) APPDESC,

            narrVersion[0], narrVersion[1]);

         SetDlgItemText(hDlg, IDD_APPTEXT, (LPCSTR)szAnsiString);

         // Load bitmap for displaying later

         hbmLogo = LoadBitmap(g_lpApp->m_hInst, "LogoBitmap");

         TraceDebug(hDlg, IDD_BITMAPLOCATION);

         ShowWindow(GetDlgItem(hDlg, IDD_BITMAPLOCATION), SW_HIDE);

         break;

      case WM_PAINT:

         {

         PAINTSTRUCT ps;

         BeginPaint(hDlg, &ps);

         // Display bitmap in IDD_BITMAPLOCATION control area

         PlaceBitmap(hDlg, IDD_BITMAPLOCATION, ps.hdc, hbmLogo);

         EndPaint(hDlg, &ps);

         }

         break;

      case WM_CLOSE :

         PostMessage(hDlg, WM_COMMAND, IDOK, 0L);

         break;

      case WM_COMMAND :

         switch(wParam) {

            case IDOK:

            case IDCANCEL:

               if (hbmLogo) DeleteObject(hbmLogo);

               EndDialog(hDlg,0);

               break;

         }

         break;

      default :

         return FALSE;

   }

   return TRUE;

}


DRAGDROP.C  (OUTLINE Sample)

/*************************************************************************

**

**    OLE 2 Sample Code

**

**    dragdrop.c

**

**    This file contains the major interfaces, methods and related support

**    functions for implementing Drag/Drop. The code contained in this

**    file is used by BOTH the Container and Server (Object) versions

**    of the Outline sample code.

**    The Drag/Drop support includes the following implementation objects:

**

**    OleDoc Object

**      exposed interfaces:

**          IDropSource

**          IDropTarget

**

**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

**

*************************************************************************/

#include "outline.h"

OLEDBGDATA

extern LPOUTLINEAPP             g_lpApp;

#if defined( USE_DRAGDROP )

/* OleDoc_QueryDrag

 * ----------------

 * Check to see if Drag operation should be initiated. A Drag operation

 * should be initiated when the mouse in either the top 10 pixels of the

 * selected list box entry or in the bottom 10 pixels of the last selected

 * item.

 */

BOOL OleDoc_QueryDrag(LPOLEDOC lpOleDoc, int y)

{

        LPLINELIST lpLL = (LPLINELIST)&((LPOUTLINEDOC)lpOleDoc)->m_LineList;

        LINERANGE LineRange;

        if ( LineList_GetSel( lpLL,  (LPLINERANGE)&LineRange) ) {

                RECT rect;

                if (!LineList_GetLineRect(lpLL,LineRange.m_nStartLine,(LPRECT)&rect))

                        return FALSE ;

                if ( rect.top <= y && y <= rect.top + DD_SEL_THRESH )

                        return TRUE;

                LineList_GetLineRect( lpLL, LineRange.m_nEndLine, (LPRECT)&rect );

                if ( rect.bottom >= y && y >= rect.bottom - DD_SEL_THRESH )

                        return TRUE;

        }

        return FALSE;

}

/* OleDoc_DoDragScroll

 * -------------------

 * Check to see if Drag scroll operation should be initiated. A Drag scroll

 * operation should be initiated when the mouse has remained in the active

 * scroll area (11 pixels frame around border of window) for a specified

 * amount of time (50ms).

 */

BOOL OleDoc_DoDragScroll(LPOLEDOC lpOleDoc, POINTL pointl)

{

        LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp;

        LPLINELIST lpLL = (LPLINELIST)&((LPOUTLINEDOC)lpOleDoc)->m_LineList;

        HWND hWndListBox = LineList_GetWindow(lpLL);

        DWORD dwScrollDir = SCROLLDIR_NULL;

        DWORD dwTime = GetCurrentTime();

        int nScrollInset = lpOleApp->m_nScrollInset;

        int nScrollDelay = lpOleApp->m_nScrollDelay;

        int nScrollInterval = lpOleApp->m_nScrollInterval;

        POINT point;

        RECT rect;

        if ( lpLL->m_nNumLines == 0 )

                return FALSE;

        point.x = (int)pointl.x;

        point.y = (int)pointl.y;

        ScreenToClient( hWndListBox, &point);

        GetClientRect ( hWndListBox, (LPRECT) &rect );

        if (rect.top <= point.y && point.y<=(rect.top+nScrollInset))

                dwScrollDir = SCROLLDIR_UP;

        else if ((rect.bottom-nScrollInset) <= point.y && point.y <= rect.bottom)

                dwScrollDir = SCROLLDIR_DOWN;

        if (lpOleDoc->m_dwTimeEnterScrollArea) {

                /* cursor was already in Scroll Area */

                if (! dwScrollDir) {

                        /* cusor moved OUT of scroll area.

                        **      clear "EnterScrollArea" time.

                        */

                        lpOleDoc->m_dwTimeEnterScrollArea = 0L;

                        lpOleDoc->m_dwNextScrollTime = 0L;

                        lpOleDoc->m_dwLastScrollDir = SCROLLDIR_NULL;

                } else if (dwScrollDir != lpOleDoc->m_dwLastScrollDir) {

                        /* cusor moved into a different direction scroll area.

                        **      reset "EnterScrollArea" time to start a new 50ms delay.

                        */

                        lpOleDoc->m_dwTimeEnterScrollArea = dwTime;

                        lpOleDoc->m_dwNextScrollTime = dwTime + (DWORD)nScrollDelay;

                        lpOleDoc->m_dwLastScrollDir = dwScrollDir;

                } else if (dwTime  && dwTime >= lpOleDoc->m_dwNextScrollTime) {

                        LineList_Scroll ( lpLL, dwScrollDir );  // Scroll doc NOW

                        lpOleDoc->m_dwNextScrollTime = dwTime + (DWORD)nScrollInterval;

                }

        } else {

                if (dwScrollDir) {

                        /* cusor moved INTO a scroll area.

                        **      reset "EnterScrollArea" time to start a new 50ms delay.

                        */

                        lpOleDoc->m_dwTimeEnterScrollArea = dwTime;

                        lpOleDoc->m_dwNextScrollTime = dwTime + (DWORD)nScrollDelay;

                        lpOleDoc->m_dwLastScrollDir = dwScrollDir;

                }

        }

        return (dwScrollDir ? TRUE : FALSE);

}

/* OleDoc_QueryDrop

** ----------------

**    Check if the desired drop operation (identified by the given key

**    state) is possible at the current mouse position (pointl).

*/

BOOL OleDoc_QueryDrop (

        LPOLEDOC        lpOleDoc,

        DWORD           grfKeyState,

        POINTL          pointl,

        BOOL            fDragScroll,

        LPDWORD         lpdwEffect

)

{

        LPLINELIST lpLL   = (LPLINELIST)&((LPOUTLINEDOC)lpOleDoc)->m_LineList;

        LINERANGE  linerange;

        short      nIndex = LineList_GetLineIndexFromPointl( lpLL, pointl );

        DWORD      dwScrollEffect = 0L;

        DWORD      dwOKEffects = *lpdwEffect;

        /* check if the cursor is in the active scroll area, if so need the

        **    special scroll cursor.

        */

        if (fDragScroll)

                dwScrollEffect = DROPEFFECT_SCROLL;

        /* if we have already determined that the source does NOT have any

        **    acceptable data for us, the return NO-DROP

        */

        if (! lpOleDoc->m_fCanDropCopy && ! lpOleDoc->m_fCanDropLink)

                goto dropeffect_none;

        /* if the Drag/Drop is local to our document, we can NOT accept a

        **    drop in the middle of the current selection (which is the exact

        **    data that is being dragged!).

        */

        if (lpOleDoc->m_fLocalDrag) {

                LineList_GetSel( lpLL, (LPLINERANGE)&linerange );

                if (linerange.m_nStartLine <= nIndex && nIndex<linerange.m_nEndLine)

                        goto dropeffect_none;

        }

        /* OLE2NOTE: determine what type of drop should be performed given

        **    the current modifier key state. we rely on the standard

        **    interpretation of the modifier keys:

        **          no modifier -- DROPEFFECT_MOVE or whatever is allowed by src

        **          SHIFT       -- DROPEFFECT_MOVE

        **          CTRL        -- DROPEFFECT_COPY

        **          CTRL-SHIFT  -- DROPEFFECT_LINK

        */

        *lpdwEffect = OleStdGetDropEffect(grfKeyState);

        if (*lpdwEffect == 0) {

                // No modifier keys given. Try in order MOVE, COPY, LINK.

                if ((DROPEFFECT_MOVE & dwOKEffects) && lpOleDoc->m_fCanDropCopy)

                        *lpdwEffect = DROPEFFECT_MOVE;

                else if ((DROPEFFECT_COPY & dwOKEffects) && lpOleDoc->m_fCanDropCopy)

                        *lpdwEffect = DROPEFFECT_COPY;

                else if ((DROPEFFECT_LINK & dwOKEffects) && lpOleDoc->m_fCanDropLink)

                        *lpdwEffect = DROPEFFECT_LINK;

                else

                        goto dropeffect_none;

        } else {

                /* OLE2NOTE: we should check if the drag source application allows

                **    the desired drop effect.

                */

                if (!(*lpdwEffect & dwOKEffects))

                        goto dropeffect_none;

                if ((*lpdwEffect == DROPEFFECT_COPY || *lpdwEffect == DROPEFFECT_MOVE)

                                && ! lpOleDoc->m_fCanDropCopy)

                        goto dropeffect_none;

                if (*lpdwEffect == DROPEFFECT_LINK && ! lpOleDoc->m_fCanDropLink)

                        goto dropeffect_none;

        }

        *lpdwEffect |= dwScrollEffect;

        return TRUE;

dropeffect_none:

        *lpdwEffect = DROPEFFECT_NONE;

        return FALSE;

}

/* OleDoc_DoDragDrop

 * -----------------

 *  Actually perform a drag/drop operation with the current selection in

 *      the source document (lpSrcOleDoc).

 *

 *  returns the result effect of the drag/drop operation:

 *      DROPEFFECT_NONE,

 *      DROPEFFECT_COPY,

 *      DROPEFFECT_MOVE, or

 *      DROPEFFECT_LINK

 */

DWORD OleDoc_DoDragDrop (LPOLEDOC lpSrcOleDoc)

{

        LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

        LPOLEAPP     lpOleApp = (LPOLEAPP)g_lpApp;

        LPOUTLINEDOC lpSrcOutlineDoc = (LPOUTLINEDOC)lpSrcOleDoc;

        LPOLEDOC lpDragDoc;

        LPLINELIST  lpSrcLL =

                                        (LPLINELIST)&((LPOUTLINEDOC)lpSrcOleDoc)->m_LineList;

        DWORD       dwEffect     = 0;

        LPLINE      lplineStart, lplineEnd;

        LINERANGE   linerange;

        BOOL        fPrevEnable1;

        BOOL        fPrevEnable2;

        HRESULT     hrErr;

        OLEDBG_BEGIN3("OleDoc_DoDragDrop\r\n")

        /* squirrel away a copy of the current selection to the ClipboardDoc */

        lpDragDoc = (LPOLEDOC)OutlineDoc_CreateDataTransferDoc(lpSrcOutlineDoc);

        if ( ! lpDragDoc) {

                dwEffect = DROPEFFECT_NONE;

                goto error;

        }

        /* OLE2NOTE: initially the DataTransferDoc is created with a 0 ref

        **    count. in order to have a stable Doc object during the drag/

        **    drop operation, we intially AddRef the Doc ref cnt and later

        **    Release it. This AddRef is artificial; it is simply

        **    done to guarantee that a harmless QueryInterface followed by

        **    a Release does not inadvertantly force our object to destroy

        **    itself prematurely.

        */

        OleDoc_AddRef(lpDragDoc);

        //NOTE: we need to keep the LPLINE pointers

        //      rather than the indexes because the

        //      indexes will not be the same after the

        //      drop occurs  -- the drop adds new

        //      entries to the list thereby shifting

        //      the whole list.

        LineList_GetSel( lpSrcLL, (LPLINERANGE)&linerange );

        lplineStart = LineList_GetLine ( lpSrcLL, linerange.m_nStartLine );

        lplineEnd   = LineList_GetLine ( lpSrcLL, linerange.m_nEndLine );

        if (! lplineStart || ! lplineEnd) {

                dwEffect = DROPEFFECT_NONE;

                goto error;

        }

        lpSrcOleDoc->m_fLocalDrop     = FALSE;

        lpSrcOleDoc->m_fLocalDrag     = TRUE;

        /* OLE2NOTE: it is VERY important to DISABLE the Busy/NotResponding

        **    dialogs BEFORE calling DoDragDrop. The DoDragDrop API starts

        **    a mouse capture modal loop. if the Busy/NotResponding comes

        **    up in the middle of this loop (eg. if one of the remoted

        **    calls like IDropTarget::DragOver call takes a long time, then

        **    the NotResponding dialog may want to come up), then the mouse

        **    capture is lost by OLE and things can get messed up.

        */

        OleApp_DisableBusyDialogs(lpOleApp, &fPrevEnable1, &fPrevEnable2);

        OLEDBG_BEGIN2("DoDragDrop called\r\n")

        hrErr = DoDragDrop ( (LPDATAOBJECT) &lpDragDoc->m_DataObject,

                                 (LPDROPSOURCE) &lpSrcOleDoc->m_DropSource,

                                 DROPEFFECT_MOVE | DROPEFFECT_COPY | DROPEFFECT_LINK,

                                 (LPDWORD) &dwEffect

        );

        OLEDBG_END2

        // re-enable the Busy/NotResponding dialogs

        OleApp_EnableBusyDialogs(lpOleApp, fPrevEnable1, fPrevEnable2);

#if defined( _DEBUG )

        if (FAILED(hrErr))

                OleDbgOutHResult("DoDragDrop returned", hrErr);

#endif

        lpSrcOleDoc->m_fLocalDrag     = FALSE;

        /* OLE2NOTE: we need to guard the lifetime of our lpSrcOleDoc

        **    object while we are deleting the lines that were drag

        **    moved. it is possible that deleting these lines could

        **    cause the deletion of a PseudoObj. the deletion of a

        **    PseudoObj will cause the Doc to be unlock

        **    (CoLockObjectExternal(FALSE,TRUE) called). each PseudoObj

        **    holds a strong lock on the Doc. It is always best to have

        **    a memory guard around such critical sections of code. in

        **    this case, it is particularly important if we were an

        **    in-place active server and this drag ended up in a drop

        **    in our outer container. this scenario will lead to a

        **    crash if we do not hold this memory guard.

        */

        OleDoc_Lock(lpSrcOleDoc, TRUE, 0);

        /* if after the Drag/Drop modal (mouse capture) loop is finished

        **    and a drag MOVE operation was performed, then we must delete

        **    the lines that were dragged.

        */

        if ( GetScode(hrErr) == DRAGDROP_S_DROP

                        && (dwEffect & DROPEFFECT_MOVE) != 0 ) {

                int i,j,iEnd;

                LPLINE lplineFocusLine;

                /* disable repainting and sending data changed notifications

                **    until after all lines have been deleted.

                */

                OutlineDoc_SetRedraw ( (LPOUTLINEDOC)lpSrcOleDoc, FALSE );

                /* if the drop was local to our document, then we must take

                **    into account that the line indices of the original source

                **    of the drag could have shifted because the dropped lines

                **    have been inserted into our document. thus we will

                **    re-determine the source line indices.

                */

                if (lpSrcOleDoc->m_fLocalDrop) {

                        i = LineList_GetFocusLineIndex ( lpSrcLL );

                        lplineFocusLine = LineList_GetLine ( lpSrcLL, i );

                }

                for ( i = j = LineList_GetLineIndex(lpSrcLL,lplineStart ) ,

                          iEnd  = LineList_GetLineIndex(lpSrcLL,lplineEnd ) ;

                          i <= iEnd ;

                          i++

                ) OutlineDoc_DeleteLine ((LPOUTLINEDOC)lpSrcOleDoc, j );

                LineList_RecalcMaxLineWidthInHimetric(lpSrcLL, 0);

                if (lpSrcOleDoc->m_fLocalDrop) {

                        i = LineList_GetLineIndex ( lpSrcLL, lplineFocusLine );

                        LineList_SetFocusLine ( lpSrcLL, (WORD)i );

                }

                OutlineDoc_SetRedraw ( (LPOUTLINEDOC)lpSrcOleDoc, TRUE );

                /* if it is a local Drag/Drop move, we need to balance the

                **    SetRedraw(FALSE) call that was made in the implementation

                **    of IDropTarget::Drop.

                */

                if (lpSrcOleDoc->m_fLocalDrop)

                        OutlineDoc_SetRedraw ( (LPOUTLINEDOC)lpSrcOleDoc, TRUE );

                LineList_ForceRedraw ( lpSrcLL, FALSE );

        }

        OleDoc_Release(lpDragDoc);  // rel artificial AddRef above

        OleDoc_Lock(lpSrcOleDoc, FALSE, FALSE);  // unlock artificial lock guard

        OLEDBG_END3

        return dwEffect;

error:

        OLEDBG_END3

        return dwEffect;

}

/*************************************************************************

** OleDoc::IDropSource interface implementation

*************************************************************************/

STDMETHODIMP OleDoc_DropSource_QueryInterface(

        LPDROPSOURCE            lpThis,

        REFIID                  riid,

        LPVOID FAR*             lplpvObj

)

{

        LPOLEDOC lpOleDoc = ((struct CDocDropSourceImpl FAR*)lpThis)->lpOleDoc;

        return OleDoc_QueryInterface(lpOleDoc, riid, lplpvObj);

}

STDMETHODIMP_(ULONG) OleDoc_DropSource_AddRef( LPDROPSOURCE lpThis )

{

        LPOLEDOC lpOleDoc = ((struct CDocDropSourceImpl FAR*)lpThis)->lpOleDoc;

        OleDbgAddRefMethod(lpThis, "IDropSource");

        return OleDoc_AddRef(lpOleDoc);

}

STDMETHODIMP_(ULONG) OleDoc_DropSource_Release ( LPDROPSOURCE lpThis)

{

        LPOLEDOC lpOleDoc = ((struct CDocDropSourceImpl FAR*)lpThis)->lpOleDoc;

        OleDbgReleaseMethod(lpThis, "IDropSource");

        return OleDoc_Release(lpOleDoc);

}

STDMETHODIMP    OleDoc_DropSource_QueryContinueDrag (

        LPDROPSOURCE            lpThis,

        BOOL                    fEscapePressed,

        DWORD                   grfKeyState

){

        if (fEscapePressed)

                return ResultFromScode(DRAGDROP_S_CANCEL);

        else if (!(grfKeyState & MK_LBUTTON))

                return ResultFromScode(DRAGDROP_S_DROP);

        else

                return NOERROR;

}

STDMETHODIMP    OleDoc_DropSource_GiveFeedback (

        LPDROPSOURCE            lpThis,

        DWORD                   dwEffect

)

{

        // Tell OLE to use the standard drag/drop feedback cursors

        return ResultFromScode(DRAGDROP_S_USEDEFAULTCURSORS);

#if defined( IF_SPECIAL_DD_CURSORS_NEEDED )

        switch (dwEffect) {

                case DROPEFFECT_NONE:

                        SetCursor ( ((LPOLEAPP)g_lpApp)->m_hcursorDragNone );

                        break;

                case DROPEFFECT_COPY:

                        SetCursor ( ((LPOLEAPP)g_lpApp)->m_hcursorDragCopy );

                        break;

                case DROPEFFECT_MOVE:

                        SetCursor ( ((LPOLEAPP)g_lpApp)->m_hcursorDragMove );

                        break;

                case DROPEFFECT_LINK:

                        SetCursor ( ((LPOLEAPP)g_lpApp)->m_hcursorDragLink );

                        break;

        }

        return NOERROR;

#endif

}

/*************************************************************************

** OleDoc::IDropTarget interface implementation

*************************************************************************/

STDMETHODIMP OleDoc_DropTarget_QueryInterface(

                LPDROPTARGET        lpThis,

                REFIID              riid,

                LPVOID FAR*         lplpvObj

)

{

        LPOLEDOC lpOleDoc = ((struct CDocDropTargetImpl FAR*)lpThis)->lpOleDoc;

        return OleDoc_QueryInterface(lpOleDoc, riid, lplpvObj);

}

STDMETHODIMP_(ULONG) OleDoc_DropTarget_AddRef(LPDROPTARGET lpThis)

{

        LPOLEDOC lpOleDoc = ((struct CDocDropTargetImpl FAR*)lpThis)->lpOleDoc;

        OleDbgAddRefMethod(lpThis, "IDropTarget");

        return OleDoc_AddRef(lpOleDoc);

}

STDMETHODIMP_(ULONG) OleDoc_DropTarget_Release ( LPDROPTARGET lpThis)

{

        LPOLEDOC lpOleDoc = ((struct CDocDropTargetImpl FAR*)lpThis)->lpOleDoc;

        OleDbgReleaseMethod(lpThis, "IDropTarget");

        return OleDoc_Release(lpOleDoc);

}

STDMETHODIMP    OleDoc_DropTarget_DragEnter (

        LPDROPTARGET            lpThis,

        LPDATAOBJECT            lpDataObj,

        DWORD                   grfKeyState,

        POINTL                  pointl,

        LPDWORD                 lpdwEffect

)

{

        LPOLEAPP   lpOleApp = (LPOLEAPP)g_lpApp;

        LPOLEDOC   lpOleDoc = ((struct CDocDropTargetImpl FAR*)lpThis)->lpOleDoc;

        LPLINELIST lpLL     = (LPLINELIST)&((LPOUTLINEDOC)lpOleDoc)->m_LineList;

        BOOL       fDragScroll;

        // artificial AddRef in case object is destroyed during call

        OleDoc_DropTarget_AddRef(lpThis);

        OLEDBG_BEGIN2("OleDoc_DropTarget_DragEnter\r\n")

        lpOleDoc->m_fDragLeave              = FALSE;

        lpOleDoc->m_dwTimeEnterScrollArea   = 0;

        lpOleDoc->m_dwLastScrollDir         = SCROLLDIR_NULL;

        /* Determine if the drag source data object offers a data format

        **    that we can copy and/or link to.

        */

        lpOleDoc->m_fCanDropCopy = OleDoc_QueryPasteFromData(

                        lpOleDoc,

                        lpDataObj,

                        FALSE   /* fLink */

        );

        lpOleDoc->m_fCanDropLink = OleDoc_QueryPasteFromData(

                        lpOleDoc,

                        lpDataObj,

                        TRUE   /* fLink */

        );

        fDragScroll = OleDoc_DoDragScroll ( lpOleDoc, pointl );

        if (OleDoc_QueryDrop(lpOleDoc,grfKeyState,pointl,fDragScroll,lpdwEffect))

                LineList_SetDragOverLineFromPointl( lpLL, pointl );

        OLEDBG_END2

        // release artificial AddRef

        OleDoc_DropTarget_Release(lpThis);

        return NOERROR;

}

STDMETHODIMP OleDoc_DropTarget_DragOver (

        LPDROPTARGET            lpThis,

        DWORD                   grfKeyState,

        POINTL                  pointl,

        LPDWORD                 lpdwEffect

)

{

        LPOLEAPP   lpOleApp = (LPOLEAPP)g_lpApp;

        LPOLEDOC   lpOleDoc = ((struct CDocDropTargetImpl FAR*)lpThis)->lpOleDoc;

        LPLINELIST lpLL   = (LPLINELIST)&((LPOUTLINEDOC)lpOleDoc)->m_LineList;

        BOOL       fDragScroll;

        // artificial AddRef in case object is destroyed during call

        OleDoc_DropTarget_AddRef(lpThis);

        fDragScroll = OleDoc_DoDragScroll ( lpOleDoc, pointl );

        if (OleDoc_QueryDrop(lpOleDoc,grfKeyState, pointl,fDragScroll,lpdwEffect))

                LineList_SetDragOverLineFromPointl( lpLL, pointl );

        else

                LineList_RestoreDragFeedback( lpLL );

        // release artificial AddRef

        OleDoc_DropTarget_Release(lpThis);

        return NOERROR;

}

STDMETHODIMP    OleDoc_DropTarget_DragLeave ( LPDROPTARGET lpThis)

{

        LPOLEDOC   lpOleDoc = ((struct CDocDropTargetImpl FAR*)lpThis)->lpOleDoc;

        LPLINELIST lpLL     = (LPLINELIST)&((LPOUTLINEDOC)lpOleDoc)->m_LineList;

        // artificial AddRef in case object is destroyed during call

        OleDoc_DropTarget_AddRef(lpThis);

        OLEDBG_BEGIN2("OleDoc_DropTarget_DragLeave\r\n")

        lpOleDoc->m_fDragLeave = TRUE;

        LineList_RestoreDragFeedback( lpLL );

        OLEDBG_END2

        // release artificial AddRef

        OleDoc_DropTarget_Release(lpThis);

        return NOERROR;

}

STDMETHODIMP    OleDoc_DropTarget_Drop (

        LPDROPTARGET            lpThis,

        LPDATAOBJECT            lpDataObj,

        DWORD                   grfKeyState,

        POINTL                  pointl,

        LPDWORD                 lpdwEffect

)

{

        LPOLEDOC   lpOleDoc = ((struct CDocDropTargetImpl FAR*)lpThis)->lpOleDoc;

        LPLINELIST lpLL     = (LPLINELIST)&((LPOUTLINEDOC)lpOleDoc)->m_LineList;

        // artificial AddRef in case object is destroyed during call

        OleDoc_DropTarget_AddRef(lpThis);

        OLEDBG_BEGIN2("OleDoc_DropTarget_Drop\r\n")

        lpOleDoc->m_fDragLeave = TRUE;

        lpOleDoc->m_fLocalDrop = TRUE;

        LineList_RestoreDragFeedback( lpLL );

        SetFocus( LineList_GetWindow( lpLL) );

        if (OleDoc_QueryDrop(lpOleDoc, grfKeyState, pointl, FALSE, lpdwEffect)) {

                BOOL fLink     = (*lpdwEffect == DROPEFFECT_LINK);

                int iFocusLine = LineList_GetFocusLineIndex( lpLL );

                BOOL fStatus;

                OutlineDoc_SetRedraw ( (LPOUTLINEDOC)lpOleDoc, FALSE );

                LineList_SetFocusLineFromPointl ( lpLL, pointl );

                fStatus = OleDoc_PasteFromData(

                                lpOleDoc,

                                lpDataObj,

                                lpOleDoc->m_fLocalDrag, /* data source is local to app */

                                fLink

                );

                // if drop was unsuccessfull, restore the original focus line

                if (! fStatus)

                        LineList_SetFocusLine( lpLL, (WORD)iFocusLine );

#if defined( INPLACE_CNTR )

                {

                        LPCONTAINERDOC lpContainerDoc = (LPCONTAINERDOC)lpOleDoc;

                        /* OLE2NOTE: if there is currently a UIActive OLE object,

                        **    then we must tell it to UIDeactivate after

                        **    the drop has completed.

                        */

                        if (lpContainerDoc->m_lpLastUIActiveLine) {

                                ContainerLine_UIDeactivate(

                                                lpContainerDoc->m_lpLastUIActiveLine);

                        }

                }

#endif

#if defined( INPLACE_SVR )

                {

                        /* OLE2NOTE: if the drop was into a in-place visible

                        **    (in-place active but NOT UIActive object), then we

                        **    want to UIActivate the object after the drop is

                        **    complete.

                        */

                        ServerDoc_UIActivate((LPSERVERDOC) lpOleDoc);

                }

#endif

                /* if it is a local Drag/Drop move, don't enable redraw.

                **    after the source is done deleting the moved lines, it

                **    will re-enable redraw

                */

                if (! (lpOleDoc->m_fLocalDrag

                        && (*lpdwEffect & DROPEFFECT_MOVE) != 0 ))

                        OutlineDoc_SetRedraw ( (LPOUTLINEDOC)lpOleDoc, TRUE );

        }

        OLEDBG_END2

        // release artificial AddRef

        OleDoc_DropTarget_Release(lpThis);

        return NOERROR;

}

#endif  // USE_DRAGDROP


FRAMETLS.H  (OUTLINE Sample)

/*************************************************************************

**

**    OLE 2 Sample Code

**

**    frametls.h

**

**    This file contains file contains data structure defintions,

**    function prototypes, constants, etc. used by the frame level

**    tools used by the Outline series of sample applications. The

**    frame level tools include a formula bar and a button bar (toolbar)

**

**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

**

*************************************************************************/

#if !defined( _FRAMETLS_H_ )

#define _FRAMETLS_H_

#ifndef RC_INVOKED

#pragma message ("INCLUDING FRAMETLS.H from " __FILE__)

#endif  /* RC_INVOKED */

#include "bttncur.h"

#include "gizmobar.h"

#define SPACE   5

#define POPUPSTUB_HEIGHT    5

/* forward type references */

typedef struct tagOUTLINEDOC FAR* LPOUTLINEDOC;

#define IDC_GIZMOBAR    1000

#define IDC_FORMULABAR  1001

#define IDB_CANCEL          0

#define IDB_EDITLINE        1

#define IDB_ADDLINE         2

#define IDB_UNINDENTLINE    3

#define IDB_INDENTLINE      4

#define BARSTATE_TOP        1

#define BARSTATE_BOTTOM     2

#define BARSTATE_POPUP      3

#define BARSTATE_HIDE       4

#define CLASS_PALETTE   "Tool Palette"

typedef struct tagBAR{

   UINT        m_uHeight;

   HWND        m_hWnd;

   int         m_nState;

} BAR, FAR* LPBAR;

typedef struct tagFRAMETOOLS {

   HWND        m_hWndPopupPalette;     // Popup Tool Palette window

   HWND        m_hWndApp;              // App Frame window

   UINT        m_uPopupWidth;          // Width of the popup palette

   HBITMAP     m_hBmp;                 // Image bitmaps

   BOOL        m_fInFormulaBar;        // does formula bar have edit focus

   BOOL        m_fToolsDisabled;       // when TRUE all tools are hidden

   BAR         m_ButtonBar;            // Button Bar

   BAR         m_FormulaBar;           // Formula Bar

   TOOLDISPLAYDATA m_tdd;      // from UIToolConfigureForDisplay

} FRAMETOOLS, FAR* LPFRAMETOOLS;

BOOL FrameToolsRegisterClass(HINSTANCE hInst);

BOOL FrameTools_Init(LPFRAMETOOLS lpft, HWND hWndParent, HINSTANCE hInst);

void FrameTools_AttachToFrame(LPFRAMETOOLS lpft, HWND hWndFrame);

void FrameTools_AssociateDoc(LPFRAMETOOLS lpft, LPOUTLINEDOC lpOutlineDoc);

void FrameTools_Destroy(LPFRAMETOOLS lpft);

void FrameTools_Move(LPFRAMETOOLS lpft, LPRECT lprcClient);

void FrameTools_PopupTools(LPFRAMETOOLS lpft);

void FrameTools_Enable(LPFRAMETOOLS lpft, BOOL fEnable);

void FrameTools_EnableWindow(LPFRAMETOOLS lpft, BOOL fEnable);

#if defined( INPLACE_CNTR ) || defined( INPLACE_SVR )

void FrameTools_NegotiateForSpaceAndShow(

      LPFRAMETOOLS            lpft,

      LPRECT                  lprcFrameRect,

      LPOLEINPLACEFRAME       lpTopIPFrame

);

#endif  // INPLACE_CNTR || INPLACE_SVR

void FrameTools_GetRequiredBorderSpace(LPFRAMETOOLS lpft, LPBORDERWIDTHS lpBorderWidths);

void FrameTools_UpdateButtons(LPFRAMETOOLS lpft, LPOUTLINEDOC lpOutlineDoc);

void FrameTools_FB_SetEditText(LPFRAMETOOLS lpft, LPSTR lpsz);

void FrameTools_FB_GetEditText(LPFRAMETOOLS lpft, LPSTR lpsz, UINT cch);

void FrameTools_FB_FocusEdit(LPFRAMETOOLS lpft);

void FrameTools_FB_SendMessage(LPFRAMETOOLS lpft, UINT uID, UINT msg, WPARAM wParam, LPARAM lParam);

void FrameTools_ForceRedraw(LPFRAMETOOLS lpft);

void FrameTools_BB_SetState(LPFRAMETOOLS lpft, int nState);

void FrameTools_FB_SetState(LPFRAMETOOLS lpft, int nState);

int FrameTools_BB_GetState(LPFRAMETOOLS lpft);

int FrameTools_FB_GetState(LPFRAMETOOLS lpft);

LRESULT FAR PASCAL FrameToolsWndProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam);

#endif // _FRAMETLS_H_


FRAMETLS.C  (OUTLINE Sample)

/*************************************************************************

**

**    OLE 2 Server Sample Code

**

**    frametls.c

**

**    This file contains all FrameTools methods and related support

**    functions. The FrameTools object is an encapsulation of the apps

**    formula bar and button bar.

**

**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

**

*************************************************************************/

#include "outline.h"

OLEDBGDATA

/* private function prototype */

static void Bar_Move(LPBAR lpbar, LPRECT lprcClient, LPRECT lprcPopup);

static void FB_ResizeEdit(LPBAR lpbar);

extern LPOUTLINEAPP g_lpApp;

extern RECT g_rectNull;

/*

 * FrameToolsRegisterClass

 *

 * Purpose:

 *  Register the popup toolbar window class

 *

 * Parameters:

 *  hInst           Process instance

 *

 * Return Value:

 *  TRUE            if successful

 *  FALSE           if failed

 *

 */

BOOL FrameToolsRegisterClass(HINSTANCE hInst)

{

WNDCLASS wc;

// Register Tool Palette Class

wc.style = CS_BYTEALIGNWINDOW;

wc.lpfnWndProc = FrameToolsWndProc;

wc.cbClsExtra = 0;

wc.cbWndExtra = 4;

wc.hInstance = hInst;

wc.hIcon = NULL;

wc.hCursor = LoadCursor(NULL, IDC_ARROW);

wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);

wc.lpszMenuName = NULL;

wc.lpszClassName = CLASS_PALETTE;

if (!RegisterClass(&wc))

return FALSE;

else

return TRUE;

}

static BOOL FrameTools_CreatePopupPalette(LPFRAMETOOLS lpft, HWND hWndFrame)

{

if (lpft->m_hWndPopupPalette)

DestroyWindow(lpft->m_hWndPopupPalette);

lpft->m_hWndPopupPalette = CreateWindow(

CLASS_PALETTE,

"Tool Palette",

WS_POPUP | WS_CAPTION | WS_CLIPCHILDREN,

CW_USEDEFAULT, 0, 0, 0,

hWndFrame,

(HMENU)NULL,

g_lpApp->m_hInst,

0L

);

if (!lpft->m_hWndPopupPalette)

return FALSE;

SetWindowLong(lpft->m_hWndPopupPalette, 0, (LONG)lpft);

return TRUE;

}

/*

 * FrameTools_Init

 *

 * Purpose:

 *  Init and create the toolbar

 *

 * Parameters:

 *  lpft            FrameTools object

 *  hWndParent      The window which owns the toolbar

 *  hInst           Process instance

 *

 * Return Value:

 *  TRUE            if successful

 *  FALSE           if failed

 *

 */

BOOL FrameTools_Init(LPFRAMETOOLS lpft, HWND hWndParent, HINSTANCE hInst)

{

RECT        rc;

UINT        uPos;

UINT        dx;

UINT        dy;

if (!lpft || !hWndParent || !hInst)

return FALSE;

//Get BTTNCUR's display information

UIToolConfigureForDisplay(&lpft->m_tdd);

dx=lpft->m_tdd.cxButton;

dy=lpft->m_tdd.cyButton;

// 15 is calculated from the total number of buttons and separators

lpft->m_uPopupWidth = dx * 15;

lpft->m_hWndApp = hWndParent;

lpft->m_ButtonBar.m_nState = BARSTATE_TOP;

lpft->m_FormulaBar.m_nState = BARSTATE_TOP;

lpft->m_fInFormulaBar = FALSE;

lpft->m_fToolsDisabled = FALSE;

lpft->m_ButtonBar.m_uHeight = lpft->m_tdd.cyBar;

lpft->m_FormulaBar.m_uHeight = lpft->m_tdd.cyBar;

//Get our image bitmaps for the display type we're on

if (72 == lpft->m_tdd.uDPI)

lpft->m_hBmp = LoadBitmap(hInst, (LPCSTR)"Image72");

if (96 == lpft->m_tdd.uDPI)

lpft->m_hBmp = LoadBitmap(hInst, (LPCSTR)"Image96");

if (120 == lpft->m_tdd.uDPI)

lpft->m_hBmp = LoadBitmap(hInst, (LPCSTR)"Image120");

if (!lpft->m_hBmp)

return FALSE;

/* Create Popup Tool Palette window */

lpft->m_hWndPopupPalette = NULL;

if (! FrameTools_CreatePopupPalette(lpft, hWndParent))

return FALSE;

uPos = 0;

//Create the GizmoBar and the client area window

GetClientRect(hWndParent, &rc);

lpft->m_ButtonBar.m_hWnd = CreateWindow(

CLASS_GIZMOBAR,

"ButtonBar",

WS_CHILD | WS_VISIBLE,

0, 0, rc.right-rc.left, lpft->m_tdd.cyBar,

hWndParent,

(HMENU)IDC_GIZMOBAR,

hInst,

0L

);

if (!lpft->m_ButtonBar.m_hWnd)

return FALSE;

SendMessage(lpft->m_ButtonBar.m_hWnd, WM_SETREDRAW, FALSE, 0L);

//File new, open, save, print

GBGizmoAdd(lpft->m_ButtonBar.m_hWnd, GIZMOTYPE_BUTTONCOMMAND, uPos++, IDM_F_NEW, dx, dy, NULL, NULL, TOOLIMAGE_FILENEW, GIZMO_NORMAL);

GBGizmoAdd(lpft->m_ButtonBar.m_hWnd, GIZMOTYPE_BUTTONCOMMAND, uPos++, IDM_F_OPEN, dx, dy, NULL, NULL, TOOLIMAGE_FILEOPEN, GIZMO_NORMAL);

GBGizmoAdd(lpft->m_ButtonBar.m_hWnd, GIZMOTYPE_BUTTONCOMMAND, uPos++, IDM_F_SAVE, dx, dy, NULL, NULL, TOOLIMAGE_FILESAVE, GIZMO_NORMAL);

GBGizmoAdd(lpft->m_ButtonBar.m_hWnd, GIZMOTYPE_BUTTONCOMMAND, uPos++, IDM_F_PRINT, dx, dy, NULL, NULL, TOOLIMAGE_FILEPRINT, GIZMO_NORMAL);

// separator

GBGizmoAdd(lpft->m_ButtonBar.m_hWnd, GIZMOTYPE_SEPARATOR, uPos++, 0, dx/2, dy, NULL, NULL, 0, GIZMO_NORMAL);

// Edit cut, copy, paste

GBGizmoAdd(lpft->m_ButtonBar.m_hWnd, GIZMOTYPE_BUTTONCOMMAND, uPos++, IDM_E_CUT, dx, dy, NULL, NULL, TOOLIMAGE_EDITCUT, GIZMO_NORMAL);

GBGizmoAdd(lpft->m_ButtonBar.m_hWnd, GIZMOTYPE_BUTTONCOMMAND, uPos++, IDM_E_COPY, dx, dy, NULL, NULL, TOOLIMAGE_EDITCOPY, GIZMO_NORMAL);

GBGizmoAdd(lpft->m_ButtonBar.m_hWnd, GIZMOTYPE_BUTTONCOMMAND, uPos++, IDM_E_PASTE, dx, dy, NULL, NULL, TOOLIMAGE_EDITPASTE, GIZMO_NORMAL);

// separator

GBGizmoAdd(lpft->m_ButtonBar.m_hWnd, GIZMOTYPE_SEPARATOR, uPos++, 0, dx/2, dy, NULL, NULL, 0, GIZMO_NORMAL);

// Line indent, unindent

GBGizmoAdd(lpft->m_ButtonBar.m_hWnd, GIZMOTYPE_BUTTONCOMMAND, uPos++, IDM_L_UNINDENTLINE, dx, dy, NULL, lpft->m_hBmp, IDB_UNINDENTLINE, GIZMO_NORMAL);

GBGizmoAdd(lpft->m_ButtonBar.m_hWnd, GIZMOTYPE_BUTTONCOMMAND, uPos++, IDM_L_INDENTLINE, dx, dy, NULL, lpft->m_hBmp, IDB_INDENTLINE, GIZMO_NORMAL);

// separator

GBGizmoAdd(lpft->m_ButtonBar.m_hWnd, GIZMOTYPE_SEPARATOR, uPos++, 0, dx/2, dy, NULL, NULL, 0, GIZMO_NORMAL);

// Help

GBGizmoAdd(lpft->m_ButtonBar.m_hWnd, GIZMOTYPE_BUTTONCOMMAND, uPos++, IDM_H_ABOUT, dx, dy, NULL, NULL, TOOLIMAGE_HELP, GIZMO_NORMAL);

SendMessage(lpft->m_ButtonBar.m_hWnd, WM_SETREDRAW, TRUE, 0L);

uPos = 0;

lpft->m_FormulaBar.m_hWnd = CreateWindow(

CLASS_GIZMOBAR,

"FormulaBar",

WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS,

0, lpft->m_tdd.cyBar, rc.right-rc.left, lpft->m_tdd.cyBar,

hWndParent,

(HMENU)IDC_FORMULABAR,

hInst,

0L

);

if (!lpft->m_FormulaBar.m_hWnd)

return FALSE;

SendMessage(lpft->m_FormulaBar.m_hWnd, WM_SETREDRAW, FALSE, 0L);

// Line add line

GBGizmoAdd(lpft->m_FormulaBar.m_hWnd, GIZMOTYPE_BUTTONCOMMAND, uPos++, IDM_L_ADDLINE, dx, dy, NULL, lpft->m_hBmp, IDB_ADDLINE, GIZMO_NORMAL);

// separator

GBGizmoAdd(lpft->m_FormulaBar.m_hWnd, GIZMOTYPE_SEPARATOR, uPos++, 0, dx/2, dy, NULL, NULL, 0, GIZMO_NORMAL);

// Line edit line, Cancel

GBGizmoAdd(lpft->m_FormulaBar.m_hWnd, GIZMOTYPE_BUTTONCOMMAND, uPos++, IDM_L_EDITLINE, dx, dy, NULL, lpft->m_hBmp, IDB_EDITLINE, GIZMO_NORMAL);

GBGizmoAdd(lpft->m_FormulaBar.m_hWnd, GIZMOTYPE_BUTTONCOMMAND, uPos++, IDM_FB_CANCEL, dx, dy, NULL, lpft->m_hBmp, IDB_CANCEL, GIZMO_NORMAL);

// separator

GBGizmoAdd(lpft->m_FormulaBar.m_hWnd, GIZMOTYPE_SEPARATOR, uPos++, 0, dx/2, dy, NULL, NULL, 0, GIZMO_NORMAL);

// Edit control for line input

GBGizmoAdd(lpft->m_FormulaBar.m_hWnd, GIZMOTYPE_EDIT, uPos++, IDM_FB_EDIT, dx*10, lpft->m_tdd.cyBar-5, NULL, NULL, 0, GIZMO_NORMAL);

SendMessage(lpft->m_FormulaBar.m_hWnd, WM_SETREDRAW, TRUE, 0L);

// Limit the text lenght of edit control

GBGizmoSendMessage(lpft->m_FormulaBar.m_hWnd, IDM_FB_EDIT, EM_LIMITTEXT,

(WPARAM)MAXSTRLEN, 0L);

//Set the GizmoBar's associate to be this client window

GBHwndAssociateSet(lpft->m_ButtonBar.m_hWnd, hWndParent);

//Set the FormulaBar's associate to be this client window

GBHwndAssociateSet(lpft->m_FormulaBar.m_hWnd, hWndParent);

return TRUE;

}

void FrameTools_AttachToFrame(LPFRAMETOOLS lpft, HWND hWndFrame)

{

if (! lpft)

return;

if (hWndFrame == NULL)

hWndFrame = OutlineApp_GetFrameWindow((LPOUTLINEAPP)g_lpApp);

if (lpft->m_hWndApp == hWndFrame)

return;     // already have this parent frame

lpft->m_hWndApp = hWndFrame;

/* parent the tool bars to the frame so we can safely

**    destroy/recreate the palette window.

*/

SetParent(lpft->m_ButtonBar.m_hWnd, hWndFrame);

SetParent(lpft->m_FormulaBar.m_hWnd, hWndFrame);

// recreate popup palette so that it is owned by the hWndFrame

FrameTools_CreatePopupPalette(lpft, hWndFrame);

// restore the correct parent for the tool bars

FrameTools_BB_SetState(lpft, lpft->m_ButtonBar.m_nState);

FrameTools_FB_SetState(lpft, lpft->m_FormulaBar.m_nState);

}

void FrameTools_AssociateDoc(LPFRAMETOOLS lpft, LPOUTLINEDOC lpOutlineDoc)

{

HWND hWnd = OutlineDoc_GetWindow(lpOutlineDoc);

if (! lpft)

return;

// if no Doc is given, then associate with the App's frame window.

if (lpOutlineDoc)

hWnd = OutlineDoc_GetWindow(lpOutlineDoc);

else

hWnd = OutlineApp_GetWindow((LPOUTLINEAPP)g_lpApp);

//Set the GizmoBar's associate to be this client window

GBHwndAssociateSet(lpft->m_ButtonBar.m_hWnd, hWnd);

//Set the FormulaBar's associate to be this client window

GBHwndAssociateSet(lpft->m_FormulaBar.m_hWnd, hWnd);

}

/*

 * FrameTools_Destroy

 *

 * Purpose:

 *  Destroy the toolbar

 *

 * Parameters:

 *  lpft            FrameTools object

 *

 * Return Value:

 *  nil

 */

void FrameTools_Destroy(LPFRAMETOOLS lpft)

{

if (!lpft)

return;

if (IsWindow(lpft->m_ButtonBar.m_hWnd))

DestroyWindow(lpft->m_ButtonBar.m_hWnd);

if (IsWindow(lpft->m_FormulaBar.m_hWnd))

DestroyWindow(lpft->m_FormulaBar.m_hWnd);

if (IsWindow(lpft->m_hWndPopupPalette))

DestroyWindow(lpft->m_hWndPopupPalette);

if (lpft->m_hBmp)

DeleteObject(lpft->m_hBmp);

}

/*

 * FrameTools_Move

 *

 * Purpose:

 *  Move and resize the toolbar

 *

 * Parameters:

 *  lpft            FrameTools object

 *  lprc            Pointer to client rectangle

 *

 * Return Value:

 *  nil

 */

void FrameTools_Move(LPFRAMETOOLS lpft, LPRECT lprcClient)

{

RECT rcPopup;

LPRECT lprcPopup = (LPRECT)&rcPopup;

int nCmdShow = SW_HIDE;

if (!lpft || lpft->m_fToolsDisabled)

return;

lprcPopup->left = 0;

lprcPopup->top = 0;

lprcPopup->right = lpft->m_uPopupWidth;

lprcPopup->bottom = lpft->m_ButtonBar.m_uHeight +

lpft->m_FormulaBar.m_uHeight;

switch (lpft->m_ButtonBar.m_nState) {

case BARSTATE_HIDE:

case BARSTATE_POPUP:

case BARSTATE_TOP:

Bar_Move(&lpft->m_ButtonBar, lprcClient, lprcPopup);

Bar_Move(&lpft->m_FormulaBar, lprcClient, lprcPopup);

break;

case BARSTATE_BOTTOM:

Bar_Move(&lpft->m_FormulaBar, lprcClient, lprcPopup);

Bar_Move(&lpft->m_ButtonBar, lprcClient, lprcPopup);

break;

}

if (lprcPopup->top) {

SetWindowPos(lpft->m_hWndPopupPalette, NULL, 0, 0, lprcPopup->right,

lprcPopup->top + GetSystemMetrics(SM_CYCAPTION),

SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW);

}

else

ShowWindow(lpft->m_hWndPopupPalette, SW_HIDE);

FB_ResizeEdit(&lpft->m_FormulaBar);

InvalidateRect(lpft->m_ButtonBar.m_hWnd, NULL, TRUE);

InvalidateRect(lpft->m_FormulaBar.m_hWnd, NULL, TRUE);

}

/*

 * FrameTools_PopupTools

 *

 * Purpose:

 *  Put both formula bar and button bar in Popup Window.

 *

 * Parameters:

 *  lpft            FrameTools object

 *

 * Return Value:

 *  nil

 */

void FrameTools_PopupTools(LPFRAMETOOLS lpft)

{

if (! lpft)

return;

FrameTools_BB_SetState(lpft, BARSTATE_POPUP);

FrameTools_FB_SetState(lpft, BARSTATE_POPUP);

FrameTools_Move(lpft, NULL);

}

/*

 * FrameTools_Enable

 *

 * Purpose:

 *  Enable/Disable(hide) all the tools of the toolbar.

 *  this will hide both the buttonbar and the

 *  formulabar independent of whether they are floating or anchored.

 *

 * Parameters:

 *  lpft            FrameTools object

 *  fEnable

 *

 * Return Value:

 *  nil

 */

void FrameTools_Enable(LPFRAMETOOLS lpft, BOOL fEnable)

{

lpft->m_fToolsDisabled = !fEnable;

if (lpft->m_fToolsDisabled) {

ShowWindow(lpft->m_hWndPopupPalette, SW_HIDE);

ShowWindow(lpft->m_ButtonBar.m_hWnd, SW_HIDE);

ShowWindow(lpft->m_FormulaBar.m_hWnd, SW_HIDE);

}

}

/*

 * FrameTools_EnableWindow

 *

 * Purpose:

 *  EnableWindow for all the tools of the toolbar.

 *  this enables/disables mouse and keyboard input to the tools.

 *  while a modal dialog is up, it is inportant to disable the

 *  floating tool windows.

 *  this will NOT hide any windows; it will only call EnableWindow.

 *

 * Parameters:

 *  lpft            FrameTools object

 *  fEnable

 *

 * Return Value:

 *  nil

 */

void FrameTools_EnableWindow(LPFRAMETOOLS lpft, BOOL fEnable)

{

EnableWindow(lpft->m_hWndPopupPalette, fEnable);

EnableWindow(lpft->m_ButtonBar.m_hWnd, fEnable);

EnableWindow(lpft->m_FormulaBar.m_hWnd, fEnable);

}

#if defined( INPLACE_CNTR ) || defined( INPLACE_SVR )

/*

 * FrameTools_NegotiateForSpaceAndShow

 *

 * Purpose:

 *  Negotiate for space for the toolbar tools with the given frame window.

 *  and make them visible.

 *  Negotiation steps:

 *     1. try to get enough space at top/bottom of window

 *     2. float the tools as a palette if space not available

 *

 * Parameters:

 *  lpft            FrameTools object

 *

 * Return Value:

 *  none

 */

void FrameTools_NegotiateForSpaceAndShow(

LPFRAMETOOLS            lpft,

LPRECT                  lprcFrameRect,

LPOLEINPLACEFRAME       lpTopIPFrame

)

{

BORDERWIDTHS    borderwidths;

RECT            rectBorder;

HRESULT         hrErr;

if (lprcFrameRect)

rectBorder = *lprcFrameRect;

else {

/* OLE2NOTE: by calling GetBorder, the server can find out the

**    size of the frame window. it can use this information to

**    make decisions about how to orient/organize it tools (eg.

**    if window is taller than wide put tools vertically at

**    left edge).

*/

OLEDBG_BEGIN2("IOleInPlaceFrame::GetBorder called\r\n")

hrErr = lpTopIPFrame->lpVtbl->GetBorder(

lpTopIPFrame,

(LPRECT)&rectBorder

);

OLEDBG_END2

}

/* Try SetBorderSpace() with the space that you need. If it fails then

** you can negotiate for space and then do the SetBorderSpace().

*/

FrameTools_GetRequiredBorderSpace(lpft,(LPBORDERWIDTHS)&borderwidths);

OLEDBG_BEGIN2("IOleInPlaceFrame::SetBorderSpace called\r\n")

hrErr = lpTopIPFrame->lpVtbl->SetBorderSpace(

lpTopIPFrame,

(LPCBORDERWIDTHS)&borderwidths

);

OLEDBG_END2

#if defined( LATER )

if (hrErr != NOERROR) {

/* Frame did not give the toolsspace that we want. So negotiate */

// REVIEW: try a different placement of the tools here

OLEDBG_BEGIN2("IOleInPlaceFrame::RequestBorderSpace called\r\n")

hrErr = lpTopIPFrame->lpVtbl->RequestBorderSpace(

lpTopIPFrame,

(LPCBORDERWIDTHS)&borderwidths

);

OLEDBG_END2

if (hrErr == NOERROR) {

OLEDBG_BEGIN2("IOleInPlaceFrame::SetBorderSpace called\r\n")

hrErr = lpTopIPFrame->lpVtbl->SetBorderSpace(

lpTopIPFrame,

(LPCBORDERWIDTHS)&borderwidths

);

OLEDBG_END2

}

}

#endif

if (hrErr == NOERROR) {

FrameTools_Move(lpft, (LPRECT)&rectBorder);   // we got what we wanted

} else {

/* We did not get tool space, so POP them up.

/* OLE2NOTE: since we are poping up our tools, we MUST inform

**    the top in-place frame window that we need NO tool space

**    BUT that it should NOT put its own tools up. if we were

**    to pass NULL instead of (0,0,0,0), then the container

**    would have the option to leave its own tools up.

*/

OLEDBG_BEGIN2("IOleInPlaceFrame::SetBorderSpace(NULL) called\r\n")

hrErr = lpTopIPFrame->lpVtbl->SetBorderSpace(

lpTopIPFrame,

(LPCBORDERWIDTHS)&g_rectNull

);

OLEDBG_END2

FrameTools_PopupTools(lpft);

}

}

#endif  // INPLACE_CNTR || INPLACE_SVR

/*

 * FrameTools_GetRequiredBorderSpace

 *

 * Purpose:

 *  Calculate the desired space for the toolbar tools.

 *

 * Parameters:

 *  lpft            FrameTools object

 *  lpBorderWidths  Widths required at top,bottom,left,right

 *

 * Return Value:

 *  nil

 */

void FrameTools_GetRequiredBorderSpace(LPFRAMETOOLS lpft, LPBORDERWIDTHS lpBorderWidths)

{

*lpBorderWidths = g_rectNull;

switch (lpft->m_ButtonBar.m_nState) {

case BARSTATE_TOP:

lpBorderWidths->top += lpft->m_ButtonBar.m_uHeight;

break;

case BARSTATE_BOTTOM:

lpBorderWidths->bottom += lpft->m_ButtonBar.m_uHeight;

break;

}

switch (lpft->m_FormulaBar.m_nState) {

case BARSTATE_TOP:

lpBorderWidths->top += lpft->m_FormulaBar.m_uHeight;

break;

case BARSTATE_BOTTOM:

lpBorderWidths->bottom += lpft->m_FormulaBar.m_uHeight;

break;

}

}

/*

 * FrameTools_UpdateButtons

 *

 * Purpose:

 *  Enable/disable individual buttons of the toolbar according to the

 *  state of the app

 *

 * Parameters:

 *  lpft            FrameTools object

 *

 * Return Value:

 *  nil

 */

void FrameTools_UpdateButtons(LPFRAMETOOLS lpft, LPOUTLINEDOC lpOutlineDoc)

{

BOOL            fEnable;

#if defined( OLE_VERSION )

LPDATAOBJECT    lpClipboardDataObj;

HRESULT         hrErr;

LPOLEAPP        lpOleApp = (LPOLEAPP)g_lpApp;

BOOL            fPrevEnable1;

BOOL            fPrevEnable2;

#endif

if (!lpft)

return;

#if defined( INPLACE_CNTR )

{

LPCONTAINERDOC lpContainerDoc = (LPCONTAINERDOC)lpOutlineDoc;

if (lpContainerDoc->m_lpLastUIActiveLine &&

lpContainerDoc->m_lpLastUIActiveLine->m_fUIActive) {

/* if there is a UIActive object, then we should disable

**    all of our "active editor" commands. we should enable

**    only those commands that are "workspace" commands.

*/

if (lpft->m_FormulaBar.m_nState != BARSTATE_HIDE) {

GBGizmoEnable(lpft->m_FormulaBar.m_hWnd,IDM_L_EDITLINE,FALSE);

GBGizmoEnable(lpft->m_FormulaBar.m_hWnd,IDM_L_ADDLINE,FALSE);

GBGizmoEnable(lpft->m_FormulaBar.m_hWnd,IDM_FB_CANCEL,FALSE);

GBGizmoEnable(lpft->m_FormulaBar.m_hWnd,IDM_L_EDITLINE,FALSE);

}

if (lpft->m_ButtonBar.m_nState != BARSTATE_HIDE)

{

GBGizmoEnable(lpft->m_ButtonBar.m_hWnd, IDM_E_CUT, FALSE);

GBGizmoEnable(lpft->m_ButtonBar.m_hWnd, IDM_E_COPY, FALSE);

GBGizmoEnable(lpft->m_ButtonBar.m_hWnd, IDM_E_PASTE, FALSE);

GBGizmoEnable(lpft->m_ButtonBar.m_hWnd,IDM_L_INDENTLINE,FALSE);

GBGizmoEnable(lpft->m_ButtonBar.m_hWnd, IDM_L_UNINDENTLINE, FALSE);

GBGizmoEnable(lpft->m_ButtonBar.m_hWnd, IDM_H_ABOUT, FALSE);

GBGizmoEnable(lpft->m_ButtonBar.m_hWnd, IDM_FB_EDIT, FALSE);

GBGizmoEnable(lpft->m_ButtonBar.m_hWnd, IDM_F_NEW, TRUE);

GBGizmoEnable(lpft->m_ButtonBar.m_hWnd, IDM_F_OPEN, TRUE);

GBGizmoEnable(lpft->m_ButtonBar.m_hWnd, IDM_F_SAVE, TRUE);

}

return;

}

}

#endif    // INPLACE_CNTR

fEnable = (BOOL)OutlineDoc_GetLineCount(lpOutlineDoc);

if (lpft->m_FormulaBar.m_nState != BARSTATE_HIDE) {

GBGizmoEnable(lpft->m_FormulaBar.m_hWnd, IDM_L_EDITLINE, fEnable);

if (! lpft->m_fInFormulaBar) {

GBGizmoEnable(lpft->m_FormulaBar.m_hWnd, IDM_L_ADDLINE, FALSE);

GBGizmoEnable(lpft->m_FormulaBar.m_hWnd, IDM_FB_CANCEL, FALSE);

GBGizmoEnable(lpft->m_FormulaBar.m_hWnd, IDM_L_EDITLINE, FALSE);

if (!fEnable) {

GBGizmoTextSet(lpft->m_FormulaBar.m_hWnd, IDM_FB_EDIT, "");

}

} else {

GBGizmoEnable(lpft->m_FormulaBar.m_hWnd, IDM_L_ADDLINE, TRUE);

GBGizmoEnable(lpft->m_FormulaBar.m_hWnd, IDM_FB_CANCEL, TRUE);

}

}

if (lpft->m_ButtonBar.m_nState != BARSTATE_HIDE)

{

GBGizmoEnable(lpft->m_ButtonBar.m_hWnd, IDM_E_CUT, fEnable);

GBGizmoEnable(lpft->m_ButtonBar.m_hWnd, IDM_E_COPY, fEnable);

GBGizmoEnable(lpft->m_ButtonBar.m_hWnd, IDM_L_INDENTLINE, fEnable);

GBGizmoEnable(lpft->m_ButtonBar.m_hWnd, IDM_L_UNINDENTLINE, fEnable);

#if defined( OLE_SERVER )

{

LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOutlineDoc;

#if defined( INPLACE_SVR )

fEnable = ((lpServerDoc->m_fUIActive) ? FALSE : TRUE);

#else

fEnable = (lpOutlineDoc->m_docInitType != DOCTYPE_EMBEDDED);

#endif  // INPLACE_SVR

GBGizmoEnable(lpft->m_ButtonBar.m_hWnd, IDM_F_NEW, fEnable);

GBGizmoEnable(lpft->m_ButtonBar.m_hWnd, IDM_F_OPEN, fEnable);

GBGizmoEnable(lpft->m_ButtonBar.m_hWnd, IDM_F_SAVE, fEnable);

}

#endif  // OLE_SERVER

#if defined( OLE_VERSION )

/* OLE2NOTE: we do not want to ever give the busy dialog when we

**    are trying to enable or disable our tool bar buttons eg.

**    even if the source of data on the clipboard is busy, we do

**    not want put up the busy dialog. thus we will disable the

**    dialog and at the end re-enable it.

*/

OleApp_DisableBusyDialogs(lpOleApp, &fPrevEnable1, &fPrevEnable2);

/* OLE2NOTE: perform OLE specific menu initialization.

**    the OLE versions use the OleGetClipboard mechanism for

**    clipboard handling. thus, they determine if the Paste

**    command should be enabled in an OLE specific manner.

*/

fEnable = FALSE;

hrErr = OleGetClipboard((LPDATAOBJECT FAR*)&lpClipboardDataObj);

if (hrErr == NOERROR) {

int nFmtEtc;

nFmtEtc = OleStdGetPriorityClipboardFormat(

lpClipboardDataObj,

lpOleApp->m_arrPasteEntries,

lpOleApp->m_nPasteEntries

);

fEnable = (nFmtEtc >= 0);  // there IS a format we like

OleStdRelease((LPUNKNOWN)lpClipboardDataObj);

}

// re-enable the busy dialog

OleApp_EnableBusyDialogs(lpOleApp, fPrevEnable1, fPrevEnable2);

GBGizmoEnable(lpft->m_ButtonBar.m_hWnd, IDM_E_PASTE, fEnable);

#else

// Base Outline version uses standard Windows clipboard handling

if(IsClipboardFormatAvailable(g_lpApp->m_cfOutline) ||

IsClipboardFormatAvailable(CF_TEXT))

GBGizmoEnable(lpft->m_ButtonBar.m_hWnd, IDM_E_PASTE, TRUE);

else

GBGizmoEnable(lpft->m_ButtonBar.m_hWnd, IDM_E_PASTE, FALSE);

#endif  // OLE_VERSION

}

}

/*

 * FrameTools_FB_SetEditText

 *

 * Purpose:

 *  Set text in the edit control in FormulaBar

 *

 * Parameters:

 *  lpft            FrameTools object

 *  lpsz            pointer to string to be set

 *

 * Return Value:

 *  nil

 */

void FrameTools_FB_SetEditText(LPFRAMETOOLS lpft, LPSTR lpsz)

{

GBGizmoTextSet(lpft->m_FormulaBar.m_hWnd, IDM_FB_EDIT, lpsz);

}

/*

 * FrameTools_FB_GetEditText

 *

 * Purpose:

 *  Get text from the edit control in FormulaBar

 *

 * Parameters:

 *  lpft            FrameTools object

 *  lpsz            pointer to buffer to receive the text

 *  cch             buffer size

 *

 * Return Value:

 *  nil

 */

void FrameTools_FB_GetEditText(LPFRAMETOOLS lpft, LPSTR lpsz, UINT cch)

{

GBGizmoTextGet(lpft->m_FormulaBar.m_hWnd, IDM_FB_EDIT, lpsz, cch);

}

/*

 * FrameTools_FB_FocusEdit

 *

 * Purpose:

 *  Set the focus in the edit control of FormulaBar

 *

 * Parameters:

 *  lpft            FrameTools object

 *

 * Return Value:

 *  nil

 */

void FrameTools_FB_FocusEdit(LPFRAMETOOLS lpft)

{

GBGizmoFocusSet(lpft->m_FormulaBar.m_hWnd, IDM_FB_EDIT);

// select the whole text in the edit control

GBGizmoSendMessage(lpft->m_FormulaBar.m_hWnd, IDM_FB_EDIT, EM_SETSEL,

(WPARAM)TRUE, MAKELPARAM(0, -1));

}

/*

 * FrameTools_FB_SendMessage

 *

 * Purpose:

 *  Send a message to the FormulaBar window gizmo

 *

 * Parameters:

 *  lpft            FrameTools object

 *  uID             gizmo ID

 *  msg

 *  wParam

 *  lParam

 *

 * Return Value:

 *  nil

 */

void FrameTools_FB_SendMessage(LPFRAMETOOLS lpft, UINT uID, UINT msg, WPARAM wParam, LPARAM lParam)

{

GBGizmoSendMessage(lpft->m_FormulaBar.m_hWnd, uID, msg, wParam, lParam);

}

/*

 * FrameTools_FB_ForceRedraw

 *

 * Purpose:

 *  Force the toolbar to draw itself

 *

 * Parameters:

 *  lpft            FrameTools object

 *

 * Return Value:

 *  nil

 */

void FrameTools_ForceRedraw(LPFRAMETOOLS lpft)

{

InvalidateRect(lpft->m_ButtonBar.m_hWnd, NULL, TRUE);

InvalidateRect(lpft->m_FormulaBar.m_hWnd, NULL, TRUE);

InvalidateRect(lpft->m_hWndPopupPalette, NULL, TRUE);

}

/*

 * FrameTools_BB_SetState

 *

 * Purpose:

 *  Set display state of ButtonBar

 *

 * Parameters:

 *  lpft            FrameTools object

 *  nState          new display state

 *

 * Return Value:

 *  nil

 */

void FrameTools_BB_SetState(LPFRAMETOOLS lpft, int nState)

{

if (!lpft) {

return;

}

lpft->m_ButtonBar.m_nState = nState;

if (nState == BARSTATE_POPUP)

SetParent(lpft->m_ButtonBar.m_hWnd, lpft->m_hWndPopupPalette);

else

SetParent(lpft->m_ButtonBar.m_hWnd, lpft->m_hWndApp);

}

/*

 * FrameTools_BB_GetState

 *

 * Purpose:

 *  Get display state of ButtonBar

 *

 * Parameters:

 *  lpft            FrameTools object

 *

 * Return Value:

 *  nState          current display state

 */

int FrameTools_BB_GetState(LPFRAMETOOLS lpft)

{

return lpft->m_ButtonBar.m_nState;

}

/*

 * FrameTools_FB_SetState

 *

 * Purpose:

 *  Set display state of FormulaBar

 *

 * Parameters:

 *  lpft            FrameTools object

 *  nState          new display state

 *

 * Return Value:

4 *  nil

 */

void FrameTools_FB_SetState(LPFRAMETOOLS lpft, int nState)

{

if (!lpft) {

return;

}

lpft->m_FormulaBar.m_nState = nState;

if (nState == BARSTATE_POPUP)

SetParent(lpft->m_FormulaBar.m_hWnd, lpft->m_hWndPopupPalette);

#if defined( INPLACE_SVR )

/* OLE2NOTE: it is dangerous for an in-place server to hide its

**    toolbar window and leave it parented to the hWndFrame of the

**    in-place container. if the in-place container call

**    ShowOwnedPopups, then it could inadvertantly be made visible.

**    to avoid this we will parent the toolbar window back to our

**    own application main window. if we are not in-place active

**    then this is the same as lpft->m_hWndApp.

*/

else if (nState == BARSTATE_HIDE)

SetParent(lpft->m_FormulaBar.m_hWnd, g_lpApp->m_hWndApp);

#endif

else

SetParent(lpft->m_FormulaBar.m_hWnd, lpft->m_hWndApp);

}

/*

 * FrameTools_FB_GetState

 *

 * Purpose:

 *  Get display state of FormulaBar

 *

 * Parameters:

 *  lpft            FrameTools object

 *

 * Return Value:

 *  nState          current display state

 */

int FrameTools_FB_GetState(LPFRAMETOOLS lpft)

{

return lpft->m_FormulaBar.m_nState;

}

/*

 * FrameToolsWndProc

 *

 * Purpose:

 *  WndProc for toolbar window

 *

 * Parameters:

 *  hWnd

 *  Message

 *  wParam

 *  lParam

 *

 * Return Value:

 *  message dependent

 */

LRESULT FAR PASCAL FrameToolsWndProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam)

{

LPFRAMETOOLS lpft = (LPFRAMETOOLS)GetWindowLong(hWnd, 0);

switch (Message) {

case WM_MOUSEACTIVATE:

return MA_NOACTIVATE;

default:

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

}

return 0L;

}

/*

 * Bar_Move

 *

 * Purpose:

 *  Resize and reposition a bar

 *

 * Parameters:

 *  lpbar           Bar object

 *  lprcClient      pointer to Client rect

 *  lprcPopup       pointer to Popup rect

 *

 * Return Value:

 *  nil

 */

static void Bar_Move(LPBAR lpbar, LPRECT lprcClient, LPRECT lprcPopup)

{

if (lpbar->m_nState == BARSTATE_HIDE) {

ShowWindow(lpbar->m_hWnd, SW_HIDE);

}

else {

ShowWindow(lpbar->m_hWnd, SW_SHOW);

switch (lpbar->m_nState) {

case BARSTATE_POPUP:

MoveWindow(lpbar->m_hWnd, lprcPopup->left, lprcPopup->top,

lprcPopup->right - lprcPopup->left, lpbar->m_uHeight,

TRUE);

lprcPopup->top += lpbar->m_uHeight;

break;

case BARSTATE_TOP:

MoveWindow(lpbar->m_hWnd, lprcClient->left, lprcClient->top,

lprcClient->right - lprcClient->left,

lpbar->m_uHeight, TRUE);

lprcClient->top += lpbar->m_uHeight;

break;

case BARSTATE_BOTTOM:

MoveWindow(lpbar->m_hWnd, lprcClient->left,

lprcClient->bottom - lpbar->m_uHeight,

lprcClient->right - lprcClient->left,

lpbar->m_uHeight, TRUE);

lprcClient->bottom -= lpbar->m_uHeight;

break;

}

}

}

/*

 * FB_ResizeEdit

 *

 * Purpose:

 *  Resize the edit control in FormulaBar

 *

 * Parameters:

 *  lpft            Bar object

 *

 * Return Value:

 *  nil

 */

static void FB_ResizeEdit(LPBAR lpbar)

{

RECT rcClient;

RECT rcEdit;

HWND hwndEdit;

GetClientRect(lpbar->m_hWnd, (LPRECT)&rcClient);

hwndEdit = GetDlgItem(lpbar->m_hWnd, IDM_FB_EDIT);

GetWindowRect(hwndEdit, (LPRECT)&rcEdit);

ScreenToClient(lpbar->m_hWnd, (LPPOINT)&rcEdit.left);

ScreenToClient(lpbar->m_hWnd, (LPPOINT)&rcEdit.right);

SetWindowPos(hwndEdit, NULL, 0, 0, rcClient.right - rcEdit.left - SPACE,

rcEdit.bottom - rcEdit.top, SWP_NOMOVE | SWP_NOZORDER);

}


HEADING.H  (OUTLINE Sample)

/*************************************************************************

**

**    OLE 2 Sample Code

**

**    heading.c

**

**    This file contains definitions used by OutlineDoc's row and

**    column headings.

**

**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

**

*************************************************************************/

#define COLUMN  10

#define IDC_ROWHEADING  2000

#define IDC_COLHEADING  2001

#define IDC_BUTTON      2002

#define HEADING_FONT    "Arial"

#define COLUMN_LETTER   'A'

typedef struct tagCOLHEADING {

HWND m_hWnd;

UINT m_uHeight;

} COLHEADING, FAR* LPCOLHEADING;

typedef struct tagROWHEADING {

HWND m_hWnd;

UINT m_uWidth;

FARPROC    m_WndProc;

} ROWHEADING, FAR* LPROWHEADING;

typedef struct tagHEADING {

COLHEADING m_colhead;

ROWHEADING m_rowhead;

HWND       m_hwndButton;

BOOL       m_fShow;

HFONT      m_hfont;

} HEADING, FAR* LPHEADING;

BOOL Heading_Create(LPHEADING lphead, HWND hWndParent, HINSTANCE hInst);

void Heading_Destroy(LPHEADING lphead);

void Heading_Move(LPHEADING lphead, HWND hwndListBox, LPSCALEFACTOR lpscale);

void Heading_Show(LPHEADING lphead, BOOL fShow);

void Heading_ReScale(LPHEADING lphead, LPSCALEFACTOR lpscale);

void Heading_CH_Draw(LPHEADING lphead, LPDRAWITEMSTRUCT lpdis, LPRECT lprcScreen, LPRECT lprcObject);

void Heading_CH_SetHorizontalExtent(LPHEADING lphead, HWND hwndListBox);

UINT Heading_CH_GetHeight(LPHEADING lphead, LPSCALEFACTOR lpscale);

LRESULT Heading_CH_SendMessage(LPHEADING lphead, UINT msg, WPARAM wParam, LPARAM lParam);

void Heading_CH_ForceRedraw(LPHEADING lphead, BOOL fErase);

void Heading_RH_ForceRedraw(LPHEADING lphead, BOOL fErase);

void Heading_RH_Draw(LPHEADING lphead, LPDRAWITEMSTRUCT lpdis);

LRESULT Heading_RH_SendMessage(LPHEADING lphead, UINT msg, WPARAM wParam, LPARAM lParam);

UINT Heading_RH_GetWidth(LPHEADING lphead, LPSCALEFACTOR lpscale);

void Heading_RH_Scroll(LPHEADING lphead, HWND hwndListBox);

LRESULT FAR PASCAL RowHeadWndProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam);


HEADING.C  (OUTLINE Sample)

/*************************************************************************

**

**    OLE 2 Sample Code

**

**    heading.c

**

**    This file contains functions and support for OutlineDoc's row and

**    column headings.

**

**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

**

*************************************************************************/

#include "outline.h"

extern LPOUTLINEAPP g_lpApp;

BOOL Heading_Create(LPHEADING lphead, HWND hWndParent, HINSTANCE hInst)

{

   HDC         hDC;

   TEXTMETRIC  tm;

   if (!lphead || !hWndParent || !hInst)

      return FALSE;

   hDC = GetDC(hWndParent);

   if (!hDC)

      return FALSE;

   if (!GetTextMetrics(hDC, (TEXTMETRIC FAR*)&tm))

      return FALSE;

   lphead->m_colhead.m_uHeight = tm.tmHeight;

   lphead->m_rowhead.m_uWidth = 4 * tm.tmAveCharWidth;

   lphead->m_fShow = TRUE;

   ReleaseDC(hWndParent, hDC);

   lphead->m_hfont = CreateFont(

         tm.tmHeight,

         0,0,0,0,0,0,0,0,

         OUT_TT_PRECIS,      // use TrueType

         CLIP_DEFAULT_PRECIS,

         DEFAULT_QUALITY,

         DEFAULT_PITCH | FF_DONTCARE,

         HEADING_FONT

   );

   if (!lphead->m_hfont)

      return FALSE;

   lphead->m_colhead.m_hWnd = CreateWindow(

         "listbox",

         "Column Heading",

         WS_VISIBLE | WS_CHILD | WS_DISABLED | LBS_OWNERDRAWVARIABLE |

               LBS_NOINTEGRALHEIGHT,

         0,0,0,0,        // any values

         hWndParent,

         (HMENU)IDC_COLHEADING,

         hInst,

         NULL);

   if (!lphead->m_colhead.m_hWnd)

      return FALSE;

   // add a dummy line to get WM_DRAWITEM message

   SendMessage(lphead->m_colhead.m_hWnd, LB_ADDSTRING, 0,

         MAKELPARAM(lphead->m_colhead.m_uHeight,0));

   lphead->m_rowhead.m_hWnd = CreateWindow(

         "listbox",

         "Row Heading",

         WS_VISIBLE | WS_CHILD | WS_DISABLED | LBS_OWNERDRAWVARIABLE,

         0,0,0,0,        // any values

         hWndParent,

         (HMENU)IDC_ROWHEADING,

         hInst,

         NULL);

   if (!lphead->m_rowhead.m_hWnd)

      return FALSE;

   SendMessage(lphead->m_rowhead.m_hWnd, LB_ADDSTRING, 0,

         MAKELPARAM(lphead->m_colhead.m_uHeight,0));

   lphead->m_rowhead.m_WndProc =

         (FARPROC) GetWindowLong(lphead->m_rowhead.m_hWnd, GWL_WNDPROC );

   SetWindowLong(lphead->m_rowhead.m_hWnd, GWL_WNDPROC,

         (LONG) RowHeadWndProc);

   lphead->m_hwndButton = CreateWindow(

         "button",

         NULL,

         WS_VISIBLE | WS_CHILD,

         0,0,0,0,        // any values

         hWndParent,

         (HMENU)IDC_BUTTON,

         hInst,

         NULL);

   if (!lphead->m_hwndButton)

      return FALSE;

   return TRUE;

}

void Heading_Destroy(LPHEADING lphead)

{

   if (!lphead)

      return;

   if (IsWindow(lphead->m_colhead.m_hWnd)) {

      DestroyWindow(lphead->m_colhead.m_hWnd);

      lphead->m_colhead.m_hWnd = NULL;

   }

   if (IsWindow(lphead->m_rowhead.m_hWnd)) {

      DestroyWindow(lphead->m_rowhead.m_hWnd);

      lphead->m_rowhead.m_hWnd = NULL;

   }

   if (IsWindow(lphead->m_hwndButton)) {

      DestroyWindow(lphead->m_hwndButton);

      lphead->m_hwndButton = NULL;

   }

#ifdef WIN32

   if (GetObjectType(lphead->m_hfont)) {

#else

   if (IsGDIObject(lphead->m_hfont)) {

#endif

      DeleteObject(lphead->m_hfont);

      lphead->m_hfont = NULL;

   }

}

void Heading_Move(LPHEADING lphead, HWND hwndDoc, LPSCALEFACTOR lpscale)

{

   int nOffsetX;

   int nOffsetY;

   RECT rcDoc;

   if (!lphead || !hwndDoc || !lpscale)

      return;

   if (!lphead->m_fShow)

      return;

   nOffsetX = (int) Heading_RH_GetWidth(lphead, lpscale);

   nOffsetY = (int) Heading_CH_GetHeight(lphead, lpscale);

   GetClientRect(hwndDoc, (LPRECT)&rcDoc);

   MoveWindow(lphead->m_hwndButton, 0, 0, nOffsetX, nOffsetY, TRUE);

   MoveWindow(

         lphead->m_colhead.m_hWnd,

         nOffsetX, 0,

         rcDoc.right-rcDoc.left-nOffsetX, nOffsetY,

         TRUE

   );

   MoveWindow(lphead->m_rowhead.m_hWnd, 0, nOffsetY, nOffsetX,

         rcDoc.bottom-rcDoc.top-nOffsetY, TRUE);

}

void Heading_Show(LPHEADING lphead, BOOL fShow)

{

   int nCmdShow;

   if (!lphead)

      return;

   lphead->m_fShow = fShow;

   nCmdShow = fShow ? SW_SHOW : SW_HIDE;

   ShowWindow(lphead->m_hwndButton, nCmdShow);

   ShowWindow(lphead->m_colhead.m_hWnd, nCmdShow);

   ShowWindow(lphead->m_rowhead.m_hWnd, nCmdShow);

}

void Heading_ReScale(LPHEADING lphead, LPSCALEFACTOR lpscale)

{

   UINT uHeight;

   if (!lphead || !lpscale)

      return;

   // Row heading is scaled with the LineList_Rescale. So, only

   // Column heading needed to be scaled here.

   uHeight = (UINT)(lphead->m_colhead.m_uHeight * lpscale->dwSyN /

         lpscale->dwSyD);

   SendMessage(lphead->m_colhead.m_hWnd, LB_SETITEMHEIGHT, 0,

         MAKELPARAM(uHeight, 0));

}

void Heading_CH_Draw(LPHEADING lphead, LPDRAWITEMSTRUCT lpdis, LPRECT lprcScreen, LPRECT lprcObject)

{

   HPEN        hpenOld;

   HPEN        hpen;

   HBRUSH      hbr;

   HFONT       hfOld;

   int         nTabInPix;

   char        letter;

   int         i;

   int         nOldMapMode;

   RECT        rcWindowOld;

   RECT        rcViewportOld;

   POINT    point;

   if (!lpdis || !lphead)

      return;

   hbr = GetStockObject(LTGRAY_BRUSH);

   FillRect(lpdis->hDC, (LPRECT)&lpdis->rcItem, hbr);

   nOldMapMode = SetDCToAnisotropic(lpdis->hDC, lprcScreen, lprcObject,

         (LPRECT)&rcWindowOld, (LPRECT)&rcViewportOld);

   hfOld = SelectObject(lpdis->hDC, lphead->m_hfont);

   hpen = GetStockObject(BLACK_PEN);

   hpenOld = SelectObject(lpdis->hDC, hpen);

   nTabInPix = XformWidthInHimetricToPixels(lpdis->hDC, TABWIDTH);

   SetBkMode(lpdis->hDC, TRANSPARENT);

   letter = COLUMN_LETTER;

   MoveToEx(lpdis->hDC, lprcObject->left, lprcObject->bottom,&point);

   LineTo(lpdis->hDC, lprcObject->left, lprcObject->top);

   for (i = 0; i < COLUMN; i++) {

      lprcObject->right = lprcObject->left + nTabInPix;

      DrawText(lpdis->hDC, (LPCSTR)&letter, 1, lprcObject,

            DT_SINGLELINE | DT_CENTER | DT_VCENTER);

      MoveToEx(lpdis->hDC, lprcObject->right, lprcObject->bottom, &point);

      LineTo(lpdis->hDC, lprcObject->right, lprcObject->top);

      letter++;

      lprcObject->left += nTabInPix;

   }

   SelectObject(lpdis->hDC, hpenOld);

   SelectObject(lpdis->hDC, hfOld);

   ResetOrigDC(lpdis->hDC, nOldMapMode, (LPRECT)&rcWindowOld,

         (LPRECT)&rcViewportOld);

}

void Heading_CH_SetHorizontalExtent(LPHEADING lphead, HWND hwndListBox)

{

   RECT rcLL;

   RECT rcCH;

   int  nLLWidth;

   int  nCHWidth;

   int  nHorizExtent;

   if (!lphead || !hwndListBox)

      return;

   nHorizExtent=(int)SendMessage(hwndListBox, LB_GETHORIZONTALEXTENT, 0, 0L);

   GetClientRect(hwndListBox, (LPRECT)&rcLL);

   GetClientRect(lphead->m_colhead.m_hWnd, (LPRECT)&rcCH);

   nLLWidth = rcLL.right - rcLL.left;

   nCHWidth = rcCH.right - rcCH.left;

   nHorizExtent += nCHWidth - nLLWidth;

   SendMessage(lphead->m_colhead.m_hWnd, LB_SETHORIZONTALEXTENT,

         nHorizExtent, 0L);

}

UINT Heading_CH_GetHeight(LPHEADING lphead, LPSCALEFACTOR lpscale)

{

   if (!lphead || !lpscale)

      return 0;

   if (lphead->m_fShow)

      return (UINT)(lphead->m_colhead.m_uHeight * lpscale->dwSyN /

            lpscale->dwSyD);

   else

      return 0;

}

LRESULT Heading_CH_SendMessage(LPHEADING lphead, UINT msg, WPARAM wParam, LPARAM lParam)

{

   if (!lphead)

      return 0;

   if (lphead->m_colhead.m_hWnd)

      return SendMessage(lphead->m_colhead.m_hWnd, msg, wParam, lParam);

}

void Heading_CH_ForceRedraw(LPHEADING lphead, BOOL fErase)

{

   if (!lphead)

      return;

   InvalidateRect(lphead->m_colhead.m_hWnd, NULL, fErase);

}

void Heading_RH_ForceRedraw(LPHEADING lphead, BOOL fErase)

{

   if (!lphead)

      return;

   InvalidateRect(lphead->m_rowhead.m_hWnd, NULL, fErase);

}

void Heading_RH_Draw(LPHEADING lphead, LPDRAWITEMSTRUCT lpdis)

{

   char        cBuf[5];

   HPEN        hpenOld;

   HPEN        hpen;

   HBRUSH      hbrOld;

   HBRUSH      hbr;

   HFONT       hfOld;

   RECT        rc;

   RECT        rcWindowOld;

   RECT        rcViewportOld;

   int         nMapModeOld;

   if (!lpdis || !lphead)

      return;

   lpdis->rcItem;

   rc.left = 0;

   rc.bottom = 0;

   rc.top = (int)lpdis->itemData;

   rc.right = lphead->m_rowhead.m_uWidth;

   nMapModeOld = SetDCToAnisotropic(lpdis->hDC, &lpdis->rcItem, &rc,

         (LPRECT)&rcWindowOld, (LPRECT)&rcViewportOld);

   hpen = GetStockObject(BLACK_PEN);

   hpenOld = SelectObject(lpdis->hDC, hpen);

   hbr = GetStockObject(LTGRAY_BRUSH);

   hbrOld = SelectObject(lpdis->hDC, hbr);

   Rectangle(lpdis->hDC, rc.left, rc.top, rc.right,

         rc.bottom);

   hfOld = SelectObject(lpdis->hDC, lphead->m_hfont);

   SetBkMode(lpdis->hDC, TRANSPARENT);

   wsprintf(cBuf, "%d", lpdis->itemID + 1);

   DrawText(lpdis->hDC, (LPSTR)cBuf, lstrlen(cBuf), (LPRECT)&rc,

         DT_SINGLELINE | DT_CENTER | DT_VCENTER);

   SelectObject(lpdis->hDC, hfOld);

   SelectObject(lpdis->hDC, hpenOld);

   SelectObject(lpdis->hDC, hbrOld);

   ResetOrigDC(lpdis->hDC, nMapModeOld, (LPRECT)&rcWindowOld,

         (LPRECT)&rcViewportOld);

}

LRESULT Heading_RH_SendMessage(LPHEADING lphead, UINT msg, WPARAM wParam, LPARAM lParam)

{

   if (!lphead)

      return 0;

   if (lphead->m_rowhead.m_hWnd)

      return SendMessage(lphead->m_rowhead.m_hWnd, msg, wParam, lParam);

}

UINT Heading_RH_GetWidth(LPHEADING lphead, LPSCALEFACTOR lpscale)

{

   if (!lphead || !lpscale)

      return 0;

   if (lphead->m_fShow)

      return (UINT)(lphead->m_rowhead.m_uWidth * lpscale->dwSxN /

            lpscale->dwSxD);

   else

      return 0;

}

void Heading_RH_Scroll(LPHEADING lphead, HWND hwndListBox)

{

   int nTopLL;

   int nTopRH;

   if (!lphead || !hwndListBox)

      return;

   nTopLL = (int)SendMessage(hwndListBox, LB_GETTOPINDEX, 0, 0L);

   nTopRH = (int)SendMessage(

         lphead->m_rowhead.m_hWnd, LB_GETTOPINDEX, 0, 0L);

   if (nTopLL != nTopRH)

      SendMessage(

            lphead->m_rowhead.m_hWnd,LB_SETTOPINDEX,(WPARAM)nTopLL,0L);

}

LRESULT FAR PASCAL RowHeadWndProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam)

{

   HWND     hwndParent = GetParent (hWnd);

   LPOUTLINEDOC lpDoc = (LPOUTLINEDOC)GetWindowLong(hwndParent, 0);

   LPHEADING lphead = OutlineDoc_GetHeading(lpDoc);

   switch (Message) {

      case WM_PAINT:

      {

         LPLINELIST lpLL = OutlineDoc_GetLineList(lpDoc);

         PAINTSTRUCT ps;

         // If there is no line in listbox, trap the message and draw the

         // background gray. Without this, the background will be painted

         // as default color.

         if (!LineList_GetCount(lpLL)) {

            BeginPaint(hWnd, &ps);

            EndPaint(hWnd, &ps);

            return 0;

         }

         break;

      }

      case WM_ERASEBKGND:

      {

         HDC hDC = (HDC)wParam;

         RECT rc;

         GetClientRect(hWnd, (LPRECT)&rc);

         FillRect(hDC, (LPRECT)&rc, GetStockObject(GRAY_BRUSH));

         return 1;

      }

   }

   return CallWindowProc(

         (WNDPROC)lphead->m_rowhead.m_WndProc,

         hWnd,

         Message,

         wParam,

         lParam

   );

}


ICNTROTL.DEF  (OUTLINE Sample)

;;

;;

;;    OLE 2.0 Container Sample Code

;;

;;    icntrotl.def

;;

;;    Definition file for icntrotl.exe

;;

;;    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

;;

;;

NAME            ICntrOtl

DESCRIPTION             'Microsoft OLE 2.0 In-Place Container Sample code'

EXETYPE         WINDOWS

STUB            'WINSTUB.EXE'

CODE            PRELOAD MOVEABLE

DATA            PRELOAD MOVEABLE MULTIPLE

HEAPSIZE        4096

;; NOTE: Do not add exports to this file.  Use __export

;; in your function prototype and definition instead.


ICNTROTL.RC  (OUTLINE Sample)

/*************************************************************************

**

**    OLE 2.0 Container Sample Code

**

**    icntrotl.rc

**

**    Resource file for icntrotl.exe

**

**	  (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

**

*************************************************************************/

#include "windows.h"

#include "outlrc.h"

#include "cntrrc.h"

SelCur      CURSOR selcross.cur

DragMoveCur CURSOR dragmove.cur

#if defined( IF_SPECIAL_DD_CURSORS_NEEDED )

DragNoneCur CURSOR dragnone.cur

DragCopyCur CURSOR dragcopy.cur

DragLinkCur CURSOR draglink.cur

#endif  // IF_SPECIAL_DD_CURSORS_NEEDED

CntrOutlMenu MENU

  BEGIN

    POPUP  "&File"

      BEGIN

        MENUITEM "&New", IDM_F_NEW

        MENUITEM "&Open...\t  Ctrl+F12", IDM_F_OPEN

        MENUITEM "&Save\t  Shift+F12", IDM_F_SAVE

        MENUITEM "Save &As...\t  F12", IDM_F_SAVEAS

        MENUITEM SEPARATOR

        MENUITEM "&Print...\t  Ctrl+Shift+F12", IDM_F_PRINT

        MENUITEM "Printer Se&tup...", IDM_F_PRINTERSETUP

        MENUITEM SEPARATOR

        MENUITEM "E&xit\t  Alt+F4", IDM_F_EXIT

      END

    POPUP  "&Edit"

      BEGIN

        MENUITEM "&Undo", IDM_E_UNDO

        MENUITEM SEPARATOR

        MENUITEM "Cu&t\t  Ctrl+X", IDM_E_CUT

        MENUITEM "&Copy\t  Ctrl+C", IDM_E_COPY

        MENUITEM "&Paste\t  Ctrl+V", IDM_E_PASTE

        MENUITEM "Paste &Special...", IDM_E_PASTESPECIAL

        MENUITEM "Paste &Link", IDM_E_PASTELINK

        MENUITEM "Cl&ear\t  Del", IDM_E_CLEAR

        MENUITEM SEPARATOR

        MENUITEM "&Insert Object...", IDM_E_INSERTOBJECT

        MENUITEM "Li&nks...", IDM_E_EDITLINKS

MENUITEM "&Object", IDM_E_OBJECTVERBMIN

        MENUITEM SEPARATOR

        MENUITEM "Select &All\t  Ctrl+A", IDM_E_SELECTALL

      END

POPUP  "O&utline"

  BEGIN

        POPUP  "&Zoom"

          BEGIN

            MENUITEM "&100%\t  Ctrl+1", IDM_V_ZOOM_100

            MENUITEM "&75%\t  Ctrl+2", IDM_V_ZOOM_75

            MENUITEM "&50%\t  Ctrl+3", IDM_V_ZOOM_50

            MENUITEM "&25%\t  Ctrl+4", IDM_V_ZOOM_25

          END

        POPUP  "&Left and Right margins"

          BEGIN

            MENUITEM "&nil", IDM_V_SETMARGIN_0

            MENUITEM "&1 cm", IDM_V_SETMARGIN_1

            MENUITEM "&2 cm", IDM_V_SETMARGIN_2

            MENUITEM "&3 cm", IDM_V_SETMARGIN_3

            MENUITEM "&4 cm", IDM_V_SETMARGIN_4

          END

        POPUP "Add &Top Line"

  BEGIN

    MENUITEM "&1 cm", IDM_V_ADDTOP_1

    MENUITEM "&2 cm", IDM_V_ADDTOP_2

    MENUITEM "&3 cm", IDM_V_ADDTOP_3

    MENUITEM "&4 cm", IDM_V_ADDTOP_4

  END

  END

    POPUP  "&Line"

      BEGIN

        MENUITEM "&Add Line\t  Enter", IDM_L_ADDLINE

        MENUITEM "E&dit Line\t  Alt+Enter", IDM_L_EDITLINE

        MENUITEM SEPARATOR

        MENUITEM "&Indent Line\t  Tab", IDM_L_INDENTLINE

        MENUITEM "U&nindent Line\t  Shift+Tab", IDM_L_UNINDENTLINE

MENUITEM SEPARATOR

MENUITEM "&Set Line Height...", IDM_L_SETLINEHEIGHT

      END

    POPUP  "&Name"

      BEGIN

        MENUITEM "&Define Name...", IDM_N_DEFINENAME

        MENUITEM "&Goto Name...", IDM_N_GOTONAME

      END

    POPUP  "&Options"

      BEGIN

        POPUP  "&Button Bar Display"

          BEGIN

            MENUITEM "At &Top", IDM_O_BB_TOP

            MENUITEM "At &Bottom", IDM_O_BB_BOTTOM

            MENUITEM "&Popup", IDM_O_BB_POPUP

            MENUITEM "&Hide", IDM_O_BB_HIDE

          END

        POPUP  "&Formula Bar Display"

          BEGIN

            MENUITEM "At &Top", IDM_O_FB_TOP

            MENUITEM "At &Bottom", IDM_O_FB_BOTTOM

            MENUITEM "&Popup", IDM_O_FB_POPUP

          END

        POPUP  "&Row and Column Heading"

          BEGIN

            MENUITEM "&Show", IDM_O_HEAD_SHOW

            MENUITEM "&Hide", IDM_O_HEAD_HIDE

          END

    MENUITEM "&Show Object", IDM_O_SHOWOBJECT

      END

    POPUP  "DbgI&Cntr"

      BEGIN

        MENUITEM "&Debug Level...", IDM_D_DEBUGLEVEL

        MENUITEM "Register Message &Filter", IDM_D_INSTALLMSGFILTER

        MENUITEM "&Reject Incoming Messages", IDM_D_REJECTINCOMING

        MENUITEM "&Inside-out Activation", IDM_D_INSIDEOUT

      END

    POPUP  "&Help"

      BEGIN

        MENUITEM "&About...", IDM_H_ABOUT

      END

  END

CntrOutlAccel ACCELERATORS

  BEGIN

    VK_F12, IDM_F_OPEN, VIRTKEY, CONTROL

    VK_F12, IDM_F_SAVE, VIRTKEY, SHIFT

    VK_F12, IDM_F_SAVEAS, VIRTKEY

    VK_F12, IDM_F_PRINT, VIRTKEY, CONTROL, SHIFT

    "x", IDM_E_CUT, VIRTKEY, CONTROL

    "c", IDM_E_COPY, VIRTKEY, CONTROL

    "v", IDM_E_PASTE, VIRTKEY, CONTROL

    VK_DELETE, IDM_E_CLEAR, VIRTKEY

    VK_RETURN, IDM_L_ADDLINE, VIRTKEY

    VK_RETURN, IDM_L_EDITLINE, VIRTKEY, ALT

    VK_TAB, IDM_L_INDENTLINE, VIRTKEY

    VK_TAB, IDM_L_UNINDENTLINE, VIRTKEY, SHIFT

    "a", IDM_E_SELECTALL, VIRTKEY, CONTROL

    ; old conventions for editing

    VK_INSERT, IDM_E_COPY, VIRTKEY, CONTROL

    VK_DELETE, IDM_E_CUT, VIRTKEY, SHIFT

    VK_INSERT, IDM_E_PASTE, VIRTKEY, SHIFT

    VK_F2, IDM_F2, VIRTKEY

VK_ESCAPE, IDM_ESCAPE, VIRTKEY

    "1", IDM_V_ZOOM_100, VIRTKEY, CONTROL

    "2", IDM_V_ZOOM_75, VIRTKEY, CONTROL

    "3", IDM_V_ZOOM_50, VIRTKEY, CONTROL

    "4", IDM_V_ZOOM_25, VIRTKEY, CONTROL

  END

; Same as CntrOutlAccel but without Delete and Backspace

; used when edit control of Formula Bar in focus

;

CntrOutlAccelFocusEdit ACCELERATORS

  BEGIN

    VK_F12, IDM_F_OPEN, VIRTKEY, CONTROL

    VK_F12, IDM_F_SAVE, VIRTKEY, SHIFT

    VK_F12, IDM_F_SAVEAS, VIRTKEY

    VK_F12, IDM_F_PRINT, VIRTKEY, CONTROL, SHIFT

    "x", IDM_E_CUT, VIRTKEY, CONTROL

    "c", IDM_E_COPY, VIRTKEY, CONTROL

    "v", IDM_E_PASTE, VIRTKEY, CONTROL

    VK_RETURN, IDM_L_ADDLINE, VIRTKEY

    VK_RETURN, IDM_L_EDITLINE, VIRTKEY, ALT

    VK_TAB, IDM_L_INDENTLINE, VIRTKEY

    VK_TAB, IDM_L_UNINDENTLINE, VIRTKEY, SHIFT

    "a", IDM_E_SELECTALL, VIRTKEY, CONTROL

VK_ESCAPE, IDM_ESCAPE, VIRTKEY

    ; old conventions for editing

    VK_INSERT, IDM_E_COPY, VIRTKEY, CONTROL

    VK_DELETE, IDM_E_CUT, VIRTKEY, SHIFT

    VK_INSERT, IDM_E_PASTE, VIRTKEY, SHIFT

  END

InPlaceCntrOutlAccel ACCELERATORS

  BEGIN

    VK_F12, IDM_F_OPEN, VIRTKEY, CONTROL

    VK_F12, IDM_F_SAVE, VIRTKEY, SHIFT

    VK_F12, IDM_F_SAVEAS, VIRTKEY

    VK_F12, IDM_F_PRINT, VIRTKEY, CONTROL, SHIFT

VK_ESCAPE, IDM_ESCAPE, VIRTKEY

    "1", IDM_V_ZOOM_100, VIRTKEY, CONTROL

    "2", IDM_V_ZOOM_75, VIRTKEY, CONTROL

    "3", IDM_V_ZOOM_50, VIRTKEY, CONTROL

    "4", IDM_V_ZOOM_25, VIRTKEY, CONTROL

  END

CntrOutlIcon ICON icntrotl.ico

Image72     BITMAP      image72.bmp

Image96     BITMAP      image96.bmp

Image120    BITMAP      image120.bmp

LogoBitmap  BITMAP      ole2.bmp

#include "DIALOGS.DLG"


ICNTROTL.C  (OUTLINE Sample)

/*************************************************************************

**

**    OLE 2.0 Sample Code

**

**    precomp.c

**

**    This file is used to precompile the OUTLINE.H header file

**

**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

**

*************************************************************************/

#include "outline.h"


ISVROTL.RC  (OUTLINE Sample)

/*************************************************************************

**

**    OLE 2.0 Server Sample Code

**

**    isvrotl.rc

**

**    Resource file for isvrotl.exe

**

**	  (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

**

*************************************************************************/

#include "windows.h"

#include "outlrc.h"

SelCur      CURSOR selcross.cur

DragMoveCur CURSOR dragmove.cur

#if defined( IF_SPECIAL_DD_CURSORS_NEEDED )

DragNoneCur CURSOR dragnone.cur

DragCopyCur CURSOR dragcopy.cur

DragLinkCur CURSOR draglink.cur

#endif  // IF_SPECIAL_DD_CURSORS_NEEDED

SvrOutlMenu MENU

  BEGIN

    POPUP  "&File"

      BEGIN

        MENUITEM "&New", IDM_F_NEW

        MENUITEM "&Open...\t  Ctrl+F12", IDM_F_OPEN

        MENUITEM "&Save\t  Shift+F12", IDM_F_SAVE

        MENUITEM "Save &As...\t  F12", IDM_F_SAVEAS

        MENUITEM SEPARATOR

        MENUITEM "&Print...\t  Ctrl+Shift+F12", IDM_F_PRINT

        MENUITEM "Printer Se&tup...", IDM_F_PRINTERSETUP

        MENUITEM SEPARATOR

        MENUITEM "E&xit\t  Alt+F4", IDM_F_EXIT

      END

    POPUP  "&Edit"

      BEGIN

        MENUITEM "&Undo", IDM_E_UNDO

        MENUITEM SEPARATOR

        MENUITEM "Cu&t\t  Ctrl+X", IDM_E_CUT

        MENUITEM "&Copy\t  Ctrl+C", IDM_E_COPY

        MENUITEM "&Paste\t  Ctrl+V", IDM_E_PASTE

        MENUITEM "Paste &Special...", IDM_E_PASTESPECIAL

        MENUITEM "Cl&ear\t  Del", IDM_E_CLEAR

        MENUITEM SEPARATOR

        MENUITEM "Select A&ll\t  Ctrl+A", IDM_E_SELECTALL

      END

POPUP  "O&utline"

  BEGIN

        POPUP  "&Zoom"

          BEGIN

            MENUITEM "&400%", IDM_V_ZOOM_400

            MENUITEM "&300%", IDM_V_ZOOM_300

            MENUITEM "&200%", IDM_V_ZOOM_200

            MENUITEM "&100%", IDM_V_ZOOM_100

            MENUITEM "&75%", IDM_V_ZOOM_75

            MENUITEM "&50%", IDM_V_ZOOM_50

            MENUITEM "&25%", IDM_V_ZOOM_25

          END

        POPUP  "&Left and Right margins"

          BEGIN

            MENUITEM "&nil", IDM_V_SETMARGIN_0

            MENUITEM "&1 cm", IDM_V_SETMARGIN_1

            MENUITEM "&2 cm", IDM_V_SETMARGIN_2

            MENUITEM "&3 cm", IDM_V_SETMARGIN_3

            MENUITEM "&4 cm", IDM_V_SETMARGIN_4

          END

        POPUP "Add &Top Line"

  BEGIN

    MENUITEM "&1 cm", IDM_V_ADDTOP_1

    MENUITEM "&2 cm", IDM_V_ADDTOP_2

    MENUITEM "&3 cm", IDM_V_ADDTOP_3

    MENUITEM "&4 cm", IDM_V_ADDTOP_4

  END

  END

    POPUP  "&Line"

      BEGIN

        MENUITEM "&Add Line\t  Enter", IDM_L_ADDLINE

        MENUITEM "E&dit Line\t  Alt+Enter", IDM_L_EDITLINE

        MENUITEM SEPARATOR

        MENUITEM "&Indent Line\t  Tab", IDM_L_INDENTLINE

        MENUITEM "U&nindent Line\t  Shift+Tab", IDM_L_UNINDENTLINE

MENUITEM SEPARATOR

MENUITEM "&Set Line Height...", IDM_L_SETLINEHEIGHT

      END

    POPUP  "&Name"

      BEGIN

        MENUITEM "&Define Name...", IDM_N_DEFINENAME

        MENUITEM "&Goto Name...", IDM_N_GOTONAME

      END

    POPUP  "&Options"

      BEGIN

        POPUP  "&Button Bar Display"

          BEGIN

            MENUITEM "At &Top", IDM_O_BB_TOP

            MENUITEM "At &Bottom", IDM_O_BB_BOTTOM

            MENUITEM "&Popup", IDM_O_BB_POPUP

            MENUITEM "&Hide", IDM_O_BB_HIDE

          END

        POPUP  "&Formula Bar Display"

          BEGIN

            MENUITEM "At &Top", IDM_O_FB_TOP

            MENUITEM "At &Bottom", IDM_O_FB_BOTTOM

            MENUITEM "&Popup", IDM_O_FB_POPUP

          END

        POPUP  "&Row and Column Heading"

          BEGIN

            MENUITEM "&Show", IDM_O_HEAD_SHOW

            MENUITEM "&Hide", IDM_O_HEAD_HIDE

          END

      END

    POPUP  "DbgI&Svr"

      BEGIN

        MENUITEM "&Debug Level...", IDM_D_DEBUGLEVEL

        MENUITEM "Register Message &Filter", IDM_D_INSTALLMSGFILTER

        MENUITEM "&Reject Incoming Messages", IDM_D_REJECTINCOMING

      END

    POPUP  "&Help"

      BEGIN

        MENUITEM "&About...", IDM_H_ABOUT

      END

  END

SvrOutlAccel ACCELERATORS

  BEGIN

    VK_F12, IDM_F_OPEN, VIRTKEY, CONTROL

    VK_F12, IDM_F_SAVE, VIRTKEY, SHIFT

    VK_F12, IDM_F_SAVEAS, VIRTKEY

    VK_F12, IDM_F_PRINT, VIRTKEY, CONTROL, SHIFT

    "x", IDM_E_CUT, VIRTKEY, CONTROL

    "c", IDM_E_COPY, VIRTKEY, CONTROL

    "v", IDM_E_PASTE, VIRTKEY, CONTROL

    VK_DELETE, IDM_E_CLEAR, VIRTKEY

    VK_RETURN, IDM_L_ADDLINE, VIRTKEY

    VK_RETURN, IDM_L_EDITLINE, VIRTKEY, ALT

    VK_TAB, IDM_L_INDENTLINE, VIRTKEY

    VK_TAB, IDM_L_UNINDENTLINE, VIRTKEY, SHIFT

    "a", IDM_E_SELECTALL, VIRTKEY, CONTROL

    ; old conventions for editing

    VK_INSERT, IDM_E_COPY, VIRTKEY, CONTROL

    VK_DELETE, IDM_E_CUT, VIRTKEY, SHIFT

    VK_INSERT, IDM_E_PASTE, VIRTKEY, SHIFT

    VK_F2, IDM_F2, VIRTKEY

  END

; used when edit control of Formula Bar in focus

;

SvrOutlAccelFocusEdit ACCELERATORS

  BEGIN

    VK_F12, IDM_F_OPEN, VIRTKEY, CONTROL

    VK_F12, IDM_F_SAVE, VIRTKEY, SHIFT

    VK_F12, IDM_F_SAVEAS, VIRTKEY

    VK_F12, IDM_F_PRINT, VIRTKEY, CONTROL, SHIFT

    VK_RETURN, IDM_L_ADDLINE, VIRTKEY

    VK_RETURN, IDM_L_EDITLINE, VIRTKEY, ALT

VK_ESCAPE, IDM_ESCAPE, VIRTKEY

  END

InPlaceSvrOutlAccel ACCELERATORS

  BEGIN

    "x", IDM_E_CUT, VIRTKEY, CONTROL

    "c", IDM_E_COPY, VIRTKEY, CONTROL

    "v", IDM_E_PASTE, VIRTKEY, CONTROL

    VK_DELETE, IDM_E_CLEAR, VIRTKEY

    VK_RETURN, IDM_L_ADDLINE, VIRTKEY

    VK_RETURN, IDM_L_EDITLINE, VIRTKEY, ALT

    VK_TAB, IDM_L_INDENTLINE, VIRTKEY

    VK_TAB, IDM_L_UNINDENTLINE, VIRTKEY, SHIFT

    "a", IDM_E_SELECTALL, VIRTKEY, CONTROL

    ; old conventions for editing

    VK_INSERT, IDM_E_COPY, VIRTKEY, CONTROL

    VK_DELETE, IDM_E_CUT, VIRTKEY, SHIFT

    VK_INSERT, IDM_E_PASTE, VIRTKEY, SHIFT

    VK_F2, IDM_F2, VIRTKEY

VK_ESCAPE, IDM_ESCAPE, VIRTKEY

  END

; used when edit control of Formula Bar in focus

; REVIEW: currently not properly used

InPlaceSvrOutlAccelFocusEdit ACCELERATORS

  BEGIN

    VK_F12, IDM_F_OPEN, VIRTKEY, CONTROL

    VK_F12, IDM_F_SAVE, VIRTKEY, SHIFT

    VK_F12, IDM_F_SAVEAS, VIRTKEY

    VK_F12, IDM_F_PRINT, VIRTKEY, CONTROL, SHIFT

    VK_RETURN, IDM_L_ADDLINE, VIRTKEY

    VK_RETURN, IDM_L_EDITLINE, VIRTKEY, ALT

VK_ESCAPE, IDM_FB_CANCEL, VIRTKEY

  END

SvrOutlIcon ICON isvrotl.ico

Image72     BITMAP      image72.bmp

Image96     BITMAP      image96.bmp

Image120    BITMAP      image120.bmp

LogoBitmap  BITMAP      ole2.bmp

#include "DIALOGS.DLG"


ISVROTL.C  (OUTLINE Sample)

/*************************************************************************

**

**    OLE 2.0 Sample Code

**

**    precomp.c

**

**    This file is used to precompile the OUTLINE.H header file

**

**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

**

*************************************************************************/

#include "outline.h"


LINKING.C  (OUTLINE Sample)

/*************************************************************************

**

**    OLE 2 Sample Code

**

**    linking.c

**

**    This file contains the major interfaces, methods and related support

**    functions for implementing linking to items. The code

**    contained in this file is used by BOTH the Container and Server

**    (Object) versions of the Outline sample code.

**

**    As a server SVROUTL supports linking to the whole document object

**    (either a file-based document or as an embedded object). It also

**    supports linking to ranges (or PseudoObjects).

**

**    As a container CNTROUTL supports linking to embedded objects.

**    (see file svrpsobj.c for Pseudo Object implementation)

**

**    OleDoc Object

**      exposed interfaces:

**          IPersistFile

**          IOleItemContainer

**          IExternalConnection

**

**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

**

*************************************************************************/

#include "outline.h"

OLEDBGDATA

extern LPOUTLINEAPP             g_lpApp;

/*************************************************************************

** OleDoc::IPersistFile interface implementation

*************************************************************************/

// IPersistFile::QueryInterface

STDMETHODIMP OleDoc_PFile_QueryInterface(

      LPPERSISTFILE       lpThis,

      REFIID              riid,

      LPVOID FAR*         lplpvObj

)

{

   LPOLEDOC lpOleDoc = ((struct CDocPersistFileImpl FAR*)lpThis)->lpOleDoc;

   return OleDoc_QueryInterface(lpOleDoc, riid, lplpvObj);

}

// IPersistFile::AddRef

STDMETHODIMP_(ULONG) OleDoc_PFile_AddRef(LPPERSISTFILE lpThis)

{

   LPOLEDOC lpOleDoc = ((struct CDocPersistFileImpl FAR*)lpThis)->lpOleDoc;

   OleDbgAddRefMethod(lpThis, "IPersistFile");

   return OleDoc_AddRef(lpOleDoc);

}

// IPersistFile::Release

STDMETHODIMP_(ULONG) OleDoc_PFile_Release (LPPERSISTFILE lpThis)

{

   LPOLEDOC lpOleDoc = ((struct CDocPersistFileImpl FAR*)lpThis)->lpOleDoc;

   OleDbgReleaseMethod(lpThis, "IPersistFile");

   return OleDoc_Release(lpOleDoc);

}

// IPersistFile::GetClassID

STDMETHODIMP OleDoc_PFile_GetClassID (

      LPPERSISTFILE       lpThis,

      CLSID FAR*          lpclsid

)

{

   LPOLEDOC lpOleDoc = ((struct CDocPersistFileImpl FAR*)lpThis)->lpOleDoc;

   LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp;

   OleDbgOut2("OleDoc_PFile_GetClassID\r\n");

#if defined( OLE_SERVER ) && defined( SVR_TREATAS )

   /* OLE2NOTE: we must be carefull to return the correct CLSID here.

   **    if we are currently preforming a "TreatAs (aka. ActivateAs)"

   **    operation then we need to return the class of the object

   **    written in the storage of the object. otherwise we would

   **    return our own class id.

   */

   return ServerDoc_GetClassID((LPSERVERDOC)lpOleDoc, lpclsid);

#else

   *lpclsid = CLSID_APP;

#endif

   return NOERROR;

}

// IPersistFile::IsDirty

STDMETHODIMP  OleDoc_PFile_IsDirty(LPPERSISTFILE lpThis)

{

   LPOLEDOC lpOleDoc = ((struct CDocPersistFileImpl FAR*)lpThis)->lpOleDoc;

   OleDbgOut2("OleDoc_PFile_IsDirty\r\n");

   if (OutlineDoc_IsModified((LPOUTLINEDOC)lpOleDoc))

      return NOERROR;

   else

      return ResultFromScode(S_FALSE);

}

// IPersistFile::Load

STDMETHODIMP OleDoc_PFile_Load (

      LPPERSISTFILE       lpThis,

      LPCOLESTR           lpszFileName,

      DWORD               grfMode

)

{

   LPOLEDOC lpOleDoc = ((struct CDocPersistFileImpl FAR*)lpThis)->lpOleDoc;

   SCODE sc;

   OLEDBG_BEGIN2("OleDoc_PFile_Load\r\n")

   /* OLE2NOTE: grfMode passed from the caller indicates if the caller

   **    needs Read or ReadWrite permissions. if appropriate the

   **    callee should open the file with the requested permissions.

   **    the caller will normally not impose sharing permissions.

   **

   **    the sample code currently always opens its file ReadWrite.

   */

   if (OutlineDoc_LoadFromFile((LPOUTLINEDOC)lpOleDoc, (LPOLESTR)lpszFileName))

      sc = S_OK;

   else

      sc = E_FAIL;

   OLEDBG_END2

   return ResultFromScode(sc);

}

// IPersistFile::Save

STDMETHODIMP OleDoc_PFile_Save (

      LPPERSISTFILE       lpThis,

      LPCOLESTR           lpszFileName,

      BOOL                fRemember

)

{

   LPOLEDOC lpOleDoc = ((struct CDocPersistFileImpl FAR*)lpThis)->lpOleDoc;

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc;

   SCODE sc;

   OLEDBG_BEGIN2("OleDoc_PFile_Save\r\n")

   /* OLE2NOTE: it is only legal to perform a Save or SaveAs operation

   **    on a file-based document. if the document is an embedded

   **    object then we can not be changed to a file-base object.

   **

   **      fRemember   lpszFileName     Type of Save

   **    ----------------------------------------------

   **        TRUE        NULL           SAVE

   **        TRUE        ! NULL         SAVE AS

   **        FALSE       ! NULL         SAVE COPY AS

   **        FALSE       NULL           ***error***

   */

   if ( (lpszFileName==NULL || (lpszFileName != NULL && fRemember))

         && ((lpOutlineDoc->m_docInitType != DOCTYPE_FROMFILE

            && lpOutlineDoc->m_docInitType != DOCTYPE_NEW)) ) {

      OLEDBG_END2

      return ResultFromScode(E_INVALIDARG);

   }

   if (OutlineDoc_SaveToFile(

         (LPOUTLINEDOC)lpOleDoc,

         lpszFileName,

         lpOutlineDoc->m_cfSaveFormat,

         fRemember)) {

      sc = S_OK;

   } else

      sc = E_FAIL;

   OLEDBG_END2

   return ResultFromScode(sc);

}

// IPersistFile::SaveCompleted

STDMETHODIMP OleDoc_PFile_SaveCompleted (

      LPPERSISTFILE       lpThis,

      LPCOLESTR           lpszFileName

)

{

   LPOLEDOC lpOleDoc = ((struct CDocPersistFileImpl FAR*)lpThis)->lpOleDoc;

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc;

   OleDbgOut2("OleDoc_PFile_SaveCompleted\r\n");

   /* This method is called after IPersistFile::Save is called. during

   **    the period between Save and SaveCompleted the object must

   **    consider itself in NOSCRIBBLE mode (ie. it is NOT allowed to

   **    write to its file. here the object can clear its NOSCRIBBLE

   **    mode flag. the outline app never scribbles to its storage, so

   **    we have nothing to do.

   */

   return NOERROR;

}

// IPersistFile::GetCurFile

STDMETHODIMP OleDoc_PFile_GetCurFile (

      LPPERSISTFILE   lpThis,

      LPOLESTR FAR*   lplpszFileName

)

{

   LPOLEDOC lpOleDoc = ((struct CDocPersistFileImpl FAR*)lpThis)->lpOleDoc;

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc;

   LPMALLOC lpMalloc;

   LPOLESTR lpsz;

   SCODE sc;

   char  szAnsiStr[256];

   OleDbgOut2("OleDoc_PFile_GetCurFile\r\n");

   /* OLE2NOTE: we must make sure to set all out ptr parameters to NULL. */

   *lplpszFileName = NULL;

   /*********************************************************************

   ** OLE2NOTE: memory returned for the lplpszFileName must be

   **    allocated appropriately using the current registered IMalloc

   **    interface. the allows the ownership of the memory to be

   **    passed to the caller (even if in another process).

   *********************************************************************/

   CoGetMalloc(MEMCTX_TASK, &lpMalloc);

   if (! lpMalloc) {

      return ResultFromScode(E_FAIL);

   }

   if (lpOutlineDoc->m_docInitType == DOCTYPE_FROMFILE) {

      /* valid filename associated; return file name */

      lpsz = (LPOLESTR)lpMalloc->lpVtbl->Alloc(

            lpMalloc,

            (OLESTRLEN(lpOutlineDoc->m_szFileName)+1)*sizeof(OLECHAR)

      );

      if (! lpsz) {

         sc = E_OUTOFMEMORY;

         goto error;

      }

      OLESTRCPY(lpsz, (LPOLESTR)lpOutlineDoc->m_szFileName);

      sc = S_OK;

   } else {

      /* no file associated; return default file name prompt */

      lpsz=(LPOLESTR)lpMalloc->lpVtbl->Alloc(lpMalloc, (lstrlen(DEFEXTENSION)+3)*sizeof(OLECHAR));

      wsprintf(szAnsiStr, "*.%s", DEFEXTENSION);

      A2W (szAnsiStr, lpsz, OLEUI_CCHPATHMAX);

      sc = S_FALSE;

   }

error:

   OleStdRelease((LPUNKNOWN)lpMalloc);

   *lplpszFileName = lpsz;

   return ResultFromScode(sc);

}

/*************************************************************************

** OleDoc::IOleItemContainer interface implementation

*************************************************************************/

// IOleItemContainer::QueryInterface

STDMETHODIMP OleDoc_ItemCont_QueryInterface(

      LPOLEITEMCONTAINER  lpThis,

      REFIID              riid,

      LPVOID FAR*         lplpvObj

)

{

   LPOLEDOC lpOleDoc =

         ((struct CDocOleItemContainerImpl FAR*)lpThis)->lpOleDoc;

   return OleDoc_QueryInterface(lpOleDoc, riid, lplpvObj);

}

// IOleItemContainer::AddRef

STDMETHODIMP_(ULONG) OleDoc_ItemCont_AddRef(LPOLEITEMCONTAINER lpThis)

{

   LPOLEDOC lpOleDoc =

         ((struct CDocOleItemContainerImpl FAR*)lpThis)->lpOleDoc;

   OleDbgAddRefMethod(lpThis, "IOleItemContainer");

   return OleDoc_AddRef((LPOLEDOC)lpOleDoc);

}

// IOleItemContainer::Release

STDMETHODIMP_(ULONG) OleDoc_ItemCont_Release(LPOLEITEMCONTAINER lpThis)

{

   LPOLEDOC lpOleDoc =

         ((struct CDocOleItemContainerImpl FAR*)lpThis)->lpOleDoc;

   OleDbgReleaseMethod(lpThis, "IOleItemContainer");

   return OleDoc_Release((LPOLEDOC)lpOleDoc);

}

// IOleItemContainer::ParseDisplayName

STDMETHODIMP OleDoc_ItemCont_ParseDisplayName(

      LPOLEITEMCONTAINER  lpThis,

      LPBC                lpbc,

      LPOLESTR            lpszDisplayName,

      ULONG FAR*          lpchEaten,

      LPMONIKER FAR*      lplpmkOut

)

{

   LPOLEDOC lpOleDoc =

         ((struct CDocOleItemContainerImpl FAR*)lpThis)->lpOleDoc;

   OLECHAR szItemName[MAXNAMESIZE];

   LPUNKNOWN lpUnk;

   HRESULT hrErr;

   OleDbgOut2("OleDoc_ItemCont_ParseDisplayName\r\n");

   /* OLE2NOTE: we must make sure to set all out ptr parameters to NULL. */

   *lplpmkOut = NULL;

   *lpchEaten = OleStdGetItemToken(

         lpszDisplayName,

         szItemName,

         MAXNAMESIZE*sizeof(OLECHAR)

   );

   /* OLE2NOTE: get a pointer to a running instance of the object. we

   **    should force the object to go running if necessary (even if

   **    this means launching its server EXE). this is the meaining of

   **    BINDSPEED_INDEFINITE. Parsing a Moniker is known to be an

   **    "EXPENSIVE" operation.

   */

   hrErr = OleDoc_ItemCont_GetObject(

         lpThis,

         szItemName,

         BINDSPEED_INDEFINITE,

         lpbc,

         &IID_IUnknown,

         (LPVOID FAR*)&lpUnk

   );

   if (hrErr == NOERROR) {

      OleStdRelease(lpUnk);   // item name FOUND; don't need obj ptr.

      CreateItemMoniker(OLESTDDELIM, szItemName, lplpmkOut);

   } else

      *lpchEaten = 0;     // item name is NOT valid

   return hrErr;

}

// IOleItemContainer::EnumObjects

STDMETHODIMP OleDoc_ItemCont_EnumObjects(

      LPOLEITEMCONTAINER  lpThis,

      DWORD               grfFlags,

      LPENUMUNKNOWN FAR*  lplpenumUnknown

)

{

   LPOLEDOC lpOleDoc =

         ((struct CDocOleItemContainerImpl FAR*)lpThis)->lpOleDoc;

   OLEDBG_BEGIN2("OleDoc_ItemCont_EnumObjects\r\n")

   /* OLE2NOTE: we must make sure to set all out ptr parameters to NULL. */

   *lplpenumUnknown = NULL;

   /* OLE2NOTE: this method should be implemented to allow programatic

   **    clients the ability to what elements the container holds.

   **    this method is NOT called in the standard linking scenarios.

   **

   **    grfFlags can be one of the following:

   **        OLECONTF_EMBEDDINGS   -- enumerate embedded objects

   **        OLECONTF_LINKS        -- enumerate linked objects

   **        OLECONTF_OTHERS       -- enumerate non-OLE compound doc objs

   **        OLECONTF_ONLYUSER     -- enumerate only objs named by user

   **        OLECONTF_ONLYIFRUNNING-- enumerate only objs in running state

   */

   OleDbgAssertSz(0, "NOT YET IMPLEMENTED!");

   OLEDBG_END2

   return ResultFromScode(E_NOTIMPL);

}

// IOleItemContainer::LockContainer

STDMETHODIMP OleDoc_ItemCont_LockContainer(

      LPOLEITEMCONTAINER  lpThis,

      BOOL                fLock

)

{

   LPOLEDOC lpOleDoc =

         ((struct CDocOleItemContainerImpl FAR*)lpThis)->lpOleDoc;

   HRESULT hrErr;

   OLEDBG_BEGIN2("OleDoc_ItemCont_LockContainer\r\n")

#if defined( _DEBUG )

   if (fLock) {

      ++lpOleDoc->m_cCntrLock;

      OleDbgOutRefCnt3(

            "OleDoc_ItemCont_LockContainer: cLock++\r\n",

            lpOleDoc,

            lpOleDoc->m_cCntrLock

      );

   } else {

      /* OLE2NOTE: when there are no open documents and the app is not

      **    under the control of the user and there are no outstanding

      **    locks on the app, then revoke our ClassFactory to enable the

      **    app to shut down.

      */

      --lpOleDoc->m_cCntrLock;

      OleDbgAssertSz (

            lpOleDoc->m_cCntrLock >= 0,

            "OleDoc_ItemCont_LockContainer(FALSE) called with cLock == 0"

      );

      if (lpOleDoc->m_cCntrLock == 0) {

         OleDbgOutRefCnt2(

               "OleDoc_ItemCont_LockContainer: UNLOCKED\r\n",

               lpOleDoc, lpOleDoc->m_cCntrLock);

      } else {

         OleDbgOutRefCnt3(

               "OleDoc_ItemCont_LockContainer: cLock--\r\n",

               lpOleDoc, lpOleDoc->m_cCntrLock);

      }

   }

#endif  // _DEBUG

   /* OLE2NOTE: in order to hold the document alive we call

   **    CoLockObjectExternal to add a strong reference to our Doc

   **    object. this will keep the Doc alive when all other external

   **    references release us. whenever an embedded object goes

   **    running a LockContainer(TRUE) is called. when the embedded

   **    object shuts down (ie. transitions from running to loaded)

   **    LockContainer(FALSE) is called. if the user issues File.Close

   **    the document will shut down in any case ignoring any

   **    outstanding LockContainer locks because CoDisconnectObject is

   **    called in OleDoc_Close. this will forceably break any

   **    existing strong reference counts including counts that we add

   **    ourselves by calling CoLockObjectExternal and guarantee that

   **    the Doc object gets its final release (ie. cRefs goes to 0).

   */

   hrErr = OleDoc_Lock(lpOleDoc, fLock, TRUE /* fLastUnlockReleases */);

   OLEDBG_END2

   return hrErr;

}

// IOleItemContainer::GetObject

STDMETHODIMP OleDoc_ItemCont_GetObject(

      LPOLEITEMCONTAINER  lpThis,

      LPOLESTR            lpszItem,

      DWORD               dwSpeedNeeded,

      LPBINDCTX           lpbc,

      REFIID              riid,

      LPVOID FAR*         lplpvObject

)

{

   LPOLEDOC lpOleDoc =

         ((struct CDocOleItemContainerImpl FAR*)lpThis)->lpOleDoc;

   HRESULT hrErr;

   OLEDBG_BEGIN2("OleDoc_ItemCont_GetObject\r\n")

   /* OLE2NOTE: we must make sure to set all out ptr parameters to NULL. */

   *lplpvObject = NULL;

#if defined( OLE_SERVER )

   /* OLE2NOTE: SERVER ONLY version should return PseudoObjects with

   **    BINDSPEED_IMMEDIATE, thus the dwSpeedNeeded is not important

   **    in the case of a pure server.

   */

   hrErr = ServerDoc_GetObject(

         (LPSERVERDOC)lpOleDoc, lpszItem,riid,lplpvObject);

#endif

#if defined( OLE_CNTR )

   /* OLE2NOTE: dwSpeedNeeded indicates how long the caller is willing

   **    to wait for us to get the object:

   **      BINDSPEED_IMMEDIATE -- only if obj already loaded && IsRunning

   **      BINDSPEED_MODERATE  -- load obj if necessary && if IsRunning

   **      BINDSPEED_INDEFINITE-- force obj to load and run if necessary

   */

   hrErr = ContainerDoc_GetObject(

         (LPCONTAINERDOC)lpOleDoc,lpszItem,dwSpeedNeeded,riid,lplpvObject);

#endif

   OLEDBG_END2

   return hrErr;

}

// IOleItemContainer::GetObjectStorage

STDMETHODIMP OleDoc_ItemCont_GetObjectStorage(

      LPOLEITEMCONTAINER  lpThis,

      LPOLESTR            lpszItem,

      LPBINDCTX           lpbc,

      REFIID              riid,

      LPVOID FAR*         lplpvStorage

)

{

   LPOLEDOC lpOleDoc =

         ((struct CDocOleItemContainerImpl FAR*)lpThis)->lpOleDoc;

   OleDbgOut2("OleDoc_ItemCont_GetObjectStorage\r\n");

   /* OLE2NOTE: we must make sure to set all out ptr parameters to NULL. */

   *lplpvStorage = NULL;

#if defined( OLE_SERVER )

   /* OLE2NOTE: in the SERVER ONLY version, item names identify pseudo

   **    objects. pseudo objects, do NOT have identifiable storage.

   */

   return ResultFromScode(E_FAIL);

#endif

#if defined( OLE_CNTR )

   // We can only return an IStorage* type pointer

   if (! IsEqualIID(riid, &IID_IStorage))

   {

      return ResultFromScode(E_FAIL);

   }

   return ContainerDoc_GetObjectStorage(

         (LPCONTAINERDOC)lpOleDoc,

         lpszItem,

         (LPSTORAGE FAR*)lplpvStorage

   );

#endif

}

// IOleItemContainer::IsRunning

STDMETHODIMP OleDoc_ItemCont_IsRunning(

      LPOLEITEMCONTAINER  lpThis,

      LPOLESTR            lpszItem

)

{

   LPOLEDOC lpOleDoc =

         ((struct CDocOleItemContainerImpl FAR*)lpThis)->lpOleDoc;

   HRESULT hrErr;

   OLEDBG_BEGIN2("OleDoc_ItemCont_IsRunning\r\n")

   /* OLE2NOTE: Check if item name is valid. if so then return if

   **    Object is running. PseudoObjects in the Server version are

   **    always considered running. Ole objects in the container must

   **    be checked if they are running.

   */

#if defined( OLE_SERVER )

   hrErr = ServerDoc_IsRunning((LPSERVERDOC)lpOleDoc, lpszItem);

#endif

#if defined( OLE_CNTR )

   hrErr = ContainerDoc_IsRunning((LPCONTAINERDOC)lpOleDoc, lpszItem);

#endif

   OLEDBG_END2

   return hrErr;

}

/*************************************************************************

** OleDoc::IExternalConnection interface implementation

*************************************************************************/

// IExternalConnection::QueryInterface

STDMETHODIMP OleDoc_ExtConn_QueryInterface(

      LPEXTERNALCONNECTION    lpThis,

      REFIID                  riid,

      LPVOID FAR*             lplpvObj

)

{

   LPOLEDOC lpOleDoc =

         ((struct CDocExternalConnectionImpl FAR*)lpThis)->lpOleDoc;

   return OleDoc_QueryInterface(lpOleDoc, riid, lplpvObj);

}

// IExternalConnection::AddRef

STDMETHODIMP_(ULONG) OleDoc_ExtConn_AddRef(LPEXTERNALCONNECTION lpThis)

{

   LPOLEDOC lpOleDoc =

         ((struct CDocExternalConnectionImpl FAR*)lpThis)->lpOleDoc;

   OleDbgAddRefMethod(lpThis, "IExternalConnection");

   return OleDoc_AddRef(lpOleDoc);

}

// IExternalConnection::Release

STDMETHODIMP_(ULONG) OleDoc_ExtConn_Release (LPEXTERNALCONNECTION lpThis)

{

   LPOLEDOC lpOleDoc =

         ((struct CDocExternalConnectionImpl FAR*)lpThis)->lpOleDoc;

   OleDbgReleaseMethod(lpThis, "IExternalConnection");

   return OleDoc_Release(lpOleDoc);

}

// IExternalConnection::AddConnection

STDMETHODIMP_(DWORD) OleDoc_ExtConn_AddConnection(

      LPEXTERNALCONNECTION    lpThis,

      DWORD                   extconn,

      DWORD                   reserved

)

{

   LPOLEDOC lpOleDoc =

         ((struct CDocExternalConnectionImpl FAR*)lpThis)->lpOleDoc;

   if( extconn & EXTCONN_STRONG ) {

#if defined( _DEBUG )

      OleDbgOutRefCnt3(

            "OleDoc_ExtConn_AddConnection: dwStrongExtConn++\r\n",

            lpOleDoc,

            lpOleDoc->m_dwStrongExtConn + 1

      );

#endif

      return ++(lpOleDoc->m_dwStrongExtConn);

   } else

   {

      return 0;

   }

}

// IExternalConnection::ReleaseConnection

STDMETHODIMP_(DWORD) OleDoc_ExtConn_ReleaseConnection(

      LPEXTERNALCONNECTION    lpThis,

      DWORD                   extconn,

      DWORD                   reserved,

      BOOL                    fLastReleaseCloses

)

{

   LPOLEDOC lpOleDoc =

         ((struct CDocExternalConnectionImpl FAR*)lpThis)->lpOleDoc;

   if( extconn & EXTCONN_STRONG ){

      DWORD dwSave = --(lpOleDoc->m_dwStrongExtConn);

#if defined( _DEBUG )

      OLEDBG_BEGIN2( (fLastReleaseCloses ?

                  "OleDoc_ExtConn_ReleaseConnection(TRUE)\r\n" :

                  "OleDoc_ExtConn_ReleaseConnection(FALSE)\r\n") )

      OleDbgOutRefCnt3(

            "OleDoc_ExtConn_ReleaseConnection: dwStrongExtConn--\r\n",

            lpOleDoc,

            lpOleDoc->m_dwStrongExtConn

      );

      OleDbgAssertSz (

            lpOleDoc->m_dwStrongExtConn >= 0,

            "OleDoc_ExtConn_ReleaseConnection called with dwStrong == 0"

      );

#endif  // _DEBUG

      if( lpOleDoc->m_dwStrongExtConn == 0 && fLastReleaseCloses )

         OleDoc_Close(lpOleDoc, OLECLOSE_SAVEIFDIRTY);

      OLEDBG_END2

      return dwSave;

   } else

   {

      return 0;

   }

}

/*************************************************************************

** OleDoc Common Support Functions

*************************************************************************/

/* OleDoc_GetFullMoniker

** ---------------------

**    Return the full, absolute moniker of the document.

**

**    NOTE: the caller must release the pointer returned when done.

*/

LPMONIKER OleDoc_GetFullMoniker(LPOLEDOC lpOleDoc, DWORD dwAssign)

{

   LPMONIKER lpMoniker = NULL;

   OLEDBG_BEGIN3("OleDoc_GetFullMoniker\r\n")

   if (lpOleDoc->m_lpSrcDocOfCopy) {

      /* CASE I: this document was created for a copy or drag/drop

      **    operation. generate the moniker which identifies the

      **    source document of the original copy.

      */

      if (! lpOleDoc->m_fLinkSourceAvail)

         goto done;        // we already know a moniker is not available

      lpMoniker=OleDoc_GetFullMoniker(lpOleDoc->m_lpSrcDocOfCopy, dwAssign);

   }

   else if (lpOleDoc->m_lpFileMoniker) {

      /* CASE II: this document is a top-level user document (either

      **    file-based or untitled). return the FileMoniker stored

      **    with the document; it uniquely identifies the document.

      */

      // we must AddRef the moniker to pass out a ptr

      lpOleDoc->m_lpFileMoniker->lpVtbl->AddRef(lpOleDoc->m_lpFileMoniker);

      lpMoniker = lpOleDoc->m_lpFileMoniker;

   }

#if defined( OLE_SERVER )

   else if (((LPSERVERDOC)lpOleDoc)->m_lpOleClientSite) {

      /* CASE III: this document is an embedded object, ask our

      **    container for our moniker.

      */

      OLEDBG_BEGIN2("IOleClientSite::GetMoniker called\r\n");

      ((LPSERVERDOC)lpOleDoc)->m_lpOleClientSite->lpVtbl->GetMoniker(

            ((LPSERVERDOC)lpOleDoc)->m_lpOleClientSite,

            dwAssign,

            OLEWHICHMK_OBJFULL,

            &lpMoniker

      );

      OLEDBG_END2

   }

#endif

   else {

      lpMoniker = NULL;

   }

done:

   OLEDBG_END3

   return lpMoniker;

}

/* OleDoc_DocRenamedUpdate

** -----------------------

**    Update the documents registration in the running object table (ROT).

**    Also inform all embedded OLE objects (container only) and/or psedudo

**    objects (server only) that the name of the document has changed.

*/

void OleDoc_DocRenamedUpdate(LPOLEDOC lpOleDoc, LPMONIKER lpmkDoc)

{

   OLEDBG_BEGIN3("OleDoc_DocRenamedUpdate\r\n")

   OleDoc_AddRef(lpOleDoc);

   /* OLE2NOTE: we must re-register ourselves as running when we

   **    get a new moniker assigned (ie. when we are renamed).

   */

   OLEDBG_BEGIN3("OleStdRegisterAsRunning called\r\n")

   OleStdRegisterAsRunning(

         (LPUNKNOWN)&lpOleDoc->m_Unknown,

         lpmkDoc,

         &lpOleDoc->m_dwRegROT

   );

   OLEDBG_END3

#if defined( OLE_SERVER )

   {

      LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOleDoc;

      LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc;

      /* OLE2NOTE: inform any linking clients that the document has been

      **    renamed.

      */

      ServerDoc_SendAdvise (

            lpServerDoc,

            OLE_ONRENAME,

            lpmkDoc,

            0        /* advf -- not relevant here */

      );

      /* OLE2NOTE: inform any clients of pseudo objects

      **    within our document, that our document's

      **    Moniker has changed.

      */

      ServerNameTable_InformAllPseudoObjectsDocRenamed(

            (LPSERVERNAMETABLE)lpOutlineDoc->m_lpNameTable, lpmkDoc);

   }

#endif

#if defined( OLE_CNTR )

   {

      LPCONTAINERDOC lpContainerDoc = (LPCONTAINERDOC)lpOleDoc;

      /* OLE2NOTE: must tell all OLE objects that our container

      **    moniker changed.

      */

      ContainerDoc_InformAllOleObjectsDocRenamed(

            lpContainerDoc,

            lpmkDoc

      );

   }

#endif

   OleDoc_Release(lpOleDoc);       // release artificial AddRef above

   OLEDBG_END3

}

#if defined( OLE_SERVER )

/*************************************************************************

** ServerDoc Supprt Functions Used by Server versions

*************************************************************************/

/* ServerDoc_PseudoObjLockDoc

** --------------------------

**    Add a lock on the Doc on behalf of the PseudoObject. the Doc may not

**    close while the Doc exists.

**

**    when a pseudo object is first created, it calls this method to

**    guarantee that the document stays alive (PseudoObj_Init).

**    when a pseudo object is destroyed, it call

**    ServerDoc_PseudoObjUnlockDoc to release this hold on the document.

*/

void ServerDoc_PseudoObjLockDoc(LPSERVERDOC lpServerDoc)

{

   LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc;

   ULONG cPseudoObj;

   cPseudoObj = ++lpServerDoc->m_cPseudoObj;

#if defined( _DEBUG )

   OleDbgOutRefCnt3(

         "ServerDoc_PseudoObjLockDoc: cPseudoObj++\r\n",

         lpServerDoc,

         cPseudoObj

   );

#endif

   OleDoc_Lock(lpOleDoc, TRUE /* fLock */, 0 /* not applicable */);

   return;

}

/* ServerDoc_PseudoObjUnlockDoc

** ----------------------------

**    Release the lock on the Doc on behalf of the PseudoObject. if this was

**    the last lock on the Doc, then it will shutdown.

*/

void ServerDoc_PseudoObjUnlockDoc(

      LPSERVERDOC         lpServerDoc,

      LPPSEUDOOBJ         lpPseudoObj

)

{

   ULONG cPseudoObj;

   LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc;

   OLEDBG_BEGIN3("ServerDoc_PseudoObjUnlockDoc\r\n")

   /* OLE2NOTE: when there are no active pseudo objects in the Doc and

   **    the Doc is not visible, and if there are no outstanding locks

   **    on the Doc, then this is a "silent update"

   **    situation. our Doc is being used programatically by some

   **    client; it is NOT accessible to the user because it is

   **    NOT visible. thus since all Locks have been released, we

   **    will close the document. if the app is only running due

   **    to the presence of this document, then the app will now

   **    also shut down.

   */

   cPseudoObj = --lpServerDoc->m_cPseudoObj;

#if defined( _DEBUG )

   OleDbgAssertSz (

         lpServerDoc->m_cPseudoObj >= 0,

         "PseudoObjUnlockDoc called with cPseudoObj == 0"

   );

   OleDbgOutRefCnt3(

         "ServerDoc_PseudoObjUnlockDoc: cPseudoObj--\r\n",

         lpServerDoc,

         cPseudoObj

   );

#endif

   OleDoc_Lock(lpOleDoc, FALSE /* fLock */, TRUE /* fLastUnlockReleases */);

   OLEDBG_END3

   return;

}

/* ServerDoc_GetObject

** -------------------

**

**    Return a pointer to an object identified by an item string

**    (lpszItem). For a server-only app, the object returned will be a

**    pseudo object.

*/

HRESULT ServerDoc_GetObject(

      LPSERVERDOC             lpServerDoc,

      LPOLESTR                lpszItem,

      REFIID                  riid,

      LPVOID FAR*             lplpvObject

)

{

   LPPSEUDOOBJ lpPseudoObj;

   LPSERVERNAMETABLE lpServerNameTable =

         (LPSERVERNAMETABLE)((LPOUTLINEDOC)lpServerDoc)->m_lpNameTable;

   *lplpvObject = NULL;

   /* Get the PseudoObj which corresponds to an item name. if the item

   **    name does NOT exist in the name table then NO object is

   **    returned. the ServerNameTable_GetPseudoObj routine finds a

   **    name entry corresponding to the item name, it then checks if

   **    a PseudoObj has already been allocated. if so, it returns the

   **    existing object, otherwise it allocates a new PseudoObj.

   */

   lpPseudoObj = ServerNameTable_GetPseudoObj(

         lpServerNameTable,

         lpszItem,

         lpServerDoc

   );

   if (! lpPseudoObj) {

      *lplpvObject = NULL;

      return ResultFromScode(MK_E_NOOBJECT);

   }

   // return the desired interface pointer of the pseudo object.

   return PseudoObj_QueryInterface(lpPseudoObj, riid, lplpvObject);

}

/* ServerDoc_IsRunning

** -------------------

**

**    Check if the object identified by an item string (lpszItem) is in

**    the running state. For a server-only app, if the item name exists in

**    in the NameTable then the item name is considered running.

**    IOleItemContainer::GetObject would succeed.

*/

HRESULT ServerDoc_IsRunning(LPSERVERDOC lpServerDoc, LPOLESTR lpszItem)

{

   LPOUTLINENAMETABLE lpOutlineNameTable =

         ((LPOUTLINEDOC)lpServerDoc)->m_lpNameTable;

   LPSERVERNAME lpServerName;

   lpServerName = (LPSERVERNAME)OutlineNameTable_FindName(

         lpOutlineNameTable,

         lpszItem

   );

   if (lpServerName)

      return NOERROR;

   else

      return ResultFromScode(MK_E_NOOBJECT);

}

/* ServerDoc_GetSelRelMoniker

** --------------------------

**    Retrieve the relative item moniker which identifies the given

**    selection (lplrSel).

**

**    Returns NULL if a moniker can NOT be created.

*/

LPMONIKER ServerDoc_GetSelRelMoniker(

      LPSERVERDOC             lpServerDoc,

      LPLINERANGE             lplrSel,

      DWORD                   dwAssign

)

{

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;

   LPSERVERNAMETABLE lpServerNameTable =

         (LPSERVERNAMETABLE)lpOutlineDoc->m_lpNameTable;

   LPOUTLINENAMETABLE lpOutlineNameTable =

         (LPOUTLINENAMETABLE)lpServerNameTable;

   LPOUTLINENAME lpOutlineName;

   LPMONIKER lpmk;

   lpOutlineName=OutlineNameTable_FindNamedRange(lpOutlineNameTable,lplrSel);

   if (lpOutlineName) {

      /* the selection range already has a name assigned */

      CreateItemMoniker(OLESTDDELIM, lpOutlineName->m_szName, &lpmk);

   } else {

      char szbuf[MAXNAMESIZE];

      OLECHAR szUniBuf[MAXNAMESIZE];

      switch (dwAssign) {

         case GETMONIKER_FORCEASSIGN:

            /* Force the assignment of the name. This is called when a

            **    Paste Link actually occurs. At this point we want to

            **    create a Name and add it to the NameTable in order to

            **    track the source of the link. This name (as all

            **    names) will be updated upon editing of the document.

            */

            wsprintf(

                  szbuf,

                  "%s %ld",

                  (LPSTR)DEFRANGENAMEPREFIX,

                  ++(lpServerDoc->m_nNextRangeNo)

            );

            lpOutlineName = OutlineApp_CreateName(lpOutlineApp);

            if (lpOutlineName) {

               A2W (szbuf, lpOutlineName->m_szName, OLEUI_CCHPATHMAX);

               lpOutlineName->m_nStartLine = lplrSel->m_nStartLine;

               lpOutlineName->m_nEndLine = lplrSel->m_nEndLine;

               OutlineDoc_AddName(lpOutlineDoc, lpOutlineName);

            } else {

               // REVIEW: do we need "Out-of-Memory" error message here?

            }

            break;

         case GETMONIKER_TEMPFORUSER:

            /* Create a name to show to the user in the Paste

            **    Special dialog but do NOT yet incur the overhead

            **    of adding a Name to the NameTable. The Moniker

            **    generated should be useful to display to the user

            **    to indicate the source of the copy, but will NOT

            **    be used to create a link directly (the caller

            **    should ask again for a moniker specifying FORCEASSIGN).

            **    we will generate the name that would be the next

            **    auto-generated range name, BUT will NOT actually

            **    increment the range counter.

            */

            wsprintf(

                  szbuf,

                  "%s %ld",

                  (LPSTR)DEFRANGENAMEPREFIX,

                  (lpServerDoc->m_nNextRangeNo)+1

            );

            break;

         case GETMONIKER_ONLYIFTHERE:

            /* the caller only wants a name if one has already been

            **    assigned. we have already above checked if the

            **    current selection has a name, so we will simply

            **    return NULL here.

            */

            return NULL;    // no moniker is assigned

         default:

            return NULL;    // unknown flag given

      }

      A2W (szbuf, szUniBuf, MAXNAMESIZE);

      CreateItemMoniker(OLESTDDELIM, szUniBuf, &lpmk);

   }

   return lpmk;

}

/* ServerDoc_GetSelFullMoniker

** ---------------------------

**    Retrieve the full absolute moniker which identifies the given

**    selection (lplrSel).

**    this moniker is created as a composite of the absolute moniker for

**    the entire document appended with an item moniker which identifies

**    the selection relative to the document.

**    Returns NULL if a moniker can NOT be created.

*/

LPMONIKER ServerDoc_GetSelFullMoniker(

      LPSERVERDOC             lpServerDoc,

      LPLINERANGE             lplrSel,

      DWORD                   dwAssign

)

{

   LPMONIKER lpmkDoc = NULL;

   LPMONIKER lpmkItem = NULL;

   LPMONIKER lpmkFull = NULL;

   lpmkDoc = OleDoc_GetFullMoniker(

         (LPOLEDOC)lpServerDoc,

         dwAssign

   );

   if (! lpmkDoc) return NULL;

   lpmkItem = ServerDoc_GetSelRelMoniker(

         lpServerDoc,

         lplrSel,

         dwAssign

   );

   if (lpmkItem) {

      CreateGenericComposite(lpmkDoc, lpmkItem, (LPMONIKER FAR*)&lpmkFull);

      OleStdRelease((LPUNKNOWN)lpmkItem);

   }

   if (lpmkDoc)

      OleStdRelease((LPUNKNOWN)lpmkDoc);

   return lpmkFull;

}

/* ServerNameTable_EditLineUpdate

 * -------------------------------

 *

 *      Update the table when a line at nEditIndex is edited.

 */

void ServerNameTable_EditLineUpdate(

      LPSERVERNAMETABLE       lpServerNameTable,

      int                     nEditIndex

)

{

   LPOUTLINENAMETABLE lpOutlineNameTable =

                              (LPOUTLINENAMETABLE)lpServerNameTable;

   LPOUTLINENAME lpOutlineName;

   LINERANGE lrSel;

   LPPSEUDOOBJ lpPseudoObj;

   int i;

   for(i = 0; i < lpOutlineNameTable->m_nCount; i++) {

      lpOutlineName=OutlineNameTable_GetName(lpOutlineNameTable, i);

      lpPseudoObj = ((LPSERVERNAME)lpOutlineName)->m_lpPseudoObj;

      /* if there is a pseudo object associated with this name, then

      **    check if the line that was modified is included within

      **    the named range.

      */

      if (lpPseudoObj) {

         OutlineName_GetSel(lpOutlineName, &lrSel);

         if(((int)lrSel.m_nStartLine <= nEditIndex) &&

            ((int)lrSel.m_nEndLine >= nEditIndex)) {

            // inform linking clients data has changed

            PseudoObj_SendAdvise(

                  lpPseudoObj,

                  OLE_ONDATACHANGE,

                  NULL,   /* lpmkDoc -- not relevant here */

                  0       /* advf -- no flags necessary */

            );

         }

      }

   }

}

/* ServerNameTable_InformAllPseudoObjectsDocRenamed

 * ------------------------------------------------

 *

 *      Inform all pseudo object clients that the name of the pseudo

 *      object has changed.

 */

void ServerNameTable_InformAllPseudoObjectsDocRenamed(

      LPSERVERNAMETABLE       lpServerNameTable,

      LPMONIKER               lpmkDoc

)

{

   LPOUTLINENAMETABLE lpOutlineNameTable =

                              (LPOUTLINENAMETABLE)lpServerNameTable;

   LPOUTLINENAME lpOutlineName;

   LPPSEUDOOBJ lpPseudoObj;

   LPMONIKER lpmkObj;

   int i;

   OLEDBG_BEGIN2("ServerNameTable_InformAllPseudoObjectsDocRenamed\r\n");

   for(i = 0; i < lpOutlineNameTable->m_nCount; i++) {

      lpOutlineName=OutlineNameTable_GetName(lpOutlineNameTable, i);

      lpPseudoObj = ((LPSERVERNAME)lpOutlineName)->m_lpPseudoObj;

      /* if there is a pseudo object associated with this name, then

      **    send OnRename advise to its linking clients.

      */

      if (lpPseudoObj &&

         ((lpmkObj=PseudoObj_GetFullMoniker(lpPseudoObj,lpmkDoc))!=NULL)) {

         // inform the clients that the name has changed

         PseudoObj_SendAdvise (

               lpPseudoObj,

               OLE_ONRENAME,

               lpmkObj,

               0           /* advf -- not relevant here */

         );

      }

   }

   OLEDBG_END2

}

/* ServerNameTable_InformAllPseudoObjectsDocSaved

 * ------------------------------------------------

 *

 *      Inform all pseudo object clients that the name of the pseudo

 *      object has changed.

 */

void ServerNameTable_InformAllPseudoObjectsDocSaved(

      LPSERVERNAMETABLE       lpServerNameTable,

      LPMONIKER               lpmkDoc

)

{

   LPOUTLINENAMETABLE lpOutlineNameTable =

                              (LPOUTLINENAMETABLE)lpServerNameTable;

   LPOUTLINENAME lpOutlineName;

   LPPSEUDOOBJ lpPseudoObj;

   LPMONIKER lpmkObj;

   int i;

   OLEDBG_BEGIN2("ServerNameTable_InformAllPseudoObjectsDocSaved\r\n");

   for(i = 0; i < lpOutlineNameTable->m_nCount; i++) {

      lpOutlineName=OutlineNameTable_GetName(lpOutlineNameTable, i);

      lpPseudoObj = ((LPSERVERNAME)lpOutlineName)->m_lpPseudoObj;

      /* if there is a pseudo object associated with this name, then

      **    send OnSave advise to its linking clients.

      */

      if (lpPseudoObj &&

         ((lpmkObj=PseudoObj_GetFullMoniker(lpPseudoObj,lpmkDoc))!=NULL)) {

         // inform the clients that the name has been saved

         PseudoObj_SendAdvise (

               lpPseudoObj,

               OLE_ONSAVE,

               NULL,   /* lpmkDoc -- not relevant here */

               0       /* advf -- not relevant here */

         );

      }

   }

   OLEDBG_END2

}

/* ServerNameTable_SendPendingAdvises

 * ----------------------------------

 *

 *      Send any pending change notifications for pseudo objects.

 *  while ReDraw is diabled on the ServerDoc, then change advise

 *  notifications are not sent to pseudo object clients.

 */

void ServerNameTable_SendPendingAdvises(LPSERVERNAMETABLE lpServerNameTable)

{

   LPOUTLINENAMETABLE lpOutlineNameTable =

                              (LPOUTLINENAMETABLE)lpServerNameTable;

   LPSERVERNAME lpServerName;

   int i;

   for(i = 0; i < lpOutlineNameTable->m_nCount; i++) {

      lpServerName = (LPSERVERNAME)OutlineNameTable_GetName(

            lpOutlineNameTable,

            i

      );

      ServerName_SendPendingAdvises(lpServerName);

   }

}

/* ServerNameTable_GetPseudoObj

** ----------------------------

**

**    Return a pointer to a pseudo object identified by an item string

**    (lpszItem). if the pseudo object already exists, then return the

**    existing object, otherwise allocate a new pseudo object.

*/

LPPSEUDOOBJ ServerNameTable_GetPseudoObj(

      LPSERVERNAMETABLE       lpServerNameTable,

      LPOLESTR                lpszItem,

      LPSERVERDOC             lpServerDoc

)

{

   LPSERVERNAME lpServerName;

   lpServerName = (LPSERVERNAME)OutlineNameTable_FindName(

         (LPOUTLINENAMETABLE)lpServerNameTable,

         lpszItem

   );

   if (lpServerName)

      return ServerName_GetPseudoObj(lpServerName, lpServerDoc);

   else

      return NULL;

}

/* ServerNameTable_CloseAllPseudoObjs

 * ----------------------------------

 *

 *  Force all pseudo objects to close. this results in sending OnClose

 *  notification to each pseudo object's linking clients.

 */

void ServerNameTable_CloseAllPseudoObjs(LPSERVERNAMETABLE lpServerNameTable)

{

   LPOUTLINENAMETABLE lpOutlineNameTable =

                              (LPOUTLINENAMETABLE)lpServerNameTable;

   LPSERVERNAME lpServerName;

   int i;

   OLEDBG_BEGIN3("ServerNameTable_CloseAllPseudoObjs\r\n")

   for(i = 0; i < lpOutlineNameTable->m_nCount; i++) {

      lpServerName = (LPSERVERNAME)OutlineNameTable_GetName(

            lpOutlineNameTable,

            i

      );

        ServerName_ClosePseudoObj(lpServerName);

   }

   OLEDBG_END3

}

/* ServerName_SetSel

 * -----------------

 *

 *      Change the line range of a  name.

 */

void ServerName_SetSel(

      LPSERVERNAME            lpServerName,

      LPLINERANGE             lplrSel,

      BOOL                    fRangeModified

)

{

   LPOUTLINENAME lpOutlineName = (LPOUTLINENAME)lpServerName;

   BOOL fPseudoObjChanged = fRangeModified;

   if (lpOutlineName->m_nStartLine != lplrSel->m_nStartLine) {

      lpOutlineName->m_nStartLine = lplrSel->m_nStartLine;

      fPseudoObjChanged = TRUE;

   }

   if (lpOutlineName->m_nEndLine != lplrSel->m_nEndLine) {

      lpOutlineName->m_nEndLine = lplrSel->m_nEndLine;

      fPseudoObjChanged = TRUE;

   }

   /* OLE2NOTE: if the range of an active pseudo object has

   **    changed, then inform any linking clients that the object

   **    has changed.

   */

   if (lpServerName->m_lpPseudoObj && fPseudoObjChanged) {

      PseudoObj_SendAdvise(

            lpServerName->m_lpPseudoObj,

            OLE_ONDATACHANGE,

            NULL,   /* lpmkDoc -- not relevant here */

            0       /* advf -- no flags necessary */

      );

   }

}

/* ServerName_SendPendingAdvises

 * -----------------------------

 *

 *      Send any pending change notifications for the associated

 *  pseudo objects for this name (if one exists).

 *  while ReDraw is diabled on the ServerDoc, then change advise

 *  notifications are not sent to pseudo object clients.

 */

void ServerName_SendPendingAdvises(LPSERVERNAME lpServerName)

{

   if (! lpServerName->m_lpPseudoObj)

      return;     // no associated pseudo object

   if (lpServerName->m_lpPseudoObj->m_fDataChanged)

      PseudoObj_SendAdvise(

            lpServerName->m_lpPseudoObj,

            OLE_ONDATACHANGE,

            NULL,   /* lpmkDoc -- not relevant here */

            0       /* advf -- no flags necessary */

      );

}

/* ServerName_GetPseudoObj

** -----------------------

**

**    Return a pointer to a pseudo object associated to a ServerName.

**    if the pseudo object already exists, then return the

**    existing object, otherwise allocate a new pseudo object.

**

**    NOTE: the PseudoObj is returned with a 0 refcnt if first created,

**    else the existing refcnt is unchanged.

*/

LPPSEUDOOBJ ServerName_GetPseudoObj(

      LPSERVERNAME            lpServerName,

      LPSERVERDOC             lpServerDoc

)

{

   // Check if a PseudoObj already exists

   if (lpServerName->m_lpPseudoObj)

      return lpServerName->m_lpPseudoObj;

   // A PseudoObj does NOT already exist, allocate a new one.

   lpServerName->m_lpPseudoObj=(LPPSEUDOOBJ) New((DWORD)sizeof(PSEUDOOBJ));

   if (lpServerName->m_lpPseudoObj == NULL) {

      OleDbgAssertSz(lpServerName->m_lpPseudoObj != NULL,   "Error allocating PseudoObj");

      return NULL;

   }

   PseudoObj_Init(lpServerName->m_lpPseudoObj, lpServerName, lpServerDoc);

   return lpServerName->m_lpPseudoObj;

}

/* ServerName_ClosePseudoObj

 * -------------------------

 *

 *      if there is an associated pseudo objects for this name (if one

 *  exists), then close it. this results in sending OnClose

 *  notification to the pseudo object's linking clients.

 */

void ServerName_ClosePseudoObj(LPSERVERNAME lpServerName)

{

   if (!lpServerName || !lpServerName->m_lpPseudoObj)

      return;     // no associated pseudo object

   PseudoObj_Close(lpServerName->m_lpPseudoObj);

}

#endif  // OLE_SERVER

#if defined( OLE_CNTR )

/*************************************************************************

** ContainerDoc Supprt Functions Used by Container versions

*************************************************************************/

/* ContainerLine_GetRelMoniker

** ---------------------------

**    Retrieve the relative item moniker which identifies the OLE object

**    relative to the container document.

**

**    Returns NULL if a moniker can NOT be created.

*/

LPMONIKER ContainerLine_GetRelMoniker(

      LPCONTAINERLINE         lpContainerLine,

      DWORD                   dwAssign

)

{

   LPMONIKER lpmk = NULL;

   /* OLE2NOTE: we should only give out a moniker for the OLE object

   **    if the object is allowed to be linked to from the inside. if

   **    so we are allowed to give out a moniker which binds to the

   **    running OLE object). if the object is an OLE 2.0 embedded

   **    object then it is allowed to be linked to from the inside. if

   **    the object is either an OleLink or an OLE 1.0 embedding

   **    then it can not be linked to from the inside.

   **    if we were a container/server app then we could offer linking

   **    to the outside of the object (ie. a pseudo object within our

   **    document). we are a container only app that does not support

   **    linking to ranges of its data.

   */

   switch (dwAssign) {

      case GETMONIKER_FORCEASSIGN:

            /* Force the assignment of the name. This is called when a

            **    Paste Link actually occurs. From now on we want

            **    to inform the OLE object that its moniker is

            **    assigned and is thus necessary to register itself

            **    in the RunningObjectTable.

            */

            CreateItemMoniker(

                  OLESTDDELIM, lpContainerLine->m_szStgName, &lpmk);

            /* OLE2NOTE: if the OLE object is already loaded and it

            **    is being assigned a moniker for the first time,

            **    then we need to inform it that it now has a moniker

            **    assigned by calling IOleObject::SetMoniker. this

            **    will force the OLE object to register in the

            **    RunningObjectTable when it enters the running

            **    state. if the object is not currently loaded,

            **    SetMoniker will be called automatically later when

            **    the object is loaded by the function

            **    ContainerLine_LoadOleObject.

            */

            if (! lpContainerLine->m_fMonikerAssigned) {

               /* we must remember forever more that this object has a

               **    moniker assigned.

               */

               lpContainerLine->m_fMonikerAssigned = TRUE;

               // we are now dirty and must be saved

               OutlineDoc_SetModified(

                     (LPOUTLINEDOC)lpContainerLine->m_lpDoc,

                     TRUE,   /* fModified */

                     FALSE,  /* fDataChanged--N/A for container ver. */

                     FALSE   /* fSizeChanged--N/A for container ver. */

               );

               if (lpContainerLine->m_lpOleObj) {

                  OLEDBG_BEGIN2("IOleObject::SetMoniker called\r\n")

                  lpContainerLine->m_lpOleObj->lpVtbl->SetMoniker(

                        lpContainerLine->m_lpOleObj,

                        OLEWHICHMK_OBJREL,

                        lpmk

                  );

                  OLEDBG_END2

               }

            }

            break;

      case GETMONIKER_ONLYIFTHERE:

            /* If the OLE object currently has a moniker assigned,

            **    then return it.

            */

            if (lpContainerLine->m_fMonikerAssigned) {

               CreateItemMoniker(

                     OLESTDDELIM,

                     lpContainerLine->m_szStgName,

                     &lpmk

               );

            }

            break;

      case GETMONIKER_TEMPFORUSER:

            /* Return the moniker that would be used for the OLE

            **    object but do NOT force moniker assignment at

            **    this point. Since our strategy is to use the

            **    storage name of the object as its item name, we

            **    can simply create the corresponding ItemMoniker

            **    (indepenedent of whether the moniker is currently

            **    assigned or not).

            */

            CreateItemMoniker(

                  OLESTDDELIM,

                  lpContainerLine->m_szStgName,

                  &lpmk

            );

            break;

      case GETMONIKER_UNASSIGN:

            lpContainerLine->m_fMonikerAssigned = FALSE;

            break;

   }

   return lpmk;

}

/* ContainerLine_GetFullMoniker

** ----------------------------

**    Retrieve the full absolute moniker which identifies the OLE object

**    in the container document.

**    this moniker is created as a composite of the absolute moniker for

**    the entire document appended with an item moniker which identifies

**    the OLE object relative to the document.

**    Returns NULL if a moniker can NOT be created.

*/

LPMONIKER ContainerLine_GetFullMoniker(

      LPCONTAINERLINE         lpContainerLine,

      DWORD                   dwAssign

)

{

   LPMONIKER lpmkDoc = NULL;

   LPMONIKER lpmkItem = NULL;

   LPMONIKER lpmkFull = NULL;

   lpmkDoc = OleDoc_GetFullMoniker(

         (LPOLEDOC)lpContainerLine->m_lpDoc,

         dwAssign

   );

   if (! lpmkDoc)

   {

       return NULL;

   }

   lpmkItem = ContainerLine_GetRelMoniker(lpContainerLine, dwAssign);

   if (lpmkItem) {

      CreateGenericComposite(lpmkDoc, lpmkItem, (LPMONIKER FAR*)&lpmkFull);

      OleStdRelease((LPUNKNOWN)lpmkItem);

   }

   if (lpmkDoc)

      OleStdRelease((LPUNKNOWN)lpmkDoc);

   return lpmkFull;

}

/* ContainerDoc_InformAllOleObjectsDocRenamed

** ------------------------------------------

**    Inform all OLE objects that the name of the ContainerDoc has changed.

*/

void ContainerDoc_InformAllOleObjectsDocRenamed(

      LPCONTAINERDOC          lpContainerDoc,

      LPMONIKER               lpmkDoc

)

{

   LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;

   int i;

   LPLINE lpLine;

   // artificial AddRef in case someone releases object during call

   OleDoc_AddRef((LPOLEDOC)lpContainerDoc);

   for (i = 0; i < lpLL->m_nNumLines; i++) {

      lpLine=LineList_GetLine(lpLL, i);

      if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE)) {

         LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)lpLine;

         /* OLE2NOTE: if the OLE object is already loaded AND the

         **    object already has a moniker assigned, then we need

         **    to inform it that the moniker of the ContainerDoc has

         **    changed. of course, this means the full moniker of

         **    the object has changed. to do this we call

         **    IOleObject::SetMoniker. this will force the OLE

         **    object to re-register in the RunningObjectTable if it

         **    is currently in the running state. it is not in the

         **    running state, the object handler can make not that

         **    the object has a new moniker. if the object is not

         **    currently loaded, SetMoniker will be called

         **    automatically later when the object is loaded by the

         **    function ContainerLine_LoadOleObject.

         **    also if the object is a linked object, we always want

         **    to call SetMoniker on the link so that in case the

         **    link source is contained within our same container,

         **    the link source will be tracked. the link rebuilds

         **    its absolute moniker if it has a relative moniker.

         */

         if (lpContainerLine->m_lpOleObj) {

            if (lpContainerLine->m_fMonikerAssigned ||

               lpContainerLine->m_dwLinkType != 0) {

               OLEDBG_BEGIN2("IOleObject::SetMoniker called\r\n")

               lpContainerLine->m_lpOleObj->lpVtbl->SetMoniker(

                     lpContainerLine->m_lpOleObj,

                     OLEWHICHMK_CONTAINER,

                     lpmkDoc

               );

               OLEDBG_END2

            }

            /* OLE2NOTE: we must call IOleObject::SetHostNames so

            **    any open objects can update their window titles.

            */

            OLEDBG_BEGIN2("IOleObject::SetHostNames called\r\n")

            lpContainerLine->m_lpOleObj->lpVtbl->SetHostNames(

                  lpContainerLine->m_lpOleObj,

                  (LPOLESTR)APPNAME,

                  ((LPOUTLINEDOC)lpContainerDoc)->m_lpszDocTitle

            );

            OLEDBG_END2

         }

      }

   }

   // release artificial AddRef

   OleDoc_Release((LPOLEDOC)lpContainerDoc);

}

/* ContainerDoc_GetObject

** ----------------------

**    Return a pointer to the desired interface of an object identified

**    by an item string (lpszItem). the object returned will be an OLE

**    object (either link or embedding).

**

**      OLE2NOTE: we must force the object to run because we are

**          REQUIRED to return a pointer the OLE object in the

**          RUNNING state.

**

**    dwSpeedNeeded indicates how long the caller is willing

**    to wait for us to get the object:

**      BINDSPEED_IMMEDIATE -- only if obj already loaded && IsRunning

**      BINDSPEED_MODERATE  -- load obj if necessary && if IsRunning

**      BINDSPEED_INDEFINITE-- force obj to load and run if necessary

*/

HRESULT ContainerDoc_GetObject(

      LPCONTAINERDOC          lpContainerDoc,

      LPOLESTR                lpszItem,

      DWORD                   dwSpeedNeeded,

      REFIID                  riid,

      LPVOID FAR*             lplpvObject

)

{

   LPLINELIST  lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;

   int         i;

   LPLINE      lpLine;

   BOOL        fMatchFound = FALSE;

   DWORD       dwStatus;

   HRESULT     hrErr;

   *lplpvObject = NULL;

   for (i = 0; i < lpLL->m_nNumLines; i++) {

      lpLine=LineList_GetLine(lpLL, i);

      if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE)) {

         LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)lpLine;

         if (OLESTRCMP(lpContainerLine->m_szStgName, lpszItem) == 0) {

            fMatchFound = TRUE;     // valid item name

            // check if object is loaded.

            if (lpContainerLine->m_lpOleObj == NULL) {

               // if BINDSPEED_IMMEDIATE is requested, object must

               // ALREADY be loadded.

               if (dwSpeedNeeded == BINDSPEED_IMMEDIATE)

                  return ResultFromScode(MK_E_EXCEEDEDDEADLINE);

               ContainerLine_LoadOleObject(lpContainerLine);

               if (! lpContainerLine->m_lpOleObj)

                  return ResultFromScode(E_OUTOFMEMORY);

            }

            /* OLE2NOTE: check if the object is allowed to be linked

            **    to from the inside (ie. we are allowed to

            **    give out a moniker which binds to the running

            **    OLE object). if the object is an OLE

            **    2.0 embedded object then it is allowed to be

            **    linked to from the inside. if the object is

            **    either an OleLink or an OLE 1.0 embedding

            **    then it can not be linked to from the inside.

            **    if we were a container/server app then we

            **    could offer linking to the outside of the

            **    object (ie. a pseudo object within our

            **    document). we are a container only app that

            **    does not support linking to ranges of its data.

            */

            OLEDBG_BEGIN2("IOleObject::GetMiscStatus called\r\n");

            lpContainerLine->m_lpOleObj->lpVtbl->GetMiscStatus(

                  lpContainerLine->m_lpOleObj,

                  DVASPECT_CONTENT, /* aspect is not important */

                  (LPDWORD)&dwStatus

            );

            OLEDBG_END2

            if (dwStatus & OLEMISC_CANTLINKINSIDE)

            {

               return ResultFromScode(MK_E_NOOBJECT);

            }

            // check if object is running.

            if (! OleIsRunning(lpContainerLine->m_lpOleObj)) {

               // if BINDSPEED_MODERATE is requested, object must

               // ALREADY be running.

               if (dwSpeedNeeded == BINDSPEED_MODERATE)

               {

                  return ResultFromScode(MK_E_EXCEEDEDDEADLINE);

               }

               /* OLE2NOTE: we have found a match for the item name.

               **    now we must return a pointer to the desired

               **    interface on the RUNNING object. we must

               **    carefully load the object and initially ask for

               **    an interface that we are sure the loaded form of

               **    the object supports. if we immediately ask the

               **    loaded object for the desired interface, the

               **    QueryInterface call might fail if it is an

               **    interface that is supported only when the object

               **    is running. thus we force the object to load and

               **    return its IUnknown*. then we force the object to

               **    run, and then finally, we can ask for the

               **    actually requested interface.

               */

               hrErr = ContainerLine_RunOleObject(lpContainerLine);

               if (hrErr != NOERROR) {

                  return hrErr;

               }

            }

            // Retrieve the requested interface

            *lplpvObject = OleStdQueryInterface(

                  (LPUNKNOWN)lpContainerLine->m_lpOleObj, riid);

            break;  // Match FOUND!

         }

      }

   }

   if (*lplpvObject != NULL) {

      return NOERROR;

   } else

   {

      return (fMatchFound ? ResultFromScode(E_NOINTERFACE)

                     : ResultFromScode(MK_E_NOOBJECT));

   }

}

/* ContainerDoc_GetObjectStorage

** -----------------------------

**    Return a pointer to the IStorage* used by the object identified

**    by an item string (lpszItem). the object identified could be either

**    an OLE object (either link or embedding).

*/

HRESULT ContainerDoc_GetObjectStorage(

      LPCONTAINERDOC          lpContainerDoc,

      LPOLESTR                lpszItem,

      LPSTORAGE FAR*          lplpStg

)

{

   LPLINELIST lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;

   int i;

   LPLINE lpLine;

   *lplpStg = NULL;

   for (i = 0; i < lpLL->m_nNumLines; i++) {

      lpLine=LineList_GetLine(lpLL, i);

      if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE)) {

         LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)lpLine;

         if (OLESTRCMP(lpContainerLine->m_szStgName, lpszItem) == 0) {

            *lplpStg = lpContainerLine->m_lpStg;

            break;  // Match FOUND!

         }

      }

   }

   if (*lplpStg != NULL) {

      return NOERROR;

   } else

   {

      return ResultFromScode(MK_E_NOOBJECT);

   }

}

/* ContainerDoc_IsRunning

** ----------------------

**    Check if the object identified by an item string (lpszItem) is in

**    the running state.

**    For a container-only app, a check is made if the OLE object

**    associated with the item name is running.

*/

HRESULT ContainerDoc_IsRunning(LPCONTAINERDOC   lpContainerDoc, LPOLESTR lpszItem)

{

   LPLINELIST  lpLL = &((LPOUTLINEDOC)lpContainerDoc)->m_LineList;

   int         i;

   LPLINE      lpLine;

   DWORD       dwStatus;

   for (i = 0; i < lpLL->m_nNumLines; i++) {

      lpLine=LineList_GetLine(lpLL, i);

      if (lpLine && (Line_GetLineType(lpLine)==CONTAINERLINETYPE)) {

         LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)lpLine;

         if (OLESTRCPY(lpContainerLine->m_szStgName, lpszItem) == 0) {

            /* OLE2NOTE: we have found a match for the item name.

            **    now we must check if the OLE object is running.

            **    we will load the object if not already loaded.

            */

            if (! lpContainerLine->m_lpOleObj) {

               ContainerLine_LoadOleObject(lpContainerLine);

               if (! lpContainerLine->m_lpOleObj)

                  return ResultFromScode(E_OUTOFMEMORY);

            }

            /* OLE2NOTE: check if the object is allowed to be linked

            **    to from the inside (ie. we are allowed to

            **    give out a moniker which binds to the running

            **    OLE object). if the object is an OLE

            **    2.0 embedded object then it is allowed to be

            **    linked to from the inside. if the object is

            **    either an OleLink or an OLE 1.0 embedding

            **    then it can not be linked to from the inside.

            **    if we were a container/server app then we

            **    could offer linking to the outside of the

            **    object (ie. a pseudo object within our

            **    document). we are a container only app that

            **    does not support linking to ranges of its data.

            */

            OLEDBG_BEGIN2("IOleObject::GetMiscStatus called\r\n")

            lpContainerLine->m_lpOleObj->lpVtbl->GetMiscStatus(

                  lpContainerLine->m_lpOleObj,

                  DVASPECT_CONTENT, /* aspect is not important */

                  (LPDWORD)&dwStatus

            );

            OLEDBG_END2

            if (dwStatus & OLEMISC_CANTLINKINSIDE)

            {

               return ResultFromScode(MK_E_NOOBJECT);

            }

            if (OleIsRunning(lpContainerLine->m_lpOleObj))

            {

               return NOERROR;

            }

            else

            {

               return ResultFromScode(S_FALSE);

            }

         }

      }

   }

   // no object was found corresponding to the item name

   return ResultFromScode(MK_E_NOOBJECT);

}

#endif  // OLE_CNTR


MAIN.C  (OUTLINE Sample)

/*************************************************************************

**

**    OLE 2 Sample Code

**

**    main.c

**

**    This file contains initialization functions which are WinMain,

**    WndProc, and OutlineApp_InitalizeMenu.

**

**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

**

*************************************************************************/

#include "ansiapi.h"

#include "outline.h"

#if defined( USE_STATUSBAR )

#include "status.h"

#endif

#if !defined( WIN32 )

#if defined( USE_CTL3D )

//#include "..\include\ctl3d.h"

#include "ctl3d.h"

#endif  // USE_CTL3D

#endif  // !WIN32

#include "initguid.h"           // forces our GUIDs to be initialized

#include "defguid.h"

#if defined( OLE_CNTR )

//*************************************************************************

#if defined( INPLACE_CNTR )

OLEDBGDATA_MAIN("ICNTR")

#else

OLEDBGDATA_MAIN("CNTR")

#endif

CONTAINERAPP g_OutlineApp;  // Global App object maintains app instance state

/* Global interface Vtbl's

 * OLE2NOTE: we only need one copy of each Vtbl. When an object which

 *      exposes an interface is instantiated, its lpVtbl is intialized

 *      to point to one of these global Vtbl's.

 */

IUnknownVtbl            g_OleApp_UnknownVtbl;

IClassFactoryVtbl       g_OleApp_ClassFactoryVtbl;

IMessageFilterVtbl      g_OleApp_MessageFilterVtbl;

IUnknownVtbl            g_OleDoc_UnknownVtbl;

IPersistFileVtbl        g_OleDoc_PersistFileVtbl;

IOleItemContainerVtbl   g_OleDoc_OleItemContainerVtbl;

IExternalConnectionVtbl g_OleDoc_ExternalConnectionVtbl;

IDataObjectVtbl         g_OleDoc_DataObjectVtbl;

#if defined( USE_DRAGDROP )

IDropSourceVtbl         g_OleDoc_DropSourceVtbl;

IDropTargetVtbl         g_OleDoc_DropTargetVtbl;

#endif  // USE_DRAGDROP

IOleUILinkContainerVtbl g_CntrDoc_OleUILinkContainerVtbl;

IOleClientSiteVtbl      g_CntrLine_UnknownVtbl;

IOleClientSiteVtbl      g_CntrLine_OleClientSiteVtbl;

IAdviseSinkVtbl         g_CntrLine_AdviseSinkVtbl;

#if defined( INPLACE_CNTR )

IOleInPlaceSiteVtbl     g_CntrLine_OleInPlaceSiteVtbl;

IOleInPlaceFrameVtbl    g_CntrApp_OleInPlaceFrameVtbl;

BOOL g_fInsideOutContainer = FALSE;     // default to outside-in activation

#endif  // INPLACE_CNTR

//*************************************************************************

#endif  // OLE_CNTR

#if defined( OLE_SERVER )

//*************************************************************************

#if defined( INPLACE_SVR )

OLEDBGDATA_MAIN("ISVR")

#else

OLEDBGDATA_MAIN("SVR")

#endif

SERVERAPP g_OutlineApp; // Global App object maintains app instance state

/* Global interface Vtbl's

 * OLE2NOTE: we only need one copy of each Vtbl. When an object which

 *      exposes an interface is instantiated, its lpVtbl is intialized

 *      to point to one of these global Vtbl's.

 */

IUnknownVtbl            g_OleApp_UnknownVtbl;

IClassFactoryVtbl       g_OleApp_ClassFactoryVtbl;

IMessageFilterVtbl      g_OleApp_MessageFilterVtbl;

IUnknownVtbl            g_OleDoc_UnknownVtbl;

IPersistFileVtbl        g_OleDoc_PersistFileVtbl;

IOleItemContainerVtbl   g_OleDoc_OleItemContainerVtbl;

IExternalConnectionVtbl g_OleDoc_ExternalConnectionVtbl;

IDataObjectVtbl         g_OleDoc_DataObjectVtbl;

#if defined( USE_DRAGDROP )

IDropSourceVtbl         g_OleDoc_DropSourceVtbl;

IDropTargetVtbl         g_OleDoc_DropTargetVtbl;

#endif  // USE_DRAGDROP

IOleObjectVtbl          g_SvrDoc_OleObjectVtbl;

IPersistStorageVtbl     g_SvrDoc_PersistStorageVtbl;

#if defined( SVR_TREATAS )

IStdMarshalInfoVtbl     g_SvrDoc_StdMarshalInfoVtbl;

#endif  // SVR_TREATAS

#if defined( INPLACE_SVR )

IOleInPlaceObjectVtbl       g_SvrDoc_OleInPlaceObjectVtbl;

IOleInPlaceActiveObjectVtbl g_SvrDoc_OleInPlaceActiveObjectVtbl;

#endif // INPLACE_SVR

IUnknownVtbl            g_PseudoObj_UnknownVtbl;

IOleObjectVtbl          g_PseudoObj_OleObjectVtbl;

IDataObjectVtbl         g_PseudoObj_DataObjectVtbl;

//*************************************************************************

#endif  // OLE_SVR

#if !defined( OLE_VERSION )

OLEDBGDATA_MAIN("OUTL")

OUTLINEAPP g_OutlineApp;    // Global App object maintains app instance state

#endif

LPOUTLINEAPP g_lpApp=(LPOUTLINEAPP)&g_OutlineApp;   // ptr to global app obj

RECT        g_rectNull = {0, 0, 0, 0};

UINT        g_uMsgHelp = 0;  // help msg from ole2ui dialogs

BOOL        g_fAppActive = FALSE;

/* WinMain

** -------

**    Main routine for the Windows application.

*/

int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

                  LPSTR lpszCmdLine, int nCmdShow)

{

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   MSG         msg;            /* MSG structure to store your messages */

#if defined( OLE_VERSION )

   /* OLE2NOTE: it is recommended that all OLE applications to set

   **    their message queue size to 96. this improves the capacity

   **    and performance of OLE's LRPC mechanism.

   */

   int cMsg = 96;   // recommend msg queue size for OLE

   while (cMsg && ! SetMessageQueue(cMsg))  // take largest size we can get.

      cMsg -= 8;

   if (! cMsg)

      return -1;  // ERROR: we got no message queue

#endif

#if defined( USE_CTL3D )

   Ctl3dRegister(hInstance);

   Ctl3dAutoSubclass(hInstance);

#endif

   if(! hPrevInstance) {

      /* register window classes if first instance of application */

      if(! OutlineApp_InitApplication(lpOutlineApp, hInstance))

         return 0;

   }

   /* Create App Frame window */

   if (! OutlineApp_InitInstance(lpOutlineApp, hInstance, nCmdShow))

      return 0;

   if (! OutlineApp_ParseCmdLine(lpOutlineApp, lpszCmdLine, nCmdShow))

      return 0;

   lpOutlineApp->m_hAccelApp = LoadAccelerators(hInstance, APPACCEL);

   lpOutlineApp->m_hAccelFocusEdit = LoadAccelerators(hInstance,

         FB_EDIT_ACCEL);

   lpOutlineApp->m_hAccel = lpOutlineApp->m_hAccelApp;

   lpOutlineApp->m_hWndAccelTarget = lpOutlineApp->m_hWndApp;

   // Main message loop

   while(GetMessage(&msg, NULL, 0, 0)) {        /* Until WM_QUIT message */

      if(!MyTranslateAccelerator(&msg)) {

         TranslateMessage(&msg);

         DispatchMessage(&msg);

      }

   }

#if defined( OLE_VERSION )

   OleApp_TerminateApplication((LPOLEAPP)lpOutlineApp);

#else

   /* OLE2NOTE: CoInitialize() is called in OutlineApp_InitInstance

   **    and therefore we need to uninitialize it when exit.

   */

   CoUninitialize();

#endif

#if defined( USE_CTL3D )

   Ctl3dUnregister(hInstance);

#endif

   return msg.wParam;

} /*  End of WinMain */

BOOL MyTranslateAccelerator(LPMSG lpmsg)

{

   // if it's not a keystroke it can not be an accelerator

   if (lpmsg->message < WM_KEYFIRST || lpmsg->message > WM_KEYLAST)

      return FALSE;

   if (g_lpApp->m_hWndAccelTarget &&

      TranslateAccelerator(g_lpApp->m_hWndAccelTarget,

                                       g_lpApp->m_hAccel,lpmsg))

      return TRUE;

#if defined( INPLACE_SVR )

   /* OLE2NOTE: if we are in-place active and we did not translate the

   **    accelerator, we need to give the top-level (frame) in-place

   **    container a chance to translate the accelerator.

   **    we ONLY need to call OleTranslateAccelerator API if the

   **    message is a keyboard message. otherwise it is harmless but

   **    unnecessary.

   **

   **    NOTE: even a in-place server that does NOT have any

   **    Accelerators must still call OleTranslateAccelerator for all

   **    keyboard messages so that the server's OWN menu mneumonics

   **    (eg. &Edit -- Alt-e) function properly.

   **

   **    NOTE: an in-place server MUST check that the accelerator is

   **    NOT one of its own accelerators BEFORE calling

   **    OleTranslateAccelerator which tries to see if it is a

   **    container accelerator. if this is a server accelerator that

   **    was not translateed because the associated menu command was

   **    disabled, we MUST NOT call OleTranslateAccelerator. The

   **    IsAccelerator helper API has been added to assist with this

   **    check.

   */

   if (g_OutlineApp.m_lpIPData &&

      !IsAccelerator(g_lpApp->m_hAccel,

         GetAccelItemCount(g_lpApp->m_hAccel), lpmsg,NULL) &&

      OleTranslateAccelerator(g_OutlineApp.m_lpIPData->lpFrame,

            (LPOLEINPLACEFRAMEINFO)&g_OutlineApp.m_lpIPData->frameInfo,

            lpmsg) == NOERROR) {

      return TRUE;

   }

#endif

   return FALSE;

}

/************************************************************************/

/*                                                                      */

/* Main Window Procedure                                                */

/*                                                                      */

/* This procedure provides service routines for the Windows events      */

/* (messages) that Windows sends to the window, as well as the user     */

/* initiated events (messages) that are generated when the user selects */

/* the action bar and pulldown menu controls or the corresponding       */

/* keyboard accelerators.                                               */

/*                                                                      */

/************************************************************************/

LRESULT FAR PASCAL AppWndProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam)

{

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)GetWindowLong(hWnd, 0);

   LPOUTLINEDOC lpOutlineDoc = NULL;

#if defined( OLE_VERSION )

   LPOLEAPP lpOleApp = (LPOLEAPP)lpOutlineApp;

#endif

#if defined( OLE_CNTR )

   LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)lpOutlineApp;

   char         szAnsiString[256];

#endif

   HWND         hWndDoc = NULL;

#if defined( USE_FRAMETOOLS )

   LPFRAMETOOLS lptb = OutlineApp_GetFrameTools(lpOutlineApp);

#endif

   if (lpOutlineApp) {

      lpOutlineDoc = OutlineApp_GetActiveDoc(lpOutlineApp);

      if (lpOutlineDoc)

         hWndDoc = OutlineDoc_GetWindow(lpOutlineDoc);

   }

   switch (Message) {

      case WM_COMMAND:

      {

#ifdef WIN32

         WORD wID    = LOWORD(wParam);

#else

         WORD wID    = wParam;

#endif

#if defined( INPLACE_CNTR )

         LPCONTAINERDOC lpContainerDoc = (LPCONTAINERDOC)lpOutlineDoc;

         LPOLEDOC lpOleDoc = (LPOLEDOC)lpOutlineDoc;

         /* OLE2NOTE: see context sensitive help technote (CSHELP.DOC)

         **    m_fMenuHelpMode flag is set when F1 is pressed when a

         **    menu item is selected. this flag is set in

         **    IOleInPlaceFrame::ContextSensitveHelp method.

         **    m_fCSHelpMode flag is set when SHIFT-F1 context

         **    sensitive help is entered. this flag is set in

         **    IOleInPlaceSite::ContextSensitiveHelp method.

         **    if either of these flags are set then the WM_COMMAND

         **    message is received then, the corresponding command

         **    should NOT executed; help can be given (if desired).

         **    also the context sensitve help mode should be exited.

         **    the two different cases have their own way to exit

         **    the mode (please refer to the technote).

         */

         if (lpOleDoc &&

            (lpContainerApp->m_fMenuHelpMode||lpOleDoc->m_fCSHelpMode) &&

            (wID > IDM_FILE)   /* min wID for app command */ &&

            (wID!=IDM_FB_EDIT) /* special wID to control FormulaBar */ ) {

            if ((lpContainerApp->m_fMenuHelpMode)) {

               LPOLEINPLACEACTIVEOBJECT lpIPActiveObj =

                     lpContainerApp->m_lpIPActiveObj;

               lpContainerApp->m_fMenuHelpMode = FALSE;

               // inform the in-place active object that we handled the

               //   menu help mode (F1) selection.

               if (lpIPActiveObj) {

                  OLEDBG_BEGIN2("IOleInPlaceActiveObject::ContextSensitiveHelp(FALSE) called\r\n")

                  lpIPActiveObj->lpVtbl->ContextSensitiveHelp(

                        lpIPActiveObj, FALSE);

                  OLEDBG_END2

               }

            }

            if ((lpOleDoc->m_fCSHelpMode)) {

               LPOLEINPLACEOBJECT lpIPObj;

               LPCONTAINERLINE lpLastIpActiveLine =

                     lpContainerDoc->m_lpLastIpActiveLine;

               lpOleDoc->m_fCSHelpMode = FALSE;

               /* inform immediate in-place container parent and,

               **    if we were a container/server, immediate

               **    in-place object children that we handled the

               **    context sensitive help mode.

               */

               if (lpLastIpActiveLine &&

                     (lpIPObj=lpLastIpActiveLine->m_lpOleIPObj)!=NULL){

                  OLEDBG_BEGIN2("IOleInPlaceObject::ContextSensitiveHelp(FALSE) called\r\n")

                  lpIPObj->lpVtbl->ContextSensitiveHelp(lpIPObj, FALSE);

                  OLEDBG_END2

               }

            }

            // if we provided help, we would do it here...

            // remove context sensitive help cursor

            SetCursor(LoadCursor(NULL,IDC_ARROW));

            return 0L;

         }

#endif  // INPLACE_CNTR

         switch (wID) {

            case IDM_F_NEW:

               OleDbgIndent(-2);   // Reset debug output indent level

               OleDbgOutNoPrefix2("\r\n");

               OLEDBG_BEGIN3("OutlineApp_NewCommand\r\n")

               OutlineApp_NewCommand(lpOutlineApp);

               OLEDBG_END3

#if defined( OLE_CNTR )

               /* OLE2NOTE: this call will attempt to recover

               **    resources by unloading DLL's that were loaded

               **    by OLE and are no longer being used. it is a

               **    good idea to call this API now and then if

               **    your app tends to run for a long time.

               **    otherwise these DLL's will be unloaded when

               **    the app exits. some apps may want to call

               **    this as part of idle-time processing. this

               **    call is optional.

               */

               OLEDBG_BEGIN2("CoFreeUnusedLibraries called\r\n")

               CoFreeUnusedLibraries();

               OLEDBG_END2

#endif

#if defined( USE_FRAMETOOLS )

               OutlineDoc_UpdateFrameToolButtons(

                     OutlineApp_GetActiveDoc(lpOutlineApp));

#endif

               break;

            case IDM_F_OPEN:

               OleDbgOutNoPrefix2("\r\n");

               OLEDBG_BEGIN3("OutlineApp_OpenCommand\r\n")

               OutlineApp_OpenCommand(lpOutlineApp);

               OLEDBG_END3

#if defined( OLE_CNTR )

               /* OLE2NOTE: this call will attempt to recover

               **    resources by unloading DLL's that were loaded

               **    by OLE and are no longer being used. it is a

               **    good idea to call this API now and then if

               **    your app tends to run for a long time.

               **    otherwise these DLL's will be unloaded when

               **    the app exits. some apps may want to call

               **    this as part of idle-time processing. this

               **    call is optional.

               */

               OLEDBG_BEGIN2("CoFreeUnusedLibraries called\r\n")

               CoFreeUnusedLibraries();

               OLEDBG_END2

#endif

#if defined( USE_FRAMETOOLS )

               OutlineDoc_UpdateFrameToolButtons(

                     OutlineApp_GetActiveDoc(lpOutlineApp));

#endif

               break;

            case IDM_F_SAVE:

               OleDbgOutNoPrefix2("\r\n");

               OLEDBG_BEGIN3("OutlineApp_SaveCommand\r\n")

               OutlineApp_SaveCommand(lpOutlineApp);

               OLEDBG_END3

               break;

            case IDM_F_SAVEAS:

               OleDbgOutNoPrefix2("\r\n");

               OLEDBG_BEGIN3("OutlineApp_SaveAsCommand\r\n")

               OutlineApp_SaveAsCommand(lpOutlineApp);

               OLEDBG_END3

               break;

            case IDM_F_PRINT:

               OleDbgOutNoPrefix2("\r\n");

               OLEDBG_BEGIN3("OutlineApp_PrintCommand\r\n")

               OutlineApp_PrintCommand(lpOutlineApp);

               OLEDBG_END3

               break;

            case IDM_F_PRINTERSETUP:

               OleDbgOutNoPrefix2("\r\n");

               OLEDBG_BEGIN3("OutlineApp_PrinterSetupCommand\r\n")

               OutlineApp_PrinterSetupCommand(lpOutlineApp);

               OLEDBG_END3

               break;

            case IDM_F_EXIT:

               SendMessage(hWnd, WM_CLOSE, 0, 0L);

               break;

            case IDM_H_ABOUT:

               OutlineApp_AboutCommand(lpOutlineApp);

               break;

#if defined( INPLACE_CNTR )

            case IDM_ESCAPE:

            {

               /* ESCAPE key pressed */

               LPCONTAINERDOC lpContainerDoc =

                        (LPCONTAINERDOC)lpOutlineDoc;

               /* OLE2NOTE: The standard OLE 2.0 UI convention

               **    is to have ESCAPE key exit in-place

               **    activation (ie. UIDeactivate). If

               **    possible it is recommended for both

               **    in-place servers AND in-place containers

               **    to take responsibility to handle the

               **    ESCAPE key accelerator. The server has

               **    the first crack at handling accelerator

               **    keys and normally the server should do

               **    the UIDeactivation. It is a good idea for

               **    in-place containers, in order to

               **    guarantee consistent behavior, to also

               **    handle the ESCAPE key and UIDeactivate

               **    the object in case the object does not do

               **    it itself. normally this should be

               **    unnecessary.

               */

               if (lpContainerDoc->m_lpLastUIActiveLine &&

                  lpContainerDoc->m_lpLastUIActiveLine->m_fUIActive)

               {

                  ContainerLine_UIDeactivate(

                        lpContainerDoc->m_lpLastUIActiveLine);

               }

               break;

            }

#endif  // INPLACE_CNTR

            default:

               // forward message to document window

               if (hWndDoc) {

                  return DocWndProc(hWndDoc, Message,wParam,lParam);

               }

         }

         break;  /* End of WM_COMMAND */

      }

      case WM_INITMENU:

         OutlineApp_InitMenu(lpOutlineApp, lpOutlineDoc, (HMENU)wParam);

         break;

#if defined( OLE_VERSION )

      /* OLE2NOTE: WM_INITMENUPOPUP is trapped primarily for the Edit

      **    menu. We didn't update the Edit menu until it is popped

      **    up to avoid the overheads of the OLE calls which are

      **    required to initialize some Edit menu items.

      */

      case WM_INITMENUPOPUP:

      {

         HMENU hMenuEdit = GetSubMenu(lpOutlineApp->m_hMenuApp, 1);

#if defined( INPLACE_CNTR )

         LPCONTAINERDOC lpContainerDoc = (LPCONTAINERDOC)lpOutlineDoc;

         /* OLE2NOTE: we must check if there is an object currently

         **    in-place UIActive. if so, then our edit menu is not

         **    on the menu; we do not want to bother updating the

         **    edit menu when it is not even there.

         */

         if (lpContainerDoc && lpContainerDoc->m_lpLastUIActiveLine &&

            lpContainerDoc->m_lpLastUIActiveLine->m_fUIActive)

            break;  // an object is in-place UI active

#endif

         if ((HMENU)wParam == hMenuEdit &&

            (LOWORD(lParam) == POS_EDITMENU) &&

            OleDoc_GetUpdateEditMenuFlag((LPOLEDOC)lpOutlineDoc)) {

            OleApp_UpdateEditMenu(lpOleApp, lpOutlineDoc, hMenuEdit);

         }

         break;

      }

#endif      // OLE_VERSION

      case WM_SIZE:

         if (wParam != SIZE_MINIMIZED)

            OutlineApp_ResizeWindows(lpOutlineApp);

         break;

      case WM_ACTIVATEAPP:

#if defined (OLE_CNTR)

         if (g_fAppActive = (BOOL) wParam)

            OleApp_QueryNewPalette(lpOleApp);

#endif

#if defined( INPLACE_CNTR )

         {

            BOOL fActivate = (BOOL)wParam;

            LPOLEINPLACEACTIVEOBJECT lpIPActiveObj =

                  lpContainerApp->m_lpIPActiveObj;

            /* OLE2NOTE: the in-place container MUST inform the

            **    inner most in-place active object (this is NOT

            **    necessarily our immediate child if there are

            **    nested levels of embedding) of the WM_ACTIVATEAPP

            **    status.

            */

            if (lpIPActiveObj) {

#if defined( _DEBUG )

               OLEDBG_BEGIN2((fActivate ?

                  "IOleInPlaceActiveObject::OnFrameWindowActivate(TRUE) called\r\n" :

                  "IOleInPlaceActiveObject::OnFrameWindowActivate(FALSE) called\r\n"))

#endif  // _DEUBG

               lpIPActiveObj->lpVtbl->OnFrameWindowActivate(

                  lpIPActiveObj, fActivate);

               OLEDBG_END2

            }

         }

#endif  // INPLACE_CNTR

         // OLE2NOTE: We can't call OutlineDoc_UpdateFrameToolButtons

         //           right away which

         //           would generate some OLE calls and eventually

         //           WM_ACTIVATEAPP and a loop was formed. Therefore, we

         //           should delay the frame tool initialization until

         //           WM_ACTIVATEAPP is finished by posting a message

         //           to ourselves.

         //           we want to ignore the WM_ACTIVATEAPP that comes

         //           as we bring up a modal dialog.

         /* Update enable/disable state of buttons in toolbar */

         if (wParam

#if defined( OLE_VERSION )

               && lpOleApp->m_cModalDlgActive == 0

#endif

         ) {

            PostMessage(hWnd, WM_U_INITFRAMETOOLS, 0, 0L);

         }

         return 0L;

      case WM_SETFOCUS:

         SetFocus(hWndDoc);

         break;

#if defined( OLE_CNTR )

      case WM_QUERYNEWPALETTE:

         if (!g_fAppActive)

            return 0L;

         return OleApp_QueryNewPalette(lpOleApp);

      case WM_PALETTECHANGED:

      {

         HWND hWndPalChg = (HWND) wParam;

         static BOOL fInPaletteChanged = FALSE;

         if (fInPaletteChanged)  // Guard against recursion

            return 0L;

         fInPaletteChanged = TRUE;

         if (hWnd != hWndPalChg)

            wSelectPalette(hWnd, lpOleApp->m_hStdPal,TRUE/*fBackground*/);

#if defined( INPLACE_CNTR )

         /* OLE2NOTE: always forward the WM_PALETTECHANGED message (via

         **    SendMessage) to any in-place objects that currently have

         **    their window visible. this gives these objects the chance

         **    to select their palettes. this is

         **    REQUIRED by all in-place containers independent of

         **    whether they use color palettes themselves--their objects

         **    may use color palettes.

         **    (see ContainerDoc_ForwardPaletteChangedMsg for more info)

         */

         if (lpOutlineDoc){

            ContainerDoc_ForwardPaletteChangedMsg(

                  (LPCONTAINERDOC)lpOutlineDoc, hWndPalChg);

         }

#endif  // INPLACE_CNTR

         fInPaletteChanged = FALSE;

         return 0L;

      }

#endif  // OLE_CNTR

      case WM_DESTROY:

         PostQuitMessage(0);

         break;

      case WM_CLOSE:  /* close the window */

         /* Close all active documents. if successful, then exit */

         OleDbgOutNoPrefix2("\r\n");

         OutlineApp_CloseAllDocsAndExitCommand(lpOutlineApp, FALSE);

         break;

      case WM_QUERYENDSESSION:

      {

#if defined( OLE_CNTR )

         /* OLE2NOTE: we are not able to make OLE LRPC calls when

         **    WM_QUERYENDSESSION is recieved (this is a

         **    SendMessage). this means, for example, that we are

         **    NOT able to ask objects to save. thus the most we can

         **    do is ask the user if he wants to exit with

         **    discarding changes or else abort shutting down.

         */

//???         W2A (APPNAME, szAnsiString, 256);

         int nResponse = MessageBox(

               hWnd,

               "Discard changes?",

               szAnsiString,

               MB_ICONQUESTION | MB_OKCANCEL

         );

         if(nResponse == IDOK)

            return 1L;      /* can terminate */

#endif

#if defined( OLE_SERVER )

         /* OLE2NOTE: an embedded object should never prompt whether

         **    it should be saved (according the OLE 2.0 User

         **    Model). therefore, an embedded object will never

         **    complain that it needs to be saved. it will always

         **    allow the QueryEndSession to proceed.

         */

         if (lpOutlineApp->m_lpDoc->m_docInitType == DOCTYPE_EMBEDDED)

            return 1L;      /* can terminate */

         else

#endif

         {

            /* this is not an embedded object; it is a user

            **    document. we will prompt if the user wants to

            **    save the document now in WM_QUERYENDSESSION. if

            **    the user cancels then that would abort the

            **    shutdown. if the user does not abort, then later

            **    in WM_ENDSESSION the document will be actually

            **    closed.

            **

            **    Because this is an SDI app, there is only one

            **    document. An MDI would need to loop through all

            **    open documents.

            */

            DWORD dwSaveOption = OLECLOSE_PROMPTSAVE;

            if (OutlineDoc_CheckSaveChanges(

                  lpOutlineApp->m_lpDoc, &dwSaveOption))

               return 1L;      /* can terminate */

         }

         /* else: can't terminate now */

         break;

      }

#if defined( OLE_VERSION)

      case WM_ENDSESSION:

      {

         BOOL fEndSession = (BOOL)wParam;

         if (fEndSession) {

            OutlineApp_CloseAllDocsAndExitCommand(lpOutlineApp, TRUE);

            return 0L;

         }

      }

      break;

#endif  // OLE_VERSION

#if defined( USE_STATUSBAR )

      case WM_MENUSELECT:

      {

         LPSTR lpszMessage;

         OLECHAR lpszUniMessage[256];

#ifdef WIN32

         UINT fuFlags    = (UINT)HIWORD(wParam);

         UINT uItem      = (UINT)LOWORD(wParam);

#else

         UINT fuFlags    = (UINT)LOWORD(lParam);

         UINT uItem      = (UINT)wParam;

#endif

         if (uItem == 0 && fuFlags == (UINT)-1) {

            GetControlMessage(STATUS_READY, &lpszMessage);

            A2W (lpszMessage, lpszUniMessage, 256);

            OutlineApp_SetStatusText(lpOutlineApp, lpszUniMessage);

         }

         else if (fuFlags & MF_POPUP) {

#ifdef WIN32

            HMENU hMainMenu = (HMENU)lParam;

            HMENU hPopupMenu = GetSubMenu(hMainMenu,uItem);

#else

            HMENU hPopupMenu = (HMENU)wParam;

#endif

            GetPopupMessage(hPopupMenu, &lpszMessage);

            A2W (lpszMessage, lpszUniMessage, 256);

            OutlineApp_SetStatusText(lpOutlineApp, lpszUniMessage);

         }

         else if (fuFlags & MF_SYSMENU) {

            GetSysMenuMessage(uItem, &lpszMessage);

            A2W (lpszMessage, lpszUniMessage, 256);

            OutlineApp_SetStatusText(lpOutlineApp, lpszUniMessage);

         }

         else if (uItem != 0) {  // Command Item

            GetItemMessage(uItem, &lpszMessage);

            A2W (lpszMessage, lpszUniMessage, 256);

            OutlineApp_SetStatusText(lpOutlineApp, lpszUniMessage);

         }

         else {

            GetControlMessage(STATUS_BLANK, &lpszMessage);

            A2W (lpszMessage, lpszUniMessage, 256);

            OutlineApp_SetStatusText(lpOutlineApp, lpszUniMessage);

         }

         break;

      }

#endif  // USE_STATUSBAR

#if defined( USE_FRAMETOOLS )

      case WM_U_INITFRAMETOOLS:

         OutlineDoc_UpdateFrameToolButtons(lpOutlineDoc);

         break;

#endif

      default:

         /* For any message for which you don't specifically provide a  */

         /* service routine, you should return the message to Windows   */

         /* for default message processing.                             */

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

   }

   return (LRESULT)0;

}     /* End of AppWndProc*/

/************************************************************************/

/*                                                                      */

/* Document Window Procedure                                            */

/*                                                                      */

/*   The Document Window is the parent of the OwnerDraw Listbox which   */

/* maintains the list of lines in the current document. This window     */

/* receives the ownerdraw callback messages from the list box.          */

/************************************************************************/

LRESULT FAR PASCAL DocWndProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam)

{

   LPOUTLINEAPP    lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   LPOUTLINEDOC    lpOutlineDoc = (LPOUTLINEDOC)GetWindowLong(hWnd, 0);

   LPLINELIST      lpLL = OutlineDoc_GetLineList(lpOutlineDoc);

   LPSCALEFACTOR   lpscale = OutlineDoc_GetScaleFactor(lpOutlineDoc);

#if defined( OLE_VERSION )

   LPOLEAPP lpOleApp = (LPOLEAPP)lpOutlineApp;

   LPOLEDOC lpOleDoc = (LPOLEDOC)lpOutlineDoc;

#if defined( OLE_CNTR )

   LPCONTAINERDOC lpContainerDoc = (LPCONTAINERDOC)lpOutlineDoc;

#endif

#if defined( OLE_SERVER )

   LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOutlineDoc;

#endif

#if defined( INPLACE_CNTR )

   LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)lpOutlineApp;

#endif

#endif  // OLE_VERSION

   switch(Message) {

#if defined( INPLACE_SVR )

      /* OLE2NOTE: ISVROTL doesn't use color palettes. The inplace objects

      **    that use color palettes must implement the following

      **    lines of code.

      **

         case WM_QUERYNEWPALETTE:

            return wSelectPalette(hWnd, hPal, FALSE); // foreground

         case WM_PALETTECHANGED:

            if (hWnd != (HWND) wParam)

               wSelectPalette(hWnd, hPal, TRUE);     // background

         break;

      **

      **

      **

      */

#endif

      case WM_MEASUREITEM:

      {

         LPMEASUREITEMSTRUCT lpmis = ((LPMEASUREITEMSTRUCT)lParam);

         switch (wParam) {

            case IDC_LINELIST:

            {

               HDC hDC = LineList_GetDC(lpLL);

               UINT uHeight;

               uHeight=Line_GetHeightInHimetric((LPLINE)lpmis->itemData);

               uHeight = XformHeightInHimetricToPixels(hDC, uHeight);

               uHeight = (UINT) (uHeight * lpscale->dwSyN /

                     lpscale->dwSyD);

               if (uHeight >LISTBOX_HEIGHT_LIMIT)

                  uHeight = LISTBOX_HEIGHT_LIMIT;

               lpmis->itemHeight = uHeight;

               LineList_ReleaseDC(lpLL, hDC);

               break;

            }

            case IDC_NAMETABLE:

            {

               // NOTE: NameTable is never made visible. do nothing.

               break;

            }

#if defined( USE_HEADING )

            case IDC_ROWHEADING:

            {

               UINT uHeight;

               uHeight = LOWORD(lpmis->itemData);

               uHeight = (UINT) (uHeight * lpscale->dwSyN /

                     lpscale->dwSyD);

               if (uHeight >LISTBOX_HEIGHT_LIMIT)

                  uHeight = LISTBOX_HEIGHT_LIMIT;

               lpmis->itemHeight = uHeight;

               break;

            }

            case IDC_COLHEADING:

            {

               UINT uHeight;

               uHeight = LOWORD(lpmis->itemData);

               uHeight = (UINT) (uHeight * lpscale->dwSyN /

                     lpscale->dwSyD);

               if (uHeight > LISTBOX_HEIGHT_LIMIT)

                  uHeight = LISTBOX_HEIGHT_LIMIT;

               lpmis->itemHeight = uHeight;

               break;

            }

#endif  // USE_HEADING

         }

         return (LRESULT)TRUE;

      }

      case WM_DRAWITEM:

      {

         LPDRAWITEMSTRUCT lpdis = ((LPDRAWITEMSTRUCT)lParam);

         switch (lpdis->CtlID) {

            case IDC_LINELIST:

            {

               RECT   rcClient;

               RECT   rcDevice;

               HWND   hWndLL = LineList_GetWindow(lpLL);

               LPLINE lpLine = (LPLINE)lpdis->itemData;

               // NOTE: When itemID == -1, the listbox is empty.

               //       We are supposed to draw focus rect only

               //       But it is not done in this app. If this line is

               //       removed, the app will crash in Line_DrawToScreen

               //       because of invalid lpLine.

               if (lpdis->itemID == -1)

                  break;

               GetClientRect(hWndLL, &rcClient);

               rcDevice = lpdis->rcItem;

               // shift the item rect to account for horizontal scrolling

               rcDevice.left += rcClient.right - lpdis->rcItem.right;

#if defined( OLE_CNTR )

               /* we need to remember the horizontal scroll offset

               **    needed for the in-place object's window.

               **    (this is specific to ICNTROTL)

               */

               if(lpdis->itemAction & ODA_DRAWENTIRE) {

                  if (Line_GetLineType(lpLine) == CONTAINERLINETYPE)

                     ((LPCONTAINERLINE)lpLine)->m_nHorizScrollShift =

                        rcDevice.left;

               }

#endif  // OLE_CNTR

               // shift rect for left margin

               rcDevice.left += (int)(XformWidthInHimetricToPixels(NULL,

                     LOWORD(OutlineDoc_GetMargin(lpOutlineDoc))) *

                     lpscale->dwSxN / lpscale->dwSxD);

               rcDevice.right = rcDevice.left +

                     (int)(XformWidthInHimetricToPixels(lpdis->hDC,

                           Line_GetWidthInHimetric(lpLine)) *

                     lpscale->dwSxN / lpscale->dwSxD);

               Line_DrawToScreen(

                     lpLine,

                     lpdis->hDC,

                     &lpdis->rcItem,

                     lpdis->itemAction,

                     lpdis->itemState,

                     &rcDevice

               );

#if defined( USE_FRAMETOOLS )

               if (lpdis->itemState & ODS_FOCUS)

                  OutlineDoc_SetFormulaBarEditText(lpOutlineDoc,lpLine);

#endif

               break;

            }

            case IDC_NAMETABLE:

            {

               // NOTE: NameTable is never made visible. do nothing

               break;

            }

#if defined( USE_HEADING )

            case IDC_ROWHEADING:

            {

               LPHEADING lphead;

               // Last dummy item shouldn't be drawn

               if (lpdis->itemID == (UINT)LineList_GetCount(lpLL))

                  break;

               // only DrawEntire need be trapped as window is disabled

               if (lpdis->itemAction == ODA_DRAWENTIRE) {

                  lphead = OutlineDoc_GetHeading(lpOutlineDoc);

                  Heading_RH_Draw(lphead, lpdis);

               }

               break;

            }

            case IDC_COLHEADING:

            {

               RECT   rect;

               RECT   rcDevice;

               RECT   rcLogical;

               LPHEADING lphead;

               // only DrawEntire need be trapped as window is disabled

               if (lpdis->itemAction == ODA_DRAWENTIRE) {

                  lphead = OutlineDoc_GetHeading(lpOutlineDoc);

                  GetClientRect(lpdis->hwndItem, &rect);

                  rcDevice = lpdis->rcItem;

                  // shift the item rect to account for

                  // horizontal scrolling

                  rcDevice.left = -(rcDevice.right - rect.right);

                  // shift rect for left margin

                  rcDevice.left += (int)(XformWidthInHimetricToPixels(

                        NULL,

                        LOWORD(OutlineDoc_GetMargin(lpOutlineDoc))) *

                     lpscale->dwSxN / lpscale->dwSxD);

                  rcDevice.right = rcDevice.left + (int)lpscale->dwSxN;

                  rcLogical.left = 0;

                  rcLogical.bottom = 0;

                  rcLogical.right = (int)lpscale->dwSxD;

                  rcLogical.top = LOWORD(lpdis->itemData);

                  Heading_CH_Draw(lphead, lpdis, &rcDevice, &rcLogical);

               }

               break;

            }

#endif  // USE_HEADING

         }

         return (LRESULT)TRUE;

      }

      case WM_SETFOCUS:

         if (lpLL)

            SetFocus(LineList_GetWindow(lpLL));

         break;

#if !defined( OLE_VERSION )

      case WM_RENDERFORMAT:

      {

         LPOUTLINEDOC lpClipboardDoc = lpOutlineApp->m_lpClipboardDoc;

         if (lpClipboardDoc)

            OutlineDoc_RenderFormat(lpClipboardDoc, wParam);

         break;

      }

      case WM_RENDERALLFORMATS:

      {

         LPOUTLINEDOC lpClipboardDoc = lpOutlineApp->m_lpClipboardDoc;

         if (lpClipboardDoc)

            OutlineDoc_RenderAllFormats(lpClipboardDoc);

         break;

      }

      case WM_DESTROYCLIPBOARD:

         if (g_lpApp->m_lpClipboardDoc) {

            OutlineDoc_Destroy(g_lpApp->m_lpClipboardDoc);

            g_lpApp->m_lpClipboardDoc = NULL;

         }

         break;

#endif   // OLE_VERSION

#if defined( OLE_CNTR )

      case WM_U_UPDATEOBJECTEXTENT:

      {

         /* Update the extents of any OLE object that is marked that

         **    its size may  have changed. when an

         **    IAdviseSink::OnViewChange notification is received,

         **    the corresponding ContainerLine is marked

         **    (m_fDoGetExtent==TRUE) and a message

         **    (WM_U_UPDATEOBJECTEXTENT) is posted to the document

         **    indicating that there are dirty objects.

         */

         ContainerDoc_UpdateExtentOfAllOleObjects(lpContainerDoc);

         break;

      }

#endif  // OLE_CNTR

#if defined( INPLACE_SVR ) || defined( INPLACE_CNTR )

      /* OLE2NOTE: Any window that is used during in-place activation

      **    must handle the WM_SETCURSOR message or else the cursor

      **    of the in-place parent will be used. if WM_SETCURSOR is

      **    not handled, then DefWindowProc sends the message to the

      **    window's parent.

      **

      **    see context sensitive help technote (CSHELP.DOC).

      **    m_fCSHelpMode flag is set when SHIFT-F1 context

      **    sensitive help is entered.

      **    if this flag is set then the context sensitive help

      **    cursor should be shown.

      */

      case WM_SETCURSOR:

         if (lpOleDoc->m_fCSHelpMode)

            SetCursor(UICursorLoad(IDC_CONTEXTHELP));

         else

            SetCursor(LoadCursor(NULL, IDC_ARROW) );

         return (LRESULT)TRUE;

#endif  // INPLACE_SVR || INPLACE_CNTR

#if defined( INPLACE_SVR )

      /* OLE2NOTE: when the in-place active, our in-place server

      **    document window (passed to IOleInPlaceFrame::SetMenu)

      **    will receive the WM_INITMENU and WM_INITMENUPOPUP messages.

      */

      case WM_INITMENU:

         OutlineApp_InitMenu(lpOutlineApp, lpOutlineDoc, (HMENU)wParam);

         break;

      /* OLE2NOTE: WM_INITMENUPOPUP is trapped primarily for the Edit

      **    menu. We didn't update the Edit menu until it is popped

      **    up to avoid the overheads of the OLE calls which are

      **    required to initialize some Edit menu items.

      */

      case WM_INITMENUPOPUP:

      {

         HMENU hMenuEdit = GetSubMenu(lpOutlineApp->m_hMenuApp, 1);

         if ((HMENU)wParam == hMenuEdit &&

            (LOWORD(lParam) == POS_EDITMENU) &&

            OleDoc_GetUpdateEditMenuFlag((LPOLEDOC)lpOutlineDoc)) {

            OleApp_UpdateEditMenu(

                  (LPOLEAPP)lpOutlineApp, lpOutlineDoc, hMenuEdit);

         }

         break;

      }

#endif      // INPLACE_SVR

#if defined( INPLACE_SVR ) && defined( USE_STATUSBAR )

      /* OLE2NOTE: when the server is in-place active the

      **    WM_MENUSELECT message is sent to the object's window and

      **    not the server app's frame window. processing this

      **    message allows there in-place server to give status bar

      **    help text for menu commands.

      */

      case WM_MENUSELECT:

      {

         LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOleDoc;

         LPSTR lpszMessage;

         OLECHAR szUniMessage[256];

#ifdef WIN32

         UINT fuFlags    = (UINT)HIWORD(wParam);

         UINT uItem      = (UINT)LOWORD(wParam);

#else

         UINT fuFlags    = (UINT)LOWORD(lParam);

         UINT uItem      = (UINT)wParam;

#endif

         if (uItem == 0 && fuFlags == (UINT)-1) {

            GetControlMessage(STATUS_READY, &lpszMessage);

            A2W( lpszMessage, szUniMessage, 256);

            ServerDoc_SetStatusText(lpServerDoc, szUniMessage);

         }

         else if (fuFlags & MF_POPUP) {

#ifdef WIN32

            HMENU hMainMenu = (HMENU)lParam;

            HMENU hPopupMenu = GetSubMenu(hMainMenu,uItem);

#else

            HMENU hPopupMenu = (HMENU)wParam;

#endif

            GetPopupMessage(hPopupMenu, &lpszMessage);

            A2W( lpszMessage, szUniMessage, 256);

            ServerDoc_SetStatusText(lpServerDoc, szUniMessage);

         }

         else if (uItem != 0) {  // Command Item

            GetItemMessage(uItem, &lpszMessage);

            A2W( lpszMessage, szUniMessage, 256);

            ServerDoc_SetStatusText(lpServerDoc, szUniMessage);

         }

         else {

            GetControlMessage(STATUS_BLANK, &lpszMessage);

            A2W( lpszMessage, szUniMessage, 256);

            ServerDoc_SetStatusText(lpServerDoc, szUniMessage);

         }

         break;

      }

#endif  // INPLACE_SVR && USE_STATUSBAR

#if defined( INPLACE_SVR ) && defined( USE_FRAMETOOLS )

      case WM_U_INITFRAMETOOLS:

         OutlineDoc_UpdateFrameToolButtons(lpOutlineDoc);

         break;

#endif      // INPLACE_SVR && USE_FRAMETOOLS

      case WM_COMMAND:

      {

#ifdef WIN32

         WORD wNotifyCode = HIWORD(wParam);

         WORD wID          = LOWORD(wParam);

         HWND hwndCtl     = (HWND) lParam;

#else

         WORD wNotifyCode = HIWORD(lParam);

         WORD wID             = wParam;

         HWND hwndCtl     = (HWND) LOWORD(lParam);

#endif

#if defined( INPLACE_SVR )

         /* OLE2NOTE: see context sensitive help technote (CSHELP.DOC)

         **    m_fMenuHelpMode flag is set when F1 is pressed when a

         **    menu item is selected. this flag is set in

         **    IOleInPlaceActiveObject::ContextSensitveHelp method.

         **    m_fCSHelpMode flag is set when SHIFT-F1 context

         **    sensitive help is entered. this flag is set in

         **    IOleInPlaceObject::ContextSensitiveHelp method.

         **    if either of these flags are set then the WM_COMMAND

         **    message is received then, the corresponding command

         **    should NOT executed; help can be given (if desired).

         **    also the context sensitve help mode should be exited.

         **    the two different cases have their own way to exit

         **    the mode (please refer to the technote).

         */

         if (lpOleDoc &&

            (lpServerDoc->m_fMenuHelpMode||lpOleDoc->m_fCSHelpMode) &&

            (wID > IDM_FILE)   /* min wID for app command */ &&

            (wID!=IDM_FB_EDIT) /* special wID to control FormulaBar */ ) {

            if ((lpServerDoc->m_fMenuHelpMode)) {

               LPOLEINPLACEFRAME lpFrame;

               lpServerDoc->m_fMenuHelpMode = FALSE;

               // inform top-level frame that we handled the

               //   menu help mode (F1) selection.

               if (lpServerDoc->m_lpIPData &&

                     (lpFrame=lpServerDoc->m_lpIPData->lpFrame)!=NULL){

                  OLEDBG_BEGIN2("IOleInPlaceFrame::ContextSensitiveHelp(FALSE) called\r\n")

                  lpFrame->lpVtbl->ContextSensitiveHelp(lpFrame, FALSE);

                  OLEDBG_END2

               }

            }

            if ((lpOleDoc->m_fCSHelpMode)) {

               LPOLEINPLACESITE lpSite;

               lpOleDoc->m_fCSHelpMode = FALSE;

               /* inform immediate in-place container parent and,

               **    if we were a container/server, immediate

               **    in-place object children that we handled the

               **    context sensitive help mode.

               */

               if (lpServerDoc->m_lpIPData &&

                     (lpSite=lpServerDoc->m_lpIPData->lpSite) !=NULL) {

                  OLEDBG_BEGIN2("IOleInPlaceSite::ContextSensitiveHelp(FALSE) called\r\n")

                  lpSite->lpVtbl->ContextSensitiveHelp(lpSite, FALSE);

                  OLEDBG_END2

               }

            }

            // if we provided help, we would do it here...

            // remove context sensitive help cursor

            SetCursor(LoadCursor(NULL,IDC_ARROW));

            return 0L;

         }

#endif  // INPLACE_SVR

#if defined( INPLACE_CNTR )

         /* OLE2NOTE: see context sensitive help technote (CSHELP.DOC)

         **    m_fMenuHelpMode flag is set when F1 is pressed when a

         **    menu item is selected. this flag is set in

         **    IOleInPlaceFrame::ContextSensitveHelp method.

         **    m_fCSHelpMode flag is set when SHIFT-F1 context

         **    sensitive help is entered. this flag is set in

         **    IOleInPlaceSite::ContextSensitiveHelp method.

         **    if either of these flags are set then the WM_COMMAND

         **    message is received then, the corresponding command

         **    should NOT executed; help can be given (if desired).

         **    also the context sensitve help mode should be exited.

         **    the two different cases have their own way to exit

         **    the mode (please refer to the technote).

         */

         if (lpOleDoc &&

            (lpContainerApp->m_fMenuHelpMode||lpOleDoc->m_fCSHelpMode) &&

            (wID > IDM_FILE)   /* min wID for app command */ &&

            (wID!=IDM_FB_EDIT) /* special wID to control FormulaBar */ ) {

            if ((lpContainerApp->m_fMenuHelpMode)) {

               LPOLEINPLACEACTIVEOBJECT lpIPActiveObj =

                     lpContainerApp->m_lpIPActiveObj;

               lpContainerApp->m_fMenuHelpMode = FALSE;

               // inform the in-place active object that we handled the

               //   menu help mode (F1) selection.

               if (lpIPActiveObj) {

                  OLEDBG_BEGIN2("IOleInPlaceActiveObject::ContextSensitiveHelp(FALSE) called\r\n")

                  lpIPActiveObj->lpVtbl->ContextSensitiveHelp(

                        lpIPActiveObj, FALSE);

                  OLEDBG_END2

               }

            }

            if ((lpOleDoc->m_fCSHelpMode)) {

               LPOLEINPLACEOBJECT lpIPObj;

               LPCONTAINERLINE lpLastIpActiveLine =

                     lpContainerDoc->m_lpLastIpActiveLine;

               lpOleDoc->m_fCSHelpMode = FALSE;

               /* inform immediate in-place container parent and,

               **    if we were a container/server, immediate

               **    in-place object children that we handled the

               **    context sensitive help mode.

               */

               if (lpLastIpActiveLine &&

                     (lpIPObj=lpLastIpActiveLine->m_lpOleIPObj)!=NULL){

                  OLEDBG_BEGIN2("IOleInPlaceObject::ContextSensitiveHelp(FALSE) called\r\n")

                  lpIPObj->lpVtbl->ContextSensitiveHelp(lpIPObj, FALSE);

                  OLEDBG_END2

               }

            }

            // if we provided help, we would do it here...

            // remove context sensitive help cursor

            SetCursor(LoadCursor(NULL,IDC_ARROW));

            return 0L;

         }

#endif  // INPLACE_CNTR

         switch (wID) {

            /*********************************************************

            ** File new, open, save and print as well as Help about

            **    are duplicated in this switch statement and they are

            **    used to trap the message from the toolbar

            **

            *********************************************************/

            case IDM_F_NEW:

               OleDbgIndent(-2);   // Reset debug output indent level

               OleDbgOutNoPrefix2("\r\n");

               OLEDBG_BEGIN3("OutlineApp_NewCommand\r\n")

               OutlineApp_NewCommand(lpOutlineApp);

               OLEDBG_END3

#if defined( OLE_CNTR )

               /* OLE2NOTE: this call will attempt to recover

               **    resources by unloading DLL's that were loaded

               **    by OLE and are no longer being used. it is a

               **    good idea to call this API now and then if

               **    your app tends to run for a long time.

               **    otherwise these DLL's will be unloaded when

               **    the app exits. some apps may want to call

               **    this as part of idle-time processing. this

               **    call is optional.

               */

               OLEDBG_BEGIN2("CoFreeUnusedLibraries called\r\n")

               CoFreeUnusedLibraries();

               OLEDBG_END2

#endif

#if defined( USE_FRAMETOOLS )

               OutlineDoc_UpdateFrameToolButtons(

                     OutlineApp_GetActiveDoc(lpOutlineApp));

#endif

               break;

            case IDM_F_OPEN:

               OleDbgOutNoPrefix2("\r\n");

               OLEDBG_BEGIN3("OutlineApp_OpenCommand\r\n")

               OutlineApp_OpenCommand(lpOutlineApp);

               OLEDBG_END3

#if defined( OLE_CNTR )

               /* OLE2NOTE: this call will attempt to recover

               **    resources by unloading DLL's that were loaded

               **    by OLE and are no longer being used. it is a

               **    good idea to call this API now and then if

               **    your app tends to run for a long time.

               **    otherwise these DLL's will be unloaded when

               **    the app exits. some apps may want to call

               **    this as part of idle-time processing. this

               **    call is optional.

               */

               OLEDBG_BEGIN2("CoFreeUnusedLibraries called\r\n")

               CoFreeUnusedLibraries();

               OLEDBG_END2

#endif

#if defined( USE_FRAMETOOLS )

               OutlineDoc_UpdateFrameToolButtons(

                     OutlineApp_GetActiveDoc(lpOutlineApp));

#endif

               break;

            case IDM_F_SAVE:

               OleDbgOutNoPrefix2("\r\n");

               OLEDBG_BEGIN3("OutlineApp_SaveCommand\r\n")

               OutlineApp_SaveCommand(lpOutlineApp);

               OLEDBG_END3

               break;

            case IDM_F_PRINT:

               OleDbgOutNoPrefix2("\r\n");

               OLEDBG_BEGIN3("OutlineApp_PrintCommand\r\n")

               OutlineApp_PrintCommand(lpOutlineApp);

               OLEDBG_END3

               break;

            case IDM_E_UNDO:

               // SORRY. NOT IMPLEMENTED

               break;

            case IDM_E_CUT:

               OleDbgOutNoPrefix2("\r\n");

               OLEDBG_BEGIN3("OutlineDoc_CutCommand\r\n")

               OutlineDoc_CutCommand(lpOutlineDoc);

               OLEDBG_END3

#if defined( USE_FRAMETOOLS )

               OutlineDoc_UpdateFrameToolButtons(lpOutlineDoc);

#endif

               break;

            case IDM_E_COPY:

               OleDbgOutNoPrefix2("\r\n");

               OLEDBG_BEGIN3("OutlineDoc_CopyCommand\r\n")

               OutlineDoc_CopyCommand(lpOutlineDoc);

               OLEDBG_END3

#if defined( USE_FRAMETOOLS )

               OutlineDoc_UpdateFrameToolButtons(lpOutlineDoc);

#endif

               break;

            case IDM_E_PASTE:

               OleDbgOutNoPrefix2("\r\n");

               OLEDBG_BEGIN3("OutlineDoc_PasteCommand\r\n")

               OutlineDoc_PasteCommand(lpOutlineDoc);

               OLEDBG_END3

#if defined( USE_FRAMETOOLS )

               OutlineDoc_UpdateFrameToolButtons(lpOutlineDoc);

#endif

               break;

#if defined( OLE_VERSION )

            case IDM_E_PASTESPECIAL:

               OleDbgOutNoPrefix2("\r\n");

               OLEDBG_BEGIN3("OleDoc_PasteSpecialCommand\r\n")

               OleDoc_PasteSpecialCommand((LPOLEDOC)lpOutlineDoc);

               OLEDBG_END3

#if defined( USE_FRAMETOOLS )

               OutlineDoc_UpdateFrameToolButtons(lpOutlineDoc);

#endif

               break;

#endif  // OLE_VERSION

            case IDM_E_CLEAR:

               OleDbgOutNoPrefix2("\r\n");

               OLEDBG_BEGIN3("OutlineDoc_ClearCommand\r\n")

               OutlineDoc_ClearCommand(lpOutlineDoc);

               OLEDBG_END3

#if defined( OLE_CNTR )

               /* OLE2NOTE: this call will attempt to recover

               **    resources by unloading DLL's that were loaded

               **    by OLE and are no longer being used. it is a

               **    good idea to call this API now and then if

               **    your app tends to run for a long time.

               **    otherwise these DLL's will be unloaded when

               **    the app exits. some apps may want to call

               **    this as part of idle-time processing. this

               **    call is optional.

               */

               OLEDBG_BEGIN2("CoFreeUnusedLibraries called\r\n")

               CoFreeUnusedLibraries();

               OLEDBG_END2

#endif

#if defined( USE_FRAMETOOLS )

               OutlineDoc_UpdateFrameToolButtons(lpOutlineDoc);

#endif

               break;

            case IDM_L_ADDLINE:

               OleDbgOutNoPrefix2("\r\n");

               OLEDBG_BEGIN3("OutlineDoc_AddTextLineCommand\r\n")

               OutlineDoc_AddTextLineCommand(lpOutlineDoc);

               OLEDBG_END3

#if defined( USE_FRAMETOOLS )

               OutlineDoc_UpdateFrameToolButtons(lpOutlineDoc);

               SetFocus(LineList_GetWindow(lpLL));

#endif

               break;

            case IDM_L_EDITLINE:

               OleDbgOutNoPrefix2("\r\n");

               OLEDBG_BEGIN3("OutlineDoc_EditLineCommand\r\n")

               OutlineDoc_EditLineCommand(lpOutlineDoc);

               OLEDBG_END3

               SetFocus(LineList_GetWindow(lpLL));

               break;

            case IDM_L_INDENTLINE:

               OleDbgOutNoPrefix2("\r\n");

               OLEDBG_BEGIN3("OutlineDoc_IndentCommand\r\n")

               OutlineDoc_IndentCommand(lpOutlineDoc);

               OLEDBG_END3

               break;

            case IDM_L_UNINDENTLINE:

               OleDbgOutNoPrefix2("\r\n");

               OLEDBG_BEGIN3("OutlineDoc_UnindentCommand\r\n")

               OutlineDoc_UnindentCommand(lpOutlineDoc);

               OLEDBG_END3

               break;

            case IDM_L_SETLINEHEIGHT:

               OleDbgOutNoPrefix2("\r\n");

               OLEDBG_BEGIN3("OutlineDoc_SetLineHeight\r\n")

               OutlineDoc_SetLineHeightCommand(lpOutlineDoc);

               OLEDBG_END3

               break;

            case IDM_E_SELECTALL:

               OleDbgOutNoPrefix2("\r\n");

               OLEDBG_BEGIN3("OutlineDoc_SelectAllCommand\r\n")

               OutlineDoc_SelectAllCommand(lpOutlineDoc);

               OLEDBG_END3

               break;

#if defined( OLE_CNTR )

            case IDM_E_INSERTOBJECT:

               OleDbgOutNoPrefix2("\r\n");

               OLEDBG_BEGIN3("ContainerDoc_InsertOleObjectCommand\r\n")

               ContainerDoc_InsertOleObjectCommand(lpContainerDoc);

               OLEDBG_END3

#if defined( USE_FRAMETOOLS )

               OutlineDoc_UpdateFrameToolButtons(lpOutlineDoc);

#endif

               break;

            case IDM_E_EDITLINKS:

               OleDbgOutNoPrefix2("\r\n");

               OLEDBG_BEGIN3("ContainerDoc_EditLinksCommand\r\n")

               ContainerDoc_EditLinksCommand(lpContainerDoc);

               OLEDBG_END3

               break;

            case IDM_E_CONVERTVERB:

               OleDbgOutNoPrefix2("\r\n");

               OLEDBG_BEGIN3("ContainerDoc_ConvertCommand\r\n")

               ContainerDoc_ConvertCommand(

                     lpContainerDoc, FALSE /*fMustActivate*/);

               OLEDBG_END3

               break;

            case IDM_E_PASTELINK:

               OleDbgOutNoPrefix2("\r\n");

               OLEDBG_BEGIN3("ContainerDoc_PasteLinkCommand\r\n")

               ContainerDoc_PasteLinkCommand(lpContainerDoc);

               OLEDBG_END3

#if defined( USE_FRAMETOOLS )

               OutlineDoc_UpdateFrameToolButtons(lpOutlineDoc);

#endif

               break;

#endif  // OLE_CNTR

            case IDM_N_DEFINENAME:

               OleDbgOutNoPrefix2("\r\n");

               OLEDBG_BEGIN3("OutlineDoc_DefineNameCommand\r\n")

               OutlineDoc_DefineNameCommand(lpOutlineDoc);

               OLEDBG_END3

               break;

            case IDM_N_GOTONAME:

               OleDbgOutNoPrefix2("\r\n");

               OLEDBG_BEGIN3("OutlineDoc_GotoNameCommand\r\n")

               OutlineDoc_GotoNameCommand(lpOutlineDoc);

               OLEDBG_END3

               break;

#if defined( USE_FRAMETOOLS )

            case IDM_O_BB_TOP:

               FrameTools_BB_SetState(

                     lpOutlineDoc->m_lpFrameTools, BARSTATE_TOP);

               OutlineDoc_AddFrameLevelTools(lpOutlineDoc);

               break;

            case IDM_O_BB_BOTTOM:

               FrameTools_BB_SetState(

                     lpOutlineDoc->m_lpFrameTools, BARSTATE_BOTTOM);

               OutlineDoc_AddFrameLevelTools(lpOutlineDoc);

               break;

            case IDM_O_BB_POPUP:

               FrameTools_BB_SetState(

                     lpOutlineDoc->m_lpFrameTools, BARSTATE_POPUP);

               OutlineDoc_AddFrameLevelTools(lpOutlineDoc);

               break;

            case IDM_O_BB_HIDE:

               FrameTools_BB_SetState(

                     lpOutlineDoc->m_lpFrameTools, BARSTATE_HIDE);

               OutlineDoc_AddFrameLevelTools(lpOutlineDoc);

               break;

            case IDM_O_FB_TOP:

               FrameTools_FB_SetState(

                     lpOutlineDoc->m_lpFrameTools, BARSTATE_TOP);

               OutlineDoc_AddFrameLevelTools(lpOutlineDoc);

               break;

            case IDM_O_FB_BOTTOM:

               FrameTools_FB_SetState(

                     lpOutlineDoc->m_lpFrameTools, BARSTATE_BOTTOM);

               OutlineDoc_AddFrameLevelTools(lpOutlineDoc);

               break;

            case IDM_O_FB_POPUP:

               FrameTools_FB_SetState(

                     lpOutlineDoc->m_lpFrameTools, BARSTATE_POPUP);

               OutlineDoc_AddFrameLevelTools(lpOutlineDoc);

               break;

            case IDM_FB_EDIT:

               switch (wNotifyCode) {

                  case EN_SETFOCUS:

                     OutlineDoc_SetFormulaBarEditFocus(

                           lpOutlineDoc, TRUE);

                     OutlineDoc_UpdateFrameToolButtons(lpOutlineDoc);

                     break;

                  case EN_KILLFOCUS:

                     OutlineDoc_SetFormulaBarEditFocus(

                           lpOutlineDoc, FALSE);

                     OutlineDoc_UpdateFrameToolButtons(lpOutlineDoc);

                     break;

               }

               break;

            case IDM_FB_CANCEL:

               SetFocus(hWnd);

               break;

            case IDM_F2:

               SendMessage(hWnd, WM_COMMAND, (WPARAM)IDM_FB_EDIT,

                     MAKELONG(0, EN_SETFOCUS));

               break;

#endif  // USE_FRAMETOOLS

            case IDM_ESCAPE:

               /* ESCAPE key pressed */

#if defined( USE_FRAMETOOLS )

               if (OutlineDoc_IsEditFocusInFormulaBar(lpOutlineDoc))

                  SendMessage(

                     hWnd, WM_COMMAND,(WPARAM)IDM_FB_CANCEL,(LPARAM)0);

#endif  // USE_FRAMETOOLS

#if defined( INPLACE_SVR )

               else {

                  LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOutlineDoc;

                  /* OLE2NOTE: The standard OLE 2.0 UI convention

                  **    is to have ESCAPE key exit in-place

                  **    activation (ie. UIDeactivate). If

                  **    possible it is recommended for both

                  **    in-place servers AND in-place containers

                  **    to take responsibility to handle the

                  **    ESCAPE key accelerator. The server has

                  **    the first crack at handling accelerator

                  **    keys and normally the server should do

                  **    the UIDeactivation.

                  */

                  if (lpServerDoc->m_fUIActive) {

                     SvrDoc_IPObj_UIDeactivate( (LPOLEINPLACEOBJECT)&

                           lpServerDoc->m_OleInPlaceObject);

                  }

               }

#endif  // INPLACE_SVR

               break;

#if defined( USE_HEADING )

            case IDC_BUTTON:

               if (wNotifyCode == BN_CLICKED) {

                  SendMessage(hWnd, WM_COMMAND, IDM_E_SELECTALL, 0L);

                  SetFocus(hWnd);

               }

               break;

            case IDM_O_HEAD_SHOW:

               OutlineDoc_ShowHeading(lpOutlineDoc, TRUE);

               break;

            case IDM_O_HEAD_HIDE:

               OutlineDoc_ShowHeading(lpOutlineDoc, FALSE);

               break;

#endif  // USE_HEADING

#if defined( OLE_CNTR )

            case IDM_O_SHOWOBJECT:

            {

               LPCONTAINERDOC lpContainerDoc =

                        (LPCONTAINERDOC)lpOutlineDoc;

               BOOL        fShowObject;

               fShowObject = !ContainerDoc_GetShowObjectFlag(

                     lpContainerDoc);

               ContainerDoc_SetShowObjectFlag(

                     lpContainerDoc, fShowObject);

               LineList_ForceRedraw(lpLL, TRUE);

               break;

            }

#endif  // OLE_CNTR

#if !defined( OLE_CNTR )

            // Container does not allow zoom factors > 100%

            case IDM_V_ZOOM_400:

            case IDM_V_ZOOM_300:

            case IDM_V_ZOOM_200:

#endif      // !OLE_CNTR

            case IDM_V_ZOOM_100:

            case IDM_V_ZOOM_75:

            case IDM_V_ZOOM_50:

            case IDM_V_ZOOM_25:

               OutlineDoc_SetCurrentZoomCommand(lpOutlineDoc, wID);

               break;

            case IDM_V_SETMARGIN_0:

            case IDM_V_SETMARGIN_1:

            case IDM_V_SETMARGIN_2:

            case IDM_V_SETMARGIN_3:

            case IDM_V_SETMARGIN_4:

               OutlineDoc_SetCurrentMarginCommand(lpOutlineDoc, wID);

               break;

            case IDM_V_ADDTOP_1:

            case IDM_V_ADDTOP_2:

            case IDM_V_ADDTOP_3:

            case IDM_V_ADDTOP_4:

            {

               UINT nHeightInHimetric;

               switch (wID) {

                  case IDM_V_ADDTOP_1:

                     nHeightInHimetric = 1000;

                     break;

                  case IDM_V_ADDTOP_2:

                     nHeightInHimetric = 2000;

                     break;

                  case IDM_V_ADDTOP_3:

                     nHeightInHimetric = 3000;

                     break;

                  case IDM_V_ADDTOP_4:

                     nHeightInHimetric = 4000;

                     break;

               }

               OutlineDoc_AddTopLineCommand(

                     lpOutlineDoc, nHeightInHimetric);

               break;

            }

            case IDM_H_ABOUT:

               OutlineApp_AboutCommand(lpOutlineApp);

               break;

            case IDM_D_DEBUGLEVEL:

               SetDebugLevelCommand();

               break;

#if defined( OLE_VERSION )

            case IDM_D_INSTALLMSGFILTER:

               InstallMessageFilterCommand();

               break;

            case IDM_D_REJECTINCOMING:

               RejectIncomingCommand();

               break;

#endif  // OLE_VERSION

#if defined( INPLACE_CNTR )

            case IDM_D_INSIDEOUT:

               g_fInsideOutContainer = !g_fInsideOutContainer;

               // force all object to unload so they can start new

               // activation behavior.

               ContainerDoc_UnloadAllOleObjectsOfClass(

                     (LPCONTAINERDOC)lpOutlineDoc,

                     &CLSID_NULL,

                     OLECLOSE_SAVEIFDIRTY

               );

               OutlineDoc_ForceRedraw(lpOutlineDoc, TRUE);

               break;

#endif  // INPLACE_CNTR

#if defined( OLE_CNTR )

            case IDC_LINELIST: {

               if (wNotifyCode == LBN_DBLCLK) {

                  /* OLE2NOTE: a container should execute the

                  **    OLEIVERB_PRIMARY verb on an OLE object

                  **    when the user DBLCLK's the object.

                  */

                  int nIndex = LineList_GetFocusLineIndex(lpLL);

                  LPLINE lpLine = LineList_GetLine(lpLL, nIndex);

                  if (lpLine &&

                        Line_GetLineType(lpLine)==CONTAINERLINETYPE) {

                     MSG msg;

                     _fmemset((LPMSG)&msg,0,sizeof(msg));

                     msg.hwnd = hWnd;

                     msg.message = Message;

                     msg.wParam = wParam;

                     msg.lParam = lParam;

                     ContainerLine_DoVerb(

                           (LPCONTAINERLINE)lpLine,

                           OLEIVERB_PRIMARY,

                           (LPMSG)&msg,

                           TRUE,

                           TRUE

                     );

                  }

#if defined( INPLACE_CNTR )

                  { // BEGIN BLOCK

                     LPCONTAINERDOC lpContainerDoc =

                           (LPCONTAINERDOC) lpOutlineDoc;

                     if (lpContainerDoc->m_fAddMyUI) {

                        /* OLE2NOTE: fAddMyUI is TRUE when

                        **    there was previously an in-place

                        **    active object which got

                        **    UIDeactivated as a result of this

                        **    DBLCLK AND the DBLCLK did NOT

                        **    result in in-place activating

                        **    another object.

                        **    (see IOleInPlaceSite::OnUIActivate and

                        **    IOleInPlaceSite::OnUIDeactivate

                        **    methods).

                        */

                        /* OLE2NOTE: You need to generate

                        **    QueryNewPalette only if you own

                        **    the top level frame (ie. you are

                        **    a top-level inplace container).

                        */

                        OleApp_QueryNewPalette((LPOLEAPP)g_lpApp);

#if defined( USE_DOCTOOLS )

                        ContainerDoc_AddDocLevelTools(lpContainerDoc);

#endif

#if defined( USE_FRAMETOOLS )

                        ContainerDoc_AddFrameLevelUI(lpContainerDoc);

#endif

                        lpContainerDoc->m_fAddMyUI = FALSE;

                     }

                  } // END BLOCK

#endif // INPLACE_CNTR

               }

               break;

            }

#endif  // OLE_CNTR

            default:

#if defined( OLE_CNTR )

               if (wID >= IDM_E_OBJECTVERBMIN) {

                  OleDbgOutNoPrefix2("\r\n");

                  OLEDBG_BEGIN3("ContainerDoc_ContainerLineDoVerbCommand\r\n")

                  ContainerDoc_ContainerLineDoVerbCommand(

                        (LPCONTAINERDOC)lpOutlineDoc,

                        (LONG)(wID-IDM_E_OBJECTVERBMIN)

                  );

                  OLEDBG_END3

                  break;

               }

#endif  // OLE_CNTR

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

         }

         break;  /* End of WM_COMMAND */

      }

      default:

         if (Message == g_uMsgHelp) {

            /* Handle OLE2UI dialog's help messages.

            ** We get the hDlg of the dialog that called us in the wParam

            ** and the dialog type in the LOWORD of the lParam,

            ** so we pass this along to our help function.

            */

            OutlineDoc_DialogHelp((HWND)wParam, LOWORD(lParam));

            break;

         }

         /* For any message for which you don't specifically provide a  */

         /* service routine, you should return the message to Windows   */

         /* for default message processing.                             */

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

   }

   return (LRESULT)0;

} /* End of DocWndProc */

//***********************************************************************

//*

//* LineListWndProc()  Drag and Drop Listbox Window Proc Sub-Class

//*

//* Sub Class the Ownerdraw list box in order to activate the drag drop.

//***********************************************************************

LRESULT FAR PASCAL LineListWndProc(

   HWND   hWnd,

   UINT   Message,

   WPARAM wParam,

   LPARAM lParam

)

{

   HWND         hwndParent = GetParent ( hWnd );

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC) GetWindowLong( hwndParent, 0 );

   LPLINELIST   lpLL = OutlineDoc_GetLineList(lpOutlineDoc);

#if defined( OLE_VERSION )

   LPOLEAPP     lpOleApp = (LPOLEAPP)lpOutlineApp;

   LPOLEDOC     lpOleDoc = (LPOLEDOC)lpOutlineDoc;

#endif  // OLE_VERSION

#if defined( INPLACE_SVR )

   LPSERVERDOC  lpServerDoc = (LPSERVERDOC)lpOutlineDoc;

   static BOOL  fUIActivateClick = FALSE;

   static BOOL  fInWinPosChged = FALSE;

#endif  // INPLACE_SVR

#if defined( INPLACE_CNTR )

   LPCONTAINERAPP lpContainerApp=(LPCONTAINERAPP)lpOutlineApp;

   LPCONTAINERDOC lpContainerDoc=(LPCONTAINERDOC)lpOutlineDoc;

#endif  // INPLACE_CNTR

   switch (Message) {

      case WM_KILLFOCUS:

         /* OLE2NOTE: when our window looses focus we

         **    should not display any active selection

         */

#if defined( INPLACE_CNTR )

         if (! lpContainerApp->m_fPendingUIDeactivate)

#endif  // INPLACE_CNTR

            LineList_RemoveSel(lpLL);

         break;

      case WM_SETFOCUS:

#if defined( INPLACE_CNTR )

         {

            HWND hWndObj=ContainerDoc_GetUIActiveWindow(lpContainerDoc);

            /* OLE2NOTE: if there is a UIActive in-place object, we must

            **    forward focus to its window as long as there is

            **    not a pending UIDeactivate. if the mouse is

            **    clicked outside of the object and the object is

            **    about to be deactivated then we do NOT want to

            **    forward focus to the object. we do NOT want it to

            **    restore its selection feedback.

            */

            if (lpContainerApp->m_fPendingUIDeactivate)

               break;

            else if (hWndObj) {

               SetFocus(hWndObj);

               break;      // do not restore containers selection state

            }

         }

#endif  // INPLACE_CNTR

         /* OLE2NOTE: when our window gains focus we

         **    should restore the previous selection

         */

         LineList_RestoreSel(lpLL);

         break;

#if defined( INPLACE_SVR )

      case WM_MOUSEACTIVATE:

      {

         if (lpServerDoc->m_fInPlaceActive && !lpServerDoc->m_fUIActive) {

            fUIActivateClick = TRUE;

         };

         break;

      }

#endif  // INPLACE_SVR

#if defined( USE_FRAMETOOLS )

      case WM_CHAR:

      {

         OutlineDoc_SetFormulaBarEditFocus(lpOutlineDoc, TRUE);

         FrameTools_FB_SetEditText(lpOutlineDoc->m_lpFrameTools, NULL);

         FrameTools_FB_SendMessage(

               lpOutlineDoc->m_lpFrameTools,

               IDM_FB_EDIT,

               Message,

               wParam,

               lParam

         );

         return (LRESULT)0;   // don't do default listbox processing

      }

#endif  // USE_FRAMETOOLS

#if defined( INPLACE_CNTR )

      case WM_VSCROLL:

      {

         if (wParam == SB_ENDSCROLL) {

            /* OLE2NOTE: after scrolling finishes, update position of

            **    in-place visible windows.

            **    (ICNTROTL specific) we first let the ListBox

            **    perform it normal processing with the EndScroll

            **    message. also we let the ListBox handle all other

            **    scroll messages.

            */

            LRESULT lResult =  CallWindowProc(

                  (WNDPROC)lpOutlineApp->m_ListBoxWndProc,

                  hWnd,

                  Message,

                  wParam,

                  lParam

            );

            ContainerDoc_UpdateInPlaceObjectRects(lpContainerDoc, 0);

            return lResult;

         }

         break;

      }

#endif  // INPLACR_CNTR

#if defined( USE_HEADING )

      case WM_HSCROLL:

      {

         LPHEADING lphead = OutlineDoc_GetHeading(lpOutlineDoc);

         Heading_CH_SendMessage(lphead, Message, wParam, lParam);

         break;

      }

      /* NOTE: WM_PAINT trapped in order to track vertical scrolling

      **    that has taken place so the row headings can be

      **    coordinated with the LineList. we wanted to trap instead

      **    but it is not generated from scrolling without using

      **    scroll bar (e.g. use keyboard).

      */

      case WM_PAINT:

      {

         Heading_RH_Scroll(OutlineDoc_GetHeading(lpOutlineDoc), hWnd);

         break;

      }

#endif  // USE_HEADING

      case WM_LBUTTONUP:

      {

#if defined( USE_DRAGDROP )

         if (lpOleDoc->m_fPendingDrag) {

            /* ButtonUP came BEFORE distance/time threshholds were

            **    exceeded. clear fPendingDrag state.

            */

            ReleaseCapture();

            KillTimer(hWnd, 1);

            lpOleDoc->m_fPendingDrag = FALSE;

         }

#endif  // USE_DRAGDROP

#if defined( INPLACE_SVR )

         if (fUIActivateClick) {

            fUIActivateClick = FALSE;

            ServerDoc_UIActivate((LPSERVERDOC) lpOleDoc);

         }

#endif  // INPLACE_SVR

#if defined( INPLACE_CNTR )

         {

            /* check if a UIDeactivate is pending.

            **      (see comment in WM_LBUTTONDOWN)

            */

            if ( lpContainerApp->m_fPendingUIDeactivate ) {

               ContainerLine_UIDeactivate(

                     lpContainerDoc->m_lpLastUIActiveLine);

               lpContainerApp->m_fPendingUIDeactivate = FALSE;

            }

         }

#endif  // INPLACE_CNTR

         break;

      }

      case WM_LBUTTONDOWN:

      {

         POINT pt;

         pt.x = (int)(short)LOWORD (lParam );

         pt.y = (int)(short)HIWORD (lParam );

#if defined( INPLACE_SVR ) || defined( INPLACE_CNTR )

         /* OLE2NOTE: see context sensitive help technote (CSHELP.DOC)

         **    m_fCSHelpMode flag is set when SHIFT-F1 context

         **    sensitive help is entered.

         **    if this flag is set then the button click should not

         **    cause any action. if the application implements a

         **    help system, then context sensitive help should be

         **    given for the location clicked by the user.

         */

         if (lpOleDoc->m_fCSHelpMode) {

            return (LRESULT)0;   // eat the button click because we do

                            // not give any help.

         }

#endif  // INPLACE_SVR || INPLACE_CNTR

#if defined( INPLACE_CNTR )

         {

            /* OLE2NOTE: both inside-out and outside-in style

            **    containers must check if the mouse click is

            **    outside of the current UIActive object (if

            **    any). If so, then set the flag indicating that

            **    there is a pending UIDeactivate needed. We do NOT

            **    want to do it now,

            **    because that would result in un-wanted movement of

            **    the data on the screen as frame adornments (eg.

            **    toolbar) and/or object adornments (eg. ruler) would

            **    be removed from the screen. we want to defer the

            **    UIDeactivate till the mouse up event. The listbox's

            **    default processing captures the mouse on button down

            **    so that it is sure to get the button up message.

            **

            **    SPECIAL NOTE: there is potential interaction here

            **    with Drag/Drop. if this button down event actually

            **    starts a Drag/Drop operation, then OLE does the mouse

            **    capture. in this situation we will NOT get our button

            **    up event. we must instead perform the UIDeactivate

            **    when the drop operation finishes

            */

            lpContainerApp->m_fPendingUIDeactivate =

                  ContainerDoc_IsUIDeactivateNeeded(lpContainerDoc, pt);

         }

#endif  // INPLACE_CNTR

#if defined( USE_DRAGDROP )

         /* OLE2NOTE: check if this is a button down on the region

         **    that is a handle to start a drag operation. for us,

         **    this this the top/bottom border of the selection.

         **    do NOT want to start a drag immediately; we want to

         **    wait until the mouse moves a certain threshold. if

         **    LButtonUp comes before mouse move to start drag, then

         **    the fPendingDrag state is cleared. we must capture

         **    the mouse to ensure the modal state is handled

         **    properly.

         */

         if ( OleDoc_QueryDrag(lpOleDoc, pt.y) ) {

            lpOleDoc->m_fPendingDrag = TRUE;

            lpOleDoc->m_ptButDown = pt;

            SetTimer(hWnd, 1, lpOleApp->m_nDragDelay, NULL);

            SetCapture(hWnd);

            /* We do NOT want to do the listbox's default

            **    processing which would be to capture the mouse

            **    and enter a modal multiple selection state until

            **    a mouse up occurs. we have just finished a modal

            **    drag/drop operation where OLE has captured the

            **    mouse. thus by now the mouse up has already occured.

            */

            return (LRESULT)0;   // don't do default listbox processing

         }

#endif  // USE_DRAGDROP

         break;

      }

      case WM_MOUSEMOVE: {

#if defined( USE_DRAGDROP )

         int  x = (int)(short)LOWORD (lParam );

         int  y = (int)(short)HIWORD (lParam );

         POINT pt = lpOleDoc->m_ptButDown;

         int nDragMinDist = lpOleApp->m_nDragMinDist;

         if (lpOleDoc->m_fPendingDrag) {

            if (! ( ((pt.x - nDragMinDist) <= x)

                  && (x <= (pt.x + nDragMinDist))

                  && ((pt.y - nDragMinDist) <= y)

                  && (y <= (pt.y + nDragMinDist)) ) ) {

               DWORD dwEffect;

               // mouse moved beyond threshhold to start drag

               ReleaseCapture();

               KillTimer(hWnd, 1);

               lpOleDoc->m_fPendingDrag = FALSE;

               // perform the modal drag/drop operation.

               dwEffect = OleDoc_DoDragDrop( lpOleDoc );

#if defined( INPLACE_CNTR )

               {

                  /* if necessary UIDeactive the in-place object.

                  **    this applies to outside-in style

                  **    container only.

                  **    (see comment above)

                  */

                  if (lpContainerApp->m_fPendingUIDeactivate) {

                     lpContainerApp->m_fPendingUIDeactivate = FALSE;

                     // do not UIDeactivate if drag/drop was canceled

                     if (dwEffect != DROPEFFECT_NONE)

                        ContainerLine_UIDeactivate(

                              lpContainerDoc->m_lpLastUIActiveLine

                        );

                  }

               }

#endif  // INPLACE_CNTR

               return (LRESULT)0; // don't do default listbox process

            }

            else {

               /* cursor did not move from initial mouse down

               **    (pending drag) point.

               */

               return (LRESULT)0; // don't do default listbox process

            }

         }

#endif  // USE_DRAGDROP

#if defined( INPLACE_CNTR )

         { // BEGIN BLOCK

            if (lpContainerDoc->m_fAddMyUI) {

               /* OLE2NOTE: fAddMyUI is TRUE when

               **    there was previously an in-place

               **    active object which got

               **    UIDeactivated as a result of a

               **    DBLCLK AND the DBLCLK did NOT

               **    result in in-place activating

               **    another object.

               **    (see IOleInPlaceSite::OnUIActivate and

               **    IOleInPlaceSite::OnUIDeactivate

               **    methods).

               */

#if defined( USE_DOCTOOLS )

               ContainerDoc_AddDocLevelTools(lpContainerDoc);

#endif

#if defined( USE_FRAMETOOLS )

               ContainerDoc_AddFrameLevelUI(lpContainerDoc);

#endif

               lpContainerDoc->m_fAddMyUI = FALSE;

            }

         } // END BLOCK

#endif // INPLACE_CNTR

         break;

      }

#if defined( USE_DRAGDROP )

      case WM_TIMER:

      {

         DWORD dwEffect;

         // drag time delay threshhold exceeded -- start drag

         ReleaseCapture();

         KillTimer(hWnd, 1);

         lpOleDoc->m_fPendingDrag = FALSE;

         // perform the modal drag/drop operation.

         dwEffect = OleDoc_DoDragDrop( lpOleDoc );

#if defined( INPLACE_CNTR )

         /* if necessary UIDeactive the in-place object.

         **    this applies to outside-in style

         **    container only.

         **    (see comment above)

         */

         if (lpContainerApp->m_fPendingUIDeactivate) {

            lpContainerApp->m_fPendingUIDeactivate = FALSE;

            // do not UIDeactivate if drag/drop was canceled

            if (dwEffect != DROPEFFECT_NONE)

               ContainerLine_UIDeactivate(

                     lpContainerDoc->m_lpLastUIActiveLine);

         }

#endif  // INPLACE_CNTR

         break;

      }

#endif  // USE_DRAGDROP

      case WM_SETCURSOR:

      {

         RECT rc;

         POINT ptCursor;

#if defined( INPLACE_SVR ) || defined( INPLACE_CNTR )

         /* OLE2NOTE: see context sensitive help technote (CSHELP.DOC)

         **    m_fCSHelpMode flag is set when SHIFT-F1 context

         **    sensitive help is entered.

         **    if this flag is set then the context sensitive help

         **    cursor should be shown.

         */

         if (lpOleDoc->m_fCSHelpMode) {

            SetCursor(UICursorLoad(IDC_CONTEXTHELP));

            return (LRESULT)TRUE;

         }

#endif  // INPLACE_SVR || INPLACE_CNTR

         GetCursorPos((POINT FAR*)&ptCursor);

         ScreenToClient(hWnd, (POINT FAR*)&ptCursor);

         GetClientRect(hWnd, (LPRECT)&rc);

         // use arrow cursor if in scroll bar

         if (! PtInRect((LPRECT)&rc, ptCursor) )

            SetCursor(LoadCursor(NULL, IDC_ARROW) );

#if defined( USE_DRAGDROP )

         // use arrow cursor if on drag handle (top/bottom of selection)

         else if ( OleDoc_QueryDrag ( lpOleDoc, ptCursor.y) )

            SetCursor(LoadCursor(NULL, IDC_ARROW) );

#endif  // USE_DRAGDROP

         else

            SetCursor(lpOutlineApp->m_hcursorSelCur);

         return (LRESULT)TRUE;

      }

#if defined( INPLACE_SVR )

      /* The handling of WM_WINDOWPOSCHANGED message is ISVROTL

      **    application specific. The nature of the owner-draw list

      **    box used by the ISVROTL application causes a recursive

      **    call to this message in some situations when in-place

      **    active. in order not to crash this recursive call must be

      **    guarded.

      */

      case WM_WINDOWPOSCHANGED:

      {

         WINDOWPOS FAR* lpWinPos = (WINDOWPOS FAR*) lParam;

         LRESULT lResult;

         // guard against recursive call

         if (fInWinPosChged)

            return (LRESULT)0;

         fInWinPosChged = TRUE;

         lResult = CallWindowProc(

               (WNDPROC)lpOutlineApp->m_ListBoxWndProc,

               hWnd,

               Message,

               wParam,

               lParam

         );

         fInWinPosChged = FALSE;

         return lResult;

      }

#endif  // INPLACE_SVR

   }

   return CallWindowProc(

         (WNDPROC)lpOutlineApp->m_ListBoxWndProc,

         hWnd,

         Message,

         wParam,

         lParam

   );

}

// Utility function to count the number of accelerator items in an

//  accelerator table.  A number of OLE APIs need this count, so

//  this can be quite handy.

// (code shamelessly stolen from the Microsoft Foundation Classes)

int GetAccelItemCount(HACCEL hAccel)

{

#if defined( WIN32 )

    return CopyAcceleratorTable(hAccel, NULL, 0);

#else

   #pragma pack(1)

   typedef struct tagACCELERATOR

   {

      BYTE    fFlags;

      WORD    wEvent;

      WORD    wID;

   } ACCELERATOR;

   #pragma pack()

   // attempt to lock down the accelerator resource

   ACCELERATOR FAR* pAccel;

   int cAccelItems = 1;

   if (hAccel == NULL ||

      (pAccel = (ACCELERATOR FAR*)LockResource((HGLOBAL)hAccel)) == NULL)

   {

      // NULL accerator table or LockResource failed on the HACCEL,

      //  no accelerators

      return 0;

   }

   // otherwise, count them -- last entry in accel table has 0x80 bit set

   while ((pAccel->fFlags & 0x80) == 0)

   {

      ++cAccelItems;

      ++pAccel;

   }

   UnlockResource((HGLOBAL)hAccel);

   return cAccelItems;

#endif

}


MEMMGR.C  (OUTLINE Sample)

/*************************************************************************

**

**    OLE 2 Sample Code

**

**    memmgr.c

**

**    This file contains memory management functions.

**

**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

**

*************************************************************************/

#include "outline.h"

/* New

 * ---

 *

 *      Allocate memory for a new structure

 */

LPVOID New(DWORD lSize)

{

LPVOID lp = OleStdMalloc((ULONG)lSize);

return lp;

}

/* Delete

 * ------

 *

 *      Free memory allocated for a structure

 */

void Delete(LPVOID lp)

{

OleStdFree(lp);

}


MESSAGE.H  (OUTLINE Sample)

/*************************************************************************

**

**    OLE 2.0 Server Sample Code

**

**    message.h

**

**    This file is a user customizable list of status messages associated

**    with menu items.

**

**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

**

*************************************************************************/

// Status bar messages and associated data.

// Message type for status bar messages.

typedef struct {

UINT wIDItem;

char *string;

} STATMESG;

/*

 * CUSTOMIZATION NOTE:  Be sure to change NUM_POPUP if you

 *                      change the number of popup messages.

 */

// REVIEW: these messages should be loaded from a string resource

// List of all menu item messages.

STATMESG MesgList[] =

{

{ IDM_F_NEW,        "Creates a new outline" },

{ IDM_F_OPEN,       "Opens an existing outline file"    },

{ IDM_F_SAVE,       "Saves the outline" },

{ IDM_F_SAVEAS,     "Saves the outline with a new name" },

{ IDM_F_PRINT,      "Prints the outline" },

{ IDM_F_PRINTERSETUP, "Changes the printer and the printing options" },

{ IDM_F_EXIT,       "Quits the application, prompting to save changes" },

{ IDM_E_UNDO,       "Undo not yet implemented" },

{ IDM_E_CUT,        "Cuts the selection and puts it on the Clipboard" },

{ IDM_E_COPY,       "Copies the selection and puts it on the Clipboard" },

{ IDM_E_PASTE,      "Inserts the Clipboard contents after current line" },

{ IDM_E_PASTESPECIAL,"Allows pasting Clipboard data using a special format" },

{ IDM_E_CLEAR,      "Clears the selection" },

{ IDM_E_SELECTALL,  "Selects the entire outline" },

#if defined( OLE_CNTR )

{ IDM_E_INSERTOBJECT, "Inserts new object after current line" },

{ IDM_E_EDITLINKS, "Edit and view links contained in the document" },

   { IDM_E_CONVERTVERB, "Converts or activates an object as another type" },

{ IDM_E_OBJECTVERBMIN, "Opens, edits or interacts with an object" },

{ IDM_E_OBJECTVERBMIN+1, "Opens, edits or interacts with an object1" },

{ IDM_E_OBJECTVERBMIN+2, "Opens, edits or interacts with an object2" },

{ IDM_E_OBJECTVERBMIN+3, "Opens, edits or interacts with an object3" },

{ IDM_E_OBJECTVERBMIN+4, "Opens, edits or interacts with an object4" },

{ IDM_E_OBJECTVERBMIN+5, "Opens, edits or interacts with an object5" },

#endif

{ IDM_L_ADDLINE,    "Adds a new line after current line" },

{ IDM_L_EDITLINE,   "Edits the current line" },

{ IDM_L_INDENTLINE, "Indents the selection" },

{ IDM_L_UNINDENTLINE, "Unindents the selection" },

{ IDM_L_SETLINEHEIGHT, "Modify the height of a line" },

{ IDM_N_DEFINENAME, "Assigns a name to the selection" },

{ IDM_N_GOTONAME,   "Jumps to a specified place in the outline" },

{ IDM_H_ABOUT,      "Displays program info, version no., and copyright" },

{ IDM_D_DEBUGLEVEL,     "Set debug level (0-4)" },

{ IDM_D_INSTALLMSGFILTER,"Install/deinstall the IMessageFilter" },

{ IDM_D_REJECTINCOMING, "Return RETRYLATER to incoming method calls" },

{ IDM_O_BB_TOP, "Position ButtonBar at top of window" },

{ IDM_O_BB_BOTTOM, "Position ButtonBar at botttom of window" },

{ IDM_O_BB_POPUP, "Put ButtonBar in popup pallet" },

{ IDM_O_BB_HIDE, "Hide ButtonBar" },

{ IDM_O_FB_TOP, "Position FormulaBar at top of window" },

{ IDM_O_FB_BOTTOM, "Position FormulaBar at botttom of window" },

{ IDM_O_FB_POPUP, "Put FormulaBar in popup pallet" },

{ IDM_O_HEAD_SHOW, "Show row/column headings" },

{ IDM_O_HEAD_HIDE, "Hide row/column headings" },

{ IDM_O_SHOWOBJECT, "Show border around objects/links" },

{ IDM_V_ZOOM_400, "Set document zoom level" },

{ IDM_V_ZOOM_300, "Set document zoom level" },

{ IDM_V_ZOOM_200, "Set document zoom level" },

{ IDM_V_ZOOM_100, "Set document zoom level" },

{ IDM_V_ZOOM_75, "Set document zoom level" },

{ IDM_V_ZOOM_50, "Set document zoom level" },

{ IDM_V_ZOOM_25, "Set document zoom level" },

{ IDM_V_SETMARGIN_0, "Remove left/right document margins" },

{ IDM_V_SETMARGIN_1, "Set left/right document margins" },

{ IDM_V_SETMARGIN_2, "Set left/right document margins" },

{ IDM_V_SETMARGIN_3, "Set left/right document margins" },

{ IDM_V_SETMARGIN_4, "Set left/right document margins" },

{ IDM_V_ADDTOP_1, "Add top line" },

{ IDM_V_ADDTOP_2, "Add top line" },

{ IDM_V_ADDTOP_3, "Add top line" },

{ IDM_V_ADDTOP_4, "Add top line" }

};

#define NUM_STATS   sizeof(MesgList)/sizeof(MesgList[0])

#define NUM_POPUP   10  // Maximum number of popup messages.

#define MAX_MESSAGE 100 // Maximum characters in a popup message.


OLEAPP.C  (OUTLINE Sample)

/*************************************************************************

**

**    OLE 2 Sample Code

**

**    oleapp.c

**

**    This file contains functions and methods that are common to

**    server and the client version of the app. This includes the class

**    factory methods and all OleApp functions.

**

**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

**

*************************************************************************/

#include "outline.h"

#include <ole2ver.h>

OLEDBGDATA

extern LPOUTLINEAPP             g_lpApp;

extern IUnknownVtbl             g_OleApp_UnknownVtbl;

extern IUnknownVtbl             g_OleDoc_UnknownVtbl;

extern IPersistFileVtbl         g_OleDoc_PersistFileVtbl;

extern IOleItemContainerVtbl    g_OleDoc_OleItemContainerVtbl;

extern IExternalConnectionVtbl  g_OleDoc_ExternalConnectionVtbl;

extern IDataObjectVtbl          g_OleDoc_DataObjectVtbl;

#if defined( USE_DRAGDROP )

extern IDropTargetVtbl          g_OleDoc_DropTargetVtbl;

extern IDropSourceVtbl          g_OleDoc_DropSourceVtbl;

#endif  // USE_DRAGDROP

#if defined( OLE_SERVER )

extern IOleObjectVtbl       g_SvrDoc_OleObjectVtbl;

extern IPersistStorageVtbl  g_SvrDoc_PersistStorageVtbl;

#if defined( SVR_TREATAS )

extern IStdMarshalInfoVtbl  g_SvrDoc_StdMarshalInfoVtbl;

#endif  // SVR_TREATAS

extern IUnknownVtbl         g_PseudoObj_UnknownVtbl;

extern IOleObjectVtbl       g_PseudoObj_OleObjectVtbl;

extern IDataObjectVtbl      g_PseudoObj_DataObjectVtbl;

#if defined( INPLACE_SVR )

extern IOleInPlaceObjectVtbl        g_SvrDoc_OleInPlaceObjectVtbl;

extern IOleInPlaceActiveObjectVtbl  g_SvrDoc_OleInPlaceActiveObjectVtbl;

#endif  // INPLACE_SVR

#endif  // OLE_SERVER

#if defined( OLE_CNTR )

extern IOleUILinkContainerVtbl  g_CntrDoc_OleUILinkContainerVtbl;

extern IUnknownVtbl             g_CntrLine_UnknownVtbl;

extern IOleClientSiteVtbl       g_CntrLine_OleClientSiteVtbl;

extern IAdviseSinkVtbl          g_CntrLine_AdviseSinkVtbl;

#if defined( INPLACE_CNTR )

extern IOleInPlaceSiteVtbl      g_CntrLine_OleInPlaceSiteVtbl;

extern IOleInPlaceFrameVtbl     g_CntrApp_OleInPlaceFrameVtbl;

extern BOOL g_fInsideOutContainer;

#endif  // INPLACE_CNTR

#endif  // OLE_CNTR

// REVIEW: these are NOT useful end-user messages

static OLECHAR ErrMsgCreateCF[] = OLESTR("Can't create Class Factory!");

static OLECHAR ErrMsgRegCF[] = OLESTR("Can't register Class Factory!");

static OLECHAR ErrMsgRegMF[] = OLESTR("Can't register Message Filter!");

extern UINT g_uMsgHelp;

/* OleApp_InitInstance

 * -------------------

 *

 * Initialize the app instance by creating the main frame window and

 * performing app instance specific initializations

 *  (eg. initializing interface Vtbls).

 *

 * RETURNS: TRUE if the memory could be allocated, and the server app

 *               was properly initialized.

 *          FALSE otherwise

 *

 */

BOOL OleApp_InitInstance(LPOLEAPP lpOleApp, HINSTANCE hInst, int nCmdShow)

{

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)lpOleApp;

   HRESULT hrErr;

   DWORD   dwBuildVersion = OleBuildVersion();

   LPMALLOC lpMalloc = NULL;

   OLEDBG_BEGIN3("OleApp_InitInstance\r\n")

   lpOleApp->m_fOleInitialized = FALSE;

   /* OLE2NOTE: check if the build version of the OLE2 DLL's match

   **    what our application is expecting.

   */

   if (HIWORD(dwBuildVersion) != rmm || LOWORD(dwBuildVersion) < rup) {

      OleDbgAssertSz(0, "ERROR: OLE 2.0 DLL's are NOT compatible!");

#if !defined( _DEBUG )

      return FALSE;   // Wrong version of DLL's

#endif

   }

   /* OLE2NOTE: the OLE libraries must be properly initialized before

   **    making any calls. OleInitialize automatically calls

   **    CoInitialize. we will use the default task memory allocator

   **    therefore we pass NULL to OleInitialize.

   */

   OLEDBG_BEGIN2("OleInitialize called\r\n")

   hrErr = OleInitialize(NULL);

   OLEDBG_END2

   if (hrErr != NOERROR) {

      OutlineApp_ErrorMessage(lpOutlineApp,OLESTR("OLE initialization failed!"));

      goto error;

   }

   /*****************************************************************

   ** OLE2NOTE: we must remember the fact that OleInitialize has

   **    been call successfully. the very last thing an app must

   **    be do is properly shut down OLE by calling

   **    OleUninitialize. This call MUST be guarded! it is only

   **    allowable to call OleUninitialize if OleInitialize has

   **    been called SUCCESSFULLY.

   *****************************************************************/

   lpOleApp->m_fOleInitialized = TRUE;

   // Initialize the OLE 2.0 interface method tables.

   if (! OleApp_InitVtbls(lpOleApp))

      goto error;

   // Register OLE 2.0 clipboard formats.

   lpOleApp->m_cfEmbedSource = RegisterClipboardFormat(CF_EMBEDSOURCE);

   lpOleApp->m_cfEmbeddedObject = RegisterClipboardFormat(

         CF_EMBEDDEDOBJECT

   );

   lpOleApp->m_cfLinkSource = RegisterClipboardFormat(CF_LINKSOURCE);

   lpOleApp->m_cfFileName = RegisterClipboardFormat(CF_FILENAME);

   lpOleApp->m_cfObjectDescriptor =

         RegisterClipboardFormat(CF_OBJECTDESCRIPTOR);

   lpOleApp->m_cfLinkSrcDescriptor =

         RegisterClipboardFormat(CF_LINKSRCDESCRIPTOR);

   lpOleApp->m_cRef                    = 0;

   lpOleApp->m_cDoc                    = 0;

   lpOleApp->m_fUserCtrl               = FALSE;

   lpOleApp->m_dwRegClassFac           = 0;

   lpOleApp->m_lpClassFactory          = NULL;

   lpOleApp->m_cModalDlgActive         = 0;

   INIT_INTERFACEIMPL(

         &lpOleApp->m_Unknown,

         &g_OleApp_UnknownVtbl,

         lpOleApp

   );

#if defined( USE_DRAGDROP )

   // delay before dragging should start, in milliseconds

   lpOleApp->m_nDragDelay = GetProfileInt(

         "windows",

         "DragDelay",

         DD_DEFDRAGDELAY

   );

   // minimum distance (radius) before drag should start, in pixels

   lpOleApp->m_nDragMinDist = GetProfileInt(

         "windows",

         "DragMinDist",

         DD_DEFDRAGMINDIST

   );

   // delay before scrolling, in milliseconds

   lpOleApp->m_nScrollDelay = GetProfileInt(

         "windows",

         "DragScrollDelay",

         DD_DEFSCROLLDELAY

   );

   // inset-width of the hot zone, in pixels

   lpOleApp->m_nScrollInset = GetProfileInt(

         "windows",

         "DragScrollInset",

         DD_DEFSCROLLINSET

   );

   // scroll interval, in milliseconds

   lpOleApp->m_nScrollInterval = GetProfileInt(

         "windows",

         "DragScrollInterval",

         DD_DEFSCROLLINTERVAL

   );

#if defined( IF_SPECIAL_DD_CURSORS_NEEDED )

   // This would be used if the app wanted to have custom drag/drop cursors

   lpOleApp->m_hcursorDragNone  = LoadCursor ( hInst, "DragNoneCur" );

   lpOleApp->m_hcursorDragCopy  = LoadCursor ( hInst, "DragCopyCur" );

   lpOleApp->m_hcursorDragMove  = LoadCursor ( hInst, "DragMoveCur" );

   lpOleApp->m_hcursorDragLink  = LoadCursor ( hInst, "DragLinkCur" );

#endif  // IF_SPECIAL_DD_CURSORS_NEEDED

#endif  // USE_DRAGDROP

   lpOleApp->m_lpMsgFilter = NULL;

#if defined( USE_MSGFILTER )

   /* OLE2NOTE: Register our message filter upon app startup. the

   **    message filter is used to handle concurrency.

   **    we will use a standard implementation of IMessageFilter that

   **    is included as part of the OLE2UI library.

   */

   lpOleApp->m_lpMsgFilter = NULL;

   if (! OleApp_RegisterMessageFilter(lpOleApp))

      goto error;

   /* OLE2NOTE: because our app is initially INVISIBLE, we must

   **    DISABLE the busy dialog. we should NOT put up any dialogs if

   **    our app is invisible. when our app window is made visible,

   **    then the busy dialog will be enabled.

   */

   OleStdMsgFilter_EnableBusyDialog(lpOleApp->m_lpMsgFilter, FALSE);

#endif  // USE_MSGFILTER

#if defined( OLE_SERVER )

   /* OLE2NOTE: perform initialization specific for an OLE server */

   if (! ServerApp_InitInstance((LPSERVERAPP)lpOutlineApp, hInst, nCmdShow))

      goto error;

#endif

#if defined( OLE_CNTR )

   /* OLE2NOTE: perform initialization specific for an OLE container */

   // Register help message

   g_uMsgHelp = RegisterWindowMessage(SZOLEUI_MSG_HELP);

   if (! ContainerApp_InitInstance((LPCONTAINERAPP)lpOutlineApp, hInst, nCmdShow))

      goto error;

#endif

#if defined( OLE_CNTR )

   lpOleApp->m_hStdPal = OleStdCreateStandardPalette();

#endif

   OLEDBG_END3

   return TRUE;

error:

   OLEDBG_END3

   return FALSE;

}

/*

 * OleApp_TerminateApplication

 * ---------------------------

 *  Perform proper OLE application cleanup before shutting down

 */

void OleApp_TerminateApplication(LPOLEAPP lpOleApp)

{

   OLEDBG_BEGIN3("OleApp_TerminateApplication\r\n")

   /* OLE2NOTE: perform a clean shut down for OLE. at this point our

   **    App refcnt should be 0, or else we should never have reached

   **    this point!

   */

   OleDbgAssertSz(lpOleApp->m_cRef == 0, "App NOT shut down properly");

   if(lpOleApp->m_fOleInitialized) {

      OLEDBG_BEGIN2("OleUninitialize called\r\n")

      OleUninitialize();

      OLEDBG_END2

   }

   OLEDBG_END3

}

/* OleApp_ParseCmdLine

 * -------------------

 *

 * Parse the command line for any execution flags/arguments.

 *      OLE2NOTE: check if "-Embedding" switch is given.

 */

BOOL OleApp_ParseCmdLine(LPOLEAPP lpOleApp, LPSTR lpszCmdLine, int nCmdShow)

{

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)lpOleApp;

   char szFileName[256];   /* buffer for filename in command line */

   BOOL fStatus = TRUE;

   BOOL fEmbedding = FALSE;

   OLECHAR szUniStr[256];

   OLEDBG_BEGIN3("OleApp_ParseCmdLine\r\n")

   szFileName[0] = '\0';

   ParseCmdLine(lpszCmdLine, &fEmbedding, (LPSTR)szFileName);

#if defined( MDI_VERSION )

   /* OLE2NOTE: an MDI app would ALWAYS register its ClassFactory. it

   **    can handle multiple objects at the same time, while an SDI

   **    application can only handle a single embedded or file-based

   **    object at a time.

   */

   fStatus = OleApp_RegisterClassFactory(lpOleApp);

#endif

   if(fEmbedding) {

      if (szFileName[0] == '\0') {

         /*****************************************************************

         ** App was launched with /Embedding.

         **    We must register our ClassFactory with OLE, remain hidden

         **    (the app window is initially created not visible), and

         **    wait for OLE to call IClassFactory::CreateInstance

         **    method. We do not automatically create a document as we

         **    do when the app is launched by the user from the

         **    FileManager. We must NOT make our app window visible

         **    until told to do so by our container.

         **

         ** OLE2NOTE: Because we are an SDI app, we only register our

         **    ClassFactory if we are launched with the /Embedding

         **    flag WITHOUT a filename. an MDI app would ALWAYS

         **    register its ClassFactory. it can handle multiple

         **    objects at the same time, while an SDI application

         **    can only handle a single embedded or file-based

         **    object at a time.

         *****************************************************************/

#if defined( SDI_VERSION )

         fStatus = OleApp_RegisterClassFactory(lpOleApp);

#endif

      } else {

         /*****************************************************************

         ** App was launched with /Embedding <Filename>.

         **    We must create a document and load the file and

         **    register it in the RunningObjectTable BEFORE we

         **    enter our GetMessage loop (ie. before we yield).

         **    One way to perform these tasks is to call the same

         **    interface methods that OLE 2.0 calls for linking to a

         **    file:

         **          IClassFactory::CreateInstance

         **          IPersistFile::Load

         **

         **    We must NOT make our app window visible until told to

         **    do so by our container. An application will be

         **    launched in this manner by an OLE 1.0 application

         **    link situation (eg. double clicking a linked object

         **    or OleCreateLinkFromFile called).

         **

         ** OLE2NOTE: Because we are an SDI app, we should NOT

         **    register our ClassFactory when we are launched with the

         **    /Embedding <Filename> flag. our SDI instance can only

         **    handle a single embedded or file-based object.

         **    an MDI app WOULD register its ClassFactory at all

         **    times because it can handle multiple objects.

         *****************************************************************/

         // allocate a new document object

         lpOutlineApp->m_lpDoc = OutlineApp_CreateDoc(lpOutlineApp, FALSE);

         if (! lpOutlineApp->m_lpDoc) {

            OLEDBG_END3

            return FALSE;

         }

         /* OLE2NOTE: initially the Doc object is created with a 0 ref

         **    count. in order to have a stable Doc object during the

         **    process of initializing the new Doc instance,

         **    we intially AddRef the Doc ref cnt and later

         **    Release it. This initial AddRef is artificial; it is simply

         **    done to guarantee that a harmless QueryInterface followed by

         **    a Release does not inadvertantly force our object to destroy

         **    itself prematurely.

         */

         OleDoc_AddRef((LPOLEDOC)lpOutlineApp->m_lpDoc);

         /* OLE2NOTE: OutlineDoc_LoadFromFile will register our document

         **    in the RunningObjectTable. this registration will

         **    AddRef our document. therefore our document will not

         **    be destroyed when we release the artificial AddRef

         */

         A2W (szFileName, szUniStr, 256);

         fStatus = OutlineDoc_LoadFromFile(

               lpOutlineApp->m_lpDoc, (LPOLESTR)szUniStr);

         OleDoc_Release((LPOLEDOC)lpOutlineApp->m_lpDoc); // rel AddRef

         OLEDBG_END3

         return fStatus;

      }

   } else {

      /*****************************************************************

      ** App was launched by the user (without /Embedding) and

      **    therefore is marked to be under user control.

      **    In this case, because we are an SDI app, we do NOT

      **    register our ClassFactory with OLE. This app instance can

      **    only manage one document at a time (either a user

      **    document or an embedded object document). An MDI app

      **    would register its ClassFactory here.

      **

      **    We must create a document for the user (either

      **    initialized from a file given on the command line or

      **    initialized as an untitled document. We must also make

      **    our app window visible to the user.

      *****************************************************************/

      // allocate a new document object

      lpOutlineApp->m_lpDoc = OutlineApp_CreateDoc(lpOutlineApp, FALSE);

      if (! lpOutlineApp->m_lpDoc) goto error;

      /* OLE2NOTE: initially the Doc object is created with a 0 ref

      **    count. in order to have a stable Doc object during the

      **    process of initializing the new Doc instance,

      **    we intially AddRef the Doc ref cnt and later

      **    Release it. This initial AddRef is artificial; it is simply

      **    done to guarantee that a harmless QueryInterface followed by

      **    a Release does not inadvertantly force our object to destroy

      **    itself prematurely.

      */

      OleDoc_AddRef((LPOLEDOC)lpOutlineApp->m_lpDoc);

      if(*szFileName) {

         // initialize the document from the specified file

         A2W (szFileName, szUniStr, 256);

         if (! OutlineDoc_LoadFromFile(lpOutlineApp->m_lpDoc, szUniStr))

            goto error;

      } else {

         // set the doc to an (Untitled) doc.

         if (! OutlineDoc_InitNewFile(lpOutlineApp->m_lpDoc))

            goto error;

      }

      // position and size the new doc window

      OutlineApp_ResizeWindows(lpOutlineApp);

      OutlineDoc_ShowWindow(lpOutlineApp->m_lpDoc); // calls OleDoc_Lock

      OleDoc_Release((LPOLEDOC)lpOutlineApp->m_lpDoc);// rel AddRef above

      // show main app window

      ShowWindow(lpOutlineApp->m_hWndApp, nCmdShow);

      UpdateWindow(lpOutlineApp->m_hWndApp);

#if defined( OLE_CNTR )

      ContainerDoc_UpdateLinks((LPCONTAINERDOC)lpOutlineApp->m_lpDoc);

#endif

   }

   OLEDBG_END3

   return fStatus;

error:

   // REVIEW: should load string from string resource

   OutlineApp_ErrorMessage(

         lpOutlineApp,

         OLESTR("Could not create document--Out of Memory")

   );

   if (lpOutlineApp->m_lpDoc)      // rel artificial AddRef above

      OleDoc_Release((LPOLEDOC)lpOutlineApp->m_lpDoc);

   OLEDBG_END3

   return FALSE;

}

/* OleApp_CloseAllDocsAndExitCommand

 * ---------------------------------

 *

 *  Close all active documents and exit the app.

 *  Because this is an SDI, there is only one document

 *  If the doc was modified, prompt the user if he wants to save it.

 *

 *  Returns:

 *      TRUE if the app is successfully closed

 *      FALSE if failed or aborted

 *

 * OLE2NOTE: in the OLE version, we can NOT directly

 *     destroy the App object. we can only take all

 *     necessary actions to ensure that our object receives

 *     all of its Releases from clients holding onto

 *     pointers (eg. closing all docs and flushing the

 *     clipboard) and then we must hide our window and wait

 *     actually for our refcnt to reach 0. when it reaches 0,

 *     our destructor (OutlineApp_Destroy) will be called.

 *     each document addref's the app object in order to

 *     guarentee that the app does not shut down while the doc

 *     is still open. closing all docs, will release these

 *     refcnt's. if there are now more open documents AND the

 *     app is not under the control of the user (ie. launched by

 *     OLE) then the app will now shut down. the OleApp_Release

 *     function executes this shut down procedure. after closing

 *     all docs, then releasing the user refcnt will force the

 *     app to shut down.

 */

BOOL OleApp_CloseAllDocsAndExitCommand(

      LPOLEAPP            lpOleApp,

      BOOL                fForceEndSession

)

{

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)lpOleApp;

   DWORD dwSaveOption = (fForceEndSession ?

                           OLECLOSE_NOSAVE : OLECLOSE_PROMPTSAVE);

   /* OLE2NOTE: in order to have a stable App object during the

   **    process of closing, we intially AddRef the App ref cnt and

   **    later Release it. This initial AddRef is artificial; it is

   **    simply done to guarantee that our App object does not

   **    destroy itself until the end of this routine.

   */

   OleApp_AddRef(lpOleApp);

   /* Because this is an SDI app, there is only one document.

   ** Close the doc. if it is successfully closed and the app will

   ** not automatically exit, then also exit the app.

   ** if this were an MDI app, we would loop through and close all

   ** open MDI child documents.

   */

#if defined( OLE_SERVER )

   if (!fForceEndSession &&

         lpOutlineApp->m_lpDoc->m_docInitType == DOCTYPE_EMBEDDED)

      dwSaveOption = OLECLOSE_SAVEIFDIRTY;

#endif

   if (! OutlineDoc_Close(lpOutlineApp->m_lpDoc, dwSaveOption)) {

      OleApp_Release(lpOleApp);

      return FALSE;     // User Aborted shutdown

   }

#if defined( _DEBUG )

   OleDbgAssertSz(

         lpOutlineApp->m_lpDoc==NULL,

         "Closed doc NOT properly destroyed"

   );

#endif

#if defined( OLE_CNTR )

   /* if we currently have data on the clipboard then we must tell

   **    the clipboard to release our clipboard data object

   **    (document)

   */

   if (lpOutlineApp->m_lpClipboardDoc)

      OleApp_FlushClipboard(lpOleApp);

#endif

   OleApp_HideWindow(lpOleApp);

   /* OLE2NOTE: this call forces all external connections to our

   **    object to close down and therefore guarantees that we receive

   **    all releases associated with those external connections.

   */

   OLEDBG_BEGIN2("CoDisconnectObject(lpApp) called\r\n")

   CoDisconnectObject((LPUNKNOWN)&lpOleApp->m_Unknown, 0);

   OLEDBG_END2

   OleApp_Release(lpOleApp);       // release artificial AddRef above

   return TRUE;

}

/* OleApp_ShowWindow

 * -----------------

 *

 *      Show the window of the app to the user.

 *      make sure app window is visible and bring the app to the top.

 *      IF fGiveUserCtrl == TRUE

 *          THEN give the user the control over the life-time of the app.

 */

void OleApp_ShowWindow(LPOLEAPP lpOleApp, BOOL fGiveUserCtrl)

{

   LPOUTLINEAPP    lpOutlineApp = (LPOUTLINEAPP)lpOleApp;

   OLEDBG_BEGIN3("OleApp_ShowWindow\r\n")

   /* OLE2NOTE: while the application is visible and under user

   **    control, we do NOT want it to be prematurely destroyed when

   **    the user closes a document. thus we must inform OLE to hold

   **    an external lock on our application on behalf of the user.

   **    this arranges that OLE holds at least 1 reference to our

   **    application that will NOT be released until we release this

   **    external lock. later, when the application window is hidden, we

   **    will release this external lock.

   */

   if (fGiveUserCtrl && ! lpOleApp->m_fUserCtrl) {

      lpOleApp->m_fUserCtrl = TRUE;

      OleApp_Lock(lpOleApp, TRUE /* fLock */, 0 /* not applicable */);

   }

   // we must show our App window and force it to have input focus

   ShowWindow(lpOutlineApp->m_hWndApp, SW_SHOWNORMAL);

   SetForegroundWindow(lpOutlineApp->m_hWndApp);

   /* OLE2NOTE: because our app is now visible, we can enable the busy

   **    dialog. we should NOT put up any dialogs if our app is

   **    invisible.

   */

   OleApp_EnableBusyDialogs(lpOleApp, TRUE, TRUE);

   OLEDBG_END3

}

/* OleApp_HideWindow

 * -----------------

 *

 *      Hide the window of the app from the user.

 *      take away the control of the app by the user.

 */

void OleApp_HideWindow(LPOLEAPP lpOleApp)

{

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)lpOleApp;

   OLEDBG_BEGIN3("OleApp_HideWindow\r\n")

   /* OLE2NOTE: the application is now being hidden, so we must release

   **    the external lock that was made on behalf of the user.

   **    if this is that last external lock on our application, thus

   **    enabling our application to complete its shutdown operation.

   */

   if (lpOleApp->m_fUserCtrl) {

      lpOleApp->m_fUserCtrl = FALSE;

      OleApp_Lock(lpOleApp, FALSE /*fLock*/, TRUE /*fLastUnlockReleases*/);

   }

   ShowWindow(lpOutlineApp->m_hWndApp, SW_HIDE);

   /* OLE2NOTE: because our app is now INVISIBLE, we must DISABLE the busy

   **    dialog. we should NOT put up any dialogs if our app is

   **    invisible.

   */

   OleApp_EnableBusyDialogs(lpOleApp, FALSE, FALSE);

   OLEDBG_END3

}

/* OleApp_Lock

** -----------

**    Lock/Unlock the App object. if the last lock is unlocked and

**    fLastUnlockReleases == TRUE, then the app object will shut down

**    (ie. it will recieve its final release and its refcnt will go to 0).

*/

HRESULT OleApp_Lock(LPOLEAPP lpOleApp, BOOL fLock, BOOL fLastUnlockReleases)

{

   HRESULT hrErr;

#if defined( _DEBUG )

   if (fLock) {

      OLEDBG_BEGIN2("CoLockObjectExternal(lpApp,TRUE) called\r\n")

   } else {

      if (fLastUnlockReleases)

         OLEDBG_BEGIN2("CoLockObjectExternal(lpApp,FALSE,TRUE) called\r\n")

      else

         OLEDBG_BEGIN2("CoLockObjectExternal(lpApp,FALSE,FALSE) called\r\n")

   }

#endif  // _DEBUG

   OleApp_AddRef(lpOleApp);       // artificial AddRef to make object stable

   hrErr = CoLockObjectExternal(

         (LPUNKNOWN)&lpOleApp->m_Unknown, fLock, fLastUnlockReleases);

   OleApp_Release(lpOleApp);       // release artificial AddRef above

   OLEDBG_END2

   return hrErr;

}

/* OleApp_Destroy

 * --------------

 *

 *  Free all OLE related resources that had been allocated for the app.

 */

void OleApp_Destroy(LPOLEAPP lpOleApp)

{

   // OLE2NOTE: Revoke our message filter upon app shutdown.

   OleApp_RevokeMessageFilter(lpOleApp);

   // OLE2NOTE: Revoke our ClassFactory upon app shutdown.

   OleApp_RevokeClassFactory(lpOleApp);

#if defined( IF_SPECIAL_DD_CURSORS_NEEDED )

   // This would be used if the app wanted to have custom drag/drop cursors

   DestroyCursor(lpOleApp->m_hcursorDragNone);

   DestroyCursor(lpOleApp->m_hcursorDragCopy);

   DestroyCursor(lpOleApp->m_hcursorDragLink);

   DestroyCursor(lpOleApp->m_hcursorDragMove);

#endif  // IF_SPECIAL_DD_CURSORS_NEEDED

#if defined( OLE_CNTR )

   if (lpOleApp->m_hStdPal) {

      DeleteObject(lpOleApp->m_hStdPal);

      lpOleApp->m_hStdPal = NULL;

   }

#endif

}

/* OleApp_DocLockApp

** -----------------

**    Add a lock on the App on behalf of the Doc. the App may not close

**    while the Doc exists.

**

**    when a document is first created, it calls this method to

**    guarantee that the application stays alive (OleDoc_Init).

**    when a document is destroyed, it calls

**    OleApp_DocUnlockApp to release this hold on the app.

*/

void OleApp_DocLockApp(LPOLEAPP lpOleApp)

{

   ULONG cDoc;

   OLEDBG_BEGIN3("OleApp_DocLockApp\r\n")

   cDoc = ++lpOleApp->m_cDoc;

   OleDbgOutRefCnt3("OleApp_DocLockApp: cDoc++\r\n", lpOleApp, cDoc);

   OleApp_Lock(lpOleApp, TRUE /* fLock */, 0 /* not applicable */);

   OLEDBG_END3

   return;

}

/* OleApp_DocUnlockApp

** -------------------

**    Forget all references to a closed document.

**    Release the lock on the App on behalf of the Doc. if this was the

**    last lock on the app, then it will shutdown.

*/

void OleApp_DocUnlockApp(LPOLEAPP lpOleApp, LPOUTLINEDOC lpOutlineDoc)

{

   ULONG cDoc;

   OLEDBG_BEGIN3("OleApp_DocUnlockApp\r\n")

   /* OLE2NOTE: when there are no open documents and the app is not

   **    under the control of the user then revoke our ClassFactory to

   **    enable the app to shut down.

   */

   cDoc = --lpOleApp->m_cDoc;

#if defined( _DEBUG )

   OleDbgAssertSz (

         lpOleApp->m_cDoc >= 0, "DocUnlockApp called with cDoc == 0");

   OleDbgOutRefCnt3(

         "OleApp_DocUnlockApp: cDoc--\r\n", lpOleApp, cDoc);

#endif

   OleApp_Lock(lpOleApp, FALSE /* fLock */, TRUE /* fLastUnlockReleases */);

   OLEDBG_END3

   return;

}

/* OleApp_HideIfNoReasonToStayVisible

** ----------------------------------

**

** if there are no more documents visible to the user and the app

**    itself is not under user control, then it has no reason to stay

**    visible. we thus should hide the app. we can not directly destroy

**    the app, because it may be validly being used programatically by

**    another client application and should remain running. the app

**    should simply be hidden from the user.

*/

void OleApp_HideIfNoReasonToStayVisible(LPOLEAPP lpOleApp)

{

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)lpOleApp;

   LPOUTLINEDOC lpOutlineDoc;

   OLEDBG_BEGIN3("OleApp_HideIfNoReasonToStayVisible\r\n")

   if (lpOleApp->m_fUserCtrl) {

      OLEDBG_END3

      return;     // remain visible; user in control of app

   }

   /* Because this is an SDI app, there is only one user document.

   ** check if it is visible to the user. an MDI app would loop over

   ** all open MDI child documents to see if any are visible.

   */

   lpOutlineDoc = (LPOUTLINEDOC)lpOutlineApp->m_lpDoc;

   if (lpOutlineDoc && IsWindowVisible(lpOutlineDoc->m_hWndDoc))

      return;     // remain visible; the doc is visible to the user

   // if we reached here, the app should be hidden

   OleApp_HideWindow(lpOleApp);

   OLEDBG_END3

}

/* OleApp_AddRef

** -------------

**

**  increment the ref count of the App object.

**

**    Returns the new ref count on the object

*/

ULONG OleApp_AddRef(LPOLEAPP lpOleApp)

{

   ++lpOleApp->m_cRef;

#if defined( _DEBUG )

   OleDbgOutRefCnt4(

         "OleApp_AddRef: cRef++\r\n",

         lpOleApp,

         lpOleApp->m_cRef

   );

#endif

   return lpOleApp->m_cRef;

}

/* OleApp_Release

** --------------

**

**  decrement the ref count of the App object.

**    if the ref count goes to 0, then the app object is destroyed.

**

**    Returns the remaining ref count on the object

*/

ULONG OleApp_Release (LPOLEAPP lpOleApp)

{

   ULONG cRef;

   cRef = --lpOleApp->m_cRef;

#if defined( _DEBUG )

   OleDbgAssertSz (lpOleApp->m_cRef >= 0, "Release called with cRef == 0");

   OleDbgOutRefCnt4(

         "OleApp_AddRef: cRef--\r\n", lpOleApp, cRef);

#endif  // _DEBUG

   /*********************************************************************

   ** OLE2NOTE: when the ClassFactory refcnt == 0, then destroy it.    **

   **    otherwise the ClassFactory is still in use.                   **

   *********************************************************************/

   if(cRef == 0)

      OutlineApp_Destroy((LPOUTLINEAPP)lpOleApp);

   return cRef;

}

/* OleApp_QueryInterface

** ---------------------

**

** Retrieve a pointer to an interface on the app object.

**

**    OLE2NOTE: this function will AddRef the ref cnt of the object.

**

**    Returns NOERROR if interface is successfully retrieved.

**            E_NOINTERFACE if the interface is not supported

*/

HRESULT OleApp_QueryInterface (

      LPOLEAPP                lpOleApp,

      REFIID                  riid,

      LPVOID FAR*             lplpvObj

)

{

   SCODE sc;

   /* OLE2NOTE: we must make sure to set all out ptr parameters to NULL. */

   *lplpvObj = NULL;

   if (IsEqualIID(riid, &IID_IUnknown)) {

      OleDbgOut4("OleApp_QueryInterface: IUnknown* RETURNED\r\n");

      *lplpvObj = (LPVOID) &lpOleApp->m_Unknown;

      OleApp_AddRef(lpOleApp);

      sc = S_OK;

   }

   else {

      sc = E_NOINTERFACE;

   }

   OleDbgQueryInterfaceMethod(*lplpvObj);

   return ResultFromScode(sc);

}

/* OleApp_RejectInComingCalls

** -------------------------

**    Reject/Handle in coming OLE (LRPC) calls.

**

**    OLE2NOTE: if the app is in a state when it can NOT handle in

**    coming OLE method calls from an external process (eg. the app has

**    an application modal dialog up), then it should call

**    OleApp_RejectInComingCalls(TRUE). in this state the

**    IMessageFilter::HandleInComingCall method will return

**    SERVERCALL_RETRYLATER. this tells the caller to try again in a

**    little while. normally the calling app will put up a dialog (see

**    OleUIBusy dialog) in this situation informing the user of the

**    situation. the user then is normally given the option to

**    "Switch To..." the busy application, retry, or cancel the

**    operation. when the app is ready to continue processing such

**    calls, it should call OleApp_RejectInComingCalls(FALSE). in this

**    state, SERVERCALL_ISHANDLED is returned by

**    IMessageFilter::HandleInComingCall.

*/

void OleApp_RejectInComingCalls(LPOLEAPP lpOleApp, BOOL fReject)

{

#if defined( _DEBUG )

   if (fReject)

      OleDbgOut3("OleApp_RejectInComingCalls(TRUE)\r\n");

   else

      OleDbgOut3("OleApp_RejectInComingCalls(FALSE)\r\n");

#endif  // _DEBUG

   OleDbgAssert(lpOleApp->m_lpMsgFilter != NULL);

   if (! lpOleApp->m_lpMsgFilter)

      return;

   OleStdMsgFilter_SetInComingCallStatus(

         lpOleApp->m_lpMsgFilter,

         (fReject ? SERVERCALL_RETRYLATER : SERVERCALL_ISHANDLED)

   );

}

/* OleApp_DisableBusyDialogs

** -------------------------

**    Disable the Busy and NotResponding dialogs.

**

**    Returns previous enable state so that it can be restored by

**    calling OleApp_ReEnableBusyDialogs.

*/

void OleApp_DisableBusyDialogs(

      LPOLEAPP        lpOleApp,

      BOOL FAR*       lpfPrevBusyEnable,

      BOOL FAR*       lpfPrevNREnable

)

{

   if (lpOleApp->m_lpMsgFilter) {

      *lpfPrevNREnable = OleStdMsgFilter_EnableNotRespondingDialog(

            lpOleApp->m_lpMsgFilter, FALSE);

      *lpfPrevBusyEnable = OleStdMsgFilter_EnableBusyDialog(

            lpOleApp->m_lpMsgFilter, FALSE);

   }

}

/* OleApp_EnableBusyDialogs

** ------------------------

**    Set the enable state of the Busy and NotResponding dialogs.

**

**    This function is typically used after a call to

**    OleApp_DisableBusyDialogs in order to restore the previous enable

**    state of the dialogs.

*/

void OleApp_EnableBusyDialogs(

      LPOLEAPP        lpOleApp,

      BOOL            fPrevBusyEnable,

      BOOL            fPrevNREnable

)

{

   if (lpOleApp->m_lpMsgFilter) {

      OleStdMsgFilter_EnableNotRespondingDialog(

            lpOleApp->m_lpMsgFilter, fPrevNREnable);

      OleStdMsgFilter_EnableBusyDialog(

            lpOleApp->m_lpMsgFilter, fPrevBusyEnable);

   }

}

/* OleApp_PreModalDialog

** ---------------------

**    Keep track that a modal dialog is about to be brought up.

**

**    while a modal dialog is up we need to take special actions:

**    1. we do NOT want to initialize our tool bar buttons on

**    WM_ACTIVATEAPP. the tool bar is not accessible.

**    2. we want to reject new top-level, incoming LRPC calls

**       (return SERVERCALL_RETRYLATER from IMessageFilter::

**        HandleInComingCall).

**    3. (IN-PLACE SERVER) tell our in-place container to disable

**    modeless dialogs by calling IOleInPlaceFrame::

**    EnableModeless(FALSE).

**    4. (IN-PLACE CONTAINER) tell our UIActive in-place object to

**    disable modeless dialogs by calling IOleInPlaceActiveObject::

**    EnableModeless(FALSE).

*/

void OleApp_PreModalDialog(LPOLEAPP lpOleApp, LPOLEDOC lpOleDoc)

{

   if (lpOleApp->m_cModalDlgActive == 0) {

      // top-level modal dialog is being brought up

#if defined( USE_FRAMETOOLS )

      LPFRAMETOOLS lptb;

      if (lpOleDoc)

         lptb = ((LPOUTLINEDOC)lpOleDoc)->m_lpFrameTools;

      else

         lptb = OutlineApp_GetFrameTools((LPOUTLINEAPP)lpOleApp);

      if (lptb)

         FrameTools_EnableWindow(lptb, FALSE);

#endif  // USE_FRAMETOOLS

      OleApp_RejectInComingCalls(lpOleApp, TRUE);

#if defined( INPLACE_SVR )

      {

         LPSERVERDOC  lpServerDoc = (LPSERVERDOC)lpOleDoc;

         /* if the document bringing up the modal dialog is

         **    currently a UIActive in-place object, then tell the

         **    top-level in-place frame to disable its modeless

         **    dialogs.

         */

         if (lpServerDoc && lpServerDoc->m_fUIActive &&

               lpServerDoc->m_lpIPData &&

               lpServerDoc->m_lpIPData->lpFrame) {

            OLEDBG_BEGIN2("IOleInPlaceFrame::EnableModless(FALSE) called\r\n");

            lpServerDoc->m_lpIPData->lpFrame->lpVtbl->EnableModeless(

                  lpServerDoc->m_lpIPData->lpFrame, FALSE);

            OLEDBG_END2

         }

      }

#endif  // INPLACE_SVR

#if defined( INPLACE_CNTR )

      {

         LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)lpOleApp;

         /* if the document bringing up the modal dialog is an

         **    in-place container that has a UIActive object, then

         **    tell the UIActive object to disable its modeless

         **    dialogs.

         */

         if (lpContainerApp->m_lpIPActiveObj) {

            OLEDBG_BEGIN2("IOleInPlaceActiveObject::EnableModless(FALSE) called\r\n");

            lpContainerApp->m_lpIPActiveObj->lpVtbl->EnableModeless(

                  lpContainerApp->m_lpIPActiveObj, FALSE);

            OLEDBG_END2

         }

      }

#endif  // INPLACE_CNTR

   }

   lpOleApp->m_cModalDlgActive++;

}

/* OleApp_PostModalDialog

** ----------------------

**    Keep track that a modal dialog is being brought down. this call

**    balances the OleApp_PreModalDialog call.

*/

void OleApp_PostModalDialog(LPOLEAPP lpOleApp, LPOLEDOC lpOleDoc)

{

   lpOleApp->m_cModalDlgActive--;

   if (lpOleApp->m_cModalDlgActive == 0) {

      // last modal dialog is being brought down

#if defined( USE_FRAMETOOLS )

      LPFRAMETOOLS lptb;

      if (lpOleDoc)

         lptb = ((LPOUTLINEDOC)lpOleDoc)->m_lpFrameTools;

      else

         lptb = OutlineApp_GetFrameTools((LPOUTLINEAPP)lpOleApp);

      if (lptb) {

         FrameTools_EnableWindow(lptb, TRUE);

         FrameTools_UpdateButtons(lptb, (LPOUTLINEDOC)lpOleDoc);

      }

#endif  // USE_FRAMETOOLS

      OleApp_RejectInComingCalls(lpOleApp, FALSE);

#if defined( INPLACE_SVR )

      {

         LPSERVERDOC  lpServerDoc = (LPSERVERDOC)lpOleDoc;

         /* if the document bringing down the modal dialog is

         **    currently a UIActive in-place object, then tell the

         **    top-level in-place frame it can re-enable its

         **    modeless dialogs.

         */

         if (lpServerDoc && lpServerDoc->m_fUIActive &&

               lpServerDoc->m_lpIPData &&

               lpServerDoc->m_lpIPData->lpFrame) {

            OLEDBG_BEGIN2("IOleInPlaceFrame::EnableModless(TRUE) called\r\n");

            lpServerDoc->m_lpIPData->lpFrame->lpVtbl->EnableModeless(

                  lpServerDoc->m_lpIPData->lpFrame, TRUE);

            OLEDBG_END2

         }

      }

#endif  // INPLACE_SVR

#if defined( INPLACE_CNTR )

      {

         LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)lpOleApp;

         /* if the document bringing down the modal dialog is an

         **    in-place container that has a UIActive object, then

         **    tell the UIActive object it can re-enable its

         **    modeless dialogs.

         */

         if (lpContainerApp->m_lpIPActiveObj) {

            OLEDBG_BEGIN2("IOleInPlaceActiveObject::EnableModless(TRUE) called\r\n");

            lpContainerApp->m_lpIPActiveObj->lpVtbl->EnableModeless(

                  lpContainerApp->m_lpIPActiveObj, TRUE);

            OLEDBG_END2

         }

      }

#endif  // INPLACE_CNTR

   }

}

/* OleApp_InitVtbls

 * ----------------

 *

 * initialize the methods in all of the interface Vtbl's

 *

 * OLE2NOTE: we only need one copy of each Vtbl. When an object which

 *      exposes an interface is instantiated, its lpVtbl is intialized

 *      to point to the single copy of the Vtbl.

 *

 */

BOOL OleApp_InitVtbls (LPOLEAPP lpOleApp)

{

   BOOL fStatus;

   // OleApp::IUnknown method table

   OleStdInitVtbl(&g_OleApp_UnknownVtbl, sizeof(IUnknownVtbl));

   g_OleApp_UnknownVtbl.QueryInterface = OleApp_Unk_QueryInterface;

   g_OleApp_UnknownVtbl.AddRef         = OleApp_Unk_AddRef;

   g_OleApp_UnknownVtbl.Release        = OleApp_Unk_Release;

   fStatus = OleStdCheckVtbl(

         &g_OleApp_UnknownVtbl,

         sizeof(IUnknownVtbl),

         OLESTR("IUnknown")

      );

   if (! fStatus) return FALSE;

   // OleDoc::IUnknown method table

   OleStdInitVtbl(&g_OleDoc_UnknownVtbl, sizeof(IUnknownVtbl));

   g_OleDoc_UnknownVtbl.QueryInterface = OleDoc_Unk_QueryInterface;

   g_OleDoc_UnknownVtbl.AddRef         = OleDoc_Unk_AddRef;

   g_OleDoc_UnknownVtbl.Release        = OleDoc_Unk_Release;

   fStatus = OleStdCheckVtbl(

         &g_OleDoc_UnknownVtbl,

         sizeof(IUnknownVtbl),

         OLESTR("IUnknown")

      );

   if (! fStatus) return FALSE;

   // OleDoc::IPersistFile method table

   OleStdInitVtbl(&g_OleDoc_PersistFileVtbl, sizeof(IPersistFileVtbl));

   g_OleDoc_PersistFileVtbl.QueryInterface = OleDoc_PFile_QueryInterface;

   g_OleDoc_PersistFileVtbl.AddRef         = OleDoc_PFile_AddRef;

   g_OleDoc_PersistFileVtbl.Release        = OleDoc_PFile_Release;

   g_OleDoc_PersistFileVtbl.GetClassID     = OleDoc_PFile_GetClassID;

   g_OleDoc_PersistFileVtbl.IsDirty        = OleDoc_PFile_IsDirty;

   g_OleDoc_PersistFileVtbl.Load           = OleDoc_PFile_Load;

   g_OleDoc_PersistFileVtbl.Save           = OleDoc_PFile_Save;

   g_OleDoc_PersistFileVtbl.SaveCompleted  = OleDoc_PFile_SaveCompleted;

   g_OleDoc_PersistFileVtbl.GetCurFile     = OleDoc_PFile_GetCurFile;

   fStatus = OleStdCheckVtbl(

         &g_OleDoc_PersistFileVtbl,

         sizeof(IPersistFileVtbl),

         OLESTR("IPersistFile")

      );

   if (! fStatus) return FALSE;

   // OleDoc::IOleItemContainer method table

   OleStdInitVtbl(&g_OleDoc_OleItemContainerVtbl, sizeof(IOleItemContainerVtbl));

   g_OleDoc_OleItemContainerVtbl.QueryInterface =

                                 OleDoc_ItemCont_QueryInterface;

   g_OleDoc_OleItemContainerVtbl.AddRef    = OleDoc_ItemCont_AddRef;

   g_OleDoc_OleItemContainerVtbl.Release   = OleDoc_ItemCont_Release;

   g_OleDoc_OleItemContainerVtbl.ParseDisplayName  =

                                 OleDoc_ItemCont_ParseDisplayName;

   g_OleDoc_OleItemContainerVtbl.EnumObjects= OleDoc_ItemCont_EnumObjects;

   g_OleDoc_OleItemContainerVtbl.LockContainer =

                                 OleDoc_ItemCont_LockContainer;

   g_OleDoc_OleItemContainerVtbl.GetObject = OleDoc_ItemCont_GetObject;

   g_OleDoc_OleItemContainerVtbl.GetObjectStorage =

                                 OleDoc_ItemCont_GetObjectStorage;

   g_OleDoc_OleItemContainerVtbl.IsRunning = OleDoc_ItemCont_IsRunning;

   fStatus = OleStdCheckVtbl(

         &g_OleDoc_OleItemContainerVtbl,

         sizeof(IOleItemContainerVtbl),

         OLESTR("IOleItemContainer")

      );

   if (! fStatus) return FALSE;

   // OleDoc::IExternalConnection method table

   OleStdInitVtbl(

         &g_OleDoc_ExternalConnectionVtbl,sizeof(IExternalConnectionVtbl));

   g_OleDoc_ExternalConnectionVtbl.QueryInterface =

                                 OleDoc_ExtConn_QueryInterface;

   g_OleDoc_ExternalConnectionVtbl.AddRef         = OleDoc_ExtConn_AddRef;

   g_OleDoc_ExternalConnectionVtbl.Release        = OleDoc_ExtConn_Release;

   g_OleDoc_ExternalConnectionVtbl.AddConnection  =

                                 OleDoc_ExtConn_AddConnection;

   g_OleDoc_ExternalConnectionVtbl.ReleaseConnection =

                                 OleDoc_ExtConn_ReleaseConnection;

   fStatus = OleStdCheckVtbl(

         &g_OleDoc_ExternalConnectionVtbl,

         sizeof(IExternalConnectionVtbl),

         OLESTR("IExternalConnection")

   );

   if (! fStatus) return FALSE;

   // OleDoc::IDataObject method table

   OleStdInitVtbl(&g_OleDoc_DataObjectVtbl, sizeof(IDataObjectVtbl));

   g_OleDoc_DataObjectVtbl.QueryInterface  = OleDoc_DataObj_QueryInterface;

   g_OleDoc_DataObjectVtbl.AddRef          = OleDoc_DataObj_AddRef;

   g_OleDoc_DataObjectVtbl.Release         = OleDoc_DataObj_Release;

   g_OleDoc_DataObjectVtbl.GetData         = OleDoc_DataObj_GetData;

   g_OleDoc_DataObjectVtbl.GetDataHere     = OleDoc_DataObj_GetDataHere;

   g_OleDoc_DataObjectVtbl.QueryGetData    = OleDoc_DataObj_QueryGetData;

   g_OleDoc_DataObjectVtbl.GetCanonicalFormatEtc =

                              OleDoc_DataObj_GetCanonicalFormatEtc;

   g_OleDoc_DataObjectVtbl.SetData         = OleDoc_DataObj_SetData;

   g_OleDoc_DataObjectVtbl.EnumFormatEtc   = OleDoc_DataObj_EnumFormatEtc;

   g_OleDoc_DataObjectVtbl.DAdvise          = OleDoc_DataObj_DAdvise;

   g_OleDoc_DataObjectVtbl.DUnadvise        = OleDoc_DataObj_DUnadvise;

   g_OleDoc_DataObjectVtbl.EnumDAdvise      = OleDoc_DataObj_EnumDAdvise;

   fStatus = OleStdCheckVtbl(

         &g_OleDoc_DataObjectVtbl,

         sizeof(IDataObjectVtbl),

         OLESTR("IDataObject")

      );

   if (! fStatus) return FALSE;

#if defined( USE_DRAGDROP )

   // OleDoc::IDropTarget method table

   OleStdInitVtbl(&g_OleDoc_DropTargetVtbl, sizeof(IDropTargetVtbl));

   g_OleDoc_DropTargetVtbl.QueryInterface= OleDoc_DropTarget_QueryInterface;

   g_OleDoc_DropTargetVtbl.AddRef      = OleDoc_DropTarget_AddRef;

   g_OleDoc_DropTargetVtbl.Release     = OleDoc_DropTarget_Release;

   g_OleDoc_DropTargetVtbl.DragEnter   = OleDoc_DropTarget_DragEnter;

   g_OleDoc_DropTargetVtbl.DragOver    = OleDoc_DropTarget_DragOver;

   g_OleDoc_DropTargetVtbl.DragLeave   = OleDoc_DropTarget_DragLeave;

   g_OleDoc_DropTargetVtbl.Drop        = OleDoc_DropTarget_Drop;

   fStatus = OleStdCheckVtbl(

         &g_OleDoc_DropTargetVtbl,

         sizeof(IDropTargetVtbl),

         OLESTR("IDropTarget")

   );

   if (! fStatus)

      return FALSE;

   // OleDoc::IDropSource method table

   OleStdInitVtbl(&g_OleDoc_DropSourceVtbl, sizeof(IDropSourceVtbl));

   g_OleDoc_DropSourceVtbl.QueryInterface  =

                              OleDoc_DropSource_QueryInterface;

   g_OleDoc_DropSourceVtbl.AddRef          = OleDoc_DropSource_AddRef;

   g_OleDoc_DropSourceVtbl.Release         = OleDoc_DropSource_Release;

   g_OleDoc_DropSourceVtbl.QueryContinueDrag =

                              OleDoc_DropSource_QueryContinueDrag;

   g_OleDoc_DropSourceVtbl.GiveFeedback    = OleDoc_DropSource_GiveFeedback;

   fStatus = OleStdCheckVtbl(

         &g_OleDoc_DropSourceVtbl,

         sizeof(IDropSourceVtbl),

         OLESTR("IDropSource")

   );

   if (! fStatus) return FALSE;

#endif  // USE_DRAGDROP

#if defined( OLE_SERVER )

   // Initialize the server specific interface method tables.

   if (! ServerApp_InitVtbls((LPSERVERAPP)lpOleApp))

      return FALSE;

#endif

#if defined( OLE_CNTR )

   // Initialize the container specific interface method tables.

   if (! ContainerApp_InitVtbls((LPCONTAINERAPP)lpOleApp))

      return FALSE;

#endif

   return TRUE;

};

/* OleApp_InitMenu

 * ---------------

 *

 *      Enable or Disable menu items depending on the state of

 * the appliation.

 * The OLE versions of the Outline sample app add a PasteSpecial command.

 * Also, the container version add InsertObject and ObjectVerb menu items.

 */

void OleApp_InitMenu(

      LPOLEAPP                lpOleApp,

      LPOLEDOC                lpOleDoc,

      HMENU                   hMenu

)

{

   BOOL bMsgFilterInstalled = FALSE;

   BOOL bRejecting = FALSE;

   if (!lpOleApp || !hMenu)

      return;

   OLEDBG_BEGIN3("OleApp_InitMenu\r\n")

   /*

   ** Enable/disable menu items for Message Filter

   */

   bMsgFilterInstalled = (lpOleApp->m_lpMsgFilter != NULL);

   bRejecting = bMsgFilterInstalled &&

      OleStdMsgFilter_GetInComingCallStatus(lpOleApp->m_lpMsgFilter) != SERVERCALL_ISHANDLED;

   CheckMenuItem(hMenu,

      IDM_D_INSTALLMSGFILTER,

      bMsgFilterInstalled ? MF_CHECKED : MF_UNCHECKED);

   EnableMenuItem(hMenu,

      IDM_D_REJECTINCOMING,

      bMsgFilterInstalled ? MF_ENABLED : MF_GRAYED);

   CheckMenuItem(hMenu,

      IDM_D_REJECTINCOMING,

      bRejecting ? MF_CHECKED : MF_UNCHECKED);

#if defined( OLE_CNTR )

   {

      LPCONTAINERDOC lpContainerDoc = (LPCONTAINERDOC)lpOleDoc;

      BOOL fShowObject;

      fShowObject = ContainerDoc_GetShowObjectFlag(lpContainerDoc);

      CheckMenuItem(

            hMenu,

            IDM_O_SHOWOBJECT,

            (fShowObject ? MF_CHECKED : MF_UNCHECKED)

      );

#if defined( INPLACE_CNTR ) && defined( _DEBUG )

      CheckMenuItem(

            hMenu,

            IDM_D_INSIDEOUT,

            g_fInsideOutContainer ? MF_CHECKED:MF_UNCHECKED);

#endif  // INPLACE_CNTR && _DEBUG

   }

#endif  // OLE_CNTR

   OLEDBG_END3

}

/* OleApp_UpdateEditMenu

 * ---------------------

 *

 *  Purpose:

 *      Update the Edit menuitems of the App according to the state of

 *      OutlineDoc

 *

 *  Parameter:

 *      lpOutlineDoc        pointer to the document

 *      hMenuEdit           edit menu handle

 */

void OleApp_UpdateEditMenu(

      LPOLEAPP                lpOleApp,

      LPOUTLINEDOC            lpOutlineDoc,

      HMENU                   hMenuEdit

)

{

   int             nFmtEtc;

   UINT            uEnablePaste = MF_GRAYED;

   UINT            uEnablePasteLink = MF_GRAYED;

   LPDATAOBJECT    lpClipboardDataObj;

   LPOLEDOC        lpOleDoc = (LPOLEDOC)lpOutlineDoc;

   HRESULT         hrErr;

   BOOL            fPrevEnable1;

   BOOL            fPrevEnable2;

   if (!lpOleApp || !lpOutlineDoc || !hMenuEdit)

      return;

   if (!OleDoc_GetUpdateEditMenuFlag(lpOleDoc))

      /* OLE2NOTE: if the flag is not set, we don't have to update

      **    the edit menu again. This blocks repetitive updating when

      **    the user move the mouse across Edit menu while holding

      **    down the button

      */

      return;

   OLEDBG_BEGIN3("OleApp_InitEditMenu\r\n")

   /* OLE2NOTE: we do not want to ever give the busy dialog when we

   **    are trying to put up our menus. eg. even if the source of

   **    data on the clipboard is busy, we do not want put up the busy

   **    dialog. thus we will disable the dialog and at the end

   **    re-enable it.

   */

   OleApp_DisableBusyDialogs(lpOleApp, &fPrevEnable1, &fPrevEnable2);

   // check if there is data on the clipboard that we can paste/paste link

   OLEDBG_BEGIN2("OleGetClipboard called\r\n")

   hrErr = OleGetClipboard((LPDATAOBJECT FAR*)&lpClipboardDataObj);

   OLEDBG_END2

   if (hrErr == NOERROR) {

      nFmtEtc = OleStdGetPriorityClipboardFormat(

            lpClipboardDataObj,

            lpOleApp->m_arrPasteEntries,

            lpOleApp->m_nPasteEntries

      );

      if (nFmtEtc >= 0)

         uEnablePaste = MF_ENABLED;  // there IS a format we like

      OLEDBG_BEGIN2("OleQueryLinkFromData called\r\n")

      hrErr = OleQueryLinkFromData(lpClipboardDataObj);

      OLEDBG_END2

      if(hrErr == NOERROR)

         uEnablePasteLink = MF_ENABLED;

      OleStdRelease((LPUNKNOWN)lpClipboardDataObj);

   }

   EnableMenuItem(hMenuEdit, IDM_E_PASTE, uEnablePaste);

   EnableMenuItem(hMenuEdit, IDM_E_PASTESPECIAL, uEnablePaste);

#if defined( OLE_CNTR )

   if (ContainerDoc_GetNextLink((LPCONTAINERDOC)lpOutlineDoc, NULL))

      EnableMenuItem(hMenuEdit, IDM_E_EDITLINKS, MF_ENABLED);

   else

      EnableMenuItem(hMenuEdit, IDM_E_EDITLINKS, MF_GRAYED);

   {

      LPCONTAINERAPP  lpContainerApp = (LPCONTAINERAPP)lpOleApp;

      HMENU           hMenuVerb = NULL;

      LPOLEOBJECT     lpOleObj = NULL;

      LPCONTAINERLINE lpContainerLine = NULL;

      BOOL            fSelIsOleObject;

      EnableMenuItem(hMenuEdit, IDM_E_PASTELINK, uEnablePasteLink);

      /* check if selection is a single line that contains an OleObject */

      fSelIsOleObject = ContainerDoc_IsSelAnOleObject(

            (LPCONTAINERDOC)lpOutlineDoc,

            &IID_IOleObject,

            (LPUNKNOWN FAR*)&lpOleObj,

            NULL,    /* we don't need the line index */

            (LPCONTAINERLINE FAR*)&lpContainerLine

      );

      if (hMenuEdit != NULL) {

         /* If the current line is an ContainerLine, add the object

         **    verb sub menu to the Edit menu. if the line is not an

         **    ContainerLine, (lpOleObj==NULL) then disable the

         **    Edit.Object command. this helper API takes care of

         **    building the verb menu as appropriate.

         */

         OleUIAddVerbMenu(

               (LPOLEOBJECT)lpOleObj,

               (lpContainerLine ? lpContainerLine->m_lpszShortType:NULL),

               hMenuEdit,

               POS_OBJECT,

               IDM_E_OBJECTVERBMIN,

               0,                     // no uIDVerbMax enforced

               TRUE,                  // Add Convert menu item

               IDM_E_CONVERTVERB,     // ID for Convert menu item

               (HMENU FAR*) &hMenuVerb

         );

#if defined( USE_STATUSBAR_LATER )

         /* setup status messages for the object verb menu */

         if (hMenuVerb) {

            // REVIEW: this string should come from a string resource.

            // REVIEW: this doesn't work for dynamically created menus

            AssignPopupMessage(

                  hMenuVerb,

                  "Open, edit or interact with an object"

            );

         }

#endif  // USE_STATUSBAR_LATER

      }

      if (lpOleObj)

         OleStdRelease((LPUNKNOWN)lpOleObj);

   }

#endif  // OLE_CNTR

   // re-enable the Busy/NotResponding dialogs

   OleApp_EnableBusyDialogs(lpOleApp, fPrevEnable1, fPrevEnable2);

   OleDoc_SetUpdateEditMenuFlag(lpOleDoc, FALSE);

   OLEDBG_END3

}

/* OleApp_RegisterClassFactory

 * ---------------------------

 *

 * Register our app's ClassFactory with OLE.

 *

 */

BOOL OleApp_RegisterClassFactory(LPOLEAPP lpOleApp)

{

   HRESULT hrErr;

   if (lpOleApp->m_lpClassFactory)

      return TRUE;    // already registered

   OLEDBG_BEGIN3("OleApp_RegisterClassFactory\r\n")

   /******************************************************************

   ** An SDI app must register its ClassFactory if it is launched

   **    for embedding (/Embedding command line option specified).

   ** An MDI app must register its ClassFactory in all cases,

   ******************************************************************/

   lpOleApp->m_lpClassFactory = AppClassFactory_Create();

   if (! lpOleApp->m_lpClassFactory) {

      OutlineApp_ErrorMessage(g_lpApp, ErrMsgCreateCF);

      goto error;

   }

   OLEDBG_BEGIN2("CoRegisterClassObject called\r\n")

   hrErr = CoRegisterClassObject(

            &CLSID_APP,

            (LPUNKNOWN)lpOleApp->m_lpClassFactory,

            CLSCTX_LOCAL_SERVER,

            REGCLS_SINGLEUSE,

            &lpOleApp->m_dwRegClassFac

   );

   OLEDBG_END2

   if(hrErr != NOERROR) {

      OleDbgOutHResult("CoRegisterClassObject returned", hrErr);

      OutlineApp_ErrorMessage(g_lpApp, ErrMsgRegCF);

      goto error;

   }

   OLEDBG_END3

   return TRUE;

error:

   if (lpOleApp->m_lpClassFactory) {

      OleStdRelease((LPUNKNOWN)lpOleApp->m_lpClassFactory);

      lpOleApp->m_lpClassFactory = NULL;

   }

   OLEDBG_END3

   return FALSE;

}

/* OleApp_RevokeClassFactory

 * -------------------------

 *

 * Revoke our app's ClassFactory.

 *

 */

void OleApp_RevokeClassFactory(LPOLEAPP lpOleApp)

{

   HRESULT hrErr;

   if (lpOleApp->m_lpClassFactory) {

      OLEDBG_BEGIN2("CoRevokeClassObject called\r\n")

      hrErr = CoRevokeClassObject(lpOleApp->m_dwRegClassFac);

      OLEDBG_END2

#if defined( _DEBUG )

      if (hrErr != NOERROR) {

         OleDbgOutHResult("CoRevokeClassObject returned", hrErr);

      }

#endif

      OleStdVerifyRelease(

            (LPUNKNOWN)lpOleApp->m_lpClassFactory,

            OLESTR("ClassFactory NOT released properly!")

      );

      lpOleApp->m_lpClassFactory = NULL;

   }

}

#if defined( USE_MSGFILTER )

/* OleApp_RegisterMessageFilter

 * ----------------------------

 *  Register our IMessageFilter*. the message filter is used to handle

 *  concurrency. we will use a standard implementation of IMessageFilter

 *  that is included as part of the OLE2UI library.

 */

BOOL OleApp_RegisterMessageFilter(LPOLEAPP lpOleApp)

{

   HRESULT hrErr;

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)lpOleApp;

   if (lpOleApp->m_lpMsgFilter == NULL) {

      // Register our message filter.

      lpOleApp->m_lpfnMsgPending = (MSGPENDINGPROC)MessagePendingProc;

      lpOleApp->m_lpMsgFilter = OleStdMsgFilter_Create(

            g_lpApp->m_hWndApp,

            (LPOLESTR)APPNAME,

            lpOleApp->m_lpfnMsgPending,

            NULL    /* Busy dialog callback hook function */

      );

      OLEDBG_BEGIN2("CoRegisterMessageFilter called\r\n")

      hrErr = CoRegisterMessageFilter(

               lpOleApp->m_lpMsgFilter,

               NULL    /* don't need previous message filter */

      );

      OLEDBG_END2

      if(hrErr != NOERROR) {

         OutlineApp_ErrorMessage(lpOutlineApp, ErrMsgRegMF);

         return FALSE;

      }

   }

   return TRUE;

}

/* OleApp_RevokeMessageFilter

 * --------------------------

 *  Revoke our IMessageFilter*. the message filter is used to handle

 *  concurrency. we will use a standard implementation of IMessageFilter

 *  that is included as part of the OLE2UI library.

 */

void OleApp_RevokeMessageFilter(LPOLEAPP lpOleApp)

{

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   if (lpOleApp->m_lpMsgFilter != NULL) {

      // Revoke our message filter

      OLEDBG_BEGIN2("CoRegisterMessageFilter(NULL) called\r\n")

      CoRegisterMessageFilter(NULL, NULL);

      OLEDBG_END2

      if (lpOleApp->m_lpfnMsgPending) {

         lpOleApp->m_lpfnMsgPending = NULL;

      }

      OleStdVerifyRelease(

            (LPUNKNOWN)lpOleApp->m_lpMsgFilter,

            OLESTR("Release MessageFilter FAILED!")

      );

      lpOleApp->m_lpMsgFilter = NULL;

   }

}

/* MessagePendingProc

 * ------------------

 *

 * Callback function for the IMessageFilter::MessagePending procedure.  This

 * function is called when a message is received by our application while

 * we are waiting for an OLE call to complete.  We are essentially

 * blocked at this point, waiting for a response from the other OLE application.

 * We should not process any messages which might cause another OLE call

 * to become blocked, or any other call which might cause re-entrancy problems.

 *

 * For this application, only process WM_PAINT messages.  A more sophisticated

 * application might allow certain menu messages and menu items to be processed

 * also.

 *

 * RETURNS: TRUE if we processed the message, FALSE if we did not.

 */

BOOL FAR PASCAL EXPORT MessagePendingProc(MSG FAR *lpMsg)

{

   // Our application is only handling WM_PAINT messages when we are blocked

   switch (lpMsg->message) {

      case WM_PAINT:

         OleDbgOut2("WM_PAINT dispatched while blocked\r\n");

         DispatchMessage(lpMsg);

         break;

   }

   return FALSE;   // return PENDINGMSG_WAITDEFPROCESS from MessagePending

}

#endif  // USE_MSGFILTER

/* OleApp_FlushClipboard

 * ---------------------

 *

 *  Force the Windows clipboard to release our clipboard DataObject.

 */

void OleApp_FlushClipboard(LPOLEAPP lpOleApp)

{

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)lpOleApp;

   LPOLEDOC lpClipboardDoc = (LPOLEDOC)lpOutlineApp->m_lpClipboardDoc;

   OLEDBG_BEGIN3("OleApp_FlushClipboard\r\n")

   /* OLE2NOTE: if for some reason our clipboard data transfer

   **    document is still held on to by an external client, we want

   **    to forceably break all external connections.

   */

   OLEDBG_BEGIN2("CoDisconnectObject called\r\n")

   CoDisconnectObject((LPUNKNOWN)&lpClipboardDoc->m_Unknown, 0);

   OLEDBG_END2

   OLEDBG_BEGIN2("OleFlushClipboard called\r\n")

   OleFlushClipboard();

   OLEDBG_END2

   lpOutlineApp->m_lpClipboardDoc = NULL;

   OLEDBG_END3

}

/* OleApp_NewCommand

 * -----------------

 *

 *  Start a new untitled document (File.New command).

 */

void OleApp_NewCommand(LPOLEAPP lpOleApp)

{

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)lpOleApp;

   LPOUTLINEDOC lpOutlineDoc = lpOutlineApp->m_lpDoc;

   if (! OutlineDoc_Close(lpOutlineDoc, OLECLOSE_PROMPTSAVE))

      return;

   OleDbgAssertSz(lpOutlineApp->m_lpDoc==NULL,"Closed doc NOT properly destroyed");

   lpOutlineApp->m_lpDoc = OutlineApp_CreateDoc(lpOutlineApp, FALSE);

   if (! lpOutlineApp->m_lpDoc) goto error;

   /* OLE2NOTE: initially the Doc object is created with a 0 ref

   **    count. in order to have a stable Doc object during the

   **    process of initializing the new Doc instance,

   **    we intially AddRef the Doc ref cnt and later

   **    Release it. This initial AddRef is artificial; it is simply

   **    done to guarantee that a harmless QueryInterface followed by

   **    a Release does not inadvertantly force our object to destroy

   **    itself prematurely.

   */

   OleDoc_AddRef((LPOLEDOC)lpOutlineApp->m_lpDoc);

   // set the doc to an (Untitled) doc.

   if (! OutlineDoc_InitNewFile(lpOutlineApp->m_lpDoc))

      goto error;

   // position and size the new doc window

   OutlineApp_ResizeWindows(lpOutlineApp);

   OutlineDoc_ShowWindow(lpOutlineApp->m_lpDoc); // calls OleDoc_Lock

   OleDoc_Release((LPOLEDOC)lpOutlineApp->m_lpDoc);  // rel artificial AddRef

   return;

error:

   // REVIEW: should load string from string resource

   OutlineApp_ErrorMessage(lpOutlineApp, OLESTR("Could not create new document"));

   if (lpOutlineApp->m_lpDoc) {

      // releasing the artificial AddRef above will destroy the document

      OleDoc_Release((LPOLEDOC)lpOutlineApp->m_lpDoc);

      lpOutlineApp->m_lpDoc = NULL;

   }

   return;

}

/* OleApp_OpenCommand

 * ------------------

 *

 *  Load a document from file (File.Open command).

 */

void OleApp_OpenCommand(LPOLEAPP lpOleApp)

{

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)lpOleApp;

   LPOUTLINEDOC lpOutlineDoc = lpOutlineApp->m_lpDoc;

   OPENFILENAME ofn;

   char szFilter[]=APPFILENAMEFILTER;

   char szFileName[256];

   UINT i;

   DWORD dwSaveOption = OLECLOSE_PROMPTSAVE;

   BOOL fStatus = TRUE;

   OLECHAR szUniStr[256];

   if (! OutlineDoc_CheckSaveChanges(lpOutlineDoc, &dwSaveOption))

      return;           // abort opening new doc

   for(i=0; szFilter[i]; i++)

      if(szFilter[i]=='|') szFilter[i]='\0';

   _fmemset((LPOPENFILENAME)&ofn,0,sizeof(OPENFILENAME));

   szFileName[0]='\0';

   ofn.lStructSize=sizeof(OPENFILENAME);

   ofn.hwndOwner=lpOutlineApp->m_hWndApp;

   ofn.lpstrFilter=(LPSTR)szFilter;

   ofn.lpstrFile=(LPSTR)szFileName;

   ofn.nMaxFile=256;

   ofn.Flags=OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;

   ofn.lpstrDefExt=DEFEXTENSION;

   OleApp_PreModalDialog(lpOleApp, (LPOLEDOC)lpOutlineApp->m_lpDoc);

   fStatus = GetOpenFileName((LPOPENFILENAME)&ofn);

   OleApp_PostModalDialog(lpOleApp, (LPOLEDOC)lpOutlineApp->m_lpDoc);

   if(! fStatus)

      return;         // user canceled file open dialog

   OutlineDoc_Close(lpOutlineDoc, OLECLOSE_NOSAVE);

   OleDbgAssertSz(lpOutlineApp->m_lpDoc==NULL,"Closed doc NOT properly destroyed");

   lpOutlineApp->m_lpDoc = OutlineApp_CreateDoc(lpOutlineApp, FALSE);

   if (! lpOutlineApp->m_lpDoc) goto error;

   /* OLE2NOTE: initially the Doc object is created with a 0 ref

   **    count. in order to have a stable Doc object during the

   **    process of initializing the new Doc instance,

   **    we intially AddRef the Doc ref cnt and later

   **    Release it. This initial AddRef is artificial; it is simply

   **    done to guarantee that a harmless QueryInterface followed by

   **    a Release does not inadvertantly force our object to destroy

   **    itself prematurely.

   */

   OleDoc_AddRef((LPOLEDOC)lpOutlineApp->m_lpDoc);

   A2W (szFileName, szUniStr, 256);

   fStatus=OutlineDoc_LoadFromFile(lpOutlineApp->m_lpDoc, (LPOLESTR)szUniStr);

   if (! fStatus) {

      // loading the doc failed; create an untitled instead

      // releasing the artificial AddRef above will destroy the document

      OleDoc_Release((LPOLEDOC)lpOutlineApp->m_lpDoc);

      lpOutlineApp->m_lpDoc = OutlineApp_CreateDoc(lpOutlineApp, FALSE);

      if (! lpOutlineApp->m_lpDoc) goto error;

      OleDoc_AddRef((LPOLEDOC)lpOutlineApp->m_lpDoc);

      if (! OutlineDoc_InitNewFile(lpOutlineApp->m_lpDoc))

         goto error;

   }

   // position and size the new doc window

   OutlineApp_ResizeWindows(lpOutlineApp);

   OutlineDoc_ShowWindow(lpOutlineApp->m_lpDoc);

#if defined( OLE_CNTR )

   UpdateWindow(lpOutlineApp->m_hWndApp);

   ContainerDoc_UpdateLinks((LPCONTAINERDOC)lpOutlineApp->m_lpDoc);

#endif

   OleDoc_Release((LPOLEDOC)lpOutlineApp->m_lpDoc);  // rel artificial AddRef

   return;

error:

   // REVIEW: should load string from string resource

   OutlineApp_ErrorMessage(lpOutlineApp, OLESTR("Could not create new document"));

   if (lpOutlineApp->m_lpDoc) {

      // releasing the artificial AddRef above will destroy the document

      OleDoc_Release((LPOLEDOC)lpOutlineApp->m_lpDoc);

      lpOutlineApp->m_lpDoc = NULL;

   }

   return;

}

#if defined( OLE_CNTR )

/* OLE2NOTE: forward the WM_QUERYNEWPALETTE message (via

**    SendMessage) to UIActive in-place object if there is one.

**    this gives the UIActive object the opportunity to select

**    and realize its color palette as the FOREGROUND palette.

**    this is optional for in-place containers. if a container

**    prefers to force its color palette as the foreground

**    palette then it should NOT forward the this message. or

**    the container can give the UIActive object priority; if

**    the UIActive object returns 0 from the WM_QUERYNEWPALETTE

**    message (ie. it did not realize its own palette), then

**    the container can realize its palette.

**    (see ContainerDoc_ForwardPaletteChangedMsg for more info)

**

**    (It is a good idea for containers to use the standard

**    palette even if they do not use colors themselves. this

**    will allow embedded object to get a good distribution of

**    colors when they are being drawn by the container)

**

*/

LRESULT OleApp_QueryNewPalette(LPOLEAPP lpOleApp)

{

#if defined( INPLACE_CNTR )

   LPCONTAINERAPP lpContainerApp = (LPCONTAINERAPP)lpOleApp;

   if (lpContainerApp && lpContainerApp->m_hWndUIActiveObj) {

      if (SendMessage(lpContainerApp->m_hWndUIActiveObj, WM_QUERYNEWPALETTE,

            (WPARAM)0, (LPARAM)0)) {

         /* Object selected its palette as foreground palette */

         return (LRESULT)1;

      }

   }

#endif  // INPLACE_CNTR

   return wSelectPalette(((LPOUTLINEAPP)lpOleApp)->m_hWndApp,

      lpOleApp->m_hStdPal, FALSE/*fBackground*/);

}

#endif // OLE_CNTR

/* This is just a helper routine */

LRESULT wSelectPalette(HWND hWnd, HPALETTE hPal, BOOL fBackground)

{

   HDC hdc;

   HPALETTE hOldPal;

   UINT iPalChg = 0;

   if (hPal == 0)

      return (LRESULT)0;

   hdc = GetDC(hWnd);

   hOldPal = SelectPalette(hdc, hPal, fBackground);

   iPalChg = RealizePalette(hdc);

   SelectPalette(hdc, hOldPal, TRUE /*fBackground*/);

   ReleaseDC(hWnd, hdc);

   if (iPalChg > 0)

      InvalidateRect(hWnd, NULL, TRUE);

   return (LRESULT)1;

}

/*************************************************************************

** OleApp::IUnknown interface implementation

*************************************************************************/

STDMETHODIMP OleApp_Unk_QueryInterface(

      LPUNKNOWN           lpThis,

      REFIID              riid,

      LPVOID FAR*         lplpvObj

)

{

   LPOLEAPP lpOleApp = ((struct CAppUnknownImpl FAR*)lpThis)->lpOleApp;

   return OleApp_QueryInterface(lpOleApp, riid, lplpvObj);

}

STDMETHODIMP_(ULONG) OleApp_Unk_AddRef(LPUNKNOWN lpThis)

{

   LPOLEAPP lpOleApp = ((struct CAppUnknownImpl FAR*)lpThis)->lpOleApp;

   OleDbgAddRefMethod(lpThis, "IUnknown");

   return OleApp_AddRef(lpOleApp);

}

STDMETHODIMP_(ULONG) OleApp_Unk_Release (LPUNKNOWN lpThis)

{

   LPOLEAPP lpOleApp = ((struct CAppUnknownImpl FAR*)lpThis)->lpOleApp;

   OleDbgReleaseMethod(lpThis, "IUnknown");

   return OleApp_Release(lpOleApp);

}

#if defined( OLE_SERVER )

/*************************************************************************

** ServerDoc Supprt Functions Used by Server versions

*************************************************************************/

/* ServerApp_InitInstance

 * ----------------------

 *

 * Initialize the app instance by creating the main frame window and

 * performing app instance specific initializations

 *  (eg. initializing interface Vtbls).

 *

 * RETURNS: TRUE if the memory could be allocated, and the server app

 *               was properly initialized.

 *          FALSE otherwise

 *

 */

BOOL ServerApp_InitInstance(

      LPSERVERAPP             lpServerApp,

      HINSTANCE               hInst,

      int                     nCmdShow

)

{

   LPOLEAPP lpOleApp = (LPOLEAPP)lpServerApp;

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)lpServerApp;

   /* Setup arrays used by IDataObject::EnumFormatEtc.

   **

   ** OLE2NOTE: The order that the formats are listed for GetData is very

   **    significant. It should be listed in order of highest fidelity

   **    formats to least fidelity formats. A common ordering will be:

   **                  1. private app formats

   **                  2. EmbedSource

   **                  3. lower fidelity interchange formats

   **                  4. pictures (metafile, dib, etc.)

   **                      (graphic-related apps offer pictures 1st!)

   **                  5. LinkSource

   */

   /* m_arrDocGetFmts array enumerates the formats that a ServerDoc

   **    DataTransferDoc object can offer (give) through a

   **    IDataObject::GetData call. a ServerDoc DataTransferDoc offers

   **    data formats in the following order:

   **                  1. CF_OUTLINE

   **                  2. CF_EMBEDSOURCE

   **                  3. CF_OBJECTDESCRIPTOR

   **                  4. CF_TEXT

   **                  5. CF_METAFILEPICT

   **                  6. CF_LINKSOURCE *

   **                  7. CF_LINKSRCDESCRIPTOR *

   **

   **    * NOTE: CF_LINKSOURCE and CF_LINKSRCDESCRIPTOR is only

   **    offered if the doc is able to give

   **    a Moniker which references the data. CF_LINKSOURCE is

   **    deliberately listed last in this array of possible formats.

   **    if the doc does not have a Moniker then the last element of

   **    this array is not used. (see SvrDoc_DataObj_EnumFormatEtc).

   **

   **    NOTE: The list of formats that a USER ServerDoc document can

   **    offer is a static list and is registered in the registration

   **    database for the SVROUTL class. The

   **    IDataObject::EnumFormatEtc method returns OLE_S_USEREG in the

   **    case the document is a user docuemt (ie. created via

   **    File.New, File.Open, InsertObject in a container, or

   **    IPersistFile::Load during binding a link source). this tells

   **    OLE to enumerate the formats automatically using the data the

   **    the REGDB.

   */

   lpOleApp->m_arrDocGetFmts[0].cfFormat   = lpOutlineApp->m_cfOutline;

   lpOleApp->m_arrDocGetFmts[0].ptd        = NULL;

   lpOleApp->m_arrDocGetFmts[0].dwAspect   = DVASPECT_CONTENT;

   lpOleApp->m_arrDocGetFmts[0].tymed      = TYMED_HGLOBAL;

   lpOleApp->m_arrDocGetFmts[0].lindex     = -1;

   lpOleApp->m_arrDocGetFmts[1].cfFormat   = lpOleApp->m_cfEmbedSource;

   lpOleApp->m_arrDocGetFmts[1].ptd        = NULL;

   lpOleApp->m_arrDocGetFmts[1].dwAspect   = DVASPECT_CONTENT;

   lpOleApp->m_arrDocGetFmts[1].tymed      = TYMED_ISTORAGE;

   lpOleApp->m_arrDocGetFmts[1].lindex     = -1;

   lpOleApp->m_arrDocGetFmts[2].cfFormat   = CF_TEXT;

   lpOleApp->m_arrDocGetFmts[2].ptd        = NULL;

   lpOleApp->m_arrDocGetFmts[2].dwAspect   = DVASPECT_CONTENT;

   lpOleApp->m_arrDocGetFmts[2].tymed      = TYMED_HGLOBAL;

   lpOleApp->m_arrDocGetFmts[2].lindex     = -1;

   lpOleApp->m_arrDocGetFmts[3].cfFormat   = CF_METAFILEPICT;

   lpOleApp->m_arrDocGetFmts[3].ptd        = NULL;

   lpOleApp->m_arrDocGetFmts[3].dwAspect   = DVASPECT_CONTENT;

   lpOleApp->m_arrDocGetFmts[3].tymed      = TYMED_MFPICT;

   lpOleApp->m_arrDocGetFmts[3].lindex     = -1;

   lpOleApp->m_arrDocGetFmts[4].cfFormat   = lpOleApp->m_cfObjectDescriptor;

   lpOleApp->m_arrDocGetFmts[4].ptd        = NULL;

   lpOleApp->m_arrDocGetFmts[4].dwAspect   = DVASPECT_CONTENT;

   lpOleApp->m_arrDocGetFmts[4].tymed      = TYMED_HGLOBAL;

   lpOleApp->m_arrDocGetFmts[4].lindex     = -1;

   lpOleApp->m_arrDocGetFmts[5].cfFormat   = lpOleApp->m_cfLinkSource;

   lpOleApp->m_arrDocGetFmts[5].ptd        = NULL;

   lpOleApp->m_arrDocGetFmts[5].dwAspect   = DVASPECT_CONTENT;

   lpOleApp->m_arrDocGetFmts[5].tymed      = TYMED_ISTREAM;

   lpOleApp->m_arrDocGetFmts[5].lindex     = -1;

   lpOleApp->m_arrDocGetFmts[6].cfFormat   = lpOleApp->m_cfLinkSrcDescriptor;

   lpOleApp->m_arrDocGetFmts[6].ptd        = NULL;

   lpOleApp->m_arrDocGetFmts[6].dwAspect   = DVASPECT_CONTENT;

   lpOleApp->m_arrDocGetFmts[6].tymed      = TYMED_HGLOBAL;

   lpOleApp->m_arrDocGetFmts[6].lindex     = -1;

   lpOleApp->m_nDocGetFmts = 7;

   /* m_arrPasteEntries array enumerates the formats that a ServerDoc

   **    object can accept (get) from the clipboard.

   **    The formats are listed in priority order.

   **    ServerDoc accept data formats in the following order:

   **                  1. CF_OUTLINE

   **                  2. CF_TEXT

   */

   // REVIEW: strings should be loaded from string resource

   lpOleApp->m_arrPasteEntries[0].fmtetc.cfFormat =lpOutlineApp->m_cfOutline;

   lpOleApp->m_arrPasteEntries[0].fmtetc.ptd      = NULL;

   lpOleApp->m_arrPasteEntries[0].fmtetc.dwAspect = DVASPECT_CONTENT;

   lpOleApp->m_arrPasteEntries[0].fmtetc.tymed    = TYMED_HGLOBAL;

   lpOleApp->m_arrPasteEntries[0].fmtetc.lindex   = -1;

   lpOleApp->m_arrPasteEntries[0].lpstrFormatName = "Outline Data";

   lpOleApp->m_arrPasteEntries[0].lpstrResultText = "Outline Data";

   lpOleApp->m_arrPasteEntries[0].dwFlags         = OLEUIPASTE_PASTEONLY;

   lpOleApp->m_arrPasteEntries[1].fmtetc.cfFormat = CF_TEXT;

   lpOleApp->m_arrPasteEntries[1].fmtetc.ptd      = NULL;

   lpOleApp->m_arrPasteEntries[1].fmtetc.dwAspect = DVASPECT_CONTENT;

   lpOleApp->m_arrPasteEntries[1].fmtetc.tymed    = TYMED_HGLOBAL;

   lpOleApp->m_arrPasteEntries[1].fmtetc.lindex   = -1;

   lpOleApp->m_arrPasteEntries[1].lpstrFormatName = "Text";

   lpOleApp->m_arrPasteEntries[1].lpstrResultText = "text";

   lpOleApp->m_arrPasteEntries[1].dwFlags         = OLEUIPASTE_PASTEONLY;

   lpOleApp->m_nPasteEntries = 2;

   /**    m_arrLinkTypes array enumerates the link types that a ServerDoc

   **    object can accept from the clipboard. ServerDoc does NOT

   **    accept any type of link from the clipboard. ServerDoc can

   **    only be the source of a link. it can not contain links.

   */

   lpOleApp->m_nLinkTypes = 0;

#if defined( INPLACE_SVR )

   lpServerApp->m_hAccelBaseApp = NULL;

   lpServerApp->m_hAccelIPSvr = LoadAccelerators(

         hInst,

         "InPlaceSvrOutlAccel"

   );

   lpServerApp->m_lpIPData = NULL;

   lpServerApp->m_hMenuEdit = GetSubMenu (

         lpOutlineApp->m_hMenuApp,

         POS_EDITMENU

   );

   lpServerApp->m_hMenuLine = GetSubMenu (

         lpOutlineApp->m_hMenuApp,

         POS_LINEMENU

   );

   lpServerApp->m_hMenuName = GetSubMenu (

         lpOutlineApp->m_hMenuApp,

         POS_NAMEMENU

   );

   lpServerApp->m_hMenuOptions = GetSubMenu (

         lpOutlineApp->m_hMenuApp,

         POS_OPTIONSMENU

   );

   lpServerApp->m_hMenuDebug = GetSubMenu (

         lpOutlineApp->m_hMenuApp,

         POS_DEBUGMENU

   );

   lpServerApp->m_hMenuHelp = GetSubMenu (

         lpOutlineApp->m_hMenuApp,

         POS_HELPMENU

   );

#endif  // INPLACE_SVR

   return TRUE;

}

/* ServerApp_InitVtbls

 * -------------------

 *

 * initialize the methods in all of the interface Vtbl's

 *

 * OLE2NOTE: we only need one copy of each Vtbl. When an object which

 *      exposes an interface is instantiated, its lpVtbl is intialized

 *      to point to the single copy of the Vtbl.

 *

 */

BOOL ServerApp_InitVtbls (LPSERVERAPP lpServerApp)

{

   BOOL fStatus;

   // ServerDoc::IOleObject method table

   OleStdInitVtbl(&g_SvrDoc_OleObjectVtbl, sizeof(IOleObjectVtbl));

   g_SvrDoc_OleObjectVtbl.QueryInterface   = SvrDoc_OleObj_QueryInterface;

   g_SvrDoc_OleObjectVtbl.AddRef           = SvrDoc_OleObj_AddRef;

   g_SvrDoc_OleObjectVtbl.Release          = SvrDoc_OleObj_Release;

   g_SvrDoc_OleObjectVtbl.SetClientSite    = SvrDoc_OleObj_SetClientSite;

   g_SvrDoc_OleObjectVtbl.GetClientSite    = SvrDoc_OleObj_GetClientSite;

   g_SvrDoc_OleObjectVtbl.SetHostNames     = SvrDoc_OleObj_SetHostNames;

   g_SvrDoc_OleObjectVtbl.Close            = SvrDoc_OleObj_Close;

   g_SvrDoc_OleObjectVtbl.SetMoniker       = SvrDoc_OleObj_SetMoniker;

   g_SvrDoc_OleObjectVtbl.GetMoniker       = SvrDoc_OleObj_GetMoniker;

   g_SvrDoc_OleObjectVtbl.InitFromData     = SvrDoc_OleObj_InitFromData;

   g_SvrDoc_OleObjectVtbl.GetClipboardData = SvrDoc_OleObj_GetClipboardData;

   g_SvrDoc_OleObjectVtbl.DoVerb           = SvrDoc_OleObj_DoVerb;

   g_SvrDoc_OleObjectVtbl.EnumVerbs        = SvrDoc_OleObj_EnumVerbs;

   g_SvrDoc_OleObjectVtbl.Update           = SvrDoc_OleObj_Update;

   g_SvrDoc_OleObjectVtbl.IsUpToDate       = SvrDoc_OleObj_IsUpToDate;

   g_SvrDoc_OleObjectVtbl.GetUserClassID   = SvrDoc_OleObj_GetUserClassID;

   g_SvrDoc_OleObjectVtbl.GetUserType      = SvrDoc_OleObj_GetUserType;

   g_SvrDoc_OleObjectVtbl.SetExtent        = SvrDoc_OleObj_SetExtent;

   g_SvrDoc_OleObjectVtbl.GetExtent        = SvrDoc_OleObj_GetExtent;

   g_SvrDoc_OleObjectVtbl.Advise           = SvrDoc_OleObj_Advise;

   g_SvrDoc_OleObjectVtbl.Unadvise         = SvrDoc_OleObj_Unadvise;

   g_SvrDoc_OleObjectVtbl.EnumAdvise       = SvrDoc_OleObj_EnumAdvise;

   g_SvrDoc_OleObjectVtbl.GetMiscStatus    = SvrDoc_OleObj_GetMiscStatus;

   g_SvrDoc_OleObjectVtbl.SetColorScheme   = SvrDoc_OleObj_SetColorScheme;

   fStatus = OleStdCheckVtbl(

         &g_SvrDoc_OleObjectVtbl,

         sizeof(IOleObjectVtbl),

         OLESTR("IOleObject")

      );

   if (! fStatus) return FALSE;

   // ServerDoc::IPersistStorage method table

   OleStdInitVtbl(&g_SvrDoc_PersistStorageVtbl, sizeof(IPersistStorageVtbl));

   g_SvrDoc_PersistStorageVtbl.QueryInterface  = SvrDoc_PStg_QueryInterface;

   g_SvrDoc_PersistStorageVtbl.AddRef          = SvrDoc_PStg_AddRef;

   g_SvrDoc_PersistStorageVtbl.Release         = SvrDoc_PStg_Release;

   g_SvrDoc_PersistStorageVtbl.GetClassID      = SvrDoc_PStg_GetClassID;

   g_SvrDoc_PersistStorageVtbl.IsDirty         = SvrDoc_PStg_IsDirty;

   g_SvrDoc_PersistStorageVtbl.InitNew         = SvrDoc_PStg_InitNew;

   g_SvrDoc_PersistStorageVtbl.Load            = SvrDoc_PStg_Load;

   g_SvrDoc_PersistStorageVtbl.Save            = SvrDoc_PStg_Save;

   g_SvrDoc_PersistStorageVtbl.SaveCompleted   = SvrDoc_PStg_SaveCompleted;

   g_SvrDoc_PersistStorageVtbl.HandsOffStorage = SvrDoc_PStg_HandsOffStorage;

   fStatus = OleStdCheckVtbl(

         &g_SvrDoc_PersistStorageVtbl,

         sizeof(IPersistStorageVtbl),

         OLESTR("IPersistStorage")

      );

   if (! fStatus) return FALSE;

#if defined( SVR_TREATAS )

   // ServerDoc::IStdMarshalInfo method table

   OleStdInitVtbl(

         &g_SvrDoc_StdMarshalInfoVtbl, sizeof(IStdMarshalInfoVtbl));

   g_SvrDoc_StdMarshalInfoVtbl.QueryInterface  =

                                 SvrDoc_StdMshl_QueryInterface;

   g_SvrDoc_StdMarshalInfoVtbl.AddRef          = SvrDoc_StdMshl_AddRef;

   g_SvrDoc_StdMarshalInfoVtbl.Release         = SvrDoc_StdMshl_Release;

   g_SvrDoc_StdMarshalInfoVtbl.GetClassForHandler =

                                 SvrDoc_StdMshl_GetClassForHandler;

   fStatus = OleStdCheckVtbl(

         &g_SvrDoc_StdMarshalInfoVtbl,

         sizeof(IStdMarshalInfoVtbl),

         OLESTR("IStdMarshalInfo")

      );

   if (! fStatus) return FALSE;

#endif  // SVR_TREATAS

#if defined( INPLACE_SVR )

   // ServerDoc::IOleInPlaceObject method table

   OleStdInitVtbl(

      &g_SvrDoc_OleInPlaceObjectVtbl,

      sizeof(IOleInPlaceObjectVtbl)

   );

   g_SvrDoc_OleInPlaceObjectVtbl.QueryInterface

                  = SvrDoc_IPObj_QueryInterface;

   g_SvrDoc_OleInPlaceObjectVtbl.AddRef

                  = SvrDoc_IPObj_AddRef;

   g_SvrDoc_OleInPlaceObjectVtbl.Release

                  = SvrDoc_IPObj_Release;

   g_SvrDoc_OleInPlaceObjectVtbl.GetWindow

                  = SvrDoc_IPObj_GetWindow;

   g_SvrDoc_OleInPlaceObjectVtbl.ContextSensitiveHelp

                  = SvrDoc_IPObj_ContextSensitiveHelp;

   g_SvrDoc_OleInPlaceObjectVtbl.InPlaceDeactivate

                  = SvrDoc_IPObj_InPlaceDeactivate;

   g_SvrDoc_OleInPlaceObjectVtbl.UIDeactivate

                  = SvrDoc_IPObj_UIDeactivate;

   g_SvrDoc_OleInPlaceObjectVtbl.SetObjectRects

                  = SvrDoc_IPObj_SetObjectRects;

   g_SvrDoc_OleInPlaceObjectVtbl.ReactivateAndUndo

                  = SvrDoc_IPObj_ReactivateAndUndo;

   fStatus = OleStdCheckVtbl(

         &g_SvrDoc_OleInPlaceObjectVtbl,

         sizeof(IOleInPlaceObjectVtbl),

         OLESTR("IOleInPlaceObject")

      );

   if (! fStatus) return FALSE;

   // ServerDoc::IOleInPlaceActiveObject method table

   OleStdInitVtbl(

      &g_SvrDoc_OleInPlaceActiveObjectVtbl,

      sizeof(IOleInPlaceActiveObjectVtbl)

   );

   g_SvrDoc_OleInPlaceActiveObjectVtbl.QueryInterface

                  = SvrDoc_IPActiveObj_QueryInterface;

   g_SvrDoc_OleInPlaceActiveObjectVtbl.AddRef

                  = SvrDoc_IPActiveObj_AddRef;

   g_SvrDoc_OleInPlaceActiveObjectVtbl.Release

                  = SvrDoc_IPActiveObj_Release;

   g_SvrDoc_OleInPlaceActiveObjectVtbl.GetWindow

                  = SvrDoc_IPActiveObj_GetWindow;

   g_SvrDoc_OleInPlaceActiveObjectVtbl.ContextSensitiveHelp

                  = SvrDoc_IPActiveObj_ContextSensitiveHelp;

   g_SvrDoc_OleInPlaceActiveObjectVtbl.TranslateAccelerator

                  = SvrDoc_IPActiveObj_TranslateAccelerator;

   g_SvrDoc_OleInPlaceActiveObjectVtbl.OnFrameWindowActivate

                  = SvrDoc_IPActiveObj_OnFrameWindowActivate;

   g_SvrDoc_OleInPlaceActiveObjectVtbl.OnDocWindowActivate

                  = SvrDoc_IPActiveObj_OnDocWindowActivate;

   g_SvrDoc_OleInPlaceActiveObjectVtbl.ResizeBorder

                  = SvrDoc_IPActiveObj_ResizeBorder;

   g_SvrDoc_OleInPlaceActiveObjectVtbl.EnableModeless

                  = SvrDoc_IPActiveObj_EnableModeless;

   fStatus = OleStdCheckVtbl(

         &g_SvrDoc_OleInPlaceActiveObjectVtbl,

         sizeof(IOleInPlaceActiveObjectVtbl),

         OLESTR("IOleInPlaceActiveObject")

      );

   if (! fStatus) return FALSE;

#endif

   // PseudoObj::IUnknown method table

   OleStdInitVtbl(&g_PseudoObj_UnknownVtbl, sizeof(IUnknownVtbl));

   g_PseudoObj_UnknownVtbl.QueryInterface  = PseudoObj_Unk_QueryInterface;

   g_PseudoObj_UnknownVtbl.AddRef          = PseudoObj_Unk_AddRef;

   g_PseudoObj_UnknownVtbl.Release         = PseudoObj_Unk_Release;

   fStatus = OleStdCheckVtbl(

         &g_PseudoObj_UnknownVtbl,

         sizeof(IUnknownVtbl),

         OLESTR("IUnknown")

      );

   if (! fStatus) return FALSE;

   // PseudoObj::IOleObject method table

   OleStdInitVtbl(&g_PseudoObj_OleObjectVtbl, sizeof(IOleObjectVtbl));

   g_PseudoObj_OleObjectVtbl.QueryInterface= PseudoObj_OleObj_QueryInterface;

   g_PseudoObj_OleObjectVtbl.AddRef        = PseudoObj_OleObj_AddRef;

   g_PseudoObj_OleObjectVtbl.Release       = PseudoObj_OleObj_Release;

   g_PseudoObj_OleObjectVtbl.SetClientSite = PseudoObj_OleObj_SetClientSite;

   g_PseudoObj_OleObjectVtbl.GetClientSite = PseudoObj_OleObj_GetClientSite;

   g_PseudoObj_OleObjectVtbl.SetHostNames  = PseudoObj_OleObj_SetHostNames;

   g_PseudoObj_OleObjectVtbl.Close         = PseudoObj_OleObj_Close;

   g_PseudoObj_OleObjectVtbl.SetMoniker    = PseudoObj_OleObj_SetMoniker;

   g_PseudoObj_OleObjectVtbl.GetMoniker    = PseudoObj_OleObj_GetMoniker;

   g_PseudoObj_OleObjectVtbl.InitFromData  = PseudoObj_OleObj_InitFromData;

   g_PseudoObj_OleObjectVtbl.GetClipboardData =

                                 PseudoObj_OleObj_GetClipboardData;

   g_PseudoObj_OleObjectVtbl.DoVerb        = PseudoObj_OleObj_DoVerb;

   g_PseudoObj_OleObjectVtbl.EnumVerbs     = PseudoObj_OleObj_EnumVerbs;

   g_PseudoObj_OleObjectVtbl.Update        = PseudoObj_OleObj_Update;

   g_PseudoObj_OleObjectVtbl.IsUpToDate    = PseudoObj_OleObj_IsUpToDate;

   g_PseudoObj_OleObjectVtbl.GetUserType   = PseudoObj_OleObj_GetUserType;

   g_PseudoObj_OleObjectVtbl.GetUserClassID= PseudoObj_OleObj_GetUserClassID;

   g_PseudoObj_OleObjectVtbl.SetExtent     = PseudoObj_OleObj_SetExtent;

   g_PseudoObj_OleObjectVtbl.GetExtent     = PseudoObj_OleObj_GetExtent;

   g_PseudoObj_OleObjectVtbl.Advise        = PseudoObj_OleObj_Advise;

   g_PseudoObj_OleObjectVtbl.Unadvise      = PseudoObj_OleObj_Unadvise;

   g_PseudoObj_OleObjectVtbl.EnumAdvise    = PseudoObj_OleObj_EnumAdvise;

   g_PseudoObj_OleObjectVtbl.GetMiscStatus = PseudoObj_OleObj_GetMiscStatus;

   g_PseudoObj_OleObjectVtbl.SetColorScheme= PseudoObj_OleObj_SetColorScheme;

   fStatus = OleStdCheckVtbl(

         &g_PseudoObj_OleObjectVtbl,

         sizeof(IOleObjectVtbl),

         OLESTR("IOleObject")

      );

   if (! fStatus) return FALSE;

   // ServerDoc::IDataObject method table

   OleStdInitVtbl(&g_PseudoObj_DataObjectVtbl, sizeof(IDataObjectVtbl));

   g_PseudoObj_DataObjectVtbl.QueryInterface =

                           PseudoObj_DataObj_QueryInterface;

   g_PseudoObj_DataObjectVtbl.AddRef       = PseudoObj_DataObj_AddRef;

   g_PseudoObj_DataObjectVtbl.Release      = PseudoObj_DataObj_Release;

   g_PseudoObj_DataObjectVtbl.GetData      = PseudoObj_DataObj_GetData;

   g_PseudoObj_DataObjectVtbl.GetDataHere  = PseudoObj_DataObj_GetDataHere;

   g_PseudoObj_DataObjectVtbl.QueryGetData = PseudoObj_DataObj_QueryGetData;

   g_PseudoObj_DataObjectVtbl.GetCanonicalFormatEtc =

                           PseudoObj_DataObj_GetCanonicalFormatEtc;

   g_PseudoObj_DataObjectVtbl.SetData      = PseudoObj_DataObj_SetData;

   g_PseudoObj_DataObjectVtbl.EnumFormatEtc= PseudoObj_DataObj_EnumFormatEtc;

   g_PseudoObj_DataObjectVtbl.DAdvise       = PseudoObj_DataObj_DAdvise;

   g_PseudoObj_DataObjectVtbl.DUnadvise     = PseudoObj_DataObj_DUnadvise;

   g_PseudoObj_DataObjectVtbl.EnumDAdvise   = PseudoObj_DataObj_EnumAdvise;

   fStatus = OleStdCheckVtbl(

         &g_PseudoObj_DataObjectVtbl,

         sizeof(IDataObjectVtbl),

         OLESTR("IDataObject")

      );

   if (! fStatus) return FALSE;

   return TRUE;

}

#endif  // OLE_SERVER

#if defined( OLE_CNTR )

/*************************************************************************

** ContainerDoc Supprt Functions Used by Container versions

*************************************************************************/

/* ContainerApp_InitInstance

 * -------------------------

 *

 * Initialize the app instance by creating the main frame window and

 * performing app instance specific initializations

 *  (eg. initializing interface Vtbls).

 *

 * RETURNS: TRUE if the memory could be allocated, and the server app

 *               was properly initialized.

 *          FALSE otherwise

 *

 */

BOOL ContainerApp_InitInstance(

      LPCONTAINERAPP          lpContainerApp,

      HINSTANCE               hInst,

      int                     nCmdShow

)

{

   LPOLEAPP lpOleApp = (LPOLEAPP)lpContainerApp;

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)lpContainerApp;

   char  szAnsiString[256];

   W2A (CONTAINERDOCFORMAT, szAnsiString, 256);

   lpContainerApp->m_cfCntrOutl=RegisterClipboardFormat(szAnsiString);

   if(! lpContainerApp->m_cfCntrOutl) {

      // REVIEW: should load string from string resource

      OutlineApp_ErrorMessage(lpOutlineApp, OLESTR("Can't register clipboard format!"));

      return FALSE;

   }

#if defined( INPLACE_CNTR )

   lpContainerApp->m_fPendingUIDeactivate  = FALSE;

   lpContainerApp->m_fMustResizeClientArea = FALSE;

   lpContainerApp->m_lpIPActiveObj         = NULL;

   lpContainerApp->m_hWndUIActiveObj       = NULL;

   lpContainerApp->m_hAccelIPCntr = LoadAccelerators(

         hInst,

         "InPlaceCntrOutlAccel"

   );

   lpContainerApp->m_hMenuFile = GetSubMenu (

         lpOutlineApp->m_hMenuApp,

         POS_FILEMENU

   );

   lpContainerApp->m_hMenuView = GetSubMenu (

         lpOutlineApp->m_hMenuApp,

         POS_VIEWMENU

   );

   lpContainerApp->m_hMenuDebug = GetSubMenu (

         lpOutlineApp->m_hMenuApp,

         POS_DEBUGMENU

   );

   INIT_INTERFACEIMPL(

         &lpContainerApp->m_OleInPlaceFrame,

         &g_CntrApp_OleInPlaceFrameVtbl,

         lpContainerApp

   );

#endif

   /* Setup arrays used by IDataObject::EnumFormatEtc. This is used to

   **    support copy/paste and drag/drop operations.

   **

   ** OLE2NOTE: The order that the formats are listed for GetData is very

   **    significant. It should be listed in order of highest fidelity

   **    formats to least fidelity formats. A common ordering will be:

   **                  1. private app formats

   **                  2. CF_EMBEDSOURCE or CF_EMBEDOBJECT (as appropriate)

   **                  3. lower fidelity interchange formats

   **                  4. CF_METAFILEPICT

   **                      (graphic-related apps might offer picture 1st!)

   **                  5. CF_OBJECTDESCRIPTOR

   **                  6. CF_LINKSOURCE

   **                  6. CF_LINKSRCDESCRIPTOR

   */

   /* m_arrDocGetFmts array enumerates the formats that a ContainerDoc

   **    object can offer (give) through a IDataObject::GetData call

   **    when the selection copied is NOT a single embedded object.

   **    when a single embedded object this list of formats available

   **    is built dynamically depending on the object copied. (see

   **    ContainerDoc_SetupDocGetFmts).

   **    The formats are listed in priority order.

   **    ContainerDoc objects accept data formats in the following order:

   **                  1. CF_CNTROUTL

   **                  2. CF_OUTLINE

   **                  3. CF_TEXT

   **                  4. CF_OBJECTDESCRIPTOR

   **

   **    OLE2NOTE: CF_OBJECTDESCRIPTOR format is used to describe the

   **    data on the clipboard. this information is intended to be

   **    used, for example, to drive the PasteSpecial dialog. it is

   **    useful to render CF_OBJECTDESCRIPTOR format even when the

   **    data on the clipboard does NOT include CF_EMBEDDEDOBJECT

   **    format or CF_EMBEDSOURCE format as when a selection that is

   **    not a single OLE object is copied from the container only

   **    version CNTROUTL. by rendering CF_OBJECTDESCRIPTOR format the

   **    app can indicate a useful string to identifiy the source of

   **    the copy to the user.

   */

   lpOleApp->m_arrDocGetFmts[0].cfFormat = lpContainerApp->m_cfCntrOutl;

   lpOleApp->m_arrDocGetFmts[0].ptd      = NULL;

   lpOleApp->m_arrDocGetFmts[0].dwAspect = DVASPECT_CONTENT;

   lpOleApp->m_arrDocGetFmts[0].tymed    = TYMED_ISTORAGE;

   lpOleApp->m_arrDocGetFmts[0].lindex   = -1;

   lpOleApp->m_arrDocGetFmts[1].cfFormat = lpOutlineApp->m_cfOutline;

   lpOleApp->m_arrDocGetFmts[1].ptd      = NULL;

   lpOleApp->m_arrDocGetFmts[1].dwAspect = DVASPECT_CONTENT;

   lpOleApp->m_arrDocGetFmts[1].tymed    = TYMED_HGLOBAL;

   lpOleApp->m_arrDocGetFmts[1].lindex   = -1;

   lpOleApp->m_arrDocGetFmts[2].cfFormat = CF_TEXT;

   lpOleApp->m_arrDocGetFmts[2].ptd      = NULL;

   lpOleApp->m_arrDocGetFmts[2].dwAspect = DVASPECT_CONTENT;

   lpOleApp->m_arrDocGetFmts[2].tymed    = TYMED_HGLOBAL;

   lpOleApp->m_arrDocGetFmts[2].lindex   = -1;

   lpOleApp->m_arrDocGetFmts[3].cfFormat = lpOleApp->m_cfObjectDescriptor;

   lpOleApp->m_arrDocGetFmts[3].ptd      = NULL;

   lpOleApp->m_arrDocGetFmts[3].dwAspect = DVASPECT_CONTENT;

   lpOleApp->m_arrDocGetFmts[3].tymed    = TYMED_HGLOBAL;

   lpOleApp->m_arrDocGetFmts[3].lindex   = -1;

   lpOleApp->m_nDocGetFmts = 4;

   /* m_arrSingleObjGetFmts array enumerates the formats that a

   **    ContainerDoc object can offer (give) through a

   **    IDataObject::GetData call when the selection copied IS a

   **    single OLE object.

   **    ContainerDoc objects accept data formats in the following order:

   **                  1. CF_CNTROUTL

   **                  2. CF_EMBEDDEDOBJECT

   **                  3. CF_OBJECTDESCRIPTOR

   **                  4. CF_METAFILEPICT  (note DVASPECT will vary)

   **                  5. CF_LINKSOURCE *

   **                  6. CF_LINKSRCDESCRIPTOR *

   **

   **    * OLE2NOTE: CF_LINKSOURCE and CF_LINKSRCDESCRIPTOR is only

   **    offered if the OLE object is allowed to be linked to from the

   **    inside (ie. we are allowed to give out a moniker which binds

   **    to the running OLE object), then we want to offer

   **    CF_LINKSOURCE format. if the object is an OLE 2.0 embedded

   **    object then it is allowed to be linked to from the inside. if

   **    the object is either an OleLink or an OLE 1.0 embedding then

   **    it can not be linked to from the inside. if we were a

   **    container/server app then we could offer linking to the

   **    outside of the object (ie. a pseudo object within our

   **    document). we are a container only app that does not support

   **    linking to ranges of its data.

   **    the simplest way to determine if an object can be linked to

   **    on the inside is to call IOleObject::GetMiscStatus and test

   **    to see if the OLEMISC_CANTLINKINSIDE bit is NOT set.

   **

   **    OLE2NOTE: optionally, a container that wants to have a

   **    potentially richer data transfer, can enumerate the data

   **    formats from the OLE object's cache and offer them too. if

   **    the object has a special handler, then it might be able to

   **    render additional data formats.

   */

   lpContainerApp->m_arrSingleObjGetFmts[0].cfFormat =

                                    lpContainerApp->m_cfCntrOutl;

   lpContainerApp->m_arrSingleObjGetFmts[0].ptd      = NULL;

   lpContainerApp->m_arrSingleObjGetFmts[0].dwAspect = DVASPECT_CONTENT;

   lpContainerApp->m_arrSingleObjGetFmts[0].tymed    = TYMED_ISTORAGE;

   lpContainerApp->m_arrSingleObjGetFmts[0].lindex   = -1;

   lpContainerApp->m_arrSingleObjGetFmts[1].cfFormat =

                                    lpOleApp->m_cfEmbeddedObject;

   lpContainerApp->m_arrSingleObjGetFmts[1].ptd      = NULL;

   lpContainerApp->m_arrSingleObjGetFmts[1].dwAspect = DVASPECT_CONTENT;

   lpContainerApp->m_arrSingleObjGetFmts[1].tymed    = TYMED_ISTORAGE;

   lpContainerApp->m_arrSingleObjGetFmts[1].lindex   = -1;

   lpContainerApp->m_arrSingleObjGetFmts[2].cfFormat =

                                    lpOleApp->m_cfObjectDescriptor;

   lpContainerApp->m_arrSingleObjGetFmts[2].ptd      = NULL;

   lpContainerApp->m_arrSingleObjGetFmts[2].dwAspect = DVASPECT_CONTENT;

   lpContainerApp->m_arrSingleObjGetFmts[2].tymed    = TYMED_HGLOBAL;

   lpContainerApp->m_arrSingleObjGetFmts[2].lindex   = -1;

   lpContainerApp->m_arrSingleObjGetFmts[3].cfFormat = CF_METAFILEPICT;

   lpContainerApp->m_arrSingleObjGetFmts[3].ptd      = NULL;

   lpContainerApp->m_arrSingleObjGetFmts[3].dwAspect = DVASPECT_CONTENT;

   lpContainerApp->m_arrSingleObjGetFmts[3].tymed    = TYMED_MFPICT;

   lpContainerApp->m_arrSingleObjGetFmts[3].lindex   = -1;

   lpContainerApp->m_arrSingleObjGetFmts[4].cfFormat =

                                       lpOleApp->m_cfLinkSource;

   lpContainerApp->m_arrSingleObjGetFmts[4].ptd      = NULL;

   lpContainerApp->m_arrSingleObjGetFmts[4].dwAspect = DVASPECT_CONTENT;

   lpContainerApp->m_arrSingleObjGetFmts[4].tymed    = TYMED_ISTREAM;

   lpContainerApp->m_arrSingleObjGetFmts[4].lindex   = -1;

   lpContainerApp->m_arrSingleObjGetFmts[5].cfFormat =

                                   lpOleApp->m_cfLinkSrcDescriptor;

   lpContainerApp->m_arrSingleObjGetFmts[5].ptd      = NULL;

   lpContainerApp->m_arrSingleObjGetFmts[5].dwAspect = DVASPECT_CONTENT;

   lpContainerApp->m_arrSingleObjGetFmts[5].tymed    = TYMED_HGLOBAL;

   lpContainerApp->m_arrSingleObjGetFmts[5].lindex   = -1;

   lpContainerApp->m_nSingleObjGetFmts = 6;

   /* NOTE: the Container-Only version of Outline does NOT offer

   **    IDataObject interface from its User documents and the

   **    IDataObject interface available from DataTransferDoc's do NOT

   **    support SetData. IDataObject interface is required by objects

   **    which can be embedded or linked. the Container-only app only

   **    allows linking to its contained objects, NOT the data of the

   **    container itself.

   */

   /*    m_arrPasteEntries array enumerates the formats that a ContainerDoc

   **    object can accept from the clipboard. this array is used to

   **    support the PasteSpecial dialog.

   **    The formats are listed in priority order.

   **    ContainerDoc objects accept data formats in the following order:

   **                  1. CF_CNTROUTL

   **                  2. CF_OUTLINE

   **                  3. CF_EMBEDDEDOBJECT

   **                  4. CF_TEXT

   **                  5. CF_METAFILEPICT

   **                  6. CF_DIB

   **                  7. CF_BITMAP

   **                  8. CF_LINKSOURCE

   **

   **    NOTE: specifying CF_EMBEDDEDOBJECT in the PasteEntry array

   **    indicates that the caller is interested in pasting OLE

   **    objects (ie. the caller calls OleCreateFromData). the

   **    OleUIPasteSpecial dialog and OleStdGetPriorityClipboardFormat

   **    call OleQueryCreateFromData to see if an OLE object format is

   **    available. thus, in fact if CF_EMBEDSOURCE or CF_FILENAME are

   **    available from the data source then and OLE object can be

   **    created and this entry will be matched. the caller should

   **    only specify one object type format.

   **    CF_FILENAME format (as generated by copying a file to

   **    the clipboard from the FileManager) is considered an object

   **    format; OleCreatFromData creates an object if the file has an

   **    associated class (see GetClassFile API) or if no class it

   **    creates an OLE 1.0 Package object. this format can also be

   **    paste linked by calling OleCreateLinkFromData.

   */

   // REVIEW: strings should be loaded from string resource

   lpOleApp->m_arrPasteEntries[0].fmtetc.cfFormat =

                           lpContainerApp->m_cfCntrOutl;

   lpOleApp->m_arrPasteEntries[0].fmtetc.ptd      = NULL;

   lpOleApp->m_arrPasteEntries[0].fmtetc.dwAspect = DVASPECT_CONTENT;

   lpOleApp->m_arrPasteEntries[0].fmtetc.tymed    = TYMED_ISTORAGE;

   lpOleApp->m_arrPasteEntries[0].fmtetc.lindex   = -1;

   lpOleApp->m_arrPasteEntries[0].lpstrFormatName = "Container Outline Data";

   lpOleApp->m_arrPasteEntries[0].lpstrResultText = "Container Outline Data";

   lpOleApp->m_arrPasteEntries[0].dwFlags         = OLEUIPASTE_PASTEONLY;

   lpOleApp->m_arrPasteEntries[1].fmtetc.cfFormat =lpOutlineApp->m_cfOutline;

   lpOleApp->m_arrPasteEntries[1].fmtetc.ptd      = NULL;

   lpOleApp->m_arrPasteEntries[1].fmtetc.dwAspect = DVASPECT_CONTENT;

   lpOleApp->m_arrPasteEntries[1].fmtetc.tymed    = TYMED_HGLOBAL;

   lpOleApp->m_arrPasteEntries[1].fmtetc.lindex   = -1;

   lpOleApp->m_arrPasteEntries[1].lpstrFormatName = "Outline Data";

   lpOleApp->m_arrPasteEntries[1].lpstrResultText = "Outline Data";

   lpOleApp->m_arrPasteEntries[1].dwFlags         = OLEUIPASTE_PASTEONLY;

   lpOleApp->m_arrPasteEntries[2].fmtetc.cfFormat =

                           lpOleApp->m_cfEmbeddedObject;

   lpOleApp->m_arrPasteEntries[2].fmtetc.ptd      = NULL;

   lpOleApp->m_arrPasteEntries[2].fmtetc.dwAspect = DVASPECT_CONTENT;

   lpOleApp->m_arrPasteEntries[2].fmtetc.tymed    = TYMED_ISTORAGE;

   lpOleApp->m_arrPasteEntries[2].fmtetc.lindex   = -1;

   lpOleApp->m_arrPasteEntries[2].lpstrFormatName = "%s";

   lpOleApp->m_arrPasteEntries[2].lpstrResultText = "%s";

   lpOleApp->m_arrPasteEntries[2].dwFlags         =

                           OLEUIPASTE_PASTE | OLEUIPASTE_ENABLEICON;

   lpOleApp->m_arrPasteEntries[3].fmtetc.cfFormat = CF_TEXT;

   lpOleApp->m_arrPasteEntries[3].fmtetc.ptd      = NULL;

   lpOleApp->m_arrPasteEntries[3].fmtetc.dwAspect = DVASPECT_CONTENT;

   lpOleApp->m_arrPasteEntries[3].fmtetc.tymed    = TYMED_HGLOBAL;

   lpOleApp->m_arrPasteEntries[3].fmtetc.lindex   = -1;

   lpOleApp->m_arrPasteEntries[3].lpstrFormatName = "Text";

   lpOleApp->m_arrPasteEntries[3].lpstrResultText = "text";

   lpOleApp->m_arrPasteEntries[3].dwFlags         = OLEUIPASTE_PASTEONLY;

   lpOleApp->m_arrPasteEntries[4].fmtetc.cfFormat = CF_METAFILEPICT;

   lpOleApp->m_arrPasteEntries[4].fmtetc.ptd      = NULL;

   lpOleApp->m_arrPasteEntries[4].fmtetc.dwAspect = DVASPECT_CONTENT;

   lpOleApp->m_arrPasteEntries[4].fmtetc.tymed    = TYMED_MFPICT;

   lpOleApp->m_arrPasteEntries[4].fmtetc.lindex   = -1;

   lpOleApp->m_arrPasteEntries[4].lpstrFormatName = "Picture (Metafile)";

   lpOleApp->m_arrPasteEntries[4].lpstrResultText = "a static picture";

   lpOleApp->m_arrPasteEntries[4].dwFlags         = OLEUIPASTE_PASTEONLY;

   lpOleApp->m_arrPasteEntries[5].fmtetc.cfFormat = CF_DIB;

   lpOleApp->m_arrPasteEntries[5].fmtetc.ptd      = NULL;

   lpOleApp->m_arrPasteEntries[5].fmtetc.dwAspect = DVASPECT_CONTENT;

   lpOleApp->m_arrPasteEntries[5].fmtetc.tymed    = TYMED_HGLOBAL;

   lpOleApp->m_arrPasteEntries[5].fmtetc.lindex   = -1;

   lpOleApp->m_arrPasteEntries[5].lpstrFormatName = "Picture (DIB)";

   lpOleApp->m_arrPasteEntries[5].lpstrResultText = "a static picture";

   lpOleApp->m_arrPasteEntries[5].dwFlags         = OLEUIPASTE_PASTEONLY;

   lpOleApp->m_arrPasteEntries[6].fmtetc.cfFormat = CF_BITMAP;

   lpOleApp->m_arrPasteEntries[6].fmtetc.ptd      = NULL;

   lpOleApp->m_arrPasteEntries[6].fmtetc.dwAspect = DVASPECT_CONTENT;

   lpOleApp->m_arrPasteEntries[6].fmtetc.tymed    = TYMED_GDI;

   lpOleApp->m_arrPasteEntries[6].fmtetc.lindex   = -1;

   lpOleApp->m_arrPasteEntries[6].lpstrFormatName = "Picture (Bitmap)";

   lpOleApp->m_arrPasteEntries[6].lpstrResultText = "a static picture";

   lpOleApp->m_arrPasteEntries[6].dwFlags         = OLEUIPASTE_PASTEONLY;

   lpOleApp->m_arrPasteEntries[7].fmtetc.cfFormat = lpOleApp->m_cfLinkSource;

   lpOleApp->m_arrPasteEntries[7].fmtetc.ptd      = NULL;

   lpOleApp->m_arrPasteEntries[7].fmtetc.dwAspect = DVASPECT_CONTENT;

   lpOleApp->m_arrPasteEntries[7].fmtetc.tymed    = TYMED_ISTREAM;

   lpOleApp->m_arrPasteEntries[7].fmtetc.lindex   = -1;

   lpOleApp->m_arrPasteEntries[7].lpstrFormatName = "%s";

   lpOleApp->m_arrPasteEntries[7].lpstrResultText = "%s";

   lpOleApp->m_arrPasteEntries[7].dwFlags         =

                        OLEUIPASTE_LINKTYPE1 | OLEUIPASTE_ENABLEICON;

   lpOleApp->m_nPasteEntries = 8;

   /*    m_arrLinkTypes array enumerates the link types that a ContainerDoc

   **    object can accept from the clipboard

   */

   lpOleApp->m_arrLinkTypes[0] = lpOleApp->m_cfLinkSource;

   lpOleApp->m_nLinkTypes = 1;

   return TRUE;

}

/* ContainerApp_InitVtbls

** ----------------------

**

**    initialize the interface Vtbl's used to support the OLE 2.0

**    Container functionality.

*/

BOOL ContainerApp_InitVtbls(LPCONTAINERAPP lpApp)

{

   BOOL fStatus;

   // ContainerDoc::IOleUILinkContainer method table

   OleStdInitVtbl(

         &g_CntrDoc_OleUILinkContainerVtbl,

         sizeof(IOleUILinkContainerVtbl)

   );

   g_CntrDoc_OleUILinkContainerVtbl.QueryInterface =

                                 CntrDoc_LinkCont_QueryInterface;

   g_CntrDoc_OleUILinkContainerVtbl.AddRef    = CntrDoc_LinkCont_AddRef;

   g_CntrDoc_OleUILinkContainerVtbl.Release   = CntrDoc_LinkCont_Release;

   g_CntrDoc_OleUILinkContainerVtbl.GetNextLink =

                              CntrDoc_LinkCont_GetNextLink;

   g_CntrDoc_OleUILinkContainerVtbl.SetLinkUpdateOptions =

                              CntrDoc_LinkCont_SetLinkUpdateOptions;

   g_CntrDoc_OleUILinkContainerVtbl.GetLinkUpdateOptions =

                              CntrDoc_LinkCont_GetLinkUpdateOptions;

   g_CntrDoc_OleUILinkContainerVtbl.SetLinkSource =

                              CntrDoc_LinkCont_SetLinkSource;

   g_CntrDoc_OleUILinkContainerVtbl.GetLinkSource =

                              CntrDoc_LinkCont_GetLinkSource;

   g_CntrDoc_OleUILinkContainerVtbl.OpenLinkSource =

                              CntrDoc_LinkCont_OpenLinkSource;

   g_CntrDoc_OleUILinkContainerVtbl.UpdateLink =

                              CntrDoc_LinkCont_UpdateLink;

   g_CntrDoc_OleUILinkContainerVtbl.CancelLink =

                              CntrDoc_LinkCont_CancelLink;

   fStatus = OleStdCheckVtbl(

         &g_CntrDoc_OleUILinkContainerVtbl,

         sizeof(IOleUILinkContainerVtbl),

         OLESTR("IOleUILinkContainer")

      );

   if (! fStatus) return FALSE;

#if defined( INPLACE_CNTR )

   // ContainerApp::IOleInPlaceFrame interface method table

   OleStdInitVtbl(

         &g_CntrApp_OleInPlaceFrameVtbl,

         sizeof(g_CntrApp_OleInPlaceFrameVtbl)

   );

   g_CntrApp_OleInPlaceFrameVtbl.QueryInterface

                  = CntrApp_IPFrame_QueryInterface;

   g_CntrApp_OleInPlaceFrameVtbl.AddRef

                  = CntrApp_IPFrame_AddRef;

   g_CntrApp_OleInPlaceFrameVtbl.Release

                  = CntrApp_IPFrame_Release;

   g_CntrApp_OleInPlaceFrameVtbl.GetWindow

                  = CntrApp_IPFrame_GetWindow;

   g_CntrApp_OleInPlaceFrameVtbl.ContextSensitiveHelp

                  = CntrApp_IPFrame_ContextSensitiveHelp;

   g_CntrApp_OleInPlaceFrameVtbl.GetBorder

                  = CntrApp_IPFrame_GetBorder;

   g_CntrApp_OleInPlaceFrameVtbl.RequestBorderSpace

                  = CntrApp_IPFrame_RequestBorderSpace;

   g_CntrApp_OleInPlaceFrameVtbl.SetBorderSpace

                  = CntrApp_IPFrame_SetBorderSpace;

   g_CntrApp_OleInPlaceFrameVtbl.SetActiveObject

                  = CntrApp_IPFrame_SetActiveObject;

   g_CntrApp_OleInPlaceFrameVtbl.InsertMenus

                  = CntrApp_IPFrame_InsertMenus;

   g_CntrApp_OleInPlaceFrameVtbl.SetMenu

                  = CntrApp_IPFrame_SetMenu;

   g_CntrApp_OleInPlaceFrameVtbl.RemoveMenus

                  = CntrApp_IPFrame_RemoveMenus;

   g_CntrApp_OleInPlaceFrameVtbl.SetStatusText

                  = CntrApp_IPFrame_SetStatusText;

   g_CntrApp_OleInPlaceFrameVtbl.EnableModeless

                  = CntrApp_IPFrame_EnableModeless;

   g_CntrApp_OleInPlaceFrameVtbl.TranslateAccelerator

                  = CntrApp_IPFrame_TranslateAccelerator;

   fStatus = OleStdCheckVtbl(

         &g_CntrApp_OleInPlaceFrameVtbl,

         sizeof(g_CntrApp_OleInPlaceFrameVtbl),

         OLESTR("IOleInPlaceFrame")

      );

   if (! fStatus) return FALSE;

#endif  // INPLACE_CNTR

   // ContainerLine::IUnknown interface method table

   OleStdInitVtbl(

         &g_CntrLine_UnknownVtbl,

         sizeof(g_CntrLine_UnknownVtbl)

      );

   g_CntrLine_UnknownVtbl.QueryInterface   = CntrLine_Unk_QueryInterface;

   g_CntrLine_UnknownVtbl.AddRef           = CntrLine_Unk_AddRef;

   g_CntrLine_UnknownVtbl.Release          = CntrLine_Unk_Release;

   fStatus = OleStdCheckVtbl(

         &g_CntrLine_UnknownVtbl,

         sizeof(g_CntrLine_UnknownVtbl),

         OLESTR("IUnknown")

      );

   if (! fStatus) return FALSE;

   // ContainerLine::IOleClientSite interface method table

   OleStdInitVtbl(

         &g_CntrLine_OleClientSiteVtbl,

         sizeof(g_CntrLine_OleClientSiteVtbl)

      );

   g_CntrLine_OleClientSiteVtbl.QueryInterface =

                                 CntrLine_CliSite_QueryInterface;

   g_CntrLine_OleClientSiteVtbl.AddRef       = CntrLine_CliSite_AddRef;

   g_CntrLine_OleClientSiteVtbl.Release      = CntrLine_CliSite_Release;

   g_CntrLine_OleClientSiteVtbl.SaveObject   = CntrLine_CliSite_SaveObject;

   g_CntrLine_OleClientSiteVtbl.GetMoniker   = CntrLine_CliSite_GetMoniker;

   g_CntrLine_OleClientSiteVtbl.GetContainer = CntrLine_CliSite_GetContainer;

   g_CntrLine_OleClientSiteVtbl.ShowObject   = CntrLine_CliSite_ShowObject;

   g_CntrLine_OleClientSiteVtbl.OnShowWindow = CntrLine_CliSite_OnShowWindow;

   g_CntrLine_OleClientSiteVtbl.RequestNewObjectLayout =

                           CntrLine_CliSite_RequestNewObjectLayout;

   fStatus = OleStdCheckVtbl(

         &g_CntrLine_OleClientSiteVtbl,

         sizeof(g_CntrLine_OleClientSiteVtbl),

         OLESTR("IOleClientSite")

      );

   if (! fStatus) return FALSE;

   // ContainerLine::IAdviseSink interface method table

   OleStdInitVtbl(

         &g_CntrLine_AdviseSinkVtbl,

         sizeof(g_CntrLine_AdviseSinkVtbl)

   );

   g_CntrLine_AdviseSinkVtbl.QueryInterface= CntrLine_AdvSink_QueryInterface;

   g_CntrLine_AdviseSinkVtbl.AddRef        = CntrLine_AdvSink_AddRef;

   g_CntrLine_AdviseSinkVtbl.Release       = CntrLine_AdvSink_Release;

   g_CntrLine_AdviseSinkVtbl.OnDataChange  = CntrLine_AdvSink_OnDataChange;

   g_CntrLine_AdviseSinkVtbl.OnViewChange  = CntrLine_AdvSink_OnViewChange;

   g_CntrLine_AdviseSinkVtbl.OnRename      = CntrLine_AdvSink_OnRename;

   g_CntrLine_AdviseSinkVtbl.OnSave        = CntrLine_AdvSink_OnSave;

   g_CntrLine_AdviseSinkVtbl.OnClose       = CntrLine_AdvSink_OnClose;

   fStatus = OleStdCheckVtbl(

         &g_CntrLine_AdviseSinkVtbl,

         sizeof(g_CntrLine_AdviseSinkVtbl),

         OLESTR("IAdviseSink")

      );

   if (! fStatus) return FALSE;

#if defined( INPLACE_CNTR )

   // ContainerLine::IOleInPlaceSite interface method table

   OleStdInitVtbl(

         &g_CntrLine_OleInPlaceSiteVtbl,

         sizeof(g_CntrLine_OleInPlaceSiteVtbl)

   );

   g_CntrLine_OleInPlaceSiteVtbl.QueryInterface

                  = CntrLine_IPSite_QueryInterface;

   g_CntrLine_OleInPlaceSiteVtbl.AddRef

                  = CntrLine_IPSite_AddRef;

   g_CntrLine_OleInPlaceSiteVtbl.Release

                  = CntrLine_IPSite_Release;

   g_CntrLine_OleInPlaceSiteVtbl.GetWindow

                  = CntrLine_IPSite_GetWindow;

   g_CntrLine_OleInPlaceSiteVtbl.ContextSensitiveHelp

                  = CntrLine_IPSite_ContextSensitiveHelp;

   g_CntrLine_OleInPlaceSiteVtbl.CanInPlaceActivate

                  = CntrLine_IPSite_CanInPlaceActivate;

   g_CntrLine_OleInPlaceSiteVtbl.OnInPlaceActivate

                  = CntrLine_IPSite_OnInPlaceActivate;

   g_CntrLine_OleInPlaceSiteVtbl.OnUIActivate

                  = CntrLine_IPSite_OnUIActivate;

   g_CntrLine_OleInPlaceSiteVtbl.GetWindowContext

                  = CntrLine_IPSite_GetWindowContext;

   g_CntrLine_OleInPlaceSiteVtbl.Scroll

                  = CntrLine_IPSite_Scroll;

   g_CntrLine_OleInPlaceSiteVtbl.OnUIDeactivate

                  = CntrLine_IPSite_OnUIDeactivate;

   g_CntrLine_OleInPlaceSiteVtbl.OnInPlaceDeactivate

                  = CntrLine_IPSite_OnInPlaceDeactivate;

   g_CntrLine_OleInPlaceSiteVtbl.DiscardUndoState

                  = CntrLine_IPSite_DiscardUndoState;

   g_CntrLine_OleInPlaceSiteVtbl.DeactivateAndUndo

                  = CntrLine_IPSite_DeactivateAndUndo;

   g_CntrLine_OleInPlaceSiteVtbl.OnPosRectChange

                  = CntrLine_IPSite_OnPosRectChange;

   fStatus = OleStdCheckVtbl(

         &g_CntrLine_OleInPlaceSiteVtbl,

         sizeof(g_CntrLine_OleInPlaceSiteVtbl),

         OLESTR("IOleInPlaceSite")

      );

   if (! fStatus) return FALSE;

#endif  // INPLACE_CNTR

   return TRUE;

}

#endif  // OLE_CNTR


OLEDOC.C  (OUTLINE Sample)

/*************************************************************************

**

**    OLE 2 Server Sample Code

**

**    oledoc.c

**

**    This file contains general OleDoc methods and related support

**    functions. OleDoc implementation is used by both the Container

**    versions and the Server (Object) versions of the Outline Sample.

**

**    This file includes general support for the following:

**    1. show/hide doc window

**    2. QueryInterface, AddRef, Release

**    3. document locking (calls CoLockObjectExternal)

**    4. document shutdown (Close, Destroy)

**    5. clipboard support

**

**    OleDoc Object

**      exposed interfaces:

**          IUnknown

**          IPersistFile

**          IOleItemContainer

**          IDataObject

**

**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

**

*************************************************************************/

#include "outline.h"

OLEDBGDATA

extern LPOUTLINEAPP             g_lpApp;

extern IUnknownVtbl             g_OleDoc_UnknownVtbl;

extern IPersistFileVtbl         g_OleDoc_PersistFileVtbl;

extern IOleItemContainerVtbl    g_OleDoc_OleItemContainerVtbl;

extern IExternalConnectionVtbl  g_OleDoc_ExternalConnectionVtbl;

extern IDataObjectVtbl          g_OleDoc_DataObjectVtbl;

#if defined( USE_DRAGDROP )

extern IDropTargetVtbl          g_OleDoc_DropTargetVtbl;

extern IDropSourceVtbl          g_OleDoc_DropSourceVtbl;

#endif  // USE_DRAGDROP

#if defined( INPLACE_CNTR )

extern BOOL g_fInsideOutContainer;

#endif

/* OleDoc_Init

 * -----------

 *

 *  Initialize the fields of a new OleDoc object. The object is initially

 *  not associated with a file or an (Untitled) document. This function sets

 *  the docInitType to DOCTYPE_UNKNOWN. After calling this function the

 *  caller should call:

 *      1.) Doc_InitNewFile to set the OleDoc to (Untitled)

 *      2.) Doc_LoadFromFile to associate the OleDoc with a file.

 *  This function creates a new window for the document.

 *

 *  NOTE: the window is initially created with a NIL size. it must be

 *        sized and positioned by the caller. also the document is initially

 *        created invisible. the caller must call OutlineDoc_ShowWindow

 *        after sizing it to make the document window visible.

 */

BOOL OleDoc_Init(LPOLEDOC lpOleDoc, BOOL fDataTransferDoc)

{

   LPOLEAPP   lpOleApp = (LPOLEAPP)g_lpApp;

   LPLINELIST lpLL     = (LPLINELIST)&((LPOUTLINEDOC)lpOleDoc)->m_LineList;

   lpOleDoc->m_cRef                        = 0;

   lpOleDoc->m_dwStrongExtConn             = 0;

#if defined( _DEBUG )

   lpOleDoc->m_cCntrLock                   = 0;

#endif

   lpOleDoc->m_lpStg                       = NULL;

   lpOleDoc->m_lpLLStm                     = NULL;

   lpOleDoc->m_lpNTStm                     = NULL;

   lpOleDoc->m_dwRegROT                    = 0;

   lpOleDoc->m_lpFileMoniker               = NULL;

   lpOleDoc->m_fLinkSourceAvail            = FALSE;

   lpOleDoc->m_lpSrcDocOfCopy              = NULL;

   lpOleDoc->m_fObjIsClosing               = FALSE;

   lpOleDoc->m_fObjIsDestroying            = FALSE;

   lpOleDoc->m_fUpdateEditMenu             = FALSE;

#if defined( USE_DRAGDROP )

   lpOleDoc->m_dwTimeEnterScrollArea       = 0L;

   lpOleDoc->m_dwNextScrollTime            = 0L;

   lpOleDoc->m_dwLastScrollDir             = SCROLLDIR_NULL;

   lpOleDoc->m_fRegDragDrop                = FALSE;

   lpOleDoc->m_fLocalDrag                  = FALSE;

   lpOleDoc->m_fCanDropCopy                = FALSE;

   lpOleDoc->m_fCanDropLink                = FALSE;

   lpOleDoc->m_fLocalDrop                  = FALSE;

   lpOleDoc->m_fDragLeave                  = FALSE;

   lpOleDoc->m_fPendingDrag                = FALSE;

#endif

#if defined( INPLACE_SVR ) || defined( INPLACE_CNTR )

   lpOleDoc->m_fCSHelpMode                 = FALSE;    // Shift-F1 context

                                          // sensitive help mode

#endif

   INIT_INTERFACEIMPL(

         &lpOleDoc->m_Unknown,

         &g_OleDoc_UnknownVtbl,

         lpOleDoc

   );

   INIT_INTERFACEIMPL(

         &lpOleDoc->m_PersistFile,

         &g_OleDoc_PersistFileVtbl,

         lpOleDoc

   );

   INIT_INTERFACEIMPL(

         &lpOleDoc->m_OleItemContainer,

         &g_OleDoc_OleItemContainerVtbl,

         lpOleDoc

   );

   INIT_INTERFACEIMPL(

         &lpOleDoc->m_ExternalConnection,

         &g_OleDoc_ExternalConnectionVtbl,

         lpOleDoc

   );

   INIT_INTERFACEIMPL(

         &lpOleDoc->m_DataObject,

         &g_OleDoc_DataObjectVtbl,

         lpOleDoc

   );

#if defined( USE_DRAGDROP )

   INIT_INTERFACEIMPL(

         &lpOleDoc->m_DropSource,

         &g_OleDoc_DropSourceVtbl,

         lpOleDoc

   );

   INIT_INTERFACEIMPL(

         &lpOleDoc->m_DropTarget,

         &g_OleDoc_DropTargetVtbl,

         lpOleDoc

   );

#endif  // USE_DRAGDROP

   /*

   ** OLE2NOTE: each user level document addref's the app object in

   **    order to guarentee that the app does not shut down while the

   **    doc is still open.

   */

   // OLE2NOTE: data transfer documents should not hold the app alive

   if (! fDataTransferDoc)

      OleApp_DocLockApp(lpOleApp);

#if defined( OLE_SERVER )

   /* OLE2NOTE: perform initialization specific for an OLE server */

   if (! ServerDoc_Init((LPSERVERDOC)lpOleDoc, fDataTransferDoc))

      return FALSE;

#endif

#if defined( OLE_CNTR )

   /* OLE2NOTE: perform initialization specific for an OLE container */

   if (! ContainerDoc_Init((LPCONTAINERDOC)lpOleDoc, fDataTransferDoc))

      return FALSE;

#endif

   return TRUE;

}

/* OleDoc_InitNewFile

 * ------------------

 *

 *  Initialize the document to be a new (Untitled) document.

 *  This function sets the docInitType to DOCTYPE_NEW.

 *

 *  OLE2NOTE: if this is a visible user document then generate a unique

 *  untitled name that we can use to register in the RunningObjectTable.

 *  We need a unique name so that clients can link to data in this document

 *  even when the document is in the un-saved (untitled) state. it would be

 *  ambiguous to register two documents titled "Outline1" in the ROT. we

 *  thus generate the lowest numbered document that is not already

 *  registered in the ROT.

 */

BOOL OleDoc_InitNewFile(LPOLEDOC lpOleDoc)

{

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc;

   static UINT uUnique = 1;

   OleDbgAssert(lpOutlineDoc->m_docInitType == DOCTYPE_UNKNOWN);

#if defined( OLE_CNTR )

   {

      LPCONTAINERDOC lpContainerDoc = (LPCONTAINERDOC)lpOleDoc;

#if defined( _DEBUG )

      OleDbgAssertSz(lpOleDoc->m_lpStg == NULL,

            "Setting to untitled with current file open"

      );

#endif

      /* Create a temp, (delete-on-release) file base storage

      **  for the untitled document.

      */

      lpOleDoc->m_lpStg = OleStdCreateRootStorage(

            NULL,

            STGM_SHARE_EXCLUSIVE

      );

      if (! lpOleDoc->m_lpStg) return FALSE;

   }

#endif

   lpOutlineDoc->m_docInitType = DOCTYPE_NEW;

   if (! lpOutlineDoc->m_fDataTransferDoc) {

      /* OLE2NOTE: choose a unique name for a Moniker so that

      **    potential clients can link to our new, untitled document.

      **    if links are established (and currently are connected),

      **    then they will be notified that we have been renamed when

      **    this document is saved to a file.

      */

      lpOleDoc->m_fLinkSourceAvail = TRUE;

      // REVIEW: should load UNTITLED string from string resource

      OleStdCreateTempFileMoniker(

            UNTITLED,

            (UINT FAR*)&uUnique,

            lpOutlineDoc->m_szFileName,

            &lpOleDoc->m_lpFileMoniker

      );

      OLEDBG_BEGIN3("OleStdRegisterAsRunning called\r\n")

      OleStdRegisterAsRunning(

            (LPUNKNOWN)&lpOleDoc->m_PersistFile,

            (LPMONIKER)lpOleDoc->m_lpFileMoniker,

            &lpOleDoc->m_dwRegROT

      );

      OLEDBG_END3

      lpOutlineDoc->m_lpszDocTitle = lpOutlineDoc->m_szFileName;

      OutlineDoc_SetTitle(lpOutlineDoc, FALSE /*fMakeUpperCase*/);

   } else {

      OLESTRCPY(lpOutlineDoc->m_szFileName, UNTITLED);

      lpOutlineDoc->m_lpszDocTitle = lpOutlineDoc->m_szFileName;

   }

   return TRUE;

}

/* OleDoc_ShowWindow

 * -----------------

 *

 *      Show the window of the document to the user.

 *      make sure app window is visible and bring the document to the top.

 *      if the document is a file-based document or a new untitled

 *      document, give the user the control over the life-time of the doc.

 */

void OleDoc_ShowWindow(LPOLEDOC lpOleDoc)

{

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp;

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc;

   LPLINELIST lpLL     = (LPLINELIST)&((LPOUTLINEDOC)lpOleDoc)->m_LineList;

#if defined( OLE_SERVER )

   LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOleDoc;

#endif // OLE_SERVER

   OLEDBG_BEGIN3("OleDoc_ShowWindow\r\n")

   /* OLE2NOTE: while the document is visible, we do NOT want it to be

   **    prematurely destroyed when a linking client disconnects. thus

   **    we must inform OLE to hold an external lock on our document.

   **    this arranges that OLE holds at least 1 reference to our

   **    document that will NOT be released until we release this

   **    external lock. later, when the document window is hidden, we

   **    will release this external lock.

   */

   if (! IsWindowVisible(lpOutlineDoc->m_hWndDoc))

      OleDoc_Lock(lpOleDoc, TRUE /* fLock */, 0 /* not applicable */);

#if defined( USE_DRAGDROP )

   /* OLE2NOTE: since our window is now being made visible, we will

   **    register our window as a potential drop target. when the

   **    window is hidden there is no reason to be registered as a

   **    drop target.

   */

   if (! lpOleDoc->m_fRegDragDrop) {

      OLEDBG_BEGIN2("RegisterDragDrop called\r\n")

      RegisterDragDrop(

            LineList_GetWindow(lpLL),

            (LPDROPTARGET)&lpOleDoc->m_DropTarget

      );

      OLEDBG_END2

      lpOleDoc->m_fRegDragDrop = TRUE;

   }

#endif  // USE_DRAGDROP

#if defined( USE_FRAMETOOLS )

   {

      /* OLE2NOTE: we need to enable our frame level tools

      */

      FrameTools_Enable(lpOutlineDoc->m_lpFrameTools, TRUE);

   }

#endif // USE_FRAMETOOLS

#if defined( OLE_SERVER )

   if (lpOutlineDoc->m_docInitType == DOCTYPE_EMBEDDED &&

         lpServerDoc->m_lpOleClientSite != NULL) {

      /* OLE2NOTE: we must also ask our container to show itself if

      **    it is not already visible and to scroll us into view. we

      **    must make sure to call this BEFORE showing our server's

      **    window and taking focus. we do not want our container's

      **    window to end up on top.

      */

      OLEDBG_BEGIN2("IOleClientSite::ShowObject called\r\n");

      lpServerDoc->m_lpOleClientSite->lpVtbl->ShowObject(

            lpServerDoc->m_lpOleClientSite

      );

      OLEDBG_END2

      /* OLE2NOTE: if we are an embedded object and we are not

      **    in-place active in our containers window, we must inform our

      **    embedding container that our window is opening.

      **    the container must now hatch our object.

      */

#if defined( INPLACE_SVR )

      if (! lpServerDoc->m_fInPlaceActive)

#endif

      {

         OLEDBG_BEGIN2("IOleClientSite::OnShowWindow(TRUE) called\r\n");

         lpServerDoc->m_lpOleClientSite->lpVtbl->OnShowWindow(

               lpServerDoc->m_lpOleClientSite,

               TRUE

         );

         OLEDBG_END2

      }

      /* OLE2NOTE: the life-time of our document is controlled by our

      **    client and NOT by the user. we are not an independent

      **    file-level object. we simply want to show our window here.

      **

      **    if we are not in-place active (ie. we are opening

      **    our own window), we must make sure our main app window is

      **    visible. we do not, however, want to give the user

      **    control of the App window; we do not want OleApp_ShowWindow

      **    to call OleApp_Lock on behalf of the user.

      */

      if (! IsWindowVisible(lpOutlineApp->m_hWndApp) ||

            IsIconic(lpOutlineApp->m_hWndApp)) {

#if defined( INPLACE_SVR )

         if (! ((LPSERVERDOC)lpOleDoc)->m_fInPlaceActive)

#endif

            OleApp_ShowWindow(lpOleApp, FALSE /* fGiveUserCtrl */);

         SetFocus(lpOutlineDoc->m_hWndDoc);

      }

   } else

#endif  // OLE_SERVER

   {    // DOCTYPE_NEW || DOCTYPE_FROMFILE

      // we must make sure our app window is visible

      OleApp_ShowWindow(lpOleApp, TRUE /* fGiveUserCtrl */);

   }

   // make document window visible and make sure it is not minimized

   ShowWindow(lpOutlineDoc->m_hWndDoc, SW_SHOWNORMAL);

   SetForegroundWindow(lpOutlineDoc->m_hWndDoc);

   OLEDBG_END3

}

/* OleDoc_HideWindow

 * -----------------

 *

 *      Hide the window of the document from the user.

 *      take away the control of the document by the user.

 */

void OleDoc_HideWindow(LPOLEDOC lpOleDoc, BOOL fShutdown)

{

   LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp;

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc;

   LPLINELIST lpLL     = (LPLINELIST)&((LPOUTLINEDOC)lpOleDoc)->m_LineList;

   if (! IsWindowVisible(lpOutlineDoc->m_hWndDoc))

      return;     // already visible

   OLEDBG_BEGIN3("OleDoc_HideWindow\r\n")

#if defined( USE_DRAGDROP )

   // The document's window is being hidden, revoke it as a DropTarget

   if (lpOleDoc->m_fRegDragDrop) {

      OLEDBG_BEGIN2("RevokeDragDrop called\r\n");

      RevokeDragDrop(LineList_GetWindow(lpLL));

      OLEDBG_END2

      lpOleDoc->m_fRegDragDrop = FALSE ;

   }

#endif  // USE_DRAGDROP

   /* OLE2NOTE: the document is now being hidden, so we must release

   **    the external lock made when the document was made visible.

   **    if this is a shutdown situation (fShutdown==TRUE), then OLE

   **    is instructed to release our document. if this is that last

   **    external lock on our document, thus enabling our document to

   **    complete its shutdown operation. If This is not a shutdown

   **    situation (eg. in-place server hiding its window when

   **    UIDeactivating or IOleObject::DoVerb(OLEVERB_HIDE) is called),

   **    then OLE is told to NOT immediately release the document.

   **    this leaves the document in an unstable state where the next

   **    Lock/Unlock sequence will shut the document down (eg. a

   **    linking client connecting and disconnecting).

   */

   if (IsWindowVisible(lpOutlineDoc->m_hWndDoc))

      OleDoc_Lock(lpOleDoc, FALSE /* fLock */, fShutdown);

   ShowWindow(((LPOUTLINEDOC)lpOleDoc)->m_hWndDoc, SW_HIDE);

#if defined( OLE_SERVER )

   {

      LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOleDoc;

      /* OLE2NOTE: if we are an embedded object and we are not

      **    in-place active, we must inform our

      **    embedding container that our window is hiding (closing

      **    from the user's perspective). the container must now

      **    un-hatch our object.

      */

      if (lpServerDoc->m_lpOleClientSite != NULL

#if defined( INPLACE_SVR )

         && !lpServerDoc->m_fInPlaceVisible

#endif

      ) {

         OLEDBG_BEGIN2("IOleClientSite::OnShowWindow(FALSE) called\r\n");

         lpServerDoc->m_lpOleClientSite->lpVtbl->OnShowWindow(

               lpServerDoc->m_lpOleClientSite,

               FALSE

         );

         OLEDBG_END2

      }

   }

#endif

   /* OLE2NOTE: if there are no more documents visible to the user.

   **    and the app itself is not under user control, then

   **    it has no reason to stay visible. we thus should hide the

   **    app. we can not directly destroy the app, because it may be

   **    validly being used programatically by another client

   **    application and should remain running. it should simply be

   **    hidded from the user.

   */

   OleApp_HideIfNoReasonToStayVisible(lpOleApp);

   OLEDBG_END3

}

/* OleDoc_Lock

** -----------

**    Lock/Unlock the Doc object. if the last lock is unlocked and

**    fLastUnlockReleases == TRUE, then the Doc object will shut down

**    (ie. it will recieve its final release and its refcnt will go to 0).

*/

HRESULT OleDoc_Lock(LPOLEDOC lpOleDoc, BOOL fLock, BOOL fLastUnlockReleases)

{

   HRESULT hrErr;

#if defined( _DEBUG )

   if (fLock) {

      OLEDBG_BEGIN2("CoLockObjectExternal(lpDoc,TRUE) called\r\n")

   } else {

      if (fLastUnlockReleases)

         OLEDBG_BEGIN2("CoLockObjectExternal(lpDoc,FALSE,TRUE) called\r\n")

      else

         OLEDBG_BEGIN2("CoLockObjectExternal(lpDoc,FALSE,FALSE) called\r\n")

   }

#endif  // _DEBUG

   hrErr = CoLockObjectExternal(

         (LPUNKNOWN)&lpOleDoc->m_Unknown, fLock, fLastUnlockReleases);

   OLEDBG_END2

   return hrErr;

}

/* OleDoc_AddRef

** -------------

**

**  increment the ref count of the document object.

**

**    Returns the new ref count on the object

*/

ULONG OleDoc_AddRef(LPOLEDOC lpOleDoc)

{

   ++lpOleDoc->m_cRef;

#if defined( _DEBUG )

   OleDbgOutRefCnt4(

         "OleDoc_AddRef: cRef++\r\n",

         lpOleDoc,

         lpOleDoc->m_cRef

   );

#endif

   return lpOleDoc->m_cRef;

}

/* OleDoc_Release

** --------------

**

**  decrement the ref count of the document object.

**    if the ref count goes to 0, then the document is destroyed.

**

**    Returns the remaining ref count on the object

*/

ULONG OleDoc_Release (LPOLEDOC lpOleDoc)

{

   ULONG cRef;

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp;

   /*********************************************************************

   ** OLE2NOTE: when the obj refcnt == 0, then destroy the object.     **

   **     otherwise the object is still in use.                        **

   *********************************************************************/

   cRef = --lpOleDoc->m_cRef;

#if defined( _DEBUG )

   OleDbgAssertSz (lpOleDoc->m_cRef >= 0, "Release called with cRef == 0");

   OleDbgOutRefCnt4(

         "OleDoc_Release: cRef--\r\n", lpOleDoc, cRef);

#endif

   if (cRef == 0)

      OutlineDoc_Destroy((LPOUTLINEDOC)lpOleDoc);

   return cRef;

}

/* OleDoc_QueryInterface

** ---------------------

**

** Retrieve a pointer to an interface on the document object.

**

**    OLE2NOTE: this function will AddRef the ref cnt of the object.

**

**    Returns S_OK if interface is successfully retrieved.

**            E_NOINTERFACE if the interface is not supported

*/

HRESULT OleDoc_QueryInterface(

      LPOLEDOC          lpOleDoc,

      REFIID            riid,

      LPVOID FAR*       lplpvObj

)

{

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc;

   SCODE sc = E_NOINTERFACE;

   /* OLE2NOTE: we must make sure to set all out ptr parameters to NULL. */

   *lplpvObj = NULL;

   if (IsEqualIID(riid, &IID_IUnknown)) {

      OleDbgOut4("OleDoc_QueryInterface: IUnknown* RETURNED\r\n");

      *lplpvObj = (LPVOID) &lpOleDoc->m_Unknown;

      OleDoc_AddRef(lpOleDoc);

      sc = S_OK;

   }

   else if(lpOutlineDoc->m_fDataTransferDoc

         && IsEqualIID(riid, &IID_IDataObject)) {

      OleDbgOut4("OleDoc_QueryInterface: IDataObject* RETURNED\r\n");

      *lplpvObj = (LPVOID) &lpOleDoc->m_DataObject;

      OleDoc_AddRef(lpOleDoc);

      sc = S_OK;

   }

   /* OLE2NOTE: if this document is a DataTransferDocument used to

   **    support a clipboard or drag/drop operation, then it should

   **    only expose IUnknown, IDataObject, and IDropSource

   **    interfaces. if the document is a normal user document, then

   **    we will also continue to consider our other interfaces.

   */

   if (lpOutlineDoc->m_fDataTransferDoc)

      goto done;

   if(IsEqualIID(riid,&IID_IPersist) || IsEqualIID(riid,&IID_IPersistFile)) {

      OleDbgOut4("OleDoc_QueryInterface: IPersistFile* RETURNED\r\n");

      *lplpvObj = (LPVOID) &lpOleDoc->m_PersistFile;

      OleDoc_AddRef(lpOleDoc);

      sc = S_OK;

   }

   else if(IsEqualIID(riid, &IID_IOleItemContainer) ||

         IsEqualIID(riid, &IID_IOleContainer) ||

         IsEqualIID(riid, &IID_IParseDisplayName) ) {

      OleDbgOut4("OleDoc_QueryInterface: IOleItemContainer* RETURNED\r\n");

      *lplpvObj = (LPVOID) &lpOleDoc->m_OleItemContainer;

      OleDoc_AddRef(lpOleDoc);

      sc = S_OK;

   }

   else if(IsEqualIID(riid, &IID_IExternalConnection)) {

      OleDbgOut4("OleDoc_QueryInterface: IExternalConnection* RETURNED\r\n");

      *lplpvObj = (LPVOID) &lpOleDoc->m_ExternalConnection;

      OleDoc_AddRef(lpOleDoc);

      sc = S_OK;

   }

#if defined( USE_DRAGDROP )

   else if(IsEqualIID(riid, &IID_IDropTarget)) {

      OleDbgOut4("OleDoc_QueryInterface: IDropTarget* RETURNED\r\n");

      *lplpvObj = (LPVOID) &lpOleDoc->m_DropTarget;

      OleDoc_AddRef(lpOleDoc);

      sc = S_OK;

   }

   else if(IsEqualIID(riid, &IID_IDropSource)) {

      OleDbgOut4("OleDoc_QueryInterface: IDropSource* RETURNED\r\n");

      *lplpvObj = (LPVOID) &lpOleDoc->m_DropSource;

      OleDoc_AddRef(lpOleDoc);

      sc = S_OK;

   }

#endif

#if defined( OLE_CNTR )

   else if (IsEqualIID(riid, &IID_IOleUILinkContainer)) {

      OleDbgOut4("OleDoc_QueryInterface: IOleUILinkContainer* RETURNED\r\n");

      *lplpvObj=(LPVOID)&((LPCONTAINERDOC)lpOleDoc)->m_OleUILinkContainer;

      OleDoc_AddRef(lpOleDoc);

      sc = S_OK;

   }

#endif

#if defined( OLE_SERVER )

   /* OLE2NOTE: if OLE server version, than also offer the server

   **    specific interfaces: IOleObject and IPersistStorage.

   */

   else if (IsEqualIID(riid, &IID_IOleObject)) {

      OleDbgOut4("OleDoc_QueryInterface: IOleObject* RETURNED\r\n");

      *lplpvObj = (LPVOID) &((LPSERVERDOC)lpOleDoc)->m_OleObject;

      OleDoc_AddRef(lpOleDoc);

      sc = S_OK;

   }

   else if(IsEqualIID(riid, &IID_IPersistStorage)) {

      OleDbgOut4("OleDoc_QueryInterface: IPersistStorage* RETURNED\r\n");

      *lplpvObj = (LPVOID) &((LPSERVERDOC)lpOleDoc)->m_PersistStorage;

      OleDoc_AddRef(lpOleDoc);

      sc = S_OK;

   }

   else if(IsEqualIID(riid, &IID_IDataObject)) {

      OleDbgOut4("OleDoc_QueryInterface: IDataObject* RETURNED\r\n");

      *lplpvObj = (LPVOID) &lpOleDoc->m_DataObject;

      OleDoc_AddRef(lpOleDoc);

      sc = S_OK;

   }

#if defined( SVR_TREATAS )

   else if(IsEqualIID(riid, &IID_IStdMarshalInfo)) {

      OleDbgOut4("OleDoc_QueryInterface: IStdMarshalInfo* RETURNED\r\n");

      *lplpvObj = (LPVOID) &((LPSERVERDOC)lpOleDoc)->m_StdMarshalInfo;

      OleDoc_AddRef(lpOleDoc);

      sc = S_OK;

   }

#endif  // SVR_TREATAS

#if defined( INPLACE_SVR )

   else if (IsEqualIID(riid, &IID_IOleWindow) ||

          IsEqualIID(riid, &IID_IOleInPlaceObject)) {

      OleDbgOut4("OleDoc_QueryInterface: IOleInPlaceObject* RETURNED\r\n");

      *lplpvObj = (LPVOID) &((LPSERVERDOC)lpOleDoc)->m_OleInPlaceObject;

      OleDoc_AddRef(lpOleDoc);

      sc = S_OK;

   }

#endif // INPLACE_SVR

#endif // OLE_SERVER

done:

   OleDbgQueryInterfaceMethod(*lplpvObj);

   return ResultFromScode(sc);

}

/* OleDoc_Close

 * ------------

 *

 *  Close the document.

 *      This functions performs the actions that are in common to all

 *      document types which derive from OleDoc (eg. ContainerDoc and

 *      ServerDoc) which are required to close a document.

 *

 *  Returns:

 *      FALSE -- user canceled the closing of the doc.

 *      TRUE -- the doc was successfully closed

 */

BOOL OleDoc_Close(LPOLEDOC lpOleDoc, DWORD dwSaveOption)

{

   LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp;

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   LPOLEDOC lpClipboardDoc;

   LPLINELIST lpLL     = (LPLINELIST)&((LPOUTLINEDOC)lpOleDoc)->m_LineList;

   BOOL fAbortIfSaveCanceled = (dwSaveOption == OLECLOSE_PROMPTSAVE);

   if (! lpOleDoc)

      return TRUE;    // active doc's are already destroyed

   if (lpOleDoc->m_fObjIsClosing)

      return TRUE;    // Closing is already in progress

   OLEDBG_BEGIN3("OleDoc_Close\r\n")

   if (! OutlineDoc_CheckSaveChanges((LPOUTLINEDOC)lpOleDoc,&dwSaveOption)

         && fAbortIfSaveCanceled) {

      OLEDBG_END3

      return FALSE;           // cancel closing the doc

   }

   lpOleDoc->m_fObjIsClosing = TRUE;   // guard against recursive call

   /* OLE2NOTE: in order to have a stable app and doc during the

   **    process of closing, we intially AddRef the App and Doc ref

   **    cnts and later Release them. These initial AddRefs are

   **    artificial; they simply guarantee that these objects do not

   **    get destroyed until the end of this routine.

   */

   OleApp_AddRef(lpOleApp);

   OleDoc_AddRef(lpOleDoc);

#if defined( OLE_CNTR )

   {

      LPCONTAINERDOC lpContainerDoc = (LPCONTAINERDOC)lpOleDoc;

      /* OLE2NOTE: force all OLE objects to close. this forces all

      **    OLE object to transition from running to loaded. we can

      **    NOT exit if any embeddings are still running.

      **    if an object can't be closed and this close operation was

      **    started by the user, then we will abort closing our document.

      */

      if (! ContainerDoc_CloseAllOleObjects(lpContainerDoc, OLECLOSE_NOSAVE)

            && fAbortIfSaveCanceled) {

         OleDoc_Release(lpOleDoc);       // release artificial AddRef above

         OleApp_Release(lpOleApp);       // release artificial AddRef above

         lpOleDoc->m_fObjIsClosing = FALSE; // clear recursion guard

         OLEDBG_END3

         return FALSE;   // Closing is aborted

      }

   }

#endif

#if defined( INPLACE_SVR )

   /* OLE2NOTE: if the server is currently in-place active we must

   **    deactivate it now before closing

   */

   ServerDoc_DoInPlaceDeactivate((LPSERVERDOC)lpOleDoc);

#endif

   /* OLE2NOTE: if this document is the source of data for the

   **    clipboard, then flush the clipboard. it is important to flush

   **    the clipboard BEFORE calling sending any notifications to

   **    clients (eg. IOleClientSite::OnShowWindow(FALSE)) which could

   **    give them a chance to run and try to get our clipboard data

   **    object that we want to destroy. (eg. our app tries to

   **    update the paste button of the toolbar when

   **    WM_ACTIVATEAPP is received.)

   */

   lpClipboardDoc = (LPOLEDOC)lpOutlineApp->m_lpClipboardDoc;

   if (lpClipboardDoc &&

      lpClipboardDoc->m_lpSrcDocOfCopy == lpOleDoc) {

      OleApp_FlushClipboard(lpOleApp);

   }

   /* OLE2NOTE: Revoke the object from the Running Object Table. it is

   **    best if the object is revoke prior to calling

   **    COLockObjectExternal(FALSE,TRUE) which is called when the

   **    document window is hidden from the user.

   */

   OLEDBG_BEGIN3("OleStdRevokeAsRunning called\r\n")

   OleStdRevokeAsRunning(&lpOleDoc->m_dwRegROT);

   OLEDBG_END3

   /* OLE2NOTE: if the user is in control of the document, the user

   **    accounts for one refcnt on the document. Closing the

   **    document is achieved by releasing the object on behalf of

   **    the user. if the document is not referenced by any other

   **    clients, then the document will also be destroyed. if it

   **    is referenced by other clients, then it will remain until

   **    they release it. it is important to hide the window and call

   **    IOleClientSite::OnShowWindow(FALSE) BEFORE sending OnClose

   **    notification.

   */

   OleDoc_HideWindow(lpOleDoc, TRUE);

#if defined( OLE_SERVER )

   {

      LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOleDoc;

      LPSERVERNAMETABLE lpServerNameTable =

         (LPSERVERNAMETABLE)((LPOUTLINEDOC)lpOleDoc)->m_lpNameTable;

      /* OLE2NOTE: force all pseudo objects to close. this informs all

      **    linking clients of pseudo objects to release their PseudoObj.

      */

      ServerNameTable_CloseAllPseudoObjs(lpServerNameTable);

      /* OLE2NOTE: send last OnDataChange notification to clients

      **    that have registered for data notifications when object

      **    stops running (ADVF_DATAONSTOP), if the data in our

      **    object has ever changed. it is best to only send this

      **    notification if necessary.

      */

      if (lpServerDoc->m_lpDataAdviseHldr) {

         if (lpServerDoc->m_fSendDataOnStop) {

            ServerDoc_SendAdvise(

                  (LPSERVERDOC)lpOleDoc,

                  OLE_ONDATACHANGE,

                  NULL,   /* lpmkDoc -- not relevant here */

                  ADVF_DATAONSTOP

            );

         }

         /* OLE2NOTE: we just sent the last data notification that we

         **    need to send; release our DataAdviseHolder. we SHOULD be

         **    the only one using it.

         */

         OleStdVerifyRelease(

               (LPUNKNOWN)lpServerDoc->m_lpDataAdviseHldr,

               OLESTR("DataAdviseHldr not released properly")

         );

         lpServerDoc->m_lpDataAdviseHldr = NULL;

      }

      // OLE2NOTE: inform all of our linking clients that we are closing.

      if (lpServerDoc->m_lpOleAdviseHldr) {

         ServerDoc_SendAdvise(

               (LPSERVERDOC)lpOleDoc,

               OLE_ONCLOSE,

               NULL,   /* lpmkDoc -- not relevant here */

               0       /* advf -- not relevant here */

         );

         /* OLE2NOTE: OnClose is the last notification that we need to

         **    send; release our OleAdviseHolder. we SHOULD be the only

         **    one using it. this will make our destructor realize that

         **    OnClose notification has already been sent.

         */

         OleStdVerifyRelease(

               (LPUNKNOWN)lpServerDoc->m_lpOleAdviseHldr,

               OLESTR("OleAdviseHldr not released properly")

         );

         lpServerDoc->m_lpOleAdviseHldr = NULL;

      }

      /* release our Container's ClientSite. */

      if(lpServerDoc->m_lpOleClientSite) {

         OleStdRelease((LPUNKNOWN)lpServerDoc->m_lpOleClientSite);

         lpServerDoc->m_lpOleClientSite = NULL;

      }

   }

#endif

   if (lpOleDoc->m_lpLLStm) {

      /* release our LineList stream. */

      OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpLLStm);

      lpOleDoc->m_lpLLStm = NULL;

   }

   if (lpOleDoc->m_lpNTStm) {

      /* release our NameTable stream. */

      OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpNTStm);

      lpOleDoc->m_lpNTStm = NULL;

   }

   if (lpOleDoc->m_lpStg) {

      /* release our doc storage. */

      OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpStg);

      lpOleDoc->m_lpStg = NULL;

   }

   if (lpOleDoc->m_lpFileMoniker) {

      OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpFileMoniker);

      lpOleDoc->m_lpFileMoniker = NULL;

   }

   /* OLE2NOTE: this call forces all external connections to our

   **    object to close down and therefore guarantees that we receive

   **    all releases associated with those external connections.

   */

   OLEDBG_BEGIN2("CoDisconnectObject(lpDoc) called\r\n")

   CoDisconnectObject((LPUNKNOWN)&lpOleDoc->m_Unknown, 0);

   OLEDBG_END2

   OleDoc_Release(lpOleDoc);       // release artificial AddRef above

   OleApp_Release(lpOleApp);       // release artificial AddRef above

   OLEDBG_END3

   return TRUE;

}

/* OleDoc_Destroy

 * --------------

 *

 *  Free all OLE related resources that had been allocated for a document.

 */

void OleDoc_Destroy(LPOLEDOC lpOleDoc)

{

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpOleDoc;

   if (lpOleDoc->m_fObjIsDestroying)

      return;     // Doc destruction is already in progress

   lpOleDoc->m_fObjIsDestroying = TRUE;    // guard against recursive call

#if defined( OLE_SERVER )

   /* OLE2NOTE: it is ALWAYS necessary to make sure that the work we

   **    do in our OleDoc_Close function is performed before we

   **    destroy our document object. this includes revoking from the

   **    Running Object Table (ROT), sending OnClose notification,

   **    revoking from Drag/Drop, closing all pseudo objects, etc.

   **    There are some tricky scenarios involving linking and

   **    when IOleObject::Close is called versus when we get our

   **    final release causing us to call our OleDoc_Destroy

   **    (destructor) function.

   **

   **    SCENARIO 1 -- closing from server (File.Exit or File.Close)

   **                  OleDoc_Close function is called directly by the

   **                  server in response to the menu command

   **                  (WM_COMMAND processing).

   **

   **    SCENARIO 2 -- closed by embedding container

   **                  our embedding container calls IOleObject::Close

   **                  directly.

   **

   **    SCENARIO 3 -- silent-update final release

   **                  THIS IS THE TRICKY ONE!!!

   **                  in the case that our object is launched because

   **                  a linking client calls IOleObject::Update on

   **                  its link, then our object will be run

   **                  invisibly, typically GetData will be called,

   **                  and then the connection from the linking client

   **                  will be released. the release of this last

   **                  linking connection should cause our object to

   **                  shut down.

   **                  there are 2 strategies to deal with this scenario:

   **

   **                  STRATEGY 1 -- implement IExternalConnection.

   **                  IExternalConnection::AddConnection will be

   **                  called (by the StubManager) every time that an

   **                  external (linking) connection is created or

   **                  CoLockObjectExternal is called. the object

   **                  should maintain a count of strong connections

   **                  (m_dwStrongExtConn). IExternalConnection::

   **                  ReleaseConnection will be called when these

   **                  connections are released. when the

   **                  m_dwStrongExtConn transistions to 0, the object

   **                  should call its IOleObject::Close function.

   **                  this assumes that CoLockObjectExternal is used

   **                  to manage locks by the object itself (eg. when

   **                  the object is visible to the user--fUserCtrl,

   **                  and when PseudoObjects are created, etc.)

   **                  this is the strategy implemented by SVROUTL.

   **

   **                  STRATEGY 2 -- guard both the destructor

   **                  function and the Close function. if the

   **                  destructor is called directly without Close

   **                  first being called, then call Close before

   **                  proceeding with the destruction code.

   **                  previously SVROUTL was organized in this

   **                  manner. that old code is conditionaly compiled

   **                  away with "#ifdef OBSOLETE" below. this

   **                  method has the disadvantage that external

   **                  remoting is no longer possible by the time the

   **                  Close is called making it impossible for

   **                  the object to ask its container to save the

   **                  object if the object is dirty. this can result

   **                  in data loss. thus STRATEGY 1 is safer.

   **                  consider the scenario where an in-place

   **                  container UIDeactivates an object but does NOT

   **                  keep the object locked running (this is

   **                  required--see CntrLine_IPSite_OnInPlaceActivate

   **                  in cntrline.c), then, if a linking client binds

   **                  and unbinds from the object, the object will be

   **                  destroyed and will NOT have an opportunity to

   **                  be saved. by implementing IExternalConnection,

   **                  a server can insulate itself from a poorly

   **                  written container.

   */

#if defined( _DEBUG )

   OleDbgAssertSz(

         (lpOutlineDoc->m_fDataTransferDoc || lpOleDoc->m_fObjIsClosing),

         "Destroy called without Close being called\r\n"

   );

#endif  // _DEBUG

#if defined( OBSOLETE )

   /* OLE2NOTE: if the document destructor is called directly because

   **    the object's refcnt went to 0 (ie. without OleDoc_Close first

   **    being called), then we need to make sure that the document is

   **    properly closed before destroying the object. this scenario

   **    could arise during a silent-update of a link. calling

   **    OleDoc_Close here guarantees that the clipboard will be

   **    properly flushed, the doc's moniker will be properly revoked,

   **    the document will be saved if necessary, etc.

   */

   if (!lpOutlineDoc->m_fDataTransferDoc && !lpOleDoc->m_fObjIsClosing)

      OleDoc_Close(lpOleDoc, OLECLOSE_NOSAVE);

#endif

   {

      LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOleDoc;

      /* OLE2NOTE: perform processing specific for an OLE server */

#if defined( SVR_TREATAS )

      if (lpServerDoc->m_lpszTreatAsType) {

         OleStdFreeString(lpServerDoc->m_lpszTreatAsType, NULL);

         lpServerDoc->m_lpszTreatAsType = NULL;

      }

#endif  // SVR_TREATAS

#if defined( INPLACE_SVR )

      if (IsWindow(lpServerDoc->m_hWndHatch))

         DestroyWindow(lpServerDoc->m_hWndHatch);

#endif  // INPLACE_SVR

   }

#endif  // OLE_SERVER

   if (lpOleDoc->m_lpLLStm) {

      /* release our LineList stream. */

      OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpLLStm);

      lpOleDoc->m_lpLLStm = NULL;

   }

   if (lpOleDoc->m_lpNTStm) {

      /* release our NameTable stream. */

      OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpNTStm);

      lpOleDoc->m_lpNTStm = NULL;

   }

   if (lpOleDoc->m_lpStg) {

      /* release our doc storage. */

      OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpStg);

      lpOleDoc->m_lpStg = NULL;

   }

   if (lpOleDoc->m_lpFileMoniker) {

      OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpFileMoniker);

      lpOleDoc->m_lpFileMoniker = NULL;

   }

   /*****************************************************************

   ** OLE2NOTE: each document addref's the app object in order to  **

   **    guarentee that the app does not shut down while the doc   **

   **    is still open. since this doc is now destroyed, we will   **

   **    release this refcnt now. if there are now more open       **

   **    documents AND the app is not under the control of the     **

   **    user (ie. launched by OLE) then the app will revoke its   **

   **    ClassFactory. if there are no more references to the      **

   **    ClassFactory after it is revoked, then the app will shut  **

   **    down. this whole procedure is triggered by calling        **

   **    OutlineApp_DocUnlockApp.                                  **

   *****************************************************************/

   OutlineApp_DocUnlockApp(lpOutlineApp, lpOutlineDoc);

}

/* OleDoc_SetUpdateEditMenuFlag

 * ----------------------------

 *

 *  Purpose:

 *      Set/clear the UpdateEditMenuFlag in OleDoc.

 *

 *  Parameters:

 *      fUpdate     new value of the flag

 *

 *  Returns:

 */

void OleDoc_SetUpdateEditMenuFlag(LPOLEDOC lpOleDoc, BOOL fUpdate)

{

   if (!lpOleDoc)

      return;

   lpOleDoc->m_fUpdateEditMenu = fUpdate;

}

/* OleDoc_GetUpdateEditMenuFlag

 * ----------------------------

 *

 *  Purpose:

 *      Get the value of the UpdateEditMenuFlag in OleDoc

 *

 *  Parameters:

 *

 *  Returns:

 *      value of the flag

 */

BOOL OleDoc_GetUpdateEditMenuFlag(LPOLEDOC lpOleDoc)

{

   if (!lpOleDoc)

      return FALSE;

   return lpOleDoc->m_fUpdateEditMenu;

}

/*************************************************************************

** OleDoc::IUnknown interface implementation

*************************************************************************/

STDMETHODIMP OleDoc_Unk_QueryInterface(

      LPUNKNOWN           lpThis,

      REFIID              riid,

      LPVOID FAR*         lplpvObj

)

{

   LPOLEDOC lpOleDoc = ((struct CDocUnknownImpl FAR*)lpThis)->lpOleDoc;

   return OleDoc_QueryInterface(lpOleDoc, riid, lplpvObj);

}

STDMETHODIMP_(ULONG) OleDoc_Unk_AddRef(LPUNKNOWN lpThis)

{

   LPOLEDOC lpOleDoc = ((struct CDocUnknownImpl FAR*)lpThis)->lpOleDoc;

   OleDbgAddRefMethod(lpThis, "IUnknown");

   return OleDoc_AddRef(lpOleDoc);

}

STDMETHODIMP_(ULONG) OleDoc_Unk_Release (LPUNKNOWN lpThis)

{

   LPOLEDOC lpOleDoc = ((struct CDocUnknownImpl FAR*)lpThis)->lpOleDoc;

   OleDbgReleaseMethod(lpThis, "IUnknown");

   return OleDoc_Release(lpOleDoc);

}


OLEOUTL.H  (OUTLINE Sample)

/*************************************************************************

**

**    OLE 2.0 Sample Code

**

**    oleoutl.h

**

**    This file contains file contains data structure defintions,

**    function prototypes, constants, etc. which are common to the

**    server version and the container version of the app.

**    app version of the Outline series of sample applications:

**          Outline -- base version of the app (without OLE functionality)

**          SvrOutl -- OLE 2.0 Server sample app

**          CntrOutl -- OLE 2.0 Containter sample app

**

**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

**

*************************************************************************/

#if !defined( _OLEOUTL_H_ )

#define _OLEOUTL_H_

#ifndef RC_INVOKED

#pragma message ("INCLUDING OLEOUTL.H from " __FILE__)

// make 'different levels of inderection' considered an error

#pragma warning (error:4047)

#endif  /* RC_INVOKED */

#if defined( USE_MSGFILTER )

//#include "..\include\msgfiltr.h"

#include "msgfiltr.h"

#endif  // USE_MSGFILTER

#include "defguid.h"

#include "ansiapi.h"

/* Defines */

/* OLE2NOTE: these strings should correspond to the strings registered

**    in the registration database.

*/

// REVIEW: should load strings from resource file

#if defined( INPLACE_SVR )

#ifdef TEST32

#define CLSID_APP   CLSID_ISvrOu32

#define FULLUSERTYPENAME    OLESTR("Ole 2.0 In-Place Server Outline 32")

#define SHORTUSERTYPENAME   OLESTR("Outline32")   // max 15 chars

#undef  APPFILENAMEFILTER

#define APPFILENAMEFILTER   "Outline Files (*.OLT)|*.olt|All files (*.*)|*.*|"

#undef  DEFEXTENSION

#define DEFEXTENSION    "olt"           // Default file extension

#else

#define CLSID_APP   CLSID_ISvrOtl

#define FULLUSERTYPENAME    OLESTR("Ole 2.0 In-Place Server Outline")

#define SHORTUSERTYPENAME   OLESTR("Outline")   // max 15 chars

#undef  APPFILENAMEFILTER

#define APPFILENAMEFILTER   "Outline Files (*.OLN)|*.oln|All files (*.*)|*.*|"

#undef  DEFEXTENSION

#define DEFEXTENSION    "oln"           // Default file extension

#endif  // TEST32

#endif  // INPLACE_SVR

#if defined( INPLACE_CNTR )

#ifdef TEST32

#define CLSID_APP   CLSID_ICntrO32

#define FULLUSERTYPENAME    OLESTR("Ole 2.0 In-Place Container Outline 32")

// #define SHORTUSERTYPENAME    "Outline32"   // max 15 chars

#undef  APPFILENAMEFILTER

#define APPFILENAMEFILTER   "CntrOutl Files (*.OLC)|*.olc|Outline Files (*.OLT)|*.olt|All files (*.*)|*.*|"

#undef  DEFEXTENSION

#define DEFEXTENSION    "olc"           // Default file extension

#else

#define CLSID_APP   CLSID_ICntrOtl

#define FULLUSERTYPENAME    OLESTR("Ole 2.0 In-Place Container Outline")

// #define SHORTUSERTYPENAME    "Outline"   // max 15 chars

#undef  APPFILENAMEFILTER

#define APPFILENAMEFILTER   "CntrOutl Files (*.OLC)|*.olc|Outline Files (*.OLN)|*.oln|All files (*.*)|*.*|"

#undef  DEFEXTENSION

#define DEFEXTENSION    "olc"           // Default file extension

#endif TEST32

#endif  // INPLACE_CNTR

#if defined( OLE_SERVER ) && !defined( INPLACE_SVR )

#ifdef TEST32

#define CLSID_APP   CLSID_SvrOut32

#define FULLUSERTYPENAME    OLESTR("Ole 2.0 Server Sample Outline 32")

#define SHORTUSERTYPENAME   OLESTR("Outline32")

#undef  APPFILENAMEFILTER

#define APPFILENAMEFILTER   "Outline Files (*.OLT)|*.olt|All files (*.*)|*.*|"

#undef  DEFEXTENSION

#define DEFEXTENSION    "olt"           // Default file extension

#else

#define CLSID_APP   CLSID_SvrOutl

#define FULLUSERTYPENAME    OLESTR("Ole 2.0 Server Sample Outline")

#define SHORTUSERTYPENAME   OLESTR("Outline")

#undef  APPFILENAMEFILTER

#define APPFILENAMEFILTER   "Outline Files (*.OLN)|*.oln|All files (*.*)|*.*|"

#undef  DEFEXTENSION

#define DEFEXTENSION    "oln"           // Default file extension

#endif  //TEST32

#endif  // OLE_SERVER && ! INPLACE_SVR

#if defined( OLE_CNTR ) && !defined( INPLACE_CNTR )

#ifdef TEST32

#define CLSID_APP   CLSID_CntrOu32

#define FULLUSERTYPENAME    OLESTR("Ole 2.0 Container Sample Outline 32")

// #define SHORTUSERTYPENAME    "Outline32"  // max 15 chars

#undef  APPFILENAMEFILTER

#define APPFILENAMEFILTER   "CntrOutl Files (*.OLC)|*.olc|Outline Files (*.OLT)|*.olt|All files (*.*)|*.*|"

#undef  DEFEXTENSION

#define DEFEXTENSION    "olc"           // Default file extension

#else

#define CLSID_APP   CLSID_CntrOutl

#define FULLUSERTYPENAME    OLESTR("Ole 2.0 Container Sample Outline")

// #define SHORTUSERTYPENAME    "Outline"  // max 15 chars

#undef  APPFILENAMEFILTER

#define APPFILENAMEFILTER   "CntrOutl Files (*.OLC)|*.olc|Outline Files (*.OLN)|*.oln|All files (*.*)|*.*|"

#undef  DEFEXTENSION

#define DEFEXTENSION    "olc"           // Default file extension

#endif  //TEST32

#endif  // OLE_CNTR && ! INPLACE_CNTR

// Maximum number of formats offered by IDataObject::GetData/SetData

#define MAXNOFMTS       10

#define MAXNOLINKTYPES   3

#if defined( USE_DRAGDROP )

#define DD_SEL_THRESH       HITTESTDELTA    // Border threshold to start drag

#define MAX_SEL_ITEMS       0x0080

#endif  // USE_DRAGDROP

/* Positions of the various menus */

#define POS_FILEMENU        0

#define POS_EDITMENU        1

#define POS_VIEWMENU        2

#define POS_LINEMENU        3

#define POS_NAMEMENU        4

#define POS_OPTIONSMENU     5

#define POS_DEBUGMENU       6

#define POS_HELPMENU        7

#define POS_OBJECT      11

/* Types */

// Document initialization type

#define DOCTYPE_EMBEDDED    3   // init from an IStorage* of an embedded obj

#define DOCTYPE_FROMSTG     4   // init from an IStorage* with doc bit set

/* Forward type definitions */

typedef struct tagOLEAPP FAR* LPOLEAPP;

typedef struct tagOLEDOC FAR* LPOLEDOC;

/* Flags to control Moniker assignment for OleDoc_GetFullMoniker */

// REVIEW: should use official OLEGETMONIKER type for final version

typedef enum tagGETMONIKERTYPE {

   GETMONIKER_ONLYIFTHERE  = 1,

   GETMONIKER_FORCEASSIGN  = 2,

   GETMONIKER_UNASSIGN     = 3,

   GETMONIKER_TEMPFORUSER  = 4

} GETMONIKERTYPE;

/* Flags to control direction for drag scrolling */

typedef enum tagSCROLLDIR {

   SCROLLDIR_NULL          = 0,

   SCROLLDIR_UP            = 1,

   SCROLLDIR_DOWN          = 2,

   SCROLLDIR_RIGHT         = 3,    // currently not used

   SCROLLDIR_LEFT          = 4     // currently not used

} SCROLLDIR;

/*************************************************************************

** class OLEDOC : OUTLINEDOC

**    OLEDOC is an extention to the base OUTLINEDOC object (structure)

**    that adds common OLE 2.0 functionality used by both the server

**    and container versions. This is an abstract class. You do not

**    instantiate an instance of OLEDOC directly but instead

**    instantiate one of its concrete subclasses: SERVERDOC or

**    CONTAINERDOC. There is one instance of an document

**    object created per document open in the app. The SDI

**    version of the app supports one ServerDoc at a time. The MDI

**    version of the app can manage multiple documents at one time.

**    The OLEDOC class inherits all fields from the OUTLINEDOC class.

**    This inheritance is achieved by including a member variable of

**    type OUTLINEDOC as the first field in the OLEDOC

**    structure. Thus a pointer to an OLEDOC object can be cast to be

**    a pointer to a OUTLINEDOC object.

*************************************************************************/

typedef struct tagOLEDOC {

   OUTLINEDOC      m_OutlineDoc;       // ServerDoc inherits from OutlineDoc

   ULONG           m_cRef;             // total ref count for document

   ULONG           m_dwStrongExtConn;  // total strong connection count

                              //  (from IExternalConnection)

                              //  when this count transitions to 0

                              //  and fLastUnlockCloses==TRUE, then

                              //  IOleObject::Close is called to

                              //  close the document.

#if defined( _DEBUG )

   ULONG           m_cCntrLock;        // total count of LockContainer locks

                              //  (for debugging purposes only)

#endif

   LPSTORAGE       m_lpStg;            // OleDoc must keep its stg open

                              //  even in-memory server doc should

                              //  keep Stg open for low memory save

   LPSTREAM        m_lpLLStm;          // Hold LineList IStream* open for

                              //  low memory save

   LPSTREAM        m_lpNTStm;          // Hold NameTable IStream* open for

                              //  low memory save

   BOOL            m_fObjIsClosing;    // flag to guard recursive close call

   BOOL            m_fObjIsDestroying; // flag to guard recursiv destroy call

   DWORD           m_dwRegROT;         // key if doc registered as running

   LPMONIKER       m_lpFileMoniker;    // moniker if file-based/untitled doc

   BOOL            m_fLinkSourceAvail; // can doc offer CF_LINKSOURCE

   LPOLEDOC        m_lpSrcDocOfCopy;   // src doc if doc created for copy

   BOOL            m_fUpdateEditMenu;  // need to update edit menu??

#if defined( USE_DRAGDROP )

   DWORD           m_dwTimeEnterScrollArea;  // time entering scroll region

   DWORD           m_dwLastScrollDir;  // current dir for drag scroll

   DWORD           m_dwNextScrollTime; // time for next scroll

   BOOL            m_fRegDragDrop;     // is doc registered as drop target?

   BOOL            m_fLocalDrag;       // is doc source of the drag

   BOOL            m_fLocalDrop;       // was doc target of the drop

   BOOL            m_fCanDropCopy;     // is Drag/Drop copy/move possible?

   BOOL            m_fCanDropLink;     // is Drag/Drop link possible?

   BOOL            m_fDragLeave;       // has drag left

   BOOL            m_fPendingDrag;     // LButtonDown--possible drag pending

   POINT           m_ptButDown;        // LButtonDown coordinates

#endif  // USE_DRAGDROP

#if defined( INPLACE_SVR ) || defined( INPLACE_CNTR )

   BOOL            m_fCSHelpMode;      // Shift-F1 context help mode

#endif

   struct CDocUnknownImpl {

      IUnknownVtbl FAR*       lpVtbl;

      LPOLEDOC                lpOleDoc;

      int                     cRef;   // interface specific ref count.

   } m_Unknown;

   struct CDocPersistFileImpl {

      IPersistFileVtbl FAR*   lpVtbl;

      LPOLEDOC                lpOleDoc;

      int                     cRef;   // interface specific ref count.

   } m_PersistFile;

   struct CDocOleItemContainerImpl {

      IOleItemContainerVtbl FAR*  lpVtbl;

      LPOLEDOC                    lpOleDoc;

      int                         cRef;   // interface specific ref count.

   } m_OleItemContainer;

   struct CDocExternalConnectionImpl {

      IExternalConnectionVtbl FAR* lpVtbl;

      LPOLEDOC                lpOleDoc;

      int                     cRef;   // interface specific ref count.

   } m_ExternalConnection;

   struct CDocDataObjectImpl {

      IDataObjectVtbl FAR*        lpVtbl;

      LPOLEDOC                    lpOleDoc;

      int                         cRef;   // interface specific ref count.

   } m_DataObject;

#ifdef USE_DRAGDROP

   struct CDocDropSourceImpl {

      IDropSourceVtbl FAR*    lpVtbl;

      LPOLEDOC                lpOleDoc;

      int                     cRef;   // interface specific ref count.

   } m_DropSource;

   struct CDocDropTargetImpl {

      IDropTargetVtbl FAR*    lpVtbl;

      LPOLEDOC                lpOleDoc;

      int                     cRef;   // interface specific ref count.

   } m_DropTarget;

#endif  // USE_DRAGDROP

} OLEDOC;

/* OleDoc methods (functions) */

BOOL OleDoc_Init(LPOLEDOC lpOleDoc, BOOL fDataTransferDoc);

BOOL OleDoc_InitNewFile(LPOLEDOC lpOleDoc);

void OleDoc_ShowWindow(LPOLEDOC lpOleDoc);

void OleDoc_HideWindow(LPOLEDOC lpOleDoc, BOOL fShutDown);

HRESULT OleDoc_Lock(LPOLEDOC lpOleDoc, BOOL fLock, BOOL fLastUnlockReleases);

ULONG OleDoc_AddRef(LPOLEDOC lpOleDoc);

ULONG OleDoc_Release (LPOLEDOC lpOleDoc);

HRESULT OleDoc_QueryInterface(

      LPOLEDOC          lpOleDoc,

      REFIID            riid,

      LPVOID FAR*       lplpUnk

);

BOOL OleDoc_Close(LPOLEDOC lpOleDoc, DWORD dwSaveOption);

void OleDoc_Destroy(LPOLEDOC lpOleDoc);

void OleDoc_SetUpdateEditMenuFlag(LPOLEDOC lpOleDoc, BOOL fUpdate);

BOOL OleDoc_GetUpdateEditMenuFlag(LPOLEDOC lpOleDoc);

void OleDoc_GetExtent(LPOLEDOC lpOleDoc, LPSIZEL lpsizel);

HGLOBAL OleDoc_GetObjectDescriptorData(

      LPOLEDOC            lpOleDoc,

      LPLINERANGE         lplrSel

);

LPMONIKER OleDoc_GetFullMoniker(LPOLEDOC lpOleDoc, DWORD dwAssign);

void OleDoc_GetExtent(LPOLEDOC lpOleDoc, LPSIZEL lpsizel);

void OleDoc_DocRenamedUpdate(LPOLEDOC lpOleDoc, LPMONIKER lpmkDoc);

void OleDoc_CopyCommand(LPOLEDOC lpSrcOleDoc);

void OleDoc_PasteCommand(LPOLEDOC lpOleDoc);

void OleDoc_PasteSpecialCommand(LPOLEDOC lpOleDoc);

LPOUTLINEDOC OleDoc_CreateDataTransferDoc(LPOLEDOC lpSrcOleDoc);

BOOL OleDoc_PasteFromData(

      LPOLEDOC            lpOleDoc,

      LPDATAOBJECT        lpSrcDataObj,

      BOOL                fLocalDataObj,

      BOOL                fLink

);

BOOL OleDoc_PasteFormatFromData(

      LPOLEDOC            lpOleDoc,

      CLIPFORMAT          cfFormat,

      LPDATAOBJECT        lpSrcDataObj,

      BOOL                fLocalDataObj,

      BOOL                fLink,

      BOOL                fDisplayAsIcon,

      HGLOBAL             hMetaPict,

      LPSIZEL             lpSizelInSrc

);

BOOL OleDoc_QueryPasteFromData(

      LPOLEDOC            lpOleDoc,

      LPDATAOBJECT        lpSrcDataObj,

      BOOL                fLink

);

#if defined( USE_DRAGDROP )

BOOL OleDoc_QueryDrag( LPOLEDOC lpOleDoc, int y );

BOOL OleDoc_QueryDrop (

   LPOLEDOC        lpOleDoc,

   DWORD           grfKeyState,

   POINTL          pointl,

   BOOL            fDragScroll,

   LPDWORD         lpdwEffect

);

DWORD OleDoc_DoDragDrop (LPOLEDOC lpSrcOleDoc);

BOOL OleDoc_DoDragScroll(LPOLEDOC lpOleDoc, POINTL pointl);

#endif  // USE_DRAGDROP

/* OleDoc::IUnknown methods (functions) */

STDMETHODIMP OleDoc_Unk_QueryInterface(

      LPUNKNOWN           lpThis,

      REFIID              riid,

      LPVOID FAR*         lplpvObj

);

STDMETHODIMP_(ULONG) OleDoc_Unk_AddRef(LPUNKNOWN lpThis);

STDMETHODIMP_(ULONG) OleDoc_Unk_Release (LPUNKNOWN lpThis);

/* OleDoc::IPersistFile methods (functions) */

STDMETHODIMP OleDoc_PFile_QueryInterface(

      LPPERSISTFILE       lpThis,

      REFIID              riid,

      LPVOID FAR*         lplpvObj

);

STDMETHODIMP_(ULONG) OleDoc_PFile_AddRef(LPPERSISTFILE lpThis);

STDMETHODIMP_(ULONG) OleDoc_PFile_Release (LPPERSISTFILE lpThis);

STDMETHODIMP OleDoc_PFile_GetClassID (

      LPPERSISTFILE       lpThis,

      CLSID FAR*          lpclsid

);

STDMETHODIMP  OleDoc_PFile_IsDirty(LPPERSISTFILE lpThis);

STDMETHODIMP OleDoc_PFile_Load (

      LPPERSISTFILE       lpThis,

      LPCOLESTR           lpszFileName,

      DWORD               grfMode

);

STDMETHODIMP OleDoc_PFile_Save (

      LPPERSISTFILE       lpThis,

      LPCOLESTR           lpszFileName,

      BOOL                fRemember

);

STDMETHODIMP OleDoc_PFile_SaveCompleted (

      LPPERSISTFILE       lpThis,

      LPCOLESTR           lpszFileName

);

STDMETHODIMP OleDoc_PFile_GetCurFile (

      LPPERSISTFILE   lpThis,

      LPOLESTR FAR*   lplpszFileName

);

/* OleDoc::IOleItemContainer methods (functions) */

STDMETHODIMP OleDoc_ItemCont_QueryInterface(

      LPOLEITEMCONTAINER  lpThis,

      REFIID              riid,

      LPVOID FAR*         lplpvObj

);

STDMETHODIMP_(ULONG) OleDoc_ItemCont_AddRef(LPOLEITEMCONTAINER lpThis);

STDMETHODIMP_(ULONG) OleDoc_ItemCont_Release(LPOLEITEMCONTAINER lpThis);

STDMETHODIMP OleDoc_ItemCont_ParseDisplayName(

      LPOLEITEMCONTAINER  lpThis,

      LPBC                lpbc,

      LPOLESTR            lpszDisplayName,

      ULONG FAR*          lpchEaten,

      LPMONIKER FAR*      lplpmkOut

);

STDMETHODIMP OleDoc_ItemCont_EnumObjects(

      LPOLEITEMCONTAINER  lpThis,

      DWORD               grfFlags,

      LPENUMUNKNOWN FAR*  lplpenumUnknown

);

STDMETHODIMP OleDoc_ItemCont_LockContainer(

      LPOLEITEMCONTAINER  lpThis,

      BOOL                fLock

);

STDMETHODIMP OleDoc_ItemCont_GetObject(

      LPOLEITEMCONTAINER  lpThis,

      LPOLESTR            lpszItem,

      DWORD               dwSpeedNeeded,

      LPBINDCTX           lpbc,

      REFIID              riid,

      LPVOID FAR*         lplpvObject

);

STDMETHODIMP OleDoc_ItemCont_GetObjectStorage(

      LPOLEITEMCONTAINER  lpThis,

      LPOLESTR            lpszItem,

      LPBINDCTX           lpbc,

      REFIID              riid,

      LPVOID FAR*         lplpvStorage

);

STDMETHODIMP OleDoc_ItemCont_IsRunning(

      LPOLEITEMCONTAINER  lpThis,

      LPOLESTR            lpszItem

);

/* OleDoc::IPersistFile methods (functions) */

STDMETHODIMP OleDoc_ExtConn_QueryInterface(

      LPEXTERNALCONNECTION    lpThis,

      REFIID                  riid,

      LPVOID FAR*             lplpvObj

);

STDMETHODIMP_(ULONG) OleDoc_ExtConn_AddRef(LPEXTERNALCONNECTION lpThis);

STDMETHODIMP_(ULONG) OleDoc_ExtConn_Release (LPEXTERNALCONNECTION lpThis);

STDMETHODIMP_(DWORD) OleDoc_ExtConn_AddConnection(

      LPEXTERNALCONNECTION    lpThis,

      DWORD                   extconn,

      DWORD                   reserved

);

STDMETHODIMP_(DWORD) OleDoc_ExtConn_ReleaseConnection(

      LPEXTERNALCONNECTION    lpThis,

      DWORD                   extconn,

      DWORD                   reserved,

      BOOL                    fLastReleaseCloses

);

/* OleDoc::IDataObject methods (functions) */

STDMETHODIMP OleDoc_DataObj_QueryInterface (

      LPDATAOBJECT        lpThis,

      REFIID              riid,

      LPVOID FAR*         lplpvObj

);

STDMETHODIMP_(ULONG) OleDoc_DataObj_AddRef(LPDATAOBJECT lpThis);

STDMETHODIMP_(ULONG) OleDoc_DataObj_Release (LPDATAOBJECT lpThis);

STDMETHODIMP OleDoc_DataObj_GetData (

      LPDATAOBJECT        lpThis,

      LPFORMATETC         lpFormatetc,

      LPSTGMEDIUM         lpMedium

);

STDMETHODIMP OleDoc_DataObj_GetDataHere (

      LPDATAOBJECT        lpThis,

      LPFORMATETC         lpFormatetc,

      LPSTGMEDIUM         lpMedium

);

STDMETHODIMP OleDoc_DataObj_QueryGetData (

      LPDATAOBJECT        lpThis,

      LPFORMATETC         lpFormatetc

);

STDMETHODIMP OleDoc_DataObj_GetCanonicalFormatEtc(

      LPDATAOBJECT        lpThis,

      LPFORMATETC         lpformatetc,

      LPFORMATETC         lpformatetcOut

);

STDMETHODIMP OleDoc_DataObj_SetData (

      LPDATAOBJECT    lpThis,

      LPFORMATETC     lpFormatetc,

      LPSTGMEDIUM     lpMedium,

      BOOL            fRelease

);

STDMETHODIMP OleDoc_DataObj_EnumFormatEtc(

      LPDATAOBJECT            lpThis,

      DWORD                   dwDirection,

      LPENUMFORMATETC FAR*    lplpenumFormatEtc

);

STDMETHODIMP OleDoc_DataObj_DAdvise(

      LPDATAOBJECT        lpThis,

      FORMATETC FAR*      lpFormatetc,

      DWORD               advf,

      LPADVISESINK        lpAdvSink,

      DWORD FAR*          lpdwConnection

);

STDMETHODIMP OleDoc_DataObj_DUnadvise(LPDATAOBJECT lpThis,DWORD dwConnection);

STDMETHODIMP OleDoc_DataObj_EnumDAdvise(

      LPDATAOBJECT        lpThis,

      LPENUMSTATDATA FAR* lplpenumAdvise

);

#ifdef USE_DRAGDROP

/* OleDoc::IDropSource methods (functions) */

STDMETHODIMP OleDoc_DropSource_QueryInterface(

   LPDROPSOURCE            lpThis,

   REFIID                  riid,

   LPVOID FAR*             lplpvObj

);

STDMETHODIMP_(ULONG) OleDoc_DropSource_AddRef( LPDROPSOURCE lpThis );

STDMETHODIMP_(ULONG) OleDoc_DropSource_Release ( LPDROPSOURCE lpThis);

STDMETHODIMP    OleDoc_DropSource_QueryContinueDrag (

   LPDROPSOURCE            lpThis,

   BOOL                    fEscapePressed,

   DWORD                   grfKeyState

);

STDMETHODIMP    OleDoc_DropSource_GiveFeedback (

   LPDROPSOURCE            lpThis,

   DWORD                   dwEffect

);

/* OleDoc::IDropTarget methods (functions) */

STDMETHODIMP OleDoc_DropTarget_QueryInterface(

      LPDROPTARGET        lpThis,

      REFIID              riid,

      LPVOID FAR*         lplpvObj

);

STDMETHODIMP_(ULONG) OleDoc_DropTarget_AddRef(LPDROPTARGET lpThis);

STDMETHODIMP_(ULONG) OleDoc_DropTarget_Release ( LPDROPTARGET lpThis);

STDMETHODIMP    OleDoc_DropTarget_DragEnter (

   LPDROPTARGET            lpThis,

   LPDATAOBJECT            lpDataObj,

   DWORD                   grfKeyState,

   POINTL                  pointl,

   LPDWORD                 lpdwEffect

);

STDMETHODIMP    OleDoc_DropTarget_DragOver (

   LPDROPTARGET            lpThis,

   DWORD                   grfKeyState,

   POINTL                  pointl,

   LPDWORD                 lpdwEffect

);

STDMETHODIMP    OleDoc_DropTarget_DragLeave ( LPDROPTARGET lpThis);

STDMETHODIMP    OleDoc_DropTarget_Drop (

   LPDROPTARGET            lpThis,

   LPDATAOBJECT            lpDataObj,

   DWORD                   grfKeyState,

   POINTL                  pointl,

   LPDWORD                 lpdwEffect

);

#endif  // USE_DRAGDROP

/*************************************************************************

** class APPCLASSFACTORY

**  APPCLASSFACTORY implements the IClassFactory interface. it

**    instantiates document instances of the correct type depending on

**    how the application is compiled (either ServerDoc or ContainerDoc

**    instances). by implementing this

**    interface in a seperate interface from the App object itself, it

**    is easier to manage when the IClassFactory should be

**    registered/revoked. when the OleApp object is first initialized

**    in OleApp_InitInstance an instance of APPCLASSFACTORY is created

**    and registered (CoRegisterClassObject called). when the App

**    object gets destroyed (in OleApp_Destroy) this APPCLASSFACTORY is

**    revoked (CoRevokeClassObject called) and released. the simple

**    fact that the IClassFactory is registered does not on its own keep

**    the application alive.

*************************************************************************/

typedef struct tagAPPCLASSFACTORY {

   IClassFactoryVtbl FAR*  m_lpVtbl;

   UINT                    m_cRef;

#if defined( _DEBUG )

   LONG                    m_cSvrLock; // total count of LockServer locks

                              //  (for debugging purposes only)

#endif

 } APPCLASSFACTORY, FAR* LPAPPCLASSFACTORY;

/* PUBLIC FUNCTIONS */

LPCLASSFACTORY WINAPI AppClassFactory_Create(void);

/* interface IClassFactory implementation */

STDMETHODIMP AppClassFactory_QueryInterface(

      LPCLASSFACTORY lpThis, REFIID riid, LPVOID FAR* ppvObj);

STDMETHODIMP_(ULONG) AppClassFactory_AddRef(LPCLASSFACTORY lpThis);

STDMETHODIMP_(ULONG) AppClassFactory_Release(LPCLASSFACTORY lpThis);

STDMETHODIMP AppClassFactory_CreateInstance (

      LPCLASSFACTORY      lpThis,

      LPUNKNOWN           lpUnkOuter,

      REFIID              riid,

      LPVOID FAR*         lplpvObj

);

STDMETHODIMP AppClassFactory_LockServer (

      LPCLASSFACTORY      lpThis,

      BOOL                fLock

);

/*************************************************************************

** class OLEAPP : OUTLINEAPP

**    OLEAPP is an extention to the base OUTLINEAPP object (structure)

**    that adds common OLE 2.0 functionality used by both the server

**    and container versions. This is an abstract class. You do not

**    instantiate an instance of OLEAPP directly but instead

**    instantiate one of its concrete subclasses: SERVERAPP or

**    CONTAINERAPP. There is one instance of an document application

**    object created per running application instance. This

**    object holds many fields that could otherwise be organized as

**    global variables. The OLEAPP class inherits all fields

**    from the OUTLINEAPP class. This inheritance is achieved by including a

**    member variable of type OUTLINEAPP as the first field in the OLEAPP

**    structure. Thus a pointer to a OLEAPP object can be cast to be

**    a pointer to a OUTLINEAPP object.

*************************************************************************/

typedef struct tagOLEAPP {

   OUTLINEAPP  m_OutlineApp;       // inherits all fields of OutlineApp

   ULONG       m_cRef;             // total ref count for app

   ULONG       m_cDoc;             // total count of open documents

   BOOL        m_fUserCtrl;        // does user control life-time of app?

   DWORD       m_dwRegClassFac;    // value returned by CoRegisterClassObject

   LPCLASSFACTORY m_lpClassFactory;// ptr to allocated ClassFactory instance

#if defined( USE_MSGFILTER )

   LPMESSAGEFILTER m_lpMsgFilter;  // ptr to allocated MsgFilter instance

   MSGPENDINGPROC m_lpfnMsgPending;// ptr to msg pending callback function

#endif  // USE_MSGFILTER

   BOOL        m_fOleInitialized;  // was OleInitialize called

   UINT        m_cModalDlgActive;  // count of modal dialogs up; 0 = no dlg.

   UINT        m_cfEmbedSource;    // OLE 2.0 clipboard format

   UINT        m_cfEmbeddedObject; // OLE 2.0 clipboard format

   UINT        m_cfLinkSource;     // OLE 2.0 clipboard format

   UINT        m_cfObjectDescriptor; // OLE 2.0 clipboard format

   UINT        m_cfLinkSrcDescriptor; // OLE 2.0 clipboard format

   UINT        m_cfFileName;       // std Windows clipboard format

   FORMATETC   m_arrDocGetFmts[MAXNOFMTS];  // fmts offered by copy & GetData

   UINT        m_nDocGetFmts;      // no of fmtetc's for GetData

   OLEUIPASTEENTRY m_arrPasteEntries[MAXNOFMTS];   // input for PasteSpl.

   int         m_nPasteEntries;                    // input for PasteSpl.

   UINT        m_arrLinkTypes[MAXNOLINKTYPES];     // input for PasteSpl.

   int         m_nLinkTypes;                       // input for PasteSpl.

#if defined( USE_DRAGDROP )

   int m_nDragDelay;       // time delay (in msec) before drag should start

   int m_nDragMinDist;     // min. distance (radius) before drag should start

   int m_nScrollDelay;     // time delay (in msec) before scroll should start

   int m_nScrollInset;     // Border inset distance to start drag scroll

   int m_nScrollInterval;  // scroll interval time (in msec)

#if defined( IF_SPECIAL_DD_CURSORS_NEEDED )

   // This would be used if the app wanted to have custom drag/drop cursors

   HCURSOR     m_hcursorDragNone;

   HCURSOR     m_hcursorDragCopy;

   HCURSOR     m_hcursorDragLink;

#endif  // IF_SPECIAL_DD_CURSORS_NEEDED

#endif  // USE_DRAGDROP

#if defined( OLE_CNTR )

   HPALETTE    m_hStdPal;        // standard color palette for OLE

                             //  it is a good idea for containers

                             //  to use this standard palette

                             //  even if they do not use colors

                             //  themselves. this will allow

                             //  embedded object to get a good

                             //  distribution of colors when they

                             //  are being drawn by the container.

                             //

#endif

   struct CAppUnknownImpl {

      IUnknownVtbl FAR*       lpVtbl;

      LPOLEAPP                lpOleApp;

      int                     cRef;   // interface specific ref count.

   } m_Unknown;

} OLEAPP;

/* ServerApp methods (functions) */

BOOL OleApp_InitInstance(LPOLEAPP lpOleApp, HINSTANCE hInst, int nCmdShow);

void OleApp_TerminateApplication(LPOLEAPP lpOleApp);

BOOL OleApp_ParseCmdLine(LPOLEAPP lpOleApp, LPSTR lpszCmdLine, int nCmdShow);

void OleApp_Destroy(LPOLEAPP lpOleApp);

BOOL OleApp_CloseAllDocsAndExitCommand(

      LPOLEAPP            lpOleApp,

      BOOL                fForceEndSession

);

void OleApp_ShowWindow(LPOLEAPP lpOleApp, BOOL fGiveUserCtrl);

void OleApp_HideWindow(LPOLEAPP lpOleApp);

void OleApp_HideIfNoReasonToStayVisible(LPOLEAPP lpOleApp);

void OleApp_DocLockApp(LPOLEAPP lpOleApp);

void OleApp_DocUnlockApp(LPOLEAPP lpOleApp, LPOUTLINEDOC lpOutlineDoc);

HRESULT OleApp_Lock(LPOLEAPP lpOleApp, BOOL fLock, BOOL fLastUnlockReleases);

ULONG OleApp_AddRef(LPOLEAPP lpOleApp);

ULONG OleApp_Release (LPOLEAPP lpOleApp);

HRESULT OleApp_QueryInterface (

      LPOLEAPP                lpOleApp,

      REFIID                  riid,

      LPVOID FAR*             lplpUnk

);

void OleApp_RejectInComingCalls(LPOLEAPP lpOleApp, BOOL fReject);

void OleApp_DisableBusyDialogs(

      LPOLEAPP        lpOleApp,

      BOOL FAR*       lpfPrevBusyEnable,

      BOOL FAR*       lpfPrevNREnable

);

void OleApp_EnableBusyDialogs(

      LPOLEAPP        lpOleApp,

      BOOL            fPrevBusyEnable,

      BOOL            fPrevNREnable

);

void OleApp_PreModalDialog(LPOLEAPP lpOleApp, LPOLEDOC lpActiveOleDoc);

void OleApp_PostModalDialog(LPOLEAPP lpOleApp, LPOLEDOC lpActiveOleDoc);

BOOL OleApp_InitVtbls (LPOLEAPP lpOleApp);

void OleApp_InitMenu(

      LPOLEAPP                lpOleApp,

      LPOLEDOC                lpOleDoc,

      HMENU                   hMenu

);

void OleApp_UpdateEditMenu(

      LPOLEAPP                lpOleApp,

      LPOUTLINEDOC            lpOutlineDoc,

      HMENU                   hMenuEdit

);

BOOL OleApp_RegisterClassFactory(LPOLEAPP lpOleApp);

void OleApp_RevokeClassFactory(LPOLEAPP lpOleApp);

#if defined( USE_MSGFILTER )

BOOL OleApp_RegisterMessageFilter(LPOLEAPP lpOleApp);

void OleApp_RevokeMessageFilter(LPOLEAPP lpOleApp);

BOOL FAR PASCAL EXPORT MessagePendingProc(MSG FAR *lpMsg);

#endif  // USE_MSGFILTER

void OleApp_FlushClipboard(LPOLEAPP lpOleApp);

void OleApp_NewCommand(LPOLEAPP lpOleApp);

void OleApp_OpenCommand(LPOLEAPP lpOleApp);

#if defined( OLE_CNTR )

LRESULT OleApp_QueryNewPalette(LPOLEAPP lpOleApp);

#endif // OLE_CNTR

LRESULT wSelectPalette(HWND hWnd, HPALETTE hPal, BOOL fBackground);

/* OleApp::IUnknown methods (functions) */

STDMETHODIMP OleApp_Unk_QueryInterface(

      LPUNKNOWN           lpThis,

      REFIID              riid,

      LPVOID FAR*         lplpvObj

);

STDMETHODIMP_(ULONG) OleApp_Unk_AddRef(LPUNKNOWN lpThis);

STDMETHODIMP_(ULONG) OleApp_Unk_Release (LPUNKNOWN lpThis);

/* Function prototypes in debug.c */

void InstallMessageFilterCommand(void);

void RejectIncomingCommand(void);

#if defined( OLE_SERVER )

#include "svroutl.h"

#endif

#if defined( OLE_CNTR )

#include "cntroutl.h"

#endif

#endif // _OLEOUTL_H_


OUTLAPP.C  (OUTLINE Sample)

/*************************************************************************

**

**    OLE 2 Sample Code

**

**    outlapp.c

**

**    This file contains OutlineApp functions.

**

**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

**

*************************************************************************/

#include "outline.h"

#include "ansiapi.h"

#if defined( USE_STATUSBAR )

#include "status.h"

#endif

#if !defined( WIN32 )

#include <print.h>

#endif

OLEDBGDATA

extern LPOUTLINEAPP g_lpApp;

extern RECT g_rectNull;

// REVIEW: should use string resource for messages

OLECHAR ErrMsgClass[] = OLESTR("Can't register window classes!");

OLECHAR ErrMsgFrame[] = OLESTR("Can't create Frame Window!");

OLECHAR ErrMsgPrinting[] = OLESTR("Can't access printer!");

/* OutlineApp_InitApplication

** --------------------------

** Sets up the class data structures and does a one-time

**      initialization of the app by registering the window classes.

**      Returns TRUE if initialization is successful

**              FALSE otherwise

*/

BOOL OutlineApp_InitApplication(LPOUTLINEAPP lpOutlineApp, HINSTANCE hInst)

{

   WNDCLASS    wndclass;

   // REVIEW: should load msg strings from string resource

   /* Register the app frame class */

   wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_BYTEALIGNWINDOW;

   wndclass.lpfnWndProc = AppWndProc;

   /* Extra storage for Class and Window objects */

   wndclass.cbClsExtra = 0;

   wndclass.cbWndExtra = sizeof(LPOUTLINEAPP); /* to store lpApp */

   wndclass.hInstance = hInst;

   wndclass.hIcon = LoadIcon(hInst, APPICON);

   wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);

   /* Create brush for erasing background */

   wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);

   wndclass.lpszMenuName = APPMENU;     /* Menu Name is App Name */

   wndclass.lpszClassName = APPWNDCLASS; /* Class Name is App Name */

   if(! RegisterClass(&wndclass)) {

      OutlineApp_ErrorMessage(lpOutlineApp, ErrMsgFrame);

      return FALSE;

   }

   /* Register the document window class */

   wndclass.style = CS_BYTEALIGNWINDOW;

   wndclass.lpfnWndProc = DocWndProc;

   wndclass.hIcon = NULL;

   wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);

   wndclass.lpszMenuName = NULL;

   wndclass.lpszClassName = DOCWNDCLASS;

   wndclass.cbWndExtra = sizeof(LPOUTLINEDOC); /* to store lpDoc */

   if(! RegisterClass(&wndclass)) {

      OutlineApp_ErrorMessage(lpOutlineApp, ErrMsgClass);

      return FALSE;

   }

#if defined( USE_STATUSBAR )

   if (! RegisterStatusClass(hInst))

      return FALSE;

#endif

#if defined( USE_FRAMETOOLS )

   if (! FrameToolsRegisterClass(hInst)) {

      return FALSE;

   }

#endif

#if defined( INPLACE_SVR )

   // We should only register the hatch window class

   // in the UI Library once per application.

   RegisterHatchWindowClass(hInst);

#endif

   return TRUE;

}

/* OutlineApp_InitInstance

 * -----------------------

 *

 *  Performs a per-instance initialization of app.

 *  This method creates the frame window.

 *

 *  RETURNS    : TRUE  - If initialization was successful.

 *               FALSE - otherwise.

 */

BOOL OutlineApp_InitInstance(LPOUTLINEAPP lpOutlineApp, HINSTANCE hInst, int nCmdShow)

{

   char  szAnsiString[256];

   lpOutlineApp->m_hInst = hInst;

   /* create application's Frame window */

   W2A (APPNAME, szAnsiString, 256);

   lpOutlineApp->m_hWndApp = CreateWindow(

         APPWNDCLASS,             /* Window class name */

         szAnsiString,            /* initial Window title */

         WS_OVERLAPPEDWINDOW|

         WS_CLIPCHILDREN,

         CW_USEDEFAULT, 0,        /* Use default X, Y            */

         CW_USEDEFAULT, 0,        /* Use default X, Y            */

         HWND_DESKTOP,            /* Parent window's handle      */

         NULL,                    /* Default to Class Menu       */

         hInst,                   /* Instance of window          */

         NULL                     /* Create struct for WM_CREATE */

   );

   if(! lpOutlineApp->m_hWndApp) {

      // REVIEW: should load string from string resource

      OutlineApp_ErrorMessage(lpOutlineApp, ErrMsgFrame);

      return FALSE;

   }

   SetWindowLong(lpOutlineApp->m_hWndApp, 0, (LONG) lpOutlineApp);

   /* defer creating the user's SDI document until we parse the cmd line. */

   lpOutlineApp->m_lpDoc = NULL;

   /* Initialize clipboard.

   */

   lpOutlineApp->m_lpClipboardDoc = NULL;

   W2A (OUTLINEDOCFORMAT, szAnsiString, 256);

   if(!(lpOutlineApp->m_cfOutline = RegisterClipboardFormat(szAnsiString))) {

      // REVIEW: should load string from string resource

      OutlineApp_ErrorMessage(lpOutlineApp, OLESTR("Can't register clipboard format!"));

      return FALSE;

   }

   /* init the standard font to be used for drawing/printing text

   *       request a Roman style True Type font of the desired size

   */

   lpOutlineApp->m_hStdFont = CreateFont(

         -DEFFONTSIZE,

         0,0,0,0,0,0,0,0,

         OUT_TT_PRECIS,      // use TrueType

         CLIP_DEFAULT_PRECIS,

         DEFAULT_QUALITY,

         VARIABLE_PITCH | FF_ROMAN,

         DEFFONTFACE

   );

   // Load special cursor for selection of Lines in ListBox.

   lpOutlineApp->m_hcursorSelCur = LoadCursor ( hInst, "SelCur" );

   /* init the Print Dialog structure */

   _fmemset((LPVOID)&lpOutlineApp->m_PrintDlg,0,sizeof(PRINTDLG));

   lpOutlineApp->m_PrintDlg.lStructSize = sizeof(PRINTDLG);

   lpOutlineApp->m_PrintDlg.hDevMode = NULL;

   lpOutlineApp->m_PrintDlg.hDevNames = NULL;

   lpOutlineApp->m_PrintDlg.Flags = PD_RETURNDC | PD_NOSELECTION | PD_NOPAGENUMS |

               PD_HIDEPRINTTOFILE;

   lpOutlineApp->m_PrintDlg.nCopies = 1;

   lpOutlineApp->m_PrintDlg.hwndOwner = lpOutlineApp->m_hWndApp;

#if defined( USE_STATUSBAR )

   lpOutlineApp->m_hWndStatusBar = CreateStatusWindow(lpOutlineApp->m_hWndApp, hInst);

   if (! lpOutlineApp->m_hWndStatusBar)

      return FALSE;

   lpOutlineApp->m_hMenuApp = GetMenu(lpOutlineApp->m_hWndApp);

   /* setup status messages for the application menus */

   {

      HMENU hMenuFile = GetSubMenu(lpOutlineApp->m_hMenuApp, 0);

      HMENU hMenuEdit = GetSubMenu(lpOutlineApp->m_hMenuApp, 1);

      HMENU hMenuOutline = GetSubMenu(lpOutlineApp->m_hMenuApp, 2);

      HMENU hMenuLine = GetSubMenu(lpOutlineApp->m_hMenuApp, 3);

      HMENU hMenuName = GetSubMenu(lpOutlineApp->m_hMenuApp, 4);

      HMENU hMenuOptions = GetSubMenu(lpOutlineApp->m_hMenuApp, 5);

      HMENU hMenuDebug = GetSubMenu(lpOutlineApp->m_hMenuApp, 6);

      HMENU hMenuHelp = GetSubMenu(lpOutlineApp->m_hMenuApp, 7);

      HMENU hMenuSys = GetSystemMenu(lpOutlineApp->m_hWndApp, FALSE);

      AssignPopupMessage(hMenuFile, "Create, open, save, print outlines or quit application");

      AssignPopupMessage(hMenuEdit, "Cut, copy, paste or clear selection");

      AssignPopupMessage(hMenuOutline, "Set zoom and margins");

      AssignPopupMessage(hMenuLine, "Create, edit, and indent lines");

      AssignPopupMessage(hMenuName, "Create, edit, delete and goto names");

      AssignPopupMessage(hMenuOptions, "Modify tools, row/col headings, display options");

      AssignPopupMessage(hMenuDebug, "Set debug trace level and other debug options");

      AssignPopupMessage(hMenuHelp, "Get help on using the application");

      AssignPopupMessage(hMenuSys,"Move, size or close application window");

   }

#endif

#if defined ( USE_FRAMETOOLS ) || defined ( INPLACE_CNTR )

   lpOutlineApp->m_FrameToolWidths = g_rectNull;

#endif  // USE_FRAMETOOLS || INPLACE_CNTR

#if defined( USE_FRAMETOOLS )

   if (! FrameTools_Init(&lpOutlineApp->m_frametools,

         lpOutlineApp->m_hWndApp, lpOutlineApp->m_hInst))

      return FALSE;

#endif

#if defined( OLE_VERSION )

   /* OLE2NOTE: perform initialization required for OLE */

   if (! OleApp_InitInstance((LPOLEAPP)lpOutlineApp, hInst, nCmdShow))

      return FALSE;

#else

   /* OLE2NOTE: Although no OLE call is made in the base outline,

   **    OLE memory allocator is used and thus CoInitialize() needs to

   **    be called.

   */

   {

      HRESULT hrErr;

      hrErr = CoInitialize(NULL);

      if (hrErr != NOERROR) {

         OutlineApp_ErrorMessage(lpOutlineApp,

               OLESTR("CoInitialize initialization failed!"));

         return FALSE;

      }

   }

#endif

   return TRUE;

}

/* OutlineApp_ParseCmdLine

 * -----------------------

 *

 * Parse the command line for any execution flags/arguments.

 */

BOOL OutlineApp_ParseCmdLine(LPOUTLINEAPP lpOutlineApp, LPSTR lpszCmdLine, int nCmdShow)

{

#if defined( OLE_VERSION )

   // Call OLE version of this function instead

   return OleApp_ParseCmdLine((LPOLEAPP)lpOutlineApp,lpszCmdLine,nCmdShow);

#else

   BOOL fStatus = TRUE;

   char szFileName[256];   /* buffer for filename in command line */

   OLECHAR szTempW[256];   /* buffer for unicode/ansi strings*/

   szFileName[0] = '\0';

   ParseCmdLine(lpszCmdLine, NULL, (LPSTR)szFileName);

   if(*szFileName) {

      // allocate a new document

      lpOutlineApp->m_lpDoc = OutlineApp_CreateDoc(lpOutlineApp, FALSE);

      if (! lpOutlineApp->m_lpDoc) goto error;

      // open the specified file

      A2W(szFileName, szTempW, 256);

      if (! OutlineDoc_LoadFromFile(lpOutlineApp->m_lpDoc, szTempW))

         goto error;

   } else {

      // create a new document

      lpOutlineApp->m_lpDoc = OutlineApp_CreateDoc(lpOutlineApp, FALSE);

      if (! lpOutlineApp->m_lpDoc) goto error;

      // set the doc to an (Untitled) doc.

      if (! OutlineDoc_InitNewFile(lpOutlineApp->m_lpDoc))

         goto error;

   }

   // position and size the new doc window

   OutlineApp_ResizeWindows(lpOutlineApp);

   OutlineDoc_ShowWindow(lpOutlineApp->m_lpDoc);

   // show main app window

   ShowWindow(lpOutlineApp->m_hWndApp, nCmdShow);

   UpdateWindow(lpOutlineApp->m_hWndApp);

   return TRUE;

error:

   // REVIEW: should load string from string resource

   OutlineApp_ErrorMessage(lpOutlineApp, OLESTR("Could not create new document"));

   if (lpOutlineApp->m_lpDoc) {

      OutlineDoc_Destroy(lpOutlineApp->m_lpDoc);

      lpOutlineApp->m_lpDoc = NULL;

   }

   return FALSE;

#endif

}

/* OutlineApp_InitMenu

 * -------------------

 *

 *      Enable or Disable menu items depending on the state of

 * the appliation

 */

void OutlineApp_InitMenu(LPOUTLINEAPP lpOutlineApp, LPOUTLINEDOC lpOutlineDoc, HMENU hMenu)

{

   WORD status;

   static UINT     uCurrentZoom = (UINT)-1;

   static UINT     uCurrentMargin = (UINT)-1;

   static UINT     uBBState = (UINT)-1;

   static UINT     uFBState = (UINT)-1;

   if (!lpOutlineApp || !lpOutlineDoc || !hMenu)

      return;

   EnableMenuItem(lpOutlineApp->m_hMenuApp, IDM_E_UNDO, MF_GRAYED);

   status = (WORD)(OutlineDoc_GetLineCount(lpOutlineDoc) ? MF_ENABLED : MF_GRAYED);

   EnableMenuItem(lpOutlineApp->m_hMenuApp, IDM_E_CUT ,status);

   EnableMenuItem(lpOutlineApp->m_hMenuApp, IDM_E_COPY ,status);

   EnableMenuItem(lpOutlineApp->m_hMenuApp, IDM_E_CLEAR ,status);

   EnableMenuItem(lpOutlineApp->m_hMenuApp, IDM_E_SELECTALL ,status);

   EnableMenuItem(lpOutlineApp->m_hMenuApp, IDM_L_EDITLINE ,status);

   EnableMenuItem(lpOutlineApp->m_hMenuApp, IDM_L_INDENTLINE ,status);

   EnableMenuItem(lpOutlineApp->m_hMenuApp, IDM_L_UNINDENTLINE ,status);

   EnableMenuItem(lpOutlineApp->m_hMenuApp, IDM_L_SETLINEHEIGHT ,status);

   EnableMenuItem(lpOutlineApp->m_hMenuApp, IDM_N_DEFINENAME ,status);

   status = (WORD)(OutlineDoc_GetNameCount(lpOutlineDoc) ? MF_ENABLED : MF_GRAYED);

   EnableMenuItem(lpOutlineApp->m_hMenuApp, IDM_N_GOTONAME, status);

   if (uCurrentZoom != (UINT)-1)

      CheckMenuItem(lpOutlineApp->m_hMenuApp, uCurrentZoom, MF_UNCHECKED);

   uCurrentZoom = OutlineDoc_GetCurrentZoomMenuCheck(lpOutlineDoc);

   CheckMenuItem(lpOutlineApp->m_hMenuApp, uCurrentZoom, MF_CHECKED);

   if (uCurrentMargin != (UINT)-1)

      CheckMenuItem(lpOutlineApp->m_hMenuApp, uCurrentMargin, MF_UNCHECKED);

   uCurrentMargin = OutlineDoc_GetCurrentMarginMenuCheck(lpOutlineDoc);

   CheckMenuItem(lpOutlineApp->m_hMenuApp, uCurrentMargin, MF_CHECKED);

#if defined( USE_FRAMETOOLS )

   if (uBBState != (UINT)-1)

      CheckMenuItem(lpOutlineApp->m_hMenuApp, uBBState, MF_UNCHECKED);

   if (lpOutlineDoc->m_lpFrameTools) {

      switch (FrameTools_BB_GetState(lpOutlineDoc->m_lpFrameTools)) {

         case BARSTATE_TOP:

            uBBState = IDM_O_BB_TOP;

            break;

         case BARSTATE_BOTTOM:

            uBBState = IDM_O_BB_BOTTOM;

            break;

         case BARSTATE_POPUP:

            uBBState = IDM_O_BB_POPUP;

            break;

         case BARSTATE_HIDE:

            uBBState = IDM_O_BB_HIDE;

            break;

      }

      CheckMenuItem(lpOutlineApp->m_hMenuApp, uBBState, MF_CHECKED);

   }

   if (uFBState != (UINT)-1)

      CheckMenuItem(lpOutlineApp->m_hMenuApp, uFBState, MF_UNCHECKED);

   if (lpOutlineDoc->m_lpFrameTools) {

      switch (FrameTools_FB_GetState(lpOutlineDoc->m_lpFrameTools)) {

         case BARSTATE_TOP:

            uFBState = IDM_O_FB_TOP;

            break;

         case BARSTATE_BOTTOM:

            uFBState = IDM_O_FB_BOTTOM;

            break;

         case BARSTATE_POPUP:

            uFBState = IDM_O_FB_POPUP;

            break;

      }

      CheckMenuItem(lpOutlineApp->m_hMenuApp, uFBState, MF_CHECKED);

   }

#endif  // USE_FRAMETOOLS

#if defined( OLE_VERSION )

   /* OLE2NOTE: perform OLE specific menu initialization.

   **    the OLE versions use the OleGetClipboard mechanism for

   **    clipboard handling. thus, they determine if the Paste and

   **    PasteSpecial commands should be enabled in an OLE specific

   **    manner.

   **    (Container only) build the OLE object verb menu if necessary.

   */

   OleApp_InitMenu(

         (LPOLEAPP)lpOutlineApp,

         (LPOLEDOC)lpOutlineDoc,

         lpOutlineApp->m_hMenuApp

   );

   /* OLE2NOTE: To avoid the overhead of initializing the Edit menu,

   **    we do it only when it is popped up. Thus we just set a flag

   **    in the OleDoc saying that the Edit menu needs to be updated

   **    but we don't do it immediately

   */

   OleDoc_SetUpdateEditMenuFlag((LPOLEDOC)lpOutlineDoc, TRUE);

#else

   // Base Outline version uses standard Windows clipboard handling

   if(IsClipboardFormatAvailable(lpOutlineApp->m_cfOutline) ||

      IsClipboardFormatAvailable(CF_TEXT))

      status = MF_ENABLED;

   else

      status = MF_GRAYED;

   EnableMenuItem(lpOutlineApp->m_hMenuApp, IDM_E_PASTE, status);

#endif

#if defined( USE_FRAMETOOLS )

   if (! OutlineDoc_IsEditFocusInFormulaBar(lpOutlineDoc)) {

      EnableMenuItem(lpOutlineApp->m_hMenuApp, IDM_L_ADDLINE, MF_GRAYED);

      EnableMenuItem(lpOutlineApp->m_hMenuApp, IDM_L_EDITLINE, MF_GRAYED);

   }

   else

      EnableMenuItem(lpOutlineApp->m_hMenuApp, IDM_L_ADDLINE, MF_ENABLED);

#endif      // USE_FRAMETOOLS

}

/* OutlineApp_GetWindow

 * --------------------

 *

 *      Get the window handle of the application frame.

 */

HWND OutlineApp_GetWindow(LPOUTLINEAPP lpOutlineApp)

{

   if (!lpOutlineApp)

      return NULL;

   return lpOutlineApp->m_hWndApp;

}

/* OutlineApp_GetFrameWindow

** -------------------------

**    Gets the current frame window to use as a parent to any dialogs

**    this app uses.

**

**    OLE2NOTE: normally this is simply the main hWnd of the app. but,

**    if the app is currently supporting an in-place server document,

**    then the frame window of the top in-place container must be used.

*/

HWND OutlineApp_GetFrameWindow(LPOUTLINEAPP lpOutlineApp)

{

   HWND hWndApp = OutlineApp_GetWindow(lpOutlineApp);

#if defined( INPLACE_SVR )

   LPSERVERDOC lpServerDoc =

         (LPSERVERDOC)OutlineApp_GetActiveDoc(lpOutlineApp);

   if (lpServerDoc && lpServerDoc->m_fUIActive)

      return lpServerDoc->m_lpIPData->frameInfo.hwndFrame;

#endif

   return hWndApp;

}

/* OutlineApp_GetInstance

 * ----------------------

 *

 *      Get the process instance of the application.

 */

HINSTANCE OutlineApp_GetInstance(LPOUTLINEAPP lpOutlineApp)

{

   if (!lpOutlineApp)

      return NULL;

   return lpOutlineApp->m_hInst;

}

/* OutlineApp_CreateDoc

 * --------------------

 *

 * Allocate a new document of the appropriate type.

 *  OutlineApp  --> creates OutlineDoc type documents

 *

 *      Returns lpOutlineDoc for successful, NULL if error.

 */

LPOUTLINEDOC OutlineApp_CreateDoc(

      LPOUTLINEAPP    lpOutlineApp,

      BOOL            fDataTransferDoc

)

{

   LPOUTLINEDOC lpOutlineDoc;

   OLEDBG_BEGIN3("OutlineApp_CreateDoc\r\n")

#if defined( OLE_SERVER )

   lpOutlineDoc = (LPOUTLINEDOC)New((DWORD)sizeof(SERVERDOC));

   _fmemset(lpOutlineDoc, 0, sizeof(SERVERDOC));

#endif

#if defined( OLE_CNTR )

   lpOutlineDoc = (LPOUTLINEDOC)New((DWORD)sizeof(CONTAINERDOC));

   _fmemset(lpOutlineDoc, 0, sizeof(CONTAINERDOC));

#endif

#if !defined( OLE_VERSION )

   lpOutlineDoc = (LPOUTLINEDOC)New((DWORD)sizeof(OUTLINEDOC));

   _fmemset(lpOutlineDoc, 0, sizeof(OUTLINEDOC));

#endif

   OleDbgAssertSz(lpOutlineDoc != NULL, "Error allocating OutlineDoc");

   if (lpOutlineDoc == NULL)

      return NULL;

   // initialize new document

   if (! OutlineDoc_Init(lpOutlineDoc, fDataTransferDoc))

      goto error;

   OLEDBG_END3

   return lpOutlineDoc;

error:

   if (lpOutlineDoc)

      Delete(lpOutlineDoc);

   OLEDBG_END3

   return NULL;

}

/* OutlineApp_CreateName

 * ---------------------

 *

 * Allocate a new Name of the appropriate type.

 *  OutlineApp --> creates standard OutlineName type names.

 *  ServerApp  --> creates enhanced SeverName type names.

 *

 *      Returns lpOutlineName for successful, NULL if error.

 */

LPOUTLINENAME OutlineApp_CreateName(LPOUTLINEAPP lpOutlineApp)

{

   LPOUTLINENAME lpOutlineName;

#if defined( OLE_SERVER )

   lpOutlineName = (LPOUTLINENAME)New((DWORD)sizeof(SERVERNAME));

#else

   lpOutlineName = (LPOUTLINENAME)New((DWORD)sizeof(OUTLINENAME));

#endif

   OleDbgAssertSz(lpOutlineName != NULL, "Error allocating Name");

   if (lpOutlineName == NULL)

      return NULL;

#if defined( OLE_SERVER )

   _fmemset((LPVOID)lpOutlineName,0,sizeof(SERVERNAME));

#else

   _fmemset((LPVOID)lpOutlineName,0,sizeof(OUTLINENAME));

#endif

   return lpOutlineName;

}

/* OutlineApp_DocUnlockApp

** -----------------------

**    Forget all references to a closed document.

*/

void OutlineApp_DocUnlockApp(LPOUTLINEAPP lpOutlineApp, LPOUTLINEDOC lpOutlineDoc)

{

   /* forget pointers to destroyed document */

   if (lpOutlineApp->m_lpDoc == lpOutlineDoc)

      lpOutlineApp->m_lpDoc = NULL;

   else if (lpOutlineApp->m_lpClipboardDoc == lpOutlineDoc)

      lpOutlineApp->m_lpClipboardDoc = NULL;

#if defined( OLE_VERSION )

   /* OLE2NOTE: when there are no open documents and the app is not

   **    under the control of the user then revoke our ClassFactory to

   **    enable the app to shut down.

   **

   **    NOTE: data transfer documents (non-user documents) do NOT

   **    hold the app alive. therefore they do not Lock the app.

   */

   if (! lpOutlineDoc->m_fDataTransferDoc)

      OleApp_DocUnlockApp((LPOLEAPP)lpOutlineApp, lpOutlineDoc);

#endif

}

/* OutlineApp_NewCommand

 * ---------------------

 *

 *  Start a new untitled document (File.New command).

 */

void OutlineApp_NewCommand(LPOUTLINEAPP lpOutlineApp)

{

#if defined( OLE_VERSION )

   // Call OLE version of this function instead

   OleApp_NewCommand((LPOLEAPP)lpOutlineApp);

#else

   LPOUTLINEDOC lpOutlineDoc = lpOutlineApp->m_lpDoc;

   if (! OutlineDoc_Close(lpOutlineDoc, OLECLOSE_PROMPTSAVE))

      return;

   OleDbgAssertSz(lpOutlineApp->m_lpDoc==NULL,"Closed doc NOT properly destroyed");

   lpOutlineApp->m_lpDoc = OutlineApp_CreateDoc(lpOutlineApp, FALSE);

   if (! lpOutlineApp->m_lpDoc) goto error;

   // set the doc to an (Untitled) doc.

   if (! OutlineDoc_InitNewFile(lpOutlineApp->m_lpDoc))

      goto error;

   // position and size the new doc window

   OutlineApp_ResizeWindows(lpOutlineApp);

   OutlineDoc_ShowWindow(lpOutlineApp->m_lpDoc); // calls OleDoc_Lock

   return;

error:

   // REVIEW: should load string from string resource

   OutlineApp_ErrorMessage(lpOutlineApp, OLESTR("Could not create new document"));

   if (lpOutlineApp->m_lpDoc) {

      OutlineDoc_Destroy(lpOutlineApp->m_lpDoc);

      lpOutlineApp->m_lpDoc = NULL;

   }

   return;

#endif

}

/* OutlineApp_OpenCommand

 * ----------------------

 *

 *  Load a document from file (File.Open command).

 */

void OutlineApp_OpenCommand(LPOUTLINEAPP lpOutlineApp)

{

#if defined( OLE_VERSION )

   // Call OLE version of this function instead

   OleApp_OpenCommand((LPOLEAPP)lpOutlineApp);

#else

   OPENFILENAME ofn;

   char szFilter[]=APPFILENAMEFILTER;

   char szFileName[256];

   OLECHAR szUniFileName[256];

   UINT i;

   DWORD dwSaveOption = OLECLOSE_PROMPTSAVE;

   BOOL fStatus = TRUE;

   if (! OutlineDoc_CheckSaveChanges(lpOutlineApp->m_lpDoc, &dwSaveOption))

      return;           // abort opening new doc

   for(i=0; szFilter[i]; i++)

      if(szFilter[i]=='|') szFilter[i]='\0';

   _fmemset((LPOPENFILENAME)&ofn,0,sizeof(OPENFILENAME));

   szFileName[0]='\0';

   ofn.lStructSize=sizeof(OPENFILENAME);

   ofn.hwndOwner=lpOutlineApp->m_hWndApp;

   ofn.lpstrFilter=(LPSTR)szFilter;

   ofn.lpstrFile=(LPSTR)szFileName;

   ofn.nMaxFile=256;

   ofn.Flags=OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;

   ofn.lpstrDefExt=DEFEXTENSION;

   if(! GetOpenFileName((LPOPENFILENAME)&ofn))

      return;         // user canceled file open dialog

   OutlineDoc_Close(lpOutlineApp->m_lpDoc, OLECLOSE_NOSAVE);

   OleDbgAssertSz(lpOutlineApp->m_lpDoc==NULL,"Closed doc NOT properly destroyed");

   lpOutlineApp->m_lpDoc = OutlineApp_CreateDoc(lpOutlineApp, FALSE);

   if (! lpOutlineApp->m_lpDoc) goto error;

   A2W (szFileName, szUniFileName, 256);

   fStatus=OutlineDoc_LoadFromFile(lpOutlineApp->m_lpDoc, (LPOLESTR)szUniFileName);

   if (! fStatus) {

      // loading the doc failed; create an untitled instead

      OutlineDoc_Destroy(lpOutlineApp->m_lpDoc);  // destroy unused doc

      lpOutlineApp->m_lpDoc = OutlineApp_CreateDoc(lpOutlineApp, FALSE);

      if (! lpOutlineApp->m_lpDoc) goto error;

      if (! OutlineDoc_InitNewFile(lpOutlineApp->m_lpDoc))

         goto error;

   }

   // position and size the new doc window

   OutlineApp_ResizeWindows(lpOutlineApp);

   OutlineDoc_ShowWindow(lpOutlineApp->m_lpDoc);

   return;

error:

   // REVIEW: should load string from string resource

   OutlineApp_ErrorMessage(lpOutlineApp, OLESTR("Could not create new document"));

   if (lpOutlineApp->m_lpDoc) {

      OutlineDoc_Destroy(lpOutlineApp->m_lpDoc);

      lpOutlineApp->m_lpDoc = NULL;

   }

   return;

#endif

}

/* OutlineApp_PrintCommand

 * -----------------------

 *

 *      Print the document

 */

void OutlineApp_PrintCommand(LPOUTLINEAPP lpOutlineApp)

{

   LPOUTLINEDOC    lpOutlineDoc = lpOutlineApp->m_lpDoc;

   HDC             hDC=NULL;

   BOOL            fMustDeleteDC = FALSE;

   BOOL            fStatus;

#if defined( OLE_VERSION )

   OleApp_PreModalDialog(

         (LPOLEAPP)lpOutlineApp, (LPOLEDOC)lpOutlineApp->m_lpDoc);

#endif

   fStatus = PrintDlg((LPPRINTDLG)&lpOutlineApp->m_PrintDlg);

#if defined( OLE_VERSION )

   OleApp_PostModalDialog(

         (LPOLEAPP)lpOutlineApp, (LPOLEDOC)lpOutlineApp->m_lpDoc);

#endif

   if (!fStatus) {

      if (!CommDlgExtendedError()) {      // Cancel button pressed

         return;

      }

   }

   else {

      hDC = OutlineApp_GetPrinterDC(lpOutlineApp);

      if (hDC) {

#if defined( OLE_VERSION )

         /* OLE2NOTE: while we are printing we do NOT want to

         **    receive any OnDataChange notifications or other OLE

         **    interface calls which could disturb the printing of

         **    the document. we will temporarily reply

         **    SERVERCALL_RETRYLATER

         */

         OleApp_RejectInComingCalls((LPOLEAPP)lpOutlineApp, TRUE);

#endif

         OutlineDoc_Print(lpOutlineDoc, hDC);

         DeleteDC(hDC);

#if defined( OLE_VERSION )

         // re-enable LRPC calls

         OleApp_RejectInComingCalls((LPOLEAPP)lpOutlineApp, FALSE);

#endif

         return;                         // Printing completed

      }

   }

   // REVIEW: should load string from string resource

   OutlineApp_ErrorMessage(lpOutlineApp, ErrMsgPrinting);

}

/* OutlineApp_PrinterSetupCommand

 * ------------------------------

 *

 *      Setup a different printer for printing

 */

void OutlineApp_PrinterSetupCommand(LPOUTLINEAPP lpOutlineApp)

{

   DWORD FlagSave;

   FlagSave = lpOutlineApp->m_PrintDlg.Flags;

   lpOutlineApp->m_PrintDlg.Flags |= PD_PRINTSETUP;

#if defined( OLE_VERSION )

   OleApp_PreModalDialog(

         (LPOLEAPP)lpOutlineApp, (LPOLEDOC)lpOutlineApp->m_lpDoc);

#endif

   PrintDlg((LPPRINTDLG)&lpOutlineApp->m_PrintDlg);

#if defined( OLE_VERSION )

   OleApp_PostModalDialog(

         (LPOLEAPP)lpOutlineApp, (LPOLEDOC)lpOutlineApp->m_lpDoc);

#endif

   lpOutlineApp->m_PrintDlg.Flags = FlagSave;

}

/*

 *  FUNCTION   : OutlineApp_GetPrinterDC ()

 *

 *  PURPOSE    : Creates a printer display context for the printer

 *

 *  RETURNS    : HDC   - A handle to printer DC.

 */

HDC OutlineApp_GetPrinterDC(LPOUTLINEAPP lpApp)

{

   HDC         hDC;

   LPDEVMODE   lpDevMode = NULL;

   LPDEVNAMES  lpDevNames;

   LPSTR       lpszDriverName;

   LPSTR       lpszDeviceName;

   LPSTR       lpszPortName;

   if(lpApp->m_PrintDlg.hDC) {

      hDC = lpApp->m_PrintDlg.hDC;

   } else {

      if(! lpApp->m_PrintDlg.hDevNames)

         return(NULL);

      lpDevNames = (LPDEVNAMES)GlobalLock(lpApp->m_PrintDlg.hDevNames);

      lpszDriverName = (LPSTR)lpDevNames + lpDevNames->wDriverOffset;

      lpszDeviceName = (LPSTR)lpDevNames + lpDevNames->wDeviceOffset;

      lpszPortName   = (LPSTR)lpDevNames + lpDevNames->wOutputOffset;

      GlobalUnlock(lpApp->m_PrintDlg.hDevNames);

      if(lpApp->m_PrintDlg.hDevMode)

         lpDevMode = (LPDEVMODE)GlobalLock(lpApp->m_PrintDlg.hDevMode);

#if defined( WIN32 )

      hDC = CreateDC(

            lpszDriverName,

            lpszDeviceName,

            lpszPortName,

            (CONST DEVMODE FAR*)lpDevMode);

#else

      hDC = CreateDC(

            lpszDriverName,

            lpszDeviceName,

            lpszPortName,

            (LPSTR)lpDevMode);

#endif

      if(lpApp->m_PrintDlg.hDevMode && lpDevMode)

         GlobalUnlock(lpApp->m_PrintDlg.hDevMode);

   }

   return(hDC);

}

/* OutlineApp_SaveCommand

 * ----------------------

 *

 *      Save the document with same name. If no name exists, prompt the user

 *      for a name (via SaveAsCommand)

 *

 *  Parameters:

 *

 *  Returns:

 *      TRUE    if succesfully

 *      FALSE   if failed or aborted

 */

BOOL OutlineApp_SaveCommand(LPOUTLINEAPP lpOutlineApp)

{

   LPOUTLINEDOC lpOutlineDoc = OutlineApp_GetActiveDoc(lpOutlineApp);

   if(lpOutlineDoc->m_docInitType == DOCTYPE_NEW)  /* file with no name */

      return OutlineApp_SaveAsCommand(lpOutlineApp);

   if(OutlineDoc_IsModified(lpOutlineDoc)) {

#if defined( OLE_SERVER )

      if (lpOutlineDoc->m_docInitType == DOCTYPE_EMBEDDED) {

         LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOutlineDoc;

         HRESULT hrErr;

         /* OLE2NOTE: if the document is an embedded object, then

         **    the "File.Save" command is changed to "File.Update".

         **    in order to update our container, we must ask our

         **    container to save us.

         */

         OleDbgAssert(lpServerDoc->m_lpOleClientSite != NULL);

         OLEDBG_BEGIN2("IOleClientSite::SaveObject called\r\n")

         hrErr = lpServerDoc->m_lpOleClientSite->lpVtbl->SaveObject(

               lpServerDoc->m_lpOleClientSite

         );

         OLEDBG_END2

         if (hrErr != NOERROR) {

            OleDbgOutHResult("IOleClientSite::SaveObject returned",hrErr);

            return FALSE;

         }

      } else

         // document is file-base user document, save it to its file.

#endif      // OLE_SERVER

      (void)OutlineDoc_SaveToFile(

            lpOutlineDoc,

            NULL,

            lpOutlineDoc->m_cfSaveFormat,

            TRUE

      );

   }

   return TRUE;

}

/* OutlineApp_SaveAsCommand

 * ------------------------

 *

 *      Save the document as another name

 *

 *  Parameters:

 *

 *  Returns:

 *      TRUE    if saved successful

 *      FALSE   if failed or aborted

 */

BOOL OutlineApp_SaveAsCommand(LPOUTLINEAPP lpOutlineApp)

{

   LPOUTLINEDOC lpOutlineDoc = lpOutlineApp->m_lpDoc;

   OPENFILENAME ofn;

   char szFilter[]=APPFILENAMEFILTER;

   char szFileName[256]="";

   OLECHAR szUniFileName[256];

   int i;

   UINT uFormat;

   BOOL fNoError = TRUE;

   BOOL fRemember = TRUE;

   BOOL fStatus;

   for(i=0; szFilter[i]; i++)

      if(szFilter[i]=='|') szFilter[i]='\0';

   _fmemset((LPOPENFILENAME)&ofn,0,sizeof(OPENFILENAME));

   ofn.lStructSize=sizeof(OPENFILENAME);

   ofn.hwndOwner=lpOutlineDoc->m_hWndDoc;

   ofn.lpstrFilter=(LPSTR)szFilter;

   ofn.lpstrFile=(LPSTR)szFileName;

   ofn.nMaxFile=256;

   ofn.Flags=OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY;

   ofn.lpstrDefExt=DEFEXTENSION;

#if defined( OLE_VERSION )

   OleApp_PreModalDialog(

         (LPOLEAPP)lpOutlineApp, (LPOLEDOC)lpOutlineApp->m_lpDoc);

#endif

   fStatus = GetSaveFileName((LPOPENFILENAME)&ofn);

#if defined( OLE_VERSION )

   OleApp_PostModalDialog(

         (LPOLEAPP)lpOutlineApp, (LPOLEDOC)lpOutlineApp->m_lpDoc);

#endif

   if (fStatus) {

#if defined( OLE_CNTR )

      // determine which file type the user selected.

      switch (ofn.nFilterIndex) {

         case 1:

            uFormat = ((LPCONTAINERAPP)lpOutlineApp)->m_cfCntrOutl;

            break;

         case 2:

            uFormat = lpOutlineApp->m_cfOutline;

            break;

         default:

            uFormat = ((LPCONTAINERAPP)lpOutlineApp)->m_cfCntrOutl;

            break;

      }

#else

      uFormat = lpOutlineApp->m_cfOutline;

#endif

#if defined( OLE_SERVER )

      /* OLE2NOTE: if the document is an embedded object, then the

      **    File.SaveAs command is changed to File.SaveCopyAs. with the

      **    Save Copy As operation, the document does NOT remember the

      **    saved file as the associated file for the document.

      */

      if (lpOutlineDoc->m_docInitType == DOCTYPE_EMBEDDED)

         fRemember = FALSE;

#endif

      A2W (szFileName, szUniFileName, 256);

      (void)OutlineDoc_SaveToFile(

            lpOutlineDoc,

            szUniFileName,

            uFormat,

            fRemember

      );

   }

   else

      fNoError = FALSE;

   return fNoError;

}

/* OutlineApp_AboutCommand

 * -----------------------

 *

 *      Show the About dialog box

 */

void OutlineApp_AboutCommand(LPOUTLINEAPP lpOutlineApp)

{

#if defined( OLE_VERSION )

   OleApp_PreModalDialog(

         (LPOLEAPP)lpOutlineApp, (LPOLEDOC)lpOutlineApp->m_lpDoc);

#endif

   DialogBox(

         lpOutlineApp->m_hInst,

         (LPSTR)"About",

         OutlineApp_GetFrameWindow(lpOutlineApp),

         (DLGPROC)AboutDlgProc

   );

#if defined( OLE_VERSION )

   OleApp_PostModalDialog(

         (LPOLEAPP)lpOutlineApp, (LPOLEDOC)lpOutlineApp->m_lpDoc);

#endif

}

/* OutlineApp_CloseAllDocsAndExitCommand

 * -------------------------------------

 *

 *  Close all active documents and exit the app.

 *  Because this is an SDI, there is only one document

 *  If the doc was modified, prompt the user if he wants to save it.

 *

 *  Returns:

 *      TRUE if the app is successfully closed

 *      FALSE if failed or aborted

 */

BOOL OutlineApp_CloseAllDocsAndExitCommand(

      LPOUTLINEAPP        lpOutlineApp,

      BOOL                fForceEndSession

)

{

   BOOL fResult;

   OLEDBG_BEGIN2("OutlineApp_CloseAllDocsAndExitCommand\r\n")

#if defined( OLE_VERSION )

   // Call OLE specific version of this function

   fResult = OleApp_CloseAllDocsAndExitCommand(

         (LPOLEAPP)lpOutlineApp, fForceEndSession);

#else

   /* Because this is an SDI app, there is only one document.

   ** Close the doc. if it is successfully closed and the app will

   ** not automatically exit, then also exit the app.

   ** if this were an MDI app, we would loop through and close all

   ** open MDI child documents.

   */

   if (OutlineDoc_Close(lpOutlineApp->m_lpDoc, OLECLOSE_PROMPTSAVE)) {

#if defined( _DEBUG )

      OleDbgAssertSz(

            lpOutlineApp->m_lpDoc==NULL,

            "Closed doc NOT properly destroyed"

      );

#endif

      OutlineApp_Destroy(lpOutlineApp);

      fResult = TRUE;

   } // else User Canceled shutdown

   else

      fResult = FALSE;

#endif

   OLEDBG_END2

   return fResult;

}

/* OutlineApp_Destroy

 * ------------------

 *

 *      Destroy all data structures used by the app and force the

 * app to shut down. This should be called after all documents have

 * been closed.

 */

void OutlineApp_Destroy(LPOUTLINEAPP lpOutlineApp)

{

   OLEDBG_BEGIN3("OutlineApp_Destroy\r\n");

#if defined( OLE_VERSION )

   /* OLE2NOTE: perform processing required for OLE */

   OleApp_Destroy((LPOLEAPP)lpOutlineApp);

#endif

   SetCursor(LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW)));

   DestroyCursor(lpOutlineApp->m_hcursorSelCur);

#if defined( USE_FRAMETOOLS )

   FrameTools_Destroy(&lpOutlineApp->m_frametools);

#endif

   if (lpOutlineApp->m_hStdFont)

      DeleteObject(lpOutlineApp->m_hStdFont);

   if(lpOutlineApp->m_PrintDlg.hDevMode)

      GlobalFree(lpOutlineApp->m_PrintDlg.hDevMode);

   if(lpOutlineApp->m_PrintDlg.hDevNames)

      GlobalFree(lpOutlineApp->m_PrintDlg.hDevNames);

#if defined( USE_STATUSBAR )

   if(lpOutlineApp->m_hWndStatusBar) {

      DestroyStatusWindow(lpOutlineApp->m_hWndStatusBar);

      lpOutlineApp->m_hWndStatusBar = NULL;

   }

#endif

   OutlineApp_DestroyWindow(lpOutlineApp);

   OleDbgOut1("@@@@ APP DESTROYED\r\n");

   OLEDBG_END3

}

/* OutlineApp_DestroyWindow

 * ------------------------

 *

 *  Destroy all windows created by the App.

 */

void OutlineApp_DestroyWindow(LPOUTLINEAPP lpOutlineApp)

{

   HWND hWndApp = lpOutlineApp->m_hWndApp;

   if(hWndApp) {

      lpOutlineApp->m_hWndApp = NULL;

      lpOutlineApp->m_hWndAccelTarget = NULL;

      DestroyWindow(hWndApp);  /* Quit the app */

   }

}

/* OutlineApp_GetFrameRect

** -----------------------

**    Get the rectangle of the app frame window EXCLUDING space for the

**    status line.

**

**    OLE2NOTE: this is the rectangle that an in-place container can

**    offer to an in-place active object from which to get frame tool

**    space.

*/

void OutlineApp_GetFrameRect(LPOUTLINEAPP lpOutlineApp, LPRECT lprcFrameRect)

{

   GetClientRect(lpOutlineApp->m_hWndApp, lprcFrameRect);

#if defined( USE_STATUSBAR )

   lprcFrameRect->bottom -= STATUS_HEIGHT;

#endif

}

/* OutlineApp_GetClientAreaRect

** ----------------------------

**    Get the rectangle of the app frame window EXCLUDING space for the

**    status line AND EXCLUDING space for any frame-level tools.

**

**    OLE2NOTE: this is the rectangle that an in-place container gives

**    to its in-place active object as the lpClipRect in

**    IOleInPlaceSite::GetWindowContext.

*/

void OutlineApp_GetClientAreaRect(

      LPOUTLINEAPP        lpOutlineApp,

      LPRECT              lprcClientAreaRect

)

{

   OutlineApp_GetFrameRect(lpOutlineApp, lprcClientAreaRect);

   /* if the app either uses frame-level tools itself or, as in-place

   **    container, is prepared to allow an in-place active object to

   **    have space for tools, then it must subtract away the space

   **    required for the tools.

   */

#if defined ( USE_FRAMETOOLS ) || defined ( INPLACE_CNTR )

   lprcClientAreaRect->top    += lpOutlineApp->m_FrameToolWidths.top;

   lprcClientAreaRect->left   += lpOutlineApp->m_FrameToolWidths.left;

   lprcClientAreaRect->right  -= lpOutlineApp->m_FrameToolWidths.right;

   lprcClientAreaRect->bottom -= lpOutlineApp->m_FrameToolWidths.bottom;

#endif  // USE_FRAMETOOLS || INPLACE_CNTR

}

/* OutlineApp_GetStatusLineRect

** ----------------------------

**    Get the rectangle required for the status line.

**

**    OLE2NOTE: the top frame-level in-place container displays its

**    status line even when an object is active in-place.

*/

void OutlineApp_GetStatusLineRect(

      LPOUTLINEAPP        lpOutlineApp,

      LPRECT              lprcStatusLineRect

)

{

   RECT rcFrameRect;

   GetClientRect(lpOutlineApp->m_hWndApp, (LPRECT)&rcFrameRect);

   lprcStatusLineRect->left    = rcFrameRect.left;

   lprcStatusLineRect->top     = rcFrameRect.bottom - STATUS_HEIGHT;

   lprcStatusLineRect->right   = rcFrameRect.right;

   lprcStatusLineRect->bottom  = rcFrameRect.bottom;

}

/* OutlineApp_ResizeWindows

 * ------------------------

 *

 * Changes the size and position of the SDI document and tool windows.

 * Normally called on a WM_SIZE message.

 *

 * Currently the app supports a status bar and a single SDI document window.

 * In the future it will have a formula bar and possibly multiple MDI

 * document windows.

 *

 * CUSTOMIZATION: Change positions of windows.

 */

void OutlineApp_ResizeWindows(LPOUTLINEAPP lpOutlineApp)

{

   LPOUTLINEDOC lpOutlineDoc = OutlineApp_GetActiveDoc(lpOutlineApp);

   RECT rcStatusLineRect;

   if (! lpOutlineApp)

      return;

#if defined( INPLACE_CNTR )

   if (lpOutlineDoc)

      ContainerDoc_FrameWindowResized((LPCONTAINERDOC)lpOutlineDoc);

#else

#if defined( USE_FRAMETOOLS )

   if (lpOutlineDoc)

      OutlineDoc_AddFrameLevelTools(lpOutlineDoc);

#else

   OutlineApp_ResizeClientArea(lpOutlineApp);

#endif  // ! USE_FRAMETOOLS

#endif  // ! INPLACE_CNTR

#if defined( USE_STATUSBAR )

   if (lpOutlineApp->m_hWndStatusBar) {

      OutlineApp_GetStatusLineRect(lpOutlineApp, (LPRECT)&rcStatusLineRect);

      MoveWindow(

            lpOutlineApp->m_hWndStatusBar,

            rcStatusLineRect.left,

            rcStatusLineRect.top,

            rcStatusLineRect.right - rcStatusLineRect.left,

            rcStatusLineRect.bottom - rcStatusLineRect.top,

            TRUE    /* fRepaint */

         );

   }

#endif  // USE_STATUSBAR

}

#if defined( USE_FRAMETOOLS ) || defined( INPLACE_CNTR )

void OutlineApp_SetBorderSpace(

      LPOUTLINEAPP        lpOutlineApp,

      LPBORDERWIDTHS      lpBorderWidths

)

{

   lpOutlineApp->m_FrameToolWidths = *lpBorderWidths;

   OutlineApp_ResizeClientArea(lpOutlineApp);

}

#endif  // USE_FRAMETOOLS || INPLACE_CNTR

void OutlineApp_ResizeClientArea(LPOUTLINEAPP lpOutlineApp)

{

   RECT rcClientAreaRect;

#if defined( MDI_VERSION )

   // Resize MDI Client Area Window here

#else

   if (lpOutlineApp->m_lpDoc) {

         OutlineApp_GetClientAreaRect(

               lpOutlineApp, (LPRECT)&rcClientAreaRect);

         OutlineDoc_Resize(lpOutlineApp->m_lpDoc,

               (LPRECT)&rcClientAreaRect);

   }

#endif

}

/* OutlineApp_GetActiveDoc

 * -----------------------

 *

 * Return the document in focus. For SDI, the same (only one) document is

 * always returned.

 */

LPOUTLINEDOC OutlineApp_GetActiveDoc(LPOUTLINEAPP lpOutlineApp)

{

   return lpOutlineApp->m_lpDoc;

}

/* OutlineApp_GetMenu

 * ------------------

 *

 * Return the menu handle of the app

 */

HMENU OutlineApp_GetMenu(LPOUTLINEAPP lpOutlineApp)

{

   if (!lpOutlineApp) {

      return NULL;

   }

   return lpOutlineApp->m_hMenuApp;

}

#if defined( USE_FRAMETOOLS )

/* OutlineApp_GetFrameTools

 * ---------------------

 *

 * Return the pointer to the toolbar object

 */

LPFRAMETOOLS OutlineApp_GetFrameTools(LPOUTLINEAPP lpOutlineApp)

{

   return (LPFRAMETOOLS)&lpOutlineApp->m_frametools;

}

#endif

/* OutlineApp_SetStatusText

 * ------------------------

 *

 * Show the given string in the status line

 */

void OutlineApp_SetStatusText(LPOUTLINEAPP lpOutlineApp, LPOLESTR lpszMessage)

{

   char szAnsiMessage[256];

   W2A (lpszMessage, szAnsiMessage, 256);

   SetStatusText(lpOutlineApp->m_hWndStatusBar, szAnsiMessage);

}

/* OutlineApp_GetActiveFont

 * ------------------------

 *

 *      Return the font used by the application

 */

HFONT OutlineApp_GetActiveFont(LPOUTLINEAPP lpOutlineApp)

{

   return lpOutlineApp->m_hStdFont;

}

/* OutlineApp_GetAppName

 * ---------------------

 *

 *      Retrieve the application name

 */

void OutlineApp_GetAppName(LPOUTLINEAPP lpOutlineApp, LPOLESTR lpszAppName)

{

   OLESTRCPY (lpszAppName, APPNAME);

}

/* OutlineApp_GetAppVersionNo

 * --------------------------

 *

 *      Get the version number (major and minor) of the application

 */

void OutlineApp_GetAppVersionNo(LPOUTLINEAPP lpOutlineApp, int narrAppVersionNo[])

{

   narrAppVersionNo[0] = APPMAJORVERSIONNO;

   narrAppVersionNo[1] = APPMINORVERSIONNO;

}

/* OutlineApp_VersionNoCheck

 * -------------------------

 *

 *      Check if the version stamp read from a file is compatible

 *      with the current instance of the application.

 *      returns TRUE if the file can be read, else FALSE.

 */

BOOL OutlineApp_VersionNoCheck(LPOUTLINEAPP lpOutlineApp, LPOLESTR lpszFormatName, int narrAppVersionNo[])

{

#if defined( OLE_CNTR )

   /* ContainerApp accepts both CF_OUTLINE and CF_CONTAINEROUTLINE formats */

   if (OLESTRCMP(lpszFormatName, CONTAINERDOCFORMAT) != 0 &&

      OLESTRCMP(lpszFormatName, OUTLINEDOCFORMAT) != 0) {

      // REVIEW: should load string from string resource

      OutlineApp_ErrorMessage(

            lpOutlineApp,

            OLESTR("File is either corrupted or not of proper type.")

         );

      return FALSE;

   }

#else

   /* OutlineApp accepts CF_OUTLINE format only */

   if (OLESTRCMP(lpszFormatName, OUTLINEDOCFORMAT) != 0) {

      // REVIEW: should load string from string resource

      OutlineApp_ErrorMessage(

            lpOutlineApp,

            OLESTR("File is either corrupted or not of proper type.")

         );

      return FALSE;

   }

#endif

   if (narrAppVersionNo[0] < APPMAJORVERSIONNO) {

      // REVIEW: should load string from string resource

      OutlineApp_ErrorMessage(

            lpOutlineApp,

            OLESTR("File was created by an older version; it can not be read.")

         );

      return FALSE;

   }

   return TRUE;

}

/* OutlineApp_ErrorMessage

 * -----------------------

 *

 *      Display an error message box

 */

void OutlineApp_ErrorMessage(LPOUTLINEAPP lpOutlineApp, LPOLESTR lpszErrMsg)

{

   HWND hWndFrame = OutlineApp_GetFrameWindow(lpOutlineApp);

   char   szAnsiErrMsg[256];

   // OLE2NOTE: only put up user message boxes if app is visible

   if (IsWindowVisible(hWndFrame)) {

#if defined( OLE_VERSION )

      OleApp_PreModalDialog(

            (LPOLEAPP)lpOutlineApp, (LPOLEDOC)lpOutlineApp->m_lpDoc);

#endif

      W2A (lpszErrMsg, szAnsiErrMsg, 256);

      MessageBox(hWndFrame, szAnsiErrMsg, NULL, MB_ICONEXCLAMATION | MB_OK);

#if defined( OLE_VERSION )

      OleApp_PostModalDialog(

            (LPOLEAPP)lpOutlineApp, (LPOLEDOC)lpOutlineApp->m_lpDoc);

#endif

   }

}

#if defined( USE_FRAMETOOLS )

/* OutlineApp_SetFormulaBarAccel

 * -----------------------------

 *

 *  Set accelerator table based on state of formula bar.

 */

void OutlineApp_SetFormulaBarAccel(

      LPOUTLINEAPP            lpOutlineApp,

      BOOL                    fEditFocus

)

{

   if (fEditFocus)

      lpOutlineApp->m_hAccel = lpOutlineApp->m_hAccelFocusEdit;

   else

      lpOutlineApp->m_hAccel = lpOutlineApp->m_hAccelApp;

}

#endif  // USE_FRAMETOOLS

/* OutlineApp_ForceRedraw

 * ----------------------

 *

 *      Force the Application window to repaint.

 */

void OutlineApp_ForceRedraw(LPOUTLINEAPP lpOutlineApp, BOOL fErase)

{

   if (!lpOutlineApp)

      return;

   InvalidateRect(lpOutlineApp->m_hWndApp, NULL, fErase);

}


OUTLDOC.C  (OUTLINE Sample)

/*************************************************************************

**

**    OLE 2 Sample Code

**

**    outldoc.c

**

**    This file contains OutlineDoc functions.

**

**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

**

*************************************************************************/

#include "outline.h"

#if !defined( OLE_VERSION )

#include <commdlg.h>

#endif

OLEDBGDATA

extern LPOUTLINEAPP g_lpApp;

#ifdef WIN32S

#define GALLOCFLG (GMEM_SHARE | GMEM_ZEROINIT | GMEM_MOVEABLE)

#else

#define GALLOCFLG (GMEM_SHARE | GMEM_ZEROINIT)

#endif

// REVIEW: should use string resource for messages

OLECHAR ErrMsgDocWnd[] = OLESTR("Can't create Document Window!");

OLECHAR ErrMsgFormatNotSupported[] = OLESTR("Clipboard format not supported!");

OLECHAR MsgSaveFile[] = OLESTR("Save existing file ?");

OLECHAR ErrMsgSaving[] = OLESTR("Error in saving file!");

OLECHAR ErrMsgOpening[] = OLESTR("Error in opening file!");

OLECHAR ErrMsgFormat[] = OLESTR("Improper file format!");

OLECHAR ErrOutOfMemory[] = OLESTR("Error: out of memory!");

static OLECHAR ErrMsgPrint[] = OLESTR("Printing Error!");

static BOOL fCancelPrint;    // TRUE if the user has canceled the print job

static HWND hWndPDlg;       // Handle to the cancel print dialog

/* OutlineDoc_Init

 * ---------------

 *

 *  Initialize the fields of a new OutlineDoc object. The object is initially

 *  not associated with a file or an (Untitled) document. This function sets

 *  the docInitType to DOCTYPE_UNKNOWN. After calling this function the

 *  caller should call:

 *      1. OutlineDoc_InitNewFile to set the OutlineDoc to (Untitled)

 *      2. OutlineDoc_LoadFromFile to associate the OutlineDoc with a file.

 *  This function creates a new window for the document.

 *

 *  NOTE: the window is initially created with a NIL size. it must be

 *        sized and positioned by the caller. also the document is initially

 *        created invisible. the caller must call OutlineDoc_ShowWindow

 *        after sizing it to make the document window visible.

 */

BOOL OutlineDoc_Init(LPOUTLINEDOC lpOutlineDoc, BOOL fDataTransferDoc)

{

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

#if defined( INPLACE_CNTR )

   lpOutlineDoc->m_hWndDoc = CreateWindow(

               DOCWNDCLASS,            // Window class name

               NULL,                   // Window's title

               /* OLE2NOTE: an in-place contanier MUST use

               **    WS_CLIPCHILDREN window style for the window

               **    that it uses as the parent for the server's

               **    in-place active window so that its

               **    painting does NOT interfere with the painting

               **    of the server's in-place active child window.

               */

               WS_CLIPCHILDREN | WS_CLIPSIBLINGS |

               WS_CHILDWINDOW,

               0, 0,

               0, 0,

               lpOutlineApp->m_hWndApp,// Parent window's handle

               (HMENU)1,               // child window id

               lpOutlineApp->m_hInst,  // Instance of window

               NULL);                  // Create struct for WM_CREATE

#else

   lpOutlineDoc->m_hWndDoc = CreateWindow(

               DOCWNDCLASS,            // Window class name

               NULL,                   // Window's title

               WS_CHILDWINDOW,

               0, 0,

               0, 0,

               lpOutlineApp->m_hWndApp,// Parent window's handle

               (HMENU)1,               // child window id

               lpOutlineApp->m_hInst,  // Instance of window

               NULL);                  // Create struct for WM_CREATE

#endif

   if(! lpOutlineDoc->m_hWndDoc) {

      OutlineApp_ErrorMessage(lpOutlineApp, ErrMsgDocWnd);

      return FALSE;

   }

   SetWindowLong(lpOutlineDoc->m_hWndDoc, 0, (LONG) lpOutlineDoc);

   if (! LineList_Init(&lpOutlineDoc->m_LineList, lpOutlineDoc))

      return FALSE;

   lpOutlineDoc->m_lpNameTable = OutlineDoc_CreateNameTable(lpOutlineDoc);

   if (! lpOutlineDoc->m_lpNameTable )

      return FALSE;

   lpOutlineDoc->m_docInitType = DOCTYPE_UNKNOWN;

   lpOutlineDoc->m_cfSaveFormat = lpOutlineApp->m_cfOutline;

   lpOutlineDoc->m_szFileName[0] = '\0';

   lpOutlineDoc->m_lpszDocTitle = lpOutlineDoc->m_szFileName;

   lpOutlineDoc->m_fDataTransferDoc = fDataTransferDoc;

   lpOutlineDoc->m_uCurrentZoom = IDM_V_ZOOM_100;

   lpOutlineDoc->m_scale.dwSxN  = (DWORD) 1;

   lpOutlineDoc->m_scale.dwSxD  = (DWORD) 1;

   lpOutlineDoc->m_scale.dwSyN  = (DWORD) 1;

   lpOutlineDoc->m_scale.dwSyD  = (DWORD) 1;

   lpOutlineDoc->m_uCurrentMargin = IDM_V_SETMARGIN_0;

   lpOutlineDoc->m_nLeftMargin  = 0;

   lpOutlineDoc->m_nRightMargin = 0;

   lpOutlineDoc->m_nDisableDraw = 0;

   OutlineDoc_SetModified(lpOutlineDoc, FALSE, FALSE, FALSE);

#if defined( USE_HEADING )

   if (! fDataTransferDoc) {

      if (!Heading_Create((LPHEADING)&lpOutlineDoc->m_heading,

            lpOutlineDoc->m_hWndDoc, lpOutlineApp->m_hInst)) {

         return FALSE;

      }

   }

#endif  // USE_HEADING

#if defined( USE_FRAMETOOLS )

   if (! fDataTransferDoc) {

      lpOutlineDoc->m_lpFrameTools = OutlineApp_GetFrameTools(lpOutlineApp);

      FrameTools_AssociateDoc(

            lpOutlineDoc->m_lpFrameTools,

            lpOutlineDoc

      );

   }

#endif  // USE_FRAMETOOLS

#if defined( OLE_VERSION )

   /* OLE2NOTE: perform initialization required for OLE */

   if (! OleDoc_Init((LPOLEDOC)lpOutlineDoc, fDataTransferDoc))

      return FALSE;

#endif  // OLE_VERSION

   return TRUE;

}

/* OutlineDoc_InitNewFile

 * ----------------------

 *

 *  Initialize the OutlineDoc object to be a new (Untitled) document.

 *  This function sets the docInitType to DOCTYPE_NEW.

 */

BOOL OutlineDoc_InitNewFile(LPOUTLINEDOC lpOutlineDoc)

{

#if defined( OLE_VERSION )

   // OLE2NOTE: call OLE version of this function instead

   return OleDoc_InitNewFile((LPOLEDOC)lpOutlineDoc);

#else

   OleDbgAssert(lpOutlineDoc->m_docInitType == DOCTYPE_UNKNOWN);

   // set file name to untitled

   // REVIEW: should load from string resource

   lstrcpyW(lpOutlineDoc->m_szFileName, UNTITLED);

   lpOutlineDoc->m_lpszDocTitle = lpOutlineDoc->m_szFileName;

   lpOutlineDoc->m_docInitType = DOCTYPE_NEW;

   if (! lpOutlineDoc->m_fDataTransferDoc)

      OutlineDoc_SetTitle(lpOutlineDoc, FALSE /*fMakeUpperCase*/);

   return TRUE;

#endif      // BASE OUTLINE VERSION

}

/* OutlineDoc_CreateNameTable

 * --------------------------

 *

 * Allocate a new NameTable of the appropriate type. Each document has

 * a NameTable and a LineList.

 *  OutlineDoc --> creates standard OutlineNameTable type name tables.

 *  ServerDoc  --> creates enhanced SeverNameTable type name tables.

 *

 *      Returns lpNameTable for successful, NULL if error.

 */

LPOUTLINENAMETABLE OutlineDoc_CreateNameTable(LPOUTLINEDOC lpOutlineDoc)

{

   LPOUTLINENAMETABLE lpOutlineNameTable;

   lpOutlineNameTable = (LPOUTLINENAMETABLE)New(

         (DWORD)sizeof(OUTLINENAMETABLE)

   );

   OleDbgAssertSz(lpOutlineNameTable != NULL,"Error allocating NameTable");

   if (lpOutlineNameTable == NULL)

      return NULL;

   // initialize new NameTable

   if (! OutlineNameTable_Init(lpOutlineNameTable, lpOutlineDoc) )

      goto error;

   return lpOutlineNameTable;

error:

   if (lpOutlineNameTable)

      Delete(lpOutlineNameTable);

   return NULL;

}

/* OutlineDoc_ClearCommand

 * -----------------------

 *

 *      Delete selection in list box by calling OutlineDoc_Delete

 */

void OutlineDoc_ClearCommand(LPOUTLINEDOC lpOutlineDoc)

{

   LPLINELIST lpLL = &lpOutlineDoc->m_LineList;

   int i;

   int nNumSel;

   LINERANGE lrSel;

   nNumSel=LineList_GetSel(lpLL, (LPLINERANGE)&lrSel);

   OutlineDoc_SetRedraw ( lpOutlineDoc, FALSE );

   for(i = 0; i < nNumSel; i++)

      OutlineDoc_DeleteLine(lpOutlineDoc, lrSel.m_nStartLine);

   OutlineDoc_SetRedraw ( lpOutlineDoc, TRUE );

   LineList_RecalcMaxLineWidthInHimetric(lpLL, 0);

}

/* OutlineDoc_CutCommand

 * ---------------------

 *

 * Cut selection to clipboard

 */

void OutlineDoc_CutCommand(LPOUTLINEDOC lpOutlineDoc)

{

   OutlineDoc_CopyCommand(lpOutlineDoc);

   OutlineDoc_ClearCommand(lpOutlineDoc);

}

/* OutlineDoc_CopyCommand

 * ----------------------

 *  Copy selection to clipboard.

 *  Post to the clipboard the formats that the app can render.

 *  the actual data is not rendered at this time. using the

 *  delayed rendering technique, Windows will send the clipboard

 *  owner window either a WM_RENDERALLFORMATS or a WM_RENDERFORMAT

 *  message when the actual data is requested.

 *

 *    OLE2NOTE: the normal delayed rendering technique where Windows

 *    sends the clipboard owner window either a WM_RENDERALLFORMATS or

 *    a WM_RENDERFORMAT message when the actual data is requested is

 *    NOT exposed to the app calling OleSetClipboard. OLE internally

 *    creates its own window as the clipboard owner and thus our app

 *    will NOT get these WM_RENDER messages.

 */

void OutlineDoc_CopyCommand(LPOUTLINEDOC lpSrcOutlineDoc)

{

#if defined( OLE_VERSION )

   // Call OLE version of this function instead

   OleDoc_CopyCommand((LPOLEDOC)lpSrcOutlineDoc);

#else

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   LPOUTLINEDOC lpClipboardDoc;

   OpenClipboard(lpSrcOutlineDoc->m_hWndDoc);

   EmptyClipboard();

   /* squirrel away a copy of the current selection to the ClipboardDoc */

   lpClipboardDoc = OutlineDoc_CreateDataTransferDoc(lpSrcOutlineDoc);

   if (! lpClipboardDoc)

      return;     // Error: could not create DataTransferDoc

   lpOutlineApp->m_lpClipboardDoc = (LPOUTLINEDOC)lpClipboardDoc;

   SetClipboardData(lpOutlineApp->m_cfOutline, NULL);

   SetClipboardData(CF_TEXT, NULL);

   CloseClipboard();

#endif  // ! OLE_VERSION

}

/* OutlineDoc_ClearAllLines

 * ------------------------

 *

 *      Delete all lines in the document.

 */

void OutlineDoc_ClearAllLines(LPOUTLINEDOC lpOutlineDoc)

{

   LPLINELIST lpLL = &lpOutlineDoc->m_LineList;

   int i;

   for(i = 0; i < lpLL->m_nNumLines; i++)

      OutlineDoc_DeleteLine(lpOutlineDoc, 0);

   LineList_RecalcMaxLineWidthInHimetric(lpLL, 0);

}

/* OutlineDoc_CreateDataTransferDoc

 * --------------------------------

 *

 *      Create a document to be use to transfer data (either via a

 *  drag/drop operation of the clipboard). Copy the selection of the

 *  source doc to the data transfer document. A data transfer document is

 *  the same as a document that is created by the user except that it is

 *  NOT made visible to the user. it is specially used to hold a copy of

 *  data that the user should not be able to change.

 *

 *  OLE2NOTE: in the OLE version the data transfer document is used

 *      specifically to provide an IDataObject* that renders the data copied.

 */

LPOUTLINEDOC OutlineDoc_CreateDataTransferDoc(LPOUTLINEDOC lpSrcOutlineDoc)

{

#if defined( OLE_VERSION )

   // Call OLE version of this function instead

   return OleDoc_CreateDataTransferDoc((LPOLEDOC)lpSrcOutlineDoc);

#else

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   LPOUTLINEDOC lpDestOutlineDoc;

   LPLINELIST lpSrcLL = &lpSrcOutlineDoc->m_LineList;

   LINERANGE lrSel;

   int nCopied;

   lpDestOutlineDoc = OutlineApp_CreateDoc(lpOutlineApp, TRUE);

   if (! lpDestOutlineDoc) return NULL;

   // set the ClipboardDoc to an (Untitled) doc.

   if (! OutlineDoc_InitNewFile(lpDestOutlineDoc))

      goto error;

   LineList_GetSel(lpSrcLL, (LPLINERANGE)&lrSel);

   nCopied = LineList_CopySelToDoc(

         lpSrcLL,

         (LPLINERANGE)&lrSel,

         lpDestOutlineDoc

   );

   return lpDestOutlineDoc;

error:

   if (lpDestOutlineDoc)

      OutlineDoc_Destroy(lpDestOutlineDoc);

   return NULL;

#endif  // ! OLE_VERSION

}

/* OutlineDoc_PasteCommand

 * -----------------------

 *

 * Paste lines from clipboard

 */

void OutlineDoc_PasteCommand(LPOUTLINEDOC lpOutlineDoc)

{

#if defined( OLE_VERSION )

   // Call OLE version of this function instead

   OleDoc_PasteCommand((LPOLEDOC)lpOutlineDoc);

#else

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   LPLINELIST lpLL = (LPLINELIST)&lpOutlineDoc->m_LineList;

   int nIndex;

   int nCount;

   HGLOBAL hData;

   LINERANGE lrSel;

   UINT uFormat;

   if (LineList_GetCount(lpLL) == 0)

      nIndex = -1;    // pasting to empty list

   else

      nIndex=LineList_GetFocusLineIndex(lpLL);

   OutlineDoc_SetRedraw ( lpOutlineDoc, FALSE );

   OpenClipboard(lpOutlineDoc->m_hWndDoc);

   uFormat = 0;

   while(uFormat = EnumClipboardFormats(uFormat)) {

      if(uFormat == lpOutlineApp->m_cfOutline) {

         hData = GetClipboardData(lpOutlineApp->m_cfOutline);

         nCount = OutlineDoc_PasteOutlineData(lpOutlineDoc, hData, nIndex);

         break;

      }

      if(uFormat == CF_TEXT) {

         hData = GetClipboardData(CF_TEXT);

         nCount = OutlineDoc_PasteTextData(lpOutlineDoc, hData, nIndex);

         break;

      }

   }

   lrSel.m_nStartLine = nIndex + nCount;

   lrSel.m_nEndLine = nIndex + 1;

   LineList_SetSel(lpLL, &lrSel);

   OutlineDoc_SetRedraw ( lpOutlineDoc, TRUE );

   CloseClipboard();

#endif      // ! OLE_VERSION

}

/* OutlineDoc_PasteOutlineData

 * ---------------------------

 *

 *      Put an array of Line Objects (stored in hOutline) into the document

 *

 * Return the number of items added

 */

int OutlineDoc_PasteOutlineData(LPOUTLINEDOC lpOutlineDoc, HGLOBAL hOutline, int nStartIndex)

{

   int nCount;

   int i;

   LPTEXTLINE arrLine;

   nCount = (int) GlobalSize(hOutline) / sizeof(TEXTLINE);

   arrLine = (LPTEXTLINE)GlobalLock(hOutline);

   if (!arrLine)

      return 0;

   for(i = 0; i < nCount; i++)

      Line_CopyToDoc((LPLINE)&arrLine[i], lpOutlineDoc, nStartIndex+i);

   GlobalUnlock(hOutline);

   return nCount;

}

/* OutlineDoc_PasteTextData

 * ------------------------

 *

 *      Build Line Objects from the strings (separated by '\n') in hText

 * and put them into the document

 */

int OutlineDoc_PasteTextData(LPOUTLINEDOC lpOutlineDoc, HGLOBAL hText, int nStartIndex)

{

   LPLINELIST  lpLL = (LPLINELIST)&lpOutlineDoc->m_LineList;

   HDC         hDC;

   LPSTR       lpszText;

   LPSTR       lpszEnd;

   LPTEXTLINE  lpLine;

   int         nLineCount;

   int         i;

   UINT        nTab;

   char        szBuf[MAXSTRLEN+1];

   lpszText=(LPSTR)GlobalLock(hText);

   if(!lpszText)

      return 0;

   lpszEnd = lpszText + lstrlen(lpszText);

   nLineCount=0;

   while(*lpszText && (lpszText<lpszEnd)) {

      // count the tab level

      nTab = 0;

      while((*lpszText == '\t') && (lpszText<lpszEnd)) {

         nTab++;

         lpszText++;

      }

      // collect the text string character by character

      for(i=0; (i<MAXSTRLEN) && (lpszText<lpszEnd); i++) {

         if ((! *lpszText) || (*lpszText == '\n'))

            break;

         szBuf[i] = *lpszText++;

      }

      szBuf[i] = 0;

      lpszText++;

      if ((i > 0) && (szBuf[i-1] == '\r'))

         szBuf[i-1] = 0;     // remove carriage return at the end

      hDC = LineList_GetDC(lpLL);

      lpLine = TextLine_Create(hDC, nTab, szBuf);

      LineList_ReleaseDC(lpLL, hDC);

      OutlineDoc_AddLine(

            lpOutlineDoc,

            (LPLINE)lpLine,

            nStartIndex + nLineCount

      );

      nLineCount++;

   }

   GlobalUnlock(hText);

   return nLineCount;

}

/* OutlineDoc_AddTextLineCommand

 * -----------------------------

 *

 *      Add a new text line following the current focus line.

 */

void OutlineDoc_AddTextLineCommand(LPOUTLINEDOC lpOutlineDoc)

{

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   LPLINELIST lpLL = &lpOutlineDoc->m_LineList;

   HDC hDC;

   int nIndex = LineList_GetFocusLineIndex(lpLL);

   char szBuf[MAXSTRLEN+1];

   UINT nTab = 0;

   LPLINE lpLine;

   LPTEXTLINE lpTextLine;

   szBuf[0] = '\0';

#if defined( USE_FRAMETOOLS )

   FrameTools_FB_GetEditText(

         lpOutlineDoc->m_lpFrameTools, szBuf, MAXSTRLEN+1);

#else

   if (! InputTextDlg(lpOutlineDoc->m_hWndDoc, szBuf, "Add Line"))

      return;

#endif

   hDC = LineList_GetDC(lpLL);

   lpLine = LineList_GetLine(lpLL, nIndex);

   if (lpLine)

      nTab = Line_GetTabLevel(lpLine);

   lpTextLine=TextLine_Create(hDC, nTab, szBuf);

   LineList_ReleaseDC(lpLL, hDC);

   if (! lpTextLine) {

      OutlineApp_ErrorMessage(lpOutlineApp, ErrOutOfMemory);

      return;

   }

   OutlineDoc_AddLine(lpOutlineDoc, (LPLINE)lpTextLine, nIndex);

}

/* OutlineDoc_AddTopLineCommand

 * ----------------------------

 *

 *      Add a top (margin) line as the first line in the LineList.

 *      (do not change the current selection)

 */

void OutlineDoc_AddTopLineCommand(

      LPOUTLINEDOC        lpOutlineDoc,

      UINT                nHeightInHimetric

)

{

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   LPLINELIST  lpLL = &lpOutlineDoc->m_LineList;

   HDC         hDC = LineList_GetDC(lpLL);

   LPTEXTLINE  lpTextLine = TextLine_Create(hDC, 0, NULL);

   LPLINE      lpLine = (LPLINE)lpTextLine;

   LINERANGE   lrSel;

   int         nNumSel;

   LineList_ReleaseDC(lpLL, hDC);

   if (! lpTextLine) {

      OutlineApp_ErrorMessage(lpOutlineApp, ErrOutOfMemory);

      return;

   }

   Line_SetHeightInHimetric(lpLine, nHeightInHimetric);

   nNumSel=LineList_GetSel(lpLL, (LPLINERANGE)&lrSel);

   if (nNumSel > 0) {

      // adjust current selection to keep equivalent selection

      lrSel.m_nStartLine += 1;

      lrSel.m_nEndLine += 1;

   }

   OutlineDoc_AddLine(lpOutlineDoc, lpLine, -1);

   if (nNumSel > 0)

      LineList_SetSel(lpLL, (LPLINERANGE)&lrSel);

}

#if defined( USE_FRAMETOOLS )

/* OutlineDoc_SetFormulaBarEditText

 * --------------------------------

 *

 *      Fill the edit control in the formula with the text string from a

 * TextLine in focus.

 */

void OutlineDoc_SetFormulaBarEditText(

      LPOUTLINEDOC            lpOutlineDoc,

      LPLINE                  lpLine

)

{

   LPLINELIST lpLL = &lpOutlineDoc->m_LineList;

   char cBuf[MAXSTRLEN+1];

   if (! lpOutlineDoc || ! lpOutlineDoc->m_lpFrameTools)

      return;

   if (Line_GetLineType(lpLine) != TEXTLINETYPE) {

      FrameTools_FB_SetEditText(lpOutlineDoc->m_lpFrameTools, NULL);

   } else {

      TextLine_GetTextData((LPTEXTLINE)lpLine, (LPSTR)cBuf);

      FrameTools_FB_SetEditText(lpOutlineDoc->m_lpFrameTools, (LPSTR)cBuf);

   }

}

/* OutlineDoc_SetFormulaBarEditFocus

 * ---------------------------------

 *

 *  Setup for formula bar to gain or loose edit focus.

 *  if gaining focus, setup up special accelerator table and scroll line

 *      into view.

 *  else restore normal accelerator table.

 */

void OutlineDoc_SetFormulaBarEditFocus(

      LPOUTLINEDOC            lpOutlineDoc,

      BOOL                    fEditFocus

)

{

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   LPLINELIST lpLL;

   int nFocusIndex;

   if (! lpOutlineDoc || ! lpOutlineDoc->m_lpFrameTools)

      return;

   lpOutlineDoc->m_lpFrameTools->m_fInFormulaBar = fEditFocus;

   if (fEditFocus && lpOutlineDoc->m_lpFrameTools) {

      lpLL = OutlineDoc_GetLineList(lpOutlineDoc);

      nFocusIndex = LineList_GetFocusLineIndex(lpLL);

      LineList_ScrollLineIntoView(lpLL, nFocusIndex);

      FrameTools_FB_FocusEdit(lpOutlineDoc->m_lpFrameTools);

   }

   OutlineApp_SetFormulaBarAccel(lpOutlineApp, fEditFocus);

}

/* OutlineDoc_IsEditFocusInFormulaBar

** ----------------------------------

**    Returns TRUE if edit focus is currently in the formula bar

**    else FALSE if not.

*/

BOOL OutlineDoc_IsEditFocusInFormulaBar(LPOUTLINEDOC lpOutlineDoc)

{

   if (! lpOutlineDoc || ! lpOutlineDoc->m_lpFrameTools)

      return FALSE;

   return lpOutlineDoc->m_lpFrameTools->m_fInFormulaBar;

}

/* OutlineDoc_UpdateFrameToolButtons

** ---------------------------------

**    Update the Enable/Disable states of the buttons in the formula

**    bar and button bar.

*/

void OutlineDoc_UpdateFrameToolButtons(LPOUTLINEDOC lpOutlineDoc)

{

   if (! lpOutlineDoc || ! lpOutlineDoc->m_lpFrameTools)

      return;

   FrameTools_UpdateButtons(lpOutlineDoc->m_lpFrameTools, lpOutlineDoc);

}

#endif  // USE_FRAMETOOLS

/* OutlineDoc_EditLineCommand

 * --------------------------

 *

 *      Edit the current focus line.

 */

void OutlineDoc_EditLineCommand(LPOUTLINEDOC lpOutlineDoc)

{

   LPLINELIST lpLL = &lpOutlineDoc->m_LineList;

   HDC hDC = LineList_GetDC(lpLL);

   int nIndex = LineList_GetFocusLineIndex(lpLL);

   LPLINE lpLine = LineList_GetLine(lpLL, nIndex);

   int nOrgLineWidthInHimetric;

   int nNewLineWidthInHimetric;

   BOOL fSizeChanged;

   if (!lpLine)

      return;

   nOrgLineWidthInHimetric = Line_GetTotalWidthInHimetric(lpLine);

   if (Line_Edit(lpLine, lpOutlineDoc->m_hWndDoc, hDC)) {

      nNewLineWidthInHimetric = Line_GetTotalWidthInHimetric(lpLine);

      if (nNewLineWidthInHimetric > nOrgLineWidthInHimetric) {

         fSizeChanged = LineList_SetMaxLineWidthInHimetric(

               lpLL,

               nNewLineWidthInHimetric

            );

      } else {

         fSizeChanged = LineList_RecalcMaxLineWidthInHimetric(

               lpLL,

               nOrgLineWidthInHimetric

            );

      }

#if defined( OLE_SERVER )

      /* Update Name Table */

      ServerNameTable_EditLineUpdate(

            (LPSERVERNAMETABLE)lpOutlineDoc->m_lpNameTable,

            nIndex

      );

#endif

      OutlineDoc_SetModified(lpOutlineDoc, TRUE, TRUE, fSizeChanged);

      LineList_ForceLineRedraw(lpLL, nIndex, TRUE);

   }

   LineList_ReleaseDC(lpLL, hDC);

}

/* OutlineDoc_IndentCommand

 * ------------------------

 *

 *      Indent selection of lines

 */

void OutlineDoc_IndentCommand(LPOUTLINEDOC lpOutlineDoc)

{

   LPLINELIST  lpLL = &lpOutlineDoc->m_LineList;

   LPLINE      lpLine;

   HDC         hDC = LineList_GetDC(lpLL);

   int         i;

   int         nIndex;

   int         nNumSel;

   LINERANGE   lrSel;

   BOOL        fSizeChanged = FALSE;

   nNumSel=LineList_GetSel(lpLL, (LPLINERANGE)&lrSel);

   OutlineDoc_SetRedraw ( lpOutlineDoc, FALSE );

   for(i = 0; i < nNumSel; i++) {

      nIndex = lrSel.m_nStartLine + i;

      lpLine=LineList_GetLine(lpLL, nIndex);

      if (! lpLine)

         continue;

      Line_Indent(lpLine, hDC);

      if (LineList_SetMaxLineWidthInHimetric(lpLL,

         Line_GetTotalWidthInHimetric(lpLine))) {

         fSizeChanged = TRUE;

      }

      LineList_ForceLineRedraw(lpLL, nIndex, TRUE);

#if defined( OLE_SERVER )

      /* Update Name Table */

      ServerNameTable_EditLineUpdate(

            (LPSERVERNAMETABLE)lpOutlineDoc->m_lpNameTable,

            nIndex

      );

#endif

   }

   LineList_ReleaseDC(lpLL, hDC);

   OutlineDoc_SetModified(lpOutlineDoc, TRUE, TRUE, fSizeChanged);

   OutlineDoc_SetRedraw ( lpOutlineDoc, TRUE );

}

/* OutlineDoc_UnindentCommand

 * --------------------------

 *

 *      Unindent selection of lines

 */

void OutlineDoc_UnindentCommand(LPOUTLINEDOC lpOutlineDoc)

{

   LPLINELIST  lpLL = &lpOutlineDoc->m_LineList;

   LPLINE      lpLine;

   HDC         hDC = LineList_GetDC(lpLL);

   int         nOrgLineWidthInHimetric;

   int         nOrgMaxLineWidthInHimetric = 0;

   int         i;

   int         nIndex;

   int         nNumSel;

   LINERANGE   lrSel;

   BOOL        fSizeChanged;

   nNumSel=LineList_GetSel(lpLL, (LPLINERANGE)&lrSel);

   OutlineDoc_SetRedraw ( lpOutlineDoc, FALSE );

   for(i = 0; i < nNumSel; i++) {

      nIndex = lrSel.m_nStartLine + i;

      lpLine=LineList_GetLine(lpLL, nIndex);

      if (!lpLine)

         continue;

      nOrgLineWidthInHimetric = Line_GetTotalWidthInHimetric(lpLine);

      nOrgMaxLineWidthInHimetric =

            (nOrgLineWidthInHimetric > nOrgMaxLineWidthInHimetric ?

               nOrgLineWidthInHimetric : nOrgMaxLineWidthInHimetric);

      Line_Unindent(lpLine, hDC);

      LineList_ForceLineRedraw(lpLL, nIndex, TRUE);

#if defined( OLE_SERVER )

      /* Update Name Table */

      ServerNameTable_EditLineUpdate(

            (LPSERVERNAMETABLE)lpOutlineDoc->m_lpNameTable,

            nIndex

      );

#endif

   }

   LineList_ReleaseDC(lpLL, hDC);

   fSizeChanged = LineList_RecalcMaxLineWidthInHimetric(

         lpLL,

         nOrgMaxLineWidthInHimetric

      );

   OutlineDoc_SetModified(lpOutlineDoc, TRUE, TRUE, fSizeChanged);

   OutlineDoc_SetRedraw ( lpOutlineDoc, TRUE );

}

/* OutlineDoc_SetLineHeightCommand

 * -------------------------------

 *

 *      Set height of the selection of lines

 */

void OutlineDoc_SetLineHeightCommand(LPOUTLINEDOC lpOutlineDoc)

{

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   LPLINELIST  lpLL;

   HDC         hDC;

   LPLINE      lpLine;

   int         nNewHeight;

   int         i;

   int         nIndex;

   int         nNumSel;

   LINERANGE   lrSel;

   if (!lpOutlineDoc)

      return;

   lpLL = &lpOutlineDoc->m_LineList;

   nNumSel=LineList_GetSel(lpLL, (LPLINERANGE)&lrSel);

   lpLine = LineList_GetLine(lpLL, lrSel.m_nStartLine);

   if (!lpLine)

      return;

   nNewHeight = Line_GetHeightInHimetric(lpLine);

#if defined( OLE_VERSION )

   OleApp_PreModalDialog((LPOLEAPP)lpOutlineApp, (LPOLEDOC)lpOutlineDoc);

#endif

   DialogBoxParam(

         lpOutlineApp->m_hInst,

         (LPSTR)"SetLineHeight",

         lpOutlineDoc->m_hWndDoc,

         (DLGPROC)SetLineHeightDlgProc,

         (LPARAM)(LPINT)&nNewHeight

   );

#if defined( OLE_VERSION )

   OleApp_PostModalDialog((LPOLEAPP)lpOutlineApp, (LPOLEDOC)lpOutlineDoc);

#endif

   if (nNewHeight == 0)

      return;     /* user hit cancel */

   hDC = LineList_GetDC(lpLL);

   for (i = 0; i < nNumSel; i++) {

      nIndex = lrSel.m_nStartLine + i;

      lpLine=LineList_GetLine(lpLL, nIndex);

      if (nNewHeight == -1) {

         switch (Line_GetLineType(lpLine)) {

            case TEXTLINETYPE:

               TextLine_CalcExtents((LPTEXTLINE)lpLine, hDC);

               break;

#if defined( OLE_CNTR )

            case CONTAINERLINETYPE:

               ContainerLine_SetHeightInHimetric(

                     (LPCONTAINERLINE)lpLine, -1);

               break;

#endif

         }

      }

      else

         Line_SetHeightInHimetric(lpLine, nNewHeight);

      LineList_SetLineHeight(lpLL, nIndex,

            Line_GetHeightInHimetric(lpLine));

   }

   LineList_ReleaseDC(lpLL, hDC);

   OutlineDoc_SetModified(lpOutlineDoc, TRUE, TRUE, TRUE);

   LineList_ForceRedraw(lpLL, TRUE);

}

/* OutlineDoc_SelectAllCommand

 * ---------------------------

 *

 *      Select all the lines in the document.

 */

void OutlineDoc_SelectAllCommand(LPOUTLINEDOC lpOutlineDoc)

{

   LPLINELIST lpLL = &lpOutlineDoc->m_LineList;

   LINERANGE lrSel;

   lrSel.m_nStartLine = 0;

   lrSel.m_nEndLine = LineList_GetCount(lpLL) - 1;

   LineList_SetSel(lpLL, &lrSel);

}

/* OutlineDoc_DefineNameCommand

 * ----------------------------

 *

 *      Define a name in the document

 */

void OutlineDoc_DefineNameCommand(LPOUTLINEDOC lpOutlineDoc)

{

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

#if defined( OLE_VERSION )

   OleApp_PreModalDialog((LPOLEAPP)lpOutlineApp, (LPOLEDOC)lpOutlineDoc);

#endif

   DialogBoxParam(

         lpOutlineApp->m_hInst,

         (LPSTR)"DefineName",

         lpOutlineDoc->m_hWndDoc,

         (DLGPROC)DefineNameDlgProc,

         (LPARAM) lpOutlineDoc

   );

#if defined( OLE_VERSION )

   OleApp_PostModalDialog((LPOLEAPP)lpOutlineApp, (LPOLEDOC)lpOutlineDoc);

#endif

}

/* OutlineDoc_GotoNameCommand

 * --------------------------

 *

 *      Goto a predefined name in the document

 */

void OutlineDoc_GotoNameCommand(LPOUTLINEDOC lpOutlineDoc)

{

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

#if defined( OLE_VERSION )

   OleApp_PreModalDialog((LPOLEAPP)lpOutlineApp, (LPOLEDOC)lpOutlineDoc);

#endif

   DialogBoxParam(

         lpOutlineApp->m_hInst,

         (LPSTR)"GotoName",

         lpOutlineDoc->m_hWndDoc,

         (DLGPROC)GotoNameDlgProc,

         (LPARAM)lpOutlineDoc

   );

#if defined( OLE_VERSION )

   OleApp_PostModalDialog((LPOLEAPP)lpOutlineApp, (LPOLEDOC)lpOutlineDoc);

#endif

}

/* OutlineDoc_ShowWindow

 * ---------------------

 *

 *      Show the window of the document to the user.

 */

void OutlineDoc_ShowWindow(LPOUTLINEDOC lpOutlineDoc)

{

#if defined( _DEBUG )

   OleDbgAssertSz(lpOutlineDoc->m_docInitType != DOCTYPE_UNKNOWN,

            "OutlineDoc_ShowWindow: can't show unitialized document\r\n");

#endif

   if (lpOutlineDoc->m_docInitType == DOCTYPE_UNKNOWN)

      return;

#if defined( OLE_VERSION )

   // Call OLE version of this function instead

   OleDoc_ShowWindow((LPOLEDOC)lpOutlineDoc);

#else

   ShowWindow(lpOutlineDoc->m_hWndDoc, SW_SHOWNORMAL);

   SetForegroundWindow(lpOutlineDoc->m_hWndDoc);

#endif

}

#if defined( USE_FRAMETOOLS )

void OutlineDoc_AddFrameLevelTools(LPOUTLINEDOC lpOutlineDoc)

{

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

#if defined( INPLACE_CNTR )

   // Call OLE In-Place Container version of this function instead

   ContainerDoc_AddFrameLevelTools((LPCONTAINERDOC)lpOutlineDoc);

#else   // ! INPLACE_CNTR

   RECT rcFrameRect;

   BORDERWIDTHS frameToolWidths;

#if defined( INPLACE_SVR )

   LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOutlineDoc;

   LPOLEINPLACEFRAME lpTopIPFrame=ServerDoc_GetTopInPlaceFrame(lpServerDoc);

   // if in-place active, add our tools to our in-place container's frame.

   if (lpTopIPFrame) {

      ServerDoc_AddFrameLevelTools(lpServerDoc);

      return;

   }

#endif  // INPLACE_SVR

   OutlineApp_GetFrameRect(g_lpApp, (LPRECT)&rcFrameRect);

   FrameTools_GetRequiredBorderSpace(

         lpOutlineDoc->m_lpFrameTools,

         (LPBORDERWIDTHS)&frameToolWidths

   );

   OutlineApp_SetBorderSpace(g_lpApp, (LPBORDERWIDTHS)&frameToolWidths);

   FrameTools_AttachToFrame(

         lpOutlineDoc->m_lpFrameTools, OutlineApp_GetWindow(lpOutlineApp));

   FrameTools_Move(lpOutlineDoc->m_lpFrameTools, (LPRECT)&rcFrameRect);

#endif  // ! INPLACE_CNTR

}

#endif  // USE_FRAMETOOLS

/* OutlineDoc_GetWindow

 * --------------------

 *

 *      Get the window handle of the document.

 */

HWND OutlineDoc_GetWindow(LPOUTLINEDOC lpOutlineDoc)

{

   if(! lpOutlineDoc) return NULL;

   return lpOutlineDoc->m_hWndDoc;

}

/* OutlineDoc_AddLine

 * ------------------

 *

 *      Add one line to the Document's LineList

 */

void OutlineDoc_AddLine(LPOUTLINEDOC lpOutlineDoc, LPLINE lpLine, int nIndex)

{

   LPLINELIST lpLL = &lpOutlineDoc->m_LineList;

   LineList_AddLine(lpLL, lpLine, nIndex);

   /* Update Name Table */

   OutlineNameTable_AddLineUpdate(lpOutlineDoc->m_lpNameTable, nIndex);

#if defined( INPLACE_CNTR )

   {

      LPCONTAINERDOC lpContainerDoc = (LPCONTAINERDOC)lpOutlineDoc;

      /* OLE2NOTE: after adding a line we need to

      **    update the PosRect of the In-Place active

      **    objects (if any) that follow the added line.

      **    NOTE: nIndex is index of line before new line.

      **          nIndex+1 is index of new line

      **          nIndex+2 is index of line after new line.

      */

      ContainerDoc_UpdateInPlaceObjectRects(lpContainerDoc, nIndex+2);

   }

#endif

   OutlineDoc_SetModified(lpOutlineDoc, TRUE, TRUE, TRUE);

}

/* OutlineDoc_DeleteLine

 * ---------------------

 *

 *

 *      Delete one line from the document's LineList

 */

void OutlineDoc_DeleteLine(LPOUTLINEDOC lpOutlineDoc, int nIndex)

{

   LPLINELIST lpLL = &lpOutlineDoc->m_LineList;

#if defined( OLE_CNTR )

   LPLINE lpLine = LineList_GetLine(lpLL, nIndex);

   LPSTORAGE lpStgDoc = NULL;

   OLECHAR szSaveStgName[CWCSTORAGENAME];

   BOOL fDeleteChildStg = FALSE;

   if (lpLine && (Line_GetLineType(lpLine) == CONTAINERLINETYPE) ) {

      /* OLE2NOTE: when a ContainerLine is being deleted by the user,

      **    it is important to delete the object's sub-storage

      **    otherwise it wastes space in the ContainerDoc's file.

      **    this function is called when lines are deleted by the

      **    Clear command and when lines are deleted by a DRAGMOVE

      **    operation.

      */

      LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)lpLine;

      // save name of child storage

//      LSTRCPYN(szSaveStgName, lpContainerLine->m_szStgName,sizeof(szSaveStgName));

      OLESTRCPY(szSaveStgName, lpContainerLine->m_szStgName);

      lpStgDoc = ((LPOLEDOC)lpContainerLine->m_lpDoc)->m_lpStg;

      fDeleteChildStg = TRUE;

   }

#endif  // OLE_CNTR

   LineList_DeleteLine(lpLL, nIndex);

#if defined( OLE_CNTR )

   if (fDeleteChildStg && lpStgDoc) {

      HRESULT hrErr;

      // delete the obsolete child storage. it is NOT fatal if this fails

      hrErr = lpStgDoc->lpVtbl->DestroyElement(lpStgDoc, szSaveStgName);

#if defined( _DEBUG )

      if (hrErr != NOERROR) {

         OleDbgOutHResult("IStorage::DestroyElement return", hrErr);

      }

#endif

   }

#endif  // OLE_CNTR

   /* Update Name Table */

   OutlineNameTable_DeleteLineUpdate(lpOutlineDoc->m_lpNameTable, nIndex);

#if defined( INPLACE_CNTR )

   {

      LPCONTAINERDOC lpContainerDoc = (LPCONTAINERDOC)lpOutlineDoc;

      /* OLE2NOTE: after deleting a line we need to

      **    update the PosRect of the In-Place active

      **    objects (if any).

      */

      ContainerDoc_UpdateInPlaceObjectRects(lpContainerDoc, nIndex);

   }

#endif

   OutlineDoc_SetModified(lpOutlineDoc, TRUE, TRUE, TRUE);

#if defined( OLE_VERSION )

   {

      LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

      LPOLEDOC    lpClipboardDoc = (LPOLEDOC)lpOutlineApp->m_lpClipboardDoc;

      /* OLE2NOTE: if the document that is the source of data on the

      **    clipborad has just had lines deleted, then the copied data

      **    is no longer considered a valid potential link source.

      **    disable the offering of CF_LINKSOURCE from the clipboard

      **    document. this avoids problems that arise when the

      **    editing operation changes or deletes the original data

      **    copied. we will not go to the trouble of determining if

      **    the deleted line actually is part of the link source.

      */

      if (lpClipboardDoc

         && lpClipboardDoc->m_fLinkSourceAvail

         && lpClipboardDoc->m_lpSrcDocOfCopy == (LPOLEDOC)lpOutlineDoc) {

         lpClipboardDoc->m_fLinkSourceAvail = FALSE;

         /* OLE2NOTE: since we are changing the list of formats on

         **    the clipboard (ie. removing CF_LINKSOURCE), we must

         **    call OleSetClipboard again. to be sure that the

         **    clipboard datatransfer document object does not get

         **    destroyed we will guard the call to OleSetClipboard

         **    within a pair of AddRef/Release.

         */

         OleDoc_AddRef((LPOLEDOC)lpClipboardDoc);    // guard obj life-time

         OLEDBG_BEGIN2("OleSetClipboard called\r\n")

         OleSetClipboard(

               (LPDATAOBJECT)&((LPOLEDOC)lpClipboardDoc)->m_DataObject);

         OLEDBG_END2

         OleDoc_Release((LPOLEDOC)lpClipboardDoc);    // rel. AddRef above

      }

   }

#endif  // OLE_VERSION

}

/* OutlineDoc_AddName

 * ------------------

 *

 *      Add a Name to the Document's NameTable

 */

void OutlineDoc_AddName(LPOUTLINEDOC lpOutlineDoc, LPOUTLINENAME lpOutlineName)

{

   LPOUTLINENAMETABLE lpOutlineNameTable = lpOutlineDoc->m_lpNameTable;

   OutlineNameTable_AddName(lpOutlineNameTable, lpOutlineName);

   OutlineDoc_SetModified(lpOutlineDoc, TRUE, FALSE, FALSE);

}

/* OutlineDoc_DeleteName

 * ---------------------

 *

 *

 *      Delete Name from the document's NameTable

 */

void OutlineDoc_DeleteName(LPOUTLINEDOC lpOutlineDoc, int nIndex)

{

   LPOUTLINENAMETABLE lpOutlineNameTable = lpOutlineDoc->m_lpNameTable;

   OutlineNameTable_DeleteName(lpOutlineNameTable, nIndex);

   OutlineDoc_SetModified(lpOutlineDoc, TRUE, FALSE, FALSE);

}

/* OutlineDoc_Destroy

 * ------------------

 *

 *  Free all memory that had been allocated for a document.

 *      this destroys the LineList & NameTable of the document.

 */

void OutlineDoc_Destroy(LPOUTLINEDOC lpOutlineDoc)

{

   LPLINELIST lpLL = &lpOutlineDoc->m_LineList;

#if defined( OLE_VERSION )

   LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp;

   LPOLEDOC lpOleDoc = (LPOLEDOC)lpOutlineDoc;

   if (lpOleDoc->m_fObjIsDestroying)

      return;     // doc destruction is in progress

#endif  // OLE_VERSION

   OLEDBG_BEGIN3("OutlineDoc_Destroy\r\n");

#if defined( OLE_VERSION )

   /* OLE2NOTE: in order to guarantee that the application does not

   **    prematurely exit before the destruction of the document is

   **    complete, we intially AddRef the App refcnt later Release it.

   **    This initial AddRef is artificial; it simply guarantees that

   **    the app object does not get destroyed until the end of this

   **    routine.

   */

   OleApp_AddRef(lpOleApp);

   /* OLE2NOTE: perform processing required for OLE */

   OleDoc_Destroy(lpOleDoc);

#endif

   LineList_Destroy(lpLL);

   OutlineNameTable_Destroy(lpOutlineDoc->m_lpNameTable);

#if defined( USE_HEADING )

   if (! lpOutlineDoc->m_fDataTransferDoc)

      Heading_Destroy((LPHEADING)&lpOutlineDoc->m_heading);

#endif

#if defined( USE_FRAMETOOLS )

   if (! lpOutlineDoc->m_fDataTransferDoc)

      FrameTools_AssociateDoc(lpOutlineDoc->m_lpFrameTools, NULL);

#endif  // USE_FRAMETOOLS

   DestroyWindow(lpOutlineDoc->m_hWndDoc);

   Delete(lpOutlineDoc);   // free memory for doc itself

   OleDbgOut1("@@@@ DOC DESTROYED\r\n");

#if defined( OLE_VERSION )

   OleApp_Release(lpOleApp);       // release artificial AddRef above

#endif

   OLEDBG_END3

}

/* OutlineDoc_ReSize

 * -----------------

 *

 *  Resize the document and its components

 *

 * Parameter:

 *      lpRect  the new size of the document. Use current size if NULL

 */

void OutlineDoc_Resize(LPOUTLINEDOC lpOutlineDoc, LPRECT lpRect)

{

   RECT            rect;

   LPLINELIST      lpLL;

#if defined( USE_HEADING )

   LPHEADING       lphead;

#endif  // USE_HEADING

   LPSCALEFACTOR   lpscale;

   HWND            hWndLL;

   if (!lpOutlineDoc)

      return;

   lpLL = (LPLINELIST)&lpOutlineDoc->m_LineList;

   lpscale = (LPSCALEFACTOR)&lpOutlineDoc->m_scale;

   hWndLL = LineList_GetWindow(lpLL);

   if (lpRect) {

      CopyRect((LPRECT)&rect, lpRect);

      MoveWindow(lpOutlineDoc->m_hWndDoc, rect.left, rect.top,

            rect.right-rect.left, rect.bottom-rect.top, TRUE);

   }

   GetClientRect(lpOutlineDoc->m_hWndDoc, (LPRECT)&rect);

#if defined( USE_HEADING )

   lphead = OutlineDoc_GetHeading(lpOutlineDoc);

   rect.left += Heading_RH_GetWidth(lphead, lpscale);

   rect.top += Heading_CH_GetHeight(lphead, lpscale);

#endif  // USE_HEADING

   if (lpLL) {

      MoveWindow(hWndLL, rect.left, rect.top,

            rect.right-rect.left, rect.bottom-rect.top, TRUE);

   }

#if defined( USE_HEADING )

   if (lphead)

      Heading_Move(lphead, lpOutlineDoc->m_hWndDoc, lpscale);

#endif  // USE_HEADING

#if defined( INPLACE_CNTR )

   ContainerDoc_UpdateInPlaceObjectRects((LPCONTAINERDOC)lpOutlineDoc, 0);

#endif

}

/* OutlineDoc_GetNameTable

 * -----------------------

 *

 *      Get nametable associated with the line list

 */

LPOUTLINENAMETABLE OutlineDoc_GetNameTable(LPOUTLINEDOC lpOutlineDoc)

{

   if (!lpOutlineDoc)

      return NULL;

   else

      return lpOutlineDoc->m_lpNameTable;

}

/* OutlineDoc_GetLineList

 * ----------------------

 *

 *      Get listlist associated with the OutlineDoc

 */

LPLINELIST OutlineDoc_GetLineList(LPOUTLINEDOC lpOutlineDoc)

{

   if (!lpOutlineDoc)

      return NULL;

   else

      return (LPLINELIST)&lpOutlineDoc->m_LineList;

}

/* OutlineDoc_GetNameCount

 * -----------------------

 *

 * Return number of names in table

 */

int OutlineDoc_GetNameCount(LPOUTLINEDOC lpOutlineDoc)

{

   return OutlineNameTable_GetCount(lpOutlineDoc->m_lpNameTable);

}

/* OutlineDoc_GetLineCount

 * -----------------------

 *

 * Return number of lines in the LineList

 */

int OutlineDoc_GetLineCount(LPOUTLINEDOC lpOutlineDoc)

{

   return LineList_GetCount(&lpOutlineDoc->m_LineList);

}

/* OutlineDoc_SetFileName

 * ----------------------

 *

 *      Set the filename of a document.

 *

 *  OLE2NOTE: If the ServerDoc has a valid filename then, the object is

 *  registered in the running object table (ROT). if the name of the doc

 *  changes (eg. via SaveAs) then the previous registration must be revoked

 *  and the document re-registered under the new name.

 */

BOOL OutlineDoc_SetFileName(LPOUTLINEDOC lpOutlineDoc, LPOLESTR lpszNewFileName, LPSTORAGE lpNewStg)

{

   OleDbgAssertSz(lpszNewFileName != NULL,   "Can't reset doc to Untitled!");

   if (lpszNewFileName == NULL)

      return FALSE;

//   AnsiLowerBuff(lpszNewFileName, (UINT)OLESTRLEN(lpszNewFileName));

   CharLowerBuffW(lpszNewFileName, OLESTRLEN(lpszNewFileName));

#if defined( OLE_CNTR )

   {

      LPCONTAINERDOC lpContainerDoc = (LPCONTAINERDOC)lpOutlineDoc;

      LPOLEDOC lpOleDoc = (LPOLEDOC)lpOutlineDoc;

      /* OLE2NOTE: the container version of the application keeps its

      **    storage open at all times. if the document's storage is not

      **    open, then open it.

      */

      if (lpNewStg) {

         /* CASE 1 -- document is being loaded from a file. lpNewStg is

         **    still open from the OutlineDoc_LoadFromFile function.

         */

         lpOutlineDoc->m_docInitType = DOCTYPE_FROMFILE;

      } else {

         /* CASE 2 -- document is being associated with a valid file

         **    that is not yet open. thus we must now open the file.

         */

         if (lpOutlineDoc->m_docInitType == DOCTYPE_FROMFILE &&

               OLESTRCMP(lpOutlineDoc->m_szFileName,lpszNewFileName)==0) {

            /* CASE 2a -- new filename is same as current file. if the

            **    stg is already open, then the lpStg is still valid.

            **    if it is not open, then open it.

            */

            if (! lpOleDoc->m_lpStg) {

               lpOleDoc->m_lpStg = OleStdOpenRootStorage(

                     lpszNewFileName,

                     STGM_READWRITE | STGM_SHARE_DENY_WRITE

               );

               if (! lpOleDoc->m_lpStg) return FALSE;

            }

         } else {

            /* CASE 2b -- new filename is NOT same as current file.

            **    a SaveAs operation is pending. open the new file and

            **    hold the storage pointer in m_lpNewStg. the

            **    subsequent call to Doc_SaveToFile will save the

            **    document into the new storage pointer and release the

            **    old storage pointer.

            */

            lpOutlineDoc->m_docInitType = DOCTYPE_FROMFILE;

            lpContainerDoc->m_lpNewStg = OleStdCreateRootStorage(

                  lpszNewFileName,

                  STGM_READWRITE | STGM_SHARE_DENY_WRITE | STGM_CREATE

            );

            if (! lpContainerDoc->m_lpNewStg) return FALSE;

         }

      }

   }

#endif      // OLE_CNTR

   if (lpOutlineDoc->m_docInitType != DOCTYPE_FROMFILE ||

      OLESTRCMP(lpOutlineDoc->m_szFileName, lpszNewFileName) != 0) {

      /* A new valid file name is being associated with the document */

      OLESTRCPY(lpOutlineDoc->m_szFileName, lpszNewFileName);

      lpOutlineDoc->m_docInitType = DOCTYPE_FROMFILE;

      // set lpszDocTitle to point to filename without path

      lpOutlineDoc->m_lpszDocTitle = lpOutlineDoc->m_szFileName +

         OLESTRLEN(lpOutlineDoc->m_szFileName) - 1;

      while (lpOutlineDoc->m_lpszDocTitle > lpOutlineDoc->m_szFileName

         && ! IS_FILENAME_DELIM(lpOutlineDoc->m_lpszDocTitle[-1])) {

         lpOutlineDoc->m_lpszDocTitle--;

      }

      OutlineDoc_SetTitle(lpOutlineDoc, TRUE /*fMakeUpperCase*/);

#if defined( OLE_VERSION )

      {

         /* OLE2NOTE: both containers and servers must properly

         **    register in the RunningObjectTable. if the document

         **    is performing a SaveAs operation, then it must

         **    re-register in the ROT with the new moniker. in

         **    addition any embedded object, pseudo objects, and/or

         **    linking clients must be informed that the document's

         **    moniker has changed.

         */

         LPOLEDOC lpOleDoc = (LPOLEDOC)lpOutlineDoc;

         if (lpOleDoc->m_lpFileMoniker) {

            OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpFileMoniker);

            lpOleDoc->m_lpFileMoniker = NULL;

         }

         CreateFileMoniker(lpszNewFileName,&lpOleDoc->m_lpFileMoniker);

         OleDoc_DocRenamedUpdate(lpOleDoc, lpOleDoc->m_lpFileMoniker);

      }

#endif      // OLE_VERSION

   }

   return TRUE;

}

/* OutlineDoc_SetTitle

 * -------------------

 *

 * Set window text to be current filename.

 * The following window hierarchy exits:

 *      hWndApp

 *          hWndDoc

 *              hWndListBox

 *  The frame window is the window which gets the title.

 */

void OutlineDoc_SetTitle(LPOUTLINEDOC lpOutlineDoc, BOOL fMakeUpperCase)

{

   HWND hWnd;

   LPSTR lpszText;

   char  szAnsiStr[256];

   if (!lpOutlineDoc->m_hWndDoc) return;

   if ((hWnd = GetParent(lpOutlineDoc->m_hWndDoc)) == NULL) return;

   lpszText = OleStdMalloc((UINT)(OLESTRLEN(APPNAME) + 4 +

                           OLESTRLEN(lpOutlineDoc->m_lpszDocTitle)));

   if (!lpszText) return;

   W2A(APPNAME, lpszText, OLESTRLEN(APPNAME)+1);

   lstrcat(lpszText," - ");

   W2A (lpOutlineDoc->m_lpszDocTitle, szAnsiStr, 256);

   lstrcat(lpszText, (LPSTR)szAnsiStr);

   if (fMakeUpperCase)

      AnsiUpperBuff(lpszText, (UINT)lstrlen(lpszText));

   SetWindowText(hWnd,lpszText);

   OleStdFree(lpszText);

}

/* OutlineDoc_Close

 * ----------------

 *

 * Close active document. If modified, prompt the user if

 * he wants to save.

 *

 *  Returns:

 *      FALSE -- user canceled the closing of the doc.

 *      TRUE -- the doc was successfully closed

 */

BOOL OutlineDoc_Close(LPOUTLINEDOC lpOutlineDoc, DWORD dwSaveOption)

{

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

#if defined( OLE_VERSION )

   /* OLE2NOTE: call OLE specific function instead */

   return OleDoc_Close((LPOLEDOC)lpOutlineDoc, dwSaveOption);

#else

   if (! lpOutlineDoc)

      return TRUE;            // active doc's are already destroyed

   if (! OutlineDoc_CheckSaveChanges(lpOutlineDoc, &dwSaveOption))

      return FALSE;           // abort closing the doc

   OutlineDoc_Destroy(lpOutlineDoc);

   OutlineApp_DocUnlockApp(lpOutlineApp, lpOutlineDoc);

   return TRUE;

#endif      // ! OLE_VERSION

}

/* OutlineDoc_CheckSaveChanges

 * ---------------------------

 *

 * Check if the document has been modified. if so, prompt the user if

 *      the changes should be saved. if yes save them.

 * Returns TRUE if the doc is safe to close (user answered Yes or No)

 *         FALSE if the user canceled the save changes option.

 */

BOOL OutlineDoc_CheckSaveChanges(

      LPOUTLINEDOC        lpOutlineDoc,

      LPDWORD             lpdwSaveOption

)

{

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   int nResponse;

   char szAnsiString[256];

   char szAnsiString2[256];

   if (*lpdwSaveOption == OLECLOSE_NOSAVE)

      return TRUE;

   if(! OutlineDoc_IsModified(lpOutlineDoc))

      return TRUE;    // saving is not necessary

   /* OLE2NOTE: our document is dirty so it needs to be saved. if

   **    OLECLOSE_PROMPTSAVE the user should be prompted to see if the

   **    document should be saved. is specified but the document is NOT

   **    visible to the user, then the user can NOT be prompted. in

   **    the situation the document should be saved without prompting.

   **    if OLECLOSE_SAVEIFDIRTY is specified then, the document

   **    should also be saved without prompting.

   */

   if (*lpdwSaveOption == OLECLOSE_PROMPTSAVE &&

         IsWindowVisible(lpOutlineDoc->m_hWndDoc)) {

      // prompt the user to see if changes should be saved.

#if defined( OLE_VERSION )

      OleApp_PreModalDialog(

            (LPOLEAPP)lpOutlineApp, (LPOLEDOC)lpOutlineApp->m_lpDoc);

#endif

      W2A (APPNAME, szAnsiString, 256);

      W2A (MsgSaveFile, szAnsiString2, 256);

      nResponse = MessageBox(

            lpOutlineApp->m_hWndApp,

            szAnsiString2,

            szAnsiString,

            MB_ICONQUESTION | MB_YESNOCANCEL

      );

#if defined( OLE_VERSION )

      OleApp_PostModalDialog(

            (LPOLEAPP)lpOutlineApp, (LPOLEDOC)lpOutlineApp->m_lpDoc);

#endif

      if(nResponse==IDCANCEL)

         return FALSE;   // close is canceled

      if(nResponse==IDNO) {

         // Reset the save option to NOSAVE per user choice

         *lpdwSaveOption = OLECLOSE_NOSAVE;

         return TRUE;    // don't save, but is ok to close

      }

   } else if (*lpdwSaveOption != OLECLOSE_SAVEIFDIRTY) {

      OleDbgAssertSz(FALSE, "Invalid dwSaveOption\r\n");

      *lpdwSaveOption = OLECLOSE_NOSAVE;

      return TRUE;        // unknown *lpdwSaveOption; close w/o saving

   }

#if defined( OLE_SERVER )

   if (lpOutlineDoc->m_docInitType == DOCTYPE_EMBEDDED) {

      LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOutlineDoc;

      HRESULT hrErr;

      /* OLE2NOTE: Update the container before closing without prompting

      **    the user. To update the container, we must ask our container

      **    to save us.

      */

      OleDbgAssert(lpServerDoc->m_lpOleClientSite != NULL);

      OLEDBG_BEGIN2("IOleClientSite::SaveObject called\r\n")

      hrErr = lpServerDoc->m_lpOleClientSite->lpVtbl->SaveObject(

            lpServerDoc->m_lpOleClientSite

      );

      OLEDBG_END2

      if (hrErr != NOERROR) {

         OleDbgOutHResult("IOleClientSite::SaveObject returned", hrErr);

         return FALSE;

      }

      return TRUE;    // doc is safe to be closed

   } else

#endif      // OLE_SERVER

   {

      return OutlineApp_SaveCommand(lpOutlineApp);

   }

}

/* OutlineDoc_IsModified

 * ---------------------

 *

 * Return modify flag of OUTLINEDOC

 */

BOOL OutlineDoc_IsModified(LPOUTLINEDOC lpOutlineDoc)

{

   if (lpOutlineDoc->m_fModified)

      return lpOutlineDoc->m_fModified;

#if defined( OLE_CNTR )

   {

      /* OLE2NOTE: if there are OLE objects, then we must ask if any of

      **    them are dirty. if so we must consider our document

      **    as modified.

      */

      LPCONTAINERDOC lpContainerDoc = (LPCONTAINERDOC)lpOutlineDoc;

      LPLINELIST  lpLL;

      int         nLines;

      int         nIndex;

      LPLINE      lpLine;

      HRESULT     hrErr;

      lpLL = (LPLINELIST)&((LPOUTLINEDOC)lpContainerDoc)->m_LineList;

      nLines = LineList_GetCount(lpLL);

      for (nIndex = 0; nIndex < nLines; nIndex++) {

         lpLine = LineList_GetLine(lpLL, nIndex);

         if (!lpLine)

            break;

         if (Line_GetLineType(lpLine) == CONTAINERLINETYPE) {

            LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)lpLine;

            if (lpContainerLine->m_lpPersistStg) {

               hrErr = lpContainerLine->m_lpPersistStg->lpVtbl->IsDirty(

                     lpContainerLine->m_lpPersistStg);

               /* OLE2NOTE: we will only accept an explicit "no i

               **    am NOT dirty statement" (ie. S_FALSE) as an

               **    indication that the object is clean. eg. if

               **    the object returns E_NOTIMPL we must

               **    interpret it as the object IS dirty.

               */

               if (GetScode(hrErr) != S_FALSE)

                  return TRUE;

            }

         }

      }

   }

#endif

   return FALSE;

}

/* OutlineDoc_SetModified

 * ----------------------

 *

 *  Set the modified flag of the document

 *

 */

void OutlineDoc_SetModified(LPOUTLINEDOC lpOutlineDoc, BOOL fModified, BOOL fDataChanged, BOOL fSizeChanged)

{

   lpOutlineDoc->m_fModified = fModified;

#if defined( OLE_SERVER )

   if (! lpOutlineDoc->m_fDataTransferDoc) {

      LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOutlineDoc;

      /* OLE2NOTE: if the document has changed, then broadcast the change

      **    to all clients who have set up Advise connections. notify

      **    them that our data (and possibly also our extents) have

      **    changed.

      */

      if (fDataChanged) {

         lpServerDoc->m_fDataChanged     = TRUE;

         lpServerDoc->m_fSizeChanged     = fSizeChanged;

         lpServerDoc->m_fSendDataOnStop  = TRUE;

         ServerDoc_SendAdvise(

               lpServerDoc,

               OLE_ONDATACHANGE,

               NULL,   /* lpmkDoc -- not relevant here */

               0       /* advf -- no flags necessary */

         );

      }

   }

#endif  // OLE_SERVER

}

/* OutlineDoc_SetRedraw

 * --------------------

 *

 *  Enable/Disable the redraw of the document on screen.

 *  The calls to SetRedraw counted so that nested calls can be handled

 *  properly. calls to SetRedraw must be balanced.

 *

 *  fEnbaleDraw = TRUE      - enable redraw

 *                FALSE     - disable redraw

 */

void OutlineDoc_SetRedraw(LPOUTLINEDOC lpOutlineDoc, BOOL fEnableDraw)

{

   static HCURSOR hPrevCursor = NULL;

   if (fEnableDraw) {

      if (lpOutlineDoc->m_nDisableDraw == 0)

         return;     // already enabled; no state transition

      if (--lpOutlineDoc->m_nDisableDraw > 0)

         return;     // drawing should still be disabled

   } else {

      if (lpOutlineDoc->m_nDisableDraw++ > 0)

         return;     // already disabled; no state transition

   }

   if (lpOutlineDoc->m_nDisableDraw > 0) {

      // this may take a while, put up hourglass cursor

      hPrevCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));

   } else {

      if (hPrevCursor) {

         SetCursor(hPrevCursor);     // restore original cursor

         hPrevCursor = NULL;

      }

   }

#if defined( OLE_SERVER )

   /* OLE2NOTE: for the Server version, while Redraw is disabled

   **    postpone sending advise notifications until Redraw is re-enabled.

   */

   {

      LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOutlineDoc;

      LPSERVERNAMETABLE lpServerNameTable =

            (LPSERVERNAMETABLE)lpOutlineDoc->m_lpNameTable;

      if (lpOutlineDoc->m_nDisableDraw == 0) {

         /* drawing is being Enabled. if changes occurred while drawing

         **    was disabled, then notify clients now.

         */

         if (lpServerDoc->m_fDataChanged)

            ServerDoc_SendAdvise(

                  lpServerDoc,

                  OLE_ONDATACHANGE,

                  NULL,   /* lpmkDoc -- not relevant here */

                  0       /* advf -- no flags necessary */

            );

         /* OLE2NOTE: send pending change notifications for pseudo objs. */

         ServerNameTable_SendPendingAdvises(lpServerNameTable);

      }

   }

#endif      // OLE_SERVER

#if defined( OLE_CNTR )

   /* OLE2NOTE: for the Container version, while Redraw is disabled

   **    postpone updating the extents of OLE objects until Redraw is

   **    re-enabled.

   */

   {

      LPCONTAINERDOC lpContainerDoc = (LPCONTAINERDOC)lpOutlineDoc;

      /* Update the extents of any OLE object that is marked that

      **    its size may  have changed. when an

      **    IAdviseSink::OnViewChange notification is received,

      **    the corresponding ContainerLine is marked

      **    (m_fDoGetExtent==TRUE) and a message

      **    (WM_U_UPDATEOBJECTEXTENT) is posted to the document

      **    indicating that there are dirty objects.

      */

      if (lpOutlineDoc->m_nDisableDraw == 0)

         ContainerDoc_UpdateExtentOfAllOleObjects(lpContainerDoc);

   }

#endif      // OLE_CNTR

   // enable/disable redraw of the LineList listbox

   LineList_SetRedraw(&lpOutlineDoc->m_LineList, fEnableDraw);

}

/* OutlineDoc_SetSel

 * -----------------

 *

 *      Set the selection in the documents's LineList

 */

void OutlineDoc_SetSel(LPOUTLINEDOC lpOutlineDoc, LPLINERANGE lplrSel)

{

   LineList_SetSel(&lpOutlineDoc->m_LineList, lplrSel);

}

/* OutlineDoc_GetSel

 * -----------------

 *

 *      Get the selection in the documents's LineList.

 *

 *      Returns the count of items selected

 */

int OutlineDoc_GetSel(LPOUTLINEDOC lpOutlineDoc, LPLINERANGE lplrSel)

{

   return LineList_GetSel(&lpOutlineDoc->m_LineList, lplrSel);

}

/* OutlineDoc_ForceRedraw

 * ----------------------

 *

 *      Force the document window to repaint.

 */

void OutlineDoc_ForceRedraw(LPOUTLINEDOC lpOutlineDoc, BOOL fErase)

{

   if (!lpOutlineDoc)

      return;

   LineList_ForceRedraw(&lpOutlineDoc->m_LineList, fErase);

   Heading_CH_ForceRedraw(&lpOutlineDoc->m_heading, fErase);

   Heading_RH_ForceRedraw(&lpOutlineDoc->m_heading, fErase);

}

/* OutlineDoc_RenderFormat

 * -----------------------

 *

 *      Render a clipboard format supported by ClipboardDoc

 */

void OutlineDoc_RenderFormat(LPOUTLINEDOC lpOutlineDoc, UINT uFormat)

{

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   HGLOBAL      hData = NULL;

   if (uFormat == lpOutlineApp->m_cfOutline)

      hData = OutlineDoc_GetOutlineData(lpOutlineDoc, NULL);

   else if (uFormat == CF_TEXT)

      hData = OutlineDoc_GetTextData(lpOutlineDoc, NULL);

   else {

      OutlineApp_ErrorMessage(lpOutlineApp, ErrMsgFormatNotSupported);

      return;

   }

   SetClipboardData(uFormat, hData);

}

/* OutlineDoc_RenderAllFormats

 * ---------------------------

 *

 *      Render all formats supported by ClipboardDoc

 */

void OutlineDoc_RenderAllFormats(LPOUTLINEDOC lpOutlineDoc)

{

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   HGLOBAL      hData = NULL;

   OpenClipboard(lpOutlineDoc->m_hWndDoc);

   hData = OutlineDoc_GetOutlineData(lpOutlineDoc, NULL);

   SetClipboardData(lpOutlineApp->m_cfOutline, hData);

   hData = OutlineDoc_GetTextData(lpOutlineDoc, NULL);

   SetClipboardData(CF_TEXT, hData);

   CloseClipboard();

}

/* OutlineDoc_GetOutlineData

 * -------------------------

 *

 * Return a handle to an array of TextLine objects for the desired line

 *      range.

 *  NOTE: if lplrSel == NULL, then all lines are returned

 *

 */

HGLOBAL OutlineDoc_GetOutlineData(LPOUTLINEDOC lpOutlineDoc, LPLINERANGE lplrSel)

{

   HGLOBAL     hOutline  = NULL;

   LPLINELIST  lpLL=(LPLINELIST)&lpOutlineDoc->m_LineList;

   LPLINE      lpLine;

   LPTEXTLINE  arrLine;

   int     i;

   int     nStart = (lplrSel ? lplrSel->m_nStartLine : 0);

   int     nEnd =(lplrSel ? lplrSel->m_nEndLine : LineList_GetCount(lpLL)-1);

   int     nLines = nEnd - nStart + 1;

   int     nCopied = 0;

   hOutline=GlobalAlloc(GALLOCFLG, sizeof(TEXTLINE)*nLines);

   if (! hOutline) return NULL;

   arrLine=(LPTEXTLINE)GlobalLock(hOutline);

   for (i = nStart; i <= nEnd; i++) {

      lpLine=LineList_GetLine(lpLL, i);

      if (lpLine && Line_GetOutlineData(lpLine, &arrLine[nCopied]))

         nCopied++;

   }

   GlobalUnlock(hOutline);

   return hOutline;

}

/* OutlineDoc_GetTextData

 * ----------------------

 *

 * Return a handle to an object's data in text form for the desired line

 *      range.

 *  NOTE: if lplrSel == NULL, then all lines are returned

 *

 */

HGLOBAL OutlineDoc_GetTextData(LPOUTLINEDOC lpOutlineDoc, LPLINERANGE lplrSel)

{

   LPLINELIST  lpLL=(LPLINELIST)&lpOutlineDoc->m_LineList;

   LPLINE  lpLine;

   HGLOBAL hText = NULL;

   LPOLESTR   lpszText = NULL;

   DWORD   dwMemSize=0;

   int     i,j;

   int     nStart = (lplrSel ? lplrSel->m_nStartLine : 0);

   int     nEnd =(lplrSel ? lplrSel->m_nEndLine : LineList_GetCount(lpLL)-1);

   int     nTabLevel;

   // calculate memory size required

   for(i = nStart; i <= nEnd; i++) {

      lpLine=LineList_GetLine(lpLL, i);

      if (! lpLine)

         continue;

      dwMemSize += Line_GetTabLevel(lpLine);

      dwMemSize += Line_GetTextLen(lpLine);

      dwMemSize += 2; // add 1 for '\r\n' at the end of each line

   }

   dwMemSize++;        // add 1 for '\0' at the end of string

   if(!(hText = GlobalAlloc(GALLOCFLG, dwMemSize)))

      return NULL;

   if(!(lpszText = (LPOLESTR)GlobalLock(hText)))

      return NULL;

   // put line text to memory

   for(i = nStart; i <= nEnd; i++) {

      lpLine=LineList_GetLine(lpLL, i);

      if (! lpLine)

         continue;

      nTabLevel=Line_GetTabLevel(lpLine);

      for(j = 0; j < nTabLevel; j++)

         *lpszText++='\t';

      Line_GetTextData(lpLine, lpszText);

      while(*lpszText)

         lpszText++;     // advance to end of string

      *lpszText++ = '\r';

      *lpszText++ = '\n';

   }

   GlobalUnlock (hText);

   return hText;

}

/* OutlineDoc_SaveToFile

 * ---------------------

 *

 *      Save the document to a file with the same name as stored in the

 * document

 */

BOOL OutlineDoc_SaveToFile(LPOUTLINEDOC lpOutlineDoc, LPCOLESTR lpszFileName, UINT uFormat, BOOL fRemember)

{

#if defined( OLE_CNTR )

   // Call OLE container specific function instead

   return ContainerDoc_SaveToFile(

         (LPCONTAINERDOC)lpOutlineDoc,

         lpszFileName,

         uFormat,

         fRemember

   );

#else

   LPSTORAGE lpDestStg = NULL;

   HRESULT hrErr;

   BOOL fStatus;

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   if (fRemember) {

      if (lpszFileName) {

         fStatus = OutlineDoc_SetFileName(

               lpOutlineDoc,

               (LPOLESTR)lpszFileName,

               NULL

         );

         if (! fStatus) goto error;

      } else

         lpszFileName = lpOutlineDoc->m_szFileName; // use cur. file name

   } else if (! lpszFileName) {

      goto error;

   }

   hrErr = StgCreateDocfile(

         lpszFileName,

         STGM_READWRITE|STGM_DIRECT|STGM_SHARE_EXCLUSIVE|STGM_CREATE,

         0,

         &lpDestStg

   );

   OleDbgAssertSz(hrErr == NOERROR, "Could not create Docfile");

   if (hrErr != NOERROR)

      goto error;

#if defined( OLE_SERVER )

   /*  OLE2NOTE: we must be sure to write our class ID into our

   **    storage. this information is used by OLE to determine the

   **    class of the data stored in our storage. Even for top

   **    "file-level" objects this information should be written to

   **    the file.

   */

   if(WriteClassStg(lpDestStg, &CLSID_APP) != NOERROR)

      goto error;

#endif

   fStatus = OutlineDoc_SaveSelToStg(

         lpOutlineDoc,

         NULL,

         uFormat,

         lpDestStg,

         FALSE,      /* fSameAsLoad */

         fRemember

   );

   if (! fStatus) goto error;

   OleStdRelease((LPUNKNOWN)lpDestStg);

   if (fRemember)

      OutlineDoc_SetModified(lpOutlineDoc, FALSE, FALSE, FALSE);

#if defined( OLE_SERVER )

   /* OLE2NOTE: (SERVER-ONLY) inform any linking clients that the

   **    document has been saved. in addition, any currently active

   **    pseudo objects should also inform their clients.

   */

   ServerDoc_SendAdvise (

         (LPSERVERDOC)lpOutlineDoc,

         OLE_ONSAVE,

         NULL,   /* lpmkDoc -- not relevant here */

         0       /* advf -- not relevant here */

   );

#endif

   return TRUE;

error:

   if (lpDestStg)

      OleStdRelease((LPUNKNOWN)lpDestStg);

   OutlineApp_ErrorMessage(lpOutlineApp, ErrMsgSaving);

   return FALSE;

#endif  // ! OLE_CNTR

}

/* OutlineDoc_LoadFromFile

 * -----------------------

 *

 *      Load a document from a file

 */

BOOL OutlineDoc_LoadFromFile(LPOUTLINEDOC lpOutlineDoc, LPOLESTR lpszFileName)

{

   LPOUTLINEAPP    lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   LPLINELIST      lpLL = &lpOutlineDoc->m_LineList;

   HRESULT         hrErr;

   SCODE           sc;

   LPSTORAGE       lpSrcStg;

   BOOL            fStatus;

   hrErr = StgOpenStorage(lpszFileName,

         NULL,

#if defined( OLE_CNTR )

         STGM_READWRITE | STGM_TRANSACTED | STGM_SHARE_DENY_WRITE,

#else

         STGM_READ | STGM_SHARE_DENY_WRITE,

#endif

         NULL,

         0,

         &lpSrcStg

   );

   if ((sc = GetScode(hrErr)) == STG_E_FILENOTFOUND) {

      OutlineApp_ErrorMessage(lpOutlineApp, OLESTR("File not found"));

      return FALSE;

   } else if (sc == STG_E_FILEALREADYEXISTS) {

      OutlineApp_ErrorMessage(lpOutlineApp, ErrMsgFormat);

      return FALSE;

   } else if (sc != S_OK) {

      OleDbgOutScode("StgOpenStorage returned", sc);

      OutlineApp_ErrorMessage(

            lpOutlineApp,

            OLESTR("File already in use--could not be opened")

      );

      return FALSE;

   }

   if(! OutlineDoc_LoadFromStg(lpOutlineDoc, lpSrcStg)) goto error;

   fStatus = OutlineDoc_SetFileName(lpOutlineDoc, lpszFileName, lpSrcStg);

   if (! fStatus) goto error;

   OleStdRelease((LPUNKNOWN)lpSrcStg);

   return TRUE;

error:

   OleStdRelease((LPUNKNOWN)lpSrcStg);

   OutlineApp_ErrorMessage(lpOutlineApp, ErrMsgOpening);

   return FALSE;

}

/* OutlineDoc_LoadFromStg

 * ----------------------

 *

 *  Load entire document from an open IStorage pointer (lpSrcStg)

 *      Return TRUE if ok, FALSE if error.

 */

BOOL OutlineDoc_LoadFromStg(LPOUTLINEDOC lpOutlineDoc, LPSTORAGE lpSrcStg)

{

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   HRESULT hrErr;

   BOOL fStatus;

   ULONG nRead;

   LINERANGE lrSel = { 0, 0 };

   LPSTREAM lpLLStm;

   OUTLINEDOCHEADER docRecord;

   OUTLINEDOCHEADER_ONDISK docRecordOnDisk;

   hrErr = lpSrcStg->lpVtbl->OpenStream(

         lpSrcStg,

         OLESTR("LineList"),

         NULL,

         STGM_READ | STGM_SHARE_EXCLUSIVE,

         0,

         &lpLLStm

   );

   if (hrErr != NOERROR) {

      OleDbgOutHResult("Open LineList Stream returned", hrErr);

      goto error;

   }

   /* read OutlineDoc header record */

   hrErr = lpLLStm->lpVtbl->Read(

         lpLLStm,

         (LPVOID)&docRecordOnDisk,

         sizeof(docRecordOnDisk),

         &nRead

   );

   if (hrErr != NOERROR) {

      OleDbgOutHResult("Read OutlineDoc header returned", hrErr);

      goto error;

    }

    //  Transform docRecordOnDisk into docRecord

    //  Compilers should handle aligment correctly

    OLESTRCPY(docRecord.m_szFormatName, docRecordOnDisk.m_szFormatName);

    docRecord.m_narrAppVersionNo[0] = (int) docRecordOnDisk.m_narrAppVersionNo[0];

    docRecord.m_narrAppVersionNo[1] = (int) docRecordOnDisk.m_narrAppVersionNo[1];

    docRecord.m_fShowHeading = (BOOL) docRecordOnDisk.m_fShowHeading;

    docRecord.m_reserved1 = docRecordOnDisk.m_reserved1;

    docRecord.m_reserved2 = docRecordOnDisk.m_reserved2;

    docRecord.m_reserved3 = docRecordOnDisk.m_reserved3;

    docRecord.m_reserved4 = docRecordOnDisk.m_reserved4;

   fStatus = OutlineApp_VersionNoCheck(

         lpOutlineApp,

         docRecord.m_szFormatName,

         docRecord.m_narrAppVersionNo

   );

   /* storage is an incompatible version; file can not be read */

   if (! fStatus)

      goto error;

   lpOutlineDoc->m_heading.m_fShow = docRecord.m_fShowHeading;

#if defined( OLE_SERVER )

   {

      // Load ServerDoc specific data

      LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOutlineDoc;

#if defined( SVR_TREATAS )

      LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

      CLSID       clsid;

      CLIPFORMAT  cfFmt;

      LPOLESTR       lpszType;

#endif  // SVR_TREATAS

      lpServerDoc->m_nNextRangeNo = (ULONG)docRecord.m_reserved1;

#if defined( SVR_TREATAS )

      /* OLE2NOTE: if the Server is capable of supporting "TreatAs"

      **    (aka. ActivateAs), it must read the class that is written

      **    into the storage. if this class is NOT the app's own

      **    class ID, then this is a TreatAs operation. the server

      **    then must faithfully pretend to be the class that is

      **    written into the storage. it must also faithfully write

      **    the data back to the storage in the SAME format as is

      **    written in the storage.

      **

      **    SVROUTL and ISVROTL can emulate each other. they have the

      **    simplification that they both read/write the identical

      **    format. thus for these apps no actual conversion of the

      **    native bits is actually required.

      */

      lpServerDoc->m_clsidTreatAs = CLSID_NULL;

      if (OleStdGetTreatAsFmtUserType(&CLSID_APP, lpSrcStg, &clsid,

                     (CLIPFORMAT FAR*)&cfFmt, (LPOLESTR FAR*)&lpszType)) {

         if (cfFmt == lpOutlineApp->m_cfOutline) {

            // We should perform TreatAs operation

            if (lpServerDoc->m_lpszTreatAsType)

               OleStdFreeString(lpServerDoc->m_lpszTreatAsType, NULL);

            lpServerDoc->m_clsidTreatAs = clsid;

            ((LPOUTLINEDOC)lpServerDoc)->m_cfSaveFormat = cfFmt;

            lpServerDoc->m_lpszTreatAsType = lpszType;

            OleDbgOut3("OutlineDoc_LoadFromStg: TreateAs ==> '");

//          OleDbgOutNoPrefix3(lpServerDoc->m_lpszTreatAsType);

            OleDbgOutNoPrefix3("'\r\n");

         } else {

            // ERROR: we ONLY support TreatAs for CF_OUTLINE format

            OleDbgOut("SvrDoc_PStg_InitNew: INVALID TreatAs Format\r\n");

            OleStdFreeString(lpszType, NULL);

         }

      }

#endif  // SVR_TREATAS

   }

#endif  // OLE_SVR

#if defined( OLE_CNTR )

   {

      // Load ContainerDoc specific data

      LPCONTAINERDOC lpContainerDoc = (LPCONTAINERDOC)lpOutlineDoc;

      lpContainerDoc->m_nNextObjNo = (ULONG)docRecord.m_reserved2;

   }

#endif  // OLE_CNTR

   OutlineDoc_SetRedraw ( lpOutlineDoc, FALSE );

   if(! LineList_LoadFromStg(&lpOutlineDoc->m_LineList, lpSrcStg, lpLLStm))

      goto error;

   if(! OutlineNameTable_LoadFromStg(lpOutlineDoc->m_lpNameTable, lpSrcStg))

      goto error;

   OutlineDoc_SetModified(lpOutlineDoc, FALSE, FALSE, FALSE);

   OutlineDoc_SetSel(lpOutlineDoc, &lrSel);

   OutlineDoc_SetRedraw ( lpOutlineDoc, TRUE );

   OleStdRelease((LPUNKNOWN)lpLLStm);

#if defined( OLE_CNTR )

   {

      LPOLEDOC lpOleDoc = (LPOLEDOC)lpOutlineDoc;

      /* A ContainerDoc keeps its storage open at all times. it is necessary

      *   to AddRef the lpSrcStg in order to hang on to it.

      */

      if (lpOleDoc->m_lpStg) {

         OleStdVerifyRelease((LPUNKNOWN)lpOleDoc->m_lpStg,

               OLESTR("Doc Storage not released properly"));

      }

      lpSrcStg->lpVtbl->AddRef(lpSrcStg);

      lpOleDoc->m_lpStg = lpSrcStg;

   }

#endif      // OLE_CNTR

   return TRUE;

error:

   OutlineDoc_SetRedraw ( lpOutlineDoc, TRUE );

   if (lpLLStm)

      OleStdRelease((LPUNKNOWN)lpLLStm);

   return FALSE;

}

/* OutlineDoc_SaveSelToStg

 * -----------------------

 *

 *      Save the specified selection of document into an IStorage*. All lines

 * within the selection along with any names completely contained within the

 * selection will be written

 *

 *      Return TRUE if ok, FALSE if error

 */

BOOL OutlineDoc_SaveSelToStg(

      LPOUTLINEDOC        lpOutlineDoc,

      LPLINERANGE         lplrSel,

      UINT                uFormat,

      LPSTORAGE           lpDestStg,

      BOOL                fSameAsLoad,

      BOOL                fRemember

)

{

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   HRESULT hrErr = NOERROR;

   LPSTREAM lpLLStm = NULL;

   LPSTREAM lpNTStm = NULL;

   ULONG nWritten;

   BOOL fStatus;

   OUTLINEDOCHEADER docRecord;

   OUTLINEDOCHEADER_ONDISK docRecordOnDisk;

   HCURSOR  hPrevCursor;

   char szAnsiString[256];

#if defined( OLE_VERSION )

   LPOLESTR lpszUserType;

   LPOLEDOC lpOleDoc = (LPOLEDOC)lpOutlineDoc;

   /*  OLE2NOTE: we must be sure to write the information required for

   **    OLE into our docfile. this includes user type

   **    name, data format, etc. Even for top "file-level" objects

   **    this information should be written to the file. Both

   **    containters and servers should write this information.

   */

#if defined( OLE_SERVER ) && defined( SVR_TREATAS )

   LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOutlineDoc;

   /* OLE2NOTE: if the Server is emulating another class (ie.

   **    "TreatAs" aka. ActivateAs), it must write the same user type

   **    name and format that was was originally written into the

   **    storage rather than its own user type name.

   **

   **    SVROUTL and ISVROTL can emulate each other. they have the

   **    simplification that they both read/write the identical

   **    format. thus for these apps no actual conversion of the

   **    native bits is actually required.

   */

   if (! IsEqualCLSID(&lpServerDoc->m_clsidTreatAs, &CLSID_NULL))

      lpszUserType = lpServerDoc->m_lpszTreatAsType;

   else

#endif  // OLE_SERVER && SVR_TREATAS

      lpszUserType = (LPOLESTR)FULLUSERTYPENAME;

   hrErr = WriteFmtUserTypeStg(lpDestStg, (CLIPFORMAT)uFormat, lpszUserType);

   if(hrErr != NOERROR) goto error;

   if (fSameAsLoad) {

      /* OLE2NOTE: we are saving into to same storage that we were

      **    passed an load time. we deliberatly opened the streams we

      **    need (lpLLStm and lpNTStm) at load time, so that we can

      **    robustly save at save time in a low-memory situation.

      **    this is particulary important the embedded objects do NOT

      **    consume additional memory when

      **    IPersistStorage::Save(fSameAsLoad==TRUE) is called.

      */

      LARGE_INTEGER libZero;

      ULARGE_INTEGER ulibZero;

      LISet32( libZero, 0 );

      LISet32( ulibZero, 0 );

      lpLLStm = lpOleDoc->m_lpLLStm;

      /*  because this is the fSameAsLoad==TRUE case, we will save

      **    into the streams that we hold open. we will AddRef the

      **    stream here so that the release below will NOT close the

      **    stream.

      */

      lpLLStm->lpVtbl->AddRef(lpLLStm);

      // truncate the current stream and seek to beginning

      lpLLStm->lpVtbl->SetSize(lpLLStm, ulibZero);

      lpLLStm->lpVtbl->Seek(

            lpLLStm, libZero, STREAM_SEEK_SET, NULL);

      lpNTStm = lpOleDoc->m_lpNTStm;

      lpNTStm->lpVtbl->AddRef(lpNTStm);   // (see comment above)

      // truncate the current stream and seek to beginning

      lpNTStm->lpVtbl->SetSize(lpNTStm, ulibZero);

      lpNTStm->lpVtbl->Seek(

            lpNTStm, libZero, STREAM_SEEK_SET, NULL);

   } else

#endif  // OLE_VERSION

   {

      hrErr = lpDestStg->lpVtbl->CreateStream(

            lpDestStg,

            OLESTR("LineList"),

            STGM_WRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE,

            0,

            0,

            &lpLLStm

      );

      if (hrErr != NOERROR) {

         OleDbgAssertSz(hrErr==NOERROR,"Could not create LineList stream");

         OleDbgOutHResult("LineList CreateStream returned", hrErr);

         goto error;

      }

      hrErr = lpDestStg->lpVtbl->CreateStream(

            lpDestStg,

            OLESTR("NameTable"),

            STGM_WRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE,

            0,

            0,

            &lpNTStm

      );

      if (hrErr != NOERROR) {

         OleDbgAssertSz(hrErr==NOERROR,"Could not create NameTable stream");

         OleDbgOutHResult("NameTable CreateStream returned", hrErr);

         goto error;

      }

   }

   // this may take a while, put up hourglass cursor

   hPrevCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));

   _fmemset((LPOUTLINEDOCHEADER)&docRecord,0,sizeof(OUTLINEDOCHEADER));

   GetClipboardFormatName(

         uFormat,

         szAnsiString,

         256

   );

   A2W(szAnsiString, docRecord.m_szFormatName, lstrlen(szAnsiString)+1);

   OutlineApp_GetAppVersionNo(lpOutlineApp, docRecord.m_narrAppVersionNo);

   docRecord.m_fShowHeading = lpOutlineDoc->m_heading.m_fShow;

#if defined( OLE_SERVER )

   {

      // Store ServerDoc specific data

      LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOutlineDoc;

      docRecord.m_reserved1 = (DWORD)lpServerDoc->m_nNextRangeNo;

   }

#endif

#if defined( OLE_CNTR )

   {

      // Store ContainerDoc specific data

      LPCONTAINERDOC lpContainerDoc = (LPCONTAINERDOC)lpOutlineDoc;

      docRecord.m_reserved2 = (DWORD)lpContainerDoc->m_nNextObjNo;

   }

#endif

   /* write OutlineDoc header record */

    //  Transform docRecord into docRecordOnDisk

    //  Compilers should handle aligment correctly

    OLESTRCPY(docRecordOnDisk.m_szFormatName, docRecord.m_szFormatName);

    docRecordOnDisk.m_narrAppVersionNo[0] = (short) docRecord.m_narrAppVersionNo[0];

    docRecordOnDisk.m_narrAppVersionNo[1] = (short) docRecord.m_narrAppVersionNo[1];

    docRecordOnDisk.m_fShowHeading = (USHORT) docRecord.m_fShowHeading;

    docRecordOnDisk.m_reserved1 = docRecord.m_reserved1;

    docRecordOnDisk.m_reserved2 = docRecord.m_reserved2;

    docRecordOnDisk.m_reserved3 = docRecord.m_reserved3;

    docRecordOnDisk.m_reserved4 = docRecord.m_reserved4;

   hrErr = lpLLStm->lpVtbl->Write(

         lpLLStm,

         (LPVOID)&docRecordOnDisk,

         sizeof(docRecordOnDisk),

         &nWritten

      );

   if (hrErr != NOERROR) {

      OleDbgOutHResult("Write OutlineDoc header returned", hrErr);

      goto error;

    }

   // Save LineList

   /* OLE2NOTE: A ContainerDoc keeps its storage open at all times. It is

   **    necessary to pass the current open storage (lpOleDoc->m_lpStg)

   **    to the LineList_SaveSelToStg method so that currently written data

   **    for any embeddings is also saved to the new destination

   **    storage. The data required by a contained object is both the

   **    ContainerLine information and the associated sub-storage that is

   **    written directly by the embedded object.

   */

   fStatus = LineList_SaveSelToStg(

      &lpOutlineDoc->m_LineList,

         lplrSel,

         uFormat,

#if defined( OLE_CNTR )

         lpOleDoc->m_lpStg,

#else

         NULL,

#endif

         lpDestStg,

         lpLLStm,

         fRemember

   );

   if (! fStatus) goto error;

   // Save associated NameTable

   fStatus = OutlineNameTable_SaveSelToStg(

         lpOutlineDoc->m_lpNameTable,

         lplrSel,

         uFormat,

         lpNTStm

   );

   if (! fStatus) goto error;

   OleStdRelease((LPUNKNOWN)lpLLStm);

   lpOutlineDoc->m_cfSaveFormat = uFormat;  // remember format used to save

   SetCursor(hPrevCursor);     // restore original cursor

   return TRUE;

error:

   if (lpLLStm)

      OleStdRelease((LPUNKNOWN)lpLLStm);

   SetCursor(hPrevCursor);     // restore original cursor

   return FALSE;

}

/* OutlineDoc_Print

 * ----------------

 *  Prints the contents of the list box in HIMETRIC mapping mode. Origin

 *  remains to be the upper left corner and the print proceeds down the

 *  page using a negative y-cordinate.

 *

 */

void OutlineDoc_Print(LPOUTLINEDOC lpOutlineDoc, HDC hDC)

{

   LPLINELIST lpLL = &lpOutlineDoc->m_LineList;

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   WORD    nIndex;

   WORD    nTotal;

   int     dy;

   BOOL    fError = FALSE;

   LPLINE  lpLine;

   RECT    rcLine;

   RECT    rcPix;

   RECT    rcHim;

   RECT    rcWindowOld;

   RECT    rcViewportOld;

   HFONT   hOldFont;

   DOCINFO di;         /* Document information for StartDoc function */

   char    szAnsiStr[256];

   /* Get dimension of page */

   rcPix.left = 0;

   rcPix.top = 0;

   rcPix.right = GetDeviceCaps(hDC, HORZRES);

   rcPix.bottom = GetDeviceCaps(hDC, VERTRES);

   SetDCToDrawInHimetricRect(hDC, (LPRECT)&rcPix, (LPRECT)&rcHim,

         (LPRECT)&rcWindowOld, (LPRECT)&rcViewportOld);

   // Set the default font size, and font face name

   hOldFont = SelectObject(hDC, lpOutlineApp->m_hStdFont);

   /* Get the lines in document */

   nIndex     = 0;

   nTotal  = LineList_GetCount(lpLL);

   /* Create the Cancel dialog */

   // REVIEW: should load dialog title from string resource file

   hWndPDlg = CreateDialog (

         lpOutlineApp->m_hInst,

         "Print",

         lpOutlineApp->m_hWndApp,

         (DLGPROC)PrintDlgProc

   );

   if(!hWndPDlg)

      goto getout;

   /* Allow the app. to inform GDI of the abort function to call */

   if(SetAbortProc(hDC, (ABORTPROC)AbortProc) < 0) {

      fError = TRUE;

      goto getout3;

   }

   /* Disable the main application window */

   EnableWindow (lpOutlineApp->m_hWndApp, FALSE);

   // initialize the rectangle for the first line

   rcLine.left = rcHim.left;

   rcLine.bottom = rcHim.top;

   /* Initialize the document */

   fCancelPrint = FALSE;

   di.cbSize = sizeof(DOCINFO);

   W2A (lpOutlineDoc->m_lpszDocTitle, szAnsiStr, 256);

   di.lpszDocName = szAnsiStr;

   di.lpszOutput = NULL;

   if(StartDoc(hDC, (DOCINFO FAR*)&di) <= 0) {

      fError = TRUE;

      OleDbgOut2("StartDoc error\n");

      goto getout5;

   }

   if(StartPage(hDC) <= 0) {       // start first page

      fError = TRUE;

      OleDbgOut2("StartPage error\n");

      goto getout2;

   }

   /* While more lines print out the text */

   while(nIndex < nTotal) {

      lpLine = LineList_GetLine(lpLL, nIndex);

      if (! lpLine)

         continue;

      dy = Line_GetHeightInHimetric(lpLine);

      /* Reached end of page. Tell the device driver to eject a page */

      if(rcLine.bottom - dy < rcHim.bottom) {

         if (EndPage(hDC) < 0) {

            fError=TRUE;

            OleDbgOut2("EndPage error\n");

            goto getout2;

         }

         // NOTE: Reset the Mapping mode of DC

         SetDCToDrawInHimetricRect(hDC, (LPRECT)&rcPix, (LPRECT)&rcHim,

               (LPRECT)&rcWindowOld, (LPRECT)&rcViewportOld);

         // Set the default font size, and font face name

         SelectObject(hDC, lpOutlineApp->m_hStdFont);

         if (StartPage(hDC) <= 0) {

            fError=TRUE;

            OleDbgOut2("StartPage error\n");

            goto getout2;

         }

         rcLine.bottom = rcHim.top;

      }

      rcLine.top = rcLine.bottom;

      rcLine.bottom -= dy;

      rcLine.right = rcLine.left + Line_GetWidthInHimetric(lpLine);

      /* Print the line */

      Line_Draw(lpLine, hDC, &rcLine, NULL, FALSE /*fHighlight*/);

      OleDbgOut2("a line is drawn\n");

      /* Test and see if the Abort flag has been set. If yes, exit. */

      if (fCancelPrint)

         goto getout2;

      /* Move down the page */

      nIndex++;

   }

   {

      int nCode;

      /* Eject the last page. */

      if((nCode = EndPage(hDC)) < 0) {

#if defined( _DEBUG )

         char szBuf[255];

         wsprintf(szBuf, "EndPage error code is %d\n", nCode);

         OleDbgOut2(szBuf);

#endif

         fError=TRUE;

         goto getout2;

      }

   }

   /* Complete the document. */

   if(EndDoc(hDC) < 0) {

      fError=TRUE;

      OleDbgOut2("EndDoc error\n");

getout2:

      /* Ran into a problem before NEWFRAME? Abort the document */

      AbortDoc(hDC);

   }

getout5:

   /* Re-enable main app. window */

   EnableWindow (lpOutlineApp->m_hWndApp, TRUE);

getout3:

   /* Close the cancel dialog */

   DestroyWindow (hWndPDlg);

getout:

   /* Error? make sure the user knows... */

   if(fError || CommDlgExtendedError())

      OutlineApp_ErrorMessage(lpOutlineApp, ErrMsgPrint);

   SelectObject(hDC, hOldFont);

}

/* OutlineDoc_DialogHelp

 * ---------------------

 *

 *  Show help message for ole2ui dialogs.

 *

 * Parameters:

 *

 *   hDlg      HWND to the dialog the help message came from - use

 *             this in the call to WinHelp/MessageBox so that

 *             activation/focus goes back to the dialog, and not the

 *             main window.

 *

 *   wParam    ID of the dialog (so we know what type of dialog it is).

 */

void OutlineDoc_DialogHelp(HWND hDlg, WPARAM wDlgID)

{

   char szMessageBoxText[64];

   if (!IsWindow(hDlg))  // don't do anything if we've got a bogus hDlg.

    return;

   lstrcpy(szMessageBoxText, "Help Message for ");

   switch (wDlgID)

   {

   case IDD_CONVERT:

      lstrcat(szMessageBoxText, "Convert");

      break;

   case IDD_CHANGEICON:

      lstrcat(szMessageBoxText, "Change Icon");

      break;

   case IDD_INSERTOBJECT:

      lstrcat(szMessageBoxText, "Insert Object");

      break;

   case IDD_PASTESPECIAL:

      lstrcat(szMessageBoxText, "Paste Special");

      break;

   case IDD_EDITLINKS:

      lstrcat(szMessageBoxText, "Edit Links");

      break;

   case IDD_CHANGESOURCE:

      lstrcat(szMessageBoxText, "Change Source");

      break;

   case IDD_INSERTFILEBROWSE:

      lstrcat(szMessageBoxText, "Insert From File Browse");

      break;

   case IDD_CHANGEICONBROWSE:

      lstrcat(szMessageBoxText, "Change Icon Browse");

      break;

   default:

      lstrcat(szMessageBoxText, "Unknown");

      break;

   }

   lstrcat(szMessageBoxText, " Dialog.");

   // You'd probably really a call to WinHelp here.

   MessageBox(hDlg, szMessageBoxText, "Help", MB_OK);

   return;

}

/* OutlineDoc_SetCurrentZoomCommand

 * --------------------------------

 *

 *  Set current zoom level to be checked in the menu.

 *  Set the corresponding scalefactor for the document.

 */

void OutlineDoc_SetCurrentZoomCommand(

      LPOUTLINEDOC        lpOutlineDoc,

      UINT                uCurrentZoom

)

{

   SCALEFACTOR scale;

   if (!lpOutlineDoc)

      return;

   lpOutlineDoc->m_uCurrentZoom = uCurrentZoom;

   switch (uCurrentZoom) {

#if !defined( OLE_CNTR )

         case IDM_V_ZOOM_400:

            scale.dwSxN = (DWORD) 4;

            scale.dwSxD = (DWORD) 1;

            scale.dwSyN = (DWORD) 4;

            scale.dwSyD = (DWORD) 1;

            break;

         case IDM_V_ZOOM_300:

            scale.dwSxN = (DWORD) 3;

            scale.dwSxD = (DWORD) 1;

            scale.dwSyN = (DWORD) 3;

            scale.dwSyD = (DWORD) 1;

            break;

         case IDM_V_ZOOM_200:

            scale.dwSxN = (DWORD) 2;

            scale.dwSxD = (DWORD) 1;

            scale.dwSyN = (DWORD) 2;

            scale.dwSyD = (DWORD) 1;

            break;

#endif      // !OLE_CNTR

         case IDM_V_ZOOM_100:

            scale.dwSxN = (DWORD) 1;

            scale.dwSxD = (DWORD) 1;

            scale.dwSyN = (DWORD) 1;

            scale.dwSyD = (DWORD) 1;

            break;

         case IDM_V_ZOOM_75:

            scale.dwSxN = (DWORD) 3;

            scale.dwSxD = (DWORD) 4;

            scale.dwSyN = (DWORD) 3;

            scale.dwSyD = (DWORD) 4;

            break;

         case IDM_V_ZOOM_50:

            scale.dwSxN = (DWORD) 1;

            scale.dwSxD = (DWORD) 2;

            scale.dwSyN = (DWORD) 1;

            scale.dwSyD = (DWORD) 2;

            break;

         case IDM_V_ZOOM_25:

            scale.dwSxN = (DWORD) 1;

            scale.dwSxD = (DWORD) 4;

            scale.dwSyN = (DWORD) 1;

            scale.dwSyD = (DWORD) 4;

            break;

   }

   OutlineDoc_SetScaleFactor(lpOutlineDoc, (LPSCALEFACTOR)&scale, NULL);

}

/* OutlineDoc_GetCurrentZoomMenuCheck

 * ----------------------------------

 *

 *  Get current zoom level to be checked in the menu.

 */

UINT OutlineDoc_GetCurrentZoomMenuCheck(LPOUTLINEDOC lpOutlineDoc)

{

   return lpOutlineDoc->m_uCurrentZoom;

}

/* OutlineDoc_SetScaleFactor

 * -------------------------

 *

 *  Set the scale factor of the document which will affect the

 *      size of the document on the screen

 *

 * Parameters:

 *

 *   scale      structure containing x and y scales

 */

void OutlineDoc_SetScaleFactor(

      LPOUTLINEDOC        lpOutlineDoc,

      LPSCALEFACTOR       lpscale,

      LPRECT              lprcDoc

)

{

   LPLINELIST      lpLL = OutlineDoc_GetLineList(lpOutlineDoc);

   HWND            hWndLL = LineList_GetWindow(lpLL);

   if (!lpOutlineDoc || !lpscale)

      return;

   InvalidateRect(hWndLL, NULL, TRUE);

   lpOutlineDoc->m_scale = *lpscale;

   LineList_ReScale((LPLINELIST)&lpOutlineDoc->m_LineList, lpscale);

#if defined( USE_HEADING )

   Heading_ReScale((LPHEADING)&lpOutlineDoc->m_heading, lpscale);

#endif

   OutlineDoc_Resize(lpOutlineDoc, lprcDoc);

}

/* OutlineDoc_GetScaleFactor

 * -------------------------

 *

 *  Retrieve the scale factor of the document

 *

 * Parameters:

 *

 */

LPSCALEFACTOR OutlineDoc_GetScaleFactor(LPOUTLINEDOC lpOutlineDoc)

{

   if (!lpOutlineDoc)

      return NULL;

   return (LPSCALEFACTOR)&lpOutlineDoc->m_scale;

}

/* OutlineDoc_SetCurrentMarginCommand

 * ----------------------------------

 *

 *  Set current Margin level to be checked in the menu.

 */

void OutlineDoc_SetCurrentMarginCommand(

      LPOUTLINEDOC        lpOutlineDoc,

      UINT                uCurrentMargin

)

{

   if (!lpOutlineDoc)

      return;

   lpOutlineDoc->m_uCurrentMargin = uCurrentMargin;

   switch (uCurrentMargin) {

      case IDM_V_SETMARGIN_0:

         OutlineDoc_SetMargin(lpOutlineDoc, 0, 0);

         break;

      case IDM_V_SETMARGIN_1:

         OutlineDoc_SetMargin(lpOutlineDoc, 1000, 1000);

         break;

      case IDM_V_SETMARGIN_2:

         OutlineDoc_SetMargin(lpOutlineDoc, 2000, 2000);

         break;

      case IDM_V_SETMARGIN_3:

         OutlineDoc_SetMargin(lpOutlineDoc, 3000, 3000);

         break;

      case IDM_V_SETMARGIN_4:

         OutlineDoc_SetMargin(lpOutlineDoc, 4000, 4000);

         break;

   }

}

/* OutlineDoc_GetCurrentMarginMenuCheck

 * ------------------------------------

 *

 *  Get current Margin level to be checked in the menu.

 */

UINT OutlineDoc_GetCurrentMarginMenuCheck(LPOUTLINEDOC lpOutlineDoc)

{

   return lpOutlineDoc->m_uCurrentMargin;

}

/* OutlineDoc_SetMargin

 * --------------------

 *

 *  Set the left and right margin of the document

 *

 * Parameters:

 *      nLeftMargin  - left margin in Himetric values

 *      nRightMargin - right margin in Himetric values

 */

void OutlineDoc_SetMargin(LPOUTLINEDOC lpOutlineDoc, int nLeftMargin, int nRightMargin)

{

   LPLINELIST lpLL;

   int        nMaxWidthInHim;

   if (!lpOutlineDoc)

      return;

   lpOutlineDoc->m_nLeftMargin = nLeftMargin;

   lpOutlineDoc->m_nRightMargin = nRightMargin;

   lpLL = OutlineDoc_GetLineList(lpOutlineDoc);

   // Force recalculation of Horizontal extent

   nMaxWidthInHim = LineList_GetMaxLineWidthInHimetric(lpLL);

   LineList_SetMaxLineWidthInHimetric(lpLL, -nMaxWidthInHim);

#if defined( INPLACE_CNTR )

   ContainerDoc_UpdateInPlaceObjectRects((LPCONTAINERDOC)lpOutlineDoc, 0);

#endif

   OutlineDoc_ForceRedraw(lpOutlineDoc, TRUE);

}

/* OutlineDoc_GetMargin

 * --------------------

 *

 *  Get the left and right margin of the document

 *

 *  Parameters:

 *      nLeftMargin  - left margin in Himetric values

 *      nRightMargin - right margin in Himetric values

 *

 *  Returns:

 *      low order word  - left margin

 *      high order word - right margin

 */

LONG OutlineDoc_GetMargin(LPOUTLINEDOC lpOutlineDoc)

{

   if (!lpOutlineDoc)

      return 0;

   return MAKELONG(lpOutlineDoc->m_nLeftMargin, lpOutlineDoc->m_nRightMargin);

}

#if defined( USE_HEADING )

/* OutlineDoc_GetHeading

 * ---------------------

 *

 *      Get Heading Object in OutlineDoc

 */

LPHEADING OutlineDoc_GetHeading(LPOUTLINEDOC lpOutlineDoc)

{

   if (!lpOutlineDoc || lpOutlineDoc->m_fDataTransferDoc)

      return NULL;

   else

      return (LPHEADING)&lpOutlineDoc->m_heading;

}

/* OutlineDoc_ShowHeading

 * ----------------------

 *

 *  Show/Hide document row/column headings.

 */

void OutlineDoc_ShowHeading(LPOUTLINEDOC lpOutlineDoc, BOOL fShow)

{

   LPHEADING   lphead = OutlineDoc_GetHeading(lpOutlineDoc);

#if defined( INPLACE_SVR )

   LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpOutlineDoc;

#endif

   if (! lphead)

      return;

   Heading_Show(lphead, fShow);

#if defined( INPLACE_SVR )

   if (lpServerDoc->m_fUIActive) {

      LPINPLACEDATA lpIPData = lpServerDoc->m_lpIPData;

      /* OLE2NOTE: our extents have NOT changed; only our the size of

      **    our object-frame adornments is changing. we can use the

      **    current PosRect and ClipRect and simply resize our

      **    windows WITHOUT informing our in-place container.

      */

      ServerDoc_ResizeInPlaceWindow(

            lpServerDoc,

            (LPRECT)&(lpIPData->rcPosRect),

            (LPRECT)&(lpIPData->rcClipRect)

      );

   } else

#else   // !INPLACE_SVR

   OutlineDoc_Resize(lpOutlineDoc, NULL);

#if defined( INPLACE_CNTR )

   ContainerDoc_UpdateInPlaceObjectRects((LPCONTAINERDOC)lpOutlineDoc, 0);

#endif  // INPLACE_CNTR

#endif  // INPLACE_SVR

   OutlineDoc_ForceRedraw(lpOutlineDoc, TRUE);

}

#endif  // USE_HEADING

/* AbortProc

 * ---------

 *  AborProc is called by GDI print code to check for user abort.

 */

BOOL FAR PASCAL EXPORT AbortProc (HDC hdc, WORD reserved)

{

   MSG msg;

   /* Allow other apps to run, or get abort messages */

   while(! fCancelPrint && PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) {

      if(!hWndPDlg || !IsDialogMessage (hWndPDlg, &msg)) {

         TranslateMessage (&msg);

         DispatchMessage  (&msg);

      }

   }

   return !fCancelPrint;

}

/* PrintDlgProc

 * ------------

 *  Dialog function for the print cancel dialog box.

 *

 *  RETURNS    : TRUE  - OK to abort/ not OK to abort

 *               FALSE - otherwise.

 */

BOOL FAR PASCAL EXPORT PrintDlgProc(

      HWND hwnd,

      WORD msg,

      WORD wParam,

      LONG lParam

)

{

   switch (msg) {

      case WM_COMMAND:

      /* abort printing if the only button gets hit */

         fCancelPrint = TRUE;

         return TRUE;

   }

   return FALSE;

}


OUTLINE.DEF  (OUTLINE Sample)

;;

;;

;;    OLE 2.0 Sample Code

;;

;;    outline.def

;;

;;    Definition file for outline.exe

;;

;;    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

;;

;;

NAME            Outline

DESCRIPTION     'Microsoft OLE 2.0 Sample code--base version'

EXETYPE         WINDOWS

STUB            'WINSTUB.EXE'

CODE            PRELOAD MOVEABLE

DATA            PRELOAD MOVEABLE MULTIPLE

HEAPSIZE        8192

;; NOTE: Do not add exports to this file.  Use __export

;; in your function prototype and definition instead.


OUTLINE.H  (OUTLINE Sample)

/*************************************************************************

**

**    OLE 2 Sample Code

**

**    outline.h

**

**    This file contains file contains data structure defintions,

**    function prototypes, constants, etc. used by the Outline series

**    of sample applications:

**          Outline  -- base version of the app (without OLE functionality)

**          SvrOutl  -- OLE 2.0 Server sample app

**          CntrOutl -- OLE 2.0 Containter (Container) sample app

**          ISvrOtl  -- OLE 2.0 Server sample app

**          CntrOutl -- OLE 2.0 Containter (Container) sample app

**

**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

**

**    For structures which we read from and write to disk we define shadow

**    structures (with the _ONDISK suffix) that allow us to maintain

**    16-bit Windows and Macintosh compatibility.

**

*************************************************************************/

#if !defined( _OUTLINE_H_ )

#define _OUTLINE_H_

#if !defined( RC_INVOKED )

#pragma message ("INCLUDING OUTLINE.H from " __FILE__)

#endif  /* RC_INVOKED */

// use strict ANSI standard (for DVOBJ.H)

#define NONAMELESSUNION

// use system defined bitmap, this line must go before windows.h

#define OEMRESOURCE

#ifdef WIN32

#define EXPORT

#define _fstrchr strchr

#else

#define EXPORT _export

#endif

#define SDI_VERSION         1   // ONLY SDI version is currently supported

#if defined( OLE_SERVER ) || defined( OLE_CNTR )

#define OLE_VERSION         1

#define USE_DRAGDROP        1   // enable drag/drop code in OLE versions

#define USE_MSGFILTER       1   // enable IMessageFilter implementation

#endif

#define USE_HEADING         1   // enable the row/col headings

#define USE_STATUSBAR       1   // enable status bar window

#define USE_FRAMETOOLS      1   // enable the toolbar

#ifndef WIN32   //BUGBUG32

#define USE_CTL3D           1   // enable 3D looking dialogs

#endif

#define STRICT  1

#include <windows.h>

#include <string.h>

#include <commdlg.h>

#include <ole2.h>

#include <ole2ui.h>

#include "outlrc.h"

#define APPMAJORVERSIONNO   3   // major no. incremented for major releases

                        //  (eg. when an incompatible change is made

                        //  to the storage format)

#define APPMINORVERSIONNO   5   // minor no. incremented for minor releases

/* Definition of SCALEFACTOR */

typedef struct tagSCALEFACTOR {

   ULONG       dwSxN;      // numerator in x direction

   ULONG       dwSxD;      // denominator in x direction

   ULONG       dwSyN;      // numerator in y direction

   ULONG       dwSyD;      // denominator in y direction

} SCALEFACTOR, FAR* LPSCALEFACTOR;

#if defined( USE_FRAMETOOLS )

#include "frametls.h"

#endif

#if defined( USE_HEADING )

#include "heading.h"

#endif

/* max line height (in pixels) allowed in a listbox */

#define LISTBOX_HEIGHT_LIMIT    255

#define MAXSTRLEN   80      // max string len in bytes

#define MAXNAMESIZE 30      // max length of names

#define MAXFORMATSIZE   10  // max length of DEFDOCFORMAT (actually size is 5)

#define TABWIDTH        2000 // 2000 in Himetric units, i.e. 2cm

#define DEFFONTPTSIZE   12

#define DEFFONTSIZE     ((DEFFONTPTSIZE*HIMETRIC_PER_INCH)/PTS_PER_INCH)

#define DEFFONTFACE     "Times New Roman"

#ifdef WIN32S

#define OUTLINEDOCFORMAT    OLESTR("Outline32")     // CF_Outline format name

#else

#define OUTLINEDOCFORMAT    OLESTR("Outline")       // CF_Outline format name

#endif

#define IS_FILENAME_DELIM(c)    ( (c) == '\\' || (c) == '/' || (c) == ':' )

// REVIEW: some of these strings should be loaded from a resource file

#define UNTITLED    OLESTR("Outline")   // title used for untitled document

#define HITTESTDELTA    5

/* Macro to get a random integer within a specified range */

#define getrandom( min, max ) ((rand() % (int)(((max)+1) - (min))) + (min))

// REVIEW: should load strings from string resource file

#ifdef TEST32

#define APPFILENAMEFILTER   "Outline Files (*.OLT)|*.olt|All files (*.*)|*.*|"

#define DEFEXTENSION    "olt"           // Default file extension

#else

#define APPFILENAMEFILTER   "Outline Files (*.OLN)|*.oln|All files (*.*)|*.*|"

#define DEFEXTENSION    "oln"           // Default file extension

#endif //TEST32

/* forward type references */

typedef struct tagOUTLINEDOC FAR* LPOUTLINEDOC;

typedef struct tagTEXTLINE FAR* LPTEXTLINE;

typedef enum tagLINETYPE {

   UNKNOWNLINETYPE,

   TEXTLINETYPE,

   CONTAINERLINETYPE

} LINETYPE;

/*************************************************************************

** class LINE

**    The class LINE is an abstract base class. Instances of class LINE

**    are NOT created; only instances of the concrete subclasses of

**    LINE can be created. In the base app version and the OLE 2.0

**    server-only version only TEXTLINE objects can be created. In the

**    OLE 2.0 client app version either TEXTLINE objects or CONTAINERLINE

**    objects can be created. The LINE class has all fields and methods

**    that are common independent of which subclass of LINE is used.

**    Each LINE object that is created in added to the LINELIST of the

**    OUTLINEDOC document.

*************************************************************************/

typedef struct tagLINE {

   LINETYPE    m_lineType;

   UINT        m_nTabLevel;

   UINT        m_nTabWidthInHimetric;

   UINT        m_nWidthInHimetric;

   UINT        m_nHeightInHimetric;

   BOOL        m_fSelected;        // does line have selection feedback

#if defined( USE_DRAGDROP )

   BOOL        m_fDragOverLine;    // does line have drop target feedback

#endif

} LINE, FAR* LPLINE;

/* Line methods (functions) */

void Line_Init(LPLINE lpLine, int nTab, HDC hDC);

void Line_Delete(LPLINE lpLine);

BOOL Line_CopyToDoc(LPLINE lpSrcLine, LPOUTLINEDOC lpDestDoc, int nIndex);

BOOL Line_Edit(LPLINE lpLine, HWND hWndDoc, HDC hDC);

void Line_Draw(

      LPLINE      lpLine,

      HDC         hDC,

      LPRECT      lpRect,

      LPRECT      lpRectWBounds,

      BOOL        fHighlight

);

void Line_DrawToScreen(

      LPLINE      lpLine,

      HDC         hDC,

      LPRECT      lprcPix,

      UINT        itemAction,

      UINT        itemState,

      LPRECT      lprcDevice

);

void Line_DrawSelHilight(LPLINE lpLine, HDC hDC, LPRECT lpRect, UINT itemAction, UINT itemState);

void Line_DrawFocusRect(LPLINE lpLine, HDC hDC, LPRECT lpRect, UINT itemAction, UINT itemState);

void Line_Unindent(LPLINE lpLine, HDC hDC);

void Line_Indent(LPLINE lpLine, HDC hDC);

LINETYPE Line_GetLineType(LPLINE lpLine);

UINT Line_GetTotalWidthInHimetric(LPLINE lpLine);

void Line_SetWidthInHimetric(LPLINE lpLine, int nWidth);

UINT Line_GetWidthInHimetric(LPLINE lpLine);

UINT Line_GetHeightInHimetric(LPLINE lpLine);

void Line_SetHeightInHimetric(LPLINE lpLine, int nHeight);

UINT Line_GetTabLevel(LPLINE lpLine);

int Line_GetTextLen(LPLINE lpLine);

void Line_GetTextData(LPLINE lpLine, LPOLESTR lpszBuf);

BOOL Line_GetOutlineData(LPLINE lpLine, LPTEXTLINE lpBuf);

int Line_CalcTabWidthInHimetric(LPLINE lpLine, HDC hDC);

BOOL Line_SaveToStg(LPLINE lpLine, UINT uFormat, LPSTORAGE lpSrcStg, LPSTORAGE lpDestStg, LPSTREAM lpLLStm, BOOL fRemember);

LPLINE Line_LoadFromStg(LPSTORAGE lpSrcStg, LPSTREAM lpLLStm, LPOUTLINEDOC lpDestDoc);

void Line_DrawDragFeedback(LPLINE lpLine, HDC hDC, LPRECT lpRect, UINT itemState );

BOOL Line_IsSelected(LPLINE lpLine);

/*************************************************************************

** class TEXTLINE : LINE

**    The class TEXTLINE is a concrete subclass of the abstract base

**    class LINE. The TEXTLINE class holds a string that can be edited

**    by the user. In the base app version and the OLE 2.0

**    server-only version only TEXTLINE objects can be created. In the

**    OLE 2.0 client app version either TEXTLINE objects or CONTAINERLINE

**    objects can be created. The TEXTLINE class inherits all fields

**    from the LINE class. This inheritance is achieved by including a

**    member variable of type LINE as the first field in the TEXTLINE

**    structure. Thus a pointer to a TEXTLINE object can be cast to be

**    a pointer to a LINE object.

**    Each TEXTLINE object that is created in added to the LINELIST of

**    the associated OUTLINEDOC document.

*************************************************************************/

typedef struct tagTEXTLINE {

   LINE m_Line;        // TextLine inherits all fields of Line

   UINT m_nLength;

   char m_szText[MAXSTRLEN+1];

} TEXTLINE;

LPTEXTLINE TextLine_Create(HDC hDC, UINT nTab, LPSTR szText);

void TextLine_Init(LPTEXTLINE lpTextLine, int nTab, HDC hDC);

void TextLine_CalcExtents(LPTEXTLINE lpLine, HDC hDC);

void TextLine_SetHeightInHimetric(LPTEXTLINE lpTextLine, int nHeight);

void TextLine_Delete(LPTEXTLINE lpLine);

BOOL TextLine_Edit(LPTEXTLINE lpLine, HWND hWndDoc, HDC hDC);

void TextLine_Draw(

      LPTEXTLINE  lpTextLine,

      HDC         hDC,

      LPRECT      lpRect,

      LPRECT      lpRectWBounds,

      BOOL        fHighlight

);

void TextLine_DrawSelHilight(LPTEXTLINE lpTextLine, HDC hDC, LPRECT lpRect, UINT itemAction, UINT itemState);

BOOL TextLine_Copy(LPTEXTLINE lpSrcLine, LPTEXTLINE lpDestLine);

BOOL TextLine_CopyToDoc(LPTEXTLINE lpSrcLine, LPOUTLINEDOC lpDestDoc, int nIndex);

int TextLine_GetTextLen(LPTEXTLINE lpTextLine);

void TextLine_GetTextData(LPTEXTLINE lpTextLine, LPSTR lpszBuf);

BOOL TextLine_GetOutlineData(LPTEXTLINE lpTextLine, LPTEXTLINE lpBuf);

BOOL TextLine_SaveToStm(LPTEXTLINE lpLine, LPSTREAM lpLLStm);

LPLINE TextLine_LoadFromStg(LPSTORAGE lpSrcStg, LPSTREAM lpLLStm, LPOUTLINEDOC lpDestDoc);

/*************************************************************************

** class LINERANGE

**    The class LINERANGE is a supporting object used to describe a

**    particular range in an OUTLINEDOC. A range is defined by a starting

**    line index and an ending line index.

*************************************************************************/

typedef struct tagLINERANGE {

   signed short    m_nStartLine;

   signed short    m_nEndLine;

} LINERANGE, FAR* LPLINERANGE;

/*************************************************************************

** class OUTLINENAME

**    The class OUTLINENAME stores a particular named selection in the

**    OUTLINEDOC document. The NAMETABLE class holds all of the names

**    defined in a particular OUTLINEDOC document. Each OUTLINENAME

**    object has a string as its key and a starting line index and an

**    ending line index for the named range.

*************************************************************************/

typedef struct tagOUTLINENAME {

   OLECHAR         m_szName[MAXNAMESIZE+1];

   signed short    m_nStartLine;  // must be signed for table update

   signed short    m_nEndLine;    // functions to work

} OUTLINENAME, FAR* LPOUTLINENAME;

void OutlineName_SetName(LPOUTLINENAME lpOutlineName, LPOLESTR lpszName);

void OutlineName_SetSel(LPOUTLINENAME lpOutlineName, LPLINERANGE lplrSel, BOOL fRangeModified);

void OutlineName_GetSel(LPOUTLINENAME lpOutlineName, LPLINERANGE lplrSel);

BOOL OutlineName_SaveToStg(LPOUTLINENAME lpOutlineName, LPLINERANGE lplrSel, UINT uFormat, LPSTREAM lpNTStm, BOOL FAR* lpfNameSaved);

BOOL OutlineName_SaveToStg(LPOUTLINENAME lpOutlineName, LPLINERANGE lplrSel, UINT uFormat, LPSTREAM lpNTStm, BOOL FAR* lpfNameSaved);

BOOL OutlineName_LoadFromStg(LPOUTLINENAME lpOutlineName, LPSTREAM lpNTStm);

/*************************************************************************

** class OUTLINENAMETABLE

**    OUTLINENAMETABLE manages the table of named selections in the

**    OUTLINEDOC document. Each OUTLINENAMETABLE entry has a string as its key

**    and a starting line index and an ending line index for the

**    named range. There is always one instance of OUTLINENAMETABLE for each

**    OUTLINEDOC created.

*************************************************************************/

typedef struct tagOUTLINENAMETABLE {

   HWND        m_hWndListBox;

   int         m_nCount;

} OUTLINENAMETABLE, FAR* LPOUTLINENAMETABLE;

/* OutlineNameTable methods (functions) */

BOOL OutlineNameTable_Init(LPOUTLINENAMETABLE lpOutlineNameTable, LPOUTLINEDOC lpOutlineDoc);

void OutlineNameTable_Destroy(LPOUTLINENAMETABLE lpOutlineNameTable);

void OutlineNameTable_ClearAll(LPOUTLINENAMETABLE lpOutlineNameTable);

LPOUTLINENAME OutlineNameTable_CreateName(LPOUTLINENAMETABLE lpOutlineNameTable);

void OutlineNameTable_AddName(LPOUTLINENAMETABLE lpOutlineNameTable, LPOUTLINENAME lpOutlineName);

void OutlineNameTable_DeleteName(LPOUTLINENAMETABLE lpOutlineNameTable, int nIndex);

int OutlineNameTable_GetNameIndex(LPOUTLINENAMETABLE lpOutlineNameTable, LPOUTLINENAME lpOutlineName);

LPOUTLINENAME OutlineNameTable_GetName(LPOUTLINENAMETABLE lpOutlineNameTable, int nIndex);

LPOUTLINENAME OutlineNameTable_FindName(LPOUTLINENAMETABLE lpOutlineNameTable, LPOLESTR lpszName);

LPOUTLINENAME OutlineNameTable_FindNamedRange(LPOUTLINENAMETABLE lpOutlineNameTable, LPLINERANGE lplrSel);

int OutlineNameTable_GetCount(LPOUTLINENAMETABLE lpOutlineNameTable);

void OutlineNameTable_AddLineUpdate(LPOUTLINENAMETABLE lpOutlineNameTable, int nAddIndex);

void OutlineNameTable_DeleteLineUpdate(LPOUTLINENAMETABLE lpOutlineNameTable, int nDeleteIndex);

BOOL OutlineNameTable_LoadFromStg(LPOUTLINENAMETABLE lpOutlineNameTable, LPSTORAGE lpSrcStg);

BOOL OutlineNameTable_SaveSelToStg(

      LPOUTLINENAMETABLE      lpOutlineNameTable,

      LPLINERANGE             lplrSel,

      UINT                    uFormat,

      LPSTREAM                lpNTStm

);

/*************************************************************************

** class LINELIST

**    The class LINELIST manages the list of Line objects in the

**    OUTLINEDOC document. This class uses a Window's Owner-draw ListBox

**    to hold the list of LINE objects. There is always one instance of

**    LINELIST for each OUTLINEDOC created.

*************************************************************************/

typedef struct tagLINELIST {

   HWND            m_hWndListBox;  // hWnd of OwnerDraw listbox

   int             m_nNumLines;        // number of lines in LineList

   int             m_nMaxLineWidthInHimetric;  // max width of listbox

   LPOUTLINEDOC    m_lpDoc;        // ptr to associated OutlineDoc

   LINERANGE       m_lrSaveSel;    // selection saved on WM_KILLFOCUS

#if defined( USE_DRAGDROP )

   int             m_iDragOverLine;    // line index w/ drop target feedback

#endif

} LINELIST, FAR* LPLINELIST;

/* LineList methods (functions) */

BOOL LineList_Init(LPLINELIST lpLL, LPOUTLINEDOC lpOutlineDoc);

void LineList_Destroy(LPLINELIST lpLL);

void LineList_AddLine(LPLINELIST lpLL, LPLINE lpLine, int nIndex);

void LineList_DeleteLine(LPLINELIST lpLL, int nIndex);

void LineList_ReplaceLine(LPLINELIST lpLL, LPLINE lpLine, int nIndex);

int LineList_GetLineIndex(LPLINELIST lpLL, LPLINE lpLine);

LPLINE LineList_GetLine(LPLINELIST lpLL, int nIndex);

void LineList_SetFocusLine ( LPLINELIST lpLL, WORD wIndex );

BOOL LineList_GetLineRect(LPLINELIST lpLL, int nIndex, LPRECT lpRect);

int LineList_GetFocusLineIndex(LPLINELIST lpLL);

int LineList_GetCount(LPLINELIST lpLL);

BOOL LineList_SetMaxLineWidthInHimetric(

      LPLINELIST lpLL,

      int nWidthInHimetric

);

void LineList_ScrollLineIntoView(LPLINELIST lpLL, int nIndex);

int LineList_GetMaxLineWidthInHimetric(LPLINELIST lpLL);

BOOL LineList_RecalcMaxLineWidthInHimetric(

      LPLINELIST          lpLL,

      int                 nWidthInHimetric

);

void LineList_CalcSelExtentInHimetric(

      LPLINELIST          lpLL,

      LPLINERANGE         lplrSel,

      LPSIZEL             lpsizel

);

HWND LineList_GetWindow(LPLINELIST lpLL);

HDC LineList_GetDC(LPLINELIST lpLL);

void LineList_ReleaseDC(LPLINELIST lpLL, HDC hDC);

void LineList_SetLineHeight(LPLINELIST lpLL,int nIndex,int nHeightInHimetric);

void LineList_ReScale(LPLINELIST lpLL, LPSCALEFACTOR lpscale);

void LineList_SetSel(LPLINELIST lpLL, LPLINERANGE lplrSel);

int LineList_GetSel(LPLINELIST lpLL, LPLINERANGE lplrSel);

void LineList_RemoveSel(LPLINELIST lpLL);

void LineList_RestoreSel(LPLINELIST lpLL);

void LineList_SetRedraw(LPLINELIST lpLL, BOOL fEnableDraw);

void LineList_ForceRedraw(LPLINELIST lpLL, BOOL fErase);

void LineList_ForceLineRedraw(LPLINELIST lpLL, int nIndex, BOOL fErase);

int LineList_CopySelToDoc(

      LPLINELIST              lpSrcLL,

      LPLINERANGE             lplrSel,

      LPOUTLINEDOC            lpDestDoc

);

BOOL LineList_SaveSelToStg(

      LPLINELIST              lpLL,

      LPLINERANGE             lplrSel,

      UINT                    uFormat,

      LPSTORAGE               lpSrcStg,

      LPSTORAGE               lpDestStg,

      LPSTREAM                lpLLStm,

      BOOL                    fRemember

);

BOOL LineList_LoadFromStg(

      LPLINELIST              lpLL,

      LPSTORAGE               lpSrcStg,

      LPSTREAM                lpLLStm

);

#if defined( USE_DRAGDROP )

void LineList_SetFocusLineFromPointl( LPLINELIST lpLL, POINTL pointl );

void LineList_SetDragOverLineFromPointl ( LPLINELIST lpLL, POINTL pointl );

void LineList_Scroll(LPLINELIST lpLL, DWORD dwScrollDir);

int LineList_GetLineIndexFromPointl(LPLINELIST lpLL, POINTL pointl);

void LineList_RestoreDragFeedback(LPLINELIST lpLL);

#endif

LRESULT FAR PASCAL LineListWndProc(

   HWND   hWnd,

   UINT   Message,

   WPARAM wParam,

   LPARAM lParam

);

// Document initialization type

#define DOCTYPE_UNKNOWN     0   // new doc created but not yet initialized

#define DOCTYPE_NEW         1   // init from scratch (new doc)

#define DOCTYPE_FROMFILE    2   // init from a file (open doc)

/*************************************************************************

** class OUTLINEDOC

**    There is one instance of the OutlineDoc class created per

**    document open in the app. The SDI version of the app supports one

**    OUTLINEDOC at a time. The MDI version of the app can manage

**    multiple documents at one time.

*************************************************************************/

/* Definition of OUTLINEDOC */

typedef struct tagOUTLINEDOC {

   LINELIST    m_LineList;         // list of lines in the doc

   LPOUTLINENAMETABLE m_lpNameTable;   // table of names in the doc

   HWND        m_hWndDoc;          // client area window for the Doc

   int         m_docInitType;      // is doc new or loaded from a file?

   BOOL        m_fDataTransferDoc; // is doc created for copy | drag/drop

   CLIPFORMAT  m_cfSaveFormat;      // format used to save the doc

   OLECHAR     m_szFileName[256];  // associated file; "(Untitled)" if none

   LPOLESTR    m_lpszDocTitle;     // name of doc to appear in window title

   BOOL        m_fModified;        // is the doc dirty (needs to be saved)?

   UINT        m_nDisableDraw;     // enable/disable updating the display

   SCALEFACTOR m_scale;            // current scale factor of the doc

   int         m_nLeftMargin;      // left margin in Himetric

   int         m_nRightMargin;     // right margin in Himetric

   UINT        m_uCurrentZoom;     // cur. zoom (used for menu checking)

   UINT        m_uCurrentMargin;   // cur. margin (used for menu checking)

#if defined( USE_HEADING )

   HEADING     m_heading;

#endif

#if defined( USE_FRAMETOOLS )

   LPFRAMETOOLS m_lpFrameTools;    // ptr to frame tools used by this doc

#endif

} OUTLINEDOC;

/* OutlineDoc methods (functions) */

BOOL OutlineDoc_Init(LPOUTLINEDOC lpOutlineDoc, BOOL fDataTransferDoc);

BOOL OutlineDoc_InitNewFile(LPOUTLINEDOC lpOutlineDoc);

LPOUTLINENAMETABLE OutlineDoc_CreateNameTable(LPOUTLINEDOC lpOutlineDoc);

void OutlineDoc_Destroy(LPOUTLINEDOC lpOutlineDoc);

BOOL OutlineDoc_Close(LPOUTLINEDOC lpOutlineDoc, DWORD dwSaveOption);

void OutlineDoc_ShowWindow(LPOUTLINEDOC lpOutlineDoc);

void OutlineDoc_FrameWindowResized(

      LPOUTLINEDOC        lpOutlineDoc,

      LPRECT              lprcFrameRect,

      LPBORDERWIDTHS      lpFrameToolWidths

);

void OutlineDoc_ClearCommand(LPOUTLINEDOC lpOutlineDoc);

void OutlineDoc_CutCommand(LPOUTLINEDOC lpOutlineDoc);

void OutlineDoc_CopyCommand(LPOUTLINEDOC lpOutlineDoc);

void OutlineDoc_ClearAllLines(LPOUTLINEDOC lpOutlineDoc);

LPOUTLINEDOC OutlineDoc_CreateDataTransferDoc(LPOUTLINEDOC lpSrcOutlineDoc);

void OutlineDoc_PasteCommand(LPOUTLINEDOC lpOutlineDoc);

int OutlineDoc_PasteOutlineData(LPOUTLINEDOC lpOutlineDoc, HGLOBAL hOutline, int nStartIndex);

int OutlineDoc_PasteTextData(LPOUTLINEDOC lpOutlineDoc, HGLOBAL hText, int nStartIndex);

void OutlineDoc_AddTextLineCommand(LPOUTLINEDOC lpOutlineDoc);

void OutlineDoc_AddTopLineCommand(

      LPOUTLINEDOC        lpOutlineDoc,

      UINT                nHeightInHimetric

);

void OutlineDoc_EditLineCommand(LPOUTLINEDOC lpOutlineDoc);

void OutlineDoc_IndentCommand(LPOUTLINEDOC lpOutlineDoc);

void OutlineDoc_UnindentCommand(LPOUTLINEDOC lpOutlineDoc);

void OutlineDoc_SetLineHeightCommand(LPOUTLINEDOC lpDoc);

void OutlineDoc_SelectAllCommand(LPOUTLINEDOC lpOutlineDoc);

void OutlineDoc_DefineNameCommand(LPOUTLINEDOC lpOutlineDoc);

void OutlineDoc_GotoNameCommand(LPOUTLINEDOC lpOutlineDoc);

void OutlineDoc_Print(LPOUTLINEDOC lpOutlineDoc, HDC hDC);

BOOL OutlineDoc_SaveToFile(LPOUTLINEDOC lpOutlineDoc, LPCOLESTR lpszFileName, UINT uFormat, BOOL fRemember);

void OutlineDoc_AddLine(LPOUTLINEDOC lpOutlineDoc, LPLINE lpLine, int nIndex);

void OutlineDoc_DeleteLine(LPOUTLINEDOC lpOutlineDoc, int nIndex);

void OutlineDoc_AddName(LPOUTLINEDOC lpOutlineDoc, LPOUTLINENAME lpOutlineName);

void OutlineDoc_DeleteName(LPOUTLINEDOC lpOutlineDoc, int nIndex);

void OutlineDoc_Resize(LPOUTLINEDOC lpDoc, LPRECT lpRect);

LPOUTLINENAMETABLE OutlineDoc_GetNameTable(LPOUTLINEDOC lpOutlineDoc);

LPLINELIST OutlineDoc_GetLineList(LPOUTLINEDOC lpOutlineDoc);

int OutlineDoc_GetNameCount(LPOUTLINEDOC lpOutlineDoc);

int OutlineDoc_GetLineCount(LPOUTLINEDOC lpOutlineDoc);

void OutlineDoc_SetTitle(LPOUTLINEDOC lpOutlineDoc, BOOL fMakeUpperCase);

BOOL OutlineDoc_CheckSaveChanges(

      LPOUTLINEDOC        lpOutlineDoc,

      LPDWORD             lpdwSaveOption

);

BOOL OutlineDoc_IsModified(LPOUTLINEDOC lpOutlineDoc);

void OutlineDoc_SetModified(LPOUTLINEDOC lpOutlineDoc, BOOL fModified, BOOL fDataChanged, BOOL fSizeChanged);

void OutlineDoc_SetRedraw(LPOUTLINEDOC lpOutlineDoc, BOOL fEnableDraw);

BOOL OutlineDoc_LoadFromFile(LPOUTLINEDOC lpOutlineDoc, LPOLESTR szFileName);

BOOL OutlineDoc_SaveSelToStg(

      LPOUTLINEDOC        lpOutlineDoc,

      LPLINERANGE         lplrSel,

      UINT                uFormat,

      LPSTORAGE           lpDestStg,

      BOOL                fSameAsLoad,

      BOOL                fRemember

);

BOOL OutlineDoc_LoadFromStg(LPOUTLINEDOC lpOutlineDoc, LPSTORAGE lpSrcStg);

BOOL OutlineDoc_SetFileName(LPOUTLINEDOC lpOutlineDoc, LPOLESTR lpszFileName, LPSTORAGE lpNewStg);

HWND OutlineDoc_GetWindow(LPOUTLINEDOC lpOutlineDoc);

void OutlineDoc_SetSel(LPOUTLINEDOC lpOutlineDoc, LPLINERANGE lplrSel);

int OutlineDoc_GetSel(LPOUTLINEDOC lpOutlineDoc, LPLINERANGE lplrSel);

void OutlineDoc_ForceRedraw(LPOUTLINEDOC lpOutlineDoc, BOOL fErase);

void OutlineDoc_RenderFormat(LPOUTLINEDOC lpOutlineDoc, UINT uFormat);

void OutlineDoc_RenderAllFormats(LPOUTLINEDOC lpOutlineDoc);

HGLOBAL OutlineDoc_GetOutlineData(LPOUTLINEDOC lpOutlineDoc, LPLINERANGE lplrSel);

HGLOBAL OutlineDoc_GetTextData(LPOUTLINEDOC lpOutlineDoc, LPLINERANGE lplrSel);

void OutlineDoc_DialogHelp(HWND hDlg, WPARAM wDlgID);

void OutlineDoc_SetCurrentZoomCommand(

      LPOUTLINEDOC        lpOutlineDoc,

      UINT                uCurrentZoom

);

UINT OutlineDoc_GetCurrentZoomMenuCheck(LPOUTLINEDOC lpOutlineDoc);

void OutlineDoc_SetScaleFactor(

      LPOUTLINEDOC        lpOutlineDoc,

      LPSCALEFACTOR       lpscale,

      LPRECT              lprcDoc

);

LPSCALEFACTOR OutlineDoc_GetScaleFactor(LPOUTLINEDOC lpDoc);

void OutlineDoc_SetCurrentMarginCommand(

      LPOUTLINEDOC        lpOutlineDoc,

      UINT                uCurrentMargin

);

UINT OutlineDoc_GetCurrentMarginMenuCheck(LPOUTLINEDOC lpOutlineDoc);

void OutlineDoc_SetMargin(LPOUTLINEDOC lpDoc, int nLeftMargin, int nRightMargin);

LONG OutlineDoc_GetMargin(LPOUTLINEDOC lpDoc);

#if defined( USE_FRAMETOOLS )

void OutlineDoc_AddFrameLevelTools(LPOUTLINEDOC lpOutlineDoc);

void OutlineDoc_SetFormulaBarEditText(

      LPOUTLINEDOC            lpOutlineDoc,

      LPLINE                  lpLine

);

void OutlineDoc_SetFormulaBarEditFocus(

      LPOUTLINEDOC            lpOutlineDoc,

      BOOL                    fEditFocus

);

BOOL OutlineDoc_IsEditFocusInFormulaBar(LPOUTLINEDOC lpOutlineDoc);

void OutlineDoc_UpdateFrameToolButtons(LPOUTLINEDOC lpOutlineDoc);

#endif  // USE_FRAMETOOLS

#if defined( USE_HEADING )

LPHEADING OutlineDoc_GetHeading(LPOUTLINEDOC lpOutlineDoc);

void OutlineDoc_ShowHeading(LPOUTLINEDOC lpOutlineDoc, BOOL fShow);

#endif  // USE_HEADING

/*************************************************************************

** class OUTLINEAPP

**    There is one instance of the OUTLINEAPP class created per running

**    application instance. This object holds many fields that could

**    otherwise be organized as global variables.

*************************************************************************/

/* Definition of OUTLINEAPP */

typedef struct tagOUTLINEAPP {

   HWND            m_hWndApp;        // top-level frame window for the App

   HMENU           m_hMenuApp;       // handle to frame level menu for App

   HACCEL          m_hAccelApp;

   HACCEL          m_hAccelFocusEdit;// Accelerator when Edit in Focus

   LPOUTLINEDOC    m_lpDoc;          // main SDI document visible to user

   LPOUTLINEDOC    m_lpClipboardDoc; // hidden doc for snapshot of copied sel

   HWND            m_hWndStatusBar;  // window for the status bar

   HCURSOR         m_hcursorSelCur;  // cursor used to select lines

   HINSTANCE       m_hInst;

   PRINTDLG        m_PrintDlg;

   HFONT           m_hStdFont;       // font used for TextLines

   UINT            m_cfOutline;      // clipboard format for Outline data

   HACCEL          m_hAccel;

   HWND            m_hWndAccelTarget;

   FARPROC         m_ListBoxWndProc; // orig listbox WndProc for subclassing

#if defined ( USE_FRAMETOOLS ) || defined ( INPLACE_CNTR )

   BORDERWIDTHS    m_FrameToolWidths;  // space required by frame-level tools

#endif  // USE_FRAMETOOLS || INPLACE_CNTR

#if defined( USE_FRAMETOOLS )

   FRAMETOOLS      m_frametools;     // frame tools (button & formula bars)

#endif  // USE_FRAMETOOLS

} OUTLINEAPP, FAR* LPOUTLINEAPP;

/* OutlineApp methods (functions) */

BOOL OutlineApp_InitApplication(LPOUTLINEAPP lpOutlineApp, HINSTANCE hInst);

BOOL OutlineApp_InitInstance(LPOUTLINEAPP lpOutlineApp, HINSTANCE hInst, int nCmdShow);

BOOL OutlineApp_ParseCmdLine(LPOUTLINEAPP lpOutlineApp, LPSTR lpszCmdLine, int nCmdShow);

void OutlineApp_Destroy(LPOUTLINEAPP lpOutlineApp);

LPOUTLINEDOC OutlineApp_CreateDoc(

      LPOUTLINEAPP    lpOutlineApp,

      BOOL            fDataTransferDoc

);

HWND OutlineApp_GetWindow(LPOUTLINEAPP lpOutlineApp);

HWND OutlineApp_GetFrameWindow(LPOUTLINEAPP lpOutlineApp);

HINSTANCE OutlineApp_GetInstance(LPOUTLINEAPP lpOutlineApp);

LPOUTLINENAME OutlineApp_CreateName(LPOUTLINEAPP lpOutlineApp);

void OutlineApp_DocUnlockApp(LPOUTLINEAPP lpOutlineApp, LPOUTLINEDOC lpOutlineDoc);

void OutlineApp_InitMenu(LPOUTLINEAPP lpOutlineApp, LPOUTLINEDOC lpDoc, HMENU hMenu);

void OutlineApp_GetFrameRect(LPOUTLINEAPP lpOutlineApp, LPRECT lprcFrameRect);

void OutlineApp_GetClientAreaRect(

      LPOUTLINEAPP        lpOutlineApp,

      LPRECT              lprcClientAreaRect

);

void OutlineApp_GetStatusLineRect(

      LPOUTLINEAPP        lpOutlineApp,

      LPRECT              lprcStatusLineRect

);

void OutlineApp_ResizeWindows(LPOUTLINEAPP lpOutlineApp);

void OutlineApp_ResizeClientArea(LPOUTLINEAPP lpOutlineApp);

void OutlineApp_AboutCommand(LPOUTLINEAPP lpOutlineApp);

void OutlineApp_NewCommand(LPOUTLINEAPP lpOutlineApp);

void OutlineApp_OpenCommand(LPOUTLINEAPP lpOutlineApp);

void OutlineApp_PrintCommand(LPOUTLINEAPP lpOutlineApp);

BOOL OutlineApp_SaveCommand(LPOUTLINEAPP lpOutlineApp);

BOOL OutlineApp_SaveAsCommand(LPOUTLINEAPP lpOutlineApp);

BOOL OutlineApp_CloseAllDocsAndExitCommand(

      LPOUTLINEAPP        lpOutlineApp,

      BOOL                fForceEndSession

);

void OutlineApp_DestroyWindow(LPOUTLINEAPP lpOutlineApp);

#if defined( USE_FRAMETOOLS )

void OutlineApp_SetBorderSpace(

      LPOUTLINEAPP        lpOutlineApp,

      LPBORDERWIDTHS      lpBorderWidths

);

LPFRAMETOOLS OutlineApp_GetFrameTools(LPOUTLINEAPP lpOutlineApp);

void OutlineApp_SetFormulaBarAccel(

      LPOUTLINEAPP            lpOutlineApp,

      BOOL                    fEditFocus

);

#endif  // USE_FRAMETOOLS

void OutlineApp_SetStatusText(LPOUTLINEAPP lpOutlineApp, LPOLESTR lpszMessage);

LPOUTLINEDOC OutlineApp_GetActiveDoc(LPOUTLINEAPP lpOutlineApp);

HMENU OutlineApp_GetMenu(LPOUTLINEAPP lpOutlineApp);

HFONT OutlineApp_GetActiveFont(LPOUTLINEAPP lpOutlineApp);

HDC OutlineApp_GetPrinterDC(LPOUTLINEAPP lpApp);

void OutlineApp_PrinterSetupCommand(LPOUTLINEAPP lpOutlineApp);

void OutlineApp_ErrorMessage(LPOUTLINEAPP lpOutlineApp, LPOLESTR lpszMsg);

void OutlineApp_GetAppVersionNo(LPOUTLINEAPP lpOutlineApp, int narrAppVersionNo[]);

void OutlineApp_GetAppName(LPOUTLINEAPP lpOutlineApp, LPOLESTR lpszAppName);

BOOL OutlineApp_VersionNoCheck(LPOUTLINEAPP lpOutlineApp, LPOLESTR lpszAppName, int narrAppVersionNo[]);

void OutlineApp_SetEditText(LPOUTLINEAPP lpApp);

void OutlineApp_SetFocusEdit(LPOUTLINEAPP lpApp, BOOL bFocusEdit);

BOOL OutlineApp_GetFocusEdit(LPOUTLINEAPP lpApp);

void OutlineApp_ForceRedraw(LPOUTLINEAPP lpOutlineApp, BOOL fErase);

/* struct definition for persistant data storage of OutlineDoc data */

#pragma pack(push, 2)

typedef struct tagOUTLINEDOCHEADER_ONDISK {

        OLECHAR     m_szFormatName[32];

        short       m_narrAppVersionNo[2];

        USHORT      m_fShowHeading;

        DWORD       m_reserved1;            // space reserved for future use

        DWORD       m_reserved2;            // space reserved for future use

        DWORD       m_reserved3;            // space reserved for future use

        DWORD       m_reserved4;            // space reserved for future use

} OUTLINEDOCHEADER_ONDISK, FAR* LPOUTLINEDOCHEADER_ONDISK;

#pragma pack(pop)

typedef struct tagOUTLINEDOCHEADER {

   OLECHAR     m_szFormatName[32];

   int         m_narrAppVersionNo[2];

   BOOL        m_fShowHeading;

   DWORD       m_reserved1;            // space reserved for future use

   DWORD       m_reserved2;            // space reserved for future use

   DWORD       m_reserved3;            // space reserved for future use

   DWORD       m_reserved4;            // space reserved for future use

} OUTLINEDOCHEADER, FAR* LPOUTLINEDOCHEADER;

#pragma pack(push,2)

typedef struct tagLINELISTHEADER_ONDISK {

        USHORT      m_nNumLines;

        DWORD       m_reserved1;            // space reserved for future use

        DWORD       m_reserved2;            // space reserved for future use

} LINELISTHEADER_ONDISK, FAR* LPLINELISTHEADER_ONDISK;

#pragma pack(pop)

typedef struct tagLINELISTHEADER {

   int         m_nNumLines;

   DWORD       m_reserved1;            // space reserved for future use

   DWORD       m_reserved2;            // space reserved for future use

} LINELISTHEADER, FAR* LPLINELISTHEADER;

#pragma pack(push,2)

typedef struct tagLINERECORD_ONDISK {

        USHORT      m_lineType;

        USHORT      m_nTabLevel;

        USHORT      m_nTabWidthInHimetric;

        USHORT      m_nWidthInHimetric;

        USHORT      m_nHeightInHimetric;

        DWORD       m_reserved;         // space reserved for future use

} LINERECORD_ONDISK, FAR* LPLINERECORD_ONDISK;

#pragma pack(pop)

typedef struct tagLINERECORD {

   LINETYPE    m_lineType;

   UINT        m_nTabLevel;

   UINT        m_nTabWidthInHimetric;

   UINT        m_nWidthInHimetric;

   UINT        m_nHeightInHimetric;

   DWORD       m_reserved;         // space reserved for future use

} LINERECORD, FAR* LPLINERECORD;

/* Function prototypes in main.c */

int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

                  LPSTR lpszCmdLine, int nCmdShow);

BOOL MyTranslateAccelerator(LPMSG lpmsg);

int GetAccelItemCount(HACCEL hAccel);

LRESULT CALLBACK EXPORT AppWndProc(HWND hWnd, UINT Message, WPARAM wParam,

                  LPARAM lParam);

LRESULT CALLBACK EXPORT DocWndProc(HWND hWnd, UINT Message, WPARAM wParam,

                  LPARAM lParam);

/* Function prototypes in outldlgs.c */

BOOL InputTextDlg(HWND hWnd, LPSTR lpszText, LPSTR lpszDlgTitle);

BOOL CALLBACK EXPORT AddEditDlgProc(HWND, UINT, WPARAM, LPARAM);

BOOL CALLBACK EXPORT SetLineHeightDlgProc(HWND hDlg, UINT Message, WPARAM wParam, LPARAM lParam);

BOOL CALLBACK EXPORT DefineNameDlgProc(HWND, UINT, WPARAM, LPARAM);

BOOL CALLBACK EXPORT GotoNameDlgProc(HWND, UINT, WPARAM, LPARAM);

void NameDlg_LoadComboBox(LPOUTLINENAMETABLE lpOutlineNameTable,HWND hCombo);

void NameDlg_LoadListBox(LPOUTLINENAMETABLE lpOutlineNameTable,HWND hListBox);

void NameDlg_AddName(HWND hCombo, LPOUTLINEDOC lpOutlineDoc, LPOLESTR lpszName, LPLINERANGE lplrSel);

void NameDlg_UpdateName(HWND hCombo, LPOUTLINEDOC lpOutlineDoc, int nIndex, LPOLESTR lpszName, LPLINERANGE lplrSel);

void NameDlg_DeleteName(HWND hCombo, LPOUTLINEDOC lpOutlineDoc, UINT nIndex);

BOOL CALLBACK EXPORT AboutDlgProc(HWND hDlg, UINT Message, WPARAM wParam, LPARAM lParam);

/* Function prototypes in outldata.c */

LPVOID New(DWORD lSize);

void Delete(LPVOID p);

/* Function prototypes in outlprnt.c */

BOOL CALLBACK EXPORT AbortProc (HDC hdc, WORD reserved);

BOOL CALLBACK EXPORT PrintDlgProc(HWND hwnd, WORD msg, WORD wParam, LONG lParam);

/* Function prototypes in debug.c */

void SetDebugLevelCommand(void);

void TraceDebug(HWND, int);

/*************************************************************************

** DEBUG ASSERTION ROUTINES

*************************************************************************/

#ifdef DBG

#include <assert.h>

#define FnAssert(lpstrExpr, lpstrMsg, lpstrFileName, iLine)     \

        (_assert(lpstrMsg ? lpstrMsg : lpstrExpr,               \

                 lpstrFileName,                                 \

                 iLine), NOERROR)

#endif //DBG

#if defined( OLE_VERSION )

#include "oleoutl.h"

#endif  // OLE_VERSION

#endif // _OUTLINE_H_


OUTLINE.MK  (OUTLINE Sample)

#

# Makefile : Builds the OLE 2.0 Outline series sample apps

#

!include <$(MSTOOLS)\samples\ole\include\olesampl.mak>

all: $(APP).exe

OLE_FLAGS = -DOLE2FINAL -DWIN32S

!ifndef NO_DEBUG

OLE_FLAGS = $(OLE_FLAGS) -DDBG -D_DEBUG -DOLE2SHIP

!endif

OLELIBS   = ole32.lib uuid.lib oleaut32.lib ole2ui.lib gizmobar.lib bttncur.lib

PCHFLAGS  = -Yuoutline.h -Fp$(APP).pch

COMMONINCL =    outline.h frametls.h outlrc.h status.h cntroutl.h cntrrc.h svroutl.h oleoutl.h

!if "$(USE_MSGFILTER)"=="1"

OLE_FLAGS  = $(OLE_FLAGS) /DUSE_MSGFILTER

!endif

PRECOMPOBJ = $(APP).obj

##########################################################################

#

# main obj lists; add new obj files here

#

!if "$(APP)" == "cntroutl"

OLE_FLAGS = $(OLE_FLAGS) /DOLE_CNTR

APP_OBJS = main.obj memmgr.obj status.obj frametls.obj \

       dialogs.obj debug.obj \

       outlapp.obj outldoc.obj heading.obj \

       outllist.obj outlline.obj outltxtl.obj \

       outlntbl.obj outlname.obj \

       oleapp.obj oledoc.obj classfac.obj debug2.obj \

       dragdrop.obj clipbrd.obj linking.obj \

       cntrbase.obj cntrline.obj

!else

!if "$(APP)" == "svroutl"

OLE_FLAGS = $(OLE_FLAGS) /DOLE_SERVER

APP_OBJS = main.obj memmgr.obj status.obj frametls.obj \

       dialogs.obj debug.obj \

       outlapp.obj outldoc.obj heading.obj \

       outllist.obj outlline.obj outltxtl.obj \

       outlntbl.obj outlname.obj \

       oleapp.obj oledoc.obj classfac.obj debug2.obj \

       dragdrop.obj clipbrd.obj linking.obj \

       svrbase.obj svrpsobj.obj

!else

!if "$(APP)" == "icntrotl"

OLE_FLAGS = $(OLE_FLAGS) /DOLE_CNTR /DINPLACE_CNTR

APP_OBJS = main.obj memmgr.obj status.obj frametls.obj \

       dialogs.obj debug.obj \

       outlapp.obj outldoc.obj heading.obj \

       outllist.obj outlline.obj outltxtl.obj \

       outlntbl.obj outlname.obj \

       oleapp.obj oledoc.obj classfac.obj debug2.obj \

       dragdrop.obj clipbrd.obj linking.obj \

       cntrbase.obj cntrline.obj cntrinpl.obj

!else

!if "$(APP)" == "isvrotl"

OLE_FLAGS = $(OLE_FLAGS) /DOLE_SERVER /DINPLACE_SVR

APP_OBJS = main.obj memmgr.obj status.obj frametls.obj \

       dialogs.obj debug.obj \

       outlapp.obj outldoc.obj heading.obj \

       outllist.obj outlline.obj outltxtl.obj \

       outlntbl.obj outlname.obj \

       oleapp.obj oledoc.obj classfac.obj debug2.obj \

       dragdrop.obj clipbrd.obj linking.obj \

       svrbase.obj svrpsobj.obj svrinpl.obj

!else

APP_OBJS = main.obj memmgr.obj status.obj frametls.obj \

       dialogs.obj debug.obj \

       outlapp.obj outldoc.obj heading.obj \

       outllist.obj outlline.obj outltxtl.obj debug2.obj \

       outlntbl.obj outlname.obj

!endif

!endif

!endif

!endif

##########################################################################

#

# create precomiled header

#

$(APP).pch : $(APP).c $(COMMONINCL)

    @echo Precompiling outline.h ...

    $(cc) $(cflags) $(cvars) $(cdebug) $(OLE_FLAGS) -Ycoutline.h -Fp$(APP).pch -Fo$(APP) $(APP).c

##########################################################################

#

# link/res commands

$(APP).exe: $(APP).pch $(APP_OBJS) $(APP).def $(APP).res ..\lib\gizmobar.lib ..\lib\bttncur.lib

    $(link) $(linkdebug) $(guilflags) $(PRECOMPOBJ) $(APP_OBJS) $(APP).res -out:$@ -map:$*.map $(OLELIBS) $(guilibsdll) advapi32.lib shell32.lib

    if not exist ..\bin mkdir ..\bin

    copy $(APP).exe ..\bin

$(APP).res: $(APP).rc outlrc.h cntrrc.h dialogs.dlg debug.rc

    rc -r -DWIN32 $(RCFLAGS) -fo$@ $(APP).rc

##########################################################################

#

# build rules for src directory

#

.c.obj:

    $(cc) $(cflags) $(cvars) $(cdebug) $(OLE_FLAGS) $(PCHFLAGS) $*.c

##########################################################################

#

# clean (erase) generated files

clean:

    -del *.obj

    -del *.res

    -del *.exe

    -del *.map

    -del *.pch

#########################################################

# Dependencies

#########################################################

main.obj : $(COMMONINCL)

    $(cc) $(cflags) $(cvars) $(cdebug) $(OLE_FLAGS) main.c

outlapp.obj : $(COMMONINCL)

outldoc.obj : $(COMMONINCL)

outllist.obj : $(COMMONINCL)

outlline.obj : $(COMMONINCL)

outltxtl.obj : $(COMMONINCL)

outlntbl.obj : $(COMMONINCL)

outlname.obj : $(COMMONINCL)

classfac.obj : $(COMMONINCL)

oleapp.obj : $(COMMONINCL)

oledoc.obj : $(COMMONINCL)

dragdrop.obj : $(COMMONINCL)

clipbrd.obj : $(COMMONINCL)

linking.obj : $(COMMONINCL)

cntrbase.obj : $(COMMONINCL)

cntrline.obj : $(COMMONINCL)

cntrinpl.obj : $(COMMONINCL)

svrpsobj.obj : $(COMMONINCL)

svrinpl.obj : $(COMMONINCL)

svrbase.obj : $(COMMONINCL)

status.obj : $(COMMONINCL) message.h status.h

memmgr.obj :

    $(cc) $(cflags) $(cvars) $(cdebug) $(OLE_FLAGS)  memmgr.c

frametls.obj : $(COMMONINCL)

heading.obj : $(COMMONINCL)

dialogs.obj : $(COMMONINCL)

debug.obj : $(COMMONINCL)

debug2.obj : $(COMMONINCL)


OUTLINE.RC  (OUTLINE Sample)

/*************************************************************************

**

**    OLE 2.0 Sample Code

**

**    outline.rc

**

**    Resource file for outline.exe

**

**	  (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

**

*************************************************************************/

#include "windows.h"

#include "outlrc.h"

SelCur    CURSOR selcross.cur

OutlineMenu MENU

  BEGIN

    POPUP  "&File"

      BEGIN

        MENUITEM "&New", IDM_F_NEW

        MENUITEM "&Open...\t  Ctrl+F12", IDM_F_OPEN

        MENUITEM "&Save\t  Shift+F12", IDM_F_SAVE

        MENUITEM "Save &As...\t  F12", IDM_F_SAVEAS

        MENUITEM SEPARATOR

        MENUITEM "&Print...\t  Ctrl+Shift+F12", IDM_F_PRINT

        MENUITEM "Printer Se&tup...", IDM_F_PRINTERSETUP

        MENUITEM SEPARATOR

        MENUITEM "E&xit\t  Alt+F4", IDM_F_EXIT

      END

    POPUP  "&Edit"

      BEGIN

        MENUITEM "&Undo", IDM_E_UNDO

        MENUITEM SEPARATOR

        MENUITEM "Cu&t\t  Ctrl+X", IDM_E_CUT

        MENUITEM "&Copy\t  Ctrl+C", IDM_E_COPY

        MENUITEM "&Paste\t  Ctrl+V", IDM_E_PASTE

        MENUITEM "Cl&ear\t  Del", IDM_E_CLEAR

        MENUITEM SEPARATOR

        MENUITEM "Select A&ll\t  Ctrl+A", IDM_E_SELECTALL

      END

POPUP  "O&utline"

  BEGIN

        POPUP  "&Zoom"

          BEGIN

            MENUITEM "&400%", IDM_V_ZOOM_400

            MENUITEM "&300%", IDM_V_ZOOM_300

            MENUITEM "&200%", IDM_V_ZOOM_200

            MENUITEM "&100%", IDM_V_ZOOM_100

            MENUITEM "&75%", IDM_V_ZOOM_75

            MENUITEM "&50%", IDM_V_ZOOM_50

            MENUITEM "&25%", IDM_V_ZOOM_25

          END

        POPUP  "&Left and Right margins"

          BEGIN

            MENUITEM "&nil", IDM_V_SETMARGIN_0

            MENUITEM "&1 cm", IDM_V_SETMARGIN_1

            MENUITEM "&2 cm", IDM_V_SETMARGIN_2

            MENUITEM "&3 cm", IDM_V_SETMARGIN_3

            MENUITEM "&4 cm", IDM_V_SETMARGIN_4

          END

        POPUP "Add &Top Line"

  BEGIN

    MENUITEM "&1 cm", IDM_V_ADDTOP_1

    MENUITEM "&2 cm", IDM_V_ADDTOP_2

    MENUITEM "&3 cm", IDM_V_ADDTOP_3

    MENUITEM "&4 cm", IDM_V_ADDTOP_4

  END

  END

    POPUP  "&Line"

      BEGIN

        MENUITEM "&Add Line\t  Enter", IDM_L_ADDLINE

        MENUITEM "E&dit Line\t  Alt+Enter", IDM_L_EDITLINE

        MENUITEM SEPARATOR

        MENUITEM "&Indent Line\t  Tab", IDM_L_INDENTLINE

        MENUITEM "U&nindent Line\t  Shift+Tab", IDM_L_UNINDENTLINE

MENUITEM SEPARATOR

MENUITEM "&Set Line Height...", IDM_L_SETLINEHEIGHT

      END

    POPUP  "&Name"

      BEGIN

        MENUITEM "&Define Name...", IDM_N_DEFINENAME

        MENUITEM "&Goto Name...", IDM_N_GOTONAME

      END

    POPUP  "&Options"

      BEGIN

        POPUP  "&Button Bar Display"

          BEGIN

            MENUITEM "At &Top", IDM_O_BB_TOP

            MENUITEM "At &Bottom", IDM_O_BB_BOTTOM

            MENUITEM "&Popup", IDM_O_BB_POPUP

            MENUITEM "&Hide", IDM_O_BB_HIDE

          END

        POPUP  "&Formula Bar Display"

          BEGIN

            MENUITEM "At &Top", IDM_O_FB_TOP

            MENUITEM "At &Bottom", IDM_O_FB_BOTTOM

            MENUITEM "&Popup", IDM_O_FB_POPUP

          END

        POPUP  "&Row and Column Heading"

          BEGIN

            MENUITEM "&Show", IDM_O_HEAD_SHOW

            MENUITEM "&Hide", IDM_O_HEAD_HIDE

          END

      END

    POPUP  "&Help"

      BEGIN

        MENUITEM "&About...", IDM_H_ABOUT

      END

  END

OutlineAccel ACCELERATORS

  BEGIN

    VK_F12, IDM_F_OPEN, VIRTKEY, CONTROL

    VK_F12, IDM_F_SAVE, VIRTKEY, SHIFT

    VK_F12, IDM_F_SAVEAS, VIRTKEY

    VK_F12, IDM_F_PRINT, VIRTKEY, CONTROL, SHIFT

    "x", IDM_E_CUT, VIRTKEY, CONTROL

    "c", IDM_E_COPY, VIRTKEY, CONTROL

    "v", IDM_E_PASTE, VIRTKEY, CONTROL

    VK_DELETE, IDM_E_CLEAR, VIRTKEY

    VK_RETURN, IDM_L_ADDLINE, VIRTKEY

    VK_RETURN, IDM_L_EDITLINE, VIRTKEY, ALT

    VK_TAB, IDM_L_INDENTLINE, VIRTKEY

    VK_TAB, IDM_L_UNINDENTLINE, VIRTKEY, SHIFT

    "a", IDM_E_SELECTALL, VIRTKEY, CONTROL

    ; old conventions for editing

    VK_INSERT, IDM_E_COPY, VIRTKEY, CONTROL

    VK_DELETE, IDM_E_CUT, VIRTKEY, SHIFT

    VK_INSERT, IDM_E_PASTE, VIRTKEY, SHIFT

    VK_F2, IDM_F2, VIRTKEY

  END

; Same as OutlineAccel but without Delete

; used when edit control of Formula Bar in focus

;

OutlineAccelFocusEdit ACCELERATORS

  BEGIN

    VK_F12, IDM_F_OPEN, VIRTKEY, CONTROL

    VK_F12, IDM_F_SAVE, VIRTKEY, SHIFT

    VK_F12, IDM_F_SAVEAS, VIRTKEY

    VK_F12, IDM_F_PRINT, VIRTKEY, CONTROL, SHIFT

    "x", IDM_E_CUT, VIRTKEY, CONTROL

    "c", IDM_E_COPY, VIRTKEY, CONTROL

    "v", IDM_E_PASTE, VIRTKEY, CONTROL

    VK_RETURN, IDM_L_ADDLINE, VIRTKEY

    VK_RETURN, IDM_L_EDITLINE, VIRTKEY, ALT

    VK_TAB, IDM_L_INDENTLINE, VIRTKEY

    VK_TAB, IDM_L_UNINDENTLINE, VIRTKEY, SHIFT

"a", IDM_E_SELECTALL, VIRTKEY, CONTROL

VK_ESCAPE, IDM_FB_CANCEL, VIRTKEY

    ; old conventions for editing

    VK_INSERT, IDM_E_COPY, VIRTKEY, CONTROL

    VK_DELETE, IDM_E_CUT, VIRTKEY, SHIFT

    VK_INSERT, IDM_E_PASTE, VIRTKEY, SHIFT

  END

OutlineIcon ICON outline.ico

Image72     BITMAP      image72.bmp

Image96     BITMAP      image96.bmp

Image120    BITMAP      image120.bmp

LogoBitmap  BITMAP      ole2.bmp

#include "DIALOGS.DLG"


OUTLINE.REG  (OUTLINE Sample)

REGEDIT

(the above line used as a quick check that we are indeed a registration script)

/*************************************************************************

** REGISTRATION INFORMATION FOR ALL OUTLINE SERIES APPLICATIONS

*************************************************************************/

ALL LINES THAT DON'T START WITH 'HKEY_CLASSES_ROOT' ARE COMMENTS.

THIS FILE CONSISTS OF A LIST OF <key> <value> PAIRS. THE key AND value SHOULD

BE SEPERATED BY A " = " mark (note spaces).

*

--- VERSIONLESS PROGID ROOT-KEY INFORMATION

    ---------------------------------------

--- ISVROTL is used as the current version of an OLEOutline server

HKEY_CLASSES_ROOT\OLEOutline = Ole 2.0 In-Place Server Outline

HKEY_CLASSES_ROOT\OLEOutline\CLSID = {00000402-0000-0000-C000-000000000046}

HKEY_CLASSES_ROOT\OLEOutline\CurVer = OLE2ISvrOtl

HKEY_CLASSES_ROOT\OLEOutline\CurVer\Insertable

/*************************************************************************

** REGISTRATION ENTRY FOR SVROUTL.EXE

*************************************************************************/

--- PROGID ROOT-KEY INFORMATION

    ---------------------------

HKEY_CLASSES_ROOT\OLE2SvrOutl = Ole 2.0 Server Sample Outline

HKEY_CLASSES_ROOT\OLE2SvrOutl\CLSID = {00000400-0000-0000-C000-000000000046}

--- SVROUTL is marked as insertable so it appears in the InsertObject dialog

HKEY_CLASSES_ROOT\OLE2SvrOutl\Insertable

--- OLE 1.0 COMPATIBILITY INFORMATION

    ---------------------------------

HKEY_CLASSES_ROOT\OLE2SvrOutl\protocol\StdFileEditing\verb\0 = &Edit

HKEY_CLASSES_ROOT\OLE2SvrOutl\protocol\StdFileEditing\server = svroutl.exe

--- WINDOWS 3.1 SHELL INFORMATION

    -----------------------------

HKEY_CLASSES_ROOT\OLE2SvrOutl\Shell\Print\Command = svroutl.exe %1

HKEY_CLASSES_ROOT\OLE2SvrOutl\Shell\Open\Command = svroutl.exe %1

--- OLE 2.0 CLSID ENTRY INFORMATION

    ------------------------------

HKEY_CLASSES_ROOT\CLSID\{00000400-0000-0000-C000-000000000046} = Ole 2.0 Server Sample Outline

HKEY_CLASSES_ROOT\CLSID\{00000400-0000-0000-C000-000000000046}\ProgID = OLE2SvrOutl

--- OLE 2.0 OBJECT HANDLER/EXE INFORMATION

    --------------------------------------

HKEY_CLASSES_ROOT\CLSID\{00000400-0000-0000-C000-000000000046}\InprocHandler32 = ole32.dll

HKEY_CLASSES_ROOT\CLSID\{00000400-0000-0000-C000-000000000046}\LocalServer32 = svroutl.exe

--- VERB MENU SUPPORT

    -----------------

--- Verb 0: "Edit", MF_UNCHECKED | MF_ENABLED, OLEVERBATTRIB_ONCONTAINERMENU

HKEY_CLASSES_ROOT\CLSID\{00000400-0000-0000-C000-000000000046}\Verb\0 = &Edit,0,2

--- This class should appear in Insert New Object list

HKEY_CLASSES_ROOT\CLSID\{00000400-0000-0000-C000-000000000046}\Insertable

--- USER TYPE NAMES

    ---------------

--- ShortName (NOTE: max 15 chars) = Server Outline

HKEY_CLASSES_ROOT\CLSID\{00000400-0000-0000-C000-000000000046}\AuxUserType\2 = Outline

--- AppName = Ole 2.0 Outline Server

HKEY_CLASSES_ROOT\CLSID\{00000400-0000-0000-C000-000000000046}\AuxUserType\3 = Ole 2.0 Outline Server

--- ICON DEFINITION

    ---------------

HKEY_CLASSES_ROOT\CLSID\{00000400-0000-0000-C000-000000000046}\DefaultIcon = svroutl.exe,0

--- DATA FORMATS SUPPORTED

    ----------------------

--- Default File Format = CF_Outline

HKEY_CLASSES_ROOT\CLSID\{00000400-0000-0000-C000-000000000046}\DataFormats\DefaultFile = Outline

--- Format 0 = CF_OUTLINE, DVASPECT_CONTENT, TYMED_HGLOBAL, DATADIR_BOTH

HKEY_CLASSES_ROOT\CLSID\{00000400-0000-0000-C000-000000000046}\DataFormats\GetSet\0 = Outline,1,1,3

--- Format 1 = CF_TEXT, DVASPECT_CONTENT, TYMED_HGLOBAL, DATADIR_BOTH

HKEY_CLASSES_ROOT\CLSID\{00000400-0000-0000-C000-000000000046}\DataFormats\GetSet\1 = 1,1,1,3

--- Format 2 = CF_METAFILEPICT, DVASPECT_CONTENT, TYMED_MFPICT, DATADIR_GET

HKEY_CLASSES_ROOT\CLSID\{00000400-0000-0000-C000-000000000046}\DataFormats\GetSet\2 = 3,1,32,1

--- Format 3 = CF_METAFILEPICT, DVASPECT_ICON, TYMED_MFPICT, DATADIR_GET

HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\DataFormats\GetSet\3 = 3,4,32,1

--- MISC STATUS SUPPORTED

    ---------------------

/* DVASPECT_CONTENT = OLEMISC_RENDERINGISDEVICEINDEPENDENT */

HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\MiscStatus = 512

--- CONVERSION FORMATS SUPPORTED

    ----------------------------

--- Readable Main formats: CF_OUTLINE, CF_TEXT

HKEY_CLASSES_ROOT\CLSID\{00000400-0000-0000-C000-000000000046}\Conversion\Readable\Main = Outline

HKEY_CLASSES_ROOT\CLSID\{00000400-0000-0000-C000-000000000046}\Conversion\Readwritable\Main = Outline

/*************************************************************************

** REGISTRATION ENTRY FOR CNTROUTL.EXE

*************************************************************************/

ENTRIES FOR Ole 2.0 Container Sample Outline

--- PROGID ROOT-KEY INFORMATION

    ---------------------------

    NOTE: CNTROUTL must have a ProgID assigned for the Windows 3.1 Shell

    file associations and Packager to function correctly.

HKEY_CLASSES_ROOT\OLE2CntrOutl = Ole 2.0 Container Sample Outline

HKEY_CLASSES_ROOT\OLE2CntrOutl\Clsid = {00000401-0000-0000-C000-000000000046}

--- WINDOWS 3.1 SHELL INFORMATION

    -----------------------------

HKEY_CLASSES_ROOT\OLE2CntrOutl\Shell\Print\Command = cntroutl.exe %1

HKEY_CLASSES_ROOT\OLE2CntrOutl\Shell\Open\Command = cntroutl.exe %1

--- OLE 2.0 CLSID ENTRY INFORMATION

    -------------------------------

HKEY_CLASSES_ROOT\CLSID\{00000401-0000-0000-C000-000000000046} = Ole 2.0 Container Sample Outline

HKEY_CLASSES_ROOT\CLSID\{00000401-0000-0000-C000-000000000046}\ProgID = OLE2CntrOutl

--- OLE 2.0 OBJECT HANDLER/EXE INFORMATION

    --------------------------------------

HKEY_CLASSES_ROOT\CLSID\{00000401-0000-0000-C000-000000000046}\InprocHandler32 = ole32.dll

HKEY_CLASSES_ROOT\CLSID\{00000401-0000-0000-C000-000000000046}\LocalServer32 = cntroutl.exe

/*************************************************************************

** REGISTRATION ENTRY FOR ISVROTL.EXE

*************************************************************************/

--- PROGID ROOT-KEY INFORMATION

    ---------------------------

HKEY_CLASSES_ROOT\OLE2ISvrOtl = Ole 2.0 In-Place Server Outline

HKEY_CLASSES_ROOT\OLE2ISvrOtl\CLSID = {00000402-0000-0000-C000-000000000046}

--- ISVROTL is marked as insertable so it appears in the InsertObject dialog

HKEY_CLASSES_ROOT\OLE2ISvrOtl\Insertable

--- OLE 1.0 COMPATIBILITY INFORMATION

    ---------------------------------

HKEY_CLASSES_ROOT\OLE2ISvrOtl\protocol\StdFileEditing\verb\1 = &Open

HKEY_CLASSES_ROOT\OLE2ISvrOtl\protocol\StdFileEditing\verb\0 = &Edit

HKEY_CLASSES_ROOT\OLE2ISvrOtl\protocol\StdFileEditing\server = isvrotl.exe

--- WINDOWS 3.1 SHELL INFORMATION

    -----------------------------

HKEY_CLASSES_ROOT\OLE2ISvrOtl\Shell\Print\Command = isvrotl.exe %1

HKEY_CLASSES_ROOT\OLE2ISvrOtl\Shell\Open\Command = isvrotl.exe %1

--- File extension must have ProgID as its value

HKEY_CLASSES_ROOT\.oln = OLE2ISvrOtl

--- OLE 2.0 CLSID ENTRY INFORMATION

    ------------------------------

HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046} = Ole 2.0 In-Place Server Outline

HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\ProgID = OLE2ISvrOtl

--- OLE 2.0 OBJECT HANDLER/EXE INFORMATION

    --------------------------------------

HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\ProgID = OLE2ISvrOtl

HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\InprocHandler32 = ole32.dll

HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\LocalServer32 = isvrotl.exe

--- VERB MENU SUPPORT

    -----------------

--- Verb 1: "Open", MF_UNCHECKED | MF_ENABLED, OLEVERBATTRIB_ONCONTAINERMENU

HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\Verb\1 = &Open,0,2

--- Verb 0: "Edit", MF_UNCHECKED | MF_ENABLED, OLEVERBATTRIB_ONCONTAINERMENU

HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\Verb\0 = &Edit,0,2

--- This class should appear in Insert New Object list

HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\Insertable

--- USER TYPE NAMES

    ---------------

--- ShortName (NOTE: recommended max 15 chars) = In-Place Outline

HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\AuxUserType\2 = Outline

--- AppName = Ole 2.0 In-Place Outline Server

HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\AuxUserType\3 = Ole 2.0 In-Place Outline Server

--- ICON DEFINITION

    ---------------

HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\DefaultIcon = isvrotl.exe,0

--- DATA FORMATS SUPPORTED

    ----------------------

--- Default File Format = CF_OUTLINE

HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\DataFormats\DefaultFile = Outline

--- Format 0 = CF_OUTLINE, DVASPECT_CONTENT, TYMED_HGLOBAL, DATADIR_BOTH

HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\DataFormats\GetSet\0 = Outline,1,1,3

--- Format 1 = CF_TEXT, DVASPECT_CONTENT, TYMED_HGLOBAL, DATADIR_BOTH

HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\DataFormats\GetSet\1 = 1,1,1,3

--- Format 2 = CF_METAFILEPICT, DVASPECT_CONTENT, TYMED_MFPICT, DATADIR_GET

HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\DataFormats\GetSet\2 = 3,1,32,1

--- Format 3 = CF_METAFILEPICT, DVASPECT_ICON, TYMED_MFPICT, DATADIR_GET

HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\DataFormats\GetSet\3 = 3,4,32,1

--- MISC STATUS SUPPORTED

    ---------------------

/* DVASPECT_CONTENT = OLEMISC_RENDERINGISDEVICEINDEPENDENT */

HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\MiscStatus = 512

/* DVASPECT_CONTENT =

**    OLEMISC_INSIDEOUT | OLEMISC_ACTIVATEWHENVISIBLE |

**    OLEMISC_RENDERINGISDEVICEINDEPENDENT

*/

HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\MiscStatus\1 = 896

--- CONVERSION FORMATS SUPPORTED

    ----------------------------

--- Readable Main formats: CF_OUTLINE, CF_TEXT

HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\Conversion\Readable\Main = Outline

HKEY_CLASSES_ROOT\CLSID\{00000402-0000-0000-C000-000000000046}\Conversion\Readwritable\Main = Outline

/*************************************************************************

** REGISTRATION ENTRY FOR ICNTROTL.EXE

*************************************************************************/

ENTRIES FOR Ole 2.0 In-Place Container Outline

--- PROGID ROOT-KEY INFORMATION

    ---------------------------

    NOTE: ICNTROTL must have a ProgID assigned for the Windows 3.1 Shell

    file associations and Packager to function correctly.

HKEY_CLASSES_ROOT\OLE2ICtrOtl = Ole 2.0 In-Place Container Outline

HKEY_CLASSES_ROOT\OLE2ICtrOtl\Clsid = {00000403-0000-0000-C000-000000000046}

--- WINDOWS 3.1 SHELL INFORMATION

    -----------------------------

HKEY_CLASSES_ROOT\OLE2ICtrOtl\Shell\Print\Command = icntrotl.exe %1

HKEY_CLASSES_ROOT\OLE2ICtrOtl\Shell\Open\Command = icntrotl.exe %1

--- File extension must have ProgID as its value

HKEY_CLASSES_ROOT\.olc = OLE2ICtrOtl

--- OLE 2.0 CLSID ENTRY INFORMATION

    -------------------------------

HKEY_CLASSES_ROOT\CLSID\{00000403-0000-0000-C000-000000000046} = Ole 2.0 In-Place Container Outline

HKEY_CLASSES_ROOT\CLSID\{00000403-0000-0000-C000-000000000046}\ProgID = OLE2ICtrOtl

--- OLE 2.0 OBJECT HANDLER/EXE INFORMATION

    --------------------------------------

HKEY_CLASSES_ROOT\CLSID\{00000403-0000-0000-C000-000000000046}\InprocHandler32 = ole32.dll

HKEY_CLASSES_ROOT\CLSID\{00000403-0000-0000-C000-000000000046}\LocalServer32 = icntrotl.exe


OUTLINE.C  (OUTLINE Sample)

/*************************************************************************

**

**    OLE 2.0 Sample Code

**

**    precomp.c

**

**    This file is used to precompile the OUTLINE.H header file

**

**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

**

*************************************************************************/

#include "outline.h"


OUTLLINE.C  (OUTLINE Sample)

/*************************************************************************

**

**    OLE 2 Sample Code

**

**    outlline.c

**

**    This file contains Line functions.

**

**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

**

*************************************************************************/

#include "outline.h"

OLEDBGDATA

extern LPOUTLINEAPP g_lpApp;

/* Line_Init

 * ---------

 *

 *      Init the calculated data of a line object

 */

void Line_Init(LPLINE lpLine, int nTab, HDC hDC)

{

   lpLine->m_lineType              = UNKNOWNLINETYPE;

   lpLine->m_nTabLevel             = nTab;

   lpLine->m_nTabWidthInHimetric   = Line_CalcTabWidthInHimetric(lpLine,hDC);

   lpLine->m_nWidthInHimetric      = 0;

   lpLine->m_nHeightInHimetric     = 0;

   lpLine->m_fSelected             = FALSE;

#if defined( USE_DRAGDROP )

   lpLine->m_fDragOverLine         = FALSE;

#endif

}

/* Line_Edit

 * ---------

 *

 *      Edit the line object.

 *

 *      Returns TRUE if line was changed

 *              FALSE if the line was NOT changed

 */

BOOL Line_Edit(LPLINE lpLine, HWND hWndDoc, HDC hDC)

{

   switch (lpLine->m_lineType) {

      case TEXTLINETYPE:

         return TextLine_Edit((LPTEXTLINE)lpLine, hWndDoc, hDC);

#if defined( OLE_CNTR )

      case CONTAINERLINETYPE:

         ContainerLine_Edit((LPCONTAINERLINE)lpLine, hWndDoc, hDC);

         break;

#endif

      default:

         return FALSE;       // unknown line type

   }

}

/* Line_GetLineType

 * ----------------

 *

 * Return type of the line

 */

LINETYPE Line_GetLineType(LPLINE lpLine)

{

   if (! lpLine) return 0;

   return lpLine->m_lineType;

}

/* Line_GetTextLen

 * ---------------

 *

 * Return length of string representation of the Line

 *  (not considering the tab level).

 */

int Line_GetTextLen(LPLINE lpLine)

{

   switch (lpLine->m_lineType) {

      case TEXTLINETYPE:

         return TextLine_GetTextLen((LPTEXTLINE)lpLine);

#if defined( OLE_CNTR )

      case CONTAINERLINETYPE:

         return ContainerLine_GetTextLen((LPCONTAINERLINE)lpLine);

#endif

      default:

         return 0;       // unknown line type

   }

}

/* Line_GetTextData

 * ----------------

 *

 * Return the string representation of the Line.

 *  (not considering the tab level).

 */

void Line_GetTextData(LPLINE lpLine, LPOLESTR lpszBuf)

{

   char szAnsiStr[256];

   switch (lpLine->m_lineType) {

     case TEXTLINETYPE:

         W2A (lpszBuf, szAnsiStr, 256);

         TextLine_GetTextData((LPTEXTLINE)lpLine, szAnsiStr);

         break;

#if defined( OLE_CNTR )

      case CONTAINERLINETYPE:

         ContainerLine_GetTextData((LPCONTAINERLINE)lpLine, lpszBuf);

         break;

#endif

      default:

         *lpszBuf = '\0';

         return;     // unknown line type

   }

}

/* Line_GetOutlineData

 * -------------------

 *

 * Return the CF_OUTLINE format representation of the Line.

 */

BOOL Line_GetOutlineData(LPLINE lpLine, LPTEXTLINE lpBuf)

{

   switch (lpLine->m_lineType) {

      case TEXTLINETYPE:

         return TextLine_GetOutlineData((LPTEXTLINE)lpLine, lpBuf);

#if defined( OLE_CNTR )

      case CONTAINERLINETYPE:

         return ContainerLine_GetOutlineData(

               (LPCONTAINERLINE)lpLine,

               lpBuf

         );

#endif

      default:

         return FALSE;       // unknown line type

   }

}

/* Line_CalcTabWidthInHimetric

 * ---------------------------

 *

 *      Recalculate the width for the line's current tab level

 */

static int Line_CalcTabWidthInHimetric(LPLINE lpLine, HDC hDC)

{

   int nTabWidthInHimetric;

   nTabWidthInHimetric=lpLine->m_nTabLevel * TABWIDTH;

   return nTabWidthInHimetric;

}

/* Line_Indent

 * -----------

 *

 *      Increment the tab level for the line

 */

void Line_Indent(LPLINE lpLine, HDC hDC)

{

   lpLine->m_nTabLevel++;

   lpLine->m_nTabWidthInHimetric = Line_CalcTabWidthInHimetric(lpLine, hDC);

#if defined( INPLACE_CNTR )

   if (Line_GetLineType(lpLine) == CONTAINERLINETYPE)

      ContainerLine_UpdateInPlaceObjectRects((LPCONTAINERLINE)lpLine, NULL);

#endif

}

/* Line_Unindent

 * -------------

 *

 * Decrement the tab level for the line

 */

void Line_Unindent(LPLINE lpLine, HDC hDC)

{

   if(lpLine->m_nTabLevel > 0) {

      lpLine->m_nTabLevel--;

      lpLine->m_nTabWidthInHimetric = Line_CalcTabWidthInHimetric(lpLine, hDC);

   }

#if defined( INPLACE_CNTR )

   if (Line_GetLineType(lpLine) == CONTAINERLINETYPE)

      ContainerLine_UpdateInPlaceObjectRects((LPCONTAINERLINE)lpLine, NULL);

#endif

}

/* Line_GetTotalWidthInHimetric

 * ----------------------------

 *

 *      Calculate the total width of the line

 */

UINT Line_GetTotalWidthInHimetric(LPLINE lpLine)

{

   return lpLine->m_nWidthInHimetric + lpLine->m_nTabWidthInHimetric;

}

/* Line_SetWidthInHimetric

 * -----------------------

 *

 *      Set the width of the line

 */

void Line_SetWidthInHimetric(LPLINE lpLine, int nWidth)

{

   if (!lpLine)

      return;

   lpLine->m_nWidthInHimetric = nWidth;

}

/* Line_GetWidthInHimetric

 * -----------------------

 *

 *      Return the width of the line

 */

UINT Line_GetWidthInHimetric(LPLINE lpLine)

{

   if (!lpLine)

      return 0;

   return lpLine->m_nWidthInHimetric;

}

/* Line_GetTabLevel

 * ----------------

 *

 * Return the tab level of a line object.

 */

UINT Line_GetTabLevel(LPLINE lpLine)

{

   return lpLine->m_nTabLevel;

}

/* Line_DrawToScreen

 * -----------------

 *

 *      Draw the item in the owner-draw listbox

 */

void Line_DrawToScreen(

      LPLINE      lpLine,

      HDC         hDC,

      LPRECT      lprcPix,

      UINT        itemAction,

      UINT        itemState,

      LPRECT      lprcDevice

)

{

   if (!lpLine || !hDC || !lprcPix || !lprcDevice)

      return;

   /* Draw a list box item in its normal drawing action.

    * Then check if it is selected or has the focus state, and call

    * functions to handle drawing for these states if necessary.

    */

   if(itemAction & (ODA_SELECT | ODA_DRAWENTIRE)) {

      HFONT hfontOld;

      int nMapModeOld;

      RECT rcWindowOld;

      RECT rcViewportOld;

      RECT rcLogical;

      // NOTE: we have to set the device context to HIMETRIC in order

      // draw the line; however, we have to restore the HDC before

      // we draw focus or dragfeedback...

      rcLogical.left = 0;

      rcLogical.bottom = 0;

      rcLogical.right = lpLine->m_nWidthInHimetric;

      rcLogical.top = lpLine->m_nHeightInHimetric;

      {

         HBRUSH hbr;

         RECT    rcDraw;

         lpLine->m_fSelected = (BOOL)(itemState & ODS_SELECTED);

         if (ODS_SELECTED & itemState) {

            /*Get proper txt colors */

            hbr = CreateSolidBrush(GetSysColor(COLOR_HIGHLIGHT));

         }

         else {

            hbr = CreateSolidBrush(GetSysColor(COLOR_WINDOW));

         }

         rcDraw = *lprcPix;

         rcDraw.right = lprcDevice->left;

         FillRect(hDC, lprcPix, hbr);

         rcDraw = *lprcPix;

         rcDraw.left = lprcDevice->right;

         FillRect(hDC, lprcPix, hbr);

         DeleteObject(hbr);

      }

      nMapModeOld=SetDCToAnisotropic(hDC, lprcDevice, &rcLogical,

                     (LPRECT)&rcWindowOld, (LPRECT)&rcViewportOld);

      // Set the default font size, and font face name

      hfontOld = SelectObject(hDC, OutlineApp_GetActiveFont(g_lpApp));

      Line_Draw(lpLine, hDC, &rcLogical, NULL, (ODS_SELECTED & itemState));

      SelectObject(hDC, hfontOld);

      ResetOrigDC(hDC, nMapModeOld, (LPRECT)&rcWindowOld,

            (LPRECT)&rcViewportOld);

#if defined( OLE_CNTR )

      if ((itemState & ODS_SELECTED) &&

         (Line_GetLineType(lpLine)==CONTAINERLINETYPE))

         ContainerLine_DrawSelHilight(

               (LPCONTAINERLINE)lpLine,

               hDC,

               lprcPix,

               ODA_SELECT,

               ODS_SELECTED

         );

#endif

   }

   /* If a list box item just gained or lost the focus,

   * call function (which could check if ODS_FOCUS bit is set)

   * and draws item in focus or non-focus state.

   */

   if(itemAction & ODA_FOCUS )

      Line_DrawFocusRect(lpLine, hDC, lprcPix, itemAction, itemState);

#if defined( OLE_CNTR )

   if (Line_GetLineType(lpLine) == CONTAINERLINETYPE) {

      LPCONTAINERLINE lpContainerLine = (LPCONTAINERLINE)lpLine;

      LPCONTAINERDOC lpDoc = lpContainerLine->m_lpDoc;

      BOOL fIsLink;

      RECT rcObj;

      if (ContainerDoc_GetShowObjectFlag(lpDoc)) {

         ContainerLine_GetOleObjectRectInPixels(lpContainerLine, &rcObj);

         fIsLink = ContainerLine_IsOleLink(lpContainerLine);

         OleUIShowObject(&rcObj, hDC, fIsLink);

      }

   }

#endif

#if defined( USE_DRAGDROP )

   if (lpLine->m_fDragOverLine)

      Line_DrawDragFeedback(lpLine, hDC, lprcPix, itemState );

#endif

}

/* Line_Draw

 * ---------

 *

 *  Draw a line on a DC.

 *

 * Parameters:

 *      hDC     - DC to which the line will be drawn

 *      lpRect  - the object rect in logical coordinates

 */

void Line_Draw(

      LPLINE      lpLine,

      HDC         hDC,

      LPRECT      lpRect,

      LPRECT      lpRectWBounds,

      BOOL        fHighlight

)

{

   switch (lpLine->m_lineType) {

      case TEXTLINETYPE:

         TextLine_Draw(

             (LPTEXTLINE)lpLine, hDC, lpRect,lpRectWBounds,fHighlight);

         break;

#if defined( OLE_CNTR )

      case CONTAINERLINETYPE:

         ContainerLine_Draw(

             (LPCONTAINERLINE)lpLine,hDC,lpRect,lpRectWBounds,fHighlight);

         break;

#endif

      default:

         return;     // unknown line type

   }

   return;

}

/* Line_DrawSelHilight

 * -------------------

 *

 *      Handles selection of list box item

 */

void Line_DrawSelHilight(LPLINE lpLine, HDC hDC, LPRECT lpRect, UINT itemAction, UINT itemState)

{

   switch (lpLine->m_lineType) {

      case TEXTLINETYPE:

         TextLine_DrawSelHilight((LPTEXTLINE)lpLine, hDC, lpRect,

            itemAction, itemState);

         break;

#if defined( OLE_CNTR )

      case CONTAINERLINETYPE:

         ContainerLine_DrawSelHilight((LPCONTAINERLINE)lpLine, hDC, lpRect,

            itemAction, itemState);

         break;

#endif

      default:

         return;     // unknown line type

   }

   return;

}

/* Line_DrawFocusRect

 * ------------------

 *

 *      Handles focus state of list box item

 */

void Line_DrawFocusRect(LPLINE lpLine, HDC hDC, LPRECT lpRect, UINT itemAction, UINT itemState)

{

   if(lpLine)

      DrawFocusRect(hDC, lpRect);

}

#if defined( USE_DRAGDROP )

/* Line_DrawDragFeedback

 * ---------------------

 *

 *      Handles focus state of list box item

 */

void Line_DrawDragFeedback(LPLINE lpLine, HDC hDC, LPRECT lpRect, UINT itemState )

{

   if(lpLine)

      DrawFocusRect(hDC, lpRect);

}

#endif  // USE_DRAGDROP

/* Line_GetHeightInHimetric

 * ------------------------

 *

 *      Return the height of the item in HIMETRIC units

 */

UINT Line_GetHeightInHimetric(LPLINE lpLine)

{

   if (!lpLine)

      return 0;

   return (UINT)lpLine->m_nHeightInHimetric;

}

/* Line_SetHeightInHimetric

 * ------------------------

 *

 *      Set the height of the item in HIMETRIC units.

 */

void Line_SetHeightInHimetric(LPLINE lpLine, int nHeight)

{

   if (!lpLine)

      return;

   switch (lpLine->m_lineType) {

      case TEXTLINETYPE:

         TextLine_SetHeightInHimetric((LPTEXTLINE)lpLine, nHeight);

         break;

#if defined( OLE_CNTR )

      case CONTAINERLINETYPE:

         ContainerLine_SetHeightInHimetric((LPCONTAINERLINE)lpLine,

               nHeight);

         break;

#endif

   }

}

/* Line_Delete

 * -----------

 *

 *      Delete the Line structure

 */

void Line_Delete(LPLINE lpLine)

{

   switch (lpLine->m_lineType) {

      case TEXTLINETYPE:

         TextLine_Delete((LPTEXTLINE)lpLine);

         break;

#if defined( OLE_CNTR )

      case CONTAINERLINETYPE:

         ContainerLine_Delete((LPCONTAINERLINE)lpLine);

         break;

#endif

      default:

         break;      // unknown line type

   }

}

/* Line_CopyToDoc

 * --------------

 *

 *      Copy a line to another Document (usually ClipboardDoc)

 */

BOOL Line_CopyToDoc(LPLINE lpSrcLine, LPOUTLINEDOC lpDestDoc, int nIndex)

{

   switch (lpSrcLine->m_lineType) {

      case TEXTLINETYPE:

         return TextLine_CopyToDoc((LPTEXTLINE)lpSrcLine,lpDestDoc,nIndex);

         break;

#if defined( OLE_CNTR )

      case CONTAINERLINETYPE:

         return ContainerLine_CopyToDoc(

               (LPCONTAINERLINE)lpSrcLine,

               lpDestDoc,

               nIndex

         );

         break;

#endif

      default:

         return FALSE;       // unknown line type

   }

}

/* Line_SaveToStg

 * --------------

 *

 *      Save a single line object to a storage

 *

 *      Return TRUE if successful, FALSE otherwise

 */

BOOL Line_SaveToStg(LPLINE lpLine, UINT uFormat, LPSTORAGE lpSrcStg, LPSTORAGE lpDestStg, LPSTREAM lpLLStm, BOOL fRemember)

{

   LINERECORD_ONDISK lineRecord;

   ULONG nWritten;

   HRESULT hrErr;

   BOOL fStatus;

   LARGE_INTEGER dlibSavePos;

   LARGE_INTEGER dlibZeroOffset;

   LISet32( dlibZeroOffset, 0 );

   /* save seek position before line record is written in case of error */

   hrErr = lpLLStm->lpVtbl->Seek(

         lpLLStm,

         dlibZeroOffset,

         STREAM_SEEK_CUR,

         (ULARGE_INTEGER FAR*)&dlibSavePos

   );

   if (hrErr != NOERROR) return FALSE;

#if defined( OLE_CNTR )

   if (lpLine->m_lineType == CONTAINERLINETYPE) {

      /* OLE2NOTE: asking an OLE object to save may cause the

      **    object to send an OnViewChange notification if there are any

      **    outstanding changes to the object. this is particularly true

      **    for objects with coarse update granularity like OLE 1.0

      **    objects. if an OnViewChange notification is received then the

      **    object's presentation cache will be updated BEFORE it is

      **    saved. It is important that the extents stored as part of

      **    the ContainerLine/Line record associated with the OLE object

      **    are updated before the Line data is saved to the storage. it

      **    is important that this extent information matches the data

      **    saved with the OLE object. the Line extent information is

      **    updated in the IAdviseSink::OnViewChange method implementation.

      */

      // only save the OLE object if format is compatible.

      if (uFormat != ((LPCONTAINERAPP)g_lpApp)->m_cfCntrOutl)

         goto error;

      fStatus = ContainerLine_SaveOleObjectToStg(

            (LPCONTAINERLINE)lpLine,

            lpSrcStg,

            lpDestStg,

            fRemember

      );

      if (! fStatus) goto error;

   }

#endif

   // compilers should handle alignment correctly

   lineRecord.m_lineType = (USHORT)lpLine->m_lineType;

   lineRecord.m_nTabLevel = (USHORT)lpLine->m_nTabLevel;

   lineRecord.m_nTabWidthInHimetric = (USHORT)lpLine->m_nTabWidthInHimetric;

   lineRecord.m_nWidthInHimetric = (USHORT)lpLine->m_nWidthInHimetric;

   lineRecord.m_nHeightInHimetric = (USHORT)lpLine->m_nHeightInHimetric;

   lineRecord.m_reserved = 0;

   /* write line record header */

   hrErr = lpLLStm->lpVtbl->Write(

         lpLLStm,

         (LPVOID)&lineRecord,

         sizeof(lineRecord),

         &nWritten

   );

   if (hrErr != NOERROR) {

      OleDbgOutHResult("Write Line header returned", hrErr);

      goto error;

    }

   switch (lpLine->m_lineType) {

      case TEXTLINETYPE:

         fStatus = TextLine_SaveToStm((LPTEXTLINE)lpLine, lpLLStm);

         if (! fStatus) goto error;

         break;

#if defined( OLE_CNTR )

      case CONTAINERLINETYPE:

         fStatus=ContainerLine_SaveToStm((LPCONTAINERLINE)lpLine,lpLLStm);

         if (! fStatus) goto error;

         break;

#endif

      default:

         goto error;       // unknown line type

   }

   return TRUE;

error:

   /* retore seek position prior to writing Line record */

   lpLLStm->lpVtbl->Seek(

         lpLLStm,

         dlibSavePos,

         STREAM_SEEK_SET,

         NULL

   );

   return FALSE;

}

/* Line_LoadFromStg

 * ----------------

 *

 *      Load a single line object from storage

 */

LPLINE Line_LoadFromStg(LPSTORAGE lpSrcStg, LPSTREAM lpLLStm, LPOUTLINEDOC lpDestDoc)

{

   LINERECORD_ONDISK lineRecord;

   LPLINE lpLine = NULL;

   ULONG nRead;

   HRESULT hrErr;

   /* read line record header */

   hrErr = lpLLStm->lpVtbl->Read(

         lpLLStm,

         (LPVOID)&lineRecord,

         sizeof(lineRecord),

         &nRead

   );

   if (hrErr != NOERROR) {

      OleDbgOutHResult("Read Line header returned", hrErr);

      return NULL;

    }

   switch ((LINETYPE)lineRecord.m_lineType) {

      case TEXTLINETYPE:

         lpLine = TextLine_LoadFromStg(lpSrcStg, lpLLStm, lpDestDoc);

         break;

#if defined( OLE_CNTR )

      case CONTAINERLINETYPE:

         lpLine = ContainerLine_LoadFromStg(lpSrcStg, lpLLStm, lpDestDoc);

         break;

#endif

      default:

         return NULL;        // unknown line type

   }

   lpLine->m_lineType = (LINETYPE) lineRecord.m_lineType;

   lpLine->m_nTabLevel = (UINT) lineRecord.m_nTabLevel;

   lpLine->m_nTabWidthInHimetric = (UINT) lineRecord.m_nTabWidthInHimetric;

   lpLine->m_nWidthInHimetric = (UINT) lineRecord.m_nWidthInHimetric;

   lpLine->m_nHeightInHimetric = (UINT) lineRecord.m_nHeightInHimetric;

   return lpLine;

}

/* Line_IsSelected

 * ---------------

 *

 *      Return the selection state of the line

 */

BOOL Line_IsSelected(LPLINE lpLine)

{

   if (!lpLine)

      return FALSE;

   return lpLine->m_fSelected;

}


OUTLLIST.C  (OUTLINE Sample)

/*************************************************************************

**

**    OLE 2 Sample Code

**

**    outldata.c

**

**    This file contains LineList and NameTable functions

**    and related support functions.

**

**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

**

*************************************************************************/

#include "outline.h"

OLEDBGDATA

extern LPOUTLINEAPP g_lpApp;

OLECHAR ErrMsgListBox[] = OLESTR("Can't create ListBox!");

static int g_iMapMode;

/* LineList_Init

 * -------------

 *

 *      Create and Initialize the LineList (owner-drawn listbox)

 */

BOOL LineList_Init(LPLINELIST lpLL, LPOUTLINEDOC lpOutlineDoc)

{

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

#if defined( INPLACE_CNTR )

   lpLL->m_hWndListBox = CreateWindow(

               "listbox",              /* Window class name           */

               NULL,                   /* Window's title              */

               /* OLE2NOTE: an in-place contanier MUST use

               **    WS_CLIPCHILDREN window style for the window

               **    that it uses as the parent for the server's

               **    in-place active window so that its

               **    painting does NOT interfere with the painting

               **    of the server's in-place active child window.

               */

               WS_CLIPCHILDREN |

               WS_CHILDWINDOW |

               WS_VISIBLE |

               WS_VSCROLL |

               WS_HSCROLL |

               LBS_EXTENDEDSEL |

               LBS_NOTIFY |

               LBS_OWNERDRAWVARIABLE |

               LBS_NOINTEGRALHEIGHT |

               LBS_USETABSTOPS,

               0, 0,                   /* Use default X, Y            */

               0, 0,                   /* Use default X, Y            */

               lpOutlineDoc->m_hWndDoc,/* Parent window's handle      */

               (HMENU)IDC_LINELIST,    /* Child Window ID             */

               lpOutlineApp->m_hInst,  /* Instance of window          */

               NULL);                  /* Create struct for WM_CREATE */

#else

   lpLL->m_hWndListBox = CreateWindow(

               "listbox",              /* Window class name           */

               NULL,                   /* Window's title              */

               WS_CHILDWINDOW |

               WS_VISIBLE |

               WS_VSCROLL |

               WS_HSCROLL |

               LBS_EXTENDEDSEL |

               LBS_NOTIFY |

               LBS_OWNERDRAWVARIABLE |

               LBS_NOINTEGRALHEIGHT |

               LBS_USETABSTOPS,

               0, 0,                   /* Use default X, Y            */

               0, 0,                   /* Use default X, Y            */

               lpOutlineDoc->m_hWndDoc,/* Parent window's handle      */

               (HMENU)IDC_LINELIST,    /* Child Window ID             */

               lpOutlineApp->m_hInst,  /* Instance of window          */

               NULL);                  /* Create struct for WM_CREATE */

#endif

   if(! lpLL->m_hWndListBox) {

      OutlineApp_ErrorMessage(g_lpApp, ErrMsgListBox);

      return FALSE;

   }

   lpOutlineApp->m_ListBoxWndProc =

         (FARPROC) GetWindowLong ( lpLL->m_hWndListBox, GWL_WNDPROC );

   SetWindowLong (lpLL->m_hWndListBox, GWL_WNDPROC, (LONG) LineListWndProc);

#if defined ( USE_DRAGDROP )

   /* m_iDragOverLine saves index of line that has drag/drop target

   **    feedback. we currently use our focus rectangle feedback for

   **    this. it would be better to have a different visual feedback

   **    for potential target of the pending drop.

   */

   lpLL->m_iDragOverLine = -1;

#endif

   lpLL->m_nNumLines = 0;

   lpLL->m_nMaxLineWidthInHimetric = 0;

   lpLL->m_lpDoc = lpOutlineDoc;

   _fmemset(&lpLL->m_lrSaveSel, 0, sizeof(LINERANGE));

   return TRUE;

}

/* LineList_Destroy

 * ----------------

 *

 *      Clear (delete) all Line objects from the list and free supporting

 *      memory (ListBox Window) used by the LineList object itself.

 */

void LineList_Destroy(LPLINELIST lpLL)

{

   int i;

   int linesTotal = lpLL->m_nNumLines;

   // Delete all Line objects

   for (i = 0; i < linesTotal; i++)

      LineList_DeleteLine(lpLL, 0);   // NOTE: always delete line 0

   // Remove all Lines from the ListBox

   SendMessage(lpLL->m_hWndListBox,LB_RESETCONTENT,0,0L);

   lpLL->m_nNumLines=0;

   DestroyWindow(lpLL->m_hWndListBox);

   lpLL->m_hWndListBox = NULL;

}

/* LineList_AddLine

 * ----------------

 *

 *      Add one line to the list box. The line is added following the

 * line with index "nIndex". If nIndex is larger than the number of lines

 * in the ListBox, then the line is appended to the end. The selection

 * is set to the newly added line.

 */

void LineList_AddLine(LPLINELIST lpLL, LPLINE lpLine, int nIndex)

{

   int nAddIndex = (lpLL->m_nNumLines == 0 ?

         0 :

         (nIndex >= lpLL->m_nNumLines ? lpLL->m_nNumLines : nIndex+1));

   LINERANGE lrSel;

#if defined( USE_HEADING )

   int nHeight = Line_GetHeightInHimetric(lpLine);

   nHeight = XformHeightInHimetricToPixels(NULL, nHeight);

   // Add a dummy string to the row heading

   Heading_RH_SendMessage(OutlineDoc_GetHeading(lpLL->m_lpDoc),

         LB_INSERTSTRING, (WPARAM)nAddIndex, MAKELPARAM(nHeight, 0));

#endif

   lrSel.m_nStartLine = nAddIndex;

   lrSel.m_nEndLine =   nAddIndex;

   if (!lpLine) {

      OutlineApp_ErrorMessage(g_lpApp, OLESTR("Could not create line."));

      return;

   }

   SendMessage(lpLL->m_hWndListBox, LB_INSERTSTRING, (WPARAM)nAddIndex,

         (DWORD)lpLine);

   LineList_SetMaxLineWidthInHimetric(

         lpLL,

         Line_GetTotalWidthInHimetric(lpLine)

   );

   lpLL->m_nNumLines++;

   LineList_SetSel(lpLL, &lrSel);

}

/* LineList_DeleteLine

 * -------------------

 *

 *      Delete one line from listbox and memory

 */

void LineList_DeleteLine(LPLINELIST lpLL, int nIndex)

{

   LPLINE lpLine = LineList_GetLine(lpLL, nIndex);

   BOOL fResetSel;

   fResetSel = (BOOL)SendMessage(lpLL->m_hWndListBox, LB_GETSEL, (WPARAM)nIndex, 0L);

   if (lpLine)

      Line_Delete(lpLine);    // free memory of Line

   // Remove the Line from the ListBox

   SendMessage(lpLL->m_hWndListBox, LB_DELETESTRING, (WPARAM)nIndex, 0L);

   lpLL->m_nNumLines--;

   if (fResetSel) {

      if (nIndex > 0) {

#if defined( WIN32 )

         SendMessage(

               lpLL->m_hWndListBox,

               LB_SETSEL,

               (WPARAM)TRUE,

               (LPARAM)nIndex-1

         );

#else

         SendMessage(

               lpLL->m_hWndListBox,

               LB_SETSEL,

               (WPARAM)TRUE,

               MAKELPARAM(nIndex-1,0)

         );

#endif

      } else {

         if (lpLL->m_nNumLines > 0) {

#if defined( WIN32 )

            SendMessage(

                  lpLL->m_hWndListBox,

                  LB_SETSEL,

                  (WPARAM)TRUE,

                  (LPARAM)0

            );

#else

            SendMessage(

                  lpLL->m_hWndListBox,

                  LB_SETSEL,

                  (WPARAM)TRUE,

                  MAKELPARAM(0,0)

            );

#endif

         }

      }

   }

#if defined( USE_HEADING )

   // Remove the dummy string from the row heading

   Heading_RH_SendMessage(OutlineDoc_GetHeading(lpLL->m_lpDoc),

         LB_DELETESTRING, (WPARAM)nIndex, 0L);

#endif

}

/* LineList_ReplaceLine

 * --------------------

 *

 *      Replace the line at a given index in the list box with a new

 * line.

 */

void LineList_ReplaceLine(LPLINELIST lpLL, LPLINE lpLine, int nIndex)

{

   LPLINE lpOldLine = LineList_GetLine(lpLL, nIndex);

   if (lpOldLine)

      Line_Delete(lpOldLine);    // free memory of Line

   else

      return;     // if no previous line then invalid index

   SendMessage(

         lpLL->m_hWndListBox,

         LB_SETITEMDATA,

         (WPARAM)nIndex,

         (LPARAM)lpLine

   );

}

/* LineList_GetLineIndex

 * ---------------------

 *

 *      Return the index of the Line given a pointer to the line.

 *      Return -1 if the line is not found.

 */

int LineList_GetLineIndex(LPLINELIST lpLL, LPLINE lpLine)

{

   LRESULT lRet;

   if (! lpLine) return -1;

   lRet = SendMessage(

         lpLL->m_hWndListBox,

         LB_FINDSTRING,

         (WPARAM)-1,

         (LPARAM)(LPCSTR)lpLine

      );

   return ((lRet == LB_ERR) ? -1 : (int)lRet);

}

/* LineList_GetLine

 * ----------------

 *

 *      Retrieve the pointer to the Line given its index in the LineList

 */

LPLINE LineList_GetLine(LPLINELIST lpLL, int nIndex)

{

   DWORD dWord;

   LRESULT lRet;

   if (lpLL->m_nNumLines == 0 || nIndex > lpLL->m_nNumLines || nIndex < 0)

      return NULL;

   lRet = SendMessage(

         lpLL->m_hWndListBox,LB_GETTEXT,nIndex,(LPARAM)(LPCSTR)&dWord);

   return ((lRet == LB_ERR || lRet == 0) ? NULL : (LPLINE)dWord);

}

/* LineList_SetFocusLine

 * ---------------------

 *

 */

void LineList_SetFocusLine ( LPLINELIST lpLL, WORD wIndex )

{

   SendMessage(lpLL->m_hWndListBox, LB_SETCARETINDEX, (WPARAM)wIndex, 0L );

}

/* LineList_GetLineRect

 * --------------------

 *

 * Retrieve the rectangle of a Line given its index in the LineList

 */

BOOL LineList_GetLineRect(LPLINELIST lpLL, int nIndex, LPRECT lpRect)

{

   DWORD iReturn = (DWORD)LB_ERR;

   if ( !(lpLL->m_nNumLines == 0 || nIndex > lpLL->m_nNumLines || nIndex < 0) )

      iReturn = SendMessage(lpLL->m_hWndListBox,LB_GETITEMRECT,nIndex,(LPARAM)lpRect);

   return (iReturn == LB_ERR ? FALSE : TRUE );

}

/* LineList_GetFocusLineIndex

 * --------------------------

 *

 * Get the index of the line that currently has focus (the active line).

 */

int LineList_GetFocusLineIndex(LPLINELIST lpLL)

{

   return (int)SendMessage(lpLL->m_hWndListBox,LB_GETCARETINDEX,0,0L);

}

/* LineList_GetCount

 * -----------------

 *

 *      Return number of line objects

 */

int LineList_GetCount(LPLINELIST lpLL)

{

   if (lpLL)

      return lpLL->m_nNumLines;

   else {

      OleDbgAssert(lpLL!=NULL);

      return 0;

   }

}

/* LineList_SetMaxLineWidthInHimetric

 * ----------------------------------

 *

 *  Adjust the maximum line width for the listbox. The max line width is

 *  used to determine if a horizontal scroll bar is needed.

 *

 *  Parameters:

 *      nWidthInHimetric - if +ve, width of an additional line

 *                       - if -ve, reset Max to be the value

 *

 *  Returns:

 *      TRUE is max line width of LineList changed

 *      FALSE if no change

 */

BOOL LineList_SetMaxLineWidthInHimetric(LPLINELIST lpLL, int nWidthInHimetric)

{

   int nWidthInPix;

   BOOL fSizeChanged = FALSE;

   LPSCALEFACTOR lpscale;

   if (!lpLL)

      return FALSE;

   lpscale = OutlineDoc_GetScaleFactor(lpLL->m_lpDoc);

   if (nWidthInHimetric < 0) {

      lpLL->m_nMaxLineWidthInHimetric = -1;

      nWidthInHimetric *= -1;

   }

   if (nWidthInHimetric > lpLL->m_nMaxLineWidthInHimetric) {

      lpLL->m_nMaxLineWidthInHimetric = nWidthInHimetric;

      nWidthInPix = XformWidthInHimetricToPixels(NULL, nWidthInHimetric +

            LOWORD(OutlineDoc_GetMargin(lpLL->m_lpDoc)) +

            HIWORD(OutlineDoc_GetMargin(lpLL->m_lpDoc)));

      nWidthInPix = (int)(nWidthInPix * lpscale->dwSxN / lpscale->dwSxD);

      SendMessage(

            lpLL->m_hWndListBox,

            LB_SETHORIZONTALEXTENT,

            nWidthInPix,

            0L

      );

      fSizeChanged = TRUE;

#if defined( USE_HEADING )

      Heading_CH_SetHorizontalExtent(

            OutlineDoc_GetHeading(lpLL->m_lpDoc), lpLL->m_hWndListBox);

#endif

   }

   return fSizeChanged;

}

/* LineList_GetMaxLineWidthInHimetric

 * ----------------------------------

 *

 *      Return the width of the widest line

 */

int LineList_GetMaxLineWidthInHimetric(LPLINELIST lpLL)

{

   return lpLL->m_nMaxLineWidthInHimetric;

}

/* LineList_RecalcMaxLineWidthInHimetric

 * -------------------------------------

 *

 *  Recalculate the maximum line width in the entire list.

 *

 *  Parameters:

 *      nWidthInHimetric should be set to the width of line being removed.

 *      nWidthInHimetric == 0 forces list to recalculate in all cases.

 *      nWidthInHimetric == current max width => forces recalc.

 *

 *  Returns:

 *      TRUE is max line width of LineList changed

 *      FALSE if no change

 */

BOOL LineList_RecalcMaxLineWidthInHimetric(

      LPLINELIST          lpLL,

   int                 nWidthInHimetric

)

{

   int i;

   LPLINE lpLine;

   BOOL fSizeChanged = FALSE;

   int nOrgMaxLineWidthInHimetric = lpLL->m_nMaxLineWidthInHimetric;

   if (nWidthInHimetric == 0 ||

      nWidthInHimetric == lpLL->m_nMaxLineWidthInHimetric) {

      lpLL->m_nMaxLineWidthInHimetric = -1;

      LineList_SetMaxLineWidthInHimetric(lpLL, 0);

      for(i = 0; i < lpLL->m_nNumLines; i++) {

         lpLine=LineList_GetLine(lpLL, i);

         LineList_SetMaxLineWidthInHimetric(

               lpLL,

               Line_GetTotalWidthInHimetric(lpLine)

         );

      }

   }

   if (nOrgMaxLineWidthInHimetric != lpLL->m_nMaxLineWidthInHimetric)

      fSizeChanged = TRUE;

   return fSizeChanged;

}

/* LineList_CalcSelExtentInHimetric

 * --------------------------------

 *

 *      Calculate the extents (widht and height) of a selection of lines.

 *

 * if lplrSel == NULL, calculate extent of all lines.

 */

void LineList_CalcSelExtentInHimetric(

      LPLINELIST          lpLL,

      LPLINERANGE         lplrSel,

      LPSIZEL             lpsizel

)

{

   int i;

   int nEndLine;

   int nStartLine;

   LPLINE lpLine;

   long lWidth;

   if (lplrSel) {

      nEndLine = lplrSel->m_nEndLine;

      nStartLine = lplrSel->m_nStartLine;

   } else {

      nEndLine = LineList_GetCount(lpLL) - 1;

      nStartLine = 0;

   }

   lpsizel->cx = 0;

   lpsizel->cy = 0;

   for(i = nStartLine; i <= nEndLine; i++) {

      lpLine=LineList_GetLine(lpLL,i);

      if (lpLine) {

         lWidth = (long)Line_GetTotalWidthInHimetric(lpLine);

         lpsizel->cx = max(lpsizel->cx, lWidth);

         lpsizel->cy += lpLine->m_nHeightInHimetric;

      }

   }

}

/* LineList_GetWindow

 * ------------------

 *

 * Return handle of list box

 */

HWND LineList_GetWindow(LPLINELIST lpLL)

{

   return lpLL->m_hWndListBox;

}

/* LineList_GetDC

 * --------------

 *

 * Return DC handle of list box

 */

HDC LineList_GetDC(LPLINELIST lpLL)

{

   HFONT hfontOld;

   HDC hDC = GetDC(lpLL->m_hWndListBox);

   int     iXppli;     //* pixels per logical inch along width

   int     iYppli;     //* pixels per logical inch along height

   SIZE    size;

   // Setup a mapping mode for the DC which maps physical pixel

   // coordinates to HIMETRIC units. The standard MM_HIMETRIC mapping

   // mode does not work correctly because it does not take into

   // account that a logical inch on the display screen is drawn

   // physically larger than 1 inch. We will setup an anisotropic

   // mapping mode which will perform the transformation properly.

   g_iMapMode = SetMapMode(hDC, MM_ANISOTROPIC);

   iXppli = GetDeviceCaps (hDC, LOGPIXELSX);

   iYppli = GetDeviceCaps (hDC, LOGPIXELSY);

   SetViewportExtEx(hDC, iXppli, iYppli, &size);

   SetWindowExtEx(hDC, HIMETRIC_PER_INCH, HIMETRIC_PER_INCH, &size);

   // Set the default font size, and font face name

   hfontOld = SelectObject(hDC, OutlineApp_GetActiveFont(g_lpApp));

   return hDC;

}

/* LineList_ReleaseDC

 * ------------------

 *

 *      Release DC of list box returned from previous LineList_GetDC call.

 */

void LineList_ReleaseDC(LPLINELIST lpLL, HDC hDC)

{

   SetMapMode(hDC, g_iMapMode);

   ReleaseDC(lpLL->m_hWndListBox, hDC);

}

/* LineList_SetLineHeight

 * ----------------------

 *

 *      Set the height of a line in the LineList list box

 */

void LineList_SetLineHeight(LPLINELIST lpLL,int nIndex,int nHeightInHimetric)

{

   LPARAM          lParam;

   LPOUTLINEDOC    lpDoc;

   LPSCALEFACTOR   lpscale;

   UINT            uHeightInPix;

   LPHEADING       lphead;

   if (!lpLL)

      return;

   lpDoc = lpLL->m_lpDoc;

   lphead = OutlineDoc_GetHeading(lpDoc);

   lpscale = OutlineDoc_GetScaleFactor(lpDoc);

   uHeightInPix = XformHeightInHimetricToPixels(NULL, nHeightInHimetric);

   Heading_RH_SendMessage(lphead, LB_SETITEMDATA, (WPARAM)nIndex,

         MAKELPARAM(uHeightInPix, 0));

   uHeightInPix = (UINT)(uHeightInPix * lpscale->dwSyN / lpscale->dwSyD);

   if (uHeightInPix > LISTBOX_HEIGHT_LIMIT)

      uHeightInPix = LISTBOX_HEIGHT_LIMIT;

   lParam = MAKELPARAM(uHeightInPix, 0);

   SendMessage(lpLL->m_hWndListBox,LB_SETITEMHEIGHT,(WPARAM)nIndex, lParam);

   Heading_RH_SendMessage(lphead, LB_SETITEMHEIGHT, (WPARAM)nIndex, lParam);

   Heading_RH_ForceRedraw(lphead, TRUE);

}

/* LineList_ReScale

 * ----------------

 *

 *      Re-scale the LineList list box

 */

void LineList_ReScale(LPLINELIST lpLL, LPSCALEFACTOR lpscale)

{

   int nIndex;

   LPLINE lpLine;

   UINT uWidthInHim;

   if (!lpLL)

      return;

   for (nIndex = 0; nIndex < lpLL->m_nNumLines; nIndex++) {

      lpLine = LineList_GetLine(lpLL, nIndex);

      if (lpLine) {

         LineList_SetLineHeight(

               lpLL,

               nIndex,

               Line_GetHeightInHimetric(lpLine)

         );

      }

   }

   uWidthInHim = LineList_GetMaxLineWidthInHimetric(lpLL);

   LineList_SetMaxLineWidthInHimetric(lpLL, -(int)uWidthInHim);

}

/* LineList_SetSel

 * ---------------

 *

 *      Set the selection in list box

 */

void LineList_SetSel(LPLINELIST lpLL, LPLINERANGE lplrSel)

{

   DWORD dwSel;

   if (lpLL->m_nNumLines <= 0 || lplrSel->m_nStartLine < 0)

      return;     // no lines in list; can't set a selection

   dwSel = MAKELPARAM(lplrSel->m_nStartLine, lplrSel->m_nEndLine);

   lpLL->m_lrSaveSel = *lplrSel;

   /* remove previous selection */

#if defined( WIN32 )

   SendMessage(

         lpLL->m_hWndListBox,

         LB_SETSEL,

         (WPARAM)FALSE,

         (LPARAM)-1

   );

#else

   SendMessage(

         lpLL->m_hWndListBox,

         LB_SETSEL,

         (WPARAM)FALSE,

         MAKELPARAM(-1,0)

   );

#endif

   /* mark selection */

   SendMessage(lpLL->m_hWndListBox,LB_SELITEMRANGE, (WPARAM)TRUE, (LPARAM)dwSel);

   /* set focus line (caret) */

   LineList_SetFocusLine ( lpLL, (WORD)lplrSel->m_nStartLine );

}

/* LineList_GetSel

 * ---------------

 *

 * Get the selection in list box.

 *

 * Returns the count of items selected

 */

int LineList_GetSel(LPLINELIST lpLL, LPLINERANGE lplrSel)

{

   int nNumSel=(int)SendMessage(lpLL->m_hWndListBox,LB_GETSELCOUNT,0,0L);

   if (nNumSel) {

      SendMessage(lpLL->m_hWndListBox,LB_GETSELITEMS,

         (WPARAM)1,(LPARAM)(int FAR*)&(lplrSel->m_nStartLine));

      lplrSel->m_nEndLine = lplrSel->m_nStartLine + nNumSel - 1;

   } else {

      _fmemset(lplrSel, 0, sizeof(LINERANGE));

   }

   return nNumSel;

}

/* LineList_RemoveSel

 * ------------------

 *

 * Remove the selection in list box but save the selection state so that

 * it can be restored by calling LineList_RestoreSel

 * LineList_RemoveSel is called when the LineList window looses focus.

 */

void LineList_RemoveSel(LPLINELIST lpLL)

{

   LINERANGE lrSel;

   if (LineList_GetSel(lpLL, &lrSel) > 0) {

      lpLL->m_lrSaveSel = lrSel;

#if defined( WIN32 )

      SendMessage(

            lpLL->m_hWndListBox,

            LB_SETSEL,

            (WPARAM)FALSE,

            (LPARAM)-1

      );

#else

      SendMessage(

            lpLL->m_hWndListBox,

            LB_SETSEL,

            (WPARAM)FALSE,

            MAKELPARAM(-1,0)

      );

#endif

   }

}

/* LineList_RestoreSel

 * ------------------

 *

 * Restore the selection in list box that was previously saved by a call to

 * LineList_RemoveSel.

 * LineList_RestoreSel is called when the LineList window gains focus.

 */

void LineList_RestoreSel(LPLINELIST lpLL)

{

   LineList_SetSel(lpLL, &lpLL->m_lrSaveSel);

}

/* LineList_SetRedraw

 * ------------------

 *

 *      Enable/Disable the redraw of the linelist (listbox) on screen

 *

 *  fEnbaleDraw = TRUE      - enable redraw

 *                FALSE     - disable redraw

 */

void LineList_SetRedraw(LPLINELIST lpLL, BOOL fEnableDraw)

{

   SendMessage(lpLL->m_hWndListBox,WM_SETREDRAW,(WPARAM)fEnableDraw,0L);

}

/* LineList_ForceRedraw

 * --------------------

 *

 *      Force redraw of the linelist (listbox) on screen

 */

void LineList_ForceRedraw(LPLINELIST lpLL, BOOL fErase)

{

   InvalidateRect(lpLL->m_hWndListBox, NULL, fErase);

}

/* LineList_ForceLineRedraw

 * ------------------------

 *

 *      Force a particular line of the linelist (listbox) to redraw.

 */

void LineList_ForceLineRedraw(LPLINELIST lpLL, int nIndex, BOOL fErase)

{

   RECT   rect;

   LineList_GetLineRect( lpLL, nIndex, (LPRECT)&rect );

   InvalidateRect( lpLL->m_hWndListBox, (LPRECT)&rect, fErase );

}

/* LineList_ScrollLineIntoView

 * ---------------------------

 *  Make sure that the specified line is in view; if necessary scroll

 *      the listbox. if any portion of the line is visible, then no

 *      scrolling will occur.

 */

void LineList_ScrollLineIntoView(LPLINELIST lpLL, int nIndex)

{

   RECT rcWindow;

   RECT rcLine;

   RECT rcInt;

   if ( lpLL->m_nNumLines == 0 )

      return;

   if (! LineList_GetLineRect( lpLL, nIndex, (LPRECT)&rcLine ) )

      return;

   GetClientRect( lpLL->m_hWndListBox, (LPRECT) &rcWindow );

   if (! IntersectRect((LPRECT)&rcInt, (LPRECT)&rcWindow, (LPRECT)&rcLine))

      SendMessage(

            lpLL->m_hWndListBox,

            LB_SETTOPINDEX,

            (WPARAM)nIndex,

            (LPARAM)NULL

      );

}

/* LineList_CopySelToDoc

 * ---------------------

 *

 *      Copy the selection of the linelist to another document

 *

 *  RETURNS: number of lines copied.

 */

int LineList_CopySelToDoc(

      LPLINELIST              lpSrcLL,

      LPLINERANGE             lplrSel,

      LPOUTLINEDOC            lpDestDoc

)

{

   int             nEndLine;

   int             nStartLine;

   LPLINELIST      lpDestLL = &lpDestDoc->m_LineList;

   signed short    nDestIndex = LineList_GetFocusLineIndex(lpDestLL);

   LPLINE          lpSrcLine;

   int             nCopied = 0;

   int             i;

   if (lplrSel) {

      nEndLine = lplrSel->m_nEndLine;

      nStartLine = lplrSel->m_nStartLine;

   } else {

      nEndLine = LineList_GetCount(lpSrcLL) - 1;

      nStartLine = 0;

   }

   for(i = nStartLine; i <= nEndLine; i++) {

      lpSrcLine = LineList_GetLine(lpSrcLL, i);

      if (lpSrcLine && Line_CopyToDoc(lpSrcLine, lpDestDoc, nDestIndex)) {

         nDestIndex++;

         nCopied++;

      }

   }

   return nCopied;

}

/* LineList_SaveSelToStg

 * ---------------------

 *

 *      Save lines in selection into lpDestStg.

 *

 *      Return TRUE if ok, FALSE if error

 */

BOOL LineList_SaveSelToStg(

      LPLINELIST              lpLL,

      LPLINERANGE             lplrSel,

      UINT                    uFormat,

      LPSTORAGE               lpSrcStg,

      LPSTORAGE               lpDestStg,

      LPSTREAM                lpLLStm,

      BOOL                    fRemember

)

{

   int nEndLine;

   int nStartLine;

   int nNumLinesWritten = 0;

   HRESULT hrErr = NOERROR;

   ULONG nWritten;

   LPLINE lpLine;

   LINELISTHEADER_ONDISK llhRecord;

   int i;

   LARGE_INTEGER dlibSaveHeaderPos;

   LARGE_INTEGER dlibZeroOffset;

   LISet32( dlibZeroOffset, 0 );

   if (lplrSel) {

      nEndLine = lplrSel->m_nEndLine;

      nStartLine = lplrSel->m_nStartLine;

   } else {

      nEndLine = LineList_GetCount(lpLL) - 1;

      nStartLine = 0;

   }

   _fmemset(&llhRecord,0,sizeof(llhRecord));

   /* save seek position for LineList header record */

   hrErr = lpLLStm->lpVtbl->Seek(

         lpLLStm,

         dlibZeroOffset,

         STREAM_SEEK_CUR,

         (ULARGE_INTEGER FAR*)&dlibSaveHeaderPos

   );

   if (hrErr != NOERROR) goto error;

   /* write LineList header record */

   hrErr = lpLLStm->lpVtbl->Write(

         lpLLStm,

         (LPVOID)&llhRecord,

         sizeof(llhRecord),

         &nWritten

    );

   if (hrErr != NOERROR) {

      OleDbgOutHResult("Write LineList header returned", hrErr);

      goto error;

    }

   for(i = nStartLine; i <= nEndLine; i++) {

      lpLine = LineList_GetLine(lpLL, i);

      if(lpLine &&

         Line_SaveToStg(lpLine, uFormat, lpSrcStg, lpDestStg, lpLLStm,

                                                fRemember))

         llhRecord.m_nNumLines++;

   }

   /* retore seek position for LineList header record */

   hrErr = lpLLStm->lpVtbl->Seek(

         lpLLStm,

         dlibSaveHeaderPos,

         STREAM_SEEK_SET,

         NULL

   );

   if (hrErr != NOERROR) goto error;

   /* write LineList header record */

   hrErr = lpLLStm->lpVtbl->Write(

         lpLLStm,

         (LPVOID)&llhRecord,

         sizeof(llhRecord),

         &nWritten

   );

   if (hrErr != NOERROR) goto error;

   /* reset seek position to end of stream */

   hrErr = lpLLStm->lpVtbl->Seek(

         lpLLStm,

         dlibZeroOffset,

         STREAM_SEEK_END,

         NULL

   );

   if (hrErr != NOERROR) goto error;

   return TRUE;

error:

#if defined( _DEBUG )

   OleDbgAssertSz(

         hrErr == NOERROR,

         "Could not write LineList header to LineList stream"

   );

#endif

   return FALSE;

}

/* LineList_LoadFromStg

 * --------------------

 *

 *      Load lines into linelist from storage.

 *

 *      Return TRUE if ok, FALSE if error

 */

BOOL LineList_LoadFromStg(

      LPLINELIST              lpLL,

      LPSTORAGE               lpSrcStg,

      LPSTREAM                lpLLStm

)

{

   HRESULT hrErr;

   ULONG nRead;

   LPLINE lpLine;

   int i;

   int nNumLines;

   LINELISTHEADER_ONDISK llineRecord;

   /* write LineList header record */

   hrErr = lpLLStm->lpVtbl->Read(

         lpLLStm,

         (LPVOID)&llineRecord,

         sizeof(llineRecord),

         &nRead

   );

   if (hrErr != NOERROR) {

      OleDbgOutHResult("Read LineList header returned", hrErr);

      goto error;

    }

   nNumLines = (int) llineRecord.m_nNumLines;

   for(i = 0; i < nNumLines; i++) {

      lpLine = Line_LoadFromStg(lpSrcStg, lpLLStm, lpLL->m_lpDoc);

      if (! lpLine)

         goto error;

      // Directly add lines to LineList without trying to update a NameTbl

      LineList_AddLine(lpLL, lpLine, i-1);

   }

   return TRUE;

error:

   // Delete any Line objects that were created

   if (lpLL->m_nNumLines > 0) {

      int nNumLines = lpLL->m_nNumLines;

      for (i = 0; i < nNumLines; i++)

         LineList_DeleteLine(lpLL, i);

   }

   return FALSE;

}

#if defined( USE_DRAGDROP )

/* LineList_SetFocusLineFromPointl

 * -------------------------------

 *

 */

void LineList_SetFocusLineFromPointl( LPLINELIST lpLL, POINTL pointl )

{

   int i = LineList_GetLineIndexFromPointl( lpLL, pointl );

   if ( i == (int)-1)

      return ;

   else

      LineList_SetFocusLine( lpLL, (WORD)i );

}

/* LineList_SetDragOverLineFromPointl

 * ----------------------------------

 *

 */

void LineList_SetDragOverLineFromPointl ( LPLINELIST lpLL, POINTL pointl )

{

   int    nIndex = LineList_GetLineIndexFromPointl( lpLL, pointl );

   LPLINE lpline = LineList_GetLine( lpLL, nIndex );

   if (!lpline)

      return;

   if (! lpline->m_fDragOverLine) {

      /* user has dragged over a new line. force new drop target line

      **    to repaint so that drop feedback will be drawn.

      */

      lpline->m_fDragOverLine = TRUE;

      LineList_ForceLineRedraw( lpLL, nIndex, TRUE /*fErase*/);

      if (lpLL->m_iDragOverLine!= -1 && lpLL->m_iDragOverLine!=nIndex) {

         /* force previous drop target line to repaint so that drop

         **    feedback will be undrawn

         */

         lpline = LineList_GetLine( lpLL, lpLL->m_iDragOverLine );

         if (lpline)

            lpline->m_fDragOverLine = FALSE;

         LineList_ForceLineRedraw(

               lpLL,lpLL->m_iDragOverLine,TRUE /*fErase*/);

      }

      lpLL->m_iDragOverLine = nIndex;

      // Force repaint immediately

      UpdateWindow(lpLL->m_hWndListBox);

   }

}

/* LineList_Scroll

 * ---------------

 *

 * Scroll the LineList list box in the desired direction by one line.

 *

 *      this function is called during a drag operation.

 */

void LineList_Scroll(LPLINELIST lpLL, DWORD dwScrollDir)

{

   switch (dwScrollDir) {

      case SCROLLDIR_UP:

         SendMessage( lpLL->m_hWndListBox, WM_VSCROLL, SB_LINEUP, 0L );

         break;

      case SCROLLDIR_DOWN:

         SendMessage( lpLL->m_hWndListBox, WM_VSCROLL, SB_LINEDOWN, 0L );

         break;

   }

}

/* LineList_GetLineIndexFromPointl

 * -------------------------------

 *   do hit test to get index of line corresponding to pointl

 */

int LineList_GetLineIndexFromPointl(LPLINELIST lpLL, POINTL pointl)

{

   RECT  rect;

   POINT point;

   DWORD i;

   point.x = (int)pointl.x;

   point.y = (int)pointl.y;

   ScreenToClient( lpLL->m_hWndListBox, &point);

   if ( lpLL->m_nNumLines == 0 )

      return -1;

   GetClientRect( lpLL->m_hWndListBox, (LPRECT) &rect );

   i = SendMessage( lpLL->m_hWndListBox, LB_GETTOPINDEX, (WPARAM)NULL, (LPARAM)NULL );

   for ( ;; i++){

      RECT rectItem;

      if (!LineList_GetLineRect( lpLL, (int)i, (LPRECT)&rectItem ) )

         return -1;

      if ( rectItem.top > rect.bottom )

         return -1;

      if ( rectItem.top <= point.y && point.y <= rectItem.bottom)

         return (int)i;

   }

}

/* LineList_RestoreDragFeedback

 * ----------------------------

 *

 * Retore the index of the line that currently has focus (the active line).

 */

void LineList_RestoreDragFeedback(LPLINELIST lpLL)

{

   LPLINE lpLine;

   if (lpLL->m_iDragOverLine < 0 )

      return;

   lpLine = LineList_GetLine( lpLL, lpLL->m_iDragOverLine);

   if (lpLine) {

      lpLine->m_fDragOverLine = FALSE;

      LineList_ForceLineRedraw( lpLL,lpLL->m_iDragOverLine,TRUE /*fErase*/);

      // Force repaint immediately

      UpdateWindow(lpLL->m_hWndListBox);

   }

   lpLL->m_iDragOverLine = -1;

}

#endif


OUTLNAME.C  (OUTLINE Sample)

/*************************************************************************

**

**    OLE 2 Sample Code

**

**    outlname.c

**

**    This file contains OutlineName functions.

**

**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

**

*************************************************************************/

#include "outline.h"

OLEDBGDATA

/* OutlineName_SetName

 * -------------------

 *

 *      Change the string of a name.

 */

void OutlineName_SetName(LPOUTLINENAME lpOutlineName, LPOLESTR lpszName)

{

   OLESTRCPY(lpOutlineName->m_szName, lpszName);

}

/* OutlineName_SetSel

 * ------------------

 *

 *      Change the line range of a  name.

 */

void OutlineName_SetSel(LPOUTLINENAME lpOutlineName, LPLINERANGE lplrSel, BOOL fRangeModified)

{

#if defined( OLE_SERVER )

   // Call OLE server specific function instead

   ServerName_SetSel((LPSERVERNAME)lpOutlineName, lplrSel, fRangeModified);

#else

   lpOutlineName->m_nStartLine = lplrSel->m_nStartLine;

   lpOutlineName->m_nEndLine = lplrSel->m_nEndLine;

#endif

}

/* OutlineName_GetSel

 * ------------------

 *

 *      Retrieve the line range of a name.

 */

void OutlineName_GetSel(LPOUTLINENAME lpOutlineName, LPLINERANGE lplrSel)

{

   lplrSel->m_nStartLine = lpOutlineName->m_nStartLine;

   lplrSel->m_nEndLine = lpOutlineName->m_nEndLine;

}

/* OutlineName_SaveToStg

 * ---------------------

 *

 *      Save a name into a storage

 */

BOOL OutlineName_SaveToStg(LPOUTLINENAME lpOutlineName, LPLINERANGE lplrSel, UINT uFormat, LPSTREAM lpNTStm, BOOL FAR* lpfNameSaved)

{

   HRESULT hrErr = NOERROR;

   ULONG nWritten;

   *lpfNameSaved = FALSE;

   /* if no range given or if the name is completely within the range,

   **      write it out.

   */

   if (!lplrSel ||

      ((lplrSel->m_nStartLine <= lpOutlineName->m_nStartLine) &&

      (lplrSel->m_nEndLine >= lpOutlineName->m_nEndLine))) {

      hrErr = lpNTStm->lpVtbl->Write(

            lpNTStm,

            lpOutlineName,

            sizeof(OUTLINENAME),

            &nWritten

      );

      *lpfNameSaved = TRUE;

   }

   return ((hrErr == NOERROR) ? TRUE : FALSE);

}

/* OutlineName_LoadFromStg

 * -----------------------

 *

 *      Load names from an open stream of a storage. if the name already

 * exits in the OutlineNameTable, it is NOT modified.

 *

 *      Returns TRUE is all ok, else FALSE.

 */

BOOL OutlineName_LoadFromStg(LPOUTLINENAME lpOutlineName, LPSTREAM lpNTStm)

{

   HRESULT hrErr = NOERROR;

   ULONG nRead;

   hrErr = lpNTStm->lpVtbl->Read(

         lpNTStm,

         lpOutlineName,

         sizeof(OUTLINENAME),

         &nRead

   );

   return ((hrErr == NOERROR) ? TRUE : FALSE);

}


OUTLNTBL.C  (OUTLINE Sample)

/*************************************************************************

**

**    OLE 2 Sample Code

**

**    outlntbl.c

**

**    This file contains OutlineNameTable functions.

**

**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

**

*************************************************************************/

#include "outline.h"

OLEDBGDATA

extern LPOUTLINEAPP g_lpApp;

OLECHAR ErrMsgNameTable[] = OLESTR("Can't create NameTable!");

/* OutlineNameTable_Init

 * ---------------------

 *

 *      initialize a name table.

 */

BOOL OutlineNameTable_Init(LPOUTLINENAMETABLE lpOutlineNameTable, LPOUTLINEDOC lpOutlineDoc)

{

   HWND lpParent = OutlineDoc_GetWindow(lpOutlineDoc);

   lpOutlineNameTable->m_nCount = 0;

   /* We will use an OwnerDraw listbox as our data structure to

   **    maintain the table of Names. this listbox will never be made

   **    visible. the listbox is just a convenient data structure to

   **    manage a collection.

   */

   lpOutlineNameTable->m_hWndListBox = CreateWindow(

               "listbox",              /* Window class name           */

               NULL,                   /* Window's title              */

               WS_CHILDWINDOW |

               LBS_OWNERDRAWFIXED,

               0, 0,                   /* Use default X, Y            */

               0, 0,                   /* Use default X, Y            */

               lpParent,               /* Parent window's handle      */

               (HMENU)IDC_NAMETABLE,   /* Child Window ID             */

               g_lpApp->m_hInst,       /* Instance of window          */

               NULL);                  /* Create struct for WM_CREATE */

   if (! lpOutlineNameTable->m_hWndListBox) {

      OutlineApp_ErrorMessage(g_lpApp, ErrMsgNameTable);

      return FALSE;

   }

   return TRUE;

}

/* OutlineNameTable_Destroy

 * ------------------------

 *

 *      Free memory used by the name table.

 */

void OutlineNameTable_Destroy(LPOUTLINENAMETABLE lpOutlineNameTable)

{

   // Delete all names

   OutlineNameTable_ClearAll(lpOutlineNameTable);

   DestroyWindow(lpOutlineNameTable->m_hWndListBox);

   Delete(lpOutlineNameTable);

}

/* OutlineNameTable_AddName

 * ------------------------

 *

 *      Add a name to the table

 */

void OutlineNameTable_AddName(LPOUTLINENAMETABLE lpOutlineNameTable, LPOUTLINENAME lpOutlineName)

{

   SendMessage(

         lpOutlineNameTable->m_hWndListBox,

         LB_ADDSTRING,

         0,

         (DWORD)lpOutlineName

   );

   lpOutlineNameTable->m_nCount++;

}

/* OutlineNameTable_DeleteName

 * ---------------------------

 *

 *      Delete a name from table

 */

void OutlineNameTable_DeleteName(LPOUTLINENAMETABLE lpOutlineNameTable,int nIndex)

{

   LPOUTLINENAME lpOutlineName = OutlineNameTable_GetName(lpOutlineNameTable, nIndex);

#if defined( OLE_SERVER )

   /* OLE2NOTE: if there is a pseudo object attached to this name, it

   **    must first be closed before deleting the Name. this will

   **    cause OnClose notification to be sent to all linking clients.

   */

   ServerName_ClosePseudoObj((LPSERVERNAME)lpOutlineName);

#endif

   if (lpOutlineName)

      Delete(lpOutlineName);      // free memory for name

   SendMessage(

         lpOutlineNameTable->m_hWndListBox,

         LB_DELETESTRING,

         (WPARAM)nIndex,

         0L

   );

   lpOutlineNameTable->m_nCount--;

}

/* OutlineNameTable_GetNameIndex

 * -----------------------------

 *

 *      Return the index of the Name given a pointer to the Name.

 *      Return -1 if the Name is not found.

 */

int OutlineNameTable_GetNameIndex(LPOUTLINENAMETABLE lpOutlineNameTable, LPOUTLINENAME lpOutlineName)

{

   LRESULT lReturn;

   if (! lpOutlineName) return -1;

   lReturn = SendMessage(

         lpOutlineNameTable->m_hWndListBox,

         LB_FINDSTRING,

         (WPARAM)-1,

         (LPARAM)(LPCSTR)lpOutlineName

      );

   return ((lReturn == LB_ERR) ? -1 : (int)lReturn);

}

/* OutlineNameTable_GetName

 * ------------------------

 *

 *      Retrieve the pointer to the Name given its index in the NameTable

 */

LPOUTLINENAME OutlineNameTable_GetName(LPOUTLINENAMETABLE lpOutlineNameTable, int nIndex)

{

   LPOUTLINENAME lpOutlineName = NULL;

    LRESULT lResult;

   if (lpOutlineNameTable->m_nCount == 0 ||

      nIndex > lpOutlineNameTable->m_nCount ||

      nIndex < 0) {

      return NULL;

   }

   lResult = SendMessage(

         lpOutlineNameTable->m_hWndListBox,

         LB_GETTEXT,

         nIndex,

         (LPARAM)(LPCSTR)&lpOutlineName

   );

    OleDbgAssert(lResult != LB_ERR);

   return lpOutlineName;

}

/* OutlineNameTable_FindName

 * -------------------------

 *

 *      Find a name in the name table given a string.

 */

LPOUTLINENAME OutlineNameTable_FindName(LPOUTLINENAMETABLE lpOutlineNameTable, LPOLESTR lpszName)

{

   LPOUTLINENAME lpOutlineName;

   BOOL fFound = FALSE;

   int i;

   for (i = 0; i < lpOutlineNameTable->m_nCount; i++) {

      lpOutlineName = OutlineNameTable_GetName(lpOutlineNameTable, i);

      if (OLESTRCPY(lpOutlineName->m_szName, lpszName) == 0) {

         fFound = TRUE;

         break;      // FOUND MATCH!

      }

   }

   return (fFound ? lpOutlineName : NULL);

}

/* OutlineNameTable_FindNamedRange

 * -------------------------------

 *

 *      Find a name in the name table which matches a given line range.

 */

LPOUTLINENAME OutlineNameTable_FindNamedRange(LPOUTLINENAMETABLE lpOutlineNameTable, LPLINERANGE lplrSel)

{

   LPOUTLINENAME lpOutlineName;

   BOOL fFound = FALSE;

   int i;

   for (i = 0; i < lpOutlineNameTable->m_nCount; i++) {

      lpOutlineName = OutlineNameTable_GetName(lpOutlineNameTable, i);

      if ((lpOutlineName->m_nStartLine == lplrSel->m_nStartLine) &&

         (lpOutlineName->m_nEndLine == lplrSel->m_nEndLine) ) {

         fFound = TRUE;

         break;      // FOUND MATCH!

      }

   }

   return (fFound ? lpOutlineName : NULL);

}

/* OutlineNameTable_GetCount

 * -------------------------

 *

 * Return number of names in nametable

 */

int OutlineNameTable_GetCount(LPOUTLINENAMETABLE lpOutlineNameTable)

{

   if (!lpOutlineNameTable)

      return 0;

   return lpOutlineNameTable->m_nCount;

}

/* OutlineNameTable_ClearAll

 * -------------------------

 *

 *      Remove all names from table

 */

void OutlineNameTable_ClearAll(LPOUTLINENAMETABLE lpOutlineNameTable)

{

   LPOUTLINENAME lpOutlineName;

   int i;

   int nCount = lpOutlineNameTable->m_nCount;

   for (i = 0; i < nCount; i++) {

      lpOutlineName = OutlineNameTable_GetName(lpOutlineNameTable, i);

      Delete(lpOutlineName);      // free memory for name

   }

   lpOutlineNameTable->m_nCount = 0;

   SendMessage(lpOutlineNameTable->m_hWndListBox,LB_RESETCONTENT,0,0L);

}

/* OutlineNameTable_AddLineUpdate

 * ------------------------------

 *

 *      Update table when a new line is added at nAddIndex

 * The line used to be at nAddIndex is pushed down

 */

void OutlineNameTable_AddLineUpdate(LPOUTLINENAMETABLE lpOutlineNameTable, int nAddIndex)

{

   LPOUTLINENAME lpOutlineName;

   LINERANGE lrSel;

   int i;

   BOOL fRangeModified = FALSE;

   for(i = 0; i < lpOutlineNameTable->m_nCount; i++) {

      lpOutlineName=OutlineNameTable_GetName(lpOutlineNameTable, i);

      OutlineName_GetSel(lpOutlineName, &lrSel);

      if((int)lrSel.m_nStartLine > nAddIndex) {

         lrSel.m_nStartLine++;

         fRangeModified = !fRangeModified;

      }

      if((int)lrSel.m_nEndLine > nAddIndex) {

         lrSel.m_nEndLine++;

         fRangeModified = !fRangeModified;

      }

      OutlineName_SetSel(lpOutlineName, &lrSel, fRangeModified);

   }

}

/* OutlineNameTable_DeleteLineUpdate

 * ---------------------------------

 *

 *      Update the table when a line at nDeleteIndex is removed

 */

void OutlineNameTable_DeleteLineUpdate(LPOUTLINENAMETABLE lpOutlineNameTable, int nDeleteIndex)

{

   LPOUTLINENAME lpOutlineName;

   LINERANGE lrSel;

   int i;

   BOOL fRangeModified = FALSE;

   for(i = 0; i < lpOutlineNameTable->m_nCount; i++) {

      lpOutlineName=OutlineNameTable_GetName(lpOutlineNameTable, i);

      OutlineName_GetSel(lpOutlineName, &lrSel);

      if((int)lrSel.m_nStartLine > nDeleteIndex) {

         lrSel.m_nStartLine--;

         fRangeModified = !fRangeModified;

      }

      if((int)lrSel.m_nEndLine >= nDeleteIndex) {

         lrSel.m_nEndLine--;

         fRangeModified = !fRangeModified;

      }

      // delete the name if its entire range is deleted

      if(lrSel.m_nStartLine > lrSel.m_nEndLine) {

         OutlineNameTable_DeleteName(lpOutlineNameTable, i);

         i--;  // re-examine this name

      } else {

         OutlineName_SetSel(lpOutlineName, &lrSel, fRangeModified);

      }

   }

}

/* OutlineNameTable_SaveSelToStg

 * -----------------------------

 *

 *      Save only the names that refer to lines completely contained in the

 * specified selection range.

 */

BOOL OutlineNameTable_SaveSelToStg(

      LPOUTLINENAMETABLE      lpOutlineNameTable,

      LPLINERANGE             lplrSel,

      UINT                    uFormat,

      LPSTREAM                lpNTStm

)

{

   HRESULT hrErr;

   ULONG nWritten;

   LPOUTLINENAME lpOutlineName;

   short nNameCount = 0;

   BOOL fNameSaved;

   BOOL fStatus;

   int i;

   LARGE_INTEGER dlibZeroOffset;

   LISet32( dlibZeroOffset, 0 );

   /* initially write 0 for count of names. the correct count will be

   **    written at the end when we know how many names qualified to

   **    be written (within the selection).

   */

   hrErr = lpNTStm->lpVtbl->Write(

         lpNTStm,

         (short FAR*)&nNameCount,

         sizeof(nNameCount),

         &nWritten

   );

   if (hrErr != NOERROR) {

      OleDbgOutHResult("Write NameTable header returned", hrErr);

      goto error;

    }

   for(i = 0; i < lpOutlineNameTable->m_nCount; i++) {

      lpOutlineName=OutlineNameTable_GetName(lpOutlineNameTable, i);

      fStatus = OutlineName_SaveToStg(

            lpOutlineName,

            lplrSel,

            uFormat,

            lpNTStm,

            (BOOL FAR*)&fNameSaved

      );

      if (! fStatus) goto error;

      if (fNameSaved) nNameCount++;

   }

   /* write the final count of names written. */

   hrErr = lpNTStm->lpVtbl->Seek(

         lpNTStm,

         dlibZeroOffset,

         STREAM_SEEK_SET,

         NULL

   );

   if (hrErr != NOERROR) {

      OleDbgOutHResult("Seek to NameTable header returned", hrErr);

      goto error;

    }

   hrErr = lpNTStm->lpVtbl->Write(

         lpNTStm,

         (short FAR*)&nNameCount,

         sizeof(nNameCount),

         &nWritten

   );

   if (hrErr != NOERROR) {

      OleDbgOutHResult("Write NameTable count in header returned", hrErr);

      goto error;

    }

   OleStdRelease((LPUNKNOWN)lpNTStm);

   return TRUE;

error:

   if (lpNTStm)

      OleStdRelease((LPUNKNOWN)lpNTStm);

   return FALSE;

}

/* OutlineNameTable_LoadFromStg

 * ----------------------------

 *

 *      Load Name Table from file

 *

 *      Return TRUE if ok, FALSE if error

 */

BOOL OutlineNameTable_LoadFromStg(LPOUTLINENAMETABLE lpOutlineNameTable, LPSTORAGE lpSrcStg)

{

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   HRESULT hrErr;

   IStream FAR* lpNTStm;

   ULONG nRead;

   short nCount;

   LPOUTLINENAME lpOutlineName;

   BOOL fStatus;

   short i;

   hrErr = lpSrcStg->lpVtbl->OpenStream(

         lpSrcStg,

         OLESTR("NameTable"),

         NULL,

         STGM_READ | STGM_SHARE_EXCLUSIVE,

         0,

         &lpNTStm

   );

   if (hrErr != NOERROR) {

      OleDbgOutHResult("OpenStream NameTable returned", hrErr);

      goto error;

    }

   hrErr = lpNTStm->lpVtbl->Read(lpNTStm,&nCount,sizeof(nCount),&nRead);

   if (hrErr != NOERROR) {

      OleDbgOutHResult("Read NameTable header returned", hrErr);

      goto error;

    }

   for (i = 0; i < nCount; i++) {

      lpOutlineName = OutlineApp_CreateName(lpOutlineApp);

      if (! lpOutlineName) goto error;

      fStatus = OutlineName_LoadFromStg(lpOutlineName, lpNTStm);

      if (! fStatus) goto error;

      OutlineNameTable_AddName(lpOutlineNameTable, lpOutlineName);

   }

   OleStdRelease((LPUNKNOWN)lpNTStm);

   return TRUE;

error:

   if (lpNTStm)

      OleStdRelease((LPUNKNOWN)lpNTStm);

   return FALSE;

}


OUTLRC.H  (OUTLINE Sample)

/*************************************************************************

**

**    OLE 2.0 Sample Code

**

**    outlrc.h

**

**    This file containes constants used in rc file for Outline.exe

**

**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

**

*************************************************************************/

#if !defined( _OUTLRC_H_ )

#define _OUTLRC_H_

#ifndef RC_INVOKED

#pragma message ("INCLUDING OUTLRC.H from " __FILE__)

#endif  /* RC_INVOKED */

#if defined( OLE_SERVER ) && ! defined( INPLACE_SVR )

#ifdef TEST32

#define APPNAME                 OLESTR("SvrOut32")

#define APPDESC                 "OLE 2.0 Server Sample Code 32"

#else

#define APPNAME                 OLESTR("SvrOutl")

#define APPDESC                 "OLE 2.0 Server Sample Code"

#endif   //TEST32

#define APPMENU                 "SvrOutlMenu"

#define APPACCEL                "SvrOutlAccel"

#define FB_EDIT_ACCEL           "SvrOutlAccelFocusEdit"

#define APPICON                 "SvrOutlIcon"

#define APPWNDCLASS             "SvrOutlApp"

#define DOCWNDCLASS             "SvrOutlDoc"

#endif  // OLE_SERVER && ! INPLACE_SVR

#if defined( INPLACE_SVR )

#ifdef TEST32

#define APPNAME                 OLESTR("ISvrOu32")

#define APPDESC                 "OLE 2.0 In-Place Server Sample Code 32"

#else

#define APPNAME                 OLESTR("ISvrOtl")

#define APPDESC                 "OLE 2.0 In-Place Server Sample Code"

#endif //TEST32

#define APPMENU                 "SvrOutlMenu"

#define APPACCEL                "SvrOutlAccel"

#define FB_EDIT_ACCEL           "SvrOutlAccelFocusEdit"

#define APPICON                 "SvrOutlIcon"

#define APPWNDCLASS             "SvrOutlApp"

#define DOCWNDCLASS             "SvrOutlDoc"

#endif  // INPLACE_SVR

#if defined( OLE_CNTR ) && ! defined( INPLACE_CNTR )

#ifdef TEST32

#define APPNAME                 OLESTR("CntrOu32")

#define APPDESC                 "OLE 2.0 Container Sample Code 32"

#else

#define APPNAME                 OLESTR("CntrOutl")

#define APPDESC                 "OLE 2.0 Container Sample Code"

#endif //TEST32

#define APPMENU                 "CntrOutlMenu"

#define APPACCEL                "CntrOutlAccel"

#define FB_EDIT_ACCEL           "CntrOutlAccelFocusEdit"

#define APPICON                 "CntrOutlIcon"

#define APPWNDCLASS             "CntrOutlApp"

#define DOCWNDCLASS             "CntrOutlDoc"

#endif  // OLE_CNTR && ! INPLACE_CNTR

#if defined( INPLACE_CNTR )

#ifdef TEST32

#define APPNAME                 OLESTR("ICntrO32")

#define APPDESC                 "OLE 2.0 In-Place Container Sample Code 32"

#else

#define APPNAME                 OLESTR("ICntrOtl")

#define APPDESC                 "OLE 2.0 In-Place Container Sample Code"

#endif

#define APPMENU                 "CntrOutlMenu"

#define APPACCEL                "CntrOutlAccel"

#define FB_EDIT_ACCEL           "CntrOutlAccelFocusEdit"

#define APPICON                 "CntrOutlIcon"

#define APPWNDCLASS             "CntrOutlApp"

#define DOCWNDCLASS             "CntrOutlDoc"

#endif  // INPLACE_CNTR

#if !defined( OLE_VERSION )

#define APPNAME                 OLESTR("Outline")

#define APPMENU                 "OutlineMenu"

#define APPACCEL                "OutlineAccel"

#define FB_EDIT_ACCEL           "OutlineAccelFocusEdit"

#define APPICON                 "OutlineIcon"

#define APPWNDCLASS             "OutlineApp"

#define DOCWNDCLASS             "OutlineDoc"

#define APPDESC                 "OLE 2.0 Sample Code"

#endif  // OLE_VERSION

#define IDM_FILE                       1000

#define IDM_F_NEW                      1050

#define IDM_F_OPEN                     1100

#define IDM_F_SAVE                     1150

#define IDM_F_SAVEAS                   1200

#define IDM_F_PRINT                    1300

#define IDM_F_PRINTERSETUP             1350

#define IDM_F_EXIT                     1450

#define IDM_EDIT                       2000

#define IDM_E_UNDO                     2050

#define IDM_E_CUT                      2150

#define IDM_E_COPY                     2200

#define IDM_E_PASTE                    2250

#define IDM_E_PASTESPECIAL             2255

#define IDM_E_CLEAR                    2300

#define IDM_E_SELECTALL                2560

#define IDM_LINE                       3000

#define IDM_L_ADDLINE                  3400

#define IDM_L_EDITLINE                 3450

#define IDM_L_INDENTLINE               3500

#define IDM_L_UNINDENTLINE             3550

#define IDM_L_SETLINEHEIGHT            3560

#define IDM_NAME                       4000

#define IDM_N_DEFINENAME               4050

#define IDM_N_GOTONAME                 4100

#define IDM_HELP                       5000

#define IDM_H_ABOUT                    5050

#define IDM_DEBUG                      6000

#define IDM_D_DEBUGLEVEL               6050

#define IDM_D_INSTALLMSGFILTER         6060

#define IDM_D_REJECTINCOMING            6070

#define IDM_O_BB_TOP                   6100

#define IDM_O_BB_BOTTOM                6150

#define IDM_O_BB_POPUP                 6200

#define IDM_O_BB_HIDE                  6210

#define IDM_O_FB_TOP                   6250

#define IDM_O_FB_BOTTOM                6300

#define IDM_O_FB_POPUP                 6350

#define IDM_O_HEAD_SHOW                6400

#define IDM_O_HEAD_HIDE                6450

#define IDM_O_SHOWOBJECT               6460

#define IDM_V_ZOOM_400                 6500

#define IDM_V_ZOOM_300                 6510

#define IDM_V_ZOOM_200                 6520

#define IDM_V_ZOOM_100                 6550

#define IDM_V_ZOOM_75                  6600

#define IDM_V_ZOOM_50                  6650

#define IDM_V_ZOOM_25                  6700

#define IDM_V_SETMARGIN_0              6750

#define IDM_V_SETMARGIN_1              6800

#define IDM_V_SETMARGIN_2              6850

#define IDM_V_SETMARGIN_3              6860

#define IDM_V_SETMARGIN_4              6870

#define IDM_V_ADDTOP_1                 6900

#define IDM_V_ADDTOP_2                 6910

#define IDM_V_ADDTOP_3                 6920

#define IDM_V_ADDTOP_4                 6930

#define IDM_FB_EDIT                    7000

#define IDM_FB_CANCEL                  7005

#define IDM_F2                         7010

#define IDM_ESCAPE                     7015

#define IDD_LINELISTBOX                101

#define IDD_EDIT                       102

#define IDD_COMBO                      103

#define IDD_DELETE                     104

#define IDD_CLOSE                      105

#define IDD_APPTEXT                    106

#define IDD_FROM                       107

#define IDD_TO                         108

#define IDD_BITMAPLOCATION             109

#define IDD_CHECK                      110

#define IDD_TEXT                       111

#define IDD_LIMIT                      112

#define IDC_LINELIST                   201

#define IDC_NAMETABLE                  202

#define WM_U_INITFRAMETOOLS            WM_USER

#ifdef RC_INVOKED

#include "debug.rc"

#endif  /* RC_INVOKED */

#endif // _OUTLRC_H_


OUTLTXTL.C  (OUTLINE Sample)

/*************************************************************************

**

**    OLE 2 Sample Code

**

**    outltxtl.c

**

**    This file contains TextLine methods and related support functions.

**

**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

**

*************************************************************************/

#include "outline.h"

OLEDBGDATA

extern LPOUTLINEAPP g_lpApp;

/* TextLine_Create

 * ---------------

 *

 *      Create a text line object and return the pointer

 */

LPTEXTLINE TextLine_Create(HDC hDC, UINT nTab, LPSTR lpszText)

{

        LPTEXTLINE lpTextLine;

        lpTextLine=(LPTEXTLINE) New((DWORD)sizeof(TEXTLINE));

        if (lpTextLine == NULL) {

                OleDbgAssertSz(lpTextLine!=NULL,"Error allocating TextLine");

                return NULL;

        }

        TextLine_Init(lpTextLine, nTab, hDC);

        if (lpszText) {

                lpTextLine->m_nLength = lstrlen(lpszText);

                lstrcpy((LPSTR)lpTextLine->m_szText, lpszText);

        } else {

                lpTextLine->m_nLength = 0;

                lpTextLine->m_szText[0] = '\0';

        }

        TextLine_CalcExtents(lpTextLine, hDC);

        return(lpTextLine);

}

/* TextLine_Init

 * -------------

 *

 *      Calculate the width/height of a text line object.

 */

void TextLine_Init(LPTEXTLINE lpTextLine, int nTab, HDC hDC)

{

        Line_Init((LPLINE)lpTextLine, nTab, hDC);   // init the base class fields

        ((LPLINE)lpTextLine)->m_lineType = TEXTLINETYPE;

        lpTextLine->m_nLength = 0;

        lpTextLine->m_szText[0] = '\0';

}

/* TextLine_Delete

 * ---------------

 *

 *      Delete the TextLine structure

 */

void TextLine_Delete(LPTEXTLINE lpTextLine)

{

        Delete((LPVOID)lpTextLine);

}

/* TextLine_Edit

 * -------------

 *

 *      Edit the text line object.

 *

 *      Returns TRUE if line was changed

 *              FALSE if the line was NOT changed

 */

BOOL TextLine_Edit(LPTEXTLINE lpLine, HWND hWndDoc, HDC hDC)

{

#if defined( USE_FRAMETOOLS )

        LPFRAMETOOLS lptb = OutlineApp_GetFrameTools(g_lpApp);

#endif

        BOOL fStatus = FALSE;

#if defined( USE_FRAMETOOLS )

        FrameTools_FB_GetEditText(lptb, lpLine->m_szText, sizeof(lpLine->m_szText));

#else

        if (! InputTextDlg(hWndDoc, lpLine->m_szText, "Edit Line"))

                return FALSE;

#endif

        lpLine->m_nLength = lstrlen(lpLine->m_szText);

        TextLine_CalcExtents(lpLine, hDC);

        fStatus = TRUE;

        return fStatus;

}

/* TextLine_CalcExtents

 * --------------------

 *

 *      Calculate the width/height of a text line object.

 */

void TextLine_CalcExtents(LPTEXTLINE lpTextLine, HDC hDC)

{

        SIZE size;

        LPLINE lpLine = (LPLINE)lpTextLine;

        if (lpTextLine->m_nLength) {

                GetTextExtentPoint(hDC, lpTextLine->m_szText,

                                                        lpTextLine->m_nLength, &size);

                lpLine->m_nWidthInHimetric=size.cx;

                lpLine->m_nHeightInHimetric=size.cy;

        } else {

                // we still need to calculate proper height even for NULL string

                TEXTMETRIC tm;

                GetTextMetrics(hDC, &tm);

                // required to set height

                lpLine->m_nHeightInHimetric = tm.tmHeight;

                lpLine->m_nWidthInHimetric = 0;

        }

#if defined( _DEBUG )

        {

                RECT rc;

                rc.left = 0;

                rc.top = 0;

                rc.right = XformWidthInHimetricToPixels(hDC,

                                lpLine->m_nWidthInHimetric);

                rc.bottom = XformHeightInHimetricToPixels(hDC,

                                lpLine->m_nHeightInHimetric);

                OleDbgOutRect3("TextLine_CalcExtents", (LPRECT)&rc);

        }

#endif

}

/* TextLine_SetHeightInHimetric

 * ----------------------------

 *

 *      Set the height of a textline object.

 */

void TextLine_SetHeightInHimetric(LPTEXTLINE lpTextLine, int nHeight)

{

        if (!lpTextLine)

                return;

        ((LPLINE)lpTextLine)->m_nHeightInHimetric = nHeight;

}

/* TextLine_GetTextLen

 * -------------------

 *

 * Return length of string of the TextLine (not considering the tab level).

 */

int TextLine_GetTextLen(LPTEXTLINE lpTextLine)

{

        return lstrlen((LPSTR)lpTextLine->m_szText);

}

/* TextLine_GetTextData

 * --------------------

 *

 * Return the string of the TextLine (not considering the tab level).

 */

void TextLine_GetTextData(LPTEXTLINE lpTextLine, LPSTR lpszBuf)

{

        lstrcpy(lpszBuf, (LPSTR)lpTextLine->m_szText);

}

/* TextLine_GetOutlineData

 * -----------------------

 *

 * Return the CF_OUTLINE format data for the TextLine.

 */

BOOL TextLine_GetOutlineData(LPTEXTLINE lpTextLine, LPTEXTLINE lpBuf)

{

        TextLine_Copy((LPTEXTLINE)lpTextLine, lpBuf);

        return TRUE;

}

/* TextLine_Draw

 * -------------

 *

 *      Draw a text line object on a DC.

 * Parameters:

 *      hDC     - DC to which the line will be drawn

 *      lpRect  - the object rectangle in logical coordinates

 *      lpRectWBounds - bounding rect of the metafile underneath hDC

 *                      (NULL if hDC is not a metafile DC)

 *                      this is used by ContainerLine_Draw to draw the OLE obj

 *      fHighlight    - TRUE use selection highlight text color

 */

void TextLine_Draw(

                LPTEXTLINE  lpTextLine,

                HDC         hDC,

                LPRECT      lpRect,

                LPRECT      lpRectWBounds,

                BOOL        fHighlight

)

{

        RECT rc;

        int nBkMode;

        COLORREF clrefOld;

        if (!lpTextLine)

                return;

        rc = *lpRect;

        rc.left += ((LPLINE)lpTextLine)->m_nTabWidthInHimetric;

        rc.right += ((LPLINE)lpTextLine)->m_nTabWidthInHimetric;

        nBkMode = SetBkMode(hDC, TRANSPARENT);

        if (fHighlight) {

                /*Get proper txt colors */

                clrefOld = SetTextColor(hDC,GetSysColor(COLOR_HIGHLIGHTTEXT));

        }

        else {

                clrefOld = SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT));

        }

        ExtTextOut(

                        hDC,

                        rc.left,

                        rc.top,

                        ETO_CLIPPED,

                        (LPRECT)&rc,

                        lpTextLine->m_szText,

                        lpTextLine->m_nLength,

                        (LPINT) NULL /* default char spacing */

        );

        SetTextColor(hDC, clrefOld);

        SetBkMode(hDC, nBkMode);

}

/* TextLine_DrawSelHilight

 * -----------------------

 *

 *      Handles selection of textline

 */

void TextLine_DrawSelHilight(LPTEXTLINE lpTextLine, HDC hDC, LPRECT lpRect, UINT itemAction, UINT itemState)

{

        if (itemAction & ODA_SELECT) {

                // check if there is a selection state change, ==> invert rect

                if (itemState & ODS_SELECTED) {

                        if (!((LPLINE)lpTextLine)->m_fSelected) {

                                ((LPLINE)lpTextLine)->m_fSelected = TRUE;

                                InvertRect(hDC, (LPRECT)lpRect);

                        }

                } else {

                        if (((LPLINE)lpTextLine)->m_fSelected) {

                                ((LPLINE)lpTextLine)->m_fSelected = FALSE;

                                InvertRect(hDC, lpRect);

                        }

                }

        } else if (itemAction & ODA_DRAWENTIRE) {

                ((LPLINE)lpTextLine)->m_fSelected=((itemState & ODS_SELECTED) ? TRUE : FALSE);

                InvertRect(hDC, lpRect);

        }

}

/* TextLine_Copy

 * -------------

 *

 *      Duplicate a textline

 */

BOOL TextLine_Copy(LPTEXTLINE lpSrcLine, LPTEXTLINE lpDestLine)

{

        _fmemcpy(lpDestLine, lpSrcLine, sizeof(TEXTLINE));

        return TRUE;

}

/* TextLine_CopyToDoc

 * ------------------

 *

 *      Copy a textline to another Document (usually ClipboardDoc)

 */

BOOL TextLine_CopyToDoc(LPTEXTLINE lpSrcLine, LPOUTLINEDOC lpDestDoc, int nIndex)

{

        LPTEXTLINE  lpDestLine;

        BOOL        fStatus = FALSE;

        lpDestLine = (LPTEXTLINE) New((DWORD)sizeof(TEXTLINE));

        if (lpDestLine == NULL) {

                OleDbgAssertSz(lpDestLine!=NULL,"Error allocating TextLine");

                return FALSE;

        }

        if (TextLine_Copy(lpSrcLine, lpDestLine)) {

                OutlineDoc_AddLine(lpDestDoc, (LPLINE)lpDestLine, nIndex);

                fStatus = TRUE;

        }

        return fStatus;

}

/* TextLine_SaveToStg

 * ------------------

 *

 *      Save a textline into a storage

 *

 *      Return TRUE if successful, FALSE otherwise

 */

BOOL TextLine_SaveToStm(LPTEXTLINE lpTextLine, LPSTREAM lpLLStm)

{

        HRESULT hrErr;

        ULONG nWritten;

        USHORT nLengthOnDisk;

        nLengthOnDisk = (USHORT) lpTextLine->m_nLength;

        hrErr = lpLLStm->lpVtbl->Write(

                        lpLLStm,

                        (LPVOID)&nLengthOnDisk,

                        sizeof(nLengthOnDisk),

                        &nWritten

        );

        if (hrErr != NOERROR) {

                OleDbgOutHResult("Write TextLine data (1) returned", hrErr);

                return FALSE;

    }

        hrErr = lpLLStm->lpVtbl->Write(

                        lpLLStm,

                        (LPVOID)lpTextLine->m_szText,

                        lpTextLine->m_nLength,

                        &nWritten

        );

        if (hrErr != NOERROR) {

                OleDbgOutHResult("Write TextLine data (2) returned", hrErr);

                return FALSE;

    }

        return TRUE;

}

/* TextLine_LoadFromStg

 * --------------------

 *

 *      Load a textline from storage

 */

LPLINE TextLine_LoadFromStg(LPSTORAGE lpSrcStg, LPSTREAM lpLLStm, LPOUTLINEDOC lpDestDoc)

{

        HRESULT hrErr;

        ULONG nRead;

        LPTEXTLINE lpTextLine;

        USHORT nLengthOnDisk;

        lpTextLine=(LPTEXTLINE) New((DWORD)sizeof(TEXTLINE));

        if (lpTextLine == NULL) {

                OleDbgAssertSz(lpTextLine!=NULL,"Error allocating TextLine");

                return NULL;

        }

        TextLine_Init(lpTextLine, 0, NULL);

        hrErr = lpLLStm->lpVtbl->Read(

                        lpLLStm,

                        (LPVOID)&nLengthOnDisk,

                        sizeof(nLengthOnDisk),

                        &nRead

        );

        if (hrErr != NOERROR) {

                OleDbgOutHResult("Read TextLine data (1) returned", hrErr);

                return NULL;

    }

        lpTextLine->m_nLength = (UINT) nLengthOnDisk;

        OleDbgAssert(lpTextLine->m_nLength < sizeof(lpTextLine->m_szText));

        hrErr = lpLLStm->lpVtbl->Read(

                        lpLLStm,

                        (LPVOID)&lpTextLine->m_szText,

                        lpTextLine->m_nLength,

                        &nRead

        );

        if (hrErr != NOERROR) {

                OleDbgOutHResult("Read TextLine data (1) returned", hrErr);

                return NULL;

    }

        lpTextLine->m_szText[lpTextLine->m_nLength] = '\0'; // add str terminator

        return (LPLINE)lpTextLine;

}


STATUS.H  (OUTLINE Sample)

/*************************************************************************

**

**    OLE 2.0 Sample Code

**

**    status.h

**

**    This file contains typedefs, defines, global variable declarations,

**    and function prototypes for the status bar window.

**

**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

**

*************************************************************************/

// Sizes of statusbar items

#if defined( USE_STATUSBAR )

   #define STATUS_HEIGHT   23

#else

   #define STATUS_HEIGHT   0

#endif

#define STATUS_RLEFT    8

#define STATUS_RRIGHT   400

#define STATUS_RTOP     3

#define STATUS_RBOTTOM  20

#define STATUS_TTOP     4

#define STATUS_TLEFT    11

#define STATUS_THEIGHT  18

typedef enum {

   STATUS_READY,

   STATUS_BLANK

} STATCONTROL;

// Window for status bar.

extern HWND hwndStatusbar;

BOOL RegisterStatusClass(HINSTANCE hInstance);

HWND CreateStatusWindow(HWND hWndApp, HINSTANCE hInst);

void DestroyStatusWindow(HWND hWndStatusBar);

void AssignPopupMessage(HMENU hmenuPopup, char *szMessage);

void SetStatusText(HWND hWndStatusBar, LPSTR lpszMessage);

void GetItemMessage(UINT wIDItem, LPSTR FAR* lplpszMessage);

void GetPopupMessage(HMENU hmenuPopup, LPSTR FAR* lplpszMessage);

void GetSysMenuMessage(UINT wIDItem, LPSTR FAR* lplpszMessage);

void GetControlMessage(STATCONTROL scCommand, LPSTR FAR* lplpszMessage);


STATUS.C  (OUTLINE Sample)

/*************************************************************************

**

**    OLE 2.0 Sample Code

**

**    status.c

**

**    This file contains the window handlers, and various initialization

**    and utility functions for an application status bar.

**

**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

**

*************************************************************************/

// Application specific include files

#include "outline.h"

#include "message.h"

#include "status.h"

// Current status message.

static char lpszStatusMessage[256];

// Window proc for status window.

LRESULT FAR PASCAL StatusWndProc

   (HWND hwnd, unsigned message, WPARAM wParam, LPARAM lParam);

// List of all constant messages.

static STATMESG ControlList[2] =

{

   {   STATUS_READY,   "Ready."    },

   {   STATUS_BLANK,   " "         }

};

// List of all system menu messages.

static STATMESG SysMenuList[16] =

{

   {   SC_SIZE,        "Change the size of the window."            },

   {   SC_MOVE,        "Move the window."                          },

   {   SC_MINIMIZE,    "Make the window iconic."                   },

   {   SC_MAXIMIZE,    "Make the window the size of the screen."   },

   {   SC_NEXTWINDOW,  "Activate the next window."                 },

   {   SC_PREVWINDOW,  "Activate the previous window."             },

   {   SC_CLOSE,       "Close this window."                        },

   {   SC_VSCROLL,     "Vertical scroll?"                          },

   {   SC_HSCROLL,     "Horizontal scroll?"                        },

   {   SC_MOUSEMENU,   "A menu for mice."                          },

   {   SC_KEYMENU,     "A menu for keys (I guess)."                },

   {   SC_ARRANGE,     "Arrange something."                        },

   {   SC_RESTORE,     "Make the window noramally sized."          },

   {   SC_TASKLIST,    "Put up the task list dialog."              },

   {   SC_SCREENSAVE,  "Save the screen!  Run for your life!"      },

   {   SC_HOTKEY,      "Boy, is this key hot!"                     }

};

// Message type for popup messages.

typedef struct {

   HMENU hmenu;

   char string[MAX_MESSAGE];

} STATPOPUP;

// List of all popup messages.

static STATPOPUP PopupList[NUM_POPUP];

static UINT nCurrentPopup = 0;

/* RegisterStatusClass

 * -------------------

 *

 * Creates classes for status window.

 *

 * HINSTANCE hInstance

 *

 * RETURNS: TRUE if class successfully registered.

 *          FALSE otherwise.

 *

 * CUSTOMIZATION: Change class name.

 *

 */

BOOL RegisterStatusClass(HINSTANCE hInstance)

{

   WNDCLASS  wc;

   wc.lpszClassName = "ObjStatus";

   wc.lpfnWndProc   = StatusWndProc;

   wc.style         = 0;

   wc.hInstance     = hInstance;

   wc.hIcon         = NULL;

   wc.cbClsExtra    = 4;

   wc.cbWndExtra    = 0;

   wc.lpszMenuName  = NULL;

   wc.hCursor       = LoadCursor(NULL, IDC_ARROW);

   wc.hbrBackground = GetStockObject(LTGRAY_BRUSH);

   if (!RegisterClass(&wc))

      return FALSE;

   return TRUE;

}

/* CreateStatusWindow

 * ------------------

 *

 * Creates status window.

 *

 * HWND hwndMain

 *

 * RETURNS: HWND of status window if creation is successful.

 *          NULL otherwise.

 *

 * CUSTOMIZATION: Change class name.

 *

 */

HWND CreateStatusWindow(HWND hWndApp, HINSTANCE hInst)

{

   RECT rect;

   int width, height;

   HWND hWndStatusBar;

   lstrcpy (lpszStatusMessage, ControlList[0].string);

   GetClientRect(hWndApp, &rect);

   width = rect.right - rect.left;

   height = rect.bottom - rect.top;

   hWndStatusBar = CreateWindow (

      "ObjStatus",

      "SvrStatus",

      WS_CHILD |

      WS_CLIPSIBLINGS |

      WS_VISIBLE,

      0, height - STATUS_HEIGHT,

      width,

      STATUS_HEIGHT,

      hWndApp,

      NULL,

      hInst,

      NULL

   );

   return hWndStatusBar;

}

/* DestroyStatusWindow

 * -------------------

 *

 * Destroys status window.

 *

 * CUSTOMIZATION: None.

 *

 */

void DestroyStatusWindow(HWND hWndStatusBar)

{

   DestroyWindow(hWndStatusBar);

}

/* AssignPopupMessage

 * ------------------

 *

 * Associates a string with a popup menu handle.

 *

 * HMENU hmenuPopup

 * char *szMessage

 *

 * CUSTOMIZATION: None.

 *

 */

void AssignPopupMessage(HMENU hmenuPopup, char *szMessage)

{

   if (nCurrentPopup < NUM_POPUP) {

      PopupList[nCurrentPopup].hmenu = hmenuPopup;

      lstrcpy(PopupList[nCurrentPopup].string, szMessage);

      ++nCurrentPopup;

   }

}

/* SetStatusText

 * -------------

 *

 * Show the message in the status line.

 */

void SetStatusText(HWND hWndStatusBar, LPSTR lpszMessage)

{

   lstrcpy (lpszStatusMessage, lpszMessage);

   InvalidateRect (hWndStatusBar, (LPRECT)NULL,  TRUE);

   UpdateWindow (hWndStatusBar);

}

/* GetItemMessage

 * --------------

 *

 * Retrieve the message associated with the given menu command item number.

 *

 * UINT wIDItem

 * LPVOID lpDoc

 *

 * CUSTOMIZATION: None.

 *

 */

void GetItemMessage(UINT wIDItem, LPSTR FAR* lplpszMessage)

{

   UINT i;

   *lplpszMessage = ControlList[1].string;

   for (i = 0; i < NUM_STATS; ++i) {

      if (wIDItem == MesgList[i].wIDItem) {

         *lplpszMessage = MesgList[i].string;

         break;

      }

   }

}

/* GetPopupMessage

 * ---------------

 *

 * Retrieve the message associated with the given popup menu.

 *

 * HMENU hmenuPopup

 * LPVOID lpDoc

 *

 * CUSTOMIZATION: None.

 *

 */

void GetPopupMessage(HMENU hmenuPopup, LPSTR FAR* lplpszMessage)

{

   UINT i;

   *lplpszMessage = ControlList[1].string;

   for (i = 0; i < nCurrentPopup; ++i) {

      if (hmenuPopup == PopupList[i].hmenu) {

         *lplpszMessage = PopupList[i].string;

         break;

      }

   }

}

/* GetSysMenuMessage

 * -----------------

 *

 * Retrieves the messages to correspond to items on the system menu.

 *

 *

 * UINT wIDItem

 * LPVOID lpDoc

 *

 * CUSTOMIZATION: None.

 *

 */

void GetSysMenuMessage(UINT wIDItem, LPSTR FAR* lplpszMessage)

{

   UINT i;

   *lplpszMessage = ControlList[1].string;

   for (i = 0; i < 16; ++i) {

      if (wIDItem == SysMenuList[i].wIDItem) {

         *lplpszMessage = SysMenuList[i].string;

         break;

      }

   }

}

/* GetControlMessage

 * -----------------

 *

 * Retrieves the general system messages.

 *

 *

 * STATCONTROL scCommand

 * LPVOID lpDoc

 *

 * CUSTOMIZATION: Add new messages.

 *

 */

void GetControlMessage(STATCONTROL scCommand, LPSTR FAR* lplpszMessage)

{

   UINT i;

   *lplpszMessage = ControlList[1].string;

   for (i = 0; i < 2; ++i) {

      if ((UINT)scCommand == ControlList[i].wIDItem) {

         *lplpszMessage = ControlList[i].string;

         break;

      }

   }

}

/* StatusWndProc

 * -------------

 *

 * Message handler for the statusbar window.

 *

 *

 * CUSTOMIZATION: None

 *

 */

LRESULT FAR PASCAL StatusWndProc

   (HWND hwnd, unsigned message, WPARAM wParam, LPARAM lParam)

{

   if (message == WM_PAINT) {

      RECT        rc;

      HDC         hdc;

      PAINTSTRUCT paintstruct;

      HPEN        hpenOld;

      HPEN        hpen;

      HFONT       hfontOld;

      HFONT       hfont;

      HPALETTE    hpalOld = NULL;

      POINT       point;

      BeginPaint (hwnd, &paintstruct);

      hdc = GetDC (hwnd);

      GetClientRect (hwnd, (LPRECT) &rc);

      hpenOld = SelectObject (hdc, GetStockObject (BLACK_PEN));

      MoveToEx (hdc, 0, 0, &point);

      LineTo (hdc, rc.right, 0);

      SelectObject (hdc, GetStockObject (WHITE_PEN));

      MoveToEx (hdc, STATUS_RRIGHT, STATUS_RTOP, &point);

      LineTo (hdc, STATUS_RRIGHT, STATUS_RBOTTOM);

      LineTo (hdc, STATUS_RLEFT-1, STATUS_RBOTTOM);

      hpen = CreatePen (PS_SOLID, 1, /* DKGRAY */ 0x00808080);

      SelectObject (hdc, hpen);

      MoveToEx (hdc, STATUS_RLEFT, STATUS_RBOTTOM-1, &point);

      LineTo (hdc, STATUS_RLEFT, STATUS_RTOP);

      LineTo (hdc, STATUS_RRIGHT, STATUS_RTOP);

      SetBkMode (hdc, TRANSPARENT);

      SetTextAlign (hdc, TA_LEFT | TA_TOP);

      hfont = CreateFont (STATUS_THEIGHT, 0, 0, 0, FW_NORMAL, FALSE, FALSE,

                     FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS,

                     CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,

                     DEFAULT_PITCH | FF_DONTCARE, "MS Sans Serif");

      hfontOld = SelectObject(hdc, hfont);

      TextOut (hdc, STATUS_TLEFT, STATUS_TTOP,

             lpszStatusMessage,

             lstrlen(lpszStatusMessage));

      // Restore original objects

      SelectObject (hdc, hfontOld);

      SelectObject (hdc, hpenOld);

      DeleteObject (hpen);

      DeleteObject (hfont);

      ReleaseDC (hwnd, hdc);

      EndPaint (hwnd, &paintstruct);

      return 0;

   }

   else {

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

   }

}


SVRBASE.C  (OUTLINE Sample)

/*************************************************************************

**

**    OLE 2 Server Sample Code

**

**    svrbase.c

**

**    This file contains all interfaces, methods and related support

**    functions for the basic OLE Object (Server) application. The

**    basic OLE Object application supports embedding an object and

**    linking to a file-based or embedded object as a whole. The basic

**    Object application includes the following implementation objects:

**

**    ClassFactory (aka. ClassObject) Object    (see file classfac.c)

**      exposed interfaces:

**          IClassFactory interface

**

**    ServerDoc Object

**      exposed interfaces:

**          IUnknown

**          IOleObject interface

**          IPersistStorage interface

**          IDataObject interface

**

**    ServerApp Object

**      exposed interfaces:

**          IUnknown

**

**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

**

*************************************************************************/

#include "outline.h"

OLEDBGDATA

extern LPOUTLINEAPP             g_lpApp;

extern IOleObjectVtbl           g_SvrDoc_OleObjectVtbl;

extern IPersistStorageVtbl      g_SvrDoc_PersistStorageVtbl;

#if defined( INPLACE_SVR )

extern IOleInPlaceObjectVtbl        g_SvrDoc_OleInPlaceObjectVtbl;

extern IOleInPlaceActiveObjectVtbl  g_SvrDoc_OleInPlaceActiveObjectVtbl;

#endif  // INPLACE_SVR

#if defined( SVR_TREATAS )

extern IStdMarshalInfoVtbl      g_SvrDoc_StdMarshalInfoVtbl;

#endif  // SVR_TREATAS

// REVIEW: should use string resource for messages

extern OLECHAR ErrMsgSaving[];

extern OLECHAR ErrMsgFormatNotSupported[];

static OLECHAR ErrMsgPSSaveFail[] = OLESTR("PSSave failed");

static OLECHAR ErrMsgLowMemNClose[] = OLESTR("Warning OUT OF MEMORY! We must close down");

extern char g_szUpdateCntrDoc[] = "&Update %s";

extern char g_szExitNReturnToCntrDoc[] = "E&xit && Return to %s";

/*************************************************************************

** ServerDoc::IOleObject interface implementation

*************************************************************************/

// IOleObject::QueryInterface method

STDMETHODIMP SvrDoc_OleObj_QueryInterface(

      LPOLEOBJECT             lpThis,

      REFIID                  riid,

      LPVOID FAR*             lplpvObj

)

{

   LPSERVERDOC lpServerDoc =

         ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;

   return OleDoc_QueryInterface((LPOLEDOC)lpServerDoc, riid, lplpvObj);

}

// IOleObject::AddRef method

STDMETHODIMP_(ULONG) SvrDoc_OleObj_AddRef(LPOLEOBJECT lpThis)

{

   LPSERVERDOC lpServerDoc =

         ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;

   OleDbgAddRefMethod(lpThis, "IOleObject");

   return OleDoc_AddRef((LPOLEDOC)lpServerDoc);

}

// IOleObject::Release method

STDMETHODIMP_(ULONG) SvrDoc_OleObj_Release(LPOLEOBJECT lpThis)

{

   LPSERVERDOC lpServerDoc =

         ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;

   OleDbgReleaseMethod(lpThis, "IOleObject");

   return OleDoc_Release((LPOLEDOC)lpServerDoc);

}

// IOleObject::SetClientSite method

STDMETHODIMP SvrDoc_OleObj_SetClientSite(

      LPOLEOBJECT             lpThis,

      LPOLECLIENTSITE         lpclientSite

)

{

      LPSERVERDOC lpServerDoc =

         ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;

   // artificial AddRef in case object is destroyed during call

   SvrDoc_OleObj_AddRef(lpThis);

   OLEDBG_BEGIN2("SvrDoc_OleObj_SetClientSite\r\n")

   // SetClientSite is only valid to call on an embedded object

   if (lpOutlineDoc->m_docInitType != DOCTYPE_EMBEDDED) {

      OleDbgAssert(lpOutlineDoc->m_docInitType == DOCTYPE_EMBEDDED);

      OLEDBG_END2

      // release artificial AddRef

      SvrDoc_OleObj_Release(lpThis);

      return ResultFromScode(E_UNEXPECTED);

   }

   /* if we currently have a client site ptr, then release it. */

   if (lpServerDoc->m_lpOleClientSite)

      OleStdRelease((LPUNKNOWN)lpServerDoc->m_lpOleClientSite);

   lpServerDoc->m_lpOleClientSite = (LPOLECLIENTSITE) lpclientSite;

   // OLE2NOTE: to be able to hold onto clientSite pointer, we must AddRef it

   if (lpclientSite)

      lpclientSite->lpVtbl->AddRef(lpclientSite);

   OLEDBG_END2

   // release artificial AddRef

   SvrDoc_OleObj_Release(lpThis);

   return NOERROR;

}

// IOleObject::GetClientSite method

STDMETHODIMP SvrDoc_OleObj_GetClientSite(

      LPOLEOBJECT             lpThis,

      LPOLECLIENTSITE FAR*    lplpClientSite

)

{

   LPSERVERDOC lpServerDoc =

         ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;

   // artificial AddRef in case object is destroyed during call

   SvrDoc_OleObj_AddRef(lpThis);

   OleDbgOut2("SvrDoc_OleObj_GetClientSite\r\n");

   /* OLE2NOTE: we MUST AddRef this interface pointer to give the

   **    caller a personal copy of the pointer

   */

   lpServerDoc->m_lpOleClientSite->lpVtbl->AddRef(

         lpServerDoc->m_lpOleClientSite

   );

   *lplpClientSite = lpServerDoc->m_lpOleClientSite;

   // release artificial AddRef

   SvrDoc_OleObj_Release(lpThis);

   return NOERROR;

}

// IOleObject::SetHostNames method

STDMETHODIMP SvrDoc_OleObj_SetHostNames(

      LPOLEOBJECT             lpThis,

      LPCOLESTR               szContainerApp,

      LPCOLESTR               szContainerObj

)

{

   LPSERVERDOC lpServerDoc =

         ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;

   LPOUTLINEDOC    lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;

   char szAnsiStr1[256], szAnsiStr2[256], szAnsiStr3[256];

   // artificial AddRef in case object is destroyed during call

   SvrDoc_OleObj_AddRef(lpThis);

   OleDbgOut2("SvrDoc_OleObj_SetHostNames\r\n");

   OLESTRCPY((LPOLESTR)lpServerDoc->m_szContainerApp, szContainerApp);

   OLESTRCPY((LPOLESTR)lpServerDoc->m_szContainerObj, szContainerObj);

   /* The Window title for an embedded object is constructed as

   **    follows:

   **      <server app name> - <obj short type> in <cont. doc name>

   **

   **    here we construct the current document title portion of the

   **    name which follows the '-'. OutlineDoc_SetTitle prepends the

   **    "<server app name> - " to the document title.

   */

   // REVIEW: this string should be loaded from string resource

   W2A (lpServerDoc->m_szContainerObj, szAnsiStr1, 256);

   W2A (SHORTUSERTYPENAME, szAnsiStr3, 256);

   wsprintf(szAnsiStr2, "%s in %s",

         szAnsiStr3, (LPSTR)szAnsiStr1);

   A2W (szAnsiStr2, lpOutlineDoc->m_szFileName, OLEUI_CCHPATHMAX);

   lpOutlineDoc->m_lpszDocTitle = lpOutlineDoc->m_szFileName;

   OutlineDoc_SetTitle(lpOutlineDoc, FALSE /*fMakeUpperCase*/);

   /* OLE2NOTE: update the application menus correctly for an embedded

   **    object. the changes include:

   **      1 Remove File/New and File/Open (SDI ONLY)

   **      2 Change File/Save As.. to File/Save Copy As..

   **      3 Change File menu so it contains "Update" instead of "Save"

   **      4 Change File/Exit to File/Exit & Return to <client doc>"

   */

   ServerDoc_UpdateMenu(lpServerDoc);

   // release artificial AddRef

   SvrDoc_OleObj_Release(lpThis);

   return NOERROR;

}

// IOleObject::Close method

STDMETHODIMP SvrDoc_OleObj_Close(

      LPOLEOBJECT             lpThis,

      DWORD                   dwSaveOption

)

{

   LPSERVERDOC lpServerDoc =

         ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;

   BOOL fStatus;

   OLEDBG_BEGIN2("SvrDoc_OleObj_Close\r\n")

   /* OLE2NOTE: the OLE 2.0 user model is that embedded objects should

   **    always be saved when closed WITHOUT any prompting to the

   **    user. this is the recommendation irregardless of whether the

   **    object is activated in-place or open in its own window.

   **    this is a CHANGE from the OLE 1.0 user model where it

   **    was the guideline that servers always prompt to save changes.

   **    thus OLE 2.0 compound document oriented container's should

   **    always pass dwSaveOption==OLECLOSE_SAVEIFDIRTY. it is

   **    possible that for programmatic uses a container may want to

   **    specify a different dwSaveOption. the implementation of

   **    various save options can be tricky, particularly considering

   **    cases involving in-place activation. the following would be

   **    reasonable behavior:

   **

   **      (1) OLECLOSE_SAVEIFDIRTY: if dirty, save. close.

   **      (2) OLECLOSE_NOSAVE: close.

   **      (3) OLECLOSE_PROMPTSAVE:

   **        (a) object visible, but not in-place:

   **               if not dirty, close.

   **               switch(prompt)

   **                  case IDYES: save. close.

   **                  case IDNO: close.

   **                  case IDCANCEL: return OLE_E_PROMPTSAVECANCELLED

   **        (b) object invisible (includes UIDeactivated object)

   **               if dirty, save. close.

   **               NOTE: NO PROMPT. it is not appropriate to prompt

   **                     if the object is not visible.

   **        (c) object is in-place active:

   **               if dirty, save. close.

   **               NOTE: NO PROMPT. it is not appropriate to prompt

   **                     if the object is active in-place.

   */

   fStatus = OutlineDoc_Close((LPOUTLINEDOC)lpServerDoc, dwSaveOption);

   OleDbgAssertSz(fStatus == TRUE, "SvrDoc_OleObj_Close failed\r\n");

   OLEDBG_END2

   return (fStatus ? NOERROR : ResultFromScode(E_FAIL));

}

// IOleObject::SetMoniker method

STDMETHODIMP SvrDoc_OleObj_SetMoniker(

      LPOLEOBJECT             lpThis,

      DWORD                   dwWhichMoniker,

      LPMONIKER               lpmk

)

{

   LPSERVERDOC lpServerDoc =

         ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;

   LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc;

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;

   LPMONIKER lpmkFull = NULL;

   HRESULT hrErr;

   SCODE sc;

   // artificial AddRef in case object is destroyed during call

   SvrDoc_OleObj_AddRef(lpThis);

   OLEDBG_BEGIN2("SvrDoc_OleObj_SetMoniker\r\n")

   /* OLE2NOTE: if our full moniker is passed then we can use it,

   **    otherwise we must call back to our ClientSite to get our full

   **    moniker.

   */

   if (dwWhichMoniker == OLEWHICHMK_OBJFULL) {

      /* Register the document as running with the new moniker and

      **      notify any clients that our moniker has changed.

      */

      OleDoc_DocRenamedUpdate(lpOleDoc, lpmk);

      if (lpOutlineDoc->m_docInitType != DOCTYPE_EMBEDDED) {

         IBindCtx  FAR  *pbc = NULL;

         LPOLESTR lpszName = NULL;

         /* OLE2NOTE: if this is a FILE-based or untitled document

         **    then we should accept this new moniker as our document's

         **    moniker. we will remember this moniker instead of the

         **    FileMoniker that we have by default. this allows

         **    systems that use special monikers to track the

         **    location of documents to inform a document that is a

         **    link source of its special moniker. this enables the

         **    document to use this special moniker when building

         **    composite monikers to identify contained objects and

         **    pseudo objects (ranges).

         **

         **    we should also use the DisplayName form of this

         **    moniker as our document name in our window title.

         */

         if (lpOleDoc->m_lpFileMoniker) {

            lpOleDoc->m_lpFileMoniker->lpVtbl->Release(

                  lpOleDoc->m_lpFileMoniker);

         }

         lpOleDoc->m_lpFileMoniker = lpmk;

         // we must AddRef the moniker to hold on to it

         lpmk->lpVtbl->AddRef(lpmk);

         /* we should also use the DisplayName form of this

         **    moniker as our document name in our window title.

         */

         CreateBindCtx(0, (LPBC FAR*)&pbc);

         lpmk->lpVtbl->GetDisplayName(lpmk,pbc,NULL,&lpszName);

         pbc->lpVtbl->Release(pbc);

         if (lpszName) {

            OLESTRCPY(lpOutlineDoc->m_szFileName, lpszName);

            lpOutlineDoc->m_lpszDocTitle = lpOutlineDoc->m_szFileName;

            OutlineDoc_SetTitle(lpOutlineDoc, FALSE /*fMakeUpperCase*/);

            OleStdFreeString(lpszName, NULL);

         }

      }

      OLEDBG_END2

      // release artificial AddRef

      SvrDoc_OleObj_Release(lpThis);

      return NOERROR;

   }

   /* if the passed moniker was NOT a full moniker then we must call

   **    back to our ClientSite to get our full moniker. this is

   **    needed in order to register in the RunningObjectTable. if we

   **    don't have a ClientSite then this is an error.

   */

   if (lpServerDoc->m_lpOleClientSite == NULL) {

      sc = E_FAIL;

      goto error;

   }

   hrErr = lpServerDoc->m_lpOleClientSite->lpVtbl->GetMoniker(

         lpServerDoc->m_lpOleClientSite,

         OLEGETMONIKER_ONLYIFTHERE,

         OLEWHICHMK_OBJFULL,

         &lpmkFull

   );

   if (hrErr != NOERROR) {

      sc = GetScode(hrErr);

      goto error;

   }

   /* Register the document as running with the new moniker and

   **      notify any clients that our moniker has changed.

   */

   OleDoc_DocRenamedUpdate(lpOleDoc, lpmkFull);

   if (lpmkFull)

      OleStdRelease((LPUNKNOWN)lpmkFull);

   OLEDBG_END2

   // release artificial AddRef

   SvrDoc_OleObj_Release(lpThis);

   return NOERROR;

error:

   OLEDBG_END2

   // release artificial AddRef

   SvrDoc_OleObj_Release(lpThis);

   return ResultFromScode(sc);

}

// IOleObject::GetMoniker method

STDMETHODIMP SvrDoc_OleObj_GetMoniker(

      LPOLEOBJECT             lpThis,

      DWORD                   dwAssign,

      DWORD                   dwWhichMoniker,

      LPMONIKER FAR*          lplpmk

)

{

   LPSERVERDOC lpServerDoc =

         ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;

   LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc;

   SCODE sc;

   // artificial AddRef in case object is destroyed during call

   SvrDoc_OleObj_AddRef(lpThis);

   OLEDBG_BEGIN2("SvrDoc_OleObj_GetMoniker\r\n")

   /* OLE2NOTE: we must make sure to set all out parameters to NULL. */

   *lplpmk = NULL;

   if (lpServerDoc->m_lpOleClientSite) {

      /* document is an embedded object. retrieve our moniker from

      **    our container.

      */

      OLEDBG_BEGIN2("IOleClientSite::GetMoniker called\r\n")

      sc = GetScode( lpServerDoc->m_lpOleClientSite->lpVtbl->GetMoniker(

            lpServerDoc->m_lpOleClientSite,

            dwAssign,

            dwWhichMoniker,

            lplpmk

      ) );

      OLEDBG_END2

   } else if (lpOleDoc->m_lpFileMoniker) {

      /* document is a top-level user document (either

      **    file-based or untitled). return the FileMoniker stored

      **    with the document; it uniquely identifies the document.

      */

      if (dwWhichMoniker == OLEWHICHMK_CONTAINER)

         sc = E_INVALIDARG;  // file-based object has no CONTAINER moniker

      else {

         *lplpmk = lpOleDoc->m_lpFileMoniker;

         (*lplpmk)->lpVtbl->AddRef(*lplpmk); // must AddRef to pass out ptr

         sc = S_OK;

      }

   } else {

      // document is not yet fully initialized => no moniker

      sc = E_FAIL;

   }

   OLEDBG_END2

   // release artificial AddRef

   SvrDoc_OleObj_Release(lpThis);

   return ResultFromScode(sc);

}

// IOleObject::InitFromData method

STDMETHODIMP SvrDoc_OleObj_InitFromData(

      LPOLEOBJECT             lpThis,

      LPDATAOBJECT            lpDataObject,

      BOOL                    fCreation,

      DWORD                   reserved

)

{

   LPSERVERDOC lpServerDoc =

         ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;

   OLEDBG_BEGIN2("SvrDoc_OleObj_InitFromData\r\n")

   // REVIEW: NOT YET IMPLEMENTED

   OLEDBG_END2

   return ResultFromScode(E_NOTIMPL);

}

// IOleObject::GetClipboardData method

STDMETHODIMP SvrDoc_OleObj_GetClipboardData(

      LPOLEOBJECT             lpThis,

      DWORD                   reserved,

      LPDATAOBJECT FAR*       lplpDataObject

)

{

   LPSERVERDOC lpServerDoc =

         ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;

   OLEDBG_BEGIN2("SvrDoc_OleObj_GetClipboardData\r\n")

   // REVIEW: NOT YET IMPLEMENTED

   OLEDBG_END2

   return ResultFromScode(E_NOTIMPL);

}

// IOleObject::DoVerb method

STDMETHODIMP SvrDoc_OleObj_DoVerb(

      LPOLEOBJECT             lpThis,

      LONG                    lVerb,

      LPMSG                   lpmsg,

      LPOLECLIENTSITE         lpActiveSite,

      LONG                    lindex,

      HWND                    hwndParent,

      LPCRECT                 lprcPosRect

)

{

   LPSERVERDOC lpServerDoc =

         ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;

   SCODE sc = S_OK;

   // artificial AddRef in case object is destroyed during call

   SvrDoc_OleObj_AddRef(lpThis);

   OLEDBG_BEGIN2("SvrDoc_OleObj_DoVerb\r\n")

   switch (lVerb) {

      default:

         /* OLE2NOTE: when an unknown verb number is given, the

         **    server must take careful action:

         **    1. if it is one of the specially defined OLEIVERB

         **    (negative numbered) verbs, the app should return an

         **    error (E_NOTIMPL) and perform no action.

         **

         **    2. if the verb is a application specific verb

         **    (positive numbered verb), then the app should

         **    return the special scode (OLEOBJ_S_INVALIDVERB). BUT,

         **    we should still perform our normal primary verb action.

         */

         if (lVerb < 0) {

            OLEDBG_END2

            return ResultFromScode(E_NOTIMPL);

         } else {

            sc = OLEOBJ_S_INVALIDVERB;

         }

         // deliberatly fall through to Primary Verb

#if !defined( INPLACE_SVR )

      case 0:

      case OLEIVERB_SHOW:

      case OLEIVERB_OPEN:

         OutlineDoc_ShowWindow(lpOutlineDoc);

         break;

      case OLEIVERB_HIDE:

         OleDoc_HideWindow((LPOLEDOC)lpServerDoc, FALSE /*fShutdown*/);

         break;

#endif  // ! INPLACE_SVR

#if defined( INPLACE_SVR )

      case 0:

      case OLEIVERB_SHOW:

         /* OLE2NOTE: if our window is already open (visible) then

         **    we should simply surface the open window. if not,

         **    then we can do our primary action of in-place

         **    activation.

         */

         if ( lpServerDoc->m_lpOleClientSite

               && ! (IsWindowVisible(lpOutlineDoc->m_hWndDoc) &&

                     ! lpServerDoc->m_fInPlaceActive) ) {

            ServerDoc_DoInPlaceActivate(

                  lpServerDoc, lVerb, lpmsg, lpActiveSite);

         }

         OutlineDoc_ShowWindow(lpOutlineDoc);

         break;

      case 1:

      case OLEIVERB_OPEN:

         ServerDoc_DoInPlaceDeactivate(lpServerDoc);

         OutlineDoc_ShowWindow(lpOutlineDoc);

         break;

      case OLEIVERB_HIDE:

         if (lpServerDoc->m_fInPlaceActive) {

            SvrDoc_IPObj_UIDeactivate(

                  (LPOLEINPLACEOBJECT)&lpServerDoc->m_OleInPlaceObject);

#if defined( SVR_INSIDEOUT )

            /* OLE2NOTE: an inside-out style in-place server will

            **    NOT hide its window in UIDeactive (an outside-in

            **    style object will hide its window in

            **    UIDeactivate). thus we need to explicitly hide

            **    our window now.

            */

            ServerDoc_DoInPlaceHide(lpServerDoc);

#endif // INSIEDOUT

         } else {

            OleDoc_HideWindow((LPOLEDOC)lpServerDoc, FALSE /*fShutdown*/);

         }

         break;

      case OLEIVERB_UIACTIVATE:

#if defined( SVR_INSIDEOUT )

      /* OLE2NOTE: only an inside-out style object supports

      **    INPLACEACTIVATE verb

      */

      case OLEIVERB_INPLACEACTIVATE:

#endif // SVR_INSIDEOUT

         /* OLE2NOTE: if our window is already open (visible) then

         **    we can NOT activate in-place.

         */

         if (IsWindowVisible(lpOutlineDoc->m_hWndDoc) &&

                  ! lpServerDoc->m_fInPlaceActive ) {

            sc = OLE_E_NOT_INPLACEACTIVE;

         } else {

            sc = GetScode( ServerDoc_DoInPlaceActivate(

                  lpServerDoc, lVerb, lpmsg, lpActiveSite) );

            if (SUCCEEDED(sc))

               OutlineDoc_ShowWindow(lpOutlineDoc);

         }

         break;

#endif  // INPLACE_SVR

   }

   OLEDBG_END2

   // release artificial AddRef

   SvrDoc_OleObj_Release(lpThis);

   return ResultFromScode(sc);

}

// IOleObject::EnumVerbs method

STDMETHODIMP SvrDoc_OleObj_EnumVerbs(

      LPOLEOBJECT             lpThis,

      LPENUMOLEVERB FAR*      lplpenumOleVerb

)

{

   OleDbgOut2("SvrDoc_OleObj_EnumVerbs\r\n");

   /* OLE2NOTE: we must make sure to set all out parameters to NULL. */

   *lplpenumOleVerb = NULL;

   /* An object implemented as a server EXE (as this sample

   **    is) may simply return OLE_S_USEREG to instruct the OLE

   **    DefHandler to call the OleReg* helper API which uses info in

   **    the registration database. Alternatively, the OleRegEnumVerbs

   **    API may be called directly. Objects implemented as a server

   **    DLL may NOT return OLE_S_USEREG; they must call the OleReg*

   **    API or provide their own implementation. For EXE based

   **    objects it is more efficient to return OLE_S_USEREG, because

   **    in then the verb enumerator is instantiated in the callers

   **    process space and no LRPC remoting is required.

   */

   return ResultFromScode(OLE_S_USEREG);

}

// IOleObject::Update method

STDMETHODIMP SvrDoc_OleObj_Update(LPOLEOBJECT lpThis)

{

   OleDbgOut2("SvrDoc_OleObj_Update\r\n");

   /* OLE2NOTE: a server-only app is always "up-to-date".

   **    a container-app which contains links where the link source

   **    has changed since the last update of the link would be

   **    considered "out-of-date". the "Update" method instructs the

   **    object to get an update from any out-of-date links.

   */

   return NOERROR;

}

// IOleObject::IsUpToDate method

STDMETHODIMP SvrDoc_OleObj_IsUpToDate(LPOLEOBJECT lpThis)

{

   OleDbgOut2("SvrDoc_OleObj_IsUpToDate\r\n");

   /* OLE2NOTE: a server-only app is always "up-to-date".

   **    a container-app which contains links where the link source

   **    has changed since the last update of the link would be

   **    considered "out-of-date".

   */

   return NOERROR;

}

// IOleObject::GetUserClassID method

STDMETHODIMP SvrDoc_OleObj_GetUserClassID(

      LPOLEOBJECT             lpThis,

      LPCLSID                 lpClassID

)

{

   LPSERVERDOC lpServerDoc =

         ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;

   OleDbgOut2("SvrDoc_OleObj_GetClassID\r\n");

   /* OLE2NOTE: we must be carefull to return the correct CLSID here.

   **    if we are currently preforming a "TreatAs (aka. ActivateAs)"

   **    operation then we need to return the class of the object

   **    written in the storage of the object. otherwise we would

   **    return our own class id.

   */

   return ServerDoc_GetClassID(lpServerDoc, lpClassID);

}

// IOleObject::GetUserType method

STDMETHODIMP SvrDoc_OleObj_GetUserType(

      LPOLEOBJECT             lpThis,

      DWORD                   dwFormOfType,

      LPOLESTR FAR*           lpszUserType

)

{

   LPSERVERDOC lpServerDoc =

         ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;

   OleDbgOut2("SvrDoc_OleObj_GetUserType\r\n");

   /* OLE2NOTE: we must make sure to set all out parameters to NULL. */

   *lpszUserType = NULL;

   /* OLE2NOTE: we must be carefull to return the correct user type here.

   **    if we are currently preforming a "TreatAs (aka. ActivateAs)"

   **    operation then we need to return the user type name that

   **    corresponds to the class of the object we are currently

   **    emmulating. otherwise we should return our normal user type

   **    name corresponding to our own class. This routine determines

   **    the current clsid in effect.

   **

   **    An object implemented as a server EXE (as this sample

   **    is) may simply return OLE_S_USEREG to instruct the OLE

   **    DefHandler to call the OleReg* helper API which uses info in

   **    the registration database. Alternatively, the OleRegGetUserType

   **    API may be called directly. Objects implemented as a server

   **    DLL may NOT return OLE_S_USEREG; they must call the OleReg*

   **    API or provide their own implementation. For EXE based

   **    objects it is more efficient to return OLE_S_USEREG, because

   **    in then the return string is instantiated in the callers

   **    process space and no LRPC remoting is required.

   */

#if defined( SVR_TREATAS )

   if (! IsEqualCLSID(&lpServerDoc->m_clsidTreatAs, &CLSID_NULL) )

      return OleRegGetUserType(

         (REFCLSID)&lpServerDoc->m_clsidTreatAs,dwFormOfType,lpszUserType);

   else

#endif  // SVR_TREATAS

   return ResultFromScode(OLE_S_USEREG);

}

// IOleObject::SetExtent method

STDMETHODIMP SvrDoc_OleObj_SetExtent(

      LPOLEOBJECT             lpThis,

      DWORD                   dwDrawAspect,

      LPSIZEL                 lplgrc

)

{

   OleDbgOut2("SvrDoc_OleObj_SetExtent\r\n");

   /* SVROUTL does NOT allow the object's size to be set by its

   **    container. the size of the ServerDoc object is determined by

   **    the data contained within the document.

   */

   return ResultFromScode(E_FAIL);

}

// IOleObject::GetExtent method

STDMETHODIMP SvrDoc_OleObj_GetExtent(

      LPOLEOBJECT             lpThis,

      DWORD                   dwDrawAspect,

      LPSIZEL                 lpsizel

)

{

   LPOLEDOC lpOleDoc =

         (LPOLEDOC)((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;

   // artificial AddRef in case object is destroyed during call

   SvrDoc_OleObj_AddRef(lpThis);

   OleDbgOut2("SvrDoc_OleObj_GetExtent\r\n");

   /* OLE2NOTE: it is VERY important to check which aspect the caller

   **    is asking about. an object implemented by a server EXE MAY

   **    fail to return extents when asked for DVASPECT_ICON.

   */

   if (dwDrawAspect == DVASPECT_CONTENT) {

      OleDoc_GetExtent(lpOleDoc, lpsizel);

      // release artificial AddRef

      SvrDoc_OleObj_Release(lpThis);

      return NOERROR;

   }

#if defined( LATER )

   else if (dwDrawAspect == DVASPECT_THUMBNAIL)

   {

      /* as our thumbnail we will render only the first page of the

      **    document. calculate extents of our thumbnail rendering.

      **

      ** OLE2NOTE: thumbnails are most often used by applications in

      **    FindFile or FileOpen type dialogs to give the user a

      **    quick view of the contents of the file or object.

      */

      OleDoc_GetThumbnailExtent(lpOleDoc, lpsizel);

      // release artificial AddRef

      SvrDoc_OleObj_Release(lpThis);

      return NOERROR;

   }

#endif

   else

   {

      // release artificial AddRef

      SvrDoc_OleObj_Release(lpThis);

      return ResultFromScode(E_FAIL);

   }

}

// IOleObject::Advise method

STDMETHODIMP SvrDoc_OleObj_Advise(

      LPOLEOBJECT             lpThis,

      LPADVISESINK            lpAdvSink,

      LPDWORD                 lpdwConnection

)

{

   LPSERVERDOC lpServerDoc =

         ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;

   HRESULT hrErr;

   SCODE   sc;

   // artificial AddRef in case object is destroyed during call

   SvrDoc_OleObj_AddRef(lpThis);

   OLEDBG_BEGIN2("SvrDoc_OleObj_Advise\r\n");

   if (lpServerDoc->m_OleDoc.m_fObjIsClosing)

   {

       //  We don't accept any more Advise's once we're closing

       sc = OLE_E_ADVISENOTSUPPORTED;

       goto error;

   }

   if (lpServerDoc->m_lpOleAdviseHldr == NULL &&

      CreateOleAdviseHolder(&lpServerDoc->m_lpOleAdviseHldr) != NOERROR) {

      sc = E_OUTOFMEMORY;

      goto error;

   }

   OLEDBG_BEGIN2("IOleAdviseHolder::Advise called\r\n")

   hrErr = lpServerDoc->m_lpOleAdviseHldr->lpVtbl->Advise(

         lpServerDoc->m_lpOleAdviseHldr,

         lpAdvSink,

         lpdwConnection

   );

   OLEDBG_END2

   OLEDBG_END2

   // release artificial AddRef

   SvrDoc_OleObj_Release(lpThis);

   return hrErr;

error:

   OLEDBG_END2

   *lpdwConnection = 0;

   // release artificial AddRef

   SvrDoc_OleObj_Release(lpThis);

   return ResultFromScode(sc);

}

// IOleObject::Unadvise method

STDMETHODIMP SvrDoc_OleObj_Unadvise(LPOLEOBJECT lpThis, DWORD dwConnection)

{

   LPSERVERDOC lpServerDoc =

         ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;

   HRESULT hrErr;

   SCODE   sc;

   // artificial AddRef in case object is destroyed during call

   SvrDoc_OleObj_AddRef(lpThis);

   OLEDBG_BEGIN2("SvrDoc_OleObj_Unadvise\r\n");

   if (lpServerDoc->m_lpOleAdviseHldr == NULL) {

      sc = E_FAIL;

      goto error;

   }

   OLEDBG_BEGIN2("IOleAdviseHolder::Unadvise called\r\n")

   hrErr = lpServerDoc->m_lpOleAdviseHldr->lpVtbl->Unadvise(

         lpServerDoc->m_lpOleAdviseHldr,

         dwConnection

   );

   OLEDBG_END2

   OLEDBG_END2

   // release artificial AddRef

   SvrDoc_OleObj_Release(lpThis);

   return hrErr;

error:

   OLEDBG_END2

   // release artificial AddRef

   SvrDoc_OleObj_Release(lpThis);

   return ResultFromScode(sc);

}

// IOleObject::EnumAdvise method

STDMETHODIMP SvrDoc_OleObj_EnumAdvise(

      LPOLEOBJECT             lpThis,

      LPENUMSTATDATA FAR*     lplpenumAdvise

)

{

   LPSERVERDOC lpServerDoc =

         ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;

   HRESULT hrErr;

   SCODE   sc;

   // artificial AddRef in case object is destroyed during call

   SvrDoc_OleObj_AddRef(lpThis);

   OLEDBG_BEGIN2("SvrDoc_OleObj_EnumAdvise\r\n");

   /* OLE2NOTE: we must make sure to set all out parameters to NULL. */

   *lplpenumAdvise = NULL;

   if (lpServerDoc->m_lpOleAdviseHldr == NULL) {

      sc = E_FAIL;

      goto error;

   }

   OLEDBG_BEGIN2("IOleAdviseHolder::EnumAdvise called\r\n")

   hrErr = lpServerDoc->m_lpOleAdviseHldr->lpVtbl->EnumAdvise(

         lpServerDoc->m_lpOleAdviseHldr,

         lplpenumAdvise

   );

   OLEDBG_END2

   OLEDBG_END2

   // release artificial AddRef

   SvrDoc_OleObj_Release(lpThis);

   return hrErr;

error:

   OLEDBG_END2

   // release artificial AddRef

   SvrDoc_OleObj_Release(lpThis);

   return ResultFromScode(sc);

}

// IOleObject::GetMiscStatus method

STDMETHODIMP SvrDoc_OleObj_GetMiscStatus(

      LPOLEOBJECT             lpThis,

      DWORD                   dwAspect,

      DWORD FAR*              lpdwStatus

)

{

   LPSERVERDOC lpServerDoc =

         ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;

   // artificial AddRef in case object is destroyed during call

   SvrDoc_OleObj_AddRef(lpThis);

   OleDbgOut2("SvrDoc_OleObj_GetMiscStatus\r\n");

   /* Get our default MiscStatus for the given Aspect. this

   **    information is registered in the RegDB. We query the RegDB

   **    here to guarantee that the value returned from this method

   **    agrees with the values in RegDB. in this way we only have to

   **    maintain the info in one place (in the RegDB). Alternatively

   **    we could have the values hard coded here.

   */

   OleRegGetMiscStatus((REFCLSID)&CLSID_APP, dwAspect, lpdwStatus);

   /* OLE2NOTE: check if the data copied is compatible to be

   **    linked by an OLE 1.0 container. it is compatible if

   **    either the data is an untitled document, a file, or a

   **    selection of data within a file. if the data is part of

   **    an embedded object, then it is NOT compatible to be

   **    linked by an OLE 1.0 container. if it is compatible then

   **    we must include OLEMISC_CANLINKBYOLE1 as part of the

   **    dwStatus flags transfered via CF_OBJECTDESCRIPTOR or

   **    CF_LINKSRCDESCRIPTOR.

   */

   if (lpOutlineDoc->m_docInitType == DOCTYPE_NEW ||

      lpOutlineDoc->m_docInitType == DOCTYPE_FROMFILE)

      *lpdwStatus |= OLEMISC_CANLINKBYOLE1;

#if defined( INPLACE_SVR )

   if (dwAspect == DVASPECT_CONTENT)

      *lpdwStatus |= (OLEMISC_INSIDEOUT | OLEMISC_ACTIVATEWHENVISIBLE);

#endif  // INPLACE_SVR

   // release artificial AddRef

   SvrDoc_OleObj_Release(lpThis);

   return NOERROR;

}

// IOleObject::SetColorScheme method

STDMETHODIMP SvrDoc_OleObj_SetColorScheme(

      LPOLEOBJECT             lpThis,

      LPLOGPALETTE            lpLogpal

)

{

   OleDbgOut2("SvrDoc_OleObj_SetColorScheme\r\n");

   // REVIEW: NOT YET IMPLEMENTED

   return ResultFromScode(E_NOTIMPL);

}

/*************************************************************************

** ServerDoc::IPersistStorage interface implementation

*************************************************************************/

// IPersistStorage::QueryInterface method

STDMETHODIMP SvrDoc_PStg_QueryInterface(

      LPPERSISTSTORAGE        lpThis,

      REFIID                  riid,

      LPVOID FAR*             lplpvObj

)

{

   LPSERVERDOC lpServerDoc =

         ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc;

   return OleDoc_QueryInterface((LPOLEDOC)lpServerDoc, riid, lplpvObj);

}

// IPersistStorage::AddRef method

STDMETHODIMP_(ULONG) SvrDoc_PStg_AddRef(LPPERSISTSTORAGE lpThis)

{

   LPSERVERDOC lpServerDoc =

         ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc;

   OleDbgAddRefMethod(lpThis, "IPersistStorage");

   return OleDoc_AddRef((LPOLEDOC)lpServerDoc);

}

// IPersistStorage::Release method

STDMETHODIMP_(ULONG) SvrDoc_PStg_Release(LPPERSISTSTORAGE lpThis)

{

   LPSERVERDOC lpServerDoc =

         ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc;

   OleDbgReleaseMethod(lpThis, "IPersistStorage");

   return OleDoc_Release((LPOLEDOC)lpServerDoc);

}

// IPersistStorage::GetClassID method

STDMETHODIMP SvrDoc_PStg_GetClassID(

      LPPERSISTSTORAGE        lpThis,

      LPCLSID                 lpClassID

)

{

   LPSERVERDOC lpServerDoc =

         ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc;

   OleDbgOut2("SvrDoc_PStg_GetClassID\r\n");

   /* OLE2NOTE: we must be carefull to return the correct CLSID here.

   **    if we are currently preforming a "TreatAs (aka. ActivateAs)"

   **    operation then we need to return the class of the object

   **    written in the storage of the object. otherwise we would

   **    return our own class id.

   */

   return ServerDoc_GetClassID(lpServerDoc, lpClassID);

}

// IPersistStorage::IsDirty method

STDMETHODIMP  SvrDoc_PStg_IsDirty(LPPERSISTSTORAGE  lpThis)

{

   LPSERVERDOC lpServerDoc =

         ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc;

   OleDbgOut2("SvrDoc_PStg_IsDirty\r\n");

   if (OutlineDoc_IsModified((LPOUTLINEDOC)lpServerDoc))

      return NOERROR;

   else

      return ResultFromScode(S_FALSE);

}

// IPersistStorage::InitNew method

STDMETHODIMP SvrDoc_PStg_InitNew(

      LPPERSISTSTORAGE        lpThis,

      LPSTORAGE               lpStg

)

{

   LPSERVERDOC lpServerDoc =

         ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc;

   LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc;

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   LPOLESTR    lpszUserType = (LPOLESTR)FULLUSERTYPENAME;

   HRESULT hrErr;

   SCODE sc;

   OLEDBG_BEGIN2("SvrDoc_PStg_InitNew\r\n")

#if defined( SVR_TREATAS )

   {

      LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

      CLSID       clsid;

      CLIPFORMAT  cfFmt;

      LPOLESTR       lpszType;

      /* OLE2NOTE: if the Server is capable of supporting "TreatAs"

      **    (aka. ActivateAs), it must read the class that is written

      **    into the storage. if this class is NOT the app's own

      **    class ID, then this is a TreatAs operation. the server

      **    then must faithfully pretend to be the class that is

      **    written into the storage. it must also faithfully write

      **    the data back to the storage in the SAME format as is

      **    written in the storage.

      **

      **    SVROUTL and ISVROTL can emulate each other. they have the

      **    simplification that they both read/write the identical

      **    format. thus for these apps no actual conversion of the

      **    native bits is actually required.

      */

      lpServerDoc->m_clsidTreatAs = CLSID_NULL;

      if (OleStdGetTreatAsFmtUserType(&CLSID_APP, lpStg, &clsid,

                     (CLIPFORMAT FAR*)&cfFmt, (LPOLESTR FAR*)&lpszType)) {

         if (cfFmt == lpOutlineApp->m_cfOutline) {

            // We should perform TreatAs operation

            if (lpServerDoc->m_lpszTreatAsType)

               OleStdFreeString(lpServerDoc->m_lpszTreatAsType, NULL);

            lpServerDoc->m_clsidTreatAs = clsid;

            ((LPOUTLINEDOC)lpServerDoc)->m_cfSaveFormat = cfFmt;

            lpServerDoc->m_lpszTreatAsType = lpszType;

            lpszUserType = lpServerDoc->m_lpszTreatAsType;

            OleDbgOut3("SvrDoc_PStg_InitNew: TreateAs ==> '");

//            OleDbgOutNoPrefix3(lpServerDoc->m_lpszTreatAsType);

            OleDbgOutNoPrefix3("'\r\n");

         } else {

            // ERROR: we ONLY support TreatAs for CF_OUTLINE format

            OleDbgOut("SvrDoc_PStg_InitNew: INVALID TreatAs Format\r\n");

            OleStdFreeString(lpszType, NULL);

         }

      }

   }

#endif  // SVR_TREATAS

   /* OLE2NOTE: a server EXE object should write its format tag to its

   **    storage in InitNew so that the DefHandler can know the format

   **    of the object. this is particularly important if the objects

   **    uses CF_METATFILE or CF_DIB as its format. the DefHandler

   **    automatically avoids separately storing presentation cache

   **    data when the object's native data is a standard presentation

   **    format.

   */

   WriteFmtUserTypeStg(lpStg,(CLIPFORMAT)lpOutlineApp->m_cfOutline,lpszUserType);

   // set the doc to a new embedded object.

   if (! ServerDoc_InitNewEmbed(lpServerDoc)) {

      sc = E_FAIL;

      goto error;

   }

   /* OLE2NOTE: An embedded object must guarantee that it can save

   **    even in low memory situations. it must be able to

   **    successfully save itself without consuming any additional

   **    memory. this means that a server is NOT supposed to open or

   **    create any streams or storages when

   **    IPersistStorage::Save(fSameAsLoad==TRUE) is called. thus an

   **    embedded object should hold onto its storage and pre-open and

   **    hold open any streams that it will need later when it is time

   **    to save.

   */

   hrErr = lpStg->lpVtbl->CreateStream(

         lpStg,

         OLESTR("LineList"),

         STGM_WRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE,

         0,

         0,

         &lpOleDoc->m_lpLLStm

   );

   if (hrErr != NOERROR) {

      OleDbgAssertSz(hrErr==NOERROR,"Could not create LineList stream");

      OleDbgOutHResult("LineList CreateStream returned", hrErr);

      sc = GetScode(hrErr);

      goto error;

   }

   hrErr = lpStg->lpVtbl->CreateStream(

         lpStg,

         OLESTR("NameTable"),

         STGM_WRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE,

         0,

         0,

         &lpOleDoc->m_lpNTStm

   );

   if (hrErr != NOERROR) {

      OleDbgAssertSz(hrErr==NOERROR,"Could not create NameTable stream");

      OleDbgOutHResult("NameTable CreateStream returned", hrErr);

      sc = GetScode(hrErr);

      goto error;

   }

   lpOleDoc->m_lpStg = lpStg;

   // OLE2NOTE: to be able to hold onto IStorage* pointer, we must AddRef it

   lpStg->lpVtbl->AddRef(lpStg);

   OLEDBG_END2

   return NOERROR;

error:

   OLEDBG_END2

   return ResultFromScode(sc);

}

// IPersistStorage::Load method

STDMETHODIMP SvrDoc_PStg_Load(

      LPPERSISTSTORAGE        lpThis,

      LPSTORAGE               lpStg

)

{

   LPSERVERDOC lpServerDoc =

         ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc;

   LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc;

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;

   SCODE sc;

   HRESULT hrErr;

   OLEDBG_BEGIN2("SvrDoc_PStg_Load\r\n")

   if (OutlineDoc_LoadFromStg((LPOUTLINEDOC)lpServerDoc, lpStg)) {

      ((LPOUTLINEDOC)lpServerDoc)->m_docInitType = DOCTYPE_EMBEDDED;

      /* OLE2NOTE: we need to check if the ConvertStg bit is on. if

      **    so, we need to clear the ConvertStg bit and mark the

      **    document as dirty so as to force a save when the document

      **    is closed. the actual conversion of the bits should be

      **    performed when the data is loaded from the IStorage*. in

      **    our case any conversion of data formats would be done in

      **    OutlineDoc_LoadFromStg function. in reality both SVROUTL

      **    and ISVROTL read and write the same format so no actual

      **    conversion of data bits is necessary.

      */

      if (GetConvertStg(lpStg) == NOERROR) {

         SetConvertStg(lpStg, FALSE);

         OleDbgOut3("SvrDoc_PStg_Load: ConvertStg==TRUE\r\n");

         OutlineDoc_SetModified(lpOutlineDoc, TRUE, FALSE, FALSE);

      }

   } else {

      sc = E_FAIL;

      goto error;

   }

   /* OLE2NOTE: An embedded object must guarantee that it can save

   **    even in low memory situations. it must be able to

   **    successfully save itself without consuming any additional

   **    memory. this means that a server is NOT supposed to open or

   **    create any streams or storages when

   **    IPersistStorage::Save(fSameAsLoad==TRUE) is called. thus an

   **    embedded object should hold onto its storage and pre-open and

   **    hold open any streams that it will need later when it is time

   **    to save.

   */

   if (lpOleDoc->m_lpLLStm)

      OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpLLStm);

   hrErr = lpStg->lpVtbl->OpenStream(

         lpStg,

         OLESTR("LineList"),

         NULL,

         STGM_READWRITE | STGM_SHARE_EXCLUSIVE,

         0,

         &lpOleDoc->m_lpLLStm

   );

   if (hrErr != NOERROR) {

      OleDbgAssertSz(hrErr==NOERROR,"Could not create LineList stream");

      OleDbgOutHResult("LineList CreateStream returned", hrErr);

      sc = GetScode(hrErr);

      goto error;

   }

   if (lpOleDoc->m_lpNTStm)

      OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpNTStm);

   hrErr = lpStg->lpVtbl->OpenStream(

         lpStg,

         OLESTR("NameTable"),

         NULL,

         STGM_READWRITE | STGM_SHARE_EXCLUSIVE,

         0,

         &lpOleDoc->m_lpNTStm

   );

   if (hrErr != NOERROR) {

      OleDbgAssertSz(hrErr==NOERROR,"Could not create NameTable stream");

      OleDbgOutHResult("NameTable CreateStream returned", hrErr);

      sc = GetScode(hrErr);

      goto error;

   }

   lpOleDoc->m_lpStg = lpStg;

   // OLE2NOTE: to be able to hold onto IStorage* pointer, we must AddRef it

   lpStg->lpVtbl->AddRef(lpStg);

   OLEDBG_END2

   return NOERROR;

error:

   OLEDBG_END2

   return ResultFromScode(sc);

}

// IPersistStorage::Save method

STDMETHODIMP SvrDoc_PStg_Save(

      LPPERSISTSTORAGE        lpThis,

      LPSTORAGE               lpStg,

      BOOL                    fSameAsLoad

)

{

   LPSERVERDOC lpServerDoc =

         ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc;

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;

   BOOL fStatus;

   SCODE sc;

   OLEDBG_BEGIN2("SvrDoc_PStg_Save\r\n")

   fStatus = OutlineDoc_SaveSelToStg(

         (LPOUTLINEDOC)lpServerDoc,

         NULL,

         lpOutlineDoc->m_cfSaveFormat,

         lpStg,

         fSameAsLoad,

         FALSE

   );

   if (! fStatus) {

      OutlineApp_ErrorMessage(g_lpApp, ErrMsgPSSaveFail);

      sc = E_FAIL;

      goto error;

   }

   lpServerDoc->m_fSaveWithSameAsLoad = fSameAsLoad;

   lpServerDoc->m_fNoScribbleMode = TRUE;

   OLEDBG_END2

   return NOERROR;

error:

   OLEDBG_END2

   return ResultFromScode(sc);

}

// IPersistStorage::SaveCompleted method

STDMETHODIMP SvrDoc_PStg_SaveCompleted(

      LPPERSISTSTORAGE        lpThis,

      LPSTORAGE               lpStgNew

)

{

   LPSERVERDOC lpServerDoc =

         ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc;

   LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc;

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;

   HRESULT hrErr;

   OLEDBG_BEGIN2("SvrDoc_PStg_SaveCompleted\r\n")

   /* OLE2NOTE: this sample application is a pure server application.

   **    a container/server application would have to call SaveCompleted

   **    for each of its contained compound document objects. if a new

   **    storage was given, then the container/server would have to

   **    open the corresponding new sub-storage for each compound

   **    document object and pass as an argument in the SaveCompleted

   **    call.

   */

   /* OLE2NOTE: it is only legal to perform a Save or SaveAs operation

   **    on an embedded object. if the document is a file-based document

   **    then we can not be changed to a IStorage-base object.

   **

   **      fSameAsLoad   lpStgNew     Type of Save     Send OnSave

   **    ---------------------------------------------------------

   **         TRUE        NULL        SAVE             YES

   **         TRUE        ! NULL      SAVE *           YES

   **         FALSE       ! NULL      SAVE AS          YES

   **         FALSE       NULL        SAVE COPY AS     NO

   **

   **    * this is a strange case that is possible. it is inefficient

   **    for the caller; it would be better to pass lpStgNew==NULL for

   **    the Save operation.

   */

   if ( ((lpServerDoc->m_fSaveWithSameAsLoad && lpStgNew==NULL) || lpStgNew)

         && (lpOutlineDoc->m_docInitType != DOCTYPE_EMBEDDED) ) {

      OLEDBG_END2

      return ResultFromScode(E_INVALIDARG);

   }

   /* OLE2NOTE: inform any linking clients that the document has been

   **    saved. in addition, any currently active pseudo objects

   **    should also inform their clients. we should only broadcast an

   **    OnSave notification if a Save or SaveAs operation was

   **    performed. we do NOT want to send the notification if a

   **    SaveCopyAs operation was performed.

   */

   if (lpStgNew || lpServerDoc->m_fSaveWithSameAsLoad) {

      /* OLE2NOTE: if IPersistStorage::Save has been called, then we

      **    need to clear the dirty bit and send OnSave notification.

      **    if HandsOffStorage is called directly without first

      **    calling Save, then we do NOT want to clear the dirty bit

      **    and send OnSave when SaveCompleted is called.

      */

      if (lpServerDoc->m_fNoScribbleMode) {

         OutlineDoc_SetModified(lpOutlineDoc, FALSE, FALSE, FALSE);

         ServerDoc_SendAdvise (

               lpServerDoc,

               OLE_ONSAVE,

               NULL,   /* lpmkDoc -- not relevant here */

               0       /* advf -- not relevant here */

         );

      }

      lpServerDoc->m_fSaveWithSameAsLoad = FALSE;

   }

   lpServerDoc->m_fNoScribbleMode = FALSE;

   /* OLE2NOTE: An embedded object must guarantee that it can save

   **    even in low memory situations. it must be able to

   **    successfully save itself without consuming any additional

   **    memory. this means that a server is NOT supposed to open or

   **    create any streams or storages when

   **    IPersistStorage::Save(fSameAsLoad==TRUE) is called. thus an

   **    embedded object should hold onto its storage and pre-open and

   **    hold open any streams that it will need later when it is time

   **    to save. if this is a SaveAs situtation, then we want to

   **    pre-open and hold open our streams to guarantee that a

   **    subsequent save will be successful in low-memory. if we fail

   **    to open these streams then we want to force ourself to close

   **    to make sure the can't make editing changes that can't be

   **    later saved.

   */

   if ( lpStgNew && !lpServerDoc->m_fSaveWithSameAsLoad ) {

      // release previous streams

      if (lpOleDoc->m_lpLLStm) {

         OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpLLStm);

         lpOleDoc->m_lpLLStm = NULL;

      }

      if (lpOleDoc->m_lpNTStm) {

         OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpNTStm);

         lpOleDoc->m_lpNTStm = NULL;

      }

      if (lpOleDoc->m_lpStg) {

         OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpStg);

         lpOleDoc->m_lpStg = NULL;

      }

      hrErr = lpStgNew->lpVtbl->OpenStream(

            lpStgNew,

            OLESTR("LineList"),

            NULL,

            STGM_READWRITE | STGM_SHARE_EXCLUSIVE,

            0,

            &lpOleDoc->m_lpLLStm

      );

      if (hrErr != NOERROR) {

         OleDbgAssertSz(hrErr==NOERROR,"Could not create LineList stream");

         OleDbgOutHResult("LineList CreateStream returned", hrErr);

         goto error;

      }

      hrErr = lpStgNew->lpVtbl->OpenStream(

            lpStgNew,

            OLESTR("NameTable"),

            NULL,

            STGM_READWRITE | STGM_SHARE_EXCLUSIVE,

            0,

            &lpOleDoc->m_lpNTStm

      );

      if (hrErr != NOERROR) {

         OleDbgAssertSz(hrErr==NOERROR,"Could not create NameTable stream");

         OleDbgOutHResult("NameTable CreateStream returned", hrErr);

         goto error;

      }

      lpOleDoc->m_lpStg = lpStgNew;

      // OLE2NOTE: to hold onto IStorage* pointer, we must AddRef it

      lpStgNew->lpVtbl->AddRef(lpStgNew);

   }

   OLEDBG_END2

   return NOERROR;

error:

   OLEDBG_END2

   return ResultFromScode(E_OUTOFMEMORY);

}

// IPersistStorage::HandsOffStorage method

STDMETHODIMP SvrDoc_PStg_HandsOffStorage(LPPERSISTSTORAGE lpThis)

{

   LPSERVERDOC lpServerDoc =

         ((struct CDocPersistStorageImpl FAR*)lpThis)->lpServerDoc;

   LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc;

   OLEDBG_BEGIN2("SvrDoc_PStg_HandsOffStorage\r\n")

   /* OLE2NOTE: An embedded object must guarantee that it can save

   **    even in low memory situations. it must be able to

   **    successfully save itself without consuming any additional

   **    memory. this means that a server is NOT supposed to open or

   **    create any streams or storages when

   **    IPersistStorage::Save(fSameAsLoad==TRUE) is called. thus an

   **    embedded object should hold onto its storage and pre-open and

   **    hold open any streams that it will need later when it is time

   **    to save. Now when HandsOffStorage is called the object must

   **    release its storage and any streams that is holds open.

   **    later when SaveCompleted is called, it will be given back its

   **    storage.

   */

   if (lpOleDoc->m_lpLLStm) {

      OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpLLStm);

      lpOleDoc->m_lpLLStm = NULL;

   }

   if (lpOleDoc->m_lpNTStm) {

      OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpNTStm);

      lpOleDoc->m_lpNTStm = NULL;

   }

   if (lpOleDoc->m_lpStg) {

      OleStdRelease((LPUNKNOWN)lpOleDoc->m_lpStg);

      lpOleDoc->m_lpStg = NULL;

   }

   OLEDBG_END2

   return NOERROR;

}

#if defined( SVR_TREATAS )

/*************************************************************************

** ServerDoc::IStdMarshalInfo interface implementation

*************************************************************************/

// IStdMarshalInfo::QueryInterface method

STDMETHODIMP SvrDoc_StdMshl_QueryInterface(

      LPSTDMARSHALINFO        lpThis,

      REFIID                  riid,

      LPVOID FAR*             lplpvObj

)

{

   LPSERVERDOC lpServerDoc =

         ((struct CDocStdMarshalInfoImpl FAR*)lpThis)->lpServerDoc;

   return OleDoc_QueryInterface((LPOLEDOC)lpServerDoc, riid, lplpvObj);

}

// IStdMarshalInfo::AddRef method

STDMETHODIMP_(ULONG) SvrDoc_StdMshl_AddRef(LPSTDMARSHALINFO lpThis)

{

   LPSERVERDOC lpServerDoc =

         ((struct CDocStdMarshalInfoImpl FAR*)lpThis)->lpServerDoc;

   OleDbgAddRefMethod(lpThis, "IStdMarshalInfo");

   return OleDoc_AddRef((LPOLEDOC)lpServerDoc);

}

// IStdMarshalInfo::Release method

STDMETHODIMP_(ULONG) SvrDoc_StdMshl_Release(LPSTDMARSHALINFO lpThis)

{

   LPSERVERDOC lpServerDoc =

         ((struct CDocStdMarshalInfoImpl FAR*)lpThis)->lpServerDoc;

   OleDbgReleaseMethod(lpThis, "IStdMarshalInfo");

   return OleDoc_Release((LPOLEDOC)lpServerDoc);

}

// IStdMarshalInfo::GetClassForHandler

STDMETHODIMP SvrDoc_StdMshl_GetClassForHandler(

      LPSTDMARSHALINFO        lpThis,

      DWORD                   dwDestContext,

      LPVOID                  pvDestContext,

      LPCLSID                 lpClassID

)

{

   LPSERVERDOC lpServerDoc =

         ((struct CDocStdMarshalInfoImpl FAR*)lpThis)->lpServerDoc;

   OleDbgOut2("SvrDoc_StdMshl_GetClassForHandler\r\n");

   // OLE2NOTE: we only handle LOCAL marshal context.

   if (dwDestContext != MSHCTX_LOCAL || pvDestContext != NULL)

      return ResultFromScode(E_INVALIDARG);

   /* OLE2NOTE: we must return our REAL clsid, NOT the clsid that we

   **    are pretending to be if a "TreatAs" is in effect.

   */

   *lpClassID = CLSID_APP;

   return NOERROR;

}

#endif  // SVR_TREATAS

/*************************************************************************

** ServerDoc Support Functions

*************************************************************************/

/* ServerDoc_Init

 * --------------

 *

 *  Initialize the fields of a new ServerDoc object. The object is initially

 *  not associated with a file or an (Untitled) document. This function sets

 *  the docInitType to DOCTYPE_UNKNOWN. After calling this function the

 *  caller should call:

 *      1.) OutlineDoc_InitNewFile to set the ServerDoc to (Untitled)

 *      2.) OutlineDoc_LoadFromFile to associate the ServerDoc with a file.

 *  This function creates a new window for the document.

 *

 *  NOTE: the window is initially created with a NIL size. it must be

 *        sized and positioned by the caller. also the document is initially

 *        created invisible. the caller must call OutlineDoc_ShowWindow

 *        after sizing it to make the document window visible.

 */

BOOL ServerDoc_Init(LPSERVERDOC lpServerDoc, BOOL fDataTransferDoc)

{

   lpServerDoc->m_cPseudoObj                   = 0;

   lpServerDoc->m_lpOleClientSite              = NULL;

   lpServerDoc->m_lpOleAdviseHldr              = NULL;

   lpServerDoc->m_lpDataAdviseHldr             = NULL;

   // initialy doc does not have any storage

   lpServerDoc->m_fNoScribbleMode              = FALSE;

   lpServerDoc->m_fSaveWithSameAsLoad          = FALSE;

   lpServerDoc->m_szContainerApp[0]            = '\0';

   lpServerDoc->m_szContainerObj[0]            = '\0';

   lpServerDoc->m_nNextRangeNo                 = 0L;

   lpServerDoc->m_lrSrcSelOfCopy.m_nStartLine  = -1;

   lpServerDoc->m_lrSrcSelOfCopy.m_nEndLine    = -1;

   lpServerDoc->m_fDataChanged                 = FALSE;

   lpServerDoc->m_fSizeChanged                 = FALSE;

   lpServerDoc->m_fSendDataOnStop              = FALSE;

#if defined( SVR_TREATAS )

   lpServerDoc->m_clsidTreatAs                 = CLSID_NULL;

   lpServerDoc->m_lpszTreatAsType              = NULL;

#endif  // SVR_TREATAS

#if defined( INPLACE_SVR )

   lpServerDoc->m_hWndHatch                    =

         CreateHatchWindow(

               OutlineApp_GetWindow(g_lpApp),

               OutlineApp_GetInstance(g_lpApp)

         );

   if (!lpServerDoc->m_hWndHatch)

      return FALSE;

   lpServerDoc->m_fInPlaceActive               = FALSE;

   lpServerDoc->m_fInPlaceVisible              = FALSE;

   lpServerDoc->m_fUIActive                    = FALSE;

   lpServerDoc->m_lpIPData                     = NULL;

   lpServerDoc->m_fMenuHelpMode                = FALSE; // F1 pressed in menu

   INIT_INTERFACEIMPL(

         &lpServerDoc->m_OleInPlaceObject,

         &g_SvrDoc_OleInPlaceObjectVtbl,

         lpServerDoc

   );

   INIT_INTERFACEIMPL(

         &lpServerDoc->m_OleInPlaceActiveObject,

         &g_SvrDoc_OleInPlaceActiveObjectVtbl,

         lpServerDoc

   );

#endif // INPLACE_SVR

   INIT_INTERFACEIMPL(

         &lpServerDoc->m_OleObject,

         &g_SvrDoc_OleObjectVtbl,

         lpServerDoc

   );

   INIT_INTERFACEIMPL(

         &lpServerDoc->m_PersistStorage,

         &g_SvrDoc_PersistStorageVtbl,

         lpServerDoc

   );

#if defined( SVR_TREATAS )

   INIT_INTERFACEIMPL(

         &lpServerDoc->m_StdMarshalInfo,

         &g_SvrDoc_StdMarshalInfoVtbl,

         lpServerDoc

   );

#endif  // SVR_TREATAS

   return TRUE;

}

/* ServerDoc_InitNewEmbed

 * ----------------------

 *

 *  Initialize the ServerDoc object to be a new embedded object document.

 *  This function sets the docInitType to DOCTYPE_EMBED.

 */

BOOL ServerDoc_InitNewEmbed(LPSERVERDOC lpServerDoc)

{

   char szAnsiStr[256];

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;

   OleDbgAssert(lpOutlineDoc->m_docInitType == DOCTYPE_UNKNOWN);

   lpOutlineDoc->m_docInitType = DOCTYPE_EMBEDDED;

   /* The Window title for an embedded object is constructed as

   **    follows:

   **      <server app name> - <obj short type> in <cont. doc name>

   **

   **    here we construct the current document title portion of the

   **    name which follows the '-'. OutlineDoc_SetTitle prepends the

   **    "<server app name> - " to the document title.

   */

   // REVIEW: this string should be loaded from string resource

   wsprintf(szAnsiStr, "%s in %s",

      (LPSTR)SHORTUSERTYPENAME,

      (LPSTR)DEFCONTAINERNAME);

   A2W (szAnsiStr, lpOutlineDoc->m_szFileName, OLEUI_CCHPATHMAX);

   lpOutlineDoc->m_lpszDocTitle = lpOutlineDoc->m_szFileName;

   /* OLE2NOTE: an embedding should be marked as initially dirty so

   **    that on close we always call IOleClientSite::SaveObject.

   */

   OutlineDoc_SetModified(lpOutlineDoc, TRUE, FALSE, FALSE);

   OutlineDoc_SetTitle(lpOutlineDoc, FALSE /*fMakeUpperCase*/);

   return TRUE;

}

/* ServerDoc_SendAdvise

 * --------------------

 *

 * This function sends an advise notification on behalf of a specific

 *  doc object to all its clients.

 */

void ServerDoc_SendAdvise(

      LPSERVERDOC     lpServerDoc,

      WORD            wAdvise,

      LPMONIKER       lpmkDoc,

      DWORD           dwAdvf

)

{

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;

   LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc;

   switch (wAdvise) {

      case OLE_ONDATACHANGE:

         // inform clients that the data of the object has changed

         if (lpOutlineDoc->m_nDisableDraw == 0) {

            /* drawing is currently enabled. inform clients that

            **    the data of the object has changed

            */

            lpServerDoc->m_fDataChanged = FALSE;

            /* OLE2NOTE: we must note the time of last change

            **    for our object in the RunningObjectTable.

            **    this is used as the basis to answer

            **    IOleObject::IsUpToDate. we only want to note

            **    the change time when an actual change takes

            **    place. we do NOT want to set it when we are

            **    notifying clients of ADVF_DATAONSTOP

            */

            if (dwAdvf == 0)

               OleStdNoteObjectChangeTime(lpOleDoc->m_dwRegROT);

            if (lpServerDoc->m_lpDataAdviseHldr) {

               OLEDBG_BEGIN2("IDataAdviseHolder::SendOnDataChange called\r\n");

               lpServerDoc->m_lpDataAdviseHldr->lpVtbl->SendOnDataChange(

                     lpServerDoc->m_lpDataAdviseHldr,

                     (LPDATAOBJECT)&lpOleDoc->m_DataObject,

                     0,

                     dwAdvf

               );

               OLEDBG_END2

            }

#if defined( INPLACE_SVR )

            /* OLE2NOTE: if the ServerDoc is currently in-place UI active,

            **    then is it important to renegotiate the size for the

            **    in-place document window BEFORE sending OnDataChange

            **    (which will cause the window to repaint).

            */

            if (lpServerDoc->m_fSizeChanged) {

               lpServerDoc->m_fSizeChanged = FALSE;

               if (lpServerDoc->m_fInPlaceActive)

                  ServerDoc_UpdateInPlaceWindowOnExtentChange(lpServerDoc);

            }

#endif

            /* OLE2NOTE: we do NOT need to tell our pseudo objects to

            **    broadcast OnDataChange notification because

            **    they will do it automatically when an editing

            **    change in the document affects a PseudoObj.

            **    (see OutlineNameTable_AddLineUpdate,

            **         OutlineNameTable_DeleteLineUpdate,

            **    and  ServerNameTable_EditLineUpdate)

            */

         } else {

            /* drawing is currently disabled. do not send

            **    notifications or call

            **    IOleInPlaceObject::OnPosRectChange until drawing

            **    is re-enabled.

            */

         }

         break;

      case OLE_ONCLOSE:

         // inform clients that the document is shutting down

         if (lpServerDoc->m_lpOleAdviseHldr) {

            OLEDBG_BEGIN2("IOleAdviseHolder::SendOnClose called\r\n");

            lpServerDoc->m_lpOleAdviseHldr->lpVtbl->SendOnClose(

                  lpServerDoc->m_lpOleAdviseHldr

            );

            OLEDBG_END2

         }

         /* OLE2NOTE: we do NOT need to tell our pseudo objects to

         **    broadcast OnClose notification because they will do

         **    it automatically when the pseudo object is closed.

         **    (see PseudoObj_Close)

         */

         break;

      case OLE_ONSAVE:

         // inform clients that the object has been saved

         OLEDBG_BEGIN3("ServerDoc_SendAdvise ONSAVE\r\n");

         if (lpServerDoc->m_lpOleAdviseHldr) {

            OLEDBG_BEGIN2("IOleAdviseHolder::SendOnSave called\r\n");

            lpServerDoc->m_lpOleAdviseHldr->lpVtbl->SendOnSave(

                  lpServerDoc->m_lpOleAdviseHldr

            );

            OLEDBG_END2

         }

         /* OLE2NOTE: inform any clients of pseudo objects

         **    within our document, that our document has been

         **    saved.

         */

         ServerNameTable_InformAllPseudoObjectsDocSaved(

               (LPSERVERNAMETABLE)lpOutlineDoc->m_lpNameTable,

               lpmkDoc

         );

         OLEDBG_END3

         break;

      case OLE_ONRENAME:

         // inform clients that the object's name has changed

         OLEDBG_BEGIN3("ServerDoc_SendAdvise ONRENAME\r\n");

         if (lpmkDoc && lpServerDoc->m_lpOleAdviseHldr) {

            OLEDBG_BEGIN2("IOleAdviseHolder::SendOnRename called\r\n");

            lpServerDoc->m_lpOleAdviseHldr->lpVtbl->SendOnRename(

                  lpServerDoc->m_lpOleAdviseHldr,

                  lpmkDoc

            );

            OLEDBG_END2

         }

         OLEDBG_END3

         break;

   }

}

/* ServerDoc_GetClassID

** --------------------

**    Return the class ID corresponding to the bits in the storage.

**    normally this will be our application's given CLSID. but if a

**    "TreateAs (aka. ActivateAs)" operation is taking place, then our

**    application needs to pretend to be the class of the object that

**    we are emulating. this is also the class that will be written

**    into the storage.

*/

HRESULT ServerDoc_GetClassID(LPSERVERDOC lpServerDoc, LPCLSID lpclsid)

{

#if defined( SVR_TREATAS )

   if (! IsEqualCLSID(&lpServerDoc->m_clsidTreatAs, &CLSID_NULL))

      *lpclsid = lpServerDoc->m_clsidTreatAs;

   else

#endif  // SVR_TREATAS

      *lpclsid = CLSID_APP;

   return NOERROR;

}

/* ServerDoc_UpdateMenu

 * --------------------

 *

 *  Update menu for embedding mode. the changes include:

 *      1 Remove File/New and File/Open (SDI ONLY)

 *      2 Change File/Save As.. to File/Save Copy As..

 *      3 Change File menu so it contains "Update" instead of "Save"

 *      4 Change File/Exit to File/Exit & Return to <client doc>"

 */

void ServerDoc_UpdateMenu(LPSERVERDOC lpServerDoc)

{

   char    str[256];

   HWND    hWndMain;

   HMENU   hMenu;

   char    szAnsiStr[256];

   OleDbgOut2("ServerDoc_UpdateMenu\r\n");

   hWndMain=g_lpApp->m_hWndApp;

   hMenu=GetMenu(hWndMain);

#if defined( SDI_VERSION )

   /* SDI ONLY: Remove File/New and File/Open */

   DeleteMenu(hMenu, IDM_F_NEW, MF_BYCOMMAND);

   DeleteMenu(hMenu, IDM_F_OPEN, MF_BYCOMMAND);

#endif

   // Change File.Save As.. to File.Save Copy As.. */

   ModifyMenu(hMenu,IDM_F_SAVEAS, MF_STRING, IDM_F_SAVEAS, "Save Copy As..");

   // Change File.Save to "&Update <container doc>"

   W2A (lpServerDoc->m_szContainerObj, szAnsiStr, 256);

   wsprintf(str, g_szUpdateCntrDoc, szAnsiStr);

   ModifyMenu(hMenu, IDM_F_SAVE, MF_STRING, IDM_F_SAVE, str);

   // Change File/Exit to File/Exit & Return to <container doc>" */

   W2A (lpServerDoc->m_szContainerObj, szAnsiStr, 256);

   wsprintf(str, g_szExitNReturnToCntrDoc, szAnsiStr);

   ModifyMenu(hMenu, IDM_F_EXIT, MF_STRING, IDM_F_EXIT, str);

   DrawMenuBar(hWndMain);

}

#if defined( MDI_VERSION )

// NOTE: ServerDoc_RestoreMenu is actually redundant because the

//          app is dying when the function is called.  (In SDI, the

//          app will terminate when the ref counter of the server doc

//          is zero). However, it is important for MDI.

/* ServerDoc_RestoreMenu

 * ---------------------

 *

 *      Reset the menu to non-embedding mode

 */

void ServerDoc_RestoreMenu(LPSERVERDOC lpServerDoc)

{

   LPOUTLINEAPP    lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   HWND            hWndMain;

   HMENU           hMenu;

   OleDbgOut2("ServerDoc_RestoreMenu\r\n");

   hWndMain = lpOutlineApp->m_hWndApp;

   hMenu = GetMenu(hWndMain);

   /* Add back File/New, File/Open.. and File/Save */

   InsertMenu(hMenu, IDM_F_SAVEAS, MF_BYCOMMAND | MF_ENABLED | MF_STRING,

      IDM_F_NEW, "&New");

   InsertMenu(hMenu, IDM_F_SAVEAS, MF_BYCOMMAND | MF_ENABLED | MF_STRING,

      IDM_F_OPEN, "&Open...");

   /* Change File menu so it contains "Save As..." instead of */

   /* "Save Copy As..." */

   ModifyMenu(hMenu, IDM_F_SAVEAS, MF_STRING, IDM_F_SAVEAS, "Save &As..");

   /* Change File menu so it contains "Save" instead of "Update" */

   ModifyMenu(hMenu, IDM_F_SAVE, MF_STRING, IDM_F_SAVE, "&Save");

   /* Change File menu so it contains "Exit" */

   /* instead of just "Exit & Return to <client doc>" */

   ModifyMenu(hMenu, IDM_F_EXIT, MF_STRING, IDM_F_EXIT, "E&xit");

   DrawMenuBar (hWndMain);

}

#endif  // MDI_VERSION


SVRINPL.C  (OUTLINE Sample)

/*************************************************************************

**

**    OLE 2 Server Sample Code

**

**    svrinpl.c

**

**    This file contains all interfaces, methods and related support

**    functions for an In-Place Object (Server) application (aka. Visual

**    Editing). The in-place Object application includes the following

**    implementation objects:

**

**    ServerDoc Object

**      exposed interfaces:

**          IOleInPlaceObject

**          IOleInPlaceActiveObject

**

**    ServerApp Object

**      exposed interfaces:

**          IUnknown

**

**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

**

*************************************************************************/

#include "outline.h"

OLEDBGDATA

extern LPOUTLINEAPP             g_lpApp;

/* OLE2NOTE: the object should compose a string that is used by

**    in-place containers to be used for the window titles. this string

**    is passed to the container application via

**    IOleInPlaceUIWindow::SetActiveObject. the string should have the

**    following form:

**          <application name> - <object short type name>

**    SDI containers can use the string directly to display in the

**    frame window title. the container would concatenate the string

**    " in <container doc name>".

**    an MDI container with the MDI child window maximized can do the

**    same as the SDI container. an MDI container with the MDI child

**    windows NOT maximized can look for the " - " in the string from

**    the object. the first part of the string (app name) would be put

**    as the frame window title; the second part would be composed with

**    " in <container doc name>" and used as the MDI child window

**    title.

*/

// REVIEW: should use string resource for messages

OLECHAR g_szIPObjectTitle[] = APPNAME OLESTR(" - ") SHORTUSERTYPENAME;

extern RECT g_rectNull;

/*************************************************************************

** ServerDoc::IOleInPlaceObject interface implementation

*************************************************************************/

// IOleInPlaceObject::QueryInterface method

STDMETHODIMP SvrDoc_IPObj_QueryInterface(

      LPOLEINPLACEOBJECT  lpThis,

      REFIID              riid,

      LPVOID FAR *        lplpvObj

)

{

   LPSERVERDOC lpServerDoc =

         ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;

   return OleDoc_QueryInterface((LPOLEDOC)lpServerDoc, riid, lplpvObj);

}

// IOleInPlaceObject::AddRef method

STDMETHODIMP_(ULONG) SvrDoc_IPObj_AddRef(LPOLEINPLACEOBJECT lpThis)

{

   LPSERVERDOC lpServerDoc =

         ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;

   OleDbgAddRefMethod(lpThis, "IOleInPlaceObject");

   return OleDoc_AddRef((LPOLEDOC)lpServerDoc);

}

// IOleInPlaceObject::Release method

STDMETHODIMP_(ULONG) SvrDoc_IPObj_Release(LPOLEINPLACEOBJECT lpThis)

{

   LPSERVERDOC lpServerDoc =

         ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;

   OleDbgReleaseMethod(lpThis, "IOleInPlaceObject");

   return OleDoc_Release((LPOLEDOC)lpServerDoc);

}

// IOleInPlaceObject::GetWindow method

STDMETHODIMP SvrDoc_IPObj_GetWindow(

      LPOLEINPLACEOBJECT  lpThis,

      HWND FAR*           lphwnd

)

{

   LPSERVERDOC lpServerDoc =

         ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;

   OLEDBG_BEGIN2("SvrDoc_IPObj_GetWindow\r\n")

   *lphwnd = ((LPOUTLINEDOC)lpServerDoc)->m_hWndDoc;

   OLEDBG_END2

   return S_OK;

}

// IOleInPlaceObject::ContextSensitiveHelp method

STDMETHODIMP SvrDoc_IPObj_ContextSensitiveHelp(

      LPOLEINPLACEOBJECT  lpThis,

      BOOL                fEnable

)

{

   LPOLEDOC lpOleDoc =

         (LPOLEDOC)((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;

   OleDbgOut2("SvrDoc_IPObj_ContextSensitiveHelp\r\n");

   /* OLE2NOTE: see context sensitive help technote (CSHELP.DOC).

   **    This method is called when SHIFT-F1 context sensitive help is

   **    entered. the cursor should then change to a question mark

   **    cursor and the app should enter a modal state where the next

   **    mouse click does not perform its normal action but rather

   **    gives help corresponding to the location clicked. if the app

   **    does not implement a help system, it should at least eat the

   **    click and do nothing.

   */

   lpOleDoc->m_fCSHelpMode = fEnable;

   return S_OK;

}

// IOleInPlaceObject::InPlaceDeactivate method

STDMETHODIMP SvrDoc_IPObj_InPlaceDeactivate(LPOLEINPLACEOBJECT lpThis)

{

   LPSERVERDOC lpServerDoc =

         ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;

   HRESULT hrErr;

   // artificial AddRef in case object is deleted during call

   SvrDoc_IPObj_AddRef(lpThis);

   OLEDBG_BEGIN2("SvrDoc_IPObj_InPlaceDeactivate\r\n")

   hrErr = ServerDoc_DoInPlaceDeactivate(lpServerDoc);

   OLEDBG_END2

   // release artificial AddRef

   SvrDoc_IPObj_Release(lpThis);

   return hrErr;

}

// IOleInPlaceObject::UIDeactivate method

STDMETHODIMP SvrDoc_IPObj_UIDeactivate(LPOLEINPLACEOBJECT lpThis)

{

   LPSERVERDOC     lpServerDoc =

                  ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;

   LPSERVERAPP     lpServerApp = (LPSERVERAPP)g_lpApp;

   LPOUTLINEDOC    lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;

   LPINPLACEDATA   lpIPData = lpServerDoc->m_lpIPData;

   LPLINELIST      lpLL = (LPLINELIST)&((LPOUTLINEDOC)lpServerDoc)->m_LineList;

   HWND            hWndApp = OutlineApp_GetWindow(g_lpApp);

   OLEDBG_BEGIN2("SvrDoc_IPObj_UIDeactivate\r\n");

   if (!lpServerDoc->m_fUIActive) {

      OLEDBG_END2

      return NOERROR;

   }

   // artificial AddRef in case object is deleted during call

   SvrDoc_IPObj_AddRef(lpThis);

   lpServerDoc->m_fUIActive = FALSE;

   // Clip the hatch window to the size of pos rect so, that the object

   // adornments and hatch border will not be visible.

   ServerDoc_ResizeInPlaceWindow(lpServerDoc,

         (LPRECT)&(lpServerDoc->m_lpIPData->rcPosRect),

         (LPRECT)&(lpServerDoc->m_lpIPData->rcPosRect)

   );

   if (lpIPData->lpDoc)

      lpIPData->lpDoc->lpVtbl->SetActiveObject(lpIPData->lpDoc, NULL, NULL);

   if (lpIPData->lpFrame) {

      lpIPData->lpFrame->lpVtbl->SetActiveObject(

         lpIPData->lpFrame,

         NULL,

         NULL

      );

   }

#if defined( USE_FRAMETOOLS )

   /* OLE2NOTE: we must hide our frame tools here but NOT call

   **    IOleInPlaceFrame::SetBorderSpace(NULL) or SetMenu(NULL).

   **    we must hide our tools BEFORE calling

   **    IOleInPlaceSite::OnUIDeactivate. the container will put

   **    his menus and tools back when OnUIDeactivate is called.

   */

   ServerDoc_RemoveFrameLevelTools(lpServerDoc);

#endif

   OLEDBG_BEGIN2("IOleInPlaceSite::OnUIDeactivate called\r\n");

   lpIPData->lpSite->lpVtbl->OnUIDeactivate(lpIPData->lpSite, FALSE);

   OLEDBG_END2

   /* Reset to use our normal app's accelerator table */

   g_lpApp->m_hAccelApp = lpServerApp->m_hAccelBaseApp;

   g_lpApp->m_hAccel = lpServerApp->m_hAccelBaseApp;

   g_lpApp->m_hWndAccelTarget = hWndApp;

   OLEDBG_END2

#if !defined( SVR_INSIDEOUT )

   /* OLE2NOTE: an "outside-in" style in-place server would hide its

   **    window here. an "inside-out" style server leaves its window

   **    visible when it is UIDeactivated. it would only hide its

   **    window when InPlaceDeactivated. this app is an "inside-out"

   **    style server. it is recommended for most server to support

   **    inside-out behavior if possible.

   */

   ServerDoc_DoInPlaceHide(lpServerDoc);

#endif // INSIEDOUT

   // release artificial AddRef

   SvrDoc_IPObj_Release(lpThis);

   return NOERROR;

}

// IOleInPlaceObject::SetObjectRects method

STDMETHODIMP SvrDoc_IPObj_SetObjectRects(

      LPOLEINPLACEOBJECT  lpThis,

      LPCRECT             lprcPosRect,

      LPCRECT             lprcClipRect

)

{

   LPSERVERDOC  lpServerDoc =

               ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;

   LPINPLACEDATA lpIPData = lpServerDoc->m_lpIPData;

   LPLINELIST   lpLL = OutlineDoc_GetLineList((LPOUTLINEDOC)lpServerDoc);

   // artificial AddRef in case object is deleted during call

   SvrDoc_IPObj_AddRef(lpThis);

   OLEDBG_BEGIN2("SvrDoc_IPObj_SetObjectRects\r\n")

#if defined( _DEBUG )

   OleDbgOutRect3("SvrDoc_IPObj_SetObjectRects (PosRect)",

         (LPRECT)lprcPosRect);

   OleDbgOutRect3("SvrDoc_IPObj_SetObjectRects (ClipRect)",

         (LPRECT)lprcClipRect);

#endif

   // save the current PosRect and ClipRect

   lpIPData->rcPosRect = *lprcPosRect;

   lpIPData->rcClipRect = *lprcClipRect;

   if (! lpServerDoc->m_fUIActive) // hatch and adornaments must not be drawn

      lprcClipRect = lprcPosRect;

   ServerDoc_ResizeInPlaceWindow(

         lpServerDoc, (LPRECT)lprcPosRect, (LPRECT)lprcClipRect);

   OLEDBG_END2

   // release artificial AddRef

   SvrDoc_IPObj_Release(lpThis);

   return NOERROR;

}

// IOleInPlaceObject::ReactivateAndUndo method

STDMETHODIMP SvrDoc_IPObj_ReactivateAndUndo(LPOLEINPLACEOBJECT lpThis)

{

   OLEDBG_BEGIN2("SvrDoc_IPObj_ReactivateAndUndo\r\n")

   // We do not support support UNDO.

   /* REVIEW: for debugging purposes it would be useful to give a

   **    message box indicating that this method has been called.

   */

   OLEDBG_END2

   return NOERROR;

}

/*************************************************************************

** ServerDoc::IOleInPlaceActiveObject interface implementation

*************************************************************************/

// IOleInPlaceActiveObject::QueryInterface method

STDMETHODIMP SvrDoc_IPActiveObj_QueryInterface(

      LPOLEINPLACEACTIVEOBJECT    lpThis,

      REFIID                      riid,

      LPVOID FAR *                lplpvObj

)

{

   SCODE sc = E_NOINTERFACE;

   LPSERVERDOC lpServerDoc =

         ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;

   /* The container should not be able to access the other interfaces

   ** of our object by doing QI on this interface.

   */

   *lplpvObj = NULL;

   if (IsEqualIID(riid, &IID_IUnknown) ||

      IsEqualIID(riid, &IID_IOleWindow) ||

      IsEqualIID(riid, &IID_IOleInPlaceActiveObject)) {

      OleDbgOut4("OleDoc_QueryInterface: IOleInPlaceActiveObject* RETURNED\r\n");

      *lplpvObj = lpThis;

      OleDoc_AddRef((LPOLEDOC)lpServerDoc);

      sc = NOERROR;

   }

   OleDbgQueryInterfaceMethod(*lplpvObj);

   return ResultFromScode(sc);

}

// IOleInPlaceActiveObject::AddRef method

STDMETHODIMP_(ULONG) SvrDoc_IPActiveObj_AddRef(

      LPOLEINPLACEACTIVEOBJECT lpThis

)

{

   LPSERVERDOC lpServerDoc =

         ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;

   OleDbgAddRefMethod(lpThis, "IOleInPlaceActiveObject");

   return OleDoc_AddRef((LPOLEDOC)lpServerDoc);

}

// IOleInPlaceActiveObject::Release method

STDMETHODIMP_(ULONG) SvrDoc_IPActiveObj_Release(

      LPOLEINPLACEACTIVEOBJECT lpThis

)

{

   LPSERVERDOC lpServerDoc =

         ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;

   OleDbgReleaseMethod(lpThis, "IOleInPlaceActiveObject");

   return OleDoc_Release((LPOLEDOC)lpServerDoc);

}

// IOleInPlaceActiveObject::GetWindow method

STDMETHODIMP SvrDoc_IPActiveObj_GetWindow(

      LPOLEINPLACEACTIVEOBJECT    lpThis,

      HWND FAR*                   lphwnd

)

{

   LPSERVERDOC lpServerDoc =

         ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;

   OLEDBG_BEGIN2("SvrDoc_IPActiveObj_GetWindow\r\n")

   *lphwnd = ((LPOUTLINEDOC)lpServerDoc)->m_hWndDoc;

   OLEDBG_END2

   return NOERROR;

}

// IOleInPlaceActiveObject::ContextSensitiveHelp method

STDMETHODIMP SvrDoc_IPActiveObj_ContextSensitiveHelp(

      LPOLEINPLACEACTIVEOBJECT    lpThis,

      BOOL                        fEnterMode

)

{

   LPSERVERDOC lpServerDoc =

         ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;

   OleDbgOut2("SvrDoc_IPActiveObj_ContextSensitiveHelp\r\n");

   /* OLE2NOTE: see context sensitive help technote (CSHELP.DOC)

   **    This method is called when F1 is pressed when a menu item is

   **    selected. this tells the in-place server application to give

   **    help rather than execute the next menu command. at a minimum,

   **    even if the in-place server application does not implement a

   **    help system, it should NOT execute the next command when

   **    fEnable==TRUE. We set the active object's m_fMenuMode flag here.

   **    later, in WM_COMMAND processing in the DocWndProc, if this

   **    flag is set then the command is NOT executed (and help could

   **    be given if we had a help system....but we don't.)

   */

   lpServerDoc->m_fMenuHelpMode = fEnterMode;

#if !defined( HACK )

   ((LPOLEDOC)lpServerDoc)->m_fCSHelpMode = fEnterMode;

#endif

   return NOERROR;

}

// IOleInPlaceActiveObject::TranslateAccelerator method

STDMETHODIMP SvrDoc_IPActiveObj_TranslateAccelerator(

      LPOLEINPLACEACTIVEOBJECT    lpThis,

      LPMSG                       lpmsg

)

{

   // This will never be called because this server is implemented as an EXE

   return NOERROR;

}

// IOleInPlaceActiveObject::OnFrameWindowActivate method

STDMETHODIMP SvrDoc_IPActiveObj_OnFrameWindowActivate(

      LPOLEINPLACEACTIVEOBJECT    lpThis,

      BOOL                        fActivate

)

{

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)

         ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;

   HWND hWndDoc = OutlineDoc_GetWindow(lpOutlineDoc);

#if defined( _DEBUG )

   if (fActivate)

      OleDbgOut2("SvrDoc_IPActiveObj_OnFrameWindowActivate(TRUE)\r\n");

   else

      OleDbgOut2("SvrDoc_IPActiveObj_OnFrameWindowActivate(FALSE)\r\n");

#endif  // _DEBUG

   /* OLE2NOTE: this is a notification of the container application's

   **    WM_ACTIVATEAPP status. some applications may find this

   **    important. we need to update the enable/disable status of our

   **    tool bar buttons.

   */

   // OLE2NOTE: We can't call OutlineDoc_UpdateFrameToolButtons

   //           right away which

   //           would generate some OLE calls and eventually

   //           WM_ACTIVATEAPP and a loop was formed. Therefore, we

   //           should delay the frame tool initialization until

   //           WM_ACTIVATEAPP is finished by posting a message

   //           to ourselves.

   /* Update enable/disable state of buttons in toolbar */

   if (fActivate)

      PostMessage(hWndDoc, WM_U_INITFRAMETOOLS, 0, 0L);

   return NOERROR;

}

// IOleInPlaceActiveObject::OnDocWindowActivate method

STDMETHODIMP SvrDoc_IPActiveObj_OnDocWindowActivate(

      LPOLEINPLACEACTIVEOBJECT    lpThis,

      BOOL                        fActivate

)

{

   LPSERVERDOC     lpServerDoc =

                  ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;

   LPINPLACEDATA   lpIPData = lpServerDoc->m_lpIPData;

#if defined( _DEBUG )

   if (fActivate)

      OleDbgOut2("SvrDoc_IPActiveObj_OnDocWindowActivate(TRUE)\r\n");

   else

      OleDbgOut2("SvrDoc_IPActiveObj_OnDocWindowActivate(FALSE)\r\n");

#endif

   if (fActivate) {

      ServerDoc_AddFrameLevelUI(lpServerDoc);

   }

   else {

#if defined( USE_FRAMETOOLS )

      /* OLE2NOTE: we must NOT call IOleInPlaceFrame::SetBorderSpace(NULL)

      **    or SetMenu(NULL) here. we should simply hide our tools.

      */

      ServerDoc_RemoveFrameLevelTools(lpServerDoc);

#endif

   }

   OLEDBG_END2

   return NOERROR;

}

// IOleInPlaceActiveObject::ResizeBorder method

STDMETHODIMP SvrDoc_IPActiveObj_ResizeBorder(

      LPOLEINPLACEACTIVEOBJECT    lpThis,

      LPCRECT                     lprectBorder,

      LPOLEINPLACEUIWINDOW        lpIPUiWnd,

      BOOL                        fFrameWindow

)

{

   LPSERVERDOC lpServerDoc =

               ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;

   OLEDBG_BEGIN2("SvrDoc_IPActiveObj_ResizeBorder\r\n")

#if defined( USE_FRAMETOOLS )

   if (fFrameWindow) {

      FrameTools_NegotiateForSpaceAndShow(

            lpOutlineDoc->m_lpFrameTools,

            (LPRECT)lprectBorder,

            (LPOLEINPLACEFRAME)lpIPUiWnd

      );

   }

#endif

   OLEDBG_END2

   return NOERROR;

}

// IOleInPlaceActiveObject::EnableModeless method

STDMETHODIMP SvrDoc_IPActiveObj_EnableModeless(

      LPOLEINPLACEACTIVEOBJECT    lpThis,

      BOOL                        fEnable

)

{

#if defined( USE_FRAMETOOLS )

   LPSERVERDOC lpServerDoc =

            ((struct CDocOleObjectImpl FAR*)lpThis)->lpServerDoc;

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;

   LPFRAMETOOLS lptb;

   /* OLE2NOTE: we must enable/disable mouse and keyboard input to our

   **    floating tool palette

   */

   if (lpOutlineDoc) {

      lptb = lpOutlineDoc->m_lpFrameTools;

      if (lptb)

         FrameTools_EnableWindow(lptb, fEnable);

   }

#endif  // USE_FRAMETOOLS

#if defined( _DEBUG )

   if (fEnable)

      OleDbgOut2("SvrDoc_IPActiveObj_EnableModeless(TRUE)\r\n");

   else

      OleDbgOut2("SvrDoc_IPActiveObj_EnableModeless(FALSE)\r\n");

#endif  // _DEBUG

   /* OLE2NOTE: this method is called when the top-level, in-place

   **    container puts up a modal dialog. it tells the UIActive

   **    object to disable it modeless dialogs for the duration that

   **    the container is displaying a modal dialog.

   **

   **    ISVROTL does not use any modeless dialogs, thus we can

   **    ignore this method.

   */

   return NOERROR;

}

/*************************************************************************

** Support Functions

*************************************************************************/

HRESULT ServerDoc_DoInPlaceActivate(

      LPSERVERDOC     lpServerDoc,

      LONG            lVerb,

      LPMSG           lpmsg,

      LPOLECLIENTSITE lpActiveSite

)

{

   LPOUTLINEAPP            lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   LPSERVERAPP             lpServerApp = (LPSERVERAPP)g_lpApp;

   LPOLEAPP                lpOleApp = (LPOLEAPP)g_lpApp;

   SCODE                   sc = E_FAIL;

   RECT                    rcPos;

   RECT                    rcClip;

   LPINPLACEDATA           lpIPData = lpServerDoc->m_lpIPData;

   LPOUTLINEDOC            lpOutlineDoc=(LPOUTLINEDOC)lpServerDoc;

   HWND                    hWndDoc = lpOutlineDoc->m_hWndDoc;

   HWND                    hWndHatch = lpServerDoc->m_hWndHatch;

   HRESULT                 hrErr;

   LPLINELIST              lpLL=(LPLINELIST)&lpOutlineDoc->m_LineList;

   LPOLEINPLACESITE    lpIPSite = NULL;

   /* OLE2NOTE: lpActiveSite should be used only for InPlace PLAYing.

   **    This app does not do inplace PLAYing, so it never uses

   **    lpActiveSite.

   */

   /* InPlace activation can only be done if the ClientSite is non-NULL. */

   if (! lpServerDoc->m_lpOleClientSite)

      return NOERROR;

   if (! lpServerDoc->m_fInPlaceActive) {

      // if the object is in open mode then we do not want to do inplace

      // activation.

      if (IsWindowVisible(lpOutlineDoc->m_hWndDoc))

      {

         return NOERROR;

      }

      lpIPSite = (LPOLEINPLACESITE)OleStdQueryInterface(

            (LPUNKNOWN)lpServerDoc->m_lpOleClientSite,

            &IID_IOleInPlaceSite

      );

      if (! lpIPSite)

         goto errActivate;

      OLEDBG_BEGIN2("IOleInPlaceSite::CanInPlaceActivate called\r\n");

      hrErr = lpIPSite->lpVtbl->CanInPlaceActivate(lpIPSite);

      OLEDBG_END2

      if (hrErr != NOERROR)

         goto errActivate;

      lpServerDoc->m_fInPlaceActive = TRUE;

      OLEDBG_BEGIN2("IOleInPlaceSite::OnInPlaceActivate called\r\n");

      hrErr = lpIPSite->lpVtbl->OnInPlaceActivate(lpIPSite);

      OLEDBG_END2

      if (hrErr != NOERROR)

         goto errActivate;

      if (! ServerDoc_AllocInPlaceData(lpServerDoc)) {

         sc = E_OUTOFMEMORY;

         OLEDBG_BEGIN2("IOleInPlaceSite::OnInPlaceDeactivate called\r\n");

         lpIPSite->lpVtbl->OnInPlaceDeactivate(lpIPSite);

         OLEDBG_END2

         goto errActivate;

      }

      (lpIPData = lpServerDoc->m_lpIPData)->lpSite = lpIPSite;

      goto InPlaceActive;

   errActivate:

      lpServerDoc->m_fInPlaceActive = FALSE;

      if (lpIPSite)

         OleStdRelease((LPUNKNOWN)lpIPSite);

      return ResultFromScode(sc);

   }

InPlaceActive:

   if (! lpServerDoc->m_fInPlaceVisible) {

      lpServerDoc->m_fInPlaceVisible = TRUE;

      OLEDBG_BEGIN2("IOleInPlaceSite::GetWindow called\r\n");

      hrErr = lpIPData->lpSite->lpVtbl->GetWindow(

               lpIPData->lpSite, &lpServerDoc->m_hWndParent);

      OLEDBG_END2

      if (hrErr != NOERROR) {

         sc = GetScode(hrErr);

         goto errRtn;

      }

      if (! lpServerDoc->m_hWndParent)

         goto errRtn;

      /* OLE2NOTE: The server should fill in the "cb" field so that the

      **    container can tell what size structure the server is

      **    expecting. this enables this structure to be easily extended

      **    in future releases of OLE. the container should check this

      **    field so that it doesn't try to use fields that do not exist

      **    since the server may be using an old structure definition.

      */

      _fmemset(

         (LPOLEINPLACEFRAMEINFO)&lpIPData->frameInfo,

         0,

         sizeof(OLEINPLACEFRAMEINFO)

      );

      lpIPData->frameInfo.cb = sizeof(OLEINPLACEFRAMEINFO);

      OLEDBG_BEGIN2("IOleInPlaceSite::GetWindowContext called\r\n");

      hrErr = lpIPData->lpSite->lpVtbl->GetWindowContext(lpIPData->lpSite,

               (LPOLEINPLACEFRAME FAR*) &lpIPData->lpFrame,

               (LPOLEINPLACEUIWINDOW FAR*)&lpIPData->lpDoc,

               (LPRECT)&rcPos,

               (LPRECT)&rcClip,

               (LPOLEINPLACEFRAMEINFO)&lpIPData->frameInfo);

      OLEDBG_END2

      if (hrErr != NOERROR) {

         sc = GetScode(hrErr);

         goto errRtn;

      }

      lpServerApp->m_lpIPData = lpIPData;

      ShowWindow(hWndDoc, SW_HIDE);   // make sure we are hidden

      /* OLE2NOTE: reparent in-place server document's window to the

      **    special in-place hatch border window. set the in-place site's

      **    window as the parent of the hatch window. position the

      **    in-place and hatch border windows using the PosRect and

      **    ClipRect.

      **    it is important to properly parent and position the in-place

      **    server window BEFORE calling IOleInPlaceFrame::SetMenu and

      **    SetBorderSpace.

      */

      ShowWindow(lpServerDoc->m_hWndHatch, SW_SHOW);

      // make sure App busy/blocked dialogs are parented to our

      // new hWndFrame

      OleStdMsgFilter_SetParentWindow(

         lpOleApp->m_lpMsgFilter,lpIPData->frameInfo.hwndFrame);

      SetParent(lpServerDoc->m_hWndHatch, lpServerDoc->m_hWndParent);

      SetParent(hWndDoc, lpServerDoc->m_hWndHatch);

#if defined( _DEBUG )

      OleDbgOutRect3("IOleInPlaceSite::GetWindowContext (PosRect)",

            (LPRECT)&rcPos);

      OleDbgOutRect3("IOleInPlaceSite::GetWindowContext (ClipRect)",

            (LPRECT)&rcClip);

#endif

      // save the current PosRect and ClipRect

      lpIPData->rcPosRect  = rcPos;

      lpIPData->rcClipRect = rcClip;

      /* OLE2NOTE: build the shared menu for the in-place container and

      **    the server.

      */

      if (ServerDoc_AssembleMenus (lpServerDoc) != NOERROR)

         goto errRtn;

#if defined( SVR_INSIDEOUT )

      if (lVerb == OLEIVERB_INPLACEACTIVATE) {

         // Clip the hatch window to the size of pos rect so, that

         // hatch and object adornments  will not be visible.

         ServerDoc_ResizeInPlaceWindow(lpServerDoc,

            (LPRECT)&(lpServerDoc->m_lpIPData->rcPosRect),

            (LPRECT)&(lpServerDoc->m_lpIPData->rcPosRect)

         );

      }

#endif  // SVR_INSIDEOUT

   }

#if defined( SVR_INSIDEOUT )

   // OLE2NOTE: if verb is OLEIVERB_INPLACEACTIVATE we do NOT want to

   // show our UI

   if (lVerb == OLEIVERB_INPLACEACTIVATE) {

      return NOERROR;

   }

#endif  // SVR_INSIDEOUT

   if (! lpServerDoc->m_fUIActive) {

      lpServerDoc->m_fUIActive = TRUE;

      OLEDBG_BEGIN2("IOleInPlaceSite::OnUIActivate called\r\n");

      hrErr = lpIPData->lpSite->lpVtbl->OnUIActivate(lpIPData->lpSite);

      OLEDBG_END2

      if (hrErr != NOERROR) {

         lpServerDoc->m_fUIActive = FALSE;

         goto errRtn;

      }

      SetFocus(hWndDoc);

      // Show the object adornments and hacth border around them.

      ServerDoc_ResizeInPlaceWindow(lpServerDoc,

               (LPRECT)&lpIPData->rcPosRect,

               (LPRECT)&lpIPData->rcClipRect

      );

      /* OLE2NOTE: IOleInPlaceFrame::SetActiveObject must be called BEFORE

      **    IOleInPlaceFrame::SetMenu.

      */

      OLEDBG_BEGIN2("IOleInPlaceSite::SetActiveObject called\r\n");

      lpIPData->lpFrame->lpVtbl->SetActiveObject(

         lpIPData->lpFrame,

         (LPOLEINPLACEACTIVEOBJECT) &lpServerDoc->m_OleInPlaceActiveObject,

         (LPOLESTR)g_szIPObjectTitle

      );

      OLEDBG_END2

      /* OLE2NOTE: If the container wants to give ownership of the

      **    palette then he would sendmessage WM_QUEYNEWPALETTE to

      **    the object window proc, before returning from

      **    IOleInPlaceFrame::SetActiveObject. Those objects which

      **    want to be edited inplace only if they have the ownership of

      **    the palette, can check at this point in the code whether

      **    they got WM_QUERYNEWPALETTE or not. If they didn't get

      **    the message, then they can inplace deactivate and do open

      **    editing instead.

      */

      if (lpIPData->lpDoc) {

         lpIPData->lpDoc->lpVtbl->SetActiveObject(

            lpIPData->lpDoc,

            (LPOLEINPLACEACTIVEOBJECT)&lpServerDoc->m_OleInPlaceActiveObject,

            (LPOLESTR)g_szIPObjectTitle

         );

      }

      /* OLE2NOTE: install the menu and frame-level tools on the in-place

      **    frame.

      */

      ServerDoc_AddFrameLevelUI(lpServerDoc);

   }

   return NOERROR;

errRtn:

   ServerDoc_DoInPlaceDeactivate(lpServerDoc);

   return ResultFromScode(sc);

}

HRESULT ServerDoc_DoInPlaceDeactivate(LPSERVERDOC lpServerDoc)

{

   LPINPLACEDATA   lpIPData = lpServerDoc->m_lpIPData;

   LPOUTLINEDOC    lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;

   if (!lpServerDoc->m_fInPlaceActive)

      return S_OK;

   lpServerDoc->m_fInPlaceActive = FALSE;

   SvrDoc_IPObj_UIDeactivate(

         (LPOLEINPLACEOBJECT)&lpServerDoc->m_OleInPlaceObject);

   /* OLE2NOTE: an inside-out style in-place server will

   **    NOT hide its window in UIDeactive (an outside-in

   **    style object will hide its window in UIDeactivate).

   **    thus, an inside-out server must explicitly hide

   **    its window in InPlaceDeactivate. it is ALSO important for an

   **    outside-in style object to call ServerDoc_DoInPlaceHide here

   **    BEFORE freeing the InPlaceData structure. it will be common

   **    for in-place containers to call IOleInPlaceObject::

   **    InPlaceDeactivate in their IOleInPlaceSite::OnUIDeactiate

   **    implementation.

   */

   ServerDoc_DoInPlaceHide(lpServerDoc);

   OLEDBG_BEGIN2("IOleInPlaceSite::OnInPlaceDeactivate called\r\n");

   lpIPData->lpSite->lpVtbl->OnInPlaceDeactivate(lpIPData->lpSite);

   OLEDBG_END2

   OleStdRelease((LPUNKNOWN)lpIPData->lpSite);

   lpIPData->lpSite = NULL;

   ServerDoc_FreeInPlaceData(lpServerDoc);

   return NOERROR;

}

HRESULT ServerDoc_DoInPlaceHide(LPSERVERDOC lpServerDoc)

{

   LPINPLACEDATA   lpIPData = lpServerDoc->m_lpIPData;

   LPOUTLINEDOC    lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;

   LPOLEAPP        lpOleApp = (LPOLEAPP)g_lpApp;

   HWND            hWndApp = OutlineApp_GetWindow(g_lpApp);

   if (! lpServerDoc->m_fInPlaceVisible)

      return NOERROR;

   // Set the parent back to server app's window

   OleDoc_HideWindow((LPOLEDOC)lpServerDoc, FALSE /* fShutdown */);

   /* we need to enusure that our window is set to normal 100% zoom.

   **    if the window is next shown in open mode it should start out

   **    at normal zoom factor. our window may have been set to a

   **    different zoom factor while it was in-place active.

   */

   OutlineDoc_SetCurrentZoomCommand(lpOutlineDoc,IDM_V_ZOOM_100);

   lpServerDoc->m_fInPlaceVisible = FALSE;

   lpServerDoc->m_hWndParent = hWndApp;

   SetParent(

      lpOutlineDoc->m_hWndDoc,

      lpServerDoc->m_hWndParent

   );

   // make sure App busy/blocked dialogs are parented to our own hWndApp

   OleStdMsgFilter_SetParentWindow(lpOleApp->m_lpMsgFilter, hWndApp);

   // Hide the in-place hatch border window.

   ShowWindow(lpServerDoc->m_hWndHatch, SW_HIDE);

   ServerDoc_DisassembleMenus(lpServerDoc);

   /* we no longer need the IOleInPlaceFrame* or the doc's

   **    IOleInPlaceWindow* interface pointers.

   */

   if (lpIPData->lpDoc) {

      OleStdRelease((LPUNKNOWN)lpIPData->lpDoc);

      lpIPData->lpDoc = NULL;

   }

   if (lpIPData->lpFrame) {

      OleStdRelease((LPUNKNOWN)lpIPData->lpFrame);

      lpIPData->lpFrame = NULL;

   }

   ((LPSERVERAPP)g_lpApp)->m_lpIPData = NULL;

   return NOERROR;

}

BOOL ServerDoc_AllocInPlaceData(LPSERVERDOC lpServerDoc)

{

   LPINPLACEDATA   lpIPData;

   if (!(lpIPData = (LPINPLACEDATA) New(sizeof(INPLACEDATA))))

      return FALSE;

   lpIPData->lpFrame       = NULL;

   lpIPData->lpDoc         = NULL;

   lpIPData->lpSite        = NULL;

   lpIPData->hOlemenu      = NULL;

   lpIPData->hMenuShared   = NULL;

   lpServerDoc->m_lpIPData = lpIPData;

   return TRUE;

}

void ServerDoc_FreeInPlaceData(LPSERVERDOC lpServerDoc)

{

   Delete(lpServerDoc->m_lpIPData);

   lpServerDoc->m_lpIPData = NULL;

}

HRESULT ServerDoc_AssembleMenus(LPSERVERDOC lpServerDoc)

{

   HMENU           hMenuShared;

   LONG FAR*       lpWidths;

   UINT            uPosition;

   UINT            uPositionStart;

   LPSERVERAPP     lpServerApp = (LPSERVERAPP) g_lpApp;

   LPINPLACEDATA   lpIPData = lpServerDoc->m_lpIPData;

   HRESULT         hresult;

   BOOL            fNoError = TRUE;

   lpWidths = lpIPData->menuGroupWidths.width;

   hMenuShared = CreateMenu();

   if (hMenuShared &&

      (hresult = lpIPData->lpFrame->lpVtbl->InsertMenus(

         lpIPData->lpFrame, hMenuShared,

         &lpIPData->menuGroupWidths)) == NOERROR) {

      /* Insert EDIT group menus */

      uPosition = (UINT)lpWidths[0]; /* # of menus in the FILE group */

      uPositionStart = uPosition;

      fNoError &= InsertMenu(

            hMenuShared,

            (UINT)uPosition,

            (UINT)(MF_BYPOSITION | MF_POPUP),

            (UINT)lpServerApp->m_hMenuEdit,

            (LPCSTR)"&Edit"

      );

      uPosition++;

      lpWidths[1] = uPosition - uPositionStart;

      /* Insert OBJECT group menus */

      uPosition += (UINT)lpWidths[2];

      uPositionStart = uPosition;

      fNoError &= InsertMenu(

            hMenuShared,

            (UINT)uPosition,

            (UINT)(MF_BYPOSITION | MF_POPUP),

            (UINT)lpServerApp->m_hMenuLine,

            (LPCSTR)"&Line"

      );

      uPosition++;

      fNoError &= InsertMenu(

            hMenuShared,

            (UINT)uPosition,

            (UINT)(MF_BYPOSITION | MF_POPUP),

            (UINT)lpServerApp->m_hMenuName,

            (LPCSTR)"&Name"

      );

      uPosition++;

      fNoError &= InsertMenu(

            hMenuShared,

            (UINT)uPosition,

            (UINT)(MF_BYPOSITION | MF_POPUP),

            (UINT)lpServerApp->m_hMenuOptions,

            (LPCSTR)"&Options"

      );

      uPosition++;

      fNoError &= InsertMenu(

            hMenuShared,

            (UINT)uPosition,

            (UINT)(MF_BYPOSITION | MF_POPUP),

            (UINT)lpServerApp->m_hMenuDebug,

            (LPCSTR)"DbgI&Svr"

      );

      uPosition++;

      lpWidths[3] = uPosition - uPositionStart;

      /* Insert HELP group menus */

      uPosition += (UINT) lpWidths[4]; /* # of menus in WINDOW group */

      uPositionStart = uPosition;

      fNoError &= InsertMenu(

            hMenuShared,

            (UINT)uPosition,

            (UINT)(MF_BYPOSITION | MF_POPUP),

            (UINT)lpServerApp->m_hMenuHelp,

            (LPCSTR)"&Help"

      );

      uPosition++;

      lpWidths[5] = uPosition - uPositionStart;

      OleDbgAssert(fNoError == TRUE);

   } else {

      /* In-place container does not allow us to add menus to the

      **    frame.

      ** OLE2NOTE: even when the in-place container does NOT allow

      **    the building of a merged menu bar, it is CRITICAL that

      **    the in-place server still call OleCreateMenuDescriptor

      **    passing NULL for hMenuShared.

      */

      if (hMenuShared) {

         DestroyMenu(hMenuShared);

         hMenuShared = NULL;

      }

   }

   lpIPData->hMenuShared = hMenuShared;

   if (!(lpIPData->hOlemenu = OleCreateMenuDescriptor(hMenuShared,

                                 &lpIPData->menuGroupWidths)))

    {

      return ResultFromScode(E_OUTOFMEMORY);

    }

   return NOERROR;

}

void ServerDoc_DisassembleMenus(LPSERVERDOC lpServerDoc)

{

   UINT             uCount;

   UINT            uGroup;

   UINT            uDeleteAt;

   LPINPLACEDATA   lpIPData = lpServerDoc->m_lpIPData;

   LONG FAR*       lpWidths = lpIPData->menuGroupWidths.width;

   BOOL            fNoError = TRUE;

   /* OLE2NOTE: even when hMenuShared is NULL (ie. the server has no

   **    Menu), there is still an hOleMenu created that must be destroyed.

   */

   if (lpIPData->hOlemenu) {

      OleDestroyMenuDescriptor (lpIPData->hOlemenu);

      lpIPData->hOlemenu = NULL;

   }

   if (! lpIPData->hMenuShared)

      return;     // no menus to be destroyed

   /* Remove server group menus. */

   uDeleteAt = 0;

   for (uGroup = 0; uGroup < 6; uGroup++) {

      uDeleteAt += (UINT)lpWidths[uGroup++];

      for (uCount = 0; uCount < (UINT)lpWidths[uGroup]; uCount++)

         fNoError &= RemoveMenu(lpIPData->hMenuShared, uDeleteAt,

                        MF_BYPOSITION);

   }

   /* Remove container group menus */

   fNoError &= (lpIPData->lpFrame->lpVtbl->RemoveMenus(

      lpIPData->lpFrame,

      lpIPData->hMenuShared) == NOERROR);

   OleDbgAssert(fNoError == TRUE);

   DestroyMenu(lpIPData->hMenuShared);

   lpIPData->hMenuShared = NULL;

}

/* ServerDoc_UpdateInPlaceWindowOnExtentChange

** -------------------------------------------

**    The size of the in-place window needs to be changed.

**    calculate the size required in Client coordinates (taking into

**    account the current scale factor imposed by the in-place

**    container) and ask our in-place container to allow us to resize.

**    our container must call us back via

**    IOleInPlaceObject::SetObjectRects for the actual sizing to take

**    place.

**

**    OLE2NOTE: the rectangle that we ask for from our in-place

**    container is always the rectangle required for the object display

**    itself (in our case the size of the LineList contents). it does

**    NOT include the space we require for object frame adornments.

*/

void ServerDoc_UpdateInPlaceWindowOnExtentChange(LPSERVERDOC lpServerDoc)

{

   SIZEL       sizelHim;

   SIZEL       sizelPix;

   RECT        rcPosRect;

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;

   LPLINELIST  lpLL=(LPLINELIST)&lpOutlineDoc->m_LineList;

   HWND        hWndLL = lpLL->m_hWndListBox;

   LPSCALEFACTOR lpscale = (LPSCALEFACTOR)&lpOutlineDoc->m_scale;

   if (!lpServerDoc->m_fInPlaceActive)

      return;

   OleDoc_GetExtent((LPOLEDOC)lpServerDoc, (LPSIZEL)&sizelHim);

   // apply current scale factor

   sizelHim.cx = sizelHim.cx * lpscale->dwSxN / lpscale->dwSxD;

   sizelHim.cy = sizelHim.cy * lpscale->dwSxN / lpscale->dwSxD;

   XformSizeInHimetricToPixels(NULL, (LPSIZEL)&sizelHim, (LPSIZEL)&sizelPix);

   GetWindowRect(hWndLL, (LPRECT)&rcPosRect);

   ScreenToClient(lpServerDoc->m_hWndParent, (POINT FAR *)&rcPosRect);

   rcPosRect.right = rcPosRect.left + (int) sizelPix.cx;

   rcPosRect.bottom = rcPosRect.top + (int) sizelPix.cy;

   OleDbgOutRect3("ServerDoc_UpdateInPlaceWindowOnExtentChange: (PosRect)", (LPRECT)&rcPosRect);

   OLEDBG_BEGIN2("IOleInPlaceSite::OnPosRectChange called\r\n");

   lpServerDoc->m_lpIPData->lpSite->lpVtbl->OnPosRectChange(

         lpServerDoc->m_lpIPData->lpSite,

         (LPRECT) &rcPosRect

   );

   OLEDBG_END2

}

/* ServerDoc_CalcInPlaceWindowPos

 * ------------------------------

 *

 *  Move (and re-scale) the ServerDoc to the specified rectangle.

 *

 *  Parameters:

 *      lprcListBox - rect in client coordinate in which the listbox will fit

 *      lprcDoc     - corresponding size of the Doc in client coordinate

 *

 */

void ServerDoc_CalcInPlaceWindowPos(

      LPSERVERDOC         lpServerDoc,

      LPRECT              lprcListBox,

      LPRECT              lprcDoc,

      LPSCALEFACTOR       lpscale

)

{

   SIZEL sizelHim;

   SIZEL sizelPix;

   LPLINELIST lpLL;

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;

   LPHEADING lphead;

   if (!lpServerDoc || !lprcListBox || !lprcDoc)

      return;

   lphead = (LPHEADING)&lpOutlineDoc->m_heading;

   lpLL = OutlineDoc_GetLineList(lpOutlineDoc);

   OleDoc_GetExtent((LPOLEDOC)lpServerDoc, (LPSIZEL)&sizelHim);

   XformSizeInHimetricToPixels(NULL, &sizelHim, &sizelPix);

   if (sizelHim.cx == 0 || sizelPix.cx == 0) {

      lpscale->dwSxN = 1;

      lpscale->dwSxD = 1;

   } else {

      lpscale->dwSxN = lprcListBox->right - lprcListBox->left;

      lpscale->dwSxD = sizelPix.cx;

   }

   if (sizelHim.cy == 0 || sizelPix.cy == 0) {

      lpscale->dwSyN = 1;

      lpscale->dwSyD = 1;

   } else {

      lpscale->dwSyN = lprcListBox->bottom - lprcListBox->top;

      lpscale->dwSyD = sizelPix.cy;

   }

   lprcDoc->left = lprcListBox->left - Heading_RH_GetWidth(lphead,lpscale);

   lprcDoc->right = lprcListBox->right;

   lprcDoc->top = lprcListBox->top - Heading_CH_GetHeight(lphead,lpscale);

   lprcDoc->bottom = lprcListBox->bottom;

}

/* ServerDoc_ResizeInPlaceWindow

** -----------------------------

**    Actually resize the in-place ServerDoc windows according to the

**    PosRect and ClipRect allowed by our in-place container.

**

**    OLE2NOTE: the PosRect rectangle that our in-place container tells

**    us is always the rectangle required for the object display

**    itself (in our case the size of the LineList contents). it does

**    NOT include the space we require for object frame adornments.

*/

void ServerDoc_ResizeInPlaceWindow(

      LPSERVERDOC         lpServerDoc,

      LPCRECT             lprcPosRect,

      LPCRECT             lprcClipRect

)

{

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;

   LPLINELIST   lpLL = (LPLINELIST)&lpOutlineDoc->m_LineList;

   SCALEFACTOR  scale;

   RECT         rcDoc;

   POINT        ptOffset;

   /* OLE2NOTE: calculate the space needed for our object frame

   **    adornments. our in-place container tells us the size that our

   **    object should take in window client coordinates

   **    (lprcPosRect). the rectangle cooresponds to the size that our

   **    LineList ListBox should be. our Doc window must the correct

   **    amount larger to accomodate our row/column headings.

   **    then move all windows into position.

   */

   ServerDoc_CalcInPlaceWindowPos(

         lpServerDoc,

         (LPRECT)lprcPosRect,

         (LPRECT)&rcDoc,

         (LPSCALEFACTOR)&scale

   );

   /* OLE2NOTE: we need to honor the lprcClipRect specified by our

   **    in-place container. we must NOT draw outside of the ClipRect.

   **    in order to achieve this, we will size the hatch window to be

   **    exactly the size that should be visible (rcVisRect). the

   **    rcVisRect is defined as the intersection of the full size of

   **    the in-place server window and the lprcClipRect.

   **    the ClipRect could infact clip the HatchRect on the

   **    right/bottom and/or on the top/left. if it is clipped on the

   **    right/bottom then it is sufficient to simply resize the hatch

   **    window. but if the HatchRect is clipped on the top/left then

   **    we must "move" the ServerDoc window (child of HatchWindow) by

   **    the delta that was clipped. the window origin of the

   **    ServerDoc window will then have negative coordinates relative

   **    to its parent HatchWindow.

   */

   SetHatchWindowSize(

         lpServerDoc->m_hWndHatch,

         (LPRECT)&rcDoc,

         (LPRECT)lprcClipRect,

         (LPPOINT)&ptOffset

   );

   // shift Doc window to account for hatch frame being drawn

   OffsetRect((LPRECT)&rcDoc, ptOffset.x, ptOffset.y);

   // move/size/set scale factor of ServerDoc window.

   OutlineDoc_SetScaleFactor(

         lpOutlineDoc, (LPSCALEFACTOR)&scale, (LPRECT)&rcDoc);

   /* reset the horizontal extent of the listbox. this makes

   **    the listbox realize that a scroll bar is not needed.

   */

   SendMessage(

         lpLL->m_hWndListBox,

         LB_SETHORIZONTALEXTENT,

         (int) 0,

         0L

   );

   SendMessage(

         lpLL->m_hWndListBox,

         LB_SETHORIZONTALEXTENT,

         (int) (lprcPosRect->right - lprcPosRect->left),

         0L

   );

}

/* ServerDoc_SetStatusText

**    Tell the active in-place frame to display a status message.

*/

void ServerDoc_SetStatusText(LPSERVERDOC lpServerDoc, LPOLESTR lpszMessage)

{

   if (lpServerDoc && lpServerDoc->m_fUIActive &&

      lpServerDoc->m_lpIPData != NULL) {

      OLEDBG_BEGIN2("IOleInPlaceFrame::SetStatusText called\r\n")

      lpServerDoc->m_lpIPData->lpFrame->lpVtbl->SetStatusText

            (lpServerDoc->m_lpIPData->lpFrame, lpszMessage);

      OLEDBG_END2

   }

}

/* ServerDoc_GetTopInPlaceFrame

** ----------------------------

**    returns NON-AddRef'ed pointer to Top In-Place Frame interface

*/

LPOLEINPLACEFRAME ServerDoc_GetTopInPlaceFrame(LPSERVERDOC lpServerDoc)

{

   if (lpServerDoc->m_lpIPData)

      return lpServerDoc->m_lpIPData->lpFrame;

   else

      return NULL;

}

void ServerDoc_GetSharedMenuHandles(

      LPSERVERDOC lpServerDoc,

      HMENU FAR*      lphSharedMenu,

      HOLEMENU FAR*   lphOleMenu

)

{

   if (lpServerDoc->m_lpIPData) {

      *lphSharedMenu = lpServerDoc->m_lpIPData->hMenuShared;

      *lphOleMenu = lpServerDoc->m_lpIPData->hOlemenu;

   } else {

      *lphSharedMenu = NULL;

      *lphOleMenu = NULL;

   }

}

void ServerDoc_AddFrameLevelUI(LPSERVERDOC lpServerDoc)

{

   LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   LPSERVERAPP lpServerApp = (LPSERVERAPP)g_lpApp;

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;

   LPOLEINPLACEFRAME lpTopIPFrame=ServerDoc_GetTopInPlaceFrame(lpServerDoc);

   HMENU           hSharedMenu;            // combined obj/cntr menu

   HOLEMENU        hOleMenu;               // returned by OleCreateMenuDesc.

   ServerDoc_GetSharedMenuHandles(

         lpServerDoc,

         &hSharedMenu,

         &hOleMenu

   );

   lpTopIPFrame->lpVtbl->SetMenu(

         lpTopIPFrame,

         hSharedMenu,

         hOleMenu,

         lpOutlineDoc->m_hWndDoc

   );

   // save normal accelerator table

   lpServerApp->m_hAccelBaseApp = lpOutlineApp->m_hAccelApp;

   // install accelerator table for UIActive server (w/ active editor cmds)

   lpOutlineApp->m_hAccel = lpServerApp->m_hAccelIPSvr;

   lpOutlineApp->m_hAccelApp = lpServerApp->m_hAccelIPSvr;

   lpOutlineApp->m_hWndAccelTarget = lpOutlineDoc->m_hWndDoc;

#if defined( USE_FRAMETOOLS )

   ServerDoc_AddFrameLevelTools(lpServerDoc);

   // update toolbar button enable states

   OutlineDoc_UpdateFrameToolButtons(lpOutlineDoc);

#endif

}

void ServerDoc_AddFrameLevelTools(LPSERVERDOC lpServerDoc)

{

   LPOUTLINEAPP    lpOutlineApp = (LPOUTLINEAPP)g_lpApp;

   LPSERVERAPP     lpServerApp = (LPSERVERAPP)g_lpApp;

   LPOUTLINEDOC    lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;

   LPOLEINPLACEFRAME lpTopIPFrame=ServerDoc_GetTopInPlaceFrame(lpServerDoc);

#if defined( USE_FRAMETOOLS )

   HWND            hWndFrame;

   FrameTools_Enable(lpOutlineDoc->m_lpFrameTools, TRUE);

   // if not in-place UI active, add our tools to our own frame.

   if (! lpServerDoc->m_fUIActive) {

      OutlineDoc_AddFrameLevelTools(lpOutlineDoc);

      return;

   }

   if ((hWndFrame = OutlineApp_GetFrameWindow(lpOutlineApp)) == NULL) {

      /* we could NOT get a valid frame window, so POP our tools up. */

      /* OLE2NOTE: since we are poping up our tools, we MUST inform

      **    the top in-place frame window that we need NO tool space

      **    BUT that it should NOT put its own tools up. if we were

      **    to pass NULL instead of (0,0,0,0), then the container

      **    would have the option to leave its own tools up.

      */

      lpTopIPFrame->lpVtbl->SetBorderSpace(

            lpTopIPFrame,

            (LPCBORDERWIDTHS)&g_rectNull

      );

      FrameTools_PopupTools(lpOutlineDoc->m_lpFrameTools);

   } else {

      /* OLE2NOTE: we need to negotiate for space and attach our frame

      **    level tools to the top-level in-place container's frame window.

      */

      FrameTools_AttachToFrame(lpOutlineDoc->m_lpFrameTools, hWndFrame);

      FrameTools_NegotiateForSpaceAndShow(

            lpOutlineDoc->m_lpFrameTools,

            NULL,

            lpTopIPFrame

      );

   }

#else   // ! USE_FRAMETOOLS

   /* OLE2NOTE: if you do NOT use frame tools, you MUST inform the top

   **    in-place frame window so that it can put back its own tools.

   */

   lpTopIPFrame->lpVtbl->SetBorderSpace(lpIPData->lpFrame, NULL);

#endif  // ! USE_FRAMETOOLS

}

#if defined( USE_FRAMETOOLS )

void ServerDoc_RemoveFrameLevelTools(LPSERVERDOC lpServerDoc)

{

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;

   OleDbgAssert(lpOutlineDoc->m_lpFrameTools != NULL);

    // Reparent our tools back to one of our own windows

    FrameTools_AttachToFrame(lpOutlineDoc->m_lpFrameTools,g_lpApp->m_hWndApp);

   FrameTools_Enable(lpOutlineDoc->m_lpFrameTools, FALSE);

}

#endif  // USE_FRAMETOOLS

void ServerDoc_UIActivate (LPSERVERDOC lpServerDoc)

{

   if (lpServerDoc->m_fInPlaceActive && !lpServerDoc->m_fUIActive) {

      ServerDoc_DoInPlaceActivate(lpServerDoc,

            OLEIVERB_UIACTIVATE,

            NULL /*lpmsg*/,

            lpServerDoc->m_lpOleClientSite

      );

      OutlineDoc_ShowWindow((LPOUTLINEDOC)lpServerDoc);

   }

}


SVROUTL.DEF  (OUTLINE Sample)

;;

;;

;;    OLE 2.0 Server Sample Code

;;

;;    svroutl.def

;;

;;    Definition file for svroutl.exe

;;

;;    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

;;

;;

NAME            SvrOutl

DESCRIPTION             'Microsoft OLE 2.0 Server Sample code'

EXETYPE         WINDOWS

STUB            'WINSTUB.EXE'

CODE            PRELOAD MOVEABLE

DATA            PRELOAD MOVEABLE MULTIPLE

HEAPSIZE        4096

;; NOTE: Do not add exports to this file.  Use __export

;; in your function prototype and definition instead.


SVROUTL.H  (OUTLINE Sample)

/*************************************************************************

**

**    OLE 2.0 Server Sample Code

**

**    svroutl.h

**

**    This file contains file contains data structure defintions,

**    function prototypes, constants, etc. used by the OLE 2.0 server

**    app version of the Outline series of sample applications:

**          Outline -- base version of the app (without OLE functionality)

**          SvrOutl -- OLE 2.0 Server sample app

**          CntrOutl -- OLE 2.0 Containter sample app

**

**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

**

*************************************************************************/

#if !defined( _SVROUTL_H_ )

#define _SVROUTL_H_

#ifndef RC_INVOKED

#pragma message ("INCLUDING SVROUTL.H from " __FILE__)

#endif  /* RC_INVOKED */

#include "oleoutl.h"

#include "ansiapi.h"

/* Defines */

// Enable SVROUTL and ISVROTL to emulate each other (TreatAs aka. ActivateAs)

#define SVR_TREATAS     1

// Enable SVROUTL and ISVROTL to convert each other (TreatAs aka. ActivateAs)

#define SVR_CONVERTTO   1

// Enable ISVROTL to operate as in inside-out style in-place object

#define SVR_INSIDEOUT   1

/* Default name used for container of the embedded object. used if

**    container forgets to call IOleObject::SetHostNames

*/

// REVIEW: should load from string resource

#define DEFCONTAINERNAME    "Unknown Document"

/* Default prefix for auto-generated range names. This is used with

**    links to unnamed ranges (pseudo objects).

*/

// REVIEW: should load from string resource

#define DEFRANGENAMEPREFIX  "Range"

// Maximum length of strings accepted through IOleObject::SetHostNames

//      (note: this is rather arbitrary; a better strategy would be to

//             dynamically allocated buffers for these strings.)

#define MAXAPPNAME  80

#define MAXCONTAINERNAME    80

// Menu option in embedding mode

#define IDM_F_UPDATE    1151

/* Types */

/* Codes for CallBack events */

typedef enum tagOLE_NOTIFICATION {

   OLE_ONDATACHANGE,        // 0

   OLE_ONSAVE,              // 1

   OLE_ONRENAME,            // 2

   OLE_ONCLOSE              // 3

} OLE_NOTIFICATION;

/* Codes to indicate mode of storage for an object.

**    Mode of the storage is modified by the IPersistStorage methods:

**      Save, HandsOffStorage, and SaveCompleted.

*/

typedef enum tagSTGMODE {

   STGMODE_NORMAL      = 0,

   STGMODE_NOSCRIBBLE  = 1,

   STGMODE_HANDSOFF    = 2

} STGMODE;

/* Forward type definitions */

typedef struct tagSERVERAPP FAR* LPSERVERAPP;

typedef struct tagSERVERDOC FAR* LPSERVERDOC;

typedef struct tagPSEUDOOBJ FAR* LPPSEUDOOBJ;

typedef struct tagINPLACEDATA {

   OLEMENUGROUPWIDTHS      menuGroupWidths;

   HOLEMENU                hOlemenu;

   HMENU                   hMenuShared;

   LPOLEINPLACESITE        lpSite;

   LPOLEINPLACEUIWINDOW    lpDoc;

   LPOLEINPLACEFRAME       lpFrame;

   OLEINPLACEFRAMEINFO     frameInfo;

   HWND                    hWndFrame;

   BOOL                    fBorderOn;

   RECT                    rcPosRect;

   RECT                    rcClipRect;

} INPLACEDATA, FAR* LPINPLACEDATA;

/*************************************************************************

** class SERVERDOC : OLEDOC

**    SERVERDOC is an extention to the abstract base OLEDOC class.

**    The OLEDOC class defines the fields, methods and interfaces that

**    are common to both server and client implementations. The

**    SERVERDOC class adds the fields, methods and interfaces that are

**    specific to OLE 2.0 Server functionality. There is one instance

**    of SERVERDOC object created per document open in the app. The SDI

**    version of the app supports one SERVERDOC at a time. The MDI

**    version of the app can manage multiple documents at one time.

**    The SERVERDOC class inherits all fields from the OLEDOC class.

**    This inheritance is achieved by including a member variable of

**    type OLEDOC as the first field in the SERVERDOC structure. Thus a

**    pointer to a SERVERDOC object can be cast to be a pointer to a

**    OLEDOC object or an OUTLINEDOC object

*************************************************************************/

typedef struct tagSERVERDOC {

   OLEDOC              m_OleDoc;           // ServerDoc inherits from OleDoc

   ULONG               m_cPseudoObj;       // total count of pseudo obj's

   LPOLECLIENTSITE     m_lpOleClientSite;  // Client associated with the obj

   LPOLEADVISEHOLDER   m_lpOleAdviseHldr;  // helper obj to hold ole advises

   LPDATAADVISEHOLDER  m_lpDataAdviseHldr; // helper obj to hold data advises

   BOOL                m_fNoScribbleMode;  // was IPS::Save called

   BOOL                m_fSaveWithSameAsLoad;  // was IPS::Save called with

                                 // fSameAsLoad==TRUE.

   OLECHAR             m_szContainerApp[MAXAPPNAME];

   OLECHAR             m_szContainerObj[MAXCONTAINERNAME];

   ULONG               m_nNextRangeNo;     // next no. for unnamed range

   LINERANGE           m_lrSrcSelOfCopy;   // src sel if doc created for copy

   BOOL                m_fDataChanged;     // data changed when draw disabled

   BOOL                m_fSizeChanged;     // size changed when draw disabled

   BOOL                m_fSendDataOnStop;  // did data ever change?

#if defined( SVR_TREATAS )

   CLSID               m_clsidTreatAs;     // clsid to pretend to be

   LPOLESTR            m_lpszTreatAsType;  // user type name to pretend to be

#endif  // SVR_TREATAS

#if defined( LATER )

   // REVIEW: is it necessary to register a WildCard Moniker

   DWORD               m_dwWildCardRegROT; // key if wildcard reg'ed in ROT

#endif

#if defined( INPLACE_SVR )

   BOOL                m_fInPlaceActive;

   BOOL                m_fInPlaceVisible;

   BOOL                m_fUIActive;

   HWND                m_hWndParent;

   HWND                m_hWndHatch;

   LPINPLACEDATA       m_lpIPData;

   BOOL                m_fMenuHelpMode;// is F1 pressed in menu, give help

   struct CDocOleInPlaceObjectImpl {

      IOleInPlaceObjectVtbl FAR*  lpVtbl;

      LPSERVERDOC                 lpServerDoc;

      int                         cRef;   // interface specific ref count.

   } m_OleInPlaceObject;

   struct CDocOleInPlaceActiveObjectImpl {

      IOleInPlaceActiveObjectVtbl FAR* lpVtbl;

      LPSERVERDOC                      lpServerDoc;

      int                              cRef;// interface specific ref count.

   } m_OleInPlaceActiveObject;

#endif // INPLACE_SVR

   struct CDocOleObjectImpl {

      IOleObjectVtbl FAR*         lpVtbl;

      LPSERVERDOC                 lpServerDoc;

      int                         cRef;   // interface specific ref count.

   } m_OleObject;

   struct CDocPersistStorageImpl {

      IPersistStorageVtbl FAR*    lpVtbl;

      LPSERVERDOC                 lpServerDoc;

      int                         cRef;   // interface specific ref count.

   } m_PersistStorage;

#if defined( SVR_TREATAS )

   struct CDocStdMarshalInfoImpl {

      IStdMarshalInfoVtbl FAR*    lpVtbl;

      LPSERVERDOC                 lpServerDoc;

      int                         cRef;   // interface specific ref count.

   } m_StdMarshalInfo;

#endif  // SVR_TREATAS

} SERVERDOC;

/* ServerDoc methods (functions) */

BOOL ServerDoc_Init(LPSERVERDOC lpServerDoc, BOOL fDataTransferDoc);

BOOL ServerDoc_InitNewEmbed(LPSERVERDOC lpServerDoc);

void ServerDoc_PseudoObjUnlockDoc(

      LPSERVERDOC         lpServerDoc,

      LPPSEUDOOBJ         lpPseudoObj

);

void ServerDoc_PseudoObjLockDoc(LPSERVERDOC lpServerDoc);

BOOL ServerDoc_PasteFormatFromData(

      LPSERVERDOC             lpServerDoc,

      CLIPFORMAT              cfFormat,

      LPDATAOBJECT            lpSrcDataObj,

      BOOL                    fLocalDataObj,

      BOOL                    fLink

);

BOOL ServerDoc_QueryPasteFromData(

      LPSERVERDOC             lpServerDoc,

      LPDATAOBJECT            lpSrcDataObj,

      BOOL                    fLink

);

HRESULT ServerDoc_GetClassID(LPSERVERDOC lpServerDoc, LPCLSID lpclsid);

void ServerDoc_UpdateMenu(LPSERVERDOC lpServerDoc);

void ServerDoc_RestoreMenu(LPSERVERDOC lpServerDoc);

HRESULT ServerDoc_GetData (

      LPSERVERDOC             lpServerDoc,

      LPFORMATETC             lpformatetc,

      LPSTGMEDIUM             lpMedium

);

HRESULT ServerDoc_GetDataHere (

      LPSERVERDOC             lpServerDoc,

      LPFORMATETC             lpformatetc,

      LPSTGMEDIUM             lpMedium

);

HRESULT ServerDoc_QueryGetData(LPSERVERDOC lpServerDoc,LPFORMATETC lpformatetc);

HRESULT ServerDoc_EnumFormatEtc(

      LPSERVERDOC             lpServerDoc,

      DWORD                   dwDirection,

      LPENUMFORMATETC FAR*    lplpenumFormatEtc

);

HANDLE ServerDoc_GetMetafilePictData(

      LPSERVERDOC             lpServerDoc,

      LPLINERANGE             lplrSel

);

void ServerDoc_SendAdvise(

      LPSERVERDOC     lpServerDoc,

      WORD            wAdvise,

      LPMONIKER       lpmkDoc,

      DWORD           dwAdvf

);

HRESULT ServerDoc_GetObject(

      LPSERVERDOC             lpServerDoc,

      LPOLESTR                   lpszItem,

      REFIID                  riid,

      LPVOID FAR*             lplpvObject

);

HRESULT ServerDoc_IsRunning(LPSERVERDOC lpServerDoc, LPOLESTR lpszItem);

LPMONIKER ServerDoc_GetSelRelMoniker(

      LPSERVERDOC             lpServerDoc,

      LPLINERANGE             lplrSel,

      DWORD                   dwAssign

);

LPMONIKER ServerDoc_GetSelFullMoniker(

      LPSERVERDOC             lpServerDoc,

      LPLINERANGE             lplrSel,

      DWORD                   dwAssign

);

#if defined( INPLACE_SVR )

HRESULT ServerDoc_DoInPlaceActivate(

      LPSERVERDOC     lpServerDoc,

      LONG            lVerb,

      LPMSG           lpmsg,

      LPOLECLIENTSITE lpActiveSite

);

HRESULT ServerDoc_DoInPlaceDeactivate(LPSERVERDOC lpServerDoc);

HRESULT ServerDoc_DoInPlaceHide(LPSERVERDOC lpServerDoc);

BOOL ServerDoc_AllocInPlaceData(LPSERVERDOC lpServerDoc);

void ServerDoc_FreeInPlaceData(LPSERVERDOC lpServerDoc);

HRESULT ServerDoc_AssembleMenus(LPSERVERDOC lpServerDoc);

void    ServerDoc_DisassembleMenus(LPSERVERDOC lpServerDoc);

void ServerDoc_CalcInPlaceWindowPos(

      LPSERVERDOC         lpServerDoc,

      LPRECT              lprcListBox,

      LPRECT              lprcDoc,

      LPSCALEFACTOR       lpscale

);

void ServerDoc_UpdateInPlaceWindowOnExtentChange(LPSERVERDOC lpServerDoc);

void ServerDoc_ResizeInPlaceWindow(

      LPSERVERDOC         lpServerDoc,

      LPCRECT             lprcPosRect,

      LPCRECT             lprcClipRect

);

void ServerDoc_ShadeInPlaceBorder(LPSERVERDOC lpServerDoc, BOOL fShadeOn);

void ServerDoc_SetStatusText(LPSERVERDOC lpServerDoc, LPOLESTR lpszMessage);

LPOLEINPLACEFRAME ServerDoc_GetTopInPlaceFrame(LPSERVERDOC lpServerDoc);

void ServerDoc_GetSharedMenuHandles(

      LPSERVERDOC lpServerDoc,

      HMENU FAR*      lphSharedMenu,

      HOLEMENU FAR*   lphOleMenu

);

void ServerDoc_AddFrameLevelUI(LPSERVERDOC lpServerDoc);

void ServerDoc_AddFrameLevelTools(LPSERVERDOC lpServerDoc);

void ServerDoc_UIActivate (LPSERVERDOC lpServerDoc);

#if defined( USE_FRAMETOOLS )

void ServerDoc_RemoveFrameLevelTools(LPSERVERDOC lpServerDoc);

#endif // USE_FRAMETOOLS

#endif // INPLACE_SVR

/* ServerDoc::IOleObject methods (functions) */

STDMETHODIMP SvrDoc_OleObj_QueryInterface(

      LPOLEOBJECT             lpThis,

      REFIID                  riid,

      LPVOID FAR*             lplpvObj

);

STDMETHODIMP_(ULONG) SvrDoc_OleObj_AddRef(LPOLEOBJECT lpThis);

STDMETHODIMP_(ULONG) SvrDoc_OleObj_Release(LPOLEOBJECT lpThis);

STDMETHODIMP SvrDoc_OleObj_SetClientSite(

      LPOLEOBJECT             lpThis,

      LPOLECLIENTSITE         lpclientSite

);

STDMETHODIMP SvrDoc_OleObj_GetClientSite(

      LPOLEOBJECT             lpThis,

      LPOLECLIENTSITE FAR*    lplpClientSite

);

STDMETHODIMP SvrDoc_OleObj_SetHostNames(

      LPOLEOBJECT             lpThis,

      LPCOLESTR               szContainerApp,

      LPCOLESTR               szContainerObj

);

STDMETHODIMP SvrDoc_OleObj_Close(

      LPOLEOBJECT             lpThis,

      DWORD                   dwSaveOption

);

STDMETHODIMP SvrDoc_OleObj_SetMoniker(

      LPOLEOBJECT             lpThis,

      DWORD                   dwWhichMoniker,

      LPMONIKER               lpmk

);

STDMETHODIMP SvrDoc_OleObj_GetMoniker(

      LPOLEOBJECT             lpThis,

      DWORD                   dwAssign,

      DWORD                   dwWhichMoniker,

      LPMONIKER FAR*          lplpmk

);

STDMETHODIMP SvrDoc_OleObj_InitFromData(

      LPOLEOBJECT             lpThis,

      LPDATAOBJECT            lpDataObject,

      BOOL                    fCreation,

      DWORD                   reserved

);

STDMETHODIMP SvrDoc_OleObj_GetClipboardData(

      LPOLEOBJECT             lpThis,

      DWORD                   reserved,

      LPDATAOBJECT FAR*       lplpDataObject

);

STDMETHODIMP SvrDoc_OleObj_DoVerb(

      LPOLEOBJECT             lpThis,

      LONG                    lVerb,

      LPMSG                   lpmsg,

      LPOLECLIENTSITE         lpActiveSite,

      LONG                    lindex,

      HWND                    hwndParent,

      LPCRECT                 lprcPosRect

);

STDMETHODIMP SvrDoc_OleObj_EnumVerbs(

      LPOLEOBJECT             lpThis,

      LPENUMOLEVERB FAR*      lplpenumOleVerb

);

STDMETHODIMP SvrDoc_OleObj_Update(LPOLEOBJECT lpThis);

STDMETHODIMP SvrDoc_OleObj_IsUpToDate(LPOLEOBJECT lpThis);

STDMETHODIMP SvrDoc_OleObj_GetUserClassID(

      LPOLEOBJECT             lpThis,

      LPCLSID                 lpclsid

);

STDMETHODIMP SvrDoc_OleObj_GetUserType(

      LPOLEOBJECT             lpThis,

      DWORD                   dwFormOfType,

      LPOLESTR FAR*           lpszUserType

);

STDMETHODIMP SvrDoc_OleObj_SetExtent(

      LPOLEOBJECT             lpThis,

      DWORD                   dwDrawAspect,

      LPSIZEL                 lplgrc

);

STDMETHODIMP SvrDoc_OleObj_GetExtent(

      LPOLEOBJECT             lpThis,

      DWORD                   dwDrawAspect,

      LPSIZEL                 lplgrc

);

STDMETHODIMP SvrDoc_OleObj_Advise(

      LPOLEOBJECT             lpThis,

      LPADVISESINK            lpAdvSink,

      LPDWORD                 lpdwConnection

);

STDMETHODIMP SvrDoc_OleObj_Unadvise(LPOLEOBJECT lpThis, DWORD dwConnection);

STDMETHODIMP SvrDoc_OleObj_EnumAdvise(

      LPOLEOBJECT             lpThis,

      LPENUMSTATDATA FAR*     lplpenumAdvise

);

STDMETHODIMP SvrDoc_OleObj_GetMiscStatus(

      LPOLEOBJECT             lpThis,

      DWORD                   dwAspect,

      DWORD FAR*              lpdwStatus

);

STDMETHODIMP SvrDoc_OleObj_SetColorScheme(

      LPOLEOBJECT             lpThis,

      LPLOGPALETTE            lpLogpal

);

STDMETHODIMP SvrDoc_OleObj_LockObject(

      LPOLEOBJECT             lpThis,

      BOOL                    fLock

);

/* ServerDoc::IPersistStorage methods (functions) */

STDMETHODIMP SvrDoc_PStg_QueryInterface(

      LPPERSISTSTORAGE        lpThis,

      REFIID                  riid,

      LPVOID FAR*             lplpvObj

);

STDMETHODIMP_(ULONG) SvrDoc_PStg_AddRef(LPPERSISTSTORAGE lpThis);

STDMETHODIMP_(ULONG) SvrDoc_PStg_Release(LPPERSISTSTORAGE lpThis);

STDMETHODIMP SvrDoc_PStg_GetClassID(

      LPPERSISTSTORAGE        lpThis,

      LPCLSID                 lpClassID

);

STDMETHODIMP  SvrDoc_PStg_IsDirty(LPPERSISTSTORAGE  lpThis);

STDMETHODIMP SvrDoc_PStg_InitNew(

      LPPERSISTSTORAGE        lpThis,

      LPSTORAGE               lpStg

);

STDMETHODIMP SvrDoc_PStg_Load(

      LPPERSISTSTORAGE        lpThis,

      LPSTORAGE               lpStg

);

STDMETHODIMP SvrDoc_PStg_Save(

      LPPERSISTSTORAGE        lpThis,

      LPSTORAGE               lpStg,

      BOOL                    fSameAsLoad

);

STDMETHODIMP SvrDoc_PStg_SaveCompleted(

      LPPERSISTSTORAGE        lpThis,

      LPSTORAGE               lpStgNew

);

STDMETHODIMP SvrDoc_PStg_HandsOffStorage(LPPERSISTSTORAGE lpThis);

#if defined( SVR_TREATAS )

/* ServerDoc::IStdMarshalInfo methods (functions) */

STDMETHODIMP SvrDoc_StdMshl_QueryInterface(

      LPSTDMARSHALINFO        lpThis,

      REFIID                  riid,

      LPVOID FAR*             lplpvObj

);

STDMETHODIMP_(ULONG) SvrDoc_StdMshl_AddRef(LPSTDMARSHALINFO lpThis);

STDMETHODIMP_(ULONG) SvrDoc_StdMshl_Release(LPSTDMARSHALINFO lpThis);

STDMETHODIMP SvrDoc_StdMshl_GetClassForHandler(

      LPSTDMARSHALINFO        lpThis,

      DWORD                   dwDestContext,

      LPVOID                  pvDestContext,

      LPCLSID                 lpClassID

);

#endif  // SVR_TREATAS

/*************************************************************************

** class SERVERAPP : OLEAPP

**    SERVERAPP is an extention to the abstract base OLEAPP class.

**    The OLEAPP class defines the fields, methods and interfaces that

**    are common to both server and client implementations. The

**    SERVERAPP class adds the fields and methods that are specific to

**    OLE 2.0 Server functionality. There is one instance of

**    SERVERAPP object created per running application instance. This

**    object holds many fields that could otherwise be organized as

**    global variables. The SERVERAPP class inherits all fields

**    from the OLEAPP class. This inheritance is achieved by including a

**    member variable of type OLEAPP as the first field in the SERVERAPP

**    structure. OLEAPP inherits from OLEAPP. This inheritance is

**    achieved in the same manner. Thus a pointer to a SERVERAPP object

**    can be cast to be a pointer to an OLEAPP or an OUTLINEAPP object

*************************************************************************/

typedef struct tagSERVERAPP {

   OLEAPP      m_OleApp;       // ServerApp inherits all fields of OleApp

#if defined( INPLACE_SVR )

   HACCEL  m_hAccelIPSvr; // accelerators for server's active object commands

   HACCEL  m_hAccelBaseApp;    // normal accel for non-inplace server mode

   HMENU   m_hMenuEdit;   // handle to Edit menu of the server app

   HMENU   m_hMenuLine;   // handle to Line menu of the server app

   HMENU   m_hMenuName;   // handle to Name menu of the server app

   HMENU   m_hMenuOptions; // handle to Options menu of the server app

   HMENU   m_hMenuDebug;       // handle to Debug menu of the server app

   HMENU   m_hMenuHelp;   // handle to Help menu of the server app

   LPINPLACEDATA   m_lpIPData;

#endif

} SERVERAPP;

/* ServerApp methods (functions) */

BOOL ServerApp_InitInstance(

      LPSERVERAPP             lpServerApp,

      HINSTANCE               hInst,

      int                     nCmdShow

);

BOOL ServerApp_InitVtbls (LPSERVERAPP lpServerApp);

/*************************************************************************

** class SERVERNAME : OUTLINENAME

**    SERVERNAME class is an extension to the OUTLINENAME base class that

**    adds functionallity required to support linking to ranges (pseudo

**    objects). Pseudo objects are used to allow linking to a range

**    (sub-selection) of a SERVERDOC document. The base class OUTLINENAME

**    stores a particular named selection in the document. The

**    NAMETABLE class holds all of the names defined in a particular

**    document. Each OUTLINENAME object has a string as its key and a

**    starting line index and an ending line index for the named range.

**    The SERVERNAME class, also, stores a pointer to a PSEUDOOBJ if one

**    has been allocated that corresponds to the named selection.

**    The SERVERNAME class inherits all fields from the OUTLINENAME class.

**    This inheritance is achieved by including a member variable of

**    type OUTLINENAME as the first field in the SERVERNAME

**    structure. Thus a pointer to an SERVERNAME object can be cast to be

**    a pointer to a OUTLINENAME object.

*************************************************************************/

typedef struct tagSERVERNAME {

   OUTLINENAME     m_Name;         // ServerName inherits all fields of Name

   LPPSEUDOOBJ m_lpPseudoObj;  // ptr to pseudo object if allocated

} SERVERNAME, FAR* LPSERVERNAME;

/* ServerName methods (functions) */

void ServerName_SetSel(

      LPSERVERNAME            lpServerName,

      LPLINERANGE             lplrSel,

      BOOL                    fRangeModified

);

void ServerName_SendPendingAdvises(LPSERVERNAME lpServerName);

LPPSEUDOOBJ ServerName_GetPseudoObj(

      LPSERVERNAME            lpServerName,

      LPSERVERDOC             lpServerDoc

);

void ServerName_ClosePseudoObj(LPSERVERNAME lpServerName);

/*************************************************************************

** class PSEUDOOBJ

**    The PSEUDOOBJ (pseudo object) is a concrete class. A pseudo object

**    is created when a link is made to a range of lines within an

**    SERVERDOC document. A pseudo object is dependent on the existance

**    of the SERVERDOC which represents the whole document.

*************************************************************************/

typedef struct tagPSEUDOOBJ {

   ULONG               m_cRef;             // total ref count for obj

   BOOL                m_fObjIsClosing;    // flag to guard recursive close

   LPSERVERNAME        m_lpName;           // named range for this pseudo obj

   LPSERVERDOC         m_lpDoc;            // ptr to whole document

   LPOLEADVISEHOLDER   m_lpOleAdviseHldr;  // helper obj to hold ole advises

   LPDATAADVISEHOLDER  m_lpDataAdviseHldr; // helper obj to hold data advises

   BOOL                m_fDataChanged;     // data changed when draw disabled

   struct CPseudoObjUnknownImpl {

      IUnknownVtbl FAR*       lpVtbl;

      LPPSEUDOOBJ             lpPseudoObj;

      int                     cRef;   // interface specific ref count.

   } m_Unknown;

   struct CPseudoObjOleObjectImpl {

      IOleObjectVtbl FAR*     lpVtbl;

      LPPSEUDOOBJ             lpPseudoObj;

      int                     cRef;   // interface specific ref count.

   } m_OleObject;

   struct CPseudoObjDataObjectImpl {

      IDataObjectVtbl FAR*    lpVtbl;

      LPPSEUDOOBJ             lpPseudoObj;

      int                     cRef;   // interface specific ref count.

   } m_DataObject;

} PSEUDOOBJ;

/* PseudoObj methods (functions) */

void PseudoObj_Init(

      LPPSEUDOOBJ             lpPseudoObj,

      LPSERVERNAME            lpServerName,

      LPSERVERDOC             lpServerDoc

);

ULONG PseudoObj_AddRef(LPPSEUDOOBJ lpPseudoObj);

ULONG PseudoObj_Release(LPPSEUDOOBJ lpPseudoObj);

HRESULT PseudoObj_QueryInterface(

      LPPSEUDOOBJ         lpPseudoObj,

      REFIID              riid,

      LPVOID FAR*         lplpUnk

);

BOOL PseudoObj_Close(LPPSEUDOOBJ lpPseudoObj);

void PseudoObj_Destroy(LPPSEUDOOBJ lpPseudoObj);

void PseudoObj_GetSel(LPPSEUDOOBJ lpPseudoObj, LPLINERANGE lplrSel);

void PseudoObj_GetExtent(LPPSEUDOOBJ lpPseudoObj, LPSIZEL lpsizel);

void PseudoObj_GetExtent(LPPSEUDOOBJ lpPseudoObj, LPSIZEL lpsizel);

void PseudoObj_SendAdvise(

      LPPSEUDOOBJ lpPseudoObj,

      WORD        wAdvise,

      LPMONIKER   lpmkObj,

      DWORD       dwAdvf

);

LPMONIKER PseudoObj_GetFullMoniker(LPPSEUDOOBJ lpPseudoObj, LPMONIKER lpmkDoc);

/* PseudoObj::IUnknown methods (functions) */

STDMETHODIMP PseudoObj_Unk_QueryInterface(

      LPUNKNOWN         lpThis,

      REFIID            riid,

      LPVOID FAR*       lplpvObj

);

STDMETHODIMP_(ULONG) PseudoObj_Unk_AddRef(LPUNKNOWN lpThis);

STDMETHODIMP_(ULONG) PseudoObj_Unk_Release (LPUNKNOWN lpThis);

/* PseudoObj::IOleObject methods (functions) */

STDMETHODIMP PseudoObj_OleObj_QueryInterface(

      LPOLEOBJECT     lpThis,

      REFIID          riid,

      LPVOID FAR*     lplpvObj

);

STDMETHODIMP_(ULONG) PseudoObj_OleObj_AddRef(LPOLEOBJECT lpThis);

STDMETHODIMP_(ULONG) PseudoObj_OleObj_Release(LPOLEOBJECT lpThis);

STDMETHODIMP PseudoObj_OleObj_SetClientSite(

      LPOLEOBJECT         lpThis,

      LPOLECLIENTSITE     lpClientSite

);

STDMETHODIMP PseudoObj_OleObj_GetClientSite(

      LPOLEOBJECT             lpThis,

      LPOLECLIENTSITE FAR*    lplpClientSite

);

STDMETHODIMP PseudoObj_OleObj_SetHostNames(

      LPOLEOBJECT             lpThis,

      LPCOLESTR               szContainerApp,

      LPCOLESTR               szContainerObj

);

STDMETHODIMP PseudoObj_OleObj_Close(

      LPOLEOBJECT             lpThis,

      DWORD                   dwSaveOption

);

STDMETHODIMP PseudoObj_OleObj_SetMoniker(

      LPOLEOBJECT lpThis,

      DWORD       dwWhichMoniker,

      LPMONIKER   lpmk

);

STDMETHODIMP PseudoObj_OleObj_GetMoniker(

      LPOLEOBJECT     lpThis,

      DWORD           dwAssign,

      DWORD           dwWhichMoniker,

      LPMONIKER FAR*  lplpmk

);

STDMETHODIMP PseudoObj_OleObj_InitFromData(

      LPOLEOBJECT             lpThis,

      LPDATAOBJECT            lpDataObject,

      BOOL                    fCreation,

      DWORD                   reserved

);

STDMETHODIMP PseudoObj_OleObj_GetClipboardData(

      LPOLEOBJECT             lpThis,

      DWORD                   reserved,

      LPDATAOBJECT FAR*       lplpDataObject

);

STDMETHODIMP PseudoObj_OleObj_DoVerb(

      LPOLEOBJECT             lpThis,

      LONG                    lVerb,

      LPMSG                   lpmsg,

      LPOLECLIENTSITE         lpActiveSite,

      LONG                    lindex,

      HWND                    hwndParent,

      LPCRECT                 lprcPosRect

);

STDMETHODIMP PseudoObj_OleObj_EnumVerbs(

      LPOLEOBJECT         lpThis,

      LPENUMOLEVERB FAR*  lplpenumOleVerb

);

STDMETHODIMP PseudoObj_OleObj_Update(LPOLEOBJECT lpThis);

STDMETHODIMP PseudoObj_OleObj_IsUpToDate(LPOLEOBJECT lpThis);

STDMETHODIMP PseudoObj_OleObj_GetUserClassID(

      LPOLEOBJECT             lpThis,

      LPCLSID                 lpclsid

);

STDMETHODIMP PseudoObj_OleObj_GetUserType(

      LPOLEOBJECT             lpThis,

      DWORD                   dwFormOfType,

      LPOLESTR FAR*           lpszUserType

);

STDMETHODIMP PseudoObj_OleObj_SetExtent(

      LPOLEOBJECT             lpThis,

      DWORD                   dwDrawAspect,

      LPSIZEL                 lplgrc

);

STDMETHODIMP PseudoObj_OleObj_GetExtent(

      LPOLEOBJECT             lpThis,

      DWORD                   dwDrawAspect,

      LPSIZEL                 lplgrc

);

STDMETHODIMP PseudoObj_OleObj_Advise(

      LPOLEOBJECT lpThis,

      LPADVISESINK lpAdvSink,

      LPDWORD lpdwConnection

);

STDMETHODIMP PseudoObj_OleObj_Unadvise(LPOLEOBJECT lpThis,DWORD dwConnection);

STDMETHODIMP PseudoObj_OleObj_EnumAdvise(

      LPOLEOBJECT lpThis,

      LPENUMSTATDATA FAR* lplpenumAdvise

);

STDMETHODIMP PseudoObj_OleObj_GetMiscStatus(

      LPOLEOBJECT             lpThis,

      DWORD                   dwAspect,

      DWORD FAR*              lpdwStatus

);

STDMETHODIMP PseudoObj_OleObj_SetColorScheme(

      LPOLEOBJECT             lpThis,

      LPLOGPALETTE            lpLogpal

);

STDMETHODIMP PseudoObj_OleObj_LockObject(

      LPOLEOBJECT             lpThis,

      BOOL                    fLock

);

/* PseudoObj::IDataObject methods (functions) */

STDMETHODIMP PseudoObj_DataObj_QueryInterface (

      LPDATAOBJECT      lpThis,

      REFIID            riid,

      LPVOID FAR*       lplpvObj

);

STDMETHODIMP_(ULONG) PseudoObj_DataObj_AddRef(LPDATAOBJECT lpThis);

STDMETHODIMP_(ULONG) PseudoObj_DataObj_Release (LPDATAOBJECT lpThis);

STDMETHODIMP PseudoObj_DataObj_GetData (

      LPDATAOBJECT    lpThis,

      LPFORMATETC     lpformatetc,

      LPSTGMEDIUM     lpMedium

);

STDMETHODIMP PseudoObj_DataObj_GetDataHere (

      LPDATAOBJECT    lpThis,

      LPFORMATETC     lpformatetc,

      LPSTGMEDIUM     lpMedium

);

STDMETHODIMP PseudoObj_DataObj_QueryGetData (

      LPDATAOBJECT    lpThis,

      LPFORMATETC     lpformatetc

);

STDMETHODIMP PseudoObj_DataObj_GetCanonicalFormatEtc (

      LPDATAOBJECT    lpThis,

      LPFORMATETC     lpformatetc,

      LPFORMATETC     lpformatetcOut

);

STDMETHODIMP PseudoObj_DataObj_SetData (

      LPDATAOBJECT    lpThis,

      LPFORMATETC     lpformatetc,

      LPSTGMEDIUM     lpmedium,

      BOOL            fRelease

);

STDMETHODIMP PseudoObj_DataObj_EnumFormatEtc(

      LPDATAOBJECT            lpThis,

      DWORD                   dwDirection,

      LPENUMFORMATETC FAR*    lplpenumFormatEtc

);

STDMETHODIMP PseudoObj_DataObj_DAdvise(

      LPDATAOBJECT    lpThis,

      FORMATETC FAR*  lpFormatetc,

      DWORD           advf,

      LPADVISESINK    lpAdvSink,

      DWORD FAR*      lpdwConnection

);

STDMETHODIMP PseudoObj_DataObj_DUnadvise(LPDATAOBJECT lpThis, DWORD dwConnection);

STDMETHODIMP PseudoObj_DataObj_EnumAdvise(

      LPDATAOBJECT lpThis,

      LPENUMSTATDATA FAR* lplpenumAdvise

);

/*************************************************************************

** class SERVERNAMETABLE : OUTLINENAMETABLE

**    SERVERNAMETABLE class is an extension to the OUTLINENAMETABLE

**    base class that adds functionallity required to support linking

**    to ranges (pseudo objects). The name table manages the table of

**    named selections in the document. Each name table entry has a

**    string as its key and a starting line index and an ending line

**    index for the named range. The SERVERNAMETABLE entries, in

**    addition, maintain a pointer to a PSEUDOOBJ pseudo object if one

**    has been already allocated. There is always one instance of

**    SERVERNAMETABLE for each SERVERDOC object created.

**    The SERVERNAME class inherits all fields from the NAME class.

**    This inheritance is achieved by including a member variable of

**    type NAME as the first field in the SERVERNAME

**    structure. Thus a pointer to an SERVERNAME object can be cast to be

**    a pointer to a NAME object.

*************************************************************************/

typedef struct tagSERVERNAMETABLE {

   OUTLINENAMETABLE    m_NameTable;    // we inherit from OUTLINENAMETABLE

   // ServerNameTable does NOT add any fields

} SERVERNAMETABLE, FAR* LPSERVERNAMETABLE;

/* ServerNameTable methods (functions) */

void ServerNameTable_EditLineUpdate(

      LPSERVERNAMETABLE       lpServerNameTable,

      int                     nEditIndex

);

void ServerNameTable_InformAllPseudoObjectsDocRenamed(

      LPSERVERNAMETABLE       lpServerNameTable,

      LPMONIKER               lpmkDoc

);

void ServerNameTable_InformAllPseudoObjectsDocSaved(

      LPSERVERNAMETABLE       lpServerNameTable,

      LPMONIKER               lpmkDoc

);

void ServerNameTable_SendPendingAdvises(LPSERVERNAMETABLE lpServerNameTable);

LPPSEUDOOBJ ServerNameTable_GetPseudoObj(

      LPSERVERNAMETABLE       lpServerNameTable,

      LPOLESTR                lpszItem,

      LPSERVERDOC             lpServerDoc

);

void ServerNameTable_CloseAllPseudoObjs(LPSERVERNAMETABLE lpServerNameTable);

#if defined( INPLACE_SVR)

/* ServerDoc::IOleInPlaceObject methods (functions) */

STDMETHODIMP SvrDoc_IPObj_QueryInterface(

      LPOLEINPLACEOBJECT  lpThis,

      REFIID              riid,

      LPVOID FAR *        lplpvObj

);

STDMETHODIMP_(ULONG) SvrDoc_IPObj_AddRef(LPOLEINPLACEOBJECT lpThis);

STDMETHODIMP_(ULONG) SvrDoc_IPObj_Release(LPOLEINPLACEOBJECT lpThis);

STDMETHODIMP SvrDoc_IPObj_GetWindow(

      LPOLEINPLACEOBJECT  lpThis,

      HWND FAR*           lphwnd

);

STDMETHODIMP SvrDoc_IPObj_ContextSensitiveHelp(

      LPOLEINPLACEOBJECT  lpThis,

      BOOL                fEnable

);

STDMETHODIMP SvrDoc_IPObj_InPlaceDeactivate(LPOLEINPLACEOBJECT lpThis);

STDMETHODIMP SvrDoc_IPObj_UIDeactivate(LPOLEINPLACEOBJECT lpThis);

STDMETHODIMP SvrDoc_IPObj_SetObjectRects(

      LPOLEINPLACEOBJECT  lpThis,

      LPCRECT             lprcPosRect,

      LPCRECT             lprcClipRect

);

STDMETHODIMP SvrDoc_IPObj_ReactivateAndUndo(LPOLEINPLACEOBJECT lpThis);

/* ServerDoc::IOleInPlaceActiveObject methods (functions) */

STDMETHODIMP SvrDoc_IPActiveObj_QueryInterface(

      LPOLEINPLACEACTIVEOBJECT    lpThis,

      REFIID                      riidReq,

      LPVOID FAR *                lplpUnk

);

STDMETHODIMP_(ULONG) SvrDoc_IPActiveObj_AddRef(

      LPOLEINPLACEACTIVEOBJECT lpThis

);

STDMETHODIMP_(ULONG) SvrDoc_IPActiveObj_Release(

      LPOLEINPLACEACTIVEOBJECT lpThis

);

STDMETHODIMP SvrDoc_IPActiveObj_GetWindow(

      LPOLEINPLACEACTIVEOBJECT    lpThis,

      HWND FAR*                   lphwnd

);

STDMETHODIMP SvrDoc_IPActiveObj_ContextSensitiveHelp(

      LPOLEINPLACEACTIVEOBJECT    lpThis,

      BOOL                        fEnable

);

STDMETHODIMP SvrDoc_IPActiveObj_TranslateAccelerator(

      LPOLEINPLACEACTIVEOBJECT    lpThis,

      LPMSG                       lpmsg

);

STDMETHODIMP SvrDoc_IPActiveObj_OnFrameWindowActivate(

      LPOLEINPLACEACTIVEOBJECT    lpThis,

      BOOL                        fActivate

);

STDMETHODIMP SvrDoc_IPActiveObj_OnDocWindowActivate(

      LPOLEINPLACEACTIVEOBJECT    lpThis,

      BOOL                        fActivate

);

STDMETHODIMP SvrDoc_IPActiveObj_ResizeBorder(

      LPOLEINPLACEACTIVEOBJECT    lpThis,

      LPCRECT                     lprectBorder,

      LPOLEINPLACEUIWINDOW        lpIPUiWnd,

      BOOL                        fFrameWindow

);

STDMETHODIMP SvrDoc_IPActiveObj_EnableModeless(

      LPOLEINPLACEACTIVEOBJECT    lpThis,

      BOOL                        fEnable

);

#endif // INPLACE_SVR

#endif // _SVROUTL_H_


 SVROUTL.RC  (OUTLINE Sample)

/*************************************************************************

**

**    OLE 2.0 Sample Code

**

**    precomp.c

**

**    This file is used to precompile the OUTLINE.H header file

**

**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

**

*************************************************************************/

#include "outline.h"


 SVRPSOBJ.C  (OUTLINE Sample)

/*************************************************************************

**

**    OLE 2 Server Sample Code

**

**    svrpsobj.c

**

**    This file contains all PseudoObj methods and related support

**    functions.

**

**    (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

**

*************************************************************************/

#include "outline.h"

OLEDBGDATA

extern LPOUTLINEAPP             g_lpApp;

extern IUnknownVtbl             g_PseudoObj_UnknownVtbl;

extern IOleObjectVtbl           g_PseudoObj_OleObjectVtbl;

extern IDataObjectVtbl          g_PseudoObj_DataObjectVtbl;

/* PseudoObj_Init

** --------------

**  Initialize fields in a newly constructed PseudoObj.

**  NOTE: ref cnt of PseudoObj initialized to 0

*/

void PseudoObj_Init(

      LPPSEUDOOBJ             lpPseudoObj,

      LPSERVERNAME            lpServerName,

      LPSERVERDOC             lpServerDoc

)

{

   OleDbgOut2("++PseudoObj Created\r\n");

   lpPseudoObj->m_cRef             = 0;

   lpPseudoObj->m_lpName           = lpServerName;

   lpPseudoObj->m_lpDoc            = lpServerDoc;

   lpPseudoObj->m_lpOleAdviseHldr  = NULL;

   lpPseudoObj->m_lpDataAdviseHldr = NULL;

   lpPseudoObj->m_fObjIsClosing    = FALSE;

   INIT_INTERFACEIMPL(

         &lpPseudoObj->m_Unknown,

         &g_PseudoObj_UnknownVtbl,

         lpPseudoObj

   );

   INIT_INTERFACEIMPL(

         &lpPseudoObj->m_OleObject,

         &g_PseudoObj_OleObjectVtbl,

         lpPseudoObj

   );

   INIT_INTERFACEIMPL(

         &lpPseudoObj->m_DataObject,

         &g_PseudoObj_DataObjectVtbl,

         lpPseudoObj

   );

   /* OLE2NOTE: Increment the refcnt of the Doc on behalf of the

   **    PseudoObj. the Document should not shut down unless all

   **    pseudo objects are closed. when a pseudo object is destroyed,

   **    it calls ServerDoc_PseudoObjUnlockDoc to release this hold on

   **    the document.

   */

   ServerDoc_PseudoObjLockDoc(lpServerDoc);

}

/* PseudoObj_AddRef

** ----------------

**

**  increment the ref count of the PseudoObj object.

**

**    Returns the new ref count on the object

*/

ULONG PseudoObj_AddRef(LPPSEUDOOBJ lpPseudoObj)

{

   ++lpPseudoObj->m_cRef;

#if defined( _DEBUG )

   OleDbgOutRefCnt4(

         "PseudoObj_AddRef: cRef++\r\n",

         lpPseudoObj,

         lpPseudoObj->m_cRef

   );

#endif

   return lpPseudoObj->m_cRef;

}

/* PseudoObj_Release

** -----------------

**

**  decrement the ref count of the PseudoObj object.

**    if the ref count goes to 0, then the PseudoObj is destroyed.

**

**    Returns the remaining ref count on the object

*/

ULONG PseudoObj_Release(LPPSEUDOOBJ lpPseudoObj)

{

   ULONG cRef;

   /*********************************************************************

   ** OLE2NOTE: when the obj refcnt == 0, then destroy the object.     **

   **     otherwise the object is still in use.                        **

   *********************************************************************/

   cRef = --lpPseudoObj->m_cRef;

#if defined( _DEBUG )

   OleDbgAssertSz(lpPseudoObj->m_cRef >= 0,"Release called with cRef == 0");

   OleDbgOutRefCnt4(

         "PseudoObj_Release: cRef--\r\n", lpPseudoObj,cRef);

#endif

   if (cRef == 0)

      PseudoObj_Destroy(lpPseudoObj);

   return cRef;

}

/* PseudoObj_QueryInterface

** ------------------------

**

** Retrieve a pointer to an interface on the PseudoObj object.

**

**    Returns S_OK if interface is successfully retrieved.

**            E_NOINTERFACE if the interface is not supported

*/

HRESULT PseudoObj_QueryInterface(

      LPPSEUDOOBJ         lpPseudoObj,

      REFIID              riid,

      LPVOID FAR*         lplpvObj

)

{

   SCODE sc = E_NOINTERFACE;

   /* OLE2NOTE: we must make sure to set all out ptr parameters to NULL. */

   *lplpvObj = NULL;

   if (IsEqualIID(riid, &IID_IUnknown)) {

      OleDbgOut4("PseudoObj_QueryInterface: IUnknown* RETURNED\r\n");

      *lplpvObj = (LPVOID) &lpPseudoObj->m_Unknown;

      PseudoObj_AddRef(lpPseudoObj);

      sc = S_OK;

   }

   else if (IsEqualIID(riid, &IID_IOleObject)) {

      OleDbgOut4("PseudoObj_QueryInterface: IOleObject* RETURNED\r\n");

      *lplpvObj = (LPVOID) &lpPseudoObj->m_OleObject;

      PseudoObj_AddRef(lpPseudoObj);

      sc = S_OK;

   }

   else if (IsEqualIID(riid, &IID_IDataObject)) {

      OleDbgOut4("PseudoObj_QueryInterface: IDataObject* RETURNED\r\n");

      *lplpvObj = (LPVOID) &lpPseudoObj->m_DataObject;

      PseudoObj_AddRef(lpPseudoObj);

      sc = S_OK;

   }

   OleDbgQueryInterfaceMethod(*lplpvObj);

   return ResultFromScode(sc);

}

/* PseudoObj_Close

 * ---------------

 *

 *  Close the pseudo object. Force all external connections to close

 *      down. This causes link clients to release this PseudoObj. when

 *      the refcount actually reaches 0, then the PseudoObj will be

 *      destroyed.

 *

 *  Returns:

 *      FALSE -- user canceled the closing of the doc.

 *      TRUE -- the doc was successfully closed

 */

BOOL PseudoObj_Close(LPPSEUDOOBJ lpPseudoObj)

{

   LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpPseudoObj->m_lpDoc;

   LPSERVERNAME lpServerName = (LPSERVERNAME)lpPseudoObj->m_lpName;

   LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp;

   LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc;

   BOOL fStatus = TRUE;

   if (lpPseudoObj->m_fObjIsClosing)

      return TRUE;    // Closing is already in progress

   lpPseudoObj->m_fObjIsClosing = TRUE;   // guard against recursive call

   OLEDBG_BEGIN3("PseudoObj_Close\r\n")

   /* OLE2NOTE: in order to have a stable App, Doc, AND pseudo object

   **    during the process of closing, we intially AddRef the App,

   **    Doc, and PseudoObj ref counts and later Release them. These

   **    initial AddRefs are artificial; they are simply done to

   **    guarantee that these objects do not get destroyed until the

   **    end of this routine.

   */

   OleApp_AddRef(lpOleApp);

   OleDoc_AddRef(lpOleDoc);

   PseudoObj_AddRef(lpPseudoObj);

   if (lpPseudoObj->m_lpDataAdviseHldr) {

      /* OLE2NOTE: send last OnDataChange notification to clients

      **    that have registered for data notifications when object

      **    stops running (ADVF_DATAONSTOP)

      */

      PseudoObj_SendAdvise(

            lpPseudoObj,

            OLE_ONDATACHANGE,

            NULL,   /* lpmkObj -- not relevant here */

            ADVF_DATAONSTOP

      );

      /* OLE2NOTE: we just sent the last data notification that we

      **    need to send; release our DataAdviseHolder. we SHOULD be

      **    the only one using it.

      */

      OleStdVerifyRelease(

            (LPUNKNOWN)lpPseudoObj->m_lpDataAdviseHldr,

            OLESTR("DataAdviseHldr not released properly")

      );

      lpPseudoObj->m_lpDataAdviseHldr = NULL;

   }

   if (lpPseudoObj->m_lpOleAdviseHldr) {

      // OLE2NOTE: inform all of our linking clients that we are closing.

      PseudoObj_SendAdvise(

            lpPseudoObj,

            OLE_ONCLOSE,

            NULL,   /* lpmkObj -- not relevant here */

            0       /* advf -- not relevant here */

      );

      /* OLE2NOTE: OnClose is the last notification that we need to

      **    send; release our OleAdviseHolder. we SHOULD be the only

      **    one using it. this will make our destructor realize that

      **    OnClose notification has already been sent.

      */

      OleStdVerifyRelease(

            (LPUNKNOWN)lpPseudoObj->m_lpOleAdviseHldr,

            OLESTR("OleAdviseHldr not released properly")

      );

      lpPseudoObj->m_lpOleAdviseHldr = NULL;

   }

   /* OLE2NOTE: this call forces all external connections to our

   **    object to close down and therefore guarantees that we receive

   **    all releases associated with those external connections.

   */

   OLEDBG_BEGIN2("CoDisconnectObject called\r\n")

   CoDisconnectObject((LPUNKNOWN)&lpPseudoObj->m_Unknown, 0);

   OLEDBG_END2

   PseudoObj_Release(lpPseudoObj);     // release artificial AddRef above

   OleDoc_Release(lpOleDoc);           // release artificial AddRef above

   OleApp_Release(lpOleApp);           // release artificial AddRef above

   OLEDBG_END3

   return fStatus;

}

/* PseudoObj_Destroy

** -----------------

**    Destroy (Free) the memory used by a PseudoObj structure.

**    This function is called when the ref count of the PseudoObj goes

**    to zero. the ref cnt goes to zero after PseudoObj_Delete forces

**    the OleObject to unload and release its pointers to the

**    PseudoObj IOleClientSite and IAdviseSink interfaces.

*/

void PseudoObj_Destroy(LPPSEUDOOBJ lpPseudoObj)

{

   LPSERVERDOC lpServerDoc = lpPseudoObj->m_lpDoc;

   LPOLEAPP    lpOleApp = (LPOLEAPP)g_lpApp;

   LPOLEDOC    lpOleDoc = (LPOLEDOC)lpServerDoc;

   OLEDBG_BEGIN3("PseudoObj_Destroy\r\n")

   /* OLE2NOTE: in order to have a stable App, Doc, AND pseudo object

   **    during the process of closing, we intially AddRef the App,

   **    Doc ref counts and later Release them. These

   **    initial AddRefs are artificial; they are simply done to

   **    guarantee that these objects do not get destroyed until the

   **    end of this routine.

   */

   OleApp_AddRef(lpOleApp);

   OleDoc_AddRef(lpOleDoc);

   /******************************************************************

   ** OLE2NOTE: we no longer need the advise and enum holder objects,

   **    so release them.

   ******************************************************************/

   if (lpPseudoObj->m_lpDataAdviseHldr) {

      /* release DataAdviseHldr; we SHOULD be the only one using it. */

      OleStdVerifyRelease(

            (LPUNKNOWN)lpPseudoObj->m_lpDataAdviseHldr,

            OLESTR("DataAdviseHldr not released properly")

         );

      lpPseudoObj->m_lpDataAdviseHldr = NULL;

   }

   if (lpPseudoObj->m_lpOleAdviseHldr) {

      /* release OleAdviseHldr; we SHOULD be the only one using it. */

      OleStdVerifyRelease(

            (LPUNKNOWN)lpPseudoObj->m_lpOleAdviseHldr,

            OLESTR("OleAdviseHldr not released properly")

         );

      lpPseudoObj->m_lpOleAdviseHldr = NULL;

   }

   /* forget the pointer to destroyed PseudoObj in NameTable */

   if (lpPseudoObj->m_lpName)

      lpPseudoObj->m_lpName->m_lpPseudoObj = NULL;

   /* OLE2NOTE: release the lock on the Doc held on behalf of the

   **    PseudoObj. the Document should not shut down unless all

   **    pseudo objects are closed. when a pseudo object is first

   **    created, it calls ServerDoc_PseudoObjLockDoc to guarantee

   **    that the document stays alive (called from PseudoObj_Init).

   */

   ServerDoc_PseudoObjUnlockDoc(lpServerDoc, lpPseudoObj);

   Delete(lpPseudoObj);        // Free the memory for the structure itself

   OleDoc_Release(lpOleDoc);       // release artificial AddRef above

   OleApp_Release(lpOleApp);       // release artificial AddRef above

   OLEDBG_END3

}

/* PseudoObj_GetSel

** ----------------

**    Return the line range for the pseudo object

*/

void PseudoObj_GetSel(LPPSEUDOOBJ lpPseudoObj, LPLINERANGE lplrSel)

{

   LPOUTLINENAME lpOutlineName = (LPOUTLINENAME)lpPseudoObj->m_lpName;

   lplrSel->m_nStartLine = lpOutlineName->m_nStartLine;

   lplrSel->m_nEndLine = lpOutlineName->m_nEndLine;

}

/* PseudoObj_GetExtent

 * -------------------

 *

 *      Get the extent (width, height) of the entire document.

 */

void PseudoObj_GetExtent(LPPSEUDOOBJ lpPseudoObj, LPSIZEL lpsizel)

{

   LPOLEDOC lpOleDoc = (LPOLEDOC)lpPseudoObj->m_lpDoc;

   LPLINELIST lpLL = (LPLINELIST)&((LPOUTLINEDOC)lpOleDoc)->m_LineList;

   LINERANGE lrSel;

   PseudoObj_GetSel(lpPseudoObj, (LPLINERANGE)&lrSel);

   LineList_CalcSelExtentInHimetric(lpLL, (LPLINERANGE)&lrSel, lpsizel);

}

/* PseudoObj_SendAdvise

 * --------------------

 *

 * This function sends an advise notification on behalf of a specific

 *  doc object to all its clients.

 */

void PseudoObj_SendAdvise(

      LPPSEUDOOBJ lpPseudoObj,

      WORD        wAdvise,

      LPMONIKER   lpmkObj,

      DWORD       dwAdvf

)

{

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpPseudoObj->m_lpDoc;

   // artificial AddRef in case object is destroyed during call

   PseudoObj_AddRef(lpPseudoObj);

   switch (wAdvise) {

      case OLE_ONDATACHANGE:

         // inform clients that the data of the object has changed

         if (lpOutlineDoc->m_nDisableDraw == 0) {

            /* drawing is currently enabled. inform clients that

            **    the data of the object has changed

            */

            lpPseudoObj->m_fDataChanged = FALSE;

            if (lpPseudoObj->m_lpDataAdviseHldr) {

               OLEDBG_BEGIN2("IDataAdviseHolder::SendOnDataChange called\r\n");

               lpPseudoObj->m_lpDataAdviseHldr->lpVtbl->SendOnDataChange(

                     lpPseudoObj->m_lpDataAdviseHldr,

                     (LPDATAOBJECT)&lpPseudoObj->m_DataObject,

                     0,

                     dwAdvf

               );

               OLEDBG_END2

            }

         } else {

            /* drawing is currently disabled. do not send

            **    notifications until drawing is re-enabled.

            */

            lpPseudoObj->m_fDataChanged = TRUE;

         }

         break;

      case OLE_ONCLOSE:

         // inform clients that the object is shutting down

         if (lpPseudoObj->m_lpOleAdviseHldr) {

            OLEDBG_BEGIN2("IOleAdviseHolder::SendOnClose called\r\n");

            lpPseudoObj->m_lpOleAdviseHldr->lpVtbl->SendOnClose(

                  lpPseudoObj->m_lpOleAdviseHldr

            );

            OLEDBG_END2

         }

         break;

      case OLE_ONSAVE:

         // inform clients that the object has been saved

         if (lpPseudoObj->m_lpOleAdviseHldr) {

            OLEDBG_BEGIN2("IOleAdviseHolder::SendOnClose called\r\n");

            lpPseudoObj->m_lpOleAdviseHldr->lpVtbl->SendOnSave(

                  lpPseudoObj->m_lpOleAdviseHldr

            );

            OLEDBG_END2

         }

         break;

      case OLE_ONRENAME:

         // inform clients that the object's name has changed

         if (lpmkObj && lpPseudoObj->m_lpOleAdviseHldr) {

            OLEDBG_BEGIN2("IOleAdviseHolder::SendOnRename called\r\n");

            if (lpPseudoObj->m_lpOleAdviseHldr)

               lpPseudoObj->m_lpOleAdviseHldr->lpVtbl->SendOnRename(

                     lpPseudoObj->m_lpOleAdviseHldr,

                     lpmkObj

               );

            OLEDBG_END2

         }

         break;

   }

   // release artificial AddRef

   PseudoObj_Release(lpPseudoObj);

}

/* PseudoObj_GetFullMoniker

 * ------------------------

 *

 * Returns the Full, absolute Moniker which identifies this pseudo object.

 */

LPMONIKER PseudoObj_GetFullMoniker(LPPSEUDOOBJ lpPseudoObj, LPMONIKER lpmkDoc)

{

   LPOUTLINENAME lpOutlineName = (LPOUTLINENAME)lpPseudoObj->m_lpName;

   LPMONIKER lpmkItem = NULL;

   LPMONIKER lpmkPseudoObj = NULL;

   if (lpmkDoc != NULL) {

      CreateItemMoniker(OLESTDDELIM,lpOutlineName->m_szName,&lpmkItem);

      /* OLE2NOTE: create an absolute moniker which identifies the

      **    pseudo object. this moniker is created as a composite of

      **    the absolute moniker for the entire document appended

      **    with an item moniker which identifies the selection of

      **    the pseudo object relative to the document.

      */

      CreateGenericComposite(lpmkDoc, lpmkItem, &lpmkPseudoObj);

      if (lpmkItem)

         OleStdRelease((LPUNKNOWN)lpmkItem);

      return lpmkPseudoObj;

   } else {

      return NULL;

   }

}

/*************************************************************************

** PseudoObj::IUnknown interface implementation

*************************************************************************/

STDMETHODIMP PseudoObj_Unk_QueryInterface(

      LPUNKNOWN         lpThis,

      REFIID            riid,

      LPVOID FAR*       lplpvObj

)

{

   LPPSEUDOOBJ lpPseudoObj =

         ((struct CPseudoObjUnknownImpl FAR*)lpThis)->lpPseudoObj;

   return PseudoObj_QueryInterface(lpPseudoObj, riid, lplpvObj);

}

STDMETHODIMP_(ULONG) PseudoObj_Unk_AddRef(LPUNKNOWN lpThis)

{

   LPPSEUDOOBJ lpPseudoObj =

         ((struct CPseudoObjUnknownImpl FAR*)lpThis)->lpPseudoObj;

   OleDbgAddRefMethod(lpThis, "IUnknown");

   return PseudoObj_AddRef(lpPseudoObj);

}

STDMETHODIMP_(ULONG) PseudoObj_Unk_Release (LPUNKNOWN lpThis)

{

   LPPSEUDOOBJ lpPseudoObj =

         ((struct CPseudoObjUnknownImpl FAR*)lpThis)->lpPseudoObj;

   OleDbgReleaseMethod(lpThis, "IUnknown");

   return PseudoObj_Release(lpPseudoObj);

}

/*************************************************************************

** PseudoObj::IOleObject interface implementation

*************************************************************************/

STDMETHODIMP PseudoObj_OleObj_QueryInterface(

      LPOLEOBJECT     lpThis,

      REFIID          riid,

      LPVOID FAR*     lplpvObj

)

{

   LPPSEUDOOBJ lpPseudoObj =

         ((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj;

   return PseudoObj_QueryInterface(lpPseudoObj, riid, lplpvObj);

}

STDMETHODIMP_(ULONG) PseudoObj_OleObj_AddRef(LPOLEOBJECT lpThis)

{

   LPPSEUDOOBJ lpPseudoObj =

         ((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj;

   OleDbgAddRefMethod(lpThis, "IOleObject");

   return PseudoObj_AddRef((LPPSEUDOOBJ)lpPseudoObj);

}

STDMETHODIMP_(ULONG) PseudoObj_OleObj_Release(LPOLEOBJECT lpThis)

{

   LPPSEUDOOBJ lpPseudoObj =

         ((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj;

   OleDbgReleaseMethod(lpThis, "IOleObject");

   return PseudoObj_Release((LPPSEUDOOBJ)lpPseudoObj);

}

STDMETHODIMP PseudoObj_OleObj_SetClientSite(

      LPOLEOBJECT         lpThis,

      LPOLECLIENTSITE     lpClientSite

)

{

   OleDbgOut2("PseudoObj_OleObj_SetClientSite\r\n");

   // OLE2NOTE: a pseudo object does NOT support SetExtent

   return ResultFromScode(E_FAIL);

}

STDMETHODIMP PseudoObj_OleObj_GetClientSite(

      LPOLEOBJECT             lpThis,

      LPOLECLIENTSITE FAR*    lplpClientSite

)

{

   OleDbgOut2("PseudoObj_OleObj_GetClientSite\r\n");

   *lplpClientSite = NULL;

   // OLE2NOTE: a pseudo object does NOT support SetExtent

   return ResultFromScode(E_FAIL);

}

STDMETHODIMP PseudoObj_OleObj_SetHostNames(

      LPOLEOBJECT             lpThis,

      LPCOLESTR               szContainerApp,

      LPCOLESTR               szContainerObj

)

{

   OleDbgOut2("PseudoObj_OleObj_SetHostNames\r\n");

   // OLE2NOTE: a pseudo object does NOT support SetExtent

   return ResultFromScode(E_FAIL);

}

STDMETHODIMP PseudoObj_OleObj_Close(

      LPOLEOBJECT             lpThis,

      DWORD                   dwSaveOption

)

{

   LPPSEUDOOBJ lpPseudoObj =

         ((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj;

   BOOL fStatus;

   OLEDBG_BEGIN2("PseudoObj_OleObj_Close\r\n")

   /* OLE2NOTE: a pseudo object's implementation of IOleObject::Close

   **    should ignore the dwSaveOption parameter. it is NOT

   **    applicable to pseudo objects.

   */

   fStatus = PseudoObj_Close(lpPseudoObj);

   OleDbgAssertSz(fStatus == TRUE, "PseudoObj_OleObj_Close failed\r\n");

   OLEDBG_END2

   return NOERROR;

}

STDMETHODIMP PseudoObj_OleObj_SetMoniker(

      LPOLEOBJECT lpThis,

      DWORD       dwWhichMoniker,

      LPMONIKER   lpmk

)

{

   OleDbgOut2("PseudoObj_OleObj_SetMoniker\r\n");

   // OLE2NOTE: a pseudo object does NOT support SetMoniker

   return ResultFromScode(E_FAIL);

}

STDMETHODIMP PseudoObj_OleObj_GetMoniker(

      LPOLEOBJECT     lpThis,

      DWORD           dwAssign,

      DWORD           dwWhichMoniker,

      LPMONIKER FAR*  lplpmk

)

{

   LPPSEUDOOBJ lpPseudoObj =

         ((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj;

   LPOLEDOC lpOleDoc = (LPOLEDOC)lpPseudoObj->m_lpDoc;

   LPMONIKER lpmkDoc;

   // artificial AddRef in case object is destroyed during call

   PseudoObj_OleObj_AddRef(lpThis);

   OLEDBG_BEGIN2("PseudoObj_OleObj_GetMoniker\r\n")

   lpmkDoc = OleDoc_GetFullMoniker(lpOleDoc, GETMONIKER_ONLYIFTHERE);

   *lplpmk = PseudoObj_GetFullMoniker(lpPseudoObj, lpmkDoc);

   OLEDBG_END2

   if (*lplpmk != NULL)

   {

      // release artificial AddRef

      PseudoObj_OleObj_Release(lpThis);

      return NOERROR;

   }

   else

   {

      // release artificial AddRef

      PseudoObj_OleObj_Release(lpThis);

      return ResultFromScode(E_FAIL);

   }

}

STDMETHODIMP PseudoObj_OleObj_InitFromData(

      LPOLEOBJECT             lpThis,

      LPDATAOBJECT            lpDataObject,

      BOOL                    fCreation,

      DWORD                   reserved

)

{

   LPPSEUDOOBJ lpPseudoObj =

         ((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj;

   OleDbgOut2("PseudoObj_OleObj_InitFromData\r\n");

   // REVIEW: NOT YET IMPLEMENTED

   return ResultFromScode(E_NOTIMPL);

}

STDMETHODIMP PseudoObj_OleObj_GetClipboardData(

      LPOLEOBJECT             lpThis,

      DWORD                   reserved,

      LPDATAOBJECT FAR*       lplpDataObject

)

{

   LPPSEUDOOBJ lpPseudoObj =

         ((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj;

   OleDbgOut2("PseudoObj_OleObj_GetClipboardData\r\n");

   // REVIEW: NOT YET IMPLEMENTED

   return ResultFromScode(E_NOTIMPL);

}

STDMETHODIMP PseudoObj_OleObj_DoVerb(

      LPOLEOBJECT             lpThis,

      LONG                    lVerb,

      LPMSG                   lpmsg,

      LPOLECLIENTSITE         lpActiveSite,

      LONG                    lindex,

      HWND                    hwndParent,

      LPCRECT                 lprcPosRect

)

{

   LPPSEUDOOBJ lpPseudoObj =

         ((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj;

   LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpPseudoObj->m_lpDoc;

   LPSERVERDOC lpServerDoc = lpPseudoObj->m_lpDoc;

   LINERANGE lrSel;

   HRESULT hrErr;

   // artificial AddRef in case object is destroyed during call

   PseudoObj_OleObj_AddRef(lpThis);

   OLEDBG_BEGIN2("PseudoObj_OleObj_DoVerb\r\n");

   /* OLE2NOTE: we must first ask our Document to perform the same

   **    verb. then if the verb is NOT OLEIVERB_HIDE we should also

   **    select the range of our pseudo object.

   **    however, we must give our document its own embedding site as

   **    its active site.

   */

   hrErr = SvrDoc_OleObj_DoVerb(

         (LPOLEOBJECT)&lpServerDoc->m_OleObject,

         lVerb,

         lpmsg,

         lpServerDoc->m_lpOleClientSite,

         lindex,

         NULL,   /* we have no hwndParent to give */

         NULL    /* we have no lprcPosRect to give */

   );

   if (FAILED(hrErr)) {

      OLEDBG_END2

      // release artificial AddRef

      PseudoObj_OleObj_Release(lpThis);

      return hrErr;

   }

   if (lVerb != OLEIVERB_HIDE) {

      PseudoObj_GetSel(lpPseudoObj, &lrSel);

      OutlineDoc_SetSel(lpOutlineDoc, &lrSel);

   }

   OLEDBG_END2

   // release artificial AddRef

   PseudoObj_OleObj_Release(lpThis);

   return NOERROR;

}

STDMETHODIMP PseudoObj_OleObj_EnumVerbs(

      LPOLEOBJECT         lpThis,

      LPENUMOLEVERB FAR*  lplpenumOleVerb

)

{

   OleDbgOut2("PseudoObj_OleObj_EnumVerbs\r\n");

   /* OLE2NOTE: we must make sure to set all out parameters to NULL. */

   *lplpenumOleVerb = NULL;

   /* A pseudo object may NOT return OLE_S_USEREG; they must call the

   **    OleReg* API or provide their own implementation. Because this

   **    pseudo object does NOT implement IPersist, simply a low-level

   **    remoting handler (ProxyManager) object as opposed to a

   **    DefHandler object is used as the handler for the pseudo

   **    object in a clients process space. The ProxyManager does NOT

   **    handle the OLE_S_USEREG return values.

   */

   return OleRegEnumVerbs((REFCLSID)&CLSID_APP, lplpenumOleVerb);

}

STDMETHODIMP PseudoObj_OleObj_Update(LPOLEOBJECT lpThis)

{

   OleDbgOut2("PseudoObj_OleObj_Update\r\n");

   /* OLE2NOTE: a server-only app is always "up-to-date".

   **    a container-app which contains links where the link source

   **    has changed since the last update of the link would be

   **    considered "out-of-date". the "Update" method instructs the

   **    object to get an update from any out-of-date links.

   */

   return NOERROR;

}

STDMETHODIMP PseudoObj_OleObj_IsUpToDate(LPOLEOBJECT lpThis)

{

   LPPSEUDOOBJ lpPseudoObj =

         ((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj;

   OleDbgOut2("PseudoObj_OleObj_IsUpToDate\r\n");

   /* OLE2NOTE: a server-only app is always "up-to-date".

   **    a container-app which contains links where the link source

   **    has changed since the last update of the link would be

   **    considered "out-of-date".

   */

   return NOERROR;

}

STDMETHODIMP PseudoObj_OleObj_GetUserClassID(

      LPOLEOBJECT             lpThis,

      LPCLSID                 lpclsid

)

{

   LPPSEUDOOBJ lpPseudoObj =

         ((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj;

   LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpPseudoObj->m_lpDoc;

   OleDbgOut2("PseudoObj_OleObj_GetUserClassID\r\n");

   /* OLE2NOTE: we must be carefull to return the correct CLSID here.

   **    if we are currently preforming a "TreatAs (aka. ActivateAs)"

   **    operation then we need to return the class of the object

   **    written in the storage of the object. otherwise we would

   **    return our own class id.

   */

   return ServerDoc_GetClassID(lpServerDoc, lpclsid);

}

STDMETHODIMP PseudoObj_OleObj_GetUserType(

      LPOLEOBJECT             lpThis,

      DWORD                   dwFormOfType,

      LPOLESTR FAR*           lpszUserType

)

{

   LPPSEUDOOBJ lpPseudoObj =

         ((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj;

   LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpPseudoObj->m_lpDoc;

   OleDbgOut2("PseudoObj_OleObj_GetUserType\r\n");

   /* OLE2NOTE: we must make sure to set all out parameters to NULL. */

   *lpszUserType = NULL;

   /* OLE2NOTE: we must be carefull to return the correct user type here.

   **    if we are currently preforming a "TreatAs (aka. ActivateAs)"

   **    operation then we need to return the user type name that

   **    corresponds to the class of the object we are currently

   **    emmulating. otherwise we should return our normal user type

   **    name corresponding to our own class. This routine determines

   **    the current clsid in effect.

   **

   **    A pseudo object may NOT return OLE_S_USEREG; they must call the

   **    OleReg* API or provide their own implementation. Because this

   **    pseudo object does NOT implement IPersist, simply a low-level

   **    remoting handler (ProxyManager) object as opposed to a

   **    DefHandler object is used as the handler for the pseudo

   **    object in a clients process space. The ProxyManager does NOT

   **    handle the OLE_S_USEREG return values.

   */

#if defined( SVR_TREATAS )

   if (! IsEqualCLSID(&lpServerDoc->m_clsidTreatAs, &CLSID_NULL) )

      return OleRegGetUserType(

         (REFCLSID)&lpServerDoc->m_clsidTreatAs,dwFormOfType,lpszUserType);

   else

#endif  // SVR_TREATAS

   return OleRegGetUserType((REFCLSID)&CLSID_APP,dwFormOfType,lpszUserType);

}

STDMETHODIMP PseudoObj_OleObj_SetExtent(

      LPOLEOBJECT             lpThis,

      DWORD                   dwDrawAspect,

      LPSIZEL                 lplgrc

)

{

   OleDbgOut2("PseudoObj_OleObj_SetExtent\r\n");

   // OLE2NOTE: a pseudo object does NOT support SetExtent

   return ResultFromScode(E_FAIL);

}

STDMETHODIMP PseudoObj_OleObj_GetExtent(

      LPOLEOBJECT             lpThis,

      DWORD                   dwDrawAspect,

      LPSIZEL                 lpsizel

)

{

   LPPSEUDOOBJ lpPseudoObj =

         ((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj;

   OleDbgOut2("PseudoObj_OleObj_GetExtent\r\n");

   /* OLE2NOTE: it is VERY important to check which aspect the caller

   **    is asking about. an object implemented by a server EXE MAY

   **    fail to return extents when asked for DVASPECT_ICON.

   */

   if (dwDrawAspect == DVASPECT_CONTENT) {

      PseudoObj_GetExtent(lpPseudoObj, lpsizel);

      return NOERROR;

   }

   else

   {

      return ResultFromScode(E_FAIL);

   }

}

STDMETHODIMP PseudoObj_OleObj_Advise(

      LPOLEOBJECT lpThis,

      LPADVISESINK lpAdvSink,

      LPDWORD lpdwConnection

)

{

   LPPSEUDOOBJ lpPseudoObj =

         ((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj;

   HRESULT hrErr;

   SCODE   sc;

   OLEDBG_BEGIN2("PseudoObj_OleObj_Advise\r\n");

   if (lpPseudoObj->m_lpOleAdviseHldr == NULL &&

      CreateOleAdviseHolder(&lpPseudoObj->m_lpOleAdviseHldr) != NOERROR) {

      sc = E_OUTOFMEMORY;

      goto error;

   }

   OLEDBG_BEGIN2("IOleAdviseHolder::Advise called\r\n")

   hrErr = lpPseudoObj->m_lpOleAdviseHldr->lpVtbl->Advise(

         lpPseudoObj->m_lpOleAdviseHldr,

         lpAdvSink,

         lpdwConnection

   );

   OLEDBG_END2

   OLEDBG_END2

   return hrErr;

error:

   OLEDBG_END2

   return ResultFromScode(sc);

}

STDMETHODIMP PseudoObj_OleObj_Unadvise(LPOLEOBJECT lpThis, DWORD dwConnection)

{

   LPPSEUDOOBJ lpPseudoObj =

         ((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj;

   HRESULT hrErr;

   SCODE   sc;

   // artificial AddRef in case object is destroyed during call

   PseudoObj_OleObj_AddRef(lpThis);

   OLEDBG_BEGIN2("PseudoObj_OleObj_Unadvise\r\n");

   if (lpPseudoObj->m_lpOleAdviseHldr == NULL) {

      sc = E_FAIL;

      goto error;

   }

   OLEDBG_BEGIN2("IOleAdviseHolder::Unadvise called\r\n")

   hrErr = lpPseudoObj->m_lpOleAdviseHldr->lpVtbl->Unadvise(

         lpPseudoObj->m_lpOleAdviseHldr,

         dwConnection

   );

   OLEDBG_END2

   OLEDBG_END2

   // release artificial AddRef

   PseudoObj_OleObj_Release(lpThis);

   return hrErr;

error:

   OLEDBG_END2

   // release artificial AddRef

   PseudoObj_OleObj_Release(lpThis);

   return ResultFromScode(sc);

}

STDMETHODIMP PseudoObj_OleObj_EnumAdvise(

      LPOLEOBJECT lpThis,

      LPENUMSTATDATA FAR* lplpenumAdvise

)

{

   LPPSEUDOOBJ lpPseudoObj =

         ((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj;

   HRESULT hrErr;

   SCODE   sc;

   // artificial AddRef in case object is destroyed during call

   PseudoObj_OleObj_AddRef(lpThis);

   OLEDBG_BEGIN2("PseudoObj_OleObj_EnumAdvise\r\n");

   /* OLE2NOTE: we must make sure to set all out parameters to NULL. */

   *lplpenumAdvise = NULL;

   if (lpPseudoObj->m_lpOleAdviseHldr == NULL) {

      sc = E_FAIL;

      goto error;

   }

   OLEDBG_BEGIN2("IOleAdviseHolder::EnumAdvise called\r\n")

   hrErr = lpPseudoObj->m_lpOleAdviseHldr->lpVtbl->EnumAdvise(

         lpPseudoObj->m_lpOleAdviseHldr,

         lplpenumAdvise

   );

   OLEDBG_END2

   OLEDBG_END2

   // release artificial AddRef

   PseudoObj_OleObj_Release(lpThis);

   return hrErr;

error:

   OLEDBG_END2

   // release artificial AddRef

   PseudoObj_OleObj_Release(lpThis);

   return ResultFromScode(sc);

}

STDMETHODIMP PseudoObj_OleObj_GetMiscStatus(

      LPOLEOBJECT             lpThis,

      DWORD                   dwAspect,

      DWORD FAR*              lpdwStatus

)

{

   LPPSEUDOOBJ lpPseudoObj =

         ((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj;

   LPOUTLINEDOC  lpOutlineDoc = (LPOUTLINEDOC)lpPseudoObj->m_lpDoc;

   OleDbgOut2("PseudoObj_OleObj_GetMiscStatus\r\n");

   /* Get our default MiscStatus for the given Aspect. this

   **    information is registered in the RegDB. We query the RegDB

   **    here to guarantee that the value returned from this method

   **    agrees with the values in RegDB. in this way we only have to

   **    maintain the info in one place (in the RegDB). Alternatively

   **    we could have the values hard coded here.

   **

   ** OLE2NOTE: A pseudo object may NOT return OLE_S_USEREG; they must

   **    call the

   **    OleReg* API or provide their own implementation. Because this

   **    pseudo object does NOT implement IPersist, simply a low-level

   **    remoting handler (ProxyManager) object as opposed to a

   **    DefHandler object is used as the handler for the pseudo

   **    object in a clients process space. The ProxyManager does NOT

   **    handle the OLE_S_USEREG return values.

   */

   OleRegGetMiscStatus((REFCLSID)&CLSID_APP, dwAspect, lpdwStatus);

   /* OLE2NOTE: check if the pseudo object is compatible to be

   **    linked by an OLE 1.0 container. it is compatible if

   **    either the pseudo object is an untitled document or a

   **    file-based document. if the pseudo object is part of

   **    an embedded object, then it is NOT compatible to be

   **    linked by an OLE 1.0 container. if it is compatible then

   **    we should include OLEMISC_CANLINKBYOLE1 as part of the

   **    dwStatus flags.

   */

   if (lpOutlineDoc->m_docInitType == DOCTYPE_NEW ||

      lpOutlineDoc->m_docInitType == DOCTYPE_FROMFILE)

      *lpdwStatus |= OLEMISC_CANLINKBYOLE1;

   return NOERROR;

}

STDMETHODIMP PseudoObj_OleObj_SetColorScheme(

      LPOLEOBJECT             lpThis,

      LPLOGPALETTE            lpLogpal

)

{

   OleDbgOut2("PseudoObj_OleObj_SetColorScheme\r\n");

   // REVIEW: NOT YET IMPLEMENTED

   return ResultFromScode(E_NOTIMPL);

}

/*************************************************************************

** PseudoObj::IDataObject interface implementation

*************************************************************************/

STDMETHODIMP PseudoObj_DataObj_QueryInterface (

      LPDATAOBJECT      lpThis,

      REFIID            riid,

      LPVOID FAR*       lplpvObj

)

{

   LPPSEUDOOBJ lpPseudoObj =

         ((struct CPseudoObjDataObjectImpl FAR*)lpThis)->lpPseudoObj;

   return PseudoObj_QueryInterface(lpPseudoObj, riid, lplpvObj);

}

STDMETHODIMP_(ULONG) PseudoObj_DataObj_AddRef(LPDATAOBJECT lpThis)

{

   LPPSEUDOOBJ lpPseudoObj =

         ((struct CPseudoObjDataObjectImpl FAR*)lpThis)->lpPseudoObj;

   OleDbgAddRefMethod(lpThis, "IDataObject");

   return PseudoObj_AddRef((LPPSEUDOOBJ)lpPseudoObj);

}

STDMETHODIMP_(ULONG) PseudoObj_DataObj_Release (LPDATAOBJECT lpThis)

{

   LPPSEUDOOBJ lpPseudoObj =

         ((struct CPseudoObjDataObjectImpl FAR*)lpThis)->lpPseudoObj;

   OleDbgReleaseMethod(lpThis, "IDataObject");

   return PseudoObj_Release((LPPSEUDOOBJ)lpPseudoObj);

}

STDMETHODIMP PseudoObj_DataObj_GetData (

      LPDATAOBJECT    lpThis,

      LPFORMATETC     lpformatetc,

      LPSTGMEDIUM     lpMedium

)

{

   LPPSEUDOOBJ lpPseudoObj =

         ((struct CPseudoObjDataObjectImpl FAR*)lpThis)->lpPseudoObj;

   LPSERVERDOC  lpServerDoc = lpPseudoObj->m_lpDoc;

   LPOUTLINEDOC  lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;

   LPSERVERAPP lpServerApp = (LPSERVERAPP)g_lpApp;

   LPOLEAPP  lpOleApp = (LPOLEAPP)lpServerApp;

   LPOUTLINEAPP  lpOutlineApp = (LPOUTLINEAPP)lpServerApp;

   LINERANGE lrSel;

   SCODE sc = S_OK;

   // artificial AddRef in case object is destroyed during call

   PseudoObj_DataObj_AddRef(lpThis);

   OLEDBG_BEGIN2("PseudoObj_DataObj_GetData\r\n")

   PseudoObj_GetSel(lpPseudoObj, &lrSel);

   /* OLE2NOTE: we must make sure to set all out parameters to NULL. */

   lpMedium->tymed = TYMED_NULL;

   lpMedium->pUnkForRelease = NULL;    // we transfer ownership to caller

   lpMedium->u.hGlobal = NULL;

   if (lpformatetc->cfFormat == lpOutlineApp->m_cfOutline) {

      // Verify caller asked for correct medium

      if (!(lpformatetc->tymed & TYMED_HGLOBAL)) {

         sc = DATA_E_FORMATETC;

         goto error;

      }

      lpMedium->u.hGlobal = OutlineDoc_GetOutlineData (lpOutlineDoc,&lrSel);

      if (! lpMedium->u.hGlobal) return ResultFromScode(E_OUTOFMEMORY);

      lpMedium->tymed = TYMED_HGLOBAL;

      OleDbgOut3("PseudoObj_DataObj_GetData: rendered CF_OUTLINE\r\n");

   } else if(lpformatetc->cfFormat == CF_METAFILEPICT &&

      (lpformatetc->dwAspect & DVASPECT_CONTENT) ) {

      // Verify caller asked for correct medium

      if (!(lpformatetc->tymed & TYMED_MFPICT)) {

         sc = DATA_E_FORMATETC;

         goto error;

      }

      lpMedium->u.hGlobal=ServerDoc_GetMetafilePictData(lpServerDoc,&lrSel);

      if (! lpMedium->u.hGlobal) {

         sc = E_OUTOFMEMORY;

         goto error;

      }

      lpMedium->tymed = TYMED_MFPICT;

      OleDbgOut3("PseudoObj_DataObj_GetData: rendered CF_METAFILEPICT\r\n");

   } else if (lpformatetc->cfFormat == CF_METAFILEPICT &&

      (lpformatetc->dwAspect & DVASPECT_ICON) ) {

      CLSID clsid;

      // Verify caller asked for correct medium

      if (!(lpformatetc->tymed & TYMED_MFPICT)) {

         sc = DATA_E_FORMATETC;

         goto error;

      }

      /* OLE2NOTE: we should return the default icon for our class.

      **    we must be carefull to use the correct CLSID here.

      **    if we are currently preforming a "TreatAs (aka. ActivateAs)"

      **    operation then we need to use the class of the object

      **    written in the storage of the object. otherwise we would

      **    use our own class id.

      */

      if (ServerDoc_GetClassID(lpServerDoc, (LPCLSID)&clsid) != NOERROR) {

         sc = DATA_E_FORMATETC;

         goto error;

      }

      lpMedium->u.hGlobal=GetIconOfClass(

            g_lpApp->m_hInst,(REFCLSID)&clsid, NULL, FALSE);

      if (! lpMedium->u.hGlobal) {

         sc = E_OUTOFMEMORY;

         goto error;

      }

      lpMedium->tymed = TYMED_MFPICT;

      OleDbgOut3("PseudoObj_DataObj_GetData: rendered CF_METAFILEPICT (icon)\r\n");

      // release artificial AddRef

      PseudoObj_DataObj_Release(lpThis);

      return NOERROR;

   } else if (lpformatetc->cfFormat == CF_TEXT) {

      // Verify caller asked for correct medium

      if (!(lpformatetc->tymed & TYMED_HGLOBAL)) {

         sc = DATA_E_FORMATETC;

         goto error;

      }

      lpMedium->u.hGlobal = OutlineDoc_GetTextData (lpOutlineDoc, &lrSel);

      if (! lpMedium->u.hGlobal) {

         sc = E_OUTOFMEMORY;

         goto error;

      }

      lpMedium->tymed = TYMED_HGLOBAL;

      OleDbgOut3("PseudoObj_DataObj_GetData: rendered CF_TEXT\r\n");

   } else {

      sc = DATA_E_FORMATETC;

      goto error;

   }

   OLEDBG_END2

   // release artificial AddRef

   PseudoObj_DataObj_Release(lpThis);

   return NOERROR;

error:

   OLEDBG_END2

   // release artificial AddRef

   PseudoObj_DataObj_Release(lpThis);

   return ResultFromScode(sc);

}

STDMETHODIMP PseudoObj_DataObj_GetDataHere (

      LPDATAOBJECT    lpThis,

      LPFORMATETC     lpformatetc,

      LPSTGMEDIUM     lpMedium

)

{

   LPPSEUDOOBJ lpPseudoObj =

         ((struct CPseudoObjDataObjectImpl FAR*)lpThis)->lpPseudoObj;

   LPSERVERDOC  lpServerDoc = lpPseudoObj->m_lpDoc;

   LPOUTLINEDOC  lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;

   LPSERVERAPP lpServerApp = (LPSERVERAPP)g_lpApp;

   LPOLEAPP  lpOleApp = (LPOLEAPP)lpServerApp;

   LPOUTLINEAPP  lpOutlineApp = (LPOUTLINEAPP)lpServerApp;

   OleDbgOut("PseudoObj_DataObj_GetDataHere\r\n");

   /* Caller is requesting data to be returned in Caller allocated

   **    medium, but we do NOT support this. we only support

   **    global memory blocks that WE allocate for the caller.

   */

   return ResultFromScode(DATA_E_FORMATETC);

}

STDMETHODIMP PseudoObj_DataObj_QueryGetData (

      LPDATAOBJECT    lpThis,

      LPFORMATETC     lpformatetc

)

{

   LPPSEUDOOBJ lpPseudoObj =

         ((struct CPseudoObjDataObjectImpl FAR*)lpThis)->lpPseudoObj;

   LPSERVERDOC  lpServerDoc = lpPseudoObj->m_lpDoc;

   LPOUTLINEDOC  lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;

   LPSERVERAPP lpServerApp = (LPSERVERAPP)g_lpApp;

   LPOLEAPP  lpOleApp = (LPOLEAPP)lpServerApp;

   LPOUTLINEAPP  lpOutlineApp = (LPOUTLINEAPP)lpServerApp;

   // artificial AddRef in case object is destroyed during call

   PseudoObj_DataObj_AddRef(lpThis);

   OleDbgOut2("PseudoObj_DataObj_QueryGetData\r\n");

   /* Caller is querying if we support certain format but does not

   **    want any data actually returned.

   */

   if (lpformatetc->cfFormat == CF_METAFILEPICT &&

      (lpformatetc->dwAspect & (DVASPECT_CONTENT | DVASPECT_ICON)) ) {

      // release artificial AddRef

      PseudoObj_DataObj_Release(lpThis);

      return OleStdQueryFormatMedium(lpformatetc, TYMED_MFPICT);

   } else if (lpformatetc->cfFormat == (lpOutlineApp)->m_cfOutline ||

         lpformatetc->cfFormat == CF_TEXT) {

      // release artificial AddRef

      PseudoObj_DataObj_Release(lpThis);

      return OleStdQueryFormatMedium(lpformatetc, TYMED_HGLOBAL);

   }

   // release artificial AddRef

   PseudoObj_DataObj_Release(lpThis);

   return ResultFromScode(DATA_E_FORMATETC);

}

STDMETHODIMP PseudoObj_DataObj_GetCanonicalFormatEtc(

      LPDATAOBJECT    lpThis,

      LPFORMATETC     lpformatetc,

      LPFORMATETC     lpformatetcOut

)

{

   HRESULT hrErr;

   OleDbgOut2("PseudoObj_DataObj_GetCanonicalFormatEtc\r\n");

   if (!lpformatetcOut)

      return ResultFromScode(E_INVALIDARG);

   /* OLE2NOTE: we must make sure to set all out parameters to NULL. */

   lpformatetcOut->ptd = NULL;

   if (!lpformatetc)

      return ResultFromScode(E_INVALIDARG);

   // OLE2NOTE: we must validate that the format requested is supported

   if ((hrErr=lpThis->lpVtbl->QueryGetData(lpThis,lpformatetc)) != NOERROR)

      return hrErr;

   /* OLE2NOTE: an app that is insensitive to target device (as the

   **    Outline Sample is) should fill in the lpformatOut parameter

   **    but NULL out the "ptd" field; it should return NOERROR if the

   **    input formatetc->ptd what non-NULL. this tells the caller

   **    that it is NOT necessary to maintain a separate screen

   **    rendering and printer rendering. if should return

   **    DATA_S_SAMEFORMATETC if the input and output formatetc's are

   **    identical.

   */

   *lpformatetcOut = *lpformatetc;

   if (lpformatetc->ptd == NULL)

      return ResultFromScode(DATA_S_SAMEFORMATETC);

   else {

      lpformatetcOut->ptd = NULL;

      return NOERROR;

   }

}

STDMETHODIMP PseudoObj_DataObj_SetData (

      LPDATAOBJECT    lpThis,

      LPFORMATETC     lpformatetc,

      LPSTGMEDIUM     lpmedium,

      BOOL            fRelease

)

{

   LPPSEUDOOBJ lpPseudoObj =

         ((struct CPseudoObjDataObjectImpl FAR*)lpThis)->lpPseudoObj;

   LPSERVERDOC  lpServerDoc = lpPseudoObj->m_lpDoc;

   LPOUTLINEDOC  lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc;

   LPSERVERAPP lpServerApp = (LPSERVERAPP)g_lpApp;

   OleDbgOut2("PseudoObj_DataObj_SetData\r\n");

   // REVIEW: NOT-YET-IMPLEMENTED

   return ResultFromScode(E_NOTIMPL);

}

STDMETHODIMP PseudoObj_DataObj_EnumFormatEtc(

      LPDATAOBJECT            lpThis,

      DWORD                   dwDirection,

      LPENUMFORMATETC FAR*    lplpenumFormatEtc

)

{

   SCODE sc;

   OleDbgOut2("PseudoObj_DataObj_EnumFormatEtc\r\n");

   /* OLE2NOTE: a pseudo object only needs to enumerate the static list

   **    of formats that are registered for our app in the

   **    registration database. it is NOT

   **    required that a pseudo object (ie. non-DataTransferDoc)

   **    enumerate the OLE formats: CF_LINKSOURCE, CF_EMBEDSOURCE, or

   **    CF_EMBEDDEDOBJECT. we do NOT use pseudo objects for data

   **    transfers.

   **

   **    A pseudo object may NOT return OLE_S_USEREG; they must call the

   **    OleReg* API or provide their own implementation. Because this

   **    pseudo object does NOT implement IPersist, simply a low-level

   **    remoting handler (ProxyManager) object as opposed to a

   **    DefHandler object is used as the handler for the pseudo

   **    object in a clients process space. The ProxyManager does NOT

   **    handle the OLE_S_USEREG return values.

   */

   if (dwDirection == DATADIR_GET)

      return OleRegEnumFormatEtc(

            (REFCLSID)&CLSID_APP, dwDirection, lplpenumFormatEtc);

   else if (dwDirection == DATADIR_SET)

      sc = E_NOTIMPL;

   else

      sc = E_INVALIDARG;

   return ResultFromScode(sc);

}

STDMETHODIMP PseudoObj_DataObj_DAdvise(

      LPDATAOBJECT    lpThis,

      FORMATETC FAR*  lpFormatetc,

      DWORD           advf,

      LPADVISESINK    lpAdvSink,

      DWORD FAR*      lpdwConnection

)

{

   LPPSEUDOOBJ lpPseudoObj =

         ((struct CPseudoObjDataObjectImpl FAR*)lpThis)->lpPseudoObj;

   HRESULT hrErr;

   SCODE   sc;

   // artificial AddRef in case object is destroyed during call

   PseudoObj_DataObj_AddRef(lpThis);

   OLEDBG_BEGIN2("PseudoObj_DataObj_DAdvise\r\n")

   /* OLE2NOTE: we must make sure to set all out parameters to NULL. */

   *lpdwConnection = 0;

   /* OLE2NOTE: we should validate if the caller is setting up an

   **    Advise for a data type that we support. we must

   **    explicitly allow an advise for the "wildcard" advise.

   */

#ifdef WIN32

   if ( !( lpFormatetc->cfFormat == 0 &&

      lpFormatetc->ptd == 0 &&

#else

   if ( !( lpFormatetc->cfFormat == NULL &&

      lpFormatetc->ptd == NULL &&

#endif

      lpFormatetc->dwAspect == -1L &&

      lpFormatetc->lindex == -1L &&

      lpFormatetc->tymed == -1L) &&

      (hrErr = PseudoObj_DataObj_QueryGetData(lpThis, lpFormatetc))

         != NOERROR) {

      sc = GetScode(hrErr);

      goto error;

   }

   if (lpPseudoObj->m_lpDataAdviseHldr == NULL &&

      CreateDataAdviseHolder(&lpPseudoObj->m_lpDataAdviseHldr) != NOERROR) {

      sc = E_OUTOFMEMORY;

      goto error;

   }

   OLEDBG_BEGIN2("IOleAdviseHolder::Advise called\r\n")

   hrErr = lpPseudoObj->m_lpDataAdviseHldr->lpVtbl->Advise(

         lpPseudoObj->m_lpDataAdviseHldr,

         (LPDATAOBJECT)&lpPseudoObj->m_DataObject,

         lpFormatetc,

         advf,

         lpAdvSink,

         lpdwConnection

   );

   OLEDBG_END2

   OLEDBG_END2

   // release artificial AddRef

   PseudoObj_DataObj_Release(lpThis);

   return hrErr;

error:

   OLEDBG_END2

   // release artificial AddRef

   PseudoObj_DataObj_Release(lpThis);

   return ResultFromScode(sc);

}

STDMETHODIMP PseudoObj_DataObj_DUnadvise(LPDATAOBJECT lpThis, DWORD dwConnection)

{

   LPPSEUDOOBJ lpPseudoObj =

         ((struct CPseudoObjDataObjectImpl FAR*)lpThis)->lpPseudoObj;

   HRESULT hrErr;

   SCODE   sc;

   // artificial AddRef in case object is destroyed during call

   PseudoObj_DataObj_AddRef(lpThis);

   OLEDBG_BEGIN2("PseudoObj_DataObj_Unadvise\r\n");

   // no one registered

   if (lpPseudoObj->m_lpDataAdviseHldr == NULL) {

      sc = E_FAIL;

      goto error;

   }

   OLEDBG_BEGIN2("IOleAdviseHolder::DUnadvise called\r\n")

   hrErr = lpPseudoObj->m_lpDataAdviseHldr->lpVtbl->Unadvise(

         lpPseudoObj->m_lpDataAdviseHldr,

         dwConnection

   );

   OLEDBG_END2

   OLEDBG_END2

   // release artificial AddRef

   PseudoObj_DataObj_Release(lpThis);

   return hrErr;

error:

   OLEDBG_END2

   // release artificial AddRef

   PseudoObj_DataObj_Release(lpThis);

   return ResultFromScode(sc);

}

STDMETHODIMP PseudoObj_DataObj_EnumAdvise(

      LPDATAOBJECT lpThis,

      LPENUMSTATDATA FAR* lplpenumAdvise

)

{

   LPPSEUDOOBJ lpPseudoObj =

         ((struct CPseudoObjDataObjectImpl FAR*)lpThis)->lpPseudoObj;

   HRESULT hrErr;

   SCODE   sc;

   // artificial AddRef in case object is destroyed during call

   PseudoObj_DataObj_AddRef(lpThis);

   OLEDBG_BEGIN2("PseudoObj_DataObj_EnumAdvise\r\n");

   /* OLE2NOTE: we must make sure to set all out parameters to NULL. */

   *lplpenumAdvise = NULL;

   if (lpPseudoObj->m_lpDataAdviseHldr == NULL) {

      sc = E_FAIL;

      goto error;

   }

   OLEDBG_BEGIN2("IOleAdviseHolder::EnumAdvise called\r\n")

   hrErr = lpPseudoObj->m_lpDataAdviseHldr->lpVtbl->EnumAdvise(

         lpPseudoObj->m_lpDataAdviseHldr,

         lplpenumAdvise

   );

   OLEDBG_END2

   OLEDBG_END2

   // release artificial AddRef

   PseudoObj_DataObj_Release(lpThis);

   return hrErr;

error:

   OLEDBG_END2

   // release artificial AddRef

   PseudoObj_DataObj_Release(lpThis);

   return ResultFromScode(sc);

}


 SPOLY

------------------------------------ OLE Automation Sample Program: SPoly ------------------------------------

SPoly is a program which draws polygons.  The only way to make spoly draw a polygon is to use its programmability  interface.

One OLE Automation object is exposed by Spoly:

  * spoly.application

Spoly.Application is the object associated with spoly's main window.  It controls drawing polygons and clearing the display.

----------------- Program Structure ----------------- SPoly implements IDispatch by hand for spoly.application.

------------------------------------ Methods defined on spoly.application ------------------------------------

Name                            Description ------------------------------------------------------------------ Draw()	Draw the polygon.

Reset()	Delete all points from the polygon.

AddPoint(X, Y)	Add a point with coordinates (x,y)  	to the polygon

EnumPoints() as VT_ENUM	Return a collection of the polygon's  	points

GetXOrigin() as short	Get the X origin of the polygon. 	 SetXOrigin(x as short)	Set the X origin of the polygon. 	 GetYOrigin() as short	Get the Y origin of the polygon. 	 SetYOrigin(y as short)	Set the Y origin of the polygon. 	 GetWidth() as short	Get and the line width of the polygon.

SetWidth(width as short)	Set the line width of the polygon.

--------------------------- Shortcomings of this sample --------------------------- 1. Many items in this sample should be properties.  Instead, they are implemented as methods.  Anything which behaves like an attribute of the object should be a property.

2. This is not a good example of how to implement a collection.


 MAKEFILE  (SPOLY Sample)

##############################################################################

#

#  (c) Copyright Microsoft Corp. 1992-1993 All Rights Reserved

#

#  File:

#

#    makefile - makefile for spoly.exe

#

#  Purpose:

#

#    Builds the OLE 2.0 sample IDispatch server, spoly.exe.

#

#

#  Usage:

#

#     NMAKE                     ; build with defaults

#     or: NMAKE option          ; build with the given option(s)

#     or: NMAKE clean           ; erase all compiled files

#

#     option:

#         dev = [win16 | win32] ; dev=win32 is the default

#         DEBUG=[0|1]           ; DEBUG=1 is the default

#

#  Notes:

#

#    This makefile assumes that the PATH, INCLUDE and LIB environment

#    variables are setup properly.

#

##############################################################################

##########################################################################

#

# Default Settings

#

!if "$(dev)" == ""

dev = win32

!endif

!if !("$(dev)" == "win16" || "$(dev)" == "win32")

!error Invalid dev option, choose from [win16 | win32]

!endif

!if "$(dev)" == "win16"

TARGET  = WIN16

!endif

!if "$(dev)" == "win32"

TARGET  = WIN32

!endif

!ifdef NODEBUG

DEBUG = 0

!endif

!if "$(DEBUG)" == "0"

NODEBUG = 1

!endif

!if "$(DEBUG)" == ""

DEBUG = 1

!endif

##########################################################################

#

# WIN16 Settings

#

!if "$(TARGET)" == "WIN16"

CC   = cl

LINK = link

RCFLAGS = -dWIN16

CFLAGS = -c -W3 -AM -GA -GEs -DWIN16

LINKFLAGS = /NOD /NOI /BATCH /ONERROR:NOEXE

LIBS = libw.lib mlibcew.lib

!if "$(DEBUG)" == "1"

CFLAGS = $(CFLAGS) -Od -Zi -D_DEBUG $(CL)

LINKFLAGS = $(LINKFLAGS) /COD

!else

CFLAGS = $(CFLAGS) -Ox $(CL)

LINKFLAGS = $(LINKFLAGS) /FAR /PACKC

!endif

!endif

##########################################################################

#

# WIN32 Settings

#

!if "$(TARGET)" == "WIN32"

!include <$(MSTOOLS)\samples\ole\include\olesampl.mak>

CC = $(cc)

CFLAGS = $(cflags) $(cvarsmt) -DUNICODE $(cdebug)

!ifndef NODEBUG

CFLAGS = $(CFLAGS) -D_DEBUG

!endif

LINK = $(link)

LINKFLAGS = $(linkdebug) $(guilflags)

RCFLAGS = -DWIN32

!endif

##########################################################################

#

# Application Settings

#

!if "$(TARGET)" == "WIN16"

LIBS = ole2.lib compobj.lib ole2disp.lib ole2nls.lib $(LIBS)

!else

!if "$(TARGET)" == "WIN32"

LIBS = $(olelibsmt)

!endif

!endif

OBJS = \

        winmain.obj     \

        cpoly.obj       \

        cpoint.obj      \

        cenumpt.obj     \

        statbar.obj     \

        clsid.obj       \

        misc.obj

goal : setflags spoly.exe

setflags :

        set CL=$(CFLAGS)

clean :

    if exist *.obj       del *.obj

    if exist spoly.exe del spoly.exe

    if exist spoly.map del spoly.map

    if exist spoly.res del spoly.res

    if exist *.pdb       del *.pdb

##########################################################################

#

# Application Build (WIN16 Specific)

#

!if "$(TARGET)" == "WIN16"

spoly.exe : $(OBJS) spoly.def spoly.res spoly.ico

        link $(LINKFLAGS) @<<

$(OBJS),

$@,,

$(LIBS),

spoly.def

<<

        rc -k -t spoly.res $@

!endif

##########################################################################

#

# Application Build (WIN32 Specific)

#

!if "$(TARGET)" == "WIN32"

spoly.exe : $(OBJS) spoly.def spoly.res spoly.ico

      $(LINK) @<<

        $(LINKFLAGS)

        -out:$@

        -map:$*.map

        $(OBJS)

        spoly.res

        $(LIBS)

<<

!endif

spoly.res : spoly.rc resource.h

        rc $(RCFLAGS) -r -fo$@ spoly.rc

winmain.obj: winmain.cpp hostenv.h resource.h spoly.h cpoint.h cpoly.h statbar.h

        $(CC) winmain.cpp

cpoint.obj: cpoint.cpp cpoint.h hostenv.h spoly.h statbar.h

        $(CC) cpoint.cpp

cpoly.obj: cpoly.cpp cpoint.h cpoly.h hostenv.h spoly.h statbar.h

        $(CC) cpoly.cpp

clsid.obj: clsid.c clsid.h

        $(CC) clsid.c

cenumpt.obj: cenumpt.cpp cenumpt.h

        $(CC) cenumpt.cpp

statbar.obj: statbar.cpp statbar.h

        $(CC) statbar.cpp

misc.obj: misc.cpp hostenv.h spoly.h

        $(CC) misc.cpp


 CENUMPT.H  (SPOLY Sample)

/***

*cenumpt.h

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*  Information Contained Herein Is Proprietary and Confidential.

*

*Purpose:

*  Definition of the CEnumPoint class.

*

*Implementation Notes:

*

*****************************************************************************/

class CEnumPoint : public IEnumVARIANT

{

public:

    static HRESULT Create(SAFEARRAY FAR* psa, CEnumPoint FAR* FAR* ppenum);

    /* IUnknown methods */

    STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppv);

    STDMETHOD_(unsigned long, AddRef)(void);

    STDMETHOD_(unsigned long, Release)(void);

    /* IEnumVARIANT methods */

    STDMETHOD(Next)(unsigned long celt, VARIANT FAR* rgvar, unsigned long FAR* pceltFetched);

    STDMETHOD(Skip)(unsigned long celt);

    STDMETHOD(Reset)(void);

    STDMETHOD(Clone)(IEnumVARIANT FAR* FAR* ppenum);

    CEnumPoint();

private:

    unsigned long m_refs;

    unsigned long m_celts;

    unsigned long m_iCurrent;

    SAFEARRAY FAR* m_psa;

};


 CENUMPT.CPP  (SPOLY Sample)

/***

*cenumpt.cpp

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*

*Purpose:

*  This module implements the CEnumPoint class.

*

*

*Implementation Notes:

*

*****************************************************************************/

#include "hostenv.h"

#include "cenumpt.h"

CEnumPoint::CEnumPoint()

{

    m_refs = 0;

    m_psa = NULL;

    m_celts = 0;

    m_iCurrent = 0;

}

/***

*HRESULT CEnumPoint::Create(SAFEARRAY*, CEnumPoint**)

*Purpose:

*  This routine creates a CPoint enumerator from the given

*  (1 X N) SafeArray of CPoint IDispatch pointers.

*

*Entry:

*  psa = pointer to a SafeArray of VARIANTs

*

*Exit:

*  return value = HRESULT

*

*  *ppenum = pointer to a CPoint enumerator

*

***********************************************************************/

HRESULT

CEnumPoint::Create(SAFEARRAY FAR* psa, CEnumPoint FAR* FAR* ppenum)

{

    long lBound;

    HRESULT hresult;

    CEnumPoint FAR* penum;

    // Verify that the SafeArray is the proper shape.

    //

    if(SafeArrayGetDim(psa) != 1)

      return ResultFromScode(E_INVALIDARG);

    hresult = SafeArrayGetLBound(psa, 1, &lBound);

    if(FAILED(hresult))

      return hresult;

    if(lBound != 0)

      return ResultFromScode(E_INVALIDARG);

    penum = new FAR CEnumPoint();

    if(penum == NULL)

      return ResultFromScode(E_OUTOFMEMORY);

    penum->AddRef();

    hresult = SafeArrayGetUBound(psa, 1, &lBound);

    if(FAILED(hresult))

      goto LError0;

    penum->m_psa = psa;

    penum->m_celts = lBound + 1;

    *ppenum = penum;

    return NOERROR;

LError0:;

    penum->Release();

    return hresult;

}

//---------------------------------------------------------------------

//                        IUnknown methods

//---------------------------------------------------------------------

STDMETHODIMP

CEnumPoint::QueryInterface(REFIID riid, void FAR* FAR* ppv)

{

    if(!IsEqualIID(riid, IID_IUnknown))

      if(!IsEqualIID(riid, IID_IEnumVARIANT)) {

        *ppv = NULL;

        return ResultFromScode(E_NOINTERFACE);

    }

    *ppv = this;

    AddRef();

    return NOERROR;

}

STDMETHODIMP_(unsigned long)

CEnumPoint::AddRef()

{

    return ++m_refs;

}

STDMETHODIMP_(unsigned long)

CEnumPoint::Release()

{

    if(--m_refs == 0){

      if(m_psa != NULL)

SafeArrayDestroy(m_psa);

      delete this;

      return 0;

    }

    return m_refs;

}

//---------------------------------------------------------------------

//                        IEnumVARIANT methods

//---------------------------------------------------------------------

/***

*HRESULT CEnumPoint::Next(unsigned long, VARIANT*, unsigned long*)

*Purpose:

*  Attempt to get the next 'celt' items in the enumeration sequence.

*

*Entry:

*  celt = the number of elements to get

*

*Exit:

*  return value = HRESULT

*    S_OK

*    S_FALSE - the end of the sequence was reached

*

*  rgvar = array of the next 'celt' items

*  *pceltFetched = count of the elements actually fetched.

*

***********************************************************************/

STDMETHODIMP

CEnumPoint::Next(

    unsigned long celt,

    VARIANT FAR* rgvar,

    unsigned long FAR* pceltFetched)

{

    long ix;

    unsigned int i;

    HRESULT hresult;

    for(i = 0; i < celt; ++i)

      VariantInit(&rgvar[i]);

    for(i = 0; i < celt; ++i){

      if(m_iCurrent == m_celts){

        hresult = ResultFromScode(S_FALSE);

goto LDone;

      }

      ix = m_iCurrent++;

      hresult = SafeArrayGetElement(m_psa, &ix, &rgvar[i]);

      if(FAILED(hresult))

goto LError0;

    }

    hresult = NOERROR;

LDone:;

    if (pceltFetched != NULL)

      *pceltFetched = i;

    return hresult;

LError0:;

    for(i = 0; i < celt; ++i)

      VariantClear(&rgvar[i]);

    return hresult;

}

/***

*HRESULT CEnumPoint::Skip(unsigned long)

*Purpose:

*  Attempt to skip over the next 'celt' elements in the enumeration

*  sequence.

*

*Entry:

*  celt = the count of elements to skip

*

*Exit:

*  return value = HRESULT

*    S_OK

*    S_FALSE -  the end of the sequence was reached

*

***********************************************************************/

STDMETHODIMP

CEnumPoint::Skip(unsigned long celt)

{

    m_iCurrent += celt;

    if(m_iCurrent > m_celts)

     m_iCurrent = m_celts;

    return (m_iCurrent == m_celts)

      ? ResultFromScode(S_FALSE) : NOERROR;

}

/***

*HRESULT CEnumPoint::Reset(void)

*Purpose:

*  Reset the enumeration sequence back to the beginning.

*

*Entry:

*  None

*

*Exit:

*  return value = SHRESULT CODE

*    S_OK

*

***********************************************************************/

STDMETHODIMP

CEnumPoint::Reset()

{

    m_iCurrent = 0;

    return NOERROR;

}

/***

*HRESULT CEnumPoint::Clone(IEnumVARIANT**)

*Purpose:

*  Retrun a CPoint enumerator with exactly the same state as the

*  current one.

*

*Entry:

*  None

*

*Exit:

*  return value = HRESULT

*    S_OK

*    E_OUTOFMEMORY

*

***********************************************************************/

STDMETHODIMP

CEnumPoint::Clone(IEnumVARIANT FAR* FAR* ppenum)

{

    HRESULT hresult;

    SAFEARRAY FAR* psa;

    CEnumPoint FAR* penum;

    hresult = SafeArrayCopy(m_psa, &psa);

    if(FAILED(hresult))

      return hresult;

    hresult = CEnumPoint::Create(psa, &penum);

    if(FAILED(hresult))

      goto LError0;

    // Assert(penum->m_celts == m_celts);

    penum->m_iCurrent = m_iCurrent;

    *ppenum = penum;

    return NOERROR;

LError0:

    SafeArrayDestroy(psa);

    return hresult;

}


 CLSID.H  (SPOLY Sample)

/***

*clsid.h

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*  Information Contained Herein Is Proprietary and Confidential.

*

*Purpose:

*  This file defines the CLSIDs

*

*Implementation Notes:

*

*****************************************************************************/

DEFINE_GUID(CLSID_CPoly, 0x00020462, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46);

DEFINE_GUID(CLSID_CPoint, 0x00020463, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46);

#ifdef INITGUID

# ifdef _MAC

DEFINE_GUID(GUID_NULL, 0L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);

DEFINE_GUID(IID_IDispatch, 0x00020400L, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46);

DEFINE_GUID(IID_IEnumVARIANT, 0x00020404L, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46);

DEFINE_GUID(IID_IUnknown, 0x00000000L, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46);

DEFINE_GUID(IID_IClassFactory, 0x00000001L, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46);

# endif

#endif


 CLSID.C  (SPOLY Sample)

/***

*clsid.c

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*  Information Contained Herein Is Proprietary and Confidential.

*

*Purpose:

*  This file allocates and initializes the CLSIDs.

*

*****************************************************************************/

#ifdef _PPCMAC

#pragma data_seg ("_FAR_DATA")

#pragma data_seg ( )

#endif //_PPCMAC

#ifdef _MAC

# include <Types.h>

#ifdef _MSC_VER

# include <Processe.h>

# include <AppleEve.h>

#else //_MSC_VER

# include <Processes.h>

# include <AppleEvents.h>

#endif //_MSC_VER

#else

# include <windows.h>

#endif

#ifndef WIN32

#include <compobj.h>

#endif //!WIN32

// this redefines the DEFINE_GUID() macro to do allocation.

//

#include <initguid.h>

#ifndef INITGUID

# define INITGUID

#endif

// due to the previous header, including this causes the DEFINE_GUID

// definitions in the following header(s) to actually allocate data.

//

#include "clsid.h"


 CPOINT.H  (SPOLY Sample)

/***

*cpoint.h

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*  Information Contained Herein Is Proprietary and Confidential.

*

*Purpose:

*  Definition of the CPoint class.

*

*  The CPoint object exposes two properties for programatic access

*  via the IDispatch interface.

*

*  properties:

*    X 	- the 'x' coordinate of the point

*    Y 	- the 'y' coordinate of the point

*

*Implementation Notes:

*

*****************************************************************************/

#ifndef	CLASS

#ifdef	__TURBOC__

#define CLASS class huge

#else

#define CLASS class FAR

#endif

#endif

class CPoly;

CLASS CPoint : public IDispatch {

    friend class CPoly;

public:

    static CPoint FAR* Create();

    /* IUnknown methods */

    STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppvObj);

    STDMETHOD_(unsigned long, AddRef)(void);

    STDMETHOD_(unsigned long, Release)(void);

    /* IDispatch methods */

    STDMETHOD(GetTypeInfoCount)(unsigned int FAR* pcTypeInfo);

    STDMETHOD(GetTypeInfo)(

      unsigned int iTypeInfo,

      LCID lcid,

      ITypeInfo FAR* FAR* ppTypeInfo);

    STDMETHOD(GetIDsOfNames)(

      REFIID riid,

      OLECHAR FAR* FAR* rgszNames,

      unsigned int cNames,

      LCID lcid,

      DISPID FAR* rgdispid);

    STDMETHOD(Invoke)(

      DISPID dispidMember,

      REFIID riid,

      LCID lcid,

      unsigned short wFlags,

      DISPPARAMS FAR* pdispparams,

      VARIANT FAR* pvarResult,

      EXCEPINFO FAR* pexcepinfo,

      unsigned int FAR* pwArgErr);

    /* Introduced methods */

    virtual short PASCAL GetX(void);

    virtual void  PASCAL SetX(short x);

    virtual short PASCAL GetY(void);

    virtual void  PASCAL SetY(short y);

private:

    CPoint();

    unsigned long m_refs;

    short m_x;

    short m_y;

};

// member DISPIDs

//

enum IDMEMBER_CPOINT {

    IDMEMBER_CPOINT_GETX = 1,

    IDMEMBER_CPOINT_SETX,

    IDMEMBER_CPOINT_GETY,

    IDMEMBER_CPOINT_SETY,

    IDMEMBER_CPOINT_MAX

};

// structure used to link together lists of points

//

struct POINTLINK {

    POINTLINK FAR* next;

    CPoint FAR* ppoint;

};

// The CPoint Class Factory

//

CLASS CPointCF : public IClassFactory

{

public:

    static IClassFactory FAR* Create();

    /* IUnknown methods */

    STDMETHOD(QueryInterface)(REFIID iid, void FAR* FAR* ppv);

    STDMETHOD_(unsigned long, AddRef)(void);

    STDMETHOD_(unsigned long, Release)(void);

    /* IClassFactory methods */

    STDMETHOD(CreateInstance)(

      IUnknown FAR* pUnkOuter, REFIID iid, void FAR* FAR* ppv);

#ifdef _MAC

    STDMETHOD(LockServer)(unsigned long fLock);

#else

    STDMETHOD(LockServer)(BOOL fLock);

#endif

private:

    CPointCF();

    unsigned long m_refs;

};


 CPOINT.CPP  (SPOLY Sample)

/***

*cpoint.cpp

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*

*Purpose:

*  This module implements the CPoint and CPointCF classes.

*

*  This module is intended as a sample implementation of the IDispatch

*  interface, and its purpose is to demonstrate how an object can

*  expose methods and properties for programatic and cross-process

*  access via the IDispatch interface.

*

*Implementation Notes:

*

*****************************************************************************/

#include "spoly.h"

#include "cpoint.h"

CPoint::CPoint()

{

    m_x = 0;

    m_y = 0;

    m_refs = 0;

}

/***

*CPoint::Create(void)

*Purpose:

*  Create an instance of a CPoint object.

*

*Entry:

*  None

*

*Exit:

*  returns a CPoint*, NULL if creation failed.

*

***********************************************************************/

CPoint FAR*

CPoint::Create()

{

    CPoint FAR* ppoint;

    if((ppoint = new FAR CPoint()) == NULL)

      return NULL;

    ppoint->AddRef();

    return ppoint;

}

//---------------------------------------------------------------------

//                     IUnknown Methods

//---------------------------------------------------------------------

STDMETHODIMP

CPoint::QueryInterface(REFIID riid, void FAR* FAR* ppv)

{

    if(!IsEqualIID(riid, IID_IUnknown))

      if(!IsEqualIID(riid, IID_IDispatch)) {

        *ppv = NULL;

        return ResultFromScode(E_NOINTERFACE);

    }

    *ppv = this;

    AddRef();

    return NOERROR;

}

STDMETHODIMP_(unsigned long)

CPoint::AddRef(void)

{

    return ++m_refs;

}

STDMETHODIMP_(unsigned long)

CPoint::Release(void)

{

    if(--m_refs == 0){

      delete this;

      return 0;

    }

    return m_refs;

}

//---------------------------------------------------------------------

//                     IDispatch methods

//---------------------------------------------------------------------

/*

 * NOTE: Support for the following two methods is not available

 * in this version.

 *

 */

STDMETHODIMP

CPoint::GetTypeInfoCount(unsigned int FAR* pctinfo)

{

    *pctinfo = 0;

    return NOERROR;

}

STDMETHODIMP

CPoint::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)

{

    UNUSED(itinfo);

    UNUSED(lcid);

    UNUSED(pptinfo);

    return ResultFromScode(E_NOTIMPL);

}

/***

*HRESULT CPoint::GetIDsOfNames(REFIID, OLECHAR**, unsigned int, LCID, long*)

*Purpose:

*  This method translates the given array of names to a corresponding

*  array of DISPIDs.

*

*  Index 0 of the name array is the member name, and indices 1-N if

*  present represent named parameters on that member.

*

*  The local ID ('lcid') is unused by this naive implementation. A more

*  sophisticated implementation, sensitive to localization and natural

*  language support would use the locale ID to interpret the given names

*  in a correct locale specific context.

*

*Entry:

*  rgszNames = pointer to an array of names

*  cNames = the number of names in the rgszNames array

*  lcid = the callers locale ID

*

*Exit:

*  return value = HRESULT

*  rgid = array of name IDs corresponding to the rgszNames array

*    this array will contain -1 for each entry that is not known.

*

***********************************************************************/

STDMETHODIMP

CPoint::GetIDsOfNames(

    REFIID riid,

    OLECHAR FAR* FAR* rgszNames,

    unsigned int cNames,

    LCID lcid,

    DISPID FAR* rgdispid)

{

static MEMBERDESC rgmdCPoint[] = {

    {OLESTR("GETX"),	IDMEMBER_CPOINT_GETX,	NULL,	0},

    {OLESTR("SETX"),	IDMEMBER_CPOINT_SETX,	NULL,	0},

    {OLESTR("GETY"),	IDMEMBER_CPOINT_GETY,	NULL,	0},

    {OLESTR("SETY"),	IDMEMBER_CPOINT_SETY,	NULL,	0}

};

    // this object only exposed the "default" interface.

    //

    if(!IsEqualIID(riid, IID_NULL))

      return ResultFromScode(DISP_E_UNKNOWNINTERFACE);

    return SPolyGetIDsOfNames(

      rgmdCPoint, DIM(rgmdCPoint), rgszNames, cNames, lcid, rgdispid);

}

/***

*HRESULT CPoint::Invoke(...)

*Purpose:

*  Dispatch a method or property request for objects of type CPoint.

*

*  see the IDispatch document for more information, and a general

*  description of this method.

*

*Entry:

*  dispidMember = the DISPID of the member being requested

*

*  riid = reference to the interface ID of the interface on this object

*    that the requested member belongs to. IID_NULL means to interpret

*    the member as belonging to the implementation defined "default"

*    or "primary" interface.

*

*  lcid = the caller's locale ID

*

*  wFlags = flags indicating the type of access being requested

*

*  pdispparams = pointer to the DISPPARAMS struct containing the

*    requested members arguments (if any) and its named parameter

*    DISPIDs (if any).

*

*Exit:

*  return value = HRESULT

*   see the IDispatch spec for a description of possible success codes.

*

*  pvarResult = pointer to a caller allocated VARIANT containing

*    the members return value (if any).

*

*  pexcepinfo = caller allocated exception info structure, this will

*    be filled in only if an exception was raised that must be passed

*    up through Invoke to an enclosing handler.

*

*  puArgErr = pointer to a caller allocated UINT, that will contain the

*    index of the offending argument if a DISP_E_TYPEMISMATCH error

*    was returned indicating that one of the arguments was of an

*    incorrect type and/or could not be reasonably coerced to a proper

*    type.

*

***********************************************************************/

STDMETHODIMP

CPoint::Invoke(

    DISPID dispidMember,

    REFIID riid,

    LCID lcid,

    unsigned short wFlags,

    DISPPARAMS FAR* pdispparams,

    VARIANT FAR* pvarResult,

    EXCEPINFO FAR* pexcepinfo,

    unsigned int FAR* puArgErr)

{

    unsigned int uArgErr;

    HRESULT hresult;

    VARIANTARG varg0;

    VARIANT varResultDummy;

    UNUSED(lcid);

    UNUSED(pexcepinfo);

    // make sure the wFlags are legal

    if(wFlags & ~(DISPATCH_METHOD | DISPATCH_PROPERTYGET | DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYPUTREF))

      return ResultFromScode(E_INVALIDARG);

    // this object only exposes a "default" interface.

    //

    if(!IsEqualIID(riid, IID_NULL))

      return ResultFromScode(DISP_E_UNKNOWNINTERFACE);

    // this makes the following code a bit simpler

    if(puArgErr == NULL)

      puArgErr = &uArgErr;

    if(pvarResult == NULL)

      pvarResult = &varResultDummy;

    VariantInit(&varg0);

    // assume the return type is void, unless we find otherwise.

    VariantInit(pvarResult);

    switch(dispidMember){

    case IDMEMBER_CPOINT_GETX:

      V_VT(pvarResult) = VT_I2;

      V_I2(pvarResult) = GetX();

      break;

    case IDMEMBER_CPOINT_SETX:

      hresult = DispGetParam(pdispparams, 0, VT_I2, &varg0, puArgErr);

      if(hresult != NOERROR)

        return hresult;

      SetX(V_I2(&varg0));

      break;

    case IDMEMBER_CPOINT_GETY:

      V_VT(pvarResult) = VT_I2;

      V_I2(pvarResult) = GetY();

      break;

    case IDMEMBER_CPOINT_SETY:

      hresult = DispGetParam(pdispparams, 0, VT_I2, &varg0, puArgErr);

      if(hresult != NOERROR)

        return hresult;

      SetY(V_I2(&varg0));

      break;

    default:

      return ResultFromScode(DISP_E_MEMBERNOTFOUND);

    }

    return NOERROR;

}

short PASCAL

CPoint::GetX()

{

    return m_x;

}

void PASCAL

CPoint::SetX(short x)

{

    m_x = x;

}

short PASCAL

CPoint::GetY()

{

    return m_y;

}

void PASCAL

CPoint::SetY(short y)

{

    m_y = y;

}

//---------------------------------------------------------------------

//         Implementation of the CPoint Class Factory

//---------------------------------------------------------------------

CPointCF::CPointCF()

{

    m_refs = 0;

}

IClassFactory FAR*

CPointCF::Create()

{

    CPointCF FAR* pCF;

    if((pCF = new FAR CPointCF()) == NULL)

      return NULL;

    pCF->AddRef();

    return pCF;

}

STDMETHODIMP

CPointCF::QueryInterface(REFIID riid, void FAR* FAR* ppv)

{

    if(!IsEqualIID(riid, IID_IUnknown))

      if(!IsEqualIID(riid, IID_IClassFactory)) {

        *ppv = NULL;

        return ResultFromScode(E_NOINTERFACE);

    }

    *ppv = this;

    ++m_refs;

    return NOERROR;

}

STDMETHODIMP_(unsigned long)

CPointCF::AddRef(void)

{

    return ++m_refs;

}

STDMETHODIMP_(unsigned long)

CPointCF::Release(void)

{

    if(--m_refs == 0){

      delete this;

      return 0;

    }

    return m_refs;

}

STDMETHODIMP

CPointCF::CreateInstance(

    IUnknown FAR* punkOuter,

    REFIID riid,

    void FAR* FAR* ppv)

{

    HRESULT hresult;

    CPoint FAR *ppoint;

    UNUSED(punkOuter);

    if((ppoint = CPoint::Create()) == NULL){

      *ppv = NULL;

      return ResultFromScode(E_OUTOFMEMORY);

    }

    hresult = ppoint->QueryInterface(riid, ppv);

    ppoint->Release();

    return hresult;

}

STDMETHODIMP

#ifdef _MAC

CPointCF::LockServer(unsigned long fLock)

#else

CPointCF::LockServer(BOOL fLock)

#endif

{

    UNUSED(fLock);

    return NOERROR;

}


 CPOLY.H  (SPOLY Sample)

/***

*cpoly.h

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*  Information Contained Herein Is Proprietary and Confidential.

*

*Purpose:

*  Definition of the CPoly class.

*

*  The CPoly class defines a number of methods and exposes them for

*  external programmability via IDispatch,

*

*  methods:

*    DRAW	- draw the polygon

*    RESET	- delete all points from the polygon

*

*    ADDPOINT(X, Y)	- add a point with coordinates (x,y) to the polygon

*

*    ENUMPOINTS	- return a collection of the polygon's points

*

*    GETXORIGIN	- get and set the X origin of the polygon

*    SETXORIGIN

*

*    GETYORIGIN	- get and set the Y origin of the polygon

*    SETYORIGIN

*

*    GETWIDTH	- get and set the line width of the polygon

*    SETWIDTH

*

*  UNDONE: update description

*

*Implementation Notes:

*

*****************************************************************************/

#ifndef	CLASS

# ifdef	__TURBOC__

#  define CLASS class huge

# else

#  define CLASS class FAR

# endif

#endif

class CPoint;

CLASS CPoly : public IDispatch

{

public:

    static CPoly FAR* Create();

    /* IUnknown methods */

    STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppvObj);

    STDMETHOD_(unsigned long, AddRef)(void);

    STDMETHOD_(unsigned long, Release)(void);

    /* IDispatch methods */

    STDMETHOD(GetTypeInfoCount)(unsigned int FAR* pcTypeInfo);

    STDMETHOD(GetTypeInfo)(

      unsigned int iTypeInfo,

      LCID lcid,

      ITypeInfo FAR* FAR* ppTypeInfo);

    STDMETHOD(GetIDsOfNames)(

      REFIID riid,

      OLECHAR FAR* FAR* rgszNames,

      unsigned int cNames,

      LCID lcid,

      DISPID FAR* rgdispid);

    STDMETHOD(Invoke)(

      DISPID dispidMember,

      REFIID riid,

      LCID lcid,

      unsigned short wFlags,

      DISPPARAMS FAR* pdispparams,

      VARIANT FAR* pvarResult,

      EXCEPINFO FAR* pexcepinfo,

      unsigned int FAR* puArgErr);

    /* Introduced methods */

    virtual void PASCAL Draw(void);

    virtual void PASCAL Reset(void);

    // add a point with the given 'x' and 'y' coordinates

    virtual HRESULT PASCAL AddPoint(short x, short y);

    // return a collection of the polygon's points

    virtual HRESULT PASCAL EnumPoints(IEnumVARIANT FAR* FAR* ppenum);

    // get/set the polygon's X origin property

    virtual short PASCAL GetXOrigin(void);

    virtual void  PASCAL SetXOrigin(short x);

    // get/set the polygon's Y origin property

    virtual short PASCAL GetYOrigin(void);

    virtual void  PASCAL SetYOrigin(short y);

    virtual short PASCAL GetWidth(void);

    virtual void  PASCAL SetWidth(short width);

    virtual short PASCAL get_red(void);

    virtual void  PASCAL set_red(short red);

    virtual short PASCAL get_green(void);

    virtual void  PASCAL set_green(short green);

    virtual short PASCAL get_blue(void);

    virtual void  PASCAL set_blue(short blue);

    // Debug method

    virtual void  PASCAL Dump(void);

public:

    // Draw all polygons.

    static void PolyDraw(void);

    // Release all polygons.

    static void PolyTerm(void);

    // Dump all polygons to dbwin.

    static void PolyDump(void);

private:

    CPoly();

    short m_xorg;

    short m_yorg;

    short m_width;

    short m_red;

    short m_green;

    short m_blue;

    unsigned long m_refs;

    unsigned int m_cPoints;

    POINTLINK FAR* m_ppointlink;

    POINTLINK FAR* m_ppointlinkLast;

};

// DISPIDs for the members and properties available via IDispatch.

//

enum IDMEMBER_CPOLY {

    IDMEMBER_CPOLY_DRAW = 1,

    IDMEMBER_CPOLY_RESET,

    IDMEMBER_CPOLY_ADDPOINT,

    IDMEMBER_CPOLY_ENUMPOINTS,

    IDMEMBER_CPOLY_GETXORIGIN,

    IDMEMBER_CPOLY_SETXORIGIN,

    IDMEMBER_CPOLY_GETYORIGIN,

    IDMEMBER_CPOLY_SETYORIGIN,

    IDMEMBER_CPOLY_GETWIDTH,

    IDMEMBER_CPOLY_SETWIDTH,

    IDMEMBER_CPOLY_GETRED,

    IDMEMBER_CPOLY_SETRED,

    IDMEMBER_CPOLY_GETGREEN,

    IDMEMBER_CPOLY_SETGREEN,

    IDMEMBER_CPOLY_GETBLUE,

    IDMEMBER_CPOLY_SETBLUE,

    IDMEMBER_CPOLY_DUMP,

    IDMEMBER_CPOLY_MAX

};

// structure used to link together polygons

//

struct POLYLINK {

    POLYLINK FAR* next;

    CPoly FAR* ppoly;

};

// The CPoly class factory

//

CLASS CPolyCF : public IClassFactory

{

public:

    static IClassFactory FAR* Create();

    /* IUnknown methods */

    STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppv);

    STDMETHOD_(unsigned long, AddRef)(void);

    STDMETHOD_(unsigned long, Release)(void);

    /* IClassFactory methods */

    STDMETHOD(CreateInstance)(

      IUnknown FAR* pUnkOuter, REFIID riid, void FAR* FAR* ppv);

#ifdef _MAC

    STDMETHOD(LockServer)(unsigned long fLock);

#else

    STDMETHOD(LockServer)(BOOL fLock);

#endif

private:

    CPolyCF();

    unsigned long m_refs;

};


 CPOLY.CPP  (SPOLY Sample)

/***

*CPoly.cpp

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*

*Purpose:

*  This module implements the CPoly and CPolyCF classes.

*

*  This module is intended as a sample implementation of the IDispatch

*  interface, and its purpose is to demonstrate how an object can

*  expose methods and properties for programatic and cross-process

*  access via the IDispatch interface.

*

*Implementation Notes:

*

*****************************************************************************/

#include "spoly.h"

#include "cpoint.h"

#include "cpoly.h"

#include "cenumpt.h"

#ifndef _MAC

extern CStatBar FAR* g_psb;

#else

extern "C" WindowPtr g_pwndClient;

#endif

// our global list of polygons.

//

POLYLINK FAR* g_ppolylink = (POLYLINK FAR*)NULL;

// global count of polygons.

//

int g_cPoly = 0;

CPoly::CPoly()

{

    m_refs = 0;

    m_xorg = 0;

    m_yorg = 0;

    m_width = 0;

    m_cPoints = 0;

    m_red   = 0;

    m_green = 0;

    m_blue  = 0;

    m_ppointlink = NULL;

    m_ppointlinkLast = NULL;

}

/***

*CPoly *CPoly::Create(void)

*Purpose:

*  Create an instance of a CPoly object, and add it to the global

*  list of polygons.

*

*Entry:

*  None

*

*Exit:

*  returns a polygon object, NULL the allocation failed.

*

***********************************************************************/

CPoly FAR*

CPoly::Create()

{

    CPoly FAR* ppoly;

    POLYLINK FAR* ppolylink;

    if((ppolylink = new FAR POLYLINK) == (POLYLINK FAR*)NULL)

      return (CPoly FAR*)NULL;

    if((ppoly = new FAR CPoly()) == (CPoly FAR*)NULL)

      return (CPoly FAR*)NULL;

    ppoly->AddRef();

    // push the new polygon onto the front of the polygon list.

    //

    ++g_cPoly;

    ppolylink->ppoly = ppoly;

    ppolylink->next = g_ppolylink;

    g_ppolylink = ppolylink;

#ifndef _MAC

    SBprintf(g_psb, TSTR("#poly = %d"), g_cPoly);

#endif

    return ppoly;

}

//---------------------------------------------------------------------

//                     IUnknown Methods

//---------------------------------------------------------------------

STDMETHODIMP

CPoly::QueryInterface(REFIID riid, void FAR* FAR* ppv)

{

    if(IsEqualIID(riid, IID_IUnknown) ||

       IsEqualIID(riid, IID_IDispatch)) {

      *ppv = this;

      AddRef();

      return NOERROR;

    }

    *ppv = NULL;

    return ResultFromScode(E_NOINTERFACE);

}

STDMETHODIMP_(unsigned long)

CPoly::AddRef()

{

    return ++m_refs;

}

STDMETHODIMP_(unsigned long)

CPoly::Release()

{

    POLYLINK FAR* FAR* pppolylink, FAR* ppolylinkDead;

    if(--m_refs == 0){

      Reset(); // release all CPoints

      // remove ourselves from the global list of polygons

      //

      for( pppolylink = &g_ppolylink;

          *pppolylink != NULL;

   pppolylink = &(*pppolylink)->next)

      {

if((*pppolylink)->ppoly == this){

  ppolylinkDead = *pppolylink;

  *pppolylink = (*pppolylink)->next;

  delete ppolylinkDead;

  break;

}

      }

      --g_cPoly;

#ifndef _MAC

      SBprintf(g_psb, TSTR("#poly = %d"), g_cPoly);

#endif

      delete this;

      return 0;

    }

    return m_refs;

}

//---------------------------------------------------------------------

//                     IDispatch Methods

//---------------------------------------------------------------------

/*

 * NOTE: Support for the following two methods is not available

 * in this version.

 *

 */

STDMETHODIMP

CPoly::GetTypeInfoCount(unsigned int FAR* pctinfo)

{

    *pctinfo = 0;

    return NOERROR;

}

STDMETHODIMP

CPoly::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)

{

    UNUSED(itinfo);

    UNUSED(lcid);

    UNUSED(pptinfo);

    return ResultFromScode(E_NOTIMPL);

}

/***

*HRESULT CPoly::GetIDsOfNames(OLECHAR**, unsigned int, LCID, long*)

*Purpose:

*  This method translates the given array of names to a corresponding

*  array of DISPIDs.

*

*  This method deferrs to a common implementation shared by

*  both the CPoly and CPoint objects. See the description of

*  'SPolyGetIDsOfNames()' in dispimpl.cpp for more information.

*

*Entry:

*  rgszNames = pointer to an array of names

*  cNames = the number of names in the rgszNames array

*  lcid = the callers locale ID

*

*Exit:

*  return value = HRESULT

*  rgdispid = array of DISPIDs corresponding to the rgszNames array

*    this array will contain -1 for each entry that is not known.

*

***********************************************************************/

STDMETHODIMP

CPoly::GetIDsOfNames(

    REFIID riid,

    OLECHAR FAR* FAR* rgszNames,

    unsigned int cNames,

    LCID lcid,

    DISPID FAR* rgdispid)

{

static PARAMDESC rgpdAddPoint[] = {

    {OLESTR("X")}, {OLESTR("Y")}

};

static MEMBERDESC rgmdCPoly[] = {

    {OLESTR("DRAW"),	   IDMEMBER_CPOLY_DRAW,	NULL,	0},

    {OLESTR("RESET"),	   IDMEMBER_CPOLY_RESET,	NULL,	0},

    {OLESTR("ADDPOINT"),   IDMEMBER_CPOLY_ADDPOINT,	rgpdAddPoint,	2},

    {OLESTR("ENUMPOINTS"), IDMEMBER_CPOLY_ENUMPOINTS,	NULL,	0},

    {OLESTR("GETXORIGIN"), IDMEMBER_CPOLY_GETXORIGIN,	NULL,	0},

    {OLESTR("SETXORIGIN"), IDMEMBER_CPOLY_SETXORIGIN,	NULL,	0},

    {OLESTR("GETYORIGIN"), IDMEMBER_CPOLY_GETYORIGIN,	NULL,	0},

    {OLESTR("SETYORIGIN"), IDMEMBER_CPOLY_SETYORIGIN,	NULL,	0},

    {OLESTR("GETWIDTH"),   IDMEMBER_CPOLY_GETWIDTH,	NULL,	0},

    {OLESTR("SETWIDTH"),   IDMEMBER_CPOLY_SETWIDTH,	NULL,	0},

    {OLESTR("get_red"),	   IDMEMBER_CPOLY_GETRED,	NULL,	0},

    {OLESTR("set_red"),	   IDMEMBER_CPOLY_SETRED,	NULL,	0},

    {OLESTR("get_green"),  IDMEMBER_CPOLY_GETGREEN,	NULL,	0},

    {OLESTR("set_green"),  IDMEMBER_CPOLY_SETGREEN,	NULL,	0},

    {OLESTR("get_blue"),   IDMEMBER_CPOLY_GETBLUE,	NULL,	0},

    {OLESTR("set_blue"),   IDMEMBER_CPOLY_SETBLUE,	NULL,	0},

    {OLESTR("DUMP"),	   IDMEMBER_CPOLY_DUMP,	NULL,	0}

};

    // this object only exposes a "default" interface.

    //

    if(!IsEqualIID(riid, IID_NULL))

      return ResultFromScode(DISP_E_UNKNOWNINTERFACE);

    return SPolyGetIDsOfNames(

      rgmdCPoly, DIM(rgmdCPoly), rgszNames, cNames, lcid, rgdispid);

}

/***

*HRESULT CPoly::Invoke(...)

*Purpose:

*  Dispatch a method or property request for objects of type CPoly.

*

*  see the IDispatch document for more information, and a general

*  description of this method.

*

*Entry:

*  dispidMember = the DISPID of the member being requested

*

*  riid = reference to the interface ID of the interface on this object

*    that the requested member belongs to. IID_NULL means to interpret

*    the member as belonging to the implementation defined "default"

*    or "primary" interface.

*

*  lcid = the caller's locale ID

*

*  wFlags = flags indicating the type of access being requested

*

*  pdispparams = pointer to the DISPPARAMS struct containing the

*    requested members arguments (if any) and its named parameter

*    DISPIDs (if any).

*

*Exit:

*  return value = HRESULT

*   see the IDispatch spec for a description of possible success codes.

*

*  pvarResult = pointer to a caller allocated VARIANT containing

*    the members return value (if any).

*

*  pexcepinfo = caller allocated exception info structure, this will

*    be filled in only if an exception was raised that must be passed

*    up through Invoke to an enclosing handler.

*

*  puArgErr = pointer to a caller allocated UINT, that will contain the

*    index of the offending argument if a DISP_E_TYPEMISMATCH error

*    was returned indicating that one of the arguments was of an

*    incorrect type and/or could not be reasonably coerced to a proper

*    type.

*

***********************************************************************/

STDMETHODIMP

CPoly::Invoke(

    DISPID dispidMember,

    REFIID riid,

    LCID lcid,

    unsigned short wFlags,

    DISPPARAMS FAR* pdispparams,

    VARIANT FAR* pvarResult,

    EXCEPINFO FAR* pexcepinfo,

    unsigned int FAR* puArgErr)

{

    HRESULT hresult;

    VARIANTARG varg0, varg1;

    VARIANT varResultDummy;

    UNUSED(lcid);

    UNUSED(pexcepinfo);

    if(wFlags & ~(DISPATCH_METHOD | DISPATCH_PROPERTYGET | DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYPUTREF))

      return ResultFromScode(E_INVALIDARG);

    // this object only exposes a "default" interface.

    //

    if(!IsEqualIID(riid, IID_NULL))

      return ResultFromScode(DISP_E_UNKNOWNINTERFACE);

    // This makes the following code a bit simpler if the caller

    // happens to be ignoring the return value. Some implementations

    // may choose to deal with this differently.

    //

    if(pvarResult == (VARIANT FAR*)NULL)

      pvarResult = &varResultDummy;

    VariantInit(&varg0);

    VariantInit(&varg1);

    // assume the return type is void, unless we find otherwise.

    VariantInit(pvarResult);

    switch(dispidMember){

    case IDMEMBER_CPOLY_DRAW:

      Draw();

      break;

    case IDMEMBER_CPOLY_RESET:

      Reset();

      break;

    case IDMEMBER_CPOLY_DUMP:

      Dump();

      break;

    case IDMEMBER_CPOLY_ADDPOINT:

      hresult = DispGetParam(pdispparams, 0, VT_I2, &varg0, puArgErr);

      if(hresult != NOERROR)

return hresult;

      hresult = DispGetParam(pdispparams, 1, VT_I2, &varg1, puArgErr);

      if(hresult != NOERROR)

return hresult;

      hresult = AddPoint(V_I2(&varg1), V_I2(&varg0));

      if(hresult != NOERROR)

return hresult;

      break;

    case IDMEMBER_CPOLY_ENUMPOINTS:

      IEnumVARIANT FAR* penum;

      hresult = EnumPoints(&penum);

      if(hresult != NOERROR)

return hresult;

      V_VT(pvarResult) = VT_UNKNOWN;

      hresult = penum->QueryInterface(

IID_IUnknown, (void FAR* FAR*)&V_UNKNOWN(pvarResult));

      if(hresult != NOERROR)

return hresult;

      penum->Release();

      break;

    case IDMEMBER_CPOLY_GETXORIGIN:

      V_VT(pvarResult) = VT_I2;

      V_I2(pvarResult) = m_xorg;

      break;

    case IDMEMBER_CPOLY_SETXORIGIN:

      hresult = DispGetParam(pdispparams, 0, VT_I2, &varg0, puArgErr);

      if(hresult != NOERROR)

        return hresult;

      m_xorg = V_I2(&varg0);

      break;

    case IDMEMBER_CPOLY_GETYORIGIN:

      V_VT(pvarResult) = VT_I2;

      V_I2(pvarResult) = m_yorg;

      break;

    case IDMEMBER_CPOLY_SETYORIGIN:

      hresult = DispGetParam(pdispparams, 0, VT_I2, &varg0, puArgErr);

      if(hresult != NOERROR)

        return hresult;

      m_yorg = V_I2(&varg0);

      break;

    case IDMEMBER_CPOLY_GETWIDTH:

      V_VT(pvarResult) = VT_I2;

      V_I2(pvarResult) = GetWidth();

      break;

    case IDMEMBER_CPOLY_SETWIDTH:

      hresult = DispGetParam(pdispparams, 0, VT_I2, &varg0, puArgErr);

      if(hresult != NOERROR)

        return hresult;

      SetWidth(V_I2(&varg0));

      break;

    case IDMEMBER_CPOLY_GETRED:

      V_VT(pvarResult) = VT_I2;

      V_I2(pvarResult) = get_red();

      break;

    case IDMEMBER_CPOLY_SETRED:

      hresult = DispGetParam(pdispparams, 0, VT_I2, &varg0, puArgErr);

      if(hresult != NOERROR)

        return hresult;

      set_red(V_I2(&varg0));

      break;

    case IDMEMBER_CPOLY_GETGREEN:

      V_VT(pvarResult) = VT_I2;

      V_I2(pvarResult) = get_green();

      break;

    case IDMEMBER_CPOLY_SETGREEN:

      hresult = DispGetParam(pdispparams, 0, VT_I2, &varg0, puArgErr);

      if(hresult != NOERROR)

        return hresult;

      set_green(V_I2(&varg0));

      break;

    case IDMEMBER_CPOLY_GETBLUE:

      V_VT(pvarResult) = VT_I2;

      V_I2(pvarResult) = get_blue();

      break;

    case IDMEMBER_CPOLY_SETBLUE:

      hresult = DispGetParam(pdispparams, 0, VT_I2, &varg0, puArgErr);

      if(hresult != NOERROR)

        return hresult;

      set_blue(V_I2(&varg0));

      break;

    default:

      return ResultFromScode(DISP_E_MEMBERNOTFOUND);

    }

    return NOERROR;

}

//---------------------------------------------------------------------

//                     Introduced Methods

//---------------------------------------------------------------------

/***

*void CPoly::Draw(void)

*Purpose:

*  Draw the polygon, using the current x/y origin and line width

*  properties.

*

*Entry:

*  None

*

*Exit:

*  None

*

***********************************************************************/

void PASCAL

CPoly::Draw()

{

    short xorg, yorg;

    POINTLINK FAR* ppointlinkFirst, FAR* ppointlink;

    if((ppointlinkFirst = m_ppointlink) == (POINTLINK FAR*)NULL)

      return;

#ifdef _MAC /* { */

    short x, y;

    RGBColor rgb;

    WindowPtr pwndSaved;

    GetPort(&pwndSaved);

    SetPort(g_pwndClient);

    PenNormal();

    PenSize(m_width, m_width);

    rgb.red = m_red;

    rgb.green = m_green;

    rgb.blue = m_blue;

    RGBForeColor(&rgb);

    xorg = m_xorg;

    yorg = m_yorg;

    MoveTo(

      xorg + ppointlinkFirst->ppoint->m_x,

      yorg + ppointlinkFirst->ppoint->m_y);

    for(ppointlink = ppointlinkFirst->next;

ppointlink != (POINTLINK FAR*)NULL;

ppointlink = ppointlink->next)

    {

      x = xorg + ppointlink->ppoint->m_x;

      y = yorg + ppointlink->ppoint->m_y;

      LineTo(x, y);

    }

    LineTo(

      xorg + ppointlinkFirst->ppoint->m_x,

      yorg + ppointlinkFirst->ppoint->m_y);

    SetPort(pwndSaved);

#else /* }{ */

    HDC hdc;

    RECT rect;

    HPEN hpen, hpenOld;

extern HWND g_hwndClient;

    GetClientRect(g_hwndClient, &rect);

    xorg = m_xorg + (short) rect.left;

    yorg = m_yorg + (short) rect.top;

    hdc = GetDC(g_hwndClient);

    hpen = CreatePen(PS_SOLID, m_width, RGB(m_red, m_green, m_blue));

    hpenOld = SelectObject(hdc, hpen);

#ifdef WIN32

    MoveToEx(hdc,

      xorg + ppointlinkFirst->ppoint->m_x,

      yorg + ppointlinkFirst->ppoint->m_y, NULL);

#else

    MoveTo(hdc,

      xorg + ppointlinkFirst->ppoint->m_x,

      yorg + ppointlinkFirst->ppoint->m_y);

#endif

    for(ppointlink = ppointlinkFirst->next;

ppointlink != (POINTLINK FAR*)NULL;

ppointlink = ppointlink->next)

    {

      LineTo(hdc,

xorg + ppointlink->ppoint->m_x,

yorg + ppointlink->ppoint->m_y);

    }

    LineTo(hdc,

      xorg + ppointlinkFirst->ppoint->m_x,

      yorg + ppointlinkFirst->ppoint->m_y);

    SelectObject(hdc, hpenOld);

    DeleteObject(hpen);

    ReleaseDC(g_hwndClient, hdc);

#endif /* } */

}

/***

*void CPoly::Reset(void)

*Purpose:

*  Release all points referenced by this poly.

*

*Entry:

*  None

*

*Exit:

*  None

*

***********************************************************************/

void PASCAL

CPoly::Reset()

{

    POINTLINK FAR* ppointlink, FAR* ppointlinkNext;

    for(ppointlink = m_ppointlink;

ppointlink != (POINTLINK FAR*)NULL;

ppointlink = ppointlinkNext)

    {

      ppointlinkNext = ppointlink->next;

      ppointlink->ppoint->Release();

      delete ppointlink;

    }

    m_cPoints = 0;

    m_ppointlink = NULL;

    m_ppointlinkLast = NULL;

}

/***

*HRESULT CPoly::AddPoint(short, short)

*Purpose:

*  Add a CPoint with the given coordinates to the end of our current

*  list of points.

*

*Entry:

*  x,y = the x and y coordinates of the new point.

*

*Exit:

*  return value = HRESULT

*

***********************************************************************/

HRESULT PASCAL

CPoly::AddPoint(short x, short y)

{

    CPoint FAR* ppoint;

    POINTLINK FAR* ppointlink;

    ppoint = CPoint::Create();

    if(ppoint == (CPoint FAR*)NULL)

      return ResultFromScode(E_OUTOFMEMORY);

    ppoint->SetX(x);

    ppoint->SetY(y);

    ppointlink = new FAR POINTLINK;

    if(ppointlink == (POINTLINK FAR*)NULL){

      delete ppoint;

      return ResultFromScode(E_OUTOFMEMORY);

    }

    ppointlink->ppoint = ppoint;

    ppointlink->next = (POINTLINK FAR*)NULL;

    if(m_ppointlinkLast == (POINTLINK FAR*)NULL){

      m_ppointlink = m_ppointlinkLast = ppointlink;

    }else{

      m_ppointlinkLast->next = ppointlink;

      m_ppointlinkLast = ppointlink;

    }

    ++m_cPoints;

    return NOERROR;

}

/***

*HRESULT CPoly::EnumPoints(IEnumVARIANT**);

*Purpose:

*  Return and enumerator for the points in this polygon.

*

*Entry:

*  None

*

*Exit:

*  return value = HRESULT

*

*  *ppenum = pointer to an IEnumVARIANT for the points in this polygon

*

***********************************************************************/

HRESULT PASCAL

CPoly::EnumPoints(IEnumVARIANT FAR* FAR* ppenum)

{

    unsigned int i;

    VARIANT var;

    HRESULT hresult;

    SAFEARRAY FAR* psa;

    CEnumPoint FAR* penum;

    POINTLINK FAR* ppointlink;

    SAFEARRAYBOUND rgsabound[1];

    rgsabound[0].lLbound = 0;

    rgsabound[0].cElements = m_cPoints;

    psa = SafeArrayCreate(VT_VARIANT, 1, rgsabound);

    if(psa == NULL){

      hresult = ResultFromScode(E_OUTOFMEMORY);

      goto LError0;

    }

    ppointlink = m_ppointlink;

    for(i = 0; i < m_cPoints; ++i){

      long ix[1];

      if(ppointlink == NULL){

        // this indicates an internal consistency error.

// (this test should probably be an assertion)

        hresult = ResultFromScode(E_FAIL);

        goto LError1;

      }

      V_VT(&var) = VT_DISPATCH;

      hresult = ppointlink->ppoint->QueryInterface(

IID_IDispatch, (void FAR* FAR*)&V_DISPATCH(&var));

      if(hresult != NOERROR)

        goto LError1;

      ix[0] = i;

      SafeArrayPutElement(psa, ix, &var);

      ppointlink = ppointlink->next;

    }

    hresult = CEnumPoint::Create(psa, &penum);

    if(hresult != NOERROR)

      goto LError1;

    *ppenum = penum;

    return NOERROR;

LError1:;

    // destroy the array if we were not successful creating the enumerator.

    SafeArrayDestroy(psa);

LError0:;

    return hresult;

}

short PASCAL

CPoly::GetXOrigin()

{

    return m_xorg;

}

void PASCAL

CPoly::SetXOrigin(short x)

{

    m_xorg = x;

}

short PASCAL

CPoly::GetYOrigin()

{

    return m_yorg;

}

void PASCAL

CPoly::SetYOrigin(short y)

{

    m_yorg = y;

}

short PASCAL

CPoly::GetWidth()

{

    return m_width;

}

void PASCAL

CPoly::SetWidth(short width)

{

    m_width = width;

}

short PASCAL

CPoly::get_red()

{

    return m_red;

}

void PASCAL

CPoly::set_red(short red)

{

    m_red = red;

}

short PASCAL

CPoly::get_green()

{

    return m_green;

}

void PASCAL

CPoly::set_green(short green)

{

    m_green = green;

}

short PASCAL

CPoly::get_blue()

{

    return m_blue;

}

void PASCAL

CPoly::set_blue(short blue)

{

    m_blue = blue;

}

/***

*void CPoly::Dump(void)

*Purpose:

*  Output a debug dump of this instance.

*

*Entry:

*  None

*

*Exit:

*  None

*

***********************************************************************/

void PASCAL

CPoly::Dump()

{

#ifdef _MAC

    // REVIEW: implement for the mac

#else

    TCHAR buffer[80];

    POINTLINK FAR* ppointlink;

    wsprintf(buffer, TSTR("CPoly(0x%x) =\n"), (int)this);

    OutputDebugString(buffer);

    wsprintf(buffer,

      TSTR("    xorg = %d, yorg = %d, width = %d, rgb = {%d,%d,%d}\n    points = "),

      m_xorg, m_yorg, m_width,

      get_red(),

      get_green(),

      get_blue());

    OutputDebugString(buffer);

    for(ppointlink = m_ppointlink;

ppointlink != (POINTLINK FAR*)NULL;

ppointlink = ppointlink->next)

    {

      wsprintf(buffer, TSTR("{%d,%d}"),

        ppointlink->ppoint->GetX(),

        ppointlink->ppoint->GetY());

      OutputDebugString(buffer);

      wsprintf(buffer, TSTR(" "));

      OutputDebugString(buffer);

    }

    wsprintf(buffer, TSTR("\n"));

    OutputDebugString(buffer);

#endif

}

/***

*void CPoly::PolyDraw(void)

*Purpose:

*  Draw all polygons.

*

*Entry:

*  None

*

*Exit:

*  None

*

***********************************************************************/

void

CPoly::PolyDraw()

{

    POLYLINK FAR* polylink;

    for(polylink = g_ppolylink;

polylink != (POLYLINK FAR*)NULL;

polylink = polylink->next)

    {

      polylink->ppoly->Draw();

    }

}

/***

*void PolyTerm(void)

*Purpose:

*  Release all polygons.

*

*Entry:

*  None

*

*Exit:

*  None

*

***********************************************************************/

void

CPoly::PolyTerm()

{

    POLYLINK FAR* ppolylink;

    POLYLINK FAR* ppolylinkNext;

    for(ppolylink = g_ppolylink;

ppolylink != (POLYLINK FAR*)NULL;

ppolylink = ppolylinkNext)

    {

      ppolylinkNext = ppolylink->next;

      ppolylink->ppoly->Release();

      delete ppolylink;

    }

    g_ppolylink = NULL;

}

/***

*void PolyDump(void)

*Purpose:

*  Invoke the debug Dump() method on all polygons were currently

*  holding on to.

*

*Entry:

*  None

*

*Exit:

*  None

*

***********************************************************************/

void

CPoly::PolyDump()

{

    POLYLINK FAR* ppolylink;

    if(g_ppolylink == (POLYLINK FAR*)NULL){

#ifndef _MAC

      OutputDebugString(TSTR("\t(none)\n"));

#endif

      return;

    }

    for(ppolylink = g_ppolylink;

ppolylink != (POLYLINK FAR*)NULL;

ppolylink = ppolylink->next)

    {

      ppolylink->ppoly->Dump();

    }

}

//---------------------------------------------------------------------

//             Implementation of the CPoly Class Factory

//---------------------------------------------------------------------

CPolyCF::CPolyCF()

{

    m_refs = 0;

}

IClassFactory FAR*

CPolyCF::Create()

{

    CPolyCF FAR* pCF;

    if((pCF = new FAR CPolyCF()) == NULL)

      return NULL;

    pCF->AddRef();

    return pCF;

}

STDMETHODIMP

CPolyCF::QueryInterface(REFIID riid, void FAR* FAR* ppv)

{

    if(!IsEqualIID(riid, IID_IUnknown)){

      if(!IsEqualIID(riid, IID_IClassFactory)){

*ppv = NULL;

        return ResultFromScode(E_NOINTERFACE);

      }

    }

    *ppv = this;

    ++m_refs;

    return NOERROR;

}

STDMETHODIMP_(unsigned long)

CPolyCF::AddRef(void)

{

    return ++m_refs;

}

STDMETHODIMP_(unsigned long)

CPolyCF::Release(void)

{

    if(--m_refs == 0){

      delete this;

      return 0;

    }

    return m_refs;

}

STDMETHODIMP

CPolyCF::CreateInstance(

    IUnknown FAR* punkOuter,

    REFIID iid,

    void FAR* FAR* ppv)

{

    HRESULT hresult;

    CPoly FAR *ppoly;

    UNUSED(punkOuter);

#ifdef _MAC

    if(GetZone() != ApplicZone()){

#ifndef _MSC_VER

#ifndef ConstStr255Param

#define ConstStr255Param StringPtr

#endif

#endif

      DebugStr((ConstStr255Param)"\pZones do not match");

    }

#endif

    if((ppoly = CPoly::Create()) == NULL){

      *ppv = NULL;

      return ResultFromScode(E_OUTOFMEMORY);

    }

    hresult = ppoly->QueryInterface(iid, ppv);

    ppoly->Release();

    return hresult;

}

STDMETHODIMP

#ifdef _MAC

CPolyCF::LockServer(unsigned long fLock)

#else

CPolyCF::LockServer(BOOL fLock)

#endif

{

    UNUSED(fLock);

    return NOERROR;

}


 HOSTENV.H  (SPOLY Sample)

/***

*hostenv.h

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*

*Purpose:

*  Generic host specific includes.

*

*Implementation Notes:

*

*****************************************************************************/

#if defined(_MAC)

#if defined(_PPCMAC)

#pragma data_seg("_FAR_DATA")

#pragma data_seg( )

#define MAXLONG 0x7fffffff

#define EventHandlerProcPtr AEEventHandlerUPP

#else //_PPCMAC

#define  GetMenuItemText(mApple,menuItem,daName)  GetItem(mApple,menuItem,daName)

#endif //_PPCMAC

#endif //_MAC

#if defined(_MAC)

#if defined(_MSC_VER)

# include <values.h>

# include <types.h>

# include <string.h>

# include <quickdra.h>

# include <fonts.h>

# include <events.h>

# include <resource.h>

# include <menus.h>

# include <textedit.h>

# include <dialogs.h>

# include <desk.h>

# include <toolutil.h>

# include <memory.h>

# include <files.h>

# include <osutils.h>

# include <osevents.h>

# include <diskinit.h>

# include <packages.h>

# include <traps.h>

# include <AppleEve.h>

#else //_MSC_VER

# include <values.h>

# include <types.h>

# include <strings.h>

# include <quickdraw.h>

# include <fonts.h>

# include <events.h>

# include <resources.h>

# include <windows.h>

# include <menus.h>

# include <textedit.h>

# include <dialogs.h>

# include <desk.h>

# include <toolutils.h>

# include <memory.h>

# include <files.h>

# include <osutils.h>

# include <osevents.h>

# include <diskinit.h>

# include <packages.h>

# include <traps.h>

# include <AppleEvents.h>

#endif //_MSC_VER

# include <ole2.h>

# include <olenls.h>

# include <dispatch.h>

# define TCHAR	char

# define TSTR(str)	str

# define STRING(str)	        (str)

# define WIDESTRING(str)        (str)

#elif defined(WIN32)

# include <windows.h>

# include <ole2.h>

# include <oleauto.h>

# if defined(UNICODE)

    #define TCHAR	WCHAR

    #define TSTR(str)	L##str

    #define STRING(str)	        (str)

    #define WIDESTRING(str)	(str)

# else

    #define TCHAR	char

    #define TSTR(str)	str

    #define STRING(str)	        AnsiString(str)

    #define WIDESTRING(str)	WideString(str)

    extern "C" char FAR* AnsiString(OLECHAR FAR* strIn);

    extern "C" OLECHAR FAR* WideString(char FAR* strIn);

# endif

#else /* WIN16 */

# include <windows.h>

# include <ole2.h>

# include <olenls.h>

# include <dispatch.h>

# define TCHAR	char

# define TSTR(str)	str

# define STRING(str)	        (str)

# define WIDESTRING(str)        (str)

#endif


 MISC.CPP  (SPOLY Sample)

/***

*misc.cpp

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*

*Purpose:

*

*Implementation Notes:

*

*****************************************************************************/

#include "spoly.h"

#include "cpoint.h"

#include "cpoly.h"

#include <stdio.h>

#if _MAC

# include <string.h>

# include <ctype.h>

#endif

#ifdef WIN32  // Use native CompareString operation

  #undef CompareString

  #ifdef UNICODE

    #define CompareString CompareStringW

  #else

    // CONSIDER: write a wrapper for CompareStringW if not available

  #endif

#else

  #define CompareString CompareStringA

#endif

unsigned long g_dwPolyCF = 0;

unsigned long g_dwPointCF = 0;

IClassFactory FAR* g_ppolyCF = NULL;

IClassFactory FAR* g_ppointCF = NULL;

#ifdef _MAC

struct regentry{

    char *szKey;

    char *szValue;

} g_rgregentry[] = {

      { "CLSID\\{00020462-0000-0000-C000-000000000046}",

"OLE Automation SPoly 1.0 Application" }

    , { "CLSID\\{00020462-0000-0000-C000-000000000046}\\LocalServer",

"SPLy" }

    , { "CLSID\\{00020462-0000-0000-C000-000000000046}\\ProgID",

"SPoly.Application" }

    , { "CLSID\\{00020462-0000-0000-C000-000000000046}\\InprocHandler",

"OLE2:Def$DefFSet" }

    , { "SPLy", "{00020462-0000-0000-C000-000000000046}" }

    , { "SPoly.Application\\CLSID",

"{00020462-0000-0000-C000-000000000046}" }

};

HRESULT

EnsureRegistration()

{

    HKEY hkey;

    if(RegOpenKey(HKEY_CLASSES_ROOT, "SPLy", &hkey) == NOERROR){

      RegCloseKey(hkey);

      return NOERROR;

    }

    for(int i = 0; i < DIM(g_rgregentry); ++i){

      if(RegSetValue(HKEY_CLASSES_ROOT, g_rgregentry[i].szKey, REG_SZ, g_rgregentry[i].szValue, 0) != ERROR_SUCCESS)

        return ResultFromScode(E_FAIL);

    }

    return NOERROR;

}

#endif

/***

*HRESULT InitOle(void)

*Purpose:

*  Initialize Ole, and register our class factories.

*

*Entry:

*  None

*

*Exit:

*  None

*

***********************************************************************/

STDAPI

InitOle()

{

    HRESULT hresult;

    if((hresult = OleInitialize(NULL)) != NOERROR)

      goto LError0;

#ifdef _MAC

    if((hresult = EnsureRegistration()) != NOERROR)

      goto LError0;

#endif

    // Register the CPoint Class Factory

    //

    if((g_ppointCF = CPointCF::Create()) == NULL){

      hresult = ResultFromScode(E_OUTOFMEMORY);

      goto LError1;

    }

    hresult = CoRegisterClassObject(

      CLSID_CPoint,

      g_ppointCF,

      CLSCTX_LOCAL_SERVER,

      REGCLS_MULTIPLEUSE,

      &g_dwPointCF);

    if(hresult != NOERROR)

      goto LError1;

    // Register the CPoly Class Factory.

    //

    if((g_ppolyCF = CPolyCF::Create()) == NULL){

      hresult = ResultFromScode(E_OUTOFMEMORY);

      goto LError1;

    }

    hresult = CoRegisterClassObject(

      CLSID_CPoly,

      g_ppolyCF,

      CLSCTX_LOCAL_SERVER,

      REGCLS_MULTIPLEUSE,

      &g_dwPolyCF);

    if(hresult != NOERROR)

      goto LError1;

    g_ppolyCF->Release();

    g_ppointCF->Release();

    return NOERROR;

LError1:;

    if(g_ppolyCF != NULL)

      g_ppolyCF->Release();

    if(g_ppointCF != NULL)

      g_ppointCF->Release();

    UninitOle();

LError0:;

    return hresult;

}

STDAPI

UninitOle()

{

    // Tell Ole to release our class factories.

    //

    if(g_dwPointCF != 0L)

      CoRevokeClassObject(g_dwPointCF);

    if(g_dwPolyCF != 0L)

      CoRevokeClassObject(g_dwPolyCF);

    OleUninitialize();

    return NOERROR;

}

/***

*HRESULT SPolyGetIDsOfNames(MEMBERDESC*, unsigned int, char**, unsigned int, LCID, long*)

*Purpose:

*  This is the table driven implementation of IDispatch::GetIDsOfNames

*  deferred to by both the CPoint and CPoly objects.

*

*Entry:

*  rgmd = pointer to an array of method descriptors

*  cMethods = number of elements in the array of method descriptors

*  rgszNames = pointer to an array of names

*  cNames = the number of names in the rgszNames array

*  lcid = the callers locale ID

*

*Exit:

*  return value = HRESULT

*  rgdispid = array of name IDs corresponding to the rgszNames array

*    this array will contain -1 for each entry that is not known.

*

***********************************************************************/

STDAPI

SPolyGetIDsOfNames(

    MEMBERDESC FAR* rgmd,

    unsigned int cMethods,

    OLECHAR FAR* FAR* rgszNames,

    unsigned int cNames,

    LCID lcid,

    DISPID FAR* rgdispid)

{

    HRESULT hresult;

    PARAMDESC FAR* ppd;

    MEMBERDESC FAR* pmd;

    unsigned int iName, iTry, cParams;

    hresult = NOERROR;

    // first lookup the member name.

    //

    for(pmd = rgmd;; ++pmd){

      if(pmd == &rgmd[cMethods])

        goto LMemberNotFound;

#if defined(WIN32) && !defined(UNICODE)

      // CompareStringW is not available on Chicago

      if(wcsicmp(rgszNames[0], pmd->szName) == 0)

#else

      if(CompareString(lcid, NORM_IGNORECASE, rgszNames[0], -1, pmd->szName, -1) == 2)

#endif

      {

rgdispid[0] = pmd->id;

break;

      }

    }

    // Lookup the named parameters, if there are any.

    if(cNames > 1){

      cParams = pmd->cParams;

      for(iName = 1; iName < cNames; ++iName){

for(iTry = 0;; ++iTry){

  if(iTry == cParams){

    hresult = ResultFromScode(DISP_E_UNKNOWNNAME);

    rgdispid[iName] = -1;

    break;

  }

  ppd = &pmd->rgpd[iTry];

#if defined(WIN32) && !defined(UNICODE)

          // CompareStringW is not available on Chicago

          if(wcsicmp(rgszNames[iName], ppd->szName) == 0)

#else

  if(CompareString(lcid, NORM_IGNORECASE, rgszNames[iName], -1, ppd->szName, -1) == 2)

#endif

  {

    // The DISPID for a named parameter is defined to be its

    // zero based positional index.  This routine assumes that

    // that PARAMDESC array was declared in correct textual order.

    //

    rgdispid[iName] = iTry;

    break;

  }

        }

      }

    }

    return hresult;

LMemberNotFound:;

    // If the member name is unknown, everything is unknown.

    for(iName = 0; iName < cNames; ++iName)

      rgdispid[iName] = -1;

    return ResultFromScode(DISP_E_UNKNOWNNAME);

}

// disable unicode expansion for assertions

#undef UNICODE

void

Assert(int fCond, char FAR* file, int line, char FAR* message)

{

    char * fmt;

    char buf[128];

    if(fCond)

      return;

    fmt = (message == NULL)

      ? "Assertion failed: %s(%d)"

      : "Assertion failed: %s(%d) '%s'";

    sprintf(buf, fmt, file, line, message);

#ifdef _MAC

    DebugStr(c2pstr(buf));

#else

#ifdef WIN32

    OutputDebugStringA(buf);

#else //WIN32

    OutputDebugString(buf);

#endif //WIN32

    DebugBreak();

#endif

}


 RESOURCE.H  (SPOLY Sample)

/***

*resource.h

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*

*Purpose:

*

*Implementation Notes:

*

*****************************************************************************/

#ifdef _MAC

#define kMinSize	500	/* minimum size (in K) */

#define kPrefSize	500	/* preferred size (in K) */

#define	rMenuBar	128	/* menu bar */

#define	rAboutAlert	128	/* about alert */

#define	rUserAlert	129	/* error alert */

#define	rWindow	128	/* application's window */

#define rIcon	128

#define	mApple	128	/* Apple menu */

#define	iAbout	1

#define	mFile	129	/* File menu */

#define	iNew	1

#define	iClose	4

#define	iQuit	12

#define	mEdit	130	/* Edit menu */

#define	iUndo	1

#define	iCut	3

#define	iCopy	4

#define	iPaste	5

#define	iClear	6

#define mSpoly	131

#define iTest	1

#define kMinHeap	21 * 1024

#define kMinSpace	8 * 1024

#else /* WIN16 || WIN32 */

# define IDM_CLEAR	1

# define IDM_DUMP	2

# define IDM_FIRSTCHILD	100

#endif


 SPOLY.DEF  (SPOLY Sample)

NAME         SPOLY

DESCRIPTION  'IDispatch Polygon Test Server'

EXETYPE      WINDOWS

STUB         'WINSTUB.EXE'

CODE         PRELOAD MOVEABLE DISCARDABLE

DATA         PRELOAD MULTIPLE

HEAPSIZE     4096

STACKSIZE    8192


 SPOLY.H  (SPOLY Sample)

/***

*spoly.h - Application-wide definitions

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*

*Purpose:

*

*Implementation Notes:

*

*****************************************************************************/

#include "hostenv.h"

#include "resource.h"

#include "clsid.h"

#if defined(_MAC)

# define PASCAL pascal

# define STRSTR strstr

#elif defined(WIN32)

# include "statbar.h"

# define STRSTR strstr

#else /* WIN16 */

# include "statbar.h"

# define STRSTR _fstrstr

#endif

#ifdef _MAC

# define UNUSED(X) ((void)(void*)&(X))

#else

# define UNUSED(X) (X)

#endif

#define DIM(X) (sizeof(X) / sizeof(X[0]))

extern "C" void Assert(int, char FAR*, int, char FAR*);

#define ASSERT(X) Assert(X, __FILE__, __LINE__, NULL)

#define ASSERTSZ(X, MSG) Assert(X, __FILE__, __LINE__, MSG)

// Description of a single named parameter.

//

typedef struct tagPARAMDESC {

    OLECHAR FAR* szName;	// parameter name

} PARAMDESC;

// Description of a single member.

//

typedef struct tagMEMBERDESC {

    OLECHAR FAR* szName;	// member name

    DISPID id;	// member id

    PARAMDESC FAR* rgpd;	// ptr to array of PARAMDESCs

    unsigned int cParams;	// number of parameters

} MEMBERDESC;

STDAPI

SPolyGetIDsOfNames(

    MEMBERDESC FAR* pmd,

    unsigned int cMethods,

    OLECHAR FAR* FAR* rgszNames,

    unsigned int cNames,

    LCID lcid,

    DISPID FAR* rgid);

STDAPI InitOle();

STDAPI UninitOle();


 SPOLY.RC  (SPOLY Sample)

#define NOKERNEL

#define NOGDI

#define NOSOUND

#define NOCOMM

#define NODRIVERS

#include "windows.h"

#include "spoly.h"

SPOLY ICON spoly.ico

SPolyMenu MENU

BEGIN

    MENUITEM	"&Clear"	IDM_CLEAR

    MENUITEM	"&Dump"	IDM_DUMP

END


 SPOLY.REG  (SPOLY Sample)

REGEDIT

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; registration info SPoly.Application (defaults to SPoly.Application.1)

HKEY_CLASSES_ROOT\SPoly.Application = OLE Automation SPoly Application

HKEY_CLASSES_ROOT\SPoly.Application\Clsid = {00020462-0000-0000-C000-000000000046}

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; registration info SPoly 1.0

; (Application Object)

HKEY_CLASSES_ROOT\SPoly.Application.1 = OLE Automation SPoly 1.0 Application

HKEY_CLASSES_ROOT\SPoly.Application.1\Clsid = {00020462-0000-0000-C000-000000000046}

HKEY_CLASSES_ROOT\CLSID\{00020462-0000-0000-C000-000000000046} = OLE Automation SPoly 1.0 Application

HKEY_CLASSES_ROOT\CLSID\{00020462-0000-0000-C000-000000000046}\ProgID = SPoly.Application.1

HKEY_CLASSES_ROOT\CLSID\{00020462-0000-0000-C000-000000000046}\VersionIndependentProgID = SPoly.Application

HKEY_CLASSES_ROOT\CLSID\{00020462-0000-0000-C000-000000000046}\LocalServer32 = spoly.exe /Automation

HKEY_CLASSES_ROOT\CLSID\{00020463-0000-0000-C000-000000000046} = SPoly.SPoint

HKEY_CLASSES_ROOT\CLSID\{00020463-0000-0000-C000-000000000046}\ProgID = SPoly.Application.1

HKEY_CLASSES_ROOT\CLSID\{00020463-0000-0000-C000-000000000046}\VersionIndependentProgID = SPoly.Application

HKEY_CLASSES_ROOT\CLSID\{00020463-0000-0000-C000-000000000046}\LocalServer32 = spoly.exe /Automation


 STATBAR.H  (SPOLY Sample)

/***

*statbar.h

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*  Information Contained Herein Is Proprietary and Confidential.

*

*Purpose:

*

*Implementation Notes:

*  This file requires windows.h and ole2.h

*

*****************************************************************************/

class CStatBar : public IUnknown {

public:

    static CStatBar FAR* Create(HANDLE hinst, HWND hwndFrame);

    // IUnknown methods

    //

    STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppv);

    STDMETHOD_(unsigned long, AddRef)(void);

    STDMETHOD_(unsigned long, Release)(void);

    // Introduced methods

    //

    void Show(void);

    inline void Move(void);

    inline void Update(void);

    inline int GetX(void);

    inline void SetX(int x);

    inline int GetY(void);

    inline void SetY(int y);

    inline int GetHeight(void);

    inline void SetHeight(int height);

    inline int GetWidth(void);

    inline void SetWidth(int width);

    //inline HFONT GetFont(void);

    void SetFont(HFONT hfont);

    //char FAR* GetText(void);

    inline void SetText(OLECHAR FAR* sz);

    void WMPaint(void);

    BOOL Register(HANDLE);

private:

    CStatBar();

    ~CStatBar();

    unsigned long	m_refs;

    HWND	m_hwnd;	// the status bar window handle

    int	m_x;	// x coordinate of upper left corner

    int	m_y;	// y coordinate of upper left corner

    int	m_height;

    int	m_width;

    HFONT	m_hfont;

    int	m_dyFont;	// font height

    int	m_dxFont;	// font width

    BSTR	m_bstrMsg;	// the status bar text

    static TCHAR FAR* m_szWndClass;

};

inline void

CStatBar::Move()

{

    MoveWindow(m_hwnd, m_x, m_y, m_width, m_height, TRUE);

}

inline void

CStatBar::Update()

{

    InvalidateRect(m_hwnd, NULL, TRUE);

    UpdateWindow(m_hwnd);

}

inline int

CStatBar::GetX()

{

    return m_x;

}

inline void

CStatBar::SetX(int x)

{

    m_x = x;

}

inline int

CStatBar::GetY(void)

{

    return m_y;

}

inline void

CStatBar::SetY(int y)

{

    m_y = y;

}

inline int

CStatBar::GetHeight(void)

{

    return m_height;

}

inline void

CStatBar::SetHeight(int height)

{

    m_height = height;

}

inline int

CStatBar::GetWidth(void)

{

    return m_width;

}

inline void

CStatBar::SetWidth(int width)

{

    m_width = width;

}

inline void

CStatBar::SetText(OLECHAR FAR* sz)

{

    SysFreeString(m_bstrMsg);

    m_bstrMsg = SysAllocString(sz);

}

extern "C" void

SBprintf(CStatBar FAR* psb, TCHAR FAR* szFmt, ...);


 STATBAR.CPP  (SPOLY Sample)

/***

*statbar.cpp

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*  Information Contained Herein Is Proprietary and Confidential.

*

*Purpose:

*

*Implementation Notes:

*

*****************************************************************************/

#include <stdarg.h>

#include "hostenv.h"

#include "statbar.h"

extern "C" long FAR PASCAL StatBarWndProc(HWND, unsigned int, WPARAM, LPARAM);

TCHAR FAR* CStatBar::m_szWndClass = TSTR("StatBarWndClass");

CStatBar::CStatBar()

{

    m_refs = 0;

    m_x = 0;

    m_y = 0;

    m_width = 0;

    m_height = 0;

    m_bstrMsg = NULL;

    m_hfont = (HANDLE)0;

}

CStatBar::~CStatBar()

{

    SysFreeString(m_bstrMsg);

}

/***

*PUBLIC CStatBar FAR* CStatBar::Create(HANDLE, HWND)

*

*Purpose:

*

*Entry:

*

*Exit:

*

***********************************************************************/

CStatBar FAR*

CStatBar::Create(HANDLE hinst, HWND hwndFrame)

{

    CStatBar FAR* psb;

    psb = new FAR CStatBar();

    if(psb == NULL)

      return NULL;

    psb->AddRef();

    if(!psb->Register(hinst))

      goto LFail;

    psb->m_hwnd = CreateWindow(

      CStatBar::m_szWndClass,

      NULL,

      WS_CHILD | WS_CLIPSIBLINGS,

      0, 0, 0, 0,

      hwndFrame,

      0,

      hinst,

      NULL);

    if(!psb->m_hwnd)

      goto LFail;

    // Stash the newly created CStatBar* in the extra bytes of the

    // associated window so we can get at the instance in the message

    // proc.

    //

    // Note: we do not AddRef for this reference. We make sure that the

    // window is destroyed when the refcnt goes to 0.

    //

    SetWindowLong(psb->m_hwnd, 0, (long)psb);

    return psb;

LFail:;

    delete psb;

    return NULL;

}

//---------------------------------------------------------------------

//                     IUnknown Methods

//---------------------------------------------------------------------

STDMETHODIMP

CStatBar::QueryInterface(REFIID riid, void FAR* FAR* ppv)

{

    if(IsEqualIID(riid,IID_IUnknown)){

      *ppv = this;

      AddRef();

      return NOERROR;

    }

    *ppv = (void FAR*)NULL;

    return ResultFromScode(E_NOINTERFACE);

}

STDMETHODIMP_(unsigned long)

CStatBar::AddRef(void)

{

    return ++m_refs;

}

STDMETHODIMP_(unsigned long)

CStatBar::Release(void)

{

    if(--m_refs == 0){

      // destroy the status bar window.

      //

      SendMessage(m_hwnd, WM_DESTROY, 0, 0L);

      delete this;

      return 0;

    }

    return m_refs;

}

//---------------------------------------------------------------------

//                     Introduced Methods

//---------------------------------------------------------------------

/***

*PRIVATE BOOL CStatBar::Register(HANDLE)

*

*Purpose:

*  Register the status bar window class.

*

*Entry:

*  None

*

*Exit:

*  return value = BOOL, TRUE if successful, FALSE if not.

*

***********************************************************************/

BOOL

CStatBar::Register(HANDLE hinst)

{

    WNDCLASS  wc;

    // register the class, unless already registered.

    if(GetClassInfo(hinst, m_szWndClass, &wc) == 0){

      wc.style         = 0;

      wc.lpfnWndProc   = StatBarWndProc;

      wc.cbClsExtra    = 0;

      wc.cbWndExtra    = sizeof(CStatBar FAR*);

      wc.hInstance     = hinst;

      wc.hIcon         = 0;

      wc.hCursor       = LoadCursor(NULL, IDC_ARROW);

      wc.hbrBackground = GetStockObject(LTGRAY_BRUSH);

      wc.lpszMenuName  = 0;

      wc.lpszClassName = CStatBar::m_szWndClass;

      if(!RegisterClass(&wc))

        return FALSE;

    }

    return TRUE;

}

/***

*PUBLIC void CStatBar::Show(void)

*

*Purpose:

*  Show the status bar window associated with this CStatBar instance.

*

*Entry:

*  None

*

*Exit:

*  None

*

***********************************************************************/

void

CStatBar::Show()

{

    ShowWindow(m_hwnd, SW_SHOW);

}

void

CStatBar::SetFont(HFONT hfont)

{

    HDC hdc;

    TEXTMETRIC tm;

    HFONT hfontOld;

    // compute the character sizes given this new font.

    //

    hdc = GetDC(m_hwnd);

    hfontOld = SelectObject(hdc, hfont);

    GetTextMetrics(hdc, &tm);

    m_dxFont = tm.tmAveCharWidth;

    m_dyFont = tm.tmHeight + tm.tmExternalLeading;

    SelectObject(hdc, hfontOld);

    ReleaseDC(m_hwnd, hdc);

    m_hfont = hfont;

}

/***

*PRIVATE CStatBar::WMPaint(void)

*

*Purpose:

*  This method is responsible for drawing the status bar, and is called

*  in response to a WM_PAINT message.

*

*Entry:

*  None

*

*Exit:

*  None

*

***********************************************************************/

void

CStatBar::WMPaint()

{

    HDC hdc;

    RECT rcMsg;

    HRGN hrgn;

    HFONT hfontOld;

    PAINTSTRUCT ps;

    HPEN hpenBlack, hpenWhite, hpenGray, hpenOld;

    hdc = BeginPaint(m_hwnd, &ps);

    // compute the message box rect

    //

    rcMsg.top	= 3;

    rcMsg.bottom= m_height - 3;

    rcMsg.left	= m_dxFont;

    rcMsg.right	= m_width - m_dxFont;

    // prepare the pens

    //

    hpenWhite	= GetStockObject(WHITE_PEN);

    hpenBlack	= GetStockObject(BLACK_PEN);

    hpenGray	= CreatePen(PS_SOLID, 1, GetSysColor(COLOR_BTNSHADOW));

    // draw a top gray line

    //

    hpenOld = SelectObject(hdc, hpenGray);

#if   defined(WIN16)

    MoveTo(hdc, ps.rcPaint.left, 0);

#elif defined(WIN32)

    MoveToEx(hdc, ps.rcPaint.left, 0, NULL);

#endif

    LineTo(hdc, ps.rcPaint.right, 0);

    // draw a white line just under

    //

    SelectObject(hdc, hpenWhite);

#if   defined(WIN16)

    MoveTo(hdc, ps.rcPaint.left, 1);

#elif defined(WIN32)

    MoveToEx(hdc, ps.rcPaint.left, 1, NULL);

#endif

    LineTo(hdc, ps.rcPaint.right, 1);

    // do not overwrite the background color

    //

    SetBkMode(hdc, TRANSPARENT);

    // message area

    //

    SelectObject(hdc, hpenBlack);

#if   defined(WIN16)

    MoveTo(hdc, rcMsg.left,  rcMsg.bottom);

#elif defined(WIN32)

    MoveToEx(hdc, rcMsg.left,  rcMsg.bottom, NULL);

#endif

    LineTo(hdc, rcMsg.left,  rcMsg.top);

    LineTo(hdc, rcMsg.right, rcMsg.top);

    SelectObject(hdc, hpenWhite);

    LineTo(hdc, rcMsg.right, rcMsg.bottom);

    LineTo(hdc, rcMsg.left,  rcMsg.bottom);

    // select the black pen for writing

    //

    SelectObject(hdc, hpenBlack);

    // select the status bar font to write in

    //

    hfontOld = SelectObject(hdc, m_hfont);

    // set the clipping region

    //

    hrgn = CreateRectRgn(

      rcMsg.left, rcMsg.top, rcMsg.right, rcMsg.bottom);

    SelectClipRgn(hdc, hrgn);

    // draw the status message

    //

    TextOut(

      hdc,

      rcMsg.left + (m_dxFont / 2),

      rcMsg.top + ((rcMsg.bottom - rcMsg.top - m_dyFont) / 2),

      STRING(m_bstrMsg), (SysStringLen(m_bstrMsg)));

    // cleanup

    //

    SelectObject(hdc, hpenOld);

    SelectObject(hdc, hfontOld);

    DeleteObject(hrgn);

    DeleteObject(hpenGray);

    EndPaint(m_hwnd, &ps);

}

extern "C" long FAR PASCAL

StatBarWndProc(

    HWND hwnd,

    unsigned int message,

    WPARAM wParam,

    LPARAM lParam)

{

    CStatBar FAR* psb;

    switch(message){

    case WM_SIZE:

      return 0;

    case WM_PAINT:

      psb = (CStatBar FAR*)GetWindowLong(hwnd, 0);

      psb->WMPaint();

      return 0;

    }

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

}

//---------------------------------------------------------------------

//                    Status Bar Utilities

//---------------------------------------------------------------------

extern "C" void

SBprintf(CStatBar FAR* psb, TCHAR FAR* szFmt, ...)

{

    va_list args;

static TCHAR buf[256];

    va_start(args, szFmt);

    wvsprintf(buf, szFmt, args);

    psb->SetText(WIDESTRING(buf));

    psb->Update();

}


 WINMAIN.CPP  (SPOLY Sample)

/***

*winmain.cpp

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*  Information Contained Herein Is Proprietary and Confidential.

*

*Purpose:

*  This module is the main entry point for the sample IDispatch polygon

*  server, spoly.exe.

*

*  This program is intended to demonstrate an implementation of the IDispatch

*  interface. Spoly is a very simple app, that implements two simple objects,

*  CPoly and CPoint and exposes their properties and methods for programatic

*  and cross-process access via IDispatch.

*

*Implementation Notes:

*

*****************************************************************************/

#include <stdio.h>

#include <string.h>

#include "spoly.h"

#include "cpoint.h"

#include "cpoly.h"

HANDLE g_hinst = 0;

HWND g_hwndFrame = 0;

HWND g_hwndClient = 0;

TCHAR g_szFrameWndClass[] = TSTR("FrameWClass");

CStatBar FAR* g_psb = NULL;

BOOL InitApplication(HANDLE);

BOOL InitInstance(HANDLE, int);

extern "C" int PASCAL WinMain(HANDLE, HANDLE, LPSTR, int);

extern "C" long FAR PASCAL FrameWndProc(HWND, UINT, WPARAM, LPARAM);

extern "C" int PASCAL

WinMain(

    HANDLE hinst,

    HANDLE hPrevInstance,

    LPSTR lpCmdLine,

    int nCmdShow)

{

    MSG msg;

    int retval;

    HRESULT hresult;

    if(!hPrevInstance)

      if(!InitApplication(hinst))

        return FALSE;

    if((hresult = InitOle()) != NOERROR)

      return FALSE;

    if(!InitInstance(hinst, nCmdShow)){

      retval = FALSE;

      UninitOle();

      goto LExit;

    }

    while(GetMessage(&msg, NULL, NULL, NULL)) {

      TranslateMessage(&msg);

      DispatchMessage(&msg);

    }

    CPoly::PolyTerm();

    retval = msg.wParam;

LExit:;

    return retval;

}

BOOL

InitApplication(HANDLE hinst)

{

    WNDCLASS  wc;

    wc.style            = CS_HREDRAW | CS_VREDRAW;

    wc.lpfnWndProc      = FrameWndProc;

    wc.cbClsExtra       = 0;

    wc.cbWndExtra       = 0;

    wc.hInstance        = hinst;

    wc.hIcon            = LoadIcon(hinst, TSTR("SPOLY"));

    wc.hCursor          = LoadCursor(NULL, IDC_ARROW);

    wc.hbrBackground    = (HBRUSH) (COLOR_APPWORKSPACE+1);

    wc.lpszMenuName     = TSTR("SPolyMenu");

    wc.lpszClassName    = g_szFrameWndClass;

    if(!RegisterClass(&wc))

      return FALSE;

    return TRUE;

}

#ifdef WIN32

#define szAppTitle TSTR("IDispatch Polygon Server (32-bit)")

#else //WIN32

#define szAppTitle TSTR("IDispatch Polygon Server")

#endif //WIN32

BOOL

InitInstance(HANDLE hinst, int nCmdShow)

{

    g_hinst = hinst;

    // Create a main frame window

    //

    g_hwndFrame = CreateWindow(

      g_szFrameWndClass,

      szAppTitle,

      WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,

      CW_USEDEFAULT,

      CW_USEDEFAULT,

      CW_USEDEFAULT,

      CW_USEDEFAULT,

      NULL,

      NULL,

      hinst,

      NULL);

    if(!g_hwndFrame)

      return FALSE;

    g_hwndClient = GetWindow(g_hwndFrame, GW_CHILD);

    if(!g_hwndClient)

      return FALSE;

    // create the status bar

    //

    g_psb = CStatBar::Create(g_hinst, g_hwndFrame);

    if(!g_psb)

      return FALSE;

    // initialize and show the status bar

    //

    g_psb->SetHeight(GetSystemMetrics(SM_CYCAPTION) - 1);

    g_psb->SetFont(GetStockObject(SYSTEM_FONT));

    g_psb->SetText(OLESTR(""));

    g_psb->Show();

    ShowWindow(g_hwndFrame, nCmdShow);

    UpdateWindow(g_hwndFrame);

    return TRUE;

}

void

FrameWndOnCreate(HWND hwnd)

{

    CLIENTCREATESTRUCT ccs;

    ccs.hWindowMenu = NULL;

    ccs.idFirstChild = IDM_FIRSTCHILD;

    g_hwndClient = CreateWindow(

      TSTR("MDICLIENT"),

      0,

      WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE,

      0, 0, 0, 0,

      hwnd,

      (HMENU) 1,

      g_hinst,

      &ccs);

}

void

FrameWndOnSize(HWND hwnd)

{

    RECT rc;

    int height;

    // Get the client rectangle for the frame window

    GetClientRect(hwnd, &rc);

    height = g_psb->GetHeight();

    // adjust the client win to make room for the status bar.

    //

    MoveWindow(

      g_hwndClient,

      rc.left,

      rc.top,

      rc.right - rc.left,

      rc.bottom - rc.top - height,

      TRUE);

    // move the status bar to the bottom of the newly positioned window.

    //

    g_psb->SetX(rc.left);

    g_psb->SetY(rc.bottom - height),

    g_psb->SetWidth(rc.right - rc.left);

    g_psb->Move();

}

extern "C" long FAR PASCAL

FrameWndProc(

    HWND hwnd,

    UINT message,

    WPARAM wParam,

    LPARAM lParam)

{

    switch(message){

    case WM_COMMAND:

      switch(wParam){

      case IDM_DUMP:

        CPoly::PolyDump();

        return 0;

      case IDM_CLEAR:

        InvalidateRect(g_hwndClient, NULL, TRUE);

        return 0;

      }

      break;

    case WM_CREATE:

      FrameWndOnCreate(hwnd);

      break;

    case WM_SIZE:

      FrameWndOnSize(hwnd);

      return 1;

    case WM_PAINT:

      CPoly::PolyDraw();

      break;

    case WM_CLOSE:

      DestroyWindow(hwnd);

      return 0;

    case WM_DESTROY:

      UninitOle();

      PostQuitMessage(0);

      return 0;

    }

    return DefFrameProc(hwnd, g_hwndClient, message, wParam, lParam);

}

#if defined(WIN32)

extern "C" OLECHAR FAR*

ConvertStrAtoW(char FAR* strIn, OLECHAR FAR* buf, UINT size)

{

  MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,

                       strIn, -1, buf, size) ;

  return buf;

}

extern "C" OLECHAR FAR*

WideString(char FAR* strIn)

{

  static OLECHAR buf[256];

  return (ConvertStrAtoW(strIn, buf, 256));

}

extern "C" char FAR*

ConvertStrWtoA(OLECHAR FAR* strIn, char FAR* buf, UINT size)

{

  int badConversion = FALSE;

  WideCharToMultiByte(CP_ACP, NULL,

                      strIn, -1,

                      buf, size,

                      NULL, &badConversion);

  return buf;

}

extern "C" char FAR*

AnsiString(OLECHAR FAR* strIn)

{

  static char buf[256];

  return (ConvertStrWtoA(strIn, buf, 256));

}

#endif


 SPOLY2

------------------------------------- OLE Automation Sample Program: SPoly2 -------------------------------------

SPoly2 is a program which draws polygons.  The only way to  make spoly2 draw a polygon is to use its programmability  interface.

One OLE Automation object is exposed by spoly2:

  * spoly2.application

Spoly2.Application is the object associated with spoly2's main window.  It controls drawing polygons and clearing the display.

----------------- Program Structure ----------------- SPoly2 implements IDispatch by using INTERFACEDATA, DispGetIDsOfNames and DispInvoke.

------------------------------------ Methods defined on spoly2.application ------------------------------------

Name	        Description ------------------------------------------------------------------ Draw()	Draw the polygon.

Reset()	Delete all points from the polygon.

AddPoint(X, Y)	Add a point with coordinates (x,y)  	to the polygon

EnumPoints() as VT_ENUM	Return a collection of the polygon's  	points

GetXOrigin() as short	Get the X origin of the polygon. 	 SetXOrigin(x as short)	Set the X origin of the polygon. 	 GetYOrigin() as short	Get the Y origin of the polygon. 	 SetYOrigin(y as short)	Set the Y origin of the polygon. 	 GetWidth() as short	Get and the line width of the polygon.

SetWidth(width as short)	Set the line width of the polygon.

--------------------------- Shortcomings of this sample --------------------------- 1. Many items in this sample should be properties.  Instead, they are implemented as methods.  Anything which behaves like an attribute of the object should be a property.

2. This is not a good example of how to implement a collection.


 MAKEFILE  (SPOLY2 Sample)

##############################################################################

#

#  (c) Copyright Microsoft Corp. 1992-1993 All Rights Reserved

#

#  File:

#

#    makefile - makefile for spoly2.exe

#

#  Purpose:

#

#    Builds the OLE 2.0 sample IDispatch server, spoly2.exe.

#

#

#  Usage:

#

#     NMAKE                     ; build with defaults

#     or: NMAKE option          ; build with the given option(s)

#     or: NMAKE clean           ; erase all compiled files

#

#     option:

#         dev = [win16 | win32] ; dev=win32 is the default

#         DEBUG=[0|1]           ; DEBUG=1 is the default

#

#  Notes:

#

#    This makefile assumes that the PATH, INCLUDE and LIB environment

#    variables are setup properly.

#

##############################################################################

##########################################################################

#

# Default Settings

#

!if "$(dev)" == ""

dev = win32

!endif

!if !("$(dev)" == "win16" || "$(dev)" == "win32")

!error Invalid dev option, choose from [win16 | win32]

!endif

!if "$(dev)" == "win16"

TARGET  = WIN16

!endif

!if "$(dev)" == "win32"

TARGET  = WIN32

!endif

!ifdef NODEBUG

DEBUG = 0

!endif

!if "$(DEBUG)" == "0"

NODEBUG = 1

!endif

!if "$(DEBUG)" == ""

DEBUG = 1

!endif

##########################################################################

#

# WIN16 Settings

#

!if "$(TARGET)" == "WIN16"

CC   = cl

LINK = link

RCFLAGS = -dWIN16

CFLAGS = -c -W3 -AM -GA -GEs -DWIN16

LINKFLAGS = /NOD /NOI /BATCH /ONERROR:NOEXE

LIBS = libw.lib mlibcew.lib

!if "$(DEBUG)" == "1"

CFLAGS = $(CFLAGS) -Od -Zi -D_DEBUG $(CL)

LINKFLAGS = $(LINKFLAGS) /COD

!else

CFLAGS = $(CFLAGS) -Ox $(CL)

LINKFLAGS = $(LINKFLAGS) /FAR /PACKC

!endif

!endif

##########################################################################

#

# WIN32 Settings

#

!if "$(TARGET)" == "WIN32"

!include <$(MSTOOLS)\samples\ole\include\olesampl.mak>

CC = $(cc)

CFLAGS = $(cflags) $(cvarsmt) -DINC_OLE2 -DUNICODE $(cdebug)

!ifndef NODEBUG

CFLAGS = $(CFLAGS) -D_DEBUG

!endif

LINK = $(link)

LINKFLAGS = $(linkdebug) $(guilflags)

RCFLAGS = -DWIN32

!endif

##########################################################################

#

# Application Settings

#

!if "$(TARGET)" == "WIN16"

LIBS = ole2.lib compobj.lib ole2disp.lib $(LIBS)

!else

!if "$(TARGET)" == "WIN32"

LIBS = $(olelibsmt)

!endif

!endif

OBJS = \

        winmain.obj     \

        cpoly.obj       \

        cpoint.obj      \

        cenumpt.obj     \

        statbar.obj     \

        clsid.obj       \

        misc.obj        \

        tdata.obj

goal : setflags spoly2.exe

setflags :

        set CL=$(CFLAGS)

clean :

    if exist *.obj      del *.obj

    if exist spoly2.exe del spoly2.exe

    if exist spoly2.map del spoly2.map

    if exist spoly2.res del spoly2.res

    if exist *.pdb       del *.pdb

##########################################################################

#

# Application Build (WIN16 Specific)

#

!if "$(TARGET)" == "WIN16"

spoly2.exe : $(OBJS) spoly2.def spoly2.res spoly2.ico

        link $(LINKFLAGS) @<<

$(OBJS),

$@,,

$(LIBS),

spoly2.def

<<

        rc -k -t spoly2.res $@

!endif

##########################################################################

#

# Application Build (WIN32 Specific)

#

!if "$(TARGET)" == "WIN32"

spoly2.exe : $(OBJS) spoly2.def spoly2.res spoly2.ico

      $(LINK) @<<

        $(LINKFLAGS)

        -out:$@

        -map:$*.map

        $(OBJS)

        spoly2.res

        $(LIBS)

<<

!endif

spoly2.res : spoly2.rc resource.h

        rc $(RCFLAGS) -r -fo$@ spoly2.rc

winmain.obj: winmain.cpp hostenv.h resource.h spoly.h statbar.h

        $(CC) winmain.cpp

cpoint.obj: cpoint.cpp cpoint.h hostenv.h spoly.h statbar.h

        $(CC) cpoint.cpp

cpoly.obj: cpoly.cpp cpoint.h cpoly.h hostenv.h spoly.h statbar.h

        $(CC) cpoly.cpp

clsid.obj: clsid.c clsid.h

        $(CC) clsid.c

cenumpt.obj: cenumpt.cpp cenumpt.h

        $(CC) cenumpt.cpp

statbar.obj: statbar.cpp statbar.h

        $(CC) statbar.cpp

misc.obj: misc.cpp hostenv.h spoly.h

        $(CC) misc.cpp

tdata.obj: tdata.cpp

        $(CC) tdata.cpp


 CENUMPT.H  (SPOLY2 Sample)

/***

*cenumpt.h

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*  Information Contained Herein Is Proprietary and Confidential.

*

*Purpose:

*  Definition of the CEnumPoint class.

*

*Implementation Notes:

*

*****************************************************************************/

class CEnumPoint : public IEnumVARIANT

{

public:

    static HRESULT Create(SAFEARRAY FAR* psa, CEnumPoint FAR* FAR* ppenum);

    /* IUnknown methods */

    STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppv);

    STDMETHOD_(unsigned long, AddRef)(void);

    STDMETHOD_(unsigned long, Release)(void);

    /* IEnumVARIANT methods */

    STDMETHOD(Next)(unsigned long celt, VARIANT FAR* rgvar, unsigned long FAR* pceltFetched);

    STDMETHOD(Skip)(unsigned long celt);

    STDMETHOD(Reset)(void);

    STDMETHOD(Clone)(IEnumVARIANT FAR* FAR* ppenum);

    CEnumPoint();

private:

    unsigned long m_refs;

    unsigned long m_celts;

    unsigned long m_iCurrent;

    SAFEARRAY FAR* m_psa;

};


 CENUMPT.CPP  (SPOLY2 Sample)

/***

*cenumpt.cpp

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*

*Purpose:

*  This module implements the CEnumPoint class.

*

*

*Implementation Notes:

*

*****************************************************************************/

#include "hostenv.h"

#include "cenumpt.h"

CEnumPoint::CEnumPoint()

{

    m_refs = 0;

    m_psa = NULL;

    m_celts = 0;

    m_iCurrent = 0;

}

/***

*HRESULT CEnumPoint::Create(SAFEARRAY*, CEnumPoint**)

*Purpose:

*  This routine creates a CPoint enumerator from the given

*  (1 X N) SafeArray of CPoint IDispatch pointers.

*

*Entry:

*  psa = pointer to a SafeArray of VARIANTs

*

*Exit:

*  return value = HRESULT

*

*  *ppenum = pointer to a CPoint enumerator

*

***********************************************************************/

HRESULT

CEnumPoint::Create(SAFEARRAY FAR* psa, CEnumPoint FAR* FAR* ppenum)

{

    long lBound;

    HRESULT hresult;

    CEnumPoint FAR* penum;

    // Verify that the SafeArray is the proper shape.

    //

    if(SafeArrayGetDim(psa) != 1)

      return ResultFromScode(E_INVALIDARG);

    hresult = SafeArrayGetLBound(psa, 1, &lBound);

    if(FAILED(hresult))

      return hresult;

    if(lBound != 0)

      return ResultFromScode(E_INVALIDARG);

    penum = new FAR CEnumPoint();

    if(penum == NULL)

      return ResultFromScode(E_OUTOFMEMORY);

    penum->AddRef();

    hresult = SafeArrayGetUBound(psa, 1, &lBound);

    if(FAILED(hresult))

      goto LError0;

    penum->m_psa = psa;

    penum->m_celts = lBound + 1;

    *ppenum = penum;

    return NOERROR;

LError0:;

    penum->Release();

    return hresult;

}

//---------------------------------------------------------------------

//                        IUnknown methods

//---------------------------------------------------------------------

STDMETHODIMP

CEnumPoint::QueryInterface(REFIID riid, void FAR* FAR* ppv)

{

    if(IsEqualIID(riid, IID_IEnumVARIANT) || IsEqualIID(riid, IID_IUnknown)){

      *ppv = this;

      AddRef();

      return NOERROR;

    }

    *ppv = NULL;

    return ResultFromScode(E_NOINTERFACE);

}

STDMETHODIMP_(unsigned long)

CEnumPoint::AddRef()

{

    return ++m_refs;

}

STDMETHODIMP_(unsigned long)

CEnumPoint::Release()

{

    if(--m_refs == 0){

      if(m_psa != NULL)

SafeArrayDestroy(m_psa);

      delete this;

      return 0;

    }

    return m_refs;

}

//---------------------------------------------------------------------

//                        IEnumVARIANT methods

//---------------------------------------------------------------------

/***

*HRESULT CEnumPoint::Next(unsigned long, VARIANT*, unsigned long*)

*Purpose:

*  Attempt to get the next 'celt' items in the enumeration sequence.

*

*Entry:

*  celt = the number of elements to get

*

*Exit:

*  return value = HRESULT

*    S_OK

*    S_FALSE - the end of the sequence was reached

*

*  rgvar = array of the next 'celt' items

*  *pceltFetched = count of the elements actually fetched.

*

***********************************************************************/

STDMETHODIMP

CEnumPoint::Next(

    unsigned long celt,

    VARIANT FAR* rgvar,

    unsigned long FAR* pceltFetched)

{

    long ix;

    unsigned int i;

    HRESULT hresult;

    for(i = 0; i < celt; ++i)

      VariantInit(&rgvar[i]);

    for(i = 0; i < celt; ++i){

      if(m_iCurrent == m_celts){

        hresult = ResultFromScode(S_FALSE);

goto LDone;

      }

      ix = m_iCurrent++;

      hresult = SafeArrayGetElement(m_psa, &ix, &rgvar[i]);

      if(FAILED(hresult))

goto LError0;

    }

    hresult = NOERROR;

LDone:;

    if (pceltFetched != NULL)

      *pceltFetched = i;

    return hresult;

LError0:;

    for(i = 0; i < celt; ++i)

      VariantClear(&rgvar[i]);

    return hresult;

}

/***

*HRESULT CEnumPoint::Skip(unsigned long)

*Purpose:

*  Attempt to skip over the next 'celt' elements in the enumeration

*  sequence.

*

*Entry:

*  celt = the count of elements to skip

*

*Exit:

*  return value = HRESULT

*    S_OK

*    S_FALSE -  the end of the sequence was reached

*

***********************************************************************/

STDMETHODIMP

CEnumPoint::Skip(unsigned long celt)

{

    m_iCurrent += celt;

    if(m_iCurrent > m_celts)

     m_iCurrent = m_celts;

    return (m_iCurrent == m_celts)

      ? ResultFromScode(S_FALSE) : NOERROR;

}

/***

*HRESULT CEnumPoint::Reset(void)

*Purpose:

*  Reset the enumeration sequence back to the beginning.

*

*Entry:

*  None

*

*Exit:

*  return value = SHRESULT CODE

*    S_OK

*

***********************************************************************/

STDMETHODIMP

CEnumPoint::Reset()

{

    m_iCurrent = 0;

    return NOERROR;

}

/***

*HRESULT CEnumPoint::Clone(IEnumVARIANT**)

*Purpose:

*  Retrun a CPoint enumerator with exactly the same state as the

*  current one.

*

*Entry:

*  None

*

*Exit:

*  return value = HRESULT

*    S_OK

*    E_OUTOFMEMORY

*

***********************************************************************/

STDMETHODIMP

CEnumPoint::Clone(IEnumVARIANT FAR* FAR* ppenum)

{

    HRESULT hresult;

    SAFEARRAY FAR* psa;

    CEnumPoint FAR* penum;

    hresult = SafeArrayCopy(m_psa, &psa);

    if(FAILED(hresult))

      return hresult;

    hresult = CEnumPoint::Create(psa, &penum);

    if(FAILED(hresult))

      goto LError0;

    // Assert(penum->m_celts == m_celts);

    penum->m_iCurrent = m_iCurrent;

    *ppenum = penum;

    return NOERROR;

LError0:

    SafeArrayDestroy(psa);

    return hresult;

}


 CLSID.H  (SPOLY2 Sample)

/***

*clsid.h

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*  Information Contained Herein Is Proprietary and Confidential.

*

*Purpose:

*  This file defines the CLSIDs

*

*Implementation Notes:

*

*****************************************************************************/

DEFINE_GUID(CLSID_CPoly2, 0x00020464, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46);

DEFINE_GUID(CLSID_CPoint2, 0x00020465, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46);

#ifdef INITGUID

# ifdef _MAC

DEFINE_GUID(GUID_NULL, 0L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);

DEFINE_GUID(IID_IDispatch, 0x00020400L, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46);

DEFINE_GUID(IID_IEnumVARIANT, 0x00020404L, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46);

DEFINE_GUID(IID_IUnknown, 0x00000000L, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46);

DEFINE_GUID(IID_IClassFactory, 0x00000001L, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46);

# endif

#endif


 CLSID.C  (SPOLY2 Sample)

/***

*clsid.c

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*  Information Contained Herein Is Proprietary and Confidential.

*

*Purpose:

*  This file allocates and initializes the CLSIDs.

*

*****************************************************************************/

#ifdef _PPCMAC

#pragma data_seg ("_FAR_DATA")

#pragma data_seg ( )

#endif //_PPCMAC

#ifdef _MAC

# include <Types.h>

#ifdef _MSC_VER

# include <Processe.h>

# include <AppleEve.h>

#else //_MSC_VER

# include <Processes.h>

# include <AppleEvents.h>

#endif //_MSC_VER

#else

# include <windows.h>

#endif

#ifndef WIN32

#include <compobj.h>

#endif //!WIN32

// this redefines the DEFINE_GUID() macro to do allocation.

//

#include <initguid.h>

#ifndef INITGUID

# define INITGUID

#endif

// due to the previous header, including this causes the DEFINE_GUID

// definitions in the following header(s) to actually allocate data.

//

#include "clsid.h"


 CPOINT.H  (SPOLY2 Sample)

/***

*cpoint.h

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*  Information Contained Herein Is Proprietary and Confidential.

*

*Purpose:

*  Definition of the CPoint class.

*

*  The CPoint object exposes two properties for programatic access

*  via the IDispatch interface.

*

*  properties:

*    X 	- the 'x' coordinate of the point

*    Y 	- the 'y' coordinate of the point

*

*Implementation Notes:

*

*****************************************************************************/

#ifndef	CLASS

#ifdef	__TURBOC__

#define CLASS class huge

#else

#define CLASS class FAR

#endif

#endif

class CPoly;

CLASS CPoint : public IDispatch {

    friend class CPoly;

public:

    static CPoint FAR* Create();

    /* IUnknown methods */

    STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppvObj);

    STDMETHOD_(unsigned long, AddRef)(void);

    STDMETHOD_(unsigned long, Release)(void);

    /* IDispatch methods */

    STDMETHOD(GetTypeInfoCount)(unsigned int FAR* pcTypeInfo);

    STDMETHOD(GetTypeInfo)(

      unsigned int iTypeInfo,

      LCID lcid,

      ITypeInfo FAR* FAR* ppTypeInfo);

    STDMETHOD(GetIDsOfNames)(

      REFIID riid,

      OLECHAR FAR* FAR* rgszNames,

      unsigned int cNames,

      LCID lcid,

      DISPID FAR* rgdispid);

    STDMETHOD(Invoke)(

      DISPID dispidMember,

      REFIID riid,

      LCID lcid,

      unsigned short wFlags,

      DISPPARAMS FAR* pdispparams,

      VARIANT FAR* pvarResult,

      EXCEPINFO FAR* pexcepinfo,

      unsigned int FAR* pwArgErr);

    /* Introduced methods */

    virtual short METHODCALLTYPE EXPORT GetX(void);

    virtual void  METHODCALLTYPE EXPORT SetX(short x);

    virtual short METHODCALLTYPE EXPORT GetY(void);

    virtual void  METHODCALLTYPE EXPORT SetY(short y);

private:

    CPoint();

    unsigned long m_refs;

    short m_x;

    short m_y;

    ITypeInfo FAR* m_ptinfo;

};

// member DISPIDs

//

enum IDMEMBER_CPOINT {

    IDMEMBER_CPOINT_GETX = 1,

    IDMEMBER_CPOINT_SETX,

    IDMEMBER_CPOINT_GETY,

    IDMEMBER_CPOINT_SETY,

    IDMEMBER_CPOINT_MAX

};

// member indices - this is an enumeration of all members on CPoint

//

enum IMETH_CPOINT {

    IMETH_CPOINT_QUERYINTERFACE = 0,

    IMETH_CPOINT_ADDREF,

    IMETH_CPOINT_RELEASE,

    IMETH_CPOINT_GETTYPEINFOCOUNT,

    IMETH_CPOINT_GETTYPEINFO,

    IMETH_CPOINT_GETIDSOFNAMES,

    IMETH_CPOINT_INVOKE,

    IMETH_CPOINT_GETX,

    IMETH_CPOINT_SETX,

    IMETH_CPOINT_GETY,

    IMETH_CPOINT_SETY

};

// structure used to link together lists of points

//

struct POINTLINK {

    POINTLINK FAR* next;

    CPoint FAR* ppoint;

};

// The CPoint Class Factory

//

CLASS CPointCF : public IClassFactory

{

public:

    static IClassFactory FAR* Create();

    /* IUnknown methods */

    STDMETHOD(QueryInterface)(REFIID iid, void FAR* FAR* ppv);

    STDMETHOD_(unsigned long, AddRef)(void);

    STDMETHOD_(unsigned long, Release)(void);

    /* IClassFactory methods */

    STDMETHOD(CreateInstance)(

      IUnknown FAR* pUnkOuter, REFIID iid, void FAR* FAR* ppv);

#ifdef _MAC

    STDMETHOD(LockServer)(unsigned long fLock);

#else

    STDMETHOD(LockServer)(BOOL fLock);

#endif

private:

    CPointCF();

    unsigned long m_refs;

};


 CPOINT.CPP  (SPOLY2 Sample)

/***

*cpoint.cpp

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*

*Purpose:

*  This module implements the CPoint and CPointCF classes.

*

*  This module is intended as a sample implementation of the IDispatch

*  interface, and its purpose is to demonstrate how an object can

*  expose methods and properties for programatic and cross-process

*  access via the IDispatch interface.

*

*Implementation Notes:

*

*****************************************************************************/

#include "spoly.h"

#include "cpoint.h"

CPoint::CPoint()

{

    m_x = 0;

    m_y = 0;

    m_refs = 0;

    m_ptinfo = NULL;

}

/***

*CPoint::Create(void)

*Purpose:

*  Create an instance of a CPoint object.

*

*Entry:

*  None

*

*Exit:

*  returns a CPoint*, NULL if creation failed.

*

***********************************************************************/

CPoint FAR*

CPoint::Create()

{

    HRESULT hresult;

    CPoint FAR* ppoint;

    ITypeInfo FAR* ptinfo;

extern INTERFACEDATA NEAR g_idataCPoint;

    if((ppoint = new FAR CPoint()) == NULL)

      return NULL;

    ppoint->AddRef();

    hresult =

      CreateDispTypeInfo(&g_idataCPoint, LOCALE_SYSTEM_DEFAULT, &ptinfo);

    if(hresult != NOERROR)

      goto LError0;

    ppoint->m_ptinfo = ptinfo;

    return ppoint;

LError0:;

    ppoint->Release();

    return NULL;

}

//---------------------------------------------------------------------

//                     IUnknown Methods

//---------------------------------------------------------------------

STDMETHODIMP

CPoint::QueryInterface(REFIID riid, void FAR* FAR* ppv)

{

    if(IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IDispatch)){

      *ppv = this;

      AddRef();

      return NOERROR;

    }

    *ppv = NULL;

    return ResultFromScode(E_NOINTERFACE);

}

STDMETHODIMP_(unsigned long)

CPoint::AddRef(void)

{

    return ++m_refs;

}

STDMETHODIMP_(unsigned long)

CPoint::Release(void)

{

    if(--m_refs == 0){

      if(m_ptinfo != NULL){

m_ptinfo->Release();

      }

      delete this;

      return 0;

    }

    return m_refs;

}

//---------------------------------------------------------------------

//                     IDispatch methods

//---------------------------------------------------------------------

STDMETHODIMP

CPoint::GetTypeInfoCount(unsigned int FAR* pctinfo)

{

    // this object has a single *introduced* interface

    //

    *pctinfo = 1;

    return NOERROR;

}

STDMETHODIMP

CPoint::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)

{

    UNUSED(lcid);

    if(itinfo != 0)

      return ResultFromScode(DISP_E_BADINDEX);

    m_ptinfo->AddRef();

    *pptinfo = m_ptinfo;

    return NOERROR;

}

/***

*HRESULT CPoint::GetIDsOfNames(REFIID, char**, unsigned int, LCID, DISPID*)

*Purpose:

*  This method translates the given array of names to a corresponding

*  array of DISPIDs.

*

*  Index 0 of the name array is the member name, and indices 1-N if

*  present represent named parameters on that member.

*

*  The local ID ('lcid') is unused by this naive implementation. A more

*  sophisticated implementation, sensitive to localization and natural

*  language support would use the locale ID to interpret the given names

*  in a correct locale specific context.

*

*Entry:

*  rgszNames = pointer to an array of names

*  cNames = the number of names in the rgszNames array

*  lcid = the callers locale ID

*

*Exit:

*  return value = HRESULT

*  rgid = array of name IDs corresponding to the rgszNames array

*    this array will contain -1 for each entry that is not known.

*

***********************************************************************/

STDMETHODIMP

CPoint::GetIDsOfNames(

    REFIID riid,

    OLECHAR FAR* FAR* rgszNames,

    unsigned int cNames,

    LCID lcid,

    DISPID FAR* rgdispid)

{

    UNUSED(lcid);

    if(!IsEqualIID(riid,IID_NULL))

      return ResultFromScode(DISP_E_UNKNOWNINTERFACE);

    return DispGetIDsOfNames(m_ptinfo, rgszNames, cNames, rgdispid);

}

/***

*HRESULT CPoint::Invoke(...)

*Purpose:

*  Dispatch a method or property request for objects of type CPoint.

*

*  see the IDispatch document for more information, and a general

*  description of this method.

*

*Entry:

*  dispidMember = the DISPID of the member being requested

*

*  riid = reference to the interface ID of the interface on this object

*    that the requested member belongs to. IID_NULL means to interpret

*    the member as belonging to the implementation defined "default"

*    or "primary" interface.

*

*  lcid = the caller's locale ID

*

*  wFlags = flags indicating the type of access being requested

*

*  pdispparams = pointer to the DISPPARAMS struct containing the

*    requested members arguments (if any) and its named parameter

*    DISPIDs (if any).

*

*Exit:

*  return value = HRESULT

*   see the IDispatch spec for a description of possible success codes.

*

*  pvarResult = pointer to a caller allocated VARIANT containing

*    the members return value (if any).

*

*  pexcepinfo = caller allocated exception info structure, this will

*    be filled in only if an exception was raised that must be passed

*    up through Invoke to an enclosing handler.

*

*  puArgErr = pointer to a caller allocated UINT, that will contain the

*    index of the offending argument if a DISP_E_TYPEMISMATCH error

*    was returned indicating that one of the arguments was of an

*    incorrect type and/or could not be reasonably coerced to a proper

*    type.

*

***********************************************************************/

STDMETHODIMP

CPoint::Invoke(

    DISPID dispidMember,

    REFIID riid,

    LCID lcid,

    unsigned short wFlags,

    DISPPARAMS FAR* pdispparams,

    VARIANT FAR* pvarResult,

    EXCEPINFO FAR* pexcepinfo,

    unsigned int FAR* puArgErr)

{

    UNUSED(lcid);

    if(!IsEqualIID(riid, IID_NULL))

      return ResultFromScode(DISP_E_UNKNOWNINTERFACE);

    return DispInvoke(

      this, m_ptinfo,

      dispidMember, wFlags, pdispparams,

      pvarResult, pexcepinfo, puArgErr);

}

//---------------------------------------------------------------------

//                       Introduced methods

//---------------------------------------------------------------------

short METHODCALLTYPE EXPORT

CPoint::GetX()

{

    return m_x;

}

void METHODCALLTYPE EXPORT

CPoint::SetX(short x)

{

    m_x = x;

}

short METHODCALLTYPE EXPORT

CPoint::GetY()

{

    return m_y;

}

void METHODCALLTYPE EXPORT

CPoint::SetY(short y)

{

    m_y = y;

}

//---------------------------------------------------------------------

//         Implementation of the CPoint Class Factory

//---------------------------------------------------------------------

CPointCF::CPointCF()

{

    m_refs = 0;

}

IClassFactory FAR*

CPointCF::Create()

{

    CPointCF FAR* pCF;

    if((pCF = new FAR CPointCF()) == NULL)

      return NULL;

    pCF->AddRef();

    return pCF;

}

STDMETHODIMP

CPointCF::QueryInterface(REFIID riid, void FAR* FAR* ppv)

{

    if(IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IClassFactory)){

      *ppv = this;

      ++m_refs;

      return NOERROR;

    }

    *ppv = NULL;

    return ResultFromScode(E_NOINTERFACE);

}

STDMETHODIMP_(unsigned long)

CPointCF::AddRef(void)

{

    return ++m_refs;

}

STDMETHODIMP_(unsigned long)

CPointCF::Release(void)

{

    if(--m_refs == 0){

      delete this;

      return 0;

    }

    return m_refs;

}

STDMETHODIMP

CPointCF::CreateInstance(

    IUnknown FAR* punkOuter,

    REFIID riid,

    void FAR* FAR* ppv)

{

    HRESULT hresult;

    CPoint FAR *ppoint;

    UNUSED(punkOuter);

    if((ppoint = CPoint::Create()) == NULL){

      *ppv = NULL;

      return ResultFromScode(E_OUTOFMEMORY);

    }

    hresult = ppoint->QueryInterface(riid, ppv);

    ppoint->Release();

    return hresult;

}

STDMETHODIMP

#ifdef _MAC

CPointCF::LockServer(unsigned long fLock)

#else

CPointCF::LockServer(BOOL fLock)

#endif

{

    UNUSED(fLock);

    return NOERROR;

}


 CPOLY.H  (SPOLY2 Sample)

/***

*cpoly.h

*

*  Copyright (C) 1992-1994 Microsoft Corporation.  All Rights Reserved.

*  Information Contained Herein Is Proprietary and Confidential.

*

*Purpose:

*  Definition of the CPoly class.

*

*  The CPoly class defines a number of methods and exposes them for

*  external programmability via IDispatch,

*

*  methods:

*    DRAW	- draw the polygon

*    RESET	- delete all points from the polygon

*

*    ADDPOINT(X, Y)	- add a point with coordinates (x,y) to the polygon

*

*    ENUMPOINTS	- return a collection of the polygon's points

*

*    GETXORIGIN	- get and set the X origin of the polygon

*    SETXORIGIN

*

*    GETYORIGIN	- get and set the Y origin of the polygon

*    SETYORIGIN

*

*    GETWIDTH	- get and set the line width of the polygon

*    SETWIDTH

*

*  UNDONE: update description

*

*Implementation Notes:

*

*****************************************************************************/

#ifndef	CLASS

# ifdef	__TURBOC__

#  define CLASS class huge

# else

#  define CLASS class FAR

# endif

#endif

class CPoint;

CLASS CPoly : public IDispatch

{

public:

    static CPoly FAR* Create();

    /* IUnknown methods */

    STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppvObj);

    STDMETHOD_(unsigned long, AddRef)(void);

    STDMETHOD_(unsigned long, Release)(void);

    /* IDispatch methods */

    STDMETHOD(GetTypeInfoCount)(unsigned int FAR* pcTypeInfo);

    STDMETHOD(GetTypeInfo)(

      unsigned int iTypeInfo,

      LCID lcid,

      ITypeInfo FAR* FAR* ppTypeInfo);

    STDMETHOD(GetIDsOfNames)(

      REFIID riid,

      OLECHAR FAR* FAR* rgszNames,

      unsigned int cNames,

      LCID lcid,

      DISPID FAR* rgdispid);

    STDMETHOD(Invoke)(

      DISPID dispidMember,

      REFIID riid,

      LCID lcid,

      unsigned short wFlags,

      DISPPARAMS FAR* pdispparams,

      VARIANT FAR* pvarResult,

      EXCEPINFO FAR* pexcepinfo,

      unsigned int FAR* puArgErr);

    /* Introduced methods */

    virtual void  METHODCALLTYPE EXPORT Draw(void);

    virtual void  METHODCALLTYPE EXPORT Reset(void);

    // add a point with the given 'x' and 'y' coordinates

    virtual HRESULT METHODCALLTYPE EXPORT AddPoint(short x, short y);

    // return a collection of the polygon's points

    virtual IUnknown FAR* METHODCALLTYPE EXPORT EnumPoints(void);

    // get/set the polygon's X origin property

    virtual short METHODCALLTYPE EXPORT GetXOrigin(void);

    virtual void  METHODCALLTYPE EXPORT SetXOrigin(short x);

    // get/set the polygon's Y origin property

    virtual short METHODCALLTYPE EXPORT GetYOrigin(void);

    virtual void  METHODCALLTYPE EXPORT SetYOrigin(short y);

    virtual short METHODCALLTYPE EXPORT GetWidth(void);

    virtual void  METHODCALLTYPE EXPORT SetWidth(short width);

    virtual short METHODCALLTYPE EXPORT get_red(void);

    virtual void  METHODCALLTYPE EXPORT set_red(short red);

    virtual short METHODCALLTYPE EXPORT get_green(void);

    virtual void  METHODCALLTYPE EXPORT set_green(short green);

    virtual short METHODCALLTYPE EXPORT get_blue(void);

    virtual void  METHODCALLTYPE EXPORT set_blue(short blue);

    // Debug method

    virtual void  METHODCALLTYPE EXPORT Dump(void);

public:

    // Draw all polygons.

    static void PolyDraw(void);

    // Release all polygons.

    static void PolyTerm(void);

    // Dump all polygons to dbwin.

    static void PolyDump(void);

private:

    CPoly();

    short m_xorg;

    short m_yorg;

    short m_width;

    short m_red;

    short m_green;

    short m_blue;

    unsigned long m_refs;

    unsigned int m_cPoints;

    ITypeInfo FAR* m_ptinfo;

    POINTLINK FAR* m_ppointlink;

    POINTLINK FAR* m_ppointlinkLast;

};

// DISPIDs for the members and properties available via IDispatch.

//

enum IDMEMBER_CPOLY {

    IDMEMBER_CPOLY_DRAW = 1,

    IDMEMBER_CPOLY_RESET,

    IDMEMBER_CPOLY_ADDPOINT,

    IDMEMBER_CPOLY_ENUMPOINTS,

    IDMEMBER_CPOLY_GETXORIGIN,

    IDMEMBER_CPOLY_SETXORIGIN,

    IDMEMBER_CPOLY_GETYORIGIN,

    IDMEMBER_CPOLY_SETYORIGIN,

    IDMEMBER_CPOLY_GETWIDTH,

    IDMEMBER_CPOLY_SETWIDTH,

    IDMEMBER_CPOLY_GETRED,

    IDMEMBER_CPOLY_SETRED,

    IDMEMBER_CPOLY_GETGREEN,

    IDMEMBER_CPOLY_SETGREEN,

    IDMEMBER_CPOLY_GETBLUE,

    IDMEMBER_CPOLY_SETBLUE,

    IDMEMBER_CPOLY_DUMP,

    IDMEMBER_CPOLY_MAX

};

// CPoly method indices

//

enum IMETH_CPOLY {

    IMETH_CPOLY_QUERYINTERFACE = 0,

    IMETH_CPOLY_ADDREF,

    IMETH_CPOLY_RELEASE,

    IMETH_CPOLY_GETTYPEINFOCOUNT,

    IMETH_CPOLY_GETTYPEINFO,

    IMETH_CPOLY_GETIDSOFNAMES,

    IMETH_CPOLY_INVOKE,

    IMETH_CPOLY_DRAW,

    IMETH_CPOLY_RESET,

    IMETH_CPOLY_ADDPOINT,

    IMETH_CPOLY_ENUMPOINTS,

    IMETH_CPOLY_GETXORIGIN,

    IMETH_CPOLY_SETXORIGIN,

    IMETH_CPOLY_GETYORIGIN,

    IMETH_CPOLY_SETYORIGIN,

    IMETH_CPOLY_GETWIDTH,

    IMETH_CPOLY_SETWIDTH,

    IMETH_CPOLY_GETRED,

    IMETH_CPOLY_SETRED,

    IMETH_CPOLY_GETGREEN,

    IMETH_CPOLY_SETGREEN,

    IMETH_CPOLY_GETBLUE,

    IMETH_CPOLY_SETBLUE,

    IMETH_CPOLY_DUMP,

    IMETH_CPOLY_MAX

};

// structure used to link together polygons

//

struct POLYLINK {

    POLYLINK FAR* next;

    CPoly FAR* ppoly;

};

// The CPoly class factory

//

CLASS CPolyCF : public IClassFactory

{

public:

    static IClassFactory FAR* Create();

    /* IUnknown methods */

    STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppv);

    STDMETHOD_(unsigned long, AddRef)(void);

    STDMETHOD_(unsigned long, Release)(void);

    /* IClassFactory methods */

    STDMETHOD(CreateInstance)(

      IUnknown FAR* pUnkOuter, REFIID riid, void FAR* FAR* ppv);

#ifdef _MAC

    STDMETHOD(LockServer)(unsigned long fLock);

#else

    STDMETHOD(LockServer)(BOOL fLock);

#endif

private:

    CPolyCF();

    unsigned long m_refs;

};


 CPOLY.CPP  (SPOLY2 Sample)

/***

*cpoly.cpp

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*

*Purpose:

*  This module implements the CPoly and CPolyCF classes.

*

*  This module is intended as a sample implementation of the IDispatch

*  interface, and its purpose is to demonstrate how an object can

*  expose methods and properties for programatic and cross-process

*  access via the IDispatch interface.

*

*Implementation Notes:

*

*****************************************************************************/

#include "spoly.h"

#include "cpoint.h"

#include "cpoly.h"

#include "cenumpt.h"

#ifndef _MAC

extern CStatBar FAR* g_psb;

#endif

#ifdef _MAC

extern "C" WindowPtr g_pwndClient;

#endif

// our global list of polygons.

//

POLYLINK FAR* g_ppolylink = (POLYLINK FAR*)NULL;

// global count of polygons.

//

int g_cPoly = 0;

CPoly::CPoly()

{

    m_refs = 0;

    m_xorg = 0;

    m_yorg = 0;

    m_width = 0;

    m_cPoints = 0;

    m_red   = 0;

    m_green = 0;

    m_blue  = 0;

    m_ptinfo = NULL;

    m_ppointlink = NULL;

    m_ppointlinkLast = NULL;

}

/***

*CPoly *CPoly::Create(void)

*Purpose:

*  Create an instance of a CPoly object, and add it to the global

*  list of polygons.

*

*Entry:

*  None

*

*Exit:

*  returns a polygon object, NULL the allocation failed.

*

***********************************************************************/

CPoly FAR*

CPoly::Create()

{

    HRESULT hresult;

    CPoly FAR* ppoly;

    ITypeInfo FAR* ptinfo;

    POLYLINK FAR* ppolylink;

extern INTERFACEDATA NEAR g_idataCPoly;

    if((ppolylink = new FAR POLYLINK) == (POLYLINK FAR*)NULL)

      return (CPoly FAR*)NULL;

    if((ppoly = new FAR CPoly()) == (CPoly FAR*)NULL)

      return (CPoly FAR*)NULL;

    ppoly->AddRef();

    // create and attach its TypeInfo

    //

    hresult = CreateDispTypeInfo(&g_idataCPoly, LOCALE_SYSTEM_DEFAULT, &ptinfo);

    if(hresult != NOERROR)

      goto LError0;

    ppoly->m_ptinfo = ptinfo;

    // push the new polygon onto the front of the polygon list.

    //

    ++g_cPoly;

    ppolylink->ppoly = ppoly;

    ppolylink->next = g_ppolylink;

    g_ppolylink = ppolylink;

#ifndef _MAC

    SBprintf(g_psb, TSTR("#poly = %d"), g_cPoly);

#endif

    return ppoly;

LError0:;

    ppoly->Release();

    return NULL;

}

//---------------------------------------------------------------------

//                     IUnknown Methods

//---------------------------------------------------------------------

STDMETHODIMP

CPoly::QueryInterface(REFIID riid, void FAR* FAR* ppv)

{

    if(!IsEqualIID(riid, IID_IUnknown))

      if(!IsEqualIID(riid, IID_IDispatch)) {

*ppv = NULL;

        return ResultFromScode(E_NOINTERFACE);

    }

    *ppv = this;

    AddRef();

    return NOERROR;

}

STDMETHODIMP_(unsigned long)

CPoly::AddRef()

{

    return ++m_refs;

}

STDMETHODIMP_(unsigned long)

CPoly::Release()

{

    POLYLINK FAR* FAR* pppolylink, FAR* ppolylinkDead;

    if(--m_refs == 0){

      Reset(); // release all CPoints

      // remove ourselves from the global list of polygons

      //

      for( pppolylink = &g_ppolylink;

  *pppolylink != NULL;

   pppolylink = &(*pppolylink)->next)

      {

if((*pppolylink)->ppoly == this){

  ppolylinkDead = *pppolylink;

  *pppolylink = (*pppolylink)->next;

  delete ppolylinkDead;

  break;

}

      }

      if(m_ptinfo != NULL){

m_ptinfo->Release();

      }

      --g_cPoly;

#ifndef _MAC

      SBprintf(g_psb, TSTR("#poly = %d"), g_cPoly);

#endif

      delete this;

      return 0;

    }

    return m_refs;

}

//---------------------------------------------------------------------

//                     IDispatch Methods

//---------------------------------------------------------------------

STDMETHODIMP

CPoly::GetTypeInfoCount(unsigned int FAR* pctinfo)

{

    // This object has a single *introduced* interface

    //

    *pctinfo = 1;

    return NOERROR;

}

STDMETHODIMP

CPoly::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)

{

    UNUSED(lcid);

    if(itinfo != 0)

      return ResultFromScode(DISP_E_BADINDEX);

    m_ptinfo->AddRef();

    *pptinfo = m_ptinfo;

    return NOERROR;

}

/***

*HRESULT CPoly::GetIDsOfNames(char**, unsigned int, LCID, DISPID*)

*Purpose:

*  This method translates the given array of names to a corresponding

*  array of DISPIDs.

*

*  This method deferrs to a common implementation shared by

*  both the CPoly and CPoint objects. See the description of

*  'SPolyGetIDsOfNames()' in dispimpl.cpp for more information.

*

*Entry:

*  rgszNames = pointer to an array of names

*  cNames = the number of names in the rgszNames array

*  lcid = the callers locale ID

*

*Exit:

*  return value = HRESULT

*  rgdispid = array of DISPIDs corresponding to the rgszNames array

*    this array will contain -1 for each entry that is not known.

*

***********************************************************************/

STDMETHODIMP

CPoly::GetIDsOfNames(

    REFIID riid,

    OLECHAR FAR* FAR* rgszNames,

    unsigned int cNames,

    LCID lcid,

    DISPID FAR* rgdispid)

{

    UNUSED(lcid);

    if(!IsEqualIID(riid, IID_NULL))

      return ResultFromScode(DISP_E_UNKNOWNINTERFACE);

    return DispGetIDsOfNames(m_ptinfo, rgszNames, cNames, rgdispid);

}

/***

*HRESULT CPoly::Invoke(...)

*Purpose:

*  Dispatch a method or property request for objects of type CPoly.

*

*  see the IDispatch document for more information, and a general

*  description of this method.

*

*Entry:

*  dispidMember = the DISPID of the member being requested

*

*  riid = reference to the interface ID of the interface on this object

*    that the requested member belongs to. IID_NULL means to interpret

*    the member as belonging to the implementation defined "default"

*    or "primary" interface.

*

*  lcid = the caller's locale ID

*

*  wFlags = flags indicating the type of access being requested

*

*  pdispparams = pointer to the DISPPARAMS struct containing the

*    requested members arguments (if any) and its named parameter

*    DISPIDs (if any).

*

*Exit:

*  return value = HRESULT

*   see the IDispatch spec for a description of possible success codes.

*

*  pvarResult = pointer to a caller allocated VARIANT containing

*    the members return value (if any).

*

*  pexcepinfo = caller allocated exception info structure, this will

*    be filled in only if an exception was raised that must be passed

*    up through Invoke to an enclosing handler.

*

*  puArgErr = pointer to a caller allocated UINT, that will contain the

*    index of the offending argument if a DISP_E_TYPEMISMATCH error

*    was returned indicating that one of the arguments was of an

*    incorrect type and/or could not be reasonably coerced to a proper

*    type.

*

***********************************************************************/

STDMETHODIMP

CPoly::Invoke(

    DISPID dispidMember,

    REFIID riid,

    LCID lcid,

    unsigned short wFlags,

    DISPPARAMS FAR* pdispparams,

    VARIANT FAR* pvarResult,

    EXCEPINFO FAR* pexcepinfo,

    unsigned int FAR* puArgErr)

{

    UNUSED(lcid);

    if(!IsEqualIID(riid, IID_NULL))

      return ResultFromScode(DISP_E_UNKNOWNINTERFACE);

    return DispInvoke(

      this, m_ptinfo,

      dispidMember, wFlags, pdispparams,

      pvarResult, pexcepinfo, puArgErr);

}

//---------------------------------------------------------------------

//                     Introduced Methods

//---------------------------------------------------------------------

/***

*void CPoly::Draw(void)

*Purpose:

*  Draw the polygon, using the current x/y origin and line width

*  properties.

*

*Entry:

*  None

*

*Exit:

*  None

*

***********************************************************************/

void METHODCALLTYPE EXPORT

CPoly::Draw()

{

    short xorg, yorg;

    POINTLINK FAR* ppointlinkFirst, FAR* ppointlink;

    if((ppointlinkFirst = m_ppointlink) == (POINTLINK FAR*)NULL)

      return;

#ifdef _MAC /* { */

    short x,y;

    RGBColor rgb;

    WindowPtr pwndSaved;

    GetPort(&pwndSaved);

    SetPort(g_pwndClient);

    PenNormal();

    PenSize(m_width, m_width);

    rgb.red = m_red;

    rgb.green = m_green;

    rgb.blue = m_blue;

    RGBForeColor(&rgb);

    xorg = m_xorg;

    yorg = m_yorg;

    MoveTo(

      xorg + ppointlinkFirst->ppoint->m_x,

      yorg + ppointlinkFirst->ppoint->m_y);

    for(ppointlink = ppointlinkFirst->next;

ppointlink != (POINTLINK FAR*)NULL;

ppointlink = ppointlink->next)

    {

      x = xorg + ppointlink->ppoint->m_x;

      y = yorg + ppointlink->ppoint->m_y;

      LineTo(x, y);

    }

    LineTo(

      xorg + ppointlinkFirst->ppoint->m_x,

      yorg + ppointlinkFirst->ppoint->m_y);

    SetPort(pwndSaved);

#else /* }{ */

    HDC hdc;

    RECT rect;

    HPEN hpen, hpenOld;

extern HWND g_hwndClient;

    GetClientRect(g_hwndClient, &rect);

    xorg = m_xorg + (short) rect.left;

    yorg = m_yorg + (short) rect.top;

    hdc = GetDC(g_hwndClient);

    hpen = CreatePen(PS_SOLID, m_width, RGB(m_red, m_green, m_blue));

    hpenOld = SelectObject(hdc, hpen);

#ifdef WIN32

    MoveToEx(hdc,

      xorg + ppointlinkFirst->ppoint->m_x,

      yorg + ppointlinkFirst->ppoint->m_y, NULL);

#else

    MoveTo(hdc,

      xorg + ppointlinkFirst->ppoint->m_x,

      yorg + ppointlinkFirst->ppoint->m_y);

#endif

    for(ppointlink = ppointlinkFirst->next;

ppointlink != (POINTLINK FAR*)NULL;

ppointlink = ppointlink->next)

    {

      LineTo(hdc,

xorg + ppointlink->ppoint->m_x,

yorg + ppointlink->ppoint->m_y);

    }

    LineTo(hdc,

      xorg + ppointlinkFirst->ppoint->m_x,

      yorg + ppointlinkFirst->ppoint->m_y);

    SelectObject(hdc, hpenOld);

    DeleteObject(hpen);

    ReleaseDC(g_hwndClient, hdc);

#endif /* } */

}

/***

*void CPoly::Reset(void)

*Purpose:

*  Release all points referenced by this poly.

*

*Entry:

*  None

*

*Exit:

*  None

*

***********************************************************************/

void METHODCALLTYPE EXPORT

CPoly::Reset()

{

    POINTLINK FAR* ppointlink, FAR* ppointlinkNext;

    for(ppointlink = m_ppointlink;

ppointlink != (POINTLINK FAR*)NULL;

ppointlink = ppointlinkNext)

    {

      ppointlinkNext = ppointlink->next;

      ppointlink->ppoint->Release();

      delete ppointlink;

    }

    m_cPoints = 0;

    m_ppointlink = NULL;

    m_ppointlinkLast = NULL;

}

/***

*HRESULT CPoly::AddPoint(short, short)

*Purpose:

*  Add a CPoint with the given coordinates to the end of our current

*  list of points.

*

*Entry:

*  x,y = the x and y coordinates of the new point.

*

*Exit:

*  return value = HRESULT

*

***********************************************************************/

HRESULT METHODCALLTYPE

CPoly::AddPoint(short x, short y)

{

    CPoint FAR* ppoint;

    POINTLINK FAR* ppointlink;

    ppoint = CPoint::Create();

    if(ppoint == (CPoint FAR*)NULL)

      return ResultFromScode(E_OUTOFMEMORY);

    ppoint->SetX(x);

    ppoint->SetY(y);

    ppointlink = new FAR POINTLINK;

    if(ppointlink == (POINTLINK FAR*)NULL){

      delete ppoint;

      return ResultFromScode(E_OUTOFMEMORY);

    }

    ppointlink->ppoint = ppoint;

    ppointlink->next = (POINTLINK FAR*)NULL;

    if(m_ppointlinkLast == (POINTLINK FAR*)NULL){

      m_ppointlink = m_ppointlinkLast = ppointlink;

    }else{

      m_ppointlinkLast->next = ppointlink;

      m_ppointlinkLast = ppointlink;

    }

    ++m_cPoints;

    return NOERROR;

}

/***

*IUnknown FAR* CPoly::EnumPoints(void);

*Purpose:

*  Return and enumerator for the points in this polygon.

*

*Entry:

*  None

*

*Exit:

*  return value = HRESULT

*

*  *ppenum = pointer to an IEnumVARIANT for the points in this polygon

*

***********************************************************************/

IUnknown FAR* METHODCALLTYPE EXPORT

CPoly::EnumPoints()

{

    unsigned int i;

    HRESULT hresult;

    VARIANT var;

    SAFEARRAY FAR* psa;

    IUnknown FAR* punk;

    CEnumPoint FAR* penum;

    POINTLINK FAR* ppointlink;

    SAFEARRAYBOUND rgsabound[1];

    rgsabound[0].lLbound = 0;

    rgsabound[0].cElements = m_cPoints;

    psa = SafeArrayCreate(VT_VARIANT, 1, rgsabound);

    if(psa == NULL){

      hresult = ResultFromScode(E_OUTOFMEMORY);

      goto LError0;

    }

    ppointlink = m_ppointlink;

    for(i = 0; i < m_cPoints; ++i){

      long ix[1];

      if(ppointlink == NULL){

        // this indicates an internal consistency error.

// (this test should probably be an assertion)

        hresult = ResultFromScode(E_FAIL);

        goto LError1;

      }

      V_VT(&var) = VT_DISPATCH;

      hresult = ppointlink->ppoint->QueryInterface(

IID_IDispatch, (void FAR* FAR*)&V_DISPATCH(&var));

      if(hresult != NOERROR)

        goto LError1;

      ix[0] = i;

      SafeArrayPutElement(psa, ix, &var);

      ppointlink = ppointlink->next;

    }

    hresult = CEnumPoint::Create(psa, &penum);

    if(hresult != NOERROR)

      goto LError1;

    // ownership of the array has passed to the enumerator

    psa = NULL;

    hresult = penum->QueryInterface(IID_IUnknown, (void FAR* FAR*)&punk);

    if(hresult != NOERROR)

      goto LError2;

    penum->Release();

    return punk;

LError2:;

    penum->Release();

LError1:;

    // destroy the array if we were not successful creating the enumerator.

    if(psa != NULL)

      SafeArrayDestroy(psa);

LError0:;

    return NULL;

}

short METHODCALLTYPE EXPORT

CPoly::GetXOrigin()

{

    return m_xorg;

}

void METHODCALLTYPE EXPORT

CPoly::SetXOrigin(short x)

{

    m_xorg = x;

}

short METHODCALLTYPE EXPORT

CPoly::GetYOrigin()

{

    return m_yorg;

}

void METHODCALLTYPE EXPORT

CPoly::SetYOrigin(short y)

{

    m_yorg = y;

}

short METHODCALLTYPE EXPORT

CPoly::GetWidth()

{

    return m_width;

}

void METHODCALLTYPE EXPORT

CPoly::SetWidth(short width)

{

    m_width = width;

}

short METHODCALLTYPE EXPORT

CPoly::get_red()

{

    return m_red;

}

void METHODCALLTYPE EXPORT

CPoly::set_red(short red)

{

    m_red = red;

}

short METHODCALLTYPE EXPORT

CPoly::get_green()

{

    return m_green;

}

void METHODCALLTYPE EXPORT

CPoly::set_green(short green)

{

    m_green = green;

}

short METHODCALLTYPE EXPORT

CPoly::get_blue()

{

    return m_blue;

}

void METHODCALLTYPE EXPORT

CPoly::set_blue(short blue)

{

    m_blue = blue;

}

/***

*void CPoly::Dump(void)

*Purpose:

*  Output a debug dump of this instance.

*

*Entry:

*  None

*

*Exit:

*  None

*

***********************************************************************/

void METHODCALLTYPE EXPORT

CPoly::Dump()

{

#ifdef _MAC

    // REVIEW: implement for the mac

#else

    TCHAR buffer[80];

    POINTLINK FAR* ppointlink;

    wsprintf(buffer, TSTR("CPoly(0x%x) =\n"), (int)this);

    OutputDebugString(buffer);

    wsprintf(buffer,

      TSTR("    xorg = %d, yorg = %d, width = %d, rgb = {%d,%d,%d}\n    points = "),

      m_xorg, m_yorg, m_width,

      get_red(),

      get_green(),

      get_blue());

    OutputDebugString(buffer);

    for(ppointlink = m_ppointlink;

ppointlink != (POINTLINK FAR*)NULL;

ppointlink = ppointlink->next)

    {

      wsprintf(buffer, TSTR("{%d,%d}"),

        ppointlink->ppoint->GetX(),

        ppointlink->ppoint->GetY());

      OutputDebugString(buffer);

      wsprintf(buffer, TSTR(" "));

      OutputDebugString(buffer);

    }

    wsprintf(buffer, TSTR("\n"));

    OutputDebugString(buffer);

#endif

}

/***

*void CPoly::PolyDraw(void)

*Purpose:

*  Draw all polygons.

*

*Entry:

*  None

*

*Exit:

*  None

*

***********************************************************************/

void

CPoly::PolyDraw()

{

    POLYLINK FAR* polylink;

    for(polylink = g_ppolylink;

polylink != (POLYLINK FAR*)NULL;

polylink = polylink->next)

    {

      polylink->ppoly->Draw();

    }

}

/***

*void PolyTerm(void)

*Purpose:

*  Release all polygons.

*

*Entry:

*  None

*

*Exit:

*  None

*

***********************************************************************/

void

CPoly::PolyTerm()

{

    POLYLINK FAR* ppolylink;

    POLYLINK FAR* ppolylinkNext;

    for(ppolylink = g_ppolylink;

ppolylink != (POLYLINK FAR*)NULL;

ppolylink = ppolylinkNext)

    {

      ppolylinkNext = ppolylink->next;

      ppolylink->ppoly->Release();

      delete ppolylink;

    }

    g_ppolylink = NULL;

}

/***

*void PolyDump(void)

*Purpose:

*  Invoke the debug Dump() method on all polygons were currently

*  holding on to.

*

*Entry:

*  None

*

*Exit:

*  None

*

***********************************************************************/

void

CPoly::PolyDump()

{

    POLYLINK FAR* ppolylink;

    if(g_ppolylink == (POLYLINK FAR*)NULL){

#ifndef _MAC

      OutputDebugString(TSTR("\t(none)\n"));

#endif

      return;

    }

    for(ppolylink = g_ppolylink;

ppolylink != (POLYLINK FAR*)NULL;

ppolylink = ppolylink->next)

    {

      ppolylink->ppoly->Dump();

    }

}

//---------------------------------------------------------------------

//             Implementation of the CPoly Class Factory

//---------------------------------------------------------------------

CPolyCF::CPolyCF()

{

    m_refs = 0;

}

IClassFactory FAR*

CPolyCF::Create()

{

    CPolyCF FAR* pCF;

    if((pCF = new FAR CPolyCF()) == NULL)

      return NULL;

    pCF->AddRef();

    return pCF;

}

STDMETHODIMP

CPolyCF::QueryInterface(REFIID riid, void FAR* FAR* ppv)

{

    if(IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IClassFactory)){

      *ppv = this;

      ++m_refs;

      return NOERROR;

    }

    *ppv = NULL;

    return ResultFromScode(E_NOINTERFACE);

}

STDMETHODIMP_(unsigned long)

CPolyCF::AddRef(void)

{

    return ++m_refs;

}

STDMETHODIMP_(unsigned long)

CPolyCF::Release(void)

{

    if(--m_refs == 0){

      delete this;

      return 0;

    }

    return m_refs;

}

STDMETHODIMP

CPolyCF::CreateInstance(

    IUnknown FAR* punkOuter,

    REFIID iid,

    void FAR* FAR* ppv)

{

    HRESULT hresult;

    CPoly FAR *ppoly;

    UNUSED(punkOuter);

    if((ppoly = CPoly::Create()) == NULL){

      *ppv = NULL;

      return ResultFromScode(E_OUTOFMEMORY);

    }

    hresult = ppoly->QueryInterface(iid, ppv);

    ppoly->Release();

    return hresult;

}

STDMETHODIMP

#ifdef _MAC

CPolyCF::LockServer(unsigned long fLock)

#else

CPolyCF::LockServer(BOOL fLock)

#endif

{

    UNUSED(fLock);

    return NOERROR;

}


 HOSTENV.H  (SPOLY2 Sample)

/***

*hostenv.h

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*

*Purpose:

*  Generic host specific includes.

*

*Implementation Notes:

*

*****************************************************************************/

#if defined(_MAC)

#if defined(_PPCMAC)

#pragma data_seg("_FAR_DATA")

#pragma data_seg( )

#define MAXLONG 0x7fffffff

#define EventHandlerProcPtr AEEventHandlerUPP

#else //_PPCMAC

#define  GetMenuItemText(mApple,menuItem,daName)  GetItem(mApple,menuItem,daName)

#endif //_PPCMAC

#endif //_MAC

#if defined(_MAC)

#if defined(_MSC_VER)

# include <values.h>

# include <types.h>

# include <string.h>

# include <quickdra.h>

# include <fonts.h>

# include <events.h>

# include <resource.h>

# include <menus.h>

# include <textedit.h>

# include <dialogs.h>

# include <desk.h>

# include <toolutil.h>

# include <memory.h>

# include <files.h>

# include <osutils.h>

# include <osevents.h>

# include <diskinit.h>

# include <packages.h>

# include <traps.h>

# include <AppleEve.h>

#else //_MSC_VER

# include <values.h>

# include <types.h>

# include <strings.h>

# include <quickdraw.h>

# include <fonts.h>

# include <events.h>

# include <resources.h>

# include <windows.h>

# include <menus.h>

# include <textedit.h>

# include <dialogs.h>

# include <desk.h>

# include <toolutils.h>

# include <memory.h>

# include <files.h>

# include <osutils.h>

# include <osevents.h>

# include <diskinit.h>

# include <packages.h>

# include <traps.h>

# include <AppleEvents.h>

#endif //_MSC_VER

# include <ole2.h>

# include <olenls.h>

# include <dispatch.h>

# define TCHAR	char

# define TSTR(str)	str

# define STRING(str)	        (str)

# define WIDESTRING(str)        (str)

#elif defined(WIN32)

# include <windows.h>

# include <ole2.h>

# include <oleauto.h>

# if defined(UNICODE)

    #define TCHAR	WCHAR

    #define TSTR(str)	L##str

    #define STRING(str)	        (str)

    #define WIDESTRING(str)	(str)

# else

    #define TCHAR	char

    #define TSTR(str)	str

    #define STRING(str)	        AnsiString(str)

    #define WIDESTRING(str)	WideString(str)

    extern "C" char FAR* AnsiString(OLECHAR FAR* strIn);

    extern "C" OLECHAR FAR* WideString(char FAR* strIn);

# endif

#else /* WIN16 */

# include <windows.h>

# include <ole2.h>

# include <olenls.h>

# include <dispatch.h>

# define TCHAR	char

# define TSTR(str)	str

# define STRING(str)	        (str)

# define WIDESTRING(str)        (str)

#endif


 MISC.CPP  (SPOLY2 Sample)

/***

*misc.cpp

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*

*Purpose:

*

*Implementation Notes:

*

*****************************************************************************/

#include "spoly.h"

#include "cpoint.h"

#include "cpoly.h"

#include <stdio.h>

#ifdef _MAC

# include <string.h>

# include <ctype.h>

#endif

unsigned long g_dwPolyCF = 0;

unsigned long g_dwPointCF = 0;

IClassFactory FAR* g_ppolyCF = NULL;

IClassFactory FAR* g_ppointCF = NULL;

#ifdef _MAC

struct regentry{

    char *szKey;

    char *szValue;

} g_rgregentry[] = {

      { "CLSID\\{00020464-0000-0000-C000-000000000046}",

"OLE Automation SPoly2 1.0 Application" }

    , { "CLSID\\{00020464-0000-0000-C000-000000000046}\\LocalServer",

        "SPL2" }

    , { "CLSID\\{00020464-0000-0000-C000-000000000046}\\ProgID",

"SPoly2.Application" }

    , { "CLSID\\{00020464-0000-0000-C000-000000000046}\\InprocHandler",

"OLE2:Def$DefFSet" }

    , { "SPL2", "{00020464-0000-0000-C000-000000000046}" }

    , { "SPoly2.Application\\CLSID",

"{00020464-0000-0000-C000-000000000046}" }

};

HRESULT

EnsureRegistration()

{

    HKEY hkey;

    if(RegOpenKey(HKEY_CLASSES_ROOT, "SPL2", &hkey) == NOERROR){

      RegCloseKey(hkey);

      return NOERROR;

    }

    for(int i = 0; i < DIM(g_rgregentry); ++i){

      if(RegSetValue(HKEY_CLASSES_ROOT, g_rgregentry[i].szKey, REG_SZ, g_rgregentry[i].szValue, 0) != ERROR_SUCCESS)

        return ResultFromScode(E_FAIL);

    }

    return NOERROR;

}

#endif

/***

*HRESULT InitOle(void)

*Purpose:

*  Initialize Ole, and register our class factories.

*

*Entry:

*  None

*

*Exit:

*  None

*

***********************************************************************/

STDAPI

InitOle()

{

    HRESULT hresult;

    if((hresult = OleInitialize(NULL)) != NOERROR)

      goto LError0;

#ifdef _MAC

    if((hresult = EnsureRegistration()) != NOERROR)

      goto LError0;

#endif

    // Register the CPoint Class Factory

    //

    if((g_ppointCF = CPointCF::Create()) == NULL){

      hresult = ResultFromScode(E_OUTOFMEMORY);

      goto LError1;

    }

    hresult = CoRegisterClassObject(

      CLSID_CPoint2,

      g_ppointCF,

      CLSCTX_LOCAL_SERVER,

      REGCLS_MULTIPLEUSE,

      &g_dwPointCF);

    if(hresult != NOERROR)

      goto LError1;

    // Register the CPoly Class Factory.

    //

    if((g_ppolyCF = CPolyCF::Create()) == NULL){

      hresult = ResultFromScode(E_OUTOFMEMORY);

      goto LError1;

    }

    hresult = CoRegisterClassObject(

      CLSID_CPoly2,

      g_ppolyCF,

      CLSCTX_LOCAL_SERVER,

      REGCLS_MULTIPLEUSE,

      &g_dwPolyCF);

    if(hresult != NOERROR)

      goto LError1;

    g_ppolyCF->Release();

    g_ppointCF->Release();

    return NOERROR;

LError1:;

    if(g_ppolyCF != NULL)

      g_ppolyCF->Release();

    if(g_ppointCF != NULL)

      g_ppointCF->Release();

    UninitOle();

LError0:;

    return hresult;

}

STDAPI

UninitOle()

{

    // Tell Ole to release our class factories.

    //

    if(g_dwPointCF != 0L)

      CoRevokeClassObject(g_dwPointCF);

    if(g_dwPolyCF != 0L)

      CoRevokeClassObject(g_dwPolyCF);

    OleUninitialize();

    return NOERROR;

}

// disable unicode expansion for assertions

#undef UNICODE

void

Assert(int fCond, char FAR* file, int line, char FAR* message)

{

    char * fmt;

    char buf[128];

    if(fCond)

      return;

    fmt = (message == NULL)

      ? "Assertion failed: %s(%d)"

      : "Assertion failed: %s(%d) '%s'";

    sprintf(buf, fmt, file, line, message);

#ifdef _MAC

    DebugStr(c2pstr(buf));

#else

#ifdef WIN32

    OutputDebugStringA(buf);

#else //WIN32

    OutputDebugString(buf);

#endif //WIN32

    DebugBreak();

#endif

}

#ifdef _MAC

#if defined(_MSC_VER)

int pascal

#else

pascal int

#endif

stricmp(char *first, char *last)

{

    unsigned short f, l;

    do{

f = tolower(*first++);

l = tolower(*last++);

    }while(f && f == l);

    return f - l;

}

#endif


 RESOURCE.H  (SPOLY2 Sample)

/***

*resource.h

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*

*Purpose:

*

*Implementation Notes:

*

*****************************************************************************/

#ifdef _MAC

#define kMinSize	500	/* minimum size (in K) */

#define kPrefSize	500	/* preferred size (in K) */

#define	rMenuBar	128	/* menu bar */

#define	rAboutAlert	128	/* about alert */

#define	rUserAlert	129	/* error alert */

#define	rWindow	128	/* application's window */

#define	mApple	128	/* Apple menu */

#define	iAbout	1

#define	mFile	129	/* File menu */

#define	iNew	1

#define	iClose	4

#define	iQuit	12

#define	mEdit	130	/* Edit menu */

#define	iUndo	1

#define	iCut	3

#define	iCopy	4

#define	iPaste	5

#define	iClear	6

#define mSpoly	131

#define iTest	1

#define kMinHeap	21 * 1024

#define kMinSpace	8 * 1024

#else /* WIN16 || WIN32 */

# define IDM_CLEAR	1

# define IDM_DUMP	2

# define IDM_FIRSTCHILD	100

#endif


 SPOLY.H  (SPOLY2 Sample)

/***

*spoly.h - Application-wide definitions

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*

*Purpose:

*

*Implementation Notes:

*

*****************************************************************************/

#include "hostenv.h"

#include "resource.h"

#include "clsid.h"

#if defined(_MAC)

# define STRSTR strstr

#elif defined(WIN32)

# include "statbar.h"

# define STRSTR strstr

#else /* WIN16 */

# include "statbar.h"

# define STRSTR _fstrstr

#endif

#ifdef _MAC

# define UNUSED(X) ((void)(void*)&(X))

#else

# define UNUSED(X) (X)

#endif

#define DIM(X) (sizeof(X) / sizeof(X[0]))

extern "C" void Assert(int, char FAR*, int, char FAR*);

#define ASSERT(X) Assert(X, __FILE__, __LINE__, NULL)

#define ASSERTSZ(X, MSG) Assert(X, __FILE__, __LINE__, MSG)

#ifndef EXPORT

# if defined(WIN32)

#  define EXPORT

# elif defined(_MAC)

#  define EXPORT

# else

#  define EXPORT __export

# endif

#endif

#ifndef NEAR

# if defined(WIN32)

#  define NEAR

# elif defined(_MAC)

#  define NEAR

# else

#  define NEAR __near

# endif

#endif

#if defined(WIN32)

# define CC_CALL        CC_STDCALL

# define METHODCALLTYPE __stdcall

#elif defined(_MAC)

# define CC_CALL        CC_CDECL

# define METHODCALLTYPE

#else

# define CC_CALL        CC_PASCAL

# define METHODCALLTYPE __pascal

#endif

STDAPI InitOle();

STDAPI UninitOle();


 SPOLY2.DEF  (SPOLY2 Sample)

NAME         SPOLY2

DESCRIPTION  'IDispatch Polygon Test Server #2'

EXETYPE      WINDOWS

STUB         'WINSTUB.EXE'

CODE         PRELOAD MOVEABLE DISCARDABLE

DATA         PRELOAD MULTIPLE

HEAPSIZE     4096

STACKSIZE    8192


 SPOLY2.RC  (SPOLY2 Sample)

#define NOKERNEL

#define NOGDI

#define NOSOUND

#define NOCOMM

#define NODRIVERS

#include "windows.h"

#include "spoly.h"

SPOLY ICON spoly2.ico

SPolyMenu MENU

BEGIN

    MENUITEM	"&Clear"	IDM_CLEAR

    MENUITEM	"&Dump"	IDM_DUMP

END


 SPOLY2.REG  (SPOLY2 Sample)

REGEDIT

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; registration info SPoly2.Application (defaults to SPoly2.Application.1)

HKEY_CLASSES_ROOT\SPoly2.Application = OLE Automation SPoly2 Application

HKEY_CLASSES_ROOT\spoly2.Application\Clsid = {00020464-0000-0000-C000-000000000046}

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; registration info SPoly2 1.0

; (Application Object)

HKEY_CLASSES_ROOT\SPoly2.Application.1 = OLE Automation SPoly2 1.0 Application

HKEY_CLASSES_ROOT\SPoly2.Application.1\Clsid = {00020464-0000-0000-C000-000000000046}

HKEY_CLASSES_ROOT\CLSID\{00020464-0000-0000-C000-000000000046} = OLE Automation Spoly2 1.0 Application

HKEY_CLASSES_ROOT\CLSID\{00020464-0000-0000-C000-000000000046}\ProgID = SPoly2.Application

HKEY_CLASSES_ROOT\CLSID\{00020464-0000-0000-C000-000000000046}\VersionIndependentProgID = SPoly2.Application

HKEY_CLASSES_ROOT\CLSID\{00020464-0000-0000-C000-000000000046}\LocalServer32 = spoly2.exe /Automation

HKEY_CLASSES_ROOT\CLSID\{00020465-0000-0000-C000-000000000046} = SPoly2.SPoint2

HKEY_CLASSES_ROOT\CLSID\{00020465-0000-0000-C000-000000000046}\ProgID = SPoly2.Application.1

HKEY_CLASSES_ROOT\CLSID\{00020465-0000-0000-C000-000000000046}\VersionIndependentProgID = SPoly.Application

HKEY_CLASSES_ROOT\CLSID\{00020465-0000-0000-C000-000000000046}\LocalServer32 = spoly2.exe /Automation


 STATBAR.H  (SPOLY2 Sample)

/***

*statbar.h

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*  Information Contained Herein Is Proprietary and Confidential.

*

*Purpose:

*

*Implementation Notes:

*  This file requires windows.h and ole2.h

*

*****************************************************************************/

class CStatBar : public IUnknown {

public:

    static CStatBar FAR* Create(HANDLE hinst, HWND hwndFrame);

    // IUnknown methods

    //

    STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppv);

    STDMETHOD_(unsigned long, AddRef)(void);

    STDMETHOD_(unsigned long, Release)(void);

    // Introduced methods

    //

    void Show(void);

    inline void Move(void);

    inline void Update(void);

    inline int GetX(void);

    inline void SetX(int x);

    inline int GetY(void);

    inline void SetY(int y);

    inline int GetHeight(void);

    inline void SetHeight(int height);

    inline int GetWidth(void);

    inline void SetWidth(int width);

    //inline HFONT GetFont(void);

    void SetFont(HFONT hfont);

    //char FAR* GetText(void);

    inline void SetText(OLECHAR FAR* sz);

    void WMPaint(void);

    BOOL Register(HANDLE);

private:

    CStatBar();

    ~CStatBar();

    unsigned long	m_refs;

    HWND	m_hwnd;	// the status bar window handle

    int	m_x;	// x coordinate of upper left corner

    int	m_y;	// y coordinate of upper left corner

    int	m_height;

    int	m_width;

    HFONT	m_hfont;

    int	m_dyFont;	// font height

    int	m_dxFont;	// font width

    BSTR	m_bstrMsg;	// the status bar text

    static TCHAR FAR* m_szWndClass;

};

inline void

CStatBar::Move()

{

    MoveWindow(m_hwnd, m_x, m_y, m_width, m_height, TRUE);

}

inline void

CStatBar::Update()

{

    InvalidateRect(m_hwnd, NULL, TRUE);

    UpdateWindow(m_hwnd);

}

inline int

CStatBar::GetX()

{

    return m_x;

}

inline void

CStatBar::SetX(int x)

{

    m_x = x;

}

inline int

CStatBar::GetY(void)

{

    return m_y;

}

inline void

CStatBar::SetY(int y)

{

    m_y = y;

}

inline int

CStatBar::GetHeight(void)

{

    return m_height;

}

inline void

CStatBar::SetHeight(int height)

{

    m_height = height;

}

inline int

CStatBar::GetWidth(void)

{

    return m_width;

}

inline void

CStatBar::SetWidth(int width)

{

    m_width = width;

}

inline void

CStatBar::SetText(OLECHAR FAR* sz)

{

    SysFreeString(m_bstrMsg);

    m_bstrMsg = SysAllocString(sz);

}

extern "C" void

SBprintf(CStatBar FAR* psb, TCHAR FAR* szFmt, ...);


 STATBAR.CPP  (SPOLY2 Sample)

/***

*statbar.cpp

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*  Information Contained Herein Is Proprietary and Confidential.

*

*Purpose:

*

*Implementation Notes:

*

*****************************************************************************/

#include <stdarg.h>

#include "hostenv.h"

#include "statbar.h"

extern "C" long FAR PASCAL StatBarWndProc(HWND, unsigned int, WPARAM, LPARAM);

TCHAR FAR* CStatBar::m_szWndClass = TSTR("StatBarWndClass");

CStatBar::CStatBar()

{

    m_refs = 0;

    m_x = 0;

    m_y = 0;

    m_width = 0;

    m_height = 0;

    m_bstrMsg = NULL;

    m_hfont = (HANDLE)0;

}

CStatBar::~CStatBar()

{

    SysFreeString(m_bstrMsg);

}

/***

*PUBLIC CStatBar FAR* CStatBar::Create(HANDLE, HWND)

*

*Purpose:

*

*Entry:

*

*Exit:

*

***********************************************************************/

CStatBar FAR*

CStatBar::Create(HANDLE hinst, HWND hwndFrame)

{

    CStatBar FAR* psb;

    psb = new FAR CStatBar();

    if(psb == NULL)

      return NULL;

    psb->AddRef();

    if(!psb->Register(hinst))

      goto LFail;

    psb->m_hwnd = CreateWindow(

      CStatBar::m_szWndClass,

      NULL,

      WS_CHILD | WS_CLIPSIBLINGS,

      0, 0, 0, 0,

      hwndFrame,

      0,

      hinst,

      NULL);

    if(!psb->m_hwnd)

      goto LFail;

    // Stash the newly created CStatBar* in the extra bytes of the

    // associated window so we can get at the instance in the message

    // proc.

    //

    // Note: we do not AddRef for this reference. We make sure that the

    // window is destroyed when the refcnt goes to 0.

    //

    SetWindowLong(psb->m_hwnd, 0, (long)psb);

    return psb;

LFail:;

    delete psb;

    return NULL;

}

//---------------------------------------------------------------------

//                     IUnknown Methods

//---------------------------------------------------------------------

STDMETHODIMP

CStatBar::QueryInterface(REFIID riid, void FAR* FAR* ppv)

{

    if(IsEqualIID(riid,IID_IUnknown)){

      *ppv = this;

      AddRef();

      return NOERROR;

    }

    *ppv = (void FAR*)NULL;

    return ResultFromScode(E_NOINTERFACE);

}

STDMETHODIMP_(unsigned long)

CStatBar::AddRef(void)

{

    return ++m_refs;

}

STDMETHODIMP_(unsigned long)

CStatBar::Release(void)

{

    if(--m_refs == 0){

      // destroy the status bar window.

      //

      SendMessage(m_hwnd, WM_DESTROY, 0, 0L);

      delete this;

      return 0;

    }

    return m_refs;

}

//---------------------------------------------------------------------

//                     Introduced Methods

//---------------------------------------------------------------------

/***

*PRIVATE BOOL CStatBar::Register(HANDLE)

*

*Purpose:

*  Register the status bar window class.

*

*Entry:

*  None

*

*Exit:

*  return value = BOOL, TRUE if successful, FALSE if not.

*

***********************************************************************/

BOOL

CStatBar::Register(HANDLE hinst)

{

    WNDCLASS  wc;

    // register the class, unless already registered.

    if(GetClassInfo(hinst, m_szWndClass, &wc) == 0){

      wc.style         = 0;

      wc.lpfnWndProc   = StatBarWndProc;

      wc.cbClsExtra    = 0;

      wc.cbWndExtra    = sizeof(CStatBar FAR*);

      wc.hInstance     = hinst;

      wc.hIcon         = 0;

      wc.hCursor       = LoadCursor(NULL, IDC_ARROW);

      wc.hbrBackground = GetStockObject(LTGRAY_BRUSH);

      wc.lpszMenuName  = 0;

      wc.lpszClassName = CStatBar::m_szWndClass;

      if(!RegisterClass(&wc))

        return FALSE;

    }

    return TRUE;

}

/***

*PUBLIC void CStatBar::Show(void)

*

*Purpose:

*  Show the status bar window associated with this CStatBar instance.

*

*Entry:

*  None

*

*Exit:

*  None

*

***********************************************************************/

void

CStatBar::Show()

{

    ShowWindow(m_hwnd, SW_SHOW);

}

void

CStatBar::SetFont(HFONT hfont)

{

    HDC hdc;

    TEXTMETRIC tm;

    HFONT hfontOld;

    // compute the character sizes given this new font.

    //

    hdc = GetDC(m_hwnd);

    hfontOld = SelectObject(hdc, hfont);

    GetTextMetrics(hdc, &tm);

    m_dxFont = tm.tmAveCharWidth;

    m_dyFont = tm.tmHeight + tm.tmExternalLeading;

    SelectObject(hdc, hfontOld);

    ReleaseDC(m_hwnd, hdc);

    m_hfont = hfont;

}

/***

*PRIVATE CStatBar::WMPaint(void)

*

*Purpose:

*  This method is responsible for drawing the status bar, and is called

*  in response to a WM_PAINT message.

*

*Entry:

*  None

*

*Exit:

*  None

*

***********************************************************************/

void

CStatBar::WMPaint()

{

    HDC hdc;

    RECT rcMsg;

    HRGN hrgn;

    HFONT hfontOld;

    PAINTSTRUCT ps;

    HPEN hpenBlack, hpenWhite, hpenGray, hpenOld;

    hdc = BeginPaint(m_hwnd, &ps);

    // compute the message box rect

    //

    rcMsg.top	= 3;

    rcMsg.bottom= m_height - 3;

    rcMsg.left	= m_dxFont;

    rcMsg.right	= m_width - m_dxFont;

    // prepare the pens

    //

    hpenWhite	= GetStockObject(WHITE_PEN);

    hpenBlack	= GetStockObject(BLACK_PEN);

    hpenGray	= CreatePen(PS_SOLID, 1, GetSysColor(COLOR_BTNSHADOW));

    // draw a top gray line

    //

    hpenOld = SelectObject(hdc, hpenGray);

#if   defined(WIN16)

    MoveTo(hdc, ps.rcPaint.left, 0);

#elif defined(WIN32)

    MoveToEx(hdc, ps.rcPaint.left, 0, NULL);

#endif

    LineTo(hdc, ps.rcPaint.right, 0);

    // draw a white line just under

    //

    SelectObject(hdc, hpenWhite);

#if   defined(WIN16)

    MoveTo(hdc, ps.rcPaint.left, 1);

#elif defined(WIN32)

    MoveToEx(hdc, ps.rcPaint.left, 1, NULL);

#endif

    LineTo(hdc, ps.rcPaint.right, 1);

    // do not overwrite the background color

    //

    SetBkMode(hdc, TRANSPARENT);

    // message area

    //

    SelectObject(hdc, hpenBlack);

#if   defined(WIN16)

    MoveTo(hdc, rcMsg.left,  rcMsg.bottom);

#elif defined(WIN32)

    MoveToEx(hdc, rcMsg.left,  rcMsg.bottom, NULL);

#endif

    LineTo(hdc, rcMsg.left,  rcMsg.top);

    LineTo(hdc, rcMsg.right, rcMsg.top);

    SelectObject(hdc, hpenWhite);

    LineTo(hdc, rcMsg.right, rcMsg.bottom);

    LineTo(hdc, rcMsg.left,  rcMsg.bottom);

    // select the black pen for writing

    //

    SelectObject(hdc, hpenBlack);

    // select the status bar font to write in

    //

    hfontOld = SelectObject(hdc, m_hfont);

    // set the clipping region

    //

    hrgn = CreateRectRgn(

      rcMsg.left, rcMsg.top, rcMsg.right, rcMsg.bottom);

    SelectClipRgn(hdc, hrgn);

    // draw the status message

    //

    TextOut(

      hdc,

      rcMsg.left + (m_dxFont / 2),

      rcMsg.top + ((rcMsg.bottom - rcMsg.top - m_dyFont) / 2),

      STRING(m_bstrMsg), (SysStringLen(m_bstrMsg)));

    // cleanup

    //

    SelectObject(hdc, hpenOld);

    SelectObject(hdc, hfontOld);

    DeleteObject(hrgn);

    DeleteObject(hpenGray);

    EndPaint(m_hwnd, &ps);

}

extern "C" long FAR PASCAL

StatBarWndProc(

    HWND hwnd,

    unsigned int message,

    WPARAM wParam,

    LPARAM lParam)

{

    CStatBar FAR* psb;

    switch(message){

    case WM_SIZE:

      return 0;

    case WM_PAINT:

      psb = (CStatBar FAR*)GetWindowLong(hwnd, 0);

      psb->WMPaint();

      return 0;

    }

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

}

//---------------------------------------------------------------------

//                    Status Bar Utilities

//---------------------------------------------------------------------

extern "C" void

SBprintf(CStatBar FAR* psb, TCHAR FAR* szFmt, ...)

{

    va_list args;

static TCHAR buf[256];

    va_start(args, szFmt);

    wvsprintf(buf, szFmt, args);

    psb->SetText(WIDESTRING(buf));

    psb->Update();

}


 TDATA.CPP  (SPOLY2 Sample)

/***

*tdata.cpp

*

*  Copyright (C) 1991-1994, Microsoft Corporation.  All Rights Reserved.

*  Information Contained Herein Is Proprietary and Confidential.

*

*Purpose:

*  CPoly and CPoint type data descriptions.

*

*  These data descriptions are used to construct TypeInfos for these

*  objects at runtime.

*

*****************************************************************************/

#include "spoly.h"

#include "cpoint.h"

#include "cpoly.h"

//---------------------------------------------------------------------

//                      CPoint type data definitions

//---------------------------------------------------------------------

static PARAMDATA NEAR rgpdataCPointSetX[] =

{

    { OLESTR("X"), VT_I2 }

};

static PARAMDATA NEAR rgpdataCPointSetY[] =

{

    { OLESTR("Y"), VT_I2 }

};

static METHODDATA NEAR rgmdataCPoint[] =

{

    // CPoint::GetX()

    {

OLESTR("GetX"),

NULL,

IDMEMBER_CPOINT_GETX,

IMETH_CPOINT_GETX,

CC_CALL,

0,

DISPATCH_METHOD,

VT_I2

    },

    // CPoint::SetX()

    {

OLESTR("SetX"),

rgpdataCPointSetX,

IDMEMBER_CPOINT_SETX,

IMETH_CPOINT_SETX,

CC_CALL,

DIM(rgpdataCPointSetX),

DISPATCH_METHOD,

VT_EMPTY

    },

    // CPoint::GetY()

    {

OLESTR("GetY"),

NULL,

IDMEMBER_CPOINT_GETY,

IMETH_CPOINT_GETY,

CC_CALL,

0,

DISPATCH_METHOD,

VT_I2

    },

    // CPoint::SetY()

    {

OLESTR("SetY"),

rgpdataCPointSetY,

IDMEMBER_CPOINT_SETY,

IMETH_CPOINT_SETY,

CC_CALL,

DIM(rgpdataCPointSetY),

DISPATCH_METHOD,

VT_EMPTY

    }

};

INTERFACEDATA NEAR g_idataCPoint =

{

    rgmdataCPoint, DIM(rgmdataCPoint)

};

//---------------------------------------------------------------------

//                   CPoly type data definitions

//---------------------------------------------------------------------

static PARAMDATA NEAR rgpdataCPolyAddPoint[] =

{

    { OLESTR("x"),	VT_I2 },

    { OLESTR("y"),	VT_I2 }

};

static PARAMDATA NEAR rgpdataCPolySetXOrigin[] =

{

    { OLESTR("x"),	VT_I2 }

};

static PARAMDATA NEAR rgpdataCPolySetYOrigin[] =

{

    { OLESTR("y"),	VT_I2 }

};

static PARAMDATA NEAR rgpdataCPolySetWidth[] =

{

    { OLESTR("width"),	VT_I2 }

};

static PARAMDATA NEAR rgpdataCPolySetRed[] =

{

    { OLESTR("red"),	VT_I2 }

};

static PARAMDATA NEAR rgpdataCPolySetGreen[] =

{

    { OLESTR("green"),	VT_I2 }

};

static PARAMDATA NEAR rgpdataCPolySetBlue[] =

{

    { OLESTR("blue"),	VT_I2 }

};

static METHODDATA NEAR rgmdataCPoly[] =

{

    // void CPoly::Draw(void)

    {

OLESTR("Draw"),

NULL,

IDMEMBER_CPOLY_DRAW,

IMETH_CPOLY_DRAW,

CC_CALL,

0,

DISPATCH_METHOD,

VT_EMPTY

    },

    // void CPoly::Reset(void)

    {

OLESTR("Reset"),

NULL,

IDMEMBER_CPOLY_RESET,

IMETH_CPOLY_RESET,

CC_CALL,

0,

DISPATCH_METHOD,

VT_EMPTY

    },

    // HRESULT CPoly::AddPoint(short x, short y)

    {

OLESTR("AddPoint"),

rgpdataCPolyAddPoint,

IDMEMBER_CPOLY_ADDPOINT,

IMETH_CPOLY_ADDPOINT,

CC_CALL,

DIM(rgpdataCPolyAddPoint),

DISPATCH_METHOD,

VT_ERROR

    },

    // IUnknown FAR* CPoly::EnumPoints(void)

    {

OLESTR("EnumPoints"),

NULL,

IDMEMBER_CPOLY_ENUMPOINTS,

IMETH_CPOLY_ENUMPOINTS,

CC_CALL,

0,

DISPATCH_METHOD,

VT_UNKNOWN

    },

    // short CPoly::GetXOrigin(void)

    {

OLESTR("GetXOrigin"),

NULL,

IDMEMBER_CPOLY_GETXORIGIN,

IMETH_CPOLY_GETXORIGIN,

CC_CALL,

0,

DISPATCH_METHOD,

VT_I2

    },

    // void CPoly::SetXOrigin(short x)

    {

OLESTR("SetXOrigin"),

rgpdataCPolySetXOrigin,

IDMEMBER_CPOLY_SETXORIGIN,

IMETH_CPOLY_SETXORIGIN,

CC_CALL,

DIM(rgpdataCPolySetXOrigin),

DISPATCH_METHOD,

VT_EMPTY

    },

    // short CPoly::GetYOrigin(void)

    {

OLESTR("GetYOrigin"),

NULL,

IDMEMBER_CPOLY_GETYORIGIN,

IMETH_CPOLY_GETYORIGIN,

CC_CALL,

0,

DISPATCH_METHOD,

VT_I2

    },

    // void CPoly::SetYOrigin(short y)

    {

OLESTR("SetYOrigin"),

rgpdataCPolySetYOrigin,

IDMEMBER_CPOLY_SETYORIGIN,

IMETH_CPOLY_SETYORIGIN,

CC_CALL,

DIM(rgpdataCPolySetYOrigin),

DISPATCH_METHOD,

VT_EMPTY

    },

    // short CPoly::GetWidth(void)

    {

OLESTR("GetWidth"),

NULL,

IDMEMBER_CPOLY_GETWIDTH,

IMETH_CPOLY_GETWIDTH,

CC_CALL,

0,

DISPATCH_METHOD,

VT_I2

    },

    // void CPoly::SetWidth(short width)

    {

OLESTR("SetWidth"),

rgpdataCPolySetWidth,

IDMEMBER_CPOLY_SETWIDTH,

IMETH_CPOLY_SETWIDTH,

CC_CALL,

DIM(rgpdataCPolySetWidth),

DISPATCH_METHOD,

VT_EMPTY

    },

    // short CPoly::get_red(void)

    {

OLESTR("get_red"),

NULL,

IDMEMBER_CPOLY_GETRED,

IMETH_CPOLY_GETRED,

CC_CALL,

0,

DISPATCH_METHOD,

VT_I2

    },

    // void CPoly::set_red(short red)

    {

OLESTR("set_red"),

rgpdataCPolySetRed,

IDMEMBER_CPOLY_SETRED,

IMETH_CPOLY_SETRED,

CC_CALL,

DIM(rgpdataCPolySetRed),

DISPATCH_METHOD,

VT_EMPTY

    },

    // short CPoly::get_green(void)

    {

OLESTR("get_green"),

NULL,

IDMEMBER_CPOLY_GETGREEN,

IMETH_CPOLY_GETGREEN,

CC_CALL,

0,

DISPATCH_METHOD,

VT_I2

    },

    // void CPoly::set_green(short green)

    {

OLESTR("set_green"),

rgpdataCPolySetGreen,

IDMEMBER_CPOLY_SETGREEN,

IMETH_CPOLY_SETGREEN,

CC_CALL,

DIM(rgpdataCPolySetGreen),

DISPATCH_METHOD,

VT_EMPTY

    },

    // short CPoly::get_blue(void)

    {

OLESTR("get_blue"),

NULL,

IDMEMBER_CPOLY_GETBLUE,

IMETH_CPOLY_GETBLUE,

CC_CALL,

0,

DISPATCH_METHOD,

VT_I2

    },

    // void CPoly::set_blue(short blue)

    {

OLESTR("set_blue"),

rgpdataCPolySetBlue,

IDMEMBER_CPOLY_SETBLUE,

IMETH_CPOLY_SETBLUE,

CC_CALL,

DIM(rgpdataCPolySetBlue),

DISPATCH_METHOD,

VT_EMPTY

    },

    // void CPoly::Dump(void)

    {

OLESTR("Dump"),

NULL,

IDMEMBER_CPOLY_DUMP,

IMETH_CPOLY_DUMP,

CC_CALL,

0,

DISPATCH_METHOD,

VT_EMPTY

    },

};

INTERFACEDATA NEAR g_idataCPoly =

{

    rgmdataCPoly, DIM(rgmdataCPoly)

};


 WINMAIN.CPP  (SPOLY2 Sample)

/***

*winmain.cpp

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*  Information Contained Herein Is Proprietary and Confidential.

*

*Purpose:

*  This module is the main entry point for the sample IDispatch polygon

*  server, spoly2.exe.

*

*  This program is intended to demonstrate an implementation of the IDispatch

*  interface. Spoly is a very simple app, that implements two simple objects,

*  CPoly and CPoint and exposes their properties and methods for programatic

*  and cross-process access via IDispatch.

*

*Implementation Notes:

*

*****************************************************************************/

#include <stdio.h>

#include <string.h>

#include "spoly.h"

#include "cpoint.h"

#include "cpoly.h"

HANDLE g_hinst = 0;

HWND g_hwndFrame = 0;

HWND g_hwndClient = 0;

TCHAR g_szFrameWndClass[] = TSTR("FrameWClass");

CStatBar FAR* g_psb = NULL;

BOOL InitApplication(HANDLE);

BOOL InitInstance(HANDLE, int);

extern "C" int PASCAL WinMain(HANDLE, HANDLE, LPSTR, int);

extern "C" long FAR PASCAL FrameWndProc(HWND, UINT, WPARAM, LPARAM);

extern "C" int PASCAL

WinMain(

    HANDLE hinst,

    HANDLE hPrevInstance,

    LPSTR lpCmdLine,

    int nCmdShow)

{

    MSG msg;

    int retval;

    HRESULT hresult;

    if(!hPrevInstance)

      if(!InitApplication(hinst))

        return FALSE;

    if((hresult = InitOle()) != NOERROR)

      return FALSE;

    if(!InitInstance(hinst, nCmdShow)){

      retval = FALSE;

      UninitOle();

      goto LExit;

    }

    while(GetMessage(&msg, NULL, NULL, NULL)) {

      TranslateMessage(&msg);

      DispatchMessage(&msg);

    }

    CPoly::PolyTerm();

    retval = msg.wParam;

LExit:;

    return retval;

}

BOOL

InitApplication(HANDLE hinst)

{

    WNDCLASS  wc;

    wc.style            = CS_HREDRAW | CS_VREDRAW;

    wc.lpfnWndProc      = FrameWndProc;

    wc.cbClsExtra       = 0;

    wc.cbWndExtra       = 0;

    wc.hInstance        = hinst;

    wc.hIcon            = LoadIcon(hinst, TSTR("SPOLY"));

    wc.hCursor          = LoadCursor(NULL, IDC_ARROW);

    wc.hbrBackground    = (HBRUSH) (COLOR_APPWORKSPACE+1);

    wc.lpszMenuName     = TSTR("SPolyMenu");

    wc.lpszClassName    = g_szFrameWndClass;

    if(!RegisterClass(&wc))

      return FALSE;

    return TRUE;

}

#ifdef WIN32

#define szAppTitle TSTR("IDispatch Polygon Server #2 (32-bit)")

#else //WIN32

#define szAppTitle TSTR("IDispatch Polygon Server #2")

#endif //WIN32

BOOL

InitInstance(HANDLE hinst, int nCmdShow)

{

    g_hinst = hinst;

    // Create a main frame window

    //

    g_hwndFrame = CreateWindow(

      g_szFrameWndClass,

      szAppTitle,

      WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,

      CW_USEDEFAULT,

      CW_USEDEFAULT,

      CW_USEDEFAULT,

      CW_USEDEFAULT,

      NULL,

      NULL,

      hinst,

      NULL);

    if(!g_hwndFrame)

      return FALSE;

    g_hwndClient = GetWindow(g_hwndFrame, GW_CHILD);

    if(!g_hwndClient)

      return FALSE;

    // create the status bar

    //

    g_psb = CStatBar::Create(g_hinst, g_hwndFrame);

    if(!g_psb)

      return FALSE;

    // initialize and show the status bar

    //

    g_psb->SetHeight(GetSystemMetrics(SM_CYCAPTION) - 1);

    g_psb->SetFont(GetStockObject(SYSTEM_FONT));

    g_psb->SetText(OLESTR(""));

    g_psb->Show();

    ShowWindow(g_hwndFrame, nCmdShow);

    UpdateWindow(g_hwndFrame);

    return TRUE;

}

void

FrameWndOnCreate(HWND hwnd)

{

    CLIENTCREATESTRUCT ccs;

    ccs.hWindowMenu = NULL;

    ccs.idFirstChild = IDM_FIRSTCHILD;

    g_hwndClient = CreateWindow(

      TSTR("MDICLIENT"),

      0,

      WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE,

      0, 0, 0, 0,

      hwnd,

      (HMENU) 1,

      g_hinst,

      &ccs);

}

void

FrameWndOnSize(HWND hwnd)

{

    RECT rc;

    int height;

    // Get the client rectangle for the frame window

    GetClientRect(hwnd, &rc);

    height = g_psb->GetHeight();

    // adjust the client win to make room for the status bar.

    //

    MoveWindow(

      g_hwndClient,

      rc.left,

      rc.top,

      rc.right - rc.left,

      rc.bottom - rc.top - height,

      TRUE);

    // move the status bar to the bottom of the newly positioned window.

    //

    g_psb->SetX(rc.left);

    g_psb->SetY(rc.bottom - height),

    g_psb->SetWidth(rc.right - rc.left);

    g_psb->Move();

}

extern "C" long FAR PASCAL

FrameWndProc(

    HWND hwnd,

    UINT message,

    WPARAM wParam,

    LPARAM lParam)

{

    switch(message){

    case WM_COMMAND:

      switch(wParam){

      case IDM_DUMP:

        CPoly::PolyDump();

        return 0;

      case IDM_CLEAR:

        InvalidateRect(g_hwndClient, NULL, TRUE);

        return 0;

      }

      break;

    case WM_CREATE:

      FrameWndOnCreate(hwnd);

      break;

    case WM_SIZE:

      FrameWndOnSize(hwnd);

      return 1;

    case WM_PAINT:

      CPoly::PolyDraw();

      break;

    case WM_CLOSE:

      DestroyWindow(hwnd);

      return 0;

    case WM_DESTROY:

      UninitOle();

      PostQuitMessage(0);

      return 0;

    }

    return DefFrameProc(hwnd, g_hwndClient, message, wParam, lParam);

}

#if defined(WIN32)

extern "C" OLECHAR FAR*

ConvertStrAtoW(char FAR* strIn, OLECHAR FAR* buf, UINT size)

{

  MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,

                       strIn, -1, buf, size) ;

  return buf;

}

extern "C" OLECHAR FAR*

WideString(char FAR* strIn)

{

  static OLECHAR buf[256];

  return (ConvertStrAtoW(strIn, buf, 256));

}

extern "C" char FAR*

ConvertStrWtoA(OLECHAR FAR* strIn, char FAR* buf, UINT size)

{

  int badConversion = FALSE;

  WideCharToMultiByte(CP_ACP, NULL,

                      strIn, -1,

                      buf, size,

                      NULL, &badConversion);

  return buf;

}

extern "C" char FAR*

AnsiString(OLECHAR FAR* strIn)

{

  static char buf[256];

  return (ConvertStrWtoA(strIn, buf, 256));

}

#endif


 TIBROWSE

--------------------------------------- OLE Automation Sample Program: TiBrowse ---------------------------------------

Tibrowse is a sample OLE Automation browser.  When started, it asks the user to selected a type library (.tlb) file. The browser then displays the contents of this file.

--------------------------- Shortcomings of this sample --------------------------- 1. This browser is not suitable for use by end users.  It is deficient in many ways.  A few of them:   - Users should never have to know that uuid's exist.  Thus,
they should not be displayed in a browser.   - Items that are restricted or that start with underscore
should not be displayed in a browser.   - Duplicates for propery get/set pairs should be removed
since users think about properties, not about get/set  	pairs.


 MAKEFILE  (TIBROWSE Sample)

####

#makefile - makefile for tibrowse.exe

#

#       Copyright (C) 1992, Microsoft Corporation

#

#Purpose:

#  Builds the OLE 2.0 sample IDispatch server, tibrowse.exe.

#

#

#  Usage: NMAKE                 ; build with defaults

#     or: NMAKE option          ; build with the given option(s)

#     or: NMAKE clean           ; erase all compiled files

#

#     option:

#         dev = [win16 | win32] ; dev=win32 is the default

#         DEBUG=[0|1]           ; DEBUG=1 is the default

#

#Notes:

#  This makefile assumes that the PATH, INCLUDE and LIB environment

#  variables are setup properly.

#

##############################################################################

##########################################################################

#

# Default Settings

#

!if "$(dev)" == ""

dev = win32

!endif

!if !("$(dev)" == "win16" || "$(dev)" == "win32")

!error Invalid dev option, choose from [win16 | win32]

!endif

!if "$(dev)" == "win16"

TARGET  = WIN16

!endif

!if "$(dev)" == "win32"

TARGET  = WIN32

!endif

!ifdef NODEBUG

DEBUG = 0

!endif

!if "$(DEBUG)" == "0"

NODEBUG = 1

!endif

!if "$(DEBUG)" == ""

DEBUG = 1

!endif

##########################################################################

#

# WIN16 Settings

#

!if "$(TARGET)" == "WIN16"

CC   = cl

LINK = link

RCFLAGS = -dWIN16

CFLAGS = -c -W3 -AM -GA -GEs -DWIN16

LINKFLAGS = /NOD /NOI /BATCH /ONERROR:NOEXE

LIBS = libw.lib mlibcew.lib

!if "$(DEBUG)" == "1"

CFLAGS = $(CFLAGS) -Od -Zi -D_DEBUG $(CL)

LINKFLAGS = $(LINKFLAGS) /COD

!else

CFLAGS = $(CFLAGS) -Ox $(CL)

LINKFLAGS = $(LINKFLAGS) /FAR /PACKC

!endif

!endif

##########################################################################

#

# WIN32 Settings

#

!if "$(TARGET)" == "WIN32"

!include <$(MSTOOLS)\samples\ole\include\olesampl.mak>

CC = $(cc)

CFLAGS = $(cflags) $(cvarsmt) -DINC_OLE2 -DUNICODE $(cdebug)

!ifndef NODEBUG

CFLAGS = $(CFLAGS) -D_DEBUG

!endif

LINK = $(link)

LINKFLAGS = $(linkdebug) $(guilflags)

RCFLAGS = -DWIN32

!endif

##########################################################################

#

# Build rules

#

.cpp.obj:

    @echo Compiling $<...

    $(CC) $<

.c.obj:

    @echo Compiling $<...

    $(CC) $<

##########################################################################

#

# Application Settings

#

APPS = tibrowse

!if "$(TARGET)" == "WIN16"

LIBS = ole2.lib compobj.lib ole2disp.lib typelib.lib commdlg.lib $(LIBS)

!endif

!if "$(TARGET)" == "WIN32"

LIBS = $(olelibsmt)

!endif

OBJS = \

         tibrowse.obj

##########################################################################

#

# Default Goal

#

goal : setflags $(APPS).exe

setflags :

        set CL=$(CFLAGS)

##########################################################################

#

# Clean (erase) generated files

#

clean :

    if exist *.obj       del *.obj

    if exist $(APPS).exe del $(APPS).exe

    if exist $(APPS).map del $(APPS).map

    if exist $(APPS).res del $(APPS).res

    if exist *.pdb       del *.pdb

##########################################################################

#

# Application Build (WIN16 Specific)

#

!if "$(TARGET)" == "WIN16"

$(APPS).exe : $(OBJS) $(APPS).def $(APPS).res $(APPS).ico

        link $(LINKFLAGS) @<<

$(OBJS),

$@,,

$(LIBS),

$(APPS).def

<<

        rc -k -t $(APPS).res $@

!endif

##########################################################################

#

# Application Build (WIN32 Specific)

#

!if "$(TARGET)" == "WIN32"

$(APPS).exe : $(OBJS) $(APPS).def $(APPS).res $(APPS).ico

      $(LINK) @<<

        $(LINKFLAGS)

        -out:$@

        -map:$*.map

        $(OBJS)

        $(APPS).res

        $(LIBS)

<<

!endif

##########################################################################

#

# Application Build (Common)

#

$(APPS).res : $(APPS).rc

        rc $(RCFLAGS) -r -fo$@ $?

##########################################################################

#

# Dependencies

#

tibrowse.obj : tibrowse.cpp resource.h

    $(CC) tibrowse.cpp


 RESOURCE.H  (TIBROWSE Sample)

/***

*resource.h

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*

*Purpose:

*

*Implementation Notes:

*

*****************************************************************************/

#ifdef _MAC

# define IDC_BASE 0

# define kMinSize	1000	/* minimum size (in K) */

# define kPrefSize	1000	/* preferred size (in K) */

# define kMinHeap	21 * 1024

# define kMinSpace	8 * 1024

# define rMenuBar	128	/* menu bar */

# define rAboutAlert	128	/* about alert */

# define rUserAlert	129	/* error alert */

# define rDlg	130

# define mApple	128	/* Apple menu */

# define iAbout	1

# define mFile	129	/* File menu */

# define iOpen	2

# define iClose	4

# define iQuit	12

# define mEdit	130	/* Edit menu */

# define iUndo	1

# define iCut	3

# define iCopy	4

# define iPaste	5

# define iClear	6

#else

# define IDC_BASE 1000

#endif

#define IDC_TYPELIST    (IDC_BASE+1)

#define IDC_MEMBERLIST  (IDC_BASE+2)

#define IDC_PARAMLIST   (IDC_BASE+3)

#define IDC_TYPEKIND    (IDC_BASE+5)

#define IDC_VERSION     (IDC_BASE+7)

#define IDC_GUID        (IDC_BASE+9)

#define IDC_HELPSTRING  (IDC_BASE+11)

#define IDC_HELPCONTEXT (IDC_BASE+13)

#define IDC_STATIC      -1


 TIBROWSE.DEF  (TIBROWSE Sample)

;------------------------------------

; TIBROWSE.DEF module definition file

;------------------------------------

NAME           TIBROWSE

DESCRIPTION    'Type library browser'

EXETYPE        WINDOWS

STUB           'WINSTUB.EXE'

CODE           PRELOAD MOVEABLE DISCARDABLE

DATA           PRELOAD MOVEABLE MULTIPLE

HEAPSIZE       1024

STACKSIZE      10240


 TIBROWSE.H  (TIBROWSE Sample)

/***

*tibrowse.h

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*

*Purpose:

*

*Implementation Notes:

*

*****************************************************************************/

#if defined(_MAC)

#if defined(_MSC_VER)

# include <values.h>

# include <types.h>

# include <string.h>

# include <quickdra.h>

# include <fonts.h>

# include <events.h>

# include <resource.h>

# include <menus.h>

# include <lists.h>

# include <textedit.h>

# include <dialogs.h>

# include <desk.h>

# include <toolutil.h>

# include <memory.h>

# include <files.h>

# include <osutils.h>

# include <osevents.h>

# include <diskinit.h>

# include <packages.h>

# include <traps.h>

# include <AppleEve.h>

# include <standard.h>

#else //_MSC_VER

# include <values.h>

# include <types.h>

# include <strings.h>

# include <quickdraw.h>

# include <fonts.h>

# include <events.h>

# include <resources.h>

# include <windows.h>

# include <menus.h>

# include <lists.h>

# include <textedit.h>

# include <dialogs.h>

# include <desk.h>

# include <toolutils.h>

# include <memory.h>

# include <files.h>

# include <osutils.h>

# include <osevents.h>

# include <diskinit.h>

# include <packages.h>

# include <traps.h>

# include <AppleEvents.h>

# include <StandardFile.h>

#endif //_MSC_VER

# include <ole2.h>

# include <olenls.h>

# include <dispatch.h>

#elif defined(WIN32)

# include <windows.h>

# include <commdlg.h>

# include <ole2.h>

# include <oleauto.h>

#else /* WIN16 */

# include <windows.h>

# include <commdlg.h>

# include <ole2.h>

# include <olenls.h>

# include <dispatch.h>

#endif

#include "resource.h"

#ifdef WIN32

# define EXPORT

#else

# define EXPORT _export

#endif

#ifdef _MAC

# define UNUSED(X) ((void)(void*)&(X))

#else

# define UNUSED(X) (X)

#endif

#define DIM(X) (sizeof(X) / sizeof(X[0]))

void AssertFail(char FAR*, int);

#define ASSERT(X) if (!(X)) { AssertFail(__FILE__, __LINE__); } else {}

#define	CHECKRESULT(X) \

  {HRESULT hresult = (X); \

    if(hresult != NOERROR && FAILED(GetScode(hresult))) MethodError(hresult); }

HRESULT OpenFile(BSTR FAR* pbstrFileName);

void    OpenTypeLib(char FAR*);

void    SetSelectedType(unsigned long);

void    FillMemberList(ITypeInfo FAR *, TYPEATTR FAR *, int cltid);

void    SetSelectedMember(unsigned long);

void    SetSelectedParam(unsigned long dwIndex);

void    UpdateMemberInfo(MEMBERID memid);

void    AssertFail(char FAR*, int);

void    MethodError(HRESULT hresult);

void    Cleanup(void);

void    MemFree(void FAR*);

#ifdef _PPCMAC

#define ROUTINE_DESC(proc)              g_rd##proc

#define DECLARE_ROUTINE_DESC(type,proc) static type ROUTINE_DESC(proc)=0

#define INIT_ROUTINE_DESC(init,proc)    { if (!ROUTINE_DESC(proc)) ROUTINE_DESC(proc)=init(proc); }

#else  // _PPCMAC

#define ROUTINE_DESC(proc)              proc

#define INIT_ROUTINE_DESC(init,proc)

#define DECLARE_ROUTINE_DESC(type,proc)

#endif // _PPCMAC


 TIBROWSE.RC  (TIBROWSE Sample)

#include "windows.h"

#include "resource.h"

TIBROWSE                ICON    DISCARDABLE     "TIBROWSE.ICO"

TIBROWSE DIALOG DISCARDABLE  -32768, 0, 272, 192

STYLE WS_MINIMIZEBOX | WS_CAPTION | WS_SYSMENU

CAPTION "Type Library Browser"

CLASS "TiBrowse"

FONT 8, "System"

BEGIN

    LTEXT           "&Type",IDC_STATIC,10,10,62,9

    LISTBOX         IDC_TYPELIST,10,20,80,80,LBS_NOINTEGRALHEIGHT |

                    WS_VSCROLL | WS_TABSTOP

    LTEXT           "&Members",IDC_STATIC,100,10,62,9

    LISTBOX         IDC_MEMBERLIST,100,20,80,80,LBS_NOINTEGRALHEIGHT |

                    WS_VSCROLL | WS_TABSTOP

    LTEXT           "&Parameters",IDC_STATIC,190,10,62,9

    LISTBOX         IDC_PARAMLIST,190,20,75,80,LBS_NOINTEGRALHEIGHT |

                    WS_VSCROLL | WS_TABSTOP

    LTEXT           "",IDC_HELPSTRING,60,170,205,18

    CONTROL         "",IDC_HELPCONTEXT,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,

                    60,155,140,7

    LTEXT           "Help String:",IDC_STATIC,10,170,45,8

    LTEXT           "Help Context:",IDC_STATIC,10,155,45,8

    LTEXT           "Type Kind:",IDC_STATIC,10,110,45,8

    LTEXT           "",IDC_TYPEKIND,60,110,140,8

    LTEXT           "GUID:",IDC_STATIC,10,140,45,8

    LTEXT           "",IDC_GUID,60,140,160,8

    LTEXT           "Version:",IDC_STATIC,10,125,45,8

    LTEXT           "",IDC_VERSION,60,125,140,8

END


 TIBROWSE.CPP  (TIBROWSE Sample)

/***

*tibrowse.cpp

*

*  Copyright (C) 1992-1994, Microsoft Corporation.  All Rights Reserved.

*  Information Contained Herein Is Proprietary and Confidential.

*

*Purpose:

*  Type Information Browser

*

*

*Implementation Notes:

*

*****************************************************************************/

#if defined(_MAC)

#if defined(_PPCMAC)

#pragma data_seg("_FAR_DATA")

#pragma data_seg( )

#define MAXLONG 0x7fffffff

#define EventHandlerProcPtr AEEventHandlerUPP

#else //_PPCMAC

#define  GetMenuItemText(mApple,menuItem,daName)  GetItem(mApple,menuItem,daName)

#endif //_PPCMAC

#endif //_MAC

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include "tibrowse.h"

#ifdef WIN32

  #define SPRINTF	swprintf

#else

  #define SPRINTF	sprintf

#endif

#if defined(UNICODE)

  #define TCHAR	WCHAR

  #define TSTR(str)	L##str

#else

  #define TCHAR	char

  #define TSTR(str)	str

  #ifndef LPTSTR

    #define LPTSTR LPSTR

  #endif

#endif

#ifdef _MAC

DECLARE_ROUTINE_DESC(UserItemUPP,DrawListbox);

#endif

#ifdef _MAC

DialogPtr g_pdlg = NULL;

ListHandle g_rghlist[IDC_PARAMLIST+1] = {NULL};

#else

HWND g_hwnd;

TCHAR g_szAppName[] = TSTR("TiBrowse");

#endif

ITypeLib  FAR *g_ptlib = NULL;

ITypeInfo FAR *g_ptinfoCur = NULL;

TYPEATTR  FAR *g_ptattrCur = NULL;

OLECHAR * g_rgszTKind[] = {

    OLESTR("Enum"),	/* TKIND_ENUM */

    OLESTR("Struct"),	/* TKIND_RECORD */

    OLESTR("Module"),	/* TKIND_MODULE */

    OLESTR("Interface"),	/* TKIND_INTERFACE */

    OLESTR("Dispinterface"),	/* TKIND_DISPATCH */

    OLESTR("Coclass"),	/* TKIND_COCLASS */

    OLESTR("Typedef"),	/* TKIND_ALIAS */

    OLESTR("Union"),	/* TKIND_UNION */

};

// Set the text of the control identified by the given control id

void

XSetDlgItemText(int ctlid, OLECHAR FAR* psz)

{

#ifdef _MAC

    Rect rc;

    Handle h;

    short kind;

    char buf[255];

    strcpy(buf, psz);

    GetDItem(g_pdlg, ctlid, &kind, &h, &rc);

    SetIText(h, c2pstr(buf));

#else

#if defined(WIN32) && !defined(UNICODE)

    char bufA[256];

    WideCharToMultiByte(CP_ACP, NULL, psz, -1, bufA, 256, NULL, NULL);

    SendDlgItemMessage(g_hwnd, ctlid, WM_SETTEXT, 0, (LPARAM)&bufA);

#else

    SendDlgItemMessage(g_hwnd, ctlid, WM_SETTEXT, 0, (LPARAM)psz);

#endif

#endif

}

// Clear the listbox identified by the given control id

void

XClrDlgItemList(int ctlid)

{

#ifdef _MAC

    LDelRow(0, 0, g_rghlist[ctlid]); // delete everything

#else

    SendMessage(GetDlgItem(g_hwnd, ctlid), LB_RESETCONTENT, 0, 0L);

#endif

}

// Add the given string to the listbox identified by the given control id

void

XAddDlgItemList(int ctlid, OLECHAR FAR* psz)

{

#ifdef _MAC

    int row;

    Point pt;

    ListHandle hlist;

    hlist = g_rghlist[ctlid];

    row = LAddRow(1, -1, hlist);

    pt.v = row, pt.h = 0;

    LSetCell(psz, strlen(psz), pt, hlist);

#else

#if defined(WIN32) && !defined(UNICODE)

    char bufA[256];

    WideCharToMultiByte(CP_ACP, NULL, psz, -1, bufA, 256, NULL, NULL);

    SendDlgItemMessage(g_hwnd, ctlid, LB_ADDSTRING, 0, (LPARAM)&bufA);

#else

    SendDlgItemMessage(g_hwnd, ctlid, LB_ADDSTRING, 0, (LPARAM)psz);

#endif

#endif

}

void Cleanup()

{

    if(g_ptinfoCur != NULL){

      if(g_ptattrCur != NULL)

        g_ptinfoCur->ReleaseTypeAttr(g_ptattrCur);

      g_ptinfoCur->Release();

      g_ptinfoCur = NULL;

    }

    if(g_ptlib != NULL){

      g_ptlib->Release();

      g_ptlib = NULL;

    }

}

void Uninit()

{

    OleUninitialize();

#ifdef _MAC

#ifndef _PPCMAC

    UninitOleManager();	// clean up applet

#endif

#endif

}

void

OpenTypeLib(OLECHAR FAR *sztlib)

{

    unsigned int utypeinfoCount, i;

    BSTR bstrName;

    TLIBATTR FAR* ptlibattr;

    /* clear out globals */

    Cleanup();

    /* clear out listboxes */

    XClrDlgItemList(IDC_TYPELIST);

    XClrDlgItemList(IDC_MEMBERLIST);

    XClrDlgItemList(IDC_PARAMLIST);

    /* load the type library */

    CHECKRESULT(LoadTypeLib(sztlib, &g_ptlib));

    /* get library attributes for the fun of it */

    CHECKRESULT(g_ptlib->GetLibAttr(&ptlibattr));

    /* release library attributes */

    g_ptlib->ReleaseTLibAttr(ptlibattr);

    /* Now add each of the names to the type list */

    utypeinfoCount = g_ptlib->GetTypeInfoCount();

    for(i = 0; i < utypeinfoCount; i++){

      CHECKRESULT(g_ptlib->GetDocumentation(i, &bstrName, NULL, NULL, NULL));

      ASSERT(bstrName);

      XAddDlgItemList(IDC_TYPELIST, bstrName);

      SysFreeString(bstrName);

    }

}

#ifdef WIN32

void

OpenTypeLib(char FAR *sztlib)

{

  OLECHAR buf[MAX_PATH];

  MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,

              sztlib, -1, buf, MAX_PATH);

  OpenTypeLib(buf);

}

#endif

/***

*void SetSelectedType

*Purpose:

*  When the user changes the selection of a type, this function updates the

*  dialog by changing the member list and the help for the type. It also sets

*  g_ptinfoCur to refer to the typeinfo.

*

*Entry:

*  dwIndex =

*

*Exit:

*  return value = None

*

***********************************************************************/

void

SetSelectedType(unsigned long dwIndex)

{

    HRESULT hr;

    BSTR bstrDoc;

    OLECHAR FAR* psz;

    OLECHAR szBuf[40];

    unsigned long dwHelpContext;

    TYPEKIND tkind;

    if(g_ptinfoCur != NULL){

      g_ptinfoCur->ReleaseTypeAttr(g_ptattrCur);

      g_ptinfoCur->Release();

    }

    /* Clear out the member list */

    XClrDlgItemList(IDC_MEMBERLIST);

    if(g_ptlib == NULL)

      return;

    // Note: the index in the list box is conveniently the same as the

    // one to pass to GetTypeInfo/GetTypeInfoType

    // typeinfo type can be obtained without actually loading the typeinfo

    CHECKRESULT(g_ptlib->GetTypeInfoType((unsigned int)dwIndex, &tkind));

    XSetDlgItemText(IDC_TYPEKIND, g_rgszTKind[tkind]);

    CHECKRESULT(g_ptlib->GetTypeInfo((unsigned int)dwIndex, &g_ptinfoCur));

    CHECKRESULT(g_ptinfoCur->GetTypeAttr(&g_ptattrCur));

    // GUID

    hr = StringFromCLSID(g_ptattrCur->guid, &psz);

    ASSERT(hr == NOERROR);

    XSetDlgItemText(IDC_GUID, psz);

    MemFree(psz);

    // Version

    SPRINTF(szBuf, OLESTR("%u.%02u"),

      g_ptattrCur->wMajorVerNum, g_ptattrCur->wMinorVerNum);

    XSetDlgItemText(IDC_VERSION, szBuf);

    CHECKRESULT(

      g_ptlib->GetDocumentation(

        (unsigned int)dwIndex, NULL, &bstrDoc, &dwHelpContext, NULL));

    // Help Context

    SPRINTF(szBuf, OLESTR("%ld"), dwHelpContext);

    XSetDlgItemText(IDC_HELPCONTEXT, szBuf);

    // Documentation string

    psz = (bstrDoc != NULL) ? bstrDoc : OLESTR("<none>");

    XSetDlgItemText(IDC_HELPSTRING, psz);

    SysFreeString(bstrDoc);

    FillMemberList(g_ptinfoCur, g_ptattrCur, IDC_MEMBERLIST);

    XClrDlgItemList(IDC_PARAMLIST);

}

/***

*void FillMemberList

*Purpose:

* Sets the current typeinfo to the typeinfo indexed by dwIndex, and

* then fills in the list box with the members of the type.

*

*Entry:

*  ptinfo =

*  ptypeattr =

*

*Exit:

*  return value = None

*

***********************************************************************/

void

FillMemberList(

    ITypeInfo FAR *ptinfo,

    TYPEATTR FAR *ptypeattr,

    int ctlid)

{

    MEMBERID memid;

    BSTR bstrName;

    unsigned int i;

    FUNCDESC FAR *pfuncdesc;

    VARDESC  FAR *pvardesc;

    /* Now add all of the functions and all of the vars.

     * This is somewhat roundabout.

     * For each one, we need to get the funcdesc, or the vardesc.

     * From that we get the MEMBERID, and finally can get to the name.

     */

    for(i = 0; i < ptypeattr->cFuncs; i++){

      CHECKRESULT(ptinfo->GetFuncDesc(i, &pfuncdesc));

      memid = pfuncdesc->memid;

      CHECKRESULT(ptinfo->GetDocumentation(memid, &bstrName, NULL, NULL, NULL));

      ptinfo->ReleaseFuncDesc(pfuncdesc);

      pfuncdesc = NULL;

      ASSERT(bstrName);

      XAddDlgItemList(ctlid, bstrName);

      SysFreeString(bstrName);

    }

    for(i = 0; i < ptypeattr->cVars; i++)

    {

      CHECKRESULT(ptinfo->GetVarDesc(i, &pvardesc));

      memid = pvardesc->memid;

      CHECKRESULT(ptinfo->GetDocumentation(memid, &bstrName, NULL, NULL, NULL));

      ptinfo->ReleaseVarDesc(pvardesc);

      pvardesc = NULL;

      ASSERT(bstrName);

      XAddDlgItemList(ctlid, bstrName);

      SysFreeString(bstrName);

    }

}

/***

*void SetSelectedMember

*Purpose:

*  When a member of a type is selected, update the help to be the help

*  of the member, and if the member is a function update the parameter

*  list to reflect that it is a function.

*

*Entry:

*  dwIndex =

*

*Exit:

*  return value = None

*

***********************************************************************/

void

SetSelectedMember(unsigned long dwIndex)

{

    MEMBERID memid;

    /* In any case, we'll need to clear out the parameter list. */

    XClrDlgItemList(IDC_PARAMLIST);

    if(g_ptattrCur == NULL)

      return;

    /* if this is a function, fill the param list, otherwise just fill

     * in the item info.

     */

    if(dwIndex < g_ptattrCur->cFuncs){

      unsigned short i;

      unsigned int cNames;

      FUNCDESC FAR *pfuncdesc;

      const unsigned int MAX_NAMES = 40;

      BSTR rgNames[MAX_NAMES];

      CHECKRESULT(g_ptinfoCur->GetFuncDesc((unsigned int) dwIndex, &pfuncdesc));

      memid = pfuncdesc->memid;

      UpdateMemberInfo(memid);

      CHECKRESULT(g_ptinfoCur->GetNames(memid, rgNames, MAX_NAMES,&cNames));

      for(i = 1; i < cNames; i++){

ASSERT(rgNames[i])

XAddDlgItemList(IDC_PARAMLIST, rgNames[i]);

SysFreeString(rgNames[i]);

      }

      ASSERT(rgNames[0]);

      SysFreeString(rgNames[0]);

      g_ptinfoCur->ReleaseFuncDesc(pfuncdesc);

    }

    else

    {

      VARDESC FAR *pvardesc;

      CHECKRESULT(

        g_ptinfoCur->GetVarDesc(

  (unsigned int)(dwIndex - g_ptattrCur->cFuncs), &pvardesc));

      memid = pvardesc->memid;

      UpdateMemberInfo(memid);

      g_ptinfoCur->ReleaseVarDesc(pvardesc);

    }

}

/***

*void UpdateMemberInfo

*Purpose:

*  sets fields on the dialog (such as help string and help context) from

*  the type information.

*

*Entry:

*  memid =

*

*Exit:

*  return value = None

*

***********************************************************************/

void

UpdateMemberInfo(MEMBERID memid)

{

    BSTR bstrDoc;

    OLECHAR buf[40];

    unsigned long dwHelpContext;

    /* get the member information */

    CHECKRESULT(g_ptinfoCur->GetDocumentation(

      memid, NULL, &bstrDoc, &dwHelpContext, NULL));

    /* update the help string displayed in the dialog */

    XSetDlgItemText(IDC_HELPSTRING, (bstrDoc != NULL) ?

                             bstrDoc : OLESTR("<none>"));

    SysFreeString(bstrDoc);

    /* update the help context displayed in the dialog */

    SPRINTF(buf, OLESTR("%ld"), dwHelpContext);

    XSetDlgItemText(IDC_HELPCONTEXT, buf);

}

/***

*void SetSelectedParam

*Purpose:

*  CONSIDER: Enhance to show parameter type information here.

*

*Entry:

*  dwIndex =

*

*Exit:

*  return value = None

*

***********************************************************************/

void

SetSelectedParam(unsigned long dwIndex)

{

}

HRESULT

GetFileName(BSTR FAR* pbstrFileName)

{

    OLECHAR buf[1024];

    BSTR bstrFileName;

#ifdef _MAC

    int i;

    Point pt;

    long dirID;

    char *p, *q;

    SFReply sfr;

    SFTypeList sftl;

    short sRefNumReal;

    SetPt(&pt, 100, 100);

    //sftl[0] = 'OTLB';

    sftl[0] = 0; // currently allow all file types

    SFGetFile(pt, NULL, NULL, -1, sftl, NULL, &sfr);

    if(!sfr.good)

      return ResultFromScode(E_FAIL);

    // translate sfr.vRefNum into a dirID

    {

WDPBRec wdpbr;

wdpbr.ioWDIndex   = 0;

wdpbr.ioVRefNum   = sfr.vRefNum;

wdpbr.ioWDVRefNum = 0;

wdpbr.ioWDIndex   = 0;

wdpbr.ioWDProcID  = 0;

wdpbr.ioNamePtr   = (StringPtr)buf;

if(PBGetWDInfoSync (&wdpbr) != noErr)

  return ResultFromScode(E_FAIL);

sRefNumReal = wdpbr.ioWDVRefNum;

dirID = wdpbr.ioWDDirID;

    }

    {

Str255 stDir;

CInfoPBRec pb;

DirInfo *pdirinfo = (DirInfo*)&pb;

char rgchTemp[256]; // REVIEW: what should the size be?

pdirinfo->ioNamePtr = stDir;

pdirinfo->ioVRefNum = sRefNumReal;

pdirinfo->ioDrParID = dirID;

pdirinfo->ioFDirIndex = -1;  // get info on a dir

buf[0] = '\0';

// loop until we hit the root dir

do{

  pdirinfo->ioDrDirID = pdirinfo->ioDrParID;

  if(PBGetCatInfoSync (&pb) != noErr)

    return ResultFromScode(E_FAIL);

  strncpy(rgchTemp, (char*)stDir, 64);

  p2cstr((StringPtr)rgchTemp);

  strcat(rgchTemp, ":");

  strcat(rgchTemp, buf);

  strcpy(buf, rgchTemp);

}while(pdirinfo->ioDrDirID != fsRtDirID);

    }

    q = (char*)sfr.fName;

    i = (int)*q++;

    p = &buf[strlen(buf)];

    while(i-->0)

      *p++ = *q++;

    *p = '\0';

    if((bstrFileName = SysAllocString(buf)) == NULL)

      return ResultFromScode(E_OUTOFMEMORY);

#else

    OPENFILENAME ofn;

    memset(&ofn, 0, sizeof(OPENFILENAME));

    ofn.lStructSize  = sizeof(OPENFILENAME);

    ofn.hwndOwner    = g_hwnd;

    ofn.lpstrFile    = (LPTSTR) &buf;

    ofn.nMaxFile     = sizeof(buf);

    *buf = OLESTR('\0');

    ofn.lpstrFilter  = TSTR("Type Libraries\0*.tlb\0\0");

    ofn.nFilterIndex = 1;

    ofn.Flags        = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_SHAREAWARE;

    if(GetOpenFileName(&ofn) == 0){

      // REVIEW: we can probably do something smarter with this error

      DWORD dwerr = CommDlgExtendedError();

      return ResultFromScode(E_FAIL);

    }

#if defined(WIN32) && !defined(UNICODE)

    OLECHAR szFileW[_MAX_PATH];

    MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,

ofn.lpstrFile, -1, szFileW, _MAX_PATH);

    if((bstrFileName = SysAllocString(szFileW)) == NULL)

      return ResultFromScode(E_OUTOFMEMORY);

#else

    if((bstrFileName = SysAllocString(ofn.lpstrFile)) == NULL)

      return ResultFromScode(E_OUTOFMEMORY);

#endif

#endif

    *pbstrFileName = bstrFileName;

    return NOERROR;

}

void

AssertFail(char FAR* file, int line)

{

    // Ansi Output for Assertion

    #ifdef UNICODE

      #define OUTPUTDEBUGSTRING	OutputDebugStringA

      #define MESSAGEBOX	MessageBoxA

    #else

      #define OUTPUTDEBUGSTRING	OutputDebugString

      #define MESSAGEBOX	MessageBox

    #endif

    char buf[128];

    sprintf(buf, "Assertion failed: %s(%d)", file, line);

#ifdef _MAC

    DebugStr(c2pstr(buf));

#else

    OUTPUTDEBUGSTRING(buf);

    if(MESSAGEBOX(NULL, buf,

  "TiBrowse Assertion.  OK to continue, CANCEL to quit.",

  MB_OKCANCEL | MB_TASKMODAL) == IDCANCEL)

      exit(1);

    DebugBreak();

#endif

}

#ifdef _MAC /* { */

void Init(void);

void EventLoop(void);

void AdjustMenus(void);

void DoEvent(EventRecord *pevent);

void DoMenuCommand(long menuResult);

void Quit(void);

#ifndef _MSC_VER

#ifndef ConstStr255Param

#define ConstStr255Param StringPtr

#endif

#endif

void Fatal(ConstStr255Param);

Boolean

IsAppWindow(WindowPtr window)

{

    return (window == NULL)

      ? false : ((WindowPeek)window)->windowKind == userKind;

}

Boolean

IsDAWindow(WindowPtr window)

{

    return (window == NULL)

      ? false : (((WindowPeek)window)->windowKind < 0);

}

void

main()

{

    Init();

//    ShowWindow(g_pdlg); // REVIEW: necessarry?

    EventLoop();

}

void

DoDialogEvent(EventRecord *pevent, short sItem)

{

    Point pt;

    GrafPtr pport;

    ListHandle hlist;

    switch(sItem){

    case IDC_TYPELIST:

    case IDC_MEMBERLIST:

    case IDC_PARAMLIST:

      if(pevent->what == mouseDown){

GetPort(&pport);

SetPort(g_pdlg);

        GlobalToLocal(&pevent->where);

hlist = g_rghlist[sItem];

        LClick(pevent->where, pevent->modifiers, hlist);

SetPt(&pt, 0, 0);

if(LGetSelect(true, &pt, hlist)){

  switch(sItem){

  case IDC_TYPELIST:

    SetSelectedType(pt.v);

    break;

  case IDC_MEMBERLIST:

    SetSelectedMember(pt.v);

    break;

  case IDC_PARAMLIST:

    SetSelectedParam(pt.v);

    break;

  }

}

SetPort(pport);

      }

      break;

    }

}

void

EventLoop()

{

    short sItem;

    DialogPtr pdlg;

    EventRecord	event;

    RgnHandle cursorRgn;

    cursorRgn = NewRgn();

    while(1){

      if(WaitNextEvent(everyEvent, &event, MAXLONG, cursorRgn)){

if (FrontWindow() != NULL

 && event.what != diskEvt

 && (event.what != keyDown || (event.modifiers & cmdKey) == 0)

 && IsDialogEvent(&event))

{

  if(DialogSelect(&event, &pdlg, &sItem)){

    ASSERT(pdlg == g_pdlg);

    DoDialogEvent(&event, sItem);

  }

}else{

  DoEvent(&event);

}

      }

    }

}

void

DoEvent(EventRecord *pevent)

{

    char key;

    short part;

    WindowPtr window;

    switch(pevent->what){

    case mouseDown:

      part = FindWindow(pevent->where, &window);

      switch(part){

      case inMenuBar:

AdjustMenus();

DoMenuCommand(MenuSelect(pevent->where));

break;

      case inSysWindow:	/* let the system handle the mouseDown */

SystemClick(pevent, window);

break;

      case inContent:

if(window != FrontWindow()){

  SelectWindow(window);

}

break;

      case inDrag:

DragWindow(window, pevent->where, &qd.screenBits.bounds);

break;

      }

      break;

    case keyDown:

    case autoKey:	/* check for menukey equivalents */

      key = (char)(pevent->message & charCodeMask);

      if(pevent->modifiers & cmdKey){	/* Command key down */

if(pevent->what == keyDown){

  /* enable/disable/check menu items properly */

  AdjustMenus();

  DoMenuCommand(MenuKey(key));

}

      }

      break;

    }

}

void

Enable(MenuHandle hmenu, short sItem, Boolean fEnable)

{

    if(fEnable)

      EnableItem(hmenu, sItem);

    else

      DisableItem(hmenu, sItem);

}

void

AdjustMenus()

{

    Boolean fIsDA;

    MenuHandle hmenu;

    fIsDA = IsDAWindow(FrontWindow());

    /* we can allow desk accessories to be closed from the menu */

    hmenu = GetMHandle(mFile);

    Enable(hmenu, iClose, fIsDA);

    hmenu = GetMHandle(mEdit);

    Enable(hmenu, iUndo,  fIsDA);

    Enable(hmenu, iCut,   fIsDA);

    Enable(hmenu, iCopy,  fIsDA);

    Enable(hmenu, iPaste, fIsDA);

    Enable(hmenu, iClear, fIsDA);

}

void

DoMenuCommand(long menuResult)

{

    short menuID;	/* the resource ID of the selected menu */

    short menuItem;	/* the item number of the selected menu */

    Str255 daName;

    menuID = HiWord(menuResult);

    menuItem = LoWord(menuResult);

    switch(menuID){

    case mApple:

      switch(menuItem){

      case iAbout:	/* bring up alert for About */

Alert(rAboutAlert, NULL);

break;

      default:

GetMenuItemText(GetMHandle(mApple), menuItem, daName);

OpenDeskAcc(daName);

break;

      }

      break;

    case mFile:

      switch(menuItem){

      case iOpen:

    {

        BSTR bstrFileName;

        if(GetFileName(&bstrFileName) != NOERROR)

{

  // REVIEW: shouldnt just bag out here

  Fatal((ConstStr255Param)"\pUnable to open Type Library");

        }

        OpenTypeLib(bstrFileName);

    }

break;

      case iQuit:

Quit();

break;

      }

      break;

    case mEdit:

      SystemEdit(menuItem-1);

      break;

    }

    HiliteMenu(0);

}

extern "C" {

#if defined(_MSC_VER)

void pascal

#else

pascal void

#endif

DrawListbox(DialogPtr pdlg, short sItem)

{

    Rect rc;

    Handle h;

    short kind;

    GrafPtr port;

    ListHandle hlist;

    ASSERT(sItem == IDC_TYPELIST

|| sItem == IDC_MEMBERLIST

|| sItem == IDC_PARAMLIST);

    GetPort(&port);

    SetPort(pdlg);

    hlist = g_rghlist[sItem];

    LUpdate(pdlg->visRgn, hlist);

    GetDItem(pdlg, sItem, &kind, &h, &rc);

    InsetRect(&rc, -1, -1);

    FrameRect(&rc);

    SetPort(port);

}

}

/***

*ListHandle CreateListBox(DialogPtr, int)

*Purpose:

*  Create a listbox on the given dialog, associated with the given

*  control id.

*

*Entry:

*  pdlg =

*  ctlid =

*

*Exit:

*  return value = ListHandle

*

***********************************************************************/

ListHandle

CreateListbox(DialogPtr pdlg, int ctlid)

{

    Handle h;

    short kind;

    Point ptCell;

    ListHandle hlist;

    Rect rcView, rcBounds;

    INIT_ROUTINE_DESC(NewUserItemProc,DrawListbox);

    GetDItem(pdlg, ctlid, &kind, &h, &rcView);

    SetDItem(pdlg, ctlid, kind, (Handle) ROUTINE_DESC(DrawListbox), &rcView);

    // make room for scroll bars

    rcView.right -= 15;

    // list is 1 wide

    SetRect(&rcBounds, 0, 0, 1, 0);

    SetPt(&ptCell, 0, 0);

    hlist = LNew(

      &rcView,

      &rcBounds,

      ptCell,

      0, (WindowPtr)pdlg, true, false, false, true);

    ASSERT(hlist != NULL);

    (*hlist)->selFlags = lUseSense | lNoRect | lNoExtend | lOnlyOne;

    return hlist;

}

/***

*DialogPtr CreateDialog(void)

*Purpose:

*  Create the TiBrowse dialog

*

*Entry:

*  None

*

*Exit:

*  return value = DialogPtr

*

***********************************************************************/

DialogPtr

CreateDialog()

{

    int i;

    Point pt;

    DialogPtr pdlg;

    ListHandle hlist;

static short rgctl[] = {IDC_TYPELIST, IDC_MEMBERLIST, IDC_PARAMLIST};

    if((pdlg = GetNewDialog(rDlg, NULL, (WindowPtr)-1)) == NULL)

      return NULL;

    for(i = 0; i < DIM(rgctl); ++i){

      g_rghlist[rgctl[i]]  = CreateListbox(pdlg, rgctl[i]);

    }

    SetPt(&pt, 0, 0);

    for(i = 0; i < DIM(rgctl); ++i){

      hlist = g_rghlist[rgctl[i]];

      LSetSelect(true, pt, hlist);

      LDoDraw(true, hlist);

    }

    return pdlg;

}

void

Init()

{

    Handle menuBar;

    MaxApplZone();

    InitGraf((Ptr)&qd.thePort);

    InitFonts();

    InitWindows();

    InitMenus();

    TEInit();

    InitDialogs(NULL);

    InitCursor();

    FlushEvents(everyEvent, 0);

#ifndef _PPCMAC

    if (InitOleManager(0) != NOERROR)

      Fatal((ConstStr255Param)"\pCould not initialize OLE Applet");

#endif

    if(OleInitialize(NULL) != NOERROR)

      Fatal((ConstStr255Param)"\pUnable to Initialize Ole");

    if((menuBar = GetNewMBar(rMenuBar)) == NULL)

      Fatal((ConstStr255Param)"\pUnable to load menu bar");

    SetMenuBar(menuBar);

    DisposHandle(menuBar);

    AddResMenu(GetMHandle(mApple), 'DRVR');

    DrawMenuBar();

    if((g_pdlg = CreateDialog()) == NULL)

      Fatal((ConstStr255Param)"\pUnable to create dialog");

}

void

Quit()

{

    Cleanup();

    Uninit();

    ExitToShell();

}

/* display fatal error alert, and exit */

void

Fatal(ConstStr255Param msg)

{

    SetCursor(&qd.arrow);

    ParamText(msg, (ConstStr255Param)"\p", (ConstStr255Param)"\p", (ConstStr255Param)"\p");

    Alert(rUserAlert, nil);

    Quit();

}

#else /* }{ */

long FAR PASCAL EXPORT WndProc (HWND, UINT, WPARAM, LPARAM) ;

int PASCAL

WinMain(

    HANDLE hinst,

    HANDLE hinstPrev,

    LPSTR lpszCmdLine,

    int nCmdShow)

{

    MSG msg;

    WNDCLASS wndclass;

    if(!hinstPrev){

      wndclass.style          = CS_HREDRAW | CS_VREDRAW;

      wndclass.lpfnWndProc    = WndProc ;

      wndclass.cbClsExtra     = 0 ;

      wndclass.cbWndExtra     = DLGWINDOWEXTRA ;

      wndclass.hInstance      = hinst ;

      wndclass.hIcon          = LoadIcon (hinst, g_szAppName) ;

      wndclass.hCursor        = LoadCursor (NULL, IDC_ARROW) ;

      wndclass.hbrBackground  = (HBRUSH) (COLOR_WINDOW + 1) ;

      wndclass.lpszMenuName   = NULL ;

      wndclass.lpszClassName  = g_szAppName ;

      RegisterClass (&wndclass) ;

    }

    if(OleInitialize(NULL) != NOERROR){

      MessageBox(NULL, TSTR("unable to initialize Ole"),

         g_szAppName, MB_OK);

      return 0;

    }

    g_hwnd = CreateDialog(hinst, g_szAppName, 0, NULL);

    if(*lpszCmdLine == '\0'){

      BSTR bstrFileName;

      if(GetFileName(&bstrFileName) != NOERROR){

Cleanup();

Uninit();

exit(-1);

      }

      OpenTypeLib(bstrFileName);

      SysFreeString(bstrFileName);

    }else{

      OpenTypeLib(lpszCmdLine);

    }

    ShowWindow(g_hwnd, nCmdShow);

    while(GetMessage (&msg, NULL, 0, 0)){

      TranslateMessage (&msg);

      DispatchMessage (&msg);

    }

    Cleanup();

    Uninit();

    return msg.wParam;

}

long FAR PASCAL EXPORT

WndProc(

    HWND hwnd,

    UINT message,

    WPARAM wParam,

    LPARAM lParam)

{

    unsigned long dwIndex;

    switch(message){

    case WM_COMMAND:

      /* We deal with the following events:

       * The selection changes on the type list and we have

       *  to update the member list & type info.

       * The selection changes on the member list and we have

       *  to update the param list & member info.

       * Selection changes on a parameter and we have to

       *  update the param info.

       */

#ifdef WIN32

# define wParamX LOWORD(wParam)

# define notifyMsg HIWORD(wParam)

#else

# define wParamX wParam

# define notifyMsg HIWORD(lParam)

#endif

      switch(wParamX){

      case IDC_TYPELIST:

        if(notifyMsg == LBN_SELCHANGE){

          dwIndex = SendDlgItemMessage(hwnd, IDC_TYPELIST, LB_GETCURSEL, 0, 0L);

  if(dwIndex != LB_ERR)

    SetSelectedType(dwIndex);

}

break;

      case IDC_MEMBERLIST:

        if(notifyMsg == LBN_SELCHANGE){

          dwIndex = SendDlgItemMessage(hwnd, IDC_MEMBERLIST, LB_GETCURSEL,0,0L);

  if(dwIndex != LB_ERR)

    SetSelectedMember(dwIndex);

}

        break;

      case IDC_PARAMLIST:

        if(notifyMsg == LBN_SELCHANGE){

          dwIndex = SendDlgItemMessage(hwnd, IDC_PARAMLIST, LB_GETCURSEL, 0,0L);

  if(dwIndex != LB_ERR)

    SetSelectedParam(dwIndex);

}

break;

      }

      return 0;

    case WM_DESTROY:

      PostQuitMessage(0);

      return 0 ;

    }

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

}

#endif /* } */

void

MethodError(HRESULT hresult)

{

    /* CONSIDER: add code to figure out what specific error this is */

    UNUSED(hresult);

#ifdef _MAC

    Fatal((ConstStr255Param)"\pType Library");

#else

    MessageBox(NULL, TSTR("Error returned from TYPELIB.DLL"),

       g_szAppName, MB_OK);

    exit(1);

#endif

}

/* free using the task allocator */

void

MemFree(void FAR* pv)

{

    HRESULT hresult;

    IMalloc FAR* pmalloc;

    hresult = CoGetMalloc(MEMCTX_TASK, &pmalloc);

    if(hresult != NOERROR){

#ifdef _MAC

      Fatal((ConstStr255Param)"\pError accessing task allocator");

#else

      MessageBox(NULL, TSTR("Error accessing task allocator"),

         g_szAppName, MB_OK);

#endif

      return;

    }

    pmalloc->Free(pv);

    pmalloc->Release();

}


WINHLPRS

These topics contain sample code and header files that create a common dialog, create a window class, and write variables to a stream. For information on compiling and building the samples, see MAKEFILE (WINHLPRS Sample).


MAKEFILE  (WINHLPRS Sample)

#+---------------------------------------------------------------------------

#

#  Microsoft Windows

#  Copyright (C) Microsoft Corporation, 1994.

#

#  File:        makefile

#

#----------------------------------------------------------------------------

!include <$(MSTOOLS)\samples\ole\include\olesampl.mak>

#

#       builds the WINHLPRS.LIB library

#

#       used by MFract and DFView

#

OLEFLAGS = -I ..\idl

all: winhlprs.lib

clean:

    -del *.lib

    -del *.obj

cwindow.obj: cwindow.cxx cwindow.h

    $(cc) $(cvars) $(cflags) $(UFLAGS) $(cdebug) $(OLEFLAGS) cwindow.cxx

cdialog.obj: cdialog.cxx cdialog.h

    $(cc) $(cvars) $(cflags) $(UFLAGS) $(cdebug) $(OLEFLAGS) cdialog.cxx

strmhelp.obj: strmhelp.cxx strmhelp.h

    $(cc) $(cvars) $(cflags) $(UFLAGS) $(cdebug) $(OLEFLAGS) strmhelp.cxx

winhlprs.lib: cwindow.obj cdialog.obj strmhelp.obj

    lib -out:winhlprs.lib cwindow.obj cdialog.obj strmhelp.obj


CDIALOG.H  (WINHLPRS Sample)

//+---------------------------------------------------------------------------

//

//  Microsoft Windows

//  Copyright (C) Microsoft Corporation, 1992 - 1994.

//

//  File:       cdialog.h

//

//  Contents:   definition for common dialog functionality

//

//  Classes:    CHlprDialog (pure virtual class)

//

//  Functions:  DialogProc

//

//  History:    4-12-94   stevebl   Created

//

//----------------------------------------------------------------------------

#ifndef __CDIALOG_H__

#define __CDIALOG_H__

#ifdef __cplusplus

extern "C" {

#endif

BOOL CALLBACK DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);

#ifdef __cplusplus

}

//+---------------------------------------------------------------------------

//

//  Class:      CHlprDialog

//

//  Purpose:    virtual base class for wrapping Windows' dialog functionality

//

//  Interface:  ShowDialog -- analagous to the Windows DialogBox function

//              DialogProc -- pure virtual DialogProc for the dialog box

//              ~CHlprDialog   -- destructor

//

//  History:    4-12-94   stevebl   Created

//

//  Notes:      This class allows a dialog box to be cleanly wrapped in

//              a c++ class.  Specifically, it provides a way for a c++ class

//              to use one of its methods as a DialogProc, giving it a "this"

//              pointer and allowing it to have direct access to all of its

//              private members.

//

//----------------------------------------------------------------------------

class CHlprDialog

{

public:

    virtual int ShowDialog(HINSTANCE hinst, LPCTSTR lpszTemplate, HWND hwndOwner);

    virtual BOOL DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) = 0;

    virtual ~CHlprDialog(){};

protected:

    HINSTANCE _hInstance;

};

#endif //__cplusplus

#endif //__CDIALOG_H__


CDIALOG.CXX  (WINHLPRS Sample)

//+---------------------------------------------------------------------------

//

//  Microsoft Windows

//  Copyright (C) Microsoft Corporation, 1992 - 1994.

//

//  File:       dialog.cxx

//

//  Contents:

//

//  Classes:    CHlprDialog

//

//  Functions:  DialogProc

//

//  History:    4-12-94   stevebl   Created

//

//----------------------------------------------------------------------------

#include <windows.h>

#include "cdialog.h"

//+---------------------------------------------------------------------------

//

//  Member:     CHlprDialog::ShowDialog

//

//  Synopsis:   Creates the dialog so that it's DialogProc member function can

//              be invoked.

//

//  Arguments:  [hinst]        - handle of the application instance

//              [lpszTemplate] - identifies the dialog box template

//              [hwndOwner]    - handle of the owner window

//

//  Returns:    return value from the dialog box

//

//  History:    4-12-94   stevebl   Created

//

//  Notes:      The dialog box object exists until deleted by the caller.

//              It can be shown any number of times.

//

//              This function is analgous to Windows' DialogBox function.  The

//              main difference being that you don't specify a DialogProc;

//              you override the pure virtal function CHlprDialog::DialogProc.

//

//----------------------------------------------------------------------------

int CHlprDialog::ShowDialog(HINSTANCE hinst, LPCTSTR lpszTemplate, HWND hwndOwner)

{

    _hInstance = hinst;

    return(DialogBoxParam(hinst, lpszTemplate, hwndOwner, (DLGPROC)::DialogProc, (long)this));

}

//+---------------------------------------------------------------------------

//

//  Function:   DialogProc

//

//  Synopsis:   Common DialogProc used by all CHlprDialog class objects.

//

//  Arguments:  [hwndDlg] - handle of dialog box

//              [uMsg]    - message

//              [wParam]  - first message parameter

//              [lParam]  - second message parameter

//

//  Returns:    response from the CHlprDialog::DialogProc method

//

//  History:    4-12-94   stevebl   Created

//

//  Notes:      This procedure is the DialogProc registered for all dialogs

//              created with the CHlprDialog class.  It uses the parameter

//              passed with the WM_INITDIALOG message to identify the dialog

//              classes' "this" pointer which it then stores in the window

//              structure's GWL_USERDATA field.  All subsequent messages

//              can then be forwarded on to the correct dialog class's

//              DialogProc method by using the pointer stored in the

//              GWL_USERDATA field.

//

//----------------------------------------------------------------------------

BOOL CALLBACK DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)

{

    CHlprDialog * pdlg;

    switch (uMsg)

    {

    case WM_INITDIALOG:

        // This message is how we identify the dialog object.

        // get a pointer to the window class object

        pdlg = (CHlprDialog *) lParam;

        // set its USERDATA word to point to the class object

        SetWindowLong(hwndDlg, GWL_USERDATA, (long) pdlg);

        break;

    default:

        // get a pointer to the window class object

        pdlg = (CHlprDialog *) GetWindowLong(hwndDlg, GWL_USERDATA);

        break;

    }

    // and call its message proc method

    if (pdlg != (CHlprDialog *) 0)

    {

        return(pdlg->DialogProc(hwndDlg, uMsg, wParam, lParam));

    }

    else

    {

        return(FALSE);

    }

}


CWINDOW.H  (WINHLPRS Sample)

//+---------------------------------------------------------------------------

//

//  Microsoft Windows

//  Copyright (C) Microsoft Corporation, 1992 - 1994.

//

//  File:       cwindow.h

//

//  Contents:   definition of a virtual window class

//

//  Classes:    CHlprWindow

//

//  Functions:  WindowProc

//

//  History:    4-12-94   stevebl   Created

//

//----------------------------------------------------------------------------

#ifndef __CWINDOW_H__

#define __CWINDOW_H__

#include <windows.h>

#ifdef __cplusplus

extern "C" {

#endif

LRESULT CALLBACK WindowProc(

    HWND hwnd,

    UINT uMsg,

    WPARAM wParam,

    LPARAM lParam);

#ifdef __cplusplus

}

//+---------------------------------------------------------------------------

//

//  Class:      CHlprWindow

//

//  Purpose:    virtual base class for wrapping a window

//

//  Interface:  Create     -- analagous to Windows' CreateWindow function

//              WindowProc -- pure virtual WindowProc for the window

//              ~CHlprWindow   -- destructor

//              CHlprWindow    -- constructor

//

//  History:    4-12-94   stevebl   Created

//

//  Notes:      This class allows a window to be cleanly wrapped in a

//              c++ class.  Specifically, it provides a way for a c++ class

//              to use one of its methods as a WindowProc, giving it a "this"

//              pointer and allowing it to have direct access to all of its

//              private members.

//

//----------------------------------------------------------------------------

class CHlprWindow

{

public:

    HWND Create(

        LPCTSTR lpszClassName,

        LPCTSTR lpszWindowName,

        DWORD dwStyle,

        int x,

        int y,

        int nWidth,

        int nHeight,

        HWND hwndParent,

        HMENU hmenu,

        HINSTANCE hinst);

    virtual LRESULT WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam) = 0;

    virtual ~CHlprWindow(){};

    HWND GetHwnd(void)

    {

        return(_hwnd);

    }

    CHlprWindow()

    {

        _hwnd = NULL;

        _hInstance = NULL;

    };

protected:

friend LRESULT CALLBACK ::WindowProc(

    HWND hwnd,

    UINT uMsg,

    WPARAM wParam,

    LPARAM lParam);

    HWND _hwnd;

    HINSTANCE _hInstance;

};

#endif

#endif //__CWINDOW_H__


CWINDOW.CXX  (WINHLPRS Sample)

//+---------------------------------------------------------------------------

//

//  Microsoft Windows

//  Copyright (C) Microsoft Corporation, 1992 - 1994.

//

//  File:       cwindow.cxx

//

//  Contents:   implementation for a window class

//

//  Classes:    CHlprWindow

//

//  Functions:  WindowProc

//

//  History:    4-12-94   stevebl   Created

//

//----------------------------------------------------------------------------

#include "cwindow.h"

//+---------------------------------------------------------------------------

//

//  Member:     CHlprWindow::Create

//

//  Synopsis:   Special version of CreateWindow.

//

//  Arguments:  [lpszClassName]  - address of registered class name

//              [lpszWindowName] - address of window name

//              [dwStyle]        - window style

//              [x]              - horizontal position of window

//              [y]              - vertical position of window

//              [nWidth]         - window width

//              [nHeight]        - window height

//              [hwndParent]     - handle of parent or owner window

//              [hmenu]          - handle of menu, or child window identifier

//              [hinst]          - handle of application instance

//

//  Returns:    HWND of the created window

//

//  Modifies:   _hwnd, _hInstance

//

//  History:    4-12-94   stevebl   Created

//

//  Notes:      The window class must have been previously registered (as

//              is normal Windows procedure) and the callback function

//              must have been registered as ::WindowProc.  ::WindowProc will

//              then forward all messages on to the CHlprWindow::WindowProc

//              method, allowing the window to directly access class members

//              (i.e. giving the WindowProc access to the "this" pointer).

//

//----------------------------------------------------------------------------

HWND CHlprWindow::Create(

    LPCTSTR lpszClassName,

    LPCTSTR lpszWindowName,

    DWORD dwStyle,

    int x,

    int y,

    int nWidth,

    int nHeight,

    HWND hwndParent,

    HMENU hmenu,

    HINSTANCE hinst)

{

    _hInstance = hinst;

    return(_hwnd =

        CreateWindow(

            lpszClassName,

            lpszWindowName,

            dwStyle,

            x,

            y,

            nWidth,

            nHeight,

            hwndParent,

            hmenu,

            hinst,

            this));

}

//+---------------------------------------------------------------------------

//

//  Function:   WindowProc

//

//  Synopsis:   Standard WindowProc that forwards Windows messages on to the

//              CHlprWindow::WindowProc method.

//

//  Arguments:  [hwnd]   - window handle

//              [uMsg]   - message

//              [wParam] - first message parameter

//              [lParam] - second message parameter

//

//  History:    4-12-94   stevebl   Created

//

//  Notes:      This Window procedure expects that it will receive a "this"

//              pointer as the lpCreateParams member passed as part of the

//              WM_CREATE message.  It saves the "this" pointer in the

//              GWL_USERDATA field of the window structure.

//

//----------------------------------------------------------------------------

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)

{

    CHlprWindow * pw;

    switch (uMsg)

    {

    case WM_CREATE:

        // Since this is the first time that we can get ahold of

        // a pointer to the window class object, all messages that might

        // have been sent before this are never seen by the Windows object

        // and only get passed on to te DefWindowProc

        // get a pointer to the window class object

        pw = (CHlprWindow *) ((CREATESTRUCT *)lParam)->lpCreateParams;

        // set its USERDATA DWORD to point to the class object

        SetWindowLong(hwnd, GWL_USERDATA, (long) pw);

        // Set it's protected _hwnd member variable to ensure that

        // member functions have access to the correct window handle.

        pw->_hwnd = hwnd;

        break;

    case WM_DESTROY:

        // This is our signal to destroy the window class object.

        pw = (CHlprWindow *) GetWindowLong(hwnd, GWL_USERDATA);

        SetWindowLong(hwnd, GWL_USERDATA, 0);

        delete pw;

        pw = (CHlprWindow *) 0;

        break;

    default:

        // get a pointer to the window class object

        pw = (CHlprWindow *) GetWindowLong(hwnd, GWL_USERDATA);

        break;

    }

    // and call its message proc method

    if (pw != (CHlprWindow *) 0)

    {

        return(pw->WindowProc(uMsg, wParam, lParam));

    }

    else

    {

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

    }

}


STRMHELP.H  (WINHLPRS Sample)

//+---------------------------------------------------------------------------

//

//  Microsoft Windows

//  Copyright (C) Microsoft Corporation, 1992 - 1994.

//

//  File:       strmhelp.h

//

//  Contents:   Routines for writting variables to a stream in an

//              architecture independent manner.

//

//  Classes:

//

//  Functions:  WriteDouble

//              ReadDouble

//              SizeDouble

//

//  History:    4-26-94   stevebl   Created

//

//----------------------------------------------------------------------------

#ifndef __STRMHELP_H__

#define __STRMHELP_H__

#ifdef __cplusplus

extern "C" {

#endif

DWORD SizeDouble(void);

HRESULT WriteDouble(IStream * pstm, double d, ULONG FAR * pcbWritten);

HRESULT ReadDouble(IStream * pstm, double * pd, ULONG FAR * pcbRead);

#ifdef __cplusplus

}

#endif

#endif //__STRMHELP_H__


STRMHELP.CXX  (WINHLPRS Sample)

//+---------------------------------------------------------------------------

//

//  Microsoft Windows

//  Copyright (C) Microsoft Corporation, 1992 - 1994.

//

//  File:       strmhelp.cxx

//

//  Contents:   Routines for writting variables to a stream in an

//              architecture independent manner.

//

//  Classes:

//

//  Functions:  WriteDouble

//              ReadDouble

//              SizeDouble

//

//  History:    4-26-94   stevebl   Created

//

//----------------------------------------------------------------------------

#include <windows.h>

#include <ole2.h>

#include "strmhelp.h"

#include <stdio.h>

#define MAX_SIZE 128

//+---------------------------------------------------------------------------

//

//  Function:   SizeDouble

//

//  Synopsis:   returns the maximum number of bytes that WriteDouble will

//              take to write a double to an IStream

//

//  Arguments:  none

//

//  Returns:    maximum number of bytes needed to write a double to an IStream

//

//  History:    4-26-94   stevebl   Created

//

//----------------------------------------------------------------------------

DWORD SizeDouble(void)

{

    return(MAX_SIZE);

}

//+---------------------------------------------------------------------------

//

//  Function:   WriteDouble

//

//  Synopsis:   rrites a double to an OLE stream in a machine independent manner

//

//  Arguments:  [pstm]       - pointer to an IStream

//              [d]          - the double to be written

//              [pcbWritten] - pointer to the number of bytes actually written

//                             (may be NULL)

//

//  Returns:    same return values as IStream::Write

//

//  History:    4-26-94   stevebl   Created

//

//----------------------------------------------------------------------------

HRESULT WriteDouble(IStream * pstm, double d, ULONG FAR * pcbWritten)

{

    char szTemp[MAX_SIZE];

    sprintf(szTemp,"%.100lg", d);

    WORD cch = strlen(szTemp);

    return(pstm->Write(szTemp, cch + 1, pcbWritten));

}

//+---------------------------------------------------------------------------

//

//  Function:   ReadDouble

//

//  Synopsis:   reads a double from an OLE stream in a machine independent

//              manner

//

//  Arguments:  [pstm]    - pointer to an IStream

//              [pd]      - pointer to the double to be read

//              [pcbRead] - pointer to the number of bytes actually read

//                          (may be NULL)

//

//  Returns:    same return values as IStream::Read

//

//  History:    4-26-94   stevebl   Created

//

//----------------------------------------------------------------------------

HRESULT ReadDouble(IStream * pstm, double * pd, ULONG FAR * pcbRead)

{

    HRESULT hr;

    char szTemp[MAX_SIZE];

    ULONG cbRead;

    DWORD cch = 0;

    do

    {

        hr = pstm->Read(&szTemp[cch], sizeof(char), &cbRead);

        if (pcbRead && SUCCEEDED(hr))

        {

            pcbRead += cbRead;

        }

    } while (SUCCEEDED(hr) && szTemp[cch++]);

    if (SUCCEEDED(hr))

    {

        sscanf(szTemp, "%lf",pd);

    }

    return(hr);

}


WRAPUI

This sample demonstrates an implementation of WRAPUI. For information on compiling and building the sample, see MAKEFILE (WRAPUI Sample).


MAKEFILE  (WRAPUI Sample)

##########################################################################

#

# Makefile for OUTLUI.DLL

#

# Usage:    NMAKE           (builds DEBUG library)

#    or:    NMAKE RELEASE=1 (builds RELEASE library -- no debug symbols)

#

# Environment variables:

#       DEVROOT_DIR=<path>  (root dir for sample code development)

#

##########################################################################

!include <$(MSTOOLS)\samples\ole\include\olesampl.mak>

!ifndef LANG

LANG=USA

!endif

!ifndef LIBRARY

LIBRARY=wrapui

!endif

RESOURCE=res

all: $(LIBRARY).dll

# ----------------------------------------------------------------------------

#                      O B J E C T   F I L E   L I S T

# ----------------------------------------------------------------------------

UI_COBJS = busy.obj     \

           common.obj   \

           convert.obj  \

           dballoc.obj  \

           dbgutil.obj  \

           dllfuncs.obj \

           drawicon.obj \

           geticon.obj  \

           hatch.obj    \

           icon.obj     \

           iconbox.obj  \

           insobj.obj   \

           links.obj    \

           msgfiltr.obj \

           enumfetc.obj \

           enumstat.obj \

           objfdbk.obj  \

           ole2ui.obj   \

           olestd.obj   \

           targtdev.obj \

           oleutl.obj   \

           pastespl.obj \

           regdb.obj    \

           resimage.obj \

           stdpal.obj   \

           suminfo.obj  \

           utility.obj

PRECOMPOBJ=precomp.obj

PRECOMP=precomp.pch

# ----------------------------------------------------------------------------

#                       R E S O U R C E   L I S T

# ----------------------------------------------------------------------------

RES =      \

           busy.h                           \

           common.h                         \

           convert.h                        \

           edlinks.h                        \

           geticon.h                        \

           icon.h                           \

           iconbox.h                        \

           insobj.h                         \

           msgfiltr.h                       \

           enumfetc.h                       \

           ole2ui.h                         \

           pastespl.h                       \

           resimage.h                       \

           $(RESOURCE)\STATIC\default.ico   \

           $(RESOURCE)\STATIC\bang.ico      \

           $(RESOURCE)\STATIC\egares.bmp    \

           $(RESOURCE)\STATIC\hivgares.bmp  \

           $(RESOURCE)\STATIC\vgares.bmp    \

           $(RESOURCE)\$(LANG)\strings.rc   \

           $(RESOURCE)\$(LANG)\busy.dlg     \

           $(RESOURCE)\$(LANG)\convert.dlg  \

           $(RESOURCE)\$(LANG)\fileopen.dlg \

           $(RESOURCE)\$(LANG)\icon.dlg     \

           $(RESOURCE)\$(LANG)\insobj.dlg   \

           $(RESOURCE)\$(LANG)\links.dlg    \

           $(RESOURCE)\$(LANG)\pastespl.dlg \

           $(RESOURCE)\$(LANG)\prompt.dlg   \

           $(RESOURCE)\ole2ui.rcv   \

           $(RESOURCE)\$(LANG)\verlocal.h

# ----------------------------------------------------------------------------

#                 D E B U G   M A K E   P A R A M E T E R S

# ----------------------------------------------------------------------------

OLE_FLAGS = /DDLL_VER /D_DLL /DOLE2ANSI /DFLAT

!ifndef NO_DEBUG

OLE_FLAGS = $(OLE_FLAGS) /DDBG /D_DEBUG /D_DEBUGTRACE=0 /DOLE2SHIP

!endif

LANG      = $(LANG)

#select language for version resource if localized version

!if ("$(LANG)"!="USA") && ("$(LANG)"!="usa")

RFLAGS=$(RFLAGS) -D VER_LOC

!endif

.SUFFIXES: .c .asm .obj .res .rc .def .bmp .ico .exe .dll .cod .str

!include "depend"

# ----------------------------------------------------------------------------

#                     I N F E R E N C E   R U L E S

# ----------------------------------------------------------------------------

# compile C file without precompiled headers into object directory\NOPC

# dont compile c files etc for lcoalized builds.

.c.obj:

    @echo Compiling $(@B).c

    $(cc) $(cflags) $(cvars) $(cdebug) $(OLE_FLAGS) -Yuole2ui.h -Fpprecomp.pch $(@B).c

.rc.res:

    @echo Resource Compiling $(@B).res

    $(rc) -I $(RESOURCE)\$(LANG);$(RESOURCE)\static;$(RESOURCE) -FO $(@B).res -R $(RFLAGS) $(@B).rc

.c.cod:

    @echo Making $(@B).cod

    $(cc) $(cflags) $(cvars) $(cdebug) $(OLE_FLAGS) -f- -Fc $(@B).c

# ----------------------------------------------------------------------------

#                        G O A L   T A R G E T S

# ----------------------------------------------------------------------------

precomp.pch: precomp.c ole2ui.h

    $(cc) $(cflags) $(cvars) $(cdebug) $(OLE_FLAGS) -Fpprecomp.pch -Ycole2ui.h precomp.c

suminfo.obj: suminfo.cpp suminfo.h wn_dos.h

    $(cc) $(cflags) $(cvars) $(cdebug) $(OLE_FLAGS) $(@B).cpp

dballoc.obj: dballoc.cpp dballoc.h

    $(cc) $(cflags) $(cvars) $(cdebug) $(OLE_FLAGS) $(@B).cpp

ole2ui.res: ole2ui.rc $(RES)

ole2ui.rc : $(RESOURCE)\$(LANG)\strings.rc

#

# Build .LIB static library

#

$(LIBRARY).dll: ole2ui.def $(PRECOMPOBJS) $(UI_COBJS) ole2ui.res

    $(implib)  -out:$*.lib -def:ole2ui.def -machine:$(CPU) $(UI_COBJS) $(PRECOMPOBJ)

    $(link) $(dlllflags) $(linkdebug) $*.exp $(UI_COBJS) $(PRECOMPOBJ) ole2ui.res -out:$*.dll -map:$*.map $(olelibsdll) advapi32.lib shell32.lib ole2ansi.lib

clean:

    -del *.obj

    -del *.dll

    -del *.res

    -del *.lib

    -del *.exp

    -del *.pch

    -del *.map


DEPEND  (WRAPUI Sample)

busy.obj : $(PRECOMP) \

        ole2ui.h olestd.h common.h utility.h busy.h

common.obj : $(PRECOMP) \

        ole2ui.h olestd.h common.h utility.h

convert.obj : $(PRECOMP) \

        ole2ui.h olestd.h common.h utility.h geticon.h regdb.h convert.h

dbgutil.obj : $(PRECOMP) \

        ole2ui.h olestd.h

dllfuncs.obj : $(PRECOMP) \

        ole2ui.h olestd.h common.h

drawicon.obj : $(PRECOMP) \

        ole2ui.h olestd.h common.h utility.h geticon.h

enumfetc.obj : $(PRECOMP) \

        ole2ui.h olestd.h enumfetc.h

enumstat.obj : $(PRECOMP) \

        ole2ui.h olestd.h

geticon.obj : $(PRECOMP) \

        ole2ui.h olestd.h common.h utility.h

hatch.obj : $(PRECOMP) \

        ole2ui.h olestd.h

icon.obj : $(PRECOMP) \

        ole2ui.h olestd.h common.h utility.h icon.h geticon.h

iconbox.obj : $(PRECOMP) \

        ole2ui.h olestd.h iconbox.h

insobj.obj : $(PRECOMP) \

        ole2ui.h olestd.h common.h utility.h icon.h insobj.h resimage.h  \

        iconbox.h geticon.h

links.obj : $(PRECOMP) \

        ole2ui.h olestd.h common.h edlinks.h utility.h

msgfiltr.obj : $(PRECOMP) \

        ole2ui.h olestd.h msgfiltr.h

objfdbk.obj : $(PRECOMP) \

        ole2ui.h olestd.h

ole2ui.obj : $(PRECOMP) \

        ole2ui.h olestd.h common.h utility.h resimage.h iconbox.h

olestd.obj : $(PRECOMP) \

        ole2ui.h olestd.h regdb.h geticon.h common.h

oleutl.obj : $(PRECOMP) \

        ole2ui.h olestd.h

pastespl.obj : $(PRECOMP) \

        ole2ui.h olestd.h pastespl.h common.h utility.h resimage.h iconbox.h  \

        geticon.h icon.h regdb.h

precomp.obj : $(PRECOMP) \

        ole2ui.h olestd.h

regdb.obj : $(PRECOMP) \

        ole2ui.h olestd.h common.h

resimage.obj : $(PRECOMP) \

        ole2ui.h olestd.h resimage.h

stdpal.obj : $(PRECOMP) \

        stdpal.h

targtdev.obj : $(PRECOMP) \

        ole2ui.h olestd.h

template.obj : $(PRECOMP) \

        ole2ui.h olestd.h common.h <FILE>.h

utility.obj : $(PRECOMP) \

        ole2ui.h olestd.h common.h utility.h geticon.h


BUSY.H  (WRAPUI Sample)

/*

 * BUSY.H

 *

 * Internal definitions, structures, and function prototypes for the

 * OLE 2.0 UI Busy dialog.

 *

 * Copyright (c)1992 Microsoft Corporation, All Right Reserved

 */

#ifndef _BUSY_H_

#define _BUSY_H_

//Internally used structure

typedef struct tagBUSY

{

//Keep this item first as the Standard* functions depend on it here.

LPOLEUIBUSY     lpOBZ;       //Original structure passed.

/*

 * What we store extra in this structure besides the original caller's

 * pointer are those fields that we need to modify during the life of

 * the dialog or that we don't want to change in the original structure

 * until the user presses OK.

 */

DWORD               dwFlags;                // Flags passed in

HWND                hWndBlocked;            // HWND of app which is blocking

} BUSY, *PBUSY, FAR *LPBUSY;

// Internal function prototypes

BOOL    GetTaskInfo(HWND hWnd, HTASK htask, LPSTR FAR* lplpszTaskName, LPSTR FAR*lplpszWindowName, HWND FAR*lphWnd);

void    BuildBusyDialogString(HWND, DWORD, int, LPSTR, LPSTR);

BOOL CALLBACK EXPORT BusyDialogProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam);

void    BusyCleanup(HWND hDlg);

BOOL    FBusyInit(HWND hDlg, WPARAM wParam, LPARAM lParam);

BOOL    InitEnumeration(void);

void    UnInitEnumeration(void);

StartTaskManager(void);

void    MakeWindowActive(HWND hWndSwitchTo);

#endif //_BUSY_H_


BUSY.C  (WRAPUI Sample)

/*

 * BUSY.C

 *

 * Implements the OleUIBusy function which invokes the "Server Busy"

 * dialog.

 *

 * Copyright (c)1992 Microsoft Corporation, All Right Reserved

 */

#define STRICT  1

#include "ole2ui.h"

#include "common.h"

#include "utility.h"

#include "busy.h"

#include <ctype.h> // for tolower() and toupper()

#if !defined( WIN32 )

#include <toolhelp.h>

#endif

/*

 * OleUIBusy

 *

 * Purpose:

 *  Invokes the standard OLE "Server Busy" dialog box which

 *  notifies the user that the server application is not receiving

 *  messages.  The dialog then asks the user to either cancel

 *  the operation, switch to the task which is blocked, or continue

 *  waiting.

 *

 * Parameters:

 *  lpBZ            LPOLEUIBUSY pointing to the in-out structure

 *                  for this dialog.

 *

 * Return Value:

 *              OLEUI_BZERR_HTASKINVALID  : Error

 *              OLEUI_BZ_SWITCHTOSELECTED : Success, user selected "switch to"

 *              OLEUI_BZ_RETRYSELECTED    : Success, user selected "retry"

 *              OLEUI_CANCEL              : Success, user selected "cancel"

 */

STDAPI_(UINT) OleUIBusy(LPOLEUIBUSY lpOBZ)

{

UINT        uRet = 0;

HGLOBAL     hMemDlg=NULL;

#if !defined( WIN32 )

// BUGBUG32:    this is not yet ported to NT

uRet=UStandardValidation((LPOLEUISTANDARD)lpOBZ, sizeof(OLEUIBUSY)

 , &hMemDlg);

// Error out if the standard validation failed

if (OLEUI_SUCCESS!=uRet)

return uRet;

// Validate HTASK

if (!IsTask(lpOBZ->hTask))

uRet = OLEUI_BZERR_HTASKINVALID;

// Error out if our secondary validation failed

if (OLEUI_ERR_STANDARDMIN <= uRet)

{

if (NULL!=hMemDlg)

FreeResource(hMemDlg);

return uRet;

}

// Invoke the dialog.

uRet=UStandardInvocation(BusyDialogProc, (LPOLEUISTANDARD)lpOBZ,

 hMemDlg, MAKEINTRESOURCE(IDD_BUSY));

#endif

return uRet;

}

/*

 * BusyDialogProc

 *

 * Purpose:

 *  Implements the OLE Busy dialog as invoked through the OleUIBusy function.

 *

 * Parameters:

 *  Standard

 *

 * Return Value:

 *  Standard

 *

 */

BOOL CALLBACK EXPORT BusyDialogProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)

{

LPBUSY         lpBZ;

UINT           uRet = 0;

//Declare Win16/Win32 compatible WM_COMMAND parameters.

COMMANDPARAMS(wID, wCode, hWndMsg);

//This will fail under WM_INITDIALOG, where we allocate it.

lpBZ=(LPBUSY)LpvStandardEntry(hDlg, iMsg, wParam, lParam, &uRet);

//If the hook processed the message, we're done.

if (0!=uRet)

return (BOOL)uRet;

//Process the temination message

if (iMsg==uMsgEndDialog)

{

BusyCleanup(hDlg);

StandardCleanup(lpBZ, hDlg);

EndDialog(hDlg, wParam);

return TRUE;

}

// Process our special "close" message.  If we get this message,

// this means that the call got unblocked, so we need to

// return OLEUI_BZ_CALLUNBLOCKED to our calling app.

if (iMsg == uMsgCloseBusyDlg)

{

SendMessage(hDlg, uMsgEndDialog, OLEUI_BZ_CALLUNBLOCKED, 0L);

return TRUE;

}

switch (iMsg)

{

case WM_INITDIALOG:

FBusyInit(hDlg, wParam, lParam);

return TRUE;

case WM_ACTIVATEAPP:

{

/* try to bring down our Busy/NotResponding dialog as if

**    the user entered RETRY.

*/

BOOL fActive = (BOOL)wParam;

if (fActive) {

// If this is the app BUSY case, then bring down our

// dialog when switching BACK to our app

if (lpBZ && !(lpBZ->dwFlags & BZ_NOTRESPONDINGDIALOG))

SendMessage(hDlg,uMsgEndDialog,OLEUI_BZ_RETRYSELECTED,0L);

} else {

// If this is the app NOT RESPONDING case, then bring down

// our dialog when switching AWAY to another app

if (lpBZ && (lpBZ->dwFlags & BZ_NOTRESPONDINGDIALOG))

SendMessage(hDlg,uMsgEndDialog,OLEUI_BZ_RETRYSELECTED,0L);

}

return TRUE;

}

case WM_COMMAND:

switch (wID)

{

case IDBZ_SWITCHTO:

{

BOOL fNotRespondingDlg =

(BOOL)(lpBZ->dwFlags & BZ_NOTRESPONDINGDIALOG);

// If user selects "Switch To...", switch activation

// directly to the window which is causing the problem.

if (IsWindow(lpBZ->hWndBlocked))

MakeWindowActive(lpBZ->hWndBlocked);

else

StartTaskManager(); // Fail safe: Start Task Manager

// If this is the app not responding case, then we want

// to bring down the dialog when "SwitchTo" is selected.

// If the app is busy (RetryRejectedCall situation) then

// we do NOT want to bring down the dialog. this is

// the OLE2.0 user model design.

if (fNotRespondingDlg)

SendMessage(hDlg, uMsgEndDialog, OLEUI_BZ_SWITCHTOSELECTED, 0L);

break;

}

case IDBZ_RETRY:

SendMessage(hDlg, uMsgEndDialog, OLEUI_BZ_RETRYSELECTED, 0L);

break;

case IDCANCEL:

SendMessage(hDlg, uMsgEndDialog, OLEUI_CANCEL, 0L);

break;

}

break;

}

return FALSE;

}

/*

 * FBusyInit

 *

 * Purpose:

 *  WM_INITIDIALOG handler for the Busy dialog box.

 *

 * Parameters:

 *  hDlg            HWND of the dialog

 *  wParam          WPARAM of the message

 *  lParam          LPARAM of the message

 *

 * Return Value:

 *  BOOL            Value to return for WM_INITDIALOG.

 */

BOOL FBusyInit(HWND hDlg, WPARAM wParam, LPARAM lParam)

{

LPBUSY           lpBZ;

LPOLEUIBUSY      lpOBZ;

HFONT            hFont;

LPSTR            lpTaskName;

LPSTR            lpWindowName;

HICON            hIcon;

lpBZ=(LPBUSY)LpvStandardInit(hDlg, sizeof(OLEUIBUSY), TRUE, &hFont);

// PvStandardInit sent a termination to us already.

if (NULL==lpBZ)

return FALSE;

// Our original structure is in lParam

lpOBZ = (LPOLEUIBUSY)lParam;

// Copy it to our instance of the structure (in lpBZ)

lpBZ->lpOBZ=lpOBZ;

//Copy other information from lpOBZ that we might modify.

lpBZ->dwFlags = lpOBZ->dwFlags;

// Set default information

lpBZ->hWndBlocked = NULL;

// Insert HWND of our dialog into the address pointed to by

// lphWndDialog.  This can be used by the app who called

// OleUIBusy to bring down the dialog with uMsgCloseBusyDialog

if (lpOBZ->lphWndDialog &&

!IsBadWritePtr((VOID FAR *)lpOBZ->lphWndDialog, sizeof(HWND)))

{

*lpOBZ->lphWndDialog = hDlg;

}

// Update text in text box --

// GetTaskInfo will return two pointers, one to the task name

// (file name) and one to the window name.  We need to call

// OleStdFree on these when we're done with them.  We also

// get the HWND which is blocked in this call

//

// In the case where this call fails, a default message should already

// be present in the dialog template, so no action is needed

if (GetTaskInfo(hDlg, lpOBZ->hTask, &lpTaskName, &lpWindowName, &lpBZ->hWndBlocked))

{

// Build string to present to user, place in IDBZ_MESSAGE1 control

BuildBusyDialogString(hDlg, lpBZ->dwFlags, IDBZ_MESSAGE1, lpTaskName, lpWindowName);

OleStdFree(lpTaskName);

OleStdFree(lpWindowName);

}

// Update icon with the system "exclamation" icon

hIcon = LoadIcon(NULL, IDI_EXCLAMATION);

SendDlgItemMessage(hDlg, IDBZ_ICON, STM_SETICON, (WPARAM)hIcon, 0L);

// Disable/Enable controls

if ((lpBZ->dwFlags & BZ_DISABLECANCELBUTTON) ||

(lpBZ->dwFlags & BZ_NOTRESPONDINGDIALOG))              // Disable cancel for "not responding" dialog

EnableWindow(GetDlgItem(hDlg, IDCANCEL), FALSE);

if (lpBZ->dwFlags & BZ_DISABLESWITCHTOBUTTON)

EnableWindow(GetDlgItem(hDlg, IDBZ_SWITCHTO), FALSE);

if (lpBZ->dwFlags & BZ_DISABLERETRYBUTTON)

EnableWindow(GetDlgItem(hDlg, IDBZ_RETRY), FALSE);

// Call the hook with lCustData in lParam

UStandardHook((LPVOID)lpBZ, hDlg, WM_INITDIALOG, wParam, lpOBZ->lCustData);

// Update caption if lpszCaption was specified

if (lpBZ->lpOBZ->lpszCaption && !IsBadReadPtr(lpBZ->lpOBZ->lpszCaption, 1)

  && lpBZ->lpOBZ->lpszCaption[0] != '\0')

SetWindowText(hDlg, (LPSTR)lpBZ->lpOBZ->lpszCaption);

return TRUE;

}

/*

 * BuildBusyDialogString

 *

 * Purpose:

 *  Builds the string that will be displayed in the dialog from the

 *  task name and window name parameters.

 *

 * Parameters:

 *  hDlg            HWND of the dialog

 *  dwFlags         DWORD containing flags passed into dialog

 *  iControl        Control ID to place the text string

 *  lpTaskName      LPSTR pointing to name of task (e.g. C:\TEST\TEST.EXE)

 *  lpWindowName    LPSTR for name of window

 *

 * Caveats:

 *  The caller of this function MUST de-allocate the lpTaskName and

 *  lpWindowName pointers itself with OleStdFree

 *

 * Return Value:

 *  void

 */

void BuildBusyDialogString(HWND hDlg, DWORD dwFlags, int iControl, LPSTR lpTaskName, LPSTR lpWindowName)

{

LPSTR       pszT, psz1, psz2, psz3;

UINT        cch;

LPSTR       pszDot, pszSlash;

UINT        uiStringNum;

/*

 * We need scratch memory for loading the stringtable string,

 * the task name, and constructing the final string.  We therefore

 * allocate three buffers as large as the maximum message

 * length (512) plus the object type, guaranteeing that we have enough

 * in all cases.

 */

cch=512;

// Use OLE-supplied allocation

if ((pszT = OleStdMalloc((ULONG)(3*cch))) == NULL)

return;

psz1=pszT;

psz2=psz1+cch;

psz3=psz2+cch;

// Parse base name out of path name, use psz2 for the task

// name to display

_fstrcpy(psz2, lpTaskName);

pszDot = _fstrrchr(psz2, '.');

if (pszDot != NULL)

  *pszDot = '\0'; // Null terminate at the DOT

pszSlash = _fstrrchr(psz2, '\\'); // Find last backslash in path

if (pszSlash != NULL)

  psz2 = pszSlash + 1; // Nuke everything up to this point

#ifdef LOWERCASE_NAME

// Compile this with /DLOWERCASE_NAME if you want the lower-case

// module name to be displayed in the dialog rather than the

// all-caps name.

{

int i,l;

// Now, lowercase all letters except first one

l = _fstrlen(psz2);

for(i=0;i<l;i++)

  psz2[i] = tolower(psz2[i]);

psz2[0] = toupper(psz2[0]);

}

#endif

// Check size of lpWindowName.  We can reasonably fit about 80

// characters into the text control, so truncate more than 80 chars

if (_fstrlen(lpWindowName) > 80)

  lpWindowName[80] = '\0';

// Load the format string out of stringtable, choose a different

// string depending on what flags are passed in to the dialog

if (dwFlags & BZ_NOTRESPONDINGDIALOG)

uiStringNum = IDS_BZRESULTTEXTNOTRESPONDING;

else

uiStringNum = IDS_BZRESULTTEXTBUSY;

if (LoadString(ghInst, uiStringNum, psz1, cch) == 0)

  return;

// Build the string. The format string looks like this:

// "This action cannot be completed because the '%s' application

// (%s) is [busy | not responding]. Choose \"Switch To\" to activate '%s' and

// correct the problem."

wsprintf(psz3, psz1, (LPSTR)psz2, (LPSTR)lpWindowName, (LPSTR)psz2);

SetDlgItemText(hDlg, iControl, (LPSTR)psz3);

OleStdFree(pszT);

return;

}

/*

 * BusyCleanup

 *

 * Purpose:

 *  Performs busy-specific cleanup before termination.

 *

 * Parameters:

 *  hDlg            HWND of the dialog box so we can access controls.

 *

 * Return Value:

 *  None

 */

void BusyCleanup(HWND hDlg)

{

   return;

}

/*

 * GetTaskInfo()

 *

 * Purpose:  Gets information about the specified task and places the

 * module name, window name and top-level HWND for the task in the specified

 * pointers

 *

 * NOTE: The two string pointers allocated in this routine are

 * the responsibility of the CALLER to de-allocate.

 *

 * Parameters:

 *    hWnd             HWND who called this function

 *    htask            HTASK which we want to find out more info about

 *    lplpszTaskName   Location that the module name is returned

 *    lplpszWindowName Location where the window name is returned

 *

 */

BOOL GetTaskInfo(HWND hWnd, HTASK htask, LPSTR FAR* lplpszTaskName, LPSTR FAR*lplpszWindowName, HWND FAR*lphWnd)

{

BOOL        fRet = FALSE;

#if !defined( WIN32 )

TASKENTRY   te;

HINSTANCE   hinstToolHelp = NULL;

typedef BOOL (WINAPI* LPFNTASKFINDHANDLE) (TASKENTRY FAR*, HTASK);

LPFNTASKFINDHANDLE lpfnTaskFindHandle;

BOOL        fFoundTaskHandle = FALSE;

#endif

HWND        hwndNext;

LPSTR       lpszTN = NULL;

LPSTR       lpszWN = NULL;

HWND        hwndFind = NULL;

// Clear out return values in case of error

*lplpszTaskName = NULL;

*lplpszWindowName = NULL;

#if !defined( WIN32 )

te.dwSize = sizeof(TASKENTRY);

#if !defined( LINK_TOOLHELP )

// Load the TOOLHELP.DLL library module

hinstToolHelp = LoadLibrary("TOOLHELP.DLL");

if (hinstToolHelp > HINSTANCE_ERROR) {  /* loaded successfully */

// Retrieve the address of the TaskFindHandle function

lpfnTaskFindHandle = (LPFNTASKFINDHANDLE)

GetProcAddress(hinstToolHelp, "TaskFindHandle");

if (lpfnTaskFindHandle != NULL) {

// Call the TaskFindHandle function

fFoundTaskHandle=

(*lpfnTaskFindHandle) ((TASKENTRY FAR*)&te, (HTASK)htask);

}

FreeLibrary(hinstToolHelp);

}

#else

fFoundTaskHandle = TaskFindHandle((TASKENTRY FAR*)&te, htask);

#endif

if (fFoundTaskHandle)

#endif

{

// Now, enumerate top-level windows in system

hwndNext = GetWindow(hWnd, GW_HWNDFIRST);

while (hwndNext)

{

// See if we can find a non-owned top level window whose

// hInstance matches the one we just got passed.  If we find one,

// we can be fairly certain that this is the top-level window for

// the task which is blocked.

//

// REVIEW:  Will this filter hold true for InProcServer DLL-created

// windows?

//

if ((hwndNext != hWnd) &&

#if !defined( WIN32 )

(GetWindowWord(hwndNext, GWW_HINSTANCE) == (UINT)te.hInst) &&

#else

(GetWindowThreadProcessId(hwndNext,NULL) == (DWORD)htask) &&

#endif

(IsWindowVisible(hwndNext)) &&

!GetWindow(hwndNext, GW_OWNER))

{

// We found our window!  Alloc space for new strings

if ((lpszTN = OleStdMalloc(OLEUI_CCHPATHMAX)) == NULL)

return TRUE;  // continue task window enumeration

if ((lpszWN = OleStdMalloc(OLEUI_CCHPATHMAX)) == NULL)

return TRUE;  // continue task window enumeration

// We found the window we were looking for, copy info to

// local vars

GetWindowText(hwndNext, lpszWN, OLEUI_CCHPATHMAX);

#if !defined( WIN32 )

 LSTRCPYN(lpszTN, te.szModule, OLEUI_CCHPATHMAX);

#else

/* WIN32 NOTE: we are not able to get a module name

**    given a thread process id on WIN32. the best we

**    can do is use the window title as the module/app

**    name.

*/

 LSTRCPYN(lpszTN, lpszWN, OLEUI_CCHPATHMAX);

#endif

hwndFind = hwndNext;

fRet = TRUE;

goto OKDone;

}

hwndNext = GetWindow(hwndNext, GW_HWNDNEXT);

}

}

OKDone:

// OK, everything was successful. Set string pointers to point to

// our data.

*lplpszTaskName = lpszTN;

*lplpszWindowName = lpszWN;

*lphWnd = hwndFind;

return fRet;

}

/*

 * StartTaskManager()

 *

 * Purpose: Starts Task Manager.  Used to bring up task manager to

 * assist in switching to a given blocked task.

 *

 */

StartTaskManager()

{

WinExec("taskman.exe", SW_SHOW);

return TRUE;

}

/*

 * MakeWindowActive()

 *

 * Purpose: Makes specified window the active window.

 *

 */

void MakeWindowActive(HWND hWndSwitchTo)

{

// Move the new window to the top of the Z-order

SetWindowPos(hWndSwitchTo, HWND_TOP, 0, 0, 0, 0,

  SWP_NOSIZE | SWP_NOMOVE);

// If it's iconic, we need to restore it.

if (IsIconic(hWndSwitchTo))

ShowWindow(hWndSwitchTo, SW_RESTORE);

}


COMMON.H  (WRAPUI Sample)

/*

 * COMMON.H

 *

 * Structures and definitions applicable to all OLE 2.0 UI dialogs.

 *

 * Copyright (c)1992 Microsoft Corporation, All Right Reserved

 */

#ifndef _COMMON_H_

#define _COMMON_H_

//Macros to handle control message packing between Win16 and Win32

#ifdef WIN32

#ifndef COMMANDPARAMS

#define COMMANDPARAMS(wID, wCode, hWndMsg)                          \

UINT        wID     = LOWORD(wParam);                           \

UINT        wCode   = HIWORD(wParam);                           \

HWND        hWndMsg = (HWND)(UINT)lParam;

#endif  //COMMANDPARAMS

#ifndef SendCommand

#define SendCommand(hWnd, wID, wCode, hControl)                     \

SendMessage(hWnd, WM_COMMAND, MAKELONG(wID, wCode)      \

, (LPARAM)hControl)

#endif  //SendCommand

#ifndef SendSetSel

#define SendSetSel(hWnd,nStart,nEnd)                               \

            SendMessage(hWnd, EM_SETSEL, (WPARAM) nStart, (LPARAM) nEnd)

#endif  //SendSetSel

#else   //Start !WIN32

#ifndef COMMANDPARAMS

#define COMMANDPARAMS(wID, wCode, hWndMsg)                          \

UINT        wID     = LOWORD(wParam);                           \

UINT        wCode   = HIWORD(lParam);                           \

HWND        hWndMsg = (HWND)(UINT)lParam;

#endif  //COMMANDPARAMS

#ifndef SendCommand

#define SendCommand(hWnd, wID, wCode, hControl)                     \

SendMessage(hWnd, WM_COMMAND, wID                       \

, MAKELONG(hControl, wCode))

#endif  //SendCommand

#ifndef SendSetSel

#define SendSetSel(hWnd,nStart,nEnd)                               \

            SendMessage(hWnd, EM_SETSEL, 0, MAKELPARAM(nStart, nEnd))

#endif  //SendSetSel

#endif  //!WIN32

//Property labels used to store dialog structures and fonts

#define STRUCTUREPROP       "Structure"

#define FONTPROP            "Font"

/*

 * Standard structure for all dialogs.  This commonality lets us make

 * a single piece of code that will validate this entire structure and

 * perform any necessary initialization.

 */

typedef struct tagOLEUISTANDARD

{

//These IN fields are standard across all OLEUI dialog functions.

DWORD           cbStruct;       //Structure Size

DWORD           dwFlags;        //IN-OUT:  Flags

HWND            hWndOwner;      //Owning window

LPCSTR          lpszCaption;    //Dialog caption bar contents

LPFNOLEUIHOOK   lpfnHook;       //Hook callback

LPARAM          lCustData;      //Custom data to pass to hook

HINSTANCE       hInstance;      //Instance for customized template name

LPCSTR          lpszTemplate;   //Customized template name

HRSRC           hResource;      //Customized template handle

} OLEUISTANDARD, *POLEUISTANDARD, FAR *LPOLEUISTANDARD;

//Function prototypes

//COMMON.C

UINT  WINAPI  UStandardValidation(const LPOLEUISTANDARD, const UINT, const HGLOBAL FAR *);

UINT  WINAPI  UStandardInvocation(DLGPROC, LPOLEUISTANDARD, HGLOBAL, LPCSTR);

LPVOID WINAPI LpvStandardInit(HWND, UINT, BOOL, HFONT FAR *);

LPVOID WINAPI LpvStandardEntry(HWND, UINT, WPARAM, LPARAM, UINT FAR *);

UINT WINAPI   UStandardHook(LPVOID, HWND, UINT, WPARAM, LPARAM);

void WINAPI   StandardCleanup(LPVOID, HWND);

void WINAPI   StandardShowDlgItem(HWND hDlg, int idControl, int nCmdShow);

//DRAWICON.C

//Structure for label and source extraction from a metafile

typedef struct tagLABELEXTRACT

{

LPSTR       lpsz;

UINT        Index;      // index in lpsz (so we can retrieve 2+ lines)

DWORD       PrevIndex;  // index of last line (so we can mimic word wrap)

union

{

UINT    cch;        //Length of label for label extraction

UINT    iIcon;      //Index of icon in source extraction.

} u;

//For internal use in enum procs

BOOL        fFoundIconOnly;

BOOL        fFoundSource;

BOOL        fFoundIndex;

} LABELEXTRACT, FAR * LPLABELEXTRACT;

//Structure for extracting icons from a metafile (CreateIcon parameters)

typedef struct tagICONEXTRACT

{

HICON       hIcon;          //Icon created in the enumeration proc.

/*

 * Since we want to handle multitasking well we have the caller

 * of the enumeration proc instantiate these variables instead of

 * using statics in the enum proc (which would be bad).

 */

BOOL        fAND;

HGLOBAL     hMemAND;        //Enumeration proc allocates and copies

} ICONEXTRACT, FAR * LPICONEXTRACT;

//Structure to use to pass info to EnumMetafileDraw

typedef struct tagDRAWINFO

{

RECT     Rect;

BOOL     fIconOnly;

} DRAWINFO, FAR * LPDRAWINFO;

int CALLBACK EXPORT EnumMetafileIconDraw(HDC, HANDLETABLE FAR *, METARECORD FAR *, int, LPARAM);

int CALLBACK EXPORT EnumMetafileExtractLabel(HDC, HANDLETABLE FAR *, METARECORD FAR *, int, LPLABELEXTRACT);

int CALLBACK EXPORT EnumMetafileExtractIcon(HDC, HANDLETABLE FAR *, METARECORD FAR *, int, LPICONEXTRACT);

int CALLBACK EXPORT EnumMetafileExtractIconSource(HDC, HANDLETABLE FAR *, METARECORD FAR *, int, LPLABELEXTRACT);

//Shared globals:  our instance, registered messages used from all dialogs and clipboard

// formats used by the PasteSpecial dialog

extern HINSTANCE  ghInst;

extern UINT       uMsgHelp;

extern UINT       uMsgEndDialog;

extern UINT       uMsgBrowse;

extern UINT       uMsgChangeIcon;

extern UINT       uMsgFileOKString;

extern UINT       uMsgCloseBusyDlg;

extern UINT       cfObjectDescriptor;

extern UINT       cfLinkSrcDescriptor;

extern UINT       cfEmbedSource;

extern UINT       cfEmbeddedObject;

extern UINT       cfLinkSource;

extern UINT       cfOwnerLink;

extern UINT       cfFileName;

//Standard control identifiers

#define ID_NULL                         98

#endif //_COMMON_H_


COMMON.C  (WRAPUI Sample)

/*

 * COMMON.C

 *

 * Standardized (and centralized) pieces of each OLE2UI dialog function:

 *  UStandardValidation     Validates standard fields in each dialog structure

 *  UStandardInvocation     Invokes a dialog through DialogBoxIndirectParam

 *  LpvStandardInit         Common WM_INITDIALOG processing

 *  LpvStandardEntry        Common code to execute on dialog proc entry.

 *  FStandardHook           Centralized hook calling function.

 *  StandardCleanup         Common exit/cleanup code.

 *  OleUIShowDlgItem        Show-Enable/Hide-Disable dialog item

 *

 * Copyright (c)1992 Microsoft Corporation, All Right Reserved

 */

#define STRICT  1

#include "ole2ui.h"

#include "common.h"

#include "utility.h"

#include <malloc.h>

/*

 * UStandardValidation

 *

 * Purpose:

 *  Performs validation on the standard pieces of any dialog structure,

 *  that is, the fields defined in the OLEUISTANDARD structure.

 *

 * Parameters:

 *  lpUI            const LPOLEUISTANDARD pointing to the shared data of

 *                  all structs.

 *  cbExpect        const UINT structure size desired by the caller.

 *  phDlgMem        const HGLOBAL FAR * in which to store a loaded customized

 *                  template, if one exists.

 *

 * Return Value:

 *  UINT            OLEUI_SUCCESS if all validation succeeded.  Otherwise

 *                  it will be one of the standard error codes.

 */

UINT WINAPI UStandardValidation(const LPOLEUISTANDARD lpUI, const UINT cbExpect

 , const HGLOBAL FAR *phMemDlg)

{

HRSRC       hRes=NULL;

HGLOBAL     hMem=NULL;

/*

 * 1.  Validate non-NULL pointer parameter.  Note:  We don't validate

 *     phDlg since it's not passed from an external source.

 */

if (NULL==lpUI)

return OLEUI_ERR_STRUCTURENULL;

//2.  Validate that the structure is readable and writable.

if (IsBadReadPtr(lpUI, cbExpect) || IsBadWritePtr(lpUI, cbExpect))

return OLEUI_ERR_STRUCTUREINVALID;

//3.  Validate the structure size

if (cbExpect!=lpUI->cbStruct)

return OLEUI_ERR_CBSTRUCTINCORRECT;

//4.  Validate owner-window handle.  NULL is considered valid.

if (NULL!=lpUI->hWndOwner && !IsWindow(lpUI->hWndOwner))

return OLEUI_ERR_HWNDOWNERINVALID;

//5.  Validate the dialog caption.  NULL is considered valid.

if (NULL!=lpUI->lpszCaption && IsBadReadPtr(lpUI->lpszCaption, 1))

return OLEUI_ERR_LPSZCAPTIONINVALID;

//6.  Validate the hook pointer.  NULL is considered valid.

if ((LPFNOLEUIHOOK)NULL!=lpUI->lpfnHook

&& IsBadCodePtr((FARPROC)lpUI->lpfnHook))

return OLEUI_ERR_LPFNHOOKINVALID;

/*

 * 7.  If hInstance is non-NULL, we have to also check lpszTemplate.

 *     Otherwise, lpszTemplate is not used and requires no validation.

 *     lpszTemplate cannot be NULL if used.

 */

if (NULL!=lpUI->hInstance)

{

//Best we can try is one character

if (NULL==lpUI->lpszTemplate || IsBadReadPtr(lpUI->lpszTemplate, 1))

return OLEUI_ERR_LPSZTEMPLATEINVALID;

hRes=FindResource(lpUI->hInstance, lpUI->lpszTemplate, RT_DIALOG);

//This is the only thing that catches invalid non-NULL hInstance

if (NULL==hRes)

return OLEUI_ERR_FINDTEMPLATEFAILURE;

hMem=LoadResource(lpUI->hInstance, hRes);

if (NULL==hMem)

return OLEUI_ERR_LOADTEMPLATEFAILURE;

}

//8.  If hResource is non-NULL, be sure we can lock it.

if (NULL!=lpUI->hResource)

{

if ((LPSTR)NULL==GlobalLock(lpUI->hResource))

return OLEUI_ERR_HRESOURCEINVALID;

GlobalUnlock(lpUI->hResource);

}

/*

 * Here we have hMem==NULL if we should use the standard template

 * or the one in lpUI->hResource.  If hMem is non-NULL, then we

 * loaded one from the calling application's resources which the

 * caller of this function has to free if it sees any other error.

 */

*(HGLOBAL FAR *)phMemDlg=hMem;

return OLEUI_SUCCESS;

}

/*

 * UStandardInvocation

 *

 * Purpose:

 *  Provides standard template loading and calling on DialogBoxIndirectParam

 *  for all the OLE UI dialogs.

 *

 * Parameters:

 *  lpDlgProc       DLGPROC of the dialog function.

 *  lpUI            LPOLEUISTANDARD containing the dialog structure.

 *  hMemDlg         HGLOBAL containing the dialog template.  If this

 *                  is NULL and lpUI->hResource is NULL, then we load

 *                  the standard template given the name in lpszStdTemplate

 *  lpszStdTemplate LPCSTR standard template to load if hMemDlg is NULL

 *                  and lpUI->hResource is NULL.

 *

 * Return Value:

 *  UINT            OLEUI_SUCCESS if all is well, otherwise and error

 *                  code.

 */

UINT WINAPI UStandardInvocation(DLGPROC lpDlgProc, LPOLEUISTANDARD lpUI

 , HGLOBAL hMemDlg, LPCSTR lpszStdTemplate)

{

HGLOBAL     hTemplate=hMemDlg;

HRSRC       hRes;

int         iRet;

//Make sure we have a template, then lock it down

if (NULL==hTemplate)

hTemplate=lpUI->hResource;

if (NULL==hTemplate)

{

hRes=FindResource(ghInst, lpszStdTemplate, RT_DIALOG);

if (NULL==hRes)

{

return OLEUI_ERR_FINDTEMPLATEFAILURE;

}

hTemplate=LoadResource(ghInst, hRes);

if (NULL==hTemplate)

{

return OLEUI_ERR_LOADTEMPLATEFAILURE;

}

}

/*

 * hTemplate has the template to use, so now we can invoke the dialog.

 * Since we have exported all of our dialog procedures using the

 * _export keyword, we do not need to call MakeProcInstance,

 * we can ue the dialog procedure address directly.

 */

iRet=DialogBoxIndirectParam(ghInst, hTemplate, lpUI->hWndOwner

, lpDlgProc, (LPARAM)lpUI);

/*

 * Cleanup the template if we explicitly loaded it.  Caller is

 * responsible for already loaded template resources.

 */

if (hTemplate!=lpUI->hResource)

FreeResource(hTemplate);

if (-1==iRet)

return OLEUI_ERR_DIALOGFAILURE;

//Return the code from EndDialog, generally OLEUI_OK or OLEUI_CANCEL

return (UINT)iRet;

}

/*

 * LpvStandardInit

 *

 * Purpose:

 *  Default actions for WM_INITDIALOG handling in the dialog, allocating

 *  a dialog-specific structure, setting that memory as a dialog property,

 *  and creating a small font if necessary setting that font as a property.

 *

 * Parameters:

 *  hDlg            HWND of the dialog

 *  cbStruct        UINT size of dialog-specific structure to allocate.

 *  fCreateFont     BOOL indicating if we need to create a small Helv

 *                  font for this dialog.

 *  phFont          HFONT FAR * in which to place a created font.  Can be

 *                  NULL if fCreateFont is FALSE.

 *

 * Return Value:

 *  LPVOID          Pointer to global memory allocated for the dialog.

 *                  The memory will have been set as a dialog property

 *                  using the STRUCTUREPROP label.

 */

LPVOID WINAPI LpvStandardInit(HWND hDlg, UINT cbStruct, BOOL fCreateFont, HFONT FAR * phFont)

{

LPVOID      lpv;

HFONT       hFont;

LOGFONT     lf;

HGLOBAL     gh;

//Must have at least sizeof(OLEUISTANDARD) bytes in cbStruct

if (sizeof(OLEUISTANDARD) > cbStruct || (fCreateFont && NULL==phFont))

{

PostMessage(hDlg, uMsgEndDialog, OLEUI_ERR_GLOBALMEMALLOC, 0L);

return NULL;

}

gh=GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT, cbStruct);

if (NULL==gh)

{

PostMessage(hDlg, uMsgEndDialog, OLEUI_ERR_GLOBALMEMALLOC, 0L);

return NULL;

}

lpv = GlobalLock(gh);

SetProp(hDlg, STRUCTUREPROP, gh);

if (fCreateFont) {

//Create the non-bold font for result and file texts.  We call

hFont=(HFONT)SendMessage(hDlg, WM_GETFONT, 0, 0L);

GetObject(hFont, sizeof(LOGFONT), &lf);

lf.lfWeight=FW_NORMAL;

//Attempt to create the font.  If this fails, then we return no font.

*phFont=CreateFontIndirect(&lf);

//If we couldn't create the font, we'll do with the default.

if (NULL!=*phFont)

SetProp(hDlg, FONTPROP, (HANDLE)*phFont);

}

return lpv;

}

/*

 * LpvStandardEntry

 *

 * Purpose:

 *  Retrieves the dialog's structure property and calls the hook

 *  as necessary.  This should be called on entry into all dialog

 *  procedures.

 *

 * Parameters:

 *  hDlg            HWND of the dialog

 *  iMsg            UINT message to the dialog

 *  wParam, lParam  WPARAM, LPARAM message parameters

 *  puHookResult    UINT FAR * in which this function stores the return value

 *                  from the hook if it is called.  If no hook is available,

 *                  this will be FALSE.

 *

 * Return Value:

 *  LPVOID          Pointer to the dialog's extra structure held in the

 *                  STRUCTUREPROP property.

 */

LPVOID WINAPI LpvStandardEntry(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam

  , UINT FAR * puHookResult)

{

LPVOID              lpv = NULL;

HGLOBAL             gh;

// This will fail under WM_INITDIALOG, where we allocate using StandardInit

gh = GetProp(hDlg, STRUCTUREPROP);

if (NULL!=puHookResult && NULL!=gh)

{

*puHookResult=0;

// gh was locked previously, lock and unlock to get lpv

lpv = GlobalLock(gh);

GlobalUnlock(gh);

//Call the hook for all messages except WM_INITDIALOG

if (NULL!=lpv && WM_INITDIALOG!=iMsg)

*puHookResult=UStandardHook(lpv, hDlg, iMsg, wParam, lParam);

}

return lpv;

}

/*

 * UStandardHook

 *

 * Purpose:

 *  Provides a generic hook calling function assuming that all private

 *  dialog structures have a far pointer to their assocated public

 *  structure as the first field, and that the first part of the public

 *  structure matches an OLEUISTANDARD.

 *

 * Parameters:

 *  pv              PVOID to the dialog structure.

 *  hDlg            HWND to send with the call to the hook.

 *  iMsg            UINT message to send to the hook.

 *  wParam, lParam  WPARAM, LPARAM message parameters

 *

 * Return Value:

 *  UINT            Return value from the hook, zero to indicate that

 *                  default action should occur,  nonzero to specify

 *                  that the hook did process the message.  In some

 *                  circumstances it will be important for the hook to

 *                  return a non-trivial non-zero value here, such as

 *                  a brush from WM_CTLCOLOR, in which case the caller

 *                  should return that value from the dialog procedure.

 */

UINT WINAPI UStandardHook(LPVOID lpv, HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)

{

LPOLEUISTANDARD     lpUI;

UINT                uRet=0;

lpUI=*((LPOLEUISTANDARD FAR *)lpv);

if (NULL!=lpUI && NULL!=lpUI->lpfnHook)

{

/*

 * In order for the hook to have the proper DS, they should be

 * compiling with -GA -GEs so and usin __export to get everything

 * set up properly.

 */

uRet=(*lpUI->lpfnHook)(hDlg, iMsg, wParam, lParam);

}

return uRet;

}

/*

 * StandardCleanup

 *

 * Purpose:

 *  Removes properties and reverses any other standard initiazation

 *  done through StandardSetup.

 *

 * Parameters:

 *  lpv             LPVOID containing the private dialog structure.

 *  hDlg            HWND of the dialog closing.

 *

 * Return Value:

 *  None

 */

void WINAPI StandardCleanup(LPVOID lpv, HWND hDlg)

{

HFONT       hFont;

HGLOBAL     gh;

hFont=(HFONT)GetProp(hDlg, FONTPROP);

if (NULL!=hFont)

DeleteObject(hFont);

RemoveProp(hDlg, FONTPROP);

gh = RemoveProp(hDlg, STRUCTUREPROP);

if (gh)

{

GlobalUnlock(gh);

GlobalFree(gh);

}

return;

}

/* StandardShowDlgItem

** -------------------

**    Show & Enable or Hide & Disable a dialog item as appropriate.

**    it is NOT sufficient to simply hide the item; it must be disabled

**    too or the keyboard accelerator still functions.

*/

void WINAPI StandardShowDlgItem(HWND hDlg, int idControl, int nCmdShow)

{

if (SW_HIDE == nCmdShow) {

ShowWindow(GetDlgItem(hDlg, idControl), SW_HIDE);

EnableWindow(GetDlgItem(hDlg, idControl), FALSE);

} else {

ShowWindow(GetDlgItem(hDlg, idControl), SW_SHOWNORMAL);

EnableWindow(GetDlgItem(hDlg, idControl), TRUE);

}

}


CONVERT.H  (WRAPUI Sample)

/*

 * CONVERT.H

 *

 * Internal definitions, structures, and function prototypes for the

 * OLE 2.0 UI Convert dialog.

 *

 * Copyright (c)1992 Microsoft Corporation, All Right Reserved

 */

#ifndef _CONVERT_H_

#define _CONVERT_H_

//Internally used structure

typedef struct tagCONVERT

{

//Keep this item first as the Standard* functions depend on it here.

LPOLEUICONVERT     lpOCV;       //Original structure passed.

/*

 * What we store extra in this structure besides the original caller's

 * pointer are those fields that we need to modify during the life of

 * the dialog but that we don't want to change in the original structure

 * until the user presses OK.

 */

DWORD               dwFlags;  // Flags passed in

HWND                hListVisible;  // listbox that is currently visible

HWND                hListInvisible;  // listbox that is currently hidden

CLSID               clsid;    // Class ID sent in to dialog: IN only

DWORD               dvAspect;

BOOL                fCustomIcon;

UINT                IconIndex;         // index (in exe) of current icon

LPSTR               lpszIconSource;    // path to current icon source

LPSTR               lpszCurrentObject;

LPSTR               lpszConvertDefault;

LPSTR               lpszActivateDefault;

} CONVERT, *PCONVERT, FAR *LPCONVERT;

//Internal function prototypes in CONVERT.C

BOOL CALLBACK EXPORT ConvertDialogProc(HWND, UINT, WPARAM, LPARAM);

BOOL            FConvertInit(HWND hDlg, WPARAM, LPARAM);

UINT            FPopulateListbox(HWND hListbox, CLSID cID);

BOOL            IsValidClassID(CLSID cID);

void            SetConvertResults(HWND, LPCONVERT);

UINT FillClassList(

CLSID clsid,

HWND hList,

HWND hListInvisible,

LPSTR FAR *lplpszCurrentClass,

BOOL fIsLinkedObject,

WORD wFormat,

UINT cClsidExclude,

LPCLSID lpClsidExclude);

BOOL            FormatIncluded(LPSTR szStringToSearch, UINT wFormat);

void            UpdateCVClassIcon(HWND hDlg, LPCONVERT lpCV, HWND hList);

void            SwapWindows(HWND, HWND, HWND);

void            ConvertCleanup(HWND hDlg, LPCONVERT lpCV);

#endif // _CONVERT_H_


CONVERT.C  (WRAPUI Sample)

/*

 * CONVERT.C

 *

 * Implements the OleUIConvert function which invokes the complete

 * Convert dialog.

 *

 * Copyright (c)1992 Microsoft Corporation, All Right Reserved

 */

#define STRICT  1

#include "ole2ui.h"

#include <stdlib.h>

#include "common.h"

#include "utility.h"

#include "geticon.h"

#include "regdb.h"

#include "convert.h"

#define CF_CLIPBOARDMIN   0xc000

#define CF_CLIPBOARDMAX   0xffff

#define AUXUSERTYPE_SHORTNAME  USERCLASSTYPE_SHORT  // short name

static char szOLE2DLL[] = "ole2.dll";   // name of OLE 2.0 library

static char szVanillaDocIcon[] = "DefIcon";

/*

 * OleUIConvert

 *

 * Purpose:

 *  Invokes the standard OLE Change Type dialog box allowing the user

 *  to change the type of the single specified object, or change the

 *  type of all OLE objects of a specified type.

 *

 * Parameters:

 *  lpCV            LPOLEUICONVERT pointing to the in-out structure

 *                  for this dialog.

 *

 * Return Value:

 *  UINT            One of the following codes, indicating success or error:

 *                      OLEUI_SUCCESS           Success

 *                      OLEUI_ERR_STRUCTSIZE    The dwStructSize value is wrong

 */

STDAPI_(UINT) OleUIConvert(LPOLEUICONVERT lpCV)

{

UINT        uRet;

HGLOBAL     hMemDlg=NULL;

uRet=UStandardValidation((LPOLEUISTANDARD)lpCV, sizeof(OLEUICONVERT)

 , &hMemDlg);

if (OLEUI_SUCCESS!=uRet)

return uRet;

// Validate structure members passed in.

#if defined( OBSOLETE )

if (!IsValidClassID(lpCV->clsid))

   uRet = OLEUI_CTERR_CLASSIDINVALID;

#endif

if ( (lpCV->dwFlags & CF_SETCONVERTDEFAULT)

 && (!IsValidClassID(lpCV->clsidConvertDefault)) )

   uRet = OLEUI_CTERR_CLASSIDINVALID;

if ( (lpCV->dwFlags & CF_SETACTIVATEDEFAULT)

 && (!IsValidClassID(lpCV->clsidActivateDefault)) )

   uRet = OLEUI_CTERR_CLASSIDINVALID;

if ( (lpCV->dvAspect != DVASPECT_ICON)

 && (lpCV->dvAspect != DVASPECT_CONTENT) )

   uRet = OLEUI_CTERR_DVASPECTINVALID;

if ( (lpCV->wFormat >= CF_CLIPBOARDMIN)

 && (lpCV->wFormat <= CF_CLIPBOARDMAX) )

{

 char szTemp[8];

 if (0 == GetClipboardFormatName(lpCV->wFormat, (LPSTR)szTemp, 8))

   uRet = OLEUI_CTERR_CBFORMATINVALID;

}

if ( (NULL != lpCV->lpszUserType)

&& (IsBadReadPtr(lpCV->lpszUserType, 1)) )

   uRet = OLEUI_CTERR_STRINGINVALID;

if ( (NULL != lpCV->lpszDefLabel)

&& (IsBadReadPtr(lpCV->lpszDefLabel, 1)) )

   uRet = OLEUI_CTERR_STRINGINVALID;

if (0!=lpCV->cClsidExclude)

{

if (NULL!=lpCV->lpClsidExclude && IsBadReadPtr(lpCV->lpClsidExclude

, lpCV->cClsidExclude*sizeof(CLSID)))

uRet=OLEUI_IOERR_LPCLSIDEXCLUDEINVALID;

}

if (OLEUI_ERR_STANDARDMIN <= uRet)

{

if (NULL!=hMemDlg)

FreeResource(hMemDlg);

return uRet;

}

//Now that we've validated everything, we can invoke the dialog.

uRet=UStandardInvocation(ConvertDialogProc, (LPOLEUISTANDARD)lpCV,

 hMemDlg, MAKEINTRESOURCE(IDD_CONVERT));

return uRet;

}

/*

 * ConvertDialogProc

 *

 * Purpose:

 *  Implements the OLE Convert dialog as invoked through the

 *  OleUIConvert function.

 *

 * Parameters:

 *  Standard

 *

 * Return Value:

 *  Standard

 *

 */

BOOL CALLBACK EXPORT ConvertDialogProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)

{

LPCONVERT           lpCV;

UINT                uRet = 0;

OLEUICHANGEICON     ci;

//Declare Win16/Win32 compatible WM_COMMAND parameters.

COMMANDPARAMS(wID, wCode, hWndMsg);

//This will fail under WM_INITDIALOG, where we allocate it.

lpCV=(LPCONVERT)LpvStandardEntry(hDlg, iMsg, wParam, lParam, (UINT FAR *)&uRet);

//If the hook processed the message, we're done.

if (0!=uRet)

return (BOOL)uRet;

//Process the temination message

if (iMsg==uMsgEndDialog)

{

ConvertCleanup(hDlg, lpCV);

StandardCleanup(lpCV, hDlg);

EndDialog(hDlg, wParam);

return TRUE;

}

// Process help message from Change Icon

if (iMsg == uMsgHelp)

{

  PostMessage(lpCV->lpOCV->hWndOwner, uMsgHelp, wParam, lParam);

  return FALSE;

}

switch (iMsg)

{

case WM_INITDIALOG:

FConvertInit(hDlg, wParam, lParam);

return TRUE;

case WM_COMMAND:

switch (wID)

{

case IDCV_ACTIVATELIST:

case IDCV_CONVERTLIST:

switch (wCode)

{

case LBN_SELCHANGE:

// Change "Results" window to reflect current selection

SetConvertResults(hDlg, lpCV);

// Update the icon we display, if we are indeed

// displaying an icon.

if ( (lpCV->dwFlags & CF_SELECTCONVERTTO)

 && (lpCV->dvAspect == DVASPECT_ICON)

 && (!lpCV->fCustomIcon) )

   UpdateCVClassIcon(hDlg, lpCV, hWndMsg);

break;

case LBN_DBLCLK:

//Same as pressing OK.

SendCommand(hDlg, IDOK, BN_CLICKED, hWndMsg);

break;

}

break;

case IDCV_CONVERTTO:

case IDCV_ACTIVATEAS:

{

HWND    hList, hListInvisible;

LRESULT lRetVal;

BOOL    fState;

hList = lpCV->hListVisible;

hListInvisible = lpCV->hListInvisible;

if (IDCV_CONVERTTO == wParam)

{

   // User just click on the button again - it was

   // already selected.

   if (lpCV->dwFlags & CF_SELECTCONVERTTO)

  break;

   // Turn painting updates off.

   SendMessage(hDlg, WM_SETREDRAW, FALSE, 0L);

   // If we're working with a linked object, don't

   // add the activate list - just the object's

   // class should appear in the listbox.

   SwapWindows(hDlg,

   hList,

   hListInvisible);

   lpCV->hListVisible = hListInvisible;

   lpCV->hListInvisible = hList;

   EnableWindow(lpCV->hListInvisible, FALSE);

   EnableWindow(lpCV->hListVisible, TRUE);

   // Update our flags.

   lpCV->dwFlags &= ~CF_SELECTACTIVATEAS;

   lpCV->dwFlags |= CF_SELECTCONVERTTO;

}

else

{

   if (lpCV->dwFlags & CF_SELECTACTIVATEAS)

  break;

   // Turn painting updates off.

   SendMessage(hDlg, WM_SETREDRAW, FALSE, 0L);

   SwapWindows(hDlg,

   hList,

   hListInvisible);

   lpCV->hListVisible = hListInvisible;

   lpCV->hListInvisible = hList;

   EnableWindow(lpCV->hListInvisible, FALSE);

   EnableWindow(lpCV->hListVisible, TRUE);

   // Update our flags.

   lpCV->dwFlags |= CF_SELECTACTIVATEAS;

   lpCV->dwFlags &= ~CF_SELECTCONVERTTO;

}

if (lpCV->dwFlags & CF_SELECTCONVERTTO)

   lRetVal = SendMessage(lpCV->hListVisible, LB_SELECTSTRING, (WPARAM)-1, (LPARAM)lpCV->lpszConvertDefault);

else

   lRetVal = SendMessage(lpCV->hListVisible, LB_SELECTSTRING, (WPARAM)-1, (LPARAM)lpCV->lpszActivateDefault);

if (LB_ERR == lRetVal)

{

   char szCurrentObject[40];

   GetDlgItemText(hDlg, IDCV_OBJECTTYPE, (LPSTR)szCurrentObject, 40);

   SendMessage(lpCV->hListVisible, LB_SELECTSTRING, (WPARAM)-1, (LPARAM)(LPSTR)szCurrentObject);

}

// Turn updates back on.

SendMessage(hDlg, WM_SETREDRAW, TRUE, 0L);

InvalidateRect(lpCV->hListVisible, NULL, TRUE);

UpdateWindow(lpCV->hListVisible);

if ((lpCV->dvAspect & DVASPECT_ICON) && (lpCV->dwFlags & CF_SELECTCONVERTTO))

  UpdateCVClassIcon(hDlg, lpCV, lpCV->hListVisible);

// Hide the icon stuff when Activate is selected...show

// it again when Convert is selected.

fState = ((lpCV->dwFlags & CF_SELECTACTIVATEAS) ||

  (lpCV->dwFlags & CF_DISABLEDISPLAYASICON)) ?

  SW_HIDE : SW_SHOW;

StandardShowDlgItem(hDlg, IDCV_DISPLAYASICON, fState);

// Only display the icon if convert is selected AND

// display as icon is checked.

if ((SW_SHOW==fState) && (DVASPECT_ICON!=lpCV->dvAspect))

   fState = SW_HIDE;

StandardShowDlgItem(hDlg, IDCV_CHANGEICON, fState);

StandardShowDlgItem(hDlg, IDCV_ICON, fState);

StandardShowDlgItem(hDlg, IDCV_ICONLABEL1, fState);

StandardShowDlgItem(hDlg, IDCV_ICONLABEL2, fState);

  SetConvertResults(hDlg, lpCV);

}

break;

case IDOK:

{

UINT  iCurSel;

LPSTR lpszCLSID;

char  szBuffer[256];

// Set OUT parameters

//

// Set output flags to current ones

//

lpCV->lpOCV->dwFlags = lpCV->dwFlags;

// Update the dvAspect and fObjectsIconChanged members

// as appropriate.

//

if (lpCV->dwFlags & CF_SELECTACTIVATEAS)

{

  // DON'T update aspect if activate as was selected.

  lpCV->lpOCV->fObjectsIconChanged = FALSE;

}

else

  lpCV->lpOCV->dvAspect = lpCV->dvAspect;

//

// Get the new clsid

//

iCurSel = (UINT)SendMessage(lpCV->hListVisible, LB_GETCURSEL, 0, 0);

SendMessage(lpCV->hListVisible, LB_GETTEXT, iCurSel, (LPARAM)(LPSTR)szBuffer);

lpszCLSID = PointerToNthField((LPSTR)szBuffer, 2, '\t');

CLSIDFromString(lpszCLSID, (LPCLSID)(&(lpCV->lpOCV->clsidNew)));

// Free the hMetaPict we got in.

OleUIMetafilePictIconFree(lpCV->lpOCV->hMetaPict);

//

// Get the hMetaPict (if display as icon is checked)

//

if (DVASPECT_ICON == lpCV->dvAspect)

{

   HICON hIcon;

   char  szLabel[OLEUI_CCHLABELMAX];

   int   Index;

   // Create the hMetaPict here from icon, label,

   // index, and path

   hIcon = (HICON)SendDlgItemMessage(hDlg, IDCV_ICON, STM_GETICON, 0, 0L);

   // the combined length of the 2 label lines won't ever be more than

   // OLEUI_CCHLABELMAX.

   Index = (int)SendDlgItemMessage(hDlg, IDCV_ICONLABEL1, WM_GETTEXT, OLEUI_CCHLABELMAX, (LPARAM)(LPSTR)szLabel);

   if (Index < OLEUI_CCHLABELMAX)

   {

  LPSTR lpszSecondLine = szLabel + Index;

  SendDlgItemMessage(hDlg, IDCV_ICONLABEL2, WM_GETTEXT,

 OLEUI_CCHLABELMAX-Index,

 (LPARAM)(LPSTR)lpszSecondLine);

   }

   lpCV->lpOCV->hMetaPict =

 OleUIMetafilePictFromIconAndLabel(hIcon,

   (LPSTR)szLabel,

   lpCV->lpszIconSource,

   lpCV->IconIndex);

}

else

   lpCV->lpOCV->hMetaPict = (HGLOBAL)NULL;

//

// End the dialog

//

SendMessage(hDlg, uMsgEndDialog, OLEUI_OK, 0L);

}

break;

case IDCANCEL:

SendMessage(hDlg, uMsgEndDialog, OLEUI_CANCEL, 0L);

break;

case ID_OLEUIHELP:

PostMessage(lpCV->lpOCV->hWndOwner,

uMsgHelp, (WPARAM)hDlg, MAKELPARAM(IDD_CONVERT, 0));

break;

case IDCV_DISPLAYASICON:

{

int i;

BOOL fCheck;

fCheck=IsDlgButtonChecked(hDlg, wID);

if (fCheck)

lpCV->dvAspect = DVASPECT_ICON;

else

lpCV->dvAspect = DVASPECT_CONTENT;

if (fCheck && (!lpCV->fCustomIcon))

   UpdateCVClassIcon(hDlg, lpCV, lpCV->hListVisible);

//Show or hide the icon depending on the check state.

i=(fCheck) ? SW_SHOWNORMAL : SW_HIDE;

StandardShowDlgItem(hDlg, IDCV_CHANGEICON, i);

StandardShowDlgItem(hDlg, IDCV_ICON, i);

StandardShowDlgItem(hDlg, IDCV_ICONLABEL1, i);

StandardShowDlgItem(hDlg, IDCV_ICONLABEL2, i);

SetConvertResults(hDlg, lpCV);

}

break;

case IDCV_CHANGEICON:

{

LPMALLOC pIMalloc;

LPSTR    pszString, pszCLSID;

int      iSel;

HICON    hIcon;

char     szLabel[OLEUI_CCHLABELMAX];

int      Index;

//Initialize the structure for the hook.

_fmemset((LPOLEUICHANGEICON)&ci, 0, sizeof(ci));

// Create the hMetaPict here from icon, label,

// index, and path

hIcon = (HICON)SendDlgItemMessage(hDlg, IDCV_ICON, STM_GETICON, 0, 0L);

// the combined length of the 2 label lines won't ever be more than

// OLEUI_CCHLABELMAX.

Index = (int)SendDlgItemMessage(hDlg, IDCV_ICONLABEL1, WM_GETTEXT, OLEUI_CCHLABELMAX, (LPARAM)(LPSTR)szLabel);

if (Index < OLEUI_CCHLABELMAX)

{

   LPSTR    lpszSecondLine;

   lpszSecondLine = szLabel + Index;

   SendDlgItemMessage(hDlg, IDCV_ICONLABEL2, WM_GETTEXT,

  OLEUI_CCHLABELMAX-Index,

  (LPARAM)(LPSTR)lpszSecondLine);

}

ci.hMetaPict =

  OleUIMetafilePictFromIconAndLabel(hIcon,

(LPSTR)szLabel,

lpCV->lpszIconSource,

lpCV->IconIndex);

ci.cbStruct =sizeof(ci);

ci.hWndOwner=hDlg;

ci.dwFlags  = CIF_SELECTCURRENT;

// Only show help if we're showing it for this dialog.

if (lpCV->dwFlags & CF_SHOWHELPBUTTON)

  ci.dwFlags  |= CIF_SHOWHELP;

iSel = (int)SendMessage(lpCV->hListVisible, LB_GETCURSEL, 0, 0L);

CoGetMalloc(MEMCTX_TASK, &pIMalloc);

pszString = (LPSTR)pIMalloc->lpVtbl->Alloc(pIMalloc, OLEUI_CCHLABELMAX + OLEUI_CCHCLSIDSTRING);

// Get whole string

SendMessage(lpCV->hListVisible, LB_GETTEXT, iSel, (LONG)pszString);

// Set pointer to CLSID (string)

pszCLSID = PointerToNthField(pszString, 2, '\t');

// Get the clsid to pass to change icon.

CLSIDFromString((LPSTR)pszCLSID, (LPCLSID)&(ci.clsid));

pIMalloc->lpVtbl->Free(pIMalloc, (LPVOID)pszString);

pIMalloc->lpVtbl->Release(pIMalloc);

//Let the hook in to customize Change Icon if desired.

uRet=UStandardHook(lpCV, hDlg, uMsgChangeIcon

   , 0, (LONG)(LPSTR)&ci);

if (0==uRet)

uRet=(UINT)(OLEUI_OK==OleUIChangeIcon((LPOLEUICHANGEICON)&ci));

//Update the display if necessary.

if (0!=uRet)

{

HICON hIcon;

char  szLabel[OLEUI_CCHLABELMAX];

DWORD dwWrapIndex;

hIcon = OleUIMetafilePictExtractIcon(ci.hMetaPict);

SendDlgItemMessage(hDlg, IDCV_ICON, STM_SETICON, (WPARAM)hIcon, 0L);

OleUIMetafilePictExtractIconSource(ci.hMetaPict, lpCV->lpszIconSource, &(lpCV->IconIndex));

OleUIMetafilePictExtractLabel(ci.hMetaPict, szLabel, OLEUI_CCHLABELMAX, &dwWrapIndex);

if (0 == dwWrapIndex)  // no second line

{

   SendDlgItemMessage(hDlg, IDCV_ICONLABEL1, WM_SETTEXT, 0, (LPARAM)(LPSTR)szLabel);

   SendDlgItemMessage(hDlg, IDCV_ICONLABEL2, WM_SETTEXT, 0, (LPARAM)(LPSTR)"");

}

else

{

   LPSTR lpszSecondLine;

   lpszSecondLine = szLabel + dwWrapIndex;

   SendDlgItemMessage(hDlg, IDCV_ICONLABEL2,

  WM_SETTEXT, 0, (LPARAM)lpszSecondLine);

   *lpszSecondLine = '\0';

   SendDlgItemMessage(hDlg, IDCV_ICONLABEL1,

  WM_SETTEXT, 0, (LPARAM)(LPSTR)szLabel);

}

// Update our custom/default flag

if (ci.dwFlags & CIF_SELECTDEFAULT)

   lpCV->fCustomIcon = FALSE;   // we're in default mode (icon changes on each LB selchange)

else if (ci.dwFlags & CIF_SELECTFROMFILE)

   lpCV->fCustomIcon = TRUE;    // we're in custom mode (icon doesn't change)

// no change in fCustomIcon if user selected current

lpCV->lpOCV->fObjectsIconChanged = TRUE;

}

}

break;

}

break;

}

return FALSE;

}

/*

 * FConvertInit

 *

 * Purpose:

 *  WM_INITIDIALOG handler for the Convert dialog box.

 *

 * Parameters:

 *  hDlg            HWND of the dialog

 *  wParam          WPARAM of the message

 *  lParam          LPARAM of the message

 *

 * Return Value:

 *  BOOL            Value to return for WM_INITDIALOG.

 */

BOOL FConvertInit(HWND hDlg, WPARAM wParam, LPARAM lParam)

{

LPCONVERT              lpCV;

LPOLEUICONVERT         lpOCV;

LPMALLOC               pIMalloc;

HFONT                  hFont;  // non-bold version of dialog's font

RECT                   rc;

DWORD                  dw;

int                    cItemsActivate;

HKEY                   hKey;

LONG                   lRet;

UINT                   nRet;

//Copy the structure at lParam into our instance memory.

lpCV=(LPCONVERT)LpvStandardInit(hDlg, sizeof(CONVERT), TRUE, (HFONT FAR *)&hFont);

//PvStandardInit send a termination to us already.

if (NULL==lpCV)

return FALSE;

lpOCV=(LPOLEUICONVERT)lParam;

lpCV->lpOCV=lpOCV;

lpCV->fCustomIcon = FALSE;

//Copy other information from lpOCV that we might modify.

lpCV->dwFlags = lpOCV->dwFlags;

lpCV->clsid = lpOCV->clsid;

lpCV->dvAspect = lpOCV->dvAspect;

lpCV->hListVisible = GetDlgItem(hDlg, IDCV_ACTIVATELIST);

lpCV->hListInvisible = GetDlgItem(hDlg, IDCV_CONVERTLIST);

lpCV->lpszCurrentObject = lpOCV->lpszUserType;

lpOCV->clsidNew = CLSID_NULL;

lpOCV->fObjectsIconChanged = FALSE;

//Allocate space for our strings

if (NOERROR != CoGetMalloc(MEMCTX_TASK, &pIMalloc))

   return FALSE;

lpCV->lpszConvertDefault = (LPSTR)pIMalloc->lpVtbl->Alloc(pIMalloc, OLEUI_CCHLABELMAX);

lpCV->lpszActivateDefault = (LPSTR)pIMalloc->lpVtbl->Alloc(pIMalloc, OLEUI_CCHLABELMAX);

lpCV->lpszIconSource = (LPSTR)pIMalloc->lpVtbl->Alloc(pIMalloc, OLEUI_CCHPATHMAX);

pIMalloc->lpVtbl->Release(pIMalloc);

//If we got a font, send it to the necessary controls.

if (NULL!=hFont)

{

SendDlgItemMessage(hDlg, IDCV_OBJECTTYPE, WM_SETFONT, (WPARAM)hFont, 0L);

SendDlgItemMessage(hDlg, IDCV_RESULTTEXT, WM_SETFONT, (WPARAM)hFont, 0L);

SendDlgItemMessage(hDlg, IDCV_ICONLABEL1, WM_SETFONT, (WPARAM)hFont, 0L);

SendDlgItemMessage(hDlg, IDCV_ICONLABEL2, WM_SETFONT, (WPARAM)hFont, 0L);

}

//Hide the help button if necessary

if (!(lpCV->dwFlags & CF_SHOWHELPBUTTON))

StandardShowDlgItem(hDlg, ID_OLEUIHELP, SW_HIDE);

//Fill the Object Type listbox with entries from the reg DB.

nRet = FillClassList(lpOCV->clsid,

  lpCV->hListVisible,

  lpCV->hListInvisible,

  &(lpCV->lpszCurrentObject),

  lpOCV->fIsLinkedObject,

  lpOCV->wFormat,

  lpOCV->cClsidExclude,

  lpOCV->lpClsidExclude);

if (nRet == -1) {

// bring down dialog if error when filling list box

PostMessage(hDlg, uMsgEndDialog, OLEUI_ERR_LOADSTRING, 0L);

}

// Set the name of the current object.

SetDlgItemText(hDlg, IDCV_OBJECTTYPE, (LPSTR)lpCV->lpszCurrentObject);

// Disable the "Activate As" button if the Activate list doesn't

// have any objects in it.

cItemsActivate = (int)SendMessage(lpCV->hListVisible, LB_GETCOUNT, 0, 0L);

if (1 >= cItemsActivate || (lpCV->dwFlags & CF_DISABLEACTIVATEAS))

  EnableWindow(GetDlgItem(hDlg, IDCV_ACTIVATEAS), FALSE);

//Set the tab width in the list to push all the tabs off the side.

GetClientRect(lpCV->hListVisible, (LPRECT)&rc);

dw=GetDialogBaseUnits();

rc.right =(8*rc.right)/LOWORD(dw);  //Convert pixels to 2x dlg units.

SendMessage(lpCV->hListVisible, LB_SETTABSTOPS, 1, (LPARAM)(LPINT)(&rc.right));

SendMessage(lpCV->hListInvisible, LB_SETTABSTOPS, 1, (LPARAM)(LPINT)(&rc.right));

// Make sure that either "Convert To" or "Activate As" is selected

// and initialize listbox contents and selection accordingly

if (lpCV->dwFlags & CF_SELECTACTIVATEAS)

{

  // Don't need to adjust listbox here because FillClassList

  // initializes to the "Activate As" state.

   CheckRadioButton(hDlg, IDCV_CONVERTTO, IDCV_ACTIVATEAS, IDCV_ACTIVATEAS);

   // Hide the icon stuff when Activate is selected...it gets shown

   // again when Convert is selected.

   StandardShowDlgItem(hDlg, IDCV_DISPLAYASICON, SW_HIDE);

   StandardShowDlgItem(hDlg, IDCV_CHANGEICON, SW_HIDE);

   StandardShowDlgItem(hDlg, IDCV_ICON, SW_HIDE);

   StandardShowDlgItem(hDlg, IDCV_ICONLABEL1, SW_HIDE);

   StandardShowDlgItem(hDlg, IDCV_ICONLABEL2, SW_HIDE);

}

else

{

  // Default case.  If user hasn't selected either flag, we will

  // come here anyway.

  // swap listboxes.

  HWND hWndTemp = lpCV->hListVisible;

  if ( lpCV->dwFlags & CF_DISABLEDISPLAYASICON ) {

  StandardShowDlgItem(hDlg, IDCV_DISPLAYASICON, SW_HIDE);

  StandardShowDlgItem(hDlg, IDCV_CHANGEICON, SW_HIDE);

  StandardShowDlgItem(hDlg, IDCV_ICON, SW_HIDE);

  StandardShowDlgItem(hDlg, IDCV_ICONLABEL1, SW_HIDE);

  StandardShowDlgItem(hDlg, IDCV_ICONLABEL2, SW_HIDE);

  }

  lpCV->dwFlags |= CF_SELECTCONVERTTO; // Make sure flag is set

  CheckRadioButton(hDlg, IDCV_CONVERTTO, IDCV_ACTIVATEAS, IDCV_CONVERTTO);

  SwapWindows(hDlg, lpCV->hListVisible, lpCV->hListInvisible);

  lpCV->hListVisible = lpCV->hListInvisible;

  lpCV->hListInvisible = hWndTemp;

  EnableWindow(lpCV->hListInvisible, FALSE);

  EnableWindow(lpCV->hListVisible, TRUE);

}

// Initialize Default strings.

// Default convert string is easy...just user the user type name from

// the clsid we got, or the current object

if ( (lpCV->dwFlags & CF_SETCONVERTDEFAULT)

 && (IsValidClassID(lpCV->lpOCV->clsidConvertDefault)) )

{

dw = OleStdGetUserTypeOfClass((LPCLSID)(&lpCV->lpOCV->clsidConvertDefault),

  lpCV->lpszConvertDefault,

  OLEUI_CCHLABELMAX,

  NULL);

if (0 == dw)

   lstrcpy((LPSTR)lpCV->lpszConvertDefault, (LPSTR)lpCV->lpszCurrentObject);

}

else

lstrcpy((LPSTR)lpCV->lpszConvertDefault, (LPSTR)lpCV->lpszCurrentObject);

   // Default activate is a bit trickier.  We want to use the user type

   // name if from the clsid we got (assuming we got one), or the current

   // object if it fails or we didn't get a clsid.  But...if there's a

   // Treat As entry in the reg db, then we use that instead.  So... the

   // logic boils down to this:

   //

   // if ("Treat As" in reg db)

   //    use it;

   // else

   //    if (CF_SETACTIVATEDEFAULT)

   //      use it;

   //    else

   //      use current object;

lRet = RegOpenKey(HKEY_CLASSES_ROOT, "CLSID", (HKEY FAR *)&hKey);

if (lRet != ERROR_SUCCESS)

  goto CheckInputFlag;

else

{

   LPSTR lpszCLSID;

   char  szKey[OLEUI_CCHKEYMAX];

   CLSID clsid;

   char  szValue[OLEUI_CCHKEYMAX];

   StringFromCLSID(&(lpCV->lpOCV->clsid), &lpszCLSID);

   lstrcpy(szKey, lpszCLSID);

   lstrcat(szKey, (LPSTR)"\\TreatAs");

   dw = OLEUI_CCHKEYMAX;

   lRet = RegQueryValue(hKey, (LPSTR)szKey, (LPSTR)szValue, (LPDWORD)&dw);

   if (lRet != ERROR_SUCCESS)

   {

  RegCloseKey(hKey);

  OleStdFreeString(lpszCLSID, NULL);

  goto CheckInputFlag;

   }

   else

   {

  CLSIDFromString((LPSTR)szValue, &clsid);

  if (0 == OleStdGetUserTypeOfClass(&clsid,

   lpCV->lpszActivateDefault,

   OLEUI_CCHLABELMAX,

   NULL))

  {

 RegCloseKey(hKey);

 OleStdFreeString(lpszCLSID, NULL);

 goto CheckInputFlag;

  }

   }

   RegCloseKey(hKey);

   OleStdFreeString(lpszCLSID, NULL);

   goto SelectStringInListbox;

}

CheckInputFlag:

if ( (lpCV->dwFlags & CF_SETACTIVATEDEFAULT)

 && (IsValidClassID(lpCV->lpOCV->clsidActivateDefault)) )

{

dw = OleStdGetUserTypeOfClass((LPCLSID)(&lpCV->lpOCV->clsidActivateDefault),

  lpCV->lpszActivateDefault,

  OLEUI_CCHLABELMAX,

  NULL);

if (0 == dw)

   lstrcpy((LPSTR)lpCV->lpszActivateDefault, (LPSTR)lpCV->lpszCurrentObject);

}

else

lstrcpy((LPSTR)(lpCV->lpszActivateDefault), (LPSTR)lpCV->lpszCurrentObject);

SelectStringInListbox:

if (lpCV->dwFlags & CF_SELECTCONVERTTO)

   lRet = SendMessage(lpCV->hListVisible, LB_SELECTSTRING, (WPARAM)-1, (LPARAM)(LPSTR)(lpCV->lpszConvertDefault));

else

   lRet = SendMessage(lpCV->hListVisible, LB_SELECTSTRING, (WPARAM)-1, (LPARAM)(LPSTR)(lpCV->lpszActivateDefault));

if (LB_ERR == lRet)

   SendMessage(lpCV->hListVisible, LB_SETCURSEL, (WPARAM)0, 0L);

// Initialize icon stuff

if (DVASPECT_ICON == lpCV->dvAspect )

{

  SendDlgItemMessage(hDlg, IDCV_DISPLAYASICON, BM_SETCHECK, TRUE, 0L);

  if ((HGLOBAL)NULL != lpOCV->hMetaPict)

  {

 char  szLabel[OLEUI_CCHLABELMAX];

 HICON hIcon;

 DWORD dwWrapIndex;

 // Set the icon to the icon from the hMetaPict,

 // set the label to the label from the hMetaPict.

 if (0 != OleUIMetafilePictExtractLabel(lpOCV->hMetaPict, (LPSTR)szLabel, OLEUI_CCHLABELMAX, &dwWrapIndex))

 {

 if (0 == dwWrapIndex)  // no second line

 {

SendDlgItemMessage(hDlg, IDCV_ICONLABEL1, WM_SETTEXT, 0, (LPARAM)(LPSTR)szLabel);

SendDlgItemMessage(hDlg, IDCV_ICONLABEL2, WM_SETTEXT, 0, (LPARAM)(LPSTR)"");

 }

 else

 {

LPSTR lpszSecondLine;

lpszSecondLine = szLabel + dwWrapIndex;

SendDlgItemMessage(hDlg, IDCV_ICONLABEL2,

   WM_SETTEXT, 0, (LPARAM)lpszSecondLine);

*lpszSecondLine = '\0';

SendDlgItemMessage(hDlg, IDCV_ICONLABEL1,

   WM_SETTEXT, 0, (LPARAM)(LPSTR)szLabel);

 }

 }

 hIcon = OleUIMetafilePictExtractIcon(lpOCV->hMetaPict);

 if (NULL != hIcon)

 {

   SendDlgItemMessage(hDlg, IDCV_ICON, STM_SETICON, (WPARAM)hIcon, 0L);

   lpCV->fCustomIcon = TRUE;

 }

 OleUIMetafilePictExtractIconSource(lpOCV->hMetaPict,

(LPSTR)(lpCV->lpszIconSource),

&(lpCV->IconIndex));

  }

  else

 UpdateCVClassIcon(hDlg, lpCV, lpCV->hListVisible);

}

else

{

  // Hide & disable icon stuff

  StandardShowDlgItem(hDlg, IDCV_ICON, SW_HIDE);

  StandardShowDlgItem(hDlg, IDCV_ICONLABEL1, SW_HIDE);

  StandardShowDlgItem(hDlg, IDCV_ICONLABEL2, SW_HIDE);

  StandardShowDlgItem(hDlg, IDCV_CHANGEICON, SW_HIDE);

}

// Call the hook with lCustData in lParam

UStandardHook((LPVOID)lpCV, hDlg, WM_INITDIALOG, wParam, lpOCV->lCustData);

// Update results window

SetConvertResults(hDlg, lpCV);

// Update caption if lpszCaption was specified

if (lpCV->lpOCV->lpszCaption && !IsBadReadPtr(lpCV->lpOCV->lpszCaption, 1)

  && lpCV->lpOCV->lpszCaption[0] != '\0')

SetWindowText(hDlg, (LPSTR)lpCV->lpOCV->lpszCaption);

return TRUE;

}

/*

 * FillClassList

 *

 * Purpose:

 *  Enumerates available OLE object classes from the registration

 *  database that we can convert or activate the specified clsid from.

 *

 *  Note that this function removes any prior contents of the listbox.

 *

 * Parameters:

 *  clsid           Class ID for class to find convert classes for

 *  hList           HWND to the listbox to fill.

 *  hListInvisible  HWND to invisible listbox that stores "activate as" list.

 *  lpszCurrentClass LPSTR to put the (hr) class name of the clsid; we

 *                   do it here since we've already got the reg db open.

 *  fIsLinkedObject BOOL is the original object a linked object

 *  wFormat         WORD specifying the format of the original class.

 *  cClsidExclude   UINT number of entries in exclude list

 *  lpClsidExclude  LPCLSID array classes to exclude for list

 *

 * Return Value:

 *  UINT            Number of strings added to the listbox, -1 on failure.

 */

UINT FillClassList(

CLSID clsid,

HWND hList,

HWND hListInvisible,

LPSTR FAR *lplpszCurrentClass,

BOOL fIsLinkedObject,

WORD wFormat,

UINT cClsidExclude,

LPCLSID lpClsidExclude)

{

DWORD       dw;

UINT        cStrings=0;

HKEY        hKey;

LONG        lRet;

char        szFormatKey[OLEUI_CCHKEYMAX];

char        szClass[OLEUI_CCHKEYMAX];

char        szFormat[OLEUI_CCHKEYMAX];

char        szHRClassName[OLEUI_CCHKEYMAX];

CLSID       clsidForList;

LPSTR       lpszCLSID;

//Clean out the existing strings.

SendMessage(hList, LB_RESETCONTENT, 0, 0L);

SendMessage(hListInvisible, LB_RESETCONTENT, 0, 0L);

//Open up the root key.

lRet=RegOpenKey(HKEY_CLASSES_ROOT, (LPSTR)"CLSID", (HKEY FAR *)&hKey);

if ((LONG)ERROR_SUCCESS!=lRet)

return (UINT)-1;

if (NULL == *lplpszCurrentClass)

{

   // alloc buffer here...

LPMALLOC pIMalloc = NULL;

HRESULT  hrErr;

hrErr = CoGetMalloc(MEMCTX_TASK, &pIMalloc);

if (hrErr != NOERROR)

{

RegCloseKey(hKey);

return FALSE;

}

// Allocate space for lpszCurrentClass

*lplpszCurrentClass = (LPSTR)pIMalloc->lpVtbl->Alloc(pIMalloc, OLEUI_CCHKEYMAX);

 pIMalloc->lpVtbl->Release(pIMalloc);

lRet = OleStdGetUserTypeOfClass((REFCLSID)&clsid,

*lplpszCurrentClass,

OLEUI_CCHLABELMAX,

NULL);

if (0 ==lRet)

{

int n = LoadString(ghInst, (UINT)IDS_PSUNKNOWNTYPE, *lplpszCurrentClass,

OLEUI_CCHKEYMAX);

if (!n)

{

RegCloseKey(hKey);

return (UINT)-1;

}

}

}

// Get the class name of the original class.

StringFromCLSID((REFCLSID)&clsid, (LPSTR FAR *)&lpszCLSID);

// Here, we step through the entire registration db looking for

// class that can read or write the original class' format.  We

// maintain two lists - an activate list and a convert list.  The

// activate list is a subset of the convert list - activate == read/write

// and convert == read. We swap the listboxes as needed with

// SwapWindows, and keep track of which is which in the lpCV structure.

// Every item has the following format:

//

//     Class Name\tclsid\0

cStrings=0;

lRet=RegEnumKey(hKey, cStrings++, (LPSTR)szClass, OLEUI_CCHKEYMAX);

while ((LONG)ERROR_SUCCESS==lRet)

{

int j;

BOOL fExclude=FALSE;

//Check if this CLSID is in the exclusion list.

CLSIDFromString((LPSTR)szClass, (LPCLSID)&clsidForList);

for (j=0; j < (int)cClsidExclude; j++)

{

if (IsEqualCLSID(&clsidForList, (LPCLSID)(lpClsidExclude+j)))

{

fExclude=TRUE;

break;

}

}

if (fExclude)

goto Next;   // don't add this class to list

// Check for a \Conversion\Readwritable\Main - if its

// readwriteable, then the class can be added to the ActivateAs

// list.

// NOTE: the presence of this key should NOT automatically be

//       used to add the class to the CONVERT list.

lstrcpy((LPSTR)szFormatKey, (LPSTR)szClass);

lstrcat((LPSTR)szFormatKey, (LPSTR)"\\Conversion\\Readwritable\\Main");

dw=OLEUI_CCHKEYMAX;

lRet=RegQueryValue(hKey, (LPSTR)szFormatKey, (LPSTR)szFormat, (LONG FAR *)&dw);

if ( ((LONG)ERROR_SUCCESS==lRet)

 && (FormatIncluded((LPSTR)szFormat, wFormat)) )

{

// Here, we've got a list of formats that this class can read

// and write. We need to see if the original class' format is

// in this list.  We do that by looking for wFormat in

// szFormat - if it in there, then we add this class to the

// ACTIVATEAS list only. we do NOT automatically add it to the

// CONVERT list. Readable and Readwritable format lists should

// be handled separately.

dw=OLEUI_CCHKEYMAX;

lRet=RegQueryValue(hKey, (LPSTR)szClass, (LPSTR)szHRClassName, (LPDWORD)&dw);

if ((LONG)ERROR_SUCCESS==lRet)

{

lstrcat((LPSTR)szHRClassName, (LPSTR)"\t");

// only add if not already in list

if (LB_ERR==SendMessage(hList,LB_FINDSTRING, 0,

(LPARAM)(LPSTR)szHRClassName)) {

lstrcat((LPSTR)szHRClassName, (LPSTR)szClass);

SendMessage(hList, LB_ADDSTRING, 0,

(DWORD)(LPSTR)szHRClassName);

}

}

}

// Here we'll check to see if the original class' format is in the

// readable list. if so, we will add the class to the CONVERTLIST

// We've got a special case for a linked object here.

// If an object is linked, then the only class that

// should appear in the convert list is the object's

// class.  So, here we check to see if the object is

// linked.  If it is, then we compare the classes.  If

// they aren't the same, then we just go to the next key.

if ( (!fIsLinkedObject)

|| (lstrcmp((LPSTR)lpszCLSID, (LPSTR)szClass) == 0) )

{

//Check for a \Conversion\Readable\Main entry

lstrcpy((LPSTR)szFormatKey, (LPSTR)szClass);

lstrcat((LPSTR)szFormatKey, (LPSTR)"\\Conversion\\Readable\\Main");

dw=OLEUI_CCHKEYMAX;

// Check to see if this class can read the original class

// format.  If it can, add the string to the listbox as

// CONVERT_LIST.

lRet=RegQueryValue(hKey, (LPSTR)szFormatKey, (LPSTR)szFormat, (LPDWORD)&dw);

if ( ((LONG)ERROR_SUCCESS==lRet)

 && (FormatIncluded((LPSTR)szFormat, wFormat)) )

{

dw=OLEUI_CCHKEYMAX;

lRet=RegQueryValue(hKey, (LPSTR)szClass, (LPSTR)szHRClassName, (LPDWORD)&dw);

if ((LONG)ERROR_SUCCESS==lRet)

{

lstrcat((LPSTR)szHRClassName, (LPSTR)"\t");

// only add if not already in list

if (LB_ERR==SendMessage(hListInvisible,LB_FINDSTRING, 0,

(LPARAM)(LPSTR)szHRClassName)) {

lstrcat((LPSTR)szHRClassName, (LPSTR)szClass);

SendMessage(hListInvisible, LB_ADDSTRING, 0,

(DWORD)(LPSTR)szHRClassName);

}

}  // end if

} // end if

} // end else

Next:

//Continue with the next key.

lRet=RegEnumKey(hKey, cStrings++, (LPSTR)szClass, OLEUI_CCHKEYMAX);

}  // end while

// If the original class isn't already in the list, add it.

lstrcpy((LPSTR)szHRClassName, *lplpszCurrentClass);

lstrcat((LPSTR)szHRClassName, (LPSTR)"\t");

lRet = SendMessage(hList, LB_FINDSTRING, (WPARAM)-1, (LPARAM)(LPSTR)szHRClassName);

// only add it if it's not there already.

if (LB_ERR == lRet) {

lstrcat((LPSTR)szHRClassName, lpszCLSID);

SendMessage(hList, LB_ADDSTRING, 0, (LPARAM)(LPSTR)szHRClassName);

}

lRet = SendMessage(hListInvisible, LB_FINDSTRING, (WPARAM)-1, (LPARAM)(LPSTR)szHRClassName);

// only add it if it's not there already.

if (LB_ERR == lRet)

SendMessage(hListInvisible, LB_ADDSTRING, 0, (LPARAM)(LPSTR)szHRClassName);

// Free the string we got from StringFromCLSID.

// OLE2NOTE:  StringFromCLSID uses your IMalloc to alloc a

// string, so you need to be sure to free the string you

// get back, otherwise you'll have leaky memory.

OleStdFreeString(lpszCLSID, NULL);

RegCloseKey(hKey);

return cStrings;

}

/*

 * OleUICanConvertOrActivateAs

 *

 * Purpose:

 *  Determine if there is any OLE object class from the registration

 *  database that we can convert or activate the specified clsid from.

 *

 * Parameters:

 *  rClsid          REFCLSID Class ID for class to find convert classes for

 *  fIsLinkedObject BOOL is the original object a linked object

 *  wFormat         WORD specifying the format of the original class.

 *

 * Return Value:

 *  BOOL            TRUE if Convert command should be enabled, else FALSE

 */

STDAPI_(BOOL) OleUICanConvertOrActivateAs(

REFCLSID    rClsid,

BOOL        fIsLinkedObject,

WORD        wFormat

)

{

DWORD       dw;

UINT        cStrings=0;

HKEY        hKey;

LONG        lRet;

char        szFormatKey[OLEUI_CCHKEYMAX];

char        szClass[OLEUI_CCHKEYMAX];

char        szFormat[OLEUI_CCHKEYMAX];

char        szHRClassName[OLEUI_CCHKEYMAX];

BOOL        fEnableConvert = FALSE;

LPSTR       lpszCLSID;

//Open up the root key.

lRet=RegOpenKey(HKEY_CLASSES_ROOT, (LPSTR)"CLSID", (HKEY FAR *)&hKey);

if ((LONG)ERROR_SUCCESS!=lRet)

return FALSE;

// Get the class name of the original class.

StringFromCLSID(rClsid, (LPSTR FAR *)&lpszCLSID);

// Here, we step through the entire registration db looking for

// class that can read or write the original class' format.

// This loop stops if a single class is found.

cStrings=0;

lRet=RegEnumKey(hKey, cStrings++, (LPSTR)szClass, OLEUI_CCHKEYMAX);

while ((LONG)ERROR_SUCCESS==lRet)

{

if (lstrcmp(lpszCLSID, szClass) == 0)

goto next;   // we don't want to consider the source class

// Check for a \Conversion\ReadWriteable\Main entry first - if its

// readwriteable, then we don't need to bother checking to see if

// its readable.

lstrcpy((LPSTR)szFormatKey, (LPSTR)szClass);

lstrcat((LPSTR)szFormatKey, (LPSTR)"\\Conversion\\Readwritable\\Main");

dw=OLEUI_CCHKEYMAX;

lRet=RegQueryValue(hKey, (LPSTR)szFormatKey, (LPSTR)szFormat, (LONG FAR *)&dw);

if ( (LONG)ERROR_SUCCESS != lRet)

{

  // Try \\DataFormats\DefaultFile too

  lstrcpy((LPSTR)szFormatKey, (LPSTR)szClass);

  lstrcat((LPSTR)szFormatKey, (LPSTR)"\\DataFormats\\DefaultFile");

  dw=OLEUI_CCHKEYMAX;

  lRet=RegQueryValue(hKey, (LPSTR)szFormatKey, (LPSTR)szFormat, (LONG FAR *)&dw);

}

if ( ((LONG)ERROR_SUCCESS==lRet)

 && (FormatIncluded((LPSTR)szFormat, wFormat)) )

{

// Here, we've got a list of formats that this class can read

// and write. We need to see if the original class' format is

// in this list.  We do that by looking for wFormat in

// szFormat - if it in there, then we add this class to the

// both lists and continue.  If not, then we look at the

// class' readable formats.

dw=OLEUI_CCHKEYMAX;

lRet=RegQueryValue(hKey, (LPSTR)szClass, (LPSTR)szHRClassName, (LPDWORD)&dw);

if ((LONG)ERROR_SUCCESS==lRet)

{

fEnableConvert = TRUE;

break;  // STOP -- found one!

}

}

// We either didn't find the readwritable key, or the

// list of readwritable formats didn't include the

// original class format.  So, here we'll check to

// see if its in the readable list.

// We've got a special case for a linked object here.

// If an object is linked, then the only class that

// should appear in the convert list is the object's

// class.  So, here we check to see if the object is

// linked.  If it is, then we compare the classes.  If

// they aren't the same, then we just go to the next key.

else if ( (!fIsLinkedObject)

|| (lstrcmp((LPSTR)lpszCLSID, (LPSTR)szClass) == 0) )

{

//Check for a \Conversion\Readable\Main entry

lstrcpy((LPSTR)szFormatKey, (LPSTR)szClass);

lstrcat((LPSTR)szFormatKey, (LPSTR)"\\Conversion\\Readable\\Main");

dw=OLEUI_CCHKEYMAX;

// Check to see if this class can read the original class

// format.  If it can, add the string to the listbox as

// CONVERT_LIST.

lRet=RegQueryValue(hKey, (LPSTR)szFormatKey, (LPSTR)szFormat, (LPDWORD)&dw);

if ( ((LONG)ERROR_SUCCESS==lRet)

 && (FormatIncluded((LPSTR)szFormat, wFormat)) )

{

dw=OLEUI_CCHKEYMAX;

lRet=RegQueryValue(hKey, (LPSTR)szClass, (LPSTR)szHRClassName, (LPDWORD)&dw);

if ((LONG)ERROR_SUCCESS==lRet)

{

fEnableConvert = TRUE;

break;  // STOP -- found one!

}  // end if

} // end if

} // end else

next:

//Continue with the next key.

lRet=RegEnumKey(hKey, cStrings++, (LPSTR)szClass, OLEUI_CCHKEYMAX);

}  // end while

// Free the string we got from StringFromCLSID.

// OLE2NOTE:  StringFromCLSID uses your IMalloc to alloc a

// string, so you need to be sure to free the string you

// get back, otherwise you'll have leaky memory.

OleStdFreeString(lpszCLSID, NULL);

RegCloseKey(hKey);

return fEnableConvert;

}

/*

 * FormatIncluded

 *

 * Purpose:

 *  Parses the string for format from the word.

 *

 * Parameters:

 *  szStringToSearch  String to parse

 *  wFormat           format to find

 *

 * Return Value:

 *  BOOL        TRUE if format is found in string,

 *              FALSE otherwise.

 */

BOOL FormatIncluded(LPSTR szStringToSearch, UINT wFormat)

{

   LPSTR        lpToken;

   char         seps[] = ",";

   static char  szFormat[255];  // max size of atom (what GetClipboardName returns)

   if (wFormat < 0xC000)             // RegisterClipboardFormat returns values

   _itoa(wFormat, szFormat, 10);  // between 0xC000 and 0xFFFF.

   else

   GetClipboardFormatName(wFormat, szFormat, 255);

   lpToken = (LPSTR)_fstrtok(szStringToSearch, seps);

   while (lpToken != NULL)

   {

 if (0 == lstrcmpi(lpToken, szFormat))

return TRUE;

 else

lpToken = (LPSTR)_fstrtok(NULL, seps);

   }

   return FALSE;

}

/*

 * UpdateCVClassIcon

 *

 * Purpose:

 *  Handles LBN_SELCHANGE for the Object Type listbox.  On a selection

 *  change, we extract an icon from the server handling the currently

 *  selected object type using the utility function HIconFromClass.

 *  Note that we depend on the behavior of FillClassList to stuff the

 *  object class after a tab in the listbox string that we hide from

 *  view (see WM_INITDIALOG).

 *

 * Parameters

 *  hDlg            HWND of the dialog box.

 *  lpCV            LPCONVERT pointing to the dialog structure

 *  hList           HWND of the Object Type listbox.

 *

 * Return Value:

 *  None

 */

void UpdateCVClassIcon(HWND hDlg, LPCONVERT lpCV, HWND hList)

{

UINT        iSel;

DWORD       cb;

HGLOBAL     hMem;

LPSTR       pszName, pszCLSID;

CLSID       clsid;

HICON       hIcon, hOldIcon;

UINT        cch, uWrapIndex;

RECT        LabelRect;

char        szLabel[OLEUI_CCHLABELMAX];

LPSTR       lpszLabel = szLabel;

HFONT       hFont;

HWND        hLabel1;

/*

 * When we change object type selection, get the new icon for that

 * type into our structure and update it in the display.

 */

iSel=(UINT)SendMessage(hList, LB_GETCURSEL, 0, 0L);

if (LB_ERR==(int)iSel)

return;

//Allocate a string to hold the entire listbox string

cb=SendMessage(hList, LB_GETTEXTLEN, iSel, 0L);

hMem=GlobalAlloc(GHND, cb+1);

if (NULL==hMem)

return;

pszName=GlobalLock(hMem);

// Get whole string

SendMessage(hList, LB_GETTEXT, iSel, (LONG)pszName);

// Set pointer to CLSID (string)

pszCLSID = PointerToNthField(pszName, 2, '\t');

//Create the class ID with this string.

CLSIDFromString((LPSTR)pszCLSID, (LPCLSID)&clsid);

hIcon = HIconAndSourceFromClass(&clsid, (LPSTR)(lpCV->lpszIconSource), &(lpCV->IconIndex));

if (NULL == hIcon)  // Use Vanilla Document

{

lstrcpy((LPSTR)(lpCV->lpszIconSource), (LPSTR)szOLE2DLL);

lpCV->IconIndex = 0;    // 1st icon in OLE2.DLL

hIcon = ExtractIcon(ghInst,

(LPSTR)(lpCV->lpszIconSource),

lpCV->IconIndex);

}

//Replace the current display with this new one.

hOldIcon = (HICON)SendDlgItemMessage(hDlg, IDCV_ICON, STM_SETICON, (WPARAM)hIcon, 0L);

hLabel1 = GetDlgItem(hDlg, IDCV_ICONLABEL1);

GetWindowRect(hLabel1, &LabelRect);

// Get the label

if (lpCV->lpOCV->lpszDefLabel) {

// width is used as 1.5 times width of icon window

lpszLabel = ChopText(hLabel1, ((LabelRect.right-LabelRect.left)*3)/2, (LPSTR)lpCV->lpOCV->lpszDefLabel);

LSTRCPYN(szLabel, lpCV->lpOCV->lpszDefLabel, sizeof(szLabel));

} else {

if ((cch = OleStdGetAuxUserType(&clsid, AUXUSERTYPE_SHORTNAME,

(LPSTR)szLabel, OLEUI_CCHLABELMAX, NULL)) == 0) {

// If we can't get the AuxUserType2, then try the long name

if ((cch = OleStdGetUserTypeOfClass(&clsid, (LPSTR)szLabel,

sizeof(szLabel), NULL)) == 0) {

// last resort; use "Document" as label

LoadString(ghInst,(UINT)IDS_DEFICONLABEL,(LPSTR)szLabel,sizeof(szLabel));

cch = lstrlen((LPSTR)szLabel);

}

}

}

hFont = (HFONT)SendMessage(hLabel1, WM_GETFONT, 0, 0L);

// Figure out where to split the label

uWrapIndex = OleStdIconLabelTextOut(NULL, hFont, 0, 0, 0, &LabelRect, (LPSTR)lpszLabel, cch, NULL);

if (0 == uWrapIndex)

{

   SendMessage(hLabel1, WM_SETTEXT, 0, (LPARAM)(LPSTR)lpszLabel);

   SendDlgItemMessage(hDlg, IDCV_ICONLABEL2, WM_SETTEXT, 0, (LPARAM)(LPSTR)"");

}

else

{

   char  chKeep;

   LPSTR lpszSecondLine;

   chKeep = szLabel[uWrapIndex];

   lpszLabel[uWrapIndex] = '\0';

   SendMessage(hLabel1, WM_SETTEXT, 0, (LPARAM)(LPSTR)lpszLabel);

   lpszLabel[uWrapIndex] = chKeep;

   lpszSecondLine = lpszLabel + uWrapIndex;

   SendDlgItemMessage(hDlg, IDCV_ICONLABEL2, WM_SETTEXT, 0, (LPARAM)lpszSecondLine);

}

// get rid of the old icon

if ((HICON)NULL != hOldIcon)

  DestroyIcon(hOldIcon);

GlobalUnlock(hMem);

GlobalFree(hMem);

return;

}

BOOL IsValidClassID(CLSID cID)

{

if (0 == _fmemcmp(&cID, &CLSID_NULL, sizeof(CLSID)))  // if (CLSID_NULL == cID)

  return FALSE;

else

  return TRUE;

}

/*

 * SetConvertResults

 *

 * Purpose:

 *  Centralizes setting of the Result display in the Convert

 *  dialog.  Handles loading the appropriate string from the module's

 *  resources and setting the text, displaying the proper result picture,

 *  and showing the proper icon.

 *

 * Parameters:

 *  hDlg            HWND of the dialog box so we can access controls.

 *  lpCV            LPCONVERT in which we assume that the dwFlags is

 *                  set to the appropriate radio button selection, and

 *                  the list box has the appropriate class selected.

 *

 * Return Value:

 *  None

 */

void SetConvertResults(HWND hDlg, LPCONVERT lpCV)

   {

LPSTR       pszT,        // temp

lpszOutput,  // text sent in SetDlgItemText

lpszDefObj,  // string containing default object class

lpszSelObj,  // string containing selected object class

lpszString;  // stirng we get from loadstring

UINT        i, cch;

HGLOBAL     hMem;

HWND        hList;  // handle to listbox (so we can just use SendMsg i

// instead of SendDlgItemMsg).

hList = lpCV->hListVisible;

/*

 * We need scratch memory for loading the stringtable string, loading

 * the object type from the listbox, loading the source object

 * type, and constructing the final string.  We therefore allocate

 * four buffers as large as the maximum message length (512) plus

 * the object type, guaranteeing that we have enough

 * in all cases.

 */

i=(UINT)SendMessage(hList, LB_GETCURSEL, 0, 0L);

cch=512+(UINT)SendMessage(hList, LB_GETTEXTLEN, i, 0L);

hMem=GlobalAlloc(GHND, (DWORD)(4*cch));

if (NULL==hMem)

return;

lpszOutput = (LPSTR)GlobalLock(hMem);

lpszSelObj = lpszOutput + cch;

lpszDefObj = lpszSelObj + cch;

lpszString = lpszDefObj + cch;

// Get selected object and null terminate human-readable name (1st field).

SendMessage(hList, LB_GETTEXT, i, (LONG)lpszSelObj);

pszT = PointerToNthField(lpszSelObj, 2, '\t');

pszT = AnsiPrev(lpszSelObj, pszT);

*pszT = '\0';

// Get default object

GetDlgItemText(hDlg, IDCV_OBJECTTYPE, lpszDefObj, 512);

//Default is an empty string.

*lpszOutput=0;

if (lpCV->dwFlags & CF_SELECTCONVERTTO)

{

if (lpCV->lpOCV->fIsLinkedObject)  // working with linked object

  LoadString(ghInst, (UINT)IDS_CVRESULTCONVERTLINK, lpszOutput, cch);

else

{

// converting to a new class

  if (0 != lstrcmp(lpszDefObj, lpszSelObj))

  {

if (0 != LoadString(ghInst, (UINT)IDS_CVRESULTCONVERTTO, lpszString, cch))

   wsprintf(lpszOutput, lpszString, lpszDefObj, lpszSelObj);

  }

  else  // converting to the same class (no conversion)

  {

 if (0 != LoadString(ghInst, (UINT)IDS_CVRESULTNOCHANGE, lpszString, cch))

   wsprintf(lpszOutput, lpszString, lpszDefObj);

  }

}

if (lpCV->dvAspect == DVASPECT_ICON)  // Display as icon is checked

{

   if (0 != LoadString(ghInst, (UINT)IDS_CVRESULTDISPLAYASICON, lpszString, cch))

lstrcat(lpszOutput, lpszString);

}

}

if (lpCV->dwFlags & CF_SELECTACTIVATEAS)

{

   if (0!=LoadString(ghInst, (UINT)IDS_CVRESULTACTIVATEAS, lpszString, cch))

  wsprintf(lpszOutput, lpszString, lpszDefObj, lpszSelObj);

   // activating as a new class

   if (0 != lstrcmp(lpszDefObj, lpszSelObj))

   {

  if (0!=LoadString(ghInst, (UINT)IDS_CVRESULTACTIVATEDIFF, lpszString, cch))

 lstrcat(lpszOutput, lpszString);

   }

   else // activating as itself.

   {

 lstrcat(lpszOutput, ".");

   }

}

//If LoadString failed, we simply clear out the results (*lpszOutput=0 above)

SetDlgItemText(hDlg, IDCV_RESULTTEXT, lpszOutput);

GlobalUnlock(hMem);

GlobalFree(hMem);

return;

}

/*

 * ConvertCleanup

 *

 * Purpose:

 *  Performs convert-specific cleanup before Convert termination.

 *

 * Parameters:

 *  hDlg            HWND of the dialog box so we can access controls.

 *

 * Return Value:

 *  None

 */

void ConvertCleanup(HWND hDlg, LPCONVERT lpCV)

{

   LPMALLOC pIMalloc;

   // Free our strings. Zero out the user type name string

   // the the calling app doesn't free to it.

   if (NOERROR == CoGetMalloc(MEMCTX_TASK, &pIMalloc))

   {

   pIMalloc->lpVtbl->Free(pIMalloc, (LPVOID)lpCV->lpszConvertDefault);

   pIMalloc->lpVtbl->Free(pIMalloc, (LPVOID)lpCV->lpszActivateDefault);

   pIMalloc->lpVtbl->Free(pIMalloc, (LPVOID)lpCV->lpszIconSource);

   if (lpCV->lpOCV->lpszUserType) {

   pIMalloc->lpVtbl->Free(pIMalloc,(LPVOID)lpCV->lpOCV->lpszUserType);

   lpCV->lpOCV->lpszUserType = NULL;

   }

   if (lpCV->lpOCV->lpszDefLabel) {

   pIMalloc->lpVtbl->Free(pIMalloc,(LPVOID)lpCV->lpOCV->lpszDefLabel);

   lpCV->lpOCV->lpszDefLabel = NULL;

   }

   pIMalloc->lpVtbl->Release(pIMalloc);

   }

   return;

}

/*

 * SwapWindows

 *

 * Purpose:

 *  Moves hWnd1 to hWnd2's position and hWnd2 to hWnd1's position.

 *  Does NOT change sizes.

 *

 *

 * Parameters:

 *  hDlg            HWND of the dialog box so we can turn redraw off

 *

 * Return Value:

 *  None

 */

void SwapWindows(HWND hDlg, HWND hWnd1, HWND hWnd2)

{

   RECT Rect1, Rect2;

   GetWindowRect(hWnd1, &Rect1);

   GetWindowRect(hWnd2, &Rect2);

   ScreenToClient(hDlg, (LPPOINT)&Rect1.left);

   ScreenToClient(hDlg, (LPPOINT)&Rect1.right);

   ScreenToClient(hDlg, (LPPOINT)&Rect2.left);

   ScreenToClient(hDlg, (LPPOINT)&Rect2.right);

   SetWindowPos(hWnd1,

NULL,

Rect2.left,

Rect2.top,

0,

0,

SWP_NOZORDER | SWP_NOSIZE);

   SetWindowPos(hWnd2,

NULL,

Rect1.left,

Rect1.top,

0,

0,

SWP_NOZORDER | SWP_NOSIZE);

   return;

}


DBALLOC.H  (WRAPUI Sample)

/***

*dballoc.h

*

*  Copyright (C) 1992-93, Microsoft Corporation.  All Rights Reserved.

*

*Purpose:

*  This file contains the definition of CDbAlloc - A debug implementation

*  of the IMalloc interface.

*

*Implementation Notes:

*

*****************************************************************************/

#ifndef DBALLOC_H_INCLUDED /* { */

#define DBALLOC_H_INCLUDED

interface IDbOutput : public IUnknown

{

STDMETHOD(QueryInterface)(THIS_ REFIID riid, void FAR* FAR* ppv) PURE;

STDMETHOD_(ULONG, AddRef)(THIS) PURE;

STDMETHOD_(ULONG, Release)(THIS) PURE;

STDMETHOD_(void, Printf)(THIS_

  char FAR* szFmt, ...) PURE;

STDMETHOD_(void, Assertion)(THIS_

  BOOL cond,

  char FAR* szExpr,

  char FAR* szFile,

  UINT uLine,

  char FAR* szMsg) PURE;

};

#endif /* } DBALLOC_H_INCLUDED */


DBALLOC.CPP  (WRAPUI Sample)

/***

*dballoc.cpp

*

*  Copyright (C) 1992-93, Microsoft Corporation.  All Rights Reserved.

*

*Purpose:

*  This file contains a debug implementation of the IMalloc interface.

*

*  This implementation is basically a simple wrapping of the C runtime,

*  with additional work to detect memory leakage, and memory overwrite.

*

*  Leakage is detected by tracking each allocation in an address

*  instance table, and then checking to see if the table is empty

*  when the last reference to the allocator is released.

*

*  Memory overwrite is detected by placing a signature at the end

*  of every allocated block, and checking to make sure the signature

*  is unchanged when the block is freed.

*

*  This implementation also has additional param validation code, as

*  well as additional check make sure that instances that are passed

*  to Free() were actually allocated by the corresponding instance

*  of the allocator.

*

*

*  Creating an instance of this debug allocator that uses the default

*  output interface would look like the following,

*

*

*  BOOL init_application_instance()

*  {

*    HRESULT hresult;

*    IMalloc FAR* pmalloc;

*

*    pmalloc = NULL;

*

*    if((hresult = OleStdCreateDbAlloc(0,&pmalloc))!=NOERROR)

*      goto LReturn;

*

*    hresult = OleInitialize(pmalloc);

*

*    // release pmalloc to let OLE hold the only ref to the it. later

*    // when OleUnitialize is called, memory leaks will be reported.

*    if(pmalloc != NULL)

*      pmalloc->Release();

*

*  LReturn:

*

*    return (hresult == NOERROR) ? TRUE : FALSE;

*  }

*

*

*  CONSIDER: could add an option to force error generation, something

*   like DBALLOC_ERRORGEN

*

*  CONSIDER: add support for heap-checking. say for example,

*   DBALLOC_HEAPCHECK would do a heapcheck every free? every 'n'

*   calls to free? ...

*

*

*Implementation Notes:

*

*  The method IMalloc::DidAlloc() is allowed to always return

*  "Dont Know" (-1).  This method is called by Ole, and they take

*  some appropriate action when they get this answer.

*

*****************************************************************************/

// Note: this file is designed to be stand-alone; it includes a

// carefully chosen, minimal set of headers.

//

// For conditional compilation we use the ole2 conventions,

//    _MAC      = mac

//    WIN32     = Win32 (NT really)

//    <nothing> = defaults to Win16

// REVIEW: the following needs to modified to handle _MAC

#define STRICT

#include <windows.h>

#include <ole2.h>

#if defined( __TURBOC__)

#define __STDC__ (1)

#endif

#define WINDLL  1           // make far pointer version of stdargs.h

#include <stdarg.h>

#if defined( __TURBOC__)

#undef __STDC__

#endif

#include <stdio.h>

#include <malloc.h>

#include <string.h>

#include <limits.h>

#include "dballoc.h"

extern "C" DWORD g_dwObjectCount; // since we don't include ole2ui.h

#define DIM(X) (sizeof(X)/sizeof((X)[0]))

#define UNREACHED 0

#if defined(WIN32)

# define MEMCMP(PV1, PV2, CB)   memcmp((PV1), (PV2), (CB))

# define MEMCPY(PV1, PV2, CB)   memcpy((PV1), (PV2), (CB))

# define MEMSET(PV,  VAL, CB)   memset((PV),  (VAL), (CB))

# define MALLOC(CB)     malloc(CB)

# define REALLOC(PV, CB)    realloc((PV), (CB))

# define FREE(PV)       free(PV)

# define HEAPMIN()

#elif defined(_MAC)

# define MEMCMP(PV1, PV2)   ERROR -- NYI

# define MEMCPY(PV1, PV2, CB)   ERROR -- NYI

# define MEMSET(PV,  VAL, CB)   ERROR -- NYI

# define MALLOC(CB)     ERROR -- NYI

# define REALLOC(PV, CB)    ERROR -- NYI

# define FREE(PV)       ERROR -- NYI

# define HEAPMIN()      ERROR -- NYI

#else

# define MEMCMP(PV1, PV2, CB)   _fmemcmp((PV1), (PV2), (CB))

# define MEMCPY(PV1, PV2, CB)   _fmemcpy((PV1), (PV2), (CB))

# define MEMSET(PV,  VAL, CB)   _fmemset((PV),  (VAL), (CB))

# define MALLOC(CB)     _fmalloc(CB)

# define REALLOC(PV, CB)    _frealloc(PV, CB)

# define FREE(PV)       _ffree(PV)

# define HEAPMIN()      _fheapmin()

#endif

/*************************************************************************

** DEBUG ASSERTION ROUTINES

*************************************************************************/

#ifdef DBG

#include <assert.h>

#define FnAssert(lpstrExpr, lpstrMsg, lpstrFileName, iLine)     \

        (_assert(lpstrMsg ? lpstrMsg : lpstrExpr,               \

                 lpstrFileName,                                 \

                 iLine), NOERROR)

#endif //DBG

#if defined( __TURBOC__ )

#define classmodel _huge

#else

#define classmodel FAR

#endif

class classmodel CStdDbOutput : public IDbOutput {

public:

static IDbOutput FAR* Create();

// IUnknown methods

STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppv);

STDMETHOD_(ULONG, AddRef)(void);

STDMETHOD_(ULONG, Release)(void);

// IDbOutput methods

STDMETHOD_(void, Printf)(char FAR* szFmt, ...);

STDMETHOD_(void, Assertion)(

  BOOL cond,

  char FAR* szExpr,

  char FAR* szFile,

  UINT uLine,

  char FAR* szMsg);

void FAR* operator new(size_t cb){

  return MALLOC(cb);

}

void operator delete(void FAR* pv){

  FREE(pv);

}

CStdDbOutput(){

  g_dwObjectCount++ ;

  m_refs = 0;

}

~CStdDbOutput() { g_dwObjectCount-- ; }

private:

ULONG m_refs;

char m_rgch[128]; // buffer for output formatting

};

//---------------------------------------------------------------------

//                implementation of the debug allocator

//---------------------------------------------------------------------

class FAR CAddrNode

{

public:

void FAR*      m_pv;    // instance

ULONG      m_cb;    // size of allocation in BYTES

ULONG          m_nAlloc;    // the allocation pass count

CAddrNode FAR* m_next;

void FAR* operator new(size_t cb){

  return MALLOC(cb);

}

void operator delete(void FAR* pv){

  FREE(pv);

}

};

class classmodel CDbAlloc : public IMalloc

{

public:

static HRESULT Create(

  ULONG options, IDbOutput FAR* pdbout, IMalloc FAR* FAR* ppmalloc);

// IUnknown methods

STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppv);

STDMETHOD_(ULONG, AddRef)(void);

STDMETHOD_(ULONG, Release)(void);

// IMalloc methods

STDMETHOD_(void FAR*, Alloc)(ULONG cb);

STDMETHOD_(void FAR*, Realloc)(void FAR* pv, ULONG cb);

STDMETHOD_(void, Free)(void FAR* pv);

STDMETHOD_(ULONG, GetSize)(void FAR* pv);

STDMETHOD_(int, DidAlloc)(void FAR* pv);

STDMETHOD_(void, HeapMinimize)(void);

void FAR* operator new(size_t cb){

  return MALLOC(cb);

}

void operator delete(void FAR* pv){

  FREE(pv);

}

CDbAlloc(){

  m_refs = 1;

  m_pdbout = NULL;

  m_cAllocCalls = 0;

  m_nBreakAtNthAlloc = 0;

  m_nBreakAtAllocSize = 0;

  MEMSET(m_rganode, 0, sizeof(m_rganode));

  g_dwObjectCount++ ;

}

~CDbAlloc() {   g_dwObjectCount-- ; }

private:

ULONG m_refs;

ULONG m_cAllocCalls;        // total count of allocation calls

ULONG m_nBreakAtNthAlloc;   // allocation number to break to debugger

//  this value should be set typically in the

//  debugger.

ULONG m_nBreakAtAllocSize;  // allocation size to break to debugger

//  this value should be set typically in the

//  debugger.

IDbOutput FAR* m_pdbout;        // output interface

CAddrNode FAR* m_rganode[64];   // address instance table

// instance table methods

BOOL IsEmpty(void);

void AddInst(void FAR* pv, ULONG nAlloc, ULONG cb);

void DelInst(void FAR* pv);

CAddrNode FAR* GetInst(void FAR* pv);

void DumpInst(CAddrNode FAR* pn);

void DumpInstTable(void);

inline UINT HashInst(void FAR* pv) const {

  return ((UINT)((ULONG)pv >> 4)) % DIM(m_rganode);

}

// output method(s)

inline void Assertion(

  BOOL cond,

  char FAR* szExpr,

  char FAR* szFile,

  UINT uLine,

  char FAR* szMsg)

{

  m_pdbout->Assertion(cond, szExpr, szFile, uLine, szMsg);

}

#define ASSERT(X) Assertion(X, #X, __FILE__, __LINE__, NULL)

#define ASSERTSZ(X, SZ) Assertion(X, #X, __FILE__, __LINE__, SZ)

static const unsigned char m_rgchSig[4];

};

const unsigned char CDbAlloc::m_rgchSig[] = { 0xDE, 0xAD, 0xBE, 0xEF };

/***

*HRESULT OleStdCreateDbAlloc(ULONG reserved, IMalloc** ppmalloc)

* Purpose:

*  Create an instance of CDbAlloc -- a debug implementation

*  of IMalloc.

*

* Parameters:

*   ULONG reserved              - reserved for future use. must be 0.

*   IMalloc FAR* FAR* ppmalloc  - (OUT) pointer to an IMalloc interface

*                                   of new debug allocator object

* Returns:

*   HRESULT

*       NOERROR         - if no error.

*       E_OUTOFMEMORY   - allocation failed.

*

***********************************************************************/

STDAPI OleStdCreateDbAlloc(ULONG reserved,IMalloc FAR* FAR* ppmalloc)

{

return CDbAlloc::Create(reserved, NULL, ppmalloc);

}

HRESULT

CDbAlloc::Create(

ULONG options,

IDbOutput FAR* pdbout,

IMalloc FAR* FAR* ppmalloc)

{

HRESULT hresult;

CDbAlloc FAR* pmalloc;

// default the instance of IDbOutput if the user didn't supply one

if(pdbout == NULL && ((pdbout = CStdDbOutput::Create()) == NULL)){

  hresult = ResultFromScode(E_OUTOFMEMORY);

  goto LError0;

}

pdbout->AddRef();

if((pmalloc = new FAR CDbAlloc()) == NULL){

  hresult = ResultFromScode(E_OUTOFMEMORY);

  goto LError1;

}

pmalloc->m_pdbout = pdbout;

*ppmalloc = pmalloc;

return NOERROR;

LError1:;

pdbout->Release();

LError0:;

return hresult;

}

STDMETHODIMP

CDbAlloc::QueryInterface(REFIID riid, void FAR* FAR* ppv)

{

if(riid == IID_IUnknown || riid == IID_IMalloc){

  *ppv = this;

  AddRef();

  return NOERROR;

}

return ResultFromScode(E_NOINTERFACE);

}

STDMETHODIMP_(ULONG)

CDbAlloc::AddRef()

{

return ++m_refs;

}

STDMETHODIMP_(ULONG)

CDbAlloc::Release()

{

if(--m_refs == 0){

  // check for memory leakage

  if(IsEmpty()){

  m_pdbout->Printf("No Memory Leaks.\n");

  }else{

  m_pdbout->Printf("Memory Leak Detected,\n");

  DumpInstTable();

  }

  m_pdbout->Release();

  delete this;

  return 0;

}

return m_refs;

}

STDMETHODIMP_(void FAR*)

CDbAlloc::Alloc(ULONG cb)

{

size_t size;

void FAR* pv;

++m_cAllocCalls;

if (m_nBreakAtNthAlloc && m_cAllocCalls == m_nBreakAtNthAlloc) {

ASSERTSZ(FALSE, "DBALLOC: NthAlloc Break target reached\r\n");

} else if (m_nBreakAtAllocSize && cb == m_nBreakAtAllocSize) {

ASSERTSZ(FALSE, "DBALLOC: AllocSize Break target reached\r\n");

}

// REVIEW: need to add support for huge allocations (on win16)

if((cb + sizeof(m_rgchSig)) > UINT_MAX)

  return NULL;

size = (size_t)cb;

if((pv = MALLOC(size + sizeof(m_rgchSig))) == NULL)

  return NULL;

// set allocated block to some non-zero value

MEMSET(pv, -1, size);

// put signature at end of allocated block

MEMCPY((char FAR*)pv + size, m_rgchSig, sizeof(m_rgchSig));

AddInst(pv, m_cAllocCalls, size);

return pv;

}

STDMETHODIMP_(void FAR*)

CDbAlloc::Realloc(void FAR* pv, ULONG cb)

{

size_t size;

// REVIEW: need to add support for huge realloc

if((cb + sizeof(m_rgchSig)) > UINT_MAX)

  return NULL;

if(pv == NULL){

  return Alloc(cb);

}

++m_cAllocCalls;

ASSERT(GetInst(pv) != NULL);

DelInst(pv);

if(cb == 0){

  Free(pv);

  return NULL;

}

size = (size_t)cb;

if((pv = REALLOC(pv, size + sizeof(m_rgchSig))) == NULL)

  return NULL;

// put signature at end of allocated block

MEMCPY((char FAR*)pv + size, m_rgchSig, sizeof(m_rgchSig));

AddInst(pv, m_cAllocCalls, size);

return pv;

}

STDMETHODIMP_(void)

CDbAlloc::Free(void FAR* pv)

{

CAddrNode FAR* pn;

static char szSigMsg[] = "Signature Check Failed";

if (pv == NULL) return;

pn = GetInst(pv);

// check for attempt to free an instance we didnt allocate

if(pn == NULL){

  ASSERTSZ(FALSE, "pointer freed by wrong allocator");

  return;

}

// verify the signature

if(MEMCMP((char FAR*)pv + pn->m_cb, m_rgchSig, sizeof(m_rgchSig)) != 0){

  m_pdbout->Printf(szSigMsg); m_pdbout->Printf("\n");

  DumpInst(GetInst(pv));

  ASSERTSZ(FALSE, szSigMsg);

}

// stomp on the contents of the block

MEMSET(pv, 0xCC, (size_t)pn->m_cb + sizeof(m_rgchSig));

DelInst(pv);

FREE(pv);

}

STDMETHODIMP_(ULONG)

CDbAlloc::GetSize(void FAR* pv)

{

CAddrNode FAR* pn;

pn = GetInst(pv);

if (pn == NULL) {

ASSERT(pn != NULL);

return 0;

}

return pn->m_cb;

}

/***

*PUBLIC HRESULT CDbAlloc::DidAlloc

*Purpose:

*  Answer if the given address belongs to a block allocated by

*  this allocator.

*

*Entry:

*  pv = the instance to lookup

*

*Exit:

*  return value = int

*    1 - did alloc

*    0 - did *not* alloc

*   -1 - dont know (according to the ole2 spec it is always legal

*        for the allocator to answer "dont know")

*

***********************************************************************/

STDMETHODIMP_(int)

CDbAlloc::DidAlloc(void FAR* pv)

{

return -1; // answer "I dont know"

}

STDMETHODIMP_(void)

CDbAlloc::HeapMinimize()

{

HEAPMIN();

}

//---------------------------------------------------------------------

//                      instance table methods

//---------------------------------------------------------------------

/***

*PRIVATE CDbAlloc::AddInst

*Purpose:

*  Add the given instance to the address instance table.

*

*Entry:

*  pv = the instance to add

*  nAlloc = the allocation passcount of this instance

*

*Exit:

*  None

*

***********************************************************************/

void

CDbAlloc::AddInst(void FAR* pv, ULONG nAlloc, ULONG cb)

{

UINT hash;

CAddrNode FAR* pn;

ASSERT(pv != NULL);

pn = (CAddrNode FAR*)new FAR CAddrNode();

if (pn == NULL) {

ASSERT(pn != NULL);

return;

}

pn->m_pv = pv;

pn->m_cb = cb;

pn->m_nAlloc = nAlloc;

hash = HashInst(pv);

pn->m_next = m_rganode[hash];

m_rganode[hash] = pn;

}

/***

*UNDONE

*Purpose:

*  Remove the given instance from the address instance table.

*

*Entry:

*  pv = the instance to remove

*

*Exit:

*  None

*

***********************************************************************/

void

CDbAlloc::DelInst(void FAR* pv)

{

CAddrNode FAR* FAR* ppn, FAR* pnDead;

for(ppn = &m_rganode[HashInst(pv)]; *ppn != NULL; ppn = &(*ppn)->m_next){

  if((*ppn)->m_pv == pv){

pnDead = *ppn;

*ppn = (*ppn)->m_next;

delete pnDead;

// make sure it doesnt somehow appear twice

ASSERT(GetInst(pv) == NULL);

return;

  }

}

// didnt find the instance

ASSERT(UNREACHED);

}

CAddrNode FAR*

CDbAlloc::GetInst(void FAR* pv)

{

CAddrNode FAR* pn;

for(pn = m_rganode[HashInst(pv)]; pn != NULL; pn = pn->m_next){

  if(pn->m_pv == pv)

return pn;

}

return NULL;

}

void

CDbAlloc::DumpInst(CAddrNode FAR* pn)

{

if (pn == NULL)

return;

m_pdbout->Printf("[0x%lx]  nAlloc=%ld  size=%ld\n",

  pn->m_pv, pn->m_nAlloc, GetSize(pn->m_pv));

}

/***

*PRIVATE BOOL IsEmpty

*Purpose:

*  Answer if the address instance table is empty.

*

*Entry:

*  None

*

*Exit:

*  return value = BOOL, TRUE if empty, FALSE otherwise

*

***********************************************************************/

BOOL

CDbAlloc::IsEmpty()

{

UINT u;

for(u = 0; u < DIM(m_rganode); ++u){

  if(m_rganode[u] != NULL)

return FALSE;

}

return TRUE;

}

/***

*PRIVATE CDbAlloc::Dump

*Purpose:

*  Print the current contents of the address instance table,

*

*Entry:

*  None

*

*Exit:

*  None

*

***********************************************************************/

void

CDbAlloc::DumpInstTable()

{

UINT u;

CAddrNode FAR* pn;

for(u = 0; u < DIM(m_rganode); ++u){

  for(pn = m_rganode[u]; pn != NULL; pn = pn->m_next){

  DumpInst(pn);

  }

}

}

//---------------------------------------------------------------------

//                implementation of CStdDbOutput

//---------------------------------------------------------------------

IDbOutput FAR*

CStdDbOutput::Create()

{

return (IDbOutput FAR*)new FAR CStdDbOutput();

}

STDMETHODIMP

CStdDbOutput::QueryInterface(REFIID riid, void FAR* FAR* ppv)

{

if(riid == IID_IUnknown){

  *ppv = this;

  AddRef();

  return NOERROR;

}

return ResultFromScode(E_NOINTERFACE);

}

STDMETHODIMP_(ULONG)

CStdDbOutput::AddRef()

{

return ++m_refs;

}

STDMETHODIMP_(ULONG)

CStdDbOutput::Release()

{

if(--m_refs == 0){

  delete this;

  return 0;

}

return m_refs;

}

STDMETHODIMP_(void)

CStdDbOutput::Printf(char FAR* lpszFmt, ...)

{

va_list args;

char szBuf[256];

#if defined( OBSOLETE )

char *pn, FAR* pf;

static char rgchFmtBuf[128];

static char rgchOutputBuf[128];

// copy the 'far' format string to a near buffer so we can use

// a medium model vsprintf, which only supports near data pointers.

//

pn = rgchFmtBuf, pf=szFmt;

while(*pf != '\0')

  *pn++ = *pf++;

*pn = '\0';

#endif

va_start(args, lpszFmt);

//    wvsprintf(rgchOutputBuf, rgchFmtBuf, args);

wvsprintf(szBuf, lpszFmt, args);

OutputDebugString(szBuf);

}

STDMETHODIMP_(void)

CStdDbOutput::Assertion(

BOOL cond,

char FAR* szExpr,

char FAR* szFile,

UINT uLine,

char FAR* szMsg)

{

if(cond)

  return;

#ifdef _DEBUG

// following is from compobj.dll (ole2)

FnAssert(szExpr, szMsg, szFile, uLine);

#else

// REVIEW: should be able to do something better that this...

DebugBreak();

#endif

}


DBGUTIL.C  (WRAPUI Sample)

/*************************************************************************

**

**    OLE 2.0 Common Utilities

**

**    dbgutil.h

**

**    This file contains file contains functions to support debug output.

**

**    (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved

**

*************************************************************************/

#define STRICT  1

#include "ole2ui.h"

static int s_nDbgIndent = 0;        // indent level for debug message

#if defined( _DEBUG )

static int s_nDbgLevel = 0;   // default dbg level printed

#else

static int s_nDbgLevel = 0;   // default dbg level printed

#endif

STDAPI_(void) OleDbgPrint(

                int     nDbgLvl,

                LPSTR   lpszPrefix,

                LPSTR   lpszMsg,

                int     nIndent

)

{

        if (nDbgLvl <= s_nDbgLevel)

                OleDbgPrintAlways(lpszPrefix, lpszMsg, nIndent);

}

STDAPI_(void) OleDbgPrintAlways(LPSTR lpszPrefix, LPSTR lpszMsg, int nIndent)

{

        int i;

        if (nIndent < 0)

                OleDbgIndent(nIndent);

        if (lpszPrefix && *lpszPrefix != '\0') {

                OutputDebugString("| ");

                for (i = 0; i < s_nDbgIndent; i++)

                        OutputDebugString("----");

                OutputDebugString(lpszPrefix);

                OutputDebugString(": ");

        }

        OutputDebugString(lpszMsg);

        if (nIndent > 0)

                OleDbgIndent(nIndent);

}

STDAPI_(void) OleDbgSetDbgLevel(int nDbgLvl)

{

        s_nDbgLevel = nDbgLvl;

}

STDAPI_(int) OleDbgGetDbgLevel( void )

{

        return s_nDbgLevel;

}

STDAPI_(void) OleDbgIndent(int n)

{

        switch (n) {

                case -1:

                        s_nDbgIndent--;

                        break;

                case 1:

                        s_nDbgIndent++;

                        break;

                case -2:

                        s_nDbgIndent = 0;

                        break;

        }

}

STDAPI_(void) OleDbgPrintRefCnt(

                int         nDbgLvl,

                LPSTR       lpszPrefix,

                LPSTR       lpszMsg,

                LPVOID      lpObj,

                ULONG       refcnt

)

{

        if (nDbgLvl <= s_nDbgLevel)

                OleDbgPrintRefCntAlways(lpszPrefix, lpszMsg, lpObj, refcnt);

}

STDAPI_(void) OleDbgPrintRefCntAlways(

                LPSTR       lpszPrefix,

                LPSTR       lpszMsg,

                LPVOID      lpObj,

                ULONG       refcnt

)

{

#if defined( _DEBUG )

        char szBuf[256];

        wsprintf(szBuf, "[obj=(0x%lx) cnt=%ld] %s", lpObj, refcnt, lpszMsg);

        OleDbgPrintAlways(lpszPrefix, szBuf, 0);

#endif

}

STDAPI_(void) OleDbgPrintRect(

                int         nDbgLvl,

                LPSTR       lpszPrefix,

                LPSTR       lpszMsg,

                LPRECT      lpRect

)

{

        if (nDbgLvl <= s_nDbgLevel)

                OleDbgPrintRectAlways(lpszPrefix, lpszMsg, lpRect);

}

STDAPI_(void) OleDbgPrintRectAlways(

                LPSTR       lpszPrefix,

                LPSTR       lpszMsg,

                LPRECT      lpRect

)

{

#if defined( _DEBUG )

        char szBuf[256];

        wsprintf(

                        szBuf,

                        "%s: (%d,%d)-(%d,%d) %dx%d\r\n",

                        lpszMsg,

                        lpRect->left,

                        lpRect->top,

                        lpRect->right,

                        lpRect->bottom,

                        (lpRect->right-lpRect->left),

                        (lpRect->bottom-lpRect->top)

        );

        OleDbgPrintAlways(lpszPrefix, szBuf, 0);

#endif

}

#define CASE_SCODE(sc)  \

                case sc: \

                        lstrcpy((LPSTR)szErrName, (LPSTR)#sc); \

                        break;

STDAPI_(void) OleDbgPrintScodeAlways(LPSTR lpszPrefix, LPSTR lpszMsg, SCODE sc)

{

#if defined( _DEBUG )

        char szBuf[256];

        char szErrName[40];

        switch (sc) {

                /* SCODE's defined in SCODE.H */

                CASE_SCODE(S_OK)

                CASE_SCODE(S_FALSE)

                CASE_SCODE(E_UNEXPECTED)

                CASE_SCODE(E_OUTOFMEMORY)

                CASE_SCODE(E_INVALIDARG)

                CASE_SCODE(E_NOINTERFACE)

                CASE_SCODE(E_POINTER)

                CASE_SCODE(E_HANDLE)

                CASE_SCODE(E_ABORT)

                CASE_SCODE(E_FAIL)

                CASE_SCODE(E_ACCESSDENIED)

                /* SCODE's defined in OLE2.H */

                CASE_SCODE(OLE_E_OLEVERB)

                CASE_SCODE(OLE_E_ADVF)

                CASE_SCODE(OLE_E_ENUM_NOMORE)

                CASE_SCODE(OLE_E_ADVISENOTSUPPORTED)

                CASE_SCODE(OLE_E_NOCONNECTION)

                CASE_SCODE(OLE_E_NOTRUNNING)

                CASE_SCODE(OLE_E_NOCACHE)

                CASE_SCODE(OLE_E_BLANK)

                CASE_SCODE(OLE_E_CLASSDIFF)

                CASE_SCODE(OLE_E_CANT_GETMONIKER)

                CASE_SCODE(OLE_E_CANT_BINDTOSOURCE)

                CASE_SCODE(OLE_E_STATIC)

                CASE_SCODE(OLE_E_PROMPTSAVECANCELLED)

                CASE_SCODE(OLE_E_INVALIDRECT)

                CASE_SCODE(OLE_E_WRONGCOMPOBJ)

                CASE_SCODE(OLE_E_INVALIDHWND)

                CASE_SCODE(OLE_E_NOT_INPLACEACTIVE)

                CASE_SCODE(OLE_E_CANTCONVERT)

                CASE_SCODE(OLE_E_NOSTORAGE)

                CASE_SCODE(DV_E_FORMATETC)

                CASE_SCODE(DV_E_DVTARGETDEVICE)

                CASE_SCODE(DV_E_STGMEDIUM)

                CASE_SCODE(DV_E_STATDATA)

                CASE_SCODE(DV_E_LINDEX)

                CASE_SCODE(DV_E_TYMED)

                CASE_SCODE(DV_E_CLIPFORMAT)

                CASE_SCODE(DV_E_DVASPECT)

                CASE_SCODE(DV_E_DVTARGETDEVICE_SIZE)

                CASE_SCODE(DV_E_NOIVIEWOBJECT)

                CASE_SCODE(OLE_S_USEREG)

                CASE_SCODE(OLE_S_STATIC)

                CASE_SCODE(OLE_S_MAC_CLIPFORMAT)

                CASE_SCODE(CONVERT10_E_OLESTREAM_GET)

                CASE_SCODE(CONVERT10_E_OLESTREAM_PUT)

                CASE_SCODE(CONVERT10_E_OLESTREAM_FMT)

                CASE_SCODE(CONVERT10_E_OLESTREAM_BITMAP_TO_DIB)

                CASE_SCODE(CONVERT10_E_STG_FMT)

                CASE_SCODE(CONVERT10_E_STG_NO_STD_STREAM)

                CASE_SCODE(CONVERT10_E_STG_DIB_TO_BITMAP)

                CASE_SCODE(CONVERT10_S_NO_PRESENTATION)

                CASE_SCODE(CLIPBRD_E_CANT_OPEN)

                CASE_SCODE(CLIPBRD_E_CANT_EMPTY)

                CASE_SCODE(CLIPBRD_E_CANT_SET)

                CASE_SCODE(CLIPBRD_E_BAD_DATA)

                CASE_SCODE(CLIPBRD_E_CANT_CLOSE)

                CASE_SCODE(DRAGDROP_E_NOTREGISTERED)

                CASE_SCODE(DRAGDROP_E_ALREADYREGISTERED)

                CASE_SCODE(DRAGDROP_E_INVALIDHWND)

                CASE_SCODE(DRAGDROP_S_DROP)

                CASE_SCODE(DRAGDROP_S_CANCEL)

                CASE_SCODE(DRAGDROP_S_USEDEFAULTCURSORS)

                CASE_SCODE(OLEOBJ_E_NOVERBS)

                CASE_SCODE(OLEOBJ_E_INVALIDVERB)

                CASE_SCODE(OLEOBJ_S_INVALIDVERB)

                CASE_SCODE(OLEOBJ_S_CANNOT_DOVERB_NOW)

                CASE_SCODE(OLEOBJ_S_INVALIDHWND)

                CASE_SCODE(INPLACE_E_NOTUNDOABLE)

                CASE_SCODE(INPLACE_E_NOTOOLSPACE)

                CASE_SCODE(INPLACE_S_TRUNCATED)

                /* SCODE's defined in COMPOBJ.H */

                CASE_SCODE(CO_E_NOTINITIALIZED)

                CASE_SCODE(CO_E_ALREADYINITIALIZED)

                CASE_SCODE(CO_E_CANTDETERMINECLASS)

                CASE_SCODE(CO_E_CLASSSTRING)

                CASE_SCODE(CO_E_IIDSTRING)

                CASE_SCODE(CO_E_APPNOTFOUND)

                CASE_SCODE(CO_E_APPSINGLEUSE)

                CASE_SCODE(CO_E_ERRORINAPP)

                CASE_SCODE(CO_E_DLLNOTFOUND)

                CASE_SCODE(CO_E_ERRORINDLL)

                CASE_SCODE(CO_E_WRONGOSFORAPP)

                CASE_SCODE(CO_E_OBJNOTREG)

                CASE_SCODE(CO_E_OBJISREG)

                CASE_SCODE(CO_E_OBJNOTCONNECTED)

                CASE_SCODE(CO_E_APPDIDNTREG)

                CASE_SCODE(CLASS_E_NOAGGREGATION)

                CASE_SCODE(CLASS_E_CLASSNOTAVAILABLE)

                CASE_SCODE(REGDB_E_READREGDB)

                CASE_SCODE(REGDB_E_WRITEREGDB)

                CASE_SCODE(REGDB_E_KEYMISSING)

                CASE_SCODE(REGDB_E_INVALIDVALUE)

                CASE_SCODE(REGDB_E_CLASSNOTREG)

                CASE_SCODE(REGDB_E_IIDNOTREG)

                CASE_SCODE(RPC_E_CALL_REJECTED)

                CASE_SCODE(RPC_E_CALL_CANCELED)

                CASE_SCODE(RPC_E_CANTPOST_INSENDCALL)

                CASE_SCODE(RPC_E_CANTCALLOUT_INASYNCCALL)

                CASE_SCODE(RPC_E_CANTCALLOUT_INEXTERNALCALL)

                CASE_SCODE(RPC_E_CONNECTION_TERMINATED)

                CASE_SCODE(RPC_E_SERVER_DIED)

                CASE_SCODE(RPC_E_CLIENT_DIED)

                CASE_SCODE(RPC_E_INVALID_DATAPACKET)

                CASE_SCODE(RPC_E_CANTTRANSMIT_CALL)

                CASE_SCODE(RPC_E_CLIENT_CANTMARSHAL_DATA)

                CASE_SCODE(RPC_E_CLIENT_CANTUNMARSHAL_DATA)

                CASE_SCODE(RPC_E_SERVER_CANTMARSHAL_DATA)

                CASE_SCODE(RPC_E_SERVER_CANTUNMARSHAL_DATA)

                CASE_SCODE(RPC_E_INVALID_DATA)

                CASE_SCODE(RPC_E_INVALID_PARAMETER)

//                CASE_SCODE(RPC_E_CANTCALLOUT_AGAIN)

                CASE_SCODE(RPC_E_UNEXPECTED)

                /* SCODE's defined in DVOBJ.H */

                CASE_SCODE(DATA_S_SAMEFORMATETC)

                CASE_SCODE(VIEW_E_DRAW)

                CASE_SCODE(VIEW_S_ALREADY_FROZEN)

                CASE_SCODE(CACHE_E_NOCACHE_UPDATED)

                CASE_SCODE(CACHE_S_FORMATETC_NOTSUPPORTED)

                CASE_SCODE(CACHE_S_SAMECACHE)

                CASE_SCODE(CACHE_S_SOMECACHES_NOTUPDATED)

                /* SCODE's defined in STORAGE.H */

                CASE_SCODE(STG_E_INVALIDFUNCTION)

                CASE_SCODE(STG_E_FILENOTFOUND)

                CASE_SCODE(STG_E_PATHNOTFOUND)

                CASE_SCODE(STG_E_TOOMANYOPENFILES)

                CASE_SCODE(STG_E_ACCESSDENIED)

                CASE_SCODE(STG_E_INVALIDHANDLE)

                CASE_SCODE(STG_E_INSUFFICIENTMEMORY)

                CASE_SCODE(STG_E_INVALIDPOINTER)

                CASE_SCODE(STG_E_NOMOREFILES)

                CASE_SCODE(STG_E_DISKISWRITEPROTECTED)

                CASE_SCODE(STG_E_SEEKERROR)

                CASE_SCODE(STG_E_WRITEFAULT)

                CASE_SCODE(STG_E_READFAULT)

                CASE_SCODE(STG_E_SHAREVIOLATION)

                CASE_SCODE(STG_E_LOCKVIOLATION)

                CASE_SCODE(STG_E_FILEALREADYEXISTS)

                CASE_SCODE(STG_E_INVALIDPARAMETER)

                CASE_SCODE(STG_E_MEDIUMFULL)

                CASE_SCODE(STG_E_ABNORMALAPIEXIT)

                CASE_SCODE(STG_E_INVALIDHEADER)

                CASE_SCODE(STG_E_INVALIDNAME)

                CASE_SCODE(STG_E_UNKNOWN)

                CASE_SCODE(STG_E_UNIMPLEMENTEDFUNCTION)

                CASE_SCODE(STG_E_INVALIDFLAG)

                CASE_SCODE(STG_E_INUSE)

                CASE_SCODE(STG_E_NOTCURRENT)

                CASE_SCODE(STG_E_REVERTED)

                CASE_SCODE(STG_E_CANTSAVE)

                CASE_SCODE(STG_E_OLDFORMAT)

                CASE_SCODE(STG_E_OLDDLL)

                CASE_SCODE(STG_E_SHAREREQUIRED)

                CASE_SCODE(STG_E_NOTFILEBASEDSTORAGE)

                CASE_SCODE(STG_E_EXTANTMARSHALLINGS)

                CASE_SCODE(STG_S_CONVERTED)

                /* SCODE's defined in MONIKER.H */

                CASE_SCODE(MK_E_CONNECTMANUALLY)

                CASE_SCODE(MK_E_EXCEEDEDDEADLINE)

                CASE_SCODE(MK_E_NEEDGENERIC)

                CASE_SCODE(MK_E_UNAVAILABLE)

                CASE_SCODE(MK_E_SYNTAX)

                CASE_SCODE(MK_E_NOOBJECT)

                CASE_SCODE(MK_E_INVALIDEXTENSION)

                CASE_SCODE(MK_E_INTERMEDIATEINTERFACENOTSUPPORTED)

                CASE_SCODE(MK_E_NOTBINDABLE)

                CASE_SCODE(MK_E_NOTBOUND)

                CASE_SCODE(MK_E_CANTOPENFILE)

                CASE_SCODE(MK_E_MUSTBOTHERUSER)

                CASE_SCODE(MK_E_NOINVERSE)

                CASE_SCODE(MK_E_NOSTORAGE)

                CASE_SCODE(MK_E_NOPREFIX)

                CASE_SCODE(MK_S_REDUCED_TO_SELF)

                CASE_SCODE(MK_S_ME)

                CASE_SCODE(MK_S_HIM)

                CASE_SCODE(MK_S_US)

                CASE_SCODE(MK_S_MONIKERALREADYREGISTERED)

                default:

                        lstrcpy(szErrName, "UNKNOWN SCODE");

        }

        wsprintf(szBuf, "%s %s (0x%lx)\n", lpszMsg, (LPSTR)szErrName, sc);

        OleDbgPrintAlways(lpszPrefix, szBuf, 0);

#endif  // _DEBUG

}

//+------------------------------------------------------------

// Function:    PopUpError

//

// Synopsis:    Displays a dialog box using provided text,

//              and presents the user with the option to

//              continue or cancel.

//

// Arguments:

//      szMsg --        The string to display in main body of dialog

//      iLine --        Line number of file in error

//      szFile --       Filename of file in error

//

// Returns:

//      IDCANCEL --     User selected the CANCEL button

//      IDOK     --     User selected the OK button

//-------------------------------------------------------------

STDAPI_(int)

PopUpError(

    char const *szMsg,

    int iLine,

    char const *szFile)

{

    int id;

    static char szAssertCaption[100];

#ifdef FLAT

    DWORD tid = GetCurrentThreadId();

    wsprintf(szAssertCaption,"File: %s line %u, thread id %d",

        szFile, iLine, tid);

#else  // FLAT

    wsprintf(szAssertCaption,"File: %s line %u",szFile,iLine);

#endif // FLAT

    id = MessageBoxA(NULL,

                     (char *) szMsg,

                     (LPSTR) szAssertCaption,

                     MB_SETFOREGROUND |

                     MB_TASKMODAL | MB_ICONEXCLAMATION | MB_OKCANCEL);

    return id;

}

STDAPI_(void)

Win4AssertEx(

    char const * szFile,

    int iLine,

    char const * szMessage)

{

    int id = PopUpError(szMessage,iLine,szFile);

        if (id == IDCANCEL)

        {

#ifdef FLAT

            DebugBreak();

#else

            _asm int 3;

#endif

        }

}


DEBUG.H  (WRAPUI Sample)

/*

 * DEBUG.H

 *

 * Definitions, structures, types, and function prototypes for debugging

 * purposes.

 *

 * Copyright (c)1992 Microsoft Corporation, All Right Reserved,

 * as applied to redistribution of this source code in source form

 * License is granted to use of compiled code in shipped binaries.

 */

#ifndef _DEBUG_H_

#define _DEBUG_H_

#ifdef DEBUG

//Basic debug macros

#define D(x)        {x;}

#define ODS(x)      D(OutputDebugString(x);OutputDebugString("\r\n"))

#define ODSsz(f, s)  {\

 char        szDebug[128];\

 wsprintf(szDebug, f, (LPSTR)s);\

 ODS(szDebug);\

 }

#define ODSu(f, u)  {\

char        szDebug[128];\

wsprintf(szDebug, f, (UINT)u);\

ODS(szDebug);\

}

#define ODSlu(f, lu) {\

 char        szDebug[128];\

 wsprintf(szDebug, f, (DWORD)lu);\

 ODS(szDebug);\

 }

#define ODSszu(f, s, u) {\

char        szDebug[128];\

wsprintf(szDebug, f, (LPSTR)s, (UINT)u);\

ODS(szDebug);\

}

#define ODSszlu(f, s, lu) {\

  char        szDebug[128];\

  wsprintf(szDebug, f, (LPSTR)s, (DWORD)lu);\

  ODS(szDebug);\

  }

#else   //NO DEBUG

#define D(x)

#define ODS(x)

#define ODSsz(f, s)

#define ODSu(f, u)

#define ODSlu(f, lu)

#define ODSszu(f, s, u)

#define ODSszlu(f, s, lu)

#endif //DEBUG

#endif //_DEBUG_H_


DLLFUNCS.C  (WRAPUI Sample)

/*

 * DLLFUNCS.C

 *

 * Contains entry and exit points for the DLL implementation

 * of the OLE 2.0 User Interface Support Library.

 *

 * This file is not needed if we are linking the static library

 * version of this library.

 *

 * Copyright (c)1992 Microsoft Corporation, All Right Reserved

 */

#define STRICT  1

#include "ole2ui.h"

#include "common.h"

OLEDBGDATA

/*

 * LibMain

 *

 * Purpose:

 *  DLL-specific entry point called from LibEntry.  Initializes

 *  the DLL's heap and registers the GizmoBar GizmoBar.

 *

 * Parameters:

 *  hInst           HINSTANCE instance of the DLL.

 *  wDataSeg        WORD segment selector of the DLL's data segment.

 *  wHeapSize       WORD byte count of the heap.

 *  lpCmdLine       LPSTR to command line used to start the module.

 *

 * Return Value:

 *  HANDLE          Instance handle of the DLL.

 *

 */

#ifdef WIN32

int CALLBACK WEP(int);

BOOL WINAPI DllMain

(

HINSTANCE hInst,

ULONG Reason,

PCONTEXT Context

)

{

UNREFERENCED_PARAMETER(Context);

if (Reason == DLL_PROCESS_DETACH)

    WEP(0);

// Initialize OLE UI libraries.  If you're linking with the static LIB

// version of this library, you need to make a call to OleUIInitialize

// explicitly in your application (because this LibMain won't be executed)

    if (Reason == DLL_PROCESS_ATTACH)

    OleUIInitialize(hInst, (HINSTANCE)0);

return TRUE;

}

#else

int FAR PASCAL LibMain(HINSTANCE hInst, WORD wDataSeg

  , WORD cbHeapSize, LPSTR lpCmdLine)

{

OleDbgOut2("LibMain: OLE2UI.DLL loaded\r\n");

// Initialize OLE UI libraries.  If you're linking with the static LIB version

// of this library, you need to make the below call in your application (because

// this LibMain won't be executed).

// The symbol LIBNAME is defined on the compiler command line

OleUIInitialize(hInst, (HINSTANCE)0);

//All done...

if (0!=cbHeapSize)

UnlockData(0);

return (int)hInst;

}

#endif

/*

 * WEP

 *

 * Purpose:

 *  Required DLL Exit function.

 *

 * Parameters:

 *  bSystemExit     BOOL indicating if the system is being shut

 *                  down or the DLL has just been unloaded.

 *

 * Return Value:

 *  void

 *

 */

int CALLBACK EXPORT WEP(int bSystemExit)

{

OleUIUnInitialize();

return 0;

}

/*

 * DllCanUnloadNow

 *

 * Purpose:

 *   Determines when it is safe to go away.

 *

 * Return Value:

 *   HRESULT    NOERROR it is safe to go away, S_FALSE this code must stay

 *              loaded.

 *

 */

STDAPI DllCanUnloadNow(void)

{

return OleUICanUnloadNow();

}

/*

 * OleUILockLibrary

 *

 *

 * Purpose:

 *   Increments & decrements a lock count to force this library to stay

 *   alive, all OLE 2.x DLL objects servers (ie. INPROC server DLL) which

 *   use the OLE2UI library in a DLL form must call this function passing TRUE

 *   in their InitInstance() routine and balance with a call, passing FALSE

 *   in their ExitInstance(). This is done so as to keep DllCanUnloadNow()

 *   from returning NOERROR until the OLE 2.x DLL server goes away.

 *   While the INPROC server DLL is loaded, it wants to force the OLE2UI

 *   DLL to remain loaded (ie. force it to return S_FALSE from the OLE2UI's

 *   DllCanUnloadNow function). It is possible that the INROC server DLL

 *   gets unloaded from a call to CoFreeUnusedLibraries, but it is still

 *   necessary for the OLE2UI library to remain in use (eg. because an

 *   enumerator returned from OleStdEnumFmtEtc_Create still exists). only

 *   after all explicit "OleUILockLibrary" locks and instances of objects

 *   created have been release will the DllCanUnloadNow function for the

 *   OLE2UI library DLL return NOERROR.

 *

 *   If the INPROC server DLL links to the OLE2UI library as a static

 *   library, then this OleUILockLibrary function should NOT be used.

 *   instead the INPROC server DLL should call OleUICanUnloadNow API from

 *   within its own DllCanUnloadNow function. The idea here is, that if there

 *   are any existing instance of objects created by the OLE2UI library

 *   functions (eg. EnumFORMATETC objects created by OleStdEnumFmtEtc_Create)

 *   then, the INPROC server DLL must NOT let itself be unloaded.

 *

 *   An EXE based object using the OLE2UI libray need NOT use either the

 *   OleUILockLibrary or OleUICanUnloadNow functions. All objects created

 *   by the OLE2UI library will have LRPC proxies and stubs created to

 *   manage remoting method calls. the worst that can happen when the EXE

 *   exits is that any outstanding proxies for unreleased objects will get

 *   RPC_E_SERVERDIED errors; they will not GPFault.

 *

 * Return Value:

 *   HRESULT    NOERROR it is safe to go away, S_FALSE this code must stay

 *              loaded.

 */

STDAPI OleUILockLibrary(BOOL fLock)

{

  HRESULT hRes = NOERROR;

  if (fLock == TRUE) {

if ((DWORD)CoLoadLibrary("ole2ui" ".dll", TRUE) != NOERROR) {

  g_dwObjectCount ++;

}else{

  hRes = ResultFromScode(CO_E_DLLNOTFOUND);

}

  }else{

g_dwObjectCount --;

  }

  return hRes;

}


DRAWICON.C  (WRAPUI Sample)

/*

 * DRAWICON.C

 *

 * Functions to handle creation of metafiles with icons and labels

 * as well as functions to draw such metafiles with or without the label.

 *

 * The metafile is created with a comment that marks the records containing

 * the label code.  Drawing the metafile enumerates the records, draws

 * all records up to that point, then decides to either skip the label

 * or draw it.

 *

 * Copyright (c)1992 Microsoft Corporation, All Right Reserved

 */

#define STRICT  1

#include "ole2ui.h"

#include "common.h"

#include "utility.h"

#include "geticon.h"

/*

 * Strings for metafile comments.  KEEP THESE IN SYNC WITH THE

 * STRINGS IN GETICON.C.

 */

static char szIconOnly[]="IconOnly";        //Where to stop to exclude label.

/*

 * OleUIMetafilePictIconFree

 *

 * Purpose:

 *  Deletes the metafile contained in a METAFILEPICT structure and

 *  frees the memory for the structure itself.

 *

 * Parameters:

 *  hMetaPict       HGLOBAL metafilepict structure created in

 *                  OleUIMetafilePictFromIconAndLabel

 *

 * Return Value:

 *  None

 */

STDAPI_(void) OleUIMetafilePictIconFree(HGLOBAL hMetaPict)

{

LPMETAFILEPICT      pMF;

if (NULL==hMetaPict)

return;

pMF=(LPMETAFILEPICT)GlobalLock(hMetaPict);

if (NULL!=pMF)

{

if (NULL!=pMF->hMF)

DeleteMetaFile(pMF->hMF);

}

GlobalUnlock(hMetaPict);

GlobalFree(hMetaPict);

return;

}

/*

 * OleUIMetafilePictIconDraw

 *

 * Purpose:

 *  Draws the metafile from OleUIMetafilePictFromIconAndLabel, either with

 *  the label or without.

 *

 * Parameters:

 *  hDC             HDC on which to draw.

 *  pRect           LPRECT in which to draw the metafile.

 *  hMetaPict       HGLOBAL to the METAFILEPICT from

 *                  OleUIMetafilePictFromIconAndLabel

 *  fIconOnly       BOOL specifying to draw the label or not.

 *

 * Return Value:

 *  BOOL            TRUE if the function is successful, FALSE if the

 *                  given metafilepict is invalid.

 */

STDAPI_(BOOL) OleUIMetafilePictIconDraw(HDC hDC, LPRECT pRect, HGLOBAL hMetaPict

  , BOOL fIconOnly)

{

LPMETAFILEPICT  pMF;

DRAWINFO        di;

int             cx, cy;

SIZE            size;

POINT           point;

if (NULL==hMetaPict)

return FALSE;

pMF=GlobalLock(hMetaPict);

if (NULL==pMF)

return FALSE;

di.Rect = *pRect;

di.fIconOnly = fIconOnly;

//Transform to back to pixels

cx=XformWidthInHimetricToPixels(hDC, pMF->xExt);

cy=XformHeightInHimetricToPixels(hDC, pMF->yExt);

SaveDC(hDC);

SetMapMode(hDC, pMF->mm);

SetViewportOrgEx(hDC, (pRect->right - cx) / 2, 0, &point);

SetViewportExtEx(hDC, min ((pRect->right - cx) / 2 + cx, cx), cy, &size);

if (fIconOnly)

{

// Since we've used the __export keyword on the

// EnumMetafileIconDraw proc, we do not need to use

// MakeProcInstance

EnumMetaFile(hDC, pMF->hMF, (MFENUMPROC)EnumMetafileIconDraw

, (LPARAM)(LPDRAWINFO)&di);

}

else

   PlayMetaFile(hDC, pMF->hMF);

RestoreDC(hDC, -1);

GlobalUnlock(hMetaPict);

return TRUE;

}

/*

 * EnumMetafileIconDraw

 *

 * Purpose:

 *  EnumMetaFile callback function that draws either the icon only or

 *  the icon and label depending on given flags.

 *

 * Parameters:

 *  hDC             HDC into which the metafile should be played.

 *  phTable         HANDLETABLE FAR * providing handles selected into the DC.

 *  pMFR            METARECORD FAR * giving the enumerated record.

 *  lParam          LPARAM flags passed in EnumMetaFile.

 *

 * Return Value:

 *  int             0 to stop enumeration, 1 to continue.

 */

int CALLBACK EXPORT EnumMetafileIconDraw(HDC hDC, HANDLETABLE FAR *phTable

, METARECORD FAR *pMFR, int cObj, LPARAM lParam)

{

LPDRAWINFO lpdi = (LPDRAWINFO)lParam;

/*

 * We play everything blindly except for DIBBITBLT (or DIBSTRETCHBLT)

 * and ESCAPE with MFCOMMENT.  For the BitBlts we change the x,y to

 * draw at (0,0) instead of wherever it was written to draw.  The

 * comment tells us there to stop if we don't want to draw the label.

 */

//If we're playing icon only, stop enumeration at the comment.

if (lpdi->fIconOnly)

{

if (META_ESCAPE==pMFR->rdFunction && MFCOMMENT==pMFR->rdParm[0])

{

if (0==lstrcmpi(szIconOnly, (LPSTR)&pMFR->rdParm[2]))

return 0;

}

/*

 * Check for the records in which we want to munge the coordinates.

 * destX is offset 6 for BitBlt, offset 9 for StretchBlt, either of

 * which may appear in the metafile.

 */

if (META_DIBBITBLT==pMFR->rdFunction)

pMFR->rdParm[6]=0;

if (META_DIBSTRETCHBLT==pMFR->rdFunction)

  pMFR->rdParm[9] = 0;

}

PlayMetaFileRecord(hDC, phTable, pMFR, cObj);

return 1;

}

/*

 * OleUIMetafilePictExtractLabel

 *

 * Purpose:

 *  Retrieves the label string from metafile representation of an icon.

 *

 * Parameters:

 *  hMetaPict       HGLOBAL to the METAFILEPICT containing the metafile.

 *  lpszLabel       LPSTR in which to store the label.

 *  cchLabel        UINT length of lpszLabel.

 *  lpWrapIndex     DWORD index of first character in last line. Can be NULL

 *                  if calling function doesn't care about word wrap.

 *

 * Return Value:

 *  UINT            Number of characters copied.

 */

STDAPI_(UINT) OleUIMetafilePictExtractLabel(HGLOBAL hMetaPict, LPSTR lpszLabel

  , UINT cchLabel, LPDWORD lpWrapIndex)

{

LPMETAFILEPICT  pMF;

LABELEXTRACT    le;

HDC             hDC;

/*

 * We extract the label by getting a screen DC and walking the metafile

 * records until we see the ExtTextOut record we put there.  That

 * record will have the string embedded in it which we then copy out.

 */

if (NULL==hMetaPict || NULL==lpszLabel || 0==cchLabel)

return FALSE;

pMF=GlobalLock(hMetaPict);

if (NULL==pMF)

return FALSE;

le.lpsz=lpszLabel;

le.u.cch=cchLabel;

le.Index=0;

le.fFoundIconOnly=FALSE;

le.fFoundSource=FALSE;  //Unused for this function.

le.fFoundIndex=FALSE;   //Unused for this function.

le.PrevIndex = 0;

//Use a screen DC so we have something valid to pass in.

hDC=GetDC(NULL);

// Since we've used the EXPORT keyword on the

// EnumMetafileExtractLabel proc, we do not need to use

// MakeProcInstance

EnumMetaFile(hDC, pMF->hMF, (MFENUMPROC)EnumMetafileExtractLabel, (LONG)(LPLABELEXTRACT)&le);

ReleaseDC(NULL, hDC);

GlobalUnlock(hMetaPict);

//Tell where we wrapped (if calling function cares)

if (NULL != lpWrapIndex)

   *lpWrapIndex = le.PrevIndex;

//Return amount of text copied

return le.u.cch;

}

/*

 * EnumMetafileExtractLabel

 *

 * Purpose:

 *  EnumMetaFile callback function that walks a metafile looking for

 *  ExtTextOut, then concatenates the text from each one into a buffer

 *  in lParam.

 *

 * Parameters:

 *  hDC             HDC into which the metafile should be played.

 *  phTable         HANDLETABLE FAR * providing handles selected into the DC.

 *  pMFR            METARECORD FAR * giving the enumerated record.

 *  pLE             LPLABELEXTRACT providing the destination buffer and length.

 *

 * Return Value:

 *  int             0 to stop enumeration, 1 to continue.

 */

int CALLBACK EXPORT EnumMetafileExtractLabel(HDC hDC, HANDLETABLE FAR *phTable

, METARECORD FAR *pMFR, int cObj, LPLABELEXTRACT pLE)

{

/*

 * We don't allow anything to happen until we see "IconOnly"

 * in an MFCOMMENT that is used to enable everything else.

 */

if (!pLE->fFoundIconOnly)

{

if (META_ESCAPE==pMFR->rdFunction && MFCOMMENT==pMFR->rdParm[0])

{

if (0==lstrcmpi(szIconOnly, (LPSTR)&pMFR->rdParm[2]))

pLE->fFoundIconOnly=TRUE;

}

return 1;

}

//Enumerate all records looking for META_EXTTEXTOUT - there can be more

//than one.

if (META_EXTTEXTOUT==pMFR->rdFunction)

{

UINT        cchMax;

LPSTR       lpszTemp;

/*

 * If ExtTextOut has NULL fuOptions, then the rectangle is omitted

 * from the record, and the string starts at rdParm[4].  If

 * fuOptions is non-NULL, then the string starts at rdParm[8]

 * (since the rectange takes up four WORDs in the array).  In

 * both cases, the string continues for (rdParm[2]+1) >> 1

 * words.  We just cast a pointer to rdParm[8] to an LPSTR and

 * lstrcpyn into the buffer we were given.

 *

 * Note that we use element 8 in rdParm instead of 4 because we

 * passed ETO_CLIPPED in for the options on ExtTextOut--docs say

 * [4] which is rect doesn't exist if we passed zero there.

 *

 */

cchMax=min(pLE->u.cch - pLE->Index, (UINT)pMFR->rdParm[2]);

lpszTemp = pLE->lpsz + pLE->Index;

lstrcpyn(lpszTemp, (LPSTR)&(pMFR->rdParm[8]), cchMax + 1);

//        lstrcpyn(lpszTemp, (LPSTR)&(pMFR->rdParm[4]), cchMax + 1);

pLE->PrevIndex = pLE->Index;

pLE->Index += cchMax;

}

return 1;

}

/*

 * OleUIMetafilePictExtractIcon

 *

 * Purpose:

 *  Retrieves the icon from metafile into which DrawIcon was done before.

 *

 * Parameters:

 *  hMetaPict       HGLOBAL to the METAFILEPICT containing the metafile.

 *

 * Return Value:

 *  HICON           Icon recreated from the data in the metafile.

 */

STDAPI_(HICON) OleUIMetafilePictExtractIcon(HGLOBAL hMetaPict)

{

LPMETAFILEPICT  pMF;

HDC             hDC;

ICONEXTRACT     ie;

/*

 * We extract the label by getting a screen DC and walking the metafile

 * records until we see the ExtTextOut record we put there.  That

 * record will have the string embedded in it which we then copy out.

 */

if (NULL==hMetaPict)

return NULL;

pMF=GlobalLock(hMetaPict);

if (NULL==pMF)

return FALSE;

//Use a screen DC so we have something valid to pass in.

hDC=GetDC(NULL);

ie.fAND=TRUE;

// We get information back in the ICONEXTRACT structure.

// (Since we've used the EXPORT keyword on the

// EnumMetafileExtractLabel proc, we do not need to use

// MakeProcInstance)

EnumMetaFile(hDC, pMF->hMF, (MFENUMPROC)EnumMetafileExtractIcon, (LONG)(LPICONEXTRACT)&ie);

ReleaseDC(NULL, hDC);

GlobalUnlock(hMetaPict);

return ie.hIcon;

}

/*

 * EnumMetafileExtractIcon

 *

 * Purpose:

 *  EnumMetaFile callback function that walks a metafile looking for

 *  StretchBlt (3.1) and BitBlt (3.0) records.  We expect to see two

 *  of them, the first being the AND mask and the second being the XOR

 *  data.  We

 *  ExtTextOut, then copies the text into a buffer in lParam.

 *

 * Parameters:

 *  hDC             HDC into which the metafile should be played.

 *  phTable         HANDLETABLE FAR * providing handles selected into the DC.

 *  pMFR            METARECORD FAR * giving the enumerated record.

 *  pIE             LPICONEXTRACT providing the destination buffer and length.

 *

 * Return Value:

 *  int             0 to stop enumeration, 1 to continue.

 */

int CALLBACK EXPORT EnumMetafileExtractIcon(HDC hDC, HANDLETABLE FAR *phTable

, METARECORD FAR *pMFR, int cObj, LPICONEXTRACT pIE)

{

LPBITMAPINFO        lpBI;

LPBITMAPINFOHEADER  lpBH;

LPBYTE              lpbSrc;

LPBYTE              lpbDst;

UINT                uWidth, uHeight;

DWORD               cb;

HGLOBAL             hMem;

BITMAP              bm;

HBITMAP             hBmp;

int                 cxIcon, cyIcon;

//Continue enumeration if we don't see the records we want.

if (META_DIBBITBLT!=pMFR->rdFunction && META_DIBSTRETCHBLT!=pMFR->rdFunction)

return 1;

/*

 * Windows 3.0 DrawIcon uses META_DIBBITBLT in whereas 3.1 uses

 * META_DIBSTRETCHBLT so we have to handle each case separately.

 */

if (META_DIBBITBLT==pMFR->rdFunction)       //Win3.0

{

//Get dimensions and the BITMAPINFO struct.

uHeight=pMFR->rdParm[1];

uWidth =pMFR->rdParm[2];

lpBI=(LPBITMAPINFO)&(pMFR->rdParm[8]);

}

if (META_DIBSTRETCHBLT==pMFR->rdFunction)   //Win3.1

{

//Get dimensions and the BITMAPINFO struct.

uHeight=pMFR->rdParm[2];

uWidth =pMFR->rdParm[3];

lpBI=(LPBITMAPINFO)&(pMFR->rdParm[10]);

}

lpBH=(LPBITMAPINFOHEADER)&(lpBI->bmiHeader);

//Pointer to the bits which follows the BITMAPINFO structure.

lpbSrc=(LPBYTE)lpBI+lpBH->biSize;

//Add the length of the color table.

if (0!=lpBH->biClrUsed)

lpbSrc+=(DWORD)(lpBH->biClrUsed*sizeof(RGBQUAD));

else

{

        if (lpBH->biBitCount <= 8)

            {

    //1 << bc gives 2, 16, 256 for 1, 4, or 256 colors

    lpbSrc+=(DWORD)((1 << (lpBH->biBitCount))*sizeof(RGBQUAD));

            }

}

/*

 * All the bits we have in lpbSrc are device-independent, so we

 * need to change them over to be device-dependent using SetDIBits.

 * Once we have a bitmap with the device-dependent bits, we can

 * GetBitmapBits to have buffers with the real data.

 *

 * For each pass we have to allocate memory for the bits.  We save

 * the memory for the mask between passes.

 */

//Use CreateBitmap for ANY monochrome bitmaps

if (pIE->fAND || 1==lpBH->biBitCount || lpBH->biBitCount > 8)

hBmp=CreateBitmap((UINT)lpBH->biWidth, (UINT)lpBH->biHeight, 1, 1, NULL);

else if (lpBH->biBitCount <= 8)

hBmp=CreateCompatibleBitmap(hDC, (UINT)lpBH->biWidth, (UINT)lpBH->biHeight);

if (!hBmp || !SetDIBits(hDC, hBmp, 0, (UINT)lpBH->biHeight, (LPVOID)lpbSrc, lpBI, DIB_RGB_COLORS))

{

if (!pIE->fAND)

GlobalFree(pIE->hMemAND);

DeleteObject(hBmp);

return 0;

}

//Allocate memory and get the DDBits into it.

GetObject(hBmp, sizeof(bm), &bm);

cb=bm.bmHeight*bm.bmWidthBytes * bm.bmPlanes;

//    if (cb % 4 != 0)        // dword align

//      cb += 4 - (cb % 4);

hMem=GlobalAlloc(GHND, cb);

if (NULL==hMem)

{

if (NULL!=pIE->hMemAND)

GlobalFree(pIE->hMemAND);

DeleteObject(hBmp);

return 0;

}

lpbDst=(LPBYTE)GlobalLock(hMem);

GetBitmapBits(hBmp, cb, (LPVOID)lpbDst);

DeleteObject(hBmp);

GlobalUnlock(hMem);

/*

 * If this is the first pass (pIE->fAND==TRUE) then save the memory

 * of the AND bits for the next pass.

 */

if (pIE->fAND)

{

pIE->fAND=FALSE;

pIE->hMemAND=hMem;

//Continue enumeration looking for the next blt record.

return 1;

}

else

{

//Get the AND pointer again.

lpbSrc=(LPBYTE)GlobalLock(pIE->hMemAND);

/*

 * Create the icon now that we have all the data.  lpbDst already

 * points to the XOR bits.

 */

cxIcon = GetSystemMetrics(SM_CXICON);

cyIcon = GetSystemMetrics(SM_CYICON);

pIE->hIcon=CreateIcon(ghInst,

  uWidth,

  uHeight,

  (BYTE)bm.bmPlanes,

  (BYTE)bm.bmBitsPixel,

  (LPVOID)lpbSrc,

  (LPVOID)lpbDst);

GlobalUnlock(pIE->hMemAND);

GlobalFree(pIE->hMemAND);

GlobalFree(hMem);

//We're done so we can stop.

return 0;

}

}

/*

 * OleUIMetafilePictExtractIconSource

 *

 * Purpose:

 *  Retrieves the filename and index of the icon source from a metafile

 *  created with OleUIMetafilePictFromIconAndLabel.

 *

 * Parameters:

 *  hMetaPict       HGLOBAL to the METAFILEPICT containing the metafile.

 *  lpszSource      LPSTR in which to store the source filename.  This

 *                  buffer should be OLEUI_CCHPATHMAX characters.

 *  piIcon          UINT FAR * in which to store the icon's index

 *                  within lpszSource

 *

 * Return Value:

 *  BOOL            TRUE if the records were found, FALSE otherwise.

 */

STDAPI_(BOOL) OleUIMetafilePictExtractIconSource(HGLOBAL hMetaPict

, LPSTR lpszSource, UINT FAR *piIcon)

{

LPMETAFILEPICT  pMF;

LABELEXTRACT    le;

HDC             hDC;

/*

 * We will walk the metafile looking for the two comment records

 * following the IconOnly comment.  The flags fFoundIconOnly and

 * fFoundSource indicate if we have found IconOnly and if we have

 * found the source comment already.

 */

if (NULL==hMetaPict || NULL==lpszSource || NULL==piIcon)

return FALSE;

pMF=GlobalLock(hMetaPict);

if (NULL==pMF)

return FALSE;

le.lpsz=lpszSource;

le.fFoundIconOnly=FALSE;

le.fFoundSource=FALSE;

le.fFoundIndex=FALSE;

//Use a screen DC so we have something valid to pass in.

hDC=GetDC(NULL);

EnumMetaFile(hDC, pMF->hMF, (MFENUMPROC)EnumMetafileExtractIconSource, (LONG)(LPLABELEXTRACT)&le);

ReleaseDC(NULL, hDC);

GlobalUnlock(hMetaPict);

//Copy the icon index to the caller's variable.

*piIcon=le.u.iIcon;

//Check that we found everything.

return (le.fFoundIconOnly && le.fFoundSource && le.fFoundIndex);

}

/*

 * EnumMetafileExtractIconSource

 *

 * Purpose:

 *  EnumMetaFile callback function that walks a metafile skipping the first

 *  comment record, extracting the source filename from the second, and

 *  the index of the icon in the third.

 *

 * Parameters:

 *  hDC             HDC into which the metafile should be played.

 *  phTable         HANDLETABLE FAR * providing handles selected into the DC.

 *  pMFR            METARECORD FAR * giving the enumerated record.

 *  pLE             LPLABELEXTRACT providing the destination buffer and

 *                  area to store the icon index.

 *

 * Return Value:

 *  int             0 to stop enumeration, 1 to continue.

 */

int CALLBACK EXPORT EnumMetafileExtractIconSource(HDC hDC, HANDLETABLE FAR *phTable

, METARECORD FAR *pMFR, int cObj, LPLABELEXTRACT pLE)

{

LPSTR       psz;

/*

 * We don't allow anything to happen until we see "IconOnly"

 * in an MFCOMMENT that is used to enable everything else.

 */

if (!pLE->fFoundIconOnly)

{

if (META_ESCAPE==pMFR->rdFunction && MFCOMMENT==pMFR->rdParm[0])

{

if (0==lstrcmpi(szIconOnly, (LPSTR)&pMFR->rdParm[2]))

pLE->fFoundIconOnly=TRUE;

}

return 1;

}

//Now see if we find the source string.

if (!pLE->fFoundSource)

{

if (META_ESCAPE==pMFR->rdFunction && MFCOMMENT==pMFR->rdParm[0])

{

LSTRCPYN(pLE->lpsz, (LPSTR)&pMFR->rdParm[2], OLEUI_CCHPATHMAX);

pLE->lpsz[OLEUI_CCHPATHMAX-1] = '\0';

pLE->fFoundSource=TRUE;

}

return 1;

}

//Next comment will be the icon index.

if (META_ESCAPE==pMFR->rdFunction && MFCOMMENT==pMFR->rdParm[0])

{

/*

 * This string contains the icon index in string form,

 * so we need to convert back to a UINT.  After we see this

 * we can stop the enumeration.  The comment will have

 * a null terminator because we made sure to save it.

 */

psz=(LPSTR)&pMFR->rdParm[2];

pLE->u.iIcon=0;

//Do Ye Olde atoi

while (*psz)

pLE->u.iIcon=(10*pLE->u.iIcon)+((*psz++)-'0');

pLE->fFoundIndex=TRUE;

return 0;

}

return 1;

}


EDLINKS.H  (WRAPUI Sample)

/*

 * EDLINKS.H

 *

 * Internal definitions, structures, and function prototypes for the

 * OLE 2.0 UI Edit Links dialog.

 *

 * Copyright (c)1992 Microsoft Corporation, All Right Reserved

 */

#ifndef _LINKS_H_

#define _LINKS_H_

//INTERNAL INFORMATION STARTS HERE

#define OLEUI_SZMAX 255

#define LINKTYPELEN 9

#define szNULL    "\0"

typedef UINT (CALLBACK* COMMDLGHOOKPROC)(HWND, UINT, WPARAM, LPARAM);

//Internally used structure

typedef struct tagLINKINFO

  {

  DWORD     dwLink;             // app specific identifier of a link

  LPSTR     lpszDisplayName;    // file based part of name

  LPSTR     lpszItemName;       // object part of name

  LPSTR     lpszShortFileName;  // filename without path

  LPSTR     lpszShortLinkType;  // Short link type - progID

  LPSTR     lpszFullLinkType;   // Full link type - user friendly name

  LPSTR     lpszAMX;          // Is the link auto (A) man (M) or dead (X)

  ULONG     clenFileName;       // count of file part of mon.

  BOOL      fSourceAvailable;   // bound or not - on boot assume yes??

  BOOL      fIsAuto;                      // 1 =automatic, 0=manual update

  BOOL      fIsMarked;                  // 1 = marked, 0 = not

  BOOL      fDontFree;         // Don't free this data since it's being reused

  BOOL      fIsSelected;        // item selected or to be selected

  } LINKINFO, FAR* LPLINKINFO;

  /*

  * What we store extra in this structure besides the original caller's

  * pointer are those fields that we need to modify during the life of

  * the dialog but that we don't want to change in the original structure

  * until the user presses OK.

  */

typedef struct tagEDITLINKS

{

  //Keep this item first as the Standard* functions depend on it here.

  LPOLEUIEDITLINKS    lpOEL;       //Original structure passed.

  BOOL        fClose;             //  Does the button read cancel (0) or

  //  close (1)?

  int         *rgIndex;           //  Array to hold indexes of selected items

  int         cSelItems;          //  Number of selected items

  BOOL        fItemsExist;        //  TRUE, items in lbox, FALSE, none

  UINT        nChgSrcHelpID;      //  ID for Help callback from ChangeSrc dlg

  char        szClose[50];        //  Text for Close button

  //    (when Cancel button gets renamed)

} EDITLINKS, *PEDITLINKS, FAR *LPEDITLINKS;

// Data to and from the ChangeSource dialog hook

typedef struct tagOLEUICHANGESOURCEHOOKDATA

{

//These IN fields are standard across all OLEUI dialog functions.

DWORD           cbStruct;         //Structure Size

DWORD           dwFlags;          //IN-OUT:  Flags

HWND            hWndOwner;        //Owning window

LPCSTR          lpszCaption;      //Dialog caption bar contents

LPFNOLEUIHOOK   lpfnHook;         //Hook callback

LPARAM          lCustData;        //Custom data to pass to hook

HINSTANCE       hInstance;        //Instance for customized template name

LPCSTR          lpszTemplate;     //Customized template name

HRSRC           hResource;        //Customized template handle

//Specifics for OLEUIINSERTOBJECT.  All are IN-OUT unless otherwise spec.

LPLINKINFO  lpLI;                 // IN: ptr to LinkInfo entry

LPEDITLINKS lpEL;                 // IN: ptr to EditLinks dialog struct

BOOL        fValidLink;           // OUT: was link source validated

LPSTR       lpszFrom;             // OUT: string containing prefix of

  //      source changed from

LPSTR       lpszTo;               // OUT: string containing prefix of

  //      source changed to

} OLEUICHANGESOURCEHOOKDATA, *POLEUICHANGESOURCEHOOKDATA,

  FAR *LPOLEUICHANGESOURCEHOOKDATA;

// Data to and from the ChangeSource dialog hook

typedef struct tagCHANGESOURCEHOOKDATA

{

LPOLEUICHANGESOURCEHOOKDATA lpOCshData;  //Original structure passed.

LPOPENFILENAME lpOfn;

BOOL        fValidLink;

int         nFileLength;

int         nEditLength;

char        szFileName[OLEUI_CCHPATHMAX];

char        szItemName[OLEUI_CCHPATHMAX];

BOOL        bFileNameStored;

BOOL        bItemNameStored;

char        szEdit[OLEUI_CCHPATHMAX];

LPSTR       lpszFrom;           // string containing prefix of source

// changed from

LPSTR       lpszTo;             // string containing prefix of source

// source changed to

} CHANGESOURCEHOOKDATA, *PCHANGESOURCEHOOKDATA, FAR *LPCHANGESOURCEHOOKDATA;

//Internal function prototypes

//LINKS.C

BOOL CALLBACK EXPORT EditLinksDialogProc(HWND, UINT, WPARAM, LPARAM);

BOOL            FEditLinksInit(HWND, WPARAM, LPARAM);

BOOL      Container_ChangeSource(HWND, LPEDITLINKS);

HRESULT   Container_AutomaticManual(HWND, BOOL, LPEDITLINKS);

HRESULT   CancelLink(HWND, LPEDITLINKS);

HRESULT   Container_UpdateNow(HWND, LPEDITLINKS);

HRESULT   Container_OpenSource(HWND, LPEDITLINKS);

int AddLinkLBItem(HWND hListBox, LPOLEUILINKCONTAINER lpOleUILinkCntr, LPLINKINFO lpLI, BOOL fGetSelected, int nIndex);

VOID    BreakString(LPLINKINFO);

int     GetSelectedItems(HWND, int FAR* FAR*);

BOOL WINAPI ChangeSource(HWND hWndOwner,

   LPSTR lpszFile,

   UINT cchFile,

   UINT iFilterString,

   COMMDLGHOOKPROC lpfnBrowseHook,

   LPOLEUICHANGESOURCEHOOKDATA lpLbhData);

UINT CALLBACK EXPORT ChangeSourceHook(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);

VOID InitControls(HWND hDlg, LPEDITLINKS lpEL);

VOID UpdateLinkLBItem(HWND hListBox, int nIndex, LPEDITLINKS lpEL, BOOL bSelect);

VOID DiffPrefix(LPCSTR lpsz1, LPCSTR lpsz2, char FAR* FAR* lplpszPrefix1, char FAR* FAR* lplpszPrefix2);

int PopupMessage(HWND hwndParent, UINT idTitle, UINT idMessage, UINT fuStyle);

BOOL FChangeAllLinks(HWND hLIstBox, LPOLEUILINKCONTAINER lpOleUILinkCntr, LPSTR lpszFrom, LPSTR lpszTo);

BOOL CFindLinks(HWND hListBox, LPSTR lpsz);

int LoadLinkLB(HWND hListBox, LPOLEUILINKCONTAINER lpOleUILinkCntr);

VOID RefreshLinkLB(HWND hListBox, LPOLEUILINKCONTAINER lpOleUILinkCntr);

#endif // __LINKS_H__


ENUMFETC.H  (WRAPUI Sample)

// This file is now OBSOLETE (include olestd.h instead)

/*************************************************************************

**

**    OLE 2 Utility Code

**

**    enumfetc.c

**

**    (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved

**

*************************************************************************/

// Function prototypes moved to olestd.h


ENUMFETC.C  (WRAPUI Sample)

/*************************************************************************

**

**    OLE 2 Utility Code

**

**    enumfetc.c

**

**    This file contains a standard implementation of IEnumFormatEtc

**    interface.

**    This file is part of the OLE 2.0 User Interface support library.

**

**    (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved

**

*************************************************************************/

#define STRICT  1

#include "ole2ui.h"

#include "enumfetc.h"

typedef struct tagOleStdEnumFmtEtc {

  IEnumFORMATETCVtbl FAR* lpVtbl;

  ULONG m_dwRefs;       /* referance count */

  ULONG m_nIndex;       /* current index in list */

  ULONG m_nCount;       /* how many items in list */

  LPFORMATETC m_lpEtc;  /* list of formatetc */

} OLESTDENUMFMTETC, FAR* LPOLESTDENUMFMTETC;

VOID  OleStdEnumFmtEtc_Destroy(LPOLESTDENUMFMTETC pEtc);

STDMETHODIMP OleStdEnumFmtEtc_QueryInterface(

LPENUMFORMATETC lpThis, REFIID riid, LPVOID FAR* ppobj);

STDMETHODIMP_(ULONG)  OleStdEnumFmtEtc_AddRef(LPENUMFORMATETC lpThis);

STDMETHODIMP_(ULONG)  OleStdEnumFmtEtc_Release(LPENUMFORMATETC lpThis);

STDMETHODIMP  OleStdEnumFmtEtc_Next(LPENUMFORMATETC lpThis, ULONG celt,

  LPFORMATETC rgelt, ULONG FAR* pceltFetched);

STDMETHODIMP  OleStdEnumFmtEtc_Skip(LPENUMFORMATETC lpThis, ULONG celt);

STDMETHODIMP  OleStdEnumFmtEtc_Reset(LPENUMFORMATETC lpThis);

STDMETHODIMP  OleStdEnumFmtEtc_Clone(LPENUMFORMATETC lpThis,

 LPENUMFORMATETC FAR* ppenum);

static IEnumFORMATETCVtbl g_EnumFORMATETCVtbl = {

OleStdEnumFmtEtc_QueryInterface,

OleStdEnumFmtEtc_AddRef,

OleStdEnumFmtEtc_Release,

OleStdEnumFmtEtc_Next,

OleStdEnumFmtEtc_Skip,

OleStdEnumFmtEtc_Reset,

OleStdEnumFmtEtc_Clone,

};

/////////////////////////////////////////////////////////////////////////////

STDAPI_(LPENUMFORMATETC)

  OleStdEnumFmtEtc_Create(ULONG nCount, LPFORMATETC lpEtc)

//----------------------------------------------------------------------------

//

//----------------------------------------------------------------------------

{

  LPMALLOC lpMalloc=NULL;

  LPOLESTDENUMFMTETC lpEF=NULL;

  DWORD dwSize;

  UINT i;

  HRESULT hRes;

  hRes = CoGetMalloc(MEMCTX_TASK, &lpMalloc);

  if (hRes != NOERROR) {

return NULL;

  }

  lpEF = (LPOLESTDENUMFMTETC)lpMalloc->lpVtbl->Alloc(lpMalloc,

 sizeof(OLESTDENUMFMTETC));

  if (lpEF == NULL) {

goto errReturn;

  }

  lpEF->lpVtbl = &g_EnumFORMATETCVtbl;

  lpEF->m_dwRefs = 1;

  lpEF->m_nCount = nCount;

  lpEF->m_nIndex = 0;

  dwSize = sizeof(FORMATETC) * lpEF->m_nCount;

  lpEF->m_lpEtc = (LPFORMATETC)lpMalloc->lpVtbl->Alloc(lpMalloc, dwSize);

  if (lpEF->m_lpEtc == NULL)

goto errReturn;

  lpMalloc->lpVtbl->Release(lpMalloc);

  for (i=0; i<nCount; i++) {

OleStdCopyFormatEtc(

(LPFORMATETC)&(lpEF->m_lpEtc[i]), (LPFORMATETC)&(lpEtc[i]));

  }

  g_dwObjectCount++ ;

  return (LPENUMFORMATETC)lpEF;

errReturn:

  if (lpEF != NULL)

lpMalloc->lpVtbl->Free(lpMalloc, lpEF);

  if (lpMalloc != NULL)

lpMalloc->lpVtbl->Release(lpMalloc);

  return NULL;

} /* OleStdEnumFmtEtc_Create()

   */

VOID

  OleStdEnumFmtEtc_Destroy(LPOLESTDENUMFMTETC lpEF)

//----------------------------------------------------------------------------

//

//----------------------------------------------------------------------------

{

LPMALLOC lpMalloc=NULL;

UINT i;

if (lpEF != NULL) {

if (CoGetMalloc(MEMCTX_TASK, &lpMalloc) == NOERROR) {

/* OLE2NOTE: we MUST free any memory that was allocated for

**    TARGETDEVICES contained within the FORMATETC elements.

*/

for (i=0; i<lpEF->m_nCount; i++) {

OleStdFree(lpEF->m_lpEtc[i].ptd);

}

if (lpEF->m_lpEtc != NULL) {

lpMalloc->lpVtbl->Free(lpMalloc, lpEF->m_lpEtc);

}

lpMalloc->lpVtbl->Free(lpMalloc, lpEF);

lpMalloc->lpVtbl->Release(lpMalloc);

}

}

g_dwObjectCount-- ;

} /* OleStdEnumFmtEtc_Destroy()

   */

STDMETHODIMP

  OleStdEnumFmtEtc_QueryInterface(

LPENUMFORMATETC lpThis, REFIID riid, LPVOID FAR* ppobj)

//----------------------------------------------------------------------------

//

//----------------------------------------------------------------------------

{

  LPOLESTDENUMFMTETC lpEF = (LPOLESTDENUMFMTETC)lpThis;

  *ppobj = NULL;

  if (IsEqualIID(riid,&IID_IUnknown) || IsEqualIID(riid,&IID_IEnumFORMATETC)){

*ppobj = (LPVOID)lpEF;

  }

  if (*ppobj == NULL) return ResultFromScode(E_NOINTERFACE);

  else{

OleStdEnumFmtEtc_AddRef(lpThis);

return NOERROR;

  }

} /* OleStdEnumFmtEtc_QueryInterface()

   */

STDMETHODIMP_(ULONG)

  OleStdEnumFmtEtc_AddRef(LPENUMFORMATETC lpThis)

//----------------------------------------------------------------------------

//

//----------------------------------------------------------------------------

{

  LPOLESTDENUMFMTETC lpEF = (LPOLESTDENUMFMTETC)lpThis;

  return lpEF->m_dwRefs++;

} /* OleStdEnumFmtEtc_AddRef()

   */

STDMETHODIMP_(ULONG)

  OleStdEnumFmtEtc_Release(LPENUMFORMATETC lpThis)

//----------------------------------------------------------------------------

//

//----------------------------------------------------------------------------

{

  LPOLESTDENUMFMTETC lpEF = (LPOLESTDENUMFMTETC)lpThis;

  DWORD dwRefs = --lpEF->m_dwRefs;

  if (dwRefs == 0)

OleStdEnumFmtEtc_Destroy(lpEF);

  return dwRefs;

} /* OleStdEnumFmtEtc_Release()

   */

STDMETHODIMP

  OleStdEnumFmtEtc_Next(LPENUMFORMATETC lpThis, ULONG celt, LPFORMATETC rgelt,

  ULONG FAR* pceltFetched)

//----------------------------------------------------------------------------

//

//----------------------------------------------------------------------------

{

  LPOLESTDENUMFMTETC lpEF = (LPOLESTDENUMFMTETC)lpThis;

  ULONG i=0;

  ULONG nOffset;

  if (rgelt == NULL) {

return ResultFromScode(E_INVALIDARG);

  }

  while (i < celt) {

nOffset = lpEF->m_nIndex + i;

if (nOffset < lpEF->m_nCount) {

  OleStdCopyFormatEtc(

(LPFORMATETC)&(rgelt[i]), (LPFORMATETC)&(lpEF->m_lpEtc[nOffset]));

  i++;

}else{

  break;

}

  }

  lpEF->m_nIndex += (WORD)i;

  if (pceltFetched != NULL) {

*pceltFetched = i;

  }

  if (i != celt) {

return ResultFromScode(S_FALSE);

  }

  return NOERROR;

} /* OleStdEnumFmtEtc_Next()

   */

STDMETHODIMP

  OleStdEnumFmtEtc_Skip(LPENUMFORMATETC lpThis, ULONG celt)

//----------------------------------------------------------------------------

//

//----------------------------------------------------------------------------

{

  LPOLESTDENUMFMTETC lpEF = (LPOLESTDENUMFMTETC)lpThis;

  ULONG i=0;

  ULONG nOffset;

  while (i < celt) {

nOffset = lpEF->m_nIndex + i;

if (nOffset < lpEF->m_nCount) {

  i++;

}else{

  break;

}

  }

  lpEF->m_nIndex += (WORD)i;

  if (i != celt) {

return ResultFromScode(S_FALSE);

  }

  return NOERROR;

} /* OleStdEnumFmtEtc_Skip()

   */

STDMETHODIMP

  OleStdEnumFmtEtc_Reset(LPENUMFORMATETC lpThis)

//----------------------------------------------------------------------------

//

//----------------------------------------------------------------------------

{

  LPOLESTDENUMFMTETC lpEF = (LPOLESTDENUMFMTETC)lpThis;

  lpEF->m_nIndex = 0;

  return NOERROR;

} /* OleStdEnumFmtEtc_Reset()

   */

STDMETHODIMP

  OleStdEnumFmtEtc_Clone(LPENUMFORMATETC lpThis, LPENUMFORMATETC FAR* ppenum)

//----------------------------------------------------------------------------

//

//----------------------------------------------------------------------------

{

  LPOLESTDENUMFMTETC lpEF = (LPOLESTDENUMFMTETC)lpThis;

  if (ppenum == NULL) {

return ResultFromScode(E_INVALIDARG);

  }

  *ppenum = OleStdEnumFmtEtc_Create(lpEF->m_nCount, lpEF->m_lpEtc);

  // make sure cloned enumerator has same index state as the original

  if (*ppenum) {

  LPOLESTDENUMFMTETC lpEFClone = (LPOLESTDENUMFMTETC)*ppenum;

  lpEFClone->m_nIndex = lpEF->m_nIndex;

  return NOERROR;

  } else

  return ResultFromScode(E_OUTOFMEMORY);

} /* OleStdEnumFmtEtc_Clone()

   */


ENUMSTAT.C  (WRAPUI Sample)

/*************************************************************************

**

**    OLE 2 Utility Code

**

**    enumstat.c

**

**    This file contains a standard implementation of IEnumStatData

**    interface.

**    This file is part of the OLE 2.0 User Interface support library.

**

**    (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved

**

*************************************************************************/

#define STRICT  1

#include "ole2ui.h"

typedef struct tagOleStdEnumStatData {

  IEnumSTATDATAVtbl FAR* lpVtbl;

  ULONG m_dwRefs;       /* referance count */

  ULONG m_nIndex;       /* current index in list */

  ULONG m_nCount;       /* how many items in list */

  LPSTATDATA m_lpStat;  /* list of STATDATA */

} OLESTDENUMSTATDATA, FAR* LPOLESTDENUMSTATDATA;

VOID  OleStdEnumStatData_Destroy(LPOLESTDENUMSTATDATA pStat);

STDMETHODIMP OleStdEnumStatData_QueryInterface(

LPENUMSTATDATA lpThis, REFIID riid, LPVOID FAR* ppobj);

STDMETHODIMP_(ULONG)  OleStdEnumStatData_AddRef(LPENUMSTATDATA lpThis);

STDMETHODIMP_(ULONG)  OleStdEnumStatData_Release(LPENUMSTATDATA lpThis);

STDMETHODIMP  OleStdEnumStatData_Next(LPENUMSTATDATA lpThis, ULONG celt,

  LPSTATDATA rgelt, ULONG FAR* pceltFetched);

STDMETHODIMP  OleStdEnumStatData_Skip(LPENUMSTATDATA lpThis, ULONG celt);

STDMETHODIMP  OleStdEnumStatData_Reset(LPENUMSTATDATA lpThis);

STDMETHODIMP  OleStdEnumStatData_Clone(LPENUMSTATDATA lpThis,

 LPENUMSTATDATA FAR* ppenum);

static IEnumSTATDATAVtbl g_EnumSTATDATAVtbl = {

OleStdEnumStatData_QueryInterface,

OleStdEnumStatData_AddRef,

OleStdEnumStatData_Release,

OleStdEnumStatData_Next,

OleStdEnumStatData_Skip,

OleStdEnumStatData_Reset,

OleStdEnumStatData_Clone,

};

/////////////////////////////////////////////////////////////////////////////

STDAPI_(BOOL)

  OleStdCopyStatData(LPSTATDATA pDest, LPSTATDATA pSrc)

//----------------------------------------------------------------------------

//

//----------------------------------------------------------------------------

{

  if ((pDest == NULL) || (pSrc == NULL)) {

return FALSE;

  }

  if (OleStdCopyFormatEtc(&pDest->formatetc, &pSrc->formatetc) == FALSE) {

return FALSE;

  }

  pDest->advf = pSrc->advf;

  pDest->pAdvSink = pSrc->pAdvSink;

  pDest->dwConnection = pSrc->dwConnection;

  if (pDest->pAdvSink != NULL) {

pDest->pAdvSink->lpVtbl->AddRef(pDest->pAdvSink);

  }

  return TRUE;

} /* OleStdCopyStatData()

   */

STDAPI_(LPENUMSTATDATA)

  OleStdEnumStatData_Create(ULONG nCount, LPSTATDATA lpStatOrg)

//----------------------------------------------------------------------------

//

//----------------------------------------------------------------------------

{

  LPMALLOC lpMalloc=NULL;

  LPOLESTDENUMSTATDATA lpSD=NULL;

  DWORD dwSize;

  WORD i;

  HRESULT hRes;

  hRes = CoGetMalloc(MEMCTX_TASK, &lpMalloc);

  if (hRes != NOERROR) {

return NULL;

  }

  lpSD = (LPOLESTDENUMSTATDATA)lpMalloc->lpVtbl->Alloc(lpMalloc,

 sizeof(OLESTDENUMSTATDATA));

  if (lpSD == NULL) {

goto errReturn;

  }

  lpSD->lpVtbl = &g_EnumSTATDATAVtbl;

  lpSD->m_dwRefs = 1;

  lpSD->m_nCount = nCount;

  lpSD->m_nIndex = 0;

  dwSize = sizeof(STATDATA) * lpSD->m_nCount;

  lpSD->m_lpStat = (LPSTATDATA)lpMalloc->lpVtbl->Alloc(lpMalloc, dwSize);

  if (lpSD->m_lpStat == NULL)

goto errReturn;

  lpMalloc->lpVtbl->Release(lpMalloc);

  for (i=0; i<nCount; i++) {

OleStdCopyStatData(

(LPSTATDATA)&(lpSD->m_lpStat[i]), (LPSTATDATA)&(lpStatOrg[i]));

  }

  g_dwObjectCount++ ;

  return (LPENUMSTATDATA)lpSD;

errReturn:

  if (lpSD != NULL)

lpMalloc->lpVtbl->Free(lpMalloc, lpSD);

  if (lpMalloc != NULL)

lpMalloc->lpVtbl->Release(lpMalloc);

  return NULL;

} /* OleStdEnumStatData_Create()

   */

VOID

  OleStdEnumStatData_Destroy(LPOLESTDENUMSTATDATA lpSD)

//----------------------------------------------------------------------------

//

//----------------------------------------------------------------------------

{

LPMALLOC lpMalloc=NULL;

WORD i;

if (lpSD != NULL) {

if (CoGetMalloc(MEMCTX_TASK, &lpMalloc) == NOERROR) {

/* OLE2NOTE: we MUST free any memory that was allocated for

**    TARGETDEVICES contained within the STATDATA elements.

*/

for (i=0; i<lpSD->m_nCount; i++) {

if( lpSD->m_lpStat[i].pAdvSink )

lpSD->m_lpStat[i].pAdvSink->lpVtbl->Release(lpSD->m_lpStat[i].pAdvSink);

OleStdFree(lpSD->m_lpStat[i].formatetc.ptd);

}

if (lpSD->m_lpStat != NULL) {

lpMalloc->lpVtbl->Free(lpMalloc, lpSD->m_lpStat);

}

lpMalloc->lpVtbl->Free(lpMalloc, lpSD);

lpMalloc->lpVtbl->Release(lpMalloc);

}

}

g_dwObjectCount-- ;

} /* OleStdEnumStatData_Destroy()

   */

STDMETHODIMP

  OleStdEnumStatData_QueryInterface(

LPENUMSTATDATA lpThis, REFIID riid, LPVOID FAR* ppobj)

//----------------------------------------------------------------------------

//

//----------------------------------------------------------------------------

{

  LPOLESTDENUMSTATDATA lpSD = (LPOLESTDENUMSTATDATA)lpThis;

  *ppobj = NULL;

  if (IsEqualIID(riid,&IID_IUnknown) || IsEqualIID(riid,&IID_IEnumSTATDATA)){

*ppobj = (LPVOID)lpSD;

  }

  if (*ppobj == NULL) return ResultFromScode(E_NOINTERFACE);

  else{

OleStdEnumStatData_AddRef(lpThis);

return NOERROR;

  }

} /* OleStdEnumStatData_QueryInterface()

   */

STDMETHODIMP_(ULONG)

  OleStdEnumStatData_AddRef(LPENUMSTATDATA lpThis)

//----------------------------------------------------------------------------

//

//----------------------------------------------------------------------------

{

  LPOLESTDENUMSTATDATA lpSD = (LPOLESTDENUMSTATDATA)lpThis;

  return lpSD->m_dwRefs++;

} /* OleStdEnumStatData_AddRef()

   */

STDMETHODIMP_(ULONG)

  OleStdEnumStatData_Release(LPENUMSTATDATA lpThis)

//----------------------------------------------------------------------------

//

//----------------------------------------------------------------------------

{

  LPOLESTDENUMSTATDATA lpSD = (LPOLESTDENUMSTATDATA)lpThis;

  DWORD dwRefs = --lpSD->m_dwRefs;

  if (dwRefs == 0)

OleStdEnumStatData_Destroy(lpSD);

  return dwRefs;

} /* OleStdEnumStatData_Release()

   */

STDMETHODIMP

  OleStdEnumStatData_Next(LPENUMSTATDATA lpThis, ULONG celt, LPSTATDATA rgelt,

  ULONG FAR* pceltFetched)

//----------------------------------------------------------------------------

//

//----------------------------------------------------------------------------

{

  LPOLESTDENUMSTATDATA lpSD = (LPOLESTDENUMSTATDATA)lpThis;

  ULONG i=0;

  ULONG nOffset;

  if (rgelt == NULL) {

return ResultFromScode(E_INVALIDARG);

  }

  while (i < celt) {

nOffset = lpSD->m_nIndex + i;

if (nOffset < lpSD->m_nCount) {

  OleStdCopyStatData(

(LPSTATDATA)&(rgelt[i]), (LPSTATDATA)&(lpSD->m_lpStat[nOffset]));

  i++;

}else{

  break;

}

  }

  lpSD->m_nIndex += (WORD)i;

  if (pceltFetched != NULL) {

*pceltFetched = i;

  }

  if (i != celt) {

return ResultFromScode(S_FALSE);

  }

  return NOERROR;

} /* OleStdEnumStatData_Next()

   */

STDMETHODIMP

  OleStdEnumStatData_Skip(LPENUMSTATDATA lpThis, ULONG celt)

//----------------------------------------------------------------------------

//

//----------------------------------------------------------------------------

{

  LPOLESTDENUMSTATDATA lpSD = (LPOLESTDENUMSTATDATA)lpThis;

  ULONG i=0;

  ULONG nOffset;

  while (i < celt) {

nOffset = lpSD->m_nIndex + i;

if (nOffset < lpSD->m_nCount) {

  i++;

}else{

  break;

}

  }

  lpSD->m_nIndex += (WORD)i;

  if (i != celt) {

return ResultFromScode(S_FALSE);

  }

  return NOERROR;

} /* OleStdEnumStatData_Skip()

   */

STDMETHODIMP

  OleStdEnumStatData_Reset(LPENUMSTATDATA lpThis)

//----------------------------------------------------------------------------

//

//----------------------------------------------------------------------------

{

  LPOLESTDENUMSTATDATA lpSD = (LPOLESTDENUMSTATDATA)lpThis;

  lpSD->m_nIndex = 0;

  return NOERROR;

} /* OleStdEnumStatData_Reset()

   */

STDMETHODIMP

  OleStdEnumStatData_Clone(LPENUMSTATDATA lpThis, LPENUMSTATDATA FAR* ppenum)

//----------------------------------------------------------------------------

//

//----------------------------------------------------------------------------

{

  LPOLESTDENUMSTATDATA lpSD = (LPOLESTDENUMSTATDATA)lpThis;

  if (ppenum == NULL) {

return ResultFromScode(E_INVALIDARG);

  }

  *ppenum = OleStdEnumStatData_Create(lpSD->m_nCount, lpSD->m_lpStat);

  // make sure cloned enumerator has same index state as the original

  if (*ppenum) {

  LPOLESTDENUMSTATDATA lpSDClone = (LPOLESTDENUMSTATDATA)*ppenum;

  lpSDClone->m_nIndex = lpSD->m_nIndex;

  return NOERROR;

  } else

  return ResultFromScode(E_OUTOFMEMORY);

} /* OleStdEnumStatData_Clone()

   */


GETICON.H  (WRAPUI Sample)

// This file is now OBSOLETE (include olestd.h instead)

/*

 * GETICON.H

 *

 * Copyright (c)1992 Microsoft Corporation, All Right Reserved

 */

/*************************************************************************

**

** The following API's are now OBSOLETE because equivalent API's have been

** added to the OLE2.DLL library

**      GetIconOfFile       superceeded by OleGetIconOfFile

**      GetIconOfClass      superceeded by OleGetIconOfClass

**      OleUIMetafilePictFromIconAndLabel

**                          superceeded by OleMetafilePictFromIconAndLabel

*************************************************************************/

// Other function prototypes moved to olestd.h


GETICON.C  (WRAPUI Sample)

/*************************************************************************

**

** The following API's are now OBSOLETE because equivalent API's have been

** added to the OLE2.DLL library

**      GetIconOfFile       superceeded by OleGetIconOfFile

**      GetIconOfClass      superceeded by OleGetIconOfClass

**      OleUIMetafilePictFromIconAndLabel

**                          superceeded by OleMetafilePictFromIconAndLabel

*************************************************************************/

/*

 *  GETICON.C

 *

 *  Functions to create DVASPECT_ICON metafile from filename or classname.

 *

 *  GetIconOfFile

 *  GetIconOfClass

 *  OleUIMetafilePictFromIconAndLabel

 *  HIconAndSourceFromClass Extracts the first icon in a class's server path

 *                          and returns the path and icon index to caller.

 *  FIconFileFromClass      Retrieves the path to the exe/dll containing the

 *                           default icon, and the index of the icon.

 *  OleStdIconLabelTextOut  Draw icon label text (line break if necessary)

 *

 *    (c) Copyright Microsoft Corp. 1992-1993 All Rights Reserved

 */

/*******

 *

 * ICON (DVASPECT_ICON) METAFILE FORMAT:

 *

 * The metafile generated with OleUIMetafilePictFromIconAndLabel contains

 * the following records which are used by the functions in DRAWICON.C

 * to draw the icon with and without the label and to extract the icon,

 * label, and icon source/index.

 *

 *  SetWindowOrg

 *  SetWindowExt

 *  DrawIcon:

 *      Inserts records of DIBBITBLT or DIBSTRETCHBLT, once for the

 *      AND mask, one for the image bits.

 *  Escape with the comment "IconOnly"

 *      This indicates where to stop record enumeration to draw only

 *      the icon.

 *  SetTextColor

 *  SetTextAlign

 *  SetBkColor

 *  CreateFont

 *  SelectObject on the font.

 *  ExtTextOut

 *      One or more ExtTextOuts occur if the label is wrapped.  The

 *      text in these records is used to extract the label.

 *  SelectObject on the old font.

 *  DeleteObject on the font.

 *  Escape with a comment that contains the path to the icon source.

 *  Escape with a comment that is the ASCII of the icon index.

 *

 *******/

#define STRICT  1

#include "ole2ui.h"

#include <stdlib.h>

#include <string.h>

#include <ctype.h>

#include <commdlg.h>

#include <memory.h>

#include <cderr.h>

#include "common.h"

#include "utility.h"

static char szSeparators[] = " \t\\/!:";

#define IS_SEPARATOR(c)         ( (c) == ' ' || (c) == '\\' || (c) == '/' || (c) == '\t' || (c) == '!' || (c) == ':' )

#define IS_FILENAME_DELIM(c)    ( (c) == '\\' || (c) == '/' || (c) == ':' )

#if defined( OBSOLETE )

static HINSTANCE  s_hInst;

static char szMaxWidth[] ="WWWWWWWWWW";

//Strings for metafile comments.

static char szIconOnly[]="IconOnly";        //Where to stop to exclude label.

static char szOLE2DLL[] = "ole2.dll";   // name of OLE 2.0 library

#define ICONINDEX              0

#define AUXUSERTYPE_SHORTNAME  USERCLASSTYPE_SHORT  // short name

#define HIMETRIC_PER_INCH   2540      // number HIMETRIC units per inch

#define PTS_PER_INCH          72      // number points (font size) per inch

#define MAP_PIX_TO_LOGHIM(x,ppli)   MulDiv(HIMETRIC_PER_INCH, (x), (ppli))

#define MAP_LOGHIM_TO_PIX(x,ppli)   MulDiv((ppli), (x), HIMETRIC_PER_INCH)

static char szVanillaDocIcon[] = "DefIcon";

static char szDocument[40] = "";

/*

 * GetIconOfFile(HINSTANCE hInst, LPSTR lpszPath, BOOL fUseFileAsLabel)

 *

 * Purpose:

 *  Returns a hMetaPict containing an icon and label (filename) for the

 *  specified filename.

 *

 * Parameters:

 *  hinst

 *  lpszPath        LPSTR path including filename to use

 *  fUseFileAsLabel BOOL TRUE if the icon's label is the filename, FALSE if

 *                  there should be no label.

 *

 * Return Value:

 *  HGLOBAL         hMetaPict containing the icon and label - if there's no

 *                  class in reg db for the file in lpszPath, then we use

 *                  Document.  If lpszPath is NULL, then we return NULL.

 */

STDAPI_(HGLOBAL) GetIconOfFile(HINSTANCE hInst, LPSTR lpszPath, BOOL fUseFileAsLabel)

{

  char     szIconFile[OLEUI_CCHPATHMAX];

  char     szLabel[OLEUI_CCHLABELMAX];

  LPSTR    lpszClsid = NULL;

  CLSID    clsid;

  HICON    hDefIcon = NULL;

  UINT     IconIndex = 0;

  HGLOBAL  hMetaPict;

  HRESULT  hResult;

  if (NULL == lpszPath)  // even if fUseFileAsLabel is FALSE, we still

return NULL;             // need a valid filename to get the class.

  s_hInst = hInst;

  hResult = GetClassFile(lpszPath, &clsid);

  if (NOERROR == hResult)  // use the clsid we got to get to the icon

  {

  hDefIcon = HIconAndSourceFromClass(&clsid,

 (LPSTR)szIconFile,

 &IconIndex);

  }

  if ( (NOERROR != hResult) || (NULL == hDefIcon) )

  {

 // Here, either GetClassFile failed or HIconAndSourceFromClass failed.

 LPSTR lpszTemp;

 lpszTemp = lpszPath;

 while ((*lpszTemp != '.') && (*lpszTemp != '\0'))

lpszTemp++;

 if ('.' != *lpszTemp)

   goto UseVanillaDocument;

 if (FALSE == GetAssociatedExecutable(lpszTemp, (LPSTR)szIconFile))

   goto UseVanillaDocument;

 hDefIcon = ExtractIcon(s_hInst, szIconFile, IconIndex);

  }

  if (hDefIcon <= (HICON)1) // ExtractIcon returns 1 if szExecutable is not exe,

  {                         // 0 if there are no icons.

UseVanillaDocument:

lstrcpy((LPSTR)szIconFile, (LPSTR)szOLE2DLL);

IconIndex = ICONINDEX;

hDefIcon = ExtractIcon(s_hInst, szIconFile, IconIndex);

  }

  // Now let's get the label we want to use.

  if (fUseFileAsLabel)   // strip off path, so we just have the filename.

  {

 int istrlen;

 LPSTR lpszBeginFile;

 istrlen = lstrlen(lpszPath);

 // set pointer to END of path, so we can walk backwards through it.

 lpszBeginFile = lpszPath + istrlen -1;

 while ( (lpszBeginFile >= lpszPath)

 && (!IS_FILENAME_DELIM(*lpszBeginFile)) )

  lpszBeginFile--;

 lpszBeginFile++;  // step back over the delimiter

 LSTRCPYN(szLabel, lpszBeginFile, sizeof(szLabel));

  }

  else   // use the short user type (AuxUserType2) for the label

  {

  if (0 == OleStdGetAuxUserType(&clsid, AUXUSERTYPE_SHORTNAME,

   (LPSTR)szLabel, OLEUI_CCHLABELMAX, NULL)) {

 if ('\0'==szDocument[0]) {

 LoadString(

 s_hInst,IDS_DEFICONLABEL,szDocument,sizeof(szDocument));

 }

 lstrcpy(szLabel, szDocument);

  }

  }

  hMetaPict = OleUIMetafilePictFromIconAndLabel(hDefIcon,

szLabel,

(LPSTR)szIconFile,

IconIndex);

  DestroyIcon(hDefIcon);

  return hMetaPict;

}

/*

 * GetIconOfClass(HINSTANCE hInst, REFCLSID rclsid, LPSTR lpszLabel, BOOL fUseTypeAsLabel)

 *

 * Purpose:

 *  Returns a hMetaPict containing an icon and label (human-readable form

 *  of class) for the specified clsid.

 *

 * Parameters:

 *  hinst

 *  rclsid          REFCLSID pointing to clsid to use.

 *  lpszLabel       label to use for icon.

 *  fUseTypeAsLabel Use the clsid's user type name as the icon's label.

 *

 * Return Value:

 *  HGLOBAL         hMetaPict containing the icon and label - if we

 *                  don't find the clsid in the reg db then we

 *                  return NULL.

 */

STDAPI_(HGLOBAL)    GetIconOfClass(HINSTANCE hInst, REFCLSID rclsid, LPSTR lpszLabel, BOOL fUseTypeAsLabel)

{

  char    szLabel[OLEUI_CCHLABELMAX];

  char    szIconFile[OLEUI_CCHPATHMAX];

  HICON   hDefIcon;

  UINT    IconIndex;

  HGLOBAL hMetaPict;

  s_hInst = hInst;

  if (!fUseTypeAsLabel)  // Use string passed in as label

  {

if (NULL != lpszLabel)

   LSTRCPYN(szLabel, lpszLabel, sizeof(szLabel));

else

   *szLabel = '\0';

  }

  else   // Use AuxUserType2 (short name) as label

  {

  if (0 == OleStdGetAuxUserType(rclsid,

AUXUSERTYPE_SHORTNAME,

(LPSTR)szLabel,

OLEUI_CCHLABELMAX,

NULL))

   // If we can't get the AuxUserType2, then try the long name

   if (0 == OleStdGetUserTypeOfClass(rclsid, szLabel, OLEUI_CCHKEYMAX, NULL)) {

 if ('\0'==szDocument[0]) {

 LoadString(

 s_hInst,IDS_DEFICONLABEL,szDocument,sizeof(szDocument));

 }

 lstrcpy(szLabel, szDocument);  // last resort

   }

  }

  // Get the icon, icon index, and path to icon file

  hDefIcon = HIconAndSourceFromClass(rclsid,

  (LPSTR)szIconFile,

  &IconIndex);

  if (NULL == hDefIcon)  // Use Vanilla Document

  {

lstrcpy((LPSTR)szIconFile, (LPSTR)szOLE2DLL);

IconIndex = ICONINDEX;

hDefIcon = ExtractIcon(s_hInst, szIconFile, IconIndex);

  }

  // Create the metafile

  hMetaPict = OleUIMetafilePictFromIconAndLabel(hDefIcon, szLabel,

(LPSTR)szIconFile, IconIndex);

  DestroyIcon(hDefIcon);

  return hMetaPict;

}

/*

 * OleUIMetafilePictFromIconAndLabel

 *

 * Purpose:

 *  Creates a METAFILEPICT structure that container a metafile in which

 *  the icon and label are drawn.  A comment record is inserted between

 *  the icon and the label code so our special draw function can stop

 *  playing before the label.

 *

 * Parameters:

 *  hIcon           HICON to draw into the metafile

 *  pszLabel        LPSTR to the label string.

 *  pszSourceFile   LPSTR containing the local pathname of the icon

 *                  as we either get from the user or from the reg DB.

 *  iIcon           UINT providing the index into pszSourceFile where

 *                  the icon came from.

 *

 * Return Value:

 *  HGLOBAL         Global memory handle containing a METAFILEPICT where

 *                  the metafile uses the MM_ANISOTROPIC mapping mode.  The

 *                  extents reflect both icon and label.

 */

STDAPI_(HGLOBAL) OleUIMetafilePictFromIconAndLabel(HICON hIcon, LPSTR pszLabel

, LPSTR pszSourceFile, UINT iIcon)

{

HDC             hDC, hDCScreen;

HMETAFILE       hMF;

HGLOBAL         hMem;

LPMETAFILEPICT  pMF;

UINT            cxIcon, cyIcon;

UINT            cxText, cyText;

UINT            cx, cy;

UINT            cchLabel = 0;

HFONT           hFont, hFontT;

int             cyFont;

char            szIndex[10];

RECT            TextRect;

SIZE            size;

POINT           point;

UINT            fuAlign;

if (NULL==hIcon)  // null label is valid but NOT a null icon

return NULL;

//Create a memory metafile

hDC=(HDC)CreateMetaFile(NULL);

if (NULL==hDC)

return NULL;

//Allocate the metafilepict

hMem=GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, sizeof(METAFILEPICT));

if (NULL==hMem)

{

hMF=CloseMetaFile(hDC);

DeleteMetaFile(hMF);

return NULL;

}

if (NULL!=pszLabel)

{

cchLabel=lstrlen(pszLabel);

if (cchLabel >= OLEUI_CCHLABELMAX)

   pszLabel[cchLabel] = '\0';   // truncate string

}

//Need to use the screen DC for these operations

hDCScreen=GetDC(NULL);

cyFont=-(8*GetDeviceCaps(hDCScreen, LOGPIXELSY))/72;

//cyFont was calculated to give us 8 point.

hFont=CreateFont(cyFont, 5, 0, 0, FW_NORMAL, 0, 0, 0, ANSI_CHARSET

, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY

, FF_SWISS, "MS Sans Serif");

hFontT=SelectObject(hDCScreen, hFont);

GetTextExtentPoint(hDCScreen,szMaxWidth,lstrlen(szMaxWidth),&size);

SelectObject(hDCScreen, hFontT);

cxText = size.cx;

cyText = size.cy * 2;

cxIcon = GetSystemMetrics(SM_CXICON);

cyIcon = GetSystemMetrics(SM_CYICON);

// If we have no label, then we want the metafile to be the width of

// the icon (plus margin), not the width of the fattest string.

if ( (NULL == pszLabel) || ('\0' == *pszLabel) )

cx = cxIcon + cxIcon / 4;

else

cx = max(cxText, cxIcon);

cy=cyIcon+cyText+4;

//Set the metafile size to fit the icon and label

SetWindowOrgEx(hDC, 0, 0, &point);

SetWindowExtEx(hDC, cx, cy, &size);

//Set up rectangle to pass to OleStdIconLabelTextOut

SetRectEmpty(&TextRect);

TextRect.right = cx;

TextRect.bottom = cy;

//Draw the icon and the text, centered with respect to each other.

DrawIcon(hDC, (cx-cxIcon)/2, 0, hIcon);

//String that indicates where to stop if we're only doing icons

Escape(hDC, MFCOMMENT, lstrlen(szIconOnly)+1, szIconOnly, NULL);

SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT));

SetBkMode(hDC, TRANSPARENT);

fuAlign = SetTextAlign(hDC, TA_LEFT | TA_TOP | TA_NOUPDATECP);

OleStdIconLabelTextOut(hDC,

   hFont,

   0,

   cy - cyText,

   ETO_CLIPPED,

   &TextRect,

   pszLabel,

   cchLabel,

   NULL);

//Write comments containing the icon source file and index.

if (NULL!=pszSourceFile)

{

//+1 on string lengths insures the null terminator is embedded.

Escape(hDC, MFCOMMENT, lstrlen(pszSourceFile)+1, pszSourceFile, NULL);

cchLabel=wsprintf(szIndex, "%u", iIcon);

Escape(hDC, MFCOMMENT, cchLabel+1, szIndex, NULL);

}

SetTextAlign(hDC, fuAlign);

//All done with the metafile, now stuff it all into a METAFILEPICT.

hMF=CloseMetaFile(hDC);

if (NULL==hMF)

{

GlobalFree(hMem);

ReleaseDC(NULL, hDCScreen);

return NULL;

}

//Fill out the structure

pMF=(LPMETAFILEPICT)GlobalLock(hMem);

//Transform to HIMETRICS

cx=XformWidthInPixelsToHimetric(hDCScreen, cx);

cy=XformHeightInPixelsToHimetric(hDCScreen, cy);

ReleaseDC(NULL, hDCScreen);

pMF->mm=MM_ANISOTROPIC;

pMF->xExt=cx;

pMF->yExt=cy;

pMF->hMF=hMF;

GlobalUnlock(hMem);

DeleteObject(hFont);

return hMem;

}

#endif  // OBSOLETE

/*

 * GetAssociatedExecutable

 *

 * Purpose:  Finds the executable associated with the provided extension

 *

 * Parameters:

 *   lpszExtension   LPSTR points to the extension we're trying to find

 *                   an exe for. Does **NO** validation.

 *

 *   lpszExecutable  LPSTR points to where the exe name will be returned.

 *                   No validation here either - pass in 128 char buffer.

 *

 * Return:

 *   BOOL            TRUE if we found an exe, FALSE if we didn't.

 *

 */

BOOL FAR PASCAL GetAssociatedExecutable(LPSTR lpszExtension, LPSTR lpszExecutable)

{

   HKEY    hKey;

   LONG    dw;

   LRESULT lRet;

   char    szValue[OLEUI_CCHKEYMAX];

   char    szKey[OLEUI_CCHKEYMAX];

   LPSTR   lpszTemp, lpszExe;

   lRet = RegOpenKey(HKEY_CLASSES_ROOT, NULL, &hKey);

   if (ERROR_SUCCESS != lRet)

  return FALSE;

   dw = OLEUI_CCHPATHMAX;

   lRet = RegQueryValue(hKey, lpszExtension, (LPSTR)szValue, &dw);  //ProgId

   if (ERROR_SUCCESS != lRet)

   {

  RegCloseKey(hKey);

  return FALSE;

   }

   // szValue now has ProgID

   lstrcpy(szKey, szValue);

   lstrcat(szKey, "\\Shell\\Open\\Command");

   dw = OLEUI_CCHPATHMAX;

   lRet = RegQueryValue(hKey, (LPSTR)szKey, (LPSTR)szValue, &dw);

   if (ERROR_SUCCESS != lRet)

   {

  RegCloseKey(hKey);

  return FALSE;

   }

   // szValue now has an executable name in it.  Let's null-terminate

   // at the first post-executable space (so we don't have cmd line

   // args.

   lpszTemp = (LPSTR)szValue;

   while (('\0' != *lpszTemp) && (isspace(*lpszTemp)))

  lpszTemp++;     // Strip off leading spaces

   lpszExe = lpszTemp;

   while (('\0' != *lpszTemp) && (!isspace(*lpszTemp)))

  lpszTemp++;     // Step through exe name

   *lpszTemp = '\0';  // null terminate at first space (or at end).

   lstrcpy(lpszExecutable, lpszExe);

   return TRUE;

}

/*

 * HIconAndSourceFromClass

 *

 * Purpose:

 *  Given an object class name, finds an associated executable in the

 *  registration database and extracts the first icon from that

 *  executable.  If none is available or the class has no associated

 *  executable, this function returns NULL.

 *

 * Parameters:

 *  rclsid          pointer to clsid to look up.

 *  pszSource       LPSTR in which to place the source of the icon.

 *                  This is assumed to be OLEUI_CCHPATHMAX

 *  puIcon          UINT FAR * in which to store the index of the

 *                  icon in pszSource.

 *

 * Return Value:

 *  HICON           Handle to the extracted icon if there is a module

 *                  associated to pszClass.  NULL on failure to either

 *                  find the executable or extract and icon.

 */

HICON WINAPI HIconAndSourceFromClass(REFCLSID rclsid, LPSTR pszSource, UINT FAR *puIcon)

{

HICON           hIcon;

UINT            IconIndex;

if (NULL==rclsid || NULL==pszSource || IsEqualCLSID(rclsid,&CLSID_NULL))

return NULL;

if (!FIconFileFromClass(rclsid, pszSource, OLEUI_CCHPATHMAX, &IconIndex))

return NULL;

hIcon=ExtractIcon(ghInst, pszSource, IconIndex);

if ((HICON)32 > hIcon)

hIcon=NULL;

else

*puIcon= IconIndex;

return hIcon;

}

/*

 * FIconFileFromClass

 *

 * Purpose:

 *  Looks up the path to executable that contains the class default icon.

 *

 * Parameters:

 *  rclsid          pointer to CLSID to look up.

 *  pszEXE          LPSTR at which to store the server name

 *  cch             UINT size of pszEXE

 *  lpIndex         LPUINT to index of icon within executable

 *

 * Return Value:

 *  BOOL            TRUE if one or more characters were loaded into pszEXE.

 *                  FALSE otherwise.

 */

BOOL WINAPI FIconFileFromClass(REFCLSID rclsid, LPSTR pszEXE, UINT cch, UINT FAR *lpIndex)

{

LONG          dw;

LONG          lRet;

HKEY          hKey;

LPMALLOC      lpIMalloc;

HRESULT       hrErr;

LPSTR         lpBuffer;

LPSTR         lpIndexString;

UINT          cBufferSize = 136;// room for 128 char path and icon's index

char          szKey[64];

LPSTR         pszClass;

if (NULL==rclsid || NULL==pszEXE || 0==cch || IsEqualCLSID(rclsid,&CLSID_NULL))

return FALSE;

//Here, we use CoGetMalloc and alloc a buffer (maxpathlen + 8) to

//pass to RegQueryValue.  Then, we copy the exe to pszEXE and the

//index to *lpIndex.

hrErr = CoGetMalloc(MEMCTX_TASK, &lpIMalloc);

if (NOERROR != hrErr)

  return FALSE;

lpBuffer = (LPSTR)lpIMalloc->lpVtbl->Alloc(lpIMalloc, cBufferSize);

if (NULL == lpBuffer)

{

  lpIMalloc->lpVtbl->Release(lpIMalloc);

  return FALSE;

}

if (CoIsOle1Class(rclsid))

{

  LPSTR lpszProgID;

  // we've got an ole 1.0 class on our hands, so we look at

  // progID\protocol\stdfileedting\server to get the

  // name of the executable.

  ProgIDFromCLSID(rclsid, &lpszProgID);

  //Open up the class key

  lRet=RegOpenKey(HKEY_CLASSES_ROOT, lpszProgID, &hKey);

  if (ERROR_SUCCESS != lRet)

  {

 lpIMalloc->lpVtbl->Free(lpIMalloc, lpszProgID);

 lpIMalloc->lpVtbl->Free(lpIMalloc, lpBuffer);

 lpIMalloc->lpVtbl->Release(lpIMalloc);

 return FALSE;

  }

  dw=(LONG)cBufferSize;

  lRet = RegQueryValue(hKey, "Protocol\\StdFileEditing\\Server", lpBuffer, &dw);

  if (ERROR_SUCCESS != lRet)

  {

 RegCloseKey(hKey);

 lpIMalloc->lpVtbl->Free(lpIMalloc, lpszProgID);

 lpIMalloc->lpVtbl->Free(lpIMalloc, lpBuffer);

 lpIMalloc->lpVtbl->Release(lpIMalloc);

 return FALSE;

  }

  // Use server and 0 as the icon index

  LSTRCPYN(pszEXE, lpBuffer, cch);

  *lpIndex = 0;

  RegCloseKey(hKey);

  lpIMalloc->lpVtbl->Free(lpIMalloc, lpszProgID);

  lpIMalloc->lpVtbl->Free(lpIMalloc, lpBuffer);

  lpIMalloc->lpVtbl->Release(lpIMalloc);

  return TRUE;

}

/*

 * We have to go walking in the registration database under the

 * classname, so we first open the classname key and then check

 * under "\\DefaultIcon" to get the file that contains the icon.

 */

StringFromCLSID(rclsid, &pszClass);

lstrcpy(szKey, "CLSID\\");

lstrcat(szKey, pszClass);

//Open up the class key

lRet=RegOpenKey(HKEY_CLASSES_ROOT, szKey, &hKey);

if (ERROR_SUCCESS != lRet)

{

lpIMalloc->lpVtbl->Free(lpIMalloc, lpBuffer);

lpIMalloc->lpVtbl->Free(lpIMalloc, pszClass);

lpIMalloc->lpVtbl->Release(lpIMalloc);

return FALSE;

}

//Get the executable path and icon index.

dw=(LONG)cBufferSize;

lRet=RegQueryValue(hKey, "DefaultIcon", lpBuffer, &dw);

if (ERROR_SUCCESS != lRet)

{

  // no DefaultIcon  key...try LocalServer

  dw=(LONG)cBufferSize;

#ifdef WIN32

      lRet=RegQueryValue(hKey, "LocalServer32", lpBuffer, &dw);

#else

      lRet=RegQueryValue(hKey, "LocalServer", lpBuffer, &dw);

#endif

  if (ERROR_SUCCESS != lRet)

  {

 // no LocalServer entry either...they're outta luck.

 RegCloseKey(hKey);

 lpIMalloc->lpVtbl->Free(lpIMalloc, lpBuffer);

 lpIMalloc->lpVtbl->Free(lpIMalloc, pszClass);

 lpIMalloc->lpVtbl->Release(lpIMalloc);

 return FALSE;

  }

  // Use server from LocalServer or Server and 0 as the icon index

  LSTRCPYN(pszEXE, lpBuffer, cch);

  *lpIndex = 0;

  RegCloseKey(hKey);

  lpIMalloc->lpVtbl->Free(lpIMalloc, lpBuffer);

  lpIMalloc->lpVtbl->Free(lpIMalloc, pszClass);

  lpIMalloc->lpVtbl->Release(lpIMalloc);

  return TRUE;

}

RegCloseKey(hKey);

// lpBuffer contains a string that looks like "<pathtoexe>,<iconindex>",

// so we need to separate the path and the icon index.

lpIndexString = PointerToNthField(lpBuffer, 2, ',');

if ('\0' == *lpIndexString)  // no icon index specified - use 0 as default.

{

   *lpIndex = 0;

}

else

{

   LPSTR lpTemp;

   static char  szTemp[16];

   lstrcpy((LPSTR)szTemp, lpIndexString);

   // Put the icon index part into *pIconIndex

   *lpIndex = atoi((const char *)szTemp);

   // Null-terminate the exe part.

   lpTemp = AnsiPrev(lpBuffer, lpIndexString);

   *lpTemp = '\0';

}

if (!LSTRCPYN(pszEXE, lpBuffer, cch))

{

   lpIMalloc->lpVtbl->Free(lpIMalloc, lpBuffer);

   lpIMalloc->lpVtbl->Free(lpIMalloc, pszClass);

   lpIMalloc->lpVtbl->Release(lpIMalloc);

   return FALSE;

}

// Free the memory we alloc'd and leave.

lpIMalloc->lpVtbl->Free(lpIMalloc, lpBuffer);

lpIMalloc->lpVtbl->Free(lpIMalloc, pszClass);

lpIMalloc->lpVtbl->Release(lpIMalloc);

return TRUE;

}

/*

 * OleStdIconLabelTextOut

 *

 * Purpose:

 *  Replacement for DrawText to be used in the "Display as Icon" metafile.

 *  Uses ExtTextOut to output a string center on (at most) two lines.

 *  Uses a very simple word wrap algorithm to split the lines.

 *

 * Parameters:  (same as for ExtTextOut, except for hFont)

 *  hDC           device context to draw into; if this is NULL, then we don't

 *                ETO the text, we just return the index of the beginning

 *                of the second line

 *  hFont         font to use

 *  nXStart       x-coordinate of starting position

 *  nYStart       y-coordinate of starting position

 *  fuOptions     rectangle type

 *  lpRect        rect far * containing rectangle to draw text in.

 *  lpszString    string to draw

 *  cchString     length of string (truncated if over OLEUI_CCHLABELMAX)

 *  lpDX          spacing between character cells

 *

 * Return Value:

 *  UINT          Index of beginning of last line (0 if there's only one

 *                line of text).

 *

 */

STDAPI_(UINT) OleStdIconLabelTextOut(HDC        hDC,

 HFONT      hFont,

 int        nXStart,

 int        nYStart,

 UINT       fuOptions,

 RECT FAR * lpRect,

 LPSTR      lpszString,

 UINT       cchString,

 int FAR *  lpDX)

{

  HDC          hDCScreen;

  static char  szTempBuff[OLEUI_CCHLABELMAX];

  int          cxString, cyString, cxMaxString;

  int          cxFirstLine, cyFirstLine, cxSecondLine;

  int          index;

  int          cch = cchString;

  char         chKeep;

  LPSTR        lpszSecondLine;

  HFONT        hFontT;

  BOOL         fPrintText = TRUE;

  UINT         iLastLineStart = 0;

  SIZE         size;

  // Initialization stuff...

  if (NULL == hDC)  // If we got NULL as the hDC, then we don't actually call ETO

fPrintText = FALSE;

  // Make a copy of the string (NULL or non-NULL) that we're using

  if (NULL == lpszString)

*szTempBuff = '\0';

  else

LSTRCPYN(szTempBuff, lpszString, sizeof(szTempBuff));

  // set maximum width

  cxMaxString = lpRect->right - lpRect->left;

  // get screen DC to do text size calculations

  hDCScreen = GetDC(NULL);

  hFontT=SelectObject(hDCScreen, hFont);

  // get the extent of our label

  GetTextExtentPoint(hDCScreen, szTempBuff, cch, &size);

  cxString = size.cx;

  cyString = size.cy;

  // Select in the font we want to use

  if (fPrintText)

 SelectObject(hDC, hFont);

  // String is smaller than max string - just center, ETO, and return.

  if (cxString <= cxMaxString)

  {

if (fPrintText)

   ExtTextOut(hDC,

  nXStart + (lpRect->right - cxString) / 2,

  nYStart,

  fuOptions,

  lpRect,

  szTempBuff,

  cch,

  NULL);

iLastLineStart = 0;  // only 1 line of text

goto CleanupAndLeave;

  }

  // String is too long...we've got to word-wrap it.

  // Are there any spaces, slashes, tabs, or bangs in string?

  if (lstrlen(szTempBuff) != (int)strcspn(szTempBuff, szSeparators))

  {

 // Yep, we've got spaces, so we'll try to find the largest

 // space-terminated string that will fit on the first line.

 index = cch;

 while (index >= 0)

 {

   char cchKeep;

   // scan the string backwards for spaces, slashes, tabs, or bangs

   while (!IS_SEPARATOR(szTempBuff[index]) )

 index--;

   if (index <= 0)

 break;

   cchKeep = szTempBuff[index];  // remember what char was there

   szTempBuff[index] = '\0';  // just for now

   GetTextExtentPoint(

   hDCScreen, (LPSTR)szTempBuff,lstrlen((LPSTR)szTempBuff),&size);

   cxFirstLine = size.cx;

   cyFirstLine = size.cy;

   szTempBuff[index] = cchKeep;   // put the right char back

   if (cxFirstLine <= cxMaxString)

   {

   iLastLineStart = index + 1;

   if (!fPrintText)

 goto CleanupAndLeave;

   ExtTextOut(hDC,

  nXStart +  (lpRect->right - cxFirstLine) / 2,

  nYStart,

  fuOptions,

  lpRect,

  (LPSTR)szTempBuff,

  index + 1,

  lpDX);

   lpszSecondLine = (LPSTR)szTempBuff;

   lpszSecondLine += index + 1;

   GetTextExtentPoint(hDCScreen,

lpszSecondLine,

lstrlen(lpszSecondLine),

&size);

   // If the second line is wider than the rectangle, we

   // just want to clip the text.

   cxSecondLine = min(size.cx, cxMaxString);

   ExtTextOut(hDC,

  nXStart + (lpRect->right - cxSecondLine) / 2,

  nYStart + cyFirstLine,

  fuOptions,

  lpRect,

  lpszSecondLine,

  lstrlen(lpszSecondLine),

  lpDX);

   goto CleanupAndLeave;

   }  // end if

   index--;

 }  // end while

  }  // end if

  // Here, there are either no spaces in the string (strchr(szTempBuff, ' ')

  // returned NULL), or there spaces in the string, but they are

  // positioned so that the first space terminated string is still

  // longer than one line. So, we walk backwards from the end of the

  // string until we find the largest string that will fit on the first

  // line , and then we just clip the second line.

  cch = lstrlen((LPSTR)szTempBuff);

  chKeep = szTempBuff[cch];

  szTempBuff[cch] = '\0';

  GetTextExtentPoint(hDCScreen, szTempBuff, lstrlen(szTempBuff),&size);

  cxFirstLine = size.cx;

  cyFirstLine = size.cy;

  while (cxFirstLine > cxMaxString)

  {

 // We allow 40 characters in the label, but the metafile is

 // only as wide as 10 W's (for aesthetics - 20 W's wide looked

 // dumb.  This means that if we split a long string in half (in

 // terms of characters), then we could still be wider than the

 // metafile.  So, if this is the case, we just step backwards

 // from the halfway point until we get something that will fit.

 // Since we just let ETO clip the second line

 szTempBuff[cch--] = chKeep;

 if (0 == cch)

   goto CleanupAndLeave;

 chKeep = szTempBuff[cch];

 szTempBuff[cch] = '\0';

 GetTextExtentPoint(

 hDCScreen, szTempBuff, lstrlen(szTempBuff), &size);

 cxFirstLine = size.cx;

  }

  iLastLineStart = cch;

  if (!fPrintText)

goto CleanupAndLeave;

  ExtTextOut(hDC,

 nXStart + (lpRect->right - cxFirstLine) / 2,

 nYStart,

 fuOptions,

 lpRect,

 (LPSTR)szTempBuff,

 lstrlen((LPSTR)szTempBuff),

 lpDX);

  szTempBuff[cch] = chKeep;

  lpszSecondLine = szTempBuff;

  lpszSecondLine += cch;

  GetTextExtentPoint(

  hDCScreen, (LPSTR)lpszSecondLine, lstrlen(lpszSecondLine), &size);

  // If the second line is wider than the rectangle, we

  // just want to clip the text.

  cxSecondLine = min(size.cx, cxMaxString);

  ExtTextOut(hDC,

 nXStart + (lpRect->right - cxSecondLine) / 2,

 nYStart + cyFirstLine,

 fuOptions,

 lpRect,

 lpszSecondLine,

 lstrlen(lpszSecondLine),

 lpDX);

CleanupAndLeave:

  SelectObject(hDCScreen, hFontT);

  ReleaseDC(NULL, hDCScreen);

  return iLastLineStart;

}

/*

 * PointerToNthField

 *

 * Purpose:

 *  Returns a pointer to the beginning of the nth field.

 *  Assumes null-terminated string.

 *

 * Parameters:

 *  lpszString        string to parse

 *  nField            field to return starting index of.

 *  chDelimiter       char that delimits fields

 *

 * Return Value:

 *  LPSTR             pointer to beginning of nField field.

 *                    NOTE: If the null terminator is found

 *                          Before we find the Nth field, then

 *                          we return a pointer to the null terminator -

 *                          calling app should be sure to check for

 *                          this case.

 *

 */

LPSTR WINAPI PointerToNthField(LPSTR lpszString, int nField, char chDelimiter)

{

   LPSTR lpField = lpszString;

   int   cFieldFound = 1;

   if (1 ==nField)

  return lpszString;

   while (*lpField != '\0')

   {

  if (*lpField++ == chDelimiter)

  {

 cFieldFound++;

 if (nField == cFieldFound)

return lpField;

  }

   }

   return lpField;

}


HATCH.C  (WRAPUI Sample)

/*

 * HATCH.C

 *

 * Miscellaneous API's to generate hatch window for in-place active

 * objects. This is part of the OLE 2.0 User Interface Support Library.

 *

 * Copyright (c)1993 Microsoft Corporation, All Right Reserved

 */

#define STRICT  1

#include "ole2ui.h"

// offsets in the extra bytes stored with the hatch window

#define EB_HATCHWIDTH       0

#define EB_HATCHRECT_LEFT   2

#define EB_HATCHRECT_TOP    4

#define EB_HATCHRECT_RIGHT  6

#define EB_HATCHRECT_BOTTOM 8

// class name of hatch window

#define CLASS_HATCH     "Hatch Window"

// local function prototypes

LRESULT WINAPI EXPORT HatchWndProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam);

/*

 * HatchRegisterClass

 *

 * Purpose:

 *  Register the hatch window

 *

 * Parameters:

 *  hInst           Process instance

 *

 * Return Value:

 *  TRUE            if successful

 *  FALSE           if failed

 *

 */

STDAPI_(BOOL) RegisterHatchWindowClass(HINSTANCE hInst)

{

WNDCLASS wc;

// Register Hatch Window Class

wc.style = CS_BYTEALIGNWINDOW;

wc.lpfnWndProc = HatchWndProc;

wc.cbClsExtra = 0;

wc.cbWndExtra = 5 * sizeof(int);    // extra bytes stores

//     uHatchWidth

//     rcHatchRect

wc.hInstance = hInst;

wc.hIcon = NULL;

wc.hCursor = LoadCursor(NULL, IDC_ARROW);

wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);

wc.lpszMenuName = NULL;

wc.lpszClassName = CLASS_HATCH;

if (!RegisterClass(&wc))

return FALSE;

else

return TRUE;

}

/*

 * CreateHatchWindow

 *

 * Purpose:

 *  Create the hatch window

 *

 * Parameters:

 *  hWndParent          parent of hatch window

 *  hInst               instance handle

 *

 * Return Value:

 *  pointer to hatch window         if successful

 *  NULL                            if failed

 *

 */

STDAPI_(HWND) CreateHatchWindow(HWND hWndParent, HINSTANCE hInst)

{

HWND         hWnd;

if (!hWndParent || !hInst)

return NULL;

hWnd = CreateWindow(

CLASS_HATCH,

"Hatch Window",

WS_CHILDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,

0, 0, 0, 0,

hWndParent,

(HMENU)NULL,

hInst,

0L

);

if (!hWnd)

return NULL;

return hWnd;

}

/*

 *  GetHatchWidth

 *

 *  Purpose:

 *      Get width of hatch border

 *

 *  Parameters:

 *      hWndHatch       hatch window handle

 *

 *  Return Value:

 *      width of the hatch border

 */

STDAPI_(UINT) GetHatchWidth(HWND hWndHatch)

{

if (!IsWindow(hWndHatch))

return 0;

return (UINT)GetWindowWord(hWndHatch, EB_HATCHWIDTH);

}

/*

 *  GetHatchRect

 *

 *  Purpose:

 *      Get hatch rect. this is the size of the hatch window if it were

 *      not clipped by the ClipRect.

 *

 *  Parameters:

 *      hWndHatch       hatch window handle

 *      lprcHatchRect   hatch rect

 *

 *  Return Value:

 *      none

 */

STDAPI_(void) GetHatchRect(HWND hWndHatch, LPRECT lprcHatchRect)

{

if (!IsWindow(hWndHatch)) {

SetRect(lprcHatchRect, 0, 0, 0, 0);

return;

}

lprcHatchRect->left = GetWindowWord(hWndHatch, EB_HATCHRECT_LEFT);

lprcHatchRect->top = GetWindowWord(hWndHatch, EB_HATCHRECT_TOP);

lprcHatchRect->right = GetWindowWord(hWndHatch, EB_HATCHRECT_RIGHT);

lprcHatchRect->bottom = GetWindowWord(hWndHatch, EB_HATCHRECT_BOTTOM);

}

/* SetHatchRect

 *

 *

 *  Purpose:

 *      Store hatch rect with HatchRect window.

 *      this rect is the size of the hatch window if it were

 *      not clipped by the ClipRect.

 *

 *  Parameters:

 *      hWndHatch       hatch window handle

 *      lprcHatchRect   hatch rect

 *

 *  Return Value:

 *      none

 */

STDAPI_(void) SetHatchRect(HWND hWndHatch, LPRECT lprcHatchRect)

{

if (!IsWindow(hWndHatch))

return;

SetWindowWord(hWndHatch, EB_HATCHRECT_LEFT,  (WORD)lprcHatchRect->left);

SetWindowWord(hWndHatch, EB_HATCHRECT_TOP,   (WORD)lprcHatchRect->top);

SetWindowWord(hWndHatch, EB_HATCHRECT_RIGHT, (WORD)lprcHatchRect->right);

SetWindowWord(hWndHatch, EB_HATCHRECT_BOTTOM,(WORD)lprcHatchRect->bottom);

}

/* SetHatchWindowSize

 *

 *

 *  Purpose:

 *      Move/size the HatchWindow correctly given the rect required by the

 *      in-place server object window and the lprcClipRect imposed by the

 *      in-place container. both rect's are expressed in the client coord.

 *      of the in-place container's window (which is the parent of the

 *      HatchWindow).

 *

 *      OLE2NOTE: the in-place server must honor the lprcClipRect specified

 *      by its in-place container. it must NOT draw outside of the ClipRect.

 *      in order to achieve this, the hatch window is sized to be

 *      exactly the size that should be visible (rcVisRect). the

 *      rcVisRect is defined as the intersection of the full size of

 *      the HatchRect window and the lprcClipRect.

 *      the ClipRect could infact clip the HatchRect on the

 *      right/bottom and/or on the top/left. if it is clipped on the

 *      right/bottom then it is sufficient to simply resize the hatch

 *      window. but if the HatchRect is clipped on the top/left then

 *      in-place server document window (child of HatchWindow) must be moved

 *      by the delta that was clipped. the window origin of the

 *      in-place server window will then have negative coordinates relative

 *      to its parent HatchWindow.

 *

 *  Parameters:

 *      hWndHatch       hatch window handle

 *      lprcIPObjRect   full size of in-place server object window

 *      lprcClipRect    clipping rect imposed by in-place container

 *      lpptOffset      offset required to position in-place server object

 *                      window properly. caller should call:

 *                          OffsetRect(&rcObjRect,lpptOffset->x,lpptOffset->y)

 *

 *  Return Value:

 *      none

 */

STDAPI_(void) SetHatchWindowSize(

HWND        hWndHatch,

LPRECT      lprcIPObjRect,

LPRECT      lprcClipRect,

LPPOINT       lpptOffset

)

{

RECT        rcHatchRect;

RECT        rcVisRect;

UINT        uHatchWidth;

POINT       ptOffset;

if (!IsWindow(hWndHatch))

return;

rcHatchRect = *lprcIPObjRect;

uHatchWidth = GetHatchWidth(hWndHatch);

InflateRect((LPRECT)&rcHatchRect, uHatchWidth + 1, uHatchWidth + 1);

IntersectRect((LPRECT)&rcVisRect, (LPRECT)&rcHatchRect, lprcClipRect);

MoveWindow(

hWndHatch,

rcVisRect.left,

rcVisRect.top,

rcVisRect.right-rcVisRect.left,

rcVisRect.bottom-rcVisRect.top,

TRUE    /* fRepaint */

);

InvalidateRect(hWndHatch, NULL, TRUE);

ptOffset.x = -rcHatchRect.left + (rcHatchRect.left - rcVisRect.left);

ptOffset.y = -rcHatchRect.top + (rcHatchRect.top - rcVisRect.top);

/* convert the rcHatchRect into the client coordinate system of the

**    HatchWindow itself

*/

OffsetRect((LPRECT)&rcHatchRect, ptOffset.x, ptOffset.y);

SetHatchRect(hWndHatch, (LPRECT)&rcHatchRect);

// calculate offset required to position in-place server doc window

lpptOffset->x = ptOffset.x;

lpptOffset->y = ptOffset.y;

}

/*

 *  HatchWndProc

 *

 *  Purpose:

 *      WndProc for hatch window

 *

 *  Parameters:

 *      hWnd

 *      Message

 *      wParam

 *      lParam

 *

 *  Return Value:

 *      message dependent

 */

LRESULT WINAPI EXPORT HatchWndProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam)

{

int nBorderWidth;

switch (Message) {

case WM_CREATE:

nBorderWidth = GetProfileInt(

"windows",

"oleinplaceborderwidth",

DEFAULT_HATCHBORDER_WIDTH

);

SetWindowWord(hWnd, EB_HATCHWIDTH, (WORD)nBorderWidth);

break;

case WM_PAINT:

{

HDC hDC;

PAINTSTRUCT ps;

RECT rcHatchRect;

nBorderWidth = GetHatchWidth(hWnd);

hDC = BeginPaint(hWnd, &ps);

GetHatchRect(hWnd, (LPRECT)&rcHatchRect);

OleUIDrawShading(&rcHatchRect, hDC, OLEUI_SHADE_BORDERIN,

nBorderWidth);

InflateRect((LPRECT)&rcHatchRect, -nBorderWidth, -nBorderWidth);

OleUIDrawHandles(&rcHatchRect, hDC, OLEUI_HANDLES_OUTSIDE,

nBorderWidth+1, TRUE);

EndPaint(hWnd, &ps);

break;

}

/* OLE2NOTE: Any window that is used during in-place activation

**    must handle the WM_SETCURSOR message or else the cursor

**    of the in-place parent will be used. if WM_SETCURSOR is

**    not handled, then DefWindowProc sends the message to the

**    window's parent.

*/

case WM_SETCURSOR:

SetCursor(LoadCursor( NULL, MAKEINTRESOURCE(IDC_ARROW) ) );

return (LRESULT)TRUE;

default:

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

}

return 0L;

}


ICON.H  (WRAPUI Sample)

/*

 * ICON.H

 *

 * Internal definitions, structures, and function prototypes for the

 * OLE 2.0 UI Change Icon dialog.

 *

 * Copyright (c)1992 Microsoft Corporation, All Right Reserved

 */

#ifndef _ICON_H_

#define _ICON_H_

#ifndef RC_INVOKED

#pragma message ("INCLUDING ICON.H from " __FILE__)

#endif  /* RC_INVOKED */

#define CXICONPAD                   12

#define CYICONPAD                   4

// Property used by ChangeIcon dialog to give its parent window access to

// its hDlg. The PasteSpecial dialog may need to force the ChgIcon dialog

// down if the clipboard contents change underneath it. if so it will send

// a IDCANCEL command to the ChangeIcon dialog.

#define PROP_HWND_CHGICONDLG    "HWND_CIDLG"

//Internally used structure

typedef struct tagCHANGEICON

{

LPOLEUICHANGEICON   lpOCI;      //Original structure passed.

/*

 * What we store extra in this structure besides the original caller's

 * pointer are those fields that we need to modify during the life of

 * the dialog but that we don't want to change in the original structure

 * until the user presses OK.

 */

DWORD               dwFlags;

HICON               hCurIcon;

char                szLabel[OLEUI_CCHLABELMAX+1];

char                szFile[OLEUI_CCHPATHMAX];

UINT                iIcon;

HICON               hDefIcon;

char                szDefIconFile[OLEUI_CCHPATHMAX];

UINT                iDefIcon;

UINT                nBrowseHelpID;      // Help ID callback for Browse dlg

} CHANGEICON, *PCHANGEICON, FAR *LPCHANGEICON;

//Internal function prototypes

//ICON.C

BOOL CALLBACK EXPORT ChangeIconDialogProc(HWND, UINT, WPARAM, LPARAM);

BOOL            FChangeIconInit(HWND, WPARAM, LPARAM);

UINT            UFillIconList(HWND, UINT, LPSTR);

BOOL            FDrawListIcon(LPDRAWITEMSTRUCT);

void            UpdateResultIcon(LPCHANGEICON, HWND, UINT);

#endif //_ICON_H_


ICON.C  (WRAPUI Sample)

/*

 * ICON.C

 *

 * Implements the OleUIChangeIcon function which invokes the complete

 * Change Icon dialog.

 *

 * Copyright (c)1992 Microsoft Corporation, All Right Reserved

 */

#define STRICT  1

#include "ole2ui.h"

#include "common.h"

#include "utility.h"

#include "icon.h"

#include "geticon.h"

/*

 * OleUIChangeIcon

 *

 * Purpose:

 *  Invokes the standard OLE Change Icon dialog box allowing the user

 *  to select an icon from an icon file, executable, or DLL.

 *

 * Parameters:

 *  lpCI            LPOLEUIChangeIcon pointing to the in-out structure

 *                  for this dialog.

 *

 * Return Value:

 *  UINT            OLEUI_SUCCESS or OLEUI_OK if all is well, otherwise

 *                  an error value.

 */

STDAPI_(UINT) OleUIChangeIcon(LPOLEUICHANGEICON lpCI)

{

UINT        uRet;

HGLOBAL     hMemDlg=NULL;

uRet=UStandardValidation((LPOLEUISTANDARD)lpCI, sizeof(OLEUICHANGEICON)

 , &hMemDlg);

if (OLEUI_SUCCESS!=uRet)

return uRet;

#if defined( OBSOLETE )

if (NULL==lpCI->hMetaPict)

uRet=OLEUI_CIERR_MUSTHAVECURRENTMETAFILE;

#endif

if (lpCI->dwFlags & CIF_USEICONEXE)

{

  if (   (NULL == lpCI->szIconExe)

  || (IsBadReadPtr(lpCI->szIconExe, lpCI->cchIconExe))

  || (IsBadWritePtr(lpCI->szIconExe, lpCI->cchIconExe)) )

 uRet = OLEUI_CIERR_SZICONEXEINVALID;

}

 // REVIEW: how do we validate the CLSID?

/*

if ('\0'==*((LPSTR)&lpCI->clsid))

uRet=OLEUI_CIERR_MUSTHAVECLSID;

*/

if (OLEUI_ERR_STANDARDMIN <= uRet)

{

if (NULL!=hMemDlg)

FreeResource(hMemDlg);

return uRet;

}

//Now that we've validated everything, we can invoke the dialog.

return UStandardInvocation(ChangeIconDialogProc, (LPOLEUISTANDARD)lpCI

   , hMemDlg, MAKEINTRESOURCE(IDD_CHANGEICON));

}

/*

 * ChangeIconDialogProc

 *

 * Purpose:

 *  Implements the OLE Change Icon dialog as invoked through the

 *  OleUIChangeIcon function.

 *

 * Parameters:

 *  Standard

 *

 * Return Value:

 *  Standard

 */

BOOL CALLBACK EXPORT ChangeIconDialogProc(HWND hDlg, UINT iMsg

 , WPARAM wParam, LPARAM lParam)

{

LPCHANGEICON            lpCI;

HICON                   hIcon;

HGLOBAL                 hMetaPict;

BOOL                    fOK=FALSE;

UINT                    uRet=0;

LPSTR                   psz;

char                    szTemp[OLEUI_CCHPATHMAX];

//Declare Win16/Win32 compatible WM_COMMAND parameters.

COMMANDPARAMS(wID, wCode, hWndMsg);

lpCI=(LPCHANGEICON)LpvStandardEntry(hDlg, iMsg, wParam, lParam, &uRet);

//If the hook processed the message, we're done.

if (0!=uRet)

return uRet;

//Process the temination message

if (iMsg==uMsgEndDialog)

{

//Insure that icons are properly destroyed.

SendDlgItemMessage(hDlg, ID_ICONLIST, LB_RESETCONTENT, 0, 0L);

StandardCleanup(lpCI, hDlg);

EndDialog(hDlg, wParam);

return TRUE;

}

switch (iMsg)

{

case WM_INITDIALOG:

FChangeIconInit(hDlg, wParam, lParam);

return TRUE;

case WM_MEASUREITEM:

{

LPMEASUREITEMSTRUCT     lpMI=(LPMEASUREITEMSTRUCT)lParam;

//All icons are system metric+padding in width and height

lpMI->itemWidth =GetSystemMetrics(SM_CXICON)+CXICONPAD;

lpMI->itemHeight=GetSystemMetrics(SM_CYICON)+CYICONPAD;

}

break;

case WM_DRAWITEM:

return FDrawListIcon((LPDRAWITEMSTRUCT)lParam);

case WM_DELETEITEM:

//Free the GDI object for the item

DestroyIcon((HICON)LOWORD(((LPDELETEITEMSTRUCT)lParam)->itemData));

break;

case WM_COMMAND:

switch (wID)

{

case ID_CURRENT:

case ID_DEFAULT:

case ID_FROMFILE:

UpdateResultIcon(lpCI, hDlg, wID);

break;

case ID_LABELEDIT:

//When the edit loses focus, update the result display

if (EN_KILLFOCUS==wCode)

{

GetDlgItemText(hDlg, ID_LABELEDIT, szTemp, sizeof(szTemp));

SetDlgItemText(hDlg, ID_RESULTLABEL, szTemp);

}

break;

case ID_FROMFILEEDIT:

//If the text changed, remove any selection in the list.

GetDlgItemText(hDlg, ID_FROMFILEEDIT, szTemp, sizeof(szTemp));

if (lpCI && lstrcmpi(szTemp, lpCI->szFile))

{

SendDlgItemMessage(hDlg, ID_ICONLIST, LB_SETCURSEL

   , (WPARAM)-1, 0);

//Also force selection of ID_FROMFILE

CheckRadioButton(hDlg, ID_CURRENT, ID_FROMFILE, ID_FROMFILE);

}

break;

case ID_ICONLIST:

switch (wCode)

{

case LBN_SETFOCUS:

//If we got the focus, see about updating.

GetDlgItemText(hDlg, ID_FROMFILEEDIT, szTemp

   , sizeof(szTemp));

//Check if file changed and update the list if so

if (lpCI && 0!=lstrcmpi(szTemp, lpCI->szFile))

{

lstrcpy(lpCI->szFile, szTemp);

UFillIconList(hDlg, ID_ICONLIST, lpCI->szFile);

UpdateResultIcon(lpCI, hDlg, ID_FROMFILE);

}

break;

case LBN_SELCHANGE:

UpdateResultIcon(lpCI, hDlg, ID_FROMFILE);

break;

case LBN_DBLCLK:

//Same as pressing OK.

SendCommand(hDlg, IDOK, BN_CLICKED, hWndMsg);

break;

}

break;

case ID_BROWSE:

{

DWORD dwOfnFlags;

/*

 * To allow the hook to customize the browse dialog, we

 * send OLEUI_MSG_BROWSE.  If the hook returns FALSE

 * we use the default, otherwise we trust that it retrieved

 * a filename for us.  This mechanism prevents hooks from

 * trapping ID_BROWSE to customize the dialog and from

 * trying to figure out what we do after we have the name.

 */

//Copy for reference

LSTRCPYN(szTemp, lpCI->szFile, sizeof(szTemp));

uRet=UStandardHook(lpCI, hDlg, uMsgBrowse, OLEUI_CCHPATHMAX

   , (LONG)(LPSTR)lpCI->szFile);

dwOfnFlags = OFN_FILEMUSTEXIST;

if (lpCI->lpOCI->dwFlags & CIF_SHOWHELP)

   dwOfnFlags |= OFN_SHOWHELP;

if (0==uRet)

uRet=(BOOL)Browse(hDlg, lpCI->szFile, NULL, OLEUI_CCHPATHMAX, (UINT)IDS_ICONFILTERS, (UINT)IDS_BROWSE, dwOfnFlags);

/*

 * Only reinitialize if the file changed, so if we got

 * TRUE from the hook but the user hit Cancel, we don't

 * spend time unecessarily refilling the list.

 */

if (0!=uRet && 0!=lstrcmpi(szTemp, lpCI->szFile))

{

CheckRadioButton(hDlg, ID_CURRENT, ID_FROMFILE, ID_FROMFILE);

SetDlgItemText(hDlg, ID_FROMFILEEDIT, lpCI->szFile);

UFillIconList(hDlg, ID_ICONLIST, lpCI->szFile);

UpdateResultIcon(lpCI, hDlg, ID_FROMFILE);

}

}

break;

case IDOK:

/*

 * If the user pressed enter, compare the current file

 * and the one we have stored.  If they match, then

 * refill the listbox instead of closing down.  This is

 * so the user can press Enter in the edit control as

 * they would expect to be able to do.

 */

GetDlgItemText(hDlg, ID_FROMFILEEDIT, szTemp, sizeof(szTemp));

//Check if the file changed at all.

if (0!=lstrcmpi(szTemp, lpCI->szFile))

{

lstrcpy(lpCI->szFile, szTemp);

UFillIconList(hDlg, ID_ICONLIST, lpCI->szFile);

UpdateResultIcon(lpCI, hDlg, ID_FROMFILE);

//Eat this message to prevent focus change.

return TRUE;

}

// Check if the file name is valid

//  (if FromFile is enabled)

if (ID_FROMFILE & lpCI->dwFlags)

{

OFSTRUCT    of;

HWND hWnd;

if (HFILE_ERROR==DoesFileExist(lpCI->szFile, &of))

{

OpenFileError(hDlg, of.nErrCode, lpCI->szFile);

hWnd = GetDlgItem(hDlg, ID_FROMFILEEDIT);

SetFocus(hWnd);

SendMessage(hWnd, EM_SETSEL, 0, MAKELPARAM(0, (WORD)-1));

return TRUE;  // eat this message

}

}

if ((HWND)LOWORD(lParam) != GetFocus())

   SetFocus((HWND)LOWORD(lParam));

/*

 * On closing, create a new metafilepict with the

 * current icon and label, destroying the old structure.

 *

 * Since we make a copy of the icon by placing it into

 * the metafile, we have to make sure we delete the

 * icon in the current field.  When the listbox is

 * destroyed WM_DELETEITEMs will clean it up appropriately.

 */

hIcon=(HICON)SendDlgItemMessage(hDlg, ID_RESULTICON

, STM_GETICON, 0, 0L);

/*

 * If default is selected then we get the source

 * information from registrion database for the

 * current class to put in the metafile.  If current

 * is selected the we just retrieve the original file

 * again and recreate the metafile.  If from file is

 * selected we use the current filename from the

 * control and the current listbox selection.

 */

psz=lpCI->szFile;

if (lpCI->dwFlags & CIF_SELECTDEFAULT)

{

psz=lpCI->szDefIconFile;

lpCI->iIcon=lpCI->iDefIcon;

hIcon=lpCI->hDefIcon;

}

if (lpCI->dwFlags & CIF_SELECTCURRENT)

{

//Go get the current icon source back.

OleUIMetafilePictExtractIconSource(lpCI->lpOCI->hMetaPict

, psz, &lpCI->iIcon);

}

if (lpCI->dwFlags & CIF_SELECTFROMFILE)

{

GetDlgItemText(hDlg, ID_FROMFILEEDIT, psz, OLEUI_CCHPATHMAX);

lpCI->iIcon=(UINT)SendDlgItemMessage(hDlg

, ID_ICONLIST, LB_GETCURSEL, 0, 0L);

}

//Get the label and go create the metafile

GetDlgItemText(hDlg, ID_LABELEDIT, szTemp, sizeof(szTemp));

//If psz is NULL (default) we get no source comments.

hMetaPict=OleUIMetafilePictFromIconAndLabel(hIcon

, szTemp, psz, lpCI->iIcon);

//Clean up the current icon that we extracted.

hIcon=(HICON)SendDlgItemMessage(hDlg, ID_CURRENTICON

, STM_GETICON, 0, 0L);

DestroyIcon(hIcon);

//Clean up the default icon

DestroyIcon(lpCI->hDefIcon);

// Remove the prop set on our parent

RemoveProp(lpCI->lpOCI->hWndOwner, PROP_HWND_CHGICONDLG);

if (NULL==hMetaPict)

SendMessage(hDlg, uMsgEndDialog, OLEUI_FALSE, 0L);

OleUIMetafilePictIconFree(lpCI->lpOCI->hMetaPict);

lpCI->lpOCI->hMetaPict=hMetaPict;

lpCI->lpOCI->dwFlags = lpCI->dwFlags;

SendMessage(hDlg, uMsgEndDialog, OLEUI_OK, 0L);

break;

case IDCANCEL:

//Clean up the current icon that we extracted.

hIcon=(HICON)SendDlgItemMessage(hDlg, ID_CURRENTICON

, STM_GETICON, 0, 0L);

DestroyIcon(hIcon);

//Clean up the default icon

DestroyIcon(lpCI->hDefIcon);

// Remove the prop set on our parent

RemoveProp(lpCI->lpOCI->hWndOwner, PROP_HWND_CHGICONDLG);

//We leave hMetaPict intact on Cancel; caller's responsibility

SendMessage(hDlg, uMsgEndDialog, OLEUI_CANCEL, 0L);

break;

case ID_OLEUIHELP:

PostMessage(lpCI->lpOCI->hWndOwner, uMsgHelp,

(WPARAM)hDlg, MAKELPARAM(IDD_CHANGEICON, 0));

break;

}

break;

default:

{

if (lpCI && iMsg == lpCI->nBrowseHelpID) {

PostMessage(lpCI->lpOCI->hWndOwner, uMsgHelp,

(WPARAM)hDlg, MAKELPARAM(IDD_CHANGEICONBROWSE, 0));

}

}

break;

}

return FALSE;

}

/*

 * FChangeIconInit

 *

 * Purpose:

 *  WM_INITIDIALOG handler for the Change Icon dialog box.

 *

 * Parameters:

 *  hDlg            HWND of the dialog

 *  wParam          WPARAM of the message

 *  lParam          LPARAM of the message

 *

 * Return Value:

 *  BOOL            Value to return for WM_INITDIALOG.

 */

BOOL FChangeIconInit(HWND hDlg, WPARAM wParam, LPARAM lParam)

{

LPCHANGEICON            lpCI;

LPOLEUICHANGEICON       lpOCI;

HFONT                   hFont;

HWND                    hList;

UINT                    cyList;

RECT                    rc, rcG;

UINT                    uID;

//1.  Copy the structure at lParam into our instance memory.

lpCI=(LPCHANGEICON)LpvStandardInit(hDlg, sizeof(CHANGEICON), TRUE, &hFont);

//PvStandardInit send a termination to us already.

if (NULL==lpCI)

return FALSE;

//Save the original pointer and copy necessary information.

lpOCI=(LPOLEUICHANGEICON)lParam;

lpCI->lpOCI  =lpOCI;

lpCI->dwFlags=lpOCI->dwFlags;

//Go extract the icon source from the metafile.

OleUIMetafilePictExtractIconSource(lpOCI->hMetaPict, lpCI->szFile, &lpCI->iIcon);

//Go extract the icon and the label from the metafile

OleUIMetafilePictExtractLabel(lpOCI->hMetaPict, lpCI->szLabel, OLEUI_CCHLABELMAX, NULL);

lpCI->hCurIcon=OleUIMetafilePictExtractIcon(lpOCI->hMetaPict);

//2.  If we got a font, send it to the necessary controls.

if (NULL!=hFont)

{

SendDlgItemMessage(hDlg, ID_RESULTLABEL, WM_SETFONT

   , (WPARAM)hFont, 0L);

}

//3.  Show or hide the help button

if (!(lpCI->dwFlags & CIF_SHOWHELP))

StandardShowDlgItem(hDlg, ID_OLEUIHELP, SW_HIDE);

/*

 * 4.  Set text limits and initial control values.  If we're given

 *     an intial label we set it in the edit and static controls.

 *     If we don't, then we copy the default contents of the static

 *     control into the edit control, meaning that only the default

 *     static control string need be localized.

 */

SendDlgItemMessage(hDlg, ID_LABELEDIT, EM_LIMITTEXT, OLEUI_CCHLABELMAX, 0L);

SendDlgItemMessage(hDlg, ID_FROMFILEEDIT, EM_LIMITTEXT, OLEUI_CCHPATHMAX,  0L);

SetDlgItemText(hDlg, ID_FROMFILEEDIT, lpCI->szFile);

//Copy the label text into the edit and static controls.

SetDlgItemText(hDlg, ID_LABELEDIT,   lpCI->szLabel);

SetDlgItemText(hDlg, ID_RESULTLABEL, lpCI->szLabel);

lpCI->hDefIcon = NULL;

if (lpCI->dwFlags & CIF_USEICONEXE)

{

   lpCI->hDefIcon = ExtractIcon(ghInst, lpCI->lpOCI->szIconExe, 0);

   if (NULL != lpCI->hDefIcon)

   {

 lstrcpy(lpCI->szDefIconFile, lpCI->lpOCI->szIconExe);

 lpCI->iDefIcon = 0;

   }

}

if (NULL == lpCI->hDefIcon)

{

   HGLOBAL hMetaPict;

   hMetaPict = GetIconOfClass(ghInst,

  &lpCI->lpOCI->clsid,

  NULL,

  TRUE);

   lpCI->hDefIcon = OleUIMetafilePictExtractIcon(hMetaPict);

   OleUIMetafilePictExtractIconSource(hMetaPict,

  lpCI->szDefIconFile,

  &lpCI->iDefIcon);

   OleUIMetafilePictIconFree(hMetaPict);

}

//Initialize all the icon displays.

SendDlgItemMessage(hDlg, ID_CURRENTICON, STM_SETICON

, (WPARAM)lpCI->hCurIcon, 0L);

SendDlgItemMessage(hDlg, ID_DEFAULTICON, STM_SETICON

, (WPARAM)lpCI->hDefIcon, 0L);

SendDlgItemMessage(hDlg, ID_RESULTICON,  STM_SETICON

, (WPARAM)lpCI->hCurIcon, 0L);

/*

 * 5.  Since we cannot predict the size of icons on any display,

 *     we have to resize the icon listbox to the size of an icon

 *     (plus padding), a scrollbar, and two borders (top & bottom).

 */

cyList=GetSystemMetrics(SM_CYICON)+GetSystemMetrics(SM_CYHSCROLL)

   +GetSystemMetrics(SM_CYBORDER)*2+CYICONPAD;

hList=GetDlgItem(hDlg, ID_ICONLIST);

GetClientRect(hList, &rc);

SetWindowPos(hList, NULL, 0, 0, rc.right, cyList

 , SWP_NOMOVE | SWP_NOZORDER);

//Set the columns in this multi-column listbox to hold one icon

SendMessage(hList, LB_SETCOLUMNWIDTH

, GetSystemMetrics(SM_CXICON)+CXICONPAD,0L);

/*

 * 5a.  If the listbox expanded below the group box, then size

 *      the groupbox down, move the label static and exit controls

 *      down, and expand the entire dialog appropriately.

 */

GetWindowRect(hList, &rc);

GetWindowRect(GetDlgItem(hDlg, ID_GROUP), &rcG);

if (rc.bottom > rcG.bottom)

{

//Calculate amount to move things down.

cyList=(rcG.bottom-rcG.top)-(rc.bottom-rc.top-cyList);

//Expand the group box.

rcG.right -=rcG.left;

rcG.bottom-=rcG.top;

SetWindowPos(GetDlgItem(hDlg, ID_GROUP), NULL, 0, 0

 , rcG.right, rcG.bottom+cyList

 , SWP_NOMOVE | SWP_NOZORDER);

//Expand the dialog box.

GetClientRect(hDlg, &rc);

SetWindowPos(hDlg, NULL, 0, 0, rc.right, rc.bottom+cyList

 , SWP_NOMOVE | SWP_NOZORDER);

//Move the label and edit controls down.

GetClientRect(GetDlgItem(hDlg, ID_LABEL), &rc);

SetWindowPos(GetDlgItem(hDlg, ID_LABEL), NULL, 0, cyList

 , rc.right, rc.bottom, SWP_NOSIZE | SWP_NOZORDER);

GetClientRect(GetDlgItem(hDlg, ID_LABELEDIT), &rc);

SetWindowPos(GetDlgItem(hDlg, ID_LABELEDIT), NULL, 0, cyList

 , rc.right, rc.bottom, SWP_NOSIZE | SWP_NOZORDER);

}

/*

 * 6.  Select Current, Default, or From File radiobuttons appropriately.

 *     The CheckRadioButton call sends WM_COMMANDs which handle

 *     other actions.  Note that if we check From File, which

 *     takes an icon from the list, we better fill the list.

 *     This will also fill the list even if default is selected.

 */

if (0!=UFillIconList(hDlg, ID_ICONLIST, lpCI->szFile))

{

//If szFile worked, then select the source icon in the listbox.

SendDlgItemMessage(hDlg, ID_ICONLIST, LB_SETCURSEL, lpCI->iIcon, 0L);

}

if (lpCI->dwFlags & CIF_SELECTCURRENT)

CheckRadioButton(hDlg, ID_CURRENT, ID_FROMFILE, ID_CURRENT);

else

{

uID=(lpCI->dwFlags & CIF_SELECTFROMFILE) ? ID_FROMFILE : ID_DEFAULT;

CheckRadioButton(hDlg, ID_CURRENT, ID_FROMFILE, uID);

}

//7.  Give our parent window access to our hDlg (via a special SetProp).

//    The PasteSpecial dialog may need to force our dialog down if the

//    clipboard contents change underneath it. if so it will send

//    us a IDCANCEL command.

SetProp(lpCI->lpOCI->hWndOwner, PROP_HWND_CHGICONDLG, hDlg);

lpCI->nBrowseHelpID = RegisterWindowMessage(HELPMSGSTRING);

//8.  Call the hook with lCustData in lParam

UStandardHook(lpCI, hDlg, WM_INITDIALOG, wParam, lpOCI->lCustData);

return TRUE;

}

/*

 * UFillIconList

 *

 * Purpose:

 *  Given a listbox and a filename, attempts to open that file and

 *  read all the icons that exist therein, adding them to the listbox

 *  hList as owner-draw items.  If the file does not exist or has no

 *  icons, then you get no icons and an appropriate warning message.

 *

 * Parameters:

 *  hDlg            HWND of the dialog containing the listbox.

 *  idList          UINT identifier of the listbox to fill.

 *  pszFile         LPSTR of the file from which to extract icons.

 *

 * Return Value:

 *  UINT            Number of items added to the listbox.  0 on failure.

 */

UINT UFillIconList(HWND hDlg, UINT idList, LPSTR pszFile)

{

HWND        hList;

UINT        i;

UINT        cIcons=0;

HCURSOR     hCur;

HICON       hIcon;

OFSTRUCT    of;

if (NULL==hDlg || !IsWindow(hDlg) || NULL==pszFile)

return 0;

hList=GetDlgItem(hDlg, idList);

if (NULL==hList)

return 0;

//Clean out the listbox.

SendMessage(hList, LB_RESETCONTENT, 0, 0L);

//If we have an empty string, just exit leaving the listbox empty as well

if (0==lstrlen(pszFile))

return 0;

//Turn on the hourglass

hCur=HourGlassOn();

//Check if the file is valid.

if (HFILE_ERROR!=DoesFileExist(pszFile, &of))

{

   #ifdef EXTRACTICONWORKS

//Get the icon count for this file.

cIcons=(UINT)ExtractIcon(ghInst, pszFile, (UINT)-1);

   #else

/*

 * ExtractIcon in Windows 3.1 with -1 eats a selector, leaving an

 * extra global memory object around for this applciation.  Since

 * changing icons may happen very often with all OLE apps in

 * the system, we have to work around it.  So we'll say we

 * have lots of icons and just call ExtractIcon until it

 * fails.  We check if there's any around by trying to get

 * the first one.

 */

cIcons=0xFFFF;

hIcon=ExtractIcon(ghInst, pszFile, 0);

//Fake a failure with cIcons=0, or cleanup hIcon from this test.

if (32 > (UINT)hIcon)

cIcons=0;

else

DestroyIcon(hIcon);

   #endif

if (0!=cIcons)

{

SendMessage(hList, WM_SETREDRAW, FALSE, 0L);

for (i=0; i<cIcons; i++)

{

hIcon=ExtractIcon(ghInst, pszFile, i);

if (32 < (UINT)hIcon)

SendMessage(hList, LB_ADDSTRING, 0, (LONG)(UINT)hIcon);

   #ifndef EXTRACTICONWORKS

else

{

//ExtractIcon failed, so let's leave now.

break;

}

   #endif

}

//Force complete repaint

SendMessage(hList, WM_SETREDRAW, TRUE, 0L);

InvalidateRect(hList, NULL, TRUE);

//Select an icon

SendMessage(hList, LB_SETCURSEL, 0, 0L);

}

else

ErrorWithFile(hDlg, ghInst, (UINT)IDS_CINOICONSINFILE, pszFile, MB_OK);

}

else

OpenFileError(hDlg, of.nErrCode, pszFile);

HourGlassOff(hCur);

return cIcons;

}

/*

 * FDrawListIcon

 *

 * Purpose:

 *  Handles WM_DRAWITEM for the icon listbox.

 *

 * Parameters:

 *  lpDI            LPDRAWITEMSTRUCT from WM_DRAWITEM

 *

 * Return Value:

 *  BOOL            TRUE if we did anything, FALSE if there are no items

 *                  in the list.

 */

BOOL FDrawListIcon(LPDRAWITEMSTRUCT lpDI)

{

COLORREF        cr;

/*

 * If there are no items in the list, then itemID is negative according

 * to the Win3.1 SDK.  Unfortunately DRAWITEMSTRUCT has an unsigned int

 * for this field, so we need the typecast to do a signed comparison.

 */

if ((int)lpDI->itemID < 0)

return FALSE;

/*

 * For selection or draw entire case we just draw the entire item all

 * over again.  For focus cases, we only call DrawFocusRect.

 */

if (lpDI->itemAction & (ODA_SELECT | ODA_DRAWENTIRE))

{

//Clear background and draw the icon.

if (lpDI->itemState & ODS_SELECTED)

cr=SetBkColor(lpDI->hDC, GetSysColor(COLOR_HIGHLIGHT));

else

cr=SetBkColor(lpDI->hDC, GetSysColor(COLOR_WINDOW));

//Draw a cheap rectangle.

ExtTextOut(lpDI->hDC, 0, 0, ETO_OPAQUE, &lpDI->rcItem

   , NULL, 0, NULL);

DrawIcon(lpDI->hDC, lpDI->rcItem.left+(CXICONPAD/2)

 , lpDI->rcItem.top+(CYICONPAD/2)

 , (HICON)LOWORD(lpDI->itemData));

//Restore original background for DrawFocusRect

SetBkColor(lpDI->hDC, cr);

}

//Always change focus on the focus action.

if (lpDI->itemAction & ODA_FOCUS || lpDI->itemState & ODS_FOCUS)

DrawFocusRect(lpDI->hDC, &lpDI->rcItem);

return TRUE;

}

/*

 * UpdateResultIcon

 *

 * Purpose:

 *  Updates the result icon using the current icon in the default display

 *  or the icon listbox depending on fFromDefault.

 *

 * Parameters:

 *  lpCI            LPCHANGEICON containing dialog flags.

 *  hDlg            HWND of the dialog

 *  uID             UINT identifying the radiobutton selected.

 *

 * Return Value:

 *  None

 */

void UpdateResultIcon(LPCHANGEICON lpCI, HWND hDlg, UINT uID)

{

UINT        iSel;

LONG        lTemp=LB_ERR;

lpCI->dwFlags &= ~(CIF_SELECTCURRENT | CIF_SELECTDEFAULT | CIF_SELECTFROMFILE);

switch (uID)

{

case ID_CURRENT:

lTemp=SendDlgItemMessage(hDlg, ID_CURRENTICON, STM_GETICON, 0, 0L);

lpCI->dwFlags |= CIF_SELECTCURRENT;

break;

case ID_DEFAULT:

lTemp=SendDlgItemMessage(hDlg, ID_DEFAULTICON, STM_GETICON, 0, 0L);

lpCI->dwFlags |= CIF_SELECTDEFAULT;

break;

case ID_FROMFILE:

//Get the selected icon from the list and place it in the result

lpCI->dwFlags |= CIF_SELECTFROMFILE;

iSel=(UINT)SendDlgItemMessage(hDlg, ID_ICONLIST, LB_GETCURSEL, 0, 0L);

if ((UINT)LB_ERR==iSel)

lTemp=SendDlgItemMessage(hDlg, ID_DEFAULTICON, STM_GETICON, 0, 0L);

else

SendDlgItemMessage(hDlg, ID_ICONLIST, LB_GETTEXT, iSel

   , (LPARAM)(LPLONG)&lTemp);

break;

}

if ((LONG)LB_ERR!=lTemp)

SendDlgItemMessage(hDlg, ID_RESULTICON, STM_SETICON, LOWORD(lTemp), 0L);

return;

}


ICONBOX.H  (WRAPUI Sample)

/*

 * ICONBOX.H

 *

 * Structures and definitions for the IconBox control.

 *

 * Copyright (c)1992 Microsoft Corporation, All Right Reserved

 */

#ifndef _ICONBOX_H_

#define _ICONBOX_H_

//Function prototypes

BOOL            FIconBoxInitialize(HINSTANCE, HINSTANCE, LPSTR);

void            IconBoxUninitialize(void);

LONG CALLBACK EXPORT IconBoxWndProc(HWND, UINT, WPARAM, LPARAM);

//Window extra bytes contain the bitmap index we deal with currently.

#define CBICONBOXWNDEXTRA               (sizeof(HGLOBAL)+sizeof(BOOL))

#define IBWW_HIMAGE                     0

#define IBWW_FLABEL                     (sizeof(HGLOBAL))

#ifdef WIN32

#define GETHIMAGE(h)                    (HGLOBAL)GetWindowLong(h, IBWW_HIMAGE)

#define SETHIMAGE(h, hmf)               (HGLOBAL)SetWindowLong(h, IBWW_HIMAGE, hmf)

#define GETFLABEL(h)                    (BOOL)GetWindowLong(h, IBWW_FLABEL)

#define SETFLABEL(h, b)                 (BOOL)SetWindowLong(h, IBWW_FLABEL, b)

#else

#define GETHIMAGE(h)                    (HGLOBAL)GetWindowWord(h, IBWW_HIMAGE)

#define SETHIMAGE(h, hmf)               (HGLOBAL)SetWindowWord(h, IBWW_HIMAGE, hmf)

#define GETFLABEL(h)                    (BOOL)GetWindowWord(h, IBWW_FLABEL)

#define SETFLABEL(h, b)                 (BOOL)SetWindowWord(h, IBWW_FLABEL, b)

#endif

//Control messages

#define IBXM_IMAGESET                   (WM_USER+0)

#define IBXM_IMAGEGET                   (WM_USER+1)

#define IBXM_IMAGEFREE                  (WM_USER+2)

#define IBXM_LABELENABLE                (WM_USER+3)

#endif //_ICONBOX_H_


ICONBOX.C  (WRAPUI Sample)

/*

 * ICONBOX.C

 *

 * Implemenatation of an IconBox control for OLE 2.0 UI dialogs that we'll

 * use wherever a dialog needs an icon/label display.  Through the control's

 * interface we can change the image or control label visibility.

 *

 * The IconBox discusses images in CF_METAFILEPICT format.  When drawing

 * such a metafile, the entire aspect is centered in the IconBox, so long

 * labels are chopped at either end.

 *

 * Copyright (c)1992 Microsoft Corporation, All Right Reserved

 */

#define STRICT  1

#include "ole2ui.h"

#include "iconbox.h"

//Flag indicating if we've registered the class

static BOOL     fRegistered=FALSE;

/*

 * FIconBoxInitialize

 *

 * Purpose:

 *  Registers the IconBox control class.

 *

 * Parameters:

 *  hInst           HINSTANCE instance of the DLL.

 *

 *  hPrevInst       HINSTANCE of the previous instance.  Used to

 *                  determine whether to register window classes or not.

 *

 *  lpszClassName   LPSTR containing the class name to register the

 *                  IconBox control class with.

 *

 * Return Value:

 *  BOOL            TRUE if all initialization succeeded, FALSE otherwise.

 */

BOOL FIconBoxInitialize(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpszClassName)

{

WNDCLASS        wc;

// Only register class if we're the first instance

if (hPrevInst)

fRegistered = TRUE;

else

{

// Static flag fRegistered guards against calling this function more

// than once

/* NOTE: the custom control classes for the ICONBOX class and the

**    RESULTIMAGE class are registered as task specific. this

**    is done both if the OLE2UI library is built as a static

**    library or as a DLL. these custom controls are

**    constructed internally as part of the OLE2UI code and do

**    NOT need to be registered as global classes.

*/

if (!fRegistered)

{

wc.lpfnWndProc   =IconBoxWndProc;

wc.cbClsExtra    =0;

wc.cbWndExtra    =CBICONBOXWNDEXTRA;

wc.hInstance     =hInst;

wc.hIcon         =NULL;

wc.hCursor       =LoadCursor(NULL, IDC_ARROW);

wc.hbrBackground =(HBRUSH)NULL;

wc.lpszMenuName  =NULL;

wc.lpszClassName =lpszClassName;

wc.style         = CS_VREDRAW | CS_HREDRAW;

fRegistered=RegisterClass(&wc);

}

}

return fRegistered;

}

/*

 * IconBoxUninitialize

 *

 * Purpose:

 *  Cleans up anything done in FIconBoxInitialize.  Currently there is

 *  nothing, but we do this for symmetry.

 *

 * Parameters:

 *  None

 *

 * Return Value:

 *  None

 */

void IconBoxUninitialize(void)

{

//Nothing to do.

return;

}

/*

 * IconBoxWndProc

 *

 * Purpose:

 *  Window Procedure for the IconBox custom control.  Only handles

 *  WM_CREATE, WM_PAINT, and private messages to manipulate the image.

 *

 * Parameters:

 *  Standard

 *

 * Return Value:

 *  Standard

 */

LONG CALLBACK EXPORT IconBoxWndProc(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam)

{

HGLOBAL         hMF=NULL;

PAINTSTRUCT     ps;

HDC             hDC;

RECT            rc;

//Handle standard Windows messages.

switch (iMsg)

{

case WM_CREATE:

            SETHIMAGE(hWnd, 0);

            SETFLABEL(hWnd, TRUE);

return 0L;

case WM_ERASEBKGND:

           {

           HWND     hWndP=GetParent(hWnd);

   HBRUSH   hBrush;

   RECT     rc;

           HDC      hDC=(HDC)wParam;

           SaveDC(hDC);

          #ifdef WIN32

   hBrush = (HBRUSH)SendMessage(hWndP, WM_CTLCOLORDLG, wParam,

  (LPARAM)hWndP);

          #else

   hBrush = (HBRUSH)SendMessage(hWndP, WM_CTLCOLOR, wParam,

              MAKELPARAM(hWndP, CTLCOLOR_DLG));

          #endif

           RestoreDC(hDC, -1);

   if (!hBrush)

 return FALSE;

   SetBrushOrgEx(hDC, 0, 0, NULL);

   GetClientRect(hWnd, &rc);

   FillRect(hDC, &rc, hBrush);

   return TRUE;

           }

case WM_PAINT:

            hMF=GETHIMAGE(hWnd);

//BeginPaint and EndPaint clear us even if hMF is NULL.

hDC=BeginPaint(hWnd, &ps);

if (NULL!=hMF)

{

BOOL            fLabel;

//Now we get to paint the metafile, centered in our rect.

GetClientRect(hWnd, &rc);

/*

 * If we're doing icon only, then place the metafile

 * at the center of our box minus half the icon width.

 * Top is top.

 */

fLabel=GETFLABEL(hWnd);

//Go draw where we decided to place it.

OleUIMetafilePictIconDraw(hDC, &rc, hMF, !fLabel);

}

EndPaint(hWnd, &ps);

break;

case IBXM_IMAGESET:

/*

 * wParam contains the new handle.

 * lParam is a flag to delete the old or not.

 */

            hMF=SETHIMAGE(hWnd, (LONG)wParam);

InvalidateRect(hWnd, NULL, TRUE);

UpdateWindow(hWnd);

//Delete the old handle if requested

if (0L!=lParam)

{

OleUIMetafilePictIconFree(hMF);

hMF=NULL;

}

return (LONG)(UINT)hMF;

case IBXM_IMAGEGET:

//Return the current index.

            hMF=GETHIMAGE(hWnd);

return (LONG)(UINT)hMF;

case IBXM_IMAGEFREE:

//Free up whatever we're holding.

            hMF=GETHIMAGE(hWnd);

OleUIMetafilePictIconFree(hMF);

return 1L;

case IBXM_LABELENABLE:

//wParam has the new flag, returns the previous flag.

return (LONG)SETFLABEL(hWnd, (BOOL)wParam);

default:

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

}

return 0L;

}


INSOBJ.H  (WRAPUI Sample)

/*

 * INSOBJ.H

 *

 * Internal definitions, structures, and function prototypes for the

 * OLE 2.0 UI Insert Object dialog.

 *

 * Copyright (c)1993 Microsoft Corporation, All Rights Reserved

 */

#ifndef _INSOBJ_H_

#define _INSOBJ_H_

//Internally used structure

typedef struct tagINSERTOBJECT

{

LPOLEUIINSERTOBJECT lpOIO;              //Original structure passed.

/*

 * What we store extra in this structure besides the original caller's

 * pointer are those fields that we need to modify during the life of

 * the dialog but that we don't want to change in the original structure

 * until the user presses OK.

 */

DWORD               dwFlags;

CLSID               clsid;

char                szFile[OLEUI_CCHPATHMAX];

BOOL                fFileSelected;      //Enables Display As Icon for links

BOOL                fAsIconNew;

BOOL                fAsIconFile;

BOOL                fFileDirty;

BOOL                fFileValid;

UINT                nErrCode;

HGLOBAL             hMetaPictFile;

UINT                nBrowseHelpID;      // Help ID callback for Browse dlg

} INSERTOBJECT, *PINSERTOBJECT, FAR *LPINSERTOBJECT;

//Internal function prototypes

//INSOBJ.C

BOOL CALLBACK EXPORT InsertObjectDialogProc(HWND, UINT, WPARAM, LPARAM);

BOOL            FInsertObjectInit(HWND, WPARAM, LPARAM);

UINT            UFillClassList(HWND, UINT, LPCLSID, BOOL);

BOOL            FToggleObjectSource(HWND, LPINSERTOBJECT, DWORD);

void            UpdateClassIcon(HWND, LPINSERTOBJECT, HWND);

void            UpdateClassType(HWND, LPINSERTOBJECT, BOOL);

void            SetInsertObjectResults(HWND, LPINSERTOBJECT);

BOOL            FValidateInsertFile(HWND, BOOL, UINT FAR*);

void            InsertObjectCleanup(HWND);

#endif //_INSOBJ_H_


INSOBJ.C  (WRAPUI Sample)

/*

 * INSOBJ.C

 *

 * Implements the OleUIInsertObject function which invokes the complete

 * Insert Object dialog.  Makes use of the OleChangeIcon function in

 * ICON.C.

 *

 * Copyright (c)1993 Microsoft Corporation, All Rights Reserved

 */

#define STRICT  1

#include "ole2ui.h"

#include <commdlg.h>

#include <memory.h>

#include <direct.h>

#include <malloc.h>

#include <dos.h>

#include "common.h"

#include "utility.h"

#include "icon.h"

#include "insobj.h"

#include "resimage.h"

#include "iconbox.h"

#include "geticon.h"

#ifdef WIN32

/* 1/23/94 - define LINK_COMMDLG avoid LoadLibrary("commdlg.dll") */

#define LINK_COMMDLG

#endif

#define IS_FILENAME_DELIM(c)    ( (c) == '\\' || (c) == '/' || (c) == ':' )

/*

 * OleUIInsertObject

 *

 * Purpose:

 *  Invokes the standard OLE Insert Object dialog box allowing the

 *  user to select an object source and classname as well as the option

 *  to display the object as itself or as an icon.

 *

 * Parameters:

 *  lpIO            LPOLEUIINSERTOBJECT pointing to the in-out structure

 *                  for this dialog.

 *

 * Return Value:

 *  UINT            OLEUI_SUCCESS or OLEUI_OK if all is well, otherwise

 *                  an error value.

 */

STDAPI_(UINT) OleUIInsertObject(LPOLEUIINSERTOBJECT lpIO)

{

UINT        uRet;

HGLOBAL     hMemDlg=NULL;

HRESULT     hrErr;

uRet=UStandardValidation((LPOLEUISTANDARD)lpIO, sizeof(OLEUIINSERTOBJECT)

 , &hMemDlg);

if (OLEUI_SUCCESS!=uRet)

return uRet;

//Now we can do Insert Object specific validation.

// NULL is NOT valid for lpszFile

if (   (NULL == lpIO->lpszFile)

|| (IsBadReadPtr(lpIO->lpszFile, lpIO->cchFile))

|| (IsBadWritePtr(lpIO->lpszFile, lpIO->cchFile)) )

 uRet=OLEUI_IOERR_LPSZFILEINVALID;

if (NULL != lpIO->lpszFile

&& (lpIO->cchFile <= 0 || lpIO->cchFile > OLEUI_CCHPATHMAX))

 uRet=OLEUI_IOERR_CCHFILEINVALID;

if (0!=lpIO->cClsidExclude)

{

if (NULL!=lpIO->lpClsidExclude && IsBadReadPtr(lpIO->lpClsidExclude

, lpIO->cClsidExclude*sizeof(CLSID)))

uRet=OLEUI_IOERR_LPCLSIDEXCLUDEINVALID;

}

//If we have flags to create any object, validate necessary data.

if (lpIO->dwFlags & (IOF_CREATENEWOBJECT | IOF_CREATEFILEOBJECT | IOF_CREATELINKOBJECT))

{

if (NULL!=lpIO->lpFormatEtc

&& IsBadReadPtr(lpIO->lpFormatEtc, sizeof(FORMATETC)))

uRet=OLEUI_IOERR_LPFORMATETCINVALID;

if (NULL!=lpIO->ppvObj && IsBadWritePtr(lpIO->ppvObj, sizeof(LPVOID)))

uRet=OLEUI_IOERR_PPVOBJINVALID;

if (NULL!=lpIO->lpIOleClientSite

&& IsBadReadPtr(lpIO->lpIOleClientSite->lpVtbl, sizeof(IOleClientSiteVtbl)))

uRet=OLEUI_IOERR_LPIOLECLIENTSITEINVALID;

if (NULL!=lpIO->lpIStorage

&& IsBadReadPtr(lpIO->lpIStorage->lpVtbl, sizeof(IStorageVtbl)))

uRet=OLEUI_IOERR_LPISTORAGEINVALID;

}

if (OLEUI_ERR_STANDARDMIN <= uRet)

{

if (NULL!=hMemDlg)

FreeResource(hMemDlg);

return uRet;

}

//Now that we've validated everything, we can invoke the dialog.

uRet=UStandardInvocation(InsertObjectDialogProc, (LPOLEUISTANDARD)lpIO

 , hMemDlg, MAKEINTRESOURCE(IDD_INSERTOBJECT));

//Stop here if we cancelled or had an error.

if (OLEUI_SUCCESS !=uRet && OLEUI_OK!=uRet)

return uRet;

/*

 * If any of the flags specify that we're to create objects on return

 * from this dialog, then do so.  If we encounter an error in this

 * processing, we return OLEUI_IOERR_SCODEHASERROR.  Since the

 * three select flags are mutually exclusive, we don't have to

 * if...else here, just if each case (keeps things cleaner that way).

 */

lpIO->sc=S_OK;

//Check if Create New was selected and we have IOF_CREATENEWOBJECT

if ((lpIO->dwFlags & IOF_SELECTCREATENEW) && (lpIO->dwFlags & IOF_CREATENEWOBJECT))

{

hrErr=OleCreate(&lpIO->clsid, &lpIO->iid, lpIO->oleRender

, lpIO->lpFormatEtc, lpIO->lpIOleClientSite, lpIO->lpIStorage

, lpIO->ppvObj);

lpIO->sc = GetScode(hrErr);

}

//Try Create From File

if ((lpIO->dwFlags & IOF_SELECTCREATEFROMFILE))

{

if (!(lpIO->dwFlags & IOF_CHECKLINK) && (lpIO->dwFlags & IOF_CREATEFILEOBJECT))

{

hrErr=OleCreateFromFile(&CLSID_NULL, lpIO->lpszFile, &lpIO->iid

, lpIO->oleRender, lpIO->lpFormatEtc, lpIO->lpIOleClientSite

, lpIO->lpIStorage, lpIO->ppvObj);

lpIO->sc = GetScode(hrErr);

}

if ((lpIO->dwFlags & IOF_CHECKLINK) && (lpIO->dwFlags & IOF_CREATELINKOBJECT))

{

hrErr=OleCreateLinkToFile(lpIO->lpszFile, &lpIO->iid

, lpIO->oleRender, lpIO->lpFormatEtc, lpIO->lpIOleClientSite

, lpIO->lpIStorage, lpIO->ppvObj);

lpIO->sc = GetScode(hrErr);

}

}

//If we tried but failed a create option, then return the appropriate error

if (S_OK!=lpIO->sc)

uRet=OLEUI_IOERR_SCODEHASERROR;

return uRet;

}

/* wGetFileTitle

** -------------

**    Dynamically link to COMMDLG.DLL to call the GetFileTitle API

*/

static int wGetFileTitle(LPCSTR lpszFile, LPSTR lpszTitle, UINT cbBuf)

{

#if !defined( LINK_COMMDLG )

HINSTANCE hinstCommDlg = NULL;

typedef int (WINAPI* LPFNGETFILETITLE) (LPCSTR, LPSTR, UINT);

LPFNGETFILETITLE lpfnGetFileTitle;

int iResult = -1;

// Load the COMMDLG.DLL library module

hinstCommDlg = LoadLibrary("COMMDLG.DLL");

if ((DWORD)hinstCommDlg > HINSTANCE_ERROR) {  /* loaded successfully */

// Retrieve the address of the GetFileTitle function

lpfnGetFileTitle = (LPFNGETFILETITLE)

GetProcAddress(hinstCommDlg, "GetFileTitle");

if (lpfnGetFileTitle != NULL) {

// Call the GetFileTitle function

iResult = (*lpfnGetFileTitle) ((LPCSTR)lpszFile,

(LPSTR)lpszTitle, cbBuf);

}

FreeLibrary(hinstCommDlg);

return iResult;

}

#else

return GetFileTitle((LPCSTR)lpszFile, (LPSTR)lpszTitle, (WORD) cbBuf);

#endif

}

/*

 * InsertObjectDialogProc

 *

 * Purpose:

 *  Implements the OLE Insert Object dialog as invoked through the

 *  OleUIInsertObject function.

 */

BOOL CALLBACK EXPORT InsertObjectDialogProc(HWND hDlg, UINT iMsg

, WPARAM wParam, LPARAM lParam)

{

LPOLEUIINSERTOBJECT     lpOIO;

LPINSERTOBJECT          lpIO;

OLEUICHANGEICON         ci;

UINT                    i;

BOOL                    fCheck=FALSE;

UINT                    uRet=0;

//Declare Win16/Win32 compatible WM_COMMAND parameters.

COMMANDPARAMS(wID, wCode, hWndMsg);

//This will fail under WM_INITDIALOG, where we allocate it.

lpIO=(LPINSERTOBJECT)LpvStandardEntry(hDlg, iMsg, wParam, lParam, &uRet);

//If the hook processed the message, we're done.

if (0!=uRet)

return (BOOL)uRet;

//Process help message from Change Icon

if (iMsg==uMsgHelp)

{

PostMessage(lpIO->lpOIO->hWndOwner, uMsgHelp, wParam, lParam);

return FALSE;

}

//Process the temination message

if (iMsg==uMsgEndDialog)

{

InsertObjectCleanup(hDlg);

StandardCleanup(lpIO, hDlg);

EndDialog(hDlg, wParam);

return TRUE;

}

switch (iMsg)

{

case WM_INITDIALOG:

return FInsertObjectInit(hDlg, wParam, lParam);

case WM_COMMAND:

switch (wID)

{

case ID_IO_CREATENEW:

FToggleObjectSource(hDlg, lpIO, IOF_SELECTCREATENEW);

break;

case ID_IO_CREATEFROMFILE:

FToggleObjectSource(hDlg, lpIO, IOF_SELECTCREATEFROMFILE);

break;

case ID_IO_LINKFILE:

fCheck=IsDlgButtonChecked(hDlg, wID);

if (fCheck)

lpIO->dwFlags |=IOF_CHECKLINK;

else

lpIO->dwFlags &=~IOF_CHECKLINK;

//Results change here, so be sure to update it.

SetInsertObjectResults(hDlg, lpIO);

UpdateClassIcon(hDlg, lpIO, NULL);

break;

case ID_IO_OBJECTTYPELIST:

switch (wCode)

{

case LBN_SELCHANGE:

UpdateClassIcon(hDlg, lpIO, hWndMsg);

SetInsertObjectResults(hDlg, lpIO);

break;

case LBN_DBLCLK:

//Same as pressing OK.

SendCommand(hDlg, IDOK, BN_CLICKED, hWndMsg);

break;

}

break;

case ID_IO_FILEDISPLAY:

//If there are characters, enable OK and Display As Icon

if (EN_CHANGE==wCode)

{

lpIO->fFileDirty = TRUE;

lpIO->fFileValid = FALSE;

lpIO->fFileSelected=

(0L!=SendMessage(hWndMsg, EM_LINELENGTH, 0, 0L));

EnableWindow(GetDlgItem(hDlg, ID_IO_LINKFILE), lpIO->fFileSelected);

EnableWindow(GetDlgItem(hDlg, ID_IO_DISPLAYASICON), lpIO->fFileSelected);

EnableWindow(GetDlgItem(hDlg, ID_IO_CHANGEICON), lpIO->fFileSelected);

EnableWindow(GetDlgItem(hDlg, IDOK), lpIO->fFileSelected);

}

if (EN_KILLFOCUS==wCode && NULL!=lpIO)

{

if (FValidateInsertFile(hDlg,FALSE,&lpIO->nErrCode)) {

lpIO->fFileDirty = FALSE;

lpIO->fFileValid = TRUE;

UpdateClassIcon(hDlg, lpIO, NULL);

UpdateClassType(hDlg, lpIO, TRUE);

} else {

lpIO->fFileDirty = FALSE;

lpIO->fFileValid = FALSE;

UpdateClassType(hDlg, lpIO, FALSE);

}

}

break;

case ID_IO_DISPLAYASICON:

fCheck=IsDlgButtonChecked(hDlg, wID);

EnableWindow(GetDlgItem(hDlg, ID_IO_CHANGEICON), fCheck);

if (fCheck)

lpIO->dwFlags |=IOF_CHECKDISPLAYASICON;

else

lpIO->dwFlags &=~IOF_CHECKDISPLAYASICON;

//Update the internal flag based on this checking

if (lpIO->dwFlags & IOF_SELECTCREATENEW)

lpIO->fAsIconNew=fCheck;

else

lpIO->fAsIconFile=fCheck;

//Re-read the class icon on Display checked

if (fCheck)

{

if (lpIO->dwFlags & IOF_SELECTCREATEFROMFILE)

{

  if (FValidateInsertFile(hDlg, TRUE,&lpIO->nErrCode))

  {

lpIO->fFileDirty = FALSE;

lpIO->fFileValid = TRUE;

UpdateClassIcon(hDlg, lpIO,

GetDlgItem(hDlg, ID_IO_OBJECTTYPELIST));

UpdateClassType(hDlg, lpIO, TRUE);

  }

  else

  {

HWND hWndEC;

lpIO->fAsIconFile= FALSE;

lpIO->fFileDirty = FALSE;

lpIO->fFileValid = FALSE;

SendDlgItemMessage(hDlg, ID_IO_ICONDISPLAY, IBXM_IMAGESET, 0, 0L);

UpdateClassType(hDlg, lpIO, FALSE);

lpIO->dwFlags &=~IOF_CHECKDISPLAYASICON;

CheckDlgButton(hDlg, ID_IO_DISPLAYASICON, 0);

hWndEC = GetDlgItem(hDlg, ID_IO_FILEDISPLAY);

SetFocus(hWndEC);

                            SendSetSel (hWndEC, 0, -1);

return TRUE;

  }

}

else

  UpdateClassIcon(hDlg, lpIO,

  GetDlgItem(hDlg, ID_IO_OBJECTTYPELIST));

}

//Results change here, so be sure to update it.

SetInsertObjectResults(hDlg, lpIO);

/*

 * Show or hide controls as appropriate.  Do the icon

 * display last because it will take some time to repaint.

 * If we do it first then the dialog looks too sluggish.

 */

i=(fCheck) ? SW_SHOWNORMAL : SW_HIDE;

StandardShowDlgItem(hDlg, ID_IO_CHANGEICON, i);

StandardShowDlgItem(hDlg, ID_IO_ICONDISPLAY, i);

break;

case ID_IO_CHANGEICON:

{

LPMALLOC  pIMalloc;

HWND      hList;

LPSTR     pszString, pszCLSID;

int       iCurSel;

// if we're in SELECTCREATEFROMFILE mode, then we need to Validate

// the contents of the edit control first.

if (lpIO->dwFlags & IOF_SELECTCREATEFROMFILE)

{

   if (   lpIO->fFileDirty

   && !FValidateInsertFile(hDlg, TRUE, &lpIO->nErrCode) )

   {

  HWND hWndEC;

  lpIO->fFileDirty = TRUE;

  hWndEC = GetDlgItem(hDlg, ID_IO_FILEDISPLAY);

  SetFocus(hWndEC);

                          SendSetSel (hWndEC, 0, -1);

  return TRUE;

   }

   else

  lpIO->fFileDirty = FALSE;

}

//Initialize the structure for the hook.

_fmemset((LPOLEUICHANGEICON)&ci, 0, sizeof(ci));

ci.hMetaPict=(HGLOBAL)SendDlgItemMessage(hDlg

, ID_IO_ICONDISPLAY, IBXM_IMAGEGET, 0, 0L);

ci.cbStruct =sizeof(ci);

ci.hWndOwner=hDlg;

ci.dwFlags  =CIF_SELECTCURRENT;

if (lpIO->dwFlags & IOF_SHOWHELP)

ci.dwFlags |= CIF_SHOWHELP;

if (lpIO->dwFlags & IOF_SELECTCREATENEW)

{

   // Initialize clsid...

   if (NOERROR != CoGetMalloc(MEMCTX_TASK, &pIMalloc))

 return FALSE;

   pszString = (LPSTR)pIMalloc->lpVtbl->Alloc(pIMalloc, OLEUI_CCHKEYMAX + OLEUI_CCHCLSIDSTRING);

   hList = GetDlgItem(hDlg, ID_IO_OBJECTTYPELIST);

   iCurSel = (int)SendMessage(hList, LB_GETCURSEL, 0, 0L);

   SendMessage(hList, LB_GETTEXT, iCurSel, (LONG)pszString);

   pszCLSID = PointerToNthField(pszString, 2, '\t');

   CLSIDFromString((LPSTR)pszCLSID, (LPCLSID)&(ci.clsid));

   pIMalloc->lpVtbl->Free(pIMalloc, (LPVOID)pszString);

   pIMalloc->lpVtbl->Release(pIMalloc);

}

else  // IOF_SELECTCREATEFROMFILE

{

   char  szFileName[OLEUI_CCHPATHMAX];

   GetDlgItemText(hDlg, ID_IO_FILEDISPLAY, (LPSTR)szFileName, OLEUI_CCHPATHMAX);

   if (NOERROR != GetClassFile((LPSTR)szFileName, (LPCLSID)&(ci.clsid)))

   {

  LPSTR lpszExtension;

  int   istrlen;

  istrlen = lstrlen(szFileName);

  lpszExtension = (LPSTR)szFileName + istrlen -1;

  while ( (lpszExtension > szFileName) &&

  (*lpszExtension != '.') )

lpszExtension--;

  GetAssociatedExecutable(lpszExtension, (LPSTR)ci.szIconExe);

  ci.cchIconExe = lstrlen(ci.szIconExe);

  ci.dwFlags |= CIF_USEICONEXE;

   }

}

//Let the hook in to customize Change Icon if desired.

uRet=UStandardHook(lpIO, hDlg, uMsgChangeIcon

, 0, (LONG)(LPSTR)&ci);

if (0==uRet)

uRet=(UINT)(OLEUI_OK==OleUIChangeIcon(&ci));

//Update the display and itemdata if necessary.

if (0!=uRet)

{

/*

 * OleUIChangeIcon will have already freed our

 * current hMetaPict that we passed in when OK is

 * pressed in that dialog.  So we use 0L as lParam

 * here so the IconBox doesn't try to free the

 * metafilepict again.

 */

SendDlgItemMessage(hDlg, ID_IO_ICONDISPLAY, IBXM_IMAGESET

, (WPARAM)ci.hMetaPict, 0L);

if (lpIO->dwFlags & IOF_SELECTCREATENEW)

  SendMessage(hList, LB_SETITEMDATA, iCurSel, MAKELPARAM(ci.hMetaPict, 0));

}

}

break;

case ID_IO_FILE:

{

/*

 * To allow the hook to customize the browse dialog, we

 * send OLEUI_MSG_BROWSE.  If the hook returns FALSE

 * we use the default, otherwise we trust that it retrieved

 * a filename for us.  This mechanism prevents hooks from

 * trapping ID_IO_BROWSE to customize the dialog and from

 * trying to figure out what we do after we have the name.

 */

char    szTemp[OLEUI_CCHPATHMAX];

char    szInitialDir[OLEUI_CCHPATHMAX];

DWORD   dwOfnFlags;

int     nChars;

BOOL    fUseInitialDir = FALSE;

nChars = GetDlgItemText(hDlg, ID_IO_FILEDISPLAY, (LPSTR)szTemp, OLEUI_CCHPATHMAX);

if (FValidateInsertFile(hDlg, FALSE, &lpIO->nErrCode))

{

int istrlen;

wGetFileTitle((LPSTR)szTemp, lpIO->szFile, OLEUI_CCHPATHMAX);

istrlen = lstrlen(lpIO->szFile);

LSTRCPYN((LPSTR)szInitialDir, szTemp, nChars - istrlen);

fUseInitialDir = TRUE;

}

else  // file name isn't valid...lop off end of szTemp to get a

  // valid directory

{

#if defined( WIN32 )

char szBuffer[OLEUI_CCHPATHMAX];

DWORD Attribs;

LSTRCPYN(szBuffer, szTemp, sizeof(szBuffer)-1);

szBuffer[sizeof(szBuffer)-1] = '\0';

if ('\\' == szBuffer[nChars-1])

   szBuffer[nChars-1] = '\0';

Attribs = GetFileAttributes(szBuffer);

if (Attribs != 0xffffffff &&

   (Attribs & FILE_ATTRIBUTE_DIRECTORY) )

{

   lstrcpy(szInitialDir, (LPSTR)szBuffer);

   fUseInitialDir = TRUE;

}

#else

static char szBuffer[OLEUI_CCHPATHMAX];

static int  attrib ;

LSTRCPYN(szBuffer, szTemp, sizeof(szBuffer)-1);

szBuffer[sizeof(szBuffer)-1] = '\0';

AnsiToOem(szBuffer, szBuffer);

#if defined( OBSOLETE )     // fix bug# 3575

if ('\\' == szBuffer[nChars-1])

   szBuffer[nChars-1] = '\0';

if(0 == _dos_getfileattr(szBuffer, &attrib))

#endif  // OBSOLETE

{

   lstrcpy(szInitialDir, (LPSTR)szBuffer);

   fUseInitialDir = TRUE;

}

#endif

*lpIO->szFile = '\0';

}

uRet=UStandardHook(lpIO, hDlg, uMsgBrowse

, OLEUI_CCHPATHMAX, (LPARAM)(LPSTR)lpIO->szFile);

dwOfnFlags = OFN_FILEMUSTEXIST;

if (lpIO->lpOIO->dwFlags & IOF_SHOWHELP)

   dwOfnFlags |= OFN_SHOWHELP;

if (0==uRet)

uRet=(UINT)Browse(hDlg,

  lpIO->szFile,

  fUseInitialDir ? (LPSTR)szInitialDir : NULL,

  OLEUI_CCHPATHMAX,

  (UINT)IDS_FILTERS,

  (UINT)IDS_BROWSE,

  dwOfnFlags);

//Only update if the file changed.

if (0!=uRet && 0!=lstrcmpi(szTemp, lpIO->szFile))

{

SetDlgItemText(hDlg, ID_IO_FILEDISPLAY, lpIO->szFile);

lpIO->fFileSelected=TRUE;

if (FValidateInsertFile(hDlg, TRUE, &lpIO->nErrCode))

{

  lpIO->fFileDirty = FALSE;

  lpIO->fFileValid = TRUE;

  UpdateClassIcon(hDlg, lpIO, NULL);

  UpdateClassType(hDlg, lpIO, TRUE);

  // auto set OK to be default button if valid file

  SendMessage(hDlg, DM_SETDEFID,

  (WPARAM)GetDlgItem(hDlg, IDOK), 0L);

  SetFocus(GetDlgItem(hDlg, IDOK));

}

else  // filename is invalid - set focus back to ec

{

  HWND hWnd;

  lpIO->fFileDirty = FALSE;

  lpIO->fFileValid = FALSE;

  hWnd = GetDlgItem(hDlg, ID_IO_FILEDISPLAY);

  SetFocus(hWnd);

                          SendSetSel (hWnd, 0, -1);

}

//Once we have a file, Display As Icon is always enabled

EnableWindow(GetDlgItem(hDlg, ID_IO_DISPLAYASICON), TRUE);

//As well as OK

EnableWindow(GetDlgItem(hDlg, IDOK), TRUE);

}

}

break;

case IDOK:

{

HWND    hListBox;

WORD    iCurSel;

char    szBuffer[OLEUI_CCHKEYMAX + OLEUI_CCHCLSIDSTRING];

LPSTR   lpszCLSID;

if ((HWND)(LOWORD(lParam)) != GetFocus())

  SetFocus((HWND)(LOWORD(lParam)));

// If the file name is clean (already validated), or

// if Create New is selected, then we can skip this part.

if (  (lpIO->dwFlags & IOF_SELECTCREATEFROMFILE)

   && (TRUE == lpIO->fFileDirty) )

{

if (FValidateInsertFile(hDlg, TRUE, &lpIO->nErrCode))

{

  lpIO->fFileDirty = FALSE;

  lpIO->fFileValid = TRUE;

  UpdateClassIcon(hDlg, lpIO, NULL);

  UpdateClassType(hDlg, lpIO, TRUE);

}

else  // filename is invalid - set focus back to ec

{

  HWND hWnd;

  lpIO->fFileDirty = FALSE;

  lpIO->fFileValid = FALSE;

  hWnd = GetDlgItem(hDlg, ID_IO_FILEDISPLAY);

  SetFocus(hWnd);

                          SendSetSel (hWnd, 0, -1);

  UpdateClassType(hDlg, lpIO, FALSE);

}

return TRUE;  // eat this message

}

else if (  (lpIO->dwFlags & IOF_SELECTCREATEFROMFILE)

   && (FALSE == lpIO->fFileValid) )

{

// filename is invalid - set focus back to ec

HWND hWnd;

char        szFile[OLEUI_CCHPATHMAX];

if (0!=GetDlgItemText(hDlg, ID_IO_FILEDISPLAY,

szFile, sizeof(szFile)))

{

OpenFileError(hDlg, lpIO->nErrCode, szFile);

}

lpIO->fFileDirty = FALSE;

lpIO->fFileValid = FALSE;

hWnd = GetDlgItem(hDlg, ID_IO_FILEDISPLAY);

SetFocus(hWnd);

                        SendSetSel (hWnd, 0, -1);

UpdateClassType(hDlg, lpIO, FALSE);

return TRUE;  // eat this message

}

//Copy the necessary information back to the original struct

lpOIO=lpIO->lpOIO;

lpOIO->dwFlags=lpIO->dwFlags;

if (lpIO->dwFlags & IOF_SELECTCREATENEW)

{

   hListBox=GetDlgItem(hDlg, ID_IO_OBJECTTYPELIST);

   iCurSel=(UINT)SendMessage(hListBox, LB_GETCURSEL, 0, 0);

   if (lpIO->dwFlags & IOF_CHECKDISPLAYASICON)

   {

   lpOIO->hMetaPict=(HGLOBAL)SendMessage(hListBox,

   LB_GETITEMDATA, iCurSel, 0L);

   /*

* Set the item data to 0 here so that the cleanup

* code doesn't delete the metafile.

*/

   SendMessage(hListBox, LB_SETITEMDATA, iCurSel, 0L);

   }

   else

   lpOIO->hMetaPict = (HGLOBAL)NULL;

   SendMessage(hListBox, LB_GETTEXT, iCurSel

   , (LPARAM)(LPSTR)szBuffer);

   lpszCLSID=PointerToNthField((LPSTR)szBuffer, 2, '\t');

   CLSIDFromString(lpszCLSID, &lpOIO->clsid);

}

else  // IOF_SELECTCREATEFROMFILE

{

   if (lpIO->dwFlags & IOF_CHECKDISPLAYASICON)

   {

 // get metafile here

  lpOIO->hMetaPict = (HGLOBAL)SendDlgItemMessage(hDlg,

 ID_IO_ICONDISPLAY,

 IBXM_IMAGEGET,

 0, 0L);

   }

   else

 lpOIO->hMetaPict = (HGLOBAL)NULL;

}

   GetDlgItemText(hDlg, ID_IO_FILEDISPLAY,

  lpIO->szFile, lpOIO->cchFile);

   LSTRCPYN(lpOIO->lpszFile, lpIO->szFile, lpOIO->cchFile);

   SendMessage(hDlg, uMsgEndDialog, OLEUI_OK, 0L);

}

break;

case IDCANCEL:

SendMessage(hDlg, uMsgEndDialog, OLEUI_CANCEL, 0L);

break;

case ID_OLEUIHELP:

PostMessage(lpIO->lpOIO->hWndOwner, uMsgHelp

, (WPARAM)hDlg, MAKELPARAM(IDD_INSERTOBJECT, 0));

break;

}

break;

default:

{

if (lpIO && iMsg == lpIO->nBrowseHelpID) {

PostMessage(lpIO->lpOIO->hWndOwner, uMsgHelp,

(WPARAM)hDlg, MAKELPARAM(IDD_INSERTFILEBROWSE, 0));

}

}

break;

}

return FALSE;

}

/*

 * FInsertObjectInit

 *

 * Purpose:

 *  WM_INITIDIALOG handler for the Insert Object dialog box.

 *

 * Parameters:

 *  hDlg            HWND of the dialog

 *  wParam          WPARAM of the message

 *  lParam          LPARAM of the message

 *

 * Return Value:

 *  BOOL            Value to return for WM_INITDIALOG.

 */

BOOL FInsertObjectInit(HWND hDlg, WPARAM wParam, LPARAM lParam)

{

LPOLEUIINSERTOBJECT     lpOIO;

LPINSERTOBJECT          lpIO;

RECT                    rc;

DWORD                   dw;

HFONT                   hFont;

HWND                    hList;

UINT                    u;

BOOL                    fCheck;

char                   *pch;

//1.  Copy the structure at lParam into our instance memory.

lpIO=(LPINSERTOBJECT)LpvStandardInit(hDlg, sizeof(INSERTOBJECT), TRUE, &hFont);

//PvStandardInit send a termination to us already.

if (NULL==lpIO)

return FALSE;

lpOIO=(LPOLEUIINSERTOBJECT)lParam;

//2.  Save the original pointer and copy necessary information.

lpIO->lpOIO  =lpOIO;

lpIO->dwFlags=lpOIO->dwFlags;

lpIO->clsid  =lpOIO->clsid;

if ( (lpOIO->lpszFile) && ('\0' != *lpOIO->lpszFile) )

LSTRCPYN((LPSTR)lpIO->szFile, lpOIO->lpszFile, OLEUI_CCHPATHMAX);

else

*(lpIO->szFile) = '\0';

lpIO->hMetaPictFile = (HGLOBAL)NULL;

//3.  If we got a font, send it to the necessary controls.

if (NULL!=hFont)

{

SendDlgItemMessage(hDlg, ID_IO_RESULTTEXT,  WM_SETFONT, (WPARAM)hFont, 0L);

SendDlgItemMessage(hDlg, ID_IO_FILETYPE,  WM_SETFONT, (WPARAM)hFont, 0L);

}

//4.  Fill the Object Type listbox with entries from the reg DB.

hList=GetDlgItem(hDlg, ID_IO_OBJECTTYPELIST);

UFillClassList(hList, lpOIO->cClsidExclude, lpOIO->lpClsidExclude

, (BOOL)(lpOIO->dwFlags & IOF_VERIFYSERVERSEXIST));

//Set the tab width in the list to push all the tabs off the side.

GetClientRect(hList, &rc);

dw=GetDialogBaseUnits();

rc.right =(8*rc.right)/LOWORD(dw);  //Convert pixels to 2x dlg units.

SendMessage(hList, LB_SETTABSTOPS, 1, (LPARAM)(LPINT)&rc.right);

//5. Initilize the file name display to cwd if we don't have any name.

if ('\0' == *(lpIO->szFile))

{

 if ((pch=_getcwd(NULL, OLEUI_CCHPATHMAX)) != NULL) {

 if (*(pch+lstrlen(pch)-1) != '\\')

 lstrcat(pch, "\\");  // put slash on end of cwd

 SetDlgItemText(hDlg, ID_IO_FILEDISPLAY, pch);

 lpIO->fFileDirty = TRUE;  // cwd is not a valid filename

#ifndef __TURBOC__

 free(pch);

#endif

 }else{

 OutputDebugString("*** Please install VC++ Patch #1 ***\n\r");

 }

}

else

{

SetDlgItemText(hDlg, ID_IO_FILEDISPLAY, lpIO->szFile);

if (FValidateInsertFile(hDlg, FALSE, &lpIO->nErrCode))

  lpIO->fFileDirty = FALSE;

else

  lpIO->fFileDirty = TRUE;

}

//6.  Initialize the selected type radiobutton.

if (lpIO->dwFlags & IOF_SELECTCREATENEW)

{

StandardShowDlgItem(hDlg, ID_IO_FILETEXT, SW_HIDE);

StandardShowDlgItem(hDlg, ID_IO_FILETYPE, SW_HIDE);

StandardShowDlgItem(hDlg, ID_IO_FILEDISPLAY, SW_HIDE);

StandardShowDlgItem(hDlg, ID_IO_FILE, SW_HIDE);

StandardShowDlgItem(hDlg, ID_IO_LINKFILE, SW_HIDE);

CheckRadioButton(hDlg, ID_IO_CREATENEW, ID_IO_CREATEFROMFILE, ID_IO_CREATENEW);

lpIO->fAsIconNew=(0L!=(lpIO->dwFlags & IOF_CHECKDISPLAYASICON));

SetFocus(hList);

}

else

{

/*

 * Use pszType as the initial File.  If there's no initial

 * file then we have to remove any check from Display As

 * Icon.  We also check Link if so indicated for this option.

 */

StandardShowDlgItem(hDlg, ID_IO_OBJECTTYPELIST, SW_HIDE);

StandardShowDlgItem(hDlg, ID_IO_OBJECTTYPETEXT, SW_HIDE);

// Don't preselect display as icon if the filename isn't valid

if (TRUE == lpIO->fFileDirty)

lpIO->dwFlags &= ~(IOF_CHECKDISPLAYASICON);

if (IOF_DISABLELINK & lpIO->dwFlags)

StandardShowDlgItem(hDlg, ID_IO_LINKFILE, SW_HIDE);

else

{

CheckDlgButton(hDlg, ID_IO_LINKFILE

, (BOOL)(0L!=(lpIO->dwFlags & IOF_CHECKLINK)));

}

CheckRadioButton(hDlg, ID_IO_CREATENEW, ID_IO_CREATEFROMFILE, ID_IO_CREATEFROMFILE);

lpIO->fAsIconFile=(0L!=(lpIO->dwFlags & IOF_CHECKDISPLAYASICON));

SetFocus(GetDlgItem(hDlg, ID_IO_FILEDISPLAY));

}

//7.  Initialize the Display as Icon state

fCheck=(BOOL)(lpIO->dwFlags & IOF_CHECKDISPLAYASICON);

u=fCheck ? SW_SHOWNORMAL : SW_HIDE;

StandardShowDlgItem(hDlg, ID_IO_CHANGEICON, u);

StandardShowDlgItem(hDlg, ID_IO_ICONDISPLAY, u);

CheckDlgButton(hDlg, ID_IO_DISPLAYASICON, fCheck);

//8.  Show or hide the help button

if (!(lpIO->dwFlags & IOF_SHOWHELP))

StandardShowDlgItem(hDlg, ID_OLEUIHELP, SW_HIDE);

//9.  Initialize the result display

UpdateClassIcon(hDlg, lpIO, GetDlgItem(hDlg, ID_IO_OBJECTTYPELIST));

SetInsertObjectResults(hDlg, lpIO);

//10.  Change the caption

if (NULL!=lpOIO->lpszCaption)

SetWindowText(hDlg, lpOIO->lpszCaption);

//11. Hide all DisplayAsIcon related controls if it should be disabled

if ( lpIO->dwFlags & IOF_DISABLEDISPLAYASICON ) {

  StandardShowDlgItem(hDlg, ID_IO_DISPLAYASICON, SW_HIDE);

  StandardShowDlgItem(hDlg, ID_IO_CHANGEICON, SW_HIDE);

  StandardShowDlgItem(hDlg, ID_IO_ICONDISPLAY, SW_HIDE);

}

lpIO->nBrowseHelpID = RegisterWindowMessage(HELPMSGSTRING);

//All Done:  call the hook with lCustData

UStandardHook(lpIO, hDlg, WM_INITDIALOG, wParam, lpOIO->lCustData);

/*

 * We either set focus to the listbox or the edit control.  In either

 * case we don't want Windows to do any SetFocus, so we return FALSE.

 */

return FALSE;

}

/*

 * UFillClassList

 *

 * Purpose:

 *  Enumerates available OLE object classes from the registration

 *  database and fills a listbox with those names.

 *

 *  Note that this function removes any prior contents of the listbox.

 *

 * Parameters:

 *  hList           HWND to the listbox to fill.

 *  cIDEx           UINT number of CLSIDs to exclude in lpIDEx

 *  lpIDEx          LPCLSID to CLSIDs to leave out of the listbox.

 *  fVerify         BOOL indicating if we are to validate existence of

 *                  servers before putting them in the list.

 *

 * Return Value:

 *  UINT            Number of strings added to the listbox, -1 on failure.

 */

UINT UFillClassList(HWND hList, UINT cIDEx, LPCLSID lpIDEx, BOOL fVerify)

{

DWORD       dw;

UINT        cStrings=0;

UINT        i;

UINT        cch;

HKEY        hKey;

LONG        lRet;

HFILE       hFile;

OFSTRUCT    of;

BOOL        fExclude;

LPMALLOC    pIMalloc;

LPSTR       pszExec;

LPSTR       pszClass;

LPSTR       pszKey;

LPSTR       pszID = NULL;

CLSID       clsid;

//Get some work buffers

if (NOERROR!=CoGetMalloc(MEMCTX_TASK, &pIMalloc))

return (UINT)-1;

pszExec=(LPSTR)pIMalloc->lpVtbl->Alloc(pIMalloc, OLEUI_CCHKEYMAX*3);

if (NULL==pszExec)

{

pIMalloc->lpVtbl->Release(pIMalloc);

return (UINT)-1;

}

pszClass=pszExec+OLEUI_CCHKEYMAX;

pszKey=pszClass+OLEUI_CCHKEYMAX;

//Open up the root key.

lRet=RegOpenKey(HKEY_CLASSES_ROOT, NULL, &hKey);

if ((LONG)ERROR_SUCCESS!=lRet)

{

pIMalloc->lpVtbl->Free(pIMalloc, (LPVOID)pszExec);

pIMalloc->lpVtbl->Release(pIMalloc);

return (UINT)-1;

}

//Clean out the existing strings.

SendMessage(hList, LB_RESETCONTENT, 0, 0L);

cStrings=0;

while (TRUE)

{

if (NULL!=pszID)

{

pIMalloc->lpVtbl->Free(pIMalloc, (LPVOID)pszID);

pszID = NULL;

}

lRet=RegEnumKey(hKey, cStrings++, pszClass, OLEUI_CCHKEYMAX);

if ((LONG)ERROR_SUCCESS!=lRet)

break;

//Cheat on lstrcat by using lstrcpy after this string, saving time

cch=lstrlen(pszClass);

// Check for \NotInsertable. if this is found then this overrides

// all other keys; this class will NOT be added to the InsertObject

// list.

lstrcpy(pszClass+cch, "\\NotInsertable");

dw=OLEUI_CCHKEYMAX;

lRet=RegQueryValue(hKey, pszClass, pszKey, &dw);

if ((LONG)ERROR_SUCCESS==lRet)

continue;   // NotInsertable IS found--skip this class

//Check for a \protocol\StdFileEditing\server entry.

lstrcpy(pszClass+cch, "\\protocol\\StdFileEditing\\server");

dw=OLEUI_CCHKEYMAX;

lRet=RegQueryValue(hKey, pszClass, pszKey, &dw);

if ((LONG)ERROR_SUCCESS==lRet)

{

/*

* Check if the EXE actually exists.  By default we don't do this

* to bring up the dialog faster.  If an application wants to be

* stringent, they can provide IOF_VERIFYSERVERSEXIST.

*/

hFile = !HFILE_ERROR;

if (fVerify)

hFile=DoesFileExist(pszKey, &of);

if (HFILE_ERROR!=hFile)

{

dw=OLEUI_CCHKEYMAX;

*(pszClass+cch)=0;  // set back to rootkey

// Get full user type name

lRet=RegQueryValue(hKey, pszClass, pszKey, &dw);

if ((LONG)ERROR_SUCCESS!=lRet)

continue;   // error getting type name--skip this class

}

}

else

{

/*

 * No \protocol\StdFileEditing\server entry.  Look to see if

 * there's an Insertable entry.  If there is, then use the

 * Clsid to look at CLSID\clsid\LocalServer and \InprocServer

 */

lstrcpy(pszClass+cch, "\\Insertable");

dw=OLEUI_CCHKEYMAX;

lRet=RegQueryValue(hKey, pszClass, pszKey, &dw);

if ((LONG)ERROR_SUCCESS!=lRet)

continue;   // Insertable NOT found--skip this class

//Get memory for pszID

pszID=pIMalloc->lpVtbl->Alloc(pIMalloc, OLEUI_CCHKEYMAX);

if (NULL==pszID)

continue;

*(pszClass+cch)=0;  // set back to rootkey

lstrcat(pszClass+cch, "\\CLSID");

dw=OLEUI_CCHKEYMAX;

lRet=RegQueryValue(hKey, pszClass, pszID, &dw);

if ((LONG)ERROR_SUCCESS!=lRet)

continue;   // CLSID subkey not found

lstrcpy(pszExec, "CLSID\\");

lstrcat(pszExec, pszID);

//CLSID\ is 6, dw contains pszID length (incl. null terminator)

            // NOTE: we must subrtract 1 for the null terminator.

            //       (this was a bug in OLE 2.01)

cch=6+(UINT)dw-1;

#ifdef WIN32

            lstrcpy(pszExec+cch, "\\LocalServer32");

#else

            lstrcpy(pszExec+cch, "\\LocalServer");

#endif

dw=OLEUI_CCHKEYMAX;

lRet=RegQueryValue(hKey, pszExec, pszKey, &dw);

if ((LONG)ERROR_SUCCESS!=lRet)

{

//Try InprocServer

#ifdef WIN32

                lstrcpy(pszExec+cch, "\\InProcServer32");

#else

                lstrcpy(pszExec+cch, "\\InProcServer");

#endif

dw=OLEUI_CCHKEYMAX;

lRet=RegQueryValue(hKey, pszExec, pszKey, &dw);

if ((LONG)ERROR_SUCCESS!=lRet)

continue;

}

if (fVerify)

{

if (HFILE_ERROR==DoesFileExist(pszKey, &of))

continue;

}

// Refetch the object name

*(pszExec+cch)=0;   //Remove final keyword.

dw=OLEUI_CCHKEYMAX;

lRet=RegQueryValue(hKey, pszExec, pszKey, &dw);

if ((LONG)ERROR_SUCCESS!=lRet)

continue;

}

//Get CLSID to add to listbox.

if (NULL==pszID)

{

CLSIDFromProgID(pszClass, &clsid);

StringFromCLSID(&clsid, &pszID);

}

else

CLSIDFromString(pszID, &clsid);

if (NULL==pszID || IsEqualCLSID(&clsid, &CLSID_NULL))

continue;

//Check if this CLSID is in the exclusion list.

fExclude=FALSE;

for (i=0; i < cIDEx; i++)

{

if (IsEqualCLSID(&clsid, (LPCLSID)(lpIDEx+i)))

{

fExclude=TRUE;

break;

}

}

if (fExclude)

continue;

//We go through all the conditions, add the string.

lstrcat(pszKey, "\t");

// only add to listbox if not a duplicate

if (LB_ERR==SendMessage(hList,LB_FINDSTRING,0,(LPARAM)pszKey))

{

lstrcat(pszKey, pszID);

SendMessage(hList, LB_ADDSTRING, 0, (LPARAM)pszKey);

}

}

if (NULL!=pszID)

{

pIMalloc->lpVtbl->Free(pIMalloc, (LPVOID)pszID);

pszID = NULL;

}

//Select the first item by default

SendMessage(hList, LB_SETCURSEL, 0, 0L);

RegCloseKey(hKey);

pIMalloc->lpVtbl->Free(pIMalloc, (LPVOID)pszExec);

pIMalloc->lpVtbl->Release(pIMalloc);

return cStrings;

}

/*

 * FToggleObjectSource

 *

 * Purpose:

 *  Handles enabling, disabling, showing, and flag manipulation when the

 *  user changes between Create New, Insert File, and Link File in the

 *  Insert Object dialog.

 *

 * Parameters:

 *  hDlg            HWND of the dialog

 *  lpIO            LPINSERTOBJECT pointing to the dialog structure

 *  dwOption        DWORD flag indicating the option just selected:

 *                  IOF_SELECTCREATENEW or IOF_SELECTCREATEFROMFILE

 *

 * Return Value:

 *  BOOL            TRUE if the option was already selected, FALSE otherwise.

 */

BOOL FToggleObjectSource(HWND hDlg, LPINSERTOBJECT lpIO, DWORD dwOption)

{

BOOL        fTemp;

UINT        uTemp;

DWORD       dwTemp;

int         i;

//Skip all of this if we're already selected.

if (lpIO->dwFlags & dwOption)

return TRUE;

// if we're switching from "from file" to "create new" and we've got

// an icon for "from file", then we need to save it so that we can

// show it if the user reselects "from file".

if ( (IOF_SELECTCREATENEW == dwOption) &&

 (lpIO->dwFlags & IOF_CHECKDISPLAYASICON) )

  lpIO->hMetaPictFile = (HGLOBAL)SendDlgItemMessage(hDlg, ID_IO_ICONDISPLAY, IBXM_IMAGEGET, 0, 0L);

/*

 * 1.  Change the Display As Icon checked state to reflect the

 *     selection for this option, stored in the fAsIcon* flags.

 */

fTemp=(IOF_SELECTCREATENEW==dwOption) ? lpIO->fAsIconNew : lpIO->fAsIconFile;

if (fTemp)

lpIO->dwFlags |=IOF_CHECKDISPLAYASICON;

else

lpIO->dwFlags &=~IOF_CHECKDISPLAYASICON;

CheckDlgButton(hDlg, ID_IO_DISPLAYASICON

 , (BOOL)(0L!=(lpIO->dwFlags & IOF_CHECKDISPLAYASICON)));

EnableWindow(GetDlgItem(hDlg, ID_IO_CHANGEICON), fTemp);

/*

 * 2.  Display Icon:  Enabled on Create New or on Create from File if

 *     there is a selected file.

 */

fTemp=(IOF_SELECTCREATENEW==dwOption) ? TRUE : lpIO->fFileSelected;

EnableWindow(GetDlgItem(hDlg, ID_IO_DISPLAYASICON), fTemp);

//OK and Link follow the same enabling as Display As Icon.

EnableWindow(GetDlgItem(hDlg, IDOK), fTemp);

EnableWindow(GetDlgItem(hDlg, ID_IO_LINKFILE), fTemp);

//3.  Enable Browse... when Create from File is selected.

fTemp=(IOF_SELECTCREATENEW==dwOption);

EnableWindow(GetDlgItem(hDlg, ID_IO_FILE),        !fTemp);

EnableWindow(GetDlgItem(hDlg, ID_IO_FILEDISPLAY), !fTemp);

/*

 * 4.  Switch between Object Type listbox on Create New and

 *     file buttons on others.

 */

uTemp=(fTemp) ? SW_SHOWNORMAL : SW_HIDE;

StandardShowDlgItem(hDlg, ID_IO_OBJECTTYPELIST, uTemp);

StandardShowDlgItem(hDlg, ID_IO_OBJECTTYPETEXT, uTemp);

uTemp=(fTemp) ? SW_HIDE : SW_SHOWNORMAL;

StandardShowDlgItem(hDlg, ID_IO_FILETEXT, uTemp);

StandardShowDlgItem(hDlg, ID_IO_FILETYPE, uTemp);

StandardShowDlgItem(hDlg, ID_IO_FILEDISPLAY, uTemp);

StandardShowDlgItem(hDlg, ID_IO_FILE, uTemp);

//Link is always hidden if IOF_DISABLELINK is set.

if (IOF_DISABLELINK & lpIO->dwFlags)

uTemp=SW_HIDE;

StandardShowDlgItem(hDlg, ID_IO_LINKFILE, uTemp);  //last use of uTemp

//5.  Clear out existing any flags selection and set the new one

dwTemp=IOF_SELECTCREATENEW | IOF_SELECTCREATEFROMFILE;

lpIO->dwFlags=(lpIO->dwFlags & ~dwTemp) | dwOption;

/*

 * Show or hide controls as appropriate.  Do the icon

 * display last because it will take some time to repaint.

 * If we do it first then the dialog looks too sluggish.

 */

i=(lpIO->dwFlags & IOF_CHECKDISPLAYASICON) ? SW_SHOWNORMAL : SW_HIDE;

StandardShowDlgItem(hDlg, ID_IO_CHANGEICON, i);

StandardShowDlgItem(hDlg, ID_IO_ICONDISPLAY, i);

//6.Change result display

SetInsertObjectResults(hDlg, lpIO);

/*

 * 7.  For Create New, twiddle the listbox to think we selected it

 *     so it updates the icon from the object type. set the focus

 *     to the list box.

 *

 *     For Insert or Link file, set the focus to the filename button

 *     and update the icon if necessary.

 */

if (fTemp) {

UpdateClassIcon(hDlg, lpIO, GetDlgItem(hDlg, ID_IO_OBJECTTYPELIST));

SetFocus(GetDlgItem(hDlg, ID_IO_OBJECTTYPELIST));

}

else

{

if (lpIO->fAsIconFile && (NULL != lpIO->hMetaPictFile) )

{

   SendDlgItemMessage(hDlg, ID_IO_ICONDISPLAY, IBXM_IMAGESET, (WPARAM)lpIO->hMetaPictFile, 0L);

   lpIO->hMetaPictFile = 0;

}

else

   UpdateClassIcon(hDlg, lpIO, NULL);

SetFocus(GetDlgItem(hDlg, ID_IO_FILE));

}

return FALSE;

}

/*

 * UpdateClassType

 *

 * Purpose:

 *  Updates static text control to reflect current file type.  Assumes

 *  a valid filename.

 *

 * Parameters

 *  hDlg            HWND of the dialog box.

 *  lpIO            LPINSERTOBJECT pointing to the dialog structure

 *  fSet            TRUE to set the text, FALSE to explicitly clear it

 *

 * Return Value:

 *  None

 */

void UpdateClassType(HWND hDlg, LPINSERTOBJECT lpIO, BOOL fSet)

{

   CLSID clsid;

   char  szFileName[OLEUI_CCHPATHMAX];

   char  szFileType[OLEUI_CCHLABELMAX];

   *szFileType = '\0';

   if (fSet)

   {

  GetDlgItemText(hDlg, ID_IO_FILEDISPLAY, (LPSTR)szFileName, OLEUI_CCHPATHMAX);

  if (NOERROR == GetClassFile((LPSTR)szFileName, &clsid) )

OleStdGetUserTypeOfClass(&clsid, szFileType, OLEUI_CCHLABELMAX, NULL);

   }

   SetDlgItemText(hDlg, ID_IO_FILETYPE, (LPSTR)szFileType);

   return;

}

/*

 * UpdateClassIcon

 *

 * Purpose:

 *  Handles LBN_SELCHANGE for the Object Type listbox.  On a selection

 *  change, we extract an icon from the server handling the currently

 *  selected object type using the utility function HIconFromClass.

 *  Note that we depend on the behavior of FillClassList to stuff the

 *  object class after a tab in the listbox string that we hide from

 *  view (see WM_INITDIALOG).

 *

 * Parameters

 *  hDlg            HWND of the dialog box.

 *  lpIO            LPINSERTOBJECT pointing to the dialog structure

 *  hList           HWND of the Object Type listbox.

 *

 * Return Value:

 *  None

 */

void UpdateClassIcon(HWND hDlg, LPINSERTOBJECT lpIO, HWND hList)

{

UINT        iSel;

DWORD       cb;

LPMALLOC    pIMalloc;

LPSTR       pszName, pszCLSID, pszTemp;

HGLOBAL     hMetaPict;

LRESULT     dwRet;

//If Display as Icon is not selected, exit

if (!(lpIO->dwFlags & IOF_CHECKDISPLAYASICON))

return;

/*

 * When we change object type selection, get the new icon for that

 * type into our structure and update it in the display.  We use the

 * class in the listbox when Create New is selected or the association

 * with the extension in Create From File.

 */

if (lpIO->dwFlags & IOF_SELECTCREATENEW)

{

iSel=(UINT)SendMessage(hList, LB_GETCURSEL, 0, 0L);

if (LB_ERR==(int)iSel)

return;

//Check to see if we've already got the hMetaPict for this item

dwRet=SendMessage(hList, LB_GETITEMDATA, (WPARAM)iSel, 0L);

hMetaPict=(HGLOBAL)(UINT)dwRet;

if (hMetaPict)

{

//Yep, we've already got it, so just display it and return.

SendDlgItemMessage(hDlg, ID_IO_ICONDISPLAY, IBXM_IMAGESET, (WPARAM)hMetaPict, 0L);

return;

}

iSel=(UINT)SendMessage(hList, LB_GETCURSEL, 0, 0L);

if (LB_ERR==(int)iSel)

return;

//Allocate a string to hold the entire listbox string

cb=SendMessage(hList, LB_GETTEXTLEN, iSel, 0L);

}

else

cb=OLEUI_CCHPATHMAX;

if (NOERROR!=CoGetMalloc(MEMCTX_TASK, &pIMalloc))

return;

pszName=(LPSTR)pIMalloc->lpVtbl->Alloc(pIMalloc, cb+1);

if (NULL==pszName)

{

pIMalloc->lpVtbl->Release(pIMalloc);

return;

}

*pszName=0;

//Get the clsid we want.

if (lpIO->dwFlags & IOF_SELECTCREATENEW)

{

//Grab the classname string from the list

SendMessage(hList, LB_GETTEXT, iSel, (LONG)pszName);

//Set pointer to CLSID (string)

pszCLSID=PointerToNthField(pszName, 2, '\t');

//Null terminate pszName string

pszTemp=AnsiPrev(pszName, pszCLSID);

*pszTemp='\0';

CLSIDFromString(pszCLSID, &lpIO->clsid);

hMetaPict = GetIconOfClass(ghInst, &lpIO->clsid, NULL, TRUE);

}

else

{

CLSID clsid;

//Get the class from the filename

GetDlgItemText(hDlg, ID_IO_FILEDISPLAY, pszName, OLEUI_CCHPATHMAX);

if (lpIO->dwFlags & IOF_CHECKLINK ||

NOERROR != GetClassFile((LPSTR)pszName, &clsid) ) {

// get icon using filename as label (if creating a link)

hMetaPict = GetIconOfFile(ghInst,

pszName, lpIO->dwFlags & IOF_CHECKLINK ? TRUE : FALSE);

} else {

// not creating a link and we can get CLSID from the filename,

// therefore generate an icon with short type name as label

hMetaPict = GetIconOfClass(ghInst, &clsid, NULL, TRUE);

}

}

//Replace the current display with this new one.

SendDlgItemMessage(hDlg, ID_IO_ICONDISPLAY, IBXM_IMAGESET, (WPARAM)hMetaPict, 0L);

//Enable or disable "Change Icon" button depending on whether

//we've got a valid filename or not.

EnableWindow(GetDlgItem(hDlg, ID_IO_CHANGEICON), hMetaPict ? TRUE : FALSE);

//Save the hMetaPict so that we won't have to re-create

if (lpIO->dwFlags & IOF_SELECTCREATENEW)

SendMessage(hList, LB_SETITEMDATA, (WPARAM)iSel, MAKELPARAM(hMetaPict,0));

pIMalloc->lpVtbl->Free(pIMalloc, (LPVOID)pszName);

pIMalloc->lpVtbl->Release(pIMalloc);

return;

}

/*

 * SetInsertObjectResults

 *

 * Purpose:

 *  Centralizes setting of the Result and icon displays in the Insert Object

 *  dialog.  Handles loading the appropriate string from the module's

 *  resources and setting the text, displaying the proper result picture,

 *  and showing the proper icon.

 *

 * Parameters:

 *  hDlg            HWND of the dialog box so we can access controls.

 *  lpIO            LPINSERTOBJECT in which we assume that the

 *                  current radiobutton and Display as Icon selections

 *                  are set.  We use the state of those variables to

 *                  determine which string we use.

 *

 * Return Value:

 *  None

 */

void SetInsertObjectResults(HWND hDlg, LPINSERTOBJECT lpIO)

{

LPSTR       pszT, psz1, psz2, psz3, psz4, pszTemp;

UINT        i, iString1, iString2, iImage, cch;

LPMALLOC    pIMalloc;

BOOL        fAsIcon;

/*

 * We need scratch memory for loading the stringtable string, loading

 * the object type from the listbox, and constructing the final string.

 * We therefore allocate three buffers as large as the maximum message

 * length (512) plus the object type, guaranteeing that we have enough

 * in all cases.

 */

i=(UINT)SendDlgItemMessage(hDlg, ID_IO_OBJECTTYPELIST, LB_GETCURSEL, 0, 0L);

cch = 512 + (i != LB_ERR

                    ? (UINT)SendDlgItemMessage(hDlg, ID_IO_OBJECTTYPELIST, LB_GETTEXTLEN, i, 0L)

: 0);

if (NOERROR!=CoGetMalloc(MEMCTX_TASK, &pIMalloc))

return;

pszTemp=(LPSTR)pIMalloc->lpVtbl->Alloc(pIMalloc, (DWORD)(4*cch));

if (NULL==pszTemp)

{

pIMalloc->lpVtbl->Release(pIMalloc);

return;

}

psz1=pszTemp;

psz2=psz1+cch;

psz3=psz2+cch;

psz4=psz3+cch;

//Default is an empty string.

iString1 = 0;

iString2 = 0;

iImage   = RESULTIMAGE_NONE;

*psz1    = 0;

fAsIcon=(0L!=(lpIO->dwFlags & IOF_CHECKDISPLAYASICON));

if (i != LB_ERR && lpIO->dwFlags & IOF_SELECTCREATENEW)

{

iString1 = (UINT)(fAsIcon ? IDS_IORESULTNEWICON : IDS_IORESULTNEW);

iString2 = (UINT)0;

iImage   = (UINT)(fAsIcon ? RESULTIMAGE_EMBEDICON : RESULTIMAGE_EMBED);

}

else if (i != LB_ERR && lpIO->dwFlags & IOF_SELECTCREATEFROMFILE)

{

//Pay attention to Link checkbox

if (lpIO->dwFlags & IOF_CHECKLINK)

{

iString1 = (UINT)(fAsIcon ? IDS_IORESULTLINKFILEICON1 : IDS_IORESULTLINKFILE1);

iString2 = (UINT)(fAsIcon ? IDS_IORESULTLINKFILEICON2 : IDS_IORESULTLINKFILE2);

iImage = (UINT)(fAsIcon ? RESULTIMAGE_LINKICON : RESULTIMAGE_LINK);

}

else

{

iString1 = (UINT)IDS_IORESULTFROMFILE1;

iString2 = (UINT)(fAsIcon ? IDS_IORESULTFROMFILEICON2 : IDS_IORESULTFROMFILE2);

iImage = (UINT)(fAsIcon ? RESULTIMAGE_EMBEDICON : RESULTIMAGE_EMBED);

}

}

// REVIEW CDH

// Load and build the display strings

if (0!=LoadString(ghInst, iString1, psz1, cch))

{

   // Load second string, if necessary

if (   (0 != iString2)

&& (0 != LoadString(ghInst, iString2, psz4, cch)) )

{

  lstrcat(psz1, psz4);  // concatenate strings together.

}

//In Create New, do the extra step of inserting the object type string

if (lpIO->dwFlags & IOF_SELECTCREATENEW)

{

SendDlgItemMessage(hDlg, ID_IO_OBJECTTYPELIST, LB_GETTEXT

  , i, (LONG)psz2);

//Null terminate at any tab (before the classname)

pszT=psz2;

while ('\t'!=*pszT && 0!=*pszT)

pszT++;

*pszT=0;

//Build the string and point psz1 to it.

wsprintf(psz3, psz1, psz2);

psz1=psz3;

}

}

//If LoadString failed, we simply clear out the results (*psz1=0 above)

SetDlgItemText(hDlg, ID_IO_RESULTTEXT, psz1);

//Go change the image and Presto!  There you have it.

SendDlgItemMessage(hDlg, ID_IO_RESULTIMAGE, RIM_IMAGESET, iImage, 0L);

pIMalloc->lpVtbl->Free(pIMalloc, (LPVOID)pszTemp);

pIMalloc->lpVtbl->Release(pIMalloc);

return;

}

/*

 * FValidateInsertFile

 *

 * Purpose:

 *  Given a possibly partial pathname from the file edit control,

 *  attempt to locate the file and if found, store the full path

 *  in the edit control ID_IO_FILEDISPLAY.

 *

 * Parameters:

 *  hDlg            HWND of the dialog box.

 *  fTellUser       BOOL TRUE if function should tell user, FALSE if

 *                   function should validate silently.

 *

 * Return Value:

 *  BOOL            TRUE if the file is acceptable, FALSE otherwise.

 */

BOOL FValidateInsertFile(HWND hDlg, BOOL fTellUser, UINT FAR* lpnErrCode)

{

OFSTRUCT    of;

HFILE       hFile;

char        szFile[OLEUI_CCHPATHMAX];

*lpnErrCode = 0;

/*

 * To validate we attempt OpenFile on the string.  If OpenFile

 * fails then we display an error.  If not, OpenFile will store

 * the complete path to that file in the OFSTRUCT which we can

 * then stuff in the edit control.

 */

if (0==GetDlgItemText(hDlg, ID_IO_FILEDISPLAY, szFile, sizeof(szFile)))

return FALSE;   // #4569 : return FALSE when there is no text in ctl

hFile=DoesFileExist(szFile, &of);

// if file is currently open (ie. sharing violation) OleCreateFromFile

// and OleCreateLinkToFile can still succeed; do not consider it an

// error.

if (HFILE_ERROR==hFile && 0x0020/*sharing violation*/!=of.nErrCode)

{

   *lpnErrCode = of.nErrCode;

   if (fTellUser)

   OpenFileError(hDlg, of.nErrCode, szFile);

   return FALSE;

}

//OFSTRUCT contains an OEM name, not ANSI as we need for the edit box.

OemToAnsi(of.szPathName, of.szPathName);

SetDlgItemText(hDlg, ID_IO_FILEDISPLAY, of.szPathName);

return TRUE;

}

/*

 * InsertObjectCleanup

 *

 * Purpose:

 *  Clears cached icon metafiles from those stored in the listbox.

 *

 * Parameters:

 *  hDlg            HWND of the dialog.

 *

 * Return Value:

 *  None

 */

void InsertObjectCleanup(HWND hDlg)

{

HWND      hList;

UINT      iItems;

HGLOBAL   hMetaPict;

LRESULT   dwRet;

UINT      i;

hList=GetDlgItem(hDlg, ID_IO_OBJECTTYPELIST);

iItems=(UINT)SendMessage(hList, LB_GETCOUNT, 0, 0L);

for (i=0; i < iItems; i++)

{

dwRet=SendMessage(hList, LB_GETITEMDATA, (WPARAM)i, 0L);

//Cast of LRESULT to UINT to HGLOBAL portable to Win32.

hMetaPict=(HGLOBAL)(UINT)dwRet;

if (hMetaPict)

OleUIMetafilePictIconFree(hMetaPict);

}

return;

}


LINKS.C  (WRAPUI Sample)

/*

 * links.c

 *

 * Implements the OleUIEditLinks function which invokes the complete

 * Edit Links dialog.

 *

 * Copyright (c)1992 Microsoft Corporation, All Right Reserved

 */

#define STRICT  1

#include "ole2ui.h"

#include "common.h"

#include "edlinks.h"

#include "utility.h"

#include <commdlg.h>

#include <dlgs.h>

#include <stdlib.h>

#ifdef WIN32

/* 1/23/94 - define LINK_COMMDLG avoid LoadLibrary ("commdlg.dll")*/

#define LINK_COMMDLG

#endif

OLEDBGDATA

/*

* OleUIEditLinks

*

* Purpose:

*  Invokes the standard OLE Edit Links dialog box allowing the user

*  to manipulate ole links (delete, update, change source, etc).

*

* Parameters:

*  lpEL            LPOLEUIEditLinks pointing to the in-out structure

*                  for this dialog.

*

* Return Value:

*  UINT            One of the following codes, indicating success or error:

*                      OLEUI_SUCCESS           Success

*                      OLEUI_ERR_STRUCTSIZE    The dwStructSize value is wrong

*/

STDAPI_(UINT) OleUIEditLinks(LPOLEUIEDITLINKS lpEL)

{

UINT        uRet;

HGLOBAL     hMemDlg=NULL;

uRet=UStandardValidation((LPOLEUISTANDARD)lpEL, sizeof(OLEUIEDITLINKS)

, &hMemDlg);

if (OLEUI_SUCCESS!=uRet)

return uRet;

/*

* PERFORM ANY STRUCTURE-SPECIFIC VALIDATION HERE!

* ON FAILURE:

*  {

*  if (NULL!=hMemDlg)

*      FreeResource(hMemDlg)

*

*  return OLEUI_<ABBREV>ERR_<ERROR>

*  }

*/

//Now that we've validated everything, we can invoke the dialog.

uRet=UStandardInvocation(EditLinksDialogProc, (LPOLEUISTANDARD)lpEL,

hMemDlg, MAKEINTRESOURCE(IDD_EDITLINKS));

/*

* IF YOU ARE CREATING ANYTHING BASED ON THE RESULTS, DO IT HERE.

*/

return uRet;

}

/*

* EditLinksDialogProc

*

* Purpose:

*  Implements the OLE Edit Links dialog as invoked through the

*  OleUIEditLinks function.

*

* Parameters:

*  Standard

*

* Return Value:

*  Standard

*/

BOOL CALLBACK EXPORT EditLinksDialogProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)

{

LPEDITLINKS           lpEL = NULL;

BOOL                  fHook=FALSE;

UINT                  uRet=0;

HRESULT               hErr;

static int            nColPos[3];

//Declare Win16/Win32 compatible WM_COMMAND parameters.

COMMANDPARAMS(wID, wCode, hWndMsg);

//This will fail under WM_INITDIALOG, where we allocate it.

lpEL=(LPEDITLINKS)LpvStandardEntry(hDlg, iMsg, wParam, lParam, &uRet);

//If the hook processed the message, we're done.

if (0!=uRet)

return (BOOL)uRet;

// Process help message from secondary dialog

if (iMsg == uMsgHelp) {

PostMessage(lpEL->lpOEL->hWndOwner, uMsgHelp, wParam, lParam);

return FALSE;

}

//Process the temination message

if (iMsg==uMsgEndDialog) {

//Free any specific allocations before calling StandardCleanup

StandardCleanup(lpEL, hDlg);

EndDialog(hDlg, wParam);

return TRUE;

   }

switch (iMsg) {

static int    nHeightLine = -1;

static int    nMaxCharWidth = -1;

case WM_INITDIALOG:

{

RECT rc;

int  nStart;

/* calculate the column positions relative to the listbox */

GetWindowRect(GetDlgItem(hDlg, ID_EL_LINKSLISTBOX), (LPRECT)&rc);

nStart = rc.left;

GetWindowRect(GetDlgItem(hDlg, ID_EL_COL1), (LPRECT)&rc);

nColPos[0] = rc.left - nStart;

GetWindowRect(GetDlgItem(hDlg, ID_EL_COL2), (LPRECT)&rc);

nColPos[1] = rc.left - nStart;

GetWindowRect(GetDlgItem(hDlg, ID_EL_COL3), (LPRECT)&rc);

nColPos[2] = rc.left - nStart;

return FEditLinksInit(hDlg, wParam, lParam);

}

break;

case WM_MEASUREITEM:

{

LPMEASUREITEMSTRUCT   lpMIS;

lpMIS = (LPMEASUREITEMSTRUCT)lParam;

if (nHeightLine == -1) {

HFONT hFont;

HDC   hDC;

TEXTMETRIC  tm;

/*  Attempt to get font dialog.  If that fails,

use system font

*/

hFont = (HANDLE)(UINT)SendMessage(hDlg, WM_GETFONT, 0, 0L);

if (hFont == NULL)

hFont = GetStockObject(SYSTEM_FONT);

hDC = GetDC(hDlg);

hFont = SelectObject(hDC, hFont);

GetTextMetrics(hDC, &tm);

nHeightLine = tm.tmHeight;

nMaxCharWidth = tm.tmMaxCharWidth;

ReleaseDC(hDlg, hDC);

}

lpMIS->itemHeight = nHeightLine;

}

break;

case WM_DRAWITEM:

{

LPDRAWITEMSTRUCT    lpDIS;

COLORREF            crText;

LPLINKINFO          lpLI;

HBRUSH              hbr;

int                 nOldBkMode;

char                sz[OLEUI_CCHPATHMAX];

LPSTR               lpsz;

RECT                rcClip;

lpDIS = (LPDRAWITEMSTRUCT)lParam;

lpLI = (LPLINKINFO)lpDIS->itemData;

if ((int)lpDIS->itemID < 0)

break;

if ((ODA_DRAWENTIRE | ODA_SELECT) & lpDIS->itemAction) {

if (ODS_SELECTED & lpDIS->itemState) {

/*Get proper txt colors */

crText = SetTextColor(lpDIS->hDC,

GetSysColor(COLOR_HIGHLIGHTTEXT));

hbr = CreateSolidBrush(GetSysColor(COLOR_HIGHLIGHT));

lpLI->fIsSelected = TRUE;

}

else {

hbr = CreateSolidBrush(GetSysColor(COLOR_WINDOW));

lpLI->fIsSelected = FALSE;

}

FillRect(lpDIS->hDC, &lpDIS->rcItem, hbr);

DeleteObject(hbr);

nOldBkMode = SetBkMode(lpDIS->hDC, TRANSPARENT);

if (lpLI->lpszDisplayName) {

lstrcpy((LPSTR)sz, lpLI->lpszDisplayName);

lpsz = ChopText(

lpDIS->hwndItem,

nColPos[1] - nColPos[0]

  - (nMaxCharWidth > 0 ? nMaxCharWidth : 5),

sz

);

rcClip.left = lpDIS->rcItem.left + nColPos[0];

rcClip.top = lpDIS->rcItem.top;

rcClip.right = lpDIS->rcItem.left + nColPos[1]

- (nMaxCharWidth > 0 ? nMaxCharWidth : 5);

rcClip.bottom = lpDIS->rcItem.bottom;

ExtTextOut(

lpDIS->hDC,

rcClip.left,

rcClip.top,

ETO_CLIPPED,

(LPRECT)&rcClip,

lpsz,

lstrlen(lpsz),

NULL

);

}

if (lpLI->lpszShortLinkType) {

rcClip.left = lpDIS->rcItem.left + nColPos[1];

rcClip.top = lpDIS->rcItem.top;

rcClip.right = lpDIS->rcItem.left + nColPos[2]

- (nMaxCharWidth > 0 ? nMaxCharWidth : 5);

rcClip.bottom = lpDIS->rcItem.bottom;

ExtTextOut(

lpDIS->hDC,

rcClip.left,

rcClip.top,

ETO_CLIPPED,

(LPRECT)&rcClip,

lpLI->lpszShortLinkType,

lstrlen(lpLI->lpszShortLinkType),

NULL

);

}

if (lpLI->lpszAMX) {

rcClip.left = lpDIS->rcItem.left + nColPos[2];

rcClip.top = lpDIS->rcItem.top;

rcClip.right = lpDIS->rcItem.right;

rcClip.bottom = lpDIS->rcItem.bottom;

ExtTextOut(

lpDIS->hDC,

rcClip.left,

rcClip.top,

ETO_CLIPPED,

(LPRECT)&rcClip,

lpLI->lpszAMX,

lstrlen(lpLI->lpszAMX),

NULL

);

}

SetBkMode(lpDIS->hDC, nOldBkMode);

// restore orig colors if we changed them

if (ODS_SELECTED & lpDIS->itemState)

SetTextColor(lpDIS->hDC, crText);

}

InitControls(hDlg, lpEL);

if (ODA_FOCUS & lpDIS->itemAction)

DrawFocusRect(lpDIS->hDC, &lpDIS->rcItem);

}

return TRUE;

case WM_DELETEITEM:

{

UINT  idCtl;

LPDELETEITEMSTRUCT  lpDIS;

LPLINKINFO  lpLI;

lpDIS = (LPDELETEITEMSTRUCT)lParam;

idCtl = wParam;

lpLI = (LPLINKINFO)lpDIS->itemData;

if (lpLI->lpszDisplayName)

OleStdFree((LPVOID)lpLI->lpszDisplayName);

if (lpLI->lpszShortLinkType)

OleStdFree((LPVOID)lpLI->lpszShortLinkType);

if (lpLI->lpszFullLinkType)

OleStdFree((LPVOID)lpLI->lpszFullLinkType);

/* The ChangeSource processing reuses allocated space for

**    links that have been modified.

*/

// Don't free the LINKINFO for the changed links

if (lpLI->fDontFree)

lpLI->fDontFree = FALSE;

else {

if (lpLI->lpszAMX)

OleStdFree((LPVOID)lpLI->lpszAMX);

OleStdFree((LPVOID)lpLI);

}

return TRUE;

}

case WM_COMPAREITEM:

{

LPCOMPAREITEMSTRUCT lpCIS = (LPCOMPAREITEMSTRUCT)lParam;

LPLINKINFO lpLI1 = (LPLINKINFO)lpCIS->itemData1;

LPLINKINFO lpLI2 = (LPLINKINFO)lpCIS->itemData2;

// Sort list entries by DisplayName

return lstrcmp(lpLI1->lpszDisplayName,lpLI2->lpszDisplayName);

}

case WM_COMMAND:

switch (wID) {

case ID_EL_CHANGESOURCE:

{

BOOL fRet = FALSE;

/* This will bring up the file open dlg with one

edit field containing the whole link name.  The file part

will (eventually) be highlighted to indicate where the

file part is.  We need to hook on OK here to be able to

send the changed string to the Parse function */

fRet = Container_ChangeSource(hDlg, lpEL);

if (!fRet)

{

#if defined( OBSOLETE )

PopupMessage(hDlg, (UINT)IDS_LINKS, (UINT)IDS_FAILED,

 MB_ICONEXCLAMATION | MB_OK);

#endif

MessageBeep(MB_ICONEXCLAMATION);  // beep to show failure.

}

InitControls(hDlg, lpEL);

}

break;

case ID_EL_AUTOMATIC:

{

/*  This is available for single or multi-select.  There is

a flag in the structure that is set initially indicating

whether the link is auto or manual so that we need not

query the link each time we want to find out.

This command will make the link automatic if not already.

It will have no effect on links already set to auto.

*/

// turn the button ON

CheckDlgButton(hDlg, ID_EL_AUTOMATIC, 1);

CheckDlgButton(hDlg, ID_EL_MANUAL, 0);

hErr = Container_AutomaticManual(hDlg, TRUE, lpEL);

if (hErr != NOERROR)

#if defined( OBSOLETE )

PopupMessage(hDlg, (UINT)IDS_LINKS, (UINT)IDS_FAILED,

MB_ICONEXCLAMATION | MB_OK);

#endif

// in order to avoid a recursion bug where poping up

// and then closing the message box causes the auto-radio

// button to re-take focus which causes it to

// automatically send another ID_EL_AUTOMATIC message, we

// will only beep to indicate failure.

MessageBeep(MB_ICONEXCLAMATION);  // beep to show failure.

InitControls(hDlg, lpEL);

}

break;

case ID_EL_MANUAL:

{

/* Same rules apply here as they do to auto link.

Additional note - just because something is changed does

not mean that it updates at the moment.  It simply

reflects what kind of updating it does while it lives in

the document.

*/

// turn the button ON

CheckDlgButton(hDlg, ID_EL_MANUAL, 1);

CheckDlgButton(hDlg, ID_EL_AUTOMATIC, 0);

hErr = Container_AutomaticManual(hDlg, FALSE, lpEL);

if (hErr != NOERROR)

#if defined( OBSOLETE )

PopupMessage(hDlg, (UINT)IDS_LINKS, (UINT)IDS_FAILED,

MB_ICONEXCLAMATION | MB_OK);

#endif

// in order to avoid a recursion bug where poping up

// and then closing the message box causes the auto-radio

// button to re-take focus which causes it to

// automatically send another ID_EL_MANUAL message, we

// will only beep to indicate failure.

MessageBeep(MB_ICONEXCLAMATION);  // beep to show failure.

InitControls(hDlg, lpEL);

}

break;

case ID_EL_CANCELLINK:

{

/*  This is Break Link now in the dlg.  This sets the

moniker to null, thereby effectively breaking the link.

The object still has its data effective at the time of

breaking, but becomes a static object.

*****It will need to be deleted from the listbox

*/

hErr = CancelLink(hDlg,lpEL);

if (hErr != NOERROR)

MessageBeep(MB_ICONEXCLAMATION);  // beep to show failure.

InitControls(hDlg, lpEL);

}

break;

case ID_EL_UPDATENOW:

{

/*  This forces an immediate update of the selected

links.  This will start the server etc, so this is a very

expensive operation.

*/

HCURSOR hCur = HourGlassOn();

hErr = Container_UpdateNow(hDlg, lpEL);

if (hErr != NOERROR)

MessageBeep(MB_ICONEXCLAMATION);  // beep to show failure.

InitControls(hDlg, lpEL);

HourGlassOff(hCur);

}

break;

case ID_EL_OPENSOURCE:

{

/*  This will only work on single selection.  It makes no

sense to open multiple sources at the same time, since

the one opened will try to show itself and become the

primary operating target, so to speak.  Button is greyed

if multi select.

Here we do not add the break because we want to exit the

dlg in this case.

*/

hErr = Container_OpenSource(hDlg, lpEL);

if (hErr != NOERROR) {

MessageBeep(MB_ICONEXCLAMATION);  // beep to show failure.

InitControls(hDlg, lpEL);

break;      // don't close dialog

}

}       // fall through

case ID_EL_CLOSE:

{

/* The user is finished with their editing - they now

return to their container document.

*/

SendMessage(hDlg, uMsgEndDialog, OLEUI_OK, 0L);

}

break;

case IDCANCEL:

{

/*  This changes to CLOSE after the user does even ONE

thing in the dlg.  Nothing can really effectively be undone.

*/

SendMessage(hDlg, uMsgEndDialog, OLEUI_CANCEL, 0L);

}

break;

case ID_OLEUIHELP:

{

PostMessage(lpEL->lpOEL->hWndOwner, uMsgHelp

, (WPARAM)hDlg, MAKELPARAM(IDD_EDITLINKS, 0));

break;

}

break;

/*	case EL_RESETLBOX:

{

HWND hListBox = GetDlgItem(hDlg, ID_EL_LINKSLISTBOX);

UINT cLinks;

SendMessage(hListBox, LB_RESETCONTENT, 0, 0L);

cLinks = LoadLinkLB(hListBox, lpEL->lpOEL->lpOleUILinkContainer);

lpEL->fItemsExist = (BOOL)cLinks;

InitControls(hDlg, lpEL);

}

break;  */

}

break;

default:

{

if (lpEL && iMsg == lpEL->nChgSrcHelpID) {

PostMessage(lpEL->lpOEL->hWndOwner, uMsgHelp,

(WPARAM)hDlg, MAKELPARAM(IDD_CHANGESOURCE, 0));

}

}

break;

}

return FALSE;

}

/*

 * FEditLinksInit

 *

 * Purpose:

 *  WM_INITIDIALOG handler for the Edit Links dialog box.

 *

 *

 * Parameters:

 *  hDlg            HWND of the dialog

 *  wParam          WPARAM of the message

 *  lParam          LPARAM of the message

 *

 * Return Value:

 *  BOOL            Value to return for WM_INITDIALOG.

 */

BOOL FEditLinksInit(HWND hDlg, WPARAM wParam, LPARAM lParam)

{

LPEDITLINKS             lpEL;

LPOLEUIEDITLINKS        lpOEL;

HFONT                   hFont;

BOOL                    fDlgItem = FALSE;

DWORD                   dwLink = 0;

ULONG                   cLinks;

LPOLEUILINKCONTAINER    lpOleUILinkCntr;

int                     n;

HWND                    hListBox = GetDlgItem(hDlg, ID_EL_LINKSLISTBOX);

//1.  Copy the structure at lParam into our instance memory.

lpEL = (LPEDITLINKS)LpvStandardInit(hDlg, sizeof(OLEUIEDITLINKS), TRUE,

&hFont);

//PvStandardInit send a termination to us already.

if (NULL==lpEL)

return FALSE;

lpOEL=(LPOLEUIEDITLINKS)lParam;

lpEL->lpOEL=lpOEL;

lpOleUILinkCntr = lpEL->lpOEL->lpOleUILinkContainer;

cLinks = LoadLinkLB(hListBox, lpOleUILinkCntr);

if (cLinks < 0)

return FALSE;

fDlgItem = (BOOL)cLinks;

lpEL->fItemsExist = (BOOL)cLinks;

InitControls(hDlg, lpEL);

//Copy other information from lpOEL that we might modify.

//2.  If we got a font, send it to the necessary controls.

if (NULL != hFont) {

// Do this for as many controls as you need it for.

// SendDlgItemMessage(hDlg, ID_<UFILL>, WM_SETFONT, (WPARAM)hFont, 0L);

}

//3.  Show or hide the help button

if (!(lpEL->lpOEL->dwFlags & ELF_SHOWHELP))

StandardShowDlgItem(hDlg, ID_OLEUIHELP, SW_HIDE);

/*

 * PERFORM OTHER INITIALIZATION HERE.  ON ANY LoadString

 * FAILURE POST OLEUI_MSG_ENDDIALOG WITH OLEUI_ERR_LOADSTRING.

 */

//4.  If requested disable UpdateNow button

if ((lpEL->lpOEL->dwFlags & ELF_DISABLEUPDATENOW))

StandardShowDlgItem(hDlg, ID_EL_UPDATENOW, SW_HIDE);

//5.  If requested disable OpenSource button

if ((lpEL->lpOEL->dwFlags & ELF_DISABLEOPENSOURCE))

StandardShowDlgItem(hDlg, ID_EL_OPENSOURCE, SW_HIDE);

//6.  If requested disable UpdateNow button

if ((lpEL->lpOEL->dwFlags & ELF_DISABLECHANGESOURCE))

StandardShowDlgItem(hDlg, ID_EL_CHANGESOURCE, SW_HIDE);

//7.  If requested disable CancelLink button

if ((lpEL->lpOEL->dwFlags & ELF_DISABLECANCELLINK))

StandardShowDlgItem(hDlg, ID_EL_CANCELLINK, SW_HIDE);

//8. Load 'Close' string used to rename Cancel button

n = LoadString(ghInst, (UINT)IDS_CLOSE, lpEL->szClose, sizeof(lpEL->szClose));

if (!n)

{

PostMessage(hDlg, uMsgEndDialog, OLEUI_ERR_LOADSTRING, 0L);

return FALSE;

}

if (cLinks > 0)

SetFocus(hListBox);

else

SetFocus(GetDlgItem(hDlg, IDCANCEL));

lpEL->nChgSrcHelpID = RegisterWindowMessage(HELPMSGSTRING);

 //n.  Call the hook with lCustData in lParam

UStandardHook(lpEL, hDlg, WM_INITDIALOG, wParam, lpOEL->lCustData);

return FALSE;

}

/*

 * ChangeSourceHook

 *

 * Purpose:

 *  Hooks the ChangeSource dialog to attempt to validate link source changes

 *  specified by the user.

 *

 * Parameters:

 *  hDlg            HWND of the dialog

 *  uMsg            UINT Message

 *  wParam          WPARAM of the message

 *  lParam          LPARAM of the message

 *

 * Return Value:

 *  UNIT            Zero = Do default processing;

 *                  Non Zero = Don't do default processing.

 */

UINT CALLBACK EXPORT ChangeSourceHook(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)

{

LPCHANGESOURCEHOOKDATA lpCshData = NULL;

LPLINKINFO lpLI = NULL;

LPEDITLINKS lpEL = NULL;

LPOLEUILINKCONTAINER lpOleUILinkCntr;

HRESULT hErr;

UINT uRet;

ULONG ulChEaten;

HGLOBAL gh;

//This will fail under WM_INITDIALOG, where we allocate it.

if (NULL!=(gh = GetProp(hDlg, STRUCTUREPROP)))

{

// gh was locked previously, lock and unlock to get lpv

lpCshData=(LPCHANGESOURCEHOOKDATA)GlobalLock(gh);

GlobalUnlock(gh);

if (lpCshData)

{

lpLI = lpCshData->lpOCshData->lpLI;

lpEL = lpCshData->lpOCshData->lpEL;

}

}

//Process the temination message

if (uMsg==uMsgEndDialog)

{

if (NULL!=(gh = RemoveProp(hDlg, STRUCTUREPROP)))

{

GlobalUnlock(gh);

GlobalFree(gh);

}

return TRUE;

}

// User pressed the OK button

if (uMsg == uMsgFileOKString) {

lpOleUILinkCntr = lpEL->lpOEL->lpOleUILinkContainer;

/* NOTE: trigger the focus lost of the edit control. This is

**    not necessary if the user click OK with the mouse but is

**    needed when the user just press <Enter>. If the mouse was

**    used, no extra is done as the MODIFY flag of the edit control

**    has been cleared.

*/

SendMessage(hDlg, WM_COMMAND, edt1,

MAKELPARAM(GetDlgItem(hDlg, edt1), EN_KILLFOCUS));

if (lpCshData->bItemNameStored) {

lpCshData->nFileLength = lstrlen((LPSTR)lpCshData->szEdit) -

lstrlen((LPSTR)lpCshData->szItemName);

}

else {

lpCshData->nFileLength = lstrlen((LPSTR)lpCshData->szEdit);

}

// Try to validate link source change

OLEDBG_BEGIN2("IOleUILinkContainer::SetLinkSource called\r\n");

hErr = lpOleUILinkCntr->lpVtbl->SetLinkSource(

lpOleUILinkCntr,

lpLI->dwLink,

(LPSTR)lpCshData->szEdit,

(ULONG)lpCshData->nFileLength,

&ulChEaten,

TRUE

);

OLEDBG_END2

// Link source change  not validated

if (hErr != NOERROR) {

uRet =PopupMessage(hDlg, (UINT)IDS_CHANGESOURCE, (UINT)IDS_INVALIDSOURCE,

MB_ICONQUESTION | MB_YESNO);

if (uRet == IDYES) {

/* User wants to correct invalid link. Set the edit

**    control selection to the invalid part of the contents.

*/

SetFocus(GetDlgItem(hDlg, edt1));

#ifdef WIN32

SendDlgItemMessage(hDlg, edt1, EM_SETSEL, ulChEaten, (DWORD)-1);

#else

SendDlgItemMessage(hDlg, edt1, EM_SETSEL, 0,

MAKELPARAM(ulChEaten, -1));

#endif

return 1; // Don't close ChangeSource dialog

}

else {

/* User does not want to correct invalid link. So set

**    the link source but don't validate the link.

*/

OLEDBG_BEGIN2("IOleUILinkContainer::SetLinkSource called\r\n");

hErr = lpOleUILinkCntr->lpVtbl->SetLinkSource(

lpOleUILinkCntr,

lpLI->dwLink,

(LPSTR)lpCshData->szEdit,

(ULONG)lpCshData->nFileLength,

&ulChEaten,

FALSE

);

OLEDBG_END2

lpCshData->fValidLink = FALSE;

}

}

else {     // Link source change validated

lpCshData->fValidLink = TRUE;

}

if (lpCshData->bItemNameStored && lpCshData->bFileNameStored) {

HWND  hListBox = GetDlgItem(lpCshData->lpOfn->hwndOwner, ID_EL_LINKSLISTBOX);

DiffPrefix(

lpLI->lpszDisplayName,

(LPSTR)lpCshData->szEdit,

(char FAR* FAR*)&lpCshData->lpszFrom,

(char FAR* FAR*)&lpCshData->lpszTo

);

/* we keep the strings if there is a difference between the

**    lpszFrom and lpszTo strings AND if the change is only

**    in the file portion otherwise free them and other

**    links won't be compared.

*/

if ( (lstrcmp(lpCshData->lpszTo, lpCshData->lpszFrom)==0)

|| (lstrlen(lpCshData->lpszTo)>lpCshData->nFileLength)) {

if (lpCshData->lpszFrom) {

OleStdFree(lpCshData->lpszFrom);

lpCshData->lpszFrom = NULL;

}

if (lpCshData->lpszTo) {

OleStdFree(lpCshData->lpszTo);

lpCshData->lpszTo = NULL;

}

}

}

// Copy OUT results to original structure

lpCshData->lpOCshData->lpszFrom = lpCshData->lpszFrom;

lpCshData->lpOCshData->lpszTo = lpCshData->lpszTo;

lpCshData->lpOCshData->fValidLink = lpCshData->fValidLink;

SendMessage(hDlg, uMsgEndDialog, 0, 0L);    // do cleanup

return 0;       // Close ChangeSource dialog

}

switch (uMsg) {

case WM_INITDIALOG:

{

LPOPENFILENAME lpOfn = (LPOPENFILENAME)lParam;

LPOLEUICHANGESOURCEHOOKDATA lpOCshData =

(LPOLEUICHANGESOURCEHOOKDATA)lpOfn->lCustData;

gh=GlobalAlloc(

GMEM_MOVEABLE|GMEM_ZEROINIT,sizeof(CHANGESOURCEHOOKDATA));

if (NULL==gh)

{

// Memory allocation error; fail to bring up dialog

PostMessage(hDlg, uMsgEndDialog, 0, 0L);

return 0;

}

lpCshData = GlobalLock(gh);

SetProp(hDlg, STRUCTUREPROP, gh);

lpCshData->lpOCshData = lpOCshData;

lpCshData->lpOfn = lpOfn;

lpLI = lpCshData->lpOCshData->lpLI;

lpCshData->bFileNameStored = TRUE;

lpCshData->bItemNameStored = TRUE;

lpCshData->nFileLength = (int)lpLI->clenFileName;

if (lpLI->lpszDisplayName) {

LSTRCPYN((LPSTR)lpCshData->szFileName, lpLI->lpszDisplayName,

lpCshData->nFileLength + 1);

lstrcpy((LPSTR)lpCshData->szEdit, lpLI->lpszDisplayName);

} else {

lpCshData->szFileName[0] = '\0';

lpCshData->szEdit[0] = '\0';

}

if (lpLI->lpszItemName)

lstrcpy((LPSTR)lpCshData->szItemName, lpLI->lpszItemName);

else

lpCshData->szItemName[0] = '\0';

return 0;

}

case WM_COMMAND:

// User pressed the CANCEL button

if (wParam == IDCANCEL)

{

/* If the focus is in the textbox, and the ESC key was hit, we

will get the WM_COMMAND/IDCANCEL message BEFORE the

EN_KILLFOCUS message.  We clear the MODIFY flag here to

make sure that the EN_KILLFOCUS message doesn't try to

access any structures that are freed by uMsgEndDialog */

SendMessage(GetDlgItem(hDlg, edt1), EM_SETMODIFY, (WPARAM)FALSE, 0L);

if (lpCshData->lpszFrom)

{

OleStdFree(lpCshData->lpszFrom);

lpCshData->lpszFrom = NULL;

}

if (lpCshData->lpszTo)

{

OleStdFree(lpCshData->lpszTo);

lpCshData->lpszTo = NULL;

}

// Copy OUT results to original structure

lpCshData->lpOCshData->lpszFrom = NULL;

lpCshData->lpOCshData->lpszTo = NULL;

lpCshData->lpOCshData->fValidLink = FALSE;

SendMessage(hDlg, uMsgEndDialog, 0, 0L);    // do cleanup

return 0;       // Close ChangeSource dialog

}

#ifdef WIN32

if ((LOWORD(wParam) == lst1) &&

(HIWORD(wParam) == LBN_SELCHANGE)) {

#else

if ((wParam == lst1) &&

(HIWORD(lParam) == LBN_SELCHANGE)) {

#endif

int     nIndex;

HWND    hListBox = (HWND)LOWORD(lParam);

static char szFileNameBuf[OLEUI_CCHPATHMAX];

static char szEditBuf[OLEUI_CCHPATHMAX];

nIndex = (int)SendMessage(hListBox, LB_GETCURSEL, 0, 0L);

SendMessage(hListBox, LB_GETTEXT,

(WPARAM)nIndex, (LPARAM)(LPSTR)szFileNameBuf);

/* need to build the full path filename for the moniker */

AnsiToOem(szFileNameBuf, szFileNameBuf);

_fullpath(szEditBuf, szFileNameBuf, sizeof(szEditBuf));

OemToAnsi(szEditBuf, szEditBuf);

/* convert filename to lower case as it appears in the

**    listbox

*/

AnsiLower((LPSTR)szEditBuf);

LSTRCPYN((LPSTR)lpCshData->szEdit, (LPSTR)szEditBuf,

sizeof(lpCshData->szEdit));

LSTRCPYN((LPSTR)lpCshData->szFileName,

(LPSTR)lpCshData->szEdit,

sizeof(lpCshData->szFileName));

lpCshData->nFileLength = lstrlen((LPSTR)lpCshData->szEdit);

if (lpCshData->bItemNameStored)

lstrcat((LPSTR)lpCshData->szEdit, lpCshData->szItemName);

SetDlgItemText(hDlg, edt1, (LPSTR)lpCshData->szEdit);

lpCshData->nEditLength = lstrlen((LPSTR)lpCshData->szEdit);

lpCshData->bFileNameStored = TRUE;

return 1;

}

#ifdef WIN32

if ((LOWORD(wParam) == lst2) &&

(HIWORD(wParam) == LBN_SELCHANGE)) {

#else

if ((LOWORD(wParam) == lst2) &&

(HIWORD(lParam) == LBN_SELCHANGE)) {

#endif

if (lpCshData->bItemNameStored)

SetDlgItemText(hDlg, edt1, (LPSTR)lpCshData->szItemName);

return 1;

}

#ifdef WIN32

if ((LOWORD(wParam) == cmb2) &&

(HIWORD(wParam) == CBN_SELCHANGE)) {

#else

if ((LOWORD(wParam) == cmb2) &&

(HIWORD(lParam) == CBN_SELCHANGE)) {

#endif

if (lpCshData->bItemNameStored)

SetDlgItemText(hDlg, edt1, (LPSTR)lpCshData->szItemName);

return 1;

}

if (LOWORD(wParam) == edt1) {

#ifdef WIN32

HWND hEdit = (HWND)lParam;

#else

HWND hEdit = (HWND)LOWORD(lParam);

#endif

#ifdef WIN32

switch (HIWORD(wParam)) {

#else

switch (HIWORD(lParam)) {

#endif

case EN_SETFOCUS:

#ifdef WIN32

SendMessage(hEdit, EM_SETSEL, 0, lpCshData->nFileLength);

#else

SendMessage(hEdit, EM_SETSEL, 0,

MAKELPARAM(0, lpCshData->nFileLength));

#endif

return 1;

case EN_KILLFOCUS:

if (SendMessage(hEdit, EM_GETMODIFY, 0, 0L)) {

char szTmp[OLEUI_CCHPATHMAX];

int nItemLength = lstrlen((LPSTR)lpCshData->szItemName);

*(LPWORD)lpCshData->szEdit = sizeof(lpCshData->szEdit) - 1;

lpCshData->nEditLength = (int)SendMessage(hEdit,

EM_GETLINE, 0, (LPARAM)(LPSTR)lpCshData->szEdit);

lpCshData->szEdit[lpCshData->nEditLength] = '\0';

LSTRCPYN((LPSTR)szTmp, (LPSTR)lpCshData->szEdit,

lpCshData->nFileLength + 1);

if (lpCshData->bFileNameStored &&

!lstrcmp((LPSTR)lpCshData->szFileName, (LPSTR)szTmp)) {

lstrcpy((LPSTR)lpCshData->szItemName,

(LPSTR)lpCshData->szEdit + lpCshData->nFileLength);

lpCshData->bItemNameStored = TRUE;

}

else if (lpCshData->bItemNameStored &&

!lstrcmp((LPSTR)lpCshData->szItemName,

(LPSTR)lpCshData->szEdit +

lpCshData->nEditLength -

nItemLength)) {

if (lpCshData->nEditLength==nItemLength) {

lpCshData->bFileNameStored = FALSE;

} else {

LSTRCPYN((LPSTR)lpCshData->szFileName,

(LPSTR)lpCshData->szEdit,

lpCshData->nEditLength -

nItemLength+1);

lpCshData->bFileNameStored = TRUE;

}

}

else {

lpCshData->bItemNameStored = FALSE;

lpCshData->bFileNameStored = FALSE;

}

SendMessage(hEdit, EM_SETMODIFY, FALSE, 0L);

}

return 0;

}

}

return 0;

default:

return 0;

}

}

/*

* ChangeSource

*

* Purpose:

*  Displays the standard GetOpenFileName dialog with a customized template and

*  hook.

*

* Parameters:

*  hWndOwner       HWND owning the dialog

*  lpszFile        LPSTR specifying the initial file.  If there is no

*                  initial file the first character of this string should

*                  be a null.

*  cchFile         UINT length of pszFile

*  iFilterString   UINT index into the stringtable for the filter string.

*  lpfnBrowseHook  COMMDLGHOOKPROC hook to process link source information when user

*                                  presses OK

*  lpCshData       LPCHANGESOURCEHOOKDATA custom data that is accessible to the hook

*

* Return Value:

*  BOOL            TRUE if the user selected a file and pressed OK.

*                  FALSE otherwise, such as on pressing Cancel.

*/

BOOL WINAPI ChangeSource(

HWND hWndOwner,

LPSTR lpszFile,

UINT cchFile,

UINT iFilterString,

COMMDLGHOOKPROC lpfnBrowseHook,

LPOLEUICHANGESOURCEHOOKDATA lpCshData

)

{

UINT            cch;

char            szFilters[OLEUI_CCHPATHMAX];

char            szDir[OLEUI_CCHPATHMAX];

char            szTitle[OLEUI_CCHPATHMAX];

OPENFILENAME    ofn;

BOOL            fStatus;

LPSTR           lpszFileBuffer;

#if !defined( LINK_COMMDLG )

   HINSTANCE hinstCommDlg = NULL;

   typedef BOOL (WINAPI* LPFNGETOPENFILENAME) (OPENFILENAME FAR*);

   LPFNGETOPENFILENAME lpfnGetOpenFileName;

#endif

if (NULL==lpszFile || 0==cchFile)

return FALSE;

lpszFileBuffer = (LPSTR)OleStdMalloc(cchFile * sizeof(char));

if (!lpszFileBuffer)

return FALSE;

lstrcpy(lpszFileBuffer, lpszFile);

// Get filters

if (0!=iFilterString)

cch = LoadString(ghInst, iFilterString, (LPSTR)szFilters,

sizeof(szFilters));

else

{

szFilters[0]=0;

cch=1;

}

if (0==cch) {

fStatus = FALSE;

goto cleanup;

}

ReplaceCharWithNull(szFilters, szFilters[cch-1]);

LSTRCPYN((LPSTR)szDir, lpszFile, sizeof(szDir));

for (cch = lstrlen((LPSTR)szDir) - 1; cch >= 0; cch--)

{

if ((szDir[cch]=='\\') || (szDir[cch]==':') || (szDir[cch]=='/'))

break;

}

if (cch < 0)

cch = 0;

szDir[cch] = '\0';

LoadString(ghInst, (UINT)IDS_CHANGESOURCE, (LPSTR)szTitle, sizeof(szTitle));

_fmemset((LPOPENFILENAME)&ofn, 0, sizeof(ofn));

ofn.lStructSize     = sizeof(ofn);

ofn.hwndOwner       = hWndOwner;

ofn.lpstrFile       = lpszFileBuffer;

ofn.nMaxFile        = cchFile;

ofn.lpstrFilter     = (LPSTR)szFilters;

ofn.nFilterIndex    = 1;

ofn.lpstrTitle      = (LPSTR)szTitle;

ofn.lpstrInitialDir = (LPSTR)szDir;

ofn.lpTemplateName  = MAKEINTRESOURCE(IDD_FILEOPEN);

ofn.lpfnHook        = lpfnBrowseHook;

ofn.hInstance       = ghInst;

ofn.lCustData       = (LPARAM)lpCshData;

ofn.Flags           = OFN_NOVALIDATE | OFN_HIDEREADONLY |

OFN_ENABLETEMPLATE | OFN_ENABLEHOOK;

   // Only show help button if edit links dialog shows it.

   if (lpCshData->lpEL->lpOEL->dwFlags & ELF_SHOWHELP)

 ofn.Flags |= OFN_SHOWHELP;

#if !defined( LINK_COMMDLG )

// Load the COMMDLG.DLL library module

hinstCommDlg = LoadLibrary("COMMDLG.DLL");

if ((DWORD)hinstCommDlg <= HINSTANCE_ERROR)   /* load failed */

return FALSE;

// Retrieve the address of GetOpenFileName function

lpfnGetOpenFileName = (LPFNGETOPENFILENAME)

GetProcAddress(hinstCommDlg, "GetOpenFileName");

if (lpfnGetOpenFileName == NULL)

{

FreeLibrary(hinstCommDlg);

return FALSE;

}

fStatus = (*lpfnGetOpenFileName) ((LPOPENFILENAME)&ofn);

FreeLibrary(hinstCommDlg);

#else

fStatus = GetOpenFileName((LPOPENFILENAME)&ofn);

#endif

cleanup:

OleStdFree((LPVOID)lpszFileBuffer);

return fStatus;

}

/*

* Container_ChangeSource

*

* Purpose:

*  Tunnel to File Open type dlg and allow user to select new file

*  for file based monikers, OR to change the whole moniker to what

*  the user types into the editable field.

*

* Parameters:

*  hDlg            HWND of the dialog

*  LPEDITLINKS     Pointer to EditLinks structure (contains all nec.

*              info)

*

* Return Value:

*  BOOL          for now, because we are not using any ole functions

*                to return an HRESULT.

*  HRESULT       HRESULT value indicating success or failure of

*              changing the moniker value

*/

BOOL Container_ChangeSource(HWND hDlg, LPEDITLINKS lpEL)

{

UINT        uRet;

int         cSelItems;

int FAR*    rgIndex;

int         i = 0;

LPLINKINFO  lpLI;

HWND        hListBox = GetDlgItem(hDlg, ID_EL_LINKSLISTBOX);

LPOLEUILINKCONTAINER lpOleUILinkCntr = lpEL->lpOEL->lpOleUILinkContainer;

OLEUICHANGESOURCEHOOKDATA  cshData;     // Data that needs to be accessed

// by the ChangeSource dialog hook

BOOL fUpdated = FALSE;

cSelItems = GetSelectedItems(hListBox, &rgIndex);

if (cSelItems < 0)

return FALSE;

if (!cSelItems)

return TRUE;

if (!lpEL->fClose) {

SetWindowText(GetDlgItem(hDlg, IDCANCEL), (LPSTR)lpEL->szClose);

lpEL->fClose = TRUE;

}

_fmemset((LPOLEUICHANGESOURCEHOOKDATA)&cshData, 0, sizeof(cshData));

cshData.cbStruct=sizeof(cshData);

cshData.hWndOwner=hDlg;

cshData.lpEL = (LPEDITLINKS)lpEL;

cshData.lpszFrom = NULL;

cshData.lpszTo = NULL;

for (i = cSelItems-1; i >=0; i--) {

SendMessage(hListBox, LB_GETTEXT, rgIndex[i],

(LPARAM) (LPLINKINFO FAR*) &lpLI);

uRet = UStandardHook(lpEL, hDlg, uMsgBrowse,

OLEUI_CCHPATHMAX, (LONG)(LPSTR)lpLI->lpszDisplayName);

if (!uRet) {

cshData.lpLI = lpLI;

/* Bring up the ChangeSource dialog after hooking it so

**    that the user specified link source is verified

**    when OK is pressed.

*/

uRet = (UINT)ChangeSource(hDlg, lpLI->lpszDisplayName,

OLEUI_CCHPATHMAX, (UINT)IDS_FILTERS, ChangeSourceHook,

&cshData);

}

/* If Cancel is pressed in any ChangeSource dialog, stop

**    the ChangeSource processing for all links.

*/

if (!uRet) {

if (rgIndex)

OleStdFree(rgIndex);

return TRUE;

}

if (cshData.lpszFrom && cshData.lpszTo &&

(CFindLinks(hListBox, cshData.lpszFrom) > 1)) {

fUpdated = FChangeAllLinks(hListBox, lpOleUILinkCntr,

cshData.lpszFrom, cshData.lpszTo);

}

if (cshData.lpszFrom)

OleStdFree(cshData.lpszFrom);

if (cshData.lpszTo)

OleStdFree(cshData.lpszTo);

/* If the link was not updated by FChangeAllLinks, then change it now */

if (!fUpdated)

UpdateLinkLBItem(hListBox, rgIndex[i], lpEL, TRUE);

} // end FOR

if (rgIndex)

OleStdFree(rgIndex);

return TRUE;

}

/*

* Container_AutomaticManual

*

* Purpose:

*   To change the selected moniker to manual or automatic update.

*

* Parameters:

*  hDlg            HWND of the dialog

*  FAutoMan        Flag indicating AUTO (TRUE/1) or MANUAL(FALSE/0)

*  LPEDITLINKS     Pointer to EditLinks structure (contains all nec.

*              info)

*            * this may change - don't know how the linked list

*            * of multi-selected items will work.

* Return Value:

*  HRESULT       HRESULT value indicating success or failure of

*              changing the moniker value

*/

HRESULT Container_AutomaticManual(HWND hDlg, BOOL fAutoMan, LPEDITLINKS lpEL)

{

HRESULT hErr = NOERROR;

int cSelItems;

int FAR* rgIndex;

int i = 0;

LPLINKINFO  lpLI;

LPOLEUILINKCONTAINER lpOleUILinkCntr = lpEL->lpOEL->lpOleUILinkContainer;

HWND        hListBox = GetDlgItem(hDlg, ID_EL_LINKSLISTBOX);

BOOL        bUpdate = FALSE;

OleDbgAssert(lpOleUILinkCntr);

/* Change so looks at flag in structure.  Only update those that

need to be updated.  Make sure to change flag if status changes.

*/

cSelItems = GetSelectedItems(hListBox, &rgIndex);

if (cSelItems < 0)

return ResultFromScode(E_FAIL);

if (!cSelItems)

return NOERROR;

if (!lpEL->fClose)

SetDlgItemText(hDlg, IDCANCEL, (LPSTR)lpEL->szClose);

for (i = 0; i < cSelItems; i++) {

SendMessage(hListBox, LB_GETTEXT, (WPARAM)rgIndex[i],

(LPARAM) (LPLINKINFO FAR*) &lpLI);

if (fAutoMan) {   // If switching to AUTOMATIC

if (!lpLI->fIsAuto) {   // Only change MANUAL links

OLEDBG_BEGIN2("IOleUILinkContainer::SetLinkUpdateOptions called\r\n");

hErr=lpOleUILinkCntr->lpVtbl->SetLinkUpdateOptions(

lpOleUILinkCntr,

lpLI->dwLink,

OLEUPDATE_ALWAYS

);

OLEDBG_END2

lpLI->fIsAuto=TRUE;

lpLI->fIsMarked = TRUE;

bUpdate = TRUE;

}

}

else {   // If switching to MANUAL

if (lpLI->fIsAuto) {  // Only do AUTOMATIC Links

OLEDBG_BEGIN2("IOleUILinkContainer::SetLinkUpdateOptions called\r\n");

hErr=lpOleUILinkCntr->lpVtbl->SetLinkUpdateOptions(

lpOleUILinkCntr,

lpLI->dwLink,

OLEUPDATE_ONCALL

);

OLEDBG_END2

lpLI->fIsAuto = FALSE;

lpLI->fIsMarked = TRUE;

bUpdate = TRUE;

}

}

if (hErr != NOERROR) {

OleDbgOutHResult("WARNING: IOleUILinkContainer::SetLinkUpdateOptions returned",hErr);

break;

}

}

if (bUpdate)

RefreshLinkLB(hListBox, lpOleUILinkCntr);

if (rgIndex)

OleStdFree((LPVOID)rgIndex);

return hErr;

}

HRESULT CancelLink(HWND hDlg, LPEDITLINKS lpEL)

{

HRESULT hErr;

LPMONIKER lpmk;

int cSelItems;

int FAR* rgIndex;

int i = 0;

LPLINKINFO  lpLI;

LPOLEUILINKCONTAINER lpOleUILinkCntr = lpEL->lpOEL->lpOleUILinkContainer;

HWND        hListBox = GetDlgItem(hDlg, ID_EL_LINKSLISTBOX);

BOOL        bUpdate = FALSE;

OleDbgAssert(lpOleUILinkCntr);

lpmk = NULL;

cSelItems = GetSelectedItems(hListBox, &rgIndex);

if (cSelItems < 0)

return ResultFromScode(E_FAIL);

if (!cSelItems)

return NOERROR;

if (!lpEL->fClose) {

SetWindowText(GetDlgItem(hDlg, IDCANCEL), (LPSTR)lpEL->szClose);

lpEL->fClose = TRUE;

}

for (i = (cSelItems - 1); i >= 0; i--) {

SendMessage(hListBox, LB_GETTEXT, (WPARAM)rgIndex[i],

(LPARAM)(LPLINKINFO FAR*) &lpLI);

OLEDBG_BEGIN2("IOleUILinkContainer::CancelLink called\r\n");

hErr = lpOleUILinkCntr->lpVtbl->CancelLink(

lpOleUILinkCntr,

lpLI->dwLink

);

OLEDBG_END2

if (hErr != NOERROR) {

OleDbgOutHResult("WARNING: IOleUILinkContainer::CancelLink returned",hErr);

lpLI->fIsMarked = TRUE;

bUpdate = TRUE;

}

else

// Delete links that we make null from listbox

SendMessage(hListBox, LB_DELETESTRING, (WPARAM) rgIndex[i], 0L);

}

if (bUpdate)

RefreshLinkLB(hListBox, lpOleUILinkCntr);

SetFocus(hListBox);

if (rgIndex)

OleStdFree((LPVOID)rgIndex);

return hErr;

}

/*

 * Container_UpdateNow

 *

 * Purpose:

 *   Immediately force an update for all (manual) links

 *

 * Parameters:

 *  hDlg            HWND of the dialog

 *  LPEDITLINKS     Pointer to EditLinks structure (contains all nec. info)

 *            * this may change - don't know how the linked list

 *            * of multi-selected items will work.

 * Return Value:

 *  HRESULT       HRESULT value indicating success or failure of

 *              changing the moniker value

 */

HRESULT Container_UpdateNow(HWND hDlg, LPEDITLINKS lpEL)

{

HRESULT         hErr;

LPLINKINFO      lpLI;

int cSelItems;

int FAR* rgIndex;

int i = 0;

LPOLEUILINKCONTAINER lpOleUILinkCntr = lpEL->lpOEL->lpOleUILinkContainer;

HWND        hListBox = GetDlgItem(hDlg, ID_EL_LINKSLISTBOX);

BOOL        bUpdate = FALSE;

OleDbgAssert(lpOleUILinkCntr);

cSelItems = GetSelectedItems(hListBox, &rgIndex);

if (cSelItems < 0)

return ResultFromScode(E_FAIL);

if (!cSelItems)

return NOERROR;

if (!lpEL->fClose) {

SetWindowText(GetDlgItem(hDlg, IDCANCEL), (LPSTR)lpEL->szClose);

lpEL->fClose = TRUE;

}

for (i = 0; i < cSelItems; i++) {

SendMessage(hListBox, LB_GETTEXT,

(WPARAM)rgIndex[i], (LPARAM)(LPLINKINFO FAR*)&lpLI);

OLEDBG_BEGIN2("IOleUILinkContainer::UpdateLink called\r\n");

hErr = lpOleUILinkCntr->lpVtbl->UpdateLink(

lpOleUILinkCntr,

lpLI->dwLink,

TRUE,

FALSE

);

OLEDBG_END2

bUpdate = TRUE;

lpLI->fIsMarked = TRUE;

if (hErr != NOERROR) {

OleDbgOutHResult("WARNING: IOleUILinkContainer::UpdateLink returned",hErr);

break;

}

}

if (bUpdate)

RefreshLinkLB(hListBox, lpOleUILinkCntr);

if (rgIndex)

OleStdFree((LPVOID)rgIndex);

return hErr;

}

/*

 * Container_OpenSource

 *

 * Purpose:

 *   Immediately force an update for all (manual) links

 *

 * Parameters:

 *  hDlg            HWND of the dialog

 *  LPEDITLINKS     Pointer to EditLinks structure (contains all nec.

 *              info)

 *

 * Return Value:

 *  HRESULT       HRESULT value indicating success or failure of

 *              changing the moniker value

 */

HRESULT Container_OpenSource(HWND hDlg, LPEDITLINKS lpEL)

{

HRESULT         hErr;

int             cSelItems;

int FAR*        rgIndex;

LPLINKINFO      lpLI;

RECT            rcPosRect;

LPOLEUILINKCONTAINER lpOleUILinkCntr = lpEL->lpOEL->lpOleUILinkContainer;

HWND            hListBox = GetDlgItem(hDlg, ID_EL_LINKSLISTBOX);

OleDbgAssert(lpOleUILinkCntr);

rcPosRect.top = 0;

rcPosRect.left = 0;

rcPosRect.right = 0;

rcPosRect.bottom = 0;

cSelItems = GetSelectedItems(hListBox, &rgIndex);

if (cSelItems < 0)

return ResultFromScode(E_FAIL);

if (cSelItems != 1)     // can't open source for multiple items

return NOERROR;

if (!lpEL->fClose) {

SetWindowText(GetDlgItem(hDlg, IDCANCEL), (LPSTR)lpEL->szClose);

lpEL->fClose = TRUE;

}

SendMessage(hListBox, LB_GETTEXT, (WPARAM)rgIndex[0],

(LPARAM)(LPLINKINFO FAR*)&lpLI);

OLEDBG_BEGIN2("IOleUILinkContainer::OpenLinkSource called\r\n");

hErr = lpOleUILinkCntr->lpVtbl->OpenLinkSource(

lpOleUILinkCntr,

lpLI->dwLink

);

OLEDBG_END2

UpdateLinkLBItem(hListBox, rgIndex[0], lpEL, TRUE);

if (hErr != NOERROR)

OleDbgOutHResult("WARNING: IOleUILinkContainer::OpenLinkSource returned",hErr);

if (rgIndex)

OleStdFree((LPVOID)rgIndex);

return hErr;

}

/* AddLinkLBItem

** -------------

**

**    Add the item pointed to by lpLI to the Link ListBox and return

**    the index of it in the ListBox

*/

int AddLinkLBItem(HWND hListBox, LPOLEUILINKCONTAINER lpOleUILinkCntr, LPLINKINFO lpLI, BOOL fGetSelected, int nIndex)

{

HRESULT hErr;

DWORD dwUpdateOpt;

OleDbgAssert(lpOleUILinkCntr && hListBox && lpLI);

lpLI->fDontFree = FALSE;

OLEDBG_BEGIN2("IOleUILinkContainer::GetLinkSource called\r\n");

hErr = lpOleUILinkCntr->lpVtbl->GetLinkSource(

lpOleUILinkCntr,

lpLI->dwLink,

(LPSTR FAR*)&lpLI->lpszDisplayName,

(ULONG FAR*)&lpLI->clenFileName,

(LPSTR FAR*)&lpLI->lpszFullLinkType,

(LPSTR FAR*)&lpLI->lpszShortLinkType,

(BOOL FAR*)&lpLI->fSourceAvailable,

fGetSelected ? (BOOL FAR*)&lpLI->fIsSelected : NULL

);

OLEDBG_END2

if (hErr != NOERROR) {

OleDbgOutHResult("WARNING: IOleUILinkContainer::GetLinkSource returned",hErr);

PopupMessage(hListBox, (UINT)IDS_LINKS, (UINT)IDS_ERR_GETLINKSOURCE,

MB_ICONEXCLAMATION | MB_OK);

goto cleanup;

}

OLEDBG_BEGIN2("IOleUILinkContainer::GetLinkUpdateOptions called\r\n");

hErr=lpOleUILinkCntr->lpVtbl->GetLinkUpdateOptions(

lpOleUILinkCntr,

lpLI->dwLink,

(LPDWORD)&dwUpdateOpt

);

OLEDBG_END2

if (hErr != NOERROR) {

OleDbgOutHResult("WARNING: IOleUILinkContainer::GetLinkUpdateOptions returned",hErr);

PopupMessage(hListBox, (UINT)IDS_LINKS, (UINT)IDS_ERR_GETLINKUPDATEOPTIONS,

MB_ICONEXCLAMATION | MB_OK);

goto cleanup;

}

if (lpLI->fSourceAvailable) {

if (dwUpdateOpt == OLEUPDATE_ALWAYS) {

lpLI->fIsAuto = TRUE;

LoadString(ghInst, (UINT)IDS_LINK_AUTO, lpLI->lpszAMX,

(int)OleStdGetSize((LPVOID)lpLI->lpszAMX));

}

else {

lpLI->fIsAuto = FALSE;

LoadString(ghInst, (UINT)IDS_LINK_MANUAL, lpLI->lpszAMX,

(int)OleStdGetSize((LPVOID)lpLI->lpszAMX));

}

}

else

LoadString(ghInst, (UINT)IDS_LINK_UNKNOWN, lpLI->lpszAMX,

(int)OleStdGetSize((LPVOID)lpLI->lpszAMX));

BreakString(lpLI);

nIndex = (int)SendMessage(hListBox,

(nIndex < 0 ? LB_ADDSTRING : LB_INSERTSTRING),

(WPARAM)(nIndex < 0 ? 0 : nIndex),

(LPARAM)(DWORD)lpLI);

if (nIndex == LB_ERR) {

PopupMessage(hListBox, (UINT)IDS_LINKS, (UINT)IDS_ERR_ADDSTRING,

MB_ICONEXCLAMATION | MB_OK);

goto cleanup;

}

return nIndex;

cleanup:

if (lpLI->lpszDisplayName)

OleStdFree((LPVOID)lpLI->lpszDisplayName);

if (lpLI->lpszShortLinkType)

OleStdFree((LPVOID)lpLI->lpszShortLinkType);

if (lpLI->lpszFullLinkType)

OleStdFree((LPVOID)lpLI->lpszFullLinkType);

return -1;

}

/* BreakString

 * -----------

 *

 *  Purpose:

 *      Break the lpszDisplayName into various parts

 *

 *  Parameters:

 *      lpLI            pointer to LINKINFO structure

 *

 *  Returns:

 *

 */

VOID BreakString(LPLINKINFO lpLI)

{

LPSTR lpsz;

if (!lpLI->clenFileName ||

(lstrlen(lpLI->lpszDisplayName)==(int)lpLI->clenFileName)) {

lpLI->lpszItemName = NULL;

}

else {

lpLI->lpszItemName = lpLI->lpszDisplayName + lpLI->clenFileName;

}

// search from last character of filename

lpsz = lpLI->lpszDisplayName + lstrlen(lpLI->lpszDisplayName);

while (lpsz > lpLI->lpszDisplayName) {

lpsz = AnsiPrev(lpLI->lpszDisplayName, lpsz);

if ((*lpsz == '\\') || (*lpsz == '/') || (*lpsz == ':'))

break;

}

if (lpsz == lpLI->lpszDisplayName)

lpLI->lpszShortFileName = lpsz;

else

lpLI->lpszShortFileName = AnsiNext(lpsz);

}

/* GetSelectedItems

 * ----------------

 *

 *  Purpose:

 *      Retrieve the indices of the selected items in the listbox

 *      Note that *lprgIndex needed to be free after using the function

 *

 *  Parameters:

 *      hListBox        window handle of listbox

 *      lprgIndex       pointer to an integer array to receive the indices

 *                      must be freed afterwards

 *

 *  Returns:

 *      number of indices retrieved, -1 if error

 */

int GetSelectedItems(HWND hListBox, int FAR* FAR* lprgIndex)

{

DWORD cSelItems;

DWORD cCheckItems;

*lprgIndex = NULL;

cSelItems = SendMessage(hListBox, LB_GETSELCOUNT, 0, 0L);

if (cSelItems < 0)      // error

return (int)cSelItems;

if (!cSelItems)

return 0;

*lprgIndex = (int FAR*)OleStdMalloc((int)cSelItems * sizeof(int));

cCheckItems = SendMessage(hListBox, LB_GETSELITEMS,

(WPARAM) cSelItems, (LPARAM) (int FAR*) *lprgIndex);

if (cCheckItems == cSelItems)

return (int)cSelItems;

else {

if (*lprgIndex)

OleStdFree((LPVOID)*lprgIndex);

*lprgIndex = NULL;

return 0;

}

}

/* InitControls

 * ------------

 *

 *  Purpose:

 *      Initialize the state of the Auto/Manual button, Link source/type

 *      static field, etc in the dialogs according to the selection in the

 *      listbox

 *

 *  Parameters:

 *      hDlg        handle to the dialog window

 */

VOID InitControls(HWND hDlg, LPEDITLINKS lpEL)

{

int         cSelItems;

HWND        hListBox;

int         i;

int FAR*    rgIndex;

LPLINKINFO  lpLI;

LPSTR       lpszType = NULL;

LPSTR       lpszSource = NULL;

int         cAuto = 0;

int         cManual = 0;

BOOL        bSameType = TRUE;

BOOL        bSameSource = TRUE;

BOOL        bNoSource = FALSE;

char        sz[OLEUI_CCHPATHMAX];

LPSTR       lpsz;

hListBox = GetDlgItem(hDlg, ID_EL_LINKSLISTBOX);

cSelItems = GetSelectedItems(hListBox, &rgIndex);

if (cSelItems < 0)

return;

if (lpEL && !(lpEL->lpOEL->dwFlags & ELF_DISABLECANCELLINK))

EnableWindow(GetDlgItem(hDlg, ID_EL_CANCELLINK), (BOOL)cSelItems);

if (lpEL && !(lpEL->lpOEL->dwFlags & ELF_DISABLEOPENSOURCE))

EnableWindow(GetDlgItem(hDlg, ID_EL_OPENSOURCE), cSelItems == 1);

if (lpEL && !(lpEL->lpOEL->dwFlags & ELF_DISABLECHANGESOURCE))

EnableWindow(GetDlgItem(hDlg, ID_EL_CHANGESOURCE), cSelItems == 1);

if (lpEL && !(lpEL->lpOEL->dwFlags & ELF_DISABLEUPDATENOW))

EnableWindow(GetDlgItem(hDlg, ID_EL_UPDATENOW), (BOOL)cSelItems);

for (i = 0; i < cSelItems; i++) {

SendDlgItemMessage(

hDlg,

ID_EL_LINKSLISTBOX,

LB_GETTEXT,

(WPARAM)rgIndex[i],

(LPARAM)(LPLINKINFO FAR*)&lpLI);

if (lpszSource && lpLI->lpszDisplayName) {

if (bSameSource && lstrcmp(lpszSource, lpLI->lpszDisplayName)) {

bSameSource = FALSE;

}

}

else

lpszSource = lpLI->lpszDisplayName;

if (lpszType && lpLI->lpszFullLinkType) {

if (bSameType && lstrcmp(lpszType, lpLI->lpszFullLinkType)) {

bSameType = FALSE;

}

}

else

lpszType = lpLI->lpszFullLinkType;

if (lpLI->fIsAuto)

cAuto++;

else

cManual++;

if (!lpLI->fSourceAvailable)

bNoSource = TRUE;

}

EnableWindow(GetDlgItem(hDlg, ID_EL_AUTOMATIC), (BOOL)cSelItems && !bNoSource);

EnableWindow(GetDlgItem(hDlg, ID_EL_MANUAL), (BOOL)cSelItems && !bNoSource);

CheckDlgButton(hDlg, ID_EL_AUTOMATIC, !bNoSource && cAuto && !cManual);

CheckDlgButton(hDlg, ID_EL_MANUAL, bNoSource || (!cAuto && cManual));

/* fill full source in static text box

**    below list

*/

if (!bSameSource || !lpszSource)

lpszSource = szNULL;

lstrcpy((LPSTR)sz, lpszSource);

lpsz = ChopText(GetDlgItem(hDlg, ID_EL_LINKSOURCE), 0, sz);

SetDlgItemText(hDlg, ID_EL_LINKSOURCE, lpsz);

/* fill full link type name in static

**    "type" text box

*/

if (!bSameType || !lpszType)

lpszType = szNULL;

SetDlgItemText(hDlg, ID_EL_LINKTYPE, lpszType);

if (rgIndex)

OleStdFree((LPVOID)rgIndex);

}

/* UpdateLinkLBItem

 * -----------------

 *

 *  Purpose:

 *      Update the linkinfo struct in the listbox to reflect the changes

 *      made by the last operation. It is done simply by removing the item

 *      from the listbox and add it back.

 *

 *  Parameters:

 *      hListBox        handle of listbox

 *      nIndex          index of listbox item

 *      lpEL            pointer to editlinks structure

 *      bSelect         select the item or not after update

 */

VOID UpdateLinkLBItem(HWND hListBox, int nIndex, LPEDITLINKS lpEL, BOOL bSelect)

{

LPLINKINFO lpLI;

DWORD       dwErr;

LPOLEUILINKCONTAINER    lpOleUILinkCntr;

if (!hListBox || (nIndex < 0) || !lpEL)

return;

lpOleUILinkCntr = lpEL->lpOEL->lpOleUILinkContainer;

dwErr = SendMessage(hListBox, LB_GETTEXT, nIndex,

(LPARAM)(LPLINKINFO FAR*) &lpLI);

if ((dwErr == LB_ERR) || !lpLI)

return;

/* Don't free the data associated with this listbox item

**    because we are going to reuse the allocated space for

**    the modified link. WM_DELETEITEM processing in the

**    dialog checks this flag before deleting data

**    associcated with list item.

*/

lpLI->fDontFree = TRUE;

SendMessage(hListBox, LB_DELETESTRING, nIndex, 0L);

nIndex = AddLinkLBItem(hListBox, lpOleUILinkCntr, lpLI, FALSE, nIndex);

if (bSelect) {

SendMessage(hListBox, LB_SETSEL, (WPARAM)TRUE, MAKELPARAM(nIndex, 0));

SendMessage(hListBox, LB_SETCARETINDEX, (WPARAM)nIndex, MAKELPARAM(TRUE, 0));

}

}

/* DiffPrefix

 * ----------

 *

 *  Purpose:

 *      Compare (case-insensitive) two strings and return the prefixes of the

 *      the strings formed by removing the common suffix string from them.

 *      Integrity of tokens (directory name, filename and object names) are

 *      preserved. Note that the prefixes are converted to upper case

 *      characters.

 *

 *  Parameters:

 *      lpsz1           string 1

 *      lpsz2           string 2

 *      lplpszPrefix1   prefix of string 1

 *      lplpszPrefix2   prefix of string 2

 *

 *  Returns:

 *

 */

VOID DiffPrefix(LPCSTR lpsz1, LPCSTR lpsz2, char FAR* FAR* lplpszPrefix1, char FAR* FAR* lplpszPrefix2)

{

LPSTR   lpstr1;

LPSTR   lpstr2;

OleDbgAssert(lpsz1 && lpsz2 && *lpsz1 && *lpsz2 && lplpszPrefix1 &&

lplpszPrefix2);

*lplpszPrefix1 = NULL;

*lplpszPrefix2 = NULL;

*lplpszPrefix1 = OleStdMalloc((lstrlen(lpsz1)+1) * sizeof(BYTE));

if (!*lplpszPrefix1)

return;

*lplpszPrefix2 = OleStdMalloc((lstrlen(lpsz2)+1) * sizeof(BYTE));

if (!*lplpszPrefix2) {

OleStdFree(*lplpszPrefix1);

*lplpszPrefix1 = NULL;

return;

}

lstrcpy(*lplpszPrefix1, lpsz1);

lstrcpy(*lplpszPrefix2, lpsz2);

//  AnsiLower(*lplpszPrefix1);

//  AnsiLower(*lplpszPrefix2);

lpstr1 = *lplpszPrefix1 + lstrlen(*lplpszPrefix1);

lpstr2 = *lplpszPrefix2 + lstrlen(*lplpszPrefix2);

while ((lpstr1>*lplpszPrefix1) && (lpstr2>*lplpszPrefix2)) {

lpstr1 = AnsiPrev(*lplpszPrefix1, lpstr1);

lpstr2 = AnsiPrev(*lplpszPrefix2, lpstr2);

if (*lpstr1 != *lpstr2) {

lpstr1 = AnsiNext(lpstr1);

lpstr2 = AnsiNext(lpstr2);

break;

}

}

for (; *lpstr1 && *lpstr1!='\\' && *lpstr1!='!'; lpstr1=AnsiNext(lpstr1));

for (; *lpstr2 && *lpstr2!='\\' && *lpstr2!='!'; lpstr2=AnsiNext(lpstr2));

*lpstr1 = '\0';

*lpstr2 = '\0';

}

/* PopupMessage

 * ------------

 *

 *  Purpose:

 *      Popup s messagebox and get some response from the user. It is the same

 *      as MessageBox() except that the title and message string are loaded

 *      from the resource file.

 *

 *  Parameters:

 *      hwndParent      parent window of message box

 *      idTitle         id of title string

 *      idMessage       id of message string

 *      fuStyle         style of message box

 */

int PopupMessage(HWND hwndParent, UINT idTitle, UINT idMessage, UINT fuStyle)

{

char szTitle[256];

char szMsg[256];

LoadString(ghInst, idTitle, (LPSTR)szTitle, sizeof(szTitle));

LoadString(ghInst, idMessage, (LPSTR)szMsg, sizeof(szMsg));

return MessageBox(hwndParent, szMsg, szTitle, fuStyle);

}

/* CFindLinks

 * --------------

 *

 *  Purpose:

 *      Count all the links in the listbox starting

 *      with lpsz.

 *

 *  Parameters:

 *      hListBox        window handle of

 *      lpOleUILinkCntr pointer to OleUI Link Container

 *      lpszFrom        prefix for matching

 *      lpszTo          prefix to substitution

 *

 *  Returns: TRUE if we attempted to update links

 */

BOOL CFindLinks(HWND hListBox, LPSTR lpsz)

{

int     cItems;

int     nIndex;

int     cch;

LPLINKINFO  lpLI;

LPSTR   szTmp[OLEUI_CCHPATHMAX];

int     cFound;

cch = lstrlen(lpsz);

cItems = (int)SendMessage(hListBox, LB_GETCOUNT, 0, 0L);

cFound = 0;

for (nIndex=0; nIndex<cItems; nIndex++) {

SendMessage(hListBox, LB_GETTEXT, nIndex,

(LPARAM)(LPLINKINFO FAR*)&lpLI);

/* if the corresponding position for the end of lpszFrom in the

**    display name is not a separator. We stop comparing this

**    link.

*/

if (!*(lpLI->lpszDisplayName + cch) ||

(*(lpLI->lpszDisplayName + cch) == '\\') ||

(*(lpLI->lpszDisplayName + cch) == '!')) {

lstrcpyn((LPSTR)szTmp, lpLI->lpszDisplayName, cch + 1);

if (!lstrcmp((LPSTR)szTmp, lpsz)) {

++cFound;

}

}

}

return(cFound);

}

/* FChangeAllLinks

 * --------------

 *

 *  Purpose:

 *      Enumerate all the links in the listbox and change those starting

 *      with lpszFrom to lpszTo.

 *

 *  Parameters:

 *      hListBox        window handle of

 *      lpOleUILinkCntr pointer to OleUI Link Container

 *      lpszFrom        prefix for matching

 *      lpszTo          prefix to substitution

 *

 *  Returns: TRUE if we attempted to update links

 */

BOOL FChangeAllLinks(HWND hListBox, LPOLEUILINKCONTAINER lpOleUILinkCntr, LPSTR lpszFrom, LPSTR lpszTo)

{

int     cItems;

int     nIndex;

int     cFrom;

LPLINKINFO  lpLI;

LPSTR   szTmp[OLEUI_CCHPATHMAX];

BOOL    bFound;

cFrom = lstrlen(lpszFrom);

cItems = (int)SendMessage(hListBox, LB_GETCOUNT, 0, 0L);

OleDbgAssert(cItems >= 0);

bFound = FALSE;

OleDbgPrint(3, "From : ", lpszFrom, 0);

OleDbgPrint(3, "", "\r\n", 0);

OleDbgPrint(3, "To   : ", lpszTo, 0);

OleDbgPrint(3, "", "\r\n", 0);

for (nIndex=0; nIndex<cItems; nIndex++) {

SendMessage(hListBox, LB_GETTEXT, nIndex,

(LPARAM)(LPLINKINFO FAR*)&lpLI);

// unmark the item

lpLI->fIsMarked = FALSE;

/* if the corresponding position for the end of lpszFrom in the

**    display name is not a separator. We stop comparing this

**    link.

*/

if (!*(lpLI->lpszDisplayName + cFrom) ||

(*(lpLI->lpszDisplayName + cFrom) == '\\') ||

(*(lpLI->lpszDisplayName + cFrom) == '!')) {

LSTRCPYN((LPSTR)szTmp, lpLI->lpszDisplayName, cFrom + 1);

if (!lstrcmp((LPSTR)szTmp, lpszFrom)) {

HRESULT hErr;

int nFileLength;

ULONG ulDummy;

if (!bFound) {

char szTitle[256];

char szMsg[256];

char szBuf[256];

int uRet;

LoadString(ghInst, (UINT)IDS_CHANGESOURCE, (LPSTR)szTitle,

sizeof(szTitle));

LoadString(ghInst, (UINT)IDS_CHANGEADDITIONALLINKS,

(LPSTR)szMsg, sizeof(szMsg));

wsprintf((LPSTR)szBuf, (LPSTR)szMsg, lpszFrom);

uRet = MessageBox(hListBox, (LPSTR)szBuf, (LPSTR)szTitle,

MB_ICONQUESTION | MB_YESNO);

if (uRet == IDYES)

bFound = TRUE;

else

return(FALSE);         // exit function

}

lstrcpy((LPSTR)szTmp, lpszTo);

lstrcat((LPSTR)szTmp, lpLI->lpszDisplayName + cFrom);

nFileLength = lstrlen((LPSTR)szTmp) -

(lpLI->lpszItemName ? lstrlen(lpLI->lpszItemName) : 0);

hErr = lpOleUILinkCntr->lpVtbl->SetLinkSource(

lpOleUILinkCntr,

lpLI->dwLink,

(LPSTR)szTmp,

(ULONG)nFileLength,

(ULONG FAR*)&ulDummy,

TRUE

);

if (hErr != NOERROR)

lpOleUILinkCntr->lpVtbl->SetLinkSource(

lpOleUILinkCntr,

lpLI->dwLink,

(LPSTR)szTmp,

(ULONG)nFileLength,

(ULONG FAR*)&ulDummy,

FALSE

);

lpLI->fIsMarked = TRUE;

}

}

}

/* have to do the refreshing after processing all links, otherwise

**    the item positions will change during the process as the

**    listbox stores items in order

*/

if (bFound)

RefreshLinkLB(hListBox, lpOleUILinkCntr);

return(TRUE);

}

/* LoadLinkLB

 * ----------

 *

 *  Purpose:

 *      Enumerate all links from the Link Container and build up the Link

 *      ListBox

 *

 *  Parameters:

 *      hListBox        window handle of

 *      lpOleUILinkCntr pointer to OleUI Link Container

 *      lpszFrom        prefix for matching

 *      lpszTo          prefix to substitution

 *

 *  Returns:

 *      number of link items loaded, -1 if error

 */

int LoadLinkLB(HWND hListBox, LPOLEUILINKCONTAINER lpOleUILinkCntr)

{

DWORD       dwLink = 0;

LPLINKINFO  lpLI;

int         nIndex;

int         cLinks;

cLinks = 0;

while ((dwLink = lpOleUILinkCntr->lpVtbl->GetNextLink(lpOleUILinkCntr,

dwLink)) != 0) {

lpLI = (LPLINKINFO)OleStdMalloc(sizeof(LINKINFO));

if (NULL == lpLI)

return -1;

lpLI->fIsMarked = FALSE;

lpLI->fIsSelected = FALSE;

lpLI->fDontFree = FALSE;

lpLI->lpszAMX = (LPSTR)OleStdMalloc((LINKTYPELEN+1)*sizeof(BYTE));

lpLI->dwLink = dwLink;

cLinks++;

if ((nIndex = AddLinkLBItem(hListBox,lpOleUILinkCntr,lpLI,TRUE,-1)) < 0)

// can't load list box

return -1;

if (lpLI->fIsSelected) {

SendMessage(hListBox, LB_SETSEL, TRUE, MAKELPARAM(nIndex, 0));

}

}

if (SendMessage(hListBox,LB_GETSELITEMS,(WPARAM)1,(LPARAM)(int FAR*)&nIndex))

SendMessage(hListBox, LB_SETCARETINDEX, (WPARAM)nIndex, MAKELPARAM(TRUE, 0));

return cLinks;

}

/* RefreshLinkLB

 * -------------

 *

 *  Purpose:

 *      Enumerate all items in the links listbox and update those with

 *      fIsMarked set.

 *      Note that this is a time consuming routine as it keeps iterating

 *      all items in the listbox until all of them are unmarked.

 *

 *  Parameters:

 *      hListBox        window handle of listbox

 *      lpOleUILinkCntr pointer to OleUI Link Container

 *

 *  Returns:

 *

 */

VOID RefreshLinkLB(HWND hListBox, LPOLEUILINKCONTAINER lpOleUILinkCntr)

{

int cItems;

int nIndex;

LPLINKINFO  lpLI;

BOOL        bStop;

OleDbgAssert(hListBox);

// Turn painting updates off.

SendMessage(hListBox, WM_SETREDRAW, FALSE, 0L);

cItems = (int)SendMessage(hListBox, LB_GETCOUNT, 0, 0L);

OleDbgAssert(cItems >= 0);

do {

LRESULT nIsSelected;

bStop = TRUE;

for (nIndex=0; nIndex<cItems; nIndex++) {

SendMessage(hListBox, LB_GETTEXT, (WPARAM)nIndex,

(LPARAM)(LPLINKINFO FAR*)&lpLI);

nIsSelected = SendMessage(hListBox, LB_GETSEL, (WPARAM)nIndex,0L);

if (lpLI->fIsMarked) {

lpLI->fIsMarked = FALSE;

lpLI->fDontFree = TRUE;

SendMessage(hListBox, LB_DELETESTRING, nIndex, 0L);

nIndex=AddLinkLBItem(hListBox, lpOleUILinkCntr, lpLI, FALSE, nIndex);

if (nIsSelected > 0) {

lpLI->fIsSelected = TRUE;

SendMessage(hListBox, LB_SETSEL, (WPARAM)TRUE,

MAKELPARAM(nIndex, 0));

SendMessage(hListBox, LB_SETCARETINDEX, (WPARAM)nIndex,

MAKELPARAM(TRUE, 0));

} else {

lpLI->fIsSelected = FALSE;

}

bStop = FALSE;

break;

}

}

} while (!bStop);

// Turn updates back on.

SendMessage(hListBox, WM_SETREDRAW, TRUE, 0L);

}


MSGFILTR.H  (WRAPUI Sample)

/*************************************************************************

**

**    OLE 2 Utility Code

**

**    msgfiltr.h

**

**    This file contains Private definitions, structures, types, and

**    function prototypes for the OleStdMessageFilter implementation of

**    the IMessageFilter interface.

**    This file is part of the OLE 2.0 User Interface support library.

**

**    (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved

**

*************************************************************************/

#if !defined( _MSGFILTR_H_ )

#define _MSGFILTR_H_

#ifndef RC_INVOKED

#pragma message ("INCLUDING MSGFILTR.H from " __FILE__)

#endif  /* RC_INVOKED */

// Message Pending callback procedure

typedef BOOL (CALLBACK* MSGPENDINGPROC)(MSG FAR *);

// HandleInComingCall callback procedure

typedef DWORD (CALLBACK* HANDLEINCOMINGCALLBACKPROC)

(

DWORD               dwCallType,

HTASK               htaskCaller,

DWORD               dwTickCount,

LPINTERFACEINFO     lpInterfaceInfo

);

/* PUBLIC FUNCTIONS */

STDAPI_(LPMESSAGEFILTER) OleStdMsgFilter_Create(

HWND hWndParent,

LPSTR szAppName,

MSGPENDINGPROC lpfnCallback,

LPFNOLEUIHOOK  lpfnOleUIHook         // Busy dialog hook callback

);

STDAPI_(void) OleStdMsgFilter_SetInComingCallStatus(

LPMESSAGEFILTER lpThis, DWORD dwInComingCallStatus);

STDAPI_(DWORD) OleStdMsgFilter_GetInComingCallStatus(

LPMESSAGEFILTER lpThis);

STDAPI_(HANDLEINCOMINGCALLBACKPROC)

OleStdMsgFilter_SetHandleInComingCallbackProc(

LPMESSAGEFILTER             lpThis,

HANDLEINCOMINGCALLBACKPROC  lpfnHandleInComingCallback);

STDAPI_(BOOL) OleStdMsgFilter_EnableBusyDialog(

LPMESSAGEFILTER lpThis, BOOL fEnable);

STDAPI_(BOOL) OleStdMsgFilter_EnableNotRespondingDialog(

LPMESSAGEFILTER lpThis, BOOL fEnable);

STDAPI_(HWND) OleStdMsgFilter_SetParentWindow(

LPMESSAGEFILTER lpThis, HWND hWndParent);

#endif // _MSGFILTR_H_


MSGFILTR.C  (WRAPUI Sample)

/*

 *    MSGFILTR.C

 *

 *    This file contains a standard implementation of IMessageFilter

 *    interface.

 *    This file is part of the OLE 2.0 User Interface support library.

 *

 *    (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved

 *

 */

#define STRICT  1

#include "ole2ui.h"

#include "msgfiltr.h"

OLEDBGDATA

typedef struct tagOLESTDMESSAGEFILTER {

IMessageFilterVtbl FAR* m_lpVtbl;

UINT                    m_cRef;

HWND                    m_hWndParent;

DWORD                   m_dwInComingCallStatus; // Status to return from

// HandleIncomingCall

HANDLEINCOMINGCALLBACKPROC m_lpfnHandleInComingCallback;

// Callback function

// to selectively handle

// interface method calls

BOOL                    m_fEnableBusyDialog;    // enable RetryRejected

//  Call dialog

BOOL                    m_fEnableNotRespondingDialog; // enable

// MessagePending dialog

MSGPENDINGPROC          m_lpfnMessagePendingCallback; // MessagePending

// Callback function

LPFNOLEUIHOOK           m_lpfnBusyDialogHookCallback; // Busy dialog hook

LPSTR                   m_lpszAppName;          // Name of application

// installing filter

HWND                    m_hWndBusyDialog;       // HWND of busy dialog.  Used

// to tear down dialog.

BOOL                    m_bUnblocking;

 }OLESTDMESSAGEFILTER, FAR* LPOLESTDMESSAGEFILTER;

/* interface IMessageFilter implementation */

STDMETHODIMP OleStdMsgFilter_QueryInterface(

LPMESSAGEFILTER lpThis, REFIID riid, LPVOID FAR* ppvObj);

STDMETHODIMP_(ULONG) OleStdMsgFilter_AddRef(LPMESSAGEFILTER lpThis);

STDMETHODIMP_(ULONG) OleStdMsgFilter_Release(LPMESSAGEFILTER lpThis);

STDMETHODIMP_(DWORD) OleStdMsgFilter_HandleInComingCall (

LPMESSAGEFILTER     lpThis,

DWORD               dwCallType,

HTASK               htaskCaller,

DWORD               dwTickCount,

LPINTERFACEINFO     dwReserved

);

STDMETHODIMP_(DWORD) OleStdMsgFilter_RetryRejectedCall (

LPMESSAGEFILTER     lpThis,

HTASK               htaskCallee,

DWORD               dwTickCount,

DWORD               dwRejectType

);

STDMETHODIMP_(DWORD) OleStdMsgFilter_MessagePending (

LPMESSAGEFILTER     lpThis,

HTASK               htaskCallee,

DWORD               dwTickCount,

DWORD               dwPendingType

);

static IMessageFilterVtbl g_OleStdMessageFilterVtbl = {

OleStdMsgFilter_QueryInterface,

OleStdMsgFilter_AddRef,

OleStdMsgFilter_Release,

OleStdMsgFilter_HandleInComingCall,

OleStdMsgFilter_RetryRejectedCall,

OleStdMsgFilter_MessagePending

};

/* GetTopWindowInWindowsTask

** -------------------------

**    Get the top most window that has focus in the given task to be

**    used as the parent for the busy dialog. we do this to handle the

**    case where a dialog window is currently up when we need to give

**    the busy dialog. if we use the current assigned parent window

**    (which typically will be the frame window of the app), then the

**    busy dialog will not be modal to the current active dialog

**    window.

*/

static HWND GetTopWindowInWindowsTask(HWND hwnd)

{

HWND hwndActive = GetActiveWindow();

if (!hwndActive)

return hwnd;

if (GetWindowTask(hwnd) == GetWindowTask(hwndActive))

return hwndActive;

else

return hwnd;

}

STDAPI_(LPMESSAGEFILTER) OleStdMsgFilter_Create(

HWND            hWndParent,

LPSTR           szAppName,

MSGPENDINGPROC  lpfnCallback,

LPFNOLEUIHOOK   lpfnOleUIHook         // Busy dialog hook callback

)

{

LPOLESTDMESSAGEFILTER lpStdMsgFilter;

LPMALLOC lpMalloc;

if (CoGetMalloc(MEMCTX_TASK, (LPMALLOC FAR*)&lpMalloc) != NOERROR)

return NULL;

lpStdMsgFilter = (LPOLESTDMESSAGEFILTER)lpMalloc->lpVtbl->Alloc(

lpMalloc, (sizeof(OLESTDMESSAGEFILTER)));

lpMalloc->lpVtbl->Release(lpMalloc);

if (! lpStdMsgFilter) return NULL;

lpStdMsgFilter->m_lpVtbl = &g_OleStdMessageFilterVtbl;

lpStdMsgFilter->m_cRef = 1;

lpStdMsgFilter->m_hWndParent = hWndParent;

lpStdMsgFilter->m_dwInComingCallStatus = SERVERCALL_ISHANDLED;

lpStdMsgFilter->m_lpfnHandleInComingCallback = NULL;

lpStdMsgFilter->m_fEnableBusyDialog = TRUE;

lpStdMsgFilter->m_fEnableNotRespondingDialog = TRUE;

lpStdMsgFilter->m_lpszAppName = szAppName;

lpStdMsgFilter->m_lpfnMessagePendingCallback = lpfnCallback;

lpStdMsgFilter->m_lpfnBusyDialogHookCallback = lpfnOleUIHook;

lpStdMsgFilter->m_hWndBusyDialog = NULL;

lpStdMsgFilter->m_bUnblocking = FALSE;

    g_dwObjectCount ++;

return (LPMESSAGEFILTER)lpStdMsgFilter;

}

/* OleStdMsgFilter_SetInComingStatus

** ---------------------------------

**    This is a private function that allows the caller to control what

**    value is returned from the IMessageFilter::HandleInComing method.

**

**    if a HandleInComingCallbackProc is installed by a call to

**    OleStdMsgFilter_SetHandleInComingCallbackProc, then this

**    overrides the dwIncomingCallStatus established by a call to

**    OleStdMsgFilter_SetInComingStatus.  Using

**    OleStdMsgFilter_SetInComingStatus allows the app to reject or

**    accept ALL in coming calls. Using a HandleInComingCallbackProc

**    allows the app to selectively handle or reject particular method

**    calls.

*/

STDAPI_(void) OleStdMsgFilter_SetInComingCallStatus(

LPMESSAGEFILTER lpThis, DWORD dwInComingCallStatus)

{

LPOLESTDMESSAGEFILTER lpStdMsgFilter = (LPOLESTDMESSAGEFILTER)lpThis;

if (!IsBadWritePtr((LPVOID)lpStdMsgFilter,  sizeof(OLESTDMESSAGEFILTER)))

lpStdMsgFilter->m_dwInComingCallStatus = dwInComingCallStatus;

else

OleDbgAssert(

"OleStdMsgFilter_SetIncomingCallStatus: Invalid IMessageFilter*");

#if defined( _DEBUG )

{

char szBuf[80];

char *szReturn;

switch(dwInComingCallStatus) {

case SERVERCALL_ISHANDLED:

szReturn = "SERVERCALL_ISHANDLED";

break;

case SERVERCALL_REJECTED:

szReturn = "SERVERCALL_REJECTED";

break;

case SERVERCALL_RETRYLATER:

szReturn = "SERVERCALL_RETRYLATER";

break;

default:

szReturn = "** ERROR: UNKNOWN **";

break;

}

wsprintf(

szBuf,

"OleStdMsgFilter_SetInComingCallStatus: Status set to %s.\r\n",

(LPSTR)szReturn

);

OleDbgOut3(szBuf);

}

#endif

}

/* OleStdMsgFilter_SetHandleInComingCallbackProc

** ---------------------------------------------

**    This is a private function that allows the caller to install (or

**    de-install) a special callback function to selectively

**    handle/reject specific incoming method calls on particular

**    interfaces.

**

**    if a HandleInComingCallbackProc is installed by a call to

**    OleStdMsgFilter_SetHandleInComingCallbackProc, then this

**    overrides the dwIncomingCallStatus established by a call to

**    OleStdMsgFilter_SetInComingStatus.  Using

**    OleStdMsgFilter_SetInComingStatus allows the app to reject or

**    accept ALL in coming calls. Using a HandleInComingCallbackProc

**    allows the app to selectively handle or reject particular method

**    calls.

**

**    to de-install the HandleInComingCallbackProc, call

**          OleStdMsgFilter_SetHandleInComingCallbackProc(NULL);

**

**    Returns previous callback proc in effect.

*/

STDAPI_(HANDLEINCOMINGCALLBACKPROC)

OleStdMsgFilter_SetHandleInComingCallbackProc(

LPMESSAGEFILTER             lpThis,

HANDLEINCOMINGCALLBACKPROC  lpfnHandleInComingCallback)

{

LPOLESTDMESSAGEFILTER lpStdMsgFilter = (LPOLESTDMESSAGEFILTER)lpThis;

HANDLEINCOMINGCALLBACKPROC    lpfnPrevCallback =

lpStdMsgFilter->m_lpfnHandleInComingCallback;

if (!IsBadWritePtr((LPVOID)lpStdMsgFilter, sizeof(OLESTDMESSAGEFILTER))) {

lpStdMsgFilter->m_lpfnHandleInComingCallback =

lpfnHandleInComingCallback;

} else {

OleDbgAssert(

"OleStdMsgFilter_SetIncomingCallStatus: Invalid IMessageFilter*");

}

#if defined( _DEBUG )

{

if (lpfnHandleInComingCallback)

OleDbgOut3(

"OleStdMsgFilter_SetHandleInComingCallbackProc SET\r\n");

else

OleDbgOut3(

"OleStdMsgFilter_SetHandleInComingCallbackProc CLEARED\r\n");

}

#endif  // _DEBUG

return lpfnPrevCallback;

}

/* OleStdMsgFilter_GetInComingStatus

** ---------------------------------

**    This is a private function that returns the current

**    incoming call status.  Can be used to disable/enable options

**    in the calling application.

**

** Returns: one of

**

**    SERVERCALL_ISHANDLED

**    SERVERCALL_REJECTED

**    SERVERCALL_RETRYLATER

**    or -1 for ERROR

**

*/

STDAPI_(DWORD) OleStdMsgFilter_GetInComingCallStatus(

LPMESSAGEFILTER lpThis)

{

LPOLESTDMESSAGEFILTER lpStdMsgFilter = (LPOLESTDMESSAGEFILTER)lpThis;

DWORD dwReturn;

if (!IsBadReadPtr((LPVOID)lpStdMsgFilter,  sizeof(OLESTDMESSAGEFILTER)))

dwReturn = lpStdMsgFilter->m_dwInComingCallStatus;

else

{

OleDbgAssert(

"OleStdMsgFilter_GetIncomingCallStatus: Invalid IMessageFilter*");

dwReturn = (DWORD)-1;

}

#if defined( _DEBUG )

{

char szBuf[80];

char *szReturn;

switch(dwReturn) {

case SERVERCALL_ISHANDLED:

szReturn = "SERVERCALL_ISHANDLED";

break;

case SERVERCALL_REJECTED:

szReturn = "SERVERCALL_REJECTED";

break;

case SERVERCALL_RETRYLATER:

szReturn = "SERVERCALL_RETRYLATER";

break;

default:

szReturn = "-1";

break;

}

wsprintf(

szBuf,

"OleStdMsgFilter_GetInComingCallStatus returns %s.\r\n",

(LPSTR)szReturn

);

OleDbgOut3(szBuf);

}

#endif

return dwReturn;

}

/* OleStdMsgFilter_EnableBusyDialog

** --------------------------------

**    This function allows the caller to control whether

**    the busy dialog is enabled. this is the dialog put up when

**    IMessageFilter::RetryRejectedCall is called because the server

**    responded SERVERCALL_RETRYLATER or SERVERCALL_REJECTED.

**

**    if the busy dialog is NOT enabled, then the rejected call is

**    immediately canceled WITHOUT prompting the user. in this situation

**    OleStdMsgFilter_RetryRejectedCall always retuns

**    OLESTDCANCELRETRY canceling the outgoing LRPC call.

**    If the busy dialog is enabled, then the user is given the choice

**    of whether to retry, switch to, or cancel.

**

**    Returns previous dialog enable state

*/

STDAPI_(BOOL) OleStdMsgFilter_EnableBusyDialog(

LPMESSAGEFILTER lpThis, BOOL fEnable)

{

LPOLESTDMESSAGEFILTER lpStdMsgFilter = (LPOLESTDMESSAGEFILTER)lpThis;

BOOL fPrevEnable = lpStdMsgFilter->m_fEnableBusyDialog;

if (!IsBadWritePtr((LPVOID)lpStdMsgFilter,  sizeof(OLESTDMESSAGEFILTER)))

lpStdMsgFilter->m_fEnableBusyDialog = fEnable;

else

OleDbgAssert(

"OleStdMsgFilter_EnableBusyDialog: Invalid IMessageFilter*");

#if defined( _DEBUG )

{

char szBuf[80];

wsprintf(

szBuf,

"OleStdMsgFilter_EnableBusyDialog: Dialog is %s.\r\n",

fEnable ? (LPSTR)"ENABLED" : (LPSTR)"DISABLED"

);

OleDbgOut3(szBuf);

}

#endif

return fPrevEnable;

}

/* OleStdMsgFilter_EnableNotRespondingDialog

** -----------------------------------------

**    This function allows the caller to control whether

**    the app "NotResponding" (Blocked) dialog is enabled. this is the

**    dialog put up when IMessageFilter::MessagePending is called.

**    If the NotResponding dialog is enabled, then the user is given

**    the choice of whether to retry or switch to, but NOT to cancel.

**

**    Returns previous dialog enable state

*/

STDAPI_(BOOL) OleStdMsgFilter_EnableNotRespondingDialog(

LPMESSAGEFILTER lpThis, BOOL fEnable)

{

LPOLESTDMESSAGEFILTER lpStdMsgFilter = (LPOLESTDMESSAGEFILTER)lpThis;

BOOL fPrevEnable = lpStdMsgFilter->m_fEnableNotRespondingDialog;

if (!IsBadWritePtr((LPVOID)lpStdMsgFilter,  sizeof(OLESTDMESSAGEFILTER)))

lpStdMsgFilter->m_fEnableNotRespondingDialog = fEnable;

else

OleDbgAssert(

"OleStdMsgFilter_EnableNotRespondingDialog: Invalid IMessageFilter*");

#if defined( _DEBUG )

{

char szBuf[80];

wsprintf(

szBuf,

"OleStdMsgFilter_EnableNotRespondingDialog: Dialog is %s.\r\n",

fEnable ? (LPSTR)"ENABLED" : (LPSTR)"DISABLED"

);

OleDbgOut3(szBuf);

}

#endif

return fPrevEnable;

}

/* OleStdMsgFilter_SetParentWindow

** -------------------------------

**    This function allows caller to set which window will be used as

**    the parent for the busy dialog.

**

**    OLE2NOTE: it would be inportant for an in-place active server to

**    reset this to its current in-place frame window when in-place

**    activated. if the hWndParent is set to NULL then the dialogs will

**    be parented to the desktop.

**

**    Returns: previous parent window

*/

STDAPI_(HWND) OleStdMsgFilter_SetParentWindow(

LPMESSAGEFILTER lpThis, HWND hWndParent)

{

LPOLESTDMESSAGEFILTER lpStdMsgFilter = (LPOLESTDMESSAGEFILTER)lpThis;

HWND hWndPrev = lpStdMsgFilter->m_hWndParent;

lpStdMsgFilter->m_hWndParent = hWndParent;

return hWndPrev;

}

STDMETHODIMP OleStdMsgFilter_QueryInterface(

LPMESSAGEFILTER lpThis, REFIID riid, LPVOID FAR* ppvObj)

{

LPOLESTDMESSAGEFILTER lpStdMsgFilter = (LPOLESTDMESSAGEFILTER)lpThis;

SCODE scode;

/* Two interfaces supported: IUnknown, IMessageFilter

*/

if (IsEqualIID(riid, &IID_IMessageFilter) || IsEqualIID(riid, &IID_IUnknown)) {

lpStdMsgFilter->m_cRef++;   // A pointer to this object is returned

*ppvObj = lpThis;

scode = S_OK;

}

else {                 // unsupported interface

*ppvObj = NULL;

scode = E_NOINTERFACE;

}

return ResultFromScode(scode);

}

STDMETHODIMP_(ULONG) OleStdMsgFilter_AddRef(LPMESSAGEFILTER lpThis)

{

LPOLESTDMESSAGEFILTER lpStdMsgFilter = (LPOLESTDMESSAGEFILTER)lpThis;

return ++lpStdMsgFilter->m_cRef;

}

STDMETHODIMP_(ULONG) OleStdMsgFilter_Release(LPMESSAGEFILTER lpThis)

{

LPOLESTDMESSAGEFILTER lpStdMsgFilter = (LPOLESTDMESSAGEFILTER)lpThis;

LPMALLOC lpMalloc;

if (--lpStdMsgFilter->m_cRef != 0) // Still used by others

return lpStdMsgFilter->m_cRef;

// Free storage

if (CoGetMalloc(MEMCTX_TASK, (LPMALLOC FAR*)&lpMalloc) != NOERROR)

return (ULONG)0;

lpMalloc->lpVtbl->Free(lpMalloc, lpStdMsgFilter);

lpMalloc->lpVtbl->Release(lpMalloc);

    g_dwObjectCount --;

return (ULONG)0;

}

STDMETHODIMP_(DWORD) OleStdMsgFilter_HandleInComingCall (

LPMESSAGEFILTER     lpThis,

DWORD               dwCallType,

HTASK               htaskCaller,

DWORD               dwTickCount,

LPINTERFACEINFO     dwReserved

)

{

LPOLESTDMESSAGEFILTER lpStdMsgFilter = (LPOLESTDMESSAGEFILTER)lpThis;

/* if a HandleInComingCallbackProc is in effect, then this

**    overrides dwIncomingCallStatus established by a call to

**    OleStdMsgFilter_SetInComingStatus.  we will call this

**    callback to allow the app to selectively handle or reject

**    incoming method calls. the LPINTERFACEINFO parameter

**    describes which method is being called.

*/

if (lpStdMsgFilter->m_lpfnHandleInComingCallback &&

!IsBadCodePtr((FARPROC)lpStdMsgFilter->m_lpfnHandleInComingCallback)){

return lpStdMsgFilter->m_lpfnHandleInComingCallback(

dwCallType,

htaskCaller,

dwTickCount,

(LPINTERFACEINFO)dwReserved

);

}

switch (dwCallType) {

case CALLTYPE_TOPLEVEL:

/* OLE2NOTE: we currently have NO pending outgoing call and

**    there is a new toplevel incoming call.

**    this call may be rejected.

*/

return lpStdMsgFilter->m_dwInComingCallStatus;

case CALLTYPE_TOPLEVEL_CALLPENDING:

/* OLE2NOTE: we currently HAVE a pending outgoing call and

**    there is a new toplevel incoming call.

**    this call may be rejected.

*/

return lpStdMsgFilter->m_dwInComingCallStatus;

case CALLTYPE_NESTED:

/* OLE2NOTE: we currently HAVE a pending outgoing call and

**    there callback on behalf of the previous outgoing

**    call. this type of call should ALWAYS be handled.

*/

return SERVERCALL_ISHANDLED;

case CALLTYPE_ASYNC:

/* OLE2NOTE: we currently have NO pending outgoing call and

**    there is a new asyncronis incoming call.

**    this call can NEVER be rejected. OLE actually ignores

**    the return code in this case and always allows the

**    call through.

*/

return SERVERCALL_ISHANDLED;    // value returned does not matter

case CALLTYPE_ASYNC_CALLPENDING:

/* OLE2NOTE: we currently HAVE a pending outgoing call and

**    there is a new asyncronis incoming call.

**    this call can NEVER be rejected. OLE ignore the

**    return code in this case.

*/

return SERVERCALL_ISHANDLED;    // value returned does not

default:

OleDbgAssert(

"OleStdMsgFilter_HandleInComingCall: Invalid CALLTYPE");

return lpStdMsgFilter->m_dwInComingCallStatus;

}

}

STDMETHODIMP_(DWORD) OleStdMsgFilter_RetryRejectedCall (

LPMESSAGEFILTER     lpThis,

HTASK               htaskCallee,

DWORD               dwTickCount,

DWORD               dwRejectType

)

{

LPOLESTDMESSAGEFILTER   lpStdMsgFilter = (LPOLESTDMESSAGEFILTER)lpThis;

DWORD                   dwRet = 0;

UINT                    uRet;

#if defined( _DEBUG )

char                    szBuf[80];

#endif

OLEDBG_BEGIN2("OleStdMsgFilter_RetryRejectedCall\r\n")

/* OLE2NOTE: we should only put up the application busy dialog when

**    the callee has responded SERVERCALL_RETRYLATER. if the

**    dwRejectType is SERVERCALL_REJECTED then there is something

**    seriously wrong with the callee (perhaps a severe low memory

**    situation). we don't want to even try to "Switch To" this app

**    or even try to "Retry".

*/

if (dwRejectType == SERVERCALL_RETRYLATER &&

lpStdMsgFilter->m_fEnableBusyDialog) {

OLEUIBUSY bz;

/* OLE2NOTE: we do not want to put up the Busy dialog immediately

**    the when an app says RETRYLATER. we should continue retrying

**    for a while in case the app can un-busy itself in a

**    reasonable amount of time.

*/

if (dwTickCount <= (DWORD)OLESTDRETRYDELAY) {

dwRet = 500;                  // Retry after .5 sec

OLEDBG_END2

return dwRet;

}

/*

** Set up structure for calling OLEUIBUSY dialog

*/

bz.cbStruct = sizeof(OLEUIBUSY);

bz.dwFlags = 0L;

bz.hWndOwner =GetTopWindowInWindowsTask(lpStdMsgFilter->m_hWndParent);

bz.lpszCaption = lpStdMsgFilter->m_lpszAppName;

bz.lpfnHook = lpStdMsgFilter->m_lpfnBusyDialogHookCallback;

bz.lCustData = 0;

bz.hInstance = NULL;

bz.lpszTemplate = NULL;

bz.hResource = 0;

bz.hTask = htaskCallee;

bz.lphWndDialog = NULL; // We don't need the hDlg for this call

uRet = OleUIBusy(&bz);

switch (uRet) {

case OLEUI_BZ_RETRYSELECTED:

dwRet = 0;                  // Retry immediately

break;

case OLEUI_CANCEL:

dwRet = OLESTDCANCELRETRY;  // Cancel pending outgoing call

break;

case OLEUI_BZERR_HTASKINVALID:

// Htask was invalid, return OLESTDRETRYDELAY anyway

dwRet = OLESTDRETRYDELAY;   // Retry after <retry delay> msec

#if defined( _DEBUG )

wsprintf(

szBuf,

"OleStdMsgFilter_RetryRejectedCall, HTASK 0x%x invalid\r\n",

htaskCallee

);

OleDbgOut3(szBuf);

#endif

break;

}

} else {

dwRet = OLESTDCANCELRETRY;  // Cancel pending outgoing call

}

#if defined( _DEBUG )

wsprintf(szBuf,

 "OleStdMsgFilter_RetryRejectedCall returns %d\r\n",

 dwRet);

OleDbgOut3(szBuf);

#endif

OLEDBG_END2

return dwRet;

}

/* a significant message is consider a mouse click or keyboard input. */

#define IS_SIGNIFICANT_MSG(lpmsg)   \

(   \

(PeekMessage((lpmsg), NULL, WM_LBUTTONDOWN, WM_LBUTTONDOWN, \

 PM_NOREMOVE | PM_NOYIELD)) \

 || (PeekMessage((lpmsg), NULL, WM_LBUTTONDBLCLK, WM_LBUTTONDBLCLK, \

 PM_NOREMOVE | PM_NOYIELD)) \

 || (PeekMessage((lpmsg), NULL, WM_NCLBUTTONDOWN, WM_NCLBUTTONDOWN, \

 PM_NOREMOVE | PM_NOYIELD)) \

 || (PeekMessage((lpmsg), NULL, WM_NCLBUTTONDBLCLK, WM_NCLBUTTONDBLCLK, \

 PM_NOREMOVE | PM_NOYIELD)) \

 || (PeekMessage((lpmsg), NULL, WM_KEYDOWN, WM_KEYDOWN, \

 PM_NOREMOVE | PM_NOYIELD)) \

 || (PeekMessage((lpmsg), NULL, WM_SYSKEYDOWN, WM_SYSKEYDOWN, \

 PM_NOREMOVE | PM_NOYIELD)) \

)

STDMETHODIMP_(DWORD) OleStdMsgFilter_MessagePending (

LPMESSAGEFILTER     lpThis,

HTASK               htaskCallee,

DWORD               dwTickCount,

DWORD               dwPendingType

)

{

LPOLESTDMESSAGEFILTER   lpStdMsgFilter = (LPOLESTDMESSAGEFILTER)lpThis;

DWORD                   dwReturn = PENDINGMSG_WAITDEFPROCESS;

MSG                     msg;

BOOL                    fIsSignificantMsg = IS_SIGNIFICANT_MSG(&msg);

UINT                    uRet;

#if defined( _DEBUG )

char szBuf[128];

wsprintf(

szBuf,

"OleStdMsgFilter_MessagePending, dwTickCount = 0x%lX\r\n",

(DWORD)dwTickCount

);

OleDbgOut4(szBuf);

#endif

/* OLE2NOTE: If our tick count for this call exceeds our standard retry

**      delay, then we need to put up the dialog.  We will only

**      consider putting up the dialog if the user has issued a

**      "significant" event (ie. mouse click or keyboard event). a

**      simple mouse move should NOT trigger this dialog.

**      Since our call to

**      OleUIBusy below enters a DialogBox() message loop, there's a

**      possibility that another call will be initiated during the dialog,

**      and this procedure will be re-entered.  Just so we don't put up

**      two dialogs at a time, we use the m_bUnblocking varable

**      to keep track of this situation.

*/

if (dwTickCount > (DWORD)OLESTDRETRYDELAY && fIsSignificantMsg

&& !lpStdMsgFilter->m_bUnblocking)

{

if (lpStdMsgFilter->m_fEnableNotRespondingDialog)

{

OLEUIBUSY bz;

lpStdMsgFilter->m_bUnblocking = TRUE;

// Eat messages in our queue that we do NOT want to be dispatched

while (PeekMessage(&msg, NULL, WM_CLOSE, WM_CLOSE, PM_REMOVE | PM_NOYIELD));

/* Set up structure for calling OLEUIBUSY dialog,

** using the "not responding" variety

*/

bz.cbStruct = sizeof(OLEUIBUSY);

bz.dwFlags = BZ_NOTRESPONDINGDIALOG;

bz.hWndOwner =GetTopWindowInWindowsTask(lpStdMsgFilter->m_hWndParent);

bz.lpszCaption = lpStdMsgFilter->m_lpszAppName;

bz.lpfnHook = lpStdMsgFilter->m_lpfnBusyDialogHookCallback;

bz.lCustData = 0;

bz.hInstance = NULL;

bz.lpszTemplate = NULL;

bz.hResource = 0;

bz.hTask = htaskCallee;

/* Set up the address to the hWnd in our MsgFilter structure.  The

** call to OleUIBusy will fill this in with the hWnd of the busy

** dialog box

*/

bz.lphWndDialog =  (HWND FAR *)&(lpStdMsgFilter->m_hWndBusyDialog);

uRet = OleUIBusy(&bz);

lpStdMsgFilter->m_bUnblocking = FALSE;

return PENDINGMSG_WAITNOPROCESS;

}

#if defined( _DEBUG )

else {

OleDbgOut3("OleStdMsgFilter_MessagePending: BLOCKED but dialog Disabled\r\n");

}

#endif

}

/* If we're already unblocking, we're being re-entered.  Don't

** process message

*/

if (lpStdMsgFilter->m_bUnblocking)

return PENDINGMSG_WAITDEFPROCESS;

/* OLE2NOTE: If we have a callback function set up, call it with the

** current message.  If not, tell OLE LPRC mechanism to automatically

** handle all messages.

*/

if (lpStdMsgFilter->m_lpfnMessagePendingCallback &&

!IsBadCodePtr((FARPROC)lpStdMsgFilter->m_lpfnMessagePendingCallback)){

MSG msg;

/* OLE2NOTE: the app provided a MessagePendingCallback

**    function. we will PeekMessage for the first message in

**    the queue and pass it to the app. the app in its callback

**    function can decide to Dispatch this message or it can

**    PeekMessage on its own giving particular message filter

**    criteria. if the app returns TRUE then we return

**    PENDINGMSG_WAITNOPROCESS to OLE telling OLE to leave the

**    message in the queue. If the app returns FALSE, then we

**    return PENDINGMSG_WAITDEFPROCESS to OLE telling OLE to do

**    its default processing with the message. by default OLE

**    dispatches system messages and eats other messages and

**    beeps.

*/

if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE | PM_NOYIELD)) {

if (lpStdMsgFilter->m_lpfnMessagePendingCallback(&msg)) {

/* TRUE return means that the app processed message.

**

** NOTE: (CHANGE FROM OLE2.0 VERSION) we leave it up to

**    the callback routine to remove the message if it

**    wants.

*/

dwReturn = PENDINGMSG_WAITNOPROCESS;

} else {

/* FALSE means that the app did not process the

**    message. we will let OLE take its

**    default action.

**

** NOTE: (CHANGE FROM OLE2.0 VERSION) we used to return

**    PENDINGMSG_WAITNOPROCESS to leave the message in

**    the queue; now we return PENDINGMSG_WAITDEFPROCESS

**    to let OLE do default processing.

*/

dwReturn = PENDINGMSG_WAITDEFPROCESS;

#if defined( _DEBUG )

wsprintf(

szBuf,

"Message (0x%x) (wParam=0x%x, lParam=0x%lx) using WAITDEFPROCESS while blocked\r\n",

msg.message,

msg.lParam,

msg.wParam

);

OleDbgOut2(szBuf);

#endif  // _DEBUG

}

}

}

return dwReturn;

}


OBJFDBK.C  (WRAPUI Sample)

/*

 * OBJFDBK.C

 *

 * Miscellaneous API's to generate UI feedback effects for OLE objects. This

 * is part of the OLE 2.0 User Interface Support Library.

 * The following feedback effects are supported:

 *      1. Object selection handles (OleUIDrawHandles)

 *      2. Open Object window shading (OleUIDrawShading)

 *

 * Copyright (c)1992 Microsoft Corporation, All Right Reserved

 */

#define STRICT  1

#include "ole2ui.h"

static void DrawHandle(HDC hdc, int x, int y, UINT cSize, BOOL bInvert, BOOL fDraw);

/*

 * OleUIDrawHandles

 *

 * Purpose:

 *  Draw handles or/and boundary around Container Object when selected

 *

 * Parameters:

 *  lpRect      Dimensions of Container Object

 *  hdc         HDC of Container Object (MM_TEXT mapping mode)

 *  dwFlags-

 *      Exclusive flags

 *          OLEUI_HANDLES_INSIDE    Draw handles on inside of rect

 *          OLEUI_HANDLES_OUTSIDE   Draw handles on outside of rect

 *      Optional flags

 *          OLEUI_HANDLES_NOBORDER  Draw handles only, no rect

 *          OLEUI_HANDLES_USEINVERSE

 *              use invert for handles and rect, o.t. use COLOR_WINDOWTEXT

 *  cSize       size of handle box

 *  fDraw       Draw if TRUE, erase if FALSE

 *

 * Return Value: null

 *

 */

STDAPI_(void) OleUIDrawHandles(

LPRECT  lpRect,

HDC     hdc,

DWORD   dwFlags,

UINT    cSize,

BOOL    fDraw

)

{

HBRUSH  hbr;

RECT    rc;

int     bkmodeOld;

BOOL    bInvert = (BOOL) (dwFlags & OLEUI_HANDLES_USEINVERSE);

CopyRect((LPRECT)&rc, lpRect);

bkmodeOld = SetBkMode(hdc, TRANSPARENT);

if (dwFlags & OLEUI_HANDLES_OUTSIDE)

InflateRect((LPRECT)&rc, cSize - 1, cSize - 1);

// Draw the handles inside the rectangle boundary

DrawHandle(hdc, rc.left, rc.top, cSize, bInvert, fDraw);

DrawHandle(hdc, rc.left, rc.top+(rc.bottom-rc.top-cSize)/2, cSize, bInvert, fDraw);

DrawHandle(hdc, rc.left, rc.bottom-cSize, cSize, bInvert, fDraw);

DrawHandle(hdc, rc.left+(rc.right-rc.left-cSize)/2, rc.top, cSize, bInvert, fDraw);

DrawHandle(hdc, rc.left+(rc.right-rc.left-cSize)/2, rc.bottom-cSize, cSize, bInvert, fDraw);

DrawHandle(hdc, rc.right-cSize, rc.top, cSize, bInvert, fDraw);

DrawHandle(hdc, rc.right-cSize, rc.top+(rc.bottom-rc.top-cSize)/2, cSize, bInvert, fDraw);

DrawHandle(hdc, rc.right-cSize, rc.bottom-cSize, cSize, bInvert, fDraw);

if (!(dwFlags & OLEUI_HANDLES_NOBORDER)) {

if (fDraw)

hbr = GetStockObject(BLACK_BRUSH);

else

hbr = GetStockObject(WHITE_BRUSH);

FrameRect(hdc, lpRect, hbr);

}

SetBkMode(hdc, bkmodeOld);

}

/*

 * DrawHandle

 *

 * Purpose:

 *  Draw a handle box at the specified coordinate

 *

 * Parameters:

 *  hdc         HDC to be drawn into

 *  x, y        upper left corner coordinate of the handle box

 *  cSize       size of handle box

 *  bInvert     use InvertRect() if TRUE, otherwise use Rectangle()

 *  fDraw       Draw if TRUE, erase if FALSE, ignored if bInvert is TRUE

 *

 * Return Value: null

 *

 */

static void DrawHandle(HDC hdc, int x, int y, UINT cSize, BOOL bInvert, BOOL fDraw)

{

HBRUSH  hbr;

HBRUSH  hbrOld;

HPEN    hpen;

HPEN    hpenOld;

RECT    rc;

if (!bInvert) {

if (fDraw) {

hpen = GetStockObject(BLACK_PEN);

hbr = GetStockObject(BLACK_BRUSH);

} else {

hpen = GetStockObject(WHITE_PEN);

hbr = GetStockObject(WHITE_PEN);

}

hpenOld = SelectObject(hdc, hpen);

hbrOld = SelectObject(hdc, hbr);

Rectangle(hdc, x, y, x+cSize, y+cSize);

SelectObject(hdc, hpenOld);

SelectObject(hdc, hbrOld);

}

else {

rc.left = x;

rc.top = y;

rc.right = x + cSize;

rc.bottom = y + cSize;

InvertRect(hdc, (LPRECT)&rc);

}

}

/*

 * OleUIDrawShading

 *

 * Purpose:

 *  Shade the object when it is in in-place editing. Borders are drawn

 *  on the Object rectangle. The right and bottom edge of the rectangle

 *  are excluded in the drawing.

 *

 * Parameters:

 *  lpRect      Dimensions of Container Object

 *  hdc         HDC for drawing

 *  dwFlags-

 *      Exclusive flags

 *          OLEUI_SHADE_FULLRECT    Shade the whole rectangle

 *          OLEUI_SHADE_BORDERIN    Shade cWidth pixels inside rect

 *          OLEUI_SHADE_BORDEROUT   Shade cWidth pixels outside rect

 *      Optional flags

 *          OLEUI_SHADE_USEINVERSE

 *              use PATINVERT instead of the hex value

 *  cWidth      width of border in pixel

 *

 * Return Value: null

 *

 */

STDAPI_(void) OleUIDrawShading(LPRECT lpRect, HDC hdc, DWORD dwFlags, UINT cWidth)

{

HBRUSH  hbr;

HBRUSH  hbrOld;

HBITMAP hbm;

RECT    rc;

UINT    wHatchBmp[] = {0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88};

COLORREF cvText;

COLORREF cvBk;

hbm = CreateBitmap(8, 8, 1, 1, wHatchBmp);

hbr = CreatePatternBrush(hbm);

hbrOld = SelectObject(hdc, hbr);

rc = *lpRect;

if (dwFlags == OLEUI_SHADE_FULLRECT) {

cvText = SetTextColor(hdc, RGB(255, 255, 255));

cvBk = SetBkColor(hdc, RGB(0, 0, 0));

PatBlt(hdc, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top,

0x00A000C9L /* DPa */ );

} else {    // either inside or outside rect

if (dwFlags == OLEUI_SHADE_BORDEROUT)

InflateRect((LPRECT)&rc, cWidth - 1, cWidth - 1);

cvText = SetTextColor(hdc, RGB(255, 255, 255));

cvBk = SetBkColor(hdc, RGB(0, 0, 0));

PatBlt(hdc, rc.left, rc.top, rc.right - rc.left,

cWidth, 0x00A000C9L /* DPa */);

PatBlt(hdc, rc.left, rc.top, cWidth, rc.bottom - rc.top,

0x00A000C9L /* DPa */);

PatBlt(hdc, rc.right - cWidth, rc.top, cWidth,

rc.bottom - rc.top, 0x00A000C9L /* DPa */);

PatBlt(hdc, rc.left, rc.bottom - cWidth, rc.right-rc.left,

cWidth, 0x00A000C9L /* DPa */);

}

SetTextColor(hdc, cvText);

SetBkColor(hdc, cvBk);

SelectObject(hdc, hbrOld);

DeleteObject(hbr);

DeleteObject(hbm);

}

/*

 * OleUIShowObject

 *

 * Purpose:

 *  Draw the ShowObject effect around the object

 *

 * Parameters:

 *  lprc        rectangle for drawing

 *  hdc         HDC for drawing

 *  fIsLink     linked object (TRUE) or embedding object (FALSE)

 *

 * Return Value: null

 *

 */

STDAPI_(void) OleUIShowObject(LPCRECT lprc, HDC hdc, BOOL fIsLink)

{

HPEN    hpen;

HPEN    hpenOld;

HBRUSH  hbrOld;

if (!lprc || !hdc)

return;

hpen = fIsLink ? CreatePen(PS_DASH, 1, RGB(0,0,0)) :

 GetStockObject(BLACK_PEN);

if (!hpen)

return;

hpenOld = SelectObject(hdc, hpen);

hbrOld = SelectObject(hdc, GetStockObject(NULL_BRUSH));

Rectangle(hdc, lprc->left, lprc->top, lprc->right, lprc->bottom);

SelectObject(hdc, hpenOld);

SelectObject(hdc, hbrOld);

if (fIsLink)

DeleteObject(hpen);

}


 OLE2UI.DEF  (WRAPUI Sample)

;;

;;    ole2ui.def

;;

;;        Definition file for ole2ui.dll

;;

;;        (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved

;;

;;

CODE            MOVEABLE DISCARDABLE

DATA            MOVEABLE SINGLE

HEAPSIZE        16392

EXPORTS         WEP                                 @1 RESIDENTNAME

;;

;; NOTE: DO NOT PLACE ANY EXPORTS HERE -- USE THE

;; __export KEYWORD INSTEAD.

SetDCToAnisotropic

SetDCToDrawInHimetricRect

ResetOrigDC

XformRectInPixelsToHimetric

XformRectInHimetricToPixels

XformSizeInPixelsToHimetric

XformSizeInHimetricToPixels

XformWidthInHimetricToPixels

XformWidthInPixelsToHimetric

XformHeightInHimetricToPixels

XformHeightInPixelsToHimetric

;; converted to a macro

;;   AreRectsEqual

ParseCmdLine

OleStdIsOleLink

OleStdQueryInterface

OleStdCreateRootStorage

OleStdOpenRootStorage

OleStdOpenOrCreateRootStorage

OleStdCreateChildStorage

OleStdOpenChildStorage

OleStdCommitStorage

OleStdCreateStorageOnHGlobal

OleStdCreateTempStorage

OleStdDoConvert

OleStdGetTreatAsFmtUserType

OleStdDoTreatAsClass

OleStdSetupAdvises

OleStdSwitchDisplayAspect

OleStdSetIconInCache

OleStdGetData

OleStdMarkPasteEntryList

OleStdGetPriorityClipboardFormat

OleStdIsDuplicateFormat

OleStdRegisterAsRunning

OleStdRevokeAsRunning

OleStdNoteFileChangeTime

OleStdNoteObjectChangeTime

OleStdGetOleObjectData

OleStdGetLinkSourceData

OleStdGetObjectDescriptorData

OleStdGetObjectDescriptorDataFromOleObject

OleStdFillObjectDescriptorFromData

;; converted to a macro

;;   OleStdCopyMetafilePict

OleStdGetMetafilePictFromOleObject

;; converted to a macro

;;   OleStdQueryOleObjectData

;; converted to a macro

;;   OleStdQueryLinkSourceData

;; converted to a macro

;;   OleStdQueryObjectDescriptorData

;; converted to a macro

;;   OleStdQueryFormatMedium

;; converted to a macro

;;   OleStdGetDropEffect

OleStdCreateTempFileMoniker

OleStdGetFirstMoniker

OleStdGetLenFilePrefixOfMoniker

OleStdMalloc

OleStdRealloc

OleStdFree

OleStdGetSize

OleStdFreeString

OleStdCopyString

OleStdGetItemToken

OleStdInitVtbl

OleStdCheckVtbl

OleStdVerifyRelease

OleStdRelease

OleStdCreateDC

OleStdCreateIC

OleStdCreateTargetDevice

OleStdDeleteTargetDevice

OleStdCopyTargetDevice

OleStdCopyFormatEtc

OleDbgPrint

OleDbgPrintAlways

OleDbgSetDbgLevel

OleDbgGetDbgLevel

OleDbgIndent

OleDbgPrintRefCnt

OleDbgPrintRefCntAlways

OleDbgPrintRect

OleDbgPrintRectAlways

OleDbgPrintScodeAlways

OleUIInitialize

OleUIUnInitialize

OleUIAddVerbMenu

;; superceeded by OleMetafilePictFromIconAndLabel

;; OleUIMetafilePictFromIconAndLabel

OleUIMetafilePictIconFree

OleUIMetafilePictIconDraw

OleUIMetafilePictExtractLabel

OleUIMetafilePictExtractIcon

OleUIMetafilePictExtractIconSource

OleUIInsertObject

OleUIPasteSpecial

OleUIEditLinks

OleUIChangeIcon

OleUIConvert

OleUIBusy

OleUIUpdateLinks

OleUIDrawHandles

OleUICanConvertOrActivateAs

OleUIDrawShading

OleUIShowObject

RegisterHatchWindowClass

CreateHatchWindow

GetHatchWidth

GetHatchRect

SetHatchRect

SetHatchWindowSize

;;_OleUIPromptUser

OleUIPromptUser

OleStdEnumFmtEtc_Create

;; superceeded by OleGetIconOfFile

;; GetIconOfFile

;; superceeded by OleGetIconOfClass

;; GetIconOfClass

OleStdGetAuxUserType

OleStdGetUserTypeOfClass

OleStdIconLabelTextOut

OleStdMsgFilter_Create

OleStdMsgFilter_SetInComingCallStatus

OleStdMsgFilter_GetInComingCallStatus

OleStdMsgFilter_EnableBusyDialog

OleStdMsgFilter_EnableNotRespondingDialog

OleStdMsgFilter_SetParentWindow

OleStdGetMiscStatusOfClass

OleStdGetDefaultFileFormatOfClass

OleStdDestroyAllElements

OleStdCreateDbAlloc

OleStdInitSummaryInfo

OleStdFreeSummaryInfo

OleStdClearSummaryInfo

;;OleStdReadSummaryInfo

OleStdWriteSummaryInfo

OleStdGetSecurityProperty

OleStdSetSecurityProperty

OleStdGetStringProperty

OleStdSetStringProperty

OleStdGetStringZProperty

OleStdGetDocProperty

OleStdSetDocProperty

OleStdGetThumbNailProperty

OleStdSetThumbNailProperty

OleStdGetDateProperty

OleStdSetDateProperty

OleStdMsgFilter_SetHandleInComingCallbackProc

OleStdEnumStatData_Create

OleStdCopyStatData

OleStdCreateStandardPalette

OleStdMkParseDisplayName

OleUILockLibrary

_


 OLE2UI.H  (WRAPUI Sample)

/*

 * OLE2UI.H

 *

 * Published definitions, structures, types, and function prototypes for the

 * OLE 2.0 User Interface support library.

 *

 * Copyright (c)1993 Microsoft Corporation, All Rights Reserved

 */

/* NOTE: All dialog and string resource ID's defined in this file are

 *    in the range:

 *          32248 - 32504   (0x7DF8 - 0x7EF8)

*/

#ifndef _OLE2UI_H_

#define _OLE2UI_H_

#ifndef RC_INVOKED

#pragma message ("Including OLE2UI.H from " __FILE__)

#endif  //RC_INVOKED

#ifdef WIN32

#define _INC_OLE

// #define __RPC_H__

#endif

#if !defined(__cplusplus) && !defined( __TURBOC__)

#define NONAMELESSUNION     // use strict ANSI standard (for DVOBJ.H)

#endif

#include <windows.h>

#include <shellapi.h>

#include <ole2.h>

#include <string.h>

#include <dlgs.h>           //For fileopen dlg; standard include

/*************************************************************************

** DEBUG ASSERTION ROUTINES

*************************************************************************/

#ifdef DBG

#include <assert.h>

#define FnAssert(lpstrExpr, lpstrMsg, lpstrFileName, iLine)     \

        (_assert(lpstrMsg ? lpstrMsg : lpstrExpr,               \

                 lpstrFileName,                                 \

                 iLine), NOERROR)

#endif //DBG

#include "olestd.h"

#ifdef __TURBOC__

#define _getcwd getcwd

#define _itoa   itoa

#define __max   max

#define _find_t find_t

#endif // __TURBOC__

#ifdef WIN32

#define _fmemset memset

#define _fmemcpy memcpy

#define _fmemcmp memcmp

#define _fstrcpy strcpy

#define _fstrlen strlen

#define _fstrrchr strrchr

#define _fstrtok strtok

// BUGBUG32: isspace function does not seem to work properly

#undef isspace

#define isspace(j) (j==' ' || j=='\t' || j=='\n')

#endif  // WIN32

#if !defined( EXPORT )

#ifdef WIN32

#define EXPORT

#else

#define EXPORT  __export

#endif  // WIN32

#endif  // !EXPORT

/*

 * Initialization / Uninitialization routines.  OleUIInitialize

 * must be called prior to using any functions in OLE2UI, and OleUIUnInitialize

 * must be called before you app shuts down and when you are done using the

 * library.

 *

 * NOTE:  If you are using the DLL version of this library, these functions

 * are automatically called in the DLL's LibMain and WEP, so you should

 * not call them directly from your application.

 */

// Backward compatibility with older library

#define OleUIUninitialize OleUIUnInitialize

STDAPI_(BOOL) OleUIInitialize(HINSTANCE hInstance, HINSTANCE hPrevInst);

STDAPI_(BOOL) OleUIUninitialize(void);

#if !defined( SZCLASSICONBOX )

#define SZCLASSICONBOX  "ole2uiIBCls"

#endif

#if !defined( SZCLASSRESULTIMAGE )

#define SZCLASSRESULTIMAGE  "ole2uiRICls"

#endif

// object count, used to support DllCanUnloadNow and OleUICanUnloadNow

extern DWORD g_dwObjectCount;

STDAPI OleUICanUnloadNow(void);

STDAPI OleUILockLibrary(BOOL fLock);

//Dialog Identifiers as passed in Help messages to identify the source.

#define IDD_INSERTOBJECT        32248

#define IDD_CHANGEICON          32249

#define IDD_CONVERT             32250

#define IDD_PASTESPECIAL        32251

#define IDD_EDITLINKS           32252

#define IDD_FILEOPEN            32253

#define IDD_BUSY                32254

#define IDD_UPDATELINKS         32255

#define IDD_CANNOTUPDATELINK    32256

#define IDD_CHANGESOURCE        32257

#define IDD_INSERTFILEBROWSE    32258

#define IDD_CHANGEICONBROWSE    32259

// The following Dialogs are message dialogs used by OleUIPromptUser API

#define IDD_LINKSOURCEUNAVAILABLE   32260

#define IDD_SERVERNOTREG        32261

#define IDD_LINKTYPECHANGED     32262

#define IDD_SERVERNOTFOUND      32263

#define IDD_OUTOFMEMORY         32264

// Stringtable identifers

#define IDS_OLE2UIUNKNOWN       32300

#define IDS_OLE2UILINK          32301

#define IDS_OLE2UIOBJECT        32302

#define IDS_OLE2UIEDIT          32303

#define IDS_OLE2UICONVERT       32304

#define IDS_OLE2UIEDITLINKCMD_1VERB     32305

#define IDS_OLE2UIEDITOBJECTCMD_1VERB   32306

#define IDS_OLE2UIEDITLINKCMD_NVERB     32307

#define IDS_OLE2UIEDITOBJECTCMD_NVERB   32308

#define IDS_OLE2UIEDITNOOBJCMD  32309

// def. icon label (usu. "Document")

#define IDS_DEFICONLABEL        32310

#define IDS_OLE2UIPASTELINKEDTYPE  32311

#define IDS_FILTERS             32320

#define IDS_ICONFILTERS         32321

#define IDS_BROWSE              32322

//Resource identifiers for bitmaps

#define IDB_RESULTSEGA                  32325

#define IDB_RESULTSVGA                  32326

#define IDB_RESULTSHIRESVGA             32327

//Missing from windows.h

#ifndef PVOID

typedef VOID *PVOID;

#endif

//Hook type used in all structures.

typedef UINT (CALLBACK *LPFNOLEUIHOOK)(HWND, UINT, WPARAM, LPARAM);

//Strings for registered messages

#define SZOLEUI_MSG_HELP                "OLEUI_MSG_HELP"

#define SZOLEUI_MSG_ENDDIALOG           "OLEUI_MSG_ENDDIALOG"

#define SZOLEUI_MSG_BROWSE              "OLEUI_MSG_BROWSE"

#define SZOLEUI_MSG_CHANGEICON          "OLEUI_MSG_CHANGEICON"

#define SZOLEUI_MSG_CLOSEBUSYDIALOG     "OLEUI_MSG_CLOSEBUSYDIALOG"

#define SZOLEUI_MSG_FILEOKSTRING        "OLEUI_MSG_FILEOKSTRING"

//Standard error definitions

#define OLEUI_FALSE                     0

#define OLEUI_SUCCESS                   1     //No error, same as OLEUI_OK

#define OLEUI_OK                        1     //OK button pressed

#define OLEUI_CANCEL                    2     //Cancel button pressed

#define OLEUI_ERR_STANDARDMIN           100

#define OLEUI_ERR_STRUCTURENULL         101   //Standard field validation

#define OLEUI_ERR_STRUCTUREINVALID      102

#define OLEUI_ERR_CBSTRUCTINCORRECT     103

#define OLEUI_ERR_HWNDOWNERINVALID      104

#define OLEUI_ERR_LPSZCAPTIONINVALID    105

#define OLEUI_ERR_LPFNHOOKINVALID       106

#define OLEUI_ERR_HINSTANCEINVALID      107

#define OLEUI_ERR_LPSZTEMPLATEINVALID   108

#define OLEUI_ERR_HRESOURCEINVALID      109

#define OLEUI_ERR_FINDTEMPLATEFAILURE   110   //Initialization errors

#define OLEUI_ERR_LOADTEMPLATEFAILURE   111

#define OLEUI_ERR_DIALOGFAILURE         112

#define OLEUI_ERR_LOCALMEMALLOC         113

#define OLEUI_ERR_GLOBALMEMALLOC        114

#define OLEUI_ERR_LOADSTRING            115

#define OLEUI_ERR_STANDARDMAX           116   //Start here for specific errors.

//Help Button Identifier

#define ID_OLEUIHELP                    99

// Help button for fileopen.dlg  (need this for resizing) 1038 is pshHelp

#define IDHELP  1038

// Static text control (use this instead of -1 so things work correctly for

// localization

#define  ID_STATIC                      98

//Maximum key size we read from the RegDB.

#define OLEUI_CCHKEYMAX                 256  // make any changes to this in geticon.c too

//Maximum verb length and length of Object menu

#define OLEUI_CCHVERBMAX                32

#define OLEUI_OBJECTMENUMAX             256

//Maximum MS-DOS pathname.

#define OLEUI_CCHPATHMAX                256 // make any changes to this in geticon.c too

#define OLEUI_CCHFILEMAX                13

//Icon label length

#define OLEUI_CCHLABELMAX               40  // make any changes to this in geticon.c too

//Length of the CLSID string

#define OLEUI_CCHCLSIDSTRING            39

/*

 * What follows here are first function prototypes for general utility

 * functions, then sections laid out by dialog.  Each dialog section

 * defines the dialog structure, the API prototype, flags for the dwFlags

 * field, the dialog-specific error values, and dialog control IDs (for

 * hooks and custom templates.

 */

//Miscellaneous utility functions.

STDAPI_(BOOL) OleUIAddVerbMenu(LPOLEOBJECT lpOleObj,

                                                         LPSTR lpszShortType,

                                                         HMENU hMenu,

                                                         UINT uPos,

                                                         UINT uIDVerbMin,

                                                         UINT uIDVerbMax,

                                                         BOOL bAddConvert,

                                                         UINT idConvert,

                                                         HMENU FAR *lphMenu);

//Metafile utility functions

#ifdef OBSOLETE

STDAPI_(HGLOBAL) OleUIMetafilePictFromIconAndLabel(HICON, LPSTR, LPSTR, UINT);

#endif // OBSOLETE

STDAPI_(void)    OleUIMetafilePictIconFree(HGLOBAL);

STDAPI_(BOOL)    OleUIMetafilePictIconDraw(HDC, LPRECT, HGLOBAL, BOOL);

STDAPI_(UINT)    OleUIMetafilePictExtractLabel(HGLOBAL, LPSTR, UINT, LPDWORD);

STDAPI_(HICON)   OleUIMetafilePictExtractIcon(HGLOBAL);

STDAPI_(BOOL)    OleUIMetafilePictExtractIconSource(HGLOBAL,LPSTR,UINT FAR *);

/*************************************************************************

** INSERT OBJECT DIALOG

*************************************************************************/

typedef struct tagOLEUIINSERTOBJECT

        {

        //These IN fields are standard across all OLEUI dialog functions.

        DWORD           cbStruct;         //Structure Size

        DWORD           dwFlags;          //IN-OUT:  Flags

        HWND            hWndOwner;        //Owning window

        LPCSTR          lpszCaption;      //Dialog caption bar contents

        LPFNOLEUIHOOK   lpfnHook;         //Hook callback

        LPARAM          lCustData;        //Custom data to pass to hook

        HINSTANCE       hInstance;        //Instance for customized template name

        LPCSTR          lpszTemplate;     //Customized template name

        HRSRC           hResource;        //Customized template handle

        //Specifics for OLEUIINSERTOBJECT.  All are IN-OUT unless otherwise spec.

        CLSID           clsid;            //Return space for class ID

        LPSTR           lpszFile;         //Filename for inserts or links

        UINT            cchFile;          //Size of lpszFile buffer: OLEUI_CCHPATHMAX

        UINT            cClsidExclude;    //IN only:  CLSIDs in lpClsidExclude

        LPCLSID         lpClsidExclude;   //List of CLSIDs to exclude from listing.

        //Specific to create objects if flags say so

        IID             iid;              //Requested interface on creation.

        DWORD           oleRender;        //Rendering option

        LPFORMATETC     lpFormatEtc;      //Desired format

        LPOLECLIENTSITE lpIOleClientSite; //Site to be use for the object.

        LPSTORAGE       lpIStorage;       //Storage used for the object

        LPVOID FAR     *ppvObj;           //Where the object is returned.

        SCODE           sc;               //Result of creation calls.

        HGLOBAL         hMetaPict;        //OUT: METAFILEPICT containing iconic aspect.

                                                                          //IFF we couldn't stuff it in the cache.

        } OLEUIINSERTOBJECT, *POLEUIINSERTOBJECT, FAR *LPOLEUIINSERTOBJECT;

//API prototype

STDAPI_(UINT) OleUIInsertObject(LPOLEUIINSERTOBJECT);

//Insert Object flags

#define IOF_SHOWHELP                0x00000001L

#define IOF_SELECTCREATENEW         0x00000002L

#define IOF_SELECTCREATEFROMFILE    0x00000004L

#define IOF_CHECKLINK               0x00000008L

#define IOF_CHECKDISPLAYASICON      0x00000010L

#define IOF_CREATENEWOBJECT         0x00000020L

#define IOF_CREATEFILEOBJECT        0x00000040L

#define IOF_CREATELINKOBJECT        0x00000080L

#define IOF_DISABLELINK             0x00000100L

#define IOF_VERIFYSERVERSEXIST      0x00000200L

#define IOF_DISABLEDISPLAYASICON    0x00000400L

//Insert Object specific error codes

#define OLEUI_IOERR_LPSZFILEINVALID         (OLEUI_ERR_STANDARDMAX+0)

#define OLEUI_IOERR_LPSZLABELINVALID        (OLEUI_ERR_STANDARDMAX+1)

#define OLEUI_IOERR_HICONINVALID            (OLEUI_ERR_STANDARDMAX+2)

#define OLEUI_IOERR_LPFORMATETCINVALID      (OLEUI_ERR_STANDARDMAX+3)

#define OLEUI_IOERR_PPVOBJINVALID           (OLEUI_ERR_STANDARDMAX+4)

#define OLEUI_IOERR_LPIOLECLIENTSITEINVALID (OLEUI_ERR_STANDARDMAX+5)

#define OLEUI_IOERR_LPISTORAGEINVALID       (OLEUI_ERR_STANDARDMAX+6)

#define OLEUI_IOERR_SCODEHASERROR           (OLEUI_ERR_STANDARDMAX+7)

#define OLEUI_IOERR_LPCLSIDEXCLUDEINVALID   (OLEUI_ERR_STANDARDMAX+8)

#define OLEUI_IOERR_CCHFILEINVALID          (OLEUI_ERR_STANDARDMAX+9)

//Insert Object Dialog identifiers

#define ID_IO_CREATENEW                 2100

#define ID_IO_CREATEFROMFILE            2101

#define ID_IO_LINKFILE                  2102

#define ID_IO_OBJECTTYPELIST            2103

#define ID_IO_DISPLAYASICON             2104

#define ID_IO_CHANGEICON                2105

#define ID_IO_FILE                      2106

#define ID_IO_FILEDISPLAY               2107

#define ID_IO_RESULTIMAGE               2108

#define ID_IO_RESULTTEXT                2109

#define ID_IO_ICONDISPLAY               2110

#define ID_IO_OBJECTTYPETEXT            2111

#define ID_IO_FILETEXT                  2112

#define ID_IO_FILETYPE                  2113

// Strings in OLE2UI resources

#define IDS_IORESULTNEW                 32400

#define IDS_IORESULTNEWICON             32401

#define IDS_IORESULTFROMFILE1           32402

#define IDS_IORESULTFROMFILE2           32403

#define IDS_IORESULTFROMFILEICON2       32404

#define IDS_IORESULTLINKFILE1           32405

#define IDS_IORESULTLINKFILE2           32406

#define IDS_IORESULTLINKFILEICON1       32407

#define IDS_IORESULTLINKFILEICON2       32408

/*************************************************************************

** PASTE SPECIAL DIALOG

*************************************************************************/

// Maximum number of link types

#define     PS_MAXLINKTYPES  8

//NOTE: OLEUIPASTEENTRY and OLEUIPASTEFLAG structs are defined in OLESTD.H

typedef struct tagOLEUIPASTESPECIAL

        {

        //These IN fields are standard across all OLEUI dialog functions.

        DWORD           cbStruct;       //Structure Size

        DWORD           dwFlags;        //IN-OUT:  Flags

        HWND            hWndOwner;      //Owning window

        LPCSTR          lpszCaption;    //Dialog caption bar contents

        LPFNOLEUIHOOK   lpfnHook;       //Hook callback

        LPARAM          lCustData;      //Custom data to pass to hook

        HINSTANCE       hInstance;      //Instance for customized template name

        LPCSTR          lpszTemplate;   //Customized template name

        HRSRC           hResource;      //Customized template handle

        //Specifics for OLEUIPASTESPECIAL.

        //IN  fields

        LPDATAOBJECT    lpSrcDataObj;       //Source IDataObject* (on the

                                                                                // clipboard) for data to paste

        LPOLEUIPASTEENTRY arrPasteEntries;  //OLEUIPASTEENTRY array which

                                                                                // specifies acceptable formats. See

                                                                                // OLEUIPASTEENTRY for more info.

        int             cPasteEntries;      //No. of OLEUIPASTEENTRY array entries

        UINT        FAR *arrLinkTypes;      //List of link types that are

                                                                                // acceptable. Link types are referred

                                                                                // to using OLEUIPASTEFLAGS in

                                                                                // arrPasteEntries

        int             cLinkTypes;         //Number of link types

        UINT            cClsidExclude;      //Number of CLSIDs in lpClsidExclude

        LPCLSID         lpClsidExclude;     //List of CLSIDs to exclude from list.

        //OUT fields

        int             nSelectedIndex;     //Index of arrPasteEntries[] that the

                                                                                // user selected

        BOOL            fLink;              //Indicates if Paste or Paste Link was

                                                                                // selected by the user

        HGLOBAL         hMetaPict;          //Handle to Metafile containing icon

                                                                                // and icon title selected by the user

                                                                                // Use the Metafile utility functions

                                                                                // defined in this header to

                                                                                // manipulate hMetaPict

        SIZEL           sizel;              // size of object/link in its source

                                                                                //  if the display aspect chosen by

                                                                                //  the user matches the aspect

                                                                                //  displayed in the source. if

                                                                                //  different aspect is chosen then

                                                                                //  sizel.cx=sizel.cy=0 is returned.

                                                                                //  sizel displayed in source is

                                                                                //  retrieved from the

                                                                                //  ObjectDescriptor if fLink is FALSE

                                                                                //  LinkSrcDescriptor if fLink is TRUE

        } OLEUIPASTESPECIAL, *POLEUIPASTESPECIAL, FAR *LPOLEUIPASTESPECIAL;

//API to bring up PasteSpecial dialog

STDAPI_(UINT) OleUIPasteSpecial(LPOLEUIPASTESPECIAL);

//Paste Special flags

// Show Help button. IN flag.

#define PSF_SHOWHELP                0x00000001L

//Select Paste radio button at dialog startup. This is the default if

// PSF_SELECTPASTE or PSF_SELECTPASTELINK are not specified. Also specifies

// state of button on dialog termination. IN/OUT flag.

#define PSF_SELECTPASTE             0x00000002L

//Select PasteLink radio button at dialog startup. Also specifies state of

// button on dialog termination. IN/OUT flag.

#define PSF_SELECTPASTELINK         0x00000004L

//Specfies if DisplayAsIcon button was checked on dialog termination. OUT flag

#define PSF_CHECKDISPLAYASICON      0x00000008L

#define PSF_DISABLEDISPLAYASICON    0x00000010L

//Paste Special specific error codes

#define OLEUI_IOERR_SRCDATAOBJECTINVALID      (OLEUI_ERR_STANDARDMAX+0)

#define OLEUI_IOERR_ARRPASTEENTRIESINVALID    (OLEUI_ERR_STANDARDMAX+1)

#define OLEUI_IOERR_ARRLINKTYPESINVALID       (OLEUI_ERR_STANDARDMAX+2)

#define OLEUI_PSERR_CLIPBOARDCHANGED          (OLEUI_ERR_STANDARDMAX+3)

//Paste Special Dialog identifiers

#define ID_PS_PASTE                    500

#define ID_PS_PASTELINK                501

#define ID_PS_SOURCETEXT               502

#define ID_PS_PASTELIST                503

#define ID_PS_PASTELINKLIST            504

#define ID_PS_DISPLAYLIST              505

#define ID_PS_DISPLAYASICON            506

#define ID_PS_ICONDISPLAY              507

#define ID_PS_CHANGEICON               508

#define ID_PS_RESULTIMAGE              509

#define ID_PS_RESULTTEXT               510

#define ID_PS_RESULTGROUP              511

#define ID_PS_STXSOURCE                512

#define ID_PS_STXAS                    513

// Paste Special String IDs

#define IDS_PSPASTEDATA                32410

#define IDS_PSPASTEOBJECT              32411

#define IDS_PSPASTEOBJECTASICON        32412

#define IDS_PSPASTELINKDATA            32413

#define IDS_PSPASTELINKOBJECT          32414

#define IDS_PSPASTELINKOBJECTASICON    32415

#define IDS_PSNONOLE                   32416

#define IDS_PSUNKNOWNTYPE              32417

#define IDS_PSUNKNOWNSRC               32418

#define IDS_PSUNKNOWNAPP               32419

/*************************************************************************

** EDIT LINKS DIALOG

*************************************************************************/

/* IOleUILinkContainer Interface

** -----------------------------

**    This interface must be implemented by container applications that

**    want to use the EditLinks dialog. the EditLinks dialog calls back

**    to the container app to perform the OLE functions to manipulate

**    the links within the container.

*/

#define LPOLEUILINKCONTAINER     IOleUILinkContainer FAR*

#undef  INTERFACE

#define INTERFACE   IOleUILinkContainer

DECLARE_INTERFACE_(IOleUILinkContainer, IUnknown)

{

        //*** IUnknown methods ***/

        STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE;

        STDMETHOD_(ULONG,AddRef) (THIS) PURE;

        STDMETHOD_(ULONG,Release) (THIS) PURE;

        STDMETHOD_(DWORD,GetNextLink) (THIS_ DWORD dwLink) PURE;

        STDMETHOD(SetLinkUpdateOptions) (THIS_ DWORD dwLink, DWORD dwUpdateOpt) PURE;

        STDMETHOD(GetLinkUpdateOptions) (THIS_ DWORD dwLink, DWORD FAR* lpdwUpdateOpt) PURE;

        STDMETHOD(SetLinkSource) (THIS_

                        DWORD       dwLink,

                        LPSTR       lpszDisplayName,

                        ULONG       lenFileName,

                        ULONG FAR*  pchEaten,

                        BOOL        fValidateSource) PURE;

        STDMETHOD(GetLinkSource) (THIS_

                        DWORD       dwLink,

                        LPSTR FAR*  lplpszDisplayName,

                        ULONG FAR*  lplenFileName,

                        LPSTR FAR*  lplpszFullLinkType,

                        LPSTR FAR*  lplpszShortLinkType,

                        BOOL FAR*   lpfSourceAvailable,

                        BOOL FAR*   lpfIsSelected) PURE;

        STDMETHOD(OpenLinkSource) (THIS_ DWORD dwLink) PURE;

        STDMETHOD(UpdateLink) (THIS_

                        DWORD dwLink,

                        BOOL fErrorMessage,

                        BOOL fErrorAction) PURE;

        STDMETHOD(CancelLink) (THIS_ DWORD dwLink) PURE;

};

typedef struct tagOLEUIEDITLINKS

        {

        //These IN fields are standard across all OLEUI dialog functions.

        DWORD           cbStruct;       //Structure Size

        DWORD           dwFlags;        //IN-OUT:  Flags

        HWND            hWndOwner;      //Owning window

        LPCSTR          lpszCaption;    //Dialog caption bar contents

        LPFNOLEUIHOOK   lpfnHook;       //Hook callback

        LPARAM          lCustData;      //Custom data to pass to hook

        HINSTANCE       hInstance;      //Instance for customized template name

        LPCSTR          lpszTemplate;   //Customized template name

        HRSRC           hResource;      //Customized template handle

        //Specifics for OLEUI<STRUCT>.  All are IN-OUT unless otherwise spec.

        LPOLEUILINKCONTAINER lpOleUILinkContainer;  //IN: Interface to manipulate

                                                                                                //links in the container

        } OLEUIEDITLINKS, *POLEUIEDITLINKS, FAR *LPOLEUIEDITLINKS;

//API Prototype

STDAPI_(UINT) OleUIEditLinks(LPOLEUIEDITLINKS);

// Edit Links flags

#define ELF_SHOWHELP                0x00000001L

#define ELF_DISABLEUPDATENOW        0x00000002L

#define ELF_DISABLEOPENSOURCE       0x00000004L

#define ELF_DISABLECHANGESOURCE     0x00000008L

#define ELF_DISABLECANCELLINK       0x00000010L

// Edit Links Dialog identifiers

#define ID_EL_CHANGESOURCE             201

#define ID_EL_AUTOMATIC                202

#define ID_EL_CLOSE                    208

#define ID_EL_CANCELLINK               209

#define ID_EL_UPDATENOW                210

#define ID_EL_OPENSOURCE               211

#define ID_EL_MANUAL                   212

#define ID_EL_LINKSOURCE               216

#define ID_EL_LINKTYPE                 217

#define ID_EL_UPDATE                   218

#define ID_EL_NULL                     -1

#define ID_EL_LINKSLISTBOX             206

#define ID_EL_COL1                     220

#define ID_EL_COL2                     221

#define ID_EL_COL3                     222

/*************************************************************************

** CHANGE ICON DIALOG

*************************************************************************/

typedef struct tagOLEUICHANGEICON

        {

        //These IN fields are standard across all OLEUI dialog functions.

        DWORD           cbStruct;       //Structure Size

        DWORD           dwFlags;        //IN-OUT:  Flags

        HWND            hWndOwner;      //Owning window

        LPCSTR          lpszCaption;    //Dialog caption bar contents

        LPFNOLEUIHOOK   lpfnHook;       //Hook callback

        LPARAM          lCustData;      //Custom data to pass to hook

        HINSTANCE       hInstance;      //Instance for customized template name

        LPCSTR          lpszTemplate;   //Customized template name

        HRSRC           hResource;      //Customized template handle

        //Specifics for OLEUICHANGEICON.  All are IN-OUT unless otherwise spec.

        HGLOBAL         hMetaPict;      //Current and final image.  Source of the

                                                                        //icon is embedded in the metafile itself.

        CLSID           clsid;          //IN only: class used to get Default icon

        char            szIconExe[OLEUI_CCHPATHMAX];

        int             cchIconExe;

        } OLEUICHANGEICON, *POLEUICHANGEICON, FAR *LPOLEUICHANGEICON;

//API prototype

STDAPI_(UINT) OleUIChangeIcon(LPOLEUICHANGEICON);

//Change Icon flags

#define CIF_SHOWHELP                0x00000001L

#define CIF_SELECTCURRENT           0x00000002L

#define CIF_SELECTDEFAULT           0x00000004L

#define CIF_SELECTFROMFILE          0x00000008L

#define CIF_USEICONEXE              0x0000000aL

//Change Icon specific error codes

#define OLEUI_CIERR_MUSTHAVECLSID           (OLEUI_ERR_STANDARDMAX+0)

#define OLEUI_CIERR_MUSTHAVECURRENTMETAFILE (OLEUI_ERR_STANDARDMAX+1)

#define OLEUI_CIERR_SZICONEXEINVALID        (OLEUI_ERR_STANDARDMAX+2)

//Change Icon Dialog identifiers

#define ID_GROUP                    120

#define ID_CURRENT                  121

#define ID_CURRENTICON              122

#define ID_DEFAULT                  123

#define ID_DEFAULTICON              124

#define ID_FROMFILE                 125

#define ID_FROMFILEEDIT             126

#define ID_ICONLIST                 127

#define ID_LABEL                    128

#define ID_LABELEDIT                129

#define ID_BROWSE                   130

#define ID_RESULTICON               132

#define ID_RESULTLABEL              133

// Stringtable defines for Change Icon

#define IDS_CINOICONSINFILE         32430

#define IDS_CIINVALIDFILE           32431

#define IDS_CIFILEACCESS            32432

#define IDS_CIFILESHARE             32433

#define IDS_CIFILEOPENFAIL          32434

/*************************************************************************

** CONVERT DIALOG

*************************************************************************/

typedef struct tagOLEUICONVERT

        {

        //These IN fields are standard across all OLEUI dialog functions.

        DWORD           cbStruct;         //Structure Size

        DWORD           dwFlags;          //IN-OUT:  Flags

        HWND            hWndOwner;        //Owning window

        LPCSTR          lpszCaption;      //Dialog caption bar contents

        LPFNOLEUIHOOK   lpfnHook;         //Hook callback

        LPARAM          lCustData;        //Custom data to pass to hook

        HINSTANCE       hInstance;        //Instance for customized template name

        LPCSTR          lpszTemplate;     //Customized template name

        HRSRC           hResource;        //Customized template handle

        //Specifics for OLEUICONVERT.  All are IN-OUT unless otherwise spec.

        CLSID           clsid;            //Class ID sent in to dialog: IN only

        CLSID           clsidConvertDefault;  //Class ID to use as convert default: IN only

        CLSID           clsidActivateDefault;  //Class ID to use as activate default: IN only

        CLSID           clsidNew;         //Selected Class ID: OUT only

        DWORD           dvAspect;         //IN-OUT, either DVASPECT_CONTENT or

                                                                          //DVASPECT_ICON

        WORD            wFormat;          //Original data format

        BOOL            fIsLinkedObject;  //IN only; true if object is linked

        HGLOBAL         hMetaPict;        //IN-OUT: METAFILEPICT containing iconic aspect.

        LPSTR           lpszUserType;     //IN-OUT: user type name of original class.

                                                                          //  We'll do lookup if it's NULL.

                                                                          //  This gets freed on exit.

        BOOL            fObjectsIconChanged;  // OUT; TRUE if ChangeIcon was called (and not cancelled)

        LPSTR           lpszDefLabel;     //IN-OUT: default label to use for icon.

                                                                          //  if NULL, the short user type name

                                                                          //  will be used. if the object is a

                                                                          //  link, the caller should pass the

                                                                          //  DisplayName of the link source

                                                                          //  This gets freed on exit.

        UINT            cClsidExclude;    //IN: No. of CLSIDs in lpClsidExclude

        LPCLSID         lpClsidExclude;   //IN: List of CLSIDs to exclude from list

        } OLEUICONVERT, *POLEUICONVERT, FAR *LPOLEUICONVERT;

//API prototype

STDAPI_(UINT) OleUIConvert(LPOLEUICONVERT);

// Determine if there is at least one class that can Convert or ActivateAs

// the given clsid.

STDAPI_(BOOL) OleUICanConvertOrActivateAs(

                REFCLSID    rClsid,

                BOOL        fIsLinkedObject,

                WORD        wFormat

);

//Convert Dialog flags

// IN only: Shows "HELP" button

#define CF_SHOWHELPBUTTON          0x00000001L

// IN only: lets you set the convert default object - the one that is

// selected as default in the convert listbox.

#define CF_SETCONVERTDEFAULT       0x00000002L

// IN only: lets you set the activate default object - the one that is

// selected as default in the activate listbox.

#define CF_SETACTIVATEDEFAULT       0x00000004L

// IN/OUT: Selects the "Convert To" radio button, is set on exit if

// this button was selected

#define CF_SELECTCONVERTTO         0x00000008L

// IN/OUT: Selects the "Activate As" radio button, is set on exit if

// this button was selected

#define CF_SELECTACTIVATEAS        0x00000010L

#define CF_DISABLEDISPLAYASICON    0x00000020L

#define CF_DISABLEACTIVATEAS       0x00000040L

//Convert specific error codes

#define OLEUI_CTERR_CLASSIDINVALID      (OLEUI_ERR_STANDARDMAX+1)

#define OLEUI_CTERR_DVASPECTINVALID     (OLEUI_ERR_STANDARDMAX+2)

#define OLEUI_CTERR_CBFORMATINVALID     (OLEUI_ERR_STANDARDMAX+3)

#define OLEUI_CTERR_HMETAPICTINVALID    (OLEUI_ERR_STANDARDMAX+4)

#define OLEUI_CTERR_STRINGINVALID       (OLEUI_ERR_STANDARDMAX+5)

//Convert Dialog identifiers

#define IDCV_OBJECTTYPE             150

#define IDCV_DISPLAYASICON          152

#define IDCV_CHANGEICON             153

#define IDCV_ACTIVATELIST           154

#define IDCV_CONVERTTO              155

#define IDCV_ACTIVATEAS             156

#define IDCV_RESULTTEXT             157

#define IDCV_CONVERTLIST            158

#define IDCV_ICON                   159

#define IDCV_ICONLABEL1             160

#define IDCV_ICONLABEL2             161

#define IDCV_STXCURTYPE             162

#define IDCV_GRPRESULT              163

#define IDCV_STXCONVERTTO           164

// String IDs for Convert dialog

#define IDS_CVRESULTCONVERTLINK     32440

#define IDS_CVRESULTCONVERTTO       32441

#define IDS_CVRESULTNOCHANGE        32442

#define IDS_CVRESULTDISPLAYASICON   32443

#define IDS_CVRESULTACTIVATEAS      32444

#define IDS_CVRESULTACTIVATEDIFF    32445

/*************************************************************************

** BUSY DIALOG

*************************************************************************/

typedef struct tagOLEUIBUSY

        {

        //These IN fields are standard across all OLEUI dialog functions.

        DWORD           cbStruct;         //Structure Size

        DWORD           dwFlags;          //IN-OUT:  Flags ** NOTE ** this dialog has no flags

        HWND            hWndOwner;        //Owning window

        LPCSTR          lpszCaption;      //Dialog caption bar contents

        LPFNOLEUIHOOK   lpfnHook;         //Hook callback

        LPARAM          lCustData;        //Custom data to pass to hook

        HINSTANCE       hInstance;        //Instance for customized template name

        LPCSTR          lpszTemplate;     //Customized template name

        HRSRC           hResource;        //Customized template handle

        //Specifics for OLEUIBUSY.

        HTASK           hTask;            //IN: HTask which is blocking

        HWND FAR *      lphWndDialog;     //IN: Dialog's HWND is placed here

        } OLEUIBUSY, *POLEUIBUSY, FAR *LPOLEUIBUSY;

//API prototype

STDAPI_(UINT) OleUIBusy(LPOLEUIBUSY);

// Flags for this dialog

// IN only: Disables "Cancel" button

#define BZ_DISABLECANCELBUTTON          0x00000001L

// IN only: Disables "Switch To..." button

#define BZ_DISABLESWITCHTOBUTTON        0x00000002L

// IN only: Disables "Retry" button

#define BZ_DISABLERETRYBUTTON           0x00000004L

// IN only: Generates a "Not Responding" dialog as opposed to the

// "Busy" dialog.  The wording in the text is slightly different, and

// the "Cancel" button is grayed out if you set this flag.

#define BZ_NOTRESPONDINGDIALOG          0x00000008L

// Busy specific error/return codes

#define OLEUI_BZERR_HTASKINVALID     (OLEUI_ERR_STANDARDMAX+0)

// SWITCHTOSELECTED is returned when user hit "switch to"

#define OLEUI_BZ_SWITCHTOSELECTED    (OLEUI_ERR_STANDARDMAX+1)

// RETRYSELECTED is returned when user hit "retry"

#define OLEUI_BZ_RETRYSELECTED       (OLEUI_ERR_STANDARDMAX+2)

// CALLUNBLOCKED is returned when call has been unblocked

#define OLEUI_BZ_CALLUNBLOCKED       (OLEUI_ERR_STANDARDMAX+3)

// Busy dialog identifiers

#define IDBZ_RETRY                      600

#define IDBZ_ICON                       601

#define IDBZ_MESSAGE1                   602

#define IDBZ_SWITCHTO                   604

// Busy dialog stringtable defines

#define IDS_BZRESULTTEXTBUSY            32447

#define IDS_BZRESULTTEXTNOTRESPONDING   32448

// Links dialog stringtable defines

#define IDS_LINK_AUTO           32450

#define IDS_LINK_MANUAL         32451

#define IDS_LINK_UNKNOWN        32452

#define IDS_LINKS               32453

#define IDS_FAILED              32454

#define IDS_CHANGESOURCE        32455

#define IDS_INVALIDSOURCE       32456

#define IDS_ERR_GETLINKSOURCE   32457

#define IDS_ERR_GETLINKUPDATEOPTIONS    32458

#define IDS_ERR_ADDSTRING       32459

#define IDS_CHANGEADDITIONALLINKS   32460

#define IDS_CLOSE               32461

/*************************************************************************

** PROMPT USER DIALOGS

*************************************************************************/

#define ID_PU_LINKS             900

#define ID_PU_TEXT              901

#define ID_PU_CONVERT           902

#define ID_PU_BROWSE            904

#define ID_PU_METER             905

#define ID_PU_PERCENT           906

#define ID_PU_STOP              907

// used for -1 ids in dialogs:

#define ID_DUMMY    999

/* inside ole2ui.c */

#ifdef __cplusplus

extern "C"

#endif

int EXPORT FAR CDECL OleUIPromptUser(WORD nTemplate, HWND hwndParent, ...);

#define UPDATELINKS_STARTDELAY  2000    // Delay before 1st link updates

                                                                                //  to give the user a chance to

                                                                                //  dismiss the dialog before any

                                                                                //  links update.

STDAPI_(BOOL) OleUIUpdateLinks(

                LPOLEUILINKCONTAINER lpOleUILinkCntr,

                HWND hwndParent,

                LPSTR lpszTitle,

                int cLinks);

/*************************************************************************

** OLE OBJECT FEEDBACK EFFECTS

*************************************************************************/

#define OLEUI_HANDLES_USEINVERSE    0x00000001L

#define OLEUI_HANDLES_NOBORDER      0x00000002L

#define OLEUI_HANDLES_INSIDE        0x00000004L

#define OLEUI_HANDLES_OUTSIDE       0x00000008L

#define OLEUI_SHADE_FULLRECT        1

#define OLEUI_SHADE_BORDERIN        2

#define OLEUI_SHADE_BORDEROUT       3

/* objfdbk.c function prototypes */

STDAPI_(void) OleUIDrawHandles(LPRECT lpRect, HDC hdc, DWORD dwFlags, UINT cSize, BOOL fDraw);

STDAPI_(void) OleUIDrawShading(LPRECT lpRect, HDC hdc, DWORD dwFlags, UINT cWidth);

STDAPI_(void) OleUIShowObject(LPCRECT lprc, HDC hdc, BOOL fIsLink);

/*************************************************************************

** Hatch window definitions and prototypes                              **

*************************************************************************/

#define DEFAULT_HATCHBORDER_WIDTH   4

STDAPI_(BOOL) RegisterHatchWindowClass(HINSTANCE hInst);

STDAPI_(HWND) CreateHatchWindow(HWND hWndParent, HINSTANCE hInst);

STDAPI_(UINT) GetHatchWidth(HWND hWndHatch);

STDAPI_(void) GetHatchRect(HWND hWndHatch, LPRECT lpHatchRect);

STDAPI_(void) SetHatchRect(HWND hWndHatch, LPRECT lprcHatchRect);

STDAPI_(void) SetHatchWindowSize(

                HWND        hWndHatch,

                LPRECT      lprcIPObjRect,

                LPRECT      lprcClipRect,

                LPPOINT     lpptOffset

);

/*************************************************************************

** VERSION VERIFICATION INFORMATION

*************************************************************************/

// The following magic number is used to verify that the resources we bind

// to our EXE are the same "version" as the LIB (or DLL) file which

// contains these routines.  This is not the same as the Version information

// resource that we place in OLE2UI.RC, this is a special ID that we will

// have compiled in to our EXE.  Upon initialization of OLE2UI, we will

// look in our resources for an RCDATA called "VERIFICATION" (see OLE2UI.RC),

// and make sure that the magic number there equals the magic number below.

#define OLEUI_VERSION_MAGIC 0x4D42

#endif  //_OLE2UI_H_


 OLE2UI.RC  (WRAPUI Sample)

/*

 * OLE2UI.RC

 *

 * Icon, menus, strings, and dialogs for the OLE 2.0 UI Support Library.

 *

 * Copyright (c)1992 Microsoft Corporation, All Right Reserved

 */

#undef PURE

#include "ole2ui.h"

//Bitmaps for ResultImage control

IDB_RESULTSEGA      BITMAP  egares.bmp

IDB_RESULTSVGA      BITMAP  vgares.bmp

IDB_RESULTSHIRESVGA BITMAP  hivgares.bmp

// Version Verification Resource (see OLE2UI.H)

VERIFICATION RCDATA

BEGIN

  OLEUI_VERSION_MAGIC

END

//Include string tables here.

#include "strings.rc"

//Include each dialog template here.

#include "insobj.dlg"

#include "icon.dlg"

#include "links.dlg"

#include "pastespl.dlg"

#include "busy.dlg"

#include "convert.dlg"

#include "fileopen.dlg"

#include "prompt.dlg"

// Only include the version resource if we are compiling the DLL version

#ifdef DLL_VER

//Version Information

#include "RES\OLE2UI.RCV"

#endif


 OLE2UI.C  (WRAPUI Sample)

/*

 * OLE2UI.C

 *

 * Contains initialization routines and miscellaneous API implementations for

 * the OLE 2.0 User Interface Support Library.

 *

 * Copyright (c)1992 Microsoft Corporation, All Right Reserved

 */

#define STRICT  1

#include "ole2ui.h"

#include "common.h"

#include "utility.h"

#include "resimage.h"

#include "iconbox.h"

#include <commdlg.h>

#define WINDLL  1           // make far pointer version of stdargs.h

#include <stdarg.h>

// NOTE: If this code is being compiled for a DLL, then we need to define

// our OLE2UI debug symbols here (with the OLEDBGDATA_MAIN macro).  If we're

// compiling for a static LIB, then the application we link to must

// define these symbols -- we just need to make an external reference here

// (with the macro OLEDBGDATA).

#ifdef DLL_VER

OLEDBGDATA_MAIN("OLE2UI")

#else

OLEDBGDATA

#endif

#if defined( _DEBUG ) && !defined( DLL_VER )

// This dummy variable is needed in order for the static link version

// of this library to work correctly.  When we include PRECOMP.OBJ

// in our library (.LIB file), it will only get linked into our

// application IF at least one symbol in precomp.c is referenced from

// either our EXE or LIB.  Therefore, we will define a variable in

// PRECOMP.C and reference it in OLE2UI.C which includes the function

// OleUIInitialize which MUST be called by the static lib user.

extern int near g_nOleUIStaticLibDummy;

int near* g_pnOleUIStaticLibDummy = &g_nOleUIStaticLibDummy;

#endif

//The DLL instance handle shared amongst all dialogs.

HINSTANCE     ghInst;

// object count, used to support DllCanUnloadNow and OleUICanUnloadNow

DWORD g_dwObjectCount=0;

DWORD g_dwLockCount=0;

//Registered messages for use with all the dialogs, registered in LibMain

UINT        uMsgHelp=0;

UINT        uMsgEndDialog=0;

UINT        uMsgBrowse=0;

UINT        uMsgChangeIcon=0;

UINT        uMsgFileOKString=0;

UINT        uMsgCloseBusyDlg=0;

//Clipboard formats used by PasteSpecial

UINT  cfObjectDescriptor;

UINT  cfLinkSrcDescriptor;

UINT  cfEmbedSource;

UINT  cfEmbeddedObject;

UINT  cfLinkSource;

UINT  cfOwnerLink;

UINT  cfFileName;

// local function prototypes

BOOL CALLBACK EXPORT PromptUserDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam);

BOOL CALLBACK EXPORT UpdateLinksDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam);

// local definition

#define WM_U_UPDATELINK WM_USER

// local structure definition

typedef struct tagUPDATELINKS

{

LPOLEUILINKCONTAINER    lpOleUILinkCntr;    // pointer to Link Container

UINT                    cLinks;             // total number of links

UINT                    cUpdated;           // number of links updated

DWORD                   dwLink;             // pointer to link

BOOL                    fError;             // error flag

LPSTR                   lpszTitle;          // caption for dialog box

} UPDATELINKS, *PUPDATELINKS, FAR *LPUPDATELINKS;

/*

 * OleUIInitialize

 *

 * NOTE: This function should only be called by your application IF it is

 * using the static-link version of this library.  If the DLL version is

 * being used, this function is automatically called from the OLE2UI DLL's

 * LibMain.

 *

 * Purpose:

 *   Initializes the OLE UI Library.

 *

 * Parameters:

 *

 *  hInstance       HINSTANCE of the module where the UI library resources

 *                  and Dialog Procedures are contained.  If you are calling

 *                  this function yourself, this should be the instance handle

 *                  of your application.

 *

 *  hPrevInst       HINSTANCE of the previous application instance.

 *                  This is the parameter passed in to your WinMain.  For

 *                  the DLL version, this should always be set to zero (for

 *                  WIN16 DLLs).

 *

 * Return Value:

 *  BOOL            TRUE if initialization was successful.

 *                  FALSE if either the "Magic Number" did not verify, or one of

 *                  the window classes could not be registered.  If the

 *                  "Magic Number" did not verify, then the resources

 *                  in your module are of a different version than the

 *                  ones you compiled with.

 */

STDAPI_(BOOL) OleUIInitialize(HINSTANCE hInstance, HINSTANCE hPrevInst)

{

HRSRC   hr;

HGLOBAL hg;

LPWORD lpdata;

OleDbgOut1("OleUIInitialize called.\r\n");

ghInst=hInstance;

// Verify that we have the correct resources added to our application

// by checking the "VERIFICATION" resource with the magic number we've

// compiled into our app.

if ((hr = FindResource(hInstance, "VERIFICATION", RT_RCDATA)) == NULL)

goto ResourceLoadError;

if ((hg = LoadResource(hInstance, hr)) == NULL)

goto ResourceLoadError;

if ((lpdata = (LPWORD)LockResource(hg)) == NULL)

goto ResourceLockError;

if ((WORD)*lpdata != (WORD)OLEUI_VERSION_MAGIC)

goto ResourceReadError;

// OK, resource versions match.  Contine on.

UnlockResource(hg);

FreeResource(hg);

OleDbgOut1("OleUIInitialize: Resource magic number verified.\r\n");

// Register messages we need for the dialogs.  If

uMsgHelp      =RegisterWindowMessage(SZOLEUI_MSG_HELP);

uMsgEndDialog =RegisterWindowMessage(SZOLEUI_MSG_ENDDIALOG);

uMsgBrowse    =RegisterWindowMessage(SZOLEUI_MSG_BROWSE);

uMsgChangeIcon=RegisterWindowMessage(SZOLEUI_MSG_CHANGEICON);

uMsgFileOKString = RegisterWindowMessage(FILEOKSTRING);

uMsgCloseBusyDlg = RegisterWindowMessage(SZOLEUI_MSG_CLOSEBUSYDIALOG);

// Register Clipboard Formats used by PasteSpecial dialog.

cfObjectDescriptor = RegisterClipboardFormat(CF_OBJECTDESCRIPTOR);

cfLinkSrcDescriptor= RegisterClipboardFormat(CF_LINKSRCDESCRIPTOR);

cfEmbedSource      = RegisterClipboardFormat(CF_EMBEDSOURCE);

cfEmbeddedObject   = RegisterClipboardFormat(CF_EMBEDDEDOBJECT);

cfLinkSource       = RegisterClipboardFormat(CF_LINKSOURCE);

cfOwnerLink        = RegisterClipboardFormat(CF_OWNERLINK);

cfFileName         = RegisterClipboardFormat(CF_FILENAME);

if (!FResultImageInitialize(hInstance, hPrevInst, SZCLASSRESULTIMAGE))

{

OleDbgOut1("OleUIInitialize: FResultImageInitialize failed. Terminating.\r\n");

return 0;

}

if (!FIconBoxInitialize(hInstance, hPrevInst, SZCLASSICONBOX))

{

OleDbgOut1("OleUIInitialize: FIconBoxInitialize failed. Terminating.\r\n");

return 0;

}

return TRUE;

ResourceLoadError:

OleDbgOut1("OleUIInitialize: ERROR - Unable to find version verification resource.\r\n");

return FALSE;

ResourceLockError:

OleDbgOut1("OleUIInitialize: ERROR - Unable to lock version verification resource.\r\n");

FreeResource(hg);

return FALSE;

ResourceReadError:

OleDbgOut1("OleUIInitialize: ERROR - Version verification values did not compare.\r\n");

{char buf[255];

wsprintf(buf, "resource read 0x%X, my value is 0x%X\n", (WORD)*lpdata, (WORD)OLEUI_VERSION_MAGIC);

OutputDebugString(buf);

}

UnlockResource(hg);

FreeResource(hg);

return FALSE;

}

/*

 * OleUIUnInitialize

 *

 * NOTE: This function should only be called by your application IF it is using

 * the static-link version of this library.  If the DLL version is being used,

 * this function is automatically called from the DLL's LibMain.

 *

 * Purpose:

 *   Uninitializes OLE UI libraries.  Deletes any resources allocated by the

 *   library.

 *

 * Return Value:

 *   BOOL       TRUE if successful, FALSE if not.  Current implementation always

 *              returns TRUE.

 */

STDAPI_(BOOL) OleUIUnInitialize()

{

IconBoxUninitialize();

ResultImageUninitialize();

return TRUE;

}

/*

 * OleUICanUnloadNow

 *

 * NOTE: if you statically link to this library and you implement

 *       DllCanUnloadNow, then you must call this routine in your

 *       implementation of DllCanUnloadNow to determine if you can be

 *       unloaded or not.

 *       this function should NOT be used if the OLE2UI library is used

 *       in DLL form.

 *

 * Purpose:

 *   Determines when it is safe to go away

 *   (ie. there are no existing object instances).

 *

 * Return Value:

 *   HRESULT    NOERROR it is safe to go away, S_FALSE this code must stay

 *              loaded.

 *

 * Comments:

 *

 *   If an INPROC server DLL links to the OLE2UI library as a static

 *   library, then the OleUILockLibrary function should NOT be used.

 *   instead the INPROC server DLL should call OleUICanUnloadNow API from

 *   within its own DllCanUnloadNow function. The idea here is, that if there

 *   are any existing instance of objects created by the OLE2UI library

 *   functions (eg. EnumFORMATETC objects created by OleStdEnumFmtEtc_Create)

 *   then, the INPROC server DLL must NOT let itself be unloaded.

 *

 *   An EXE based object using the OLE2UI libray need NOT use either the

 *   OleUILockLibrary or OleUICanUnloadNow functions. All objects created

 *   by the OLE2UI library will have LRPC proxies and stubs created to

 *   manage remoting method calls. the worst that can happen when the EXE

 *   exits is that any outstanding proxies for unreleased objects will get

 *   RPC_E_SERVERDIED errors; they will not GPFault.

 */

STDAPI OleUICanUnloadNow()

{

  if (g_dwObjectCount == 0) {

return NOERROR;

  }

  return ResultFromScode(S_FALSE);

}

/*

 * OleUIAddVerbMenu

 *

 * Purpose:

 *  Add the Verb menu for the specified object to the given menu.  If the

 *  object has one verb, we directly add the verb to the given menu.  If

 *  the object has multiple verbs we create a cascading sub-menu.

 *

 * Parameters:

 *  lpObj           LPOLEOBJECT pointing to the selected object.  If this

 *                  is NULL, then we create a default disabled menu item.

 *

 *  lpszShortType   LPSTR with short type name (AuxName==2) corresponding

 *                  to the lpOleObj. if the string is NOT known, then NULL

 *                  may be passed. if NULL is passed, then

 *                  IOleObject::GetUserType will be called to retrieve it.

 *                  if the caller has the string handy, then it is faster

 *                  to pass it in.

 *

 *  hMenu           HMENU in which to make modifications.

 *

 *  uPos            Position of the menu item

 *

 *  uIDVerbMin      UINT ID value at which to start the verbs.

 *                      verb_0 = wIDMVerbMin + verb_0

 *                      verb_1 = wIDMVerbMin + verb_1

 *                      verb_2 = wIDMVerbMin + verb_2

 *                      etc.

 *  uIDVerbMax      UINT maximum ID value allowed for object verbs.

 *                     if uIDVerbMax==0 then any ID value is allowed

 *

 *  bAddConvert     BOOL specifying whether or not to add a "Convert" item

 *                  to the bottom of the menu (with a separator).

 *

 *  idConvert       UINT ID value to use for the Convert menu item, if

 *                  bAddConvert is TRUE.

 *

 *  lphMenu         HMENU FAR * of the cascading verb menu if it's created.

 *                  If there is only one verb, this will be filled with NULL.

 *

 *

 * Return Value:

 *  BOOL            TRUE if lpObj was valid and we added at least one verb

 *                  to the menu.  FALSE if lpObj was NULL and we created

 *                  a disabled default menu item

 */

STDAPI_(BOOL) OleUIAddVerbMenu(LPOLEOBJECT lpOleObj,

 LPSTR lpszShortType,

 HMENU hMenu,

 UINT uPos,

 UINT uIDVerbMin,

 UINT uIDVerbMax,

 BOOL bAddConvert,

 UINT idConvert,

 HMENU FAR *lphMenu)

{

LPPERSISTSTORAGE    lpPS=NULL;

LPENUMOLEVERB       lpEnumOleVerb = NULL;

OLEVERB             oleverb;

LPUNKNOWN           lpUnk;

LPSTR               lpszShortTypeName = lpszShortType;

LPSTR               lpszVerbName = NULL;

HRESULT             hrErr;

BOOL                fStatus;

BOOL                fIsLink = FALSE;

BOOL                fResult = TRUE;

BOOL                fAddConvertItem = FALSE;

int                 cVerbs = 0;

UINT                uFlags = MF_BYPOSITION;

static BOOL         fFirstTime = TRUE;

static char         szBuffer[OLEUI_OBJECTMENUMAX];

static char         szNoObjectCmd[OLEUI_OBJECTMENUMAX];

static char         szObjectCmd1Verb[OLEUI_OBJECTMENUMAX];

static char         szLinkCmd1Verb[OLEUI_OBJECTMENUMAX];

static char         szObjectCmdNVerb[OLEUI_OBJECTMENUMAX];

static char         szLinkCmdNVerb[OLEUI_OBJECTMENUMAX];

static char         szUnknown[OLEUI_OBJECTMENUMAX];

static char         szEdit[OLEUI_OBJECTMENUMAX];

static char         szConvert[OLEUI_OBJECTMENUMAX];

*lphMenu=NULL;

// Set fAddConvertItem flag

if (bAddConvert & (idConvert != 0))

   fAddConvertItem = TRUE;

// only need to load the strings the 1st time

if (fFirstTime) {

if (0 == LoadString(ghInst, (UINT)IDS_OLE2UIEDITNOOBJCMD,

 (LPSTR)szNoObjectCmd, OLEUI_OBJECTMENUMAX))

return FALSE;

if (0 == LoadString(ghInst, (UINT)IDS_OLE2UIEDITLINKCMD_1VERB,

 (LPSTR)szLinkCmd1Verb, OLEUI_OBJECTMENUMAX))

return FALSE;

if (0 == LoadString(ghInst, (UINT)IDS_OLE2UIEDITOBJECTCMD_1VERB,

 (LPSTR)szObjectCmd1Verb, OLEUI_OBJECTMENUMAX))

return FALSE;

if (0 == LoadString(ghInst, (UINT)IDS_OLE2UIEDITLINKCMD_NVERB,

 (LPSTR)szLinkCmdNVerb, OLEUI_OBJECTMENUMAX))

return FALSE;

if (0 == LoadString(ghInst, (UINT)IDS_OLE2UIEDITOBJECTCMD_NVERB,

 (LPSTR)szObjectCmdNVerb, OLEUI_OBJECTMENUMAX))

return FALSE;

if (0 == LoadString(ghInst, (UINT)IDS_OLE2UIUNKNOWN,

 (LPSTR)szUnknown, OLEUI_OBJECTMENUMAX))

return FALSE;

if (0 == LoadString(ghInst, (UINT)IDS_OLE2UIEDIT,

 (LPSTR)szEdit, OLEUI_OBJECTMENUMAX))

return FALSE;

if ( (0 == LoadString(ghInst, (UINT)IDS_OLE2UICONVERT,

   (LPSTR)szConvert, OLEUI_OBJECTMENUMAX)) && fAddConvertItem)

return FALSE;

fFirstTime = FALSE;

}

// Delete whatever menu may happen to be here already.

DeleteMenu(hMenu, uPos, uFlags);

if (!lpOleObj)

goto AVMError;

if (! lpszShortTypeName) {

// get the Short form of the user type name for the menu

OLEDBG_BEGIN2("IOleObject::GetUserType called\r\n")

hrErr = lpOleObj->lpVtbl->GetUserType(

lpOleObj,

USERCLASSTYPE_SHORT,

(LPSTR FAR*)&lpszShortTypeName

);

OLEDBG_END2

if (NOERROR != hrErr) {

OleDbgOutHResult("IOleObject::GetUserType returned", hrErr);

}

}

// check if the object is a link (it is a link if it support IOleLink)

hrErr = lpOleObj->lpVtbl->QueryInterface(

lpOleObj,

&IID_IOleLink,

(LPVOID FAR*)&lpUnk

);

if (NOERROR == hrErr) {

fIsLink = TRUE;

OleStdRelease(lpUnk);

}

// Get the verb enumerator from the OLE object

OLEDBG_BEGIN2("IOleObject::EnumVerbs called\r\n")

hrErr = lpOleObj->lpVtbl->EnumVerbs(

lpOleObj,

(LPENUMOLEVERB FAR*)&lpEnumOleVerb

);

OLEDBG_END2

if (NOERROR != hrErr) {

OleDbgOutHResult("IOleObject::EnumVerbs returned", hrErr);

}

if (!(*lphMenu = CreatePopupMenu()))

goto AVMError;

// loop through all verbs

while (lpEnumOleVerb != NULL) {         // forever

hrErr = lpEnumOleVerb->lpVtbl->Next(

lpEnumOleVerb,

1,

(LPOLEVERB)&oleverb,

NULL

);

if (NOERROR != hrErr)

break;              // DONE! no more verbs

/* OLE2NOTE: negative verb numbers and verbs that do not

**    indicate ONCONTAINERMENU should NOT be put on the verb menu

*/

if (oleverb.lVerb < 0 ||

! (oleverb.grfAttribs & OLEVERBATTRIB_ONCONTAINERMENU)) {

/* OLE2NOTE: we must still free the verb name string */

if (oleverb.lpszVerbName)

OleStdFreeString(oleverb.lpszVerbName, NULL);

continue;

}

// we must free the previous verb name string

if (lpszVerbName)

OleStdFreeString(lpszVerbName, NULL);

lpszVerbName = oleverb.lpszVerbName;

if ( 0 == uIDVerbMax ||

(uIDVerbMax >= uIDVerbMin+(UINT)oleverb.lVerb) ) {

fStatus = InsertMenu(

*lphMenu,

(UINT)-1,

MF_BYPOSITION | (UINT)oleverb.fuFlags,

uIDVerbMin+(UINT)oleverb.lVerb,

(LPSTR)lpszVerbName

);

if (! fStatus)

goto AVMError;

cVerbs++;

}

}

// Add the separator and "Convert" menu item.

if (fAddConvertItem) {

if (0 == cVerbs) {

LPSTR lpsz;

LPSTR lpszSrc = (LPSTR)szConvert;

// if object has no verbs, then use "Convert" as the obj's verb

lpsz = lpszVerbName = OleStdMalloc(sizeof(szConvert));

uIDVerbMin = idConvert;

// remove "&" and "..." from "&Convert..." string

if (lpsz) {

while (*lpszSrc && *lpszSrc != '.') {

if (*lpszSrc != '&') {

*lpsz = *lpszSrc;

if (IsDBCSLeadByte(*lpszSrc)) {

// copy second byte of DBCS character

lpsz++;

*lpsz = *(lpszSrc+1);

}

lpsz++;

}

lpszSrc = AnsiNext(lpszSrc);

}

*lpsz = '\0';

}

}

if (cVerbs > 0) {

fStatus = InsertMenu(*lphMenu,

(UINT)-1,

MF_BYPOSITION | MF_SEPARATOR,

(UINT)0,

(LPCSTR)NULL);

if (! fStatus)

goto AVMError;

}

/* add convert menu */

fStatus = InsertMenu(*lphMenu,

(UINT)-1,

MF_BYPOSITION,

idConvert,

(LPCSTR)szConvert);

if (! fStatus)

goto AVMError;

cVerbs++;

}

/*

 * Build the appropriate menu based on the number of verbs found

 *

 * NOTE:  Localized verb menus may require a different format.

 *        to assist in localization of the single verb case, the

 *        szLinkCmd1Verb and szObjectCmd1Verb format strings start

 *        with either a '0' (note: NOT '\0'!) or a '1':

 *           leading '0' -- verb type

 *           leading '1' -- type verb

 */

if (cVerbs == 0) {

// there are NO verbs (not even Convert...). set the menu to be

// "<short type> &Object/Link" and gray it out.

wsprintf(

szBuffer,

(fIsLink ? (LPSTR)szLinkCmdNVerb:(LPSTR)szObjectCmdNVerb),

(lpszShortTypeName ? lpszShortTypeName : (LPSTR)"")

);

uFlags |= MF_GRAYED;

#if defined( OBSOLETE )

//No verbs.  Create a default using Edit as the verb.

LPSTR       lpsz = (fIsLink ? szLinkCmd1Verb : szObjectCmd1Verb);

if (*lpsz == '0') {

wsprintf(szBuffer, lpsz+1, (LPSTR)szEdit,

(lpszShortTypeName ? lpszShortTypeName : (LPSTR)"")

);

}

else {

wsprintf(szBuffer, lpsz+1,

(lpszShortTypeName ? lpszShortTypeName : (LPSTR)""),

(LPSTR)szEdit

);

}

#endif

fResult = FALSE;

DestroyMenu(*lphMenu);

*lphMenu = NULL;

}

else if (cVerbs == 1) {

//One verb without Convert, one item.

LPSTR       lpsz = (fIsLink ? szLinkCmd1Verb : szObjectCmd1Verb);

LPSTR       lpsz1 = lpszVerbName;

// remove "&" from the verb name string. the &Object or &Link

// should be the menu accelerator.

// if only "verb" is "Convert" then the "&" has already been stripped

if (lpsz1 && !fAddConvertItem) {

            LPSTR lpszVerbName2 = OleStdMalloc(lstrlen(lpszVerbName)+1);

            LPSTR lpsz2 = lpszVerbName2;

            if (lpsz2) {

                while (*lpsz1) {

                    if (*lpsz1 != '&') {

                        *lpsz2 = *lpsz1;

                        if (IsDBCSLeadByte(*lpsz1)) {

                        // copy second byte of DBCS character

                            lpsz2++;

                            *lpsz2 = *(lpsz1+1);

                        }

                        lpsz2++;

                    }

                    lpsz1 = AnsiNext(lpsz1);

                }

                *lpsz2 = '\0';

                OleStdFreeString(lpszVerbName, NULL);

                lpszVerbName = lpszVerbName2;

            }

        }

if (*lpsz == '0') {

wsprintf(szBuffer, lpsz+1, lpszVerbName,

(lpszShortTypeName ? lpszShortTypeName : (LPSTR)"")

);

}

else {

wsprintf(szBuffer, lpsz+1,

(lpszShortTypeName ? lpszShortTypeName : (LPSTR)""),

lpszVerbName

);

}

// if only "verb" is "Convert..." then append the ellipses

if (fAddConvertItem)

lstrcat(szBuffer, "...");

DestroyMenu(*lphMenu);

*lphMenu=NULL;

}

else {

//Multiple verbs or one verb with Convert, add the cascading menu

wsprintf(

szBuffer,

(fIsLink ? (LPSTR)szLinkCmdNVerb:(LPSTR)szObjectCmdNVerb),

(lpszShortTypeName ? lpszShortTypeName : (LPSTR)"")

);

uFlags |= MF_ENABLED | MF_POPUP;

uIDVerbMin=(UINT)*lphMenu;

}

if (!InsertMenu(hMenu, uPos, uFlags, uIDVerbMin, (LPSTR)szBuffer))

AVMError:

{

InsertMenu(hMenu, uPos, MF_GRAYED | uFlags,

uIDVerbMin, (LPSTR)szNoObjectCmd);

#if defined( OBSOLETE )

HMENU hmenuDummy = CreatePopupMenu();

InsertMenu(hMenu, uPos, MF_GRAYED | MF_POPUP | uFlags,

(UINT)hmenuDummy, (LPSTR)szNoObjectCmd);

#endif

fResult = FALSE;

}

if (lpszVerbName)

OleStdFreeString(lpszVerbName, NULL);

if (!lpszShortType && lpszShortTypeName)

OleStdFreeString(lpszShortTypeName, NULL);

if (lpEnumOleVerb)

lpEnumOleVerb->lpVtbl->Release(lpEnumOleVerb);

return fResult;

}

/* PromptUserDlgProc

 * -----------------

 *

 *  Purpose:

 *      Dialog procedure used by OleUIPromptUser(). Returns when a button is

 *      clicked in the dialog box and the button id is return.

 *

 *  Parameters:

 *      hDlg

 *      iMsg

 *      wParam

 *      lParam

 *

 *  Returns:

 *

 */

BOOL CALLBACK EXPORT PromptUserDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)

{

switch (iMsg) {

case WM_INITDIALOG:

{

LPSTR lpszTitle;

char szBuf[256];

char szFormat[256];

va_list *pargptr;

if (!lParam) {

EndDialog(hDlg, -1);

return FALSE;

}

            //

            //  lParam is really a va_list *.  We called va_start and va_end in

            //  the function that calls this.

            //

            pargptr = (va_list *) lParam;

lpszTitle = va_arg(*pargptr, LPSTR);

SetWindowText(hDlg, lpszTitle);

GetDlgItemText(hDlg, ID_PU_TEXT,(LPSTR)szFormat,sizeof(szFormat));

wvsprintf((LPSTR)szBuf, (LPSTR)szFormat, *pargptr);

SetDlgItemText(hDlg, ID_PU_TEXT, (LPSTR)szBuf);

return TRUE;

}

case WM_COMMAND:

EndDialog(hDlg, wParam);

return TRUE;

default:

return FALSE;

}

}

/* OleUIPromptUser

 * ---------------

 *

 *  Purpose:

 *      Popup a dialog box with the specified template and returned the

 *      response (button id) from the user.

 *

 *  Parameters:

 *      nTemplate       resource number of the dialog

 *      hwndParent      parent of the dialog box

 *      ...             title of the dialog box followed by argument list

 *                      for the format string in the static control

 *                      (ID_PU_TEXT) of the dialog box.

 *                      The caller has to make sure that the correct number

 *                      and type of argument are passed in.

 *

 *  Returns:

 *      button id selected by the user (template dependent)

 *

 *  Comments:

 *      the following message dialog boxes are supported:

 *

 *      IDD_LINKSOURCEUNAVAILABLE -- Link source is unavailable

 *          VARARG Parameters:

 *              None.

 *          Used for the following error codes:

 *              OLE_E_CANT_BINDTOSOURCE

 *              STG_E_PATHNOTFOUND

 *              (sc >= MK_E_FIRST) && (sc <= MK_E_LAST) -- any Moniker error

 *              any unknown error if object is a link

 *

 *      IDD_SERVERNOTFOUND -- server registered but NOT found

 *          VARARG Parameters:

 *              LPSTR lpszUserType -- user type name of object

 *          Used for the following error codes:

 *              CO_E_APPNOTFOUND

 *              CO_E_APPDIDNTREG

 *              any unknown error if object is an embedded object

 *

 *      IDD_SERVERNOTREG -- server NOT registered

 *          VARARG Parameters:

 *              LPSTR lpszUserType -- user type name of object

 *          Used for the following error codes:

 *              REGDB_E_CLASSNOTREG

 *              OLE_E_STATIC -- static object with no server registered

 *

 *      IDD_LINKTYPECHANGED -- class of link source changed since last binding

 *          VARARG Parameters:

 *              LPSTR lpszUserType -- user type name of ole link source

 *          Used for the following error codes:

 *              OLE_E_CLASSDIFF

 *

 *      IDD_LINKTYPECHANGED -- class of link source changed since last binding

 *          VARARG Parameters:

 *              LPSTR lpszUserType -- user type name of ole link source

 *          Used for the following error codes:

 *              OLE_E_CLASSDIFF

 *

 *      IDD_OUTOFMEMORY -- out of memory

 *          VARARG Parameters:

 *              None.

 *          Used for the following error codes:

 *              E_OUTOFMEMORY

 *

 */

int EXPORT FAR CDECL OleUIPromptUser(WORD nTemplate, HWND hwndParent, ...)

{

    int         nRet;

    va_list     arglist;

    LPARAM      lParam;

    //

    //  We want to pass the variable list of arguments to PrompUserDlgProc,

    //  but we can't just pass arglist because arglist is not always the

    //  same size as an LPARAM (e.g. on Alpha va_list is a structure).

    //  So, we pass the a pointer to the arglist instead.

    //

    va_start(arglist, hwndParent);

    lParam = (LPARAM) &arglist;

    nRet = DialogBoxParam(ghInst, MAKEINTRESOURCE(nTemplate), hwndParent,

            PromptUserDlgProc, lParam);

    va_end(arglist);

    return nRet;

}

/* UpdateLinksDlgProc

 * ------------------

 *

 *  Purpose:

 *      Dialog procedure used by OleUIUpdateLinks(). It will enumerate all

 *      all links in the container and updates all automatic links.

 *      Returns when the Stop Button is clicked in the dialog box or when all

 *      links are updated

 *

 *  Parameters:

 *      hDlg

 *      iMsg

 *      wParam

 *      lParam          pointer to the UPDATELINKS structure

 *

 *  Returns:

 *

 */

BOOL CALLBACK EXPORT UpdateLinksDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)

{

LPUPDATELINKS FAR*      lplpUL = NULL;

HANDLE                  gh;

static BOOL             fAbort = FALSE;

//Process the temination message

if (iMsg==uMsgEndDialog)

{

gh = RemoveProp(hDlg, STRUCTUREPROP);

if (NULL!=gh) {

GlobalUnlock(gh);

GlobalFree(gh);

}

EndDialog(hDlg, wParam);

return TRUE;

}

switch (iMsg) {

case WM_INITDIALOG:

{

gh=GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT,sizeof(LPUPDATELINKS));

SetProp(hDlg, STRUCTUREPROP, gh);

if (NULL==gh)

{

PostMessage(hDlg, uMsgEndDialog, OLEUI_ERR_GLOBALMEMALLOC,0L);

return FALSE;

}

fAbort = FALSE;

lplpUL = (LPUPDATELINKS FAR*)GlobalLock(gh);

if (lplpUL) {

*lplpUL = (LPUPDATELINKS)lParam;

SetWindowText(hDlg, (*lplpUL)->lpszTitle);

SetTimer(hDlg, 1, UPDATELINKS_STARTDELAY, NULL);

return TRUE;

} else {

PostMessage(hDlg, uMsgEndDialog, OLEUI_ERR_GLOBALMEMALLOC,0L);

return FALSE;

}

}

case WM_TIMER:

KillTimer(hDlg, 1);

gh = GetProp(hDlg, STRUCTUREPROP);

if (NULL!=gh) {

// gh was locked previously, lock and unlock to get lplpUL

lplpUL = GlobalLock(gh);

GlobalUnlock(gh);

}

if (! fAbort && lplpUL)

PostMessage(hDlg, WM_U_UPDATELINK, 0, (LPARAM)(*lplpUL));

else

PostMessage(hDlg,uMsgEndDialog,OLEUI_CANCEL,0L);

return 0;

case WM_COMMAND:    // Stop button

fAbort = TRUE;

SendMessage(hDlg, uMsgEndDialog, OLEUI_OK, 0L);

return TRUE;

case WM_U_UPDATELINK:

{

HRESULT         hErr;

int             nPercent;

RECT            rc;

char            szPercent[5];       // 0% to 100%

HBRUSH          hbr;

HDC             hDC;

HWND            hwndMeter;

MSG             msg;

DWORD           dwUpdateOpt;

LPUPDATELINKS   lpUL = (LPUPDATELINKS)lParam;

lpUL->dwLink=lpUL->lpOleUILinkCntr->lpVtbl->GetNextLink(

lpUL->lpOleUILinkCntr,

lpUL->dwLink

);

while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {

if (! IsDialogMessage(hDlg, &msg)) {

TranslateMessage(&msg);

DispatchMessage(&msg);

}

}

if (fAbort)

return FALSE;

if (!lpUL->dwLink) {        // all links processed

SendMessage(hDlg, uMsgEndDialog, OLEUI_OK, 0L);

return TRUE;

}

hErr = lpUL->lpOleUILinkCntr->lpVtbl->GetLinkUpdateOptions(

lpUL->lpOleUILinkCntr,

lpUL->dwLink,

(LPDWORD)&dwUpdateOpt

);

if ((hErr == NOERROR) && (dwUpdateOpt == OLEUPDATE_ALWAYS)) {

hErr = lpUL->lpOleUILinkCntr->lpVtbl->UpdateLink(

lpUL->lpOleUILinkCntr,

lpUL->dwLink,

FALSE,      // fMessage

FALSE       // ignored

);

lpUL->fError |= (hErr != NOERROR);

lpUL->cUpdated++;

nPercent = lpUL->cUpdated * 100 / lpUL->cLinks;

if (nPercent <= 100) {  // do NOT advance % beyond 100%

// update percentage

wsprintf((LPSTR)szPercent, "%d%%", nPercent);

SetDlgItemText(hDlg, ID_PU_PERCENT, (LPSTR)szPercent);

// update indicator

hwndMeter = GetDlgItem(hDlg, ID_PU_METER);

GetClientRect(hwndMeter, (LPRECT)&rc);

InflateRect((LPRECT)&rc, -1, -1);

rc.right = (rc.right - rc.left) * nPercent / 100 + rc.left;

hbr = CreateSolidBrush(GetSysColor(COLOR_HIGHLIGHT));

if (hbr) {

hDC = GetDC(hwndMeter);

if (hDC) {

FillRect(hDC, (LPRECT)&rc, hbr);

ReleaseDC(hwndMeter, hDC);

}

DeleteObject(hbr);

}

}

}

while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {

if (! IsDialogMessage(hDlg, &msg)) {

TranslateMessage(&msg);

DispatchMessage(&msg);

}

}

PostMessage(hDlg, WM_U_UPDATELINK, 0, lParam);

return TRUE;

}

default:

return FALSE;

}

}

/* OleUIUpdateLink

 * ---------------

 *

 *  Purpose:

 *      Update all links in the Link Container and popup a dialog box which

 *      shows the progress of the updating.

 *      The process is stopped when the user press Stop button or when all

 *      links are processed.

 *

 *  Parameters:

 *      lpOleUILinkCntr         pointer to Link Container

 *      hwndParent              parent window of the dialog

 *      lpszTitle               title of the dialog box

 *      cLinks                  total number of links

 *

 *  Returns:

 *      TRUE                    all links updated successfully

 *      FALSE                   otherwise

 */

STDAPI_(BOOL) OleUIUpdateLinks(LPOLEUILINKCONTAINER lpOleUILinkCntr, HWND hwndParent, LPSTR lpszTitle, int cLinks)

{

LPUPDATELINKS lpUL = (LPUPDATELINKS)OleStdMalloc(sizeof(UPDATELINKS));

BOOL          fError;

OleDbgAssert(lpOleUILinkCntr && hwndParent && lpszTitle && (cLinks>0));

OleDbgAssert(lpUL);

lpUL->lpOleUILinkCntr = lpOleUILinkCntr;

lpUL->cLinks           = cLinks;

lpUL->cUpdated         = 0;

lpUL->dwLink           = 0;

lpUL->fError           = FALSE;

lpUL->lpszTitle    = lpszTitle;

DialogBoxParam(ghInst, MAKEINTRESOURCE(IDD_UPDATELINKS),

hwndParent, UpdateLinksDlgProc, (LPARAM)lpUL);

fError = lpUL->fError;

OleStdFree((LPVOID)lpUL);

return !fError;

}


 OLESTD.H  (WRAPUI Sample)

/*************************************************************************

**

**    OLE 2.0 Standard Utilities

**

**    olestd.h

**

**    This file contains file contains data structure defintions,

**    function prototypes, constants, etc. for the common OLE 2.0

**    utilities.

**    These utilities include the following:

**          Debuging Assert/Verify macros

**          HIMETRIC conversion routines

**          reference counting debug support

**          OleStd API's for common compound-document app support

**

**    (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved

**

*************************************************************************/

#if !defined( _OLESTD_H_ )

#define _OLESTD_H_

#ifndef RC_INVOKED

#pragma message ("INCLUDING OLESTD.H from " __FILE__)

#endif  /* RC_INVOKED */

#if defined( __TURBOC__ ) || defined( WIN32 )

#define _based(a)

#endif

#ifndef RC_INVOKED

#include <dos.h>        // needed for filetime

#endif  /* RC_INVOKED */

#include <commdlg.h>    // needed for LPPRINTDLG

#include <shellapi.h>   // needed for HKEY

// String table defines...

#define  IDS_OLESTDNOCREATEFILE   700

#define  IDS_OLESTDNOOPENFILE     701

#define  IDS_OLESTDDISKFULL       702

/*

 * Some C interface declaration stuff

 */

#if ! defined(__cplusplus)

typedef struct tagINTERFACEIMPL {

IUnknownVtbl FAR*       lpVtbl;

LPVOID                  lpBack;

int                     cRef;   // interface specific ref count.

} INTERFACEIMPL, FAR* LPINTERFACEIMPL;

#define INIT_INTERFACEIMPL(lpIFace, pVtbl, pBack)   \

((lpIFace)->lpVtbl = pVtbl, \

((LPINTERFACEIMPL)(lpIFace))->lpBack = (LPVOID)pBack,   \

((LPINTERFACEIMPL)(lpIFace))->cRef = 0  \

)

#if defined( _DEBUG )

#define OleDbgQueryInterfaceMethod(lpUnk)   \

((lpUnk) != NULL ? ((LPINTERFACEIMPL)(lpUnk))->cRef++ : 0)

#define OleDbgAddRefMethod(lpThis, iface)   \

((LPINTERFACEIMPL)(lpThis))->cRef++

#if _DEBUGLEVEL >= 2

#define OleDbgReleaseMethod(lpThis, iface) \

(--((LPINTERFACEIMPL)(lpThis))->cRef == 0 ? \

OleDbgOut("\t" iface "* RELEASED (cRef == 0)\r\n"),1 : \

 (((LPINTERFACEIMPL)(lpThis))->cRef < 0) ? \

( \

DebugBreak(), \

OleDbgOut(  \

"\tERROR: " iface "* RELEASED TOO MANY TIMES\r\n") \

),1 : \

1)

#else       // if _DEBUGLEVEL < 2

#define OleDbgReleaseMethod(lpThis, iface) \

(--((LPINTERFACEIMPL)(lpThis))->cRef == 0 ? \

1 : \

 (((LPINTERFACEIMPL)(lpThis))->cRef < 0) ? \

( \

OleDbgOut(  \

"\tERROR: " iface "* RELEASED TOO MANY TIMES\r\n") \

),1 : \

1)

#endif      // if _DEBUGLEVEL < 2

#else       // ! defined (_DEBUG)

#define OleDbgQueryInterfaceMethod(lpUnk)

#define OleDbgAddRefMethod(lpThis, iface)

#define OleDbgReleaseMethod(lpThis, iface)

#endif      // if defined( _DEBUG )

#endif      // ! defined(__cplusplus)

/*

 * Some docfiles stuff

 */

#define STGM_DFRALL (STGM_READWRITE | STGM_TRANSACTED | STGM_SHARE_DENY_WRITE)

#define STGM_DFALL (STGM_READWRITE | STGM_TRANSACTED | STGM_SHARE_EXCLUSIVE)

#define STGM_SALL (STGM_READWRITE | STGM_SHARE_EXCLUSIVE)

/*

 * Some moniker stuff

 */

// Delimeter used to separate ItemMoniker pieces of a composite moniker

#if defined( _MAC )

#define OLESTDDELIM ":"

#else

#define OLESTDDELIM "\\"

#endif

/*

 * Some Concurrency stuff

 */

/* standard Delay (in msec) to wait before retrying an LRPC call.

**    this value is returned from IMessageFilter::RetryRejectedCall

*/

#define OLESTDRETRYDELAY    (DWORD)5000

/* Cancel the pending outgoing LRPC call.

**    this value is returned from IMessageFilter::RetryRejectedCall

*/

#define OLESTDCANCELRETRY   (DWORD)-1

/*

 * Some Icon support stuff.

 *

 * The following API's are now OBSOLETE because equivalent API's have been

 * added to the OLE2.DLL library

 *      GetIconOfFile       superceeded by OleGetIconOfFile

 *      GetIconOfClass      superceeded by OleGetIconOfClass

 *      OleUIMetafilePictFromIconAndLabel

 *                          superceeded by OleMetafilePictFromIconAndLabel

 *

 * The following macros are defined for backward compatibility with previous

 * versions of the OLE2UI library. It is recommended that the new Ole* API's

 * should be used instead.

 */

#define GetIconOfFile(hInst, lpszFileName, fUseFileAsLabel) \

OleGetIconOfFile(lpszFileName, fUseFileAsLabel)

#define GetIconOfClass(hInst, rclsid, lpszLabel, fUseTypeAsLabel) \

OleGetIconOfClass(rclsid, lpszLabel, fUseTypeAsLabel)

#define OleUIMetafilePictFromIconAndLabel(hIcon,pszLabel,pszSourceFile,iIcon)\

OleMetafilePictFromIconAndLabel(hIcon, pszLabel, pszSourceFile, iIcon)

/*

 * Some Clipboard Copy/Paste & Drag/Drop support stuff

 */

//Macro to set all FormatEtc fields

#define SETFORMATETC(fe, cf, asp, td, med, li)   \

((fe).cfFormat=cf, \

 (fe).dwAspect=asp, \

 (fe).ptd=td, \

 (fe).tymed=med, \

 (fe).lindex=li)

//Macro to set interesting FormatEtc fields defaulting the others.

#define SETDEFAULTFORMATETC(fe, cf, med)  \

((fe).cfFormat=cf, \

 (fe).dwAspect=DVASPECT_CONTENT, \

 (fe).ptd=NULL, \

 (fe).tymed=med, \

 (fe).lindex=-1)

// Macro to test if two FormatEtc structures are an exact match

#define IsEqualFORMATETC(fe1, fe2)  \

(OleStdCompareFormatEtc(&(fe1), &(fe2))==0)

// Clipboard format strings

#define CF_EMBEDSOURCE      "Embed Source"

#define CF_EMBEDDEDOBJECT   "Embedded Object"

#define CF_LINKSOURCE       "Link Source"

#define CF_CUSTOMLINKSOURCE "Custom Link Source"

#define CF_OBJECTDESCRIPTOR "Object Descriptor"

#define CF_LINKSRCDESCRIPTOR "Link Source Descriptor"

#define CF_OWNERLINK        "OwnerLink"

#define CF_FILENAME         "FileName"

#define OleStdQueryOleObjectData(lpformatetc)   \

(((lpformatetc)->tymed & TYMED_ISTORAGE) ?    \

NOERROR : ResultFromScode(DV_E_FORMATETC))

#define OleStdQueryLinkSourceData(lpformatetc)   \

(((lpformatetc)->tymed & TYMED_ISTREAM) ?    \

NOERROR : ResultFromScode(DV_E_FORMATETC))

#define OleStdQueryObjectDescriptorData(lpformatetc)    \

(((lpformatetc)->tymed & TYMED_HGLOBAL) ?    \

NOERROR : ResultFromScode(DV_E_FORMATETC))

#define OleStdQueryFormatMedium(lpformatetc, tymd)  \

(((lpformatetc)->tymed & tymd) ?    \

NOERROR : ResultFromScode(DV_E_FORMATETC))

// Make an independent copy of a MetafilePict

#define OleStdCopyMetafilePict(hpictin, phpictout)  \

(*(phpictout) = OleDuplicateData(hpictin,CF_METAFILEPICT,GHND|GMEM_SHARE))

// REVIEW: these need to be added to OLE2.H

#if !defined( DD_DEFSCROLLINTERVAL )

#define DD_DEFSCROLLINTERVAL    50

#endif

#if !defined( DD_DEFDRAGDELAY )

#define DD_DEFDRAGDELAY         200

#endif

#if !defined( DD_DEFDRAGMINDIST )

#define DD_DEFDRAGMINDIST       2

#endif

/* OleStdGetDropEffect

** -------------------

**

** Convert a keyboard state into a DROPEFFECT.

**

** returns the DROPEFFECT value derived from the key state.

**    the following is the standard interpretation:

**          no modifier -- Default Drop     (NULL is returned)

**          CTRL        -- DROPEFFECT_COPY

**          SHIFT       -- DROPEFFECT_MOVE

**          CTRL-SHIFT  -- DROPEFFECT_LINK

**

**    Default Drop: this depends on the type of the target application.

**    this is re-interpretable by each target application. a typical

**    interpretation is if the drag is local to the same document

**    (which is source of the drag) then a MOVE operation is

**    performed. if the drag is not local, then a COPY operation is

**    performed.

*/

#define OleStdGetDropEffect(grfKeyState)    \

( (grfKeyState & MK_CONTROL) ?          \

( (grfKeyState & MK_SHIFT) ? DROPEFFECT_LINK : DROPEFFECT_COPY ) :  \

( (grfKeyState & MK_SHIFT) ? DROPEFFECT_MOVE : 0 ) )

/* The OLEUIPASTEFLAG enumeration is used by the OLEUIPASTEENTRY structure.

 *

 * OLEUIPASTE_ENABLEICON    If the container does not specify this flag for the entry in the

 *   OLEUIPASTEENTRY array passed as input to OleUIPasteSpecial, the DisplayAsIcon button will be

 *   unchecked and disabled when the the user selects the format that corresponds to the entry.

 *

 * OLEUIPASTE_PASTEONLY     Indicates that the entry in the OLEUIPASTEENTRY array is valid for pasting only.

 * OLEUIPASTE_PASTE         Indicates that the entry in the OLEUIPASTEENTRY array is valid for pasting. It

 *   may also be valid for linking if any of the following linking flags are specified.

 *

 * If the entry in the OLEUIPASTEENTRY array is valid for linking, the following flags indicate which link

 * types are acceptable by OR'ing together the appropriate OLEUIPASTE_LINKTYPE<#> values.

 * These values correspond as follows to the array of link types passed to OleUIPasteSpecial:

 *   OLEUIPASTE_LINKTYPE1=arrLinkTypes[0]

 *   OLEUIPASTE_LINKTYPE2=arrLinkTypes[1]

 *   OLEUIPASTE_LINKTYPE3=arrLinkTypes[2]

 *   OLEUIPASTE_LINKTYPE4=arrLinkTypes[3]

 *   OLEUIPASTE_LINKTYPE5=arrLinkTypes[4]

 *   OLEUIPASTE_LINKTYPE6=arrLinkTypes[5]

 *   OLEUIPASTE_LINKTYPE7=arrLinkTypes[6]

 *  OLEUIPASTE_LINKTYPE8=arrLinkTypes[7]

 *

 * where,

 *   UINT arrLinkTypes[8] is an array of registered clipboard formats for linking. A maximium of 8 link

 *   types are allowed.

 */

typedef enum tagOLEUIPASTEFLAG

{

   OLEUIPASTE_ENABLEICON    = 2048,     // enable display as icon

   OLEUIPASTE_PASTEONLY     = 0,

   OLEUIPASTE_PASTE         = 512,

   OLEUIPASTE_LINKANYTYPE   = 1024,

   OLEUIPASTE_LINKTYPE1     = 1,

   OLEUIPASTE_LINKTYPE2     = 2,

   OLEUIPASTE_LINKTYPE3     = 4,

   OLEUIPASTE_LINKTYPE4     = 8,

   OLEUIPASTE_LINKTYPE5     = 16,

   OLEUIPASTE_LINKTYPE6     = 32,

   OLEUIPASTE_LINKTYPE7     = 64,

   OLEUIPASTE_LINKTYPE8     = 128

} OLEUIPASTEFLAG;

/*

 * PasteEntry structure

 * --------------------

 * An array of OLEUIPASTEENTRY entries is specified for the PasteSpecial dialog

 * box. Each entry includes a FORMATETC which specifies the formats that are

 * acceptable, a string that is to represent the format in the  dialog's list

 * box, a string to customize the result text of the dialog and a set of flags

 * from the OLEUIPASTEFLAG enumeration.  The flags indicate if the entry is

 * valid for pasting only, linking only or both pasting and linking. If the

 * entry is valid for linking, the flags indicate which link types are

 * acceptable by OR'ing together the appropriate OLEUIPASTE_LINKTYPE<#> values.

 * These values correspond to the array of link types as follows:

 *   OLEUIPASTE_LINKTYPE1=arrLinkTypes[0]

 *   OLEUIPASTE_LINKTYPE2=arrLinkTypes[1]

 *   OLEUIPASTE_LINKTYPE3=arrLinkTypes[2]

 *   OLEUIPASTE_LINKTYPE4=arrLinkTypes[3]

 *   OLEUIPASTE_LINKTYPE5=arrLinkTypes[4]

 *   OLEUIPASTE_LINKTYPE6=arrLinkTypes[5]

 *   OLEUIPASTE_LINKTYPE7=arrLinkTypes[6]

 *   OLEUIPASTE_LINKTYPE8=arrLinkTypes[7]

 *   UINT arrLinkTypes[8]; is an array of registered clipboard formats

 *                        for linking. A maximium of 8 link types are allowed.

 */

typedef struct tagOLEUIPASTEENTRY

{

   FORMATETC        fmtetc;            // Format that is acceptable. The paste

   //   dialog checks if this format is

   //   offered by the object on the

   //   clipboard and if so offers it for

   //   selection to the user.

   LPCSTR           lpstrFormatName;   // String that represents the format to the user. Any %s

   //   in this string is replaced by the FullUserTypeName

   //   of the object on the clipboard and the resulting string

   //   is placed in the list box of the dialog. Atmost

   //   one %s is allowed. The presence or absence of %s indicates

   //   if the result text is to indicate that data is

   //   being pasted or that an object that can be activated by

   //   an application is being pasted. If %s is

   //   present, the result-text says that an object is being pasted.

   //   Otherwise it says that data is being pasted.

   LPCSTR           lpstrResultText;   // String to customize the result text of the dialog when

   //  the user selects the format correspoding to this

   //  entry. Any %s in this string is replaced by the the application

   //  name or FullUserTypeName of the object on

   //  the clipboard. Atmost one %s is allowed.

   DWORD            dwFlags;           // Values from OLEUIPASTEFLAG enum

   DWORD            dwScratchSpace;    // Scratch space available to be used

   //   by routines which loop through an

   //   IEnumFORMATETC* to mark if the

   //   PasteEntry format is available.

   //   this field CAN be left uninitialized.

} OLEUIPASTEENTRY, *POLEUIPASTEENTRY, FAR *LPOLEUIPASTEENTRY;

#define OLESTDDROP_NONE         0

#define OLESTDDROP_DEFAULT      1

#define OLESTDDROP_NONDEFAULT   2

/*

 * Some misc stuff

 */

#define EMBEDDINGFLAG "Embedding"     // Cmd line switch for launching a srvr

#define HIMETRIC_PER_INCH   2540      // number HIMETRIC units per inch

#define PTS_PER_INCH        72        // number points (font size) per inch

#define ROUNDED_A_DIV_B(a,b) \

( ((2 * ((a) % (b))) >= (b)) ? (((a)/(b))+1) : ((a)/(b)) )

#define MAP_PIX_TO_LOGHIM(x,ppli)   \

ROUNDED_A_DIV_B( (((LONG)HIMETRIC_PER_INCH) * ((LONG)(x))), \

 ((LONG)(ppli)) )

#define MAP_LOGHIM_TO_PIX(x,ppli)   \

ROUNDED_A_DIV_B( (((LONG)(ppli)) * ((LONG)(x))), \

 ((LONG)HIMETRIC_PER_INCH) )

// Returns TRUE if all fields of the two Rect's are equal, else FALSE.

#define AreRectsEqual(lprc1, lprc2)     \

(((lprc1->top == lprc2->top) &&     \

  (lprc1->left == lprc2->left) &&   \

  (lprc1->right == lprc2->right) && \

  (lprc1->bottom == lprc2->bottom)) ? TRUE : FALSE)

#ifdef WIN32

#define LSTRCPYN(lpdst, lpsrc, cch) \

(\

(lpdst)[(cch)-1] = '\0', \

((cch)>1 ? strncpy(lpdst, lpsrc, (cch)-1) : 0)\

)

#else

#define LSTRCPYN(lpdst, lpsrc, cch) \

(\

(lpdst)[(cch)-1] = '\0', \

((cch)>1 ? _fstrncpy(lpdst, lpsrc, (cch)-1) : 0)\

)

#endif

/****** DEBUG Stuff *****************************************************/

#ifdef _DEBUG

#if !defined( _DBGTRACE )

#define _DEBUGLEVEL 2

#else

#define _DEBUGLEVEL _DBGTRACE

#endif

#if defined( NOASSERT )

#define OLEDBGASSERTDATA

#define OleDbgAssert(a)

#define OleDbgAssertSz(a, b)

#define OleDbgVerify(a)

#define OleDbgVerifySz(a, b)

#else   // ! NOASSERT

#define OLEDBGASSERTDATA    \

static char _based(_segname("_CODE")) _szAssertFile[]= __FILE__;

#define OleDbgAssert(a) \

(!(a) ? FnAssert(#a, NULL, _szAssertFile, __LINE__) : (HRESULT)1)

#define OleDbgAssertSz(a, b)    \

(!(a) ? FnAssert(#a, b, _szAssertFile, __LINE__) : (HRESULT)1)

#define OleDbgVerify(a) \

OleDbgAssert(a)

#define OleDbgVerifySz(a, b)    \

OleDbgAssertSz(a, b)

#endif  // ! NOASSERT

#define OLEDBGDATA_MAIN(szPrefix)   \

char near g_szDbgPrefix[] = szPrefix;    \

OLEDBGASSERTDATA

#define OLEDBGDATA  \

extern char near g_szDbgPrefix[];    \

OLEDBGASSERTDATA

#define OLEDBG_BEGIN(lpsz) \

OleDbgPrintAlways(g_szDbgPrefix,lpsz,1);

#define OLEDBG_END  \

OleDbgPrintAlways(g_szDbgPrefix,"End\r\n",-1);

#define OleDbgOut(lpsz) \

OleDbgPrintAlways(g_szDbgPrefix,lpsz,0)

#define OleDbgOutNoPrefix(lpsz) \

OleDbgPrintAlways("",lpsz,0)

#define OleDbgOutRefCnt(lpsz,lpObj,refcnt)      \

OleDbgPrintRefCntAlways(g_szDbgPrefix,lpsz,lpObj,(ULONG)refcnt)

#define OleDbgOutRect(lpsz,lpRect)      \

OleDbgPrintRectAlways(g_szDbgPrefix,lpsz,lpRect)

#define OleDbgOutHResult(lpsz,hr)   \

OleDbgPrintScodeAlways(g_szDbgPrefix,lpsz,GetScode(hr))

#define OleDbgOutScode(lpsz,sc) \

OleDbgPrintScodeAlways(g_szDbgPrefix,lpsz,sc)

#define OleDbgOut1(lpsz)    \

OleDbgPrint(1,g_szDbgPrefix,lpsz,0)

#define OleDbgOutNoPrefix1(lpsz)    \

OleDbgPrint(1,"",lpsz,0)

#define OLEDBG_BEGIN1(lpsz)    \

OleDbgPrint(1,g_szDbgPrefix,lpsz,1);

#define OLEDBG_END1 \

OleDbgPrint(1,g_szDbgPrefix,"End\r\n",-1);

#define OleDbgOutRefCnt1(lpsz,lpObj,refcnt)     \

OleDbgPrintRefCnt(1,g_szDbgPrefix,lpsz,lpObj,(ULONG)refcnt)

#define OleDbgOutRect1(lpsz,lpRect)     \

OleDbgPrintRect(1,g_szDbgPrefix,lpsz,lpRect)

#define OleDbgOut2(lpsz)    \

OleDbgPrint(2,g_szDbgPrefix,lpsz,0)

#define OleDbgOutNoPrefix2(lpsz)    \

OleDbgPrint(2,"",lpsz,0)

#define OLEDBG_BEGIN2(lpsz)    \

OleDbgPrint(2,g_szDbgPrefix,lpsz,1);

#define OLEDBG_END2 \

OleDbgPrint(2,g_szDbgPrefix,"End\r\n",-1);

#define OleDbgOutRefCnt2(lpsz,lpObj,refcnt)     \

OleDbgPrintRefCnt(2,g_szDbgPrefix,lpsz,lpObj,(ULONG)refcnt)

#define OleDbgOutRect2(lpsz,lpRect)     \

OleDbgPrintRect(2,g_szDbgPrefix,lpsz,lpRect)

#define OleDbgOut3(lpsz)    \

OleDbgPrint(3,g_szDbgPrefix,lpsz,0)

#define OleDbgOutNoPrefix3(lpsz)    \

OleDbgPrint(3,"",lpsz,0)

#define OLEDBG_BEGIN3(lpsz)    \

OleDbgPrint(3,g_szDbgPrefix,lpsz,1);

#define OLEDBG_END3 \

OleDbgPrint(3,g_szDbgPrefix,"End\r\n",-1);

#define OleDbgOutRefCnt3(lpsz,lpObj,refcnt)     \

OleDbgPrintRefCnt(3,g_szDbgPrefix,lpsz,lpObj,(ULONG)refcnt)

#define OleDbgOutRect3(lpsz,lpRect)     \

OleDbgPrintRect(3,g_szDbgPrefix,lpsz,lpRect)

#define OleDbgOut4(lpsz)    \

OleDbgPrint(4,g_szDbgPrefix,lpsz,0)

#define OleDbgOutNoPrefix4(lpsz)    \

OleDbgPrint(4,"",lpsz,0)

#define OLEDBG_BEGIN4(lpsz)    \

OleDbgPrint(4,g_szDbgPrefix,lpsz,1);

#define OLEDBG_END4 \

OleDbgPrint(4,g_szDbgPrefix,"End\r\n",-1);

#define OleDbgOutRefCnt4(lpsz,lpObj,refcnt)     \

OleDbgPrintRefCnt(4,g_szDbgPrefix,lpsz,lpObj,(ULONG)refcnt)

#define OleDbgOutRect4(lpsz,lpRect)     \

OleDbgPrintRect(4,g_szDbgPrefix,lpsz,lpRect)

#else   //  !_DEBUG

#define OLEDBGDATA_MAIN(szPrefix)

#define OLEDBGDATA

#define OleDbgAssert(a)

#define OleDbgAssertSz(a, b)

#define OleDbgVerify(a)         (a)

#define OleDbgVerifySz(a, b)    (a)

#define OleDbgOutHResult(lpsz,hr)

#define OleDbgOutScode(lpsz,sc)

#define OLEDBG_BEGIN(lpsz)

#define OLEDBG_END

#define OleDbgOut(lpsz)

#define OleDbgOut1(lpsz)

#define OleDbgOut2(lpsz)

#define OleDbgOut3(lpsz)

#define OleDbgOut4(lpsz)

#define OleDbgOutNoPrefix(lpsz)

#define OleDbgOutNoPrefix1(lpsz)

#define OleDbgOutNoPrefix2(lpsz)

#define OleDbgOutNoPrefix3(lpsz)

#define OleDbgOutNoPrefix4(lpsz)

#define OLEDBG_BEGIN1(lpsz)

#define OLEDBG_BEGIN2(lpsz)

#define OLEDBG_BEGIN3(lpsz)

#define OLEDBG_BEGIN4(lpsz)

#define OLEDBG_END1

#define OLEDBG_END2

#define OLEDBG_END3

#define OLEDBG_END4

#define OleDbgOutRefCnt(lpsz,lpObj,refcnt)

#define OleDbgOutRefCnt1(lpsz,lpObj,refcnt)

#define OleDbgOutRefCnt2(lpsz,lpObj,refcnt)

#define OleDbgOutRefCnt3(lpsz,lpObj,refcnt)

#define OleDbgOutRefCnt4(lpsz,lpObj,refcnt)

#define OleDbgOutRect(lpsz,lpRect)

#define OleDbgOutRect1(lpsz,lpRect)

#define OleDbgOutRect2(lpsz,lpRect)

#define OleDbgOutRect3(lpsz,lpRect)

#define OleDbgOutRect4(lpsz,lpRect)

#endif  //  _DEBUG

/*************************************************************************

** Function prototypes

*************************************************************************/

//OLESTD.C

STDAPI_(int) SetDCToAnisotropic(HDC hDC, LPRECT lprcPhysical, LPRECT lprcLogical, LPRECT lprcWindowOld, LPRECT lprcViewportOld);

STDAPI_(int) SetDCToDrawInHimetricRect(HDC, LPRECT, LPRECT, LPRECT, LPRECT);

STDAPI_(int) ResetOrigDC(HDC, int, LPRECT, LPRECT);

STDAPI_(int)        XformWidthInHimetricToPixels(HDC, int);

STDAPI_(int)        XformWidthInPixelsToHimetric(HDC, int);

STDAPI_(int)        XformHeightInHimetricToPixels(HDC, int);

STDAPI_(int)        XformHeightInPixelsToHimetric(HDC, int);

STDAPI_(void) XformRectInPixelsToHimetric(HDC, LPRECT, LPRECT);

STDAPI_(void) XformRectInHimetricToPixels(HDC, LPRECT, LPRECT);

STDAPI_(void) XformSizeInPixelsToHimetric(HDC, LPSIZEL, LPSIZEL);

STDAPI_(void) XformSizeInHimetricToPixels(HDC, LPSIZEL, LPSIZEL);

STDAPI_(int) XformWidthInHimetricToPixels(HDC, int);

STDAPI_(int) XformWidthInPixelsToHimetric(HDC, int);

STDAPI_(int) XformHeightInHimetricToPixels(HDC, int);

STDAPI_(int) XformHeightInPixelsToHimetric(HDC, int);

STDAPI_(void) ParseCmdLine(LPSTR, BOOL FAR *, LPSTR);

STDAPI_(BOOL) OleStdIsOleLink(LPUNKNOWN lpUnk);

STDAPI_(LPUNKNOWN) OleStdQueryInterface(LPUNKNOWN lpUnk, REFIID riid);

STDAPI_(LPSTORAGE) OleStdCreateRootStorage(LPSTR lpszStgName, DWORD grfMode);

STDAPI_(LPSTORAGE) OleStdOpenRootStorage(LPSTR lpszStgName, DWORD grfMode);

STDAPI_(LPSTORAGE) OleStdOpenOrCreateRootStorage(LPSTR lpszStgName, DWORD grfMode);

STDAPI_(LPSTORAGE) OleStdCreateChildStorage(LPSTORAGE lpStg, LPSTR lpszStgName);

STDAPI_(LPSTORAGE) OleStdOpenChildStorage(LPSTORAGE lpStg, LPSTR lpszStgName, DWORD grfMode);

STDAPI_(BOOL) OleStdCommitStorage(LPSTORAGE lpStg);

STDAPI OleStdDestroyAllElements(LPSTORAGE lpStg);

STDAPI_(LPSTORAGE) OleStdCreateStorageOnHGlobal(

HANDLE hGlobal,

BOOL fDeleteOnRelease,

DWORD dwgrfMode

);

STDAPI_(LPSTORAGE) OleStdCreateTempStorage(BOOL fUseMemory, DWORD grfMode);

STDAPI OleStdDoConvert(LPSTORAGE lpStg, REFCLSID rClsidNew);

STDAPI_(BOOL) OleStdGetTreatAsFmtUserType(

REFCLSID        rClsidApp,

LPSTORAGE       lpStg,

CLSID FAR*      lpclsid,

CLIPFORMAT FAR* lpcfFmt,

LPSTR FAR*      lplpszType

);

STDAPI OleStdDoTreatAsClass(LPSTR lpszUserType, REFCLSID rclsid, REFCLSID rclsidNew);

STDAPI_(BOOL) OleStdSetupAdvises(LPOLEOBJECT lpOleObject, DWORD dwDrawAspect,

LPSTR lpszContainerApp, LPSTR lpszContainerObj,

LPADVISESINK lpAdviseSink, BOOL fCreate);

STDAPI OleStdSwitchDisplayAspect(

LPOLEOBJECT             lpOleObj,

LPDWORD                 lpdwCurAspect,

DWORD                   dwNewAspect,

HGLOBAL                 hMetaPict,

BOOL                    fDeleteOldAspect,

BOOL                    fSetupViewAdvise,

LPADVISESINK            lpAdviseSink,

BOOL FAR*               lpfMustUpdate

);

STDAPI OleStdSetIconInCache(LPOLEOBJECT lpOleObj, HGLOBAL hMetaPict);

STDAPI_(HGLOBAL) OleStdGetData(

LPDATAOBJECT        lpDataObj,

CLIPFORMAT          cfFormat,

DVTARGETDEVICE FAR* lpTargetDevice,

DWORD               dwAspect,

LPSTGMEDIUM         lpMedium

);

STDAPI_(void) OleStdMarkPasteEntryList(

LPDATAOBJECT        lpSrcDataObj,

LPOLEUIPASTEENTRY   lpPriorityList,

int                 cEntries

);

STDAPI_(int) OleStdGetPriorityClipboardFormat(

LPDATAOBJECT        lpSrcDataObj,

LPOLEUIPASTEENTRY   lpPriorityList,

int                 cEntries

);

STDAPI_(BOOL) OleStdIsDuplicateFormat(

LPFORMATETC         lpFmtEtc,

LPFORMATETC         arrFmtEtc,

int                 nFmtEtc

);

STDAPI_(void) OleStdRegisterAsRunning(LPUNKNOWN lpUnk, LPMONIKER lpmkFull, DWORD FAR* lpdwRegister);

STDAPI_(void) OleStdRevokeAsRunning(DWORD FAR* lpdwRegister);

STDAPI_(void) OleStdNoteFileChangeTime(LPSTR lpszFileName, DWORD dwRegister);

STDAPI_(void) OleStdNoteObjectChangeTime(DWORD dwRegister);

STDAPI OleStdGetOleObjectData(

LPPERSISTSTORAGE    lpPStg,

LPFORMATETC         lpformatetc,

LPSTGMEDIUM         lpMedium,

BOOL                fUseMemory

);

STDAPI OleStdGetLinkSourceData(

LPMONIKER           lpmk,

LPCLSID             lpClsID,

LPFORMATETC         lpformatetc,

LPSTGMEDIUM         lpMedium

);

STDAPI_(HGLOBAL) OleStdGetObjectDescriptorData(

CLSID               clsid,

DWORD               dwAspect,

SIZEL               sizel,

POINTL              pointl,

DWORD               dwStatus,

LPSTR               lpszFullUserTypeName,

LPSTR               lpszSrcOfCopy

);

STDAPI_(HGLOBAL) OleStdGetObjectDescriptorDataFromOleObject(

LPOLEOBJECT         lpOleObj,

LPSTR               lpszSrcOfCopy,

DWORD               dwAspect,

POINTL              pointl,

LPSIZEL             lpSizelHim

);

STDAPI_(HGLOBAL) OleStdFillObjectDescriptorFromData(

LPDATAOBJECT       lpDataObject,

LPSTGMEDIUM        lpmedium,

CLIPFORMAT FAR*    lpcfFmt

);

STDAPI_(HANDLE) OleStdGetMetafilePictFromOleObject(

LPOLEOBJECT         lpOleObj,

DWORD               dwDrawAspect,

LPSIZEL             lpSizelHim,

DVTARGETDEVICE FAR* ptd

);

STDAPI_(void) OleStdCreateTempFileMoniker(LPSTR lpszPrefixString, UINT FAR* lpuUnique, LPSTR lpszName, LPMONIKER FAR* lplpmk);

STDAPI_(LPMONIKER) OleStdGetFirstMoniker(LPMONIKER lpmk);

STDAPI_(ULONG) OleStdGetLenFilePrefixOfMoniker(LPMONIKER lpmk);

STDAPI OleStdMkParseDisplayName(

REFCLSID        rClsid,

LPBC            lpbc,

LPSTR           lpszUserName,

ULONG FAR*      lpchEaten,

LPMONIKER FAR*  lplpmk

);

STDAPI_(LPVOID) OleStdMalloc(ULONG ulSize);

STDAPI_(LPVOID) OleStdRealloc(LPVOID pmem, ULONG ulSize);

STDAPI_(void) OleStdFree(LPVOID pmem);

STDAPI_(ULONG) OleStdGetSize(LPVOID pmem);

STDAPI_(void) OleStdFreeString(LPSTR lpsz, LPMALLOC lpMalloc);

STDAPI_(LPSTR) OleStdCopyString(LPSTR lpszSrc, LPMALLOC lpMalloc);

STDAPI_(ULONG) OleStdGetItemToken(LPSTR lpszSrc, LPSTR lpszDst,int nMaxChars);

STDAPI_(UINT)     OleStdIconLabelTextOut(HDC        hDC,

 HFONT      hFont,

 int        nXStart,

 int        nYStart,

 UINT       fuOptions,

 RECT FAR * lpRect,

 LPSTR      lpszString,

 UINT       cchString,

 int FAR *  lpDX);

// registration database query functions

STDAPI_(UINT)     OleStdGetAuxUserType(REFCLSID rclsid,

  UINT   wAuxUserType,

  LPSTR  lpszAuxUserType,

  int    cch,

  HKEY   hKey);

STDAPI_(UINT)     OleStdGetUserTypeOfClass(REFCLSID rclsid,

   LPSTR lpszUserType,

   UINT cch,

   HKEY hKey);

STDAPI_(BOOL) OleStdGetMiscStatusOfClass(REFCLSID, HKEY, DWORD FAR *);

STDAPI_(CLIPFORMAT) OleStdGetDefaultFileFormatOfClass(

REFCLSID        rclsid,

HKEY            hKey

);

STDAPI_(void) OleStdInitVtbl(LPVOID lpVtbl, UINT nSizeOfVtbl);

STDMETHODIMP OleStdNullMethod(LPUNKNOWN lpThis);

STDAPI_(BOOL) OleStdCheckVtbl(LPVOID lpVtbl, UINT nSizeOfVtbl, LPSTR lpszIface);

STDAPI_(ULONG) OleStdVerifyRelease(LPUNKNOWN lpUnk, LPSTR lpszMsg);

STDAPI_(ULONG) OleStdRelease(LPUNKNOWN lpUnk);

STDAPI_(HDC) OleStdCreateDC(DVTARGETDEVICE FAR* ptd);

STDAPI_(HDC) OleStdCreateIC(DVTARGETDEVICE FAR* ptd);

STDAPI_(DVTARGETDEVICE FAR*) OleStdCreateTargetDevice(LPPRINTDLG lpPrintDlg);

STDAPI_(BOOL) OleStdDeleteTargetDevice(DVTARGETDEVICE FAR* ptd);

STDAPI_(DVTARGETDEVICE FAR*) OleStdCopyTargetDevice(DVTARGETDEVICE FAR* ptdSrc);

STDAPI_(BOOL) OleStdCopyFormatEtc(LPFORMATETC petcDest, LPFORMATETC petcSrc);

STDAPI_(int) OleStdCompareFormatEtc(FORMATETC FAR* pFetcLeft, FORMATETC FAR* pFetcRight);

STDAPI_(BOOL) OleStdCompareTargetDevice

(DVTARGETDEVICE FAR* ptdLeft, DVTARGETDEVICE FAR* ptdRight);

STDAPI_(void) OleDbgPrint(

int     nDbgLvl,

LPSTR   lpszPrefix,

LPSTR   lpszMsg,

int     nIndent

);

STDAPI_(void) OleDbgPrintAlways(LPSTR lpszPrefix, LPSTR lpszMsg, int nIndent);

STDAPI_(void) OleDbgSetDbgLevel(int nDbgLvl);

STDAPI_(int) OleDbgGetDbgLevel( void );

STDAPI_(void) OleDbgIndent(int n);

STDAPI_(void) OleDbgPrintRefCnt(

int         nDbgLvl,

LPSTR       lpszPrefix,

LPSTR       lpszMsg,

LPVOID      lpObj,

ULONG       refcnt

);

STDAPI_(void) OleDbgPrintRefCntAlways(

LPSTR       lpszPrefix,

LPSTR       lpszMsg,

LPVOID      lpObj,

ULONG       refcnt

);

STDAPI_(void) OleDbgPrintRect(

int         nDbgLvl,

LPSTR       lpszPrefix,

LPSTR       lpszMsg,

LPRECT      lpRect

);

STDAPI_(void) OleDbgPrintRectAlways(

LPSTR       lpszPrefix,

LPSTR       lpszMsg,

LPRECT      lpRect

);

STDAPI_(void) OleDbgPrintScodeAlways(LPSTR lpszPrefix, LPSTR lpszMsg, SCODE sc);

// debug implementation of the IMalloc interface.

STDAPI OleStdCreateDbAlloc(ULONG reserved, IMalloc FAR* FAR* ppmalloc);

STDAPI_(LPENUMFORMATETC)

  OleStdEnumFmtEtc_Create(ULONG nCount, LPFORMATETC lpEtc);

STDAPI_(LPENUMSTATDATA)

  OleStdEnumStatData_Create(ULONG nCount, LPSTATDATA lpStat);

STDAPI_(BOOL)

  OleStdCopyStatData(LPSTATDATA pDest, LPSTATDATA pSrc);

STDAPI_(HPALETTE)

  OleStdCreateStandardPalette(void);

#if defined( OBSOLETE )

/*************************************************************************

** The following API's have been converted into macros:

**          OleStdQueryOleObjectData

**          OleStdQueryLinkSourceData

**          OleStdQueryObjectDescriptorData

**          OleStdQueryFormatMedium

**          OleStdCopyMetafilePict

**          AreRectsEqual

**          OleStdGetDropEffect

**

**    These macros are defined above

*************************************************************************/

STDAPI_(BOOL) AreRectsEqual(LPRECT lprc1, LPRECT lprc2);

STDAPI_(BOOL) OleStdCopyMetafilePict(HANDLE hpictin, HANDLE FAR* phpictout);

STDAPI OleStdQueryOleObjectData(LPFORMATETC lpformatetc);

STDAPI OleStdQueryLinkSourceData(LPFORMATETC lpformatetc);

STDAPI OleStdQueryObjectDescriptorData(LPFORMATETC lpformatetc);

STDAPI OleStdQueryFormatMedium(LPFORMATETC lpformatetc, TYMED tymed);

STDAPI_(DWORD) OleStdGetDropEffect ( DWORD grfKeyState );

#endif  // OBSOLETE

#endif // _OLESTD_H_


 OLESTD.C  (WRAPUI Sample)

/*************************************************************************

**

**    OLE 2 Standard Utilities

**

**    olestd.c

**

**    This file contains utilities that are useful for most standard

**        OLE 2.0 compound document type applications.

**

**    (c) Copyright Microsoft Corp. 1992 All Rights Reserved

**

*************************************************************************/

#define NONAMELESSUNION     // use strict ANSI standard (for DVOBJ.H)

#define STRICT  1

#include "ole2ui.h"

#include <stdlib.h>

#include <ctype.h>

#include <shellapi.h>

#include "regdb.h"

#include "geticon.h"

#include "common.h"

OLEDBGDATA

static char szAssertMemAlloc[] = "CoGetMalloc failed";

/* OleStdSetupAdvises

** ------------------

**    Setup the standard View advise required by a standard,

**    compound document-oriented container. Such a container relies on

**    Ole to manage the presentation of the Ole object. The container

**    call IViewObject::Draw to render (display) the object.

**

**    This helper routine performs the following tasks:

**                      setup View advise

**                      Call IOleObject::SetHostNames

**                      Call OleSetContainedObject

**

**    fCreate should be set to TRUE if the object is being created. if

**    an existing object is being loaded, then fCreate should be FALSE.

**    if it is a creation situation, then the ADVF_PRIMEFIRST flag is

**    used when settinp up the IViewObject::Advise. This will result in

**    the immediate sending of the initial picture.

**

**    OLE2NOTE: the standard container does NOT need to set up an OLE

**    Advise (IOleObject::Advise). this routine does NOT set up an OLE

**    Advise (a previous version of this function used to setup this

**    advise, but it was not useful).

*/

STDAPI_(BOOL) OleStdSetupAdvises(LPOLEOBJECT lpOleObject, DWORD dwDrawAspect,

LPSTR lpszContainerApp, LPSTR lpszContainerObj,

LPADVISESINK lpAdviseSink, BOOL fCreate)

{

LPVIEWOBJECT lpViewObject;

HRESULT hrErr;

BOOL fStatus = TRUE;

#if defined( SPECIAL_CONTAINER )

DWORD dwTemp;

#endif

hrErr = lpOleObject->lpVtbl->QueryInterface(

lpOleObject,

&IID_IViewObject,

(LPVOID FAR*)&lpViewObject

);

/* Setup View advise */

if (hrErr == NOERROR) {

OLEDBG_BEGIN2("IViewObject::SetAdvise called\r\n")

lpViewObject->lpVtbl->SetAdvise(

lpViewObject,

dwDrawAspect,

(fCreate ? ADVF_PRIMEFIRST : 0),

lpAdviseSink

);

OLEDBG_END2

OleStdRelease((LPUNKNOWN)lpViewObject);

} else {

fStatus = FALSE;

}

#if defined( SPECIAL_CONTAINER )

/* Setup OLE advise.

**    OLE2NOTE: normally containers do NOT need to setup an OLE

**    advise. this advise connection is only useful for the OLE's

**    DefHandler and the OleLink object implementation. some

**    special container's might need to setup this advise for

**    programatic reasons.

**

**    NOTE: this advise will be torn down automatically by the

**    server when we release the object, therefore we do not need

**    to store the connection id.

*/

OLEDBG_BEGIN2("IOleObject::Advise called\r\n")

hrErr = lpOleObject->lpVtbl->Advise(

lpOleObject,

lpAdviseSink,

(DWORD FAR*)&dwTemp

);

OLEDBG_END2

if (hrErr != NOERROR) fStatus = FALSE;

#endif

/* Setup the host names for the OLE object. */

OLEDBG_BEGIN2("IOleObject::SetHostNames called\r\n")

hrErr = lpOleObject->lpVtbl->SetHostNames(

lpOleObject,

lpszContainerApp,

lpszContainerObj

);

OLEDBG_END2

if (hrErr != NOERROR) fStatus = FALSE;

/* Inform the loadded object's handler/inproc-server that it is in

**    its embedding container's process.

*/

OLEDBG_BEGIN2("OleSetContainedObject(TRUE) called\r\n")

OleSetContainedObject((LPUNKNOWN)lpOleObject, TRUE);

OLEDBG_END2

return fStatus;

}

/* OleStdSwitchDisplayAspect

** -------------------------

**    Switch the currently cached display aspect between DVASPECT_ICON

**    and DVASPECT_CONTENT.

**

**    NOTE: when setting up icon aspect, any currently cached content

**    cache is discarded and any advise connections for content aspect

**    are broken.

**

**    RETURNS:

**      S_OK -- new display aspect setup successfully

**      E_INVALIDARG -- IOleCache interface is NOT supported (this is

**                  required).

**      <other SCODE> -- any SCODE that can be returned by

**                  IOleCache::Cache method.

**      NOTE: if an error occurs then the current display aspect and

**            cache contents unchanged.

*/

STDAPI OleStdSwitchDisplayAspect(

LPOLEOBJECT             lpOleObj,

LPDWORD                 lpdwCurAspect,

DWORD                   dwNewAspect,

HGLOBAL                 hMetaPict,

BOOL                    fDeleteOldAspect,

BOOL                    fSetupViewAdvise,

LPADVISESINK            lpAdviseSink,

BOOL FAR*               lpfMustUpdate

)

{

LPOLECACHE      lpOleCache = NULL;

LPVIEWOBJECT    lpViewObj = NULL;

LPENUMSTATDATA  lpEnumStatData = NULL;

STATDATA        StatData;

FORMATETC       FmtEtc;

STGMEDIUM       Medium;

DWORD           dwAdvf;

DWORD           dwNewConnection;

DWORD           dwOldAspect = *lpdwCurAspect;

HRESULT         hrErr;

if (lpfMustUpdate)

*lpfMustUpdate = FALSE;

lpOleCache = (LPOLECACHE)OleStdQueryInterface(

(LPUNKNOWN)lpOleObj,&IID_IOleCache);

// if IOleCache* is NOT available, do nothing

if (! lpOleCache)

return ResultFromScode(E_INVALIDARG);

// Setup new cache with the new aspect

FmtEtc.cfFormat = 0;     // whatever is needed to draw

FmtEtc.ptd      = NULL;

FmtEtc.dwAspect = dwNewAspect;

FmtEtc.lindex   = -1;

FmtEtc.tymed    = TYMED_NULL;

/* OLE2NOTE: if we are setting up Icon aspect

**    then we do not want DataAdvise notifications to ever change

**    the contents of the data cache. thus we set up a NODATA

**    advise connection. otherwise we set up a standard DataAdvise

**    connection.

*/

if (dwNewAspect == DVASPECT_ICON)

dwAdvf = ADVF_NODATA;

else

dwAdvf = ADVF_PRIMEFIRST;

OLEDBG_BEGIN2("IOleCache::Cache called\r\n")

hrErr = lpOleCache->lpVtbl->Cache(

lpOleCache,

(LPFORMATETC)&FmtEtc,

dwAdvf,

(LPDWORD)&dwNewConnection

);

OLEDBG_END2

if (! SUCCEEDED(hrErr)) {

OleDbgOutHResult("IOleCache::Cache returned", hrErr);

OleStdRelease((LPUNKNOWN)lpOleCache);

return hrErr;

}

*lpdwCurAspect = dwNewAspect;

/* OLE2NOTE: if we are setting up Icon aspect with a custom icon,

**    then stuff the icon into the cache. otherwise the cache must

**    be forced to be updated. set the *lpfMustUpdate flag to tell

**    caller to force the object to Run so that the cache will be

**    updated.

*/

if (dwNewAspect == DVASPECT_ICON && hMetaPict) {

FmtEtc.cfFormat = CF_METAFILEPICT;

FmtEtc.ptd      = NULL;

FmtEtc.dwAspect = DVASPECT_ICON;

FmtEtc.lindex   = -1;

FmtEtc.tymed    = TYMED_MFPICT;

Medium.tymed            = TYMED_MFPICT;

Medium.u.hGlobal        = hMetaPict;

Medium.pUnkForRelease   = NULL;

OLEDBG_BEGIN2("IOleCache::SetData called\r\n")

hrErr = lpOleCache->lpVtbl->SetData(

lpOleCache,

(LPFORMATETC)&FmtEtc,

(LPSTGMEDIUM)&Medium,

FALSE   /* fRelease */

);

OLEDBG_END2

} else {

if (lpfMustUpdate)

*lpfMustUpdate = TRUE;

}

if (fSetupViewAdvise && lpAdviseSink) {

/* OLE2NOTE: re-establish the ViewAdvise connection */

lpViewObj = (LPVIEWOBJECT)OleStdQueryInterface(

(LPUNKNOWN)lpOleObj,&IID_IViewObject);

if (lpViewObj) {

OLEDBG_BEGIN2("IViewObject::SetAdvise called\r\n")

lpViewObj->lpVtbl->SetAdvise(

lpViewObj,

dwNewAspect,

0,

lpAdviseSink

);

OLEDBG_END2

OleStdRelease((LPUNKNOWN)lpViewObj);

}

}

/* OLE2NOTE: remove any existing caches that are set up for the old

**    display aspect. It WOULD be possible to retain the caches set

**    up for the old aspect, but this would increase the storage

**    space required for the object and possibly require additional

**    overhead to maintain the unused cachaes. For these reasons the

**    strategy to delete the previous caches is prefered. if it is a

**    requirement to quickly switch between Icon and Content

**    display, then it would be better to keep both aspect caches.

*/

if (fDeleteOldAspect) {

OLEDBG_BEGIN2("IOleCache::EnumCache called\r\n")

hrErr = lpOleCache->lpVtbl->EnumCache(

lpOleCache,

(LPENUMSTATDATA FAR*)&lpEnumStatData

);

OLEDBG_END2

while(hrErr == NOERROR) {

hrErr = lpEnumStatData->lpVtbl->Next(

lpEnumStatData,

1,

(LPSTATDATA)&StatData,

NULL

);

if (hrErr != NOERROR)

break;              // DONE! no more caches.

if (StatData.formatetc.dwAspect == dwOldAspect) {

// Remove previous cache with old aspect

OLEDBG_BEGIN2("IOleCache::Uncache called\r\n")

lpOleCache->lpVtbl->Uncache(lpOleCache,StatData.dwConnection);

OLEDBG_END2

}

}

if (lpEnumStatData) {

OleStdVerifyRelease(

(LPUNKNOWN)lpEnumStatData,

"OleStdSwitchDisplayAspect: Cache enumerator NOT released"

);

}

}

if (lpOleCache)

OleStdRelease((LPUNKNOWN)lpOleCache);

return NOERROR;

}

/* OleStdSetIconInCache

** --------------------

**    SetData a new icon into the existing DVASPECT_ICON cache.

**

**    RETURNS:

**      HRESULT returned from IOleCache::SetData

*/

STDAPI OleStdSetIconInCache(LPOLEOBJECT lpOleObj, HGLOBAL hMetaPict)

{

LPOLECACHE      lpOleCache = NULL;

FORMATETC       FmtEtc;

STGMEDIUM       Medium;

HRESULT         hrErr;

if (! hMetaPict)

return FALSE;   // invalid icon

lpOleCache = (LPOLECACHE)OleStdQueryInterface(

(LPUNKNOWN)lpOleObj,&IID_IOleCache);

if (! lpOleCache)

return FALSE;   // if IOleCache* is NOT available, do nothing

FmtEtc.cfFormat = CF_METAFILEPICT;

FmtEtc.ptd      = NULL;

FmtEtc.dwAspect = DVASPECT_ICON;

FmtEtc.lindex   = -1;

FmtEtc.tymed    = TYMED_MFPICT;

// stuff the icon into the cache.

Medium.tymed            = TYMED_MFPICT;

Medium.u.hGlobal        = hMetaPict;

Medium.pUnkForRelease   = NULL;

OLEDBG_BEGIN2("IOleCache::SetData called\r\n")

hrErr = lpOleCache->lpVtbl->SetData(

lpOleCache,

(LPFORMATETC)&FmtEtc,

(LPSTGMEDIUM)&Medium,

FALSE   /* fRelease */

);

OLEDBG_END2

OleStdRelease((LPUNKNOWN)lpOleCache);

return hrErr;

}

/* OleStdDoConvert

** ---------------

** Do the container-side responsibilities for converting an object.

**    This function would be used in conjunction with the OleUIConvert

**    dialog. If the user selects to convert an object then the

**    container must do the following:

**          1. unload the object.

**          2. write the NEW CLSID and NEW user type name

**              string into the storage of the object,

**              BUT write the OLD format tag.

**          3. force an update of the object to force the actual

**              conversion of the data bits.

**

**    This function takes care of step 2.

*/

STDAPI OleStdDoConvert(LPSTORAGE lpStg, REFCLSID rClsidNew)

{

HRESULT error;

CLSID clsidOld;

CLIPFORMAT cfOld;

LPSTR lpszOld = NULL;

char szNew[OLEUI_CCHKEYMAX];

if ((error = ReadClassStg(lpStg, &clsidOld)) != NOERROR) {

clsidOld = CLSID_NULL;

goto errRtn;

}

// read old fmt/old user type; sets out params to NULL on error

error = ReadFmtUserTypeStg(lpStg, &cfOld, &lpszOld);

OleDbgAssert(error == NOERROR || (cfOld == 0 && lpszOld == NULL));

// get new user type name; if error, set to NULL string

if (OleStdGetUserTypeOfClass(

(LPCLSID)rClsidNew, szNew,sizeof(szNew),NULL /* hKey */) == 0)

szNew[0] = '\0';

// write class stg

if ((error = WriteClassStg(lpStg, rClsidNew)) != NOERROR)

goto errRtn;

// write old fmt/new user type;

if ((error = WriteFmtUserTypeStg(lpStg, cfOld, szNew)) != NOERROR)

goto errRewriteInfo;

// set convert bit

if ((error = SetConvertStg(lpStg, TRUE)) != NOERROR)

goto errRewriteInfo;

goto okRtn;

errRewriteInfo:

(void)WriteClassStg(lpStg, &clsidOld);

(void)WriteFmtUserTypeStg(lpStg, cfOld, lpszOld);

errRtn:

okRtn:

OleStdFreeString(lpszOld, NULL);

return error;

}

/* OleStdGetTreatAsFmtUserType

** ---------------------------

**    Determine if the application should perform a TreatAs (ActivateAs

**    object or emulation) operation for the object that is stored in

**    the storage.

**

**    if the CLSID written in the storage is not the same as the

**    application's own CLSID (clsidApp), then a TreatAs operation

**    should take place. if so determine the format the data should be

**    written and the user type name of the object the app should

**    emulate (ie. pretend to be). if this information is not written

**    in the storage then it is looked up in the REGDB. if it can not

**    be found in the REGDB, then the TreatAs operation can NOT be

**    executed.

**

**    RETURNS: TRUE -- if TreatAs should be performed.

**               valid lpclsid, lplpszType, lpcfFmt to TreatAs are returned

**                      (NOTE: lplpszType must be freed by caller)

**             FALSE -- NO TreatAs. lpszType will be NULL.

**               lpclsid = CLSID_NULL; lplpszType = lpcfFmt = NULL;

*/

STDAPI_(BOOL) OleStdGetTreatAsFmtUserType(

REFCLSID        rclsidApp,

LPSTORAGE       lpStg,

CLSID FAR*      lpclsid,

CLIPFORMAT FAR* lpcfFmt,

LPSTR FAR*      lplpszType

)

{

HRESULT hrErr;

HKEY    hKey;

LONG    lRet;

UINT    lSize;

char    szBuf[OLEUI_CCHKEYMAX];

*lpclsid    = CLSID_NULL;

*lpcfFmt    = 0;

*lplpszType = NULL;

hrErr = ReadClassStg(lpStg, lpclsid);

if (hrErr == NOERROR &&

! IsEqualCLSID(lpclsid, &CLSID_NULL) &&

! IsEqualCLSID(lpclsid, rclsidApp)) {

hrErr = ReadFmtUserTypeStg(lpStg,(CLIPFORMAT FAR*)lpcfFmt,lplpszType);

if (hrErr == NOERROR && lplpszType && *lpcfFmt != 0)

return TRUE;    // Do TreatAs. info was in lpStg.

/* read info from REGDB

**    *lpcfFmt = value of field: CLSID\{...}\DataFormats\DefaultFile

**    *lplpszType = value of field: CLSID\{...}

*/

//Open up the root key.

lRet=RegOpenKey(HKEY_CLASSES_ROOT, NULL, &hKey);

if (lRet != (LONG)ERROR_SUCCESS)

return FALSE;

*lpcfFmt = OleStdGetDefaultFileFormatOfClass(lpclsid, hKey);

if (*lpcfFmt == 0)

return FALSE;

lSize = OleStdGetUserTypeOfClass(lpclsid,szBuf,sizeof(szBuf),hKey);

if (lSize == 0)

return FALSE;

*lplpszType = OleStdCopyString(szBuf, NULL);

} else {

return FALSE;       // NO TreatAs

}

}

/* OleStdDoTreatAsClass

** --------------------

** Do the container-side responsibilities for "ActivateAs" (aka.

**    TreatAs) for an object.

**    This function would be used in conjunction with the OleUIConvert

**    dialog. If the user selects to ActivateAs an object then the

**    container must do the following:

**          1. unload ALL objects of the OLD class that app knows about

**          2. add the TreatAs tag in the registration database

**              by calling CoTreatAsClass().

**          3. lazily it can reload the objects; when the objects

**              are reloaded the TreatAs will take effect.

**

**    This function takes care of step 2.

*/

STDAPI OleStdDoTreatAsClass(LPSTR lpszUserType, REFCLSID rclsid, REFCLSID rclsidNew)

{

HRESULT hrErr;

LPSTR   lpszCLSID = NULL;

LONG    lRet;

HKEY    hKey;

OLEDBG_BEGIN2("CoTreatAsClass called\r\n")

hrErr = CoTreatAsClass(rclsid, rclsidNew);

OLEDBG_END2

if ((hrErr != NOERROR) && lpszUserType) {

lRet = RegOpenKey(HKEY_CLASSES_ROOT, (LPCSTR)"CLSID",

(HKEY FAR *)&hKey);

StringFromCLSID(rclsid, (LPSTR FAR*)&lpszCLSID);

RegSetValue(hKey, lpszCLSID, REG_SZ, lpszUserType,

lstrlen(lpszUserType));

if (lpszCLSID)

OleStdFreeString(lpszCLSID, NULL);

hrErr = CoTreatAsClass(rclsid, rclsidNew);

RegCloseKey(hKey);

}

return hrErr;

}

/* OleStdIsOleLink

** ---------------

**    Returns TRUE if the OleObject is infact an OLE link object. this

**    checks if IOleLink interface is supported. if so, the object is a

**    link, otherwise not.

*/

STDAPI_(BOOL) OleStdIsOleLink(LPUNKNOWN lpUnk)

{

LPOLELINK lpOleLink;

lpOleLink = (LPOLELINK)OleStdQueryInterface(lpUnk, &IID_IOleLink);

if (lpOleLink) {

OleStdRelease((LPUNKNOWN)lpOleLink);

return TRUE;

} else

return FALSE;

}

/* OleStdQueryInterface

** --------------------

**    Returns the desired interface pointer if exposed by the given object.

**    Returns NULL if the interface is not available.

**    eg.:

**      lpDataObj = OleStdQueryInterface(lpOleObj, &IID_DataObject);

*/

STDAPI_(LPUNKNOWN) OleStdQueryInterface(LPUNKNOWN lpUnk, REFIID riid)

{

LPUNKNOWN lpInterface;

HRESULT hrErr;

hrErr = lpUnk->lpVtbl->QueryInterface(

lpUnk,

riid,

(LPVOID FAR*)&lpInterface

);

if (hrErr == NOERROR)

return lpInterface;

else

return NULL;

}

/* OleStdGetData

** -------------

**    Retrieve data from an IDataObject in a specified format on a

**    global memory block. This function ALWAYS returns a private copy

**    of the data to the caller. if necessary a copy is made of the

**    data (ie. if lpMedium->pUnkForRelease != NULL). The caller assumes

**    ownership of the data block in all cases and must free the data

**    when done with it. The caller may directly free the data handle

**    returned (taking care whether it is a simple HGLOBAL or a HANDLE

**    to a MetafilePict) or the caller may call

**    ReleaseStgMedium(lpMedium). this OLE helper function will do the

**    right thing.

**

**    PARAMETERS:

**        LPDATAOBJECT lpDataObj  -- object on which GetData should be

**                                                         called.

**        CLIPFORMAT cfFormat     -- desired clipboard format (eg. CF_TEXT)

**        DVTARGETDEVICE FAR* lpTargetDevice -- target device for which

**                                  the data should be composed. This may

**                                  be NULL. NULL can be used whenever the

**                                  data format is insensitive to target

**                                  device or when the caller does not care

**                                  what device is used.

**        LPSTGMEDIUM lpMedium    -- ptr to STGMEDIUM struct. the

**                                  resultant medium from the

**                                  IDataObject::GetData call is

**                                  returned.

**

**    RETURNS:

**       HGLOBAL -- global memory handle of retrieved data block.

**       NULL    -- if error.

*/

STDAPI_(HGLOBAL) OleStdGetData(

LPDATAOBJECT        lpDataObj,

CLIPFORMAT          cfFormat,

DVTARGETDEVICE FAR* lpTargetDevice,

DWORD               dwDrawAspect,

LPSTGMEDIUM         lpMedium

)

{

HRESULT hrErr;

FORMATETC formatetc;

HGLOBAL hGlobal = NULL;

HGLOBAL hCopy;

LPVOID  lp;

formatetc.cfFormat = cfFormat;

formatetc.ptd = lpTargetDevice;

formatetc.dwAspect = dwDrawAspect;

formatetc.lindex = -1;

switch (cfFormat) {

case CF_METAFILEPICT:

formatetc.tymed = TYMED_MFPICT;

break;

case CF_BITMAP:

formatetc.tymed = TYMED_GDI;

break;

default:

formatetc.tymed = TYMED_HGLOBAL;

break;

}

OLEDBG_BEGIN2("IDataObject::GetData called\r\n")

hrErr = lpDataObj->lpVtbl->GetData(

lpDataObj,

(LPFORMATETC)&formatetc,

lpMedium

);

OLEDBG_END2

if (hrErr != NOERROR)

return NULL;

if ((hGlobal = lpMedium->u.hGlobal) == NULL)

return NULL;

// Check if hGlobal really points to valid memory

if ((lp = GlobalLock(hGlobal)) != NULL) {

if (IsBadReadPtr(lp, 1)) {

GlobalUnlock(hGlobal);

return NULL;    // ERROR: memory is NOT valid

}

GlobalUnlock(hGlobal);

}

if (hGlobal != NULL && lpMedium->pUnkForRelease != NULL) {

/* OLE2NOTE: the callee wants to retain ownership of the data.

**    this is indicated by passing a non-NULL pUnkForRelease.

**    thus, we will make a copy of the data and release the

**    callee's copy.

*/

hCopy = OleDuplicateData(hGlobal, cfFormat, GHND|GMEM_SHARE);

ReleaseStgMedium(lpMedium); // release callee's copy of data

hGlobal = hCopy;

lpMedium->u.hGlobal = hCopy;

lpMedium->pUnkForRelease = NULL;

}

return hGlobal;

}

/* OleStdMalloc

** ------------

**    allocate memory using the currently active IMalloc* allocator

*/

STDAPI_(LPVOID) OleStdMalloc(ULONG ulSize)

{

LPVOID pout;

LPMALLOC pmalloc;

if (CoGetMalloc(MEMCTX_TASK, &pmalloc) != NOERROR) {

OleDbgAssertSz(0, szAssertMemAlloc);

return NULL;

}

pout = (LPVOID)pmalloc->lpVtbl->Alloc(pmalloc, ulSize);

if (pmalloc != NULL) {

ULONG refs = pmalloc->lpVtbl->Release(pmalloc);

}

return pout;

}

/* OleStdRealloc

** -------------

**    re-allocate memory using the currently active IMalloc* allocator

*/

STDAPI_(LPVOID) OleStdRealloc(LPVOID pmem, ULONG ulSize)

{

LPVOID pout;

LPMALLOC pmalloc;

if (CoGetMalloc(MEMCTX_TASK, &pmalloc) != NOERROR) {

OleDbgAssertSz(0, szAssertMemAlloc);

return NULL;

}

pout = (LPVOID)pmalloc->lpVtbl->Realloc(pmalloc, pmem, ulSize);

if (pmalloc != NULL) {

ULONG refs = pmalloc->lpVtbl->Release(pmalloc);

}

return pout;

}

/* OleStdFree

** ----------

**    free memory using the currently active IMalloc* allocator

*/

STDAPI_(void) OleStdFree(LPVOID pmem)

{

LPMALLOC pmalloc;

if (pmem == NULL)

return;

if (CoGetMalloc(MEMCTX_TASK, &pmalloc) != NOERROR) {

OleDbgAssertSz(0, szAssertMemAlloc);

return;

}

pmalloc->lpVtbl->Free(pmalloc, pmem);

if (pmalloc != NULL) {

ULONG refs = pmalloc->lpVtbl->Release(pmalloc);

}

}

/* OleStdGetSize

** -------------

**    Get the size of a memory block that was allocated using the

**    currently active IMalloc* allocator.

*/

STDAPI_(ULONG) OleStdGetSize(LPVOID pmem)

{

ULONG ulSize;

LPMALLOC pmalloc;

if (CoGetMalloc(MEMCTX_TASK, &pmalloc) != NOERROR) {

OleDbgAssertSz(0, szAssertMemAlloc);

return (ULONG)-1;

}

ulSize = pmalloc->lpVtbl->GetSize(pmalloc, pmem);

if (pmalloc != NULL) {

ULONG refs = pmalloc->lpVtbl->Release(pmalloc);

}

return ulSize;

}

/* OleStdFreeString

** ----------------

**    Free a string that was allocated with the currently active

**    IMalloc* allocator.

**

**    if the caller has the current IMalloc* handy, then it can be

**    passed as a argument, otherwise this function will retrieve the

**    active allocator and use it.

*/

STDAPI_(void) OleStdFreeString(LPSTR lpsz, LPMALLOC lpMalloc)

{

BOOL fMustRelease = FALSE;

if (! lpMalloc) {

if (CoGetMalloc(MEMCTX_TASK, &lpMalloc) != NOERROR)

return;

fMustRelease = TRUE;

}

lpMalloc->lpVtbl->Free(lpMalloc, lpsz);

if (fMustRelease)

lpMalloc->lpVtbl->Release(lpMalloc);

}

/* OleStdCopyString

** ----------------

**    Copy a string into memory allocated with the currently active

**    IMalloc* allocator.

**

**    if the caller has the current IMalloc* handy, then it can be

**    passed as a argument, otherwise this function will retrieve the

**    active allocator and use it.

*/

STDAPI_(LPSTR) OleStdCopyString(LPSTR lpszSrc, LPMALLOC lpMalloc)

{

LPSTR lpszDest = NULL;

BOOL fMustRelease = FALSE;

UINT lSize = lstrlen(lpszSrc);

if (! lpMalloc) {

if (CoGetMalloc(MEMCTX_TASK, &lpMalloc) != NOERROR)

return NULL;

fMustRelease = TRUE;

}

lpszDest = lpMalloc->lpVtbl->Alloc(lpMalloc, lSize+1);

if (lpszDest)

lstrcpy(lpszDest, lpszSrc);

if (fMustRelease)

lpMalloc->lpVtbl->Release(lpMalloc);

return lpszDest;

}

/*

 * OleStdCreateStorageOnHGlobal()

 *

 * Purpose:

 *  Create a memory based IStorage*.

 *

 *  OLE2NOTE: if fDeleteOnRelease==TRUE, then the ILockBytes is created

 *            such that it will delete them memory on its last release.

 *            the IStorage on created on top of the ILockBytes in NOT

 *            created with STGM_DELETEONRELEASE. when the IStorage receives

 *            its last release, it will release the ILockBytes which will

 *            in turn free the memory. it is in fact an error to specify

 *            STGM_DELETEONRELEASE in this situation.

 *

 * Parameters:

 *  hGlobal --  handle to MEM_SHARE allocated memory. may be NULL and

 *              memory will be automatically allocated.

 *  fDeleteOnRelease -- controls if the memory is freed on the last release.

 *  grfMode --  flags passed to StgCreateDocfileOnILockBytes

 *

 *  NOTE: if hGlobal is NULL, then a new IStorage is created and

 *              STGM_CREATE flag is passed to StgCreateDocfileOnILockBytes.

 *        if hGlobal is non-NULL, then it is assumed that the hGlobal already

 *              has an IStorage inside it and STGM_CONVERT flag is passed

 *              to StgCreateDocfileOnILockBytes.

 *

 * Return Value:

 *    SCODE  -  S_OK if successful

 */

STDAPI_(LPSTORAGE) OleStdCreateStorageOnHGlobal(

HANDLE hGlobal,

BOOL fDeleteOnRelease,

DWORD grfMode

)

{

DWORD grfCreateMode=grfMode | (hGlobal==NULL ? STGM_CREATE:STGM_CONVERT);

HRESULT hrErr;

LPLOCKBYTES lpLockBytes = NULL;

DWORD reserved = 0;

LPSTORAGE lpStg = NULL;

hrErr = CreateILockBytesOnHGlobal(

hGlobal,

fDeleteOnRelease,

(LPLOCKBYTES FAR*)&lpLockBytes

);

if (hrErr != NOERROR)

return NULL;

hrErr = StgCreateDocfileOnILockBytes(

lpLockBytes,

grfCreateMode,

reserved,

(LPSTORAGE FAR*)&lpStg

);

if (hrErr != NOERROR) {

OleStdRelease((LPUNKNOWN)lpLockBytes);

return NULL;

}

OleStdRelease((LPUNKNOWN)lpLockBytes);

return lpStg;

}

/*

 * OleStdCreateTempStorage()

 *

 * Purpose:

 *  Create a temporay IStorage* that will DeleteOnRelease.

 *  this can be either memory based or file based.

 *

 * Parameters:

 *  fUseMemory -- controls if memory-based or file-based stg is created

 *  grfMode --  storage mode flags

 *

 * Return Value:

 *    LPSTORAGE  -  if successful, NULL otherwise

 */

STDAPI_(LPSTORAGE) OleStdCreateTempStorage(BOOL fUseMemory, DWORD grfMode)

{

LPSTORAGE   lpstg;

HRESULT     hrErr;

DWORD       reserved = 0;

if (fUseMemory) {

lpstg = OleStdCreateStorageOnHGlobal(

NULL,  /* auto allocate */

TRUE,  /* delete on release */

grfMode

);

} else {

/* allocate a temp docfile that will delete on last release */

hrErr = StgCreateDocfile(

NULL,

grfMode | STGM_DELETEONRELEASE | STGM_CREATE,

reserved,

&lpstg

);

if (hrErr != NOERROR)

return NULL;

}

return lpstg;

}

/* OleStdGetOleObjectData

** ----------------------

**    Render CF_EMBEDSOURCE/CF_EMBEDDEDOBJECT data on an TYMED_ISTORAGE

**    medium by asking the object to save into the storage.

**    the object must support IPersistStorage.

**

**    if lpMedium->tymed == TYMED_NULL, then a delete-on-release

**    storage is allocated (either file-based or memory-base depending

**    the value of fUseMemory). this is useful to support an

**    IDataObject::GetData call where the callee must allocate the

**    medium.

**

**    if lpMedium->tymed == TYMED_ISTORAGE, then the data is writen

**    into the passed in IStorage. this is useful to support an

**    IDataObject::GetDataHere call where the caller has allocated his

**    own IStorage.

*/

STDAPI OleStdGetOleObjectData(

LPPERSISTSTORAGE        lpPStg,

LPFORMATETC             lpformatetc,

LPSTGMEDIUM             lpMedium,

BOOL                    fUseMemory

)

{

LPSTORAGE   lpstg = NULL;

DWORD       reserved = 0;

SCODE       sc = S_OK;

HRESULT     hrErr;

lpMedium->pUnkForRelease = NULL;

if (lpMedium->tymed == TYMED_NULL) {

if (lpformatetc->tymed & TYMED_ISTORAGE) {

/* allocate a temp docfile that will delete on last release */

lpstg = OleStdCreateTempStorage(

TRUE /*fUseMemory*/,

STGM_READWRITE | STGM_TRANSACTED | STGM_SHARE_EXCLUSIVE

);

if (!lpstg)

return ResultFromScode(E_OUTOFMEMORY);

lpMedium->u.pstg = lpstg;

lpMedium->tymed = TYMED_ISTORAGE;

lpMedium->pUnkForRelease = NULL;

} else {

return ResultFromScode(DATA_E_FORMATETC);

}

} else if (lpMedium->tymed == TYMED_ISTORAGE) {

lpMedium->tymed = TYMED_ISTORAGE;

} else {

return ResultFromScode(DATA_E_FORMATETC);

}

// OLE2NOTE: even if OleSave returns an error you should still call

// SaveCompleted.

OLEDBG_BEGIN2("OleSave called\r\n")

hrErr = OleSave(lpPStg, lpMedium->u.pstg, FALSE /* fSameAsLoad */);

OLEDBG_END2

if (hrErr != NOERROR) {

OleDbgOutHResult("WARNING: OleSave returned", hrErr);

sc = GetScode(hrErr);

}

OLEDBG_BEGIN2("IPersistStorage::SaveCompleted called\r\n")

hrErr = lpPStg->lpVtbl->SaveCompleted(lpPStg, NULL);

OLEDBG_END2

if (hrErr != NOERROR) {

OleDbgOutHResult("WARNING: SaveCompleted returned",hrErr);

if (sc == S_OK)

sc = GetScode(hrErr);

}

return ResultFromScode(sc);

}

STDAPI OleStdGetLinkSourceData(

LPMONIKER           lpmk,

LPCLSID             lpClsID,

LPFORMATETC         lpformatetc,

LPSTGMEDIUM         lpMedium

)

{

LPSTREAM    lpstm = NULL;

DWORD       reserved = 0;

HRESULT     hrErr;

if (lpMedium->tymed == TYMED_NULL) {

if (lpformatetc->tymed & TYMED_ISTREAM) {

hrErr = CreateStreamOnHGlobal(

NULL, /* auto allocate */

TRUE, /* delete on release */

(LPSTREAM FAR*)&lpstm

);

if (hrErr != NOERROR) {

lpMedium->pUnkForRelease = NULL;

return ResultFromScode(E_OUTOFMEMORY);

}

lpMedium->u.pstm = lpstm;

lpMedium->tymed = TYMED_ISTREAM;

lpMedium->pUnkForRelease = NULL;

} else {

lpMedium->pUnkForRelease = NULL;

return ResultFromScode(DATA_E_FORMATETC);

}

} else {

if (lpMedium->tymed == TYMED_ISTREAM) {

lpMedium->tymed = TYMED_ISTREAM;

lpMedium->u.pstm = lpMedium->u.pstm;

lpMedium->pUnkForRelease = NULL;

} else {

lpMedium->pUnkForRelease = NULL;

return ResultFromScode(DATA_E_FORMATETC);

}

}

hrErr = OleSaveToStream((LPPERSISTSTREAM)lpmk, lpMedium->u.pstm);

if (hrErr != NOERROR) return hrErr;

return WriteClassStm(lpMedium->u.pstm, lpClsID);

}

/*

 * OleStdGetObjectDescriptorData

 *

 * Purpose:

 *  Fills and returns a OBJECTDESCRIPTOR structure.

 *  See OBJECTDESCRIPTOR for more information.

 *

 * Parameters:

 *  clsid           CLSID   CLSID of object being transferred

 *  dwDrawAspect    DWORD   Display Aspect of object

 *  sizel           SIZEL   Size of object in HIMETRIC

 *  pointl          POINTL  Offset from upper-left corner of object where mouse went

 *                          down for drag. Meaningful only when drag-drop is used.

 *  dwStatus        DWORD   OLEMISC flags

 *  lpszFullUserTypeName  LPSTR Full User Type Name

 *  lpszSrcOfCopy   LPSTR   Source of Copy

 *

 * Return Value:

 *  HBGLOBAL         Handle to OBJECTDESCRIPTOR structure.

 */

STDAPI_(HGLOBAL) OleStdGetObjectDescriptorData(

CLSID     clsid,

DWORD     dwDrawAspect,

SIZEL     sizel,

POINTL    pointl,

DWORD     dwStatus,

LPSTR     lpszFullUserTypeName,

LPSTR     lpszSrcOfCopy

)

{

HGLOBAL            hMem = NULL;

IBindCtx   FAR    *pbc = NULL;

LPOBJECTDESCRIPTOR lpOD;

DWORD              dwObjectDescSize, dwFullUserTypeNameLen, dwSrcOfCopyLen;

// Get the length of Full User Type Name; Add 1 for the null terminator

dwFullUserTypeNameLen = lpszFullUserTypeName ? lstrlen(lpszFullUserTypeName)+1 : 0;

// Get the Source of Copy string and it's length; Add 1 for the null terminator

if (lpszSrcOfCopy)

   dwSrcOfCopyLen = lstrlen(lpszSrcOfCopy)+1;

else {

   // No src moniker so use user type name as source string.

   lpszSrcOfCopy =  lpszFullUserTypeName;

   dwSrcOfCopyLen = dwFullUserTypeNameLen;

}

// Allocate space for OBJECTDESCRIPTOR and the additional string data

dwObjectDescSize = sizeof(OBJECTDESCRIPTOR);

hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE,

   dwObjectDescSize + dwFullUserTypeNameLen + dwSrcOfCopyLen);

if (NULL == hMem)

goto error;

lpOD = (LPOBJECTDESCRIPTOR)GlobalLock(hMem);

// Set the FullUserTypeName offset and copy the string

if (lpszFullUserTypeName)

{

lpOD->dwFullUserTypeName = dwObjectDescSize;

lstrcpy((LPSTR)lpOD+lpOD->dwFullUserTypeName , lpszFullUserTypeName);

}

else lpOD->dwFullUserTypeName = 0;  // zero offset indicates that string is not present

// Set the SrcOfCopy offset and copy the string

if (lpszSrcOfCopy)

{

lpOD->dwSrcOfCopy = dwObjectDescSize + dwFullUserTypeNameLen;

lstrcpy((LPSTR)lpOD+lpOD->dwSrcOfCopy , lpszSrcOfCopy);

}

else lpOD->dwSrcOfCopy = 0;  // zero offset indicates that string is not present

// Initialize the rest of the OBJECTDESCRIPTOR

lpOD->cbSize       = dwObjectDescSize + dwFullUserTypeNameLen + dwSrcOfCopyLen;

lpOD->clsid        = clsid;

lpOD->dwDrawAspect = dwDrawAspect;

lpOD->sizel        = sizel;

lpOD->pointl       = pointl;

lpOD->dwStatus     = dwStatus;

GlobalUnlock(hMem);

return hMem;

error:

   if (hMem)

   {

   GlobalUnlock(hMem);

   GlobalFree(hMem);

   }

   return NULL;

}

/*

 * OleStdGetObjectDescriptorDataFromOleObject

 *

 * Purpose:

 *  Fills and returns a OBJECTDESCRIPTOR structure. Information for the structure is

 *  obtained from an OLEOBJECT.

 *  See OBJECTDESCRIPTOR for more information.

 *

 * Parameters:

 *  lpOleObj        LPOLEOBJECT OleObject from which ONJECTDESCRIPTOR info

 *                  is obtained.

 *  lpszSrcOfCopy   LPSTR string to identify source of copy.

 *                  May be NULL in which case IOleObject::GetMoniker is called

 *                  to get the moniker of the object. if the object is loaded

 *                  as part of a data transfer document, then usually

 *                  lpOleClientSite==NULL is passed to OleLoad when loading

 *                  the object. in this case the IOleObject:GetMoniker call

 *                  will always fail (it tries to call back to the object's

 *                  client site). in this situation a non-NULL lpszSrcOfCopy

 *                  parameter should be passed.

 *  dwDrawAspect    DWORD   Display Aspect of object

 *  pointl          POINTL  Offset from upper-left corner of object where

 *                  mouse went down for drag. Meaningful only when drag-drop

 *                  is used.

 *  lpSizelHim      SIZEL   (optional) If the object is being scaled in its

 *                  container, then the container should pass the extents

 *                  that it is using to display the object.

 *                  May be NULL if the object is NOT being scaled. in this

 *                  case, IViewObject2::GetExtent will be called to get the

 *                  extents from the object.

 *

 * Return Value:

 *  HBGLOBAL         Handle to OBJECTDESCRIPTOR structure.

 */

STDAPI_(HGLOBAL) OleStdGetObjectDescriptorDataFromOleObject(

LPOLEOBJECT lpOleObj,

LPSTR       lpszSrcOfCopy,

DWORD       dwDrawAspect,

POINTL      pointl,

LPSIZEL     lpSizelHim

)

{

CLSID clsid;

LPSTR lpszFullUserTypeName = NULL;

LPMONIKER lpSrcMonikerOfCopy = NULL;

HGLOBAL hObjDesc;

IBindCtx  FAR  *pbc = NULL;

HRESULT hrErr;

SIZEL sizelHim;

BOOL  fFreeSrcOfCopy = FALSE;

LPOLELINK lpOleLink = (LPOLELINK)

   OleStdQueryInterface((LPUNKNOWN)lpOleObj,&IID_IOleLink);

LPVIEWOBJECT2 lpViewObj2 = (LPVIEWOBJECT2)

OleStdQueryInterface((LPUNKNOWN)lpOleObj, &IID_IViewObject2);

BOOL  fIsLink = (lpOleLink ? TRUE : FALSE);

char  szLinkedTypeFmt[80];

LPSTR lpszBuf = NULL;

DWORD dwStatus = 0;

// Get CLSID

OLEDBG_BEGIN2("IOleObject::GetUserClassID called\r\n")

hrErr = lpOleObj->lpVtbl->GetUserClassID(lpOleObj, &clsid);

OLEDBG_END2

if (hrErr != NOERROR)

clsid = CLSID_NULL;

// Get FullUserTypeName

OLEDBG_BEGIN2("IOleObject::GetUserType called\r\n")

hrErr = lpOleObj->lpVtbl->GetUserType(

lpOleObj,

USERCLASSTYPE_FULL,

(LPSTR FAR*)&lpszFullUserTypeName

);

OLEDBG_END2

// REVIEW: added IDS_OLE2UILINKEDTYPE to strings.rc

/* if object is a link, then expand usertypename to be "Linked %s" */

if (fIsLink && lpszFullUserTypeName) {

if (0 == LoadString(ghInst, (UINT)IDS_OLE2UIPASTELINKEDTYPE,

(LPSTR)szLinkedTypeFmt, sizeof(szLinkedTypeFmt)))

lstrcpy(szLinkedTypeFmt, (LPSTR)"Linked %s");

lpszBuf = OleStdMalloc(

lstrlen(lpszFullUserTypeName)+lstrlen(szLinkedTypeFmt)+1);

if (lpszBuf) {

wsprintf(lpszBuf, szLinkedTypeFmt, lpszFullUserTypeName);

OleStdFreeString(lpszFullUserTypeName, NULL);

lpszFullUserTypeName = lpszBuf;

}

}

/* Get Source Of Copy

**    if the object is an embedding, then get the object's moniker

**    if the object is a link, then get the link source moniker

*/

if (fIsLink) {

OLEDBG_BEGIN2("IOleLink::GetSourceDisplayName called\r\n")

hrErr = lpOleLink->lpVtbl->GetSourceDisplayName(

lpOleLink, &lpszSrcOfCopy );

OLEDBG_END2

fFreeSrcOfCopy = TRUE;

} else {

if (lpszSrcOfCopy == NULL) {

OLEDBG_BEGIN2("IOleObject::GetMoniker called\r\n")

hrErr = lpOleObj->lpVtbl->GetMoniker(

lpOleObj,

OLEGETMONIKER_TEMPFORUSER,

OLEWHICHMK_OBJFULL,

(LPMONIKER FAR*)&lpSrcMonikerOfCopy

);

OLEDBG_END2

if (hrErr == NOERROR)

{

CreateBindCtx(0, (LPBC FAR*)&pbc);

lpSrcMonikerOfCopy->lpVtbl->GetDisplayName(

lpSrcMonikerOfCopy, pbc, NULL, &lpszSrcOfCopy);

pbc->lpVtbl->Release(pbc);

fFreeSrcOfCopy = TRUE;

}

}

}

// Get SIZEL

if (lpSizelHim) {

// Use extents passed by the caller

sizelHim = *lpSizelHim;

} else if (lpViewObj2) {

// Get the current extents from the object

OLEDBG_BEGIN2("IViewObject2::GetExtent called\r\n")

hrErr = lpViewObj2->lpVtbl->GetExtent(

lpViewObj2,

dwDrawAspect,

-1,     /*lindex*/

NULL,   /*ptd*/

(LPSIZEL)&sizelHim

);

OLEDBG_END2

if (hrErr != NOERROR)

sizelHim.cx = sizelHim.cy = 0;

} else {

sizelHim.cx = sizelHim.cy = 0;

}

// Get DWSTATUS

OLEDBG_BEGIN2("IOleObject::GetMiscStatus called\r\n")

hrErr = lpOleObj->lpVtbl->GetMiscStatus(

lpOleObj,

dwDrawAspect,

&dwStatus

);

OLEDBG_END2

if (hrErr != NOERROR)

dwStatus = 0;

// Get OBJECTDESCRIPTOR

hObjDesc = OleStdGetObjectDescriptorData(

clsid,

dwDrawAspect,

sizelHim,

pointl,

dwStatus,

lpszFullUserTypeName,

lpszSrcOfCopy

);

if (! hObjDesc)

goto error;

// Clean up

if (lpszFullUserTypeName)

OleStdFreeString(lpszFullUserTypeName, NULL);

if (fFreeSrcOfCopy && lpszSrcOfCopy)

OleStdFreeString(lpszSrcOfCopy, NULL);

if (lpSrcMonikerOfCopy)

OleStdRelease((LPUNKNOWN)lpSrcMonikerOfCopy);

if (lpOleLink)

OleStdRelease((LPUNKNOWN)lpOleLink);

if (lpViewObj2)

OleStdRelease((LPUNKNOWN)lpViewObj2);

return hObjDesc;

error:

if (lpszFullUserTypeName)

OleStdFreeString(lpszFullUserTypeName, NULL);

if (fFreeSrcOfCopy && lpszSrcOfCopy)

OleStdFreeString(lpszSrcOfCopy, NULL);

if (lpSrcMonikerOfCopy)

OleStdRelease((LPUNKNOWN)lpSrcMonikerOfCopy);

if (lpOleLink)

OleStdRelease((LPUNKNOWN)lpOleLink);

if (lpViewObj2)

OleStdRelease((LPUNKNOWN)lpViewObj2);

return NULL;

}

/*

 * OleStdFillObjectDescriptorFromData

 *

 * Purpose:

 *  Fills and returns a OBJECTDESCRIPTOR structure. The source object will

 *  offer CF_OBJECTDESCRIPTOR if it is an OLE2 object, CF_OWNERLINK if it

 *  is an OLE1 object, or CF_FILENAME if it has been copied to the clipboard

 *  by FileManager.

 *

 * Parameters:

 *  lpDataObject    LPDATAOBJECT Source object

 *  lpmedium        LPSTGMEDIUM  Storage medium

 *  lpcfFmt         CLIPFORMAT FAR * Format offered by lpDataObject

 *                  (OUT parameter)

 *

 * Return Value:

 *  HBGLOBAL         Handle to OBJECTDESCRIPTOR structure.

 */

STDAPI_(HGLOBAL) OleStdFillObjectDescriptorFromData(

LPDATAOBJECT     lpDataObject,

LPSTGMEDIUM      lpmedium,

CLIPFORMAT FAR* lpcfFmt

)

{

CLSID              clsid;

SIZEL              sizelHim;

POINTL             pointl;

LPSTR              lpsz, szFullUserTypeName, szSrcOfCopy, szClassName, szDocName, szItemName;

int                nClassName, nDocName, nItemName, nFullUserTypeName;

LPSTR              szBuf = NULL;

HGLOBAL            hMem = NULL;

HKEY               hKey = NULL;

LPMALLOC           pIMalloc = NULL;

DWORD              dw = OLEUI_CCHKEYMAX;

HGLOBAL            hObjDesc;

HRESULT            hrErr;

// GetData CF_OBJECTDESCRIPTOR format from the object on the clipboard.

// Only OLE 2 objects on the clipboard will offer CF_OBJECTDESCRIPTOR

if (hMem = OleStdGetData(

lpDataObject,

(CLIPFORMAT) cfObjectDescriptor,

NULL,

DVASPECT_CONTENT,

lpmedium))

{

*lpcfFmt = cfObjectDescriptor;

return hMem;  // Don't drop to clean up at the end of this function

}

// If CF_OBJECTDESCRIPTOR is not available, i.e. if this is not an OLE2 object,

//     check if this is an OLE 1 object. OLE 1 objects will offer CF_OWNERLINK

else if (hMem = OleStdGetData(

lpDataObject,

(CLIPFORMAT) cfOwnerLink,

NULL,

DVASPECT_CONTENT,

lpmedium))

{

*lpcfFmt = cfOwnerLink;

// CF_OWNERLINK contains null-terminated strings for class name, document name

// and item name with two null terminating characters at the end

szClassName = (LPSTR)GlobalLock(hMem);

nClassName = lstrlen(szClassName);

szDocName   = szClassName + nClassName + 1;

nDocName   = lstrlen(szDocName);

szItemName  = szDocName + nDocName + 1;

nItemName  =  lstrlen(szItemName);

hrErr = CoGetMalloc(MEMCTX_TASK, &pIMalloc);

if (hrErr != NOERROR)

goto error;

// Find FullUserTypeName from Registration database using class name

if (RegOpenKey(HKEY_CLASSES_ROOT, NULL, &hKey) != ERROR_SUCCESS)

   goto error;

// Allocate space for szFullUserTypeName & szSrcOfCopy. Maximum length of FullUserTypeName

// is OLEUI_CCHKEYMAX. SrcOfCopy is constructed by concatenating FullUserTypeName, Document

// Name and ItemName separated by spaces.

szBuf = (LPSTR)pIMalloc->lpVtbl->Alloc(pIMalloc,

(DWORD)2*OLEUI_CCHKEYMAX+nDocName+nItemName+4);

if (NULL == szBuf)

goto error;

szFullUserTypeName = szBuf;

szSrcOfCopy = szFullUserTypeName+OLEUI_CCHKEYMAX+1;

// Get FullUserTypeName

if (RegQueryValue(hKey, NULL, szFullUserTypeName, &dw) != ERROR_SUCCESS)

   goto error;

// Build up SrcOfCopy string from FullUserTypeName, DocumentName & ItemName

lpsz = szSrcOfCopy;

lstrcpy(lpsz, szFullUserTypeName);

nFullUserTypeName = lstrlen(szFullUserTypeName);

lpsz[nFullUserTypeName]=' ';

lpsz += nFullUserTypeName+1;

lstrcpy(lpsz, szDocName);

lpsz[nDocName] = ' ';

lpsz += nDocName+1;

lstrcpy(lpsz, szItemName);

sizelHim.cx = sizelHim.cy = 0;

pointl.x = pointl.y = 0;

CLSIDFromProgID(szClassName, &clsid);

hObjDesc = OleStdGetObjectDescriptorData(

clsid,

DVASPECT_CONTENT,

sizelHim,

pointl,

0,

szFullUserTypeName,

szSrcOfCopy

);

if (!hObjDesc)

   goto error;

 }

 // Check if object is CF_FILENAME

 else if (hMem = OleStdGetData(

lpDataObject,

(CLIPFORMAT) cfFileName,

NULL,

DVASPECT_CONTENT,

lpmedium))

 {

 *lpcfFmt = cfFileName;

 lpsz = (LPSTR)GlobalLock(hMem);

 hrErr = GetClassFile(lpsz, &clsid);

 /* OLE2NOTE: if the file does not have an OLE class

 **    associated, then use the OLE 1 Packager as the class of

 **    the object to be created. this is the behavior of

 **    OleCreateFromData API

 */

 if (hrErr != NOERROR)

CLSIDFromProgID("Package", &clsid);

 sizelHim.cx = sizelHim.cy = 0;

 pointl.x = pointl.y = 0;

 hrErr = CoGetMalloc(MEMCTX_TASK, &pIMalloc);

 if (hrErr != NOERROR)

goto error;

 szBuf = (LPSTR)pIMalloc->lpVtbl->Alloc(pIMalloc, (DWORD)OLEUI_CCHKEYMAX);

 if (NULL == szBuf)

goto error;

 OleStdGetUserTypeOfClass(&clsid, szBuf, OLEUI_CCHKEYMAX, NULL);

 hObjDesc = OleStdGetObjectDescriptorData(

clsid,

DVASPECT_CONTENT,

sizelHim,

pointl,

0,

szBuf,

lpsz

);

if (!hObjDesc)

   goto error;

 }

 else goto error;

 // Clean up

 if (szBuf)

 pIMalloc->lpVtbl->Free(pIMalloc, (LPVOID)szBuf);

 if (pIMalloc)

 pIMalloc->lpVtbl->Release(pIMalloc);

 if (hMem)

 {

 GlobalUnlock(hMem);

 GlobalFree(hMem);

 }

 if (hKey)

 RegCloseKey(hKey);

 return hObjDesc;

error:

   if (szBuf)

   pIMalloc->lpVtbl->Free(pIMalloc, (LPVOID)szBuf);

   if (pIMalloc)

   pIMalloc->lpVtbl->Release(pIMalloc);

 if (hMem)

 {

 GlobalUnlock(hMem);

 GlobalFree(hMem);

 }

 if (hKey)

 RegCloseKey(hKey);

 return NULL;

}

#if defined( OBSOLETE )

/*************************************************************************

** The following API's have been converted into macros:

**          OleStdQueryOleObjectData

**          OleStdQueryLinkSourceData

**          OleStdQueryObjectDescriptorData

**          OleStdQueryFormatMedium

**          OleStdCopyMetafilePict

**          OleStdGetDropEffect

**

**    These macros are defined in olestd.h

*************************************************************************/

STDAPI OleStdQueryOleObjectData(LPFORMATETC lpformatetc)

{

if (lpformatetc->tymed & TYMED_ISTORAGE) {

return NOERROR;

} else {

return ResultFromScode(DATA_E_FORMATETC);

}

}

STDAPI OleStdQueryLinkSourceData(LPFORMATETC lpformatetc)

{

if (lpformatetc->tymed & TYMED_ISTREAM) {

return NOERROR;

} else {

return ResultFromScode(DATA_E_FORMATETC);

}

}

STDAPI OleStdQueryObjectDescriptorData(LPFORMATETC lpformatetc)

{

if (lpformatetc->tymed & TYMED_HGLOBAL) {

return NOERROR;

} else {

return ResultFromScode(DATA_E_FORMATETC);

}

}

STDAPI OleStdQueryFormatMedium(LPFORMATETC lpformatetc, TYMED tymed)

{

if (lpformatetc->tymed & tymed) {

return NOERROR;

} else {

return ResultFromScode(DATA_E_FORMATETC);

}

}

/*

 * OleStdCopyMetafilePict()

 *

 * Purpose:

 *    Make an independent copy of a MetafilePict

 * Parameters:

 *

 * Return Value:

 *    TRUE if successful, else FALSE.

 */

STDAPI_(BOOL) OleStdCopyMetafilePict(HANDLE hpictin, HANDLE FAR* phpictout)

{

HANDLE hpictout;

LPMETAFILEPICT ppictin, ppictout;

if (hpictin == NULL || phpictout == NULL) {

OleDbgAssert(hpictin == NULL || phpictout == NULL);

return FALSE;

}

*phpictout = NULL;

if ((ppictin = (LPMETAFILEPICT)GlobalLock(hpictin)) == NULL) {

return FALSE;

}

hpictout = GlobalAlloc(GHND|GMEM_SHARE, sizeof(METAFILEPICT));

if (hpictout && (ppictout = (LPMETAFILEPICT)GlobalLock(hpictout))){

ppictout->hMF  = CopyMetaFile(ppictin->hMF, NULL);

ppictout->xExt = ppictin->xExt;

ppictout->yExt = ppictin->yExt;

ppictout->mm   = ppictin->mm;

GlobalUnlock(hpictout);

}

*phpictout = hpictout;

return TRUE;

}

/* OleStdGetDropEffect

** -------------------

**

** Convert a keyboard state into a DROPEFFECT.

**

** returns the DROPEFFECT value derived from the key state.

**    the following is the standard interpretation:

**          no modifier -- Default Drop     (NULL is returned)

**          CTRL        -- DROPEFFECT_COPY

**          SHIFT       -- DROPEFFECT_MOVE

**          CTRL-SHIFT  -- DROPEFFECT_LINK

**

**    Default Drop: this depends on the type of the target application.

**    this is re-interpretable by each target application. a typical

**    interpretation is if the drag is local to the same document

**    (which is source of the drag) then a MOVE operation is

**    performed. if the drag is not local, then a COPY operation is

**    performed.

*/

STDAPI_(DWORD) OleStdGetDropEffect( DWORD grfKeyState )

{

if (grfKeyState & MK_CONTROL) {

if (grfKeyState & MK_SHIFT)

return DROPEFFECT_LINK;

else

return DROPEFFECT_COPY;

} else if (grfKeyState & MK_SHIFT)

return DROPEFFECT_MOVE;

return 0;    // no modifier -- do default operation

}

#endif  // OBSOLETE

/*

 * OleStdGetMetafilePictFromOleObject()

 *

 * Purpose:

 *      Generate a MetafilePict by drawing the OLE object.

 * Parameters:

 *  lpOleObj        LPOLEOBJECT pointer to OLE Object

 *  dwDrawAspect    DWORD   Display Aspect of object

 *  lpSizelHim      SIZEL   (optional) If the object is being scaled in its

 *                  container, then the container should pass the extents

 *                  that it is using to display the object.

 *                  May be NULL if the object is NOT being scaled. in this

 *                  case, IViewObject2::GetExtent will be called to get the

 *                  extents from the object.

 *  ptd             TARGETDEVICE FAR*   (optional) target device to render

 *                  metafile for. May be NULL.

 *

 * Return Value:

 *    HANDLE    -- handle of allocated METAFILEPICT

 */

STDAPI_(HANDLE) OleStdGetMetafilePictFromOleObject(

LPOLEOBJECT         lpOleObj,

DWORD               dwDrawAspect,

LPSIZEL             lpSizelHim,

DVTARGETDEVICE FAR* ptd

)

{

LPVIEWOBJECT2 lpViewObj2 = NULL;

HDC hDC;

HMETAFILE hmf;

HANDLE hMetaPict;

LPMETAFILEPICT lpPict;

RECT rcHim;

RECTL rclHim;

SIZEL sizelHim;

HRESULT hrErr;

SIZE size;

POINT point;

lpViewObj2 = (LPVIEWOBJECT2)OleStdQueryInterface(

(LPUNKNOWN)lpOleObj, &IID_IViewObject2);

if (! lpViewObj2)

return NULL;

// Get SIZEL

if (lpSizelHim) {

// Use extents passed by the caller

sizelHim = *lpSizelHim;

} else {

// Get the current extents from the object

OLEDBG_BEGIN2("IViewObject2::GetExtent called\r\n")

hrErr = lpViewObj2->lpVtbl->GetExtent(

lpViewObj2,

dwDrawAspect,

-1,     /*lindex*/

ptd,    /*ptd*/

(LPSIZEL)&sizelHim

);

OLEDBG_END2

if (hrErr != NOERROR)

sizelHim.cx = sizelHim.cy = 0;

}

hDC = CreateMetaFile(NULL);

rclHim.left     = 0;

rclHim.top      = 0;

rclHim.right    = sizelHim.cx;

rclHim.bottom   = sizelHim.cy;

rcHim.left      = (int)rclHim.left;

rcHim.top       = (int)rclHim.top;

rcHim.right     = (int)rclHim.right;

rcHim.bottom    = (int)rclHim.bottom;

SetWindowOrgEx(hDC, rcHim.left, rcHim.top, &point);

SetWindowExtEx(hDC, rcHim.right-rcHim.left, rcHim.bottom-rcHim.top,&size);

OLEDBG_BEGIN2("IViewObject::Draw called\r\n")

hrErr = lpViewObj2->lpVtbl->Draw(

lpViewObj2,

dwDrawAspect,

-1,

NULL,

ptd,

NULL,

hDC,

(LPRECTL)&rclHim,

(LPRECTL)&rclHim,

NULL,

0

);

OLEDBG_END2

OleStdRelease((LPUNKNOWN)lpViewObj2);

if (hrErr != NOERROR) {

OleDbgOutHResult("IViewObject::Draw returned", hrErr);

}

hmf = CloseMetaFile(hDC);

hMetaPict = GlobalAlloc(GHND|GMEM_SHARE, sizeof(METAFILEPICT));

if (hMetaPict && (lpPict = (LPMETAFILEPICT)GlobalLock(hMetaPict))){

lpPict->hMF  = hmf;

lpPict->xExt = (int)sizelHim.cx ;

lpPict->yExt = (int)sizelHim.cy ;

lpPict->mm   = MM_ANISOTROPIC;

GlobalUnlock(hMetaPict);

}

return hMetaPict;

}

/* Call Release on the object that is expected to go away.

**      if the refcnt of the object did no go to 0 then give a debug message.

*/

STDAPI_(ULONG) OleStdVerifyRelease(LPUNKNOWN lpUnk, LPSTR lpszMsg)

{

ULONG cRef;

cRef = lpUnk->lpVtbl->Release(lpUnk);

#if defined( _DEBUG )

if (cRef != 0) {

char szBuf[80];

if (lpszMsg)

MessageBox(NULL, lpszMsg, NULL, MB_ICONEXCLAMATION | MB_OK);

wsprintf(

(LPSTR)szBuf,

"refcnt (%ld) != 0 after object (0x%lx) release\n",

cRef,

lpUnk

);

if (lpszMsg)

OleDbgOut1(lpszMsg);

OleDbgOut1((LPSTR)szBuf);

OleDbgAssertSz(cRef == 0, (LPSTR)szBuf);

} else {

char szBuf[80];

wsprintf(

(LPSTR)szBuf,

"refcnt = 0 after object (0x%lx) release\n", lpUnk

);

OleDbgOut4((LPSTR)szBuf);

}

#endif

return cRef;

}

/* Call Release on the object that is NOT necessarily expected to go away.

*/

STDAPI_(ULONG) OleStdRelease(LPUNKNOWN lpUnk)

{

ULONG cRef;

cRef = lpUnk->lpVtbl->Release(lpUnk);

#if defined( _DEBUG )

{

char szBuf[80];

wsprintf(

(LPSTR)szBuf,

"refcnt = %ld after object (0x%lx) release\n",

cRef,

lpUnk

);

OleDbgOut4((LPSTR)szBuf);

}

#endif

return cRef;

}

/* OleStdInitVtbl

** --------------

**

**    Initialize an interface Vtbl to ensure that there are no NULL

**    function pointers in the Vtbl. All entries in the Vtbl are

**    set to a valid funtion pointer (OleStdNullMethod) that issues

**        debug assert message (message box) and returns E_NOTIMPL if called.

**

**    NOTE: this funtion does not initialize the Vtbl with usefull

**    function pointers, only valid function pointers to avoid the

**    horrible run-time crash when a call is made through the Vtbl with

**    a NULL function pointer. this API is only necessary when

**    initializing the Vtbl's in C. C++ guarantees that all interface

**    functions (in C++ terms -- pure virtual functions) are implemented.

*/

STDAPI_(void) OleStdInitVtbl(LPVOID lpVtbl, UINT nSizeOfVtbl)

{

LPVOID FAR* lpFuncPtrArr = (LPVOID FAR*)lpVtbl;

UINT nMethods = nSizeOfVtbl/sizeof(VOID FAR*);

UINT i;

for (i = 0; i < nMethods; i++) {

lpFuncPtrArr[i] = OleStdNullMethod;

}

}

/* OleStdCheckVtbl

** ---------------

**

**    Check if all entries in the Vtbl are properly initialized with

**    valid function pointers. If any entries are either NULL or

**    OleStdNullMethod, then this function returns FALSE. If compiled

**    for _DEBUG this function reports which function pointers are

**    invalid.

**

**    RETURNS:  TRUE if all entries in Vtbl are valid

**                              FALSE otherwise.

*/

STDAPI_(BOOL) OleStdCheckVtbl(LPVOID lpVtbl, UINT nSizeOfVtbl, LPSTR lpszIface)

{

LPVOID FAR* lpFuncPtrArr = (LPVOID FAR*)lpVtbl;

UINT nMethods = nSizeOfVtbl/sizeof(VOID FAR*);

UINT i;

BOOL fStatus = TRUE;

int nChar = 0;

for (i = 0; i < nMethods; i++) {

if (lpFuncPtrArr[i] == NULL || lpFuncPtrArr[i] == OleStdNullMethod) {

#if defined( _DEBUG )

char szBuf[256];

wsprintf(szBuf, "%s::method# %d NOT valid!", lpszIface, i);

OleDbgOut1((LPSTR)szBuf);

#endif

fStatus = FALSE;

}

}

return fStatus;

}

/* OleStdNullMethod

** ----------------

**    Dummy method used by OleStdInitVtbl to initialize an interface

**    Vtbl to ensure that there are no NULL function pointers in the

**    Vtbl. All entries in the Vtbl are set to this function. this

**    function issues a debug assert message (message box) and returns

**    E_NOTIMPL if called. If all is done properly, this function will

**    NEVER be called!

*/

STDMETHODIMP OleStdNullMethod(LPUNKNOWN lpThis)

{

MessageBox(

NULL,

"ERROR: INTERFACE METHOD NOT IMPLEMENTED!\r\n",

NULL,

MB_SYSTEMMODAL | MB_ICONHAND | MB_OK

);

return ResultFromScode(E_NOTIMPL);

}

static BOOL  GetFileTimes(LPSTR lpszFileName, FILETIME FAR* pfiletime)

{

#ifdef WIN32

WIN32_FIND_DATA fd;

HANDLE hFind;

hFind = FindFirstFile(lpszFileName,&fd);

if (hFind == NULL || hFind == INVALID_HANDLE_VALUE) {

return FALSE;

}

FindClose(hFind);

*pfiletime = fd.ftLastWriteTime;

return TRUE;

#else

static char sz[256];

static struct _find_t fileinfo;

LSTRCPYN((LPSTR)sz, lpszFileName, sizeof(sz)-1);

sz[sizeof(sz)-1]= '\0';

AnsiToOem(sz, sz);

return (_dos_findfirst(sz,_A_NORMAL|_A_HIDDEN|_A_SUBDIR|_A_SYSTEM,

 (struct _find_t *)&fileinfo) == 0 &&

CoDosDateTimeToFileTime(fileinfo.wr_date,fileinfo.wr_time,pfiletime));

#endif

}

/* OleStdRegisterAsRunning

** -----------------------

**    Register a moniker in the RunningObjectTable.

**    if there is an existing registration (*lpdwRegister!=NULL), then

**    first revoke that registration.

**

**    new dwRegister key is returned via *lpdwRegister parameter.

*/

STDAPI_(void) OleStdRegisterAsRunning(LPUNKNOWN lpUnk, LPMONIKER lpmkFull, DWORD FAR* lpdwRegister)

{

LPRUNNINGOBJECTTABLE lpROT;

HRESULT hrErr;

DWORD dwOldRegister = *lpdwRegister;

OLEDBG_BEGIN2("OleStdRegisterAsRunning\r\n")

OLEDBG_BEGIN2("GetRunningObjectTable called\r\n")

hrErr = GetRunningObjectTable(0,(LPRUNNINGOBJECTTABLE FAR*)&lpROT);

OLEDBG_END2

if (hrErr == NOERROR) {

/* register as running if a valid moniker is passed

**

** OLE2NOTE: we deliberately register the new moniker BEFORE

**    revoking the old moniker just in case the object

**    currently has no external locks. if the object has no

**    locks then revoking it from the running object table will

**    cause the object's StubManager to initiate shutdown of

**    the object.

*/

if (lpmkFull) {

OLEDBG_BEGIN2("IRunningObjectTable::Register called\r\n")

lpROT->lpVtbl->Register(lpROT, 0, lpUnk,lpmkFull,lpdwRegister);

OLEDBG_END2

#if defined(_DEBUG)

{

char szBuf[512];

LPSTR lpszDisplay;

LPBC lpbc;

CreateBindCtx(0, (LPBC FAR*)&lpbc);

lpmkFull->lpVtbl->GetDisplayName(

lpmkFull,

lpbc,

NULL,

(LPSTR FAR*)&lpszDisplay

);

OleStdRelease((LPUNKNOWN)lpbc);

wsprintf(

szBuf,

"Moniker '%s' REGISTERED as [0x%lx] in ROT\r\n",

lpszDisplay,

*lpdwRegister

);

OleDbgOut2(szBuf);

OleStdFreeString(lpszDisplay, NULL);

}

#endif  // _DEBUG

}

// if already registered, revoke

if (dwOldRegister != 0) {

#if defined(_DEBUG)

{

char szBuf[512];

wsprintf(

szBuf,

"Moniker [0x%lx] REVOKED from ROT\r\n",

dwOldRegister

);

OleDbgOut2(szBuf);

}

#endif  // _DEBUG

OLEDBG_BEGIN2("IRunningObjectTable::Revoke called\r\n")

lpROT->lpVtbl->Revoke(lpROT, dwOldRegister);

OLEDBG_END2

}

OleStdRelease((LPUNKNOWN)lpROT);

} else {

OleDbgAssertSz(

lpROT != NULL,

"OleStdRegisterAsRunning: GetRunningObjectTable FAILED\r\n"

);

}

OLEDBG_END2

}

/* OleStdRevokeAsRunning

** ---------------------

**    Revoke a moniker from the RunningObjectTable if there is an

**    existing registration (*lpdwRegister!=NULL).

**

**    *lpdwRegister parameter will be set to NULL.

*/

STDAPI_(void) OleStdRevokeAsRunning(DWORD FAR* lpdwRegister)

{

LPRUNNINGOBJECTTABLE lpROT;

HRESULT hrErr;

OLEDBG_BEGIN2("OleStdRevokeAsRunning\r\n")

// if still registered, then revoke

if (*lpdwRegister != 0) {

OLEDBG_BEGIN2("GetRunningObjectTable called\r\n")

hrErr = GetRunningObjectTable(0,(LPRUNNINGOBJECTTABLE FAR*)&lpROT);

OLEDBG_END2

if (hrErr == NOERROR) {

#if defined(_DEBUG)

{

char szBuf[512];

wsprintf(

szBuf,

"Moniker [0x%lx] REVOKED from ROT\r\n",

*lpdwRegister

);

OleDbgOut2(szBuf);

}

#endif  // _DEBUG

OLEDBG_BEGIN2("IRunningObjectTable::Revoke called\r\n")

lpROT->lpVtbl->Revoke(lpROT, *lpdwRegister);

OLEDBG_END2

*lpdwRegister = 0;

OleStdRelease((LPUNKNOWN)lpROT);

} else {

OleDbgAssertSz(

lpROT != NULL,

"OleStdRevokeAsRunning: GetRunningObjectTable FAILED\r\n"

);

}

}

OLEDBG_END2

}

/* OleStdNoteFileChangeTime

** ------------------------

**    Note the time a File-Based object has been saved in the

**    RunningObjectTable. These change times are used as the basis for

**    IOleObject::IsUpToDate.

**    It is important to set the time of the file-based object

**    following a save operation to exactly the time of the saved file.

**    this helps IOleObject::IsUpToDate to give the correct answer

**    after a file has been saved.

*/

STDAPI_(void) OleStdNoteFileChangeTime(LPSTR lpszFileName, DWORD dwRegister)

{

if (dwRegister != 0) {

LPRUNNINGOBJECTTABLE lprot;

FILETIME filetime;

if (GetFileTimes(lpszFileName, &filetime) &&

GetRunningObjectTable(0,&lprot) == NOERROR)

{

lprot->lpVtbl->NoteChangeTime( lprot, dwRegister, &filetime );

lprot->lpVtbl->Release(lprot);

OleDbgOut2("IRunningObjectTable::NoteChangeTime called\r\n");

}

}

}

/* OleStdNoteObjectChangeTime

** --------------------------

**    Set the last change time of an object that is registered in the

**    RunningObjectTable. These change times are used as the basis for

**    IOleObject::IsUpToDate.

**

**    every time the object sends out a OnDataChange notification, it

**    should update the Time of last change in the ROT.

**

**    NOTE: this function set the change time to the current time.

*/

STDAPI_(void) OleStdNoteObjectChangeTime(DWORD dwRegister)

{

if (dwRegister != 0) {

LPRUNNINGOBJECTTABLE lprot;

FILETIME filetime;

if (GetRunningObjectTable(0,&lprot) == NOERROR)

{

CoFileTimeNow( &filetime );

lprot->lpVtbl->NoteChangeTime( lprot, dwRegister, &filetime );

lprot->lpVtbl->Release(lprot);

OleDbgOut2("IRunningObjectTable::NoteChangeTime called\r\n");

}

}

}

/* OleStdCreateTempFileMoniker

** ---------------------------

**    return the next available FileMoniker that can be used as the

**    name of an untitled document.

**    the FileMoniker is built of the form:

**          <lpszPrefixString><number>

**      eg. "Outline1", "Outline2", etc.

**

**    The RunningObjectTable (ROT) is consulted to determine if a

**    FileMoniker is in use. If the name is in use then the number is

**    incremented and the ROT is checked again.

**

** Parameters:

**    LPSTR lpszPrefixString    - prefix used to build the name

**    UINT FAR* lpuUnique       - (IN-OUT) last used number.

**                                  this number is used to make the

**                                  name unique. on entry, the input

**                                  number is incremented. on output,

**                                  the number used is returned. this

**                                  number should be passed again

**                                  unchanged on the next call.

**    LPSTR lpszName            - (OUT) buffer used to build string.

**                                  caller must be sure buffer is large

**                                  enough to hold the generated string.

**    LPMONIKER FAR* lplpmk     - (OUT) next unused FileMoniker

**

** Returns:

**    void

**

** Comments:

**    This function is similar in spirit to the Windows API

**    CreateTempFileName.

*/

STDAPI_(void) OleStdCreateTempFileMoniker(

LPSTR           lpszPrefixString,

UINT FAR*       lpuUnique,

LPSTR           lpszName,

LPMONIKER FAR*  lplpmk

)

{

LPRUNNINGOBJECTTABLE lpROT = NULL;

UINT i = (lpuUnique != NULL ? *lpuUnique : 1);

HRESULT hrErr;

wsprintf(lpszName, "%s%d", lpszPrefixString, i++);

CreateFileMoniker(lpszName, lplpmk);

OLEDBG_BEGIN2("GetRunningObjectTable called\r\n")

hrErr = GetRunningObjectTable(0,(LPRUNNINGOBJECTTABLE FAR*)&lpROT);

OLEDBG_END2

if (hrErr == NOERROR) {

while (1) {

if (! *lplpmk)

break;  // failed to create FileMoniker

OLEDBG_BEGIN2("IRunningObjectTable::IsRunning called\r\n")

hrErr = lpROT->lpVtbl->IsRunning(lpROT,*lplpmk);

OLEDBG_END2

if (hrErr != NOERROR)

break;  // the Moniker is NOT running; found unused one!

OleStdVerifyRelease(

(LPUNKNOWN)*lplpmk,

"OleStdCreateTempFileMoniker: Moniker NOT released"

);

wsprintf(lpszName, "%s%d", lpszPrefixString, i++);

CreateFileMoniker(lpszName, lplpmk);

}

OleStdRelease((LPUNKNOWN)lpROT);

}

if (lpuUnique != NULL)

*lpuUnique = i;

}

/* OleStdGetFirstMoniker

** ---------------------

**    return the first piece of a moniker.

**

**    NOTE: if the given moniker is not a generic composite moniker,

**    then an AddRef'ed pointer to the given moniker is returned.

*/

STDAPI_(LPMONIKER) OleStdGetFirstMoniker(LPMONIKER lpmk)

{

LPMONIKER       lpmkFirst = NULL;

LPENUMMONIKER   lpenumMoniker;

DWORD           dwMksys;

HRESULT         hrErr;

if (! lpmk)

return NULL;

if (lpmk->lpVtbl->IsSystemMoniker(lpmk, (LPDWORD)&dwMksys) == NOERROR

&& dwMksys == MKSYS_GENERICCOMPOSITE) {

/* OLE2NOTE: the moniker is a GenericCompositeMoniker.

**    enumerate the moniker to pull off the first piece.

*/

hrErr = lpmk->lpVtbl->Enum(

lpmk,

TRUE /* fForward */,

(LPENUMMONIKER FAR*)&lpenumMoniker

);

if (hrErr != NOERROR)

return NULL;    // ERROR: give up!

hrErr = lpenumMoniker->lpVtbl->Next(

lpenumMoniker,

1,

(LPMONIKER FAR*)&lpmkFirst,

NULL

);

lpenumMoniker->lpVtbl->Release(lpenumMoniker);

return lpmkFirst;

} else {

/* OLE2NOTE: the moniker is NOT a GenericCompositeMoniker.

**    return an AddRef'ed pointer to the input moniker.

*/

lpmk->lpVtbl->AddRef(lpmk);

return lpmk;

}

}

/* OleStdGetLenFilePrefixOfMoniker

** -------------------------------

**    if the first piece of the Moniker is a FileMoniker, then return

**    the length of the filename string.

**

**    lpmk      pointer to moniker

**

**    Returns

**      0       if moniker does NOT start with a FileMoniker

**      uLen    string length of filename prefix of the display name

**              retrieved from the given (lpmk) moniker.

*/

STDAPI_(ULONG) OleStdGetLenFilePrefixOfMoniker(LPMONIKER lpmk)

{

LPMONIKER       lpmkFirst = NULL;

DWORD           dwMksys;

LPSTR           lpsz = NULL;

LPBC            lpbc = NULL;

ULONG           uLen = 0;

HRESULT         hrErr;

if (! lpmk)

return 0;

lpmkFirst = OleStdGetFirstMoniker(lpmk);

if (lpmkFirst) {

if ( (lpmkFirst->lpVtbl->IsSystemMoniker(

lpmkFirst, (LPDWORD)&dwMksys) == NOERROR)

&& dwMksys == MKSYS_FILEMONIKER) {

hrErr = CreateBindCtx(0, (LPBC FAR*)&lpbc);

if (hrErr == NOERROR) {

hrErr = lpmkFirst->lpVtbl->GetDisplayName(

lpmkFirst,

lpbc,

NULL,   /* pmkToLeft */

(LPSTR FAR*)&lpsz

);

if (hrErr == NOERROR && lpsz != NULL) {

uLen = lstrlen(lpsz);

OleStdFreeString(lpsz, NULL);

}

OleStdRelease((LPUNKNOWN)lpbc);

}

}

lpmkFirst->lpVtbl->Release(lpmkFirst);

}

return uLen;

}

/* OleStdMkParseDisplayName

**    Parse a string into a Moniker by calling the OLE API

**    MkParseDisplayName. if the original link source class was an OLE1

**    class, then attempt the parsing assuming the same class applies.

**

**    if the class of the previous link source was an OLE1 class,

**    then first attempt to parse a string that it is qualified

**    with the progID associated with the OLE1 class. this more

**    closely matches the semantics of OLE1 where the class of

**    link sources is not expected to change. prefixing the

**    string with "@<ProgID -- OLE1 class name>!" will force the

**    parsing of the string to assume the file is of that

**    class.

**    NOTE: this trick of prepending the string with "@<ProgID>

**    only works for OLE1 classes.

**

**  PARAMETERS:

**    REFCLSID rClsid       -- original class of link source.

**                              CLSID_NULL if class is unknown

**    ... other parameters the same as MkParseDisplayName API ...

**

**  RETURNS

**    NOERROR if string parsed successfully

**    else error code returned by MkParseDisplayName

*/

STDAPI OleStdMkParseDisplayName(

REFCLSID        rClsid,

LPBC            lpbc,

LPSTR           lpszUserName,

ULONG FAR*      lpchEaten,

LPMONIKER FAR*  lplpmk

)

{

HRESULT hrErr;

if (!IsEqualCLSID(rClsid,&CLSID_NULL) && CoIsOle1Class(rClsid) &&

lpszUserName[0] != '@') {

LPSTR lpszBuf;

LPSTR lpszProgID;

// Prepend "@<ProgID>!" to the input string

ProgIDFromCLSID(rClsid, &lpszProgID);

if (lpszProgID == NULL)

goto Cont1;

lpszBuf = OleStdMalloc(

(ULONG)lstrlen(lpszUserName)+lstrlen(lpszProgID)+3);

if (lpszBuf == NULL) {

if (lpszProgID)

OleStdFree(lpszProgID);

goto Cont1;

}

wsprintf(lpszBuf, "@%s!%s", lpszProgID, lpszUserName);

OLEDBG_BEGIN2("MkParseDisplayName called\r\n")

hrErr = MkParseDisplayName(lpbc, lpszBuf, lpchEaten, lplpmk);

OLEDBG_END2

if (lpszProgID)

OleStdFree(lpszProgID);

if (lpszBuf)

OleStdFree(lpszBuf);

if (hrErr == NOERROR)

return NOERROR;

}

Cont1:

OLEDBG_BEGIN2("MkParseDisplayName called\r\n")

hrErr = MkParseDisplayName(lpbc, lpszUserName, lpchEaten, lplpmk);

OLEDBG_END2

return hrErr;

}

/*

 * OleStdMarkPasteEntryList

 *

 * Purpose:

 *  Mark each entry in the PasteEntryList if its format is available from

 *  the source IDataObject*. the dwScratchSpace field of each PasteEntry

 *  is set to TRUE if available, else FALSE.

 *

 * Parameters:

 *  LPOLEUIPASTEENTRY   array of PasteEntry structures

 *  int                 count of elements in PasteEntry array

 *  LPDATAOBJECT        source IDataObject* pointer

 *

 * Return Value:

 *   none

 */

STDAPI_(void) OleStdMarkPasteEntryList(

LPDATAOBJECT        lpSrcDataObj,

LPOLEUIPASTEENTRY   lpPriorityList,

int                 cEntries

)

{

LPENUMFORMATETC     lpEnumFmtEtc = NULL;

#define FORMATETC_MAX 20

FORMATETC           rgfmtetc[FORMATETC_MAX];

int                 i;

HRESULT             hrErr;

long                j, cFetched;

// Clear all marks

for (i = 0; i < cEntries; i++) {

lpPriorityList[i].dwScratchSpace = FALSE;

if (! lpPriorityList[i].fmtetc.cfFormat) {

// caller wants this item always considered available

// (by specifying a NULL format)

lpPriorityList[i].dwScratchSpace = TRUE;

} else if (lpPriorityList[i].fmtetc.cfFormat == cfEmbeddedObject

|| lpPriorityList[i].fmtetc.cfFormat == cfEmbedSource

|| lpPriorityList[i].fmtetc.cfFormat == cfFileName) {

// if there is an OLE object format, then handle it

// specially by calling OleQueryCreateFromData. the caller

// need only specify one object type format.

OLEDBG_BEGIN2("OleQueryCreateFromData called\r\n")

hrErr = OleQueryCreateFromData(lpSrcDataObj);

OLEDBG_END2

if(NOERROR == hrErr) {

lpPriorityList[i].dwScratchSpace = TRUE;

}

} else if (lpPriorityList[i].fmtetc.cfFormat == cfLinkSource) {

// if there is OLE 2.0 LinkSource format, then handle it

// specially by calling OleQueryLinkFromData.

OLEDBG_BEGIN2("OleQueryLinkFromData called\r\n")

hrErr = OleQueryLinkFromData(lpSrcDataObj);

OLEDBG_END2

if(NOERROR == hrErr) {

lpPriorityList[i].dwScratchSpace = TRUE;

}

}

}

OLEDBG_BEGIN2("IDataObject::EnumFormatEtc called\r\n")

hrErr = lpSrcDataObj->lpVtbl->EnumFormatEtc(

lpSrcDataObj,

DATADIR_GET,

(LPENUMFORMATETC FAR*)&lpEnumFmtEtc

);

OLEDBG_END2

if (hrErr != NOERROR)

return;    // unable to get format enumerator

// Enumerate the formats offered by the source

// Loop over all formats offered by the source

cFetched = 0;

_fmemset(rgfmtetc,0,sizeof(rgfmtetc[FORMATETC_MAX]) );

if (lpEnumFmtEtc->lpVtbl->Next(

lpEnumFmtEtc, FORMATETC_MAX, rgfmtetc, &cFetched) == NOERROR

|| (cFetched > 0 && cFetched <= FORMATETC_MAX) )

{

for (j = 0; j < cFetched; j++)

{

for (i = 0; i < cEntries; i++)

{

if (! lpPriorityList[i].dwScratchSpace &&

IsEqualFORMATETC(rgfmtetc[j], lpPriorityList[i].fmtetc))

{

lpPriorityList[i].dwScratchSpace = TRUE;

}

}

}

} // endif

// Clean up

if (lpEnumFmtEtc)

OleStdRelease((LPUNKNOWN)lpEnumFmtEtc);

}

/* OleStdGetPriorityClipboardFormat

** --------------------------------

**

**    Retrieve the first clipboard format in a list for which data

**    exists in the source IDataObject*.

**

**    Returns -1 if no acceptable match is found.

**            index of first acceptable match in the priority list.

**

*/

STDAPI_(int) OleStdGetPriorityClipboardFormat(

LPDATAOBJECT        lpSrcDataObj,

LPOLEUIPASTEENTRY   lpPriorityList,

int                 cEntries

)

{

int i;

int nFmtEtc = -1;

// Mark all entries that the Source provides

OleStdMarkPasteEntryList(lpSrcDataObj, lpPriorityList, cEntries);

// Loop over the target's priority list of formats

for (i = 0; i < cEntries; i++)

{

if (lpPriorityList[i].dwFlags != OLEUIPASTE_PASTEONLY &&

!(lpPriorityList[i].dwFlags & OLEUIPASTE_PASTE))

continue;

// get first marked entry

if (lpPriorityList[i].dwScratchSpace) {

nFmtEtc = i;

break;          // Found priority format; DONE

}

}

return nFmtEtc;

}

/* OleStdIsDuplicateFormat

** -----------------------

**    Returns TRUE if the lpFmtEtc->cfFormat is found in the array of

**    FormatEtc structures.

*/

STDAPI_(BOOL) OleStdIsDuplicateFormat(

LPFORMATETC         lpFmtEtc,

LPFORMATETC         arrFmtEtc,

int                 nFmtEtc

)

{

int i;

for (i = 0; i < nFmtEtc; i++) {

if (IsEqualFORMATETC((*lpFmtEtc), arrFmtEtc[i]))

return TRUE;

}

return FALSE;

}

/* OleStdGetItemToken

 * ------------------

 *

 * LPSTR lpszSrc - Pointer to a source string

 * LPSTR lpszDst - Pointer to destination buffer

 *

 * Will copy one token from the lpszSrc buffer to the lpszItem buffer.

 * It considers all alpha-numeric and white space characters as valid

 * characters for a token. the first non-valid character delimates the

 * token.

 *

 * returns the number of charaters eaten.

 */

STDAPI_(ULONG) OleStdGetItemToken(LPSTR lpszSrc, LPSTR lpszDst, int nMaxChars)

{

ULONG chEaten = 0L;

// skip leading delimeter characters

while (*lpszSrc && --nMaxChars > 0

   && ((*lpszSrc=='/') || (*lpszSrc=='\\') ||

   (*lpszSrc=='!') || (*lpszSrc==':'))) {

*lpszSrc++;

chEaten++;

}

// Extract token string (up to first delimeter char or EOS)

while (*lpszSrc && --nMaxChars > 0

   && !((*lpszSrc=='/') || (*lpszSrc=='\\') ||

   (*lpszSrc=='!') || (*lpszSrc==':'))) {

*lpszDst++ = *lpszSrc++;

chEaten++;

}

*lpszDst = '\0';

return chEaten;

}

/*************************************************************************

** OleStdCreateRootStorage

**    create a root level Storage given a filename that is compatible

**    to be used by a top-level OLE container. if the filename

**    specifies an existing file, then an error is returned.

**    the root storage (Docfile) that is created by this function

**    is suitable to be used to create child storages for embedings.

**    (CreateChildStorage can be used to create child storages.)

**    NOTE: the root-level storage is opened in transacted mode.

*************************************************************************/

STDAPI_(LPSTORAGE) OleStdCreateRootStorage(LPSTR lpszStgName, DWORD grfMode)

{

HRESULT hr;

DWORD grfCreateMode = STGM_READWRITE | STGM_TRANSACTED;

DWORD reserved = 0;

LPSTORAGE lpRootStg;

char szMsg[64];

// if temp file is being created, enable delete-on-release

if (! lpszStgName)

grfCreateMode |= STGM_DELETEONRELEASE;

hr = StgCreateDocfile(

lpszStgName,

grfMode | grfCreateMode,

reserved,

(LPSTORAGE FAR*)&lpRootStg

);

if (hr == NOERROR)

return lpRootStg;               // existing file successfully opened

OleDbgOutHResult("StgCreateDocfile returned", hr);

if (0 == LoadString(ghInst, (UINT)IDS_OLESTDNOCREATEFILE, (LPSTR)szMsg, 64))

  return NULL;

MessageBox(NULL, (LPSTR)szMsg, NULL,MB_ICONEXCLAMATION | MB_OK);

return NULL;

}

/*************************************************************************

** OleStdOpenRootStorage

**    open a root level Storage given a filename that is compatible

**    to be used by a top-level OLE container. if the file does not

**    exist then an error is returned.

**    the root storage (Docfile) that is opened by this function

**    is suitable to be used to create child storages for embedings.

**    (CreateChildStorage can be used to create child storages.)

**    NOTE: the root-level storage is opened in transacted mode.

*************************************************************************/

STDAPI_(LPSTORAGE) OleStdOpenRootStorage(LPSTR lpszStgName, DWORD grfMode)

{

HRESULT hr;

DWORD reserved = 0;

LPSTORAGE lpRootStg;

char  szMsg[64];

if (lpszStgName) {

hr = StgOpenStorage(

lpszStgName,

NULL,

grfMode | STGM_TRANSACTED,

NULL,

reserved,

(LPSTORAGE FAR*)&lpRootStg

);

if (hr == NOERROR)

return lpRootStg;     // existing file successfully opened

OleDbgOutHResult("StgOpenStorage returned", hr);

}

if (0 == LoadString(ghInst, (UINT)IDS_OLESTDNOOPENFILE, szMsg, 64))

  return NULL;

MessageBox(NULL, (LPSTR)szMsg, NULL,MB_ICONEXCLAMATION | MB_OK);

return NULL;

}

/*************************************************************************

** OpenOrCreateRootStorage

**    open a root level Storage given a filename that is compatible

**    to be used by a top-level OLE container. if the filename

**    specifies an existing file, then it is open, otherwise a new file

**    with the given name is created.

**    the root storage (Docfile) that is created by this function

**    is suitable to be used to create child storages for embedings.

**    (CreateChildStorage can be used to create child storages.)

**    NOTE: the root-level storage is opened in transacted mode.

*************************************************************************/

STDAPI_(LPSTORAGE) OleStdOpenOrCreateRootStorage(LPSTR lpszStgName, DWORD grfMode)

{

HRESULT hrErr;

SCODE sc;

DWORD reserved = 0;

LPSTORAGE lpRootStg;

char      szMsg[64];

if (lpszStgName) {

hrErr = StgOpenStorage(

lpszStgName,

NULL,

grfMode | STGM_READWRITE | STGM_TRANSACTED,

NULL,

reserved,

(LPSTORAGE FAR*)&lpRootStg

);

if (hrErr == NOERROR)

return lpRootStg;      // existing file successfully opened

OleDbgOutHResult("StgOpenStorage returned", hrErr);

sc = GetScode(hrErr);

if (sc!=STG_E_FILENOTFOUND && sc!=STG_E_FILEALREADYEXISTS) {

return NULL;

}

}

/* if file did not already exist, try to create a new one */

hrErr = StgCreateDocfile(

lpszStgName,

grfMode | STGM_READWRITE | STGM_TRANSACTED,

reserved,

(LPSTORAGE FAR*)&lpRootStg

);

if (hrErr == NOERROR)

return lpRootStg;               // existing file successfully opened

OleDbgOutHResult("StgCreateDocfile returned", hrErr);

if (0 == LoadString(ghInst, (UINT)IDS_OLESTDNOCREATEFILE, (LPSTR)szMsg, 64))

  return NULL;

MessageBox(NULL, (LPSTR)szMsg, NULL, MB_ICONEXCLAMATION | MB_OK);

return NULL;

}

/*

** OleStdCreateChildStorage

**    create a child Storage inside the given lpStg that is compatible

**    to be used by an embedded OLE object. the return value from this

**    function can be passed to OleCreateXXX functions.

**    NOTE: the child storage is opened in transacted mode.

*/

STDAPI_(LPSTORAGE) OleStdCreateChildStorage(LPSTORAGE lpStg, LPSTR lpszStgName)

{

if (lpStg != NULL) {

LPSTORAGE lpChildStg;

DWORD grfMode = (STGM_READWRITE | STGM_TRANSACTED |

STGM_SHARE_EXCLUSIVE);

DWORD reserved = 0;

HRESULT hrErr = lpStg->lpVtbl->CreateStorage(

lpStg,

lpszStgName,

grfMode,

reserved,

reserved,

(LPSTORAGE FAR*)&lpChildStg

);

if (hrErr == NOERROR)

return lpChildStg;

OleDbgOutHResult("lpStg->lpVtbl->CreateStorage returned", hrErr);

}

return NULL;

}

/*

** OleStdOpenChildStorage

**    open a child Storage inside the given lpStg that is compatible

**    to be used by an embedded OLE object. the return value from this

**    function can be passed to OleLoad function.

**    NOTE: the child storage is opened in transacted mode.

*/

STDAPI_(LPSTORAGE) OleStdOpenChildStorage(LPSTORAGE lpStg, LPSTR lpszStgName, DWORD grfMode)

{

LPSTORAGE lpChildStg;

LPSTORAGE lpstgPriority = NULL;

DWORD reserved = 0;

HRESULT hrErr;

if (lpStg  != NULL) {

hrErr = lpStg->lpVtbl->OpenStorage(

lpStg,

lpszStgName,

lpstgPriority,

grfMode | STGM_TRANSACTED | STGM_SHARE_EXCLUSIVE,

NULL,

reserved,

(LPSTORAGE FAR*)&lpChildStg

);

if (hrErr == NOERROR)

return lpChildStg;

OleDbgOutHResult("lpStg->lpVtbl->OpenStorage returned", hrErr);

}

return NULL;

}

/* OleStdCommitStorage

** -------------------

**    Commit the changes to the given IStorage*. This routine can be

**    called on either a root-level storage as used by an OLE-Container

**    or by a child storage as used by an embedded object.

**

**    This routine first attempts to perform this commit in a safe

**    manner. if this fails it then attempts to do the commit in a less

**    robust manner (STGC_OVERWRITE).

*/

STDAPI_(BOOL) OleStdCommitStorage(LPSTORAGE lpStg)

{

HRESULT hrErr;

// make the changes permanent

hrErr = lpStg->lpVtbl->Commit(lpStg, 0);

if (GetScode(hrErr) == STG_E_MEDIUMFULL) {

// try to commit changes in less robust manner.

OleDbgOut("Warning: commiting with STGC_OVERWRITE specified\n");

hrErr = lpStg->lpVtbl->Commit(lpStg, STGC_OVERWRITE);

}

if (hrErr != NOERROR)

{

char szMsg[64];

if (0 == LoadString(ghInst, (UINT)IDS_OLESTDDISKFULL, (LPSTR)szMsg, 64))

   return FALSE;

MessageBox(NULL, (LPSTR)szMsg, NULL, MB_ICONEXCLAMATION | MB_OK);

return FALSE;

}

else {

return TRUE;

}

}

/* OleStdDestroyAllElements

** ------------------------

**    Destroy all elements within an open storage. this is subject

**    to the current transaction.

*/

STDAPI OleStdDestroyAllElements(LPSTORAGE lpStg)

{

IEnumSTATSTG FAR* lpEnum;

STATSTG sstg;

HRESULT hrErr;

hrErr = lpStg->lpVtbl->EnumElements(

lpStg, 0, NULL, 0, (IEnumSTATSTG FAR* FAR*)&lpEnum);

if (hrErr != NOERROR)

return hrErr;

while (1) {

if (lpEnum->lpVtbl->Next(lpEnum, 1, &sstg, NULL) != NOERROR)

break;

lpStg->lpVtbl->DestroyElement(lpStg, sstg.pwcsName);

OleStdFree(sstg.pwcsName);

}

lpEnum->lpVtbl->Release(lpEnum);

return NOERROR;

}


 OLEUTL.C  (WRAPUI Sample)

/*

 * OLEUTL.C

 *

 * Miscellaneous utility functions for OLE 2.0 Applications:

 *

 *  Function                      Purpose

 *  -------------------------------------------------------------------

 *  SetDCToDrawInHimetricRect     Sets up an HIMETRIC mapping mode in a DC.

 *  ResetOrigDC                   Performs the opposite of

 *                                SetDCToDrawInHimetricRect

 *  XformWidthInPixelsToHimetric  Converts an int width into HiMetric units

 *  XformWidthInHimetricToPixels  Converts an int width from HiMetric units

 *  XformHeightInPixelsToHimetric Converts an int height into HiMetric units

 *  XformHeightInHimetricToPixels Converts an int height from HiMetric units

 *  XformRectInPixelsToHimetric   Converts a rect into HiMetric units

 *  XformRectInHimetricToPixels   Converts a rect from HiMetric units

 *  XformSizeInPixelsToHimetric   Converts a SIZEL into HiMetric units

 *  XformSizeInHimetricToPixels   Converts a SIZEL from HiMetric units

 *  AreRectsEqual                 Compares to Rect's

 *

 *  ParseCmdLine                  Determines if -Embedding exists

 *  OpenOrCreateRootStorage       Creates a root docfile for OLE storage

 *  CommitStorage                 Commits all changes in a docfile

 *  CreateChildStorage            Creates child storage in another storage

 *  OpenChildStorage              Opens child storage in another storage

 *

 *

 * Copyright (c)1992 Microsoft Corporation, All Right Reserved

 */

#define STRICT  1

#include "ole2ui.h"

#include <stdlib.h>

#include <ctype.h>

//Internal function to this module

static LPSTR GetWord(LPSTR lpszSrc, LPSTR lpszDst);

/*

 * SetDCToAnisotropic

 *

 * Purpose:

 *  Setup the correspondence between the rect in device unit (Viewport) and

 *  the rect in logical unit (Window) so that the proper scaling of

 *  coordinate systems will be calculated. set up both the Viewport and

 *  the window as follows:

 *

 *      1) ------------------ ( 2

 *      |                     |

 *      |                     |

 *      |                     |

 *      |                     |

 *      |                     |

 *      3) ------------------ ( 4

 *

 *      Origin   = P3

 *      X extent = P2x - P3x

 *      Y extent = P2y - P3y

 *

 * Parameters:

 *  hDC             HDC to affect

 *  lprcPhysical    LPRECT containing the physical (device) extents of DC

 *  lprcLogical     LPRECT containing the logical extents

 *  lprcWindowOld   LPRECT in which to preserve the window for ResetOrigDC

 *  lprcViewportOld LPRECT in which to preserver the viewport for ResetOrigDC

 *

 * Return Value:

 *  int             The original mapping mode of the DC.

 */

STDAPI_(int) SetDCToAnisotropic(

HDC hDC,

LPRECT lprcPhysical, LPRECT lprcLogical,

LPRECT lprcWindowOld, LPRECT lprcViewportOld)

{

int     nMapModeOld=SetMapMode(hDC, MM_ANISOTROPIC);

SetWindowOrgEx(hDC, lprcLogical->left, lprcLogical->bottom, (LPPOINT)&lprcWindowOld->left);

SetWindowExtEx(hDC, (lprcLogical->right-lprcLogical->left), (lprcLogical->top-lprcLogical->bottom), (LPSIZE)&lprcWindowOld->right);

SetViewportOrgEx(hDC, lprcPhysical->left, lprcPhysical->bottom, (LPPOINT)&lprcViewportOld->left);

SetViewportExtEx(hDC, (lprcPhysical->right-lprcPhysical->left), (lprcPhysical->top-lprcPhysical->bottom), (LPSIZE)&lprcViewportOld->right);

return nMapModeOld;

}

/*

 * SetDCToDrawInHimetricRect

 *

 * Purpose:

 *  Setup the correspondence between the rect in pixels (Viewport) and

 *  the rect in HIMETRIC (Window) so that the proper scaling of

 *  coordinate systems will be calculated. set up both the Viewport and

 *  the window as follows:

 *

 *      1) ------------------ ( 2

 *      |                     |

 *      |                     |

 *      |                     |

 *      |                     |

 *      |                     |

 *      3) ------------------ ( 4

 *

 *      Origin   = P3

 *      X extent = P2x - P3x

 *      Y extent = P2y - P3y

 *

 * Parameters:

 *  hDC             HDC to affect

 *  lprcPix         LPRECT containing the pixel extents of DC

 *  lprcHiMetric    LPRECT to receive the himetric extents

 *  lprcWindowOld   LPRECT in which to preserve the window for ResetOrigDC

 *  lprcViewportOld LPRECT in which to preserver the viewport for ResetOrigDC

 *

 * Return Value:

 *  int             The original mapping mode of the DC.

 */

STDAPI_(int) SetDCToDrawInHimetricRect(

HDC hDC,

LPRECT lprcPix, LPRECT lprcHiMetric,

LPRECT lprcWindowOld, LPRECT lprcViewportOld)

{

int     nMapModeOld=SetMapMode(hDC, MM_ANISOTROPIC);

BOOL    fSystemDC  =FALSE;

if (NULL==hDC)

{

hDC=GetDC(NULL);

fSystemDC=TRUE;

}

XformRectInPixelsToHimetric(hDC, lprcPix, lprcHiMetric);

SetWindowOrgEx(hDC, lprcHiMetric->left, lprcHiMetric->bottom, (LPPOINT)&lprcWindowOld->left);

SetWindowExtEx(hDC, (lprcHiMetric->right-lprcHiMetric->left), (lprcHiMetric->top-lprcHiMetric->bottom), (LPSIZE)&lprcWindowOld->right);

SetViewportOrgEx(hDC, lprcPix->left, lprcPix->bottom, (LPPOINT)&lprcViewportOld->left);

SetViewportExtEx(hDC, (lprcPix->right-lprcPix->left), (lprcPix->top-lprcPix->bottom), (LPSIZE)&lprcViewportOld->right);

if (fSystemDC)

ReleaseDC(NULL, hDC);

return nMapModeOld;

}

/*

 * ResetOrigDC

 *

 * Purpose:

 *  Restores a DC set to draw in himetric from SetDCToDrawInHimetricRect.

 *

 * Parameters:

 *  hDC             HDC to restore

 *  nMapModeOld     int original mapping mode of hDC

 *  lprcWindowOld   LPRECT filled in SetDCToDrawInHimetricRect

 *  lprcViewportOld LPRECT filled in SetDCToDrawInHimetricRect

 *

 * Return Value:

 *  int             Same as nMapModeOld.

 */

STDAPI_(int) ResetOrigDC(

HDC hDC, int nMapModeOld,

LPRECT lprcWindowOld, LPRECT lprcViewportOld)

{

POINT     pOld;

SetMapMode(hDC, nMapModeOld);

SetWindowOrgEx(hDC,   lprcWindowOld->left,    lprcWindowOld->top,      (LPPOINT)&pOld);

SetWindowExtEx(hDC,   lprcWindowOld->right,   lprcWindowOld->bottom,   (LPSIZE)&pOld);

SetViewportOrgEx(hDC, lprcViewportOld->left,  lprcViewportOld->top,    (LPPOINT)&pOld);

SetViewportExtEx(hDC, lprcViewportOld->right, lprcViewportOld->bottom, (LPSIZE)&pOld);

return nMapModeOld;

}

/*

 * XformWidthInPixelsToHimetric

 * XformWidthInHimetricToPixels

 * XformHeightInPixelsToHimetric

 * XformHeightInHimetricToPixels

 *

 * Functions to convert an int between a device coordinate system and

 * logical HiMetric units.

 *

 * Parameters:

 *  hDC             HDC providing reference to the pixel mapping.  If

 *                  NULL, a screen DC is used.

 *

 *  Size Functions:

 *  lpSizeSrc       LPSIZEL providing the structure to convert.  This

 *                  contains pixels in XformSizeInPixelsToHimetric and

 *                  logical HiMetric units in the complement function.

 *  lpSizeDst       LPSIZEL providing the structure to receive converted

 *                  units.  This contains pixels in

 *                  XformSizeInPixelsToHimetric and logical HiMetric

 *                  units in the complement function.

 *

 *  Width Functions:

 *  iWidth          int containing the value to convert.

 *

 * Return Value:

 *  Size Functions:     None

 *  Width Functions:    Converted value of the input parameters.

 *

 * NOTE:

 *  When displaying on the screen, Window apps display everything enlarged

 *  from its actual size so that it is easier to read. For example, if an

 *  app wants to display a 1in. horizontal line, that when printed is

 *  actually a 1in. line on the printed page, then it will display the line

 *  on the screen physically larger than 1in. This is described as a line

 *  that is "logically" 1in. along the display width. Windows maintains as

 *  part of the device-specific information about a given display device:

 *      LOGPIXELSX -- no. of pixels per logical in along the display width

 *      LOGPIXELSY -- no. of pixels per logical in along the display height

 *

 *  The following formula converts a distance in pixels into its equivalent

 *  logical HIMETRIC units:

 *

 *      DistInHiMetric = (HIMETRIC_PER_INCH * DistInPix)

 *                       -------------------------------

 *                           PIXELS_PER_LOGICAL_IN

 *

 */

STDAPI_(int) XformWidthInPixelsToHimetric(HDC hDC, int iWidthInPix)

{

int     iXppli;     //Pixels per logical inch along width

int     iWidthInHiMetric;

BOOL    fSystemDC=FALSE;

if (NULL==hDC || GetDeviceCaps(hDC, TECHNOLOGY) == DT_METAFILE

|| GetDeviceCaps(hDC, LOGPIXELSX) == 0)

{

hDC=GetDC(NULL);

fSystemDC=TRUE;

}

iXppli = GetDeviceCaps (hDC, LOGPIXELSX);

//We got pixel units, convert them to logical HIMETRIC along the display

iWidthInHiMetric = (int)MAP_PIX_TO_LOGHIM(iWidthInPix, iXppli);

if (fSystemDC)

ReleaseDC(NULL, hDC);

return iWidthInHiMetric;

}

STDAPI_(int) XformWidthInHimetricToPixels(HDC hDC, int iWidthInHiMetric)

{

int     iXppli;     //Pixels per logical inch along width

int     iWidthInPix;

BOOL    fSystemDC=FALSE;

if (NULL==hDC || GetDeviceCaps(hDC, TECHNOLOGY) == DT_METAFILE

|| GetDeviceCaps(hDC, LOGPIXELSX) == 0)

{

hDC=GetDC(NULL);

fSystemDC=TRUE;

}

iXppli = GetDeviceCaps (hDC, LOGPIXELSX);

//We got logical HIMETRIC along the display, convert them to pixel units

iWidthInPix = (int)MAP_LOGHIM_TO_PIX(iWidthInHiMetric, iXppli);

if (fSystemDC)

ReleaseDC(NULL, hDC);

return iWidthInPix;

}

STDAPI_(int) XformHeightInPixelsToHimetric(HDC hDC, int iHeightInPix)

{

int     iYppli;     //Pixels per logical inch along height

int     iHeightInHiMetric;

BOOL    fSystemDC=FALSE;

if (NULL==hDC || GetDeviceCaps(hDC, TECHNOLOGY) == DT_METAFILE

|| GetDeviceCaps(hDC, LOGPIXELSY) == 0)

{

hDC=GetDC(NULL);

fSystemDC=TRUE;

}

iYppli = GetDeviceCaps (hDC, LOGPIXELSY);

//* We got pixel units, convert them to logical HIMETRIC along the display

iHeightInHiMetric = (int)MAP_PIX_TO_LOGHIM(iHeightInPix, iYppli);

if (fSystemDC)

ReleaseDC(NULL, hDC);

return iHeightInHiMetric;

}

STDAPI_(int) XformHeightInHimetricToPixels(HDC hDC, int iHeightInHiMetric)

{

int     iYppli;     //Pixels per logical inch along height

int     iHeightInPix;

BOOL    fSystemDC=FALSE;

if (NULL==hDC || GetDeviceCaps(hDC, TECHNOLOGY) == DT_METAFILE

|| GetDeviceCaps(hDC, LOGPIXELSY) == 0)

{

hDC=GetDC(NULL);

fSystemDC=TRUE;

}

iYppli = GetDeviceCaps (hDC, LOGPIXELSY);

//* We got logical HIMETRIC along the display, convert them to pixel units

iHeightInPix = (int)MAP_LOGHIM_TO_PIX(iHeightInHiMetric, iYppli);

if (fSystemDC)

ReleaseDC(NULL, hDC);

return iHeightInPix;

}

/*

 * XformRectInPixelsToHimetric

 * XformRectInHimetricToPixels

 *

 * Purpose:

 *  Convert a rectangle between pixels of a given hDC and HIMETRIC units

 *  as manipulated in OLE.  If the hDC is NULL, then a screen DC is used

 *  and assumes the MM_TEXT mapping mode.

 *

 * Parameters:

 *  hDC             HDC providing reference to the pixel mapping.  If

 *                  NULL, a screen DC is used.

 *  lprcSrc         LPRECT providing the rectangle to convert.  This

 *                  contains pixels in XformRectInPixelsToHimetric and

 *                  logical HiMetric units in the complement function.

 *  lprcDst         LPRECT providing the rectangle to receive converted units.

 *                  This contains pixels in XformRectInPixelsToHimetric and

 *                  logical HiMetric units in the complement function.

 *

 * Return Value:

 *  None

 *

 * NOTE:

 *  When displaying on the screen, Window apps display everything enlarged

 *  from its actual size so that it is easier to read. For example, if an

 *  app wants to display a 1in. horizontal line, that when printed is

 *  actually a 1in. line on the printed page, then it will display the line

 *  on the screen physically larger than 1in. This is described as a line

 *  that is "logically" 1in. along the display width. Windows maintains as

 *  part of the device-specific information about a given display device:

 *      LOGPIXELSX -- no. of pixels per logical in along the display width

 *      LOGPIXELSY -- no. of pixels per logical in along the display height

 *

 *  The following formula converts a distance in pixels into its equivalent

 *  logical HIMETRIC units:

 *

 *      DistInHiMetric = (HIMETRIC_PER_INCH * DistInPix)

 *                      -------------------------------

 *                            PIXELS_PER_LOGICAL_IN

 *

 * Rect in Pixels (MM_TEXT):

 *

 *              0---------- X

 *              |

 *              |       1) ------------------ ( 2   P1 = (rc.left, rc.top)

 *              |       |                     |     P2 = (rc.right, rc.top)

 *              |       |                     |     P3 = (rc.left, rc.bottom)

 *              |       |                     |     P4 = (rc.right, rc.bottom)

 *                      |                     |

 *              Y       |                     |

 *                      3) ------------------ ( 4

 *

 *              NOTE:   Origin   = (P1x, P1y)

 *                      X extent = P4x - P1x

 *                      Y extent = P4y - P1y

 *

 *

 * Rect in Himetric (MM_HIMETRIC):

 *

 *

 *                      1) ------------------ ( 2   P1 = (rc.left, rc.top)

 *              Y       |                     |     P2 = (rc.right, rc.top)

 *                      |                     |     P3 = (rc.left, rc.bottom)

 *              |       |                     |     P4 = (rc.right, rc.bottom)

 *              |       |                     |

 *              |       |                     |

 *              |       3) ------------------ ( 4

 *              |

 *              0---------- X

 *

 *              NOTE:   Origin   = (P3x, P3y)

 *                      X extent = P2x - P3x

 *                      Y extent = P2y - P3y

 *

 *

 */

STDAPI_(void) XformRectInPixelsToHimetric(

HDC hDC, LPRECT lprcPix, LPRECT lprcHiMetric)

{

int     iXppli;     //Pixels per logical inch along width

int     iYppli;     //Pixels per logical inch along height

int     iXextInPix=(lprcPix->right-lprcPix->left);

int     iYextInPix=(lprcPix->bottom-lprcPix->top);

BOOL    fSystemDC=FALSE;

if (NULL==hDC || GetDeviceCaps(hDC, TECHNOLOGY) == DT_METAFILE

|| GetDeviceCaps(hDC, LOGPIXELSX) == 0)

{

hDC=GetDC(NULL);

fSystemDC=TRUE;

}

iXppli = GetDeviceCaps (hDC, LOGPIXELSX);

iYppli = GetDeviceCaps (hDC, LOGPIXELSY);

//We got pixel units, convert them to logical HIMETRIC along the display

lprcHiMetric->right = (int)MAP_PIX_TO_LOGHIM(iXextInPix, iXppli);

lprcHiMetric->top   = (int)MAP_PIX_TO_LOGHIM(iYextInPix, iYppli);

lprcHiMetric->left    = 0;

lprcHiMetric->bottom  = 0;

if (fSystemDC)

ReleaseDC(NULL, hDC);

return;

}

STDAPI_(void) XformRectInHimetricToPixels(

HDC hDC, LPRECT lprcHiMetric, LPRECT lprcPix)

{

int     iXppli;     //Pixels per logical inch along width

int     iYppli;     //Pixels per logical inch along height

int     iXextInHiMetric=(lprcHiMetric->right-lprcHiMetric->left);

int     iYextInHiMetric=(lprcHiMetric->bottom-lprcHiMetric->top);

BOOL    fSystemDC=FALSE;

if (NULL==hDC || GetDeviceCaps(hDC, TECHNOLOGY) == DT_METAFILE

|| GetDeviceCaps(hDC, LOGPIXELSX) == 0)

{

hDC=GetDC(NULL);

fSystemDC=TRUE;

}

iXppli = GetDeviceCaps (hDC, LOGPIXELSX);

iYppli = GetDeviceCaps (hDC, LOGPIXELSY);

//We got pixel units, convert them to logical HIMETRIC along the display

lprcPix->right = (int)MAP_LOGHIM_TO_PIX(iXextInHiMetric, iXppli);

lprcPix->top   = (int)MAP_LOGHIM_TO_PIX(iYextInHiMetric, iYppli);

lprcPix->left  = 0;

lprcPix->bottom= 0;

if (fSystemDC)

ReleaseDC(NULL, hDC);

return;

}

/*

 * XformSizeInPixelsToHimetric

 * XformSizeInHimetricToPixels

 *

 * Functions to convert a SIZEL structure (Size functions) or

 * an int (Width functions) between a device coordinate system and

 * logical HiMetric units.

 *

 * Parameters:

 *  hDC             HDC providing reference to the pixel mapping.  If

 *                  NULL, a screen DC is used.

 *

 *  Size Functions:

 *  lpSizeSrc       LPSIZEL providing the structure to convert.  This

 *                  contains pixels in XformSizeInPixelsToHimetric and

 *                  logical HiMetric units in the complement function.

 *  lpSizeDst       LPSIZEL providing the structure to receive converted

 *                  units.  This contains pixels in

 *                  XformSizeInPixelsToHimetric and logical HiMetric

 *                  units in the complement function.

 *

 *  Width Functions:

 *  iWidth          int containing the value to convert.

 *

 * Return Value:

 *  Size Functions:     None

 *  Width Functions:    Converted value of the input parameters.

 *

 * NOTE:

 *  When displaying on the screen, Window apps display everything enlarged

 *  from its actual size so that it is easier to read. For example, if an

 *  app wants to display a 1in. horizontal line, that when printed is

 *  actually a 1in. line on the printed page, then it will display the line

 *  on the screen physically larger than 1in. This is described as a line

 *  that is "logically" 1in. along the display width. Windows maintains as

 *  part of the device-specific information about a given display device:

 *      LOGPIXELSX -- no. of pixels per logical in along the display width

 *      LOGPIXELSY -- no. of pixels per logical in along the display height

 *

 *  The following formula converts a distance in pixels into its equivalent

 *  logical HIMETRIC units:

 *

 *      DistInHiMetric = (HIMETRIC_PER_INCH * DistInPix)

 *                       -------------------------------

 *                           PIXELS_PER_LOGICAL_IN

 *

 */

STDAPI_(void) XformSizeInPixelsToHimetric(

HDC hDC, LPSIZEL lpSizeInPix, LPSIZEL lpSizeInHiMetric)

{

int     iXppli;     //Pixels per logical inch along width

int     iYppli;     //Pixels per logical inch along height

BOOL    fSystemDC=FALSE;

if (NULL==hDC || GetDeviceCaps(hDC, TECHNOLOGY) == DT_METAFILE

|| GetDeviceCaps(hDC, LOGPIXELSX) == 0)

{

hDC=GetDC(NULL);

fSystemDC=TRUE;

}

iXppli = GetDeviceCaps (hDC, LOGPIXELSX);

iYppli = GetDeviceCaps (hDC, LOGPIXELSY);

//We got pixel units, convert them to logical HIMETRIC along the display

lpSizeInHiMetric->cx = (LONG)MAP_PIX_TO_LOGHIM(lpSizeInPix->cx, iXppli);

lpSizeInHiMetric->cy = (LONG)MAP_PIX_TO_LOGHIM(lpSizeInPix->cy, iYppli);

if (fSystemDC)

ReleaseDC(NULL, hDC);

return;

}

STDAPI_(void) XformSizeInHimetricToPixels(

HDC hDC, LPSIZEL lpSizeInHiMetric, LPSIZEL lpSizeInPix)

{

int     iXppli;     //Pixels per logical inch along width

int     iYppli;     //Pixels per logical inch along height

BOOL    fSystemDC=FALSE;

if (NULL==hDC || GetDeviceCaps(hDC, TECHNOLOGY) == DT_METAFILE

|| GetDeviceCaps(hDC, LOGPIXELSX) == 0)

{

hDC=GetDC(NULL);

fSystemDC=TRUE;

}

iXppli = GetDeviceCaps (hDC, LOGPIXELSX);

iYppli = GetDeviceCaps (hDC, LOGPIXELSY);

//We got logical HIMETRIC along the display, convert them to pixel units

lpSizeInPix->cx = (LONG)MAP_LOGHIM_TO_PIX(lpSizeInHiMetric->cx, iXppli);

lpSizeInPix->cy = (LONG)MAP_LOGHIM_TO_PIX(lpSizeInHiMetric->cy, iYppli);

if (fSystemDC)

ReleaseDC(NULL, hDC);

return;

}

#if defined( OBSOLETE )

// This function has been converted to a macro

/* AreRectsEqual

** -------------

*/

STDAPI_(BOOL) AreRectsEqual(LPRECT lprc1, LPRECT lprc2)

{

if ((lprc1->top == lprc2->top) &&

(lprc1->left == lprc2->left) &&

(lprc1->right == lprc2->right) &&

(lprc1->bottom == lprc2->bottom))

return TRUE;

return FALSE;

}

#endif  // OBSOLETE

/*

 * ParseCmdLine

 *

 * Parses the Windows command line which was passed to WinMain.

 * This function determines if the -Embedding switch has been given.

 *

 */

STDAPI_(void) ParseCmdLine(

LPSTR lpszLine,

BOOL FAR* lpfEmbedFlag,

LPSTR szFileName)

{

int i=0;

char szBuf[256];

if(lpfEmbedFlag)

*lpfEmbedFlag = FALSE;

szFileName[0]='\0';             // NULL string

// skip blanks

while(isspace(*lpszLine)) lpszLine++;

if(!*lpszLine)   // No filename or options, so start a fresh document.

return;

// Check for "-Embedding" or "/Embedding" and set fEmbedding.

if(lpfEmbedFlag && (*lpszLine == '-' || *lpszLine == '/')) {

lpszLine++;

lpszLine = GetWord(lpszLine, szBuf);

*lpfEmbedFlag = !lstrcmp(szBuf, EMBEDDINGFLAG);

}

// skip blanks

while(isspace(*lpszLine)) lpszLine++;

// set szFileName to argument

while(lpszLine[i]) {

szFileName[i]=lpszLine[i];

i++;

}

szFileName[i]='\0';

}

/* GetWord

 * -------

 *

 * LPSTR lpszSrc - Pointer to a source string

 * LPSTR lpszDst - Pointer to destination buffer

 *

 * Will copy one space-terminated or null-terminated word from the source

 * string to the destination buffer.

 * returns: pointer to next character following the word.

 */

static LPSTR GetWord(LPSTR lpszSrc, LPSTR lpszDst)

{

while (*lpszSrc && !isspace(*lpszSrc))

*lpszDst++ = *lpszSrc++;

*lpszDst = '\0';

return lpszSrc;

}


 PASTESPL.H  (WRAPUI Sample)

/*

 * PASTESPL.H

 *

 * Internal definitions, structures, and function prototypes for the

 * OLE 2.0 UI Paste Special dialog.

 *

 * Copyright (c)1992 Microsoft Corporation, All Right Reserved

 */

#ifndef _PASTESPL_H_

#define _PASTESPL_H_

#ifndef RC_INVOKED

#pragma message ("INCLUDING PASTESPL.H from " __FILE__)

#endif  /* RC_INVOKED */

// Length of buffers to hold the strings 'Unknown Type', Unknown Source'

//   and 'the application which created it'

#define PS_UNKNOWNSTRLEN               100

//Property label used to store clipboard viewer chain information

#define NEXTCBVIEWER        "NextCBViewer"

//Internally used structure

typedef struct tagPASTESPECIAL

{

//Keep this item first as the Standard* functions depend on it here.

LPOLEUIPASTESPECIAL  lpOPS;                //Original structure passed.

/*

 * What we store extra in this structure besides the original caller's

 * pointer are those fields that we need to modify during the life of

 * the dialog but that we don't want to change in the original structure

 * until the user presses OK.

 */

DWORD                dwFlags;              // Local copy of paste special flags

int                  nPasteListCurSel;     // Save the selection the user made last

int                  nPasteLinkListCurSel; //    in the paste and pastelink lists

int                  nSelectedIndex;       // Index in arrPasteEntries[] corresponding to user selection

BOOL                 fLink;                // Indicates if Paste or PasteLink was selected by user

HGLOBAL              hBuff;                // Scratch Buffer for building up strings

char                 szUnknownType[PS_UNKNOWNSTRLEN];    // Buffer for 'Unknown Type' string

char                 szUnknownSource[PS_UNKNOWNSTRLEN];  // Buffer for 'Unknown Source' string

char                 szAppName[OLEUI_CCHKEYMAX]; // Application name of Source. Used in the result text

 //   when Paste is selected. Obtained using clsidOD.

// Information obtained from OBJECTDESCRIPTOR. This information is accessed when the Paste

//    radio button is selected.

CLSID                clsidOD;              // ClassID of source

SIZEL                sizelOD;              // sizel transfered in

   //  ObjectDescriptor

LPSTR                szFullUserTypeNameOD; // Full User Type Name

LPSTR                szSourceOfDataOD;     // Source of Data

BOOL                 fSrcAspectIconOD;     // Does Source specify DVASPECT_ICON?

BOOL                 fSrcOnlyIconicOD;     // Does Source specify OLEMISC_ONLYICONIC?

HGLOBAL              hMetaPictOD;          // Metafile containing icon and icon title

HGLOBAL              hObjDesc;             // Handle to OBJECTDESCRIPTOR structure from which the

   //   above information is obtained

// Information obtained from LINKSRCDESCRIPTOR. This infomation is accessed when the PasteLink

//   radio button is selected.

CLSID                clsidLSD;             // ClassID of source

SIZEL                sizelLSD;             // sizel transfered in

   //  LinkSrcDescriptor

LPSTR                szFullUserTypeNameLSD;// Full User Type Name

LPSTR                szSourceOfDataLSD;    // Source of Data

BOOL                 fSrcAspectIconLSD;    // Does Source specify DVASPECT_ICON?

BOOL                 fSrcOnlyIconicLSD;    // Does Source specify OLEMISC_ONLYICONIC?

HGLOBAL              hMetaPictLSD;         // Metafile containing icon and icon title

HGLOBAL              hLinkSrcDesc;         // Handle to LINKSRCDESCRIPTOR structure from which the

   //   above information is obtained

BOOL                 fClipboardChanged;    // Has clipboard content changed

   //   if so bring down dlg after

   //   ChangeIcon dlg returns.

} PASTESPECIAL, *PPASTESPECIAL, FAR *LPPASTESPECIAL;

// Data corresponding to each list item. A pointer to this structure is attached to each

//   Paste\PasteLink list box item using LB_SETITEMDATA

typedef struct tagPASTELISTITEMDATA

{

   int                   nPasteEntriesIndex;   // Index of arrPasteEntries[] corresponding to list item

   BOOL                  fCntrEnableIcon;      // Does calling application (called container here)

   //    specify OLEUIPASTE_ENABLEICON for this item?

} PASTELISTITEMDATA, *PPASTELISTITEMDATA, FAR *LPPASTELISTITEMDATA;

//Internal function prototypes

//PASTESPL.C

BOOL CALLBACK EXPORT PasteSpecialDialogProc(HWND, UINT, WPARAM, LPARAM);

BOOL            FPasteSpecialInit(HWND hDlg, WPARAM, LPARAM);

BOOL            FTogglePasteType(HWND, LPPASTESPECIAL, DWORD);

void            ChangeListSelection(HWND, LPPASTESPECIAL, HWND);

void            EnableDisplayAsIcon(HWND, LPPASTESPECIAL);

void            ToggleDisplayAsIcon(HWND, LPPASTESPECIAL);

void            ChangeIcon(HWND, LPPASTESPECIAL);

void            SetPasteSpecialHelpResults(HWND, LPPASTESPECIAL);

BOOL            FAddPasteListItem(HWND, BOOL, int, LPPASTESPECIAL, LPMALLOC, LPSTR, LPSTR);

BOOL            FFillPasteList(HWND, LPPASTESPECIAL);

BOOL            FFillPasteLinkList(HWND, LPPASTESPECIAL);

BOOL            FHasPercentS(LPCSTR, LPPASTESPECIAL);

HGLOBAL         AllocateScratchMem(LPPASTESPECIAL);

void            FreeListData(HWND);

#endif  //_PASTESPL_H_


 PASTESPL.C  (WRAPUI Sample)

/*

 * PASTESPL.C

 *

 * Implements the OleUIPasteSpecial function which invokes the complete

 * Paste Special dialog.

 *

 * Copyright (c)1992 Microsoft Corporation, All Rights Reserved

 */

#define STRICT  1

#include "ole2ui.h"

#include "pastespl.h"

#include "common.h"

#include "utility.h"

#include "resimage.h"

#include "iconbox.h"

#include "geticon.h"

#include "icon.h"

#include "regdb.h"

#include <stdlib.h>

OLEDBGDATA

/*

 * OleUIPasteSpecial

 *

 * Purpose:

 *  Invokes the standard OLE Paste Special dialog box which allows the user

 *  to select the format of the clipboard object to be pasted or paste linked.

 *

 * Parameters:

 *  lpPS         LPOLEUIPasteSpecial pointing to the in-out structure

 *               for this dialog.

 *

 * Return Value:

 *  UINT        One of the following codes or one of the standard error codes (OLEUI_ERR_*)

 *              defined in OLE2UI.H, indicating success or error:

 *              OLEUI_OK                           User selected OK

 *              OLEUI_CANCEL                       User cancelled the dialog

 *              OLEUI_IOERR_SRCDATAOBJECTINVALID   lpSrcDataObject field of OLEUIPASTESPECIAL invalid

 *              OLEUI_IOERR_ARRPASTEENTRIESINVALID arrPasteEntries field of OLEUIPASTESPECIAL invalid

 *              OLEUI_IOERR_ARRLINKTYPESINVALID    arrLinkTypes field of OLEUIPASTESPECIAL invalid

 *              OLEUI_PSERR_CLIPBOARDCHANGED       Clipboard contents changed while dialog was up

 */

STDAPI_(UINT) OleUIPasteSpecial(LPOLEUIPASTESPECIAL lpPS)

{

UINT        uRet;

HGLOBAL     hMemDlg=NULL;

uRet=UStandardValidation((LPOLEUISTANDARD)lpPS, sizeof(OLEUIPASTESPECIAL)

, &hMemDlg);

if (uRet != OLEUI_SUCCESS)

return uRet;

//Validate PasteSpecial specific fields

if (NULL == lpPS->lpSrcDataObj || IsBadReadPtr(lpPS->lpSrcDataObj,  sizeof(IDataObject)))

uRet = OLEUI_IOERR_SRCDATAOBJECTINVALID;

if (NULL == lpPS->arrPasteEntries || IsBadReadPtr(lpPS->arrPasteEntries,  sizeof(OLEUIPASTEENTRY)))

uRet = OLEUI_IOERR_ARRPASTEENTRIESINVALID;

if (NULL != lpPS->arrLinkTypes && IsBadReadPtr(lpPS->arrLinkTypes,  sizeof(UINT)))

uRet = OLEUI_IOERR_ARRLINKTYPESINVALID;

if (0!=lpPS->cClsidExclude)

{

if (NULL!=lpPS->lpClsidExclude && IsBadReadPtr(lpPS->lpClsidExclude

, lpPS->cClsidExclude*sizeof(CLSID)))

uRet=OLEUI_IOERR_LPCLSIDEXCLUDEINVALID;

}

if (uRet >= OLEUI_ERR_STANDARDMIN)

{

if (NULL != hMemDlg)

FreeResource(hMemDlg);

return uRet;

}

//Now that we've validated everything, we can invoke the dialog.

uRet = UStandardInvocation(PasteSpecialDialogProc, (LPOLEUISTANDARD)lpPS

, hMemDlg, MAKEINTRESOURCE(IDD_PASTESPECIAL));

/*

* IF YOU ARE CREATING ANYTHING BASED ON THE RESULTS, DO IT HERE.

*/

return uRet;

}

/*

 * PasteSpecialDialogProc

 *

 * Purpose:

 *  Implements the OLE Paste Special dialog as invoked through the

 *  OleUIPasteSpecial function.

 *

 * Parameters:

 *  Standard

 *

 * Return Value:

 *  Standard

 */

BOOL CALLBACK EXPORT PasteSpecialDialogProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)

{

LPOLEUIPASTESPECIAL     lpOPS;

LPPASTESPECIAL          lpPS;

BOOL                    fHook=FALSE;

HCURSOR                 hCursorOld;

//Declare Win16/Win32 compatible WM_COMMAND parameters.

COMMANDPARAMS(wID, wCode, hWndMsg);

//This will fail under WM_INITDIALOG, where we allocate it.

lpPS=(LPPASTESPECIAL)LpvStandardEntry(hDlg, iMsg, wParam, lParam, &fHook);

//If the hook processed the message, we're done.

if (0!=fHook)

return fHook;

// Process help message from Change Icon

if (iMsg == uMsgHelp)

{

PostMessage(lpPS->lpOPS->hWndOwner, uMsgHelp, wParam, lParam);

return FALSE;

}

//Process the temination message

if (iMsg==uMsgEndDialog)

{

HWND    hwndNextViewer;

// Free the icon/icon-title metafile corresponding to Paste/PasteList option which is not selected

if (lpPS->fLink)

OleUIMetafilePictIconFree(lpPS->hMetaPictOD);

else OleUIMetafilePictIconFree(lpPS->hMetaPictLSD);

// Free data associated with each list box entry

FreeListData(GetDlgItem(hDlg, ID_PS_PASTELIST));

FreeListData(GetDlgItem(hDlg, ID_PS_PASTELINKLIST));

//Free any specific allocations before calling StandardCleanup

if (lpPS->hObjDesc) GlobalFree(lpPS->hObjDesc);

if (lpPS->hLinkSrcDesc) GlobalFree(lpPS->hLinkSrcDesc);

if (lpPS->hBuff) GlobalFree(lpPS->hBuff);

// Change the clipboard notification chain

hwndNextViewer = GetProp(hDlg, NEXTCBVIEWER);

if (hwndNextViewer != HWND_BROADCAST)

{

SetProp(hDlg, NEXTCBVIEWER, HWND_BROADCAST);

ChangeClipboardChain(hDlg, hwndNextViewer);

}

RemoveProp(hDlg, NEXTCBVIEWER);

StandardCleanup(lpPS, hDlg);

EndDialog(hDlg, wParam);

return TRUE;

}

switch (iMsg)

{

case WM_INITDIALOG:

hCursorOld = HourGlassOn();

FPasteSpecialInit(hDlg, wParam, lParam);

HourGlassOff(hCursorOld);

return FALSE;

case WM_DRAWCLIPBOARD:

{

HWND    hwndNextViewer = GetProp(hDlg, NEXTCBVIEWER);

HWND    hDlg_ChgIcon;

if (hwndNextViewer == HWND_BROADCAST)

break;

if (hwndNextViewer)

{

SendMessage(hwndNextViewer, iMsg, wParam, lParam);

// Refresh next viewer in case it got modified

//    by the SendMessage() (likely if multiple

//    PasteSpecial dialogs are up simultaneously)

hwndNextViewer = GetProp(hDlg, NEXTCBVIEWER);

}

SetProp(hDlg, NEXTCBVIEWER, HWND_BROADCAST);

ChangeClipboardChain(hDlg, hwndNextViewer);

/* OLE2NOTE: if the ChangeIcon dialog is currently up, then

**    we need to defer bringing down PasteSpecial dialog

**    until after ChangeIcon dialog returns. if the

**    ChangeIcon dialog is NOT up, then we can bring down

**    the PasteSpecial dialog immediately.

*/

if ((hDlg_ChgIcon=(HWND)GetProp(hDlg,PROP_HWND_CHGICONDLG))!=NULL)

{

// ChangeIcon dialog is UP

lpPS->fClipboardChanged = TRUE;

} else {

// ChangeIcon dialog is NOT up

//  Free icon and icon title metafile

SendDlgItemMessage(

hDlg, ID_PS_ICONDISPLAY, IBXM_IMAGEFREE, 0, 0L);

SendMessage(

hDlg, uMsgEndDialog, OLEUI_PSERR_CLIPBOARDCHANGED,0L);

}

break;

}

case WM_CHANGECBCHAIN:

{

HWND    hwndNextViewer = GetProp(hDlg, NEXTCBVIEWER);

if (wParam == (UINT)hwndNextViewer)

#ifdef WIN32

SetProp(hDlg, NEXTCBVIEWER, (hwndNextViewer = (HWND)lParam));

#else

SetProp(hDlg, NEXTCBVIEWER, (hwndNextViewer = (HWND)LOWORD(lParam)));

#endif

else if (hwndNextViewer && hwndNextViewer != HWND_BROADCAST)

SendMessage(hwndNextViewer, iMsg, wParam, lParam);

break;

}

case WM_COMMAND:

switch (wID)

{

case ID_PS_PASTE:

FTogglePasteType(hDlg, lpPS, PSF_SELECTPASTE);

break;

case ID_PS_PASTELINK:

FTogglePasteType(hDlg, lpPS, PSF_SELECTPASTELINK);

break;

case ID_PS_DISPLAYLIST:

switch (wCode)

{

case LBN_SELCHANGE:

ChangeListSelection(hDlg, lpPS, hWndMsg);

break;

case LBN_DBLCLK:

// Same as pressing OK

SendCommand(hDlg, IDOK, BN_CLICKED, hWndMsg);

break;

}

break;

case ID_PS_DISPLAYASICON:

ToggleDisplayAsIcon(hDlg, lpPS);

break;

case ID_PS_CHANGEICON:

ChangeIcon(hDlg, lpPS);

if (lpPS->fClipboardChanged) {

// Free icon and icon title metafile

SendDlgItemMessage(

hDlg, ID_PS_ICONDISPLAY, IBXM_IMAGEFREE,0,0L);

SendMessage(

hDlg, uMsgEndDialog,

OLEUI_PSERR_CLIPBOARDCHANGED, 0L);

}

break;

case IDOK:

{

BOOL fDestAspectIcon =

((lpPS->dwFlags & PSF_CHECKDISPLAYASICON) ?

TRUE : FALSE);

lpOPS = lpPS->lpOPS;

// Return current flags

lpOPS->dwFlags = lpPS->dwFlags;

// Return index of arrPasteEntries[] corresponding to format selected by user

lpOPS->nSelectedIndex = lpPS->nSelectedIndex;

// Return if user selected Paste or PasteLink

lpOPS->fLink = lpPS->fLink;

/* if user selected same ASPECT as displayed in the

**    source, then sizel passed in the

**    ObjectDescriptor/LinkSrcDescriptor is

**    applicable. otherwise, the sizel does not apply.

*/

if (lpPS->fLink) {

if (lpPS->fSrcAspectIconLSD == fDestAspectIcon)

lpOPS->sizel = lpPS->sizelLSD;

else

lpOPS->sizel.cx = lpOPS->sizel.cy = 0;

} else {

if (lpPS->fSrcAspectIconOD == fDestAspectIcon)

lpOPS->sizel = lpPS->sizelOD;

else

lpOPS->sizel.cx = lpOPS->sizel.cy = 0;

}

// Return metafile with icon and icon title that the user selected

lpOPS->hMetaPict=(HGLOBAL)SendDlgItemMessage(hDlg, ID_PS_ICONDISPLAY,

IBXM_IMAGEGET, 0, 0L);

SendMessage(hDlg, uMsgEndDialog, OLEUI_OK, 0L);

break;

}

case IDCANCEL:

// Free icon and icon title metafile

SendDlgItemMessage(

hDlg, ID_PS_ICONDISPLAY, IBXM_IMAGEFREE, 0, 0L);

SendMessage(hDlg, uMsgEndDialog, OLEUI_CANCEL, 0L);

break;

case ID_OLEUIHELP:

PostMessage(lpPS->lpOPS->hWndOwner, uMsgHelp,

(WPARAM)hDlg, MAKELPARAM(IDD_PASTESPECIAL, 0));

break;

}

break;

}

return FALSE;

}

/*

 * FPasteSpecialInit

 *

 * Purpose:

 *  WM_INITIDIALOG handler for the Paste Special dialog box.

 *

 * Parameters:

 *  hDlg            HWND of the dialog

 *  wParam          WPARAM of the message

 *  lParam          LPARAM of the message

 *

 * Return Value:

 *  BOOL            Value to return for WM_INITDIALOG.

 */

BOOL FPasteSpecialInit(HWND hDlg, WPARAM wParam, LPARAM lParam)

{

LPPASTESPECIAL              lpPS;

LPOLEUIPASTESPECIAL         lpOPS;

HFONT                       hFont;

BOOL                        fPasteAvailable, fPasteLinkAvailable;

STGMEDIUM                   medium;

LPOBJECTDESCRIPTOR          lpOD;

LPLINKSRCDESCRIPTOR         lpLSD;

int                         n;

CLIPFORMAT                  cfFormat;

// Copy the structure at lParam into our instance memory.

lpPS = (LPPASTESPECIAL)LpvStandardInit(hDlg, sizeof(PASTESPECIAL), TRUE, &hFont);

// PvStandardInit sent a termination to us already.

if (NULL == lpPS)

return FALSE;

lpOPS=(LPOLEUIPASTESPECIAL)lParam;

// Copy other information from lpOPS that we might modify.

lpPS->lpOPS = lpOPS;

lpPS->dwFlags = lpOPS->dwFlags;

// Initialize user selections in the Paste and PasteLink listboxes

lpPS->nPasteListCurSel = 0;

lpPS->nPasteLinkListCurSel = 0;

// If we got a font, send it to the necessary controls.

if (NULL!=hFont)

{

SendDlgItemMessage(hDlg, ID_PS_SOURCETEXT, WM_SETFONT, (WPARAM)hFont, 0L);

SendDlgItemMessage(hDlg, ID_PS_RESULTTEXT, WM_SETFONT, (WPARAM)hFont, 0L);

}

// Hide the help button if required

if (!(lpPS->lpOPS->dwFlags & PSF_SHOWHELP))

StandardShowDlgItem(hDlg, ID_OLEUIHELP, SW_HIDE);

// Hide all DisplayAsIcon related controls if it should be disabled

if ( lpPS->dwFlags & PSF_DISABLEDISPLAYASICON ) {

  StandardShowDlgItem(hDlg, ID_PS_DISPLAYASICON, SW_HIDE);

  StandardShowDlgItem(hDlg, ID_PS_CHANGEICON, SW_HIDE);

  StandardShowDlgItem(hDlg, ID_PS_ICONDISPLAY, SW_HIDE);

}

// PSF_CHECKDISPLAYASICON is an OUT flag. Clear it if has been set on the way in.

lpPS->dwFlags = lpPS->dwFlags & ~PSF_CHECKDISPLAYASICON;

//  Change the caption if required

if (NULL != lpOPS->lpszCaption)

SetWindowText(hDlg, lpOPS->lpszCaption);

// Load 'Unknown Source' and 'Unknown Type' strings

n = LoadString(ghInst, (UINT)IDS_PSUNKNOWNTYPE, lpPS->szUnknownType, PS_UNKNOWNSTRLEN);

if (n)

n = LoadString(ghInst, (UINT)IDS_PSUNKNOWNSRC, lpPS->szUnknownSource, PS_UNKNOWNSTRLEN);

if (!n)

{

PostMessage(hDlg, uMsgEndDialog, OLEUI_ERR_LOADSTRING, 0L);

return FALSE;

}

lpPS->szAppName[0]='\0';

// GetData CF_OBJECTDESCRIPTOR. If the object on the clipboard in an OLE1 object (offering CF_OWNERLINK)

// or has been copied to clipboard by FileMaager (offering CF_FILENAME), an OBJECTDESCRIPTOR will be

// created will be created from CF_OWNERLINK or CF_FILENAME. See OBJECTDESCRIPTOR for more info.

if (lpPS->hObjDesc = OleStdFillObjectDescriptorFromData(lpOPS->lpSrcDataObj, &medium, &cfFormat))

{

lpOD = GlobalLock(lpPS->hObjDesc);

// Get FullUserTypeName, SourceOfCopy and CLSID

if (lpOD->dwFullUserTypeName)

lpPS->szFullUserTypeNameOD = (LPSTR)lpOD+lpOD->dwFullUserTypeName;

else lpPS->szFullUserTypeNameOD = lpPS->szUnknownType;

if (lpOD->dwSrcOfCopy)

{

lpPS->szSourceOfDataOD = (LPSTR)lpOD+lpOD->dwSrcOfCopy;

// If CF_FILENAME was offered, source of copy is a path name. Fit the path to the

// static control that will display it.

if (cfFormat == cfFileName)

lpPS->szSourceOfDataOD = ChopText(GetDlgItem(hDlg, ID_PS_SOURCETEXT), 0, lpPS->szSourceOfDataOD);

}

else lpPS->szSourceOfDataOD = lpPS->szUnknownSource;

lpPS->clsidOD = lpOD->clsid;

lpPS->sizelOD = lpOD->sizel;

// Does source specify DVASPECT_ICON?

if (lpOD->dwDrawAspect & DVASPECT_ICON)

   lpPS->fSrcAspectIconOD = TRUE;

else lpPS->fSrcAspectIconOD = FALSE;

// Does source specify OLEMISC_ONLYICONIC?

if (lpOD->dwStatus & OLEMISC_ONLYICONIC)

lpPS->fSrcOnlyIconicOD = TRUE;

else lpPS->fSrcOnlyIconicOD = FALSE;

// Get application name of source from auxusertype3 in the registration database

if (0==OleStdGetAuxUserType(&lpPS->clsidOD, 3, lpPS->szAppName, OLEUI_CCHKEYMAX, NULL))

{

 // Use "the application which created it" as the name of the application

 if (0==LoadString(ghInst, (UINT)IDS_PSUNKNOWNAPP, lpPS->szAppName, PS_UNKNOWNSTRLEN))

 {

 PostMessage(hDlg, uMsgEndDialog, OLEUI_ERR_LOADSTRING, 0L);

 return FALSE;

 }

}

// Retrieve an icon from the object

if (lpPS->fSrcAspectIconOD)

{

lpPS->hMetaPictOD = OleStdGetData(

lpOPS->lpSrcDataObj,

CF_METAFILEPICT,

NULL,

DVASPECT_ICON,

&medium

);

}

// If object does not offer icon, obtain it from the CLSID

if (NULL == lpPS->hMetaPictOD)

{

lpPS->hMetaPictOD = GetIconOfClass(

ghInst,

&lpPS->clsidOD,

NULL,

TRUE);   // Use the short user type name (auxusertype3)

}

}

// Does object offer CF_LINKSRCDESCRIPTOR?

if (lpPS->hLinkSrcDesc = OleStdGetData(

lpOPS->lpSrcDataObj,

(CLIPFORMAT)cfLinkSrcDescriptor,

NULL,

DVASPECT_CONTENT,

&medium))

{

// Get FullUserTypeName, SourceOfCopy and CLSID

lpLSD = GlobalLock(lpPS->hLinkSrcDesc);

if (lpLSD->dwFullUserTypeName)

lpPS->szFullUserTypeNameLSD = (LPSTR)lpLSD+lpLSD->dwFullUserTypeName;

else lpPS->szFullUserTypeNameLSD = lpPS->szUnknownType;

if (lpLSD->dwSrcOfCopy)

lpPS->szSourceOfDataLSD = (LPSTR)lpLSD+lpLSD->dwSrcOfCopy;

else lpPS->szSourceOfDataLSD = lpPS->szUnknownSource;

// if no ObjectDescriptor, then use LinkSourceDescriptor source string

if (!lpPS->hObjDesc)

lpPS->szSourceOfDataOD = lpPS->szSourceOfDataLSD;

lpPS->clsidLSD = lpLSD->clsid;

lpPS->sizelLSD = lpLSD->sizel;

// Does source specify DVASPECT_ICON?

if (lpLSD->dwDrawAspect & DVASPECT_ICON)

   lpPS->fSrcAspectIconLSD = TRUE;

else lpPS->fSrcAspectIconLSD = FALSE;

// Does source specify OLEMISC_ONLYICONIC?

if (lpLSD->dwStatus & OLEMISC_ONLYICONIC)

lpPS->fSrcOnlyIconicLSD = TRUE;

else lpPS->fSrcOnlyIconicLSD = FALSE;

// Retrieve an icon from the object

if (lpPS->fSrcAspectIconLSD)

{

lpPS->hMetaPictLSD = OleStdGetData(

lpOPS->lpSrcDataObj,

CF_METAFILEPICT,

NULL,

DVASPECT_ICON,

&medium

);

}

// If object does not offer icon, obtain it from the CLSID

if (NULL == lpPS->hMetaPictLSD)

{

char szLabel[OLEUI_CCHLABELMAX];

HWND hIconWnd;

RECT IconRect;

int  nWidth;

LPSTR lpszLabel;

hIconWnd = GetDlgItem(hDlg, ID_PS_ICONDISPLAY);

GetClientRect(hIconWnd, &IconRect);

nWidth = ((IconRect.right-IconRect.left) * 3) / 2;   // width is 1.5 times width of iconbox

LSTRCPYN(szLabel, lpPS->szSourceOfDataLSD, sizeof(szLabel));

szLabel[sizeof(szLabel)-1] = '\0';

lpszLabel = ChopText(hIconWnd, nWidth, (LPSTR)szLabel);

lpPS->hMetaPictLSD = GetIconOfClass(

ghInst,

&lpPS->clsidLSD,

lpszLabel,       /* use chopped source string as label */

FALSE            /* not applicable */

);

}

}

else if (lpPS->hObjDesc)     // Does not offer CF_LINKSRCDESCRIPTOR but offers CF_OBJECTDESCRIPTOR

{

// Copy the values of OBJECTDESCRIPTOR

lpPS->szFullUserTypeNameLSD = lpPS->szFullUserTypeNameOD;

lpPS->szSourceOfDataLSD = lpPS->szSourceOfDataOD;

lpPS->clsidLSD = lpPS->clsidOD;

lpPS->sizelLSD = lpPS->sizelOD;

lpPS->fSrcAspectIconLSD = lpPS->fSrcAspectIconOD;

lpPS->fSrcOnlyIconicLSD = lpPS->fSrcOnlyIconicOD;

// Don't copy the hMetaPict; instead get a separate copy

if (lpPS->fSrcAspectIconLSD)

{

lpPS->hMetaPictLSD = OleStdGetData(

lpOPS->lpSrcDataObj,

CF_METAFILEPICT,

NULL,

DVASPECT_ICON,

&medium

);

}

if (NULL == lpPS->hMetaPictLSD)

{

char szLabel[OLEUI_CCHLABELMAX];

HWND hIconWnd;

RECT IconRect;

int  nWidth;

LPSTR lpszLabel;

hIconWnd = GetDlgItem(hDlg, ID_PS_ICONDISPLAY);

GetClientRect(hIconWnd, &IconRect);

nWidth = ((IconRect.right-IconRect.left) * 3) / 2;   // width is 1.5 times width of iconbox

LSTRCPYN(szLabel, lpPS->szSourceOfDataLSD, sizeof(szLabel));

szLabel[sizeof(szLabel)-1] = '\0';

lpszLabel = ChopText(hIconWnd, nWidth, (LPSTR)szLabel);

lpPS->hMetaPictLSD = GetIconOfClass(

ghInst,

&lpPS->clsidLSD,

lpszLabel,   /* Use chopped source string as label */

FALSE        /* Not applicable */

);

}

}

// Not an OLE object

if (lpPS->hObjDesc == NULL && lpPS->hLinkSrcDesc == NULL)

{

 lpPS->szFullUserTypeNameLSD = lpPS->szFullUserTypeNameOD = lpPS->szUnknownType;

 lpPS->szSourceOfDataLSD = lpPS->szSourceOfDataOD = lpPS->szUnknownSource;

 lpPS->hMetaPictLSD = lpPS->hMetaPictOD = NULL;

}

// Allocate scratch memory to construct item names in the paste and pastelink listboxes

lpPS->hBuff = AllocateScratchMem(lpPS);

if (lpPS->hBuff == NULL)

{

   PostMessage(hDlg, uMsgEndDialog, OLEUI_ERR_GLOBALMEMALLOC, 0L);

   return FALSE;

}

// Select the Paste Link Button if specified. Otherwise select

//      Paste Button by default

if (lpPS->dwFlags & PSF_SELECTPASTELINK)

lpPS->dwFlags = (lpPS->dwFlags & ~PSF_SELECTPASTE) | PSF_SELECTPASTELINK;

else

lpPS->dwFlags =(lpPS->dwFlags & ~PSF_SELECTPASTELINK) | PSF_SELECTPASTE;

// Mark which PasteEntry formats are available from source data object

OleStdMarkPasteEntryList(

lpOPS->lpSrcDataObj,lpOPS->arrPasteEntries,lpOPS->cPasteEntries);

// Check if items are available to be pasted

fPasteAvailable = FFillPasteList(hDlg, lpPS);

if (!fPasteAvailable)

{

lpPS->dwFlags &= ~PSF_SELECTPASTE;

EnableWindow(GetDlgItem(hDlg, ID_PS_PASTE), FALSE);

}

// Check if items are available to be paste-linked

fPasteLinkAvailable = FFillPasteLinkList(hDlg, lpPS);

if (!fPasteLinkAvailable)

{

lpPS->dwFlags &= ~PSF_SELECTPASTELINK;

EnableWindow(GetDlgItem(hDlg, ID_PS_PASTELINK), FALSE);

}

// If one of Paste or PasteLink is disabled, select the other one

//    regardless of what the input flags say

if (fPasteAvailable && !fPasteLinkAvailable)

lpPS->dwFlags |= PSF_SELECTPASTE;

if (fPasteLinkAvailable && !fPasteAvailable)

lpPS->dwFlags |= PSF_SELECTPASTELINK;

if (lpPS->dwFlags & PSF_SELECTPASTE)

{

// FTogglePaste will set the PSF_SELECTPASTE flag, so clear it.

lpPS->dwFlags &= ~PSF_SELECTPASTE;

CheckRadioButton(hDlg, ID_PS_PASTE, ID_PS_PASTELINK, ID_PS_PASTE);

FTogglePasteType(hDlg, lpPS, PSF_SELECTPASTE);

}

else if (lpPS->dwFlags & PSF_SELECTPASTELINK)

{

// FTogglePaste will set the PSF_SELECTPASTELINK flag, so clear it.

lpPS->dwFlags &= ~PSF_SELECTPASTELINK;

CheckRadioButton(hDlg, ID_PS_PASTE, ID_PS_PASTELINK, ID_PS_PASTELINK);

FTogglePasteType(hDlg, lpPS, PSF_SELECTPASTELINK);

}

else  // Items are not available to be be Pasted or Paste-Linked

{

// Enable or disable DisplayAsIcon and set the result text and image

EnableDisplayAsIcon(hDlg, lpPS);

SetPasteSpecialHelpResults(hDlg, lpPS);

}

// Give initial focus to the list box

SetFocus(GetDlgItem(hDlg, ID_PS_DISPLAYLIST));

// Set property to handle clipboard change notifications

SetProp(hDlg, NEXTCBVIEWER, HWND_BROADCAST);

SetProp(hDlg, NEXTCBVIEWER, SetClipboardViewer(hDlg));

lpPS->fClipboardChanged = FALSE;

/*

 * PERFORM OTHER INITIALIZATION HERE.

 */

// Call the hook with lCustData in lParam

UStandardHook(lpPS, hDlg, WM_INITDIALOG, wParam, lpOPS->lCustData);

return TRUE;

}

/*

 * FTogglePasteType

 *

 * Purpose:

 *  Toggles between Paste and Paste Link. The Paste list and PasteLink

 *  list are always invisible. The Display List is filled from either

 *  the Paste list or the PasteLink list depending on which Paste radio

 *  button is selected.

 *

 * Parameters:

 *  hDlg            HWND of the dialog

 *  lpPS             Paste Special Dialog Structure

 *  dwOption        Paste or PasteSpecial option

 *

 * Return Value:

 *  BOOL            Returns TRUE if the option has already been selected.

 *                  Otherwise the option is selected and FALSE is returned

 */

BOOL FTogglePasteType(HWND hDlg, LPPASTESPECIAL lpPS, DWORD dwOption)

{

DWORD dwTemp;

HWND hList, hListDisplay;

DWORD dwData;

int i, nItems;

LPSTR lpsz;

// Skip all this if the button is already selected

if (lpPS->dwFlags & dwOption)

return TRUE;

dwTemp = PSF_SELECTPASTE | PSF_SELECTPASTELINK;

lpPS->dwFlags = (lpPS->dwFlags & ~dwTemp) | dwOption;

// Hide IconDisplay. This prevents flashing if the icon display is changed

StandardShowDlgItem(hDlg, ID_PS_ICONDISPLAY, SW_HIDE);

hListDisplay = GetDlgItem(hDlg, ID_PS_DISPLAYLIST);

// If Paste was selected

if (lpPS->dwFlags & PSF_SELECTPASTE)

{

// Set the Source of the object in the clipboard

SetDlgItemText(hDlg, ID_PS_SOURCETEXT, lpPS->szSourceOfDataOD);

// If an icon is available

if (lpPS->hMetaPictOD)

// Set the icon display

SendDlgItemMessage(hDlg, ID_PS_ICONDISPLAY, IBXM_IMAGESET,

  (WPARAM)lpPS->hMetaPictOD, 0L);

hList = GetDlgItem(hDlg, ID_PS_PASTELIST);

// We are switching from PasteLink to Paste. Remember current selection

//    in PasteLink list so it can be restored.

lpPS->nPasteLinkListCurSel = (int)SendMessage(hListDisplay, LB_GETCURSEL, 0, 0L);

if (lpPS->nPasteLinkListCurSel == LB_ERR)

lpPS->nPasteLinkListCurSel = 0;

// Remember if user selected Paste or PasteLink

lpPS->fLink = FALSE;

}

else    // If PasteLink was selected

{

// Set the Source of the object in the clipboard

SetDlgItemText(hDlg, ID_PS_SOURCETEXT, lpPS->szSourceOfDataLSD);

// If an icon is available

if (lpPS->hMetaPictLSD)

// Set the icon display

SendDlgItemMessage(hDlg, ID_PS_ICONDISPLAY, IBXM_IMAGESET,

  (WPARAM)lpPS->hMetaPictLSD, 0L);

hList = GetDlgItem(hDlg, ID_PS_PASTELINKLIST);

// We are switching from Paste to PasteLink. Remember current selection

//    in Paste list so it can be restored.

lpPS->nPasteListCurSel = (int)SendMessage(hListDisplay, LB_GETCURSEL, 0, 0L);

if (lpPS->nPasteListCurSel == LB_ERR)

lpPS->nPasteListCurSel = 0;

// Remember if user selected Paste or PasteLink

lpPS->fLink = TRUE;

}

// Turn drawing off while the Display List is being filled

SendMessage(hListDisplay, WM_SETREDRAW, (WPARAM)FALSE, 0L);

// Move data to Display list box

SendMessage(hListDisplay, LB_RESETCONTENT, 0, 0L);

nItems = (int) SendMessage(hList, LB_GETCOUNT, 0, 0L);

lpsz = (LPSTR)GlobalLock(lpPS->hBuff);

for (i = 0; i < nItems; i++)

{

SendMessage(hList, LB_GETTEXT, (WPARAM)i, (LPARAM)lpsz);

dwData = SendMessage(hList, LB_GETITEMDATA, (WPARAM)i, 0L);

SendMessage(hListDisplay, LB_INSERTSTRING, (WPARAM)i, (LPARAM)lpsz);

SendMessage(hListDisplay, LB_SETITEMDATA, (WPARAM)i, dwData);

}

GlobalUnlock(lpPS->hBuff);

// Restore the selection in the Display List from user's last selection

if (lpPS->dwFlags & PSF_SELECTPASTE)

SendMessage(hListDisplay, LB_SETCURSEL, lpPS->nPasteListCurSel, 0L);

else

SendMessage(hListDisplay, LB_SETCURSEL, lpPS->nPasteLinkListCurSel, 0L);

// Paint Display List

SendMessage(hListDisplay, WM_SETREDRAW, (WPARAM)TRUE, 0L);

InvalidateRect(hListDisplay, NULL, TRUE);

UpdateWindow(hListDisplay);

// Auto give the focus to the Display List

SetFocus(hListDisplay);

// Enable/Disable DisplayAsIcon and set the help result text and bitmap corresponding to

//    the current selection

ChangeListSelection(hDlg, lpPS, hListDisplay);

return FALSE;

}

/*

 * ChangeListSelection

 *

 * Purpose:

 *  When the user changes the selection in the list, DisplayAsIcon is enabled or disabled,

 *  Result text and bitmap are updated and the index of the arrPasteEntries[] corresponding

 *  to the current format selection is saved.

 *

 * Parameters:

 *  hDlg            HWND of the dialog

 *  lpPS             Paste Special Dialog Structure

 *  hList           HWND of the List

 *

 * Return Value:

 *  No return value

 */

void ChangeListSelection(HWND hDlg, LPPASTESPECIAL lpPS, HWND hList)

{

LPPASTELISTITEMDATA lpItemData;

int nCurSel;

EnableDisplayAsIcon(hDlg, lpPS);

SetPasteSpecialHelpResults(hDlg, lpPS);

// Remember index of arrPasteEntries[] corresponding to the current selection

nCurSel = (int)SendMessage(hList, LB_GETCURSEL, 0, 0L);

if (nCurSel == LB_ERR) return;

lpItemData = (LPPASTELISTITEMDATA) SendMessage(hList, LB_GETITEMDATA,

(WPARAM)nCurSel, 0L);

if ((LRESULT)lpItemData == LB_ERR) return;

lpPS->nSelectedIndex = lpItemData->nPasteEntriesIndex;

}

/*

 * EnableDisplayAsIcon

 *

 * Purpose:

 *  Enable or disable the DisplayAsIcon button depending on whether

 *  the current selection can be displayed as an icon or not. The following table describes

 *  the state of DisplayAsIcon. The calling application is termed CONTAINER, the source

 *  of data on the clipboard is termed SOURCE.

 *  Y = Yes; N = No; Blank = State does not matter;

 * =====================================================================

 * SOURCE          SOURCE             CONTAINER             DisplayAsIcon

 * specifies       specifies          specifies             Initial State

 * DVASPECT_ICON   OLEMISC_ONLYICONIC OLEUIPASTE_ENABLEICON

 *

 *                                    N                     Unchecked&Disabled

 *                 Y                  Y                     Checked&Disabled

 * Y               N                  Y                     Checked&Enabled

 * N               N                  Y                     Unchecked&Enabled

 * =====================================================================

 *

 * Parameters:

 *  hDlg            HWND of the dialog

 *  lpPS             Paste Special Dialog Structure

 *

 * Return Value:

 *  No return value

 */

void EnableDisplayAsIcon(HWND hDlg, LPPASTESPECIAL lpPS)

{

int nIndex;

BOOL fCntrEnableIcon;

BOOL fSrcOnlyIconic = (lpPS->fLink) ? lpPS->fSrcOnlyIconicLSD : lpPS->fSrcOnlyIconicOD;

BOOL fSrcAspectIcon = (lpPS->fLink) ? lpPS->fSrcAspectIconLSD : lpPS->fSrcAspectIconOD;

HWND hList;

LPPASTELISTITEMDATA lpItemData;

HGLOBAL hMetaPict = (lpPS->fLink) ? lpPS->hMetaPictLSD : lpPS->hMetaPictOD;

hList = GetDlgItem(hDlg, ID_PS_DISPLAYLIST);

// Get data corresponding to the current selection in the listbox

nIndex = (int)SendMessage(hList, LB_GETCURSEL, 0, 0);

if (nIndex != LB_ERR)

{

lpItemData = (LPPASTELISTITEMDATA) SendMessage(hList, LB_GETITEMDATA, (WPARAM)nIndex, 0L);

if ((LRESULT)lpItemData != LB_ERR)

fCntrEnableIcon = lpItemData->fCntrEnableIcon;

else fCntrEnableIcon = FALSE;

}

else fCntrEnableIcon = FALSE;

// If there is an icon available

if (hMetaPict != NULL)

{

if (!fCntrEnableIcon)          // Does CONTAINER specify OLEUIPASTE_ENABLEICON?

{

// Uncheck & Disable DisplayAsIcon

lpPS->dwFlags &= ~PSF_CHECKDISPLAYASICON;

CheckDlgButton(hDlg, ID_PS_DISPLAYASICON, FALSE);

EnableWindow(GetDlgItem(hDlg, ID_PS_DISPLAYASICON), FALSE);

// Hide IconDisplay and ChangeIcon button

StandardShowDlgItem(hDlg, ID_PS_ICONDISPLAY, SW_HIDE);

StandardShowDlgItem(hDlg, ID_PS_CHANGEICON, SW_HIDE);

}

else if (fSrcOnlyIconic)       // Does SOURCE specify OLEMISC_ONLYICONIC?

{

// Check & Disable DisplayAsIcon

lpPS->dwFlags |= PSF_CHECKDISPLAYASICON;

CheckDlgButton(hDlg, ID_PS_DISPLAYASICON, TRUE);

EnableWindow(GetDlgItem(hDlg, ID_PS_DISPLAYASICON), FALSE);

// Show IconDisplay and ChangeIcon button

StandardShowDlgItem(hDlg, ID_PS_ICONDISPLAY, SW_SHOWNORMAL);

StandardShowDlgItem(hDlg, ID_PS_CHANGEICON, SW_SHOWNORMAL);

}

else if (fSrcAspectIcon)       // Does SOURCE specify DVASPECT_ICON?

{

 // Check & Enable DisplayAsIcon

 lpPS->dwFlags |= PSF_CHECKDISPLAYASICON;

 CheckDlgButton(hDlg, ID_PS_DISPLAYASICON, TRUE);

 EnableWindow(GetDlgItem(hDlg, ID_PS_DISPLAYASICON), TRUE);

 // Show IconDisplay and ChangeIcon button

 StandardShowDlgItem(hDlg, ID_PS_ICONDISPLAY, SW_SHOWNORMAL);

 StandardShowDlgItem(hDlg, ID_PS_CHANGEICON, SW_SHOWNORMAL);

}

else

{

 //Uncheck and Enable DisplayAsIcon

 lpPS->dwFlags &= ~PSF_CHECKDISPLAYASICON;

 CheckDlgButton(hDlg, ID_PS_DISPLAYASICON, FALSE);

 EnableWindow(GetDlgItem(hDlg, ID_PS_DISPLAYASICON), TRUE);

 // Hide IconDisplay and ChangeIcon button

 StandardShowDlgItem(hDlg, ID_PS_ICONDISPLAY, SW_HIDE);

 StandardShowDlgItem(hDlg, ID_PS_CHANGEICON, SW_HIDE);

}

}

else  // No icon available

{

// Unchecked & Disabled

lpPS->dwFlags &= ~PSF_CHECKDISPLAYASICON;

CheckDlgButton(hDlg, ID_PS_DISPLAYASICON, FALSE);

EnableWindow(GetDlgItem(hDlg, ID_PS_DISPLAYASICON), FALSE);

// Hide IconDisplay and ChangeIcon button

StandardShowDlgItem(hDlg, ID_PS_ICONDISPLAY, SW_HIDE);

StandardShowDlgItem(hDlg, ID_PS_CHANGEICON, SW_HIDE);

}

}

/*

 * ToggleDisplayAsIcon

 *

 * Purpose:

 *  Toggles the DisplayAsIcon button. Hides or shows the Icon Display and

 *  the ChangeIcon button and changes the help result text and bitmap.

 *

 * Parameters:

 *  hDlg            HWND of the dialog

 *  lpPS             Paste Special Dialog Structure

 *

 * Return Value:

 *  None

 *

 */

void ToggleDisplayAsIcon(HWND hDlg, LPPASTESPECIAL lpPS)

{

BOOL fCheck;

int i;

fCheck = IsDlgButtonChecked(hDlg, ID_PS_DISPLAYASICON);

if (fCheck)

lpPS->dwFlags |= PSF_CHECKDISPLAYASICON;

else lpPS->dwFlags &= ~PSF_CHECKDISPLAYASICON;

// Set the help result text and bitmap

SetPasteSpecialHelpResults(hDlg, lpPS);

// Show or hide the Icon Display and ChangeIcon button depending

// on the check state

i = (fCheck) ? SW_SHOWNORMAL : SW_HIDE;

StandardShowDlgItem(hDlg, ID_PS_ICONDISPLAY, i);

StandardShowDlgItem(hDlg, ID_PS_CHANGEICON, i);

}

/*

 * ChangeIcon

 *

 * Purpose:

 *  Brings up the ChangeIcon dialog which allows the user to change

 *  the icon and label.

 *

 * Parameters:

 *  hDlg            HWND of the dialog

 *  lpPS             Paste Special Dialog Structure

 *

 * Return Value:

 *  None

 *

 */

void ChangeIcon(HWND hDlg, LPPASTESPECIAL lpPS)

{

OLEUICHANGEICON ci;

UINT uRet;

CLSID   clsid     = (lpPS->fLink) ? lpPS->clsidLSD : lpPS->clsidOD;

//Initialize the structure

_fmemset((LPOLEUICHANGEICON)&ci, 0, sizeof(ci));

ci.hMetaPict = (HGLOBAL)SendDlgItemMessage(hDlg, ID_PS_ICONDISPLAY, IBXM_IMAGEGET, 0, 0L);

ci.cbStruct = sizeof(ci);

ci.hWndOwner = hDlg;

ci.clsid = clsid;

ci.dwFlags  = CIF_SELECTCURRENT;

// Only show help in the ChangeIcon dialog if we're showing it in this dialog.

if (lpPS->dwFlags & PSF_SHOWHELP)

ci.dwFlags |= CIF_SHOWHELP;

// Let the hook in to customize Change Icon if desired.

uRet = UStandardHook(lpPS, hDlg, uMsgChangeIcon, 0, (LONG)(LPSTR)&ci);

if (0 == uRet)

uRet=(UINT)(OLEUI_OK==OleUIChangeIcon(&ci));

// Update the display if necessary.

if (0!=uRet)

{

/*

* OleUIChangeIcon will have already freed our

* current hMetaPict that we passed in when OK is

* pressed in that dialog.  So we use 0L as lParam

* here so the IconBox doesn't try to free the

* metafilepict again.

*/

SendDlgItemMessage(hDlg, ID_PS_ICONDISPLAY, IBXM_IMAGESET, (WPARAM)ci.hMetaPict, 0L);

// Remember the new icon chosen by the user. Note that Paste and PasteLink have separate

//    icons - changing one does not change the other.

if (lpPS->fLink)

lpPS->hMetaPictLSD = ci.hMetaPict;

else lpPS->hMetaPictOD = ci.hMetaPict;

}

}

/*

 *SetPasteSpecialHelpResults

 *

 * Purpose:

 *  Sets the help result text and bitmap according to the current

 *  list selection. The following state table indicates which ResultText

 *  and ResultImage are selected. If %s in the lpstrFormatName is present,

 *  it is assumed that an object is being pasted/paste-linked, otherwise it

 *  is assumed that data is being pasted/paste-linked.

 *  Y = Yes; N = No; Blank = State does not matter;

 *  The numbers in the the ResultText and ResultImage columns refer to the table

 *  entries that follow.

 * =====================================================================

 * Paste/       lpstrFormatName in                DisplayAsIcon Result      Result

 * PasteLink    arrPasteEntry[]contains %s        checked       Text        Image

 *              (Is Object == Y, Is Data == N)

 * Paste        N                                               1           1

 * Paste        Y                                 N             2           2

 * Paste        Y                                 Y             3           3

 * PasteLink    N                                               4           4

 * PasteLink    Y                                 N             5           4

 * PasteLink    Y                                 Y             6           5

 * =====================================================================

 * Result Text:

 *

 * 1. "Inserts the contents of the Clipboard into your document as <native type name,

 *     and optionally an additional help sentence>"

 * 2. "Inserts the contents of the Clipboard into your document so that you may

 *     activate it using <object app name>"

 * 3. "Inserts the contents of the Clipboard into your document so that you may

 *     activate it using <object app name>.  It will be displayed as an icon."

 * 4. "Inserts the contents of the Clipboard into your document as <native type name>.

 *     Paste Link creates a link to the source file so that changes to the source file

 *     will be reflected in your document."

 * 5. "Inserts a picture of the Clipboard contents into your document.  Paste Link

 *     creates a link to the source file so that changes to the source file will be

 *     reflected in your document."

 * 6. "Inserts an icon into your document which represents the Clipboard contents.

 *     Paste Link creates a link to the source file so that changes to the source file

 *     will be reflected in your document."

 * =====================================================================

 * Result Image:

 *

 * 1. Clipboard Image

 * 2. Paste image, non-iconic.

 * 3. Paste image, iconic.

 * 4. Paste Link image, non-iconic

 * 5. Paste Link image, iconic

 * ====================================================================

 *

 * Parameters:

 *  hDlg            HWND of the dialog

 *  lpPS             Paste Special Dialog Structure

 *

 * Return Value:

 *  No return value

 */

void SetPasteSpecialHelpResults(HWND hDlg, LPPASTESPECIAL lpPS)

{

LPSTR               psz1, psz2, psz3, psz4;

UINT                i, iString, iImage, cch;

int                 nPasteEntriesIndex;

BOOL                fDisplayAsIcon;

BOOL                fIsObject;

HWND                hList;

LPPASTELISTITEMDATA  lpItemData;

LPOLEUIPASTESPECIAL lpOPS = lpPS->lpOPS;

LPSTR       szFullUserTypeName = (lpPS->fLink) ?

lpPS->szFullUserTypeNameLSD : lpPS->szFullUserTypeNameOD;

LPSTR       szInsert;

hList = GetDlgItem(hDlg, ID_PS_DISPLAYLIST);

i=(UINT)SendMessage(hList, LB_GETCURSEL, 0, 0L);

if (i != LB_ERR)

{

lpItemData = (LPPASTELISTITEMDATA)SendMessage(hList, LB_GETITEMDATA, i, 0L);

if ((LRESULT)lpItemData == LB_ERR) return;

nPasteEntriesIndex = lpItemData->nPasteEntriesIndex;

// Check if there is a '%s' in the lpstrFormatName, then an object is being

//   pasted/pastelinked. Otherwise Data is being pasted-pastelinked.

fIsObject = FHasPercentS(lpOPS->arrPasteEntries[nPasteEntriesIndex].lpstrFormatName,

lpPS);

}

else return;

// Is DisplayAsIcon checked?

fDisplayAsIcon=(0L!=(lpPS->dwFlags & PSF_CHECKDISPLAYASICON));

szInsert = szFullUserTypeName;

if (lpPS->dwFlags & PSF_SELECTPASTE)     // If user selected Paste

{

if (fIsObject)

{

iString = (UINT)(fDisplayAsIcon ? IDS_PSPASTEOBJECTASICON : IDS_PSPASTEOBJECT);

iImage  = (UINT)(fDisplayAsIcon ? RESULTIMAGE_EMBEDICON   : RESULTIMAGE_EMBED);

szInsert = lpPS->szAppName;

}

else

{

iString = (UINT)IDS_PSPASTEDATA;

iImage  = RESULTIMAGE_PASTE;

}

}

else if (lpPS->dwFlags & PSF_SELECTPASTELINK)   // User selected PasteLink

{

if (fIsObject)

{

iString = (UINT)(fDisplayAsIcon ? IDS_PSPASTELINKOBJECTASICON : IDS_PSPASTELINKOBJECT);

iImage  = (UINT)(fDisplayAsIcon ? RESULTIMAGE_LINKICON : RESULTIMAGE_LINK);

}

else

{

iString = (UINT)IDS_PSPASTELINKDATA;

iImage  = (UINT)RESULTIMAGE_LINK;

}

}

else   // Should never occur.

{

iString = (UINT)IDS_PSNONOLE;

iImage = RESULTIMAGE_PASTE;

}

// hBuff contains enough space for the 4 buffers required to build up the help

//   result text.

cch = (UINT)GlobalSize(lpPS->hBuff)/4;

psz1=(LPSTR)GlobalLock(lpPS->hBuff);

psz2=psz1+cch;

psz3=psz2+cch;

psz4=psz3+cch;

// Default is an empty string.

*psz1=0;

if (0!=LoadString(ghInst, iString, psz1, cch))

{

// Insert the FullUserTypeName of the source object into the partial result text

//   specified by the container.

wsprintf(psz3, lpOPS->arrPasteEntries[nPasteEntriesIndex].lpstrResultText,

(LPSTR)szInsert);

// Insert the above partial result text into the standard result text.

wsprintf(psz4, psz1, (LPSTR)psz3);

psz1=psz4;

}

// If LoadString failed, we simply clear out the results (*psz1=0 above)

SetDlgItemText(hDlg, ID_PS_RESULTTEXT, psz1);

// Change the result bitmap

SendDlgItemMessage(hDlg, ID_PS_RESULTIMAGE, RIM_IMAGESET, iImage, 0L);

GlobalUnlock(lpPS->hBuff);

}

/*

 * FAddPasteListItem

 *

 * Purpose:

 *  Adds an item to the list box

 *

 * Parameters:

 *  hList            HWND List into which item is to be added

 *  fInsertFirst     BOOL Insert in the beginning of the list?

 *  nPasteEntriesIndex int Index of Paste Entry array this list item corresponsds to

 *  lpPS             Paste Special Dialog Structure

 *  pIMalloc         LPMALLOC  Memory Allocator

 *  lpszBuf          LPSTR Scratch buffer to build up string for list entry

 *  lpszFullUserTypeName LPSTR full user type name for object entry

 *

 * Return Value:

 *  BOOL            TRUE if sucessful.

 *                  FALSE if unsucessful.

 */

BOOL FAddPasteListItem(

HWND hList, BOOL fInsertFirst, int nPasteEntriesIndex,

LPPASTESPECIAL lpPS,

LPMALLOC pIMalloc, LPSTR lpszBuf, LPSTR lpszFullUserTypeName)

{

LPOLEUIPASTESPECIAL lpOPS = lpPS->lpOPS;

LPPASTELISTITEMDATA lpItemData;

int                 nIndex;

// Allocate memory for each list box item

lpItemData = (LPPASTELISTITEMDATA)pIMalloc->lpVtbl->Alloc(

pIMalloc, (DWORD)sizeof(PASTELISTITEMDATA));

if (NULL == lpItemData)

return FALSE;

// Fill data associated with each list box item

lpItemData->nPasteEntriesIndex = nPasteEntriesIndex;

lpItemData->fCntrEnableIcon = ((lpOPS->arrPasteEntries[nPasteEntriesIndex].dwFlags &

OLEUIPASTE_ENABLEICON) ? TRUE : FALSE);

// Build list box entry string, insert the string and add the data the corresponds to it

wsprintf(

(LPSTR)lpszBuf,

lpOPS->arrPasteEntries[nPasteEntriesIndex].lpstrFormatName,

(LPSTR)lpszFullUserTypeName

);

// only add to listbox if not a duplicate

if (LB_ERR!=SendMessage(hList,LB_FINDSTRING, 0, (LPARAM)(LPSTR)lpszBuf)) {

// item is already in list; SKIP this one

pIMalloc->lpVtbl->Free(pIMalloc, (LPVOID)lpItemData);

return TRUE;    // this is NOT an error

}

nIndex = (int)SendMessage(

hList,

(fInsertFirst ? LB_INSERTSTRING : LB_ADDSTRING),

0,

(LPARAM)(LPSTR)lpszBuf

);

SendMessage(

hList,

LB_SETITEMDATA,

nIndex,

(LPARAM)(LPPASTELISTITEMDATA)lpItemData

);

return TRUE;

}

/*

 * FFillPasteList

 *

 * Purpose:

 *  Fills the invisible paste list with the formats offered by the clipboard object and

 *  asked for by the container.

 *

 * Parameters:

 *  hDlg            HWND of the dialog

 *  lpPS             Paste Special Dialog Structure

 *

 * Return Value:

 *  BOOL            TRUE if sucessful and if formats could be found.

 *                  FALSE if unsucessful or if no formats could be found.

 */

BOOL FFillPasteList(HWND hDlg, LPPASTESPECIAL lpPS)

{

LPOLEUIPASTESPECIAL lpOPS = lpPS->lpOPS;

LPMALLOC            pIMalloc     = NULL;

LPSTR               lpszBuf      = (LPSTR)GlobalLock(lpPS->hBuff);

HWND                hList;

int                 i, j;

int                 nItems = 0;

int                 nDefFormat = -1;

BOOL                fTryObjFmt = FALSE;

BOOL                fInsertFirst;

BOOL                fExclude;

HRESULT             hrErr;

hrErr = CoGetMalloc(MEMCTX_TASK, &pIMalloc);

if (hrErr != NOERROR)

goto error;

hList = GetDlgItem(hDlg, ID_PS_PASTELIST);

// Loop over the target's priority list of formats

for (i = 0; i < lpOPS->cPasteEntries; i++)

{

if (lpOPS->arrPasteEntries[i].dwFlags != OLEUIPASTE_PASTEONLY &&

!(lpOPS->arrPasteEntries[i].dwFlags & OLEUIPASTE_PASTE))

continue;

fInsertFirst = FALSE;

if (lpOPS->arrPasteEntries[i].fmtetc.cfFormat==cfFileName

|| lpOPS->arrPasteEntries[i].fmtetc.cfFormat==cfEmbeddedObject

|| lpOPS->arrPasteEntries[i].fmtetc.cfFormat==cfEmbedSource) {

if (! fTryObjFmt) {

fTryObjFmt = TRUE;      // only use 1st object format

fInsertFirst = TRUE;    // OLE obj format should always be 1st

//Check if this CLSID is in the exclusion list.

fExclude=FALSE;

for (j=0; j < (int)lpOPS->cClsidExclude; j++)

{

if (IsEqualCLSID(&lpPS->clsidOD,

 (LPCLSID)(lpOPS->lpClsidExclude+j)))

{

fExclude=TRUE;

break;

}

}

if (fExclude)

continue;   // don't add the object entry to list

} else {

continue;   // already added an object format to list

}

}

// add to list if entry is marked TRUE

if (lpOPS->arrPasteEntries[i].dwScratchSpace) {

if (nDefFormat < 0)

nDefFormat = (fInsertFirst ? 0 : nItems);

else if (fInsertFirst)

nDefFormat++;   // adjust for obj fmt inserted 1st in list

if (!FAddPasteListItem(hList, fInsertFirst, i, lpPS, pIMalloc,

lpszBuf, lpPS->szFullUserTypeNameOD))

goto error;

nItems++;

}

}

// initialize selection to first format matched in list

if (nDefFormat >= 0)

lpPS->nPasteListCurSel = nDefFormat;

// Clean up

if (pIMalloc)

pIMalloc->lpVtbl->Release(pIMalloc);

if (lpszBuf)

   GlobalUnlock(lpPS->hBuff);

// If no items have been added to the list box (none of the formats

//   offered by the source matched those acceptable to the container),

//   return FALSE

if (nItems > 0)

return TRUE;

else

return FALSE;

error:

if (pIMalloc)

pIMalloc->lpVtbl->Release(pIMalloc);

if (lpszBuf)

   GlobalUnlock(lpPS->hBuff);

FreeListData(hList);

return FALSE;

}

/*

 * FFillPasteLinkList

 *

 * Purpose:

 *  Fills the invisible paste link list with the formats offered by the clipboard object and

 *  asked for by the container.

 *

 * Parameters:

 *  hDlg            HWND of the dialog

 *  lpPS             Paste Special Dialog Structure

 *

 * Return Value:

 *  BOOL            TRUE if sucessful and if formats could be found.

 *                  FALSE if unsucessful or if no formats could be found.

 */

BOOL FFillPasteLinkList(HWND hDlg, LPPASTESPECIAL lpPS)

{

LPOLEUIPASTESPECIAL lpOPS        = lpPS->lpOPS;

LPDATAOBJECT        lpSrcDataObj = lpOPS->lpSrcDataObj;

LPENUMFORMATETC     lpEnumFmtEtc = NULL;

LPMALLOC            pIMalloc     = NULL;

LPSTR               lpszBuf      = (LPSTR)GlobalLock(lpPS->hBuff);

OLEUIPASTEFLAG      pasteFlag;

UINT arrLinkTypesSupported[PS_MAXLINKTYPES];  // Array of flags that

  // indicate which link types

  // are supported by source.

FORMATETC           fmtetc;

int                 i, j;

int                 nItems = 0;

BOOL                fLinkTypeSupported = FALSE;

HWND                hList;

int                 nDefFormat = -1;

BOOL                fTryObjFmt = FALSE;

BOOL                fInsertFirst;

HRESULT             hrErr;

hrErr = CoGetMalloc(MEMCTX_TASK, &pIMalloc);

if (hrErr != NOERROR)

goto error;

// Remember which link type formats are offered by lpSrcDataObj.

_fmemset(&fmtetc, 0, sizeof(FORMATETC));

for (i = 0; i < lpOPS->cLinkTypes; i++)

{

if (lpOPS->arrLinkTypes[i] == cfLinkSource) {

OLEDBG_BEGIN2("OleQueryLinkFromData called\r\n")

hrErr = OleQueryLinkFromData(lpSrcDataObj);

OLEDBG_END2

if(NOERROR == hrErr)

{

arrLinkTypesSupported[i] = 1;

fLinkTypeSupported = TRUE;

}

else arrLinkTypesSupported[i] = 0;

}

else {

fmtetc.cfFormat = lpOPS->arrLinkTypes[i];

fmtetc.dwAspect = DVASPECT_CONTENT;

fmtetc.tymed    = 0xFFFFFFFF;       // All tymed values

fmtetc.lindex   = -1;

OLEDBG_BEGIN2("IDataObject::QueryGetData called\r\n")

hrErr = lpSrcDataObj->lpVtbl->QueryGetData(lpSrcDataObj,&fmtetc);

OLEDBG_END2

if(NOERROR == hrErr)

{

arrLinkTypesSupported[i] = 1;

fLinkTypeSupported = TRUE;

}

else arrLinkTypesSupported[i] = 0;

}

}

// No link types are offered by lpSrcDataObj

if (! fLinkTypeSupported) {

nItems = 0;

goto cleanup;

}

hList = GetDlgItem(hDlg, ID_PS_PASTELINKLIST);

// Enumerate the formats acceptable to container

for (i = 0; i < lpOPS->cPasteEntries; i++)

{

fLinkTypeSupported = FALSE;

// If container will accept any link type offered by source object

if (lpOPS->arrPasteEntries[i].dwFlags & OLEUIPASTE_LINKANYTYPE)

fLinkTypeSupported = TRUE;

else

{

// Check if any of the link types offered by the source

//    object are acceptable to the container

// This code depends on the LINKTYPE enum values being powers of 2

for (pasteFlag = OLEUIPASTE_LINKTYPE1, j = 0;

 j < lpOPS->cLinkTypes;

 pasteFlag*=2, j++)

{

if ((lpOPS->arrPasteEntries[i].dwFlags & pasteFlag) &&

arrLinkTypesSupported[j])

{

fLinkTypeSupported = TRUE;

break;

}

}

}

fInsertFirst = FALSE;

if (lpOPS->arrPasteEntries[i].fmtetc.cfFormat==cfFileName

|| lpOPS->arrPasteEntries[i].fmtetc.cfFormat==cfLinkSource) {

if (! fTryObjFmt) {

fTryObjFmt = TRUE;      // only use 1st object format

fInsertFirst = TRUE;    // OLE obj format should always be 1st

} else {

continue;   // already added an object format to list

}

}

// add to list if entry is marked TRUE

if (fLinkTypeSupported && lpOPS->arrPasteEntries[i].dwScratchSpace) {

if (nDefFormat < 0)

nDefFormat = (fInsertFirst ? 0 : nItems);

else if (fInsertFirst)

nDefFormat++;   // adjust for obj fmt inserted 1st in list

if (!FAddPasteListItem(hList, fInsertFirst, i, lpPS, pIMalloc,

lpszBuf, lpPS->szFullUserTypeNameLSD))

goto error;

nItems++;

}

} // end FOR

nItems = (int)SendMessage(hList, LB_GETCOUNT, 0, 0L);

// initialize selection to first format matched in list

if (nDefFormat >= 0)

lpPS->nPasteLinkListCurSel = nDefFormat;

cleanup:

// Clean up

if (pIMalloc)

pIMalloc->lpVtbl->Release(pIMalloc);

if (lpszBuf)

   GlobalUnlock(lpPS->hBuff);

// If no items have been added to the list box (none of the formats

//   offered by the source matched those acceptable to the destination),

//   return FALSE

if (nItems > 0)

return TRUE;

else

return FALSE;

error:

if (pIMalloc)

pIMalloc->lpVtbl->Release(pIMalloc);

if (lpszBuf)

   GlobalUnlock(lpPS->hBuff);

FreeListData(hList);

return FALSE;

}

/*

 * FreeListData

 *

 * Purpose:

 *  Free the local memory associated with each list box item

 *

 * Parameters:

 *  hList           HWND of the list

 *

 * Return Value:

 *  None

 */

void FreeListData(HWND hList)

{

int                nItems, i;

LPPASTELISTITEMDATA lpItemData;

LPMALLOC           pIMalloc;

HRESULT            hrErr;

hrErr = CoGetMalloc(MEMCTX_TASK, &pIMalloc);

if (hrErr != NOERROR)

return;

nItems = (int) SendMessage(hList, LB_GETCOUNT, 0, 0L);

for (i = 0; i < nItems; i++)

{

lpItemData = (LPPASTELISTITEMDATA)SendMessage(hList, LB_GETITEMDATA, (WPARAM)i, 0L);

if ((LRESULT)lpItemData != LB_ERR)

pIMalloc->lpVtbl->Free(pIMalloc, (LPVOID)lpItemData);

}

pIMalloc->lpVtbl->Release(pIMalloc);

}

/*

 * FHasPercentS

 *

 * Purpose:

 *  Determines if string contains %s.

 *

 * Parameters:

 *  lpsz            LPCSTR string in which occurence of '%s' is looked for

 *

 * Return Value:

 *  BOOL            TRUE if %s is found, else FALSE.

 */

BOOL FHasPercentS(LPCSTR lpsz, LPPASTESPECIAL lpPS)

{

   int n = 0;

   LPSTR lpszTmp;

   if (!lpsz) return FALSE;

   // Copy input string to buffer. This allows caller to pass a

   //   code-based string. Code segments may be swapped out in low memory situations

   //   and so code-based strings need to be copied before string elements can be accessed.

   lpszTmp = (LPSTR)GlobalLock(lpPS->hBuff);

   lstrcpy(lpszTmp, lpsz);

   while (*lpszTmp)

   {

   if (*lpszTmp == '%')

   {

   lpszTmp = AnsiNext(lpszTmp);

   if (*lpszTmp == 's')            // If %s, return

   {

   GlobalUnlock(lpPS->hBuff);

   return TRUE;

   }

   else if (*lpszTmp == '%')        // if %%, skip to next character

   lpszTmp = AnsiNext(lpszTmp);

   }

   else lpszTmp = AnsiNext(lpszTmp);

   }

   GlobalUnlock(lpPS->hBuff);

   return FALSE;

}

/*

 * AllocateScratchMem

 *

 * Purpose:

 *  Allocates scratch memory for use by the PasteSpecial dialog. The memory is

 *  is used as the buffer for building up strings using wsprintf. Strings are built up

 *  using the buffer while inserting items into the Paste & PasteLink lists and while

 *  setting the help result text. It must be big  enough to handle the string that results after

 *  replacing the %s in the lpstrFormatName and lpstrResultText in arrPasteEntries[]

 *  by the FullUserTypeName. It must also be big enough to build the dialog's result text

 *  after %s substitutions by the FullUserTypeName or the ApplicationName.

 *

 * Parameters:

 *  lpPS             Paste Special Dialog Structure

 *

 * Return Value:

 *  HGLOBAL         Handle to allocated global memory

 */

HGLOBAL AllocateScratchMem(LPPASTESPECIAL lpPS)

{

LPOLEUIPASTESPECIAL lpOPS = lpPS->lpOPS;

int nLen, i;

int nSubstitutedText = 0;

int nAlloc = 0;

// Get the maximum length of the FullUserTypeNames specified by OBJECTDESCRIPTOR

//   and the LINKSRCDESCRIPTOR and the Application Name. Any of these may be substituted

//   for %s in the result-text/list entries.

if (lpPS->szFullUserTypeNameOD)

nSubstitutedText = lstrlen(lpPS->szFullUserTypeNameOD);

if (lpPS->szFullUserTypeNameLSD)

nSubstitutedText = __max(nSubstitutedText, lstrlen(lpPS->szFullUserTypeNameLSD));

if (lpPS->szAppName)

nSubstitutedText = __max(nSubstitutedText, lstrlen(lpPS->szAppName));

// Get the maximum length of lpstrFormatNames & lpstrResultText in arrPasteEntries

nLen = 0;

for (i = 0; i < lpOPS->cPasteEntries; i++)

{

   nLen = __max(nLen, lstrlen(lpOPS->arrPasteEntries[i].lpstrFormatName));

   nLen = __max(nLen, lstrlen(lpOPS->arrPasteEntries[i].lpstrResultText));

}

// Get the maximum length of lpstrFormatNames and lpstrResultText after %s  has

//   been substituted (At most one %s can appear in each string).

//   Add 1 to hold NULL terminator.

nAlloc = nLen+nSubstitutedText+1;

// Allocate scratch memory to be used to build strings

// nAlloc is big enough to hold any of the lpstrResultText or lpstrFormatName in arrPasteEntries[]

//   after %s substitution.

// We also need space to build up the help result text. 512 is the maximum length of the

//   standard dialog help text before substitutions. 512+nAlloc is the maximum length

//   after %s substition.

// SetPasteSpecialHelpResults() requires 4 such buffers to build up the result text

return GlobalAlloc(GHND, (DWORD)4*(512+nAlloc));

}


 PRECOMP.C  (WRAPUI Sample)

/*

 * PRECOMP.C

 *

 * This file is used to precompile the OLE2UI.H header file

 *

 * Copyright (c)1992 Microsoft Corporation, All Right Reserved

 */

#define STRICT  1

#include "ole2ui.h"

#if defined( _DEBUG ) && !defined( DLL_VER )

// This dummy variable is needed in order for the static link version

// of this library to work correctly.  When we include PRECOMP.OBJ

// in our library (.LIB file), it will only get linked into our

// application IF at least one symbol in precomp.c is referenced from

// either our EXE or LIB.  Therefore, we will define a variable in

// PRECOMP.C and reference it in OLE2UI.C which includes the function

// OleUIInitialize which MUST be called by the static lib user.

int near g_nOleUIStaticLibDummy = 0;

#endif


 REGDB.H  (WRAPUI Sample)

// This file is now OBSOLETE (include olestd.h instead)

/*

 *  Regdb.h

 *

 *    (c) Copyright Microsoft Corp. 1992 All Rights Reserved

 */

// Function prototypes moved to olestd.h


 REGDB.C  (WRAPUI Sample)

/*

 *  REGDB.C

 *

 *  Functions to query the registration database

 *

 *  OleStdGetMiscStatusOfClass

 *  OleStdGetDefaultFileFormatOfClass

 *  OleStdGetAuxUserType

 *  OleStdGetUserTypeOfClass

 *

 *    (c) Copyright Microsoft Corp. 1992-1993 All Rights Reserved

 *

 */

#define STRICT  1

#include "ole2ui.h"

#include "common.h"

#include <ctype.h>

OLEDBGDATA

// Replacement for stdlib atol,

// which didn't work and doesn't take far pointers.

// Must be tolerant of leading spaces.

//

//

static LONG Atol(LPSTR lpsz)

{

signed int sign = +1;

UINT base = 10;

LONG l = 0;

if (NULL==lpsz)

{

OleDbgAssert (0);

return 0;

}

while (isspace(*lpsz))

lpsz++;

if (*lpsz=='-')

{

lpsz++;

sign = -1;

}

if (lpsz[0]=='0' && lpsz[1]=='x')

{

base = 16;

lpsz+=2;

}

if (base==10)

{

while (isdigit(*lpsz))

{

l = l * base + *lpsz - '0';

lpsz++;

}

}

else

{

OleDbgAssert (base==16);

while (isxdigit(*lpsz))

{

l = l * base + isdigit(*lpsz) ? *lpsz - '0' : toupper(*lpsz) - 'A' + 10;

lpsz++;

}

}

return l * sign;

}

/*

 * OleStdGetUserTypeOfClass(REFCLSID, LPSTR, UINT, HKEY)

 *

 * Purpose:

 *  Returns the user type (human readable class name) of the specified class.

 *

 * Parameters:

 *  rclsid          pointer to the clsid to retrieve user type of.

 *  lpszUserType    pointer to buffer to return user type in.

 *  cch             length of buffer pointed to by lpszUserType

 *  hKey            hKey for reg db - if this is NULL, then we

 *                   open and close the reg db within this function.  If it

 *                   is non-NULL, then we assume it's a valid key to the

 *                   \ root and use it without closing it. (useful

 *                   if you're doing lots of reg db stuff).

 *

 * Return Value:

 *  UINT            Number of characters in returned string.  0 on error.

 *

 */

STDAPI_(UINT) OleStdGetUserTypeOfClass(REFCLSID rclsid, LPSTR lpszUserType, UINT cch, HKEY hKey)

{

   LONG     dw;

   LONG     lRet;

   LPSTR    lpszCLSID, lpszProgID;

   BOOL     fFreeProgID = FALSE;

   BOOL     bCloseRegDB = FALSE;

   char     szKey[128];

   LPMALLOC lpIMalloc;

   if (!lpszUserType)

   return 0;

   *lpszUserType = '\0';

   if (hKey == NULL)

   {

 //Open up the root key.

 lRet=RegOpenKey(HKEY_CLASSES_ROOT, NULL, &hKey);

 if ((LONG)ERROR_SUCCESS!=lRet)

   return (UINT)FALSE;

 bCloseRegDB = TRUE;

   }

   // Get a string containing the class name

   StringFromCLSID(rclsid, &lpszCLSID);

   wsprintf(szKey, "CLSID\\%s", lpszCLSID);

   dw=cch;

   lRet = RegQueryValue(hKey, szKey, lpszUserType, &dw);

   if ((LONG)ERROR_SUCCESS!=lRet) {

   // Load 'Unknown Source' and 'Unknown Type' strings

   dw = (LONG)LoadString(ghInst, (UINT)IDS_PSUNKNOWNTYPE, lpszUserType, cch);

   }

   if ( ((LONG)ERROR_SUCCESS!=lRet) && (CoIsOle1Class(rclsid)) )

   {

  // We've got an OLE 1.0 class, so let's try to get the user type

  // name from the ProgID entry.

  ProgIDFromCLSID(rclsid, &lpszProgID);

  fFreeProgID = TRUE;

  dw = cch;

  lRet = RegQueryValue(hKey, lpszProgID, lpszUserType, &dw);

  if ((LONG)ERROR_SUCCESS != lRet)

dw = 0;

   }

   if (NOERROR == CoGetMalloc(MEMCTX_TASK, &lpIMalloc))

   {

   if (fFreeProgID)

 lpIMalloc->lpVtbl->Free(lpIMalloc, (LPVOID)lpszProgID);

   lpIMalloc->lpVtbl->Free(lpIMalloc, (LPVOID)lpszCLSID);

   lpIMalloc->lpVtbl->Release(lpIMalloc);

   }

   if (bCloseRegDB)

  RegCloseKey(hKey);

   return (UINT)dw;

}

/*

 * OleStdGetAuxUserType(RCLSID, WORD, LPSTR, int, HKEY)

 *

 * Purpose:

 *  Returns the specified AuxUserType from the reg db.

 *

 * Parameters:

 *  rclsid          pointer to the clsid to retrieve aux user type of.

 *  hKey            hKey for reg db - if this is NULL, then we

 *                   open and close the reg db within this function.  If it

 *                   is non-NULL, then we assume it's a valid key to the

 *                   \ root and use it without closing it. (useful

 *                   if you're doing lots of reg db stuff).

 *  wAuxUserType    which aux user type field to look for.  In 4/93 release

 *                  2 is short name and 3 is exe name.

 *  lpszUserType    pointer to buffer to return user type in.

 *  cch             length of buffer pointed to by lpszUserType

 *

 * Return Value:

 *  UINT            Number of characters in returned string.  0 on error.

 *

 */

STDAPI_(UINT) OleStdGetAuxUserType(REFCLSID rclsid,

   UINT     wAuxUserType,

   LPSTR    lpszAuxUserType,

   int      cch,

   HKEY     hKey)

{

   HKEY     hThisKey;

   BOOL     fCloseRegDB = FALSE;

   LONG     dw;

   LRESULT  lRet;

   LPSTR    lpszCLSID;

   LPMALLOC lpIMalloc;

   char     szKey[OLEUI_CCHKEYMAX];

   char     szTemp[32];

   lpszAuxUserType[0] = '\0';

   if (NULL == hKey)

   {

  lRet = RegOpenKey(HKEY_CLASSES_ROOT, NULL, &hThisKey);

  if (ERROR_SUCCESS != lRet)

  return 0;

   }

   else

  hThisKey = hKey;

   StringFromCLSID(rclsid, &lpszCLSID);

   lstrcpy(szKey, "CLSID\\");

   lstrcat(szKey, lpszCLSID);

   wsprintf(szTemp, "\\AuxUserType\\%d", wAuxUserType);

   lstrcat(szKey, szTemp);

   dw = cch;

   lRet = RegQueryValue(hThisKey, szKey, lpszAuxUserType, &dw);

   if (ERROR_SUCCESS != lRet) {

 dw = 0;

 lpszAuxUserType[0] = '\0';

   }

   if (fCloseRegDB)

  RegCloseKey(hThisKey);

   if (NOERROR == CoGetMalloc(MEMCTX_TASK, &lpIMalloc))

   {

   lpIMalloc->lpVtbl->Free(lpIMalloc, (LPVOID)lpszCLSID);

   lpIMalloc->lpVtbl->Release(lpIMalloc);

   }

   return (UINT)dw;

}

/*

 * OleStdGetMiscStatusOfClass(REFCLSID, HKEY)

 *

 * Purpose:

 *  Returns the value of the misc status for the given clsid.

 *

 * Parameters:

 *  rclsid          pointer to the clsid to retrieve user type of.

 *  hKey            hKey for reg db - if this is NULL, then we

 *                   open and close the reg db within this function.  If it

 *                   is non-NULL, then we assume it's a valid key to the

 *                   \\CLSID root and use it without closing it. (useful

 *                   if you're doing lots of reg db stuff).

 *

 * Return Value:

 *  BOOL            TRUE on success, FALSE on failure.

 *

 */

STDAPI_(BOOL) OleStdGetMiscStatusOfClass(REFCLSID rclsid, HKEY hKey, DWORD FAR * lpdwValue)

{

   DWORD dw;

   LONG  lRet;

   LPSTR lpszCLSID;

   char  szKey[64];

   char  szMiscStatus[OLEUI_CCHKEYMAX];

   BOOL  bCloseRegDB = FALSE;

   if (hKey == NULL)

   {

 //Open up the root key.

 lRet=RegOpenKey(HKEY_CLASSES_ROOT, "CLSID", &hKey);

 if ((LONG)ERROR_SUCCESS!=lRet)

   return FALSE;

 bCloseRegDB = TRUE;

   }

   // Get a string containing the class name

   StringFromCLSID(rclsid, &lpszCLSID);

   // Construct key

   lstrcpy(szKey, lpszCLSID);

   lstrcat(szKey, "\\MiscStatus");

   dw=OLEUI_CCHKEYMAX;

   lRet = RegQueryValue(hKey, szKey, (LPSTR)szMiscStatus, &dw);

   if ((LONG)ERROR_SUCCESS!=lRet)

   {

   OleStdFreeString(lpszCLSID, NULL);

   if (bCloseRegDB)

  RegCloseKey(hKey);

   return FALSE;

   }

   *lpdwValue = Atol((LPSTR)szMiscStatus);

   OleStdFreeString(lpszCLSID, NULL);

   if (bCloseRegDB)

  RegCloseKey(hKey);

   return TRUE;

}

/*

 * CLIPFORMAT OleStdGetDefaultFileFormatOfClass(REFCLSID, HKEY)

 *

 * Purpose:

 *  Returns the default file format of the specified class.

 *  this is entered in REGDB as follows:

 *      CLSID\{...}\DataFormats\DefaultFile = <cfFmt>

 *

 * Parameters:

 *  rclsid          pointer to the clsid to retrieve user type of.

 *  hKey            hKey for reg db- if this is NULL, then we

 *                   open and close the reg db within this function.  If it

 *                   is non-NULL, then we assume it's a valid key to the

 *                   \ root and use it without closing it. (useful

 *                   if you're doing lots of reg db stuff).

 *

 * Return Value:

 *  cfFmt   -- DefaultFile format

 *  NULL    -- failed to get default file format

 *

 */

STDAPI_(CLIPFORMAT) OleStdGetDefaultFileFormatOfClass(

REFCLSID        rclsid,

HKEY            hKey

)

{

   CLIPFORMAT cfFmt = 0;

   DWORD dw;

   LONG  lRet;

   LPSTR lpszCLSID;

   BOOL  bCloseRegDB = FALSE;

   char  szKey[128];

   char  szDefaultFile[OLEUI_CCHKEYMAX];

   BOOL  bStatus = TRUE;

   if (hKey == NULL)

   {

 //Open up the root key.

 lRet=RegOpenKey(HKEY_CLASSES_ROOT, NULL, &hKey);

 if ((LONG)ERROR_SUCCESS!=lRet)

   return 0;

 bCloseRegDB = TRUE;

   }

   // Get a string containing the class name

   StringFromCLSID(rclsid, &lpszCLSID);

   // Construct key

   wsprintf(szKey, "CLSID\\%s\\DataFormats\\DefaultFile", lpszCLSID);

   OleStdFreeString(lpszCLSID, NULL);

   dw=OLEUI_CCHKEYMAX;

   lRet = RegQueryValue(hKey, szKey, (LPSTR)szDefaultFile, (LONG FAR *)&dw);

   if ((LONG)ERROR_SUCCESS!=lRet)

   bStatus = FALSE;

   else {

   /* if the format is a number, then it should refer to one of the

   **    standard Windows formats.

   */

   if (isdigit(szDefaultFile[0]))

   cfFmt = (CLIPFORMAT)Atol(szDefaultFile);

   else

   cfFmt = RegisterClipboardFormat(szDefaultFile);

   }

   if (bCloseRegDB)

  RegCloseKey(hKey);

   return cfFmt;

}


 RESIMAGE.H  (WRAPUI Sample)

/*

 * RESIMAGE.H

 *

 * Structures and definitions for the ResultImage control.

 *

 * Copyright (c)1992 Microsoft Corporation, All Right Reserved

 */

#ifndef _RESIMAGE_H_

#define _RESIMAGE_H_

/*

 * Indices into the bitmaps to extract the right image.  Each bitmap

 * contains five images arranged vertically, so the offset to the correct

 * image is (iImage*cy)

 */

#define RESULTIMAGE_NONE                0xFFFF

#define RESULTIMAGE_PASTE               0

#define RESULTIMAGE_EMBED               1

#define RESULTIMAGE_EMBEDICON           2

#define RESULTIMAGE_LINK                3

#define RESULTIMAGE_LINKICON            4

#define RESULTIMAGE_LINKTOLINK          5

#define RESULTIMAGE_LINKTOLINKICON      6

#define RESULTIMAGE_MIN                 0

#define RESULTIMAGE_MAX                 6

//Total number of images in each bitmap.

#define CIMAGESY                        (RESULTIMAGE_MAX+1)

//The color to use for transparancy (cyan)

#define RGBTRANSPARENT                  RGB(0, 255, 255)

//Function prototypes

BOOL            FResultImageInitialize(HINSTANCE, HINSTANCE, LPSTR);

void            ResultImageUninitialize(void);

LONG CALLBACK EXPORT ResultImageWndProc(HWND, UINT, WPARAM, LPARAM);

void            TransparentBlt(HDC, UINT, UINT, HBITMAP, UINT, UINT, UINT, UINT, COLORREF);

//Window extra bytes contain the bitmap index we deal with currently.

#define CBRESULTIMAGEWNDEXTRA          sizeof(UINT)

#define RIWW_IMAGEINDEX                0

//Control messages

#define RIM_IMAGESET                   (WM_USER+0)

#define RIM_IMAGEGET                   (WM_USER+1)

//Special ROP code for TransparentBlt.

#define ROP_DSPDxax  0x00E20746

#endif //_RESIMAGE_H_


 RESIMAGE.C  (WRAPUI Sample)

/*

 * RESIMAGE.C

 *

 * Implementation of the Results Image control for OLE 2.0 UI dialogs.

 * We need a separate control for dialogs in order to control the repaints

 * properly and to provide a clean message interface for the dialog

 * implementations.

 *

 * Copyright (c)1992 Microsoft Corporation, All Right Reserved

 */

#define STRICT  1

#include "ole2ui.h"

#include "resimage.h"

OLEDBGDATA

//Flag indicating if we've registered the class

static BOOL     fRegistered=FALSE;

//Bitmap and image dimensions for result images.

static HBITMAP  hBmpResults=NULL;

static UINT     cxBmpResult=0;

static UINT     cyBmpResult=0;

/*

 * FResultImageInitialize

 *

 * Purpose:

 *  Attempts to load result bitmaps for the current display driver

 *  for use in OLE 2.0 UI dialogs.  Also registers the ResultImage

 *  control class.

 *

 * Parameters:

 *  hInst           HINSTANCE instance of the DLL.

 *

 *  hPrevInst       HINSTANCE of the previous instance.  Used to

 *                  determine whether to register window classes or not.

 *

 *  lpszClassName   LPSTR containing the class name to register the

 *                  ResultImage control class with.

 *

 * Return Value:

 *  BOOL            TRUE if all initialization succeeded, FALSE otherwise.

 */

BOOL FResultImageInitialize(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpszClassName)

{

int         cx, iBmp;

HDC         hDC;

BITMAP      bm;

WNDCLASS        wc;

/*

 * Determine the aspect ratio of the display we're currently

 * running on and load the appropriate bitmap into the global

 * hBmpResults (used from the ResultImage control only).

 *

 * By retrieving the logical Y extent of the display driver, you

 * only have limited possibilities:

 *      LOGPIXELSY      Display

 *      ----------------------------------------

 *         48             CGA    (unsupported)

 *         72             EGA

 *         96             VGA

 *        120             8514/a (i.e. HiRes VGA)

 */

hDC=GetDC(NULL);

if (NULL==hDC)

return FALSE;

cx=GetDeviceCaps(hDC, LOGPIXELSY);

ReleaseDC(NULL, hDC);

/*

 * Instead of single comparisons, check ranges instead, so in case

 * we get something funky, we'll act reasonable.

 */

if (72 >=cx)             iBmp=(UINT)IDB_RESULTSEGA;

if (72 < cx && 120 > cx) iBmp=(UINT)IDB_RESULTSVGA;

if (120 <=cx)            iBmp=(UINT)IDB_RESULTSHIRESVGA;

hBmpResults=LoadBitmap(hInst, MAKEINTRESOURCE(iBmp));

if (NULL==hBmpResults)

{

//On error, fail loading the DLL

OleDbgOut1("FResultImageInitialize:  Failed LoadBitmap.\r\n");

return FALSE;

}

OleDbgOut4("FResultImageInitialize:  Loaded hBmpResults\r\n");

//Now that we have the bitmap, calculate image dimensions

GetObject(hBmpResults, sizeof(BITMAP), &bm);

cxBmpResult=bm.bmWidth;

cyBmpResult=bm.bmHeight/CIMAGESY;

// Only register class if we're the first instance

if (hPrevInst)

fRegistered = TRUE;

else

{

// Static flag fRegistered guards against calling this function more

// than once in the same instance

/* NOTE: the custom control classes for the ICONBOX class and the

**    RESULTIMAGE class are registered as task specific. this

**    is done both if the OLE2UI library is built as a static

**    library or as a DLL. these custom controls are

**    constructed internally as part of the OLE2UI code and do

**    NOT need to be registered as global classes.

*/

if (!fRegistered)

{

wc.lpfnWndProc   =ResultImageWndProc;

wc.cbClsExtra    =0;

wc.cbWndExtra    =CBRESULTIMAGEWNDEXTRA;

wc.hInstance     =hInst;

wc.hIcon         =NULL;

wc.hCursor       =LoadCursor(NULL, IDC_ARROW);

wc.hbrBackground =NULL;

wc.lpszMenuName  =NULL;

wc.lpszClassName =lpszClassName;

wc.style         = CS_VREDRAW | CS_HREDRAW;

fRegistered = RegisterClass(&wc);

}

}

return fRegistered;

}

/*

 * ResultImageUninitialize

 *

 * Purpose:

 *  Cleans up anything done in FResultImageInitialize, such as freeing

 *  the bitmaps.  Call from WEP.

 *

 * Parameters:

 *  None

 *

 * Return Value:

 *  None

 */

void ResultImageUninitialize(void)

{

if (NULL!=hBmpResults)

{

DeleteObject(hBmpResults);

}

return;

}

/*

 * ResultImageWndProc

 *

 * Purpose:

 *  Window Procedure for the ResultImage custom control.  Only handles

 *  WM_CREATE, WM_PAINT, and private messages to manipulate the bitmap.

 *

 * Parameters:

 *  Standard

 *

 * Return Value:

 *  Standard

 */

LONG CALLBACK EXPORT ResultImageWndProc(HWND hWnd, UINT iMsg

, WPARAM wParam, LPARAM lParam)

{

UINT            iBmp;

PAINTSTRUCT     ps;

HDC             hDC;

//Handle standard Windows messages.

switch (iMsg)

{

case WM_CREATE:

SetWindowWord(hWnd, RIWW_IMAGEINDEX, RESULTIMAGE_NONE);

return 0L;

case WM_PAINT:

{

RECT            rc;

UINT            x, y;

HDC             hDCDlg;

HBRUSH          hBr;

LOGBRUSH        lb;

HWND            hDlg;

iBmp=GetWindowWord(hWnd, RIWW_IMAGEINDEX);

hDC=BeginPaint(hWnd, &ps);

/*

 * Our job before using TransparentBlt is to figure out

 * where to position the result image.  We place it centered

 * on this control, so get our rect's center and subtract

 * half of the image dimensions.

 */

GetClientRect(hWnd, &rc);

x=(rc.right+rc.left-cxBmpResult)/2;

y=(rc.bottom+rc.top-cyBmpResult)/2;

//Get the backgroup color the dialog is using.

hDlg=GetParent(hWnd);

hDCDlg=GetDC(hDlg);

#if defined( WIN32 )

hBr = (HBRUSH)SendMessage(hDlg,

WM_CTLCOLORDLG,

(WPARAM)hDCDlg,

(LPARAM)hDlg);

#else

hBr = (HBRUSH)SendMessage(hDlg,

WM_CTLCOLOR,

(WPARAM)hDCDlg,

MAKELPARAM(hDlg, CTLCOLOR_DLG));

#endif

ReleaseDC(hDlg, hDCDlg);

GetObject(hBr, sizeof(LOGBRUSH), &lb);

SetBkColor(hDC, lb.lbColor);

// Paint the image

if (RESULTIMAGE_NONE!=iBmp)

TransparentBlt(hDC, x, y, hBmpResults, 0, iBmp*cyBmpResult

   , cxBmpResult, cyBmpResult, RGBTRANSPARENT);

// Or, erase the rectangle if no image is to be displayed

else

{

RECT    rc;

rc.top  = y;

rc.left = x;

rc.bottom = y + cyBmpResult;

rc.right  = x + cxBmpResult;

FillRect(hDC, &rc, hBr);

}

EndPaint(hWnd, &ps);

}

break;

case RIM_IMAGESET:

//wParam contains the new index.

iBmp=GetWindowWord(hWnd, RIWW_IMAGEINDEX);

//Validate the index before changing it and repainting

if (RESULTIMAGE_NONE==wParam ||

((RESULTIMAGE_MIN <= wParam) && (RESULTIMAGE_MAX >= wParam)))

{

SetWindowWord(hWnd, RIWW_IMAGEINDEX, (WORD)wParam);

InvalidateRect(hWnd, NULL, FALSE);

UpdateWindow(hWnd);

}

//Return the previous index.

return iBmp;

case RIM_IMAGEGET:

//Return the current index.

iBmp=GetWindowWord(hWnd, RIWW_IMAGEINDEX);

return (LONG)iBmp;

default:

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

}

return 0L;

}

/*

 * TransparentBlt

 *

 * Purpose:

 *  Given a DC, a bitmap, and a color to assume as transparent in that

 *  bitmap, BitBlts the bitmap to the DC letting the existing background

 *  show in place of the transparent color.

 *

 * Parameters:

 *  hDC             HDC on which to draw.

 *  x, y            UINT location at which to draw the bitmap

 *  hBmp            HBITMIP to draw from

 *  xOrg, yOrg      UINT coordinates from which to draw the bitamp

 *  cx, cy          UINT dimensions of the bitmap to Blt.

 *  cr              COLORREF to consider as transparent.

 *

 * Return Value:

 *  None

 */

void TransparentBlt(HDC hDC, UINT x, UINT y, HBITMAP hBmp, UINT xOrg, UINT yOrg

, UINT cx, UINT cy, COLORREF cr)

{

HDC         hDCSrc, hDCMid, hMemDC;

HBITMAP     hBmpMono, hBmpT;

HBRUSH      hBr, hBrT;

COLORREF    crBack, crText;

if (NULL==hBmp)

return;

//Get three intermediate DC's

hDCSrc=CreateCompatibleDC(hDC);

hDCMid=CreateCompatibleDC(hDC);

hMemDC=CreateCompatibleDC(hDC);

SelectObject(hDCSrc, hBmp);

//Create a monochrome bitmap for masking

hBmpMono=CreateCompatibleBitmap(hDCMid, cx, cy);

SelectObject(hDCMid, hBmpMono);

//Create a middle bitmap

hBmpT=CreateCompatibleBitmap(hDC, cx, cy);

SelectObject(hMemDC, hBmpT);

//Create a monochrome mask where we have 0's in the image, 1's elsewhere.

crBack=SetBkColor(hDCSrc, cr);

BitBlt(hDCMid, 0, 0, cx, cy, hDCSrc, xOrg, yOrg, SRCCOPY);

SetBkColor(hDCSrc, crBack);

//Put the unmodified image in the temporary bitmap

BitBlt(hMemDC, 0, 0, cx, cy, hDCSrc, xOrg, yOrg, SRCCOPY);

//Create an select a brush of the background color

hBr=CreateSolidBrush(GetBkColor(hDC));

hBrT=SelectObject(hMemDC, hBr);

//Force conversion of the monochrome to stay black and white.

crText=SetTextColor(hMemDC, 0L);

crBack=SetBkColor(hMemDC, RGB(255, 255, 255));

/*

 * Where the monochrome mask is 1, Blt the brush; where the mono mask

 * is 0, leave the destination untouches.  This results in painting

 * around the image with the background brush.  We do this first

 * in the temporary bitmap, then put the whole thing to the screen.

 */

BitBlt(hMemDC, 0, 0, cx, cy, hDCMid, 0, 0, ROP_DSPDxax);

BitBlt(hDC,    x, y, cx, cy, hMemDC, 0, 0, SRCCOPY);

SetTextColor(hMemDC, crText);

SetBkColor(hMemDC, crBack);

SelectObject(hMemDC, hBrT);

DeleteObject(hBr);

DeleteDC(hMemDC);

DeleteDC(hDCSrc);

DeleteDC(hDCMid);

DeleteObject(hBmpT);

DeleteObject(hBmpMono);

return;

}


 STDPAL.H  (WRAPUI Sample)

/*-----------------------------------------------------------------------

|   stdpal.h

|

|   Standard App Palette useful for OLE applications.  v 1.01

|

|   #include this file in the same file as HpalCreateAppPalette

|

|   NOTE:  Palette MUST be created with HpalCreateAppPalette

|

|   Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.

|

-----------------------------------------------------------------------*/

#ifndef CSCONST

#if (defined(FLAT) || defined(__TURBOC__))

#define CSCONST(type) type const

#else

#define CSCONST(type) type _based(_segname("_CODE")) const

#endif

#endif

CSCONST(unsigned char) palSVGA[256][3] =

{

// R     G     B

{0x00, 0x00, 0x00}, // 0 Sys Black  gray 0

{0x80, 0x00, 0x00}, // 1 Sys Dk Red

{0x00, 0x80, 0x00}, // 2 Sys Dk Green

{0x80, 0x80, 0x00}, // 3 Sys Dk Yellow

{0x00, 0x00, 0x80}, // 4 Sys Dk Blue

{0x80, 0x00, 0x80}, // 5 Sys Dk Violet

{0x00, 0x80, 0x80}, // 6 Sys Dk Cyan

{0xc0, 0xc0, 0xc0}, // 7 Sys Lt Grey    gray 192

{0xc0, 0xdc, 0xc0}, // 8 Sys 8

{0xa6, 0xca, 0xf0}, // 9 Sys 9 (the first 10 are fixed by Windows)

{0x80, 0x00, 0x00}, // 10 Sys Dk Red repeat

{0x00, 0x80, 0x00}, // 11 Sys Dk Green repeat

{0x80, 0x80, 0x00}, // 12 Sys Dk Yellow repeat

{0x00, 0x00, 0x80}, // 13 Sys Dk Blue repeat

{0x80, 0x00, 0x80}, // 14 Sys Dk Violet repeat

{0x00, 0x80, 0x80}, // 15 Sys Dk Cyan repeat

{0x80, 0x80, 0x80}, // 16 Sys Dk Grey repeat    gray 128

{0x80, 0x80, 0xff}, // 17 Excel Chart Fill 1

{0x80, 0x20, 0x60}, // 18 Excel Chart Fill 2

{0xff, 0xff, 0xc0}, // 19 Excel Chart Fill 3

{0xa0, 0xe0, 0xe0}, // 20 Excel Chart Fill 4

{0x60, 0x00, 0x80}, // 21 Excel Chart Fill 4

{0xff, 0x80, 0x80}, // 22 Excel Chart Fill 6

{0x00, 0x80, 0xc0}, // 23 Excel Chart Fill 7

{0xc0, 0xc0, 0xff}, // 24 Excel Chart Fill 8

{0x00, 0xcf, 0xff}, // 25 Excel clrt entry

{0x69, 0xff, 0xff}, // 26 Excel clrt entry

{0xe0, 0xff, 0xe0}, // 27 Excel clrt entry

{0xdd, 0x9c, 0xb3}, // 28 Excel clrt entry

{0xb3, 0x8f, 0xee}, // 29 Excel clrt entry

{0x2a, 0x6f, 0xf9}, // 30 Excel clrt entry

{0x3f, 0xb8, 0xcd}, // 31 Excel clrt entry

{0x48, 0x84, 0x36}, // 32 Excel clrt entry

{0x95, 0x8c, 0x41}, // 33 Excel clrt entry

{0x8e, 0x5e, 0x42}, // 34 Excel clrt entry

{0xa0, 0x62, 0x7a}, // 35 Excel clrt entry

{0x62, 0x4f, 0xac}, // 36 Excel clrt entry

{0x1d, 0x2f, 0xbe}, // 37 Excel clrt entry

{0x28, 0x66, 0x76}, // 38 Excel clrt entry

{0x00, 0x45, 0x00}, // 39 Excel clrt entry

{0x45, 0x3e, 0x01}, // 40 Excel clrt entry

{0x6a, 0x28, 0x13}, // 41 Excel clrt entry

{0x85, 0x39, 0x6a}, // 42 Excel clrt entry

{0x4a, 0x32, 0x85}, // 43 Excel clrt entry

{0x04, 0x04, 0x04}, // 44   gray 4

{0x08, 0x08, 0x08}, // 45   gray 8

{0x0c, 0x0c, 0x0c}, // 46   gray 12

{0x11, 0x11, 0x11}, // 47   gray 17

{0x16, 0x16, 0x16}, // 48   gray 22

{0x1c, 0x1c, 0x1c}, // 49   gray 28

{0x22, 0x22, 0x22}, // 50   gray 34

{0x29, 0x29, 0x29}, // 51   gray 41

{0x30, 0x30, 0x30}, // 52   gray 48

{0x5f, 0x5f, 0x5f}, // 53 swapped so inversions look good   gray 95

{0x55, 0x55, 0x55}, // 54 swapped so inversions look good   gray 85

{0x4d, 0x4d, 0x4d}, // 55 swapped so inversions look good   gray 77

{0x42, 0x42, 0x42}, // 56 swapped so inversions look good   gray 66

{0x39, 0x39, 0x39}, // 57 swapped so inversions look good   gray 57

{0x00, 0x07, 0x00}, // 58

{0x0d, 0x00, 0x00}, // 59

{0xb7, 0x99, 0x81}, // 60

{0x84, 0x99, 0xb4}, // 61

{0xbd, 0xbd, 0x90}, // 62

{0x7f, 0x7f, 0x60}, // 63

{0x60, 0x60, 0x7f}, // 64

{0x00, 0x0e, 0x00}, // 65

{0x1b, 0x00, 0x00}, // 66

{0x28, 0x00, 0x00}, // 67

{0x08, 0x09, 0x2b}, // 68

{0x00, 0x1d, 0x00}, // 69

{0x39, 0x00, 0x00}, // 70

{0x00, 0x00, 0x9b}, // 71

{0x00, 0x25, 0x00}, // 72

{0x49, 0x00, 0x00}, // 73

{0x11, 0x11, 0x3b}, // 74

{0x00, 0x2f, 0x00}, // 75

{0x5d, 0x00, 0x00}, // 76

{0x17, 0x17, 0x45}, // 77

{0x00, 0x3a, 0x00}, // 78

{0x49, 0x11, 0x11}, // 79

{0x1c, 0x1c, 0x53}, // 80

{0x00, 0x16, 0xff}, // 81

{0x2b, 0x00, 0xff}, // 82

{0x21, 0x21, 0x6c}, // 83

{0x59, 0x14, 0x14}, // 84

{0x00, 0x51, 0x00}, // 85

{0x47, 0x1a, 0x6a}, // 86

{0x19, 0x32, 0x67}, // 87

{0x00, 0x61, 0x00}, // 88

{0x00, 0x31, 0xff}, // 89

{0x61, 0x00, 0xff}, // 90

{0x53, 0x20, 0x7b}, // 91

{0x16, 0x43, 0x67}, // 92

{0x2e, 0x2e, 0xe2}, // 93

{0x26, 0x59, 0x16}, // 94

{0x51, 0x46, 0x04}, // 95

{0x68, 0x2e, 0x49}, // 96

{0x07, 0x52, 0x8f}, // 97

{0x6a, 0x18, 0xb8}, // 98

{0x90, 0x23, 0x15}, // 99

{0x00, 0x53, 0xff}, // 100

{0xa3, 0x00, 0xff}, // 101

{0x6a, 0x4a, 0x12}, // 102

{0x75, 0x33, 0x6c}, // 103

{0x4a, 0x41, 0x9a}, // 104

{0x37, 0x65, 0x0b}, // 105

{0xa4, 0x2c, 0x15}, // 106

{0x83, 0x1f, 0xb1}, // 107

{0x4e, 0x2c, 0xff}, // 108

{0x20, 0x51, 0xb6}, // 109

{0x08, 0x64, 0x92}, // 110

{0x6f, 0x56, 0x0b}, // 111

{0x59, 0x43, 0xad}, // 112

{0x36, 0x72, 0x12}, // 113

{0xb0, 0x33, 0x17}, // 114

{0x00, 0xa1, 0x00}, // 115

{0x77, 0x5f, 0x1f}, // 116

{0x89, 0x47, 0x71}, // 117

{0xb0, 0x43, 0x1c}, // 118

{0xb7, 0x2d, 0x7d}, // 119

{0x00, 0x86, 0x95}, // 120

{0x7a, 0x6e, 0x23}, // 121

{0x26, 0x9f, 0x00}, // 122

{0x73, 0xa9, 0x01}, // 123

{0x00, 0x00, 0x00}, // 124 free 0   gray 0

{0x00, 0x00, 0x00}, // 125 free 2   gray 0

{0x00, 0x00, 0x00}, // 126 free 4   gray 0

{0x00, 0x00, 0x00}, // 127 free 6   gray 0

{0x00, 0x00, 0x00}, // 128 free 7   gray 0

{0x00, 0x00, 0x00}, // 129 free 5   gray 0

{0x00, 0x00, 0x00}, // 130 free 3   gray 0

{0x00, 0x00, 0x00}, // 131 free 1   gray 0

{0x00, 0xca, 0x00}, // 132

{0xac, 0x5b, 0x01}, // 133

{0x20, 0x1d, 0xc2}, // 134

{0x94, 0x52, 0x70}, // 135

{0x24, 0xaa, 0x4c}, // 136

{0x0a, 0x94, 0x89}, // 137

{0x36, 0x6e, 0x7b}, // 138

{0x44, 0x75, 0x90}, // 139

{0xff, 0x00, 0xa8}, // 140

{0x00, 0x71, 0xff}, // 141

{0xdf, 0x00, 0xff}, // 142

{0x56, 0x91, 0x4a}, // 143

{0x34, 0x48, 0xf8}, // 144

{0xcc, 0x32, 0x82}, // 145

{0xe4, 0x41, 0x70}, // 146

{0x68, 0xca, 0x01}, // 147

{0x36, 0xbc, 0x42}, // 148

{0x00, 0x9a, 0xff}, // 149

{0x96, 0x22, 0xb7}, // 150

{0x85, 0x7d, 0x33}, // 151

{0x25, 0xb7, 0x8c}, // 152

{0x36, 0x5a, 0xed}, // 153

{0x5c, 0xff, 0x00}, // 154

{0xff, 0x48, 0x00}, // 155

{0x22, 0x9b, 0xa2}, // 156

{0x42, 0xcf, 0x4d}, // 157

{0xc2, 0x58, 0x52}, // 158

{0x20, 0xd3, 0x95}, // 159

{0xa5, 0x24, 0xe0}, // 160

{0x73, 0x56, 0xb5}, // 161

{0xa9, 0xa9, 0x00}, // 162

{0xd0, 0x6f, 0x3c}, // 163

{0x67, 0x9f, 0x58}, // 164

{0x89, 0xcf, 0x0b}, // 165

{0xff, 0xac, 0x00}, // 166

{0xa7, 0x2e, 0xfe}, // 167

{0xe2, 0x59, 0x7f}, // 168

{0x4c, 0xdc, 0x67}, // 169

{0xff, 0x18, 0xff}, // 170

{0x3a, 0x7d, 0xff}, // 171

{0xb1, 0xd0, 0x18}, // 172

{0xc7, 0xff, 0x00}, // 173

{0xff, 0xe2, 0x00}, // 174

{0xdf, 0x9a, 0x3d}, // 175

{0x56, 0x81, 0x9f}, // 176

{0xc6, 0x43, 0xba}, // 177

{0xaf, 0x71, 0x8b}, // 178

{0x38, 0xa2, 0xc9}, // 179

{0xd1, 0x53, 0xce}, // 180

{0xff, 0x9a, 0x65}, // 181

{0x46, 0xca, 0xdb}, // 182

{0xff, 0x4d, 0xff}, // 183

{0xc8, 0xe9, 0x6a}, // 184

{0x4c, 0xde, 0xe0}, // 185

{0xff, 0x98, 0xff}, // 186

{0xdf, 0xc0, 0x82}, // 187

{0xe9, 0xec, 0xa5}, // 188

{0xf5, 0xf6, 0xcd}, // 189

{0xff, 0xd0, 0xff}, // 190

{0xb1, 0xac, 0x5a}, // 191

{0x63, 0x91, 0xae}, // 192

{0x22, 0x4c, 0x65}, // 193

{0x8d, 0x4e, 0x3f}, // 194

{0x50, 0x70, 0x70}, // 195

{0xd0, 0xff, 0xff}, // 196

{0xff, 0xe7, 0xff}, // 197

{0x69, 0x69, 0x69}, // 198  gray 105

{0x77, 0x77, 0x77}, // 199  gray 119

{0x86, 0x86, 0x86}, // 200  gray 134

{0x96, 0x96, 0x96}, // 201  gray 150

{0x9d, 0x9d, 0x9d}, // 202  gray 157

{0xa4, 0xa4, 0xa4}, // 203  gray 164

{0xb2, 0xb2, 0xb2}, // 204  gray 178

{0xcb, 0xcb, 0xcb}, // 205  gray 203

{0xd7, 0xd7, 0xd7}, // 206  gray 215

{0xdd, 0xdd, 0xdd}, // 207  gray 221

{0xe3, 0xe3, 0xe3}, // 208  gray 227

{0xea, 0xea, 0xea}, // 209  gray 234

{0xf1, 0xf1, 0xf1}, // 210  gray 241

{0xf8, 0xf8, 0xf8}, // 211  gray 248

{0xb2, 0xc1, 0x66}, // 212

{0x80, 0xbf, 0x78}, // 213

{0xc6, 0xf0, 0xf0}, // 214

{0xb2, 0xa4, 0xff}, // 215

{0xff, 0xb3, 0xff}, // 216

{0xd1, 0x8e, 0xa3}, // 217

{0xc3, 0xdc, 0x37}, // 218

{0xa0, 0x9e, 0x54}, // 219

{0x76, 0xae, 0x70}, // 220

{0x78, 0x9e, 0xc1}, // 221

{0x83, 0x64, 0xbf}, // 222

{0xa4, 0x83, 0xd3}, // 223

{0xd1, 0x3f, 0x32}, // 224

{0xff, 0x7d, 0x00}, // 225

{0x44, 0x78, 0x23}, // 226

{0x24, 0x5f, 0x60}, // 227

{0x0e, 0x0e, 0x2c}, // 228

{0xbe, 0x00, 0x00}, // 229

{0xff, 0x1f, 0x00}, // 230

{0x31, 0x39, 0x00}, // 231

{0xd9, 0x85, 0x3e}, // 232

{0x02, 0x77, 0x85}, // 233

{0xb0, 0xd8, 0x81}, // 234

{0x56, 0x21, 0x1d}, // 235

{0x00, 0x00, 0x30}, // 236

{0x88, 0xc8, 0xb3}, // 237

{0xa0, 0x79, 0x00}, // 238

{0xc0, 0xc0, 0xc0}, // 239 Sys Dk Grey repeat inversion gray 192

{0xea, 0x70, 0x81}, // 240

{0x51, 0xf1, 0x69}, // 241

{0xff, 0xff, 0x80}, // 242

{0x91, 0x74, 0xcd}, // 243

{0xff, 0x7c, 0xff}, // 244

{0xa2, 0xff, 0xff}, // 245

{0xff, 0xfb, 0xf0}, // 246 Sys Reserved

{0xa0, 0xa0, 0xa4}, // 247 Sys Reserved

{0x80, 0x80, 0x80}, // 248 Sys Lt Gray  gray 128

{0xff, 0x00, 0x00}, // 249 Sys Red

{0x00, 0xff, 0x00}, // 250 Sys Green

{0xff, 0xff, 0x00}, // 251 Sys Yellow

{0x00, 0x00, 0xff}, // 252 Sys Blue

{0xff, 0x00, 0xff}, // 253 Sys Violet

{0x00, 0xff, 0xff}, // 254 Sys Cyan

{0xff, 0xff, 0xff} // 255 Sys White gray 255

};


 STDPAL.C  (WRAPUI Sample)

/*-----------------------------------------------------------------------

|   stdpal.c

|

|   Standard App Palette useful for OLE applications.

|   Use OleStdCreateStandardPalette API to create the palette.

|

|   NOTE:  The OLE2UI sample source code that will ship with Windows

|          "Chicago" will have the "Chicago" standard palette, which

|          we expect to be different than this palette. We recommend

|          using the "Chicago" palette when it becomes available.

|

|   Copyright (c) 1992 - 1993 Microsoft Corporation. All rights reserved.

|

-----------------------------------------------------------------------*/

#ifndef PC_RESERVED

#include <windows.h>

#endif

#include "ole2ui.h"

#include "stdpal.h"

#define cpeAppPal 256  // number of colors in our apps palette

typedef struct

{

WORD wVersion;

WORD cpe;

PALETTEENTRY rgpe[cpeAppPal];

} LOGPAL;

/*-----------------------------------------------------------------------

|   OleStdCreateStandardPalette

|

|       Creates the standard Apps palette.  Create one of these for your

|   app, and select/realize it into each DC.

|

|   Arguments:

|       void:

|

|   Returns:

|

|   Keywords:

-----------------------------------------------------------------------*/

STDAPI_(HPALETTE) OleStdCreateStandardPalette(void)

{

HDC hdc;

HPALETTE hpal;

hpal = (HPALETTE) NULL;

hdc = GetDC(NULL);

if (hdc != NULL && GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE)

{

int cpeSysPal;

int cpeReserved;

cpeSysPal = GetDeviceCaps(hdc, SIZEPALETTE);

cpeReserved = GetDeviceCaps(hdc, NUMRESERVED);

if (cpeSysPal > cpeReserved)

{

int cpeReserved2;

unsigned char FAR* lpb;

PALETTEENTRY FAR* ppe;

PALETTEENTRY FAR* ppeMac;

LOGPAL logpal;

cpeReserved2 = cpeReserved/2;

// Get the system palette entries at the beginning and end.

GetSystemPaletteEntries(hdc, 0, cpeReserved2, logpal.rgpe);

GetSystemPaletteEntries(hdc, cpeSysPal - cpeReserved2, cpeReserved2,

&logpal.rgpe[cpeAppPal-cpeReserved2]);

logpal.cpe = cpeAppPal;

logpal.wVersion = 0x300;

lpb = (BYTE FAR *) &palSVGA[10];

ppe = (PALETTEENTRY FAR*)&logpal.rgpe[cpeReserved2];

ppeMac = (PALETTEENTRY FAR*)&logpal.rgpe[cpeAppPal-cpeReserved2];

while (ppe < ppeMac)

{

ppe->peFlags = PC_NOCOLLAPSE;

ppe->peRed   = *lpb++;

ppe->peGreen = *lpb++;

ppe->peBlue  = *lpb++;

ppe++;

}

hpal = CreatePalette((LOGPALETTE FAR *)&logpal);

}

}

ReleaseDC(NULL, hdc);

return hpal;

}


 SUMINFO.H  (WRAPUI Sample)

/*************************************************************************

**

**    OLE 2.0 Property Set Utilities

**

**    suminfo.h

**

**    This file contains file contains data structure defintions,

**    function prototypes, constants, etc. for OLE 2.0 Property Set

**    utilities used to manage the Summary Info property set.

**

**    (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved

**

*************************************************************************/

#ifndef SUMINFO_H

#define SUMINFO_H

#include <ole2.h>

#include <objbase.h>

#include <oleauto.h>

/* A SUMINFO variable is an instance of an abstract data type.  Thus,

**    there can be an arbitrary number of SummaryInfo streams open

**    simultaneously (subject to available memory).  Each variable must

**    be initialized prior to use by calling Init and freed after its

**    last use by calling Free.  The param argument to Init is reserved

**    for future expansion and should be zero initially. Once a SUMINFO

**    variable is allocated (by Init), the user can call the Set

**    procedures to initialize fields.  A copy of the arguments is made

**    in every case except SetThumbnail where control of the storage

**    occupied by the METAFILEPICT is merely transferred.  When the

**    Free routine is called, all storage will be deallocated including

**    that of the thumbnail.  The arguments to SetThumbNail and the

**    return values from GetThumbNail correspond to the OLE2.0 spec.

**    Note that on input, the thumbnail is read on demand but all the

**    other properties are pre-loaded.  The thumbnail is manipulated as

**    a windows handle to a METAFILEPICT structure, which in turn

**    contains a handle to the METAFILE.  The transferClip argument on

**    GetThumbNail, when set to true, transfers responsibility for

**    storage management of the thumbnail to the caller; that is, after

**    Free has been called, the handle is still valid. Clear can be

**    used to free storage for all the properties but then you must

**    call Read to load them again.  All the code is based on FAR

**    pointers.

**    CoInitialize MUST be called PRIOR to calling OleStdInitSummaryInfo.

**    Memory is allocated using the currently active IMalloc*

**    allocator (as is returned by call CoGetMalloc(MEMCTX_TASK) ).

**

** Common scenarios:

**    Read SummaryInfo

**    ----------------

**      OleStdInitSummaryInfo()

**      OleStdReadSummaryInfo()

**      . . . . .

**      call different Get routines

**      . . . . .

**      OleStdFreeSummaryInfo()

**

**    Create SummaryInfo

**    ------------------

**      OleStdInitSummaryInfo()

**      call different Set routines

**      OleStdWriteSummaryInfo()

**      OleStdFreeSummaryInfo()

**

**    Update SummaryInfo

**    ------------------

**      OleStdInitSummaryInfo()

**      OleStdReadSummaryInfo()

**      OleStdGetThumbNailProperty(necessary only if no SetThumb)

**      call different Set routines

**      OleStdWriteSummaryInfo()

**      OleStdFreeSummaryInfo()

*/

#define WORDMAX 256     //current string max for APPS; 255 + null terminator

typedef     union {

          short    iVal;             /* VT_I2                */

          long     lVal;             /* VT_I4                */

          float    fltVal;           /* VT_R4                */

          double       dblVal;       /* VT_R8                */

          DWORD bool;                /* VT_BOOL              */

          SCODE    scodeVal;         /* VT_ERROR             */

          DWORD    systimeVal;       /* VT_SYSTIME           */

          unsigned char bstrVal[WORDMAX]; /* VT_BSTR              */

        } VTUNION;

typedef struct _FMTID

        {

        DWORD dword;

        WORD words[2];

        BYTE bytes[8];

        } FMTID;

typedef struct _PROPSETLIST

        {

        FMTID formatID;

        DWORD byteOffset;

        } PROPSETLIST;

typedef struct _PROPIDLIST

        {

        DWORD propertyID;

        DWORD byteOffset;

        } PROPIDLIST;

typedef struct _PROPVALUE

        {

        DWORD vtType;

        VTUNION vtValue;

        } PROPVALUE;

typedef struct _SECTION

        {

        DWORD cBytes;

        DWORD cProperties;

        PROPIDLIST rgPropId[1/*cProperties*/];  //variable-length array

        PROPVALUE rgPropValue[1];      //CANNOT BE ACCESSED BY NAME; ONLY BY POINTER

        } SECTION;

typedef struct _SUMMARYINFO

        {

        WORD byteOrder;

        WORD formatVersion;

        WORD getOSVersion;

        WORD osVersion;

        CLSID classId;  //from compobj.h

        DWORD cSections;

        PROPSETLIST rgPropSet[1/*cSections*/]; //variable-length array

        SECTION rgSections[1/*cSections*/];    //CANNOT BE ACCESSED BY NAME; ONLY BY POINTER

        } SUMMARYINFO;

#define osWinOnDos 0

#define osMac 1

#define osWinNT 2

#define PID_DICTIONARY 0X00000000

#define PID_CODEPAGE 0X00000001

#define PID_TITLE 0X00000002

#define PID_SUBJECT 0X00000003

#define PID_AUTHOR 0X00000004

#define PID_KEYWORDS 0X00000005

#define PID_COMMENTS 0X00000006

#define PID_TEMPLATE 0X00000007

#define PID_LASTAUTHOR 0X00000008

#define PID_REVNUMBER 0X00000009

#define PID_EDITTIME 0X0000000A

#define PID_LASTPRINTED 0X0000000B

#define PID_CREATE_DTM_RO 0X0000000C

#define PID_LASTSAVE_DTM 0X0000000D

#define PID_PAGECOUNT 0X0000000E

#define PID_WORDCOUNT 0X0000000F

#define PID_CHARCOUNT 0X00000010

#define PID_THUMBNAIL 0X00000011

#define PID_APPNAME 0X00000012

#define PID_SECURITY 0X00000013

#define cPID_STANDARD (PID_SECURITY+1-2)

#ifndef WIN32

#define MAXWORD 256         //maximum string size for APPS at present

#endif

typedef struct _STDZ

        {

        DWORD vtType;

        union {

        DWORD vtByteCount;

        unsigned char fill[4];  //use last byte as byte count for stz requests

        };

        unsigned char rgchars[MAXWORD];

        } STDZ;

#define VTCB fill[3]    //used to set/get the count byte when in memory

typedef struct _THUMB

        {

        DWORD vtType;

        DWORD cBytes;       //clip size in memory

        DWORD selector;     //on disk -1,win clip no.  -2,mac clip no. -3,ole FMTID  0,bytes  nameLength, format name

        DWORD clipFormat;

        unsigned char FAR *lpstzName;

        unsigned char FAR *lpByte;

        } THUMB;

#define VT_CF_BYTES 0

#define VT_CF_WIN (-1)

#define VT_CF_MAC (-2)

#define VT_CF_FMTID (-3)

#define VT_CF_NAME (-4)

#define VT_CF_EMPTY (-5)

#define VT_CF_OOM (-6)      // Out of memory

typedef THUMB FAR *LPTHUMB;

typedef STDZ FAR *LPSTDZ;

typedef struct _TIME

        {

        DWORD vtType;

        FILETIME time;

        } TIME;

typedef struct _INTS

        {

        DWORD vtType;

        DWORD value;

        } INTS;

#define MAXTIME (PID_LASTSAVE_DTM-PID_EDITTIME+1)

#define MAXINTS (PID_CHARCOUNT-PID_PAGECOUNT+1+1)

#define MAXSTDZ (PID_REVNUMBER-PID_TITLE+1+1)

typedef struct _STANDARDSECINMEM

        {

        DWORD cBytes;

        DWORD cProperties;

        PROPIDLIST rgPropId[cPID_STANDARD/*cProperties*/];  //variable-length array

        TIME rgTime[MAXTIME];

        INTS rgInts[MAXINTS];

        LPSTDZ rglpsz[MAXSTDZ];

        THUMB thumb;

        } STANDARDSECINMEM;

#define OFFSET_NIL 0X00000000

#define AllSecurityFlagsEqNone 0

#define fSecurityPassworded 1

#define fSecurityRORecommended 2

#define fSecurityRO 4

#define fSecurityLockedForAnnotations 8

#define PropStreamNamePrefixByte '\005'

#define PropStreamName "\005SummaryInformation"

#define cbNewSummaryInfo(nSection) (sizeof(SUMMARYINFO)-sizeof(SECTION)+sizeof(PROPSETLIST)*((nSection)-1))

#define cbNewSection(nPropIds) (sizeof(SECTION)-sizeof(PROPVALUE)+sizeof(PROPIDLIST)*((nPropIds)-1))

#define FIntelOrder(prop) ((prop)->byteOrder==0xfffe)

#define SetOs(prop, os) {(prop)->osVersion=os; (prop)->getOSVersion=LOWORD(GetVersion());}

#define SetSumInfFMTID(fmtId) {(fmtId)->dword=0XF29F85E0; *(long FAR *)&(fmtId)->words=0X10684FF9;\

                                *(long FAR *)&(fmtId)->bytes[0]=0X000891AB; *(long FAR *)&(fmtId)->bytes[4]=0XD9B3272B;}

#define FEqSumInfFMTID(fmtId) ((fmtId)->dword==0XF29F85E0&&*((long FAR *)&(fmtId)->words)==0X10684FF9&&\

                                *((long FAR *)&(fmtId)->bytes[0])==0X000891AB&&*((long FAR *)&(fmtId)->bytes[4])==0XD9B3272B)

#define FSzEqPropStreamName(sz) _fstricmp(sz, PropStreamName)

#define ClearSumInf(lpsuminf, cb) {_fmemset(lpsuminf,0,cb); (lpsuminf)->byteOrder=0xfffe;\

                                SetOs(lpsuminf, osWinOnDos);}

typedef void FAR *LPSUMINFO;

typedef LPSTR LPSTZR;

typedef void FAR *THUMBNAIL;  //for VT_CF_WIN this is an unlocked global handle

#define API __far __pascal

/*************************************************************************

** Public Summary Info Property Set Management API

*************************************************************************/

extern "C" {

STDAPI_(LPSUMINFO) OleStdInitSummaryInfo(int reserved);

STDAPI_(void) OleStdFreeSummaryInfo(LPSUMINFO FAR *lplp);

STDAPI_(void) OleStdClearSummaryInfo(LPSUMINFO lp);

STDAPI_(int) OleStdReadSummaryInfo(LPSTREAM lpStream, LPSUMINFO lp);

STDAPI_(int) OleStdWriteSummaryInfo(LPSTREAM lpStream, LPSUMINFO lp);

STDAPI_(DWORD) OleStdGetSecurityProperty(LPSUMINFO lp);

STDAPI_(int) OleStdSetSecurityProperty(LPSUMINFO lp, DWORD security);

STDAPI_(LPSTR) OleStdGetStringProperty(LPSUMINFO lp, DWORD pid);

STDAPI_(int) OleStdSetStringProperty(LPSUMINFO lp, DWORD pid, LPSTR lpsz);

STDAPI_(LPSTZR) OleStdGetStringZProperty(LPSUMINFO lp, DWORD pid);

STDAPI_(void) OleStdGetDocProperty(

                LPSUMINFO       lp,

                DWORD FAR*      nPage,

                DWORD FAR*      nWords,

                DWORD FAR*      nChars

);

STDAPI_(int) OleStdSetDocProperty(

                LPSUMINFO       lp,

                DWORD           nPage,

                DWORD           nWords,

                DWORD           nChars

);

STDAPI_(int) OleStdGetThumbNailProperty(

                LPSTREAM        lps,

                LPSUMINFO       lp,

                DWORD FAR*      clipFormatNo,

                LPSTR FAR*      lpszName,

                THUMBNAIL FAR*  clip,

                DWORD FAR*      byteCount,

                BOOL            transferClip

);

STDAPI_(int) OleStdSetThumbNailProperty(

                LPSTREAM        lps,

                LPSUMINFO       lp,

                int             vtcfNo,

                DWORD           clipFormatNo,

                LPSTR           lpszName,

                THUMBNAIL       clip,

                DWORD           byteCount

);

STDAPI_(void) OleStdGetDateProperty(

                LPSUMINFO       lp,

                DWORD           pid,

                int FAR*        yr,

                int FAR*        mo,

                int FAR*        dy,

                DWORD FAR*      sc

);

STDAPI_(int) OleStdSetDateProperty(

                LPSUMINFO       lp,

                DWORD           pid,

                int             yr,

                int             mo,

                int             dy,

                int             hr,

                int             mn,

                int             sc

);

} //END C

#endif  // SUMINFO_H


 SUMINFO.CPP  (WRAPUI Sample)

/*************************************************************************

**

**    OLE 2.0 Property Set Utilities

**

**    suminfo.cpp

**

**    This file contains functions that are useful for the manipulation

**    of OLE 2.0 Property Sets particularly to manage the Summary Info

**    property set.

**

**    (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved

**

*************************************************************************/

// Note: this file is designed to be stand-alone; it includes a

// carefully chosen, minimal set of headers.

//

// For conditional compilation we use the ole2 conventions,

//    _MAC      = mac

//    WIN32     = Win32 (NT really)

//    <nothing> = defaults to Win16

// REVIEW: the following needs to modified to handle _MAC

#define STRICT

#include <windows.h>

#include <string.h>

#include <ole2.h>

#include "ole2ui.h"

/* A LPSUMINFO variable is a pointer to an instance of an abstract data

**    type.  There can be an arbitrary number of SummaryInfo streams open

**    simultaneously (subject to available memory); each must have its

**    own LPSUMINFO instance. Each LPSUMINFO instance must

**    be initialized prior to use by calling Init and freed after its

**    last use by calling Free.  The param argument to Init is reserved

**    for future expansion and should be zero initially. Once a LPSUMINFO

**    instance is allocated (by Init), the user can call the Set

**    procedures to initialize fields.  A copy of the arguments is made

**    in every case except SetThumbnail where control of the storage

**    occupied by the METAFILEPICT is merely transferred.  When the

**    Free routine is called, all storage will be deallocated including

**    that of the thumbnail.  The arguments to SetThumbNail and the

**    return values from GetThumbNail correspond to the OLE2.0 spec.

**    Note that on input, the thumbnail is read on demand but all the

**    other properties are pre-loaded.  The thumbnail is manipulated as

**    a windows handle to a METAFILEPICT structure, which in turn

**    contains a handle to the METAFILE.  The transferClip argument on

**    GetThumbNail, when set to true, transfers responsibility for

**    storage management of the thumbnail to the caller; that is, after

**    Free has been called, the handle is still valid. Clear can be

**    used to free storage for all the properties but then you must

**    call Read to load them again.  All the code is based on FAR

**    pointers.

**    CoInitialize MUST be called PRIOR to calling OleStdInitSummaryInfo.

**    Memory is allocated using the currently active IMalloc*

**    allocator (as is returned by call CoGetMalloc(MEMCTX_TASK) ).

**

** Common scenarios:

**    Read SummaryInfo

**    ----------------

**      OleStdInitSummaryInfo()

**      OleStdReadSummaryInfo()

**      . . . . .

**      call different Get routines

**      . . . . .

**      OleStdFreeSummaryInfo()

**

**    Create SummaryInfo

**    ------------------

**      OleStdInitSummaryInfo()

**      call different Set routines

**      OleStdWriteSummaryInfo()

**      OleStdFreeSummaryInfo()

**

**    Update SummaryInfo

**    ------------------

**      OleStdInitSummaryInfo()

**      OleStdReadSummaryInfo()

**      OleStdGetThumbNailProperty(necessary only if no SetThumb)

**      call different Set routines

**      OleStdWriteSummaryInfo()

**      OleStdFreeSummaryInfo()

*/

#define CHAR unsigned char

#define fTrue 1

#define fFalse 0

#define BYTE unsigned char

#define WORD unsigned short

#define DWORD unsigned long

#define LPVOID void FAR *

#define uchar unsigned char

#define ulong unsigned long

#define BOOL unsigned char

#define BF unsigned int

#include "suminfo.h"

#include "wn_dos.h"

#if defined( _DEBUG )

// following is from compobj.dll (ole2)

#define ASSERT(x) (!(x) ? FnAssert(#x, NULL, __FILE__, __LINE__) : 0)

#else

#define ASSERT(x)

#endif

typedef struct _RSUMINFO

{

WORD byteOrder;

WORD formatVersion;

WORD getOSVersion;

WORD osVersion;

CLSID classId;  //from compobj.h

DWORD cSections;

PROPSETLIST rgPropSet[1/*cSections*/]; //one section in standard summary info

STANDARDSECINMEM section;

ULONG fileOffset;   //offset for thumbnail to support demand read

} RSUMINFO;

typedef RSUMINFO FAR * LPRSI;

typedef union _foo{

ULARGE_INTEGER uli;

struct {

DWORD       dw;

DWORD       dwh;

};

struct {

WORD    w0;

WORD    w1;

WORD    w2;

WORD    w3;

};

} Foo;

/* MemAlloc

** ---------

**    allocate memory using the currently active IMalloc* allocator

*/

static LPVOID MemAlloc(ULONG ulSize)

{

LPVOID pout;

LPMALLOC pmalloc;

if (CoGetMalloc(MEMCTX_TASK, &pmalloc) != NOERROR) {

ASSERT(pmalloc);

return NULL;

}

pout = (LPVOID)pmalloc->Alloc(ulSize);

if (pmalloc != NULL) {

ULONG refs = pmalloc->Release();

}

return pout;

}

/* MemFree

** -------

**    free memory using the currently active IMalloc* allocator

*/

static void MemFree(LPVOID pmem)

{

LPMALLOC pmalloc;

if (pmem == NULL)

return;

if (CoGetMalloc(MEMCTX_TASK, &pmalloc) != NOERROR) {

ASSERT(pmalloc);

return;

}

pmalloc->Free(pmem);

if (pmalloc != NULL) {

ULONG refs = pmalloc->Release();

}

}

// Replace the first argument with the product of itself and the multiplier

static void ulargeMultiply(ULARGE_INTEGER FAR *ul, USHORT m)

{

Foo out, in;

in.uli = *ul;

out.dw = (ULONG)m * in.w0;      in.w0 = out.w0;

out.dw = (ULONG)m * in.w1 + out.w1; in.w1 = out.w0;

out.dw = (ULONG)m * in.w2 + out.w1; in.w2 = out.w0;

out.dw = (ULONG)m * in.w3 + out.w1; in.w3 = out.w0;

*ul = in.uli;

}

// Replace the first argument with the product of itself and the multiplier

static void ulargeDivide(ULARGE_INTEGER FAR *ul, USHORT m)

{

Foo out, in;

DWORD i;

in.uli = *ul;

out.dwh = in.dwh/(ULONG)m;

i = in.dwh%(ULONG)m;

in.w2 = in.w1;

in.w3 = (WORD)i;

out.w1 = (WORD)(in.dwh/(ULONG)m);

in.w1 = (WORD)(in.dwh%(ULONG)m);

out.w0 = (WORD)(in.dw/(ULONG)m);

*ul = out.uli;

}

static void setStandard(LPRSI lprsi)

{

int i;

lprsi->cSections = 1;

SetSumInfFMTID(&lprsi->rgPropSet[0].formatID);

_fmemcpy(&lprsi->classId, &lprsi->rgPropSet[0].formatID, sizeof(FMTID));

lprsi->rgPropSet[0].byteOffset = cbNewSummaryInfo(1);

for (i=0; i<cPID_STANDARD; i++)

lprsi->section.rgPropId[i].propertyID = PID_TITLE+i;

lprsi->section.cProperties = cPID_STANDARD; //always; do null test to check validity

}

extern "C" {

/*************************************************************************

**

** OleStdInitSummaryInfo

**

** Purpose:

**    Initialize a Summary Info structure.

**

** Parameters:

**    int reserved             - reserverd for future use. must be 0.

**

** Return Value:

**    LPSUMINFO

**

** Comments:

**    CoInitialize MUST be called PRIOR to calling OleStdInitSummaryInfo.

**    Memory is allocated using the currently active IMalloc*

**    allocator (as is returned by call CoGetMalloc(MEMCTX_TASK) ).

**    Each LPSUMINFO instance must be initialized prior to use by

**    calling OleStdInitSummaryInfo. Once a LPSUMINFO instance is allocated

**    (by OleStdInitSummaryInfo), the user can call the Set procedures to

**    initialize fields.

*************************************************************************/

STDAPI_(LPSUMINFO) OleStdInitSummaryInfo(int reserved)

{

LPRSI lprsi;

if ((lprsi = (LPRSI)MemAlloc(sizeof(RSUMINFO))) != NULL)

{

ClearSumInf(lprsi, sizeof(RSUMINFO));

} else return NULL;

setStandard(lprsi);

return (LPSUMINFO)lprsi;

}

/*************************************************************************

**

** OleStdFreeSummaryInfo

**

** Purpose:

**    Free a Summary Info structure.

**

** Parameters:

**    LPSUMINFO FAR *lp           - pointer to open Summary Info struct

**

** Return Value:

**    void

**

** Comments:

**    Memory is freed using the currently active IMalloc*

**    allocator (as is returned by call CoGetMalloc(MEMCTX_TASK) ).

**    Every LPSUMINFO struct must be freed after its last use.

**    When the OleStdFreeSummaryInfo routine is called, all storage will be

**    deallocated including that of the thumbnail (unless ownership of

**    the thumbnail has been transfered to the caller -- see

**    description of transferClip in GetThumbnail API).

**

*************************************************************************/

STDAPI_(void) OleStdFreeSummaryInfo(LPSUMINFO FAR *lplp)

{

if (lplp==NULL||*lplp==NULL) return;

OleStdClearSummaryInfo(*lplp);

MemFree(*lplp);

*lplp = NULL;

}

/*************************************************************************

**

** OleStdClearSummaryInfo

**

** Purpose:

**    Free storage (memory) for all the properties of the LPSUMINFO.

**

** Parameters:

**    LPSUMINFO FAR *lp             - pointer to open Summary Info struct

**

** Return Value:

**    void

**

** Comments:

**    After calling OleStdClearSummaryInfo you must call OleStdReadSummaryInfo to

**    load them again.

**

*************************************************************************/

STDAPI_(void) OleStdClearSummaryInfo(LPSUMINFO lp)

{

OleStdSetStringProperty(lp, PID_TITLE, NULL);

OleStdSetStringProperty(lp, PID_SUBJECT, NULL);

OleStdSetStringProperty(lp, PID_AUTHOR, NULL);

OleStdSetStringProperty(lp, PID_KEYWORDS, NULL);

OleStdSetStringProperty(lp, PID_COMMENTS, NULL);

OleStdSetStringProperty(lp, PID_TEMPLATE, NULL);

OleStdSetStringProperty(lp, PID_REVNUMBER, NULL);

OleStdSetStringProperty(lp, PID_APPNAME, NULL);

OleStdSetThumbNailProperty(NULL, lp, VT_CF_EMPTY, 0, NULL, NULL, 0);

ClearSumInf((LPRSI)lp, sizeof(RSUMINFO));

}

/*************************************************************************

**

** OleStdReadSummaryInfo

**

** Purpose:

**    Read all Summary Info properties into memory (except thumbnail

**    which is demand loaded).

**

** Parameters:

**    LPSTREAM lps                  - open SummaryInfo IStream*

**    LPSUMINFO FAR *lp             - pointer to open Summary Info struct

**

** Return Value:

**    int                           - 1 for success

**                                  - 0 if error occurs

** Comments:

**

*************************************************************************/

STDAPI_(int) OleStdReadSummaryInfo(LPSTREAM lpStream, LPSUMINFO lp)

{

STANDARDSECINMEM FAR *lpSSIM=(STANDARDSECINMEM FAR*)&((LPRSI)lp)->section;

LPRSI lpSumInfo = (LPRSI)lp;

SCODE sc;

ULONG cbRead,i,sectionOffset;

LARGE_INTEGER a;

ULARGE_INTEGER b;

int j,k,l;

union {

RSUMINFO rsi;

STDZ stdz;

};

OleStdClearSummaryInfo(lp);

LISet32(a, 0);

sc = GetScode(lpStream->Seek(a, STREAM_SEEK_SET, &b));

if (FAILED(sc)) goto fail;

sectionOffset = cbNewSummaryInfo(1);

sc = GetScode(lpStream->Read(&rsi, sectionOffset, &cbRead));

if (FAILED(sc)||cbRead<sectionOffset) goto fail;

if (!FIntelOrder(&rsi)||rsi.formatVersion!=0) goto fail;

j = (int)rsi.cSections;

while (j-->0) {

if (FEqSumInfFMTID(&rsi.rgPropSet[0].formatID)) {

sectionOffset = rsi.rgPropSet[0].byteOffset;

break;

} else {

sc = GetScode(lpStream->Read(&rsi.rgPropSet[0].formatID, sizeof(PROPSETLIST), &cbRead));

if (FAILED(sc)||cbRead!=sizeof(PROPSETLIST)) goto fail;

}

if (j<=0) goto fail;

}

LISet32(a, sectionOffset);

sc = GetScode(lpStream->Seek(a, STREAM_SEEK_SET, &b));

if (FAILED(sc)) goto fail;

sc = GetScode(lpStream->Read(&rsi.section, cbNewSection(1), &cbRead));

if (FAILED(sc)||cbRead!=cbNewSection(1)) goto fail;

i = rsi.section.cBytes+sectionOffset;

j = (int)rsi.section.cProperties;

if (j>cPID_STANDARD) goto fail;

k = 0;

while (j-->0) {

k++;

switch (l=(int)rsi.section.rgPropId[0].propertyID) {

case PID_PAGECOUNT:

case PID_WORDCOUNT:

case PID_CHARCOUNT:

case PID_SECURITY:

if (l==PID_SECURITY) l=3; else l-=PID_PAGECOUNT;

cbRead = sectionOffset+rsi.section.rgPropId[0].byteOffset;

if (cbRead>=i) goto fail;

LISet32(a, cbRead);

sc = GetScode(lpStream->Seek(a, STREAM_SEEK_SET, &b));

if (FAILED(sc)) goto fail;

sc = GetScode(lpStream->Read(&lpSSIM->rgInts[l], sizeof(INTS), &cbRead));

if (FAILED(sc)||cbRead!=sizeof(INTS)) goto fail;

if (lpSSIM->rgInts[l].vtType==VT_EMPTY) break;

if (lpSSIM->rgInts[l].vtType!=VT_I4) goto fail;

break;

case PID_EDITTIME:

case PID_LASTPRINTED:

case PID_CREATE_DTM_RO:

case PID_LASTSAVE_DTM:

l-=PID_EDITTIME;

cbRead = sectionOffset+rsi.section.rgPropId[0].byteOffset;

if (cbRead>=i) goto fail;

LISet32(a, cbRead);

sc = GetScode(lpStream->Seek(a, STREAM_SEEK_SET, &b));

if (FAILED(sc)) goto fail;

sc = GetScode(lpStream->Read(&lpSSIM->rgTime[l], sizeof(TIME), &cbRead));

if (FAILED(sc)||cbRead!=sizeof(TIME)) goto fail;

if (lpSSIM->rgTime[l].vtType==VT_EMPTY) break;

if (lpSSIM->rgTime[l].vtType!=VT_FILETIME) goto fail;

break;

case PID_TITLE:

case PID_SUBJECT:

case PID_AUTHOR:

case PID_KEYWORDS:

case PID_COMMENTS:

case PID_TEMPLATE:

case PID_LASTAUTHOR:

case PID_REVNUMBER:

case PID_APPNAME:

cbRead = sectionOffset+rsi.section.rgPropId[0].byteOffset;

if (cbRead>=i) goto fail;

LISet32(a, cbRead);

sc = GetScode(lpStream->Seek(a, STREAM_SEEK_SET, &b));

if (FAILED(sc)) goto fail;

sc = GetScode(lpStream->Read(&stdz, sizeof(STDZ), &cbRead));

if (FAILED(sc)||cbRead<sizeof(DWORD)*2) goto fail;

if (stdz.vtType==VT_EMPTY||stdz.vtByteCount<=1) break;

if (stdz.vtType!=VT_LPSTR||stdz.vtByteCount>WORDMAX) goto fail;

stdz.rgchars[(int)stdz.vtByteCount-1] = '\0';

OleStdSetStringProperty(lp, (DWORD)l, (LPSTR)&stdz.rgchars[0]);

break;

case PID_THUMBNAIL:

cbRead = sectionOffset+rsi.section.rgPropId[0].byteOffset;

if (cbRead>=i) goto fail;

LISet32(a, cbRead);

sc = GetScode(lpStream->Seek(a, STREAM_SEEK_SET, &b));

if (FAILED(sc)) goto fail;

lpSumInfo->fileOffset = cbRead+sizeof(DWORD)*3;

sc = GetScode(lpStream->Read(&lpSSIM->thumb, sizeof(DWORD)*4, &cbRead));

if (FAILED(sc)||cbRead!=sizeof(DWORD)*4) {

lpSSIM->thumb.vtType = VT_EMPTY;

goto fail;

}

if (lpSSIM->thumb.vtType == VT_EMPTY) {

lpSSIM->thumb.cBytes = 0;

break;

}

if (lpSSIM->thumb.vtType != VT_CF) {

lpSSIM->thumb.vtType = VT_EMPTY;

goto fail;

}

lpSSIM->thumb.cBytes -= sizeof(DWORD); //for selector

if (lpSSIM->thumb.selector==VT_CF_WIN||lpSSIM->thumb.selector==VT_CF_MAC) {

lpSumInfo->fileOffset += sizeof(DWORD);

lpSSIM->thumb.cBytes -= sizeof(DWORD); //for format val

}

break;

default: ;

}

if (j<=0)

{

// We should fail if the document is password-protected.

if(OleStdGetSecurityProperty(lp)==fSecurityPassworded)

goto fail;

return 1;

}

LISet32(a, sectionOffset+sizeof(DWORD)*2+k*sizeof(PROPIDLIST));

sc = GetScode(lpStream->Seek(a, STREAM_SEEK_SET, &b));

if (FAILED(sc)) goto fail;

sc = GetScode(lpStream->Read(&rsi.section.rgPropId[0], sizeof(PROPIDLIST), &cbRead));

if (FAILED(sc)||cbRead!=sizeof(PROPIDLIST)) goto fail;

}

fail:

OleStdClearSummaryInfo(lpSumInfo);

return 0;

}

/*************************************************************************

**

** OleStdWriteSummaryInfo

**

** Purpose:

**    Write all Summary Info properties to a IStream*

**

** Parameters:

**    LPSTREAM lps                  - open SummaryInfo IStream*

**    LPSUMINFO FAR *lp             - pointer to open Summary Info struct

**

** Return Value:

**    int                           - 1 for success

**                                  - 0 if error occurs

** Comments:

**

*************************************************************************/

STDAPI_(int) OleStdWriteSummaryInfo(LPSTREAM lpStream, LPSUMINFO lp)

{

STANDARDSECINMEM FAR *lpSSIM=(STANDARDSECINMEM FAR*)&((LPRSI)lp)->section;

// REVIEW: localization issues for propert sets

//         do we need to include a code page and dictionary?

LPRSI lpSumInfo = (LPRSI)lp;

SCODE sc;

ULONG cbWritten;

ULONG cBytes, oBytes, k,l,m,n;

LARGE_INTEGER a;

ULARGE_INTEGER b;

CHAR FAR *lps;

LPMETAFILEPICT lpmfp;

int i,j,s;

setStandard(lpSumInfo);

oBytes = cbNewSection(cPID_STANDARD);  //offsets are relative to the section

cBytes = cbNewSection(cPID_STANDARD)+(sizeof(TIME)*MAXTIME)+(sizeof(INTS)*MAXINTS);

lpSSIM->rgPropId[PID_EDITTIME-2].byteOffset = oBytes;

lpSSIM->rgPropId[PID_LASTPRINTED-2].byteOffset = oBytes+sizeof(TIME);

lpSSIM->rgPropId[PID_CREATE_DTM_RO-2].byteOffset = oBytes+sizeof(TIME)*2;

lpSSIM->rgPropId[PID_LASTSAVE_DTM-2].byteOffset = oBytes+sizeof(TIME)*3;

lpSSIM->rgPropId[PID_PAGECOUNT-2].byteOffset = oBytes+(sizeof(TIME)*MAXTIME);

lpSSIM->rgPropId[PID_WORDCOUNT-2].byteOffset = oBytes+(sizeof(TIME)*MAXTIME+sizeof(INTS));

lpSSIM->rgPropId[PID_CHARCOUNT-2].byteOffset = oBytes+(sizeof(TIME)*MAXTIME+sizeof(INTS)*2);

lpSSIM->rgPropId[PID_SECURITY-2].byteOffset = oBytes+(sizeof(TIME)*MAXTIME+sizeof(INTS)*3);

oBytes += sizeof(TIME)*MAXTIME + sizeof(INTS)*MAXINTS;

lpSSIM->rgPropId[PID_THUMBNAIL-2].byteOffset = oBytes;

l = 0;

if (lpSSIM->thumb.vtType==VT_EMPTY) k = sizeof(DWORD);

else {

l = ((lpSSIM->thumb.cBytes+4-1)>>2)<<2;

if (lpSSIM->thumb.selector==VT_CF_BYTES) k = sizeof(DWORD)*3;

else if (lpSSIM->thumb.selector==VT_CF_FMTID) {k = sizeof(DWORD)*3; l += sizeof(FMTID); }

else if (lpSSIM->thumb.selector==VT_CF_NAME)  {k = sizeof(DWORD)*3; l += (((*lpSSIM->thumb.lpstzName+1+3)>>2)<<2);}

else k = sizeof(DWORD)*4;

}

cBytes += k+l;

oBytes += k+l;

for (i=0; i<MAXSTDZ; i++) {

j = 0;

if (lpSSIM->rglpsz[i]!=NULL) {

j = lpSSIM->rglpsz[i]->VTCB+1/*null*/;

lpSSIM->rglpsz[i]->vtByteCount = j;

j = (((j+4-1)>>2)<<2)+sizeof(DWORD);

cBytes += j;

}

if (i!=MAXSTDZ-1) lpSSIM->rgPropId[i].byteOffset = oBytes;

else lpSSIM->rgPropId[PID_APPNAME-2].byteOffset = oBytes;

oBytes += j+sizeof(DWORD);

cBytes += sizeof(DWORD); //type

}

lpSSIM->cBytes = cBytes;

LISet32(a, 0);

sc = GetScode(lpStream->Seek(a, STREAM_SEEK_SET, &b));

if (FAILED(sc)) return 0;

sc = GetScode(lpStream->Write(lpSumInfo, cbNewSummaryInfo(1), &cbWritten));

if (FAILED(sc)||cbWritten!=cbNewSummaryInfo(1)) return 0;

sc = GetScode(lpStream->Write(lpSSIM, cbNewSection(cPID_STANDARD)+sizeof(TIME)*MAXTIME+sizeof(INTS)*MAXINTS, &cbWritten));

if (FAILED(sc)||cbWritten!=cbNewSection(cPID_STANDARD)+sizeof(TIME)*MAXTIME+sizeof(INTS)*MAXINTS) return 0;

m = lpSSIM->thumb.cBytes;

if (lpSSIM->thumb.lpstzName!=NULL) s = *lpSSIM->thumb.lpstzName;

else s = 0;

if (m!=0) {

lpSSIM->thumb.cBytes = (k-sizeof(DWORD)*2)+

(((lpSSIM->thumb.cBytes+4-1)>>2)<<2)+(((s+4-1)>>2)<<2);

n = lpSSIM->thumb.selector;

lps = lpSSIM->thumb.lpByte;

ASSERT(lps!=NULL);  //maybe a GetThumbNail here

ASSERT(n!=VT_CF_NAME);

if (n==VT_CF_WIN) { //bytes are in global memory

lpmfp = (LPMETAFILEPICT)GlobalLock((HANDLE)(DWORD)lps);

if (lpmfp==NULL) goto fail;

lps = (CHAR FAR*)GlobalLock(lpmfp->hMF);

}

if (n==VT_CF_NAME) lpSSIM->thumb.selector = *lpSSIM->thumb.lpstzName+1/*null*/;

}

sc = GetScode(lpStream->Write(&lpSSIM->thumb, k, &cbWritten));

if (FAILED(sc)||cbWritten!=k) goto fail;

if (s!=0) {

k = ((s+1+4-1)>>2)<<2;

sc = GetScode(lpStream->Write(lpSSIM->thumb.lpstzName+1, k, &cbWritten));

if (FAILED(sc)||cbWritten!=k) goto fail;

}

if (m!=0) {

k = ((m+3)>>2)<<2;

if (n==VT_CF_WIN||VT_CF_NAME) { //bytes are in global memory

sc = GetScode(lpStream->Write(lpmfp, sizeof(METAFILEPICT), &cbWritten));

k -= sizeof(METAFILEPICT);

}

sc = GetScode(lpStream->Write(lps, k, &cbWritten));

if (FAILED(sc)||cbWritten!=k) goto fail;

if (n==VT_CF_WIN||VT_CF_NAME) { //bytes are in global memory

GlobalUnlock(lpmfp->hMF);

GlobalUnlock((HANDLE)(DWORD)lpSSIM->thumb.lpByte);

}

}

lpSSIM->thumb.cBytes = m;   //restore in mem value

lpSSIM->thumb.selector = n;

k = VT_EMPTY;

for (i=0; i<MAXSTDZ; i++) {

if (lpSSIM->rglpsz[i]!=NULL) {

l = lpSSIM->rglpsz[i]->vtByteCount;

j = ((((int)l+4-1)/4)*4)+sizeof(DWORD)*2;

sc = GetScode(lpStream->Write(lpSSIM->rglpsz[i], j, &cbWritten));

if (FAILED(sc)||cbWritten!=(ULONG)j) return 0;

lpSSIM->rglpsz[i]->vtByteCount = 0; //restore stz count convention

lpSSIM->rglpsz[i]->VTCB = (int)l;

} else {

sc = GetScode(lpStream->Write(&k, sizeof(DWORD), &cbWritten));

if (FAILED(sc)||cbWritten!=sizeof(DWORD)) return 0;

}

}

return 1;

fail:

lpSSIM->thumb.cBytes = m;   //restore in mem value

lpSSIM->thumb.selector = n;

if (m!=0&&(n==VT_CF_WIN||VT_CF_NAME)) { //bytes are in global memory

GlobalUnlock((HANDLE)(DWORD)lps);

}

return 0;

}

/*************************************************************************

**

** OleStdGetSecurityProperty

**

** Purpose:

**    Retrieve the Security Property

**

** Parameters:

**    LPSUMINFO FAR *lp           - pointer to open Summary Info struct

**

** Return Value:

**    DWORD                       - security level

**          AllSecurityFlagsEqNone 0    - no security

**          fSecurityPassworded 1       - password required

**          fSecurityRORecommended 2    - read-only is recommended

**          fSecurityRO 4               - read-only is required

**          fSecurityLockedForAnnotations 8 - locked for annotations

**

** Comments:

**    by noting the (suggested; that is, application-enforced) security

**    level on the document, an application other than the originator

**    of the document can adjust its user interface to the properties

**    appropriately. An application should not display any of the

**    information about a password protected document, and should not

**    allow modifications to enforced read-only or locked for

**    annotations documents. It should warn the user about read-only

**    recommended if the user attempts to modify properties.

**

*************************************************************************/

STDAPI_(DWORD) OleStdGetSecurityProperty(LPSUMINFO lp)

{

STANDARDSECINMEM FAR *lpSSIM=(STANDARDSECINMEM FAR*)&((LPRSI)lp)->section;

if (lpSSIM->rgInts[3].vtType == VT_I4) return lpSSIM->rgInts[3].value;

return 0;

}

/*************************************************************************

**

** OleStdSetSecurityProperty

**

** Purpose:

**    Set the Security Property

**

** Parameters:

**    LPSUMINFO FAR *lp           - pointer to open Summary Info struct

**    DWORD security              - security level

**          AllSecurityFlagsEqNone 0    - no security

**          fSecurityPassworded 1       - password required

**          fSecurityRORecommended 2    - read-only is recommended

**          fSecurityRO 4               - read-only is required

**          fSecurityLockedForAnnotations 8 - locked for annotations

**

** Return Value:

**    int                           - 1 for success

**                                  - 0 if error occurs

**                                    (there are no errors)

**

** Comments:

**    by noting the (suggested; that is, application-enforced) security

**    level on the document, an application other than the originator

**    of the document can adjust its user interface to the properties

**    appropriately. An application should not display any of the

**    information about a password protected document, and should not

**    allow modifications to enforced read-only or locked for

**    annotations documents. It should warn the user about read-only

**    recommended if the user attempts to modify properties.

**

*************************************************************************/

STDAPI_(int) OleStdSetSecurityProperty(LPSUMINFO lp, DWORD security)

{

STANDARDSECINMEM FAR *lpSSIM=(STANDARDSECINMEM FAR*)&((LPRSI)lp)->section;

// REVIEW: check valid transitions; how do we know APP called us?

if (security==0) {

lpSSIM->rgInts[3].vtType = VT_EMPTY;

return 1;

}

lpSSIM->rgInts[3].vtType = VT_I4;

lpSSIM->rgInts[3].value = security;

return 1;

}

/*************************************************************************

**

** OleStdGetStringProperty

**

** Purpose:

**    Retrieve a String Propety.

**    (returns zero terminated string -- C string)

**

** Parameters:

**    LPSUMINFO FAR *lp             - pointer to open Summary Info struct

**    DWORD pid                     - ID of String Property

**

** Return Value:

**    LPSTR                         - value of String Property

**                                      (zero terminated string--C string)

**

** Comments:

**    String should NOT be freed by caller. Memory for string will be

**    freed when OleStdFreeSummaryInfo is called.

*************************************************************************/

STDAPI_(LPSTR) OleStdGetStringProperty(LPSUMINFO lp, DWORD pid)

{

LPSTR l = OleStdGetStringZProperty(lp,pid);

if (l==NULL) return NULL; else return l+1;

}

/*************************************************************************

**

** OleStdSetStringProperty

**

** Purpose:

**    Set a String Propety

**    (takes zero terminated string -- C string)

**

** Parameters:

**    LPSUMINFO FAR *lp             - pointer to open Summary Info struct

**    DWORD pid                     - ID of String Property

**    LPSTR lpsz                    - new value for String Property.

**                                      zero terminated string -- C string.

**                                      May be NULL, in which case the

**                                      propery is cleared.

**

** Return Value:

**    int                           - 1 if successful

**                                  - 0 invalid property id

**

** Comments:

**    The input string is copied.

**

*************************************************************************/

STDAPI_(int) OleStdSetStringProperty(LPSUMINFO lp, DWORD pid, LPSTR lpsz)

{

LPRSI lprsi=(LPRSI)lp;

STANDARDSECINMEM FAR* lpSSIM=(STANDARDSECINMEM FAR*)&((LPRSI)lp)->section;

int i;

if (pid==PID_APPNAME) {

pid = MAXSTDZ-1;

} else if (pid<PID_TITLE || pid>PID_REVNUMBER) return 0; else pid -= 2;

ASSERT(lpSSIM);

if (lpSSIM->rglpsz[pid]) MemFree(lpSSIM->rglpsz[pid]);

if ((lpsz==NULL)||(*lpsz==0)) {

lpSSIM->rglpsz[pid] = NULL;

return (1);

}

i = _fstrlen(lpsz);

lpSSIM->rglpsz[pid] = (STDZ FAR*)MemAlloc(i+1/*null*/+sizeof(DWORD)*2);

if (lpSSIM->rglpsz[pid]==NULL) return 0;

_fstrcpy((LPSTR)&lpSSIM->rglpsz[pid]->rgchars, lpsz);

lpSSIM->rglpsz[pid]->vtType = VT_LPSTR;

lpSSIM->rglpsz[pid]->vtByteCount = 0;

lpSSIM->rglpsz[pid]->VTCB = i;

return (1);

}

/*************************************************************************

**

** OleStdGetStringZProperty

**

** Purpose:

**    Retrieve a String Propety.

**    (returns zero-terminated with leading byte count string)

**

** Parameters:

**    LPSUMINFO FAR *lp             - pointer to open Summary Info struct

**    DWORD pid                     - ID of Property

**

** Return Value:

**    LPSTZR                        - value of String Property

**                                      (zero-terminated with leading

**                                      byte count)

**

** Comments:

**    String should NOT be freed by caller. Memory for string will be

**    freed when OleStdFreeSummaryInfo is called.

*************************************************************************/

STDAPI_(LPSTZR) OleStdGetStringZProperty(LPSUMINFO lp, DWORD pid)

{

STANDARDSECINMEM FAR *lpSSIM=(STANDARDSECINMEM FAR*)&((LPRSI)lp)->section;

if (pid==PID_APPNAME) {

pid = MAXSTDZ-1;

} else if (pid<PID_TITLE || pid>PID_REVNUMBER) return NULL; else pid -= 2;

if (lpSSIM->rglpsz[pid]!=NULL) {

return (LPSTR)&lpSSIM->rglpsz[pid]->VTCB;

}

return NULL;

}

/*************************************************************************

**

** OleStdGetDocProperty

**

** Purpose:

**    Retrieve document properties (no. pages, no. words, no. characters)

**

** Parameters:

**    LPSUMINFO FAR *lp             - pointer to open Summary Info struct

**    DWORD FAR *nPage              - (OUT) number of pages in document

**    DWORD FAR *nWords             - (OUT) number of words in document

**    DWORD FAR *nChars             - (OUT) number of charactrs in doc

**

** Return Value:

**    void

**

** Comments:

**

*************************************************************************/

STDAPI_(void) OleStdGetDocProperty(

LPSUMINFO       lp,

DWORD FAR*      nPage,

DWORD FAR*      nWords,

DWORD FAR*      nChars

)

{

STANDARDSECINMEM FAR *lpSSIM=(STANDARDSECINMEM FAR*)&((LPRSI)lp)->section;

*nPage=0; *nWords=0; *nChars=0;

if (lpSSIM->rgInts[0].vtType == VT_I4) *nPage = lpSSIM->rgInts[0].value;

if (lpSSIM->rgInts[1].vtType == VT_I4) *nWords = lpSSIM->rgInts[1].value;

if (lpSSIM->rgInts[2].vtType == VT_I4) *nChars = lpSSIM->rgInts[2].value;

}

/*************************************************************************

**

** OleStdSetDocProperty

**

** Purpose:

**    Set document properties (no. pages, no. words, no. characters)

**

** Parameters:

**    LPSUMINFO FAR *lp             - pointer to open Summary Info struct

**    DWORD nPage                   - number of pages in document

**    DWORD nWords                  - number of words in document

**    DWORD nChars                  - number of charactrs in doc

**

** Return Value:

**    int                           - 1 for success

**                                  - 0 if error occurs

**                                    (there are no errors)

**

** Comments:

**

*************************************************************************/

STDAPI_(int) OleStdSetDocProperty(

LPSUMINFO       lp,

DWORD           nPage,

DWORD           nWords,

DWORD           nChars

)

{

DWORD vttype=VT_I4;

STANDARDSECINMEM FAR *lpSSIM=(STANDARDSECINMEM FAR*)&((LPRSI)lp)->section;

if ((nPage|nWords|nChars)==0) {

vttype = VT_EMPTY;

nPage=0; nWords=0; nChars=0;

}

lpSSIM->rgInts[0].vtType = vttype;

lpSSIM->rgInts[1].vtType = vttype;

lpSSIM->rgInts[2].vtType = vttype;

lpSSIM->rgInts[0].value = nPage;

lpSSIM->rgInts[1].value = nWords;

lpSSIM->rgInts[2].value = nChars;

return 1;

}

/*************************************************************************

**

** OleStdGetThumbNailProperty

**

** Purpose:

**    Retrieve a Thumbnail Property

**

** Parameters:

**    LPSTREAM lps

**    LPSUMINFO FAR *lp             - pointer to open Summary Info struct

**    DWORD FAR* clipFormatNo       - clipboard format for thumbnail

**                                      (type of value depends on vtcf

**                                      return value.)

**                                      NOTE: ONLY VT_CF_WIN is

**                                      implemented, so clipFormatNo

**                                      will be CF_METAFILEPICT

**    LPSTR FAR* lpszName           - format name if VT_CF_NAME is

**                                      returned

**                                      NOTE: NOT IMPLEMENTED

**    THUMBNAIL FAR* clip           - handle to thumbnail

**                                      for VT_CF_WIN clip will be

**                                      handle to MetafilePict

**                                      NOTE: only VT_CF_WIN IMPLEMENTED

**    DWORD FAR* byteCount          - size of thumbnail stream

**                                      for VT_CF_WIN case this should

**                                      be combined size of both the

**                                      Metafile as well as the

**                                      MetafilePict structure.

**    BOOL transferClip             - transfer ownership of thumbnail

**                                      to caller. (see comment)

**

** Return Value:

**    int vtcfNo                    - OLE thumbnail selector value

**      VT_CF_WIN                   - Windows thumbnail

**                                      (interpret clipFormatNo as

**                                      Windows clipboard format)

**      VT_CF_FMTID                 - (NOT IMPLEMENTED)

**                                      thumbnail format is specified

**                                      by ID. use clipFormatNo.

**                                      (but NOT a Windows format ID)

**

**      VT_CF_NAME                  - (NOT IMPLEMENTED)

**                                      thumbnail format is specified

**                                      by name. use lpszName.

**      VT_CF_EMPTY                 - blank thumbnail

**                                      (clip will be NULL)

**      VT_CF_OOM                   - Memory allocation failure

**

** Comments:

**    NOTE: Currently there is only proper support for VT_CF_WIN.

**    OleStdSetThumbNailProperty does implement VT_CF_FMTID and VT_CF_NAME,

**    however, OleStdGetThumbNailProperty, OleStdReadSummaryInfo and

**    OleStdWriteSummaryInfo only support VT_CF_WIN.

**

**    Note that on input, the thumbnail is read on demand while all the

**    other properties are pre-loaded.  The thumbnail is manipulated as

**    a windows handle to a METAFILEPICT structure, which in turn

**    contains a handle to the METAFILE.  The transferClip argument on

**    GetThumbNail, when set to true, transfers responsibility for

**    storage management of the thumbnail to the caller; that is, after

**    OleStdFreeSummaryInfo has been called, the handle is still valid.

*************************************************************************/

STDAPI_(int) OleStdGetThumbNailProperty(

LPSTREAM        lps,

LPSUMINFO       lp,

DWORD FAR*      clipFormatNo,

LPSTR FAR*      lpszName,

THUMBNAIL FAR*  clip,

DWORD FAR*      byteCount,

BOOL            transferClip

)

{

int i;

LPRSI lprsi=(LPRSI)lp;

STANDARDSECINMEM FAR *lpSSIM=(STANDARDSECINMEM FAR*)&((LPRSI)lp)->section;

ULONG cbRead, cbToRead;

LARGE_INTEGER a;

ULARGE_INTEGER b;

CHAR FAR *lpst;

LPMETAFILEPICT lpmfp;

HANDLE hst, hmfp;

SCODE sc;

*byteCount = 0;

if (lpSSIM->thumb.cBytes==0) return VT_CF_EMPTY;

if (lpSSIM->thumb.lpByte==NULL) {

LISet32(a, lprsi->fileOffset);

sc = GetScode(lps->Seek(a, STREAM_SEEK_SET, &b));

if (FAILED(sc)) return VT_CF_EMPTY;

i = (int) lpSSIM->thumb.selector;

if (i>0||i==VT_CF_FMTID) {

if (i>255) return VT_CF_EMPTY;

else if (i==VT_CF_FMTID) i = sizeof(FMTID);

else lpSSIM->thumb.selector = (DWORD)VT_CF_NAME;

cbToRead = ((i+3)>>2)<<2;

lpSSIM->thumb.lpstzName=(unsigned char FAR*)MemAlloc(i+1/*n*/+1);

if (lpSSIM->thumb.lpstzName==NULL) return VT_CF_OOM;

sc = GetScode(lps->Read(lpSSIM->thumb.lpstzName+1, cbToRead, &cbRead));

if (FAILED(sc)||cbRead!=cbToRead) return VT_CF_EMPTY;

*lpSSIM->thumb.lpstzName = i;

*(lpSSIM->thumb.lpstzName+i) = 0;

lpSSIM->thumb.cBytes -= cbToRead+sizeof(DWORD);

}

i = (int) lpSSIM->thumb.selector;

cbToRead = lpSSIM->thumb.cBytes;

if (cbToRead>65535) return VT_CF_OOM;

ASSERT(i!=VT_CF_NAME);

if (i==VT_CF_WIN) {

cbToRead -= sizeof(METAFILEPICT);

hmfp = GlobalAlloc(GMEM_MOVEABLE, sizeof(METAFILEPICT));

if (hmfp==NULL) return VT_CF_OOM;

hst = GlobalAlloc(GMEM_MOVEABLE, cbToRead);

if (hst==NULL) {

GlobalFree(hmfp);

return VT_CF_OOM;

}

lpmfp = (LPMETAFILEPICT)GlobalLock(hmfp);

sc = GetScode(lps->Read(lpmfp, sizeof(METAFILEPICT), &cbRead));

if (FAILED(sc)||cbRead!=sizeof(METAFILEPICT)) {

GlobalUnlock(hmfp);

GlobalFree(hmfp);

GlobalFree(hst);

return VT_CF_EMPTY;

}

lpst = (CHAR FAR*)GlobalLock(hst);

lpmfp->hMF = (HMETAFILE)hst;

lpSSIM->thumb.lpByte = (CHAR FAR*)hmfp;

} else {

lpst = (unsigned char FAR*)MemAlloc((int)cbToRead);

if (lpst==NULL) return VT_CF_OOM;

lpSSIM->thumb.lpByte = lpst;

}

sc = GetScode(lps->Read(lpst, cbToRead, &cbRead));

if (i==VT_CF_WIN) {

GlobalUnlock(hst);

GlobalUnlock(hmfp);

}

if (FAILED(sc)||cbRead!=cbToRead) {

if (i==VT_CF_WIN) {

GlobalFree(hst);

GlobalFree(hmfp);

} else MemFree(lpst);

lpSSIM->thumb.lpByte = NULL;

if ((i==VT_CF_NAME||i==VT_CF_FMTID)&&(lpSSIM->thumb.lpstzName!=NULL))

MemFree(lpSSIM->thumb.lpstzName);

return VT_CF_EMPTY;

}

}

*clipFormatNo = lpSSIM->thumb.clipFormat;

*byteCount = lpSSIM->thumb.cBytes;

if(lpszName!=NULL)

*lpszName = (char FAR*)lpSSIM->thumb.lpstzName+1;

*clip = (char FAR*)lpSSIM->thumb.lpByte;

if (transferClip) lpSSIM->thumb.lpByte=NULL;

return (int)lpSSIM->thumb.selector;

}

/*************************************************************************

**

** OleStdSetThumbNailProperty

**

** Purpose:

**    Set a Thumbnail Property

**

** Parameters:

**    LPSTREAM lps                  - open SummaryInfo IStream*

**    LPSUMINFO FAR *lp             - pointer to open Summary Info struct

**    int vtcfNo                    - OLE thumbnail selector value

**          VT_CF_WIN                   - Windows thumbnail

**                                        (interpret clipFormatNo as

**                                        Windows clipboard format)

**          VT_CF_FMTID                 - thumbnail format is specified

**                                        by ID. use clipFormatNo.

**                                        (but NOT a Windows format ID)

**

**          VT_CF_NAME                  - thumbnail format is specified

**                                        by name. use lpszName.

**          VT_CF_EMPTY                 - blank thumbnail

**                                        (clip will be NULL)

**

**    DWORD FAR* clipFormatNo       - clipboard format for thumbnail

**                                      used if vtcfNo is VT_CF_WIN or

**                                      VT_CF_FMTID. interpretation of

**                                      value depends on vtcfNo specified.

**                                      (normally vtcfNo==VT_CF_WIN and

**                                      clipFormatNo==CF_METAFILEPICT)

**    LPSTR FAR* lpszName           - format name if vtcfNo is VT_CF_NAME

**    THUMBNAIL clip                - handle to thumbnail

**                                      for VT_CF_WIN clip will be

**                                      handle to MetafilePict

**    DWORD FAR* byteCount          - size of thumbnail stream

**                                      for VT_CF_WIN case this should

**                                      be combined size of both the

**                                      Metafile as well as the

**                                      MetafilePict structure.

**

** Return Value:

**    int                           - 1 for success

**                                  - 0 if error occurs

**

** Comments:

**    NOTE: Currently there is only proper support for VT_CF_WIN.

**    OleStdSetThumbNailProperty does implement VT_CF_FMTID and VT_CF_NAME,

**    however, OleStdGetThumbNailProperty, OleStdReadSummaryInfo and

**    OleStdWriteSummaryInfo only support VT_CF_WIN.

**

**    This function copies lpszName but saves the "clip" handle passed.

**

**    NOTE: overwriting or emptying frees space for clip and name.

**    The thumbnail is manipulated as a windows handle to a

**    METAFILEPICT structure, which in turn contains a handle to the

**    METAFILE.

*************************************************************************/

STDAPI_(int) OleStdSetThumbNailProperty(

LPSTREAM        lps,

LPSUMINFO       lp,

int             vtcfNo,

DWORD           clipFormatNo,

LPSTR           lpszName,

THUMBNAIL       clip,

DWORD           byteCount

)

{

int i;

LPRSI lprsi=(LPRSI)lp;

STANDARDSECINMEM FAR *lpSSIM=(STANDARDSECINMEM FAR*)&((LPRSI)lp)->section;

LPMETAFILEPICT lpmfp;

if (lpSSIM==NULL||vtcfNo>0||vtcfNo<VT_CF_EMPTY||(vtcfNo==VT_CF_NAME&&(lpszName==NULL||*lpszName==0))) {

return 0;

}

if (vtcfNo!=VT_CF_EMPTY&&(clip==0||byteCount==0)) return 0;

i = (int) lpSSIM->thumb.vtType;

if (i!=VT_EMPTY) {

i = (int) lpSSIM->thumb.selector;

ASSERT(i!=VT_CF_NAME);

if (i==VT_CF_WIN) {

if (lpSSIM->thumb.lpByte!=NULL) {

lpmfp = (LPMETAFILEPICT)GlobalLock((HANDLE)(DWORD)lpSSIM->thumb.lpByte);

GlobalFree(lpmfp->hMF);

GlobalUnlock((HANDLE)(DWORD)lpSSIM->thumb.lpByte);

GlobalFree((HANDLE)(DWORD)lpSSIM->thumb.lpByte);

}

} else {

MemFree(lpSSIM->thumb.lpByte);

}

if ((i==VT_CF_NAME||i==VT_CF_FMTID)&&(lpSSIM->thumb.lpstzName!=NULL))

MemFree(lpSSIM->thumb.lpstzName);

lpSSIM->thumb.lpstzName = NULL;

lpSSIM->thumb.lpByte = NULL;

}

if (vtcfNo==VT_CF_EMPTY) {

lpSSIM->thumb.vtType = VT_EMPTY;

lpSSIM->thumb.cBytes = 0;

} else {

lpSSIM->thumb.vtType = VT_CF;

lpSSIM->thumb.selector = vtcfNo;

lpSSIM->thumb.cBytes = byteCount;

lpSSIM->thumb.clipFormat = clipFormatNo;

lpSSIM->thumb.lpByte = (unsigned char FAR*)clip;    //just save the hnadle

if (vtcfNo==VT_CF_NAME||vtcfNo==VT_CF_FMTID) {

i = _fstrlen(lpszName);

if (vtcfNo==VT_CF_FMTID) ASSERT(i==sizeof(FMTID));

lpSSIM->thumb.lpstzName =

(unsigned char FAR*)MemAlloc(i+1/*n*/+1/*null*/);

if (lpSSIM->thumb.lpstzName==NULL) {

lpSSIM->thumb.vtType = VT_EMPTY;

return 0;

}

_fstrcpy((char FAR*)lpSSIM->thumb.lpstzName+1, lpszName);

*lpSSIM->thumb.lpstzName = i;

}

}

return 1;

}

/*************************************************************************

**

** OleStdGetDateProperty

**

** Purpose:

**    Retrieve Data Property

**

** Parameters:

**    LPSUMINFO FAR *lp             - pointer to open Summary Info struct

**    DWORD pid                     - ID of Property

**    int FAR *yr                   - (OUT) year

**    int FAR *mo                   - (OUT) month

**    int FAR *dy                   - (OUT) day

**    DWORD FAR *sc                 - (OUT) seconds

**

** Return Value:

**    void

**

** Comments:

**

*************************************************************************/

STDAPI_(void) OleStdGetDateProperty(

LPSUMINFO       lp,

DWORD           pid,

int FAR*        yr,

int FAR*        mo,

int FAR*        dy,

DWORD FAR*      sc

)

{

STANDARDSECINMEM FAR *lpSSIM=(STANDARDSECINMEM FAR*)&((LPRSI)lp)->section;

SFFS sffs;

pid -= PID_EDITTIME;

*yr = 0; *mo = 0; *dy = 0; *sc = 0;

if (pid<0||pid>=MAXTIME) return;

if (lpSSIM->rgTime[pid].vtType == VT_FILETIME) {

if (pid==0) {

//convert from 100ns to seconds

ulargeDivide((ULARGE_INTEGER FAR*)&lpSSIM->rgTime[0].time, 10000);

ulargeDivide((ULARGE_INTEGER FAR*)&lpSSIM->rgTime[0].time, 1000);

pid = lpSSIM->rgTime[0].time.dwLowDateTime;

*sc = pid%((DWORD)60*60*24);

pid /= (DWORD)60*60*24;

*dy = (int)(pid%(DWORD)30);

pid /= (DWORD)30;

*mo = (int)(pid%(DWORD)12);

*yr = (int)(pid/(DWORD)12);

} else {

if (CoFileTimeToDosDateTime(&lpSSIM->rgTime[pid].time,

&sffs.dateVariable, &sffs.timeVariable)) {

*yr = sffs.yr+1980;

*mo = sffs.mon;

*dy = sffs.dom;

*sc = (DWORD)sffs.hr*3600+sffs.mint*60+sffs.sec*2;

}

}

}

return;

}

/*************************************************************************

**

** OleStdSetDateProperty

**

** Purpose:

**    Set Data Property

**

** Parameters:

**    LPSUMINFO FAR *lp             - pointer to open Summary Info struct

**    DWORD pid                     - ID of Property

**    int yr                        - year

**    int mo                        - month

**    int dy                        - day

**    DWORD sc                      - seconds

**

** Return Value:

**    int                           - 1 for success

**                                  - 0 if error occurs

**

** Comments:

**    Use all zeros to clear.

**    The following is an example of valid input:

**          yr=1993 mo=1(Jan) dy=1(1st) hr=12(noon) mn=30 sc=23

**    for PID_EDITTIME property, the values are a zero-origin duration

**    of time.

**

*************************************************************************/

STDAPI_(int) OleStdSetDateProperty(

LPSUMINFO       lp,

DWORD           pid,

int             yr,

int             mo,

int             dy,

int             hr,

int             mn,

int             sc

)

{

STANDARDSECINMEM FAR *lpSSIM=(STANDARDSECINMEM FAR*)&((LPRSI)lp)->section;

SFFS sffs;

pid -= PID_EDITTIME;

if (pid<0||pid>=MAXTIME) return 0;

if ((yr|mo|dy|hr|mn|sc)==0) {   //all must be zero

lpSSIM->rgTime[pid].vtType = VT_EMPTY;

return 1;

}

lpSSIM->rgTime[pid].vtType = VT_FILETIME;

if (pid==0) {

lpSSIM->rgTime[0].time.dwLowDateTime =

(((((DWORD)yr*365+mo*30)+dy)*24+hr)*60+mn)*60+sc;

lpSSIM->rgTime[0].time.dwHighDateTime = 0;

//10^7 nanoseconds/second

ulargeMultiply((ULARGE_INTEGER FAR*)&lpSSIM->rgTime[0].time, 10000);

//convert to units of 100 ns

ulargeMultiply((ULARGE_INTEGER FAR*)&lpSSIM->rgTime[0].time, 1000);

} else {

sffs.yr = max(yr-1980,0);

sffs.mon = mo;

sffs.dom = dy;

sffs.hr = hr;

sffs.mint= mn;

sffs.sec = sc/2;  //dos is 2 second intervals

if (!CoDosDateTimeToFileTime(sffs.date, sffs.time,

&lpSSIM->rgTime[pid].time)) {

lpSSIM->rgTime[pid].vtType = VT_EMPTY;

return 0;

}

}

return 1;

}

} //END C


 TARGTDEV.C  (WRAPUI Sample)

/*************************************************************************

**

**    OLE 2 Standard Utilities

**

**    olestd.c

**

**    This file contains utilities that are useful for dealing with

**    target devices.

**

**    (c) Copyright Microsoft Corp. 1992 All Rights Reserved

**

*************************************************************************/

#define STRICT  1

#include "ole2ui.h"

#ifndef WIN32

#include <print.h>

#endif

/*

 * OleStdCreateDC()

 *

 * Purpose:

 *

 * Parameters:

 *

 * Return Value:

 *    SCODE  -  S_OK if successful

 */

STDAPI_(HDC) OleStdCreateDC(DVTARGETDEVICE FAR* ptd)

{

HDC hdc=NULL;

LPDEVNAMES lpDevNames;

LPDEVMODE lpDevMode;

LPSTR lpszDriverName;

LPSTR lpszDeviceName;

LPSTR lpszPortName;

if (ptd == NULL) {

hdc = CreateDC("DISPLAY", NULL, NULL, NULL);

goto errReturn;

}

lpDevNames = (LPDEVNAMES) ptd; // offset for size field

if (ptd->tdExtDevmodeOffset == 0) {

lpDevMode = NULL;

}else{

lpDevMode  = (LPDEVMODE) ((LPSTR)ptd + ptd->tdExtDevmodeOffset);

}

lpszDriverName = (LPSTR) lpDevNames + ptd->tdDriverNameOffset;

lpszDeviceName = (LPSTR) lpDevNames + ptd->tdDeviceNameOffset;

lpszPortName   = (LPSTR) lpDevNames + ptd->tdPortNameOffset;

hdc = CreateDC(lpszDriverName, lpszDeviceName, lpszPortName, lpDevMode);

errReturn:

return hdc;

}

/*

 * OleStdCreateIC()

 *

 * Purpose: Same as OleStdCreateDC, except that information context is

 *          created, rather than a whole device context.  (CreateIC is

 *          used rather than CreateDC).

 *          OleStdDeleteDC is still used to delete the information context.

 *

 * Parameters:

 *

 * Return Value:

 *    SCODE  -  S_OK if successful

 */

STDAPI_(HDC) OleStdCreateIC(DVTARGETDEVICE FAR* ptd)

{

HDC hdcIC=NULL;

LPDEVNAMES lpDevNames;

LPDEVMODE lpDevMode;

LPSTR lpszDriverName;

LPSTR lpszDeviceName;

LPSTR lpszPortName;

if (ptd == NULL) {

hdcIC = CreateIC("DISPLAY", NULL, NULL, NULL);

goto errReturn;

}

lpDevNames = (LPDEVNAMES) ptd; // offset for size field

lpDevMode  = (LPDEVMODE) ((LPSTR)ptd + ptd->tdExtDevmodeOffset);

lpszDriverName = (LPSTR) lpDevNames + ptd->tdDriverNameOffset;

lpszDeviceName = (LPSTR) lpDevNames + ptd->tdDeviceNameOffset;

lpszPortName   = (LPSTR) lpDevNames + ptd->tdPortNameOffset;

hdcIC = CreateIC(lpszDriverName, lpszDeviceName, lpszPortName, lpDevMode);

errReturn:

return hdcIC;

}

/*

 * OleStdCreateTargetDevice()

 *

 * Purpose:

 *

 * Parameters:

 *

 * Return Value:

 *    SCODE  -  S_OK if successful

 */

STDAPI_(DVTARGETDEVICE FAR*) OleStdCreateTargetDevice(LPPRINTDLG lpPrintDlg)

{

DVTARGETDEVICE FAR* ptd=NULL;

LPDEVNAMES lpDevNames, pDN;

LPDEVMODE lpDevMode, pDM;

UINT nMaxOffset;

LPSTR pszName;

DWORD dwDevNamesSize, dwDevModeSize, dwPtdSize;

if ((pDN = (LPDEVNAMES)GlobalLock(lpPrintDlg->hDevNames)) == NULL) {

goto errReturn;

}

if ((pDM = (LPDEVMODE)GlobalLock(lpPrintDlg->hDevMode)) == NULL) {

goto errReturn;

}

nMaxOffset =  (pDN->wDriverOffset > pDN->wDeviceOffset) ?

pDN->wDriverOffset : pDN->wDeviceOffset ;

nMaxOffset =  (pDN->wOutputOffset > nMaxOffset) ?

pDN->wOutputOffset : nMaxOffset ;

pszName = (LPSTR)pDN + nMaxOffset;

dwDevNamesSize = (DWORD)(nMaxOffset+lstrlen(pszName) + 1/* NULL term */);

dwDevModeSize = (DWORD) (pDM->dmSize + pDM->dmDriverExtra);

dwPtdSize = sizeof(DWORD) + dwDevNamesSize + dwDevModeSize;

if ((ptd = (DVTARGETDEVICE FAR*)OleStdMalloc(dwPtdSize)) != NULL) {

// copy in the info

ptd->tdSize = (UINT)dwPtdSize;

lpDevNames = (LPDEVNAMES) &ptd->tdDriverNameOffset;

_fmemcpy(lpDevNames, pDN, (size_t)dwDevNamesSize);

lpDevMode=(LPDEVMODE)((LPSTR)&ptd->tdDriverNameOffset+dwDevNamesSize);

_fmemcpy(lpDevMode, pDM, (size_t)dwDevModeSize);

ptd->tdDriverNameOffset += 4 ;

ptd->tdDeviceNameOffset += 4 ;

ptd->tdPortNameOffset   += 4 ;

ptd->tdExtDevmodeOffset = (UINT)dwDevNamesSize + 4 ;

}

errReturn:

GlobalUnlock(lpPrintDlg->hDevNames);

GlobalUnlock(lpPrintDlg->hDevMode);

return ptd;

}

/*

 * OleStdDeleteTargetDevice()

 *

 * Purpose:

 *

 * Parameters:

 *

 * Return Value:

 *    SCODE  -  S_OK if successful

 */

STDAPI_(BOOL) OleStdDeleteTargetDevice(DVTARGETDEVICE FAR* ptd)

{

BOOL res=TRUE;

if (ptd != NULL) {

OleStdFree(ptd);

}

return res;

}

/*

 * OleStdCopyTargetDevice()

 *

 * Purpose:

 *  duplicate a TARGETDEVICE struct. this function allocates memory for

 *  the copy. the caller MUST free the allocated copy when done with it

 *  using the standard allocator returned from CoGetMalloc.

 *  (OleStdFree can be used to free the copy).

 *

 * Parameters:

 *  ptdSrc      pointer to source TARGETDEVICE

 *

 * Return Value:

 *    pointer to allocated copy of ptdSrc

 *    if ptdSrc==NULL then retuns NULL is returned.

 *    if ptdSrc!=NULL and memory allocation fails, then NULL is returned

 */

STDAPI_(DVTARGETDEVICE FAR*) OleStdCopyTargetDevice(DVTARGETDEVICE FAR* ptdSrc)

{

  DVTARGETDEVICE FAR* ptdDest = NULL;

  if (ptdSrc == NULL) {

return NULL;

  }

  if ((ptdDest = (DVTARGETDEVICE FAR*)OleStdMalloc(ptdSrc->tdSize)) != NULL) {

_fmemcpy(ptdDest, ptdSrc, (size_t)ptdSrc->tdSize);

  }

  return ptdDest;

}

/*

 * OleStdCopyFormatEtc()

 *

 * Purpose:

 *  Copies the contents of a FORMATETC structure. this function takes

 *  special care to copy correctly copying the pointer to the TARGETDEVICE

 *  contained within the source FORMATETC structure.

 *  if the source FORMATETC has a non-NULL TARGETDEVICE, then a copy

 *  of the TARGETDEVICE will be allocated for the destination of the

 *  FORMATETC (petcDest).

 *

 *  OLE2NOTE: the caller MUST free the allocated copy of the TARGETDEVICE

 *  within the destination FORMATETC when done with it

 *  using the standard allocator returned from CoGetMalloc.

 *  (OleStdFree can be used to free the copy).

 *

 * Parameters:

 *  petcDest      pointer to destination FORMATETC

 *  petcSrc       pointer to source FORMATETC

 *

 * Return Value:

 *    returns TRUE is copy is successful; retuns FALSE if not successful

 */

STDAPI_(BOOL) OleStdCopyFormatEtc(LPFORMATETC petcDest, LPFORMATETC petcSrc)

{

  if ((petcDest == NULL) || (petcSrc == NULL)) {

return FALSE;

  }

  petcDest->cfFormat = petcSrc->cfFormat;

  petcDest->ptd      = OleStdCopyTargetDevice(petcSrc->ptd);

  petcDest->dwAspect = petcSrc->dwAspect;

  petcDest->lindex   = petcSrc->lindex;

  petcDest->tymed    = petcSrc->tymed;

  return TRUE;

}

// returns 0 for exact match, 1 for no match, -1 for partial match (which is

// defined to mean the left is a subset of the right: fewer aspects, null target

// device, fewer medium).

STDAPI_(int) OleStdCompareFormatEtc(FORMATETC FAR* pFetcLeft, FORMATETC FAR* pFetcRight)

{

BOOL bExact = TRUE;

if (pFetcLeft->cfFormat != pFetcRight->cfFormat)

return 1;

else if (!OleStdCompareTargetDevice (pFetcLeft->ptd, pFetcRight->ptd))

return 1;

if (pFetcLeft->dwAspect == pFetcRight->dwAspect)

// same aspects; equal

;

else if ((pFetcLeft->dwAspect & ~pFetcRight->dwAspect) != 0)

// left not subset of aspects of right; not equal

return 1;

else

// left subset of right

bExact = FALSE;

if (pFetcLeft->tymed == pFetcRight->tymed)

// same medium flags; equal

;

else if ((pFetcLeft->tymed & ~pFetcRight->tymed) != 0)

// left not subset of medium flags of right; not equal

return 1;

else

// left subset of right

bExact = FALSE;

return bExact ? 0 : -1;

}

STDAPI_(BOOL) OleStdCompareTargetDevice

(DVTARGETDEVICE FAR* ptdLeft, DVTARGETDEVICE FAR* ptdRight)

{

if (ptdLeft == ptdRight)

// same address of td; must be same (handles NULL case)

return TRUE;

else if ((ptdRight == NULL) || (ptdLeft == NULL))

return FALSE;

else if (ptdLeft->tdSize != ptdRight->tdSize)

// different sizes, not equal

return FALSE;

#ifdef WIN32

else if (memcmp(ptdLeft, ptdRight, ptdLeft->tdSize) != 0)

#else

else if (_fmemcmp(ptdLeft, ptdRight, (int)ptdLeft->tdSize) != 0)

#endif

// not same target device, not equal

return FALSE;

return TRUE;

}


 TEMPLATE.H  (WRAPUI Sample)

/*

 * TEMPLATE.H

 *

 * CUSTOMIZATION INSTRUCTIONS:

 *

 * Copyright (c)1992 Microsoft Corporation, All Right Reserved

 *

 *

 *  1.  Replace <FILE> with the uppercased filename for this file.

 *      Lowercase the <FILE>.h entry

 *

 *  2.  Replace <NAME> with the mixed case dialog name in one word,

 *      such as InsertObject

 *

 *  3.  Replace <FULLNAME> with the mixed case dialog name in multiple

 *      words, such as Insert Object

 *

 *  4.  Replace <ABBREV> with the suffix for pointer variables, such

 *      as the IO in InsertObject's pIO or the CI in ChangeIcon's pCI.

 *      Check the alignment of the first variable declaration in the

 *      Dialog Proc after this.  I will probably be misaligned with the

 *      rest of the variables.

 *

 *  5.  Replace <STRUCT> with the uppercase structure name for this

 *      dialog sans OLEUI, such as INSERTOBJECT.  Changes OLEUI<STRUCT>

 *      in most cases, but we also use this for IDD_<STRUCT> as the

 *      standard template resource ID.

 *

 *  6.  Find <UFILL> fields and fill them out with whatever is appropriate.

 *

 *  7.  Delete this header up to the start of the next comment.

 *

 */

/*

 * <FILE>.H

 *

 * Internal definitions, structures, and function prototypes for the

 * OLE 2.0 UI <FULLNAME> dialog.

 *

 * Copyright (c)1992 Microsoft Corporation, All Right Reserved

 */

#ifndef <UFILL>

#define <UFILL>

//UFILL>  Move from here to INTERNAL to to OLE2UI.H

typedef struct tagOLEUI<STRUCT>

{

//These IN fields are standard across all OLEUI dialog functions.

DWORD           cbStruct;       //Structure Size

DWORD           dwFlags;        //IN-OUT:  Flags

HWND            hWndOwner;      //Owning window

LPCSTR          lpszCaption;    //Dialog caption bar contents

LPFNOLEUIHOOK   lpfnHook;       //Hook callback

LPARAM          lCustData;      //Custom data to pass to hook

HINSTANCE       hInstance;      //Instance for customized template name

LPCSTR          lpszTemplate;   //Customized template name

HRSRC           hResource;      //Customized template handle

//Specifics for OLEUI<STRUCT>.  All are IN-OUT unless otherwise spec.

} OLEUI<STRUCT>, *POLEUI<STRUCT>, FAR *LPOLEUI<STRUCT>;

//API Prototype

UINT FAR PASCAL OleUI<NAME>(LPOLEUI<STRUCT>);

//<FULLNAME> flags

#define <ABBREV>F_SHOWHELP                0x00000001L

<UFILL>

//<FULLNAME> specific error codes

//DEFINE AS OLEUI_<ABBREV>ERR_<ERROR>     (OLEUI_ERR_STANDARDMAX+n)

<UFILL>

//<FULLNAME> Dialog identifiers

//FILL IN DIALOG IDs HERE

<UFILL>

//INTERNAL INFORMATION STARTS HERE

//Internally used structure

typedef struct tag<STRUCT>

{

//Keep this item first as the Standard* functions depend on it here.

LPOLEUI<STRUCT>     lpO<ABBREV>;       //Original structure passed.

/*

 * What we store extra in this structure besides the original caller's

 * pointer are those fields that we need to modify during the life of

 * the dialog but that we don't want to change in the original structure

 * until the user presses OK.

 */

<UFILL>

} <STRUCT>, *P<STRUCT>;

//Internal function prototypes

//<FILE>.C

BOOL FAR PASCAL <NAME>DialogProc(HWND, UINT, WPARAM, LPARAM);

BOOL            F<NAME>Init(HWND hDlg, WPARAM, LPARAM);

<UFILL>

#endif //<UFILL>


 TEMPLATE.C  (WRAPUI Sample)

/*

 * TEMPLATE.C

 *

 * Copyright (c)1992 Microsoft Corporation, All Right Reserved

 *

 *

 * CUSTOMIZATION INSTRUCTIONS:

 *

 *  1.  Replace <FILE> with the uppercased filename for this file.

 *      Lowercase the <FILE>.h entry

 *

 *  2.  Replace <NAME> with the mixed case dialog name in one word,

 *      such as InsertObject

 *

 *  3.  Replace <FULLNAME> with the mixed case dialog name in multiple

 *      words, such as Insert Object

 *

 *  4.  Replace <ABBREV> with the suffix for pointer variables, such

 *      as the IO in InsertObject's pIO or the CI in ChangeIcon's pCI.

 *      Check the alignment of the first variable declaration in the

 *      Dialog Proc after this.  I will probably be misaligned with the

 *      rest of the variables.

 *

 *  5.  Replace <STRUCT> with the uppercase structure name for this

 *      dialog sans OLEUI, such as INSERTOBJECT.  Changes OLEUI<STRUCT>

 *      in most cases, but we also use this for IDD_<STRUCT> as the

 *      standard template resource ID.

 *

 *  6.  Find <UFILL> fields and fill them out with whatever is appropriate.

 *

 *  7.  Delete this header up to the start of the next comment.

 */

/*

 * <FILE>.C

 *

 * Implements the OleUI<NAME> function which invokes the complete

 * <FULLNAME> dialog.

 *

 * Copyright (c)1992 Microsoft Corporation, All Right Reserved

 */

#define STRICT  1

#include "ole2ui.h"

#include "common.h"

#include "<FILE>.h"

/*

 * OleUI<NAME>

 *

 * Purpose:

 *  Invokes the standard OLE <FULLNAME> dialog box allowing the user

 *  to <UFILL>

 *

 * Parameters:

 *  lp<ABBREV>            LPOLEUI<NAME> pointing to the in-out structure

 *                  for this dialog.

 *

 * Return Value:

 *  UINT            One of the following codes, indicating success or error:

 *                      OLEUI_SUCCESS           Success

 *                      OLEUI_ERR_STRUCTSIZE    The dwStructSize value is wrong

 */

STDAPI_(UINT) OleUI<NAME>(LPOLEUI<STRUCT> lp<ABBREV>)

{

UINT        uRet;

HGLOBAL     hMemDlg=NULL;

uRet=UStandardValidation((LPOLEUISTANDARD)lp<ABBREV>, sizeof(OLEUI<STRUCT>)

 , &hMemDlg);

if (OLEUI_SUCCESS!=uRet)

return uRet;

/*

 * PERFORM ANY STRUCTURE-SPECIFIC VALIDATION HERE!

 * ON FAILURE:

 *  {

 *  if (NULL!=hMemDlg)

 *      FreeResource(hMemDlg)

 *

 *  return OLEUI_<ABBREV>ERR_<ERROR>

 *  }

 */

//Now that we've validated everything, we can invoke the dialog.

uRet=UStandardInvocation(<NAME>DialogProc, (LPOLEUISTANDARD)lp<ABBREV>

 , hMemDlg, MAKEINTRESOURCE(IDD_<STRUCT>));

/*

 * IF YOU ARE CREATING ANYTHING BASED ON THE RESULTS, DO IT HERE.

 */

<UFILL>

return uRet;

}

/*

 * <NAME>DialogProc

 *

 * Purpose:

 *  Implements the OLE <FULLNAME> dialog as invoked through the

 *  OleUI<NAME> function.

 *

 * Parameters:

 *  Standard

 *

 * Return Value:

 *  Standard

 */

BOOL CALLBACK EXPORT <NAME>DialogProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)

{

P<STRUCT>               p<ABBREV>;

BOOL                    fHook=FALSE;

//Declare Win16/Win32 compatible WM_COMMAND parameters.

COMMANDPARAMS(wID, wCode, hWndMsg);

//This will fail under WM_INITDIALOG, where we allocate it.

p<ABBREV>=(<STRUCT>)PvStandardEntry(hDlg, iMsg, wParam, lParam, &uHook);

//If the hook processed the message, we're done.

if (0!=uHook)

return (BOOL)uHook;

//Process the temination message

if (iMsg==uMsgEndDialog)

{

//Free any specific allocations before calling StandardCleanup

StandardCleanup((PVOID)p<ABBREV>, hDlg);

EndDialog(hDlg, wParam);

return TRUE;

}

switch (iMsg)

{

case WM_INITDIALOG:

F<NAME>Init(hDlg, wParam, lParam);

return TRUE;

case WM_COMMAND:

switch (wID)

{

case IDOK:

/*

 * PERFORM WHATEVER FUNCTIONS ARE DEFAULT HERE.

 */

SendMessage(hDlg, uMsgEndDialog, OLEUI_OK, 0L);

break;

case IDCANCEL:

/*

 * PERFORM ANY UNDOs HERE, BUT NOT CLEANUP THAT WILL

 * ALWAYS HAPPEN WHICH SHOULD BE IN uMsgEndDialog.

 */

SendMessage(hDlg, uMsgEndDialog, OLEUI_CANCEL, 0L);

break;

case ID_OLEUIHELP:

PostMessage(p<ABBREV>->lpO<ABBREV>->hWndOwner, uMsgHelp

, (WPARAM)hDlg, MAKELPARAM(IDD_<STRUCT>, 0));

break;

}

break;

}

return FALSE;

}

/*

 * F<NAME>Init

 *

 * Purpose:

 *  WM_INITIDIALOG handler for the <FULLNAME> dialog box.

 *

 * Parameters:

 *  hDlg            HWND of the dialog

 *  wParam          WPARAM of the message

 *  lParam          LPARAM of the message

 *

 * Return Value:

 *  BOOL            Value to return for WM_INITDIALOG.

 */

BOOL F<NAME>Init(HWND hDlg, WPARAM wParam, LPARAM lParam)

{

P<STRUCT>               p<ABBREV>;

LPOLEUI<STRUCT>         lpO<ABBREV>;

HFONT                   hFont;

//1.  Copy the structure at lParam into our instance memory.

p<ABBREV>=(PSTRUCT)PvStandardInit(hDlg, sizeof(<STRUCT>), TRUE, &hFont);

//PvStandardInit send a termination to us already.

if (NULL==p<ABBREV>)

return FALSE;

lpO<ABBREV>=(LPOLEUI<STRUCT>)lParam);

p<ABBREV>->lpO<ABBREV>=lpO<ABBREV>;

//Copy other information from lpO<ABBREV> that we might modify.

<UFILL>

//2.  If we got a font, send it to the necessary controls.

if (NULL!=hFont)

{

//Do this for as many controls as you need it for.

SendDlgItemMessage(hDlg, ID_<UFILL>, WM_SETFONT, (WPARAM)hFont, 0L);

}

//3.  Show or hide the help button

if (!(p<ABBREV>->lpO<ABBREV>->dwFlags & <ABBREV>F_SHOWHELP))

StandardShowDlgItem(hDlg, ID_OLEUIHELP, SW_HIDE);

/*

 * PERFORM OTHER INITIALIZATION HERE.  ON ANY LoadString

 * FAILURE POST OLEUI_MSG_ENDDIALOG WITH OLEUI_ERR_LOADSTRING.

 */

//n.  Call the hook with lCustData in lParam

UStandardHook((PVOID)p<ABBREV>, hDlg, WM_INITDIALOG, wParam, lpO<ABBREV>->lCustData);

return TRUE;

}


 UTILITY.H  (WRAPUI Sample)

/*

 * UTILITY.H

 *

 * Miscellaneous prototypes and definitions for OLE UI dialogs.

 *

 * Copyright (c)1992 Microsoft Corporation, All Right Reserved

 */

#ifndef _UTILITY_H_

#define _UTILITY_H_

//Function prototypes

//UTILITY.C

HCURSOR  WINAPI HourGlassOn(void);

void     WINAPI HourGlassOff(HCURSOR);

BOOL     WINAPI Browse(HWND, LPSTR, LPSTR, UINT, UINT, UINT, DWORD);

int      WINAPI ReplaceCharWithNull(LPSTR, int);

int      WINAPI ErrorWithFile(HWND, HINSTANCE, UINT, LPSTR, UINT);

HFILE WINAPI DoesFileExist(LPSTR lpszFile, OFSTRUCT FAR* lpOpenBuf);

HICON FAR PASCAL    HIconAndSourceFromClass(REFCLSID, LPSTR, UINT FAR *);

BOOL FAR PASCAL FIconFileFromClass(REFCLSID, LPSTR, UINT, UINT FAR *);

LPSTR FAR PASCAL PointerToNthField(LPSTR, int, char);

BOOL FAR PASCAL GetAssociatedExecutable(LPSTR, LPSTR);

HICON    WINAPI HIconFromClass(LPSTR);

BOOL     WINAPI FServerFromClass(LPSTR, LPSTR, UINT);

UINT     WINAPI UClassFromDescription(LPSTR, LPSTR, UINT);

UINT     WINAPI UDescriptionFromClass(LPSTR, LPSTR, UINT);

BOOL     WINAPI FVerbGet(LPSTR, UINT, LPSTR);

LPSTR    WINAPI ChopText(HWND hwndStatic, int nWidth, LPSTR lpch);

void     WINAPI OpenFileError(HWND hDlg, UINT nErrCode, LPSTR lpszFile);

#endif //_UTILITY_H_


 UTILITY.C  (WRAPUI Sample)

/*

 * UTILITY.C

 *

 * Utility routines for functions inside OLE2UI.DLL

 *

 *  General:

 *  ----------------------

 *  HourGlassOn             Displays the hourglass

 *  HourGlassOff            Hides the hourglass

 *

 *  Misc Tools:

 *  ----------------------

 *  Browse                  Displays the "File..." or "Browse..." dialog.

 *  ReplaceCharWithNull     Used to form filter strings for Browse.

 *  ErrorWithFile           Creates an error message with embedded filename

 *  OpenFileError           Give error message for OpenFile error return

 *  ChopText                Chop a file path to fit within a specified width

 *  DoesFileExist           Checks if file is valid

 *

 *  Registration Database:

 *  ----------------------

 *  HIconFromClass          Extracts the first icon in a class's server path

 *  FServerFromClass        Retrieves the server path for a class name (fast)

 *  UClassFromDescription   Finds the classname given a description (slow)

 *  UDescriptionFromClass   Retrieves the description for a class name (fast)

 *  FGetVerb                Retrieves a specific verb for a class (fast)

 *

 *

 * Copyright (c)1992 Microsoft Corporation, All Right Reserved

 */

#define STRICT  1

#include "ole2ui.h"

#include <stdlib.h>

#include <commdlg.h>

#include <memory.h>

#include <cderr.h>

#include "common.h"

#include "utility.h"

#include "geticon.h"

#ifdef WIN32

/* 1/23/94 - define LINK_COMMDLG avoid LoadLibrary ("commdlg.dll")*/

#define LINK_COMMDLG

#endif

OLEDBGDATA

/*

 * HourGlassOn

 *

 * Purpose:

 *  Shows the hourglass cursor returning the last cursor in use.

 *

 * Parameters:

 *  None

 *

 * Return Value:

 *  HCURSOR         Cursor in use prior to showing the hourglass.

 */

HCURSOR WINAPI HourGlassOn(void)

{

HCURSOR     hCur;

hCur=SetCursor(LoadCursor(NULL, IDC_WAIT));

ShowCursor(TRUE);

return hCur;

}

/*

 * HourGlassOff

 *

 * Purpose:

 *  Turns off the hourglass restoring it to a previous cursor.

 *

 * Parameters:

 *  hCur            HCURSOR as returned from HourGlassOn

 *

 * Return Value:

 *  None

 */

void WINAPI HourGlassOff(HCURSOR hCur)

{

ShowCursor(FALSE);

SetCursor(hCur);

return;

}

/*

 * Browse

 *

 * Purpose:

 *  Displays the standard GetOpenFileName dialog with the title of

 *  "Browse."  The types listed in this dialog are controlled through

 *  iFilterString.  If it's zero, then the types are filled with "*.*"

 *  Otherwise that string is loaded from resources and used.

 *

 * Parameters:

 *  hWndOwner       HWND owning the dialog

 *  lpszFile        LPSTR specifying the initial file and the buffer in

 *                  which to return the selected file.  If there is no

 *                  initial file the first character of this string should

 *                  be NULL.

 *  lpszInitialDir  LPSTR specifying the initial directory.  If none is to

 *                  set (ie, the cwd should be used), then this parameter

 *                  should be NULL.

 *  cchFile         UINT length of pszFile

 *  iFilterString   UINT index into the stringtable for the filter string.

 *  iTitleString    UINT index into the stringtable for the title string.

 *  dwOfnFlags      DWORD flags to OR with OFN_HIDEREADONLY

 *

 * Return Value:

 *  BOOL            TRUE if the user selected a file and pressed OK.

 *                  FALSE otherwise, such as on pressing Cancel.

 */

BOOL WINAPI Browse(HWND hWndOwner, LPSTR lpszFile, LPSTR lpszInitialDir, UINT cchFile, UINT iFilterString, UINT iTitleString, DWORD dwOfnFlags)

{

   UINT           cch;

   char           szTitle[256];

   char           szFilters[256];

   OPENFILENAME   ofn;

   BOOL           fStatus;

   DWORD          dwError;

#if !defined( LINK_COMMDLG )

   HINSTANCE hinstCommDlg = NULL;

   typedef BOOL (WINAPI* LPFNGETOPENFILENAME) (OPENFILENAME FAR*);

   LPFNGETOPENFILENAME lpfnGetOpenFileName;

   typedef DWORD (WINAPI* LPFNCOMMDLGEXTENDEDERROR) (void);

   LPFNCOMMDLGEXTENDEDERROR lpfnCommDlgExtendedError;

#endif

if (NULL==lpszFile || 0==cchFile)

return FALSE;

/*

 * REVIEW:  Exact contents of the filter combobox is TBD.  One idea

 * is to take all the extensions in the RegDB and place them in here

 * with the descriptive class name associate with them.  This has the

 * extra step of finding all extensions of the same class handler and

 * building one extension string for all of them.  Can get messy quick.

 * UI demo has only *.* which we do for now.

 */

if (0!=iFilterString)

cch=LoadString(ghInst, iFilterString, (LPSTR)szFilters, sizeof(szFilters));

else

{

szFilters[0]=0;

cch=1;

}

if (0==cch)

return FALSE;

ReplaceCharWithNull(szFilters, szFilters[cch-1]);

if (0!=iTitleString)

cch=LoadString(ghInst, iTitleString, (LPSTR)szTitle, sizeof(szTitle));

else

{

szTitle[0]=0;

cch=1;

}

if (0==cch)

return FALSE;

//Prior string must also be initialized, if there is one.

_fmemset((LPOPENFILENAME)&ofn, 0, sizeof(ofn));

ofn.lStructSize =sizeof(ofn);

ofn.hwndOwner   =hWndOwner;

ofn.lpstrFile   =lpszFile;

ofn.nMaxFile    =cchFile;

ofn.lpstrFilter =(LPSTR)szFilters;

ofn.nFilterIndex=1;

ofn.lpstrTitle  =(LPSTR)szTitle;

ofn.hInstance   = ghInst;

ofn.lpTemplateName = MAKEINTRESOURCE(IDD_FILEOPEN);

if (NULL != lpszInitialDir)

  ofn.lpstrInitialDir = lpszInitialDir;

ofn.Flags= OFN_HIDEREADONLY | OFN_ENABLETEMPLATE | (dwOfnFlags) ;

#if !defined( LINK_COMMDLG )

// Load the COMMDLG.DLL library module

hinstCommDlg = LoadLibrary("COMMDLG.DLL");

if ((DWORD)hinstCommDlg <= HINSTANCE_ERROR)   /* load failed */

return FALSE;

// Retrieve the address of required functions

lpfnGetOpenFileName = (LPFNGETOPENFILENAME)

GetProcAddress(hinstCommDlg, "GetOpenFileName");

lpfnCommDlgExtendedError = (LPFNCOMMDLGEXTENDEDERROR)

GetProcAddress(hinstCommDlg, "CommDlgExtendedError");

if (lpfnGetOpenFileName == NULL || lpfnCommDlgExtendedError == NULL)

{

FreeLibrary(hinstCommDlg);

return FALSE;

}

//On success, copy the chosen filename to the static display

fStatus = (*lpfnGetOpenFileName) ((LPOPENFILENAME)&ofn);

dwError = (*lpfnCommDlgExtendedError)();

FreeLibrary(hinstCommDlg);

return fStatus;

#else

//On success, copy the chosen filename to the static display

fStatus = GetOpenFileName((LPOPENFILENAME)&ofn);

dwError = CommDlgExtendedError();

return fStatus;

#endif

}

/*

 * ReplaceCharWithNull

 *

 * Purpose:

 *  Walks a null-terminated string and replaces a given character

 *  with a zero.  Used to turn a single string for file open/save

 *  filters into the appropriate filter string as required by the

 *  common dialog API.

 *

 * Parameters:

 *  psz             LPSTR to the string to process.

 *  ch              int character to replace.

 *

 * Return Value:

 *  int             Number of characters replaced.  -1 if psz is NULL.

 */

int WINAPI ReplaceCharWithNull(LPSTR psz, int ch)

{

int             cChanged=-1;

if (NULL!=psz)

{

while (0!=*psz)

{

if (ch==*psz)

{

*psz=0;

cChanged++;

}

psz++;

}

}

return cChanged;

}

/*

 * ErrorWithFile

 *

 * Purpose:

 *  Displays a message box built from a stringtable string containing

 *  one %s as a placeholder for a filename and from a string of the

 *  filename to place there.

 *

 * Parameters:

 *  hWnd            HWND owning the message box.  The caption of this

 *                  window is the caption of the message box.

 *  hInst           HINSTANCE from which to draw the idsErr string.

 *  idsErr          UINT identifier of a stringtable string containing

 *                  the error message with a %s.

 *  lpszFile        LPSTR to the filename to include in the message.

 *  uFlags          UINT flags to pass to MessageBox, like MB_OK.

 *

 * Return Value:

 *  int             Return value from MessageBox.

 */

int WINAPI ErrorWithFile(HWND hWnd, HINSTANCE hInst, UINT idsErr

  , LPSTR pszFile, UINT uFlags)

{

int             iRet=0;

HANDLE          hMem;

const UINT      cb=(2*OLEUI_CCHPATHMAX);

LPSTR           psz1, psz2, psz3;

if (NULL==hInst || NULL==pszFile)

return iRet;

//Allocate three 2*OLEUI_CCHPATHMAX byte work buffers

hMem=GlobalAlloc(GHND, (DWORD)(3*cb));

if (NULL==hMem)

return iRet;

psz1=GlobalLock(hMem);

psz2=psz1+cb;

psz3=psz2+cb;

if (0!=LoadString(hInst, idsErr, psz1, cb))

{

wsprintf(psz2, psz1, pszFile);

//Steal the caption of the dialog

GetWindowText(hWnd, psz3, cb);

iRet=MessageBox(hWnd, psz2, psz3, uFlags);

}

GlobalUnlock(hMem);

GlobalFree(hMem);

return iRet;

}

/*

 * HIconFromClass

 *

 * Purpose:

 *  Given an object class name, finds an associated executable in the

 *  registration database and extracts the first icon from that

 *  executable.  If none is available or the class has no associated

 *  executable, this function returns NULL.

 *

 * Parameters:

 *  pszClass        LPSTR giving the object class to look up.

 *

 * Return Value:

 *  HICON           Handle to the extracted icon if there is a module

 *                  associated to pszClass.  NULL on failure to either

 *                  find the executable or extract and icon.

 */

HICON WINAPI HIconFromClass(LPSTR pszClass)

{

HICON           hIcon;

char            szEXE[OLEUI_CCHPATHMAX];

UINT            Index;

CLSID           clsid;

if (NULL==pszClass)

return NULL;

CLSIDFromString(pszClass, &clsid);

if (!FIconFileFromClass((REFCLSID)&clsid, szEXE, sizeof(szEXE), &Index))

return NULL;

hIcon=ExtractIcon(ghInst, szEXE, Index);

if ((HICON)32 > hIcon)

hIcon=NULL;

return hIcon;

}

/*

 * FServerFromClass

 *

 * Purpose:

 *  Looks up the classname in the registration database and retrieves

 *  the name under CLSID\[Local|InProc]Server.

 *

 * Parameters:

 *  pszClass        LPSTR to the classname to look up.

 *  pszEXE          LPSTR at which to store the server name

 *  cch             UINT size of pszEXE

 *

 * Return Value:

 *  BOOL            TRUE if one or more characters were loaded into pszEXE.

 *                  FALSE otherwise.

 */

BOOL WINAPI FServerFromClass(LPSTR pszClass, LPSTR pszEXE, UINT cch)

{

DWORD       dw;

LONG        lRet;

HKEY        hKey;

if (NULL==pszClass || NULL==pszEXE || 0==cch)

return FALSE;

/*

 * We have to go walking in the registration database under the

 * classname, so we first open the classname key and then check

 * under "\\LocalServer" to get the .EXE.

 */

//Open up the class key

lRet=RegOpenKey(HKEY_CLASSES_ROOT, pszClass, &hKey);

if ((LONG)ERROR_SUCCESS!=lRet)

return FALSE;

//Get the executable path.

dw=(DWORD)cch;

#ifdef WIN32

   lRet=RegQueryValue(hKey, "LocalServer32", pszEXE, &dw);

#else

   lRet=RegQueryValue(hKey, "LocalServer", pszEXE, &dw);

#endif

    if ((LONG)ERROR_SUCCESS!=lRet)

        {

        //Try InprocServer

#ifdef WIN32

        lRet=RegQueryValue(hKey, "InProcServer32", pszEXE, &dw);

#else

        lRet=RegQueryValue(hKey, "InProcServer32", pszEXE, &dw);

#endif

        }

RegCloseKey(hKey);

return ((ERROR_SUCCESS == lRet) && (dw > 0));

}

/*

 * UClassFromDescription

 *

 * Purpose:

 *  Looks up the actual OLE class name in the registration database

 *  for the given descriptive name chosen from a listbox.

 *

 * Parameters:

 *  psz             LPSTR to the descriptive name.

 *  pszClass        LPSTR in which to store the class name.

 *  cb              UINT maximum length of pszClass.

 *

 * Return Value:

 *  UINT            Number of characters copied to pszClass.  0 on failure.

 */

UINT WINAPI UClassFromDescription(LPSTR psz, LPSTR pszClass, UINT cb)

{

DWORD           dw;

HKEY            hKey;

char            szClass[OLEUI_CCHKEYMAX];

LONG            lRet;

UINT            i;

//Open up the root key.

lRet=RegOpenKey(HKEY_CLASSES_ROOT, NULL, &hKey);

if ((LONG)ERROR_SUCCESS!=lRet)

return 0;

i=0;

lRet=RegEnumKey(hKey, i++, szClass, OLEUI_CCHKEYMAX);

//Walk the available keys

while ((LONG)ERROR_SUCCESS==lRet)

{

dw=(DWORD)cb;

lRet=RegQueryValue(hKey, szClass, pszClass, &dw);

//Check if the description matches the one just enumerated

if ((LONG)ERROR_SUCCESS==lRet)

{

if (!lstrcmp(pszClass, psz))

break;

}

//Continue with the next key.

lRet=RegEnumKey(hKey, i++, szClass, OLEUI_CCHKEYMAX);

}

//If we found it, copy to the return buffer

if ((LONG)ERROR_SUCCESS==lRet)

lstrcpy(pszClass, szClass);

else

dw=0L;

RegCloseKey(hKey);

return (UINT)dw;

}

/*

 * UDescriptionFromClass

 *

 * Purpose:

 *  Looks up the actual OLE descriptive name name in the registration

 *  database for the given class name.

 *

 * Parameters:

 *  pszClass        LPSTR to the class name.

 *  psz             LPSTR in which to store the descriptive name.

 *  cb              UINT maximum length of psz.

 *

 * Return Value:

 *  UINT            Number of characters copied to pszClass.  0 on failure.

 */

UINT WINAPI UDescriptionFromClass(LPSTR pszClass, LPSTR psz, UINT cb)

{

DWORD           dw;

HKEY            hKey;

LONG            lRet;

if (NULL==pszClass || NULL==psz)

return 0;

//Open up the root key.

lRet=RegOpenKey(HKEY_CLASSES_ROOT, NULL, &hKey);

if ((LONG)ERROR_SUCCESS!=lRet)

return 0;

//Get the descriptive name using the class name.

dw=(DWORD)cb;

lRet=RegQueryValue(hKey, pszClass, psz, &dw);

RegCloseKey(hKey);

psz+=lstrlen(psz)+1;

*psz=0;

if ((LONG)ERROR_SUCCESS!=lRet)

return 0;

return (UINT)dw;

}

// returns width of line of text. this is a support routine for ChopText

static LONG GetTextWSize(HDC hDC, LPSTR lpsz)

{

SIZE size;

if (GetTextExtentPoint(hDC, lpsz, lstrlen(lpsz), (LPSIZE)&size))

return size.cx;

else {

return 0;

}

}

/*

 * ChopText

 *

 * Purpose:

 *  Parse a string (pathname) and convert it to be within a specified

 *  length by chopping the least significant part

 *

 * Parameters:

 *  hWnd            window handle in which the string resides

 *  nWidth          max width of string in pixels

 *                  use width of hWnd if zero

 *  lpch            pointer to beginning of the string

 *

 * Return Value:

 *  pointer to the modified string

 */

LPSTR WINAPI ChopText(HWND hWnd, int nWidth, LPSTR lpch)

{

#define PREFIX_SIZE    7 + 1

#define PREFIX_FORMAT "%c%c%c...\\"

char    szPrefix[PREFIX_SIZE];

BOOL    fDone = FALSE;

int     i;

RECT    rc;

HDC     hdc;

HFONT   hfont;

HFONT   hfontOld = NULL;

SIZE	size;

if (!hWnd || !lpch)

return NULL;

/* Get length of static field. */

if (!nWidth)

{

GetClientRect(hWnd, (LPRECT)&rc);

nWidth = rc.right - rc.left;

}

/* Set up DC appropriately for the static control */

hdc = GetDC(hWnd);

hfont = (HFONT)SendMessage(hWnd, WM_GETFONT, 0, 0L);

if (NULL != hfont)   // WM_GETFONT returns NULL if window uses system font

hfontOld = SelectObject(hdc, hfont);

/* check horizontal extent of string */

GetTextExtentPoint(hdc, lpch, lstrlen(lpch), &size);

if (size.cx > nWidth)

{

/* string is too long to fit in static control; chop it */

/* set up new prefix & determine remaining space in control */

wsprintf((LPSTR) szPrefix, PREFIX_FORMAT, lpch[0], lpch[1], lpch[2]);

GetTextExtentPoint(hdc, (LPSTR)szPrefix, lstrlen(szPrefix), &size);

nWidth -= size.cx;

/*

** advance a directory at a time until the remainder of the

** string fits into the static control after the "x:\...\" prefix

*/

while (!fDone)

{

#ifdef DBCS

while (*lpch && (*lpch != '\\'))

lpch = AnsiNext(lpch);

if (*lpch)

lpch = AnsiNext(lpch);

#else

while (*lpch && (*lpch++ != '\\'));

#endif

if (*lpch)

GetTextExtentPoint(hdc, lpch, lstrlen(lpch), &size);

if (!*lpch || size.cx <= nWidth)

{

if (!*lpch)

/*

** Nothing could fit after the prefix; remove the

** final "\" from the prefix

*/

szPrefix[lstrlen((LPSTR) szPrefix) - 1] = 0;

/* rest or string fits -- stick prefix on front */

for (i = lstrlen((LPSTR) szPrefix) - 1; i >= 0; --i)

*--lpch = szPrefix[i];

fDone = TRUE;

}

}

}

if (NULL != hfont)

SelectObject(hdc, hfontOld);

ReleaseDC(hWnd, hdc);

return(lpch);

#undef PREFIX_SIZE

#undef PREFIX_FORMAT

}

/*

 * OpenFileError

 *

 * Purpose:

 *  display message for error returned from OpenFile

 *

 * Parameters:

 *  hDlg            HWND of the dialog.

 *  nErrCode        UINT error code returned in OFSTRUCT passed to OpenFile

 *  lpszFile        LPSTR file name passed to OpenFile

 *

 * Return Value:

 *  None

 */

void WINAPI OpenFileError(HWND hDlg, UINT nErrCode, LPSTR lpszFile)

{

switch (nErrCode) {

case 0x0005:    // Access denied

ErrorWithFile(hDlg, ghInst, (UINT)IDS_CIFILEACCESS, lpszFile, MB_ICONEXCLAMATION | MB_OK);

break;

case 0x0020:    // Sharing violation

ErrorWithFile(hDlg, ghInst, (UINT)IDS_CIFILESHARE, lpszFile, MB_ICONEXCLAMATION | MB_OK);

break;

case 0x0002:    // File not found

case 0x0003:    // Path not found

ErrorWithFile(hDlg, ghInst, (UINT)IDS_CIINVALIDFILE, lpszFile, MB_ICONEXCLAMATION | MB_OK);

break;

default:

ErrorWithFile(hDlg, ghInst, (UINT)IDS_CIFILEOPENFAIL, lpszFile, MB_ICONEXCLAMATION | MB_OK);

break;

}

}

#define chSpace        ' '

#define chPeriod       '.'

#define PARSE_EMPTYSTRING   -1

#define PARSE_INVALIDDRIVE  -2

#define PARSE_INVALIDPERIOD -3

#define PARSE_INVALIDDIRCHAR    -4

#define PARSE_INVALIDCHAR   -5

#define PARSE_WILDCARDINDIR -6

#define PARSE_INVALIDNETPATH    -7

#define PARSE_INVALIDSPACE  -8

#define PARSE_EXTENTIONTOOLONG  -9

#define PARSE_DIRECTORYNAME -10

#define PARSE_FILETOOLONG   -11

/*---------------------------------------------------------------------------

 * ParseFile

 * Purpose:  Determine if the filename is a legal DOS name

 * Input:    Long pointer to a SINGLE file name

 *           Circumstance checked:

 *           1) Valid as directory name, but not as file name

 *           2) Empty String

 *           3) Illegal Drive label

 *           4) Period in invalid location (in extention, 1st in file name)

 *           5) Missing directory character

 *           6) Illegal character

 *           7) Wildcard in directory name

 *           8) Double slash beyond 1st 2 characters

 *           9) Space character in the middle of the name (trailing spaces OK)

 *          10) Filename greater than 8 characters

 *          11) Extention greater than 3 characters

 * Notes:

 *   Filename length is NOT checked.

 *   Valid filenames will have leading spaces, trailing spaces and

 *     terminating period stripped in place.

 *

 * Returns:  If valid, LOWORD is byte offset to filename

 *                     HIWORD is byte offset to extention

 *                            if string ends with period, 0

 *                            if no extention is given, string length

 *           If invalid, LOWORD is error code suggesting problem (< 0)

 *                       HIWORD is approximate offset where problem found

 *                       Note that this may be beyond the offending character

 *--------------------------------------------------------------------------*/

static long ParseFile(LPSTR lpstrFileName)

{

  short nFile, nExt, nFileOffset, nExtOffset;

  BOOL bExt;

  BOOL bWildcard;

  short nNetwork = 0;

  BOOL  bUNCPath = FALSE;

  LPSTR lpstr = lpstrFileName;

/* Strip off initial white space.  Note that TAB is not checked */

/* because it cannot be received out of a standard edit control */

/* 30 January 1991  clarkc                                      */

  while (*lpstr == chSpace)

  lpstr++;

  if (!*lpstr)

{

  nFileOffset = PARSE_EMPTYSTRING;

  goto FAILURE;

}

  if (lpstr != lpstrFileName)

{

  lstrcpy(lpstrFileName, lpstr);

  lpstr = lpstrFileName;

}

  if (*AnsiNext(lpstr) == ':')

{

  char cDrive = (*lpstr | (BYTE) 0x20);  /* make lowercase */

/* This does not test if the drive exists, only if it's legal */

  if ((cDrive < 'a') || (cDrive > 'z'))

{

  nFileOffset = PARSE_INVALIDDRIVE;

  goto FAILURE;

}

  lpstr = AnsiNext(AnsiNext(lpstr));

}

  if ((*lpstr == '\\') || (*lpstr == '/'))

{

  if (*++lpstr == chPeriod)               /* cannot have c:\. */

{

  if ((*++lpstr != '\\') && (*lpstr != '/'))   /* unless it's stupid */

{

  if (!*lpstr)        /* it's the root directory */

  goto MustBeDir;

  nFileOffset = PARSE_INVALIDPERIOD;

  goto FAILURE;

}

  else

  ++lpstr;   /* it's saying top directory (again), thus allowed */

}

  else if ((*lpstr == '\\') && (*(lpstr-1) == '\\'))

{

/* It seems that for a full network path, whether a drive is declared or

 * not is insignificant, though if a drive is given, it must be valid

 * (hence the code above should remain there).

 * 13 February 1991           clarkc

 */

  ++lpstr;            /* ...since it's the first slash, 2 are allowed */

  nNetwork = -1;      /* Must receive server and share to be real     */

  bUNCPath = TRUE;    /* No wildcards allowed if UNC name             */

}

  else if (*lpstr == '/')

{

  nFileOffset = PARSE_INVALIDDIRCHAR;

  goto FAILURE;

}

}

  else if (*lpstr == chPeriod)

{

  if (*++lpstr == chPeriod)  /* Is this up one directory? */

  ++lpstr;

  if (!*lpstr)

  goto MustBeDir;

  if ((*lpstr != '\\') && (*lpstr != '/'))

{

  nFileOffset = PARSE_INVALIDPERIOD;

  goto FAILURE;

}

  else

  ++lpstr;   /* it's saying directory, thus allowed */

}

  if (!*lpstr)

{

  goto MustBeDir;

}

/* Should point to first char in 8.3 filename by now */

  nFileOffset = nExtOffset = nFile = nExt = 0;

  bWildcard = bExt = FALSE;

  while (*lpstr)

{

/*

 *  The next comparison MUST be unsigned to allow for extended characters!

 *  21 Feb 1991   clarkc

 */

  if (*lpstr < chSpace)

{

  nFileOffset = PARSE_INVALIDCHAR;

  goto FAILURE;

}

  switch (*lpstr)

{

  case '"':             /* All invalid */

  case '+':

  case ',':

  case ':':

  case ';':

  case '<':

  case '=':

  case '>':

  case '[':

  case ']':

  case '|':

{

  nFileOffset = PARSE_INVALIDCHAR;

  goto FAILURE;

}

  case '\\':      /* Subdirectory indicators */

  case '/':

nNetwork++;

if (bWildcard)

  {

nFileOffset = PARSE_WILDCARDINDIR;

goto FAILURE;

  }

else if (nFile == 0)        /* can't have 2 in a row */

  {

nFileOffset = PARSE_INVALIDDIRCHAR;

goto FAILURE;

  }

else

  {                         /* reset flags */

++lpstr;

if (!nNetwork && !*lpstr)

  {

nFileOffset = PARSE_INVALIDNETPATH;

goto FAILURE;

  }

nFile = nExt = 0;

bExt = FALSE;

  }

break;

  case chSpace:

{

  LPSTR lpSpace = lpstr;

  *lpSpace = '\0';

  while (*++lpSpace)

{

  if (*lpSpace != chSpace)

{

  *lpstr = chSpace;        /* Reset string, abandon ship */

  nFileOffset = PARSE_INVALIDSPACE;

  goto FAILURE;

}

}

}

break;

  case chPeriod:

if (nFile == 0)

  {

if (*++lpstr == chPeriod)

++lpstr;

if (!*lpstr)

goto MustBeDir;

if ((*lpstr != '\\') && (*lpstr != '/'))

  {

nFileOffset = PARSE_INVALIDPERIOD;

goto FAILURE;

  }

++lpstr;              /* Flags are already set */

  }

else if (bExt)

  {

nFileOffset = PARSE_INVALIDPERIOD;  /* can't have one in ext */

goto FAILURE;

  }

else

  {

nExtOffset = 0;

++lpstr;

bExt = TRUE;

  }

break;

  case '*':

  case '?':

if (bUNCPath)

  {

nFileOffset = PARSE_INVALIDNETPATH;

goto FAILURE;

  }

bWildcard = TRUE;

/* Fall through to normal character processing */

  default:

if (bExt)

  {

if (++nExt == 1)

nExtOffset = lpstr - lpstrFileName;

else if (nExt > 3)

  {

nFileOffset = PARSE_EXTENTIONTOOLONG;

goto FAILURE;

  }

if ((nNetwork == -1) && (nFile + nExt > 11))

  {

nFileOffset = PARSE_INVALIDNETPATH;

goto FAILURE;

  }

  }

else if (++nFile == 1)

nFileOffset = lpstr - lpstrFileName;

else if (nFile > 8)

  {

/* If it's a server name, it can have 11 characters */

if (nNetwork != -1)

  {

nFileOffset = PARSE_FILETOOLONG;

goto FAILURE;

  }

else if (nFile > 11)

  {

nFileOffset = PARSE_INVALIDNETPATH;

goto FAILURE;

  }

  }

lpstr = AnsiNext(lpstr);

break;

}

}

/* Did we start with a double backslash but not have any more slashes? */

  if (nNetwork == -1)

{

  nFileOffset = PARSE_INVALIDNETPATH;

  goto FAILURE;

}

  if (!nFile)

{

MustBeDir:

  nFileOffset = PARSE_DIRECTORYNAME;

  goto FAILURE;

}

  if ((*(lpstr - 1) == chPeriod) &&          /* if true, no extention wanted */

  (*AnsiNext(lpstr-2) == chPeriod))

  *(lpstr - 1) = '\0';               /* Remove terminating period   */

  else if (!nExt)

FAILURE:

  nExtOffset = lpstr - lpstrFileName;

  return(MAKELONG(nFileOffset, nExtOffset));

}

/*

 * DoesFileExist

 *

 * Purpose:

 *  Determines if a file path exists

 *

 * Parameters:

 *  lpszFile        LPSTR - file name

 *  lpOpenBuf       OFSTRUCT FAR* - points to the OFSTRUCT structure that

 *                      will receive information about the file when the

 *                      file is first opened. this field is filled by the

 *                      Windows OpenFile API.

 *

 * Return Value:

 *  HFILE   HFILE_ERROR - file does NOT exist

 *          file handle (as returned from OpenFile) - file exists

 */

HFILE WINAPI DoesFileExist(LPSTR lpszFile, OFSTRUCT FAR* lpOpenBuf)

{

long        nRet;

int         i;

static char *arrIllegalNames[] = {

"LPT1",

"LPT2",

"LPT3",

"COM1",

"COM2",

"COM3",

"COM4",

"CON",

"AUX",

"PRN"

};

// Check if file name is syntactically correct.

//   (OpenFile sometimes crashes if path is not syntactically correct)

nRet = ParseFile(lpszFile);

if (LOWORD(nRet) < 0)

goto error;

// Check is the name is an illegal name (eg. the name of a device)

for (i=0; i < (sizeof(arrIllegalNames)/sizeof(arrIllegalNames[0])); i++) {

if (lstrcmpi(lpszFile, arrIllegalNames[i])==0)

goto error; // illegal name FOUND

}

return OpenFile(lpszFile, lpOpenBuf, OF_EXIST);

error:

_fmemset(lpOpenBuf, 0, sizeof(OFSTRUCT));

lpOpenBuf->nErrCode = 0x0002;   // File not found

return HFILE_ERROR;

}


 WN_DOS.H  (WRAPUI Sample)

/*************************************************************************

**

**    OLE 2.0 Property Set Utilities

**

**    wn_dos.h

**

**    This file contains file contains data structure defintions,

**    function prototypes, constants, etc. for Windows 3.x form of

**    DOS calls. This is used by the SUMINFO OLE 2.0 Property Set

**    utilities used to manage the Summary Info property set.

**

**    (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved

**

*************************************************************************/

#ifndef WN_DOS_H

#define WN_DOS_H

#include <dos.h>

#define WIN 1

#define cbMaxFile 146 //from inc\path.h

#define SEEK_FROM_BEGINNING 0

#define SEEK_FROM_END 2

#define chDOSPath ('\\')        // FUTURE: not used all places it could be

#define chDOSWildAll    '*'     /* DOS File name wild card. */

#define chDOSWildSingle '?'

// Close, seek, delete, rename, flush, get attributes, read, write

/* RPC TEMP

int  FCloseOsfnWin(WORD);

#define FCloseOsfn(osfn)    FCloseOsfnWin(osfn)

long DwSeekDwWin(WORD,LONG,WORD);

#define DwSeekDw(osfn, dwSeek, bSeekFrom)   DwSeekDwWin(osfn, dwSeek, bSeekFrom)

EC  EcDeleteSzFfnameWin(char *);

#define EcDeleteSzFfname(szFile) EcDeleteSzFfnameWin(szFile)

EC  EcRenameSzFfnameWin(char *,char *);

#define EcRenameSzFfname(szFileCur,szFileNew) EcRenameSzFfnameWin(szFileCur,szFileNew)

int FFlushOsfnWin(int);

#define FFlushOsfn(osfn)    FFlushOsfnWin(osfn)

WORD DaGetFileModeSzWin(char *);

#define DaGetFileModeSz(szFile) DaGetFileModeSzWin(szFile)

int  CbReadOsfnWin(int, void far *, UINT);

int  CbWriteOsfnWin(int, void far *, UINT);

#define CbWriteOsfn(osfn,lpch,cbWrite)  CbWriteOsfnWin(osfn,lpch,cbWrite)

*/

#define WinOpenFile(sz,ofs,n)   OpenFile(sz,ofs,n)

#define SeekHfile(f,off,kind) _llseek(f,off,kind)

#define CbReadOsfn(osfn,lpch,cbRead)    CbReadOsfnWin(osfn,lpch,cbRead)

#define CbReadHfile(f,buf,n) _lread(f,buf,n)

#define CbReadOsfnWin(f,buf,n) CbReadHfile(f,buf,n)

#define EcFindFirst4dm(a,b,c) _dos_findfirst((const char *)(b),c,(struct find_t*)a)

#define EcFindNext4dm(a) _dos_findnext((struct find_t*)a)

#define FHfileToSffsDate(handle,date,time) _dos_getftime(handle, (unsigned *)(date), (unsigned *)(time))

#define SeekHfile(f, off, kind) _llseek(f,off,kind)

/* buffer structure to be used with EcFindFirst() and EcFindNext() */

typedef struct _SFFS

{ /* Search Find File Structure */

uchar buff[21]; // dos search info

uchar wAttr;

union

{

unsigned short timeVariable;    /*RPC47*/

BF time:16;

struct

{

BF sec : 5;

BF mint: 6;

BF hr  : 5;

};

};

union

{

unsigned short dateVariable;

BF date:16;

struct

{

BF dom : 5;

BF mon : 4;

BF yr  : 7;

};

};

ulong cbFile;

uchar szFileName[13];

} SFFS;

// find first file/find next file

#define PszFromPsffs(psffs)     ((psffs)->szFileName)

#define CopySzFilePsffs(psffs,sz)   OemToAnsi((char HUGE *)&((psffs)->szFileName[0]),(char HUGE *)(sz))

#define CbSzFilePsffs(psffs)    CbSz((psffs)->szFileName)

#define CbFileSizePsffs(psffs)  (psffs)->cbFile

#define AttribPsffs(psffs)      (psffs)->wAttr

#define EcFindFirstCore(psffs, sz, wAttr) EcFindFirst(psffs, sz, wAttr)   /*RPC22*/

#define FDotPsffs(psffs) ((psffs)->szFileName[0]=='.')   /*RPC23*/

#define AppendSzWild(sz) {int i=_fstrlen((char FAR *)(sz)); sz[i]='*'; sz[i+1]='.'; sz[i+2]='*'; sz[i+3]='\0';}

// disk free space

unsigned long LcbDiskFreeSpaceWin(int);

#define LcbDiskFreeSpace(chDrive) LcbDiskFreeSpaceWin(chDrive)

// date and time    /*RPC39*/

/*

typedef struct _TIM {                    // Time structure returned by OsTime

CHAR minutes, hour, hsec, sec;

} TIM;

typedef struct _DAT {                    // Date structure returned by OsDate

int  year;

CHAR month, day, dayOfWeek;

} DAT;

*/

#define TIM dostime_t    /*RPC39*/

#define DAT dosdate_t

#define OsTimeWin(TIM) _dos_gettime(TIM)

#define OsDateWin(DAT) _dos_getdate(DAT)

/* DOS File Attributes */

#define DA_NORMAL       0x00

#define DA_READONLY     0x01

#define DA_HIDDEN       0x02

#define DA_SYSTEM       0x04

#define DA_VOLUME       0x08

#define DA_SUBDIR       0x10

#define DA_ARCHIVE      0x20

#define DA_NIL          0xFFFF  /* Error DA */

#define dosxSharing     32      /* Extended error code for sharing viol. */

#define nErrNoAcc       5       /* OpenFile error code for Access Denied */

#define nErrFnf         2       /* OpenFile error code for File Not Found */

/* Components of the Open mode for OpenSzFfname (DOS FUNC 3DH) */

#define MASK_fINH       0x80

#define MASK_bSHARE     0x70

#define MASK_bACCESS    0x07

#define bSHARE_DENYRDWR 0x10

#define bSHARE_DENYWR   0x20

#define bSHARE_DENYNONE 0x40

/* Seek-from type codes passed to DOS function 42H */

#define SF_BEGINNING    0       /* Seek from beginning of file */

#define SF_CURRENT      1       /* Seek from current file pointer */

#define SF_END          2       /* Seek from end of file */

typedef struct _DOSDTTM /* DOS DaTe TiMe */

{

union

{

long lDOSDttm;

struct

{

BF day: 5;

BF month:   4;

BF year:    7;

BF sec: 5;

BF mint:    6;

BF hours:   5;

} S1;

} U1;

} DOSDTTM;

int  FOsfnIsFile(int);

void DateStamp(int, LONG *,  int);

int  DosxError(void);

int  ShellExec(int, int);

#endif //WN_DOS_H


Introduction

This book provides procedural and reference information for OLE Automation. While OLE Automation runs on other platforms, such as the Apple® Macintosh® system, the focus of this document is applications that use the Windows® 32-bit operating system.

To get the most out of this book, you should be familiar with:

•	The C++ programming language.

•	The Microsoft® Windows programming environment, version 3.1 or later. The OLE protocols are implemented through dynamic-link libraries (DLLs) that are used in conjunction with other Microsoft Windows programs.

•	The OLE 2 Component Object Model. This model is the foundation of OLE. It is explained in depth by the books listed in "Other Books and Technical Support."


About This Book

The book contains three parts:

Part 1 	About OLE Automation

Chapter 1 "Overview of OLE Automation," introduces the basic concepts of OLE Automation and identifies the components you'll use.

Chapter 2, "Exposing OLE Automation Objects," shows how to write and expose programmable objects for use by OLE Automation controllers.

Chapter 3, "Accessing OLE Automation Objects," explains how to write applications and programming tools that access exposed objects.

Chapter 4, "Standards and Guidelines," lists the standard OLE Automation objects that are recommended for most applications, and describes naming conventions for objects.

Part 2 	Reference Information

Chapter 5, "Dispatch Interfaces," describes the interfaces and functions that support access to exposed objects.

Chapter 6, "Data Manipulation Functions," describes functions that manipulate arrays, strings, and variant types of data within OLE Automation.

Chapter 7, "MkTypLib and Object Description Language," describes the MkTypLib tool and its source file language. MkTypLib creates type libraries according to the description you provide.

Chapter 8, "Type Description Interfaces," describes the interfaces and functions that allow programs to read and bind to the descriptions of objects in a type library.

Chapter 9, "Type Building Interfaces," describes the interfaces and functions that are used by tools like MkTypLib to describe objects and build type libraries.

Appendixes

Appendix A, "National Language Support Functions," describes functions for 16-bit systems that support multiple national languages.

Appendix B, "Files You Need," lists the files you and your customers need to run OLE Automation applications.

Appendix C, "Information for Visual Basic Programmers," lists the OLE API's called by Visual Basic statements.

Appendix D, "How OLE Automation Compares Strings," describes the string comparison rules applied by OLE Automation.

Appendix E, "Handling GUIDs," provides supplemental information on GUIDs.

The Glossary defines terms useful in understanding OLE Automation.


Other Books and Technical Support

OLE Automation is part of OLE, which provides mechanisms for in-place activation, structured file storage, and many other application features. These other parts of OLE 2 are fully described by two books:

•	OLE 2 Programmer's Reference, Volume 1 describes the component object model, in-place activation, visual editing, structured file storage, and application registration in terms of the APIs and interfaces provided by OLE.

•	Inside OLE 2 by Kraig Brockschmidt provides introductory and how-to information about implementing OLE objects and containers.

If you are developing C++ applications, you may also find The CDK Programmer's Guide useful. This book is included with the Microsoft OLE Custom Controls Developer's Kit, which is part of Microsoft C++, version 2.0.

For technical support, see the OLE 2 SDK and the documentation for the product with which you received OLE. Support for OLE Automation is also provided through a forum on Compuserve. To access this forum, type GO WINOBJ at any Compuserve prompt. Once you are in the forum, ask your questions in Section 8.


Document Conventions

The following typographical conventions are used throughout this book:

Convention	Meaning
bold	Indicates a word that is a function name or other fixed part of a programming language, the Microsoft Windows operating system, or the OLE Application Programming Interface (API). For example, DispInvoke is an OLE-specific function. These words must always be typed exactly as they are printed.
italic	Indicates a word that is a placeholder or variable. For example, ClassName would be a placeholder for any OLE object class name. Function parameters in API reference material are italic to indicate that any variable name can be used. In addition, OLE terms are italicized at first use to highlight their definition.
UPPERCASE	Indicates a constant or an MS-DOS® path and name. For example, E_INVALIDARG is a constant. C:\OLE2\INCLUDE\OLE2.H is an MS-DOS path and name.
InitialCaps	Indicates the name of an object, method, property, user-defined function or event. For example, the Application object has a Visible property.
monospace	Indicates source code and syntax spacing. For example: *pdwRegisterCF = 0;
Note  The interface syntax in this book follows the variable-naming convention known as Hungarian notation, invented by programmer Charles Simonyi. Variables are prefixed with lowercase letters indicating their data type. For example, lpszNewDocname would be a long pointer to a zero-terminated string named NewDocname. See Programming Windows by Charles Petzold for more information about Hungarian notation.


Overview of OLE Automation

OLE Automation is a technology that lets software packages expose their unique features to scripting tools and other applications. OLE Automation uses the OLE Component Object Model (COM), but may be implemented independently from other OLE features, such as in-place activation. Using OLE Automation, you can:

•	Create applications and programming tools that expose objects.

•	Create and manipulate objects exposed in one application from another application.

•	Create tools that access and manipulate objects. These tools can include embedded macro languages, external programming tools, object browsers, and compilers.

The objects an application or programming tool exposes are called OLE Automation objects. Applications and programming tools that access those objects are called OLE Automation controllers. OLE Automation objects and controllers interact as follows:

Applications and other software packages define and expose objects, which can be acted upon by OLE Automation controllers. Type information describes the exposed objects, and can be used by OLE Automation controllers at either compile time or run time.


Why Expose Objects?

Exposing objects provides a way to manipulate an application's tools programmatically. This allows your customers to use a programming tool to automate repetitive tasks that you might not anticipate.

For example, Microsoft Excel exposes a variety of objects that you can use to build applications. One such object is the Workbook, which contains a group of related worksheets, charts, and macros — the Excel equivalent of a three-ring binder. Using OLE Automation, you could write an application that accesses Excel Workbook objects, possibly to print them, as in the following diagram:

With OLE Automation, solution providers can use your general-purpose objects to build applications that target a specific task. For example, a general-purpose drawing tool could expose objects that draw boxes, lines, and arrows, or insert text, and so forth. Another programmer could build a flowcharting tool by accessing the exposed objects and adding a user interface and other application-specific features.

Exposing objects to OLE Automation or supporting OLE Automation within a macro language offers several benefits:

•	Exposed objects from many applications are available in a single programming environment. Software developers can choose from these objects to create solutions that span applications.

•	Exposed objects are accessible from any macro language or programming tool that implements OLE Automation. Systems integrators are not limited to the programming language in which the objects were developed; instead, they can choose the programming tool or macro language that best suits their own needs and capabilities.

•	Object names can remain consistent across versions of an application.

•	Object names can automatically conform to the user's national language.


What Is an OLE Automation Object?

An OLE Automation object is an instance of a class that exposes properties, methods, and events to OLE Automation controllers. An OLE Automation server is an application or library that is capable of creating one or more OLE Automation objects. For example, Microsoft Excel exposes many objects, which you can use to create new applications and programming tools. Within Excel, objects are organized hierarchically, with an object named Application at the top of the hierarchy. The following figure shows some of Excel's objects.

Each OLE Automation object has its own unique member functions. Exposing the member functions makes the object programmable by OLE Automation controllers. You can expose two types of members for an object:

•	Methods are actions that an object can perform. For example, Excel's Worksheet object provides a Calculate method, which recalculates the values in the worksheet.

•	Properties are functions that access information about the state of an object. The Worksheet object's Visible property determines whether the worksheet is visible on the display.

For example, you could expose the following objects in a document-based application by implementing these methods and properties:

OLE Automation object	Methods	Properties
Application	Help Quit Save Repeat Undo	ActiveDocument Application Caption DefaultFilePath Documents Height Name Parent Path Printers StatusBar Top Value Visible Width
Document	Activate Close NewWindow Print PrintPreview RevertToSaved Save SaveAs	Application Author Comments FullName Keywords Name Parent Path ReadOnly Saved Subject Title Value
Often, an application needs several instances of an object. For example, an OLE application based on Excel may have multiple workbooks. To provide an easy way to access and program the workbooks, Excel exposes an object named Workbooks, which refers to all the current Workbook objects. Workbooks is a collection object; other collection objects in Excel are shaded in the preceding figure. Collection objects let you iterate over the objects they manage. If you create an application with a multiple-document interface (MDI), you might expose a collection object named Documents with the following methods and properties:

Collection object	Methods	Properties
Documents	Add Close Item Open	Application Count Parent


What Is an OLE Automation Controller?

An OLE Automation controller is an application or programming tool that manipulates one or more OLE Automation objects. The objects may exist in the same application or in another application. OLE Automation controllers can use existing objects, create new instances of objects, get and set properties, and invoke methods that the object supports.

Microsoft Visual Basic™ is an OLE Automation controller. Using Visual Basic and similar programming tools, you can create packaged scripts to access OLE Automation objects. You can also create controllers by:

•	Writing code within an application that accesses another application's exposed objects through OLE Automation.

•	Revising an existing programming tool, such as an embedded macro language, to add support for OLE Automation.

•	Developing a new application, such as a compiler or type information browser, that supports OLE Automation.


How Do Controllers and Objects Interact?

OLE Automation controllers can access OLE Automation objects in two different ways:

•	By using the IDispatch interface.

•	By directly calling one of the member functions in the object's virtual function table (VTBL).

An interface is a group of related functions that provide a service. All OLE Automation objects must implement the IUnknown interface, which manages all the other interfaces that the object supports. The IDispatch interface, which derives from IUnknown, consists of functions that allow access to the methods and properties of OLE Automation objects. A custom interface is a Component Object Model interface that is not defined as part of OLE; in short, any user-defined interface is a custom interface.

The virtual function table (VTBL) lists the addresses of all the properties and methods that are members of the object, including the member functions of the interfaces that it supports. The first three members of the VTBL are the members of the IUnknown interface; and subsequent entries are the members of the other supported interfaces. The following figure shows the VTBL for an object that supports the IUnknown and IDispatch interfaces:

If the object does not support IDispatch, the entries for the members of the object's custom interfaces immediately follow the members of IUnknown. For example, the following figure shows the VTBL for an object that supports a custom interface named IMyInterface:

When you expose an object for OLE Automation, you must decide whether to implement an IDispatch interface, a VTBL interface, or both. Microsoft strongly recommends that your objects provide a dual interface, which supports both access methods. In a dual interface, the first three entries in the VTBL are the members of IUnknown, the next four entries are the members of IDispatch, and the subsequent entries are the addresses of the members of the dual interface. The following figure shows the VTBL for an object that supports a dual interface named IMyInterface:

In addition to providing access to objects, OLE Automation provides information about exposed objects. Using IDispatch or a type library, an OLE Automation controller or programming tool can determine the interfaces a object supports and the names of its members. Type libraries are especially useful for this purpose because they can be accessed at compile time. For more information, see What Is a Type Library?, and Type Libraries.


Accessing an Object Through the IDispatch Interface

OLE Automation controllers can use the IDispatch interface to access objects that implement this interface. The controller must first create the object, then query the object's IUnknown interface for a pointer to its IDispatch interface.

Although programmers know objects, methods, and properties by name, IDispatch keeps track of them internally by a number, the Dispatch ID (DISPID). Before an OLE Automation controller can access a property or method, it must have the DISPID that maps to the name of the member.

With the DISPID, it can call IDispatch::Invoke to access the property or invoke the method, packaging the parameters for the property or method into one of the IDispatch::Invoke parameters.

The object's implementation of IDispatch::Invoke must then unpackage the parameters, call the property or method, and be prepared to handle any errors that occur. When the property or method returns, the object passes its return value back to the controller through an IDispatch::Invoke parameter.

DISPIDs are available at run time and, in some circumstances, at compile time. At run time, controllers get DISPIDs by calling the IDispatch::GetIDsOfNames function. This is called late binding because the controller binds to the property or method at run time.

The DISPID of each property or method is fixed, and is part of the object's type description. If the object is described in a type library, an OLE Automation controller can read the DISPIDs from the type library at compile time, and thus avoid calling IDispatch::GetIDsOfNames. This is called ID binding. Because it requires only one call to IDispatch (that is, the call to Invoke) rather than the two calls required by late binding, it is generally about twice as fast. Late binding controllers can improve performance by caching DISPIDs after retrieving them, so that IDispatch::GetIDsOfNames is called only once for each property or method.


Accessing an Object Through the VTBL

OLE Automation allows an OLE Automation controller to call a method or property accessor function directly, either within or across processes. This approach, called VTBL binding, does not use the IDispatch interface. The controller gets type information from the type library at compile time, then calls the methods and functions directly. VTBL binding is faster than both ID binding and late binding because access is direct; no calls are made through IDispatch.


In-Process and Local Server Objects

OLE Automation objects may exist in the same process as their controller or in a different process. In-process objects are implemented in a DLL and run in the process space of the controller. Because they're contained in a DLL, they can't be run stand-alone. Local server objects are implemented in an .EXE file and run in a separate process space. Access to in-process objects is much faster than access to local server objects, because OLE Automation does not need to make remote procedure calls across the process boundary.

The BrowseH sample is an in-process OLE Automation object. The Hello and Lines samples are both local server OLE Automation objects.

The access mechanism (IDispatch or VTBL) and the location of an object (in-process or local server) determine the fixed overhead required for access. Note that the most important factor in performance, however, is the quantity and nature of the work performed by the methods and procedures being invoked. If the method is time-consuming or requires remote procedure calls, the overhead of one additional call to IDispatch may be negligible.


What Is a Type Library?

A type library is a file or part of a file that describes the type of one or more OLE Automation objects. Type libraries do not store objects; type libraries store type information. By accessing a type library, applications and browsers can determine the characteristics of an object, such as the interfaces the object supports and the names and addresses of each interface's members. You can also invoke a member through a type library; see Chapter 8, "Type Description Interfaces," for details.

When you expose OLE Automation objects, you should create a type library to make your objects easily accessible to other developers. The simplest way is to describe your objects in an Object Description Language (ODL) file, and then compile the file with the MkTypLib tool, as described in Chapter 7, "MkTypLib and Object Description Language."


Exposing OLE Automation Objects

Exposing objects makes them available for programmatic use by other applications and programming tools. To expose objects, you need to implement the objects using OLE Automation; create a type library that describes the exposed objects; and register the objects with the system.

This chapter discusses how you should design an application that exposes objects, then uses the Hello and Lines samples from the OLE 2 Software Development Kit (SDK) to demonstrate how to implement the design. Throughout the chapter, the filename for the example precedes the example in parentheses.


Design Considerations

When you expose objects to OLE Automation, you need to decide which interfaces to implement and how to organize your objects. In addition, you should create a type library. This section provides information to guide you in designing an OLE Automation application.


Dual Interfaces

Although OLE Automation allows you to implement an IDispatch interface, a VTBL interface, or a dual interface (which encompasses both), Microsoft strongly recommends that you implement dual interfaces for all exposed OLE Automation objects. Dual interfaces have significant advantages over IDispatch-only or VTBL-only interfaces:

•	Binding can take place at compile time through the VTBL interface, or at run time through IDispatch.

•	OLE Automation controllers that can use the VTBL interface may benefit from improved performance.

•	Existing OLE Automation controllers that use the IDispatch interface will continue to work.

•	The VTBL interface is easier to call from C++.

•	Dual interfaces are required for compatibility with Visual Basic object support features.


Converting Existing Objects to Dual Interfaces

If you have already implemented exposed objects that support only the IDispatch interface, you should convert them to support dual interfaces.

To convert an IDispatch interface to a dual interface

1.	Edit the Object Description Language (.ODL) file to declare a dual interface instead of an IDispatch interface.

2.	Rearrange the parameter lists so that the methods and properties of your exposed objects return an HRESULT and pass their return values in a parameter.

3.	If your object implements an exception handler, revise your code to use the OLE Automation error handling interface. This interface provides for detailed, contextual error information through both IDispatch and VTBL interfaces.

See "Setting Up the VTBL Interface," "Returning an Error," and "Creating a Type Library" later in this chapter for details.


Type Libraries

In addition to implementing dual interfaces, you should create a type library for each set of objects you expose. Because VTBL references are bound at compile time, exposed objects that support VTBL binding must be described in a type library.

Type libraries provide these important benefits:

•	Type checking can be performed at compile time, helping developers of OLE Automation controllers to write fast, correct code to access your objects.

•	You can use the DispInvoke function to implement IDispatch automatically. Using DispInvoke ensures that your implementation will be correct.

•	Visual Basic applications can create objects with specific interface types, rather than the generic Object type, and take advantage of early binding.

•	OLE Automation controllers that don't support VTBLs can read and cache DISPIDs at compile time, thereby improving run time performance.

•	Type browsers can scan the library, allowing others to see the characteristics of your objects.

•	The RegisterTypeLib function can be used to register your exposed objects.

•	Local server access is improved, because OLE Automation uses information from the type library to package the parameters passed to an object in another process.


The Application Object

Document-based, user-interactive applications that expose OLE Automation objects should have one top-level object called the Application object. This object is initialized as the active object when the application starts.

The Application object identifies the application and provides a way for OLE Automation controllers to bind to and navigate the application's exposed objects. All other exposed objects are subordinate to the Application object; it is the root-level object in the object hierarchy.

The names of the Application object's members are part of the global name space,  so OLE Automation controllers need not qualify them. For example, if MyApplication is the name of the Application object, a Visual Basic program can refer to a method of MyApplication as MyApplication.MyMethod or simply MyMethod. However, you should be careful not to overload the Application object;too many members can cause ambiguity and decrease performance. A large, complicated application with many members should be organized hierarchically, with a few generalized objects at the top, branching out into smaller, more specialized objects. Microsoft Excel is a good example of this kind of application.


Shutdown Behavior

OLE Automation objects must shut down in the following way:

•	If the object's application is visible, the object should shut down only in response to an explicit user command (for example, the Exit command from the File menu) or from the equivalent command from an OLE Automation controller.

•	If the object's application is not visible, the object should shut down only when the last external reference to it disappears.


Steps to Exposing Objects

To expose OLE Automation objects, you must write code to initialize the objects, implement the objects, and release OLE when your application terminates.

To initialize your exposed objects

1.	Initialize OLE.

2.	Register the class factories of your exposed objects.

3.	Register the active object.

To implement your exposed objects

1.	Implement the IUnknown, IDispatch, and VTBL interfaces for the objects.

2.	Implement the properties and methods of the objects.

To release OLE when your application terminates

1.	Revoke the registration of the class factories and revoke the active object.

2.	Unintialize OLE.

To make your objects available for use by others

1.	Create an object description (.ODL) file that describes the properties and methods of the exposed objects, and use MkTypLib to compile the .ODL file into a type library.

2.	Create a registration (.REG) file for your application.


Initializing OLE to Expose Objects

To initialize OLE and your exposed objects, you use the following functions:

•	OleInitialize— Initializes OLE.

•	CoRegisterClassObject—Registers the object's class factory with OLE so that other applications may use it to create new objects.

•	RegisterActiveObject— Registers the active object, allowing other applications to connect to an existing object.


Implementing Exposed Objects

The following figure shows the interfaces you should implement in order to expose OLE Automation objects:

The member functions are listed under each interface name.

The class factory object implements the IClassFactory and IUnknown interfaces. (All objects must implement IUnknown, which allows OLE Automation controllers to determine what interfaces the object supports.) A class factory can create instances of a class.

The object implements two interfaces: IUnknown and IMyInterface. IMyInterface is a dual interface, which supports both late binding through IDispatch and early binding through the VTBL. The dual interface thus provides two ways to invoke the object's methods and properties. IDispatch includes the member functions GetIDsOfNames, GetTypeInfo, GetTypeInfoCount, and Invoke.

Member1 and Member2 are the members of IMyInterface. These members are available as direct entry points through the object's VTBL. They can also be accessed through IDispatch::Invoke.

You must also decide how to handle errors that occur in your exposed objects. If your object supports a dual interface and needs to return detailed, contextual error information, you also need to implement the OLE Automation error interface, IErrorInfo.

In addition to writing code to implement objects, you need to create a type library and a registration file. You describe the types of the exposed objects in the object description language (ODL), and use the MkTypLib tool to compile the ODL file into a type library (.TLB) and a header file (.H). The registration file provides information that the operating system and OLE need to locate objects.


Releasing OLE to Expose Objects

To release OLE and your exposed objects, you use the following functions:

•	RevokeActiveObject—Ends an object's status as the active object.

•	CoRevokeClassObject—Informs OLE that a class factory is no longer available for use by other applications.

•	OLEUninitialize—Releases OLE.


"Hello World" Example

The Hello example in the OLE 2 SDK is a simple OLE Automation application with one object. It has these characteristics:

•	Supports VTBL binding

•	Permits multiple instances of its exposed object to exist at the same time

•	Implements IErrorInfo for exception handling

The sections that follow demonstrate how the Hello sample exposes a simple class. The code is abridged to illustrate the essential parts; see the source code in the OLE 2 SDK for a complete listing.


Initializing OLE for the "Hello World" Example

When the Hello application starts, it initializes OLE and the creates the object to be exposed through OLE Automation. For example (MAIN.CPP):

BOOL InitInstance (HINSTANCE hinst)

{

HRESULT hr;

char ach[STR_LEN];

// Intialize OLE

hr = OleInitialize(NULL);

if (FAILED(hr))

return FALSE;

// Create an instance of the Hello Application object. The object is

// created with refcount 0.

LoadString(hinst, IDS_HelloMessage, ach, sizeof(ach));

hr = CHello::Create(hinst, ach, &g_phello);

if (FAILED(hr))

return FALSE;

return TRUE;

}

This function calls OleInitialize to initialize OLE. It loads the string ach with the initial hello message, obtained from the string table through the constant IDS_HelloMessage. Then it calls CHello::Create to create a single, global instance of the application object, passing it the initial hello message and receiving a value for g_phello, a pointer to the instance. If the function is successful, it returns True.


Registering the Active Object

After Hello creates an instance of the object, it exposes and registers the class factory (if necessary) and registers the active object (MAIN.CPP):

BOOL ProcessCmdLine(LPSTR pCmdLine,

LPDWORD pdwRegisterCF,

LPDWORD pdwRegisterActiveObject,

int nCmdShow)

{

LPCLASSFACTORY pcf = NULL;

HRESULT hr;

*pdwRegisterCF = 0;

*pdwRegisterActiveObject = 0;

// Expose class factory for application object if command line

// contains the /Automation switch.

if (_fstrstr(pCmdLine, "-Automation") != NULL

|| _fstrstr(pCmdLine, "/Automation") != NULL)

{

pcf = new CHelloCF;

if (pcf)

goto error;

pcf->AddRef();

hr = CoRegisterClassObject(CLSID_Hello, pcf,

CLSCTX_LOCAL_SERVER,

REGCLS_SINGLEUSE,

pdwRegisterCF);

if (hr != NOERROR)

goto error;

pcf->Release();

}

else g_phello->ShowWindow(nCmdShow); //Show if started stand-alone.

RegisterActiveObject(g_phello, CLSID_Hello, ACTIVEOBJECT_WEAK,

pdwRegisterActiveObject);

return TRUE;

error:

if (!pcf)

pcf->Release();

return FALSE;

}

The sample first checks the command line for the /Automation switch. This switch indicates that the application should be started for programmatic access, so that OLE Automation controllers can create additional instances of the application's class. In this case, the class factory must be created and registered. If the switch is present, Hello creates a new CHelloCF object and calls its AddRef method, thereby creating the class factory.

Next, the sample calls CoRegisterClassObject to register the class factory. It passes the object's class ID (CLSID_Hello), a pointer to the CHelloCF object (pcf), and two constants (CLSCTX_LOCAL_SERVER and REGCLS_SINGLEUSE) that govern the class factory's use. CLSCTX_LOCAL_SERVER indicates that the executable code for the object runs in a separate process from the controller. REGCLS_SINGLEUSE allows only one OLE Automation controller to use each instance of the class factory. The value returned through pdwRegisterCF must later be used to revoke the class factory.

Finally, the sample registers the active object. Registering an active object lets OLE Automation controllers retrieve an object that is already running, rather than create a new instance of the object. The Application object must be registered.


Implementing IUnknown

Every OLE object must implement the IUnknown interface, which allows controllers to query the object to find out what interfaces it supports. IUnknown has three member functions: QueryInterface, AddRef, and Release. The sample implements them for the CHello object as follows (HELLO.CPP):

STDMETHODIMP

CHello::QueryInterface(REFIID iid, void FAR* FAR* ppv)

{

*ppv = NULL;

if (iid == IID_IUnknown || iid == IID_IDispatch || iid == IID_IHello

*ppv = this;

else if (iid == IID_ISupportErrorInfo)

*ppv = &m_SupportErrorInfo;

else return ResultFromScode(E_NOINTERFACE);

AddRef();

return NOERROR;

}

STDMETHODIMP_(ULONG)

CHello::AddRef(void)

{

return ++m_cRef;

}

STDMETHODIMP_(ULONG)

CHello::Release(void)

{

if (--m_cRef == 0)

{

delete this;

return 0;

}

return m_cRef;

}


Implementing IClassFactory

A class factory is a class that is capable of creating instances of another class. Hello implements a single class factory, called CHelloCF, as follows (HELLOCF.CPP):

CHelloCF::CHelloCF(void)

{

m_cRef = 0;

}

STDMETHODIMP

CHelloCF::QueryInterface(REFIID iid, void FAR* FAR* ppv)

{

*ppv = NULL;

if (iid == IID_IUnknown || iid == IID_IClassFactory)

*ppv = this;

else

return ResultFromScode(E_NOINTERFACE);

AddRef();

return NOERROR;

}

STDMETHODIMP_(ULONG)

CHelloCF::AddRef(void)

{

return ++m_cRef;

}

STDMETHODIMP_(ULONG)

CHelloCF::Release(void)

{

if (--m_cRef == 0)

{

delete this;

return 0;

}

return m_cRef;

}

STDMETHODIMP

CHelloCF::CreateInstance(IUnknown FAR* punkOuter,

REFIID riid,

void FAR* FAR* ppv)

{

HRESULT hr;

*ppv = NULL;

// This implementation doesn't allow aggregation.

if (punkOuter)

return ResultFromScode(CLASS_E_NOAGGREGATION);

hr = g_phello->QueryInterface(riid, ppv);

if (FAILED(hr))

{

g_phello->Quit();

return hr;

}

return NOERROR;

}

STDMETHODIMP

CHelloCF::LockServer(BOOL fLock)

{

CoLockObjectExternal(g_phello, fLock, TRUE);

return NOERROR;

}

The class factory supports six member functions. QueryInterface, AddRef, and Release are the required IUnknown members, and CreateInstance and LockServer are the required IClassFactory members. The function CHelloCF::CHelloCF is a C++ constructor function. By default, the constructor function initializes the object's VTBLs; CHelloCF::CHelloCF also initializes the reference count for the class.


Implementing IDispatch

The IDispatch interface provides access to and information about an object. The interface requires the member functions GetTypeInfoCount, GetTypeInfo, GetIdsOfNames, and Invoke. The Hello sample implements IDispatch as follows (HELLO.CPP):

STDMETHODIMP

CHello::GetTypeInfoCount(UINT FAR* pctinfo)

{

*pctinfo = 1;

return NOERROR;

}

STDMETHODIMP

CHello::GetTypeInfo(

UINT itinfo,

LCID lcid,

ITypeInfo FAR* FAR* pptinfo)

{

*pptinfo = NULL;

if(itinfo != 0)

return ResultFromScode(DISP_E_BADINDEX);

m_ptinfo->AddRef();

*pptinfo = m_ptinfo;

return NOERROR;

}

STDMETHODIMP

CHello::GetIDsOfNames(

REFIID riid,

OLECHAR FAR* FAR* rgszNames,

UINT cNames,

LCID lcid,

DISPID FAR* rgdispid)

{

return DispGetIDsOfNames(m_ptinfo, rgszNames, cNames, rgdispid);

}

STDMETHODIMP

CHello::Invoke(

DISPID dispidMember,

REFIID riid,

LCID lcid,

WORD wFlags,

DISPPARAMS FAR* pdispparams,

VARIANT FAR* pvarResult,

EXCEPINFO FAR* pexcepinfo,

UINT FAR* puArgErr)

{

HRESULT hr;

m_bRaiseException = FALSE;

hr =  DispInvoke(

this, m_ptinfo,

dispidMember, wFlags, pdispparams,

pvarResult, pexcepinfo, puArgErr);

if (m_bRaiseException)

{

if (NULL != pexcepinfo)

_fmemcpy(pexcepinfo, &m_excepinfo, sizeof(EXCEPINFO));

return ResultFromScode(DISP_E_EXCEPTION);

}

else return hr;

}

OLE Automation includes two functions, DispGetIdsOfNames and DispInvoke, which provide standard implementations for IDispatch::GetIdsOfNames and IDispatch::Invoke. The Hello sample uses these two functions to simplify the code.


Implementing VTBL Binding

In addition to the IDispatch interface, the Hello sample supports VTBL binding. Objects that support a VTBL interface return an HRESULT instead of a value when a member is invoked, and pass their return value as the last parameter. They may also accept a locale identifier (LCID) parameter, which allows them to parse strings correctly for the local language. The following example shows how the Visible property is implemented (HELLO.CPP):

STDMETHODIMP

CHello::put_Visible(BOOL bVisible)

{

ShowWindow(bVisible ? SW_SHOW : SW_HIDE);

return NOERROR;

}

STDMETHODIMP

CHello::get_Visible(BOOL FAR* pbool)

{

*pbool =  m_bVisible;

return NOERROR;

}

Additional information must be specified in ODL to create a dual interface, as shown in "Creating the Type Information."


Handling Errors

Hello includes an exception handler, which passes exceptions through IDispatch::Invoke and supports rich error information through VTBLs (HELLO.CPP):

STDMETHODIMP

CHello::RaiseException(int nID)

{

extern SCODE g_scodes[];

char szError[STR_LEN];

ICreateErrorInfo *pcerrinfo;

IErrorInfo *perrinfo;

HRESULT hr;

_fmemset(&m_excepinfo, 0, sizeof(EXCEPINFO));

m_excepinfo.wCode = nID;

if (LoadString(m_hinst, nID, szError, sizeof(szError)))

m_excepinfo.bstrDescription = SysAllocString(szError);

m_excepinfo.bstrSource = SysAllocString(m_bstrName);

m_bRaiseException = TRUE;

// Set ErrInfo object so that VTBL binding container
// applications can get rich error information.

hr = CreateErrorInfo(&pcerrinfo);

if (SUCCEEDED(hr))

{

pcerrinfo->SetGUID(IID_IHello);

if (m_excepinfo.bstrSource)

pcerrinfo->SetSource(m_excepinfo.bstrSource);

if (m_excepinfo.bstrDescription)

pcerrinfo->SetDescription(m_excepinfo.bstrDescription);

hr = pcerrinfo->QueryInterface(IID_IErrorInfo,

(LPVOID FAR*) &perrinfo);

if (SUCCEEDED(hr))

{

SetErrorInfo(0, perrinfo);

perrinfo->Release();

}

pcerrinfo->Release();

}

return ResultFromScode(g_scodes[nID-1001]);

}

Hello's member functions call this routine when an exception occurs. RaiseException fills in an EXCEPINFO structure that is available through IDispatch::Invoke. It also sets the system's error object, so that container applications that call through VTBLs can retrieve rich error information. Note that because IDispatch::Invoke is effectively such a container, it retrieves the rich error information and returns it through the EXCEPINFO parameter.

Hello also implements the ISupportErrorInfo interface, which allows OLE Automation controllers to query whether an error object will be available (HELLO.CPP):

CSupportErrorInfo::CSupportErrorInfo(IUnknown FAR* punkObject,

REFIID riid)

{

m_punkObject = punkObject;

m_iid = riid;

}

STDMETHODIMP

CSupportErrorInfo::QueryInterface(REFIID iid, void FAR* FAR* ppv)

{

return m_punkObject->QueryInterface(iid, ppv);

}

STDMETHODIMP_(ULONG)

CSupportErrorInfo::AddRef(void)

{

return m_punkObject->AddRef();

}

STDMETHODIMP_(ULONG)

CSupportErrorInfo::Release(void)

{

return m_punkObject->Release();

}

STDMETHODIMP

CSupportErrorInfo::InterfaceSupportsErrorInfo(REFIID riid)

{

return (riid == m_iid) ? NOERROR : ResultFromScode(S_FALSE);

}


Releasing Objects and OLE

When the Hello application ends, it revokes the class factory and the active object, and uninitializes OLE. For example (MAIN.CPP):

void Uninitialize(DWORD dwRegisterCF, DWORD dwRegisterActiveObject)

{

if (dwRegisterCF != 0)

CoRevokeClassObject(dwRegisterCF);

if (dwRegisterActiveObject != 0)

RevokeActiveObject(dwRegisterActiveObject, NULL);

OleUninitialize();

}


Creating the Type Information

Type information for the Hello sample is described in ODL. MkTypLib compiles the ODL file to create a type library (HELLOTL.TLB) and a header file (HELLOTL.H). The following example shows the description for the Hello type library, interface, and Application object (HELLO.ODL):

[

uuid(F37C8060-4AD5-101B-B826-00DD01103DE1),      // LIBID_Hello

helpstring("Hello 2.0 Type Library"),

lcid(0x0409),

version(2.0)

]

library Hello

{

    importlib("stdole.tlb");

    [

      uuid(F37C8062-4AD5-101B-B826-00DD01103DE1),   // IID_IHello

      helpstring("Application object for the Hello application."),

      oleautomation,

      dual

    ]

    interface IHello : IDispatch

    {

      	[propget, helpstring("Returns the application of the object.")]

      	HRESULT Application([out, retval] IHello** retval);

[propget,

helpstring("Returns the full name of the application.")]

      	HRESULT FullName([out, retval] BSTR* retval);

      	[propget, id(0),

helpstring("Returns the name of the application.")]

      	HRESULT Name([out, retval] BSTR* retval);

        [propget, helpstring("Returns the parent of the object.")]

        HRESULT Parent([out, retval] IHello** retval);

        [propput]

        HRESULT Visible([in] boolean VisibleFlag);

        [propget,

helpstring

("Sets or returns whether the main window is visible.")]

        HRESULT Visible([out, retval] boolean* retval);

        [helpstring("Exits the application.")]

        HRESULT Quit();

        [propput,

helpstring("Sets or returns the hello message to be used.")]

        HRESULT HelloMessage([in] BSTR Message);

        [propget]

        HRESULT HelloMessage([out, retval] BSTR *retval);

        [helpstring("Say Hello using HelloMessage.")]

        HRESULT SayHello();

    }

    [

       uuid(F37C8061-4AD5-101B-B826-00DD01103DE1),      // CLSID_Hello

       helpstring("Hello Class"),

       appobject

    ]

    coclass Hello

    {

        [default]          interface IHello;

                           interface IDispatch;

    }

}

The items enclosed by square brackets are attributes, which provide further information about the objects in the file. The oleautomation and dual attributes, for example, indicate that the IHello interface supports both IDispatch and VTBL binding. The appobject attribute indicates that the Hello is the Application object.


Creating a Registration File for the "Hello World" Example

The system registration database lists all the OLE objects in the system. OLE uses this database to locate objects and to determine their capabilities. The registration file registers the application, the type library, and the exposed classes of the sample (HELLO.REG):

REGEDIT

; Registration information for OLE Automation Hello 2.0 Application

; Version independent registration. Points to Version 2.0

HKEY_CLASSES_ROOT\Hello.Application = Hello 2.0 Application

HKEY_CLASSES_ROOT\Hello.Application\Clsid = {F37C8061-4AD5-101B-B826-00DD01103DE1}

; Version 2.0 registration

HKEY_CLASSES_ROOT\Hello.Application.2 = Hello 2.0 Application

HKEY_CLASSES_ROOT\Hello.Application.2\Clsid = {F37C8061-4AD5-101B-B826-00DD01103DE1}

HKEY_CLASSES_ROOT\CLSID\{F37C8061-4AD5-101B-B826-00DD01103DE1} = Hello 2.0 Application

HKEY_CLASSES_ROOT\CLSID\{F37C8061-4AD5-101B-B826-00DD01103DE1}\ProgID = Hello.Application.2

HKEY_CLASSES_ROOT\CLSID\{F37C8061-4AD5-101B-B826-00DD01103DE1}\VersionIndependentProgID = Hello.Application

HKEY_CLASSES_ROOT\CLSID\{F37C8061-4AD5-101B-B826-00DD01103DE1}\LocalServer = hello.exe /Automation

; Type library registration information

HKEY_CLASSES_ROOT\TypeLib\{F37C8060-4AD5-101B-B826-00DD01103DE1}

HKEY_CLASSES_ROOT\TypeLib\{F37C8060-4AD5-101B-B826-00DD01103DE1}\2.0 = Hello 2.0 Type Library

HKEY_CLASSES_ROOT\TypeLib\{F37C8060-4AD5-101B-B826-00DD01103DE1}\2.0\HELPDIR =

;US english

HKEY_CLASSES_ROOT\TypeLib\{F37C8060-4AD5-101B-B826-00DD01103DE1}\2.0\409\win16 = hello.tlb

; Interface registration. All interfaces that support vtable binding must be

; registered as follows. RegisterTypeLib & LoadTypeLib will do this automatically.

; IID_IHello = {F37C8062-4AD5-101B-B826-00DD01103DE1}

; LIBID_Hello = {F37C8060-4AD5-101B-B826-00DD01103DE1}

HKEY_CLASSES_ROOT\Interface\{F37C8062-4AD5-101B-B826-00DD01103DE1} = IHello

HKEY_CLASSES_ROOT\Interface\{F37C8060-4AD5-101B-B826-00DD01103DE1}\TypeLib = {F37C8060-4AD5-101B-B826-00DD01103DE1}

HKEY_CLASSES_ROOT\Interface\{F37C8060-4AD5-101B-B826-00DD01103DE1}\ProxyStubClsid = {00020424-0000-0000-C000-000000000046}

To merge your object's registration information with the system registry, your object should expose the DLLRegisterServer API, as described in the OLE Controls Reference. DLLRegisterServer should call RegisterTypeLib to register the type library and the interfaces supported by your application.


Limitations of the "Hello World" Example

The "Hello World" example was simplified for demonstration purposes. It has the following limitations:

•	Has only one object.

•	Uses only scalar argument types. OLE Automation also supports methods and properties that accept arguments of complex types, including arrays, references to objects, and formatted data, but not structures.

•	Supports one national language. DispInvoke does not accommodate multiple localized member names, and therefore is useful only for single-language applications.

The remainder of this chapter explains in more detail the OLE Automation features that appear in Hello, as well as covering these more advanced features. Filenames in the rest of the chapter refer to the Lines sample.


Creating Class IDs

Each object you expose for creation must have a unique class identifier (CLSID). CLSIDs are universally unique identifiers (UUIDs, also called globally unique identifiers, or GUIDs) that identify class objects to OLE. The CLSID is included in your application and must be registered with the operating system when your application is installed.

Run the GUIDGEN.EXE utility included in the \OLE2\BIN directory to generate UUIDs. By default, GUIDGEN puts a DEFINE_GUID macro on the clipboard which you can paste into your source.

In the following example, the macro defines a class ID for Lines (TLB.H):

DEFINE_GUID(CLSID_Lines,0x3C591B21,0x1F13,0x101B,0xB8,0x26,0x00,0xDD,0x01,0x10,0x3D,0xE1);

When MkTypLib creates the optional header file (TLB.H), it inserts DEFINE_GUID macros for each library, interface, and class in your application.


Initializing OLE

OLE2.DLL provides functions to initialize OLE and to initialize exposed objects for creation using OLE Automation.

To initialize OLE

1.	Initialize the OLE DLLs by calling OleInitialize.

2.	Create an instance of each class factory you expose. You need a class factory for the Application object and any other top-level objects.

3.	Call CoRegisterClassObject for each class your application exposes.

The following routine initializes OLE, then creates an instance of the Lines Application object (Lines sample, MAIN.CPP):

BOOL InitInstance (HINSTANCE hinst)

{

HRESULT hr;

// Intialize OLE

hr = OleInitialize(NULL);

if (FAILED(hr))

return FALSE;

// Create an instance of the Lines Application object. The object is

// created with refcount 0.

hr = CApplication::Create(hinst, &g_pApplication);

if (FAILED(hr))

return FALSE;

return TRUE;

}


Initializing the Active Object

The following function creates and registers the application's class factory, then registers the Lines Application object as the active object (MAIN.CPP):

BOOL ProcessCmdLine(LPSTR lpCmdLine, LPDWORD pdwRegisterCF,

LPDWORD pdwRegisterActiveObject, int nCmdShow)

{

LPCLASSFACTORY pcf = NULL;

HRESULT hr;

*pdwRegisterCF = 0;

*pdwRegisterActiveObject = 0;

// Expose class factory for application object if command line

// contains the /Automation switch.

if (_fstrstr(lpCmdLine, "-Automation") != NULL

|| _fstrstr(lpCmdLine, "/Automation") != NULL)

{

pcf = new CApplicationCF;

if (pcf)

goto error;

pcf->AddRef();

hr = CoRegisterClassObject(CLSID_Lines, pcf,

CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE,

pdwRegisterCF);

if (hr != NOERROR)

goto error;

pcf->Release();

}

else	// Show window if started stand-alone

g_pApplication->ShowWindow(nCmdShow );

// Register Lines application object in the Running Object Table (ROT) // Use weak registration so that the ROT releases its reference when

// all external references are released.

RegisterActiveObject(g_pApplication, CLSID_Lines, ACTIVEOBJECT_WEAK,

pdwRegisterActiveObject);

return TRUE;

error:

if (!pcf)

pcf->Release();

return FALSE;

}

OLE Automation provides several functions to identify and retrieve the running instance of an object or application:

•	RegisterActiveObject — Sets the active object for an application. (Use when application starts.)

•	RevokeActiveObject — Revokes the active object. (Use when application ends.)

•	GetActiveObject — Retrieves a pointer to the object that is active. (In Visual Basic, this is implemented by the GetObject function.)

Applications can have more than one active object at a time. To be initialized as an active object, an object must:

•	Have a class factory (that is, the object provides an interface for creating instances of itself).

•	Identify its class factory by a programmatic ID (ProgID) in the system registry.

•	Be registered by a call to RegisterActiveObject when the object is created or becomes active.

The Application object must be registered as an active object.

The example exposes the class factory for the Lines application, CApplicationCF, if the command line contains the /Automation switch. OLE applies this switch if it appears on the command line or in the application's registration entry. The switch indicates that the application was started for programmatic access, and therefore OLE needs to register the class factory and create an instance of the Application object. OLE also supports the /Embedding switch, which indicates that an application was started by a container application.

You should register the Application object's class factory only if the application is launched with the /Automation switch. When /Automation is not specified, the application was started for some reason other than programmatic access through OLE Automation. If you register the class factory under these circumstances, and the user later requests a new instance of the Application object, OLE Automation will return the existing instance instead of creating a new instance.

The sample calls CoRegisterClassObject to register the class factory as the active object. The CLSCTX_LOCAL_SERVER flag means that the code that creates and manages Application objects will run in a separate process space on this machine.

Because the Application object's class factory is exposed, the call specifies the REGCLS_SINGLEUSE flag. When a multiple-document interface (MDI) application starts, it typically registers the class factory for its Document object, specifying REGCLS_MULTIPLEUSE. This attribute allows the existing application instance to be used later, when instances of the document objects need to be created. Each new Application object, however, requires a new instance of the application to be launched, and therefore should specify REGCLS_SINGLEUSE. If the application registered its class factory using REGCLS_MULTIPLEUSE, the next CreateObject call that tried to create the application would get an existing copy.

The following chart shows how applications should expose their Application and Document objects.

Command line	MDI application	SDI application
/Embedding	Expose class factories  for document classes, but  not for the application. Call RegisterActiveObject  for the Application object.	Expose class factories for document class, but not for the application. Call RegisterActiveObject for the Application object.
/Automation	Expose class factories for  document classes. Expose class factory for  the application using  RegisterClassObject. Call RegisterActiveObject  for the Application object.	Do not expose class factory for document class. Expose class factory for the Application object using RegisterClassObject. Call RegisterActiveObject for the Application object.
No OLE switches	Expose class factories  for document classes, but  not for the application. Call RegisterActiveObject  for the Application object.	Call RegisterActiveObject for the Application object.
The call to RegisterActiveObject enters the Application object in OLE's running object table, so that OLE Automation controllers can retrieve the running object instead of creating a new instance. Thus, Visual Basic applications can use the GetObject statement to access an existing object.

The example specifies weak registration (ACTIVEOBJECT_WEAK), which means that OLE will release the object when all external connections to it have disappeared. OLE Automation objects should always be given weak registration. See RegisterActiveObject in Chapter 5 for more information.

The OLE 2 Programmer's Reference, Volume 1 provides more information on the OleInitialize and CoRegisterClassObject functions. Inside OLE 2 provides more information on verifying your application's entries in the registration database.


Creating the IUnknown Interface

IUnknown defines three member functions you must implement for each object you expose. The prototypes for these functions reside in OLE2.H:

•	QueryInterface — Identifies which OLE interfaces the object supports.

•	AddRef — Increments a member variable that tracks the number of references to the object.

•	Release — Decrements the member variable that tracks the instances of the object. If an object has zero references, Release frees the object.

These functions provide the fundmental interface through which OLE can access your objects. The OLE 2 Programmer's Reference, Volume 1, describes in detail how to implement the functions.

The IUnknown interface for the Line object looks like this (Lines sample, LINE.CPP):

STDMETHODIMP

CLine::QueryInterface(REFIID iid, void FAR* FAR* ppv)

{

*ppv = NULL;

if (iid == IID_IUnknown || iid == IID_IDispatch || iid == IID_ILine)

*ppv = this;

else if (iid == IID_ISupportErrorInfo)

*ppv = &m_SupportErrorInfo;

else return ResultFromScode(E_NOINTERFACE);

AddRef();

return NOERROR;

}

STDMETHODIMP_(ULONG)

CLine::AddRef(void)

{

return ++m_cRef;

}

STDMETHODIMP_(ULONG)

CLine::Release(void)

{

if(--m_cRef == 0)

{

delete this;

return 0;

}

return m_cRef;

}

The Line object implements the IID_ILine dual interface for VTBL binding. It also implements the IID_ISupportErrorInfo interface, so that it can return rich, contextual error information through VTBLs.


Exposing Objects for Creation with IClassFactory

Before OLE can create an object, it needs access to the object's class factory. The class factory implements the IClassFactory interface. For detailed information about this interface, see Inside OLE and the OLE 2 Programmer's Reference, Volume1; this chapter only describes what you must do to expose objects for OLE Automation.

You need to implement a class factory for objects that may be created explicitly through the OLE function CoCreateInstance or the Visual Basic New operator. For example, an application exposes an Application object for creation, but may have many other programmable objects that can be created or destroyed by referencing a member of the Application object. In this case, only the Application object needs a class factory.

For each class factory, you need to implement the following two member functions, which provide services for OLE API functions. The prototypes for the member functions reside in OLE2.H:

•	CreateInstance — Creates an instance of the object's class.

•	LockServer — Prevents the object's server from shutting down, even if the last instance of the object is released. LockServer can improve the performance of applications that create and release objects frequently.

In general, the CreateInstance method should create a new instance of the object's class. For the Application object, however, the CreateInstance method should return the existing instance of the Application object, which is registered in the running object table.

The Lines sample implements a class factory for its Application object, as follows (APPCF.CPP):

STDMETHODIMP

CApplicationCF::CreateInstance(IUnknown FAR* punkOuter,

REFIID riid,

void FAR* FAR* ppv)

{

HRESULT hr;

*ppv = NULL;

// This implementation doesn't allow aggregation.

if (punkOuter)

return ResultFromScode(CLASS_E_NOAGGREGATION);

// This is REGCLS_SINGLEUSE class factory, so CreateInstance will be

// called at most once. An application object has a REGCLS_SINGLEUSE

// class factory. The global application object has already been

// created when CreateInstance is called. A REGCLS_MULTIPLEUSE class

// factory's CreateInstance would be called multiple times and would

// create a new object each time. An MDI application would have a

// REGCLS_MULTIPLEUSE class factory for its document objects.

hr = g_pApplication->QueryInterface(riid, ppv);

if (FAILED(hr))

{

g_pApplication->Quit();

return hr;

}

return NOERROR;

}

STDMETHODIMP

CApplicationCF::LockServer(BOOL fLock)

{

CoLockObjectExternal(g_pApplication, fLock, TRUE);

return NOERROR;

}

The object's class factory must also implement an IUnknown interface. For example (APPCF.CPP):

STDMETHODIMP

CApplicationCF::QueryInterface(REFIID iid, void FAR* FAR* ppv)

{

*ppv = NULL;

if (iid == IID_IUnknown || iid == IID_IClassFactory)

*ppv = this;

else

return ResultFromScode(E_NOINTERFACE);

AddRef();

return NOERROR;

}

STDMETHODIMP_(ULONG)

CApplicationCF::AddRef(void)

{

return ++m_cRef;

}

STDMETHODIMP_(ULONG)

CApplicationCF::Release(void)

{

if(--m_cRef == 0)

{

delete this;

return 0;

}

return m_cRef;

}


Creating the IDispatch Interface

IDispatch provides a late-bound mechanism to access and retrieve information about an object's methods and properties. In addition to the member functions inherited from IUnknown, you need to implement the following member functions within the class definition of each object you expose through OLE Automation:

•	GetTypeInfoCount — Returns the number of type descriptions for the object. For objects that support IDispatch, the type information count is always 1.

•	GetTypeInfo — Retrieves a description of the object's programmable interface.

•	GetIDsOfNames — Maps the name of a method or property to a Dispatch ID, which can later be used to invoke the method or property.

•	Invoke —Calls one of the object's methods, or gets or sets one of its properties.

You may implement IDispatch by any of the following means:

•	Calling the CreateStdDispatch function. This approach is the simplest, but it does not provide for rich error handling or multiple national languages.

•	Delegating to the DispInvoke and DispGetIDsOfNames functions, or to ITypeInfo::Invoke and ITypeInfo::GetIDsOfNames. This is the recommended approach, because it supports multiple locales and allows you to return exceptions.

•	Implementing the member functions without delegating to the dispatch functions. This approach is seldom necessary. Because Invoke is a complex interface with many subtle semantics that are difficult to emulate, Microsoft strongly recommends that your code delegate to ITypeInfo::Invoke to implement this mechanism.

The following sections explain how to use CreateStdDispatch and DispInvoke to implement IDispatch.


Implementing IDispatch by Calling CreateStdDispatch

The simplest way to implement the IDispatch interface is to call CreateStdDispatch. This approach works for OLE Automation objects that return only the standard dispatch exception codes, support a single national language, and do not support dual interfaces.

CreateStdDispatch returns a pointer to the created IDispatch interface. It takes three pointers as input: a pointer to the object's IUnknown interface; a pointer to the object to expose; and a pointer to the type information for the object. The following example implements IDispatch for an object named CCalc by calling CreateStdDispatch on the loaded type information:

CCalc FAR*

CCalc::Create()

{

HRESULT hresult;

CCalc FAR* pcalc;

ITypeLib FAR* ptlib;

ITypeInfo FAR* ptinfo;

IUnknown FAR* punkStdDisp;

ptlib = NULL;

ptinfo = NULL;

// Some error handling code omitted...

if ((pcalc = new FAR CCalc()) == NULL)

return NULL;

pcalc->AddRef();

// Load the type library from the information in the registry.

if ((hresult = LoadRegTypeLib(LIBID_DspCalc2, 1, 0, 0x0409, &ptlib))

!= 	NOERROR){

goto LError0;

}

if ((hresult = ptlib->GetTypeInfoOfGuid(IID_ICalculator, &ptinfo))

!= NOERROR){

goto LError0;

}

// Create an aggregate with an instance of the default

// implementation of IDispatch that is initialized with our

// TypeInfo.

//

hresult = CreateStdDispatch(

pcalc,	// controlling unknown

&(pcalc->m_arith),	// VTBL pointer to dispatch on

ptinfo,

&punkStdDisp);


Implementing IDispatch by Delegating

Another way to implement IDispatch is to use the dispatch functions DispInvoke and DispGetIDsOfNames. These functions give you the option of supporting multiple national languages and creating application-specific exceptions that are passed back to OLE Automation controllers.

The Lines sample implements IDispatch::GetIDsOfNames and IDispatch::Invoke using these functions (LINES.CPP):

STDMETHODIMP

CLines::GetIDsOfNames(

REFIID riid,

char FAR* FAR* rgszNames,

UINT cNames,

LCID lcid,

DISPID FAR* rgdispid)

{

return DispGetIDsOfNames(m_ptinfo, rgszNames, cNames, rgdispid);

}

STDMETHODIMP

CLines::Invoke(

DISPID dispidMember,

REFIID riid,

LCID lcid,

WORD wFlags,

DISPPARAMS FAR* pdispparams,

VARIANT FAR* pvarResult,

EXCEPINFO FAR* pexcepinfo,

UINT FAR* puArgErr)

{

HRESULT hr;

m_bRaiseException = FALSE;

hr =  DispInvoke(

this, m_ptinfo,

dispidMember, wFlags, pdispparams,

pvarResult, pexcepinfo, puArgErr);

if (m_bRaiseException)

{

if (NULL != pexcepinfo)

_fmemcpy(pexcepinfo, &m_excepinfo, sizeof(EXCEPINFO));

return ResultFromScode(DISP_E_EXCEPTION);

}

else return hr;

}

In the preceding example, CLines::Invoke handles exceptions by initializing the variable m_bRaiseException to False before calling DispInvoke. If an exception occurs, the invoked member places error information in the variable m_excepinfo, and sets m_bRaiseException to True. Then CLines::Invoke copies m_excepinfo and returns DISP_E_EXCEPTION.


Setting Up the VTBL Interface

The Lines sample supports VTBL binding as well as the IDispatch interface. By supporting this dual interface, the sample allows OLE Automation controllers both the flexibility of the IDispatch interface and the speed of VTBLs. Controllers that know the names of the members can compile directly against the function pointers in the VTBL; controllers that don't have this information can use IDispatch at run time.

To have a dual interface, an interface must:

•	Declare all its members to return an HRESULT and pass their actual return values as the last parameter.

•	Have only OLE Automation-compatible parameters and return types, as described in Chapter 7, "MkTypLib and Object Description Language."

•	Specify the dual attribute on the interface description in the ODL file.

•	Initialize the VTBLs with the appropriate member function pointers.

The IPoint, IPoints, ILine, ILines, IPane, and IApplication interfaces in the Lines sample are all dual interfaces. The IPoint interface defines functions that get and put the values of the X and Y properties, as follows (POINT.CPP):

STDMETHODIMP

CPoint::get_x(int FAR* pnX)

{

*pnX = m_nX;

return NOERROR;

}

STDMETHODIMP

CPoint::put_x(int nX)

{

m_nX = nX;

return NOERROR;

}

STDMETHODIMP

CPoint::get_y(int FAR* pnY)

{

*pnY = m_nY;

return NOERROR;

}

STDMETHODIMP

CPoint::put_y(int nY)

{

m_nY = nY;

return NOERROR;

}

The get_x and get_y accessor functions pass their return values in the last parameter, pnX and pnY, and return an HRESULT as the function value.

In the ODL file, the interface is described as follows (LINES.ODL):

[

uuid(3C591B25-1F13-101B-B826-00DD01103DE1),    // IID_IPoint

helpstring("Point object."),

oleautomation,

dual

]

interface IPoint : IDispatch

{

[propget, helpstring("Returns and sets x coordinate.")]

HRESULT x([out, retval] int* retval);

[propput, helpstring("Returns and sets x coordinate.")]

HRESULT x([in] int Value);

[propget, helpstring("Returns and sets y coordinate.")]

HRESULT y([out, retval] int* retval);

[propput, helpstring("Returns and sets y coordinate.")]

HRESULT y([in] int Value);

}

The oleautomation and dual attributes indicate that the interface supports both IDispatch and VTBL binding. All the member functions are declared with HRESULT return values. The get accessor functions, indicated by the propget attribute, return their value in the last parameter. This parameter has the out and retval attributes.

For more information on dual interfaces, see the reference page for the dual attribute in Chapter 7.


Creating the Programmable Interface

An object's programmable interface comprises the properties and methods it defines. Organizing the objects, properties, and methods that an application exposes is like creating an object-oriented framework for an application. Chapter 4, "Standards and Guidelines," discusses some of the concepts behind naming and organizing the programmable elements your application may expose.


Creating Methods

A method is an action that an object can perform, such as drawing a line or clearing the display. Methods can take any number of arguments, including optional arguments, and they may be passed either by value or by reference. A method may or may not return a value.

In the Lines sample, the Application object exposes the following method (APP.CPP):

STDMETHODIMP

CApplication::CreatePoint(IPoint FAR* FAR* ppPoint)

{

CPoint FAR* ppoint = NULL;

HRESULT hr;

// Create new item and QI for IDispatch.

hr = CPoint::Create(&ppoint);

if (FAILED(hr))

{hr = RaiseException(IDS_OutOfMemory); goto error;}

hr = ppoint->QueryInterface(IID_IDispatch, (void FAR* FAR*)ppPoint);

if (FAILED(hr))

{hr = RaiseException(IDS_Unexpected); goto error;}

return NOERROR;

error:

if (ppoint)

delete ppoint;

return hr;

}

The CreatePoint method creates a new point and returns a pointer to it in the parameter pPoint.


Creating Properties

A property is a member function that sets or returns information about the state of the object, such as color or visibility. Most properties have a pair of accessor functions — a function to get the property value and a function to set the property value. Properties that are read-only or write-only, however, have only one accessor function.

In the Lines sample, the CLine object exposes the Color property. This property is implemented by the following accessor functions (LINE.CPP):

STDMETHODIMP

CLine::get_Color(long FAR* plColorref)

{

*plColorref =  m_colorref;

return NOERROR;

}

STDMETHODIMP

CLine::put_Color(long lColorref)

{

m_colorref = (COLORREF)lColorref;

return NOERROR;

}

The accessor functions for a single property have the same dispatch ID (DISPID). The purpose of each function is indicated by attributes set for the function. These attributes are set in the ODL description of the function (as in LINES.ODL) and are passed in the wFlags parameter to Invoke to set the context for the call. The attributes and flags are shown in the following table:

Purpose of function	ODL attribute	wFlags
Return a value	propget	DISPATCH_PROPERTYGET
Set a value	propput	DISPATCH_PROPERTYPUT
Set a reference	propputref	DISPATCH_PROPERTYPUTREF
The propget attribute designates the accessor function that gets the value of a property. When OLE Automation controller needs to get the value of the property, it passes the DISPATCH_PROPERTYGET flag to Invoke.

The propput attribute designates the accessor function that sets the value of a property. When an OLE Automation controller needs to set a property by value, it passes the DISPATCH_PROPERTYPUT flag to Invoke. In Visual Basic, Let statements set properties by value.

The propputref attribute indicates that the property should be set by reference, rather than by value. OLE Automation controllers that need to set a reference to a property pass DISPATCH_PROPERTYPUTREF in these cases. Visual Basic treats the Set statement as a by-reference property assignment.


The Value Property

The Value property defines the default behavior of an object when no property or method is specified. It is typically used for the property that users associate most closely with the object. For example, a cell in a spreadsheet might have many properties (Font, Width, Height, and so on), but its Value property is special, yielding the value of the cell. To refer to this property, a user need not specify the property name Cell(1,1).Value, but can simply use Cell(1,1).

The Value property is identified by the dispatch ID DISPID_VALUE. In an ODL file, the Value property for an object has the attribute id(0).

In the Lines sample, ILines.Item, IPoints.Item, and IApplication.Name are the Value properties of the ILines, IPoints, and IApplication objects, respectively. The ILines.Item object is described as follows:

interface ILines : IDispatch

{

.

.//Some descriptions omitted

.

[propget, id(0), helpstring(

"Given an integer index, returns one of the lines in the collection")]

HRESULT Item([in] long Index,[out, retval] ILine** retval);

.

.

.

}

Using this property, a user can refer to the fourth line in the collection as ILines(4).Item or simply as ILines(4).

See Chapter 4, "Standards and Guidelines," for more on recommended objects, properties, and methods.


Returning Objects

To return an object from a property or method, the application should return a pointer to the object's implementation of the IDispatch interface. The data type of the return value should be VT_DISPATCH or VT_UNKNOWN (if the object doesn't support IDispatch). The Object Description Language (ODL) for the object should specify the name of the interface, rather than IDispatch*, as follows:

ICustom * MyMember(...) {...};

The example declares a member that returns a pointer to a custom interface called ICustom.


Passing Formatted Data

Often, an application needs to accept formatted data as an argument to a method or property. Examples include a bitmap, formatted text, or a spreadsheet range. When handling formatted data, the application should pass an object that implements the OLE IDataObject interface. For detailed information about the interface, see  the OLE 2 Programmer's Reference, Volume 1.

Using this interface, applications can retrieve data of any Clipboard format. Because an IDataObject instance can provide data of more than one format, a caller can provide data in several formats, and let the called object choose which format is most appropriate (like the Clipboard).

If the data object implements IDispatch, it should be passed using the VT_DISPATCH flag. If the data object does not support IDispatch, it should be passed with the VT_UNKNOWN flag.


Restricting Access

OLE Automation provides several ways of restricting access to objects. The simplest approach is not to document the properties and methods you don't want customers to see. Alternatively, you can prevent a property or method from appearing in type library browsers by specifying the hidden attribute in ODL.

The restricted attribute goes one step further, preventing user calls from binding to the property or method as well as hiding it from type browsers. For example, the following restricts access to the _NewEnum property of the ILines object:

[propget, restricted, id(DISPID_NEWENUM)]  // Must be propget.

HRESULT _NewEnum( [out, retval] IUnknown** retval);

Restricted properties and methods can be invoked by OLE Automation controllers, but are not visible to the customer or end user who may be using a language such as Visual Basic. In addition, they can't be bound to by user calls.


Creating Collection Objects

A collection object contains a group of exposed objects of the same type and can iterate over them. Collection objects do not need an IClassFactory implementation, because they are accessed from elements that have their own class factories.

For example, the Lines sample has a collection object named CLines that iterates over a group of Line objects. The following routine creates and initializes the CLines collection object (LINES.CPP):

STDMETHODIMP

CLines::Create(ULONG lMaxSize, long lLBound, CPane FAR* pPane,

CLines FAR* FAR* ppLines)

{

HRESULT hr;

CLines FAR* pLines = NULL;

SAFEARRAYBOUND sabound[1];

*ppLines = NULL;

// Create new collection.

pLines = new CLines();

if (pLines == NULL)

goto error;

pLines->m_cMax = lMaxSize;

pLines->m_cElements = 0;

pLines->m_lLBound = lLBound;

pLines->m_pPane = pPane;

// Load type information for the Lines collection from type library.

hr = LoadTypeInfo(&pLines->m_ptinfo, IID_ILines);

if (FAILED(hr))

goto error;

// Create a safe array of variants used to implement the collection.

sabound[0].cElements = lMaxSize;

sabound[0].lLbound = lLBound;

pLines->m_psa = SafeArrayCreate(VT_VARIANT, 1, sabound);

if (pLines->m_psa == NULL)

{

hr = ResultFromScode(E_OUTOFMEMORY);

goto error;

}

*ppLines = pLines;

return NOERROR;

error:

if (pLines == NULL)

return ResultFromScode(E_OUTOFMEMORY);

if (pLines->m_ptinfo)

pLines->m_ptinfo->Release();

if (pLines->m_psa)

SafeArrayDestroy(pLines->m_psa);

pLines->m_psa = NULL;

pLines->m_ptinfo = NULL;

delete pLines;

return hr;

}

The parameters to CLines::Create specify the maximum number of lines that the collection can contain, the lower bound of the indexes of the collection, and a pointer to a pane, which contains the lines and points in the sample.

OLE Automation defines the IEnumVARIANT interface to provide a standard way for OLE Automation controllers to iterate over collections. In addition, every collection object must expose a read-only property named _NewEnum to let OLE Automation controllers know that the object supports iteration. The _NewEnum property returns an enumerator object that supports IEnumVariant.


Implementing IEnumVARIANT

The IEnumVARIANT interface provides a way to iterate through the items contained by a collection object. This interface is supported by an enumerator object that is returned by the _NewEnum property of the collection object, as in the following figure:

The IEnumVARIANT interface defines these member functions:

•	Next — Retrieves one or more elements in a collection, starting with the current element.

•	Skip — Skips over one or more elements in a collection.

•	Reset — Resets the current element to the first element in the collection.

•	Clone — Copies the current state of the enumeration so you can return to the current element after using Skip or Reset.

In the Lines example, CEnumVariant implements the Next, Skip, Reset, and Clone member functions (ENUMVAR.CPP):

STDMETHODIMP

CEnumVariant::Next(ULONG cElements, VARIANT FAR* pvar,

ULONG FAR* pcElementFetched)

{

HRESULT hr;

ULONG l;

long l1;

ULONG l2;

if (pcElementFetched != NULL)

*pcElementFetched = 0;

for (l=0; l<cElements; l++)

VariantInit(&pvar[l]);

// Retrieve the next cElements elements.

for (l1=m_lCurrent, l2=0; l1<(long)(m_lLBound+m_cElements) &&

l2<cElements; l1++, l2++)

{

hr = SafeArrayGetElement(m_psa, &l1, &pvar[l2]);

if (FAILED(hr))

goto error;

}

// Set count of elements retrieved

if (pcElementFetched != NULL)

*pcElementFetched = l2;

m_lCurrent = l1;

return  (l2 < cElements) ? ResultFromScode(S_FALSE) : NOERROR;

error:

for (l=0; l<cElements; l++)

VariantClear(&pvar[l]);

return hr;

}

STDMETHODIMP

CEnumVariant::Skip(ULONG cElements)

{

m_lCurrent += cElements;

if (m_lCurrent > (long)(m_lLBound+m_cElements))

{

m_lCurrent =  m_lLBound+m_cElements;

return ResultFromScode(S_FALSE);

}

else return NOERROR;

}

STDMETHODIMP

CEnumVariant::Reset()

{

m_lCurrent = m_lLBound;

return NOERROR;

}

STDMETHODIMP

CEnumVariant::Clone(IEnumVARIANT FAR* FAR* ppenum)

{

CEnumVariant FAR* penum = NULL;

HRESULT hr;

*ppenum = NULL;

hr = CEnumVariant::Create(m_psa, m_cElements, &penum);

if (FAILED(hr))

goto error;

penum->AddRef();

penum->m_lCurrent = m_lCurrent;

*ppenum = penum;

return NOERROR;

error:

if (penum)

penum->Release();

return hr;

}


Implementing the _NewEnum Property

The _NewEnum property identifies an object as supporting iteration through the IEnumVARIANT interface. The _NewEnum property has the following requirements:

•	Must be named _NewEnum and must not be localized.

•	Must return a pointer to the enumerator object's IUnknown interface.

•	Must have DISPID = DISPID_NEWENUM (-4)

The Lines example contains two collections, Lines and Points, and implements a _NewEnum property for each.  Both are restricted properties, available to OLE Automation controllers, but invisible to users of scripting or macro languages supported by OLE Automation controllers. The property returns an enumerator (IEnumVariant) for the items in the collection.

The following code implements the _NewEnum property for the Lines collection (LINES.CPP):

STDMETHODIMP

CLines::get__NewEnum(IUnknown FAR* FAR* ppunkEnum)

{

CEnumVariant FAR* penum = NULL;;

HRESULT hr;

*ppunkEnum = NULL;

// Create a new enumerator for items currently in the collection and

// QueryInterface for IUnknown.

hr = CEnumVariant::Create(m_psa, m_cElements, &penum);

if (FAILED(hr))

{hr = RaiseException(IDS_OutOfMemory); goto error;}

hr = penum->QueryInterface(IID_IUnknown, (VOID FAR* FAR*)ppunkEnum);

if (FAILED(hr))

{hr = RaiseException(IDS_Unexpected); goto error;}

return NOERROR;

error:

if (penum)

delete penum;

return hr;

}


Handling Events

In addition to supporting properties and methods, OLE Automation objects can be a source of events. In OLE Automation, an event is a method that is called by an OLE Automation object, rather than implemented by the object. For example, an object might include an event method named Button that retrieves clicks of the mouse button. Instead of being implemented by the object, the Button method returns an object that is a source of events.

In OLE Automation, you use the source attribute to identify a member that is a source of events. See the reference page for the source attribute in Chapter 7 for more information.

Details of the OLE Automation event interfaces are provided in the CDK Programmer's Guide.


Returning an Error

OLE Automation objects typically return rich contextual error information, including an error number, a description of the error, and the path of a Help file that supplies further documentation. Objects that do not need to return detailed error information can simply return an HRESULT that indicates the nature of the error.


Passing Exceptions through IDispatch

When an error occurs, objects invoked through IDispatch can return DISP_E_EXCEPTION and pass the details in the pexcepinfo parameter (an EXCEPINFO structure) to IDispatch::Invoke. The EXCEPINFO structure is defined in Chapter 5, "Dispatch Interfaces."

The Lines sample defines an exception handler that fills the EXCEPINFO structure and signals IDispatch to return DISP_E_EXCEPTION (APP.CPP):

STDMETHODIMP

CApplication::RaiseException(int nID)

{

extern SCODE g_scodes[];

char szError[STR_LEN];

ICreateErrorInfo *pcerrinfo;

IErrorInfo *perrinfo;

HRESULT hr;

_fmemset(&m_excepinfo, 0, sizeof(EXCEPINFO));

m_excepinfo.wCode = nID;

if (LoadString(m_hinst, nID, szError, sizeof(szError)))

m_excepinfo.bstrDescription = SysAllocString(szError);

m_excepinfo.bstrSource = SysAllocString(m_bstrName);

m_bRaiseException = TRUE;

// Set ErrInfo object so that vtable binding containers can get

// rich error information.

hr = CreateErrorInfo(&pcerrinfo);

if (SUCCEEDED(hr))

{

pcerrinfo->SetGUID(IID_IApplication);

if (m_excepinfo.bstrSource)

pcerrinfo->SetSource(m_excepinfo.bstrSource);

if (m_excepinfo.bstrDescription)

pcerrinfo->SetDescription(m_excepinfo.bstrDescription);

hr = pcerrinfo->QueryInterface(IID_IErrorInfo,

(LPVOID FAR*) &perrinfo);

if (SUCCEEDED(hr))

{

SetErrorInfo(0, perrinfo);

perrinfo->Release();

}

pcerrinfo->Release();

}

return ResultFromScode(g_scodes[nID-1001]);

}

To raise an exception, properties and methods of the CApplication object call RaiseException, passing an integer error ID This routine fills the global EXCEPINFO structure, m_b_excepinfo, with information about the error. It also sets the global flag m_b_RaiseException, which signals IDispatch::Invoke to return DISP_E_EXCEPTION.


Passing Exceptions through VTBLs

The Lines example also provides rich error information for members invoked through VTBLs. Because VTBL-bound calls bypass the IDispatch interface, they cannot return exceptions through IDispatch. Instead, they must use OLE Automation's error handling interfaces. The RaiseException function shown in the example calls CreateErrorInfo to create an error object, then fills the object's data fields with information about the error. When all the information has been successfully recorded, it calls SetErrorInfo to associate the error object with the current thread of execution.

OLE Automation objects similar to the CApplication object, which use the error interfaces, must implement the ISupportErrorInfo interface as well. This interface identifies the object as supporting the error interfaces, and ensures that error information can be propagated correctly up the call chain. The following example shows how Lines implements this interface (ERRINFO.CPP):

STDMETHODIMP

CSupportErrorInfo::CSupportErrorInfo(IUnknown FAR* punkObject,

REFIID riid)

{

m_punkObject = punkObject;

m_iid = riid;

}

CSupportErrorInfo::QueryInterface(REFIID iid, void FAR* FAR* ppv)

{

return m_punkObject->QueryInterface(iid, ppv);

}

STDMETHODIMP_(ULONG)

CSupportErrorInfo::AddRef(void)

{

return m_punkObject->AddRef();

}

STDMETHODIMP_(ULONG)

CSupportErrorInfo::Release(void)

{

return m_punkObject->Release();

}

STDMETHODIMP

CSupportErrorInfo::InterfaceSupportsErrorInfo(REFIID riid)

{

return (riid == m_iid) ? NOERROR : ResultFromScode(S_FALSE);

}

ISupportErrorInfo has the QueryInterface, AddRef, and Release methods inherited from IUnknown, along with the InterfaceSupportsErrorInfo method. OLE Automation controllers call InterfaceSupportsErrorInfo to check whether the OLE Automation object supports the IErrorInfo interface, so that they can access the error object.


Releasing OLE

To release OLE on exit

1.	Revoke the active object by calling RevokeActiveObject.

2.	Revoke the classes of your exposed objects by calling CoRevokeClassObject.

3.	Uninitialize OLE by calling OleUninitialize.

The following code revokes an active Lines object, revokes the Lines class, then uninitializes OLE (MAIN.CPP):

void Uninitialize(DWORD dwRegisterCF, DWORD dwRegisterActiveObject)

{

if (dwRegisterCF != 0)

CoRevokeClassObject(dwRegisterCF);

if (dwRegisterActiveObject != 0)

RevokeActiveObject(dwRegisterActiveObject, NULL);

OleUninitialize();

}


Creating a Type Library

Type information is the OLE Automation standard for describing the objects, properties, and methods that your OLE Automation server exposes. Browsers and compilers use the type information to display and access the exposed objects.

Most OLE Automation servers create type libraries. Type libraries contain type information, Help filenames and contexts, and function-specific documentation strings, and enable access at both compile time and run time. Type libraries are described in Object Description Language (ODL) and are compiled by MkTypLib, as the following figure illustrates:

OLE Automation also supports the creation of alternative tools that compile and access type information. Chapter 9, "Type Building Interfaces," describes interfaces for creating these tools.

A type library stores complete type information for all of an application's exposed objects. It may be included as a resource in a DLL or remain as a stand-alone file (.TLB).

To create a type library

1.	Write an object description script (.ODL file) for the objects you expose.

2.	Build the type library (.TLB) and class description header file (.H) from the script using MkTypLib.


Writing an Object Description Script

An object description script is essentially an annotated header file, written in Object Description Language (ODL). The following example shows a portion of LINES.ODL, the object description script for the Lines sample.

[

uuid(3C591B20-1F13-101B-B826-00DD01103DE1),	// LIBID_Lines

helpstring("Lines 1.0 Type Library"),

lcid(0x0409),

version(1.0)

]

library Lines

{

importlib("stdole.tlb");

#define DISPID_NEWENUM -4

.

.

.

The preceding entry describes the type library (LINES.TLB) created by the sample. The items in square brackets are attributes, which provide additional information about the library. In the example, the attributes give the library's universally unique identifier (UUID), a Help string, a locale identifier, and a version number.

The importlib directive is similar to the C or C++ #include directive. It allows access to the type descriptions in STDOLE.TLB from the Lines library. However, it doesn't copy those types into LINES.TLB. Therefore, to use LINES.TLB, both LINES.TLB and STDOLE.TLB must be available.

By default, ODL files are preprocessed with the C preprocessor, so the #include and #define directives may be used.

The ODL script continues with information on the objects in the type library:

[

uuid(3C591B25-1F13-101B-B826-00DD01103DE1),	// IID_IPoint

helpstring("Point object."),

oleautomation,

dual

]

interface IPoint : IDispatch

{

[propget, helpstring("Returns and sets x coordinate.")]

HRESULT x( [out, retval] int* retval);

[propput, helpstring("Returns and sets x coordinate.")]

HRESULT x([in] int Value);

[propget, helpstring("Returns and sets y coordinate.")]

HRESULT y( [out, retval] int* retval);

[propput, helpstring("Returns and sets y coordinate.")]

HRESULT y([in] int Value);

}

// .

// . Additional definitions omitted

// .

}

This entry describes the IPoint interface. The interface has the attributes oleautomation and dual, indicating that the types of all its properties and methods are compatible with OLE Automation, and that it supports binding through both IDispatch and VTBLs. IPoint has two pairs of property accessor functions, which set and return the X and Y properties.

The Value parameter of both the X and Y properties has the in attribute. These parameters supply a value and are read-only. Conversely, the retval parameter of each property has the out and retval attributes, indicating that it returns the value of the property.

Because IPoint supports VTBL binding and rich error information, its properties return HRESULTs and pass their function return values through retval parameters. For more information, see Chapter 7, "MkTypLib and Object Description Language."

[

uuid(3C591B21-1F13-101B-B826-00DD01103DE1),	// CLSID_Lines

helpstring("Lines Class"),

appobject

]

coclass Lines

{

[default] interface IApplication;

interface IDispatch;

}

}

The file concludes with the description of the Lines Application object, as specified by the appobject attribute. The default attribute applies to the IApplication interface, indicating that this interface will be returned by default.


Building the Type Library

The MkTypLib tool builds type libraries. MkTypLib is described in detail in Chapter 7, "MkTypLib and Object Description Language."

To create a type library from an object description script

From Windows, run the MkTypLib tool on the script. For example:

MKTYPLIB /TLB output.tlb /H output.h inscript.odl

The example creates a type library named OUTPUT.TLB and a header file named OUTPUT.H, based on the object description script INSCRIPT.ODL.

Note that MkTypLib requires Windows. If you run it from NMAKE, you must use the WX server support provided with OLE. For example, start WXSRVR in Windows and use the following command line in your NMAKE script:

MKTYPLIB /o odlscrip.err /TLB output.tlb /h output.h inscript.odl

Alternatively, you can add MkTypLib to the Tools menu in the Microsoft Visual C++ programming environment. If you do this, be sure to check the "Ask for Arguments" check box, so the programming environment will prompt you for the options and input file before running the tool.

After creating the type library (.TLB), you can include it in the resource step of building your application or leave it as a stand-alone file. In either case, be sure to specify the filename and path of the library in the application's registration file (.REG), so that OLE Automation can find the type library when necessary. See the following section for information on registering the type library.

To build an application that uses a type library

1.	Include the header file output by MkTypLib in your project.

2.	Compile the project.

3.	Optionally, use the Resource Compiler to bind the type library with your compiled project. You can bind the type library with DLLs or with .EXE files. For example, to bind a type library named OUTPUT.TLB with a DLL, use the following statement in the .RC file for the DLL:

1 typelib output.tlb

A DLL that contains a typelib resource usually has the .OLB (object library) extension.

The following figure illustrates the process.


Creating a Registration File

Before an application can use OLE and OLE Automation, the OLE objects must be registered with the user's system registration database. Registration makes the following possible:

•	OLE Automation controllers can create instances of the OLE Automation objects through CoCreateInstance.

•	OLE Automation tools can find the type libraries that are installed on the user's computer.

•	OLE can find remoting code for the interfaces.

OLE provides sample registration files to perform this task for the OLE objects and the sample applications.

To create a registration file

1.	Copy LINES.REG.

2.	Rename and edit the file, adding entries for your application.

The registration file provides information about the application, Application object, classes of objects, type libraries, and interfaces. Entries for objects and interfaces start with the constant HKEY_CLASSES_ROOT, which represents the root key of the entire registration database. Entries for type libraries start with HKEY_TYPELIB_ROOT. After the constant, each entry supplies specific information about an object, type library, or interface.

The following sections give a brief overview of the syntax used in registering OLE Automation objects. For detailed information, refer to the OLE 2 Programmer's Reference, Volume 1.

Note that you can use the DLLRegisterServer function to register all the objects implemented by a DLL. This function registers the class IDs for each object, the ProgIDs for each application, and the type library. For details, refer to the description of DLLRegisterServer in the CDK Programmer's Guide.


Registering the Application

Registration maps the programmatic ID (ProgID) of the application to a unique class ID (CLSID), so that you can create instances of the application by name, rather than by CLSID. For example, registering Microsoft Excel associates a CLSID with the ProgID "Excel.Application." In Visual Basic, you use the ProgId to create an instance of the application, as follows:

SET xl = CreateObject("Excel.Application")

By passing the ProgID to CLSIDFromProgID, you can get the corresponding CLSID for use in CoCreateInstance. Only applications that will be used in this way need to be registered.

The registration file uses the following syntax for the application:

\ AppName.ObjectName[.VersionNumber] = human_readable_string
\ AppName.ObjectName\CLSID = {UUID}

AppName

The name of the application.

ObjectName

The name of the object to be registered, in this case, Application.

VersionNumber

The optional version number of the object.

human_readable_string

A string that describes the application, as you want it to appear to users. The recommended maximum length is 40 characters.

UUID

The universally unique ID for the application class (CLSID). To generate a universally unique ID for your class, run the utility GUIDGEN.EXE provided in the \OLE2\BIN directory.

Example

REGEDIT

; Registration information for OLE Automation Hello 2.0 Application

; Version independent registration. Points to Version 2.0

HKEY_CLASSES_ROOT\Hello.Application = OLE Automation Hello Application

HKEY_CLASSES_ROOT\Hello.Application\Clsid = {F37C8061-4AD5-101B-B826-00DD01103DE1}

; Version 2.0 registration

HKEY_CLASSES_ROOT\Hello.Application.2 = OLE Automation Hello 2.0 Application

HKEY_CLASSES_ROOT\Hello.Application.2\Clsid = {F37C8061-4AD5-101B-B826-00DD01103DE1}


Registering Classes

Objects that can be created with CoCreateInstance must also be registered with the system. For these objects, registration maps a CLSID to the OLE Automation server file (.DLL or .EXE) in which the object resides. The CLSID also maps an OLE Automation object back to its application and ProgID. The following figure shows how registration connects ProgIDs, CLSIDs, and OLE Automation servers:

The registration file uses the following syntax for each class of each object your application exposes:

\CLSID\{UUID} = human_readable_string
\CLSID\{UUID}\ProgID = AppName.ObjectName.VersionNumber
\CLSID\{UUID}\VersionIndependentProgID = AppName.ObjectName
\CLSID\{UUID}\LocalServer[32] = filepath[/Automation]
\CLSID\{UUID}\InProcServer[32] = filepath[/Automation]

human_readable_string

A string that describes the object, as you want it to appear to users. The recommended maximum length is 40 characters.

AppName

The name of the application, as specified previously in the application registration string.

ObjectName

The name of the object to be registered.

VersionNumber

The version number of the object.

UUID

The universally unique ID for the application class (CLSID). To generate a universally unique ID for your class, run the utility GUIDGEN.EXE provided in the \OLE2\BIN directory.

filepath

The full path and name of the file that contains the object. The optional /Automation switch tells the application it was launched for OLE Automation purposes. The switch should be specified for the Application object's class. For more information on /Automation, see the section "Initializing the Active Object" earlier in this chapter.

The programmatic IDs (ProgID and VersionIndependentProgID) are used by other programmers to gain access to the objects you expose. These IDs should follow consistent naming guidelines across all your applications. They may contain up to 39 characters, must not contain any punctuation (except for the period), and must not start with a digit.

Version-independent names consist of an AppName.ObjectName, without a version number; for example, Word.Document or Excel.Chart.

Version-dependent names consist of an AppName.ObjectName.VersionNumber, such as Excel.Application.5.

LocalServer indicates that the OLE Automation server is an EXE file and runs in a separate process from the OLE Automation controller. InProcServer indicates that the server is a DLL and runs in the same process as the OLE Automation controller. The optional 32 specifies a server intended for use on 32-bit Windows systems.

The filepath you register should give the full path and name, so that applications need not rely on the MS-DOS PATH variable to find the object.

Example

HKEY_CLASSES_ROOT\CLSID\{F37C8061-4AD5-101B-B826-00DD01103DE1} = Hello 2.0 Application

HKEY_CLASSES_ROOT\CLSID\{F37C8061-4AD5-101B-B826-00DD01103DE1}\ProgID = Hello.Application.2

HKEY_CLASSES_ROOT\CLSID\{F37C8061-4AD5-101B-B826-00DD01103DE1}\VersionIndependentProgID = Hello.Application

HKEY_CLASSES_ROOT\CLSID\{F37C8061-4AD5-101B-B826-00DD01103DE1}\LocalServer = hello.exe /Automation


Registering Type Library Information

Tools and applications that expose type information must register the information so that it is available to type browsers and programming tools. You can generate the correct registration entries for a type library by calling the RegisterTypeLib function on the type library. You can then use REGEDIT, supplied with the Windows SDK, to write the registration entries to a text file from your system registration database.

The following information is registered for a type library:

\TypeLib\{libUUID}
\TypeLib\{libUUID}\major.minor = human_readable_string
\TypeLib\{libUUID}\major.minor\HELPDIR = [helpfile_path]
\TypeLib\{libUUID}\major.minor\Flags = typelib_flags
\TypeLib\{libUUID}\major.minor\lcid\platform = localized_typelib_filename

libUUID

The universally unique ID of the type library.

major.minor

The two-part version number of the type library. If only the minor version number increases, all the features of the previous type library are supported in a compatible way. If the major version number changes, code that compiled against the type library must be recompiled. The version number of the type library may differ from the version number of the application.

human_readable_string

A string that describes the type library, as you want it to appear to users. The recommended maximum length is 40 characters.

helpfile_path

The directory where the Help file for the types in the type library is located. Note that if the application supports type libraries for multiple languages, the libraries may refer to different filenames in the Help file directory.

typelib_flags

The hexadecimal representation of the type library flags for this type library. These are the values of the LIBFLAGS enumeration, and are the same flags specified in the uLibFlags parameter to ICreateTypeLib::SetLibFlags. They can't have leading zeros or the 0x prefix.

lcid

The hexadecimal string representation of the locale ID (LCID). It is one to four hexadecimal digits with no 0x prefix and no leading zeros. The LCID may have a neutral sublanguage.

platform

The target operating system platform: 16-bit Windows, 32-bit Windows, or Mac.

localized_typelib_filename

The full name of the localized type library.

Using the LCID specifier, an application can explicitly register the filenames of type libraries for different languages. This allows the application to find the desired language without having to open all type libraries with a given name. To find the type library for Australian English (309), the application would first look for it and, if that fails, look for an entry for Standard English (9). If there is no entry for Standard English, the application looks for the LANG_SYSTEM_DEFAULT (0). For more information on locale support, refer to your operating system documentation for the NLS interface; for 16-bit systems, see Appendix A, "National Language Support Functions."

Example

; Type library registration information

HKEY_CLASSES_ROOT\TypeLib\{F37C8060-4AD5-101B-B826-00DD01103DE1}

HKEY_CLASSES_ROOT\TypeLib\{F37C8060-4AD5-101B-B826-00DD01103DE1}\2.0 = OLE Automation Hello 2.0 Type Library

HKEY_CLASSES_ROOT\TypeLib\{F37C8060-4AD5-101B-B826-00DD01103DE1}\2.0\HELPDIR =

;US english

HKEY_CLASSES_ROOT\TypeLib\{F37C8060-4AD5-101B-B826-00DD01103DE1}\2.0\409\win16 = hello.tlb


Registering Interfaces

Applications that add interfaces need to register the interfaces, so that OLE can find the appropriate remoting code for interprocess communication. By default, OLE Automation registers dispinterfaces that appear in the ODL file. It also registers remote OLE Automation-compatible interfaces that are not registered elsewhere under the ProxyStubClsid for PSAutomation.

The information registered for an interface is as follows:

\Interface\{IID} = InterfaceName
\Interface\{IID}\Typelib = LIBID
\Interface\{IID}\ProxyStubClsid[32] = CLSID

IID

The universally unique ID of the interface.

InterfaceName

The name of the interface.

LIBID

The UUID associated with the type library in which the interface is described.

CLSID

The UUID associated with the proxy/stub implementation of the interface, used internally by OLE for interprocess communication. OLE Automation objects use the proxy/stub implementation of IDispatch.

Example

The following lines from HELLO.REG register the interface for VTBL binding. The ProxyStubClsid in the example refers to the proxy/stub implementation of IDispatch.

HKEY_CLASSES_ROOT\Interface\{F37C8062-4AD5-101B-B826-00DD01103DE1} = IHello

HKEY_CLASSES_ROOT\Interface\{F37C8060-4AD5-101B-B826-00DD01103DE1}\TypeLib = {F37C8060-4AD5-101B-B826-00DD01103DE1}

HKEY_CLASSES_ROOT\Interface\{F37C8060-4AD5-101B-B826-00DD01103DE1}\ProxyStubClsid = {00020424-0000-0000-C000-000000000046}


Registration File Example

Lines uses the following entries to register its Application object (Lines.Application) and its type library with the system (LINES.REG):

REGEDIT

; Registration information for the Lines Automation Object application

; Version independent registration

HKEY_CLASSES_ROOT\Lines.Application = Lines

HKEY_CLASSES_ROOT\Lines.Application\Clsid = {3C591B21-1F13-101B-B826-00DD01103DE1}

; Version 1.0 registration

HKEY_CLASSES_ROOT\Lines.Application.1 = Lines 1.0

HKEY_CLASSES_ROOT\Lines.Application.1\Clsid = {3C591B21-1F13-101B-B826-00DD01103DE1}

HKEY_CLASSES_ROOT\CLSID\{3C591B21-1F13-101B-B826-00DD01103DE1} = Lines 1.0

HKEY_CLASSES_ROOT\CLSID\{3C591B21-1F13-101B-B826-00DD01103DE1}\ProgID = Lines.Application.1

HKEY_CLASSES_ROOT\CLSID\{3C591B21-1F13-101B-B826-00DD01103DE1}\VersionIndependentProgID = Lines.Application

HKEY_CLASSES_ROOT\CLSID\{3C591B21-1F13-101B-B826-00DD01103DE1}\LocalServer = lines.exe /Automation

; Type library registration information

HKEY_CLASSES_ROOT\TypeLib\{3C591B20-1F13-101B-B826-00DD01103DE1}

HKEY_CLASSES_ROOT\TypeLib\{3C591B20-1F13-101B-B826-00DD01103DE1}\1.0 = Lines 1.0 Type Library

HKEY_CLASSES_ROOT\TypeLib\{3C591B20-1F13-101B-B826-00DD01103DE1}\1.0\HELPDIR =

;US english

HKEY_CLASSES_ROOT\TypeLib\{3C591B20-1F13-101B-B826-00DD01103DE1}\1.0\409\win16 = lines.tlb

; Interface registration. All interfaces that support vtable binding must be

; registered as follows. RegisterTypeLib & LoadTypeLib will do this automatically.

; LIBID_Lines = {3C591B20-1F13-101B-B826-00DD01103DE1}

; IID_IPoint = {3C591B25-1F13-101B-B826-00DD01103DE1}

HKEY_CLASSES_ROOT\Interface\{3C591B25-1F13-101B-B826-00DD01103DE1} = IPoint

HKEY_CLASSES_ROOT\Interface\{3C591B25-1F13-101B-B826-00DD01103DE1}\TypeLib = {3C591B20-1F13-101B-B826-00DD01103DE1}

HKEY_CLASSES_ROOT\Interface\{3C591B25-1F13-101B-B826-00DD01103DE1}\ProxyStubClsid = {00020424-0000-0000-C000-000000000046}

; IID_ILine = {3C591B24-1F13-101B-B826-00DD01103DE1}

HKEY_CLASSES_ROOT\Interface\{3C591B24-1F13-101B-B826-00DD01103DE1} = ILine

HKEY_CLASSES_ROOT\Interface\{3C591B24-1F13-101B-B826-00DD01103DE1}\TypeLib = {3C591B20-1F13-101B-B826-00DD01103DE1}

HKEY_CLASSES_ROOT\Interface\{3C591B24-1F13-101B-B826-00DD01103DE1}\ProxyStubClsid = {00020424-0000-0000-C000-000000000046}

; IID_ILines = {3C591B26-1F13-101B-B826-00DD01103DE1}

HKEY_CLASSES_ROOT\Interface\{3C591B26-1F13-101B-B826-00DD01103DE1} = ILines

HKEY_CLASSES_ROOT\Interface\{3C591B26-1F13-101B-B826-00DD01103DE1}\TypeLib = {3C591B20-1F13-101B-B826-00DD01103DE1}

HKEY_CLASSES_ROOT\Interface\{3C591B26-1F13-101B-B826-00DD01103DE1}\ProxyStubClsid = {00020424-0000-0000-C000-000000000046}

; IID_IPoints = {3C591B27-1F13-101B-B826-00DD01103DE1}

HKEY_CLASSES_ROOT\Interface\{3C591B27-1F13-101B-B826-00DD01103DE1} = IPoints

HKEY_CLASSES_ROOT\Interface\{3C591B27-1F13-101B-B826-00DD01103DE1}\TypeLib = {3C591B20-1F13-101B-B826-00DD01103DE1}

HKEY_CLASSES_ROOT\Interface\{3C591B27-1F13-101B-B826-00DD01103DE1}\ProxyStubClsid = {00020424-0000-0000-C000-000000000046}

; IID_IPane = {3C591B23-1F13-101B-B826-00DD01103DE1}

HKEY_CLASSES_ROOT\Interface\{3C591B23-1F13-101B-B826-00DD01103DE1} = IPane

HKEY_CLASSES_ROOT\Interface\{3C591B23-1F13-101B-B826-00DD01103DE1}\TypeLib = {3C591B20-1F13-101B-B826-00DD01103DE1}

HKEY_CLASSES_ROOT\Interface\{3C591B23-1F13-101B-B826-00DD01103DE1}\ProxyStubClsid = {00020424-0000-0000-C000-000000000046}

; IID_IApplication = {3C591B22-1F13-101B-B826-00DD01103DE1}

HKEY_CLASSES_ROOT\Interface\{3C591B22-1F13-101B-B826-00DD01103DE1} = IApplication

HKEY_CLASSES_ROOT\Interface\{3C591B22-1F13-101B-B826-00DD01103DE1}\TypeLib = {3C591B20-1F13-101B-B826-00DD01103DE1}

HKEY_CLASSES_ROOT\Interface\{3C591B22-1F13-101B-B826-00DD01103DE1}\ProxyStubClsid = {00020424-0000-0000-C000-000000000046}


Supporting Multiple National Languages

Applications sometimes need to expose objects with names that differ across localized versions of the product. The names pose a problem for programming languages that need to access these objects, because late binding will be sensitive to the locale of the application. The IDispatch interface provides a range of solutions that vary in cost of implementation and quality of language support. All methods of the IDispatch interface that are potentially sensitive to language are passed a locale ID (LCID), which identifies the local language context.

The following are some of the approaches a class implementation may take:

•	Accept any LCID and use the same member names in all locales. This is acceptable if the exposed interface will typically be accessed only by very advanced users. For example, the member names for OLE 2 interfaces will never be localized.

•	Accept all LCIDs supported by all versions of the product. In this case, the implementation of GetIDsOfNames would need to interpret the passed array of names based on the given LCID. This is the most acceptable solution because it allows users to write code in their natural language and run the code on any localized version of the application.

•	Simply return an error (DISP_E_UNKNOWNLCID) from GetIDsOfNames if the caller's LCID doesn't match the localized version of the class. This would prevent your customers from being able to write late-bound code that runs on machines with different localized implementations of the class.

•	Recognize the particular version's localized names, as well as one language that is recognized in all versions. For example, a French version might accept French and English names, where English is the language supported in all versions. Users who want to write code that runs in all countries would have to use English.

However, to provide general language support, the application should check the LCID before interpreting member names. Because Invoke is passed an LCID, methods can properly interpret parameters whose meaning varies by locale. The following sections provide examples and guidelines of how to create multilingual applications.


Implementing IDispatch for Multilingual Applications

When creating applications that will support multiple languages, you need to create separate type libraries for each supported language and write versions of the IDispatch member functions that include dependencies for each language. In the following example, the Hello example code is modified to define locale IDs for both US English and German.

Write a separate type library for each supported language.

The type libraries use the same DISPIDs and GUIDs but localize names and Help strings based on the language. The following registration file example includes entries for US English and German.

; Type library registration information

HKEY_CLASSES_ROOT\TypeLib\{F37C8060-4AD5-101B-B826-00DD01103DE1}

HKEY_CLASSES_ROOT\TypeLib\{F37C8060-4AD5-101B-B826-00DD01103DE1}\2.0 =

Hello 2.0 Type Library

HKEY_CLASSES_ROOT\TypeLib\{F37C8060-4AD5-101B-B826-00DD01103DE1}\2.0\HELPDIR

=

;US english

HKEY_CLASSES_ROOT\TypeLib\{F37C8060-4AD5-101B-B826-00DD01103DE1}\2.0\409\win16 = helloeng.tlb

;German

HKEY_CLASSES_ROOT\TypeLib\{F37C8060-4AD5-101B-B826-00DD01103DE1}\2.0\407\win16 = helloger.tlb

Define the locale IDs for the supported languages.

Refer to the next section to obtain the language IDs for your supported languages.

// Locale IDs for the languages that are supported

#define LCID_ENGLISH MAKELCID(MAKELANGID(0x09, 0x01))

#define LCID_GERMAN  MAKELCID(MAKELANGID(0x07, 0x01))

Using the Hello code example, you define member variables that will be used to hold English and German type information.

class FAR CHello : public IHello

{

public:

:

private:

LPTYPEINFO m_ptinfoEnglish;   // English type information of Hello

application interface.

LPTYPEINFO m_ptinfoGerman;    // German type information of Hello

application interface.

:

};

Load type information for each supported language

The following example uses the LoadTypeInfo function to load locale-specific type library information when the Hello object is created.

LoadTypeInfo(&phello->m_ptinfoEnglish, IID_IHello, LCID_ENGLISH);

LoadTypeInfo(&phello->m_ptinfoGerman, IID_IHello, LCID_GERMAN);

/* LoadTypeInfo - Gets type information of an object's interface from

 * the type library.

 *

 * Parameters:

 *  ppunkStdDispatch	Returns type information.

 *  clsid	Interface id of object in type library.

 *  lcid	Locale ID of typeinfo to be loaded.

 *

 * Return Value:

 *  HRESULT

 *

 */

HRESULT LoadTypeInfo(ITypeInfo FAR* FAR* pptinfo, REFCLSID clsid,
LCID lcid)

{

HRESULT hr;

LPTYPELIB ptlib = NULL;

LPTYPEINFO ptinfo = NULL;

*pptinfo = NULL;

// Load Type Library.

hr = LoadRegTypeLib(LIBID_Hello, 2, 0, lcid, &ptlib);

if (FAILED(hr))

return hr;

// Get type information for interface of the object.

hr = ptlib->GetTypeInfoOfGuid(clsid, &ptinfo);

if (FAILED(hr))

{

ptlib->Release();

return hr;

}

ptlib->Release();

*pptinfo = ptinfo;

return NOERROR;

}

Implement the IDispatch member functions

The following code implements language-sensitive versions of GetTypeInfoCount, GetIDsOfNames, and Invoke. Note that Invoke doesn't check the locale ID, but merely passes it to DispInvoke.

STDMETHODIMP

CHello::GetTypeInfoCount(UINT FAR* pctinfo)

{

*pctinfo = 1;

return NOERROR;

}

STDMETHODIMP

CHello::GetTypeInfo(

UINT itinfo,

LCID lcid,

ITypeInfo FAR* FAR* pptinfo)

{

LPTYPEINFO ptinfo;

*pptinfo = NULL;

if(itinfo != 0)

return ResultFromScode(DISP_E_BADINDEX);

if(lcid == LOCALE_SYSTEM_DEFAULT || lcid == 0)

lcid = GettSystemDefaultLCID();

if(lcid == LOCALE_USER_DEFAULT)

lcid = GetUserDefaultLCID();

switch(lcid)

{

case LCID_GERMAN:

ptinfo = m_ptinfoGerman;

break;

case LCID_ENGLISH:

ptinfo = m_ptinfoEnglish;

break;

default:

return ResultFromScode(DISP_E_UNKNOWNLCID);

}

ptinfo->AddRef();

*pptinfo = ptinfo;

return NOERROR;

}

STDMETHODIMP

CHello::GetIDsOfNames(

REFIID riid,

OLECHAR FAR* FAR* rgszNames,

UINT cNames,

LCID lcid,

DISPID FAR* rgdispid)

{

LPTYPEINFO ptinfo;

if(lcid == LOCALE_SYSTEM_DEFAULT || lcid == 0)

lcid = GetSystemDeraultLCID();

if(lcid == LOCALE_USER_DEFAULT)

lcid = GetUserDefaultLCID();

switch(lcid)

{

case LCID_GERMAN:

ptinfo = m_ptinfoGerman;

break;

case LCID_ENGLISH:

ptinfo = m_ptinfoEnglish;

break;

default:

return ResultFromScode(DISP_E_UNKNOWNLCID);

}

return DispGetIDsOfNames(ptinfo, rgszNames, cNames, rgdispid);

}

STDMETHODIMP

CHello::Invoke(

DISPID dispidMember,

REFIID riid,

LCID lcid,

WORD wFlags,

DISPPARAMS FAR* pdispparams,

VARIANT FAR* pvarResult,

EXCEPINFO FAR* pexcepinfo,

UINT FAR* puArgErr)

{

HRESULT hr;

m_bRaiseException = FALSE;

hr =  DispInvoke(

this, m_ptinfoEnglish,

dispidMember, wFlags, pdispparams,

pvarResult, pexcepinfo, puArgErr);

if (m_bRaiseException)

{

if (NULL != pexcepinfo)

_fmemcpy(pexcepinfo, &m_excepinfo, sizeof(EXCEPINFO));

return ResultFromScode(DISP_E_EXCEPTION);

}

else return hr;

}


Interpreting Arguments and Strings Based on LCID

Some methods or properties need to interpret arguments based on the LCID. Such methods or properties can require that an LCID be passed as an argument.

The following code example implements a property that takes an LCID. In this example, get_CheckingBalance returns a currency string that contains the amount of money in the checking account. The currency string should be correctly formated depending on the locale that is passed in. ConvertCurrency is a private function that converts the checking balance to the currency of the country described by llcid. The string form of converted currency is placed in m_szBalance. GetCurrencyFormat is a 32-bit Windows function that that formats a currency string for the given locale.

The following represents the .ODLfile:

[

uuid(83219430-CB36-11cd-B774-00DD01103DE1),

helpstring("Bank Account object."),

oleautomation,

dual

]

interface IBankAccount : IDispatch

{

[propget, helpstring("Returns account balance formatted for the 	country described by localeID.")]

HRESULT CheckingBalance([in, lcid] long localeID, [out, retval] 	BSTR* retval);

:

}

The following represents the .H file:

class FAR CBankAccount : public IBankAccount

{

public:

// IUnknown methods

:

// IDispatch methods

:

// IBankAccount methods

STDMETHOD(get_CheckingBalance)(long llcid, BSTR FAR* pbstr);

:

}

The following represents the .CPP file:

STDMETHODIMP

CBankAccount::get_CheckingBalance(long llcid, BSTR FAR* pbstr)

{

TCHAR ach[100];

ConvertCurrency(llcid);

GetCurrencyFormat(llcid, 0, m_szBalance, NULL, ach,
sizeof(ach));

*pbstr = SysAllocString(ach); // Return currency string formated

 // according to locale id.

return NOERROR;

}

The LCID is commonly used to parse strings that contain locale-dependent information. For example, a function that takes a string such as "6/11/59" needs the LCID to determine whether the month is June (6) or November (11). The LCID should not be used for output strings, including error strings; these should always be displayed in the current system language.


Locale, Language, and Sublanguage IDs

The following macro is defined for creating LCIDs (WINNT.H for 32-bit systems; OLENLS.H for 16-bit systems):

/*

 * LCID creation/extraction macros:

 *

 * 	MAKELCID - construct locale ID from language ID and

 * 	country code.

 */

#define MAKELCID(l)	((DWORD)(((WORD)(l)) | (((DWORD)((WORD)(0))) << 16)))

There are two predefined LCID values: LOCALE_SYSTEM_DEFAULT is the system default locale, and LOCALE_USER_DEFAULT is the current user's locale.

Another macro constructs a language ID:

/*

 * Language ID creation/extraction macros:

 *

 * 	MAKELANGID - construct language ID from primary language ID and

 * 	sublanguage ID

*/

#define MAKELANGID(p, s)	((((USHORT)(s)) << 10) | (USHORT)(p))

The following three combinations of primary language ID and sublanguage ID have special meanings:

PRIMARYLANGID	SUBLANGID	Result
LANG_NEUTRAL	SUBLANG_NEUTRAL	Language neutral
LANG_NEUTRAL	SUBLANG_SYS_DEFAULT	System default language
LANG_NEUTRAL	SUBLANG_DEFAULT	User default language
For primary language IDs, the range 0x200 to 0x3ff is user definable. The range 0x000 to 0x1ff is reserved for system use. For sublanguage IDs, the range 0x20 to 0x3f is user definable. The range 0x00 to 0x1f is reserved for system use.


Language tables

The following table lists the primary language IDs supported by OLE Automation. For more information on national language support for 16-bit Windows systems, refer to Appendix A, "National Language Support Functions." On 32-bit Windows systems, see your operating system documentation.

Language	PRIMARYLANGID
Neutral	0x00
Chinese	0x04
Czech	0x05
Danish	0x06
Dutch	0x13
English	0x09
Finnish	0x0b
French	0x0c
German	0x07
Greek	0x08
Hungarian	0x0e
Icelandic	0x0F
Italian	0x10
Japanese	0x11
Korean	0x12
Norwegian	0x14
Polish	0x15
Portuguese	0x16
Russian	0x19
Slovak	0x1b
Spanish	0x0a
Swedish	0x1d
Turkish	0x1F
The following table lists the sublanguage IDs supported by OLE Automation. For more information on national language support for 16-bit systems, refer to Appendix A, "National Language Support Functions." On 32-bit Windows systems, see your operating system documentation.

Sublanguage	SUBLANGID
Neutral	0x00
Default	0x01
System Default	0x02
Chinese (Simplified)	0x02
Chinese (Traditional)	0x01
Czech	0x01
Danish	0x01
Dutch	0x01
Dutch (Belgian)	0x02
English (US)	0x01
English (UK)	0x02
English (Australian)	0x03
English (Canadian)	0x04
English (Irish)	0x06
English (New Zealand)	0x05
Finnish	0x01
French	0x01
French (Belgian)	0x02
French (Canadian)	0x03
French (Swiss)	0x04
German	0x01
German (Swiss)	0x02
German (Austrian)	0x03
Greek	0x01
Hungarian	0x01
Icelandic	0x01
Italian	0x01
Italian (Swiss)	0x02
Japanese	0x01
Korean	0x01
Norwegian (Bokmal)	0x01
Norwegian (Nynorsk)	0x02
Polish	0x01
Portuguese	0x02
Portuguese (Brazilian)	0x01
Russian	0x01
Slovak	0x01
Spanish (Castilian) (1)	0x01
Spanish (Mexican)	0x02
Spanish (Modern) (1)	0x03
Swedish	0x01
Turkish	0x01
1 The only difference between Spanish (Castilian) and Spanish (Modern) is the sort ordering. The LCType values are all the same.


Accessing OLE Automation Objects

To access exposed objects, you can create OLE Automation controllers using Microsoft Visual Basic™, Microsoft Visual C++™, Microsoft Excel, Microsoft Project, and other applications and programming languages that support OLE. This chapter discusses several strategies for accessing exposed objects:

•	Creating scripts with Microsoft Visual Basic

•	Creating your own controllers that manipulate objects

•	Creating type information browsers

Regardless of the strategy you choose, your OLE Automation controller needs to follow these steps:

To initialize and create the object

1.	Initialize OLE.

2.	Create an instance of the exposed object.

To manipulate methods and properties

1.	Get information about the object's methods and properties.

2.	Invoke the methods and properties.

To release OLE when your application or programming tool terminates

1.	Revoke the active object.

2.	Unitialize OLE.


Packaging Scripts Using Visual Basic

Microsoft Visual Basic  provides a complete programming environment for creating Windows applications.

Visual Basic can manipulate the exposed OLE objects of other applications. Internally, it fully supports OLE Automation dual interfaces. For the syntax and semantics of the OLE Automation features, see the Visual Basic Help file, VB.HLP. Appendix C lists how the Visual Basic statements translate into OLE application programming interfaces (APIs).

Note  You don't need Visual Basic in order to use OLE Automation. It is presented here as an example of a programming tool that supports OLE Automation and is convenient for packaging OLE Automation scripts. Optionally, you can use a different OLE Automation controller for your testing.

You can call exposed objects directly from programs written with Visual Basic. This figure shows how this was done for the sample program HELLO.EXE:

To access an exposed object

1.	Start Visual Basic. Initialization and release of OLE is handled automatically by Visual Basic.

2.	Use the Tools/References menu to select the type library of the object.

3.	Add code to declare a variable of the interface type. For example:

Dim HelloObj As IHello

4.	Add code in event procedures to create an instance of the object and to manipulate the object using its properties and methods. For example:

Sub Form_Load ( )

Set HelloObj = New Hello.Hello

End Sub

Sub SetVisible_Click ( )

HelloObj.Visible = True

End Sub

5.	From the Run menu, choose Start and trigger the event by clicking the form.

The following figure shows the interfaces you use when accessing exposed objects through Visual Basic.


Accessing a Remote Object

With Visual Basic, accessing the remote object requires only that the program declare an object variable and assign the return of a New statement to the variable. The following is the syntax for the statements:

Dim ObjectVar As InterfaceName
Set ObjectVar = New CoClassName

The Dim statement declares a variable of an interface type. The New keyword creates an instance of an object. Used together, the two declare and create an instance of an OLE Automation object. For example:

Dim MyLines As ILines

Set MyLines = New Lines.Lines

The Dim statement declares the object variable MyLines of the interface type ILines. The Set statement assigns a new object of the component object class (coclass) Lines to the variable MyLines. When you use the Dim statement to set a variable to an interface type, susbsequent uses of the variable execute faster than with the generic Object syntax.

The New keyword applies only to creating coclasses of interface or dispinterface types. To create other types of objects, you must declare the variable with the Dim statement, and then use the CreateObject function as follows:

Set ObjectVar = CreateObject(ProgID)

CreateObject creates an OLE Automation object, based on the specified ProgID. The ProgID has the form:

"AppName.ObjectName"

The AppName is the name of the application, and the ObjectName identifies the type of object to create. See "Registering the Application" in Chapter 2 for more information on ProgIDs.

The GetObject function can be used to re-establish the reference to the most recently used object that corresponds to the Filename and AppName.ObjectName specification.

Set ObjectVar = GetObject("Filename", ProgID)

For example, if the OLE Automation controller needs an existing instance of an object instead of a new instance, it could use GetObject.

The Hello sample application included in the OLE 2 Software Development Kit (SDK) displays a Hello message in response to a mouse click. You can add a simple form that accesses the Hello application's exposed object from another process.

To add a form

1.	Start Visual Basic.

2.	Choose Open Project from the File menu.

3.	In the dialog box, select VB.MAK from the \OLE2\SAMPLE\HELLO\VB directory.

4.	In the Forms box, choose View Form to see the form, or choose View Code to see the Visual Basic code.

'Module-level declarations

Dim HelloObj As IHello

Sub Form_load ( )

Set HelloObj = New Hello.Hello

End Sub

Sub Invoke_SayHello_Method_Click ( )

HelloObj.SayHello

End Sub

Sub Get_HelloMsg_Property_Click ()

Debug.Print HelloObj.HelloMessage

End Sub

Sub Set_HelloMsg_Property_Click ( )

HelloObj.HelloMessage = "Hello Universe"

End Sub

Sub SetVisible_Click ( )

HelloObj.Visible = True

End Sub

The Form_Load subroutine creates the Hello Application object, and the other subroutines manipulate Hello's Application object through the Visible and HelloMessage properties and the SayHello method.

To program an object in Visual Basic, you need its class name and the names and parameters of its properties and methods. For the Hello sample, you need to know the exact names of the SayHello method and the Visible and HelloMsg properties, and the types of their arguments. This information is published as documentation for many objects, such as those exposed by Microsoft Excel. You can also obtain the information by viewing the object's type library with an object browser like  the one included in Visual Basic. A sample browser, BROWSE, is provided in the OLE 2 SDK.


Creating an Invisible Object

In the preceding section, Visual Basic was used to access and program a form-based interface for Hello. The Hello Application object was started as invisible and was later displayed when its Visible property was set to True. Some objects are not visible, and some objects are never displayed to the user. For example, a word processing application may expose its spelling checker engine as an object. This object supports a method called CheckWord that takes a string as an argument. If the string is spelled correctly, the method returns True; otherwise, the method returns False. If the string is spelled incorrectly, you could pass it to another (hypothetical) method called SuggestWord that returns a suggestion for its correct spelling. The code might look something like this:

Sub CheckSpelling ()

Dim ObjVar As New SpellChecker

Dim MyWord, Result

MyWord = "potatoe"

' Check the spelling.

Result = ObjVar.CheckWord MyWord

' If False, get suggestion.

If Not Result Then

MyWord = ObjVar.SuggestWord MyWord

End If

End Sub

In this example, the spelling checker is never displayed to the user. Its capabilities are exposed through the properties and methods of the spelling checker object.

As shown in the example, you create and reference invisible objects the same way as any other type of object.


Activating an Object from a File

Many OLE Automation applications allow the user to save objects in files. For example, a spreadsheet application that supports Worksheet objects allows the user to save the worksheet in a file. The same application may also support a chart object that the user can save in a file. To activate an object that has been saved in a file, you use the GetObject function.

To activate an object from a file, first declare an object variable, then call the GetObject function using the following syntax:

GetObject (filename[, ProgID])

The filename argument is a string containing the full path and name of the file you want to activate. For example, an application named SPDSHEET.EXE creates an object that was saved in a file called REVENUE.SPD. The following code invokes SPDSHEET.EXE, loads the file REVENUE.SPD, and assigns REVENUE.SPD to an object variable:

Dim Ss As Spreadsheet

Set Ss = GetObject("C:\ACCOUNTS\REVENUE.SPD")

If the filename argument is omitted, GetObject returns the currently active object of the specified ProgID. For example:

Set Ss = GetObject (,"SpdSheet.Application")

If there is no active object of the class SpdSheet.Application, an error occurs.

In addition to activating an entire file, some applications let you activate part of a file. To activate part of a file, add an exclamation point (!) or a backslash (\) to the end of the filename, followed by a string that identifies the part of the file you want to activate. Refer to the object's documentation for information on how to create this string.

For example, if SPDSHEET.EXE is a spreadsheet application that uses R1C1 syntax, the following code could be used to activate a range of cells within REVENUE.SPD:

Set Ss = GetObject("C:\ACCOUNTS\REVENUE.SPD!R1C1:R10C20")

These examples invoke an application and activate an object. Notice that in these examples the application name (SPDSHEET.EXE) is never specified. When you use GetObject to activate an object, the registry files determine the application to invoke and the object to activate based on the filename or ProgID you provide. If you do not include a ProgID, OLE Automation activates the default object of the specified file.

Some OLE Automation servers, however, support more than one class of object. Suppose the spreadsheet file, REVENUE.SPD, supports three different classes of objects: an Application object, a Worksheet object, and a Toolbar object, all of which are part of the same file. To specify which object to activate, you must supply an argument for the optional ProgID parameter. For example:

Set Ss = GetObject("C:\REVENUE.SPD", "SPDSHEET.TOOLBAR")

This statement activates the Spdsheet.Toolbar object in the file REVENUE.SPD.


Accessing Linked and Embedded Objects

Some applications that supply objects support linking and embedding as well as OLE Automation. Using the OLE custom control (MSOLE2.VBX) from the OLE toolkit, you can create and display linked and embedded objects in a Visual Basic application. If the objects also support OLE Automation, you can access their properties and methods using the Object property. The Object property returns the object in the OLE control. This property refers to an OLE object in the same way an object variable created using the New, CreateObject, or GetObject functions refers to the object.

For example, an OLE control named Ole1 contains an object that supports OLE Automation. This object has an Insert method, a Select method, and a Bold property. In this case, you could write the following code to manipulate the OLE control's object:

' Insert text in the object.

Ole1.Object.Insert "Hello, world."

' Select the text.

Ole1.Object.Select

' Format the text as bold.

Ole1.Object.Bold = True


Manipulating Objects

Once you have created a variable that references an OLE object, the object can be manipulated in the same way as any other Visual Basic object. To get and set an object's properties or to perform an object's methods, you use the object.property or object.method syntax. You can include multiple objects, properties, and methods on the same line of code using the following syntax:

ObjVar.Cell(1,1).FontBold = True


Accessing an Object's Properties

To assign a value to a property of an object, put the object variable and property name on the left side of an assignment and the desired property setting on the right side. For example:

Dim ObjVar As IMyInterface

Dim RowPos, ColPos

Set ObjVar = New MyObject

ObjVar.Text = "Hello, world"

ObjVar.Cell(RowPos, ColPos) = "This property accepts two arguments."

' Sets the font for ObjVar.Selection.

ObjVar.Selection.Font = 12

You can also retrieve property values from an object:

Dim X As Object

X = ObjVar.Text

X = ObjVar.Range(12, 32)


Invoking Methods

In addition to getting and setting properties, you can manipulate an object using the methods it supports. Some methods may return a value, as in the following example:

X = ObjVar.Calculate(1,2,3)

Methods that do not return a value behave like subroutines. For example:

' This method requires two arguments.

ObjVar.Move XPos, YPos

If you assign such a method to a variable, an error occurs.


Creating Applications and Tools That Access Objects

OLE Automation provides interfaces for accessing exposed objects from an application or programming tool written in C or C++. The following sections show C++ code that uses the same type of access method as the Visual Basic code described earlier in this chapter. Although the process is more complicated than with Visual Basic, the approach is similar. Note, however, that this section shows the minimum code necessary to access and manipulate a remote object.

You can use the IDispatch interface to access OLE Automation objects, or you can access objects directly through the VTBL. Because VTBL references can be bound at compile time, VTBL access is generally faster than access through IDispatch. Whenever possible, you should use the ITypeInfo interface to get information about an object, including the VTBL addresses of the object's members. Then use this information to access OLE Automation objects through the VTBL.

To create compilers and other programming tools that use information from type libraries, you use the ITypeComp interface. This interface binds to exposed objects at compile time. For details on ITypeComp, see Chapter 8, "Type Description Interfaces."


Accessing Members through VTBLs

For objects that have dual interfaces, the first seven members of the VTBL are the members of IUnknown and IDispatch, and the subsequent members are standard OLE Component Object Model (COM) entries for the interface's member functions. You can call these entries directly from C++.

To access a method or property through the VTBL

1.	Initialize OLE.

2.	Create an instance of the exposed object.

3.	Manipulate the properties and methods of the object.

4.	Uninitialize OLE.

The code excerpt that follows shows how to access a property of the Hello object. Error handling has been omitted for brevity.

HRESULT hr;

CLSID clsid;	//CLSID of Hello object

LPUNKNOWN punk = NULL;	//IUnknown of Hello object

IHello* phello = NULL;	//IHello interface of Hello object

//Initialize OLE.

hr = OleInitialize(NULL);

// Retrieve CLSID from the progID for Hello.

hr = CLSIDFromProgID("Hello.Application", &clsid);

// Create an instance of the Hello object and ask for its

// IDispatch interface.

hr = CoCreateInstance(clsid, NULL, CLSCTX_SERVER,

IID_IUnknown, (void FAR* FAR*)&punk);

hr = punk->QueryInterface(IID_IHello, (void FAR* FAR*)&pHello);

punk->Release();	//Release when no longer needed.

hr = pHello->put_Visible (TRUE);

//Additional code to work with other methods and properties.

// .

// .

// .

OleUninitialize();

The example initializes OLE, then calls the CLSIDFromProgID function to obtain the CLSID for the Hello application. With the CLSID, the example can call CoCreateInstance to create an instance of the Hello Application object. CoCreateInstance returns a pointer to the object's IUnknown interface (punk), and this, in turn, is used to call QueryInterface to get pHello, a pointer to the IID_IHello dual interface. The punk is no longer needed, so the example releases it. The example then sets the value of the Visible property to True.

If the function returns an error HRESULT, you can get detailed, contextual information through the IErrorInfo interface.


Accessing Members through IDispatch

To bind to exposed objects at run time, you use IDispatch.

To create an OLE Automation controller using IDispatch

1.	Initialize OLE.

2.	Create an instance of the object you want to access. The object's OLE Automation server creates the object.

3.	Obtain a reference to the object's IDispatch interface (if it has implemented one).

4.	Manipulate the object through the methods and properties exposed in its IDispatch interface.

5.	Terminate the object by invoking the appropriate method in its IDispatch interface or by releasing all references to the object.

6.	Uninitialize OLE.

The following table shows minimum set of functions necessary to manipulate a remote object.

Function	Purpose	Interface
OleInitialize	Initializes OLE	OLE API function
CoCreateInstance	Creates an instance of the class represented by the specified class ID, and returns a pointer to the object's IUnknown interface.	Component object API function
QueryInterface	Checks whether IDispatch has been implemented for the object.  If so, returns a pointer to the IDispatch implementation.	IUnknown
GetIDsOfNames	Returns DISPIDs for properties  and methods and their parameters.	IDispatch
Invoke	Invokes a method, or sets or gets  a property of the remote object.	IDispatch
Release	Decrements the reference count  for an IUnknown or  IDispatch object.	IUnknown
OleUninitialize	Uninitializes OLE.	OLE API function
The code that follows is extracted from is a generalized Windows-based OLE Automation controller for the Hello sample. The controller relies on helper functions provided in INVHELP.CPP, available in \OLE2\SAMPLE\BROWSE. Error checking is omitted to save space, but would normally be used where an HRESULT is returned.

The two functions that follow initialize OLE, then create an instance of an object and get a pointer to the object's IDispatch interface (INVHELP.CPP):

BOOL InitOle(void)

{

if(OleInitialize(NULL) != 0)

return FALSE;

return TRUE;

}

HRESULT CreateObject(LPSTR pszProgID, IDispatch FAR* FAR* ppdisp)

{

CLSID clsid;	// CLSID of OLE Automation object

HRESULT hr;

LPUNKNOWN punk = NULL;	// IUnknown of OLE Automation object

LPDISPATCH pdisp = NULL;	// IDispatch of OLE Automation object

*ppdisp = NULL;

// Retrieve CLSID from the progID that the user specified.

hr = CLSIDFromProgID(pszProgID, &clsid);

if (FAILED(hr))

goto error;

// Create an instance of the OLE Automation object and ask for the

// IDispatch interface.

hr = CoCreateInstance(clsid, NULL, CLSCTX_SERVER,

IID_IUnknown, (void FAR* FAR*)&punk);

if (FAILED(hr))

goto error;

hr = punk->QueryInterface(IID_IDispatch, (void FAR* FAR*)&pdisp);

if (FAILED(hr))

goto error;

*ppdisp = pdisp;

punk->Release();

return NOERROR;

error:

if (punk) punk->Release();

if (pdisp) pdisp->Release();

return hr;

}

The CreateObject function is passed a ProgID and returns a pointer to the IDispatch implementation of the specified object. CreateObject calls the OLE API CLSIDFromProgID to get the CLSID that corresponds to the requested object, then passes the CLSID to CoCreateInstance to create an instance of the object and get a pointer to the object's IUnknown interface. (The CLSIDFromProgID function is described in the OLE 2 Programmer's Reference, Volume 1). With this pointer, CreateObject calls IUnknown::QueryInterface, specifying IID_IDispatch, to get a pointer to the object's IDispatch interface.

HRESULT FAR

Invoke(LPDISPATCH pdisp,

WORD wFlags,

LPVARIANT pvRet,

EXCEPINFO FAR* pexcepinfo,

UINT FAR* pnArgErr,

LPSTR pszName,

char *pszFmt,

...)

{

va_list argList;

va_start(argList, pszFmt);

DISPID dispid;

HRESULT hr;

VARIANTARG* pvarg = NULL;

if (pdisp == NULL)

return ResultFromScode(E_INVALIDARG);

// Get DISPID of property/method

hr = pdisp->GetIDsOfNames(IID_NULL, &pszName, 1,

LOCALE_SYSTEM_DEFAULT, &dispid);

if(FAILED(hr))

return hr;

DISPPARAMS dispparams;

_fmemset(&dispparams, 0, sizeof dispparams);

// Determine number of arguments.

if (pszFmt != NULL)

CountArgsInFormat(pszFmt, &dispparams.cArgs);

// Property puts have a named argument that represents the value

// being assigned to the property.

DISPID dispidNamed = DISPID_PROPERTYPUT;

if (wFlags & DISPATCH_PROPERTYPUT)

{

if (dispparams.cArgs == 0)

return ResultFromScode(E_INVALIDARG);

dispparams.cNamedArgs = 1;

dispparams.rgdispidNamedArgs = &dispidNamed;

}

if (dispparams.cArgs != 0)

{

// Allocate memory for all VARIANTARG parameters.

pvarg = new VARIANTARG[dispparams.cArgs];

if(pvarg == NULL)

return ResultFromScode(E_OUTOFMEMORY);

dispparams.rgvarg = pvarg;

_fmemset(pvarg, 0, sizeof(VARIANTARG) * dispparams.cArgs);

// Get ready to walk vararg list.

LPSTR psz = pszFmt;

pvarg += dispparams.cArgs - 1;   // Params go in opposite order.

while (psz = GetNextVarType(psz, &pvarg->vt))

{

if (pvarg < dispparams.rgvarg)

{

hr = ResultFromScode(E_INVALIDARG);

goto cleanup;

}

switch (pvarg->vt)

{

case VT_I2:

V_I2(pvarg) = va_arg(argList, short);

break;

case VT_I4:

V_I4(pvarg) = va_arg(argList, long);

break;

// Additional cases omitted to save space...

default:

{

hr = ResultFromScode(E_INVALIDARG);

goto cleanup;

}

break;

}

--pvarg; // Get ready to fill next argument.

} //while

} //if

// Initialize return variant, in case caller forgot. Caller can pass

// NULL if no return value is expected.

if (pvRet)

VariantInit(pvRet);

// Make the call.

hr = pdisp->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, wFlags,

&dispparams, pvRet, pexcepinfo, pnArgErr);

cleanup:

// Clean up any arguments that need it.

if (dispparams.cArgs != 0)

{

VARIANTARG FAR* pvarg = dispparams.rgvarg;

UINT cArgs = dispparams.cArgs;

while (cArgs--)

{

switch (pvarg->vt)

{

case VT_BSTR:

VariantClear(pvarg);

break;

}

++pvarg;

}

}

delete dispparams.rgvarg;

va_end(argList);

return hr;

}

The Invoke function in the example is a general-purpose function that calls IDispatch::Invoke to invoke a property or method of an OLE Automation object. As arguments, it accepts the object's IDispatch implementation, the name of the member to invoke, flags that control the invocation, and a variable list of the member's arguments.

Using the object's IDispatch implementation and the name of the member, it calls GetIDsOfNames to get the DISPID of the requested member. The member's DISPID must be used later, in the call to IDispatch::Invoke.

The invocation flags specify whether a method, property put, or property get function is being invoked. The helper function simply passes these flags directly to IDispatch::Invoke.

The helper function next fills in the DISPPARAMS structure with the parameters of the member. DISPPARAMS structures have the following form:

typedef struct FARSTRUCT tagDISPPARAMS{

VARIANTARG FAR* rgvarg; 	// Array of arguments

DISPID FAR* rgdispidNamedArgs; 	// Dispids of named arguments

UINT cArgs; 	// Number of arguments

UINT cNamedArgs; 	// Number of named arguments

} DISPPARAMS;

The rgvarg field is a pointer to an array of VARIANTARG structures. Each element of the array specifies an argument, whose position in the array corresponds to its position in the parameter list of the method definition. The cArgs field specifies the total number of arguments, and the cNamedArgs field specifies the number of named arguments. For methods and property get functions,  all arguments may be accessed as positional, or they may be accessed as named arguments. Property put functions have a named argument that is the new value for the property. The DISPID of this argument is DISPID_PROPERTYPUT.

To build the rgvarg array, the Invoke helper function retrieves the parameter values and types from its own argument list, and constructs a VARIANTARG structure for each one. (See INVHELP.CPP for a description of the format string that specifies the types of the parameters.) Parameters are put in the array in reverse order, so that the last parameter is in rgvarg[0] and so forth. Although VARIANTARG has the following five fields, only the first and fifth are used:

typedef struct FARSTRUCT tagVARIANT VARIANTARG;

struct FARSTRUCT tagVARIANT{

VARTYPE vt;

unsigned short wReserved1;

unsigned short wReserved2;

unsigned short wReserved3;

union {

short	iVal;	/* VT_I2	*/

.

.	// The rest of this union specifies numerous other types.

.

};

} VARIANTARG;

The first field contains the argument's type, and the fifth contains its value. To pass a long integer, for example, the vt and iVal fields of the VARIANTARG structure would be filled with VT_I4 (long integer) and the actual value of the long integer.

In addition, for property put functions, the first element of the rgdispidNamedArgs array must contain DISPID_PROPERTYPUT.

After filling the DISPPARAMS structure, the Invoke helper function initializes pvRet, a VARIANT in which IDispatch::Invoke returns a value from the method or property. The following is the actual call to IDispatch::Invoke:

hr = pdisp->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, wFlags,

&dispparams, pvRet, pexcepinfo, pnArgErr);

The variable pdisp is a pointer to the object's IDispatch interface. The dispid is the DISPID of the method or property being invoked. The value IID_NULL must be specified for all IDispatch::Invoke calls, and LOCALE_SYSTEM_DEFAULT is a constant denoting the default LCID for this system. The wFlags, dispparams, and pvRet arguments have already been discussed. In the final two arguments, pexcepinfo and pnArgErr, IDispatch::Invoke can return error information. If the invoked member has defined an exception handler, it returns exception information in pexcepinfo. If certain errors occur in the argument vector, pnArgErr points to the errant argument. The function return value hr is an HRESULT that indicates success or various types of failure.

For more information, including how to pass optional arguments, see "IDispatch::Invoke" in Chapter 5, "Dispatch Interfaces."


Creating Type Information Browsers

Type information browsers allow you and your customers to scan type libraries to determine what types of objects are available. The following figure shows the interfaces you use when you create compilers or browsers that access type libraries.

The Browse sample in \OLE2\SAMPLE\BROWSE shows how a browser might access a type library. The Browse sample is a Windows-based type browser that presents a dialog box from which you can select the type information items to display. This function prompts you for the name of the type library, opens the library, and gathers and displays information.


Standards and Guidelines

This chapter describes the standard OLE Automation objects and discusses naming guidelines for creating objects that are unique to applications, especially user-interactive applications that support a multiple-document interface (MDI). However, if your OLE Automation object is not user interactive or supports only a single-document interface (SDI), you should adapt the standards and guidelines as appropriate.

•	Standard objects comprise a standard set of objects defined by OLE. They should be used as appropriate to your application. The objects described in this chapter are oriented toward document-based, user-interactive applications. Other applications (such as noninteractive database servers) may have different requirements.

•	Naming guidelines are recommendations meant to improve consistency across applications.

This chapter covers each of these points in turn. Examples are shown in a hypothetical syntax derived from Visual Basic.

Note  These standards and guidelines are subject to change.


Standard Objects

The following table lists the OLE Automation standard objects. Although none of these objects is required, user-interactive applications with subordinate objects should include an Application object.

Object name	Description
Application	Top-level object; provides a standard way for OLE Automation controllers to retrieve and navigate an application's subordinate objects.
Document	Provides a way to open, print, change, and save an application document.
Documents	Provides a way to iterate over and select open documents in multiple-document interface (MDI) applications.
Font	Describes fonts that are used to display or print text.
The following figure shows how the standard objects fit into the organization of the objects an application provides.

The following sections describe the standard properties and methods for all objects, all collection objects, and each of the standard objects. These sections list only the standard methods and properties for each object, as well as the standard arguments for those properties and methods.

Note  You may define additional application-specific properties and methods for each object. You may also provide additional optional arguments for any of the listed properties or methods; however, the optional arguments should follow the standard arguments in a positional argument list.


All Objects

All objects, including the Application object and collection objects, must provide the following properties:

Property name	Return type	Description
Application	VT_DISPATCH	Returns the Application object; read only.
Parent	VT_DISPATCH	Returns the creator of the object; read only.
Note  The Application and Parent properties of the Application object return the Application object.


All Collection Objects

A collection provides a set of objects over which iteration can be performed. All collection objects must provide the following properties:

Property name	Return type	Description
Count	VT_I4	Returns the number of items in the collection; read only. Required.
_NewEnum	VT_DISPATCH	A special property that returns an enumerator object that implements IEnumVARIANT. Required.


Collection Methods

Methods for collections are described in the following table. The Item method is required; other methods are optional.

Method name	Return type	Description
Add	VT_DISPATCH or VT_EMPTY	Adds an item to a collection. Returns VT_DISPATCH if object is created (object can't exist outside the collection) or VT_EMPTY if no object is created (object can exist outside the collection).
Item	Varies with type of collection	Returns the indicated item in the collection.  Required. The Item method may take one or more arguments to indicate the element within the collection to return. This method is the default member (DISPID_VALUE) for the collection object.
Remove	VT_EMPTY	Removes an item from a collection. Uses indexing arguments in the same way as the Item method.
All collection objects must provide at least one form of indexing through the Item method. The dispatch ID of the Item method is DISPID_VALUE. Because it is the default member, it can be used in the following convenient form:

ThirdDef = MyWords(3).Definition 	' Equivalent to

' MyWords.Item(3).Definition

The Item method takes one or more arguments to indicate the index. Indexes may be numbers, strings, or other types. For example:

DogDef = MyWords("dog").Definition

Important  Within the application's type library, the _NewEnum property has a special dispatch ID: DISPID_NEWENUM. The name "_NewEnum" should not be localized.

The Add method may take one or more arguments. For example, if MyWord is an object with the properties Letters and Definition:

Dim MyWord As New Word

Dim MyDictionary as Words

MyWord = "dog"

MyWord.Letters = "Dog"

MyWord.Definition = "My best friend."

MyDictionary.Add MyWord

MyDictionary.Remove("Dog")

For more information on creating collection objects, see Chapter 2, "Exposing OLE Automation Objects."


Kinds of Collections

The standard for collections allows you to describe two kinds of collections, depending on whether it makes sense for the collected objects to exist outside the collection.

In some cases, it isn't logical for an object to exist independently of its collection. For example, an application's Documents collection contains all currently open Document objects. Opening a document means adding it to the collection, and closing the document means removing it from the collection. All open documents are, therefore, part of the collection; the application can't have open documents that aren't part of the collection. The relationship between the collection and the members of the collection can be shown in the following ways:

•	Documents.Add creates an object (an open document) and adds it to the collection. Since an object is created, a reference to it is returned:

Set MyDoc = Documents.Add

•	Document.Close removes an object from the collection:

Set SomeDoc = Documents(3)

SomeDoc.Close

In other cases, it is logical for the objects to exist outside the collection. For example, a Mail application might have Name objects, and many collections of these Name objects. Each Name object would have a user's email name, full name, and possibly other information. The email name and full name would likely be properties named EmailName and FullName.

Additionally, the application might have the following collections of Name objects:

•	 A collection for the "to" list on each piece of mail

•	 A collection of the names of all of the people to whom a user has sent mail

The collections of Name objects could be indexed by using either EmailName or  FullName.

For these collections, the Add method doesn't create an object because the object already exists. Therefore, the Add method should take an object as an argument and should not return a value. Assuming the existence of two collections (AddressBook and ToList), a user might execute the following code to add a Name object to the ToList collection:

Dim Message as Object

Dim AddressBook as Object

Dim NameRef as Object

.
.
.

Set NameRef = AddressBook.Names("Fred Funk")

Message.ToList.Add   NameRef

The Name object already exists and is contained in the AddressBook collection. The first line of code gets a reference to the Name object for "Fred Funk" and makes NameRef point to it. The second line of code adds a reference to the object to the ToList collection. No new object is created, so no reference is returned from the Add method. Unlike the relationship between Documents and Document, there is no way for the collected object (the Name) to know how to remove itself from the collections in which it is contained. Thus, to remove an item from a collection, the Remove method is used:

Message.ToList.Remove("Fred Funk")

This line of code removes the Name object that has the FullName "Fred Funk." The "Fred Funk" object may exist in other collections. These other collections will be unaffected.


Application Object Properties

If a type library is used, the Application object should be the object that has the appobj attribute. Because some OLE Automation controllers use the type information to allow unqualified access to the Application object's members, it is important to avoid overloading the Application object with too many members.

The Application object should have the properties listed in the following table. The Application, FullName, Name, Parent, and Visible properties are required; other properties are optional.

Property name	Return type	Description
ActiveDocument	VT_DISPATCH, VT_EMPTY	Returns the active document object or VT_EMPTY if none; read only.
Application	VT_DISPATCH	Returns the Application object; read only.  Required.
Caption	VT_BSTR	Sets or returns the title of the application window; read/write.  Setting the Caption to VT_EMPTY returns control to the application.
DefaultFilePath	VT_BSTR	Sets or returns the default path specification used by the application for opening files; read/write.
Documents	VT_DISPATCH	Returns a collection object for the open documents; read only.
FullName	VT_BSTR	Returns the file specification for the application, including path; read only. For example, C:\DRAWDIR\SCRIBBLE.  Required.
Height	VT_R4	Sets or returns the distance between the top and bottom edge of the main application window; read/write.
Interactive	VT_BOOL	Sets or returns True if the application accepts actions from the user, and False otherwise; read/write.
Left	VT_R4	Sets or returns the distance between the left edge of the physical screen and the main application window; read/write.
Name	VT_BSTR	Returns the name of the application, such as "Microsoft Excel"; read only. The Name property is the default member (DISPID_VALUE) for the Application object. Required.
Parent	VT_DISPATCH	Returns the Application object; read only. Required.
Path	VT_BSTR	Returns the path specification for the application's executable file; read only. For example, C:\DRAWDIR if the executable is C:\DRAWDIR\SCRIBBLE.EXE.
StatusBar	VT_BSTR	Sets or returns the text displayed in the status bar; read/write.
Top	VT_R4	Sets or returns the distance between the top edge of the physical screen and main application window; read/write.
Visible	VT_BOOL	Sets or returns whether the application is visible to the user; read/write. The default is False when the application is started with /Automation command-line switch. Required.
Width	VT_R4	Sets or returns the distance between the left and right edges of the main application window; read/write.
The Application object should have the following methods. The Quit method is required; other methods are optional.

Method name	Return type	Description
Help	VT_EMPTY	Displays online Help. May take three optional arguments: helpfile (VT_BSTR), helpcontextID (VT_I4), and helpstring (VT_BSTR). The helpfile argument specifies the Help file to display; if omitted, the main Help file for the application is displayed. The helpcontextID and helpstring arguments specify a Help context to display, and only one of them may be supplied; if both are omitted, the default Help topic is displayed.
Quit	VT_EMPTY	Exits the application and closes all open documents. Required.
Repeat	VT_EMPTY	Repeats the previous action in the user interface.
Undo	VT_EMPTY	Reverses the previous action in the user interface.


Document Object Properties

If your application is document-based, it should provide a Document object named "Document." Use a different name only if "Document" is inappropriate, for example, if your application uses highly technical or otherwise specialized terminology within its user interface.

The Document object should have the properties listed in the table that follows. The Application, FullName, Name, Parent, Path, and Saved properties are required; other properties are optional.

Property name	Return type	Description
Application	VT_DISPATCH	Returns the Application object; read only. Required.
Author	VT_BSTR	Sets or returns the summary information about the document's author; read/write.
Comments	VT_BSTR	Sets or returns summary information comments for the document; read/write.
FullName	VT_BSTR	Returns the file specification of the document, including path; read only. Required.
Keywords	VT_BSTR	Sets or returns summary information keywords associated with the document; read/write.
Name	VT_BSTR	Returns the filename of the document, not including the file's path specification; read only.
Parent	VT_DISPATCH	Returns the parent of the Document object; read only. Required.
Path	VT_BSTR	Returns the path specification for the document, not including the filename or filename extension; read only. Required.
ReadOnly	VT_BOOL	Returns True if the file is read only and False otherwise; read only.
Saved	VT_BOOL	Returns True if the document has never been saved, but has not changed since it was created. Returns True if it has been saved and has not changed since last saved. Returns False if it has never been saved and has changed since it was created; or if it was saved, but has changed since last saved. Read only; required.
Subject	VT_BSTR	Sets or returns the summary information about the subject of the document; read/write.
Title	VT_BSTR	Sets or returns the summary information about the title of the document; read/write.
The Document object should have the following methods. The Activate, Close, Print, Save, and SaveAs methods are required; other methods are optional.

Method name	Return type	Description
Activate	VT_EMPTY	Activates the first window associated with the document. Required.
Close	VT_EMPTY	Closes all windows associated with the document and removes the document from the Documents collection. Required. Takes two optional arguments, saveChanges (VT_BOOL) and fileName (VT_BSTR). The fileName argument specifies the name of the file in which to save the document.
NewWindow	VT_EMPTY	Creates a new window for the document.
Print	VT_EMPTY	Prints the document. Required. Takes three optional arguments: from (VT_I2), to (VT_I2), and copies (VT_I2). The from and to arguments specify the page range to print. The copies argument specifies the number of copies to print.
PrintOut	VT_EMPTY	Same as Print method, but provides an easier way to use the method in Visual Basic version 3.0, because Print is a Visual Basic keyword.
PrintPreview	VT_EMPTY	Previews the pages and page breaks of the document. Equivalent to choosing Print Preview from the File menu.
RevertToSaved	VT_EMPTY	Reverts to the last saved copy of the document, discarding any changes.
Save	VT_EMPTY	Saves changes to the file specified in the document's FullName property. Required.
SaveAs	VT_EMPTY	Saves changes to a file. Required. Takes one optional argument, filename (VT_BSTR). The filename argument may optionally include a path specification.


Documents Collection Object Properties

If your application supports a multiple-document interface (MDI), you should provide a Documents collection object. Use the name "Documents" for this collection unless the name is inappropriate for your application.

The Documents collection object should have all of the following properties.

Property name	Return type	Description
Application	VT_DISPATCH	Returns the Application object; read only. Required.
Count	VT_I4	Returns the number of items in the collection; read only. Required.
_NewEnum	VT_DISPATCH	A special property that returns an enumerator object that implements IEnumVARIANT. Required.
Parent	VT_DISPATCH	Returns the parent of the Documents collection object; read only. Required.
The Documents collection object should have all of the following methods.

Method name	Return type	Description
Add	VT_DISPATCH	Creates a new document and adds it to the collection. Returns the document that was created. Required.
Close	VT_EMPTY	Closes all documents in the collection. Required.
Item	VT_DISPATCH or VT_EMPTY	Returns a Document object from the collection or returns VT_EMPTY if the document does not exist. Takes an optional argument, index, which may be a string (VT_BSTR) indicating the document name, a number (VT_I4) indicating the ordered position within the collection, or either (VT_VARIANT). If index is omitted, returns the Document collection. The Item method is the default member (DISPID_VALUE). Required.
Open	VT_DISPATCH or VT_EMPTY	Opens an existing document and adds it to the collection. Returns the document that was opened or VT_EMPTY if the object could not be opened. Takes one required argument, filename, and one optional argument, password. Both arguments have type VT_BSTR. Required.


Font Object Properties

The Font object may be appropriate for some applications. It should have the following properties. The Application, Bold, Italic, Parent, and Size properties are required; other properties are optional.

Property name	Return type	Description
Application	VT_DISPATCH	Returns the Application object; read only. Required.
Bold	VT_BOOL	Sets or returns True if the font is boldface, and False otherwise; read/write. Required.
Color	VT_I4	Sets or returns the RGB color of the font; read/write.
Italic	VT_BOOL	Sets or returns True if the font is italic, and False otherwise; read/write. Required.
Name	VT_BSTR	Returns the name of the font; read only.
OutlineFont	VT_BOOL	Sets or returns True if the font is scaleable, and False otherwise. For example, bitmapped fonts are not scaleable, whereas TrueType fonts are scaleable; read/write.
Parent	VT_DISPATCH	Returns the parent of the Font object; read only.  Required.
Shadow	VT_BOOL	Sets or returns True if the font appears with a shadow, and False otherwise; read/write.
Size	VT_R4	Sets or returns the size of the font in points; read/write. Required.
Strikethrough	VT_BOOL	Sets or returns True if the font appears with a line running through it, and False otherwise; read/write.
Subscript	VT_BOOL	Sets or returns True if the font is subscripted, and False otherwise; read/write.
Superscript	VT_BOOL	Sets or returns True if the font is superscripted and False otherwise; read/write.


Storage Object Naming Conventions

Choose names for exposed objects, properties, and methods that can be easily understood by the users of your application. The guidelines in this section apply to all the items you expose:

•	Objects (implemented as classes in your application)

•	Properties and methods (implemented as members of a class)

•	Named arguments (implemented as named parameters in a member function)

•	Constants and enumerations (implemented as settings for properties and methods)

Use entire words or syllables

It is easier for users to remember complete words than to remember whether you abbreviated Window as Wind, Wn, or Wnd.

When you need to abbreviate because an identifier would be too long, try to use complete initial syllables. For example, use AltExpEval instead of AlternateExpressionEvaluation.

Use	Don't use
Application	App
Window	Wnd
Use mixed case

All identifiers should use mixed case, rather than underscores, to separate words.

Use	Don't use
ShortcutMenus	Shortcut_Menus, Shortcutmenus, SHORTCUTMENUS, SHORTCUT_MENUS
BasedOn	basedOn
Use the same word you use in the interface

Use consistent terminology; don't use names like HWND that are based on Hungarian notation. Try to use the same word your users would use to describe a concept.

Use	Don't use
Name	Lbl
Use the correct plural for the class name

Collection classes should use the correct plural for the class name. For example, if you have a class named Axis, you should store the collection of Axis objects in an Axes class. Similarly, a collection of Vertex objects is stored in a Vertices class. In cases where English uses the same word for the plural, append the word "Collection."

Use	Don't use
Axes	Axiss
SeriesCollection	CollectionSeries
Windows	ColWindow
Using plurals rather than inventing new names for collections reduces the number of items a user must remember. It also simplifies the selection of names for collections.

Note, however, that for some collections this may not be appropriate, especially where a set of objects exists independently of the collection. For example, a Mail program might have a Name object that exists in several collections, such as ToList, CCList, and GroupList. In this case, you might specify the individual name collections as ToNames, CCNames, and GroupNames.


Dispatch Interfaces

The dispatch interfaces provide a way to expose and access objects within an application. OLE Automation defines the following dispatch interfaces and functions:

•	IDispatch interface — Exposes objects, methods, and properties to OLE Automation programming tools and other applications.

•	Dispatch functions — Simplify the implementation of an IDispatch interface. You can use these functions to automatically generate an IDispatch interface.

•	IEnumVARIANT interface — Provides a way for OLE Automation controllers to iterate over collection objects.


Overview of Dispatch Interfaces

The following table describes the member functions of each of the dispatch interfaces.

Interface	Member name	Purpose
IDispatch	Invoke	Provides access to properties and methods exposed by the object.
	GetIDsOfNames	Maps a single member name and an optional set of argument names to a corresponding set of integer DISPIDs, which may then be used  on subsequent calls to Invoke.
	GetTypeInfo	Retrieves the type information for an object.
	GetTypeInfoCount	Retrieves the number of type information interfaces that an object provides (either 0 or 1).
IEnumVARIANT	Clone	Creates a copy of the current enumeration state.
	Next	Gets the next item or items in the enumeration sequence and returns them through an array.
	Reset	Resets the enumeration sequence to the beginning.
	Skip	Skips over the next item or items in the enumeration sequence.


Overview of Dispatch Functions

The dispatch functions are summarized in the following table. For 32-bit systems, these functions are provided in OLEAUT32.DLL; the header file is OLEAUTO.H, and the import library is OLEAUT32.LIB. For 16-bit systems, these functions are provided in OLE2DISP.DLL; the header file is DISPATCH.H, and the import library is OLE2DISP.LIB.

Category	Function name	Purpose
Dispatch interface creation	CreateDispTypeInfo	Creates simplified type information for an object.
	CreateStdDispatch	Creates a standard IDispatch implementation for an object.
	DispGetIDsOfNames	Converts a set of names to DISPIDs.
	DispGetParam	Retrieves and coerces elements from a DISPPARAMS structure.
	DispInvoke	Calls a member function of an IDispatch interface.
Active object initialization	GetActiveObject	Retrieves an instance of an object that is initialized with OLE.
	RegisterActiveObject	Initializes a running object with OLE. (Use when application starts.)
	RevokeActiveObject	Revokes a running application's initialization with OLE. (Use when application ends.)


IDispatch Interface

Implemented by	Used by	Header filename
Applications  that expose  programmable objects.	Applications  that access  programmable objects.	OLEAUTO.H (32-bit systems) DISPATCH.H (16-bit systems)
OLE Automation objects may implement the IDispatch interface for access by OLE Automation controllers, such as Visual Basic. The object's properties and methods can be accessed using IDispatch::GetIDsOfNames and IDispatch::Invoke.

The following examples show how to access an OLE Automation object through the IDispatch interface. Note that the code is abbreviated and omits error handling.

// Declarations of variables used

DEFINE_GUID(CLSID_Hello,	//...portions omitted for brevity...

HRESULT hresult;

IUnknown * punk;

IDispatch * pdisp;

OLECHAR FAR* szMember = "SayHello";

DISPID dispid;

DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};

EXCEPINFO excepinfo;

UINT nArgErr;

In the following lines, OleInitialize loads the OLE DLLs and CoCreateInstance initializes the OLE Automation object's class factory. For more information on these two functions, see the OLE 2 Programmer's Reference, Volume 1.

// Initialize OLE DLLs

hresult = OleInitialize(NULL);

// OLE function CoCreateInstance starts application using GUID

hresult = CoCreateInstance(CLSID_Hello, &punk);

QueryInterface checks whether the object supports IDispatch. (As with any call to QueryInterface, the returned pointer must be released when it is no longer needed.)

// QueryInterface to see if it supports IDispatch.

hresult = punk->QueryInterface(IID_IDispatch, &pdisp);

GetIDsOfNames retrieves the dispatch identifier (DISPID) for the indicated method or property, in this case, szMember.

// Retrieve the dispatch identifier for the SayHello method.

// Use defaults where possible.

hresult = pdisp->GetIDsOfNames(

IID_NULL,

&szMember,

1,

LOCALE_SYSTEM_DEFAULT,

&dispid);

In the following call to Invoke, the dispatch identifier (dispid) indicates the property or method to invoke. The SayHello method takes no parameters, so the fifth argument (&dispparamsNoArgs), contains NULL and 0, as initialized at declaration. To invoke a property or method that requires parameters, you would need to supply the parameters in the DISPPARAMS structure.

// Invoke the method. Use defaults where possible.

hresult = pdisp->Invoke(

dispid,

IID_NULL,

LOCALE_SYSTEM_DEFAULT,

DISPATCH_METHOD,

&dispparamsNoArgs,

NULL,

NULL,

NULL);


Data Types, Structures, and Enumerations

The IDispatch interface uses these data types and structures:

Name	Purpose
BSTR	A length-prefixed string.
CALLCONV	Identifies the calling convention used by a member function.
CURRENCY	Provides a precise data type of monetary data.
DISPID	Identifies a method, property, or argument to Invoke.
DISPPARAMS	Contains arguments passed to a method or property.
EXCEPINFO	Describes an error that occurred during Invoke.
INTERFACEDATA	Describes the members of an interface.
LCID	Provides locale information for international string comparisons and localized member names.
METHODDATA	Describes a method or property.
PARAMDATA	Describes a parameter to a method.
VARIANT	Describes a VARIANTARG that can't have the VT_BYREF bit set. Because VT_BYREF is not set, data of type VARIANT can't be passed within DISPPARAMS.
VARIANTARG	Describes arguments that may be passed within DISPPARAMS.
VARTYPE	Identifies the available variant types.


BSTR

A length-prefixed string used by OLE Automation data manipulation functions.

typedef OLECHAR *BSTR;

For details on this data type, see Chapter 6, "Data Manipulation Functions."


CALLCONV

Identifies the calling convention used by a member function described in METHODDATA.

typedef enum tagCALLCONV {

      CC_CDECL = 1

    , CC_MSCPASCAL

    , CC_PASCAL = CC_MSCPASCAL

    , CC_MACPASCAL

    , CC_STDCALL

    , CC_RESERVED

    , CC_SYSCALL

    , CC_MPWCDECL

    , CC_MPWPASCAL

    , CC_MAX	/* end of enum marker */

} CALLCONV;

On 16-bit Windows systems, functions implemented with the CC_CDECL calling convention can't have return type float or double. This includes functions returning DATE, which is a floating-point type.


CURRENCY

A currency number is stored as an 8-byte, two's complement integer, scaled by 10,000 to give a fixed-point number with 15 digits to the left of the decimal point and 4 digits to the right. This representation provides a range of ±922337203685477.5807. The currency data type is useful for calculations involving money, or for any fixed-point calculation where accuracy is particularly important.

typedef CY CURRENCY;

The data type is defined as a structure for working with currency more conveniently:

typedef struct tagCY

{

unsigned long Lo;

long Hi;

}

CY;


DISPID

Used by IDispatch::Invoke to identify methods, properties, and arguments.

typedef LONG DISPID;

The following DISPIDs have special meaning:

DISPID	Description
DISPID_VALUE	The default member for the object. This property or method is invoked when an OLE Automation controller specifies the object name without a property or method.
DISPID_NEWENUM	The _NewEnum property. This special, restricted property is required for collection objects. It returns an enumerator object that supports IEnumVariant and should have the restricted attribute specified in ODL.
DISPID_EVALUATE	The Evaluate method.  This method is implicitly invoked when the OLE Automation controller encloses the arguments in square brackets. For example, the following two lines are equivalent: x.[A1:C1].value = 10 x.Evaluate("A1:C1").value = 10 The Evaluate method has the dispatch ID DISPID_EVALUATE.
DISPID_PROPERTYPUT	The parameter that receives the value of an assignment in a property "put."
DISPID_CONSTRUCTOR	The C++ constructor function for the object.
DISPID_DESTRUCTOR	The C++ destructor function for the object.
DISPID_UNKNOWN	Value returned by IDispatch::GetIDsOfNames to indicate that a member or parameter name was not found.


DISPPARAMS

Used by IDispatch::Invoke to contain the arguments passed to a method or property. For more information, see the reference page for IDispatch::Invoke later in this chapter.

typedef struct FARSTRUCT tagDISPPARAMS{

VARIANTARG FAR* rgvarg;	// Array of arguments

DISPID FAR* rgdispidNamedArgs;	// Dispatch IDs of named arguments

unsigned int cArgs;	// Number of arguments

unsigned int cNamedArgs;	// Number of named arguments

} DISPPARAMS;


EXCEPINFO

Describes an exception that occurred during IDispatch::Invoke. See the reference page for "IDispatch::Invoke" for more information on exceptions.

typedef struct FARSTRUCT tagEXCEPINFO {

unsigned short wCode;	// An error code describing the error.

unsigned short wReserved;

BSTR bstrSource;	// Source of the exception.

BSTR bstrDescription;	// Textual description of the error.

BSTR bstrHelpFile;	// Help file path.

unsigned long dwHelpContext;	// Help context ID.

void FAR* pvReserved;

/* Pointer to function that fills in Help and description info */

HRESULT (STDAPICALLTYPE FAR* pfnDeferredFillIn)

(struct tagEXCEPINFO FAR*);

SCODE scode;	// An SCODE describing the error.

} EXCEPINFO, FAR* LPEXCEPINFO;

The following table describes the fields of the EXCEPINFO structure:

Name	Type	Description
wCode	unsigned short	An error code identifying the error. Error codes should be greater than 1000.  Either this field or the scode field must be filled in; the other must be set to 0.
wReserved	unsigned short	Reserved; should be set to 0.
bstrSource	BSTR	A textual, human-readable name of the source of the exception. Typically this will be an application name.  This field should be filled in by the implementor of IDispatch.
bstrDescription	BSTR	A textual, human-readable description of the error intended for the customer. If no description is available, use NULL.
bstrHelpFile	BSTR	The fully qualified drive, path, and filename of a Help file with more information about the error. If no Help is available, use NULL.
dwHelpContext	unsigned long	The Help context of the topic within the Help file. This field should be filled in if and only if the bstrHelpFile field is not NULL.
pvReserved	void FAR*	Must be set to NULL.
pfnDeferredFillIn	HRESULT (STDAPICALLTYPE FAR* pfnDeferredFillIn) (struct tagEXCEPINFO FAR*)	Pointer to a function that takes an EXCEPINFO structure as an argument and returns an HRESULT value. If deferred fill-in is not desired, this field should be set to NULL.
scode	SCODE	An SCODE describing the error. Either this field or wCode (but not both) must be filled in; the other must be set to 0.
Use the pfnDeferredFillIn field to allow an object to defer filling in the bstrDescription, bstrHelpFile, and dwHelpContext fields until they are needed. This field might be used, for example, if loading the string for the error is a time-consuming operation. To use deferred fill-in, the object puts a function pointer in this slot and does not fill any of the other fields except wCode (which is required in any case). To get additional information, the caller passes the EXCEPINFO structure back to the pexcepinfo callback function, which fills in the additional information. When the OLE Automation object and the OLE Automation controller are in different processes, the OLE Automation object calls pfnDeferredFillIn before returning to the controller.


INTERFACEDATA

Describes the OLE Automation object's properties and methods.

typedef struct FARSTRUCT tagINTERFACEDATA {

METHODDATA FAR* pmethdata;	// Pointer to an array of METHODDATAs

unsigned int cMembers;	// Count of members

} INTERFACEDATA;


LCID and National Language Support

Identifies a locale for national language support. Locale information is used for international string comparisons and localized member names. For information on LCIDs, see "Supporting Multiple National Languages" in Chapter 2.

typedef unsigned long LCID;


METHODDATA

Used to describe a method or property.

typedef struct FARSTRUCT tagMETHODDATA {

OLECHAR FAR* szName;	// Member name

PARAMDATA FAR* ppdata;	// Pointer to array of PARAMDATAs

DISPID dispid;	// Member ID

unsigned int iMeth;	// Method index

CALLCONV cc;	// Calling convention

unsigned int cArgs;	// Count of arguments

unsigned short wFlags;	// Whether this is a method or
// a property get, put, or putref

VARTYPE vtReturn;	// Return type

} METHODDATA;

The following table describes the fields of the METHODDATA structure:

Name	Type	Description
szName	OLECHAR  FAR*	The method name.
ppdata	PARAMDATA FAR*	The parameters for the method. The first parameter is ppdata[0], and so on.
dispid	DISPID	The ID of the method as used in IDispatch.
iMeth	unsigned int	The index of the method in the interface's VTBL. The indexes start with 0.
cc	CALLCONV	The calling convention. The CDECL and Pascal calling conventions are supported by the dispatch interface creation functions, such as CreateStdDispatch.
cArgs	unsigned int	The number of arguments for the method.
wFlags	unsigned short	Flags that indicate whether the method is used for getting or setting a property. The flags are the same as in IDispatch::Invoke. DISPATCH_METHOD indicates this is not used for a property. DISPATCH_PROPERTYGET indicates the method is used to get a property value. DISPATCH_PROPERTYPUT indicates the method is used to set the value of a property. DISPATCH_PROPERTYPUTREF indicates the method is used to make the property refer to a passed-in object.
vtReturn	VARTYPE	Return type for the method.


PARAMDATA

Used to describe a parameter accepted by a method or property.

typedef struct FARSTRUCT tagPARAMDATA {

OLECHAR FAR* szName;	// Parameter name

VARTYPE vt;	// Parameter type

} PARAMDATA;

The following table describes the fields of the PARAMDATA structure:

Name	Type	Description
szName	OLECHAR FAR *	The parameter name. Names should follow standard conventions for programming language access; that is, no embedded spaces or control characters, and 32 or fewer characters. This name should be localized, because each type description describes names for a particular locale.
vt	VARTYPE	The VARTYPE that will be used by the receiver. If more than one parameter type is accepted, VT_VARIANT should be specified.


VARIANT and VARIANTARG

Use VARIANTARG to describe arguments passed within DISPPARAMS. Use VARIANT to specify variant data that can't be passed by reference; the VARIANT type can't have the VT_BYREF bit set. Note that VARIANTs can be passed by value even if VARIANTARGs cannot.

typedef struct FARSTRUCT tagVARIANT VARIANT;

typedef struct FARSTRUCT tagVARIANT VARIANTARG;

typedef struct tagVARIANT  {

VARTYPE vt;

unsigned short wReserved1;

unsigned short wReserved2;

unsigned short wReserved3;

union {

unsigned char	bVal;	/* VT_UI1	*/

short	iVal;	/* VT_I2	*/

long	lVal;	/* VT_I4	*/

float	fltVal;	/* VT_R4	*/

double	dblVal;	/* VT_R8	*/

VARIANT_BOOL	bool;	/* VT_BOOL	*/

SCODE	scode;	/* VT_ERROR	*/

CY	cyVal;	/* VT_CY	*/

DATE	date;	/* VT_DATE	*/

BSTR	bstrVal;	/* VT_BSTR	*/

Iunknown	FAR* punkVal;	/* VT_UNKNOWN	*/

Idispatch	FAR* pdispVal;	/* VT_DISPATCH	*/

SAFEARRAY	FAR* parray;	/* VT_ARRAY|*	*/

unsigned char	FAR *pbVal;	/* VT_BYREF|VT_UI1	*/

short	FAR* piVal;	/* VT_BYREF|VT_I2	*/

long	FAR* plVal;	/* VT_BYREF|VT_I4	*/

float	FAR* pfltVal;	/* VT_BYREF|VT_R4	*/

double	FAR* pdblVal;	/* VT_BYREF|VT_R8	*/

VARIANT_BOOL	FAR* pbool;	/* VT_BYREF|VT_BOOL	*/

SCODE	FAR* pscode;	/* VT_BYREF|VT_ERROR	*/

CY	FAR* pcyVal;	/* VT_BYREF|VT_CY	*/

DATE	FAR* pdate;	/* VT_BYREF|VT_DATE	*/

BSTR	FAR* pbstrVal;	/* VT_BYREF|VT_BSTR	*/

IUnknown FAR*	FAR* ppunkVal;	/* VT_BYREF|VT_UNKNOWN	*/

IDispatch FAR*	FAR* ppdispVal;	/* VT_BYREF|VT_DISPATCH	*/

SAFEARRAY FAR*	FAR* parray;	/* VT_ARRAY|*	*/

VARIANT	FAR* pvarVal;	/* VT_BYREF|VT_VARIANT	*/

void	FAR* byref;	/* Generic ByRef	*/

};

};

To simplify extracting values from VARIANTARGs, OLE Automation provides a set of functions for manipulating this type. Use of these functions is strongly recommended to ensure that applications apply consistent coercion rules. The functions are described in Chapter 6, "Data Manipulation Functions."

The vt value governs the interpretation of the union as follows:

Value	Description
VT_EMPTY	No value was specified. If an argument is left blank, you should not return VT_EMPTY for the argument. Instead, you should return the VT_ERROR value: DISP_E_MEMBERNOTFOUND.
VT_EMPTY | VT_BYREF	Illegal.
VT_UI1	An unsigned 1-byte character is stored in bVal.
VT_UI1 | VT_BYREF	A reference to an unsigned 1-byte character was passed; a pointer to the value is in pbVal.
VT_I2	A 2-byte integer value is stored in iVal.
VT_I2 | VT_BYREF	A reference to a 2-byte integer was passed; a pointer to the value is in piVal.
VT_I4	A 4-byte integer value is stored in lVal.
VT_I4 | VT_BYREF	A reference to a 4-byte integer was passed; a pointer to the value is in plVal.
VT_R4	An IEEE 4-byte real value is stored in fltVal.
VT_R4 | VT_BYREF	A reference to an IEEE 4-byte real was passed; a pointer to the value is in pfltVal.
VT_R8	An 8-byte IEEE real value is stored in dblVal.
VT_R8 | VT_BYREF	A reference to an 8-byte IEEE real was passed; a pointer to its value is in pdblVal.
VT_CY	A currency value was specified. A currency number is stored as an 8-byte, two's complement integer, scaled by 10,000 to give a fixed-point number with 15 digits to the left of the decimal point and 4 digits to the right. The value is in cyVal.
VT_CY | VT_BYREF	A reference to a currency value was passed; a pointer to the value is in pcyVal.
VT_BSTR	A string was passed; it is stored in bstrVal. This pointer must be obtained and freed via the BSTR functions, which are described in Chapter 6, "Data Manipulation Functions."
VT_BSTR | VT_BYREF	A reference to a string was passed. A BSTR* which points to a BSTR is in pbstrVal. The referenced pointer must be obtained or freed via the BSTR functions.
VT_NULL	A propagating NULL value was specified. This should not be confused with the NULL pointer. The NULL value is used for tri-state logic as with SQL.
VT_NULL | VT_BYREF	Illegal.
VT_ERROR	An SCODE was specified. The type of the error is specified in scode. Generally, operations on error values should raise an exception or propagate the error to the return value, as appropriate.
VT_ERROR | VT_BYREF	A reference to an SCODE was passed. A pointer to the value is in pscode.
VT_BOOL	A Boolean (True/False) value was specified. A value of 0xFFFF (all bits one) indicates True; a value of 0 (all bits zero) indicates False. No other values are legal.
VT_BOOL | VT_BYREF	A reference to a Boolean value. A pointer to the Boolean value is in pbool.
VT_DATE	A value denoting a date and time was specified. Dates are represented as double-precision numbers, where midnight, January 1, 1900 is 2.0, January 2, 1900 is 3.0, and so on. The value is passed in date. This is the same numbering system used by most spreadsheet programs, although some incorrectly believe that February 29, 1900 existed, and thus set January 1, 1900 to 1.0. The date can be converted to and from an MS-DOS representation using VariantTimeToDosDateTime, discussed in Chapter 6, "Data Manipulation Functions."
VT_DATE | VT_BYREF	A reference to a date was passed. A pointer to the value is in pdate.
VT_DISPATCH	A pointer to an object was specified. The pointer is in pdispVal. This object is only known to implement IDispatch; the object can be queried as to whether it supports any other desired interface by calling QueryInterface on the object. Objects that do not implement IDispatch should be passed using VT_UNKNOWN.
VT_DISPATCH | VT_BYREF	A pointer to a pointer to an object was specified. The pointer to the object is stored in the location referred to by ppdispVal.
VT_VARIANT	Illegal. VARIANTARGs must be passed by reference.
VT_VARIANT | VT_BYREF	A pointer to another VARIANTARG is passed in pvarVal. This referenced VARIANTARG will never have the VT_BYREF bit set in vt, so only one level of indirection can ever be present. This value can be used to support languages that allow functions to change the types of variables passed by reference.
VT_UNKNOWN	A pointer to an object that implements the IUnknown interface is passed in punkVal.
VT_UNKNOWN | VT_BYREF	A pointer to a pointer to the IUnknown interface is passed in ppunkVal. The pointer to the interface is stored in the location referred to by ppunkVal.
VT_ARRAY | <anything>	An array of data type <anything> was passed. (VT_EMPTY and VT_NULL are illegal types to combine with VT_ARRAY). The pointer in pByrefVal points to an array descriptor, which describes the dimensions, size, and in-memory location of the array. The array descriptor is never accessed directly, but instead is read and modified using the functions described in Chapter 6, "Data Manipulation Functions."


VARTYPE

VARTYPE is an enumeration type used in VARIANT, TYPEDESC, OLE property sets, and safe arrays. The enumeration constants listed below are valid in the vt field of a VARIANT structure.

typedef unsigned short VARTYPE;

enum VARENUM{

VT_EMPTY	= 0,	// Not specified

VT_NULL	= 1,	// Null

VT_I2	= 2,	// 2-byte signed int

VT_I4	= 3,	// 4-byte signed int

VT_R4	= 4,	// 4-byte real

VT_R8	= 5,	// 8-byte real

VT_CY	= 6,	// Currency

VT_DATE	= 7,	// Date

VT_BSTR	= 8,	// Binary string

VT_DISPATCH	= 9,	// IDispatch FAR*

VT_ERROR	= 10,	// SCODE

VT_BOOL	= 11,	// Boolean; True=-1, False=0

VT_VARIANT	= 12,	// VARIANT FAR*

VT_UNKNOWN  = 13,	// IUnknown FAR*

VT_UI1	= 17,	// Unsigned char

.

.	//Other constants that are not valid in VARIANTs

.

};

VT_RESERVED	= (int) 0x8000

// By reference: a pointer to the data is passed

VT_BYREF  	= (int) 0x4000

VT_ARRAY 	= (int) 0x2000	// A safe array of the data is passed


IDispatch::GetIDsOfNames

HRESULT IDispatch::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid)
REFIID riid
OLECHAR FAR* FAR* rgszNames
unsigned int cNames
LCID lcid
DISPID FAR* rgdispid

Maps a single member and an optional set of argument names to a corresponding set of integer DISPIDs, which may be used on subsequent calls to IDispatch::Invoke. The dispatch function DispGetIDsOfNames provides a standard implementation of GetIDsOfNames.

Parameters

riid

Reserved for future use. Must be NULL.

rgszNames

Passed-in array of names to be mapped.

cNames

Count of the names to be mapped.

lcid

The locale context in which to interpret the names.

rgdispid

Caller-allocated array, each element of which contains an ID corresponding to one of the names passed in the rgszNames array. The first element represents the member name; the subsequent elements represent each of the member's parameters.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
E_OUTOFMEMORY	Out of memory.
DISP_E_UNKNOWNNAME	One or more of the names were not known.  The returned array of DISPIDs contains DISPID_UNKNOWN for each entry that corresponds to an unknown name.
DISP_E_UNKNOWNLCID	The LCID was not recognized.
Comments

An IDispatch implementation may choose to associate any positive integer ID value with a given name. Zero is reserved for the default, or Value property; −1 is reserved to indicate an unknown name; and other negative values are defined for other purposes. For example, if GetIDsOfNames is called and the implementation does not recognize one or more of the names, it will return DISP_E_UNKNOWNNAME and the rgdispid array will contain DISPID_UNKNOWN for the entries that correspond to the unknown names.

The member and parameter DISPIDs must remain constant for the lifetime of the object. This allows a client to obtain the DISPIDs once and cache them for later use.

When GetIDsOfNames is called with more than one name, the first name (rgszNames[0]) corresponds to the member name, and subsequent names correspond to the names of the member's parameters.

The same name may map to different DISPIDs, depending on context. For example, a name may have a DISPID when it is used as a member name with a particular interface, a different DISPID as a member of a different interface, and different mapping for each time it appears as a parameter.

The IDispatch interface binds to names at run time. To bind at compile time instead, an IDispatch client can map names to DISPIDs using the type information interfaces described in Chapter 8, "Type Description Interfaces." This allows a client to bind to members at compile time and avoid calling GetIDsOfNames at run time.

The implementation of GetIDsOfNames must be case insensitive. Clients that need case-sensitive name mapping should use the type information interfaces to map names to DISPIDs, rather than calling GetIDsOfNames.

Examples

The following code from the Lines sample file LINE.CPP implements the GetIDsOfNames member function for the CLine class. The OLE Automation object uses the standard implementation, DispGetIDsOfNames.

STDMETHODIMP

CLine::GetIDsOfNames(

REFIID riid,

OLECHAR FAR* FAR* rgszNames,

UINT cNames,

LCID lcid,

DISPID FAR* rgdispid)

{

return DispGetIDsOfNames(m_ptinfo, rgszNames, cNames, rgdispid);

}

The following code might appear in an OLE Automation controller that calls GetIDsOfNames to get the DISPID of the CLine Color property.

HRESULT hresult;

IDispatch FAR* pdisp = (IDispatch FAR*)NULL;

DISPID dispid;

OLECHAR FAR* szMember = "color";

// Omitted code that sets pdisp...

hresult = pdisp->GetIDsOfNames(

IID_NULL,

&szMember,

1, LOCALE_SYSTEM_DEFAULT,

&dispid);

See Also

CreateStdDispatch, DispGetIDsOfNames, ITypeInfo::GetIDsOfNames


IDispatch::GetTypeInfo

HRESULT IDispatch::GetTypeInfo(itinfo, lcid, pptinfo)
unsigned int itinfo
LCID lcid
ITypeInfo FAR* FAR* pptinfo

Retrieves a type information object, which can be used to get the type information for an interface.

Parameters

itinfo

The type information to return. Pass 0 to retrieve type information for the IDispatch implementation.

lcid

The locale ID for the type information. An object may be able to return different type information for different languages. This is important for classes that support localized member names. For classes that don't support localized member names, this parameter can be ignored.

pptinfo

Receives a pointer to the type information object requested.


Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success; the TypeInfo element exists.
DISP_E_BADINDEX	Failure; itinfo argument was not 0.
TYPE_E_ELEMENTNOTFOUND	Failure; itinfo argument was not 0.
Example

The following code from the sample file LINES.CPP loads information from the type library and implements the member function GetTypeInfo:

// These lines from CLines::Create load type information for the
// Lines collection from the type library.

hr = LoadTypeInfo(&pLines->m_ptinfo, IID_ILines);

if (FAILED(hr))

goto error;

// Additional code omitted...

// This function implements GetTypeInfo for the CLines collection.

STDMETHODIMP

CLines::GetTypeInfo(

UINT itinfo,

LCID lcid,

ITypeInfo FAR* FAR* pptinfo)

{

*pptinfo = NULL;

if(itinfo != 0)

return ResultFromScode(DISP_E_BADINDEX);

m_ptinfo->AddRef();

*pptinfo = m_ptinfo;

return NOERROR;

}

See Also

CreateStdDispatch, CreateDispTypeInfo


IDispatch::GetTypeInfoCount

HRESULT IDispatch::GetTypeInfoCount(pctinfo)
unsigned int FAR* pctinfo

Retrieves the number of type information interfaces that an object provides
(either 0 or 1).

Parameters

pctinfo

Points to location that receives the number of type information interfaces that the object provides. If the object provides type information, this number is 1; otherwise the number is 0.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success
E_NOTIMPL	Failure
Comments

The function may return zero, which indicates that the object does not provide any type information. In this case, the object may still be programmable through IDispatch, but does not provide type information for browsers, compilers, or other programming tools that access type information. This may be useful for hiding an object from browsers or for preventing early binding on an object.

Example

This code from the Lines sample file LINES.CPP implements the GetTypeInfoCount member function for the CLines class. (OLE Automation object.)

STDMETHODIMP

CLines::GetTypeInfoCount(UINT FAR* pctinfo)

{

*pctinfo = 1;

return NOERROR;

}

See Also

CreateStdDispatch


IDispatch::Invoke

HRESULT IDispatch::Invoke(dispidMember, riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr)
DISPID dispidMember
REFIID riid
LCID lcid
unsigned short wFlags
DISPPARAMS FAR* pdispparams
VARIANT FAR* pvarResult
EXCEPINFO FAR* pexcepinfo
unsigned int FAR* puArgErr

Provides access to properties and methods exposed by an object. The dispatch function DispInvoke provides a standard implementation of IDispatch::Invoke.

Parameters

dispidMember

Identifies the member. Use GetIDsOfNames or the object's documentation to obtain the dispatch identifier.

riid

Reserved for future use. Must be IID_NULL.

lcid

The locale context in which to interpret arguments. The lcid is used by the GetIDsOfNames function, and is also passed to Invoke to allow the object to interpret its arguments in a locale-specific way. Applications that don't support multiple national languages can ignore this parameter. See "Supporting Multiple National Languages," in Chapter 2, for more information.

wFlags

Flags describing the context of the Invoke call, as follows:

Value	Description
DISPATCH_METHOD	The member is being invoked as a method. If a property has the same name, both this and the DISPATCH_PROPERTYGET flag may be set.
DISPATCH_PROPERTYGET	The member is being retrieved as a property or data member.
DISPATCH_PROPERTYPUT	The member is being changed as a property or data member.
DISPATCH_PROPERTYPUTREF	The member is being changed via a reference assignment, rather than a value assignment. This flag is valid only when the property accepts a reference to an object.
pdispparams

Pointer to a structure containing an array of arguments, array of argument dispatch IDs for named arguments, and counts for number of elements in the arrays. See the Comments section for a description of the DISPPARAMS structure.

pvarResult

Pointer to where the result is to be stored, or NULL if the caller expects no result. This argument is ignored if DISPATCH_PROPERTYPUT or DISPATCH_PROPERTYPUTREF is specified.

pexcepinfo

Pointer to a structure containing exception information. This structure should be filled in if DISP_E_EXCEPTION is returned.

puArgErr

The index within rgvarg of the first argument that has an error. Arguments are stored in pdispparams->rgvarg in reverse order, so the first argument is the one with the highest index in the array. This parameter is returned only when the resulting SCODE is DISP_E_TYPEMISMATCH or DISP_E_PARAMNOTFOUND; see "Returning Errors" for details.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
DISP_E_BADPARAMCOUNT	The number of elements provided  DISPPARAMS is different from the number of arguments accepted by the method or property.
DISP_E_BADVARTYPE	One of the arguments in rgvarg is not a valid variant type.
DISP_E_EXCEPTION	The application needs to raise an exception. In this case the structure passed in pexcepinfo should be filled in.
DISP_E_MEMBERNOTFOUND	The requested member does not exist, or the call to Invoke tried to set the value of a read-only property.
DISP_E_NONAMEDARGS	This implementation of IDispatch does not support named arguments.
DISP_E_OVERFLOW	One of the arguments in rgvarg could not be coerced to the specified type.
DISP_E_PARAMNOTFOUND	One of the parameter dispatch IDs does not correspond to a parameter on the method. In this case puArgErr should be set to the first argument that contains the error.
DISP_E_TYPEMISMATCH	One or more of the arguments could not be coerced. The index within rgvarg of the first parameter with the incorrect type is returned in the puArgErr parameter.
DISP_E_UNKNOWNINTERFACE	The interface ID passed in riid is not IID_NULL.
DISP_E_UNKNOWNLCID	The member being invoked interprets string arguments according to the locale ID (LCID), and the LCID is not recognized. If the LCID is not needed to interpret arguments, this error should not be returned.
DISP_E_PARAMNOTOPTIONAL	A required parameter was omitted.
To return other errors, you can define your own errors using the MAKE_SCODE macro.

Comments

Generally, you should not implement Invoke directly; instead, you should use the dispatch interface creation functions CreateStdDispatch and DispInvoke.  For details, refer to "CreateStdDispatch" and "DispInvoke" in this chapter, and "Creating the IDispatch Interface" in Chapter 2.

However, if you need to perform some application-specific processing before calling a member, your code should perform the necessary actions and then call ITypeInfo::Invoke to invoke the member. ITypeInfo::Invoke acts exactly like IDispatch::Invoke. In fact, the standard implementations of IDispatch::Invoke that are created by CreateStdDispatch and DispInvoke defer to ITypeInfo::Invoke.

In an OLE Automation controller, use IDispatch::Invoke to get and set the values of properties or to call a method of an OLE Automation object. The dispidMember argument identifies the member to invoke. The dispatch IDs that identify members are defined by the implementor of the object, and can be determined by using the object's documentation, the IDispatch::GetIDsOfNames function, or the ITypeInfo interface.

Except as noted, the information that follows addresses developers of OLE Automation controllers. Nevertheless, if you're writing code that exposes OLE Automation objects, you should be familiar with all this information, because it describes the behavior that users of your exposed objects will expect.

Calling a Method with No Arguments

The simplest use of Invoke is to call a method that has no arguments.  You need only pass the dispatch ID of the method, a locale ID, the DISPATCH_METHOD flag, and an empty DISPPARAMS stucture. For example:

HRESULT hresult;

IUnknown FAR* punk;
IDispatch FAR* pdisp = (IDispatch FAR*)NULL;

OLECHAR FAR* szMember = "simple";

DISPID dispid;

DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};

hresult = CoCreateInstance(CLSID_CMyObject, NULL, CLSCTX_SERVER,
IID_Unknown, (void FAR* FAR*)&punk);

hresult = punk->QueryInterface(IID_IDispatch,
(void FAR* FAR*)&pdisp);

hresult = pdisp->GetIDsOfNames(IID_NULL, &szMember, 1,
LOCALE_SYSTEM_DEFAULT, &dispid) ;

hresult = pdisp->Invoke(

dispid,

IID_NULL,

LOCALE_SYSTEM_DEFAULT,

DISPATCH_METHOD,

&dispparamsNoArgs, NULL, NULL, NULL);

The example invokes a method named Simple on an object of the class CMyObject. First, it calls CoCreateInstance, which instantiates the object and returns a pointer to the object's IUnknown interface (punk). Next, it calls QueryInterface, receiving a pointer to the object's IDispatch interface (pdisp), and then uses pdisp to call the object's GetIDsOfNames function, passing the string 'Simple' in szMember to get the dispatch ID for the Simple method. With the dispatch ID for Simple in dispid, it calls Invoke to invoke the method, specifying DISPATCH_METHOD for the wFlags parameter, and using the system default locale.

To further simplify the code, the example declares a DISPPARAMS structure named dispparamsNoArgs appropriate to an Invoke call with no arguments.

Because the Simple method takes no arguments and returns no result, the puArgErr and pvarResult parameters are NULL. In addition, the example passes NULL for pexcepinfo, indicating that it is not prepared to handle exceptions and will handle only HRESULT errors.

Most methods, however, take one or more arguments. To invoke these methods, you must fill in the DISPPARAMS structure, as described in "Passing Parameters."

OLE Automation defines special dispatch IDs for invoking an object's Value (default), _NewEnum, and Evaluate members. See DISPID.

Getting and Setting Properties

Properties are accessed the same way as methods, except that DISPATCH_PROPERTYGET or DISPATCH_PROPERTYPUT is specified instead of DISPATCH_METHOD. Note that some languages can't distinguish between retrieving a property and calling a method; both the DISPATCH_PROPERTYGET and DISPATCH_METHOD flags should be set in this case.

The following example gets the value of a property named On.  Assume that the object has been created and its interfaces queried as in the previous example:

VARIANT FAR *pvarResult;

//...code omitted for brevity...

szMember = "On";

hresult = pdisp->GetIDsOfNames(IID_NULL, &szMember, 1,
LOCALE_SYSTEM_DEFAULT, &dispid) ;

hresult = pdisp->Invoke(

dispid,

IID_NULL,

LOCALE_SYSTEM_DEFAULT,

DISPATCH_PROPERTYGET,

&dispparamsNoArgs, pvarResult, NULL, NULL);

As in the previous example, the code calls GetIDsOfNames for the dispatch ID of the On property, then passes the ID to Invoke. Invoke returns the property's value in pvarResult. In general, the return value does not have VT_BYREF set. However, implementors may set this bit and return a pointer to the return value, if the lifetime of the return value is the same as that of the object.

To change the property's value, the call looks like this:

VARIANT FAR *pvarResult;

DISPPARAMS dispparams;

//...Code omitted for brevity...

szMember = "On";

dispparams.rgvarg[0].vt = VT_BOOL;

dispparams.rgvarg[0].bool = FALSE;

dispparams.rgdispidNamedArgs = DISPID_PROPERTYPUT;

dispparams.cArgs = 1;

disparams.cNamedArgs = 1;

hresult = pdisp->GetIDsOfNames(IID_NULL, &szMember, 1,
LOCALE_SYSTEM_DEFAULT, &dispid) ;

hresult = pdisp->Invoke(

dispid,

IID_NULL,

LOCALE_SYSTEM_DEFAULT,

DISPATCH_PROPERTYPUT,

&dispparams, NULL, NULL, NULL);

The new value for the property ( the Boolean value False) is passed as an argument when the On property's put function is invoked. Note that the dispatch ID for the argument is DISPID_PROPERTYPUT. This special dispatch ID is defined by OLE Automation to designate the parameter that contains the new value for a property's put function. The remaining details of the DISPPARAMS structure are described in the next section, "Passing Parameters."

The DISPATCH_PROPERTYPUT flag in the example above indicates that a property is being set by value. In Visual Basic, the following statement assigns the Value (default) property of YourObj to the property Prop:

MyObj.Prop = YourObj

This statement should be flagged as a DISPATCH_PROPERTYPUT. Similarly, statements like the following assign the Value property of one object to the Value property of another object:

Worksheet.Cell(1,1) = Worksheet.Cell(6,6)

MyDoc.Text1 = YourDoc.Text1

These statements result in a PROPERTY_PUT operation on Worksheet.Cell(1,1) and MyDoc.Text1.

Use the DISPATCH_PROPERTYPUTREF flag to indicate a property or data member that should be set by reference. For example, the following Visual Basic statement assigns the pointer to YourObj to the property Prop, and should be flagged as DISPATCH_PROPERTYPUTREF:

Set MyObj.Prop = YourObj

The Set statement causes a reference assignment, rather than a value assignment.

Note that the right side parameter is always passed by name, and should not be accessed positionally.

Passing Parameters

Arguments to the method or property being invoked are passed in the DISPPARAMS structure. This structure consists of a pointer to an array of arguments represented as variants, a pointer to an array of dispatch IDs for named arguments, and the number of arguments in each array.

typedef struct FARSTRUCT tagDISPPARAMS{

VARIANTARG FAR* rgvarg;	// Array of arguments

DISPID FAR* rgdispidNamedArgs; 	// Dispatch IDs of named arguments

unsigned int cArgs;	// Number of arguments

unsigned int cNamedArgs; 	// Number of named arguments

} DISPPARAMS;

The arguments are passed in the array rgvarg[ ], with the number of arguments passed in cArgs. Place the arguments in the array from last to first, so rgvarg[0] has the last argument and rgvarg[cArgs −1] has the first argument. The method or property may change the values of elements within the array rgvarg only if they have the VT_BYREF flag set; otherwise they should be considered read only.

A dispatch invocation can have named arguments as well as positional arguments. If cNamedArgs is 0, all the elements of rgvarg[ ] represent positional arguments. If cNamedArgs is nonzero, each element of rgdispidNamedArgs[ ] contains the DISPID of a named argument, and the value of the argument is in the matching element of rgvarg[ ]. The dispatch IDs of the named arguments are always contiguous in rgdispidNamedArgs, and their values are in the first cNamedArgs elements of rgvarg. Named arguments can't be accessed positionally and vice versa.

The DISPID of an argument is its zero-based position in the argument list. For example, the following method takes three arguments:

BOOL _export CDECL

CCredit::CheckCredit(BSTR bstrCustomerID,	// DISPID = 0
 BSTR bstrLenderID,	// DISPID = 1
 CURRENCY cLoanAmt)	// DISPID = 2

{

... // Code omitted.

}

If you include the DISPID with each named argument, you may pass the named arguments to Invoke in any order. For example, if a method is to be invoked with two positional arguments, followed by three named arguments (A, B, and C), using the following hypothetical syntax, then cArgs would be 5, and cNamedArgs would be 3:

object.method("arg1", "arg2", A := "argA", B := "argB", C: = "argC")

The first positional argument would be in rgvarg[4]. The second positional argument would be in rgvarg[3]. The ordering of named arguments should be immaterial to the IDispatch implementation, but these are also generally passed in reverse order. The argument named A would be in rgvarg[2], with the DISPID of A in rgdispidNamedArgs[2]. The argument named B would be in rgvarg[1], with the corresponding DISPID in rgdispidNamedArgs[1]. The argument named C would be in rgvarg[0], with the DISPID corresponding to C in rgdispidNamedArgs[0]. The following diagram illustrates the arrays and their contents.

You can also use Invoke on members with optional arguments, but all the optional arguments must be of type VARIANT. As with required arguments, the contents of the argument vector depend on whether the arguments are positional or named. The invoked member must ensure that the arguments are valid; Invoke merely passes the DISPPARAMS structure it receives.

Omitting named arguments is straightforward. You simply pass the arguments in rgvarg and their DISPIDs in rgdispidNamedArgs. To omit the argument named B, in the preceding example, you would set rgvarg[0] to the value of C, with its DISPID in rgdispidNamedArgs[0]; and rgvarg[1] to the value of A, with its DISPID in rgdispidNamedArgs[1]. The subsequent positional arguments would occupy elements 2 and 3 of the arrays. In this case, cArgs is 4, and cNamedArgs is 2.

If the arguments are positional (unnamed), set cArgs to the total number of possible arguments, cNamedArgs to zero, and pass VT_ERROR as the type of the omitted arguments, and DISP_E_PARAMNOTFOUND as the value. For example, the following code invokes ShowMe (,1):

VARIANT FAR *pvarResult;

EXCEPINFO FAR *pExcepinfo;

unsigned int FAR *puArgErr;

DISPPARAMS dispparams;

//...Code omitted for brevity...

szMember = "ShowMe";

hresult = pdisp->GetIDsOfNames(IID_NULL, &szMember, 1,
LOCALE_SYSTEM_DEFAULT, &dispid) ;

dispparams.rgvarg[0].vt = VT_I2;

dispparams.rgvarg[0].ival = 1;

dispparams.rgvarg[1].vt = VT_ERROR;

dispparams.rgvarg[1].scode = DISP_E_PARAMNOTFOUND;

dispparams.cArgs = 2;

disparams.cNamedArgs = 0;

hresult = pdisp->Invoke(

dispid,

IID_NULL,

LOCALE_SYSTEM_DEFAULT,

DISPATCH_METHOD,

&dispparams, pvarResult, pExcepinfo, puArgErr);

The example takes two positional arguments, but omits the first. Therefore, rgvarg[0] contains 1, the value of the last argument in the argument list, and rgvarg[1] contains VT_ERROR and the error scode, indicating the omitted first argument.

The calling code is responsible for releasing all strings and objects referred to by rgvarg[ ] or placed in *pvarResult. As with other parameters that are passed by value, if the invoked member must maintain access to a string after returning, the string should be copied. Similarly, if the member needs access to a passed object pointer after returning, it must call AddRef on the object. A common example occurs when an object property is changed to refer to a new object, using the DISPATCH_PROPERTYPUTREF flag.

For those implementing IDispatch::Invoke, OLE Automation provides the DispGetParam function to retrieve parameters from the argument vector and coerce them to the proper type. See the reference page for DispGetParam later in this chapter, for details.

Indexed Properties

When you invoke indexed properties of any dimension, you need to pass the indexes as additional arguments. To set an indexed property, place the new value in the first element of the rgvarg[ ] vector, and the indexes in the subsequent elements. To get an indexed property, pass the indexes in the first n elements of rgvarg and the number of indexes in cArg. Invoke returns the value of the property in pvarResult.

OLE Automation stores array data in column-major order, which is the same ordering scheme used by Visual Basic and FORTRAN, but different from C, C++, and Pascal. If you're programming in C, C++, or Pascal, you need to pass the indexes in the reverse order. The following example shows how to fill the DISPPARAMS structure in C++:

dispparams.rgvarg[0].vt = VT_I2;

dispparams.rgvarg[0].iVal = 99;

dispparams.rgvarg[1].vt = VT_I2;

dispparams.rgvarg[1].iVal = 2;

dispparams.rgvarg[2].vt = VT_I2;

dispparams.rgvarg[2].iVal = 1;

dispparams.rgdispidNamedArgs = DISPID_PROPERTYPUT;

dispparams.cArgs = 3;

disparams.cNamedArgs = 1;

The example changes the value of Prop[1,2] to 99.  The new property value is passed in rgvarg[0]. The rightmost index is passed in rgvarg[1], and the next index in rgvarg[2]. The cArgs field specifies the number of elements of rgvarg[ ] that contain data, and cNamedArgs is 1, indicating the new value for the property.

Property collections are an extension of this feature.

Raising Exceptions During Invoke

When you implement IDispatch::Invoke, you can choose to communicate errors either through the normal return value or by raising an exception. An exception is a special situation that is normally dealt with by jumping to the nearest enclosing exception handler.

To raise an exception, IDispatch::Invoke returns DISP_E_EXCEPTION and fills the structure passed through pexcepinfo with information about the cause of the exception or error. You can use the information to understand the cause of the exception and deal with it as necessary.

The exception information structure includes an error code number which identifies the kind of exception, a string which describes the error in a human-readable way, and a Help file and Help context number which can be passed to Windows Help for details about the error. At a minimum, the error code number must be filled in with a valid number.

If you consider IDispatch as another way to call C++ style methods in an interface, EXCEPINFO models the throwing of an exception or longjmp() call by such a method.

Returning Errors

Invoke returns DISP_E_MEMBERNOTFOUND if one of the following conditions occurs:

•	A member or parameter with the specified DISPID and matching cArgs can't be found, and the parameter is not optional.

•	The member is a void function and the caller didn't set pvarResult to NULL.

•	The member is a read-only property and the caller set wFlags to DISPATCH_PROPERTYPUT or DISPATCH_PROPERTYPUTREF.

If Invoke finds the member, but uncovers errors in the argument list, it returns one of several other errors. DISP_E_BAD_PARAMCOUNT means that the DISPPARAMS structure contains an incorrect number of parameters for the property or method. DISP_E_NONAMEDARGS means that Invoke received named arguments, but they are not supported by this member.

DISP_E_PARAMNOTFOUND means that the correct number of parameters was passed, but the dispatch ID for one or more parameters was incorrect. If Invoke can't convert one of the arguments to the desired type, it returns DISP_E_TYPEMISMATCH. In these two cases, if it can identify which argument is incorrect, Invoke sets *puArgErr to the index within rgvarg of the argument with the error. For example, if an OLE Automation method expects a reference to a double-precision number as an argument, but receives a reference to an integer, the argument should be coerced. However, if the method receives a date, IDispatch::Invoke returns DISP_E_TYPEMISMATCH and sets *puArgErr to the index of the integer in the argument array.

OLE Automation provides functions to perform standard conversions of VARIANT, and these should be used for consistent operation. Only when these functions fail is DISP_E_TYPEMISMATCH returned. For more information on converting arguments, see Chapter 6, "Data Manipulation Functions."


Example

This code from the Lines sample file LINES.CPP implements the Invoke member function for the CLines class:

STDMETHODIMP

CLines::Invoke(

DISPID dispidMember,

REFIID riid,

LCID lcid,

WORD wFlags,

DISPPARAMS FAR* pdispparams,

VARIANT FAR* pvarResult,

EXCEPINFO FAR* pexcepinfo,

UINT FAR* puArgErr)

{

HRESULT hr;

m_bRaiseException = FALSE;

hr =  DispInvoke(

this, m_ptinfo,

dispidMember, wFlags, pdispparams,

pvarResult, pexcepinfo, puArgErr);

if (m_bRaiseException)

{

if (NULL != pexcepinfo)

_fmemcpy(pexcepinfo, &m_excepinfo, sizeof(EXCEPINFO));

return ResultFromScode(DISP_E_EXCEPTION);

}

else return hr;

}

This code calls the CLine Invoke member function to get the value of the Color property:

HRESULT hr;

EXCEPINFO excepinfo;

UINT nArgErr;

VARIANT vRet;

DISPPARAMS FAR * pdisp;

OLECHAR FAR* szMember;

DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};

// Initialization code omitted for brevity.

szMember = "Color";

hr = pdisp->GetIDsOfNames(IID_NULL, &szMember, 1, LOCALE_SYSTEM_DEFAULT,

&dispid);

// Get Color property.

hr = pdisp->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT,

 DISPATCH_PROPERTYGET, &dispparams, &vRet, &excepinfo, &nArgErr);

See Also

CreateStdDispatch, DispInvoke, DispGetParam, ITypeInfo::Invoke


Dispatch Interface Creation Functions

Implemented by	Used by	Header filename	Import library name
OLEAUT32.DLL  (32-bit systems) OLE2DISP.DLL  (16-bit systems)	Applications  that expose  programmable objects.	OLEAUTO.H DISPATCH.H	OLEAUT32.LIB OLE2DISP.LIB
These functions simplify the creation of IDispatch interfaces.


CreateDispTypeInfo

HRESULT CreateDispTypeInfo (pInterfacedata, lcid, pptinfo)
INTERFACEDATA pInterfacedata
LCID lcid
ITypeInfo FAR* FAR* pptinfo

Creates simplified type information for use in an implementation of IDispatch.

Parameters

pInterfacedata

The interface description that this type information describes.

lcid

The locale ID (LCID) for the names used in the type information.

pptinfo

On return, pointer to a pointer to a type information implementation for use in DispGetIDsOfNames and DispInvoke.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	The interface is supported.
E_INVALIDARG	Either the interface description or the locale ID is invalid.
E_OUTOFMEMORY	Insufficient memory to complete operation.


Comments

Type information may be constructed at run time using CreateDispTypeInfo and an INTERFACEDATA structure that describes the object being exposed.

The type information returned by this function is primarily designed to automate the implementation of IDispatch. CreateDispTypeInfo doesn't return all the type information described in Chapter 9, "Type Building Interfaces." The argument pInterfaceData is not a complete description of an interface. It does not include Help information, comments, optional parameters, and other type information that is useful in different contexts.

The recommended method for providing type information about an object is to describe the object using the Object Description Language (ODL) and to compile the object description into a type library using MkTypLib.

To use type information from a type library, use the LoadTypeLib and GetTypeInfoOfGuid functions instead of CreateDispTypeInfo. For more information, see Chapter 8, "Type Description Interfaces."

Example

The code that follows creates type information from the INTERFACEDATA shown to expose the CCalc object.

static METHODDATA NEARDATA rgmdataCCalc[] =

{

      PROPERTY(VALUE,   IMETH_ACCUM,    IDMEMBER_ACCUM,    VT_I4)

    , PROPERTY(ACCUM,   IMETH_ACCUM,    IDMEMBER_ACCUM,    VT_I4)

    , PROPERTY(OPND,    IMETH_OPERAND,  IDMEMBER_OPERAND,  VT_I4)

    , PROPERTY(OP,      IMETH_OPERATOR, IDMEMBER_OPERATOR, VT_I2)

    ,  METHOD0(EVAL,    IMETH_EVAL,     IDMEMBER_EVAL,     VT_BOOL)

    ,  METHOD0(CLEAR,   IMETH_CLEAR,    IDMEMBER_CLEAR,    VT_EMPTY)

    ,  METHOD0(DISPLAY, IMETH_DISPLAY,  IDMEMBER_DISPLAY,  VT_EMPTY)

    ,  METHOD0(QUIT,    IMETH_QUIT,     IDMEMBER_QUIT,     VT_EMPTY)

    ,  METHOD1(BUTTON,  IMETH_BUTTON,   IDMEMBER_BUTTON,   VT_BOOL)

};

INTERFACEDATA NEARDATA g_idataCCalc =

{

rgmdataCCalc, DIM(rgmdataCCalc)

};

// Use Dispatch Interface creation functions to implement IDispatch

CCalc FAR*

CCalc::Create()

{

HRESULT hresult;

CCalc FAR* pcalc;

CArith FAR* parith;

ITypeInfo FAR* ptinfo;

IUnknown FAR* punkStdDisp;

extern INTERFACEDATA NEARDATA g_idataCCalc;

if((pcalc = new FAR CCalc()) == NULL)

return NULL;

pcalc->AddRef();

parith = &(pcalc->m_arith);

// Build a TypeInfo for the functionality on this object that

// is being exposed for external programmability.

hresult = CreateDispTypeInfo(

&g_idataCCalc, LOCALE_SYSTEM_DEFAULT, &ptinfo);

if(hresult != NOERROR)

goto LError0;

// Create an aggregate with an instance of the default

// implementation of IDispatch that is initialized with our

// TypeInfo.

hresult = CreateStdDispatch(

pcalc,	// controlling unknown

parith,	// instance to dispatch on

ptinfo,	// typeinfo describing the instance

&punkStdDisp);

ptinfo->Release();

if(hresult != NOERROR)

goto LError0;

pcalc->m_punkStdDisp = punkStdDisp;

return pcalc;

LError0:;

pcalc->Release();

return NULL;

}


CreateStdDispatch

HRESULT CreateStdDispatch (punkOuter, pvThis, ptinfo, ppunkStdDisp)
IUnknown FAR* punkOuter
void FAR* pvThis
ITypeInfo FAR* ptinfo
IUnknown FAR* FAR* ppunkStdDisp

Creates a standard implementation of the IDispatch interface through a single function call. This simplifies exposing objects through OLE Automation.

Parameters

punkOuter

Pointer to the object's IUnknown implementation.

pvThis

Pointer to the object to expose.

ptinfo

Pointer to the type information that describes the exposed object.

ppunkStdDisp

Pointer to the location where the implementation of the IDispatch interface for this object is returned. This pointer is NULL if the function fails.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
E_INVALIDARG	One of the first three arguments is invalid.
E_OUTOFMEMORY	There was insufficient memory to complete the operation.
Comments

You can use CreateStdDispatch when you create an object instead of implementing the IDispatch member functions for the object. The implementation that CreateStdDispatch creates has these limitations:

•	Supports only one national language

•	Supports only dispatch-defined exception codes returned from Invoke

LoadTypeLib, GetTypeInfoOfGuid, and CreateStdDispatch comprise the minimum set of functions you need to cal l to expose an object using a type library. For more information on LoadTypeLib and GetTypeInfoOfGuid, see Chapter 8, "Type Description Interfaces."

CreateDispTypeInfo and CreateStdDispatch comprise the minimum set of dispatch components you need to call to expose an object using type information provided by the INTERFACEDATA structure.

Example

The following code implements the IDispatch interface for the CCalc class using CreateStdDispatch.

CCalc FAR*

CCalc::Create()

{

HRESULT hresult;

CCalc FAR* pcalc;

CArith FAR* parith;

ITypeInfo FAR* ptinfo;

IUnknown FAR* punkStdDisp;

extern INTERFACEDATA NEARDATA g_idataCCalc;

if((pcalc = new FAR CCalc()) == NULL)

return NULL;

pcalc->AddRef();

parith = &(pcalc->m_arith);

// Build a TypeInfo for the functionality on this object that

// is being exposing for external programmability.

hresult = CreateDispTypeInfo(

&g_idataCCalc, LOCALE_SYSTEM_DEFAULT, &ptinfo);

if(hresult != NOERROR)

goto LError0;

// Create an aggregate with an instance of the default

// implementation of IDispatch that is initialized with our

// TypeInfo.

hresult = CreateStdDispatch(

pcalc,	// controlling unknown

parith,	// instance to dispatch on

ptinfo,	// typeinfo describing the instance

&punkStdDisp);

ptinfo->Release();

if(hresult != NOERROR)

goto LError0;

pcalc->m_punkStdDisp = punkStdDisp;

return pcalc;

LError0:;

pcalc->Release();

return NULL;

}


DispGetIDsOfNames

HRESULT DispGetIDsOfNames (ptinfo, rgszNames, cNames, rgdispid)
ITypeInfo * ptinfo
OLECHAR FAR* FAR* rgszNames
unsigned int	cNames
DISPID FAR* rgdispid

Uses type information to convert a set of names to DISPIDs. This is the recommended implementation of IDispatch::GetIDsOfNames.

Parameters

ptinfo

Pointer to the type information for an interface. Note that this type information is specific to one interface and language code, so it is not necessary to pass an IID or LCID to this function.

rgszNames

An array of name strings, which can be the same array passed to DispInvoke in the DISPPARAMS structure. If cNames is greater than one, the first name is interpreted as a method name and subsequent names are interpreted as parameters to that method.

cNames

The number of elements in rgszNames.

rgdispid

Pointer to an array of DISPIDs to be filled in by this function. The first ID corresponds to the method name; subsequent IDs are interpreted as parameters to the method.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	The interface is supported.
E_INVALIDARG	One of the arguments is invalid.
DISP_E_UNKNOWNNAME	One or more of the given names were not known.  The returned array of DISPIDs will contain DISPID_UNKNOWN for each entry that corresponds to an unknown name.
Other returns	Any of the ITypeInfo::Invoke errors may also be returned.
Example

This code from the Lines sample file POINTS.CPP implements the member function GetIDsOfNames for the CPoints class using DispGetIDsOfNames.

STDMETHODIMP

CPoints::GetIDsOfNames(

REFIID riid,

char FAR* FAR* rgszNames,

UINT cNames,

LCID lcid,

DISPID FAR* rgdispid)

{

return DispGetIDsOfNames(m_ptinfo, rgszNames, cNames, rgdispid);

}

See Also

CreateStdDispatch, IDispatch::GetIDsOfNames


DispGetParam

HRESULT DispGetParam(dispparams, iPosition, vt, pvarResult, puArgErr)
DISPPARAMS FAR* dispparams
unsigned int iPosition
VARTYPE vt
VARIANT FAR* pvarResult
unsigned int FAR* puArgErr

Retrieves a parameter from the DISPPARAMS structure, checking both named parameters and positional parameters, and coerces it to the specified type.

Parameters

dispparams

Pointer to the parameters passed to IDispatch::Invoke.

iPosition

The position of the parameter in the parameter list. DispGetParam starts at the end of the array, so if iPosition is 0, the last parameter in the array is returned.

vt

The type to which the argument should be coerced.

pvarResult

Pointer to the variant into which to pass the parameter.

puArgErr

On return, pointer to the index of the argument that caused a DISP_E_TYPEMISMATCH error. This pointer should be returned to Invoke to indicate the position of the argument in DISPPARAMS that caused the error.

Return Value

The SCODE obtained from the HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
DISP_E_BADVARTYPE	The variant type vt is not supported.
DISP_E_OVERFLOW	The retrieved parameter could not be  coerced to the specified type.
DISP_E_PARAMNOTFOUND	The parameter indicated by iPosition  could not be found.
DISP_E_TYPEMISMATCH	The argument could not be coerced to the specified type.
E_INVALIDARG	One of the arguments was invalid.
E_OUTOFMEMORY	Insufficient memory to complete operation.
Comments

The output parameter pvarResult must be a valid VARIANT; any existing contents will be released in the standard way. The contents of the VARIANT should be freed with VariantFree.

If DispGetParam is used to get the right side of a property put operation, the second parameter should be DISPID_PROPERTYPUT. For example:

DispGetParam(&dispparams, DISPID_PROPERTYPUT, VT_BOOL, &varResult)

Note also that named parameters can't be accessed positionally, and vice versa.

Example

The following example uses DispGetParam to set X and Y properties:

STDMETHODIMP

CPoint::Invoke(

DISPID dispidMember,

REFIID riid,

LCID lcid,

unsigned short wFlags,

DISPPARAMS FAR* pdispparams,

VARIANT FAR* pvarResult,

EXCEPINFO FAR* pexcepinfo,

unsigned int FAR* puArgErr)

{

unsigned int uArgErr;

HRESULT hresult;

VARIANTARG varg0;

VARIANT varResultDummy;

UNUSED(lcid);

UNUSED(pexcepinfo);

// Make sure the wFlags are legal

if(wFlags & ~(DISPATCH_METHOD | DISPATCH_PROPERTYGET |

DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYPUTREF))

return ResultFromScode(E_INVALIDARG);

// This object only exposes a "default" interface.

if(!IsEqualIID(riid, IID_NULL))

return ResultFromScode(DISP_E_UNKNOWNINTERFACE);

// It simplifies the following code if the caller

// ignores the return value.

if(puArgErr == NULL)

puArgErr = &uArgErr;

if(pvarResult == NULL)

pvarResult = &varResultDummy;

VariantInit(&varg0);

// Assume the return type is void, unless we find otherwise.

VariantInit(pvarResult);

switch(dispidMember){

case IDMEMBER_CPOINT_GETX:

V_VT(pvarResult) = VT_I2;

V_I2(pvarResult) = GetX();

break;

case IDMEMBER_CPOINT_SETX:

hresult = DispGetParam(pdispparams, 0, VT_I2, &varg0, puArgErr);

if(hresult != NOERROR)

return hresult;

SetX(V_I2(&varg0));

break;

case IDMEMBER_CPOINT_GETY:

V_VT(pvarResult) = VT_I2;

V_I2(pvarResult) = GetY();

break;

case IDMEMBER_CPOINT_SETY:

hresult = DispGetParam(pdispparams, 0, VT_I2, &varg0, puArgErr);

if(hresult != NOERROR)

return hresult;

SetY(V_I2(&varg0));

break;

default:

return ResultFromScode(DISP_E_MEMBERNOTFOUND);

}

return NOERROR;

}

See Also

CreateStdDispatch, IDispatch::Invoke


DispInvoke

HRESULT DispInvoke(_this, ptinfo, dispidMember, wFlags, pparams, pvarResult, pexcepinfo, puArgErr)
void FAR* _this
ITypeInfo FAR* ptinfo
DISPID dispidMember
unsigned short wFlags
DISPPARAMS FAR* pparams
VARIANT FAR* pvarResult
EXCEPINFO	pexcepinfo
unsigned int FAR* puArgErr

Automatically calls member functions on an interface, given type information for the interface. You can describe an interface with type information and implement IDispatch::Invoke for the interface using this single call.

Parameters

 _this

Pointer to an implementation of the IDispatch interface described by ptinfo.

ptinfo

Pointer to the type information describing the interface.

dispidMember

Identifies the member. Use GetIDsOfNames or the object's documentation to obtain the dispatch ID.

wFlags

Flags describing the context of the Invoke call, as follows:

Value	Description
DISPATCH_METHOD	The member is being invoked as a method. If a property has the same name, both  this and the DISPATCH_PROPERTYGET  flag may be set.
DISPATCH_PROPERTYGET	The member is being retrieved as a  property or data member.
DISPATCH_PROPERTYPUT	The member is being changed as a  property or data member.
DISPATCH_PROPERTYPUTREF	The member is being changed via a reference assignment, rather than a  value assignment. This flag is valid  only when the property accepts a  reference to an object.
pparams

Pointer to a structure containing an array of arguments, an array of argument dispatch IDs for named arguments, and counts for number of elements in the arrays.

pvarResult

Pointer to where the result is to be stored, or NULL if the caller expects no result. This argument is ignored if DISPATCH_PROPERTYPUT or DISPATCH_PROPERTYPUTREF is specified.

pexcepinfo

Pointer to a structure containing exception information. This structure should be filled in if DISP_E_EXCEPTION is returned.

puArgErr

The index within rgvarg of the first argument that has an error. Arguments are stored in pdispparams->rgvarg in reverse order, so the first argument is the one with the highest index in the array. This parameter is returned only when the resulting SCODE is DISP_E_TYPEMISMATCH or DISP_E_PARAMNOTFOUND.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
DISP_E_BADPARAMCOUNT	The number of elements provided in DISPPARAMS is different from the number of arguments accepted by the method or property.
DISP_E_BADVARTYPE	One of the arguments in DISPPARAMS is not a valid variant type.
DISP_E_EXCEPTION	The application needs to raise an exception. In this case, the structure passed in pexcepinfo should be filled in.
DISP_E_MEMBERNOTFOUND	The requested member does not exist.
DISP_E_NONAMEDARGS	This implementation of IDispatch does not support named arguments.
DISP_E_OVERFLOW	One of the arguments in DISPPARAMS could not be coerced to the specified type.
DISP_E_PARAMNOTFOUND	One of the parameter IDs does not correspond to a parameter on the method. In this case puArgErr is set to the first argument that contains the error.
DISP_E_PARAMNOTOPTIONAL	A required parameter was omitted.
DISP_E_TYPEMISMATCH	One or more of the arguments could not be coerced. The index within rgvarg of the first parameter with the incorrect type is returned in puArgErr.
E_INVALIDARG	One of the arguments is invalid.
E_OUTOFMEMORY	Insufficient memory to complete operation.
Other returns	Any of the ITypeInfo::Invoke errors may also be returned.
Comments

The parameter _this is a pointer to an implementation of the interface being deferred to. DispInvoke builds a stack frame, coerces parameters using standard coercion rules, pushes them on the stack, and calls the correct member function in the virtual function table (VTBL).

Example

The following code from the Lines sample file LINES.CPP implements IDispatch::Invoke using DispInvoke. This function uses  m_bRaiseException to signal that an error occurred during the DispInvoke call.

STDMETHODIMP

CLines::Invoke(

DISPID dispidMember,

REFIID riid,

LCID lcid,

WORD wFlags,

DISPPARAMS FAR* pdispparams,

VARIANT FAR* pvarResult,

EXCEPINFO FAR* pexcepinfo,

UINT FAR* puArgErr)

{

HRESULT hr;

if (NULL == pexcepinfo)

return ResultFromScode(E_INVALIDARG);

m_bRaiseException = FALSE;

hr =  DispInvoke(

this, m_ptinfo,

dispidMember, wFlags, pdispparams,

pvarResult, pexcepinfo, puArgErr);

if (m_bRaiseException)

{

_fmemcpy(pexcepinfo, &m_excepinfo, sizeof(EXCEPINFO));

return ResultFromScode(DISP_E_EXCEPTION);

}

else return hr;

}

See Also

CreateStdDispatch, IDispatch::Invoke


Active Object Registration Functions

Implemented by	Used by	Header filename	Import library name
OLEAUT32.DLL  (32-bit systems) OLE2DISP.DLL  (16-bit systems)	Applications  that expose or  access programmable  objects.	OLEAUTO.H DISPATCH.H	OLEAUT32.LIB OLE2DISP.LIB
These functions let you identify a running instance of an object. Because they use the OLE object table (GetRunningObjectTable), they also require either OLE32.DLL (for 32-bit systems) or OLE2.DLL (for 16-bit systems).

When an application is started with the /Automation switch, it should initialize its Application object as the active object by calling RegisterActiveObject after it initializes OLE.

Applications may also initialize other top-level objects as the active object. For example, an application that exposes a Document object may want to let OLE Automation controllers retrieve and modify the currently active document.

For more information on initializing the active object, see Chapter 2, "Exposing OLE Automation Objects."


GetActiveObject

HRESULT GetActiveObject(rclsid, pvreserved, ppunk)
REFCLSID rclsid
void FAR* pvreserved
IUnknown FAR* FAR* ppunk

Retrieves a pointer to a running application initialized with OLE.

Parameters

rclsid

Pointer to the class ID of the active object from the OLE registration database.

pvreserved

Reserved for future use. Must be NULL.

ppunk

On return, a pointer to the requested active object.


Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success
Other returns	Failure


RegisterActiveObject

HRESULT RegisterActiveObject (punk, rclsid, pvreserved, pdwRegister)
IUnknown FAR* punk
REFCLSID rclsid
DWORD dwFlags
unsigned long FAR* pdwRegister

Registers an object as the active object for its class.

Parameters

punk

Pointer to the IUnknown interface of the active object.

rclsid

Pointer to the class ID of the active object.

dwFlags

Flags controlling registration of the object. Possible values are ACTIVEOBJECT_STRONG and ACTIVEOBJECT_WEAK.

pdwRegister

On return, pointer to a handle. You must pass this handle to RevokeActiveObject to end the object's status as active.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success
Other returns	Failure
Comments

The RegisterActiveObject function registers the object to which punk points as the active object for the class denoted by rclsid. Registration causes the object to be listed in OLE's running object table, a globally accessible lookup table that keeps track of the objects that are currently running on your computer. (See the OLE 2 Programmer's Reference, Volume 1 for more information on the running object table.) The dwFlags parameter specifies the strength or weakness of the registration, which affects the way the object is shut down.

In general, OLE Automation objects should behave in the following manner:

•	If the object is visible, it should shut down only in response to an explicit user command (such as the Exit command from the File menu), or to the equivalent command from an OLE Automation controller (invoking the Quit or Exit method on the Application object).

•	If the object is not visible, it should shut down only when the last external connection to it disappears.

Strong registration performs an AddRef on the object, thereby incrementing the reference count of the object (and its associated stub) in the running object table. A strongly registered object must be explicitly revoked from the table with RevokeActiveObject. Strong registration (ACTIVEOBJECT_STRONG) is the default.

Weak registration keeps a pointer to the object in the running object table, but does not increment the reference count. Consequently, when the last external connection to a weakly registered object disappears, OLE releases the object's stub and the object itself is no longer available.

To ensure the desired behavior, you must consider not only OLE's default actions, but also the following:

•	Even though your code creates an invisible object, the object may become visible at some later time. Once the object is visible, it should remain visible and active until it receives an explicit command to shut down, which may occur after references from your code disappear.

•	Other OLE Automation controllers may be using the object. If so, your code should not force the object to shut down.

To avoid possible conflicts, OLE Automation objects should always register with ACTIVEOBJECT_WEAK, and call CoLockObjectExternal when necessary to guarantee that the object remains active. CoLockObjectExternal adds a strong lock, thereby preventing the object's reference count from reaching zero. For detailed information on this function, refer to the OLE 2 Programmer's Reference, Volume 1.

Most commonly, objects need to call CoLockObjectExternal when they become visible, so that they remain active until the user requests shutdown.

To shut down correctly, your code should follow these steps

1.	When the object becomes visible, make the following call to add a lock on behalf of the user:

CoLockObjectExternal(punk, TRUE, TRUE)

The lock should remain in effect until the user explicitly requests shutdown, such as with a Quit or Exit command.

2.	When the user requests shutdown, call CoLockObjectExternal again to free the lock, as follows:

CoLockObjectExternal(punk, FALSE, TRUE)

3.	Call RevokeActiveObject to make the object inactive.

4.	To end all connections from remote processes, call CoDisconnectObject as follows:

CoDisconnectObject(punk, 0)

This function is described in the OLE 2 Programmer's Reference, Volume 1.


RevokeActiveObject

HRESULT RevokeActiveObject (dwRegister, pvreserved)
unsigned long dwRegister
void FAR* pvreserved

Ends an object's status as active.

Parameters

dwRegister

A handle previously returned by RegisterActiveObject.

pvreserved

Reserved for future use. Must be NULL.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success
Other returns	Failure


IEnumVARIANT Interface

Implemented by	Used by	Header filename
Applications that  expose collections  of objects.	Applications that  access collections  of objects.	OLEAUTO.H (32-bit systems) DISPATCH.H (16-bit systems)
The IEnumVARIANT interface provides a method for enumerating a collection of variants, including heterogeneous collections of objects and intrinsic types. Callers of this interface need not know the specific type, or types, of the elements in the collection.

The following is the definition that results from expanding the parameterized type IEnumVARIANT:

 interface IEnumVARIANT : IUnknown {

virtual HRESULT Next(unsigned long celt,
VARIANT FAR* rgvar,
unsigned long FAR* pceltFetched) = 0;

virtual HRESULT Skip(unsigned long celt) = 0;

virtual HRESULT Reset() = 0;

virtual HRESULT Clone(IEnumVARIANT FAR* FAR* ppenum) = 0;

};

See the sample file ENUMVAR.CPP in the Lines sample to see how to implement a collection of objects using IEnumVARIANT.


IEnumVARIANT::Clone

HRESULT IEnumVARIANT::Clone(ppenum)
IEnumVARIANT FAR* FAR* ppenum

Creates a copy of the current enumeration state.

Parameter

ppenum

On return, pointer to the location of the clone enumerator.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
E_OUTOFMEMORY	Insufficient memory to complete the operation.
Comments

Using this function, you can record a particular point in the enumeration sequence, then return to it at a later time. The enumerator returned is of the same actual interface as the one that is being cloned.

There is no guarantee that exactly the same set of variants will be enumerated the second time as was enumerated the first. Although an exact duplicate is desirable, the outcome depends on the collection being enumerated. Some collections (for example, an enumeration of the files in a directory) will find it impractical to maintain this condition.

Example

The following code implements IEnumVariant::Clone for collections in the Lines sample (ENUMVAR.CPP):

STDMETHODIMP

CEnumVariant::Clone(IEnumVARIANT FAR* FAR* ppenum)

{

CEnumVariant FAR* penum = NULL;

HRESULT hr;

*ppenum = NULL;

hr = CEnumVariant::Create(m_psa, m_cElements, &penum);

if (FAILED(hr))

goto error;

penum->AddRef();

penum->m_lCurrent = m_lCurrent;

*ppenum = penum;

return NOERROR;

error:

if (penum)

penum->Release();

return hr;

}


IEnumVARIANT::Next

HRESULT IEnumVARIANT::Next(celt, rgvar, pceltFetched)
unsigned long celt
VARIANT FAR* rgvar
unsigned long FAR* pceltFetched

Attempts to get the next celt items in the enumeration sequence and return them through the array pointed to by rgvar.

Parameters

celt

The number of elements to be returned.

rgvar

An array of at least size celt in which the elements are to be returned.

pceltFetched

Pointer to the number of elements returned in rgvar, or NULL.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	The number of elements returned is celt.
S_FALSE	The number of elements returned is less than celt.
Comments

If fewer than the requested number of elements remain in the sequence, return only the remaining elements; the actual number of elements returned is passed through *pceltFetched (unless it is NULL).

Example

The following code implements IEnumVariant::Next for collections in the Lines sample (ENUMVAR.CPP):

STDMETHODIMP

CEnumVariant::Next(ULONG cElements, VARIANT FAR* pvar, ULONG FAR* pcElementFetched)

{

HRESULT hr;

ULONG l;

long l1;

ULONG l2;

if (pcElementFetched != NULL)

*pcElementFetched = 0;

for (l=0; l<cElements; l++)

VariantInit(&pvar[l]);

// Retrieve the next cElements elements.

for (l1=m_lCurrent, l2=0; l1<(long)(m_lLBound+m_cElements) &&

l2<cElements; l1++, l2++)

{

hr = SafeArrayGetElement(m_psa, &l1, &pvar[l2]);

if (FAILED(hr))

goto error;

}

// Set count of elements retrieved

if (pcElementFetched != NULL)

*pcElementFetched = l2;

m_lCurrent = l1;

return  (l2 < cElements) ? ResultFromScode(S_FALSE) : NOERROR;

error:

for (l=0; l<cElements; l++)

VariantClear(&pvar[l]);

return hr;

}


IEnumVARIANT::Reset

HRESULT IEnumVARIANT::Reset()

Resets the enumeration sequence to the beginning.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success
S_FALSE	Failure
Comments

There is no guarantee that exactly the same set of variants will be enumerated the second time as was enumerated the first. Although an exact duplicate is desirable, the outcome depends on the collection being enumerated. Some collections (for example, an enumeration of the files in a directory) will find it impractical to maintain this condition.

Example

The following code implements IEnumVariant::Reset for collections in the Lines sample (ENUMVAR.CPP):

STDMETHODIMP

CEnumVariant::Reset()

{

m_lCurrent = m_lLBound;

return NOERROR;

}


IEnumVARIANT::Skip

HRESULT IEnumVARIANT::Skip(celt)
unsigned long celt

Attempts to skip over the next celt elements in the enumeration sequence.

Parameter

celt

The number of elements to skip.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	The specified number of elements was skipped.
S_FALSE	The end of the sequence was reached before skipping the requested number of elements.
Example

The following code implements IEnumVariant::Reset for collections in the Lines sample (ENUMVAR.CPP):

STDMETHODIMP

CEnumVariant::Skip(ULONG cElements)

{

m_lCurrent += cElements;

if (m_lCurrent > (long)(m_lLBound+m_cElements))

{

m_lCurrent =  m_lLBound+m_cElements;

return ResultFromScode(S_FALSE);

}

else return NOERROR;

}


Data Manipulation Functions

Data manipulation functions access and manipulate the array, string, and variant data types used by OLE Automation.


Overview of Data Manipulation Functions

The data manipulation functions are summarized in the following table.

Category	Function name	Purpose
Array manipulation	SafeArrayAccessData	Increments the lock count of an array and returns a pointer to array data.
	SafeArrayAllocData	Allocates memory for a safe array based on a descriptor created with SafeArrayAllocDescriptor.
	SafeArrayAllocDescriptor	Allocates memory for a safe array descriptor.
	SafeArrayCopy	Copies an existing array.
	SafeArrayCreate	Creates a new array descriptor.
	SafeArrayDestroy	Destroys an array descriptor.
	SafeArrayDestroyData	Frees memory used by the data elements in a safe array.
	SafeArrayDestroyDescriptor	Frees memory used by a safe array descriptor.
	SafeArrayGetDim	Returns the number of dimensions in an array.
	SafeArrayGetElement	Retrieves an element of an array.
	SafeArrayGetElemsize	Returns the size of an element.
	SafeArrayGetLBound	Retrieves the lower bound for a given dimension.
	SafeArrayGetUBound	Retrieves the upper bound for a given dimension.
	SafeArrayLock	Increments the lock count of an array.
	SafeArrayPtrOfIndex	Returns a pointer to an array element.
	SafeArrayPutElement	Assigns an element into an array.
	SafeArrayRedim	Resizes a safe array.
	SafeArrayUnAccessData	Frees a pointer to array data and decrements the lock count of the array.
	SafeArrayUnlock	Decrements the lock count of an array.
String manipulation	SysAllocString	Creates and initializes a string.
	SysAllocStringByteLen	Creates a zero-terminated string of a specified length (32-bit only).
	SysAllocStringLen	Creates a string of a specified length.
	SysFreeString	Frees a previously created string.
	SysReAllocString	Changes the size and value of a string.
	SysReAllocStringLen	Changes the size of an existing string.
	SysStringByteLen	Returns the length of a string in bytes (32-bit only).
	SysStringLen	Returns the length of a string.
Variant manipulation	VariantChangeType	Converts a variant to another type.
	VariantChangeTypeEx	Converts a variant to another type using a locale ID.
	VariantClear	Releases resources and sets a variant to VT_EMPTY.
	VariantCopy	Copies a variant.
	VariantCopyInd	Copies variants that may contain a pointer.
	VariantInit	Initializes a variant.
	Low-level conversion functions	Converts specific types of variants to other variant types. These functions are called by VariantChangeType and VariantChangeTypeEx.
Time conversion	DosDateTimeToVariantTime	Converts MS-DOS date and time representations to a variant time.
	VariantTimeToDosDateTime	Converts a variant time to MS-DOS date and time representations.


Array Manipulation Functions

Implemented by	Used by	Header filename	Import library name
OLEAUT32.DLL (32-bit systems) OLE2DISP.DLL (16-bit systems)	Applications that expose or access programmable objects.	OLEAUTO.H DISPATCH.H	OLEAUT32.LIB OLE2DISP.LIB
The arrays passed by IDispatch::Invoke within VARIANTARGs are called safe arrays. Safe arrays contain information about the number of dimensions and bounds within them. When an array is an argument or the return value of a function, the parray field of VARIANTARG points to an array descriptor. This array descriptor should not be accessed directly unless you are creating arrays containing elements with nonvariant data types. Instead, use the functions SafeArrayAccessData and SafeArrayUnaccessData to access the data.

The base type of the array is indicated by VT_ tag | VT_ARRAY. The data referenced by an array descriptor is stored in column-major order, which is the same ordering scheme used by Visual Basic and FORTRAN, but different from C and Pascal. Column-major order means that the leftmost dimension (as specified in a programming language syntax) changes first.

Following are the definitions of the safe array descriptor and the functions to use when accessing the data in the descriptor and the array itself.


Data Types and Structures

SAFEARRAY
SAFEARRAYBOUND


SAFEARRAY

typedef struct FARSTRUCT tagSAFEARRAY {

unsigned short cDims; 	// Count of dimensions in this array.

unsigned short fFeatures;	// Flags used by the SafeArray

// routines documented below:

#if defined(WIN32)

unsigned long cbElements;	// Size of an element of the array;

// Does not include size of

// pointed-to data.

unsigned long cLocks;	// Number of times the array has been

// locked without corresponding unlock.

#else

unsigned short cbElements;

unsigned short cLocks;

unsigned long handle;	// Unused but kept for compatibility

#endif

void HUGEP* pvData; 	// Pointer to the data.

SAFEARRAYBOUND rgsabound[1];	// One bound for each dimension.

} SAFEARRAY;

Note that the definition varies, depending on the target operating system platform. On 32-bit Windows systems, both the cbElements and cLocks parameters are unsigned long integers, and the handle parameter is omitted. On 16-bit Windows systems, cbElements and cLocks are unsigned short integers, and the handle parameter has been retained for compatibility with earlier software.

The array rgsabound is stored with the leftmost dimension in rgsabound[0] and the rightmost dimension in rgsabound[cDims − 1]. If an array were specified in C-like syntax as a[2][5], it would have two elements in the rgsabound vector. Element 0 has an lLbound of 0 and a cElements of 2. Element 1 has an lLbound of 0 and a cElements of 5.

The fFeatures flags describe attributes of an array that may affect how the array is released. This allows freeing the array without referencing its containing variant. The bits are accessed using the following constants:

#define FADF_AUTO	0x0001	// Array is allocated on the stack.

#define FADF_STATIC	0x0002	// Array is statically allocated.

#define FADF_EMBEDDED	0x0004	// Array is embedded in a structure.

#define FADF_FIXEDSIZE	0x0010	// Array may not be resized or

// reallocated.

#define FADF_BSTR	0x0100	// An array of BSTRs.

#define FADF_UNKNOWN	0x0200	// An array of IUnknown*.

#define FADF_DISPATCH	0x0400	// An array of IDispatch*.

#define FADF_VARIANT	0x0800	// An array of VARIANTs.

#define FADF_RESERVED	0xF0E8	// Bits reserved for future use.


SAFEARRAYBOUND

typedef struct tagSAFEARRAYBOUND {

unsigned long cElements;

long lLbound;

} SAFEARRAYBOUND;

This structure represents the bounds of one dimension of the array. The lower bound of the dimension is represented by lLbound, and cElements represents the number of elements in the dimension.


SafeArrayAccessData

HRESULT SafeArrayAccessData (psa, ppvdata)
SAFEARRAY FAR* psa
void HUGEP* FAR* ppvdata

Increments the lock count of an array and retrieves a pointer to the array data.

Parameters

psa

Pointer to an array descriptor created by SafeArrayCreate.

ppvdata

On exit, pointer to a pointer to the array data. Note that arrays may be larger than 64K, so huge pointers must be used in Windows version 3.1 or later.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
E_INVALIDARG	The argument psa was not a valid safe array descriptor.
E_UNEXPECTED	The array could not be locked.


SafeArrayAllocData

HRESULT SafeArrayAllocData(psa)
SAFEARRAY FAR* psa

Allocates memory for a safe array based on a descriptor created with SafeArrayAllocDescriptor.

Parameters

psa

Pointer to an array descriptor created by SafeArrayAllocDescriptor.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
E_INVALIDARG	The argument psa was not a valid safe array descriptor.
E_UNEXPECTED	The array could not be locked.
Example

The following example creates a safe array using the SafeArrayAllocDescriptor and SafeArrayAllocData functions.

SAFEARRAY FAR* FAR*ppsa;

unsigned int ndim = 2;

HRESULT hresult = SafeArrayAllocDescriptor( ndim, ppsa );

if( FAILED( hresult ) )

return ERR_OutOfMemory;

(*ppsa)->rgsabound[ 0 ].lLbound = 0;

(*ppsa)->rgsabound[ 0 ].cElements = 5;

(*ppsa)->rgsabound[ 1 ].lLbound = 1;

(*ppsa)->rgsabound[ 1 ].cElements = 4;

hresult = SafeArrayAllocData( *ppsa );

if( FAILED( hresult ) ) {

SafeArrayDestroyDescriptor( *ppsa )

return ERR_OutOfMemory;

}

See Also

SafeArrayAllocData, SafeArrayDestroyData, SafeArrayDestroyDescriptor


SafeArrayAllocDescriptor

HRESULT SafeArrayAllocDescriptor(cDims, ppsaOut)
unsigned int cDims
SAFEARRAY FAR* FAR* ppsaOut

Allocates memory for a safe array descriptor.

Parameters

cDims

The number of dimensions of the array.

ppsaOut

Pointer to a location in which to store the created array descriptor.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
E_INVALIDARG	The argument psa was not a valid safe array descriptor.
E_UNEXPECTED	The array could not be locked.
Comments

This function lets you create safe arrays containing elements with data types other than those provided by SafeArrayCreate. After creating an array descriptor using SafeArrayAllocDescriptor, set the element size in the array descriptor and call SafeArrayAllocData to allocate memory for the array elements.

Example

The following example creates a safe array using the SafeArrayAllocDescriptor and SafeArrayAllocData functions.

SAFEARRAY FAR* FAR*ppsa;

unsigned int ndim = 2;

HRESULT hresult = SafeArrayAllocDescriptor( ndim, ppsa );

if( FAILED( hresult ) )

return ERR_OutOfMemory;

(*ppsa)->rgsabound[ 0 ].lLbound = 0;

(*ppsa)->rgsabound[ 0 ].cElements = 5;

(*ppsa)->rgsabound[ 1 ].lLbound = 1;

(*ppsa)->rgsabound[ 1 ].cElements = 4;

hresult = SafeArrayAllocData( *ppsa );

if( FAILED( hresult ) ) {

SafeArrayDestroyDescriptor( *ppsa )

return ERR_OutOfMemory;

}

See Also

SafeArrayAllocData, SafeArrayDestroyData, SafeArrayDestroyDescriptor


SafeArrayCopy

HRESULT SafeArrayCopy(psa, ppsaOut)
SAFEARRAY FAR* psa
SAFEARRAY FAR* FAR* ppsaOut

Creates a copy of an existing safe array.

Parameters

psa

Pointer to an array descriptor created by SafeArrayCreate.

ppsaOut

Pointer to a location in which to return the new array descriptor.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
E_INVALIDARG	The argument psa was not a valid safe array descriptor.
E_OUTOFMEMORY	Insufficient memory to create the copy.
Comments

SafeArrayCopy calls the string or variant manipulation functions if the array to copy contains either of those data types. If the array being copied contains object references, the reference counts for those objects are incremented.

See Also

SysAllocStringLen, VariantCopy, VariantCopyInd.


SafeArrayCreate

SAFEARRAY * SafeArrayCreate(vt, cDims, rgsabound)
VARTYPE vt
unsigned int cDims
SAFEARRRAYBOUND FAR* rgsabound

Creates a new array descriptor, allocates and initializes the data for the array, and returns a pointer to the new array descriptor.


Parameters

vt

The base type of the array (that is, the VARTYPE of each element of the array). The VARTYPE is restricted to a subset of the variant types. Neither the VT_ARRAY nor the VT_BYREF flag can be set. VT_EMPTY and VT_NULL are not valid base types for the array. All other types are legal.

cDims

Number of dimensions in the array. This can't be changed after the array is created.

rgsabound

Pointer to a vector of bounds (one for each dimension) to allocate for the array.

Return Value

Points to the array descriptor, or NULL if the array could not be created.

Example

HRESULT PASCAL __export CPoly::EnumPoints(IEnumVARIANT FAR* FAR* ppenum)

{

unsigned int i;

HRESULT hresult;

VARIANT var;

SAFEARRAY FAR* psa;

CEnumPoint FAR* penum;

POINTLINK FAR* ppointlink;

SAFEARRAYBOUND rgsabound[1];

rgsabound[0].lLbound = 0;

rgsabound[0].cElements = m_cPoints;

psa = SafeArrayCreate(VT_VARIANT, 1, rgsabound);

if(psa == NULL){

hresult = ReportResult(0, E_OUTOFMEMORY, 0, 0);

goto LError0;

}

.

.	// Code omitted here.

.

LError0:;

return hresult;

}


SafeArrayDestroy

HRESULT SafeArrayDestroy(psa)
SAFEARRAY FAR* psa

Destroys an existing array descriptor and all the data in the array. If objects are stored in the array, Release is called on each object in the array.

Parameters

psa

Pointer to an array descriptor created by SafeArrayCreate.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
DISP_E_ARRAYISLOCKED	The array is currently locked.
E_INVALIDARG	The item pointed to by psa is not a safe array descriptor.
Example

STDMETHODIMP_(ULONG) CEnumPoint::Release()

{

if(--m_refs == 0){

if(m_psa != NULL)

SafeArrayDestroy(m_psa);

delete this;

return 0;

}

return m_refs;

}


SafeArrayDestroyData

HRESULT SafeArrayDestroyData(psa)
SAFEARRAY FAR* psa

Destroys all the data in a safe array. If objects are stored in the array, Release is called on each object in the array.

Parameters

psa

Pointer to an array descriptor.


Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
DISP_E_ARRAYISLOCKED	The array is currently locked.
E_INVALIDARG	The item pointed to by psa is not a safe array descriptor.
Comments

This function is typically used when freeing safe arrays that contain elements with data types other than variants.

See Also

SafeArrayAllocData, SafeArrayAllocDescriptor, SafeArrayDestroyDescriptor


SafeArrayDestroyDescriptor

HRESULT SafeArrayDestroyDescriptor(psa)
SAFEARRAY FAR* psa

Destroys a descriptor of a safe array.

Parameters

psa

Pointer to a safe array descriptor.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
DISP_E_ARRAYISLOCKED	The array is currently locked.
E_INVALIDARG	The item pointed to by psa is not a safe array descriptor.
Comments

This function is typically used to destroy the descriptor of a safe array that contains elements with data types other than variants. Destroying the array descriptor does not destroy the elements in the array. Call SafeArrayDestroyData to free the elements before destroying the array descriptor.

See Also

SafeArrayAllocData, SafeArrayAllocDescriptor, SafeArrayDestroyData


SafeArrayGetDim

unsigned int SafeArrayGetDim(psa)
SAFEARRAY FAR* psa

Returns the number of dimensions in the array.

Parameters

psa

Pointer to an array descriptor created by SafeArrayCreate.

Return Value

Returns the number of dimensions in the array.

Example

HRESULT

CEnumPoint::Create(SAFEARRAY FAR* psa, CEnumPoint FAR* FAR* ppenum)

{

long lBound;

HRESULT hresult;

CEnumPoint FAR* penum;

// Verify that the SafeArray is the proper shape.

//

if(SafeArrayGetDim(psa) != 1)

return ReportResult(0, E_INVALIDARG, 0, 0);

.

.	// Code omitted here.

.

}


SafeArrayGetElement

HRESULT SafeArrayGetElement(psa, rgIndices, pvData)
SAFEARRAY FAR* psa
long FAR* rgIndices
void FAR* pvData

Retrieves a single element of the array.


Parameters

psa

Pointer to an array descriptor created by SafeArrayCreate.

rgIndices

Pointer to a vector of indexes for each dimension of the array. The rightmost (least significant) dimension is rgIndices[0]. The leftmost dimension is stored at rgIndices[psa->cDims − 1].

pvData

Pointer to the location to place the element of the array.

Comments

This function automatically calls SafeArrayLock and SafeArrayUnlock before and after retrieving the element. The caller must provide a storage area of the correct size to receive the data. If the data element is a string, object, or variant, the function copies the element in the correct way.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
DISP_E_BADINDEX	The specified index is invalid.
E_INVALIDARG	One of the arguments is invalid.
E_OUTOFMEMORY	Memory could not be allocated for the element.
Example

STDMETHODIMP CEnumPoint::Next(

ULONG celt,

VARIANT FAR rgvar[],

ULONG FAR* pceltFetched)

{

unsigned int i;

long ix;

HRESULT hresult;

for(i = 0; i < celt; ++i)

VariantInit(&rgvar[i]);

for(i = 0; i < celt; ++i){

if(m_iCurrent == m_celts){

hresult = ReportResult(0, S_FALSE, 0, 0);

goto LDone;

}

ix = m_iCurrent++;

hresult = SafeArrayGetElement(m_psa, &ix, &rgvar[i]);

if(FAILED(hresult))

goto LError0;

}

hresult = NOERROR;

LDone:;

*pceltFetched = i;

return hresult;

LError0:;

for(i = 0; i < celt; ++i)

VariantClear(&rgvar[i]);

return hresult;

}


SafeArrayGetElemsize

unsigned int SafeArrayGetElemsize(psa)
SAFEARRAY FAR* psa

Returns the size, in bytes, of the elements of a safe array.

Parameters

psa

Pointer to an array descriptor created by SafeArrayCreate.


SafeArrayGetLBound

HRESULT SafeArrayGetLBound(psa, nDim, plLbound)
SAFEARRAY FAR* psa
unsigned int nDim
long FAR* plLbound

Returns the lower bound for any dimension of a safe array.


Parameters

psa

Pointer to an array descriptor created by SafeArrayCreate.

nDim

The array dimension for which to get the lower bound.

plLbound

Pointer to the location to return the lower bound.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
DISP_E_BADINDEX	The specified index is out of bounds.
E_INVALIDARG	One of the arguments is invalid.
Example

HRESULT

CEnumPoint::Create(SAFEARRAY FAR* psa, CEnumPoint FAR* FAR* ppenum)

{

long lBound;

HRESULT hresult;

CEnumPoint FAR* penum;

// Verify that the SafeArray is the proper shape.

//

hresult = SafeArrayGetLBound(psa, 1, &lBound);

if(FAILED(hresult))

return hresult;

.

.	// Code omitted here.

.

}


SafeArrayGetUBound

HRESULT SafeArrayGetUBound(psa, nDim, plUbound)
SAFEARRAY FAR* psa
unsigned int nDim
long FAR* plUbound

Returns the upper bound for any dimension of a safe array.

Parameters

psa

Pointer to an array descriptor created by SafeArrayCreate().

nDim

The array dimension for which to get the upper bound.

plUbound

Pointer to the location to return the upper bound.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
DISP_E_BADINDEX	The specified index is out of bounds.
E_INVALIDARG	One of the arguments is invalid.
Example

HRESULT

CEnumPoint::Create(SAFEARRAY FAR* psa, CEnumPoint FAR* FAR* ppenum)

{

long lBound;

HRESULT hresult;

CEnumPoint FAR* penum;

// Verify that the SafeArray is the proper shape.

//

hresult = SafeArrayGetUBound(psa, 1, &lBound);

if(FAILED(hresult))

goto LError0;

.

.	// Code omitted

.

LError0:;

penum->Release();

return hresult;

}


SafeArrayLock

HRESULT SafeArrayLock(psa)
SAFEARRAY FAR* psa

Increments the lock count of an array and places a pointer to the array data in pvData of the array descriptor.

Parameters

psa

Pointer to an array descriptor created by SafeArrayCreate.

Comments

The pointer in the array descriptor is valid until SafeArrayUnlock is called. Calls to SafeArrayLock can be nested; an equal number of calls to SafeArrayUnlock are required.

An array can't be deleted while it is locked.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
E_INVALIDARG	The argument psa was not a valid safe array descriptor.
E_UNEXPECTED	The array could not be locked.


SafeArrayPtrOfIndex

HRESULT SafeArrayPtrOfIndex(psa, rgIndices, ppvData)
SAFEARRAY FAR* psa
long FAR* rgIndices
void HUGEP* FAR* ppvData

Returns a pointer to an array element.

Parameters

psa

Pointer to an array descriptor created by SafeArrayCreate.

rgIndices

An array of index values that identify an element of the array. All indexes for the element must be specified.

ppvData

On return, pointer to the element identified by the values in rgIndices.

Comments

The array should be locked before SafeArrayPtrOfIndex is called. Failing to lock the array may cause unpredictable results.


Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
E_INVALIDARG	The argument psa was not a valid safe array descriptor.
DISP_E_BADINDEX	The specified index was invalid.


SafeArrayPutElement

HRESULT SafeArrayPutElement(psa, rgIndices, pvData)
SAFEARRAY FAR* psa
long FAR* rgIndices
void FAR* pvData

Assigns a single element into the array.

Parameters

psa

Pointer to an array descriptor created by SafeArrayCreate.

rgIndices

Pointer to a vector of indexes for each dimension of the array. The rightmost (least significant) dimension is rgIndices[0]. The leftmost dimension is stored at rgIndices[psa->cDims − 1].

pvData

Pointer to the data to assign to the array. VT_DISPATCH, VT_UNKNOWN, and VT_BSTR variant types are pointers and don't require another level of indirection.

Comments

This function automatically calls SafeArrayLock and SafeArrayUnlock before and after assigning the element. If the data element is a string, object, or variant, the function copies it correctly. If the existing element is a string, object or variant, it is cleared correctly.

Note that you can have multiple locks on an array, so you can put elements into an array while the array is locked by other operations.


Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
DISP_E_BADINDEX	The specified index was invalid.
E_INVALIDARG	One of the arguments is invalid.
E_OUTOFMEMORY	Memory could not be allocated for the element.
Example

HRESULT PASCAL __export CPoly::EnumPoints(IEnumVARIANT FAR* FAR* ppenum)

{

unsigned int i;

HRESULT hresult;

VARIANT var;

SAFEARRAY FAR* psa;

CEnumPoint FAR* penum;

POINTLINK FAR* ppointlink;

SAFEARRAYBOUND rgsabound[1];

rgsabound[0].lLbound = 0;

rgsabound[0].cElements = m_cPoints;

psa = SafeArrayCreate(VT_VARIANT, 1, rgsabound);

.

.	// Code omitted here.

.

V_VT(&var) = VT_DISPATCH;

hresult = ppointlink->ppoint->QueryInterface(

IID_IDispatch, (void FAR* FAR*)&V_DISPATCH(&var));

if(hresult != NOERROR)

goto LError1;

ix[0] = i;

SafeArrayPutElement(psa, ix, &var);

ppointlink = ppointlink->next;

}

hresult = CEnumPoint::Create(psa, &penum);

if(hresult != NOERROR)

goto LError1;

*ppenum = penum;

return NOERROR;

LError1:;

SafeArrayDestroy(psa);

LError0:;

return hresult;

}


SafeArrayRedim

HRESULT SafeArrayRedim(psa, psaboundNew)
SAFEARRAY FAR* psa
SAFEARRAYBOUND FAR* psaboundNew

Changes the least significant (rightmost) bound of a safe array.

Parameters

psa

Pointer to an array descriptor.

psaboundNew

Pointer to a new safe array bound structure containing the new array bound. Only the least significant dimension of an array may be changed.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
DISP_E_ARRAYISLOCKED	The array is currently locked.
E_INVALIDARG	The item pointed to by psa is not a safe array descriptor.
Comments

If you reduce the bound of an array, SafeArrayRedim deallocates the array elements outside the new array boundary. If you increase the bound of an array, SafeArrayRedim allocates and initializes the new array elements. The data is preserved for elements that exist in both the old and the new array.


SafeArrayUnaccessData

HRESULT SafeArrayUnaccessData(psa)
SAFEARRAY FAR* psa

Decrements the lock count of an array and invalidates the pointer retrieved by SafeArrayAccessData.

Parameters

psa

Pointer to an array descriptor created by SafeArrayCreate.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
E_INVALIDARG	The argument psa was not a valid safe array descriptor.
E_UNEXPECTED	The array could not be unlocked.


SafeArrayUnlock

HRESULT SafeArrayUnlock(psa)
SAFEARRAY FAR* psa

Decrements the lock count of an array so it can be freed or resized.

Parameters

psa

Pointer to an array descriptor created by SafeArrayCreate.

Comments

This function is called after access to the data in an array is finished.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
E_INVALIDARG	The argument psa was not a valid safe array descriptor.
E_UNEXPECTED	The array could not be unlocked.


String Manipulation Functions

Implemented by	Used by	Header filename	Import library name
OLEAUT32.DLL (32-bit systems) OLE2DISP.DLL (16-bit systems)	Applications that expose or access programmable objects.	OLEAUTO.H DISPATCH.H	OLEAUT32.LIB OLE2DISP.LIB
To handle strings that are allocated by one component and freed by another, OLE Automation defines a special set of functions. These functions use the following data type:

typedef OLECHAR FAR* BSTR;

These strings are zero-terminated, and in most cases they can be treated just like OLECHAR * strings. However, a BSTR can be queried for its length rather than scanned, so it may contain embedded null characters. The length is stored as an integer at the memory location preceding the data in the string. Instead of reading this location directly, applications should use the string manipulation functions to access the length of a BSTR. In situations where you can be sure that a BSTR will not be translated from ANSI to Unicode or vice versa, you can use BSTRs to pass binary data. For example, if your code will run only on 16-bit systems and interact only with other 16-bit systems, you may use BSTRs. However, the preferred method of passing binary data is to use a SAFEARRAY of VT_UI1.

A NULL pointer is a valid value for a BSTR variable; by convention, it is always treated the same as a pointer to a BSTR that contains zero characters. Also, by convention, calls to functions that take a BSTR reference parameter must pass either a NULL pointer or a pointer to an allocated BSTR. If the implementation of a function that takes a BSTR reference parameter assigns a new BSTR to the parameter, it must free the previously referenced BSTR.


SysAllocString

BSTR SysAllocString(sz)
OLECHAR FAR* sz

Allocates a new string and copies the passed string into it. Returns NULL if insufficient memory exists or if NULL is passed in.

Parameter

sz

A zero-terminated string to copy.

Return Value

If successful, points to a BSTR containing the string. If insufficient memory exists or sz was NULL, returns NULL.

Strings created with SysAllocString should be freed with SysFreeString.

Example

inline void CStatBar::SetText(OLECHAR FAR* sz)

{

SysFreeString(m_bstrMsg);

m_bstrMsg = SysAllocString(sz);

}


SysAllocStringByteLen

BSTR SysAllocStringByteLen(psz, len)
char FAR* psz
unsigned int len

Allocates a new string of len bytes, copies len bytes from the passed string into it, and then appends a null character. Valid for 32-bit systems only.

Parameter

psz

A zero-terminated string to copy, or NULL to keep the string uninitialized.

len

Number of bytes to copy from psz. A null character is placed afterwards, making a total of len+1 bytes allocated.

Return Value

Points to a copy of the string or NULL, if insufficient memory exists.

Comments

If psz is NULL, a string of the requested length is allocated, but not initialized. The string psz can contain embedded null characters and need not end with a null. The returned string should later be freed with SysFreeString.


SysAllocStringLen

BSTR SysAllocStringLen(pch, cch)
OLECHAR FAR* pch
unsigned int cch

Allocates a new string, copies cch characters from the passed string into it, and then appends a null character.

Parameter

pch

A pointer to cch characters to copy, or NULL to keep the string uninitialized.

cch

Number of characters to copy from pch*. A null character is placed afterwards, making a total of cch+1 characters allocated.

Return Value

Points to a copy of the string or NULL, if insufficient memory exists.

Comments

If pch is NULL, a string of the requested length is allocated, but not initialized. The string pch can contain embedded null characters and need not end with a null. The returned string should later be freed with SysFreeString.


SysFreeString

void SysFreeString(bstr)
BSTR bstr

Frees a string previously allocated by SysAllocString, SysAllocStringByteLen, SysReAllocString, SysAllocStringLen, or SysReAllocStringLen.

Parameter

bstr

A BSTR allocated earlier or NULL. If NULL, the function simply returns.

Return Value

None.

Example

CStatBar::~CStatBar()

{

SysFreeString(m_bstrMsg);

}


SysReAllocString

BOOL SysReAllocString(pbstr, sz)
BSTR FAR* pbstr
OLECHAR FAR* sz

Allocates a new BSTR and copies the passed string into it, then frees the BSTR currently referenced by pbstr and resets pbstr to point to the new BSTR. Returns False if insufficient memory exists.

Parameter

pbstr

Points to a variable containing a BSTR.

sz

A zero-terminated string to copy.

Return Value

Returns False if insufficient memory exists.


SysReAllocStringLen

BOOL SysReAllocStringLen(pbstr, pch, cch)
BSTR FAR* pbstr
OLECHAR FAR* pch
unsigned int cch

Creates a new BSTR containing a specified number of characters from an old BSTR and frees the old BSTR.

Parameter

pbstr

Pointer to a variable containing a BSTR.

pch

Pointer to cch characters to copy, or NULL to keep the string uninitialized.

cch

Number of characters to copy from pch*. A null character is placed afterwards, making a total of cch+1 characters allocated.

Return Value

Returns True if the string is successfully reallocated, or False if insufficient memory exists.

Comments

Allocates a new string, copies cch characters from the passed string into it, and then appends a null character. Frees the BSTR currently referenced by pbstr and resets pbstr to point to the new BSTR. If pch is NULL, a string of length cch is allocated, but not initialized.

The string pch can contain embedded null characters and need not end with a null.


SysStringByteLen

unsigned int SysStringByteLen(bstr)
BSTR bstr

Returns the length in bytes of a BSTR. Valid for 32-bit systems only.

Parameter

bstr

A BSTR previously allocated. It cannot be NULL.

Return Value

The number of bytes in bstr, not including a terminating null character.

Comments

The value returned may be different from fstrlen(bstr), if the BSTR was allocated with Sys[Re]AllocStringLen or SysAllocStringByteLen, and the passed-in characters included a null character in the first len characters. For a BSTR allocated with Sys[Re]AllocStringLen or SysAllocStringByteLen, this function always returns the number of bytes specified in the len parameter at allocation time.

Example

// Draw the status message

//

TextOut(

hdc,

rcMsg.left + (m_dxFont / 2),

rcMsg.top + ((rcMsg.bottom - rcMsg.top - m_dyFont) / 2),

m_bstrMsg, SysStringByteLen(m_bstrMsg));


SysStringLen

unsigned int SysStringLen(bstr)
BSTR bstr

Returns the length of a BSTR.

Parameter

bstr

A BSTR previously allocated; can't be NULL.

Return Value

The number of characters in bstr, not including a terminating null character.


Comments

The value returned may be different from _fstrlen(bstr), if the BSTR was allocated with Sys[Re]AllocStringLen or SysAllocStringByteLen, and the passed-in characters included a null character in the first cch characters. For a BSTR allocated with Sys[Re]AllocStringLen or SysAllocStringByteLen, this function always returns the number of characters specified in the cch parameter at allocation time.

Example

// Draw the status message

//

TextOut(

hdc,

rcMsg.left + (m_dxFont / 2),

rcMsg.top + ((rcMsg.bottom - rcMsg.top - m_dyFont) / 2),

m_bstrMsg, SysStringLen(m_bstrMsg));


Variant Manipulation Functions

Implemented by	Used by	Header filename	Import library name
OLEAUT32.DLL (32-bit systems) OLE2DISP.DLL (16-bit systems)	Applications that expose or access programmable objects.	OLEAUTO.H DISPATCH.H	OLEAUT32.LIB OLE2DISP.LIB
These functions are provided to allow applications to manipulate VARIANTARG variables. Applications that implement IDispatch should test each VARIANTARG for all permitted types by attempting to coerce the variant to each type (using VariantChangeType or VariantChangeTypeEx). If objects are allowed, the application should always test for object types before other types. If an object type is expected, the application must test (via IUnknown::QueryInterface) whether the object is of the type desired.

Although applications can access and interpret the VARIANTARGs without these functions, using them ensures uniform conversion and coercion rules for all implementors of IDispatch. (For example, these functions automatically coerce numeric arguments to strings and vice versa, when necessary.)

Because variants can contain strings, references to scalars and objects, and arrays, certain data ownership rules must be obeyed. All the variant manipulation functions conform to the following rules:

1.	All VARIANTARGs must be initialized by VariantInit before use.

2.	For the types VT_UI1, VT_I2, VT_I4, VT_R4, VT_R8, VT_BOOL, VT_ERROR, VT_CY, VT_DATE, data is stored within the VARIANT structure. Any pointers to the data become invalid when the type of the variant is changed.

3.	For VT_BYREF | any type, the memory pointed to by the variant is owned and freed by the caller of the function.

4.	For VT_BSTR, there is only one owner for the string. All strings in variants must be allocated with the SysAllocString function. When releasing or changing the type of a variant with the VT_BSTR type, SysFreeString is called on the contained string.

5.	For VT_ARRAY | any type, the rule is analogous to the rule for VT_BSTR. All arrays in variants must be allocated with SafeArrayCreate. When releasing or changing the type of a variant with the VT_ARRAY flag set, SafeArrayDestroy is called.

6.	For VT_DISPATCH and VT_UNKNOWN, the pointed-to objects have reference counts that are incremented when they are placed in a variant. When releasing or changing the type of the variant, Release is called on the pointed-to object.


VariantChangeType

HRESULT VariantChangeType(pvargDest, pvargSrc, wFlags, vtNew)
VARIANTARG FAR* pvargDest
VARIANTARG FAR* pvargSrc
unsigned short wFlags
VARTYPE vtNew

This function converts a variant from one type to another.

Parameters

pvargDest

Pointer to the VARIANTARG to receive the coerced type. If this is the same as pvargSrc, the variant will be converted in place.

pvargSrc

Pointer to the source VARIANTARG to be coerced.

wFlags

Flags that control the coercion. The only defined flag is VARIANT_NOVALUEPROP, which prevents the function from attempting to coerce an object to a fundamental type by getting the Value property. Applications should set this flag only if necessary, because it makes their behavior inconsistent with other applications.

vtNew

The type to coerce to. If the return code is S_OK, the vt field of the *pvargDest will always be the same as this value.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
DISP_E_BADVARTYPE	The variant type vtNew is not a valid type of variant.
DISP_E_OVERFLOW	The data pointed to by pvargSrc does not fit in the destination type.
DISP_E_TYPEMISMATCH	The argument could not be coerced to the specified type.
E_INVALIDARG	One of the arguments is invalid.
E_OUTOFMEMORY	Memory could not be allocated for the conversion.
Comments

The VariantChangeType function handles coercions between the fundamental types (including numeric-to-string and string-to-numeric coercions). A variant that has VT_BYREF set is coerced to a value by fetching the referenced value. An object is coerced to a value by invoking the object's Value property (DISPID_VALUE).

Typically, the implementor of IDispatch::Invoke determines which member is being accessed, then calls VariantChangeType to get the value of one or more arguments. For example, if the IDispatch call specifies a SetTitle member that takes one string argument, the implementor would call VariantChangeType to attempt to coerce the argument to VT_BSTR. If VariantChangeType did not return an error, the argument could then be fetched directly from the bstrVal field of the VARIANTARG. If VariantChangeType returned DISP_E_TYPEMISMATCH, the implementor would set *puArgErr to 0 (indicating the argument in error) and return DISP_E_TYPEMISMATCH from IDispatch::Invoke.

Note that you should not attempt to change the type of a VARIANTARG in the rgvarg array in place.

Arrays of one type can't be converted to arrays of another type with this function.

See Also

VariantChangeTypeEx


VariantChangeTypeEx

HRESULT VariantChangeTypeEx(pvargDest, pvargSrc, lcid, wFlags, vtNew)
VARIANTARG FAR* pvargDest
VARIANTARG FAR* pvargSrc
LCID lcid
unsigned short wFlags
VARTYPE vtNew

This function converts a variant from one type to another using a locale ID.

Parameters

pvargDest

Pointer to the VARIANTARG to receive the coerced type. If this is the same as pvargSrc, the variant will be converted in place.

pvargSrc

Pointer to the source VARIANTARG to be coerced.

lcid

The locale ID for the variant to coerce. The locale ID is useful when the type of the source or destination VARIANTARG is VT_BSTR, VT_DISPATCH, or VT_DATE.

wFlags

Flags that control the coercion. The only defined flag is VARIANT_NOVALUEPROP, which prevents the function from attempting to coerce an object to a fundamental type by getting its Value property. Applications should set this flag only if necessary, because it makes their behavior inconsistent with other applications.

vtNew

The type to coerce to. If the return code is S_OK, the vt field of the *pvargDest is guaranteed to be equal to this value.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
DISP_E_BADVARTYPE	The variant type vtNew is not a valid type of variant.
DISP_E_OVERFLOW	The data pointed to by pvargSrc does not fit in the destination type.
DISP_E_TYPEMISMATCH	The argument could not be coerced to the specified type.
E_INVALIDARG	One of the arguments is invalid.
E_OUTOFMEMORY	Memory could not be allocated for the conversion.
Comments

The VariantChangeTypeEx function handles coercions between the fundamental types (including numeric to string and string to numeric coercions). To change a type with the VT_BYREF flag set to one without VT_BYREF set, VariantChangeTypeEx fetches the referenced value. Objects are coerced to fundamental types by fetching the value of the Value property.

Typically, the implementor of IDispatch::Invoke determines which member is being accessed, then calls VariantChangeType to get the value of one or more arguments. For example, if the IDispatch call specifies a SetTitle member that takes one string argument, the implementor would call VariantChangeTypeEx to attempt to coerce the argument to VT_BSTR. If VariantChangeTypeEx did not return an error, the argument could then be fetched directly from the bstrVal field of the VARIANTARG. If VariantChangeTypeEx returned DISP_E_TYPEMISMATCH, the implementor would set *puArgErr to 0 (indicating the argument in error) and return DISP_E_TYPEMISMATCH from IDispatch::Invoke.

Note that you should not attempt to change the type of a VARIANTARG in the rgvarg array in place.

Arrays of one type can't be converted to arrays of another type with this function.

See Also

VariantChangeType


VariantClear

HRESULT VariantClear(pvarg)
VARIANTARG FAR* pvarg

Clears a variant.

Parameter

pvarg

Pointer to the VARIANTARG to clear.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
DISP_E_ARRAYISLOCKED	The variant contains an array that is locked.
DISP_E_BADVARTYPE	The variant type pvarg is not a valid type of variant.
E_INVALIDARG	One of the arguments is invalid.
Comments

This function should be used to clear variables of type VARIANTARG (or VARIANT) before the memory containing the VARIANTARG is freed (as when a local variable goes out of scope).

The function clears a VARIANTARG by setting the vt field to VT_EMPTY and the wReserved field to 0. The current contents of the VARIANTARG are released first. If the vt field is VT_BSTR, the string is freed; if the vt field is VT_DISPATCH, the object is released. If the vt field has the VT_ARRAY bit set, the array is freed.

In certain cases, you may prefer to clear a variant in your own code, without calling VariantClear. For example, it is permissible to change the type of a VT_I4 variant to some other type without calling this function. However, you must call VariantClear if you receive a VT_type that you are not prepared to handle. Using VariantClear in these cases ensures that your code will continue to work if OLE Automation adds new variant types in the future.

Example

for(i = 0; i < celt; ++i)

VariantClear(&rgvar[i]);


VariantCopy

HRESULT VariantCopy(pvargDest, pvargSrc)
VARIANTARG FAR* pvargDest
VARIANTARG FAR* pvargSrc

Frees the destination variant and makes a copy of the source variant.

Parameters

pvargDest

Pointer to the VARIANTARG to receive the copy.

pvargSrc

Pointer to the VARIANTARG to be copied.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
DISP_E_ARRAYISLOCKED	The variant contains an array that is locked.
DISP_E_BADVARTYPE	The source and destination have an invalid variant type (usually uninitialized).
E_OUTOFMEMORY	Memory could not be allocated for the copy.
E_INVALIDARG	The argument pvargSrc was VT_BYREF.
Comments

First, any memory owned by pvargDest is freed as in VariantClear (note that pvargDest must point to a valid initialized variant, and not simply an uninitialized memory location). Then, pvargDest receives an exact copy of the contents of pvargSrc. If pvargSrc is a VT_BSTR, a copy of the string is made. If pvargSrc is a VT_ARRAY, the entire array is copied. If pvargSrc is a VT_DISPATCH or VT_UNKNOWN, AddRef is called to increment the object's reference count.


VariantCopyInd

HRESULT VariantCopyInd(pvarDest, pvargSrc)
VARIANT FAR* pvarDest
VARIANTARG FAR* pvargSrc

Frees the destination variant and makes a copy of the source VARIANTARG, performing the necessary indirection if the source is specified to be VT_BYREF.

Parameters

pvarDest

Pointer to the VARIANTARG to receive the copy.

pvargSrc

Pointer to the VARIANTARG to be copied.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
DISP_E_ARRAYISLOCKED	The variant contains an array that is locked.
DISP_E_BADVARTYPE	The source and destination have an invalid variant type (usually uninitialized).
E_OUTOFMEMORY	Memory could not be allocated for the copy.
E_INVALIDARG	The argument pvargSrc was VT_ARRAY.
Comments

This function is useful when you need to make a copy of a variant and guarantee that it is not VT_BYREF, such as when handling arguments in an implementation of IDispatch::Invoke.

For example, if the source is a (VT_BYREF | VT_I2), the destination will be a ByVal VT_I2. The same is true for all legal VT_BYREF combinations including VT_VARIANT.

If pvargSrc is (VT_BYREF | VT_VARIANT) and the contained variant is also VT_BYREF, the contained variant is also dereferenced.

This function frees any existing contents of pvarDest.


VariantInit

void VariantInit(pvarg)
VARIANTARG FAR* pvarg

Initializes a variant.

Parameter

pvarg

Pointer to the VARIANTARG to initialize.

Comments

The VariantInit function initializes the VARIANTARG by setting the vt field to VT_EMPTY and the wReserved field to 0. Unlike VariantClear, this function does not interpret the current contents of the VARIANTARG. VariantInit should be used to initialize new local variables of type VARIANTARG (or VARIANT).

Example

for(i = 0; i < celt; ++i)

VariantInit(&rgvar[i]);


Low-Level Variant Conversion Functions

The following low-level functions for converting variant data types are provided by OLEAUT32.DLL (for 32-bit systems) and OLE2DISP.DLL (for 16-bit systems). These functions are used by the higher-level variant manipulation functions, such as VariantChangeType, but may be called directly as well.

Convert to type	From type	Function
unsigned char	unsigned char	None
	short	VarUI1FromI2(sIn, pbOut)
	long	VarUI1FromI4(lIn, pbOut)
	float	VarUI1FromR4(fltIn, pbOut)
	double	VarUI1FromR8(dblIn, pbOut)
	CURRENCY	VarUI1FromCy(cyIn, pbOut)
	DATE	VarUI1FromDate(dateIn, pbOut)
	OLECHAR FAR*	VarUI1FromStr(strIn, lcid, dwFlags, pbOut)
	IDispatch FAR*	VarUI1FromDisp(pdispIn, lcid, dwFlags, pbOut)
	BOOL	VarUI1FromBool(boolIn, pbOut)
short	unsigned char	VarI2FromUI1(bIn, psOut)
	short	None
	long	VarI2FromI4(lIn, psOut)
	float	VarI2FromR4(fltIn, psOut)
	double	VarI2FromR8(dblIn, psOut)
	CURRENCY	VarI2FromCy(cyIn, psOut)
	DATE	VarI2FromDate(dateIn, psOut)
	OLECHAR FAR*	VarI2FromStr(strIn, lcid, dwFlags, psOut)
	IDispatch FAR*	VarI2FromDisp(pdispIn, lcid, dwFlags, psOut)
	BOOL	VarI2FromBool(boolIn, psOut)
long	unsigned char	VarI4FromUI1(bIn, plOut)
	short	VarI4FromI2(sIn, plOut)
	long	None
	float	VarI4FromR4(fltIn, plOut)
	double	VarI4FromR8(dblIn, plOut)
	CURRENCY	VarI4FromCy(cyIn, plOut)
	DATE	VarI4FromDate(dateIn, plOut)
	OLECHAR FAR*	VarI4FromStr(strIn, lcid, dwFlags, plOut)
	IDispatch FAR*	VarI4FromDisp(pdispIn, lcid, dwFlags, plOut)
	BOOL	VarI4FromBool(boolIn, plOut)
float	unsigned char	VarR4FromUI1(bIn, prOut)
	short	VarR4FromI2(sIn, prOut)
	long	VarR4FromI4(lIn, prOut)
	float	None
	double	VarR4FromR8(dblIn, prOut)
	CURRENCY	VarR4FromCy(cyIn, prOut)
	DATE	VarR4FromDate(dateIn, prOut)
	OLECHAR FAR*	VarR4FromStr(strIn, lcid, dwFlags, prOut)
	IDispatch FAR*	VarR4FromDisp(pdispIn, lcid, dwFlags, prOut)
	BOOL	VarR4FromBool(boolIn, prOut)
double	unsigned char	VarR8FromUI1(bIn, pdblOut)
	short	VarR8FromI2(sIn, pdblOut)
	long	VarR8FromI4(lIn, pdblOut)
	float	VarR8FromR4(fltIn, pdblOut)
	double	None
	CURRENCY	VarR8FromCy(cyIn, pdblOut)
	DATE	VarR8FromDate(dateIn, pdblOut)
	OLECHAR FAR*	VarR8FromStr(strIn, lcid, dwFlags, pdblOut)
	IDispatch FAR*	VarR8FromDisp(pdispIn, lcid, dwFlags, pdblOut)
	BOOL	VarR8FromBool(boolIn, pdblOut)
DATE	unsigned char	VarDateFromUI1(bIn, pdateOut)
	short	VarDateFromI2(sIn, pdateOut)
	long	VarDateFromI4(lIn, pdateOut)
	float	VarDateFromR4(fltIn, pdateOut)
	double	VarDateFromR8(dblIn, pdateOut)
	CURRENCY	VarDateFromCy(cyIn, pdateOut)
	DATE	None
	OLECHAR FAR*	VarDateFromStr(strIn, lcid, dwFlags, pdateOut)
	IDispatch FAR*	VarDateFromDisp(pdispIn, lcid, dwFlags, pdateOut)
	BOOL	VarDateFromBool(boolIn, pdateOut)
CURRENCY	unsigned char	VarCyFromUI1(bIn, pcyOut)
	short	VarCyFromI2(sIn, pcyOut)
	long	VarCyFromI4(lIn, pcyOut)
	float	VarCyFromR4(fltIn, pcyOut)
	double	VarCyFromR8(dblIn, pcyOut)
	CURRENCY	None
	DATE	VarCyFromDate(dateIn, pcyOut)
	OLECHAR FAR*	VarCyFromStr(strIn, lcid, dwFlags, pcyOut)
	IDispatch FAR*	VarCyFromDisp(pdispIn, lcid, dwFlags, pcyOut)
	BOOL	VarCyFromBool(boolIn, pcyOut)
BSTR	unsigned char	VarBstrFromUI1(bIn, lcid, dwFlags, pbstrOut)
	short	VarBstrFromI2(sIn, lcid, dwFlags, pbstrOut)
	long	VarBstrFromI4(lIn, lcid, dwFlags, pbstrOut)
	float	VarBstrFromR4(fltIn, lcid, dwFlags, pbstrOut)
	double	VarBstrFromR8(dblIn, lcid, dwFlags, pbstrOut)
	CURRENCY	VarBstrFromCy(cyIn, lcid, dwFlags, pbstrOut)
	DATE	VarBstrFromDate(dateIn, lcid, dwFlags, pbstrOut)
	OLECHAR FAR*	None
	IDispatch FAR*	VarBstrFromDisp(pdispIn, lcid, dwFlags, pbstrOut)
	BOOL	VarBstrFromBool(boolIn, lcid, dwFlags, pbstrOut)
BOOL	unsigned char	VarBoolFromUI1(bIn, pboolOut)
	short	VarBoolFromI2(sIn, pboolOut)
	long	VarBoolFromI4(lIn, pboolOut)
	float	VarBoolFromR4(fltIn, pboolOut)
	double	VarBoolFromR8(dblIn, pboolOut)
	CURRENCY	VarBoolFromCy(cyIn, pboolOut)
	DATE	VarBoolFromDate(dateIn, pboolOut)
	OLECHAR FAR*	VarBoolFromStr(strIn, lcid, dwFlags, pboolOut)
	IDispatch FAR*	VarBoolFromDisp(pdispIn, lcid, dwFlags, pboolOut)
	BOOL	None


Parameters

bIn, sIn, lIn, fltIn, dblIn, cyIn, dateIn, strIn, pdispIn, boolIn

The value to coerce. These parameters have following data types:

Parameter	Data type
bIn	unsigned char
sIn	short
lIn	long
fltIn	float
dblIn	double
cyIn	CURRENCY
dateIn	DATE
strIn	OLECHAR FAR*
pdispIn	IDispatch FAR*
boolIn	BOOL
lcid

For conversions from string and VT_DISPATCH input, the locale ID to use for the conversion. For a list of locale IDs, see "Supporting Multiple National Languages" in Chapter 2.

dwFlags

One or more of the following flags:

Flag	Description
LOCALE_NOUSEROVERRIDE	Use the system default locale settings, rather than custom user locale settings.
VAR_TIMEVALUEONLY	Omit the date portion of a VT_DATE and return the time only. Applies to conversions to or from dates.
VAR_DATEVALUEONLY	Omit the time portion of a VT_DATE and return the time only. Applies to conversions to or from dates.
pbOut, psOut, plOut, pfltOut, pdblOut, pcyOut, pstrOut, pdispOut, pboolOut

A pointer to the coerced value. These parameters have following data types:

Parameter	Data type
pbOut	unsigned char
psOut	short
plOut	long
pfltOut	float
pdblOut	double
pcyOut	CURRENCY
pdateOut	DATE
pstrOut	OLECHAR FAR*
pdispOut	IDispatch FAR*
pboolOut	BOOL
Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
DISP_E_BADVARTYPE	The input parameter is not a valid type of variant.
DISP_E_OVERFLOW	The data pointed to by the output parameter does not fit in the destination type.
DISP_E_TYPEMISMATCH	The argument could not be coerced to the specified type.
E_INVALIDARG	One of the arguments is invalid.
E_OUTOFMEMORY	Memory could not be allocated for the conversion.


Date and Time Conversion Functions

The following functions to convert between dates and times stored in MS-DOS format and the variant representation are provided by OLEAUT32.DLL (for 32-bit systems) and OLE2DISP.DLL (for 16-bit systems).


DosDateTimeToVariantTime

int DosDateTimeToVariantTime(wDOSDate, wDOSTime, pvtime)
unsigned short wDOSDate
unsigned short wDOSTime
double FAR* pvtime

Converts the MS-DOS representation of time to the date and time representation stored in variant.

Parameters

wDOSDate

The MS-DOS date to convert.

wDOSTime

The MS-DOS time to convert.

pvtime

Pointer to the location to store the converted time.

Return Value

One of the following:

Result	Meaning
True	Success
False	Failure
Comments

MS-DOS records file dates and times as packed 16-bit values. An MS-DOS date has the following format:

Bits	Contents
0-4	Day of the month (1−31)
5-8	Month (1 = January, 2 = February, and so on)
9-15	Year offset from 1980 (add 1980 to get actual year)
An MS-DOS time has the following format:

Bits	Contents
0-4	Second divided by 2
5-10	Minute (0−59)
11-15	Hour (0−23 on a 24-hour clock)


VariantTimeToDosDateTime

int VariantTimeToDosDateTime(vtime, pwDOSDate, pwDOSTime)
double vtime
unsigned short FAR* pwDOSDate
unsigned short FAR* pwDOSTime

Converts the variant representation of a date and time to MS-DOS date and time values.

Parameters

vtime

The variant time to convert.

pwDOSDate

Pointer to location to store the converted MS-DOS date.

pwDOSTime

Pointer to location to store the converted MS-DOS time.

Return Value

One of the following:

Result	Meaning
True	Success
False	Failure
Comments

A variant time is stored as an 8-byte real value (double), representing a date between January 1, 1753 and December 31, 2078, inclusive. The value 2.0 represents January 1, 1900; 3.0 represents January 2, 1900, and so on. Adding 1 to the value increments the date by a day. The fractional part of the value represents the time of day. Thus, 2.5 represents noon on January 1, 1900; 3.25 is 6:00 a.m. on January 2, 1900; and so on. Negative numbers represent the dates prior to December 30, 1899.

See the Comments section of "DosDateTimeToVariantTime" for a description of the MS-DOS date and time formats.


MkTypLib and Object Description Language

When you expose OLE Automation objects, you permit interoperability with other vendors' programs. For others to use your objects, they must have access to the objects' characteristics (properties and methods). To make this information public, you can:

•	Publish object and type definitions (for example, as printed documentation).

•	Code objects into a compiled .C or .CPP file, so they can be accessed using IDispatch::GetTypeInfo or implementations of the ITypeInfo and ITypeLib interfaces.

•	Use the MkTypLib tool to create a type library that contains the objects, then make the type library available to others.

MkTypLib compiles scripts that are written in the Object Description Language (ODL). This chapter provides a reference to the MkTypLib tool and ODL.


Contents of a Type Library

Type libraries are OLE compound document files that include information about types and objects exposed by an OLE application. A type library may contain any of the following:

•	Information about data types, such as aliases, enumerations, structures, or unions.

•	Descriptions of one or more objects, such as a module, interface, IDispatch interface (dispinterface), or component object class (coclass). Each of these descriptions is commonly referred to as a typeinfo.

•	References to type descriptions from other type libraries.

Including the type library with your product makes information about the objects it contains available to your customers' applications and programming tools. You can ship type libraries in any of the following forms:

•	A resource in a dynamic-link library (DLL). This resource should have the type typelib and an integer ID. It must be declared in the resource (.RC) file as follows:

1 typelib mylib1.tlb

2 typelib mylib2.tlb

There can be multiple type library resources in a DLL. Application developers use the resource compiler to add the .TLB file to their own DLL. A DLL with one or more type library resources typically has the extension .OLB (object library).

•	A resource in an .EXE file. The file may contain multiple type libraries.

•	A stand-alone binary file. The .TLB file output by MkTypLib is a binary file.

Object browsers, compilers, and similar tools access type libraries through the ITypeLib, ITypeInfo, and ITypeComp interfaces. Type library tools (such as MkTypLib) can be created using the ICreateTypeLib and ICreateTypeInfo interfaces.


MkTypLib: Type Library Creation Tool

MkTypLib processes scripts written in the Object Description Language (ODL), producing a type library (.TLB) and an optional C or C++ style header file.

MkTypLib uses the ICreateTypeLib and ICreateTypeInfo interfaces to create type libraries. Type libraries can, in turn, be accessed by tools such as type browsers and compilers that use the ITypeLib and ITypeInfo interfaces, as shown in the following figure.


Invoking MkTypLib

To invoke MkTypLib, choose the Run command from either the Program Manager or the File Manager File menu, then enter the following command line in the dialog box:

MkTypLib [options] ODLfile

MkTypLib creates a type library (.TLB) file based on the object description script in the file specified by ODLfile. It can optionally produce a header file (extension .H), which is a stripped version of the input file suitable for inclusion in C or C++ programs that want to access the types defined in the input file. In the header file, MkTypLib inserts DEFINE_GUID macros for each element (interface, dispinterface, and so forth) defined in the type library.

The options can be a series of options prefixed with a hyphen (-) or a slash (/) as follows:

Option	Description
/? or /help	Displays command line Help. The ODLfile does not need to be specified in this case.
/align:alignment	Sets the default alignment for types in the library. An alignment value of 1 indicates natural alignment; n indicates alignment on byte n.
/cpp_cmd cpppath	Specifies cpppath as the command to run the C preprocessor. By default, MkTypLib invokes CL.
/cpp_opt "options"	Specifies options for the C preprocessor. Default is "/C /E /D__MKTYPLIB__."
/D define[=value]	Defines the name define for the C preprocessor. The value is its optional value. No space is allowed between the equal sign (=) and the value.
/h filename	Specifies filename as the name for a stripped version of the input file. This file can be used as a C or C++ header file.
/I includedir	Specifies includedir as the directory where include files are located for the C preprocessor.
/nocpp	Suppresses invocation of the C preprocessor.
/nologo	Disables display of the copyright banner.
/o outputfile	Redirects output (for example, error messages) to specified outputfile.
/tlb filename	Specifies filename as the name of the output .TLB file. If not specified, this is the same as the name of the ODLfile with the extension .TLB.
/win16 /win32 /mac /mips /alpha  /ppc /ppc32	Specifies type of output type library to produce. Default is the current operating system.
/w0	Disables warnings.
Although MkTypLib offers minimal error reporting, error messages include accurate line and column number information that can be used with text editors to locate the source of errors.

MkTypLib spawns the C preprocessor. The symbol __MKTYPLIB__ is predefined for the preprocessor.


ODL File Syntax

The general syntax for an ODL file is as follows:

[attributes] library libname {definitions};

The attributes associate characteristics with the library, such as its Help file and UUID. Attributes must be enclosed in square brackets.

The definitions consist of the descriptions of the imported libraries, data types, modules, interfaces, dispinterfaces, and coclasses that are part of the type library. Braces ({}) must surround the definitions.

The following table summarizes the elements that may appear in definitions. Each element is described in detail in the section, "ODL Reference."

Purpose	Library element	Description
Allows references to other type libraries.	importlib (lib1)	Specifies an external type library that contains definitions referenced in this type library.
Declares data types used by the objects in this type library.	typedef [attributes] aliasname	An alias declared using C syntax. Must have at least one attribute to be included in the type library.
	typedef [attributes] enum	An enumeration declared using C typedef and enum keywords.
	typedef [attributes] struct	A structure declared using C typedef and struct keywords.
	typedef [attributes] union	A union declared using C typedef and union keywords.
Describes functions that enable querying the DLL.	[attributes] module	Constants and general data functions whose actions are not restricted to any specified class of objects.
Describes interfaces.	[attributes] dispinterface	An interface describing the methods and properties for an object that must be accessed through IDispatch::Invoke.
	[attributes] interface	An interface describing the methods and properties for an object that may be accessed through IDispatch::Invoke or through VTBL entries.
Describes OLE classes.	[attributes] coclass	Specifies a top-level object, with all its interfaces and dispinterfaces.
Within the library description, modules, interfaces, dispinterfaces, and coclasses follow the same general syntax:

[attributes] elementname typename {
memberdescriptions
};

The attributes set characteristics for the element. The elementname is a keyword that indicates the kind of item (module, interface, dispinterface, or coclass), and the typename defines the name of the item. The memberdescriptions define the members (constants, functions, properties, and methods) of each element.

Aliases, enumerations, unions, and structures have the following syntax:

typedef [typeattributes] typekind typename {
memberdescriptions
};

For these types, the attributes follow the typedef keyword, and the typekind indicates the data type (enum, union, or struct). See the keyword descriptions for details.

Note  The square brackets ([])and braces ({}) in these descriptions are part of the syntax, not descriptive symbols. The semicolon after the closing brace (}) that terminates the library definition (and all other type definitions) is optional.


ODL File Example

The following example shows the ODL file for the Lines sample, extracted from LINES.ODL:

[

uuid(3C591B20-1F13-101B-B826-00DD01103DE1),	// LIBID_Lines

helpstring("Lines 1.0 Type Library"),

lcid(0x0409),

version(1.0)

]

library Lines

{

importlib("stdole.tlb");

#define DISPID_NEWENUM -4

[

uuid(3C591B25-1F13-101B-B826-00DD01103DE1),  // IID_IPoint

helpstring("Point object."),

oleautomation,

dual

]

interface IPoint : IDispatch

{

[propget, helpstring("Returns and sets x coordinate.")]

HRESULT x([out, retval] int* retval);

[propput, helpstring("Returns and sets x coordinate.")]

HRESULT x([in] int Value);

[propget, helpstring("Returns and sets y coordinate.")]

HRESULT y([out, retval] int* retval);

[propput, helpstring("Returns and sets y coordinate.")]

HRESULT y([in] int Value);

}

// Additional interfaces omitted for brevity

[

uuid(3C591B27-1F13-101B-B826-00DD01103DE1),	// IID_IPoints

helpstring("Points collection."),

oleautomation,

dual

]

interface IPoints : IDispatch

{

[propget, helpstring("Returns number of points in collection.")]

HRESULT Count([out, retval] long* retval);

[propget, id(0),

helpstring("Given an index, returns a point in the collection")]

HRESULT Item([in] long Index, [out, retval] IPoint** retval);

[propget, restricted, id(DISPID_NEWENUM)]	// Must be propget.

HRESULT _NewEnum([out, retval] IUnknown** retval);

}

// Additional interface omitted for brevity

[

uuid(3C591B22-1F13-101B-B826-00DD01103DE1),	// IID_IApplication

helpstring("Application object."),

oleautomation,

dual

]

interface IApplication : IDispatch

{

[propget, helpstring("Returns the application of the object.")]

HRESULT Application(	[out, retval] IApplication** retval);

[propget,

helpstring("Returns the full name of the application.")]

HRESULT FullName([out, retval] BSTR* retval);

[propget, id(0),

helpstring("Returns the name of the application.")]

HRESULT Name([out, retval] BSTR* retval);

[propget, helpstring("Returns the parent of the object.")]

HRESULT Parent([out, retval] IApplication** retval);

[propput]

HRESULT Visible([in] boolean VisibleFlag);

[propget, helpstring

("Sets or returns whether the main window is visible.")]

HRESULT Visible(	[out, retval] boolean* retval);

[helpstring("Exits the application.")]

HRESULT Quit();

// Additional methods omitted for brevity

[helpstring("Creates new Point object initialized to (0,0).")]

HRESULT CreatePoint(	[out, retval] IPoint** retval);

}

[

uuid(3C591B21-1F13-101B-B826-00DD01103DE1),	// CLSID_Lines

helpstring("Lines Class"),

appobject

]

coclass Lines

{

[default] interface IApplication;

interface IDispatch;

}

}

The example describes a library named Lines, which imports the standard OLE library STDOLE.TLB. The #define directive defines the constant DISPID_NEWENUM, which is needed for the _NewEnum property of the IPoints collection.

The example shows declarations for three interfaces in the library: IPoint, IPoints, and IApplication. Because all three are dual interfaces, their members may be invoked through IDispatch or directly through VTBLs. In addition, all their members return HRESULT values and pass their return values as retval parameters. Therefore, they can support the IErrorInfo interface, through which they can return detailed error information, no matter how they are invoked.

The IPoint interface has two properties, x and y, and two pairs of accessor functions to get and set the properties.

The IPoints interface is a collection of points. It supports three read-only properties, each of which has a single accessor function. The Count and Item properties return the number of points and the value of a single point, respectively. The _NewEnum property, required for collection objects, returns an enumerator object for the collection. This property has the restricted attribute, indicating that it should not be invoked from a macro language.

The IApplication interface describes the application object. It supports properties named Application, FullName, Name, Parent, Visible, and Pane; and methods named Quit, CreateLine, and CreatePoint.

Finally, the script defines a coclass named Lines. The appobject attribute makes the members of the coclass (IApplication and IDispatch) globally accessible in the type library. IApplication is defined as the default member, indicating that it is the programmability interface intended for use by macro languages.


Source File Contents

The following sections describe the proper format for comments, constants, identifiers, and other syntactic items within an ODL file.


Array Definitions

MkTypLib accepts both fixed-size arrays and arrays declared as SAFEARRAY.

Use C-style syntax for a fixed-size array:

type arrname[size];

To describe a SAFEARRAY, use the following syntax:

SAFEARRAY (elementtype) *arrayname

A function returning a SAFEARRAY has the following syntax:

SAFEARRAY (elementtype) myfunction(parameterlist);


Comments

To include comments in an ODL file, use C-style syntax in either block form (/*...*/) or single-line form (\\). MkTypLib ignores the comments, and does not preserve them in the header (.H) file.


Constants

A constant can be either numeric or a string, depending on the attribute.

Numerics

Numeric input is usually an integer (in either decimal or in hexadecimal using the standard 0x format), but may also be a single character constant (for example, \0).

Strings

A string is delimited by double-quotation marks (") and may not span multiple lines. The backslash character (\) acts as an escape character. The backslash character followed by any character (even another backslash) prevents the second character from being interpreted with any special meaning; the backslash is not included in the text.

For example, to include a double-quotation mark (") in the text without causing it to be interpreted as the closing delimiter, precede it with a backslash (\"). Similarly, you can use a double backslash (\\) to put a backslash into the text. Some examples of valid strings are:

"commandName"
"This string contains a \"quote\"."

"Here's a pathname: c:\\bin\\binp"

A string can be up to 255 characters long.


Filenames

A filename is a string that represents either a full or partial path. OLE Automation expects to find files in directories referenced by the type library registration entries, so partial pathnames are typically used. See Chapter 2, "Exposing OLE Automation Objects," for more information about registration.


Forward Declarations

Forward declarations permit forward references to types. Forward references have the following form:

typedef struct mydata;

interface aninterface;

dispinterface fordispatch;

coclass pococlass;


The Globally Unique ID (GUID)

A UUID is a globally unique ID (GUID). This number is created by running the GUIDGEN.EXE command-line program. GUIDGEN will never produce the same number twice, no matter how many times it is run or how many different machines it runs on. Every entity (such as an interface) that needs to be uniquely identified has a GUID.


Identifiers

Identifiers can be up to 255 characters long, and must conform to C-style syntax. MkTypLib is case sensitive, but it generates type libraries that are case insensitive. Thus, it is possible to define a user-defined type whose name differs from that of a built-in type only by case. However, user-defined type names (and member names) that differ only in case refer to the same type or member. Except for property accessor functions, it is illegal for two members of a type to have the same name, regardless of case.


Intrinsic Data Types

The following data types are recognized by MkTypLib:

Type	Description
boolean	Data item that can have the values True or False. The size maps to VARIANT_BOOL.
char	8-bit signed data item.
double	64-bit IEEE floating-point number.
int	Signed integer, whose size is system-dependent.
float	32-bit IEEE floating-point number.
long	32-bit signed integer.
short	16-bit signed integer.
void	Allowed only as return type for a function, or in a function parameter list to indicate no arguments.
wchar_t	Unicode character accepted only for 32-bit type libraries.
BSTR	Length-prefixed string, as described in Chapter 5, "Dispatch Interfaces."
CURRENCY	8-byte fixed-point number.
DATE	64-bit floating-point fractional number of days since December 30, 1899.
HRESULT	Return type used for reporting error information in interfaces, as described in the OLE 2 Programmer's Reference, Volume 1.
Type	Description
LPWSTR	Unicode string accepted only for 32-bit type libraries.
LPSTR	Zero-terminated string.
SCODE	Built-in error type that corresponds to VT_ERROR. An SCODE does not contain the additional error information provided by HRESULT.
VARIANT	One of the variant data types as described in Chapter 5, "Dispatch Interfaces."
IDispatch *	Pointer to IDispatch interface.
IUnknown *	Pointer to IUnknown interface. (Any OLE interface can be represented by its IUnknown interface.)
The keyword unsigned may be specified before int, char, short, and long.


String Definitions

Strings can be declared using the LPSTR type, which indicates a zero-terminated string, and with the BSTR type, which indicates a length-prefixed string (as defined in Chapter 5, "Dispatch Interfaces." In 32-bit type libraries, Unicode strings can be defined with the LPWSTR type.


ODL Reference

The remainder of this chapter provides reference material on the attributes, statements, and directives that are part of the Object Description Language (ODL).


Attribute Descriptions

The following sections describe the ODL attributes and list the types of objects to which they apply, and the equivalent flags set in the object's typeinfo.


appobject

Description

Identifies the Application object.

Allowed on

Coclass

Comments

Indicates that the members of the class may be accessed without qualification when accessing this type library.

Flags

TYPEFLAG_FAPPOBJECT


bindable

Description

Indicates that the property supports data binding.

Allowed on

Property

Comments

Refers to the property as a whole, so it must be specified wherever the property is defined. Therefore, you need to specify the attribute on both the property get description and on the property set description.

Flags

FUNCFLAG_FBINDABLE, VARFLAG_FBINDABLE


control

Description

Indicates that the item represents a control from which a container site will derive additional typelibs or coclasses.

Allowed on

Typelib, coclass

Comments

This attribute allows you to mark type libraries that describe controls so that they will not be displayed in type browsers intended for nonvisual objects.

Flags

TYPEFLAG_FCONTROL, LIBFLAG_FCONTROL


default

Description

Indicates that the interface or dispinterface represents the default programmability interface, intended for use by macro languages.

Allowed on

Coclass member

Comments

A coclass may have at most two default members. One represents the source interface or dispinterface, and the other represents the sink interface or dispinterface. If the default attribute is not specified for any member of the coclass or cotype, the first source and sink members that do not have the restricted attribute are treated as the defaults.

Flags

IMPLTYPEFLAG_FDEFAULT


defaultbind

Description

Indicates the single, bindable property that best represents the object.

Allowed on

Property

Comments

Properties that have the defaultbind attribute must also have the bindable attribute. You can't specify defaultbind on more than one property in a dispinterface.

This attribute is used by containers that have a user model involving binding to an object rather than binding to a property of an object. An object can support data binding but not have this attribute.

Flags

FUNCFLAG_FDEFAULTBIND, VARFLAG_FDEFAULTBIND


displaybind

Description

Indicates a property that should be displayed to the user as bindable.

Allowed on

Property

Comments

Properties that have the displaybind attribute must also have the bindable attribute. An object can support data binding but not have this attribute.

Flags

FUNCFLAG_FDISPLAYBIND, VARFLAG_FDISPLAYBIND


dllname(str)

Description

Defines the name of the DLL that contains the entry points for a module.

Allowed on

Module (required)

Comments

The str argument gives the filename of the DLL.


dual

Description

Identifies an interface that exposes properties and methods through IDispatch and directly through the VTBL.

Allowed on

Interface

Comments

The interface must be compatible with OLE Automation and derive from IDispatch. Not allowed on dispinterfaces.

The dual attribute creates an interface that is both a Dispatch interface and a Component Object Model (COM) interface. The first seven entries of the VTBL for a dual interface are the seven members of IDispatch, and the remaining entries are OLE COM entries for direct access to members of the dual interface. All the parameters and return types specified for members of a dual interface must be OLE Automation-compatible types.

All members of a dual interface must pass an HRESULT as the function return value. Members that need to return other values should specify the last parameter as [retval, out] indicating an output parameter that returns the value of the function. In addition, members that need to support multiple locales should pass an lcid parameter.

A dual interface provides for both the speed of direct VTBL binding and the flexibility of IDispatch binding. For this reason, dual interfaces are recommended whenever possible.

Note  If your application accesses object data by casting the THIS pointer within the interface call, you should check the VTBL pointers in the object against your own VTBL pointers to ensure that you are connected to the appropriate proxy.

Specifying dual on an interface implies that the interface is compatible with OLE Automation, and therefore causes both the TYPEFLAG_FDUAL and TYPEFLAG_FOLEAUTOMATION flags to be set.

Flags

TYPEFLAG_FDUAL, TYPEFLAG_FOLEAUTOMATION


entry(entryid)

Description

Identifies the entry point in the DLL.

Allowed on

Functions in a module (required)

Comments

If entryid is a string, this is a named entry point. If entryid is a number, the entry point is defined by an ordinal. This attribute provides a way to obtain the address of a function in a module.


helpcontext(numctxt)

Description

Sets the context within the Help file.

Allowed on

Library, interface, dispinterface, struct, enum, union, module, typedef, method, struct member, enum value, property, coclass, const

Comments

Retrieved via the GetDocumentation functions in the ITypeLib and ITypeInfo interfaces. The numctxt is a 32-bit Help context within the Help file.


helpfile(filename)

Description

Sets the name of the Help file.

Allowed on

Library

Comments

Retrieved via the GetDocumentation functions in the ITypeLib and ITypeInfo interfaces.

All types in a library share the same Help file.


helpstring(string)

Description

Sets the Help string.

Allowed on

Library, interface, dispinterface, struct, enum, union, module, typedef, method, struct member, enum value, property, coclass, const

Comments

Retrieved via the GetDocumentation functions in the ITypeLib and ITypeInfo interfaces.


hidden

Description

Indicates that the item exists but should not be displayed in a user-oriented browser.

Allowed on

Property, method, coclass, dispinterface, interface, library


Comments

This attribute allows you to remove members from your interface (by shielding them from further use) while maintaining compatibility with existing code.

When specified for a library, the attribute prevents the entire library from being displayed. It is intended for use by controls. Hosts need to create a new type library that wraps the control with extended properties.

Flags

VARFLAG_FHIDDEN, FUNCFLAG_FHIDDEN, TYPEFLAG_FHIDDEN


id(num)

Description

Identifies the DISPID of the member.

Allowed on

Method or property in an interface or dispinterface

Comments

The num is a 32-bit integral value in the following format:

Bits	Value
0−15	Offset. Any value is permissible.
16−21	The nesting level of this typeinfo in the inheritance hierarchy. For example: interface mydisp : IDispatch The nesting level of IUnknown is 0, IDispatch is 1, and mydisp is 2.
22−25	Reserved; must be zero
26−28	DISPID value.
29	True if this is the member ID for a FuncDesc; otherwise False.
30−31	Must be 01.
Negative IDs are reserved for use by OLE Automation.


in

Description

Specifies an input parameter.

Allowed on

Parameter

Comments

The parameter may be a pointer (such as char *) but the value it refers to is not returned.


lcid

Description

Indicates that the parameter is a locale ID.

Allowed on

Parameter in a member of an interface

Comments

At most one parameter may have this attribute. The parameter must have the in attribute and can't have the out attribute, and its type must be long. The lcid attribute is not allowed on dispinterfaces.

The lcid attribute allows members in the VTBL to receive an LCID at invocation. By convention, the lcid parameter is the last parameter that does not have the retval attribute. If the member specifies propertyput or propertyputref, the lcid parameter must precede the parameter that represents the right side of the property assignment.

ITypeInfo::Invoke passes the LCID of the typeinfo into the lcid parameter. Parameters with this attibute are not displayed in user-oriented browsers.


lcid(numid)

Description

Identifies the locale for a type library.

Allowed on

Library

Comments

The numid is a 32-bit locale ID as used in Win32 National Language Support. The locale ID is typically entered in hexadecimal.


licensed

Description

Indicates that the class is licensed.

Allowed on

Coclass

Flags

TYPEFLAG_FLICENSED


nonextensible

Description

Indicates that the IDispatch implementation includes only the properties and methods listed in the interface description.

Allowed on

Dispinterface, interface

Comments

The interface must have the dual attribute.

By default, OLE Automation assumes that interfaces may add members at run time; that is, it assumes they are extensible.

Flags

TYPEFLAG_FNONEXTENSIBLE


odl

Description

Identifies an interface as an ODL interface.

Allowed on

Interface (required)

Comments

This attribute must appear on all interfaces.


oleautomation

Description

Indicates that an interface is compatible with OLE Automation.

Allowed on

Interface

Comments

Not allowed on dispinterfaces.

The oleautomation attribute indicates that an interface is compatible with OLE Automation. The parameters and return types specified for its members must be OLE Automation-compatible, as listed in the following table.

Type	Description
boolean	Data item that can have the value True or False. The size corresponds to VARIANT_BOOL.
unsigned char	8-bit unsigned data item.
double	64-bit IEEE floating-point number.
float	32-bit IEEE floating-point number.
Type	Description
int	Signed integer, whose size is system-dependent.
long	32-bit signed integer.
short	16-bit signed integer.
BSTR	Length-prefixed string, as described in Chapter 5, "Dispatch Interfaces."
CURRENCY	8-byte fixed-point number.
DATE	64-bit floating-point fractional number of days since December 30, 1899.
SCODE	Built-in error type that corresponds to VT_ERROR.
typedef enum myenum	Signed integer, whose size is system-dependent.
interface IDispatch *	Pointer to IDispatch interface (VT_DISPATCH).
interface IUnknown *	Pointer to interface that does not derive from IDispatch (VT_UNKNOWN). (Any OLE interface can be represented by its IUnknown interface.)
dispinterface Typename *	Pointer to IDispatch-derived interface (VT_DISPATCH).
coclass Typename *	Pointer to a coclass name (VT_UNKNOWN).
[oleautomation] interface Typename *	Pointer to an interface that derives from IDispatch.
A parameter is compatible with OLE Automation if its type is an OLE Automation-compatible type, a pointer to an OLE Automation-compatible type, or a SAFEARRAY of an OLE Automation-compatible type.

A return type is compatible with OLE Automation if its type is an HRESULT or is void. Methods in OLE Automation must return either HRESULT or void.

A member is compatible with OLE Automation if its return type and all of its parameters are OLE-Automation compatible.

An interface is compatible with OLE Automation if it derives from IDispatch or IUnknown, if it has the oleautomation attribute, and if all of its VTBL entries are OLE-Automation compatible. For 32-bit systems, the calling convention for all methods in the interface must be STDCALL. For 16-bit systems, all methods must have the CDECL calling convention. Every dispinterface is OLE Automation-compatible.

Flags

TYPEFLAG_FOLEAUTOMATION


optional

Description

Specifies an optional parameter.

Allowed on

Parameter

Comments

Valid only if the parameter is of type VARIANT or VARIANT*. All subsequent parameters of the function must also be optional.


out

Description

Specifies an output parameter.

Allowed on

Parameter

Comments

The parameter must be a pointer to memory that will receive a result.


propget

Description

Specifies a property accessor function.

Allowed on

Functions; methods in interfaces and dispinterfaces

Comments

The property must have the same name as the function. At most, one of propget, propput, and propputref can be specified for a function.

Flags

INVOKE_PROPERTYGET


propput

Description

Specifies a property-setting function.

Allowed on

Functions; methods in interfaces and dispinterfaces

Comments

The property must have the same name as the function. At most, one of propget, propput and propputref can be specified.

Flags

INVOKE_PROPERTYPUT


propputref

Description

Specifies a property-setting function that uses a reference instead of a value.

Allowed on

Functions; methods in interfaces and dispinterfaces

Comments

The property must have the same name as the function. At most, one of propget, propput and propputref can be specified.

Flags

INVOKE_PROPERTYPUTREF


public

Description

Includes an alias declared with the typedef keyword in the type library.

Allowed on

Aliases declared with typedef

Comments

By default, an alias that is declared with typedef and has no other attributes is treated as a #define and is not included in the type library. Using the public attribute ensures that the alias becomes part of the type library.


readonly

Description

Prohibits assignment to a variable.

Allowed on

Variable

Flags

VARFLAG_FREADONLY


requestedit

Description

Indicates that the property supports the OnRequestEdit notification.

Allowed on

Property

Comments

The property supports the OnRequestEdit notification, raised by a property before it is edited. An object can support data binding but not have this attribute.

Flags

FUNCFLAG_FREQUESTEDIT, VARFLAG_FREQUESTEDIT


restricted

Description

Prevents the item from being used by a macro programmer.

Allowed on

Type library, coclass member, member of a module or interface

Comments

Allowed on a member of a coclass, independent of whether the member is a dispinterface or interface, and independent of whether the member is a sink or source. A member of a coclass can't have both the restricted and default attributes.

Flags

IMPLTYPEFLAG_FRESTRICTED, FUNCFLAG_FRESTRICTED


retval

Description

Designates the parameter that receives the return value of the member.

Allowed on

Parameters of interface members that describe methods or get properties

Comments

This attribute may be used only on the last parameter of the member. The parameter must have the out attribute and must be a pointer type.

Parameters with this attibute are not displayed in user-oriented browsers.

Flags

IDLFLAG_FRETVAL


source

Description

Indicates that a member is a source of events.

Allowed on

Member of a coclass; property or method.

Comments

For a member of a coclass, this attribute means that the member is called rather than implemented.

On a property or method, indicates that the member returns an object or VARIANT that is a source of events. The object implements IConnectionPointContainer.

Flags

IMPLTYPEFLAG_FSOURCE, VARFLAG_SOURCE, FUNCFLAG_SOURCE


string

Description

Specifies a string.

Allowed on

Struct, member, parameter, property

Comments

Included only for compatibility with IDL; use LPSTR for a zero-terminated string.


uuid(uuidval)

Description

Specifies the UUID of the item.

Allowed on

Required for library, dispinterface, interface, and coclass; optional on struct, enum, union, module, and typedef

Comments

The uuidval is a 16-byte value formatted as hexadecimal digits in the following format: 12345678-1234-1234-1234-123456789ABC. This value is returned in the TypeAttr structure retrieved by TypeInfo::GetTypeAttr.


vararg

Description

Indicates a variable number of arguments.

Allowed on

Function

Comments

Indicates that the last parameter is a safe array of VARIANT type, which contains all the remaining parameters.


version(versionval)

Description

Specifies a version number.

Allowed on

Library, struct, module, dispinterface, interface, coclass, enum, union.

Comments

The argument versionval is a real number in the format n.m, where n is a major version number and m is a minor version number.


ODL Statements and Directives

The following sections describe the statements and directives that make up the Object Description Language.


The coclass Statement

Describes the GUID and supported interfaces for a component object.

Syntax

[attributes]
coclass classname {
[attributes2] [interface | dispinterface] interfacename;
. . .
};

Syntax Elements

attributes

The uuid attribute is required on a coclass. This is the same uuid that is registered as a CLSID in the system registration database. The helpstring, helpcontext, licensed, version, control, hidden, and appobject attributes are accepted, but not required, before a coclass definition. See "Attribute Descriptions," earlier in this chapter, for more information on the attributes accepted before a coclass definition. The appobject attribute makes the functions and properties of the coclass globally available in the type library.

classname

Name by which the common object is known in the type library.

attributes2

Optional attributes for the interface or dispinterface. The source, default, and restricted attributes are accepted on an interface or dispinterface within a coclass.

interfacename

Either an interface declared with the interface keyword, or a dispinterface declared with the dispinterface keyword.

Comments

The Microsoft Component Object Model defines a class as an implementation that allows QueryInterface between a set of interfaces.

Examples

[ uuid(BFB73347-822A-1068-8849-00DD011087E8), version(1.0), helpstring("A class"), helpcontext(2481), appobject]

coclass myapp {

[source] interface IMydocfuncs;

dispinterface DMydocfuncs;

};

[uuid 00000000-0000-0000-0000-123456789019]

coclass foo

{

[restricted] interface bar;

interface baz;

}


The dispinterface Statement

Defines a set of properties and methods on which you can call IDispatch::Invoke. A dispinterface may be defined by explicitly listing the set of supported methods and properties (Syntax 1) or by listing a single interface (Syntax 2).

Syntax 1

[attributes]
dispinterface intfname {
properties:
proplist
methods:
methlist
};

Syntax 2

[attributes]
dispinterface intfname {
interface interfacename
};

Syntax Elements

attributes

The helpstring, helpcontext, hidden, uuid, and version attributes are accepted before dispinterface. See "Attribute Descriptions," earlier in this chapter, for more information on the attributes accepted before a dispinterface definition. Attributes (including the brackets) may be omitted. The uuid attribute is required.

intfname

The name by which the dispinterface is known in the type library. This name must be unique within the type library.

interfacename

(Syntax 2) The name of the interface to declare as an IDispatch interface.

proplist

(Syntax 1) An optional list of properties supported by the object, declared in the form of variables. This is the short form for declaring the property functions in the methods list. See the comments section for details.

methlist

(Syntax 1) A list comprising a function prototype for each method and property in the dispinterface. Any number of function definitions can appear in methlist. A function in methlist has the following form:

[attributes] returntype methname(params);

The following attributes are accepted on a method in a dispinterface: helpstring, helpcontext, string (for compatibility with IDL), bindable, defaultbind, displaybind, propget, propput, propputref, and vararg. If vararg is specified, the last parameter must be a safe array of VARIANT type.

The parameter list is a comma-delimited list, each element of which has the following form:

[attributes] type paramname

The type can be any declared or built-in type, or a pointer to any type. Attributes on parameters are:

in, out, optional, string

If optional appears, it must only be specified on the rightmost parameters, and the types of those parameters must be VARIANT.

Comments

Method functions are specified exactly as described in "The module Statement," except that the entry attribute is not allowed. Note that STDOLE32.TLB (STDOLE.TLB on 16-bit systems) must be imported, because a dispinterface inherits from IDispatch.

You can declare properties in either the properties or methods lists. Declaring properties in the properties list does not indicate the type of access the property supports (that is, get, put, or putref). Specify the readonly attribute for properties that don't support put or putref. If you declare the property functions in the methods list, functions for one property all have the same ID.

Using Syntax 1, the properties: and methods: tags are required. The id attribute is also required on each member. For example:

properties:

[id(0)] int Value;	// Default property.

methods:

[id(1)] void Show();

Unlike interface members, dispinterface members cannot use the retval attribute to return a value in addition to an HRESULT error code. The lcid attribute is likewise invalid for dispinterfaces, because IDispatch::Invoke passes an LCID. However, it is possible to redeclare an interface that uses these attributes.

Using Syntax 2, interfaces that support IDispatch and are declared earlier in an ODL script can be redeclared as IDispatch interfaces as follows:

dispinterface helloPro {

interface hello;

};

The preceding example declares all of the members of hello and all of the members that hello inherits as supporting IDispatch. In this case, if hello were declared earlier with lcid and retval members that returned HRESULTs, MkTypLib would remove each lcid parameter and HRESULT return type, and instead mark the return type as that of the retval parameter.

The properties and methods of a dispinterface are not part of the VTBL of the dispinterface. Consequently, CreateStdDispatch and DispInvoke can't be used to implement IDispatch::Invoke. The dispinterface is used when an application needs to expose existing non-VTBL functions through OLE Automation. These applications can implement IDispatch::Invoke by examining the dispidMember parameter and directly calling the corresponding function.

Example

[ uuid(BFB73347-822A-1068-8849-00DD011087E8), version(1.0), helpstring("Useful help string."), helpcontext(2480)]

dispinterface MyDispatchObject {

properties:

[id(1)] int x;	//An integer property named x

[id(2)] BSTR y;	//A string property named y

methods:

[id(3)] void show();	//No arguments, no result

[id(11)] int computeit(int inarg, double *outarg);

};

[uuid 00000000-0000-0000-0000-123456789012]

dispinterface MyObject

{

properties:

methods:

[id(1), propget, bindable, defaultbind, displaybind]

long x();

[id(1), propput, bindable, defaultbind, displaybind]

void x(long rhs);

}


The enum Statement

Defines a C-style enumerated type.

Syntax

typedef [attributes] enum [tag] {
enumlist
} enumname;

Syntax Elements

attributes

The helpstring, helpcontext, hidden, and uuid attributes are accepted before an enum. The helpstring and helpcontext attributes are accepted on an enumeration element. See "Attribute Descriptions," earlier in this chapter, for more information on the attributes accepted before an enumeration definition. Attributes (including the brackets) may be omitted. If uuid is omitted, the enumeration is not uniquely specified in the system.

tag

An optional tag, as with a C enum.

enumlist

List of enumerated elements.

enumname

Name by which the enumeration is known in the type library.

Comments

The enum keyword must be preceded by typedef. The enumeration description must precede other references to the enumeration in the library. If = value is not specified for enumerators, the numbering progresses as with enumerations in C. The type of the enum elements is int, the system default integer, which depends on the target type library specification.

Examples

typedef [uuid(DEADF00D-C0DE-B1FF-F001-A100FF001ED),

helpstring("Farm Animals are friendly"), helpcontext(234)]

enum {

[helpstring("Moo")] cows = 1,

pigs = 2

} ANIMALS;


The importlib Directive

Makes types that have already been compiled into another type library available to the library currently being created. All importlib directives must precede the other type descriptions in the library.

Syntax

importlib(filename);

Syntax Elements

filename

The location of the type library file when MkTypLib is executed.

Comments

The importlib directive makes any type defined in the imported library accessible from within the library being compiled. Ambiguity is resolved as follows. The current library is searched for the type. If the type can't be found, MkTypLib searches the imported library that is lexically first, then the next, and so on. To import a type name in code, you must enter the name as libname.typename, where libname is the library name as it appeared in the library statement when the library was compiled.

The imported type library should be distributed with the library being compiled.

Example

The following example imports the libraries STDOLE.TLB and MYDISP.TLB:

library BrowseHelper

{

importlib("stdole.tlb");

importlib("mydisp.tlb");

//Additional text omitted

}


The interface Statement

Defines an interface, which is a set of function definitions. An interface can inherit from any base interface.

Syntax

[attributes]
interface interfacename [:baseinterface] {
functionlist
};

Syntax Elements

attributes

The dual, helpstring, helpcontext, hidden, odl, oleautomation, uuid, and version attributes are accepted before interface. If the interface is a member of a coclass, the source, default, and restricted attributes are also accepted. See "Attribute Descriptions," earlier in this chapter, for more information on the attributes accepted before an interface definition.

The odl and uuid attributes are required on all interface declarations.

interfacename

The name by which the interface is known in the type library.

baseinterface

The name of the interface that is the base class for this interface.

functionlist

List of function prototypes for each function in the interface. Any number of function definitions can appear in the function list. A function in the function list has the following form:

[attributes] returntype [calling convention] funcname(params);

The following attributes are accepted on a function in an interface: helpstring, helpcontext, string, propget, propput, propputref, bindable, defaultbind, displaybind, and vararg. If vararg is specified, the last parameter must be a safe array of VARIANT type. The optional calling convention can be any one of __pascal/_pascal/pascal or __cdecl/_cdecl/cdecl, __stdcall/_stdcall/stdcall. In other words, the calling convention specification can include up to two leading underscores.

The parameter list is a comma-delimited list as follows:

[attributes] type paramname

The type can be any previously declared type, built-in type, a pointer to any type, or a pointer to a built-in type. Attributes on parameters are:

in, out, optional, string

If optional appears, it must only be specified on the rightmost parameters, and the types of those parameters must be VARIANT.

Comments

Because the functions described by the interface statement are in the VTBL, you can use DispInvoke and CreateStdDispatch to provide an implementation of IDispatch::Invoke. For this reason, interface is more commonly used than dispinterface to describe the properties and methods of an object.

Functions in interfaces are the same as described in "The module Statement," except that the entry attribute is not allowed.

Members of interfaces that need to raise exceptions should return an HRESULT and specify a retval parameter for the actual return value. The retval parameter is always the last parameter in the list.

Examples

The following example defines an interface named Hello with two member functions, HelloProc and Shutdown:

[uuid(BFB73347-822A-1068-8849-00DD011087E8), version(1.0)]

interface hello : IUnknown

{

void HelloProc([in, string] unsigned char * pszString);

void Shutdown(void);

};

The next example defines a dual interface named IMyInt, which has a pair of accessor functions for the MyMessage property and a method that returns a string.

[dual]

interface IMyInt : IDispatch

{

//A property that is a string

[propget] HRESULT MyMessage([in, lcid] LCID lcid,

[out, retval] BSTR *pbstrRetVal);

[propput] HRESULT MyMessage([in] BSTR rhs, [in, lcid] DWORD lcid);

//A method returning a string

HRESULT SayMessage([in] long NumTimes,

   [in, lcid] DWORD lcid,

   [out, retval] BSTR *pbstrRetVal);

}

The members of this interface return error information and function return values through the HRESULT values and retval parameters, respectively. Tools that access the members can return the HRESULT to their users, or can simply expose the retval parameter as the return value and handle the HRESULT transparently.

Note that a dual interface must derive from IDispatch.


The library Statement

Describes a type library. This description contains all the other information in a MkTypLib input file.

Syntax

[attributes] library libname {
definitions
};

Syntax Elements

attributes

The helpstring, helpcontext, lcid, restricted, hidden, control, and uuid attributes are accepted before a library statement. See "Attribute Descriptions," earlier in this chapter, for more information on the attributes accepted before a library definition. The uuid attribute is required.

libname

The name by which the type library is known.

definitions

Descriptions of any imported libraries, data types, modules, interfaces, dispinterfaces, and coclasses relevant to the object being exposed.

Comments

The library statement must precede any other type definitions.

Example

[

uuid(F37C8060-4AD5-101B-B826-00DD01103DE1), // LIBID_Hello

helpstring("Hello 2.0 Type Library"),

lcid(0x0409),

version(2.0)

]

library Hello

{

importlib("stdole.tlb");

[

uuid(F37C8062-4AD5-101B-B826-00DD01103DE1),	// IID_IHello

helpstring("Application object for the Hello application."),

oleautomation,

dual

]

interface IHello : IDispatch

{

[propget, helpstring("Returns the application of the object.")]

HRESULT Application([in, lcid] long localeID,

[out, retval] IHello** retval)

}

}


The module Statement

Defines a group of functions, typically a set of DLL entry points.

Syntax

[attributes]
module modulename {
elementlist
};

Syntax Elements

attributes

The uuid, version, helpstring, helpcontext, hidden, and dllname attributes are accepted before a module statement. See "Attribute Descriptions," earlier in this chapter, for more information on the attributes accepted before a module definition. The dllname attribute is required. If uuid is omitted, the module is not uniquely specified in the system.

modulename

The name of the module.

elementlist

List of constant definitions and function prototypes for each function in the DLL. Any number of function definitions can appear in the function list. A function in the function list has the following form:

[attributes] returntype [calling convention] funcname(params);
[attributes] const constname = constval;

Only the helpstring and helpcontext attributes are accepted for a const.

The following attributes are accepted on a function in a module: helpstring, helpcontext, string, entry, propget, propput, propputref, vararg. If vararg is specified, the last parameter must be a safe array of VARIANT type.

The optional calling convention can be one of __pascal/_pascal/pascal, __cdecl/_cdecl/cdecl, or __stdcall/_stdcall/stdcall. The calling convention can include up to two leading underscores.

The parameter list is a comma-delimited list of:

[attributes] type paramname

The type can be any previously declared type or built-in type, a pointer to any type, or a pointer to a built-in type. Attributes on parameters are:

in, out, optional

If optional appears, it must only be specified on the rightmost parameters, and the types of those parameters must be VARIANT.

Comments

The header file (.H) output for modules is a series of function prototypes. The module keyword and surrounding brackets are stripped from the header (.H) file output, but a comment (\\ module modulename) is inserted before the prototypes. The keyword extern is inserted before the declarations.

Example

[uuid(D00BED00-CEDE-B1FF-F001-A100FF001ED),

helpstring("This is not GDI.EXE"), helpcontext(190), 	dllname("MATH.DLL")]

module somemodule{

[helpstring("Color for the frame")] unsigned long const COLOR_FRAME

= 0xH80000006;

[helpstring("Not a rectangle but a square"), entry(1)] pascal double square([in] double x);

};


The struct Statement

Defines a C-style structure.

Syntax

typedef [attributes]
struct [tag] {
memberlist
} structname;

Syntax Elements

attributes

The helpstring, helpcontext, uuid, hidden, and version attributes are accepted before a struct statement. The helpstring, helpcontext, string attributes are accepted on a structure member. See "Attribute Descriptions," earlier in this chapter, for more information on the attributes accepted before a structure definition. Attributes (including the brackets) may be omitted. If uuid is omitted, the structure is not uniquely specified in the system.

tag

An optional tag, as with a C struct.

memberlist

List of structure members defined with C syntax.

structname

Name by which the structure is known in the type library.

Comments

The struct keyword must be preceded with typedef. The structure description must precede other references to the structure in the library. Members of a struct can be of any built-in type, or any type defined lexically as a typedef before the struct. See the sections "String Definitions" and "Array Definitions," earlier in this chapter, for a description of how strings and arrays can be entered.

Example

typedef [uuid(BFB7334B-822A-1068-8849-00DD011087E8),

helpstring("A task"), helpcontext(1019)]

struct {

DATE startdate;

DATE enddate;

BSTR ownername;

SAFEARRAY (int) subtasks;

int A_C_array[10];

} TASKS;


The typedef Statement

Creates an alias for a type.

Syntax

typedef [attributes] basetype aliasname;

Syntax Elements

attributes

Any attribute specifications must follow the typedef keyword. If no attributes and no other type (for example enum, struct, or union) are specified, the alias is treated as a #define and does not appear in the type library. If no other attribute is desired, public can be used to explicitly include the alias in the type library. The helpstring, helpcontext, and uuid attributes are accepted before a typedef. See "Attribute Descriptions," earlier in this chapter, for more information. If uuid is omitted, the typedef is not uniquely specified in the system.

aliasname

Name by which the type will be known in the type library.

basetype

The type for which the alias is defined.

Comments

The typedef keyword must also be used whenever a struct or enum is defined. The name recorded for the enum or struct is the typedef name, not the tag for the enumeration. No attributes are required to make sure the alias appears in the type library.

Enumerations, structures, and unions must be defined with the typedef keyword. The attributes for a type defined with typedef are enclosed in brackets following the typedef keyword. If a simple alias typedef has no attributes, it is treated like a #define and the aliasname does not appear in the library. Any attribute (use public if no others are desired) specified between the typedef keyword and the rest of a simple alias definition causes the alias to appear explicitly in the type library. The attributes typically include such items as a Help string and Help context.

Examples

typedef [public]  long DWORD;

The preceding example creates a type description for an alias type with the name DWORD.

typedef enum {

TYPE_FUNCTION = 0,

TYPE_PROPERTY = 1,

TYPE_CONSTANT = 2,

TYPE_PARAMETER = 3

} OBJTYPE;

The second example creates a type description for an enumeration named OBJTYPE, which has four enumerator values.


The union Statement

Defines a C-style union.

Syntax

typedef [attributes] union [tag] {
memberlist
} unionname;

Syntax Elements

attributes

The helpstring, helpcontext, uuid, hidden, and version attributes are accepted before a union. The helpstring, helpcontext, and string attributes are accepted on a union member. See "Attribute Descriptions," earlier in this chapter, for more information on the attributes accepted before a union definition. Attributes (including the square brackets) may be omitted. If uuid is omitted, the union is not uniquely specified in the system.

tag

An optional tag, as with a C union.

memberlist

List of union members defined with C syntax.

unionname

Name by which the union is known in the type library.

Comments

The union keyword must be preceded with typedef. The union description must precede other references to the structure in the library. Members of a union can be of any built-in type, or any type defined lexically as a typedef before the union. See the sections "String Definitions" and "Array Definitions," earlier in this chapter, for a description of how strings and arrays can be entered.

Example

[uuid(BFB7334C-822A-1068-8849-00DD011087E8), helpstring("A task"), helpcontext(1019)]

typedef union {

COLOR polycolor;

int	cVertices;

boolean filled;

SAFEARRAY (int) subtasks;

} UNIONSHOP;


Type Description Interfaces

The type description interfaces provide a way to read and bind to the descriptions of objects in a type library. The descriptions are used by OLE Automation controllers when they browse, create, and manipulate OLE Automation objects.

The type description interfaces include:

•	ITypeLib —Used to retrieve information about a type library.

•	ITypeInfo — Used to read the type information within the type library.

•	ITypeComp — Used when creating compilers that use type information.


Overview of Type Description Interfaces

A type library is a container for type descriptions. ITypeLib provides access to information about a type description's containing library. ITypeInfo lets you access the type descriptions in a type library. The following table describes the member functions of each of the type description interfaces:

Category	Member name	Purpose
ITypeLib	FindName	Finds occurrences of a type description in a type library.
	GetDocumentation	Retrieves the library's documentation string, name of the complete Help file path and name, and the context ID for the library Help topic in the Help file.
	GetLibAttr	Retrieves the structure containing the library's attributes.
	GetTypeComp	Retrieves a pointer to the ITypeComp for a type library. This enables a client compiler to bind to the library's types, variables, constants and global functions.
	GetTypeInfo	Retrieves the specified type description in the library.
	GetTypeInfoCount	Retrieves the number of type descriptions in the library.
	GetTypeInfoType	Retrieves the type of a type description.
	GetTypeInfoOfGuid	Retrieves the type description corresponding to the specified GUID.
	IsName	Indicates whether a passed-in string contains the name of a type or member described in the library.
	ReleaseTLibAttr	Releases TLIBATTR originally obtained from ITypeLib::GetLibAttr.
ITypeInfo	AddressOfMember	Retrieves the addresses of static functions or variables, such as those defined in a DLL.
	CreateInstance	Creates a new instance of a type that describes a component object class (coclass).
	GetContainingTypeLib	Retrieves both the type library that contains a specific type description and the index of the type description within the type library.
	GetDllEntry	Retrieves a description or specification of an entry point for a function in a DLL.
	GetDocumentation	Retrieves the documentation string, name of the complete Help file path and name, and the context ID for the Help topic for a specified type description.
	GetFuncDesc	Retrieves the FUNCDESC structure containing information about a specified function.
	GetIDsOfNames	Maps between member names and member IDs and parameter names and parameter IDs.
	GetImplTypeFlags	Retrieves the IMPLTYPE flags for an interface.
	GetMops	Retrieves marshaling information.
	GetNames	Retrieves the variable with the specified member ID, or the name of the function and parameter names corresponding to the specified function ID.
	GetRefTypeInfo	Retrieves the type descriptions referenced by a given type description.
	GetRefTypeOfImplType	Retrieves the type description of the specified implemented interface types for a coclass, or an inherited interface.
	GetTypeAttr	Retrieves a TYPEATTR structure containing the attributes of the type description.
	GetTypeComp	Retrieves the ITypeComp interface for the type description, which enables a client compiler to bind to the type description's members.
	GetVarDesc	Retrieves a VARDESC structure describing the specified variable.
	Invoke	Invokes a method or accesses a property of an object that implements the interface described by the type description.
	ReleaseFuncDesc	Releases a FUNCDESC previously returned by GetFuncDesc.
	ReleaseTypeAttr	Releases a TYPEATTR previously returned by GetTypeAttr.
	ReleaseVarDesc	Releases a VARDESC previously returned by GetVarDesc.
ITypeComp	Bind	Maps a name to a member of a type, or binds global variables and functions contained in a type library.
	BindType	Binds to the type descriptions contained within a type library.


Overview of Type Description Functions

The functions for loading, registering, and querying type libraries are provided by OLEAUT32.DLL (for 32-bit systems) and TYPELIB.DLL (for 16-bit systems).

Category	Function name	Purpose
Library loading	LoadTypeLib	Loads and registers a type library.
	LoadRegTypeLib	Uses registry information to load a type library.
Library registration	RegisterTypeLib	Adds information about a type library to the system registry.
	QueryPathOfRegTypeLib	Retrieves the path of a registered type library.
Type compilation	LHashValOfNameSys LHashValOfName	Computes a hash value for a name that can then be passed to ITypeComp::Bind, ITypeComp::BindType, ITypeLib::IsName, or ITypeLib::FindName.


ITypeLib Interface

Implemented by	Used by	Header filename
OLEAUT32.DLL (32-bit systems) TYPELIB.DLL (16-bit systems)	Tools that need to access the descriptions of objects contained in type libraries.	OLEAUTO.H DISPATCH.H
Data describing a set of objects is stored in a type library. A type library may be a stand-alone binary file (.TLB), a resource in a DLL or .EXE file, or part of a compound document file.

A type library contains descriptions of one or more objects, and is accessed through the ITypeLib interface. The descriptions of individual objects are accessed through the ITypeInfo interface. The system registry contains a list of all the installed type libraries. Type library organization is illustrated in the following figure:

The ITypeLib interface provides methods for accessing a library of type descriptions. This interface supports the following:

•	Generalized containment for type information. ITypeLib allows iteration over the type descriptions contained in the library.

•	Global functions and data. A type library can contain descriptions of a set of modules, each of which is the equivalent of a C or C++ source file that exports data and functions. The type library supports compiling references to the exported data and functions.

•	General information, including a user-readable name for the library and Help for the library as a whole.


Using Structures and Enumerations with the ITypeLib Interface

The ITypeLib interface uses the following structures and enumerations:


Using LIBFLAGS with the ITypeLib Interface

The LIBFLAGS enumeration defines flags that apply to type libraries. LIBFLAGS is defined as follows:

typedef enum tagLIBFLAGS {

LIBFLAG_FRESTRICTED = 0x01

, LIBFLAG_FCONTROL = 0x02

, LIBFLAG_FHIDDEN = 0x04

} LIBFLAGS;

Value	Description
LIBFLAG_FCONTROL	The type library describes controls and should not be displayed in type browsers intended for nonvisual objects.
LIBFLAG_FRESTRICTED	The type library is restricted and should not be displayed to users.
LIBFLAG_FHIDDEN	The type library should not be displayed to users, though its use is not restricted. It is intended for use by controls. Hosts need to create a new typelib that wraps the control with extended properties.


Using SYSKIND with the ITypeLib Interface

The SYSKIND identifies the target operating system platform.

typedef enum tagSYSKIND[

SYS_WIN16,

SYS_WIN32,

SYS_MAC

] SYSKIND;

Value	Description
SYS_WIN16	The target operating system for the type library is 16-bit Windows systems. Data members are packed.
SYS_WIN32	The target operating system for the type library is 32-bit Windows systems. Data members are naturally aligned (for example, 2-byte integers are aligned on even-byte boundaries; 4-byte integers are aligned on quad-word boundaries, and so forth).
SYS_MAC	The target operating system for the type library is Macintosh. All data members are aligned on even-byte boundaries.


Using TLIBATTR with the ITypeLib Interface

The TLIBATTR structure contains information about a type library. Information from this structure is used to identify the type library and to provide national language support for member names.

typedef struct FARSTRUCT tagTLIBATTR {

GUID guid;	// Unique ID of the library

LCID lcid;	// Language/locale of the library

SYSKIND syskind;	// Target hardware platform

unsigned short wMajorVerNum;	// Major version number

unsigned short wMinorVerNum;	// Minor version number

unsigned short wLibFlags;	// Library flags

} TLIBATTR, FAR * LPTLIBATTR;

For more information on national language support, see "Supporting Multiple National Languages" in Chapter 2, and refer to the NLS API reference material in the Windows NT documentation.


ITypeLib::FindName

HRESULT ITypeLib::FindName(szNameBuf, lHashVal, rgptinfo, rgmemid, pcFound)
OLECHAR FAR* szNameBuf
unsigned long lHashVal
ITypeInfo FAR* FAR* rgptinfo
MEMBERID FAR* rgmemid
unsigned int FAR* pcFound

Finds occurrences of a type description in a type library. This may be used to quickly verify that a name exists in a type library.

Parameter

szNameBuf

The name to search for.

lHashVal

A hash value to speed up the search, computed by LHashValOfNameSys. If lHashVal = 0, a value will be computed for you.

rgptinfo

On return, an array of pointers to the type descriptions that contain the name specified in szNameBuf. May not be NULL.

rgmemid

An array of the MEMBERIDs of the found items; rgmemid[i] is the MEMBERID which indexes into the type description specified by rgptinfo[i]. May not be NULL.

pcFound

On entry, indicates how many instances to look for. For example, you may call with *pcFound = 1 in order to find the first occurrence. In this case, the search stops when one is found.

On exit, indicates the number of instances that were found. If the in and out values of *pcFound are identical, there may be more type descriptions that contain the name.


Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
E_OUTOFMEMORY	Out of memory.
E_INVALIDARG	One or more of the arguments is invalid.
TYPE_E_IOERROR	The function could not write to the file.
TYPE_E_INVDATAREAD	The function could not read from the file.
TYPE_E_UNSUPFORMAT	The type library has an old format.
TYPE_E_INVALIDSTATE	The type library could not be opened.
TYPE_E_CANTLOADLIBRARY	The library or DLL could not be loaded.
TYPE_E_ELEMENTNOTFOUND	The element was not found.
Comments

Passing *pcFound = n indicates that there is enough room in the rgptinfo and rgmemid arrays for n (ptinfo, memid) pairs. The function returns MEMID_NIL in rgmemid[i] if the name in szNameBuf is the name of the typeinfo in rgptinfo[i].


ITypeLib::GetDocumentation

HRESULT ITypeLib::GetDocumentation(index, lpbstrName, lpbstrDocString, lpdwHelpContext, lpbstrHelpFile)
int index
BSTR FAR* lpbstrName
BSTR FAR* lpbstrDocString
unsigned long FAR* lpdwHelpContext
BSTR FAR* lpbstrHelpFile

Retrieves the library's documentation string, name of the complete Help file path and name, and the context ID for the library Help topic in the Help file.

Parameter

index

Index of the type description whose documentation is to be returned; if index is −1, then the documentation for the library itself is returned.

lpbstrName

Returns a BSTR that contains the name of the specified item. If the caller does not need the item name, then lpbstrName can be NULL.

lpbstrDocString

Returns a BSTR that contains the documentation string for the specified item. If the caller does not need the documentation string, then lpbstrDocString can be NULL.

lpdwHelpContext

Returns the Help context ID associated with the specified item. If the caller does not need the Help context ID, then lpdwHelpContext can be NULL.

lpbstrHelpFile

Returns a BSTR that contains the fully qualified name of the Help file. If the caller does not need the Help filename, then lpbstrHelpFile can be NULL.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
STG_E_INSUFFICIENTMEMORY	Out of memory.
E_INVALIDARG	One or more of the arguments is invalid.
TYPE_E_IOERROR	The function could not write to the file.
TYPE_E_INVDATAREAD	The function could not read from the file.
TYPE_E_UNSUPFORMAT	The type library has an old format.
TYPE_E_INVALIDSTATE	The type library could not be opened.
TYPE_E_ELEMENTNOTFOUND	The element was not found.
Comments

The caller should free the BSTR parameters lpbstrName, lpbstrDocString, and lpbstrHelpFile.

Example

for (i = 0; i < utypeinfoCount; i++)

{

CHECKRESULT(ptlib->GetDocumentation(i, &bstrName,

NULL, NULL, NULL));

.

.

.

SysFreeString(bstrName);

}


ITypeLib::GetLibAttr

HRESULT ITypeLib::GetLibAttr(lplptlibattr)
TLIBATTR FAR* FAR* lplptlibattr

Retrieves the structure containing the library's attributes.

Parameter

lplptlibattr

Pointer to a structure containing the library's attributes.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
E_OUTOFMEMORY	Out of memory.
E_INVALIDARG	One or more of the arguments is invalid.
TYPE_E_IOERROR	The function could not write to the file.
TYPE_E_INVDATAREAD	The function could not read from the file.
TYPE_E_UNSUPFORMAT	The type library has an unsupported format.
TYPE_E_INVALIDSTATE	The type library could not be opened.
Comments

Use ITypeLib::ReleaseTLibAttr to free the memory occupied by the TLIBATTR structure.


ITypeLib::GetTypeComp

HRESULT ITypeLib::GetTypeComp(lplptcomp)
ITypeComp FAR* FAR* lplptcomp

Enables a client compiler to bind to the library's types, variables, constants and global functions.

Parameter

lplptcomp

Points to a pointer to the ITypeComp instance for this ITypeLib that a client compiler can use to bind to types in the ITypeLib and to the global functions, variables, and constants defined in the ITypeLib.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
E_OUTOFMEMORY	Out of memory.
E_INVALIDARG	One or more of the arguments is invalid.
TYPE_E_IOERROR	The function could not read from the file.
TYPE_E_INVDATAREAD	The function could not read from the file.
TYPE_E_UNSUPFORMAT	The type library has an old format.
TYPE_E_INVALIDSTATE	The type library could not be opened.
TYPE_E_WRONGTYPEKIND	Type mismatch.
Comments

The Bind function of the returned TypeComp binds to global functions, variables, constants, enumerated values, and coclass members. The Bind function also binds the names of the TYPEKINDs of TKIND_MODULE, TKIND_ENUM, and TKIND_COCLASS. These names shadow any global names defined within the type information. The members of TKIND_ENUM, TKIND_MODULE, and TKIND_COCLASS types marked as Application objects can be directly bound to from ITypeComp, without specifying the name of the module.

ITypeComp::Bind and ITypeComp::BindType accept only unqualified names. ITypeLib::GetTypeComp returns a pointer to the ITypeComp interface, which is then used to bind to global elements in the library. The names of some types (TKIND_ENUM, TKIND_MODULE, and TKIND_COCLASS) share the name space with variables, functions, constants, and enumerators. If a member requires qualification to differentiate it from other items in the name space, GetTypeComp can be called successively for each qualifier in order to bind to the desired member. This allows programming language compilers to access members of modules, enumerations, and coclasses, even though the member can't be bound to with a qualified name.


ITypeLib::GetTypeInfo

HRESULT ITypeLib::GetTypeInfo(index, lplpitinfo)
unsigned int	index
ITypeInfo FAR* FAR* lplpitinfo

Retrieves the specified type description in the library.

Parameters

index

Index of the ITypeInfo to be returned.

lplpitinfo

If successful, returns a pointer to the ITypeInfo.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
TYPE_E_ELEMENTNOTFOUND	Index is outside the range of 0 to GetTypeInfoCount() −1.
E_OUTOFMEMORY	Out of memory.
E_INVALIDARG	One or more of the arguments is invalid.
TYPE_E_IOERROR	The function could not read from the file.
TYPE_E_INVDATAREAD	The function could not read from the file.
TYPE_E_UNSUPFORMAT	The type library has an old format.
TYPE_E_REGISTRYACCESS	There was an error accessing the system registration database.
TYPE_E_INVALIDSTATE	The type library could not be opened.
Comments

For dual interfaces, ITypeLib::GetTypeInfo returns only the TKIND_DISPATCH typeinfo. To get the TKIND_INTERFACE typeinfo, call ITypeInfo::GetRefTypeOfImplType on the TKIND_DISPATCH typeinfo, passing an index of −1. Then pass the returned typeinfo handle to ITypeInfo::GetRefTypeInfo.

Example

The following example gets the TKIND_INTERFACE typeinfo for a dual interface.

ptlib->GetTypeInfo((unsigned int) dwIndex, &ptypeinfoDisp);

ptypeinfoDisp->GetRefTypeOfImplType(-1, &phreftype);

ptypeinfoDisp->GetRefTypeInfo(phreftype, &ptypeinfoInt);


ITypeLib::GetTypeInfoCount

unsigned int ITypeLib::GetTypeInfoCount( )

Comments

Returns the number of type descriptions in the type library.


ITypeLib::GetTypeInfoOfGuid

HRESULT ITypeLib::GetTypeInfoOfGuid(lpguid, lplpitinfo)
REFGUID lpguid
ITypeInfo FAR* FAR* lplpitinfo

Retrieves the type description corresponding to the specified GUID.

Parameters

lpguid

Pointer to the globally unique ID of the type description.

lplpitinfo

Pointer to a pointer to the ITypeInfo.


Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
TYPE_E_ELEMENTNOTFOUND	No type description was found in the library with the specified guid.
E_OUTOFMEMORY	Out of memory.
E_INVALIDARG	One or more of the arguments is invalid.
TYPE_E_IOERROR	The function could not write to the file.
TYPE_E_INVDATAREAD	The function could not read from the file.
TYPE_E_UNSUPFORMAT	The type library has an old format.
TYPE_E_REGISTRYACCESS	There was an error accessing the system registration database.
TYPE_E_INVALIDSTATE	The type library could not be opened.


ITypeLib::GetTypeInfoType

HRESULT ITypeLib::GetTypeInfoType(index, ptypekind)
unsigned int index
TYPEKIND FAR* ptypekind

Retrieves the type of a type description.

Parameters

index

The index of the type description within the type library.

ptypekind

A pointer to the TYPEKIND for the type description.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
TYPE_E_ELEMENTNOTFOUND	Index is outside the range of 0 to GetTypeInfoCount() −1.


ITypeLib::IsName

HResult ITypeLib::IsName(szNameBuf, lHashVal, lpfName)
OLECHAR FAR* szNameBuf
unsigned long lHashVal
BOOL lpfName

Indicates whether a passed-in string contains the name of a type or member described in the library.

Parameter

szNameBuf

The string to test. If IsName is successful, szNameBuf is modified to match the case (capitalization) found in the type library.

lHashVal

The hash value of szNameBuf.

lpfName

Upon return, set to True if szNameBuf was found in the type library; otherwise False.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
E_OUTOFMEMORY	Out of memory.
E_INVALIDARG	One or more of the arguments is invalid.
TYPE_E_IOERROR	The function could not read from the file.
TYPE_E_INVDATAREAD	The function could not read from the file.
TYPE_E_UNSUPFORMAT	The type library has an old format.
TYPE_E_INVALIDSTATE	The type library could not be opened.


ITypeLib::ReleaseTLibAttr

void ITypeLib::ReleaseTLibAttr(lptlibattr)
TLIBATTR FAR* lptlibattr

Releases TLIBATTR originally obtained from ITypeLib::GetLibAttr.

Parameter

lptlibattr

Pointer to the TLIBATTR to be freed.

Comments

Releases the specified TLIBATTR. This TLIBATTR was previously obtained with a call to GetTypeLib::GetLibAttr.


ITypeInfo Interface

Implemented by	Used by	Header filename
OLEAUT32.DLL (32-bit systems) TYPELIB.DLL (16-bit systems)	Tools that need to access the descriptions of objects contained in type libraries.	OLEAUTO.H DLL (32-bit systems) DISPATCH.H (16-bit systems)
This section describes ITypeInfo, an interface usually used for reading information about objects. For example, an object browser tool could use ITypeInfo to extract information about the characteristics and capabilities of objects from type libraries.

Type information interfaces are intended to describe the parts of the application that can be called by outside clients, rather than those that might be used internally to build an application.

The ITypeInfo interface provides access to the following:

•	The set of function descriptions associated with the type; for interfaces, this contains the set of member functions in the interface.

•	The set of data member descriptions associated with the type; for structures, this contains the set of fields of the type.

•	The general attributes of the type such as whether it describes a structure, an interface, and so forth.

You can use the type description of an IDispatch interface to implement the IDispatch interface. See the description of CreateStdDispatch in Chapter 5, "Dispatch Interfaces," for more information.

An ITypeInfo instance provides various information about a type, and is used in different ways. A compiler could use an ITypeInfo to compile references to members of the type. A type interface browser could use it to find information about each member of the type. An IDispatch implementor could use it to provide automatic delegation of IDispatch calls to an interface.


Type Descriptions

The information associated with an object described by ITypeInfo can include a set of functions, a set of data members, and various type attributes. It is essentially the same as the information described by a C++ class declaration. A C++ class declaration can be used to define both interfaces and structures, as well as any combination of functions and data members. In addition to interfaces and structure definitions, the ITypeInfo interface is used to describe other types, including enumerations and aliases. Because the interface to a C file or library is simply a set of functions and variable declarations, ITypeInfo is used to describe these as well.

Type information comprises individual type descriptions. Each type description must have one of the following forms:

Category	ODL keyword	Description
alias	typedef	An alias for another type.
enumeration	enum	An enumeration.
structure	struct	A structure.
union	union	A single data item that can have one of a specified group of types.
module	module	Data and functions not accessed through VTBL entries.
IDispatch interface	dispinterface	IDispatch properties and methods accessed through IDispatch::Invoke.
OLE interface	interface	OLE member functions accessed through VTBL entries.
Component object class	coclass	A component object class. Specifies an implementation of one or more OLE interfaces and one or more IDispatch interfaces.
Note that all bit flags that are not specifically used should be set to zero for future compatibility.

Alias

An alias has TypeKind = TKIND_ALIAS. An alias is an empty set of functions, an empty set of data members, and a type description (located in the TYPEATTR) which gives the actual type of the alias.

Enumeration

An enumeration has TypeKind = TKIND_ENUM. An enumeration is an empty set of functions and a set of constant data members.

Structure

A structure description has TypeKind = TKIND_RECORD. A structure is an empty set of functions and a set of per-instance data members.

Union

A union description has TypeKind = TKIND_UNION. A union is an empty set of functions and a set of per-instance data members, each of which has an instance offset of zero.

Module

A module has TypeKind = TKIND_MODULE. A module is a set of static functions and a set of static data members.

OLE-compatible Interfaces

An interface definition has TypeKind = TKIND_INTERFACE. An interface is a set of pure virtual functions and an empty set of data members. If a type description contains any virtual functions, then the pointer to the VTBL is the first 4 bytes of the instance.

The type information fully describes the member functions in the vtable, including parameter names and types and function return types. It may inherit from no more than one other interface.

Note that with interfaces and dispinterfaces, all members should have different names, except the accessor functions of properties. For property functions having the same name, the documentation string and Help context should be set for only one of the functions (because they conceptually define the same property).

Dispatch Interfaces

These include objects (TypeKind = TKIND_DISPATCH) that support the IDispatch interface with a specification of the dispatch data members (for example, properties) and methods supported through the object's Invoke implementation. All members of the dispinterface should have different IDs, except for the accessor functions of properties.

Dual Interfaces

Dual interfaces have two different typeinfos for the same interface. The TKIND_INTERFACE typeInfo describes the interface as a standard OLE COM interface. The TKIND_DISPATCH typeinfo describes the interface as a standard Dispatch interface. The lcid and retval parameters and HRESULT return types are removed, and the return type of the member is specified to be the same type as the retval parameter.

By default, the TypeKind for a dual interface is TKIND_DISPATCH. Tools that bind to interfaces should check the type flags for TYPEFLAG_FDUAL. If this flag is set, the TKIND_INTERFACE typeinfo is available through a call to ITypeInfo::GetRefTypeOfImplType with an index of −1, followed by a call to ITypeInfo::GetRefTypeInfo.

Component Object Classes (coclasses)

These include objects (TypeKind = TKIND_COCLASS) that support a set of implemented interfaces, which can be of either TKIND_INTERFACE or TKIND_DISPATCH.


Using Structures and Enumerations with the ITypeInfo Interface

Structures and enumerations used by ITypeInfo include the following:


ARRAYDESC

A pointer to an ARRAYDESC is contained within the TYPEDESC, which describes a C-style array. The TYPEDESC describes the type of the array's elements and information describing the array's dimensions. It is defined as follows:

typedef struct tagARRAYDESC{

TYPEDESC tdescElem;	// Element type.

unsigned short cDims;	// Dimension count.

SAFEARRAYBOUND rgbounds[1];	// Variable length array containing one

// element for each dimension.

} ARRAYDESC;


ELEMDESC

An ELEMDESC structure includes the type description and process-transfer information for a variable, a function, or a function parameter. It is defined as follows:

typedef struct tagELEMDESC{

TYPEDESC tdesc;	// Type of the element.

IDLDESC idldesc;	// Information needed for transferring the

// element between processes.

}  ELEMDESC;


FUNCDESC

A FUNCDESC describes a function, and is defined as follows:

typedef struct tagFUNCDESC {

MEMBERID memid;	// Function member ID

SCODE FAR* lprgscode;	// Legal SCODES for the function.

ELEMDESC FAR* lprgelemdescParam;  // Array of parameter types

FUNCKIND funckind;	// specifies whether the function is 	// virtual, static, or dispatch-only.

INVOKEKIND invkind;	// Invocation kind; indicates if this is a 	//property function and if so, what kind.

CALLCONV callconv;	// Specifies the function's calling 	// convention.

short cParams;	// Count of total number of parameters.

short cParamsOpt;	// Count of optional parameters (detailed

// description below).

short oVft;	// For FUNC_VIRTUAL, specifies the offset in 	// the virtual function table.

short cScodes;	// Count of permitted Scodes.

ELEMDESC elemdescFunc;	// Contains the return type of the function.

unsigned short wFuncFlags; // See below for definition of flags.

}	FUNCDESC;

The field cParams specifies the total number of required and optional parameters.

The cParamsOpt field specifies the form of optional parameters accepted by the function, as follows:

•	A value of 0 specifies that no optional arguments are supported.

•	A value of −1 specifies that the method's last parameter is a pointer to a safe array of variants. Any number of variant arguments greater than cParams −1 must be packaged by the caller into a safe array and passed as the final parameter. This array of optional parameters must be freed by the caller after control is returned from the call.

•	Any other number indicates that the last n parameters of the function are variants and need not be specified explicitly by the caller. The parameters left unspecified should be filled in by the compiler or interpreter as variants of type VT_ERROR with the value DISP_E_PARAMNOTFOUND.

The fields cScodes and lprgscode store the count and the set of errors that a function can return. If cScodes = −1 then the set of errors is unknown.
If cScodes = −1 or cScodes = 0, then lprgscode is undefined.


FUNCFLAGS

The FUNCFLAGS enumeration is defined as follows:

typedef enum tagFUNCFLAGS {

FUNCFLAG_FRESTRICTED= 1

, FUNCFLAG_FSOURCE= 0x2

, FUNCFLAG_FBINDABLE= 0x4

, FUNCFLAG_FREQUESTEDIT= 0x8

, FUNCFLAG_FDISPLAYBIND= 0x10

, FUNCFLAG_FDEFAULTBIND= 0x20

, FUNCFLAG_FHIDDEN= 0x40

} FUNCFLAGS;

Value	Description
FUNCFLAG_FRESTRICTED	The function should not be accessible from macro languages. This flag is intended for system-level functions or functions that you do not want type browsers to display.
FUNCFLAG_FSOURCE	The function returns an object that is a source of events.
FUNCFLAG_FBINDABLE	The function that supports data binding.
FUNCFLAG_FDISPLAYBIND	The function that is displayed to the user as bindable; that is, FUNC_FBINDABLE must also be set.
FUNCFLAG_FDEFAULTBIND	The function that best represents the object. Only one function in a typeinfo may have this attribute.
FUNCFLAG_FHIDDEN	The function should not be displayed to the user, though it exists and is bindable.


FUNCKIND

The FUNCKIND enumeration is defined as follows:

typedef enum tagFUNCKIND {

FUNC_VIRTUAL,

FUNC_PUREVIRTUAL,

FUNC_NONVIRTUAL,

FUNC_STATIC,

FUNC_DISPATCH,

} FUNCKIND;

Value	Description
FUNC_PUREVIRTUAL	The function is accessed through the virtual function table and takes an implicit this pointer.
FUNC_VIRTUAL	The function is accessed the same as PUREVIRTUAL, except the function has an implementation.
FUNC_NONVIRTUAL	The function is accessed by static address and takes an implicit this pointer.
FUNC_STATIC	The function is accessed by static address and does not take an implicit this pointer.
FUNC_DISPATCH	The function can be accessed only through IDispatch.


HREFTYPE

HREFTYPE is a handle that identifies a type description.

typedef unsigned long HREFTYPE;


IDLDESC

An IDLDESC contains information needed for transferring a structure element, parameter, or function return value between processes, and is defined as follows:

typedef struct FARSTRUCT tagIDLDESC {

unsigned long dwReserved;

unsigned short wIDLFlags;	/* IN, OUT, and so on */

} IDLDESCtypedef struct tagIDLDESC{

Note that dwReserved is reserved for future use and should be set to NULL.


IDLFLAGS

The IDLFLAGS are defined as follows:

#define IDLFLAG_NONE	0

#define IDLFLAG_FIN	0x1

#define IDLFLAG_FOUT	0x2

#define IDLFLAG_FLCID	0x4

#define IDLFLAG_FRETVAL	0x8

Value	Description
IDLFLAG_NONE	Whether the parameter passes or receives information is unspecified. IDispatch interfaces can use this flag.
IDLFLAG_FIN	Parameter passes information from the caller to the callee.
IDLFLAG_FOUT	Parameter returns information from the callee to the caller.
IDLFLAG_FIN | IDLFLAG_FOUT	Parameter passes and returns information.
IDLFLAG_FLCID	Parameter is the LCID of a client application.
IDLFLAG_FRETVAL	Parameter is the return value of the member.


IMPLTYPEFLAGS

The IMPLTYPEFLAGS are defined as follows:

/* IMPLTYPE Flags */

#define IMPLTYPEFLAG_FDEFAULT	0x1

#define IMPLTYPEFLAG_FSOURCE	0x2

#define IMPLTYPEFLAG_FRESTRICTED	0x4

Value	Description
IMPLTYPEFLAG_FDEFAULT	The interface or dispinterface represents the default for the source or sink.
IMPLTYPEFLAG_FSOURCE	This member of a coclass is called rather than implemented.
IMPLTYPEFLAG_FRESTRICTED	The member should not be displayed or programmable by users.


INVOKEKIND

The INVOKEKIND enumeration is defined as follows:

typedef enum tagINVOKEKIND {

INVOKE_FUNC = DISPATCH_METHOD,

INVOKE_PROPERTYGET = DISPATCH_PROPERTYGET,

INVOKE_PROPERTYPUT = DISPATCH_PROPERTYPUT,

INVOKE_PROPERTYPUTREF = DISPATCH_PROPERTYPUTREF

} INVOKEKIND;

Value	Description
INVOKE_FUNC	The member is called using normal function invocation syntax.
INVOKE_PROPERTYGET	The function is invoked by using normal property access syntax.
INVOKE_PROPERTYPUT	The function is invoked by using property value assignment syntax. Syntactically, a typical programming language might represent changing a property in the same way as assignment; for example: object.property := value.
INVOKE_PROPERTYPUTREF	The function is invoked by using property reference assignment syntax.
Note that in C, value assignment is written as *pobj1 = *pobj2, while reference assignment is written as pobj1 = pobj2. Other languages have other syntactic conventions. A property or data member may support value assignment only, reference assignment only, or both. For a more detailed description of property functions, see Chapter 5, "Dispatch Interfaces." These enumeration constants are the same constants that are passed to IDispatch::Invoke to specify the way in which a function is invoked.


MEMBERID

MEMBERID identifies the member in a type description. For IDispatch interfaces, this is the same as DISPID.

typedef DISPID MEMBERID;

This is a 32-bit integral value in the following format:

Bits	Value
0−15	Offset. Any value is permissible.
16−21	The nesting level of this typeinfo in the inheritance hierarchy. For example: interface mydisp : IDispatch The nesting level of IUnknown is 0, IDispatch is 1, and mydisp is 2.
22−25	Reserved; must be zero
26−28	DISPID value.
29	True if this is the member ID for a FuncDesc; otherwise False.
30−31	Must be 01.
Negative IDs are reserved for use by OLE Automation.


TYPEATTR

The TYPEATTR structure contains attributes of an ITypeInfo, and is defined as follows:

typedef struct FARSTRUCT tagTYPEATTR {

GUID guid;	// The GUID of the TypeInfo

LCID lcid;	// Locale of member names and doc

// strings

unsigned long dwReserved;

MEMBERID memidConstructor;	// ID of constructor,MEMBERID_NIL if

// None

MEMBERID memidDestructor;	// ID of destructor, MEMBERID_NIL if

// None

OLECHAR FAR* lpstrSchema;	// Reserved for future use

unsigned long cbSizeInstance;// The size of an instance of 	// this type.

TYPEKIND typekind;	// The kind of type this typeinfo 	// describes.

unsigned short cFuncs;	// Number of functions

unsigned short cVars;	// Number of variables/data members

unsigned short cImplTypes;	// Number of implemented interfaces

unsigned short cbSizeVft;	// The size of this type's virtual 	// func table

unsigned short cbAlignment;	// Byte alignment for an instance 	// of this type

unsigned short wTypeFlags;

unsigned short wMajorVerNum;	// Major version number

unsigned short wMinorVerNum;	// Minor version number

TYPEDESC tdescAlias;	// If TypeKind == TKIND_ALIAS, 	// specifies the type for which 	// this type is an alias

IDLDESC idldescType;	// IDL attributes of the 	// described type

} TYPEATTR, FAR* LPTYPEATTR;

The cbAlignment field indicates how addresses are aligned. A value of 0 indicates alignment on the 64K boundary; 1 indicates no special alignment. For other values, n indicates aligned on byte n.


TYPEDESC

A TYPEDESC, which describes the type of a variable, the return type of a function, or the type of a function parameter, is defined as follows:

typedef struct FARSTRUCT tagTYPEDESC {

union {

/* VT_PTR|VT_SAFEAEEAY - the pointed-at type */

struct FARSTRUCT tagTYPEDESC FAR* lptdesc;

/* VT_CARRAY */

struct FARSTRUCT tagARRAYDESC FAR* lpadesc;

/* VT_USERDEFINED - this is used to get a TypeInfo for a user-

   defined type */

HREFTYPE hreftype;

}UNION_NAME(u);

VARTYPE vt;

} TYPEDESC;

If the variable is VT_SAFEARRAY or VT_PTR, the union portion of the TYPEDESC contains a pointer to a TYPEDESC that specifies the element type.


TYPEFLAGS

The TYPEFLAGS enumeration is defined as follows:

typedef enum tagTYPEFLAGS {

TYPEFLAG_FAPPOBJECT = 0x01

, TYPEFLAG_FCANCREATE = 0x02

, TYPEFLAG_FLICENSED = 0x04

, TYPEFLAG_FPREDECLID = 0x08

, TYPEFLAG_FHIDDEN = 0x10

, TYPEFLAG_FCONTROL = 0x20

, TYPEFLAG_FDUAL = 0x40

, TYPEFLAG_FNONEXTENSIBLE = 0x80

, TYPEFLAG_FOLEAUTOMATION = 0x100

} TYPEFLAGS;

Value	Description
TYPEFLAG_FAPPOBJECT	A type description that describes an Application object.
TYPEFLAG_FCANCREATE	Instances of the type can be created by ITypeInfo::CreateInstance.
TYPEFLAG_FLICENSED	The type is licensed.
TYPEFLAG_FPREDECLID	The type is predefined. The client application should automatically create a single instance of the object that has this attribute. The name of the variable that points to the object is the same as the class name of the object.
TYPEFLAG_FHIDDEN	The type should not be displayed to browsers.
TYPEFLAG_FCONTROL	The type is a control from which other types will be derived, and should not be displayed to users.
TYPEFLAG_FDUAL	The types in the interface derive from IDispatch and are fully compatible with OLE Automation. Not allowed on Dispatch interfaces.
TYPEFLAG_FNONEXTENSIBLE	The interface can't add members at run time.
TYPEFLAG_FOLEAUTOMATION	The types used in the interface are fully compatible with OLE, and may be displayed in an object browser. Setting dual on an interface sets this flag in addition to TYPEFLAG_FDUAL. Not allowed on dispinterfaces.
TYPEFLAG_FAPPOBJECT may be used on type descriptions with TypeKind = TKIND_COCLASS, and indicates that the type description describes an Application object.

Members of the Application object are globally accessible in that the Bind method of the ITypeComp instance associated with the library binds to the members of an Application object just as it does for type descriptions that have TypeKind = TKIND_MODULE.

The type description implicitly defines a global variable with the same name and type as the type described by the type description. This variable is also globally accessible. Specifically, when Bind is passed the name of an Application object, a VARDESC is returned describing the implicit variable. The ID of the implicitly created variable is always ID_DEFAULTINST.

When the CreateInstance function of an Application object type description is called, it uses GetActiveObject to retrieve the Application object. If GetActiveObject fails because the application is not running, then CreateInstance calls CoCreateInstance (which should start the application).

When TYPEFLAG_FCANCREATE is True, ITypeInfo::CreateInstance can create an instance of the type. Note that this is currently true only for component object classes for which a GUID has been specified.


TYPEKIND

The TYPEKIND enumeration is defined as follows:

typedef enum tagTYPEKIND {

  TKIND_ENUM = 0

, TKIND_RECORD

, TKIND_MODULE

, TKIND_INTERFACE

, TKIND_DISPATCH

, TKIND_COCLASS

, TKIND_ALIAS

, TKIND_UNION

, TKIND_MAX	/* end of enum marker */

} TYPEKIND;

Value	Description
TKIND_ALIAS	A type that is an alias for another type.
TKIND_COCLASS	A set of implemented component object interfaces.
TKIND_DISPATCH	A set of methods and properties that are accessible through IDispatch::Invoke. By default, dual interfaces return TKIND_DISPATCH.
TKIND_ENUM	A set of enumerators.
TKIND_INTERFACE	A type that has virtual functions, all of which are pure.
TKIND_MODULE	A module which can only have static functions and data (for instance, a DLL).
TKIND_RECORD	A struct with no methods.
TKIND_UNION	A union, all of whose members have offset zero.


VARDESC

A VARDESC structure describes a variable, constant, or data member, and is defined as follows:

typedef struct FARSTRUCT tagVARDESC {

MEMBERID memid;

OLECHAR FAR* lpstrSchema;/* reserved for future use */

union {

/* VAR_PERINSTANCE - the offset of this 	   variable within the instance */

unsigned long oInst;

/* VAR_CONST—the value of the constant */

VARIANT FAR* lpvarValue;

}UNION_NAME(u);

ELEMDESC elemdescVar;

unsigned short wVarFlags;

VARKIND varkind;

} VARDESC


VARFLAGS

The VARFLAGS enumeration is defined as follows:

typedef enum tagVARFLAGS {

VARFLAG_FREADONLY= 1

  , VARFLAG_FSOURCE= 0x2

  , VARFLAG_FBINDABLE= 0x4

  , VARFLAG_FREQUESTEDIT= 0x8

  , VARFLAG_FDISPLAYBIND= 0x10

  , VARFLAG_FDEFAULTBIND= 0x20

  , VARFLAG_FHIDDEN= 0x40

} VARFLAGS;

Value	Description
VARFLAG_READONLY	Assignment to the variable should not be allowed.
VARFLAG_FSOURCE	The variable returns an object that is a source of events.
VARFLAG_FBINDABLE	The variable supports data binding.
VARFLAG_FDISPLAYBIND	The variable is displayed to the user as bindable; that is, VARFLAG_FBINDABLE must also be set.
VARFLAG_FDEFAULTBIND	The variable is the single property that best represents the object. Only one variable in a typeinfo may have this attibute.
VARFLAG_FHIDDEN	The variable should not be displayed to the user in a browser, though it exists and is bindable.


VARKIND

The VARKIND enumeration is defined as follows:

typedef enum tagVARKIND {

VAR_PERINSTANCE,

VAR_STATIC,

VAR_CONST,

VAR_DISPATCH

} VARKIND;

Value	Description
VAR_PERINSTANCE	The variable is a field or member of the type; it exists at a fixed offset within each instance of the type.
VAR_STATIC	There is only one instance of the variable.
VAR_CONST	The VARDESC describes a symbolic constant. There is no memory associated with it.
VAR_DISPATCH	The variable can only be accessed through IDispatch::Invoke.


ITypeInfo::AddressOfMember

HRESULT ITypeInfo::AddressOfMember(memid, invkind, lplpvoid)
MEMBERID memid
INVOKEKIND invkind
VOID FAR* FAR* lplpvoid

Retrieves the addresses of static functions or variables, such as those defined in a DLL.

Parameters

memid

Member ID of the static member whose address is to be retrieved.
The member ID is defined by DISPID.

invkind

Specifies whether the member is a property, and if so, what kind.

lplpvoid

Upon return, points to a pointer to the static member.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
E_OUTOFMEMORY	Out of memory.
E_INVALIDARG	One or more of the arguments is invalid.
TYPE_E_IOERROR	The function could not read from the file.
TYPE_E_WRONGTYPEKIND	Type mismatch.
TYPE_E_INVDATAREAD	The function could not read from the file.
TYPE_E_UNSUPFORMAT	The type library has an old format.
TYPE_E_INVALIDSTATE	The type library could not be opened.
TYPE_E_ELEMENTNOTFOUND	The element was not found.
TYPE_E_DLLFUNCTIONNOTFOUND	The function could not be found in the DLL.
TYPE_E_CANTLOADLIBRARY	The type library or DLL could not be loaded.
Comments

The addresses are valid until the caller releases its reference to the type description. Note that the invkind parameter can be ignored unless the address of a property function is being requested.

If the type description inherits from another type description, this function recurses on the base type description, if necessary, to find the item with the requested member ID.


ITypeInfo::CreateInstance

HRESULT ITypeInfo::CreateInstance(punkOuter, riid, ppvObj)
IUnknown FAR* punkOuter
REFIID riid
VOID FAR* FAR* ppvObj

Creates a new instance of a type that describes a component object class (coclass).

Parameters

punkOuter

A pointer to the controlling IUnknown. If NULL, then a stand-alone instance is created. If valid, then an aggregate object is created.

riid

An ID for the interface the caller will use to communicate with the resulting object.

ppvObj

On return, points to a pointer to an instance of the created object.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
E_OUTOFMEMORY	Out of memory.
TYPE_E_WRONGTYPEKIND	Type mismatch.
E_INVALIDARG	One or more of the arguments is invalid.
E_NOINTERFACE	OLE could not find an implementation of one or more required interfaces.
TYPE_E_UNSUPFORMAT	The type library has an old format.
TYPE_E_INVALIDSTATE	The type library could not be opened.
Other returns	Additional errors may be returned from GetActiveObject or CoCreateInstance.
Comments

For types that describe a component object class (coclass), CreateInstance creates a new instance of the class. Normally CreateInstance calls CoCreateInstance with the type description's GUID. For an Application object, it first calls GetActiveObject. If the application is active, GetActiveObject returns the active object; otherwise, if GetActiveObject fails, CreateInstance calls CoCreateInstance.


ITypeInfo::GetContainingTypeLib

HRESULT ITypeInfo::GetContainingTypeLib(lplptlib, lpindex)
ITypeLib FAR* FAR* lplptlib
unsigned int FAR* lpindex

Retrieves the containing type library and the index of the type description within that type library.

Parameters

lplptlib

Upon return, points to a pointer to the containing type library.

lpindex

Upon return, points to the index of the type description within the containing type library.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
E_OUTOFMEMORY	Out of memory.
E_INVALIDARG	One or more of the arguments is invalid.
E_NOINTERFACE	OLE could not find an implementation of one or more required interfaces.
TYPE_E_IOERROR	The function could not write to the file.
TYPE_E_INVDATAREAD	The function could not read from the file.
TYPE_E_UNSUPFORMAT	The type library has an old format.
TYPE_E_INVALIDSTATE	The type library could not be opened.


ITypeInfo::GetDllEntry

HRESULT ITypeInfo::GetDllEntry(memid, invkind, lpbstrDllName, lpbstrName, lpwOrdinal)
MEMBERID memid
INVOKEKIND invkind
BSTR FAR* lpbstrDllName
BSTR FAR* lpbstrName
unsigned short FAR* lpwOrdinal

Retrieves a description or specification of an entry point for a function in a DLL.

Parameters

memid

ID of the member function whose DLL entry description is to be returned.

invkind

Specifies the kind of member identified by memid. This is important for properties, because one memid can identify up to three separate functions.

lpbstrDllName

If not NULL, the function sets *lpbstrDllName to a BSTR containing the DLL name.

lpbstrName

If not NULL, the function sets *lpbstrName to a BSTR containing the name of the entry point; if the entry point is specified by an ordinal, *lpbstrName is set to NULL.

lpwOrdinal

If not NULL, and if the function is defined by ordinal, then lpwOrdinal is set to point to the ordinal.


Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
E_OUTOFMEMORY	Out of memory.
E_INVALIDARG	One or more of the arguments is invalid.
E_NOINTERFACE	OLE could not find an implementation of one or more required interfaces.
TYPE_E_ELEMENTNOTFOUND	The element was not found.
TYPE_E_IOERROR	The function could not read from the file.
TYPE_E_INVDATAREAD	The function could not read from the file.
TYPE_E_UNSUPFORMAT	The type library has an old format.
TYPE_E_INVALIDSTATE	The type library could not be opened.
TYPE_E_WRONGTYPEKIND	Type mismatch.
Comments

The caller passes in a MEMID representing the member function whose entry description is desired. If the function has a DLL entry point, the name of the DLL containing the function, and either its name or ordinal identifier are placed in the passed-in pointers allocated by the caller. If there is no DLL entry point for the function, an error is returned.

If the type description inherits from another type description, this function recurses on the base type description if necessary, to find the item with the requested member ID.

The caller should use SysFreeString() to free the BSTRs referenced by lpbstrName and lpbstrDllName.


ITypeInfo::GetDocumentation

HRESULT ITypeInfo::GetDocumentation(memid, lpbstrName, lpbstrDocString, lpdwHelpContext, lpbstrHelpFile)
MEMBERID memid
BSTR FAR* lpbstrName
BSTR FAR* lpbstrDocString
unsigned long FAR* lpdwHelpContext
BSTR FAR* lpbstrHelpFile

Retrieves the documentation string, name of the complete Help file path and name, and the context ID for the Help topic for a specified type description.

Parameters

memid

ID of the member whose documentation is to be returned.

lpbstrName

Pointer to a BSTR allocated by the callee into which the name of the specified item is placed. If the caller does not need the item name, lpbstrName can be NULL.

lpbstrDocString

Pointer to a BSTR into which the documentation string for the specified item is placed. If the caller does not need the documentation string, lpbstrDocString can be NULL.

lpdwHelpContext

Pointer to the Help context associated with the specified item. If the caller does not need the Help context, the lpdwHelpContext can be NULL.

lpbstrHelpFile

Pointer to a BSTR into which the fully qualified name of the Help file is placed. If the caller does not need the Help filename, lpbstrHelpFile can be NULL.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
E_OUTOFMEMORY	Out of memory.
E_INVALIDARG	One or more of the arguments is invalid.
TYPE_E_IOERROR	The function could not read from the file.
TYPE_E_ELEMENTNOTFOUND	The element was not found.
TYPE_E_INVDATAREAD	The function could not read from the file.
TYPE_E_UNSUPFORMAT	The type library has an old format.
TYPE_E_INVALIDSTATE	The type library could not be opened.
TYPE_E_ELEMENTNOTFOUND	The element was not found.
Comments

Provides access to the documentation for the member specified by the memid parameter. If the passed-in memid is MEMBERID_NIL, then the documentation for the type description is returned.

If the type description inherits from another type description, this function recurses on the base type description, if necessary, to find the item with the requested member ID.

The caller should use SysFreeString() to free the BSTRs referenced by lpbstrName, lpbstrDocString, and lpbstrHelpFile.


Example

CHECKRESULT(ptypeinfo->GetDocumentation(idMember, &bstrName, NULL, NULL,

NULL));

.

.

.

SysFreeString (bstrName);


ITypeInfo::GetFuncDesc

HRESULT ITypeInfo::GetFuncDesc(index, lplpfuncdesc)
unsigned int index
FUNCDESC FAR* FAR* lplpfuncdesc

Retrieves the FUNCDESC structure containing information about a specified function.

Parameters

index

Index of the function whose description is to be returned. The index should be in the range of 0 to 1 less than the number of functions in this type.

lplpfuncdesc

Upon return, points to a pointer to a FUNCDESC that describes the specified function.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
E_OUTOFMEMORY	Out of memory.
E_INVALIDARG	One or more of the arguments is invalid.
TYPE_E_IOERROR	The function could not read from the file.
TYPE_E_INVDATAREAD	The function could not read from the file.
TYPE_E_UNSUPFORMAT	The type library has an old format.
TYPE_E_INVALIDSTATE	The type library could not be opened.
Comments

Provides access to a FUNCDESC that describes the function with the specified index. The FUNCDESC should be freed with ITypeInfo::ReleaseFuncDesc(). The number of functions in the type is one of the attributes contained in the TYPEATTR structure.


Example

CHECKRESULT(ptypeinfo->GetFuncDesc(i, &pfuncdesc));

idMember = pfuncdesc->elemdescFunc.ID;

CHECKRESULT(ptypeinfo->GetDocumentation(idMember,

        &bstrName, NULL, NULL, NULL));

ptypeinfo->ReleaseFuncDesc(pfuncdesc);


ITypeInfo::GetIDsOfNames

HRESULT ITypeInfo::GetIDsOfNames(rgszNames, cNames, rgmemid)
OLECHAR FAR* FAR* rgszNames
unsigned int cNames
MEMBERID FAR* rgmemid

Maps between member names and member IDs, and parameter names and parameter IDs.

Parameters

rgszNames

Passed-in pointer to an array of names to be mapped.

cNames

Count of the names to be mapped.

rgmemid

Caller-allocated array in which name mappings are placed.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
STG_E_INSUFFICIENTMEMORY	Out of memory.
E_OUTOFMEMORY	Out of memory.
E_INVALIDARG	One or more of the arguments is invalid.
DISP_E_UNKNOWNNAME	One or more of the names could not be found.
DISP_E_UNKNOWNLCID	The LCID could not be found in the OLE DLLs.
TYPE_E_IOERROR	The function could not write to the file.
TYPE_E_INVDATAREAD	The function could not read from the file.
TYPE_E_UNSUPFORMAT	The type library has an old format.
TYPE_E_INVALIDSTATE	The type library could not be opened.
TYPE_E_WRONGTYPEKIND	Type mismatch.


Comments

Maps the name of a member (rgszNames[0]) and its parameters
(rgszNames[1] ...rgszNames[cNames − 1]) to the ID of the member (rgid[0]) and the IDs of the specified parameters (rgid[1] ... rgid[cNames − 1]). Note that the IDs of parameters are 0 for the first parameter in the member function's argument list, 1 for the second, and so on.

If the type description inherits from another type description, this function recurses on the base type description, if necessary, to find the item with the requested member ID.


ITypeInfo::GetImplTypeFlags

HRESULT ITypeInfo:: GetImplTypeFlags(index, pimpltypeflags)
unsigned int index
MEMBERID FAR* pimpltypeflags

Retrieves the IMPLTYPEFLAGS for one implemented interface or base interface in a type description.

Parameters

index

Index of the implemented interface or base interface for which to get the flags.

pimpltypeflags

On return, pointer to the IMPLTYPEFLAGS.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
E_OUTOFMEMORY	Out of memory.
E_INVALIDARG	One or more of the arguments is invalid.
TYPE_E_INVDATAREAD	The function could not read from the file.
TYPE_E_UNSUPFORMAT	The type library has an old format.
TYPE_E_INVALIDSTATE	The type library could not be opened.
TYPE_E_WRONGTYPEKIND	Type mismatch.
Comments

The flags are associated with the act of inheritance, not with the inherited interface.


ITypeInfo::GetMops

HRESULT ITypeInfo::GetMops(memid, lpbstrMops)
MEMBERID memid
BSTR FAR* lpbstrMops

Retrieves marshaling information.

Parameters

memid

Member ID indicating which marshaling information is sought.

lpbstrMops

Upon return, points to a pointer to the opcode string used in marshaling the fields of the structure described by the referenced type description, or NULL if there is no information to return.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
E_OUTOFMEMORY	Out of memory.
E_INVALIDARG	One or more of the arguments is invalid.
TYPE_E_IOERROR	The function could not read from the file.
TYPE_E_UNSUPFORMAT	The type library has an old format.
TYPE_E_INVALIDSTATE	The type library could not be opened.
TYPE_E_ELEMENTNOTFOUND	The element was not found.
TYPE_E_WRONGTYPEKIND	Type mismatch.
Comments

If the passed-in member ID is MEMBERID_NIL, the function returns the opcode string for marshaling the fields of the structure described by the type description. Otherwise, it returns the opcode string for marshaling the function specified by the index.

If the type description inherits from another type description, this function recurses on the base type description, if necessary, to find the item with the requested member ID.


ITypeInfo::GetNames

HRESULT ITypeInfo::GetNames(memid, rgbstrNames, cNameMax, lpcName)
MEMBERID memid
BSTR FAR* rgbstrNames
unsigned int cNameMax
unsigned int FAR* lpcName

Retrieves the variable with the specified member ID, or the name of the property or method and its parameters, corresponding to the specified function ID.

Parameters

memid

ID of member whose name (or names) is to be returned.

rgbstrNames

Pointer to caller-allocated array. On return, each of these lpcName elements is filled in to point to a BSTR containing the name (or names) associated with the member.

cNameMax

Length of the passed-in rgbstrNames array.

lpcName

On return, points to number representing the number of names in rgbstrNames array.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
E_OUTOFMEMORY	Out of memory.
E_INVALIDARG	One or more of the arguments is invalid.
TYPE_E_IOERROR	The function could not read from the file.
TYPE_E_INVDATAREAD	The function could not read from the file.
TYPE_E_UNSUPFORMAT	The type library has an old format.
TYPE_E_INVALIDSTATE	The type library could not be opened.
TYPE_E_WRONGTYPEKIND	Type mismatch.
TYPE_E_ELEMENTNOTFOUND	The element was not found.
Comments

The caller must release the returned BSTR array.

If the member ID identifies a property that is implemented with property functions, the property name is returned.

For property get functions, the names of the function and its parameters are always returned.

For property put and put reference functions, the right side of the assignment is unnamed. If cNameMax is less than is required to return all the names of parameters of a function, then only the names of the first cNameMax − 1 parameters are returned. The names of the parameters are returned in the array in the same order they appear elsewhere in the interface, for example, in the same order they appear in the parameter array associated with the FUNCDESC.

If the type description inherits from another type description, this function recurses on the base type description, if necessary, to find the item with the requested member ID.


ITypeInfo::GetRefTypeInfo

HRESULT ITypeInfo::GetRefTypeInfo(hreftype, lplptinfo)
HREFTYPE hreftype
ITypeInfo FAR* FAR* lplptinfo

If a type description references other type descriptions, this function retrieves the referenced type descriptions.

Parameters

hreftype

Handle to the referenced type description to be returned.

lplptinfo

Points to a pointer to the referenced type description.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
E_OUTOFMEMORY	Out of memory.
E_INVALIDARG	One or more of the arguments is invalid.
TYPE_E_IOERROR	The function could not read from the file.
TYPE_E_INVDATAREAD	The function could not read from the file.
TYPE_E_UNSUPFORMAT	The type library has an old format.
TYPE_E_INVALIDSTATE	The type library could not be opened.
TYPE_E_WRONGTYPEKIND	Type mismatch.
TYPE_E_ELEMENTNOTFOUND	The element was not found.
TYPE_E_REGISTRYACCESS	There was an error accessing the system registration database.
TYPE_E_LIBNOTREGISTERED	The type library was not found in the system registration database.
Comments

On return, the second parameter contains a pointer to a pointer to a type description that is referenced by this type description. A type description must have a reference to each type description that occurs as the type of any of its variables, function parameters, or function return types. For example, if the type of a data member is a record type, the typeinfo for that data member contains the hreftype of a referenced type description. To get a pointer to the type description, the reference is passed to GetRefTypeInfo.


ITypeInfo::GetRefTypeOfImplType

HRESULT ITypeInfo::GetRefTypeOfImplType(index, lphreftype)
unsigned int index
HREFTYPE FAR* lphreftype

If this type description describes a component object class, the function retrieves the type description of the specified implemented interface types. For an interface, GetRefTypeOfImplType returns the type information for inherited interfaces, if any exist.

Parameters

index

Index of the implemented type whose handle is returned. The valid range is 0 to the cImplTypes field in the TYPEATTR structure.

lphreftype

Upon return, points to a handle for the implemented interface (if any). This handle can be passed to ITypeInfo::GetRefTypeInfo to get the type description.


Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
TYPE_E_ELEMENTNOTFOUND	Passed index is outside the range 0 to 1 less than the number of function descriptions.
E_INVALIDARG	One or more of the arguments is invalid.
TYPE_E_IOERROR	The function could not read from the file.
TYPE_E_INVDATAREAD	The function could not read from the file.
TYPE_E_UNSUPFORMAT	The type library has an old format.
TYPE_E_INVALIDSTATE	The type library could not be opened.
TYPE_E_IOERROR	The function could not write to the file.
TYPE_E_INVDATAREAD	The function could not read from the file.
TYPE_E_UNSUPFORMAT	The type library has an old format.
TYPE_E_INVALIDSTATE	The type library could not be opened.
Comments

If you have the TKIND_DISPATCH typeinfo for a dual interface, you can get the TKIND_INTERFACE typeinfo by calling GetRefTypeOfImplType with an Index of −1, and passing the returned lpHRefType handle to GetRefTypeInfo to retrieve the typeinfo.


ITypeInfo::GetTypeAttr

HRESULT ITypeInfo::GetTypeAttr(lplptypeattr)
TYPEATTR FAR* FAR* lplptypeattr

Retrieves a TYPEATTR structure containing the attributes of the type description.

Parameter

lplptypeattr

Upon return, points to a pointer to a structure that contains the attributes of this type description.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
E_OUTOFMEMORY	Out of memory.
E_INVALIDARG	One or more of the arguments is invalid.
TYPE_E_IOERROR	The function could not write to the file.
TYPE_E_INVDATAREAD	The function could not read from the file.
TYPE_E_UNSUPFORMAT	The type library has an old format.
TYPE_E_INVALIDSTATE	The type library could not be opened.
Comments

To free the TYPEATTR structure, use ITypeInfo::ReleaseTypeAttr.

Example

CHECKRESULT(ptypeinfoCur->GetTypeAttr(&ptypeattrCur));

.

.

.

ptypeinfoCur->ReleaseTypeAttr(ptypeattrCur);


ITypeInfo::GetTypeComp

HRESULT ITypeInfo::GetTypeComp(lplpcomp)
ITypeComp FAR* FAR* lplpcomp

Retrieves the ITypeComp interface for the type description, which enables a client compiler to bind to the type description's members.

Parameter

lplpcomp

Upon return, points to a pointer to the ITypeComp of the containing type library.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
E_OUTOFMEMORY	Out of memory.
E_INVALIDARG	One or more of the arguments is invalid.
TYPE_E_IOERROR	The function could not read from the file.
TYPE_E_INVDATAREAD	The function could not read from the file.
TYPE_E_UNSUPFORMAT	The type library has an old format.
TYPE_E_INVALIDSTATE	The type library could not be opened.
TYPE_E_WRONGTYPEKIND	Type mismatch.
Comments

A client compiler can use the ITypeComp interface to bind to members of the type.


ITypeInfo::GetVarDesc

HRESULT ITypeInfo::GetVarDesc(index, lplpvardesc)
unsigned int index
VARDESC FAR* FAR* lplpvardesc

Retrieves a VARDESC structure describing the specified variable.

Parameters

index

Index of the variable whose description is to be returned. The index should be in the range of 0 to 1 less than the number of variables in this type.

lplpvardesc

Upon return, points to a pointer to a VARDESC that describes the specified variable.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
E_OUTOFMEMORY	Out of memory.
E_INVALIDARG	One or more of the arguments is invalid.
TYPE_E_IOERROR	The function could not read from the file.
TYPE_E_INVDATAREAD	The function could not read from the file.
TYPE_E_UNSUPFORMAT	The type library has an old format.
TYPE_E_INVALIDSTATE	The type library could not be opened.
Comments

To free the VARDESC structure, use ReleaseVarDesc.

Example

CHECKRESULT(ptypeinfo->GetVarDesc(i, &pvardesc));

idMember = pvardesc->memid;

CHECKRESULT(ptypeinfo->GetDocumentation(idMember, &bstrName, NULL, NULL,

NULL));

ptypeinfo->ReleaseVarDesc(pvardesc);


ITypeInfo::Invoke

HRESULT ITypeInfo::Invoke(lpvInstance, memid, wFlags, pdispparams, pvargResult, pexcepinfo, puArgErr)
VOID FAR* lpvInstance
MEMBERID memid
unsigned short wFlags
DISPPARAMS FAR* pdispparams
VARIANT FAR* pvargResult
EXCEPINFO FAR* pexcepinfo
unsigned int FAR* puArgErr

Invokes a method or accesses a property of an object that implements the interface described by the type description.

Parameters

lpvInstance

Pointer to an instance of the interface described by this type description.

memid

Identifies the interface member.

wFlags

Flags describing the context of the invoke call, as follows:

Value	Description
DISPATCH_METHOD	The member was accessed as a method. If there is ambiguity, both this and the DISPATCH_PROPERTYGET flag may be set.
DISPATCH_PROPERTYGET	The member is being retrieved as a property or data member.
DISPATCH_PROPERTYPUT	The member is being changed as a property or data member.
DISPATCH_PROPERTYPUTREF	The member is being changed by using a reference assignment, rather than a value assignment. This value is only valid when the property accepts a reference to an object.
pdispparams

Points to a structure containing an array of arguments, an array of DISPIDs for named arguments, and counts of the number of elements in each array.

pvargResult

Should be NULL if the caller expects no result; otherwise, it should be a pointer to the location at which the result is to be stored. If wFlags specifies DISPATCH_PROPERTYPUT or DISPATCH_PROPERTYPUTREF, pvargResult is ignored.

pexcepinfo

Points to an exception information structure, which is filled in only if DISP_E_EXCEPTION is returned. If pexcepinfo is NULL on input, only an HRESULT error will be returned.

puArgErr

If Invoke returns DISP_E_TYPEMISMATCH, puArgErr indicates the index (within rgvarg) of the argument with incorrect type. If more than one argument has an error, puArgErr indicates only the first argument with an error. Note that arguments in pdispparams->rgvarg appear in reverse order, so the first argument is the one having the highest index in the array. Can't be NULL.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
E_INVALIDARG	One or more of the arguments is invalid.
DISP_E_EXCEPTION	The member being invoked has returned an error HRESULT. If the member implements IErrorInfo, details are available in the error object. Otherwise, the pexcepinfo parameter contains details.
TYPE_E_IOERROR	The function could not read from the file.
TYPE_E_INVDATAREAD	The function could not read from the file.
TYPE_E_UNSUPFORMAT	The type library has an old format.
TYPE_E_REGISTRYACCESS	There was an error accessing the system registration database.
TYPE_E_LIBNOTREGISTERED	The type library was not found in the system registration database.
TYPE_E_INVALIDSTATE	The type library could not be opened.
TYPE_E_WRONGTYPEKIND	Type mismatch.
TYPE_E_ELEMENTNOTFOUND	The element was not found.
TYPE_E_BADMODULEKIND	The module does not support Invoke.
Other returns	Any of the IDispatch::Invoke errors may also be returned.
Comments

Use ITypeInfo::Invoke to access a member of an object or invoke a method that implements the interface described by this type description. For objects that support the IDispatch interface, Invoke can be used to implement IDispatch::Invoke.

ITypeInfo::Invoke takes a pointer to an instance of the class. Otherwise, its parameters are the same as IDispatch::Invoke, except that ITypeInfo::Invoke omits the REFIID and LCID parameters. When called, ITypeInfo::Invoke performs the actions described by the IDispatch::Invoke parameters on the specified instance.

For VTBL interface members, ITypeInfo::Invoke passes the LCID of the typeinfo into parameters tagged with the lcid attribute, and the returned value into the retval parameter.

If the type description inherits from another type description, this function recurses on the base type description if necessary, to find the item with the requested member ID.


ITypeInfo::ReleaseFuncDesc

VOID ITypeInfo::ReleaseFuncDesc(lpfuncdesc)
FUNCDESC FAR* lpfuncdesc

Releases a FUNCDESC previously returned by GetFuncDesc.

Parameter

lpfuncdes

Pointer to the FUNCDESC to be freed.

Comments

ReleaseFuncDesc releases a FUNCDESC that was returned through ITypeInfo::GetFuncDesc.

Example

ptypeinfoCur->ReleaseFuncDesc(pfuncdesc);


ITypeInfo::ReleaseTypeAttr

VOID ITypeInfo::ReleaseTypeAttr(lptypeattr)
TYPEATTR FAR* lptypeattr

Releases a TYPEATTR previously returned by GetTypeAttr.

Parameter

lptypeattr

Pointer to the TYPEATTR to be freed.

Comments

ReleaseTypeAttr releases a TYPEATTR that was returned through ITypeInfo::GetTypeAttr.


ITypeInfo::ReleaseVarDesc

VOID ITypeInfo::ReleaseVarDesc(lpvardesc)
VARDESC FAR* lpvardesc

Releases a VARDESC previously returned by GetVarDesc.

Parameter

lpvardesc

Pointer to the VARDESC to be freed.

Comments

ReleaseVarDesc releases a VARDESC that was returned through ITypeInfo::GetVarDesc.

Example

VARDESC     FAR *pvardesc;

CHECKRESULT(ptypeinfo->GetVarDesc(i, &pvardesc));

idMember = pvardesc->memid;

CHECKRESULT(ptypeinfo->GetDocumentation(idMember, &bstrName, NULL, NULL, 	NULL));

ptypeinfo->ReleaseVarDesc(pvardesc);


ITypeComp Interface

Implemented by	Used by	Header filename
OLEAUT32.DLL (32-bit systems) TYPELIB.DLL (16-bit systems)	Tools that compile references to objects contained in type libraries.	OLEAUTO.H DISPATCH.H
Binding is the process of mapping names to types and type members. The ITypeComp interface provides a fast way to access information that compilers need when binding to and instantiating structures and interfaces.


Using Structures and Enumerations with the ITypeComp Interface

The ITypeComp interface uses the following structures and enumerations:


BINDPTR

A union containing a pointer to a FUNCDESC, VARDESC, or an ITypeComp interface.

typedef union tagBINDPTR {

FUNCDESC FAR* lpfuncdesc;

VARDESC FAR* lpvardesc;

ITypeComp FAR* lptcomp;

} BINDPTR;


DESCKIND

Identifies the type of the type description being bound to.

typedef enum tagDESCKIND {

DESCKIND_NONE,

DESCKIND_FUNCDESC,

DESCKIND_VARDESC,

DESCKIND_TYPECOMP,

DESCKIND_IMPLICITAPPOBJ

} DESCKIND;

Comments

Value	Description
DESCKIND_NONE	No match was found.
DESCKIND_FUNCDESC	A FUNCDESC was returned.
DESCKIND_VARDESC	A VARDESC was returned.
DESCKIND_TYPECOMP	A TYPECOMP was returned.
DESCKIND_IMPLICITAPPOBJ	An IMPLICITAPPOBJ was returned.


ITypeComp::Bind

HRESULT ITypeComp::Bind(szName, lHashVal, wFlags, lplptinfo, lpdesckind, lpbindptr)
OLECHAR FAR* szName
unsigned long lHashVal
unsigned short wFlags
ITypeInfo FAR* FAR* lplptinfo
DESCKIND FAR* lpdesckind
BINDPTR FAR* lpbindptr

Maps a name to a member of a type, or binds global variables and functions contained in a type library.

Parameters

szName

Name to be bound.

lHashVal

Hash value for the name computed by LHashValOfNameSys.

wFlags

Flags word containing one or more of the INVOKE flags defined in the INVOKEKIND enumeration. Specifies whether the name was referenced as a method or as a property. When binding to a variable, specify the INVOKE_PROPERTYGET flag. Specify 0 to bind to any type of member.

lplptinfo

If a FUNCDESC or VARDESC was returned, then lplptinfo points to a pointer to the type description that contains the item to which it is bound.

lpdesckind

Pointer to a DESCKIND enumerator that indicates whether the name bound to a VARDESC, FUNCDESC, or TYPECOMP. Points to DESCKIND_NONE if there was no match.

lpbindptr

Upon return, contains a pointer to the bound-to VARDESC, FUNCDESC, or ITypeComp.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
E_OUTOFMEMORY	Out of memory.
E_INVALIDARG	One or more of the arguments is invalid.
TYPE_E_IOERROR	The function could not read from the file.
TYPE_E_INVDATAREAD	The function could not read from the file.
TYPE_E_UNSUPFORMAT	The type library has an old format.
TYPE_E_INVALIDSTATE	The type library could not be opened.
TYPE_E_AMBIGUOUSNAME	More than one instance of this name occurs in the type library.
Comments

Used for binding to the variables and methods of a type, or for binding to the global variables and methods in a type library. The returned DESCKIND pointer lpdesckind indicates whether the name was bound to a VARDESC, a FUNCDESC, or an ITypeComp instance. The returned lpbindptr points to the VARDESC, FUNCDESC, or ITypeComp.

If a data member or method is bound to, then lplptinfo points to the type description that contains the method or data member.

If Bind binds the name to a nested binding context, it returns a pointer to an ITypeComp instance in lpbindptr and a NULL type description pointer in lplptinfo. For example, if you pass the name of a type description for a module (TKIND_MODULE), enumeration (TKIND_ENUM), or coclass (TKIND_COCLASS) Bind returns the ITypeComp instance of the type description for the module, enumeration, or coclass. This feature supports languages like Visual Basic that allow references to the members of a type description to be qualified by the name of the type description. For example, a function in a module can be referenced by modulename.functionname.

The members of TKIND_ENUM, TKIND_MODULE, and TKIND_COCLASS types marked as Application objects can be directly bound to from ITypeComp, without specifying the name of the module. The ITypeComp of a coclass defers to the ITypeComp of its default interface.

As with other methods of ITypeComp, ITypeInfo, and ITypeLib, the calling code is responsible for releasing the returned object instances or structures. If a VARDESC or FUNCDESC is returned, the caller is responsible for deleting it via the returned type description and releasing the type description instance itself; otherwise, if an ITypeComp instance is returned, the caller must release it.

Special rules apply if you call a type library's Bind method, passing it the name of a member of an Application object class (that is, a class that has the TYPEFLAG_FAPPOBJECT flag set). In this case, Bind returns DESCKIND_IMPLICITAPPOBJ in lpdesckind, a VARDESC that describes the Application object in lpbindptr, and the ITypeInfo of the Application object class in lplptinfo. To bind to the object, you must call ITypeInfo::GetTypeComp to get the ITypeComp of the Application object class, and then reinvoke its Bind method with the name initially passed to the type library's ITypeComp.

The caller should use the returned ITypeInfo pointer (lplptinfo) to get the address of the member.

Note that the wflags parameter is the same as the wflags parameter in IDispatch::Invoke.


ITypeComp::BindType

HRESULT ITypeComp::BindType(szName, lHashVal, lplpitinfo, lplpitcomp
OLECHAR FAR* szName
unsigned long lHashVal
ITypeInfo FAR* FAR* lplptinfo
ITypeComp FAR* FAR* lplptcomp

Binds to the type descriptions contained within a type library.

Parameters

szName

Name to be bound.

lHashVal

Hash value for the name computed by LHashValOfName.

lplptinfo

Upon return, contains a pointer to a pointer to an ITypeInfo of the type to which the name was bound.

lplptcomp

 Reserved for future use. Pass NULL.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
E_OUTOFMEMORY	Out of memory.
E_INVALIDARG	One or more of the arguments is invalid.
TYPE_E_IOERROR	The function could not read from the file.
TYPE_E_INVDATAREAD	The function could not read from the file.
TYPE_E_UNSUPFORMAT	The type library has an old format.
TYPE_E_INVALIDSTATE	The type library could not be opened.
TYPE_E_AMBIGUOUSNAME	More than one instance of this name occurs in the type library.


Comments

Used for binding a type name to the ITypeInfo that describes the type. This function is invoked on the ITypeComp returned by ITypeLib::GetTypeComp to bind to types defined within that library. It could also be used in the future for binding to nested types.


Type Compilation Functions

The type compilation functions are:

LHashValOfName
LHashValOfNameSys


LHashValOfName

unsigned long LHashValOfName(lcid, szName)
LCID lcid
OLECHAR FAR* szName

Computes a hash value for a name that can then be passed to ITypeComp::Bind, ITypeComp::BindType, ITypeLib::FindName, or ITypeLib::IsName.

Parameters

lcid

The locale ID for the string.

szName

String whose hash value is to be computed.

Return Value

A 32-bit hash value representing the name passed in.

Comments

This function is equivalent to LHashValOfNameSys. The OLEAUTO.H header file contains macros that define LHashValOfName as LHashValOfNameSys with the target operating system (syskind), based on your build preprocessor flags.

LHashValOfName computes a 32-bit hash value for a name which can then be passed to ITypeComp::Bind, ITypeComp::BindType, ITypeLib::FindName, or ITypeLib::IsName. The returned hash value is independent of the case of the characters in szName as long as the language of the name is one of the languages supported by the OLE National Language Specification API. Specifically, for any two strings, if those strings match when a case-insensitive comparison is done using any language, then they will produce the same hash value.


LHashValOfNameSys

unsigned long LHashValOfName(syskind, lcid, szName)
SYSKIND syskind
LCID lcid
OLECHAR FAR* szName

Computes a hash value for a name that can then be passed to ITypeComp::Bind, ITypeComp::BindType, ITypeLib::FindName, or ITypeLib::IsName.

Parameters

syskind

The SYSKIND of the target operating system.

lcid

The locale ID for the string.

szName

String whose hash value is to be computed.

Return Value

A 32-bit hash value representing the name passed in.


Type Library Loading and Registration Functions

The type library loading and registration functions are:

LoadTypeLib
LoadRegTypeLib
RegisterTypeLib
QueryPathOfRegTypeLib


LoadTypeLib

HRESULT LoadTypeLib(szFileName, lplptlib)
OLECHAR FAR* szFileName
ITypeLib FAR* FAR* lplptlib

Loads and registers a type library.

Parameters

szFileName

Contains the name of the file from which LoadTypeLib should attempt to load a type library.

lplptlib

On return, contains a pointer to a pointer to the loaded type library.


Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
E_OUTOFMEMORY	Out of memory.
E_INVALIDARG	One or more of the arguments is invalid.
TYPE_E_IOERROR	The function could not write to the file.
TYPE_E_INVALIDSTATE	The type library could not be opened.
TYPE_E_INVDATAREAD	The function could not read from the file.
TYPE_E_UNSUPFORMAT	The type library has an old format.
TYPE_E_INVALIDSTATE	The type library could not be opened.
TYPE_E_UNKNOWNLCID	The LCID could not be found in the OLE support DLLs.
TYPE_E_CANTLOADLIBRARY	The type library or DLL could not be loaded.
Other returns	All FACILITY_STORAGE errors may be returned.
Comments

LoadTypeLib loads and registers a type library (usually created with MkTypLib) that is stored in the specified file. If szFileName specifies only a filename, with no path, LoadTypeLib searches for the file and proceeds as follows:

•	If the file is a stand-alone type library implemented by TYPELIB.DLL, the library is loaded directly.

•	If the file is a DLL or .EXE, the file is loaded. By default, the type library is extracted from the first resource of type ITypeLib. To load a different type library resource, append an integer index to szFileName. For example:

LoadTypeLib("C:\MONTANA\EXE\MFA.EXE\3", lplptlib)

This statement loads the type library resource 3 from the file MFA.EXE.

•	If the file is none of the above, the filename is parsed into a moniker (an object that represents a file-based link source), then bound to the moniker. This approach allows LoadTypeLib to be used on foreign type libraries, including in-memory type libraries. Foreign type libraries can't reside in a DLL or .EXE file. See OLE 2 Programmer's Reference, Vol. 1 for more information on monikers.

If the type library is already loaded, LoadTypeLib increments the type library's reference count and returns a pointer to the type library.


LoadRegTypeLib

HRESULT LoadRegTypeLib(guid, wVerMajor, wVerMinor, lcid, lplptlib)
REFGUID guid
unsigned short wVerMajor
unsigned short wVerMinor
LCID lcid
ITypeLib FAR* FAR* lplptlib

Uses registry information to load a type library.

Parameters

guid

ID of the library being loaded.

wVerMajor

Major version number of library being loaded.

wVerMinor

Minor version number of library being loaded.

lcid

National language code of library being loaded.

lplptlib

On return, points to a pointer to the loaded type library.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
E_OUTOFMEMORY	Out of memory.
E_INVALIDARG	One or more of the arguments is invalid.
TYPE_E_IOERROR	The function could not read from the file.
TYPE_E_INVALIDSTATE	The type library could not be opened.
TYPE_E_INVDATAREAD	The function could not read from the file.
TYPE_E_UNSUPFORMAT	The type library has an old format.
TYPE_E_INVALIDSTATE	The type library could not be opened.
TYPE_E_UNKNOWNLCID	The passed in LCID could not be found in the OLE support DLLs.
TYPE_E_CANTLOADLIBRARY	The type library or DLL could not be loaded.
Other returns	All FACILITY_STORAGE and system registry errors may also be returned.


Comments

LoadRegTypeLib defers to LoadTypeLib to load the file.

LoadRegTypeLib compares the requested version numbers against those found in the system registry and takes one of the following actions:

•	If one of the registered libraries exactly matches both the requested major and minor version numbers, then that type library is loaded.

•	If one or more registered type libraries exactly match the requested major version number and have a greater minor version number than that requested, the one with the greatest minor version number is loaded.

•	If none of the registered type libraries exactly match the requested major version number or if none of those which do exactly match the major version number also have a minor version number greater than or equal to the requested minor version number, then LoadRegTypeLib returns an error.


RegisterTypeLib

HRESULT RegisterTypeLib(ptlib, szFullPath, szHelpDir)
ITypeLib FAR* ptlib
OLECHAR FAR* szFullPath
OLECHAR FAR* szHelpDir

Adds information about a type library to the system registry.

Parameters

ptlib

Pointer to the type library being registered.

szFullPath

Fully qualified path specification for the type library being registered.

szHelpDir

Directory in which the Help file for the library being registered can be found. May be NULL.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
E_OUTOFMEMORY	Out of memory.
E_INVALIDARG	One or more of the arguments is invalid.
TYPE_E_IOERROR	The function could not write to the file.
TYPE_E_REGISTRYACCESS	The system registration database could not be opened.
TYPE_E_INVALIDSTATE	The type library could not be opened.
Comments

RegisterTypeLib can be used during application initialization to correctly register the application's type library.

In addition to filling in a complete registry entry under the TypeLib key, RegisterTypeLib adds entries for each of the dispinterfaces and OLE Automation-compatible interfaces, including dual interfaces. This information is required in order to create instances of these interfaces.


QueryPathOfRegTypeLib

HRESULT QueryPathOfRegTypeLib(guid, wVerMajor, wVerMinor, lcid, lpBstrPathName)
REFGUID guid
unsigned short wVerMajor
unsigned short wVerMinor
LCID lcid
LPBSTR lpBstrPathName

Retrieves the path of a registered type library.

Parameters

guid

ID of the library whose path is to be queried.

wVerMajor

Major version number of the library whose path is to be queried.

wVerMinor

Minor version number of the library whose path is to be queried.

lcid

National language code for the library whose path is to be queried.

lpBstrPathName

Caller-allocated BSTR in which the type library name is returned.

Return Value

The SCODE obtained from the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success
Comments

Returns the fully qualified filename specified for the type library in the registry. The caller allocates the BSTR that is passed in, and must free it after use.


Type Building Interfaces

The type building interfaces, ICreateTypeInfo and ICreateTypeLib, are used to build tools that automate the process of generating type descriptions and creating type libraries. The MkTypLib tool, for example, uses these interfaces to create type libraries. See Chapter 7, "MkTypLib and Object Description Language," for more information on MkTypLib.

Generally, you do not need to write custom implementations of these interfaces; MkTypLib itself uses the default implementations, which are returned by the CreateTypeLib function. If you want to create tools similar to MkTypLib, calling the default implementations should suffice.

Implemented by	Used by	Header filename	Import library name
OLEAUT32.DLL (32-bit systems) TYPELIB.DLL (16-bit systems)	Applications that expose programmable objects.	OLEAUTO.H DISPATCH.H	OLEAUT32.LIB TYPELIB.LIB


ICreateTypeInfo Interface

The type building interfaces include the following member functions:

Interface	Member name	Purpose
ICreateTypeInfo	AddFuncDesc	Adds a function description as a type description.
	AddImplType	Specifies an inherited interface.
	AddRefTypeInfo	Adds a type description to those referenced by the type description being created.
	AddVarDesc	Adds a data member description as a type description.
	DefineFuncAsDllEntry	Associates a DLL entry point with a function that has a specified index.
	LayOut	Assigns VTBL offsets for virtual functions and instance offsets for per-instance data members.
	SetAlignment	Specifies data alignment for types of TKIND_RECORD.
	SetDocString	Sets the documentation string displayed by type browsers.
	SetFuncAndParamNames	Sets the function name and names of its parameters.
	SetFuncDocString	Sets the documentation string for a function.
	SetFuncHelpContext	Sets the Help context for a function.
	SetGuid	Sets the globally unique ID for the type library.
	SetHelpContext	Sets the Help context of the type description.
	SetImplTypeFlags	Sets the attributes for an implemented or inherited interface of a type.
	SetMops	Sets the opcode string for a type description.
	SetSchema	Reserved for future use.
	SetTypeDescAlias	Sets the type description for which this type description is an alias, if TYPEKIND=TKIND_ALIAS.
	SetTypeFlags	Sets type flags of the type description being created.
	SetTypeIdlDesc	Reserved for future use.
	SetVarDocString	Sets the documentation string for a variable.
	SetVarHelpContext	Sets the Help context for a variable.
	SetVarName	Sets the name of a variable.
	SetVersion	Sets version numbers for the type description.
ICreateTypeLib	CreateTypeInfo	Creates a new type description instance within the type library.
	SaveAllChanges	Saves the ICreateTypeLib instance.
	SetDocString	Sets the documentation string for the type library.
	SetHelpContext	Sets the Help context for general information about the type library in the Help file.
	SetHelpFileName	Sets the Help filename.
	SetLcid	Sets the locale code indicating the national language associated with the library.
	SetLibFlags	Sets library flags, such as LIBFLAG_FRESTRICTED.
	SetName	Sets the name of the type library.
	SetGuid	Sets the globally unique ID for the type library.
	SetVersion	Sets major and minor version numbers for the type library.
Library creation functions	CreateTypeLib	Gives access to a new object instance that supports the ICreateTypeLib interface.


Enumerations and Structures

The type building interfaces use the following structures and enumerations.


Using LIBFLAGS with the ICreateTypeInfo Interface

The LIBFLAGS enumeration defines flags that apply to type libraries. LIBFLAGS is defined as follows:

typedef enum tagLIBFLAGS {

LIBFLAG_FRESTRICTED = 0x01

, LIBFLAG_FCONTROL = 0x02

, LIBFLAG_FHIDDEN = 0x04

} LIBFLAGS;

Value	Description
LIBFLAG_FCONTROL	The type library describes controls and should not be displayed in type browsers intended for nonvisual objects.
LIBFLAG_FRESTRICTED	The type library is restricted and should not be displayed to users.
LIBFLAG_FHIDDEN	The type library should not be displayed to users, although its use is not restricted. To be used by controls; hosts should create a new type library that wraps the control with extended properties.


Using SYSKIND with the ICreateTypeInfo Interface

The SYSKIND identifies the target operating system platform.

typedef enum tagSYSKIND[

SYS_WIN16,

SYS_WIN32,

SYS_MAC

] SYSKIND;

Value	Description
SYS_WIN16	The target operating system for the type library is 16-bit Windows systems. By default, data members are packed.
SYS_WIN32	The target operating system for the type library is 32-bit Windows systems. By default, data members are naturally aligned (for example, 2-byte integers are aligned on even-byte boundaries; 4-byte integers are aligned on quad-word boundaries, and so forth).
SYS_MAC	The target operating system for the type library is Macintosh. By default, all data members are aligned on even-byte boundaries.


ICreateTypeInfo::AddFuncDesc

HRESULT ICreateTypeInfo::AddFuncDesc(index, lpFuncDesc)
unsigned int index
FUNCDESC FAR* lpFuncDesc


Parameters

index

Index of the new FUNCDESC in the type information.

lpFuncDesc

Pointer to a FUNCDESC structure that describes the function. The bstrIDLInfo field in the FUNCDESC should be set to NULL for future compatibility.

Return Value

The SCODE value of the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
STG_E_INSUFFICIENTMEMORY	Out of memory.
E_OUTOFMEMORY	Out of memory.
E_INVALIDARG	One or more of the arguments is invalid.
E_ACCESSDENIED	Can't write to destination.
TYPE_E_WRONGTYPEKIND	Type mismatch.
Comments

AddFuncDesc is used to add a function description to the type description. The index specifies the order of the functions within the type information. The first function has an index of zero. If an index is specified that exceeds one less than the number of functions in the type information, then an error is returned. Calling this function does not pass ownership of the FUNCDESC structure to ICreateTypeInfo. Therefore, the caller must still deallocate the FUNCDESC structure.

The passed-in VTBL field (oVft) of the FUNCDESC is ignored. This attribute is set when ICreateTypeInfo::LayOut is called.

AddFuncDesc uses the passed-in member ID fields within each FUNCDESC for classes with TYPEKIND = TKIND_DISPATCH or TKIND_INTERFACE. If the member IDs are set to MEMID_NIL, AddFuncDesc assigns member IDs to the functions. Otherwise, the member ID fields within each FUNCDESC are ignored.

Note that any HREFTYPE fields in the FUNCDESC structure must have been produced by the same instance of ITypeInfo for which AddFuncDesc is called.

The get and put accessor functions for the same property must have the same DISPID.


ICreateTypeInfo::AddImplType

HRESULT ICreateTypeInfo::AddImplType(index, hreftype)
unsigned int index
HREFTYPE hreftype

Parameters

index

Index of the implementation class to be added; specifies the order of the type relative to the other type.

hreftype

Handle to the referenced type description obtained from AddRefType description.

Return Value

The SCODE value of the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
STG_E_INSUFFICIENTMEMORY	Out of memory.
E_OUTOFMEMORY	Out of memory.
E_ACCESSDENIED	Can't write to destination.
TYPE_E_WRONGTYPEKIND	Type mismatch.
Comments

AddImplType is used only for specifying an inherited interface or an interface implemented by a component object class.


ICreateTypeInfo::AddRefTypeInfo

HRESULT ICreateTypeInfo::AddRefTypeInfo(lptinfo, lphreftype)
ITypeInfo FAR* lptinfo
HREFTYPE FAR* lphreftype

Parameters

lptinfo

Pointer to the type description to be referenced.

lphreftype

On return, pointer to the handle that this type description associates with the referenced type information.


Return Value

The SCODE value of the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
STG_E_INSUFFICIENTMEMORY	Out of memory.
E_OUTOFMEMORY	Out of memory.
E_INVALIDARG	One or more of the arguments is invalid.
E_ACCESSDENIED	Can't write to destination.
TYPE_E_WRONGTYPEKIND	Type mismatch.
Comments

Adds a type description to those referenced by the type description being created. The second parameter returns a pointer to the handle of the added type information. If AddRefTypeInfo has previously been called for the same type information, the index that was returned by the previous call is returned in lphreftype.


ICreateTypeInfo::AddVarDesc

HRESULT ICreateTypeInfo::AddVarDesc(index, lpVarDesc)
unsigned int index
VARDESC FAR* lpVarDesc

Parameters

index

Index of the variable or data member to be added to the type description.

lpVarDesc

Pointer to the variable or data member description to be added.

Return Value

The SCODE value of the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
STG_E_INSUFFICIENTMEMORY	Out of memory.
E_OUTOFMEMORY	Out of memory.
E_INVALIDARG	One or more of the arguments is invalid.
E_ACCESSDENIED	Can't write to destination.
TYPE_E_WRONGTYPEKIND	Type mismatch.


Comments

Adds a variable or data member description to the type description. The index specifies the order of the variables. The first variable has an index of zero. ICreateTypeInfo::AddVarDesc returns an error if the specified index is greater than the number of variables currently in the type information. Calling this function does not pass ownership of the VARDESC structure to ICreateTypeInfo. Note that the Instance field (oInst) of the VARDESC structure is ignored; this attribute is set when ICreateTypeInfo::LayOut is called. Also, the member ID fields within the VARDESCs are ignored unless the TYPEKIND of the class is TKIND_DISPATCH.

Any HREFTYPE fields in the VARDESC structure must have been produced by the same instance of ITypeInfo for which AddVarDesc is called.

AddVarDesc ignores the contents of the idldesc field of the ELEMDESC.


ICreateTypeInfo::DefineFuncAsDllEntry

HRESULT ICreateTypeInfo::DefineFuncAsDllEntry(index, szDllName, szProcName)
unsigned int index
OLECHAR FAR* szDllName
OLECHAR FAR* szProcName

Parameters

index

Index of the function.

szDllName

Name of the DLL containing the entry point.

szProcName

Name of the entry point or an ordinal (if the high word is zero).

Return Value

The SCODE value of the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
STG_E_INSUFFICIENTMEMORY	Out of memory.
E_OUTOFMEMORY	Out of memory.
E_INVALIDARG	One or more of the arguments is invalid.
TYPE_E_ELEMENTNOTFOUND	The element can't be found.
TYPE_E_WRONGTYPEKIND	Type mismatch.


Comments

Associates a DLL entry point with the function that has the specified index. If the high word of szProcName is zero, then the low word must contain the ordinal of the entry point; otherwise, szProcName points to the zero-terminated name of the entry point.


ICreateTypeInfo::LayOut

HRESULT ICreateTypeInfo::LayOut()

Return Value

The SCODE value of the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
STG_E_INSUFFICIENTMEMORY	Out of memory.
E_OUTOFMEMORY	Out of memory.
E_ACCESSDENIED	Can't write to destination.
TYPE_E_UNDEFINEDTYPE	Bound to unrecognized type.
TYPE_E_INVALIDSTATE	The type library's state is not valid for this operation.
TYPE_E_WRONGTYPEKIND	Type mismatch.
TYPE_E_ELEMENTNOTFOUND	The element can't be found.
TYPE_E_AMBIGUOUSNAME	More than one item exists with this name.
TYPE_E_SIZETOOBIG	The type information is too large to lay out.
TYPE_E_TYPEMISMATCH	Type mismatch.
Comments

LayOut assigns VTBL offsets for virtual functions and instance offsets for per-instance data members, and creates the two typeinfos for dual interfaces. LayOut also assigns member ID numbers to the functions and variables unless the TYPEKIND of the class is TKIND_DISPATCH. LayOut should be called after all members of the type information are defined and before the type library is saved.

Use SaveAllChanges to save the type information after calling LayOut. Don't call other members of the ICreateTypeInfo interface after calling LayOut.

Note that different implementations of ICreateTypeInfo or other interfaces that create type information are free to assign any member ID numbers, provided that all members, including inherited members, have unique IDs.


ICreateTypeInfo::SetAlignment

HRESULT ICreateTypeInfo::SetAlignment(cbAlignment)
unsigned short cbAlignment

Parameters

cbAlignment

Alignment method for the type. A value of 0 indicates alignment on the 64K boundary; 1 indicates no special alignment. For other values, n indicates alignment on byte n.

Return Value

The SCODE value of the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
STG_E_INSUFFICIENTMEMORY	Out of memory.
E_OUTOFMEMORY	Out of memory.
E_ACCESSDENIED	Can't write to destination.
TYPE_E_INVALIDSTATE	The type library's state is not valid for this operation.
Comments

Specifies the data alignment for an item of TYPEKIND=TKIND_RECORD. The alignment is the minimum of the natural alignment (for example, byte data on byte boundaries, word data on word boundaries, and so on) and the alignment denoted by cbAlignment.


ICreateTypeInfo::SetDocString

HRESULT ICreateTypeInfo::SetDocString(szDoc)
OLECHAR FAR* szDoc

Parameters

szDoc

Pointer to the documentation string.


Return Value

The SCODE value of the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
STG_E_INSUFFICIENTMEMORY	Out of memory.
E_OUTOFMEMORY	Out of memory.
E_ACCESSDENIED	Can't write to destination.
TYPE_E_INVALIDSTATE	The type library's state is not valid for this operation.
Comments

Sets the documentation string displayed by type browsers. The documentation string is a brief description of the type description being created.


ICreateTypeInfo::SetFuncAndParamNames

HRESULT ICreateTypeInfo::SetFuncAndParamNames(index, rgszNames, cNames)
unsigned int index
OLECHAR FAR* FAR* rgszNames
unsigned int cNames

Parameters

index

Index of the function whose function name and parameter names are to be set.

rgszNames

Array of pointers to names. The first element is the function name; subsequent elements are names of parameters.

cNames

Number of elements in the rgszNames array.


Return Value

The SCODE value of the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
STG_E_INSUFFICIENTMEMORY	Out of memory.
E_OUTOFMEMORY	Out of memory.
E_INVALIDARG	One or more of the arguments is invalid.
E_ACCESSDENIED	Can't write to destination.
TYPE_E_ELEMENTNOTFOUND	The element can't be found.
Comments

Sets the name of a function and the names of its parameters to the names in the array of pointers rgszNames. You only need to use SetFuncAndParamNames once for each property, because all property accessor functions are identified by one name. For property functions, provide names for the named parameters only; the last parameter for put and putref accessor functions is unnamed.


ICreateTypeInfo::SetFuncDocString

HRESULT ICreateTypeInfo::SetFuncDocString(index, szDocString)
unsigned int index
OLECHAR FAR* szDocString

Parameters

index

Index of the function.

szDocString

Pointer to the documentation string.

Return Value

The SCODE value of the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
STG_E_INSUFFICIENTMEMORY	Out of memory.
E_OUTOFMEMORY	Out of memory.
E_INVALIDARG	One or more of the arguments is invalid.
E_ACCESSDENIED	Can't write to destination.
TYPE_E_ELEMENTNOTFOUND	The element can't be found.


Comments

Sets the documentation string for the function with the specified index. The documentation string is a brief description of the function intended for use by tools like type browsers. You only need to use SetFuncDocString once for each property, because all property accessor functions are identified by one name.


ICreateTypeInfo::SetFuncHelpContext

HRESULT ICreateTypeInfo::SetFuncHelpContext(index, dwHelpContext)
unsigned int index
unsigned long dwHelpContext

Parameters

index

Index of the function.

dwHelpContext

A Help context ID for the Help topic.

Return Value

The SCODE value of the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
STG_E_INSUFFICIENTMEMORY	Out of memory.
E_OUTOFMEMORY	Out of memory.
E_ACCESSDENIED	Can't write to destination.
TYPE_E_ELEMENTNOTFOUND	The element can't be found.
E_INVALIDARG	One or more of the arguments is invalid.
Comments

Sets the Help context for the function with the specified index. You only need to use SetFuncHelpContext once for each property, because all property accessor functions are identified by one name.


ICreateTypeInfo::SetGuid

HRESULT ICreateTypeInfo::SetGuid(guid)
REFGUID guid

Parameters

guid

Globally unique ID to be associated with the type description.


Return Value

The SCODE value of the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
STG_E_INSUFFICIENTMEMORY	Out of memory.
E_OUTOFMEMORY	Out of memory.
E_ACCESSDENIED	Can't write to destination.
Comments

Sets the globally unique ID (GUID) associated with the type description. For an interface, this is an interface ID; for a coclass, it is a class ID. See Chapter 7, "MkTypLib and Object Description Language," for information on GUIDs.


ICreateTypeInfo::SetHelpContext

HRESULT ICreateTypeInfo::SetHelpContext(dwHelpContext)
unsigned long dwHelpContext

Parameters

dwHelpContext

Handle to the Help context.

Return Value

The SCODE value of the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
STG_E_INSUFFICIENTMEMORY	Out of memory.
E_OUTOFMEMORY	Out of memory.
E_INVALIDARG	One or more of the arguments is invalid.
E_ACCESSDENIED	Can't write to destination.
Comments

Sets the Help context of the type information.


ICreateTypeInfo::SetImplTypeFlags

HRESULT ICreateTypeInfo::SetImplTypeFlags(index, impltypeflags)
unsigned int index
int impltypeflags

Parameters

index

Index of the interface for which to set type flags.

impltypeflags

IMPLTYPE flags to set.

Return Value

The SCODE value of the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
STG_E_INSUFFICIENTMEMORY	Out of memory.
E_OUTOFMEMORY	Out of memory.
E_INVALIDARG	One or more of the arguments is invalid.
E_ACCESSDENIED	Can't write to destination.
Comments

Sets the IMPLTYPE flags for the indexed interface. See the "IMPLTYPEFLAGS" section in Chapter 8, "Type Description Interfaces."


ICreateTypeInfo::SetMops

HRESULT ICreateTypeInfo::SetMops(index, bstrMops)
unsigned int index
BSTR bstrMops

Parameters

index

Index of the member for which to set the opcode string. If index is −1, sets the opcode string for the type description.

bstrMops

The marshaling opcode string.


Return Value

The SCODE value of the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
STG_E_INSUFFICIENTMEMORY	Out of memory.
E_OUTOFMEMORY	Out of memory.
E_INVALIDARG	One or more of the arguments is invalid.
E_ACCESSDENIED	Can't write to destination.
Comments

Sets the marshaling opcode string associated with the type description or the function.


ICreateTypeInfo::SetTypeDescAlias

HRESULT ICreateTypeInfo::SetTypeDescAlias(lptDescAlias)
TYPEDESC FAR* lptDescAlias

Parameters

lptDescAlias

Pointer to a type description that describes the type for which this is an alias.

Return Value

The SCODE value of the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
STG_E_INSUFFICIENTMEMORY	Out of memory.
E_OUTOFMEMORY	Out of memory.
E_INVALIDARG	One or more of the arguments is invalid.
E_ACCESSDENIED	Can't write to destination.
TYPE_E_WRONGTYPEKIND	Type mismatch.
Comments

Call SetTypeDescAlias for a type description whose TYPEKIND is TKIND_ALIAS to set the type for which it is an alias.


ICreateTypeInfo::SetTypeFlags

HRESULT ICreateTypeInfo::SetTypeFlags(uTypeFlags)
unsigned int uTypeFlags

Parameter

uTypeFlags

Settings for the type flags.

Return Value

The SCODE value of the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
STG_E_INSUFFICIENTMEMORY	Out of memory.
E_OUTOFMEMORY	Out of memory.
E_INVALIDARG	One or more of the arguments is invalid.
E_ACCESSDENIED	Can't write to destination.
TYPE_E_WRONGTYPEKIND	Type mismatch.
Comments

Use SetTypeFlags to set the flags for the type description. See the "TYPEFLAGS" section in Chapter 8, "Type Description Interfaces," for details.


ICreateTypeInfo::SetVarDocString

HRESULT ICreateTypeInfo::SetVarDocString(index, szDocString)
unsigned int index
OLECHAR FAR* szDocString

Parameters

index

Index of the variable being documented.

szDocString

The documentation string to be set.


Return Value

The SCODE value of the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
STG_E_INSUFFICIENTMEMORY	Out of memory.
E_OUTOFMEMORY	Out of memory.
E_ACCESSDENIED	Can't write to destination.
TYPE_E_ELEMENTNOTFOUND	The element was not found.
Comments

Sets the documentation string for the variable with the specified index.


ICreateTypeInfo::SetVarHelpContext

HRESULT ICreateTypeInfo::SetVarHelpContext(index, dwHelpContext)
unsigned int index
unsigned long dwHelpContext

Parameters

index

Index of the variable described by the type description.

dwHelpContext

Handle to the Help context for the Help topic on the variable.

Return Value

The SCODE value of the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
STG_E_INSUFFICIENTMEMORY	Out of memory.
E_OUTOFMEMORY	Out of memory.
E_ACCESSDENIED	Can't write to destination.
TYPE_E_ELEMENTNOTFOUND	The element can't be found.
Comments

Sets the Help context for the variable with the specified index.


ICreateTypeInfo::SetVarName

HRESULT	ICreateTypeInfo::SetVarName(index, szName)
unsigned int index
OLECHAR FAR* szName

Parameters

index

Index of the variable whose name is being set.

szName

Name for the variable.

Return Value

The SCODE value of the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
STG_E_INSUFFICIENTMEMORY	Out of memory.
E_OUTOFMEMORY	Out of memory.
E_ACCESSDENIED	Can't write to destination.
TYPE_E_ELEMENTNOTFOUND	The element can't be found.
Comments

Sets the name of a variable.


ICreateTypeInfo::SetVersion

HRESULT ICreateTypeInfo::SetVersion(wMajorVerNum, wMinorVerNum)
unsigned short wMajorVerNum
unsigned short wMinorVerNum

Parameters

wMajorVerNum

Major version number for the type.

wMinorVerNum

Minor version number for the type.


Return Value

The SCODE value of the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
E_ACCESSDENIED	Can't write to destination.
TYPE_E_INVALIDSTATE	The type library's state is not valid for this operation.
Comments

Sets the major and minor version number of the type information.


ICreateTypeLib Interface

The ICreateTypeLib interface methods are:

ICreateTypeLib::CreateTypeInfo
ICreateTypeLib::SaveAllChanges
ICreateTypeLib::SetDocString
ICreateTypeLib::SetGuid
ICreateTypeLib::SetHelpContext
ICreateTypeLib::SetHelpFileName
ICreateTypeLib::SetLibFlags
ICreateTypeLib::SetLcid
ICreateTypeLib::SetName
ICreateTypeLib::SetVersion
CreateTypeLib


ICreateTypeLib::CreateTypeInfo

HRESULT	ICreateTypeLib::CreateTypeInfo(szName, tkind, lplpctinfo)
OLECHAR FAR* szName
TYPEKIND tkind
ICreateTypeInfo FAR* FAR* lplpctinfo

Parameters

szName

Name of the new type.

tkind

TYPEKIND of the type description to be created.

lplpctinfo

On return, contains a pointer to the type description.

Return Value

The SCODE value of the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
STG_E_INSUFFICIENTMEMORY	Out of memory.
E_OUTOFMEMORY	Out of memory.
E_INVALIDARG	One or more of the arguments is invalid.
TYPE_E_INVALIDSTATE	The type library's state is not valid for this operation.
TYPE_E_NAMECONFLICT	The provided name is not unique.
TYPE_E_WRONGTYPEKIND	Type mismatch.


Comments

Use CreateTypeInfo to create a new type description instance within the library. An error is returned if the specified name already appears in the library. Valid tkind values are described in the "TYPEKIND" section in Chapter 8, "Type Description Interfaces."


ICreateTypeLib::SaveAllChanges

HRESULT ICreateTypeLib::SaveAllChanges()

Return Value

The SCODE value of the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
STG_E_INSUFFICIENTMEMORY	Out of memory.
E_OUTOFMEMORY	Out of memory.
E_INVALIDARG	One or more of the arguments is invalid.
TYPE_E_IOERROR	The function can't write to the file.
TYPE_E_INVALIDSTATE	The type library's state is not valid for this operation.
Other returns	All FACILITY_STORAGE errors.
Comments

Saves the ICreateTypeLib instance following the layout of the type information. Do not call any other ICreateTypeLib methods after calling SaveAllChanges.


ICreateTypeLib::SetDocString

HRESULT ICreateTypeLib::SetDocString(szDoc)
OLECHAR FAR* szDoc

Parameters

szDoc

A documentation string that briefly describes the type library.


Return Value

The SCODE value of the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
STG_E_INSUFFICIENTMEMORY	Out of memory.
E_OUTOFMEMORY	Out of memory.
E_INVALIDARG	One or more of the arguments is invalid.
Comments

Sets the documentation string associated with the library. The documentation string is a brief description of the library intended for use by type information browsing tools.


ICreateTypeLib::SetGuid

HRESULT ICreateTypeLib::SetGuid(guid)
REFGUID guid

Parameters

guid

The universal unique ID to be assigned to the library.

Return Value

The SCODE value of the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
STG_E_INSUFFICIENTMEMORY	Out of memory.
E_OUTOFMEMORY	Out of memory.
E_INVALIDARG	One or more of the arguments is invalid.
TYPE_E_INVALIDSTATE	The type library's state is not valid for this operation.
Comments

Sets the universal unique ID (UUID) associated with the type library. UUIDs are described in Chapter 7, "MkTypLib and Object Description Language."


ICreateTypeLib::SetHelpContext

HRESULT ICreateTypeLib::SetHelpContext(dwHelpContext)
unsigned long dwHelpContext

Parameters

dwHelpContext

Help context to be assigned to the library.

Return Value

The SCODE value of the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
STG_E_INSUFFICIENTMEMORY	Out of memory.
E_OUTOFMEMORY	Out of memory.
E_INVALIDARG	One or more of the arguments is invalid.
TYPE_E_INVALIDSTATE	The type library's state is not valid for this operation.
Comments

Sets the Help context for retrieving general Help information for the type library. Note that calling SetHelpContext with a Help context of zero is equivalent to not calling it at all, because zero indicates a NULL Help context.


ICreateTypeLib::SetHelpFileName

HRESULT ICreateTypeLib::SetHelpFileName(szFileName)
OLECHAR FAR* szFileName

Parameters

szFileName

The name of the Help file for the library.

Return Value

The SCODE value of the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
STG_E_INSUFFICIENTMEMORY	Out of memory.
E_OUTOFMEMORY	Out of memory.
E_INVALIDARG	One or more of the arguments is invalid.
TYPE_E_INVALIDSTATE	The type library's state is not valid for this operation.


Comments

Sets the name of the Help file. Each type library can reference a single Help file.

The GetDocumentation method of the created ITypeLib returns a fully qualified path for the Help file, which is formed by appending the name passed into szFileName to the registered Help directory for the type library. The Help directory is registered under:

\TYPELIB\<guid of library>\<Major.Minor version >\HELPDIR


ICreateTypeLib::SetLibFlags

HRESULT ICreateTypeLib::SetLibFlags(uLibFlags)
unsigned int uLibFlags

Parameters

uLibFlags

The flags to set for the library.

Return Value

The SCODE value of the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
STG_E_INSUFFICIENTMEMORY	Out of memory.
E_OUTOFMEMORY	Out of memory.
E_INVALIDARG	One or more of the arguments is invalid.
TYPE_E_INVALIDSTATE	The type library's state is not valid for this operation.
Comments

Valid uLibFlags values are listed in "Using LIBFLAGS with the ICreateTypeInfo Interface," earlier in this chapter.


ICreateTypeLib::SetLcid

HRESULT ICreateTypeLib::SetLcid(lcid)
LCID lcid

Parameters

lcid

An LCID representing the locale ID for the type library.


Return Value

The SCODE value of the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
STG_E_INSUFFICIENTMEMORY	Out of memory.
E_OUTOFMEMORY	Out of memory.
E_INVALIDARG	One or more of the arguments is invalid.
TYPE_E_INVALIDSTATE	The type library's state is not valid for this operation.
Comments

Sets the binary Microsoft national language ID associated with the library. For more information on national language IDs, see "Supporting Multiple National Languages," in Chapter 2, "Exposing OLE Automation Objects." For additional information for 16-bit systems, refer to Appendix A, "National Language Support Functions." For 32-bit systems, refer to the Windows NT documentation on the NLS API.


ICreateTypeLib::SetName

HRESULT ICreateTypeLib::SetName(szName)
OLECHAR FAR* szName

Parameters

szName

Name to be assigned to the library.

Return Value

The SCODE value of the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
STG_E_INSUFFICIENTMEMORY	Out of memory.
E_OUTOFMEMORY	Out of memory.
E_INVALIDARG	One or more of the arguments is invalid.
TYPE_E_INVALIDSTATE	The type library's state is not valid for this operation.
Comments

Sets the name of the type library.


ICreateTypeLib::SetVersion

HRESULT ICreateTypeLib::SetVersion(wMajorVerNum, wMinorVerNum)
unsigned short wMajorVerNum
unsigned short wMinorVerNum

Parameters

wMajorVerNum

Major version number for the library.

wMinorVerNum

Minor version number for the library.

Return Value

The SCODE value of the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
TYPE_E_INVALIDSTATE	The type library's state is not valid for this operation.
Comments

Sets the major and minor version numbers of the type library.


CreateTypeLib

HRESULT CreateTypeLib(syskind, szFile, lplpctlib)
SYSKIND syskind
OLECHAR FAR* szFile
ICreateTypeLib FAR* FAR* lplpctlib

Parameters

syskind

The target operating system for which to create a type library.

szFile

The name of the file to create.

lplpctlib

Pointer to an instance supporting the ICreateTypeLib interface.


Return Value

The SCODE value of the returned HRESULT is one of the following:

SCODE	Meaning
S_OK	Success.
STG_E_INSUFFICIENTMEMORY	Out of memory.
E_OUTOFMEMORY	Out of memory.
E_INVALIDARG	One or more of the arguments is invalid.
TYPE_E_IOERROR	The function could not create the file.
Other returns	All FACILITY_STORAGE errors.
Comments

CreateTypeLib sets its output parameter (lplpctlib) to point to a newly created object that supports the ICreateTypeLib interface.


Glossary

A

accessor function

A function that sets or retrieves the value of a property. Most properties have a pair of accessor functions; properties that are read-only may have only one accessor function.

Application object

The top-level object in an application's object hierarchy. The Application object identifies the application to the system and typically becomes active when the application starts. Specified by the appobj attribute in the type library.

C

class identifier (CLSID)

A UUID that identifies an OLE object. An object registers its CLSID in the system registration database so that it can be loaded and programmed by other applications.

class factory

An object that implements the IClassFactory interface, which allows it to create other objects of a specific class.

coclass

Component object model class; a top-level object in the object hierarchy.

collection object

A grouping of exposed objects. A collection object enables you to address multiple occurrences of an object as a unit, for example, to draw a set of points.

component object

A Windows object identified by a unique class identifier (CLSID), which associates the object with a DLL or an .EXE file.

compound document

A document that contains data of different formats, such as sound clips, spreadsheets, text, and bitmaps, created by different applications. Compound documents are stored by container applications.

container application

An application that provides storage, a display site, and access to a compound document object.

D

Dispatch identifier (DISPID)

The number by which a member function, parameter, or data member of an object is known internally to IDispatch.

dispinterface

An IDispatch interface that responds only to a certain fixed set of names. The properties and methods of the dispinterface are not in the virtual function table (VTBL) for the object.

dual interface

An interface that supports both IDispatch and VTBL binding.

E

event

An action recognized by an object, such as clicking the mouse or pressing a key, and for which you can write code to respond. In OLE Automation, an event is a method that is called, rather than implemented, by an OLE Automation object.

event sink

A function that handles events. The code associated with a Visual Basic form, which contains event handlers for one or more controls, is an event sink.

event source

A control that experiences events and calls an event handler to dispose of them.

exposed object

See OLE Automation object.

H

HRESULT

A value returned from a function call to an interface, consisting of a severity code, context information, a facility code, and a status code that describes the result. For 16-bit Windows systems, the HRESULT is an opaque result handle defined to be zero for a successful return from a function, and nonzero if error or status information is to be returned. To convert an HRESULT into the more detailed SCODE, applications call GetSCode(). See SCODE.

I

ID binding

The ability to bind member names to DISPIDs at compile time, for example, by obtaining the IDs from a type library. This approach eliminates the need for calls to IDispatch::GetIDsOfNames and results in improved performance over late-bound calls. See also late binding.

in-place activation

The ability to activate an object from within an OLE control and to associate a verb with that activation (for example, edit, play, change). Sometimes referred to as in-place editing or visual editing.

in-process server

An object application that runs in the same process space as the OLE Automation controller.

interface

One or more well-defined base classes providing member functions that, when implemented in an application, provide a specific service. Interfaces may include compiled support functions to simplify their implementation.

L

late binding

The ability to bind names to IDs at run time, rather than compile time.

local server

An object application implemented in an .EXE file that  runs in a separate process space from the OLE Automation controller.

locale identifier (LCID)

A 32-bit value that identifies the human language preferred by a user, region, or application.

M

marshaling

The process of packaging and sending interface parameters across process boundaries.

member function

One of a group of related functions that make up an interface. See also method and property.

method

Member functions of an exposed object that perform some action on the object, such as saving it to disk.

multiple-document interface (MDI) application

An application that can support multiple documents from one application instance.  MDI object applications can simultaneously service a user and one or more embedding containers. See also single-document interface (SDI) application.

O

object

A unit of information that resides in a compound document and whose behavior is constant no matter where it is located or used.

Object Description Language (ODL)

A scripting language used to describe exposed libraries, objects, types, and interfaces. ODL scripts are compiled into type libraries by the MkTypLib tool.

OLE

An acronym for Object Linking and Embedding.

OLE Automation

A technology that provides a way to manipulate objects defined by an application or library from outside the application. OLE Automation enables programmability.

OLE Automation controller

An application, programming tool, or scripting language that accesses OLE Automation objects. Visual Basic is an OLE Automation controller.

OLE Automation object

An instance of a class defined within an application that is exposed for access by other applications or programming tools by means of OLE Automation interfaces.

OLE Automation server

An application, type library, or other source that makes OLE Automation objects available for programming by other applications, programming tools, or scripting languages.

P

programmable object

See OLE Automation object. property

A data member of an exposed object. Properties are set or returned by means of get and put accessor functions.

proxy

An interface-specific object that packages parameters for that interface in preparation for a remote method call. A proxy runs in the address space of the sender and communicates with a corresponding stub in the receiver's address space. See also stub, marshaling, and unmarshaling.

S

safe array

An array that contains information about the number of dimensions and the bounds of its dimensions. Safe arrays are passed by IDispatch::Invoke within VARIANTARGs. Their base type is VT_tag | VT_ARRAY.

SCODE

A DWORD value that is used to pass detailed information to the caller of an interface member or API function. The status codes for OLE interfaces and API's are defined in FACILITY_ITF. See HRESULT.

single-document interface (SDI) application

An application that can support only one document at a time. Multiple instances of an SDI application must be started to service both an embedded object and a user. See also multiple-document interface (MDI) application.

stub

An interface-specific object that unpackages the parameters for that interface after they are marshaled across the process boundary, and makes the requested method call. The stub runs in the address space of the receiver and communicates with a corresponding proxy in the sender's address space. See proxy, marshaling, and unmarshaling.

type description

The information used to build the type information for one or more aspects of an application's interface. Type descriptions are written in Object Description Language (ODL) and include both programmable and nonprogrammable interfaces.

type information

Information that describes the interfaces of an application. Type information is created from type descriptions using OLE Automation tools, such as MkTypLib or the CreateDispTypeInfo function. Type information may be accessed through the ITypeInfo interface.

type information element

A unit of information identified by one of these statements in a type description: typedef, enum, struct, module, interface, dispinterface, or coclass.

type library

A file or component within another file that contains type information. Type libraries are created from type descriptions using MkTypLib, and may be accessed through the ITypeLib interface.

U

unmarshaling

The process of unpackaging parameter that have been sent across process boundaries.

V

Value property

The property that defines the default behavior of an object when no other methods or properties are specified. You indicate the Value property by specifying the default attribute in ODL.

virtual function table (VTBL)

A table of function pointers, such as an implementation of a class in C++. The pointers in the VTBL point to the members of the interfaces that an object supports.


National Language Support Functions

The National Language Support (NLS) functions provide support for applications that deal with multiple locales at once, especially for applications supporting OLE Automation. Locale information is passed to allow the application to interpret both the member names and the argument data in the proper locale context. On 32-bit Windows systems, an NLS API is part the system software; the information in this appendix applies only to 16-bit Windows systems.

Implemented by	Used by	Header filename	Import library name
OLE2NLS.DLL	Applications that support multiple national languages.	OLENLS.H	OLE2NLS.LIB
For OLE Automation, applications need to get locale information and to compare and transform strings into the proper format for each locale.

A locale is simply user preference information that denotes the user's language and sublanguage, represented as a list of values. National language support incorporates several disparate definitions of a locale into one coherent model. It is designed to be general enough at a low level to support multiple distinct high-level functions, such as the ANSI C locale functions.

A code page is the mapping between character glyphs (shapes) and the 1- or 2-byte numeric values that are used to represent them. Microsoft Windows version 3.1 uses one of several code pages, depending on the localized version of Windows installed. For example, the Russian version uses code page 1251 (Cyrillic), while the English/US and Western European versions use code page 1252 (Multilingual). For historical reasons, the Windows code page in effect is referred to as the ANSI code page.

Because only one code page is in effect at a time, it is impossible for a computer running English/US Windows version 3.1 to correctly display or print data from the Cyrillic code page; the fonts do not contain the Cyrillic characters. However, it can still manipulate the characters internally, and they will display correctly again if moved back to a machine running Russian Windows.

All NLS functions use the locale ID to identify which code page a piece of text is assumed to lie in; for example, when returning locale information (like month names) for Russian, the returned string can be meaningfully displayed in the Cyrillic code page only, because other code pages don't contain the appropriate characters. Similarly, when attempting to change the case of a string with the Russian locale, the case-mapping rules assume the characters are in the Cyrillic code page.

These functions can be divided into two categories:

•	String transformation — NLS functions support uppercasing, lowercasing, generating sort keys (all locale-dependent), and getting string type information.

•	Locale manipulation — NLS functions return information about installed locales for use in string transformations.


Overview of NLS Functions

The following table lists the NLS functions.

Function	Purpose
CompareStringA	Compares two strings of the same locale.
LCMapStringA	Transforms the case or sort order of a string.
GetLocaleInfoA	Retrieves locale information from the user's system.
GetStringTypeA	Retrieves locale type information about each character in a string.
GetSystemDefaultLangID	Retrieves the default LANGID from a user's system. (1)
GetSystemDefaultLCID	Retrieves the default LCID from a user's system.
GetUserDefaultLangID	Retrieves the default LANGID from a user's system.
GetUserDefaultLCID	Retrieves the default LCID from a user's system. (1)
1 Because Microsoft Windows is a single-user system, GetUserDefaultLangID and GetUserDefaultLCID return the same information as GetSystemDefaultLangID and GetSystemDefaultLCID.


Localized Member Names

An application may expose a set of objects whose members have names that differ across localized versions of the product. This poses a problem for programming languages that want to access such objects because it means that late binding will be sensitive to the locale of the application. The IDispatch and VTBL interfaces allow software developers a range of solutions which vary in cost of implementation and quality of national language support. All methods of the IDispatch interface that are potentially sensitive to language are passed a locale ID (LCID).

Following are some of the possible approaches a class implementation may take:

•	Accept any LCID and use the same member names in all locales. This is acceptable if the interface will typically be accessed only by advanced users. For example, the member names for OLE interfaces will never be localized.

•	Simply return an error (DISP_E_UNKNOWNLCID) if the caller's LCID doesn't match the localized version of the class. This would prevent users from being able to write late-bound code which runs on machines with different localized implementations of the class.

•	Recognize the particular version's localized names, as well as one language which is recognized in all versions. For example, a French version might accept French and English names, where English is the language supported in all versions. This would constrain users, who want to write code which runs in all countries, to use English.

•	Accept all LCIDs supported by all versions of the product. This means that the implementation of GetIDsOfNames would need to interpret the passed array of names based on the given LCID. This is the preferred solution because users would be able to write code in their national language and run the code on any localized version of the application.

At the very least, the application must check the LCID before interpreting member names. Also note that the meaning of parameters passed to a member function may depend on the caller's national language. For example, a spreadsheet application might interpret the arguments to a SetFormula method differently, depending on the LCID.


Locale ID (LCID)

The IDispatch interface uses the 32-bit Windows definition of a locale ID (LCID) to identify locales. An LCID is a DWORD value which contains the language ID (LANGID) in the lower word and a reserved value in the upper word. The bits are as follows:

This LCID has the components necessary to uniquely identify one of the installed system-defined locales.

/*

 * LCID creation/extraction macros:

 *

 *	MAKELCID - construct locale ID from language ID and

 *	country code.

 */

#define MAKELCID(l)	((DWORD)(((WORD)(l)) | (((DWORD)((WORD)(0))) << 16)))

There are two predefined LCID values: LOCALE_SYSTEM_DEFAULT is the system default locale, and LOCALE_USER_DEFAULT is the current user's locale. However, when querying the NLS APIs for several pieces of information, it is more efficient to query once for the current locale with GetSystemDefaultLCID or GetUserDefaultLCID, rather than using these constants.


Language ID (LANGID)

A LANGID is a 16-bit value which is the combination of a primary and sublanguage ID. The bits are as follows:

Macros are provided for constructing a LANGID and extracting the fields:

/*

 * Language ID creation/extraction macros:

 *

 *    MAKELANGID - construct language ID from primary language ID and

 *                 sublanguage ID.

 *    PRIMARYLANGID - extract primary language ID from a language ID.

 *    SUBLANGID - extract sublanguage ID from a language ID.

 *    LANGIDFROMLCID - get the language ID from a locale ID.

 */

#define MAKELANGID(p, s)	((((USHORT)(s)) << 10) | (USHORT)(p))

#define PRIMARYLANGID(lgid)	((USHORT)(lgid) & 0x3ff)

#define SUBLANGID(lgid)	((USHORT)(lgid) >> 10)

#define LANGIDFROMLCID(lcid)	((WORD)(lcid))

The following three combinations of primary and sublanguage IDs have special meanings:

PRIMARYLANGID	SUBLANGID	Meaning
LANG_NEUTRAL	SUBLANG_NEUTRAL	Language neutral
LANG_NEUTRAL	SUBLANG_SYS_DEFAULT	System default language
LANG_NEUTRAL	SUBLANG_DEFAULT	User default language
For primary language IDs, the range 0x200 to 0x3ff is user definable. The range 0x000 to 0x1ff is reserved for system use. The following table lists the primary language IDs supported by OLE Automation:

Language	PRIMARYLANGID
Neutral	0x00
Chinese	0x04
Czech	0x05
Danish	0x06
Dutch	0x13
English	0x09
Finnish	0x0b
French	0x0c
German	0x07
Greek	0x08
Hungarian	0x0e
Icelandic	0x0F
Italian	0x10
Japanese	0x11
Korean	0x12
Norwegian	0x14
Polish	0x15
Portuguese	0x16
Russian	0x19
Serbo Croatian	0x1a
Slovak	0x1b
Spanish	0x0a
Swedish	0x1d
Turkish	0x1F
For sublanguage IDs, the range 0x20 to 0x3f is user definable. The range 0x00 to 0x1f is reserved for system use. The following table lists the sublanguage IDs supported by OLE Automation:

Sublanguage	SUBLANGID
Neutral	0x00
Default	0x01
System Default	0x02
Chinese (Simplified)	0x02
Chinese (Traditional)	0x01
Dutch	0x01
Dutch (Belgian)	0x02
English (US)	0x01
English (UK)	0x02
English (Australian)	0x03
English (Canadian)	0x04
English (Irish)	0x06
English (New Zealand)	0x05
French	0x01
French (Belgian)	0x02
French (Canadian)	0x03
French (Swiss)	0x04
German	0x01
German (Swiss)	0x02
German (Austrian)	0x03
Greek	0x01
Icelandic	0x01
Italian	0x01
Italian (Swiss)	0x02
Japanese	0x01
Korean	0x01
Norwegian (Bokmal)	0x01
Norwegian (Nynorsk)	0x02
Portuguese	0x02
Portuguese (Brazilian)	0x01
Serbo Croatian (Latin)	0x01
Spanish (Castilian)1	0x01
Spanish (Mexican)	0x02
Spanish (Modern)1	0x03
Turkish	0x01
1 The only difference between Spanish (Castilian) and Spanish (Modern) is the sort ordering. All of the LCType values are the same.


Locale Constants (LCTYPE)

An LCTYPE is a constant which specifies a particular piece of locale information.

typedef  DWORD  LCTYPE;

The list of supported LCTYPES follows. All values are null-terminated, variable length strings. Numeric values are expressed as strings of decimal digits unless otherwise noted. The values in the brackets indicate the maximum number of characters allowed for the string (including the null-termination). If no maximum is indicated, the string may be of variable length.

Constant name	Description
LOCALE_ILANGUAGE	A language ID represented in hexadecimal digits; see previous sections. [5]
LOCALE_SLANGUAGE	The full localized name of the language.
LOCALE_SENGLANGUAGE	The full English name of the language from the ISO Standard 639. This will always be restricted to characters that can be mapped into the ASCII 127-character subset.
LOCALE_SABBREVLANGNAME	The abbreviated name of the language, created by taking the two-letter language abbreviation, as found in ISO Standard 639, and adding a third letter as appropriate to indicate the sublanguage.
LOCALE_SNATIVELANGNAME	The native name of the language.
LOCALE_ICOUNTRY	The country code, based on international phone codes, also referred to as IBM country codes. [6]
LOCALE_SCOUNTRY	The full localized name of the country.
LOCALE_SENGCOUNTRY	The full English name of the country. This will always be restricted to characters that can be mapped into the ASCII 127-character subset.
LOCALE_SABBREVCTRYNAME	The abbreviated name of the country as found in ISO Standard 3166.
LOCALE_SNATIVECTRYNAME	The native name of the country.
LOCALE_IDEFAULTLANGUAGE	Language ID for the principal language spoken in this locale. This is provided so that partially specified locales can be completed with default values. [5]
LOCALE_IDEFAULTCOUNTRY	Country code for the principal country in this locale. This is provided so that partially specified locales can be completed with default values. [6]
LOCALE_IDEFAULTANSICODEPAGE	The ANSI code page associated with this locale. Format: 4 Unicode decimal digits plus a Unicode null-terminator. [10] [6]
LOCALE_IDEFAULTCODEPAGE	The OEM code page associated with the country. [6]
LOCALE_SLIST	Characters used to separate list items; for example, comma is used in many locales.
LOCALE_IMEASURE	This value is "0" for the metric system (S.I.) and "1" for the U.S. system of measurements. [2]
LOCALE_SDECIMAL	Characters used for the decimal separator.
LOCALE_STHOUSAND	Characters used as the separator between groups of digits left of the decimal.
LOCALE_SGROUPING	Sizes for each group of digits to the left of the decimal. An explicit size is required for each group; sizes are separated by semicolons. If the last value is 0, the preceding value is repeated. To group thousands, specify "3;0."
LOCALE_IDIGITS	The number of fractional digits. [3]
LOCALE_ILZERO	Whether to use leading zeros in decimal fields. [2] A setting of 0 means use no leading zeros; 1 means use leading zeros.
LOCALE_SNATIVEDIGITS	The ten characters that are the native equivalent of the ASCII '0-9'.
LOCALE_INEGNUMBER	Negative number mode. [2] "0"  (1.1) "1"  -1.1 "2"  -1.1 "3"  1.1 "4"  1.1
LOCALE_SCURRENCY	The string used as the local monetary symbol.
LOCALE_SINTLSYMBOL	Three characters of the International monetary symbol specified in ISO 4217 Codes for the Representation of Currencies and Funds, followed by the character separating this string from the amount.
LOCALE_SMONDECIMALSEP	Characters used for the monetary decimal separators.
LOCALE_SMONTHOUSANDSEP	Characters used as monetary separator between groups of digits left of the decimal.
LOCALE_SMONGROUPING	Sizes for each group of monetary digits to the left of the decimal. An explicit size is needed for each group; sizes are separated by semicolons. If the last value is 0, the preceding value is repeated. To group thousands, specify "3;0".
LOCALE_ICURRDIGITS	Number of fractional digits for the local monetary format. [3]
LOCALE_IINTLCURRDIGITS	Number of fractional digits for the international monetary format. [3]
LOCALE_ICURRENCY	Positive currency mode. [2] "0" Prefix, no separation  "1" Suffix, no separation "2" Prefix, 1-character separation "3" Suffix, 1-character separation
LOCALE_INEGCURR	Negative currency mode. [2] "0" ($1.1) "1" -$1.1 "2" $-1.1 "3" $1.1- "4" $(1.1$) "5" -1.1$ "6" 1.1-$ "7" 1.1$- "8" -1.1 $     (space before $) "9"  -$ 1.1     (space after $) "10" 1.1 $-     (space before $)
LOCALE_ICALENDARTYPE	The type of calendar currently in use. [2] "1" Gregorian (as in U.S.) "2" Gregorian (always English strings) "3" Era: Year of the Emperor (Japan) "4" Era: Year of the Republic of China "5" Tangun Era (Korea)
LOCALE_IOPTIONALCALENDAR	The additional calendar types available for this LCID; can be a null-separated list of all valid optional calendars. [2] "0" None available "1" Gregorian (as in U.S.) "2" Gregorian (always English strings) "3" Era: Year of the Emperor (Japan) "4" Era: Year of the Republic of China "5" Tangun Era (Korea)
LOCALE_SDATE	Characters used for the date separator.
LOCALE_STIME	Characters used for the time separator.
LOCALE_STIMEFORMAT	Time formatting string. [80]
LOCALE_SSHORTDATE	Short Date_Time formatting strings for this locale.
LOCALE_SLONGDATE	Long Date_Time formatting strings for this locale.
LOCALE_IDATE	Short Date format ordering specifier. [2] "0" Month − Day − Year "1" Day − Month − Year "2" Year − Month − Day
LOCALE_ILDATE	Long Date format ordering specifier. [2] "0" Month − Day − Year "1" Day − Month − Year "2" Year − Month − Day
LOCALE_ITIME	Time format specifier. [2] "0" AM/PM 12-hour format "1" 24-hour format
LOCALE_ITIMEMARKPOSN	Whether the time marker string (AM|PM) precedes or follows the time string. (The registry value is named ITimePrefix for previous Far East version compatibility.) "0"  Suffix (9:15 AM) "1"  Prefix (AM 9:15)
LOCALE_ICENTURY	Whether to use full 4-digit century. [2] "0" Two digit "1" Full century
LOCALE_ITLZERO	Whether to use leading zeros in time fields. [2] "0" No leading zeros "1" Leading zeros for hours
LOCALE_IDAYLZERO	Whether to use leading zeros in day fields. [2] "0" No leading zeros "1" Leading zeros
LOCALE_IMONLZERO	Whether to use leading zeros in month fields. [2] "0" No leading zeros "1" Leading zeros
LOCALE_S1159	String for the AM designator.
LOCALE_S2359	String for the PM designator.
LOCALE_IFIRSTWEEKOFYEAR	Specifies which week of the year is considered first. [2] "0" Week containing 1/1 is the first week of the year. "1" First full week following 1/1is the first week of the year. "2" First week with at least 4 days is the first week of the year.
LOCALE_IFIRSTDAYOFWEEK	Specifies the day considered first in the week. [2] "0" SDAYNAME1 "1" SDAYNAME2 "2" SDAYNAME3 "3" SDAYNAME4 "4" SDAYNAME5 "5" SDAYNAME6 "6" DAYNAME7
LOCALE_SDAYNAME1	Long name for Monday.
LOCALE_SDAYNAME2	Long name for Tuesday.
LOCALE_SDAYNAME2	Long name for Tuesday.
LOCALE_SDAYNAME3	Long name for Wednesday.
LOCALE_SDAYNAME4	Long name for Thursday.
LOCALE_SDAYNAME5	Long name for Friday.
LOCALE_SDAYNAME6	Long name for Saturday.
LOCALE_SDAYNAME7	Long name for Sunday.
LOCALE_SABBREVDAYNAME1	Abbreviated name for Monday.
LOCALE_SABBREVDAYNAME2	Abbreviated name for Tuesday.
LOCALE_SABBREVDAYNAME3	Abbreviated name for Wednesday.
LOCALE_SABBREVDAYNAME4	Abbreviated name for Thursday.
LOCALE_SABBREVDAYNAME5	Abbreviated name for Friday.
LOCALE_SABBREVDAYNAME6	Abbreviated name for Saturday.
LOCALE_SABBREVDAYNAME7	Abbreviated name for Sunday.
LOCALE_SMONTHNAME1	Long name for January.
LOCALE_SMONTHNAME2	Long name for February.
LOCALE_SMONTHNAME3	Long name for March.
LOCALE_SMONTHNAME4	Long name for April.
LOCALE_SMONTHNAME5	Long name for May.
LOCALE_SMONTHNAME6	Long name for June.
LOCALE_SMONTHNAME7	Long name for July.
LOCALE_SMONTHNAME8	Long name for August.
LOCALE_SMONTHNAME9	Long name for September.
LOCALE_SMONTHNAME10	Long name for October.
LOCALE_SMONTHNAME11	Long name for November.
LOCALE_SMONTHNAME12	Long name for December.
LOCALE_SMONTHNAME13	Native name for 13th month, if it exists.
LOCALE_SABBREVMONTHNAME1	Abbreviated name for January.
LOCALE_SABBREVMONTHNAME2	Abbreviated name for February.
LOCALE_SABBREVMONTHNAME3	Abbreviated name for March.
LOCALE_SABBREVMONTHNAME4	Abbreviated name for April.
LOCALE_SABBREVMONTHNAME5	Abbreviated name for May.
LOCALE_SABBREVMONTHNAME6	Abbreviated name for June.
LOCALE_SABBREVMONTHNAME7	Abbreviated name for July.
LOCALE_SABBREVMONTHNAME8	Abbreviated name for August.
LOCALE_SABBREVMONTHNAME9	Abbreviated name for September.
LOCALE_SABBREVMONTHNAME10	Abbreviated name for October.
LOCALE_SABBREVMONTHNAME11	Abbreviated name for November.
LOCALE_SABBREVMONTHNAME12	Abbreviated name for December.
LOCALE_SABBREVMONTHNAME13	Native abbreviated name for 13th month, if it exists.
LOCALE_SPOSITIVESIGN	String value for the positive sign.
LOCALE_SNEGATIVESIGN	String value for the negative sign.
LOCALE_IPOSSIGNPOSN	Formatting index for positive values. [2]  "0" Parentheses surround the amount and the monetary symbol. "1" The sign string precedes the amount and the monetary symbol. "2" The sign string precedes the amount and the monetary symbol. "3" The sign string precedes the amount and the monetary symbol. "4" The sign string precedes the amount and the monetary symbol.
LOCALE_INEGSIGNPOSN	Formatting index for negative values. [2]  "0" Parentheses surround the amount and the monetary symbol. "1" The sign string precedes the amount and the monetary symbol. "2" The sign string precedes the amount and the monetary symbol. "3" The sign string precedes the amount and the monetary symbol. "4" The sign string precedes the amount and the monetary symbol.
LOCALE_IPOSSYMPRECEDES	"1" if the monetary symbol precedes; "0" if it succeeds a positive amount. [2]
LOCALE_IPOSSEPBYSPACE	"1" if the monetary symbol is separated by a space from a positive amount; "0" otherwise. [2]
LOCALE_INEGSYMPRECEDES	"1" if the monetary symbol precedes; "0" if it succeeds a negative amount. [2]
LOCALE_INEGSEPBYSPACE	"1" if the monetary symbol is separated by a space from a negative amount; "0" otherwise. [2]
The following table shows the equivalence between LCTYPE values and the information stored in the [intl] section of WIN.INI. These values will be retrieved from WIN.INI if information for the current system locale is queried. Values for LCTYPEs not in the following table do not depend on information stored in WIN.INI.

WIN.INI settings	LCTYPE
sLanguage (1)	LOCALE_SABBREVLANGNAME
iCountry	LOCALE_ICOUNTRY
sCountry	LOCALE_SCOUNTRY
sList	LOCALE_SLIST
iMeasure	LOCALE_IMEASURE
sDecimal	LOCALE_SDECIMAL
sThousand	LOCALE_STHOUSAND
iDigits	LOCALE_IDIGITS
iLZero	LOCALE_ILZERO
sCurrency	LOCALE_SCURRENCY
iCurrDigits	LOCALE_ICURRDIGITS
iCurrency	LOCALE_ICURRENCY
iNegCurr	LOCALE_INEGCURR
sDate	LOCALE_SDATE
sTime	LOCALE_STIME
sShortDate	LOCALE_SSHORTDATE
sLongDate	LOCALE_SLONGDATE
iDate	LOCALE_IDATE
iTime	LOCALE_ITIME
iTLZero	LOCALE_ITLZERO
s1159	LOCALE_S1159
s2359	LOCALE_S2359
1 Unlike in WIN.INI, values returned by LOCALE_SABBREVLANGNAME are always in uppercase.


CompareStringA

int CompareStringA(LCID, dwCmpFlags, lpString1, cchCount1, lpString2, cchCount2)
LCID LCID
DWORD dwCmpFlags
LPCSTR lpString1
int cchCount1
LPCSTR lpString2
int cchCount2

Compares two character strings of the same locale according to the supplied LCID.

Parameters

LCID

Locale context for the comparison. The strings are assumed to be represented in the default ANSI code page for this locale.

dwCmpFlags

Flags that indicate the character traits to use or ignore when comparing the two strings. Several flags can be combined (in the case of this function, there are no illegal combinations of flags), or none can be used at all. Compare flags include the following.

Value	Meaning
NORM_IGNORECASE	Ignore case; default is OFF.
NORM_IGNOREKANATYPE	Ignore Japanese hiragana/katakana character differences; default is OFF.
NORM_IGNORENONSPACE	Ignore nonspacing marks (accents, diacritics and vowel marks); default is OFF.
NORM_IGNORESYMBOLS	Ignore symbols; default is OFF.
NORM_IGNOREWIDTH	Ignore character width, default is OFF.
lpString1 and lpString2

The two strings to be compared.

cchCount1 and cchCount2

The character counts of the two strings. The count does not include the null-terminator (if any). If either cchCount1 or cchCount2 is −1, the corresponding string is assumed to be null-terminated and the length will be calculated automatically.


Return Value

Value	Meaning
0	Failure.
1	lpString1 is less than lpString2.
2	lpString1 is equal to lpString2.
3	lpString1 is greater than lpString2.
Comments

When used without any flags, this function uses the same sorting algorithm as lstrcmp in the given locale. When used with NORM_IGNORECASE, the same algorithm as lstrcmpi is used.

For DBCS locales, the flag NORM_IGNORECASE has an effect on all the wide (two-byte) characters as well as the narrow (one-byte) characters. This includes the wide Greek and Cyrillic characters.

In Chinese Simplified, the sorting order used to compare the strings is based on the following sequence: symbols, digit numbers, English letters and Chinese Simplified characters. The characters within each group sort in character code order.

In Chinese Traditional, the sorting order used to compare the strings is based on the "number of strokes" in the characters. Symbols, digit numbers, and English characters are considered to have zero strokes. The sort sequence is symbols, digit numbers, English letters and Chinese Traditional characters. The characters within each stroke-number group sort in character code order.

In Japanese, the sorting order used to compare the strings is based on the Japanese 50-on sorting sequence. The Kanji ideographic characters sort in character code order.

In Japanese, the flag NORM_IGNORENONSPACE has an effect on the daku-on, handaku-on, chou-on, you-on, and soku-on modifiers, and on the repeat kana/kanji characters.

In Korean, the sort order is based on the sequence: symbols, digit numbers, Jaso and Hangeul, Hanja, and English. Within the Jaso-Hangeul group, each Jaso character is followed by the Hangeuls that start with that Jaso. Hanja characters are sorted in Hangeul pronounciation order. Where multiple Hanja have the same Hangeul pronounciation they are sorted in character code order.

The NORM_IGNORENONSPACE flag only has an effect for the locales in which accented characters are sorted in a second pass from main characters (that is, all characters in the string are first compared without regard to accents and, if the strings are equal, a second pass over the strings to compare accents is performed). In this case, this flag causes the second pass to not be performed. Some locales sort accented characters in the first pass, in which case this flag will have no effect.

Note that if the return value is 2, the two strings are "equal" in the collation sense, though not necessarily identical (case might be ignored, and so on).

If the two strings are of different lengths, they are compared up to the length of the shortest one. If they are equal to that point, the return value will indicate that the longer string is greater.

To maintain the C run-time convention of comparing strings, the value 2 can be subtracted from a nonzero return value. The meaning of < 0, == 0, and > 0 is then consistent with the C run-time conventions.


LCMapStringA

int LCMapStringA(LCID, dwMapFlags, lpSrcStr, cchSrc, lpDestStr, cchDest)
LCID LCID
DWORD dwMapFlags
LPCSTR lpSrcStr
int cchSrc
LPSTR lpDestStr
int cchDest

Parameters

LCID

Locale context for the mapping. The strings are assumed to be represented in the default ANSI code page for this locale.

dwMapFlags

Flags that indicate what type of transformation is to occur during mapping. Several flags can be combined on a single transformation (though some combinations are illegal). Mapping options include the following.

Name	Meaning
LCMAP_LOWERCASE	Lowercase.
LCMAP_UPPERCASE	Uppercase.
LCMAP_SORTKEY	Character sort key.
LCMAP_HALFWIDTH	Narrow characters (where applicable).
LCMAP_FULLWIDTH	Wide characters (where applicable).
LCMAP_HIRAGANA	Hiragana.
LCMAP_KATAKANA	Katakana.
NORM_IGNORECASE	Ignore case; default is OFF.
NORM_IGNORENONSPACE	Ignore nonspacing; default is OFF.
NORM_IGNOREWIDTH	Ignore character width; default is OFF.
NORM_IGNOREKANATYPE	Ignore Japanese hiragana/katakana character differences; default is OFF.
NORM_IGNORESYMBOLS	Ignore symbols; default is OFF.
The latter five options (NORM_IGNORECASE, NORM_IGNORENONSPACE, NORM_IGNOREWIDTH, NORM_IGNOREKANATYPE,and NORM_IGNORESYMBOLS) are normalization options that can only be used in combination with the LCMAP_SORTKEY conversion option.

Conversion options can be combined only when they are taken from the following three groups, and then only when there is no more than one option from each group:

•	Casing options (LCMAP_LOWERCASE, LCMAP_UPPERCASE)

•	Width options (LCMAP_HALFWIDTH, LCMAP_FULLWIDTH)

•	Kana options (LCMAP_HIRAGANA, LCMAP_KATAKANA)

lpSrcStr

Pointer to the supplied string to be mapped.

cchSrc

Character count of the input string buffer. If −1, lpSrcStr is assumed to be null-terminated and the length will be calculated automatically.

lpDestStr

Pointer to the memory buffer to store the resulting mapped string.

cchDest

Character count of the memory buffer pointed to by lpDestStr. If cchDest is 0, then the return value of this function is the number of characters required to hold the mapped string. The lpDestStr pointer is not referenced in this case.

Return Value

Value	Meaning
0	Failure
The number of characters written to lpDestSt	Success
Comments

LCMapStringA maps one character string to another, performing the specified locale-dependent translation.

The flag LCMAP_UPPER produces the same result as AnsiUpper in the given locale; the flag LCMAP_LOWER produces the same result as AnsiLower. In particular, like these functions, this function always maps a single character to a single character.

The mapped string will be null-terminated if the source string is null-terminated.

When used with LCMAP_UPPER and LCMAP_LOWER, the lpSrcStr and lpDestStr may be the same to produce an in-place mapping. When LCMAP_SORTKEY is used, the lpSrcStr and lpDestStr pointers may not be the same; an error will result in this case.

The LCMAP_SORTKEY transformation transforms two strings such that when compared with the standard C library function strcmp (by strict numerical valuation of their characters), the same order would result as if the original strings were compared with CompareStringA. When LCMAP_SORTKEY is specified, the output string will be a string (without NULLs, except for the terminator), but the "character" values will not be meaningful display values. This is similar behavior to the ANSI C function strxfrm.


GetLocaleInfoA

int GetLocaleInfoA(LCID, LCType, lpLCData, cchData)
LCID LCID
LCTYPE LCType
LPSTR lpLCData
int cchData

Parameters

LCID

ID for a locale. The returned string will be represented in the default ANSI code page for this locale.

LCType

Flag that indicates the type of information to be returned by the call. See the listing of constant values in this chapter. LOCALE_NOUSEROVERRIDE | LCTYPE indicates that the desired information will always be retrieved from the locale database, even if the LCID is the current one, and the user has changed some of the values with the control panel. If this flag is not specified, values in WIN.INI take precedence over the database settings when getting values for the current system default locale.

lpLCData

Pointer to the memory where GetLocaleInfoA will return the requested data. This pointer is not referenced if cchData is 0.

cchData

Character count of the supplied lpLCData memory buffer. If cchData is 0, the return value is the number of characters required to hold the string, including the terminating NULL character. lpLCData is not referenced in this case.

Return Value

Value	Meaning
0	Failure
The number of characters copied, including the terminating NULL character	Success
Comments

GetLocaleInfoA returns one of the various pieces of information about a locale by querying the stored locale database or WIN.INI. The call also indicates how much memory is necessary to contain the desired information.

The information returned is always a null-terminated string. No integers are returned by this function ; numeric values are returned as text (see format descriptions under LCTYPE).


GetStringTypeA

BOOL GetStringTypeA(LCID, dwInfoType, lpSrcStr, cchSrc, lpCharType)
LCID LCID
DWORD dwInfoType
LPCSTR  lpSrcStr
int cchSrc
LPWORD lpCharType

Parameters

LCID

Locale context for the mapping. The string is assumed to be represented in the default ANSI code page for this locale.

dwInfoType

Type of character information to retrieve. The various types are divided into different levels (see Comments for a list of the information included in each type). The options are mutually exclusive. The following types are supported:

•	CT_CTYPE1

•	CT_CTYPE2

•	CT_CTYPE3

lpSrcStr

String for which character types are requested. If cchSrc is −1, lpSrcStr is assumed to be null-terminated.

 cchSrc

Character count of lpSrcStr. If cchSrc is −1, lpSrcStr is assumed to be null-terminated. Note that this must also be the character count of lpCharType.

lpCharType

Array of the same length as lpSrcStr (cchSrc). On output, the array contains one word corresponding to each character in lpSrcStr.

Return Value

Value	Meaning
0	Failure
1	Success
Comments

The lpSrcStr and lpCharType pointers may not be the same; in this case the error ERROR_INVALID_PARAMETER results.

The character type bits are divided up into several levels. One level's information can be retrieved by a single call.

This function supports three character types:

•	Ctype 1

•	Ctype 2

•	Ctype 3

Ctype 1 types support ANSI C and POSIX character typing functions. A bitwise OR of these values is returned when dwInfoType is set to CT_CTYPE1. For DBCS locales, the Ctype 1 attributes apply to both the narrow characters and the wide characters. The Japanese hiragana and katakana characters, and the kanji ideograph characters all have the C1_ALPHA attribute.

The following table lists the Ctype 1 character types.

Name	Value	Meaning
C1_UPPER	0x0001	Uppercase1
C1_LOWER	0x0002	Lowercase1
C1_DIGIT	0x0004	Decimal digits
C1_SPACE	0x0008	Space characters
C1_PUNCT	0x0010	Punctuation
C1_CNTRL	0x0020	Control characters
C1_BLANK	0x0040	Blank characters
C1_XDIGIT	0x0080	Hexadecimal digits
C1_ALPHA	0x0100	Any letter
1 The Windows version 3.1 functions IsCharUpper and IsCharLower do not always produce correct results for characters in the range 0x80-0x9f, so they may produce different results than this function for characters in that range. (For example, the German Windows version 3.1 language driver incorrectly reports 0x9a, lowercase s hacek, as uppercase).
Ctype 2 types support the proper layout of text. For DBCS locales, Ctype 2 applies to both narrow and wide characters. The directional attributes are assigned so that the BiDi layout algorithm standardized by Unicode produces the correct results. See The Unicode Standard: Worldwide Character Encoding from Addison-Wesley for more information on the use of these attributes.

	Name	Value	Meaning
Strong	C2_LEFTTORIGHT	0x1	Left to right
	C2_RIGHTTOLEFT	0x2	Right to left
Weak	C2_EUROPENUMBER	0x3	European number, European digit
	C2_EUROPESEPARATOR	0x4	European numeric separator
	C2_EUROPETERMINATOR	0x5	European numeric terminator
	C2_ARABICNUMBER	0x6	Arabic number
	C2_COMMONSEPARATOR	0x7	Common numeric separator
Neutral	C2_BLOCKSEPARATOR	0x8	Block separator
	C2_SEGMENTSEPARATOR	0x9	Segment separator
	C2_WHITESPACE	0xA	White space
	C2_OTHERNEUTRAL	0xB	Other neutrals
Not applicable	C2_NOTAPPLICABLE	0x0	No implicit direction (for example, control codes)
Ctype 3 types are general text-processing information. A bitwise OR of these values is returned when dwInfoType is set to CT_CTYPE3. For DBCS locales, the Ctype 3 attributes apply to both the narrow characters and the wide characters. The Japanese hiragana and katakana characters and the kanji ideograph characters all have the C3_ALPHA attribute.

Name	Value	Meaning
C3_NONSPACING	0x1	Nonspacing mark
C3_DIACRITIC	0x2	Diacritic nonspacing mark
C3_VOWELMARK	0x4	Vowel nonspacing mark
C3_SYMBOL	0x8	Symbol
C3_KATAKANA	0x10	Katakana character
C3_HIRAGANA	0x20	Hiragana character
C3_HALFWIDTH	0x40	Narrow character
C3_FULLWIDTH	0x80	Wide character
C3_IDEOGRAPH	0x100	Ideograph
C3_ALPHA	0x8000	Any letter
C3_NOTAPPLICABLE	0x0	Not applicable


GetSystemDefaultLangID

Returns the system default language ID.

LANGID GetSystemDefaultLangID(void);

Return Value

Value	Meaning
0	Failure
The system default LANGID	Success
Comments

See GetSystemDefaultLCID for information on how this value is determined.


GetSystemDefaultLCID

Returns the system default LCID.

LCID GetSystemDefaultLCID(void)

Return Value

Value	Meaning
0	Failure
System default locale ID	Success


Comments

The return value is determined by examining the values of sLanguage and iCountry in WIN.INI, and comparing the values to those in the stored locale database. If no matching values are found, or the required values cannot be read from WIN.INI, or if the stored locale database cannot be loaded, the value 0 is returned.


GetUserDefaultLangID

Returns the user default LANGID.

LANGID GetUserDefaultLangID(void)

Return Value

Value	Meaning
0	Failure
The user default LANGID	Success
Comments

Because Windows version 3.1 is a single-user system, the value returned from this function is always the same as that returned from GetSystemDefaultLangID.


GetUserDefaultLCID

Returns the user default LCID.

LCID GetUserDefaultLCID(void)

Return Value

Value	Meaning
0	Failure
The user default locale ID	Success
Comments

Because Windows version 3.1 is a single-user system, the value returned by this function is always the same as that returned from GetSystemDefaultLCID.


Files You Need

To use OLE Automation, you need the following files. The filenames shown in bold are required by your application at run time. Note that you should not ship the files with your 32-bit Windows application; these files are provided as part of the32-bit Windows operating system.

32-bit filenames	16-bit filenames	Purpose
None	OLE2.REG	Registers OLE and OLE Automation. OLE is a system component on 32-bit systems, and therefore no .REG file is required.
None	OLE2NLS.DLL OLE2NLS.LIB OLENLS.H	Provides functions for applications that support multiple national languages. Note that on 32-bit systems, NLS features are provided by the Win32 NLS API.
OLEPRX32.DLL	OLE2PROX.DLL	Coordinates object access across processes.
MKTYPLIB.EXE	MKTYPLIB.EXE	Builds type libraries from interface descriptions.
OLEAUT32.DLL OLEAUT32.LIB OLEAUTO.H	TYPELIB.DLL DISPATCH.H	Accesses type libraries.
32-bit filenames	16-bit filenames	Purpose
	OLE2DISP.DLL OLE2DISP.LIB DISPATCH.H	Provides functions for creating OLE Automation objects and retrieving active objects at run time. Accesses OLE Automation objects by invoking methods and properties.
OLE32.DLL OLE32.LIB OLE2.H	OLE2.DLL OLE2.LIB OLE2.H	Provides OLE functions that may be used by OLE objects or containers.
	COMPOBJ.DLL COMPOBJ.LIB OLE2.H COMPOBJ.H	Supports component object creation and access.
	STORAGE.DLL STORAGE.LIB OLE2.H STORAGE.H	Supports access to subfiles, such as type libraries, within compound documents.


Information for Visual Basic Programmers

Visual Basic provides full support for OLE Automation. The following table lists how Visual Basic statements translate into OLE APIs.

Visual Basic Statement	OLE APIs
CreateObject ("ProgID")	CLSIDFromProgID() CoCreateInstance() QueryInterface() to get IDispatch interface
GetObject ("filename", "ProgID")	CLSIDFromProgID() CoCreateInstance() QueryInterface() for IPersistFile interface Load() on IPersistFile interface QueryInterface() to get IDispatch interface
GetObject ("filename")	CreateBindCtx() creates the bind context for the subsequent functions. MkParseDisplayName() returns a moniker handle for BindMoniker. BindMoniker() returns a pointer to the IDispatch interface. Release() on moniker handle. Release() on context.
GetObject (, "ProgID")	CLSIDFromProgID() GetActiveObject() on class ID. QueryInterface() to get IDispatch interface.
Dim x As New interface	Find CLSID for interface. CoCreateInstance() QueryInterface()


How OLE Automation Compares Strings

This appendix describes how the OLE Automation implementations compare strings. Understanding these comparisons is useful when creating applications that support national languages that use accents and digraphs. The information in this appendix applies to the following:

•	CreateStdDispatch (OLEAUT32.DLL on 32-bit Windows systems, OLE2DISP.DLL on 16-bit Windows systems)

•	DispGetIDsOfNames (OLEAUT32.DLL on 32-bit Windows systems, OLE2DISP.DLL on 16-bit Windows systems)

•	ITypeLib::FindName (OLEAUT32.DLL on 32-bit Windows systems, TYPELIB.DLL on 16-bit Windows systems)

•	ITypeInfo::GetIDsOfNames (OLEAUT32.DLL on 32-bit Windows systems, TYPELIB.DLL on 16-bit Windows systems)

•	MkTypLib (MKTYPLIB.EXE)

When comparing strings, the listed OLE Automation components use the following rules:

•	Comparisons are sensitive to locale based on the string's LCID. A string must have an LCID that is supported by the application or type library. Locales and LCIDs are described in the section "Supporting Multiple National Languages," in Chapter 2.

•	Accent characters are ignored. For example, the string "à" compares the same as "a."

•	Case is ignored. For example, the string "A" compares the same as "a."

•	Comparisons are sensitive to digraphs. For example, the string "Æ" is not the same as "AE."

•	For Japanese, Korean, and Chinese locales, ITypeLib::FindName and ITypeLib::GetIDsOfNames ignore width and kanatype.


Handling GUIDs

Globally unique identifiers (GUIDs) appear in many places in a typical OLE Automation application. GUID errors can cause persistent bugs. To help you avoid GUID problems, this appendix lists all the places GUIDs appear in a typical OLE Automation application, describes common characteristics of GUID bugs, and offers some GUID management techniques.

GUIDs are the same as UUIDs (Universally Unique Identifiers). A class identifier (CLSID) is a UUID/GUID that refers to a class.


The System Registry

The system registry is a central repository containing information about objects. GUIDs are used to index that information. You can view the registration information on your system by running REGEDIT with the /V option:

regedit /v

Typically, a name is connected with a GUID (for example, "Hello.Application" maps to a GUID) and then the GUID is connected to all the other relevant aspects (for example, the GUID maps to "HELLO.EXE").

You create GUIDs with the tool GUIDGEN.EXE. Running GUIDGEN.EXE produces a huge hex number which uniquely identifies your object, whether it be a class, an interface, a library, or some other kind of object.


Where GUIDs Live

GUIDs appear in the following places:

•	.REG files — When you create an application, you usually create one or more .REG files. The .REG files contain the GUIDs for the classes that your application exposes. These GUIDs are added to the registry when you run REGEDIT.EXE to register your classes, or when you register type information with LoadTypeLib.

•	The system registry — Contains the GUIDs for your classes in multiple places. This is where OLE and applications get information about your classes.

•	.ODL files — When you describe objects in an Object Description Language (.ODL) file, you provide a GUID for each object. Compiling the .ODL file with MKTYPLIB.EXE places the GUIDs in a type library, which usually exists as a .TLB file. If you change a GUID in an .ODL file, make sure that you run MkTypLib again.

•	.TLB files — Type libraries describe your classes, and this information includes the GUIDs for the classes. You can browse .TLB files using the TIBROWSE sample application supplied with OLE.

•	.H files — Most application developers will declare CLSIDs for their classes in a header file using the DEFINE_GUID macro.


Troubleshooting

The following are common problems with GUIDs.

Problem

"GetObject can't seem to create an instance of my application."

Solution

Visual Basic uses the OLE calls listed in Appendix C to find the .EXE file that creates your application instance.

Visual Basic proceeds as follows

1.	Looks up the GUID for your object. For the Hello application, Visual Basic maps the ProgID Hello.Application into a GUID.

2.	Finds the object's server. This is HELLO.EXE for the Hello application.

3.	Launches the application.

If an error occurs, check the following:

•	Did you remember to run the .REG file?

•	Are the entries in the registry correct? Check to see if all the GUIDs match.

•	Can the application be launched? The executable (.EXE) file for the application, listed in the LocalServer entry, should either be on the path or it should be fully specified, for example, c:\ole2\sample\hello\hello.bin.

Problem

"When I use GetObject, the application launches and then the GetObject call fails."

Solution

Normally, a class factory is registered using CoRegisterClassObject when your application is started. Some applications register their class factories only when launched with the /Automation switch. If you inherited code or copied a sample, you should find out whether it checks for this switch. The /Automation option could appear in the .REG file, the registry, or in your development environment.

Problem

"GetTypeInfoOfGuid() is failing to get the type information from my type library."

Solution

When you call GetTypeInfoOfGuid, you provide a GUID. If this GUID doesn't match the GUID in your .TLB file, no type information will be returned. The GUID in your code is likely to be declared in a header file. You can check the GUID in your .TLB file by using BROWSE, which is provided with OLE, or with the Visual Basic Object Browser.


GUID Management

The problem with managing GUIDs is that they are pervasive, and their length prohibits simple comparisons.

The single most important technique in managing GUIDs is to keep a central list of all the GUIDs you use. Use the MAKE_GUID macro or the GUIDGEN tool with the -n option to generate the required number of GUIDs, and place the resulting strings in the first column of a spreadsheet. Each time you use a new GUID, enter a description of its purpose in the second column of the spreadsheet.

Keeping a central list has several advantages:

•	Listing all the GUIDs in one location may prevent you from accidentally reusing a GUID. This often happens when you clone an application in order to create another one.

•	You can use the spreadsheet to compare GUIDs. You can check that a GUID is correct by copying it from the place where it is being used (for example, a .REG file), pasting it into the spreadsheet, and then comparing the two cells with the "="operator.

•	You'll have a record of your GUID use in case of future problems, and you'll have a single source of information to find the GUID for your object.


 BROWSE

SAMPLE: BROWSE: OLE Automation controller

BROWSE is an automation  controller that controls the automation objects of the  BROWSEH (Browse Helper) inproc server to browse a type library. BROWSE is a developer-oriented type library browser.

In addition to displaying type library information, this sample shows how to control an automation object by accessing it's properties and methods.

(BROWSEH is an Automation object that exposes the type information of a  type library. BROWSEH is shipped as sample code with this release).

To compile: -----------

Requires OLE 2.02 or later. Use the external makefile called makefile to compile.

To run: -------

Run browse.exe and use the menu to select a type library to browse.

Files: ------

INVHELP.CPP, INVHELP.H contains two helper functions that are useful to create an automation object (CreateObject()) and to invoke a method or property of that object (Invoke()). These functions are general enough to be used by any Automation controller.

BROWSE.CPP uses the helper functions in invhelp.cpp to access the properties and methods of the automation objects of BROWSEH.

MAKEFILE makefile.

================================================================================


 MAKEFILE   (BROWSE OLE Sample)

####

#makefile - makefile for browse.exe

#

#       Copyright (C) 1994, Microsoft Corporation

#

#Purpose:

#  Builds the OLE 2.0 Automation controller, browse.exe.

#

#

#  Usage: NMAKE                 ; build with defaults

#     or: NMAKE option          ; build with the given option(s)

#     or: NMAKE clean           ; erase all compiled files

#

#     option: dev = [win16 | win32]    ; dev=win32 is the default

#             DEBUG=[0 | 1]            ; DEBUG=1 is the default

#             HOST=[DOS | NT | WIN95]  ; HOST=DOS (for win16)

#                                      ; HOST=NT (for win32 on NT)

#                                      ; HOST=WIN95 (for win32 on Win95)

#

#Notes:

#  This makefile assumes that the PATH, INCLUDE and LIB environment

#  variables are setup properly.

#

##############################################################################

##########################################################################

#

# Default Settings

#

CPU = i386

!if "$(dev)" == ""

dev = win32

HOST = NT

!endif

!if !("$(dev)" == "win16" || "$(dev)" == "win32")

!error Invalid dev option, choose from [win16 | win32]

!endif

!if "$(dev)" == "win16"

TARGET  = WIN16

!if "$(HOST)" == ""

HOST  = DOS

!endif

!endif

!if "$(dev)" == "win32"

TARGET  = WIN32

!if "$(HOST)" == ""

HOST  = NT

!endif

!endif

!ifdef NODEBUG

DEBUG = 0

!endif

!if "$(DEBUG)" == "0"

NODEBUG = 1

!endif

!if "$(DEBUG)" == ""

DEBUG = 1

!endif

##########################################################################

#

# WIN16 Settings

#

!if "$(TARGET)" == "WIN16"

CC   = cl

LINK = link

!if "$(HOST)" == "DOS"

WX   = wx /w

!else

WX   =

!endif

RCFLAGS = -dWIN16

CFLAGS = -c -W3 -AM -GA -GEs -DWIN16

LINKFLAGS = /NOD /NOI /BATCH /ONERROR:NOEXE

LIBS = libw.lib mlibcew.lib

!if "$(DEBUG)" == "1"

CFLAGS = $(CFLAGS) -Od -Zi -D_DEBUG $(CL)

LINKFLAGS = $(LINKFLAGS) /COD

!else

CFLAGS = $(CFLAGS) -Ox $(CL)

LINKFLAGS = $(LINKFLAGS) /FAR /PACKC

!endif

!endif

##########################################################################

#

# WIN32 Settings

#

!if "$(TARGET)" == "WIN32"

WX =

!include <ntwin32.mak>

CC = $(cc)

CFLAGS = $(cflags) $(cvarsmt) -DINC_OLE2 $(cdebug)

!if "$(HOST)" == "NT"

CFLAGS = $(CFLAGS) -DUNICODE

!endif

!ifndef NODEBUG

CFLAGS = $(CFLAGS) -D_DEBUG

!endif

LINK = $(link)

LINKFLAGS = $(linkdebug) $(guilflags)

RCFLAGS = -DWIN32

!endif

##########################################################################

#

# Build rules

#

.cpp.obj:

    @echo Compiling $<...

    $(CC) $<

.c.obj:

    @echo Compiling $<...

    $(CC) $<

##########################################################################

#

# Application Settings

#

APPS = browse

!if "$(TARGET)" == "WIN16"

LIBS = commdlg.lib ole2.lib compobj.lib ole2disp.lib typelib.lib $(LIBS)

!endif

!if "$(TARGET)" == "WIN32"

LIBS = $(ole2libsmt)

!endif

OBJS = browse.obj invhelp.obj

##########################################################################

#

# Default Goal

#

goal : setflags $(APPS).exe

setflags :

    set CL=$(CFLAGS)

##########################################################################

#

# Clean (erase) generated files

#

clean :

    if exist *.obj       del *.obj

    if exist $(APPS).exe del $(APPS).exe

    if exist $(APPS).map del $(APPS).map

    if exist $(APPS).res del $(APPS).res

    if exist *.pdb       del *.pdb

##########################################################################

#

# Application Build (WIN16 Specific)

#

!if "$(TARGET)" == "WIN16"

$(APPS).exe : $(OBJS) $(APPS).def $(APPS).res $(APPS).ico

    link $(LINKFLAGS) @<<

$(OBJS),

$@,,

$(LIBS),

$(APPS).def

<<

    rc -k -t $(APPS).res $@

!endif

##########################################################################

#

# Application Build (WIN32 Specific)

#

!if "$(TARGET)" == "WIN32"

$(APPS).exe : $(OBJS) $(APPS).def $(APPS).res $(APPS).ico

      $(LINK) @<<

        $(LINKFLAGS)

        -out:$@

        -map:$*.map

        $(OBJS)

        $(APPS).res

        $(LIBS)

<<

!endif

##########################################################################

#

# Application Build (Common)

#

$(APPS).res : $(APPS).rc

    rc $(RCFLAGS) -r -fo$@ $?

##########################################################################

#

# Dependencies

#

browse.obj : browse.cpp browse.h resource.h

     $(CC) browse.cpp

invhelp.obj : invhelp.cpp invhelp.h

     $(CC) invhelp.cpp


 BROWSE.H   (BROWSE OLE Sample)

#ifdef WIN32

#ifdef UNICODE

    #define FROM_OLE_STRING(str) str

    #define TO_OLE_STRING(str) str

#else

    #define FROM_OLE_STRING(str) ConvertToAnsi(str)

    char* ConvertToAnsi(OLECHAR FAR* szW);

    #define TO_OLE_STRING(str) ConvertToUnicode(str)

    OLECHAR* ConvertToUnicode(char FAR* szA);

    // Maximum length of string that can be converted between Ansi & Unicode

    #define STRCONVERT_MAXLEN 500

#endif

#else  // WIN16

  #define APIENTRY far pascal

  #define TCHAR char

  #define TEXT(sz) sz

  #define FROM_OLE_STRING(str) str

  #define TO_OLE_STRING(str) str

  #define LPTSTR LPSTR

  #define LPCTSTR LPCSTR

  // Windows NT defines the following in windowsx.h

  #define GET_WM_COMMAND_ID(w,l) (w)

  #define GET_WM_COMMAND_CMD(w,l) HIWORD(l)

  #define GET_WM_COMMAND_HWND(w,l) LOWORD(l)

#endif

// Function prototypes

int APIENTRY WinMain (HINSTANCE, HINSTANCE, LPSTR, int);

#ifdef WIN16

BOOL __export CALLBACK MainDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);

#else

BOOL CALLBACK MainDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);

#endif

typedef enum {

    TYPE_FUNCTION = 0,

    TYPE_PROPERTY = 1,

    TYPE_CONSTANT = 2,

    TYPE_PARAMETER = 3

} OBJTYPE;

class CBrowseApp

{

public:

    void Init(HWND hwndMain);

    void Cleanup();

    void ClearTypeLibStaticFields();

    void ClearTypeInfoStaticFields();

    void ClearElementStaticFields();

    void ClearParamStaticFields();

    HRESULT BrowseTypeLibrary();

    HRESULT ChangeTypeInfosSelection();

    HRESULT ChangeElementsSelection();

    HRESULT ChangeParametersSelection();

    void OpenElementHelpFile();

    void EmptyList(HWND hwndList);

    HRESULT LoadList(LPDISPATCH pdispItems, int nListID);

    HRESULT TypeToString(LPDISPATCH pdispTypeDesc, LPTSTR pszTypeName);

    void IDLFlagsToString(int n, LPTSTR psz);

    void CallConvToString(int n, LPTSTR psz);

    void FuncKindToString(int n, LPTSTR psz);

    void InvokeKindToString(int n, LPTSTR psz);

    void VariantToString(VARIANT v, LPTSTR psz);

private:

   HINSTANCE m_hinst;           // App's HINSTANCE.

   HWND m_hwndMain;             // App's main window which is a dialog..

   HFONT m_hfont;               // Non-bold font used for dialog fields.

   TCHAR m_szHelpFile[128];     // Help file used by type library being browsed.

   long m_lElemHelpCtx;         // Help context of TypeInfo element being browsed.

};


 INVHELP.H   (BROWSE OLE Sample)

HRESULT CreateObject(LPOLESTR pszProgID, IDispatch FAR* FAR* ppdisp);

HRESULT

Invoke(LPDISPATCH pdisp,

    WORD wFlags,

    LPVARIANT pvRet,

    EXCEPINFO FAR* pexcepinfo,

    UINT FAR* pnArgErr,

    LPOLESTR pszName,

    LPCTSTR pszFmt,

    ...);


 RESOURCE.H   (BROWSE OLE Sample)

//{{NO_DEPENDENCIES}}

// App Studio generated include file.

// Used by BROWSER.RC

//

#define IDD_MAINDIALOG                  101

#define ID_MENU                         102

#define ID_ICON                         103

#define IDC_TYPEINFOSLIST               1001

#define IDC_ELEMENTSLIST                1002

#define IDC_PARAMETERSLIST              1003

#define IDC_TYPELIB_NAME                1004

#define IDC_TYPELIB_DOC                 1005

#define IDC_TYPELIB_VERSION             1006

#define IDC_TYPELIB_HELPFILE            1007

#define IDC_TYPELIB_LCID                1008

#define IDC_TYPEINFO_TYPE               1009

#define IDC_TYPEINFO_HELPCTX            1010

#define IDC_TYPEINFO_DOC                1011

#define IDC_TYPEINFO_ALIASTYPE          1012

#define IDC_ELEM_TYPE                   1013

#define IDC_ELEM_HELPCTX                1014

#define IDC_ELEM_FUNCKIND               1015

#define IDC_ELEM_CALLCONV               1016

#define IDC_ELEM_INVOKEKIND             1017

#define IDC_ELEM_MEMID                  1018

#define IDC_ELEM_CONST_VALUE            1019

#define IDC_ELEM_DOC                    1020

#define IDC_PARAM_TYPE                  1021

#define IDC_PARAM_INOUT                 1022

#define IDC_ELEM_OPEN_HELPFILE          1023

#define IDC_TYPELIB_FIRST               1004

#define IDC_TYPELIB_LAST                1008

#define IDC_TYPEINFO_FIRST              1009

#define IDC_TYPEINFO_LAST               1012

#define IDC_ELEM_FIRST                  1013

#define IDC_ELEM_LAST                   1020

#define IDC_PARAM_FIRST                 1021

#define IDC_PARAM_LAST                  1022

#define IDM_FILEOPEN                    40001

#define IDM_EXIT                        40002

#define IDC_STATIC                      -1


 BROWSE.CPP   (BROWSE OLE Sample)

/*************************************************************************

**

**    Type Library Browser

**

**    browseex.cpp

**

**

**     Written by Microsoft Product Support Services, Windows Developer Support

**    (c) Copyright Microsoft Corp. 1994 All Rights Reserved

**

*************************************************************************/

#include <windows.h>

#include <windowsx.h>

#ifdef WIN16

  #include <ole2.h>

  #include <compobj.h>

  #include <dispatch.h>

  #include <variant.h>

  #include <olenls.h>

  #include <commdlg.h>

#endif

#include "resource.h"

#include "browse.h"

#include "invhelp.h"

CBrowseApp BrowseApp;         // Application

int APIENTRY WinMain (HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpCmdLine, int nCmdShow)

{

   WNDCLASS wc;

   HRESULT hr;

   //  It is recommended that all OLE applications set

   //  their message queue size to 96. This improves the capacity

   //  and performance of OLE's LRPC mechanism.

   int cMsg = 96;                  // Recommend msg queue size for OLE

   while (cMsg && !SetMessageQueue(cMsg))  // take largest size we can get.

       cMsg -= 8;

   if (!cMsg)

       return -1;

   // Register class for the dialog that is the main window.

   wc.style = 0;

   wc.lpfnWndProc = DefDlgProc;

   wc.cbClsExtra = 0;

   wc.cbWndExtra = DLGWINDOWEXTRA;

   wc.hInstance = hinst;

   wc.hIcon = LoadIcon(hinst, MAKEINTRESOURCE(ID_ICON));

   wc.hCursor = LoadCursor(NULL, IDC_ARROW);

   wc.hbrBackground = HBRUSH(COLOR_WINDOW + 1);

   wc.lpszMenuName = NULL;

   wc.lpszClassName = TEXT("DlgClass");

   RegisterClass(&wc);

   hr = OleInitialize(NULL);

   if FAILED(hr)

   {

       MessageBox(NULL, TEXT("Could not Intialize OLE"), TEXT("Error"), MB_ICONEXCLAMATION|MB_OK);

       return 0;

   }

   DialogBox(hinst, MAKEINTRESOURCE(IDD_MAINDIALOG), NULL, (DLGPROC)MainDialogFunc);

   OleUninitialize();

   return 0;

}

BOOL CALLBACK MainDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)

{

   HRESULT hr;

   switch (msg)

   {

      case WM_INITDIALOG:

          BrowseApp.Init(hwndDlg);

          return FALSE;

      case WM_COMMAND:

         switch(GET_WM_COMMAND_ID(wParam,lParam))

         {

             case IDM_EXIT:

             case IDCANCEL:

                 BrowseApp.Cleanup();

                 EndDialog(hwndDlg, IDOK);

                 CoFreeUnusedLibraries();

                 return TRUE;

             case IDM_FILEOPEN:

                 hr = BrowseApp.BrowseTypeLibrary();

                 if (FAILED(hr))

                     MessageBox(hwndDlg, TEXT("Failed to browse type library"), TEXT("Error"), MB_ICONEXCLAMATION|MB_OK);

                 return TRUE;

             case IDC_TYPEINFOSLIST:

                 switch (GET_WM_COMMAND_CMD(wParam, lParam))

                 {

                     case LBN_SELCHANGE:

                         hr = BrowseApp.ChangeTypeInfosSelection();

                         if (FAILED(hr))

                             MessageBox(hwndDlg, TEXT("Failed to get TypeInfo information"), TEXT("Error"), MB_ICONEXCLAMATION|MB_OK);

                         return TRUE;

                 }

                 break;

             case IDC_ELEMENTSLIST:

                 switch (GET_WM_COMMAND_CMD(wParam, lParam))

                 {

                     case LBN_SELCHANGE:

                         hr = BrowseApp.ChangeElementsSelection();

                         if (FAILED(hr))

                             MessageBox(hwndDlg, TEXT("Failed to get Element information"), TEXT("Error"), MB_ICONEXCLAMATION|MB_OK);

                         return TRUE;

                 }

                 break;

             case IDC_PARAMETERSLIST:

                 switch (GET_WM_COMMAND_CMD(wParam, lParam))

                 {

                     case LBN_SELCHANGE:

                         hr = BrowseApp.ChangeParametersSelection();

                         if (FAILED(hr))

                             MessageBox(hwndDlg, TEXT("Failed to get Parameter information"), TEXT("Error"), MB_ICONEXCLAMATION|MB_OK);

                         return TRUE;

                 }

                 break;

             case IDC_ELEM_OPEN_HELPFILE:

                 BrowseApp.OpenElementHelpFile();

                 return TRUE;

         }

         break;

   }

   return FALSE;

}

/*

 * CBrowseApp::BrowseTypeLibrary

 *

 * Purpose:

 *  Prompts user for type library. Fills the TypeInfo list with the TypeInfos of

 *  the type library.

 *

 */

HRESULT CBrowseApp::BrowseTypeLibrary()

{

    OPENFILENAME   ofn;

    TCHAR szFileName[128];

    BOOL bRes;

    VARIANT vRet;

    EXCEPINFO excepinfo;

    UINT nArgErr;

    HRESULT hr;

    HCURSOR hcursorOld;

    LPDISPATCH pdispBrowseHelper = NULL;

    LPDISPATCH pdispTypeLibrary = NULL;

    LPDISPATCH pdispTypeInfos = NULL;

    TCHAR szTemp[100];

    // Prompt user for type library

    szFileName[0] = '\0';

    _fmemset(&ofn, 0, sizeof(ofn));

    ofn.lStructSize = sizeof(ofn);

    ofn.hwndOwner = m_hwndMain;

    ofn.lpstrFile = szFileName;

    ofn.nMaxFile  = sizeof(szFileName);

    ofn.hInstance = m_hinst;

    ofn.lpstrFilter  = TEXT("Type Libraries *.tlb,*.olb\0*.tlb;*.olb\0All Files *.*\0*.*\0\0");

    ofn.nFilterIndex = 1;

    ofn.Flags= OFN_FILEMUSTEXIST;

    bRes = GetOpenFileName(&ofn);

    if (!bRes)

        return ResultFromScode(S_FALSE);

    // Empty lists and clear fields.

    EmptyList(GetDlgItem(m_hwndMain, IDC_TYPEINFOSLIST));

    EmptyList(GetDlgItem(m_hwndMain, IDC_ELEMENTSLIST));

    EmptyList(GetDlgItem(m_hwndMain, IDC_PARAMETERSLIST));

    ClearTypeLibStaticFields();

    ClearTypeInfoStaticFields();

    ClearElementStaticFields();

    ClearParamStaticFields();

    EnableWindow(GetDlgItem(m_hwndMain, IDC_ELEM_OPEN_HELPFILE), FALSE);

    hcursorOld = SetCursor(LoadCursor(NULL, IDC_WAIT));

    // Create BrowseHelper object

    hr = CreateObject(OLESTR("BrowseHelper.Browser"), &pdispBrowseHelper);

    if (FAILED(hr))

    {

        MessageBox(m_hwndMain, TEXT("Failed to create BrowseHelper object"), TEXT("Error"), MB_ICONEXCLAMATION|MB_OK);

        goto error;

    }

    // Invoke IBrowseHelper.BrowseTypeLibrary(szFileName). Returns ITypeLibrary.

    hr = Invoke(pdispBrowseHelper, DISPATCH_METHOD, &vRet, &excepinfo, &nArgErr,

                      OLESTR("BrowseTypeLibrary"), TEXT("s"), (LPOLESTR)TO_OLE_STRING(szFileName));

    if (FAILED(hr))

        goto error;

    pdispTypeLibrary = V_DISPATCH(&vRet);

    // Invoke ITypeLibrary.Name. Returns BSTR.

    hr = Invoke(pdispTypeLibrary, DISPATCH_PROPERTYGET, &vRet, &excepinfo, &nArgErr,

                OLESTR("Name"), TEXT(""));

    if (FAILED(hr))

        goto error;

    SetDlgItemText(m_hwndMain, IDC_TYPELIB_NAME, FROM_OLE_STRING(V_BSTR(&vRet)));

    VariantClear(&vRet);

    // Invoke ITypeLibrary.HelpFile. Returns BSTR.

    hr = Invoke(pdispTypeLibrary, DISPATCH_PROPERTYGET, &vRet, &excepinfo, &nArgErr,

                OLESTR("HelpFile"), TEXT(""));

    if (FAILED(hr))

        goto error;

    SetDlgItemText(m_hwndMain, IDC_TYPELIB_HELPFILE, FROM_OLE_STRING(V_BSTR(&vRet)));

    if (NULL == V_BSTR(&vRet))

        m_szHelpFile[0] = '\0';

    else lstrcpy(m_szHelpFile, FROM_OLE_STRING(V_BSTR(&vRet)));

    VariantClear(&vRet);

    // Invoke ITypeLibrary.Documentation. Returns BSTR.

    hr = Invoke(pdispTypeLibrary, DISPATCH_PROPERTYGET, &vRet, &excepinfo, &nArgErr,

                OLESTR("Documentation"), TEXT(""));

    if (FAILED(hr))

        goto error;

    SetDlgItemText(m_hwndMain, IDC_TYPELIB_DOC, FROM_OLE_STRING(V_BSTR(&vRet)));

    VariantClear(&vRet);

    // Invoke ITypeLibrary.LocaleID. Returns VT_I4.

    hr = Invoke(pdispTypeLibrary, DISPATCH_PROPERTYGET, &vRet, &excepinfo, &nArgErr,

                OLESTR("LocaleID"), TEXT(""));

    if (FAILED(hr))

        goto error;

    wsprintf(szTemp, TEXT("0x%lx"), V_I4(&vRet));

    SetDlgItemText(m_hwndMain, IDC_TYPELIB_LCID, szTemp);

    // Invoke ITypeLibrary.MajorVersion. Returns VT_I2.

    hr = Invoke(pdispTypeLibrary, DISPATCH_PROPERTYGET, &vRet, &excepinfo, &nArgErr,

                OLESTR("MajorVersion"), TEXT(""));

    if (FAILED(hr))

        goto error;

    wsprintf(szTemp, TEXT("%d"), V_I2(&vRet));

    // Invoke ITypeLibrary.MinorVersion. Returns VT_I2.

    hr = Invoke(pdispTypeLibrary, DISPATCH_PROPERTYGET, &vRet, &excepinfo, &nArgErr,

                OLESTR("MinorVersion"), TEXT(""));

    if (FAILED(hr))

        goto error;

    wsprintf(szTemp, TEXT("%s.%d"), (LPSTR)szTemp, V_I2(&vRet));

    SetDlgItemText(m_hwndMain, IDC_TYPELIB_VERSION, szTemp);

    // Invoke ITypeLibrary.TypeInfos. Returns ICollection of ITypeInfo.

    hr = Invoke(pdispTypeLibrary, DISPATCH_PROPERTYGET, &vRet, &excepinfo, &nArgErr,

                OLESTR("TypeInfos"), TEXT(""));

    if (FAILED(hr))

        goto error;

    pdispTypeInfos = V_DISPATCH(&vRet);

    // Load TypeInfo list with the names of the type infos.

    hr = LoadList(pdispTypeInfos, IDC_TYPEINFOSLIST);

    if (FAILED(hr))

        goto error;

    pdispBrowseHelper->Release();

    pdispTypeLibrary->Release();

    pdispTypeInfos->Release();

    SetCursor(hcursorOld);

    return NOERROR;

error:

    if (pdispBrowseHelper) pdispBrowseHelper->Release();

    if (pdispTypeLibrary) pdispTypeLibrary->Release();

    if (pdispTypeInfos) pdispTypeLibrary->Release();

    VariantClear(&vRet);

    SetCursor(hcursorOld);

    return hr;

}

/*

 * CBrowseApp::ChangeTypeInfosSelection

 *

 * Purpose:

 *  Called when user changes selection in TypeInfos list box. Information

 *  about the the selected TypeInfo is dispayed. Elements of the TypeInfo

 *  are placed in the Elements list box.

 *

 */

HRESULT CBrowseApp::ChangeTypeInfosSelection()

{

    int nCurSel;

    VARIANT vRet;

    EXCEPINFO excepinfo;

    UINT nArgErr;

    HRESULT hr;

    HCURSOR hcursorOld;

    LPDISPATCH pdispTypeInfo;

    TYPEKIND typekind;

    TCHAR szTemp[100];

    LPDISPATCH pdispElements = NULL;

    LPDISPATCH pdispMembers = NULL;

    LPDISPATCH pdispFunctions = NULL;

    LPDISPATCH pdispProperties = NULL;

    LPDISPATCH pdispMethods = NULL;

    LPDISPATCH pdispInterfaces = NULL;

    LPDISPATCH pdispTypeDesc = NULL;

    // Get current selection in TypeInfos list.

    nCurSel = (int)SendDlgItemMessage(m_hwndMain, IDC_TYPEINFOSLIST, LB_GETCURSEL, 0, 0L);

    if (nCurSel == LB_ERR)

        return NOERROR;

    // Get IDispatch* of selected TypeInfo.

    pdispTypeInfo = (LPDISPATCH) SendDlgItemMessage(m_hwndMain, IDC_TYPEINFOSLIST, LB_GETITEMDATA,

                (WPARAM)nCurSel, 0L);

    // Empty Elements & Parameters lists.

    EmptyList(GetDlgItem(m_hwndMain, IDC_ELEMENTSLIST));

    EmptyList(GetDlgItem(m_hwndMain, IDC_PARAMETERSLIST));

    ClearElementStaticFields();

    ClearParamStaticFields();

    ClearTypeInfoStaticFields();

    hcursorOld = SetCursor(LoadCursor(NULL, IDC_WAIT));

    // Invoke ITypeInformation.HelpContext. Returns VT_I4.

    hr = Invoke(pdispTypeInfo, DISPATCH_PROPERTYGET, &vRet, &excepinfo, &nArgErr,

                OLESTR("HelpContext"), TEXT(""));

    if (FAILED(hr))

        goto error;

    wsprintf(szTemp, TEXT("%ld"), V_I4(&vRet));

    SetDlgItemText(m_hwndMain, IDC_TYPEINFO_HELPCTX, szTemp);

    // Invoke ITypeInformation.Documentation. Returns BSTR.

    hr = Invoke(pdispTypeInfo, DISPATCH_PROPERTYGET, &vRet, &excepinfo, &nArgErr,

                OLESTR("Documentation"), TEXT(""));

    if (FAILED(hr))

        goto error;

    SetDlgItemText(m_hwndMain, IDC_TYPEINFO_DOC, FROM_OLE_STRING(V_BSTR(&vRet)));

    VariantClear(&vRet);

    // Invoke ITypeInformation.TypeInfoKind. Returns TYPEKIND.

    hr = Invoke(pdispTypeInfo, DISPATCH_PROPERTYGET, &vRet, &excepinfo, &nArgErr,

                OLESTR("TypeInfoKind"), TEXT(""));

    if (FAILED(hr))

        goto error;

    typekind = (TYPEKIND)V_I2(&vRet);

    switch (typekind)

    {

        case TKIND_ENUM:

            SetDlgItemText(m_hwndMain, IDC_TYPEINFO_TYPE, TEXT("TKIND_ENUM"));

            // Invoke IEnum.Elements. Returns ICollection of IConstant.

            hr = Invoke(pdispTypeInfo, DISPATCH_PROPERTYGET, &vRet, &excepinfo, &nArgErr,

                        OLESTR("Elements"), TEXT(""));

            if (FAILED(hr))

                goto error;

            pdispElements = V_DISPATCH(&vRet);

            // Put the Enumerator constants in the Elements list.

            hr = LoadList(pdispElements, IDC_ELEMENTSLIST);

            if (FAILED(hr))

                goto error;

            pdispElements->Release();

            break;

        case TKIND_RECORD:

            SetDlgItemText(m_hwndMain, IDC_TYPEINFO_TYPE, TEXT("TKIND_RECORD"));

            // Invoke IStruct.Members. Returns ICollection of IProperty.

            hr = Invoke(pdispTypeInfo, DISPATCH_PROPERTYGET, &vRet, &excepinfo, &nArgErr,

                        OLESTR("Members"), TEXT(""));

            if (FAILED(hr))

                goto error;

            pdispMembers = V_DISPATCH(&vRet);

            // Put the Structure memebers in the Elements list.

            hr = LoadList(pdispMembers, IDC_ELEMENTSLIST);

            if (FAILED(hr))

                goto error;

            pdispMembers->Release();

            break;

        case TKIND_MODULE:

            SetDlgItemText(m_hwndMain, IDC_TYPEINFO_TYPE, TEXT("TKIND_MODULE"));

            // Invoke IModule.Functions. Returns ICollection of IFunction.

            hr = Invoke(pdispTypeInfo, DISPATCH_PROPERTYGET, &vRet, &excepinfo, &nArgErr,

                        OLESTR("Functions"), TEXT(""));

            if (FAILED(hr))

                goto error;

            pdispFunctions = V_DISPATCH(&vRet);

            // Put the Module functions in the Elements list.

            hr = LoadList(pdispFunctions, IDC_ELEMENTSLIST);

            if (FAILED(hr))

                goto error;

            pdispFunctions->Release();

            break;

        case TKIND_INTERFACE:

            SetDlgItemText(m_hwndMain, IDC_TYPEINFO_TYPE, TEXT("TKIND_INTERFACE"));

            // Invoke IInterface.Functions. Returns ICollection of IFunction.

            hr = Invoke(pdispTypeInfo, DISPATCH_PROPERTYGET, &vRet, &excepinfo, &nArgErr,

                        OLESTR("Functions"), TEXT(""));

            if (FAILED(hr))

                goto error;

            pdispFunctions = V_DISPATCH(&vRet);

            // Put the Interface functions in the Elements list.

            hr = LoadList(pdispFunctions, IDC_ELEMENTSLIST);

            if (FAILED(hr))

                goto error;

            pdispFunctions->Release();

            break;

        case TKIND_DISPATCH:

            SetDlgItemText(m_hwndMain, IDC_TYPEINFO_TYPE, TEXT("TKIND_DISPATCH"));

            // Invoke Dispinterface.Properties. Returns ICollection of IProperty.

            hr = Invoke(pdispTypeInfo, DISPATCH_PROPERTYGET, &vRet, &excepinfo, &nArgErr,

                        OLESTR("Properties"), TEXT(""));

            if (FAILED(hr))

                goto error;

            pdispProperties = V_DISPATCH(&vRet);

            // Invoke IDispinterface.Methods. Returns ICollection of IFunction.

            hr = Invoke(pdispTypeInfo, DISPATCH_PROPERTYGET, &vRet, &excepinfo, &nArgErr,

                        OLESTR("Methods"), TEXT(""));

            if (FAILED(hr))

                goto error;

            pdispMethods = V_DISPATCH(&vRet);

            // Put the Dispinterface properties and methods in the Elements list.

            hr = LoadList(pdispProperties, IDC_ELEMENTSLIST);

            if (FAILED(hr))

                goto error;

            pdispProperties->Release();

            hr = LoadList(pdispMethods, IDC_ELEMENTSLIST);

            if (FAILED(hr))

                goto error;

            pdispMethods->Release();

            break;

        case TKIND_COCLASS:

            SetDlgItemText(m_hwndMain, IDC_TYPEINFO_TYPE, TEXT("TKIND_COCLASS"));

            // Invoke ICoClass.Interfaces. Returns ICollection of IInterface & IDispinterface.

            hr = Invoke(pdispTypeInfo, DISPATCH_PROPERTYGET, &vRet, &excepinfo, &nArgErr,

                        OLESTR("Interfaces"), TEXT(""));

            if (FAILED(hr))

                goto error;

            pdispInterfaces = V_DISPATCH(&vRet);

            // Put the CoClass interfaces and dispinterfaces in the Elements list.

            hr = LoadList(pdispInterfaces, IDC_ELEMENTSLIST);

            if (FAILED(hr))

                goto error;

            pdispInterfaces->Release();

            break;

        case TKIND_ALIAS:

            // An alias does not have elements. Display the base type.

            SetDlgItemText(m_hwndMain, IDC_TYPEINFO_TYPE, TEXT("TKIND_ALIAS"));

            // Invoke IAlias.BaseType. Returns ITypeDesc.

            hr = Invoke(pdispTypeInfo, DISPATCH_PROPERTYGET, &vRet, &excepinfo, &nArgErr,

                        OLESTR("BaseType"), TEXT(""));

            if (FAILED(hr))

                goto error;

            pdispTypeDesc = V_DISPATCH(&vRet);

            szTemp[0] = '\0'; // Must initialize to empty string before calling TypeToString.

            hr = TypeToString(pdispTypeDesc, szTemp);

            if (FAILED(hr))

                goto error;

            SetDlgItemText(m_hwndMain, IDC_TYPEINFO_ALIASTYPE, szTemp);

            pdispTypeDesc->Release();

            break;

        case TKIND_UNION:

            SetDlgItemText(m_hwndMain, IDC_TYPEINFO_TYPE, TEXT("TKIND_UNION"));

            // Invoke IUnion.Members. Returns ICollection of IProperty.

            hr = Invoke(pdispTypeInfo, DISPATCH_PROPERTYGET, &vRet, &excepinfo, &nArgErr,

                        OLESTR("Members"), TEXT(""));

            if (FAILED(hr))

                goto error;

            pdispMembers = V_DISPATCH(&vRet);

            // Put the Union members in the Elements list.

            hr = LoadList(pdispMembers, IDC_ELEMENTSLIST);

            if (FAILED(hr))

                goto error;

            pdispMembers->Release();

            break;

    }

    SetCursor(hcursorOld);

    return NOERROR;

error:

    if (pdispElements) pdispElements->Release();

    if (pdispMembers) pdispMembers->Release();

    if (pdispFunctions) pdispFunctions->Release();

    if (pdispProperties) pdispProperties->Release();

    if (pdispMethods) pdispElements->Release();

    if (pdispInterfaces) pdispInterfaces->Release();

    if (pdispTypeDesc) pdispTypeDesc->Release();

    VariantClear(&vRet);

    SetCursor(hcursorOld);

    return hr;

}

/*

 * CBrowseApp::ChangeElementsSelection

 *

 * Purpose:

 *  Called when user changes selection in Elements list box. Information

 *  about the the selected Element is dispayed. If the element is a function,

 *  the parameters are placed in the the Parameters list box.

 *

 */

HRESULT CBrowseApp::ChangeElementsSelection()

{

    int nCurSel;

    VARIANT vRet;

    EXCEPINFO excepinfo;

    UINT nArgErr;

    HRESULT hr;

    int nKind;

    TYPEKIND typekind;

    LPDISPATCH pdispElement;

    LPDISPATCH pdispParameters = NULL;

    LPDISPATCH pdispTypeDesc = NULL;

    TCHAR szTemp[100];

    // Disable the help file button.

    EnableWindow(GetDlgItem(m_hwndMain, IDC_ELEM_OPEN_HELPFILE), FALSE);

    // Get current selection in Elements list.

    nCurSel = (int)SendDlgItemMessage(m_hwndMain, IDC_ELEMENTSLIST, LB_GETCURSEL, 0, 0L);

    if (nCurSel == LB_ERR)

        return NOERROR;

    // Get IDispatch* of selected Element.

    pdispElement = (LPDISPATCH) SendDlgItemMessage(m_hwndMain, IDC_ELEMENTSLIST, LB_GETITEMDATA,

                (WPARAM)nCurSel, 0L);

    // Empty Parameters lists.

    EmptyList(GetDlgItem(m_hwndMain, IDC_PARAMETERSLIST));

    ClearParamStaticFields();

    ClearElementStaticFields();

    // Invoke IFunction/IConstant/IProperty/IInterface/IDispinterface.HelpContext. Returns VT_I4.

    hr = Invoke(pdispElement, DISPATCH_PROPERTYGET, &vRet, &excepinfo, &nArgErr,

                OLESTR("HelpContext"), TEXT(""));

    if (FAILED(hr))

        goto error;

    wsprintf(szTemp, TEXT("%ld"), V_I4(&vRet));

    SetDlgItemText(m_hwndMain, IDC_ELEM_HELPCTX, szTemp);

    m_lElemHelpCtx = V_I4(&vRet);

    // Invoke IFunction/IConstant/IProperty/IInterface/IDispinterface.Documentation. Returns BSTR.

    hr = Invoke(pdispElement, DISPATCH_PROPERTYGET, &vRet, &excepinfo, &nArgErr,

                OLESTR("Documentation"), TEXT(""));

    if (FAILED(hr))

        goto error;

    SetDlgItemText(m_hwndMain, IDC_ELEM_DOC, FROM_OLE_STRING(V_BSTR(&vRet)));

    VariantClear(&vRet);

    // Invoke IFunction/IConstant/IProperty.MemberID. Returns VT_I4.

    hr = Invoke(pdispElement, DISPATCH_PROPERTYGET, &vRet, &excepinfo, &nArgErr,

                OLESTR("MemberID"), TEXT(""));

    if (FAILED(hr))

    {

        // This maybe a interface/dispinterface element of a coclass

        hr = Invoke(pdispElement, DISPATCH_PROPERTYGET, &vRet, &excepinfo, &nArgErr,

                OLESTR("TypeInfoKind"), TEXT(""));

        if (FAILED(hr))

            goto error;

        typekind = (TYPEKIND)V_I2(&vRet);

        if (typekind == TKIND_INTERFACE)

            SetDlgItemText(m_hwndMain, IDC_ELEM_TYPE, TEXT("TKIND_INTERFACE"));

        else if (typekind == TKIND_DISPATCH)

            SetDlgItemText(m_hwndMain, IDC_ELEM_TYPE, TEXT("TKIND_DISPATCH"));

        else SetDlgItemText(m_hwndMain, IDC_ELEM_TYPE, TEXT("Unknown element"));

        return NOERROR;

    }

    wsprintf(szTemp, TEXT("0x%lx"), V_I4(&vRet));

    SetDlgItemText(m_hwndMain, IDC_ELEM_MEMID, szTemp);

    // Invoke IFunction/IConstant/IProperty.Kind property. Returns OBJKIND.

    hr = Invoke(pdispElement, DISPATCH_PROPERTYGET, &vRet, &excepinfo, &nArgErr,

                OLESTR("Kind"), TEXT(""));

    if (FAILED(hr))

        goto error;

    nKind = V_I2(&vRet);

    switch (nKind)

    {

        case TYPE_FUNCTION: //Function

            // Invoke IFunction.Parameters. Returns ICollection of IParameter..

            hr = Invoke(pdispElement, DISPATCH_PROPERTYGET, &vRet, &excepinfo, &nArgErr,

                        OLESTR("Parameters"), TEXT(""));

            if (FAILED(hr))

                goto error;

            pdispParameters = V_DISPATCH(&vRet);

            hr = LoadList(pdispParameters, IDC_PARAMETERSLIST);

            if FAILED(hr)

                goto error;

            pdispParameters->Release(); pdispParameters = NULL;

            // Invoke IFunction.CallConvention. Returns CALLCONV.

            hr = Invoke(pdispElement, DISPATCH_PROPERTYGET, &vRet, &excepinfo, &nArgErr,

                OLESTR("CallConvention"), TEXT(""));

            if (FAILED(hr))

                goto error;

            CallConvToString(V_I2(&vRet), szTemp);

            SetDlgItemText(m_hwndMain, IDC_ELEM_CALLCONV, szTemp);

            // Invoke IFunction.FuncKind. Returns FUNCKIND.

            hr = Invoke(pdispElement, DISPATCH_PROPERTYGET, &vRet, &excepinfo, &nArgErr,

                OLESTR("FuncKind"), TEXT(""));

            if (FAILED(hr))

                goto error;

            FuncKindToString(V_I2(&vRet), szTemp);

            SetDlgItemText(m_hwndMain, IDC_ELEM_FUNCKIND, szTemp);

            // Invoke IFunction.InvocationKind. Returns INVOKEKIND.

            hr = Invoke(pdispElement, DISPATCH_PROPERTYGET, &vRet, &excepinfo, &nArgErr,

                OLESTR("InvocationKind"), TEXT(""));

            if (FAILED(hr))

                goto error;

            InvokeKindToString(V_I2(&vRet), szTemp);

            SetDlgItemText(m_hwndMain, IDC_ELEM_INVOKEKIND, szTemp);

            // Invoke IFunction.ReturnType. Returns ITypeDesc.

            hr = Invoke(pdispElement, DISPATCH_PROPERTYGET, &vRet, &excepinfo, &nArgErr,

                OLESTR("ReturnType"), TEXT(""));

            if (FAILED(hr))

                goto error;

            break;

        case TYPE_CONSTANT:

            // Invoke IConstant.Value. Returns VARIANT.

            hr = Invoke(pdispElement, DISPATCH_PROPERTYGET, &vRet, &excepinfo, &nArgErr,

                OLESTR("Value"), TEXT(""));

            if (FAILED(hr))

                goto error;

            VariantToString(vRet, szTemp);

            SetDlgItemText(m_hwndMain, IDC_ELEM_CONST_VALUE, szTemp);

            // Fall through to default.

        default:

            // Invoke IConstant/IProperty.Type. Returns ITypeDesc.

            hr = Invoke(pdispElement, DISPATCH_PROPERTYGET, &vRet, &excepinfo, &nArgErr,

                OLESTR("Type"), TEXT(""));

            if (FAILED(hr))

                goto error;

            break;

    }

    // Get string that describes type and display it.

    pdispTypeDesc = V_DISPATCH(&vRet);

    szTemp[0] = '\0'; // Must initialize to empty string before calling TypeToString.

    hr = TypeToString(pdispTypeDesc, szTemp);

    if (FAILED(hr))

        goto error;

    SetDlgItemText(m_hwndMain, IDC_ELEM_TYPE, szTemp);

    pdispTypeDesc->Release();

    // Enable the helpfile button if a helpfile and help context is specified.

    if (m_lElemHelpCtx && m_szHelpFile[0])

        EnableWindow(GetDlgItem(m_hwndMain, IDC_ELEM_OPEN_HELPFILE), TRUE);

    return NOERROR;

error:

    if (pdispParameters) pdispParameters->Release();

    VariantClear(&vRet);

    return hr;

}

/*

 * CBrowseApp::ChangeParametersSelection

 *

 * Purpose:

 *  Called when user changes selection in Parameters list box. Information

 *  about the the selected Parameter is dispayed.

 *

 */

HRESULT CBrowseApp::ChangeParametersSelection()

{

    int nCurSel;

    VARIANT vRet;

    EXCEPINFO excepinfo;

    UINT nArgErr;

    HRESULT hr;

    LPDISPATCH pdispParameter;

    LPDISPATCH pdispTypeDesc = NULL;

    TCHAR szTemp[100];

    // Get current selection in Parameters list.

    nCurSel = (int)SendDlgItemMessage(m_hwndMain, IDC_PARAMETERSLIST, LB_GETCURSEL, 0, 0L);

    if (nCurSel == LB_ERR)

        return NOERROR;

    // Get IDispatch* of selected Parameter.

    pdispParameter = (LPDISPATCH) SendDlgItemMessage(m_hwndMain, IDC_PARAMETERSLIST, LB_GETITEMDATA,

                (WPARAM)nCurSel, 0L);

    ClearParamStaticFields();

    // Invoke IParameter.IDLFlags. Returns VT_I2.

    hr = Invoke(pdispParameter, DISPATCH_PROPERTYGET, &vRet, &excepinfo, &nArgErr,

                OLESTR("IDLFlags"), TEXT(""));

    if (FAILED(hr))

        goto error;

    IDLFlagsToString(V_I2(&vRet), szTemp);

    SetDlgItemText(m_hwndMain, IDC_PARAM_INOUT, szTemp);

    // Invoke IParameter.Type. Returns ITypeDesc.

    hr = Invoke(pdispParameter, DISPATCH_PROPERTYGET, &vRet, &excepinfo, &nArgErr,

                OLESTR("Type"), TEXT(""));

    if (FAILED(hr))

        goto error;

   // Get string that describes type and display it.

    pdispTypeDesc = V_DISPATCH(&vRet);

    szTemp[0] = '\0'; // Must initialize to empty string before calling TypeToString.

    hr = TypeToString(pdispTypeDesc, szTemp);

    if (FAILED(hr))

        goto error;

    SetDlgItemText(m_hwndMain, IDC_PARAM_TYPE, szTemp);

    pdispTypeDesc->Release();

    return NOERROR;

error:

    if (pdispTypeDesc) pdispTypeDesc->Release();

    VariantClear(&vRet);

    return hr;

}

/*

 * CBrowseApp::OpenElementHelpFile

 *

 * Purpose:

 *  Opens the helpfile for the element.

 *

 */

void CBrowseApp::OpenElementHelpFile()

{

    BOOL b;

    b = WinHelp(m_hwndMain, m_szHelpFile, HELP_CONTEXT, m_lElemHelpCtx);

    if (!b)

        MessageBox(m_hwndMain, TEXT("Failed to open help file"), TEXT("Error"),

            MB_ICONEXCLAMATION|MB_OK);

}

void CBrowseApp::EmptyList(HWND hwndList)

{

    int nItems, i;

    LPDISPATCH pdispItem;

    nItems = (int)SendMessage(hwndList, LB_GETCOUNT, 0, 0L);

    for (i=0; i<nItems; i++)

    {

        pdispItem = (LPDISPATCH)SendMessage(hwndList, LB_GETITEMDATA, (WPARAM)i, 0L);

        if (pdispItem)

            pdispItem->Release();

    }

    SendMessage(hwndList, LB_RESETCONTENT, 0, 0L);

}

/*

 * CBrowseApp::LoadList

 *

 * Parameters:

 *  pdispItems IDispatch* of collection of items to be put into the list.

 *  nListID    Identifies the list to be filled.

 *

 * Purpose:

 *  Loads the list with the items in the collection.

 *

 */

HRESULT CBrowseApp::LoadList(LPDISPATCH pdispItems, int nListID)

{

    VARIANT vRet, v;

    HRESULT hr;

    EXCEPINFO excepinfo;

    UINT nArgErr;

    LPUNKNOWN punkEnum;

    IEnumVARIANT FAR* penum = NULL;

    LPDISPATCH pdispItem = NULL;

    int nIndex;

    // Get _NewEnum property. Returns enumerator's IUnknown.

    hr = Invoke(pdispItems, DISPATCH_PROPERTYGET, &vRet, &excepinfo, &nArgErr,

                        OLESTR("_NewEnum"), TEXT(""));

    if (FAILED(hr))

        goto error;

    punkEnum = V_UNKNOWN(&vRet);

    hr = punkEnum->QueryInterface(IID_IEnumVARIANT, (LPVOID FAR*)&penum);

    if (FAILED(hr))

        goto error;

    punkEnum->Release();

    VariantInit(&v);

    // Enumerate the Items.

    while (S_OK == penum->Next(1, &v, NULL))

    {

        pdispItem = V_DISPATCH(&v);

        pdispItem->AddRef();

        VariantClear(&v);

        // Get Name of Item.

        hr = Invoke(pdispItem, DISPATCH_PROPERTYGET, &vRet, &excepinfo, &nArgErr,

                    OLESTR("Name"), TEXT(""));

        if (FAILED(hr))

            goto error;

        // Add name to ItemsList.

        nIndex = (int)SendDlgItemMessage(m_hwndMain, nListID, LB_ADDSTRING,

            0, (LPARAM)(LPTSTR)FROM_OLE_STRING(V_BSTR(&vRet)));

        VariantClear(&vRet);

        // Save IDispatch* of Item in the list.

        SendDlgItemMessage(m_hwndMain, nListID, LB_SETITEMDATA,

            nIndex, (LPARAM)pdispItem);

    }

    penum->Release();

    return NOERROR;

error:

    if (penum) penum->Release();

    if (pdispItem) pdispItem->Release();

    return hr;

}

void CBrowseApp::Init(HWND hwndMain)

{

    HFONT hfontDlg;

    LOGFONT lfont;

    int nID;

    m_hwndMain = hwndMain;

    m_hfont = NULL;

#ifdef WIN16

    m_hinst = (HINSTANCE)GetWindowWord(hwndMain, GWW_HINSTANCE);

#else

    m_hinst = (HINSTANCE)GetWindowLong(hwndMain, GWL_HINSTANCE);

#endif

    EnableWindow(GetDlgItem(m_hwndMain, IDC_ELEM_OPEN_HELPFILE), FALSE);

    // Change to the font of the fields to a non-bold font.

    hfontDlg = (HFONT)SendMessage(m_hwndMain, WM_GETFONT, NULL, NULL);

    if (!hfontDlg)

        return;

    GetObject(hfontDlg, sizeof(LOGFONT), (LPVOID)&lfont);

    lfont.lfWeight = FW_NORMAL;

    if (m_hfont = CreateFontIndirect(&lfont))

        for (nID=IDC_TYPELIB_FIRST; nID<=IDC_PARAM_LAST; nID++)

            SendDlgItemMessage(m_hwndMain, nID, WM_SETFONT, (WPARAM)m_hfont, 0L);

}

void CBrowseApp::Cleanup()

{

    EmptyList(GetDlgItem(m_hwndMain, IDC_TYPEINFOSLIST));

    EmptyList(GetDlgItem(m_hwndMain, IDC_ELEMENTSLIST));

    EmptyList(GetDlgItem(m_hwndMain, IDC_PARAMETERSLIST));

    ClearTypeLibStaticFields();

    ClearTypeInfoStaticFields();

    ClearElementStaticFields();

    ClearParamStaticFields();

    if (m_hfont)

        DeleteObject(m_hfont);

}

void CBrowseApp::ClearTypeLibStaticFields()

{

    int nID;

    for (nID=IDC_TYPELIB_FIRST; nID<=IDC_TYPELIB_LAST; nID++)

        SetDlgItemText(m_hwndMain, nID, TEXT(""));

}

void CBrowseApp::ClearTypeInfoStaticFields()

{

    int nID;

    for (nID=IDC_TYPEINFO_FIRST; nID<=IDC_TYPEINFO_LAST; nID++)

        SetDlgItemText(m_hwndMain, nID, TEXT(""));

}

void CBrowseApp::ClearElementStaticFields()

{

    int nID;

    for (nID=IDC_ELEM_FIRST; nID<=IDC_ELEM_LAST; nID++)

        SetDlgItemText(m_hwndMain, nID, TEXT(""));

}

void CBrowseApp::ClearParamStaticFields()

{

    int nID;

    for (nID=IDC_PARAM_FIRST; nID<=IDC_PARAM_LAST; nID++)

        SetDlgItemText(m_hwndMain, nID, TEXT(""));

}

#define CASE_VT(vt)  \

        case vt: \

            lstrcat(pszTypeName, TEXT(#vt)); \

            break;

HRESULT CBrowseApp::TypeToString(LPDISPATCH pdispTypeDesc, LPTSTR pszTypeName)

{

    VARIANT vRet;

    VARTYPE vartype;

    HRESULT hr;

    EXCEPINFO excepinfo;

    UINT nArgErr;

    LPDISPATCH pdispTypeDesc2;

    // Get Type property

    hr = Invoke(pdispTypeDesc, DISPATCH_PROPERTYGET, &vRet, &excepinfo, &nArgErr,

                OLESTR("Type"), TEXT(""));

    if (FAILED(hr))

        goto error;

    vartype = V_I2(&vRet);

    if (vartype & 0x2000)  // If SafeArray

      lstrcat(pszTypeName, TEXT("SAFEARRAY("));

    switch (vartype & ~0x7000)

    {

    CASE_VT(VT_EMPTY)

    CASE_VT(VT_NULL)

    CASE_VT(VT_I2)

    CASE_VT(VT_I4)

    CASE_VT(VT_R4)

    CASE_VT(VT_R8)

    CASE_VT(VT_CY)

    CASE_VT(VT_DATE)

    CASE_VT(VT_BSTR)

    CASE_VT(VT_DISPATCH)

    CASE_VT(VT_ERROR)

    CASE_VT(VT_BOOL)

    CASE_VT(VT_VARIANT)

    CASE_VT(VT_UNKNOWN)

    CASE_VT(VT_I1)

    CASE_VT(VT_UI1)

    CASE_VT(VT_UI2)

    CASE_VT(VT_UI4)

    CASE_VT(VT_I8)

    CASE_VT(VT_UI8)

    CASE_VT(VT_INT)

    CASE_VT(VT_UINT)

    CASE_VT(VT_VOID)

    CASE_VT(VT_HRESULT)

    CASE_VT(VT_SAFEARRAY)

    CASE_VT(VT_CARRAY)

    CASE_VT(VT_LPSTR)

    CASE_VT(VT_LPWSTR)

    CASE_VT(VT_FILETIME)

    CASE_VT(VT_BLOB)

    CASE_VT(VT_STREAM)

    CASE_VT(VT_STORAGE)

    CASE_VT(VT_STREAMED_OBJECT)

    CASE_VT(VT_STORED_OBJECT)

    CASE_VT(VT_BLOB_OBJECT)

    CASE_VT(VT_CF)

    CASE_VT(VT_CLSID)

    case VT_PTR:

         // Get ITypeDesc.PointerDesc property. Returns ITypeDesc.

         hr = Invoke(pdispTypeDesc, DISPATCH_PROPERTYGET, &vRet, &excepinfo, &nArgErr,

                OLESTR("PointerDesc"), TEXT(""));

         if (FAILED(hr))

             goto error;

         pdispTypeDesc2 = V_DISPATCH(&vRet);

         TypeToString(pdispTypeDesc2, pszTypeName);

         lstrcat(pszTypeName, TEXT(" *"));

         pdispTypeDesc2->Release();

         break;

    case VT_USERDEFINED:

         // Get ITypeDesc.UserDefinedDesc property. Returns ITypeInformation

         hr = Invoke(pdispTypeDesc, DISPATCH_PROPERTYGET, &vRet, &excepinfo, &nArgErr,

                OLESTR("UserDefinedDesc"), TEXT(""));

         if (FAILED(hr))

             goto error;

         pdispTypeDesc2 = V_DISPATCH(&vRet);

         // Get ITypeInformation.Name property. Returns BSTR.

         hr = Invoke(pdispTypeDesc2, DISPATCH_PROPERTYGET, &vRet, &excepinfo, &nArgErr,

                OLESTR("Name"), TEXT(""));

         if (FAILED(hr))

             goto error;

         lstrcat(pszTypeName, FROM_OLE_STRING(V_BSTR(&vRet)));

         VariantClear(&vRet);

         pdispTypeDesc2->Release();

         break;

    }

    if (vartype & 0x2000) // If SafeArray

        lstrcat(pszTypeName, TEXT(")"));

    return NOERROR;

error:

    return ERROR;

}

void CBrowseApp::IDLFlagsToString(int n, LPTSTR psz)

{

   psz[0] = '\0';

   if (n & IDLFLAG_FIN)

   {

       lstrcpy(psz, TEXT("IN"));

       if (n & IDLFLAG_FOUT)

           lstrcat(psz, TEXT("|OUT"));

   }

   else if (n & IDLFLAG_FOUT)

       lstrcpy(psz, TEXT("OUT"));

}

#define CASE_INVOKE(invokekind)  \

        case invokekind: \

            lstrcpy(psz, TEXT(#invokekind)); \

            break;

void CBrowseApp::CallConvToString(int n, LPTSTR psz)

{

    CALLCONV c = (CALLCONV)n;

    switch (c)

    {

        CASE_INVOKE(CC_CDECL)

        CASE_INVOKE(CC_PASCAL)

        CASE_INVOKE(CC_MACPASCAL)

        CASE_INVOKE(CC_STDCALL)

        CASE_INVOKE(CC_SYSCALL)

        default:

            lstrcpy(psz, TEXT("Unknown"));

    }

}

#define CASE_FUNC(funckind)  \

        case funckind: \

            lstrcpy(psz, TEXT(#funckind)); \

            break;

void CBrowseApp::FuncKindToString(int n, LPTSTR psz)

{

    FUNCKIND f = (FUNCKIND)n;

    switch (f)

    {

        CASE_FUNC(FUNC_VIRTUAL)

        CASE_FUNC(FUNC_PUREVIRTUAL)

        CASE_FUNC(FUNC_NONVIRTUAL)

        CASE_FUNC(FUNC_STATIC)

        CASE_FUNC(FUNC_DISPATCH)

        default:

            lstrcpy(psz, TEXT("Unknown"));

    }

}

#define CASE_INVOKE(invokekind)  \

        case invokekind: \

            lstrcpy(psz, TEXT(#invokekind)); \

            break;

void CBrowseApp::InvokeKindToString(int n, LPTSTR psz)

{

    INVOKEKIND i = (INVOKEKIND)n;

    switch (i)

    {

        CASE_INVOKE(INVOKE_FUNC)

        CASE_INVOKE(INVOKE_PROPERTYGET)

        CASE_INVOKE(INVOKE_PROPERTYPUT)

        CASE_INVOKE(DISPATCH_PROPERTYPUTREF)

        default:

            lstrcpy(psz, TEXT("Unknown"));

    }

}

void CBrowseApp::VariantToString(VARIANT v, LPTSTR psz)

{

    HRESULT hr;

    VARIANT vTemp;

    VariantInit(&vTemp);

    hr = VariantChangeType(&vTemp, &v, 0, VT_BSTR);

    if (FAILED(hr))

        lstrcpy(psz, TEXT("Cannot Display Value"));

    else lstrcpy(psz, FROM_OLE_STRING(V_BSTR(&vTemp)));

    VariantClear(&vTemp);

}

#ifdef WIN32

#ifndef UNICODE

char* ConvertToAnsi(OLECHAR FAR* szW)

{

  static char achA[STRCONVERT_MAXLEN];

  WideCharToMultiByte(CP_ACP, 0, szW, -1, achA, STRCONVERT_MAXLEN, NULL, NULL);

  return achA;

}

OLECHAR* ConvertToUnicode(char FAR* szA)

{

  static OLECHAR achW[STRCONVERT_MAXLEN];

  MultiByteToWideChar(CP_ACP, 0, szA, -1, achW, STRCONVERT_MAXLEN);

  return achW;

}

#endif

#endif


 INVHELP.CPP   (BROWSE OLE Sample)

/*************************************************************************

**

**    Automation Controller helper functions

**

**    invhelp.cpp

**

**

**     Written by Microsoft Product Support Services, Windows Developer Support

**    (c) Copyright Microsoft Corp. 1994 All Rights Reserved

**

*************************************************************************/

#include <windows.h>

#include <windowsx.h>

#ifdef WIN16

  #include <ole2.h>

  #include <compobj.h>

  #include <dispatch.h>

  #include <variant.h>

  #include <olenls.h>

#endif

#include <stdarg.h>

#ifdef WIN16

  #define LPCTSTR LPCSTR

  #define LPOLESTR LPSTR

#endif

HRESULT CountArgsInFormat(LPCTSTR pszFmt, UINT FAR *pn);

LPCTSTR GetNextVarType(LPCTSTR pszFmt, VARTYPE FAR* pvt);

/*

 * CreateObject

 *

 * Purpose:

 *  Creates an instance of the Automation object and obtains it's IDispatch interface.

 *  Uses Unicode with OLE.

 *

 * Parameters:

 *  pszProgID         ProgID of Automation object

 *  ppdisp             Returns IDispatch of Automation object

 *

 * Return Value:

 *  HRESULT indicating success or failure

 */

HRESULT CreateObject(LPOLESTR pszProgID, IDispatch FAR* FAR* ppdisp)

{

    CLSID clsid;                   // CLSID of automation object

    HRESULT hr;

    LPUNKNOWN punk = NULL;         // IUnknown of automation object

    LPDISPATCH pdisp = NULL;       // IDispatch of automation object

    *ppdisp = NULL;

    // Retrieve CLSID from the progID that the user specified

    hr = CLSIDFromProgID(pszProgID, &clsid);

    if (FAILED(hr))

        goto error;

    // Create an instance of the automation object and ask for the IDispatch interface

    hr = CoCreateInstance(clsid, NULL, CLSCTX_SERVER,

                          IID_IUnknown, (void FAR* FAR*)&punk);

    if (FAILED(hr))

        goto error;

    hr = punk->QueryInterface(IID_IDispatch, (void FAR* FAR*)&pdisp);

    if (FAILED(hr))

        goto error;

    *ppdisp = pdisp;

    punk->Release();

    return NOERROR;

error:

    if (punk) punk->Release();

    if (pdisp) pdisp->Release();

    return hr;

}

/*

 * Invoke

 *

 * Purpose:

 *  Invokes a property accessor function or method of an automation object. Uses Unicode with OLE.

 *

 * Parameters:

 *  pdisp         IDispatch* of automation object.

 *  wFlags        Specfies if property is to be accessed or method to be invoked.

 *                Can hold DISPATCH_PROPERTYGET, DISPATCH_PROPERTYPUT, DISPATCH_METHOD,

 *                DISPATCH_PROPERTYPUTREF or DISPATCH_PROPERTYGET|DISPATCH_METHOD.

 *  pvRet         NULL if caller excepts no result. Otherwise returns result.

 *  pexcepinfo    Returns exception info if DISP_E_EXCEPTION is returned. Can be NULL if

 *                caller is not interested in exception information.

 *  pnArgErr      If return is DISP_E_TYPEMISMATCH, this returns the index (in reverse

 *                order) of argument with incorrect type. Can be NULL if caller is not interested

 *                in this information.

 *  pszName       Name of property or method.

 *  pszFmt        Format string that describes the variable list of parameters that

 *                follows. The format string can contain the follwoing characters.

 *                & = mark the following format character as VT_BYREF

 *                b = VT_BOOL

 *                i = VT_I2

 *                I = VT_I4

 *                r = VT_R2

 *                R = VT_R4

 *                c = VT_CY

 *                s = VT_BSTR (far string pointer can be passed, BSTR will be allocated by this function).

 *                e = VT_ERROR

 *                d = VT_DATE

 *                v = VT_VARIANT. Use this to pass data types that are not described in

 *                                the format string. (For example SafeArrays).

 *                D = VT_DISPATCH

 *                U = VT_UNKNOWN

 *

 *  ...           Arguments of the property or method. Arguments are described by pszFmt.

 *                ****FAR POINTERS MUST BE PASSED FOR POINTER ARGUMENTS in Win16.****

 * Return Value:

 *  HRESULT indicating success or failure

 *

 * Usage examples:

 *

 *  HRESULT hr;

 *  LPDISPATCH pdisp;

 *  BSTR bstr;

 *  short i;

 *  BOOL b;

 *  VARIANT v, v2;

 *

 *1. bstr = SysAllocString(OLESTR(""));

 *   hr = Invoke(pdisp, DISPATCH_METHOD, NULL, NULL, NULL, OLESTR("method1"),

 *        TEXT("bis&b&i&s"), TRUE, 2, (LPOLESTR)OLESTR("param"), (BOOL FAR*)&b, (short FAR*)&i, (BSTR FAR*)&bstr);

 *

 *2. VariantInit(&v);

 *   V_VT(&v) = VT_R8;

 *   V_R8(&v) = 12345.6789;

 *   VariantInit(&v2);

 *   hr = Invoke(pdisp, DISPATCH_METHOD, NULL, NULL, NULL, OLESTR("method2"),

 *         TEXT("v&v"), v, (VARIANT FAR*)&v2);

 */

HRESULT

Invoke(LPDISPATCH pdisp,

    WORD wFlags,

    LPVARIANT pvRet,

    EXCEPINFO FAR* pexcepinfo,

    UINT FAR* pnArgErr,

    LPOLESTR pszName,

    LPCTSTR pszFmt,

    ...)

{

    va_list argList;

    va_start(argList, pszFmt);

    DISPID dispid;

    HRESULT hr;

    VARIANTARG* pvarg = NULL;

    if (pdisp == NULL)

        return ResultFromScode(E_INVALIDARG);

    // Get DISPID of property/method

    hr = pdisp->GetIDsOfNames(IID_NULL, &pszName, 1, LOCALE_USER_DEFAULT, &dispid);

    if(FAILED(hr))

        return hr;

    DISPPARAMS dispparams;

    _fmemset(&dispparams, 0, sizeof dispparams);

    // determine number of arguments

    if (pszFmt != NULL)

        CountArgsInFormat(pszFmt, &dispparams.cArgs);

    // Property puts have a named argument that represents the value that the property is

    // being assigned.

    DISPID dispidNamed = DISPID_PROPERTYPUT;

    if (wFlags & DISPATCH_PROPERTYPUT)

    {

        if (dispparams.cArgs == 0)

            return ResultFromScode(E_INVALIDARG);

        dispparams.cNamedArgs = 1;

        dispparams.rgdispidNamedArgs = &dispidNamed;

    }

    if (dispparams.cArgs != 0)

    {

        // allocate memory for all VARIANTARG parameters

        pvarg = new VARIANTARG[dispparams.cArgs];

        if(pvarg == NULL)

            return ResultFromScode(E_OUTOFMEMORY);

        dispparams.rgvarg = pvarg;

        _fmemset(pvarg, 0, sizeof(VARIANTARG) * dispparams.cArgs);

        // get ready to walk vararg list

        LPCTSTR psz = pszFmt;

        pvarg += dispparams.cArgs - 1;   // params go in opposite order

        while (psz = GetNextVarType(psz, &pvarg->vt))

        {

            if (pvarg < dispparams.rgvarg)

            {

                hr = ResultFromScode(E_INVALIDARG);

                goto cleanup;

            }

            switch (pvarg->vt)

            {

            case VT_I2:

                V_I2(pvarg) = va_arg(argList, short);

                break;

            case VT_I4:

                V_I4(pvarg) = va_arg(argList, long);

                break;

            case VT_R4:

                V_R4(pvarg) = va_arg(argList, float);

                break;

            case VT_DATE:

            case VT_R8:

                V_R8(pvarg) = va_arg(argList, double);

                break;

            case VT_CY:

                V_CY(pvarg) = va_arg(argList, CY);

                break;

            case VT_BSTR:

                V_BSTR(pvarg) = SysAllocString(va_arg(argList, OLECHAR FAR*));

                if (pvarg->bstrVal == NULL)

                {

                    hr = ResultFromScode(E_OUTOFMEMORY);

                    pvarg->vt = VT_EMPTY;

                    goto cleanup;

                }

                break;

            case VT_DISPATCH:

                V_DISPATCH(pvarg) = va_arg(argList, LPDISPATCH);

                break;

            case VT_ERROR:

                V_ERROR(pvarg) = va_arg(argList, SCODE);

                break;

            case VT_BOOL:

                V_BOOL(pvarg) = va_arg(argList, BOOL) ? -1 : 0;

                break;

            case VT_VARIANT:

                *pvarg = va_arg(argList, VARIANTARG);

                break;

            case VT_UNKNOWN:

                V_UNKNOWN(pvarg) = va_arg(argList, LPUNKNOWN);

                break;

            case VT_I2|VT_BYREF:

                V_I2REF(pvarg) = va_arg(argList, short FAR*);

                break;

            case VT_I4|VT_BYREF:

                V_I4REF(pvarg) = va_arg(argList, long FAR*);

                break;

            case VT_R4|VT_BYREF:

                V_R4REF(pvarg) = va_arg(argList, float FAR*);

                break;

            case VT_R8|VT_BYREF:

                V_R8REF(pvarg) = va_arg(argList, double FAR*);

                break;

            case VT_DATE|VT_BYREF:

                V_DATEREF(pvarg) = va_arg(argList, DATE FAR*);

                break;

            case VT_CY|VT_BYREF:

                V_CYREF(pvarg) = va_arg(argList, CY FAR*);

                break;

            case VT_BSTR|VT_BYREF:

                V_BSTRREF(pvarg) = va_arg(argList, BSTR FAR*);

                break;

            case VT_DISPATCH|VT_BYREF:

                V_DISPATCHREF(pvarg) = va_arg(argList, LPDISPATCH FAR*);

                break;

            case VT_ERROR|VT_BYREF:

                V_ERRORREF(pvarg) = va_arg(argList, SCODE FAR*);

                break;

            case VT_BOOL|VT_BYREF:

                {

                    BOOL FAR* pbool = va_arg(argList, BOOL FAR*);

                    *pbool = 0;

                    V_BOOLREF(pvarg) = (VARIANT_BOOL FAR*)pbool;

                }

                break;

            case VT_VARIANT|VT_BYREF:

                V_VARIANTREF(pvarg) = va_arg(argList, VARIANTARG FAR*);

                break;

            case VT_UNKNOWN|VT_BYREF:

                V_UNKNOWNREF(pvarg) = va_arg(argList, LPUNKNOWN FAR*);

                break;

            default:

                {

                    hr = ResultFromScode(E_INVALIDARG);

                    goto cleanup;

                }

                break;

            }

            --pvarg; // get ready to fill next argument

        } //while

    } //if

    // Initialize return variant, in case caller forgot. Caller can pass NULL if return

    // value is not expected.

    if (pvRet)

        VariantInit(pvRet);

    // make the call

    hr = pdisp->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, wFlags,

        &dispparams, pvRet, pexcepinfo, pnArgErr);

cleanup:

    // cleanup any arguments that need cleanup

    if (dispparams.cArgs != 0)

    {

        VARIANTARG FAR* pvarg = dispparams.rgvarg;

        UINT cArgs = dispparams.cArgs;

        while (cArgs--)

        {

            switch (pvarg->vt)

            {

            case VT_BSTR:

                VariantClear(pvarg);

                break;

            }

            ++pvarg;

        }

    }

    delete dispparams.rgvarg;

    va_end(argList);

    return hr;

}

HRESULT CountArgsInFormat(LPCTSTR pszFmt, UINT FAR *pn)

{

    *pn = 0;

    if(pszFmt == NULL)

      return NOERROR;

    while (*pszFmt)

    {

       if (*pszFmt == '&')

           pszFmt++;

       switch(*pszFmt)

       {

           case 'b':

           case 'i':

           case 'I':

           case 'r':

           case 'R':

           case 'c':

           case 's':

           case 'e':

           case 'd':

           case 'v':

           case 'D':

           case 'U':

               ++*pn;

               pszFmt++;

               break;

           case '\0':

           default:

               return ResultFromScode(E_INVALIDARG);

        }

    }

    return NOERROR;

}

LPCTSTR GetNextVarType(LPCTSTR pszFmt, VARTYPE FAR* pvt)

{

    *pvt = 0;

    if (*pszFmt == '&')

    {

         *pvt = VT_BYREF;

         pszFmt++;

         if (!*pszFmt)

             return NULL;

    }

    switch(*pszFmt)

    {

        case 'b':

            *pvt |= VT_BOOL;

            break;

        case 'i':

            *pvt |= VT_I2;

            break;

        case 'I':

            *pvt |= VT_I4;

            break;

        case 'r':

            *pvt |= VT_R4;

            break;

        case 'R':

            *pvt |= VT_R8;

            break;

        case 'c':

            *pvt |= VT_CY;

            break;

        case 's':

            *pvt |= VT_BSTR;

            break;

        case 'e':

            *pvt |= VT_ERROR;

            break;

        case 'd':

            *pvt |= VT_DATE;

            break;

        case 'v':

            *pvt |= VT_VARIANT;

            break;

        case 'U':

            *pvt |= VT_UNKNOWN;

            break;

        case 'D':

            *pvt |= VT_DISPATCH;

            break;

        case '\0':

             return NULL;     // End of Format string

        default:

            return NULL;

    }

    return ++pszFmt;

}


 BROWSEH

SAMPLE: BROWSEH: InProc OLE Automation Server that browses a type library

BROWSEH is a inproc OLE Automation Server that browses a type library. It shows how to create an inproc Automation server and how to use the ITypeLib and ITypeInfo interfaces to browse a type library.

BROWSEH exposes a number of automation objects that correspond to components of a type library. This allows an automation controller like BROWSE (shipped with the OLE 2.02 SDK) to access the properties and methods of these objects to browse the type library instead of directly using ITypeLib and ITypeInfo. So BROWSEH is a type library browse helper.

BROWSEH does not support vtable binding. Controllers must use IDispatch to control this server.

ProgID: BrowseHelper.Browser

See main.cpp for code to create an inproc automation server. See other source files for code that uses ITypeLib and ITypeInfo to browse various components of a type library.

To compile: -----------

Requires OLE 2.02 or later. Use the external makefile called makefile to compile.  In Win16, run the WXSRVER.EXE from \OLE2\BIN before running the makefile. The makefile invokes mktyplib.exe that reads mydisp.odl and browseh.odl and creates the  type libraries, mydisp.tlb and browseh.tlb. It then compliles the source files.

To run: -------

Change browseh.reg to provide the full path of browseh.dll and browseh.tlb.  Register browseh.reg in the registration database by double-clicking it. Run the Automation controller BROWSE that uses BROWSEH to browse a type library.

Files: ------ MYDISP.ODL  Contains the description of a base class that implements IDispatch. All              automation objects in this server derive from this class. This the implementation             of IDispatch in the base class to be inherited in the derived classes.
BROWSEH.ODL Object description language that describes the objects that BROWSEH exposes. TLB.H       Header file generated by mktyplib.exe MAKEFILE    Makefile for project. MAIN.CPP    Code to create an inproc server.

Other files implement the BROWSEH automation server. For example coclass.cpp demonstates how to use ITypeInfo and ITypeLib to browse a coclass in a type library. ================================================================================


 MAKEFILE   (BROWSEH OLE Sample)

####

#makefile - makefile for browseh.dll

#

#       Copyright (C) 1994, Microsoft Corporation

#

#Purpose:

#  Builds the Inproc OLE 2.0 Automation object, browseh.dll.

#

#

#  Usage: NMAKE                 ; build with defaults

#     or: NMAKE option          ; build with the given option(s)

#     or: NMAKE clean           ; erase all compiled files

#

#     option: dev = [win16 | win32]    ; dev=win32 is the default

#             DEBUG=[0 | 1]            ; DEBUG=1 is the default

#             HOST=[DOS | NT | WIN95]  ; HOST=DOS (for win16)

#                                      ; HOST=NT (for win32 on NT)

#                                      ; HOST=WIN95 (for win32 on Win95)

#

#Notes:

#  This makefile assumes that the PATH, INCLUDE and LIB environment

#  variables are setup properly.

#

##############################################################################

##########################################################################

#

# Default Settings

#

CPU = i386

!if "$(dev)" == ""

dev = win32

HOST = NT

!endif

!if !("$(dev)" == "win16" || "$(dev)" == "win32")

!error Invalid dev option, choose from [win16 | win32]

!endif

!if "$(dev)" == "win16"

TARGET  = WIN16

!if "$(HOST)" == ""

HOST  = DOS

!endif

!endif

!if "$(dev)" == "win32"

TARGET  = WIN32

!if "$(HOST)" == ""

HOST  = NT

!endif

!endif

!ifdef NODEBUG

DEBUG = 0

!endif

!if "$(DEBUG)" == "0"

NODEBUG = 1

!endif

!if "$(DEBUG)" == ""

DEBUG = 1

!endif

##########################################################################

#

# WIN16 Settings

#

!if "$(TARGET)" == "WIN16"

CC   = cl

LINK = link

!if "$(HOST)" == "DOS"

WX   = wx /w

!else

WX   =

!endif

RCFLAGS = -dWIN16

CFLAGS = -c -W3 -AM -GD -DWIN16

LINKFLAGS = /NOD /BATCH /ONERROR:NOEXE

LIBS = libw.lib mdllcew.lib

!if "$(DEBUG)" == "1"

CFLAGS = $(CFLAGS) -Od -Zi -D_DEBUG $(CL)

LINKFLAGS = $(LINKFLAGS) /COD

!else

CFLAGS = $(CFLAGS) -Ox $(CL)

LINKFLAGS = $(LINKFLAGS) /FAR /PACKC

!endif

!endif

##########################################################################

#

# WIN32 Settings

#

!if "$(TARGET)" == "WIN32"

WX =

!include <ntwin32.mak>

CC = $(cc)

CFLAGS = $(cflags) $(cvarsmt) -DINC_OLE2 $(cdebug)

!if "$(HOST)" == "NT"

CFLAGS = $(CFLAGS) -DUNICODE

!endif

!ifndef NODEBUG

CFLAGS = $(CFLAGS) -D_DEBUG

!endif

LINK = $(link)

LINKFLAGS = $(linkdebug) $(guilflags) -dll -entry:_DllMainCRTStartup$(DLLENTRY)\

      -export:DllGetClassObject -export:DllCanUnloadNow

RCFLAGS = -DWIN32

!endif

##########################################################################

#

# Build rules

#

.cpp.obj:

    @echo Compiling $<...

    $(CC) $<

.c.obj:

    @echo Compiling $<...

    $(CC) $<

##########################################################################

#

# Application Settings

#

APPS = browseh

!if "$(TARGET)" == "WIN16"

LIBS = $(LIBS) ole2.lib compobj.lib ole2disp.lib typelib.lib

!endif

!if "$(TARGET)" == "WIN32"

LIBS = $(ole2libsmt)

!endif

OBJS = alias.obj main.obj mydisp.obj browseh.obj browsecf.obj collect.obj \

       enumvar.obj typelib.obj typeinfo.obj intface.obj dispface.obj module.obj \

       coclass.obj function.obj property.obj param.obj enum.obj constant.obj \

       type.obj union.obj struct.obj

##########################################################################

#

# Default Goal

#

goal : setflags $(APPS).dll

setflags :

    set CL=$(CFLAGS)

##########################################################################

#

# Clean (erase) generated files

#

clean :

    if exist *.obj       del *.obj

    if exist $(APPS).dll del $(APPS).dll

    if exist $(APPS).tlb del $(APPS).tlb

    if exist $(APPS).map del $(APPS).map

    if exist $(APPS).res del $(APPS).res

    if exist tlb.h       del tlb.h

    if exist *.log       del *.log

    if exist *.pdb       del *.pdb

##########################################################################

#

# Application Build (WIN16 Specific)

#

!if "$(TARGET)" == "WIN16"

$(APPS).dll : $(OBJS) $(APPS).def $(APPS).res

    link @<<

$(LINKFLAGS)+

$(OBJS),

$@,,

$(LIBS),

$(APPS).def

<<

    rc -k -t $(APPS).res $@

!endif

##########################################################################

#

# Application Build (WIN32 Specific)

#

!if "$(TARGET)" == "WIN32"

$(APPS).dll : $(OBJS) $(APPS).def $(APPS).res

      $(LINK) @<<

        $(LINKFLAGS)

        -out:$@

        -map:$*.map

        $(OBJS)

        $(APPS).res

        $(LIBS)

<<

!endif

##########################################################################

#

# Application Build (Common)

#

$(APPS).res : $(APPS).rc

    rc $(RCFLAGS) -r -fo$@ $?

##########################################################################

#

# Dependencies

#

mydisp.tlb :: mydisp.odl

     if exist mydisp.tlb  del mydisp.tlb

     $(WX) mktyplib /D$(TARGET) /o mydisp.log /tlb mydisp.tlb mydisp.odl

     type mydisp.log

tlb.h : browseh.odl mydisp.tlb

     if exist tlb.h  del tlb.h

     if exist browseh.tlb  del browseh.tlb

     $(WX) mktyplib /D$(TARGET) /h tlb.h /o browseh.log /tlb browseh.tlb browseh.odl

     type browseh.log

main.obj : main.cpp browseh.h mydisp.h tlb.h

     $(CC) main.cpp

mydisp.obj : mydisp.cpp browseh.h mydisp.h tlb.h

     $(CC) mydisp.cpp

browseh.obj : browseh.cpp browseh.h mydisp.h tlb.h

     $(CC) browseh.cpp

browsecf.obj : browsecf.cpp browseh.h mydisp.h tlb.h

     $(CC) browsecf.cpp

typelib.obj : typelib.cpp browseh.h mydisp.h tlb.h

     $(CC) typelib.cpp

typeinfo.obj : typeinfo.cpp browseh.h mydisp.h tlb.h

     $(CC) typeinfo.cpp

intface.obj : intface.cpp browseh.h mydisp.h tlb.h

     $(CC) intface.cpp

dispface.obj : dispface.cpp browseh.h mydisp.h tlb.h

     $(CC) dispface.cpp

module.obj : module.cpp browseh.h mydisp.h tlb.h

     $(CC) module.cpp

coclass.obj : coclass.cpp browseh.h mydisp.h tlb.h

     $(CC) coclass.cpp

function.obj : function.cpp browseh.h mydisp.h tlb.h

     $(CC) function.cpp

property.obj : property.cpp browseh.h mydisp.h tlb.h

     $(CC) property.cpp

param.obj : param.cpp browseh.h mydisp.h tlb.h

     $(CC) param.cpp

collect.obj : collect.cpp browseh.h mydisp.h tlb.h

     $(CC) collect.cpp

enumvar.obj : enumvar.cpp browseh.h mydisp.h tlb.h

     $(CC) enumvar.cpp

enum.obj : enum.cpp browseh.h mydisp.h tlb.h

     $(CC) enum.cpp

constant.obj : constant.cpp browseh.h mydisp.h tlb.h

     $(CC) constant.cpp

alias.obj : alias.cpp browseh.h mydisp.h tlb.h

     $(CC) alias.cpp

struct.obj : struct.cpp browseh.h mydisp.h tlb.h

     $(CC) struct.cpp

union.obj : union.cpp browseh.h mydisp.h tlb.h

     $(CC) union.cpp

type.obj : type.cpp browseh.h mydisp.h tlb.h

     $(CC) type.cpp


 BROWSEH.H   (BROWSEH OLE Sample)

#ifdef WIN32

#ifdef UNICODE

    #define FROM_OLE_STRING(str) str

    #define TO_OLE_STRING(str) str

#else

    #define FROM_OLE_STRING(str) ConvertToAnsi(str)

    char FAR* ConvertToAnsi(OLECHAR FAR* szW);

    #define TO_OLE_STRING(str) ConvertToUnicode(str)

    OLECHAR FAR* ConvertToUnicode(char FAR* szA);

    // Maximum length of string that can be converted between Ansi & Unicode

    #define STRCONVERT_MAXLEN 300

#endif

#else  // WIN16

  #define TCHAR char

  #define TEXT(sz) sz

  #define FROM_OLE_STRING(str) str

  #define TO_OLE_STRING(str) str

  #define LPTSTR LPSTR

#endif

#include "mydisp.h"

#include "tlb.h"

// MAX len of string table entries

#define STR_LEN   200

// String table constants

#define IDS_SERVERNAME             1

// These exception strings IDs that is will used in EXCEPINFO.wCode

#define IDS_Unexpected             1001

#define IDS_OutOfMemory            1002

#define IDS_InvalidIndex           1003

#define IDS_CollectionFull         1004

#define IDS_CannotFindTypeLibrary  1005

#define IDS_TypeLibraryCreationFailed 1006

#define IDS_WrongType               1007

#define IDS_InvalidProgid           1008

#define IDS_CouldNotCreateObject    1009

#define IDS_ObjectDoesNotSupportAutomation   1010

#define IDS_ObjectDoesNotProvideTypeInfo  1011

// Function prototypes

BOOL InitDLL (HINSTANCE hInstance);

extern "C" STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID FAR *ppv);

extern "C" STDAPI DllCanUnloadNow(void);

//Forward declarations.

class CArrayBound;

class FAR CBrowseHelperCF : public IClassFactory

{

public:

    // IUnknown methods

    STDMETHOD(QueryInterface)(REFIID riid, LPVOID FAR* ppvObj);

    STDMETHOD_(ULONG, AddRef)(void);

    STDMETHOD_(ULONG, Release)(void);

    // IClassFactory methods

    STDMETHOD(CreateInstance)(IUnknown FAR* punkOuter, REFIID riid, void FAR* FAR* ppv);

    STDMETHOD(LockServer)(BOOL fLock);

    CBrowseHelperCF();

private:

    ULONG m_cRef;                   // Reference count

};

class FAR CBrowseHelper : public IBrowseHelper

{

public:

    // IBrowseHelper automation exposed methods

    STDMETHOD_(ITypeLibrary FAR*, BrowseTypeLibrary)(BSTR bstrPath);

    STDMETHOD_(REFCLSID, GetInterfaceID)();

    static HRESULT Create(CBrowseHelper FAR* FAR* ppBrowseHelper); // Creates and intializes Applicaton object

    CBrowseHelper();

    ~CBrowseHelper();

};

class FAR CTypeLibrary : public ITypeLibrary

{

public:

    // ITypeLibrary automation exposed properties & methods

    STDMETHOD_(BSTR, get_Name)();

    STDMETHOD_(BSTR, get_Documentation)();

    STDMETHOD_(long, get_HelpContext)();

    STDMETHOD_(BSTR, get_HelpFile)();

    STDMETHOD_(long, get_LocaleID)();

    STDMETHOD_(int, get_MajorVersion)();

    STDMETHOD_(int, get_MinorVersion)();

    STDMETHOD_(ICollection FAR*, get_TypeInfos)();

    STDMETHOD_(REFCLSID, GetInterfaceID)();

    static HRESULT Create(LPTYPELIB ptlib, CTypeLibrary FAR* FAR* ppTypeLibrary); // Creates and intializes TypeLibrary object

    CTypeLibrary();

    ~CTypeLibrary();

private:

    BSTR m_bstrName;               // Type Library name

    BSTR m_bstrDocumentation;      // Documentation

    unsigned long m_ulHelpContext; // HelpContext

    BSTR m_bstrHelpFile;           // HelpFile

    GUID m_guid;                   // GUID

    LCID m_lcid;                   // Locale ID

    unsigned short m_wMajorVer;    // Major version

    unsigned short m_wMinorVer;    // Minor version

    LPTYPELIB m_ptlib;             // ITypeLib* of type library.

    LPDISPATCH m_pdispTypeInfos;   // Collection of typeinfos contained by this typelib

};

// CTypeInfo is the base class for all the TypeInfos (CInterface, CDispinterface,

// CModule, CCoClass, CEnum, CStruct, CUnion, CAlias)

class FAR CTypeInfo : public ITypeInformation

{

public:

    // ITypeInfo automation exposed properties & methods

    STDMETHOD_(BSTR, get_Name)();

    STDMETHOD_(BSTR, get_Documentation)();

    STDMETHOD_(long, get_HelpContext)();

    STDMETHOD_(BSTR, get_HelpFile)();

    STDMETHOD_(TYPEKIND, get_TypeInfoKind)();

    STDMETHOD_(REFCLSID, GetInterfaceID)();

    STDMETHOD(_InitTypeInfo)(LPTYPEINFO ptinfo); // Called by derived class to intialize this base class

    static HRESULT Create(LPTYPEINFO ptinfo, CTypeInfo FAR* FAR* ppTypeInfo); // Creates and intializes TypeInfo object

    CTypeInfo();

    ~CTypeInfo();

private:

    BSTR m_bstrName;               // TypeInfo name

    BSTR m_bstrDocumentation;      // Documentation

    unsigned long m_ulHelpContext; // Help context

    BSTR m_bstrHelpFile;           // Help file

    TYPEKIND m_typekind;           // Type of TypeInfo. See TYPEKIND enumeration.

    GUID m_guid;                   // GUID

};

class FAR CInterface : public CTypeInfo

{

public:

    // IInterface automation exposed properties & methods

    STDMETHOD_(ICollection FAR*, get_Functions)();

    STDMETHOD_(REFCLSID, GetInterfaceID)();

    static HRESULT Create(LPTYPEINFO ptinfo, CInterface FAR* FAR* ppInterface); // Creates and intializes Interface object

    CInterface();

    ~CInterface();

private:

    LPTYPEINFO m_ptinfo;             // ITypeInfo* of interface typeinfo.

    LPDISPATCH m_pdispFunctions;     // Collection of functions in interface.

};

class FAR CDispinterface : public CTypeInfo

{

public:

    // IDispinterface automation exposed properties & methods

    STDMETHOD_(ICollection FAR*, get_Properties)();

    STDMETHOD_(ICollection FAR*, get_Methods)();

    STDMETHOD_(REFCLSID, GetInterfaceID)();

    static HRESULT Create(LPTYPEINFO ptinfo, CDispinterface FAR* FAR* ppDispinterface); // Creates and intializes Dispinterface object

    CDispinterface();

    ~CDispinterface();

private:

    LPTYPEINFO m_ptinfo;              // ITypeInfo* of dispinterface typeinfo.

    LPDISPATCH m_pdispProperties;     // Collection of properties in dispinterface

    LPDISPATCH m_pdispMethods;        // Collection of methods in dispinterface

};

class FAR CModule : public CTypeInfo

{

public:

    // IModule automation exposed properties & methods

    STDMETHOD_(ICollection FAR*, get_Functions)();

    STDMETHOD_(REFCLSID, GetInterfaceID)();

    static HRESULT Create(LPTYPEINFO ptinfo, CModule FAR* FAR* ppInterface); // Creates and intializes Module object

    CModule();

    ~CModule();

private:

    LPTYPEINFO m_ptinfo;              // ITypeInfo* of module typeinfo.

    LPDISPATCH m_pdispFunctions;      // Collection of functions in module

};

class FAR CCoClass : public CTypeInfo

{

public:

    // ICoClass automation exposed properties & methods

    STDMETHOD_(ICollection FAR*, get_Interfaces)();

    STDMETHOD_(REFCLSID, GetInterfaceID)();

    static HRESULT Create(LPTYPEINFO ptinfo, CCoClass FAR* FAR* ppCoClass); // Creates and intializes CoClass object

    CCoClass();

    ~CCoClass();

private:

    LPTYPEINFO m_ptinfo;              // ITypeInfo* of coclass typeinfo.

    LPDISPATCH m_pdispInterfaces;     // Collection of interfaces/dispinterfaces in coclass

};

class FAR CEnum : public CTypeInfo

{

public:

    // IEnum automation exposed properties & methods

    STDMETHOD_(ICollection FAR*, get_Elements)();

    STDMETHOD_(REFCLSID, GetInterfaceID)();

    static HRESULT Create(LPTYPEINFO ptinfo, CEnum FAR* FAR* ppEnum); // Creates and intializes Enum object

    CEnum();

    ~CEnum();

private:

    LPTYPEINFO m_ptinfo;             // ITypeInfo* of enum typeinfo.

    LPDISPATCH m_pdispElements;      // Collection of elements in enum.

};

class FAR CStruct : public CTypeInfo

{

public:

     // IStruct automation exposed properties & methods

    STDMETHOD_(ICollection FAR*, get_Members)();

    STDMETHOD_(REFCLSID, GetInterfaceID)();

    static HRESULT Create(LPTYPEINFO ptinfo, CStruct FAR* FAR* ppStruct); // Creates and intializes Struct object

    CStruct();

    ~CStruct();

private:

    LPTYPEINFO m_ptinfo;            // ITypeInfo* of struct typeinfo.

    LPDISPATCH m_pdispMembers;      // Collection of members in struct.

};

class FAR CUnion : public CTypeInfo

{

public:

    // IUnion automation exposed properties & methods

    STDMETHOD_(ICollection FAR*, get_Members)();

    STDMETHOD_(REFCLSID, GetInterfaceID)();

    static HRESULT Create(LPTYPEINFO ptinfo, CUnion FAR* FAR* ppUnion); // Creates and intializes Struct object

    CUnion();

    ~CUnion();

private:

    LPTYPEINFO m_ptinfo;            // ITypeInfo* of union typeinfo.

    LPDISPATCH m_pdispMembers;      // Collection of members in union.

};

class FAR CAlias : public CTypeInfo

{

public:

    // IAlias automation exposed properties & methods

    STDMETHOD_(ITypeDesc FAR*, get_BaseType)();

    STDMETHOD_(REFCLSID, GetInterfaceID)();

    static HRESULT Create(LPTYPEINFO ptinfo, CAlias FAR* FAR* ppAlias); // Creates and intializes Alias object

    CAlias();

    ~CAlias();

private:

    LPTYPEINFO m_ptinfo;             // ITypeInfo* of alias typeinfo.

    LPDISPATCH m_pdispTypeDescBase;  // IDispatch of ITypeDesc which describes the base type of this alias.

};

// CFunction represents all functions (including methods).

class FAR CFunction : public IFunction

{

public:

    // IFunction automation exposed properties & methods

    STDMETHOD_(BSTR, get_Name)();

    STDMETHOD_(BSTR, get_Documentation)();

    STDMETHOD_(long, get_HelpContext)();

    STDMETHOD_(BSTR, get_HelpFile)();

    STDMETHOD_(ITypeDesc FAR*, get_ReturnType)();

    STDMETHOD_(ICollection FAR*, get_Parameters)();

    STDMETHOD_(MEMBERID, get_Memberid)();

    STDMETHOD_(CALLCONV, get_CallConvention)();

    STDMETHOD_(FUNCKIND, get_FuncKind)();

    STDMETHOD_(INVOKEKIND, get_InvocationKind)();

    STDMETHOD_(OBJTYPE, get_Kind)();

    STDMETHOD_(REFCLSID, GetInterfaceID)();

    static HRESULT Create(LPTYPEINFO ptinfo, unsigned short nIndex, CFunction FAR* FAR* ppFunction); // Creates and intializes Function object

    CFunction();

    ~CFunction();

private:

    BSTR m_bstrName;                     // Function name.

    BSTR m_bstrDocumentation;            // Documentation.

    unsigned long m_ulHelpContext;       // Help context.

    BSTR m_bstrHelpFile;                 // Help file.

    LPDISPATCH m_pdispTypeDesc;          // IDispatch of ITypeDesc that described return type.

    LPDISPATCH m_pdispParameters;        // Collection of parameters function.

    LPFUNCDESC m_pfuncdesc;              // FUNCDESC of function.

    LPTYPEINFO m_ptinfoFunction;         // TypeInfo of which this function is an element.

};

// CProperty represents dispinterface properties and structure & union members.

class FAR CProperty : public IProperty

{

public:

    // IProperty automation exposed properties & methods

    STDMETHOD_(BSTR, get_Name)();

    STDMETHOD_(BSTR, get_Documentation)();

    STDMETHOD_(long, get_HelpContext)();

    STDMETHOD_(BSTR, get_HelpFile)();

    STDMETHOD_(ITypeDesc FAR*, get_Type)();

    STDMETHOD_(MEMBERID, get_Memberid)();

    STDMETHOD_(OBJTYPE, get_Kind)();

    STDMETHOD_(REFCLSID, GetInterfaceID)();

    static HRESULT Create(LPTYPEINFO ptinfo, LPVARDESC pvardesc, CProperty FAR* FAR* ppProperty); // Creates and intializes Property object

    CProperty();

    ~CProperty();

private:

    BSTR m_bstrName;                     // Property name.

    BSTR m_bstrDocumentation;            // Documentation.

    unsigned long m_ulHelpContext;       // Help Context.

    BSTR m_bstrHelpFile;                 // Helpfile.

    MEMBERID m_memid;                    // MEMBERID of property.

    LPDISPATCH m_pdispTypeDesc;          // ITypeDesc that describes type of property.

};

class FAR CConstant : public IConstant

{

public:

    // IConstant automation exposed properties & methods

    STDMETHOD_(BSTR, get_Name)();

    STDMETHOD_(BSTR, get_Documentation)();

    STDMETHOD_(long, get_HelpContext)();

    STDMETHOD_(BSTR, get_HelpFile)();

    STDMETHOD_(ITypeDesc FAR*, get_Type)();

    STDMETHOD_(VARIANT, get_Value)();

    STDMETHOD_(MEMBERID, get_Memberid)();

    STDMETHOD_(OBJTYPE, get_Kind)();

    STDMETHOD_(REFCLSID, GetInterfaceID)();

    static HRESULT Create(LPTYPEINFO ptinfo, LPVARDESC pvardesc, CConstant FAR* FAR* ppConstant); // Creates and intializes Constant object

    CConstant();

    ~CConstant();

private:

    BSTR m_bstrName;                       // Constant name

    BSTR m_bstrDocumentation;              // Documentation

    unsigned long m_ulHelpContext;         // Help context

    BSTR m_bstrHelpFile;                   // Helpfile

    LPDISPATCH m_pdispTypeDesc;            // ITypeDesc that describes type of constant.

    MEMBERID m_memid;                      // MEMBERID.

    VARIANT m_vValue;                      // Constant value.

};

class FAR CParameter : public IParameter

{

public:

    // IParameter automation exposed properties & methods

    STDMETHOD_(BSTR, get_Name)();

    STDMETHOD_(ITypeDesc FAR*, get_Type)();

    STDMETHOD_(int, get_IDLFlags)();

    STDMETHOD_(OBJTYPE, get_Kind)();

    STDMETHOD_(REFCLSID, GetInterfaceID)();

    static HRESULT Create(LPTYPEINFO ptinfo, BSTR bstrName, TYPEDESC FAR* ptypedesc,

         IDLDESC FAR* pidldesc, CParameter FAR* FAR* ppParameter);  // Creates and intializes Parameter object

    CParameter();

    ~CParameter();

private:

    BSTR m_bstrName;                      // Parameter name.

    unsigned short m_wIDLFlags;           // specifies in/out/in-out/none

    LPDISPATCH m_pdispTypeDesc;           // ITypeDesc* that describes type of parameter.

};

// Describes a type

class FAR CTypeDesc : public ITypeDesc

{

public:

    // ITypeDesc automation exposed properties & methods

    STDMETHOD_(short, get_Type)();

    STDMETHOD_(ITypeInformation FAR*, get_UserDefinedDesc)();

    STDMETHOD_(IArrayDesc FAR*, get_ArrayDesc)();

    STDMETHOD_(ITypeDesc FAR*, get_PointerDesc)();

    STDMETHOD_(REFCLSID, GetInterfaceID)();

    static HRESULT Create(LPTYPEINFO ptinfo, TYPEDESC FAR* ptypedesc, CTypeDesc FAR* FAR* ppTypeDesc); // Creates and intializes TypeDesc object

    CTypeDesc();

    ~CTypeDesc();

private:

    VARTYPE m_vartype;                  // Type

    LPDISPATCH m_pdispUserDefinedDesc;  // If m_vartype==VT_USERDEFINED, contains ITypeInformation* of user-defined type.,

    LPDISPATCH m_pdispArrayDesc;        // if m_vartype==VT_CARRAY, contains IArrayDesc*

    LPDISPATCH m_pdispPointerDesc;      // if m_vartype==VT_PTR contains ITypeDesc* of type pointed to.

};

// Describes C-Style array

class FAR CArrayDesc : public IArrayDesc

{

public:

    // IArrayDesc automation exposed properties & methods

    STDMETHOD_(ITypeDesc FAR*, get_ElementType)();

    STDMETHOD_(ICollection FAR*, get_ArrayBounds)();

    STDMETHOD_(REFCLSID, GetInterfaceID)();

    static HRESULT Create(LPTYPEINFO ptinfo, ARRAYDESC FAR* parraydesc, CArrayDesc FAR* FAR* ppArrayDesc); // Creates and intializes ArrayDesc object

    CArrayDesc();

    ~CArrayDesc();

private:

    LPDISPATCH m_pdispTypeDescElement;     // ITypeDesc that descibed type of array element.

    LPDISPATCH m_pdispArrayBounds;         // IArrayBound that describes array bounds.

};

class FAR CArrayBound : public IArrayBound

{

public:

    // IArrayBound automation exposed properties & methods

    STDMETHOD_(long, get_ElementsCount)();

    STDMETHOD_(long, get_LowerBound)();

    STDMETHOD_(REFCLSID, GetInterfaceID)();

    static HRESULT Create(unsigned long cElements, long lLBound, CArrayBound FAR* FAR* ppArrayBound); // Creates and intializes ArrayBound object

private:

    unsigned long m_cElements;             // Count of elements in array.

    long m_lLBound;                        // Lower bound of array.

};

// Generic collection class that holds all collections.

class FAR CCollection : public ICollection

{

public:

    // ICollection automation exposed properties & methods

    STDMETHOD_(long, get_Count)();

    STDMETHOD_(LPDISPATCH, get_Item)(long lIndex);

    STDMETHOD_(LPUNKNOWN, get__NewEnum)();

    // CCollection methods

    STDMETHOD_(void, Add)(LPDISPATCH pdispItem);

    STDMETHOD_(REFCLSID, GetInterfaceID)();

    static HRESULT Create(ULONG lMaxSize, long lLBound, CCollection FAR* FAR* ppCollection); // Creates and intializes Collection object

    CCollection();

    ~CCollection();

private:

    SAFEARRAY FAR *m_psa;          // Safe array that holds Collection collection items.

    ULONG m_cElements;             // Number of items in Collection collection.

    ULONG m_cMax;                  // Maximum number of items Collection collection can hold.

    long m_lLBound;                // Lower bound of index of Collection collection.

};

class FAR CEnumVariant : public IEnumVARIANT

{

public:

    // IUnknown methods

    STDMETHOD(QueryInterface)(REFIID riid, LPVOID FAR* ppvObj);

    STDMETHOD_(ULONG, AddRef)();

    STDMETHOD_(ULONG, Release)();

    // IEnumVARIANT methods

    STDMETHOD(Next)(ULONG cElements, VARIANT FAR* pvar, ULONG FAR* pcElementFetched);

    STDMETHOD(Skip)(ULONG cElements);

    STDMETHOD(Reset)();

    STDMETHOD(Clone)(IEnumVARIANT FAR* FAR* ppenum);

    static HRESULT Create(SAFEARRAY FAR*, ULONG, CEnumVariant FAR* FAR*); // Creates and intializes Enumerator

    CEnumVariant();

    ~CEnumVariant();

private:

    ULONG m_cRef;           // Reference count

    ULONG m_cElements;      // Number of elements in enumerator.

    long m_lLBound;         // Lower bound of index.

    long m_lCurrent;        // Current index.

    SAFEARRAY FAR* m_psa;   // Safe array that holds elements.

};


 MYDISP.H   (BROWSEH OLE Sample)

class FAR CMyDispatch : public IDispatch

{

public:

    /* IUnknown methods */

    STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID FAR* ppvObj);

    STDMETHOD_(ULONG, AddRef)(THIS);

    STDMETHOD_(ULONG, Release)(THIS);

    /* IDispatch methods */

    STDMETHOD(GetTypeInfoCount)(THIS_ UINT FAR* pctinfo);

    STDMETHOD(GetTypeInfo)(

      THIS_

      UINT itinfo,

      LCID lcid,

      ITypeInfo FAR* FAR* pptinfo);

    STDMETHOD(GetIDsOfNames)(

      THIS_

      REFIID riid,

      OLECHAR FAR* FAR* rgszNames,

      UINT cNames,

      LCID lcid,

      DISPID FAR* rgdispid);

    STDMETHOD(Invoke)(

      THIS_

      DISPID dispidMember,

      REFIID riid,

      LCID lcid,

      WORD wFlags,

      DISPPARAMS FAR* pdispparams,

      VARIANT FAR* pvarResult,

      EXCEPINFO FAR* pexcepinfo,

      UINT FAR* puArgErr);

      CMyDispatch();

      virtual ~CMyDispatch();

    /* CMyDispatch methods */

    STDMETHOD(LoadTypeInfo)(REFCLSID clsid);

    STDMETHOD_(void, RaiseException)(int nID);

    STDMETHOD_(REFCLSID, GetInterfaceID)() PURE;

private:

    LPTYPEINFO m_ptinfo;         // Type information of interface.

    ULONG m_cRef;                // Reference count.

    EXCEPINFO m_excepinfo;       // Information to raise an exception on error.

    BOOL m_bRaiseException;      // Properties and methods use this to signal an exception to be raised.

#ifdef _DEBUG

public:

    TCHAR m_szClassName[100];

#endif

};


 TLB.H   (BROWSEH OLE Sample)

/* This header file machine-generated by mktyplib.exe */

/* Interface to type library: BrowseHelper */

#ifndef _BrowseHelper_H_

#define _BrowseHelper_H_

DEFINE_GUID(LIBID_BrowseHelper,0x19FEEEC0,0x4104,0x101B,0xB8,0x26,0x00,0xDD,0x01,0x10,0x3D,0xE1);

interface IArrayDesc;

typedef enum {

    TYPE_FUNCTION = 0,

    TYPE_PROPERTY = 1,

    TYPE_CONSTANT = 2,

    TYPE_PARAMETER = 3

} OBJTYPE;

DEFINE_GUID(IID_ICollection,0x19FEEECC,0x4104,0x101B,0xB8,0x26,0x00,0xDD,0x01,0x10,0x3D,0xE1);

/* Definition of interface: ICollection */

DECLARE_INTERFACE_(ICollection, CMyDispatch)

{

#ifndef NO_BASEINTERFACE_FUNCS

    /* CMyDispatch methods */

/* You must describe methods for this interface here */

#endif

    /* ICollection methods */

    STDMETHOD_(long, get_Count)(THIS) PURE;

    STDMETHOD_(IDispatch *, get_Item)(THIS_ long Index) PURE;

    STDMETHOD_(IUnknown *, get__NewEnum)(THIS) PURE;

};

DEFINE_GUID(IID_ITypeLibrary,0x19FEEEC3,0x4104,0x101B,0xB8,0x26,0x00,0xDD,0x01,0x10,0x3D,0xE1);

/* Definition of interface: ITypeLibrary */

DECLARE_INTERFACE_(ITypeLibrary, CMyDispatch)

{

#ifndef NO_BASEINTERFACE_FUNCS

    /* CMyDispatch methods */

/* You must describe methods for this interface here */

#endif

    /* ITypeLibrary methods */

    STDMETHOD_(BSTR, get_Name)(THIS) PURE;

    STDMETHOD_(BSTR, get_Documentation)(THIS) PURE;

    STDMETHOD_(long, get_HelpContext)(THIS) PURE;

    STDMETHOD_(BSTR, get_HelpFile)(THIS) PURE;

    STDMETHOD_(long, get_LocaleID)(THIS) PURE;

    STDMETHOD_(int, get_MajorVersion)(THIS) PURE;

    STDMETHOD_(int, get_MinorVersion)(THIS) PURE;

    STDMETHOD_(ICollection FAR*, get_TypeInfos)(THIS) PURE;

};

DEFINE_GUID(IID_ITypeInformation,0x19FEEEC4,0x4104,0x101B,0xB8,0x26,0x00,0xDD,0x01,0x10,0x3D,0xE1);

/* Definition of interface: ITypeInformation */

DECLARE_INTERFACE_(ITypeInformation, CMyDispatch)

{

#ifndef NO_BASEINTERFACE_FUNCS

    /* CMyDispatch methods */

/* You must describe methods for this interface here */

#endif

    /* ITypeInformation methods */

    STDMETHOD_(BSTR, get_Name)(THIS) PURE;

    STDMETHOD_(BSTR, get_Documentation)(THIS) PURE;

    STDMETHOD_(long, get_HelpContext)(THIS) PURE;

    STDMETHOD_(BSTR, get_HelpFile)(THIS) PURE;

    STDMETHOD_(TYPEKIND, get_TypeInfoKind)(THIS) PURE;

    STDMETHOD(_InitTypeInfo)(THIS_ LPTYPEINFO ptinfo) PURE;

};

DEFINE_GUID(IID_IBrowseHelper,0x19FEEEC2,0x4104,0x101B,0xB8,0x26,0x00,0xDD,0x01,0x10,0x3D,0xE1);

/* Definition of interface: IBrowseHelper */

DECLARE_INTERFACE_(IBrowseHelper, CMyDispatch)

{

#ifndef NO_BASEINTERFACE_FUNCS

    /* CMyDispatch methods */

/* You must describe methods for this interface here */

#endif

    /* IBrowseHelper methods */

    STDMETHOD_(ITypeLibrary FAR*, BrowseTypeLibrary)(THIS_ BSTR TypeLibraryPath) PURE;

};

DEFINE_GUID(IID_ITypeDesc,0x19FEEED1,0x4104,0x101B,0xB8,0x26,0x00,0xDD,0x01,0x10,0x3D,0xE1);

/* Definition of interface: ITypeDesc */

DECLARE_INTERFACE_(ITypeDesc, CMyDispatch)

{

#ifndef NO_BASEINTERFACE_FUNCS

    /* CMyDispatch methods */

/* You must describe methods for this interface here */

#endif

    /* ITypeDesc methods */

    STDMETHOD_(short, get_Type)(THIS) PURE;

    STDMETHOD_(ITypeInformation FAR*, get_UserDefinedDesc)(THIS) PURE;

    STDMETHOD_(IArrayDesc FAR*, get_ArrayDesc)(THIS) PURE;

    STDMETHOD_(ITypeDesc FAR*, get_PointerDesc)(THIS) PURE;

};

DEFINE_GUID(IID_IArrayBound,0x19FEEED3,0x4104,0x101B,0xB8,0x26,0x00,0xDD,0x01,0x10,0x3D,0xE1);

/* Definition of interface: IArrayBound */

DECLARE_INTERFACE_(IArrayBound, CMyDispatch)

{

#ifndef NO_BASEINTERFACE_FUNCS

    /* CMyDispatch methods */

/* You must describe methods for this interface here */

#endif

    /* IArrayBound methods */

    STDMETHOD_(long, get_ElementsCount)(THIS) PURE;

    STDMETHOD_(long, get_LowerBound)(THIS) PURE;

};

DEFINE_GUID(IID_IArrayDesc,0x19FEEED2,0x4104,0x101B,0xB8,0x26,0x00,0xDD,0x01,0x10,0x3D,0xE1);

/* Definition of interface: IArrayDesc */

DECLARE_INTERFACE_(IArrayDesc, CMyDispatch)

{

#ifndef NO_BASEINTERFACE_FUNCS

    /* CMyDispatch methods */

/* You must describe methods for this interface here */

#endif

    /* IArrayDesc methods */

    STDMETHOD_(ITypeDesc FAR*, get_ElementType)(THIS) PURE;

    STDMETHOD_(ICollection FAR*, get_ArrayBounds)(THIS) PURE;

};

DEFINE_GUID(IID_IInterface,0x19FEEEC5,0x4104,0x101B,0xB8,0x26,0x00,0xDD,0x01,0x10,0x3D,0xE1);

/* Definition of interface: IInterface */

DECLARE_INTERFACE_(IInterface, ITypeInformation)

{

#ifndef NO_BASEINTERFACE_FUNCS

    /* CMyDispatch methods */

/* You must describe methods for this interface here */

    /* ITypeInformation methods */

    STDMETHOD_(BSTR, get_Name)(THIS) PURE;

    STDMETHOD_(BSTR, get_Documentation)(THIS) PURE;

    STDMETHOD_(long, get_HelpContext)(THIS) PURE;

    STDMETHOD_(BSTR, get_HelpFile)(THIS) PURE;

    STDMETHOD_(TYPEKIND, get_TypeInfoKind)(THIS) PURE;

    STDMETHOD(_InitTypeInfo)(THIS_ LPTYPEINFO ptinfo) PURE;

#endif

    /* IInterface methods */

    STDMETHOD_(IDispatch *, get_Functions)(THIS) PURE;

};

DEFINE_GUID(IID_IDispinterface,0x19FEEEC6,0x4104,0x101B,0xB8,0x26,0x00,0xDD,0x01,0x10,0x3D,0xE1);

/* Definition of interface: IDispinterface */

DECLARE_INTERFACE_(IDispinterface, ITypeInformation)

{

#ifndef NO_BASEINTERFACE_FUNCS

    /* CMyDispatch methods */

/* You must describe methods for this interface here */

    /* ITypeInformation methods */

    STDMETHOD_(BSTR, get_Name)(THIS) PURE;

    STDMETHOD_(BSTR, get_Documentation)(THIS) PURE;

    STDMETHOD_(long, get_HelpContext)(THIS) PURE;

    STDMETHOD_(BSTR, get_HelpFile)(THIS) PURE;

    STDMETHOD_(TYPEKIND, get_TypeInfoKind)(THIS) PURE;

    STDMETHOD(_InitTypeInfo)(THIS_ LPTYPEINFO ptinfo) PURE;

#endif

    /* IDispinterface methods */

    STDMETHOD_(ICollection FAR*, get_Properties)(THIS) PURE;

    STDMETHOD_(ICollection FAR*, get_Methods)(THIS) PURE;

};

DEFINE_GUID(IID_IModule,0x19FEEEC7,0x4104,0x101B,0xB8,0x26,0x00,0xDD,0x01,0x10,0x3D,0xE1);

/* Definition of interface: IModule */

DECLARE_INTERFACE_(IModule, ITypeInformation)

{

#ifndef NO_BASEINTERFACE_FUNCS

    /* CMyDispatch methods */

/* You must describe methods for this interface here */

    /* ITypeInformation methods */

    STDMETHOD_(BSTR, get_Name)(THIS) PURE;

    STDMETHOD_(BSTR, get_Documentation)(THIS) PURE;

    STDMETHOD_(long, get_HelpContext)(THIS) PURE;

    STDMETHOD_(BSTR, get_HelpFile)(THIS) PURE;

    STDMETHOD_(TYPEKIND, get_TypeInfoKind)(THIS) PURE;

    STDMETHOD(_InitTypeInfo)(THIS_ LPTYPEINFO ptinfo) PURE;

#endif

    /* IModule methods */

    STDMETHOD_(ICollection FAR*, get_Functions)(THIS) PURE;

};

DEFINE_GUID(IID_ICoClass,0x19FEEEC8,0x4104,0x101B,0xB8,0x26,0x00,0xDD,0x01,0x10,0x3D,0xE1);

/* Definition of interface: ICoClass */

DECLARE_INTERFACE_(ICoClass, ITypeInformation)

{

#ifndef NO_BASEINTERFACE_FUNCS

    /* CMyDispatch methods */

/* You must describe methods for this interface here */

    /* ITypeInformation methods */

    STDMETHOD_(BSTR, get_Name)(THIS) PURE;

    STDMETHOD_(BSTR, get_Documentation)(THIS) PURE;

    STDMETHOD_(long, get_HelpContext)(THIS) PURE;

    STDMETHOD_(BSTR, get_HelpFile)(THIS) PURE;

    STDMETHOD_(TYPEKIND, get_TypeInfoKind)(THIS) PURE;

    STDMETHOD(_InitTypeInfo)(THIS_ LPTYPEINFO ptinfo) PURE;

#endif

    /* ICoClass methods */

    STDMETHOD_(ICollection FAR*, get_Interfaces)(THIS) PURE;

};

DEFINE_GUID(IID_IEnum,0x19FEEECD,0x4104,0x101B,0xB8,0x26,0x00,0xDD,0x01,0x10,0x3D,0xE1);

/* Definition of interface: IEnum */

DECLARE_INTERFACE_(IEnum, ITypeInformation)

{

#ifndef NO_BASEINTERFACE_FUNCS

    /* CMyDispatch methods */

/* You must describe methods for this interface here */

    /* ITypeInformation methods */

    STDMETHOD_(BSTR, get_Name)(THIS) PURE;

    STDMETHOD_(BSTR, get_Documentation)(THIS) PURE;

    STDMETHOD_(long, get_HelpContext)(THIS) PURE;

    STDMETHOD_(BSTR, get_HelpFile)(THIS) PURE;

    STDMETHOD_(TYPEKIND, get_TypeInfoKind)(THIS) PURE;

    STDMETHOD(_InitTypeInfo)(THIS_ LPTYPEINFO ptinfo) PURE;

#endif

    /* IEnum methods */

    STDMETHOD_(ICollection FAR*, get_Elements)(THIS) PURE;

};

DEFINE_GUID(IID_IStruct,0x19FEEECE,0x4104,0x101B,0xB8,0x26,0x00,0xDD,0x01,0x10,0x3D,0xE1);

/* Definition of interface: IStruct */

DECLARE_INTERFACE_(IStruct, ITypeInformation)

{

#ifndef NO_BASEINTERFACE_FUNCS

    /* CMyDispatch methods */

/* You must describe methods for this interface here */

    /* ITypeInformation methods */

    STDMETHOD_(BSTR, get_Name)(THIS) PURE;

    STDMETHOD_(BSTR, get_Documentation)(THIS) PURE;

    STDMETHOD_(long, get_HelpContext)(THIS) PURE;

    STDMETHOD_(BSTR, get_HelpFile)(THIS) PURE;

    STDMETHOD_(TYPEKIND, get_TypeInfoKind)(THIS) PURE;

    STDMETHOD(_InitTypeInfo)(THIS_ LPTYPEINFO ptinfo) PURE;

#endif

    /* IStruct methods */

    STDMETHOD_(ICollection FAR*, get_Members)(THIS) PURE;

};

DEFINE_GUID(IID_IUnion,0x19FEEECF,0x4104,0x101B,0xB8,0x26,0x00,0xDD,0x01,0x10,0x3D,0xE1);

/* Definition of interface: IUnion */

DECLARE_INTERFACE_(IUnion, ITypeInformation)

{

#ifndef NO_BASEINTERFACE_FUNCS

    /* CMyDispatch methods */

/* You must describe methods for this interface here */

    /* ITypeInformation methods */

    STDMETHOD_(BSTR, get_Name)(THIS) PURE;

    STDMETHOD_(BSTR, get_Documentation)(THIS) PURE;

    STDMETHOD_(long, get_HelpContext)(THIS) PURE;

    STDMETHOD_(BSTR, get_HelpFile)(THIS) PURE;

    STDMETHOD_(TYPEKIND, get_TypeInfoKind)(THIS) PURE;

    STDMETHOD(_InitTypeInfo)(THIS_ LPTYPEINFO ptinfo) PURE;

#endif

    /* IUnion methods */

    STDMETHOD_(ICollection FAR*, get_Members)(THIS) PURE;

};

DEFINE_GUID(IID_IAlias,0x19FEEED0,0x4104,0x101B,0xB8,0x26,0x00,0xDD,0x01,0x10,0x3D,0xE1);

/* Definition of interface: IAlias */

DECLARE_INTERFACE_(IAlias, ITypeInformation)

{

#ifndef NO_BASEINTERFACE_FUNCS

    /* CMyDispatch methods */

/* You must describe methods for this interface here */

    /* ITypeInformation methods */

    STDMETHOD_(BSTR, get_Name)(THIS) PURE;

    STDMETHOD_(BSTR, get_Documentation)(THIS) PURE;

    STDMETHOD_(long, get_HelpContext)(THIS) PURE;

    STDMETHOD_(BSTR, get_HelpFile)(THIS) PURE;

    STDMETHOD_(TYPEKIND, get_TypeInfoKind)(THIS) PURE;

    STDMETHOD(_InitTypeInfo)(THIS_ LPTYPEINFO ptinfo) PURE;

#endif

    /* IAlias methods */

    STDMETHOD_(ITypeDesc FAR*, get_BaseType)(THIS) PURE;

};

DEFINE_GUID(IID_IFunction,0x19FEEEC9,0x4104,0x101B,0xB8,0x26,0x00,0xDD,0x01,0x10,0x3D,0xE1);

/* Definition of interface: IFunction */

DECLARE_INTERFACE_(IFunction, CMyDispatch)

{

#ifndef NO_BASEINTERFACE_FUNCS

    /* CMyDispatch methods */

/* You must describe methods for this interface here */

#endif

    /* IFunction methods */

    STDMETHOD_(BSTR, get_Name)(THIS) PURE;

    STDMETHOD_(BSTR, get_Documentation)(THIS) PURE;

    STDMETHOD_(long, get_HelpContext)(THIS) PURE;

    STDMETHOD_(BSTR, get_HelpFile)(THIS) PURE;

    STDMETHOD_(ITypeDesc FAR*, get_ReturnType)(THIS) PURE;

    STDMETHOD_(ICollection FAR*, get_Parameters)(THIS) PURE;

    STDMETHOD_(MEMBERID, get_Memberid)(THIS) PURE;

    STDMETHOD_(CALLCONV, get_CallConvention)(THIS) PURE;

    STDMETHOD_(FUNCKIND, get_FuncKind)(THIS) PURE;

    STDMETHOD_(INVOKEKIND, get_InvocationKind)(THIS) PURE;

    STDMETHOD_(OBJTYPE, get_Kind)(THIS) PURE;

};

DEFINE_GUID(IID_IProperty,0x19FEEECA,0x4104,0x101B,0xB8,0x26,0x00,0xDD,0x01,0x10,0x3D,0xE1);

/* Definition of interface: IProperty */

DECLARE_INTERFACE_(IProperty, CMyDispatch)

{

#ifndef NO_BASEINTERFACE_FUNCS

    /* CMyDispatch methods */

/* You must describe methods for this interface here */

#endif

    /* IProperty methods */

    STDMETHOD_(BSTR, get_Name)(THIS) PURE;

    STDMETHOD_(BSTR, get_Documentation)(THIS) PURE;

    STDMETHOD_(long, get_HelpContext)(THIS) PURE;

    STDMETHOD_(BSTR, get_HelpFile)(THIS) PURE;

    STDMETHOD_(ITypeDesc FAR*, get_Type)(THIS) PURE;

    STDMETHOD_(MEMBERID, get_Memberid)(THIS) PURE;

    STDMETHOD_(OBJTYPE, get_Kind)(THIS) PURE;

};

DEFINE_GUID(IID_IConstant,0x19FEEED4,0x4104,0x101B,0xB8,0x26,0x00,0xDD,0x01,0x10,0x3D,0xE1);

/* Definition of interface: IConstant */

DECLARE_INTERFACE_(IConstant, CMyDispatch)

{

#ifndef NO_BASEINTERFACE_FUNCS

    /* CMyDispatch methods */

/* You must describe methods for this interface here */

#endif

    /* IConstant methods */

    STDMETHOD_(BSTR, get_Name)(THIS) PURE;

    STDMETHOD_(BSTR, get_Documentation)(THIS) PURE;

    STDMETHOD_(long, get_HelpContext)(THIS) PURE;

    STDMETHOD_(BSTR, get_HelpFile)(THIS) PURE;

    STDMETHOD_(ITypeDesc FAR*, get_Type)(THIS) PURE;

    STDMETHOD_(VARIANT, get_Value)(THIS) PURE;

    STDMETHOD_(MEMBERID, get_Memberid)(THIS) PURE;

    STDMETHOD_(OBJTYPE, get_Kind)(THIS) PURE;

};

DEFINE_GUID(IID_IParameter,0x19FEEECB,0x4104,0x101B,0xB8,0x26,0x00,0xDD,0x01,0x10,0x3D,0xE1);

/* Definition of interface: IParameter */

DECLARE_INTERFACE_(IParameter, CMyDispatch)

{

#ifndef NO_BASEINTERFACE_FUNCS

    /* CMyDispatch methods */

/* You must describe methods for this interface here */

#endif

    /* IParameter methods */

    STDMETHOD_(BSTR, get_Name)(THIS) PURE;

    STDMETHOD_(ITypeDesc FAR*, get_Type)(THIS) PURE;

    STDMETHOD_(int, get_IDLFlags)(THIS) PURE;

    STDMETHOD_(OBJTYPE, get_Kind)(THIS) PURE;

};

DEFINE_GUID(CLSID_BrowseHelper,0x19FEEEC1,0x4104,0x101B,0xB8,0x26,0x00,0xDD,0x01,0x10,0x3D,0xE1);

class BrowseHelper;

#endif


 ALIAS.CPP   (BROWSEH OLE Sample)

/*************************************************************************

**

**    OLE Automation TypeLibrary Browse Helper Sample

**

**    alias.cpp

**

**    CAlias implementation

**

**     Written by Microsoft Product Support Services, Windows Developer Support

**    (c) Copyright Microsoft Corp. 1994 All Rights Reserved

**

*************************************************************************/

#include <windows.h>

#include <windowsx.h>

#ifdef WIN16

  #include <ole2.h>

  #include <compobj.h>

  #include <dispatch.h>

  #include <variant.h>

  #include <olenls.h>

#endif

#include "browseh.h"

/*

 * CAlias::Create

 *

 * Purpose:

 *  Creates an instance of the Alias automation object and initializes it.

 *

 * Parameters:

 *  ptinfo     Typeinfo of Alias.

 *  ppAlias    Returns Alias automation object.

 *

 * Return Value:

 *  HRESULT

 *

 */

HRESULT

CAlias::Create(LPTYPEINFO ptinfo, CAlias FAR* FAR* ppAlias)

{

    HRESULT hr;

    CAlias FAR* pAlias = NULL;

    LPTYPEATTR ptypeattr = NULL;

    CTypeDesc FAR* pTypeDesc;

    *ppAlias = NULL;

    // Create alias object.

    pAlias = new CAlias();

    if (pAlias == NULL)

    {

        hr = ResultFromScode(E_OUTOFMEMORY);

        goto error;

    }

    // Load type information for the object from type library.

    hr = pAlias->LoadTypeInfo(IID_IAlias);

    if (FAILED(hr))

        goto error;

    // Ask base class (CTypeInfo) to initialize

    hr = pAlias->_InitTypeInfo(ptinfo);

    if (FAILED(hr))

        goto error;

    // Get base type of this alias.

    hr = ptinfo->GetTypeAttr(&ptypeattr);

    if (FAILED(hr))

        return NULL;

    hr = CTypeDesc::Create(ptinfo, &ptypeattr->tdescAlias, &pTypeDesc);

    if (FAILED(hr))

        goto error;

    pTypeDesc->QueryInterface(IID_IDispatch, (LPVOID FAR*)&pAlias->m_pdispTypeDescBase);

    ptinfo->ReleaseTypeAttr(ptypeattr);

#ifdef _DEBUG

    lstrcpyn(pAlias->m_szClassName, TEXT("Alias"), 100);

#endif

    *ppAlias = pAlias;

    return NOERROR;

error:

    if (pAlias == NULL) return ResultFromScode(E_OUTOFMEMORY);

    if (pAlias->m_pdispTypeDescBase) pAlias->m_pdispTypeDescBase->Release();

    if (ptypeattr) ptinfo->ReleaseTypeAttr(ptypeattr);

    // Set to NULL to prevent destructor from attempting to free again

    pAlias->m_pdispTypeDescBase = NULL;

    delete pAlias;

    return hr;

}

/*

 * CAlias::CAlias

 *

 * Purpose:

 *  Constructor for CAlias object. Initializes members to NULL.

 *

 */

CAlias::CAlias()

{

    m_pdispTypeDescBase = NULL;

}

/*

 * CAlias::~CAlias

 *

 * Purpose:

 *  Destructor for CAlias object.

 *

 */

CAlias::~CAlias()

{

    if (m_pdispTypeDescBase) m_pdispTypeDescBase->Release();

}

STDMETHODIMP_(REFCLSID)

CAlias::GetInterfaceID()

{

    return IID_IAlias;

}

STDMETHODIMP_(ITypeDesc FAR*)

CAlias::get_BaseType()

{

    m_pdispTypeDescBase->AddRef();

    return (ITypeDesc FAR*)m_pdispTypeDescBase;

}


 BROWSECF.CPP   (BROWSEH OLE Sample)

/*************************************************************************

**

**    OLE Automation TypeLibrary Browse Helper Sample

**

**    BrowseHelpercf.cpp

**

**    CBrowseHelperCF (class factory) implementation

**

**     Written by Microsoft Product Support Services, Windows Developer Support

**    (c) Copyright Microsoft Corp. 1994 All Rights Reserved

**

*************************************************************************/

#include <windows.h>

#include <windowsx.h>

#ifdef WIN16

  #include <ole2.h>

  #include <compobj.h>

  #include <dispatch.h>

  #include <variant.h>

  #include <olenls.h>

#endif

#include "browseh.h"

CBrowseHelperCF::CBrowseHelperCF(void)

{

    m_cRef = 0;

}

/*

 * CBrowseHelperCF::QueryInterface, AddRef, Release

 *

 * Purpose:

 *  Implements IUnknown::QueryInterface, AddRef, Release

 *

 */

STDMETHODIMP

CBrowseHelperCF::QueryInterface(REFIID iid, void FAR* FAR* ppv)

{

    *ppv = NULL;

    if (iid == IID_IUnknown || iid == IID_IClassFactory)

        *ppv = this;

    else

        return ResultFromScode(E_NOINTERFACE);

    AddRef();

    return NOERROR;

}

STDMETHODIMP_(ULONG)

CBrowseHelperCF::AddRef(void)

{

    return ++m_cRef;

}

STDMETHODIMP_(ULONG)

CBrowseHelperCF::Release(void)

{

    if(--m_cRef == 0)

    {

        delete this;

        return 0;

    }

    return m_cRef;

}

/*

 * CBrowseHelperCF::CreateInstance, LockServer

 *

 * Purpose:

 *  Implements IClassFactory::CreateInstance, LockServer

 *

 */

STDMETHODIMP

CBrowseHelperCF::CreateInstance(IUnknown FAR* punkOuter,

                         REFIID riid,

                         void FAR* FAR* ppv)

{

    CBrowseHelper FAR* pBrowseHelper;

    HRESULT hr;

    *ppv = NULL;

    // This implementation does not allow aggregation

    if (punkOuter)

        return ResultFromScode(CLASS_E_NOAGGREGATION);

    // Create an instance of the BrowseHelper automation object.

    hr = CBrowseHelper::Create(&pBrowseHelper);

    if (FAILED(hr))

        return hr;

    hr = pBrowseHelper->QueryInterface(riid, ppv);

    if (FAILED(hr))

    {

        delete pBrowseHelper;

        return hr;

    }

    return NOERROR;

}

STDMETHODIMP

CBrowseHelperCF::LockServer(BOOL fLock)

{

    extern ULONG g_cLock;

    if (fLock)

        g_cLock++;

    else

        g_cLock--;

    return NOERROR;

}


 BROWSEH.CPP   (BROWSEH OLE Sample)

/*************************************************************************

**

**    OLE Automation TypeLibrary Browse Helper Sample

**

**    browse.cpp

**

**    CBrowseHelper implementation

**

**     Written by Microsoft Product Support Services, Windows Developer Support

**    (c) Copyright Microsoft Corp. 1994 All Rights Reserved

**

*************************************************************************/

#include <windows.h>

#include <windowsx.h>

#ifdef WIN16

  #include <ole2.h>

  #include <compobj.h>

  #include <dispatch.h>

  #include <variant.h>

  #include <olenls.h>

#endif

#include "browseh.h"

/*

 * CBrowseHelper::Create

 *

 * Purpose:

 *  Creates an instance of the BrowseHelper automation object and initializes it.

 *

 * Parameters:

 *  ppBrowseHelper   Returns BrowseHelper automation object.

 *

 * Return Value:

 *  HRESULT

 *

 */

HRESULT

CBrowseHelper::Create(CBrowseHelper FAR* FAR* ppBrowseHelper )

{

    HRESULT hr;

    CBrowseHelper FAR* pBrowseHelper = NULL;

    *ppBrowseHelper = NULL;

    // Create object.

    pBrowseHelper = new CBrowseHelper();

    if (pBrowseHelper == NULL)

    {

        hr = ResultFromScode(E_OUTOFMEMORY);

        goto error;

    }

    // Load type information for the application object from type library.

    hr = pBrowseHelper->LoadTypeInfo(IID_IBrowseHelper);

    if (FAILED(hr))

        goto error;

#ifdef _DEBUG

    lstrcpyn(pBrowseHelper->m_szClassName, TEXT("BrowseHelper"), 100);

#endif

    *ppBrowseHelper = pBrowseHelper;

    return NOERROR;

error:

    if (pBrowseHelper == NULL)

        return ResultFromScode(E_OUTOFMEMORY);

    delete pBrowseHelper;

    return hr;

}

/*

 * CBrowseHelper::CBrowseHelper

 *

 * Purpose:

 *  Constructor for CBrowseHelper object. Initializes members to NULL.

 *

 */

CBrowseHelper::CBrowseHelper()

{

    extern ULONG g_cObj;

    g_cObj++;

}

/*

 * CBrowseHelper::~CBrowseHelper

 *

 * Purpose:

 *  Destructor for CBrowseHelper object. Frees BrowseHelper message BSTR and default

 *  IDispatch implementation. Closes the aplication.

 *

 */

CBrowseHelper::~CBrowseHelper()

{

     extern ULONG g_cObj;

     g_cObj--;

}

STDMETHODIMP_(REFCLSID)

CBrowseHelper::GetInterfaceID()

{

    return IID_IBrowseHelper;

}

/*

 * CBrowseHelper::BrowseTypeLibrary

 *

 * Purpose:

 *  Opens and browses type library. Creates and returns a TypeLibrary object.

 *

 */

STDMETHODIMP_(ITypeLibrary FAR*)

CBrowseHelper::BrowseTypeLibrary(BSTR bstrPath)

{

    LPTYPELIB ptlib = NULL;

    LPDISPATCH pdisp;

    HRESULT hr;

    CTypeLibrary FAR* pTypeLibrary;

    hr = LoadTypeLib(bstrPath, &ptlib);

    if (FAILED(hr))

        {RaiseException(IDS_CannotFindTypeLibrary); return NULL;}

    hr = CTypeLibrary::Create(ptlib, &pTypeLibrary);

    if (FAILED(hr))

         {RaiseException(IDS_TypeLibraryCreationFailed); goto error;}

    hr = pTypeLibrary->QueryInterface(IID_IDispatch, (void FAR* FAR*)&pdisp);

    if (FAILED(hr))

        {RaiseException(IDS_Unexpected); goto error;}

    ptlib->Release();

    return (ITypeLibrary FAR*)pdisp;

error:

    if (ptlib)

        ptlib->Release();

    return NULL;

}


 COCLASS.CPP   (BROWSEH OLE Sample)

/*************************************************************************

**

**    OLE Automation TypeLibrary Browse Helper Sample

**

**    coclass.cpp

**

**    CCoClass implementation

**

**     Written by Microsoft Product Support Services, Windows Developer Support

**    (c) Copyright Microsoft Corp. 1994 All Rights Reserved

**

*************************************************************************/

#include <windows.h>

#include <windowsx.h>

#ifdef WIN16

  #include <ole2.h>

  #include <compobj.h>

  #include <dispatch.h>

  #include <variant.h>

  #include <olenls.h>

#endif

#include "browseh.h"

/*

 * CCoClass::Create

 *

 * Purpose:

 *  Creates an instance of the CoClass automation object and initializes it.

 *

 * Parameters:

 *  ptinfo       TypeInfo of coclass.

 *  ppCoClass    Returns CoClass automation object.

 *

 * Return Value:

 *  HRESULT

 *

 */

HRESULT

CCoClass::Create(LPTYPEINFO ptinfo, CCoClass FAR* FAR* ppCoClass)

{

    HRESULT hr;

    CCoClass FAR* pCoClass = NULL;

    *ppCoClass = NULL;

    // Create object.

    pCoClass = new CCoClass();

    if (pCoClass == NULL)

    {

        hr = ResultFromScode(E_OUTOFMEMORY);

        goto error;

    }

    // Load type information for the object from type library.

    hr = pCoClass->LoadTypeInfo(IID_ICoClass);

    if (FAILED(hr))

        goto error;

    // Ask base class (CTypeInfo) to initialize.

    hr = pCoClass->_InitTypeInfo(ptinfo);

    if (FAILED(hr))

        goto error;

    ptinfo->AddRef();

    pCoClass->m_ptinfo = ptinfo;

#ifdef _DEBUG

    lstrcpyn(pCoClass->m_szClassName, TEXT("CoClass"), 100);

#endif

    *ppCoClass = pCoClass;

    return NOERROR;

error:

    if (pCoClass == NULL) return ResultFromScode(E_OUTOFMEMORY);

    if (pCoClass->m_ptinfo) pCoClass->m_ptinfo->Release();

    // Set to NULL to prevent destructor from attempting to free again

    pCoClass->m_ptinfo = NULL;

    delete pCoClass;

    return hr;

}

/*

 * CCoClass::CCoClass

 *

 * Purpose:

 *  Constructor for CCoClass object. Initializes members to NULL.

 *

 */

CCoClass::CCoClass()

{

    m_pdispInterfaces = NULL;

    m_ptinfo = NULL;

}

/*

 * CCoClass::~CCoClass

 *

 * Purpose:

 *  Destructor for CCoClass object.

 *

 */

CCoClass::~CCoClass()

{

    if (m_pdispInterfaces) m_pdispInterfaces->Release();

    if (m_ptinfo) m_ptinfo->Release();

}

STDMETHODIMP_(REFCLSID)

CCoClass::GetInterfaceID()

{

    return IID_ICoClass;

}

STDMETHODIMP_(ICollection FAR*)

CCoClass::get_Interfaces()

{

    HRESULT hr;

    CCollection FAR* pCollection = NULL;

    CInterface FAR* pInterface;

    CCoClass FAR* pCoClass;

    LPDISPATCH pdisp;

    HREFTYPE hreftype;

    LPTYPEATTR ptypeattr = NULL;

    LPTYPEINFO ptinfoInterface = NULL;

    LPTYPELIB ptlib = NULL;

    unsigned int nIndex;

    unsigned short n;

    TYPEKIND typekind;

    if (m_pdispInterfaces == NULL)

    {

        hr = m_ptinfo->GetTypeAttr(&ptypeattr);

        if (FAILED(hr))

            {RaiseException(IDS_Unexpected); return NULL;}

        hr = CCollection::Create(ptypeattr->cImplTypes, 0, &pCollection);

        if (FAILED(hr))

            {RaiseException(IDS_Unexpected); goto error;}

        // Enumerate interfaces/dispinterfaces in coclass and return a collection of these.

        for (n=0; n<ptypeattr->cImplTypes; n++)

        {

            hr = m_ptinfo->GetRefTypeOfImplType(n, &hreftype);

            if (FAILED(hr))

                {RaiseException(IDS_Unexpected); goto error;}

            hr = m_ptinfo->GetRefTypeInfo(hreftype, &ptinfoInterface);

            if (FAILED(hr))

                {RaiseException(IDS_Unexpected); goto error;}

            hr = ptinfoInterface->GetContainingTypeLib(&ptlib, &nIndex);

            if (FAILED(hr))

                {RaiseException(IDS_Unexpected); goto error;}

            hr = ptlib->GetTypeInfoType(nIndex, &typekind);

            if (FAILED(hr))

                {RaiseException(IDS_Unexpected); goto error;}

            ptlib->Release();

            ptlib = NULL;

            switch (typekind)

            {

                case TKIND_INTERFACE:

                    hr = CInterface::Create(ptinfoInterface, &pInterface);

                    if (FAILED(hr))

                        {RaiseException(IDS_Unexpected); goto error;}

                    pInterface->QueryInterface(IID_IDispatch, (void FAR* FAR*)&pdisp);

                    break;

                case TKIND_DISPATCH:

                    hr = CCoClass::Create(ptinfoInterface, &pCoClass);

                    if (FAILED(hr))

                        {RaiseException(IDS_Unexpected); goto error;}

                    pCoClass->QueryInterface(IID_IDispatch, (void FAR* FAR*)&pdisp);

                    break;

            }

            ptinfoInterface->Release();

            ptinfoInterface = NULL;

            pCollection->Add(pdisp);

            pdisp->Release();

        }

        pCollection->QueryInterface(IID_IDispatch, (void FAR* FAR*)&pdisp);

        m_pdispInterfaces = pdisp;

        m_ptinfo->ReleaseTypeAttr(ptypeattr);

    }

    m_pdispInterfaces->AddRef();

    return (ICollection FAR*)m_pdispInterfaces;

error:

    if (ptypeattr) m_ptinfo->ReleaseTypeAttr(ptypeattr);

    if (pCollection) delete pCollection;

    if (ptlib) ptlib->Release();

    if (ptinfoInterface) ptinfoInterface->Release();

    return NULL;

}


 COLLECT.CPP   (BROWSEH OLE Sample)

/*************************************************************************

**

**    OLE Automation TypeLibrary Browse Helper Sample

**

**    collect.cpp

**

**    CCollection implementation

**

**     Written by Microsoft Product Support Services, Windows Developer Support

**    (c) Copyright Microsoft Corp. 1994 All Rights Reserved

**

*************************************************************************/

#include <windows.h>

#include <windowsx.h>

#ifdef WIN16

  #include <ole2.h>

  #include <compobj.h>

  #include <dispatch.h>

  #include <variant.h>

  #include <olenls.h>

#endif

#include "browseh.h"

/*

 * CCollection::Create

 *

 * Purpose:

 *  Creates an instance of a collection object and initializes it.

 *

 * Parameters:

 *  lMaxSize   Maximum number of items that can added to collection.

 *  lLBound    Lower bound of index of collection.

 *  ppCollection    Returns collection object.

 *

 * Return Value:

 *  HRESULT

 *

 */

HRESULT

CCollection::Create(ULONG lMaxSize, long lLBound, CCollection FAR* FAR* ppCollection)

{

    HRESULT hr;

    CCollection FAR* pCollection = NULL;

    SAFEARRAYBOUND sabound[1];

    *ppCollection = NULL;

    // Create new collection

    pCollection = new CCollection();

    if (pCollection == NULL)

        goto error;

    // Load type information for the collection from type library.

    hr = pCollection->LoadTypeInfo(IID_ICollection);

    if (FAILED(hr))

        goto error;

    // If lMaxSize is 0 increment it to 1 or SafeArrayCreate will fail

    if (lMaxSize == 0)

       lMaxSize = 1;

    pCollection->m_cMax = lMaxSize;

    pCollection->m_cElements = 0;

    pCollection->m_lLBound = lLBound;

    // Create a safe array which is used to implement the collection

    sabound[0].cElements = lMaxSize;

    sabound[0].lLbound = lLBound;

    pCollection->m_psa = SafeArrayCreate(VT_VARIANT, 1, sabound);

    if (pCollection->m_psa == NULL)

    {

        hr = ResultFromScode(E_OUTOFMEMORY);

        goto error;

    }

#ifdef _DEBUG

    lstrcpyn(pCollection->m_szClassName, TEXT("Collection"), 100);

#endif

    *ppCollection = pCollection;

    return NOERROR;

error:

    if (pCollection == NULL)

        return ResultFromScode(E_OUTOFMEMORY);

    if (pCollection->m_psa)

        SafeArrayDestroy(pCollection->m_psa);

    pCollection->m_psa = NULL;

    delete pCollection;

    return hr;

}

/*

 * CCollection::CCollection

 *

 * Purpose:

 *  Constructor for CCollection object. Initializes members to NULL.

 *

 */

CCollection::CCollection()

{

    m_psa = NULL;

}

/*

 * CCollection::~CCollection

 *

 * Purpose:

 *  Destructor for CCollection object.

 *

 */

CCollection::~CCollection()

{

     if (m_psa) SafeArrayDestroy(m_psa);

}

STDMETHODIMP_(REFCLSID)

CCollection::GetInterfaceID()

{

    return IID_ICollection;

}

/*

 * CCollection::get_Count

 *

 * Purpose:

 *  Returns number of items in collection.

 *

 */

STDMETHODIMP_(long)

CCollection::get_Count(void)

{

    return m_cElements;

}

/*

 * CCollection::get_Item

 *

 * Purpose:

 *  Retrieves item from collection, given an index.

 *

 * Parameters:

 *   lIndex   Index of item to be retrieved.

 *

 * Returns

 *  IDispatch of item retrieved from collection.

 *

 */

STDMETHODIMP_(LPDISPATCH)

CCollection::get_Item(long lIndex)

{

    HRESULT hr;

    VARIANT v;

    LPDISPATCH pdisp = NULL;

    // Check if integer index is within range

    if (lIndex < m_lLBound || lIndex >= (long)(m_lLBound+m_cElements))

        {RaiseException(IDS_InvalidIndex); return NULL;}

    // Retrieve and return item. Note that SafeArrayGetElement AddRefs so an additional AddRef

    // is not required.

    VariantInit(&v);

    hr = SafeArrayGetElement(m_psa, &lIndex, &v);

    if (FAILED(hr))

        {RaiseException(IDS_Unexpected); return NULL;}

    return V_DISPATCH(&v);

}

/*

 * CCollection::get_NewEnum

 *

 * Purpose:

 *  Returns an enumerator (IEnumVARIANT) for the items curently in the collection.

 *  The NewEnum property is restricted and so is invisible to users of an

 *  automation controller's scripting language. Automation controllers that support

 *  a 'For Each' statement to iterate through the elements of a collection will use

 *  the enumerator returned by NewEnum. The enumerator creates a snapshot of the

 *  the current state of the collection.

 *

 */

STDMETHODIMP_(LPUNKNOWN)

CCollection::get__NewEnum(void)

{

    CEnumVariant FAR* penum = NULL;;

    LPUNKNOWN punkEnumVariant = NULL;

    HRESULT hr;

    // Create new enumerator for items currently in collection and QI for IUnknown

    hr = CEnumVariant::Create(m_psa, m_cElements, &penum);

    if (FAILED(hr))

        {RaiseException(IDS_OutOfMemory); goto error;}

    hr = penum->QueryInterface(IID_IUnknown, (VOID FAR* FAR*)&punkEnumVariant);

    if (FAILED(hr))

        {RaiseException(IDS_Unexpected); goto error;}

    return punkEnumVariant;

error:

    if (penum)

        delete penum;

    return NULL;

}

/*

 * CCollection::Add

 *

 * Purpose:

 *  Adds an item to the collection.

 *

 * Parameters:

 *  pdispItemAdd    Item to be added to collection.

 *

 */

STDMETHODIMP_(void)

CCollection::Add(LPDISPATCH pdispItem)

{

    HRESULT hr;

    LONG l;

    VARIANT v;

    // Is the collection full?

    if (m_cElements == m_cMax)

        {RaiseException(IDS_CollectionFull); return;}

    l = m_lLBound+m_cElements;

    VariantInit(&v);

    V_VT(&v) = VT_DISPATCH;

    V_DISPATCH(&v) = pdispItem;

    hr = SafeArrayPutElement(m_psa, &l, &v);

    if (FAILED(hr))

        {RaiseException(IDS_Unexpected); return;}

    m_cElements++;

}


 CONSTANT.CPP   (BROWSEH OLE Sample)

/*************************************************************************

**

**    OLE Automation Constant Browse Helper Sample

**

**    Constant.cpp

**

**    CConstant implementation

**

**     Written by Microsoft Product Support Services, Windows Developer Support

**    (c) Copyright Microsoft Corp. 1994 All Rights Reserved

**

*************************************************************************/

#include <windows.h>

#include <windowsx.h>

#ifdef WIN16

  #include <ole2.h>

  #include <compobj.h>

  #include <dispatch.h>

  #include <variant.h>

  #include <olenls.h>

#endif

#include "browseh.h"

/*

 * CConstant::Create

 *

 * Purpose:

 *  Creates an instance of the Constant automation object and initializes it.

 *

 * Parameters:

 *  ptinfo        TypeInfo of which this constant is an element.

 *  pvardesc      VARDESC that describes this constant.

 *  ppConstant    Returns Constant automation object.

 *

 * Return Value:

 *  HRESULT

 *

 */

HRESULT

CConstant::Create(LPTYPEINFO ptinfo, LPVARDESC pvardesc, CConstant FAR* FAR* ppConstant)

{

    HRESULT hr;

    CConstant FAR* pConstant = NULL;

    BSTR bstr;

    unsigned int cNames;

    CTypeDesc FAR* pTypeDesc = NULL;

    *ppConstant = NULL;

    // Create object.

    pConstant = new CConstant();

    if (pConstant == NULL)

    {

        hr = ResultFromScode(E_OUTOFMEMORY);

        goto error;

    }

    // Load type information for the application object from type library.

    hr = pConstant->LoadTypeInfo(IID_IConstant);

    if (FAILED(hr))

        goto error;

    pConstant->m_memid = pvardesc->memid;

    ptinfo->GetNames(pvardesc->memid, &bstr, 1, &cNames);

    pConstant->m_bstrName = bstr;

    // Type of constant.

    hr = CTypeDesc::Create(ptinfo, &pvardesc->elemdescVar.tdesc, &pTypeDesc);

    if (FAILED(hr))

        goto error;

    pTypeDesc->QueryInterface(IID_IDispatch, (LPVOID FAR*)&pConstant->m_pdispTypeDesc);

    // Constant value.

    if (pvardesc->varkind == VAR_CONST)

        pConstant->m_vValue = *pvardesc->lpvarValue;

    else goto error;

    hr = ptinfo->GetDocumentation(pvardesc->memid, NULL, &pConstant->m_bstrDocumentation,

             &pConstant->m_ulHelpContext, &pConstant->m_bstrHelpFile);

    if (FAILED(hr))

        goto error;

#ifdef _DEBUG

    lstrcpyn(pConstant->m_szClassName, TEXT("Constant"), 100);

#endif

    *ppConstant = pConstant;

    return NOERROR;

error:

    if (pConstant == NULL) return ResultFromScode(E_OUTOFMEMORY);

    if (pConstant->m_bstrName) SysFreeString(pConstant->m_bstrName);

    if (pConstant->m_bstrDocumentation) SysFreeString(pConstant->m_bstrDocumentation);

    if (pConstant->m_bstrHelpFile) SysFreeString(pConstant->m_bstrHelpFile);

    // Set to NULL to prevent destructor from attempting to free again

    pConstant->m_bstrName = NULL;

    pConstant->m_bstrDocumentation = NULL;

    pConstant->m_bstrHelpFile = NULL;

    delete pConstant;

    return hr;

}

/*

 * CConstant::CConstant

 *

 * Purpose:

 *  Constructor for CConstant object. Initializes members to NULL.

 *

 */

CConstant::CConstant()

{

    m_bstrName = NULL;

    m_bstrDocumentation = NULL;

    m_bstrHelpFile = NULL;

    m_pdispTypeDesc = NULL;

}

/*

 * CConstant::~CConstant

 *

 * Purpose:

 *  Destructor for CConstant object.

 *

 */

CConstant::~CConstant()

{

     if (m_bstrName) SysFreeString(m_bstrName);

     if (m_bstrDocumentation) SysFreeString(m_bstrDocumentation);

     if (m_bstrHelpFile) SysFreeString(m_bstrHelpFile);

     if (m_pdispTypeDesc) m_pdispTypeDesc->Release();

}

STDMETHODIMP_(REFCLSID)

CConstant::GetInterfaceID()

{

    return IID_IConstant;

}

STDMETHODIMP_(BSTR)

CConstant::get_Name()

{

    return SysAllocString(m_bstrName);

}

STDMETHODIMP_(BSTR)

CConstant::get_Documentation()

{

    return SysAllocString(m_bstrDocumentation);

}

STDMETHODIMP_(long)

CConstant::get_HelpContext()

{

    return (long)m_ulHelpContext;

}

STDMETHODIMP_(BSTR)

CConstant::get_HelpFile()

{

    return SysAllocString(m_bstrHelpFile);

}

STDMETHODIMP_(ITypeDesc FAR*)

CConstant::get_Type()

{

    m_pdispTypeDesc->AddRef();

    return (ITypeDesc FAR*)m_pdispTypeDesc;

}

STDMETHODIMP_(VARIANT)

CConstant::get_Value()

{

    return m_vValue;

}

STDMETHODIMP_(MEMBERID)

CConstant::get_Memberid()

{

    return m_memid;

}

STDMETHODIMP_(OBJTYPE)

CConstant::get_Kind()

{

    return TYPE_CONSTANT;

}


 DISPFACE.CPP   (BROWSEH OLE Sample)

/*************************************************************************

**

**    OLE Automation TypeLibrary Browse Helper Sample

**

**    dispface.cpp

**

**    CDispinterface implementation

**

**     Written by Microsoft Product Support Services, Windows Developer Support

**    (c) Copyright Microsoft Corp. 1994 All Rights Reserved

**

*************************************************************************/

#include <windows.h>

#include <windowsx.h>

#ifdef WIN16

  #include <ole2.h>

  #include <compobj.h>

  #include <dispatch.h>

  #include <variant.h>

  #include <olenls.h>

#endif

#include "browseh.h"

/*

 * CDispinterface::Create

 *

 * Purpose:

 *  Creates an instance of the Dispinterface automation object and initializes it.

 *

 * Parameters:

 *  ptinfo             TypeInfo of dispinterface.

 *  ppDispinterface    Returns Dispinterface automation object.

 *

 * Return Value:

 *  HRESULT

 *

 */

HRESULT

CDispinterface::Create(LPTYPEINFO ptinfo, CDispinterface FAR* FAR* ppDispinterface)

{

    HRESULT hr;

    CDispinterface FAR* pDispinterface = NULL;

    *ppDispinterface = NULL;

    // Create object.

    pDispinterface = new CDispinterface();

    if (pDispinterface == NULL)

    {

        hr = ResultFromScode(E_OUTOFMEMORY);

        goto error;

    }

    // Load type information for the object from type library.

    hr = pDispinterface->LoadTypeInfo(IID_IDispinterface);

    if (FAILED(hr))

        goto error;

    // Ask base class (CTypeInfo) to initialize.

    hr = pDispinterface->_InitTypeInfo(ptinfo);

    if (FAILED(hr))

        goto error;

    ptinfo->AddRef();

    pDispinterface->m_ptinfo = ptinfo;

#ifdef _DEBUG

    lstrcpyn(pDispinterface->m_szClassName, TEXT("Dispinterface"), 100);

#endif

    *ppDispinterface = pDispinterface;

    return NOERROR;

error:

    if (pDispinterface == NULL) return ResultFromScode(E_OUTOFMEMORY);

    if (pDispinterface->m_ptinfo) pDispinterface->m_ptinfo->Release();

    // Set to NULL to prevent destructor from attempting to free again

    pDispinterface->m_ptinfo = NULL;

    delete pDispinterface;

    return hr;

}

/*

 * CDispinterface::CDispinterface

 *

 * Purpose:

 *  Constructor for CDispinterface object. Initializes members to NULL.

 *

 */

CDispinterface::CDispinterface()

{

    m_pdispProperties = NULL;

    m_pdispMethods = NULL;

    m_ptinfo = NULL;

}

/*

 * CDispinterface::~CDispinterface

 *

 * Purpose:

 *  Destructor for CDispinterface object.

 *

 */

CDispinterface::~CDispinterface()

{

    if (m_pdispProperties) m_pdispProperties->Release();

    if (m_pdispMethods) m_pdispMethods->Release();

    if (m_ptinfo) m_ptinfo->Release();

}

STDMETHODIMP_(REFCLSID)

CDispinterface::GetInterfaceID()

{

    return IID_IDispinterface;

}

STDMETHODIMP_(ICollection FAR*)

CDispinterface::get_Methods()

{

    HRESULT hr;

    CFunction FAR* pFunction;

    CCollection FAR* pCollection = NULL;

    LPDISPATCH pdisp;

    LPTYPEATTR ptypeattr = NULL;

    unsigned short n;

    if (m_pdispMethods == NULL)

    {

        hr = m_ptinfo->GetTypeAttr(&ptypeattr);

        if (FAILED(hr))

            {RaiseException(IDS_Unexpected); return NULL;}

        hr = CCollection::Create(ptypeattr->cFuncs, 0, &pCollection);

        if (FAILED(hr))

            {RaiseException(IDS_Unexpected); goto error;}

        // Enumerate methods and return a collection of these.

        for (n=0; n<ptypeattr->cFuncs; n++)

        {

            hr = CFunction::Create(m_ptinfo, n, &pFunction);

            if (FAILED(hr))

                {RaiseException(IDS_Unexpected); goto error;}

            pFunction->QueryInterface(IID_IDispatch, (void FAR* FAR*)&pdisp);

            pCollection->Add(pdisp);

            pdisp->Release();

        }

        pCollection->QueryInterface(IID_IDispatch, (void FAR* FAR*)&pdisp);

        m_pdispMethods = pdisp;

        m_ptinfo->ReleaseTypeAttr(ptypeattr);

    }

    m_pdispMethods->AddRef();

    return (ICollection FAR*)m_pdispMethods;

error:

    if (ptypeattr) m_ptinfo->ReleaseTypeAttr(ptypeattr);

    if (pCollection) delete pCollection;

    return NULL;

}

STDMETHODIMP_(ICollection FAR*)

CDispinterface::get_Properties()

{

    HRESULT hr;

    CProperty FAR* pProperty;

    CCollection FAR* pCollection = NULL;

    LPDISPATCH pdisp;

    LPVARDESC pvardesc = NULL;

    LPTYPEATTR ptypeattr = NULL;

    unsigned short n;

    if (m_pdispProperties == NULL)

    {

        hr = m_ptinfo->GetTypeAttr(&ptypeattr);

        if (FAILED(hr))

            {RaiseException(IDS_Unexpected); return NULL;}

        hr = CCollection::Create(ptypeattr->cVars, 0, &pCollection);

        if (FAILED(hr))

            {RaiseException(IDS_Unexpected); goto error;}

        // Enumerate properties and return a collection of these.

        for (n=0; n<ptypeattr->cVars; n++)

        {

            hr = m_ptinfo->GetVarDesc(n, &pvardesc);

            if (FAILED(hr))

                {RaiseException(IDS_Unexpected); goto error;}

            hr = CProperty::Create(m_ptinfo, pvardesc, &pProperty);

            if (FAILED(hr))

                {RaiseException(IDS_Unexpected); goto error;}

            m_ptinfo->ReleaseVarDesc(pvardesc);

            pvardesc = NULL;

            pProperty->QueryInterface(IID_IDispatch, (void FAR* FAR*)&pdisp);

            pCollection->Add(pdisp);

            pdisp->Release();

        }

        pCollection->QueryInterface(IID_IDispatch, (void FAR* FAR*)&pdisp);

        m_pdispProperties = pdisp;

        m_ptinfo->ReleaseTypeAttr(ptypeattr);

    }

    m_pdispProperties->AddRef();

    return (ICollection FAR*)m_pdispProperties;

error:

    if (ptypeattr) m_ptinfo->ReleaseTypeAttr(ptypeattr);

    if (pCollection) delete pCollection;

    if (pvardesc) m_ptinfo->ReleaseVarDesc(pvardesc);

    return NULL;

}


 ENUM.CPP   (BROWSEH OLE Sample)

/*************************************************************************

**

**    OLE Automation TypeLibrary Browse Helper Sample

**

**    enum.cpp

**

**    CEnum implementation

**

**     Written by Microsoft Product Support Services, Windows Developer Support

**    (c) Copyright Microsoft Corp. 1994 All Rights Reserved

**

*************************************************************************/

#include <windows.h>

#include <windowsx.h>

#ifdef WIN16

  #include <ole2.h>

  #include <compobj.h>

  #include <dispatch.h>

  #include <variant.h>

  #include <olenls.h>

#endif

#include "browseh.h"

/*

 * CEnum::Create

 *

 * Purpose:

 *  Creates an instance of the Enum automation object and initializes it.

 *

 * Parameters:

 *  ptinfo    TypeInfo of Enum.

 *  ppEnum    Returns Enum automation object.

 *

 * Return Value:

 *  HRESULT

 *

 */

HRESULT

CEnum::Create(LPTYPEINFO ptinfo, CEnum FAR* FAR* ppEnum)

{

    HRESULT hr;

    CEnum FAR* pEnum = NULL;

    *ppEnum = NULL;

    // Create object.

    pEnum = new CEnum();

    if (pEnum == NULL)

    {

        hr = ResultFromScode(E_OUTOFMEMORY);

        goto error;

    }

    // Load type information for the object from type library.

    hr = pEnum->LoadTypeInfo(IID_IEnum);

    if (FAILED(hr))

        goto error;

    // Ask base class (CTypeInfo) to initialize.

    hr = pEnum->_InitTypeInfo(ptinfo);

    if (FAILED(hr))

        goto error;

    ptinfo->AddRef();

    pEnum->m_ptinfo = ptinfo;

#ifdef _DEBUG

    lstrcpyn(pEnum->m_szClassName, TEXT("Enum"), 100);

#endif

    *ppEnum = pEnum;

    return NOERROR;

error:

    if (pEnum == NULL) return ResultFromScode(E_OUTOFMEMORY);

    if (pEnum->m_ptinfo) pEnum->m_ptinfo->Release();

    // Set to NULL to prevent destructor from attempting to free again

    pEnum->m_ptinfo = NULL;

    delete pEnum;

    return hr;

}

/*

 * CEnum::CEnum

 *

 * Purpose:

 *  Constructor for CEnum object. Initializes members to NULL.

 *

 */

CEnum::CEnum()

{

    m_pdispElements = NULL;

    m_ptinfo = NULL;

}

/*

 * CEnum::~CEnum

 *

 * Purpose:

 *  Destructor for CEnum object.

 *

 */

CEnum::~CEnum()

{

    if (m_pdispElements) m_pdispElements->Release();

    if (m_ptinfo) m_ptinfo->Release();

}

STDMETHODIMP_(REFCLSID)

CEnum::GetInterfaceID()

{

    return IID_IEnum;

}

STDMETHODIMP_(ICollection FAR*)

CEnum::get_Elements()

{

    HRESULT hr;

    CConstant FAR* pConstant;

    CCollection FAR* pCollection = NULL;

    LPDISPATCH pdisp;

    LPVARDESC pvardesc = NULL;

    LPTYPEATTR ptypeattr = NULL;

    unsigned short n;

    if (m_pdispElements == NULL)

    {

        hr = m_ptinfo->GetTypeAttr(&ptypeattr);

        if (FAILED(hr))

            {RaiseException(IDS_Unexpected); return NULL;}

        hr = CCollection::Create(ptypeattr->cVars, 0, &pCollection);

        if (FAILED(hr))

            {RaiseException(IDS_Unexpected); goto error;}

        // Enumerate enum constants and return a collection of these.

        for (n=0; n<ptypeattr->cVars; n++)

        {

            hr = m_ptinfo->GetVarDesc(n, &pvardesc);

            if (FAILED(hr))

                {RaiseException(IDS_Unexpected); goto error;}

            hr = CConstant::Create(m_ptinfo, pvardesc, &pConstant);

            if (FAILED(hr))

                {RaiseException(IDS_Unexpected); goto error;}

            m_ptinfo->ReleaseVarDesc(pvardesc);

            pvardesc = NULL;

            pConstant->QueryInterface(IID_IDispatch, (void FAR* FAR*)&pdisp);

            pCollection->Add(pdisp);

            pdisp->Release();

        }

        pCollection->QueryInterface(IID_IDispatch, (void FAR* FAR*)&pdisp);

        m_pdispElements = pdisp;

        m_ptinfo->ReleaseTypeAttr(ptypeattr);

    }

    m_pdispElements->AddRef();

    return (ICollection FAR*)m_pdispElements;

error:

    if (ptypeattr) m_ptinfo->ReleaseTypeAttr(ptypeattr);

    if (pCollection) delete pCollection;

    if (pvardesc) m_ptinfo->ReleaseVarDesc(pvardesc);

    return NULL;

}


 ENUMVAR.CPP   (BROWSEH OLE Sample)

/*************************************************************************

**

**    OLE Automation TypeLibrary Browse Helper Sample

**

**    enumvar.cpp

**

**    CEnumVariant implementation

**

**     Written by Microsoft Product Support Services, Windows Developer Support

**    (c) Copyright Microsoft Corp. 1994 All Rights Reserved

**

*************************************************************************/

#include <windows.h>

#include <windowsx.h>

#ifdef WIN16

  #include <ole2.h>

  #include <compobj.h>

  #include <dispatch.h>

  #include <variant.h>

  #include <olenls.h>

#endif

#include "browseh.h"

/*

 * CEnumVariant::Create

 *

 * Purpose:

 *  Creates an instance of the IEnumVARIANT enumerator object and initializes it.

 *

 * Parameters:

 *  psa        Safe array containing items to be enumerated.

 *  cElements  Number of items to be enumerated.

 *  ppenumvariant    Returns enumerator object.

 *

 * Return Value:

 *  HRESULT

 *

 */

HRESULT

CEnumVariant::Create(SAFEARRAY FAR* psa, ULONG cElements, CEnumVariant FAR* FAR* ppenumvariant)

{

    HRESULT hr;

    CEnumVariant FAR* penumvariant = NULL;

    long lLBound;

    *ppenumvariant = NULL;

    penumvariant = new CEnumVariant();

    if (penumvariant == NULL)

        goto error;

    penumvariant->m_cRef = 0;

    // Copy elements into safe array that is used in enumerator implemenatation and

    // initialize state of enumerator.

    hr = SafeArrayGetLBound(psa, 1, &lLBound);

    if (FAILED(hr))

        goto error;

    penumvariant->m_cElements = cElements;

    penumvariant->m_lLBound = lLBound;

    penumvariant->m_lCurrent = lLBound;

    hr = SafeArrayCopy(psa, &penumvariant->m_psa);

    if (FAILED(hr))

       goto error;

    *ppenumvariant = penumvariant;

    return NOERROR;

error:

    if (penumvariant == NULL)

        return ResultFromScode(E_OUTOFMEMORY);

    if (penumvariant->m_psa)

        SafeArrayDestroy(penumvariant->m_psa);

    penumvariant->m_psa = NULL;

    delete penumvariant;

    return hr;

}

/*

 * CEnumVariant::CEnumVariant

 *

 * Purpose:

 *  Constructor for CEnumVariant object. Initializes members to NULL.

 *

 */

CEnumVariant::CEnumVariant()

{

    m_psa = NULL;

}

/*

 * CEnumVariant::~CEnumVariant

 *

 * Purpose:

 *  Destructor for CEnumVariant object.

 *

 */

CEnumVariant::~CEnumVariant()

{

    if (m_psa) SafeArrayDestroy(m_psa);

}

/*

 * CEnumVariant::QueryInterface, AddRef, Release

 *

 * Purpose:

 *  Implements IUnknown::QueryInterface, AddRef, Release

 *

 */

STDMETHODIMP

CEnumVariant::QueryInterface(REFIID iid, void FAR* FAR* ppv)

{

    *ppv = NULL;

    if (iid == IID_IUnknown || iid == IID_IEnumVARIANT)

        *ppv = this;

    else return ResultFromScode(E_NOINTERFACE);

    AddRef();

    return NOERROR;

}

STDMETHODIMP_(ULONG)

CEnumVariant::AddRef(void)

{

#ifdef _DEBUG

    TCHAR ach[50];

    wsprintf(ach, TEXT("Ref = %ld, Enum\r\n"), m_cRef+1);

    OutputDebugString(ach);

#endif

    return ++m_cRef;  // AddRef Application Object if enumerator will outlive application object

}

STDMETHODIMP_(ULONG)

CEnumVariant::Release(void)

{

#ifdef _DEBUG

    TCHAR ach[50];

    wsprintf(ach, TEXT("Ref = %ld, Enum\r\n"), m_cRef-1);

    OutputDebugString(ach);

#endif

    if(--m_cRef == 0)

    {

        delete this;

        return 0;

    }

    return m_cRef;

}

/*

 * CEnumVariant::Next

 *

 * Purpose:

 *  Retrieves the next cElements elements. Implements IEnumVARIANT::Next.

 *

 */

STDMETHODIMP

CEnumVariant::Next(ULONG cElements, VARIANT FAR* pvar, ULONG FAR* pcElementFetched)

{

    HRESULT hr;

    ULONG l;

    long l1;

    ULONG l2;

    if (pcElementFetched != NULL)

        *pcElementFetched = 0;

    for (l=0; l<cElements; l++)

        VariantInit(&pvar[l]);

    // Retrieve the next cElements elements.

    for (l1=m_lCurrent, l2=0; l1<(long)(m_lLBound+m_cElements) && l2<cElements; l1++, l2++)

    {

       hr = SafeArrayGetElement(m_psa, &l1, &pvar[l2]);

       if (FAILED(hr))

           goto error;

    }

    // Set count of elements retrieved

    if (pcElementFetched != NULL)

        *pcElementFetched = l2;

    m_lCurrent = l1;

    return  (l2 < cElements) ? ResultFromScode(S_FALSE) : NOERROR;

error:

    for (l=0; l<cElements; l++)

        VariantClear(&pvar[l]);

    return hr;

}

/*

 * CEnumVariant::Skip

 *

 * Purpose:

 *  Skips the next cElements elements. Implements IEnumVARIANT::Skip.

 *

 */

STDMETHODIMP

CEnumVariant::Skip(ULONG cElements)

{

    m_lCurrent += cElements;

    if (m_lCurrent > (long)(m_lLBound+m_cElements))

    {

        m_lCurrent =  m_lLBound+m_cElements;

        return ResultFromScode(S_FALSE);

    }

    else return NOERROR;

}

/*

 * CEnumVariant::Reset

 *

 * Purpose:

 *  Resets the current element in the enumerator to the beginning. Implements IEnumVARIANT::Reset.

 *

 */

STDMETHODIMP

CEnumVariant::Reset()

{

    m_lCurrent = m_lLBound;

    return NOERROR;

}

/*

 * CEnumVariant::Clone

 *

 * Purpose:

 *  Creates a copy of the current enumeration state. Implements IEnumVARIANT::Clone.

 *

 */

STDMETHODIMP

CEnumVariant::Clone(IEnumVARIANT FAR* FAR* ppenum)

{

    CEnumVariant FAR* penum = NULL;

    HRESULT hr;

    *ppenum = NULL;

    hr = CEnumVariant::Create(m_psa, m_cElements, &penum);

    if (FAILED(hr))

        goto error;

    penum->AddRef();

    penum->m_lCurrent = m_lCurrent;

    *ppenum = penum;

    return NOERROR;

error:

    if (penum)

        penum->Release();

    return hr;

}


 FUNCTION.CPP   (BROWSEH OLE Sample)

/*************************************************************************

**

**    OLE Automation TypeLibrary Browse Helper Sample

**

**    function.cpp

**

**    CFunction implementation

**

**     Written by Microsoft Product Support Services, Windows Developer Support

**    (c) Copyright Microsoft Corp. 1994 All Rights Reserved

**

*************************************************************************/

#include <windows.h>

#include <windowsx.h>

#ifdef WIN16

  #include <ole2.h>

  #include <compobj.h>

  #include <dispatch.h>

  #include <variant.h>

  #include <olenls.h>

#endif

#include "browseh.h"

/*

 * CFunction::Create

 *

 * Purpose:

 *  Creates an instance of the Function automation object and initializes it.

 *

 * Parameters:

 *  ptinfo        TypeInfo of which this Function is an element of.

 *  nIndex	      Index of function in containing TypeInfo.

 *  ppFunction    Returns Function automation object.

 *

 * Return Value:

 *  HRESULT

 *

 */

HRESULT

CFunction::Create(LPTYPEINFO ptinfo, unsigned short nIndex, CFunction FAR* FAR* ppFunction)

{

    HRESULT hr;

    CFunction FAR* pFunction = NULL;

    CTypeDesc FAR* pTypeDesc = NULL;

    *ppFunction = NULL;

    // Create object.

    pFunction = new CFunction();

    if (pFunction == NULL)

    {

        hr = ResultFromScode(E_OUTOFMEMORY);

        goto error;

    }

    // Load type information for the application object from type library.

    hr = pFunction->LoadTypeInfo(IID_IFunction);

    if (FAILED(hr))

        goto error;

    hr = ptinfo->GetFuncDesc(nIndex, &pFunction->m_pfuncdesc);

    if (FAILED(hr))

        goto error;

    // Function return type.

    hr = CTypeDesc::Create(ptinfo, &pFunction->m_pfuncdesc->elemdescFunc.tdesc, &pTypeDesc);

    if (FAILED(hr))

        goto error;

    pTypeDesc->QueryInterface(IID_IDispatch, (LPVOID FAR*)&pFunction->m_pdispTypeDesc);

    hr = ptinfo->GetDocumentation(pFunction->m_pfuncdesc->memid, &pFunction->m_bstrName, &pFunction->m_bstrDocumentation,

             &pFunction->m_ulHelpContext, &pFunction->m_bstrHelpFile);

    if (FAILED(hr))

        goto error;

    ptinfo->AddRef();

    pFunction->m_ptinfoFunction = ptinfo;

#ifdef _DEBUG

    lstrcpyn(pFunction->m_szClassName, TEXT("Function"), 100);

#endif

    *ppFunction = pFunction;

    return NOERROR;

error:

    if (pFunction == NULL) return ResultFromScode(E_OUTOFMEMORY);

    if (pFunction->m_pfuncdesc) ptinfo->ReleaseFuncDesc(pFunction->m_pfuncdesc);

    if (pFunction->m_ptinfoFunction) pFunction->m_ptinfoFunction->Release();

    if (pFunction->m_bstrName) SysFreeString(pFunction->m_bstrName);

    if (pFunction->m_bstrDocumentation) SysFreeString(pFunction->m_bstrDocumentation);

    if (pFunction->m_bstrHelpFile) SysFreeString(pFunction->m_bstrHelpFile);

    // Set to NULL to prevent destructor from attempting to free again

    pFunction->m_ptinfoFunction = NULL;

    pFunction->m_pfuncdesc = NULL;

    pFunction->m_bstrName = NULL;

    pFunction->m_bstrDocumentation = NULL;

    pFunction->m_bstrHelpFile = NULL;

    delete pFunction;

    return hr;

}

/*

 * CFunction::CFunction

 *

 * Purpose:

 *  Constructor for CFunction object. Initializes members to NULL.

 *

 */

CFunction::CFunction()

{

    m_bstrName = NULL;

    m_bstrDocumentation = NULL;

    m_bstrHelpFile = NULL;

    m_pdispParameters = NULL;

    m_ptinfoFunction = NULL;

    m_pfuncdesc = NULL;

    m_pdispTypeDesc = NULL;

}

/*

 * CFunction::~CFunction

 *

 * Purpose:

 *  Destructor for CFunction object.

 *

 */

CFunction::~CFunction()

{

     if (m_bstrName) SysFreeString(m_bstrName);

     if (m_bstrDocumentation) SysFreeString(m_bstrDocumentation);

     if (m_bstrHelpFile) SysFreeString(m_bstrHelpFile);

     if (m_pdispParameters) m_pdispParameters->Release();

     if (m_pfuncdesc && m_ptinfoFunction) m_ptinfoFunction->ReleaseFuncDesc(m_pfuncdesc);

     if (m_ptinfoFunction) m_ptinfoFunction->Release();

     if (m_pdispTypeDesc) m_pdispTypeDesc->Release();

}

STDMETHODIMP_(REFCLSID)

CFunction::GetInterfaceID()

{

    return IID_IFunction;

}

STDMETHODIMP_(BSTR)

CFunction::get_Name()

{

    return SysAllocString(m_bstrName);

}

STDMETHODIMP_(BSTR)

CFunction::get_Documentation()

{

    return SysAllocString(m_bstrDocumentation);

}

STDMETHODIMP_(long)

CFunction::get_HelpContext()

{

    return (long)m_ulHelpContext;

}

STDMETHODIMP_(BSTR)

CFunction::get_HelpFile()

{

    return SysAllocString(m_bstrHelpFile);

}

STDMETHODIMP_(ITypeDesc FAR*)

CFunction::get_ReturnType()

{

    m_pdispTypeDesc->AddRef();

    return (ITypeDesc FAR*)m_pdispTypeDesc;

}

STDMETHODIMP_(ICollection FAR*)

CFunction::get_Parameters()

{

    HRESULT hr;

    CParameter FAR* pParameter;

    CCollection FAR* pCollection = NULL;

    LPDISPATCH pdisp;

    BSTR FAR* rgbstrNames = NULL;

    unsigned int cNames;

    unsigned short n = 0;

    if (m_pdispParameters == NULL)

    {

        // Create a collection of parameters and return it.

        rgbstrNames = new BSTR[m_pfuncdesc->cParams+1];

        if (rgbstrNames == NULL)

            {RaiseException(IDS_OutOfMemory); return NULL;}

        hr = m_ptinfoFunction->GetNames(m_pfuncdesc->memid, rgbstrNames, m_pfuncdesc->cParams+1, &cNames);

        if (FAILED(hr))

            {RaiseException(IDS_Unexpected); goto error;}

        SysFreeString(rgbstrNames[0]);

        hr = CCollection::Create(cNames-1, 0, &pCollection);

        if (FAILED(hr))

            {RaiseException(IDS_Unexpected); goto error;}

        for (n=0; n<cNames-1; n++)

        {

            hr = CParameter::Create(m_ptinfoFunction, rgbstrNames[n+1],

                   &m_pfuncdesc->lprgelemdescParam[n].tdesc,

                   &m_pfuncdesc->lprgelemdescParam[n].idldesc,

                   &pParameter);

            if (FAILED(hr))

                {RaiseException(IDS_Unexpected); goto error;}

            SysFreeString(rgbstrNames[n+1]);

            pParameter->QueryInterface(IID_IDispatch, (void FAR* FAR*)&pdisp);

            pCollection->Add(pdisp);

            pdisp->Release();

        }

        pCollection->QueryInterface(IID_IDispatch, (void FAR* FAR*)&pdisp);

        m_pdispParameters = pdisp;

        delete rgbstrNames;

    }

    m_pdispParameters->AddRef();

    return (ICollection FAR*)m_pdispParameters;

error:

    if (pCollection) delete pCollection;

    if (rgbstrNames)

        for (; n<cNames-1; n++)

            SysFreeString(rgbstrNames[n+1]);

    return NULL;

}

STDMETHODIMP_(MEMBERID)

CFunction::get_Memberid()

{

    return m_pfuncdesc->memid;

}

STDMETHODIMP_(CALLCONV)

CFunction::get_CallConvention()

{

    return m_pfuncdesc->callconv;

}

STDMETHODIMP_(FUNCKIND)

CFunction::get_FuncKind()

{

    return m_pfuncdesc->funckind;

}

STDMETHODIMP_(INVOKEKIND)

CFunction::get_InvocationKind()

{

    return m_pfuncdesc->invkind;

}

STDMETHODIMP_(OBJTYPE)

CFunction::get_Kind()

{

    return TYPE_FUNCTION;

}


 INTFACE.CPP   (BROWSEH OLE Sample)

/*************************************************************************

**

**    OLE Automation TypeLibrary Browse Helper Sample

**

**    intface.cpp

**

**    CInterface implementation

**

**     Written by Microsoft Product Support Services, Windows Developer Support

**    (c) Copyright Microsoft Corp. 1994 All Rights Reserved

**

*************************************************************************/

#include <windows.h>

#include <windowsx.h>

#ifdef WIN16

  #include <ole2.h>

  #include <compobj.h>

  #include <dispatch.h>

  #include <variant.h>

  #include <olenls.h>

#endif

#include "browseh.h"

/*

 * CInterface::Create

 *

 * Purpose:

 *  Creates an instance of the Interface automation object and initializes it.

 *

 * Parameters:

 *  ptinfo         TypeInfo of interface.

 *  ppInterface    Returns Interface automation object.

 *

 * Return Value:

 *  HRESULT

 *

 */

HRESULT

CInterface::Create(LPTYPEINFO ptinfo, CInterface FAR* FAR* ppInterface)

{

    HRESULT hr;

    CInterface FAR* pInterface = NULL;

    *ppInterface = NULL;

    // Create object.

    pInterface = new CInterface();

    if (pInterface == NULL)

    {

        hr = ResultFromScode(E_OUTOFMEMORY);

        goto error;

    }

    // Load type information for the object from type library.

    hr = pInterface->LoadTypeInfo(IID_IInterface);

    if (FAILED(hr))

        goto error;

    // Intialize base class, CTypeInfo

    hr = pInterface->_InitTypeInfo(ptinfo);

    if (FAILED(hr))

        goto error;

    ptinfo->AddRef();

    pInterface->m_ptinfo = ptinfo;

#ifdef _DEBUG

    lstrcpyn(pInterface->m_szClassName, TEXT("Interface"), 100);

#endif

    *ppInterface = pInterface;

    return NOERROR;

error:

    if (pInterface == NULL) return ResultFromScode(E_OUTOFMEMORY);

    if (pInterface->m_ptinfo) pInterface->m_ptinfo->Release();

    // Set to NULL to prevent destructor from attempting to free again

    pInterface->m_ptinfo = NULL;

    delete pInterface;

    return hr;

}

/*

 * CInterface::CInterface

 *

 * Purpose:

 *  Constructor for CInterface object. Initializes members to NULL.

 *

 */

CInterface::CInterface()

{

    m_pdispFunctions = NULL;

    m_ptinfo = NULL;

}

/*

 * CInterface::~CInterface

 *

 * Purpose:

 *  Destructor for CInterface object.

 *

 */

CInterface::~CInterface()

{

    if (m_pdispFunctions) m_pdispFunctions->Release();

    if (m_ptinfo) m_ptinfo->Release();

}

STDMETHODIMP_(REFCLSID)

CInterface::GetInterfaceID()

{

    return IID_IInterface;

}

STDMETHODIMP_(ICollection FAR*)

CInterface::get_Functions()

{

    HRESULT hr;

    CFunction FAR* pFunction;

    CCollection FAR* pCollection = NULL;

    LPDISPATCH pdisp;

    LPTYPEATTR ptypeattr = NULL;

    unsigned short n;

    if (m_pdispFunctions == NULL)

    {

        // Create collection of functions in interface.

        hr = m_ptinfo->GetTypeAttr(&ptypeattr);

        if (FAILED(hr))

            {RaiseException(IDS_Unexpected); return NULL;}

        hr = CCollection::Create(ptypeattr->cFuncs, 0, &pCollection);

        if (FAILED(hr))

            {RaiseException(IDS_Unexpected); goto error;}

        for (n=0; n<ptypeattr->cFuncs; n++)

        {

            hr = CFunction::Create(m_ptinfo, n, &pFunction);

            if (FAILED(hr))

                {RaiseException(IDS_Unexpected); goto error;}

            pFunction->QueryInterface(IID_IDispatch, (void FAR* FAR*)&pdisp);

            pCollection->Add(pdisp);

            pdisp->Release();

        }

        pCollection->QueryInterface(IID_IDispatch, (void FAR* FAR*)&pdisp);

        m_pdispFunctions = pdisp;

        m_ptinfo->ReleaseTypeAttr(ptypeattr);

    }

    m_pdispFunctions->AddRef();

    return (ICollection FAR*)m_pdispFunctions;

error:

    if (ptypeattr) m_ptinfo->ReleaseTypeAttr(ptypeattr);

    if (pCollection) delete pCollection;

    return NULL;

}


 MAIN.CPP   (BROWSEH OLE Sample)

/*************************************************************************

**

**    OLE Automation TypeLibrary Browse Helper Sample

**

**    main.cpp

**

**    new and delete operator redefinition to use memory manager of calling

**    task.

**    LibMain, WEP, DllGetClassObject, DllCanUnloadNow, DLL initialization.

**    Procedure to create standard dispatch implementation.

**

**     Written by Microsoft Product Support Services, Windows Developer Support

**    (c) Copyright Microsoft Corp. 1994 All Rights Reserved

**

*************************************************************************/

#include <windows.h>

#include <windowsx.h>

#ifdef WIN16

  #include <ole2.h>

  #include <compobj.h>

  #include <dispatch.h>

  #include <variant.h>

  #include <olenls.h>

#endif

#include <initguid.h>

#include "browseh.h"

// Globals

HINSTANCE   g_hinst;                   // Instance of application

                                       //Count number of objects and number of locks.

ULONG       g_cObj=0;

ULONG       g_cLock=0;

// String resource buffers

TCHAR g_szServerName[STR_LEN];

/*

 * new

 *

 * Purpose:

 *   Since this is an InProcServer object, the memory allocator used by

 *   the calling task must be used.

 *   This is done by redefining the global new operator and using new

 *   for all memory allocations.

 */

void FAR* operator new(size_t size)

{

    IMalloc FAR* pMalloc;

    LPVOID lpv;

    if (CoGetMalloc(MEMCTX_TASK, &pMalloc) == NOERROR)

    {

        lpv = pMalloc->Alloc(size);

        pMalloc->Release();

        return lpv;

    }

    return NULL;

}

/*

 * delete

 *

 * Purpose:

 *   Use the memory manager of the calling task to free memory.

 */

void operator delete(void FAR* lpv)

{

    IMalloc FAR* pMalloc;

    if (lpv == NULL) return;

    if( CoGetMalloc(MEMCTX_TASK, &pMalloc) == NOERROR)

    {

        if (pMalloc->DidAlloc(lpv))

            pMalloc->Free(lpv);

        pMalloc->Release();

    }

}

#ifdef WIN16

/*

 * LibMain

 *

 * Purpose:

 *  Called by Win16 on DLL load. Does any one-time initializations.

 *

 */

int PASCAL LibMain (HINSTANCE hinst, WORD wDataSeg, WORD cbHeapSize, LPSTR lpCmdLine)

{

   if (cbHeapSize != 0)

       UnlockData(0);

   g_hinst = hinst;

   if (!InitDLL(hinst))

         return FALSE;

   return TRUE;

}

/*

 * WEP

 *

 * Purpose:

 *  Called by Windows on DLL unload.

 *

 */

extern "C" void FAR PASCAL _WEP(int bSystemExit)

{

    return;

}

#else //Win 32

BOOL WINAPI DllMain (HINSTANCE hinst, DWORD dwReason, LPVOID lpReserved)

{

    switch (dwReason)

    {

        case DLL_PROCESS_ATTACH:

            if (!InitDLL(hinst))

                return FALSE;

    else return TRUE;

    	default:

    return TRUE;

    }

}

#endif

/*

 * DLLGetClassObject

 *

 * Purpose:

 *  OLE calls this funtion to obtain the class factory. Note that the class

 *  factory is not registered by the inproc server.

 *

 */

STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid,

                                   LPVOID FAR *ppv)

{

    LPCLASSFACTORY pcf;

    HRESULT hr;

    *ppv =  NULL;

    // Check if this CLSID is supported.

    if (rclsid != CLSID_BrowseHelper)

       return ResultFromScode(E_FAIL);

    // Create class factory and return it

    pcf = new CBrowseHelperCF;

    if (!pcf)

        return ResultFromScode(E_OUTOFMEMORY);

    hr = pcf->QueryInterface(riid, ppv);

    if (FAILED(hr))

    {

        delete pcf;

        return hr;

    }

    return NOERROR;

}

/*

 * DLLCanUnloadNow

 *

 * Purpose:

 *  DllCanUnloadNow is called by OLE to determine if the DLL can be unloded.

 *

 */

STDAPI DllCanUnloadNow(void)

{

    if (g_cObj==0L && g_cLock==0L)

        return ResultFromScode(S_OK);

    else return ResultFromScode(S_FALSE);

}

/*

 * InitDLL

 *

 * Purpose:

 *  Load strings & Registers the window class

 *

 * Parameters:

 *  hinstance       hinstance of application

 *

 */

BOOL InitDLL (HINSTANCE hinst)

{

   return LoadString(hinst, IDS_SERVERNAME, g_szServerName, sizeof(g_szServerName));

}


 MODULE.CPP   (BROWSEH OLE Sample)

/*************************************************************************

**

**    OLE Automation TypeLibrary Browse Helper Sample

**

**    module.cpp

**

**    CModule implementation

**

**     Written by Microsoft Product Support Services, Windows Developer Support

**    (c) Copyright Microsoft Corp. 1994 All Rights Reserved

**

*************************************************************************/

#include <windows.h>

#include <windowsx.h>

#ifdef WIN16

  #include <ole2.h>

  #include <compobj.h>

  #include <dispatch.h>

  #include <variant.h>

  #include <olenls.h>

#endif

#include "browseh.h"

/*

 * CModule::Create

 *

 * Purpose:

 *  Creates an instance of the Module automation object and initializes it.

 *

 * Parameters:

 *  ptinfo      TypeInfo of module.

 *  ppModule    Returns Module automation object.

 *

 * Return Value:

 *  HRESULT

 *

 */

HRESULT

CModule::Create(LPTYPEINFO ptinfo, CModule FAR* FAR* ppModule)

{

    HRESULT hr;

    CModule FAR* pModule = NULL;

    *ppModule = NULL;

    // Create object.

    pModule = new CModule();

    if (pModule == NULL)

    {

        hr = ResultFromScode(E_OUTOFMEMORY);

        goto error;

    }

    // Load type information for the object from type library.

    hr = pModule->LoadTypeInfo(IID_IModule);

    if (FAILED(hr))

        goto error;

    // Intialize base class, CTypeInfo

    hr = pModule->_InitTypeInfo(ptinfo);

    if (FAILED(hr))

        goto error;

    ptinfo->AddRef();

    pModule->m_ptinfo = ptinfo;

#ifdef _DEBUG

    lstrcpyn(pModule->m_szClassName, TEXT("Module"), 100);

#endif

    *ppModule = pModule;

    return NOERROR;

error:

    if (pModule == NULL) return ResultFromScode(E_OUTOFMEMORY);

    if (pModule->m_ptinfo) pModule->m_ptinfo->Release();

    // Set to NULL to prevent destructor from attempting to free again

    pModule->m_ptinfo = NULL;

    delete pModule;

    return hr;

}

/*

 * CModule::CModule

 *

 * Purpose:

 *  Constructor for CModule object. Initializes members to NULL.

 *

 */

CModule::CModule()

{

    m_pdispFunctions = NULL;

    m_ptinfo = NULL;

}

/*

 * CModule::~CModule

 *

 * Purpose:

 *  Destructor for CModule object.

 *

 */

CModule::~CModule()

{

    if (m_pdispFunctions) m_pdispFunctions->Release();

    if (m_ptinfo) m_ptinfo->Release();

}

STDMETHODIMP_(REFCLSID)

CModule::GetInterfaceID()

{

    return IID_IModule;

}

STDMETHODIMP_(ICollection FAR*)

CModule::get_Functions()

{

    HRESULT hr;

    CFunction FAR* pFunction;

    CCollection FAR* pCollection = NULL;

    LPDISPATCH pdisp;

    LPTYPEATTR ptypeattr = NULL;

    unsigned short n;

    if (m_pdispFunctions == NULL)

    {

        // Create collection of functions of the interface.

        hr = m_ptinfo->GetTypeAttr(&ptypeattr);

        if (FAILED(hr))

            {RaiseException(IDS_Unexpected); return NULL;}

        hr = CCollection::Create(ptypeattr->cFuncs, 0, &pCollection);

        if (FAILED(hr))

            {RaiseException(IDS_Unexpected); goto error;}

        for (n=0; n<ptypeattr->cFuncs; n++)

        {

            hr = CFunction::Create(m_ptinfo, n, &pFunction);

            if (FAILED(hr))

                {RaiseException(IDS_Unexpected); goto error;}

            pFunction->QueryInterface(IID_IDispatch, (void FAR* FAR*)&pdisp);

            pCollection->Add(pdisp);

            pdisp->Release();

        }

        pCollection->QueryInterface(IID_IDispatch, (void FAR* FAR*)&pdisp);

        m_pdispFunctions = pdisp;

        m_ptinfo->ReleaseTypeAttr(ptypeattr);

    }

    m_pdispFunctions->AddRef();

    return (ICollection FAR*)m_pdispFunctions;

error:

    if (ptypeattr) m_ptinfo->ReleaseTypeAttr(ptypeattr);

    if (pCollection) delete pCollection;

    return NULL;

}


 MYDISP.CPP   (BROWSEH OLE Sample)

/*************************************************************************

**

**    OLE Automation TypeLibrary Browse Helper Sample

**

**    mydisp.cpp

**

**    CMyDispatch implementation

**

**     Written by Microsoft Product Support Services, Windows Developer Support

**    (c) Copyright Microsoft Corp. 1994 All Rights Reserved

**

**    The CMyDispatch object implement IUnknown & IDispatch for all the automation

**    objects in this sample. All objects derive from CMyDispatch.

**

*************************************************************************/

#include <windows.h>

#include <windowsx.h>

#ifdef WIN16

  #include <ole2.h>

  #include <compobj.h>

  #include <dispatch.h>

  #include <variant.h>

  #include <olenls.h>

#endif

#include "browseh.h"

/*

 * CMyDispatch::CMyDispatch

 *

 * Purpose:

 *  Constructor for CMyDispatch object. Initializes members to NULL.

 *

 */

CMyDispatch::CMyDispatch()

{

    m_ptinfo = NULL;

    m_cRef = 0;

}

/*

 * CMyDispatch::~CMyDispatch

 *

 * Purpose:

 *  Destructor for CMyDispatch object.

 *

 */

CMyDispatch::~CMyDispatch()

{

     if (m_ptinfo) m_ptinfo->Release();

}

/*

 * CMyDispatch::QueryInterface, AddRef, Release

 *

 * Purpose:

 *  Implements IUnknown::QueryInterface, AddRef, Release

 *

 */

STDMETHODIMP

CMyDispatch::QueryInterface(REFIID iid, void FAR* FAR* ppv)

{

    *ppv = NULL;

    if (iid == IID_IUnknown)

        *ppv = this;

    else if (iid == IID_IDispatch)

        *ppv = this;

    else if (iid == GetInterfaceID())

        *ppv = this;

    else return ResultFromScode(E_NOINTERFACE);

    AddRef();

    return NOERROR;

}

STDMETHODIMP_(ULONG)

CMyDispatch::AddRef(void)

{

#ifdef _DEBUG

    TCHAR ach[150];

    wsprintf(ach, TEXT("Ref = %ld, Object = %s\r\n"), m_cRef+1, m_szClassName);

    OutputDebugString(ach);

#endif

    return ++m_cRef;

}

STDMETHODIMP_(ULONG)

CMyDispatch::Release(void)

{

#ifdef _DEBUG

    TCHAR ach[150];

    wsprintf(ach, TEXT("Ref = %ld, Object = %s\r\n"), m_cRef-1, m_szClassName);

    OutputDebugString(ach);

#endif

    if(--m_cRef == 0)

    {

        delete this;

        return 0;

    }

    return m_cRef;

}

/*

 * CMyDispatch::GetTypeInfoCount

 *

 * Purpose:

 *  Implements IDispatch::GetTypeInfoCount.

 *

 */

STDMETHODIMP

CMyDispatch::GetTypeInfoCount(UINT FAR* pctinfo)

{

    *pctinfo = 1;

    return NOERROR;

}

/*

 * CMyDispatch::GetTypeInfo

 *

 * Purpose:

 *  Implements IDispatch::GetTypeInfo.

 *

 */

STDMETHODIMP

CMyDispatch::GetTypeInfo(

      UINT itinfo,

      LCID lcid,

      ITypeInfo FAR* FAR* pptinfo)

{

    *pptinfo = NULL;

    if(itinfo != 0)

        return ResultFromScode(DISP_E_BADINDEX);

    m_ptinfo->AddRef();

    *pptinfo = m_ptinfo;

    return NOERROR;

}

/*

 * CMyDispatch::GetIDsOfNames

 *

 * Purpose:

 *  Implements IDispatch::GetIDsOfNames.  The standard implementation, DispGetIDsOfNames,

 *  is used.

 *

 */

STDMETHODIMP

CMyDispatch::GetIDsOfNames(

      REFIID riid,

      OLECHAR FAR* FAR* rgszNames,

      UINT cNames,

      LCID lcid,

      DISPID FAR* rgdispid)

{

    return DispGetIDsOfNames(m_ptinfo, rgszNames, cNames, rgdispid);

}

/*

 * CMyDispatch::Invoke

 *

 * Purpose:

 *  Implements IDispatch::Invoke.  The standard implementation, DispInvoke,

 *  is used. Properties and methods  will

 *  set m_bRaiseException to raise an exception.

 *

 */

STDMETHODIMP

CMyDispatch::Invoke(

      DISPID dispidMember,

      REFIID riid,

      LCID lcid,

      WORD wFlags,

      DISPPARAMS FAR* pdispparams,

      VARIANT FAR* pvarResult,

      EXCEPINFO FAR* pexcepinfo,

      UINT FAR* puArgErr)

{

    HRESULT hr;

    m_bRaiseException = FALSE;

    hr =  DispInvoke(

        this, m_ptinfo,

        dispidMember, wFlags, pdispparams,

        pvarResult, pexcepinfo, puArgErr);

    if (m_bRaiseException)

    {

       if (NULL != pexcepinfo)

           _fmemcpy(pexcepinfo, &m_excepinfo, sizeof(EXCEPINFO));

       return ResultFromScode(DISP_E_EXCEPTION);

    }

    else return hr;

}

/*

 * CMyDispatch::LoadTypeInfo

 *

 *  Purpose:

 *   Gets type information of an object's interface from type library.

 *

 * Parameters:

 *  clsid               Interface id of object in type library.

 *

 * Return Value:

 *  HRESULT

 *

 */

STDMETHODIMP

CMyDispatch::LoadTypeInfo(REFCLSID clsid)

{

    HRESULT hr;

    LPTYPELIB ptlib = NULL;

    LPTYPEINFO ptinfo = NULL;

    // Load Type Library. If required, notify user on failure.

    hr = LoadRegTypeLib(LIBID_BrowseHelper, 1, 0, 0x0409, &ptlib);

    if (FAILED(hr))

        return hr;

    // Get type information for interface of the object.

    hr = ptlib->GetTypeInfoOfGuid(clsid, &ptinfo);

    if (FAILED(hr))

    {

        ptlib->Release();

        return hr;

    }

    ptlib->Release();

    m_ptinfo = ptinfo;

    return NOERROR;

}

/*

 * CMyDispatch::RaiseException

 *

 *  Purpose:

 *   Raises exception so CMyDispatch::Invoke will return DISP_E_EXCEPTION

 *

 * Parameters:

 *  nID               ID of exception to be raised.

 *

 */

STDMETHODIMP_(void)

CMyDispatch::RaiseException(int nID)

{

    extern HINSTANCE g_hinst;

    extern TCHAR g_szServerName[];

    TCHAR szError[STR_LEN];

    _fmemset(&m_excepinfo, 0, sizeof(EXCEPINFO));

    m_excepinfo.wCode = nID;

    if (LoadString(g_hinst, nID, szError, sizeof(szError)))

        m_excepinfo.bstrDescription = SysAllocString(TO_OLE_STRING(szError));

    m_excepinfo.bstrSource = SysAllocString(TO_OLE_STRING(g_szServerName));

    m_bRaiseException = TRUE;

}


 PARAM.CPP   (BROWSEH OLE Sample)

/*************************************************************************

**

**    OLE Automation TypeLibrary Browse Helper Sample

**

**    param.cpp

**

**    CParameter implementation

**

**     Written by Microsoft Product Support Services, Windows Developer Support

**    (c) Copyright Microsoft Corp. 1994 All Rights Reserved

**

*************************************************************************/

#include <windows.h>

#include <windowsx.h>

#ifdef WIN16

  #include <ole2.h>

  #include <compobj.h>

  #include <dispatch.h>

  #include <variant.h>

  #include <olenls.h>

#endif

#include "browseh.h"

/*

 * CParameter::Create

 *

 * Purpose:

 *  Creates an instance of the Parameter automation object and initializes it.

 *

 * Parameters:

 *  ptinfo         TypeInfo in which the function of this parameter is contained.

 *  bstrName       Name of parameter

 *  ptypedesc      Type of parameter.

 *  pidldesc       IDLDESC of parameter.

 *  ppParameter    Returns Parameter automation object.

 *

 * Return Value:

 *  HRESULT

 *

 */

HRESULT

CParameter::Create(LPTYPEINFO ptinfo, BSTR bstrName, TYPEDESC FAR* ptypedesc,

     IDLDESC FAR* pidldesc, CParameter FAR* FAR* ppParameter)

{

    HRESULT hr;

    CParameter FAR* pParameter = NULL;

    CTypeDesc FAR* pTypeDesc = NULL;

    *ppParameter = NULL;

    // Create object.

    pParameter = new CParameter();

    if (pParameter == NULL)

    {

        hr = ResultFromScode(E_OUTOFMEMORY);

        goto error;

    }

   // Load type information for the object from type library.

    hr = pParameter->LoadTypeInfo(IID_IParameter);

    if (FAILED(hr))

        goto error;

    pParameter->m_bstrName = SysAllocString(bstrName);

    // Parameter type.

    hr = CTypeDesc::Create(ptinfo, ptypedesc, &pTypeDesc);

    if (FAILED(hr))

        goto error;

    pTypeDesc->QueryInterface(IID_IDispatch, (LPVOID FAR*)&pParameter->m_pdispTypeDesc);

    pParameter->m_wIDLFlags = pidldesc->wIDLFlags;

#ifdef _DEBUG

    lstrcpyn(pParameter->m_szClassName, TEXT("Parameter"), 100);

#endif

    *ppParameter = pParameter;

    return NOERROR;

error:

    if (pParameter == NULL) return ResultFromScode(E_OUTOFMEMORY);

    delete pParameter;

    return hr;

}

/*

 * CParameter::CParameter

 *

 * Purpose:

 *  Constructor for CParameter object. Initializes members to NULL.

 *

 */

CParameter::CParameter()

{

    m_bstrName = NULL;

    m_pdispTypeDesc = NULL;

}

/*

 * CParameter::~CParameter

 *

 * Purpose:

 *  Destructor for CParameter object.

 *

 */

CParameter::~CParameter()

{

     if (m_bstrName) SysFreeString(m_bstrName);

     if (m_pdispTypeDesc) m_pdispTypeDesc->Release();

}

STDMETHODIMP_(REFCLSID)

CParameter::GetInterfaceID()

{

    return IID_IParameter;

}

STDMETHODIMP_(BSTR)

CParameter::get_Name()

{

    return SysAllocString(m_bstrName);

}

STDMETHODIMP_(ITypeDesc FAR*)

CParameter::get_Type()

{

    m_pdispTypeDesc->AddRef();

    return (ITypeDesc FAR*)m_pdispTypeDesc;

}

STDMETHODIMP_(int)

CParameter::get_IDLFlags()

{

    return (int)m_wIDLFlags;

}

STDMETHODIMP_(OBJTYPE)

CParameter::get_Kind()

{

    return TYPE_PARAMETER;

}


 HELLCTRL

HELLCTRL is a vtable binding automation controller that controls the HELLO 2.0 sample.

HELLCTRL uses CoCreateInstance to create an instance of Hello and  obtains its IHello interface using QueryInterface. It then  calls the methods of the IHello interface to access the properties and methods of the Hello object. Rich Error Information is obtained by accessing the IErrorInfo interface.

FILES: ------

tlb.h File copied from the HELLO 2.0 sample. This file was

      generated by mktyplib in the HELLO 2.0 sample.

hellctrl.cpp, hellctrl.h Controller source files.

TO RUN: -------

Select the CreateHello menu after registering the HELLO 2.0 sample. This was launch Hello invisibly. Use the SetVisible menu to make it visible.


 MAKEFILE   (HELLCTRL OLE Sample)

####

#makefile - makefile for browse.exe

#

#       Copyright (C) 1994, Microsoft Corporation

#

#Purpose:

#  Builds the OLE 2.0 Automation controller, browse.exe.

#

#

#  Usage: NMAKE                 ; build with defaults

#     or: NMAKE option          ; build with the given option(s)

#     or: NMAKE clean           ; erase all compiled files

#

#     option: dev = [win16 | win32]    ; dev=win32 is the default

#             DEBUG=[0 | 1]            ; DEBUG=1 is the default

#             HOST=[DOS | NT | WIN95]  ; HOST=DOS (for win16)

#                                      ; HOST=NT (for win32 on NT)

#                                      ; HOST=WIN95 (for win32 on Win95)

#

#Notes:

#  This makefile assumes that the PATH, INCLUDE and LIB environment

#  variables are setup properly.

#

##############################################################################

##########################################################################

#

# Default Settings

#

CPU = i386

!if "$(dev)" == ""

dev = win32

HOST = NT

!endif

!if !("$(dev)" == "win16" || "$(dev)" == "win32")

!error Invalid dev option, choose from [win16 | win32]

!endif

!if "$(dev)" == "win16"

TARGET  = WIN16

!if "$(HOST)" == ""

HOST  = DOS

!endif

!endif

!if "$(dev)" == "win32"

TARGET  = WIN32

!if "$(HOST)" == ""

HOST  = NT

!endif

!endif

!ifdef NODEBUG

DEBUG = 0

!endif

!if "$(DEBUG)" == "0"

NODEBUG = 1

!endif

!if "$(DEBUG)" == ""

DEBUG = 1

!endif

##########################################################################

#

# WIN16 Settings

#

!if "$(TARGET)" == "WIN16"

CC   = cl

LINK = link

!if "$(HOST)" == "DOS"

WX   = wx /w

!else

WX   =

!endif

RCFLAGS = -dWIN16

CFLAGS = -c -W3 -AM -GA -GEs -DWIN16

LINKFLAGS = /NOD /NOI /BATCH /ONERROR:NOEXE

LIBS = libw.lib mlibcew.lib

!if "$(DEBUG)" == "1"

CFLAGS = $(CFLAGS) -Od -Zi -D_DEBUG $(CL)

LINKFLAGS = $(LINKFLAGS) /COD

!else

CFLAGS = $(CFLAGS) -Ox $(CL)

LINKFLAGS = $(LINKFLAGS) /FAR /PACKC

!endif

!endif

##########################################################################

#

# WIN32 Settings

#

!if "$(TARGET)" == "WIN32"

WX =

!include <ntwin32.mak>

CC = $(cc)

CFLAGS = $(cflags) $(cvarsmt) -DINC_OLE2 $(cdebug)

!if "$(HOST)" == "NT"

CFLAGS = $(CFLAGS) -DUNICODE

!endif

!ifndef NODEBUG

CFLAGS = $(CFLAGS) -D_DEBUG

!endif

LINK = $(link)

LINKFLAGS = $(linkdebug) $(guilflags)

RCFLAGS = -DWIN32

!endif

##########################################################################

#

# Build rules

#

.cpp.obj:

    @echo Compiling $<...

    $(CC) $<

.c.obj:

    @echo Compiling $<...

    $(CC) $<

##########################################################################

#

# Application Settings

#

APPS = hellctrl

!if "$(TARGET)" == "WIN16"

LIBS = commdlg.lib ole2.lib compobj.lib ole2disp.lib typelib.lib $(LIBS)

!endif

!if "$(TARGET)" == "WIN32"

LIBS = $(ole2libsmt)

!endif

OBJS = hellctrl.obj

##########################################################################

#

# Default Goal

#

goal : setflags $(APPS).exe

setflags :

    set CL=$(CFLAGS)

##########################################################################

#

# Clean (erase) generated files

#

clean :

    if exist *.obj       del *.obj

    if exist $(APPS).exe del $(APPS).exe

    if exist $(APPS).map del $(APPS).map

    if exist $(APPS).res del $(APPS).res

    if exist *.pdb       del *.pdb

##########################################################################

#

# Application Build (WIN16 Specific)

#

!if "$(TARGET)" == "WIN16"

$(APPS).exe : $(OBJS) $(APPS).def $(APPS).res $(APPS).ico

    link $(LINKFLAGS) @<<

$(OBJS),

$@,,

$(LIBS),

$(APPS).def

<<

    rc -k -t $(APPS).res $@

!endif

##########################################################################

#

# Application Build (WIN32 Specific)

#

!if "$(TARGET)" == "WIN32"

$(APPS).exe : $(OBJS) $(APPS).def $(APPS).res $(APPS).ico

      $(LINK) @<<

        $(LINKFLAGS)

        -out:$@

        -map:$*.map

        $(OBJS)

        $(APPS).res

        $(LIBS)

<<

!endif

##########################################################################

#

# Application Build (Common)

#

$(APPS).res : $(APPS).rc

    rc $(RCFLAGS) -r -fo$@ $?

##########################################################################

#

# Dependencies

#

hellctrl.obj : hellctrl.cpp hellctrl.h tlb.h

     $(CC) hellctrl.cpp


 HELLCTRL.H   (HELLCTRL OLE Sample)

#ifdef WIN32

#ifdef UNICODE

    #define FROM_OLE_STRING(str) str

    #define TO_OLE_STRING(str) str

#else

    #define FROM_OLE_STRING(str) ConvertToAnsi(str)

    char* ConvertToAnsi(OLECHAR FAR* szW);

    #define TO_OLE_STRING(str) ConvertToUnicode(str)

    OLECHAR* ConvertToUnicode(char FAR* szA);

    // Maximum length of string that can be converted between Ansi & Unicode

    #define STRCONVERT_MAXLEN 500

#endif

#else  // WIN16

  #define APIENTRY far pascal

  #define TCHAR char

  #define TEXT(sz) sz

  #define FROM_OLE_STRING(str) str

  #define TO_OLE_STRING(str) str

  #define LPTSTR LPSTR

  #define LPCTSTR LPCSTR

  // Windows NT defines the following in windowsx.h

  #define GET_WM_COMMAND_ID(w,l) (w)

  #define GET_WM_COMMAND_CMD(w,l) HIWORD(l)

  #define GET_WM_COMMAND_HWND(w,l) LOWORD(l)

#endif

// Menu-item IDs

#define IDM_CREATEHELLO  300

#define IDM_SETVISIBLE   301

#define IDM_SETINVISIBLE   302

#define IDM_GETHELLOMESSAGE   303

#define IDM_SAYHELLO  304

#define IDM_RELEASEHELLO 305

// MAX len of string table entries

#define STR_LEN   100

// String table constants

#define IDS_PROGNAME                   1

#define IDS_RESULT                     2

#define IDS_ERROR                      3

// Function prototypes

int PASCAL WinMain (HINSTANCE, HINSTANCE, LPSTR, int);

BOOL InitApplication (HINSTANCE);

BOOL InitInstance (HINSTANCE, int);

void DisplayError(IHello FAR* phello);

#ifdef WIN16

LRESULT __export CALLBACK MainWndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

#else

LRESULT CALLBACK MainWndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

#endif


 RESOURCE.H   (HELLCTRL OLE Sample)

//{{NO_DEPENDENCIES}}

// Microsoft Visual C++ generated include file.

// Used by hellctrl.ico

//

#define IDI_ICON1                       101

// Next default values for new objects

//

#ifdef APSTUDIO_INVOKED

#ifndef APSTUDIO_READONLY_SYMBOLS

#define _APS_NEXT_RESOURCE_VALUE        102

#define _APS_NEXT_COMMAND_VALUE         40001

#define _APS_NEXT_CONTROL_VALUE         1000

#define _APS_NEXT_SYMED_VALUE           101

#endif

#endif


 TLB.H   (HELLCTRL OLE Sample)

/* This header file machine-generated by mktyplib.exe */

/* Interface to type library: Hello */

#ifndef _Hello_H_

#define _Hello_H_

DEFINE_GUID(LIBID_Hello,0xF37C8060,0x4AD5,0x101B,0xB8,0x26,0x00,0xDD,0x01,0x10,0x3D,0xE1);

DEFINE_GUID(IID_IHello,0xF37C8062,0x4AD5,0x101B,0xB8,0x26,0x00,0xDD,0x01,0x10,0x3D,0xE1);

/* Definition of interface: IHello */

DECLARE_INTERFACE_(IHello, IDispatch)

{

#ifndef NO_BASEINTERFACE_FUNCS

    /* IUnknown methods */

    STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE;

    STDMETHOD_(ULONG, AddRef)(THIS) PURE;

    STDMETHOD_(ULONG, Release)(THIS) PURE;

    /* IDispatch methods */

    STDMETHOD(GetTypeInfoCount)(THIS_ UINT FAR* pctinfo) PURE;

    STDMETHOD(GetTypeInfo)(

      THIS_

      UINT itinfo,

      LCID lcid,

      ITypeInfo FAR* FAR* pptinfo) PURE;

    STDMETHOD(GetIDsOfNames)(

      THIS_

      REFIID riid,

      OLECHAR FAR* FAR* rgszNames,

      UINT cNames,

      LCID lcid,

      DISPID FAR* rgdispid) PURE;

    STDMETHOD(Invoke)(

      THIS_

      DISPID dispidMember,

      REFIID riid,

      LCID lcid,

      WORD wFlags,

      DISPPARAMS FAR* pdispparams,

      VARIANT FAR* pvarResult,

      EXCEPINFO FAR* pexcepinfo,

      UINT FAR* puArgErr) PURE;

#endif

    /* IHello methods */

    STDMETHOD(get_Application)(THIS_ IHello FAR* FAR* retval) PURE;

    STDMETHOD(get_FullName)(THIS_ BSTR FAR* retval) PURE;

    STDMETHOD(get_Name)(THIS_ BSTR FAR* retval) PURE;

    STDMETHOD(get_Parent)(THIS_ IHello FAR* FAR* retval) PURE;

    STDMETHOD(put_Visible)(THIS_ VARIANT_BOOL VisibleFlag) PURE;

    STDMETHOD(get_Visible)(THIS_ VARIANT_BOOL FAR* retval) PURE;

    STDMETHOD(Quit)(THIS) PURE;

    STDMETHOD(put_HelloMessage)(THIS_ BSTR Message) PURE;

    STDMETHOD(get_HelloMessage)(THIS_ BSTR FAR* retval) PURE;

    STDMETHOD(SayHello)(THIS) PURE;

};

DEFINE_GUID(CLSID_Hello,0xF37C8061,0x4AD5,0x101B,0xB8,0x26,0x00,0xDD,0x01,0x10,0x3D,0xE1);

class Hello;

#endif


 HELLCTRL.CPP   (HELLCTRL OLE Sample)

/*************************************************************************

**

**    Automation Controller that uses vtable binding.

**    Controls the HELLO automation object.

**

**    hellctrl.cpp

**

**

**     Written by Microsoft Product Support Services, Windows Developer Support

**    (c) Copyright Microsoft Corp. 1994 All Rights Reserved

**

*************************************************************************/

#define STRICT

#include <windows.h>

#include <windowsx.h>

#ifdef WIN16

  #include <ole2.h>

  #include <compobj.h>

  #include <dispatch.h>

  #include <variant.h>

  #include <olenls.h>

  #include <commdlg.h>

#endif

#include <initguid.h>

#include "tlb.h"

#include "hellctrl.h"

// Globals

HINSTANCE g_hinst;                          // Instance of application

HWND      g_hwnd;                           // Toplevel window handle

// String resource buffers

TCHAR g_szTitle[STR_LEN];                    // Main window caption

TCHAR g_szResult[STR_LEN];                   // "Result"

TCHAR g_szError[STR_LEN];                    // "Error"

/*

 * WinMain

 *

 * Purpose:

 *  Main entry point of application. Should register the app class

 *  if a previous instance has not done so and do any other one-time

 *  initializations.

 *

 */

int APIENTRY WinMain (HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpCmdLine, int nCmdShow)

{

   MSG msg;

   //  It is recommended that all OLE applications set

   //  their message queue size to 96. This improves the capacity

   //  and performance of OLE's LRPC mechanism.

   int cMsg = 96;                  // Recommend msg queue size for OLE

   while (cMsg && !SetMessageQueue(cMsg))  // take largest size we can get.

       cMsg -= 8;

   if (!cMsg)

       return -1;                  // ERROR: we got no message queue

   // Load string constants

   LoadString(hinst, IDS_PROGNAME, g_szTitle, STR_LEN);

   LoadString(hinst, IDS_RESULT, g_szResult, STR_LEN);

   LoadString(hinst, IDS_ERROR, g_szError, STR_LEN);

   if (!hinstPrev)

      if (!InitApplication(hinst))

         return (FALSE);

   if(OleInitialize(NULL) != NOERROR)

      return FALSE;

   if (!InitInstance(hinst, nCmdShow))

      return (FALSE);

   while (GetMessage(&msg, NULL, NULL, NULL))

   {

      TranslateMessage(&msg);

      DispatchMessage(&msg);

   }

   OleUninitialize();

   return (msg.wParam); // Returns the value from PostQuitMessage

}

/*

 * InitApplication

 *

 * Purpose:

 *  Registers window class

 *

 * Parameters:

 *  hinst       hInstance of application

 *

 * Return Value:

 *  TRUE if initialization succeeded, FALSE otherwise.

 */

BOOL InitApplication (HINSTANCE hinst)

{

   WNDCLASS wc;

   wc.style = CS_DBLCLKS;

   wc.lpfnWndProc = MainWndProc;

   wc.cbClsExtra = 0;

   wc.cbWndExtra = 0;

   wc.hInstance = hinst;

   wc.hIcon = LoadIcon(hinst, TEXT("ControlIcon"));

   wc.hCursor = LoadCursor(NULL, IDC_ARROW);

   wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);

   wc.lpszMenuName = TEXT("ControlMenu");

   wc.lpszClassName = TEXT("MainWndClass");

   return RegisterClass(&wc);

 }

/*

 * InitInstance

 *

 * Purpose:

 *  Creates and shows main window

 *

 * Parameters:

 *  hinst           hInstance of application

 *  nCmdShow        specifies how window is to be shown

 *

 * Return Value:

 *  TRUE if initialization succeeded, FALSE otherwise.

 */

BOOL InitInstance (HINSTANCE hinst, int nCmdShow)

{

   g_hinst = hinst;

   // Create Main Window

   g_hwnd = CreateWindow(TEXT("MainWndClass"), g_szTitle,

                       WS_OVERLAPPEDWINDOW,

                       CW_USEDEFAULT, CW_USEDEFAULT,

                       400, 200,

                       NULL, NULL, hinst, NULL);

   if (!g_hwnd)

      return FALSE;

   ShowWindow(g_hwnd, nCmdShow);

   UpdateWindow(g_hwnd);

   return TRUE;

}

/*

 * MainWndProc

 *

 * Purpose:

 *  Window procedure for main window

 *

 */

LRESULT CALLBACK MainWndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)

{

   static IHello FAR* phello = NULL;

   HRESULT hr;

   LPUNKNOWN punk;

   switch (msg)

   {

      case WM_COMMAND:

         switch (wParam)

         {

            case IDM_CREATEHELLO:

                // Create Hello object and QueryInterface for IHello interface.

                hr = CoCreateInstance(CLSID_Hello, NULL, CLSCTX_SERVER,

                     IID_IUnknown, (void FAR* FAR*)&punk);

                if (FAILED(hr))

                {

                    MessageBox(NULL, TEXT("CoCreateInstance"), g_szError, MB_OK);

                    return 0L;

                }

                hr = punk->QueryInterface(IID_IHello,  (void FAR* FAR*)&phello);

                if (FAILED(hr))

                {

                    MessageBox(NULL, TEXT("QueryInterface(IID_IHello)"), g_szError, MB_OK);

                    punk->Release();

                    return 0L;

                }

                punk->Release();

                return 0L;

            case IDM_SETVISIBLE:

                // Set Visible property to TRUE

                hr = phello->put_Visible(TRUE);

                if (FAILED(hr))

                    DisplayError(phello);

                return 0L;

            case IDM_SETINVISIBLE:

                // Set visible property to FALSE

                hr = phello->put_Visible(FALSE);

                if (FAILED(hr))

                    DisplayError(phello);

                return 0L;

            case IDM_GETHELLOMESSAGE:

            {

                // Access Hello Message property and display it

                // in a MessageBox

                BSTR bstr = NULL;   // BSTR must be intialized before passing

                                    // to get_HelloMessage.

                hr = phello->get_HelloMessage(&bstr);

                if (FAILED(hr))

                    DisplayError(phello);

                else MessageBox(NULL, FROM_OLE_STRING(bstr), g_szResult, MB_OK);

                // Caller is responsible for freeing parameters and return values.

                if (bstr)

                    SysFreeString(bstr);

                return 0L;

            }

            case IDM_SAYHELLO:

                // Invoke SayHello method

                hr = phello->SayHello();

                if (FAILED(hr))

                    DisplayError(phello);

                return 0L;

            case IDM_RELEASEHELLO:

                // Release the Hello object

                phello->Release();

                phello = NULL;

                return 0L;

         }

         break;

      case WM_INITMENUPOPUP:

      {

         HMENU hmenu = (HMENU)wParam;

         if (LOWORD(lParam) != 0)

            return 0L;

         // Enable or gray the appropriate menu items. phello indicates if an automation object

         //  is currently being controlled.

         EnableMenuItem(hmenu, IDM_CREATEHELLO,  MF_BYCOMMAND | (phello?MF_GRAYED:MF_ENABLED));

         EnableMenuItem(hmenu, IDM_SETVISIBLE,   MF_BYCOMMAND | (phello?MF_ENABLED:MF_GRAYED));

         EnableMenuItem(hmenu, IDM_SETINVISIBLE,   MF_BYCOMMAND | (phello?MF_ENABLED:MF_GRAYED));

         EnableMenuItem(hmenu, IDM_GETHELLOMESSAGE,   MF_BYCOMMAND | (phello?MF_ENABLED:MF_GRAYED));

         EnableMenuItem(hmenu, IDM_SAYHELLO,  MF_BYCOMMAND | (phello?MF_ENABLED:MF_GRAYED));

         EnableMenuItem(hmenu, IDM_RELEASEHELLO, MF_BYCOMMAND | (phello?MF_ENABLED:MF_GRAYED));

         return 0L;

      }

      case WM_DESTROY:

         if (phello)

            phello->Release();

         PostQuitMessage(0);

         break;

      default:

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

   }

   return NULL;

}

/*

 * DisplayError

 *

 * Purpose:

 *  Obtains Rich Error Information about the automation error from

 *  the IErrorInfo interface.

 *

 */

void DisplayError(IHello FAR* phello)

{

   IErrorInfo FAR* perrinfo;

   BSTR bstrDesc;

   HRESULT hr;

 /*

   // This is commented out because the OLE 2.02 release did not

   // include remoting code for ISupportErrorInfo.

   ISupportErrorInfo FAR* psupporterrinfo;

   hr = phello->QueryInterface(IID_ISupportErrorInfo, (LPVOID FAR*)&psupporterrinfo);

   if (FAILED(hr))

   {

      MessageBox(NULL, TEXT("QueryInterface(IID_ISupportErrorInfo)"), g_szError, MB_OK);

      return;

   }

   hr = psupporterrinfo->InterfaceSupportsErrorInfo(IID_IHello);

   if (hr != NOERROR)

   {

       psupporterrinfo->Release();

       return;

   }

   psupporterrinfo->Release();

*/

   // In this example only the error description is obtained and displayed.

   // See the IErrorInfo interface fo other information that is available.

   hr = GetErrorInfo(0, &perrinfo);

   if (FAILED(hr))

       return;

   hr = perrinfo->GetDescription(&bstrDesc);

   if (FAILED(hr))

   {

       perrinfo->Release();

       return;

   }

   MessageBox(NULL, FROM_OLE_STRING(bstrDesc), g_szError, MB_OK);

   SysFreeString(bstrDesc);

}

#ifdef WIN32

#ifndef UNICODE

char* ConvertToAnsi(OLECHAR FAR* szW)

{

  static char achA[STRCONVERT_MAXLEN];

  WideCharToMultiByte(CP_ACP, 0, szW, -1, achA, STRCONVERT_MAXLEN, NULL, NULL);

  return achA;

}

OLECHAR* ConvertToUnicode(char FAR* szA)

{

  static OLECHAR achW[STRCONVERT_MAXLEN];

  MultiByteToWideChar(CP_ACP, 0, szA, -1, achW, STRCONVERT_MAXLEN);

  return achW;

}

#endif

#endif


 HELLO

SAMPLE: HELLO: Simple OLE Automation Server

HELLO is a simple OLE Automation server application.  This is a good sample to use to learn to create your first OLE Automation server. This has one object that supports the following properties and methods:

Hello Object:

 Properties
    HelloMessage
 Methods
    SayHello

The sample the following features:

· Supports dual interfaces which allows access of automation properties and methods through   vtable binding and through IDispatch.
· Provides Rich Error information for vtable-binding controllers. This is does by implementing   ISupportErrorInfo and using IErrorInfo.
· Implements active object registration using RegisterActiveObject and RevokeActiveObject.  · Implements correct shut-down behavior.  · Includes a .reg file which contains Hello.Application and Hello.Application.2 as progIDs. · When created for automation, is invisible initially.

To compile: -----------

Requires OLE 2.02 or later. Use the external makefile called makefile to compile.  In Win16, run the WXSRVER.EXE from \OLE2\BIN before running the makefile. The makefile invokes mktyplib.exe that reads hello.odl and creates the type library, hello.tlb. It then compliles the source files.

To run: -------

Change hello.reg to provide the full path of hello.exe and hello.tlb.  Register hello.reg in the registration database by double-clicking it. The HELLCTRL directory contains a controller that will control HELLO using vtable-binding.

Files: ------

HELLO.ODL   Object description language that describes the property and method that HELLO exposes.
TLB.H       Header file generated by mktyplib.exe MAKEFILE    Makefile for project.

Other files implement the HELLO automation server. ================================================================================


 MAKEFILE   (HELLO OLE Sample)

####

#makefile - makefile for hello.exe

#

#       Copyright (C) 1994, Microsoft Corporation

#

#Purpose:

#  Builds the OLE 2.0 Automation object, hello.exe.

#

#

#  Usage: NMAKE                 ; build with defaults

#     or: NMAKE option          ; build with the given option(s)

#     or: NMAKE clean           ; erase all compiled files

#

#     option: dev = [win16 | win32]    ; dev=win32 is the default

#             DEBUG=[0 | 1]            ; DEBUG=1 is the default

#             HOST=[DOS | NT | WIN95]  ; HOST=DOS (for win16)

#                                      ; HOST=NT (for win32 on NT)

#                                      ; HOST=WIN95 (for win32 on Win95)

#

#Notes:

#  This makefile assumes that the PATH, INCLUDE and LIB environment

#  variables are setup properly.

#

##############################################################################

##########################################################################

#

# Default Settings

#

CPU = i386

!if "$(dev)" == ""

dev = win32

HOST = NT

!endif

!if !("$(dev)" == "win16" || "$(dev)" == "win32")

!error Invalid dev option, choose from [win16 | win32]

!endif

!if "$(dev)" == "win16"

TARGET  = WIN16

!if "$(HOST)" == ""

HOST  = DOS

!endif

!endif

!if "$(dev)" == "win32"

TARGET  = WIN32

!if "$(HOST)" == ""

HOST  = NT

!endif

!endif

!ifdef NODEBUG

DEBUG = 0

!endif

!if "$(DEBUG)" == "0"

NODEBUG = 1

!endif

!if "$(DEBUG)" == ""

DEBUG = 1

!endif

##########################################################################

#

# WIN16 Settings

#

!if "$(TARGET)" == "WIN16"

CC   = cl

LINK = link

!if "$(HOST)" == "DOS"

WX   = wx /w

!else

WX   =

!endif

RCFLAGS = -dWIN16

CFLAGS = -c -W3 -AM -GA -GEs -DWIN16

LINKFLAGS = /NOD /NOI /BATCH /ONERROR:NOEXE

LIBS = libw.lib mlibcew.lib

!if "$(DEBUG)" == "1"

CFLAGS = $(CFLAGS) -Od -Zi -D_DEBUG $(CL)

LINKFLAGS = $(LINKFLAGS) /COD

!else

CFLAGS = $(CFLAGS) -Ox $(CL)

LINKFLAGS = $(LINKFLAGS) /FAR /PACKC

!endif

!endif

##########################################################################

#

# WIN32 Settings

#

!if "$(TARGET)" == "WIN32"

WX =

!include <ntwin32.mak>

CC = $(cc)

CFLAGS = $(cflags) $(cvarsmt) -DINC_OLE2 $(cdebug)

!if "$(HOST)" == "NT"

CFLAGS = $(CFLAGS) -DUNICODE

!endif

!ifndef NODEBUG

CFLAGS = $(CFLAGS) -D_DEBUG

!endif

LINK = $(link)

LINKFLAGS = $(linkdebug) $(guilflags)

RCFLAGS = -DWIN32

!endif

##########################################################################

#

# Build rules

#

.cpp.obj:

    @echo Compiling $<...

    $(CC) $<

.c.obj:

    @echo Compiling $<...

    $(CC) $<

##########################################################################

#

# Application Settings

#

APPS = hello

!if "$(TARGET)" == "WIN16"

LIBS = ole2.lib compobj.lib ole2disp.lib typelib.lib $(LIBS)

!endif

!if "$(TARGET)" == "WIN32"

LIBS = $(ole2libsmt)

!endif

OBJS = main.obj hello.obj hellocf.obj

##########################################################################

#

# Default Goal

#

goal : setflags $(APPS).exe

setflags :

    set CL=$(CFLAGS)

##########################################################################

#

# Clean (erase) generated files

#

clean :

    if exist *.obj       del *.obj

    if exist $(APPS).exe del $(APPS).exe

    if exist $(APPS).tlb del $(APPS).tlb

    if exist $(APPS).map del $(APPS).map

    if exist $(APPS).res del $(APPS).res

    if exist tlb.h       del tlb.h

    if exist *.log       del *.log

    if exist *.pdb       del *.pdb

##########################################################################

#

# Application Build (WIN16 Specific)

#

!if "$(TARGET)" == "WIN16"

$(APPS).exe : $(OBJS) $(APPS).def $(APPS).res $(APPS).ico

    link $(LINKFLAGS) @<<

$(OBJS),

$@,,

$(LIBS),

$(APPS).def

<<

    rc -k -t $(APPS).res $@

!endif

##########################################################################

#

# Application Build (WIN32 Specific)

#

!if "$(TARGET)" == "WIN32"

$(APPS).exe : $(OBJS) $(APPS).def $(APPS).res $(APPS).ico

      $(LINK) @<<

        $(LINKFLAGS)

        -out:$@

        -map:$*.map

        $(OBJS)

        $(APPS).res

        $(LIBS)

<<

!endif

##########################################################################

#

# Application Build (Common)

#

$(APPS).res : $(APPS).rc

    rc $(RCFLAGS) -r -fo$@ $?

##########################################################################

#

# Dependencies

#

tlb.h : hello.odl

     if exist tlb.h  del tlb.h

     if exist hello.tlb  del hello.tlb

     $(WX) mktyplib /D$(TARGET) /h tlb.h /o hello.log /tlb hello.tlb hello.odl

     type hello.log

main.obj : main.cpp hello.h tlb.h

     $(CC) main.cpp

hello.obj : hello.cpp hello.h tlb.h

     $(CC) hello.cpp

hellocf.obj : hellocf.cpp hello.h tlb.h

     $(CC) hellocf.cpp


 HELLO.H   (HELLO OLE Sample)

#ifdef WIN32

#ifdef UNICODE

    #define FROM_OLE_STRING(str) str

    #define TO_OLE_STRING(str) str

#else

    #define FROM_OLE_STRING(str) ConvertToAnsi(str)

    char* ConvertToAnsi(OLECHAR FAR* szW);

    #define TO_OLE_STRING(str) ConvertToUnicode(str)

    OLECHAR* ConvertToUnicode(char FAR* szA);

    // Maximum length of string that can be converted between Ansi & Unicode

    #define STRCONVERT_MAXLEN 300

#endif

#else  // WIN16

  #define APIENTRY far pascal

  #define TCHAR char

  #define TEXT(sz) sz

  #define FROM_OLE_STRING(str) str

  #define TO_OLE_STRING(str) str

  #define LPTSTR LPSTR

  // Windows NT defines the following in windowsx.h

  #define GET_WM_COMMAND_ID(w,l) (w)

  #define GET_WM_COMMAND_CMD(w,l) HIWORD(l)

  #define GET_WM_COMMAND_HWND(w,l) LOWORD(l)

#endif

#define STRICT

// Resource IDs

#define IDD_MAINWINDOW   101

#define IDI_ICON         102

// Child window IDs

#define IDC_HELLODISPLAY 101

#define IDC_SAYHELLO     102

// MAX len of string table entries

#define STR_LEN   100

// String table constants

#define IDS_Name                 1

#define IDS_HelloMessage         2

#define IDS_ErrorLoadingTypeLib  3

#define IDS_SayHello             4

#define IDS_ProgID               5

#define IDS_Unexpected           1001

// SCODEs for the Hello Application. This is required for vtable-binding

// Automation objects want to return custom HRESULTs. All the OLE-defined

// FACILITY_ITF codes have a code value which lies in the region 0x0000-0x01FFF.

// While it is legal for the definer to use any code, it is highly recommended

// that only code values in the range 0x0200-0xFFFF be used, as this will reduce the

// possiblity of accidental confusion with any OLE-defined errors.

#define HELLO_E_FIRST       MAKE_SCODE(SEVERITY_ERROR, FACILITY_ITF, 0x0200)

#define HELLO_E_UNEXPECTED  (HELLO_E_FIRST + 0x0)

// Unexpected error

// Number of SCODEs

#define SCODE_COUNT 1

// Function prototypes

int APIENTRY WinMain (HINSTANCE, HINSTANCE, LPSTR, int);

BOOL InitApplication (HINSTANCE);

BOOL InitInstance (HINSTANCE);

BOOL ProcessCmdLine(LPSTR lpCmdLine, LPDWORD pdwRegisterCF, LPDWORD pdwRegisterActiveObject, int nCmdShow);

void Uninitialize(DWORD dwRegisterCF, DWORD dwRegisterActiveObject);

HRESULT LoadTypeInfo(ITypeInfo FAR* FAR* pptinfo, REFCLSID clsid);

#ifdef WIN16

extern "C" LRESULT __export CALLBACK MainWndProc (HWND, UINT, WPARAM, LPARAM);

#else

extern "C" LRESULT CALLBACK MainWndProc (HWND, UINT, WPARAM, LPARAM);

#endif

#include "tlb.h"

// ISupportErrorInfo interface implementation

interface CSupportErrorInfo : public ISupportErrorInfo

{

public:

    // IUnknown methods

    STDMETHOD(QueryInterface)(REFIID riid, LPVOID FAR* ppvObj);

    STDMETHOD_(ULONG, AddRef)(void);

    STDMETHOD_(ULONG, Release)(void);

    // ISupportErrorInfo method

    STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid);

    CSupportErrorInfo(IUnknown FAR* punkObject, REFIID riid);

private:

    LPUNKNOWN m_punkObject;  // IUnknown of Object that implements this interface

    GUID m_iid;

};

class FAR CHello : public IHello

{

public:

    // IUnknown methods

    STDMETHOD(QueryInterface)(REFIID riid, LPVOID FAR* ppvObj);

    STDMETHOD_(ULONG, AddRef)(void);

    STDMETHOD_(ULONG, Release)(void);

    // IDispatch methods

    STDMETHOD(GetTypeInfoCount)(UINT FAR* pctinfo);

    STDMETHOD(GetTypeInfo)(

      UINT itinfo,

      LCID lcid,

      ITypeInfo FAR* FAR* pptinfo);

    STDMETHOD(GetIDsOfNames)(

      REFIID riid,

      OLECHAR FAR* FAR* rgszNames,

      UINT cNames,

      LCID lcid,

      DISPID FAR* rgdispid);

    STDMETHOD(Invoke)(

      DISPID dispidMember,

      REFIID riid,

      LCID lcid,

      WORD wFlags,

      DISPPARAMS FAR* pdispparams,

      VARIANT FAR* pvarResult,

      EXCEPINFO FAR* pexcepinfo,

      UINT FAR* puArgErr);

    // IHello methods

    STDMETHOD(get_Application)(IHello FAR* FAR* ppHello);

    STDMETHOD(get_FullName)(BSTR FAR* pbstr);

    STDMETHOD(get_Name)(BSTR FAR* pbstr);

    STDMETHOD(get_Parent)(IHello FAR* FAR* ppHello);

    STDMETHOD(put_Visible)(VARIANT_BOOL bVisible);

    STDMETHOD(get_Visible)(VARIANT_BOOL FAR* pbool);

    STDMETHOD(Quit)();

    STDMETHOD(put_HelloMessage)(BSTR bstrMessage);

    STDMETHOD(get_HelloMessage)(BSTR FAR* pbstrMessage);

    STDMETHOD(SayHello)();

    // CHello methods

    STDMETHOD(RaiseException)(int nID);

    STDMETHOD_(void, ShowWindow)(int nCmdShow);

    static HRESULT Create(HINSTANCE hinst, LPTSTR lpszHelloMessage, CHello FAR* FAR* pphello); // Creates and intializes Hello object

    CHello();

    ~CHello();

public:

    HWND m_hwnd;                   // Application window.

    HINSTANCE m_hinst;             // Hinstance of application.

    BSTR m_bstrName;               // Name of application.

BSTR m_bstrProgID;             // ProgID of application.

private:

    LPTYPEINFO m_ptinfo;           // Type information of Hello application interface.

    BSTR m_bstrHelloMsg;           // Hello message

    BSTR m_bstrFullName;           // Full name of application.

    BOOL m_bVisible;               // Is window visible?

    EXCEPINFO m_excepinfo;         // Information to raise an exception on error.

    BOOL m_bRaiseException;        // Properties and methods use this to signal that an exception is to be raised.

    ULONG m_cRef;                  // Reference count

    CSupportErrorInfo m_SupportErrorInfo; // ISupportErrorInfo interface implementation

};

class FAR CHelloCF : public IClassFactory

{

public:

    // IUnknown methods

    STDMETHOD(QueryInterface)(REFIID riid, LPVOID FAR* ppvObj);

    STDMETHOD_(ULONG, AddRef)(void);

    STDMETHOD_(ULONG, Release)(void);

    // IClassFactory methods

    STDMETHOD(CreateInstance)(IUnknown FAR* punkOuter, REFIID riid,

                              void FAR* FAR* ppv);

    STDMETHOD(LockServer)(BOOL fLock);

    CHelloCF();

private:

    ULONG m_cRef;                   // Reference count

};

extern CHello FAR* g_phello;


 TLB.H   (HELLO OLE Sample)

/* This header file machine-generated by mktyplib.exe */

/* Interface to type library: Hello */

#ifndef _Hello_H_

#define _Hello_H_

DEFINE_GUID(LIBID_Hello,0xF37C8060,0x4AD5,0x101B,0xB8,0x26,0x00,0xDD,0x01,0x10,0x3D,0xE1);

DEFINE_GUID(IID_IHello,0xF37C8062,0x4AD5,0x101B,0xB8,0x26,0x00,0xDD,0x01,0x10,0x3D,0xE1);

/* Definition of interface: IHello */

DECLARE_INTERFACE_(IHello, IDispatch)

{

#ifndef NO_BASEINTERFACE_FUNCS

    /* IUnknown methods */

    STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE;

    STDMETHOD_(ULONG, AddRef)(THIS) PURE;

    STDMETHOD_(ULONG, Release)(THIS) PURE;

    /* IDispatch methods */

    STDMETHOD(GetTypeInfoCount)(THIS_ UINT FAR* pctinfo) PURE;

    STDMETHOD(GetTypeInfo)(

      THIS_

      UINT itinfo,

      LCID lcid,

      ITypeInfo FAR* FAR* pptinfo) PURE;

    STDMETHOD(GetIDsOfNames)(

      THIS_

      REFIID riid,

      OLECHAR FAR* FAR* rgszNames,

      UINT cNames,

      LCID lcid,

      DISPID FAR* rgdispid) PURE;

    STDMETHOD(Invoke)(

      THIS_

      DISPID dispidMember,

      REFIID riid,

      LCID lcid,

      WORD wFlags,

      DISPPARAMS FAR* pdispparams,

      VARIANT FAR* pvarResult,

      EXCEPINFO FAR* pexcepinfo,

      UINT FAR* puArgErr) PURE;

#endif

    /* IHello methods */

    STDMETHOD(get_Application)(THIS_ IHello FAR* FAR* retval) PURE;

    STDMETHOD(get_FullName)(THIS_ BSTR FAR* retval) PURE;

    STDMETHOD(get_Name)(THIS_ BSTR FAR* retval) PURE;

    STDMETHOD(get_Parent)(THIS_ IHello FAR* FAR* retval) PURE;

    STDMETHOD(put_Visible)(THIS_ VARIANT_BOOL VisibleFlag) PURE;

    STDMETHOD(get_Visible)(THIS_ VARIANT_BOOL FAR* retval) PURE;

    STDMETHOD(Quit)(THIS) PURE;

    STDMETHOD(put_HelloMessage)(THIS_ BSTR Message) PURE;

    STDMETHOD(get_HelloMessage)(THIS_ BSTR FAR* retval) PURE;

    STDMETHOD(SayHello)(THIS) PURE;

};

DEFINE_GUID(CLSID_Hello,0xF37C8061,0x4AD5,0x101B,0xB8,0x26,0x00,0xDD,0x01,0x10,0x3D,0xE1);

class Hello;

#endif


 HELLO.CPP   (HELLO OLE Sample)

/*************************************************************************

**

**    OLE Automation Hello 2.0 Application.

**

**    hello.cpp

**

**    CHello implementation

**

**     Written by Microsoft Product Support Services, Windows Developer Support

**    (c) Copyright Microsoft Corp. 1994 All Rights Reserved

**

*************************************************************************/

#include <windows.h>

#include <windowsx.h>

#ifdef WIN16

  #include <ole2.h>

  #include <compobj.h>

  #include <dispatch.h>

  #include <variant.h>

  #include <olenls.h>

#endif

#include "hello.h"

/*

 * CHello::Create

 *

 * Purpose:

 *  Creates an instance of the Hello Application object and initializes it.

 *

 * Parameters:

 *  hinst      HINSTANCE of application.

 *  lpszHelloMessage Initial Hello message.

 *  pphello    Returns Hello automation object.

 *

 * Return Value:

 *  HRESULT

 *

 */

HRESULT

CHello::Create(HINSTANCE hinst, LPTSTR lpszHelloMessage, CHello FAR* FAR* pphello)

{

    TCHAR ach[STR_LEN];

    TCHAR achFullName[260];

    HRESULT hr;

    CHello FAR* phello = NULL;

    HWND hwnd;

    *pphello = NULL;

    // Create Hello Application object

    phello = new CHello();

    if (phello == NULL)

        goto error;

    // Create Main Window

    hwnd = CreateDialog(hinst, MAKEINTRESOURCE(IDD_MAINWINDOW), NULL, NULL);

    if (!hwnd)

    {

        hr = ResultFromScode(E_OUTOFMEMORY);

        goto error;

    }

    phello->m_cRef = 0;

    phello->m_bVisible = FALSE;

    phello->m_hwnd = hwnd;

    phello->m_hinst = hinst;

    // FullName

    GetModuleFileName(hinst, achFullName, sizeof(achFullName));

    phello->m_bstrFullName = SysAllocString(TO_OLE_STRING(achFullName));

    if (NULL == phello->m_bstrFullName)

    {

        hr = ResultFromScode(E_OUTOFMEMORY);

        goto error;

    }

    // Name

    LoadString(hinst, IDS_Name, ach, sizeof(ach));

    phello->m_bstrName = SysAllocString(TO_OLE_STRING(ach));

    if (NULL == phello->m_bstrName)

    {

        hr = ResultFromScode(E_OUTOFMEMORY);

        goto error;

    }

    // ProgID

    LoadString(hinst, IDS_ProgID, ach, sizeof(ach));

    phello->m_bstrProgID = SysAllocString(TO_OLE_STRING(ach));

    if (NULL == phello->m_bstrProgID)

    {

        hr = ResultFromScode(E_OUTOFMEMORY);

        goto error;

    }

    // Hello Message

    phello->m_bstrHelloMsg = SysAllocString(TO_OLE_STRING(lpszHelloMessage));

    if (NULL == phello->m_bstrHelloMsg)

    {

        hr = ResultFromScode(E_OUTOFMEMORY);

        goto error;

    }

    // Load type information from type library. If required, notify user on failure.

    hr = LoadTypeInfo(&phello->m_ptinfo, IID_IHello);

    if (FAILED(hr))

    {

        LoadString(hinst, IDS_ErrorLoadingTypeLib, ach, sizeof(ach));

        MessageBox(NULL, ach, FROM_OLE_STRING(phello->m_bstrName), MB_OK);

        goto error;

    }

    *pphello = phello;

    return NOERROR;

error:

    if (phello == NULL) return ResultFromScode(E_OUTOFMEMORY);

    if (phello->m_bstrFullName) SysFreeString(phello->m_bstrFullName);

    if (phello->m_bstrName) SysFreeString(phello->m_bstrName);

    if (phello->m_bstrProgID) SysFreeString(phello->m_bstrProgID);

    if (phello->m_bstrHelloMsg) SysFreeString(phello->m_bstrHelloMsg);

    if (phello->m_ptinfo) phello->m_ptinfo->Release();

    // Set to NULL to prevent destructor from attempting to free again

    phello->m_bstrFullName = NULL;

    phello->m_bstrName = NULL;

phello->m_bstrProgID = NULL;

    phello->m_bstrHelloMsg = NULL;

    phello->m_ptinfo = NULL;

    delete phello;

    return hr;

}

/*

 * CHello::CHello

 *

 * Purpose:

 *  Constructor for CHello object. Initializes members to NULL.

 *

 */

#pragma warning (disable : 4355)

CHello::CHello() : m_SupportErrorInfo(this, IID_IHello)

#pragma warning (default : 4355)

{

    extern ULONG g_cObj;

    m_hwnd = NULL;

    m_bstrFullName = NULL;

    m_bstrName = NULL;

m_bstrProgID = NULL;

    m_bstrHelloMsg = NULL;

    m_ptinfo = NULL;

    m_bVisible = 0;

}

/*

 * CHello::~CHello

 *

 * Purpose:

 *  Destructor for CHello object.

 *

 */

CHello::~CHello()

{

     extern ULONG g_cObj;

     if (m_bstrFullName) SysFreeString(m_bstrFullName);

     if (m_bstrName) SysFreeString(m_bstrName);

 if (m_bstrProgID) SysFreeString(m_bstrProgID);

     if (m_bstrHelloMsg) SysFreeString(m_bstrHelloMsg);

     if (m_ptinfo) m_ptinfo->Release();

     if (IsWindow(m_hwnd)) DestroyWindow(m_hwnd);

}

/*

 * CHello::QueryInterface, AddRef, Release

 *

 * Purpose:

 *  Implements IUnknown::QueryInterface, AddRef, Release

 *

 */

STDMETHODIMP

CHello::QueryInterface(REFIID iid, void FAR* FAR* ppv)

{

    *ppv = NULL;

    if (iid == IID_IUnknown || iid == IID_IDispatch || iid == IID_IHello  )

        *ppv = this;

    else if (iid == IID_ISupportErrorInfo)

        *ppv = &m_SupportErrorInfo;

    else return ResultFromScode(E_NOINTERFACE);

    AddRef();

    return NOERROR;

}

STDMETHODIMP_(ULONG)

CHello::AddRef(void)

{

#ifdef _DEBUG

    TCHAR ach[50];

    wsprintf(ach, TEXT("AddRef: Ref = %ld, Hello\r\n"), m_cRef+1);

    OutputDebugString(ach);

#endif

    return ++m_cRef;

}

STDMETHODIMP_(ULONG)

CHello::Release(void)

{

#ifdef _DEBUG

    TCHAR ach[50];

    wsprintf(ach, TEXT("Release: Ref = %ld, Hello\r\n"), m_cRef-1);

    OutputDebugString(ach);

#endif

    if(--m_cRef == 0)

    {

        delete this;

        return 0;

    }

    return m_cRef;

}

/*

 * CHello::GetTypeInfoCount

 *

 * Purpose:

 *  Implements IDispatch::GetTypeInfoCount.

 *

 */

STDMETHODIMP

CHello::GetTypeInfoCount(UINT FAR* pctinfo)

{

    *pctinfo = 1;

    return NOERROR;

}

/*

 * CHello::GetTypeInfo

 *

 * Purpose:

 *  Implements IDispatch::GetTypeInfo.

 *

 */

STDMETHODIMP

CHello::GetTypeInfo(

      UINT itinfo,

      LCID lcid,

      ITypeInfo FAR* FAR* pptinfo)

{

    *pptinfo = NULL;

    if(itinfo != 0)

        return ResultFromScode(DISP_E_BADINDEX);

    m_ptinfo->AddRef();

    *pptinfo = m_ptinfo;

    return NOERROR;

}

/*

 * CHello::GetIDsOfNames

 *

 * Purpose:

 *  Implements IDispatch::GetIDsOfNames.  The standard implementation, DispGetIDsOfNames,

 *  is used.

 *

 */

STDMETHODIMP

CHello::GetIDsOfNames(

      REFIID riid,

      OLECHAR FAR* FAR* rgszNames,

      UINT cNames,

      LCID lcid,

      DISPID FAR* rgdispid)

{

    return DispGetIDsOfNames(m_ptinfo, rgszNames, cNames, rgdispid);

}

/*

 * CHello::Invoke

 *

 * Purpose:

 *  Implements IDispatch::Invoke.  The standard implementation, DispInvoke,

 *  is used.

 *

 */

STDMETHODIMP

CHello::Invoke(

      DISPID dispidMember,

      REFIID riid,

      LCID lcid,

      WORD wFlags,

      DISPPARAMS FAR* pdispparams,

      VARIANT FAR* pvarResult,

      EXCEPINFO FAR* pexcepinfo,

      UINT FAR* puArgErr)

{

    HRESULT hr;

    m_bRaiseException = FALSE;

    hr =  DispInvoke(

        this, m_ptinfo,

        dispidMember, wFlags, pdispparams,

        pvarResult, pexcepinfo, puArgErr);

    if (m_bRaiseException)

    {

   if (NULL != pexcepinfo)

           _fmemcpy(pexcepinfo, &m_excepinfo, sizeof(EXCEPINFO));

       return ResultFromScode(DISP_E_EXCEPTION);

    }

    else return hr;

}

/*

 * CHello::put_HelloMessage, get_HelloMessage, SayHello

 *

 * Purpose:

 *  Implements the standard Application, FullName, Name, Parent & Visible properties

 *  and the Quit method.

 *

 */

STDMETHODIMP

CHello::get_Application(IHello FAR* FAR* ppHello)

{

    HRESULT hr;

    *ppHello = NULL;

    hr = QueryInterface(IID_IDispatch, (void FAR* FAR*)ppHello);

    if (FAILED(hr))

        return RaiseException(IDS_Unexpected);

    return hr;

}

STDMETHODIMP

CHello::get_FullName(BSTR FAR* pbstr)

{

    *pbstr = SysAllocString(m_bstrFullName);

    return NOERROR;

}

STDMETHODIMP

CHello::get_Name(BSTR FAR* pbstr)

{

    *pbstr = SysAllocString(m_bstrName);

    return NOERROR;

}

STDMETHODIMP

CHello::get_Parent(IHello FAR* FAR* ppHello)

{

    HRESULT hr;

    *ppHello = NULL;

    hr = QueryInterface(IID_IDispatch, (void FAR* FAR*)ppHello);

    if (FAILED(hr))

        return RaiseException(IDS_Unexpected);

    return NOERROR;

}

STDMETHODIMP

CHello::put_Visible(VARIANT_BOOL bVisible)

{

    ShowWindow(bVisible ? SW_SHOW : SW_HIDE);

    return NOERROR;

}

STDMETHODIMP

CHello::get_Visible(VARIANT_BOOL FAR* pbool)

{

    *pbool =  m_bVisible;

    return NOERROR;

}

STDMETHODIMP

CHello::Quit()

{

    // CoDisconnectObject has no effect for an inproc server.  So the controller

    // will GP fault if it attempts to access the object (including calling IUnknown::Release())

    // after Quit has been called. For a local server, CoDisconnectObject will disconnect

    // the object from external connections. So the controller will get an RPC error if

    // it accesses the object after calling Quit and controller will not GP fault.

    CoDisconnectObject((LPUNKNOWN)this, 0);

    PostMessage(m_hwnd, WM_CLOSE, 0, 0L);

    return NOERROR;

}

/*

 * CHello::put_HelloMessage, get_HelloMessage, SayHello

 *

 * Purpose:

 *  Implements the HelloMessage property and the SayHello method.

 *

 */

STDMETHODIMP

CHello::put_HelloMessage(BSTR bstrMessage)

{

    SysReAllocString(&m_bstrHelloMsg, bstrMessage);

    return NOERROR;

}

STDMETHODIMP

CHello::get_HelloMessage(BSTR FAR* pbstrMessage)

{

    *pbstrMessage = SysAllocString(m_bstrHelloMsg);

    return NOERROR;

}

STDMETHODIMP

CHello::SayHello()

{

    SetDlgItemText(m_hwnd, IDC_HELLODISPLAY, FROM_OLE_STRING(m_bstrHelloMsg));

    return NOERROR;

}

STDMETHODIMP_(void)

CHello::ShowWindow(int nCmdShow)

{

    // Return if curently hidden and asked to hide or currently visible

    // and asked to show.

    if ((!m_bVisible && nCmdShow == SW_HIDE) || (m_bVisible && nCmdShow != SW_HIDE))

        return;

    m_bVisible = (nCmdShow == SW_HIDE) ? FALSE : TRUE;

    // The Automation object shutdown behavior is as follows:

    // 1. If the object application is visible, it shuts down only in response to an

    // explicit user command (File/Exit) or it's programmatic equivalent (for example

    // the Quit method of the Application object).

    // 2. If the object application is not visible, it goes away when it's last

    // object is released.

    //

    // CoLockObjectExternal can be used to increment the ref count of the application object

    // when it is visible. This will implement shutdown behavior 1. When the application

    // goes invisible, CoLockObjectExternal is used to decrement the ref count. This will

    // implement shutdown behavior 2.

    if (m_bVisible)

        CoLockObjectExternal(this, TRUE /*fLock*/, TRUE/*ignored when fLock==TRUE*/);

    else CoLockObjectExternal(this, FALSE/*fLock*/, TRUE/*fLastLockReleases*/);

    ::ShowWindow (m_hwnd, nCmdShow);

}

/*

 * CHello::RaiseException

 *

 * Purpose:

 *  Fills the EXCEPINFO structure and signal IDispatch::Invoke to return DISP_E_EXCEPTION.

 *  Sets ErrorInfo object for vtable-binding controllers.

 *

 */

STDMETHODIMP

CHello::RaiseException(int nID)

{

    extern SCODE g_scodes[];

    TCHAR szError[STR_LEN];

    ICreateErrorInfo *pcerrinfo;

    IErrorInfo *perrinfo;

    HRESULT hr;

    _fmemset(&m_excepinfo, 0, sizeof(EXCEPINFO));

    m_excepinfo.wCode = nID;

    if (LoadString(m_hinst, nID, szError, sizeof(szError)))

        m_excepinfo.bstrDescription = SysAllocString(TO_OLE_STRING(szError));

    m_excepinfo.bstrSource = SysAllocString(m_bstrProgID);

    m_bRaiseException = TRUE;

    // Set ErrInfo object so that vtable binding containers can get

    // rich error information.

    hr = CreateErrorInfo(&pcerrinfo);

    if (SUCCEEDED(hr))

    {

       pcerrinfo->SetGUID(IID_IHello);

       if (m_excepinfo.bstrSource)

           pcerrinfo->SetSource(m_excepinfo.bstrSource);

       if (m_excepinfo.bstrDescription)

           pcerrinfo->SetDescription(m_excepinfo.bstrDescription);

       hr = pcerrinfo->QueryInterface(IID_IErrorInfo, (LPVOID FAR*) &perrinfo);

       if (SUCCEEDED(hr))

       {

          SetErrorInfo(0, perrinfo);

          perrinfo->Release();

       }

       pcerrinfo->Release();

    }

    return ResultFromScode(g_scodes[nID-1001]);

}

/*

 * ISupportErrorInfo implementation

 *

 */

CSupportErrorInfo::CSupportErrorInfo(IUnknown FAR* punkObject, REFIID riid)

{

    m_punkObject = punkObject;

    m_iid = riid;

}

STDMETHODIMP

CSupportErrorInfo::QueryInterface(REFIID iid, void FAR* FAR* ppv)

{

    return m_punkObject->QueryInterface(iid, ppv);

}

STDMETHODIMP_(ULONG)

CSupportErrorInfo::AddRef(void)

{

    return m_punkObject->AddRef();

}

STDMETHODIMP_(ULONG)

CSupportErrorInfo::Release(void)

{

    return m_punkObject->Release();

}

STDMETHODIMP

CSupportErrorInfo::InterfaceSupportsErrorInfo(REFIID riid)

{

    return (riid == m_iid) ? NOERROR : ResultFromScode(S_FALSE);

}


 HELLOCF.CPP   (HELLO OLE Sample)

/*************************************************************************

**

**    OLE Automation Hello 2.0 Application.

**

**    hellocf.cpp

**

**    CHelloCF (class factory) implementation

**

**     Written by Microsoft Product Support Services, Windows Developer Support

**    (c) Copyright Microsoft Corp. 1994 All Rights Reserved

**

*************************************************************************/

#include <windows.h>

#include <windowsx.h>

#ifdef WIN16

  #include <ole2.h>

  #include <compobj.h>

  #include <dispatch.h>

  #include <variant.h>

  #include <olenls.h>

#endif

#include "hello.h"

CHelloCF::CHelloCF(void)

{

    m_cRef = 0;

}

/*

 * CHelloCF::QueryInterface, AddRef, Release

 *

 * Purpose:

 *  Implements IUnknown::QueryInterface, AddRef, Release

 *

 */

STDMETHODIMP

CHelloCF::QueryInterface(REFIID iid, void FAR* FAR* ppv)

{

    *ppv = NULL;

    if (iid == IID_IUnknown || iid == IID_IClassFactory)

        *ppv = this;

    else

        return ResultFromScode(E_NOINTERFACE);

    AddRef();

    return NOERROR;

}

STDMETHODIMP_(ULONG)

CHelloCF::AddRef(void)

{

#ifdef _DEBUG

    TCHAR ach[50];

    wsprintf(ach, TEXT("Ref = %ld, Hello Class Factory\r\n"), m_cRef+1);

    OutputDebugString(ach);

#endif

    return ++m_cRef;

}

STDMETHODIMP_(ULONG)

CHelloCF::Release(void)

{

#ifdef _DEBUG

    TCHAR ach[50];

    wsprintf(ach, TEXT("Ref = %ld, Hello Class Factory\r\n"), m_cRef-1);

    OutputDebugString(ach);

#endif

    if(--m_cRef == 0)

    {

        delete this;

        return 0;

    }

    return m_cRef;

}

/*

 * CHelloCF::CreateInstance, LockServer

 *

 * Purpose:

 *  Implements IClassFactory::CreateInstance, LockServer

 *

 */

STDMETHODIMP

CHelloCF::CreateInstance(IUnknown FAR* punkOuter,

                         REFIID riid,

                         void FAR* FAR* ppv)

{

     HRESULT hr;

    *ppv = NULL;

    // This implementation does'nt allow aggregation

    if (punkOuter)

        return ResultFromScode(CLASS_E_NOAGGREGATION);

    // This is REGCLS_SINGLEUSE class factory, so CreateInstance will be

    // called atmost once. An application objects has a REGCLS_SINGLEUSE class

    // factory. The global application object has already been created when

    // CreateInstance is called. A REGCLS_MULTIPLEUSE class factory's

    // CreateInstance would be called multiple times and would create a new

    // object each time. An MDI application would have a REGCLS_MULTIPLEUSE

    // class factory for it's document objects.

    hr = g_phello->QueryInterface(riid, ppv);

    if (FAILED(hr))

    {

        g_phello->Quit();

        return hr;

    }

    return NOERROR;

}

STDMETHODIMP

CHelloCF::LockServer(BOOL fLock)

{

    CoLockObjectExternal(g_phello, fLock, TRUE);

    return NOERROR;

}


 MAIN.CPP   (HELLO OLE Sample)

/*************************************************************************

**

**    OLE Automation Hello 2.0 Application.

**

**    main.cpp

**

**     Written by Microsoft Product Support Services, Windows Developer Support

**    (c) Copyright Microsoft Corp. 1994 All Rights Reserved

**

*************************************************************************/

#include <windows.h>

#include <windowsx.h>

#ifdef WIN16

  #include <ole2.h>

  #include <compobj.h>

  #include <dispatch.h>

  #include <variant.h>

  #include <olenls.h>

#endif

#include <initguid.h>

#include "hello.h"

// Globals

CHello FAR* g_phello;

SCODE g_scodes[SCODE_COUNT] =          // Array of SCODEs for easy lookup

{

    HELLO_E_UNEXPECTED

};

/*

 * WinMain

 *

 * Purpose:

 *  Main entry point of application.

 *

 */

int APIENTRY WinMain (HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR pCmdLine, int nCmdShow)

{

    MSG msg;

    DWORD dwRegisterCF;

    DWORD dwRegisterActiveObject;

    //  It is recommended that all OLE applications set

    //  their message queue size to 96. This improves the capacity

    //  and performance of OLE's LRPC mechanism.

    int cMsg = 96;                  // Recommend msg queue size for OLE

    while (cMsg && !SetMessageQueue(cMsg))  // take largest size we can get.

        cMsg -= 8;

    if (!cMsg)

        return -1;                  // ERROR: we got no message queue

    if (!hinstPrev)

       if (!InitApplication(hinst)) // Register window class

          return FALSE;

    if (!InitInstance(hinst))   // Initialize OLE and create Hello application object

        return (FALSE);

    // Determine if /Automation was specified in command line and register class

    // factory and active object. Show window if application was started stand alone.

    if (!ProcessCmdLine(pCmdLine, &dwRegisterCF, &dwRegisterActiveObject, nCmdShow))

    {

       Uninitialize(dwRegisterCF, dwRegisterActiveObject);

       return (FALSE);

    }

    while (GetMessage(&msg, NULL, 0, 0))

    {

       TranslateMessage(&msg);

       DispatchMessage(&msg);

    }

    Uninitialize(dwRegisterCF, dwRegisterActiveObject);

    return (msg.wParam);

}

/*

 * InitApplication

 *

 * Purpose:

 *  Registers window class

 *

 * Parameters:

 *  hinst       hInstance of application

 *

 * Return Value:

 *  TRUE if initialization succeeded, FALSE otherwise.

 */

BOOL InitApplication (HINSTANCE hinst)

{

   WNDCLASS wc;

   wc.style = CS_DBLCLKS | CS_SAVEBITS | CS_BYTEALIGNWINDOW;

   wc.lpfnWndProc = MainWndProc;

   wc.cbClsExtra = 0;

   wc.cbWndExtra = DLGWINDOWEXTRA;

   wc.hInstance = hinst;

   wc.hIcon = LoadIcon(hinst, MAKEINTRESOURCE(IDI_ICON));

   wc.hCursor = LoadCursor(NULL, IDC_ARROW);

   wc.hbrBackground = HBRUSH(COLOR_WINDOW + 1);

   wc.lpszMenuName = NULL;

   wc.lpszClassName = TEXT("MainWndClass");

   return RegisterClass(&wc);

}

/*

 * InitInstance

 *

 * Purpose:

 *  Intializes OLE and creates Hello Application object

 *

 * Parameters:

 *  hinst           hInstance of application

 *

 * Return Value:

 *  TRUE if initialization succeeded, FALSE otherwise.

 */

BOOL InitInstance (HINSTANCE hinst)

{

    HRESULT hr;

    TCHAR ach[STR_LEN];

    // Intialize OLE

    hr = OleInitialize(NULL);

    if (FAILED(hr))

       return FALSE;

    // Create an instance of the Hello Application object. Object is

    // created with refcount 0.

    LoadString(hinst, IDS_HelloMessage, ach, sizeof(ach));

    hr = CHello::Create(hinst, ach, &g_phello);

    if (FAILED(hr))

        return FALSE;

    return TRUE;

}

/*

 * ProcessCmdLine

 *

 * Purpose:

 *  Check if command line contains /Automation. If so, the class factory of the

 *  application object is registered.  If not, the application was started stand-alone and

 *  so the window is shown. The application object is registered using RegisterActiveObject.

 *

 * Parameters:

 *  pCmdLine       Command line passed to application

 *  pdwRegisterCF   Returns id returned after class factory registration. Can be used to

 *                  revoke class factory registration.

 *  pdwRegisterActiveObject   Returns id returned after active object registration. Can be used to

 *                  revoke active object registration.

 *  nCmdShow        Specifies how window is to be shown if application was started stand alone.

 *

 * Return Value:

 *    TRUE if OLE initialization succeeded, FALSE otherwise.

 *

 */

BOOL ProcessCmdLine(LPSTR pCmdLine, LPDWORD pdwRegisterCF, LPDWORD pdwRegisterActiveObject, int nCmdShow)

{

   LPCLASSFACTORY pcf = NULL;

   HRESULT hr;

   *pdwRegisterCF = 0;

   *pdwRegisterActiveObject = 0;

   // Expose class factory for application object if command line contains the

   // Automation switch

   if (_fstrstr(pCmdLine, "-Automation") != NULL

       || _fstrstr(pCmdLine, "/Automation") != NULL)

   {

       pcf = new CHelloCF;

       if (!pcf)

           goto error;

       pcf->AddRef();

       hr = CoRegisterClassObject(CLSID_Hello, pcf,

                                     CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE,

                                     pdwRegisterCF);

       if (hr != NOERROR)

           goto error;

       pcf->Release();

   }

   else g_phello->ShowWindow(nCmdShow);    // Show window if started stand-alone

   // Register Hello application object in the Running Object Table (ROT). This

   // allows controllers to connect to a running application object instead of creating

   // a new instance. Use weak registration so that the ROT releases it's reference when

   // all external references are released. If strong registration is used, the ROT will not

   // release it's reference until RevokeActiveObject is called and so will keep

   // the object alive even after all external references have been released.

   RegisterActiveObject(g_phello, CLSID_Hello, ACTIVEOBJECT_WEAK, pdwRegisterActiveObject);

   return TRUE;

error:

    if (pcf)

        pcf->Release();

    return FALSE;

}

/*

 * Uninitialize

 *

 *  Purpose:

 *   Revoke class factory and active object registration and uninitialize OLE.

 *

 * Parameters:

 *  dwRegisterCF ID returned after class factory registration.

 *  dwRegisterActiveObject ID returned after active object registration.

 *

 */

void Uninitialize(DWORD dwRegisterCF, DWORD dwRegisterActiveObject)

{

    if (dwRegisterCF != 0)

        CoRevokeClassObject(dwRegisterCF);

    if (dwRegisterActiveObject != 0)

        RevokeActiveObject(dwRegisterActiveObject, NULL);

    OleUninitialize();

}

/*

 * MainWndProc

 *

 * Purpose:

 *  Window procedure for main window. The main window is a dialog.

 *

 */

LRESULT CALLBACK MainWndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)

{

   switch (msg)

   {

      case WM_COMMAND:

      {

          switch(GET_WM_COMMAND_ID(wParam, lParam))

          {

              case IDC_SAYHELLO:

                  g_phello->SayHello();

                  break;

              case IDC_HELLODISPLAY:

                  switch(GET_WM_COMMAND_CMD(wParam, lParam))

                  {

                      TCHAR ach[100];

                      case EN_CHANGE:

                      // Update HelloMsg property of Hello object corresponding to this

                       // window when the contents of the edit control change.

                       GetDlgItemText(hwnd, IDC_HELLODISPLAY, ach, 100);

                       g_phello->put_HelloMessage(TO_OLE_STRING(ach));

                  }

                  return 0L;

                  default:

                      return 0L;

                  break;

          }

      }

      break;

      case WM_CLOSE:

         // Hide the window to release the refcount added by CoLockObjectExternal

         // (See CHello::ShowWindow)

         g_phello->ShowWindow(SW_HIDE);

         return DefDlgProc(hwnd, msg, wParam, lParam);

         break;

      case WM_DESTROY:

         PostQuitMessage(0);

         break;

      default:

         return DefDlgProc(hwnd, msg, wParam, lParam);

   }

   return NULL;

}

/*

 * LoadTypeInfo

 *

 *  Purpose:

 *   Gets type information of an object's interface from type library.

 *

 * Parameters:

 *  ppunkStdDispatch    Returns type information.

 *  clsid               Interface id of object in type library.

 *

 * Return Value:

 *  HRESULT

 *

 */

HRESULT LoadTypeInfo(ITypeInfo FAR* FAR* pptinfo, REFCLSID clsid)

{

    HRESULT hr;

    LPTYPELIB ptlib = NULL;

    LPTYPEINFO ptinfo = NULL;

    *pptinfo = NULL;

    // Load Type Library.

    hr = LoadRegTypeLib(LIBID_Hello, 2, 0, 0x0409, &ptlib);

    if (FAILED(hr))

    {

        // if it wasn't registered, try to load it from the path

        // if this succeeds, it will have registered the type library for us

        // for the next time.

        hr = LoadTypeLib(OLESTR("hello.tlb"), &ptlib);

        if(FAILED(hr))

            return hr;

    }

    // Get type information for interface of the object.

    hr = ptlib->GetTypeInfoOfGuid(clsid, &ptinfo);

    if (FAILED(hr))

    {

        ptlib->Release();

        return hr;

    }

    ptlib->Release();

    *pptinfo = ptinfo;

    return NOERROR;

}

#ifdef WIN32

#ifndef UNICODE

char* ConvertToAnsi(OLECHAR FAR* szW)

{

  static char achA[STRCONVERT_MAXLEN];

  WideCharToMultiByte(CP_ACP, 0, szW, -1, achA, STRCONVERT_MAXLEN, NULL, NULL);

  return achA;

}

OLECHAR* ConvertToUnicode(char FAR* szA)

{

  static OLECHAR achW[STRCONVERT_MAXLEN];

  MultiByteToWideChar(CP_ACP, 0, szA, -1, achW, STRCONVERT_MAXLEN);

  return achW;

}

#endif

#endif


 LINES

SAMPLE: Lines: OLE Automation Server that implements collections

LINES is an OLE Automation server application that implements collections.   LINES allows a collection on lines to be drawn on a pane using OLE Automation. It exposes the following objects.

Application object:

 Properties
   Application
   FullName
   Name
   Pane	        Returns the pane in the drawing window.
   Parent
   Visible
 Methods
   CreateLine	Returns a newly created Line object with no start or end point.
   CreatePoint	Returns a newly created Point object initialized to (0,0).

Pane object:  Properties
   Lines	Returns a collection of all of the Line objects in the drawing.
   Points	Returns a collection of all of the Point objects in the drawing.
   MaxX	        Returns the maximum visible X coordinate value in twips.
   MaxY	        Returns the maximum visible Y coordinate value in twips.
 Methods
   Clear        Removes all of the Lines and Points from the drawing and refreshes the client area.                   The result is a blank slate, as if the application had just been launched.
   Refresh      Clears the drawing area and redraws each of the lines in the Lines collection.

Line object:

 Properties
   Color	An RGB color.
   EndPoint	A Point object inidcating the end point for the line.
   StartPoint	A Point object indicating the start point for the line.
   Thickness	A thickness, represented in twips.

Point object:

 Properties
   x
   y

Lines collection:  Standard collection properties and methods.  Objects that are added must be of type Line.    Objects returned are of type Line.
 Add and Remove cause redrawing of the pane.
 Adding a line causes two points to be added to the Points collection.
 Removing a line may cause one or more points to be removed from the points collection.

Points collection:

 Standard collection properties and methods. Objects returned are of type Point.
 This collection does not allow addition and removal of members.
 The Points collection does not have duplicates. If there are two lines in the drawing
 which share an end point (x, y), (x, y) only appears in the collection once.

The sample the following features:

· Supports dual interfaces which allows access of automation properties and methods through   vtable binding and through IDispatch.
· Provides Rich Error information for vtable-binding controllers. This is does by implementing   ISupportErrorInfo and using IErrorInfo.
· Implements 2 collections. · Implements active object registration using RegisterActiveObject and RevokeActiveObject.  · Implements correct shut-down behavior.  · Includes a .reg file which contains Lines.Application as progID. · When created for automation, is invisible initially.

To compile: -----------

Requires OLE 2.02 or later. Use the external makefile called makefile to compile.  In Win16, run the WXSRVER.EXE from \OLE2\BIN before running the makefile. The makefile invokes mktyplib.exe that reads lines.odl and creates the type library, lines.tlb. It then compliles the source files.

To run: -------

Change lines.reg to provide the full path of lines.exe and lines.tlb.  Register lines.reg in the registration database by double-clicking it. The VB directory contains VB 3.0 files to control this sample. Load vb.mak into VB 3.0 and run. This will launch and control LINES. VB 3.0 uses late binding (not vtable-binding) to control LINES. A vtable-binding controller for LINES can be built along the lines of the HELLCTRL sample.

Files: ------

LINES.ODL   Object description language that describes the objects that LINES exposes. TLB.H       Header file generated by mktyplib.exe MAKEFILE    Makefile for project.

Other files implement the LINES automation server. ===========================================================================


 MAKEFILE   (LINES OLE Sample)

####

#makefile - makefile for lines.exe

#

#       Copyright (C) 1994, Microsoft Corporation

#

#Purpose:

#  Builds the OLE 2.0 Automation object, lines.exe.

#

#

#  Usage: NMAKE                 ; build with defaults

#     or: NMAKE option          ; build with the given option(s)

#     or: NMAKE clean           ; erase all compiled files

#

#     option: dev = [win16 | win32]    ; dev=win32 is the default

#             DEBUG=[0 | 1]            ; DEBUG=1 is the default

#             HOST=[DOS | NT | WIN95]  ; HOST=DOS (for win16)

#                                      ; HOST=NT (for win32 on NT)

#                                      ; HOST=WIN95 (for win32 on Win95)

#

#Notes:

#  This makefile assumes that the PATH, INCLUDE and LIB environment

#  variables are setup properly.

#

##############################################################################

##########################################################################

#

# Default Settings

#

CPU = i386

!if "$(dev)" == ""

dev = win32

HOST = NT

!endif

!if !("$(dev)" == "win16" || "$(dev)" == "win32")

!error Invalid dev option, choose from [win16 | win32]

!endif

!if "$(dev)" == "win16"

TARGET  = WIN16

!if "$(HOST)" == ""

HOST  = DOS

!endif

!endif

!if "$(dev)" == "win32"

TARGET  = WIN32

!if "$(HOST)" == ""

HOST  = NT

!endif

!endif

!ifdef NODEBUG

DEBUG = 0

!endif

!if "$(DEBUG)" == "0"

NODEBUG = 1

!endif

!if "$(DEBUG)" == ""

DEBUG = 1

!endif

##########################################################################

#

# WIN16 Settings

#

!if "$(TARGET)" == "WIN16"

CC   = cl

LINK = link

!if "$(HOST)" == "DOS"

WX   = wx /w

!else

WX   =

!endif

RCFLAGS = -dWIN16

CFLAGS = -c -W3 -AM -GA -GEs -DWIN16

LINKFLAGS = /NOD /NOI /BATCH /ONERROR:NOEXE

LIBS = libw.lib mlibcew.lib

!if "$(DEBUG)" == "1"

CFLAGS = $(CFLAGS) -Od -Zi -D_DEBUG $(CL)

LINKFLAGS = $(LINKFLAGS) /COD

!else

CFLAGS = $(CFLAGS) -Ox $(CL)

LINKFLAGS = $(LINKFLAGS) /FAR /PACKC

!endif

!endif

##########################################################################

#

# WIN32 Settings

#

!if "$(TARGET)" == "WIN32"

WX =

!include <ntwin32.mak>

CC = $(cc)

CFLAGS = $(cflags) $(cvarsmt) -DINC_OLE2 $(cdebug)

!if "$(HOST)" == "NT"

CFLAGS = $(CFLAGS) -DUNICODE

!endif

!ifndef NODEBUG

CFLAGS = $(CFLAGS) -D_DEBUG

!endif

LINK = $(link)

LINKFLAGS = $(linkdebug) $(guilflags)

RCFLAGS = -DWIN32

!endif

##########################################################################

#

# Build rules

#

.cpp.obj:

    @echo Compiling $<...

    $(CC) $<

.c.obj:

    @echo Compiling $<...

    $(CC) $<

##########################################################################

#

# Application Settings

#

APPS = lines

!if "$(TARGET)" == "WIN16"

LIBS = ole2.lib compobj.lib ole2disp.lib typelib.lib commdlg.lib $(LIBS)

!endif

!if "$(TARGET)" == "WIN32"

LIBS = $(ole2libsmt)

!endif

OBJS = main.obj app.obj appcf.obj pane.obj line.obj point.obj lines.obj points.obj \

       enumvar.obj errinfo.obj

##########################################################################

#

# Default Goal

#

goal : setflags $(APPS).exe

setflags :

    set CL=$(CFLAGS)

##########################################################################

#

# Clean (erase) generated files

#

clean :

    if exist *.obj       del *.obj

    if exist $(APPS).exe del $(APPS).exe

    if exist $(APPS).tlb del $(APPS).tlb

    if exist $(APPS).map del $(APPS).map

    if exist $(APPS).res del $(APPS).res

    if exist tlb.h       del tlb.h

    if exist *.log       del *.log

    if exist *.pdb       del *.pdb

##########################################################################

#

# Application Build (WIN16 Specific)

#

!if "$(TARGET)" == "WIN16"

$(APPS).exe : $(OBJS) $(APPS).def $(APPS).res $(APPS).ico

    link $(LINKFLAGS) @<<

$(OBJS),

$@,,

$(LIBS),

$(APPS).def

<<

    rc -k -t $(APPS).res $@

!endif

##########################################################################

#

# Application Build (WIN32 Specific)

#

!if "$(TARGET)" == "WIN32"

$(APPS).exe : $(OBJS) $(APPS).def $(APPS).res $(APPS).ico

      $(LINK) @<<

        $(LINKFLAGS)

        -out:$@

        -map:$*.map

        $(OBJS)

        $(APPS).res

        $(LIBS)

<<

!endif

##########################################################################

#

# Application Build (Common)

#

$(APPS).res : $(APPS).rc

    rc $(RCFLAGS) -r -fo$@ $?

##########################################################################

#

# Dependencies

#

tlb.h : lines.odl

     if exist tlb.h  del tlb.h

     if exist lines.tlb  del lines.tlb

     $(WX) mktyplib /D$(TARGET) /h tlb.h /o lines.log /tlb lines.tlb lines.odl

     type lines.log

main.obj : main.cpp lines.h tlb.h

     $(CC) main.cpp

app.obj : app.cpp lines.h tlb.h

     $(CC) app.cpp

appcf.obj : appcf.cpp lines.h tlb.h

     $(CC) appcf.cpp

pane.obj : pane.cpp lines.h tlb.h

     $(CC) pane.cpp

line.obj : line.cpp lines.h tlb.h

     $(CC) line.cpp

point.obj : point.cpp lines.h tlb.h

     $(CC) point.cpp

lines.obj : lines.cpp lines.h tlb.h

     $(CC) lines.cpp

points.obj : points.cpp lines.h tlb.h

     $(CC) points.cpp

enumvar.obj : enumvar.cpp lines.h tlb.h

     $(CC) enumvar.cpp

errinfo.obj : errinfo.cpp lines.h tlb.h

     $(CC) errinfo.cpp


 LINES.H   (LINES OLE Sample)

#ifdef WIN32

#ifdef UNICODE

    #define FROM_OLE_STRING(str) str

    #define TO_OLE_STRING(str) str

#else

    #define FROM_OLE_STRING(str) ConvertToAnsi(str)

    char* ConvertToAnsi(OLECHAR FAR* szW);

    #define TO_OLE_STRING(str) ConvertToUnicode(str)

    OLECHAR* ConvertToUnicode(char FAR* szA);

    // Maximum length of string that can be converted between Ansi & Unicode

    #define STRCONVERT_MAXLEN 300

#endif

#else  // WIN16

  #define APIENTRY far pascal

  #define TCHAR char

  #define TEXT(sz) sz

  #define FROM_OLE_STRING(str) str

  #define TO_OLE_STRING(str) str

  #define LPTSTR LPSTR

  // Windows NT defines the following in windowsx.h

  #define GET_WM_COMMAND_ID(w,l) (w)

  #define GET_WM_COMMAND_CMD(w,l) HIWORD(l)

  #define GET_WM_COMMAND_HWND(w,l) LOWORD(l)

#endif

#include "tlb.h"

#define STRICT

// Menu IDs

#define IDM_DRAWLINE  101

#define IDM_CLEAR     102

#define IDM_EXIT      103

// Dialog ID

#define IDD_DRAWLINE  101

// Icon ID

#define IDI_ICON      102

// Dialog Control IDs

#define IDC_THICKNESS     101

#define IDC_CHOOSECOLOR   102

#define IDC_STARTPOINT_X  103

#define IDC_STARTPOINT_Y  104

#define IDC_ENDPOINT_X    105

#define IDC_ENDPOINT_Y    106

#define IDC_STATIC         -1

// MAX len of string table entries

#define STR_LEN   200

// String table constants

#define IDS_Name                   1

#define IDS_ErrorLoadingTypeLib    2

#define IDS_ProgID                 3

#define IDS_Unexpected             1001

#define IDS_OutOfMemory            1002

#define IDS_InvalidIndex           1003

#define IDS_CollectionFull         1004

#define IDS_LineFromOtherInstance  1005

#define IDS_CantAddEndPoints       1006

#define IDS_PointFromOtherInstance 1007

#define IDS_NoVisibleXCoordinate   1008

#define IDS_NoVisibleYCoordinate   1009

#define IDS_NoStartPoint           1010

#define IDS_NoEndPoint             1011

// SCODEs for the Lines Application. This is required for vtable-binding

// Automation objects want to return custom HRESULTs. All the OLE-defined

// FACILITY_ITF codes have a code value which lies in the region 0x0000-0x01FFF.

// While it is legal for the definer to use any code, it is highly recommended

// that only code values in the range 0x0200-0xFFFF be used, as this will reduce the

// possiblity of accidental confusion with any OLE-defined errors.

#define LINES_E_FIRST MAKE_SCODE(SEVERITY_ERROR, FACILITY_ITF, 0x0200)

#define LINES_E_UNEXPECTED              (LINES_E_FIRST + 0x0)

// Unexpected error

#define LINES_E_OUTOFMEMORY             (LINES_E_FIRST + 0x1)

// Out of memory

#define LINES_E_INVALIDINDEX            (LINES_E_FIRST + 0x2)

// Invalid index to Points or Lines collections

#define LINES_E_COLLECTIONFULL          (LINES_E_FIRST + 0x3)

// Points or Lines collection is full

#define LINES_E_LINEFROMOTHERINSTANCE   (LINES_E_FIRST + 0x4)

// Line from another instance of this application cannot be added.

#define LINES_E_CANTADDENDPOINTS        (LINES_E_FIRST + 0x5)

// End points of line cannot be added to collection. (Make sure line has two end points).

#define LINES_E_POINTFROMOTHERINSTANCE  (LINES_E_FIRST + 0x6)

// Point from another instance of this application cannot be added.

#define LINES_E_NOVISIBLEXCOORDINATE    (LINES_E_FIRST + 0x7)

// No visible X coordinate.

#define LINES_E_NOVISIBLEYCOORDINATE    (LINES_E_FIRST + 0x8)

// No visible Y coordinate.

#define LINES_E_NOSTARTPOINT            (LINES_E_FIRST + 0x9)

// Line does not have a start point.

#define LINES_E_NOENDPOINT              (LINES_E_FIRST + 0xA)

// Line does not have an end point.

// Number of SCODEs

#define SCODE_COUNT 11

// Function prototypes

int APIENTRY WinMain (HINSTANCE, HINSTANCE, LPSTR, int);

BOOL InitApplication (HINSTANCE);

BOOL InitInstance (HINSTANCE);

BOOL ProcessCmdLine(LPSTR pCmdLine, LPDWORD pdwRegisterCF, LPDWORD pdwRegisterActiveObject, int nCmdShow);

void Uninitialize(DWORD dwRegisterCF, DWORD dwRegisterActiveObject);

HRESULT LoadTypeInfo(ITypeInfo FAR* FAR* pptinfo, REFCLSID clsid);

#ifdef WIN16

extern "C" LRESULT __export CALLBACK MainWndProc (HWND, UINT, WPARAM, LPARAM);

extern "C" BOOL __export CALLBACK DrawLineDialogFunc(HWND, UINT, WPARAM, LPARAM);

#else

extern "C" LRESULT CALLBACK MainWndProc (HWND, UINT, WPARAM, LPARAM);

extern "C" BOOL CALLBACK DrawLineDialogFunc(HWND, UINT, WPARAM, LPARAM);

#endif

// Class definitions

class CPane;

class CLine;

class CPoint;

class CLines;

class CPoints;

// ISupportErrorInfo interface implementation

interface CSupportErrorInfo : public ISupportErrorInfo

{

public:

    // IUnknown methods

    STDMETHOD(QueryInterface)(REFIID riid, LPVOID FAR* ppvObj);

    STDMETHOD_(ULONG, AddRef)(void);

    STDMETHOD_(ULONG, Release)(void);

    // ISupportErrorInfo method

    STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid);

    CSupportErrorInfo(IUnknown FAR* punkObject, REFIID riid);

private:

    LPUNKNOWN m_punkObject;  // IUnknown of Object that implements this interface

    GUID m_iid;

};

class FAR CApplicationCF : public IClassFactory

{

public:

    // IUnknown methods

    STDMETHOD(QueryInterface)(REFIID riid, LPVOID FAR* ppvObj);

    STDMETHOD_(ULONG, AddRef)(void);

    STDMETHOD_(ULONG, Release)(void);

    // IClassFactory methods

    STDMETHOD(CreateInstance)(IUnknown FAR* punkOuter, REFIID riid,

                              void FAR* FAR* ppv);

    STDMETHOD(LockServer)(BOOL fLock);

    CApplicationCF();

private:

    ULONG m_cRef;                   // Reference count

};

class FAR CApplication : public IApplication

{

public:

    /* IUnknown methods */

    STDMETHOD(QueryInterface)(REFIID riid, LPVOID FAR* ppvObj);

    STDMETHOD_(ULONG, AddRef)();

    STDMETHOD_(ULONG, Release)();

    /* IDispatch methods */

    STDMETHOD(GetTypeInfoCount)(UINT FAR* pctinfo);

    STDMETHOD(GetTypeInfo)(

      UINT itinfo,

      LCID lcid,

      ITypeInfo FAR* FAR* pptinfo);

    STDMETHOD(GetIDsOfNames)(

      REFIID riid,

      OLECHAR FAR* FAR* rgszNames,

      UINT cNames,

      LCID lcid,

      DISPID FAR* rgdispid);

    STDMETHOD(Invoke)(

      DISPID dispidMember,

      REFIID riid,

      LCID lcid,

      WORD wFlags,

      DISPPARAMS FAR* pdispparams,

      VARIANT FAR* pvarResult,

      EXCEPINFO FAR* pexcepinfo,

      UINT FAR* puArgErr);

    /* IApplication automation exposed properties and methods */

    STDMETHOD(get_Application)(IApplication FAR* FAR* ppApplication);

    STDMETHOD(get_FullName)(BSTR FAR* pbstr);

    STDMETHOD(get_Name)(BSTR FAR* pbstr);

    STDMETHOD(get_Parent)(IApplication FAR* FAR* ppApplication);

    STDMETHOD(put_Visible)(VARIANT_BOOL bVisible);

    STDMETHOD(get_Visible)(VARIANT_BOOL FAR* pbVisible);

    STDMETHOD(Quit)();

    STDMETHOD(get_Pane)(IPane FAR* FAR* ppPane);

    STDMETHOD(CreateLine)(ILine FAR* FAR* ppLine);

    STDMETHOD(CreatePoint)(IPoint FAR* FAR* ppPoint);

    /* CApplication methods */

    STDMETHOD_(void, Draw)();

    STDMETHOD_(void, OnSize)(unsigned int nWidth, unsigned int nHeight);

    STDMETHOD_(void, ShowWindow)(int nCmdShow);

    STDMETHOD_(void, CreateAndDrawLine)();

    STDMETHOD_(void, ClearPane)();

    STDMETHOD(RaiseException)(int nID);

    static HRESULT Create(HWND hwnd, CApplication FAR* FAR* ppApplication); // Creates and intializes Applicaton object

    CApplication();

    ~CApplication();

public:

    HWND m_hwnd;                   // Application window.

    HINSTANCE m_hinst;             // Hinstance of application.

    BSTR m_bstrName;               // Name of application.

BSTR m_bstrProgID;             // ProgID of application.

    BOOL m_bUserClosing;           // User is closing the application.

private:

    LPTYPEINFO m_ptinfo;           // Type information of IApplication interface.

    BSTR m_bstrFullName;           // Full name of application.

    BOOL m_bVisible;               // Is window visible?

    CPane FAR* m_pPane;            // Pointer to the Pane object.

    EXCEPINFO m_excepinfo;         // Information to raise an exception on error.

    BOOL m_bRaiseException;        // Properties and methods use this to signal that an exception is to be raised.

    ULONG m_cRef;                  // Reference count.

    CSupportErrorInfo m_SupportErrorInfo; // ISupportErrorInfo interface implementation

};

class FAR CPane : public IPane

{

public:

    /* IUnknown methods */

    STDMETHOD(QueryInterface)(REFIID riid, LPVOID FAR* ppvObj);

    STDMETHOD_(ULONG, AddRef)();

    STDMETHOD_(ULONG, Release)();

    /* IDispatch methods */

    STDMETHOD(GetTypeInfoCount)(UINT FAR* pctinfo);

    STDMETHOD(GetTypeInfo)(

      UINT itinfo,

      LCID lcid,

      ITypeInfo FAR* FAR* pptinfo);

    STDMETHOD(GetIDsOfNames)(

      REFIID riid,

      OLECHAR FAR* FAR* rgszNames,

      UINT cNames,

      LCID lcid,

      DISPID FAR* rgdispid);

    STDMETHOD(Invoke)(

      DISPID dispidMember,

      REFIID riid,

      LCID lcid,

      WORD wFlags,

      DISPPARAMS FAR* pdispparams,

      VARIANT FAR* pvarResult,

      EXCEPINFO FAR* pexcepinfo,

      UINT FAR* puArgErr);

    /* IPane automation exposed properties & methods */

    STDMETHOD(get_Lines)(ILines FAR* FAR* ppLines);

    STDMETHOD(get_Points)(IPoints FAR* FAR* ppPoints);

    STDMETHOD(get_MaxX)(int FAR* pnMaxX);

    STDMETHOD(get_MaxY)(int FAR* pnMaxY);

    STDMETHOD(Clear)();

    STDMETHOD(Refresh)();

    /* CPane methods */

    STDMETHOD_(void, Draw)();

    STDMETHOD_(void, OnSize)(unsigned int nWidth, unsigned int nHeight);

    STDMETHOD_(HDC,  GetDC)();

    STDMETHOD_(void, ReleaseDC)(HDC hdc);

    STDMETHOD_(void, InvalidateRect)(LPRECT prc);

    STDMETHOD_(void, Update)(void);

    STDMETHOD_(BOOL, AddPoint)(CPoint FAR* pPoint);

    STDMETHOD_(void, RemovePoint)(CPoint FAR* pPoint);

    STDMETHOD(RaiseException)(int nID);

    static HRESULT Create(HWND hwnd, CPane FAR* FAR* ppPane); // Creates and intializes Pane object

    CPane();

    ~CPane();

private:

    LPTYPEINFO m_ptinfo;           // Type information of IPane interface.

    HWND m_hwnd;                   // Main window.

    CLines FAR *m_pLines;          // Lines collection.

    CPoints FAR* m_pPoints;        // Points collection.

    int m_nMaxX;                   // Maximum visible X coordinate in twips.

    int m_nMaxY;                   // Maximum visible Y coordinate in twips.

    int m_nWidth;                  // Width of pane in twips.

    int m_nHeight;                 // Height of pane in twips.

    EXCEPINFO m_excepinfo;         // Information to raise an exception on error.

    BOOL m_bRaiseException;        // Properties and methods use this to signal that an exception is to be raised.

    ULONG m_cRef;                  // Reference count.

    CSupportErrorInfo m_SupportErrorInfo; // ISupportErrorInfo interface implementation

};

class FAR CLine : public ILine

{

public:

    /* IUnknown methods */

    STDMETHOD(QueryInterface)(REFIID riid, LPVOID FAR* ppvObj);

    STDMETHOD_(ULONG, AddRef)();

    STDMETHOD_(ULONG, Release)();

    /* IDispatch methods */

    STDMETHOD(GetTypeInfoCount)(UINT FAR* pctinfo);

    STDMETHOD(GetTypeInfo)(

      UINT itinfo,

      LCID lcid,

      ITypeInfo FAR* FAR* pptinfo);

    STDMETHOD(GetIDsOfNames)(

      REFIID riid,

      OLECHAR FAR* FAR* rgszNames,

      UINT cNames,

      LCID lcid,

      DISPID FAR* rgdispid);

    STDMETHOD(Invoke)(

      DISPID dispidMember,

      REFIID riid,

      LCID lcid,

      WORD wFlags,

      DISPPARAMS FAR* pdispparams,

      VARIANT FAR* pvarResult,

      EXCEPINFO FAR* pexcepinfo,

      UINT FAR* puArgErr);

    /* ILine automation exposed properties & methods */

    STDMETHOD(get_Color)(long FAR* plColorref);

    STDMETHOD(put_Color)(long lColorref);

    STDMETHOD(get_EndPoint)(IPoint FAR* FAR* ppPoint);

    STDMETHOD(putref_EndPoint)(IPoint FAR* pPoint);

    STDMETHOD(get_StartPoint)(IPoint FAR* FAR* ppPoint);

    STDMETHOD(putref_StartPoint)(IPoint FAR* pPoint);

    STDMETHOD(get_Thickness)(int FAR* pnThickness);

    STDMETHOD(put_Thickness)(int nThickness);

    /* CLine methods */

    STDMETHOD_(void, Draw)(HDC hdc);

    STDMETHOD_(void, GetInvalidateRect)(LPRECT prc);

    STDMETHOD_(BOOL, AddEndPointsToPane)(CPane FAR* pPane);

    STDMETHOD_(void, RemoveEndPointsFromPane)(CPane FAR* pPane);

    STDMETHOD(RaiseException)(int nID);

    static HRESULT Create(CLine FAR* FAR* ppLine); // Creates and intializes Line object

    CLine();

    ~CLine();

private:

    LPTYPEINFO m_ptinfo;           // Type information of ILine interface.

    COLORREF m_colorref;           // RGB color of line.

    CPoint FAR* m_pPointStart;     // Start point of line.

    CPoint FAR* m_pPointEnd;       // End point of line.

    int m_nThickness;              // Line thickness in twips.

    EXCEPINFO m_excepinfo;         // Information to raise an exception on error.

    BOOL m_bRaiseException;        // Properties and methods use this to signal that an exception is to be raised.

    ULONG m_cRef;                  // Reference count.

    CSupportErrorInfo m_SupportErrorInfo; // ISupportErrorInfo interface implementation

};

class FAR CPoint : public IPoint

{

public:

    /* IUnknown methods */

    STDMETHOD(QueryInterface)(REFIID riid, LPVOID FAR* ppvObj);

    STDMETHOD_(ULONG, AddRef)();

    STDMETHOD_(ULONG, Release)();

    /* IDispatch methods */

    STDMETHOD(GetTypeInfoCount)(UINT FAR* pctinfo);

    STDMETHOD(GetTypeInfo)(

      UINT itinfo,

      LCID lcid,

      ITypeInfo FAR* FAR* pptinfo);

    STDMETHOD(GetIDsOfNames)(

      REFIID riid,

      OLECHAR FAR* FAR* rgszNames,

      UINT cNames,

      LCID lcid,

      DISPID FAR* rgdispid);

    STDMETHOD(Invoke)(

      DISPID dispidMember,

      REFIID riid,

      LCID lcid,

      WORD wFlags,

      DISPPARAMS FAR* pdispparams,

      VARIANT FAR* pvarResult,

      EXCEPINFO FAR* pexcepinfo,

      UINT FAR* puArgErr);

    /* IPoint automation exposed properties & methods */

    STDMETHOD(get_x)(int FAR* pnX);

    STDMETHOD(put_x)(int nX);

    STDMETHOD(get_y)(int FAR* pnY);

    STDMETHOD(put_y)(int nY);

    /* CPoint methods */

    STDMETHOD_(ULONG, InternalAddRef)();

    STDMETHOD_(ULONG, InternalRelease)();

    STDMETHOD_(int, get_x)();

    STDMETHOD_(int, get_y)();

    static HRESULT Create(CPoint FAR* FAR* ppPoint); // Creates and intializes Point object

    CPoint();

    ~CPoint();

private:

    LPTYPEINFO m_ptinfo;           // Type information of IPoint interface.

    int m_nX;                      // X coordinate of point in twips.

    int m_nY;                      // Y coordinate of point in twips.

    ULONG m_cInternalRef;          // Reference count for the use of the Points collection only.

    ULONG m_cRef;                  // Reference count.

    CSupportErrorInfo m_SupportErrorInfo; // ISupportErrorInfo interface implementation

};

class FAR CLines : public ILines

{

public:

    /* IUnknown methods */

    STDMETHOD(QueryInterface)(REFIID riid, LPVOID FAR* ppvObj);

    STDMETHOD_(ULONG, AddRef)();

    STDMETHOD_(ULONG, Release)();

    /* IDispatch methods */

    STDMETHOD(GetTypeInfoCount)(UINT FAR* pctinfo);

    STDMETHOD(GetTypeInfo)(

      UINT itinfo,

      LCID lcid,

      ITypeInfo FAR* FAR* pptinfo);

    STDMETHOD(GetIDsOfNames)(

      REFIID riid,

      OLECHAR FAR* FAR* rgszNames,

      UINT cNames,

      LCID lcid,

      DISPID FAR* rgdispid);

    STDMETHOD(Invoke)(

      DISPID dispidMember,

      REFIID riid,

      LCID lcid,

      WORD wFlags,

      DISPPARAMS FAR* pdispparams,

      VARIANT FAR* pvarResult,

      EXCEPINFO FAR* pexcepinfo,

      UINT FAR* puArgErr);

    /* ILines automation exposed properties & methods */

    STDMETHOD(Add)(ILine FAR* pLine);

    STDMETHOD(get_Count)(long FAR* lCount);

    STDMETHOD(get_Item)(long lIndex, ILine FAR* FAR* ppLine);

    STDMETHOD(get__NewEnum)(IUnknown FAR* FAR* ppunkEnum);

    STDMETHOD(Remove)(long lIndex);

    /* CLines methods */

    STDMETHOD_(void, Draw)(HDC hdc);

    STDMETHOD_(void, Clear)();

    STDMETHOD(RaiseException)(int nID);

    static HRESULT Create(ULONG lMaxSize, long lLBound, CPane FAR* pPane, CLines FAR* FAR* ppLines); // Creates and intializes Lines object

    CLines();

    ~CLines();

private:

    LPTYPEINFO m_ptinfo;           // Type information of ILines interface.

    SAFEARRAY FAR *m_psa;          // Safe array that holds Lines collection items.

    ULONG m_cElements;             // Number of items in Lines collection.

    ULONG m_cMax;                  // Maximum number of items Lines collection can hold.

    long m_lLBound;                // Lower bound of index of Lines collection.

    CPane FAR* m_pPane;            // Pointer to the Pane object that contains this Lines collection.

    EXCEPINFO m_excepinfo;         // Information to raise an exception on error.

    BOOL m_bRaiseException;        // Properties and methods use this to signal that an exception is to be raised.

    ULONG m_cRef;                  // Reference count.

    CSupportErrorInfo m_SupportErrorInfo; // ISupportErrorInfo interface implementation

};

class FAR CPoints : public IPoints

{

public:

    /* IUnknown methods */

    STDMETHOD(QueryInterface)(REFIID riid, LPVOID FAR* ppvObj);

    STDMETHOD_(ULONG, AddRef)();

    STDMETHOD_(ULONG, Release)();

    /* IDispatch methods */

    STDMETHOD(GetTypeInfoCount)(UINT FAR* pctinfo);

    STDMETHOD(GetTypeInfo)(

      UINT itinfo,

      LCID lcid,

      ITypeInfo FAR* FAR* pptinfo);

    STDMETHOD(GetIDsOfNames)(

      REFIID riid,

      OLECHAR FAR* FAR* rgszNames,

      UINT cNames,

      LCID lcid,

      DISPID FAR* rgdispid);

    STDMETHOD(Invoke)(

      DISPID dispidMember,

      REFIID riid,

      LCID lcid,

      WORD wFlags,

      DISPPARAMS FAR* pdispparams,

      VARIANT FAR* pvarResult,

      EXCEPINFO FAR* pexcepinfo,

      UINT FAR* puArgErr);

    /* IPoints automation exposed properties & methods */

    STDMETHOD(get_Count)(long FAR* plCount);

    STDMETHOD(get_Item)(long lIndex, IPoint FAR* FAR* ppPoint);

    STDMETHOD(get__NewEnum)(IUnknown FAR* FAR* ppunkEnum);

    /* CPoints methods */

    STDMETHOD_(BOOL, Add)(CPoint FAR* pPointNew);

    STDMETHOD_(BOOL, Remove)(CPoint FAR* pPointRemove);

    STDMETHOD_(void, Clear)();

    STDMETHOD_(void, GetMaxXMaxY)(int FAR* pnX, int FAR* pnY, LPRECT prc);

    STDMETHOD(RaiseException)(int nID);

    static HRESULT Create(ULONG lMaxSize, long lLBound, CPane FAR* pPane, CPoints FAR* FAR* ppPoints); // Creates and intializes Points object

    CPoints();

    ~CPoints();

private:

    LPTYPEINFO m_ptinfo;           // Type information of IPoints interface.

    SAFEARRAY FAR *m_psa;          // Safe array that holds Points collection items.

    ULONG m_cElements;             // Number of items in Points collection.

    ULONG m_cMax;                  // Maximum number of items Points collection can hold.

    long m_lLBound;                // Lower bound of index of Points collection.

    CPane FAR* m_pPane;            // Pointer to the Pane object that contains this Points collection.

    EXCEPINFO m_excepinfo;         // Information to raise an exception on error.

    BOOL m_bRaiseException;        // Properties and methods use this to signal that an exception is to be raised.

    ULONG m_cRef;                  // Reference count.

    CSupportErrorInfo m_SupportErrorInfo; // ISupportErrorInfo interface implementation

};

class FAR CEnumVariant : public IEnumVARIANT

{

public:

    // IUnknown methods

    STDMETHOD(QueryInterface)(REFIID riid, LPVOID FAR* ppvObj);

    STDMETHOD_(ULONG, AddRef)();

    STDMETHOD_(ULONG, Release)();

    // IEnumVARIANT methods

    STDMETHOD(Next)(ULONG cElements, VARIANT FAR* pvar, ULONG FAR* pcElementFetched);

    STDMETHOD(Skip)(ULONG cElements);

    STDMETHOD(Reset)();

    STDMETHOD(Clone)(IEnumVARIANT FAR* FAR* ppenum);

    static HRESULT Create(SAFEARRAY FAR*, ULONG, CEnumVariant FAR* FAR*); // Creates and intializes Enumerator

    CEnumVariant();

    ~CEnumVariant();

private:

    ULONG m_cRef;           // Reference count

    ULONG m_cElements;      // Number of elements in enumerator.

    long m_lLBound;         // Lower bound of index.

    long m_lCurrent;        // Current index.

    SAFEARRAY FAR* m_psa;   // Safe array that holds elements.

};

// Structure filled by dialog from user input to create a line.

typedef struct _lineinfo

{

    COLORREF colorref;    // RGB color of line.

    POINT ptStart;        // Start point of line.

    POINT ptEnd;          // End point of line.

    int nThickness;       // Thickness of line.

} LINEINFO, FAR* LPLINEINFO;

extern CApplication FAR* g_pApplication;


 TLB.H   (LINES OLE Sample)

/* This header file machine-generated by mktyplib.exe */

/* Interface to type library: Lines */

#ifndef _Lines_H_

#define _Lines_H_

DEFINE_GUID(LIBID_Lines,0x3C591B20,0x1F13,0x101B,0xB8,0x26,0x00,0xDD,0x01,0x10,0x3D,0xE1);

DEFINE_GUID(IID_IPoint,0x3C591B25,0x1F13,0x101B,0xB8,0x26,0x00,0xDD,0x01,0x10,0x3D,0xE1);

/* Definition of interface: IPoint */

DECLARE_INTERFACE_(IPoint, IDispatch)

{

#ifndef NO_BASEINTERFACE_FUNCS

    /* IUnknown methods */

    STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE;

    STDMETHOD_(ULONG, AddRef)(THIS) PURE;

    STDMETHOD_(ULONG, Release)(THIS) PURE;

    /* IDispatch methods */

    STDMETHOD(GetTypeInfoCount)(THIS_ UINT FAR* pctinfo) PURE;

    STDMETHOD(GetTypeInfo)(

      THIS_

      UINT itinfo,

      LCID lcid,

      ITypeInfo FAR* FAR* pptinfo) PURE;

    STDMETHOD(GetIDsOfNames)(

      THIS_

      REFIID riid,

      OLECHAR FAR* FAR* rgszNames,

      UINT cNames,

      LCID lcid,

      DISPID FAR* rgdispid) PURE;

    STDMETHOD(Invoke)(

      THIS_

      DISPID dispidMember,

      REFIID riid,

      LCID lcid,

      WORD wFlags,

      DISPPARAMS FAR* pdispparams,

      VARIANT FAR* pvarResult,

      EXCEPINFO FAR* pexcepinfo,

      UINT FAR* puArgErr) PURE;

#endif

    /* IPoint methods */

    STDMETHOD(get_x)(THIS_ int FAR* retval) PURE;

    STDMETHOD(put_x)(THIS_ int Value) PURE;

    STDMETHOD(get_y)(THIS_ int FAR* retval) PURE;

    STDMETHOD(put_y)(THIS_ int Value) PURE;

};

DEFINE_GUID(IID_ILine,0x3C591B24,0x1F13,0x101B,0xB8,0x26,0x00,0xDD,0x01,0x10,0x3D,0xE1);

/* Definition of interface: ILine */

DECLARE_INTERFACE_(ILine, IDispatch)

{

#ifndef NO_BASEINTERFACE_FUNCS

    /* IUnknown methods */

    STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE;

    STDMETHOD_(ULONG, AddRef)(THIS) PURE;

    STDMETHOD_(ULONG, Release)(THIS) PURE;

    /* IDispatch methods */

    STDMETHOD(GetTypeInfoCount)(THIS_ UINT FAR* pctinfo) PURE;

    STDMETHOD(GetTypeInfo)(

      THIS_

      UINT itinfo,

      LCID lcid,

      ITypeInfo FAR* FAR* pptinfo) PURE;

    STDMETHOD(GetIDsOfNames)(

      THIS_

      REFIID riid,

      OLECHAR FAR* FAR* rgszNames,

      UINT cNames,

      LCID lcid,

      DISPID FAR* rgdispid) PURE;

    STDMETHOD(Invoke)(

      THIS_

      DISPID dispidMember,

      REFIID riid,

      LCID lcid,

      WORD wFlags,

      DISPPARAMS FAR* pdispparams,

      VARIANT FAR* pvarResult,

      EXCEPINFO FAR* pexcepinfo,

      UINT FAR* puArgErr) PURE;

#endif

    /* ILine methods */

    STDMETHOD(get_Color)(THIS_ long FAR* retval) PURE;

    STDMETHOD(put_Color)(THIS_ long rgb) PURE;

    STDMETHOD(get_EndPoint)(THIS_ IPoint FAR* FAR* retval) PURE;

    STDMETHOD(putref_EndPoint)(THIS_ IPoint FAR* Point) PURE;

    STDMETHOD(get_StartPoint)(THIS_ IPoint FAR* FAR* retval) PURE;

    STDMETHOD(putref_StartPoint)(THIS_ IPoint FAR* Point) PURE;

    STDMETHOD(get_Thickness)(THIS_ int FAR* retval) PURE;

    STDMETHOD(put_Thickness)(THIS_ int Value) PURE;

};

DEFINE_GUID(IID_ILines,0x3C591B26,0x1F13,0x101B,0xB8,0x26,0x00,0xDD,0x01,0x10,0x3D,0xE1);

/* Definition of interface: ILines */

DECLARE_INTERFACE_(ILines, IDispatch)

{

#ifndef NO_BASEINTERFACE_FUNCS

    /* IUnknown methods */

    STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE;

    STDMETHOD_(ULONG, AddRef)(THIS) PURE;

    STDMETHOD_(ULONG, Release)(THIS) PURE;

    /* IDispatch methods */

    STDMETHOD(GetTypeInfoCount)(THIS_ UINT FAR* pctinfo) PURE;

    STDMETHOD(GetTypeInfo)(

      THIS_

      UINT itinfo,

      LCID lcid,

      ITypeInfo FAR* FAR* pptinfo) PURE;

    STDMETHOD(GetIDsOfNames)(

      THIS_

      REFIID riid,

      OLECHAR FAR* FAR* rgszNames,

      UINT cNames,

      LCID lcid,

      DISPID FAR* rgdispid) PURE;

    STDMETHOD(Invoke)(

      THIS_

      DISPID dispidMember,

      REFIID riid,

      LCID lcid,

      WORD wFlags,

      DISPPARAMS FAR* pdispparams,

      VARIANT FAR* pvarResult,

      EXCEPINFO FAR* pexcepinfo,

      UINT FAR* puArgErr) PURE;

#endif

    /* ILines methods */

    STDMETHOD(Add)(THIS_ ILine FAR* NewLine) PURE;

    STDMETHOD(get_Count)(THIS_ long FAR* retval) PURE;

    STDMETHOD(get_Item)(THIS_ long Index, ILine FAR* FAR* retval) PURE;

    STDMETHOD(get__NewEnum)(THIS_ IUnknown * FAR* retval) PURE;

    STDMETHOD(Remove)(THIS_ long Index) PURE;

};

DEFINE_GUID(IID_IPoints,0x3C591B27,0x1F13,0x101B,0xB8,0x26,0x00,0xDD,0x01,0x10,0x3D,0xE1);

/* Definition of interface: IPoints */

DECLARE_INTERFACE_(IPoints, IDispatch)

{

#ifndef NO_BASEINTERFACE_FUNCS

    /* IUnknown methods */

    STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE;

    STDMETHOD_(ULONG, AddRef)(THIS) PURE;

    STDMETHOD_(ULONG, Release)(THIS) PURE;

    /* IDispatch methods */

    STDMETHOD(GetTypeInfoCount)(THIS_ UINT FAR* pctinfo) PURE;

    STDMETHOD(GetTypeInfo)(

      THIS_

      UINT itinfo,

      LCID lcid,

      ITypeInfo FAR* FAR* pptinfo) PURE;

    STDMETHOD(GetIDsOfNames)(

      THIS_

      REFIID riid,

      OLECHAR FAR* FAR* rgszNames,

      UINT cNames,

      LCID lcid,

      DISPID FAR* rgdispid) PURE;

    STDMETHOD(Invoke)(

      THIS_

      DISPID dispidMember,

      REFIID riid,

      LCID lcid,

      WORD wFlags,

      DISPPARAMS FAR* pdispparams,

      VARIANT FAR* pvarResult,

      EXCEPINFO FAR* pexcepinfo,

      UINT FAR* puArgErr) PURE;

#endif

    /* IPoints methods */

    STDMETHOD(get_Count)(THIS_ long FAR* retval) PURE;

    STDMETHOD(get_Item)(THIS_ long Index, IPoint FAR* FAR* retval) PURE;

    STDMETHOD(get__NewEnum)(THIS_ IUnknown * FAR* retval) PURE;

};

DEFINE_GUID(IID_IPane,0x3C591B23,0x1F13,0x101B,0xB8,0x26,0x00,0xDD,0x01,0x10,0x3D,0xE1);

/* Definition of interface: IPane */

DECLARE_INTERFACE_(IPane, IDispatch)

{

#ifndef NO_BASEINTERFACE_FUNCS

    /* IUnknown methods */

    STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE;

    STDMETHOD_(ULONG, AddRef)(THIS) PURE;

    STDMETHOD_(ULONG, Release)(THIS) PURE;

    /* IDispatch methods */

    STDMETHOD(GetTypeInfoCount)(THIS_ UINT FAR* pctinfo) PURE;

    STDMETHOD(GetTypeInfo)(

      THIS_

      UINT itinfo,

      LCID lcid,

      ITypeInfo FAR* FAR* pptinfo) PURE;

    STDMETHOD(GetIDsOfNames)(

      THIS_

      REFIID riid,

      OLECHAR FAR* FAR* rgszNames,

      UINT cNames,

      LCID lcid,

      DISPID FAR* rgdispid) PURE;

    STDMETHOD(Invoke)(

      THIS_

      DISPID dispidMember,

      REFIID riid,

      LCID lcid,

      WORD wFlags,

      DISPPARAMS FAR* pdispparams,

      VARIANT FAR* pvarResult,

      EXCEPINFO FAR* pexcepinfo,

      UINT FAR* puArgErr) PURE;

#endif

    /* IPane methods */

    STDMETHOD(get_Lines)(THIS_ ILines FAR* FAR* retval) PURE;

    STDMETHOD(get_Points)(THIS_ IPoints FAR* FAR* retval) PURE;

    STDMETHOD(get_MaxX)(THIS_ int FAR* retval) PURE;

    STDMETHOD(get_MaxY)(THIS_ int FAR* retval) PURE;

    STDMETHOD(Clear)(THIS) PURE;

    STDMETHOD(Refresh)(THIS) PURE;

};

DEFINE_GUID(IID_IApplication,0x3C591B22,0x1F13,0x101B,0xB8,0x26,0x00,0xDD,0x01,0x10,0x3D,0xE1);

/* Definition of interface: IApplication */

DECLARE_INTERFACE_(IApplication, IDispatch)

{

#ifndef NO_BASEINTERFACE_FUNCS

    /* IUnknown methods */

    STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE;

    STDMETHOD_(ULONG, AddRef)(THIS) PURE;

    STDMETHOD_(ULONG, Release)(THIS) PURE;

    /* IDispatch methods */

    STDMETHOD(GetTypeInfoCount)(THIS_ UINT FAR* pctinfo) PURE;

    STDMETHOD(GetTypeInfo)(

      THIS_

      UINT itinfo,

      LCID lcid,

      ITypeInfo FAR* FAR* pptinfo) PURE;

    STDMETHOD(GetIDsOfNames)(

      THIS_

      REFIID riid,

      OLECHAR FAR* FAR* rgszNames,

      UINT cNames,

      LCID lcid,

      DISPID FAR* rgdispid) PURE;

    STDMETHOD(Invoke)(

      THIS_

      DISPID dispidMember,

      REFIID riid,

      LCID lcid,

      WORD wFlags,

      DISPPARAMS FAR* pdispparams,

      VARIANT FAR* pvarResult,

      EXCEPINFO FAR* pexcepinfo,

      UINT FAR* puArgErr) PURE;

#endif

    /* IApplication methods */

    STDMETHOD(get_Application)(THIS_ IApplication FAR* FAR* retval) PURE;

    STDMETHOD(get_FullName)(THIS_ BSTR FAR* retval) PURE;

    STDMETHOD(get_Name)(THIS_ BSTR FAR* retval) PURE;

    STDMETHOD(get_Parent)(THIS_ IApplication FAR* FAR* retval) PURE;

    STDMETHOD(put_Visible)(THIS_ VARIANT_BOOL VisibleFlag) PURE;

    STDMETHOD(get_Visible)(THIS_ VARIANT_BOOL FAR* retval) PURE;

    STDMETHOD(Quit)(THIS) PURE;

    STDMETHOD(get_Pane)(THIS_ IPane FAR* FAR* retval) PURE;

    STDMETHOD(CreateLine)(THIS_ ILine FAR* FAR* retval) PURE;

    STDMETHOD(CreatePoint)(THIS_ IPoint FAR* FAR* retval) PURE;

};

DEFINE_GUID(CLSID_Lines,0x3C591B21,0x1F13,0x101B,0xB8,0x26,0x00,0xDD,0x01,0x10,0x3D,0xE1);

class Lines;

#endif


 APP.CPP   (LINES OLE Sample)

/*************************************************************************

**

**    OLE Automation Lines Object.

**

**    app.cpp

**

**    CApplication implementation

**

**     Written by Microsoft Product Support Services, Windows Developer Support

**    (c) Copyright Microsoft Corp. 1994 All Rights Reserved

**

*************************************************************************/

#include <windows.h>

#include <windowsx.h>

#ifdef WIN16

  #include <ole2.h>

  #include <compobj.h>

  #include <dispatch.h>

  #include <variant.h>

  #include <olenls.h>

#endif

#include "lines.h"

/*

 * CApplication::Create

 *

 * Purpose:

 *  Creates an instance of the Application automation object and initializes it.

 *

 * Parameters:

 *  hinst            HINSTANCE of application.

 *  ppApplication    Returns Application automation object.

 *

 * Return Value:

 *  HRESULT

 *

 */

HRESULT

CApplication::Create(HINSTANCE hinst, CApplication FAR* FAR* ppApplication )

{

    TCHAR ach[STR_LEN];

    TCHAR achFullName[260];

    HRESULT hr;

    CApplication FAR* pApplication = NULL;

    HWND hwnd;

    *ppApplication = NULL;

    // Create application object.

    pApplication = new CApplication();

    if (pApplication == NULL)

    {

        hr = ResultFromScode(E_OUTOFMEMORY);

        goto error;

    }

    LoadString(hinst, IDS_Name, ach, sizeof(ach));

    hwnd = CreateWindow(TEXT("MainWndClass"), ach,

                       WS_OVERLAPPEDWINDOW,

                       CW_USEDEFAULT, CW_USEDEFAULT,

                       650, 650,

                       NULL, NULL, hinst, NULL);

    if (!hwnd)

    {

       hr = ResultFromScode(E_OUTOFMEMORY);

       goto error;

    }

    pApplication->m_hwnd = hwnd;

    pApplication->m_hinst = hinst;

    // Set name and fullname of application.

    pApplication->m_bstrName = SysAllocString(TO_OLE_STRING(ach));

    if (NULL == pApplication->m_bstrName)

    {

        hr = ResultFromScode(E_OUTOFMEMORY);

        goto error;

    }

    GetModuleFileName(hinst, achFullName, sizeof(achFullName));

    pApplication->m_bstrFullName = SysAllocString(TO_OLE_STRING(achFullName));

    if (NULL == pApplication->m_bstrFullName)

    {

        hr = ResultFromScode(E_OUTOFMEMORY);

        goto error;

    }

    // ProgID

    LoadString(hinst, IDS_ProgID, ach, sizeof(ach));

    pApplication->m_bstrProgID = SysAllocString(TO_OLE_STRING(ach));

    if (NULL == pApplication->m_bstrProgID)

    {

        hr = ResultFromScode(E_OUTOFMEMORY);

        goto error;

    }

    // Load type information for the application object from type library.

    // If required, notify user on failure.

    hr = LoadTypeInfo(&pApplication->m_ptinfo, IID_IApplication);

    if (FAILED(hr))

    {

        LoadString(hinst, IDS_ErrorLoadingTypeLib, ach, sizeof(ach));

        MessageBox(NULL, ach, FROM_OLE_STRING(pApplication->m_bstrName), MB_OK);

        goto error;

    }

    // Create Pane

    hr = CPane::Create(hwnd, &pApplication->m_pPane);

    if (FAILED(hr))

       goto error;

    pApplication->m_pPane->AddRef();

    *ppApplication = pApplication;

    return NOERROR;

error:

    if (pApplication == NULL)

        return ResultFromScode(E_OUTOFMEMORY);

    if (pApplication->m_bstrFullName)

        SysFreeString(pApplication->m_bstrFullName);

    if (pApplication->m_bstrName)

        SysFreeString(pApplication->m_bstrName);

    if (pApplication->m_bstrProgID)

        SysFreeString(pApplication->m_bstrProgID);

    if (pApplication->m_ptinfo)

        pApplication->m_ptinfo->Release();

    if (pApplication->m_pPane)

        pApplication->m_pPane->Release();

    // Set to NULL to prevent destructor from attempting to free again

    pApplication->m_bstrFullName = NULL;

    pApplication->m_bstrName = NULL;

pApplication->m_bstrProgID = NULL;

    pApplication->m_ptinfo = NULL;

    pApplication->m_pPane = NULL;

    delete pApplication;

    return hr;

}

/*

 * CApplication::CApplication

 *

 * Purpose:

 *  Constructor for CApplication object. Initializes members to NULL.

 *

 */

#pragma warning (disable : 4355)

CApplication::CApplication() : m_SupportErrorInfo(this, IID_IApplication)

#pragma warning (default : 4355)

{

    extern ULONG g_cObj;

    m_hwnd = NULL;

    m_bstrFullName = NULL;

    m_bstrName = NULL;

m_bstrProgID = NULL;

    m_ptinfo = NULL;

    m_pPane = NULL;

    m_cRef = 0;

    m_bVisible = 0;

    m_bUserClosing = FALSE;

}

/*

 * CApplication::~CApplication

 *

 * Purpose:

 *  Destructor for CApplication object. Frees Application message BSTR and default

 *  IDispatch implementation. Closes the aplication.

 *

 */

CApplication::~CApplication()

{

     extern ULONG g_cObj;

     if (m_bstrFullName) SysFreeString(m_bstrFullName);

     if (m_bstrName) SysFreeString(m_bstrName);

     if (m_bstrProgID) SysFreeString(m_bstrProgID);

     if (m_ptinfo) m_ptinfo->Release();

     if (m_pPane) m_pPane->Release();

     if (!m_bUserClosing && IsWindow(m_hwnd)) DestroyWindow(m_hwnd);

}

/*

 * CApplication::QueryInterface, AddRef, Release

 *

 * Purpose:

 *  Implements IUnknown::QueryInterface, AddRef, Release

 *

 */

STDMETHODIMP

CApplication::QueryInterface(REFIID iid, void FAR* FAR* ppv)

{

    *ppv = NULL;

    if (iid == IID_IUnknown || iid == IID_IDispatch || iid == IID_IApplication)

        *ppv = this;

    else if (iid == IID_ISupportErrorInfo)

        *ppv = &m_SupportErrorInfo;

    else return ResultFromScode(E_NOINTERFACE);

    AddRef();

    return NOERROR;

}

STDMETHODIMP_(ULONG)

CApplication::AddRef(void)

{

#ifdef _DEBUG

    TCHAR ach[50];

    wsprintf(ach, TEXT("Ref = %ld, App\r\n"), m_cRef+1);

    OutputDebugString(ach);

#endif

    return ++m_cRef;

}

STDMETHODIMP_(ULONG)

CApplication::Release(void)

{

#ifdef _DEBUG

    TCHAR ach[50];

    wsprintf(ach, TEXT("Ref = %ld, App\r\n"), m_cRef-1);

    OutputDebugString(ach);

#endif

    if(--m_cRef == 0)

    {

        delete this;

        return 0;

    }

    return m_cRef;

}

/*

 * CApplication::GetTypeInfoCount

 *

 * Purpose:

 *  Implements IDispatch::GetTypeInfoCount.

 *

 */

STDMETHODIMP

CApplication::GetTypeInfoCount(UINT FAR* pctinfo)

{

    *pctinfo = 1;

    return NOERROR;

}

/*

 * CApplication::GetTypeInfo

 *

 * Purpose:

 *  Implements IDispatch::GetTypeInfo.

 *

 */

STDMETHODIMP

CApplication::GetTypeInfo(

      UINT itinfo,

      LCID lcid,

      ITypeInfo FAR* FAR* pptinfo)

{

    *pptinfo = NULL;

    if(itinfo != 0)

        return ResultFromScode(DISP_E_BADINDEX);

    m_ptinfo->AddRef();

    *pptinfo = m_ptinfo;

    return NOERROR;

}

/*

 * CApplication::GetIDsOfNames

 *

 * Purpose:

 *  Implements IDispatch::GetIDsOfNames.  The standard implementation, DispGetIDsOfNames,

 *  is used.

 *

 */

STDMETHODIMP

CApplication::GetIDsOfNames(

      REFIID riid,

      OLECHAR FAR* FAR* rgszNames,

      UINT cNames,

      LCID lcid,

      DISPID FAR* rgdispid)

{

    return DispGetIDsOfNames(m_ptinfo, rgszNames, cNames, rgdispid);

}

/*

 * CApplication::Invoke

 *

 * Purpose:

 *  Implements IDispatch::Invoke.  The standard implementation, DispInvoke,

 *  is used. Properties and methods exposed by the application object will

 *  set m_bRaiseException to raise an exception.

 *

 */

STDMETHODIMP

CApplication::Invoke(

      DISPID dispidMember,

      REFIID riid,

      LCID lcid,

      WORD wFlags,

      DISPPARAMS FAR* pdispparams,

      VARIANT FAR* pvarResult,

      EXCEPINFO FAR* pexcepinfo,

      UINT FAR* puArgErr)

{

    HRESULT hr;

    m_bRaiseException = FALSE;

    hr =  DispInvoke(

        this, m_ptinfo,

        dispidMember, wFlags, pdispparams,

        pvarResult, pexcepinfo, puArgErr);

    if (m_bRaiseException)

    {

       if (NULL != pexcepinfo)

           _fmemcpy(pexcepinfo, &m_excepinfo, sizeof(EXCEPINFO));

       return ResultFromScode(DISP_E_EXCEPTION);

    }

    else return hr;

}

/*

 * CApplication::get_Application, get_FullName, get_Name, get_Parent, get_Visible, put_Visible, Quit

 *

 * Purpose:

 *  Implements the standard Application, FullName, Name, Parent & Visible properties

 *  and the Quit method.

 *

 */

STDMETHODIMP

CApplication::get_Application(IApplication FAR* FAR* ppApplication)

{

    HRESULT hr;

    hr = QueryInterface(IID_IDispatch, (void FAR* FAR*)ppApplication);

    if (FAILED(hr))

        return RaiseException(IDS_Unexpected);

    return NOERROR;

}

STDMETHODIMP

CApplication::get_FullName(BSTR FAR* pbstr)

{

    *pbstr = SysAllocString(m_bstrFullName);

    return NOERROR;

}

STDMETHODIMP

CApplication::get_Name(BSTR FAR* pbstr)

{

    *pbstr = SysAllocString(m_bstrName);

    return NOERROR;

}

STDMETHODIMP

CApplication::get_Parent(IApplication FAR* FAR* ppApplication)

{

    HRESULT hr;

    hr = QueryInterface(IID_IDispatch, (void FAR* FAR*)ppApplication);

    if (FAILED(hr))

        return RaiseException(IDS_Unexpected);

    return NOERROR;

}

STDMETHODIMP

CApplication::put_Visible(VARIANT_BOOL bVisible)

{

    ShowWindow(bVisible ? SW_SHOW : SW_HIDE);

    return NOERROR;

}

STDMETHODIMP

CApplication::get_Visible(VARIANT_BOOL FAR* pbVisible)

{

    *pbVisible = m_bVisible;

    return NOERROR;

}

STDMETHODIMP

CApplication::Quit()

{

    // CoDisconnectObject has no effect for an inproc server.  So the controller

    // will GP fault if it attempts to access the object (including calling IUnknown::Release())

    // after Quit has been called. For a local server, CoDisconnectObject will disconnect

    // the object from external connections. So the controller will get an RPC error if

    // it access the object after calling Quit. The controller will not GP fault in this case.

    CoDisconnectObject((LPUNKNOWN)this, 0);

    PostMessage(m_hwnd, WM_CLOSE, 0, 0L);

    return NOERROR;

}

/*

 * CApplication::get_Pane

 *

 * Purpose:

 *  Returns pane object.

 *

 */

STDMETHODIMP

CApplication::get_Pane(IPane FAR* FAR* ppPane)

{

    HRESULT hr;

    hr = m_pPane->QueryInterface(IID_IDispatch, (void FAR* FAR*)ppPane);

    if (FAILED(hr))

        return RaiseException(IDS_Unexpected);

    return NOERROR;

}

/*

 * CApplication::CreateLine

 *

 * Purpose:

 *  Returns a newly created line object with no start or end point.

 *

 */

STDMETHODIMP

CApplication::CreateLine(ILine FAR* FAR* ppLine)

{

    CLine FAR* pline = NULL;

    HRESULT hr;

    // Create new item and QI for IDispatch

    hr = CLine::Create(&pline);

    if (FAILED(hr))

        {hr = RaiseException(IDS_OutOfMemory); goto error;}

    hr = pline->QueryInterface(IID_IDispatch, (void FAR* FAR*)ppLine);

    if (FAILED(hr))

        {hr = RaiseException(IDS_Unexpected); goto error;}

    return NOERROR;

error:

    if (pline)

        delete pline;

    return hr;

}

/*

 * CApplication::CreateLine

 *

 * Purpose:

 *  Returns a newly created point object intialized to (0,0).

 *

 */

STDMETHODIMP

CApplication::CreatePoint(IPoint FAR* FAR* ppPoint)

{

    CPoint FAR* ppoint = NULL;

    HRESULT hr;

    // Create new item and QI for IDispatch

    hr = CPoint::Create(&ppoint);

    if (FAILED(hr))

        {hr = RaiseException(IDS_OutOfMemory); goto error;}

    hr = ppoint->QueryInterface(IID_IDispatch, (void FAR* FAR*)ppPoint);

    if (FAILED(hr))

        {hr = RaiseException(IDS_Unexpected); goto error;}

    return NOERROR;

error:

    if (ppoint)

        delete ppoint;

    return hr;

}

/*

 *

 * The following methods are not exposed through Automation

 *

 */

STDMETHODIMP_(void)

CApplication::Draw()

{

   m_pPane->Draw();

}

/*

 * CApplication::OnSize

 *

 * Purpose:

 *  Called when application window receives WM_SIZE.

 *

 */

STDMETHODIMP_(void)

CApplication::OnSize(unsigned int nWidth, unsigned int nHeight)

{

   m_pPane->OnSize(nWidth, nHeight);

}

STDMETHODIMP_(void)

CApplication::ShowWindow(int nCmdShow)

{

    // Return if curently hidden and asked to hide or currently visible

    // and asked to show.

    if ((!m_bVisible && nCmdShow == SW_HIDE) || (m_bVisible && nCmdShow != SW_HIDE))

        return;

    m_bVisible = (nCmdShow == SW_HIDE) ? FALSE : TRUE;

    // The Automation object shutdown behavior is as follows:

    // 1. If the object application is visible, it shuts down only in response to an

    // explicit user command (File/Exit) or it's programmatic equivalent (for example

    // the Quit method of the Application object).

    // 2. If the object application is not visible, it goes away when it's last

    // object is released.

    //

    // CoLockObjectExternal can be used to increment the ref count of the application object

    // when it is visible. This will implement shutdown behavior 1. When the application

    // goes invisible, CoLockObjectExternal is used to decrement the ref count. This will

    // implement shutdown behavior 2.

    if (m_bVisible)

        CoLockObjectExternal(this, TRUE /*fLock*/, TRUE/*ignored when fLock==TRUE*/);

    else CoLockObjectExternal(this, FALSE/*fLock*/, TRUE/*fLastLockReleases*/);

    ::ShowWindow (m_hwnd, nCmdShow);

}

STDMETHODIMP_(void)

CApplication::CreateAndDrawLine()

{

    LINEINFO lineinfo;

    CLine FAR* pLine = NULL;

    CPoint FAR* pPointStart = NULL;

    CPoint FAR* pPointEnd = NULL;

    ILines FAR* pLines = NULL;

    int nRet;

    HRESULT hr;

    nRet = DialogBoxParam(m_hinst, MAKEINTRESOURCE(IDD_DRAWLINE), m_hwnd,

                      (DLGPROC)DrawLineDialogFunc, (LPARAM)(LPLINEINFO)&lineinfo);

    if (nRet != IDOK)

        return;

    hr = CLine::Create(&pLine);

    if (FAILED(hr))

        goto error;

    hr = CPoint::Create(&pPointStart);

    if (FAILED(hr))

        goto error;

    hr = CPoint::Create(&pPointEnd);

    if (FAILED(hr))

        goto error;

    pPointStart->put_x(lineinfo.ptStart.x);

    pPointStart->put_y(lineinfo.ptStart.y);

    pPointEnd->put_x(lineinfo.ptEnd.x);

    pPointEnd->put_y(lineinfo.ptEnd.y);

    pLine->putref_StartPoint(pPointStart);

    pLine->putref_EndPoint(pPointEnd);

    pLine->put_Thickness(lineinfo.nThickness);

    pLine->put_Color(lineinfo.colorref);

    hr = m_pPane->get_Lines(&pLines);

    if (FAILED(hr))

        goto error;

    hr = pLines->Add(pLine);

    if (FAILED(hr))

        goto error;

    pLines->Release();

    return;

error:

    if (pLine) delete pLine;

    if (pPointStart) delete pPointStart;

    if (pPointEnd) delete pPointEnd;

    if (pLines) pLines->Release();

    MessageBox(m_hwnd, TEXT("Cannot create Line"), m_bstrName, MB_OK);

}

STDMETHODIMP_(void)

CApplication::ClearPane()

{

    m_pPane->Clear();

}

/*

 * CApplication::RaiseException

 *

 * Purpose:

 *  Fills the EXCEPINFO structure and signal IDispatch::Invoke to return DISP_E_EXCEPTION.

 *  Sets ErrorInfo object for vtable-binding controllers.

 *

 */

STDMETHODIMP

CApplication::RaiseException(int nID)

{

    extern SCODE g_scodes[];

    TCHAR szError[STR_LEN];

    ICreateErrorInfo *pcerrinfo;

    IErrorInfo *perrinfo;

    HRESULT hr;

    _fmemset(&m_excepinfo, 0, sizeof(EXCEPINFO));

    m_excepinfo.wCode = nID;

    if (LoadString(m_hinst, nID, szError, sizeof(szError)))

        m_excepinfo.bstrDescription = SysAllocString(TO_OLE_STRING(szError));

    m_excepinfo.bstrSource = SysAllocString(m_bstrProgID);

    m_bRaiseException = TRUE;

    // Set ErrInfo object so that vtable binding containers can get

    // rich error information.

    hr = CreateErrorInfo(&pcerrinfo);

    if (SUCCEEDED(hr))

    {

       pcerrinfo->SetGUID(IID_IApplication);

       if (m_excepinfo.bstrSource)

           pcerrinfo->SetSource(m_excepinfo.bstrSource);

       if (m_excepinfo.bstrDescription)

           pcerrinfo->SetDescription(m_excepinfo.bstrDescription);

       hr = pcerrinfo->QueryInterface(IID_IErrorInfo, (LPVOID FAR*) &perrinfo);

       if (SUCCEEDED(hr))

       {

          SetErrorInfo(0, perrinfo);

          perrinfo->Release();

       }

       pcerrinfo->Release();

    }

    return ResultFromScode(g_scodes[nID-1001]);

}


 APPCF.CPP   (LINES OLE Sample)

/*************************************************************************

**

**    OLE Simple InProc Automation Object.

**

**    Applicationcf.cpp

**

**    CApplicationCF (class factory) implementation

**

**     Written by Microsoft Product Support Services, Windows Developer Support

**    (c) Copyright Microsoft Corp. 1994 All Rights Reserved

**

*************************************************************************/

#include <windows.h>

#include <windowsx.h>

#ifdef WIN16

  #include <ole2.h>

  #include <compobj.h>

  #include <dispatch.h>

  #include <variant.h>

  #include <olenls.h>

#endif

#include "lines.h"

CApplicationCF::CApplicationCF(void)

{

    m_cRef = 0;

}

/*

 * CApplicationCF::QueryInterface, AddRef, Release

 *

 * Purpose:

 *  Implements IUnknown::QueryInterface, AddRef, Release

 *

 */

STDMETHODIMP

CApplicationCF::QueryInterface(REFIID iid, void FAR* FAR* ppv)

{

    *ppv = NULL;

    if (iid == IID_IUnknown || iid == IID_IClassFactory)

        *ppv = this;

    else

        return ResultFromScode(E_NOINTERFACE);

    AddRef();

    return NOERROR;

}

STDMETHODIMP_(ULONG)

CApplicationCF::AddRef(void)

{

    return ++m_cRef;

}

STDMETHODIMP_(ULONG)

CApplicationCF::Release(void)

{

    if(--m_cRef == 0)

    {

        delete this;

        return 0;

    }

    return m_cRef;

}

/*

 * CApplicationCF::CreateInstance, LockServer

 *

 * Purpose:

 *  Implements IClassFactory::CreateInstance, LockServer

 *

 */

STDMETHODIMP

CApplicationCF::CreateInstance(IUnknown FAR* punkOuter,

                         REFIID riid,

                         void FAR* FAR* ppv)

{

    HRESULT hr;

    *ppv = NULL;

    // This implementation does'nt allow aggregation

    if (punkOuter)

        return ResultFromScode(CLASS_E_NOAGGREGATION);

    // This is REGCLS_SINGLEUSE class factory, so CreateInstance will be

    // called atmost once. An application objects has a REGCLS_SINGLEUSE class

    // factory. The global application object has already been created when

    // CreateInstance is called. A REGCLS_MULTIPLEUSE class factory's

    // CreateInstance would be called multiple times and would create a new

    // object each time. An MDI application would have a REGCLS_MULTIPLEUSE

    // class factory for it's document objects.

    hr = g_pApplication->QueryInterface(riid, ppv);

    if (FAILED(hr))

    {

        g_pApplication->Quit();

        return hr;

    }

    return NOERROR;

}

STDMETHODIMP

CApplicationCF::LockServer(BOOL fLock)

{

    CoLockObjectExternal(g_pApplication, fLock, TRUE);

    return NOERROR;

}


 ENUMVAR.CPP   (LINES OLE Sample)

/*************************************************************************

**

**    OLE Automation Collection sample

**

**    enumvar.cpp

**

**    CEnumVariant implementation

**

**     Written by Microsoft Product Support Services, Windows Developer Support

**    (c) Copyright Microsoft Corp. 1993 All Rights Reserved

**

*************************************************************************/

#include <windows.h>

#include <windowsx.h>

#ifdef WIN16

  #include <ole2.h>

  #include <compobj.h>

  #include <dispatch.h>

  #include <variant.h>

  #include <olenls.h>

#endif

#include "lines.h"

/*

 * CEnumVariant::Create

 *

 * Purpose:

 *  Creates an instance of the IEnumVARIANT enumerator object and initializes it.

 *

 * Parameters:

 *  psa        Safe array containing items to be enumerated.

 *  cElements  Number of items to be enumerated.

 *  ppenumvariant    Returns enumerator object.

 *

 * Return Value:

 *  HRESULT

 *

 */

HRESULT

CEnumVariant::Create(SAFEARRAY FAR* psa, ULONG cElements, CEnumVariant FAR* FAR* ppenumvariant)

{

    HRESULT hr;

    CEnumVariant FAR* penumvariant = NULL;

    long lLBound;

    *ppenumvariant = NULL;

    penumvariant = new CEnumVariant();

    if (penumvariant == NULL)

        goto error;

    penumvariant->m_cRef = 0;

    // Copy elements into safe array that is used in enumerator implemenatation and

    // initialize state of enumerator.

    hr = SafeArrayGetLBound(psa, 1, &lLBound);

    if (FAILED(hr))

        goto error;

    penumvariant->m_cElements = cElements;

    penumvariant->m_lLBound = lLBound;

    penumvariant->m_lCurrent = lLBound;

    hr = SafeArrayCopy(psa, &penumvariant->m_psa);

    if (FAILED(hr))

       goto error;

    *ppenumvariant = penumvariant;

    return NOERROR;

error:

    if (penumvariant == NULL)

        return ResultFromScode(E_OUTOFMEMORY);

    if (penumvariant->m_psa)

        SafeArrayDestroy(penumvariant->m_psa);

    penumvariant->m_psa = NULL;

    delete penumvariant;

    return hr;

}

/*

 * CEnumVariant::CEnumVariant

 *

 * Purpose:

 *  Constructor for CEnumVariant object. Initializes members to NULL.

 *

 */

CEnumVariant::CEnumVariant()

{

    m_psa = NULL;

}

/*

 * CEnumVariant::~CEnumVariant

 *

 * Purpose:

 *  Destructor for CEnumVariant object.

 *

 */

CEnumVariant::~CEnumVariant()

{

    if (m_psa) SafeArrayDestroy(m_psa);

}

/*

 * CEnumVariant::QueryInterface, AddRef, Release

 *

 * Purpose:

 *  Implements IUnknown::QueryInterface, AddRef, Release

 *

 */

STDMETHODIMP

CEnumVariant::QueryInterface(REFIID iid, void FAR* FAR* ppv)

{

    *ppv = NULL;

    if (iid == IID_IUnknown || iid == IID_IEnumVARIANT)

        *ppv = this;

    else return ResultFromScode(E_NOINTERFACE);

    AddRef();

    return NOERROR;

}

STDMETHODIMP_(ULONG)

CEnumVariant::AddRef(void)

{

#ifdef _DEBUG

    TCHAR ach[50];

    wsprintf(ach, TEXT("Ref = %ld, Enum\r\n"), m_cRef+1);

    OutputDebugString(ach);

#endif

    return ++m_cRef;  // AddRef Application Object if enumerator will outlive application object

}

STDMETHODIMP_(ULONG)

CEnumVariant::Release(void)

{

#ifdef _DEBUG

    TCHAR ach[50];

    wsprintf(ach, TEXT("Ref = %ld, Enum\r\n"), m_cRef-1);

    OutputDebugString(ach);

#endif

    if(--m_cRef == 0)

    {

        delete this;

        return 0;

    }

    return m_cRef;

}

/*

 * CEnumVariant::Next

 *

 * Purpose:

 *  Retrieves the next cElements elements. Implements IEnumVARIANT::Next.

 *

 */

STDMETHODIMP

CEnumVariant::Next(ULONG cElements, VARIANT FAR* pvar, ULONG FAR* pcElementFetched)

{

    HRESULT hr;

    ULONG l;

    long l1;

    ULONG l2;

    if (pcElementFetched != NULL)

        *pcElementFetched = 0;

    for (l=0; l<cElements; l++)

        VariantInit(&pvar[l]);

    // Retrieve the next cElements elements.

    for (l1=m_lCurrent, l2=0; l1<(long)(m_lLBound+m_cElements) && l2<cElements; l1++, l2++)

    {

       hr = SafeArrayGetElement(m_psa, &l1, &pvar[l2]);

       if (FAILED(hr))

           goto error;

    }

    // Set count of elements retrieved

    if (pcElementFetched != NULL)

        *pcElementFetched = l2;

    m_lCurrent = l1;

    return  (l2 < cElements) ? ResultFromScode(S_FALSE) : NOERROR;

error:

    for (l=0; l<cElements; l++)

        VariantClear(&pvar[l]);

    return hr;

}

/*

 * CEnumVariant::Skip

 *

 * Purpose:

 *  Skips the next cElements elements. Implements IEnumVARIANT::Skip.

 *

 */

STDMETHODIMP

CEnumVariant::Skip(ULONG cElements)

{

    m_lCurrent += cElements;

    if (m_lCurrent > (long)(m_lLBound+m_cElements))

    {

        m_lCurrent =  m_lLBound+m_cElements;

        return ResultFromScode(S_FALSE);

    }

    else return NOERROR;

}

/*

 * CEnumVariant::Reset

 *

 * Purpose:

 *  Resets the current element in the enumerator to the beginning. Implements IEnumVARIANT::Reset.

 *

 */

STDMETHODIMP

CEnumVariant::Reset()

{

    m_lCurrent = m_lLBound;

    return NOERROR;

}

/*

 * CEnumVariant::Clone

 *

 * Purpose:

 *  Creates a copy of the current enumeration state. Implements IEnumVARIANT::Clone.

 *

 */

STDMETHODIMP

CEnumVariant::Clone(IEnumVARIANT FAR* FAR* ppenum)

{

    CEnumVariant FAR* penum = NULL;

    HRESULT hr;

    *ppenum = NULL;

    hr = CEnumVariant::Create(m_psa, m_cElements, &penum);

    if (FAILED(hr))

        goto error;

    penum->AddRef();

    penum->m_lCurrent = m_lCurrent;

    *ppenum = penum;

    return NOERROR;

error:

    if (penum)

        penum->Release();

    return hr;

}


 ERRINFO.CPP   (LINES OLE Sample)

/*************************************************************************

**

**    OLE Automation Lines Object.

**

**    errinfo.cpp

**

**    CSupportErrorInfo implementation

**

**     Written by Microsoft Product Support Services, Windows Developer Support

**    (c) Copyright Microsoft Corp. 1994 All Rights Reserved

**

*************************************************************************/

#include <windows.h>

#include <windowsx.h>

#ifdef WIN16

  #include <ole2.h>

  #include <compobj.h>

  #include <dispatch.h>

  #include <variant.h>

  #include <olenls.h>

#endif

#include "lines.h"

CSupportErrorInfo::CSupportErrorInfo(IUnknown FAR* punkObject, REFIID riid)

{

    m_punkObject = punkObject;

    m_iid = riid;

}

STDMETHODIMP

CSupportErrorInfo::QueryInterface(REFIID iid, void FAR* FAR* ppv)

{

    return m_punkObject->QueryInterface(iid, ppv);

}

STDMETHODIMP_(ULONG)

CSupportErrorInfo::AddRef(void)

{

    return m_punkObject->AddRef();

}

STDMETHODIMP_(ULONG)

CSupportErrorInfo::Release(void)

{

    return m_punkObject->Release();

}

STDMETHODIMP

CSupportErrorInfo::InterfaceSupportsErrorInfo(REFIID riid)

{

    return (riid == m_iid) ? NOERROR : ResultFromScode(S_FALSE);

}


 LINE.CPP   (LINES OLE Sample)

/*************************************************************************

**

**    OLE Automation Lines Object.

**

**    line.cpp

**

**    CLine implementation

**

**     Written by Microsoft Product Support Services, Windows Developer Support

**    (c) Copyright Microsoft Corp. 1994 All Rights Reserved

**

*************************************************************************/

#include <windows.h>

#include <windowsx.h>

#ifdef WIN16

  #include <ole2.h>

  #include <compobj.h>

  #include <dispatch.h>

  #include <variant.h>

  #include <olenls.h>

#endif

#include "lines.h"

/*

 * CLine::Create

 *

 * Purpose:

 *  Creates an instance of the Line automation object and initializes it.

 *

 * Parameters:

 *  ppLine    Returns Line automation object.

 *

 * Return Value:

 *  HRESULT

 *

 */

HRESULT

CLine::Create(CLine FAR* FAR* ppLine )

{

    HRESULT hr;

    CLine FAR* pLine = NULL;

    *ppLine = NULL;

    pLine = new CLine();

    if (pLine == NULL)

        goto error;

    // Load type information for the line from type library.

    hr = LoadTypeInfo(&pLine->m_ptinfo, IID_ILine);

    if (FAILED(hr))

        goto error;

    *ppLine = pLine;

    return NOERROR;

error:

    if (pLine == NULL)

        return ResultFromScode(E_OUTOFMEMORY);

    if (pLine->m_ptinfo)

        pLine->m_ptinfo->Release();

    // Set to NULL to prevent destructor from attempting to free again

    pLine->m_ptinfo = NULL;

    delete pLine;

    return hr;

}

/*

 * CLine::CLine

 *

 * Purpose:

 *  Constructor for CLine object. Initializes members to NULL.

 *

 */

#pragma warning (disable : 4355)

CLine::CLine() : m_SupportErrorInfo(this, IID_ILine)

#pragma warning (default : 4355)

{

    m_ptinfo = NULL;

    m_pPointStart = NULL;

    m_pPointEnd = NULL;

    m_nThickness = 0;

    m_colorref = 0;

    m_cRef = 0;

}

/*

 * CLine::~CLine

 *

 * Purpose:

 *  Destructor for CLine object.

 *

 */

CLine::~CLine()

{

     if (m_ptinfo) m_ptinfo->Release();

     if (m_pPointStart) m_pPointStart->Release();

     if (m_pPointEnd) m_pPointEnd->Release();

}

/*

 * CLine::QueryInterface, AddRef, Release

 *

 * Purpose:

 *  Implements IUnknown::QueryInterface, AddRef, Release

 *

 */

STDMETHODIMP

CLine::QueryInterface(REFIID iid, void FAR* FAR* ppv)

{

    *ppv = NULL;

    if (iid == IID_IUnknown || iid == IID_IDispatch || iid == IID_ILine)

        *ppv = this;

    else if (iid == IID_ISupportErrorInfo)

        *ppv = &m_SupportErrorInfo;

    else return ResultFromScode(E_NOINTERFACE);

    AddRef();

    return NOERROR;

}

STDMETHODIMP_(ULONG)

CLine::AddRef(void)

{

#ifdef _DEBUG

    TCHAR ach[50];

    wsprintf(ach, TEXT("Ref = %ld, Line\r\n"), m_cRef+1);

    OutputDebugString(ach);

#endif

    return ++m_cRef;

}

STDMETHODIMP_(ULONG)

CLine::Release(void)

{

#ifdef _DEBUG

    TCHAR ach[50];

    wsprintf(ach, TEXT("Ref = %ld, Line\r\n"), m_cRef-1);

    OutputDebugString(ach);

#endif

    if(--m_cRef == 0)

    {

        delete this;

        return 0;

    }

    return m_cRef;

}

/*

 * CLine::GetTypeInfoCount

 *

 * Purpose:

 *  Implements IDispatch::GetTypeInfoCount.

 *

 */

STDMETHODIMP

CLine::GetTypeInfoCount(UINT FAR* pctinfo)

{

    *pctinfo = 1;

    return NOERROR;

}

/*

 * CLine::GetTypeInfo

 *

 * Purpose:

 *  Implements IDispatch::GetTypeInfo.

 *

 */

STDMETHODIMP

CLine::GetTypeInfo(

      UINT itinfo,

      LCID lcid,

      ITypeInfo FAR* FAR* pptinfo)

{

    *pptinfo = NULL;

    if(itinfo != 0)

        return ResultFromScode(DISP_E_BADINDEX);

    m_ptinfo->AddRef();

    *pptinfo = m_ptinfo;

    return NOERROR;

}

/*

 * CLine::GetIDsOfNames

 *

 * Purpose:

 *  Implements IDispatch::GetIDsOfNames.  The standard implementation, DispGetIDsOfNames,

 *  is used.

 *

 */

STDMETHODIMP

CLine::GetIDsOfNames(

      REFIID riid,

      OLECHAR FAR* FAR* rgszNames,

      UINT cNames,

      LCID lcid,

      DISPID FAR* rgdispid)

{

    return DispGetIDsOfNames(m_ptinfo, rgszNames, cNames, rgdispid);

}

/*

 * CLine::Invoke

 *

 * Purpose:

 *  Implements IDispatch::Invoke.  The standard implementation, DispInvoke,

 *  is used. Properties and methods exposed by the application object will

 *  set m_bRaiseException to raise an exception.

 *

 */

STDMETHODIMP

CLine::Invoke(

      DISPID dispidMember,

      REFIID riid,

      LCID lcid,

      WORD wFlags,

      DISPPARAMS FAR* pdispparams,

      VARIANT FAR* pvarResult,

      EXCEPINFO FAR* pexcepinfo,

      UINT FAR* puArgErr)

{

    HRESULT hr;

// VB 3.0/Disptest have a bug in which they pass DISPATCH_PROPERTYPUT

    // instead of DISPATCH_PROPERTYPUTREF for the EndPoint and StartPoint

    // properties. Future versions of VB will correctly pass DISPATCH_PROPERTYPUTREF.

    // EndPoint has DISPID == 1 and StartPoint has DISPID == 2 - see lines.odl.

    // The following code works around the VB 3.0/Disptest bug.

    if ((dispidMember == 1 || dispidMember == 2)

        && wFlags == DISPATCH_PROPERTYPUT)

        wFlags = DISPATCH_PROPERTYPUTREF;

    m_bRaiseException = FALSE;

    hr =  DispInvoke(

        this, m_ptinfo,

        dispidMember, wFlags, pdispparams,

        pvarResult, pexcepinfo, puArgErr);

    if (m_bRaiseException)

    {

       if (NULL != pexcepinfo)

           _fmemcpy(pexcepinfo, &m_excepinfo, sizeof(EXCEPINFO));

       return ResultFromScode(DISP_E_EXCEPTION);

    }

    else return hr;

}

/*

 *

 * Properties and methods exposed through automation.

 *

 */

STDMETHODIMP

CLine::get_Color(long FAR* plColorref)

{

    *plColorref =  m_colorref;

    return NOERROR;

}

STDMETHODIMP

CLine::put_Color(long lColorref)

{

    m_colorref = (COLORREF)lColorref;

    return NOERROR;

}

STDMETHODIMP

CLine::get_EndPoint(IPoint FAR* FAR* ppPoint)

{

    HRESULT hr;

    *ppPoint = NULL;

    if (NULL == m_pPointEnd)

        return RaiseException(IDS_NoStartPoint);

    hr = m_pPointEnd->QueryInterface(IID_IDispatch, (void FAR* FAR*)ppPoint);

    if (FAILED(hr))

        return RaiseException(IDS_Unexpected);

    return NOERROR;

}

STDMETHODIMP

CLine::putref_EndPoint(IPoint FAR* pPointNew)

{

    HRESULT hr;

    CPoint FAR* pPoint;

    // Save the IPoint interface so we can easily access private data

    hr = pPointNew->QueryInterface(IID_IPoint, (void FAR* FAR*)&pPoint);

    if (FAILED(hr))

        return RaiseException(IDS_PointFromOtherInstance);

    // Replace the old point with the new

    if (m_pPointEnd)

       m_pPointEnd->Release();

    m_pPointEnd = pPoint;

    return NOERROR;

}

STDMETHODIMP

CLine::get_StartPoint(IPoint FAR* FAR* ppPoint)

{

    HRESULT hr;

    *ppPoint = NULL;

    if (NULL == m_pPointStart)

        return RaiseException(IDS_NoStartPoint);

    hr = m_pPointStart->QueryInterface(IID_IDispatch, (void FAR* FAR*)ppPoint);

    if (FAILED(hr))

        return RaiseException(IDS_Unexpected);

    return NOERROR;

}

STDMETHODIMP

CLine::putref_StartPoint(IPoint FAR* pPointNew)

{

    HRESULT hr;

    CPoint FAR* pPoint;

    // Save the IPoint interface so we can easily access private data

    hr = pPointNew->QueryInterface(IID_IPoint, (void FAR* FAR*)&pPoint);

    if (FAILED(hr))

        return RaiseException(IDS_PointFromOtherInstance);

    // Replace the old point with the new

    if (m_pPointStart)

       m_pPointStart->Release();

    m_pPointStart = pPoint;

    return NOERROR;

}

STDMETHODIMP

CLine::get_Thickness(int FAR* pnThickness)

{

    *pnThickness = m_nThickness;

    return NOERROR;

}

STDMETHODIMP

CLine::put_Thickness(int nThickness)

{

    m_nThickness = nThickness;

    return NOERROR;

}

/*

 *

 * The following methods are not exposed through Automation

 *

 */

STDMETHODIMP_(void)

CLine::Draw(HDC hdc)

{

    HPEN hpen, hpenOld;

    if (m_pPointStart == NULL)

        return;

    if (m_pPointEnd == NULL)

        return;

    hpen = CreatePen(PS_SOLID, m_nThickness, m_colorref);

    hpenOld = (HGDIOBJ)SelectObject(hdc, (HGDIOBJ)hpen);

    MoveToEx(hdc, m_pPointStart->get_x(), m_pPointStart->get_y(), NULL);

    LineTo(hdc, m_pPointEnd->get_x(), m_pPointEnd->get_y());

    SelectObject(hdc, (HGDIOBJ)hpenOld);

    DeleteObject((HGDIOBJ)hpen);

    return;

}

/*

 * CLine::GetInvalidateRect

 *

 * Purpose:

 *  Get the rectangle that cicumscribes the line. This rectangle is used to invalidate the area

 *  of the window where the line is to be draw or erased.

 *

 */

STDMETHODIMP_(void)

CLine::GetInvalidateRect(LPRECT prc)

{

    int nX1, nY1, nX2, nY2;

    nX1 = m_pPointStart->get_x();

    nY1 = m_pPointStart->get_y();

    nX2 = m_pPointEnd->get_x();

    nY2 = m_pPointEnd->get_y();

    if (nX1 < nX2)

    {

        prc->left = nX1;

        prc->right = nX2;

    }

    else

    {

        prc->left = nX2;

        prc->right = nX1;

    }

    if (nY1 < nY2)

    {

        prc->top = nY1;

        prc->bottom = nY2;

    }

    else

    {

        prc->top = nY2;

        prc->bottom = nY1;

    }

    InflateRect(prc, m_nThickness, m_nThickness);

}

STDMETHODIMP_(BOOL)

CLine::AddEndPointsToPane(CPane FAR* pPane)

{

    // Does the line have end points?

    if (NULL == m_pPointStart)

       return FALSE;

    if (NULL == m_pPointEnd)

       return FALSE;

    // Add points to Point collection in the Pane object.

    if (pPane->AddPoint(m_pPointStart))

        return pPane->AddPoint(m_pPointEnd);

    return FALSE;

}

STDMETHODIMP_(void)

CLine::RemoveEndPointsFromPane(CPane FAR* pPane)

{

    // Remove the end points of the line to be removed from the Points collection in the Pane.

    if (NULL != m_pPointStart)

        pPane->RemovePoint(m_pPointStart);

    if (NULL != m_pPointEnd)

       pPane->RemovePoint(m_pPointEnd);

}

/*

 * CLine::RaiseException

 *

 * Purpose:

 *  Fills the EXCEPINFO structure and signal IDispatch::Invoke to return DISP_E_EXCEPTION.

 *  Sets ErrorInfo object for vtable-binding controllers.

 *

 */

STDMETHODIMP

CLine::RaiseException(int nID)

{

    extern SCODE g_scodes[];

    TCHAR szError[STR_LEN];

    ICreateErrorInfo *pcerrinfo;

    IErrorInfo *perrinfo;

    HRESULT hr;

    _fmemset(&m_excepinfo, 0, sizeof(EXCEPINFO));

    m_excepinfo.wCode = nID;

    if (LoadString(g_pApplication->m_hinst, nID, szError, sizeof(szError)))

        m_excepinfo.bstrDescription = SysAllocString(TO_OLE_STRING(szError));

    m_excepinfo.bstrSource = SysAllocString(g_pApplication->m_bstrProgID);

    m_bRaiseException = TRUE;

    // Set ErrInfo object so that vtable binding containers can get

    // rich error information.

    hr = CreateErrorInfo(&pcerrinfo);

    if (SUCCEEDED(hr))

    {

       pcerrinfo->SetGUID(IID_ILine);

       if (m_excepinfo.bstrSource)

           pcerrinfo->SetSource(m_excepinfo.bstrSource);

       if (m_excepinfo.bstrDescription)

           pcerrinfo->SetDescription(m_excepinfo.bstrDescription);

       hr = pcerrinfo->QueryInterface(IID_IErrorInfo, (LPVOID FAR*) &perrinfo);

       if (SUCCEEDED(hr))

       {

          SetErrorInfo(0, perrinfo);

          perrinfo->Release();

       }

       pcerrinfo->Release();

    }

    return ResultFromScode(g_scodes[nID-1001]);

}


 LINES.CPP   (LINES OLE Sample)

/*************************************************************************

**

**    OLE Automation Lines object

**

**    lines.cpp

**

**    CLines collection implementation

**

**     Written by Microsoft Product Support Services, Windows Developer Support

**    (c) Copyright Microsoft Corp. 1993 All Rights Reserved

**

*************************************************************************/

#include <windows.h>

#include <windowsx.h>

#ifdef WIN16

  #include <ole2.h>

  #include <compobj.h>

  #include <dispatch.h>

  #include <variant.h>

  #include <olenls.h>

#endif

#include "lines.h"

/*

 * CLines::Create

 *

 * Purpose:

 *  Creates an instance of a Lines collection object and initializes it.

 *

 * Parameters:

 *  lMaxSize   Maximum number of items that can added to collection.

 *  lLBound    Lower bound of index of collection.

 *  pPane      Pointer to pane that contains this collection. Required because the pane coordinates

 *             the lines and points collection.

 *  ppLines    Returns Lines collection object.

 *

 * Return Value:

 *  HRESULT

 *

 */

HRESULT

CLines::Create(ULONG lMaxSize, long lLBound, CPane FAR* pPane, CLines FAR* FAR* ppLines)

{

    HRESULT hr;

    CLines FAR* pLines = NULL;

    SAFEARRAYBOUND sabound[1];

    *ppLines = NULL;

    // Create new collection

    pLines = new CLines();

    if (pLines == NULL)

        goto error;

    pLines->m_cMax = lMaxSize;

    pLines->m_cElements = 0;

    pLines->m_lLBound = lLBound;

    pLines->m_pPane = pPane;

    // Load type information for the Lines collection from type library.

    hr = LoadTypeInfo(&pLines->m_ptinfo, IID_ILines);

    if (FAILED(hr))

        goto error;

    // Create a safe array of variants which is used to implement the collection.

    sabound[0].cElements = lMaxSize;

    sabound[0].lLbound = lLBound;

    pLines->m_psa = SafeArrayCreate(VT_VARIANT, 1, sabound);

    if (pLines->m_psa == NULL)

    {

        hr = ResultFromScode(E_OUTOFMEMORY);

        goto error;

    }

    *ppLines = pLines;

    return NOERROR;

error:

    if (pLines == NULL)

        return ResultFromScode(E_OUTOFMEMORY);

    if (pLines->m_ptinfo)

        pLines->m_ptinfo->Release();

    if (pLines->m_psa)

        SafeArrayDestroy(pLines->m_psa);

    pLines->m_psa = NULL;

    pLines->m_ptinfo = NULL;

    delete pLines;

    return hr;

}

/*

 * CLines::CLines

 *

 * Purpose:

 *  Constructor for CLines object. Initializes members to NULL.

 *

 */

#pragma warning (disable : 4355)

CLines::CLines() : m_SupportErrorInfo(this, IID_ILines)

#pragma warning (default : 4355)

{

    m_cRef = 0;

    m_psa = NULL;

    m_ptinfo = NULL;

}

/*

 * CLines::~CLines

 *

 * Purpose:

 *  Destructor for CLines object.

 *

 */

CLines::~CLines()

{

     if (m_ptinfo) m_ptinfo->Release();

     if (m_psa) SafeArrayDestroy(m_psa);

}

/*

 * CLines::QueryInterface, AddRef, Release

 *

 * Purpose:

 *  Implements IUnknown::QueryInterface, AddRef, Release

 *

 */

STDMETHODIMP

CLines::QueryInterface(REFIID iid, void FAR* FAR* ppv)

{

    *ppv = NULL;

    if (iid == IID_IUnknown || iid == IID_ILines || iid == IID_IDispatch)

        *ppv = this;

    else if (iid == IID_ISupportErrorInfo)

        *ppv = &m_SupportErrorInfo;

    else return ResultFromScode(E_NOINTERFACE);

    AddRef();

    return NOERROR;

}

STDMETHODIMP_(ULONG)

CLines::AddRef(void)

{

#ifdef _DEBUG

    TCHAR ach[50];

    wsprintf(ach, TEXT("Ref = %ld, Lines\r\n"), m_cRef+1);

    OutputDebugString(ach);

#endif

    return ++m_cRef;

}

STDMETHODIMP_(ULONG)

CLines::Release(void)

{

#ifdef _DEBUG

    TCHAR ach[50];

    wsprintf(ach, TEXT("Ref = %ld, Lines\r\n"), m_cRef-1);

    OutputDebugString(ach);

#endif

    if(--m_cRef == 0)

    {

        delete this;

        return 0;

    }

    return m_cRef;

}

/*

 * CLines::GetTypeInfoCount

 *

 * Purpose:

 *  Implements IDispatch::GetTypeInfoCount.

 *

 */

STDMETHODIMP

CLines::GetTypeInfoCount(UINT FAR* pctinfo)

{

    *pctinfo = 1;

    return NOERROR;

}

/*

 * CLines::GetTypeInfo

 *

 * Purpose:

 *  Implements IDispatch::GetTypeInfo.

 *

 */

STDMETHODIMP

CLines::GetTypeInfo(

      UINT itinfo,

      LCID lcid,

      ITypeInfo FAR* FAR* pptinfo)

{

    *pptinfo = NULL;

    if(itinfo != 0)

        return ResultFromScode(DISP_E_BADINDEX);

    m_ptinfo->AddRef();

    *pptinfo = m_ptinfo;

    return NOERROR;

}

/*

 * CLines::GetIDsOfNames

 *

 * Purpose:

 *  Implements IDispatch::GetIDsOfNames.  The standard implementation, DispGetIDsOfNames,

 *  is used.

 *

 */

STDMETHODIMP

CLines::GetIDsOfNames(

      REFIID riid,

      OLECHAR FAR* FAR* rgszNames,

      UINT cNames,

      LCID lcid,

      DISPID FAR* rgdispid)

{

    return DispGetIDsOfNames(m_ptinfo, rgszNames, cNames, rgdispid);

}

/*

 * CLines::Invoke

 *

 * Purpose:

 *  Implements IDispatch::Invoke.  The standard implementation, DispInvoke,

 *  is used. Properties and methods exposed by the lines collection object will

 *  set m_bRaiseException to raise an exception.

 *

 */

STDMETHODIMP

CLines::Invoke(

      DISPID dispidMember,

      REFIID riid,

      LCID lcid,

      WORD wFlags,

      DISPPARAMS FAR* pdispparams,

      VARIANT FAR* pvarResult,

      EXCEPINFO FAR* pexcepinfo,

      UINT FAR* puArgErr)

{

    HRESULT hr;

    m_bRaiseException = FALSE;

    hr =  DispInvoke(

        this, m_ptinfo,

        dispidMember, wFlags, pdispparams,

        pvarResult, pexcepinfo, puArgErr);

    if (m_bRaiseException)

    {

       if (NULL != pexcepinfo)

           _fmemcpy(pexcepinfo, &m_excepinfo, sizeof(EXCEPINFO));

       return ResultFromScode(DISP_E_EXCEPTION);

    }

    else return hr;

}

/*

 *

 * Properties and methods exposed through automation.

 *

 */

/*

 * CLines::Add

 *

 * Purpose:

 *  Adds a line to the lines collection.

 *

 * Parameters:

 *  pLineNew    IDispatch of line to be added to collection.

 *

 */

STDMETHODIMP

CLines::Add(ILine FAR* pLineNew)

{

    HRESULT hr;

    LONG l;

    CLine FAR* pLine = NULL;

    VARIANT v;

    HDC hdc;

    // Is the collection full?

    if (m_cElements == m_cMax)

        return RaiseException(IDS_CollectionFull);

    hr = pLineNew->QueryInterface(IID_ILine, (void FAR* FAR*)&pLine);

    if (FAILED(hr))

        return RaiseException(IDS_LineFromOtherInstance);

    // Add end points of line to the pane's point collection

    if (FALSE == pLine->AddEndPointsToPane(m_pPane))

        {hr = RaiseException(IDS_CantAddEndPoints); goto error;}

    // Add new line to collection

    l = m_lLBound+m_cElements;

    VariantInit(&v);

    V_VT(&v) = VT_DISPATCH;

    V_DISPATCH(&v) = pLineNew;

    hr = SafeArrayPutElement(m_psa, &l, &v);

    if (FAILED(hr))

        {hr = RaiseException(IDS_Unexpected); goto error;}

    m_cElements++;

    // Draw the new line

    hdc = m_pPane->GetDC();

    pLine->Draw(hdc);

    m_pPane->ReleaseDC(hdc);

    pLine->Release();

    return NOERROR;

error:

    if (pLine)

        pLine->Release();

    return hr;

}

/*

 * CLines::get_Count

 *

 * Purpose:

 *  Returns number of items in collection.

 *

 */

STDMETHODIMP

CLines::get_Count(long FAR* lCount)

{

    *lCount = m_cElements;

    return NOERROR;

}

/*

 * CLines::get_Item

 *

 * Purpose:

 *  Retrieves item from collection, given an index.

 *

 * Parameters:

 *   lIndex   Index of item to be retrieved.

 *   ppLine   Returns IDispatch of item retrieved from collection.

 *

 */

STDMETHODIMP

CLines::get_Item(long lIndex, ILine FAR* FAR* ppLine)

{

    HRESULT hr;

    VARIANT v;

    // Check if index is within range

    if (lIndex < m_lLBound || lIndex >= (long)(m_lLBound+m_cElements))

        return RaiseException(IDS_InvalidIndex);

    // Retrieve and return item. Note that SafeArrayGetElement AddRefs, so an additional AddRef

    // is not required.

    VariantInit(&v);

    hr = SafeArrayGetElement(m_psa, &lIndex, &v);

    if (FAILED(hr))

        return RaiseException(IDS_Unexpected);

    *ppLine = (ILine FAR*) V_DISPATCH(&v);

    return NOERROR;

}

/*

 * CLines::get_NewEnum

 *

 * Purpose:

 *  Returns an enumerator (IEnumVARIANT) for the items curently in the collection.

 *  The NewEnum property is restricted and so is invisible to users of an

 *  automation controller's scripting language. Automation controllers that support

 *  a 'For Each' statement to iterate through the elements of a collection will use

 *  the enumerator returned by NewEnum. The enumerator creates a snapshot of the

 *  the current state of the collection.

 *

 */

STDMETHODIMP

CLines::get__NewEnum(IUnknown FAR* FAR* ppunkEnum)

{

    CEnumVariant FAR* penum = NULL;;

    HRESULT hr;

    *ppunkEnum = NULL;

    // Create new enumerator for items currently in collection and QI for IUnknown

    hr = CEnumVariant::Create(m_psa, m_cElements, &penum);

    if (FAILED(hr))

        {hr = RaiseException(IDS_OutOfMemory); goto error;}

    hr = penum->QueryInterface(IID_IUnknown, (VOID FAR* FAR*)ppunkEnum);

    if (FAILED(hr))

        {hr = RaiseException(IDS_Unexpected); goto error;}

    return NOERROR;

error:

    if (penum)

        delete penum;

    return hr;

}

/*

 * CLines::Remove

 *

 * Purpose:

 *  Removes specified item from collection.

 *

 * Parameters:

 *   lIndex   Index of item to be removed.

 *

 */

STDMETHODIMP

CLines::Remove(long lIndex)

{

    HRESULT hr;

    long l;

    VARIANT HUGEP *pvar;

    CLine FAR* pLine = NULL;

    RECT rc;

    // Check if integer index is within range.

    if (lIndex < m_lLBound || lIndex >= (long)(m_lLBound+m_cElements))

        return RaiseException(IDS_InvalidIndex);

    hr = SafeArrayAccessData(m_psa, (void HUGEP* FAR*)&pvar);

    if (FAILED(hr))

        return RaiseException(IDS_Unexpected);

    V_DISPATCH(&pvar[lIndex-m_lLBound])->QueryInterface(IID_ILine, (void FAR* FAR*)&pLine);

    // Ask the pane to invalidate the area where the line is drawn.

    pLine->GetInvalidateRect(&rc);

    m_pPane->InvalidateRect(&rc);

    // Remove end points of line from the pane's point collection.

    pLine->RemoveEndPointsFromPane(m_pPane);

    // Remove Line

    V_DISPATCH(&pvar[lIndex-m_lLBound])->Release();

    // Move up the array elements, after the element to be removed.

    for (l=lIndex-m_lLBound; l<(long)(m_cElements-1); l++)

        pvar[l] = pvar[l+1];

    // Remove last element.

    V_VT(&pvar[l]) = VT_EMPTY;

    pLine->Release();

    hr = SafeArrayUnaccessData(m_psa);

    if (FAILED(hr))

       return RaiseException(IDS_Unexpected);

    m_cElements--;

    m_pPane->Update();     // Ask the pane to repaint invalidated areas caused by removal of line.

    return NOERROR;

}

/*

 *

 * The following methods are not exposed through Automation

 *

 */

/*

 * CLines::Draw

 *

 * Purpose:

 *  Draws all lines in collection.

 *

 */

STDMETHODIMP_(void)

CLines::Draw(HDC hdc)

{

    HRESULT hr;

    long l;

    CLine FAR* pLine = NULL;

    VARIANT HUGEP *pvar;

    // Draw each line in the Lines collection

    hr = SafeArrayAccessData(m_psa, (void HUGEP* FAR*)&pvar);

    if (FAILED(hr))

       return;

    for (l=0; l<(long)m_cElements; l++)

    {

        hr = V_DISPATCH(&pvar[l])->QueryInterface(IID_ILine, (void FAR* FAR*)&pLine);

        if (FAILED(hr))

            continue;

        pLine->Draw(hdc);

        pLine->Release();

    }

    hr = SafeArrayUnaccessData(m_psa);

    if (FAILED(hr))

        return;

    return;

}

/*

 * CLines::Clear

 *

 * Purpose:

 *  Removes all items from collection.

 *

 */

STDMETHODIMP_(void)

CLines::Clear(void)

{

    SafeArrayDestroyData(m_psa);

    SafeArrayAllocData(m_psa);

    m_cElements = 0;

}

/*

 * CLines::RaiseException

 *

 * Purpose:

 *  Fills the EXCEPINFO structure and signal IDispatch::Invoke to return DISP_E_EXCEPTION.

 *  Sets ErrorInfo object for vtable-binding controllers.

 *

 */

STDMETHODIMP

CLines::RaiseException(int nID)

{

    extern SCODE g_scodes[];

    TCHAR szError[STR_LEN];

    ICreateErrorInfo *pcerrinfo;

    IErrorInfo *perrinfo;

    HRESULT hr;

    _fmemset(&m_excepinfo, 0, sizeof(EXCEPINFO));

    m_excepinfo.wCode = nID;

    if (LoadString(g_pApplication->m_hinst, nID, szError, sizeof(szError)))

        m_excepinfo.bstrDescription = SysAllocString(TO_OLE_STRING(szError));

    m_excepinfo.bstrSource = SysAllocString(g_pApplication->m_bstrProgID);

    m_bRaiseException = TRUE;

    // Set ErrInfo object so that vtable binding containers can get

    // rich error information.

    hr = CreateErrorInfo(&pcerrinfo);

    if (SUCCEEDED(hr))

    {

       pcerrinfo->SetGUID(IID_ILines);

       if (m_excepinfo.bstrSource)

           pcerrinfo->SetSource(m_excepinfo.bstrSource);

       if (m_excepinfo.bstrDescription)

           pcerrinfo->SetDescription(m_excepinfo.bstrDescription);

       hr = pcerrinfo->QueryInterface(IID_IErrorInfo, (LPVOID FAR*) &perrinfo);

       if (SUCCEEDED(hr))

       {

          SetErrorInfo(0, perrinfo);

          perrinfo->Release();

       }

       pcerrinfo->Release();

    }

    return ResultFromScode(g_scodes[nID-1001]);

}


 MAIN.CPP   (LINES OLE Sample)

/*************************************************************************

**

**    OLE Automation Lines Object.

**

**    main.cpp

**

**     Written by Microsoft Product Support Services, Windows Developer Support

**    (c) Copyright Microsoft Corp. 1994 All Rights Reserved

**

*************************************************************************/

#include <windows.h>

#include <windowsx.h>

#ifdef WIN16

  #include <ole2.h>

  #include <compobj.h>

  #include <dispatch.h>

  #include <variant.h>

  #include <olenls.h>

  #include <commdlg.h>

#endif

#include <initguid.h>

#include "lines.h"

// Globals

CApplication FAR* g_pApplication;

SCODE g_scodes[SCODE_COUNT] =                // Array of SCODEs for easy lookup

{    LINES_E_UNEXPECTED,

     LINES_E_OUTOFMEMORY,

     LINES_E_INVALIDINDEX,

     LINES_E_COLLECTIONFULL,

     LINES_E_LINEFROMOTHERINSTANCE,

     LINES_E_CANTADDENDPOINTS,

     LINES_E_POINTFROMOTHERINSTANCE,

     LINES_E_NOVISIBLEXCOORDINATE,

     LINES_E_NOVISIBLEYCOORDINATE,

     LINES_E_NOSTARTPOINT,

     LINES_E_NOENDPOINT

};

/*

 * WinMain

 *

 * Purpose:

 *  Main entry point of application.

 *

 */

int APIENTRY WinMain (HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR pCmdLine, int nCmdShow)

{

    MSG msg;

    DWORD dwRegisterCF;

    DWORD dwRegisterActiveObject;

    //  It is recommended that all OLE applications set

    //  their message queue size to 96. This improves the capacity

    //  and performance of OLE's LRPC mechanism.

    int cMsg = 96;                  // Recommend msg queue size for OLE

    while (cMsg && !SetMessageQueue(cMsg))  // take largest size we can get.

        cMsg -= 8;

    if (!cMsg)

        return -1;                  // ERROR: we got no message queue

    if (!hinstPrev)

       if (!InitApplication(hinst)) // Register window class

          return FALSE;

    if (!InitInstance(hinst))   // Initialize OLE and create Lines application object

        return (FALSE);

    // Determine if /Automation was specified in command line and register class

    // factory and active object. Show window if application was started stand alone.

    if (!ProcessCmdLine(pCmdLine, &dwRegisterCF, &dwRegisterActiveObject, nCmdShow))

    {

       Uninitialize(dwRegisterCF, dwRegisterActiveObject);

       return (FALSE);

    }

    while (GetMessage(&msg, NULL, 0, 0))

    {

       TranslateMessage(&msg);

       DispatchMessage(&msg);

    }

    Uninitialize(dwRegisterCF, dwRegisterActiveObject);

    return (msg.wParam);

}

/*

 * InitApplication

 *

 * Purpose:

 *  Registers window class

 *

 * Parameters:

 *  hinst       hInstance of application

 *

 * Return Value:

 *  TRUE if initialization succeeded, FALSE otherwise.

 */

BOOL InitApplication (HINSTANCE hinst)

{

   WNDCLASS wc;

   wc.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;

   wc.lpfnWndProc = MainWndProc;

   wc.cbClsExtra = 0;

   wc.cbWndExtra = 0;

   wc.hInstance = hinst;

   wc.hIcon = LoadIcon(hinst, MAKEINTRESOURCE(IDI_ICON));

   wc.hCursor = LoadCursor(NULL, IDC_ARROW);

   wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);

   wc.lpszMenuName = TEXT("AppMenu");

   wc.lpszClassName = TEXT("MainWndClass");

   return RegisterClass(&wc);

}

/*

 * InitInstance

 *

 * Purpose:

 *  Intializes OLE and creates Lines Application object

 *

 * Parameters:

 *  hinst           hInstance of application

 *

 * Return Value:

 *  TRUE if initialization succeeded, FALSE otherwise.

 */

BOOL InitInstance (HINSTANCE hinst)

{

    HRESULT hr;

    // Intialize OLE

    hr = OleInitialize(NULL);

    if (FAILED(hr))

       return FALSE;

    // Create an instance of the Lines Application object. Object is

    // created with refcount 0.

    hr = CApplication::Create(hinst, &g_pApplication);

    if (FAILED(hr))

        return FALSE;

    return TRUE;

}

/*

 * ProcessCmdLine

 *

 * Purpose:

 *  Check if command line contains /Automation. If so, the class factory of the

 *  application object is registered.  If not, the application was started stand-alone and

 *  so the window is shown. The application object is registered using RegisterActiveObject.

 *

 * Parameters:

 *  pCmdLine       Command line passed to application

 *  pdwRegisterCF   Returns id returned after class factory registration. Can be used to

 *                  revoke class factory registration.

 *  pdwRegisterActiveObject   Returns id returned after active object registration. Can be used to

 *                  revoke active object registration.

 *  nCmdShow        Specifies how window is to be shown if application was started stand alone.

 *

 * Return Value:

 *    TRUE if OLE initialization succeeded, FALSE otherwise.

 *

 */

BOOL ProcessCmdLine(LPSTR pCmdLine, LPDWORD pdwRegisterCF, LPDWORD pdwRegisterActiveObject, int nCmdShow)

{

   LPCLASSFACTORY pcf = NULL;

   HRESULT hr;

   *pdwRegisterCF = 0;

   *pdwRegisterActiveObject = 0;

   // Expose class factory for application object if command line contains the

   // Automation switch

   if (_fstrstr(pCmdLine, "-Automation") != NULL

       || _fstrstr(pCmdLine, "/Automation") != NULL)

   {

       pcf = new CApplicationCF;

       if (!pcf)

           goto error;

       pcf->AddRef();

       hr = CoRegisterClassObject(CLSID_Lines, pcf,

                                     CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE,

                                     pdwRegisterCF);

       if (hr != NOERROR)

           goto error;

       pcf->Release();

   }

   else g_pApplication->ShowWindow(nCmdShow);    // Show window if started stand-alone

   // Register Lines application object in the Running Object Table (ROT). This

   // allows controllers to connect to a running application object instead of creating

   // a new instance. Use weak registration so that the ROT releases it's reference when

   // all external references are released. If strong registration is used, the ROT will not

   // release it's reference until RevokeActiveObject is called and so will keep

   // the object alive even after all external references have been released.

   RegisterActiveObject(g_pApplication, CLSID_Lines, ACTIVEOBJECT_WEAK, pdwRegisterActiveObject);

   return TRUE;

error:

    if (pcf)

        pcf->Release();

    return FALSE;

}

/*

 * Uninitialize

 *

 *  Purpose:

 *   Revoke class factory and active object registration and uninitialize OLE.

 *

 * Parameters:

 *  dwRegisterCF ID returned after class factory registration.

 *  dwRegisterActiveObject ID returned after active object registration.

 *

 */

void Uninitialize(DWORD dwRegisterCF, DWORD dwRegisterActiveObject)

{

    if (dwRegisterCF != 0)

        CoRevokeClassObject(dwRegisterCF);

    if (dwRegisterActiveObject != 0)

        RevokeActiveObject(dwRegisterActiveObject, NULL);

    OleUninitialize();

}

/*

 * MainWndProc

 *

 * Purpose:

 *  Window procedure for main window

 *

 */

LRESULT CALLBACK MainWndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)

{

   switch (msg)

   {

      case WM_PAINT:

          g_pApplication->Draw();

          break;

      case WM_SIZE:

          g_pApplication->OnSize(LOWORD(lParam), HIWORD(lParam));

          break;

      case WM_COMMAND:

      {

          switch(GET_WM_COMMAND_ID(wParam,lParam))

          {

              case IDM_DRAWLINE:

                  g_pApplication->CreateAndDrawLine();

                  break;

              case IDM_CLEAR:

                  g_pApplication->ClearPane();

                  break;

              case IDM_EXIT:

                  PostMessage(hwnd, WM_CLOSE, 0, 0L);

                  break;

          }

      }

      break;

      case WM_CLOSE:

         // Hide the window to release the refcount added by CoLockObjectExternal

         // (See CLines::ShowWindow)

         g_pApplication->m_bUserClosing = TRUE;

         g_pApplication->ShowWindow(SW_HIDE);

         DestroyWindow(hwnd);

         return 0L;

      case WM_DESTROY:

         PostQuitMessage(0);

         break;

      default:

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

   }

   return NULL;

}

/*

 * DrawLineDialogFunc

 *

 * Purpose:

 *  Dialog function of DrawLine dialog. Prompts user and returns information to draw a line.

 *

 */

BOOL CALLBACK DrawLineDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)

{

   static LPLINEINFO plineinfo;

   BOOL b;

   CHOOSECOLOR cc;

   COLORREF clrCustom[16];

   int n;

   switch (msg)

   {

      case WM_INITDIALOG:

         plineinfo = (LPLINEINFO)lParam;

         // Initialize edit controls. Units are twips.

         SetDlgItemText(hwndDlg, IDC_STARTPOINT_X, TEXT("4500"));

         SetDlgItemText(hwndDlg, IDC_STARTPOINT_Y, TEXT("4500"));

         SetDlgItemText(hwndDlg, IDC_ENDPOINT_X, TEXT("8000"));

         SetDlgItemText(hwndDlg, IDC_ENDPOINT_Y, TEXT("8000"));

         SetDlgItemText(hwndDlg, IDC_THICKNESS, TEXT("100"));

         plineinfo->colorref = 0;

         return TRUE;

      case WM_COMMAND:

         switch(GET_WM_COMMAND_ID(wParam,lParam))

         {

             case IDOK:

                 plineinfo->ptStart.x = GetDlgItemInt(hwndDlg, IDC_STARTPOINT_X, &b, TRUE);

                 plineinfo->ptStart.y = GetDlgItemInt(hwndDlg, IDC_STARTPOINT_Y, &b, TRUE);

                 plineinfo->ptEnd.x = GetDlgItemInt(hwndDlg, IDC_ENDPOINT_X, &b, TRUE);

                 plineinfo->ptEnd.y = GetDlgItemInt(hwndDlg, IDC_ENDPOINT_Y, &b, TRUE);

                 plineinfo->nThickness = GetDlgItemInt(hwndDlg, IDC_THICKNESS, &b, TRUE);

                 EndDialog(hwndDlg, IDOK);

                 return TRUE;

             case IDCANCEL:

                 EndDialog(hwndDlg, IDCANCEL);

                 return TRUE;

             case IDC_CHOOSECOLOR:

                 memset(&cc, 0, sizeof(CHOOSECOLOR));

                 cc.lStructSize = sizeof(CHOOSECOLOR);

                 cc.hwndOwner = hwndDlg;

                 cc.rgbResult = RGB(0, 0, 0);

                 cc.Flags = CC_RGBINIT;

                 for (n=0; n<16; n++)

                    clrCustom[n] = RGB(255, 255, 255);

                 cc.lpCustColors = clrCustom;

                 if (ChooseColor(&cc))

                     plineinfo->colorref = cc.rgbResult;

         }

         break;

   }

   return FALSE;

}

/*

 * LoadTypeInfo

 *

 *  Purpose:

 *   Gets type information of an object's interface from type library.

 *

 * Parameters:

 *  ppunkStdDispatch    Returns type information.

 *  clsid               Interface id of object in type library.

 *

 * Return Value:

 *  HRESULT

 *

 */

HRESULT LoadTypeInfo(ITypeInfo FAR* FAR* pptinfo, REFCLSID clsid)

{

    HRESULT hr;

    LPTYPELIB ptlib = NULL;

    LPTYPEINFO ptinfo = NULL;

    *pptinfo = NULL;

    // Load Type Library.

    hr = LoadRegTypeLib(LIBID_Lines, 1, 0, 0x0409, &ptlib);

    if (FAILED(hr))

    {

        // if it wasn't registered, try to load it from the path

        // if this succeeds, it will have registered the type library for us

        // for the next time.

        hr = LoadTypeLib(OLESTR("lines.tlb"), &ptlib);

        if(FAILED(hr))

            return hr;

    }

    // Get type information for interface of the object.

    hr = ptlib->GetTypeInfoOfGuid(clsid, &ptinfo);

    if (FAILED(hr))

    {

        ptlib->Release();

        return hr;

    }

    ptlib->Release();

    *pptinfo = ptinfo;

    return NOERROR;

}

#ifdef WIN32

#ifndef UNICODE

char* ConvertToAnsi(OLECHAR FAR* szW)

{

  static char achA[STRCONVERT_MAXLEN];

  WideCharToMultiByte(CP_ACP, 0, szW, -1, achA, STRCONVERT_MAXLEN, NULL, NULL);

  return achA;

}

OLECHAR* ConvertToUnicode(char FAR* szA)

{

  static OLECHAR achW[STRCONVERT_MAXLEN];

  MultiByteToWideChar(CP_ACP, 0, szA, -1, achW, STRCONVERT_MAXLEN);

  return achW;

}

#endif

#endif


 PANE.CPP   (LINES OLE Sample)

/*************************************************************************

**

**    OLE Automation Lines Object.

**

**    pane.cpp

**

**    CPane implementation

**

**     Written by Microsoft Product Support Services, Windows Developer Support

**    (c) Copyright Microsoft Corp. 1994 All Rights Reserved

**

*************************************************************************/

#include <windows.h>

#include <windowsx.h>

#ifdef WIN16

  #include <ole2.h>

  #include <compobj.h>

  #include <dispatch.h>

  #include <variant.h>

  #include <olenls.h>

#endif

#include "lines.h"

/*

 * CPane::Create

 *

 * Purpose:

 *  Creates an instance of the Pane automation object and initializes it.

 *

 * Parameters:

 *  hwnd      Handle of the window of the pane.

 *  ppPane    Returns Pane automation object.

 *

 * Return Value:

 *  HRESULT

 *

 */

HRESULT

CPane::Create(HWND hwnd, CPane FAR* FAR* ppPane )

{

    HRESULT hr;

    CPane FAR* pPane = NULL;

    *ppPane = NULL;

    pPane = new CPane();

    if (pPane == NULL)

        goto error;

    pPane->m_hwnd = hwnd;

    // Create an empty Lines collection of size 100

    hr = CLines::Create(100, 1, pPane, &pPane->m_pLines);

    if (FAILED(hr))

       goto error;

    pPane->m_pLines->AddRef();

    // Create an empty Points collection of size 200

    hr = CPoints::Create(200, 1, pPane, &pPane->m_pPoints);

    if (FAILED(hr))

       goto error;

    pPane->m_pPoints->AddRef();

    // Load type information for the pane object from type library.

    hr = LoadTypeInfo(&pPane->m_ptinfo, IID_IPane);

    if (FAILED(hr))

        goto error;

    *ppPane = pPane;

    return NOERROR;

error:

    if (pPane == NULL)

        return ResultFromScode(E_OUTOFMEMORY);

    if (pPane->m_ptinfo)

        pPane->m_ptinfo->Release();

    if (pPane->m_pLines)

        pPane->m_pLines->Release();

    if (pPane->m_pPoints)

        pPane->m_pPoints->Release();

    // Set to NULL to prevent destructor from attempting to free again

    pPane->m_ptinfo = NULL;

    pPane->m_pLines = NULL;

    pPane->m_pPoints = NULL;

    delete pPane;

    return hr;

}

/*

 * CPane::CPane

 *

 * Purpose:

 *  Constructor for CPane object. Initializes members to NULL.

 *

 */

#pragma warning (disable : 4355)

CPane::CPane() : m_SupportErrorInfo(this, IID_IPane)

#pragma warning (default : 4355)

{

    m_cRef = 0;

    m_hwnd = NULL;

    m_ptinfo = NULL;

    m_pLines = NULL;

    m_pPoints = NULL;

    m_nMaxX = -1;

    m_nMaxY = -1;

}

/*

 * CPane::~CPane

 *

 * Purpose:

 *  Destructor for CPane object.

 *

 */

CPane::~CPane()

{

     if (m_ptinfo) m_ptinfo->Release();

     if (m_pLines) m_pLines->Release();

     if (m_pPoints) m_pPoints->Release();

}

/*

 * CPane::QueryInterface, AddRef, Release

 *

 * Purpose:

 *  Implements IUnknown::QueryInterface, AddRef, Release

 *

 */

STDMETHODIMP

CPane::QueryInterface(REFIID iid, void FAR* FAR* ppv)

{

    *ppv = NULL;

    if (iid == IID_IUnknown || iid == IID_IDispatch || iid == IID_IPane)

        *ppv = this;

    else if (iid == IID_ISupportErrorInfo)

        *ppv = &m_SupportErrorInfo;

    else return ResultFromScode(E_NOINTERFACE);

    AddRef();

    return NOERROR;

}

STDMETHODIMP_(ULONG)

CPane::AddRef(void)

{

#ifdef _DEBUG

    TCHAR ach[50];

    wsprintf(ach, TEXT("Ref = %ld, Pane\r\n"), m_cRef+1);

    OutputDebugString(ach);

#endif

    return ++m_cRef;

}

STDMETHODIMP_(ULONG)

CPane::Release(void)

{

#ifdef _DEBUG

    TCHAR ach[50];

    wsprintf(ach, TEXT("Ref = %ld, Pane\r\n"), m_cRef-1);

    OutputDebugString(ach);

#endif

    if(--m_cRef == 0)

    {

        delete this;

        return 0;

    }

    return m_cRef;

}

/*

 * CPane::GetTypeInfoCount

 *

 * Purpose:

 *  Implements IDispatch::GetTypeInfoCount.

 *

 */

STDMETHODIMP

CPane::GetTypeInfoCount(UINT FAR* pctinfo)

{

    *pctinfo = 1;

    return NOERROR;

}

/*

 * CPane::GetTypeInfo

 *

 * Purpose:

 *  Implements IDispatch::GetTypeInfo.

 *

 */

STDMETHODIMP

CPane::GetTypeInfo(

      UINT itinfo,

      LCID lcid,

      ITypeInfo FAR* FAR* pptinfo)

{

    *pptinfo = NULL;

    if(itinfo != 0)

        return ResultFromScode(DISP_E_BADINDEX);

    m_ptinfo->AddRef();

    *pptinfo = m_ptinfo;

    return NOERROR;

}

/*

 * CPane::GetIDsOfNames

 *

 * Purpose:

 *  Implements IDispatch::GetIDsOfNames.  The standard implementation, DispGetIDsOfNames,

 *  is used.

 *

 */

STDMETHODIMP

CPane::GetIDsOfNames(

      REFIID riid,

      OLECHAR FAR* FAR* rgszNames,

      UINT cNames,

      LCID lcid,

      DISPID FAR* rgdispid)

{

    return DispGetIDsOfNames(m_ptinfo, rgszNames, cNames, rgdispid);

}

/*

 * CPane::Invoke

 *

 * Purpose:

 *  Implements IDispatch::Invoke.  The standard implementation, DispInvoke,

 *  is used. Properties and methods exposed by the pane object will

 *  set m_bRaiseException to raise an exception.

 *

 */

STDMETHODIMP

CPane::Invoke(

      DISPID dispidMember,

      REFIID riid,

      LCID lcid,

      WORD wFlags,

      DISPPARAMS FAR* pdispparams,

      VARIANT FAR* pvarResult,

      EXCEPINFO FAR* pexcepinfo,

      UINT FAR* puArgErr)

{

    HRESULT hr;

    m_bRaiseException = FALSE;

    hr =  DispInvoke(

        this, m_ptinfo,

        dispidMember, wFlags, pdispparams,

        pvarResult, pexcepinfo, puArgErr);

    if (m_bRaiseException)

    {

       if (NULL != pexcepinfo)

           _fmemcpy(pexcepinfo, &m_excepinfo, sizeof(EXCEPINFO));

       return ResultFromScode(DISP_E_EXCEPTION);

    }

    else return hr;

}

/*

 * CPane::get_Lines

 *

 * Purpose:

 *  Returns the collection of all line objects in the drawing.

 *

 */

STDMETHODIMP

CPane::get_Lines(ILines FAR* FAR* ppLines)

{

    HRESULT hr;

    hr = m_pLines->QueryInterface(IID_IDispatch, (void FAR* FAR*)ppLines);

    if (FAILED(hr))

        return RaiseException(IDS_Unexpected);

    return NOERROR;

}

/*

 * CPane::get_Points

 *

 * Purpose:

 *  Returns the collection of all point objects in the drawing.

 *

 */

STDMETHODIMP

CPane::get_Points(IPoints FAR* FAR* ppPoints)

{

    HRESULT hr;

    hr = m_pPoints->QueryInterface(IID_IDispatch, (void FAR* FAR*)ppPoints);

    if (FAILED(hr))

        return RaiseException(IDS_Unexpected);

    return NOERROR;

}

/*

 * CPane::get_MaxX, get_MaxY

 *

 * Purpose:

 *  Returns the maximum visible X & Y coordinate values in twips.

 *

 */

STDMETHODIMP

CPane::get_MaxX(int FAR* pnMaxX)

{

     *pnMaxX = m_nMaxX;

    if (m_nMaxX == -1)

        return RaiseException(IDS_NoVisibleXCoordinate);

    return NOERROR;

}

STDMETHODIMP

CPane::get_MaxY(int FAR* pnMaxY)

{

    *pnMaxY = m_nMaxY;

    if (m_nMaxY == -1)

        return RaiseException(IDS_NoVisibleYCoordinate);

    return NOERROR;

}

/*

 * CPane::Clear

 *

 * Purpose:

 *  Removes all the Lines and Points from the drawing and refreshes the client area.

 *  The result is a blank slate as if the application had just been launched.

 *

 */

STDMETHODIMP

CPane::Clear()

{

    m_pLines->Clear();

    m_pPoints->Clear();

    ::InvalidateRect(m_hwnd, NULL, TRUE);

    UpdateWindow(m_hwnd);

    m_nMaxX = m_nMaxY = -1;

    return NOERROR;

}

/*

 * CPane::Refresh

 *

 * Purpose:

 *  Invalidates the entire drawing window so the drawing is cleared

 *  and each of the lines in the Lines collection is redrawn.

 *

 */

STDMETHODIMP

CPane::Refresh()

{

    ::InvalidateRect(m_hwnd, NULL, TRUE);

    UpdateWindow(m_hwnd);

    return NOERROR;

}

/*

 *

 * The following methods are not exposed through Automation

 *

 */

STDMETHODIMP_(void)

CPane::Draw(void)

{

    PAINTSTRUCT ps;

    BeginPaint(m_hwnd, &ps);

    SetMapMode(ps.hdc, MM_TWIPS);

    SetWindowOrgEx(ps.hdc, 0, m_nHeight, NULL);

    m_pLines->Draw(ps.hdc);

    EndPaint(m_hwnd, &ps);

}

/*

 * CPane::OnSize

 *

 * Purpose:

 *  Called when the pane is resized. Remembers the new size and gets the new maximum visible

 *  x and y coordinates.

 *

 */

STDMETHODIMP_(void)

CPane::OnSize(unsigned int nWidth, unsigned int nHeight)

{

   HDC hdc;

   POINT pt;

   RECT rc;

   // Translate the height and width of pane from device units to twips.

   hdc = ::GetDC(m_hwnd);

   SetMapMode(hdc, MM_TWIPS);

   pt.x = nWidth; pt.y = nHeight;

   DPtoLP(hdc, &pt, 1);

   m_nWidth = pt.x;

   m_nHeight = -pt.y;

   ::ReleaseDC(m_hwnd, hdc);

   // Get the new max visible x and y coordinates

   SetRect(&rc, 0, 0, m_nWidth, m_nHeight);

   m_pPoints->GetMaxXMaxY(&m_nMaxX, &m_nMaxY, &rc);

}

STDMETHODIMP_(HDC)

CPane::GetDC()

{

    HDC hdc;

    hdc = ::GetDC(m_hwnd);

    SetMapMode(hdc, MM_TWIPS);

    SetWindowOrgEx(hdc, 0, m_nHeight, NULL);

    return hdc;

}

STDMETHODIMP_(void)

CPane::ReleaseDC(HDC hdc)

{

    ::ReleaseDC(m_hwnd, hdc);

}

STDMETHODIMP_(void)

CPane::InvalidateRect(LPRECT prc)

{

    RECT rc;

    HDC hdc;

    int t;

   // Translate the area to be invalidated from twips to device units

   hdc = ::GetDC(m_hwnd);

   SetMapMode(hdc, MM_TWIPS);

   SetWindowOrgEx(hdc, 0, m_nHeight, NULL);

   rc = *prc;

   LPtoDP(hdc, (LPPOINT)&rc.left, 1);

   LPtoDP(hdc, (LPPOINT)&rc.right, 1);

   // Make sure left is not greater than right and top is not greater than bottom. Otherwise

   // InvalidateRect will not invalidate.

   if (rc.right < rc.left)

   {

       t = rc.right;

       rc.right = rc.left;

       rc.left = t;

   }

   if (rc.bottom < rc.top)

   {

       t = rc.bottom;

       rc.bottom = rc.top;

       rc.top = t;

   }

   ::InvalidateRect(m_hwnd, &rc, TRUE);

   ::ReleaseDC(m_hwnd, hdc);

}

STDMETHODIMP_(void)

CPane::Update(void)

{

    UpdateWindow(m_hwnd);

}

/*

 * CPane::AddPoint

 *

 * Purpose:

 *  Adds a point to the point collection. Updates max visible coordinates is required.

 *

 */

STDMETHODIMP_(BOOL)

CPane::AddPoint(CPoint FAR* pPoint)

{

    int nX, nY;

    nX = pPoint->get_x();

    nY = pPoint->get_y();

    if (nX > m_nMaxX && nX <= m_nWidth)

        m_nMaxX = nX;

    if (nY > m_nMaxY && nY <= m_nHeight)

        m_nMaxY = nY;

    return m_pPoints->Add(pPoint);

}

/*

 * CPane::RemovePoint

 *

 * Purpose:

 *  Removes point from point collection. Updates max visible coordinates is required.

 *

 */

STDMETHODIMP_(void)

CPane::RemovePoint(CPoint FAR* pPoint)

{

    RECT rc;

    // If point was removed from the collection, update max visible X & Y coordinates

    if (m_pPoints->Remove(pPoint))

    {

        SetRect(&rc, 0, 0, m_nWidth, m_nHeight);

        m_pPoints->GetMaxXMaxY(&m_nMaxX, &m_nMaxY, &rc);

    }

}

/*

 * CPane::RaiseException

 *

 * Purpose:

 *  Fills the EXCEPINFO structure and signal IDispatch::Invoke to return DISP_E_EXCEPTION.

 *  Sets ErrorInfo object for vtable-binding controllers.

 *

 */

STDMETHODIMP

CPane::RaiseException(int nID)

{

    extern SCODE g_scodes[];

    TCHAR szError[STR_LEN];

    ICreateErrorInfo *pcerrinfo;

    IErrorInfo *perrinfo;

    HRESULT hr;

    _fmemset(&m_excepinfo, 0, sizeof(EXCEPINFO));

    m_excepinfo.wCode = nID;

    if (LoadString(g_pApplication->m_hinst, nID, szError, sizeof(szError)))

        m_excepinfo.bstrDescription = SysAllocString(TO_OLE_STRING(szError));

    m_excepinfo.bstrSource = SysAllocString(g_pApplication->m_bstrProgID);

    m_bRaiseException = TRUE;

    // Set ErrInfo object so that vtable binding containers can get

    // rich error information.

    hr = CreateErrorInfo(&pcerrinfo);

    if (SUCCEEDED(hr))

    {

       pcerrinfo->SetGUID(IID_IPane);

       if (m_excepinfo.bstrSource)

           pcerrinfo->SetSource(m_excepinfo.bstrSource);

       if (m_excepinfo.bstrDescription)

           pcerrinfo->SetDescription(m_excepinfo.bstrDescription);

       hr = pcerrinfo->QueryInterface(IID_IErrorInfo, (LPVOID FAR*) &perrinfo);

       if (SUCCEEDED(hr))

       {

          SetErrorInfo(0, perrinfo);

          perrinfo->Release();

       }

       pcerrinfo->Release();

    }

    return ResultFromScode(g_scodes[nID-1001]);

}


 POINT.CPP   (LINES OLE Sample)

/*************************************************************************

**

**    OLE Automation Points Object.

**

**    point.cpp

**

**    CPoint implementation

**

**     Written by Microsoft Product Support Services, Windows Developer Support

**    (c) Copyright Microsoft Corp. 1994 All Rights Reserved

**

*************************************************************************/

#include <windows.h>

#include <windowsx.h>

#ifdef WIN16

  #include <ole2.h>

  #include <compobj.h>

  #include <dispatch.h>

  #include <variant.h>

  #include <olenls.h>

#endif

#include "lines.h"

/*

 * CPoint::Create

 *

 * Purpose:

 *  Creates an instance of the Point automation object and initializes it.

 *

 * Parameters:

 *  ppPoint    Returns Point automation object.

 *

 * Return Value:

 *  HRESULT

 *

 */

HRESULT

CPoint::Create(CPoint FAR* FAR* ppPoint )

{

    HRESULT hr;

    CPoint FAR* pPoint = NULL;

    *ppPoint = NULL;

    pPoint = new CPoint();

    if (pPoint == NULL)

        goto error;

    // Load type information for the point from type library.

    hr = LoadTypeInfo(&pPoint->m_ptinfo, IID_IPoint);

    if (FAILED(hr))

        goto error;

    *ppPoint = pPoint;

    return NOERROR;

error:

    if (pPoint == NULL)

        return ResultFromScode(E_OUTOFMEMORY);

    if (pPoint->m_ptinfo)

        pPoint->m_ptinfo->Release();

    // Set to NULL to prevent destructor from attempting to free again

    pPoint->m_ptinfo = NULL;

    delete pPoint;

    return hr;

}

/*

 * CPoint::CPoint

 *

 * Purpose:

 *  Constructor for CPoint object. Initializes members to NULL.

 *

 */

#pragma warning (disable : 4355)

CPoint::CPoint() : m_SupportErrorInfo(this, IID_IPoint)

#pragma warning (default : 4355)

{

    m_cRef = 0;

    m_cInternalRef = 0;

    m_ptinfo = NULL;

    m_nX = -1;

    m_nY = -1;

}

/*

 * CPoint::~CPoint

 *

 * Purpose:

 *  Destructor for CPoint object. Frees Point message BSTR and default

 *  IDispatch implementation. Closes the aplication.

 *

 */

CPoint::~CPoint()

{

     if (m_ptinfo) m_ptinfo->Release();

}

/*

 * CPoint::QueryInterface, AddRef, Release

 *

 * Purpose:

 *  Implements IUnknown::QueryInterface, AddRef, Release

 *

 */

STDMETHODIMP

CPoint::QueryInterface(REFIID iid, void FAR* FAR* ppv)

{

    *ppv = NULL;

    if (iid == IID_IUnknown || iid == IID_IDispatch || iid == IID_IPoint)

        *ppv = this;

    else if (iid == IID_ISupportErrorInfo)

        *ppv = &m_SupportErrorInfo;

    else return ResultFromScode(E_NOINTERFACE);

    AddRef();

    return NOERROR;

}

STDMETHODIMP_(ULONG)

CPoint::AddRef(void)

{

#ifdef _DEBUG

    TCHAR ach[50];

    wsprintf(ach, TEXT("Ref = %ld, Point\r\n"), m_cRef+1);

    OutputDebugString(ach);

#endif

    return ++m_cRef;

}

STDMETHODIMP_(ULONG)

CPoint::Release(void)

{

#ifdef _DEBUG

    TCHAR ach[50];

    wsprintf(ach, TEXT("Ref = %ld, Point\r\n"), m_cRef-1);

    OutputDebugString(ach);

#endif

    if(--m_cRef == 0)

    {

        delete this;

        return 0;

    }

    return m_cRef;

}

/*

 * CPoint::GetTypeInfoCount

 *

 * Purpose:

 *  Implements IDispatch::GetTypeInfoCount.

 *

 */

STDMETHODIMP

CPoint::GetTypeInfoCount(UINT FAR* pctinfo)

{

    *pctinfo = 1;

    return NOERROR;

}

/*

 * CPoint::GetTypeInfo

 *

 * Purpose:

 *  Implements IDispatch::GetTypeInfo.

 *

 */

STDMETHODIMP

CPoint::GetTypeInfo(

      UINT itinfo,

      LCID lcid,

      ITypeInfo FAR* FAR* pptinfo)

{

    *pptinfo = NULL;

    if(itinfo != 0)

        return ResultFromScode(DISP_E_BADINDEX);

    m_ptinfo->AddRef();

    *pptinfo = m_ptinfo;

    return NOERROR;

}

/*

 * CPoint::GetIDsOfNames

 *

 * Purpose:

 *  Implements IDispatch::GetIDsOfNames.  The standard implementation, DispGetIDsOfNames,

 *  is used.

 *

 */

STDMETHODIMP

CPoint::GetIDsOfNames(

      REFIID riid,

      OLECHAR FAR* FAR* rgszNames,

      UINT cNames,

      LCID lcid,

      DISPID FAR* rgdispid)

{

    return DispGetIDsOfNames(m_ptinfo, rgszNames, cNames, rgdispid);

}

/*

 * CPoint::Invoke

 *

 * Purpose:

 *  Implements IDispatch::Invoke.  The standard implementation, DispInvoke,

 *  is used.

 *

 */

STDMETHODIMP

CPoint::Invoke(

      DISPID dispidMember,

      REFIID riid,

      LCID lcid,

      WORD wFlags,

      DISPPARAMS FAR* pdispparams,

      VARIANT FAR* pvarResult,

      EXCEPINFO FAR* pexcepinfo,

      UINT FAR* puArgErr)

{

    return DispInvoke(

        this, m_ptinfo,

        dispidMember, wFlags, pdispparams,

        pvarResult, pexcepinfo, puArgErr);

}

STDMETHODIMP

CPoint::get_x(int FAR* pnX)

{

    *pnX = m_nX;

    return NOERROR;

}

STDMETHODIMP

CPoint::put_x(int nX)

{

    m_nX = nX;

    return NOERROR;

}

STDMETHODIMP

CPoint::get_y(int FAR* pnY)

{

    *pnY = m_nY;

    return NOERROR;

}

STDMETHODIMP

CPoint::put_y(int nY)

{

    m_nY = nY;

    return NOERROR;

}

/*

 *

 * The following methods are not exposed through Automation

 *

 */

/*

 * CPoint::InternalAddRef, InternalRelease

 *

 * Purpose:

 *  Implements an internal ref count for the use of the points collection.

 *  The points collection does not have duplicates, instead a reference count is incremented.

 *  A point is removed from the collection when the reference count drops to 0.

 *

 */

STDMETHODIMP_(ULONG)

CPoint::InternalAddRef(void)

{

#ifdef _DEBUG

    TCHAR ach[50];

    wsprintf(ach, TEXT("Internal Ref = %ld, Point\r\n"), m_cInternalRef+1);

    OutputDebugString(ach);

#endif

    return ++m_cInternalRef;

}

STDMETHODIMP_(ULONG)

CPoint::InternalRelease(void)

{

#ifdef _DEBUG

    TCHAR ach[50];

    wsprintf(ach, TEXT("Internal Ref = %ld, Point\r\n"), m_cInternalRef-1);

    OutputDebugString(ach);

#endif

    return --m_cInternalRef;

}

STDMETHODIMP_(int)

CPoint::get_x(void)

{

    return m_nX;

}

STDMETHODIMP_(int)

CPoint::get_y(void)

{

    return m_nY;

}


 POINTS.CPP   (LINES OLE Sample)

/*************************************************************************

**

**    OLE Automation Points object

**

**    points.cpp

**

**    CPoints collection implementation

**

**     Written by Microsoft Product Support Services, Windows Developer Support

**    (c) Copyright Microsoft Corp. 1993 All Rights Reserved

**

*************************************************************************/

#include <windows.h>

#include <windowsx.h>

#ifdef WIN16

  #include <ole2.h>

  #include <compobj.h>

  #include <dispatch.h>

  #include <variant.h>

  #include <olenls.h>

#endif

#include "lines.h"

/*

 * CPoints::Create

 *

 * Purpose:

 *  Creates an instance of a collection object and initializes it.

 *

 * Parameters:

 *  lMaxSize   Maximum number of items that can added to collection.

 *  lLBound    Lower bound of index of collection.

 *  pPane      Pointer to pane that contains this collection. Required because the pane coordinates

 *             the lines and points collection.

 *  ppPoints    Returns collection object.

 *

 * Return Value:

 *  HRESULT

 *

 */

HRESULT

CPoints::Create(ULONG lMaxSize, long lLBound, CPane FAR* pPane, CPoints FAR* FAR* ppPoints)

{

    HRESULT hr;

    CPoints FAR* pPoints = NULL;

    SAFEARRAYBOUND sabound[1];

    *ppPoints = NULL;

    // Create new collection

    pPoints = new CPoints();

    if (pPoints == NULL)

        goto error;

    pPoints->m_cMax = lMaxSize;

    pPoints->m_cElements = 0;

    pPoints->m_lLBound = lLBound;

    pPoints->m_pPane = pPane;

    // Load type information for the points collection from type library.

    hr = LoadTypeInfo(&pPoints->m_ptinfo, IID_IPoints);

    if (FAILED(hr))

        goto error;

    // Create a safe array which is used to implement the collection.

    sabound[0].cElements = lMaxSize;

    sabound[0].lLbound = lLBound;

    pPoints->m_psa = SafeArrayCreate(VT_VARIANT, 1, sabound);

    if (pPoints->m_psa == NULL)

    {

        hr = ResultFromScode(E_OUTOFMEMORY);

        goto error;

    }

    *ppPoints = pPoints;

    return NOERROR;

error:

    if (pPoints == NULL)

        return ResultFromScode(E_OUTOFMEMORY);

    if (pPoints->m_ptinfo)

        pPoints->m_ptinfo->Release();

    if (pPoints->m_psa)

        SafeArrayDestroy(pPoints->m_psa);

    pPoints->m_psa = NULL;

    pPoints->m_ptinfo = NULL;

    delete pPoints;

    return hr;

}

/*

 * CPoints::CPoints

 *

 * Purpose:

 *  Constructor for CPoints object. Initializes members to NULL.

 *

 */

#pragma warning (disable : 4355)

CPoints::CPoints() : m_SupportErrorInfo(this, IID_IPoints)

#pragma warning (default : 4355)

{

    m_cRef = 0;

    m_psa = NULL;

    m_ptinfo = NULL;

}

/*

 * CPoints::~CPoints

 *

 * Purpose:

 *  Destructor for CPoints object.

 *

 */

CPoints::~CPoints()

{

     if (m_ptinfo) m_ptinfo->Release();

     if (m_psa) SafeArrayDestroy(m_psa);

}

/*

 * CPoints::QueryInterface, AddRef, Release

 *

 * Purpose:

 *  Implements IUnknown::QueryInterface, AddRef, Release

 *

 */

STDMETHODIMP

CPoints::QueryInterface(REFIID iid, void FAR* FAR* ppv)

{

    *ppv = NULL;

    if (iid == IID_IUnknown || iid == IID_IPoints || iid == IID_IDispatch)

        *ppv = this;

    else if (iid == IID_ISupportErrorInfo)

        *ppv = &m_SupportErrorInfo;

    else return ResultFromScode(E_NOINTERFACE);

    AddRef();

    return NOERROR;

}

STDMETHODIMP_(ULONG)

CPoints::AddRef(void)

{

#ifdef _DEBUG

    TCHAR ach[50];

    wsprintf(ach, TEXT("Ref = %ld, Points\r\n"), m_cRef+1);

    OutputDebugString(ach);

#endif

    return ++m_cRef;

}

STDMETHODIMP_(ULONG)

CPoints::Release(void)

{

#ifdef _DEBUG

    TCHAR ach[50];

    wsprintf(ach, TEXT("Ref = %ld, Points\r\n"), m_cRef-1);

    OutputDebugString(ach);

#endif

    if(--m_cRef == 0)

    {

        delete this;

        return 0;

    }

    return m_cRef;

}

/*

 * CPoints::GetTypeInfoCount

 *

 * Purpose:

 *  Implements IDispatch::GetTypeInfoCount.

 *

 */

STDMETHODIMP

CPoints::GetTypeInfoCount(UINT FAR* pctinfo)

{

    *pctinfo = 1;

    return NOERROR;

}

/*

 * CPoints::GetTypeInfo

 *

 * Purpose:

 *  Implements IDispatch::GetTypeInfo.

 *

 */

STDMETHODIMP

CPoints::GetTypeInfo(

      UINT itinfo,

      LCID lcid,

      ITypeInfo FAR* FAR* pptinfo)

{

    *pptinfo = NULL;

    if(itinfo != 0)

        return ResultFromScode(DISP_E_BADINDEX);

    m_ptinfo->AddRef();

    *pptinfo = m_ptinfo;

    return NOERROR;

}

/*

 * CPoints::GetIDsOfNames

 *

 * Purpose:

 *  Implements IDispatch::GetIDsOfNames.  The standard implementation, DispGetIDsOfNames,

 *  is used.

 *

 */

STDMETHODIMP

CPoints::GetIDsOfNames(

      REFIID riid,

      OLECHAR FAR* FAR* rgszNames,

      UINT cNames,

      LCID lcid,

      DISPID FAR* rgdispid)

{

    return DispGetIDsOfNames(m_ptinfo, rgszNames, cNames, rgdispid);

}

/*

 * CPoints::Invoke

 *

 * Purpose:

 *  Implements IDispatch::Invoke.  The standard implementation, DispInvoke,

 *  is used. Properties and methods exposed by the points object will

 *  set m_bRaiseException to raise an exception.

 *

 */

STDMETHODIMP

CPoints::Invoke(

      DISPID dispidMember,

      REFIID riid,

      LCID lcid,

      WORD wFlags,

      DISPPARAMS FAR* pdispparams,

      VARIANT FAR* pvarResult,

      EXCEPINFO FAR* pexcepinfo,

      UINT FAR* puArgErr)

{

    HRESULT hr;

    m_bRaiseException = FALSE;

    hr =  DispInvoke(

        this, m_ptinfo,

        dispidMember, wFlags, pdispparams,

        pvarResult, pexcepinfo, puArgErr);

    if (m_bRaiseException)

    {

       if (NULL != pexcepinfo)

           _fmemcpy(pexcepinfo, &m_excepinfo, sizeof(EXCEPINFO));

       return ResultFromScode(DISP_E_EXCEPTION);

    }

    else return hr;

}

/*

 * CPoints::get_Count

 *

 * Purpose:

 *  Returns number of items in collection.

 *

 */

STDMETHODIMP

CPoints::get_Count(long FAR* plCount)

{

    *plCount = m_cElements;

    return NOERROR;

}

/*

 * CPoints::get_Item

 *

 * Purpose:

 *  Retrieves item from collection, given an index.

 *

 * Parameters:

 *   lIndex   Index of item to be retrieved.

 *

 * Returns

 *  IDispatch of item retrieved from collection.

 *

 */

STDMETHODIMP

CPoints::get_Item(long lIndex, IPoint FAR* FAR* ppPoint)

{

    HRESULT hr;

    VARIANT v;

    LPDISPATCH pdisp = NULL;

    // Check if integer index is within range

    if (lIndex < m_lLBound || lIndex >= (long)(m_lLBound+m_cElements))

        return RaiseException(IDS_InvalidIndex);

    // Retrieve and return item. Note that SafeArrayGetElement AddRefs so an additional AddRef

    // is not required.

    VariantInit(&v);

    hr = SafeArrayGetElement(m_psa, &lIndex, &v);

    if (FAILED(hr))

        return RaiseException(IDS_Unexpected);

    *ppPoint = (IPoint FAR*) V_DISPATCH(&v);

    return NOERROR;

}

/*

 * CPoints::get_NewEnum

 *

 * Purpose:

 *  Returns an enumerator (IEnumVARIANT) for the items curently in the collection.

 *  The NewEnum property is restricted and so is invisible to users of an

 *  automation controller's scripting language. Automation controllers that support

 *  a 'For Each' statement to iterate through the elements of a collection will use

 *  the enumerator returned by NewEnum. The enumerator creates a snapshot of the

 *  the current state of the collection.

 *

 */

STDMETHODIMP

CPoints::get__NewEnum(IUnknown FAR* FAR* ppunkEnum)

{

    CEnumVariant FAR* penum = NULL;

    HRESULT hr;

    // Create new enumerator for items currently in collection and QI for IUnknown

    hr = CEnumVariant::Create(m_psa, m_cElements, &penum);

    if (FAILED(hr))

        {hr = RaiseException(IDS_OutOfMemory); goto error;}

    hr = penum->QueryInterface(IID_IUnknown, (VOID FAR* FAR*)ppunkEnum);

    if (FAILED(hr))

        {hr = RaiseException(IDS_Unexpected); goto error;}

    return NOERROR;

error:

    if (penum)

        delete penum;

    return hr;

}

/*

 *

 * The following methods are not exposed through Automation

 *

 */

/*

 * CPoints::Add

 *

 * Purpose:

 *  Adds an item to the collection. The points collection does not have duplicates.

 *

 * Parameters:

 *  pPointAdd    Point to be added to collection.

 *

 */

STDMETHODIMP_(BOOL)

CPoints::Add(CPoint FAR* pPointAdd)

{

    HRESULT hr;

    LONG l;

    VARIANT v;

    VARIANT HUGEP *pvar;

    int nX, nY;

    BOOL bFound = FALSE;

    LPDISPATCH pdispPointAdd = NULL;

    CPoint FAR *pPoint;

    LPDISPATCH pdispPoint;

    // Is the collection full?

    if (m_cElements == m_cMax)

        goto error;

    // Get coordinates of point to be added to collection

    nX = pPointAdd->get_x();

    nY = pPointAdd->get_y();

    hr = SafeArrayAccessData(m_psa, (void HUGEP* FAR*)&pvar);

    if (FAILED(hr))

        goto error;

    // Check if point to be added is already in the collection.

    for (l=0; l<(long)m_cElements; l++)

    {

        pdispPoint = V_DISPATCH(&pvar[l]);

        hr = pdispPoint->QueryInterface(IID_IPoint, (void FAR* FAR*)&pPoint);

        if (FAILED(hr))

            continue;

        if (nX == pPoint->get_x() &&  nY == pPoint->get_y())

        {

            // Point is already in the collection. AddRef it.

            // Internal AddRef keeps track of number of times this point was added to this collection. When

            //    this internal ref count drops to 0, this point can be removed from this collection.

            pPoint->InternalAddRef();

            pdispPoint->AddRef();

            bFound = TRUE;

            pPoint->Release();

            break;

        }

        pPoint->Release();

    }

    hr = SafeArrayUnaccessData(m_psa);

    if (FAILED(hr))

       goto error;

    // Add point if it was not in the collection.

    if (!bFound)

    {

        l = m_lLBound+m_cElements;

        hr = pPointAdd->QueryInterface(IID_IDispatch, (void FAR* FAR*)&pdispPointAdd);

        if (FAILED(hr))

            goto error;

        VariantInit(&v);

        V_VT(&v) = VT_DISPATCH;

        V_DISPATCH(&v) = pdispPointAdd;

        hr = SafeArrayPutElement(m_psa, &l, &v);

        if (FAILED(hr))

            goto error;

        // Internal AddRef keeps track of number of times this point was added to this collection. When

        //    this internal ref count drops to 0, this point can be removed from this collection.

        pPointAdd->InternalAddRef();

        pdispPointAdd->Release();

        m_cElements++;

    }

    return TRUE;

error:

    if (pdispPointAdd)

        pdispPointAdd->Release();

    return FALSE;

}

/*

 * CPoints::Remove

 *

 * Purpose:

 *  Removes specified item from collection. The points collection does not have duplicates.

 *

 * Parameters:

 *   pPointRemove    Point to be removed from collection.

 *

 */

STDMETHODIMP_(BOOL)

CPoints::Remove(CPoint FAR* pPointRemove)

{

    HRESULT hr;

    long l, lIndex;

    VARIANT HUGEP *pvar;

    ULONG cRef;

    int nX, nY;

    CPoint FAR* pPoint = NULL;

    BOOL bFound = FALSE;

    BOOL bRet = FALSE;

    // Get coordinates of point to be removed from collection

    nX = pPointRemove->get_x();

    nY = pPointRemove->get_y();

    hr = SafeArrayAccessData(m_psa, (void HUGEP* FAR*)&pvar);

    if (FAILED(hr))

       goto error;

    // Check if point to be removed is in the collection.

    for (l=0; l<(long)m_cElements; l++)

    {

        hr = V_DISPATCH(&pvar[l])->QueryInterface(IID_IPoint, (void FAR* FAR*)&pPoint);

        if (FAILED(hr))

            continue;

        if (nX == pPoint->get_x() &&  nY == pPoint->get_y())

        {

            // Release point. Note that this collection does not have duplicates. Duplicate

            // points are handled by increasing the ref count.

            V_DISPATCH(&pvar[l])->Release();

            cRef = pPoint->InternalRelease();

            bFound = TRUE;

            lIndex = l;

            pPoint->Release();

            break;

        }

        pPoint->Release();

    }

    // If the internal ref count of point to be removed has dropped to 0, move up the array elements

    // after the element to be removed.

    if (bFound && cRef == 0)

    {

        for (l=lIndex; l<(long)(m_cElements-1); l++)

            pvar[l] = pvar[l+1];

        // Remove last element.

        V_VT(&pvar[l]) = VT_EMPTY;

        m_cElements--;

        bRet = TRUE;

    }

    hr = SafeArrayUnaccessData(m_psa);

    if (FAILED(hr))

       goto error;

    return bRet;

error:

    return FALSE;

}

/*

 * CPoints::Clear

 *

 * Purpose:

 *  Removes all items from collection.

 *

 */

STDMETHODIMP_(void)

CPoints::Clear(void)

{

    SafeArrayDestroyData(m_psa);

    SafeArrayAllocData(m_psa);

    m_cElements = 0;

}

/*

 * CPoints::GetMaxXMaxY

 *

 * Purpose:

 *  Get the maximum X and Y coordinates that are in the rectangle, prc.

 *

 */

STDMETHODIMP_(void)

CPoints::GetMaxXMaxY(int FAR *pnX, int FAR *pnY, LPRECT prc)

{

    HRESULT hr;

    long l;

    VARIANT HUGEP *pvar;

    int nMaxX, nMaxY;

    CPoint FAR* pPoint;

    POINT pt;

    hr = SafeArrayAccessData(m_psa, (void HUGEP* FAR*)&pvar);

    if (FAILED(hr))

       return;

    nMaxX = -1; nMaxY = -1;

    // Find the maximume X and Y coordinates that are in the prc rectangle.

    for (l=0; l<(long)m_cElements; l++)

    {

        V_DISPATCH(&pvar[l])->QueryInterface(IID_IPoint, (void FAR* FAR*)&pPoint);

        pt.x = pPoint->get_x();

        pt.y = pPoint->get_y();

        if (PtInRect(prc, pt))

        {

            if (pt.x > nMaxX)

                nMaxX = pt.x;

            if (pt.y > nMaxY)

                nMaxY = pt.y;

        }

        pPoint->Release();

    }

    *pnX = nMaxX;

    *pnY = nMaxY;

    SafeArrayUnaccessData(m_psa);

    return;

}

/*

 * CPoints::RaiseException

 *

 * Purpose:

 *  Fills the EXCEPINFO structure and signal IDispatch::Invoke to return DISP_E_EXCEPTION.

 *  Sets ErrorInfo object for vtable-binding controllers.

 *

 */

STDMETHODIMP

CPoints::RaiseException(int nID)

{

    extern SCODE g_scodes[];

    TCHAR szError[STR_LEN];

    ICreateErrorInfo *pcerrinfo;

    IErrorInfo *perrinfo;

    HRESULT hr;

    _fmemset(&m_excepinfo, 0, sizeof(EXCEPINFO));

    m_excepinfo.wCode = nID;

    if (LoadString(g_pApplication->m_hinst, nID, szError, sizeof(szError)))

        m_excepinfo.bstrDescription = SysAllocString(TO_OLE_STRING(szError));

    m_excepinfo.bstrSource = SysAllocString(g_pApplication->m_bstrProgID);

    m_bRaiseException = TRUE;

    // Set ErrInfo object so that vtable binding containers can get

    // rich error information.

    hr = CreateErrorInfo(&pcerrinfo);

    if (SUCCEEDED(hr))

    {

       pcerrinfo->SetGUID(IID_IPoints);

       if (m_excepinfo.bstrSource)

           pcerrinfo->SetSource(m_excepinfo.bstrSource);

       if (m_excepinfo.bstrDescription)

           pcerrinfo->SetDescription(m_excepinfo.bstrDescription);

       hr = pcerrinfo->QueryInterface(IID_IErrorInfo, (LPVOID FAR*) &perrinfo);

       if (SUCCEEDED(hr))

       {

          SetErrorInfo(0, perrinfo);

          perrinfo->Release();

       }

       pcerrinfo->Release();

    }

    return ResultFromScode(g_scodes[nID-1001]);

}


256-Color Support in OLE 2.0 Containers

PSS ID Number: Q98872

Authored 16-May-1993	Last modified 24-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.0

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

SUMMARY

If a client application draws a 256-color object in OLE version 1.0,

the palette is always realized and used during the OleDraw command. As

a result, the palette from the last object displayed is always used,

causing previously drawn objects to update poorly.

In OLE version 2.0, OleDraw does not realize the palette

automatically. Instead, a container must call

IViewObject::GetColorSet() to retrieve the logical palette for each of

its displayed objects. With this information, the container can

construct a palette that best suits all of its displayed objects.

MORE INFORMATION

To get the equivalent of OLE 1.0 functionality in an OLE 2.0

container, IViewObject::GetColorSet must still be used to get a

logical palette for an object, and in turn a palette must be created

and realized from this information.

The following C++ function demonstrates the implementation of a

drawing routine for an OLE 2.0 container that behaves similar to an

OLE 1.0 client application.

Sample Code

-----------

void DrawObject(LPOLEOBJECT lpOleObject)

{

LPVIEWOBJECT lpViewObject;

    // Get a pointer to IViewObject.

    lpOleObject->QueryInterface(IID_IViewObject,

                                (LPVOID FAR *) &lpViewObject);

    // If the QI succeeds, get the LOGPALETTE for the object.

    if (lpView)

        lpView->GetColorSet(DVASPECT_CONTENT, -1, NULL, NULL, NULL,

                            &pColorSet);

    HPALETTE hPal=NULL;

    HPALETTE hOldPal=NULL;

    // If a LOGPALETTE was returned (not guaranteed), create the

    // palette and realize it. Note: A smarter application

    // would want to get the LOGPALETTE for each of its visible

    // objects, and try to create a palette that satisfies all of the

    // visible objects. Also, OleStdFree() is use to free the

    // returned LOGPALETTE.

    if ((pColorSet))

        {

        hPal = CreatePalette((const LPLOGPALETTE) pColorSet);

        hOldPal = SelectPalette(hDC, hPal, FALSE);

        RealizePalette(hDC);

        OleStdFree(pColorSet);

        }

    // Draw the object.

    OleDraw(m_lpOleObject, DVASPECT_CONTENT, hDC, &rect);

    // If we created a palette, restore the old one and destroy

    // the object.

    if (hPal)

        {

        SelectPalette(hDC,hOldPal,FALSE);

        DeleteObject(hPal);

        }

    // If a view pointer was successfully returned, it needs to be

    // released.

    if (lpView)

        lpView->Release();

}

Additional reference words: 1.00 2.00 3.50 4.00 95

KBCategory: kbole kbprg

KBSubcategory: LeTwoPrs


Adding Type Libraries as Resources to .DLL and .EXE Files

PSS ID Number: Q122285

Authored 01-Nov-1994	Last modified 21-Apr-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.02

A type library can be added as a resource to an .EXE or .DLL file by using

the following statement in the .RC file:

   1 typelib TEST.TLB

TEST.TLB is the type library to be added as a resource.

If a type library is added as a resource, a separate .TLB file need not be

shipped with the application. LoadTypeLib() and LoadRegTypeLib() can be

used to load the type library from the .EXE or .DLL file in which it exists

as a resource.

NOTE: OLE version 2.02 or higher is needed to read a type library from an

.EXE file.

Additional reference words: 2.00 Automation

KBCategory: kbole kbprg

KBSubcategory: LeTwoAto


BUG: (I)CntrOutl Does Not Set Target Device Information

PSS ID Number: Q108310

Authored 08-Dec-1993	Last modified 17-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

SYMPTOMS

During the print process from (I)CntrOutl, a server application is asked to

render its display with the TARGETDEVICE structure set to NULL instead of

containing a valid structure. This implies that (I)CntrOutl wants a screen

representation rather than a printed representation of the object.

CAUSE

(I)CntrOutl is not filling out the TARGETDEVICE structure; it prefers to

use a screen representation on the printer, rather than request the printed

presentation.

STATUS

Microsoft has confirmed this to be a problem in the Microsoft products

listed at the beginning of this article. We are researching this problem

and will post new information here as it becomes available.

Additional reference words: 2.01 3.50 4.00

KBCategory: kbole kbbuglist

KBSubcategory: LeTwoTls


BUG: Accelerator Causes Crash in ISvrOutl Embedded in C12Test

PSS ID Number: Q108311

Authored 08-Dec-1993	Last modified 17-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

SYMPTOMS

After embedding an ISvrOutl object in Cl2Test or Cl32Test, pressing the

ALT+BACKSPACE accelerator (Undo) results in a general protection (GP) fault

within ISvrOutl.

STATUS

Microsoft has confirmed this to be a problem in the Cl2Test (Cl32Test) test

application. We are researching this problem and will post new information

here as it becomes available.

Additional reference words: 2.01 3.50 4.00 Outline Server Inplace GPF gp-

fault crash

KBCategory: kbole kbbuglist

KBSubcategory: LeTwoTls


BUG: Borland WINSIGHT Causes GP Faults w/ Some OLE Sample

PSS ID Number: Q112410

Authored 08-Mar-1994	Last modified 21-Apr-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

SYMPTOMS

If Borland's WINSIGHT tool is running when you start some of the sample

applications that have been included in the OLE 2.01 SDK, a general

protection (GP) Fault will occur before the main application window

appears.

The following OLE 2.01 SDK sample applications are affected:

   cl2test.exe

   sr2test.exe

   outline.exe

   cntroutl.exe

   svroutl.exe

   icntrotl.exe

   isvrotl.exe

STATUS

Microsoft has confirmed this to be a problem in the OLE SDK version 2.01.

We are researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

Additional reference words: 2.01 toolkit gpf gp-fault buglist2.01

KBCategory: kbole kbbuglist

KBSubcategory: LeTwoTls


BUG: Cannot Paste Link SR2TEST Object in OLE 1.0 Client

PSS ID Number: Q108932

Authored 20-Dec-1993	Last modified 17-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

SYMPTOMS

The Paste Link option is not available in an OLE 1.0 client application

after copying an unsaved SR2TEST object to the clipboard.

CAUSE

SR2TEST is not setting the OLEMISC_CANLINKBYOLE1 bit in the Link Source

Descriptor that it places onto the clipboard.

STATUS

Microsoft has confirmed this to be a problem in the Microsoft products

listed at the beginning of this article. We are researching this problem

and will post new information here as it becomes available.

Additional reference words: 2.01 3.50 4.00 test

KBCategory: kbole kbbuglist

KBSubcategory: LeTwoTls


BUG: CL2TEST Does Not Display Prompt String from GetCurFile()

PSS ID Number: Q111014

Authored 03-Feb-1994	Last modified 24-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

SYMPTOMS

IPersistFile::GetCurFile() returns S_FALSE to indicate that the document

has no currently associated file. In this case, GetCurFile() returns the

default prompt string for the filename (as would be displayed in the Save

As dialog box under the File menu) in the lplpszFileName parameter.

When CL2TEST calls IPersistFile::GetCurFile(), and GetCurFile() returns

S_FALSE, CL2TEST fails to display the returned prompt string.

STATUS

Microsoft has confirmed this to be a problem in the Microsoft products

listed at the beginning of this article. We are researching this problem

and will post new information here in the Microsoft Knowledge Base as it

becomes available.

MORE INFORMATION

To call IPersistFile::GetCurFile() on an object embedded in CL2TEST, click

the object using the right mouse button, choose PersistFile Method from the

pop-up menu, then choose GetCurFile.

Additional reference words: 2.01 3.50 4.00 95 Toolkit

KBCategory: kbole kbbuglist

KBSubcategory: LeTwoTls


BUG: CL2TEST Fails to Parse Filenames with Extended

PSS ID Number: Q109548

Authored 04-Jan-1994	Last modified 16-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

SYMPTOMS

When attempting to insert a new embedded object from a file, CL2TEST fails

with the error STG_E_FILENOTFOUND if the filename or directory name

provided contains an extended character.

STATUS

Microsoft has confirmed this to be a problem with the CL2TEST sample

application in the Object Linking and Embedding Software Development Kit

(SDK) version 2.01. We are researching this problem and will post new

information here as it becomes available.

This problem does not occur with 32-bit OLE.

MORE INFORMATION

To insert a new embedded object from a file into a CL2TEST document, from

use CL2TEST's Insert menu, choose Embed From File.

Additional reference words: 2.01 toolkit buglist2.01

KBCategory: kbole kbbuglist

KBSubcategory: LeTwoTls


BUG: CL2TEST Handles Icon Aspect Incorrectly

PSS ID Number: Q111339

Authored 09-Feb-1994	Last modified 17-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

SYMPTOMS

Selecting the iconic aspect when inserting an object in CL2TEST results in

the object being created and displayed with the content aspect.

CAUSE

CL2TEST is passing the DVASPECT_CONTENT flag to the embedded object when

calling IViewObject::Draw. The correct flag to pass is DVASPECT_ICON.

STATUS

Microsoft has confirmed this to be a problem in the CL2TEST test

application included with the Object Linking and Embedding SDK version

2.01. We are researching this problem and will post new information here in

the Microsoft Knowledge Base as it becomes available.

MORE INFORMATION

To specify a custom FORMATETC when inserting an object into CL2TEST, choose

the "Select FormatETC" button found on CL2TEST's Create Invisible dialog

box (from the Insert menu, choose Object).

Additional reference words: 2.01 3.50 4.00

KBCategory: kbole kbbuglist

KBSubcategory: LeTwoTls


BUG: CL2TEST Not Properly Activating Links to Embedded

PSS ID Number: Q111340

Authored 09-Feb-1994	Last modified 16-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

SYMPTOMS

Double-clicking a link to an embedded object in CL2TEST results in the

activation remaining on CL2TEST. The correct action would be for the

container of the embedded object to obtain the activation and edit the

object visually (if possible).

STATUS

Microsoft has confirmed this to be a problem in the Object Linking and

Embedding SDK version 2.01.

This is not a problem with the Visual C++ 2.x CL32TEST under Windows NT

3.5.

Additional reference words: 2.01 toolkit buglist2.01

KBCategory: kbole kbbuglist

KBSubcategory: LeTwoTls


BUG: CreateFromTemplate of OLE 2 Object into OLE 1 Container

PSS ID Number: Q111595

Authored 14-Feb-1994	Last modified 17-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

SYMPTOMS

An OLE 2.01 or later object is inserted into an OLE 1.0 container using

OleCreateFromTemplate(). The OLE libraries start the server, but then the

object creation fails, or a blank object is created.

STATUS

Microsoft has confirmed this to be a problem in the Microsoft products

listed at the beginning of this article. We are researching this problem

and will post new information here in the Microsoft Knowledge Base as it

becomes available.

Additional reference words: 2.01 3.50 4.00

KBCategory: kbole kbbuglist

KBSubcategory: LeTwoArc


BUG: Deleting an Open Packager Object Causes GP Fault

PSS ID Number: Q108931

Authored 20-Dec-1993	Last modified 15-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

SYMPTOMS

Deleting an object from within the Object Packager results in a general

protection (GP) fault.

CAUSE

The object is being edited in its server as a result of double-clicking the

Content window. Deleting the object while in this state causes the Object

Packager to GP fault.

STATUS

Microsoft has confirmed this to be a problem in Object Packager version

2.01. We are researching this problem and will post new information here as

it becomes available.

This problem does not occur on Windows NT 3.5, with Object Packager 3.5.

Additional reference words: 2.01 GPF gp-fault crash

KBCategory: kbole kbbuglist

KBSubcategory: LeTwoApp


BUG: DIB Can Be Returned Only on TYMED_HGLOBAL

PSS ID Number: Q98679

Authored 11-May-1993	Last modified 17-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.0

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

SYMPTOMS

IDataObject::GetData returns DV_E_FORMATETC when requesting a

device-independent bitmap (DIB) from an OLE object.

CAUSE

The DIB must be returned in a STGMEDIUM of type TYMED_HGLOBAL.

RESOLUTION

Add TYMED_HGLOBAL to the tymed member of the FORMATETC structure being

passed to IDataObject::GetData.

STATUS

Microsoft has confirmed this to be a problem the Microsoft products listed

at the beginning of this article. We are researching this problem and will

post new information here in the Microsoft Knowledgebase as it becomes

available.

Additional reference words: 2.00 3.50 4.00

KBCategory: kbole kbbuglist

KBSubcategory: LeTwoDdc


BUG: Embedded Object's Size Changes When it Is Run

PSS ID Number: Q110872

Authored 01-Feb-1994	Last modified 17-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

SYMPTOMS

A non-running embedded object is resized in an OLE 2.01 container

application. The next time the object is run, it snaps back to its previous

size.

CAUSE

The container application failed to call IOleObject::SetExtent() after

calling OleRun().

RESOLUTION

IOleObject::SetExtent() can be called only when an object is running. If an

object is resized while it is not running, the container application should

take note of this. When the object is subsequently run, the container

should then inform the object of its new size by calling

IOleObject::SetExtent().

STATUS

Microsoft has confirmed this to be a problem in the Microsoft products

listed at the beginning of this article. We are researching this problem

and will post new information here in the Microsoft Knowledge Base when it

becomes available.

Additional reference words: 2.01 3.50 4.00

KBCategory: kbole kbbuglist

KBSubcategory: LeTwoCdt


BUG: First Entry in Paste Special Dialog Is Blank

PSS ID Number: Q110798

Authored 28-Jan-1994	Last modified 24-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

SYMPTOMS

The first format entry in the Paste Special dialog box is blank after

copying an OLE2Link object from an OLE 1.0 client to the clipboard.

NOTE: An OLE2Link object is created by the OLE 1.0 compatibility layer when

an OLE 2.0 link is copied from an OLE 2.0 application to the clipboard, and

then pasted into an OLE 1.0 client application.

CAUSE

The CLSID and lpszFullUserTypeName of the OBJECTDESCRIPTOR structure are

left blank by the OLE 1.0 compatibility layer.

STATUS

Microsoft has confirmed this to be a problem in the OLE libraries version

2.01. We are researching this problem and will post new information here in

the Microsoft Knowledge Base as it becomes available.

This is not a problem in 32-bit OLE.

Additional reference words: 2.01 buglist2.01

KBCategory: kbole kbbuglist

KBSubcategory: LeTwoArc


BUG: Iconic OLE Object Prints as Black Rectangle on

PSS ID Number: Q110796

Authored 28-Jan-1994	Last modified 16-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

SYMPTOMS

Calling OleDraw() or IViewObject::Draw() to print an iconic OLE object to a

PostScript printer results in a black rectangle being drawn.

CAUSE

Internally, the OLE DLLs (dynamic-link libraries) are using the DrawIcon()

function to draw the icon. DrawIcon() requires the target device to support

the SRCINVERT ROP (raster operation) code. PostScript does not support this

particular ROP code.

RESOLUTION

An application can call OleDraw() or IViewObject::Draw() using a memory DC

(device context). A bitmap of the memory DC can be retrieved, which can be

used with the BitBlt() function to get the correct output to the printer.

STATUS

Microsoft has confirmed this to be a problem in the OLE Libraries version

2.01.

This is not a problem in 32-bit OLE.

Additional reference words: 2.01

KBCategory: kbole kbbuglist

KBSubcategory: LeTwoPrs


BUG: IEnumUnknown Is Not Remoted

PSS ID Number: Q110799

Authored 28-Jan-1994	Last modified 21-Apr-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

SYMPTOMS

All calls to IOleContainer::EnumObjects() fail.

CAUSE

IOleContainer::EnumObjects() returns a pointer to IEnumUnknown. The current

implementation of OLE does not include remoting code for the IEnumUnknown

interface. There is no proxy and stub code, therefore the methods in this

interface cannot be marshaled to another process.

STATUS

Microsoft has confirmed this to be a problem in the OLE Libraries version

2.01. We are researching this problem and will post new information here in

the Microsoft Knowledge Base as it becomes available.

Additional reference words: 2.01 buglist2.01

KBCategory: kbole kbbuglist

KBSubcategory: LeTwoCdt


BUG: Insert Object from Zero Length File Causes GP Fault

PSS ID Number: Q108371

Authored 09-Dec-1993	Last modified 15-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

SYMPTOMS

Creating an object from a zero length file that does not have a valid file

class extension results in a general protection (GP) fault after displaying

the message, "Not enough memory to perform this operation. Close one or

more applications and try again."

CAUSE

When creating an object from a file that does not have a valid class

extension, the Object Packager is invoked to generate the embedded object.

In the case of a zero length source file, the Packager document-level DDE

window is rendered invalid before a terminate message can be sent to it.

STATUS

Microsoft has confirmed this to be a problem in the Object Linking and

Embedding (OLE) libraries version 2.01.

While the operation still fails with Object Packager 3.5 under Windows NT

3.5, the Object Packager provides a better error message.

Additional reference words: 2.01 gpf gp fault

KBCategory: kbole kbbuglist

KBSubcategory: LeTwoArc


BUG: Invisible MSDRAW Object Retains Keyboard Focus

PSS ID Number: Q110715

Authored 27-Jan-1994	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft OLE version 1.0

 - Microsoft OLE Libraries for Windows and Win32s, versions 2.0 and 2.01

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, version 3.5

SYMPTOMS

When an invisible MSDRAW object is inserted as an OLE embedded object,

the object retains the keyboard focus. This behaviour is incorrect. The

MSDRAW object should not take the focus until it has been made visible.

This problem occurs whether the MSDRAW object is inserted into an

OLE 1.0 client application or into an OLE 2.0 container application.

STATUS

Microsoft has confirmed this to be a problem with MSDRAW version 1.0. We

are researching this problem and will post new information here as it

becomes available.

Additional reference words: 1.00 2.00 3.50

KBCategory: kbole kbbuglist

KBSubcategory: LeTwoApp


BUG: IOleCache::Cache Returns Incorrect Error Value

PSS ID Number: Q110488

Authored 24-Jan-1994	Last modified 24-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

SYMPTOMS

An OLE 2.0 container application calls IOleCache::Cache for a particular

FORMATETC and is returned the value OLE_S_FORMATETC_NOTSUPPORTED. A

subsequent call to IOleCache::Cache with the same FORMATETC returns

CACHE_S_SAMECACHE.

CAUSE

The OLE 2.0 server application has a message filter installed and is

rejecting all incoming calls. The default object handler cannot get the

information from the server to fill the cache, but the cache is still

created. A more appropriate return value would be

OLE_S_SOMECACHES_NOTUPDATED.

STATUS

Microsoft has confirmed this to be a problem in the Microsoft products

listed at the beginning of this article. We are researching this problem

and will post new information here in the Microsoft Knowledge Base as it

becomes available.

Additional reference words: 2.01 3.50 4.00 95

KBCategory: kbole kbbuglist

KBSubcategory: LeTwoPrs


BUG: IOleCache::Cache(), ADVF_DATAONSTOP, and OLE 1.0 Objects

PSS ID Number: Q111614

Authored 14-Feb-1994	Last modified 17-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

SYMPTOMS

An OLE 2.0 container application document contains an embedded OLE 1.0

object. The container calls IOleCache::Cache() to control the cached

presentation data for the object, and specifies ADVF_DATAONSTOP as the

advise flag to Cache(). The user makes some changes to the object in the

OLE 1.0 server, then attempts to update the object's presentation in the

server by choosing the Update command from the File menu. Finally, the user

closes the object server.

In this specific scenario, the object's presentation in the server is not

updated. The object's native data, however, is correct.

CAUSE

When the user selects Update, the presentation for the object does not go

across to the cache or the container, because the container specified

ADVF_DATAONSTOP as the cache option. As part of the update operation, the

server internally marks the object as "not dirty". Because the object is

not dirty, when the server is subsequently closed, it does not send any

data to the container or the cache.

RESOLUTION

Container applications should not specify the ADVF_DATAONSTOP flag when

calling IOleCache::Cache(). Instead, they should specify ADVFCACHE_ONSAVE.

When ADVFCACHE_ONSAVE is used, the OLE 1.0 object's cached presentation

data will be updated correctly.

STATUS

Microsoft has confirmed this to be a problem in the Microsoft products

listed at the beginning of this article. We are researching this problem

and will post new information here as it becomes available.

Additional reference words: 2.01 3.50 4.00

KBCategory: kbole kbbuglist

KBSubcategory: LeTwoPrs


BUG: IOleObject::Close(OLECLOSE_NOSAVE) and DoVerb()

PSS ID Number: Q111577

Authored 14-Feb-1994	Last modified 17-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

SYMPTOMS

An OLE 2.0 container application inserts a new embedded object into a

document. The container calls IOleObject::Update() on the object to update

the cache, then calls IOleObject::Close(OLECLOSE_NOSAVE) to transition the

object back to the running state. Finally, the container tries to rerun the

object by calling IOleObject::DoVerb().

In this particular scenario, DoVerb() will return STG_E_FILENOTFOUND, and

the object will not be rerun.

CAUSE

Because the container specifies OLECLOSE_NOSAVE when calling Close(), the

object is never saved to persistent storage. However, the object has

internally been marked as not being a brand new object. Consequently, when

the container calls DoVerb(), the object's handler calls

IPersistStorage::Load() on the object, attempting to put the object into

the running state. This call will fail, because the object has never been

saved.

RESOLUTION

The solution to this problem is for the container to specify

OLECLOSE_SAVEIFDIRTY when calling Close().

STATUS

Microsoft has confirmed this to be a problem in the Microsoft products

listed at the beginning of this article. We are researching this problem

and will post new information here in the Microsoft Knowledge Base as it

becomes available.

Additional reference words: 2.10 3.50 4.00

KBCategory: kbole kbbuglist

KBSubcategory: LeTwoCdt


BUG: IROT::Register() and IOL::SetDisplayName() Inconsistency

PSS ID Number: Q111607

Authored 14-Feb-1994	Last modified 17-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

SYMPTOMS

IRunningObjectTable::Register() allows monikers that are not valid

filenames to be registered as file monikers. However, if the display name

string passed to IOleLink::SetSourceDisplayName() is not a valid filename,

SetSourceDisplayName() returns STG_E_FILENOTFOUND.

STATUS

Microsoft has confirmed this to be a problem in the Microsoft products

listed at the beginning of this article. We are researching this problem

and will post new information here in the Microsoft Knowledge Base as it

becomes available.

MORE INFORMATION

This inconsistency may become apparent when an OLE application is calling

IOleLink::SetSourceDisplayName() to change the source of a link object. It

is possible that a new file moniker that is not a valid source name will be

registered on the running object table--for example, a moniker of "New 1"

for a new, as yet unsaved document. It will not be possible to use

SetSourceDisplayName() to link to this object, however, because "New 1" is

not a valid filename, and therefore it will be rejected by

SetSourceDisplayName().

Additional reference words: 2.01 3.10 3.50 4.00

KBCategory: kbole kbbuglist

KBSubcategory: LeTwoLnk


BUG: Object Packager GPFs w/ Paths Greater Than 64 Characters

PSS ID Number: Q109116

Authored 21-Dec-1993	Last modified 16-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

SYMPTOMS

Packaging an object that has a fully qualified path of more than 64 letters

results in a general protection (GP) fault in the Object Packager.

CAUSE

MS-DOS paths have a limit of 64 characters. The Object Packager does not

correctly handle scenarios that involve File Manager paths greater than

this limit.

STATUS

Microsoft has confirmed this to be a problem in the Windows 3.1 Object

Packager.

This problem does not occur with Object Packager 3.5 on Windows NT 3.5.

MORE INFORMATION

Steps to Reproduce

------------------

1. Create a directory structure in File Manager that results in a path

   greater than 64 characters. You must use File Manager because MS-DOS

   will not allow a directory structure this large to be created.

2. Use File Manager to copy a file into this new subdirectory. File Manager

   must be used because MS-DOS will not recognize this directory.

3. Select the file from within File Manager.

4. Choose Copy from the File menu.

5. Choose the Copy To Clipboard button to place the filename and path on

   the clipboard.

6. Launch CntOutl and Paste Link.

Additional reference words: 2.10 3.10 GPF GP-Fault buglist2.01

KBCategory: kbole kbbuglist

KBSubcategory: LeTwoApp


BUG: OLE 1.0 Server Launched for Paste Link

PSS ID Number: Q111578

Authored 14-Feb-1994	Last modified 17-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

SYMPTOMS

An OLE 1.0 server application copies an object to the clipboard, then

enters the blocked state. An OLE 2.0 container application then attempts to

paste a link to the object from the clipboard. The OLE 2.0 application is

frozen.

Next, the OLE 1.0 application is shut down. This unfreezes the OLE 2.0

container application, which proceeds to paste the link to the OLE 1.0

object. However, an instance of the OLE 1.0 server is launched. Normally,

the server is not run in a paste-link scenario.

STATUS

Microsoft has confirmed this to be a problem in the Microsoft products

listed at the beginning of this article. We are researching this problem

and will post new information here in the Microsoft Knowledge Base as it

becomes available.

Additional reference words: 3.10 3.50 4.00

KBCategory: kbole kbbuglist

KBSubcategory: LeTwoArc


BUG: OLE 2.0 Compatibility Layer Uses Document IDataObject

PSS ID Number: Q111585

Authored 14-Feb-1994	Last modified 17-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

SYMPTOMS

Whenever the OLE 1.0 client compatibility layer uses IDataObject, it uses

the OLE 2.0 server's document-level data object rather than the server's

pseudo-object data object.

STATUS

Microsoft has confirmed this to be a problem in the Microsoft products

listed at the beginning of this article. We are researching this problem

and will post new information here in the Microsoft Knowledge Base as it

becomes available.

MORE INFORMATION

One of the side-effects of this problem is that the following key is

required in the OLE 2.0 server application's CLSID listing in the

registration database

   GetSet

      |- X = 3, 1, 32, 1

where X is application-dependent. If this key is missing from the

registration database, then any attempt to embed the OLE 2.0 object into an

OLE 1.0 client will fail, even if the server application fully supports

IDataObject::EnumFormatEtc.

The GetSet key is used by server applications to describe the formats that

an object is capable of rendering, or having set. OLE looks at this key

when it needs to know which formats an object supports, without having to

run the object. This key is required in this situation because the OLE 1.0

compatibility layer is always going to refer to the registration database

to enumerate the formats supported by the server application. This

particular key represents the METAFILEPICT format, which must be supported

for OLE 1.0 compatibility.

Additional reference words: 2.01 3.50 4.00 toolkit

KBCategory: kbole kbbuglist

KBSubcategory: LeTwoPrs


BUG: OLE 2.0 Containers & 1.0 Objects that Close w/out Saving

PSS ID Number: Q109547

Authored 04-Jan-1994	Last modified 17-May-1995

The information in this article applies to:

 - Microsoft OLE version 1.0

 - Microsoft OLE Libraries for Windows and Win32s, versions 2.0 and 2.01

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

SYMPTOMS

When an OLE 1.0 object is inserted into an OLE 2.0 container document and

then closed without an update being invoked, the correct streams for that

object are not written to storage. Any subsequent attempt by the container

to load the object will fail.

CAUSE

When the OLE 1.0 object is closed without an update, the OLE 2.0 container

receives an IAdviseSink::OnClose() message without having first received an

IClientSite::SaveObject() message. Unless the container takes steps to work

around this problem, incorrect streams will be saved.

RESOLUTION

To protect against this scenario, OLE 2.0 containers that want data to be

available after an OLE 1.0 object closes without updating can implement

code similar to the following pseudocode:

   OleCreate();

   OleRun();

   IOleObject::Update();       \\ To get a snapshot of the data.

   OleSave();                  \\ To save the data to storage.

   IOleObject::DoVerb();

Alternatively, the container could just delete any objects that call

IAdviseSink::OnClose() without first calling IClientSite::SaveObject().

STATUS

Microsoft has confirmed this to be a problem in the products listed at the

beginning of this article. We are researching this problem and will post

new information here as it becomes available.

MORE INFORMATION

For more information about known idiosyncrasies of embedding or linking OLE

1.0 objects into OLE 2.0 containers, please see the "Compatibility with OLE

1.0" section of the OLE SDK Help file.

Additional reference words: 1.00 2.00 2.01 3.50 4.00 toolkit

KBCategory: kbole kbbuglist

KBSubcategory: LeTwoArc


BUG: OLE 2.0 Does Not Support CF_OWNERDISPLAY

PSS ID Number: Q109552

Authored 04-Jan-1994	Last modified 17-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

SYMPTOMS

If an application places a data transfer object onto the clipboard and that

data object enumerates CF_OWNERDISPLAY as one of the clipboard formats, the

application will not receive the WM_PAINTCLIPBOARD message.

CAUSE

The WM_PAINTCLIPBOARD message is sent to the clipboard owner in order to

paint the clipboard viewer window. After performing an OleSetClipboard,

clipboard ownership belongs to the OLE libraries. Because no window handle

information is passed with OleSetClipboard, the OLE libraries cannot

forward this message to the calling application.

STATUS

Microsoft has confirmed this to be a problem in the Microsoft products

listed at the beginning of this article. We are researching this problem

and will post new information here as it becomes available.

Additional reference words: 2.01 3.50 4.00

KBCategory: kbole kbbuglist

KBSubcategory: LeTwoDdc


BUG: OLE Type Emulation for Previously Loaded Objects

PSS ID Number: Q111608

Authored 14-Feb-1994	Last modified 25-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

SYMPTOMS

OLE type emulation is the process that allows the application user to

specify that all objects of some particular type are henceforth to be

activated as objects of some alternate, emulating type. When objects of the

original type are subsequently run, the server for the emulating type is

launched to serve them.

However, this emulation does not occur for objects of the original type

that were already in the loaded state when the type emulation occurred.

When such objects are subsequently run, they are run as the original type,

not the emulating type. The original server is launched, not the server for

the emulating type.

CAUSE

When an object is in the loaded state, its object handler is running. The

handler is, in general, particular to the original type for that object,

and therefore cannot emulate another object type.

STATUS

Microsoft has confirmed this to be a problem with the Microsoft products

listed at the beginning of this article. We are researching this problem

and will post new information here in the Microsoft Knowledge Base as it

becomes available.

MORE INFORMATION

If a container application has previously loaded instances of the original

type, it should reload each such object as the alternative, emulating type

the next time that object is run.

For more information on OLE type emulation, see "Emulating Different Object

Types" in the Object Linking and Embedding Software Development Kit (SDK)

version 2.01 "Programmer's Reference" help file.

Additional reference words: 2.01 3.50 4.00 95

KBCategory: kbole kbbuglist

KBSubcategory: LeTwoUim


BUG: OleConvertStorageToOLESTREAM() Fails When CLSID Is NULL

PSS ID Number: Q111611

Authored 14-Feb-1994	Last modified 17-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

SYMPTOMS

The OleConvertStorageToOLESTREAM() API (application programming interface)

call is used to convert the storage of an embedded object from the OLE 2.0

storage model to the OLE 1.0 storage model. However, if the OLE 2.0 object

has a CLSID of NULL, then OleConvertStorageToOLESTREAM() fails with a

return code of OLE_E_CLASS.

STATUS

Microsoft has confirmed this to be a problem in the Microsoft products

listed at the beginning of this article. We are researching this problem

and will post new information here in the Microsoft Knowledge Base as it

becomes available.

MORE INFORMATION

Note that it is unusual for an embedded object to have a CLSID of NULL.

However, after IOleLink::SetSourceDisplayName() has been called to change

the source of an embedded link object, it is possible for that link object

to have a CLSID of NULL.

Additional reference words: 2.01 3.50 4.00

KBCategory: kbole kbbuglist

KBSubcategory: LeTwoPst


BUG: OleCreate and IOleCache::Cache Fail with Multiple TYMEDs

PSS ID Number: Q109543

Authored 04-Jan-1994	Last modified 16-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

SYMPTOMS

The OLE 2.01 creation functions [OleCreate(), OleCreateFromData(), and so

forth] and IOleCache::Cache() fail if multiple values are specified for the

TYMED field of the FORMATETC parameter. The functions fail even if the

object server supports at least one of the TYMED values specified.

STATUS

Microsoft has confirmed this to be a problem in version 2.01 of the OLE

libraries. We are researching this problem and will post new information

here in the Microsoft Knowledge Base as it becomes available.

This is not a problem in 32-bit OLE.

Additional reference words: 2.01

KBCategory: kbole kbbuglist

KBSubcategory: LeTwoCom


BUG: OLERENDER_ASIS Results in Blank Embedded Object

PSS ID Number: Q110714

Authored 27-Jan-1994	Last modified 17-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

SYMPTOMS

If an OLE 1.0 client application contains an embedded object and copies the

object to the clipboard and an OLE 2.0 container application then performs

a paste operation by creating a new embedded object based on the clipboard

data by calling OleGetClipboard() and then calling OleCreateFromData(), the

resulting embedded object appears blank in the container's document if the

OLE 2.0 container specifies OLERENDER_ASIS as the renderOpt parameter to

OleCreateFromData().

CAUSE

The OLE 1.0 compatibility layer has placed the CF_EMBEDSOURCE format onto

the clipboard on behalf of the OLE 1.0 client application. This is

incorrect. When copying an embedded object to the clipboard, the

CF_EMBEDDEDOBJECT format should be supplied.

NOTE: The DOBJVIEW test application supplied with the OLE Software

Development Kit (SDK) version 2.01 can be used to determine which clipboard

formats are supplied by the clipboard data object.

RESOLUTION

An OLE 2.0 container application can avoid specifying OLERENDER_ASIS as the

renderOpt parameter to OleCreateFromData() when the clipboard data object

does not supply the CF_EMBEDDEDOBJECT format.

STATUS

Microsoft has confirmed this to be a problem in the products listed at the

beginning of this article. We are researching this problem and will post

new information here in the Microsoft Knowledge Base as it becomes

available.

Additional reference words: 2.01 3.50 4.00

KBCategory: kbole kbbuglist

KBSubcategory: LeTwoCdt


BUG: Paste Link Disabled Across the Network

PSS ID Number: Q108939

Authored 20-Dec-1993	Last modified 17-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

SYMPTOMS

The OleQueryLinkFromData application programming interface (API) function

returns failure when clipbook data from another machine is copied to the

local clipboard, even if the clipbook contains all of the data needed to

create a link.

CAUSE

cfLinkSource is not being rendered by the OLE libraries when data is being

transferred via NetDDE.

STATUS

Microsoft has confirmed this to be a problem in the Microsoft products

listed at the beginning of this article. We are researching this problem

and will post new information here as it becomes available.

Reference words: 2.01 3.50 4.00 Paste Link

KBCategory: kbole kbbuglist

KBSubcategory: LeTwoDdc


BUG: Paste-Linking a 256-Color Paintbrush Object

PSS ID Number: Q111612

Authored 14-Feb-1994	Last modified 16-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

 - Microsoft OLE Libraries for Windows NT, version 2.1

SYMPTOMS

A 256-color bitmap is loaded into Microsoft Paintbrush version 3.11

(included with Windows 3.11) and 3.50 (included with Windows NT 3.5). The

image is selected and then copied to the clipboard. An OLE 2.0 application

then pastes a link to the object from the clipboard. To perform the paste-

link operation, the container calls OleCreateLinkFromData(), specifying

OLERENDER_FORMAT as the rendering option and CF_DIB as the desired format.

The resulting link object in the OLE 2.0 application has an incorrect

appearance, such as being colored solid black.

STATUS

Microsoft has confirmed this to be a problem with the Object Linking and

Embedding libraries version 2.01. We are researching this problem and will

post new information here in the Microsoft Knowledge Base as it becomes

available.

MORE INFORMATION

Normally an OLE 2.0 application will specify OLERENDER_DRAW as the

rendering option. This allows OLE to cache a metafile presentation for the

object. When a metafile is cached, the 256-color Paintbrush object is

displayed correctly.

Additional reference words: 2.00 2.01 2.10 3.50

KBCategory: kbole kbbuglist

KBSubcategory: LeTwoApp


BUG: Printing Does Not Work from CL2TEST.EXE

PSS ID Number: Q112413

Authored 08-Mar-1994	Last modified 16-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

 - Microsoft Visual C++ 32-bit Edition, versions 2.0 and 2.1

 - Microsoft Win32 Software Development Kit (SDK), version 3.5

SYMPTOMS

Printing does not work correctly from CL2TEST.EXE or CL32TEST.EXE. Choosing

Print from the File menu results in a blank printout.

CAUSE

Printing has not been correctly implemented in the test container

application.

STATUS

Microsoft has confirmed this to be a problem in the CL2TEST test

application included with the Microsoft products listed at the beginning of

this article. We are researching this problem and will post new information

here in the Microsoft Knowledge Base as it becomes available.

Additional reference words: 2.00 2.01 2.10 3.50

KBCategory: kbole kbbuglist

KBSubcategory: LeTwoTls


BUG: Relative Monikers and OLE 1.0 Link Objects

PSS ID Number: Q111609

Authored 14-Feb-1994	Last modified 21-Apr-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

SYMPTOMS

When a link object from an OLE 2.0 application is copied to the clipboard

and then pasted into an OLE 1.0 application, the OLE 2.0 emulation layer

preserves the object's relative moniker. If the OLE 1.0 application

document is closed and then reopened by an OLE 2.0 version of the

application, OLE 2.0 will create a full moniker for the linked object by

appending the preserved relative moniker to the file moniker for the

document. This full moniker will be incorrect, because it will point to the

new document rather than to the first OLE 2.0 application's document that

contains the original linked object.

However, OLE 2.0 will still be able to bind to the linked object by

following the absolute moniker that is also stored with the object

(providing that the absolute location of the original linked object has not

changed). At the time of this binding, OLE will then correct the full

moniker for the object.

STATUS

Microsoft has confirmed this to be a problem with the Object Linking and

Embedding libraries version 2.01. We are researching this problem and will

post new information here in the Microsoft Knowledge Base as it becomes

available.

Additional reference words: 2.10 buglist2.01

KBCategory: kbole kbbuglist

KBSubcategory: LeTwoArc


BUG: Retaining Clipboard IDataObject Causes Unexpected Result

PSS ID Number: Q109545

Authored 04-Jan-1994	Last modified 17-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

SYMPTOMS

An application holding on to a clipboard IDataObject pointer, and making

repeated calls to IDataObject::EnumFormatEtc() through that pointer, may

find that the set of formats returned by EnumFormatEtc() changes between

calls.

RESOLUTION

As noted in the Object Linking and Embedding SDK version 2.01

documentation, an application that calls OleGetClipboard() to retrieve an

IDataObject interface pointer should hold on to that IDataObject pointer

only for a very short time.

STATUS

Microsoft has confirmed this to be a problem in the products listed at the

beginning of this article. We are researching this problem and will post

new information here in the Microsoft Knowledge Base as it becomes

available.

MORE INFORMATION

Steps to Reproduce

------------------

1. Copy an object from an OLE 1.0 server to the clipboard.

2. Call OleGetClipboard() to obtain an IDataObject pointer to the

   clipboard object.

3. Call IDataObject::EnumFormatEtc() to enumerate the available formats.

4. Without calling IDataObject::Release(), copy an object from an OLE 2.0

   server to the clipboard.

5. Call IDataObject::EnumFormatEtc() again. The formats enumerated have

   changed to the formats provided by the new OLE 2.0 object.

The OLE2UI library's implementation of the Paste Special dialog box

(provided in the Object Linking and Embedding SDK version 2.01) works

around this problem. The Paste Special dialog box is launched by calling

OleUIPasteSpecial(). If the user changes the contents of the clipboard

while this dialog is up, the OLE2UI code detects the change and responds by

ending the dialog box. When this happens, OleUIPasteSpecial() returns

OLEUI_PSERR_CLIPBOARDCHANGED.

The dialog box detects changes to the clipboard contents by calling

SetClipboardViewer() to splice itself into the clipboard viewer chain.

Additional reference words: 2.01 3.50 4.00 toolkit

KBCategory: kbole kbbuglist

KBSubcategory: LeTwoDdc


BUG: Set Line Height on ISvrOutl Object Causes GPF in Cl2Test

PSS ID Number: Q108930

Authored 20-Dec-1993	Last modified 17-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

SYMPTOMS

In certain circumstances, editing the Line Height of an ISvrOutl object

embedded within Cl2Test results in a general protection (GP) fault after

displaying the following message:

   GDI - An error has occurred in your application. If you choose Ignore,

   you should save your work in a new file. If you choose Close, your

   application will terminate.

STATUS

Microsoft has confirmed this to be a problem in the Microsoft products

listed at the beginning of this article. We are researching this problem

and will post new information here as it becomes available.

MORE INFORMATION

Steps to Reproduce

------------------

1. Launch ISvrOutl, create a line item.

2. Edit/Copy the line.

3. Launch CL2TEST.EXE.

4. Edit/Paste.

5. Edit/Outline/Open or double-click the object.

6. Within ISvrOutl, Line/Set Line Height.

7. Enter 1 in the height field, choose OK.

Additional reference words: 2.01 3.50 4.00 In Place Inplace sample gpf gp-

fault

KBCategory: kbole kbbuglist

KBSubcategory: LeTwoTls


BUG: SR2TEST Menu Items Enabled Incorrectly

PSS ID Number: Q109546

Authored 04-Jan-1994	Last modified 17-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

SYMPTOMS

During an in-place activation session, SR2TEST sometimes incorrectly

enables menu items on its Edit menu.

STATUS

Microsoft has confirmed this to be a problem in the Microsoft products

listed at the beginning of this article. We are researching this problem

and will post new information here as it becomes available.

MORE INFORMATION

Steps to Reproduce Problem

--------------------------

1. Start SR2TEST.

2. Start CL2TEST.

3. Create a new CL2TEST document.

4. Insert an SR2TEST object in-place into the CL2TEST document.

5. While the SR2TEST object is still in-place active within CL2TEST, choose

   Delete from the Edit menu to delete the shape.

At this point, the Cut, Copy, and Delete menu items on the Edit menu are

still enabled. This is incorrect because there is no shape remaining in the

SR2TEST object to cut, copy, or delete.

Additional reference words: 2.01 3.50 4.00 toolkit

KBCategory: kbole kbbuglist

KBSubcategory: LeTwoTls


BUG: SR2TEST Won't Close After Editing Link Object

PSS ID Number: Q108935

Authored 20-Dec-1993	Last modified 24-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

SYMPTOMS

After editing a linked SR2TEST object from CL2TEST, SR2TEST fails to shut

down after first displaying the following message box:

   Error Document not unlocked. Attempt Self-unlocking?

CAUSE

The BindToSource button from the Properties dialog box was chosen in

CL2TEST before running the object. CL2TEST is not properly releasing the

bind context, locking SR2TEST open.

STATUS

Microsoft has confirmed this to be a problem in the CL2TEST test

application shipped with the OLE Toolkit version 2.01. We are researching

this problem and will post new information here as it becomes available.

This is not a problem with CL32TEST included with the 32-bit OLE libraries.

Additional reference words: 2.01

KBCategory: kbole kbbuglist

KBSubcategory: LeTwoTls


BUG: Status Bar Not Redrawn With SR2TEST When In-Place

PSS ID Number: Q109541

Authored 04-Jan-1994	Last modified 24-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

SYMPTOMS

After inserting an SR2TEST object into the in-place version of the OUTLINE

sample application, the status bar will not be redrawn until the container

application's window is resized.

STATUS

Microsoft has confirmed this to be a problem in the SR2TEST sample

application included with the OLE SDK version 2.01. We are researching this

problem and will post new information here in the Microsoft Knowledge Base

as it becomes available.

This is not a problem with SR32TEST included with the 32-bit OLE libraries.

MORE INFORMATION

Steps to Reproduce

------------------

1. Run ICNTOUTL.EXE.

2. Choose Insert Object from Edit menu.

3. Choose OleTest SrTest 2.0 Shape from the list box.

4. Choose OK.

5. Resize the container window.

Additional reference words: 2.01 In Place Inplace

KBCategory: kbole kbbuglist

KBSubcategory: LeTwoTls


BUG: SVROUTL Link Not Displayed Correctly in CNTROUTL

PSS ID Number: Q110871

Authored 01-Feb-1994	Last modified 17-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

SYMPTOMS

Selecting the Paste Link menu item in the CNTROUTL sample application does

not correctly display the contents of the link if the source application is

the SVROUTL sample application.

This problem occurs only if the information created in SVROUTL is edited

further after the Edit Copy operation in SVROUTL, but before the Paste Link

operation in CNTROUTL. In this situation, the resulting link object is

displayed as originally copied to the clipboard, and does not reflect the

changes made after the copy operation.

STATUS

Microsoft has confirmed this to be a problem with the CNTROUTL and SVROUTL

samples included with the Microsoft products listed at the beginning of

this article. We are researching this problem and will post new information

here as it becomes available.

MORE INFORMATION

This problem occurs only when the SVROUTL link object is first pasted into

CNTROUTL. After the initial paste operation, any further modifications to

the information in SVROUTL are correctly reflected in the display of the

linked object in CNTROUTL.

Additional reference words: 2.01 3.50 4.00

KBCategory: kbole kbbuglist

KBSubcategory: LeTwoTls


BUG: Windows OLE DLLs Do Not Convert Mac OLESTREAM

PSS ID Number: Q112412

Authored 08-Mar-1994	Last modified 21-Apr-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

SYMPTOMS

The OLE 2.01 libraries will not convert a Mac OLESTREAM to a Windows

OLESTREAM. Similarly, the Windows OLE dynamic-link libraries (DLLs) will

not convert a Mac IStorage to a Windows OLESTREAM.

STATUS

Microsoft has confirmed this to be a problem in the OLE SDK version 2.01.

We are researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

MORE INFORMATION

The Macintosh OLE 2.0 libraries will be able to convert non-Macintosh

OLESTREAMs by means of OleConvertOLESTREAMToIStorage. At this time, there

are no known Macintosh OLE 1.0 applications that generate Windows-

compatible files that contain Mac OLESTREAMs.

Additional reference words: 2.01 buglist2.01

KBCategory: kbole kbbuglist

KBSubcategory: LeTwoArc


BUG:IOleObject::IsUpToDate Returns Wrong Value for Manual

PSS ID Number: Q111655

Authored 15-Feb-1994	Last modified 17-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

SYMPTOMS

To determine whether an OLE link needs to be updated, an OLE 2.0 container

application needs to call IOleObject::IsUpToDate. If this method returns

S_FALSE, the link needs to be updated; otherwise, the link can be

considered up to date. However, calling IOleObject::IsUpToDate on a manual

link while the link server is not running results in an a return value of

S_FALSE, even if the link is current. The result of this is that OLE 2.0

container applications may update links unnecessarily.

STATUS

Microsoft has confirmed this to be a problem in the Microsoft products

listed at the beginning of this article. We are researching this problem

and will post new information here in the Microsoft Knowledge Base as it

becomes available.

Additional reference words: 2.01 3.50 4.00

KBCategory: kbole kbbuglist

KBSubcategory: LeTwoLnk


CLEANDB.EXE Not Included in OLE 2.01 SDK

PSS ID Number: Q109431

Authored 04-Jan-1994	Last modified 21-Apr-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

The Registration Database Cleaner (CLEANDB.EXE), which shipped with the OLE

2.0 SDK, is no longer shipped in version 2.01 of the OLE SDK.

CLEANDB.EXE was used to remove keys from the registration database that

were added by pre-release versions of OLE 2.0 but not used in the final

version. Because these keys are obsolete, CLEANDB.EXE was removed from the

OLE SDK in version 2.01.

Additional reference words: 2.01

KBCategory: kbole kbprg

KBSubcategory: LeTwoTls


Containers Should Not Query for IOleInPlaceActiveObject

PSS ID Number: Q98678

Authored 11-May-1993	Last modified 17-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.0

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

OLE (object linking and embedding) version 2.0 container applications

should never call QueryInterface to get a pointer to the

IOleInPlaceActiveObject interface. Instead, the container should

AddRef() the pointer passed to IOleInPlaceUIWindow::SetActiveObject

and save it until needed.

Consider the scenario in which a nested object is currently inplace

active; that is, the container contains an object and this contained

object in turn holds another object that is inplace active. The

container has a pointer only to the "outer" object, and is not aware

of the "inner" object. Calling QueryInterface to get a pointer to

IOleInPlaceActiveObject is meaningless on the outer object because the

outer object is not currently inplace active. The only reliable way to

get a pointer to the correct IOleInPlaceActiveObject interface is

through IOleInPlaceUIWindow::SetActiveObject.

Objects capable of inplace activation should guard against this case,

and never return IOleInPlaceActiveObject from QueryInterface.

Additional reference words: 2.00 3.50 4.00

KBCategory: kbole kbprg

KBSubcategory: LeTwoInp


Corrections for Inside OLE 2 Sample Code

PSS ID Number: Q113255

Authored 29-Mar-1994	Last modified 20-Jun-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

 - Microsoft OLE Libraries, version 2.1, included with:

    - Microsoft Windows NT, version 3.5

SUMMARY

The sample code for the book "Inside OLE 2," by Kraig Brockschmidt

(Microsoft Press) was originally written to be compatible with OLE 2.0.

This code has been updated to be compatible with OLE 2.01, and also to fix

some problems in the original code. This article describes the changes that

were made in updating the code. The changes are described in detail in the

"More Information" section of this article below; below a quick list of the

problems that required changes:

 - Compiler Errors on IViewObject::Draw()

 - Compiler Errors on OleUIAddVerbMenu()

 - Compiler Errors on OleStdGetObjectDescriptorFromOleObject()

 - Compiler Errors on IDS_CLOSE

 - Linker Fails with CLASSLIB Sample

 - Compiler Errors Referencing GETICON.H

 - Incorrect Prototypes for LibMain() and WEP()

 - Patron GP Faults During Activate As

 - Patron's Convert To Fails

 - CLASSLIB String Allocations Fail with Some Compilers

 - CImpIPolyline::WriteToFile() Returns an Incorrect Value

 - CImpIOleObject::GetClientSite() Returns an Incorrect Value

 - Polyline Registers a Format with an Uninitialized String

 - DataTran Reference Counting Problem

 - Component Cosmo Fails to Release Polyline Object

 - Cosmo Fails to Load When Used with HCosmo Handler

 - Patron Does Not Work with Some Printer Drivers

 - ClassLib Creates Table of Invalid String Pointers

 - Errors in Enumerator Samples

 - Samples GP Fault When Closing Iconized Documents

Updated Sample Code Available

-----------------------------

The INOLE2 Software Library sample contains a complete source tree for

updated "Inside OLE 2" sample code. All of the changes described in this

article have already been made to the INOLE2 code.

The easiest way to update all of the "Inside OLE 2" samples is to get a

completely new source tree from INOLE2, and then rebuild the samples from

scratch under OLE 2.01. This article can then be used as a reference,

explaining what changes were made and why there were necessary.

INOLE2 can be downloaded as a self-extracting file from the Microsoft

Software Library (MSL) on the following services:

 - CompuServe

      GO MSL and download INOLE2.EXE

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download INOLE2.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \softlib\mslfiles directory

      Get INOLE2.EXE

NOTE: This archive contains subdirectories, be sure to use the -d command

line switch during extraction.

MORE INFORMATION

BOOKUI.DLL

----------

If the original source code to the Inside OLE 2 samples is updated

according to this article, and the samples are then rebuilt to be

compatible with OLE 2.01, it will also be necessary to rebuild an OLE 2.01

version of the OLE2UI library for the samples to use. To do so, build a

library called BOOKUI.DLL according to the instructions in the OLE 2.01

SDK.

Use this new DLL to replace the INOLE2\BUILD\BOOKUI.DLL file included with

the book.

If the samples are rebuilt from the INOLE2 Software Library sample, it is

not necessary to manually rebuild BOOKUI.DLL, because INOLE2 already

includes an updated version of BOOKUI.DLL.

1. Compiler Errors on IViewObject::Draw()

-----------------------------------------

Problem:

The prototype for IViewObject::Draw() changed between OLE 2.0 and OLE 2.01.

In 2.0 the lprcBounds and lprcWBounds parameters were prototyped as "const

LPRECTL"; in 2.01 they are prototyped as "LPCRECTL". This change causes

the HCosmo (Chapter 11) and Polyline (Chapters 11 and 16) sample

applications to fail during compilation under 2.01.

Solution:

To correct this error, update all references to IViewObject::Draw() in

the Inside OLE 2 sample code by changing const LPRECTL to LPCRECTL.

This change will be necessary in the following files:

   interfac\iviewobj.cpp

   interfac\iviewobj.h

   chap11\hcosmo\hcosmo.h

   chap11\hcosmo\iviewobj.cpp

   chap11\polyline\iviewobj.cpp

   chap11\polyline\polyline.h

   chap16\polyline\iviewobj.cpp

   chap16\polyline\polyline.h

2. Compiler Errors on OleUIAddVerbMenu()

----------------------------------------

Problem:

The prototype for OleUIAddVerbMenu() changed between OLE 2.0 and OLE 2.01.

The OLE2UI library version OLE 2.01 added an additional parameter to

OleUIAddVerbMenu(). This new parameter is an integer value called

"idVerbMax", and it indicates the largest number the container allows for a

verb menu item identifier. The idVerbMax parameter immediately follows the

idVerbMin parameter.

The Patron sample applications were written for the OLE 2.0 version of the

user interface library, which did not include this new parameter.

Consequently, these samples do not compile with the OLE 2.01 header files.

This difference affects the versions of Patron found in Chapters 9, 12, 13,

14, and 15.

Solution:

To correct this problem, perform the following two steps:

1. Build an OLE 2.01 version of BOOKUI.DLL, as described in problem 1

   above.

2. Update all calls to OleUIAddVerbMenu() in Patron by passing "ID_VERBMAX"

   (already defined in RESOURCE.H) as the idVerbMax parameter. For example,

   in the function CPage::FQueryObjectSelected(), change the following

      OleUIAddVerbMenu(NULL, NULL, hMenu, MENUPOS_OBJECT

          , IDM_VERBMIN, FALSE, 0, &hMenuTemp);

   to read as follows:

      OleUIAddVerbMenu(NULL, NULL, hMenu, MENUPOS_OBJECT

          , IDM_VERBMIN, IDM_VERBMAX, FALSE, 0, &hMenuTemp);

   This change will be necessary in the functions

   CPage::FQueryObjectSelected() and CTenant::AddVerbMenu() in each of the

   following files:

      chap09\patron\page.cpp

      chap09\patron\tenant.cpp

      chap12\patron\page.cpp

      chap12\patron\tenant.cpp

      chap13\patron\page.cpp

      chap13\patron\tenant.cpp

      chap14\patron\page.cpp

      chap14\patron\tenant.cpp

      chap15\patron\page.cpp

      chap15\patron\tenant.cpp

3. Compiler Errors on OleStdGetObjectDescriptorFromOleObject()

--------------------------------------------------------------

Problem:

The prototype for OleStdGetObjectDescriptorFromOleObject() changed between

OLE 2.0 and OLE 2.01. Version 2.01 of the OLE2UI library added an

additional parameter to OleStdGetObjectDescriptorFromOleObject(). This new

parameter, "lpSizelHim", is an LPSIZEL value and points to a structure that

indicates the dimensions of the object. The lpSizelHim parameter was added

to the end of the existing parameter list.

The Patron sample applications were written for the OLE 2.0 version of the

user interface library, which did not include this new parameter.

Consequently, these samples do not compile with the OLE 2.01 header files.

This difference affects the versions of Patron in Chapters 9, 12, 13, 14,

and 15.

Solution:

To correct this problem, perform the following two steps:

1. Build an OLE 2.01 version of BOOKUI.DLL, as described in problem 1

   above.

2a. To quickly solve the problem, update all calls to

    OleStdGetObjectDescriptorFromOleObject() in Patron by passing NULL as

    the lpSizelHim parameter.

2b. For a more complete solution to the problem, first declare a local

    variable:

       SIZEL   szl;

    Then replace the code:

       stm.hGlobal=OleStdGetObjectDescriptorDataFromOleObject

           (m_pIOleObject, NULL, m_fe.dwAspect, ptl);

    with the code:

       SETSIZEL(szl, (10*(m_rcl.right-m_rcl.left))

           , (10 * (m_rcl.bottom-m_rcl.top)));

       stm.hGlobal=OleStdGetObjectDescriptorDataFromOleObject

           (m_pIOleObject, NULL, m_fe.dwAspect, ptl, &szl);

    This code correctly computes the size of the object and then stores

    those extents into the object descriptor.

These changes will be necessary in the function

CTenant::CopyEmbeddedObject() in each of the following files:

   chap09\patron\tenant.cpp

   chap12\patron\tenant.cpp

   chap13\patron\tenant.cpp

   chap14\patron\tenant.cpp

   chap15\patron\tenant.cpp

These changes will also be necessary in the function

CTenant::CopyLinkedObject(), found in TENANT.CPP in Chapters 12, 13, 14,

and 15.

4. Compiler Errors on IDS_CLOSE

-------------------------------

Problem:

The OLE2UI.H header file shipped with OLE 2.01 defines a symbol IDS_CLOSE.

This symbol causes a conflict with a symbol of the same name defined in the

Cosmo samples.

This conflict affects the versions of Cosmo in Chapters 10, 13, 14, and 16.

The files affected are COSMO.RC and RESOURCE.H.

Solution:

To correct the problem, rename IDS_CLOSE in RESOURCE.H to IDS_CLOSE2, and

change the single occurrence of IDS_CLOSE in COSMO.RC to IDS_CLOSE2 in each

chapter. These changes are necessary in the following files:

   chap10\cosmo\cosmo.rc

   chap10\cosmo\resource.h

   chap13\cosmo\cosmo.rc

   chap13\cosmo\resource.h

   chap14\cosmo\cosmo.rc

   chap14\cosmo\resource.h

   chap16\cosmo\cosmo.rc

   chap16\cosmo\resource.h

5. Linker Fails with CLASSLIB Sample

------------------------------------

Problem:

There is an error in the FILES.LST file in the CLASSLIB directory of the

sample code. The first entry in this file, "cstrtable.obj", is a valid long

filename under Windows NT, but the file created during compilation is

actually "cstrtabl.obj" (no "e" on table). This causes no problems with a

16-bit compiler, because the extra "e" is ignored. However, it will

cause an error with a 32-bit compiler.

Solution:

To solve the problem, remove the "e", thus changing "cstrtable.obj"

to "cstrtabl.obj".

6. Compiler Errors Referencing GETICON.H

----------------------------------------

Problem:

In OLE 2.0, container applications must include the file GETICON.H, which

is supplied with the OLE Software

Development Kit (SDK) version 2.0. In OLE 2.01, applications no longer need

to include GETICON.H, because the information in that file has been moved

to other header files. Because it is no longer needed, GETICON.H is not

included with the OLE 2.01 SDK.

The Patron sample applications of Chapters 14 and 15 were written for OLE

2.0, so they include GETICON.H. Because this file is no longer available,

these versions of Patron fail to compile with the OLE 2.01 SDK.

Solution:

To correct the problem, comment out or delete the line "#include

<geticon.h>" in TENANT.CPP. This change is necessary in the following

files:

   chap14\patron\tenant.cpp

   chap15\patron\tenant.cpp

7. Incorrect Prototypes for LibMain() and WEP()

-----------------------------------------------

Problem:

The LibMain() and WEP() functions in all of the DLL samples are prototyped

incorrectly. These prototypes cause errors when using some compilers (for

example, Borland C++ 4.0); they do not cause problems with other compilers

(for example, Microsoft Visual C++ versions 1.0 and 1.5).

Solution:

The DLL samples in Inside OLE 2 implement the LibMain() and WEP() functions

as follows:

   HANDLE FAR PASCAL LibMain(HANDLE hInstance, WORD wDataSeg

       , WORD cbHeapSize, LPSTR lpCmdLine)

       {

       ...

       return hInstance;

       }

   void FAR PASCAL WEP(int bSystemExit)

       {

       return;

       }

To match the Windows SDK specifications, both of these functions should

return an int:

   int FAR PASCAL LibMain(HANDLE hInstance, WORD wDataSeg

       , WORD cbHeapSize, LPSTR lpCmdLine)

       {

       ...

       return (int)hInstance;

       }

   int FAR PASCAL WEP(int bSystemExit)

       {

       return 0;

       }

To solve this problem, make the changes above to all occurrences of

LibMain() and WEP() in the Inside OLE 2 sample code.

8. Patron GP Faults During Activate As

--------------------------------------

Summary:

The Patron sample applications from Chapters 14 and 15 support the OLE 2

Convert dialog box. Choosing Activate As from this dialog box sometimes

causes a GP fault.

Problem:

The problem lies in the way that the CTenant::Close() function uses the

fReopen flag. When Close() determines that there are no references to the

tenant IStorage, it normally resets the internal state of the tenant to

default values. As part of this process, it sets the member m_pIStorage to

NULL. However, if fReopen is TRUE, this assignment to NULL is skipped.

This can lead to situations where m_pIStorage is non-NULL but the storage

itself has been destroyed. Thus m_pIStorage is an invalid pointer, and

trying to call through it causes a GP fault.

To correct this problem, ensure that the m_pIStorage variable is set to

NULL any time its reference count is 0 (zero). This correction involves

removing a condition in the CTenant::Close() function, which is found in

the Patron source file TENANT.CPP.

Solution:

To correct this problem, edit the code to CTenant::Close() as follows:

Where you see the lines

   if (!fReopen)

       m_pIStorage=NULL;

remove the "if" statement, leaving:

   m_pIStorage=NULL;

The fReopen flag was used in an attempt to provide some optimization when

performing Activate As, but this flag is not necessary. The updated Inside

OLE 2 sample code referenced above has removed the flag entirely. This

affects the TENANT.CPP, TENANT.H, and PAGE.CPP source files of the PATRON

samples in Chapters 14 and 15.

9. Patron's Convert To Fails

Summary:

The Patron sample applications from Chapters 14 and 15 support the OLE 2

Convert dialog box. When Convert To is chosen from this dialog box, PATRON

fails to perform the conversion properly.

Problem:

The problem is that CPage::FConvertObject() releases the page's IStorage

pointer without committing it. Because Patron uses transacted storage, this

discards all changes, including the conversion that just happened.

The code in error (listed on Page 817 of Inside OLE 2) is as follows:

   if ((CF_SELECTCONVERTTO & ct.dwFlags)

       && !IsEqualCLSID(ct.clsid, ct.clsidNew))

       {

       LPSTORAGE   pIStorage;

       //This should be the only close necessary.

       m_pTenantCur->RectGet(&rcl, FALSE);

       m_pTenantCur->StorageGet(&pIStorage);

       m_pTenantCur->Close(FALSE, FALSE);

       hr=OleStdDoConvert(pIStorage, ct.clsidNew);

       pIStorage->Release();

This code does not commit the changes to the storage affected by

OleStdDoConvert before releasing pIStorage.

Solution:

To correct this problem, include a call to pIStorage->Commit() before

releasing the storage:

   if ((CF_SELECTCONVERTTO & ct.dwFlags)

       && !IsEqualCLSID(ct.clsid, ct.clsidNew))

       {

       LPSTORAGE   pIStorage;

       //This should be the only close necessary.

       m_pTenantCur->RectGet(&rcl, FALSE);

       m_pTenantCur->StorageGet(&pIStorage);

       m_pTenantCur->Close(FALSE, FALSE);

       hr=OleStdDoConvert(pIStorage, ct.clsidNew);

       pIStorage->Commit(STGC_ONLYIFCURRENT);

       pIStorage->Release();

   ...

10. CLASSLIB String Allocations Fail with Some Compilers

--------------------------------------------------------

Summary:

The Inside OLE 2 sample code includes a CLASSLIB library. Compiling the

CStringTable class from this library may cause string space allocation

failures with some compilers.

Problem:

The problem is an uninitialized local variable "cchUsed" in the function

CStringTable::FInit(). This routine is found in the CLASSLIB source file

SCSTRTABL.CPP.

Solution:

Initialize cchUsed to zero, for example, change the line

   UINT        cchUsed;

to read as follows:

   UINT        cchUsed=0;

11. CImpIPolyline::WriteToFile() Returns an Incorrect Value

-----------------------------------------------------------

Summary:

The Polyline sample DLL in Chapter 4 contains a function,

CImpIPolyline::WriteToFile(), which returns an incorrect value.

Problem:

If WriteToFile()'s write operation succeeds, it should return NOERROR.

Instead, it returns POLYLINE_E_WRITEFAILURE.

Solution:

In the code for the CImpIPolyline::WriteToFile() function, change the lines

that read

   return (m_pObj->m_fDirty) ?

       NOERROR : ResultFromScode(POLYLINE_E_WRITEFAILURE);

to read as follows:

   return (!m_pObj->m_fDirty) ?

       NOERROR : ResultFromScode(POLYLINE_E_WRITEFAILURE);

Make this change to the Chapter 4 version of Polyline.

CImpIPolyline::WriteToFile() is in the Polyline source file IPOLYLIN.CPP.

12. CImpIOleObject::GetClientSite() Returns an Incorrect Value

--------------------------------------------------------------

Summary:

The Cosmo sample applications in Chapters 10, 13, 14 and 16 contain a

function, CImpIOleObject::GetClientSite(), that returns an incorrect value.

Problem:

When GetClientSite() encounters no errors, it should return NOERROR.

Instead, it returns E_NOTIMPL.

Solution:

In the code for CImpIOleObject::GetClientSite(), change the line that reads

   return ResultFromScode(E_NOTIMPL);

to read as follows:

   return NOERROR;

Make this change to the versions of Cosmo in Chapters 10, 13, 14 and 16.

CImpIOleObject::GetClientSite() is in the Cosmo source file IOLEOBJ.CPP.

13. Polyline Registers a Format with an Uninitialized String

------------------------------------------------------------

Summary:

The Polyline sample DLLs in Chapters 5, 6, 11 and 16 attempt to register a

clipboard format using an uninitialized string. As a result, data formats

do not get properly transferred during clipboard, drag & drop, and compound

document operations.

Problem:

The offending line is:

   m_cf=RegisterClipboardFormat(PSZ(IDS_STORAGEFORMAT));

At constructor time, the stringtable referenced by the PSZ macro (this

macro tries to access the member CPolyine::m_pST) has not been initialized,

so m_cf is not set properly.

Solution:

To correct the error, the line of code listed above that initializes m_cf

must be moved into the function CPolyline::FInit(). Specifically, move the

line of code to occur after the code that initializes the stringtable:

   if (!m_pST->FInit(IDS_POLYLINEMIN, IDS_POLYLINEMAX))

       return FALSE;

   m_cf=RegisterClipboardFormat(PSZ(IDS_STORAGEFORMAT));

Make this one-line change to the versions of Polyline in Chapters 5, 11,

and 16. CPolyline::FInit() is in the Polyline source file POLYLINE.CPP.

Correcting this error in the Chapter 6 version of Polyline requires an

extra step. All lines initializing the FORMATETC arrays m_rgfeGet[0] and

m_rgfeSet[0] in which m_cf is stored must also be moved into

CPolyline::FInit(). The most convenient way to make this change is to

simply move all the FORMATETC initialization to the end of FInit(). Note

that Polyline does not use the FORMATETC arrays in Chapters 11 and 16, so

this extra step is not necessary in those chapters.

14. DataTran Reference Counting Problem

---------------------------------------

Summary:

The DataTran data transfer object in Chapter 7 has a reference-counting

problem in the function CImpIDataObj::GetData(). As a result, storage

elements in the STGMEDIUM returned by GetData() may become invalid while

they are still in use.

Problem:

GetData() incorrectly fails to call AddRef() on any IStorage or IStream

pointer contained in the STGMEDIUM it returns.

Solution:

To correct this error, add the following lines of code to GetData(),

immediately after the line "*pSTM = pRen->stm;":

   /*

    * Must remember to AddRef any other objects

    * in the STGMEDIUM:  storages and streams.

    */

   if (TYMED_ISTORAGE==pSTM->tymed)

       pSTM->pstg->AddRef();

   if (TYMED_ISTREAM==pSTM->tymed)

       pSTM->pstm->AddRef();

GetData() is in the DataTran source file IDATAOBJ.CPP.

15. Component Cosmo Fails to Release Polyline Object

----------------------------------------------------

Summary:

The Component Cosmo samples in Chapter 6, 7, 8, 11 and 16 fail to fully

clean up their allocations when closing a document. As a result, files may

not be saved completely and unused code is left in memory.

Problem:

In the function CCosmoDoc::~CCosmoDoc(), CoCosmo obtains an IDataObject

pointer on the Polyline object it maintains in the document. It then fails

to release this pointer, resulting in the problems listed above.

Solution:

In the code for CCosmoDoc::~CCosmoDoc(), add a call to

IDataObject::Release().

Change the lines

   if (SUCCEEDED(hr))

       pIDataObject->DUnadvise(m_dwConn);

to read as follows:

   if (SUCCEEDED(hr))

       {

       pIDataObject->DUnadvise(m_dwConn);

       pIDataObject->Release();

       }

CCosmoDoc::~CCosmoDoc() is in the CoCosmo source file DOCUMENT.CPP.

16. Cosmo Fails to Load When Used with HCosmo Handler

-----------------------------------------------------

Summary:

The Cosmo sample applications in Chapter 10, 13, 14, or 16, when they are

being used in conjunction with the custom object handler HCosmo from

Chapter 11, fail to load and activate a Cosmo object. This problem occurs

when a container application is reloading a Cosmo object from a saved file,

and also when a container application is reactivating a Cosmo object after

the object has been first created and then deactivated.

Problem:

The problem actually lies in HCosmo. HCosmo incorrectly keeps the object

stream open in the object's IStorage. It does this so that it can perform

low-memory saves without having to reopen the stream.

However, when a process has a stream open and that stream has a particular

IStorage as its parent, the OLE 2 implementation of STORAGE.DLL does not

allow the process to open the stream a second time from the same parent

IStorage. Therefore, when the Cosmo application receives the IStorage

pointer from HCosmo, and attempts to open the same object stream that

HCosmo already has open, the attempt to open the stream fails.

This problem shows up in HCosmo's implementation of IOleObject::DoVerb().

HCosmo delegates the DoVerb() call to the default handler, and the default

handler attempts to launch Cosmo. As described above, Cosmo cannot open the

object stream, so it returns an error of STG_E_READFAULT to the default

handler, which in turn returns STG_E_READFAULT to HCosmo.

As noted above, HCosmo keeps the object stream open so that it can perform

low-memory saves without having to reopen the stream. However, this is not

necessary. Because HCosmo never makes changes to the object, it never has

to save anything in a low-memory situation. Specifically, it never has to

save any changes to the storage when its IPersistStorage::Save() is called

with the fSameAsLoad flag set to TRUE. Because this is the only case where

an IPersistStorage implementation should not attempt to allocate memory, it

is totally unnecessary for HCosmo to cache any pointers to the stream.

Solution:

To correct the problem, make the following five changes to HCosmo's

IPersistStorage implementation (HCosmo's implementation of IPersistStorage

is in the source file IPERSTOR.CPP):

1. In CImpIPersistStorage::InitNew(), add the lines below immediately

   before the call to WriteClassStg():

      m_pObj->m_pIStream->Release();

      m_pObj->m_pIStream=NULL;

2. In CImpIPersistStorage::Load(), replace the line

      m_pObj->m_pIStream=pIStream;

   with the following:

      pIStream->Release();

      m_pObj->m_pIStream=NULL;

3. In CImpIPersistStorage::Save(), remove all the code inside the "if

   (fSameAsLoad)" condition (it is unnecessary).

4. In CImpIPersistStorage::SaveCompleted(), remove the lines of code below

   that occur inside the "if (NULL!=pIStorage)" condition:

      hr=pIStorage->OpenStream("CONTENTS", 0, STGM_DIRECT

          | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0

          , &pIStream);

      if (FAILED(hr))

          return hr;

      if (NULL!=m_pObj->m_pIStream)

          m_pObj->m_pIStream->Release();

      m_pObj->m_pIStream=pIStream;

5. In CImpIPersistStorage::HandsOffStorage(), remove the condition and body

   of code below:

      if (NULL!=m_pObj->m_pIStream)

          {

          m_pObj->m_pIStream->Release();

          m_pObj->m_pIStream=NULL;

          }

The m_pIStream member of CFigure can then be eliminated entirely, because

it is no longer used in this IPersistStorage implementation.

17. Patron Does Not Work with Some Printer Drivers

--------------------------------------------------

Summary:

The Patron sample applications do not work correctly with certain printer

drivers, including the standard PostScript driver.

One symptom of failure is getting a blank document window when creating a

new Patron document; that is, no page image appears. Another symptom is

getting a GP fault in the printer driver when attempting to execute

the Printer Setup command from Patron's File menu.

Problem:

The problem is caused by the fact that Patron is not sensitive to the

variable length of the DEVMODE structure returned by the printer driver.

Patron normally obtains the DEVMODE data by calling the Windows PrintDlg()

API; it then copies that data to a private stream in its Compound File.

However, Patron only copies sizeof(DEVMODE) bytes, and therefore loses any

additional driver-specific information that might exist at the end of the

DEVMODE structure.

Some printer drivers, such as the Hewlett-Packard (HP) LaserJet PCL

drivers, use no extra information. Patron works correctly with these

drivers. Other drivers, such as the standard PostScript driver, use extra

information; with these drivers, Patron fails.

Solution:

To correct this problem, change the implementation of Patron's CPages class

so that it works with variable length DEVMODE structures, and therefore

with all printer drivers.

The changes are too extensive to list in this article; as noted at the top

of this article, an updated version of the Inside OLE 2 sample code source

tree is available on the Software Library. The following is a brief

overview of the code that needs to be changed to correct this problem:

The CPages class is defined in the header file PAGES.H, and implemented in

PAGES.CPP. The functions that need to be updated are:

 - CPages::DevmodeSet() and CPages::DevModeGet() in all chapters

 - CPages::ConfigureForDevice() in Chapters 2 and 5

 - CPages::DevReadConfig() in all chapters other than 2 and 5

After these changes have been made, the new Patron will be unable to read

files generated by previous versions of Patron. There is no automatic

conversion facility provided in these samples. To convert a file from the

old Patron format to the new Patron format, follow these steps:

1. Run an old version of Patron from Chapter 14.

2. Run a new version of Patron from Chapter 15 (or, run the old Chapter 15

   Patron and the new Chapter 14 Patron).

3. Load the old file into the old Patron.

4. Transfer all objects from the old Patron to the new Patron, using the

   clipboard or drag-and-drop method.

5. Save the new document in the new Patron.

18. ClassLib Creates Table of Invalid String Pointers

-----------------------------------------------------

Summary:

The ClassLib sample framework implements a string table class called

CStringTable. In certain situations the implementation of this class can

create a table of invalid string pointers.

Problem:

The function CStringTable::FInit() allocates a block of memory and loads

strings from the application's resources into that memory. It then

initializes a table of far pointers into that memory, one pointer for each

string.

FInit() then reallocates the memory block, in order to free up any unused

space. This reallocation could move the memory block. Because the far

pointers in the pointer array point into the block that has moved, they all

become invalid.

Solution:

To avoid this problem, delete the following lines in the

CStringTable::FInit() function:

   //Now reallocate the string memory to however much we used, plus 1

   psz=(LPSTR)_frealloc(m_pszStrings, cchUsed+1);

   if (NULL!=psz)

       m_pszStrings=psz;

This solution wastes a little memory, but is simpler than trying to

recompute all the string pointers; ClassLib is intended to be a simple

example.

CStringTable::FInit() is in ClassLib's CSTRABL.CPP file.

19. Errors in Enumerator Samples

--------------------------------

Summary:

The enumerator samples in "Inside OLE 2" contain two errors. This section

describes the errors and the changes necessary to fix them. The changes are

detailed for the IEnumRect enumerator found in Chapter 3; similar changes

are required in all enumerators in the book's sample code.

Problem 1:

If the first parameter to an enumerator's Next() function (called "celt" in

the OLE 2 documentation, "cRects" in the sample) is 1, it is permissible

for the last parameter (called "pceltFetched" in the documentation,

"pdwRects" in the sample) to be NULL. IEnumRect::Next() simply returns

FALSE in this case, which is incorrect.

Solution 1:

To correct this error, change the lines of code in IEnumRect::New() that

read

   if (NULL==pdwRects)

       return FALSE;

   *pdwRects=0L;

to read as follows:

   if (NULL==pdwRects)

       {

       if (1L!=cRect)

           return FALSE;

       }

   else

       *pdwRects=0L;

Problem 2:

IEnumRect::Next() stores an incorrect value into the out parameter

pdwRects.

Solution 2:

To correct this error, change the line of code in IEnumRect::New() that

reads

   *pdwRects=(cRectReturn-cRect);

to read as follows:

   if (NULL!=pdwRects)

       *pdwRects=cRectReturn;

The same changes should be made to the IENUM.CPP files in the following

"Inside OLE 2" sample code directories:

   interface

   chap03\enumc

   chap03\enumcpp

   chap06\polyline

   chap06\ddataobj

   chap06\edataobj

   chap07\datatran

20. Samples GP Fault When Closing Iconized Documents

----------------------------------------------------

Summary:

The sample applications may cause a GP fault when closing one or more

iconized documents.

Problem:

The CClient::QueryCloseAllDocuments() function (found in the ClassLib

source file CCLIENT.CPP) can cause this GP fault through incorrect use of

its local variable hPrevClose.

Solution:

To correct this problem, change the code to

CClient::QueryCloseAllDocuments() by adding the two lines below that read

"hPrevClose=NULL":

BOOL CClient::QueryCloseAllDocuments(BOOL fClose)

    {

    ...

    for ( ; hWndT; hWndT=GetWindow(hWndT, GW_HWNDNEXT))

        {

        if (NULL!=hPrevClose)

            {

            pDoc=(LPCDocument)SendMessage(hPrevClose

                , DOCM_PDOCUMENT, 0, 0L);

            CloseDocument(pDoc);

            hPrevClose=NULL;            // ADD THIS LINE

            }

    ...

    //Close the last window as necessary.

    if (fClose && NULL!=hPrevClose)

        {

        pDoc=(LPCDocument)SendMessage(hPrevClose, DOCM_PDOCUMENT, 0, 0L);

        CloseDocument(pDoc);

        hPrevClose=NULL;                // ADD THIS LINE

        }

    ...

Additional reference words: 2.01 gpf gp-fault

KBCategory: kbole kbfile

KBSubcategory: LeTwoOth


Determining If an Object Is Capable of Visual Editing

PSS ID Number: Q99045

Authored 20-May-1993	Last modified 17-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, versions 2.0 and 2.01

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

SUMMARY

It is impossible for a container to consistently determine whether an

object will attempt negotiation for visual editing. However, by

determining whether the object supports the IOleInPlaceObject

interface, the container may want to assume that the negotiation will

occur.

The default object handler will always fail a call to QueryInterface

for IOleInPlaceObject if the object is in the loaded state. The

container must first run the object and then query for the

IOleInPlaceObject interface. If this QueryInterface call succeeds,

then the container can assume that the object supports visual editing,

and may start negotiation on the execution of a verb.

MORE INFORMATION

The following C++ code returns TRUE if an object may start visual

negotiation when IOleObject::DoVerb is called:

BOOL fCanInPlaceActivate(LPOLEOBJECT lpObject)

{

LPOLEINPLACEOBJECT lpInPlaceObject;

BOOL retval;

    // Run the object.

    OleRun(lpObject);

    // Query for IOleInPlaceObject.

    HRESULT herr = lpObject->QueryInterface(IID_IOleInPlaceObject,

                                            (LPVOID FAR *)

                                            lpInPlaceObject);

    // Check the return value.

    if (herr == NOERROR)

        {

        retval = TRUE;

        lpInPlaceObject->Release();

        }

    else

        retval = FALSE;

    lpObject::Close(OLECLOSE_NOSAVE);

    return retval;

}

Additional reference words: 2.00 3.50 4.00

KBCategory: kbole kbprg kbcode

KBSubcategory: LeTwoInp


DOCERR: DISPCALC and OP_MULTIPLY

PSS ID Number: Q114972

Authored 18-May-1994	Last modified 16-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

SUMMARY

In the "OLE 2.0 Programmer's Reference," volume 2, page 12,

please change the following line:

      Calculator.Op  OP_MULTIPLY

to read as follows:

      Calculator.Op = 3 ' OP_MULTIPLY

MORE INFORMATION

In order to set the Op method to multiply, you have to use the

equal sign("=") to set the Op member equal to 3.

For easier reading, you should add the following line after the "DIM

Calculator As Object" line:

      Const OP_MULTIPLY = 3

This allows you to use the OP_MULTIPLY value instead of the hard-coded

value of 3.

This code snippet has been corrected in the Online documentation provided

with Visual C++ 2.x and the Win32 SDK.

Additional reference words: 2.01

KBCategory: kbole kbdocerr

KBSubCategory: LeTwoOth


DOCERR: F1 Help for Menu Items in an OLE 2.0 Container

PSS ID Number: Q118897

Authored 01-Aug-1994	Last modified 17-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

SUMMARY

The "OLE 2.0 Programmer's Reference," volume 1, describes on pages 727

through 731 how an application that you would like to be a container for

inplace edited objects can support F1 Help for menu items. This information

is also contained in the OLE Technical Note CSHELP.DOC.

The application may have its own keyboard message filter added so that it

can intercept the F1 key, or it may ask the OLE default object handler to

add a message filter. A sample keyboard message filter is provided for

applications that you would like to implement their own message filters.

However, the sample message filter does not handle the case properly when

an object is inplace activated.

This article contains a sample message filter that properly handles the

inplace activated case.

MORE INFORMATION

If the sample message filter is used, when an object is inplace activated

and the application attempts to provide F1 Help for one of the server's

menu items, the server processes the menu command instead of providing

Help. F1 Help works properly for menu items handled by the container.

In the sample filter, if an object is inplace activated and the F1 key is

pressed, the message filter sends the registered message OM_POST_WM_COMMAND

to the frame window. The frame window handles OM_POST_WM_COMMAND by posting

a WM_COMMAND message to the container or the server as appropriate. After

the OM_POST_WM_COMMAND message is sent (and thus after the WM_COMMAND

message is posted), the filter calls IOleWindow::ContextSensitiveHelp(TRUE)

for both the frame window and the inplace activated object, to enter

context-sensitive Help mode. OLE's LRPC call to ContextSensitiveHelp() for

the inplace activated object gives the server application the opportunity

to check its message queue, and the WM_COMMAND message gets processed

before the ContextSensitiveHelp() method is executed in the server. Because

the inplace activated object does not know that it should be in context-

sensitive Help mode, it processes the WM_COMMAND message as normal.

To correctly provide F1 Help for all menu items, the container may use the

standard OLE 2.0 implementation of F1 menu processing. To use the standard

OLE 2.0 implementation of F1 menu processing, pass non-NULL pointers to the

"lpFrame" and "lpActiveObj" parameters of OleSetMenuDescriptor().

Alternatively, the container may use the revised filter (listed below). In

the revised filter, the calls to IOleWindow::ContextSensitiveHelp() are

made before OM_POST_WM_COMMAND is sent to the frame window. This ensures

that the server enters context-sensitive Help mode before the WM_COMMAND

message is posted. One side effect is that if the F1 key is pressed while

the current selection is a popup menu, the message filter will need to exit

context-sensitive Help mode by calling

IOleWindow::ContextSensitiveHelp(FALSE) for both the frame window and the

inplace activated object.

Sample Code

-----------

/* Compile options needed:    (or  ; Assemble options needed:  )

*/

MessageFilterProc(int nCode, WPARAM wParam, LPARAM lParam)

{

   LPMSG lpMsg = (LPMSG) lParam;

   // If it is not the F1 key then let the message

   // (without modification) go to the next proc

   // in the message filter chain.

   if (lpMsg  &&  lpMsg->message == WM_KEYDOWN  &&

       lpMsg->wParam == VK_F1) {

      HMENU   hmenuPopUp;

      // Container app can not know what the current menu

      // selection is if an object is getting inplace

      // edited in it, because the menu bar is shared and

      // the menu messages are  intercepted and dispatched

      // to the appropriate process by OLE's frame

      // window sub-classing (see Box 3). So, when the

      // container sends the OM_POST_WM_COMMAND,

      //

      //    if (an object is getting inplace edited)

      //       it will go to Box 3, and OLE posts WM_COMMAND

      //          to the right process.

      //    else

      //       it will go to Box 4, which is app's own

      //          frame wnd proc, and its OM_POST_WM_COMMAND

      //          code can post the WM_COMMAND for the

      //          current selection (that the app maintains).

      //

      // With this scheme the same message filter proc can

      // be used whether the object is getting inplace

      // edited or not.

      // NOTE 1: If the current selection is a popup menu,

      // then WM_COMMAND can not be generated, so the code

      // for OM_POST_WM_COMMAND returns handle of the popup

      // menu, otherwise it returns NULL

      // NOTE 2: Do uOmPostWmCommand =

      //           RegisterWindowMessage("OM_POST_WM_COMMND")

      // at startup.

      // call the frame and active inplace object's

      // ContextSensitiveHelp() methods.

      lpFrame->ContextSensitiveHelp(TRUE);

      lpInPlaceActiveObj->ContextSensitiveHelp(TRUE);

      // when either of these 2 objects receive the WM_COMMAND

      // they will call the other one's ContextSensitiveHelp()

      // method. Note that the tree walk will not happen if the

      // CSH mode has been entered because of  F1 on selected menu.

      if (hmenuPopup = (HMENU)SendMessage(hwndFrame,

                                          uOmPostWmCommand,

                                          0, 0L)) {

         // Now the apps have 4 options:

         // 1. Give Help for the popup menu and cancel the

         //    menu mode as well as the CSH mode (WORD does

         //    this).

         // 2. Change the cursor to question mark cursor

         //    (== SHIFT+F1), and do not disturb the menu

         //    state, and enter the CSH mode. (EXCEL does

         //    this)

         // 3. Remove the CSH mode and cancel the menu mode.

         // 4. Leave the menu state as it is and ignore the

         //    F1 key (ie. don't pass the F1 key down the

         //    msg filter chain).

         //

         // We (OLE) recommend option 4, and if the container

         // app wants us to install the message filter, then

         // this is what we will do. In this sample code also

         // we are going for option 4.

         lpFrame->ContextSensitiveHelp(FALSE);

         lpInPlaceActiveObj->ContextSensitiveHelp(FALSE);

         return TRUE; // let the system know that we have

                      // handled the message

      }

      // Change message value to be WM_CANCELMODE and then call

      // the next proc in the message filter chain. When windows

      // USER's menu processing code sees this message it will

      // bring down menu state and come out of its menu processing

      // loop.

      lpMsg->message = WM_CANCELMODE;

      lpMsg->wParam  = NULL;

      lpMsg->lParam  = NULL;

   }

   return CallNextHookEx (hMsgHook, nCode, wParam, lParam);

}

Additional reference words: 2.01 3.50 4.00 Containers docerr

KBCategory: kbole kbdocerr

KBSubCategory: LeTwoCli


DOCERR: OleGetClipboard Not Needed Before OleSetClipboard

PSS ID Number: Q104961

Authored 04-Oct-1993	Last modified 16-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.0

The function descriptions for OleSetClipboard and OleGetClipboard in

the OLE version 2.0 "Programmer's Reference: Creating Programmable

Applications" manual incorrectly state that an application must obtain

access to the clipboard by successfully calling OleGetClipboard before

making a call to OleSetClipboard. In fact, a call to OleGetClipboard

is not required before making a call to OleSetClipboard.

This documentation error also appears in the OLE version 2.0 online

reference file, OLE2API.HLP, in the function descriptions for

OleSetClipboard and OleGetClipboard.

The correct information is in the OLE 2.0 documentation included with

Visual C++ 2.0.

Additional reference words: 2.00

KBCategory: kbole kbdocerr

KBSubcategory: LeTwoDdc


DOCERR: Text Corrections for Inside OLE 2

PSS ID Number: Q113188

Authored 29-Mar-1994	Last modified 21-Apr-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

SUMMARY

This article contains a list of errors in the text of the book "Inside OLE

2," by Kraig Brockschmidt (Microsoft Press).

Many of the errors listed below also affect the book's sample code; the

descriptions for those errors include references to another Knowledge Base

article, which describes the problems (and their solutions) in more detail.

For additional information on these problems and their solutions, please

see the following article(s) in the Microsoft Knowledge Base:

ARTICLE-ID: Q113255

TITLE     : SAMPLE: Corrections for Inside OLE 2 Sample Code

The sample code for "Inside OLE 2" was originally written to be compatible

with OLE 2.0. This code has been updated to be compatible with OLE 2.01,

and also to fix some problems in the original code. The entire source tree

for the updated sample code is included in the INOLE2 Software Library

sample. INOLE2 can be found in the Microsoft Software Library by searching

on the word INOLE2.

MORE INFORMATION

List of Text Errors

-------------------

Page 71:   The second line of the last paragraph should read "with all the

           functions in the preceding table...". The book has "tale"

           instead of "table".

Pages 82-  The exact implementations of CImpIEnumRECT::Next on these pages

83, 92-    are incorrect--for more information, see the section "Errors in

93:        Enumerator Samples" in the Knowledge Base article "SAMPLE:

           Corrections for Inside OLE 2 Sample Code."

           Also, on page 83 there should be no space between "book" and

           "1632" in the text "#include <book 1632.h>".

Page 105:  The second use of QueryInterface in the Transitive property

           should read "pInterface2->QueryInterface(IInterface3)". The

           book has IInterface2 as the parameter to QueryInterface,

           which is incorrect.

Page 157:  A space is missing between "LPLPVOID" and "ppv" in the

           last parameter of the declaration CKoala::QueryInterface.

Page 161:  The prototype for WEP should return an int, not VOID.

Page 197:  The line of code under "if (IsEqual(riid, IID_IAnimal))"

           should read "*ppv=(LPVOID)m_pAnimal". In the text the

           underscore is mistakenly a space, dash, and space.

Page 199:  A space is missing between "LPLPVOID" and "ppv" in the

           last parameter of the declaration CKoala::QueryInterface.

Page 243:  The second sentence in the second paragraph should read:

           "The Structured Storage definition of IStream allows streams

           to contain up to 2^64 (2 raised to the 64th power)

           addressable bytes of data."

            The text incorrectly reads "264" instead of "2^64."

Pages 257- The code listings for CPages::DevModeSet, CPages::DevModeGet,

259:       and CPages::ConfigureForDevice should be changed to correct a

           problem with certain printer drivers in Patron. For more

           information on this problem, see the section "Patron Does Not

           Work with Some Printer Drivers" in the Knowledge Base article

           "SAMPLE: Corrections for Inside OLE 2 Sample Code."

Pages 289- Both LibMain and WEP functions should return an int.

290:       For more information, see the section "Incorrect Prototypes for

           LibMain() and WEP()" in the Knowledge Base article "SAMPLE:

           Corrections for Inside OLE 2 Sample Code."

Page 316:  The implementation of CImpIEnumFormatEtc::Next is incorrect.

           For more information on this problem, see the section "Errors in

           Enumerator Samples" in the Knowledge Base article "SAMPLE:

           Corrections for Inside OLE 2 Sample Code."

Page 331:  The description of IDataObject::GetCanonicalFormatEtc

           is incorrect. For correct details, see the Microsoft Object

           Linking and Embedding version 2.0 "Programmer's Reference."

Page 365:  The "const LPRECTL" parameter to IViewObject::Draw

           should be of type "LPCRECTL" to match OLE 2.01. The book

           is correct for OLE 2.0. For more information, see the section

           "Compiler Errors on IViewObject::Draw()" in the Knowledge

           Base article "SAMPLE: Corrections for Inside OLE 2 Sample Code."

Page 368:  The call to pIViewObject->Draw about should read:

           "pIViewObject->Draw(dwAspect, -1, NULL, NULL, 0, hdcDraw,

           lprcBounds, NULL, NULL, 0);". In the book, the dwAspect and

           hDC parameters are incorrect.

Page 399:  When CImpIDataObject::GetData calls AddRef() before returning,

           it should also call AddRef on any IStorage or IStream pointer

           inside the STGMEDIUM, if that is the medium in use. For more

           information, see the section "Datatran Reference Counting

           Problem" in the Knowledge Base article "SAMPLE: Corrections

           for Inside OLE 2 Sample Code."

Page 437:  The word "consumer" in the caption of Figure 8-6 should be

           "target."

Pages 544- In OLE 2.01 there is a new, additional parameter to

546:       OleUIAddVerbMenu called "idVerbMax", which comes immediately

           after "idVerbMin." This parameter was not present in OLE 2.0.

           For information on how this change affects the sample code, see

           the section "Compiler Errors on OleUIAddVerbMenu" in

           the Knowledge Base article "SAMPLE: Corrections for Inside

           OLE 2 Sample Code."

Page 554:  Under OLE 2.01 the OleStdGetObjectDescriptorFromOleObject

           function (used in the Patron sample application) requires an

           additional LPSIZEL as the last parameter. For more information

           on how this change affects the sample code, see the section

           "Compiler Errors on OleStdGetObjectDescriptorFromOleObject()"

           in the Knowledge Base article "SAMPLE: Corrections for Inside

           OLE 2 Sample Code."

Pages 614- No ellipsis ("...") is necessary to separate functions in

622:       Listing 10-5. There is no code omitted from the listing in these

           places.

Page 630:  The right curly brace just above the "else" at the bottom

           of the page should be indented to align with the call

           to ModifyMenu above it.

Pages 663- The bottom of page 663 mentions how a handler should hold

665:       onto open streams for low-memory save situations. This is

           important ONLY for elements that are entirely manipulated

           by the handler and never touched by the server. The handler

           should not cache or hold pointers to the same elements the

           server must access. For more information on this problem, see

           the section "Component Cosmo Fails to Release Polyline Object"

           in the Knowledge Base article "SAMPLE: Corrections for Inside

           OLE 2 Sample Code."

           If a handler manipulates and changes data unaffected by

           the server, it must fulfill the IPersistStorage contract for

           only those formats. The server is responsible for all

           others that it modifies.

Page 668:  The "const LPRECTL" parameter to IViewObject::Draw

           should be of type "LPCRECTL" to match OLE 2.01. The book

           is correct for OLE 2.0. For more information on how this change

           affects the sample code, see the section "Compiler Errors on

           IViewObject::Draw()" of the Knowledge Base article "SAMPLE:

           Corrections for Inside OLE 2 Sample Code."

Page 687:  There should not be "//" before the large bold "IOLEOBJ.CPP"

           in this code listing. The label is not part of the code.

Page 788:  Same problem with OleStdGetObjectDescriptorFromOleObject

           as described above for page 554.

Page 814:  Same problem with OleUIAddVerbMenu as described above for

           pages 544-546.

Page 817:  Remove the second parameter to pTenantCur->Close. It should

           read "pTenantCur->Close(FALSE);". For more information on this

           problem, see the section "Patron GP Faults During Activate As"

           in the Knowledge Base article "SAMPLE: Corrections for Inside

           OLE 2 Sample Code."

Page 817:  There should be a call to pIStorage->Commit(STGC_ONLYIFCURRENT)

           immediately after the call to OleStdDoConvert and before

           the call to pIStorage->Release. For more information, see

           the section "Patron Convert To Fails" of the Knowledge Base

           article "SAMPLE: Corrections for Inside OLE 2 Sample Code."

Page 819:  Remove the second parameter to pTenantCur->Close. It should

           read "pTenantCur->Close(FALSE);". This matches the change

           necessary for a bug resolution described in the section "Patron

           GP Faults During Activate As" in the Knowledge Base article

           "SAMPLE: Corrections for Inside OLE 2 Sample Code."

Page 846:  The parenthetical entry in the fourth line of the last

           paragraph should read "(linked objects are NOT allowed...)".

           The book reads "now" instead of "not".

Page 861:  The second sentence of the third paragraph under "Active

           vs. UI Active and Inside-Out Objects" should read:

           "The answer...as they are visible-end users DO NOT have to

           double-click..."

           The DO NOT is important.

NOTE: Versions of "Inside OLE 2" printed after March 1994 (third printing

or later) have been corrected.

Additional reference words: 2.01 mspress docerr

KBCategory: kbole kbdocerr

KBSubcategory: LeTwoOth


FIX: SR2TEST GP Faults During Object Shutdown

PSS ID Number: Q104141

Authored 08-Sep-1993	Last modified 16-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.0

SYMPTOMS

A general protection (GP) fault occurs when calling IOleObject::Close()

on an SR2TEST object.

CAUSE

SR2TEST does not properly handle the case in which IOleObject::Close()

is called after OleInPlaceObject::UIDeactivate() without first calling

IOleInPlaceObject::InPlaceDeactivate().

RESOLUTION

Call IOleInPlaceObject::InPlaceDeactivate() before calling

IOleObject::Close.

STATUS

Microsoft has confirmed this to be a problem in OLE version 2.0. This

problem was corrected in OLE version 2.01.

Additional reference words: 2.00 gpf gp-fault

KBCategory: kbole kbfixlist kbbuglist

KBSubcategory: LeTwoTls


FIX: TYPE_E_CANTLOADLIBRARY Error on Win32s

PSS ID Number: Q131051

Authored 02-Jun-1995	Last modified 20-Jun-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.03

 - Microsoft Win32s version 1.20

SYMPTOMS

A 32-bit OLE Automation server that implements dual or vtable binding

interfaces finds that loading the type library or a typeinfo from the type

library fails under Win32s version 1.20 with this error:

   TYPE_E_CANTLOADLIBRARY

CAUSE

A problem in OpenFile in Win32s version 1.20 causes the search for

STDOLE32.TLB to be done incorrectly.

STATUS

Microsoft has confirmed this to be a bug in Win32s version 1.20. This bug

was corrected in Win32s version 1.25a, which can be obtained from the

Microsoft Software Library by searching for PW1118.EXE.

Download PW1118.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for PW1118.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download PW1118.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the SOFTLIB\MSLFILES directory

      Get PW1118.EXE

Additional reference words: 2.0 2.00

KBCategory: kbprg kbole kbfixlist kbbuglist kbfile

KBSubcategory: LeTwoArc


FORMATETC for IDataObject::DAdvise Must be Validated

PSS ID Number: Q114600

Authored 08-May-1994	Last modified 17-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

SUMMARY

Applications implementing IDataObject must validate the FORMATETC structure

that is passed to IDataObject::DAdvise(). Some commercial applications,

such as Microsoft Excel 5.0, will try to set up an Advise on their own

native format before setting up an Advise on the format selected by the

user in the Paste Special dialog box while creating a link.

MORE INFORMATION

When validating the FORMATETC structure, the server application needs to

allow wildcard Advises to succeed. A Wildcard Advise is an Advise set up by

the default link object so that it can properly maintain the time-of-last-

change. A Wildcard Advise is requested by passing a FORMATETC with cfFormat

= 0, ptd = NULL, dwAspect = -1L, and tymed = -1L. Code to validate the

FORMATETC structure might look as follows:

   // if not a Wildcard Advise and the data format is not supported,

   // return failure.

   if( !(pfmtetc->cfFormat == NULL  &&

         pfmtetc->ptd      == NULL  &&

         pfmtetc->dwAspect == -1L   &&

         pfmtetc->lindex   == -1L   &&

         pfmtetc->tymed    == -1L)

      && FAILED(hres = QueryGetData(pfmtetc)) )

      return hres;

   // Now pass on to the Data Advise holder

For more information on the IDataObject::DAdvise() member function, please

refer to pages 436-439 of the "OLE Programmer's Reference, Volume 1".

Additional reference words: 2.01 3.50 4.00

KBCategory: kbole kbprg

KBSubcategory: LeTwoSvr


How to Obtain Documentation for MS Graph 5.0 Automation

PSS ID Number: Q131049

Authored 02-Jun-1995	Last modified 06-Jun-1995

The information in this article applies to:

 - Microsoft Graph 5.0

 - Microsoft OLE Libraries for Windows and Win32s, version 2.03

 - Microsoft OLE libraries included with:

    - Microsoft Windows NT version 3.5

    - Microsoft Windows 95

Documentation of the Microsoft Graph version 5.0 automation properties and

methods can be found in the VBAGRP.EXE self-extracting file in the library

of the ADK/ADT section of the MSACCESS forum on Compuserve.

Additional reference words: 2.0 3.50 4.00 2.00

KBCategory: kbprg

KBSubcategory: LeTwoAto


How to Test OLE Applications with Outline

PSS ID Number: Q131154

Authored 04-Jun-1995	Last modified 07-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.5

 - Microsoft OLE Libraries for Windows and Win32s, versions 2.01, 2.02,

   and 2.03

 - Microsoft OLE Libraries included with:

    - Microsoft Windows NT version 3.5

    - Microsoft Windows 95

SUMMARY

To understand how an OLE application should handle an OLE scenario, you may

find it helpful to examine an existing application that handles that

scenario correctly.

The OUTLINE series of OLE sample applications can provide a log of debug

output. This log shows all of the OLE calls that the OUTLINE application

handles and the OLE calls that it makes. Examining this log is a useful OLE

problem-solving tool, and an excellent way to learn about OLE programming.

MORE INFORMATION

The OUTLINE series consists of four different applications: CNTROUTL (OLE

container), SVROUTL (OLE server), ICNTROTL (in-place editing-capable

OLE container), and ISVROTL (in-place editing-capable OLE server). The

OUTLINE series is included as sample code with the OLE SDK and with the

Win32 SDK.

Each of the four OUTLINE applications implements a Debug Level dialog

box. The following table show the debugging information produced by each

debug level value:

Debug Level   Debugging Information Produced

-----------------------------------------------------------------------

   0          No debug messages (default).

   1          Print message when a Document or Application is destroyed.

   2          Trace every OLE API and method call.

   3          Give a more OUTLINE app specific context to the OLE calls.

   4          Track all memory reference counts (AddRef/Release).

The debug output forms a log of all the incoming and outgoing OLE method

calls that OUTLINE handles. Use the DBWIN tool to capture and display this

output. Note that although there are both 16-bit and 32-bit versions of

the OUTLINE samples, DBWIN can currently only be used to capture output

from the 16-bit samples.

Benefits to Examining the Watch Log

-----------------------------------

The first benefit to examining the watch log produced by one of the

OUTLINE samples is that it shows the series of calls that an OLE

application needs to make in order to handle a given OLE scenario. For

example, to see what calls an OLE container application needs to make when

transitioning an embedded object from the loaded to the running state,

double-click an object embedded into a CNTROUTL document to run that

object; then examine the log that CNTROUTL produces.

The next benefit arises from the fact that the source code to the OUTLINE

samples is included with Microsoft Visual C++. The watch log shows you

the key calls that OUTLINE makes to handle some particular scenario.

Using a GREP utility, you can search the OUTLINE source code for those

calls, and then examine that code. The OUTLINE source code is a very

thorough implementation of OLE functionality.

In addition, you can run the OUTLINE application under a debugger, setting

break points before the key calls, and then stepping through that code.

Finally, the OUTLINE source code contains many source code comments labeled

"OLE2NOTE." These comments contain in-depth discussions of some of the

more detailed aspects of OLE programming.

Additional reference words: kbinf 2.01 2.02 2.03 3.50 4.00

KBCategory: kbole kbtshoot

KBSubcategory: LeTwoTls


How Visual Basic Automation Statements Map to OLE Calls

PSS ID Number: Q122288

Authored 01-Nov-1994	Last modified 21-Apr-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.02

 - Microsoft Visual Basic for Windows, version 3.0

SUMMARY

This article lists the OLE API and interface calls to which the Visual

Basic CreateObject and GetObject calls map. Each listing shows how to

obtain the IDispatch of an OLE Automation object. You can then invoke a

property or method of the OLE Automation object by using

IDispatch::GetIDsOfNames and IDispatch::Invoke.

MORE INFORMATION

The code listed below does not do any error checking. When you implement

it, you should add the code to do necessary error checking. See the OLE SDK

documentation for more information about each function or interface. Each

code listing shows how to obtain the pointer to IDispatch of an Automation

object in the pdisp variable.

CreateObject(progID)

--------------------

This creates a new automation object and returns a pointer to the IDispatch

of that object.

CLSID clsid;

LPUNKNOWN punk;

LPDISPATCH pdisp;

OleInitialize(NULL), if OLE isn't already loaded.

CLSIDFromProgID(progID, &clsid);

CoCreateInstance(clsid, NULL, CLSCTX_SERVER,

                 IID_IUnknown, (LPVOID FAR*)&punk);

punk->QueryInterface(IID_IDispatch, (LPVOID FAR*)&pdisp);

punk->Release();

GetObject(filename, progID)

---------------------------

GetObject has three different semantics depending on the number of

parameters passed. An automation object must implement IPersistFile to

support GetObject(filename, progID).

CLSID clsid;

LPUNKNOWN punk;

LPDISPATCH pdisp;

LPPERSISTFILE pPF;

OleInitialize(NULL), if OLE isn't already loaded

CLSIDFromProgID(progID, &clsid);

CoCreateInstance(clsid, NULL, CLSCTX_SERVER,

                 IID_IUnknown, (LPVOID FAR*)&punk);

punk->QueryInterface(IID_IPersistFile, (LPVOID FAR*)&pPF);

punk->Release();

pPF->Load(filename, 0);

pPF->QueryInterface(IID_IDispatch, (LPVOID FAR*)&pdisp);

pPF->Release();

GetObject(filename,)

--------------------

GetObject has three different semantics depending on the number of

parameters passed. An automation object must implement IPersistFile to

support GetObject(filename,).

LPBC pbc;

ULONG cEaten;

LPMONIKER pmk;

LPDISPATCH pdisp;

OleInitialize(NULL), if OLE isn't already loaded

CreateBindCtx(0, &pbc);

MkParseDisplayName(pbc, filename, &cEaten, &pmk);

BindMoniker(pmk, 0, IID_IDispatch, (LPVOID FAR*)&pdisp);

pmk->Release();

pbc->Release();

GetObject(, progID)

---------------------

GetObject has three different semantics depending on the number of

parameters passed. An automation object must call RegisterActiveObject to

support GetObject(, progID).

CLSID clsid;

LPUNKNOWN punk;

LPDISPATCH pdisp;

OleInitialize(NULL), if OLE isn't already loaded

CLSIDFromProgID(progID, &clsid);

GetActiveObject(clsid, NULL, (LPVOID FAR*)&punk);

punk->QueryInterface(IID_IDispatch, (LPVOID FAR*)&pdisp);

punk->Release();

Additional reference words: 2.00 3.00

KBCategory: kbold kbprg kbcode

KBSubcategory: LeTwoAto


Insert Link from File Changes Current Directory

PSS ID Number: Q109553

Authored 04-Jan-1994	Last modified 21-Apr-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

The Insert Object dialog box allows a user to insert a linked object into

the container document from a file residing on disk. This action changes

the current working directory to the drive and directory in which the file

resides. If this file is located on a network drive and the network drive

becomes unavailable after the link is established, any subsequent attempt

to insert an embedded object will fail until the working directory is

changed to a drive and directory that is accessible.

The problem materializes when the OLE 2.0 libraries attempt to WinExec a

server application for a subsequent embedded object. In this situation, the

call to WinExec fails because the current working directory is invalid.

The Open common dialog box changes the current working directory unless

OFN_NOCHANGEDIR is specified. The UI Change Source dialog box depends on

the change directory functionality, however, and therefore the Insert

Object dialog box cannot be modified to correct the problem.

Additional reference words: 2.01 OpenFile

KBCategory: kbole kbprg

KBSubcategory: LeTwoTls


Limits of VB 3.0 & Disptest as Automation Controllers

PSS ID Number: Q122287

Authored 01-Nov-1994	Last modified 21-Apr-1995

The information in this article applies to:

 - Microsoft Visual Basic for Windows, version 3.0

 - Microsoft OLE Libraries for Windows and Win32s, version 2.02

SUMMARY

Visual Basic version 3.0 for Windows and Disptest (the automation

controller that shipped with OLE version 2.0) have the following

limitations as automation controllers in addition to those described on

pages 67-69 of the OLE 2 Programmer's Reference, Volume 2:

 - Parameters cannot be passed by reference to Automation properties or

   methods.

 - Array elements cannot be accessed.

 - When an exception is raised by an automation object, the value of

   the wCode field of the EXCEPINFO structure is not used. Instead the

   value 440 is displayed.

MORE INFORMATION

Parameters Cannot Be Passed by Reference

----------------------------------------

Visual Basic version 3.0 for Windows and Disptest cannot pass parameters by

reference to automation properties and methods.

This is a limitation of Visual Basic version 3.0 and Disptest, not of OLE

Automation. OLE Automation allows building controllers that pass parameters

by reference.

Here are three workarounds:

 - Use return values of properties and methods to return a value instead of

   using byref parameters for this purpose. This approach cannot be used

   when a property or method returns multiple values.

   -or-

 - Use third party controllers (see the list below) while you wait for a

   future version of Visual Basic, or use Visual Basic for Applications,

   which ships with Microsoft Excel version 5.0. Microsoft Visual Basic for

   Applications cannot be redistributed by or incorporated into products

   that are not manufactured by Microsoft. However, if user of your

   application has Microsoft Excel version 5.0 installed, you can use its

   Visual Basic for Applications as a controller of any Automation server.

   Here are two known third-party controllers:

   NOTE: The products included here are manufactured by vendors

   independent of Microsoft; we make no warranty, implied or otherwise,

   regarding these products' performance or reliability.

   Softbridge Basic Language

   Mystic River Software, Inc. 125 CambridgePark Drive, Cambridge MA 02140

   Tel:1-800-298-3500, 617-497-1585

   Fax:617-864-7747

   Summit BasicScript

   Summit Software Company, 2844 Sweet Road, Jamesville, NY  13078

   Tel: 315-677-9000

   Fax: 315-677-3224

   Internet: info@summsoft.com

   Compuserve: 71211,3504

   -or-

 - Write a DLL that has exported functions that correspond to Automation

   methods and properties exposed by the automation server. Visual Basic

   version 3.0 can call these exported DLL functions, which in turn can

   call the corresponding automation properties or methods in the

   automation server. This approach works because Visual Basic version 3.0

   can pass parameters by reference to DLL functions.

   The DLL functions can pass parameters by reference to the properties and

   methods of the automation method or property because OLE supports

   passing parameters by reference. This approach may not be suitable for

   some automation servers that implement nested objects.

Array Elements Cannot Be Accessed

---------------------------------

Array elements cannot be accessed in Visual Basic version 3.0 or Disptest.

As a result, code similar to the following code cannot be executed in

Visual Basic version 3.0 or in Disptest if selection returns a safearray.

This is because safearray elements cannot be accessed in Visual Basic

version 3.0 or in Disptest.

   Value = ObjVar.Selection(I)

   ObjVar.Selection(I) = Value

Workarounds include using indexed properties, third-party controllers,

Visual Basic for Applications in Microsoft Excel version 5.0, or waiting

for a future release of Visual Basic.

Indexed properties are properties that take parameters. For example,

in the example code, Selection could be made a property that takes an

index parameter. Here is a description in the .ODL file of an indexed

parameter called Value whose property type is VARIANT:

   [propget] VARIANT Value(long index);

   [propput] void Value(long index, VARIANT NewValue);

In a dispinterface, an indexed property should be used under the 'methods'

keyword. A Microsoft Foundations Classes (MFC) implementation can use the

DISP_PROPERTY_PARAM macro in the dispatch map to implement an indexed

property.

The disadvantage of implementing array element access using indexed

properties is the performance penalty caused by each indexed property

access requiring the overhead of an RPC/LRPC call (for LocalServer

Automation objects).

Value of EXCEPINFO.wCode Not Displayed on Exceptions

----------------------------------------------------

When an automation object raises an exception by returning DISP_E_EXCEPTION

from IDispatch::Invoke and by filling the pexcepinfo parameter of this

method, Visual Basic version 3.0 and Disptest will ignore the value

returned in the wCode field of the EXCEPINFO structure, instead returning

the value 440. Note that either the wCode or scode field of EXCEPINFO

should be set to 0 -- both cannot be used.

Workarounds include using third-party controllers, Visual Basic for

Applications in Microsoft Excel version 5.0, or waiting for a future

release of Visual Basic.

Additional reference words: 2.00 3.00 5.00

KBCategory: kbole kbprg kb3rdparty

KBSubcategory: LeTwoAto


Object Creation Overview

PSS ID Number: Q104139

Authored 08-Sep-1993	Last modified 17-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.0

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

SUMMARY

The actual process of creating an OLE object can seem confusing when

first learning OLE. To elucidate the object creation process, this

article describes the steps taken by the OLE 2.0 libraries in response

to a call to OleCreate(), with the OLERENDER_DRAW format passed as the

renderopt parameter. This article gives a basic overview of the object

creation process; it does not describe specific application

programming interfaces (APIs) in detail.

MORE INFORMATION

Typically, the container application presents the user with a dialog

box containing the various types of objects that can be created on a

particular system. These object types are enumerated from the

Registration Database--each entry in the database has a name that the

user can understand, as well as a unique identifier for the object

type called a CLSID.

The container tells OLE that it wants to create an object. At this

point, the container gives OLE the CLSID of the desired object, a

pointer to a child storage within the container's compound file, and a

pointer variable for OLE to return a pointer to a requested interface

(typically IOleObject):

    Container         OLE

   -----------    -----------

   |OleCreate|--->|         |

   |         |    |         |

   |         |    |         |

   |         |    |         |

   |         |    |         |

   |         |    |         |

   -----------    -----------

The OLE libraries then consult the registration database to find the

name of the executable file associated with the CLSID:

    Container         OLE

   -----------    -----------

   |OleCreate|--->|         |

   |         |    |         |

   |         |    |         |

   |         |    |         |

   |         |    |         |

   |         |    |         |

   -----------    -----------

                    |

                    V

                 Reg DB

The server is then started with the -Embedding flag. When the server

parses the command line and sees the -Embedding flag, it knows that it

is being started on behalf of OLE and should remain hidden until it is

explicitly told to become visible. At this point, the server registers

a pointer to its IClassFactory interface with OLE:

    Container         OLE           Server

   -----------    -----------    -----------------

   |OleCreate|--->|         |--->|               |

   |         |    |         |<---| IClassFactory |

   |         |    |         |    |               |

   |         |    |         |    |               |

   |         |    |         |    |               |

   |         |    |         |    |               |

   -----------    -----------    -----------------

                    |

                    V

                 Reg DB

OLE calls the server through the IClassFactory interface and asks to

instantiate an object, returning the pointer to the interface

requested by the container in the creation routine:

    Container         OLE           Server

   -----------    -----------    ------------------

   |OleCreate|--->|         |--->|                |

   |         |    |         |<---| IClassFactory  |

   |         |    |         |--->| -------------  |

   |         |    |         |<---|-|IOleObject |  |

   |         |    |         |    | |IDataObject|  |

   |         |    |         |    | |    etc    |  |

   |         |    |         |    | -------------  |

   -----------    -----------    ------------------

                    |

                    V

                 Reg DB

OLE queries the object for the IDataObject interface, and then calls

GetData method to fill the presentation cache with a metafile,

device-independent bitmap (DIB), or a bitmap. Later, when the

container asks the object to draw itself, OLE will intercept the call

and use one of the entries in the presentation cache:

    Container         OLE           Server

   -----------    -----------    ------------------

   |OleCreate|--->|         |--->|                |

   |         |    |         |<---| IClassFactory  |

   |         |    |         |--->| -------------  |

   |         |    |         |<---|-|IOleObject |  |

   |         |    |         |    | |IDataObject|  |

   |         |    |         |    | |    etc    |  |

   |         |    |         |    | -------------  |

   -----------    -----------    ------------------

                    |      |

                    V      v

                Reg DB  Cache

At this point, the creation routine returns to the container. Now, the

container will generally query the interface pointer returned for the

IViewObject interface. The container uses the IViewObject interface to

ask the object to notify the container (through the container's

IAdviseSink interface) every time the object's view changes, so that

the container can update its display. At this point, the server

creates an advise holder to notify the object of its changes:

    Container             OLE              Server

   --------------    -------------    ------------------

   |            |    |           |    |                |

   |            |    |           |    | IClassFactory  |

   |            |    |           |    | -------------  |

   |            |--->|IOleObject |----->|IOleObject |  |

   |            |    |           |    | |IDataObject|  |

   |            |    |           |    | |    etc    |  |

   |            |    |           |    | -------------  |

   |IAdviseSink |<---|           |<---|IOleAdviseHolder|

   --------------    -------------    ------------------

                        |      |

                        V      v

                     Reg DB  Cache

Note, the object still is not visible at this point. Now an explicit

call to IOleObject::DoVerb() must be made with the verb OLEIVERB_SHOW.

This tells the server to make the object visible for editing.

Every time the user makes a change to the object, the object calls OLE

through the advise holder to notify the libraries that the view has

been changed. The libraries then query the object for the new

presentation(s) to fill the presentation cache. Then the advise sink

of the container application is called to notify the container that

its view is no longer up to date, and should be repainted.

The container then in turn tells OLE to draw the object, at which

point the libraries render the information from the cache.

At some point, the user tells the server that he or she is finished

editing the object. The server tells the container that it is now

going away, and that the object needs to be saved into the container's

persistent storage. The container responds by telling the object to

save itself into a substorage of the container's compound file. The

OLE libraries "intercept" this call and save internal state

information, as well as the presentation cache, into streams of this

substorage. Then, the libraries tell the object to save itself into

the container provided substorage.

After saving the object, the container's compound file resembles the

following:

   ----------------

   | Root Storage |

   ----------------

           |   ---------------                   * = Stream

           |---|   object    |                   - = Storage

           |   | sub-storage |

           |   ---------------

           |          |   ****************

           |          |---*  OLE State   *

           |          |   ****************

           |          |   ****************

           |          |---* Presentation *

           |          |   ****************

           |          |   ****************

           |          |---* Native Data  *

           |              ****************

           |    ***************

           |    *  Container  *

           |--- *    State    *

                * Information *

                ***************

The container can continue to redraw the object even though the server

application is no longer around because the object's presentation is

stored in OLE's internal cache:

    Container             OLE

   --------------    -------------

   |            |    |           |

   |            |    |           |

   |            |    |           |

   |            |--->|IOleObject |

   |            |    |           |

   |            |    |           |

   |            |    |           |

   |IAdviseSink |<---|           |

   --------------    -------------

                        |      |

                        V      v

                     Reg DB  Cache

Now the user can save the document in the container application and

exit. Upon exiting, the container queries the object for the

IViewObject interface so the container can tell OLE to stop sending

updates. Then the container asks the object to close.

If the user now reloads the document, or moves the document to another

machine, the OLE libraries can still render the object because the

presentation is actually stored within the container's compound file.

When the object is reloaded, the libraries can refill the presentation

cache from the information stored within the compound file.

Additional reference words: 2.00 3.50 4.00

KBCategory: kbole kbprg

KBSubcategory: LeTwoCdt


Objects in .EXE Cannot be Aggregated

PSS ID Number: Q114598

Authored 08-May-1994	Last modified 17-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, versions 2.0 and 2.01

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

Attempting to create an aggregate object with a Non-Control object

implemented in another .EXE is not possible. Passing a value for the

punkOuter parameter of IClassFactory::CreateInstance() in this situation

results in the error value CLASS_E_NOAGGREGATION.

The proxy for IClassFactory returns this error value immediately, without

calling the CreateInstance() method in the object. According to the rules

of aggregation, the Non-Control Object must not reference count the pointer

to the controlling IUnknown. If the parts of the aggregate object reside in

separate process spaces, the proxy for the controlling IUnknown will be

freed prematurely due to the lack of this reference count. Without the

interface proxy, the pointer to the controlling IUnknown stored by the Non-

Control Object is no longer valid, causing problems when delegating calls

to the outer IUnknown.

For more information on the process of Aggregation, please refer to

the "OLE 2 Programmer's Reference", "Working with Windows's Objects".

Additional reference words: 2.01 3.50 4.00

KBCategory: kbole kbprg

KBSubcategory: LeTwoOh


OLE 2.02 Update for Windows and Win32s

PSS ID Number: Q121835

Authored 19-Oct-1994	Last modified 20-Jun-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.02

SUMMARY

The file OLE202.EXE contains upgrades and additions to the 16-bit OLE files

shipped with the Win32 SDK for Windows NT 3.5. This also includes the

32-bit counterparts for Win32s to the 16-bit tools shipped with the 16-bit

OLE2 SDK. These files supercede the components of the OLE version 2.01 SDK

for Windows 3.1x and Windows for Workgroups.

For additional information regarding Win32s availability, please see the

following article in the Microsoft Knowledge Base:

   ARTICLE-ID: Q122235

   TITLE     : Microsoft Win32s Upgrade

For additional information regarding the availability of updated OLE 2.02

libraries, please see the following article in the Microsoft Knowledge

Base:

   ARTICLE-ID: Q123087

   TITLE     : WW1116: OLE Version 2.02

MORE INFORMATION

Download OLE202.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for OLE202.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download OLE202.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \softlib\mslfiles directory

      Get OLE202.EXE

OLE202.EXE holds the following 16-bit updates and additions to the OLE202

SDK that shipped with Windows NT version 3.5:

LRPCSPY.EXE

DOBJVIEW.EXE

IROTVIEW.EXE

OLE2VIEW.EXE

COMPOBJ.DLL

OLENLS.H

VARIANT.H

DISPATCH.H

OLE2DISP.LIB

OLE2NLS.LIB

TYPELIB.LIB

and additions:

RPCSPY32.EXE

DOBJVW32.EXE

IROTVW32.EXE

OLE2VW32.EXE

NOTE: The tools contained in OLE202.EXE are designed to work with Windows

3.1 (16-bit) or Win32s 1.2, and the OLE 2.02 DLLs only. Do not mix the OLE

2.02 DLLs with the OLE 2.01 DLLs. You must install the OLE 2.02 DLLs over

the OLE 2.01 DLLs. The tools include new automation features such as vtable

binding and OLE32 tools for Win32s. Please see the Win32 OLE help file or

the OLEHLP.TXT file for details about the new automation features.

Additional reference words: 2.01 2.02 3.50 3.10 1.20

KBCategory: kbole kbtool kbfile

KBSubcategory: letwomisc


OleCreateFromFile() Does Not Check for Reserved Names

PSS ID Number: Q111015

Authored 03-Feb-1994	Last modified 21-Apr-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

Before an OLE 2.0 container application calls OleCreateFromFile() to create

an embedded object from the contents of a named file, it must make sure

that the filename it passes as the lpszFile parameter to

OleCreateFromFile() is not a reserved MS-DOS device name, such as COM1 or

LPT1. This check is necessary because OleCreateFromFile() does not perform

such a check itself.

A container application generally obtains the filename to pass to

OleCreateFromFile() by presenting the user with the Insert Object dialog

box. Many containers use the OLE2UI library implementation of the Insert

Object dialog box, by calling OleUIInsertObject(). OleUIInsertObject()

performs a check to make sure that the filename supplied by the user is not

a reserved MS-DOS device name; if the user supplies a filename such as

"COM1", OleUIInsertObject() brings up a modal dialog box stating "File COM1

Does Not Exist."

Therefore, container applications that use OleUIInsertObject() do not have

to perform a check for reserved names.

Additional reference words: 2.01

KBCategory: kbole

KBSubcategory: LeTwoCdt


Passing Structures in OLE Automation

PSS ID Number: Q122289

Authored 01-Nov-1994	Last modified 21-Apr-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.02

 - Microsoft Visual Basic for Windows, version 3.0

SUMMARY

OLE Automation does not allow structures to be passed as parameters.

Automation servers that work with standard controllers can model a

structure as an automation object. Automation servers that work with

custom controllers can pass structures as a safearray of VT_UI1 or

by passing a data transfer object that supports IDataObject.

MORE INFORMATION

OLE Automation does not support passing structures as parameters to

automation methods and properties. Here are some ways to work around this:

NOTE: Standard controllers are products such as Visual Basic that can

control any automation server. A custom controller is written to

control a specific automation server.

If the Automation server is designed to work with standard controllers such

as Visual Basic, the structure could be modeled as an automation object.

For example, consider this structure:

struct point {

    short x;

    short y;

};

This could modeled as an automation object with two properties, x and y.

Visual Basic code such as the following could be used to get and set the

values of the properties. Note how the CreateLine method, which required

two points as parameters, is implemented as taking references to two

automation objects.

Dim Application As Object

Dim P1 As Object

Dim P2 As Object

Dim Line As Object

:

Set P1 = Application.CreatePoint()

P1.x = 3

P1.y = 4

Set P2 = Application.CreatePoint()

P2.x = 20

P2.y = 21

Set Line = Application.CreateLine(P1, P2)

The CreatePoint method returns a Point automation object whose x & y

properties are set. The type of the value returned by CreatePoint is

IDispatch* or a pointer to an object that supports automation. The

CreateLine method takes two parameters of type IDispatch* or a pointer

to an object that supports automation.

The disadvantage of this solution is that if the automation server is

not an inproc server, each property access will result in the overhead

of an LRPC/RPC call.

If the automation server is designed to work with custom controllers,

the structure could be serialized into a safearray of VT_UI1 and the

resultant binary data could be passed as a parameter of type

SAFEARRAY(unsigned char). Another solution is to create a data transfer

object that supports IDataObject. The IUnknown of this data transfer

object could be passed in a parameter of type IUnknown*.  The server

could then use IDataObject::GetData with a private clipboard format

to get the storage medium in which the structure was serialized. Both

these solutions will not work with standard controllers such as Visual

Basic.

NOTE: Serializing the structure into a BSTR will not work because

the Unicode-ANSI conversions done by OLE's 16:32 bit interoperablity

layer assumes that BSTRs contain strings and not binary data. Consequently,

binary data passed in BSTRs can be corrupted by such conversions. However,

serializing binary data into BSTRs will work if both controller and server

are 16-bit. It will also work if both the controller and server are 32-bit

and both support Unicode. This is because 32-bit OLE supports only Unicode,

not ANSI. A safearray of VT_UI is preferred because of these limitations

of passing binary data through BSTRs.

Additional reference words: 2.00 3.00

KBCategory: kbole kbprg kbcode

KBSubcategory: LeTwoAto


Passing Variant Parameters in OLE Automation

PSS ID Number: Q104960

Authored 04-Oct-1993	Last modified 17-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.0

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

A variant must be initialized using VariantInit after creation and

before it is passed to a function. A variant with a valid value must

be cleared using VariantClear before a new value is assigned to it.

A variant must be passed to or from a function in a valid state and

the contents of the variant must be correctly freed. This requires

that the following be done:

1. On creation of a variant, call VariantInit before passing it to a

   function.

2. A function that is passed a variant should clear it using

   VariantClear to free the previous contents before assigning it a

   new value.

VariantInit sets the vt field of the VARIANT (or VARIANTARG) structure

to VT_EMPTY but does not free the contents of the variant.

VariantClear frees the contents of the variant depending on the

current value of the vt field and then sets the vt field to VT_EMPTY.

Passing an uninitialized variant to a function is a common error. This

may cause problems when the VariantClear call in the function tries to

free the contents of the uninitialized variant based on the undefined

value of the vt field.

Additional reference words: 2.00 2.01 3.50 4.00

KBCategory: kbole kbprg

KBSubcategory: LeTwoAto


PRB: Calling IOleObject::InitFromData Returns E_NOTIMPL

PSS ID Number: Q108312

Authored 08-Dec-1993	Last modified 17-May-1995

The information in this article applies to:

 - Microsoft OLE version 1.0

 - Microsoft OLE Libraries for Windows and Win32s, versions 2.0 and 2.01

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

SYMPTOMS

After an OLE 2.0 container successfully returns from a call to OleCreate(),

a subsequent call to IOleObject::InitFromData() returns with a failure of

E_NOTIMPL.

CAUSE

The object being manipulated is an OLE 1.0 object.

RESOLUTION

This is a limitation of an OLE 1.0 server application. Contact the

manufacturer of the server application to find out the availability of an

OLE 2.0-compliant version of the server.

MORE INFORMATION

OLE 1.0 does not have a feature equivalent to IOleObject::InitFromData, and

therefore the OLE 2.0 libraries cannot synthesize this functionality in the

OLE 1.0 compatibility layer.

If the object application is an OLE 2.0-compliant application, the error is

returned by the object application's implementation of this method.

Additional reference words: 1.00 2.00 2.01 3.50 4.00

KBCategory: kbole kbprg kbprb

KBSubcategory: LeTwoArc


PRB: Compiler Doesn't Lay Out Overloaded Functions in Order

PSS ID Number: Q131104

Authored 04-Jun-1995	Last modified 07-Jun-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.03

 - Microsoft OLE libraries included with:

    - Microsoft Windows NT version 3.5

    - Microsoft Windows 95

 - Microsoft Visual C++ for Windows, version 1.52

 - Microsoft Visual C++, 32-Bit Edition, version 2.1

SYMPTOMS

The Microsoft Visual C++ compiler does not lay out overloaded functions in

the vtable in the order in which they are declared. This does not adhere to

the COM binary standard. (See the OLE Specification section 3.1.1.1 for a

discussion of the COM binary standard.) If there are no overloaded

functions, the COM binary standard is followed.

In general, it is not a good idea to use overloaded methods in a COM

interface because this precludes use of the interface from languages like C

that do not support overloading.

CAUSE

All the overloads of a function are laid out together in successive entries

in the reverse order of their declaration, overall in the order of the

first overload of each name. Therefore given this declaration:

class A {

   virtual void a();

   virtual void b();

   virtual void a(int);

   virtual void b(int);

};

Entries in the vtable are laid out in this order: A::a(int), A::a(),

A::b(int), A::b(). The COM binary standard requires that functions be laid

out in the order in which they are declared.

STATUS

This behavior is built into the design. It cannot be modified because of

legacy code that depends on this behavior.

Additional reference words: 2.03 1.52 4.00 3.50 2.10

KBCategory: kbprg kbole kbprb

KBSubcategory: LeTwoArc


PRB: Compound File Sharing Problems on Novell Netware

PSS ID Number: Q131050

Authored 02-Jun-1995	Last modified 06-Jun-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.03

NOTE: Novell Netware is manufactured by a vendor independent of Microsoft;

we make no warranty, implied or otherwise, regarding this product's

performance or reliability.

SYMPTOMS

STGM_SHARE_DENY_WRITE is ineffective when opening compound files on a

network drive when the computer is running Novell Netware version 4.1 or

earlier.

For example with the following code, the open will succeed the first time

as expected, but it will also succeed in subsequent openings, which should

not happen because of STGM_SHARE_DENY_WRITE.

   hr = StgOpenStorage(szFileName, NULL, STGM_TRANSACTED | STGM_READWRITE |

                STGM_SHARE_DENY_WRITE, NULL, 0, &lpStg);

CAUSE

This problem is caused by incorrect range locking done by Novell Netware.

RESOLUTION

This problem doesn't occur if the computer is running the Microsoft

Network.

STATUS

We are researching this problem and will post new information here in the

Microsoft Knowledge Base as it becomes available.

Additional reference words: 2.0 2.00

KBCategory: kb3rdparty kbprg kbnetwork kbprb

KBSubcategory: LeTwoPst


PRB: GetData Returns Outdated Data for OLE 1.0 Object

PSS ID Number: Q110716

Authored 27-Jan-1994	Last modified 17-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

SYMPTOMS

If an OLE 2.0 container application document contains an embedded OLE 1.0

object, and the container calls IDataObject::GetData() to retrieve data for

that object, the data returned is out of date, and does not reflect the OLE

1.0 server's most recent changes to the object.

CAUSE

OLE 1.0 embedded object servers only update the cache when the user chooses

the Update command from the File menu. OLE 1.0 objects do not update the

cache for every change to the object. Therefore, an OLE 1.0 object's cache

often contains outdated data.

RESOLUTION

The container can obtain the latest object data by calling

IOleObject::Update(). This function ensures that any data or view caches

maintained inside the object are up to date.

REFERENCES

For more information on known idiosyncrasies of embedding OLE 1.0 objects

into OLE 2.0 containers, see "Working with OLE 1 Servers" in the OLE

Software Development Kit (SDK) version 2.01 Programmer's Reference.

Additional reference words: 2.01 3.50 4.00

KBCategory: kbole kbprg kbprb

KBSubcategory: LeTwoArc


PRB: GP Fault When Using 16-Bit Automation DLLs

PSS ID Number: Q131047

Authored 02-Jun-1995	Last modified 06-Jun-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.03

SYMPTOMS

After dynamically loading and then unloading one of the 16-bit OLE

Automation DLLs (OLE2DISP.DLL, LOE2NLS.DLL, or TYPELIB.DLL), you experience

a general protection (GP) fault in COMPOBJ.DLL.

CAUSE

If any of the 16-bit OLE Automation DLLs (OLE2DISP.DLL, LOE2NLS.DLL, or

TYPELIB.DLL) is dynamically loaded, it should not be unloaded until after

OleUninitialize has been called. Otherwise a general protection (GP) fault

can occur in COMPOBJ.DLL.

RESOLUTION

If you dynamically load any of the 16-bit OLE Automation DLLs

(OLE2DISP.DLL, LOE2NLS.DLL, or TYPELIB.DLL), don't unload it until

OleUninitialize has been called.

STATUS

This requirement is by design.

Additional reference words: GPF

KBCategory: kbprg kbole kbprb

KBSubcategory: LeTwoAto


PRB: IOleObject::IsUpToDate() and OLE 1.0 Link Objects

PSS ID Number: Q111613

Authored 14-Feb-1994	Last modified 17-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

SYMPTOMS

An OLE 2.0 container application calls IOleObject::IsUpToDate to determine

whether or not an OLE 1.0 link object is up to date. IsUpToDate() returns

S_FALSE, even though the object is actually up to date.

CAUSE

The OLE 1.0 compatibility layer always considers OLE 1.0 link objects to be

out of date. If the OLE 1.0 object is not running, the compatibility layer

always returns S_FALSE to IOleObject::IsUpToDate().

MORE INFORMATION

This problem can occur whenever an OLE 2.0 container application loads a

document that contains links to OLE 1.0 objects. As part of loading the

document, the link container updates any out of date automatic links. To

find the out of date links, the container calls IOleObject::IsUpToDate() on

each link that has a link-update option of OLEUPDATE_ALWAYS.

As described above, IsUpToDate will always return S_FALSE for an OLE 1.0

object that is not running. The container application will then update the

link object (which requires running the object's server), even if it was

not actually out of date.

For more information on the known idiosyncrasies of embedding or linking

OLE 1.0 objects into OLE 2.01 containers, see "Working with OLE 1 Servers"

in the OLE SDK version 2.01 "Programmer's Reference."

Additional reference words: 2.01 3.50 4.00

KBCategory: kbole

KBSubcategory: LeTwoArc


PRB: IROT::IsRunning() Returns S_FALSE for OLE 1.0 Servers

PSS ID Number: Q109544

Authored 04-Jan-1994	Last modified 17-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

SYMPTOMS

When an OLE 2.0 container application calls

IRunningObjectTable::IsRunning() on the moniker for a linked OLE 1.0

object, IsRunning() returns S_FALSE even if that OLE 1.0 object is already

running.

CAUSE

OLE 1.0 objects do not register themselves in the running object

table while they are running.

RESOLUTION

Calling IMoniker::IsRunning() on the moniker for a linked OLE 1.0 object

correctly returns S_OK if the object is indeed running.

As noted in the OLE SDK version 2.01 documentation for

IRunningObjectTable::IsRunning(), clients of a moniker should not call

IRunningObjectTable::IsRunning() directly; instead, they should call

IMoniker::IsRunning().

Additional reference words: 2.01 3.50 4.00 irot

KBCategory: kbole

KBSubcategory: LeTwoLnk


PRB: LoadTypeLib Does Not Register Type Library

PSS ID Number: Q131055

Authored 02-Jun-1995	Last modified 12-Jun-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.03

 - Microsoft OLE libraries included with:

    - Microsoft Windows NT version 3.5

    - Microsoft Windows 95

SYMPTOMS

LoadTypeLib will not register the type library if the path of the type

library is specified in the szFileName parameter. For backward

compatibility, LoadTypeLib will register the type library if the path is

not specified.

RESOLUTION

RegisterTypeLib should be used to register a type library.

STATUS

This behavior is by design.

Additional reference words: 2.0 2.00

KBCategory: kbprg kbprb

KBSubcategory: LeTwoAto


PRB: Menu Mnemonics Not Working During In-Place Activation

PSS ID Number: Q104460

Authored 19-Sep-1993	Last modified 17-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.0

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

SYMPTOMS

The menu mnemonics for an object do not operate properly, causing the

system to hang.

CAUSE

The server application is not calling OleTranslateAccelerator inside

of its message loop.

RESOLUTION

For menu commands to be dispatched properly during in-place editing,

OLE 2.0 needs to have the server application call

OleTranslateAccelerator, even if the server application does not have

accelerator support. This OLE application programming interface (API)

does the needed translation of key messages, and ensures that the

appropriate action occurs.

To be more efficient, a server application need only pass "keystroke"

messages to OleTranslateAccelerator. The following code demonstrates

what the message loop for an OLE server application should look like:

Sample Code

-----------

 // Message loop for an OLE server.

 //

 while (GetMessage(&msg, NULL, NULL))

    {

    if (m_fInplaceActive)  // If currently active in place.

        if (msg.message >= WM_KEYFIRST && msg.message <= WM_KEYLAST)

            // If it is a "keystroke" message.

            if (OleTranslateAccelerator(...) == NOERROR)

                continue; // OLE handled the message

    TranslateMessage(...);

    DispatchMessage(...);

    }

MORE INFORMATION

When the object's server is a stand-alone .EXE and the in-place active

object gets a keystroke message that is not a recognized accelerator,

the object must check to see if the message is one that the container

recognizes by calling the OleTranslateAccelerator function. If the

container does not want the keystroke, then the

OleTranslateAccelerator function will return FALSE. In this case, the

object should continue using its normal TranslateMessage and

DispatchMessage code.

If the container accepts the keystroke, OLE will call the container's

IOleInPlaceFrame::TranslateAccelerator member function to translate

the message. The container may call the Windows TranslateAccelerator

and/or TranslateMDISysAccel functions to process the accelerator key,

or do its own special processing.

Additional reference words: 2.00 3.50 4.00

KBCategory: kbole kbprg kbprb

KBSubcategory: LeTwoInp


PRB: Object Appears Larger During Visual Editing

PSS ID Number: Q104791

Authored 29-Sep-1993	Last modified 17-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.0

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

SYMPTOMS

An OLE 2.0 object appears larger during visual editing compared to the

loaded state.

CAUSE

The Windows application programming interface (API) LPtoDP is being

used to convert the size of the object from MM_HIMETRIC to MM_TEXT.

The object is then drawn with the MM_TEXT coordinates as the bounding

rectangle.

RESOLUTION

LPtoDP is dependent on the current mapping mode to perform a

conversion from logical points to device points. For a more accurate

transformation, a function must be written to "manually" convert the

units from MM_HIMETRIC to MM_TEXT by using GetDeviceCaps to get the

logical pixels per inch for use in the conversion. The OLE2UI library,

included with the OLE 2.0 toolkit, already includes several

transformation functions to properly convert the units:

   XformWidthInPixelsToHimetric  - Converts an int width into HiMetric

units

   XformWidthInHimetricToPixels  - Converts an int width from HiMetric

units

   XformHeightInPixelsToHimetric - Converts an int height into HiMetric

                                   units

   XformHeightInHimetricToPixels - Converts an int height from HiMetric

                                   units

   XformRectInPixelsToHimetric   - Converts a rect into HiMetric units

   XformRectInHimetricToPixels   - Converts a rect from HiMetric units

   XformSizeInPixelsToHimetric   - Converts a SIZEL into HiMetric units

   XformSizeInHimetricToPixels   - Converts a SIZEL from HiMetric units

For more information on these functions, consult the "User Interface

Dialog Help" help file (OLE2UI.HLP) included with the OLE 2.0 toolkit.

Additional reference words: 2.00 3.50 4.00

KBCategory: kbole kbprg kbprb

KBSubcategory: LeTwoPrs


PRB: OleCreate Problems with Borland Compiler

PSS ID Number: Q104461

Authored 19-Sep-1993	Last modified 21-Apr-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.0

SYMPTOMS

Using the OLE 2.0 application programming interface (API), OleCreate

can cause unexpected behavior and return unexpected error codes when

used in an application compiled with the Borland C++ compiler.

CAUSE

At link time, the Borland file IMPORT.LIB is included before the OLE

2.0 libraries. In the IMPORT.LIB file there is a reference to the OLE

1.0 OleCreate function.

RESOLUTION

Include OLE2.LIB before IMPORT.LIB when specifying the libraries for

linking.

Additional reference words: 2.00 third party third-party 3rd

KBCategory: kbole kbprg kbprb

KBSubcategory: LeTwoApp


PRB: Paste Link Option Does Not Appear in OLE 1.0 Clients

PSS ID Number: Q98680

Authored 11-May-1993	Last modified 17-May-1995

The information in this article applies to:

 - Microsoft OLE version 1.0

 - Microsoft OLE Libraries for Windows and Win32s, version 2.0

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

SYMPTOMS

The Paste Link option remains unavailable (grayed) in an OLE version

1.0 client when an OLE version 2.0 object places its data on the

clipboard.

CAUSE

The CF_OBJECTDESCRIPTOR and CF_LINKSRCDESCRIPTOR formats do not have

the OLEMISC_CANLINKBYOLE1 bit set in the dwStatus member of the

OBJECTDESCRIPTOR structure.

RESOLUTION

Add the OLEMISC_CANLINKBYOLE1 flag to the dwStatus member of the

OBJECTDESCRIPTOR structure.

MORE INFORMATION

OLE 1.0 clients do not support links to embedded objects. OLE 2.0

containers that support links to embedded objects should not set this

flag if the object being placed on the clipboard could result in a

link to an embedded object. Removing this flag prevents an OLE 1.0

client from attempting to make a link in this scenario.

Additional reference words: 1.00 2.00 3.50 4.00

KBCategory: kbole kbprg kbprb

KBSubcategory: LeTwoDdc


PRB: Problem with ScrollBar Control While Activated In-place

PSS ID Number: Q108942

Authored 20-Dec-1993	Last modified 21-Apr-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, versions 2.0 and 2.01

SUMMARY

It is not possible to use a ScrollBar child control inside a window that

will be used as the in-place window in a container application.

SYMPTOMS

The ScrollBar control does not generate WM_VSCROLL or WM_HSCROLL messages

to its parent window.

CAUSE

One way to understand this problem is to examine the case where you have

an OLE container application that inserts an in-place capable object into

itself using the Insert Object menu option.

When the object is created, and if the container application allows the

object to embed itself in-place in the container application, it will set

the parent of its editing window to be a window that belongs to the

container.

Therefore, a situation occurs where two applications are running; that is,

the container and the server. The server application created and owns the

window procedure for a window that the object lives in; however, the parent

of this window is a window of the container application.

Imagine now that the object's editing window (created by the server and

parented by the container) contains a ScrollBar child control. When the

user clicks the ScrollBar control by using the left mouse button, a

WM_LBUTTONDOWN message is generated that gets handled internally by

Windows's ScrollBar child control code.

This code makes a check to ensure that the message queue that has just

delivered this message is also owned by the current active application. If

they are not, the message will not be processed further and scroll bar

messages will not be sent to the ScrollBar control's parent.

This is the case with the in-place scenario described above, and the root

of the problem.

The active application is the container application but the message queue

that delivered the scroll bar message belongs to the server application.

Also note that this problem does not apply to in-place editing windows that

have scroll bars that were created using the WS_HSCROLL or WS_VSCROLL

style. The message processing for these scroll bars is slightly different

from ScrollBar child controls.

RESOLUTION

Instead of creating a child control with the "scrollbar" class, create a

new window class (for example, MYSCROLL) whose window procedure forwards

WM_VSCROLL and WM_HSCROLL messages to its parent.

Then you can create windows of this class with either WS_HSCROLL or

WS_VSCROLL. Then position these windows the same way you would position

ScrollBar controls. When you enable/disable the scroll bar, use the

SB_HORZ, SB_VERT flags in the call to EnableScrollBar.

NOTE: You must have one row of pixels of the little window's client area

visible or Windows will hide the horizontal scroll bar. This does not apply

to the vertical scroll bar; that is, you do not need to have a column of

pixels visible.

Additional reference words: 2.00 2.01

KBCategory: kbole kbprg kbprb

KBSubcategory: LeTwoApp


PRB: Property or Method Name Not Recognized on Some Machines

PSS ID Number: Q131053

Authored 02-Jun-1995	Last modified 06-Jun-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.03

SYMPTOMS

If the sLangage and iCountry fields in the [intl] section of WIN.INI are

missing or have incorrect entries, IDispatch::GetIDsOfNames fails (it

returns the DISP_E_UNKNOWNNAME error) if it is implemented using

DispGetIDsOfNames or CreateStdDispatch and a typeinfo created using an

INTERFACEDATA structure.

CAUSE

If an automation server's IDispatch is implemented using a typeinfo created

from the INTERFACEDATA structure, access of properties or methods may fail

on some computers. These computers may have missing or incorrect sLanguage

and iCountry fields in the [intl] section of WIN.INI. These fields are used

by DispGetIDsOfNames and CreateStdDispatch's IDispatch::GetIDsOfNames to

obtain locale information. These functions fail (DISP_E_UNKNOWNNAME) if the

locale information cannot be obtained.

RESOLUTION

To solve this problem, modify the fields in WIN.INI to look similar to

this:

   [intl]

   sLanguage=enu

   iCountry=1

Where:

 - enu means U.S. English.

 - iCountry specifies the country code. This number matches the country's

   international telephone code, except for Canada, which is 2. The default

   is 1.

You can also change these fields by using the International Control Panel

applet by selecting the appropriate Country and Language.

STATUS

This behavior is by design. This problem doesn't occur with typeinfos

obtained from type libraries. Microsoft strongly recommends that type

libraries be used for the implementation of IDispatch. The INTERFACEDATA

approach was a temporary solution to create typeinfos while type libraries

were in Beta.

Additional reference words: 2.0 2.00

KBCategory: kbprg kbole kbprb

KBSubcategory: LeTwoAto


PRB: Some OLE Containers Do Not Call IViewObject::Draw

PSS ID Number: Q131155

Authored 04-Jun-1995	Last modified 07-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) for Windows NT

   version 3.5

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

 - Microsoft OLE Libraries included with:

    - Microsoft Windows NT version 3.5

    - Microsoft Windows 95

SYMPTOMS

A custom OLE rendering handler finds that its IViewObject::Draw method is

never called by some OLE container applications.

CAUSE

Some OLE container applications never call IViewObject::Draw. These

applications do not use the caching and drawing services provided by the

object handler. Instead, they do their own caching and drawing of the

presentations for OLE objects embedded in their documents.

Two examples of such container applications are Microsoft Word version 6.0

and Microsoft Excel version 5.0. They cache metafile representations of

embedded OLE objects, and then do their own drawing of those metafiles.

STATUS

This behavior is by design. It is not possible to get Microsoft Word or

Microsoft Excel to use a handler's drawing services.

Additional reference words: 2.01 3.50 4.00 5.00 6.00

KBCategory: kbole kbprb

KBSubcategory: LeTwoOh


PRB: Synchronous OLE Call Fails If in Inter-task SendMessage

PSS ID Number: Q131056

Authored 02-Jun-1995	Last modified 06-Jun-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.03

 - Microsoft OLE libraries included with:

    - Microsoft Windows NT version 3.5

    - Microsoft Windows 95

SYMPTOMS

A synchronous OLE call made by the recipient of an inter-task SendMessage

fails.

CAUSE

The cause is discussed in detail in the "More Information" section of this

article.

RESOLUTION

Use PostMessage instead of an inter-task SendMessage.

STATUS

This behavior is by design.

MORE INFORMATION

See the beginning of chapter 13 in the OLE 2 Programmer's Reference Volume

1 for the categories of OLE calls. An understanding of these categories is

required for this article.

The majority of OLE calls are synchronous calls. A synchronous call to a

different process yields to that process and waits for a reply from that

process. In addition, OLE has input-synchronized calls that relate to the

inplace-activation interfaces. Input-synchronized calls are implemented

using an inter-task SendMessage.

16-bit Windows doesn't allow a task to yield while in an inter-task

SendMessage because a system deadlock could occur. The deadlock occurs

because a message for the sender could be present at the top of the

shared system queue, and this prevents other tasks, including the

recipient of the SendMessage, from retrieving their messages from the

system queue until the sender does. The sender cannot retrieve its message

because it is waiting for the inter-task SendMessage to return.

In 32-bit Windows, each process has its own system queue and this

architecture normally prevents deadlock problem from occuring. However,

when one process is inplace active in another process's window, the system

queues of the two processes are synchronized as in 16-bit windows, so the

deadlock could occur. To prevent this, OLE stops synchronous OLE calls from

being made while the caller is the recipient of an input-synchronized call.

OLE determines if the caller of the synchronous call is a recipient of

an input-synchronized call by using the InSendMessage() API. This broad

check prevents a synchronous call from being made if the caller is

currently a recipient of any inter-task SendMessage.

Additional reference words: 2.0 2.00

KBCategory: kbprg kbole kbprb

KBSubcategory: LeTwoArc


Properties with Optional Parameters Not Supported

PSS ID Number: Q131048

Authored 02-Jun-1995	Last modified 06-Jun-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.03

 - Microsoft OLE libraries included with:

    - Microsoft Windows NT version 3.5

    - Microsoft Windows 95

Properties with optional parameters are currently not supported by the

IDispatch::Invoke implementation provided by the OLE system (DispInvoke

and CreateStdDispatch). For example, the following results in an error from

MKTYPLIB.EXE:

[propput]

void MyProperty([in] BSTR bstrValue, [in, optional] VARIANT vIndex,);

[propget]

BSTR MyProperty([in, optional] VARIANT vIndex);

Properties with non-optional parameters are allowed. For example, the

following is acceptable:

[propput] void MyProperty([in] short nIndex, [in] BSTR bstrValue);

[propget] BSTR MyProperty([in] short nIndex);

Additional reference words: 2.0 2.00 3.50 4.00

KBCategory: kbprg kbole

KBSubcategory: LeTwoAto


Reference Counting Rules

PSS ID Number: Q104138

Authored 08-Sep-1993	Last modified 17-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.0

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

SUMMARY

In the component object model, an interface's lifetime is controlled

through reference counting. The reference count for an interface is

manipulated through the AddRef() and Release() member functions

inherited from IUnknown. The AddRef() member increments an interface's

reference count, and the Release() method decrements it. Once an

interface's reference count goes to zero, there are no longer any

valid pointers to that interface. If the reference count on all of an

object's interfaces is zero, then the object can be freed because

there are no longer any pointers to the object.

MORE INFORMATION

Reference Counting Rules

------------------------

The following list is a copy of the reference counting rules (taken

from pages 83 and 84 of the OLE 2.0 specification) that must be

followed. Small code samples have been added in this article to help

clarify the rules.

1. Every new copy of an interface pointer must be AddRef()'d, and

   every destruction of an interface pointer must be Release()'d

   except where subsequent rules explicitly permit otherwise.

   a. In-Out parameters to functions: The caller must AddRef() the

      actual parameter, because it will be Release()'d by the callee

      when the out-value is stored on top of it.

      LPOLEOBJECT lpObject;

         .

         .  // Get pointer to IOleObject.

         .

      LPVIEWOBJECT lpView = lpObject;

      lpObject->AddRef()

      // GetViewObject is a theoretical function that takes a

      // pointer to anything derived from IUnknown, and then

      // returns a pointer to IViewObject in the same variable

      // passed as the parameter. The AddRef() above is needed so

      // that the original pointer to IOleObject is not freed.

      GetViewObject(lpView);

   b. Fetching a global variable: The local copy of an interface

      pointer fetched from an existing copy of the pointer in a global

      variable must be independently reference counted because called

      functions might destroy the copy in the global while the local

      copy is still alive.

      void function()

      {

      // Get a pointer to IOleObject from a global variable.

      LPOLEOBJECT lpOleObject = glpObject;

      // This AddRef() is needed so that the interface

      // pointed to by the global variable, glpObject,

      // does not get released by a different part of

      // the applications code.

      lpOleObject->AddRef();

         .

         . // use lpOleObject;

         .

      lpOleObject->Release();

      }

   c. New pointers synthesized out of "thin air": A function that

      synthesizes an interface pointer using special internal

      knowledge rather than obtaining it from some other source must

      do an initial AddRef() on the newly synthesized pointer.

      Important examples of such routines include instance creation

      routines, implementations of IUnknown::QueryInterface, and so

      forth.

      STDMETHDOIMP IUnknown::QueryInteface( REFIID iidInterface,

                                         LPVOID FAR *ppvObj)

      {

      *ppvObj = NULL;

      SCODE sc = E_NOINTERFACE;

      if (iidInterface == IUnknown)

          {

          *ppvObj = this;

          // This AddRef() is needed because a new pointer

          // was just created.

          AddRef();

         sc = S_OK;

          }

      return ResultFromScode(sc);

      }

   d. Returning a copy of an internally stored pointer: Once the

      pointer has been returned, the callee has no idea how its

      lifetime relates to that of the internally stored copy of the

      pointer. Thus, the callee must AddRef() the pointer copy before

      returning to it.

      // m_lpOleObject is a private member variable of a C++ class.

      // GetOleObject is a member function to return access to this

      // pointer.

      void GetOleObject (LPVOID FAR *ppObject)

      {

          *ppObject = m_lpOleObject;

          // This AddRef() is needed due to this rule.

          m_lpOleObject->AddRef();

       }

2. Special knowledge on the part of a piece of code about the

   relationships of the beginnings and endings of the lifetimes of two

   or more copies of an interface pointer can allow AddRef()/Release()

   pairs to be omitted.

   a. In-parameters to functions: The copy of an interface pointer

      that is passed as an actual parameter to a function has a

      lifetime that is nested in that of the pointer used to

      initialize the value. Therefore, the actual parameter need not

      be separately reference counted.

      void function (LPOLEOBJECT lpOleObject)

      {

      // Can use lpOleObject in this function

      // without doing AddRef() and Release().

      }

   b. Out-parameters from functions, including return values: To set

      the out parameter, the function itself by Rule 1 must have a

      stable copy of the interface pointer. On exit, the

      responsibility for releasing the pointer is transferred from the

      callee to the caller. Thus, the out parameter need not be

      referenced counted.

      LPVIEWOBJECT lpView;

      HERROR hErr = lpOleObject->QueryInterface(IID_IViewObject,

                                                (LPVOID FAR *)lpView);

      if (hErr = NOERROR)

          {

          // The QueryInterface succeeded. lpView does not have

          // to be AddRef()'d because it has already been done

          // by the QueryInterface method.

          }

   c. Local variables: A function implementation clearly has

      omniscient knowledge of the lifetimes of each of the pointer

      variables allocated on the stack frame. It can therefore use

      this knowledge to omit redundant AddRef()/Release() pairs.

      void function()

      {

      LPOLEOBJECT lpTempObject;

         .

         .

         .

      lpTempObject = lpObject;

         .

         .  // lpTempObject can be used

         .  // without reference counting as long as

         .  // it is known that the lifetime of lpObject

         .  // outside of this function call.

         .

      }

   d. Backpointers. Some data structures are of the nature of

      containing two components, A and B, each with a pointer to the

      other. If the lifetime of one component (A) is known to contain

      the lifetime of the other (B), then the pointer from the second

      component back to the first (from B to A) need not be reference

      counted. Often, avoiding the cycle that would otherwise be

      created is important in maintaining the appropriate freeing

      behavior.

Additional reference words: 2.00 3.50 4.00

KBCategory: kbole kbprg

KBSubcategory: LeTwoCom


Returning Floats and Doubles from Automation methods

PSS ID Number: Q122286

Authored 01-Nov-1994	Last modified 21-Apr-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.02

SUMMARY

Automation properties or methods implemented with the C calling convention

in the Windows 16-bit operating system can't return type Float or Double.

This includes the Date type, which is a floating-point type. To work around

this, you can implement them using the Pascal calling convention.

MORE INFORMATION

Automation methods and properties can be marked as using one of the calling

conventions described by the CALLCONV enumeration. This calling convention

is used by the standard IDispatch implementation provided by

CreateStdDispatch and by DispInvoke to call property accessor functions or

methods. Note that the an automation controller does not directly use these

calling conventions.

Because of a C Language implementation limitation, automation properties

and methods that return Float or Double cannot use the C calling

convention. You need to use the Pascal calling convention.

For example, describe a method or automation property that returns a Float

or Double as follows in the .ODL file:

[propget] float pascal MyProperty();

float pascal MyMethod();

Additional reference words: 2.00

KBCategory: kbole kbprg

KBSubcategory: LeTwoAto


Rules for Freeing BSTRs in OLE Automation

PSS ID Number: Q108934

Authored 20-Dec-1993	Last modified 17-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

SUMMARY

The callee frees a BSTR passed in as a by-reference parameter before

assigning the parameter a new value. In all other cases, the caller frees

the BSTR.

MORE INFORMATION

OLE Automation defines the BSTR data type to handle strings that are

allocated by one component and freed by another. The rule for freeing a

BSTR is as follows:

The callee frees a BSTR passed in as a by-reference parameter before

assigning the parameter a new value. In all other cases, the caller frees

the BSTR.

In other words, the caller handles BSTRs as follows:

1. Free BSTR returned by called function or returned through a by-

   reference parameter of called function.

2. Free BSTR passed as a by-value parameter to a function.

The callee handles BSTRs as follows:

1. Free BSTR passed in as a by-reference parameter before assigning a new

   value to the parameter. Do not free if a new value is not assigned to

   the by-reference parameter.

2. Do not free BSTR passed in as a by-value parameter.

3. Do not free BSTR that has been returned to caller.

4. If a BSTR passed in by the caller is to be stored by the callee, store

   a copy using SysAllocString(). The caller will release the BSTR that it

   passed in.

5. If a stored BSTR is to be returned, return a copy of the BSTR. The

   caller will release the BSTR that is returned.

Additional reference words: 2.01 3.50 4.00

KBCategory: kbole kbprg

KBSubcategory: LeTwoAto


SAMPLE: BINARY: Transfer Binary Data Using OLE Automation

PSS ID Number: Q131046

Authored 02-Jun-1995	Last modified 20-Jun-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.03

 - Microsoft OLE libraries included with:

    - Microsoft Windows NT version 3.5

    - Microsoft Windows 95

BINARY is an OLE Automation server that you can obtain from the Microsoft

Software Library. It demonstrates how to transfer binary data using a

SAFEARRAY of unsigned char. The CTRL directory in this sample contains an

automation controller that will obtain the binary data from the server.

Binary data can be transferred with OLE Automation by using a SAFEARRAY of

unsigned char (VT_ARRAY|VT_UI1). Binary data can also be transferred by

passing the IUnknown of a data trasfer object that supports IDataObject.

This sample uses the first approach, not the second.

Standard controllers like Visual Basic cannot access binary data

transferred through automation. For more information about this, please see

the following article in the Microsoft Knowledge Base:

   ARTICLE-ID: Q122289

   TITLE     : Passing Structures in OLE Automation

See the README.TXT in the sample for details on how to compile and run the

sample. After you download BINARY.EXE, use the following command to run it:

    BINARY.EXE -d

This builds the directory structure for you.

Download BINARY.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for BINARY.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download BINARY.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get BINARY.EXE

Additional reference words: 3.50 4.00

KBCategory: kbole kbprg kbcode kbfile

KBSubcategory: LeTwoAt


SAMPLE: DECODE16: OLE Error Code Decoder Tool

PSS ID Number: Q122956

Authored 16-Nov-1994	Last modified 20-Jun-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.02

DECODE16 is a sample decoder of 16-bit OLE version 2.02 error codes. See

the DECODE32 sample for a decoder of 32-bit OLE error codes. Enter the

HRESULT in hexadecimal format, and press the Decode button.

Download DECODE16.EXE, a self-extracting file, from the Microsoft

Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for DECODE16.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download DECODE16.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get DECODE16.EXE

Download DECODE32.EXE, a self-extracting file, from the Microsoft

Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for DECODE32.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download DECODE32.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get DECODE32.EXE

Additional reference words: 2.02

KBCategory: kbole kbcode kbfile

KBSubcategory: LeTwoTls


SAMPLE: DECODE32: OLE Error Code Decoder Tool

PSS ID Number: Q122957

Authored 16-Nov-1994	Last modified 20-Jun-1995

The information in this article applies to:

 - Microsoft OLE Libraries, version 2.1, included with:

    - Microsoft Windows NT, version 3.5

DECODE32 is a sample decoder for 32-bit OLE version error codes. See

the DECODE16 sample for a decoder for 16-bit OLE error codes. In addition

to decoding the HRESULT, DECODE32 also uses FormatMessage() to provide a

description of the error. Enter the HRESULT in hexadecimal format and press

the Decode button.

Download DECODE32.EXE, a self-extracting file, from the Microsoft

Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for DECODE32.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download DECODE32.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get DECODE32.EXE

Download DECODE16.EXE, a self-extracting file, from the Microsoft

Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for DECODE16.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download DECODE16.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get DECODE16.EXE

Additional reference words: HRESULT SCODE DECODE

KBCategory: kbole kbcode kbfile

KBSubcategory: LeTwoTls


SAMPLE: DRGDRPS: OLE Drag-Drop Source

PSS ID Number: Q122955

Authored 16-Nov-1994	Last modified 20-Jun-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.02

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

OLE version 2.02 and later provide drag-drop functionality that allows data

to be dragged between and within applications. DRGDRPS is a sample that

provides an OLE drag-drop Source that allows data of format CF_TEXT to be

dragged from it.

The DRGDRPS sample implements IDataObject, IDropSource, and IEnumFormatEtc

interfaces. It calls DoDragDrop when the user clicks on its main window to

initiate a drag. It allows copying of data by dragging to a drag-drop

target.

Download DRGDRPS.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for DRGDRPS.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download DRGDRPS.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get DRGDRPS.EXE

See the DRGDRPT sample for an example of an OLE drag-drop target. Download

DRGDRPT.EXE, a self-extracting file, from the Microsoft Software Library

(MSL) on the following services:

 - CompuServe

      GO MSL

      Search for DRGDRPT.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download DRGDRPT.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get DRGDRPT.EXE

See the SIMPDND sample in the OLE2 SDK for a more complex drag-drop

example.

Additional reference words: 2.02 3.50 4.00

KBCategory: kbole kbcode kbfile

KBSubcategory: LeTwoDdc


SAMPLE: DRGDRPT: OLE Drag-Drop Target

PSS ID Number: Q122954

Authored 16-Nov-1994	Last modified 20-Jun-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.02

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

OLE version 2.0 provides drag-drop functionality that allows data to be

dragged between and within applications. DRGDRPT is a sample application

for an OLE drag-drop target that allows data of format CF_TEXT to be

dropped on it. DRGDRPT implements the IDropTarget interface. It registers

its main window as a drop target using RegisterDragDrop.

Download DRGDRPT.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for DRGDRPT.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download DRGDRPT.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get DRGDRPT.EXE

For an example of an OLE drag-drop source, see the DRGDRPS code sample.

Download DRGDRPS.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for DRGDRPS.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download DRGDRPS.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get DRGDRPS.EXE

See the SIMPDND sample in the OLE2 SDK for a more complex drag-drop

example.

Additional reference words: 2.02 3.50 4.00

KBCategory: kbole kbcode kbfile

KBSubcategory: LeTwoDdc


SAMPLE: MFCINP16: Inproc 16-bit MFC Automation Object

PSS ID Number: Q130843

Authored 30-May-1995	Last modified 20-Jun-1995

The information in this article applies to:

 - Microsoft OLE version 2.03

 - Microsoft Foundation Classes (MFC) included with

   Microsoft Visual C++ for Windows, version 1.52

SUMMARY

MFC's App Wizard will not generate an inproc OLE Automation server. This

article gives you the steps to follow to create an inproc automation server

using MFC. MFCINP16, a sample available in the Microsoft Software Library,

is a 16-bit inproc automation object that was created using the steps in

this article.

Download MFCINP16.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for MFCINP16.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download MFCINP16.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get MFCINP16.EXE

MORE INFORMATION

MFC's App Wizard doesn't generate inproc (DLL) OLE servers because it is

not possible for MFC to fully implement one that can open into a separate

window. MFC needs to hook into the client's main message retrieval loop to

translate accelerators of the separate window and to implement idle-time

processing. OLE doesn't provide such a mechansim. It is entirely possible

to implement an inproc server in MFC with no user interface or with a very

simple user interface. This article shows you how.

Steps to Create a 16-Bit Inproc Automation Object in MFC

--------------------------------------------------------

It is assumed that Visual C++ version 1.51 or greater and the Control

Development Kit have been installed.

1. Use INPROC.CPP, INPROC.H, and STDAFX.H from the sample as the starting

   point. Copy these into a new directory. The names INPROC.CPP and

   INPROC.H can be changed to something more appropriate for your project.

2. Create a new project by choosing New from the Project menu and selecting

   the Windows dynamic-link library as the type. Add INPROC.CPP to this

   project. (The sample uses inproc for the project name.)

3. From the Options menu, choose Project and select Compiler. Add the

   following in the C/C++ CompilerOptions dialog box under the

   CustomOptions category in the OtherOptions edit control:

   /D "_USRDLL"

   From the Options menu, choose Project and select Linker. Add the

   following libraries in the LinkerOptions dialog box under the Input

   category in the Libraries edit control:

   ole2, compobj, ole2disp, typelib, ole2nls, mfcoleui, storage

4. Choose ClassWizard from the Project menu. ClassWizard will complain that

   the .CLW file does not exist. It will ask you to rebuild the .CLW file

   by opening the project in App Studio and running ClassWizard.

5. Open AppStudio by choosing it from the Tools menu. Save the resource

   file, and run ClassWizard from AppStudio by choosing ClassWizard from

   the Resource menu. The CLW file will now be built after you choose OK in

   the SelectSourceFiles dialog box. Complet the following steps:

   a. Select the OLE Automation tab in the MFC ClassWizard dialog.

   b. Choose the AddClass button, and add a class of type CCmdTarget.

   c. Select the OLEAutomation check box.

   d. Select the OLECreatable check box, and provide an ExternalName

      (progID) if this is a top-level automation object. This external name

      will be used by the automation controller/client to create the

      object. (The sample creates a class called TestObject, which has an

      external name Inproc.TestObject.)

6. Add the required automation properties and methods to the newly

   created class. (The sample creates a method called TestMethod that

   returns void and has no parameters. The method calls MessageBeep.)

7. Attempt to build the project. Visual C++ will ask if you want to

   create a default .DEF file. Edit the default .DEF file to export the

   following:

   DllGetClassObject

   DllCanUnloadNow

   DllRegisterServer

8. Build the project. Register the inproc Automation object by choosing

   RegisterControl from the Tools menu.

9. VB.MAK and VB.FRM in the sample are Visual Basic version 3.0 files that

   you can use to control the object.

Additional reference words: 2.03 1.52

KBCategory: kbole kbprg kbfile

KBSubcategory: LeTwoAto


SAMPLE: MFCINP32 Inproc 32-bit MFC Automation Object

PSS ID Number: Q130842

Authored 30-May-1995	Last modified 20-Jun-1995

The information in this article applies to:

 - Microsoft OLE version 2.03

 - Microsoft Foundation Classes (MFC) included with:

   Microsoft Visual C++, 32-bit Edition, version 2.0

SUMMARY

MFC's App Wizard in Visual C++ version 2.0 will not generate an inproc OLE

Automation server. This article gives steps you can follow to create an

inproc automation server using MFC. You can also obtain a sample (MFCINP32)

from the Microsoft Software Library that is a 32-bit inproc automation

object created by following the steps in this article.

Download MFCINP32.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for MFCINP32.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download MFCINP32.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get MFCINP32.EXE

NOTE: The App Wizard in Visual C++ version 2.1 and above does generate an

inproc OLE Automation server.

MORE INFORMATION

MFC's App Wizard doesn't generate inproc (DLL) OLE servers because it is

not possible for MFC to fully implement one that can open into a separate

window. MFC needs to hook into the client's main message retrieval loop to

translate accelerators of the separate window and to implement idle-time

processing. OLE doesn't provide such a mechansim. It is entirely possible

to implement an inproc server in MFC with no user interface or with a very

simple user interface. This article provides the instructions to do this.

Steps to Create 32-Bit Inproc Automation Object in MFC

------------------------------------------------------

It is assumed that Visual C++ version 2.0 and the Control Development Kit

have been installed.

1. Use INPROC.CPP, INPROC.H, and STDAFX.H from the sample as the starting

   point. Copy these into a new directory. The names INPROC.CPP and

   INPROC.H can be changed to something more appropriate for your project.

2. Create a new project of type Dynamic-Link Library. (Do not select MFC

   AppWizard DLL.) Add INPROC.CPP to this project.

3. Create an .ODL file (INPROC.ODL) containing a modification of the

   following code, and add it to the project.

      [ uuid(ABEBE5A0-0C69-11CE-B774-00DD01103DE1), version(1.0) ]

      library inproc

      {

           importlib("stdole32.tlb");

          //{{AFX_APPEND_ODL}}

      };

   Don't use the same UUID as the one shown here. Instead generate a new

   one by running GUIDGEN.EXE, and use that value. The library name can be

   changed from inproc to a name more appropriate for your project. The

   version number can also be changed.

4. Create the .DEF file (INPROC.DEF) containing the following code, and add

   it to the project.

      LIBRARY   INPROC

      EXPORTS

                DllGetClassObject

                DllCanUnloadNow

                DllRegisterServer

   The library name can be changed from INPROC to a name more appropriate

   for your project.

5. Select Project Settings, as follows:

    - In the ProjectSettings dialog box under General, select Use MFC in a

      shared DLL.

    - In the ProjectSettings dialog box under C/C++, remove _AFXDLL, and

      add _USRDLL and _WINDLL under Preprocessor definitions.

    - In the ProjectSettings dialog under Link, add the following libraries

      to Object/Library modules:

      ole32.lib oleaut32.lib

6. Choose ClassWizard from the Project menu. ClassWizard will complain that

   the .CLW file does not exist. It will ask you to rebuild the .CLW file

   by opening the .RC file and running ClassWizard again.

7. Open your .RC file or create a new .RC file by choosing New from the

   File menu and selecting Resource Script. Save the new .RC file

   (INPROC.RC). Now bring up ClassWizard. The .CLW file will now be built

   after you choose OK in the SelectSourceFiles dialog box. Follow these

   steps:

   a. Select the OLE Automation tab in the ClassWizard dialog.

   b. Choose the AddClass button, and add a class of type CCmdTarget.

   c. Select the OLEAutomation check box.

   d. Select the OLECreatable check box, and provide an ExternalName

      (progID) if this is a top-level automation object. This external name

      is used by the automation controller/client to create the object.

      (The sample creates a class called TestObject that has an external

      name Inproc.TestObject.)

8. Add the required automation properties and methods to the newly created

   class. (The sample creates a method called TestMethod that returns void

   and has no parameters. The method calls MessageBeep.)

9. Build the project. Register the inproc Automation object by using the

   Tools/RegisterControl menu.

10. Note that a 16 bit controller like Visual Basic version 3.0 cannot

    control a 32-bit inproc automation object because 16-bit to 32-bit

    interoperability is not supported with inproc automation objects.

    Instead, write a 32-bit controller to control this 32-bit inproc

    automation object.

Additional reference words: 2.00 3.00

KBCategory: kbole kbprg kbfile kbcode

KBSubcategory: LeTwoAto


SAMPLE: Multilingual OLE Automation Object

PSS ID Number: Q107698

Authored 24-Nov-1993	Last modified 20-Jun-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.0

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

SUMMARY

MULTLING demonstrates how to create an OLE automation object that supports

multiple languages. This allows the controller of an automation object to

access properties and methods using any of the languages that are

supported.

Download MULTLING.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for MULTLING.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download MULTLING.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \softlib\mslfiles directory

      Get MULTLING.EXE

MORE INFORMATION

This multilingual OLE automation object sample checks the Locale ID (LCID)

passed methods of the IDispatch interface to determine the language being

used by the automation controller. The object supports access of properties

and methods in English, French, and German.

One Type Library Per Language

-----------------------------

The automation object registers three different type libraries in the

registration database--one for each supported language. The type libraries

have the same UUIDs but different locale attributes. Each type library is

loaded at object creation and the ITypeInfo interface is obtained from each

as follows (see LoadTypeInfo in MAIN.CPP):

   LoadRegTypeLib(LIBID_Hello, 1, 0, lcid, &ptlib);

   ptlib->GetTypeInfoOfGuid(IID_IHello, &ptinfo);

Also see ENGLISH.ODL, FRENCH.ODL, GERMAN.ODL, and HELLO.REG.

Interpret LCID in IDispatch Methods

-----------------------------------

The implementation of IDispatch::GetTypeInfo, GetIDsOfNames, and Invoke

checks the value of the lcid parameter to determine the locale ID and uses

the appropriate ITypeInfo for that language (See CHello::GetTypeInfo,

GetIDsOfNames, and Invoke in HELLO.CPP).

To Run

------

The multilingual automation object exposes one VT_BSTR property

(HelloMessage) and one method (SayHello).

ProgID                  :  HelloMultiLingual.Hello

Method and Property Names:

English         French         German          Action

-----------------------------------------------------------------------

HelloMessage    SalutMessage   HalloNachricht  Sets or gets the

                                               HelloMessage string.

SayHello        DitSalut       SagHallo        Displays the HelloMessage

                                               in an edit control.

Use the AUTOCTRL sample to control the multilingual automation object. The

AUTOCTRL automation controller allows the locale ID to be specified.

Update the path in HELLO.REG to the current location of the object and the

type libraries.

To Compile

----------

Requires OLE 2.01 or later.

Include device=vmb.386 in the [386Enh] section of SYSTEM.INI.

Note that vmb.386 can be found in \OLE2\BIN.

Run the WXSERVER.EXE from \OLE2\BIN before running the makefile.

Additional reference words: 2.00 3.50 4.00 multi-lingual softlib

MULTLING.EXE

KBCategory: kbole kbfile

KBSubcategory: LeTwoAto


SAMPLE: OLE Automation '94 Documentation and Samples

PSS ID Number: Q124385

Authored 29-Dec-1994	Last modified 20-Jun-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.02

SUMMARY

You can get a draft of the second edition of OLE 2 Programmer's Reference,

Volume 2 and the samples it contains from two files (OA94DOC.EXE and

OA94SAMP.EXE). The final version will be released in 1995. The samples

demonstrate many of the new Automation features.

IMPORTANT: After downloading OA94SAMP.EXE, run it in an empty directory

using the -d option to maintain the directory structure:

   OA94SAMP.EXE -d

Download OA94DOC.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for OA94DOC.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download OA94DOC.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get OA94DOC.EXE

Download OA94SAMP.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for OA94SAMP.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download OA94SAMP.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get OA94SAMP.EXE

MORE INFORMATION

OLE Automation '94 is the version of OLE Automation that shipped

with version 2.02 of the OLE libraries.

Contents for OA94DOC

--------------------

The OA94DOC.EXE self-extracting file contains a draft of the second edition

of OLE 2 Programmer's Reference, Volume 2. It documents the following new

features introduced in OLE Automation '94:

   VTBL binding and dual interfaces.

   Error handling mechanisms for interfaces that support vtable binding.

   New registration flags for RegisterActiveObject().

   New ODL Attributes.

   Multiple type libraries can now be stored in an executable (.EXE) file

      or DLL. These libraries can be loaded using LoadTypeLibFromResource.

   MkTypLib includes DEFINE_GUID macros in the generated header file for

      each element (interface, dispinterface, and so forth) defined in the

      type library.

   SafeArrayPtrOfIndex().

   VT_UI1 data type.

   Additions to ITypeInfo Structures and Enumerations.

   Additions to National Language Support LCTYPE constants in 16 bit.

You will fild a discussion of the new features in TECHNOTE.DOC, which

is included in OA94DOC.EXE.

Contents for OA94SAMP

---------------------

The OA94SAMP.EXE self-extracting file contains the samples referenced in

OA94DOC. The following samples are included:

   HELLO - A simple automation object that implements a dual interface.

   HELLCTRL - A simple automation controller that controls HELLO

      using vtable binding.

   LINES - A more complex automation object that implements several dual

      interfaces and two collections.

   BROWSEH - (Browse Helper) An inproc (DLL) automation object that

      exposes properties and methods that allow easy browsing of a type

      library. This sample doesn't implement dual interfaces.

   BROWSE - An automation controller that uses late-binding to control

      BROWSEH. It displays the type library information obtained from

      BROWSEH. The INVHELP.CPP file in this sample contains helper

      functions that allow easy creation of any late-binding automation

      controller.

The WIN16 directory contains 16-bit versions of the samples, and the WIN32

directory contains a version that you can compile for 16-bit or 32-bit by

changing the dev option in the makefile to compile for 16- or 32-bit and

changing the HOST option to compile a 32-bit version for Windows NT or for

Windows 95. The .REG entries for the samples in the WIN32 directory are set

up for 32-bit, so you need to change them to the 16-bit keys if you are

compiling for the 16-bit environment.

The 32-bit version of the samples for NT use Unicode.

The 32-bit version of the samples for Windows 95 use Unicode with the OLE

API and interfaces and use ANSI with the Windows 95 API. This is because

Windows 95 uses ANSI and 32-bit OLE uses Unicode, regardless of the

platform. The samples do the appropriate Unicode-to-ANSI conversions to

support this.

See the README.TXT file for each sample for more details.

Additional reference words:

KBCategory: kbole kbprg kbcode kbfile

KBSubcategory: LeTwoAto


SAMPLE: OLE Automation Collection

PSS ID Number: Q107546

Authored 23-Nov-1993	Last modified 17-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.0

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

SUMMARY

COLLECT demonstrates how to create an OLE automation collection object.

COLLECT can be found in the Software/Data Library by searching on the word

COLLECT, the Q number of this article, or S14424. COLLECT was archived

using the PKware file-compression utility.

MORE INFORMATION

The collection object implements the following methods and properties: Add

Method, Count Property, Item Property, NewEnum Property, and Remove Method.

Error handling in the collection object involves raising exceptions.

CreateStdDispatch does not allow exceptions to be raised, so the collection

object implements the IDispatch interface using DispGetIDsOfNames and

DispInvoke.

Add Method

----------

Description:     Adds the indicated item to the collection. If an object

                 is created, it should be returned.

Arguments:       Varies. It can be a pointer to the object that is to be

                 added or it can the information required to create the

                 object.

Return type:     Varies. If no object is created, the return type should

                 be void. If an object is created, the return type should

                 be VT_DISPATCH.

Note: The Add method is not appropriate for all collections, so it is not

required. For many application-created collections, objects are

automatically added to the collection for the user.

Count Property

--------------

Description:     Returns the number of items in the collection. Read-only

                 property.

Arguments:       None.

Return type:     VT_I4.

Item Property

-------------

Description:     Returns the indicated item in the collection.

Argument:        Specifies the index. Some collections allow various types

                 of indexing. For example, this sample allows an integer or

                 string to be specified as an index.

Return type:     VT_DISPATCH.

Note: Item is the default value for the object, so it should have the

special DISPID, DISPID_VALUE. MkTypLib automatically assigns this DISPID if

the default attribute is specified in the ODL file.

_NewEnum Property

-----------------

Description:     Returns an enumerator that supports IEnumVariant for the

                 items currently in the collection. Read-only property.

Arguments:       None.

Return type:     VT_UNKNOWN.

Note: NewEnum will not be accessible to users and must have the restricted

attribute in the ODL file. The NewEnum method must have a special DISPID,

DISPID_NEWENUM. The defining characteristic of a collection is the ability

for a user to iterate over the items in it. Some languages will have built-

in support for collections. The NewEnum method allows an OLE automation

controller to support "for each" iteration over a collection:

   For Each Item In Collection

   Debug.Print Item.Text

   Next Item

OLE automation controllers that support "for each" iteration will call the

NewEnum method on the collection object and then QueryInterface on the

resulting IUnknown to get the desired IEnumVariant.

Remove Method

-------------

Description:     Removes the specified item from the collection.

Argument:        Specifies the index. Some collections allow various types

                 of indexing. For example, this sample allows an integer

                 or string to be specified as an index.

Return type:     void.

Note: The object is not deleted. It is simply removed from the collection.

Remove should support the same kinds of indexing as the Item() method for

the same collection. The Remove method is not appropriate for all

collections, so it is not required. For many application-created

collections, objects are automatically removed the collection for the user.

To Run

-------

The collection sample application object exposes the following:

   ProgID :  Collection.Application

   Method and Property Names     Notes

   -----------------------------------------------------------

   [App Object]

   Collection  (read only prop)  Returns empty collection.

   New Item    (method)          Creates and returns new item.

   [Item Object]

   Text        (default prop)    Sets and returns string.

   [Collection Object]

   See above for exposed properties and methods.

Update the path in HELLO.REG to the current location of the object and the

type libraries.

To Compile

----------

Requires OLE version 2.01 or later.

Include device=vmb.386 in the [386Enh] section of SYSTEM.INI.

Note that vmb.386 can be found in \OLE2\BIN.

Run WXSERVER.EXE from \OLE2\BIN before running the makefile.

Additional reference words: 2.00 3.50 4.00 softlib COLLECT.EXE

KBCategory: kbole kbfile

KBSubcategory: LeTwoAto


SAMPLE: OLE Automation Controller Sample

PSS ID Number: Q106080

Authored 31-Oct-1993	Last modified 17-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.0

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

SUMMARY

AUTOCTRL demonstrates how to create an OLE automation controller.

AUTOCTRL can be found in the Software/Data Library by searching on the

word AUTOCTRL, the Q number of this article, or S14364. AUTOCTRL was

archived using the PKware file-compression utility.

MORE INFORMATION

This OLE automation controller sample demonstrates how to create an

OLE automation object and how to access its properties and methods.

Creating an Automation Object

-----------------------------

[CreateObject() in file AUTOCTRL.CPP.]

The user is prompted for the ProgID of the automation object to be

created. CLSIDFromProgID is used to obtain the CLSID of the object;

CoCreateInstance is used to create the object.

Accessing Properties and Methods

--------------------------------

IDispatch::GetIDsOfNames is used to obtain the ID of the property or

method to be accessed; IDispatch::Invoke is used to access the

property or method. This controller prompts the user for the locale

ID; however, many controllers such as Visual Basic use the default

system locale ID.

Setting a Property

------------------

[See SetProperty() in AUTOCTRL.CPP.]

The user is prompted for the property name, property value, property

type and locale ID. This controller supports three types: VT_BSTR,

VT_I2 and VT_R4. Setting the property requires an implicit named

parameter, which represents the new value of the property. The DISPID

of this implicit named parameter is DISPID_PROPERTYPUT.

Getting a Property

------------------

[See GetProperty() in AUTOCTRL.CPP.]

The user is prompted for the property name, property type, and locale

ID.

Invoking a Method

-----------------

[See InvokeMethod() in AUTOCTRL.CPP.]

The user is prompted for the method name and the locale ID. This

controller supports only methods without parameters.

Additional reference words: 2.00 3.50 4.00 softlib AUTOCTRL.EXE

KBCategory: kbole kbfile

KBSubcategory: LeTwoAto


SAMPLE: OLE Automation Inproc Object

PSS ID Number: Q107982

Authored 01-Dec-1993	Last modified 20-Jun-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.0

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

SUMMARY

AUTODLL demonstrates how to create a OLE automation inproc object.

Download AUTODLL.EXE, a self-extracting file, from the Microsoft

Software Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for AUTODLL.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download AUTODLL.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the SOFTLIB\MSLFILES directory

      Get AUTODLL.EXE

MORE INFORMATION

AUTODLL implements a OLE automation inproc object (DLL server) called Hello

that exposes one property, HelloMessage, and one method, SayHello. It uses

an OLE provided IDispatch implementation that is created using

CreateStdDispatch.

The AUTODLL dynamic-link library (DLL) uses the memory allocator used by

the calling task. This is required of all inproc objects. The new and

delete operators are redefined to use the calling task's memory allocator

and all memory management is done using the redefined new and delete.

The interface that AUTODLL exposes is described using an object description

language (HELLO.ODL). The mktyplib tool is used to create a type library

(HELLO.TLB) from HELLO.ODL. CreateStdDispatch is then used to implement an

IDispatch interface using the interface description in the type library.

AUTODLL exports DllGetClassObject, which is called by OLE to get the class

factory. OLE uses this classfactory to create a Hello object. Automation

controllers use the IDispatch interface exposed by the Hello object to

access its property and method. AUTODLL also exports DllCanUnloadNow.

The SIMPAUTO sample in the Software/Data library demonstrates the

implementation of an automation object with the same methods and properties

as AUTODLL, but which is an EXE. The main differences between the two

samples are in the MAIN.CPP file.

To Run

------

The Hello object exposes the following:

   ProgID : SimpleAutomationInProc.Hello

   Method & Property Names       Notes

   --------------------------------------------------------------

   HelloMessage  (prop)          Sets and returns string.

   SayHello    (method)          Displays HelloMessage in an edit

                                 control.

Update the path in HELLO.REG to the current location of the object and the

type library.

To Compile

----------

Requires OLE 2.01 or later.

Include device=vmb.386 in the [386Enh] section of SYSTEM.INI.

Note that vmb.386 can be found in \OLE2\BIN.

Run the WXSERVER.EXE from \OLE2\BIN before running the makefile.

Files

-----

MAIN.CPP    Does initialization, redefines new and delete, implements

            DllGetClassObject, DllCanUnloadNow. and contains code that

            calls CreateStdDispatch.

HELLO.CPP   Implements the HELLO object.

HELLOCF.CPP Implements the HELLO class factory.

HELLO.ODL   Object Description Language that describes the property and

            method that HELLO exposes.

HELLO.H     Defines the HELLO object and the class factory.

TLB.H       Header file created by mktyplib.

MAKEFILE    Makefile for project.

VB.MAK,

VB.FRM      Visual Basic project files to control this sample.

Additional reference words: 2.00 3.50 4.00 server softlib AUTODLL.EXE

KBCategory: kbole kbfile

KBSubcategory: LeTwoAto


SAMPLE: Ole2View 1.33 Update Available in Software Library

PSS ID Number: Q122244

Authored 01-Nov-1994	Last modified 20-Jun-1995

The information in this article applies to:

 - Microsoft Win32 Software Development Kit (SDK) version 3.5

 - Microsoft Visual C++ for Windows, version 1.5

 - Microsoft Visual C++, 32-bit Edition, version 2.0

SUMMARY

An update to the OLE2View sample application is available in the Microsoft

Software Library (MSL) as a self-extracting file named OLE2V.EXE. This file

contains both 16- and 32-bit versions of Ole2View version 1.33.

This new release of the sample application fixes several bugs (mostly of a

cosmetic nature) found in the versions of Ole2View that shipped with Visual

C++ versions 1.5 and 2.0 and with the Win32 Software Development Kit (SDK)

for Windows NT version 3.5.

Download OLE2V.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for OLE2V.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download OLE2V.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \softlib\mslfiles directory

      Get OLE2V.EXE

MORE INFORMATION

Files Included in OLE2V.EXE

---------------------------

OLE2VIEW.EXE  - Ole2View 1.33 (Win16)

DEFO2V.DLL    - IDataObject and ITypeLib interface viewers (Win16)

OLE2VW32.EXE  - Ole2View 1.33 (Win32)

DEFO2V32.DLL  - IDataObject and ITypeLib interface viewers (Win32)

OLE2VIEW.HLP  - Helpfile

Version 1.33 Changes

--------------------

- The 32-bit version was made 100% compatible with Windows 95 in terms of

  using the right colors, and so on.

- A Bug that appears in the Japanese version of Windows (display of

  spurious characters) was fixed.

- DEFO2V32.DLL was changed to include only the ANSI versions of the

  interface viewers. Now DispplayIDataObjectA, DispplayIDispatchA,

  DispplayITypeInfoA, and DispplayITypeLibA are gone. DispplayIDataObject,

  DispplayIDispatch, DispplayITypeInfo, and DispplayITypeLib are now ANSI;

  they used to be Unicode. This change was made to simplify debugging

  DEFO2V and because the Unicode versions were never called.

Please report bugs to Microsoft and make suggestions by sending electronic

mail to this alias:

   ole2view@microsoft.com

Additional reference words: 2.00 1.50 visualc 3.50 softlib

KBCategory: kbother kbprg kbfile

KBSubcategory: letwomisc


SAMPLE: SAFEARAY: Use of Safe Arrays in Automation

PSS ID Number: Q131086

Authored 02-Jun-1995	Last modified 20-Jun-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.03

 - Microsoft OLE libraries included with:

    - Microsoft Windows NT versions 3.5 and 3.51

    - Microsoft Windows 95

SUMMARY

SAFEARAY is an OLE Automation server application that demonstrates the

use of safe arrays.

Download SAFEARAY.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services.

 - CompuServe

      GO MSL

      Search for SAFEARAY.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download SAFEARAY.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get SAFEARAY.EXE

MORE INFORMATION

SAFEARAY implements the following methods (in addition to the standard

application object methods).

SlowSort: Sorts an input safearray of BSTRs and returns the sorted array

and the time required for the sort. The array is passed by reference

because it needs to be modified by the sort. SlowSort uses

SafeArrayGetElement and SafeArrayPutElement to access the array

elements.

FastSort: Has the same functionality as SlowSort but uses

SafeArrayAccessData to get a pointer to the array elements. This allows

array elements to be accessed directly instead of using

SafeArrayGetElement and SafeArrayPutElement. This accounts for the speed

improvement over SlowSort.

Average: Finds the average of an input safe array of integers. The array

is not passed by reference.

GetArray: Creates and returns a safe array of BSTRs.

See the README.TXT included for instructions to compile and run this

sample.

Additional reference words: 3.50 4.00

KBCategory: kbprg kbfile

KBSubcategory: LeTwoAt


SAMPLE: Simple OLE 2.0 Container

PSS ID Number: Q99464

Authored 30-May-1993	Last modified 20-Jun-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.0

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

There is a sample application called SIMPLE in the Software/Data

Library that demonstrates how to implement an OLE version 2.0

container application. SIMPLE is intended to be the simplest OLE 2.0

container that is capable of visual editing. SIMPLE demonstrates the

use of the OLE 2.0 libraries from a C++ application.

Download SIMPLE.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for SIMPLE.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download SIMPLE.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \softlib\mslfiles directory

      Get SIMPLE.EXE

Additional reference words: 2.00 3.50 4.00

KBCategory: kbole kbfile

KBSubcategory: LeTwoInp


SAMPLE: Simple OLE Automation Object Sample

PSS ID Number: Q107981

Authored 01-Dec-1993	Last modified 20-Jun-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.0

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

SUMMARY

SIMPAUTO demonstrates how to create a simple OLE automation object.

Download SIMPAUTO.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for SIMPAUTO.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download SIMPAUTO.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \softlib\mslfiles directory

      Get SIMPAUTO.EXE

MORE INFORMATION

SIMPAUTO implements a simple OLE automation object called Hello that

exposes one property, HelloMessage, and one method, SayHello. It uses an

OLE-provided IDispatch implementation that is created using

CreateStdDispatch.

The interface that SIMPAUTO exposes is described using an object

description language (HELLO.ODL). The mktyplib tool is used to create a

type library (HELLO.TLB) from HELLO.ODL. CreateStdDispatch() is then used

to implement an IDispatch interface using the interface description in the

type library.

SIMPAUTO registers a class factory if it is started with the -Automation

command-line switch. OLE uses this classfactory to create a Hello object.

Automation controllers uses the IDispatch interface exposed by the Hello

object to access its property and method.

The AUTODLL sample in the Software Library demonstrates the

implementation of an inproc automation object with the same methods and

properties as SIMPAUTO, but which is a DLL. The main differences between

the two samples are in the MAIN.CPP file.

To Run

------

The Hello object exposes the following:

   ProgID : SimpleAutomation.Hello

   Method and Property Names       Notes

   --------------------------------------------------------------

   HelloMessage  (prop)          Sets and returns string.

   SayHello    (method)          Displays HelloMessage in an edit

                                 control.

Update the HELLO.REG file in two places to include the full path

information to the HELLOEXE and the HELLO.TLB files. Change the lines from

the following:

   LocalServer = hello.exe -Automation

   win16 = hello.tlb

to something similar to the following:

   LocalServer = c:\source\simpauto\hello.exe -Automation

   win16 = c:\source\simpauto\hello.tlb

To Compile

----------

Requires OLE 2.01 or later.

Include device=vmb.386 in the [386Enh] section of SYSTEM.INI. Note that

vmb.386 can be found in \OLE2\BIN. Run the WXSRVER.EXE from \OLE2\BIN

before running the makefile.

Files

-----

MAIN.CPP    Does initialization, creates main window, contains message

            retriever, and contains code that calls CreateStdDispatch.

HELLO.CPP   Implements the HELLO object.

HELLOCF.CPP Implements the HELLO class factory.

HELLO.ODL   Object description Language that describes the property and

            method that HELLO exposes.

HELLO.H     Defines the HELLO object and the class factory.

TLB.H       Header file created by mktyplib.

MAKEFILE    Makefile for project.

VB.MAK,

VB.FRM      Visual Basic project files to control this sample.

Additional reference words: 2.00 3.50 4.00 softlib SIMPAUTO.EXE

KBCategory: kbole kbfile

KBSubcategory: LeTwoAto


SAMPLE: TYPEBLD: How to Use ICreateTypeLib & ICreateTypeInfo

PSS ID Number: Q131105

Authored 04-Jun-1995	Last modified 20-Jun-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.03

 - Microsoft OLE libraries included with:

    - Microsoft Windows NT version 3.5

    - Microsoft Windows 95

SUMMARY

The TYPEBLD sample demonstrates how to create an OLE Automation type

library using the ICreateTypeLib and ICreateTypeInfo interfaces.

Download TYPEBLD.EXE, a self-extracting file, from the Microsoft Software

Library (MSL) on the following services:

 - CompuServe

      GO MSL

      Search for TYPEBLD.EXE

      Display results and download

 - Microsoft Download Service (MSDL)

      Dial (206) 936-6735 to connect to MSDL

      Download TYPEBLD.EXE

 - Internet (anonymous FTP)

      ftp ftp.microsoft.com

      Change to the \SOFTLIB\MSLFILES directory

      Get TYPEBLD.EXE

See the README.TXT file included in the sample for instructions on to

compile and run this sample.

MORE INFORMATION

The type library that is created is called HELLO.TLB and corresponds to one

that would have been built by MKTYPLIB.EXE if it had compiled the following

.ODL file.

Sample .ODL File

----------------

[

  uuid(2F6CA420-C641-101A-B826-00DD01103DE1),            // LIBID_Hello

  helpstring("Hello 1.0 Type Library"),

  lcid(0x0409),

  version(1.0)

]

library Hello

{

#ifdef WIN32

    importlib("stdole32.tlb");

#else

    importlib("stdole.tlb");

#endif

    [

      uuid(2F6CA422-C641-101A-B826-00DD01103DE1),        // IID_IHello

      helpstring("Hello Interface")

    ]

    interface IHello : IUnknown

    {

        [propput] void HelloMessage([in] BSTR Message);

        [propget] BSTR HelloMessage(void);

        void SayHello(void);

    }

    [

      uuid(2F6CA423-C641-101A-B826-00DD01103DE1),        // IID_DHello

      helpstring("Hello Dispinterface")

    ]

    dispinterface DHello

    {

      interface IHello;

    }

    [

       uuid(2F6CA421-C641-101A-B826-00DD01103DE1),       // CLSID_Hello

       helpstring("Hello Class")

    ]

    coclass Hello

    {

        dispinterface DHello;

        interface IHello;

    }

}

Additional reference words: 3.50 4.00

KBCategory: kbole kbfile kbcode

KBSubcategory: LeTwoAt


SIMPSVR Implements IDataObject::GetData Incorrectly

PSS ID Number: Q114599

Authored 08-May-1994	Last modified 16-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.01

The simple server sample application (SIMPSVR.EXE) included with the OLE

2.01 SDK incorrectly implements the IDataObject::GetData() method. The code

checks the cfFormat member of the FORMATEC structure to see if the format

is CF_BITMAP. If so, the code continues, filling out the STGMEDIUM with a

METAFILEPICT. The code should be comparing the cfFormat with

CF_METAFILEPICT.

The sample code continues to work correctly because the STGMEDIUM structure

is filled out appropriately for CF_METAFILEPICT. The default handler puts

the information into the cache based on the value that is returned, rather

than on the value that is requested.

The sample code included with Visual C++ for Windows version 1.5x has been

corrected. It now compares against CF_METAFILEPICT.

Additional reference words: 2.01

KBCategory: kbole kbprg

KBSubcategory: LeTwoSvr


Sizing OLE 2.0 Objects and OLEMISC_RECOMPOSEONRESIZE

PSS ID Number: Q114014

Authored 21-Apr-1994	Last modified 17-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, versions 2.0 and 2.01

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

SUMMARY

Some server applications want to have their presentation displayed

differently based on the size of the object in the container application.

For example, if version 6.0 of Microsoft Word For Windows is used as a

server application, Word for Windows will rewrap the text of an object

based on the object size in the container. This is accomplished in a server

application by setting the OLEMISC_RECOMPOSEONRESIZE bit in the MiscStatus

bits.

However, for setting the OLEMISC_RECOMPOSEONRESIZE bit to work, the

container application must properly implement its sizing code by honoring

the OLEMISC_RECOMPOSEONRESIZE bit returned by IOleObject::GetMiscStatus().

MORE INFORMATION

To properly honor the OLEMISC_RECOMPOSEONRESIZE bit, the container needs to

check the MiscStatus bits by calling IOleObject::GetMiscStatus(). Once the

status bits are retrieved, the container can then check to see if the

OLEMISC_RECOMPOSEONRESIZE bit is set. If the bit is set, then the server

wishes to be notified every time the object size changes in the container.

To inform the server application the object has been resized, the container

needs to call IOleObject::SetExtent() to set the new size of the object.

However, IOleObject::SetExtent() only works while the object is in the

running state. The container application should check if the object is

already in a running state by calling the OleIsRunning() function. This is

important because the container needs to restore the state of the object

once the operation is complete. If the object was not in the running state,

OleRun() needs to be called such that the IOleObject::SetExtent() call

takes effect. At this point the IOleObject::SetExtent() method call can be

made, and should be followed with a call to IOleObject::Update() to update

the presentation of the object in the container. Finally, if this section

of code ran the server, then it needs to transition the server back to the

loaded state by calling IOleObject::Close().

NOTE: Some container applications may want to come up with a more elaborate

scheme for keeping servers running. Starting and stopping servers is an

expensive process, so the container application might come up with a way to

keep the last X (X being application specific) servers held in the running

state.

The following code is a simple implementation for the container:

// Pass this function a pointer to the object's IOleObject interface,

// the Aspect that has changed size, and the new size of the object.

// returns TRUE if the object had the Recompose on Resize bit set.

BOOL fChkResize(LPOLEOBJECT lpObject, DWASPECT dwAspect, LPSIZEL lpsizel)

{

    DWORD dwStatus = 0; // For the status bits

    BOOL fShutdown = FALSE;  // don't shut the object down

    BOOL retval = FALSE;

    // Get the status bits.

    lpObject->GetMiscStatus(DVASPECT_CONTENT, &dwStatus);

    // is recompose on resize set?

    if ( dwStatus & OLEMISC_RECOMPOSEONRESIZE )

        {

        retval = TRUE;  // the bit was set

        // if the object isn't running, start the object and remember.

        if (!OleIsRunning(lpObject)

            {

            OleRun(lpObject);

            fShutdown = TRUE;

            }

        // set the extent

        lpObject->SetExtent(dwAspect, lpsizel);

        // update the cache

        lpObject->Update();

        // go back to the loaded state only if the object was in the

        // loaded state upon entry to this function.

        if (fShutdown)

            lpObject->Close(OLECLOSE_SAVEIFDIRTY);

        }

    return retval;

}

Additional reference words: 2.00 2.01 3.50 4.00

KBCategory: kbole kbprg

KBSubcategory: LeTwoPrs


Summary List of OLE Bugs

PSS ID Number: Q112036

Authored 28-Feb-1994	Last modified 21-Apr-1995

The information in this article applies to:

 - Microsoft OLE version 1.0

 - Microsoft OLE Libraries for Windows and Win32s, versions 2.0 and 2.01

SUMMARY

The information in this article is a summary of individual articles

contained in the Microsoft Knowledge Base (as of 4/21/95). These articles

can be found by querying on the article's ID number or on words in the

title and text. The Microsoft Knowledge Base can be accessed on CompuServe

(go mdkb) and on the Internet (through ftp.microsoft.com or

www.microsoft.com).

BUG LISTING

 - BUG: OleCreateLinkFromFile Fails on CD-ROM-Based File

 - BUG: DIB Can Be Returned Only on TYMED_HGLOBAL

 - BUG: SR2TEST GP Faults During Object Shutdown

 - BUG: (I)CntrOutl Does Not Set Target Device Information

 - BUG: Accelerator Causes Crash in ISvrOutl Embedded in C12Test

 - BUG: Insert Object from Zero Length File Causes GP Fault

 - BUG: Set Line Height on ISvrOutl Object Causes GPF in Cl2Test

 - BUG: Deleting an Open Packager Ojbect Causes GP Fault

 - BUG: Cannot Paste Link SR2TEST Object in OLE 1.0 Client

 - BUG: SR2TEST Won't Close After Editing Link Object

 - BUG: Paste Link Disabled Across the Network

 - BUG: Object Packager GPFs w/Paths Greater Than 64 Characters

 - BUG: Status Bar Not Redrawn With SR2TEST When In-Place

 - BUG: Cursor Does Not Update with Sr2Test and ICntOutl

 - BUG: OleCreate and IOleCache::Cache Fail with Multiple TYMEDs

 - BUG: IROT::IsRunning() Returns S_FALSE for OLE 1.0 Servers

 - BUG: Retaining Clipboard IDataObject Causes Unexpected Result

 - BUG: SR2TEST Menu Items Enabled Incorrectly

 - BUG: OLE 2.0 Containers & 1.0 Objects that Close w/out Saving

 - BUG: CL2TEST Fails to Parse Filenames with Extended Characters

 - BUG: Insertion of Large .WAV Object Fails

 - BUG: OLE 2.01 Does Not Support CF_OWNERDISPLAY

 - BUG: IOleCache::Cache Returns Incorrect Error Value

 - BUG: OLERENDER_ASIS Results in Blank Embedded Object

 - BUG: Invisible MSDRAW Object Retains Keyboard Focus

 - BUG: Iconic OLE Object Prints as Black Rectangle on PostScript

 - BUG: First Entry in Paste Special Dialog Is Blank

 - BUG: IEnumUnknown Is Not Remoted

 - BUG: SVROUTL Link Not Displayed Correctly in CNTROUTL

 - PRB: Embedded Object's Size Changes When it Is Run

 - BUG: Embedded Object's Size Changes When it is Run

 - BUG: SVROUTL Link Not Displayed Correctly in CNTROUTL

 - BUG: CL2TEST Does Not Display Prompt String from GetCurFile()

 - BUG: CL2TEST Handles Icon Aspect Incorrectly

 - BUG: CL2TEST Not Properly Activating Links to Embedded Objects

 - BUG: IOleObject::Close(OLECLOSE_NOSAVE) and DoVerb()

 - BUG: OLE 1.0 Server Launched for Paste Link

 - BUG: OLE 2.0 Compatibility Layer Uses Document IDataObject

 - BUG: CreateFromTemplate of OLE 2 Object into OLE 1 Container

 - BUG: IROT::Register() and IOL::SetDisplayName() Inconsistency

 - BUG: OLE Type Emulation for Previously Loaded Objects

 - BUG: Relative Monikers and OLE 1.0 Link Objects

 - BUG: OleConvertStorageToOLESTREAM() Fails When CLSID Is NULL

 - BUG: Paste-Linking a 256-Color Paintbrush Object

 - PRB: IOleObject::IsUpToDate() and OLE 1.0 Link Objects

 - BUG: IOleCache::Cache(), ADVF_DATAONSTOP, and OLE 1.0 Objects

 - BUG: IOleObject::IsUpToDate Returns Wrong Value for Manual Link

 - BUG: Borland WINSIGHT Causes GP Faults w/Some OLE Sample Apps

 - BUG: Windows OLE DLLs Do Not Convert Mac OLESTREAM

 - BUG: Printing Does Not Work from CL2TEST.EXE

-----------------------------------------------------

BUG: OleCreateLinkFromFile Fails on CD-ROM-Based File

-----------------------------------------------------

Article ID: Q86408

In an OLE client application, the

OleCreateLinkFromFile function returns the value OLE_ERROR_DRIVE.

----------------------------------------------

BUG: DIB Can Be Returned Only on TYMED_HGLOBAL

----------------------------------------------

Article ID: Q98679

IDataObject::GetData returns DV_E_FORMATETC when requesting a

device-independent bitmap (DIB) from an OLE object.

---------------------------------------------

BUG: SR2TEST GP Faults During Object Shutdown

---------------------------------------------

Article ID: Q104141

A general protection (GP) fault occurs when calling IOleObject::Close()

on an SR2TEST object.

-------------------------------------------------------

BUG: (I)CntrOutl Does Not Set Target Device Information

-------------------------------------------------------

Article ID: Q108310

During the print process from (I)CntrOutl, a server application is asked to

render its display with the TARGETDEVICE structure set to NULL instead of

containing a valid structure. This implies that (I)CntrOutl wants a screen

representation rather than a printed representation of the object.

-------------------------------------------------------------

BUG: Accelerator Causes Crash in ISvrOutl Embedded in C12Test

-------------------------------------------------------------

Article ID: Q108311

After embedding an ISvrOutl object in Cl2Test, pressing the ALT+BACKSPACE

accelerator (Undo) results in a general protection (GP) fault within

ISvrOutl.

--------------------------------------------------------

BUG: Insert Object from Zero Length File Causes GP Fault

--------------------------------------------------------

Article ID: Q108371

Creating an object from a zero length file that does not have a valid file

class extension results in a general protection (GP) fault after displaying

the message, "Not enough memory to perform this operation. Close one or

more applications and try again."

-------------------------------------------------------------

BUG: Set Line Height on ISvrOutl Object Causes GPF in Cl2Test

-------------------------------------------------------------

Article ID: Q108930

In certain circumstances, editing the Line Height of an ISvrOutl object

embedded within Cl2Test results in a general protection (GP) fault after

displaying the following message:

   GDI - An error has occurred in your application. If you choose Ignore,

   you should save your work in a new file. If you choose Close, your

   application will terminate.

-----------------------------------------------------

BUG: Deleting an Open Packager Ojbect Causes GP Fault

-----------------------------------------------------

Article ID: Q108931

Deleting an object from within the Object Packager results in a general

protection (GP) fault.

-------------------------------------------------------

BUG: Cannot Paste Link SR2TEST Object in OLE 1.0 Client

-------------------------------------------------------

Article ID: Q108932

The Paste Link option is not available in an OLE 1.0 client application

after copying an unsaved SR2TEST object to the clipboard.

--------------------------------------------------

BUG: SR2TEST Won't Close After Editing Link Object

--------------------------------------------------

Article ID: Q108935

After editing a linked SR2TEST object from CL2TEST, SR2TEST fails to shut

down after first displaying the following message box:

   Error Document not unlocked. Attempt Self-unlocking?

-------------------------------------------

BUG: Paste Link Disabled Across the Network

-------------------------------------------

Article ID: Q108939

The OleQueryLinkFromData application programming interface (API) function

returns failure when clipbook data from another machine is copied to the

local clipboard, even if the clipbook contains all of the data needed to

create a link.

------------------------------------------------------------

BUG: Object Packager GPFs w/Paths Greater Than 64 Characters

------------------------------------------------------------

Article ID: Q109116

Packaging an object that has a fully qualified path of more than 64 letters

results in a general protection (GP) fault in the Object Packager.

------------------------------------------------------

BUG: Status Bar Not Redrawn With SR2TEST When In-Place

------------------------------------------------------

Article ID: Q109541

After inserting an SR2TEST object into the in-place version of the OUTLINE

sample application, the status bar will not be redrawn until the container

application's window is resized.

-----------------------------------------------------

BUG: Cursor Does Not Update with Sr2Test and ICntOutl

-----------------------------------------------------

Article ID: Q109542

After inserting an Sr2Test object within the in-place Outline sample

application, cursor display is not handled correctly when the cursor is

positioned over the in-place object.

-------------------------------------------------------------

BUG: OleCreate and IOleCache::Cache Fail with Multiple TYMEDs

-------------------------------------------------------------

Article ID: Q109543

The OLE 2.01 creation functions [OleCreate(), OleCreateFromData(), and so

forth] and IOleCache::Cache() fail if multiple values are specified for the

TYMED field of the FORMATETC parameter. The functions fail even if the

object server supports at least one of the TYMED values specified.

----------------------------------------------------------

BUG: IROT::IsRunning() Returns S_FALSE for OLE 1.0 Servers

----------------------------------------------------------

Article ID: Q109544

When an OLE 2.01 container application calls

IRunningObjectTable::IsRunning() on the moniker for a linked OLE 1.0

object, IsRunning() returns S_FALSE even if that OLE 1.0 object is already

running.

-------------------------------------------------------------

BUG: Retaining Clipboard IDataObject Causes Unexpected Result

-------------------------------------------------------------

Article ID: Q109545

An application holding on to a clipboard IDataObject pointer, and making

repeated calls to IDataObject::EnumFormatEtc() through that pointer, may

find that the set of formats returned by EnumFormatEtc() changes between

calls.

-------------------------------------------

BUG: SR2TEST Menu Items Enabled Incorrectly

-------------------------------------------

Article ID: Q109546

During an in-place activation session, SR2TEST sometimes incorrectly

enables menu items on its Edit menu.

-------------------------------------------------------------

BUG: OLE 2.0 Containers & 1.0 Objects that Close w/out Saving

-------------------------------------------------------------

Article ID: Q109547

When an OLE 1.0 object is inserted into an OLE 2.0 container document and

then closed without an update being invoked, the correct streams for that

object are not written to storage. Any subsequent attempt by the container

to load the object will fail.

--------------------------------------------------------------

BUG: CL2TEST Fails to Parse Filenames with Extended Characters

--------------------------------------------------------------

Article ID: Q109548

When attempting to insert a new embedded object from a file, CL2TEST fails

with the error STG_E_FILENOTFOUND if the filename or directory name

provided contains an extended character.

-----------------------------------------

BUG: Insertion of Large .WAV Object Fails

-----------------------------------------

Article ID: Q109549

In some cases, inserting a large .WAV file object into either an OLE 1.0 or

OLE 2.0 container will fail.

----------------------------------------------

BUG: OLE 2.01 Does Not Support CF_OWNERDISPLAY

----------------------------------------------

Article ID: Q109552

If an application places a data transfer object onto the clipboard and that

data object enumerates CF_OWNERDISPLAY as one of the clipboard formats, the

application will not receive the WM_PAINTCLIPBOARD message.

---------------------------------------------------

BUG: IOleCache::Cache Returns Incorrect Error Value

---------------------------------------------------

Article ID: Q110488

An OLE 2.0 container application calls IOleCache::Cache for a particular

FORMATETC and is returned the value OLE_S_FORMATETC_NOTSUPPORTED. A

subsequent call to IOleCache::Cache with the same FORMATETC returns

CACHE_S_SAMECACHE.

----------------------------------------------------

BUG: OLERENDER_ASIS Results in Blank Embedded Object

----------------------------------------------------

Article ID: Q110714

If an OLE 1.0 client application contains an embedded object and copies the

object to the clipboard and an OLE 2.0 container application then performs

a paste operation by creating a new embedded object based on the clipboard

data by calling OleGetClipboard() and then calling OleCreateFromData(), the

resulting embedded object appears blank in the container's document if the

OLE 2.0 container specifies OLERENDER_ASIS as the renderOpt parameter to

OleCreateFromData().

---------------------------------------------------

BUG: Invisible MSDRAW Object Retains Keyboard Focus

---------------------------------------------------

Article ID: Q110715

When an invisible MSDRAW object is inserted as an OLE embedded object,

the object retains the keyboard focus. This behaviour is incorrect. The

MSDRAW object should not take the focus until it has been made visible.

This problem occurs whether the MSDRAW object is inserted into an

OLE 1.0 client application or into an OLE 2.0 container application.

--------------------------------------------------------------

BUG: Iconic OLE Object Prints as Black Rectangle on PostScript

--------------------------------------------------------------

Article ID: Q110796

Calling OleDraw() or IViewObject::Draw() to print an iconic OLE object to a

PostScript printer results in a black rectangle being drawn.

-------------------------------------------------

BUG: First Entry in Paste Special Dialog Is Blank

-------------------------------------------------

Article ID: Q110798

The first format entry in the Paste Special dialog box is blank after

copying an OLE2Link object from an OLE 1.0 client to the clipboard.

NOTE: An OLE2Link object is created by the OLE 1.0 compatibility layer when

an OLE 2.0 link is copied from an OLE 2.0 application to the clipboard, and

then pasted into an OLE 1.0 client application.

--------------------------------

BUG: IEnumUnknown Is Not Remoted

--------------------------------

Article ID: Q110799

All calls to IOleContainer::EnumObjects() fail.

-----------------------------------------------------

BUG: SVROUTL Link Not Displayed Correctly in CNTROUTL

-----------------------------------------------------

Article ID: Q110871

Selecting the Paste Link menu item in the CNTROUTL sample application does

not correctly display the contents of the link if the source application is

the SVROUTL sample application.

This problem occurs only if the information created in SVROUTL is edited

further after the Edit Copy operation in SVROUTL, but before the Paste Link

operation in CNTROUTL. In this situation, the resulting link object is

displayed as originally copied to the clipboard, and does not reflect the

changes made after the copy operation.

--------------------------------------------------

PRB: Embedded Object's Size Changes When it Is Run

--------------------------------------------------

Article ID: Q110872

A non-running embedded object is resized in an OLE 2.01 container

application. The next time the object is run, it snaps back to its previous

size.

--------------------------------------------------

BUG: Embedded Object's Size Changes When it is Run

--------------------------------------------------

Article ID: Q111004

A non-running embedded object is resized in an OLE 2.01 container

application. The next time the object is run, it snaps back to its previous

size.

-----------------------------------------------------

BUG: SVROUTL Link Not Displayed Correctly in CNTROUTL

-----------------------------------------------------

Article ID: Q111006

Selecting the Paste Link menu choice in the CNTROUTL sample application

does not correctly display the contents of the link if the source

application is the SVROUTL sample application.

This problem occurs only if the information created in SVROUTL is edited

further after the Edit Copy operation in SVROUTL, but before

the Paste Link operation in CNTROUTL. In this situation, the resulting

link object is displayed as originally copied to the clipboard, and does

not reflect the changes made after the copy operation.

-------------------------------------------------------------

BUG: CL2TEST Does Not Display Prompt String from GetCurFile()

-------------------------------------------------------------

Article ID: Q111014

IPersistFile::GetCurFile() returns S_FALSE to indicate that the document

has no currently associated file. In this case, GetCurFile() returns the

default prompt string for the filename (as would be displayed in the Save

As dialog box under the File menu) in the lplpszFileName parameter.

When CL2TEST calls IPersistFile::GetCurFile(), and GetCurFile() returns

S_FALSE, CL2TEST fails to display the returned prompt string.

--------------------------------------------

BUG: CL2TEST Handles Icon Aspect Incorrectly

--------------------------------------------

Article ID: Q111339

Selecting the iconic aspect when inserting an object in CL2TEST results in

the object being created and displayed with the content aspect.

--------------------------------------------------------------

BUG: CL2TEST Not Properly Activating Links to Embedded Objects

--------------------------------------------------------------

Article ID: Q111340

Double-clicking a link to an embedded object in CL2TEST results in the

activation remaining on CL2TEST. The correct action would be for the

container of the embedded object to obtain the activation and edit the

object visually (if possible).

----------------------------------------------------

BUG: IOleObject::Close(OLECLOSE_NOSAVE) and DoVerb()

----------------------------------------------------

Article ID: Q111577

An OLE 2.0 container application inserts a new embedded object into a

document. The container calls IOleObject::Update() on the object to update

the cache, then calls IOleObject::Close(OLECLOSE_NOSAVE) to transition the

object back to the running state. Finally, the container tries to rerun the

object by calling IOleObject::DoVerb().

In this particular scenario, DoVerb() will return STG_E_FILENOTFOUND, and

the object will not be rerun.

-------------------------------------------

BUG: OLE 1.0 Server Launched for Paste Link

-------------------------------------------

Article ID: Q111578

An OLE 1.0 server application copies an object to the clipboard, then

enters the blocked state. An OLE 2.0 container application then attempts to

paste a link to the object from the clipboard. The OLE 2.0 application is

frozen.

Next, the OLE 1.0 application is shut down. This unfreezes the OLE 2.0

container application, which proceeds to paste the link to the OLE 1.0

object. However, an instance of the OLE 1.0 server is launched. Normally,

the server is not run in a paste-link scenario.

----------------------------------------------------------

BUG: OLE 2.0 Compatibility Layer Uses Document IDataObject

----------------------------------------------------------

Article ID: Q111585

Whenever the OLE 1.0 client compatibility layer uses IDataObject, it uses

the OLE 2.0 server's document-level data object rather than the server's

pseudo-object data object.

------------------------------------------------------------

BUG: CreateFromTemplate of OLE 2 Object into OLE 1 Container

------------------------------------------------------------

Article ID: Q111595

An OLE 2.01 object is inserted into an OLE 1.0 container using

OleCreateFromTemplate(). The OLE libraries start the server, but then the

object creation fails, or a blank object is created.

-------------------------------------------------------------

BUG: IROT::Register() and IOL::SetDisplayName() Inconsistency

-------------------------------------------------------------

Article ID: Q111607

IRunningObjectTable::Register() allows monikers that are not valid

filenames to be registered as file monikers. However, if the display name

string passed to IOleLink::SetSourceDisplayName() is not a valid filename,

SetSourceDisplayName() returns STG_E_FILENOTFOUND.

-----------------------------------------------------

BUG: OLE Type Emulation for Previously Loaded Objects

-----------------------------------------------------

Article ID: Q111608

OLE type emulation is the process that allows the application user to

specify that all objects of some particular type are henceforth to be

activated as objects of some alternate, emulating type. When objects of the

original type are subsequently run, the server for the emulating type is

launched to serve them.

However, this emulation does not occur for objects of the original type

that were already in the loaded state when the type emulation occurred.

When such objects are subsequently run, they are run as the original type,

not the emulating type. The original server is launched, not the server for

the emulating type.

-----------------------------------------------

BUG: Relative Monikers and OLE 1.0 Link Objects

-----------------------------------------------

Article ID: Q111609

When a link object from an OLE 2.0 application is copied to the clipboard

and then pasted into an OLE 1.0 application, the OLE 2.0 emulation layer

preserves the object's relative moniker. If the OLE 1.0 application

document is closed and then reopened by an OLE 2.0 version of the

application, OLE 2.0 will create a full moniker for the linked object by

appending the preserved relative moniker to the file moniker for the

document. This full moniker will be incorrect, because it will point to the

new document rather than to the first OLE 2.0 application's document that

contains the original linked object.

However, OLE 2.0 will still be able to bind to the linked object by

following the absolute moniker that is also stored with the object

(providing that the absolute location of the original linked object has not

changed). At the time of this binding, OLE will then correct the full

moniker for the object.

------------------------------------------------------------

BUG: OleConvertStorageToOLESTREAM() Fails When CLSID Is NULL

------------------------------------------------------------

Article ID: Q111611

The OleConvertStorageToOLESTREAM() API (application programming interface)

call is used to convert the storage of an embedded object from the OLE 2.0

storage model to the OLE 1.0 storage model. However, if the OLE 2.0 object

has a CLSID of NULL, then OleConvertStorageToOLESTREAM() fails with a

return code of OLE_E_CLASS.

------------------------------------------------

BUG: Paste-Linking a 256-Color Paintbrush Object

------------------------------------------------

Article ID: Q111612

A 256-color bitmap is loaded into Microsoft Paintbrush version 3.11. The

image is selected and then copied to the clipboard. An OLE 2.0 application

then pastes a link to the object from the clipboard. To perform the paste-

link operation, the container calls OleCreateLinkFromData(), specifying

OLERENDER_FORMAT as the rendering option and CF_DIB as the desired format.

The resulting link object in the OLE 2.0 application has an incorrect

appearance, such as being colored solid black.

------------------------------------------------------

PRB: IOleObject::IsUpToDate() and OLE 1.0 Link Objects

------------------------------------------------------

Article ID: Q111613

An OLE 2.0 container application calls IOleObject::IsUpToDate to determine

whether or not an OLE 1.0 link object is up to date. IsUpToDate() returns

S_FALSE, even though the object is actually up to date.

-------------------------------------------------------------

BUG: IOleCache::Cache(), ADVF_DATAONSTOP, and OLE 1.0 Objects

-------------------------------------------------------------

Article ID: Q111614

An OLE 2.0 container application document contains an embedded OLE 1.0

object. The container calls IOleCache::Cache() to control the cached

presentation data for the object, and specifies ADVF_DATAONSTOP as the

advise flag to Cache(). The user makes some changes to the object in the

OLE 1.0 server, then attempts to update the object's presentation in the

server by choosing the Update command from the File menu. Finally, the user

closes the object server.

In this specific scenario, the object's presentation in the server is not

updated. The object's native data, however, is correct.

--------------------------------------------------------------

BUG:IOleObject::IsUpToDate Returns Wrong Value for Manual Link

--------------------------------------------------------------

Article ID: Q111655

To determine whether an OLE link needs to be updated, an OLE 2.0 container

application needs to call IOleObject::IsUpToDate. If this method returns

S_FALSE, the link needs to be updated; otherwise, the link can be

considered up to date. However, calling IOleObject::IsUpToDate on a manual

link while the link server is not running results in an a return value of

S_FALSE, even if the link is current. The result of this is that OLE 2.0

container applications may update links unnecessarily.

-------------------------------------------------------------

BUG: Borland WINSIGHT Causes GP Faults w/Some OLE Sample Apps

-------------------------------------------------------------

Article ID: Q112410

If Borland's WINSIGHT tool is running when you start some of the sample

applications that have been included in the OLE 2.01 SDK, a general

protection (GP) Fault will occur before the main application window

appears.

The following OLE 2.01 SDK sample applications are affected:

   cl2test.exe

   sr2test.exe

   outline.exe

   cntroutl.exe

   svroutl.exe

   icntrotl.exe

   isvrotl.exe

--------------------------------------------------

BUG: Windows OLE DLLs Do Not Convert Mac OLESTREAM

--------------------------------------------------

Article ID: Q112412

The OLE 2.01 libraries will not convert a Mac OLESTREAM to a Windows

OLESTREAM. Similarly, the Windows OLE dynamic-link libraries (DLLs) will

not convert a Mac IStorage to a Windows OLESTREAM.

--------------------------------------------

BUG: Printing Does Not Work from CL2TEST.EXE

--------------------------------------------

Article ID: Q112413

Printing does not work correctly from CL2TEST.EXE. Choosing Print from the

File menu results in a blank printout.

Additional reference words: 1.00 2.00

KBCategory: kbole kbbuglist

KBSubCategory: LeTwoOth


The Component Object Model

PSS ID Number: Q104140

Authored 08-Sep-1993	Last modified 17-May-1995

The information in this article applies to:

 - Microsoft OLE Libraries for Windows and Win32s, version 2.0

 - Microsoft OLE Libraries, included with:

    - Microsoft Windows NT, versions 3.5 and 3.51

    - Microsoft Windows 95

SUMMARY

The Component Object Model is a specification that describes the

process of communicating through interfaces, acquiring access to

interfaces through the QueryInterface method, determining pointer

lifetime through reference counting, and re-using objects through

aggregation.

MORE INFORMATION

Object

------

An object is an item in the system that exposes interfaces to

manipulate the data or properties of the object. An object is created

by directly or indirectly calling the CoCreateInstance() application

programming interface (API), which in turn creates a new instance of

the object and returns a pointer to a requested interface. For more

details, see pages 93 and 94 of the "OLE 2.0 Design Specification."

Interfaces

----------

An interface is a group of related functions. Communication between

two objects in a system occurs by calling the functions in an

interface through a pointer to that interface. An interface pointer is

originally obtained at the time the object is created.

A good example of an interface is a window that supports drag and

drop. The window exposes an interface with methods that could be used

during drag and drop. The object being dragged could communicate with

the window through this interface. Such an interface might resemble

the following:

   interface IDropTarget : IUnknown {

       virtual HRESULT DragEnter() = 0; // Mouse entered the window.

       virtual HRESULT DragOver()  = 0; // Called each mouse move.

       virtual HRESULT DragLeave() = 0; // Mouse left the window.

       virtual HRESULT Drop()      = 0; // Item dropped on the window.

       };

For more information on interfaces, refer to pages 57-60 of the "OLE

2.0 Design Specification."

IUnknown

--------

All interfaces used in the component object model are derived from a

base interface called IUnknown. The methods contained within IUnknown

are related because they deal with object maintenance. The IUnknown

interface is defined as:

   interface IUnknown {

       virtual HRESULT QueryInterface( REFIID, VOID FAR *) = 0;

       virtual ULONG   AddRef() = 0;

       virtual ULONG   Release() = 0;

   };

IUnknown::QueryInterface is used for interface negotiation. The other

methods are used for reference counting to control the life of the

object.

More information on the IUnknown interface can be found on pages 81-83

of the "OLE 2.0 Design Specification."

Interface Negotiation

---------------------

Given a pointer to a particular interface, an object can be queried

for another interface. This is done by calling the QueryInterface()

method in an interface. The following code demonstrates querying for

the IOleObject interface:

   // Assume that a pointer to an arbitrary interface, pint,

   // exists.

   LPOLEOBJECT pOleObject;

   HRESULT hErr;

   // Query the interface.

   hErr = pint->QueryInterface(IID_IOleObject, (LPVOID FAR *)

                                               &pOleObject);

   if (hErr == NOERROR)

       // Object supports this IOleObject. The IOleObject

       // methods can now be called through pOleObject.

   else

       // Object does not support IOleObject.

Reference Counting

------------------

Interface lifetime is controlled through reference counting. To

increment the reference count on an interface, call the AddRef()

method. To decrement the reference count on an interface, call the

Release() method. Once an interface's reference count goes to zero,

the pointer to that interface is no longer valid. If the reference

count on all of an object's interfaces is zero, then the object can be

freed because there are no longer any pointers to the object.

More information on reference counting can be found on pages 83 and 84

of the "OLE 2.0 Design Specification."

Aggregation

-----------

Aggregation is the ability of an object to be re-used or extended

dynamically, without having to recompile the original object code. For

more information on the process of aggregation, please refer to the

"OLE 2.0 Design Specification," pages 61-63.

Additional reference words: 2.00 3.50 4.00

KBCategory: kbole kbprg

KBSubcategory: LeTwoCom


Using MKTYPLIB /h Option to Output C or C++ Style Header file

PSS ID Number: Q124597

Authored 05-Jan-1995	Last modified 21-Apr-1995

The information in this article applies to:

 - The Type Library Generator (MKTYPLIB.EXE), included with:

    - Microsoft Win32 Software Development Kit (SDK) for Windows NT

      version 3.5

    - Microsoft Visual C++, 32-bit Edition, version 2.0

      on the following platform: x86

SUMMARY

In addition to generating type libraries, MKTYPLIB can output a C or C++

style header file if you use the optional /h option. When you use the /h

option, MKTYPLIB creates a header file with the name specified following

the /h option. Any existing file of the same name will be overwritten

without warning.

MKTYPLIB always uses the "libraryname" from the LIBRARY keyword in the

ODL file to create the #ifndef wrappers in the generated header file,

regardless of the name specified for the file on the command line.

MORE INFORMATION

Consider this ODL file (MYPROJ.ODL):

   // example ODL file

   library MYPROJ

   {

      ...

   }

If you run MKTYPLIB on this ODL file by using this command line:

   C:\> MKTYPLIB /h odlfile.h myproj.odl

the ODLFILE.H generated by MKTYPLIB looks like this:

   #ifndef _MYPROJ_H_

   #define _MYPROJ_H_

   ...

   #endif

This can cause problems when compiling source files if another header file

also uses _MYPROJ_H_ in its #ifndef wrappers. Only the first file to use

_MYPROJ_H_ will actually be included in the source file.

If you are using the _<filename>_H_ convention for #ifndef wrappers, make

sure none of your header files have the same name as your type library.

Alternatively, use a different naming convention for the #ifndef wrappers

in your header files.

Additional reference words: 2.00 3.50

KBCategory: kbole kbtool

KBSubCategory: LeTwoTls


Introduction

This book describes how to create applications that use the Microsoft® Windows® Pen Application Programming Interface (API). The book is divided into two parts. Part 1 presents an overview of pen-based computing and describes the various components of the Pen API. Sample code supplements the text and later chapters present a complete sample program and sample recognizer as examples. (Recognizers translate pen strokes into characters, symbols, or shapes.) Part 2 provides a reference for the functions, structures, messages, and constants that make up the Pen API. Following the reference, a number of appendixes provide information about the differences between versions 1.0 and 2.0 of the Pen API, the 32-bit pen services, and more.

The Microsoft Windows 95 operating system includes a subset of the Pen API for displaying pen data. This allows a pen-based application to collect pen data from a pen tablet, store the data, and later display the data on any personal computer running Windows 95, even without pen hardware. The full pen services come only with pen hardware from original equipment manufacturers (OEMs) of pen equipment. Thus, an application running with Windows 95 has guaranteed access to at least the display portion of the Pen API; if a pen tablet is attached, the application can also accept pen input.

The full pen services of the Pen API version 2.0 described in this book can run only with Windows 95 or later Windows versions.

This book assumes a familiarity with the C language and with Windows programming in general. To keep discussions concise, the text does not digress to define such general terms as dynamic-link library (DLL), callback function, or message. However, pen-based computing generates its own lexicon, so the text defines new terms specific to the Pen API as they are introduced. In addition, a brief glossary of terminology specific to pen-based computing appears at the end of this book.


Organization

This book is divided into the following chapters and appendixes.

Chapter or appendix	Describes
Chapter 1, Overview of the Pen Application Programming Interface	Architecture of the Pen API.
Chapter 2, Starting Out with System Defaults	How to add pen functionality to an application with a minimum of programming effort.
Chapter 3, The Writing Process	How an application gets input from a pen device.
Chapter 4, The Inking Process	How an application collects and changes pen input data.
Chapter 5, The Recognition Process	Converting raw pen input into usable characters such as letters and numerals.
Chapter 6, Design Considerations	Proper techniques, warnings, and tips for writing a pen-based application.
Chapter 7, A Sample Pen Application	The PENAPP.C sample application, to illustrate the information in Chapters 1 through 6.
Chapter 8, Writing a Recognizer	The requirements and design of a recognizer. Illustrates information using the sample recognizer SREC.C as a model.
Chapter 9, Summary of the Pen Application Programming Interface	Pen API services, listed by category.
Chapter 10, Pen Application Programming Interface Functions	Functions, listed alphabetically.
Chapter 11, Pen Application Programming Interface Structures	Structures, listed alphabetically.
Chapter 12, Pen Application Programming Interface Messages	Messages, listed alphabetically.
Chapter 13, Pen Application Programming Interface Constants	Constants, listed alphabetically.
Appendix A, Differences Between Versions 1.0 and 2.0 of the Pen Application Programming Interface	Changes and improvements to the Pen API.
Appendix B, Using the 32-Bit Pen Application Programming Interface	How to write 32-bit pen-based applications.
Appendix C, Modifying the SYSTEM.INI File	Settings used in Windows SYSTEM.INI.
Appendix D, Accessing the Pen Device Driver	How an application calls the pen driver.
Glossary	Pen-based terms.


Document Conventions

The following document conventions are used throughout this book.

Convention	Description
Bold text	Bold letters indicate a specific term or punctuation mark intended to be used literally: language functions or keywords (such as DrawPenDataEx or switch), MS-DOS® commands, and command-line options. You must type these terms and punctuation marks exactly as shown. The use of uppercase or lowercase letters is usually, but not always, significant. For example, you can invoke the C compiler by typing either CL, cl, or Cl at the MS-DOS prompt.
( )	In syntax statements, parentheses enclose one or more parameters that you pass to a function.
Italic text	Italic text indicates a placeholder; you are expected to provide an actual value. For example, in the following syntax the placeholder lpszRecogName represents a pointer to the filename of a recognizer: InstallRecognizer( lpszRecogName ); New terms pertaining to pen-based computing also appear in italics where they are first introduced or defined in the text. Such terms are also listed in the glossary.
Monospace text	Code examples are displayed in a nonproportional typeface.
if(!RegisterClass(LPWNDCLASS)&wc))      .      .      . else	A vertical ellipsis in a program example indicates that a portion of the program has been omitted.
. . .	A horizontal ellipsis following an item indicates that more items having the same form may appear.
[[ ]]	Double brackets enclose optional fields or parameters in command lines or syntax statements.
|	A vertical bar indicates that you can enter one of the entries shown on either side of the bar. In symbol graphs, a vertical bar indicates the possible character choices.
{ }	Braces indicate that you must specify one of the enclosed items.
SMALL CAPITAL LETTERS	Small capital letters indicate the names of keys and key sequences; for example, CTRL+ALT+DEL. If the key names are separated by commas instead of plus signs; for example ALT, F—then you must press the keys consecutively rather than together.


Books and Articles for Further Reading

The documentation listed in the following table provides additional information about the Pen API and about Windows in general.

Title	Contents
Microsoft Windows Pen API version 2.0 online Help	Online reference for Pen API functions, structures, messages, and constants.
Microsoft Windows Software Development Kit (SDK) documentation, or equivalent documentation	Information about the application programming interface of the Windows operating system.
Microsoft Windows Device Driver Kit (DDK) documentation, or equivalent documentation	Description of the application programming interface of the Windows device drivers. Required only for developing drivers.
Duncan, Ray. "Power Programming." PC Magazine. New York, New York: Ziff-Davis Publishing Company, January 14, 1992 through May 12, 1992	Series of articles on the basics of the Pen API version 1.0.
Petzold, Charles. Programming Windows. Third edition. Redmond, Washington: Microsoft Press, 1992	Good introduction to general programming for Windows.


System Requirements

You can develop pen applications for version 2.0 of the Pen API with the following software and hardware:

•	A personal computer running Windows 95 or a later version of Windows

•	A mouse, tablet, or other pointing device supported by the Pen API

•	Microsoft Win32® Software Development Kit (SDK)

•	Microsoft Windows 95 Device Driver Kit (DDK) — necessary only if you will be building pen, display, or keyboard drivers

•	Microsoft C Optimizing Compiler, version 5.1 or later, or Microsoft QuickC® for Windows version 1.0 or later

•	Microsoft Macro Assembler version 5.1 or later — necessary only if you will be building pen, display, or keyboard drivers

You may also use equivalent development software produced by other manufacturers, such as Borland International, Inc.


Acknowledgments

Special thanks to the contributors to this book including:

Writers	Beck Zaratian Don Gilbert	Mark Williams
Editors	David Steinmetz Peter Delaney	Barb Ellsworth David Thornbrugh
Program Managers	Jeff Aamodt Eric Berman	Steve Liffick
Pen Services Development Team	Eric Onasick Vinayak Bhalerao Haresh Ved	Shishir Pardikar Chris Leyerle Fumitaka Kawasaki
Recognition Development Team	Mike Van Kleeck Justin Ferrari Sung Rhee Donald Sidoroff Greg Hullender	Jim Adcock Shamik Basu Oswaldo Ribas Patrick Haluptzok
Testing Team	Becca Moss Brian Watson Xian-Ling Wu	Keith Stutler Randy Shedden David Flenniken


Overview of the Pen Application Programming Interface

This chapter presents an overview of pen-based computing, divided into two main sections. The first section broadly describes the various components that make up the Pen application programming interface (API). The second section describes how applications access the pen services to incorporate pen-based features.

The architecture of version 2.0 of the Pen API remains similar to version 1.0, but its style and design differ considerably. Even if you have worked with version 1.0, you should read this chapter to understand the shift in programming philosophy in version 2.0.


Architecture of the Pen API

The seemingly simple step of getting data from the pen to an application involves many intermediate tasks. Fortunately, the Pen API itself takes on the major share of this work. By providing applications with convenient access to pen features, the Pen API insulates the programmer from the most tedious aspects of pen data recognition. At the same time, its flexible design allows applications to control most of the low-level processes of pen input.

As you read this section, keep in mind that the complexities of the Pen API architecture in no way imply a corresponding difficulty in creating pen-based programs. You will find that writing intelligent pen-based software is no more difficult than writing other applications for Microsoft Windows.

Figure 1.1 illustrates the interaction between applications and the main components of the Pen API.

The following four sections describe each component of Figure 1.1, beginning with the main Windows component. Each section contains a figure that incorporates Figure 1.1, exploding the component into a detailed view. The accompanying text describes the component and explains how it interacts with the other components.


Windows

As Figure 1.2 shows, the heart of the pen-based services for Microsoft Windows 95 consists of two libraries — PKPD.DLL and PENWIN.DLL. The PKPD.DLL file provides ink management for the pen services of Windows 95. This allows an application to display and manipulate ink data with any installation of Windows 95, even one without pen hardware. Chapter 9, "Summary of the Pen Application Programming Interface," identifies the pen services exported by PKPD.DLL.

The PENWIN.DLL file is available only with original equipment manufacturer (OEM) pen hardware and provides additional pen services that collect, modify, and recognize ink data. Before using these input and recognition features, an application should first test for the presence of the PENWIN.DLL file and either gracefully exit or alter its behavior accordingly.

In Pen Windows version 1.0, applications were required to call RegisterPenApp in order to tell the system to convert all edit controls to handwriting edit (hedit) controls. With Pen API version 2.0, however, this is not necessary; all edit controls in applications are automatically converted. If the application is version-stamped as a Windows 95 − based application, the conversion is automatic; otherwise, applications version-stamped as Windows 3.1 − based applications require the call to RegisterPenApp that was required for Pen Windows version 1.0.

It is important to understand that for any application to successfully use the functions in PENWIN.DLL, the computer on which it is running must load the pen services when Windows boots and terminated the pen services when Windows shuts down (that is, PENWIN.DLLmust be referenced from the drivers line in the [Boot] section of the SYSTEM.INI file). This does not apply to functions in the PKPD.DLL library, which is automatically available on all Windows 95 systems. See Appendix C, "Modifying the SYSTEM.INI File," for information on the SYSTEM.INI file requirements.

Because of this requirement, PENWIN.DLL should never be statically linked by any application that may be run on a system on which pen services are not installed. Instead, its functions should always be called using function pointers. Typically, when the pen-aware application initializes, it calls GetSystemMetrics with SM_PENWINDOWS as a parameter which, if returned successful, provides a handle to the loaded library. Then, for each PENWIN.DLL function used by the application, the application calls the GetProcAddress function (with the library handle and the function name) and saves a function pointer to be used in future calls to that function. See the HFORM sample application for an example of this technique.

By not linking PENWIN.LIB, it is insured that an application running on a system on which PENWIN.DLL has not been installed, but which contains PENWIN.DLL on the path, will not load PENWIN.DLL at runtime. Pen components not loaded at system boot time are not guaranteed to perform properly. Note that this applies for both 16-bit and 32-bit libraries.

Applications that are destined to be run only on systems that have pen services installed can link directly to PENWIN.LIB. These applications should test for the existence of pen services at startup, however, and exit if it is not found. Note that most of the examples in this manual follow normal linking practice for the sake of readability and do not use the safer practice of using function pointers. It is the responsibility of the developer to choose the best means of accessing the functions in PENWIN.DLL for each application.

The Pen Message Interpreter provides basic pen services to pen-unaware applications. Such applications, which do not explicitly take advantage of Windows pen services, currently represent a majority of Windows-based software. The Message Interpreter allows use of a pen with pen-unaware programs by capturing handwritten input and other pen events and converting them into equivalent keyboard and mouse messages. The application has no knowledge of the pen or that pen input has occurred.

In capturing handwritten input, the Message Interpreter acts only when it detects a standard I-beam pointer or insertion point in the pen-unaware application. Since applications generally show the system I-beam pointer when prompting for input in writing areas, the Message Interpreter reliably serves most pen-unaware programs. However, a few pen-unaware Windows-based applications do not prompt with a standard I-beam pointer, defeating the Interpreter's detection method. Although the Interpreter still allows the pen to serve as a mouse with such applications, it cannot interpret handwritten input.

The Message Interpreter may also falter when serving applications developed for a version of Windows earlier than version 3.1. These applications were not designed with the pen in mind and therefore may not work optimally with the pen. For example, edit fields in applications written for Windows version 3.0 are often too small to write in with a pen. A final problem with older applications is that the Message Interpreter has no means of receiving contextual information from the application about what sort of input it expects. This can reduce recognition accuracy.

The Message Interpreter is of academic interest for the programmer because it pertains to only pen-unaware applications. The rest of this book focuses on how to write pen-aware applications and dynamic-link libraries (DLLs) that make use of the Pen API directly.


Drivers

Figure 1.3 shows the two types of drivers that function within the Pen API system. Most drivers incorporate two modules: an installable device driver that uses the Windows installable driver interface and a virtual device driver that handles interaction with the hardware.


Pen Driver

The pen installable device driver, which Windows supplies as the file PENC.DRV, interacts with the virtual pen driver (VPENDC.VXD) and passes pen movement data to Windows. The fact that the pen driver's data may sometimes be needed for on-the-fly handwriting recognition places several constraints on a pen input device:

•	The pen driver must be able to report the location of the pen at least 60 times per second. This rate ensures the true path of the pen is reported accurately enough to support the efforts of vector-based recognizers. It also makes the ink, a path of pixels that traces the pen's movement, appear smooth and natural at normal writing speeds. For more information about recognizers, see the "Recognizer" section later in this chapter.

•	The pen driver must be able to report pen positions with a resolution of at least 200 points per inch. This degree of resolution ensures ink coordinates are sufficiently fine to let the recognizer make accurate judgments about the path of the pen over the digitizing surface.

•	Regardless of the resolution of the device, the pen driver must report the pen position in tablet coordinates of 0.001 inch. This convention ensures that Windows, the recognizer modules, and the application all view the ink at the same scale.


Display Driver

The display driver is responsible for interacting with the display hardware and the graphics device interface (GDI) module of Microsoft Windows. A display driver should support inking to provide the user with visible feedback as the pen moves. Technically, the Pen API does not require inking support from the display driver. However, the system is far more practical and convenient when the user can see the ink trail left by the pen.

Two types of display drivers are supported:  Display Control Interface (DCI) drivers (called DCI Providers) and non-DCI drivers, such as older VGA or 8514 drivers. For DCI Providers, no extra work is required to support the pen interface.

To support inking in a non-DCI driver, the display driver must be able to:

•	Export the GetLPDevice function to provide Windows with a value identifying the pen hardware.

•	Export the InkReady function, which Windows calls to notify the driver that the pen is in motion and Windows is ready to display ink. InkReady must be able to handle calls during system interrupts.

•	Provide a pointer in the shape of a pen.

Windows — not the display driver — displays the ink. When Windows receives notice through its InkReady function, the driver calls back into Windows to draw the ink.

For more details on display drivers, refer to the device driver kit (DDK) for Windows 95.


Recognizer

A recognizer is a DLL with functions that determine what symbol a pattern of pen strokes represents. As illustrated in Figure 1.4, Windows allows the concurrent operation of more than one recognizer. For example, one recognizer may specialize in English letters, another in mathematical symbols, another in geometric shapes, and so forth.

Each handwriting recognizer can access any number of word lists. Word lists offer a way for a recognizer to corroborate and refine its guesses. For example, if a recognizer cannot decide whether a handwritten word is "boy" or "looy," finding one word but not the other in a word list helps the recognizer make a more confident choice.

Although many recognizers may be available to an application, only one serves as the system default recognizer. This is the recognizer that Windows automatically installs and calls by default. To use other recognizers, an application must first specifically install them. (For information about how to install multiple recognizers, see Chapter 5, "The Recognition Process.") The Microsoft Handwriting Recognizer (GRECO.DLL)  is provided as the default system recognizer on most OEM tablet installations of Microsoft pen services. The Microsoft Handwriting Recognizer recognizes all European letters, numerals, and punctuation, with emphasis on English, French, and German, An application can set up a different system recognizer by identifying the new file in the Windows registry. Appendix A explains how to set up a new default recognizer.


Accessing the Pen API from Applications

As Figure 1.5 shows, applications that accept user input are divided into two categories: pen-aware and pen-unaware applications. A pen-unaware application, as the name implies, is written to expect input only through the keyboard or mouse, unaware of the existence of Windows pen services. However, if a pen device is present, Windows 95 supports its use both as a mouse and for text entry with a pen-unaware application. For details about how Windows allows the use of a pen with an application not written to accept pen input, see "Pen-Unaware Applications" in Chapter 2, "Starting Out with System Defaults."

The Pen API is designed for small handheld systems with limited memory and power, so its API consists of 16-bit functions. Therefore, Windows provides a thunk layer for 32-bit applications to call through to the API. The thunk layer automatically converts 32-bit function parameters and structure data to 16-bit equivalents. The application must ensure its data will fit into the smaller sizes before calling into the Pen API. See Appendix B for information about using the 32-bit API.


Starting Out with System Defaults

As much as possible, the Pen application programming interface (API) handles the many complexities of pen-based computing. A rich API leaves the developer free to concentrate on design without having to worry about details. This chapter describes how to create a pen-based application that relies on the system default services of the Pen API. For the sake of simplicity, the term "application" as used in this chapter refers both to Windows-based programs and dynamic-link libraries (DLLs).


Pen-Unaware Applications

Microsoft Windows 95 supports the use of a pen even with pen-unaware applications. For such applications, Windows provides a means for the pen to mimic both mouse and keyboard data. It does this in two ways.

The first method, the Pen Message Interpreter, is described in the "Windows" section in the previous chapter. The second method involves two utility "applets" called Writing Palette (WRITEPAL.EXE) and Screen Keyboard (SK.EXE), both supplied as installed applications. Writing Palette allows the user to enter handwritten text for those occasions when the Message Interpreter fails to detect an input prompt. For example, when running an MS-DOS text editor in a window, the user can input handwritten text through the Writing Palette utility. The Pen API translates the handwritten text into characters and displays the result in the writing window. The user can then correct the text if necessary and tap the OK button when the corrections are recognized. Windows feeds the characters to the pen-unaware text editor as a series of WM_KEYDOWN and WM_KEYUP messages as though they were typed at the keyboard.

The Screen Keyboard applet displays an image of a typical keyboard on which the user can "type" by tapping the keys of the on-screen keyboard with the pen. Each key is sent as soon as it is typed. This does not require recognition because no handwriting is involved.


Pen-Aware Applications

The Pen API allows the developer to approach pen-based computing in stages. For those who wish to do only a minimum amount of programming work and yet incorporate significant pen capabilities in an application, the Pen API provides the DoDefaultPenInput function. DoDefaultPenInput embodies a set of more complex API elements in one function. As its name implies, it allows applications to rely on the system to make all of the decisions concerning pen input. The developer can incrementally enhance a pen-based application as time and interest permit.

When called in response to a WM_LBUTTONDOWN message generated by the pen device, DoDefaultPenInput starts a cascade of messages. These messages reflect the many steps of the recognition process, each message serving as a notice that a next step in the process is about to occur. The application can take some action prior to each step or simply ignore the message and let the DefWindowProc function provide default services.

This approach follows standard Windows messaging procedures. If an application lets the message pass through to DefWindowProc, Windows translates the pen events into the appropriate keyboard messages. For example, handwritten characters generate appropriate WM_CHAR messages. In this way, a developer can gradually modify an existing application to become more and more sophisticated about pen input by adding code to handle more of the DoDefaultPenInput messages.

The following sections describe the programming convenience of using system defaults, which you might think of as "letting the system do the work." The text also mentions various options available to the developer who wishes to exercise more control over the recognition process. These options involve manipulating data objects such as HRC and HPENDATA, which are fully described in Chapters 4 and 5. The following sections serve as an introduction to the entire process of converting pen-based input to usable data. When you later decide to incorporate additional recognition management into your application, see Chapters 4 and 5.


Beginning an Input Session

A pen input session begins when the user touches pen to tablet and begins writing. The end of the session depends on parameters established by the application. Usually, the session ends when the user taps the pen outside the writing area or when a brief period of inactivity elapses. As when writing with a real pen, people tend to pause between words or sentences to gather their thoughts; an application can use these momentary pauses to get recognition results. A new session begins when the user begins writing again.

When the pen first touches the tablet at the start of an input session, Windows sends a WM_LBUTTONDOWN message to the application's main window procedure. In a pen-based environment, this message can indicate either a true mouse event or that the pen point has touched the tablet. The application must distinguish between these two possibilities before calling the DoDefaultPenInput function, as shown in the following fragment:

LONG	lExtraInfo;

.

.

.

switch (wMsg)

{

case WM_LBUTTONDOWN:

// If true pen-down event, call DoDefaultPenInput.

lExtraInfo = GetMessageExtraInfo();

if (IsPenEvent( wMsg, lExtraInfo )

return DoDefaultPenInput( hwnd, LOWORD(lExtraInfo) );

else	// No, it's a mouse

{	//   button down

.

.

.


DoDefaultPenInput Messages

This section lists in chronologic order the message traffic that DoDefaultPenInput generates. It discusses why an application might want to handle each message and explains what action DefWindowProc takes. The sample application described in Chapter 7, "A Sample Pen Application," demonstrates how to handle most of these messages.


Step 1: PE_BEGININPUT Submessage

Immediately upon calling DoDefaultPenInput, an application receives a WM_PENEVENT message with a PE_BEGININPUT submessage. Sending WM_PENEVENT and PE_BEGININPUT via the SendMessage function is the equivalent of calling DoDefaultPenInput. The caller should not trap the PE_BEGININPUT submessage because DefWindowProc starts the chain of events based on this message. The application should complete all its initialization work before calling DoDefaultPenInput.


Step 2: PE_SETTARGETS Submessage

Windows sends the WM_PENEVENT message with a PE_SETTARGETS submessage to the window that received the PE_BEGININPUT submessage. PE_SETTARGETS is important when several windows on the screen vie for input at the same time, presenting Windows with more than one potential recipient for the pen data. This can occur when a dialog box contains multiple edit controls or a forms program prompts the user simultaneously with several writing areas. The user can write in different writing areas without having to pause between each and wait for recognition results. Windows treats the writing as part of a single input session, regardless of the targets.

DoDefaultPenInput must therefore select between targets when distributing pen data. A target is a rectangular area associated with the handle of a window that is a valid destination for pen data. When writing starts, all valid targets participate in the DoDefaultPenInput messaging. This allows the user to move freely between windows — for example, writing the name of a city in one control, interrupting to write the date in another control, then moving back to the first control to add the state and zip code. The system correctly routes pen input to the control on which ink was written or, barring that, to the control nearest the ink.

DoDefaultPenInput handles all routing automatically. Upon receiving a PE_SETTARGETS submessage, the application can process the message and create a TARGINFO structure that describes all valid targets for the pen data. If the application chooses not to process PE_SETTARGETS itself, DefWindowProc enumerates the children of the window and creates a TARGINFO structure automatically. If the application returns FALSE to the PE_SETTARGETS submessage, Windows assumes no targets exist and sends the pen data to the window that received PE_SETTARGETS.

For information on how to specify a target area larger than the window size, see the "PE_SETTARGETS Submessage"section.


Step 3: PE_GETPCMINFO Submessage

If the application calls DefWindowProc to process the PE_SETTARGETS submessage, every descendant of the window that received PE_SETTARGETS receives a PE_GETPCMINFO message. This message is so named because it gets information about the pen collection mode (PCM). The PCM describes the system state during an input session when the pen is writing and not operating as a mouse.

PE_GETPCMINFO gives each target the opportunity to:

•	Proclaim or disclaim itself as a valid target.

•	Specify termination conditions, such as timeout or range.

•	Identify areas in which tapping terminates the input session.

•	Do any combination of the above.

In processing PE_GETPCMINFO, the child window must fill in a PCMINFO structure that describes how pen interaction should proceed. If the candidate window wishes to receive input from the pen and become a true target, it can provide the coordinates of a bounding rectangle in the rectBound member of PCMINFO. The bounding rectangle constitutes the target area of the child window; inking that occurs within or nearest a bounding rectangle is sent to the window associated with the rectangle. If the child window does not process PE_GETPCMINFO, Windows does not consider the window a candidate for pen input but also does not prevent ink from overwriting the window.

DefWindowProc collects all bounding rectangles and exclusion rectangles provided by the descendant windows and creates a master PCMINFO structure that describes the situation.

For information about how to initialize and make changes to a PCMINFO structure, see the "Starting the Chain of Events" section in Chapter 3, "The Writing Process." See Chapter 11, "Pen Application Programming Interface Structures," for descriptions of the structure members.


Step 4: PE_GETINKINGINFO Message

Each target specified in the TARGINFO structure created in step 2 that has a valid bounding rectangle from step 3 receives a PE_GETINKINGINFO message. In response to this message, a child window can set ink color and ink width, establish the ink clip region, and specify whether or not Windows should automatically restore the screen and erase the ink after pen interaction has ceased.

Processing the message through DefWindowProc sets the system default ink attributes, uses the window boundary for the ink clip region, and forces automatic restoration of the screen after input. DefWindowProc merges the responses from each target into a master INKINGINFO structure.


Step 5: Master PCMINFO and INKINGINFO Structures

Having created a master PCMINFO structure and a master INKINGINFO structure, DefWindowProc sends one more PE_GETPCMINFO message and PE_GETINKINGINFO message to the parent window that contains the child targets. This provides the parent window a final opportunity to examine and change, if necessary, the system's assumptions about the impending inking event. For example, the parent window can specify a default ink color in the INKINGINFO structure or set an exclusion region around a screen object that had not, for some reason, handled the PE_GETPCMINFO message.


Step 6: PE_BEGINDATA Message

When pen activity destined for a particular target begins, the target first receives a PE_BEGINDATA message. This message provides the target a way to inform DoDefaultPenInput what to do with the data. If DefWindowProc handles this message, it assigns the pen data to a default HRC object and uses the system recognizer for recognition. (For more information about the system default recognizer, see "Recognizer" and "Creating the HRC.") Alternatively, the target can attach its own HRC for recognition, an HPENDATA to store the data, or a private object of some kind associated with the target.

To govern recognition, an application should handle PE_BEGINDATA, create and configure its own HRC object, and identify the object with the dwData member of the TARGET structure pointed to by the message's lParam. The application calls the CreateCompatibleHRC function to create the HRC object and set its context. This forces the system to use the new HRC. For more information about HRC and how to create one with CreateCompatibleHRC, see "The HRC Object."


Step 7: PE_MOREDATA Message

Multiple PE_MOREDATA messages can arrive at each target window to indicate more pen data is available. Generally, an application passes PE_MOREDATA on to DefWindowProc for default processing. DefWindowProc accrues new data by adding it to the HRC or HPENDATA object established in step 6.


Step 8: PE_ENDDATA Message

The PE_ENDDATA message informs a target window that input for the target has ceased. The message's lParam points to a TARGET structure, the dwData member of which identifies the HRC or HPENDATA created in step 6. If recognizing

input through an HRC object, the application should let DefWindowProc handle this message. However, DefWindowProc will destroy an HPENDATA object when processing PE_ENDDATA. To preserve the HPENDATA, the application has two choices:

•	Trap the message, preventing it from reaching DefWindowProc. In this case, the HPENDATA object outlives the input session. Note that an HPENDATA object occupies memory in the system heap. When finished, the application must remove the object by calling DestroyPenData to avoid wasting resources.

•	Alternatively, copy the HPENDATA object with DuplicatePenData before letting the PE_ENDDATA message fall through to DefWindowProc. However, this approach has no advantage over the preceding method, merely trading the original object for its clone. Again, the application is responsible for destroying the new HPENDATA object.


Step 9: PE_RESULT Message

The PE_RESULT message arrives only if the application has specified an HRC object in step 6, rather than an HPENDATA or other object. The message signals the target window that recognition results are ready. This message differs slightly from the others in that its lParam holds the HRC handle and not a pointer to a TARGET structure. If DefWindowProc handles PE_RESULT, it converts the recognizer's best guess to a string of characters and sends them to the target window as WM_CHAR messages. Gestures are also converted to appropriate messages, such as WM_COPY or WM_PASTE.

If the application handles the message, it must not destroy the HRC for the default system recognizer. Because DoDefaultPenInput created the default HRC, it expects to destroy it as well. The application must not destroy objects it did not create.

At this point, an application can process any of the results itself. For example, it might check for a recognized gesture such as the lasso or cut gesture. The procedure for examining gestures at this point involves three steps:

1.	Retrieve any recognized gesture symbols from the HRCRESULT object by calling the GetResultsHRC function with the GRH_GESTURE argument.

2.	If this call indicates the recognizer has found a gesture, the application then calls the GetSymbolsHRCRESULT function to see if the gesture is a lasso or X mark.

3.	If the gesture is a lasso or X mark, the application should examine the data further to determine the size of the gesture, as outlined in the following example.

If the first or second test fails, indicating the recognizer has found no lasso or X mark, the application should pass the PE_RESULT message to DefWindowProc for text processing. Note that the lasso and cut gestures cannot exist with other gestures; therefore, the following code allocates only one HRCRESULT object because it examines at most a single gesture:

HRCRESULT	hresult;	// Look at only the first gesture

HPENDATA	hpendata;	// Points that comprise the gesture

HRGN	hrgn;	// Screen region of the gesture

SYV	syv;	// Symbol value of the gesture

UINT	uRgnType;	// Region type: X or LASSO

int	cGest;	// Count of gestures in results

.

.

.

switch ( wParam )	// Handle WM_PENEVENT messages

{

case PE_RESULT:

// Check for gesture

cGest = GetResultsHRC( (HRC) lParam,	// HRC handle

  GRH_GESTURE,	// Gestures only

  (LPHRCRESULT)&hresult,	// Buffer

  1 );	// Get one result

// If one gesture available, get its symbol

if (cGest == 1)

{

GetSymbolsHRCRESULT( hresult,	// HRCRESULT handle

 0,	// Index to 1st syv

 (LPSYV) &syv,	// Symbol buffer

 1 );	// Get 1 symbol

//

// If the gesture is lasso or x, collect the

// points that make up the gesture

//

if (syv == SYV_LASSO  ||  syv == SYV_CUT)

{

hpendata = GetPenDataHRC( (HRC) lParam );

if (hpendata)

{

// Step 1:  Get region of the gesture

uRgnType = (syv==SYV_LASSO) ? CPDR_LASSO : CPDR_BOX;

hrgn = CreatePenDataRegion( hpendata, uRngType );

// Step 2: Determine what text lies within the

// region.  If the gesture covers more than one

// letter of a word but not the entire word, assume

// it's meant for entire word.

.

.

.

// Step 3:  Either select . . .

if (syv == SYV_LASSO)

{

.	// Select the text

.

.

}

// . . . or delete the text

else

{

.	// Delete the text

.

.

}

DeleteObject( hrgn );

DestroyHPENDATA( hpendata );

}

}

}

break;

default:

DefWindowProc( hwnd, message, wParam, lParam );

}

As the previous code shows, applying a gesture to text requires three steps:

1.	Call the CreatePenDataRegion function to find the region covered by the gesture.

2.	Determine the text that lies within the gesture's region using the Windows GetTextExtent function or some other method.

3.	Select or cut the text, according to the gesture.


Step 10: PE_ENDINPUT Message

Windows sends the PE_ENDINPUT message to the window that received the PE_BEGININPUT submessage in step 1. An application can perform any necessary cleanup chores at this time, but should pass the PE_ENDINPUT message to DefWindowProc.


The Writing Process

This chapter begins a series of three chapters that describe the three main stages of converting pen input into valid computer data. This chapter looks at the writing process. The next two chapters discuss the processes of inking and recognition.

The writing process includes the various ways a user can write input to a pen-based application. These involve not only writing words and scribbling figures with a pen, but also gesturing with predefined pen movements and tapping an on-screen keyboard.

This chapter is divided into three main sections, each discussing a different method by which an application can accept writing from the pen. The first section describes the pen edit controls, which are pen-based versions of a standard Windows edit control. The second section discusses ink input application programming interface (API) services, which allow an application to govern pen interaction at a lower level than edit controls. The final section briefly describes the on-screen keyboard.


Pen Edit Controls

The Pen API provides three different edit controls for pen input — the handwriting edit (hedit ), boxed edit (bedit), and ink edit (iedit) controls. (The first letter of the control name is pronounced separately, as in "h-edit.")

The first two controls are designed for text input. Characters written in an hedit or bedit control are passed to one or more recognizers and interpreted as equivalent digital text. Usually, the interpreted text replaces the handwritten glyphs within the control window after the recognition finishes. The iedit control serves as a drawing area. With the exception of gestures, the iedit control does not attempt to recognize written input but merely preserves the pen data in its raw form.

An application creates a pen edit control through the Windows CreateWindow function, specifying a class of HEDIT, BEDIT, or IEDIT. The next three sections describe the pen edit controls in detail and provide examples of how to create them.


The hedit Control

Except under special circumstances, the hedit control displays two sets of text. First, the handwritten characters appear as written by the user, formed by the ink trail of the pen. When the writing is recognized, the handwritten ink disappears from the screen, replaced within the control window by the interpreted characters as determined by the recognizer. The interpreted text appears in a Windows font as though typed at the keyboard.

The following instruction creates a multiline hedit control with left justification:

hwndHedit = CreateWindow( "HEDIT", NULL,

                           ES_MULTILINE | ES_LEFT |

                           WS_CHILD | WS_VISIBLE,

                           CW_USEDEFAULT, CW_USEDEFAULT,

                           CW_USEDEFAULT, CW_USEDEFAULT,

                           hwndParent, CHILD_ID, hinstCurrent, NULL );

The styles of ES_MULTILINE and ES_LEFT do not constrain the freeform approach of handwriting in an hedit control. The user can write anywhere on the pen tablet allowed by the control — usually within or near the control window. The styles determine the format of the resulting interpreted text displayed in the control.

The hedit control is a pen-aware version of the default Windows 3.1 edit control. The hedit control not only supports handwritten characters and gestures, but also responds normally to keyboard and mouse events in the same way as an edit control. An application can use an hedit control anywhere a regular edit control will work, including dialog boxes. In fact, specifying EDIT class for a control in Windows 95 automatically creates an hedit control. The hedit control is visually identical to a standard control except that it displays a pen pointer instead of an I-beam pointer. Single-line hedit controls also display a lens button when a pen is present. When specifying an HEDIT control for a dialog box in a resource, use the DIALOGEX resource. Refer to the DIALOGEX resource description in the Win32 SDK tools documentation for a more information on using the HEDIT control class.

With a window style of ES_READONLY, an hedit window can accept no pen input. The pointer within the control does not change to a pen.

An hedit control processes tabs and carriage returns differently depending on whether they are entered as gestures or typed from the keyboard. If the user draws a tab or carriage return gesture in a multiline hedit control, the control inserts a tab or carriage return character into the text. For tabs and carriage returns entered from the keyboard, an hedit control in a dialog box mimics the standard dialog box behavior — that is, pressing the TAB or RETURN key passes control respectively to the TABSTOP or DEFPUSHBUTTON statement given in the dialog box template.


hedit Control Messages

The Pen API defines the WM_PENCTL message and its alias, WM_HEDITCTL. An application can send the WM_PENCTL message to an hedit control like this:

lRet = SendMessage( hwndHedit, WM_PENCTL, wParam, lParam );

The wParam parameter of WM_PENCTL contains an identifier for an HE_ submessage, as listed in Chapter 12, "Pen API Messages." The lParam specifies a value dependent on the HE_ submessage. For more information about the wParam and corresponding lParam values, see the entry for WM_PENCTL messages in Chapter 12, "Pen Application Programming Interface Messages."

Sizing the Writing Area with Control Messages

An hedit control must make allowances for handwriting input by providing a sufficiently large area in which to write. Typically, this area incorporates the control window itself plus an ample margin around the border of the window. Besides increasing user comfort, this extra space helps ensure parts of written characters are not inadvertently clipped, making them difficult to recognize. For example, the cut gesture X often extends above the text selected for deletion. Losing part of the gesture at the edge of the control window can make it less recognizable.

Note that adjusting a control's writing area does not change the appearance or size of the control window on the screen. It only specifies an invisible area overlaying the window; any ink within the writing area belongs to the control. It is possible, though not recommended, to enlarge the writing areas of two nearby controls so that they overlap. In this case, Windows assumes ink within the overlapping area belongs to only one of the control windows, according to normal Windows z-ordering.

The Pen API provides two methods for an application to adjust the size of the control writing area. These methods involve either receiving a PE_SETTARGETS submessage or sending an HE_SETINFLATE submessage. The following sections describe both methods.

PE_SETTARGETS Submessage

As described in the "DoDefaultPenInput Messages" section in Chapter 2, Windows sends a PE_SETTARGETS submessage to the application's window procedure before ink collection begins. This submessage gives the application the opportunity to set the target writing areas by specifying a new TARGINFO structure identified by lParam. The structure member rgTarget contains an array of TARGET structures, one for each target area. The rectangle in the rectBound member of TARGET specifies each target's writing area. The following code fragment shows how to set a writing area 4 pixels larger than the boundaries of the child window:

#define      NTARG	3               // Number of target windows

#define      MARGIN	4               // Inflation margin in pixel units

LPTARGINFO   lpti;                   // Allocate new TARGINFO structure

HWND         hwndCtl[NTARG];         // Handles to child windows

RECT         rect;                   // Bounding rectangle of child

RECTL        rectl;                  // Long version of bounding rect

HGLOBAL      h;

.

.

.

h = GlobalAlloc( sizeof( TARGINFO ) + (NTARG - 1)*sizeof( TARGET ) );

lpti = GlobalLock( h );

lpti->cbSize = sizeof( TARGETINFO );

lpti->wFlags    = 0;

lpti->htrgOwner = HtrgFromHwnd( hWnd );

lpti->cTargets  = NTARG;

for (i=0; i < NTARG; i++)

{

GetWindowRect( hwndCtl[i], (LPRECT) &rect );

rectl.left   = (LONG) (rect.left   - MARGIN);    // Inflate

rectl.top    = (LONG) (rect.top    - MARGIN);    //   rectangle

rectl.right  = (LONG) (rect.right  + MARGIN);    //   by MARGIN

rectl.bottom = (LONG) (rect.bottom + MARGIN);    //   pixel units

lpti->rgTarget[i].idTarget         = i;

lpti->rgTarget[i].htrgTarget       = HtrgFromHwnd( hwndCtl[i] );

lpti->rgTarget[i].rectBound.left   = rectl.left;

lpti->rgTarget[i].rectBound.right  = rectl.right;

lpti->rgTarget[i].rectBound.top    = rectl.top;

lpti->rgTarget[i].rectBound.bottom = rectl.bottom;

}

If the Windows DefWindowProc function handles the PE_SETTARGETS submessage, it creates a TARGINFO structure identifying all child windows as targets. DefWindowProc does not inflate writing areas; that is, it sets the writing area for each child window within the window borders.

HE_SETINFLATE Submessage

An application can also enlarge a control's writing area by sending the submessage HE_SETINFLATE to the control window specifying a RECTOFS structure:

typedef struct {

                  int  dLeft;            // Left margin

                  int  dTop;             // Top margin

                  int  dRight;           // Right margin

                  int  dBottom;          // Bottom margin

               } RECTOFS FAR * LPRECTOFS;

The RECTOFS structure does not contain the coordinates of a writing rectangle per se; instead, it contains the dimensions of the additional writing margin around the control window. The margins specify how many pixel units to add to each member of the windows rectangle. Margins conform to the x-y screen coordinate system. Thus, to inflate a writing area, specify negative values for dLeft and dTop as shown here:

#define     MARGIN    4              // Inflation margin in pixel units

RECTOFS     rectofs = { -MARGIN,     // Structure of window margins

                        -MARGIN,

                         MARGIN,

                         MARGIN};

.

.

.

wParam = HE_SETINFLATE;

lParam = (LONG)((LPRECTOFS) &rectofs);

lRet   = SendMessage( hwndHedit, WM_PENCTL, wParam, lParam );

An application can retrieve a window's current inflation margins with the submessage HE_GETINFLATE like this:

wParam = HE_GETINFLATE;

lParam = (LONG)((LPRECTOFS) &rectofs);

lRet   = SendMessage( hwndHedit, WM_PENCTL, wParam, lParam );

This call fills the RECTOFS structure pointed to by lParam with the control window's current margins.

Notification Messages

An hedit window's parent receives the same EN_ notification messages as the parent of a standard edit window. The parent receives a WM_COMMAND message in which the low-order word of the wParam parameter contains the control ID number and the lParam parameter contains the edit window handle. In 16-bit applications, the high-order word of lParam also contains the notification value. In 32-bit applications, the high-order word of wParam contains the notification. The hedit control also provides HN_ notifications, described in Chapter 12, "Pen Application Programming Interface Messages."

The hedit control also sends a WM_CTLINIT message to its parent windows when created. The wParam parameter holds the constant CTLINIT_HEDIT and lParam points to a CTLINITBEDIT structure. The structure contains the current system assumptions concerning the appearance and behavior of the hedit control. The parent window has the option of changing any of these assumptions.


Printing an Edit Control

An application can display a pen edit control in any device context by sending the control a WM_PRINT message. The message's wParam contains the HDC handle for the device context. This technique, which applies to all pen edit controls, provides a means for printing the contents of a control window.


The bedit Control

The bedit (boxed edit) control is a variation of the hedit control. All characteristics of an hedit control described in the preceding section also apply to the bedit control, with two exceptions:

•	A bedit window displays writing guides in which the user must write. Interpreted text returned from the recognizer replaces the handwritten characters within the guides.

•	A bedit control does not support edit control styles ES_READONLY, ES_CENTER, ES_LEFT, and ES_RIGHT. (Text in a bedit is left aligned.)

An application can specify guides either as a comb or as a set of boxes, as shown in Figure 3.1. The comb consists of a horizontal line with spaced tick marks. The user writes individual characters between the marks.

These visual guides can greatly improve recognition because they remove from the recognizer the significant burden of correctly segmenting the text into separate characters. For example, consider Figure 3.2, which shows a word written in an hedit control.

In this case, the recognizer would probably have difficulty choosing between the words "clean" and "dean" because of the narrow spacing between the first two strokes. The bedit control removes such ambiguities. By writing within the guides of a bedit control, the user implicitly informs the recognizer what strokes compose a single character.

For a description of how the bedit control has been improved in Windows 95, see Appendix A, "Differences Between Versions 1.0 and 2.0 of the Pen Application Programming Interface."

Windows treats characters in a bedit control as a continuous stream of text. If the control contains more than one row, text wraps at each row end without regard to word boundaries. The EM_SETWORDBREAK message has no effect on a boxed edit control.

An application creates a bedit control with the Windows CreateWindow function, specifying a window class of BEDIT. The following code shows how to create a multiline bedit control:

hwndBedit = CreateWindow( "BEDIT", NULL,

                           ES_MULTILINE | WS_CHILD | WS_VISIBLE,

                           CW_USEDEFAULT, CW_USEDEFAULT,

                           CW_USEDEFAULT, CW_USEDEFAULT,

                           hwndParent, CHILD_ID, hinstCurrent, NULL );

The BOXLAYOUT structure governs the height and style of the box grid within the bedit control. Its style member accepts one of the following BXS_ values:

Style	Description
BXS_NONE	Resets current box style to the default comb style.
BXS_RECT	Specifies a grid of closed rectangular boxes.
BXS_BOXCROSS	Specifies small crosses at the center of each box. This is used mainly to aid recognition of certain Far Eastern languages.
To set box height and style, fill a BOXLAYOUT structure with the desired values and pass it as a submessage of WM_PENCTL, as shown here:

    BOXLAYOUT boxlayout;

.

.

.

    boxlayout.cyCusp    = 6;             // Box sides are 6 pixels high

    boxlayout.cyEndCusp = 6;             // Ends should be the same

    boxlayout.style     = BXS_RECT;      // Grid of closed boxes

    iRet = SendMessage( hwndHedit, WM_PENCTL, HE_SETBOXLAYOUT,

                        (LONG)((LPBOXLAYOUT) &boxlayout) );

Refer to Chapter 11, "Pen Application Programming Interface Structures," for a more detailed description of the BOXLAYOUT structure. The next section explains how to set the system assumptions about the appearance of a bedit control.


bedit Control Messages

The bedit control sends a WM_CTLINIT message to its parent windows when created. The wParam parameter holds the constant CTLINIT_BEDIT and lParam points to a CTLINITBEDIT structure. The structure contains the current system assumptions concerning the appearance and behavior of the bedit control. The parent window has the option of changing any of these assumptions.

An application can also initialize a bedit control for a dialog box by using a DIALOGEX resource  in the dialog resource file (.RC) and specifying a CONTROL statement with a class of BEDIT or specifying a BEDIT edit control class. In this case, the control still sends the WM_CTLINIT message.  However, the CTLINITBEDIT structure reflects the specifications of the BEDIT class statement instead of the system defaults. As before, the parent window can modify the structure if desired. Refer to Chapters 11 and 12 for descriptions of the CTLINITBEDIT structure and WM_CTLINIT message, respectively. Refer to the DIALOGEX resource description in the Win32 SDK tools for more information on using the BEDIT control class.

The EM_LIMITTEXT message deserves special mention because it has changed slightly from version 1.0 of the Pen API. The message now sets the maximum number of bytes of text, rather than the number of boxes, that the control can hold. Note that although a newline character occupies only one box, the newline itself — carriage return and linefeed — takes 2 bytes. Certain Far Eastern languages also require 2 bytes per character.

Thus, the EM_LIMITTEXT message has the same effect on bedit controls as it does on hedit and edit controls. For example, the instruction

SendMessage( hwndBedit, EM_LIMITTEXT, 50, 0L );

sets to 50 the number of bytes the bedit control can accept. This has the following effects on the control:

•	If the user attempts to write the 51st byte, the control beeps and ignores the input.

•	If the user inserts text into existing text, the control beeps and ignores further input after the total number of bytes equals 50.


Using bedit Controls in Dialog Boxes

Windows determines the number of box cells that can fit within a control window based on the window dimensions and the cell widths given in a GUIDE structure. Although the Pen API does not provide a way to explicitly set the number of boxes displayed in a bedit control, an application can imply the number by adjusting the size of the control window or the size of the cells. Under certain circumstances, however, Windows may change the dimensions of a bedit control in a dialog box, thus potentially decreasing or increasing the number of box cells within the bedit.

Usually, this makes no difference to the developer or the user. But if your application must always show a specific number of boxes within a bedit, this section explains how to forestall or handle any changes.

By default, Windows sizes a dialog box and its controls based on the system font. If the dialog template requests a different font with a FONT statement and the font is not available when Windows creates the dialog box, Windows selects an available font that best matches the requested font. It then scales the dialog box and the controls within it according to the size of the selected font, but does not also scale the bedit guides. Thus, although a bedit window may change in size because of new scaling, the size of the boxes within it remain the same. For this reason, the window may end up with fewer or more cells than the programmer expects.

To ensure a bedit window always displays a specific number of cells, use one of the following techniques:

•	Remove the FONT statement from the dialog template and let Windows use the system font in the dialog box controls.

•	Specify a font likely to be always available. However, this technique cannot guarantee correct results for an application that must run under many different configurations of Windows.

•	Readjust the size of the bedit window after Windows has changed it. When processing WM_INITDIALOG, an application can call the GetWindowRect function to see whether Windows has resized the bedit control window. If so, the application can restore the window's original size with either the MoveWindow or SetWindowPos function.

Note that this technique assumes a generous blank area surrounds the control, so that if your application enlarges the control window while Windows shrinks the rest of the dialog box, the various components of the dialog box do not overlap.

•	Recalculate the GUIDE values if Windows has changed the window size.

By default, all the controls within a dialog box use the font selected for the dialog box. An application can set a different font in bedit controls within the dialog box by sending a WM_SETFONT message when processing WM_INITDIALOG.


The iedit Control

The ink edit (iedit) control provides easy formatting and manipulation of ink input. It is not designed for text input, and in this regard differs from the other two pen edit controls, hedit and bedit. Think of iedit instead as a convenient drawing area suitable for sketches, diagrams, signatures, doodling — any sort of pen input that does not need to be recognized as text. However, an application can collect handwritten text as input from an iedit control and later transfer it to an hedit or bedit control for editing, if desired, or send it to a recognizer for recognition.

An iedit control ignores most keyboard input because the user cannot type text into an iedit window. However, an iedit control supports the following keystrokes and key combinations as convenient shortcuts:

Keystroke or key combination	Effect
DEL	Delete selected strokes.
CTRL+X	Cut selected strokes to clipboard.
CTRL+C	Copy selected strokes to clipboard.
CTRL+V or CTRL+P	Paste stroke from clipboard
CTRL+A	Select all strokes.
CTRL+Z	Undo last command.
An iedit window can scroll like any other edit control. Specifying a window style incorporating WS_VSCROLL and WS_HSCROLL creates a scrollable drawing area of 32,767 by 32,767 coordinate units. Scroll bars appear on the iedit window only when ink resides outside the current visible area. This behavior mimics the Control Panel window, which displays scroll bars only when an icon lies hidden beyond the boundaries of the window.

The following sample procedure demonstrates how to use iedit to create a drawing area within a single window. After creating the main parent window, the procedure InitInstance copies the window's coordinates into a RECT structure. It then uses the results when sizing the child iedit window so that the child window entirely overlays its parent.

HWND    vhwndMain;                   // Main window

HWND    vhwndIedit;                  // iedit control window

.

.

.

BOOL InitInstance( HINSTANCE hInstance, int nCmdShow )

{

    RECT    rect;                    // Main window rectangle

    //

    // Create main window

    //

    vhwndMain = CreateWindow(

        "StylusClass",               // Window class name

        "Stylus Sample Program",     // Text for title bar

        WS_OVERLAPPEDWINDOW,         // Window style

        CW_USEDEFAULT,               // Default horizontal position

        CW_USEDEFAULT,               // Default vertical position

        CW_USEDEFAULT,               // Default width

        CW_USEDEFAULT,               // Default height

        NULL,                        // No parent

        NULL,                        // Class default menu

        hInstance,                   // Window owner

        NULL );                      // Unused pointer

    if (!vhwndMain)                  // If can't create window,

        return FALSE;                //   exit

    //

    // Create iedit control window within main window

    //

    GetClientRect( vhwndMain, (LPRECT) &rect );

    vhwndIedit = CreateWindow(

        "IEDIT",                     // Window class name

        NULL,                        // No title bar

        WS_CHILD | WS_VISIBLE |      // Window style

        WS_HSCROLL | WS_VSCROLL,

        0,                           // Overlay control window

        0,                           //   onto parent window

        rect.right - rect.left,      // Use parent width

        rect.bottom - rect.top,      //   and parent height

        vhwndMain,                   // Parent window handle

        (HMENU) CHILD_ID,            // Child ID

        hInstance,                   // Window owner

        NULL );                      // Unused pointer

    if (!vhwndIedit)                 // If problem,

        return FALSE;                //   return error code

    SetFocus( vhwndIedit );            // Give control immediate focus

    ShowWindow( vhwndMain, nCmdShow ); // Display main window

    UpdateWindow( vhwndMain );         // Force WM_PAINT message

    return TRUE;                       // Return success

}


iedit Control Messages

When created, an iedit control behaves similarly to a bedit control, as described in the "bedit Control Messages" section. The iedit sends a WM_CTLINIT message to its parent window. The message's wParam parameter contains the constant CTLINIT_IEDIT and lParam points to a CTLINITIEDIT structure. The structure contains the current system assumptions concerning the appearance and behavior of the iedit control.

An application can initialize an iedit control in a dialog box by specifying the desired attributes in an IEDIT statement in the .RC file. See "bedit Control Messages" for details. For information about the CTLINITIEDIT structure, see Chapter 11.


Ink Input

The pen edit controls discussed previously provide a simple and efficient method for an application to accept handwritten input. Pen edit controls continue the philosophy and design of a standard Windows edit control; that is, they place the burden of getting user input on the system rather than the application.

However, ink input API services also offer an application low-level control over the writing process. Ink input allows an application to gather raw data from the pen, then process it in any way it wishes. For example, the application can manage its own inking or even postpone inking to a later time. It can massage or filter the pen data in some way — say, by rotating an image based on pen movement. It can pass the data to a handwriting recognizer or simply throw the data away. Ink input offers an application greater freedom with ink data than simply parsing it for characters.

As you might expect, the increased control afforded by ink input requires increased programming effort. The flexibility of ink input does not allow a simple recipe of tasks, but in broad terms the three main steps are as follows:

1.	Start the chain of events.

2.	Collect and display data.

3.	Process the data.

An application can rely on the DoDefaultPenInput function to collect and process ink input. For a description of this function, see Chapter 2, "Starting Out with System Defaults." The following sections focus on the lowest-level API services. Through these low-level services, an application has complete control over ink input. These are the same services DoDefaultPenInput calls internally. If you have read Chapter 2, the message traffic described here will seem familiar.

The PENAPP sample application described in Chapter 7, "A Sample Pen Application," demonstrates how to use the low-level API services for ink input. Most of the code fragments in the following sections appear in the PENAPP.C source listing located in the SAMPLES\C\PENAPP directory.


Starting the Chain of Events

When an application receives a WM_LBUTTONDOWN message, that message signals the beginning of an input session. (For a definition of input session, see "Beginning an Input Session" in Chapter 2.) The following code fragment shows how to handle the message when not calling DoDefaultPenInput:

INKINGINFO   inkinfo;

PCMINFO      pcminfo;

HPCM         hpcm;

LONG         lExInfo;

int          iRet = TRUE;

.

.

.

switch (wMsg)

{

case WM_LBUTTONDOWN:	  // Pen down (maybe)

lExInfo = GetMessageExtraInfo();

if (IsPenEvent( wMsg, LOWORD(lExInfo) ) 	// If true pen down,

{	  //   take the actions

.	  //   described in the

.	  //   text below

.

}

else	  // No, it's a mouse

{	  //   button down

The application initializes a PCMINFO structure and INKINGINFO structure in preparation for data collection and display. DoDefaultPenInput handles this task automatically, then provides the application an opportunity to selectively change the default values. (For a description of the submessages PE_GETPCMINFO and PE_GETINKINGINFO, see "DoDefaultPenInput Messages" in Chapter 2.) If it does not call DoDefaultPenInput, an application must initialize the structures itself, as shown here:

#define         TIME_OUT      1000               // Time-out in msec

PCMINFO         pcm;

INKINGINFO      ink;

.

.

.

pcm.cbSize = sizeof( PCMINFO );          	       //  Required

pcm.dwPcm = PCM_TIMEOUT | PCM_RECTBOUND;        //  When to end session

pcm.dwTimeOut = TIME_OUT;                       //  Time-out value in ms

GetWindowRect( hwnd, (LPRECT) &pcm.rectBound ); //  Use window borders

ink.cbSize    = sizeof( INKINGINFO );           //  initialize

.                                           //   the INKINGINFO

.                                           //   structure "ink"

.

The above lines specify that the input session ends when the pen travels (or taps) outside the hwnd window or pauses for the number of milliseconds set by the constant TIME_OUT. For a detailed description of these structures, see the entries for PCMINFO and INKINGINFO in Chapter 11, "Pen Application Programming Interface Structures."


Collecting and Displaying Data

After initializing the necessary structures, the application calls StartPenInput to begin the process of collecting ink data:

hpcm = StartPenInput( hwnd, LOWORD (lExtraInfo),

                      (LPPCMINFO) &pcm, NULL );

The returned value hpcm is a handle to the pen collection mode — that is, the input session — that StartPenInput begins. The variable lExtraInfo is the value returned by GetMessageExtraInfo called when first processing the message WM_LBUTTONDOWN (see the preceding code fragment). Note that the StartPenInput call initiates ink collection, not ink display. The application must take separate steps to begin inking immediately after StartPenInput returns.

Inking is the process of displaying a trail of bits behind the tip of the pen as it moves across the surface of the digitizer, simulating the ink dropped by a real pen. If necessary, an application can take on the burden of real-time inking by hooking hardware interrupts with SetPenHook and calling the appropriate graphics device interface (GDI) functions to incrementally display ink. However, the Pen API provides a much simpler and more convenient method with the StartInking function.

As the PCMINFO structure governs StartPenInput, the INKINGINFO structure determines how StartInking operates. To turn on inking with StartInking, an application supplies the handle returned by StartPenInput and a pointer to the initialized INKINGINFO structure, like this:

iRet = StartInking( hpcm, LOWORD (lExtraInfo),

                    (LPINKINGINFO) &ink );

StartInking offers flexibility in how it displays ink. By modifying values in the INKINGINFO structure, an application can change ink color as the pen moves over a specified screen area or it can prevent ink from overwriting a screen object. With the wFlags member of INKINGINFO, an application can request automatic screen restoration to erase the ink. In this case, Windows replaces the ink trail with the original screen contents overwritten by the ink. This is much faster and simpler than repainting an entire window. Alternatively, an application can prevent ink erasure when pen input ends if, for example, it wants to preserve annotations or other handwritten notes on the screen. The StartInking function allows both scenarios.

When StartPenInput returns, a stream of WM_PENEVENT messages begins to arrive at the application window procedure. These messages contain submessages that represent current pen activity, such as PE_TERMINATING, PE_PENMOVE, PE_PENDOWN, and PE_PENUP. These submessages represent milestones in the system's ongoing process of collecting data from the pen driver. Each message affords an application the opportunity to gather the raw pen data that has accumulated since the last WM_PENEVENT message.

Windows maintains an internal buffer for data collection, informally named "the ten-second buffer" as a reminder of its limitations. An application should regularly drain the internal buffer by copying data from it at every opportunity afforded by the WM_PENEVENT messages. If it responds to no other event, the application must at least collect data when it receives the PE_BUFFERWARNING submessage, which indicates the internal buffer is more than half full.

To gather the data, an application calls GetPenInput. This can be done either in a polling model or in an event-driven model.

In the polling model, the application must repeatedly call GetPenInput to get data. It is important for the application to yield periodically; for example, by calling the PeekMessage function. A fast loop can potentially process the points before the system can collect more. In this case, successive calls to GetPenInput return 0 until the user writes some more. Polling is typically terminated when GetPenInput detects and returns a termination condition specified in StartPenInput.

In the event model, the application calls GetPenInput in response to each WM_PENEVENT message. The following fragment shows a typical message handler that accumulates ink coordinates in an array of POINT structures. The example assumes StartPenInput has already been called:

POINT       rgPt[MAX_POINTS];            // Array of POINT structures

STROKEINFO  si;                          // Receives pen stroke info

.

.

.

switch (wParam)                          // Process WM_PENEVENT message

{

case PE_PENDOWN:                     // On any of these events,

case PE_PENMOVE:                     //   get all points currently

case PE_PENUP:                       //   in the internal buffer

case PE_TERMINATING:

case PE_BUFFERWARNING:

GetPenInput( hpcm, (LPPOINT) rgPt, NULL, NULL,

                      MAX_POINTS, (LPSTROKEINFO) &si );

//

// Latest batch of pen coordinates is now collected

// into rgPt array.  At this point, the coordinates can be:

//	(1) Passed to a recognizer (or recognizers)

//	(2) Passed to a target or control

//	(3) Placed into an HPENDATA object

//

.

.

.

break;

case PE_TERMINATED:

// Input session has ended. Do any required

// clean-up work and display the results.

.

.

.

break;

The example continually calls GetPenInput while the pen is in motion until it receives a PE_TERMINATING submessage, indicating the data flow is about to stop. Windows sends a PE_TERMINATING message when it detects one of the termination conditions specified in the PCMINFO structure. Typically, the input session ends when the user taps the pen outside a given tablet area or when a specified period of pen inactivity elapses.

An application may need to call StopPenInput to stop further data collection. The call to StopPenInput is not necessary if the input session ends because of a condition defined in the PCMINFO structure. In this case, the system calls StopPenInput internally. However, if the application terminates the input session for any other reason, it must call StopPenInput explicitly. Unless your application defines all possible termination conditions in a PCMINFO structure, it should call StopPenInput on detection of a condition that requires termination. Even if the system has already called the function, subsequent calls do no harm.

The preceding description also applies to StopInking, provided the application has called StartInking to display ink. The system calls StopInking automatically if it detects one of the termination conditions defined in the PCMINFO structure; otherwise, the application should call StopInking explicitly when required.


Processing the Data

The GetPenInput function accumulates the coordinates of the pen stroke in an array of POINT structures and places information about the stroke in a STROKEINFO structure. This data is "raw" in that it represents a literal history of the pen movement. Some applications will require no more than this. However, further processing of the raw data using other functions of the Pen API usually requires placing the data into an HPENDATA or HRC object.

The next two chapters examine these objects thoroughly and continue the code fragment outlined previously. Chapter 4, "The Inking Process," describes how an application can alter or manipulate ink data with an HPENDATA object. Chapter 5, "The Recognition Process," describes the HRC object, which pertains solely to handwriting recognition.


The On-screen Keyboard

The hedit and bedit controls automatically provide user access to the on-screen keyboard. In other situations, an application can display the on-screen keyboard as required by calling the ShowKeyboard function.

Besides displaying and hiding the on-screen keyboard, ShowKeyboard can also move and minimize the display and select different keyboard types. For a detailed description of the capabilities of ShowKeyboard, see Chapter 10, "Pen Application Programming Interface Functions." For other considerations concerning ShowKeyboard, see the "Recognition: Use and Misuse" section in Chapter 6.


The Inking Process

This chapter introduces the inking process, in which an application collects and manipulates ink data written by the user. The inking process is a logical next step from the writing process, described in the preceding chapter. In the writing process, the application provides the means for the user to enter ink. In the inking process, the application assembles the ink data, optionally modifies it, and applies it to some task.

The inking process pertains to ink data collected for its own sake rather than immediately passed on to a recognizer for interpretation. Although an application can later submit gathered data to a recognizer, the inking process deals with ink that "stays ink" rather than serving as transitory symbols immediately converted into recognized characters.

The HPENDATA data object serves as the major instrument in the inking process. The first part of this chapter describes HPENDATA and the various application programming interface (API) functions that serve it. Example code fragments throughout illustrate how to store and manage ink data with the HPENDATA services.

An application can refer to the data in an HPENDATA object by stroke and point indices, or time intervals. For viewing and manipulating ink data that falls within specified time intervals, the Pen API provides the HINKSET object. The last section of this chapter, "The HINKSET Object," examines HINKSET and its corresponding API functions.


The HPENDATA Object

An application accesses ink data with HPENDATA, which stands for "a handle to pen data." Windows stores the pen data in a block of memory, called the HPENDATA object. This data structure is analogous to the other Window "H" data types such as HDC, HCURSOR, and HPEN. HPENDATA shares certain similarities with these data types:

•	The handle references an internal data structure that resides in memory.

•	Windows provides various API functions that operate on the data.

•	Developers should ignore the details of the underlying data structure and use the API functions alone to perform the required work.

The remainder of this chapter discusses the HPENDATA object and the API functions used to manipulate the data it contains.


Overview of HPENDATA

Windows allocates the HPENDATA object with an internal call to the Windows GlobalAlloc function. Other Windows data objects are allocated from the USER or GDI heaps, but the large size of an HPENDATA object necessitates allocation from the system global heap.

Windows imposes a 64K limit on the size of each HPENDATA object. At a report rate of 120 samples per second, at 4 bytes per data point, plus some overhead data structures, minus the time the pen is not in contact with the surface of the tablet, a single HPENDATA object can contain the data representing roughly two and one-half minutes of pen activity.

The following section describes the internal structure of an HPENDATA memory block. Though not recommended, your application can use this information to read ink data if necessary. However, the internal structure of the HPENDATA block may change in future versions of Windows. Therefore, applications should always use standard API functions to read from an HPENDATA object.

Important  Under no circumstances should an application write directly into an HPENDATA block. The Pen API provides functions for modifying ink data safely. Directly changing point data in the block can cause hazardous side effects.


Data Within an HPENDATA Object

Figure 4.1 illustrates the internal structure of an HPENDATA object.

Windows stores the pen data in memory in a simple hierarchy. Data points are grouped by strokes in the order in which they are entered. The HPENDATA block of memory begins with a descriptive header area. The following sections describe the data points, the stroke headers, and the main header that make up an HPENDATA object.

Note that the drawing in Figure 4.1 is not to scale. The data points generally represent a much larger proportion of the memory block than the header components.


Data Points

The data points associated with each stroke are initially tablet coordinates with a resolution of 0.001 inch and an origin at the upper left corner of the tablet. Tablets must report points in this scale regardless of their actual resolution. The Pen API provides functions to scale the points to other metric systems. It is not necessary for the data in an HPENDATA object to remain at a resolution of 0.001 inch.

If Windows is running in portrait mode, the tablet still reports coordinates with the upper left corner of the tablet corresponding to the current upper left corner of the display. The developer need not be concerned with the current orientation of the screen. The (0,0) coordinate of the Windows display always corresponds to (0,0) on the tablet.

The HPENDATA object can contain additional information supported by the pen device, such as pen pressure, angle, and rotation. The main header section of the HPENDATA object specifies how this additional information is stored in the stroke data areas for each data point. Internally, such data, which reflects original equipment manufacturer (OEM) hardware, is stored immediately following the block of coordinates for a stroke. This is called OEM data.


Stroke Headers

A stroke refers to the data points collected while the pen is in contact with the tablet. These are called pen-down points. When the user lifts the pen, the stroke ends. A new stroke begins when the pen next touches the tablet. Some tablets also support proximity strokes, which consist of points received when the pen is not in contact with the tablet but near enough for the tablet to sense the pen movement. Such points are called pen-up points; a stroke consisting of pen-up points is said to have a pen-up state.

As Figure 4.1 shows, a stroke header prefaces each collection of pen coordinates that make up a single stroke. Note that the structure of the stroke header in version 2.0 of the Pen API is different from the stroke header of version 1.0, because, instead of the STROKEINFO structure used in version 1.0, the stroke header now consists of a variable-length array . The current STROKEINFO structure is still compatible with version 1.0 stroke headers.

Figure 4.1 shows strokes of different sizes. This is because the pen can be in contact with the surface of the tablet for longer or shorter periods of time, resulting in more or fewer points of data. The length of a single stroke is limited only by the 64K maximum size of an HPENDATA memory block.


Main Header

A PENDATAHEADER structure is the first part of the main header of the HPENDATA object. The PENDATAHEADER structure, described in Chapter 11, "Pen Application Programming Interface Structures," contains the following information:

•	Number of strokes

•	Total number of points

•	Number of points in longest stroke

•	Size in bytes of the memory block

•	Bounding rectangle of all pen-down points

•	Ink color

•	Ink width

•	Version

The wPndts member of the PENDATAHEADER structure describes the state of the data in the HPENDATA object. The state of the data reflects whether the data is compressed, includes pen-up points, or includes OEM data. The wPndts element is a bitwise-OR combination of the PDTS_ flags described in Chapter 13, "Pen Application Programming Interface Constants."

The next component in the main header is a PENINFO structure. The PENINFO structure contains information about the tablet device that produced the data. This information includes the tablet width, height, resolution, report rate, proximity capabilities, and barrel-button status. For more information about the PENINFO structure, see Chapter 11, "Pen Application Programming Interface Structures."

The cbOemData member of the PENINFO structure specifies how much (if any) OEM pen data each pen packet contains. The format and order of the extra OEM information are contained in the rgboempeninfo member, which is an array of OEMPENINFO structures. The OEMPENINFO structures describe the order, minimum value, and scale of any OEM pen data the tablet reports along with the coordinate data. Chapter 11 describes the OEMPENINFO structure in detail.


HPENDATA Functions

This section introduces the Pen API functions that manipulate ink data in an HPENDATA object. The recognition functions described in the next chapter apply to a specific task — the recognition of text. The HPENDATA functions, however, are not so easily summed up. They are building blocks for an infinite variety of tasks, according to the requirements and imagination of the developer. For this reason, the best introduction to the HPENDATA functions is a simple list of their capabilities.

The following subsections group the functions into six categories and provide a brief description of each function. These subsections serve only as an introduction to the HPE NDATA functions. For complete details about the functions, see the appropriate reference sections in Chapter 10, "Pen Application Programming Interface Functions." To see some of the HPENDATA functions in use, refer to the PENAPP sample program presented in Chapter 7, "A Sample Pen Application."

The six categories of the HPENDATA functions are:

•	Creating an HPENDATA object

•	Displaying ink data

•	Scaling ink data

•	Examining ink data

•	Editing or copying ink data

•	Compressing ink data

The order in which functions appear in the following lists reflects either a logical sequence of discussion or, where such criteria do not exist, simple alphabetic ordering. The order does not imply relative importance of the functions.


Creating an HPENDATA Object

The Pen API provides five functions that allocate and free an HPENDATA object. These functions are similar to many Windows data types.

Note  It is recommended that you use only the functions from version 2.0 of the Pen API. Although API from version 1.0 are included for backward compatibility, it is not guaranteed that they will be supported in future versions of the Pen API.

The functions that allocate and free HPENDATA objects are as follows:

Function	Description
CreatePenData	Creates an empty HPENDATA object. The application provides the PENINFO structure for the header, the real size of any OEM data stored with each coordinate, and the scale of the coordinates. Superseded by CreatePenDataEx.
CreatePenDataEx	Creates an empty HPENDATA object. This function is an enhanced version of CreatePenData that provides an application with greater control over the contents of the HPENDATA object.
CreatePenDataHRC	Returns a handle to an HPENDATA object copied from an HRC object. Since this call creates a new HPENDATA, the application should free the object when finished by calling DestroyPenData, described below. The AddPenDataHRC function reverses the process by copying pen data to an HRC object. Chapter 5, "The Recognition Process," describes the HRC object.
DuplicatePenData	Duplicates an HPENDATA object, allowing an application to create clones of existing pen data. Since this call creates a new HPENDATA, the application should free the object when finished by calling DestroyPenData, described below.
DestroyPenData	Frees the heap memory occupied by the HPENDATA block. If the function returns TRUE, the handle to the object is no longer valid and should be set to NULL.


Displaying Pen Data

The Pen API provides four functions for displaying the pen data contained in an HPENDATA object. An additional function, CreatePenDataRegion, determines the screen area necessary to display the pen data. This enables an application to determine the screen area affected by a gesture.

The following table describes the API drawing functions:

Function	Description
DrawPenData	Draws pen data in the specified device context using the Windows GDI Polyline function. The ink width and color specified in the PENDATAHEADER structure have no effect on how DrawPenData renders the ink. The rendering of the ink data produced by DrawPenData generally does not exactly match the rendering produced by the display driver when the data was first collected. An application that requires an exact replication of the original ink rendering should call the RedisplayPenData function.
DrawPenDataEx	Draws pen data in its original color or in a given device context. This function is an enhanced version of DrawPenData. Besides basic drawing capabilities, DrawPenDataEx can control the speed at which the data is rendered, a process called animation. This function can also draw a selected subset of strokes or the points within a stroke, rather than the entire pen data. DrawPenDataEx can display a set of sequential strokes with a single call. Drawing nonsequential strokes — say, the second, fifth, and eighth strokes of the pen data — requires separate calls to DrawPenDataEx for each stroke.
DrawPenDataFmt	A macro function that simplifies calls to DrawPenDataEx by specifying: • Rendering ink data in original ink attributes and speed (no animation). • Entire data set is drawn (no stroke subsets). • Each stroke is drawn with the color and width specified in the stroke header.
RedisplayPenData	Draws pen data ink that exactly matches the original rendering. RedisplayPenData displays pen data with a square GDI pen brush for maximum drawing speed. When displaying wide lines of ink, this optimization can cause the ends of abutting lines to appear "blocky."
CreatePenDataRegion	Returns a region of the screen required to show the contents of an HPENDATA object. Another call to the GDI function GetRgnBox returns the bounding rectangle that holds the region. (See also the description of GetPenDataAttributes, which can return the bounding rectangle for the entire set of pen data.) The application should call the Windows function DestroyObject to free the region when finished.


Scaling Pen Data

The Pen API provides three functions to transform or scale pen data in an HPENDATA object. The related functions TPtoDP and DPtoTP do not operate explicitly on an HPENDATA object, but instead convert the resolution of an array of points.

Function	Description
MetricScalePenData	Converts pen coordinates between metric and English standard measurements. Metric units are 0.1 and 0.01 millimeter; English standard units are 0.001 inch. These scaling metrics comply with the mapping modes set in the Windows function SetMapMode, described in the Windows Software Development Kit. MetricScalePenData can also convert pen data to display resolution. See "Converting Data to Display Resolution" later in this chapter.
OffsetPenData	Offsets the coordinates in an HPENDATA object to make them relative to another origin. The function adds or subtracts offset values to or from the coordinate points. The offset values must use the same units as the pen data. Offsetting coordinates does not lose data. The process is completely reversible and does not reduce recognition accuracy.
ResizePenData	Scales ink into arbitrarily sized rectangles. This function exhibits the same weakness as the other scaling functions. It preserves rectangle proportions, but rounding errors prevent the scaling process from being precisely reversible. However, enlarging the ink data generally does not adversely affect recognition accuracy for data later given to a recognizer.


Examining Pen Data

The following functions enable an application to examine, directly modify, or retrieve information from an HPENDATA object:

Function	Description
BeginEnumStrokes GetPenDataStroke EndEnumStrokes	These three functions work in tandem. Together, they enable an application to directly read an HPENDATA block in memory. Use these functions with caution and only for reading pen data. Do not attempt to write into an HPENDATA block. BeginEnumStrokes returns a far pointer to the HPENDATA memory block within the global heap. GetPenDataStroke retrieves pointers to point data within the HPENDATA. Although an HPENDATA block no longer prefaces strokes with STROKEINFO structures, GetPenDataStroke can retrieve a STROKEINFO structure corresponding to any stroke within the block. When the application has finished with the memory block, it must call EndEnumStrokes. This unlocks the block in the global heap and invalidates the pointers returned by GetPenDataStroke. For this reason, an application must not use the pointers once it has called EndEnumStrokes.
GetPenDataInfo	Retrieves summary information from the pen data memory block. It is superseded by the GetPenDataAttributes function to some extent.
GetPenDataAttributes	Provides enhanced versions of some of the capabilities of GetPenDataInfo. It also provides additional detailed information taken from the HPENDATA block. For example, GetPenDataAttributes can return • The total number of points in the HPENDATA • The total number of strokes • The time the HPENDATA was created • The device sampling rate
GetStrokeAttributes SetStrokeAttributes	Retrieve or set information about a given stroke in an HPENDATA object. For example, these functions can get or set • The pen state (up or down) for a stroke • The ink color and width • The absolute time the stroke occurred
GetStrokeTableAttributes SetStrokeTableAttributes	Retrieve or set information about all strokes in an HPENDATA object that share a given class. For all such strokes, these functions can get or set: • The ink color and width. • The user value. • The number of entries in the stroke table.
HitTestPenData	Determines whether a given point lies near the line of a stroke. The function accepts a threshold value that describes a square region around the given point on the tablet or screen. If a stroke in an HPENDATA block passes through the square, this function reports a "hit." HitTestPenData considers only points with a pen-down state.


Editing or Copying Pen Data

The functions listed below add, delete, or copy coordinate data to and from an HPENDATA object.

An empty HPENDATA object has the following value for the wPndts member of its PENDATAHEADER structure:

PDTS_NOUPPOINTS | PDTS_NOCOLLINEAR | PDTS_NOEMPTYSTROKES

For a full list of PDTS_ values, see Chapter 13, "Pen Application Programming Interface Constants." See Chapter 11 for a description of PENDATAHEADER.

Functions in the following list with a name prefix of Add, Insert, Extract, or Remove add to or delete from an HPENDATA object. These functions check the results of their operation and adjust the value in wPndts accordingly.

Function	Description
AddPenDataHRC	Copies the pen data from an HPENDATA object to an HRC object. This function provides the means for deferred recognition. An application can gather pen data into an HPENDATA block, manipulate or store it if desired, then later copy the data to an HRC object for recognition.
AddPointsPenData	Appends a set of points, including a STROKEINFO structure and any corresponding OEM data, to an HPENDATA object.
ExtractPenDataPoints	Copies points and OEM data from an HPENDATA block to supplied buffers. The application can convert the points to screen resolution with the TPtoDP function to reduce the buffer size. The application can also optionally delete these points from the original pen data.
ExtractPenDataStrokes	Copies selected strokes from an HPENDATA block, optionally creating a new HPENDATA block containing the copied strokes. ExtractPenDataStrokes can optionally delete the original strokes.
GetPointsFromPenData	Retrieves information from an HPENDATA object in a way similar to the GetPenDataStroke function. However, GetPointsFromPenData copies the required data to buffers supplied by the application rather than simply returning pointers to the original data in the global heap. Therefore, the application need not call BeginEnumStrokes and/or EndEnumStrokes when using GetPointsFromPenData.
InsertPenData	Merges two separate HPENDATA objects into a single object.
InsertPenDataPoints	Inserts points into the stroke of an existing HPENDATA object. InsertPenDataPoints automatically updates the stroke and pen data headers. This function can adversely affect recognition accuracy for data that must later be recognized.
InsertPenDataStroke	Inserts an entire stroke into an existing HPENDATA object. InsertPenDataStroke automatically updates the stroke and pen data headers. The ink of the inserted stroke has default color and width. To change these attributes, call SetStrokeAttributes after inserting the stroke.
PenDataToBuffer PenDataFromBuffer	Copy an HPENDATA object as sequential data from and to a buffer. PenDataFromBuffer creates and loads an HPENDATA object with the data from the sequential buffer created by PenDataToBuffer. These functions are used to transfer pen data to and from a file or the clipboard.
RemovePenDataStrokes	Deletes a contiguous set of strokes from an HPENDATA object.


Compressing Pen Data

Data compression plays an important role in pen-based computing. The high sampling rates of a pen device, combined with large amounts of input, result in large blocks of ink data. The Pen API offers three methods of compression, each with advantages and disadvantages depending on the intended use of the ink data.

•	Removal of redundant or otherwise unwanted data from the data structure. This compression method does not result in loss of recognition accuracy if the compressed data is later recognized.

•	Reversible compression, also called "lossless" compression. Subsequently decompressing the data produces an HPENDATA object identical to the original. Since this compression method loses no information, the data can later be recognized with no loss of accuracy. However, the application cannot copy the compressed data to an HRC object; it must first uncompress the data before calling AddPenInputHRC.

•	Irreversible compression, sometimes called "lossy" compression. This method produces the highest degree of compression, but at the cost of lost information. Though the data is still perfectly suitable for display, it cannot be uncompressed and given to a recognizer without a significant loss of recognition accuracy. Irreversible compression is discussed later in the section "Converting Data to Display Resolution."


Compression Functions

Following are the three compression functions provided by the Pen API.

Function	Description
CompactPenData	Provided only for compatibility with version 1.0 of the Pen API and may not be supported in future versions. Use the functions CompressPenData and TrimPenData instead.
CompressPenData	Primary function used to compress and uncompress pen data.
TrimPenData	Removes selected data from an HPENDATA object to reduce the size of the memory block. For example, TrimPenData can remove OEM information, timing indexes, pen-up points, and so forth.


Converting Data to Display Resolution

Converting the points in an HPENDATA block to display resolution effectively compresses the data because display coordinates are coarser than tablet coordinates and therefore occupy less memory. However, the conversion is irreversible; an application cannot convert the points back to their original tablet resolution. Moreover, converting to display coordinates virtually disallows subsequent recognition of the data because recognizers lose accuracy when dealing with data at coarse screen coordinates.

To compress pen data to screen resolution

1.	Call MetricScalePenData to convert the ink data from tablet coordinates to display coordinates.

2.	Call TrimPenData with the TPD_COLLINEAR flag to remove the duplicate and collinear points.

These two steps substantially reduce the number of points in the pen data by removing many high-resolution digitizer points. The following code fragment demonstrates these steps:

HPENDATA	hpendata;	// Handle to HPENDATA object

.

.

.

if (MetricScalePenData( hpendata, PDTS_DISPLAY ))

iRet = TrimPenData( hpendata, TPD_COLLINEAR );

After converting the HPENDATA block to display resolution, the application can call CompressPenData or TrimPenData to compress the points even more. For maximum compression of data intended only for display, use the following instructions instead of the preceding example:

if (MetricScalePenData( hpendata, PDTS_DISPLAY ))

if (TrimPenData( hpendata, TPD_EVERYTHING ) == PDR_OK)

CompressPenData( hpendata, CMPD_COMPRESS );


The HINKSET Object

An inkset object consists of time intervals for either individual strokes or a collection of strokes. In turn, the interval of each stroke consists of the times at which the stroke begins and ends. In this way, a pen-based application can refer to a stroke not only by the points it contains but also by the time interval in which the stroke occurs. A rough analogy of this sort of indirect referencing is the way some programming languages allow the use of pointers to indicate data.

Timing information principally serves recognizers. It provides them with an additional characteristic of the raw data that may offer clues for interpretation.

Timing information has other uses, as well. For example, it enables an application to accurately verify a signature by comparing not only the coordinates but the duration of each stroke against a copy of the original signature. This is an effective safeguard against forgery because of the difficulty of simultaneously duplicating both the pattern and duration of the original signature.

An HINKSET object can contain up to 5,460 intervals. An interval is expressed as an INTERVAL structure, which consists of two ABSTIME structures. Each INTERVAL structure identifies a stroke's start and stop times in milliseconds. See the appropriate reference sections in Chapter 11 for type definitions of the ABSTIME and INTERVAL structures.


The HINKSET Functions

The Pen API provides six functions for creating, adding data to, and destroying an HINKSET object. The functions automatically ensure intervals within an inkset remain in chronological order.

Function	Description
CreateInkset	Creates an empty inkset into which intervals can be added with the AddInksetInterval function.
CreateInksetHRCRESULT	Retrieves the intervals for a specified series of symbols returned by the recognizer.
AddInksetInterval	Adds a single INTERVAL structure to an existing HINKSET object. Intervals need not be added in any particular order because AddInksetInterval automatically sorts the intervals chronologically and merges overlapping intervals.
GetInksetInterval	Copies a series of intervals from an HINKSET object to an array of INTERVAL structures.
GetInksetIntervalCount	Returns the number of intervals in an HINKSET object.
DestroyInkset	Frees the memory occupied by an HINKSET object and invalidates its handle.


Timing Information

For uncompressed data, a stroke's interval implies the number of points in the stroke. An application can obtain this number directly from a STROKEINFO structure. The following is of academic interest only, illustrating how time intervals correspond to the point data within a stroke.

First, an application gets the device sampling rate with a call to GetPenDataInfo. The sampling rate is the number of points the pen device driver sends to Windows during each second of pen activity.

HPENDATA        hpndt;

PENINFO         peninfo;

int             nSamplingRate;

.

.

.

if (GetPenDataInfo( hpndt, NULL, (LPPENINFO) &peninfo, 0 ))

    nSamplingRate = peninfo.nSamplingRate;

Alternatively, an application can query the pen device driver directly for the sampling rate, as described in "Recognition Functions" in Chapter 8, "Writing a Recognizer."

The number of points in a stroke can now be determined from the start and stop times in the stroke's INTERVAL structure:

INTERVAL        interval;

int             nSamplingRate, nPoints, nms;

.

.

.

// Compute number of milliseconds in interval

nms = ((interval.atEnd.sec - interval.atBegin.sec) * 1000) +

       (interval.atEnd.ms - interval.atBegin.ms);

// Compute number of points that occurred during interval

nPoints = (nms * nSamplingRate) / 1000;

After recognition, an application can determine the time intervals at which recognized symbols were written. Calling CreateInksetHRCRESULT creates the inkset for the required intervals:

HINKSET     hinkset;             // Allocate the inkset

HRCRESULT   hresult;             // Symbols for guesses go here

.

.

.

// Get symbols that make up the recognizer's best guess

GetResultsHRC( hrc, GRH_ALL, (LPHRCRESULT) &hresult, 1 );

// Get the inkset for symbols 2 through 11 of the guess

hinkset = CreateInksetHRCRESULT( hresult, 2, 10 );

The above code fragment creates an inkset containing a maximum of 10 intervals corresponding to the second through eleventh symbols of the recognizer's best guess. The section "Unboxed Recognition"  in the next chapter describes the GetResultsHRC function in detail. For a description of the internal workings of CreateInksetHRCRESULT, see "The Recognition Functions" in Chapter 8, "Writing a Recognizer."


Timing Macros

The PENWIN.H file defines several macro functions designed to deal with timing information. The following reference section briefly describes these macros.


dwDiffAT

dwDiffAT( at1, at2 )

Compute time difference in milliseconds between two ABSTIME (absolute time) structures at1 and at2. If at2 is more than at1, the result is positive.

Example

x = dwDiffAT( at1, at2);	// Get time difference in milliseconds


dwDurInterval

dwDurInterval( lpi )

Calculate the duration in milliseconds of the INTERVAL structure lpi points to.

Example

x = dwDurInterval( lpi );	// Get duration in milliseconds


FAbsTimeInInterval

FAbsTimeInInterval( at, lpi )

Test whether the time in the ABSTIME structure at is contained within the time interval in the INTERVAL structure pointed to by lpi.

Example

if (FAbsTimeInInterval( at, lpi ))	// TRUE if at within INTERVAL


FIntervalInInterval

FIntervalInInterval( lpiT, lpiS )

Test whether the time interval in the INTERVAL structure pointed to by lpiT is within the INTERVAL structure pointed to by lpiS.

Example

if (FIntervalInterval( lpiT, lpiS ))	// TRUE if lpiT within lpiS


FIntervalXInterval

FIntervalXInterval( lpiT, lpiS )

Test whether the time interval in the INTERVAL structure pointed to by lpiT overlaps the INTERVAL structure pointed to by lpiS.

Example

if (FIntervalXInterval( lpiT, lpiS ))	// TRUE if lpiT overlaps lpiS


FLTAbsTimeFLTEAbsTime
FEQAbsTime

FLTAbsTime( at1, at2 )

FLTEAbsTime( at1, at2 )

FEQAbsTime( at1, at2 )

Compare two ABSTIME structures at1 and at2. These macros return TRUE for the following conditions: less than, less than or equal, and equal.

Example

if (FLTAbsTime( at1, at2 ))   // TRUE if at1 < at2

if (FLTEAbsTime( at1, at2 ))  // TRUE if at1 <= at2

if (FEQAbsTime( at1, at2 ))   // TRUE if at1 == at2


MakeAbsTime

MakeAbsTime( lpat, sec, ms )

Initialize the ABSTIME structure pointed to by lpat with the values sec and ms.

Example

sec = 5;                         // Time = 5.4 seconds (5 seconds

ms  = 400;                       //   plus 400 milliseconds)

MakeAbsTime( lpat, sec, ms );    // Fill ABSTIME structure


The Recognition Process

Recognition is the process of translating pen strokes into characters, symbols, or shapes. An application conducts recognition by passing the raw pen data to special dynamic-link libraries (DLLs) called recognizers, each of which may specialize in a particular data type. For example, one recognizer may specialize in English text, another in Greek, and yet another in electronic symbols.

The system default recognizer serves the recognition needs of most applications. Alternatively, applications can load additional recognizers and select which to use for any given input. Regardless of the recognizer, the DoDefaultPenInput function can conveniently run the entire recognition process.

An application interfaces with recognizers through a data object called HRC, an abbreviation for "handle to a recognition context." This chapter describes the HRC and explains how an application uses the HRC functions to recognize pen-based handwriting.


The HRC Object

The HRC object incorporates a set of functions, called the HRC functions, that govern the recognition process. To conduct handwriting recognition, an application creates an HRC object, configures its recognition parameters, sends pen data to the object, gives the object time to perform recognition, and eventually gets results from the object.

An HRC object provides four different functions, serving as:

•	Recognition manager, containing the word lists, templates, alphabets, and GUIDE information that aid recognition.

•	Data storage, containing the pen coordinates placed into the object with the AddPenInputHRC or AddPenDataHRC functions. An application can retrieve the entire set of pen data stored in the HRC object or only a portion. For example, it can retrieve only the ink associated with a specific letter or word in the recognized text.

•	Recognition workhorse, handling the task of recognition through the ProcessHRC function.

•	Results warehouse, storing recognition results and guesses.


Using the HRC Functions

The following sections describe how an application uses the HRC functions to recognize handwritten input as the user writes. The text builds on the steps given in "Starting the Chain of Events"  in Chapter 3, "The Writing Process;" refer to that section for more details on each step in the process. The following sections deal with five separate areas of the recognition process:

•	Creating the HRC

•	Configuring the HRC

•	Processing

•	Getting results

•	Destroying the HRC and other recognition objects


Creating the HRC

Before recognition can occur, the application must create an HRC object. DoDefaultPenInput does this automatically for the system recognizer, or an application can call the CreateCompatibleHRC function to specify another recognizer. CreateCompatibleHRC takes two arguments: a handle to an existing HRC (if any) that serves as a template for the new HRC, and the handle to the recognizer that serves the new HRC.

Either or both arguments can be NULL. Giving NULL as the first argument creates a new HRC with default settings. The next section, "Configuring the HRC," describes the default parameters, which include the following settings:

•	Recognition ends after a brief period of inactivity or when the user taps outside the target window.

•	The target window does not use guides.

•	The recognizer returns only its best guess without alternative guesses.

Giving NULL as the second argument binds the HRC to the system default recognizer. Microsoft Windows sets the supplied file GRECO.DLL as the system default recognizer, specified in the Microsoft Windows 95 system registry. Refer to Appendix A for an explanation of how to change the default to another recognizer.

CreateCompatibleHRC, which is analogous to CreateCompatibleDC, copies configuration information from an existing HRC to the new HRC, which the application can then modify. The following fragment demonstrates how to load a fictitious recognizer called RECOG1.DLL and bind it to a new HRC patterned after an existing HRC called hrcTemplate:

HRC     hrc1;                       // Handle to new HRC

HREC    hrec1;                      // Module handle of recognizer

.

.

.

hrec1 = InstallRecognizer( "RECOG1.DLL" );

if (hrec1)

hrc1 = CreateCompatibleHRC( hrcTemplate, hrec1 );

Each HRC can access only one recognizer and the binding lasts the life of the HRC. To use multiple recognizers, an application must create multiple HRC objects, binding each to a different recognizer. The Pen API does not provide a means for changing the recognizer associated with an HRC.

As shown in the example above, an application must call InstallRecognizer to load any other recognizer it will use. The exception is the system default recognizer, which is already installed when the system starts up. An application should not install the system recognizer with InstallRecognizer. Doing so only creates an unnecessary module handle.

To preserve system resources, an application must free all handles obtained from InstallRecognizer with separate calls to UninstallRecognizer. Unlike other DLLs, a recognizer belongs to the system instead of the application. Windows does not unload the recognizer from memory until every client has called UninstallRecognizer.

Once it receives a valid HRC handle, the application can begin configuring the HRC to perform handwriting recognition.


Configuring the HRC

Before passing data to the HRC, the application must ensure the HRC is properly configured to perform recognition. The configuration information in an HRC provides a context to guide the recognition process. For example, if the application expects only numerical input, it can configure the HRC accordingly. This prevents the recognizer from mistakenly confusing the numeral "0" for the letter "O."

A new HRC shares the same configuration as the template HRC given when calling CreateCompatibleHRC. If the application does not provide a template for CreateCompatibleHRC, the new HRC receives a default configuration.

The following paragraphs describe the various configurations an application can set for an HRC object.


Alphabet

The SetAlphabetHRC function specifies a set of symbols the HRC should expect in the input. (A similar function, SetBoxAlphabetHRC, provides the same service for a group of boxes when the HRC uses guides.) For example, the application can constrain recognition to numerals and uppercase letters, as shown here:

iRet = SetAlphabetHRC( hrc1, ALC_NUMERIC | ALC_UCALPHA, NULL );

For more details about SetAlphabetHRC and SetBoxAlphabetHRC, see Chapter 10, "Pen Application Programming Interface Functions."

The first argument of SetAlphabetHRC is the HRC handle returned by CreateCompatibleHRC. The second argument is a bitwise-OR value formed by the desired combination of ALC_ constants, some of which are listed here:

Alphabet constant	Description
ALC_DEFAULT	Default alphabet value for recognizer. If recognizer can serve as a system recognizer, its default alphabet must include at least the ALC_SYSMINIMUM set. The Pen API does not specify a default for nonsystem recognizers.
ALC_LCALPHA	Lowercase letters: a−z.
ALC_UCALPHA	Uppercase letters: A−Z.
ALC_NUMERIC	Numerals: 0−9.
ALC_ALPHANUMERIC	Combines ALC_LCALPHA, ALC_UCALPHA, and ALC_NUMERIC.
ALC_PUNC	Punctuation: !-;`"?()&.,;\.
ALC_MATH	Math symbols: %^*()-+={}<>,/.
ALC_MONETARY	Monetary symbols: ,.$ (or as determined by language).
ALC_OTHER	Other special characters: @#|_~[].
ALC_ASCII	Seven-bit characters ASCII #20 to ASCII #127.
ALC_WHITE	White space such as tabs and newline and space characters.
ALC_NONPRINT	TAB, ENTER, and CTRL keys.
ALC_SYSMINIMUM	Combines ALC_ALPHANUMERIC, ALC_PUNC, ALC_WHITE, and ALC_GESTURE.
If an application does not specify alphabet configuration either through an existing HRC model or by calling SetAlphabetHRC or SetBoxAlphabetHRC, Windows assumes ALC_SYSMINIMUM as the default alphabet configuration. For a complete list of ALC_ values, see Chapter 13, "Pen Application Programming Interface Constants."


Gesture

A default HRC enables all gestures. An application can disable certain gestures by calling the EnableGestureSetHRC function to change the gesture configuration for the HRC. The following example disables the gestures for cut, copy, and paste while enabling all other gestures:

iRet = EnableGestureSetHRC( hrc1, GST_ALL ^ GST_CLIP, TRUE );

For more information about EnableGestureSetHRC, see the reference section in Chapter 10, "Pen Application Programming Interface Functions."

The first argument of EnableGestureSetHRC is the HRC handle returned by CreateComptibleHRC. The second argument is a bitwise-OR value formed by the desired combination of GST_ constants, listed here:

Gesture constant	Description
GST_CLIP	Cut, copy, and paste.
GST_WHITE	Space, tab, and newline.
GST_SEL	Lasso selection.
GST_EDIT	Insert, correct, and undo.
GST_SYS	Combines all the above.
GST_CIRCLELO	Lowercase circle gestures.
GST_CIRCLEUP	Uppercase circle gestures.
GST_CIRCLE	Combines GST_CIRCLELO and GST_CIRCLEUP.
GST_ALL	Combines all the above.


Word List

An application can select a word list from any number of lists to attach to an HRC. A word list, referenced by a handle, consists of words the recognizer should consider when translating a handwritten word or phrase. For example, Figure 5.1 shows a case in which the recognizer must decide between the valid interpretations of "boy" and "looy".

By consulting a word list that contains the entry "boy" but not "looy", the recognizer can select the first choice with more confidence.

An application must call the CreateHWL function to create a word list. The function accepts a pointer to a word list already in memory. Alternatively, an application can fill the word list from an existing file through the ReadHWL function. The SetWordlistHRC function attaches the word list to a particular HRC, and DestroyHWL returns the memory occupied by the list to the operating system.

The function SetWordlistCoercionHRC allows an application to establish the word list's influence over the recognizer's interpretations. The function accepts the following values to set the degree of coercion:

Coercion value	Description
SCH_ADVISE	The recognizer should use the word list only for hints; results are not strongly coerced to match the word list. This is the default coercion value.
SCH_FORCE	If the recognizer does not find an exact match in the word list, it should return the best fit. For example, if the recognizer interprets a handwritten word as "swoden," it will return "Sweden," given a word list of country names.
SCH_NONE	Cancels any coercion currently in effect.
The following code fragment illustrates all these steps by reading a list of country names from the fictitious file COUNTRY.LST and attaching the list to the HRC identified by the handle hrc1. It calls SetWordlistCoercionHRC to force the recognizer to return only names found in the COUNTRY.LST file. The code assumes vhwl is a global variable, visible in all parts of the program.

HWL	vhwl;	// Handle to word list

HFILE	hfile;	// File handle

OFSTRUCT	OFstruct;	// Receives info about open file

int	iRet;	// Return code

.

.

.

// In intialization procedure, open and read the word list

hfile = OpenFile( "COUNTRY.LST", (LPOFSTRUCT) &OFstruct, OF_READ );

if (hfile != HFILE_ERROR)

{

vhwl  = CreateHWL( hrec1, NULL, WLT_EMPTY );	// Create empty list

iRet  = ReadHWL( vhwl, hfile );	// Read list from file

}

.

.

.

// After creating hrc1, attach word list vhwl to it

SetWordlistHRC( hrc1, vhwl );	// Attach list to hrc1

SetWordlistCoercionHRC( hrc1, SCH_FORCE );	// Establish coercion

.

.

.

//Before terminating, destroy word list

DestroyHWL( vhwl );

Note that an application must first set the word list with SetWordlistHRC before calling SetWordlistCoercionHRC.


Guide

Guides are visual cues such as lines or boxes in a bedit control. Guide configuration informs the recognizer of the types and locations of guides displayed for the user. With this information, the recognizer can confidently determine which pen strokes constitute a single character or shape. For an illustration of box guides, see the "The bedit Control" section in Chapter 3, "The Writing Process."

To establish guide configuration, an application calls the SetGuideHRC function, providing a pointer to a GUIDE structure:

GUIDE	guide;

.

.

.

iRet = SetGuideHRC( hrc1, (LPGUIDE) &guide, 0 );


Number of Recognition Guesses

The application can specify the maximum number of guesses the recognizer should provide in its results. This allows the application to prevent the recognizer from generating more alternative guesses than required.

Set the maximum number of guesses with the SetMaxResultsHRC function. The following example code tells the recognizer to provide its five best guesses:

iRet = SetMaxResultsHRC( hrc1, 5 );

The default number of maximum recognition results is 1.


Processing

Once the HRC object has been properly created and configured, it can take on its role of recognition agent. To fulfill this role, the HRC requires:

•	The data generated by the pen movement.

•	Sufficient central processing unit (CPU) time to execute the recognition algorithms and generate results.

The following sections describe how an application supplies these two requirements to the HRC object.


Adding Data to an HRC Object

An application provides pen data to the HRC through one of two API functions: AddPenInputHRC or AddPenDataHRC.

AddPenInputHRC operates at intervals as pen data is collected, in the same manner as GetPenInput. An application must call AddPenInputHRC only after it has called GetPenInput. AddPenInputHRC provides the pen coordinates and original equipment manufacturer (OEM) data to the recognizer bound to the HRC object.

AddPenDataHRC also provides pen data to the recognizer, but is designed to operate after all the data is collected. An application can thus collect pen data without realtime recognition, store the data in an HPENDATA structure, and call AddPenDataHRC to recognize the data any time thereafter.


Allocating Processing Time

After it has supplied the raw pen data to an HRC object, the application then allocates processing time for recognition by calling ProcessHRC. To accommodate applications with time-critical communications requirements or other CPU-intensive activities, ProcessHRC takes a time-out value (in milliseconds) as its second argument. If the time-out period elapses before ProcessHRC finishes processing, the function returns an HRCR_INCOMPLETE value. In this way, an application can repeatedly allocate small slices of time until the recognizer finishes its work.

PENWIN.H defines three time-out codes that an application can use when calling ProcessHRC. The following table describes the time-out codes.

Time-out code	Description
PH_MIN	Allocates the smallest possible period of time to the recognizer, approximately 50 milliseconds.
PH_DEFAULT	Allocates a moderate amount of time to the recognizer, approximately 200 milliseconds.
PH_MAX	Grants the recognizer as much time as it requires to complete the recognition.
The following line allocates the default time-out period to the recognizer in the HRC identified by the handle hrc1:

iRet = ProcessHRC( hrc1, PH_DEFAULT );

Typically, AddPenInputHRC and ProcessHRC work together in a loop or in repeated response to a PE_ message as the user writes. One function continually retrieves the latest pen data while the other processes that data. When the input session terminates, an application should call ProcessHRC with PH_MAX to finalize the recognition.

See the reference section for ProcessHRC in Chapter 10 for additional information about this function. When ProcessHRC returns, the application can retrieve results from the HRC object, as described in the next section.


Getting Results

The Pen API provides three methods for an application to get recognition results. The first two methods are functions — GetBoxResultsHRC and GetResultsHRC — that retrieve the results from an HRC object. The GetBoxResultsHRC function assumes the application has provided a GUIDE structure to the HRC. If the application has not specified a GUIDE structure, it must call GetResultsHRC to retrieve an HRCRESULT object for each alternative guess.

The third method applies only to version 1.0 recognition functions. It retrieves recognition results for both boxed and unboxed input from an RCRESULT structure. With this method, an application must dissect the RCRESULT structure to get information that GetBoxResultsHRC and GetResultsHRC provide automatically.

The rest of this section gives examples for each of the three methods.


Boxed Recognition

GetBoxResultsHRC retrieves boxed recognition results on a box-by-box basis. The function fills an array of BOXRESULTS structures with the results and alternatives for a set of boxed character positions in the recognized text. Each of the BOXRESULTS structure in the array contains one or more recognition guesses for a single box.

For example, consider the case in which the user has written a seven-letter word before requesting recognition — say, by tapping an OK button. The application can retrieve results individually for each box by calling GetBoxResultsHRC in a loop, or provide an array of at least seven BOXRESULTS structures and receive all seven recognition results with a single call to GetBoxResultsHRC.

The following example code retrieves recognition results two boxes at a time. It requests only the first alternative for each box, which represents the recognizer's best guess about the character in the box:

#define	NBOX	2	// Number of boxes to get

#define	NALT	1	// Only one alternative per box

BOXRESULTS	box[NBOX];	// Array of BOXRESULTS structures

UINT	iSyv = 0;	// Index of symbol values

int	cBox;	// Number of results returned

.

.

.

do {

cBox = GetBoxResultsHRC( hrc1, NALT, iSyv, NBOX,

   (LPBOXRESULTS)&box, FALSE );

.	// Do error checking

.	// Read results from

.	//   box[] array

iSyv += (UINT) cBox;	// Increment index

} while (cBox == NBOX)	// Loop for next boxes

By requesting only a single alternative for a small number of boxes, the preceding example can allocate the array on the stack. However, the BOXRESULTS structure contains a variable-length array of type SYV for additional alternative characters. For a value of NALT greater than 1, the application must allocate extra space for the alternatives in each BOXRESULTS, as the following line demonstrates:

HGLOBAL	hMem = GlobalAlloc( GHND,

   NBOX*( sizeof(BOXRESULTS) + (NALT-1)*sizeof(SYV)) );

The example provided in the GetBoxResultsHRC reference section in Chapter 10 further illustrates how to use this function.

When GetBoxResultsHRC returns, the application can walk the BOXRESULTS array and display the information appropriately. The boxed edit control described in the "The bedit Control" section in Chapter 3 uses GetBoxResultsHRC to perform recognition and to generate alternative results.

Boxed writing does not constrain an application to call GetBoxResultsHRC for recognition results. An application can also call GetResultsHRC, described next, even if the HRC is configured for box guides.


Unboxed Recognition

For recognition of unboxed handwriting — that is, writing without visual guides as specified by a GUIDE structure, an application must call the GetResultsHRC function. This function fills an array of HRCRESULT objects, each containing a separate guess by the recognizer. The number of HRCRESULT objects in the array is always less than or equal to the maximum number of guesses requested through the SetMaxResultsHRC function.

An example will clarify this. Assume an application contains the following instructions:

#define	MAX_GUESS	5	// Maximum number of guesses allowed

.

.

.

SetMaxResultsHRC( hrc1, MAX_GUESS );

The user next writes a word that the recognizer associated with hrc1 guesses to be, in descending order of probability, either "clear," "dear," "clean," "dean," or "deer." Though it might have generated even more guesses, the recognizer is constrained to stop after its fifth guess by the earlier call to SetMaxResultsHRC. In this case, a subsequent call to GetResultsHRC fills an array of up to five HRCRESULT objects, the first HRCRESULT containing the word "clear," the second the word "dear," and so forth.

An HRCRESULT object does not contain a normal ASCII string representation of a guess. This is not possible since a guess might be made up of a gesture, shape, or other entity that has no ASCII equivalent. Instead, an HRCRESULT contains a string of symbol values, which are 32-bit numbers type-defined as SYV.

Symbol values can represent geometric shapes, gestures, letters of the alphabet, Japanese Kanji characters, musical notes, electronic symbols, or any other symbols defined by the recognizer. The Pen API provides the function SymbolToCharacter to convert the null-terminated symbol string in HRCRESULT to an ASCII string.

The following code continues the example above, illustrating how to retrieve and display the five guesses returned by the recognizer:

#define     MAX_GUESS   5       // Maximum number of guesses allowed

#define     MAX_CHAR	    50      // Maximum number of characters in

                                //   a single guess

HRCRESULT   result[MAX_GUESS];  // Array for recognition result objects

int         cGuess;

.

.

.

SetMaxResultsHRC( hrc1, MAX_GUESS );

.

.

.

//

// Get all (non-gesture) guesses available, and if no errors,

// convert to ASCII strings and display them.  Note in our

// example the following call returns the value 5 to cGuess.

//

cGuess = GetResultsHRC( hrc1, GRH_NONGESTURE,

                       (LPHRCRESULT) &result, MAX_GUESS );

if (cGuess > 0)

{

int     i, cSyv, cChar;

char    szText[MAX_CHAR];           // Buffer for converted text

SYV     rgSyv[MAX_CHAR];            // Buffer for symbol string

//

// Loop cGuess (5) times, retrieving each time a symbol string

// representing a different guess.  Convert the symbol string

// to a normal ASCII string and display it.

//

// In our example, the five iterations of this loop display the

// words "clear," "dear," "clean," "dean," and "deer."

//

for (i = 0; i < cGuess; i++)

{

cSyv = GetSymbolsHRCRESULT( result[i], 0, rgSyv, MAX_CHAR );

if (cSyv > 0)

{

             SymbolToCharacter( (LPSYV) rgSyv, cSyv,

                                (LPSTR) szText, (LPINT) &cChar );

.

.	// After converting to ASCII

.	//   string, display text

             TextOut( hdc, nX, nY, (LPSTR) szText, cChar );

.

.

.

}

        DestroyHRCRESULT( result[i] );  // When finished with results,

        result[i] = NULL;               //   destroy HRCRESULT objects

}

}

For another example of how to use the GetResultsHRC function, see "Step 9: PE_RESULT Message" in Chapter 2. If an application must retrieve an unknown number of symbol values from the recognizer, it should follow these three steps:

1.	Call GetSymbolCountHRCRESULT to determine the number of symbol values the recognizer can return.

2.	Allocate a sufficient buffer for the values.

3.	Call GetSymbolsHRCRESULT. to copy the symbol values to the buffer.


Getting Results from the RCRESULT Structure

Note  The RCRESULT structure is supported only for backward compatibility. It may not exist in future versions of the Pen API. Applications should obtain recognition results through the API functions described in this chapter, rather than from an RCRESULT structure.

The RCRESULT structure applies only when an application calls either of the version 1.0 recognition functions, Recognize or RecognizeData. In this case, the system sends a WM_RCRESULT message to the application. The wParam of this message contains a REC_ submessage that indicates why recognition ended. The lParam of WM_RCRESULT points to an RCRESULT structure, which contains all the results of the recognition.

An application can retrieve from the RCRESULT structure all the recognizer's guesses by walking through the list, called the symbol graph, contained in the RCRESULT structure.

The RCRESULT structure identifies the recognizer's "best guess," which is the guess in which the recognizer places the most confidence. With this information, an application can conveniently retrieve an ASCII string of the best guess by calling SymbolToCharacter:

char	szBestGuess[MAX_CHAR];	// ASCII string of best guess

.

.

.

switch (wMsg)

{

case WM_RCRESULT:

SymbolToCharacter(

(LPSYV) ((LPRCRESULT)lparam)->lpsyv,	// Symbol string

MAX_CHAR,	// Maximum length

(LPSTR) szBestGuess,	// Buffer for ASCII

NULL );	// Don't need count

Compare the above call to SymbolToCharacter with the previous example. Here, the second argument represents a maximum, rather than the actual length of the symbol string, which is the value

(int) ((LPRCRESULT)lparam)->cSyv

By specifying the length of the buffer that receives the ASCII text, the second argument sets a cap on the number of symbols SymbolToCharacter will convert. This prevents the function from overflowing the szBestGuess buffer if the length of the symbol string happens to be larger than MAX_CHAR. SymbolToCharacter returns when it encounters SYV_NULL at the end of the symbol string or when it converts MAX_CHAR symbols, whichever occurs first.

An application that calls Recognize or RecognizeData must be prepared to receive WM_RCRESULT messages before calling either function. This is because the recognizer dispatches all WM_RCRESULT messages associated with a particular recognition event before Recognize or RecognizeData returns.

Version 2.0 of the Pen API provides, through function calls, all the information contained in an RCRESULT structure. An application need not examine the structure at all. RCRESULT is a product of recognition, and is therefore of more interest to the recognizer developer than the application developer. Consequently, it is described in more detail in Chapter 8, "Writing a Recognizer."


Destroying the HRC

The useful life of an HRC object usually expires when the recognizer returns results at the end of an input session. The next input session requires the creation of a new HRC. When finished with an HRC object, an application should destroy the object in two steps:

1.	Call DestroyHRC to free the occupied memory.

2.	Set the HRC handle to NULL.

For example:

HRC	vhrc = NULL;	// Set to NULL until HRC is created

.

.	// Create and use the HRC

.

DestroyHRC( vhrc );	// Destroy the HRC when finished

vhrc = NULL;	// Handle is now invalid

When DestroyHRC returns, the handle value remains unchanged though no longer valid. The second step above prevents frustrating bugs arising from the inadvertent use of an invalid HRC handle.

This same advice applies to the other recognition objects, HRCRESULT and HWL. After calling DestroyHRCRESULT or DestroyHWL, always set the invalid handle to NULL.


Design Considerations

The developer of pen-based applications should bear in mind the unusual qualities of a pen interface. Input through a pen device provides unique advantages, yet at the same time carries severe limitations. The best applications will seek to profit from one quality while minimizing the effects of the other.

This chapter discusses some of the characteristics of an intelligent and responsive pen-based application. It offers tips, ideas, and a few warnings. The advice is based on experience and the results of usability studies conducted by Microsoft.


Basic Principles

Consider the following basic principles when designing the user interface of a pen-based application. Though not intended to constrain the developer's creativity, these principles can help ensure that the resulting application appeals to its users.

•	Keep it simple.

•	Use familiar models.

•	Show feedback for user.

•	Make it fast.

•	Make it fun.

•	Make exploration safe.

•	Let the user maintain control.

The following sections explore each of these guidelines.


Keep It Simple

The developer should value simplicity over power when designing a pen-based application. Simplicity is not only a characteristic of good interface design, it hastens the user's acceptance of a type of input paradigm apt to be new and unfamiliar.

The same principles for writing a standard Windows-based application apply equally to pen-based programs:

•	Limit features and options to reduce the number of choices a user must make. When adapting an existing application to run on a pen-based computer, remember the so-called "80/20" rule: 80 percent of an application's value is typically provided by only 20 percent of its features.

•	Keep the interface clear, consistent, uncomplicated, and predictable. The relationship between what a user does and how the application responds should be logical and consistent. Keeping the interface consistent and predictable reduces the amount of information the user must remember in order to use an application.

•	Make possible actions and results visible to the user. Enable the user to work directly with objects without resorting to abstractions. The user wants to "send mail" or "find a note," not "open an application" or "search for data."

•	Use constraints to prevent the user from choosing inappropriate actions and provide default choices whenever appropriate. Constraints encourage the user to make appropriate decisions by limiting unlikely choices. For example, a button enabling a user to save or pause a game should not be visible until play has started.


Use Familiar Models

Familiar conceptual models are powerful aids in user-interface design. A conceptual model enables users to apply knowledge gained from experience toward understanding the structure and use of the application. For example, an Address application modeled after a typical paper-based address book would allow users to apply their understanding of address books to the new application.


Use Feedback

The user should receive immediate and tangible feedback during interaction with an application. Appropriate feedback includes acknowledging a request, pointing out an error, or tracking the progress of an operation. Although auditory feedback can be useful for attracting a user's attention, it should be used sparingly in a pen-based application for the following reasons:

•	Many users find beeps annoying.

•	Pen-based computers will be used more and more frequently in conference rooms and other group areas where beeping from a machine will not be welcome.

•	Auditory messages disappear without a trace. If the user is momentarily away or distracted, the auditory signal has failed to do its job.

•	If the user can turn the warning sound off, sound is not a reliable source of feedback.

•	An audible notification is not useful for users who are deaf or hard of hearing.


Make It Fast

A simple and responsive interface is more appealing than an attractive yet sluggish interface. An application should always be ready for user input and prepared to offer immediate feedback. Ideally, results should quickly follow the user's actions.

Where immediate results are not possible, run lengthy operations in separate threads if practical. This technique has the advantage of at least simulating speed by returning control quickly to the user.


Make It Fun

Users will look for applications that have simple, creative interfaces that are fun to use when deciding what to keep on their portable pen-based machines. Paying special attention to the visual appeal of an interface pays off in gaining user acceptance. The most powerful interfaces are those that combine aesthetics with functionality.


Make Exploration Safe

People like to explore applications and learn by trial and error. Such selfmotivated learning is extremely effective, but users might not always be aware of potential dangers. Even with the best-designed interface, users make mistakes — such as accidentally tapping the wrong object or data, or making a wrong decision about which data to select. The interface should accommodate user exploration by:

•	Softening any penalty caused by mistake.

•	Minimizing the opportunities for errors.

•	Handling user errors gracefully, without implying the user is at fault.

•	Allowing easy undo and undelete.

•	Keeping separate training databases to accommodate guest users.


Let the User Maintain Control

People want to feel in control of an application. A well-designed, responsive user interface contributes much toward the user's perception of being in control. The following list gives design suggestions for achieving this:

•	Enable the user to interrupt long operations.

•	Discard meaningless user input during long operations. While waiting, users might randomly tap on the pen tablet or display. To dispose of spurious input in a discreet manner, enable your application to distinguish between meaningful and unintentional data.

•	Allow the user to specify desired default settings.


Recognition: Use and Misuse

Recognition is often the deciding factor in how people react to pen-based computing. It is, unfortunately, an inexact science and always will be. The best applications will seek to minimize the potential for error introduced by recognition by restricting as much as possible the amount of recognition necessary. The following may give you some ideas.


Selecting Is Better Than Writing

As much as possible, let the user select rather than write. For example, take advantage of spin-box and list-box controls that don't require written input. When prompting for a date, present the user with a simple calendar on which he or she can pick a date by tapping with the pen.

Keep track of previous entries and allow the user to select one from a list rather than having to rewrite it. For example, when prompting for a name, consider using a combo-box control to provide access to a list of the previous 10 or so names the user has last entered. This confines the potential for recognition errors to the first time the name is written.

When prompting for a filename, provide an option for browsing through directory lists, allowing the user to select a file and path by tapping the filename with the pen.


bedit Is Better Than hedit

People prefer to write in the relatively unrestricted space of an hedit control, but the bedit control offers better recognition accuracy. The comb and box guides of a bedit also serve as discreet prompts, informing the user that the application awaits written input.

If saving screen space is important, consider using a lens instead of a bedit. Always create a single-line edit control with ES_AUTOHSCROLL so it shows a lens button.


Real Time Is Better Than Deferred Time

Deferred recognition offers the seductive advantages of speed and instantaneous response. By collecting ink without pausing to recognize it, an application can easily keep up with rapid pen movements. The input can be recognized later when requested by the user, or perhaps during periods of user inactivity.

However, Microsoft tests have demonstrated that the accuracy of deferred recognition often compares unfavorably to real-time recognition. This has nothing to do with the recognizers, since they apply the same processing procedures to the data regardless of when the ink is collected. The discrepancy arises from the fact that people tend to write more carelessly if not continually informed about the recognizer's success rate.

By seeing the recognition results as they write, users naturally adapt their writing speed and style to assure the greatest recognition accuracy. Although in theory the user should train the recognizer, to a certain extent the reverse undeniably occurs.


Make Corrections Easy

Users don't mind recognition errors as much as they mind the effort required to correct the errors. A good pen model focuses on making corrections as easy and fast as possible.

An error in recognition should never have unpleasant consequences. For example, misrecognizing an undo gesture wastes the user's time. When in doubt, prompt for confirmation and make confirmation easy — say, with an extra-large OK button. The extra step will annoy the user less than having to recover from the error.


Provide Easy Access to the On-screen Keyboard

The on-screen keyboard serves well for short input, especially for correcting erroneous recognition results. An application should ensure that the on-screen keyboard is easily accessible to the user, yet remains unobtrusive. Microsoft usability studies have shown that users prefer writing to tapping on the on-screen keyboard, even though the latter is often faster because it avoids recognition errors. Consider making the on-screen keyboard more or less noticeable depending on whether your application runs on a desktop system with a real keyboard or on a handheld unit with no physical keyboard.


Other Considerations

The developer of pen-based applications should consider other facets of pen computing besides recognition. This section lists a few ideas.


Don't Rely on Gestures

In a well-designed pen application, all operations are possible without gestures. The application may support gestures as shortcuts, but should not sacrifice common operations for the sake of the gesture.

Gestures also tend to remain a hidden (or "nondiscoverable") functionality, which the novice user often does not guess at. Gestures should facilitate the experienced user without hampering the uninitiated.

Action handles provide the same benefits as gestures. Moreover, they are more discoverable and reliable, since they do not require recognition.

Every pen application should, at minimum, support the cut and lasso gestures. Anything else is at the discretion of the developer. Incidentally, usability tests have found that a common gesture among novice users is to scribble over an entry to erase or undo it. An intelligent application should respond to such unknown gestures and display a polite inquiry, listing possible alternative actions that the user can select by tapping.


Provide Ample Target Space

The pen often proves an inaccurate pointing device. The well-behaved pen application allows ample margin for pointing errors from the user, who can easily miss a small button or other target. Consider the following suggestions to make your pen-based application friendly to the user with poor aim:

•	Create targets as large as practical.

•	Space toolbar buttons so that they have gaps between them.

•	Avoid crowding dialog boxes with controls placed near one another.

•	Pen-down events falling within a few pixels of a button should be treated as a press of that button. Always increase the effective size of a control by sending the HE_SETINFLATE submessage, as described in the "HE_SETINFLATE Submessage" section in Chapter 3, "The Writing Process."

•	Compensate for the pixel sizes of different displays. Use GetDeviceCaps to determine sizes and maintain uniform dimensions for on-screen targets.


Use Position Clues

A pen-based application should consider position clues in determining the user's intentions. The following offers a few examples of inferring the user's desires from the position of the ink:

•	A gesture drawn over part of a selection should operate on the entire selection. In the same vein, a gesture or lasso that intersects more than a single letter of a word is probably meant for the entire word.

•	Writing text on a line below existing text serves as a good indication the user intends the new text to go on a new line. In this case, an application can insert a newline character automatically.

•	Text written over an insertion point should be inserted at the insertion point.


Conserve Power

A pen-based environment will often be found on small notebook- or handheld-size computers. Users will appreciate pen-based applications that extend battery life by conserving power. Here are a few power-saving tips:

•	Avoid "disk hits" as much as possible. Hard disks on small systems often turn off after a period of inactivity and powering them up again significantly affects battery life. An application should avoid unnecessarily accessing the disk, since doing so may force the system to repower the drive.

•	Keep code and data files small to minimize the disk swapping Windows must do to clear memory. Restrict the number of dynamic-link library (DLL) files your application requires and consider loading the DLLs early. In this way, Windows reads the DLL files immediately after having loaded the application itself, while the disk is still in motion. Linking to a DLL's import library ensures that the DLL is installed at the same time as the application.

However, this advice applies only to small DLL files and DLLs that the application will most likely use at some point. Large DLL files that stand a good chance of not being required by the application should be loaded explicitly only when needed by calling the InstallRecognizer function or the LoadLibrary function. Although this risks powering up a dormant disk drive, it also prevents unneeded objects from occupying memory.

•	Prefer visual to auditory signals. Besides the negative reasons cited in the "Use Feedback" section, beeps from the speaker also waste battery power.

•	Reduce video power drain by making background colors black.


Guidelines for Applications

The following presents some recommended approaches for different types of applications, based on the guidelines presented above. While by no means exhaustive, the material may give you some ideas for various types of applications.


Annotation

Many different types of software can benefit from the unique advantages of pen-based annotation. A user annotates by writing with a pen on top of an existing document, as though on an overlaying transparent sheet. This allows adding to the document free-form writing such as notes, diagrams, review comments, questions, and so forth.

Unless evident by the context, an application should prompt the user to identify a position in the document to attach the annotation. This prevents the annotation from drifting from its intended location if the underlying document is changed.

Often, annotated text remains unrecognized, captured as ink data. Reduce such text to display resolution to minimize the file space it occupies. For more information on how to achieve maximum compression of handwritten text, see "Converting Data to Display Resolution"  in Chapter 4.


Word Processor

Although the pen does not serve well to create a word-processor document, it can do so for small editing tasks on existing documents, such as for cut-and-paste operations, formatting changes, rewriting small amounts of text, and navigation (scrolling). Thus, the pen in a word-processing application should behave as a pointing device most of the time. The user should be able to select text by dragging the pen and the selection should include an action handle. Double-tapping should display a writing window, as should an "edit" command on a selection action handle. Consider also providing an insertion-point action handle, including an "insert text" command.

When the user creates a new blank document, the application should automatically display an editing window because the user clearly intends to enter new text. For existing documents, the application should provide a means for annotating the text, either by inserting scribble notes (like Post-it™ notes) or by inking directly on top of the text.


Spreadsheet

Within the spreadsheet area, the pen should default to a pointer. If the application allows in-cell editing, double-tapping the cell should open a writing window in which the user can write or edit the contents of the cell. This window should include a palette of commonly entered symbols such as "*" or formula names that are hard to recognize. This allows the user to enter an unambiguous symbol by tapping an appropriate button.

A formula bar area should behave more like the word-processor application just described. If the area is empty, the application should display the writing window automatically. Naturally, the recognizer should be configured according to the type of input expected, whether text, numerical, or whatever.

Annotation, including quick notes and diagrams, represents an ideal usage of a pen in a spreadsheet application. Often, annotated text can be kept as ink and does not require recognition. Anchoring and targeting annotations on a spreadsheet is somewhat easier than on a word-processing document because cells do not flow in the same manner as text. Annotations should be anchored to the data and not the cell. This ensures that, if the data moves to another cell, the annotation moves with it.

Because spreadsheets contain much data that is not based on words, on-screen keyboards should be easy to display (and automatic in many circumstances). As with word-processing applications, writing in a spreadsheet will most likely be limited to small editing and format changes.

The user will often wish to edit the contents of a single cell to see how it affects the rest of the spreadsheet. To facilitate this operation with a pen, the application should anticipate as much as possible. For example, double-tapping a field containing a numeric value should display a numeric on-screen keypad.

If the spreadsheet offers text entry with recognition, it should provide an appropriate tool accessible from a toolbar or menu. When the user selects text-entry mode, the spreadsheet should enlarge (zoom), allowing the user to write comfortably within a cell. The application can rely on the automatic targeting capabilities provided by the Pen application programming interface (API), described in Chapter 2, to route text appropriately to different cells.


Mail

Perhaps the most common operations in electronic mail with a pen are navigation, annotation, responding to and forwarding mail, and composition of short notes.

When the user selects "new" to create a new blank message or presses a "reply" or "forward" button, the application should automatically display a writing window in which the user can enter new text. In the case of the reply and forward operations, the writing window should include the text of the original message. The user may wish to selectively edit or delete parts of the original message when replying or forwarding. The application should provide action handles for this.


Forms

Pen computers are ideal for filling out electronic forms. Forms applications can achieve superior handwriting recognition for several reasons:

•	The bedit control with its built-in guides serves perfectly in many if not all the writing sections of a form.

•	Because each writing window of an electronic form often expects input of a certain type, the forms application can constrain recognition to that type. For example, an application can restrict recognition to numerals for a control window that expects a telephone number.

•	Through the use of word lists such as local street names or regional cities, a recognizer can greatly improve accuracy for certain input sections of the form.

Forms usually appear blank or nearly blank by default, so the most common operation in a forms application is adding text. The system's automatic targeting routes input to the proper control window without intervention by the application.

A writing window should appear automatically on the appropriate field if recognized text produces questionable results. Double-tapping should display a writing window, and the application should provide a lens (writing window) and on-screen keyboard accelerator buttons. It should also provide insertion-point action handles for selection.


Shell

The most common shell operations involve selecting files, opening files or running programs, dragging filenames to copy or move files, and deleting files. A pointer-based interface serves all such operations well. Therefore, the pen should behave as a pointer in the shell. Tapping or dragging a rectangular marquee should select files, double-tapping should open files, and dragging should copy or move files. The shell can provide deletion services on selected files either through a "delete" option in a menu or by handling a cut gesture.


A Sample Pen Application

This chapter describes a simple pen-based application called PENAPP that demonstrates some of the programming techniques covered in the previous chapters. The source code in this chapter is fragmentary, illustrating only the most interesting parts of the application. For the complete source listing, see the file PENAPP.C in the Microsoft Win32 Software Development Kit, in the SAMPLES\PEN\PENAPP directory.

PENAPP uses the sample recognizer SREC, described in the next chapter, "Writing a Recognizer." The source files for SREC also reside in the SAMPLES directory. To see PENAPP in action, you must first build both PENAPP.EXE and SREC.DLL using the supplied makefiles. Place the  SREC.DLL file in your Windows directory or in a directory on the PATH list before running PENAPP.

The SAMPLES\PEN directory also provides source code for other sample pen-based applications. All code is commented, demonstrating different approaches to different issues.


Overview of PENAPP

PENAPP is a standard pen-based application with the familiar Windows look. It displays a main window with a border, an application menu, and Minimize and Maximize buttons. It also has three child windows titled Input, Info, and Raw Data.

In operation, PENAPP accepts pen input through the Input child window. Depending on the menu option, PENAPP sends the input to the system recognizer or the sample custom recognizer SREC, or collects the data into an HPENDATA object to create a mirror image of the ink.

The output from the recognizers is displayed through the Raw Data and Info child windows. The Raw Data child window redisplays the raw input data, sized for the smaller window. The Info child window displays one of the following, depending on the current menu selection:

•	If the selected recognizer is the system recognizer, the Info child window displays the recognized ANSI text.

•	If the selected recognizer is the sample custom recognizer, the Info child window displays an arrow indicating the compass direction of the input stroke. If the pen rests on the tablet surface without moving, the Info window displays a single dot.

•	If the Mirror option is selected, the Info window displays a mirror image of the drawing.

In this chapter, PENAPP function and variable names appear in monospace font, including the application's entry function, WinMain. In keeping with the conventions of the rest of the book, API elements are styled bold.


Initialization

The PENAPP function WinMain is a standard Windows entry function. PENAPP uses initialization functions, called InitApp and InitInstance, to create windows and initialize data. To an experienced programmer in Windows, the WinMain and initialization functions will look very familiar.


WinMain

The WinMain function performs the same tasks as a regular Windows function:

•	It calls the initialization functions to register window classes and create windows.

•	It enters a message loop to process messages from the application queue.

•	The message loop ends when the user chooses Exit from the menu, generating a WM_DESTROY message, which in turn posts a WM_QUIT message to WinMain. When the GetMessage function detects the WM_QUIT message, it returns NULL to end the loop.

The WinMain function calls GetSystemMetrics to check whether pen services are installed. If they are not found, the application should either exit with an explanatory message or alter its behavior to run without pen input.

Note that Microsoft pen services must be installed when Windows starts. Simply linking PENWIN.DLL and loading it at runtime is not sufficient to initialize pen services. For this reason, unless it is known that the application being developed  will always be run on a system with pen services installed, pen API should  be called through function pointers. This mechanism insures that a pen-aware application can run only on a system on which pen services has been properly installed and will not run on any system that merely has PENWIN.DLL on the path. See the HFORM sample application for an example of this technique.

For the sake of simplicity and readability, the PENAPP application described in this chapter links directly to PENWIN.DLL and does not use function pointers.

int PASCAL	WinMain(

HANDLE hInstance,	// Instance handle

HANDLE hPrevInstance,	// Previous instance handle

LPSTR lpszCommandLine,	// Command line string

int cmdShow )	// ShowWindow flag

{

MSG	msg;

// Mention to prevent compiler warnings ....

lpszCommandLine;

if (!hPrevInstance)	// If first instance,

if (!InitApp( hInstance ))	//   register window class

return FALSE;	// Exit if can't register

if (!InitInstance( hInstance, nCmdShow ))

// Create this instance's window

return FALSE;	 	// Exit if error

if (!GetSystemMetrics( SM_PENWINDOWS ))	// If no pen services

return FALSE;	// exit

while (GetMessage( (LPMSG) &msg, NULL, 0, 0) )

{

TranslateMessage( (LPMSG) &msg );

DispatchMessage( (LPMSG) &msg );

}

return 0;	// Success

}

The InitApp function initializes data and registers the window classes. Following standard programming practice for Windows, the function returns FALSE if it cannot register the window classes.

For the Input window, InitApp specifies a cursor type of IDC_PEN. This is the default cursor type supplied by the pen-aware display driver. For more information on pen types, see the reference section for the IDC_ constants in Chapter 13, "Pen Application Programming Interface Constants."

The following fragment shows how InitApp creates the Input window:

BOOL	InitApp( HANDLE hInstance )	// Instance handle

{

WNDCLASS	wc;

.

.

.

//

// Register PenApp child window classes

//

wc.hCursor       = LoadCursor( NULL, IDC_PEN );

wc.hIcon         = NULL;

wc.lpszMenuName  = NULL;

wc.lpszClassName = (LPSTR) szPenAppInputClass;

wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);

wc.style         = CS_VREDRAW | CS_HREDRAW | CS_SAVEBITS;

wc.lpfnWndProc   = InputWndProc;

if (!RegisterClass( (LPWNDCLASS) &wc) )

return FALSE;

.

.

.

}


InitInstance

The InitInstance function initializes all data structures for the program instance and creates the necessary windows. InitInstance looks like a standard Windows initialization function except that it calls the InstallRecognizer function to load the default recognizer SREC. Windows loads the default recognizer automatically, so a program should call InstallRecognizer to load only recognizers other than the default recognizer.

The following fragment taken from the InitInstance function shows how the program loads the SREC recognizer:

BOOL	InitInstance(

HANDLE hInstance,	// Instance handle

int cmdShow )	// ShowWindow flag

{

.

.

.

//

// Load sample recognizer SREC

//

vhrec = InstallRecognizer( (LPSTR) szSampleRec );

if (vhrec)

return TRUE;

else

{

   MessageBox( vhwndMain, "Could not install recognizer SREC",

    szPenAppWnd, MB_OK | MB_ICONSTOP );

   return FALSE;

}

}


Window Procedures

PENAPP provides a separate procedure to handle messages for each of its four windows. In accordance with usual programming techniques for Windows, each window procedure passes all unprocessed messages to DefWindowProc for default processing.

The following sections describe the procedures for the Main, Input, Raw, and Info windows.


MainWndProc

As its name implies, the MainWndProc function handles messages sent to the program's parent (main) window. These messages signal that the user has made a menu selection, resized the window, or changed the pen system through Control Panel. These actions generate, respectively, the following messages:

•	WM_COMMAND message. If the user selects a command from the Options menu, the program notes the selection in the global flag viMenuSel. The state of this flag determines whether subsequent input goes to the system recognizer or the sample recognizer SREC, or is collected into an HPENDATA object for conversion to a mirror image.

•	WM_SIZE message. PENAPP resizes its windows according to the information in the lParam variable.

•	WM_PENMISCINFO message. The procedure allows this message to fall through to DefWindowProc for default handling.

LRESULT CALLBACK	MainWndProc(

HWND hwnd,	// Window handle

UINT message,	// Message

WPARAM wParam,	// Varies

LPARAM lParam )	// Varies

{

LONG	lRet = 0L;

.

.

.

switch (message)

{

case WM_COMMAND:

switch (wParam)

{

case miExit:

DestroyWindow( vhwndMain );

break;

case miSample:

case miSystem:

case miMirror:

ResetWindow( wParam );

break;

}

break;

.

.

.

case WM_DESTROY:

if (vhpendata)

{

// PKPD.DLL API: function pointer not needed:

DestroyPenData( vhpendata );

vhpendata = NULL;

}

//

// Unload sample recognizer. (Don't

// unload system default recognizer.)

//

UninstallRecognizer( vhrec );

vhrec = NULL;

PostQuitMessage( 0 );

break;

default:

lRet = DefWindowProc( hwnd, message, wParam, lParam );

break;

}

return lRet;

}


InputWndProc

The InputWndProc procedure receives the WM_LBUTTONDOWN message that signals the start of an input session. It distinguishes between a pen-down event and a true mouse event, using the methods described in the "Beginning an Input Session" section in Chapter 2.

When it detects the start of a pen-input session, InputWndProc calls the DoDefaultPenInput function to handle the chores of initialization, data collection, and inking.

As described in the "Step 3: PE_GETPCMINFO Message" section in Chapter 2, InputWndProc immediately receives a PE_GETPCMINFO submessage. The lParam variable points to an initialized PCMINFO structure that the system will use for recognition. The SREC recognizer requires the structure to specify a pen-up event as a condition of termination. Accordingly, InputWndProc takes this opportunity to set the PCM_PENUP flag.

InputWndProc next receives a PE_BEGINDATA submessage, as described in "Step 6:  PE_BEGINDATA Message" in Chapter 2. In response, the procedure takes one of the following courses of action:

•	If currently using the sample recognizer, InputWndProc creates an HRC object for that recognizer and specifies the HRC in the TARGET structure pointed to by lParam. This tells DoDefaultPenInput to use the sample recognizer SREC instead of the system default recognizer.

•	If displaying a mirror image of the ink, InputWndProc creates an HPENDATA object for the ink and specifies it in the TARGET structure pointed to by lParam. This tells DoDefaultPenInput to collect data into the HPENDATA block instead of passing it to a recognizer.

•	If using the default recognizer, InputWndProc simply passes the message to DefWindowProc, which creates an HRC for the default recognizer. The code also demonstrates how an application can take advantage of the convenience afforded by DefWindowProc, yet override any default assumptions it makes.

When DefWindowProc returns, lParam still points to the TARGET structure, which now reflects the default assumptions. One of these assumptions limits to one the maximum number of guesses the system recognizer should return. Since PENAPP requires a maximum of five guesses, it changes the value by calling SetMaxResultsHRC for the HRC that DefWindowProc creates.

The PE_ENDDATA submessage informs InputWndProc that the input session has ended. The procedure collects any symbols returned by the current recognizer into an array of symbol strings called vsyvSymbol. This portion of the code does not check to see which menu option is current. It simply collects symbols into the array if available. If the Mirror option is selected, the attempt to collect recognized symbols harmlessly fails since no HRC exists.

After it collects the data, InputWndProc invalidates all three child windows. This sends WM_PAINT messages to each window, clearing the Input window and causing the other two windows to display their new data.

#define	MAX_GUESS	5	// Maximum number of guesses

#define	MAX_CHAR	20	// Maximum number of characters per guess

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

HRCRESULT	vrghresult[MAX_GUESS];	 // Array of results

SYV	 vsyvSymbol[MAX_GUESS][MAX_CHAR];	 // Array of symbol strings

int	vcSyv[MAX_GUESS];	 // Array of string lengths

.

.

.

LRESULT CALLBACK	InputWndProc(

HWND hwnd,	// Window handle

UINT message,	// Message

WPARAM wParam,	// Varies

LPARAM lParam )	// Varies

{

LONG	lRet = 0L;	// Initialize return code to FALSE

HRC	hrc;	// HRC object

HDC	hdc;

PAINSTRUCT	ps;

DWORD	dwInfo;

int	i, cGuess;

switch (message)

{

.

.

.

 case WM_LBUTTONDOWN:

//

// Two possibilities exist: user is using mouse or the pen.	// The latter case indicates the user is starting to write.

//

dwInfo = GetMessageExtraInfo();

if (IsPenEvent( msg, dwInfo ))

{

  if (DoDefaultPenInput( vhwndInput,

 (UINT)dwInfo ) == PCMR_OK)

lRet = TRUE;

else

lRet = DefWindowProc( hwnd, msg, wParam, lParam );

}

break;

case WM_PENEVENT:

switch (wParam)

{

  case PE_GETPCMINFO:

//

// If using SREC recognizer, ensure session ends

// on pen-up.

//

if (viMenuSel == miSample)

((LPPCMINFO) lParam)->dwPcm |= PCM_PENUP;

lRet = DefWindowProc( hwnd, msg, wParam, lParam );

break;

case PE_BEGINDATA:

//

// 1) If using sample recognizer, create an HRC

//    for it and specify it in the TARGET structure

//    pointed to by lParam.  This tells

//    DoDefaultPenInput to use the sample recognizer

//    instead of the system default.

//

// 2) If displaying mirror image of ink, create an

//    HPENDATA for it.  This tells DeDefaultPenInput

//    to collect data into the HPENDATA object

//    instead of passing it to a recognizer.

//

// 3) If using default recognizer, pass to

//    DefWindowProc.  DefWindowProc sets the maximum

//    number of guesses to 1; the code below shows

//    how to access the HRC that DefWindowProc

//    creates and reset the maximum number of

//    guesses to MAX_GUESS.

//

if (vhpendata)

{

DestroyPenData( vhpendata );

vhpendata = NULL;

}

switch (viMenuSel)

{

case miSample:

hrc = CreateCompatibleHRC( NULL, vhrec );

if (hrc)

{

((LPTARGET) lParam)->dwData = hrc;

lRet = LRET_HRC;

}

break;

case miMirror:

vhpendata = CreatePenData( NULL, 0,

   PDTS_HIENGLISH, 0 );

if (vhpendata)

{

((LPTARGET) lParam)->dwData = vhpendata;

lRet = LRET_HPENDATA;

}

break;

case miSystem:

lRet = DefWindowProc( hwnd, msg,

  wParam, lParam );

//

// On return, lParam->dwData points to HRC.

// Use it to reset max number of guesses.

//

SetMaxResultsHRC(

   ((LPTARGET) lParam)->dwData,

   MAX_GUESS );

break;

}

break;

case PE_ENDDATA:

//

// DefWindowProc will destroy vhpendata, so if

// collecting mirror image, don't let DefWindowProc

// handle message.

//

   if (viMenuSel != miMirror)

   lRet = DefWindowProc(hwnd, msg, wParam, lParam);

   break;

case PE_RESULT:

//

// At end of input, collect recognition results (if

// any) into symbol strings.  DoDefaultPenInput

// generates the PE_RESULT submessage only when

// using a recognizer.  The lParam contains the HRC

// for the recognition process.

//

// Collect pen data for DrawRawData

vhpendata = CreatePenDataHRC( (HRC) lParam );

// Initialize array to zero

for (i = 0; i < MAX_GUESS; i++)

vcSyv[i] = SYV_NULL;

// Get number of guesses available

cGuess = GetResultsHRC( (HRC) lParam,

 GRH_ALL,

 (LPHRCRESULT) vrghresult,

 MAX_GUESS );

// Get guesses (in vsyvSymbol) and

// their lengths (in vcSyv)

if (cGuess != HRCR_ERROR )

for (i = 0; i < cGuess; i++)

vcSyv[i] = GetSymbolsHRCRESULT(

    vrghresult[i],

    0,

    (LPSYV) vsyvSymbol[i],

    MAX_CHAR );

break;

.

.

.

default:

lRet = DefWindowProc( hwnd, msg, wParam, lParam );

}	// End switch (wParam)

break;

default:

lRet = DefWindowProc( hwnd, message, wParam, lParam );

  }	// End switch (msg)

return lRet;

}


InfoWndProc

PENAPP displays results in the Info window. When the InfoWndProc procedure receives a WM_PAINT message, it calls one of three functions to display the results, depending on the current menu selection. It calls:

•	DisplayGuesses if the Default option is chosen.

•	DrawArrow if the Sample option is chosen.

•	DrawMirrorImage if the Mirror option is chosen.

The following list describes the three functions and points out interesting portions of their code.


DisplayGuesses

The DisplayGuesses function writes the guesses returned from the default recognizer. The guesses appear in a column, listed in descending order of confidence. The for loop shown below converts the symbol values to characters, then calls the Windows function TextOut to display the text.

VOID	DisplayGuesses( HDC hdc )	// DC handle

{

TEXTMETRIC	tm;

int	nX, nY;	// Text coords

.

.

.

for (i = 0; i < MAX_GUESS; i++)

{

if (vcSyv[i])

{

SymbolToCharacter( (LPSYV) vsyvSymbol[i],

  vcSyv[i],

  (LPSTR) szText,

  (LPINT) &cChar );

TextOut( hdc, nX, nY, (LPSTR) szText, cChar );

nY += tm.tmExternalLeading + tm.tmHeight;

}

}

}


DrawArrow

DrawArrow draws an arrow to indicate the symbol value returned from the SREC recognizer. SREC returns a compass direction determined from the start and end points of the stroke. DrawArrow reads the direction in vsyvSymbol and diplays an appropriate arrow.


DrawMirrorImage

DrawMirrorImage creates a mirror image of the data by subtracting each x-coordinate from the tablet width. This moves each point from one side of the tablet to a corresponding position on the other side. In other words, the original distance from the tablet's left side now becomes the point's distance from the tablet's right side.

DrawMirrorImage works in five steps:

1.	Creates a duplicate HPENDATA of the input data.

2.	Calls TrimPenData to remove unneeded information from the block.

3.	Converts the new HPENDATA block to a mirror image.

4.	Displays the mirror image by calling DrawPenDataFmt.

5.	Deletes the mirror image HPENDATA block.


RawWndProc

The RawWndProc function is a standard Windows procedure for the Raw Data child window. It calls the DrawRawData function to draw a copy of the input resized for the Raw Data window. Normal pen-down strokes appear in the current window color; pen-up strokes appear in blue. Note that the system recognizer GRECO.DLL does not collect pen-up strokes. Therefore, the blue pen-up strokes do not appear when default recognition is selected from the menu.

DrawRawData calls the DrawPenDataEx function to display the strokes. Since DrawPenDataEx does not show pen-up strokes, DrawRawData first changes all pen-up strokes to pen-down strokes. The following fragment illustrates this:

VOID DrawRawData( HDC hdc )

{

PENDATAHEADER   pendataheader;  // Header for vhpendata

HPEN	         hpenUp, hpenSave;  	// GDI pen for up-strokes

UINT            fPen;           // Pen flag

UINT            iStroke=0;      // Stroke counter

int             nWidth;         // Ink width

.

.

.

if ( !GetPenDataInfo( vhpendata, &pendataheader, NULL, 0 ))

return;

nWidth   = NSetExtents (hdc, &pendataheader, &rectWnd );

hpenUp   = CreatePen( PS_SOLID, nWidth, rgbBlue );

hpenSave = SelectObject( hdc, hpenUp );

// Loop for each stroke, beginning with first

for (iStroke = 0; iStroke < pendataheader.cStrokes; ++iStroke)

{

//

// If down stroke, use same ink characteristics as original.

// If up stroke, first call SetStrokeAttributes to convert it

// to a down stroke, then draw it in blue ink with GDI pen.

//

 	 if (GetStrokeAttributes(vhpendata, iStroke, NULL, GSA_DOWN))

fPen = DPD_DRAWSEL;

  else

  {

SetStrokeAttributes( vhpendata, iStroke, 1, SSA_DOWN );

fPen = DPD_HDCPEN;

  }

  iRet = DrawPenDataEx(hdc, NULL, vhpendata, iStroke, iStroke,

  0, IX_END, NULL, NULL, fPen );

 	 // Set altered strokes back to their original pen-up state

 if (fPen == DPD_HDCPEN)

   SetStrokeAttributes( vhpendata, iStroke, 0, SSA_DOWN );

}

SelectObject( hdc, hpenSave );

DeleteObject( hpenUp );

return

}


Writing a Recognizer

A recognizer is a dynamic-link library (DLL) that interprets lines of ink as characters and symbols. Version 2.0 of the Pen API allows a pen-based application to install multiple recognizers and use them selectively. Each recognizer should specialize in recognizing a particular set of symbols instead of trying to handle many different types. Besides keeping the recognizer code manageable, this approach lets an application choose among several available recognizers to fulfill its current recognition needs.

The recognizer developer must know both sides of the interface between application and recognizer. The foregoing chapters, particularly Chapter 5, "The Recognition Process," should be read before venturing into this one.

Such a developer should also have some familiarity with the coding requirements of a DLL. For information about how to write a DLL, see the Guide to Programming manual in the Microsoft Windows Software Development Kit. In addition, the "Writing a Dynamic-Link Library for Windows" chapter in the MASM version 6.1 Programmer's Guide offers valuable information about DLL coding requirements.

This chapter describes the framework of a recognizer DLL and the functions it must export. The final section presents a sample recognizer called SREC. The source file for SREC resides in the SAMPLES\PEN\SREC subdirectory.


Recognizer Objects

Three objects serve the process of recognition, identified by their handles: recognition context (HRC), recognition context result (HRCRESULT), and word list (HWL). The structure and implementation of these objects are left to the recognizer developer and remain invisible to applications and the system. However, the objects must comply with the following two requirements:

•	The handle value must be a 32-bit pointer to the object in memory.

•	The first DWORD (32 bits) of the memory that the handle points to is reserved for system use. The recognizer must not alter the DWORD value during the life of the object.

Thus, a recognizer's internal structure of a recognition object should be of the following form:

typedef struct {

DWORD dwReserved;

.

.

.

} INTERNALOBJECT;

It is the application's responsibility to destroy the recognition objects when finished. A recognizer should validate all handles to ensure an object exists before processing. Although a product of an HRC, an HRCRESULT is usually an independent object. Destroying an HRC does not destroy its HRCRESULT objects, which remain valid objects and must be destroyed separately.

A single HWL object can be associated with multiple HRC objects at any given time. The recognizer should not allow alteration of an HWL while processing any of its associated HRC objects. Similarly, the recognizer should not allow destruction of an HWL before the destruction of all its associated HRC objects. In either case, the recognizer should return an error to the application.


How a Recognizer Works

There are two techniques for recognizing handwriting, called bitmap and vector recognition.

Bitmap recognition attempts to match an ink image with a record of known character images. The bitmap recognizer sees the ink data as a stencil pattern of points that it can compare to a library of patterns, searching for the closest match. This technique, employed by optical character recognizers (OCRs), works well for patterns limited to a few styles and sizes.

In contrast, vector recognition sees the ink as lines rather than points. The method considers characteristics of the lines collected as the pen moves. These characteristics include sequence, curvature, direction, and so forth. Given the wide varieties and styles of handwriting, vector recognition works best for deciphering pen input. The Pen API does not mandate which method a recognizer employs, but is designed to facilitate vector rather than bitmap recognition.


List of Exported Functions

Technically, an application does not call directly into a recognizer's exported functions, though the distinction is not important to the recognizer. Instead, all calls go to the system, which acts as a switchboard to route the calls to the proper recognizer when more than one recognizer is installed. For example, when an application loads a recognizer with InstallRecognizer, that recognizer exports functions with the same name as those exported by other recognizers, including the default recognizer. The system automatically transfers calls to the correct recognizer based on the HRC argument or other value that identifies the intended recipient.

As a DLL, a recognizer must export functions to the pen system that installs the recognizer. This section lists these recognition functions, describes their purpose, and identifies them as required or optional.

The optional functions that a recognizer should provide depend on the clients it will serve. Commonly, a recognizer DLL is part of an application package designed only for that application. As author of both client application and its private DLL, the developer need write only those functions the application requires. In this case, the developer is also free to design other functions not specified by the Pen API.

At the other extreme, some recognizers serve client applications indiscriminately. For example, a developer might market a recognizer of foreign script to various application developers with international product lines. A recognizer can also take on the role of system default recognizer, in which case it must:

•	Export all recognizer functions.

•	Recognize letters, punctuation, numbers, and predefined gestures from ink data.

•	Associate raw data with matched results.

•	Return characters only within the requested subset.

•	Return an "I don't know" response when appropriate.

A system default recognizer should support all recognizer functions, not merely export stub versions of the optional functions. At the very least, the recognizer must return an HRCR_UNSUPPORTED value from functions it does not support. For a description of how to specify the system recognizer through the registry, see Appendix A, "Differences Between Versions 1.0 and 2.0 of the Pen Application Programming Interface."

The following sections describe all 47 recognition functions of the Pen API version 2.0. The lists of functions represent the following categories:

•	Initialization

•	HRC functions

•	HRCRESULT functions

•	Alphabet support

•	Word lists

•	Training

All recognizers must export 13 required functions, which are indicated by asterisks in the following tables. The functions without asterisks are optional for a recognizer. Each table corresponds to one of the categories listed previously, with functions arranged in alphabetic order within the table.


Initialization

The Pen API specifies the following functions for initializing, modifying, and closing down the recognizer. Note that, in version 2.0 of the Pen API, the required function ConfigRecognizer handles all initialization and configuration tasks. The other initialization functions are obsolete in version 2.0 and should only be included in a recognizer if it is expected to work with older applications that work with a version 1.0 recognizer (see the Microsoft Pen Windows, version 1.0 documentation for descriptions of these functions).

Function	Description
ConfigRecognizer*	Provides access for querying or altering recognizer configuration. In version 2.0, only the system calls ConfigRecognizer. Applications call ConfigHREC, which the system translates into a call to ConfigRecognizer.
CloseRecognizer	Required only for compatibility with version 1.0 API. Called when the system uninstalls a version 1.0 recognizer.
InitRecognizer	Required only for compatibility with version 1.0 API. Called when the system installs a version 1.0 recognizer.
RecognizeDataInternal	Required only for compatibility with version 1.0 API. The system calls this function only when an application calls RecognizeData.
RecognizeInternal	Required only for compatibility with version 1.0 API. The system calls this function only when an application calls Recognize.


HRC Functions

In general terms, the HRC functions carry out the recognition process. Together, they collect raw data, derive recognized symbols from the data, and place the symbols into HRCRESULT objects. Their work ends with recognition. To retrieve the recognized symbols, an application calls the HRCRESULT functions described in the next section.

Function	Description
AddPenInputHRC*	Adds input to the recognizer's HRC object. This function is normally called at every pen movement, providing data a few points at a time.
CreatePenDataHRC	Returns an HPENDATA handle for the pen data within the HRC.
CreateCompatibleHRC*	Creates an empty HRC object, ready to receive input data.
DestroyHRC*	Frees the memory occupied by an HRC object, invalidating the handle value.
EnableGestureSetHRC	Enables or disables the recognition of a specified set of gestures.
EnableSystemDictionaryHRC	Specifies whether or not the recognizer should use its dictionary to validate recognition guesses.
EndPenInputHRC*	Notifies the recognizer that input has ended for the session. This function does not initiate recognition of the collected data; the client application must call ProcessHRC to do that.
GetBoxResultsHRC	Gets recognition results for a range of boxes.
GetGuideHRC	Retrieves a copy of the GUIDE structure (if any) used in the HRC.
GetHRECFromHRC*	Gets the module handle to the recognizer DLL attached to the HRC.
GetMaxResultsHRC	Gets the current maximum number of guesses the recognizer can make for the HRC.
GetResultsHRC*	Retrieves recognition results as HRCRESULT objects. Each object represents one guess.
ProcessHRC*	Tells the recognizer that it should begin recognition and sets the maximum amount of time allowed for the task.
SetGuideHRC	Specifies a GUIDE structure for recognition.
SetMaxResultsHRC	Sets the maximum number of guesses the recognizer can make for the HRC.


HRCRESULT Functions

The HRCRESULT functions retrieve recognized symbols and other associated information from the recognizer. The GetResultsHRC function described in the previous table collects results into one or more HRCRESULT objects. Each object represents an alternative interpretation the recognizer has made about the input. Once an application calls GetResultsHRC to create the HRCRESULT objects, it can then call the HRCRESULT functions listed here to get the recognized characters from the objects.

Function	Description
CreateInksetHRCRESULT	Creates an inkset corresponding to recognition results.
DestroyHRCRESULT*	Frees the memory occupied by an HRCRESULT object, invalidating the handle value.
GetAlternateWordsHRCRESULT	Retrieves alternative guesses from the results of a recognition process.
GetBoxMappingHRCRESULT	Retrieves the indices for a range of symbols in boxes. For example, if writing begins in the fifth box of a guide, this function returns the index 4 for the first symbol.
GetHotspotsHRCRESULT	Returns the critical point for a given recognized gesture. (See the "Hot Spots" section.)
GetSymbolCountHRCRESULT*	Gets the length of the symbol array that forms one of the recognizer's guesses.
GetSymbolsHRCRESULT*	Retrieves symbol values corresponding to one of the recognizer's guesses.


Specifying an Alphabet Set

By supporting the following alphabet functions, a recognizer enables an application to specify which alphabet sets to consider during recognition. Alphabets are sets of characters within the entire range of characters the recognizer can interpret. For example, an application can limit recognition to any combination of lowercase characters, punctuation, math symbols, and so forth.

The Pen API defines ALC_ values to identify an alphabet set. For further information on alphabets and an abbreviated list of the most common ALC_ values, see "Configuring the HRC" in Chapter 5, "The Recognition Process." A full list of ALC_ values appears in Chapter 13, "Pen Application Programming Interface Constants."

The Pen API allows an application to set a priority when using multiple alphabet sets. Priority can resolve conflicts when one glyph has different interpretations in different alphabets. For example, consider a case in which input consists of both letters and numerals, but the application expects numerals more often. By setting an alphabet of ALC_ALPHANUMERIC and a priority of ALC_NUMERIC, the application tells the recognizer to consider both letters and numerals, but interpret for numerals first. This helps resolve the problem of distinguishing between the numeral "0" and the letter "O."

The following table lists the optional recognizer functions that pertain to alphabets.

Function	Description
GetAlphabetHRC	Retrieves bitwise-OR flags of ALC_ values indicating which alphabet(s) the recognizer can currently recognize.
GetAlphabetPriorityHRC	Retrieves bitwise-OR flags of ALC_values indicating priority.
SetAlphabetHRC	Constrains recognition to a specified set of alphabet characters.
SetAlphabetPriorityHRC	Specifies the priority of alphabets used during recognition.
SetBoxAlphabetHRC	Constrains recognition to a set of specified alphabet characters for individual boxes in a group of boxes.


Word Lists

A word list acts as a broad alphabet set. A list consists of valid words that can influence the confidence a recognizer places in a guess. After guessing at a word (or phrase), a recognizer can search for the guess in one or more word lists. Locating a guess in a word list helps verify the validity of the guess.

A word list can consist of a small group of words permanently stored in the recognizer's data segment. Often, however, the words reside in an accompanying file that the recognizer reads as required. A word list file should be in standard ANSI text format, one word per line, with each line ending in a carriage return and linefeed. This allows the user to emend the files, if necessary, with a text editor.

A recognizer that uses word lists should export the ReadHWL and WriteHWL functions. These functions read and write standard word list files, enabling an application to move words directly between a file and an HWL object.

The table below lists the exported functions for a recognizer that uses word lists.

Function	Description
AddWordsHWL	Adds a specified collection of words to an existing word list in memory.
CreateHWL	Creates a word list in memory, either empty or containing a given list of words.
DestroyHWL	Destroys a word list, invalidating the handle.
GetWordlistCoercionHRC	Retrieves the current degree of influence a word list or the system dictionary has on the confidence level of a guess.
GetWordlistHRC	Retrieves a word list from the HRC object.
ReadHWL	Reads from a file into an empty word list. The words must be in ANSI text format, one word per line, each line ending with a carriage return and linefeed.
SetWordlistCoercionHRC	Specifies the influence a word list or the system dictionary should exert on the confidence level of a guess.
SetWordlistHRC	Sets a word list into the HRC object.
WriteHWL	Writes from a word list to a file. The words are written as ANSI text, one word per line.


Training

Training is optional for a recognizer and the method of its implementation is up to the developer. Through training, a recognizer can consider the individual style and writing characteristics of different users when interpreting handwriting.

Training can be classified as either passive or active. However, the distinction usually pertains more to the application than to the recognizer. In passive training, the application quietly calls the recognizer's training functions whenever the user corrects a wrong guess. Correctly implemented, passive training helps ensure that the recognizer learns from its mistakes.

Active training takes place only when specifically requested by the user. A training window prompts the user for written samples, then the verified input is given to the recognizer to store in its database for that user. The recognizer can provide the active training support, though usually this task is left to an application. Microsoft usability studies have shown that users do not object to the time invested in active training.

The following table lists the functions that a recognizer with training capabilities can export. Only TrainHREC is used by version 2.0 Pen API. The other functions are obsolete in version 2.0 and should be included in a recognizer only if it is expected to work with older applications that work with a version 1.0 recognizer (see the Microsoft Pen Windows version 1.0 documentation for descriptions of these functions).

Function	Description
TrainContextInternal	Passes a previous recognition result that may contain errors along with the required interpretation. The system calls this function in response to a call to TrainContext. This function applies only to training recognizers compatible with version 1.0 of the Pen API. It is superseded by the TrainHREC function.
TrainHREC	Passes ink data and its required interpretation to the recognizer. The recognizer then stores the data and interpretation for future reference.
TrainInkInternal	Passes a previous erroneous recognition result along with the correct interpretation. The system calls this function when the application calls TrainInk. TrainInkInternal is rendered obsolete by TrainHREC and is only for training recognizers compatible with version 1.0 of the Pen API.


Interpreting Input

Typically, a recognizer converts pen input to recognized data in three steps:

1.	Collect and process the raw pen input data.

2.	Segment the written symbols.

3.	Note the order and direction of pen strokes.


Processing Raw Data

Raw data for recognition consists of pen coordinates. At a minimum, the recognizer must collect coordinate data while the pen is in contact with the tablet. Optionally, the recognizer can also process additional pen data such as pen pressure, the height of the pen tip above the pad, the angle of the pen, and the rotation of the pen. Not all pen devices can provide such information.

The Microsoft Handwriting Recognizer (GRECO.DLL) processes only coordinate data. The Pen API provides the OEMPENINFO structure for other types of pen data. For details, see the entry for OEMPENINFO in Chapter 11, "Pen Application Programming Interface Structures."

Noise Reduction and Normalization

To improve recognition, a recognizer can optionally employ noise reduction and normalization techniques. Noise reduction filters the input to weed out erroneous input—for example, pen skips, inadvertent marks from the user, or spurious noise from the input device.

Normalization corrects the natural skewing of handwritten text. In the same way that lines of text tend to run askew on blank paper, lines of pen input are usually not parallel to the top and bottom of the tablet. (An application can provide guidelines to help correct this tendency.)

Coordinates should be normalized relative to a horizontal line, called the baseline, that marks the bottom of the text. The baseline is analogous to a single line on lined notebook paper. Letter descenders, such as the lower parts of "y" or "j," descend below the baseline.

If a guide is present, its vertical coordinate defines the baseline. The baseline of a single-line guide in absolute coordinates is the sum of the yOrigin and cyBase members of the GUIDE structure. For more information, see the reference description of the GUIDE structure.

Allowed Time

The recognizer must return within the period of time specified by the dwTimeMax parameter of the ProcessHRC function. This parameter can have the values PH_MIN, PH_DEFAULT, or PH_MAX. Respectively, these values limit the time allowed for processing to approximately 50 milliseconds, 200 milliseconds, or as much time as required.

For values other than PH_MAX, the recognizer must ensure that it does not exceed the allotted time. The recognizer can either regularly poll with the GetTickCount function to mark the passage of time or, through the SetTimer function, provide a callback function that sets a time-out flag. The SREC sample recognizer described at the end of this chapter demonstrates the latter technique.

Allowed Number of Guesses

The recognizer must return no more than the maximum number of guesses specified by the SetMaxResultsHRC function. For a description of this function, see the "Number of Recognition Guesses" section in Chapter 5. By default, the recognizer returns only its best guess with no alternative guesses.


Segmentation of Symbols

A recognizer can view symbols at any granularity. For instance, most handwriting recognizers see individual letters and numerals as symbols. A recognizer for cursive writing, on the other hand, may see a complete word as a single symbol without distinguishing each letter of the word.

No matter how it views symbols, a recognizer must separate them within a stream of written symbols, a process called segmentation. The task of segmenting letters is greatly facilitated if the application provides box guides. In this case, the recognizer can assume that strokes lying within a box constitute a single character. The problem of accurate segmentation becomes more difficult for unguided text.

Segmentation is a crucial issue for recognizing different handwriting styles. The following table lists the forms of input in decreasing order of constraint on the user. The information in the table is taken from IBM Research Report RC 11175, No. 50249, (May 21, 1985), An Adaptive System for Handwriting Recognition, by C. C. Tappert.

Input form	Definition
Boxed input	Each character appears within its own box.
Discrete spaced	A set of strokes in a given space belong to the same character. (This is also called external segmentation.)
Discrete run on	Printed characters can overlap.
Cursive	Letters are connected by ligatures. The recognizer must either identify discrete letters or interpret a whole word at a time.
Mixed	The recognizer can segment discrete, run-on, and cursive writing.
Figure 8.1 illustrates these various styles.

The Pen API places few restrictions on the recognizer. At a minimum, however, a default recognizer must be able to recognize discrete characters because many applications do not use boxed input.


Stroke Order and Direction

Noting the order and placement of strokes can help a recognizer handle the following cases:

•	Delayed strokes. A delayed stroke occurs after other strokes, but belongs to an earlier, unfinished character. For example, in writing the word "two," the user might cross the "t" only after writing the rest of the word.

•	Correction strokes. A correction stroke alters the interpretation of other strokes — for example, placing a small stroke on the top of a "y" to change it to a "g." Correction strokes are often delayed.

•	Characters written out of order. For example, the user should be able to first write "t  o," then fill in a "w" between the letters. The recognizer should recognize the completed word as "two" instead of "tow."

•	Variations in stroke order or direction. Different users often write the multiple strokes of characters in a different order and direction. To take an extreme example, the four strokes forming a capital "E" can be written in 2 (4) *4! = 384 distinct ways.


Returning Results

To return results, the recognizer must conform to the procedures described in the section "Getting Results" in Chapter 5. That section examines the case where the words "clear," "dear," "clean," "dean," and "deer" represent valid interpretations of a handwritten word. In such a case, the recognizer should return the possibilities arranged in order of decreasing likelihood.

Without an internal concept of likelihood, the recognizer must impose an arbitrary order. However, for multiple recognizers to cooperate, a recognizer must have some concept of a poor match and be able to return "unknown" in lieu of a guess. While the pen API does not strictly require a recognizer to assign confidence levels to its guesses, without confidence values a recognizer cannot work efficiently with other recognizers.

The recognizer must be able to associate individual strokes with a recognized symbol. Applications can use the stroke data to correctly juxtapose the recognized text with the ink on the screen, redraw the data, or send information to other recognizers.

Speed and timing are very important in the recognition process. A recognizer should recognize input at least at the speed of normal handwriting, approximately two to three characters per second.


Results Messages

Results messages concerning recognition come from the system, not the recognizer. The messages depend on what services the application uses:

•	If DoDefaultPenInput runs the recognition process, it sends a chain of messages to the application as described in Chapter 2, "Starting Out with System Defaults."

•	If the application calls one of the version 1.0 recognizer functions, such as Recognize or ProcessWriting, the system generates a WM_RCRESULT message. The system can send many WM_RCRESULT messages during a single recognition event, depending on the frequency that the application has specified for receiving data. The lParam of each message points to a new, self-contained RCRESULT structure that contains the recognition results generated since the last WM_RCRESULT message.


The RCRESULT Structure

A recognizer can store its results in any format the developer wishes. It need not create an RCRESULT structure except in response to calls to certain superseded functions such as Recognize and RecognizeData. For completeness, this section describes the RCRESULT structure, which the developer may wish to use as a model for storage. Although a recognizer must calculate the information found in an RCRESULT structure, it need not organize the information in the same format.

Note  The RCRESULT structure is not required in version 2.0 of the Pen API and is supported only to maintain compatibility with older applications that use version 1.0 recognizer API.

The first member of the RCRESULT structure is a list called the symbol graph, which contains all the recognizer's guesses. An application can read the guesses in order of likelihood by walking through the symbol graph.

The Symbol Graph

The best way to understand the symbol graph is to first diagram its contents before describing how to actually read it. The following discussion again takes up the example in the section "Getting Results" in Chapter 5, in which the recognizer generated the five guesses "clear," "dear," "clean," "dean," and "deer." A diagram of the symbol graph that represents all these possibilities might look like this:

Letter:     {  cl   |   d  }    e    {  a   |   e  }    {  r   |   n  }

Confidence:    80%     60%    100%     85%     20%        80%     50%

Average:    clear   86%

            dear    81%

            clean   79%

            dean    74%

            deer    58%

If you study the diagram a moment, you will see its logic. Alternative letters appear separated by a C bitwise-OR symbol, with the most likely alternative first. All the guesses in this example, however, agree that the second (or third) character is the letter "e," so it has no alternatives. Taking the first letter in each alternative set produces the most likely of the guesses — in this case, the word "clear."

The symbol graph includes confidence values for each character or character set (as in the case of the interpretation "cl"). The recognizer can determine a confidence value for an entire word by averaging the values for each character or character set, as shown in the diagram above. (Note that this hypothesis is purely for purposes of discussion. The pen API does not mandate how a recognizer determines its confidence levels. The influence of word lists and other factors may also change confidence levels.)

Symbol graphs must, therefore, contain three types of information:

•	All characters (or character sets) determined as likely interpretations for a set of pen strokes

•	A map identifying the pen strokes that correspond to each interpretation

•	A confidence level for each interpretation

As described in Chapter 11, "Pen Application Programming Interface Structures," the symbol graph is a structure of type SYG. The SYG structure contains two additional data structures that provide the needed information: symbol correspondence and symbol element structures.

A symbol correspondence structure SYC delineates a specific subset of the strokes entered by the user. Each SYC contains the first and last strokes of a subset; these strokes and the strokes between them define the subset of pen data associated with the SYC. The symbol graph contains an array of SYC structures, each of which corresponds to a different part of the ink input. Taken together, the SYC structures define all the ink gathered during the input session.

A SYG structure also contains an array of symbol element SYE structures. An SYE contains a symbol value, a confidence level, and an index into the array of SYC structures. Each character or character set in the recognized input has its own symbol element.

The Best Guess

The RCRESULT structure also provides information about the recognizer's "best guess." The best guess is simply the first interpretation in the symbol graph, which lists interpretations in descending order of probability. Since an application is often interested only in the most likely interpretation, the recognizer should place in the RCRESULT the following three members specifically to identify the best guess:

•	The lpsyv member points to a null-terminated symbol string containing the best guess.

•	The cSyv member contains the number of symbols in the best guess string.

•	The hSyv member is the handle to the memory block to which lpsyv points.

Location and Position of the Input

The RCRESULT structure also contains information regarding the location and position of the ink entered by the user.

•	The nBaseLine member is the recognizer's estimate of the baseline of the ink entered by the user. (For a definition of baseline, see "Noise Reduction and Normalization" earlier in this chapter.) If the baseline is not known, the recognizer sets this value to 0. The Microsoft Handwriting Recognizer (GRECO.DLL) sets nBaseLine to 0.

•	The nMidLine member is the recognizer's estimate of the midline of the ink entered by the user. If the midline is not known, the recognizer sets this value to 0. The Microsoft Handwriting Recognizer sets nMidLine to 0.

•	The rectBoundInk member is a Windows RECT structure. It holds the bounding rectangle that circumscribes the area of the screen on which the user has written. Typically, an application uses rectBoundInk to invalidate the screen area to update the display in the appropriate location. This occurs, for example, when Windows replaces ink on the screen with recognized text.

Contextual Information

Two elements of the RCRESULT structure provide information about the recognition event, but not as a part of the results of recognition. They are lprc, a far pointer to the RC structure passed to the Recognize function, and wResultsType, a flag that describes how the recognition event proceeded. The wResultsType flag contains a combination of RCRT_ constants, described in Chapter 13, "Pen Application Programming Interface Constants."

The Ink

The final two members of the RCRESULT structure contain information about the ink entered by the user.

•	The pntEnd member contains the last point of the ink data from the user only if PCM_RECTBOUND or PCM_RECTEXCLUDE have been specified. An application sets these flags either in the lPcm member of the RC structure or the dwPcm member of the PCMINFO structure.

•	The hpendata member is a handle to a pen data memory block that contains all of the ink information entered by the user.


Hot Spots

While recognizing a symbol, the recognizer may also identify critical points on the symbol called hot spots. Hot spots can apply to any symbol but usually are of interest only for gestures. For example, if the user writes an X for deletion, the cross of the X — its hot spot — points to the item to be deleted. If the recognizer identifies hot spots for a recognized symbol, it places coordinates for all hot spot points in the rgpntHotSpot member of the symbol's SYG structure. This array can hold up to MAXHOTSPOT points. Note that all symbols do not have the same number of hot spots, and many symbols have none.


Writing a Recognizer

A recognizer must reflect the developer's requirements, design, and programming style. Although it cannot prescribe any one method for creating a recognizer, this section offers guidance on writing several important recognition functions. The section also presents a sample recognizer called SREC to illustrate some of the information in this chapter.

For a description of how an application uses the InstallRecognizer function to load a recognizer function, see "Creating the HRC" in Chapter 5. The reference section for InstallRecognizer in Chapter 10 also discusses how to load a recognizer by using the LoadLibrary function to aid in debugging the recognizer. To designate a recognizer as the system default recognizer, see "Registry Configuration" in Appendix A.


Recognition Functions

The following sections provide fragmentary examples of the recognition functions AddPenInputHRC, CreateCompatibleHRC, CreateInksetHRCRESULT, CreatePenDataHRC, and DestroyHRC.

For purposes of discussion, the examples assume the recognizer's HRC takes the form of a private structure called HRCinternal. This structure contains a handle to an HPENDATA block, which stores the stroke information and pen data points for an input session. (For a description of HPENDATA, see "The HPENDATA Object" in Chapter 4.) The HRC applies only to a single session — say, a word written by the user. The client application must create a new HRC to recognize the next word.

The following typedef statement defines the hypothetical HRC object used by the example code fragments in this section:

typedef struct

{

DWORD       reserved;           // Reserve first DWORD for system

HGLOBAL     hglobal;            // Handle from GlobalAlloc

HPENDATA    hpendata;           // HPENDATA handle for input

int         wPdk;               // Current stroke is pen-up or down

                                    // Other information for the HRC

.

.

} HRCinternal, FAR *LPHRCinternal;

Notice that the structure reserves the first DWORD for system use. This is required for all recognizer objects. The structure also groups pertinent variables within the object itself instead of allocating them as global data. This ensures that the object remains private to the client that creates it.

In the code that follows, all internal functions have an "N" prefix. This helps distinguish them from standard API functions.


CreateCompatibleHRC

The CreateCompatibleHRC function allocates memory for the HRC object. The example below calls the Windows function GlobalAlloc and uses the returned memory handle as the HRC. Locking the allocated memory with GlobalLock provides a far pointer to the allocated HRCinternal structure.

When an input session begins, the pen state is always down. Therefore, the function initializes the wPdk member to PDK_DOWN.

HRC WINAPI	CreateCompatibleHRC( HRC hrcTemplate, HREC hrec )

{

HGLOBAL         hglobal;        // Handle of allocated HRC object

LPHRCinternal   lphrc;          // Far pointer to object

.

.

.

// Allocate memory for HRC and get far pointer to it

hglobal = GlobalAlloc( GHND, sizeof( HRCinternal ) );

lphrc   = (LPHRCinternal) GlobalLock( hglobal );

// If failure, return NULL

if (!lphrc)

return NULL;

// Save HRC memory handle, because DestroyHRC will need it

lphrc->hglobal = hglobal;

// If template provided, copy its information to the new HRC

if (hrcTemplate)

NCopyTemplateInfo( hrcTemplate, lphrc );

// Initialize other information

lphrc->hpendata = CreatePenData( NULL, 0, PDTS_HIENGLISH, 0 );

lphrc->wPdk     = PDK_DOWN;

.

.

.

// If no errors, return pointer as HRC handle

return ((HRC) lphrc);

}


DestroyHRC

Generally, the life of an HRC object is brief. An application destroys the HRC after obtaining results from the recognizer and creates a new HRC at the start of the next input session.

In the model described above, CreateCompatibleHRC calls GlobalAlloc to allocate system memory in which the HRC object resides. The function returns a pointer to the fixed allocation as an HRC handle.

DestroyHRC reverses the action, using the original HGLOBAL handle to free the allocated memory. When DestroyHRC successfully returns, the HRC handle is no longer valid. The application should set the handle to NULL to prevent accidental reuse, as described in "Destroying the HRC" in Chapter 5.

int WINAPI	DestroyHRC( HRC hrc )

{

    LPHRCinternal  lphrc = (LPHRCinternal) hrc;  // Pointer to HRC

if (!GlobalUnlock( lphrc->hglobal ))

return HRCR_OK;

else

return HRCR_ERROR;

}


AddPenInputHRC

As the pen moves, an application continually gets data from the pen driver by calling GetPenInput. It then passes the retrieved information to the recognizer via AddPenInputHRC. This function may be called many times before the user completes the stroke. Each time, AddPenInputHRC receives a small subset of points that collectively form a pen stroke.

Along with the subset of points, AddPenInputHRC receives a STROKEINFO structure that represents the points in the subset. For example, the member dwTick contains the starting time for each subset, not the entire stroke. (The starting time of the first subset of a stroke is also the starting time of the entire stroke.) Similarly, cPnt contains the point count only for the current subset.

The following example lets the system take care of accumulating the points. It calls the AddPointsPenData API function to add the subset of points to the HPENDATA block belonging to the HRC. The code also demonstrates how a recognizer can determine when one stroke ends and another begins. This allows the recognizer to take some intermediate steps to facilitate recognition at the end of each stroke. Such intermediate work can remove some of the burden from ProcessHRC, improving response time and perhaps accuracy as well.

int WINAPI	AddPenInputHRC( HRC hrc, LPPOINT lppnt, LPVOID lpvOem,

                            UINT oemdatatype, LPSTROKEINFO lpsi )

{

    LPHRCinternal   lphrc = (LPHRCinternal) hrc; // Pointer to HRC

    int             iRet  = HRCR_OK;             // Return code

.

.

.

//

// If state change from down to up (or vice versa), the previous

// stroke has ended and the point data that lppnt points to belongs

// to a new stroke.  Take any intermediate action to process the

// just-completed stroke.

//

if (lpsi->wPdk != lphrc->wPdk)

{

.

.	// Take intermediate action

.

lphrc->wPdk = lpsi->wPdk	// Note new pen state

}

// Accumulate stroke points in internal HPENDATA object

if (!AddPointsPenData( lphrc->hpendata,	// HPENDATA handle

   lppnt,	// Point subset

   lpvOem,	// OEM data

   lpsi ))	// Subset STROKEINFO

iRet = HRCR_ERROR;

.

.

.

// Return appropriate error code (HRCR_OK or HRCR_ERROR)

return (iRet);

}


CreatePenDataHRC

The CreatePenDataHRC function returns a handle to an HPENDATA object that contains the raw data used for recognition. In the example code above, AddPenInputHRC has already done the work of storing the pen data into an internal HPENDATA. Thus, the hypothetical CreatePenDataHRC function outlined below simply duplicates the internal object.

HPENDATA WINAPI    CreatePenDataHRC( HRC hrc )

{

    LPHRCinternal  lphrc = (LPHRCinternal) hrc;  // Pointer to HRC

// Clone the internal HPENDATA and return its handle

return (DuplicatePenData( lphrc->hpendata, 0 ));

}


CreateInksetHRCRESULT

The optional CreateInksetHRCRESULT function creates a corresponding inkset from the data in an HPENDATA object. For a description of inksets and the INTERVAL structure, see "The HINKSET Object" in Chapter 4.

A description of the CreateInksetHRCRESULT function first requires a brief discussion of stroke start and end times. Some of this information also appears in the section "Timing Information" in Chapter 4, but it is presented here from the point of view of the recognizer rather than the application.

A stroke's start time is the starting tick count of the first group of points that AddPenInputHRC receives when a new stroke begins. The member dwTick of the STROKEINFO structure is the number of milliseconds that have elapsed since the system tick reference determined at system startup time. A recognizer can retrieve this value in an ABSTIME structure through a call to the Pen API function GetPenMiscInfo:

    ABSTIME  atTickRef;

    GetPenMiscInfo( PMI_TICKREF, (LPARAM)((LPABSTIME) &atTickRef) );

The STROKEINFO structure also contains in its cPnt member the number of points in the collection. Because the pen device sends points at a constant rate (called the sampling rate), the number of points in the collection implies how much time has elapsed between the first and last points.

The sampling rate does not change, so the recognizer need only determine the rate during initialization and store the value. The following example shows how a recognizer can get the sampling rate from the pen driver:

PENINFO     pinfo;

HDRVR       hPenDrv;

int         vnSamplingRate;

.

.

.

hPenDrv = OpenDriver( "pen", 0, 0 );

if (hPenDrv)

{

if (SendDriverMessage( hPenDrv, DRV_GetPenInfo, (LPARAM)&pinfo, 0 ))

vnSamplingRate = pinfo.nSamplingRate;

CloseDriver( hDriverPen, 0, 0 );

}

With this information, CreateInksetHRCRESULT can fill an INTERVAL structure with a stroke's start and stop times as shown below. The code assumes the HRCRESULT object contains the HRC handle. This allows the internal function NGetStrokeFromHPENDATA to locate the internal HPENDATA object with the raw input data.

HINKSET WINAPI CreateInksetHRCRESULT( HRCRESULT hrcresult,

  UINT isyv, UINT csyv)

{

HINKSET     hinkset;

INTERVAL    interval;

STROKEINFO  si;

DWORD       dwMsec;

UINT        i, j;

// Call Pen API to create hinkset object

hinkset = CreateInkset( GMEM_MOVEABLE | GMEM_DDESHARE );

// Initialize INTERVAL with tick reference (described above)

GetPenMiscInfo( PMI_TICKREF,

                    (LPARAM)((LPABSTIME) &interval.atBegin) );

// For each SYV in the HRCRESULT between the given indices ...

for (i = 0; i < csyv; i++, isyv++ )

{

j = 0;

// For each stroke in the SYV ...

while ( NGetStrokeFromHPENDATA( hrcresult, &si, isyv, j++ ))

{

//

// Calculate the interval for the stroke.

// Note si.dwTick is the number of milliseconds

// that have elapsed since system start-up.

//

dwMsec = (DWORD)(1000L*interval.atBegin.sec +

    interval.atBegin.ms + si.dwTick);

interval.atBegin.sec = dwMsec/1000L;

interval.atBegin.ms  = (UINT)(dwMsec % 1000L);

dwMsec = (DWORD)(1000L*interval.atBegin.sec +

     interval.atBegin.ms +

     1000L*si.cPnt/vnSamplingRate);

interval.atEnd.sec = dwMsec/1000L;

interval.atEnd.ms  = (UINT)(dwMsec % 1000L);

// Call Pen API function to add interval to inkset

AddInksetInterval( hinkset, (LPINTERVAL) &interval );

}

}

return (hinkset);

}


A Sample Recognizer

This section describes a simple recognizer called SREC that demonstrates some of the information given in this chapter. The text describes the most interesting parts of the program and illustrates with code fragments. The complete source listing for SREC.C resides in the SAMPLES\PEN\SREC subdirectory.

SREC is used by the PENAPP application described in Chapter 7, "A Sample Pen Application." To see how SREC works, you must create both PENAPP.EXE and SREC.DLL using the supplied MAKE files, then run PENAPP.

When using the SREC recognizer, PENAPP specifies that a stroke ends when the pen leaves the tablet. Therefore, SREC recognizes only one stroke at a time. SREC takes the beginning and ending points of the stroke and calculates the nearest compass direction of the line formed by these endpoints.

For its HRC object, SREC creates a structure that contains an HPENDATA handle to the input data, the module handle returned from InstallRecognizer, and recognition results. The following typedef statements define the HRC and HRCRESULT objects for SREC. Notice that SREC keeps its HRCRESULT within the HRC.

typedef struct                      // HRCRESULT object

{

DWORD   reserved;               // Reserve top DWORD

SYG     syg;                    // Recognition results

} HRCRESULTinternal, FAR *LPHRCRESULTinternal;

typedef struct                      // HRC object

{

DWORD               reserved;   // Reserve top DWORD

HPENDATA            hpendata;   // Raw pen data to be recognized

HREC                hrec;       // Module handle for SREC

HRCRESULTinternal   hrcresult;  // HRCRESULT structure

} HRCinternal, FAR *LPHRCinternal;

When it finishes recognizing a stroke, SREC fills out a SYG symbol graph structure. The structure holds one of the symbol values listed here:

Symbol value	Direction
syvEast	Right
syvSouth	Down
syvWest	Left
syvNorth	Up
syvDot	Single tap
The following sections describe the functions that SREC exports. These functions appear under the same categories described earlier in this chapter, in the section "List of Exported Functions." This allows for quick cross-referencing between a general description of a function and its actual implementation in SREC.

Although defined by the Pen API, the function names below appear in monospace font rather than bold because the names refer to routines in the SREC.C source file.


SREC Initialization Functions

As a Windows dynamic-link library, SREC exports LibMain and WEP. As a recognizer, it also exports the required initialization function ConfigRecognizer. All recognizers compatible with version 2.0 of the Pen API must provide these functions.

LibMain and WEP

The first two functions in the SREC recognizer are the standard Windows functions required in any dynamic-link library, LibMain and WEP. LibMain, the main DLL function, is analogous to WinMain. It performs any needed initialization and unlocks the data segment of the library. WEP is the standard DLL termination function, which receives control when Windows unloads the DLL. For a description of WEP, see the references listed at the beginning of this chapter.

ConfigRecognizer

The ConfigRecognizer function handles the recognizer's initialization tasks and configures it for special options. When it loads a recognizer, InstallRecognizer internally calls the recognizer's ConfigRecognizer function with the subcommand WCR_INITRECOGNIZER. In response to this call, the recognizer should perform any required initialization tasks.

As its name suggests, ConfigRecognizer handles more than initialization work. It also provides the means for setting recognizer options and to query for capabilities. With version 2.0 of the Pen API, which can load multiple recognizers, applications do not call ConfigRecognizer, because the function provides no way to identify the intended library. Instead, applications call the ConfigHREC function, which takes

the same arguments as ConfigRecognizer, with the addition of the HREC handle returned from InstallRecognizer. Internally, the system identifies the intended recognizer from the handle and passes the arguments to ConfigRecognizer in the appropriate recognizer. Thus, ConfigHREC and ConfigRecognizer refer to the same function. ConfigRecognizer is unique in that it is the only function exported by a recognizer that applications do not call directly.

As the following code fragment shows, SREC returns only its identification string and version number from ConfigRecognizer. Note also that SREC does not allow itself to be set as the system recognizer. Since SREC does not support standard editing gestures or recognize characters, it cannot serve as a system default recognizer.

int WINAPI   ConfigRecognizer( UINT uSubFunc,

                               WPARAM wParam, LPARAM lParam )

{

int	iRet = TRUE;

switch ( uSubFunc )

{

.

.

.

case WCR_INITRECOGNIZER:	// No initialization or

case WCR_CLOSERECOGNIZER:	//   clean up duties to

break;	//   perform

case WCR_RECOGNAME:

lstrncpy( (LPSTR)lParam, szID, wParam );

break;

case WCR_DEFAULT:	// Can't be system default

case WCR_QUERY:	// Does not support config dialog

case WCR_QUERYLANGUAGE:	// Does not support any language

iRet = FALSE;

break;

case WCR_PWVERSION:

case WCR_VERSION:

iRet = 0x0002;	// Recognizer version 2.0

break;

default:

iRet = FALSE;	// Anything else is unsupported

break;

}

return iRet;

}

For a complete list of WCR_ subfunctions, refer to the reference section for ConfigRecognizer in Chapter 10.

When the last client application unloads a recognizer, the UninstallRecognizer function calls the recognizer's ConfigRecognizer function with the command WCR_CLOSERECOGNIZER. This informs the recognizer that it is being unloaded. The previous code takes no action for WCR_CLOSERECOGNIZER because in SREC, memory allocations come from the local heap. As with any Windows-based program, a DLL's heap resides in its data segment. When Windows unloads a DLL, it automatically returns the entire data segment to the memory pool.

However, unloading SREC does not destroy its internal HPENDATA object. HPENDATA blocks occupy global heap space. If the client application terminates or unloads SREC without first destroying all HRC objects created by SREC, the corresponding HPENDATA blocks are left orphaned in memory. A recognizer more intelligent than SREC should maintain a count of active HPENDATA allocations and free any that remain before terminating.

A recognizer's WEP routine also receives control when Windows unloads the recognizer. Developers should note a subtle difference between handling cleanup chores in ConfigRecognizer and in WEP. When the former executes in response to the WCR_CLOSERECOGNIZER subfunction, the client is still active. However, the WEP routine cannot safely make the same assumption when it executes. ConfigRecognizer can therefore conceivably post a message to the client or perform some other action that relies on an active recipient.

The disadvantage of ConfigRecognizer is that the recognizer cannot be certain the function will execute because the client might not call UninstallRecognizer. Since the WEP function is guaranteed to execute when Windows unloads the recognizer, essential cleanup duties, such as unhooking interrupts, should be handled in WEP.


SREC Recognition Functions

This section takes a brief look at some of SREC's exported recognition functions, including CreateCompatibleHRC, ProcessHRC, and CreatePenDataHRC. The code uses the macro

#define  lpHRC    ((LPHRCinternal) hrc)

to represent a far pointer to the HRC object.

CreateCompatibleHRC

The CreateCompatibleHRC function allocates an HRCinternal structure in the local heap, creates an HPENDATA block for the pen data, and returns a far pointer to the structure. The LPTR argument forces LocalAlloc to return a far pointer to the allocation instead of a memory handle. This far pointer serves as SREC's HRC handle.

Since the HRC has no configurable elements, SREC ignores any template HRC provided in the first parameter.

HRC WINAPI 	CreateCompatibleHRC( HRC hrcTemplate, HREC hrec )

{

HRC	hrc;

hrc = (HRC) LocalAlloc( LPTR, sizeof( HRCinternal ) );

if (hrc)

{

lpHRC->hrec     = hrec;

lpHRC->hpendata = CreatePenData( NULL, 0, PDTS_HIENGLISH, 0 );

if (lpHRC->hpendata)

return (hrc);

}

LocalFree( (HLOCAL) hrc );	// If error, free allocation

return NULL;	//   and return NULL

}

ProcessHRC

The most interesting feature of SREC's ProcessHRC function is the way it sets a time limit for processing. If called with a limit of PH_MIN or PH_DEFAULT, ProcessHRC passes the address of a callback function to SetTimer. When the specified time-out period elapses, the callback function receives control and sets a global flag called vfOutOfTime.

A recognizer can use this technique to ensure that it does not overrun a specified time limit. Its internal processing functions should check the vfOutOfTime flag regularly and, if it is set, terminate immediately. In this case, ProcessHRC returns a value of HRCR_INCOMPLETE to tell the caller recognition has not yet finished.

int WINAPI      ProcessHRC( HRC hrc, DWORD dwTimeMax )

{

    UINT        idTimer, uTime;

    int         iRet;

vfOutOfTime = FALSE;	// Initialize time-out flag

if (dwTimeMax != PH_MAX)	// If time limit specified ...

{

uTime   = (dwTimeMax == PH_MIN) ? 50 : 200;

idTimer = SetTimer( NULL, NULL, uTime, (TIMERPROC) TimerProc );

iRet    = GetSYG( hrc );	// Quit if out of time

KillTimer( NULL, idTimer );

}

else

iRet = GetSYG( hrc );	// Don't quit until finished

return (iRet);

}

VOID CALLBACK	TimerProc( HWND hwnd, UINT ms, UINT iId, DWORD dwTm )

{

vfOutOfTime = TRUE;

}

CreatePenDataHRC

SREC keeps an HPENDATA handle in its HRC structure. Because the AddPenInputHRC function has already stored pen input in the internal HPENDATA block, CreatePenDataHRC simply duplicates the block.

HPENDATA WINAPI	CreatePenDataHRC( HRC hrc )

{

if (hrc)

return (DuplicatePenData( lpHRC->hpendata, 0 ));

else

return NULL;

}


Summary of the Pen Application Programming Interface

This chapter summarizes the pen services by listing them according to category. The lists complement the detailed descriptions of functions, structures, messages, and constants in the reference chapters that follow this chapter. The lists let you quickly identify those services that pertain to your application, then refer to the reference chapters for detailed information.

The "Pen Kernel Functions" section is of interest to developers who want to write applications for Microsoft Windows 95 that use ink data without the presence of pen hardware.


Pen API Functions

The Pen Application Programming Interface (API) provides functions that can be divided into 10 broad categories. The following table describes the 10 categories. Other tables list the functions within each category.

Function category	Description
System and hardware	Provide information about pen hardware and current system assumptions.
Display	Display ink data, get screen information.
Pen data	Collect, copy, move, and delete data in an HPENDATA object.
Recognition	Recognize handwritten characters.
Symbol manipulation	Collect and convert symbols returned from a recognizer.
Time intervals	Manipulate time intervals associated with pen strokes.
Compression	Reduce the size of an HPENDATA object.
Utility	Miscellaneous utility services provided by the system.
Hook	Program hooks to monitor inking or recognition.
Obsolete	Obsolete functions of version 1.0 maintained by version 2.0 only for compatibility reasons.


List of Pen API Functions

The following tables list by category all functions in version 2.0 of the Pen API. Functions appear in alphabetical order within each category, together with a brief description.

System and hardware functions	Description
GetPenAsyncState	Gets state of pen barrel button.
GetPenMiscInfo	Gets current system settings.
GetVersionPenWin	Gets the Pen API version number.
SetPenMiscInfo	Sets system defaults and assumptions.
UpdatePenInfo	Called by the pen driver to notify the system of a change in the driver configuration.
Display functions	Description
CreatePenDataRegion	Returns a screen region that contains the points of an HPENDATA object.
DrawPenDataEx	Enhanced version of DrawPenData.
DrawPenDataFmt	Default version of DrawPenDataEx.
RedisplayPenData	Displays collected pen data exactly as originally drawn.
ShowKeyboard	Displays or hides the on-screen keyboard.
StartInking	Begins the process of leaving a visible ink trail  as the pen moves. See the descriptions of StartPenInput and DoDefaultPenInput.
StopInking	Stops the inking process begun by a call to StartInking.
Pen data functions	Description
AddPenDataHRC	Adds an HPENDATA object to an HRC.
AddPointsPenData	Adds new points and original equipment manufacturer (OEM) data to an existing HPENDATA object.
CreatePenData	Allocates memory for a new HPENDATA object and initializes its header.
CreatePenDataEx	Enhanced version of CreatePenData.
CreatePenDataHRC	Returns handle to HPENDATA object associated with an HRC.
DestroyPenData	Frees memory occupied by an HPENDATA memory block.
DuplicatePenData	Clones an existing HPENDATA object.
ExtractPenDataPoints	Copies or removes points from a stroke.
ExtractPenDataStrokes	Copies or removes selected strokes, optionally creating a new HPENDATA object from the copied strokes.
GetPenDataAttributes	Retrieves information about an HPENDATA object.
GetPenDataInfo	Gets status information for an HPENDATA object.
GetPointsFromPenData	Returns an array of points from an HPENDATA object.
GetStrokeAttributes	Retrieves information about a stroke.
GetStrokeTableAttributes	Retrieves information about a stroke's class.  The class is an entry in a table stored in the PENDATAHEADER structure.
InsertPenData	Combines two HPENDATA blocks.
InsertPenDataPoints	Inserts points into a stroke in an HPENDATA object.
InsertPenDataStroke	Inserts data for a new stroke into an existing HPENDATA object.
OffsetPenData	Offsets pen data points by a specified amount.
PenDataFromBuffer	Reverse of PenDataToBuffer, which must be called first. Creates an HPENDATA block and writes the buffer back into it.
PenDataToBuffer	Serializes the contents of an HPENDATA block to a buffer.
RemovePenDataStrokes	Removes specified strokes from an HPENDATA object.
ResizePenData	Scales ink data to fit a specified rectangle.
SetStrokeAttributes	Sets attributes of a stroke. Reverse of GetStrokeAttributes.
SetStrokeTableAttributes	Sets attributes for a stroke's class. Reverse of GetStrokeTableAttributes.
Recognition functions	Description
AddPenInputHRC	Adds raw pen input to an HRC object.
AddWordsHWL	Adds words to a word list.
ConfigRecognizer	System access to recognizer configuration. Applications should not call this function.
CreateCompatibleHRC	Creates an empty HRC object.
CreateHWL	Creates a word list.
DestroyHRC	Destroys a recognizer's recognition context object.
DestroyHRCRESULT	Destroys a recognizer's results object.
DestroyHWL	Destroys the word list handle created by CreateHWL and frees its memory.
EnableGestureSetHRC	Enables or disables recognition of specified gestures.
EnableSystemDictionaryHRC	Specifies whether a recognizer should use its dictionary.
EndPenInputHRC	Informs a recognizer that the input session has ended.
GetAlphabetHRC	Retrieves the current alphabet from a recognizer.
GetAlphabetPriorityHRC	Retrieves the current alphabet priority from a recognizer.
GetAlternateWordsHRCRESULT	Gets alternative guesses made by a recognizer.
GetBoxMappingHRCRESULT	Retrieves from a recognizer the locations of a range of symbols in boxes.
GetBoxResultsHRC	Gets recognition results for a range of boxes.
GetGuideHRC	Gets a copy of the GUIDE structure (if any) in an HRC object.
GetHotspotsHRCRESULT	Returns the hot spots for a specified gesture.
GetHRECFromHRC	Gets module handle of recognizer from an HRC.
GetMaxResultsHRC	Gets the maximum number of guesses a recognizer can make.
GetResultsHRC	Retrieves an HRCRESULT object from recognizer containing recognition results.
GetWordlistCoercionHRC	Gets the current degree of influence a word list or dictionary has on recognition confidence levels.
GetWordlistHRC	Gets a word list from an HRC object.
InstallRecognizer	Loads a specified recognizer.
ProcessHRC	Tells recognizer to process input for a given period of time.
ReadHWL	Reads a word list from a file.
SetAlphabetHRC	Specifies the alphabet for a recognition session.
SetAlphabetPriorityHRC	Specifies alphabet priority for a session.
SetBoxAlphabetHRC	Specifies the alphabet for a range of boxes.
SetGuideHRC	Specifies guides for an HRC.
SetMaxResultsHRC	Sets the maximum number of guesses a recognizer can make.
SetWordlistCoercionHRC	Sets the degree of influence a word list or dictionary has on recognition confidence levels.
SetWordlistHRC	Identifies a word list for an HRC object.
TrainHREC	Passes ink and correct interpretations to recognizer for training.
UninstallRecognizer	Unloads a specified recognizer.
WriteHWL	Writes a word list to a file.
Symbol manipulation functions	Description
CharacterToSymbol	Converts an ANSI string to an array of symbol values.
EnumSymbols	Enumerates symbol strings in a symbol graph.
FirstSymbolFromGraph	Returns the array of symbols that is the most likely interpretation of a specific symbol graph.
GetSymbolCount	Returns the number of symbol strings contained in the symbol graph.
GetSymbolCountHRCRESULT	Gets the number of symbol values in results.
GetSymbolMaxLength	Gets the length of the longest symbol string contained in the symbol graph.
GetSymbolsHRCRESULT	Gets symbol values of recognition results.
SymbolToCharacter	Converts an array of symbols to an ANSI string.
Time interval functions	Description
AddInksetInterval	Adds an INTERVAL structure to an existing HINKSET object.
CreateInkset	Creates an empty inkset into which intervals can be added with the AddInksetInterval function.
CreateInksetHRCRESULT	Retrieves the intervals for a specified series of symbols returned by the recognizer.
DestroyInkset	Frees memory occupied by an inkset and invalidates the HINKSET handle.
GetInksetInterval	Copies a series of intervals from an HINKSET object to an array of INTERVAL structures.
GetInksetIntervalCount	Returns the number of intervals in an HINKSET object.
Compression functions	Description
CompressPenData	Compresses and uncompresses data.
DPtoTP	Converts display coordinates to tablet coordinates.
MetricScalePenData	Converts pen data points to one of the supported metric modes.
TPtoDP	Converts tablet coordinates to display coordinates.
TrimPenData	Removes selected data from an HPENDATA block.
Utility functions	Description
AtomicVirtualEvent	Blocks out physical pen events while posting virtual events.
BoundingRectFromPoints	Returns the bounding rectangle of an array of points.
ConfigHREC	Configures or queries recognizer options.
CorrectWriting	Displays lens or Correct Text dialog box to allow user to correct text.
CorrectWritingEx	Sends text to the CorrectText dialog box to allow the user to edit text using the Japanese Data Input Window. (Japanese version only.)
DoDefaultPenInput	Runs high-level recognition/data collection. Internally calls StartPenInput, StartInking, StopPenInput, and StopInking.
GetPenAppFlags	Returns the task flags created by SetPenAppFlags.
GetPenInput	Collects input data as the user writes.
GetPenResource	Retrieves a copy of the pen services resource. (Japanese version only.)
HitTestPenData	Determines whether a given point lies near a stroke.
IsPenEvent	Determines whether a WM_LBUTTONDOWN message is generated by a mouse or pen device.
KKConvert	(Japanese version only.) Activates the Kana-to-Kanji converter.
PeekPenInput	Retrieves information about a pen packet in the pen input queue. This function is similar to GetPenInput, but does not remove the pen packet from the queue.
PostVirtualKeyEvent	Simulates a keystroke by sending a virtual key code to Windows.
PostVirtualMouseEvent	Simulates mouse activity by sending a virtual mouse event to Windows.
SetPenAppFlags	Sets pen flags for the application that are used globally by the pen services.
StartPenInput	Begins collecting into an internal buffer ink  data generated by the moving pen. See also  the descriptions of . DoDefaultPenInput and StartInking.
StopPenInput	Ends collection process begun by a call to StartPenInput.
TargetPoints	Determines the logical recipient of data among several targets.
Hook functions	Description
SetPenHook	Sets or removes a hook for capturing low-level pen events.
SetResultsHookHREC	Sets a hook for recognition results.
UnhookResultsHookHREC	Unhooks a hook set by SetResultsHookHREC.
Obsolete functions	Description
BeginEnumStrokes	Locks an HPENDATA memory block in global memory in preparation for reading.
CloseRecognizer	Called by the system when uninstalling a  recognizer. Subfunction has been superseded  by WCR_CLOSERECOGNIZER in ConfigRecognizer.
CompactPenData	Data compression function superseded by CompressPenData and TrimPenData.
DictionarySearch	Searches dictionary for a word or phrase.
DrawPenData	Displays ink according to a display context HDC. Superseded by DrawPenDataEx.
EmulatePen	Emulates a pen system.
EndEnumStrokes	Unlocks an HPENDATA memory block. Required after calling BeginEnumStrokes.
GetGlobalRC	Retrieves a copy of the current system RC structure.
GetPenDataStroke	Gets the raw data for a stroke stored in an HPENDATA memory block.
GetPenHwEventData	Retrieves a range of pen event data from the internal pen data buffer.
InitRC	Initializes recognition context for the recognizer. Only for compatibility with version 1.0.
InitRecognizer	Called by the system when it installs a recognizer. Superseded by WCR_INITRECOGNIZER subfunction in ConfigRecognizer.
IsPenAware	Checks application's capability to handle pen events. Superseded by GetPenAppFlags.
ProcessWriting	Runs high-level recognition services. Superseded by DoDefaultPenInput.
Recognize	Begins recognition for a version 1.0 recognizer.
RecognizeData	Delayed recognition for a version 1.0 recognizer.
RegisterPenApp	Identifies an application to the system as pen-aware. Superseded by SetPenAppFlags.
SetGlobalRC	Sets default settings for the specified recognition context. This function should be called only from the pen Control Panel program.
SetRecogHook	Installs and removes a recognition hook in version 1.0. Superseded by SetResultsHookHREC.
TrainContext	Passes to the recognizer a previous recognition result that may contain errors along with the required interpretation.
TrainContextInternal	Called by system when an application calls TrainContext.
TrainInk	Informs the recognizer at the DLL recognition level that the raw data input represents the symbol value results.
TrainInkInternal	Called by system when an application calls TrainInk.


Pen Kernel Functions

As described in Chapter 1, the services of the Pen API are provided by the libraries PENWIN.DLL and PKPD.DLL. PENWIN.DLL is provided by original equipment manufacturers and exists only on systems with attached pen hardware. The ink management services of PKPD.DLL, however, are part of Windows 95. This allows an application to display and manipulate ink data with any installation of Windows 95, even one without pen hardware.

The following table lists the 41 Pen API functions exported by PKPD. If an application detects Windows 95 without PENWIN.DLL, it can still use these functions to display, examine, alter, and compress existing ink data.

AddInksetInterval

AddPointsPenData

BeginEnumStrokes

BoundingRectFromPoints

CompactPenData

CompressPenData

CreateInkset

CreatePenData

CreatePenDataEx

CreatePenDataRegion

DestroyInkset

DestroyPenData

DrawPenData

DrawPenDataEx

DrawPenDataFmt

DuplicatePenData

EndEnumStrokes

ExtractPenDataPoints

ExtractPenDataStrokes

GetInksetInterval

GetInksetIntervalCount

GetPenDataAttributes

GetPenDataInfo

GetPenDataStroke

GetPointsFromPenData

GetStrokeAttributes

GetStrokeTableAttributes

HitTestPenData

InsertPenData

InsertPenDataPoints

InsertPenDataStroke

MetricScalePenData

OffsetPenData

PenDataFromBuffer

PenDataToBuffer

RedisplayPenData

RemovePenDataStrokes

ResizePenData

SetStrokeAttributes

SetStrokeTableAttributes

TrimPenData


Pen API Structures

The Pen API defines 31 structures in the following categories:

Structure category	Description
System and hardware	Information about the system and pen hardware.
Display	Structures that affect display.
Guides and controls	Structures that affect boxes, guides, and controls.
Recognition	Pertain to the process and results of recognition.
Pen data	Information about points and strokes.
Target	Pertain to target windows.
Time intervals	Stroke interval information.
The following tables list the structures of the Pen API by category. For structures new to version 2.0, the first member is cbSize, which contains the structure's size in bytes.

Important  Before using a version 2.0 structure, an application must initialize its cbSize mem-ber with the value sizeof( structname ), where structname represents the name of the structure. For example:

INKINGINFO        inkinginfo;

inkinginfo.cbSize = sizeof( INKINGINFO );

or

INKINGINFO        inkinginfo = {sizeof( INKINGINFO )};

System and hardware structures	Description
CALBSTRUCT	Pen calibration information.
OEMPENINFO	Tablet hardware information provided by original equipment manufacturer.
PDEVENT	Provides information about the pen device associated with an IN_PDEVENT notification.
PENINFO	Pen or tablet hardware information.
Display structures	Description
ANIMATEINFO	Animation information used by the DrawPenDataEx function.
CWX	Specifies optional parameters for the CorrectWritingEx function. (Japanese version only.)
INKINGINFO	Specifies where and how to display ink.
PCMINFO	Specifies screen areas that affect pen data collection.
PENTIP	Width and color of ink trail left by pen.
RECTOFS	Offsets of inflated or deflated writing area.
SKBINFO	Information about on-screen keyboard.
Guide and control structures	Description
BOXEDITINFO	Size information for boxed edit control.
BOXLAYOUT	Layout of boxed edit control.
CTLINITBEDIT	Initialization for boxed edit control.
CTLINITHEDIT	Initialization for handwriting edit control.
CTLINITIEDIT	Initialization for ink edit control.
GUIDE	Characteristics of handwriting guides.
Recognition structures	Description
BOXRESULTS	Results returned from the GetBoxResultsHRC function.
RC	Various information about the recognition context used by version 1.0 recognition functions.
RCRESULT	Results of recognition initiated through a version 1.0 recognition function.
SYC	Symbol correspondence linking ink strokes with a particular recognized symbol.
SYE	Symbol element containing a recognized symbol and its confidence level.
SYG	Symbol graph containing SYC and SYE struc-tures that together specify all guesses a recog-nizer has made.
Pen data structures	Description
PENDATAHEADER	Header structure of an HPENDATA memory block.
PENPACKET	Data sent by pen driver to inform system of pen activity.
STRKFMT	Attributes of a stroke.
STROKEINFO	Information about points making up a single stroke.
Time interval structures	Description
ABSTIME	Time of a pen data point in seconds and milliseconds.
INTERVAL	Start and end times for a set of data points.
Target structures	Description
INPPARAMS	Describes a set of targets.
TARGET	Information about a single target window.
TARGINFO	Information about a set of targets.


Pen API Messages

The Pen API defines message and submessage values identified by the following prefixes:

Message prefix	Description
CTLINIT_	Submessages for WM_CTLINIT.
DRV_	Messages from the pen hardware driver.
HE_	Submessages of WM_PENCTL for hedit and bedit controls.
HN_	Notification messages for hedit and bedit controls.
IE_	Messages for iedit control.
IN_	Notification messages for iedit control.
PE_	Submessages for WM_PENEVENT.
PMSC_	Submessages for WM_PENMISC.
SKB_	Submessages for WM_SKB.
SKN_	Notifications for WM_SKB.
WM_	Window messages for pen-based applications.


Pen API Constants

The PENWIN.H header file defines manifest constants for the Pen API, most of which begin with prefixes of two or more letters to indicate their purpose. The following table describes the prefixes of the Pen API constants:

Constant prefix	Description
AI_	Options for AnimateProc function.
ALC_	Alphabet codes.
BEI_	Information for bedit control.
BESC_	Size of bedit control.
BXD_	Define dimensions of bedit control (Roman).
BXDK_	Define dimensions of bedit control (Japanese).
BXS_	Styles for bedit controls.
CMPD_	Options for CompressPenData function.
COLOR_	Input method editor colors for bedit control.
CPD_	Storage codes for CreatePenDataEx.
CPDR_	Types for CreatePenDataRegion.
CWR_	Options for CorrectWriting.
DIRQ_	Dictionary request codes.
DPD_	Flags for DrawPenDataEx function.
EPDP_	Options for ExtractPenDataPoints.
EPDS_	Options for ExtractPenDataStrokes.
GGRC_	Options for GetGlobalRC.
GPA_	Options for GetPenDataAttributes.
GRH_	Return types from GetResultsHRC.
GSA_	Options for GetStrokeAttributes.
GST_	Codes for EnableGestureSetHRC.
HEKK_	Subfunctions for kana-kanji conversions.
HEP_	Subfunctions for HE_STOPINKMODE.
HKP_	Options for SetPenHook.
HRCR_	Return values from recognition functions.
IDC_	Cursor types defined by pen display driver.
IEB_	Codes for background in iedit controls.
IEDO_	Codes for draw option IE_ messages.
IEM_	Menu codes for IE_ iedit control messages.
IEMODE_	Codes for IE_SETMODE message.
IEN_	Codes for IE_SETNOTIFY message.
IER_	Codes for stroke format IE_ messages.
IEREC_	Codes for recognition IE_ messages.
IES_	Style attributes for iedit control.
IESEC_	Codes for security IE_ messages.
IESF_	Flags for STRKFMT structure.
ISR_	Return values from inkset functions.
OBM_	Public bitmaps.
PCM_	Termination conditions for pen collection mode.
PCMR_	Return values from data collection functions.
PDC_	Pen device capability codes.
PDK_	Pen driver state bits for GetPenAsyncState function.
PDR_	General pen data return values.
PDT_	Pen driver values specific to original equipment manufacturer.
PDTS_	Trim options for MetricScalePenData.
PDTT_	Trim options for CompactPenData.
PENTIP_	Values for PENTIP structure.
PHW_	Report codes for CreatePenDataEx.
PII_	Flags for INKINGINFO structure.
PMI_	Codes for GetPenMiscInfo, SetPenMiscInfo, and WM_PENMISCINFO.
PMSCL_	lParam values for PMSC_ constants.
PMSCR_	Return values for PMSC_TARGETING subfunction.
PWF_	Subcodes of PMI_SYSFLAGS.
RC_	Values for RC structure.
RCD_	Indicates writing direction (left to right, top down, etc.).
RCO_	Recognition options for RC structure.
RCOR_	Tablet orientation codes.
RCP_	User preference codes.
RCRT_	Values for wResultsType member of RCRESULT structure.
REC_	Return codes from a version 1.0 recognizer.
RHH_	Hook types for ResultsHookHREC.
SGRC_	Options for SetGlobalRC.
SHC_	Codes for word-list coercion functions.
SKB_	Flag values for ShowKeyboard.
SSA_	Options for SetStrokeAttributes.
SSH_	Indicates writing direction (left to right, etc.).
SYV_	Codes for symbol characters, shapes, and gestures.
TPD_	Options for TrimPenData function.
TPT_	Flags for TARGINFO structure.
VWM_	Flag values for PostVirtualMouseEvent.
WCR_	Configuration options for ConfigHREC and ConfigRecognizer.
WLT_	Word list types.


Pen Application Programming Interface Functions

This chapter provides a reference listing of the pen API functions, arranged in alphabetical order. Each entry describes a separate function organized under the following margin headings:

Margin heading	Description
Parameters	List of function parameters
Return Value	Possible return values and their meanings
Comments	Additional information about the function
See Also	Cross-reference to related API services
Next to each function name is a number that identifies the pen API version that supports the function — for example, 1.0 or 2.0.

The names of application callback functions appear in italics to indicate the names are placeholders. Callback functions can have any name.

Constants that pertain only to a specific function are listed in this chapter in the reference entry for that function. Generally, constants that pertain to two or more API services appear in Chapter 13, "Pen Application Programming Interface Constants."


AddInksetInterval [New - Windows 95]
AddInksetInterval

2.0      [New - Windows 95]

Merges an interval into an inkset.

BOOL AddInksetInterval( HINKSET hinkset, LPINTERVAL lpiNew )

Parameters

hinkset

Handle to an inkset.

lpiNew

Address of an INTERVAL structure.

Return Value

Returns TRUE if successful; otherwise FALSE.

Comments

The inkset is reallocated to a larger size by this function. The interval merges with any existing intervals, changing the interval only when required. For example, if the new interval is a subset of an existing one, there will be no change. Similarly, if the new interval overlaps an existing one, the union is formed. The maximum number of intervals allowed is defined to be (65536 - sizeof(INKSET)) / sizeof(INTERVAL), which evaluates to 5460.

The ending time of the new interval must be greater than or equal to the beginning time. If the interval has a duration of 0, AddInksetInterval does nothing, but returns TRUE.

An inkset formed using this function is guaranteed to have the intervals in ascending chronological order.

See Also

GetInksetInterval, INTERVAL


AddPenDataHRC [New - Windows 95]
AddPenDataHRC

2.0      [New - Windows 95]

Adds an HPENDATA object to an HRC object for recognition.

int AddPenDataHRC( HRC hrc, HPENDATA hpndt )

Parameters

hrc

Handle to the HRC object.

hpndt

Handle to the HPENDATA object.

Return Value

Returns HRCR_OK if successful; otherwise, returns one of the following negative values:

Constant	Description
HRCR_ERROR	Invalid parameter or other error.
HRCR_MEMERR	Insufficient memory.
HRCR_INVALIDPNDT	Invalid pen data object.
Comments

Before terminating, the application must free the pen data, using DestroyPenData. Because the recognizer copies any data it requires, the recognizer does not affect the original data.

Calling this function is equivalent to adding data to the recognition context by walking the pen data strokes from beginning to end in stroke order. (Note that the stroke order may not necessarily be in chronological order if insertions have been made.)

A recognizer is not required to use or maintain OEM data; that is, a recognizer may choose to ignore some or all of the OEM data it receives from AddPenDataHRC. This means that the HPENDATA object that the recognizer returns through its CreatePenDataHRC function may differ from hpndt in its OEM data.

See Also

CreatePenData, AddPenInputHRC


AddPenInputHRC [New - Windows 95]
AddPenInputHRC

2.0      [New - Windows 95]

Adds pen data to an HRC object for recognition. A recognizer must export this function.

int AddPenInputHRC( HRC hrc, LPPOINT lppt, LPVOID lpvOem, UINT fuOem, LPSTROKEINFO lpsi )

Parameters

hrc

Handle to the HRC object.

lppt

Address of an array of POINT structures.

lpvOem

Address of a buffer containing OEM data, or NULL if there is no OEM data.

fuOem

Flags to specify which OEM data is valid.

lpsi

Address of a STROKEINFO structure.

Return Value

Returns HRCR_OK if successful; otherwise, returns one of the following negative values:

Constant	Description
HRCR_ERROR	Invalid parameter or other error.
HRCR_MEMERR	Insufficient memory.
Comments

A recognizer is not required to use or maintain OEM data; that is, a recognizer may choose to ignore some or all of the OEM data it receives from AddPenInputHRC. This means that the HPENDATA object that the recognizer returns through its CreatePenDataHRC function may differ from hpndt in its OEM data.

See Also

GetPenInput, GetPenDataStroke


AddPointsPenData [New - Windows 95]
AddPointsPenData

1.0     2.0      [New - Windows 95]

Adds a set of data points to the pen data object.

HPENDATA AddPointsPenData( HPENDATA hpendata, LPPOINT lppt, LPVOID lpvOem, LPSTROKEINFO lpsiNew )

Parameters

hpendata

Handle to a pen data object.

lppt

Address of an array of POINT structures containing new data points to be added to the pen data. Zero points can be added to force a change of pen state or to set a new pen state.

lpvOem

OEM data. Can be set to NULL if there is no additional OEM data. The pen data header determines how the OEM data is interpreted.

lpsiNew

Address of a STROKEINFO structure for new stroke data. Contains the count of points from lppt to be added.

Return Value

Returns a handle to the pen data object. Normally, this is the same handle originally passed to the function. NULL is returned on error. The size of hpendata is limited to 64K.

Comments

A call to GetPenHwEventData or GetPenInput gets the lpsiNew and lpvOem values. A subsequent call to AddPointsPenData appends the set of points to the HPENDATA memory block identified by hpendata. The lpsiNew argument points to a STROKEINFO structure that describes the new points, and lpvOem points to the corresponding OEM data (if any) to be added along with the points.

The STROKEINFO structure indicates the pen state of the new points—that is, whether the pen is up or down. To avoid unnecessarily creating new strokes in the HPENDATA block, AddPointsPenData compares the pen state of the new points with the pen state of the last stroke in the HPENDATA block. If the new points have the same pen state as the last stroke, the function appends the points to the last stroke and updates the last STROKEINFO structure within the HPENDATA block. If the new points have a different pen state, AddPointsPenData appends them to the HPENDATA block as a new stroke, along with the STROKEINFO structure pointed to by lpsiNew.

AddPointsPenData does not scale the data points. The calling application must ensure that the added data points have the same scale as the rest of the HPENDATA block.

See Also

CreatePenData, GetPenHwEventData


AddWordsHWL [New - Windows 95]
AddWordsHWL

2.0      [New - Windows 95]

Adds words to a word list.

int AddWordsHWL( HWL hwl, LPSTR lpsz, UINT uType )

Parameters

hwl

Handle to a word list, or the constant HWL_SYSTEM for the recognizer's master word list.

lpsz

A pointer to a source of words, depending on the uType parameter.

uType

Word list type. This can be one of the following values:

Constant	Description
WLT_STRING	lpsz points to a single null-terminated character string in memory.
WLT_STRINGTABLE	lpsz points to an array of null-terminated character strings in memory. The list is terminated by two null characters.
WLT_WORDLIST	lpsz is the handle of a previously created word list, cast as LPSTR.
Return Value

Returns HRCR_OK if successful; otherwise, returns one of the following negative values:

Constant	Description
HRCR_ERROR	Invalid parameter or other error.
HRCR_MEMERR	Insufficient memory.
Comments

If a user wants to add a word to the system word list, which is available whenever the system dictionary is enabled (see EnableSystemDictionaryHRC), then hwl should be set to the predefined constant HWL_SYSTEM. Words that are not normally found in a dictionary, such as a person's name, can be added to the system word list. How this list is implemented, its size, or if it even exists, depends on the recognizer. A typical recognizer might maintain a thousand-word list, replacing random entries on overflow.

The HWL_SYSTEM constant cannot be used in any of the other word-list functions. For example, it is not possible to destroy the system word list with the DestroyHWL function.

For a description of word lists and how a recognizer uses them, see "Configuring the HRC" in Chapter 5, "The Recognition Process."

See Also

CreateHWL, EnableSystemDictionaryHRC


AnimateProc [New - Windows 95]
AnimateProc

2.0      [New - Windows 95]

The AnimateProc function is an application-defined callback function that provides information to DrawPenDataEx on a periodic basis. The name AnimateProc serves only as a placeholder; the function can have any name.

BOOL CALLBACK AnimateProc( HPENDATA hpndt, UINT iStrk, UINT cPnt, UINT FAR * lpuSpeedPct, LPARAM lParam )

Parameters

hpndt

Handle to the pen data currently being drawn.

iStrk

Zero-based index to the stroke being drawn, or about to be drawn.

cPnt

Count of points already drawn in this stroke.

lpuSpeedPct

Address of the speed-percent value.

lParam

Application-specific data passed to the callback. This value is specified in ANIMATEINFO.

Return Value

The callback function must return TRUE to continue drawing the pen data. Returning FALSE stops animation immediately.

Comments

One of the parameters of DrawPenDataEx provides the address of this callback function. The application must create an instance of this function using the MakeProcInstance function, and ensure that it is exported in the module-definition (.DEF) file.

The application can monitor the state of animation or provide the user with an opportunity to change the speed of animation, including pausing it, using the value addressed by lpuSpeedPct.

The application can also pass application-specific information to the callback in lParam. For example, a handle to the DC (device context) can be passed.

Callbacks are made at the beginning of the stroke or time interval, before any drawing is done. However, if AI_SKIPUPSTROKES is specified, a callback is not made before up strokes.

See Also

DrawPenDataEx,  ANIMATEINFO


AtomicVirtualEvent [New - Windows 95]
AtomicVirtualEvent

1.0     2.0      [New - Windows 95]

Locks out pen packets.

void AtomicVirtualEvent( BOOL fBegin )

Parameters

fBegin

Flag for beginning or ending lockout. TRUE begins lockout, FALSE ends it.

Return Value

This function does not return a value.

Comments

AtomicVirtualEvent is used by the Pen Palette or a similar virtual-keyboard program to lock out pen packets while the application is posting simulated key or mouse events.

Calling AtomicVirtualEvent with a TRUE value blocks input from physical devices until they are freed with a call specifying FALSE. Applications should end the lockout as quickly as possible.

An interruptable thread should not call AtomicVirtualEvent.

Example

The following code fragment posts a mouse click:

AtomicVirtualEvent( TRUE );

PostVirtualMouseEvent( VWM_MOUSELEFTDOWN, xPos, yPos );

PostVirtualMouseEvent( VWM_MOUSEMOVE, xPos, yPos );

PostVirtualMouseEvent( VWM_MOUSELEFTUP, xPos, yPos );

AtomicVirtualEvent( FALSE );

See Also

PostVirtualKeyEvent, PostVirtualMouseEvent


BeginEnumStrokes [New - Windows 95]
BeginEnumStrokes

1.0     2.0      [New - Windows 95]

Locks a pen data block in memory in preparation for enumerating strokes.

Note  This function is provided only for compatibility with version 1.0 of the Pen API, and will not be supported in future versions.

LPPENDATA BeginEnumStrokes( HPENDATA hpendata )

Parameters

hpendata

Handle to an HPENDATA object.

Return Value

Returns a pointer to the locked pen data if successful. Returns NULL if hpendata is compressed or if the handle cannot be locked.

Comments

BeginEnumStrokes calls the GlobalLock function internally, returning a far pointer to the memory block in the global heap. This serves to lock the data in preparation for direct reading or calling GetPenDataStroke. The return value from BeginEnumStrokes is used as an argument for GetPenDataStroke. After calling BeginEnumStrokes to lock data, an application must unlock the data when finished by calling EndEnumStrokes.

An application should never modify data directly within an HPENDATA block. Doing so can invalidate other information in the block. To modify an HPENDATA block, use one of the Pen API functions listed in Chapter 4, "The Inking Process."

See Also

EndEnumStrokes, GetPenDataStroke


BoundingRectFromPoints [New - Windows 95]
BoundingRectFromPoints

1.0     2.0      [New - Windows 95]

Calculates a rectangle that bounds a range of points.

void BoundingRectFromPoints( LPPOINT lppt, UINT cPt, LPRECT lprect )

Parameters

lppt

Address of an array of POINT structures.

cPt

Number of POINT structures in the array. This parameter can be 0.

lprect

Address of a RECT structure that contains the bounding rectangle when the function returns.

Return Value

This function does not return a value.

Comments

The bounding rectangle is empty at [0,0] if there are no points. For a single point, the rectangle is empty at that point.


CharacterToSymbol [New - Windows 95]
CharacterToSymbol

1.0     2.0      [New - Windows 95]

Converts an ANSI string to an array of SYV_ symbol values.

int CharacterToSymbol( LPSTR lpstr, int cSyv, LPSYV lpsyv )

Parameters

lpstr

Address of a null-terminated ANSI string to be converted.

cSyv

Maximum number of SYV_ symbols the array lpsyv can hold.

lpsyv

Address of an array of SYV_ symbol values into which CharacterToSymbol places the converted symbols. The array must be large enough to hold cSyv symbols.

Return Value

Returns the number of characters converted, or −1 if there is an error.

Comments

Conversion proceeds until a null byte is found in lpstr or until lpsyv has been filled with cSyv symbols. A null byte is converted to SYV_NULL.

See Also

SymbolToCharacter, SYG, SYV_


CompactPenData [New - Windows 95]
CompactPenData

1.0     2.0      [New - Windows 95]

Compacts pen data based on specified trim options.

Note  This function is provided for compatibility with version 1.0 of the Pen API and will not be supported in future versions. Use TrimPenData and CompressPenData instead.

HPENDATA CompactPenData( HPENDATA hpndt, UINT fuTrim )

Parameters

hpndt

Handle to a pen data object.

fuTrim

Data-trimming options:

PDTT_DEFAULT

Reallocates memory block to fit the data; does not trim the data. If you call CompactPenData with this trim option and then call the GlobalSize function with the pen data handle as a parameter, you can retrieve the size of the pen data.

PDTT_ALL

Removes the PENINFO structure from the header. Discards all data from pen-up points (points collected when the pen is not in contact with the tablet), and removes OEM data and collinear points.

PDTT_COLLINEAR

Removes successive identical (coincident) points and collinear points from the pen data. After the operation is performed, PDTS_NOCOLLINEAR is set in the wPndts member of the PENDATAHEADER structure. The collinear points can be removed with very little if any loss of recognition accuracy. If the collinear points are removed before the points are scaled to display coordinates, there may be a small change in the displayed image.

PDTT_COMPRESS

Compresses the data without losing any information. After the data has been compressed, the compressed handle to the pen data can be passed as a parameter only to the functions CompactPenData, GetPenDataInfo, and DuplicatePenData. CompactPenData uses a "lossless" compression method that retains the ability for an application to recognize the ink after subsequent decompression. You can use this option with other trim options, including PDTT_DECOMPRESS. In this case, compression is done after all other options have been satisfied.

PDTT_DECOMPRESS

Decompresses the data. You can use this option with other trim options, including PDTT_COMPRESS. In this case, decompression is performed first, followed by any other trim options specified, and followed by recompression if PDTT_COMPRESS is specified. Since the compression method used by CompactPenData does not lose information, the data is completely restored.

PDTT_OEMDATA

Removes all OEM data—this is data other than coordinates, such as pressure. This option does not affect delayed recognition unless a recognizer is being used that expressly requires OEM data. For example, signature recognizers often use pressure information.

PDTT_PENINFO

Removes the PENINFO structure from the header. You can use this option if there is no OEM data associated with the data points or if the application does not use any of the OEM data. This option has no effect on the pen data for delayed recognition. Any OEM data present is also removed.

PDTT_UPPOINTS

Removes all data from pen-up points (points collected when the pen is not in contact with the tablet). This option has no effect on delayed recognition. This option is not usually necessary because pen-up points are not a part of standard pen data.

Return Value

If successful, CompactPenData returns a handle to a pen data object; otherwise, it returns NULL. CompactPenData may fail and return NULL in low-memory situations if compression or decompression is requested.

Comments

The PDTS_ bits are set in the wPndts member of the PENDATAHEADER structure to indicate which operations have been performed.

See Also

CompressPenData, TrimPenData, CreatePenData, PENINFO, PENDATAHEADER


CompressPenData [New - Windows 95]
CompressPenData

2.0      [New - Windows 95]

Compresses or decompresses the data in an HPENDATA object.

int CompressPenData( HPENDATA hpndt, UINT fuFlags, DWORD dwReserved )

Parameters

hpndt

Handle to the HPENDATA object.

fuFlags

Specifies whether to compress or decompress the data, as follows:

Constant	Description
CMPD_COMPRESS	Compress the pen data.
CMPD_DECOMPRESS	Decompress the pen data.
dwReserved

Must be 0.

Return Value

This function returns one of the following:

Constant	Description
PDR_OK	Successful completion. Redundant operations, such as compressing an HPENDATA object that has already been compressed, are not errors.
PDR_ERROR	Illegal parameter or other error.
PDR_MEMERR	Memory error.
PDR_PNDTERR	Invalid pen data.
PDR_VERSIONERR	Could not convert old pen data.
Comments

This function replaces the the version 1.0 Pen API function CompactPenData, which is supported for compatibility only.

For a discussion of data compression, see "Compressing Pen Data" in Chapter 4, "The Inking Process."

See Also

CompactPenData,  TrimPenData


ConfigHREC [New - Windows 95]
ConfigHREC

2.0      [New - Windows 95]

Allows an application to set or query recognizer-specific values. All calls to ConfigHREC are serviced by the recognizer's ConfigRecognizer function. In version 2.0 of the Pen API, applications must call ConfigHREC rather than ConfigRecognizer.

int ConfigHREC( HREC hrec, UINT uSubFunction, WPARAM wParam, LPARAM lParam )

Parameters

hrec

Module handle of the recognizer library. If this value is NULL, the system default recognizer is used.

uSubFunction

Recognizer subfunction identifier. See the "Comments" section below.

wParam

Depends on the value of uSubFunction.

lParam

Address of a buffer. The contents of the buffer depend on the value of uSubFunction.

Return Value

If successful, returns 0 or a positive value as described in the list of uSubfunction constants below; otherwise, returns one of the following negative values:

Constant	Description
HRCR_ERROR	Missing recognizer, invalid parameter, or other error.
HRCR_MEMERR	Insufficient memory.
Comments

The uSubFunction parameter contains one of the following WCR_ values that identifies the requested configuration service:

WCR_CONFIGDIALOG

Instructs the recognizer to open a dialog box to set any recognizer-specific parameters. (This is analogous to DEVMODE in printer drivers, which is called when a user sets up a printer.) Some examples of the kind of settings a recognizer might implement are whether or not to allow cursive input, how much to depend on stroke order, and how rapidly to modify prototypes based on the user's own style.

The lParam parameter points to the name of the user currently selected in the Control Panel application. The wParam parameter is used by the recognizer as the parent window for any dialog boxes it displays. The return value is always TRUE.

WCR_DEFAULT

Returns TRUE if the recognizer is capable of being a default recognizer. A default recognizer must support the standard character set as well as standard gestures.

WCR_GETALCPRIORITY

Returns the current default alphabet priority being used by the recognizer. The lParam parameter points to a variable that specifies the alphabet priority as a bitwise-OR combination of ALC_ values. The wParam parameter is not used. This subfunction is used by the system; applications should instead get alphabet priority by calling GetAlphabetPriorityHRC. The return value is TRUE if successful.

WCR_GETANSISTATE

Returns TRUE if the recognizer can recognize all of the ANSI character set; otherwise, returns FALSE or HRCR_ERROR.

WCR_GETDIRECTION

If successful, returns the current writing direction assumed by the recognizer; otherwise, returns HRCR_ERROR.

WCR_GETHAND

If successful, returns 0 if the user writes with the right hand or nonzero if the user writes with the left hand; otherwise, returns HRCR_ERROR.

WCR_PRIVATE

Values above WCR_PRIVATE have a meaning dependent on the recognizer.

WCR_PWVERSION

Returns the version number of the Pen API for which this recognizer was created. This value is 2 for the current version.

WCR_QUERY

Returns TRUE if the recognizer supports a configuration dialog box.

WCR_QUERYLANGUAGE

The wParam parameter is not used. The lParam parameter points to a null-terminated language string. The return value is TRUE if the recognizer supports the language; otherwise, it is FALSE.

WCR_RECOGNAME

Retrieves an identification string from the recognizer. The lParam parameter is treated as a far pointer to a buffer that is filled with an identification string from the recognizer. The wParam parameter is the size of the buffer to fill. The identification string is a short description of the recognizer that Control Panel presents to the user. A sample string is "US English character set, cursive & print." The return value is always 0.

WCR_SETALCPRIORITY

Sets the current default alphabet priority for the recognizer to the value in lParam. Note that setting a priority for individual characters is not supported for defaults. The wParam parameter is not used. This subfunction is used by the system; applications should set priority explicitly in an HRC with the SetAlphabetPriorityHRC function. The return value is TRUE if successful.

WCR_SETANSISTATE

Sets a flag to enable or disable recognition of the entire ANSI character set. Setting lParam to 1 enables recognition of the entire ANSI set; setting lParam to 0 allows recognition of only English (ASCII) characters. The wParam parameter is not used.

The WCR_SETANSISTATE subfunction determines the default setting when CreateCompatibleHRC creates an HRC. An application can explicitly override the setting for the HRC with the SetInternationalHRC function. The return value is TRUE if successful.

WCR_SETDIRECTION

Sets the current writing direction for the recognizer to the value in lParam, which can be an appropriate combination of the RCD_ values. The wParam parameter is not used. The return value is TRUE if successful.

WCR_SETHAND

Sets the current writing hand preference for the recognizer. The lParam parameter is 0 for a right-handed user or 1 for a left-handed user. The wParam parameter is not used. The return value is TRUE if successful.

WCR_TRAIN

This subfunction returns TRAIN_NONE if the recognizer does not support training. A return value of TRAIN_DEFAULT indicates support for the default trainer, including the capability of resetting its database to the original "factory" setting (see WCR_TRAINSAVE). A return value of TRAIN_CUSTOM indicates that the recognizer also provides its own custom trainer. A return value of TRAIN_BOTH indicates support for both kinds of training.

WCR_TRAINMAX

The recognizer returns the maximum number of SYV_ symbol values that it can train for any given shape.

The recognizer should return 0 if it can train any number of characters. For example, the Microsoft recognizer can train one character for a shape; a cursive recognizer may allow more.

WCR_TRAINSAVE

The trainer calls the ConfigHREC function with the parameters set to (WCR_TRAINSAVE, TRAIN_SAVE, 0) when it is time to save the data-base. This happens when the user closes the trainer. After this call, the recognizer should return TRUE if it can successfully save the database; otherwise, it should return FALSE.

The trainer calls the function with (WCR_TRAINSAVE, TRAIN_REVERT, 0) before it discards any changes made to the database that have not yet been saved to disk (that is, revert to saved). This happens when the user cancels the changes. The recognizer should return TRUE if it is successful.

The trainer can alternatively call ConfigHREC with (WCR_TRAINSAVE, TRAIN_RESET, 0) to reset the database to the original "factory" settings. The recognizer should return TRUE if it is successful.

WCR_TRAINDIRTY

The recognizer returns TRUE if the recognizer needs to save training. The recognizer returns FALSE if no training occurred, if the recognizer does not use a database for training, if the recognizer saves as it works, or if the recognizer cannot revert the training.

The hwnd parameter is a handle to the requesting window. The trainer can use this as the parent window for a dialog box, for example. If there has been a recent recognition, a pointer to it is passed in the lParam parameter, although this may be NULL.

The format for the WCR_TRAINDIRTY subfunction call is:

ConfigHREC( hrec, WCR_TRAINDIRTY, 0, 0 );

WCR_TRAINCUSTOM

If the recognizer returns TRAIN_CUSTOM or TRAIN_BOTH in response to WCR_TRAIN, it will receive a WCR_TRAINCUSTOM message when it is time to display its own training system.

The format for the WCR_TRAINCUSTOM subfunction call is:

ConfigHREC( hrec, WCR_TRAINCUSTOM, hwnd, lprcresult );

WCR_USERCHANGE

Notifies the recognizer of a change in user. The lParam parameter points to a null-terminated string containing the user's name. The wParam parameter specifies the required modification:

A wParam value of CRUC_NOTIFY indicates a new user, the name of whom is in the string that lParam points to.

A wParam value of CRUC_REMOVE indicates that the user identified by lParam should be removed from the recognizer's user list. If the recognizer has saved any files or settings for the user, they should be deleted in response to this notification.

WCR_VERSION

Returns the version number. The low-order byte of the return value specifies the major (version) number. The high-order byte specifies the minor (revision) number.

See Also

ConfigRecognizer, ALC_, SYV_


ConfigRecognizer [New - Windows 95]
ConfigRecognizer

1.0     2.0      [New - Windows 95]

Provides system access to the configuration settings of a recognizer. In version 2.0 of the Pen API, only the pen system can call ConfigRecognizer. Applications must call ConfigHREC to query or set recognizer configuration values. The system routes ConfigHREC calls to the ConfigRecognizer function of the appropriate recognizer.

A recognizer must export ConfigRecognizer. The information in this entry is for recognizer developers only, not application developers.

UINT ConfigRecognizer( UINT uSubFunction, WPARAM wParam, LPARAM lParam )

Parameters

uSubFunction

Recognizer subfunction identifier. See ConfigHREC for descriptions of the WCR_ subfunctions that ConfigRecognizer must support. In addition, ConfigRecognizer must support the following two WCR_ subfunctions:

WCR_INITRECOGNIZER

When an application installs a recognizer by using InstallRecognizer, the system calls the recognizer's ConfigRecognizer function with the WCR_INITRECOGNIZER subfunction. The wParam parameter is not used and lParam is a far pointer to an ASCII string containing the user's name, as set in the system registry. If successful, the recognizer should return 1; otherwise, it should return 0 to indicate an error.

In response to the WCR_INITRECOGNIZER subfunction, the recognizer should perform any required initialization tasks. (This subfunction replaces the InitRecognizer function exported by version 1.0 recognizers.)

WCR_CLOSERECOGNIZER

When an application unloads a recognizer by using UninstallRecognizer, the system calls the recognizer's ConfigRecognizer function with the WCR_CLOSERECOGNIZER subfunction. The wParam and lParam parameters are not used. If successful, the recognizer should return 1; otherwise, it should return 0 to indicate an error.

In response to the WCR_CLOSERECOGNIZER subfunction, the recognizer should perform any required cleanup tasks. (This subfunction replaces the CloseRecognizer function exported by version 1.0 recognizers.)

wParam

Depends on the value of uSubFunction.

lParam

A value, or an address of a buffer. The contents of the buffer depend on the value of uSubFunction.

Return Value

Returns 0 or a positive value, depending on uSubFunction.

Comments

ConfigRecognizer provides initialization and query services for the pen system. The parameter uSubFunction is a WCR_ value that specifies the configuration service that ConfigRecognizer must perform.

When an application calls ConfigHREC, the system determines the appropriate recognizer and passes the call to that recognizer's ConfigRecognizer function. ConfigHREC exists only because its extra argument hrec identifies to the system the intended recognizer library. This information is necessary in version 2.0 of the Pen API, which allows multiple recognizer libraries to exist simultaneously. Thus, the names ConfigHREC and ConfigRecognizer refer to the same function. Applications refer to the function as ConfigHREC, while recognizers export it as ConfigRecognizer.

See Also

ConfigHREC, SYV_


CorrectWriting [New - Windows 95]
CorrectWriting

1.0     2.0      [New - Windows 95]

Sends text to the CorrectText dialog box to allow the user to edit text using a single-line or multiline bedit control.

BOOL CorrectWriting( HWND hwnd, LPSTR lpText0, UINT cbText0, LPVOID lpvReserved, DWORD dwFlags, DWORD dwParam )

Parameters

hwnd

Handle of the owner of the CorrectText dialog box or writing tools used to edit the text.

lpText0

Far pointer to a buffer containing the text to be corrected.

When CorrectWriting returns, the lpText0 buffer holds the corrected text. As a general rule, this parameter should allow for growth by a factor of at least two or some maximum size that depends on the field of entry.

cbText0

Number of characters in lpText0. This value must be greater than 1 and include a byte for the string's null terminator.

lpvReserved

This parameter is reserved and should be set to NULL.

dwFlags

Translation and style flags, formed by the low-order word and high-order word of dwFlags. The low-order word must be one or more of the following flags, combined with the bitwise-OR operator. Note that the CWR_REPLACECR and CWR_REPLACETAB flags replace CWR_STRIPTAB and CWR_STRIPCR, respectively; both flags are in version 1.0 of the Pen API.

Constant	Description
CWR_BOXES	Create bedit writing tool instead of keyboard. This flag can be used only for edit control and its derivatives. Use of this flag by applications is not recommended.
CWR_HEDIT	Indicates that the given hwnd is an edit control or a control derived from the edit control. This flag can be used only for edit control and its derivatives. Use of this flag by applications is not recommended.
CWR_INSERT	Use "Insert Text" instead of "Edit Text" as the title. CWR_TITLE overrides this flag.
CWR_KEYBOARD	Create keyboard writing tool instead of bedit lens. This flag can be used only for edit control and its derivatives. Use of this flag by applications is not recommended.
CWR_KKCONVERT	Initiate IME (Japanese version only).
CWR_REPLACECR	Replace carriage return characters in the text in the buffer by spaces just before the call returns.
CWR_REPLACETAB	Replace tabs in the text in the buffer by spaces just before the call returns.
CWR_SIMPLE	Use writing tool (simple dialog box). This flag can be used only for an edit control and its derivatives. Use of this flag by applications is not recommended.
CWR_SINGLELINEEDIT	Replace carriage returns and tabs with spaces and strip linefeeds from the text in the buffer just before the call returns.
CWR_STRIPLF	Strip linefeed characters from the text in the buffer just before the call returns.
CWR_TITLE	Interpret dwParam (see below) as a pointer to the title text string.
The high-order word must be one of the following values and cannot be combined with the bitwise-OR operator. The values determine the type of keyboard to show when the user clicks the keyboard button in the dialog box.

Constant	Description
CWRK_TELPAD	Use the telephone-type keyboard.
CWRK_BASIC	Use the basic keyboard.
CWRK_DEFAULT	Use the default keyboard type. The default keyboard type is currently the same as the basic keyboard type.
CWRK_FULL	Use the full keyboard.
CWRK_NUMPAD	Use the numeric keyboard.
dwParam

A far pointer to a text string that serves as the title of the dialog box if CWR_TITLE is present in dwFlags; otherwise, this parameter must be 0.

Return Value

Returns TRUE if the writing tool or CorrectWriting operation was successful. Otherwise, the return value is FALSE.

Comments

CorrectWriting sends a WM_PENMISC message with PMSC_GETHRC as the lParam to the specified window. This message requests the HRC handle associated with the window, which the system then uses for the dialog box. The window should return a copy of its HRC so that the system can destroy it before the call returns. If the window returns NULL to this message, the system creates a default HRC.

Note that in the Japanese version, CorrectWriting is supported but internally calls CorrectWritingEx, which opens a Dialog Input Window.


CorrectWritingEx [New - Windows 95]
CorrectWritingEx

2.0      [New - Windows 95]

Sends text to the CorrectText dialog box to allow the user to edit text using the Japanese Data Input Window. (Japanese version only.)

INT CorrectWritingEx( HWND hwnd, LPSTR lpText, UINT cbText, LPCWX lpcwx )

Parameters

hwnd

Handle of the owner of the CorrectText dialog box or writing tool used to edit the text. This can be NULL.

lpText

Far pointer to a buffer containing text to correct. This is copied into the Data Input Window's edit control.  If lpText is NULL, a WM_GETTEXT message is sent to the text source window, specified by the hwndText member of lpcwx, or if lpcwx or its hwndText member is NULL, to hwnd.  On successful exit, a WM_SETTEXT message will be sent to that window with modified text.

cbText

Size of the lpText buffer. If the source of the text is an edit control constrained by EM_LIMITTEXT, cbText should reflect that size. If lpText is NULL, the cbText value will be used to limit text if it is greater than zero; otherwise, no limit is used and the returned text may be of arbitrary size.

lpcwx

Address of a CWX structure, or NULL. The structure is used to specify optional correction parameters; for a description of its members, see CWX. If this value is NULL, the following default assumptions are made:

•	The text window is the same as the owner window hwnd.

•	A default recognition context is used.

•	The edit control style is a combination of ES_LEFT and ES_MULTILINE.

•	All text is selected; the caption is "Edit Text".

•	Most recently use values for context flags, keyboard, keyboard states, position, and size are used.

Return Value

If there is a programming or memory error, the negative value CWXR_ERROR is returned. Otherwise, one of the following nonnegative values is returned:

Constant	Description
CWXR_MODIFIED	User pressed the OK button.
CWXR_UNMODIFIED	User pressed the Cancel button, or closed the dialog, or pressed the OK button but did not make any changes to the text.
Comments

An application must be sure to initialize the CWX structure properly if it is used. In particular, the cbSize member must be set to sizeof(CWX), and the remaining fields (at least up to dwSel) are typically set to zero.

Example

The following example shows how to initialize and call CorrectWritingEx when a button is pressed in a dialog:

CWX cwx = {sizeof(CWX), 0, NULL, NULL, {0}, 0L, 0L};

cwx.hwndText = GetDlgItem(hdlg, IDD_ETSL);	// dialog edit

cwx.dwEditStyle = GetWindowLong(cwx.hwndText, GWL_STYLE)

| ES_PASSWORD;

cwx.dwSel = SendMessage(cwx.hwndText, EM_GETSEL, 0, 0);

_fstrcpy((LPSTR)cwx.szCaption, (LPSTR)"Enter your password:");

// we specify kbd and context, but use MRU placement

cwx.wApplyFlags = CWXA_KBD | CWXA_STATE | CWXA_CONTEXT;

// don't update most-recently used settings for this one-shot:

cwx.wApplyFlags |= CWXA_NOUPDATEMRU;

cwx.ixkb = CWXK_QWERTY;

cwx.rgState[CWXK_QWERTY-CWXK_FIRST] = CWXKS_HAN | CWXKS_ROMA;

cwx.dwFlags = CWX_NOTOOLTIPS | CWX_TOPMOST;	// no distractions

if (CorrectWritingEx(hdlg, NULL, 0, &cwx) != CWXR_MODIFIED)

ErrBox(EB_WHOAREYOU);

// validate pwd in the text window etc...

See Also

CWX


CreateCompatibleHRC [New - Windows 95]
CreateCompatibleHRC

2.0      [New - Windows 95]

Creates a handwriting recognition context HRC that can be used to do handwriting recognition, optionally compatible with an existing context template. A recognizer must export this function.

HRC CreateCompatibleHRC( HRC hrcTemplate, HREC hrec )

Parameters

hrcTemplate

Handle to an existing HRC object that can provide default settings for the recognition context being created. If NULL, this parameter is ignored and default settings are used.

hrec

Instance handle of the recognizer library. This is the value returned by the Windows function LoadLibrary. Note that the module handle returned by the Windows function GetModuleHandle does not work in this case. If this value is NULL, the system default recognizer is used by internally making a call to GetPenMiscInfo with PMI_SYSREC as the first argument.

Return Value

Returns a handle to a new HRC object if successful; otherwise, returns NULL.

Comments

The hrcTemplate parameter can be used to copy an old context into the new HRC object. This includes settings such as word lists, coercion, and GUIDE structure, but excludes any pen data that may be in the old context.

See Also

DestroyHRC, GetResultsHRC, SetMaxResultsHRC


CreateHWL [New - Windows 95]
CreateHWL

2.0      [New - Windows 95]

Creates a handle to a word list.

HWL CreateHWL( HREC hrec, LPSTR lpsz, UINT uType, DWORD dwReserved )

Parameters

hrec

Module handle of the recognizer library. If this value is NULL, the system default recognizer is used.

lpsz

A pointer to a source of words, depending on the uType parameter.

Type

Word-list type. This can be one of the following values:

Constant	Description
WLT_EMPTY	An empty word list is created. The lpsz parameter is ignored.
WLT_STRING	The lpsz parameter points to a single null-terminated character string in memory.
WLT_STRINGTABLE	The lpsz parameter points to an array of null-terminated character strings in memory. The list is terminated by two null characters.
dwReserved

Must be 0.

Return Value

If successful, returns the handle of a newly created word list; otherwise, returns NULL. If the recognizer does not support word lists, the return value is NULL.

Comments

CreateHWL creates a word list for constraining recognition. Word lists can be combined using the AddWordsHWL function.

To make a word list from words in a file, an application uses CreateHWL to create an empty word list, then reads the file into it with the ReadHWL function.

Any word lists created by an application must eventually be destroyed by calling DestroyHWL. Attempting to unload a recognizer that has open word lists results in an error.

For a description of word lists and how a recognizer uses them, see "Configuring the HRC" in Chapter 5, "The Recognition Process."

Example

The following example demonstrates how to provide a word list to constrain recognition results to the words "Canada," "USA," or "Mexico":

static char szNames[] = { "Canada",

  "USA",

  "Mexico"

};

HWL hwlCountries = CreateHWL( NULL,

(LPSTR)szNames,

WLT_STRINGS, 0L );	      // Create early for later use

.

.

.

if (hrc = CreateCompatibleHRC( NULL, NULL ))

{

   SetWordlistHRC( hrc, hwlCountries );       // Set list into HRC

   SetWordlistCoercionHRC( hrc, SCH_FORCE );  // Force match

   .

   .	   // Code that collects and recognizes input goes here

   .

}

See Also

AddWordsHWL, DestroyHWL, SetWordlistHRC


CreateInkset [New - Windows 95]
CreateInkset

2.0      [New - Windows 95]

Creates an empty inkset.

HINKSET CreateInkset( UINT gmemFlags )

Parameters

gmemFlags

Flag that specifies whether or not the Windows GlobalAlloc function should create a shared memory object when the inkset object is created. This flag should be either 0 or GMEM_DDESHARE. The GMEM_MOVEABLE and GMEM_ZEROINIT flags are added to this value, and other GMEM_ flags are ignored.

Return Value

Returns a handle to an inkset if successful; otherwise, the return value is NULL.

See Also

DestroyInkset, INTERVAL


CreateInksetHRCRESULT [New - Windows 95]
CreateInksetHRCRESULT

2.0      [New - Windows 95]

Creates an inkset from parts of a recognition result.

HINKSET CreateInksetHRCRESULT( HRCRESULT hrcresult, UINT iSyv, UINT cSyv )

Parameters

hrcresult

Handle of an HRCRESULT object.

iSyv

Index to first symbol for inkset.

cSyv

Count of symbols.

Return Value

Returns the handle of a newly created inkset if successful. If the index to the first symbol iSyv is invalid, or some other error occurs, the return value is NULL.

Comments

The inkset spans a series of continuous symbols; disjoint sets are not allowed. Before terminating, the calling application must destroy the HINKSET object by calling DestroyInkset.

If the range of symbols specified by iSyv + cSyv exceeds the number of symbols available, the returned inkset is valid only for available symbols. This is not an error, so it is possible to assign cSyv a large value to get an inkset for all symbols after iSyv.

For a description of inksets, see "The HINKSET Object" in Chapter 4, "The Inking Process."

See Also

DestroyInkset, GetResultsHRC


CreatePenData [New - Windows 95]
CreatePenData

1.0     2.0      [New - Windows 95]

Creates an empty HPENDATA block.

Note  This function is provided only for compatibility with version 1.0 of the Pen API and will not be supported in future versions. Use CreatePenDataEx instead.

HPENDATA CreatePenData( LPPENINFO lppeninfo, int cbOem, UINT uScale, UINT gmemFlags )

Parameters

lppeninfo

Address of tablet information to be inserted into the PENINFO structure in the pen data header. If this parameter is NULL, the current tablet settings are retrieved from the hardware instead. If there is no tablet, the pen data will not have an embedded PENINFO section and the wPndts member in PENDATAHEADER will have the PDTS_NOPENINFO flag set.

cbOem

Width of OEM data packet. If this value is greater than or equal to 0, the OEM data overrides the contents of the PENINFO structure, if present; otherwise, a negative value such as −1 can be used to specify that the system should calculate the size of the OEM data packet.

uScale

Data-scaling metric value. This parameter can be one of the following values:

Constant	Description
PDTS_LOMETRIC	Each logical unit is mapped to 0.1 millimeter. Positive x is to the right; positive y is down.
PDTS_HIMETRIC	Each logical unit is mapped to 0.01 millimeter. Positive x is to the right; positive y is down.
PDTS_HIENGLISH	Each logical unit is mapped to 0.001 inch. Positive x is to the right; positive y is down.
PDTS_ARBITRARY	The application has done its own scaling of the data point.
PDTS_STANDARDSCALE	The standard scaling metric; equivalent to PDTS_HIENGLISH.
gmemFlags

Flag that specifies whether or not the Windows GlobalAlloc function should create a shared memory object when the pen data object is created. This should be either 0 or GMEM_DDESHARE. The GMEM_MOVEABLE and GMEM_ZEROINIT flags are added to this value, and other GMEM_ flags are ignored.

Return Value

Returns a handle to a new and empty pen data object if successful; otherwise, it returns NULL.

Comments

The application provides the PENINFO structure for the header, the real size of any OEM data stored with each coordinate, and the scale of the coordinates.

The uScale parameter specifies scaling values that are also used in the MetricScalePenData function and in the PENDATAHEADER structure member wPndts. The scaling values do not behave in the same way as the Windows scaling units with similar names. For example, a 1-inch line in MM_HIENGLISH will not necessarily be an inch long on the screen because GDI does not know the size of the monitor. However, with PDTS_HIENGLISH in MetricScalePenData, a line drawn an inch long is actually an inch long.

If lppeninfo is NULL, and if there is no tablet on the system (that is, if SendDriverMessage fails), it returns NULL.

The cbOem value must be less than or equal to 12, depending on the size of the OEM data packet. A value of 0 explicitly sets the amount of OEM information to none. A negative value indicates that the size of the OEM data packet is to be calculated by the system. Any existing value for the cbOemData member of PENINFO can be overwritten.

See Also

CreatePenDataEx, DestroyPenData, PDTS_


CreatePenDataEx [New - Windows 95]
CreatePenDataEx

2.0      [New - Windows 95]

Creates a PENDATA structure with specified OEM data subsets.

HPENDATA CreatePenDataEx( LPPENINFO lppeninfo, UINT uScale, UINT fuOptions, UINT gmemFlags )

Parameters

lppeninfo

Address of tablet information to be inserted into the PENINFO structure in the pen data header. If this parameter is NULL, the current tablet settings are retrieved from the hardware instead. If there is no tablet, the pendata will not have an embedded PENINFO section and the wPndts member in PENDATAHEADER will have the PDTS_NOPENINFO flag set.

uScale

Data-scaling metric value. This parameter can be one of the following values:

Constant	Description
PDTS_LOMETRIC	Each logical unit is mapped to 0.1 millimeter. Positive x is to the right; positive y is down.
PDTS_HIMETRIC	Each logical unit is mapped to 0.01 millimeter. Positive x is to the right; positive y is down.
PDTS_HIENGLISH	Each logical unit is mapped to 0.001 inch. Positive x is to the right; positive y is down.
PDTS_ARBITRARY	The application has done its own scaling of the data point.
PDTS_STANDARDSCALE	The standard scaling metric is equivalent to PDTS_HIENGLISH.
fuOptions

Storage and trim options. If this parameter is 0, no timing, PDK_, or OEM data is stored. If it is CPD_DEFAULT, everything but user data is stored.

Otherwise, this parameter can explicitly specify subsets of OEM and other data. To do so, the parameter should be a combination of one of the CPD_USER values that allocate extra storage and any collection of PHW_ constants. (These values should be combined using the bitwise-OR operator.)

The following table lists the PHW_ values for the fuOptions parameter:

Constant	Description
PHW_PRESSURE	Report pressure in OEM data if available.
PHW_HEIGHT	Report height in OEM data if available.
PHW_ANGLEXY	Report XY-angle in OEM data if available.
PHW_ANGLEZ	Report Z-angle in OEM data if available.
PHW_BARRELROTATION	Report barrel rotation in OEM data if available.
PHW_OEMSPECIFIC	Report OEM-specific value in OEM data if available.
PHW_PDK	Report per-point PDK_ bits in OEM data.
PHW_ALL	Report all available OEM data. This flag is the sum of all other PHW_ flags. The following table lists the CPD_ values for the fuOptions parameter:
CPD_DEFAULT	Store timing, PDK, and all OEM data for each stroke.
CPD_USERBYTE	Set internal flag to add space for one byte of additional storage to be allocated for each stroke. Added space is for application use.
CPD_USERWORD	Set internal flag to add space for one word of additional storage to be allocated for each stroke. Added space is for application use.
CPD_USERDWORD	Set internal flag to add space for one doubleword of additional storage to be allocated for each stroke. Added space is for application use.
CPD_TIME	Maintain absolute time information for each stroke.
gmemFlags

Flag that specifies whether GlobalAlloc should create a shared memory object or not when the pen data object is created. This should be either 0 or GMEM_DDESHARE. The GMEM_MOVEABLE and GMEM_ZEROINIT flags are added to this value, and other GMEM_ flags are ignored.

Return Value

Returns the handle to the HPENDATA object if successful; otherwise, returns NULL.

Comments

CreatePenDataEx is an extension of CreatePenData that allows a more detailed specification of what is stored in each stroke of the pen data.

The fuOptions parameter is typically specified as CPD_DEFAULT to request collection and storage of all information generated by the tablet, including x-y data, absolute stroke timing information, and all available OEM data. The OEM data set that is actually stored in the pen data is the minimum set that satisfies both the request and what is physically available from the tablet (that is, intersection set).

If lppeninfo is NULL, and if there is no tablet on the system (that is, if the SendDriverMessage function fails), the pen data that is created will not have any hardware or OEM information and a default sampling rate of 100Hz will be used. This case is similar to removing PENINFO from the header using TrimPenData with a parameter of TPD_PENINFO.

A value of 0 for fuOptions is used to indicate that only coordinate data is required. While recognition of this type of pen data may suffer, this provides the least complicated type of pen data.

PHW_ bits can be specified to indicate which OEM values or per-point PDK_ pen state information is to be collected. Note that, except for PHW_PDK, which is always valid, this is only a request; if the hardware does not support certain types of OEM data, that data will be absent.

The uScale parameter specifies scaling values that are also used in the MetricScalePenData function and in the PENDATAHEADER structure member wPndts. The scaling values do not behave in the same way as the Windows scaling units with similar names. For example, a 1-inch line in MM_HIENGLISH will not necessarily be an inch long on the screen, because GDI does not know the size of the monitor. However, with PDTS_HIENGLISH in MetricScalePenData, a line drawn an inch long is actually an inch long.

See Also

CreatePenData, DestroyPenData, PDTS_, PDK_


CreatePenDataHRC [New - Windows 95]
CreatePenDataHRC

2.0      [New - Windows 95]

Returns the handle to the HPENDATA object containing the pen data in the HRC.

HPENDATA CreatePenDataHRC( HRC hrc )

Parameters

hrc

Handle to the HRC object.

Return Value

Returns a handle to the HPENDATA object if successful; otherwise, it returns NULL.

Comments

It is the responsibility of the caller to destroy the HPENDATA object.

A recognizer is not required to use or maintain OEM data; that is, a recognizer can choose to ignore some or all of the OEM data it receives from AddPenDataHRC or AddPenInputHRC. This means that the HPENDATA object the recognizer returns through CreatePenDataHRC may not contain all the OEM data originally provided by the application. Whether or not a recognizer uses the OEM data, it should store all such data it receives and forward it so that subsequent recognizers, if any, can use the data.

See Also

AddPenInputHRC, AddPenDataHRC


CreatePenDataRegion [New - Windows 95]
CreatePenDataRegion

2.0      [New - Windows 95]

Creates a region that envelops the point data in an HPENDATA object.

HRGN CreatePenDataRegion( HPENDATA hpndt, UINT uType )

Parameters

hpndt

Handle to the HPENDATA object.

uType

Type of region to create. This can be one of the following values:

CPDR_BOX

The bounding box of the pen data ink is converted to a region.

CPDR_LASSO

The pen data describes a lasso that makes up the boundary of the region. If the last point of the pen data does not coincide with the first point, a closed figure is created either by joining the endpoints with a straight line or by using the intersection point of the beginning and ending line segments, whichever is more appropriate. Only the first stroke is used; if the pen data has more than a single stroke, subsequent strokes are ignored.

Return Value

This function returns a handle to a region if successful; otherwise the return value is NULL.

Comments

The coordinates of the region are the same as those used in the pen data. It is the application's responsibility to remove the region when the application is finished with it, using the Windows DeleteObject function.

CreatePenDataRegion enables an application to determine the screen area a gesture such as lasso or cut applies to. For an example of how to use the CreatePenDataRegion function to determine the area of a gesture, see the section "DoDefaultPenInput Messages" in Chapter 2, "Starting Out with System Defaults."


DestroyHRC [New - Windows 95]
DestroyHRC

2.0      [New - Windows 95]

Destroys an HRC object. A recognizer must export this function.

int DestroyHRC( HRC hrc )

Parameters

hrc

Handle to the HRC object.

Return Value

Returns HRCR_OK if successful; otherwise, returns one of the following negative values:

Constant	Description
HRCR_ERROR	Invalid parameter or other error.
HRCR_MEMERR	Insufficient memory.
Comments

If the HRC contains other objects such as an HPENDATA object, the recognizer must destroy the contained objects as well. After DestroyHRC returns HRCR_OK, the handle hrc is no longer valid. The application should set hrc to NULL to ensure it is not inadvertently used again.

See Also

CreateCompatibleHRC, DestroyHRCRESULT


DestroyHRCRESULT [New - Windows 95]
DestroyHRCRESULT

2.0      [New - Windows 95]

Destroys an HRCRESULT object. A recognizer must export this function.

int DestroyHRCRESULT( HRCRESULT hrcresult )

Parameters

hrcresult

Handle to the HRCRESULT object to destroy.

Return Value

Returns HRCR_OK if successful; otherwise, returns one of the following negative values:

Constant	Description
HRCR_ERROR	Invalid parameter or other error.
HRCR_MEMERR	Insufficient memory.
Comments

A recognizer must maintain a count of the number of HRCRESULT objects it creates. If an application calls DestroyHRC, the recognizer should not remove the HRC from memory until the application has called DestroyHRCRESULT for all HRCRESULT objects associated with the HRC.

After DestroyHRCRESULT returns HRCR_OK, the handle hrcresult is no longer valid. The application should set hrcresult to NULL to ensure it is not inadvertently used again.

See Also

GetResultsHRC, DestroyHRC


DestroyHWL [New - Windows 95]
DestroyHWL

2.0      [New - Windows 95]

Destroys a handle to a handwriting-recognition word list.

int DestroyHWL( HWL hwl )

Parameters

hwl

Word list to destroy.

Return Value

Returns HRCR_OK if successful; otherwise, returns one of the following negative values:

Constant	Description
HRCR_ERROR	Invalid parameter or other error.
HRCR_MEMERR	Insufficient memory.
HRCR_UNSUPPORTED	The recognizer does not support this function.
Comments

After DestroyHWL returns HRCR_OK, the handle hwl is no longer valid. The application should set hwl to NULL to ensure it is not inadvertently used again.

See Also

CreateHWL


DestroyInkset [New - Windows 95]
DestroyInkset

2.0      [New - Windows 95]

Frees memory associated with an inkset.

BOOL DestroyInkset( HINKSET hinkset )

Parameters

hinkset

Handle of an inkset to destroy.

Return Value

Returns TRUE if successful; otherwise FALSE.

Comments

Once memory is freed, the handle hinkset is invalid. The application should set the handle to NULL.

See Also

CreateInkset, INTERVAL


DestroyPenData [New - Windows 95]
DestroyPenData

1.0     2.0      [New - Windows 95]

Frees the memory associated with a specified pen data memory block.

BOOL DestroyPenData( HPENDATA hpndt )

Parameters

hpndt

Handle to a pen data memory block to destroy.

Return Value

Returns TRUE if the memory was successfully freed; otherwise, FALSE.

Comments

Once the memory block is destroyed, the HPENDATA handle is no longer valid. The application should set the handle to NULL.

See Also

CreatePenData, CreatePenDataEx


DictionarySearch [New - Windows 95]
DictionarySearch

1.0     2.0      [New - Windows 95]

Performs a dictionary search for a version 1.0 recognizer.

Note  This function is provided only for compatibility with version 1.0 of the Pen API and will not be supported in future versions.

BOOL DictionarySearch( LPRC lprc, LPSYE lpsye, int cSye, LPSYV lpsyv, int csyvMax )

Parameters

lprc

Address of an RC structure.

lpsye

Address of an array of SYE symbol elements that constitute the symbol graph.

cSye

Number of SYE structures in the array.

lpsyv

Output buffer of SYV types. This parameter contains the return results of the dictionary search. A SYV_NULL value is always appended at the end of this buffer. Therefore, this parameter must have enough space for csyvMax + 1 SYV symbol values.

csyvMax

Size of the output buffer.

Return Value

Returns TRUE if any enumeration is found in a dictionary. It returns FALSE if a NULL dictionary was requested or none of the enumerations was found in any dictionary.

Comments

The DictionarySearch function uses the symbol graph pointed to by lpsye, performs a dictionary search based on the options set in lprc, and returns the result as an array of SYV symbol values in the buffer pointed to by lpsyv. The function returns the number of SYV elements copied, limited by the maximum specified in the csyvMax parameter.

DictionarySearch first passes the symbol graph with DIRQ_SYMBOLGRAPH to all the dictionaries in the rglpdf array in the specified RC structure. If none succeeds, the function enumerates the symbol graph in lpsye and searches through all of the dictionary functions for a match. The calling application can get suggestions by setting the RCO_SUGGEST flag in the lRcOptions field in the RC structure. When this flag is set and no enumeration is found in any of the dictionaries in the rglpdf array, DictionarySearch tries to get a suggestion from the dictionaries on the path. DictionarySearch takes the first suggestion offered by any dictionary and returns that as the result of the search. If there are no suggestions, the function returns the best enumeration. The best enumeration is obtained using the FirstSymbolFromGraph function.

If the option RCO_NOSPACEBREAK is set in the lRcOptions field of the specified RC structure, DictionarySearch treats the entire lpsye array as a single symbol graph. If this flag is not set, the function breaks down the input symbol graph into tokens delimited by white space, performs the search sequence on each of them, and assembles the result in the lpsyv array.

This function uses the EnumSymbols function for enumeration and the wTryDictionary member in the RC structure to specify the maximum number of enumerations to search through for each symbol graph token.

See Also

EnumSymbols, FirstSymbolFromGraph, SYE, SYV_, RC


DoDefaultPenInput [New - Windows 95]
DoDefaultPenInput

2.0      [New - Windows 95]

Initiates default handling of pen input.

int DoDefaultPenInput( HWND hwnd, UINT wEventRef )

Parameters

hwnd

Handle to the window initiating the default processing.

wEventRef

An identifier of a pen event in the input stream, from which input is begun. This identifier is the value returned from the GetMessageExtraInfo function.

Return Value

Returns one of the following values:

Constant	Description
PCMR_OK	Pen collection was successfully started.
PCMR_ALREADYCOLLECTING	StartPenInput has already been called for this session.
PCMR_APPTERMINATED	The application aborted input.
PCMR_ERROR	Illegal parameter or unspecified error.
PCMR_INVALID_PACKETID	Invalid packet identifier.
PCMR_SELECT	Press-and-hold was detected. Collection is not started.
PCMR_TAP	A pen tap was detected. Collection is not started.
Comments

DoDefaultPenInput simplifies the pen input process by including the following capabilities in a single call:

•	Starts pen input by calling StartPenInput

•	Starts inking by calling StartInking

•	Saves the screen background overwritten by the ink

•	Collects the pen input data

•	Stops inking by calling StopInking

•	Stops pen input by calling StopPenInput

•	Targets the pen input data to windows

•	Recognizes results

•	Sends the recognition results to the targets

The default processing proceeds in three phases: initialization, data gathering, and termination. A set of submessages corresponds to each of the three phases.

•	During the initialization phase, the system sends the WM_PENEVENT sub-message PE_SETTARGETS and potentially several PE_GETPCMINFO and PE_GETINKINGINFO messages. After the target or the DefWindowProc function handles these messages and returns a value of PCMR_OK to indicate success, the data-gathering phase begins.

•	During the data-gathering phase, the window specified by the hwnd parameter starts to receive the core pen-input submessages PE_PENDOWN, PE_PENUP, and PE_PENMOVE. The window should let these submessages fall through to DefWindowProc, which translates them into the higher-level messages PE_BEGINDATA and PE_MOREDATA. These are sent to one of the windows specified in the htrgTarget members of the TARGET structures if targeting is in progress; otherwise, the messages are sent to hwnd.

•	The termination phase begins when the pen input terminates. The target window should let the core termination messages PE_TERMINATING and PE_TERMINATED fall through to DefWindowProc. The PE_ENDDATA, PE_RESULT, and PE_ENDINPUT submessages are sent by DefWindowProc while processing PE_TERMINATED.

A return value of LRET_ABORT to any of the WM_PENEVENT submessages aborts the entire process of default input.

See Also

WM_PENEVENT, StartPenInput, StartInking, StopPenInput, StopInking


DPtoTP [New - Windows 95]
DPtoTP

1.0     2.0      [New - Windows 95]

Converts an array of points in display coordinates to tablet coordinates.

BOOL DPtoTP( LPPOINT lppt, int cPnt )

Parameters

lppt

Address of an array of POINT structures to convert to tablet coordinates. This parameter cannot be NULL.

cPnt

Number of POINT structures to convert.

Return Value

Returns TRUE if the conversion was successful; otherwise, returns FALSE.

Comments

Because of possible rounding errors, the DPtoTP and TPtoDP functions are not guaranteed to be perfect inverses of each other.

The calling application must avoid overflow by passing in points that are within the limits of the current physical display.

See Also

TPtoDP


DrawPenData [New - Windows 95]
DrawPenData

1.0     2.0      [New - Windows 95]

Displays the pen data in an HPENDATA object as a trail of visible ink.

void DrawPenData( HDC hdc, LPRECT lprect, HPENDATA hpndt )

Parameters

hdc

Handle to a device context. This parameter can also be the handle of a metafile.

lprect

Bounding rectangle of ink, in client coordinates. Can be NULL.

hpndt

Handle to a pen data object.

Return Value

This function does not return a value. If hpndt is NULL, DrawPenData does nothing.

Comments

DrawPenData draws the pen data in the specified device context using the GDI Polyline function. The current settings in the device context rather than the ink characteristics determine how the data is rendered. This means the ink width and color specified in the PENDATAHEADER structure have no effect on how DrawPenData renders the ink. To alter the display characteristics of the ink, an application must call the appropriate Windows GDI functions to set the GDI drawing pen (not to be confused with the real pen).

The application using DrawPenData must either scale the data points or set the mapping appropriately if lprect is NULL.

If lprect is not NULL, the points are scaled into lprect as the drawing is done. Internally, nondestructive calls to the SetViewportExt, SetViewPortOrg, SetWindowOrg, and SetWindowExt functions are used to render the pen data in the device context within the bounds of the provided rectangle. An application must compute the proper pen width (if it is other than 1) before calling this function with a valid lprect parameter to account for the scaling that occurs.

DrawPenData draws the ink in the rectangle relative to the upper-left corner of the window. It ignores any changes that have been made to the origin of the device context by previous calls to the SetWindowOrg or SetViewportOrg functions. If the origin has changed, the rectangle passed to DrawPenData must be offset by the appropriate amount.

If the ink is to be drawn with a width of greater than 1 pixel, the width of the currently selected pen must be set to achieve the desired result. The width must be set in client coordinates if a mapping mode is set in the device context. For example, if the mapping mode has been set to MM_HIENGLISH, the pen width must be set to a number appropriate for the desired width in MM_HIENGLISH units to preserve the proper scale of the ink. This scaling is only an issue when the ink width is greater than 1.

The rendering of the ink data produced by DrawPenData generally does not exactly match the rendering produced by the display driver when the data was first collected. This discrepancy results because DrawPenData and the Polyline function use different algorithms to draw the data. The difference is an occasional "off by one" error that appears as a shifting of some pixels around the edges, depending on the rounding done by Polyline. An application that requires an exact replication of the original ink rendering should call the RedisplayPenData function.

The DrawPenDataEx function allows more control when drawing the contents of pen structures.

See Also

CreatePenData, DrawPenDataEx, DuplicatePenData, RedisplayPenData


DrawPenDataEx [New - Windows 95]
DrawPenDataEx

2.0      [New - Windows 95]

An enhanced version of DrawPenData. Besides displaying the pen data in an HPENDATA object as a trail of visible ink, DrawPenDataEx can govern the speed at which the data is rendered, a process called animation.

int DrawPenDataEx( HDC hdc, LPRECT lprectVP, HPENDATA hpndt, UINT iStrkFirst, UINT iStrkLast, UINT iPntFirst, UINT iPntLast, ANIMATEPROC lpfnAnimateCB, LPANIMATEINFO lpai, UINT fuFlags )

Parameters

hdc

Handle to a device context.

lprectVP

Viewport rectangle, usually the bounding rectangle of the pen data, in client coordinates. The ink is scaled to fit the specified rectangle. If this parameter is NULL, the bounding rectangle of the ink in hpndt is used, in whatever coordinate system it happens to be in.

hpndt

Handle to a pen data object.

iStrkFirst

Index of the first stroke to display.

iStrkLast

Index of the last stroke to display.

iPntFirst

Index of the first point in the first stroke to display.

iPntLast

Index of the last point in the last stroke to display.

lpfnAnimateCB

Pointer to a callback function instance, or NULL. The callback function is called periodically during drawing, and animation is controlled by values in the structure addressed by the next parameter, lpai, which should not be NULL. If lpfnAnimateCB and the speed in the lpai structure parameters are NULL, the specified pen data is drawn without regard to timing information, and no callback functions are generated. See AnimateProc for a description of the callback function.

lpai

Address of an ANIMATEINFO structure that specifies animation parameters to control how the pen data is drawn. If this parameter is NULL, the function draws the specified pen data without regard to timing information, and no callback functions are generated; otherwise, the caller must initialize the cbSize member to sizeof( ANIMATEINFO ).

fuFlags

This flag can be 0 or one of the following values:

DPD_HDCPEN

Use the GDI pen already selected into the specified device context. If this flag is set, any pen formatting stored in hpndt is ignored and all strokes are drawn with a single width and color. The DrawPenData function uses this flag.

DPD_DRAWSEL

Paint selected strokes in the specified range. A solid pen is used, with a width slightly larger than the stroke width. This flag can be used only for drawing and is ignored for animation. It is incompatible with DPD_HDCPEN.

Return Value

Returns PDR_OK if successful. Attempting to draw an empty HPENDATA (containing no strokes) also returns PDR_OK. Otherwise, returns one of the following:

Constant	Description
PDR_ABORT	Drawing aborted because pen data became invalid after a callback or yield.
PDR_CANCEL	Callback cancel or impasse. An impasse occurs when the user attempts to animate with 0 percent speed (that is, pause),  but the callback interval is on a per-stroke basis.
PDR_COMPRESSED	Pen data is compressed.
PDR_ERROR	Bad animation structure, invalid sampling rate (0 or less) in pen data header, illegal flags, or other error.
PDR_MEMERR	Memory error.
PDR_PNDTERR	Invalid pen data. This value is also returned if the pen data is destroyed or corrupted during drawing or animation. This error can occur if an application is drawing a large pen data object and then destroys the data before drawing is complete.
PDR_PNTINDEXERR	Invalid point index.
PDR_STRKINDEXERR	Invalid stroke index.
PDR_VERSIONERR	Could not convert old pendata.
Comments

DrawPenDataEx is a general-purpose drawing function for rendering pen data objects. The calling application can use the timing information in the strokes to animate the pen data and specify which subset of the pen data should be drawn.

Partial pen data objects can be drawn by specifying first and last strokes and points with iStrkFirst, iStrkLast, iPntFirst, and iPntLast. Set beginning values to 0 and ending values to IX_END to display the entire pen data object. The function fails if any of these values lie outside the ranges available in the pen data. The stroke values must be between 0 and the total number of strokes in the pen data, and the point indices must be between 0 and the number of points in their stroke.

DrawPenDataEx can display only a set of sequential strokes with a single call. To draw nonsequential strokes—say, the second, fifth, and eighth strokes of the pen data—requires multiple calls to DrawPenDataEx.

Ink displayed by DrawPenDataEx differs slightly from the original rendering, as described in the DrawPenData topic. However, DrawPenDataEx can automatically display the ink with its original color and width, saving the application the burden of resetting the current GDI pen characteristics. To draw the ink according to the GDI settings, set fuFlags to DPD_HDCPEN.

If lpfnAnimateCB is not NULL, the specified callback function must return TRUE to continue drawing, or FALSE to terminate drawing.

An application can modify the pen data while it is being rendered, for example, during an animation callback, task switching, or internal yield. However, doing so can make internal pointers or data invalid and result in unpredictable behavior. For this reason, editing the pen data during rendering is not recommended.

See Also

AnimateProc, DrawPenData, RedisplayPenData, DrawPenDataFmt, ANIMATEINFO


DrawPenDataFmt [New - Windows 95]
DrawPenDataFmt

2.0      [New - Windows 95]

The DrawPenDataFmt macro is used to draw pen data using its stored stroke attributes.

int DrawPenDataFmt( HDC hdc, LPRECT lprectVP, HPENDATA hpndt )

Parameters

hdc

Handle to a device context.

lprectVP

Viewport rectangle, usually the bounding rectangle of the HPENDATA object, in client coordinates. The ink is scaled to fit the specified rectangle. If this parameter is NULL, the bounding rectangle of the ink in hpndt is used, in whatever coordinate system it happens to be in.

hpndt

Handle to an HPENDATA object.

Return Value

Returns PDR_OK if successful. Attempting to draw valid but empty pen data (containing no strokes) also returns PDR_OK. Otherwise, the return value is one of the following:

Constant	Description
PDR_COMPRESSED	Pen data is compressed.
PDR_ERROR	Invalid sampling rate (0 or less) in pen data header, or other error.
PDR_MEMERR	Memory error.
PDR_PNDTERR	Invalid pen data.
PDR_VERSIONERR	Could not convert old pen data.
Comments

The DrawPenDataFmt macro is a wrapper for DrawPenDataEx, providing default values for most of the parameters.

The definition is:

#define DrawPenDataFmt( hdc, lprectVP, hpndt )

DrawPenDataEx( hdc, lprectVP, hpndt, 0, IX_END, 0, IX_END, NULL,

   NULL, 0 );

These default values specify:

•	Full-speed rendering (no animation).

•	Entire data set is drawn (no stroke subsets).

See Also

DrawPenDataEx


DuplicatePenData [New - Windows 95]
DuplicatePenData

1.0     2.0      [New - Windows 95]

Duplicates an HPENDATA object, allowing an application to generate clones of existing pen data.

HPENDATA DuplicatePenData( HPENDATA hpendata, UINT gmemFlags )

Parameters

hpendata

Pen data to be duplicated.

gmemFlags

Flag that specifies whether or not the Windows GlobalAlloc function should create a shared memory object when the pen data object is created. This should be either 0 or GMEM_DDESHARE. The GMEM_MOVEABLE and GMEM_ZEROINIT flags are added to this value and other GMEM_ flags are ignored.

Return Value

Returns a handle to the duplicated pen data object if successful; otherwise, it returns NULL. It returns NULL if memory is not allocated successfully.

Comments

The DuplicatePenData function duplicates the data specified by the hpendata parameter by creating a second pen data memory block. The application is responsible for destroying this memory block by calling DestroyPenData.

See Also

CreatePenData, DestroyPenData


EmulatePen [New - Windows 95]
EmulatePen

1.0     2.0      [New - Windows 95]

Emulates a pen in an application that does not use the standard Windows I-beam cursor in text areas.

Note  This function is provided only for compatibility with version 1.0 of the Pen API and will not be supported in future versions. Use DoDefaultPenInput or hedit controls instead.

void EmulatePen( BOOL fPen )

Parameters

fPen

Flag to set pen emulation. TRUE activates pen emulation; FALSE turns it off.

Return Value

This function does not return a value.

Comments

The application must call EmulatePen with fPen set to TRUE whenever the cursor is over a text input window. When the cursor leaves that area, the application must call EmulatePen with fPen set to FALSE.

EmulatePen is useful only for those applications that do not use other Pen API services and do not use the standard Windows I-beam cursor. Windows automatically provides pen-based input in edit controls that use the I-beam cursor, as described in Chapter 1.

See Also

DoDefaultPenInput


EnableGestureSetHRC [New - Windows 95]
EnableGestureSetHRC

2.0      [New - Windows 95]

Enables or disables recognition of specific gestures or collections of gestures in an HRC object.

int EnableGestureSetHRC( HRC hrc, SYV syv, BOOL fEnable )

Parameters

hrc

Handle to the HRC object.

syv

Either a gesture SYV_ symbol value, such as SYV_COPY, or one or more of the following GST_ constants combined using the bitwise-OR operator. Note that individual SYV_ gesture symbol values cannot be combined with GST_ constants.

Constant	Description
GST_SEL	Selection and lasso.
GST_CLIP	Cut, copy, paste.
GST_WHITE	Space, tab, return.
GST_EDIT	Insert, correct, undo.
GST_CIRCLELO	Lowercase circle gestures.
GST_CIRCLEUP	Uppercase circle gestures.
GST_CIRCLE	All circle gestures.
GST_ALL	All gestures.
fEnable

Enable recognition flag. This flag must be set to TRUE to enable recognition of the gesture or gestures in syv, or to FALSE to disable recognition of the specified gestures.

Return Value

Returns HRCR_OK if successful; otherwise, returns one of the following negative values:

Constant	Description
HRCR_ERROR	Invalid parameter or other error.
HRCR_MEMERR	Insufficient memory.
HRCR_UNSUPPORTED	The recognizer does not support this function.
Comments

The results of EnableGestureSetHRC are cumulative. The function can be called several times in succession to refine the precise gesture set required. However, calling EnableGestureSetHRC with syv set to GST_ALL and fEnable set to FALSE disables all gestures.

By default, a recognition context HRC enables all gestures that its associated recognizer supports.

Example

The following example enables selection, Clipboard functions, and SYV_CIRCLEUPA:

EnableGestureSetHRC( hrc, GST_ALL, FALSE );	    // Disable all

EnableGestureSetHRC( hrc, GST_SEL | GST_CLIP, TRUE ); // Enable sets

EnableGestureSetHRC( hrc, SYV_CIRCLEUPA, TRUE );	    // Enable circle A

See Also

SetAlphabetHRC, SYV_


EnableSystemDictionaryHRC [New - Windows 95]
EnableSystemDictionaryHRC

2.0      [New - Windows 95]

Enables or disables a recognizer's dictionary.

int EnableSystemDictionaryHRC( HRC hrc, BOOL fEnable )

Parameters

hrc

Handle to the HRC object for the recognizer.

fEnable

Enable recognition flag. This flag must be set to TRUE to enable use of the dictionary, or FALSE to disable its use.

Return Value

Returns HRCR_OK if successful; otherwise, returns one of the following negative values:

Constant	Description
HRCR_ERROR	Invalid parameter, no system dictionary, or other error.
HRCR_MEMERR	Insufficient memory.
HRCR_UNSUPPORTED	The recognizer does not support this function.
Comments

The enable state of the system dictionary does not affect any word lists that may be set into the HRC object.

See Also

SetWordlistHRC


EndEnumStrokes [New - Windows 95]
EndEnumStrokes

1.0     2.0      [New - Windows 95]

Unlocks an HPENDATA memory block previously locked with the function BeginEnumStrokes.

Note  This function is provided only for compatibility with version 1.0 of the Pen API, and will not be supported in future versions.

LPPENDATA EndEnumStrokes( HPENDATA hpndt )

Parameters

hpndt

Handle to the locked HPENDATA memory block.

Return Value

Returns NULL if the function is successful; otherwise, the return value is nonzero.

Comments

EndEnumStrokes internally calls the Windows GlobalUnlock function to unlock the memory block specified by hpndt. Calling EndEnumStrokes invalidates any pointers previously returned by the GetPenDataStroke function.

See Also

BeginEnumStrokes, GetPenDataStroke


EndPenInputHRC [New - Windows 95]
EndPenInputHRC

2.0      [New - Windows 95]

Informs a recognizer that pen data input has been terminated. A recognizer must export this function.

int EndPenInputHRC( HRC hrc )

Parameters

hrc

Handle to the HRC object for the recognizer.

Return Value

Returns HRCR_OK if successful; otherwise, returns one of the following negative values:

Constant	Description
HRCR_MEMERR	Insufficient memory.
HRCR_ERROR	Invalid parameter or other error.
Comments

EndPenInputHRC does not instruct the recognizer to complete recognition; an application must call ProcessHRC to do that. However, an application that does not use DoDefaultPenInput must call EndPenInputHRC when it detects that input has finished. (DoDefaultPenInput calls EndPenInputHRC internally.)

The recognizer can terminate open-ended states and reduce ambiguity in searches when it knows that no more ink will arrive. For example, the recognizer can keep various options open for possible delayed strokes that can modify a character. EndPenInputHRC tells the recognizer that no more delayed strokes will arrive.

After calling EndPenInputHRC for an HRC, an application should cease adding pen input into the HRC. Some recognizers, such as the Microsoft Handwriting Recognizer (GRECO.DLL), do not accept late pen input. If the application calls AddPenInputHRC after having called EndPenInputHRC for the same HRC, the Microsoft Handwriting Recognizer returns HRCR_ERROR.

Other recognizers may differ. With such recognizers, a client may continue to add pen input without error into a recognition context, even after having called EndPenInputHRC. However, doing so is not efficient. In the worst case, the recognizer may be forced to reprocess all of the pen data from the beginning.

For an example of a normal termination sequence, see the code sample in GetSymbolsHRCRESULT.

See Also

ProcessHRC, DoDefaultPenInput


EnumSymbols [New - Windows 95]
EnumSymbols

1.0     2.0      [New - Windows 95]

Enumerates strings in a symbol graph in order of most probable to least probable.

UINT EnumSymbols( LPSYG lpsyg, UINT cstrMax, ENUMPROC lpEnumFunc, LPVOID lvData )

Parameters

lpsyg

Address of the symbol graph SYG.

cstrMax

Maximum number of strings to enumerate.

lpEnumFunc

Address of enumeration function.

lvData

Application-specific data.

Return Value

Returns the number of strings enumerated.

Comments

The EnumSymbols function enumerates all symbol strings (to a maximum defined by cstrMax) contained in the symbol graph that lpsyg points to. The lpEnumFunc parameter points to the enumeration function called with each enumeration.

To generate all the symbols from a symbol graph, set cstrMax equal to the value retrieved by passing lpsyg to GetSymbolCount.

See Also

EnumSymbolsCallback, FirstSymbolFromGraph, SYG, SYV_


EnumSymbolsCallback [New - Windows 95]
EnumSymbolsCallback

1.0     2.0      [New - Windows 95]

EnumSymbolsCallback is a callback function pointed to by the lpEnumFunc parameter of EnumSymbols. The callback function can have any name. The function's name must appear in the EXPORT section of the application's module definition file.

int CALLBACK EnumSymbolsCallback( LPSYV lpsyv, int csyv, FAR void * lvData )

Parameters

lpsyv

Symbol string.

csyv

Count of symbols in string.

lvData

Address of application-specific data from EnumSymbols.

Return Value

Returns TRUE to continue enumeration, or FALSE to stop enumeration.

See Also

EnumSymbols, SYV_


ExtractPenDataPoints [New - Windows 95]
ExtractPenDataPoints

2.0      [New - Windows 95]

Extracts points from a specified stroke in an HPENDATA object.

int ExtractPenDataPoints( HPENDATA hpndt, UINT iStrk, UINT iPnt, UINT cPnts, LPPOINT lppt, LPVOID lpvOem, UINT fuOption )

Parameters

hpndt

Handle to an HPENDATA object.

iStrk

Zero-based index of the stroke to remove points from.

iPnt

Zero-based index to the first point to remove.

cPnts

Count of points to remove. If this value is greater than the number of points after iPnt, all the points from iPnt to the last point of the stroke are removed. ExtractPenDataPoints fails if iPnt is greater then the number of points in the stroke.

lppt

Array of POINT structures that receives the extracted points. This must be large enough to hold cPnts points.

lpvOem

Buffer to put extracted OEM data if it exists, or NULL. This must be large enough to hold cPnts OEM packets.

fuOption

Flags. This value can be EPDP_REMOVE to remove the points from the stroke in the pen data object.

Return Value

Returns PDR_OK if successful; otherwise, the return value can be one of the following negative values:

Constant	Description
PDR_COMPRESSED	Pen data is compressed.
PDR_ERROR	Parameter or other unspecified error.
PDR_MEMERR	Out of memory.
PDR_STRKINDEXERR	Invalid stroke index.
PDR_PNTINDEXERR	Invalid point index.
PDR_VERSIONERR	Could not convert old pen data object.
Comments

ExtractPenDataPoints extracts points (and OEM data, if any) from a specified stroke of the pen data object specified by hpndt. It copies the extracted points and the OEM data to the buffers pointed to by lppt and lpvOem.

Use ExtractPenDataStrokes to extract strokes from the pen data object or RemovePenDataStrokes to remove strokes from the pen data object.

See Also

InsertPenDataPoints, InsertPenDataStroke, RemovePenDataStrokes


ExtractPenDataStrokes [New - Windows 95]
ExtractPenDataStrokes

2.0      [New - Windows 95]

Creates a new HPENDATA object that is a subset of an existing object.

int ExtractPenDataStrokes( HPENDATA hpndt, UINT fuExtract, LPARAM lParam, LPHPENDATA lphpndtNew, UINT gmemFlags )

Parameters

hpndt

Handle to an existing pen data object.

fuExtract

Extraction options and modifiers. This value can be a combination of one of the principal EPDS_ options, with an optional comparison modifier, if appropriate, and the optional EPDS_REMOVE modifier. The flags should be combined using the bitwise-OR operator.

The following table gives the principal options. These options specify what the new pen data object will be based on.

Constant	Description
EPDS_INKSET	Based on a handle to an inkset. The EPDS_GT, EPDS_GTE, EPDS_LT, and EPDS_LTE comparison operators are ignored, because extraction is based on matching the inkset. (However, EPDS_NOT creates a pen data set with all stroke/inkset intersections that do not match the provided inkset.)
EPDS_PENTIP	Based on complete pen-tip characteristics.
EPDS_SELECT	Based on selected strokes.
EPDS_STROKEINDEX	Based on index.
EPDS_TIPCOLOR	Based on pen-tip color.
EPDS_TIPWIDTH	Based on pen-tip width.
EPDS_TIPNIB	Based on pen tip nib style.
EPDS_USER	Based on user-specific value. The following table gives the optional comparison modifiers and the optional removal modifier:
EPDS_LT	Less than comparison: extract all strokes with attribute less than the value specified in lParam.
EPDS_LTE	Less than or equal comparison: extract all strokes with attributes less than or equal to the value specified in lParam.
EPDS_GT	Greater than comparison: extract all strokes with attributes greater than the value specified in lParam.
EPDS_GTE	Greater than or equal comparison: extract all strokes with attributes greater than or equal to the value specified in lParam.
Constant	Description
EPDS_NOT	Negative comparison (alias EPDS_NE): extract all strokes with attributes not equal to the value specified by lParam. If combined with other EPDS_ constants, reverses the constant meaning (for example, EPDS_NE | EPDS_LT | EPDS_GT means not less than or not greater than). If lParam is EPDS_SELECT, EPDS_NOT means extract all unselected strokes.
EPDS_REMOVE	Remove matching strokes from source. If this flag is added, any strokes matching the criteria for extraction are removed from the source pen data.
lParam

Meaning is dependent on the value of the fuExtract parameter, as follows:

Constant	Description
EPDS_INKSET	lParam is a handle to an inkset.
EPDS_PENTIP	lParam is a pointer to a PENTIP structure to compare. Only equal or not-equal matches are supported. EPDS_LT, for example, is ignored.
EPDS_SELECT	lParam is not used and should be set to 0.
EPDS_STROKEINDEX	lParam is a zero-based stroke index to compare.
EPDS_TIPCOLOR	lParam is a pen tip color to compare.
EPDS_TIPNIB	lParam is a pen tip nib style to compare. Only equal or not-equal matches are supported.
EPDS_TIPWIDTH	lParam is a pen tip width to compare.
EPDS_USER	lParam is a user-specific value to compare, cast to a double-word value.
lphpndtNew

Address of a pen data handle if one is to be created; otherwise, NULL.

gmemFlags

Flag that specifies whether or not the Windows GlobalAlloc function should create a shared memory object when the pen data object is created. This should be either 0 or GMEM_DDESHARE. The GMEM_MOVEABLE and GMEM_ZEROINIT flags are added to this value, and other GMEM_ flags are ignored.

Return Value

Returns the number of strokes that match the comparison criteria if successful, or a negative error value. (The return value can be 0. The maximum is the largest integer value.)  The error value can be one of the following:

Constant	Description
PDR_COMPRESSED	Pen data is compressed.
PDR_ERROR	Parameter or other unspecified error.
PDR_INKSETERR	Invalid inkset and EPDS_INKSET specified.
PDR_MEMERR	Memory error.
PDR_NA	Option not available.
PDR_PNDTERR	Invalid pendata.
PDR_STRKINDEXERR	Invalid stroke index.
PDR_USERDATAERR	EPDS_USER was specified but there is no per-stroke user data.
PDR_VERSIONERR	Could not convert old pendata.
Comments

ExtractPenDataStrokes extracts strokes from an existing pen data object, optionally creating a new pen data object made up of the extracted strokes. The extraction can be a copy or move process; that is, the source pen data object can remain the same or contain only the remaining strokes not moved to the new structure. Modifier flags in fuExtract specify how the value in lParam compares with attributes of the pen data strokes (equal by default, greater than, less than, or none of these three).

If lphpndtNew is NULL, no pen data object is created. This is useful for modifying the original pen data object hpndt (when EPDS_REMOVE specified), or simply for determining a return value without modifying or creating a pen data object. If lphpndtNew is not NULL, the flags specified by gmemFlags are passed to the GlobalAlloc function when memory for the pen data memory block is created.

If EPDS_REMOVE is specified, any strokes with an attribute matching the comparison criteria are removed from the source pen data object, regardless of whether a new pen data is created. In the case of inksets, this may actually generate more strokes if there are multiple intersections with the inkset within any one stroke.

Example

To create an HPENDATA object consisting only of selected strokes:

ExtractPenDataStrokes( hpndt, EPDS_SELECT, 0, &hpndtDst, 0 );

To return the count of selected strokes:

ExtractPenDataStrokes( hpndt, EPDS_SELECT, 0, NULL, 0 );

To delete all but the selected strokes from the source:

ExtractPenDataStrokes( hpndt, EPDS_NOT | EPDS_SELECT | EPDS_REMOVE,

   0, NULL, 0 );

To copy strokes 0 through 10 inclusive to a new HPENDATA object:

ExtractPenDataStrokes( hpndt, EPDS_LTE | EPDS_STROKE, 10,

   &hpndtDst, 0 );

To move all but blue strokes to a separate HPENDATA object:

ExtractPenDataStrokes( hpndt, EPDS_NOT | EPDS_TIPCOLOR | EPDS_REMOVE,

   RGB_BLUE, &hpndtDst, 0 );

See Also

DuplicatePenData


FirstSymbolFromGraph [New - Windows 95]
FirstSymbolFromGraph

1.0     2.0      [New - Windows 95]

Retrieves an array of symbols that is the most likely interpretation of a specified symbol graph SYG.

void FirstSymbolFromGraph( LPSYG lpsyg, LPSYV lpsyv, int cSyvMax, LPINT lpcSyv )

Parameters

lpsyg

Address of the symbol graph.

lpsyv

Address of an empty array of SYV_ symbol values. FirstSymbolFromGraph fills this array with the likeliest interpretation from the graph.

cSyvMax

Size of the array that lpsyv points to.

lpcSyv

Number of symbols returned in lpsyv. This value is 0 if lpsyg is empty. It is −1 if the buffer is not large enough to hold the results.

Return Value

This function does not return a value.

Comments

The array of symbols is identical to the first string returned to the EnumSymbolsCallback callback function of EnumSymbols.

See Also

EnumSymbols, SYG, SYV_


GetAlphabetHRC [New - Windows 95]
GetAlphabetHRC

2.0      [New - Windows 95]

Retrieves the alphabet being used in a handwriting recognition context HRC.

int GetAlphabetHRC( HRC hrc, LPALC lpalc, LPBYTE rgbfAlc )

Parameters

hrc

Handle to the HRC object.

lpalc

Address of a buffer that receives the current ALC_ values. If NULL, this parameter is ignored.

rgbfAlc

Address of an array of bits or NULL. If NULL, this parameter is ignored. If lpalc contains ALC_USEBITMAP and rgbfAlc points to a valid array, the array is filled according to the bits set by the SetAlphabetHRC function.

Return Value

Returns HRCR_OK if successful; otherwise, returns one of the following negative values:

Constant	Description
HRCR_ERROR	Invalid parameter or other error.
HRCR_MEMERR	Insufficient memory.
HRCR_UNSUPPORTED	The recognizer does not support this function.
Comments

If rgbfAlc is not NULL, the array it points to must be large enough to accommodate 256 bits (32 bytes). If the nth bit is set, the nth ANSI character is recognizable. Bits representing characters with ASCII values less than 32 (the space character) currently have no meaning.

ALC_DEFAULT specifies the set of characters at or above ALC_SYSMINIMUM that the recognizer can accurately distinguish.

For a description of alphabets and their relationship to a recognizer, see "Configuring the HRC" in Chapter 5, "The Recognition Process."

See Also

EnableGestureSetHRC, SetAlphabetHRC, GetAlphabetPriorityHRC, ALC_


GetAlphabetPriorityHRC [New - Windows 95]
GetAlphabetPriorityHRC

2.0      [New - Windows 95]

Retrieves the alphabet priority used in a handwriting recognition context HRC.

int GetAlphabetPriorityHRC( HRC hrc, LPALC lpalc, LPBYTE rgbfalc )

Parameters

hrc

Handle to the HRC object.

lpalc

Address of an ALC type that will be filled with the current ALC_ priority values.

rgbfalc

Address of a 256-bit (32-byte) buffer whose bits map to ANSI single-byte characters, or NULL if this information is not required.

Return Value

Returns HRCR_OK if successful; otherwise, returns one of the following negative values:

Constant	Description
HRCR_ERROR	Invalid parameter or other error.
HRCR_MEMERR	Insufficient memory.
HRCR_UNSUPPORTED	The recognizer does not support this function.
For a description of how a recognizer uses alphabet priority, see "Configuring the HRC" in Chapter 5, "The Recognition Process."

See Also

GetAlphabetHRC, SetAlphabetPriorityHRC, ALC_


GetAlternateWordsHRCRESULT [New - Windows 95]
GetAlternateWordsHRCRESULT

2.0      [New - Windows 95]

Returns alternative word interpretations of a previous result. (Not supported in Japanese version.)

int GetAlternateWordsHRCRESULT( HRCRESULT hrcresult, UINT iSyv, UINT cSyv, LPHRCRESULT rghrcresults, UINT cResults )

Parameters

hrcresult

Handle of a results object.

iSyv

Index of the first of a span of symbols within the results object.

cSyv

The number of symbols in the original result, starting at iSyv, for which alternative words are required.

rghrcresults

Address of a result array. This address cannot be NULL.

cResults

The size of the rghrcresults array in results. This parameter must be greater than 0.

Return Value

Returns the number of results actually provided, if successful. This can be less than the space allocated in rghrcresults, and may be 0; otherwise, returns one of the following negative values:

Constant	Description
HRCR_ERROR	Invalid parameter or other error.
HRCR_MEMERR	Insufficient memory.
HRCR_UNSUPPORTED	The recognizer does not support this function.
Comments

GetAlternateWordsHRCRESULT provides alternative word interpretations of a previous result. The alternatives returned are strongly coerced to words in the recognizer's dictionary, if enabled, and the word list, if any, of the HRC that processed the results.

The span of symbols defined by iSyv and cSyv need not fall on word boundaries. However, the recognizer returns only a single word per result. It is the application's responsibility to ensure that embedding a full word within other symbols makes sense. (The application can also choose to let the user make that decision.) For example, finding alternatives for "polce" in the phrase "pig-in-a-polce" could legitimately return "poke" as an alternative, but alternatives for "kef" in "markefplace" would probably be meaningless.

See Also

GetResultsHRC


GetBoxMappingHRCRESULT [New - Windows 95]
GetBoxMappingHRCRESULT

2.0      [New - Windows 95]

Returns the box indices for a range of symbols.

int GetBoxMappingHRCRESULT( HRCRESULT hrcresult, UINT iSyv, UINT cSyv, UINT FAR * rgi )

Parameters

hrcresult

Handle of a results object.

iSyv

Index of the first symbol of interest in the results object.

cSyv

The number of symbols following iSyv for which box indices are required. Note that the array rgi must be large enough to accommodate this many items of size UINT. A value of 0 is allowed, in which case the function simply returns 0.

rgi

Address of an index array. The array must be large enough to store cSyv indices. This address cannot be NULL.

Return Value

Returns the number of indices actually retrieved, if successful. This can be less than the space allocated in rgi if iSyv indexes an element near the end of the results array, and is 0 if iSyv indexes a nonexistent element; otherwise, returns one of the following negative values:

Constant	Description
HRCR_ERROR	Invalid parameter or other error.
HRCR_MEMERR	Insufficient memory.
HRCR_UNSUPPORTED	The recognizer does not support this function.
Comments

GetBoxMappingHRCRESULT is typically used with boxed input established by SetGuideHRC. If no guide structure has been set, the recognizer will return HRCR_ERROR.

It is possible to allocate a small buffer in rgi and call GetBoxMappingHRCRESULT repeatedly, incrementing the index iSyv each time by the number of indices returned in the previous call until GetBoxMappingHRCRESULT returns 0.

See Also

GetResultsHRC, SetGuideHRC


GetBoxResultsHRC [New - Windows 95]
GetBoxResultsHRC

2.0      [New - Windows 95]

Encapsulates recognizer functionality for boxed input.

int GetBoxResultsHRC( HRC hrc, UINT cAlt, UINT iSyv, UINT cBoxRes, LPBOXRESULTS rgBoxResults, BOOL fGetInkset )

Parameters

hrc

Handle to the HRC object used for the boxed input.

cAlt

Count of alternatives expected in the BOXRESULTS structure. If this parameter is 0, the function returns 0.

iSyv

Index to the starting symbol.

cBoxRes

The count of BOXRESULTS structures that the rgBoxResults array can hold. This parameter must be greater than 0.

rgBoxResults

Address of an array of BOXRESULTS structures.

fGetInkset

Flag to request inksets for each result if TRUE. If FALSE, the recognizer provides no inksets.

Return Value

Returns the count of BOXRESULTS elements returned in the rgBoxResults structure, if successful; otherwise, returns one of the following negative values:

Constant	Description
HRCR_ERROR	Invalid parameter or other error.
HRCR_INVALIDGUIDE	The guide structure is invalid.
HRCR_MEMERR	Insufficient memory.
HRCR_HOOKED	A hook preempted the result.
HRCR_UNSUPPORTED	The recognizer does not support this function.
Comments

GetBoxResultsHRC simplifies the task of boxed recognition by providing character alternatives on a per-box basis in one call.

If fGetInkset is TRUE, the recognizer assigns a valid inkset handle to the hinksetBox member of the BOXRESULTS structure addressed by rgBoxResults. It is the application's responsibility to destroy these inksets with DestroyInkset.

Example

The following code sample gets results for 10 boxes at a time, with five alternatives per box:

HANDLE hMem = GlobalAlloc( GHND, 10 * (sizeof( BOXRESULTS )

 + (5-1) * sizeof( SYV )) );

LPBOXRESULTS rgBoxR = (LPBOXRESULTS)GlobalLock( hMem );

UINT indx = 0;

do

{

   int cRes = GetBoxResultsHRC( hrc, 5, indx, 10, rgBoxR, FALSE );

   .

   .	// Check for errors and use rgBoxR

   .

   indx += (UINT)cRes;

}

while (cRes == 10);

See Also

GetBoxMappingHRCRESULT, GetResultsHRC, DestroyInkset


GetGlobalRC [New - Windows 95]
GetGlobalRC

1.0     2.0      [New - Windows 95]

Queries the current default settings and fills an RC structure with the global values. In version 2.0 of the Pen API, RC is made obsolete by the HRC object.

Note  This function is provided only for compatibility with version 1.0 of the Pen API and will not be supported in future versions.

UINT GetGlobalRC( LPRC lprc, LPSTR lpszDefRecog, LPSTR lpszDefDict, int cbDefDictMax )

Parameters

lprc

Address of an RC structure. This parameter can be NULL.

lpszDefRecog

Address of a character string in which the default recognizer module name is returned. This must be at least 128 bytes long. This parameter can be NULL.

lpszDefDict

Buffer in which the default dictionary path is returned. This path ends with two null characters. This parameter can be NULL.

cbDefDictMax

Size of lpszDefDict buffer to be filled.

Return Value

Returns GGRC_OK if successful; otherwise, the return value may be one of the following values:

Constant	Description
GGRC_PARAMERROR	One or more invalid parameters were detected. The call to GetGlobalRC has no effect.
GGRC_DICTBUFTOOSMALL	The size of the lpszDefDict buffer is not large enough to contain the entire dictionary path. The buffer is filled with as many complete dictionary module names as allowed by the size. The list is terminated by a null string.
Comments

GetGlobalRC fills the RC structure with global values. Values that have no default settings—for example, the bounding rectangle—are set to 0.

An application does not need to call this function to use the default values. When an application initializes an RC structure using InitRC, the system default values are set as the values for the structure members. This function returns the actual current values for RC members. The InitRC function returns the default values, which include placeholder values for some RC members.

See Also

InitRC,  SetGlobalRC,  RC


GetGuideHRC [New - Windows 95]
GetGuideHRC

2.0      [New - Windows 95]

Retrieves the guide structure being used in a recognition context HRC.

int GetGuideHRC( HRC hrc, LPGUIDE lpguide, UINT FAR * lpnFirstVisible )

Parameters

hrc

Handle to the HRC object.

lpguide

Address of a GUIDE structure; all coordinates are in screen coordinates. This parameter cannot be NULL.

lpnFirstVisible

Pointer to first visible character or line, or NULL. For boxed controls, this is the first visible box (leftmost and topmost for left-right, top-down languages like English). For other controls, this is the first visible character position (left-most for English) in a single-line control, and the first visible line (topmost for English) in multiline controls.

If set to NULL, lpnFirstVisible is ignored.

Return Value

Returns HRCR_OK if successful; otherwise, returns one of the following negative values:

Constant	Description
HRCR_ERROR	Invalid parameter or other error.
HRCR_MEMERR	Insufficient memory.
HRCR_UNSUPPORTED	The recognizer does not support this function.
See Also

GUIDE, SetGuideHRC


GetHotspotsHRCRESULT [New - Windows 95]
GetHotspotsHRCRESULT

2.0      [New - Windows 95]

Retrieves the hot spots for a particular symbol.

int GetHotspotsHRCRESULT( HRCRESULT hrcresult, UINT iSyv, LPPOINT lppt, UINT cPnts )

Parameters

hrcresult

Handle of a results object.

iSyv

Index of the symbol in the results object.

lppt

Address of an array of up to MAXHOTSPOT POINT structures.

cPnts

Actual size of lppt array in points.

Return Value

If successful, returns the count of hot spots; otherwise, returns one of the following negative values:

Constant	Description
HRCR_ERROR	Invalid parameter or other error.
HRCR_MEMERR	Insufficient memory.
HRCR_UNSUPPORTED	The recognizer does not support this function.
Comments

Any symbol can have hot spots, but they are usually of interest only for gestures. For example, if the user writes "X" for deletion, the center of the "X"—its hotspot —points to the item to be deleted. Hot spots are returned in tablet coordinates. The maximum number of hot spots allowed is provided in the PENWIN.H constant MAXHOTSPOT. The Microsoft Handwriting Recognizer (GRECO.DLL), supports this function for gesture symbols only.

If cPnts is smaller than the actual number of hot spots, only cPnts points are reported.


GetHRECFromHRC [New - Windows 95]
GetHRECFromHRC

2.0      [New - Windows 95]

Retrieves a handle to the recognizer bound to an HRC object. A recognizer must export this function.

HREC GetHRECFromHRC( HRC hrc )

Parameters

hrc

Handle to the HRC object.

Return Value

If successful, returns the handle to the recognizer used for the HRC object; otherwise, returns NULL.

See Also

CreateCompatibleHRC, InstallRecognizer


GetInksetInterval [New - Windows 95]
GetInksetInterval

2.0      [New - Windows 95]

Retrieves an interval from an inkset.

int GetInksetInterval( HINKSET hinkset, UINT uIndex, LPINTERVAL lpi )

Parameters

hinkset

Handle to an inkset.

uIndex

Zero-based index of an interval or IX_END.

lpi

Pointer to an INTERVAL structure. This can be NULL if the user merely wishes to find out how many intervals are in the inkset.

Return Value

GetInksetInterval returns the number of intervals in the inkset if successful; otherwise, the return value can be one of the following negative values:

Constant	Description
ISR_ERROR	The inkset handle is bad, or a parameter error.
ISR_BADINDEX	The interval index is bad.
ISR_BADINKSET	The inkset has been corrupted or contains bad intervals.
Comments

An application can use GetInksetInterval to enumerate all the intervals in an inkset.

See Also

GetInksetIntervalCount, INTERVAL


GetInksetIntervalCount [New - Windows 95]
GetInksetIntervalCount

2.0      [New - Windows 95]

Returns the number of intervals in an inkset.

int GetInksetIntervalCount( HINKSET hinkset )

Parameters

hinkset

Handle to an inkset.

Return Value

Returns the number of intervals in the inkset is successful; otherwise, the return value can be one of the following negative values:

Constant	Description
ISR_ERROR	The inkset handle is bad, or a parameter error.
ISR_BADINKSET	The inkset has been corrupted or contains bad intervals.
Comments

An application uses GetInksetIntervalCount to determine how many intervals there are to enumerate in an inkset. This function can also be used to verify that an inkset is valid.

See Also

GetInksetInterval


GetInternationalHRC [New - Windows 95]
GetInternationalHRC

2.0      [New - Windows 95]

Retrieves the country, language, script direction, and international preferences from a recognition context HRC object.

int GetInternationalHRC( HRC hrc, UINT FAR * lpuCountry, LPSTR lpszLangCode, UINT FAR * lpfuFlags, UINT FAR * lpuDir )

Parameters

hrc

Handle to the HRC object.

lpuCountry

The country code, or NULL to ignore this value.

lpszLangCode

A buffer large enough to receive a three-letter string (that is, 4 bytes) identifying the language ("enu", "fra", etc.). If set to NULL, lpszLangCode is ignored.

lpfuFlags

A pointer to a flags value or NULL to ignore this value. If GetInternationalHRC returns SIH_ALLANSICHAR in lpfuFlags, it means that the user intends to use the entire ANSI character set. If this is the case, the application should ignore the value returned in lpszLangCode, since all the ANSI-based languages are undifferentiated.

lpuDir

Address of a value for the script direction, or NULL to ignore this value. This value specifies which primary and secondary writing directions are in use. Possible values are:

Constant	Description
SSH_RD	To right and down (English).
SSH_RU	To right and up.
SSH_LD	To left and down (Hebrew).
SSH_LU	To left and up.
SSH_DL	Down and to the left (Chinese).
SSH_DR	Down and to the right (Chinese).
SSH_UL	Up and to the left.
SSH_UR	Up and to the right.
Return Value

Returns HRCR_OK if successful; otherwise, returns one of the following negative values:

Constant	Description
HRCR_ERROR	Invalid parameter or other error.
HRCR_MEMERR	Insufficient memory.
HRCR_UNSUPPORTED	The recognizer does not support this function.
See Also

SetInternationalHRC


GetMaxResultsHRC [New - Windows 95]
GetMaxResultsHRC

2.0      [New - Windows 95]

Gets the maximum number of recognition results that a recognizer can generate in the current handwriting recognition context HRC object.

int GetMaxResultsHRC( HRC hrc )

Parameters

hrc

Handle to the HRC object.

Return Value

If successful, returns the maximum number of recognition results as a positive number; otherwise, returns one of the following negative values:

Constant	Description
HRCR_ERROR	Invalid parameter or other error.
HRCR_MEMERR	Insufficient memory.
Comments

The default maximum number of results a recognizer can return is 1. An application must call SetMaxResultsHRC to set a different maximum value.

See Also

SetMaxResultsHRC


GetPenAppFlags [New - Windows 95]
GetPenAppFlags

2.0      [New - Windows 95]

GetPenAppFlags returns task pen flags cached by RegisterPenApp.

UINT GetPenAppFlags(  )

Return Value

GetPenAppFlags returns the flags set by RegisterPenApp for the current task. It extends and replaces the functionality of the version 1.0 function IsPenAware, which will not be supported in future versions of the Pen API.

Applications written specifically for Windows 95 and later versions automatically get RPA_DEFAULT so that any edit controls created by such applications automatically become pen-aware.

If the registration cache has been destroyed (which indicates PENWIN.DLL has been unloaded), this function returns 0.

See Also

RegisterPenApp, IsPenAware


GetPenAsyncState [New - Windows 95]
GetPenAsyncState

1.0     2.0      [New - Windows 95]

Gets the state of the pen barrel button.

BOOL GetPenAsyncState( UINT wPDK )

Parameters

wPDK

One of the PDK_ values for the barrel buttons. The following table lists the PDK_ values that GetPenAsyncState can query for:

Constant	Description
PDK_BARREL1	Get state of barrel button 1.
PDK_BARREL2	Get state of barrel button 2.
PDK_BARREL3	Get state of barrel button 3.
Return Value

Returns TRUE if the specified barrel button state is currently down; otherwise, the return value is FALSE.


GetPenDataAttributes [New - Windows 95]
GetPenDataAttributes

2.0      [New - Windows 95]

Retrieves information about an HPENDATA object.

int GetPenDataAttributes( HPENDATA hpndt, LPVOID lpvBuffer, UINT uOption )

Parameters

hpndt

Handle to the HPENDATA object.

lpvBuffer

Pointer to a structure whose type depends on uOption, or NULL if the uOption parameter does not require this buffer.

uOption

Specifies the attributes to retrieve. This parameter can be one of the following:

Constant	Description
GPA_MAXLEN	Retrieves the length (in points) of the longest stroke. lpvBuffer is unused and ignored.
GPA_POINTS	Retrieves the total number of points. lpvBuffer is unused and ignored.
GPA_PDTS	Retrieves the PDTS_ bits. lpvBuffer is unused and ignored.
GPA_RATE	Retrieves the sampling rate in samples per second. lpvBuffer is unused and ignored.
GPA_RECTBOUND	Retrieves the bounding rectangle of all pen-down points. lpvBuffer is the address of a RECT structure.
GPA_RECTBOUNDINK	Like GPA_RECTBOUND, retrieves the bounding rectangle of all pen-down points, but inflates the rectangle to accommodate ink width. lpvBuffer is the address of a RECT structure.
GPA_SIZE	Retrieves the size of the pen data memory block in bytes. Because of the potential large size of this value, the return value of the function is not used. Instead, lpvBuffer is the address of a DWORD variable to fill with the size.
GPA_STROKES	Retrieves the total number of strokes, including pen-up strokes. lpvBuffer is unused and ignored.
GPA_TIME	Retrieves the absolute time of creation of the pen data. lpvBuffer is the address of an ABSTIME structure.
GPA_USER	Retrieves the number of user bytes available per stroke: 0, 1, 2, or 4. lpvBuffer is unused and ignored.
GPA_VERSION	Retrieves the version number of the pen data. lpvBuffer is unused and ignored.
Return Value

Returns PDR_OK or an integer value if successful, depending on the uOption parameter.

Comments

GetPenDataAttributes provides enhancements of some of the capabilities of GetPenDataInfo. It also provides additional detailed information taken from the HPENDATA block.

See Also

GetStrokeAttributes, GetPenDataInfo


GetPenDataInfo [New - Windows 95]
GetPenDataInfo

1.0     2.0      [New - Windows 95]

This function retrieves information from an HPENDATA memory block. It is superseded by the GetPenDataAttributes function.

BOOL GetPenDataInfo( HPENDATA hpndt, LPPENDATAHEADER lppdh, LPPENINFO lppeninfo, DWORD dwReserved )

Parameters

hpndt

Handle to a pen data object that receives the pen data information.

lppdh

Address of a PENDATAHEADER structure, or NULL if not required.

lppeninfo

Address of a PENINFO structure, or NULL if not required.

dwReserved

Reserved for future use. Must be set to 0.

Return Value

Returns TRUE if successful. The return value is FALSE if invalid parameters are used, or if the handle to the pen data is invalid, or if the requested PENINFO does not exist in the pen data.

Comments

This function retrieves the header and pen information in the pen data memory block. If lppeninfo is not NULL and the pen data does not contain pen information, the contents of lppeninfo are not changed. The wPndts member in the PENDATAHEADER structure can be checked to see if the HPENDATA object has a PENINFO structure associated with it (a value of PTDS_NOPENINFO indicates not). The amount of data allocated is contained in the cbSizeUsed member of the PENDATAHEADER structure.

See Also

GetPenDataAttributes


GetPenDataStroke [New - Windows 95]
GetPenDataStroke

1.0     2.0      [New - Windows 95]

Returns a pointer to stroke data contained in an HPENDATA memory block previously locked with the BeginEnumStrokes function.

Note  This function is provided only for compatibility with version 1.0 of the Pen API and will not be supported in future versions. Use other services such as GetPenDataAttributes, GetPointsFromPenData, or GetStrokeAttributes to examine an HPENDATA block.

BOOL GetPenDataStroke( LPPENDATA lppd, UINT iStrk, LPPOINT FAR * lplppt, LPVOID FAR * lplpvOem, LPSTROKEINFO lpsi )

Parameters

lppd

Address of the HPENDATA memory block. This parameter is the value returned by a previous call to the BeginEnumStrokes function.

iStrk

Zero-based index of the stroke to retrieve.

lplppt

Address of a pointer to a point. The pointer returned by the function will point to the first point of the stroke inside the pen data object. This parameter can be NULL if point data is not required.

lplpvOem

Address of a void pointer. The pointer returned by the function will point to the OEM data block of the stroke inside the pen data object. The format of the OEM data is specified by the rgoempeninfo member in the PENINFO structure. This parameter can be NULL if OEM data is not required.

lpsi

Address of a STROKEINFO structure. This parameter can be NULL if stroke information is not required.

Return Value

Returns TRUE if successful. If the stroke requested is out of range, the function returns FALSE.

Comments

GetPenDataStroke returns in lpsi a pointer to a STROKEINFO structure created from the stroke referenced by iStrk. The lpsi parameter does not point directly into the HPENDATA memory block.

However, the lplppt argument points to the first point of the stroke inside the HPENDATA block. For a description of how the GetPenDataStroke function has changed in version 2.0 of the Pen API, refer to AppendixA.

Applications must call BeginEnumStrokes before calling GetPenDataStroke. After the last call to GetPenDataStroke, the application must call EndEnumStrokes. Once EndEnumStrokes is called, the data that lplppt and lplpvOem point to is no longer valid.

Under no circumstances should an application modify data directly within an HPENDATA block. Doing so can invalidate other information in the block. To modify an HPENDATA block, use one of the Pen API functions listed in Chapter 4, "The Inking Process."

See Also

BeginEnumStrokes, EndEnumStrokes, GetStrokeAttributes


GetPenHwEventData [New - Windows 95]
GetPenHwEventData

1.0     2.0      [New - Windows 95]

Gets the pen data associated with events in a given range.

Note  This function is provided only for compatibility with version 1.0 of the Pen API and will not be supported in future versions. Use DoDefaultPenInput or GetPenInput instead.

REC GetPenHwEventData( UINT wEventRefBeg, UINT wEventRefEnd, LPPOINT lppt, LPVOID lpvOemData, int cPntMax, LPSTROKEINFO lpsi )

Parameters

wEventRefBeg

Beginning pen event.

wEventRefEnd

Ending pen event.

lppt

Address of a an array of POINT structures. The size of the array must be at least sizeof( POINT ) multiplied by cPntMax.

lpvOemData

Buffer to fill with OEM-specific data. This can be NULL if no data is required.

cPntMax

Maximum number of samples to return.

lpsi

Address of a STROKEINFO structure that receives the stroke information, including the count of points and point state. Also included is the time stamp of the first point returned in the buffer, which is the number of milliseconds that have elapsed since Windows started.

Return Value

Returns REC_OK if successful; otherwise, the return value can be one of the following:

Constant	Description
REC_BUFFERTOOSMALL	The array identified by lppt is not large enough to hold all the points requested.
REC_PARAMERROR	Invalid parameter.
Comments

This function fetches all data collected from the pen event wEventRefBeg up to but not including the pen event wEventRefEnd. If wEventRefBeg equals wEventRefEnd, GetPenHwEventData retrieves the single pen event associated with wEventRefBeg.

The values for wEventRefBeg and wEventRefEnd are obtained by calling the Windows GetMessageExtraInfo function.

This function can be called directly from an application. If it returns REC_BUFFERTOOSMALL, no data is returned and the cPnt member of lpsi contains the number of points between wEventRefBeg and wEventRefEnd. If REC_OK is returned, the cPnt member contains the number of valid points placed in the array at lppt.

See Also

STROKEINFO


GetPenInput [New - Windows 95]
GetPenInput

2.0      [New - Windows 95]

Collects data after StartPenInput has started pen input.

int GetPenInput( HPCM hpcm, LPPOINT lppt, LPVOID lpvOem, UINT fuOemFlags, UINT cPntMax, LPSTROKEINFO lpsi )

Parameters

hpcm

Handle to the current collection. This is the return value from StartPenInput.

lppt

Address of an array of POINT structures. The array must consist of at least cPntMax structures.

lpvOem

The address of a buffer of OEM data associated with each point. This parameter can be NULL if the application does not require OEM data.

fuOemFlags

Flags specifying which OEM data to retrieve. If this parameter is NULL, all OEM data provided by the tablet is returned in the order specified by the rgoempeninfo array in PENINFO.

These flags have an implicit order. For example, if pressure and barrel rotation are specified, cPntMax pairs of these data are returned, in the order [pressure, rotation], [pressure, rotation], and so on.

Constant	Description
PHW_PRESSURE	Retrieve pressure data.
PHW_HEIGHT	Retrieve height data.
PHW_ANGLEXY	Retrieve data pertaining to the x- and y-coordinates.
PHW_ANGLEZ	Retrieve data pertaining to the z-coordinates.
PHW_BARRELROTATION	Retrieve barrel-rotation data.
PHW_OEMSPECIFIC	Retrieve OEM-specific data.
PHW_PDK	Retrieve per-point PDK_ information in OEM data.
cPntMax

The number of POINT structures in the array at lppt. This is the maximum number of points to return and also the maximum number of OEM items the buffer at lpvOem can hold.

lpsi

A pointer to a STROKEINFO structure. This structure receives information about the first point of the collection of points placed into the array at lppt. The cbPnts member contains the packet ID of the first point. All returned points in the collection have the same tip polarity (that is, up or down) as the first point.

Return Value

Returns 0 if there are no points available. If the return value is positive, the value is the number of points copied to the lppt (and, optionally, lpvOem) buffers. Otherwise, the return value is one of the following:

Constant	Description
PCMR_APPTERMINATED	Input has already terminated because the application called StopPenInput. There are no more points to retrieve.
PCMR_EVENTLOCK	An event must be taken out of the queue using the Windows functions PeekMessage or GetMessage before any more points can be retrieved using GetPenInput.
PCMR_INVALIDCOLLECTION	The hpcm handle is invalid because the calling application did not start input with StartPenInput.
PCMR_TERMTIMEOUT	Input has already terminated because the specified time-out period has elapsed.
PCMR_TERMRANGE	Input has already terminated because the pen has left the range of the tablet's zone of sensitivity.
PCMR_TERMPENUP	Input has already terminated because the pen was lifted from the tablet.
PCMR_TERMEX	Input has already terminated because the pen went down in a specified exclusion rectangle or region.
PCMR_TERMBOUND	Input has already terminated because the pen went down outside a specified bounding rectangle or region.
Comments

Once an application initiates pen-input collection by calling StartPenInput, the application then calls the GetPenInput function frequently to retrieve the actual data arriving from the pen device. This can be done by responding to hardware events or by continuously polling.

In the polling model, the application repeatedly calls GetPenInput to get data. It is important for the application to yield periodically; for example, by calling PeekMessage. A fast loop can potentially process the points before the system can collect more. In this case, successive calls to GetPenInput return 0 until the user writes some more. Polling is typically terminated when GetPenInput detects and returns a termination condition specified in StartPenInput.

In the event model, the application calls GetPenInput on receipt of a WM_PENEVENT message. All points up to this event are returned to the caller. An application can retrieve all available data in a short loop, until GetPenInput returns PCMR_EVENTLOCK. The application then falls out of the loop and exits the window procedure. The process begins again when the window procedure is called in response to another WM_PENEVENT message in the application's message queue.

If lpvOem is not NULL, the buffer must be large enough to hold cPntMax OEM data packets. The size of each packet is the width specified in the cbOemData member of the PENINFO structure, plus sizeof( UINT ) if PDK_ values are required.

Example

The following code example gathers more pen input for use by the recognizer. Assume the application has already called StartPenInput and is using the messaging collection model.

POINT	rgPnt[cbBuffer];

STROKEINFO	si;

// ... in WM_PENEVENT message handler:

switch (wParam)

{

.

.

.

case PE_PENUP:

case PE_PENMOVE:

case PE_TERMINATING:

// Get all the points collected since the last message

while ( (iRet = GetPenInput( hpcm, rgPnt, NULL, 0,

 cbBuffer, &si) ) > 0)

{

// Add pen data to recognition context and def process

AddPenInputHRC( vhrc, rgPnt, NULL, 0, &si );

ProcessHRC( vhrc, PH_DEFAULT );

}

break;

See Also

PeekPenInput,  StartPenInput,  PDK_


GetPenResource [New - Windows 95]
GetPenResource

2.0      [New - Windows 95]

The GetPenResource function retrieves a copy of a pen services resource. (Japanese version only.)

HANDLE GetPenResource( WPARAM wParam )

Parameters

wParam

Specifies the pen services resource for which to retrieve a handle. This may be one of the following:

Constant	Description
GPR_CURSPEN	Standard pen cursor.
GPR_CURSCOPY	Copy cursor.
GPR_CURSUNKNOWN	Unknown cursor.
GPR_CURSERASE	Erase cursor.
GPR_BMCRMONO	Monochrome Return bitmap.
GPR_BMLFMONO	Monochrome LineFeed bitmap.
GPR_BMTABMONO	Monochrome Tab bitmap.
GPR_BMDELETE	Delete bitmap.
GPR_BMLENSBTN	Lens buttonface bitmap.
GPR_BMHSPMONO	Hankaku space bitmap (Japanese version only).
GPR_BMZSPMONO	Zenkaku space bitmap (Japanese version only).
Comments

An application can use this function to get a copy of a cursor or bitmap used by pen services. It is the application's responsibility to destroy the object by calling either the DestroyCursor or DeleteObject Windows API.

Return Value

This function returns a handle to an object, depending on the index specified by wParam if successful. Otherwise the return value is NULL.


GetPenMiscInfo [New - Windows 95]
GetPenMiscInfo

1.0     2.0      [New - Windows 95]

Retrieves values pertaining to the pen system.

LONG GetPenMiscInfo( WPARAM wParam, LPARAM lParam )

Parameters

wParam

Specifies the identifier of the pen system value to retrieve. The pen system identifier must be a PMI_ value. See the table below for the possible PMI_ values in wParam.

lParam

Address of storage for data. This must not be NULL. The calling application must ensure that there is sufficient room to store the requested information. The type of storage object that lParam points to depends on wParam, as described in the following table. For each value of wParam in the first column, the second column describes the corresponding requirement for lParam:

wParam constant	LParam description
PMI_BEDIT	lParam is the address of a BOXEDITINFO structure. Boxed edit information.
PMI_CXTABLET	lParam is a far pointer to a UINT value specifying the width of tablet (in units of 0.001 inch) if present; otherwise,  the width of the screen.
PMI_CYTABLET	lParam is a far pointer to a UINT value specifying the height of tablet (in units of 0.001 inch) if present; otherwise,  the height of the screen.
PMI_INDEXFROMRGB	lParam is a far pointer to a DWORD value. On entry, lParam is the address of an RGB ink color value. On return, the low-order word of lParam is replaced with an index in the range 0 to 15 for the closest standard ink color and the high-order word is 0.
PMI_ENABLEFLAGS	lParam is a far pointer to a WORD value containing a flag describing whether certain Pen API features are enabled. The flags can be a combination of the following values: PWE_AUTOWRITE   Enable pen functionality where the I-Beam cursor is present. PWE_ACTIONHANDLES   Enable action handles in controls. PWE_INPUTCURSOR   Show cursor while writing. PWE_LENS   Enable pop-up letter guides (that is, the lens).
PMI_PENTIP	lParam is the address of a PENTIP structure.
PMI_RGBFROMINDEX	lParam is the address of a DWORD value. On entry, lParam is the address of an index in the range 0 to 15; on return, this value at this address is replaced with the standard RGB ink color value.
wParam constant	LParam description
PMI_SYSFLAGS	lParam is a far pointer to a WORD value containing a flag describing which pen system components are loaded. The flags can be a combination of the following values: PWF_RC1   Support available for Pen API version 1.0 Recognition Context (RC) and associated functions. PWF_PEN   Pen/tablet hardware is present. PWF_INKDISPLAY   Ink-compatible display driver is present. PWF_RECOGNIZER   System recognizer is present. PWF_BEDIT   Boxed edit (bedit) control is available. PWF_HEDIT   Handwriting edit (hedit) control is available. PWF_IEDIT   Ink edit (iedit) control is available. PWF_ENHANCED   Enhanced features, including gesture support and 1 millisecond timing, are available. PWF_FULL   All components listed above are present..
PMI_SYSREC	lParam is a far pointer to an HREC value which is the handle of the system recognizer, if present.
PMI_TICKREF	lParam is the address of an ABSTIME structure indicating  the absolute reference time that the system uses to calculate time-stamps for strokes in pen data objects and inkset
PMI_TIMEOUT	lParam is a far pointer to a UINT value indicating time-out value to end hand-writing input, in milliseconds.
PMI_TIMEOUTGEST	lParam is a far pointer to a UINT value indicating time-out value to end a gesture, in milliseconds.
PMI_TIMEOUTSEL	lParam is a far pointer to a UINT value indicating  the time-out value in milli-seconds for press-and-hold gesture. The range of permissible values is 0 to 5000. If press-and-hold has been disabled, this value is 65,535.
Return Value

The return value is PMIR_OK if successful; otherwise it is one of the following negative error values:

Constant	Description
PMIR_INDEX	wParam is out of range.
PMIR_NA	Support for this value of wParam is not available.
PMIR_VALUE	lParam is NULL or a invalid pointer.
Comments

The information type returned varies depending on the index. Note that if a UINT is expected, for example, it is an error to provide the address of a DWORD variable without explicitly setting the HIWORD to 0. This function only sets the LOWORD in this case, and since the variable is usually declared on the stack, there would be an unknown value in the HIWORD. See the examples below.

If wParam is PMI_INDEXFROMRGB or PMI_RGBFROMINDEX, the standard pen-tip color table is as follows:

00  black       RGB(  0,   0,   0)

01  dark blue   RGB(  0,   0, 127)

02  dark green  RGB(  0, 127,   0)

03  dark cyan   RGB(  0, 127, 127)

04  dark red    RGB(127,   0,   0)

05  purple      RGB(127,   0, 127)

06  brown       RGB(127, 127,   0)

07  gray        RGB(127, 127, 127)

08  light gray  RGB(192, 192, 192)

09  blue        RGB(  0,   0, 255)

10  green       RGB(  0, 255,   0)

11  cyan        RGB(  0, 255, 255)

12  red         RGB(255,   0,   0)

13  magenta     RGB(255,   0, 255)

14  yellow      RGB(255, 255,   0)

15  white       RGB(255, 255, 255)

Example

The following code sample retrieves the timeout and pen tip:

UINT uTimeout;

PENTIP tip;

GetPenMiscInfo( PMI_TIMEOUT, (LPARAM)(UINT FAR *)&utimeout );

GetPenMiscInfo( PMI_PENTIP, (LPARAM)(LPPENTIP)&tip );

Note that the following is an error, since the HIWORD is undefined:

DWORD dwTimeout;

GetPenMiscInfo( PMI_TIMEOUT, (LPARAM)&dwtimeout );	  // Wrong!

See Also

SetPenMiscInfo,  PMI_


GetPointsFromPenData [New - Windows 95]
GetPointsFromPenData

1.0     2.0      [New - Windows 95]

Retrieves a specified range of points.

BOOL GetPointsFromPenData( HPENDATA hpndt, UINT iStrk, UINT iPnt, UINT cPnts, LPPOINT lppt )

Parameters

hpndt

Handle to a pen data object.

iStrk

The zero-based stroke index from which points are retrieved.

iPnt

First point to retrieve from the specified stroke.

cPnts

Number of points to retrieve. If this value is 0, the function returns TRUE.

lppt

Address of buffer to fill with points.

Return Value

Returns TRUE if successful, or FALSE if the requested points are out of range.

Comments

GetPointsFromPenData performs a function similar to GetPenDataStroke in that it retrieves information from an HPENDATA memory block. But GetPointsFromPenData copies the required data to buffers supplied by the application, rather than simply returning pointers to the original data in the global heap.

An application can also request a copy of a particular subset of points within a stroke. In this case, iPnt identifies the first point and cPnts is the number of points to retrieve. This allows an application to digest the points in an HPENDATA block a few at a time to avoid having to allocate a large block of memory for the entire set of points.

GetPointsFromPenData returns the last point in a stroke if the iPnt argument is set to a value larger than the total number of points in the stroke. In the same manner, the function returns the points of the last stroke if iStrk exceeds the total number of strokes in the HPENDATA block. If the count of points to return is 1 and iPnt is beyond the last point in the stroke, the function returns the last point in the stroke.

See Also

GetPenDataStroke


GetResultsHRC [New - Windows 95]
GetResultsHRC

2.0      [New - Windows 95]

Retrieves results from a recognition context HRC. A recognizer must export this function.

int GetResultsHRC( HRC hrc, UINT uType, LPHRCRESULT rghrcresults, UINT cResults )

Parameters

hrc

Handle to the HRC object.

uType

Specifies the type of expected results. This can be one of the following values:

Constant	Description
GRH_ALL	Return all results.
GRH_GESTURE	Return results of type gesture only.
GRH_NONGESTURE	Return all results not of type gesture.
rghrcresults

Address of an array of HRCRESULT objects.

cResults

The size of the rghrcresults array, in objects. The actual size in bytes can be calculated by multiplying cResults by the size of HRCRESULT. This parameter must be greater than 0.

Return Value

Returns the actual number of results returned if successful. This can be 0; otherwise, returns one of the following negative values:

Constant	Description
HRCR_ERROR	Invalid parameter or other error.
HRCR_HOOKED	A hook preempted the result.
HRCR_MEMERR	Insufficient memory.
Comments

The actual number of results returned by this function may be less than the number specified by cResults. It is also less than or equal to the count specified at the creation of hrc by the cMaxResults parameter in SetMaxResultsHRC, regardless of the size of the rghrcresults array.

A return value of 0 indicates that the recognizer was not able to recognize any of the input, even if coerced by a word list set into the HRC. A recognizer should never return a result consisting entirely of SYV_UNKNOWN symbols.

The calling application must explicitly destroy each valid result using DestroyHRCRESULT. However, if the return value is 0 or negative, the contents of the rghrcresults array are undefined (though not NULL) and DestroyHRCRESULT must not be called.

See Also

DestroyHRCRESULT


GetStrokeAttributes [New - Windows 95]
GetStrokeAttributes

2.0      [New - Windows 95]

Retrieves information about a stroke in an HPENDATA object.

int GetStrokeAttributes( HPENDATA hpndt, UINT iStrk, LPVOID lpvBuffer, UINT uOption )

Parameters

hpndt

Handle to the HPENDATA object, which must not be compressed.

iStrk

Zero-based stroke index. If there are no strokes in the pen data, an index of 0 can be used to retrieve the default attributes for the pen data. A value of IX_END specifies the last available stroke in the pen data.

lpvBuffer

Pointer to a structure whose type depends on uOption, or NULL if the uOption parameter does not require this buffer.

uOption

Specifies the attributes to retrieve. This parameter has one of the following values:

Constant	Description
GSA_DOWN	Retrieve the up/down state of the pen tip for this stroke. Returns 1 if the stroke is a down-stroke or 0 if it is an up-stroke. lpvBuffer is unused and ignored.
GSA_PENTIP	Retrieve the pen-tip characteristics (color, width, nib) used by the stroke specified by iStrk. lpvBuffer is a pointer to a PENTIP structure. Return value is PDR_OK.
GSA_PENTIPCLASS	Retrieve the pen-tip characteristics (color, width, nib), if any, for the class of strokes of which the stroke specified by iStrk is a member. lpvBuffer is a pointer to a PENTIP structure. Return value is PDR_OK.
GSA_RECTBOUND	Retrieve the bounding rectangle of the specified stroke. lpvBuffer is a pointer to a RECT structure. Return value is PDR_OK.
GSA_SELECT	Retrieve the selection status of the specified stroke. lpvBuffer is unused and ignored. Returns a nonzero value if the stroke is selected; otherwise, the return value is 0.
GSA_SIZE	Retrieve size of stroke in points and bytes. lpvBuffer is a pointer to a double-word value, or NULL. LOWORD(*(LPDWORD)lpvBuffer) is the size in points, and HIWORD(*(LPDWORD)lpvBuffer) is the size in bytes. Return value is PDR_OK.
GSA_TIME	Retrieve the absolute time of the stroke. lpvBuffer is a pointer to an ABSTIME structure; it cannot be NULL. The sec field specifies the number of seconds since Jan 1, 1970, and the ms field specifies the number of milliseconds offset from that time to the beginning of the stroke. Return value is PDR_OK.
GSA_USER	Retrieve the user value, if any, for the stroke. lpvBuffer is a pointer to a double-word value, or NULL. Returns the number of bytes of user data available in the stroke: 0, 1, 2, or 4.
GSA_USERCLASS	Retrieve the user value, if any, for the class of strokes of which the stroke specified by iStrk is a member. lpvBuffer is a pointer to a double-word value, or NULL. The return value is 4 because the user value in the strokes class table is a doubleword value.
Return Value

Returns PDR_OK or an integer value if successful, as described for the uOption parameter. If an error occurs, returns one of the following:

Constant	Description
PDR_COMPRESSED	Pen data is compressed.
PDR_ERROR	Parameter or other unspecified error.
PDR_MEMERR	Memory error.
PDR_PNDTERR	Invalid pen data.
PDR_STRKINDEXERR	Invalid stroke index.
PDR_TIMESTAMPERR	Timing information was removed.
PDR_VERSIONERR	Could not convert old pen data.
See Also

CreatePenDataEx, GetStrokeTableAttributes, SetStrokeAttributes, SetStrokeTableAttributes, PENTIP


GetStrokeTableAttributes [New - Windows 95]
GetStrokeTableAttributes

2.0      [New - Windows 95]

Retrieves information about a stroke's class from the table in the PENDATAHEADER of an HPENDATA object.

int GetStrokeTableAttributes( HPENDATA hpndt, UINT iTblEntry, LPVOID lpvBuffer, UINT uOption )

Parameters

hpndt

Handle to the HPENDATA object, which must not be compressed.

iTblEntry

Zero-based table index to the class entry in the pen data header.

lpvBuffer

Pointer to a structure whose type depends on uOption, or NULL if the uOption parameter does not require this buffer.

uOption

Specifies the attributes to retrieve. This parameter can be one of the following:

Constant	Description
GSA_PENTIPTABLE	Retrieve the pen-tip characteristics (color, width, nib) of the class of strokes specified by iTblEntry. lpvBuffer is a pointer to a PENTIP structure. Return value is the number of strokes using this class.
GSA_SIZETABLE	Retrieve the number of entries in the stroke class table. iTblEntry and lpvBuffer are unused and ignored. Return value is the number of classes used in the stroke class table.
GSA_USERTABLE	Retrieve the user value, if any, of the class of strokes specified by iTblEntry. lpvBuffer is a pointer to a doubleword value, or NULL. The number of bytes that are valid in lpvBuffer depends on flags set in CreatePenDataEx. This number is returned by the function, and can be 0 (no user value), 1 (byte value),  2 (word value), or 4 (doubleword value). Return value  is 4, because the user value in the stroke class table  is a doubleword value.
Return Value

Returns an integer if successful, depending on the value of uOption, as described above. If an error occurs, returns one of the following:

Constant	Description
PDR_COMPRESSED	Pen data is compressed.
PDR_ERROR	Parameter or other unspecified error.
PDR_MEMERR	Memory error.
PDR_PNDTERR	Invalid pen data.
PDR_VERSIONERR	Could not convert old pen data.
See Also

CreatePenDataEx, GetStrokeAttributes, SetStrokeAttributes, SetStrokeTableAttributes, PENTIP


GetSymbolCount [New - Windows 95]
GetSymbolCount

1.0     2.0      [New - Windows 95]

Returns the number of symbol strings contained in a symbol graph SYG.

int GetSymbolCount( LPSYG lpsyg )

Parameters

lpsyg

Address of the symbol graph.

Return Value

Returns the number of possible symbol strings that can be generated from the symbol graph. Returns −1 for any graph that can generate more than 32,767 symbol strings, or if there is a parameter error.

Example

For example, if the symbol graph pointed to by lpsyg is

ex {a | u} mple

GetSymbolCount returns the value 2 because the graph contains two symbol strings ("example" and "exumple").

See Also

EnumSymbols, FirstSymbolFromGraph, GetSymbolMaxLength SYG, SYV_


GetSymbolCountHRCRESULT [New - Windows 95]
GetSymbolCountHRCRESULT

2.0      [New - Windows 95]

Retrieves the count of symbols available in a recognition result. A recognizer must export this function.

int GetSymbolCountHRCRESULT( HRCRESULT hrcresult )

Parameters

hrcresult

Handle of a results object.

Return Value

Returns the count of symbols if successful; otherwise, returns one of the following negative values:

Constant	Description
HRCR_ERROR	Invalid parameter or other error.
HRCR_MEMERR	Insufficient memory.
Comments

This function is typically called before GetSymbolsHRCRESULT to determine the size of a buffer required to store the symbol values returned in a recognition result. To calculate the size of the buffer, multiply the value returned by this function by sizeof( SYV ).

See Also

GetSymbolsHRCRESULT, SYV_


GetSymbolMaxLength [New - Windows 95]
GetSymbolMaxLength

1.0     2.0      [New - Windows 95]

Returns the length of the longest symbol string contained in a symbol graph SYG.

int GetSymbolMaxLength( LPSYG lpsyg )

Parameters

lpsyg

Address of the symbol graph.

Return Value

Returns the number of symbols in the longest symbol string that can be generated from the symbol graph, or −1 if there is a parameter error.

Example

For example, if the symbol graph pointed to by lpsyg is

ab {c | de} f

GetSymbolMaxLength returns 5 because the longest string is "abdef".

See Also

EnumSymbols, FirstSymbolFromGraph, SYG, SYV_


GetSymbolsHRCRESULT [New - Windows 95]
GetSymbolsHRCRESULT

2.0      [New - Windows 95]

Retrieves an array of symbol values corresponding to a recognition result. A recognizer must export this function.

int GetSymbolsHRCRESULT( HRCRESULT hrcresult, UINT iSyv, LPSYV rgsyv, UINT cSyv )

Parameters

hrcresult

Handle of a results object.

iSyv

Index of the first symbol of interest in the results object.

rgsyv

Address of a buffer in which to put the symbols. The array must be large enough to store cSyv symbols.

cSyv

The size of rgsyv in symbols (not bytes). This is the number of symbols to be returned. A value of 0 is legal, in which case the function simply returns 0.

Return Value

Returns the count of symbols copied, if successful; otherwise, returns one of the following negative values:

Constant	Description
HRCR_ERROR	Invalid parameter or other error.
HRCR_MEMERR	Insufficient memory.
Comments

It is possible to allocate a small buffer in rgsyv and call this function repeatedly, incrementing the index iSyv each time by the number of symbols returned in the previous call, until the function returns 0.

Example

The following example gets a character result, using a small buffer:

#define CBCHBUF 1024	// Char buffer

#define CSYVMAX 32	// Relatively small symbol chunk

HRC	  vhrc; 	      // Handle to a handwriting context

HRCRESULT vhrcresult;	      // Handle to a recognition result

SYV	  vrgsyv[CSYVMAX];    // Symbol result buffer

char	  vrgcBuff[CBCHBUF];  // Buffer for recognition results

.

.	     // Code that creates HRC, gets input, etc....

.

EndPenInputHRC( vhrc );     // Tell recognizer no more ink

ProcessHRC( vhrc, PH_MAX ); // Finish recognition

.

.	     // Retrieve a handle to the results

.

if (GetResultsHRC( vhrc, &vhrcresult, 1 ) > 0)

{

int i = 0, cSyv;

// Retrieve some symbols

while ((cSyv = GetSymbolsHRCRESULT( vhrcresult,

i, vrgsyv, CSYVMAX )) > 0)

{

if (i + cSyv + 1 > CBCHBUF) // Don't overflow buffer

cSyv = CBCHBUF - i - 1;

if (cSyv > 0)	    // Still have something?

{

SymbolToCharacter( vrgsyv, cSyv, vrgcBuff + i, NULL );

i += cSyv;

}

if (i + 1 >= CBCHBUF)

break;

}

vrgcBuff[i] = chNull;	 // Terminate string

}

DestroyHRCRESULT( vhrcresult );  // We're finished with result

vhrcresult = NULL;

DestroyHRC( vhrc );	 // Finished with this HRC session

vhrc = NULL;

See Also

GetSymbolCountHRCRESULT, SYV_


GetVersionPenWin [New - Windows 95]
GetVersionPenWin

1.0     2.0      [New - Windows 95]

Retrieves the Pen API version number.

UINT GetVersionPenWin(  )

Return Value

The low-order byte of the return value specifies the major (version) number. The high-order byte specifies the minor (revision) number.


GetWordlistCoercionHRC [New - Windows 95]
GetWordlistCoercionHRC

2.0      [New - Windows 95]

Retrieves the current word list coercion setting in a handwriting-recognition context HRC.

int GetWordlistCoercionHRC( HRC hrc )

Parameters

hrc

Handle to the HRC object.

Return Value

If successful, returns one of the following values:

Constant	Description
SCH_ADVISE	The word list is a hint to the recognizer, and results are not strongly coerced to match the word list.
SCH_FORCE	If results do not match the word list, the closest fit is returned.
SCH_NONE	Do not coerce. This flag can be used to turn off a previous request.
Otherwise, returns one of the following negative values:

Constant	Description
HRCR_ERROR	Invalid parameter or other error.
HRCR_MEMERR	Insufficient memory.
HRCR_UNSUPPORTED	The recognizer does not support this function.
See Also

SetWordlistCoercionHRC


GetWordlistHRC [New - Windows 95]
GetWordlistHRC

2.0      [New - Windows 95]

Retrieves a word list from a recognition context HRC.

int GetWordlistHRC( HRC hrc, LPHWL lphwl )

Parameters

hrc

Handle to the HRC object.

lphwl

Address of a handle to a word list. The recognizer sets the handle to NULL if the recognition context does not contain a word list.

Return Value

Returns HRCR_OK if successful; otherwise, returns one of the following negative values:

Constant	Description
HRCR_ERROR	Invalid parameter or other error.
HRCR_MEMERR	Insufficient memory.
HRCR_UNSUPPORTED	The recognizer does not support this function.
Comments

An HRC can be configured for only one word list at a time. This is independent of the recognizer's dictionary, which can be manipulated through the EnableSystemDictionaryHRC function.

For a description of word lists and how a recognizer uses them, see "Configuring the HRC" in Chapter 5, "The Recognition Process."

See Also

SetWordlistHRC


HitTestPenData [New - Windows 95]
HitTestPenData

2.0      [New - Windows 95]

Determines if a given point lies on or near the pen-down strokes contained in an HPENDATA object.

int HitTestPenData( HPENDATA hpndt, LPPOINT lppt, UINT dThresh, UINT FAR* lpiStrk, UINT FAR* lpiPnt )

Parameters

hpndt

Handle to the HPENDATA object. HitTestPenData does not alter the data in the HPENDATA object.

lppt

Address of a POINT structure containing the point to test.

dThresh

Threshold around the point given in lppt. The point lies at the center of a square with sides of length dThresh. If HitTestPenData finds a point in the HPENDATA object that lies in the square, it indicates a "hit." dThresh must have the same scaling units as the points in the HPENDATA or the result will not be correct. If dThresh is 0, HitTestPenData assumes a default threshold value of 3.

lpiStrk

Stroke index from which to begin testing. After HitTestPenData returns from a successful test, the variable that lpiStrk points to contains the index of the hit stroke.

lpiPnt

Point index from which to begin testing. After HitTestPenData returns from a successful test, the variable that lpiPnt points to contains the index of the hit point in the stroke indicated by lpiStrk.

Return Value

Returns one of the following if successful:

Constant	Description
PDR_HIT	The point hits (intersects) the pen data or falls within the provided threshold around a particular point in the pen data as specified by the stroke and the point indices. The stroke and point values are returned in lpiStrk and lpiPnt, respectively.
PDR_NOHIT	The point does not hit (intersect) the pen data nor does it fall within the provided threshold around a particular point in the pen data as specified by the stroke and the point indices.
Otherwise, the function returns one of the following negative values:

Constant	Description
PDR_COMPRESSED	Pen data is compressed.
PDR_ERROR	Parameter or other unspecified error.
PDR_MEMERR	Memory error.
PDR_PNDTERR	Invalid pen data.
PDR_PNTINDEXERR	Invalid point index.
PDR_STRKINDEXERR	Invalid stroke index.
PDR_VERSIONERR	Could not convert old pen data.
Comments

HitTestPenData checks whether the point specified by lppt falls within the threshold specified by dThresh around a point in the pen data, depending on the zero-based starting stroke and point indices specified by lpiStrk and lpiPnt. This function tests only down strokes in the pen data. If lpiStrk is greater than the number of strokes in the pen data, testing starts from the first stroke.

Similarly, if lpiPnt is greater than the number of points in the stroke, testing starts from the first point in that stroke. The first point in the first stroke (from the specified indices) that meets the test condition is returned via lpiPnt and lpiStrk, respectively.

In any case, HitTestPenData accounts for the width of the ink trail. If the value given in dThresh is less than the ink width, HitTestPenData ignores the specified value of dThresh and instead uses the ink width as the threshold.

HitTestPenData does not consider pen-up strokes.


InitRC [New - Windows 95]
InitRC

1.0     2.0      [New - Windows 95]

Initializes an RC structure with default values.

Note  This function is provided only for compatibility with version 1.0 of the Pen API, and will not be supported in future versions.

void InitRC( HWND hwnd, LPRC lprc )

Parameters

hwnd

Handle to a window.

lprc

Address of the RC structure to initialize.

Return Value

This function does not return a value.

Comments

InitRC serves little purpose in applications that conform to version 2.0 of the Pen API. Under version 2.0, a recognizer maintains an HRC object, which makes the RC structure obsolete.

For suggestions on how to update a version 1.0 application to remove services that rely on RC, see the section "The RC Structure" in Appendix A.

InitRC initializes an RC structure with default values, many of which come from the global RC structure. The application can use the initialized RC structure when calling the Recognize function. Although an application can change any of these values, it should be careful about changing those items that can be set by the user through the Windows Control Panel.

InitRC sets the bounding rectangle to the client area of the window identified by hwnd. The bounding rectangle is valid only until the window is resized or moved. When this occurs, the application must again call InitRC to update the rectBound member of the RC structure or correct rectBound manually. If the window handle hwnd is NULL, the bounding rectangle and hwnd remain uninitialized. The application must set the hwnd member to a valid window before calling Recognize or RecognizeData.

The following table describes the default values used to initialize the RC structure. Values not listed in the table come from the global RC. Some of the global default values can be modified by the user in Control Panel.

Value	Description
rc.alc	ALC_DEFAULT. The function uses the complete alphabet and all gestures. The exact character set depends on the recognizer.
rc.lRcOptions	Zero.
rc.hwnd	hwnd (the first argument of InitRC).
rc.wResultMode	RRM_COMPLETE.
rc.rectBound	(0,0,0,0) or client rectangle of hwnd if hwnd is not NULL.
rc.lPcm	PCM_ADDDEFAULTS, or PCM_ADDDEFAULTS | PCM_RECTBOUND if hwnd is not NULL.
rc.rectExclude	(0,0,0,0).
rc.guide	(0,0,0,0,0,0,0).
rc.wRcOrient	RCOR_NORMAL.
rc.wRcDirect	0x0103
Members the user can change through the system Control Panel are filled with values indicating that the system default should be used. These placeholder values are RC_WDEFAULT or RC_LDEFAULT, depending on whether the member is a UINT or LONG value. During the processing of ProcessWriting, Recognize, or RecognizeData, these values are replaced with the current system defaults before the RC structure is passed to the recognizer. If the PCM_ADDDEFAULTS flag is set in lPcm, the values of the lPcm member in the global RC are combined with the current lPcm values with OR operators at the time the recognizer is called. If the high bit is set in wRcPreferences, the values of the wRcPreferences member in the global RC are combined with the current wRcPreferences values with bitwise-OR operators at the time the recognizer is called.

The following table gives the default values for the members of the RC structure:

Value	Description
rc.hrec	RC_WDEFAULT
rc.lpfnYield	RC_LDEFAULT
rc.lpUser	RC_LDEFAULT
rc.wCountry	RC_WDEFAULT
rc.wIntlPreferences	RC_WDEFAULTFLAGS
rc.lpLanguage	RC_LDEFAULT
rc.rglpdf	RC_LDEFAULT
rc.wTryDictionary	RC_WDEFAULT
rc.clErrorLevel	RC_WDEFAULT
rc.wTimeOut	RC_WDEFAULT
rc.wRcPreferences	RC_WDEFAULTFLAGS
rc.nInkWidth	RC_WDEFAULT
rc.rgbInk	RC_LDEFAULT
rc.alcPriority	ALC_NOPRIORITY
rc.rgbfAlc	Array initialized to 0
The RC structure pointed to in the RCRESULT structure is a copy of the original RC structure passed as a parameter to Recognize. In the copy, default values are replaced. All coordinates are in the tablet coordinate system and the lRcOptions member has the RCO_TABLETCOORD flag set.

See Also

Recognize,  RecognizeData,  RC,  ALC_,  PCM_,  RCO_


InsertPenData [New - Windows 95]
InsertPenData

2.0      [New - Windows 95]

Merges two blocks of pen data at the specified stroke index.

int InsertPenData( HPENDATA hpndtDst, HPENDATA hpndtSrc, UINT iStrk )

Parameters

hpndtDst

Handle of the pen data object to merge into. When this function returns, this is the handle of the merged data.

hpndtSrc

Handle of the pen data object to merge from.

iStrk

Stroke index. The merge operation occurs before this index. This parameter can also be IX_END to append hpndtSrc to the end of hpndtDst.

Return Value

Returns PDR_OK if successful; otherwise, the return value is one of the following negative values:

Constant	Description
PDR_COMPRESSED	Pen data is compressed.
PDR_ERROR	Parameter or other unspecified error.
PDR_MEMERR	Out of memory.
PDR_OEMDATAERR	Incompatible OEM data in the two pen data objects.
PDR_STRKINDEXERR	Invalid stroke index.
PDR_TIMESTAMPERR	Incompatible time fields in the two pen data objects.
PDR_USERDATAERR	Incompatible user space in the two pen data objects.
PDR_VERSIONERR	Could not convert old pen data object.
Comments

InsertPenData merges two blocks of pen data starting at the zero-based stroke index specified by iStrk of the destination pen data.

The blocks of pen data to be merged must be compatible. The calling application should ensure that the blocks of data are in the same scaling mode. The user space, if present, should be of the same size. OEM data, if present, must be compatible and of the same type. The application can use TrimPenData to delete certain information from either the source or the destination HPENDATA object to make it compatible. If hpndtDst has timing information and hpndtSrc does not, the merge fails. However, if hpndtDst does not have timing information and hpndtSrc does have it, the timing is stripped from hpndtSrc.

For a description of timing information, see "The HINKSET Object" in Chapter 4, "The Inking Process."

See Also

InsertPenDataStroke, InsertPenDataPoints, MetricScalePenData, TrimPenData, CreatePenDataEx


InsertPenDataPoints [New - Windows 95]
InsertPenDataPoints

2.0      [New - Windows 95]

Inserts points into an existing HPENDATA object.

int InsertPenDataPoints( HPENDATA hpndt, UINT iStrk, UINT iPnt, UINT cPnts, LPPOINT lppt, LPVOID lpvOem )

Parameters

hpndt

Handle to an HPENDATA object.

iStrk

Zero-based index of the stroke into which the points are inserted. If this value is IX_END, the points are inserted in the last stroke.

iPnt

Zero-based index of the point in the stroke before which the points are inserted. If this value is IX_END, the points are appended to the end of the stroke.

cPnts

Total number of points to be inserted. If this is 0, the function returns PDR_OK without taking any other action.

lppt

Address of an array of POINT structures containing the points to be inserted.

lpvOem

Address of a buffer containing the OEM data to be inserted. This value can be NULL only if the HPENDATA object does not have OEM data or a PENINFO structure.

Return Value

Returns PDR_OK if successful; otherwise, the return value can be one of the following negative values:

Constant	Description
PDR_COMPRESSED	Pen data is compressed.
PDR_ERROR	Parameter or other unspecified error.
PDR_MEMERR	Out of memory.
PDR_STRKINDEXERR	Invalid stroke index.
PDR_PNTINDEXERR	Invalid point index.
PDR_VERSIONERR	Could not convert old pen data object.
Comments

InsertPenDataPoints inserts points into an existing stroke of the specified pen data object. It does not create a new stroke. (Use the InsertPenDataStroke function to insert new strokes into the pen data object.) The stroke attributes are not affected by the points added to the stroke.

The calling application must ensure that lppt and lpvOem are valid and that the points are in the same scale as those of the pen data object. InsertPenDataPoints performs no automatic scaling of the points.

InsertPenDataPoints does not make any timing adjustments after adding points. This can affect recognition accuracy and should be used judiciously.

For a description of timing information, see "The HINKSET Object" in Chapter 4, "The Inking Process."

See Also

AddPointsPenData, ExtractPenDataPoints, InsertPenData, InsertPenDataStroke, RemovePenDataStrokes


InsertPenDataStroke [New - Windows 95]
InsertPenDataStroke

2.0      [New - Windows 95]

Inserts a stroke into an existing HPENDATA object.

int InsertPenDataStroke( HPENDATA hpndt, UINT iStrk, LPPOINT lppt, LPVOID lpvOem, LPSTROKEINFO lpsiNew )

Parameters

hpndt

Handle to the HPENDATA object that receives the inserted strokes.

iStrk

Zero-based index of the stroke at which the new stroke is to be inserted. If this value is IX_END, the stroke is appended at the end of the HPENDATA memory block.

lppt

Pointer to a buffer containing the points to be inserted.

lpvOem

Pointer to a buffer of OEM data. This value can be NULL only if the pen data object does not have OEM data or a PENINFO structure.

lpsiNew

Pointer to the STROKEINFO structure containing information about the stroke.

Return Value

Returns PDR_OK if successful; otherwise, the return value can be one of the following negative values:

Constant	Description
PDR_COMPRESSED	Pen data is compressed.
PDR_ERROR	Parameter or other unspecified error.
PDR_MEMERR	Out of memory.
PDR_STRKINDEXERR	Invalid stroke index.
PDR_TIMESTAMPERR	Timing error.
PDR_VERSIONERR	Could not convert old pen data object.
Comments

InsertPenDataStroke inserts an entire stroke into an HPENDATA object. Use InsertPenDataPoints to insert points into a particular stroke.

The inserted stroke assumes the default pen-tip attributes. SetStrokeAttributes should be called after inserting the stroke to change such stroke attributes as the pen-tip characteristics or user data.

The calling application must ensure that lppt and lpvOem are valid, and that the points in the stroke that is being added have compatible scaling modes.

Attempting to insert an empty stroke simply returns PDR_OK.

See Also

AddPointsPenData, ExtractPenDataPoints, InsertPenDataPoints, RemovePenDataStrokes, STROKEINFO


InstallRecognizer [New - Windows 95]
InstallRecognizer

1.0     2.0      [New - Windows 95]

Loads and initializes a specified recognizer.

HREC InstallRecognizer( LPSTR lpszRecogName )

Parameters

lpszRecogName

Name of recognizer to load. If lpszRecogName is NULL, the default recognizer is loaded. (An application should not set lpszRecogName to NULL, because Windows automatically loads the default recognizer on initialization.)

Return Value

Returns a handle to a recognizer if successful; otherwise, returns NULL.

Comments

The recognizer's name is the name of the DLL to be loaded. Windows searches for the recognizer file according to the standard rules for searching for a DLL—that is, it first searches the current directory, then the Windows directory, the system subdirectory, the PATH directories, and so forth. The procedure fails if the library cannot be found, the load fails, or the loaded DLL is not a valid recognizer. The recognizer may decline to load if it requires hardware information such as pen pressure that the pen device cannot provide.

An application should not load the default recognizer. All recognizers installed by an application must be uninstalled by a call to UninstallRecognizer before the application terminates.

After loading a recognizer library, the system calls the recognizer's ConfigRecognizer function with the subfunction WCR_INITRECOGNIZER.

An application can load a recognizer with a call to LoadLibrary instead of InstallRecognizer. However, the application must first link with an import library derived from the recognizer DLL. The recognizer's import library must appear in the library section of the LINK command line before PENWIN.LIB. This forces the application's calls to pass directly to the recognizer's exported recognition functions instead of the system.

This procedure may facilitate debugging the recognizer, but otherwise serves no purpose. It prevents use of other recognizers, including the system default recognizer. For a discussion of import libraries, refer to the section on the IMPLIB utility described in the Environment and Tools manual of the Microsoft VisualC++ documentation.

See Also

ConfigRecognizer, ConfigHREC, UninstallRecognizer


IsPenAware [New - Windows 95]
IsPenAware

1.0     2.0      [New - Windows 95]

Checks the capability of an application to handle pen events by returning cached task pen flags.

Note  This function is provided only for compatibility with version 1.0 of the Pen API and will not be supported in future versions. Use GetPenAppFlags instead.

UINT IsPenAware(  )

Return Value

Returns the registration flags word set by a previous call to the SetPenAppFlags function. If SetPenAppFlags has not been called, IsPenAware returns 0.

See Also

GetPenAppFlags, SetPenAppFlags


IsPenEvent [New - Windows 95]
IsPenEvent

1.0     2.0      [New - Windows 95]

Checks whether a mouse event was generated by the pen driver.

BOOL IsPenEvent( UINT message, LONG lExtraInfo )

Parameters

message

Windows mouse message being queried.

lExtraInfo

Value returned by GetMessageExtraInfo for the given message.

Return Value

Returns TRUE if the mouse event referenced by the message parameter was generated by the pen driver; otherwise, returns FALSE.

Comments

Mouse drivers that have not been updated to be compatible with pens may produce an event that cannot be distinguished from a real pen event. This has a very low probability of occurring.


KKConvert [New - Windows 95]
KKConvert

2.0      [New - Windows 95]

Activates the Kana-to-Kanji converter. (Japanese version only.)

BOOL KKConvert( HWND hwndConvert, HWND hwndCaller, LPSTR  lpBuf, UINT cbBuf, LPPOINT lpPoint )

Parameters

hwndConvert

Handle to the window with the text to be converted.

hwndCaller

Handle to the window that calls KKConvert.

lpBuf

The text to be converted.

cBuf

The number of bytes (greater than 1) in lpBuf.

lpPoint

The positition where the Kana-to-Kanji converter will appear.

Return Value

Returns TRUE if the text is successfully converted; otherwise, returns FALSE.

Comments

If lpBuf is NULL, the currently-selected text in the window specified by hwndConvert will be used for conversion and then replaced with the converted text. If lpBuf is not NULL, the text in lpBuf will be converted and replaced with the converted text. If the length of the converted text is longer than cbBuf, the text will be truncated.

If the window referenced by hwndConvert is of the bedit class, lpPnt is ignored; otherwise, the center of the Kana-to-Kanji conversion is displayed at lpPnt.

If the window referenced by hwndConvert is of the hedit class and lpPnt is NULL, then the current caret position is used; otherwise, the client position (0,0) in the window referenced by hwndConvert is used.


MetricScalePenData [New - Windows 95]
MetricScalePenData

1.0     2.0      [New - Windows 95]

Converts pen data points to one of the supported metric modes.

BOOL MetricScalePenData( HPENDATA hpndt, UINT wPndtNew )

Parameters

hpndt

Handle to a pen data object containing the points to be converted.

wPndtNew

Scaling metric to be used with the data, as listed here:

Constant	Description
PDTS_LOMETRIC	Each logical unit is mapped to 0.1 millimeter. Positive x is to the right; positive y is down.
PDTS_HIMETRIC	Each logical unit is mapped to 0.01 millimeter. Positive x is to the right; positive y is down.
PDTS_HIENGLISH	Each logical unit is mapped to 0.001 inch. Positive x is to the right; positive y is down. This is equivalent to PDTS_STANDARDSCALE.
PDTS_DISPLAY	This parameter scales the data, using DPtoTP. The pen data memory block is left in display coordinates.
Return Value

Returns TRUE if successful, or FALSE if hpndt is in a compressed state or if the data is not already in one of the metric modes such as PDTS_ARBITRARY.

Comments

The MetricScalePenData function converts pen coordinates between metric and English standard measurements. Metric units are 0.1 and 0.01 millimeter; English standard units are 0.001 inch. These scaling metrics form the same mapping mode set in the Windows function SetMapMode.

MetricScalePenData allows an application to transform pen data to the mapping mode set for a device context. This ensures that ink rendered in the device context appears in the proper scale.

Note the following caveats about MetricScalePenData:

•	Because of rounding errors, scaling is not precisely reversible between mapping modes. Rounding errors can also adversely affect recognition accuracy if the data is later given to a recognizer. The problem arises when transforming the standard ink scale of HIENGLISH to a scale of lower resolution, a transformation that loses some of the original data. The lost data cannot be recovered, even if the coordinates are converted back into HIENGLISH.

•	The scaling is not perfect and results in numerous "off-by-one" discrepancies, visible when displaying the scaled data.

Strictly speaking, the PDTS_DISPLAY scaling type is not a metric scale. To use it, the current scale of the data must be in PDTS_STANDARDSCALE units.

The effect of this call is similar to that of using the TPtoDP function on the array of points. A recognizer may not accurately recognize the resulting data. As with the other scales, the PDTS_DISPLAY is set in the wPndts member of the pen data header. If data is in PDTS_DISPLAY scale, MetricScalePenData cannot be called to scale it back to the other metric scales. No overflow checks are made. Because of rounding errors, scaling conversion is not perfectly reversible. Recognizers must recognize points that have been scaled to PDTS_STANDARDSCALE (equivalent to PDTS_HIENGLISH).

See Also

OffsetPenData, ResizePenData, PDTS_


OffsetPenData [New - Windows 95]
OffsetPenData

1.0     2.0      [New - Windows 95]

Offsets the coordinates in an HPENDATA memory block to make them relative to another origin.

BOOL OffsetPenData( HPENDATA hpndt, int dx, int dy )

Parameters

hpndt

Handle to a pen data object.

dx

Offset of x-axis; that is, the amount to move left or right. To move left, the dx value must be negative.

dy

Offset of y-axis; that is, the amount to move up or down. To move up, the dy value must be negative.

Return Value

Returns TRUE if successful, or FALSE if hpndt is in a compressed state.

Comments

For every point in hpndt, dx is added to the x-coordinate and dy is added to the y-coordinate. No overflow checks are made.

An application can use OffsetPenData to make points at display resolution relative to a particular window. If the window is then moved, the application need only call OffsetPenData again to move the data by the same amount, as shown in the example.

Example

The following sample code illustrates using the OffsetPenData function.

DWORD	dwOrg;	// Store window origin

.

.

.

// After creating window, note its current position

dwOrg = GetWindowOrg( hWnd );

.

.

.

switch( wMsg )

{

case WM_MOVE:

dx    = (int) (LOWORD(lParam) - LOWORD(dwOrg));	// X increment

dy    = (int) (HIWORD(lParam) - HIWORD(dwOrg));	// Y increment

dwOrg = (DWORD) lParam;	// Keep new org

OffsetPenData( hpendata, dx, dy );

See Also

MetricScalePenData, ResizePenData


PeekPenInput [New - Windows 95]
PeekPenInput

2.0      [New - Windows 95]

Retrieves information about a specified pen packet in the pen input queue. For a definition of pen packet, see the description of SetPenHook.

int PeekPenInput( HPCM hpcm, UINT idEvent, LPPOINT lppt, LPVOID lpvOem, UINT fuOemFlags )

Parameters

hpcm

Handle to a pen collection. This is the return value from StartPenInput.

idEvent

The identifier of the packet to be retrieved. The idEvent is the low-order word of the value returned from the Windows GetMessageExtraInfo function when processing a WM_LBUTTONDOWN message.

lppt

Far pointer to a POINT structure. PeekPenInput copies the point corresponding to idEvent into the buffer pointed to by lppt.

lpvOem

The address of a buffer of OEM data in the packet. This parameter can be NULL if no OEM data is required.

fuOemFlags

Flags specifying which OEM data to retrieve. If this parameter is NULL, all of the OEM data provided by the tablet is returned in the order specified by the rgoempeninfo array in PENINFO.

These flags have an implicit order. For example, if pressure and barrel rotation are specified in that order, cPntMax pairs of these data are returned in the same order: [pressure, rotation], [pressure, rotation], and so on. (cPntMax is the number of POINT structures specified in GetPenInput.)

Constant	Description
PHW_PRESSURE	Retrieve pressure data.
PHW_HEIGHT	Retrieve height data.
PHW_ANGLEXY	Retrieve data pertaining to the x- and y-coordinates.
PHW_ANGLEZ	Retrieve data pertaining to the z-coordinates.
PHW_BARRELROTATION	Retrieve barrel-rotation data.
PHW_OEMSPECIFIC	Retrieve OEM-specific data.
PHW_PDK	Retrieve PDK_ data.
Return Value

Returns PCMR_OK if successful; otherwise, the return value can be one of the following:

Constant	Description
PCMR_INVALIDCOLLECTION	The hpcm handle is invalid because the calling application did not start input with StartPenInput.
PCMR_INVALID_PACKETID	idEvent is invalid.
Comments

Unlike GetPenInput, this function does not remove data from the pen input queue. It only returns information about the packet specified by idEvent.

Whereas lppt points into the pen input queue, lpvOem does not. If lpvOem is not NULL, it points to a buffer provided by the caller into which the OEM data are copied from the pen input queue.

The buffer that lpvOem points to must be large enough to hold the requested OEM data copied from the packet. The size of each packet is the width specified in the cbOemData member of the PENINFO structure, plus sizeof( UINT ) if PDK_ values are required.

See Also

GetPenInput,  PENPACKET,  PDK_


PenDataFromBuffer [New - Windows 95]
PenDataFromBuffer

2.0      [New - Windows 95]

Creates a HPENDATA object from serial data in a buffer. The buffer must have been previously written by the PenDataToBuffer function.

LONG PenDataFromBuffer( LPHPENDATA lphpndt, UINT gmemFlags, LPBYTE lpBuffer, LONG cbBuf, LPDWORD lpdwState )

Parameters

lphpndt

Pointer to an uninitialized HPENDATA handle. If PenDataFromBuffer returns successfully, lphpndt points to a new HPENDATA object containing a copy of the serial points.

gmemFlags

Flag that specifies whether or not the Windows GlobalAlloc function should create a shared memory object when the pen data object is created. This should be either 0 or GMEM_DDESHARE. The GMEM_MOVEABLE and GMEM_ZEROINIT flags are added to this value and other GMEM_ flags are ignored.

lpBuffer

Pointer to a byte buffer containing serial data.

cbBuf

Size of the buffer, which must be at least 64 bytes in size. If the buffer serves as an intermediate holding area, it need not be as large as the final HPENDATA object. To create the object, the application must call PenDataFromBuffer successively, each time reading a new section of data into the buffer that lpBuffer points to before the call. The example below illustrates this technique by filling an HPENDATA object in stages, reading data from a file in cbBuf increments.

lpdwState

Address of a DWORD variable used by the system to maintain the transfer state. The DWORD variable must be initialized to 0 before the first call to PenDataFromBuffer. Between successive calls to PenDataFromBuffer, the application must not alter the value that lpdwState points to. lpdwState can be NULL to signify that the buffer contains the entire data set for the HPENDATA object. This implies that subsequent calls to PenDataFromBuffer are not necessary.

Return Value

If successful, PenDataFromBuffer returns the number of bytes transferred from the buffer. If the size of the pen data is larger than the buffer, the return value is equal to the buffer size passed in cbBuf. A value of 0 indicates no more data to transfer. If there is an error, one of the following negative values is returned:

Constant	Description
PDR_ERROR	Parameter or overflow error.
PDR_MEMERR	Memory error.
Comments

The data being provided by the application must have been previously written by the PenDataToBuffer function. The application cannot modify this data in any way. Embedded values within the first 64 bytes provide information to PenDataFromBuffer about the size of the pen data.

PenDataFromBuffer creates an HPENDATA object and provides a handle to it. The application must destroy the object when finished. The lphpndt argument points to a valid HPENDATA handle only if the function returns PDR_OK.

While this function is reconstituting the HPENDATA object, the application must not attempt to use it in any way because it will be invalid until the last buffer is read.

Example

The following example shows how to create a HPENDATA object from a file (hfile) that has already been opened for reading. Before reading the pen data, its length is retrieved from the file:

#define cbBufMax	1024

HPENDATA NEAR PASCAL ReadPenData( HFILE hfile )

{

HPENDATA	hpndt = NULL;

LONG	cb, cbRead, cbHpndt;

BYTE	lpbBuf[cbBufMax];	// Buffer

DWORD	dwState = 0L;	// Must initialize to 0

if (!hfile

|| (cb = _lread(hfile, &cbHpndt, sizeof(DWORD))) == HFILE_ERROR

|| cb != sizeof(LONG))

return NULL;

while (cbHpndt > 0)

{

if ((cbRead = _lread( hfile, lpbBuf, min(cbHpndt, cbBufMax )))

== HFILE_ERROR

|| PenDataFromBuffer( &hpndt, 0, lpbBuf,

  cbBufMax, &dwState ) < 0)

{

if (hpndt)

DestroyPenData( hpndt );

return NULL;

}

cbHpndt -= cbRead;

}

return hpndt;

}

See Also

PenDataToBuffer,  GetPenDataAttributes


PenDataToBuffer [New - Windows 95]
PenDataToBuffer

2.0      [New - Windows 95]

Writes the data in an existing HPENDATA object to a serial buffer.

LONG PenDataToBuffer( HPENDATA hpndt, LPBYTE lpBuffer, LONG cbBuf, LPDWORD lpdwState )

Parameters

hpndt

Handle to the HPENDATA object.

lpBuffer

Pointer to an empty buffer.

cbBuf

Size of the buffer in bytes. The buffer must be at least 64 bytes in size. If the buffer serves as an intermediate holding area, it need not be as large as the HPENDATA object. To read all data from the object in this case, the application must call PenDataToBuffer successively, each time copying the data from the buffer that lpBuffer points to before the next call. The example below illustrates this technique by writing an HPENDATA object in cbBuf increments to a file.

lpdwState

Address of a DWORD variable used by the system to maintain the transfer state. The DWORD variable must be initialized to 0 before the first call to PenDataToBuffer. Between successive calls to PenDataToBuffer, the application must not alter the value that lpdwState points to. lpdwState can be NULL to signify that the buffer is large enough to contain the entire HPENDATA object. This implies that subsequent calls to PenDataToBuffer are not necessary.

Return Value

If successful, PenDataToBuffer returns the number of bytes transferred into the buffer. If the size of the pen data is larger than the buffer, the return value is equal to the buffer size passed in cbBuf until the final transfer, when it is typically some smaller value. A value of 0 indicates no more data to transfer. If there is an error, one of the following negative values is returned:

Constant	Description
PDR_ERROR	Parameter or other unspecified error.
PDR_MEMERR	Memory error.
PDR_PNDTERR	Invalid HPENDATA object.
PDR_VERSIONERR	Could not convert old HPENDATA object.
Comments

The buffer need not be large enough to accommodate the entire HPENDATA object. To allocate a buffer large enough for a single transfer, the application can determine the required size with the GetPenDataAttributes subfunction GPA_SIZE .

Example

The following example shows how to save an HPENDATA object to a file (hfile) that has already been opened for writing. The length of the pen data is saved in the file before writing the pen data itself:

#define cbBufMax	1024

BOOL NEAR PASCAL	WritePenData( HFILE hfile, HPENDATA hpndt )

{

BYTE    lpbBuf[cbBufMax];

DWORD   dwState = 0L;	// Must initialize to zero

LONG    cb;

LONG    cbSize;

if (!hfile || !hpndt)

return FALSE;

// Get size and save to file

if (GetPenDataAttributes(hpndt, (LPVOID)&cbSize, GPA_SIZE) < 0)

return FALSE;

// write size of pen data to file so that it can be used while reading it back

if (_lwrite(hfile, &cbSize, sizeof(LONG)) == HFILE_ERROR)

return FALSE;

// Write the pen data in chunks, and repeat until done

while ((cb = PenDataToBuffer(hpndt, lpbBuf,

  cbBufMax, &dwState )) > 0L)

{

if (_lwrite( hfile, lpbBuf, (UINT)cb ) == HFILE_ERROR)

return FALSE;

}

return (cb >= 0L);	// Return TRUE if cb >= 0

}

See Also

PenDataFromBuffer


PostVirtualKeyEvent [New - Windows 95]
PostVirtualKeyEvent

1.0     2.0      [New - Windows 95]

Posts a virtual key-code event to Windows.

void PostVirtualKeyEvent( UINT vk, BOOL fUp )

Parameters

vk

Virtual key. This argument takes a Windows VK_ constant as defined in the WINDOWS.H include file. Depending on the key, this is either the key scan code or the ASCII equivalent to represent a character key. For example, VK_A has the value "A."

fUp

Key-transition flag. This parameter should be FALSE to specify that the key is down or TRUE to specify that it is up.

Return Value

This function does not return a value.

Comments

PostVirtualKeyEvent does not check the virtual key code for errors.

Normally, an application should follow a key-down message with a corresponding key-up message to accurately simulate the actual events from the keyboard. You can post repeating keys by calling PostVirtualKeyEvent consecutively, one call per repeat, with fUp set to FALSE. End the sequence with a single call to PostVirtualKeyEvent with fUp set to TRUE.

The events are posted to the system message queue. The application with the input focus can receive the messages by calling the Windows GetMessage or PeekMessage function.

See Also

AtomicVirtualEvent, PostVirtualMouseEvent


PostVirtualMouseEvent [New - Windows 95]
PostVirtualMouseEvent

1.0     2.0      [New - Windows 95]

Posts a virtual mouse code to Windows.

void PostVirtualMouseEvent( UINT wMouseFlags, int xPos, int yPos )

Parameters

wMouseFlags

Flags indicating the type of mouse event. This can be one or more of the following values, combined by a bitwise-OR operator.

Constant	Description
VWM_MOUSEMOVE	Simulates a change in the mouse cursor position. This flag can be combined with any of the other flags in this table.
VWM_MOUSELEFTDOWN	Simulates pushing the left mouse button.
VWM_MOUSELEFTUP	Simulates releasing the left mouse button.
VWM_MOUSERIGHTDOWN	Simulates pushing the right mouse button.
VWM_MOUSERIGHTUP	Simulates releasing the right mouse button.
xPos

The x-axis position in screen coordinates.

yPos

The y-axis position in screen coordinates.

Return Value

This function does not return a value.

Comments

The x- and y-axis positions are absolute positions in screen coordinates. Note that the x and y values should not exceed the screen-resolution limits. Values greater than the maximum resolution in the x-direction (640 for standard VGA) or the y-direction (480 for standard VGA) cause an overflow.

The events are posted to the system message queue. The application with the input focus can receive the messages by calling the Windows GetMessage or PeekMessage message.

Because of the way Windows interprets mouse messages, the calling application must be careful about the order in which events are sent to the system. A message that represents both a button-state transition and a move generates first a Windows event for the button transition at the current pointer location and then a move to the new location. To simulate a move to a new location followed by a button transition, the application must make separate calls to PostVirtualMouseEvent for each simulated event.

Example

When posting events, the caller should bracket the calls by calls to AtomicVirtualEvent, which locks out pen packets while the application is posting simulated mouse events. For example, the following code fragment posts a mouse event:

AtomicVirtualEvent(TRUE);

//

//  ... PostVirtualMouseEvent calls go here

//

AtomicVirtualEvent(FALSE);

The Windows GetMessageExtraInfo function returns 0 for any messages generated by PostVirtualMouseEvent.

See Also

AtomicVirtualEvent, PostVirtualKeyEvent


ProcessHRC [New - Windows 95]
ProcessHRC

2.0      [New - Windows 95]

Gives a recognizer sufficient time for intermediate processing of pen input. A recognizer must export this function.

int ProcessHRC( HRC hrc, DWORD dwTimeMax )

Parameters

hrc

Handle to the HRC object for the recognizer.

dwTimeMax

The maximum time in milliseconds that the recognizer should process before returning from this call. This parameter can also be one of the following time-out codes:

Constant	Description
PH_MIN	The recognizer should take only a very small amount of time to process the input, typically 50 milliseconds.
PH_DEFAULT	The recognizer should take a moderate amount of time to process the input, typically 200 milliseconds.
PH_MAX	The recognizer should take as much time as required to complete recognition.
Return Value

If there are no errors, returns one of the following values:

Constant	Description
HRCR_OK	Processing is successful.
HRCR_INCOMPLETE	The recognizer is still processing the current batch of input.
HRCR_GESTURE	The recognizer has recognized a possible gesture.  This can be returned before the recognition process  is complete. If the processing completes, HRCR_COMPLETE is always returned, even for gestures.
HRCR_COMPLETE	The recognizer completed processing and does not expect any more input.
To indicate an error, ProcessHRC returns one of the following negative values:

Constant	Description
HRCR_ERROR	Invalid parameter or other error.
HRCR_MEMERR	Insufficient memory.
Comments

ProcessHRC returns if the time specified by dwTimeMax elapses before recognition is complete.

In an operating environment that does not use threads, this function allows an application to provide some time for the recognizer to process input. By checking the return value, the application is able to monitor the progress, specifically whether a gesture is a recognition candidate. If the function returns HRCR_GESTURE, the application can call GetResultsHRC to determine whether the gesture should be acted on immediately.

Typically, the return value is HRCR_OK if the current batch of ink input has been processed by the recognizer, and HRCR_INCOMPLETE if the recognizer has not yet finished processing.

If ProcessHRC is called with PH_MAX, recognition is complete only if EndPenInputHRC has been called to notify the recognizer that no more results are expected. The return value in this case is HRCR_COMPLETE, and the application is free to get and display final results. If the application supplies further input at this point, it has the effect of canceling the EndPenInputHRC call, although this procedure is not recommended for reasons of efficiency.

However, PH_MAX may result in poorer performance, since further processing in the system is blocked until ProcessHRC returns. Instead, the application can call ProcessHRC in an idle loop or a separate thread, calling it repeatedly with smaller time allotments until the function returns HRCR_COMPLETE. Note that if a separate thread is used to finish processing, the main thread can call this function with PH_MIN from time to time to determine if processing has finished (that is, checking for the HRCR_COMPLETE return value).

The first time that ProcessHRC is called for a particular recognition context, functions that set its state cannot be used for the remainder of that context's existence. The following functions return an error if they are called before ProcessHRC returns HRCR_COMPLETE:

•	EnableGestureSetHRC

•	EnableSystemDictionaryHRC

•	SetAlphabetHRC

•	SetAlphabetPriorityHRC

•	SetBoxAlphabetHRC

•	SetWordlistCoercionHRC

•	SetGuideHRC

•	SetInternationalHRC

•	SetMaxResultsHRC

•	SetWordlistHRC

See Also

EndPenInputHRC, GetResultsHRC


ProcessWriting [New - Windows 95]
ProcessWriting

1.0     2.0      [New - Windows 95]

Processes handwriting.

Note  This function is provided only for compatibility with version 1.0 of the Pen API and will not be supported in future versions. Use DoDefaultPenInput instead.

REC ProcessWriting( HWND hwnd, LPRC lprc )

Parameters

hwnd

Window to receive messages. This parameter must not be NULL.

lprc

Address of RC structure to use for recognition. This parameter can be NULL.

Return Value

Returns values less than 0 if the application should treat the event as a mouse event instead of a pen event. Return values less than 0 occur if the event did not come from a pen, the user performed a press-and-hold action (REC_POINTEREVENT), or an error occurred—for example, running out of memory.

Comments

The ProcessWriting function is similar to Recognize except that ProcessWriting also takes care of inking, removing the ink, and converting the results message to standard Windows messages.

Depending on the existing code in an application, ProcessWriting may not be suitable for making an application pen-aware. This function can also limit the power of a pen interface.

If lprc is NULL, a default RC structure is created for the application. The default RC structure contains all system defaults and the inking is constrained to the client area of hwnd. If lprc points to a valid RC structure, the rectBound member of the RC structure is used to constrain the inking. Regardless of whether the application provides an RC or not, ProcessWriting assumes a value of RRM_COMPLETE for the wResultMode member. See RC for a description of wResultMode and the RRM_ values.

After the writing is completed, the ink is removed before any messages are sent to hwnd. After the ink is removed, the screen is updated and hwnd receives a WM_RCRESULT message. If the application processes this message, it should return TRUE. In this case, no further messages are sent.

If the application returns FALSE, ProcessWriting performs the default conversion of the results message to standard Windows messages, as shown in the following table. The messages are sent rather than posted. Note that the DefWindowProc function returns 0 when processing the WM_RCRESULT message.

Results message	Windows message
SYV_BACKSPACE	WM_LBUTTONDOWN, followed by WM_LBUTTONUP at the hot spot of the gesture, followed by WM_CHAR specifying a backspace.
SYV_CLEAR	WM_CLEAR.
SYV_CLEARWORD	WM_LBUTTONDOWN, WM_LBUTTONUP, WM_LBUTTONDBLCLK, WM_LBUTTONUP at the same point, followed by WM_CLEAR.
SYV_COPY	WM_COPY.
Results message	Windows message
SYV_CORRECT	WM_LBUTTONDOWN, WM_LBUTTONUP, WM_LBUTTONDBLCLK, WM_LBUTTONUP at the hot spot of the gesture, followed by WM_COPY. At this point the Edit Text dialog box is activated; it retrieves text from the Clipboard. This uses the existing selection, if any. The previous contents of the Clipboard are lost.
SYV_CUT	WM_CUT.
SYV_EXTENDSELECT	WM_LBUTTONDOWN, followed by WM_LBUTTONUP at the hot spot of the gesture.  The MK_SHIFT flag is set for the wParam of these messages.
SYV_LASSO	WM_LBUTTONDOWN at upper-left corner of selected area, followed by WM_MOUSEMOVE message, followed by WM_LBUTTONUP at the lower-right corner of selected area.
SYV_PASTE	WM_LBUTTONDOWN, followed by WM_LBUTTONUP at the hot spot of the gesture, followed by WM_PASTE.
SYV_RETURN	WM_LBUTTONDOWN, followed by WM_LBUTTONUP at the hot spot of the gesture, followed by WM_CHAR specifying a carriage return.
SYV_SPACE	WM_LBUTTONDOWN, followed by WM_LBUTTONUP at the hot spot of the gesture, followed by WM_CHAR specifying a space.
SYV_TAB	WM_LBUTTONDOWN, followed by WM_LBUTTONUP at the hot spot of the gesture, followed by WM_CHAR specifying a tab.
SYV_UNDO	WM_UNDO.
text	One WM_CHAR message per character of text.
The SYV_ symbol values in the previous table identify gestures. To see a complete list of symbol values, refer to Chapter 13, "Pen Application Programming Interface Constants."

The lParam of a WM_RCRESULT message generated by ProcessWriting is a far pointer to an RCRESULT structure. By default, when an application receives a WM_RCRESULT message, the hpendata member of the RCRESULT structure is NULL. If you need the HPENDATA handle, set the RCO_SAVEHPENDATA flag in the lRcOptions member of the RC structure. In this case, the calling application is responsible for destroying the HPENDATA object.

See Also

DoDefaultPenInput, InitRC, Recognize, REC_, SYV_, RCO_


ReadHWL [New - Windows 95]
ReadHWL

2.0      [New - Windows 95]

Reads a word list from a file.

int ReadHWL( HWL hwl, HFILE hfile )

Parameters

hwl

A handle to an empty word list.

hfile

A handle to a file previously opened for reading.

Return Value

Returns HRCR_OK if successful; otherwise, returns one of the following negative values:

Constant	Description
HRCR_ERROR	Invalid parameter or file or other error.
HRCR_MEMERR	Insufficient memory.
Comments

The words are expected as ANSI text, one word per line, followed by a carriage return and linefeed. In this context, a word can represent a phrase and contain spaces or other noncharacters, such as "New York" and "ne'er-do-well." Empty lines or lines containing only spaces or tabs are allowed but ignored.

The file that hfile refers to must already exist and be open for reading.

The hwl parameter must be the handle of an empty word list created by CreateHWL. If the word list is not empty, ReadHWL returns HRCR_ERROR.

Once the file is read, it can be closed immediately.

Example

The following example demonstrates how to provide a word list to constrain recognition results to the words contained in the fictitious file COUNTRY.LST:

HWL	  hwlCountries = CreateHWL( NULL, NULL, WLT_EMPTY, 0L );

OFSTRUCT	  ofStruct;

HFILE	  hfile = OpenFile( "country.lst", &ofStruct, OF_READ );

if (hfile != HFILE_ERROR)

{

ReadHWL(hwlCountries, hfile);

_lclose(hfile);

}

else

ErrorMsg(FILEOPEN);

.

.

.

if (hrc = CreateCompatibleHRC( NULL, NULL ))

{

SetWordlistHRC( hrc, hwlCountries );	    // Set list into HRC

SetWordlistCoercionHRC( hrc, SCH_FORCE );  // Force match

.

.     // Code that collects and recognizes input here

.

}

See Also

CreateHWL, WriteHWL


Recognize [New - Windows 95]
Recognize

1.0     2.0      [New - Windows 95]

Begins sampling pen data and converts tablet input to recognized symbols.

Note  This function is provided only for compatibility with version 1.0 of the Pen API and will not be supported in future versions.

REC Recognize( LPRC lprc )

Parameters

lprc

Address of an RC structure.

Return Value

Returns an REC_ value. See the "Comments" section for a description of the return values.7

Comments

The RC structure that lprc points to contains the parameters that control recognition. The system sends recognition results via the WM_RCRESULT message to the window indicated by the hwnd member of the RC. All results messages are sent before Recognize returns. Multiple result messages can be sent if the application asks for results to be sent to the application before all input has been completed (as indicated by the wResultMode member of the RC structure).

An application that uses version 1.0 recognizers should call Recognize when the input session begins, signaled by the WM_LBUTTONDOWN message.

The value REC_OK is used in the wParam of the WM_RCRESULT message to indicate that more data is coming. Return values of greater than 0 signal normal successful completion. Return values of less than 0 indicate abnormal termination. Return values of less than REC_DEBUG are reserved for return values from

debugging versions of the system or recognizer. If an application creates a condition that would be caught in a debugging version while running a nondebugging version, the results are undefined.

Each return value can be the wParam value of the WM_RCRESULT message or the return value for Recognize. The wParam value of the last WM_RCRESULT message generated by a call to Recognize is the return value of Recognize. Some error conditions, such as REC_OOM or REC_NOTABLET, are returned without generating any corresponding WM_RCRESULT message.

All of the values listed in the following table are in the debug version only. No WM_RCRESULT message is generated if these values are returned by Recognize.

Constant	Description
REC_ALC	Invalid enabled alphabet.
REC_BADEVENTREF	Returned when the wEventRef member in the lprc structure is invalid.
REC_CLVERIFY	Invalid verification level.
REC_DEBUG	All debugging return values are less than this.
REC_DICT	Invalid dictionary parameters.
REC_ERRORLEVEL	Invalid error level.
REC_GUIDE	Invalid GUIDE structure.
REC_HREC	Invalid recognition handle.
REC_HWND	Invalid handle to window to send results to.
REC_INVALIDREF	Invalid data reference parameter.
REC_LANGUAGE	Returned by the recognizer when the lpLanguage member contains a language that is not supported  by the recognizer. Call ConfigRecognizer with the WCR_QUERYLANGUAGE subfunction to determine whether a particular language is supported.
REC_NOCOLLECTION	In version 1.0, was returned by GetPenHwData if collection mode has not been set. Not used now.
REC_OEM	Error codes less than or equal to REC_OEM are specific to the recognizer.
REC_PCM	Invalid lPcm member in the RC structure. There is no way for the recognition to end.
REC_RECTBOUND	Invalid rectangle.
REC_RECTEXCLUDE	Invalid rectangle.
REC_RESULTSMODE	Unsupported results mode requested.
See Also

InitRC, RecognizeData, GetPenHwEventData,  RC,  REC_


RecognizeData [New - Windows 95]
RecognizeData

1.0     2.0      [New - Windows 95]

Converts the data in an HPENDATA object to recognized symbols.

Note  This function is provided only for compatibility with version 1.0 of the Pen API and will not be supported in future versions.

REC RecognizeData( LPRC lprc, HPENDATA hpndt )

Parameters

lprc

Address of an RC structure.

hpndt

Handle to an HPENDATA object.

Return Value

Returns REC_DONE if successful, or an REC_ error code if an error occurs.

Comments

RecognizeData recognizes data in an HPENDATA object and returns the results to the window specified in the RC structure. RecognizeData is similar to Recognize. The difference is that in RecognizeData, the input data comes from a buffer of points already collected instead of from the tablet driver. Members pertaining to the end of recognition in the RC structure are ignored.

RecognizeData can return REC_BUSY if the recognizer is not reentrant. A recognizer is not guaranteed to return the same results for identical input. This is because persistent states, such as the current average size of writing or the position of the baseline, can affect recognition results. In addition, training may change the prototypes against which the data is being compared.

RecognizeData attempts to convert the pen data to PDTS_STANDARDSCALE if it is not already in standard scale. If the conversion fails (for example, because the data was in an application-specific scale PDTS_ARBITRARY), the data is still passed to the recognizer. A recognizer may return an error code (REC_BADHPENDATA) for data in a scale it cannot handle.

See Also

InitRC, Recognize, GetPenHwEventData, RC, REC_,  PDTS_


RedisplayPenData [New - Windows 95]
RedisplayPenData

1.0     2.0      [New - Windows 95]

Redraws the pen data in the same manner as originally inked.

BOOL RedisplayPenData( HDC hdc, HPENDATA hpndt, LPPOINT lpDelta, LPPOINT lpExt, int nInkWidth, DWORD rgbColor )

Parameters

hdc

Handle to a device context. The mapping mode should be MM_TEXT.

hpndt

Handle to a pen data object. The pen data must be scaled to PDTS_DISPLAY or PDTS_STANDARDSCALE.

lpDelta

An offset, in logical units, that is subtracted from the pen data points to position the ink. If lpDelta is NULL, there is no offset.

lpExt

Extent, in logical units, for scaling. If lpExt is NULL, no scaling is performed.

nInkWidth

Width of the ink to be drawn, in pixels (1 to 15). If nInkWidth is −1, the strokes are rendered using the original ink width stored in the stroke header. An ink width of 0 causes the function to simply return TRUE.

rgbColor

RGB value of the color to draw the ink. If rgbColor is 0xFFFFFFFF, the strokes are rendered using the original ink color stored in the stroke header.

Return Value

Returns TRUE if successful; otherwise FALSE.

Comments

The nInkWidth and rgbColor values override the pen currently selected for the hdc device context.

If the mapping mode of the hdc device context is not MM_TEXT, two problems can occur:

•	RedisplayPenData uses TPtoDP to prepare the pen data points for rendering. After this, the points are in MM_TEXT coordinates; this assumes an MM_TEXT device context for display. If the device context is in a different mapping mode, the ink coordinates will not be correct. Even if you use the ink-scaling functions to bypass this problem, you will still encounter rounding-error problems between the two scalings.

•	No matter what scaling is done, rounding errors occur when converting between modes. These errors cause the ink to shift slightly when repainted.

For any rendering into a device context that represents anything other than a display device context, DrawPenDataEx should be used. This is because RedisplayPenData makes assumptions that are not optimal for other devices such as printers or metafiles.

RedisplayPenData provides the ability to re-create original inking perfectly. To do this, an application can use either of two methods:

•	After the input session ends and data is collected into an HPENDATA object, store the current origin of the window containing the ink. When calling RedisplayPenData to redraw the ink, supply the origin value in the lpDelta argument, set lpExt to NULL, and set the mapping mode of the device context to MM_TEXT. Only ink data with a common window origin can be merged into a single HPENDATA.

•	In the second method, the application must call two Pen functions immediately after collecting the data into an HPENDATA object. The first call to MetricScalePenData converts the pen data to display coordinates. The second call to OffsetPenData sets the display coordinates relative to the window containing the original ink. To display, the application must call RedisplayPenData with lpDelta and lpExt set to NULL and the mapping mode of the device context set to MM_TEXT. If the application adopts this method for multiple HPENDATA objects, it can later merge them to form a single HPENDATA object (up to the 64K limit).

The second method has the advantages of simplicity and data compression. See the description of MetricScalePenData for a discussion of the limitations of converting data to display resolution.

Since the pen data has the origin of (0,0) based on the upper-left corner of the display, applications must move from a screen-relative position to a position relative to the device context. To do this, subtract the origin of the device context (in screen coordinates) from the object currently residing in screen-coordinate space.

The lpDelta parameter enables the application to render ink relative to the window instead of relative to the screen. An application should call the ClientToScreen function for (0,0) to find the proper screen coordinates to be placed in the *lpDelta POINT structure. Once this is done, the pen data is rendered at the appropriate location in window coordinates. If lpDelta is NULL, no offset for the data is assumed.

The lpExt argument specifies the extents into which the data should be scaled. If extents are provided, data is scaled into a rectangle described by lpDelta and lpExt. The values of x and y in lpExt and lpDelta are in the mapping mode of the device context into which the data is rendered.

RedisplayPenData displays pen data with a square graphical device interface (GDI) pen brush for maximum drawing speed. When displaying wide lines of ink, this optimization can cause the ends of abutting lines to appear blocky. If you prefer a smoother look to the joints of wide lines at the expense of rendering speed, draw the ink with DrawPenData, DrawPenDataEx, or DrawPenDataFmt instead of RedisplayPenData. These functions draw wide lines by flood-filling a region, thus smoothing the ends.

See Also

DrawPenData,  DrawPenDataEx,  PDTS_


RegisterPenApp [New - Windows 95]
RegisterPenApp

1.0     2.0      [New - Windows 95]

Notifies the pen system that the application edit controls should be replaced with hedit controls. This function is required only for applications that specify EDIT class (instead of HEDIT class) for control windows with versions of Windows earlier than Windows 95.

Note that this function has been superseded by the SetPenAppFlags function in the 2.0 version of the Pen API, although calling RegisterPenApp is still supported. See SetPenAppFlags for more information.

void RegisterPenApp( UINT fuFlags, UINT uVersion )


RemovePenDataStrokes [New - Windows 95]
RemovePenDataStrokes

2.0      [New - Windows 95]

Removes strokes from an HPENDATA object.

int RemovePenDataStrokes( HPENDATA hpndt, UINT iStrk, UINT cStrks )

Parameters

hpndt

Handle to the HPENDATA object.

iStrk

Zero-based index of the first stroke to remove. This value can be IX_END to remove the last stroke. The function fails if iStrk is greater than the number of strokes in the pen data object.

cStrks

Count of strokes to remove. If this value is greater than the number of strokes after the specified stroke index, the stroke indexed by iStrk and all following strokes are removed. cStrks can be IX_END to remove all strokes from iStrk onward.

Return Value

Returns PDR_OK if successful; otherwise, the return value can be one of the following negative values:

Constant	Description
PDR_COMPRESSED	Pen data is compressed.
PDR_ERROR	Parameter or other unspecified error.
PDR_MEMERR	Out of memory.
PDR_PNDTERR	Invalid pen data object.
PDR_STRKINDEXERR	Invalid stroke index.
PDR_VERSIONERR	Could not convert old pen data object.
Comments

RemovePenDataStrokes removes the number of strokes specified by cStrks, starting at the stroke specified by iStrk. Use ExtractPenDataPoints to remove points from a particular stroke of the pen data object.

See Also

ExtractPenDataPoints, InsertPenDataPoints, InsertPenDataStroke


ResizePenData [New - Windows 95]
ResizePenData

1.0     2.0      [New - Windows 95]

Scales ink in an HPENDATA object into an arbitrarily sized rectangle.

BOOL ResizePenData( HPENDATA hpndt, LPRECT lprect )

Parameters

hpndt

Handle to a pen data object.

lprect

Address of a bounding rectangle, or NULL.

Return Value

Returns TRUE if successful; otherwise, the return value is FALSE.

Comments

This function changes the physical size of the object without changing the meaning of the measurements. Use the MetricScalePenData function to convert the data to one of the supported metric modes of measurement.

ResizePenData physically resizes the data in hpndt to the bounding rectangle dimensions given by the lprect parameter. Data from hpndt is mapped to the new rectangle. If lprect is NULL, this function recalculates the bounding rectangle (the rectBound member in the PENDATAHEADER structure). For example, consider the case of pen data with PDTS_HIMETRIC scaling bounded by the square (500, 600, 1500, 1600). To double the size, set lprect to (500, 600, 2500, 2600).

See Also

OffsetPenData, MetricScalePenData, PDTS_


ResultsHookHREC [New - Windows 95]
ResultsHookHREC

2.0      [New - Windows 95]

The ResultsHookHREC function is an application-defined callback function that provides the application with the opportunity to view all recognition results before they are returned to the application. The name ResultsHookHREC is a placeholder; the function can have any name.

BOOL CALLBACK ResultsHookHREC( HREC hrec, HRC hrc, WORD wHooktype, UINT cResults, UINT cAlt, LPVOID rgresults )

Parameters

hrec

Module handle of the recognizer library whose results are being hooked.

hrc

Handle to the HRC object for the recognizer that hrec refers to.

wHooktype

Type of hook. This can be one of the following values:

RHH_STD

Standard results generated by GetResultsHRC.

RHH_BOX

Boxed results generated by GetBoxResultsHRC.

cResults

Count of results available.

cAlt

Count of box alternatives. This is valid only if wHooktype is RHH_BOX.

rgresults

An array of result objects. The object type depends on wHooktype. If RHH_STD, rgresults should be cast as LPHRCRESULT and the array receives cResults HRCRESULT objects. If RHH_BOX, rgresults should be cast as LPBOXRESULTS and the array receives cResults BOXRESULTS structures.

Return Value

The application hook function should return TRUE to indicate that it has processed the data and that the recognizer should do no further processing. In this case, it is the application's responsibility to destroy the results and inksets, if any; otherwise, the hook function should return FALSE.

See Also

SetResultsHookHREC


SetAlphabetHRC [New - Windows 95]
SetAlphabetHRC

2.0      [New - Windows 95]

Specifies which alphabet should be used in an HRC object.

int SetAlphabetHRC( HRC hrc, ALC alc, LPBYTE rgbfAlc )

Parameters

hrc

Handle to the HRC object.

alc

Alphabet. This value is one or more ALC_ values combined using the bitwise-OR operator.

rgbfAlc

Array of bits if alc contains ALC_USEBITMAP; otherwise, it can be NULL.

Return Value

Returns HRCR_OK if successful; otherwise, returns one of the following negative values:

Constant	Description
HRCR_ERROR	Invalid parameter or other error.
HRCR_MEMERR	Insufficient memory.
HRCR_UNSUPPORTED	The recognizer does not support this function.
Comments

Some recognizers may not support ALC_ values and alphabet priorities. An application should check for HRCR_UNSUPPORTED when using this function.

The following values may require Japanese, wide-character, or recognizer-specific support: ALC_DBCS, ALC_JIS1, ALC_KANJI, ALC_OEM, ALC_HIRAGANA, and ALC_KATAKANA. In addition, ALC_RESERVED is reserved for future use and is ignored. Recognizers, such as the Microsoft Handwriting Recognizer (GRECO.DLL) for default American English, can return HRCR_OK even if some of these values are set.

The size of the rgbfAlc array, if used, must be large enough to accommodate 256 bits (32 bytes). If the nth bit is set, then the nth ANSI character is recognizable. Bits representing characters less than 32 (space) currently have no meaning.

The ALC_GESTURE value is ignored, even if it is part of the alc parameter. See EnableGestureSetHRC.

For a description of alphabets and their relationship to a recognizer, see "Configuring the HRC" in Chapter 5, "The Recognition Process." For a list of alphabet codes, see Chapter 13, "Pen API Constants."

See Also

EnableGestureSetHRC, GetAlphabetHRC

SetAlphabetPriorityHRC, ALC_


SetAlphabetPriorityHRC [New - Windows 95]
SetAlphabetPriorityHRC

2.0      [New - Windows 95]

Specifies the priority of alphabet sets in an HRC object.

int SetAlphabetPriorityHRC( HRC hrc, ALC alc, LPBYTE rgbfalc )

Parameters

hrc

Handle to the HRC object.

alc

Alphabet priority. This value is one or more ALC_ values combined using the bitwise-OR operator.

rgbfalc

Address of a 256-bit (32-byte) buffer whose bits map to ANSI single-byte characters if alc contains ALC_USEBITMAP; otherwise, it can be NULL.

Return Value

Returns HRCR_OK if successful; otherwise, returns one of the following negative values:

Constant	Description
HRCR_ERROR	Invalid parameter or other error.
HRCR_MEMERR	Insufficient memory.
HRCR_UNSUPPORTED	The recognizer does not support this function.
Comments

Some recognizers may not support ALC_ values and priorities. An application should check for HRCR_UNSUPPORTED when using this function.

For a description of how a recognizer uses alphabet priority, see "Configuring the HRC" in Chapter 5, "The Recognition Process." For a list of alphabet codes, see Chapter 13, "Pen Application Programming Interface Constants."

See Also

GetAlphabetHRC, SetAlphabetHRC, GetAlphabetPriorityHRC, ALC_


SetBoxAlphabetHRC [New - Windows 95]
SetBoxAlphabetHRC

2.0      [New - Windows 95]

Specifies the alphabet codes to use for a range of boxes.

int SetBoxAlphabetHRC( HRC hrc, LPALC rgalc, UINT cAlc )

Parameters

hrc

Handle to an HRC object.

rgalc

An array of cAlc ALC_ values. The array is mapped onto boxes starting at box zero.

cAlc

Number of ALC_ values in rgalc. This should match the number of boxes. If this parameter is 0, SetBoxAlphabetHRC simply returns 0.

Return Value

Returns HRCR_OK if successful; otherwise, returns one of the following negative values:

Constant	Description
HRCR_ERROR	Invalid parameter or other error.
HRCR_MEMERR	Insufficient memory.
HRCR_UNSUPPORTED	The recognizer does not support this function.
Comments

SetBoxAlphabetHRC applies only when an HRC has been configured for box guides with the SetGuideHRC function. Although SetAlphabetHRC can also specify an alphabet set for boxed input, it attaches the same alphabet setting to all boxes indiscriminately. SetBoxAlphabetHRC offers greater control by allowing an application to set different alphabets for individual boxes of a single HRC.

Example

For example, consider a boxed entry on a requisition form that expects a part number consisting of five characters. The first two characters are uppercase letters, the next two are numerals, and the last character can be either another numeral or a lowercase revision code. The following example demonstrates how to configure the HRC for this hypothetical scenario:

#define  PART_LEN    5                  // Five characters in entry

HRC      hrcPart;                       // HRC for parts entry

GUIDE    guidePart;                     // GUIDE for parts entry

ALC      alcPart[PART_LEN];             // Array of ALC_ codes for entry

.

.                                   // Initialize the GUIDE here

.

guidePart.cHorzBox = PART_LEN;          // Number of boxes in entry

guidePart.cVertBox = 1;                 // Single row

guidePart.cyMid    = 0;                 // No midline

iret = SetGuideHRC( hrcPart, (LPGUIDE)&guidePart, 0 );

if (iret == HRCR_OK)

{

alcPart[0] = alcPart[1] = ALC_UCALPHA;  // Uppercase in boxes 1-2

alcPart[2] = alcPart[3] = ALC_NUMERIC;  // Numerals in boxes 3-4

alcPart[4] = ALC_LCALPHA | ALC_NUMERIC; // Lower or numeral in box 5

// Map alphabet codes onto boxes of parts number entry

SetBoxAlphabet( hrcPart, (LPALC)&alcPart, PART_LEN );

}

See Also

GetAlphabetHRC, SetAlphabetHRC, ALC_


SetGlobalRC [New - Windows 95]
SetGlobalRC

1.0     2.0      [New - Windows 95]

Sets the current default settings for the global RC structure. In version 2.0 of the Pen API, the RC structure is made obsolete by the HRC object.

Note  This function is provided only for compatibility with version 1.0 of the Pen API and will not be supported in future versions.

UINT SetGlobalRC( LPRC lprc, LPSTR lpszDefRecog, LPSTR lpszDefDict )

Parameters

lprc

Address of an RC structure or NULL.

lpszDefRecog

Address of string specifying the name of the default recognizer module (maximum 128 bytes).

lpszDefDict

Address of a string specifying the default dictionary path. The list should end with two null characters.

Return Value

Returns the value SGRC_OK if successful. If an error occurs, the return value consists of one or more of the following values, combined using the bitwise-OR operator.

Constant	Description
SGRC_USER	An invalid user name was found in the supplied RC structure. The call to SetGlobalRC has no effect.
SGRC_PARAMERROR	One or more invalid parameters were detected. The call to SetGlobalRC has no effect.
SGRC_RC	The supplied recognition context lprc has entries, other than the user name, that contain invalid settings for a global recognition context. The supplied recognition context is ignored.
SGRC_RECOGNIZER	The supplied recognizer module name lpszDefRecog is invalid or the recognizer cannot be loaded. The supplied recognizer module name is ignored.
SGRC_DICTIONARY	The supplied dictionary path lpszDefDict is invalid or some dictionaries on the path cannot be loaded. The supplied dictionary path is ignored.
SGRC_INIFILE	An error was encountered while saving the new global recognition context settings to the pen section of the system registry. The new settings are lost after rebooting Windows.
Comments

Because the default RC values are shared among all version 1.0 applications running, the values should be changed only through the Control Panel. Whenever a change is made to the global RC values, the WM_PENMISCINFO message is sent to all top-level windows. The wParam and lParam values are not used, and they are set to 0.

Any of the parameters can be NULL to indicate that the calling application does not want the value changed.

SetGlobalRC uses only the following members of the RC structure pointed to by the lprc parameter:

clErrorLevel lPcm (PCM_TIMEOUT and PCM_RANGE bits)  lpLanguage lpUser nInkWidth rgbInk wCountry wIntlPreferences wRcDirect wRcPreferences wTimeOut wTryDictionary

When InitRC is called for a new recognizer from within the SetGlobalRC call, the RC structure that is passed in contains the new values for all members except hrec and rglpdf. No new recognizer and dictionaries have been set up at this point.

When a version 1.0 application receives a WM_PENMISCINFO message, it should call ConfigRecognizer with a WCR_RCCHANGE subfunction request. This should be done for all recognizers that the application has loaded, excluding the default recognizer. The RC Manager calls ConfigRecognizer in the new default recognizer with a WCR_RCCHANGE subfunction request.

SetGlobalRC does not save the RCP_MAPCHAR flag in the wRcPreferences member of the RC structure to the system registry. The RCP_MAPCHAR flag is reflected in the global RC for the current session only.

See Also

InitRC,  GetGlobalRC,  RC


SetGuideHRC [New - Windows 95]
SetGuideHRC

2.0      [New - Windows 95]

Sets a guide structure into an HRC object.

int SetGuideHRC( HRC hrc, LPGUIDE lpguide, UINT nFirstVisible )

Parameters

hrc

Handle to the HRC object.

lpguide

Pointer to a GUIDE structure, or NULL. All coordinates are in screen coordinates.

nFirstVisible

For boxed controls, nFirstVisible refers to the first visible box (leftmost and topmost for left-right, top-down languages like English). For other controls, this is the first visible character position (leftmost for English) in a single-line control, and the first visible line (topmost for English) in multiline controls.

Return Value

Returns HRCR_OK if successful; otherwise, returns one of the following negative values:

Constant	Description
HRCR_ERROR	Invalid parameter or other error.
HRCR_INVALIDGUIDE	The guide structure is invalid.
HRCR_MEMERR	Insufficient memory.
Comments

This function is useful for doing boxed recognition. The GUIDE structure defines the size and position of the boxes. The nFirstVisible parameter notifies the recognizer which is the first visible character position (single-line controls) or line (multiline controls) in case the contents were scrolled. The writing direction affects the meaning of this value.

If lpguide is NULL, or if all the members in the GUIDE structure are 0, the recognizer does not use guides (free input).

See Also

GetGuideHRC, GUIDE


SetInternationalHRC [New - Windows 95]
SetInternationalHRC

2.0      [New - Windows 95]

Sets the country, language, and script direction into a recognition context HRC.

int SetInternationalHRC( HRC hrc, UINT uCountry, LPCSTR lpszLangCode, UINT fuFlags, UINT uDir )

Parameters

hrc

Handle to the HRC object.

uCountry

The country code. A value of 0 indicates that this value should not be set.

lpszLangCode

A three-letter, null-terminated string identifying the language (for example, "enu" or "fra"), or NULL. A value of NULL indicates that the language code should not be changed. For a list of three-letter language identifiers, refer to Volume 1 of the Programmers Reference in the Windows Software Development Kit.

fuFlags

Flags. can be either SIH_ALLANSICHAR to indicate the user intends to use the entire ANSI character set, or 0.

uDir

The script direction. This parameter specifies which primary and secondary writing directions to set. The default directions are left to right for the primary direction and top to bottom for the secondary. A value of 0 indicates that the writing direction should not be changed. Possible values for uDir are:

Constant	Description
SSH_RD	Left to right and down (English).
SSH_RU	Left to right and up.
SSH_LD	Right to left and down (Hebrew).
SSH_LU	Right to left and up.
SSH_DL	Down and to the left (Chinese).
SSH_DR	Down and to the right (Chinese).
SSH_UL	Up and to the left.
SSH_UR	Up and to the right.
Return Value

Returns HRCR_OK if successful; otherwise, returns one of the following negative values:

Constant	Description
HRCR_ERROR	Invalid parameter or other error.
HRCR_MEMERR	Insufficient memory.
HRCR_UNSUPPORTED	The recognizer does not support this function.
Comments

Setting fuFlags to the value of SIH_ALLANSICHAR indicates the recognizer should interpret text written in any language based on ANSI characters. To constrain recognition to a particular language, an application should set fuFlags to 0 and provide the appropriate language code in lpszLangCode.

SetInternationalHRC overrides the default ALLANSICHAR setting in the recognizer set by ConfigHREC for the life of the HRC object. ConfigHREC should be used to change the default value.

See Also

GetInternationalHRC, ConfigHREC


SetMaxResultsHRC [New - Windows 95]
SetMaxResultsHRC

2.0      [New - Windows 95]

Sets the maximum number of guesses a recognizer should make when interpreting pen data. When the recognizer formulates this number of results, the recognition process ends.

int SetMaxResultsHRC( HRC hrc, UINT cMaxResults )

Parameters

hrc

Handle to the HRC object for the recognizer.

cMaxResults

The maximum number of results a recognition context should generate. This value must be greater than 0.

Return Value

Returns HRCR_OK if successful; otherwise, returns one of the following negative values:

Constant	Description
HRCR_ERROR	Invalid parameter or other error.
HRCR_MEMERR	Insufficient memory.
HRCR_UNSUPPORTED	The recognizer does not support this function.
Comments

Subsequent calls to SetMaxResultsHRC override any previous settings. If the application does not call SetMaxResultsHRC to explicitly set a maximum value, the default number of results generated is 1.

See Also

GetMaxResultsHRC, CreateCompatibleHRC


SetPenAppFlags [New - Windows 95]
SetPenAppFlags

2.0      [New - Windows 95]

An application calls this function to set pen-specific properties that apply globally to the application. This function replaces and enhances the RegisterPenApp function from version 1.0 of Pen Windows.

void SetPenAppFlags( UINT fuFlags, UINT uVersion )

Parameters

fuFlags

Flags specifying application options. The following flags can be combined by using the bitwise-OR operator:

Constant	Description
RPA_HEDIT	Specifies that the system should treat any EDIT-class controls in the application as having HEDIT class.
RPA_KANJIFIXEDBEDIT	Boxed edit controls are a fixed size appropriate for use with kanji. (Japanese version only.)
RPA_DBCSPRIORITY	By default, double-byte equivalents of single-byte characters (as used in Japan) are preferred in recognition results.
RPA_SBCSPRIORITY	By default, single-byte characters are preferred in recognition results. (Japanese version only.)
RPA_DEFAULT	Specifies default pen behavior for the application. This includes RPA_HEDIT.
uVersion

The Pen API version number. The nonzero value PENVER causes the application to be registered with Windows. A value of 0 unregisters the application.

Return Value

This function does not return a value.

Comments

SetPenAppFlags should be called when an application starts with PENVER for the uVersion parameter. PENVER is the Pen API version number, defined in PENWIN.H.

PENVER ensures that the structures used are appropriate for the version of the Pen API for which the application was compiled. In version 1.0, uVersion was a BOOL value, so by default the version number was 0x0001. Beginning with Pen API version 2.0, PENVER contains the major release number in the HIBYTE and the minor release number in the LOBYTE. Thus, for version 2.0, PENVER is defined as 0x0200.

When an application terminates, it should call SetPenAppFlags with uVersion set to 0. An application can unregister itself in this way more than once without error to accommodate alternative exit code paths.

An application can call GetPenAppFlags to determine which flags were set by an earlier call to SetPenAppFlags. However, normally only the system requires this information.

Applications written specifically for Windows 95 and later Windows versions automatically get RPA_DEFAULT so that any edit controls created by such applications become pen-aware.

See Also

GetPenAppFlags


SetPenHook [New - Windows 95]
SetPenHook

1.0     2.0      [New - Windows 95]

Installs and removes a pen packet hook. This function is typically used by system-level applications such as Control Panel applications.

BOOL SetPenHook( HKP hkpOp, LPFNRAWHOOK lpfn )

Parameters

hkpOp

Operation to be performed. This parameter can be HKP_SETHOOK to install a hook or HKP_UNHOOK to remove a function from the hook list.

lpfn

Pointer to callback function to handle pen packets.

Return Value

Returns TRUE if successful or FALSE if GetPenInput is unable to set or remove the hook. The callback function returns FALSE to cancel the processing of a pen packet.

Comments

The pen device generates approximately 100 hardware interrupts per second. At each interrupt, the device sends data to the pen driver, which organizes the data into a pen packet. Each packet contains the x- and y-coordinates of the current pen position, the time, and possibly extra OEM data such as pen pressure, angle, and so forth. The pen device may require more than one hardware interrupt to send all the information for a single packet, so the rate at which the driver sends pen packets may be less than the rate of interrupts generated by the pen hardware.

When it has created a pen packet, the driver passes it to the system, which buffers the packets in an internal queue as they arrive from the pen driver. The internal queue is informally known as the "ten-second buffer" to indicate how much data it can hold before overflowing. An application must call GetPenInput regularly to remove data from the queue.

SetPenHook enables an application to examine, modify, or cancel pen packets as they arrive from the pen driver before GetPenInput sees them.

See Also

SetPenHookCallback, SetResultsHookHREC, GetPenInput


SetPenHookCallback [New - Windows 95]
SetPenHookCallback

1.0     2.0      [New - Windows 95]

SetPenHookCallback represents the name of the callback function that the lpfn argument of SetPenHook points to. An application can use any name.

BOOL lpfn SetPenHookCallback( LPPENPACKET lppp )

Parameters

lppp

Far pointer to the most recent pen packet received from the pen driver.

Return Value

Returns TRUE to continue processing, FALSE to cancel pen packet.

Comments

For a definition of pen packet, see the description for SetPenHook.

At each interrupt, the system adds the latest packet from the pen driver to an internal queue. It then calls the application's SetPenHookCallback callback function, providing it with a pointer to the latest packet in the queue. This enables the callback function to examine, modify, or cancel each pen packet as it arrives from the pen driver.

To get the pen packet data from a version 2.0 pen driver, defined as OEM_PENPACKET, simply cast the LPPENPACKET value passed into this function to the type LPOEM_PENPACKET. The pen services detect the pen driver version automatically and return the correct data pen packet data type.

See Also

SetPenHook, PENPACKET


SetPenMiscInfo [New - Windows 95]
SetPenMiscInfo

1.0     2.0      [New - Windows 95]

Sets constants pertaining to the pen system.

LONG SetPenMiscInfo( UINT wParam, LPARAM lParam )

Parameters

wParam

Specifies the identifier of the pen system measurement to set. The identifier must be a PMI_ value, and may be combined with PMI_SAVE (to force an immediate initialization file update) using the bitwise-OR operator for some values. See the following table for the possible PMI_ values in wParam.

lParam

Specifies the value of the pen system measurement to set. Depending on the value of wParam (listed in the first column of the table below), lParam can be the address of a structure or a value, as described here:

wParam constant	lParam description
PMI_BEDIT	lParam is the address of a BOXEDITINFO structure.
PMI_ENABLEFLAGS	lParam is a WORD value.
PMI_PENTIP	lParam is the address of a PENTIP structure.
PMI_TIMEOUT	lParam is a UINT value.
PMI_TIMEOUTGEST	lParam is a UINT value.
PMI_TIMEOUTSEL	lParam is a UINT value.
Return Value

Returns PMIR_OK if successful; otherwise, returns one of the following negative error values:

Constant	Description
PMIR_INDEX	wParam is out of range.
PMIR_INIERROR	Error writing to PENWIN.INI file.
PMIR_INVALIDBOXEDITINFO	BOXEDITINFO structure is invalid.
PMIR_NA	Support for this value of wParam is not available.
PMIR_VALUE	lParam is invalid.
Comments

The type of information SetPenMiscInfo sets depends on wParam. The function is provided for system applications such as Control Panel. User applications should not generally call SetPenMiscInfo.

A WM_PENMISCINFO message is posted to all top-level windows whenever SetPenMiscInfo successfully changes a setting, forwarding the value for wParam. In the case of PMI_BEDIT, a WM_PENMISC message is also broadcast to ensure compatibility with version 1.0 of the Pen API. The wParam is set to PMSC_BEDITCHANGE and lParam is a far pointer to a BOXEDITINFO structure.

SetPenMiscInfo cannot set all the values available in GetPenMiscInfo because certain values are determined by the system. These values are PMI_SYSREC, PMI_CXTABLET, PMI_CYTABLET, PMI_SYSFLAGS, PMI_TICKREF, PMI_INDEXFROMRGB, and PMI_RGBFROMINDEX.

The flag PMI_SAVE can be combined with the wParam identifier for the following values: PMI_BEDIT, PMI_ENABLEFLAGS, PMI_PENTIP, PMI_TIMEOUT, PMI_TIMEOUTGEST, and PMI_TIMEOUTSEL. This forces Windows to immediately update its initialization information.

Example

The following code sample changes the pen color to red and the time out to a half second (500 milliseconds), then forces a save-file update:

PENTIP tip;

GetPenMiscInfo( PMI_PENTIP, (LPARAM)(LPPENTIP) &tip );

tip.rgb = RGB(255, 0, 0);

SetPenMiscInfo( PMI_PENTIP, (LPARAM)(LPPENTIP) &tip );

SetPenMiscInfo( PMI_TIMEOUT | PMI_SAVE, (LPARAM)500 );

See Also

GetPenMiscInfo,  WM_PENMISCINFO,  PMI_


SetRecogHook [New - Windows 95]
SetRecogHook

1.0     2.0      [New - Windows 95]

Installs and removes a recognition hook. This function works only for Pen API version 1.0 recognizers accessed through Recognize or RecognizeData.

Note  This function is provided only for compatibility with version 1.0 of the Pen API and will not be supported in future versions. Use SetResultsHookHREC instead.

BOOL SetRecogHook( UINT uScope, UINT uSetOp, HWND hwndHook )

Parameters

uScope

Scope of hook. The hook parameter uSetOp determines the scope of the hook. The following table lists the HWR_ values for uSetOp:

Constant	Description
HWR_RESULTS	The hook window receives a WM_HOOKRCRESULT message before a WM_RCRESULT message is sent to the target window.
HWR_APPWIDE	The hook window receives the message WM_HOOKRCRESULT before a WM_RCRESULT message is sent to the target window if the target window belongs to the same task as the window that set an HWR_APPWIDE hook. This is useful for implementing application-wide gestures.  The RCRT_ALREADYPROCESSED flag is set in the wResultsType member of the RCRESULTS structure sent with WM_RCRESULT if an application-wide hook has already processed the data.
uSetOp

Parameter to determine whether hook is set or removed. The operation parameter uSetOp determines whether the hook is set or removed. The following table lists the HKP_ values for uScope:

Constant	Description
HKP_SETHOOK	Installs a hook.
HKP_UNHOOK	Removes function from hook list.
hwndHook

Handle to a window.

Return Value

Returns TRUE if successful; otherwise, FALSE.

Comments

SetRecogHook enables a version 1.0 application to examine the results of recognition before they are sent to the target application.

The hook message is WM_HOOKRCRESULT. The wParam and lParam parameters are the same as for the WM_RCRESULT message. If the window procedure that receives the WM_HOOKRCRESULT message returns FALSE, the message WM_HOOKRCRESULT is not sent to any of the remaining hooks in the chain.

No drawing should occur during the processing of the WM_HOOKRCRESULT and before recognition is complete. Drawing at these times could cause timing problems, with ink reappearing in formerly invisible controls as they are redrawn.

See Also

SetResultsHookHREC


SetResultsHookHREC [New - Windows 95]
SetResultsHookHREC

2.0      [New - Windows 95]

Sets up a hook callback function for recognition results.

HRECHOOK SetResultsHookHREC( HREC hrec, HRCRESULTHOOKPROC lpfnHook )

Parameters

hrec

Module handle of the recognizer library whose results are to be hooked. If hrec is set to NULL, the hook function specified in lpfnHook receives results from the system default recognizer. If hrec is set to SRH_HOOKALL, the hook function receives results for all recognizers the application has installed, including the system recognizer.

lpfnHook

Address of the hook function.

Return Value

Returns a handle to the installed hook if successful; otherwise, the return value is NULL. The application must provide this handle when calling UnhookResultsHookHREC to remove the hook.

Comments

An application can set multiple hooks. The system calls the hooks in reverse order —that is, the most-recently-set hook is called first, then the previous hook, and so on. If a hook function captures a result, the function that requested the results returns HRCR_HOOKED to the application.

See Also

ResultsHookHREC, UnhookResultsHookHREC


SetStrokeAttributes [New - Windows 95]
SetStrokeAttributes

2.0      [New - Windows 95]

Sets attributes of a stroke or of a class of strokes in an HPENDATA object.

int SetStrokeAttributes( HPENDATA hpndt, UINT iStrk, LPARAM lParam, UINT uOption )

Parameters

hpndt

Handle to the HPENDATA object.

iStrk

Zero-based stroke index. A value of IX_END can be used to specify the last available stroke in the pen data.

lParam

A pointer to a structure (cast to the LPARAM type), or a byte, word, or double-word value, depending on uOption. This parameter cannot be NULL.

uOption

Specifies the attributes to set. This parameter has one of the following values:

Constant	Description
SSA_DOWN	Set the up and down state of the pen tip for the stroke specified by iStrk. lParam is nonzero to make it a downstroke or 0 to make it an upstroke.
SSA_PENTIP	Set the pen-tip characteristics (color, width, nib type) used by the stroke specified by iStrk. lParam is a pointer to a PENTIP structure. If this attribute does not already exist in the stroke class table, a new entry for this type of stroke is created. There can be up to 255 different types of strokes.
SSA_PENTIPCLASS	Set the pen-tip characteristics (color, width, nib) for all strokes of which the stroke specified by iStrk is a member. lParam is a pointer to a PENTIP structure. If the new type already exists in the stroke class table, the types are merged.
SSA_SELECT	Set the selection status of the stroke specified by iStrk. lParam is nonzero to select it or 0 to deselect it.
SSA_TIME	Set the absolute time of the stroke. lParam is a pointer to an ABSTIME structure. The sec member of the ABSTIME structure specifies the number of seconds since Jan 1, 1970, and the ms member specifies the number of milliseconds offset from that time to the beginning of the stroke.
SSA_USER	Set the user value for the stroke specified by iStrk. lParam is a BYTE, WORD, or DWORD value, and the pen data must have been created with the corresponding size allocated for user values.
SSA_USERCLASS	Set the user value for the class of strokes of which the stroke specified by iStrk is a member. lParam is a BYTE, WORD, or DWORD value, and the pen data must have been created with the corresponding size allocated for user values.
Return Value

Returns PDR_OK if successful; otherwise, returns one of the following negative values:

Constant	Description
PDR_COMPRESSED	Pen data is compressed.
PDR_ERROR	Parameter or other unspecified error.
PDR_MEMERR	Memory error.
PDR_PNDTERR	Invalid pen data.
PDR_SCTERR	Stroke class table may be full, or related error.
PDR_STRKINDEXERR	Invalid stroke index.
PDR_TIMESTAMPERR	Timing information was removed.
PDR_VERSIONERR	Could not convert old pen data.
Comments

The bounding rectangle of the pen data is recalculated each time the SSA_DOWN option is used, because the rectangle represents the bounds of only the pen-down points. Setting a pen-up point to the down state simply adds (union) the bounding rectangles of the existing pen data and the stroke. Setting a pen-down point to the up state is more calculation-intensive, however, since the bounding rectangle must be calculated from all of the remaining strokes.

See Also

CreatePenDataEx, GetStrokeAttributes, GetStrokeTableAttributes, SetStrokeTableAttributes, PENTIP


SetStrokeTableAttributes [New - Windows 95]
SetStrokeTableAttributes

2.0      [New - Windows 95]

Sets attributes of a stroke's class within an HPENDATA object. (The class is an entry in a table stored in the PENDATAHEADER structure. Modifying the table entry affects all the strokes described by the entry.)

int SetStrokeTableAttributes( HPENDATA hpndt, UINT iTblEntry, LPARAM lParam, UINT uOption )

Parameters

hpndt

Handle to the HPENDATA object.

iTblEntry

Zero-based table index to the class entry in the pen data header.

lParam

A pointer to a structure (cast to the LPARAM type), or a byte, word, or doubleword value, depending on uOption. This parameter cannot be NULL.

uOption

Specifies the attributes to set. This parameter can be one of the following:

SSA_PENTIPTABLE

Set the pen-tip characteristics (color, width, nib) of the class of strokes specified by iTblEntry. lParam is a pointer to a PENTIP structure. All the strokes sharing this entry in the stroke class table receive the new pen-tip attribute.

SSA_USERTABLE

Set the user value, if any, of the class of strokes specified by iTblEntry. lParam is a byte, word, or doubleword value, and the pen data must have been created with the corresponding size allocated for user values. All the strokes sharing this stroke class table entry receive the new user value.

Return Value

Returns PDR_OK if successful; otherwise, returns one of the following negative values:

Constant	Description
PDR_COMPRESSED	Pen data is compressed.
PDR_ERROR	Parameter or other unspecified error.
PDR_MEMERR	Memory error.
PDR_PNDTERR	Invalid pen data.
PDR_SCTERR	Stroke class table may be full, or related error.
PDR_VERSIONERR	Could not convert old pen data.
See Also

CreatePenDataEx, GetStrokeAttributes, GetStrokeTableAttributes, SetStrokeAttributes, PENTIP


SetWordlistCoercionHRC [New - Windows 95]
SetWordlistCoercionHRC

2.0      [New - Windows 95]

Specifies to what degree input must match a word list set into an HRC. SetWordlistCoercionHRC determines the influence a recognizer's word list or dictionary has on the recognizer's guesses.

int SetWordlistCoercionHRC( HRC hrc, UINT uCoercion )

Parameters

hrc

Handle to the HRC object.

uCoercion

Coercion flag. This can be one of the following:

SCH_ADVISE

The word list serves only to advise the recognizer, but lacks a strong degree of influence. Recognition results are not strongly coerced to match the word list.

SCH_FORCE

If the recognizer's guess is not found in the word list, the closest matching entry in the list is returned. For example, if the recognizer interprets writing as "Cana", it returns "Canada" from a word list of country names.

SCH_NONE

Do not coerce. This flag can be used to turn off a previous request.

Return Value

Returns HRCR_OK if successful; otherwise, returns one of the following negative values:

Constant	Description
HRCR_ERROR	Invalid parameter or other error, including an attempt to set coercion with no word lists set into the recognition context.
HRCR_MEMERR	Insufficient memory.
HRCR_UNSUPPORTED	The recognizer does not support this function.
Comments

The default type of coercion a recognizer provides is SCH_ADVISE. That is, results are not strongly coerced to any word list that might be set into a recognition context.

Coercion is used only if a word list (HWL) has actually been set into an HRC with SetWordlistHRC, or if the recognizer's dictionary is enabled by EnableSystemDictionaryHRC. If the HRC is configured with a word list and the recognizer's dictionary is also enabled, coercion is done on both; the priority depends on the recognizer.

See Also

CreateHWL, GetWordlistCoercionHRC


SetWordlistHRC [New - Windows 95]
SetWordlistHRC

2.0      [New - Windows 95]

Sets a word list into a recognition context HRC object.

int SetWordlistHRC( HRC hrc, HWL hwl )

Parameters

hrc

Handle to the HRC object.

hwl

Handle to a word list to use, or NULL. A value of NULL means that the recognizer should not constrain recognition based on any word list, including its own dictionary.

Return Value

Returns HRCR_OK if successful; otherwise, returns one of the following negative values:

Constant	Description
HRCR_ERROR	Invalid parameter or other error.
HRCR_MEMERR	Insufficient memory.
HRCR_UNSUPPORTED	The recognizer does not support this function.
Comments

Specifying NULL for hrc does not destroy the word list specified by hwl. Applications must call DestroyHWL to destroy a word list.

Only one word list can be set into an HRC at a time. This is independent of the recognizer's dictionary, which can be manipulated through the function EnableSystemDictionaryHRC.

For a description of word lists and how a recognizer uses them, see "Configuring the HRC" in Chapter 5, "The Recognition Process."

See Also

CreateHWL, DestroyHWL


ShowKeyboard [New - Windows 95]
ShowKeyboard

1.0     2.0      [New - Windows 95]

Shows or hides the on-screen keyboard. (Not supported in Japanese version.)

Note  This function is provided only for compatibility with version 1.0 of the Pen API, and will not be supported in future versions. It is not supported for 32-bit applications. Applications should interface directly with the on-screen keyboard.

BOOL ShowKeyboard( HWND hwnd, UINT wCommand, LPPOINT lppt, LPSKBINFO lpSKBInfo )

Parameters

hwnd

Handle of window invoking the on-screen keyboard.

wCommand

A show request and optional keypad. The values for the show requests are listed in the "Comments" section below.

lppt

Address of a POINT structure containing the keyboard position in screen coordinates. If NULL, the keyboard appears centered on the display.

lpSKBInfo

Address of an SKBINFO structure to be filled with values for the current keyboard. This parameter is ignored if NULL. If the hwnd member of the SKBINFO structure is NULL, no on-screen keyboard has been loaded.

Return Value

Returns TRUE if successful; otherwise FALSE.

Comments

Any user action on the keyboard itself overrides the function requests. For example, if the user closes the on-screen keyboard, the keyboard becomes unregistered for all windows in all applications. If the user minimizes the keyboard, the active SKBINFO structure is changed to reflect the new state.

ShowKeyboard tracks registration information for up to 20 window handles. If one application displays the keyboard and then another one does the same thing, both applications must request that the keyboard be hidden before it actually disappears.

The following SKB_ requests can be specified in the wCommand parameter:

Constant	Description
SKB_HIDE	Hides the on-screen keyboard. This request may not actually hide the keyboard if another application is also using it. The command decrements the use count for the keyboard. SKB_HIDE automatically loads the on-screen keyboard if it is not already present.
SKB_QUERY	Returns the current state of the keyboard pointed to  by the lpSKBInfo parameter without invoking a new keyboard state. This command does not automatically load the on-screen keyboard.
SKB_SHOW	Shows the on-screen keyboard in a restored state at  the most recently used screen location. This command increments a window-use count. SKB_SHOW automatically loads the on-screen keyboard if it is not present.
The SKB_SHOW command in the wCommand parameter can be combined using the bitwise-OR operator with any of the command or keypad requests listed in the following tables:

Constant	Description
SKB_CENTER	Centers the keyboard on the display. This command  has higher priority than SKB_MOVE.
SKB_MINIMIZE	Displays the on-screen keyboard in a minimized state. This command can be used with SKB_CENTER or SKB_MOVE. If it is used with SKB_MOVE, the location specified will be used when the keyboard is restored.
SKB_MOVE	Moves the keyboard to the location specified by the lppt parameter. If lppt is NULL, the keyboard is centered on the screen. If it is not NULL, lppt specifies a pointer to the x and y screen coordinates of the upper-left corner of the restored keyboard.
The following keypad requests can be used with SKB_SHOW in the wCommand parameter. The SKB_BASIC, SKB_FULL, and SKB_NUMPAD constants can not be combined with the OR operator:

Constant	Description
SKB_BASIC	Switches the keyboard to a partial keyboard with no extended keys.
SKB_FULL	Switches the keyboard to the full 101-key display.
SKB_NUMPAD	Switches the keyboard to a partial keyboard consisting only of ESC, TAB, SHIFT, and the numeric keypad.
The following three bitmaps are provided for owner-draw push buttons that can be used to invoke the on-screen keyboard. The application must process WM_DRAWITEM and other button-related code. On-screen keyboard push buttons should behave the same way as other standard buttons (for example, the Minimize button) and take the appropriate action when a button-up message is received following a button-down message.

Constant	Description
OBM_SKBBTNUP	Push button is up.
OBM_SKBBTNDOWN	Push button is down.
OBM_SKBBTNDISABLED	Push button is disabled.
Example

The up bitmap, for example, can be loaded as shown in the following code sample:

HANDLE hDLL = GetSystemMetrics( SM_PENWINDOWS );

HBITMAP hBitmap = LoadBitmap( hDLL,

MAKEINTRESOURCE(OBM_SKBBTNUP) );

The application must call the Windows DeleteObject function to delete each bit-map handle returned by the Windows LoadBitmap function.

The button should be left in the up state after it is released. If the user closes the keyboard and the buttons are up, they will still be up the next time the keyboard is opened. The following code sample retrieves the current keyboard and restores the current state:

#include <penwin.h>

if (ShowKeyboard( hwnd, SKB_SHOW, NULL, NULL)) // Nonzero: no error.

{

.

.                        // Perform some tasks.

.

ShowKeyboard( hwnd, SKB_HIDE, NULL, NULL );

}

else

ErrorMsg( "Unable to use Screen Keyboard" );

The following code sample moves the keyboard and then puts it back into its starting position:

SKBINFO skbinfo;

WORD wCommand = SKB_SHOW | SKB_MOVE;

POINT pnt;

pnt.x = wSKBLeft;    // Initialize point.

pnt.y = wSKBTop;

// Show the keyboard.

ShowKeyboard( hwnd, wCommand, &pnt, &skbinfo );

.

.

.

// Now restore the keyboard.

if (skbinfo.fVisible)

wCommand = SKB_SHOW | SKB_MOVE |

(skbinfo.fMinimized ? SKB_MINIMIZED : 0);

else

wCommand = SKB_HIDE;

ShowKeyboard( hwnd, wCommand, (LPPOINT)(&skbinfo.rect), NULL) ;


StartInking [New - Windows 95]
StartInking

2.0      [New - Windows 95]

Starts inking feedback while pen input is being collected.

int StartInking( HPCM hpcm, UINT idEvent, LPINKINGINFO lpinkinginfo )

Parameters

hpcm

Handle to the current collection. This is the return value from StartPenInput.

idEvent

The identifier of the packet at which to start inking.

lpinkinginfo

Address of an INKINGINFO structure, used to specify the characteristics of the ink. This parameter can be NULL to use the default ink characteristics. Otherwise, the structure's cbSize member must be initialized with sizeof( INKINGINFO ).

Return Value

Returns PCMR_OK if inking started successfully; otherwise, returns one of the following:

Constant	Description
PCMR_DISPLAYERR	There is no display device, or it was unable to ink at this time, or there was an error in setting the pen-tip characteristics.
PCMR_ERROR	The INKINGINFO structure contains invalid values, or there was some other unspecified error.
PCMR_INVALIDCOLLECTION	The hpcm handle is invalid because the calling application did not start input by calling StartPenInput.
PCMR_INVALID_PACKETID	The idEvent parameter is invalid.
Comments

An application calls StartInking to track pen movement while the pen tip is down. When pen input is started by calling the StartPenInput function, Windows initializes the internal INKINGINFO structure as follows:

•	The wFlags member is set to PII_INKPENTIP | PII_INKCLIPRECT.

•	The tip member is set to the system default pen tip, as obtained by calling the GetPenMiscInfo function.

•	The rectClip member is set to the client area, in screen coordinates, of the window that was used in the call to the StartPenInput function.

The first call to StartInking with the lpinkinginfo parameter set to NULL starts inking with the settings listed above. If the calling application uses a non-NULL value for lpinkinginfo, the appropriate internal inking parameters are modified before inking starts, depending on the flags set in the wFlags member of the INKINGINFO structure.

Whenever StartInking is called, the current settings of the internal inking structure are added to or replaced. Specific values must be set in the members of INKINGINFO to disable them. Refer to the description of each member in the INKINGINFO structure for these values.

If a region is passed in for clipping or stopping the ink, the application must destroy the region. Since a copy is made, the region can be destroyed immediately following the call to StartInking. The application can specify either a clip region or a clip rectangle. Specifying both will result in the clip rectangle being ignored.

Example

The following code example changes the inking tip from the default (as set by a call to StartPenInput) to red ink, 5 pixels wide. It also adds an inkstop rectangle (inking stops if the pen touches down inside the inkstop rectangle). The clipping rectangle remains unchanged from the default settings.

INKINGINFO inkinginfo;

inkinginfo.cbSize           = sizeof( INKINGINFO );

inkinginfo.wFlags           = PII_INKPENTIP | PII_INKSTOPRECT;

inkinginfo.tip.cbSize       = sizeof( PENTIP );

inkinginfo.tip.rgb          = RGB( 255,0,0 );

inkinginfo.tip.bwidth       = 5;

inkinginfo.rectInkStop.left = rectInkTop.top = 0;

inkinginfo.rectInkStop.right = rectInkTop.bottom = 100;

ClientToScreen( hwnd, (LPPOINT)&(inkinginfo.rectInkStop) );

ClientToScreen( hwnd, (LPPOINT)&(inkinginfo.rectInkStop.right) );

StartInking( hpcm, wEventRef, &inkinginfo );

See Also

INKINGINFO, StartPenInput, StopInking


StartPenInput [New - Windows 95]
StartPenInput

2.0      [New - Windows 95]

Begins collecting information from the pen input stream.

HPCM StartPenInput( HWND hwnd, UINT idEvent, LPPCMINFO lppcmInfo, LPINT lpiErrRet )

Parameters

hwnd

Handle of the window that receives the WM_PENEVENT messages generated by StartPenInput.

idEvent

Identifies the packet in the global queue of pen packets maintained internally by the system. The idEvent is the low-order word of the value returned from the GetMessageExtraInfo function when processing a WM_LBUTTONDOWN message. For a definition of pen packet, see the description for SetPenHook.

lppcmInfo

Address of a PCMINFO structure. If NULL, the system creates a default PCMINFO structure with the following values:

Constant	Description
dwPcm	PCM_RECTBOUND | PCM_TIMEOUT | PCM_TAPNHOLD
rectBound	The bounding rectangle of the window identified by hwnd These values determine that the input session (a) terminates when pen activity ceases for a specified time-out period; (b) terminates when the pen moves outside the bounds of the window; or (c) does not begin at all if the user taps and holds the pen for a specified time-out period (about one-half second). This "tap-and-hold" gesture switches the system from input mode to selection mode. Usually, the cursor changes from a pen (indicating input) to an upside-down arrow (indicating selection) to acknowledge the switch. Subsequent pen movement then behaves as a mouse with the left button held down. This allows the user to make selections as though dragging the mouse.
lpiErrRet

Address of an integer that receives a return code when StartPenInput terminates. If NULL, no return code is provided. If not NULL, the return code is one of the following values:

Constant	Description
PCMR_OK	Pen collection was successfully started.
PCMR_ALREADYCOLLECTING	StartPenInput has already been called for this session.
PCMR_ERROR	Illegal parameter or unspecified error.
PCMR_INVALID_PACKETID	Invalid idEvent parameter.
PCMR_SELECT	Tap-and-hold gesture detected. Collection is not started, as described in the description of the lppcmInfo parameter.
PCMR_TAP	The pen has briefly tapped the tablet. This event may be inadvertent and in any case does not indicate that the user has started to write; therefore, collection is not started.
Return Value

Returns a handle to the application's queue of pen packets, if successful. Returns NULL to indicate an error or the detection of a tap or press-and-hold condition.

Comments

When this function returns successfully, Windows creates a queue of pen packets for the calling application. All subsequent pen packets from the pen device, beginning with the packet identified by the idEvent argument, are placed into the queue. Until a termination condition occurs (as specified in the lppcmInfo parameter), or until the application calls StopPenInput, the queue continues to receive all the packets generated by the pen device as the pen moves.

An application can retrieve all the pen input in its queue of pen packets but should never destroy the queue.

In event mode (the default mode), the collection session specified by the hpcm of the GetPenInput function becomes invalid when the WM_PENEVENT message (with the PE_TERMINATED submessage) is removed from the application's message queue. This message is posted to the application's message queue either as a consequence of automatic termination or a call to StopPenInput.

In polling mode, the application's queue of pen packets is destroyed (and the hpcm of GetPenInput becomes invalid) after a successful call to StopPenInput or a termination return value from the GetPenInput function.

If lppcmInfo is NULL, a default PCMINFO structure is established with the dwPcm member set to PCM_RECTBOUND | PCM_TIMEOUT | PCM_TAPHOLD, the rectBound member set to the bounds of hwnd, and the dwTimeout member set to the default system time out.

If the dwPcm member of PCMINFO does not have the PCM_DOPOLLING flag set, WM_PENEVENT messages are sent to the specified window for significant events such as pen down, pen up, or after some threshold number of points has been received. Otherwise, the application should poll for data using GetPenInput.

Other bits in the dwPcm member of PCMINFO can be used to determine which conditions, if any, terminate pen input. An application can also call StopPenInput to explicitly terminate the input.

Example

The following example initiates pen input in a window procedure on detection of pen down:

static HPCM vhpcm;

//... omitted ...

switch (message)

{

case WM_LBUTTONDOWN:

{

// Get extra info associated with event:

DWORD dwExtraInfo = GetMessageExtraInfo();

if (IsPenEvent( message, dwExtraInfo ))   // Checks PDK bits

{

PCMINFO pcminfo;        // Pen collection mode structure

pcminfo.cbSize    = sizeof( PCMINFO );

pcminfo.dwPcm     = PCM_RECTBOUND | PCM_TIMEOUT;

pcminfo.dwTimeout = dwTimeOutDefault;   // 1 second

// Set inclusion rect to client area, but in screen coords:

GetClientRect( hwnd, &pcminfo.rectBound );

ClientToScreen( hwnd, (LPPOINT) &pcminfo.rectBound );

ClientToScreen( hwnd, (LPPOINT) &pcminfo.rectBound.right );

// Start gathering input:

if (vhpcm = StartPenInput( hwnd,

LOWORD( dwExtraInfo ), &pcminfo, NULL ))

return 1L;                         // We handled it

}

// Else fall into DefWindowProc below...

}

break;

See Also

GetPenInput, StopPenInput, PCMINFO WM_PENEVENT, PCM_


StopInking [New - Windows 95]
StopInking

2.0      [New - Windows 95]

Stops inking feedback.

int StopInking( HPCM hpcm )

Parameters

hpcm

Handle to the current collection. This is the return value from StartPenInput.

Return Value

Returns PCMR_OK if successful; otherwise, returns the following value:

Constant	Description
PCMR_INVALIDCOLLECTION	The hpcm handle is invalid, or there is no collection, or inking has not been started.
Comments

Inking must have been started by using the StartInking function for this function to have any effect.

See Also

StartInking


StopPenInput [New - Windows 95]
StopPenInput

2.0      [New - Windows 95]

Terminates collection of pen input.

int StopPenInput( HPCM hpcm, UINT idEvent, int nTermReason )

Parameters

hpcm

Handle to the collection of the pen data gathered during the input session. HPCM stands for "handle to a pen collection mode."

idEvent

The identifier of the packet in the task-specific queue at which the pen input should be terminated. If this value is PID_CURRENT, pen input stops immediately (that is, at the latest position in the task queue) and no further input is collected. The idEvent parameter is the low-order word of the value returned from the Windows GetMessageExtraInfo function when processing a WM_LBUTTONDOWN message.

nTermReason

The reason for termination. This value is passed to the termination message PE_TERMINATED. It can be one of the following:

Constant	Description
PCMR_APPTERMINATED	Application terminated input.
PCMR_TERMBOUND	Pen was pressed outside bounding rectangle or region.
PCMR_TERMEX	Pen was pressed inside exclusion rectangle or region.
PCMR_TERMPENUP	Pen was lifted from the tablet.
PCMR_TERMRANGE	Pen left the tablet's range of sensitivity.
PCMR_TERMTIMEOUT	Time-out expired.
Return Value

Returns PCMR_OK if successful; otherwise, the return value can be one of the following:

Constant	Description
PCMR_INVALIDCOLLECTION	The hpcm handle is invalid because the calling application did not start input with StartPenInput.
PCMR_INVALID_PACKETID	idEvent is invalid.
Comments

This function allows an application to explicitly terminate pen collection without waiting for one of the conditions specified by StartPenInput in the dwPcm member of PCMINFO.

Due to the asynchronous nature of pen input messages, the application should wait for the WM_PENEVENT message with wParam set to PE_TERMINATED to make sure that the pen input process has completely terminated. This does not apply if the application is using the polling method of pen input.

See Also

StartPenInput


SymbolToCharacter [New - Windows 95]
SymbolToCharacter

1.0     2.0      [New - Windows 95]

Converts an array of SYV_ symbol values to an ANSI string.

BOOL SymbolToCharacter( LPSYV lpsyv, int cSyv, LPSTR lpstr, LPINT lpnConv )

Parameters

lpsyv

Address of the array of SYV_ symbol values.

cSyv

Count of symbols in the lpsyv array, including the terminating SYV_NULL.

lpstr

Address of a buffer that receives the ANSI string. The buffer should be large enough to hold at least cSyv number of ANSI characters (including SYV_NULL).

lpnConv

If not NULL, lpnConv contains the number of symbols converted when the function returns. If NULL, this parameter is ignored.

Return Value

Returns TRUE if successful. If one or more symbols cannot be converted to ANSI, the return value is FALSE.

Comments

For ANSI characters, the size of the lpstr buffer must be at least cSyv bytes. For double-byte characters (kanji, for example), the buffer size must be at least (2 * cSyv) bytes. The SymbolToCharacter function converts at most cSyv symbol values from lpsyv and places the equivalent ANSI characters in the lpstr buffer. The conversion proceeds until an SYV_NULL value is encountered or until cSyv symbols have been converted. An SYV_NULL is converted to 0. The actual number of symbols converted is returned in lpnConv if lpnConv is not NULL.

See Also

CharacterToSymbol, SYG, SYV_


TargetPoints [New - Windows 95]
TargetPoints

2.0      [New - Windows 95]

Determines the target to which pen data belongs.

int TargetPoints( LPTARGINFO lptarginfo, LPPOINT lppt, DWORD dwReserved, UINT fuReserved, LPSTROKEINFO lpsi )

Parameters

lptarginfo

Address of a targeting data TARGINFO structure.

lppt

Address of a buffer of POINT structures in tablet coordinates.

dwReserved

This parameter is reserved for future use and its value is ignored.

fuReserved

This parameter is reserved for future use and its value is ignored.

lpsi

A pointer to a STROKEINFO structure. This structure holds information about the stroke being targeted.

Return Value

Returns an array index, starting from 0, of the target in the rgTarget array of the TARGINFO structure, if successful. If no suitable target is found, or if there are no points to target, TargetPoints returns −1.

Comments

To select the desired targeting behavior, the application should set the dwFlags member of the TARGINFO structure that lptarginfo points to.

See Also

GetPenInput,  TARGET,  TARGINFO


TPtoDP [New - Windows 95]
TPtoDP

1.0     2.0      [New - Windows 95]

Converts points in tablet coordinates to display (screen) coordinates.

BOOL TPtoDP( LPPOINT lppt, int cPnt )

Parameters

lppt

Address of an array of POINT structures to convert to display coordinates. This parameter cannot be NULL.

cPnt

Number of POINT structures to convert.

Return Value

Returns TRUE if the conversion was successful; otherwise, returns FALSE.

Comments

The conversion fails if some tablet points lie outside the region mapped to the screen.

Because of rounding errors, the DPtoTP and TPtoDP functions are not guaranteed to be perfect inverses of each other.

See Also

DPtoTP


TrainContext [New - Windows 95]
TrainContext

1.0     2.0      [New - Windows 95]

Provides the recognizer a previous recognition result that may contain errors, plus the correct interpretation of the raw data.

Note  This function is provided only for compatibility with version 1.0 of the Pen API and will not be supported in future versions. Use TrainHREC instead.

BOOL TrainContext( LPRCRESULT lprcresult, LPSYE lpsye, int csye, LPSYC lpsyc, int csyc )

Parameters

lprcresult

Address of the RCRESULT structure containing the handle to the pen data that contains the raw data and the recognizer's original interpretation of that data. This parameter cannot be NULL.

lpsye

Address of an array of SYE structures that specify the correct interpretation of the raw data. The values of the  iSyc members of these structures index the SYC structures pointed to be the lpsyc parameter.

csye

The number of SYE structures in the lpsye array.

lpsyc

An array of SYC structures that establish the mapping between the raw data and the characters in the hpendata member of the structure pointed to by the lprcresult parameter.

csyc

The number of SYC structures in the lpsyc array.

Return Value

Returns TRUE if the ink is accepted for training; otherwise, returns FALSE.

Comments

TrainContext is called by an application with a recognition result that may contain mistakes, along with a correct interpretation, so that the recognizer can learn from the mistake and improve subsequent recognition. A second, simpler training function for 1.0 recognizers is provided by TrainInk.

TrainContext internally calls the function TrainContextInternal exported by the recognizer identified by the hrec member of the RC structure pointed to by the lprc member of the RCRESULT structure. A version 1.0 recognizer should export both TrainContextInternal and TrainInkInternal, but can simply return FALSE from both functions if the recognizer does not support this type of training.

When a training application is able to provide contextual information (such as segmentation suggestions) to the version 1.0 recognizer, it calls the TrainContext function. The lprcresult parameter points to an RCRESULT structure that contains the results of a previous recognition. The raw data is also contained in the hpendata member of the structure pointed to be lprcresult.

In addition to providing the incorrect interpretation of the data (by means of the symbol graph, the lpsyv member in the RCRESULT structure), a more detailed, correct interpretation is also provided by the SYE structures and SYC structures. Because the correct interpretation is passed by SYE structures, it is possible to suggest segmentation boundaries to the recognizer.

Suppose, for example, that a user writes "lc," and the recognizer interprets it as "k". A trainer calls TrainContext using, first, an array of SYC structures that point to the ink of the "lc" and, second, the two SYE structures with the SYV values "l" and "c". These two SYE structures share the same index into the lpsyc array, indicating that both use the ink that was interpreted as "k".

Segmentation errors can be corrected in the other direction as well. Suppose, for example, the user writes "k" and the recognizer interprets it as "lc". A trainer could call TrainContext using a single SYE with SYV values equal to "k" and an array of SYC structures that incorporate the ink the recognizer had previously assigned to the "l" and the "c".

To train several SYV symbol values to a single piece of ink (for example, a long stroke that is an "he" ligature), there will be two consecutive SYE structures—one for the "h" and one for the "e". Both SYE structures have the same iSyc member; this means that the SYE structures both point to the same ink. A recognizer must take this into consideration to avoid training the two characters separately using the same ink for both; that would result in having "he" trained as "he he".

A recognizer can supply its own custom training dialog boxes. An application should check whether the recognizer supports custom training by calling ConfigRecognizer with the WCR_TRAIN subfunction.

The trainer does not display an error message if TrainInk or TrainContext returns FALSE. Error messages that occur when training fails must be handled by the recognizer.

See Also

ConfigRecognizer, TrainInk, TrainHREC, SYC,  SYE,  SYV_


TrainHREC [New - Windows 95]
TrainHREC

2.0      [New - Windows 95]

Passes ink and its symbol interpretation to the recognizer for training.

int TrainHREC( HREC hrec, LPSYV lpsyv, UINT cSyv, HPENDATA hpndt, UINT uConflict )

Parameters

hrec

Module handle of the recognizer library. If this value is NULL, the system default recognizer is used.

lpsyv

Address of an array of symbols to train.

cSyv

Count of symbols in lpsyv. This must be greater than 0.

hpndt

Handle to an HPENDATA object.

uConflict

One of the following TH_ values that specify how to handle training conflicts:

Constant	Description
TH_QUERY	Query the user if the proposed training conflicts with symbols in the database.
TH_FORCE	Perform the training without querying the user, even if there is a conflict with the database.
TH_SUGGEST	Abandon the training if there is any conflict with the database and return an error (HRCR_CONFLICT).
Return Value

Returns HRCR_OK if training is successful; otherwise, returns one of the following negative values:

Constant	Description
HRCR_ERROR	Invalid parameter or other error.
HRCR_CONFLICT	TH_SUGGEST was specified but there was a conflict with the database. No training was done.
HRCR_INVALIDPNDT	Invalid HPENDATA object.
HRCR_MEMERR	Insufficient memory.
HRCR_UNSUPPORTED	The recognizer does not support this function.
Comments

Typically, an application calls TrainHREC to train a single symbol. In other words, lpsyv points to a single symbol that is followed by an SYV_NULL terminator. However, multiple symbols—for example, those representing the character string "ng"—may also be trainable, depending on the recognizer.

If uConflict is TH_QUERY, the recognizer is free to prompt the user with a dialog box to resolve training conflicts. If it is TH_FORCE, the training is performed regardless of conflicts and the original conflicting data may be lost. TH_SUGGEST trains the recognizer only if there are no conflicts; otherwise, the call fails and returns HRCR_CONFLICT.

If the user picks a meaning for some ink from a list of alternatives, such as in a boxed edit control, the application can elect to train the recognizer with this information. In this case, either TH_FORCE or TH_SUGGEST is a suitable value for uConflict.

Training gestures depends on the recognizer. The Microsoft Handwriting Recognizer (GRECO.DLL) does not support training for gestures.

See Also

CreateCompatibleHREC


TrainInk [New - Windows 95]
TrainInk

1.0     2.0      [New - Windows 95]

Provides raw data and a correct interpretation of the data to the recognizer.

Note  This function is provided only for compatibility with version 1.0 of the Pen API and will not be supported in future versions. Use TrainHREC instead.

BOOL TrainInk( LPRC lprc, HPENDATA hpndt, LPSYV lpsyv )

Parameters

lprc

Address of an RC structure, or NULL. If this parameter is NULL, the RC Manager replaces it with a pointer to the global RC structure, then calls the recognizer associated with the global RC. If lprc is not NULL, the RC Manager calls the recognizer identified by the hrec member of the RC structure.

hpndt

Handle to an HPENDATA object containing the ink to be trained. This parameter cannot be NULL.

lpsyv

Pointer to a string of SYV symbol values terminated by SYV_NULL. This parameter cannot be NULL.

Return Value

Returns TRUE if the ink described by the pen data could be trained; otherwise, it returns FALSE.

Comments

Applications call TrainInk with raw data accompanied by a correct interpretation of the data, so that the recognizer can improve subsequent recognition. A second, more complex training function for version 1.0 recognizers is provided by TrainContext.

TrainInk is called by an application to access the TrainInkInternal function in the recognizer library. A private 1.0 recognizer must export both TrainInkInternal and TrainContextInternal, but the functions can simply return FALSE if the recognizer does not support this type of training.

TrainInk provides the lowest level of basic shape training. It requests the recognizer to assign the meaning in lpsyv to the ink in hpndt. The recognizer should interpret the ink to meet that request.

In the most common case, lpsyv points to a single character, and the recognizer will train a new shape based on the ink and that character. In other cases, multiple SYV symbol values can be passed, indicating that the ink represents multiple characters. The recognizer must decide whether to simply add a new shape with a meaning based on multiple SYV symbol values or to segment the ink into separate shapes for each SYV.

An application should check whether a recognizer supports training by calling ConfigRecognizer with the WCR_TRAIN subfunction.

The trainer does not display an error message if TrainInk or TrainContext returns FALSE. Error messages that occur when training fails must be handled by the recognizer.

See Also

ConfigRecognizer,  TrainContext,  TrainHREC, SYV_


TrimPenData [New - Windows 95]
TrimPenData

2.0      [New - Windows 95]

Removes selected data from an HPENDATA object.

HPENDATA TrimPenData( HPENDATA hpndt, DWORD dwTrimOptions, DWORD dwReserved )

Parameters

hpndt

Handle to the HPENDATA object.

dwTrimOptions

The following option flags are listed in the order in which the trimming operations are performed. For example, OEM data is removed (TPD_OEMDATA) before duplicate points (TPD_COLLINEAR).

Constant	Description
TPD_RECALCSIZE	Recalculate size of pen data and reallocate if smaller.
TPD_UPPOINTS	Remove pen-up strokes from the HPENDATA object.
PHW_PRESSURE	Remove OEM pressure information.
PHW_HEIGHT	Remove OEM height information.
PHW_ANGLEXY	Remove OEM XY-angle information.
PHW_ANGLEZ	Remove OEM Z-angle information.
PHW_BARRELROTATION	Remove OEM barrel rotation information.
PHW_OEMSPECIFIC	Remove OEM-specific value information.
PHW_PDK	Remove per-point Pen Driver Kit (PDK_) information.
TPD_PHW	Remove all OEM and PDK information, but not stroke tick or user data.
TPD_OEMDATA	Remove all OEM values and PDK data.
TPD_PENINFO	Remove PENINFO structure from header. Note that any OEM information present is discarded.
TPD_COLLINEAR	Remove collinear and duplicate (coincident) points. There may not be any OEM data.
TPD_USER	Remove per-stroke user information.
TPD_TIME	Remove per-stroke timing information.
TPD_EMPTYSTROKES	Remove all strokes with 0 points.
TPD_EVERYTHING	Remove everything possible except pen-down strokes. This includes both TPD_ and PHW_ flags.
dwReserved

Must be 0.

Return Value

Returns PDR_OK if successful; otherwise, it returns one of the following negative values:

Constant	Description
PDR_COMPRESSED	The pen data was compressed.
PDR_ERROR	An unspecified memory error occurred.
PDR_MEMERR	Memory error.
PDR_OEMDATAERR	The pen data does not have specific pressure or height (PHW_) information. Thus, the specified PHW_ data could not be selectively trimmed. Use TPD_OEMDATA to remove all OEM information.
PDR_PNDTERR	Invalid pen data.
PDR_VERSIONERR	A version 1.0 pen data object could not be converted to the 2.0 format.
Comments

TrimPenData supplements the capabilities of CompressPenData. Together, these two functions replace the version 1.0 Pen API function CompactPenData, which is supported for compatibility only.

The data that hpndt points to must not be compressed. If it is, TrimPenData simply retrieves the original (untrimmed) pen data.

See Also

CompactPenData, CompressPenData, PDK_


UnhookResultsHookHREC [New - Windows 95]
UnhookResultsHookHREC

2.0      [New - Windows 95]

Unhooks a recognizer result hook set with the SetResultsHookHREC function.

int UnhookResultsHookHREC( HREC hrec, HRECHOOK hHook )

Parameters

hrec

Module handle of the recognizer library. If this value is NULL, the system default recognizer is used.

hHook

Handle of the hook function.

Return Value

Returns HRCR_OK if successful; otherwise, returns one of the following negative values:

Constant	Description
HRCR_ERROR	Invalid parameter or other error.
HRCR_MEMERR	Insufficient memory.
See Also

ResultsHookHREC, SetResultsHookHREC


UninstallRecognizer [New - Windows 95]
UninstallRecognizer

1.0     2.0      [New - Windows 95]

Unloads a recognizer previously installed with InstallRecognizer.

void UninstallRecognizer( HREC hrec )

Parameters

hrec

Recognizer handle.

Return Value

This function does not return a value.

Comments

Windows maintains a use count for all installed recognizers and doesn't unload a recognizer until the last remaining client application has called UninstallRecognizer. For every call an application makes to InstallRecognizer, it must must make a matching call to UninstallRecognizer.

Before unloading a recognizer library, the system calls the recognizer's ConfigRecognizer function with the subfunction WCR_CLOSERECOGNIZER.

It is not necessary to uninstall the default recognizer; an application must uninstall all recognizers that it explicitly loads.

See Also

InstallRecognizer, ConfigHREC


UpdatePenInfo [New - Windows 95]
UpdatePenInfo

1.0     2.0      [New - Windows 95]

Notifies the RC Manager that a PENINFO value has changed. This function is called by pen drivers compatible with version 1.0 of the Pen API.

Note  This function is provided only for compatibility with version 1.0 of the Pen API and will not be supported in future versions.

void UpdatePenInfo( LPPENINFO lppeninfo )

Parameters

lppeninfo

Address of a PENINFO structure containing the new information.

Return Value

This function does not return a value.

Comments

A PENINFO value may change when the user alters the driver parameters in the configuration dialog box. When this happens, the pen driver must call UpdatePenInfo to notify the RC Manager of the change.

See Also

PENINFO


WriteHWL [New - Windows 95]
WriteHWL

2.0      [New - Windows 95]

Writes a word list to a file.

int WriteHWL( HWL hwl, HFILE hfile )

Parameters

hwl

Handle to a word list.

hfile

A handle to a file previously opened for writing.

Return Value

Returns HRCR_OK if successful; otherwise, returns one of the following negative values:

Constant	Description
HRCR_ERROR	Invalid parameter, or file or other error.
HRCR_MEMERR	Insufficient memory.
Comments

The words are saved as ANSI text, one word per line, followed by a carriage return and linefeed. The file must already exist and be open for writing. An application can append to the file by positioning the file pointer at the end before calling WriteHWL. In this context, a word can represent a phrase and contain spaces or other noncharacters, such as "New York" and "ne're-do-well."

For a description of word lists and how a recognizer uses them, see "Configuring the HRC" in Chapter 5, "The Recognition Process."

See Also

CreateHWL, ReadHWL


Pen Application Programming Interface Structures

This chapter describes in alphabetical order the structures defined by the Pen Application Programming Interface (API). Each entry includes the structure typedef definition, descriptions of the structure members, and cross-references where appropriate. The entry heading identifies the Pen API version, such as 1.0 or 2.0, that supports the structure.


ABSTIME [New - Windows 95]
ABSTIME

2.0      [New - Windows 95]

Absolute time structure.

typedef struct {

DWORD sec;

UINT ms;

} ABSTIME;

Members

sec

Number of seconds since 12:00 A.M. of January 1, 1970, as returned by the C run time library time function.

ms

Additional offset in milliseconds. This member can be any value from 0 through 999.

See Also

GetStrokeAttributes, SetStrokeAttributes, INTERVAL


ANIMATEINFO [New - Windows 95]
ANIMATEINFO

2.0      [New - Windows 95]

Animation information used by the DrawPenDataEx function for animation control.

typedef struct {

DWORD cbSize;

UINT uSpeedPct;

UINT uPeriodCB;

UINT fuFlags;

LPARAM lParam;

DWORD dwReserved;

} ANIMATEINFO;

Members

cbSize

Size of this structure in bytes.

uSpeedPct

Drawing speed, expressed as a percentage of the user's entry speed. To redraw pen data at the same speed at which it was created, this value should be set to 100. A value of 0 halts drawing. Setting uSpeedPct to 0 is valid only if the lpfnAnimateCB parameter of DrawPenDataEx is defined. Otherwise, the drawing halts with no way to restart it. uSpeedPct can be changed by a call-back function.

uPeriodCB

Callback period in milliseconds. Typical values are 1 (very fast), 250 (fast), 1000 (slow), or 0 (never). Any value in uPeriodCB is ignored if the DrawPenDataEx argument lpfnAnimateCB is NULL. uPeriodCB may also be AI_CBSTROKE, to indicate that the callback should occur after each stroke is drawn.

fuFlags

Flags that control animation (can be 0). The AI_SKIPUPSTROKES option specifies that the time taken to account for the points in the up strokes should be ignored. If this flag is 0, and if the value in uSpeedPct is small enough, there will be a delay between pen-down strokes, reflecting the user's inter-stroke delay during creation of the pen data.

lParam

Application value to pass to the callback function set up by the lpfnAnimateCB argument of DrawPenDataEx.

dwReserved

Must be 0.

Comments

Before using ANIMATEINFO, an application must initialize cbSize with sizeof( ANIMATEINFO ).

See Also

AnimateProc, DrawPenDataEx


BOXEDITINFO [New - Windows 95]
BOXEDITINFO

2.0      [New - Windows 95]

Size information for boxed edit control.

typedef struct {

int cxBox;

int cyBox;

int cxBase;

int cyBase;

int cyMid;

BOXLAYOUT boxlayout;

UINT wFlags;

BYTE szFaceName[BEI_FACESIZE];

UINT wFontHeight;

UINT rgwReserved[8];

} BOXEDITINFO;

Members

cxBox

Width of a single box.

cyBox

Height of a single box.

cxBase

In-box x-margin to guideline.

cyBase

In-box y-offset from top to baseline.

cyMid

Reserved for future use; must be set to 0.

boxlayout

BOXLAYOUT structure.

wFlags

Flags specifying boxed edit options. Currently, the only defined option is BEIF_BOXCROSS.

szFaceName[BEI_FACESIZE]

Font face name, where BEI_FACESIZE is defined as 32.

wFontHeight

Font height.

rgwReserved[8]

Reserved for future use; must be set to 0.

See Also

BOXLAYOUT


BOXLAYOUT [New - Windows 95]
BOXLAYOUT

1.0    2.0      [New - Windows 95]

Specifies some of the characteristics of a bedit control. The GUIDE and BOXEDITINFO structures determine the rest. The HE_GETBOXLAYOUT and HE_SETBOXLAYOUT wParam values of the WM_PENCTL message retrieve and set the BOXLAYOUT structure for a bedit control.

For more details, see the WM_PENCTL message.

typedef struct {

int cyCusp;

int cyEndCusp;

UINT style;

DWORD dwReserved1;

DWORD dwReserved2;

DWORD dwReserved3;

} BOXLAYOUT;

Members

cyCusp

Height of the box in pixels when BXS_RECT is specified; otherwise, height of the cusp in pixels (in comb style).

cyEndCusp

Height of cusps, in pixels, at extreme ends.

style

Bitwise-OR combination of the following BXS_ flags:

Constant	Description
BXS_NONE	Default comb style.
BXS_RECT	Rectangular boxes (instead of comb style).
BXS_BOXCROSS	(Japanese version only.) Rectangular boxes with a small cross at the center of each cell. Note that any state set via this flag (or the absence of it) may be overridden by the user's selection of the BOXCROSS setting in the Bedit Control Panel.
dwReserved1

Reserved; must be set to 0.

dwReserved2

Reserved; must be set to 0.

dwReserved3

Reserved; must be set to 0.

Comments

The following table lists the default values for the BOXLAYOUT structure.

Value	Description
cyCusp	Equivalent in pixels of BXD_CUSPHEIGHT dialog units.
cyEndCusp	Equivalent in pixels of BXD_ENDCUSPHEIGHT dialog units.
style	Comb style.
Figure 11.1 shows the general layout of a boxed edit control. Some of the terms in the figure are explained in the reference entry for the GUIDE structure. Figure 11.2 shows an individual cell from a boxed edit control.

See Also

BOXEDITINFO, WM_PENCTL, GUIDE, BXD_


BOXRESULTS [New - Windows 95]
BOXRESULTS

2.0      [New - Windows 95]

Contains box results for the GetBoxResultsHRC function.

typedef struct {

int indxBox;

HINKSET hinksetBox;

SYV rgSyv[1];

} BOXRESULTS;

Members

indxBox

Index of the box with respect to the GUIDE structure.

hinksetBox

An inkset representing the pen data that belongs to the box, if requested by the GetBoxResultsHRC function. This member can be NULL.

rgSyv[1]

Variable-length array of alternative guesses made by the recognizer. The guesses are arranged in descending order of confidence, so that the first alternative in the array is the most likely choice.

See Also

GetBoxResultsHRC, GUIDE


CALBSTRUCT [New - Windows 95]
CALBSTRUCT

1.0    2.0      [New - Windows 95]

Pen calibration information.

typedef struct {

int wOffsetX;

int wOffsetY;

int wDistinctWidth;

int wDistinctHeight;

} CALBSTRUCT;

Members

wOffsetX

Value in tablet units to add to x-coordinates for proper calibration.

wOffsetY

Value in tablet units to add to y-coordinates for proper calibration.

wDistinctWidth

Specifies the number of distinct x-coordinates the tablet can detect.

wDistinctHeight

Specifies the number of distinct y-coordinates the tablet can detect. The wDistinctWidth and wDistinctHeight members have the same meanings and values as the identically-named members in the PENINFO structure.


CTLINITBEDIT [New - Windows 95]
CTLINITBEDIT

2.0      [New - Windows 95]

Initialization information for a boxed edit (bedit) control.

typedef struct {

DWORD cbSize;

HWND hwnd;

int id;

int wSizeCategory;

WORD wFlags;

DWORD dwReserved;

} CTLINITBEDIT;

Members

cbSize

Size of this structure in bytes.

hwnd

Handle of a boxed edit window.

id

Control identifier.

wSizeCategory

Size category, which can be one of the following BESC_ constants:

Constant	Description
BESC_DEFAULT	Use the default size parameters to create the  boxed edit control. This results in the same behavior as BESC_KANJIFIXED for applications that have registered themselves through the  use of the SetPenAppFlags function with the RPI_KANJIFIXEDBEDIT flag. For all other applications, it results in the same behavior as BESC_ROMANFIXED.
BESC_ROMANFIXED	Comb-style bedit control with dimensions indicated by BXD_ constants (in dialog units). Meant for use with Roman characters.
BESC_KANJIFIXED	(Japanese version only.) Box-style bedit control with dimensions indicated by BXDK_ constants (in dialog units). Meant for use with kanji characters. This value should be used by applications that cannot handle user-defined box sizes.
BESC_USERDEFINED	A bedit control that can handle the box size parameters defined by the user. For further details, see the description for PMSC_BEDITCHANGE in the reference section for the WM_PENMISC message.
wFlags

Flags that determine certain properties of the boxed edit control. This can be a combination of the following values:

Constant	Description
CIB_NOGDMSG	(Not supported in Japanese version.)  Do not display the garbage-detection message box when writing in the bedit control.
CIB_NOACTIONHANDLE	Do not create action handles.
CIB_NOFLASHCURSOR	Do not change the cursor if tap-and-hold action is detected.
CIB_NOWRITING	(Japanese version only.) Do not allow pen input into the control. Other methods of inputting text, such as keyboard input or pasting from the keyboard, are allowed.
dwReserved

Reserved, should be set to 0.

Comments

Before using CTLINITBEDIT, an application must initialize cbSize with sizeof( CTLINITBEDIT ).

See Also

WM_CTLINIT


CTLINITHEDIT [New - Windows 95]
CTLINITHEDIT

2.0      [New - Windows 95]

Initialization information for a handwriting edit (hedit) control.

typedef struct {

DWORD cbSize;

HWND hwnd;

int id;

DWORD dwFlags;

DWORD dwReserved;

} CTLINITHEDIT;

Members

cbSize

Size of this structure in bytes.

hwnd

Handle of boxed edit window.

id

Control identifier.

dwFlags

Flags that determine some properties of the hedit control. This can be a combination of the following values:

Constant	Description
CIH_NOGDMSG	(Not supported in Japanese version.) Do not put up the garbage-detection message box when writing in this hedit control.
CIH_NOACTIONHANDLE	Do not create action handles for this hedit control.
CIH_NOEDITTEXT	Do not show the edit text, insert text, or  writing tool dialogs when writing in this hedit control.
CIH_NOFLASHCURSOR	Do not change the cursor while doing tap-and-hold selection in this hedit control.
dwReserved

Reserved, should be set to 0.

Comments

Before using CTLINITHEDIT, an application must initialize cbSize with sizeof( CTLINITHEDIT ).

See Also

WM_CTLINIT


CTLINITIEDIT [New - Windows 95]
CTLINITIEDIT

2.0      [New - Windows 95]

Specifies the initial settings and options of an ink edit (iedit) control. A pointer to this structure is passed to the parent window of the control as the lParam parameter of the WM_CTLINIT message. This forms the last step of the control's processing of the WM_CREATE message.

typedef struct {

DWORD cbSize;

HWND hwnd;

int id;

WORD ieb;

WORD iedo;

WORD iei;

WORD ien;

WORD ierec;

WORD ies;

WORD iesec;

HPENDATA hpndt;

WORD pdts;

HGDIOBJ hgdiobj;

HPEN hpenGrid;

POINT ptOrgGrid;

WORD wVGrid;

WORD wHGrid;

DWORD dwApp;

DWORD dwReserved;

} CTLINITIEDIT;

Members

cbSize

Size of this structure in bytes.

hwnd

Handle to an ink edit window.

id

Control identifier.

ieb

Background IEB_ bit values (see IE_SETBKGND).

iedo

Draw options IEDO_ bit values (see IE_SETDRAWOPTS).

iei

Ink input IEI_ bit values (see IE_SETINKINPUT).

ien

Notification IEN_ bit values (see IE_SETNOTIFY).

ierec

Recognition IEREC_ bit values (see IE_SETRECOG).

ies

Style IES_ bit values (see IE_GETSTYLE).

iesec

Security IESEC_ bit values (see IE_SETSECURITY).

hpndt

Initial pen data.

pdts

Initial map mode.

hgdiobj

Brush or bitmap, depending on background bits option in ieb.

hpenGrid

Pen to use in drawing grid.

ptOrgGrid

Point of origin for the grid lines.

wVGrid

Vertical grid line spacing.

wHGrid

Horizontal grid line spacing.

dwApp

Application data.

dwReserved

Reserved.

Comments

Before using CTLINITIEDIT, an application must initialize cbSize with sizeof( CTLINITIEDIT ).

See Also

IE_SETBKGND, IE_SETDRAWOPTS, IE_SETNOTIFY, IE_SETRECOG, IE_SETSECURITY, IE_GETSTYLE, IE_SETDRAWOPTS, WM_CTLINIT


CWX [New - Windows 95]
CWX

2.0      [New - Windows 95]

Specifies optional parameters for the CorrectWritingEx function. (Japanese version only.)

typedef struct {

DWORD cbSize;

WORD wApplyFlags;

HWND hwndText;

HRC hrc;

char szCaption[CBCAPTIONCWX];

DWORD dwEditStyle;

DWORD dwSel;

DWORD dwFlags;

WORD ixkb;

WORD rgState[CKBCWX];

POINT ptUL;

SIZE sizeHW;

} CWX;

Members

cbSize

Size of this structure in bytes. This field must be initialized to sizeof(CWX).

wApplyFlags

Options to specify which members of this structure are to be used to override the most-recently-used values provided by default; not all fields qualify. If this value is 0, the most-recently-used settings will be shown; otherwise, this value can be a combination of the following values:

Constant	Description
CWXA_CONTEXT	Use the dwFlags member to specify context.
CWXA_KBD	Use the ixkb member to specify a keyboard.
CWXA_STATE	Apply the states provided in the rgState array.
CWXA_PTUL	Move the dialog box upper corner to the screen position specified by the ptUL member.
CWXA_SIZE	Use the window size specified by the sizeHW member while using the handwriting recognition tab.
CWXA_NOUPDATEMRU	Do not update the registry with the last state of the correction dialog. This causes any changes made to the position and state of the Data Input Window to be discarded. This has no effect on user changes to the text, however.
hwndText

Text window to which to send WM_GETTEXT and WM_SETTEXT messages. If this is NULL, the owner of the Correct Writing dialog box will be used.

hrc

Handle to a recognition context. If this is NULL, a WM_PENMISC message with the wParam parameter of PMSC_GETHRC will be sent to the owner window to get a recognition context. If that too is NULL, then a default context will be used. The system will destroy its copy of hrc before the call returns.

szCaption[CBCAPTIONCWX]

A null-terminated array of characters to be used for a dialog caption. If this string has 0 length, then the default caption "Edit Text" will be used. The maximum length of caption allowed is specified by the CBCAPTIONCWX constant.

dwEditStyle

Style to use for the Data Input Window's edit control. By default this is ES_LEFT. If this style includes ES_MULTILINE, entry of Return and Tab characters is allowed; otherwise, they are not allowed. In any case, the style of the actual edit control will look like a multiline edit control.

dwSel

Specifies the selection. The low-order word (LOWORD) is the start position and the high-order word (HIWORD) is the end position. The default values are 0 for start and 0xFFFF for end, to select all text.

dwFlags

Specifies context flags, provided that the CWXA_CONTEXT bit is set in the wApplyFlags member; otherwise, the most-recently-used context flags are used and this field is ignored. On return, this field contains the updated flags. The flags may be CWX_DEFAULT (0), or a bitwise-OR combination of the following constant values:

Constant	Description
CWX_TOPMOST	Specifies that the dialog window is to be a topmost window. The window is not topmost by default.
CWX_NOTOOLTIPS	Disables showing tool tips for graphical buttons. They are shown by default.
CWX_JPERIOD	Specifies that the Japanese period is to be used on some keys on the Data Input Window keypads. The English period is used by default.
CWX_JCOMMA	Specifies that the Japanese comma is to be used on some keys on the Data Input Window keypads. The English comma is used by default.
CWX_DEFAULT	Zero; none of the above flags are set.
ixkb

Specifies which Data Input Window keyboard, or handwriting input, is to be used first, provided that the CWXA_KBD bit is set in the wApplyFlags member; otherwise, the most-recently use keyboard is used and this field is ignored. On return, this field contains the updated keyboard identifier. This may be one of the following values:

Constant	Description
CWXK_HW	Handwriting, not keyboard, input. If this value is specified, most of the dialog will be available for handwriting input, and the dialog will be sizable.
CWXK_50	50-On keyboard.
CWXK_QWERTY	QWERTY keyboard, including Hiragana, Katakana, and Romaji-to-Kana conversion alternative states.
CWXK_ROMAJI	Condensed Romaji-to-Kana keyboard, similar to some pocket computers.
CWXK_NUM	Numeric and Telephone keyboard.
CWXK_KANJI	Kanji keyboard, which provides a method of specifying a Kanji character based on its strokes.
CWXK_CODE	Kanji Code Finder keyboard, which allows the lookup of a Kanji character based on its JIS, Shift-JIS, or Kuten code value.
CWXK_YOMI	Kanji character finder based on the sound, or "reading" (Yomi) of the character.
rgState[CKBCWX]

An array of keyboard states with which to initialize the CKBCWX number of keyboards, provided that the CWXA_STATE bit is set in the wApplyFlags member; otherwise, the most-recently-used states are used and this member is ignored. On return, this member contains the updated states. Each element of the array may be CWXKS_DEFAULT (0, which is equivalent to CWXKS_HAN + CWXKS_ROMA), or a bitwise-OR combination of the following constants:

Constant	Description
CWXKS_CAPS	Set CAPSLOCK state on QWERTY keyboard.
CWXKS_HAN	Set Hankaku (single-byte) state.
CWXKS_ZEN	Set Zenkaku (double-byte) state.
CWXKS_ROMA	Set Romaji characters state.
CWXKS_HIRA	Set Hiragana characters state.
CWXKS_KATA	Set Katakana characters state.
ptUL

Specifies the upper-left corner of the dialog in screen coordinates, provided that the CWXA_PTUL bit is set in the wApplyFlags member; otherwise, the most-recently-used position is used and this member is ignored. On return, this member contains the updated screen position of the upper-left corner.

sizeHW

Specifies the size of the dialog when it is in handwriting input mode, provided that the CWXA_SIZE bit is set in the wApplyFlags member; otherwise, the most-recently-used size is used and this field is ignored. On return, this field contains the updated size.

Comments

Note that even if some bits are not set in wApplyFlags, the corresponding structure members are still updated with the last-used values on return.

See Also

CorrectWritingEx


GUIDE [New - Windows 95]
GUIDE

1.0    2.0      [New - Windows 95]

Specifies the characteristics of any guidelines used in the writing area.

typedef struct {

int xOrigin;

int yOrigin;

int cxBox;

int cyBox;

int cxBase;

int cyBase;

int cHorzBox;

int cVertBox;

int cyMid;

} GUIDE;

Members

xOrigin

Position of left edge of the first box in screen coordinates.

yOrigin

Position of top edge of the first box in screen coordinates.

cxBox

Width of each box in screen pixels.

cyBox

Height of each box in screen pixels.

cxBase

Margin to the guideline. This is one-half the distance in pixels between adjacent boxes.

cyBase

Vertical distance in pixels from the baseline to the top of the box.

cHorzBox

Number of columns of boxes.

cVertBox

Number of rows of boxes.

cyMid

Distance in pixels from the baseline to the midline, or 0 if midline is not present.

Comments

If the application has drawn guidelines on the screen on which the user is expected to write, the application should set the values in the GUIDE structure to inform the recognizer. The GUIDE structure is for the recognizer's use only. Setting the GUIDE structure does not by itself draw any visual clues on the display. It is the responsibility of the application or the control to draw the visual clues. The appearance of a boxed edit control is determined by the BOXLAYOUT and GUIDE structures together.

The xOrigin and yOrigin members are screen coordinates of the top-left corner of the area to write in. The cyBox and cxBox members are the height and width of the individual boxes to write in. The cHorzBox and cVertBox members specify the number of columns and rows. cyBase specifies a baseline within the box. (Setting cyBase to 0 indicates no baseline.) The cxBase member gives a horizontal displacement of the edge of the guideline from the edge of the box where writing is expected to start.

If only horizontal lines are present, set cxBox to 0. In this case, only yOrigin, cyBox, cyBase, and cyMid are valid. A default GUIDE structure has all elements set to 0.

To establish a guide, initialize a GUIDE structure and set it into an HRC with the SetGuideHRC function. This also applies to a standard bedit, as demonstrated in "The bedit Control" in Chapter 3.

For boxed input, the GetBoxMappingHRCRESULT function returns an index to the box containing the requested input character. This is numbered in zero-based row-major order. In Figure 11.3 below, for example, the "h" character is in box 12.

For best recognition results, the pair-wise ratios of cxBox, cyBox, and cyBase should be similar to the default ratios.

See Also

SetGuideHRC, BOXLAYOUT, BXD_


INKINGINFO [New - Windows 95]
INKINGINFO

2.0      [New - Windows 95]

Provides information about where and how the system should display ink.

typedef struct {

DWORD cbSize;

UINT wFlags;

PENTIP tip;

RECT rectClip;

RECT rectInkStop;

HRGN hrgnClip;

HRGN hrgnInkStop;

} INKINGINFO;

Members

cbSize

Size of this structure in bytes.

wFlags

A bitwise-OR combination of the following PII_ flags:

Constant	Description
PII_INKPENTIP	Use tip for pen characteristics.
PII_INKCLIPRECT	Clip ink using rectClip.
PII_INKSTOPRECT	Terminate inking on a pen-down event inside rectInkStop.
PII_INKCLIPRGN	Clip ink using hrgnClip. If hrgnClip is set,  any value in rectClip is disregarded.
PII_INKSTOPRGN	Terminate inking on a pen-down event inside hrgnInkStop.
PII_SAVEBACKGROUND	Save the background that is being inked on.  The saved background is restored when the current input session terminates.
PII_CLIPSTOP	Directs Windows to stop inking if the pen  goes down outside rectClip or hrgnClip, if either have been set.
tip

A PENTIP structure defining the pen type, size, and color.

rectClip

Clipping rectangle for the ink. Setting rectClip to {−32767, −32767, 32767, 32767} is equivalent to having no clipping region.

rectInkStop

Rectangle in which a pen-down event stops inking. Setting rectInkStop to empty is equivalent to not having an ink stop region.

hrgnClip

Clipping region for the ink. Setting hrgnClip to NULL is equivalent to not having a clipping region.

hrgnInkStop

Region in which a pen-down event stops inking. Setting hrgnInkStop to NULL is equivalent to not having an ink stop region.

Comments

All areas are in screen coordinates.

The wFlags member specifies which of the other members contain valid information. For example, if PII_INKCLIPRECT is set in wFlags, the rectClip member specifies the clipping rectangle. Otherwise, a default value is used.

Before using INKINGINFO, an application must initialize cbSize with sizeof( INKINGINFO ).

See Also

PENTIP, StartInking, WM_PENEVENT


INPPARAMS [New - Windows 95]
INPPARAMS

2.0      [New - Windows 95]

Describes a set of targets.

typedef struct {

DWORD cbSize;

DWORD dwFlags;

HPENDATA hpndt;

TARGET target;

} INPPARAMS;

Members

cbSize

Size of this structure in bytes.

dwFlags

Reserved for future use; must be 0.

hpndt

Handle to a pen data object.

target

A TARGET structure where input is directed.

Comments

Before using INPPARAMS, an application must initialize cbSize with sizeof( INPPARAMS ).

See Also

TARGET


INTERVAL [New - Windows 95]
INTERVAL

2.0      [New - Windows 95]

Interval structure for inksets.

typedef struct {

ABSTIME atBegin;

ABSTIME atEnd;

} INTERVAL;

Members

atBegin

Beginning of 1-millisecond granularity interval.

atEnd

Time at 1 millisecond past end of interval.

See Also

ABSTIME


OEMPENINFO [New - Windows 95]
OEMPENINFO

1.0    2.0      [New - Windows 95]

Structure containing original equipment manufacturer (OEM) hardware information for the pen or tablet.

typedef struct {

UINT wPdt;

UINT wValueMax;

UINT wDistinct;

} OEMPENINFO;

Members

wPdt

A combination of PDT_ values.

wValueMax

The largest value returned by the device.

wDistinct

The number of distinct readings possible.

Comments

The OEMPENINFO structure contains a description of the additional OEM information that the hardware can generate. It is a component of the PENINFO structure.

Besides capturing the x- and y- coordinates of the pen movement, a pen device has the option of providing a number of other types of input data, such as pen pressure, height of the pen tip above the tablet surface, angle of the pen, and so on. A pen driver can capture up to MAXOEMDATAWORDS types of data, where MAXOEMDATAWORDS is defined as six. An application can access the OEM data through the GetPenInput function. A recognizer can receive OEM data from an application through the AddPenInputHRC function. It is the up to the application whether to send this data or not.

Each pen event generates a packet of information from the pen driver that contains the current pen position and, optionally, other types of OEM information. The cbOemData member of the PENINFO structure specifies the width of the optional OEM data in bytes. Each type of data is one word wide. The type of data in the nth word of the OEM data packet is given by the nth element of the rgoempeninfo member (an array of OEMPENINFO structures) in the PENINFO structure.

For the wPdt member, PDT_NULL indicates no data. Values greater than PDT_OEMSPECIFIC are reserved for private use by drivers for data types not currently defined as standard. The wValueMax member contains the largest variable size the device can return for that data type. The wDistinct member is the number of distinct readings the device can take between 0 and wValueMax.

For a list of values for the wPdt member, see the entry for PDT_ values in Chapter 13, "Pen Application Programming Interface Constants."

Example

As an example of how to use OEMPENINFO, consider a device that can sense both the height above the tablet surface and the Z-angle of the pen. Assume the device can sense 256 levels of height in a range from 0 to 10 centimeters and has a resolution of 1 degree on the angle of the pen. The two additional words of OEM information occupy 4 bytes, so the cbOemData and rgoempeninfo members of PENINFO look like this:

peninfo.cbOemData = 4

peninfo.rgoempeninfo[MAXOEMDATAWORDS] = {

{PDT_HEIGHT, 1000, 256},

{PDT_ANGLEZ, 1800, 180},

{PDT NULL, 0, 0},

{PDT_NULL, 0, 0},

{PDT_NULL, 0, 0},

{PDT_NULL, 0, 0} };

This optional information is saved by the pen driver in the same manner as the x- and y- coordinate data. There must be a one-to-one correspondence between the OEM event data and the coordinate data.

Figure 11.5 shows the pen in a position where both the Xy-angle and Z-angle are approximately 45 degrees.

See Also

PENINFO


OEM_PENPACKET [New - Windows 95]
OEM_PENPACKET

2.0      [New - Windows 95]

A pen packet used by Pen API, version 2.0, consisting of the information received from the pen device for a single sample. For a definition of pen packet, see SetPenHook.

typedef struct {

UINT wTabletX;

UINT wTabletY;

UINT wPDK;

UINT rgwOemData[MAXOEMDATAWORDS];

DWORD dwTime;

} PENPACKET;

Members

wTabletX

The x-dimension in raw tablet coordinates.

wTabletY

The y-dimension in raw tablet coordinates.

wPDK

Pen hardware state bits, expressed as a combination of PDK_ values.

rgwOemData[MAXOEMDATAWORDS]

Array of OEM-specific data. MAXOEMDATAWORDS is defined as 6.

dwTime

Time stamp indicating when the pen packet originated.

Comments

A pen packet is the basic unit of communication between the pen driver and Windows. A pen packet contains all of the information about a single logical event: x-y coordinate position, button states, and any optional information such as pressure or barrel rotation. Several physical events—that is, interrupts—may be needed to construct a single logical event.

The rgwOemData member contains the data relating to the OEM hardware, such as pen pressure, angle, and so forth.

See Also

SetPenHookCallback, OEMPENINFO, PENPACKET


PCMINFO [New - Windows 95]
PCMINFO

2.0      [New - Windows 95]

Pen collection mode information. All regions and rectangles are in screen coordinates. Time-out values are in milliseconds.

typedef struct {

DWORD cbSize;

DWORD dwPcm;

RECT rectBound;

RECT rectExclude;

HRGN hrgnBound;

HRGN hrgnExclude;

DWORD dwTimeout;

} PCMINFO;

Members

cbSize

Size of this structure in bytes.

dwPcm

A combination of PCM_ flags specifying options for pen collection.

rectBound

Bounding rectangle for pen collection.

rectExclude

Exclusion rectangle for pen collection.

hrgnBound

Bounding region for pen collection.

hrgnExclude

Exclusion region for pen collection.

dwTimeout

Time-out before terminating pen collection.

Comments

Before using PCMINFO, an application must initialize cbSize with sizeof( PCMINFO ).

See Also

StartPenInput, WM_PENEVENT, PCM_


PDEVENT [New - Windows 95]
PDEVENT

2.0      [New - Windows 95]

Provides details of the pointing-device event that is the subject of an IN_PDEVENT notification. A pointing-device event can be a pen tap, mouse double-click, and so on. This structure is returned by the IE_GETPDEVENT message.

typedef struct {

DWORD cbSize;

HWND hwnd;

UINT wm;

WPARAM wParam;

LPARAM lParam;

POINT pt;

BOOL fPen;

LONG lExInfo;

DWORD dwReserved;

} PDEVENT;

Members

cbSize

Size of this structure in bytes.

hwnd

Handle to ink edit window.

wm

Window WM_ message.

wParam

wParam of event.

lParam

lParam of event.

pt

Event point in ink edit client coordinates.

fPen

TRUE if pen event, FALSE if mouse event.

lExInfo

Windows GetMessageExtraInfo function return value.

dwReserved

Reserved.

Comments

Before using PDEVENT, an application must initialize cbSize with sizeof( PDEVENT ).

For descriptions of the WM_ messages that pertain to pen-based computing, refer to Chapter 12, "Pen Application Programming Interface Messages."

See Also

IE_GETPDEVENT, IN_PDEVENT


PENDATAHEADER [New - Windows 95]
PENDATAHEADER

1.0    2.0      [New - Windows 95]

Main header of an HPENDATA memory block.

typedef struct {

UINT wVersion;

UINT cbSizeUsed;

UINT cStrokes;

UINT cPnt;

UINT cPntStrokeMax;

RECT rectBound;

UINT wPndts;

int nInkWidth;

DWORD rgbInk;

} PENDATAHEADER;

Members

wVersion

Pen data format version. Same as the version number for the Pen API, which is currently 0x0002. Calling GetPenDataAttributes with the GPA_VERSION argument retrieves the value of wVersion.

cbSizeUsed

Size (in bytes) of pen data memory block.

cStrokes

Number of strokes in the block. (Each pen-down and pen-up sequence counts as a single stroke.)

cPnt

Count of all points in the block. Calling GetPenDataAttributes with the GPA_POINTS argument retrieves the value of cPnt.

cPntStrokeMax

Length (in points) of longest stroke. Calling GetPenDataAttributes with the GPA_MAXLEN argument retrieves the value of cPntStrokeMax.

rectBound

Bounding rectangle of all pen-down points.

wPndts

Data scaling metric value, expressed as a bitwise-OR combination of PDTS_ values.

nInkWidth

Ink width, in pixels.

rgbInk

Ink color.

Comments

The PENDATAHEADER structure describes the contents of an HPENDATA memory block. Use the GetPenDataInfo or GetPenDataAttributes function to retrieve information from a PENDATAHEADER structure.

For a description of the HPENDATA memory block, see "The HPENDATA Object" in Chapter 4, "The Inking Process."

For a list of data scaling values, refer to the entry for PDTS_ values in Chapter 13, "Pen Application Programming Interface Constants."

See Also

GetPenDataInfo, GetPenDataAttributes, PDTS_


PENINFO [New - Windows 95]
PENINFO

1.0    2.0      [New - Windows 95]

Contains dimensions, sampling rate, and other information about the pen or tablet hardware.

typedef struct {

UINT cxRawWidth;

UINT cyRawHeight;

UINT wDistinctWidth;

UINT wDistinctHeight;

int nSamplingRate;

int nSamplingDist;

LONG lPdc;

int cPens;

int cbOemData;

OEMPENINFO rgoempeninfo[MAXOEMDATAWORDS];

UINT rgwReserved[7];

UINT fuOEM;

} PENINFO;

Members

cxRawWidth

Width of tablet in thousandths of an inch. Also specifies the maximum tablet x-coordinate.

cyRawHeight

Height of tablet in thousandths of an inch. Also specifies the maximum tablet y-coordinate.

wDistinctWidth

Number of distinct x-coordinates the hardware can detect.

wDistinctHeight

Number of distinct y-coordinates the hardware can detect. Together, the wDistinctWidth and wDistinctHeight members express the x-y resolution of the tablet. For example, if a tablet is 8 inches wide and has a resolution of 1/500 of an inch, cxRawWidth is 8000 and wDistinctWidth is 4000 because the tablet hardware can return 4000 distinct x-order values ranging from 0 to 8000.

nSamplingRate

Specifies the number of samples per second the tablet can return. This value may be less than the number of hardware interrupts per second the tablet generates because several interrupts may be required to create one pen packet sample. See the "Comments" section below for information on adjusting the sampling rate.

nSamplingDist

Specifies the distance in distinct tablet units a pen must travel before a new pen event is generated. See the "Comments" section below for information on adjusting the sampling distance.

lPdc

Pen-device capabilities, expressed as a bitwise-OR combination of the PDC_ flags.

cPens

Number of pens the tablet can simultaneously support.

cbOemData

Specifies the width, in bytes, of the additional OEM data passed in each pen packet. For example, if a tablet can detect pressure and Z-angle information, this information occupies two additional words of OEM data, so cbOemData is 4.

rgoempeninfo[MAXOEMDATAWORDS]

An array of OEMPENINFO structures. Each structure describes one word of additional OEM data contained in each pen packet. (MAXOEMDATAWORDS is defined as 6.)

rgwReserved[7]

Reserved for internal use.

fuOEM

Flags representing which OEM data to report in rgoempeninfo; used by applications to determine the OEM data used in an HPENDATA object. This member is set and used internally by the pen services and should never be modified by an application. This member is a bitwise-OR combination of the following values:

Constant	Description
PHW_ALL	Report all available OEM data.
PHW_PRESSURE	Report pressure if available.
PHW_HEIGHT	Report height if available.
PHW_ANGLEXY	Report Xy-angle if available.
PHW_ANGLEZ	Report Z-angle if available.
PHW_BARRELROTATION	Report barrel rotation if available.
PHW_OEMSPECIFIC	Report OEM-specific value if available.
PHW_PDK	Report per-point PDK_ values.
Comments

The DRV_GetPenInfo pen driver message fills a PENINFO structure with the current device parameters. DRV_GetPenInfo returns FALSE if a tablet is not present. If this occurs, the PENINFO structure that the message's lParam1 points to is not valid. Note that an application should retrieve tablet information with the GetPenDataInfo and GetPenDataAttributes functions, rather than accessing the pen driver directly.

An application can also adjust the tablet sampling rate and sampling distance by sending the DRV_SetSamplingRate or DRV_SetSamplingDist messages to the device driver. For more information, see Appendix E, "Accessing the Pen Device Driver."

For a list of state bits for the pen driver, refer to the entry for PDK_ values in Chapter 13, "Pen Application Programming Interface Constants."

See Also

CreatePenDataEx, GetPenDataInfo, TrimPenData, UpdatePenInfo, OEMPENINFO


PENPACKET [New - Windows 95]
PENPACKET

1.0    2.0      [New - Windows 95]

A pen packet used by Pen Windows, version 1.0, consisting of the information received from the pen device for a single sample. For a definition of pen packet, see SetPenHook.

typedef struct {

UINT wTabletX;

UINT wTabletY;

UINT wPDK;

UINT rgwOemData[MAXOEMDATAWORDS];

} PENPACKET;

Members

wTabletX

The x-dimension in raw tablet coordinates.

wTabletY

The y-dimension in raw tablet coordinates.

wPDK

Pen hardware state bits, expressed as a combination of PDK_ values.

rgwOemData[MAXOEMDATAWORDS]

Array of OEM-specific data. MAXOEMDATAWORDS is defined as 6.

Comments

A pen packet is the basic unit of communication between the pen driver and Windows. A pen packet contains all of the information about a single logical event: x-y coordinate position, button states, and any optional information such as pressure or barrel rotation. Several physical events—that is, interrupts—may be needed to construct a single logical event.

The rgwOemData member contains the real-time values associated with the pen data types described in the entry for the OEMPENINFO structure.

See Also

SetPenHookCallback, OEMPENINFO, OEM_PENPACKET


PENTIP [New - Windows 95]
PENTIP

2.0      [New - Windows 95]

Pen tip characteristics.

typedef struct {

DWORD cbSize;

BYTE btype;

BYTE bwidth;

BYTE bheight;

BYTE bOpacity;

COLORREF rgb;

DWORD dwFlags;

DWORD dwReserved;

} PENTIP;

Members

cbSize

Size of this structure in bytes.

btype

Pen nib type. Types in the range 0 through 63 are reserved for predefined standard types. An application can use values in the range 64 through 255.

bwidth

Pen nib width, in display device units (pixels).

bheight

Pen nib height, in display device units (pixels). In the current version of the Pen API, this member is ignored.

bOpacity

Opacity of the ink, which corresponds to the JOT standard. bOpacity must have one of the following values:

Constant	Description
PENTIP_OPAQUE	New ink overwrites any existing ink.
PENTIP_HILITE	New ink is visible but partly transparent, possibly interacting with underlying ink.
PENTIP_TRANSPARENT	Ink is completely transparent. There is no interaction with any underlying ink.
rgb

RGB pen color.

dwFlags

Reserved.

dwReserved

Reserved; must be set to 0.

Comments

Before using PENTIP, an application must initialize cbSize with sizeof( PENTIP ).

See Also

GetStrokeAttributes, SetStrokeAttributes, GetStrokeTableAttributes, SetStrokeTableAttributes, GetPenMiscInfo, SetPenMiscInfo, INKINGINFO


RC [New - Windows 95]
RC

1.0    2.0      [New - Windows 95]

Defines a recognition context (RC) for applications compatible with version 1.0 of the Pen API. Applications that do not call the superseded functions Recognize or RecognizeData do not use the RC structure. These applications instead use HRC objects, which render RC obsolete.

Note

The RC structure is provided only for compatibility with version 1.0 of the Pen API and will not be supported in future versions.

typedef struct {

HREC hrec;

HWND hwnd;

UINT wEventRef;

UINT wRcPreferences;

LONG lRcOptions;

RCYIELDPROC lpfnYield;

BYTE lpUser[cbRcUserMax];

UINT wCountry;

UINT wIntlPreferences;

char lpLanguage[cbRcLanguageMax];

LPDF rglpdf[MAXDICTIONARIES];

UINT wTryDictionary;

CL clErrorLevel;

ALC alc;

ALC alcPriority;

BYTE rgbfAlc[cbRcrgbfAlcMax];

UINT wResultMode;

UINT wTimeOut;

LONG lPcm;

RECT rectBound;

RECT rectExclude;

GUIDE guide;

UINT wRcOrient;

UINT wRcDirect;

int nInkWidth;

COLORREF rgbInk;

DWORD dwAppParam;

DWORD dwDictParam;

DWORD dwRecognizer;

UINT rgwReserved[cwRcReservedMax];

} RC;

Members

hrec

Handle of recognizer to use.

hwnd

Window to which results are sent.

wEventRef

Index into ink buffer.

wRcPreferences

Flags specifying preferences, described in "Comments" section.

lRcOptions

Recognition options, described in "Comments" section.

lpfnYield

Procedure called during processing of the Yield Windows function.

lpUser[cbRcUserMax]

Current writer.

wCountry

Country code.

wIntlPreferences

Flags for international preferences.

lpLanguage[cbRcLanguageMax]

Language strings.

rglpdf[MAXDICTIONARIES]

List of dictionary functions.

wTryDictionary

Maximum enumerations to search.

clErrorLevel

Level where recognizer should reject input.

alc

Enabled ALC_ alphabet codes.

alcPriority

Sets priority of the ALC_ codes.

rgbfAlc[cbRcrgbfAlcMax]

Bit field for enabled characters.

wResultMode

Result return mode specifying when to send (either as soon as possible or when complete). The RRM_ codes are described in "Comments" section.

wTimeOut

Recognition time-out in milliseconds.

lPcm

Bitwise-OR combination of PCM_ flags for ending the recognition session.

rectBound

Bounding rectangle for inking. By default, the rectangle is in screen coordinates.

rectExclude

A pen-down event inside this rectangle terminates recognition.

guide

GUIDE structure that defines guidelines for recognizer.

wRcOrient

Orientation of writing with regard to the tablet.

wRcDirect

Direction of writing.

nInkWidth

Ink width of 1−15 pixels. A value of 0 prevents display of the ink.

rgbInk

Ink color.

dwAppParam

For application use.

dwDictParam

For application use; to be passed on to dictionaries.

dwRecognizer

For application use; to be passed on to recognizer.

rgwReserved[cwRcReservedMax]

Reserved.

Comments

The following paragraphs discuss the RC members, listed in the order in which they appear in the preceding structure.

hrec

The hrec member is the handle of the recognizer to use. This value should be set to the value returned by a previous call to InstallRecognizer, or to RC_WDEFAULT for the default recognizer.

If hrec is NULL, no recognizer is used. WM_RCRESULT messages are generated as with a real recognizer, but the wResultsType member of RCRESULT is set to RCRT_NORECOG, and the hSyv and lpsyv members are set to NULL. (For a list of other values in wResultsType, see the entry for RCRT_ values in Chapter 13, "Pen Application Programming Interface Constants.")

hwnd

The hwnd member specifies the window to send recognition results to. This member cannot be NULL. Also, the mouse capture is set to this window to clear the queue of pending mouse messages that were meant for recognition.

wEventRef

The value for wEventRef indicates which tablet data to begin recognition with. The wEventRef member is returned from the GetMessageExtraInfo function.

InitRC sets this member to RC_WDEFAULT. If Recognize is called during the processing of the WM_LBUTTONDOWN message that initiates the input session, the application need take no other action.

Before an application starts recognition on some other Windows event, it should use GetMessageExtraInfo to save the event reference of the appropriate mouse message and place this value in wEventRef before calling Recognize.

This member is not used on calls to RecognizeData.

wRcPreferences

The wRcPreferences member specifies the user preferences as a combination of RCP_ constants.

lRcOptions

The lRcOptions member specifies various options for recognition. It is a bitwise-OR combination of RCO_ constants.

lpfnYield

The lpfnYield member points to a callback function used by the recognizer before it yields. The application sets this to NULL for no yield processing. Recognition can often take more than a few seconds; therefore, a recognizer should periodically call the yield function to yield control to other Windows tasks. The default yield function is:

BOOL FAR PASCAL StandardYieldFunction()

{

Yield( );

return 1;

}

If Recognize or RecognizeData is called with lpfnYield set to RC_LDEFAULT, then the default yield function is called. If the lpfnYield member is not NULL, the recognizer calls lpfnYield every time before it yields.

lpUser

#define	cbRcUserMax	32

BYTE	lpUser[cbRcUserMax];

The lpUser member specifies the name of the current writer. The current writer is used to specify any custom prototype sets that might be available to the recognizer. If the lpUser member is NULL, it means that the recognizer should use the standard prototype set—that is, the prototype set as it existed before it was modified (through training, for example).

wCountry

The wCountry member contains the country code. The values for country code are the same as the values used by the International item of the Control Panel for the iCountry member in the [intl] section of the WIN.INI file.

wIntlPreferences

The wIntlPreferences member contains a combination of various RCIP_ flags. Currently, this member can be only 0 or RCIP_ALLANSICHAR. If 0, only characters from the current language or languages are enabled. If wIntlPreferences is RCIP_ALLANSICHAR, the entire ANSI character set is enabled.

lpLanguage

#define	cbRcLanguageMax	44

char	lpLanguage[cbRcLanguageMax]

The lpLanguage member is a list of language strings. Each string is null-terminated and the list ends with a null string.

The set of values for each language string is the same as the set used by the International item of the Control Panel for the sLanguage member in the [Intl] section of the WIN.INI file. These three-letter codes are documented in the Microsoft Windows Software Development Kit.

A recognizer should implement recognition of the ANSI character set and then use this information during recognition to limit a match to the appropriate subset. The lpLanguage member holds strictly optional information; a recognizer may choose to ignore it. By definition, the character set implied by a language string is the set of characters that can be generated from the country-specific keyboard without using the ALT+numeric keypad combinations. It is still possible to enter ANSI characters outside the given language through the use of the onscreen keyboard and ALT+numeric keypad combinations.

rglpdf

#define	MAXDICTIONARIES 16

LPDF	rglpdf[MAXDICTIONARIES]

The dictionary path member rglpdf specifies which dictionaries are called by the RC Manager to convert symbol graphs into strings.

If rglpdf[0] is NULL, the NULL dictionary path is used. The NULL dictionary path indicates that the first enumeration from the symbol graph is used as the best enumeration. The array of dictionary functions is null-terminated. During recognition, the dictionary functions are called in the order in which they appear. For more details, see the entry for the DictionarySearch function.

wTryDictionary

The wTryDictionary member specifies the maximum number of enumerations generated from the symbol graph during dictionary processing on the results of recognition. The minimum number allowed is 1 and the maximum is 4096. The default value is 100.

clErrorLevel

Recognition accuracy is defined as the percentage of times the recognizer accurately assigns a symbol to an input. There is no penalty or gain if the recognizer does not attempt a match and returns "unknown." The value can range from 0 to 100.

There are situations in which a higher accuracy rating is preferable despite an increased number of unknown results. For example, in a forms application, the Social Security field must be correctly recognized. If the recognizer is unsure, it can get the application to prompt the user again for the input (or a portion of it). At other times, it is preferable that the recognizer make a guess, no matter how wild, in order to limit the number of unknown results. For example, while taking notes in a meeting, the user may not care whether all of the results are transcribed perfectly.

The clErrorLevel member allows the application to signal its preference to the recognizer. Recognizers should return the SYV_UNKNOWN symbol for any symbol having a confidence level below clErrorLevel.

alc

The alc member is used to define the enabled alphabet for any RC structure with ALC_ constants. Any of the ALC_ constants can be combined together with a bitwise-OR operator to form the desired set of characters.

The actual characters enabled depend on the language. For example, if the user has requested French language support, the letter "è" is included in the lowercase alphabet. In the same way, "£" replaces "$" if ALC_MONETARY is set in British systems. For a list of alphabet values, see the entry for ALC_ values in Chapter 13, "Pen Application Programming Interface Constants."

Setting the RCIP_ALLANSICHAR flag in the wIntlPreferences member of the RC structure enables all characters of the appropriate set regardless of the language setting.

A recognizer that recognizes characters other than ANSI can ignore this member. If you want an application to pass character subset information to private non-ANSI recognizers, you can use the dwRecognizer member.

A recognizer should not return a symbol value outside the specified subset. However, a recognizer does not have to force a match to the subset; it can return SYV_UNKNOWN if a suitable match is not found.

alcPriority

The alcPriority member sets the priority of the ALC_ codes used to enable alphabets. It does this by telling the recognizer in which order to list options in the symbol graph.

The alcPriority member uses the same ALC_ codes used in the alc member. The bits set in alcPriority should be a subset of those set in alc. Bits set in alcPriority that are not also set in the alc member have no effect.

A recognizer can recognize a glyph that belongs to more than one enabled ALC_ subset. For example, a vertical stroke can be the letter "l" in the ALC_LCALPHA subset or the number "1" in the ALC_NUMERIC subset. The alcPriority member specifies that the recognizer should first return those interpretations that are in the subsets indicated in alcPriority. If no interpretations are in any of the alcPriority sets, or no priority members are set, the recognizer returns all possibilities within the enabled sets.

For example, suppose the user writes a symbol that looks like either a "q" or a "9." The generated symbol graph contains {q | 9 }. The alcPriority member determines the exact look of the symbol graph. If alcPriority has the ALC_ALPHA bit set, the recognizer should return { q | 9 } in the symbol graph. If alcPriority has the ALC_NUMERIC bit set, the recognizer should return { 9 | q } in the symbol graph.

Note that alcPriority does not affect the dictionary processing directly.

If ALC_USEBITMAP is set, the rgbfAlc member indicates which characters have priority.

rgbfAlc

#define	cbRcrgbfAlcMax	32

BYTE	rgbfAlc[cbRcrgbfAlcMax];

The rgbfAlc member is the bit field used for enabled characters. For more details, see the description of ALC_ constants. If ALC_USEBITMAP is set, the 256-bit bit field in rgbfAlc is used to indicate which characters from the ANSI character set are currently enabled. Character 0 is the low bit of the low-order byte in the array. Characters thus indicated are connected by OR operators to any characters enabled using the other ALC_ codes. A "1" set in a bit array indicates that the character is enabled.

As an example, to enable the "$" character, set the fifth bit of byte four like this:

rgbfAlc[4] |= 0x10

A recognizer that recognizes characters other than ANSI can ignore this member. If an application wants to pass character subset information to private non-ANSI recognizers, it can use the dwRecognizer member of the RC structure.

A set of macros, defined in PENWIN.H, simplifies user setting and testing the rgbfAlc bits for an RC structure. The ANSI macros listed in the following table set (bit=1), clear (bit=0), or test (TRUE if bit==1, else FALSE) the appropriate bits in lprc->rgbfAlc corresponding to the index i, which is the ANSI value to use. The lprc is a pointer to the RC structure containing the rgbfAlc[] array.

Macro	Description
SetAlcBitAnsi( lprc, i )	Sets the bit specified by i in rgbfAlc of lprc to 1.
ResetAlcBitAnsi( lprc, i )	Resets the bit specified by i in rgbfAlc of lprc to 0.
IsAlcBitAnsi( lprc, i )	Returns TRUE if the bit specified by i in rgbfAlc of lprc is set.
Only the IsAlcBitAnsi macro returns a value (BOOL). The return values of the other macros are undefined.

Setting bits in rgbfAlc[] also requires combining ALC_USEBITMAP by an OR operator with alc for the bits to have meaning. The bits are used in addition to other alc settings. For example, adding ALC_NUMERIC does not also set the bits in rgbfAlc that correspond to 0 through 9. Thus, to recognize octal numbers (the set 0 to 7), use the following code:

RC rc;

int i;

rc.alc = ALC_USEBITMAP;                // Note no ALC_NUMERIC

for (i = (int)'0'; i <= (int)'7'; i++)

SetAlcBitAnsi( &rc, i );

wResultMode

The wResultMode member specifies the timing and granularity of the results messages to be sent back to the specified window. The following times are defined.

Constant	Description
RRM_WORD	The granularity is set at a word boundary. As soon as the recognizer sees a word break, it can send all symbols up to the point of the word break.
RRM_NEWLINE	The granularity is set at a new line. As soon as the recognizer sees a line break, it sends the result to that point.
RRM_COMPLETE	When recognition is completed by one of the methods (for example, time-out or barrel button), the results message is sent just before Recognize returns.
RRM_STROKE	The granularity is set at the stroke level. A result message is sent at each stroke. This is used in the NULL recognizer.
RRM_SYMBOL	The granularity is set at the symbol level. A result message is sent at each symbol. Default dictionary processing is disabled when this value is used.
A recognizer is free to send the messages any time after the requested time (defined in the preceding order), but it cannot send any messages sooner. Because of recognizer constraints, a recognizer may combine intermediate results messages. For example, if an application requests RRM_WORD, the recognizer may choose to return results on a line-by-line basis instead.

Results sent at a word boundary do not have to be sent strictly one word at a time. The requirements are as follows:

•	The raw data returned must be contiguous, and it must begin with a pen-down and end with a pen-up.

•	The returned "word" may contain spaces. For example, "fat{space | NULL}cat" would be resolved into two words, "fat cat." This is also necessary if the raw data for successive words overlaps.

•	The recognizer should not send a word until it knows what follows the word. If the word is followed by a word on the same line, the word should be space-terminated. If the word is followed by text on a new line, the recognizer should append a soft newline symbol. The key point is that the recognizer must make it possible for the application to detect word and line spacing so it can display the recognized text appropriately.

•	Once a word has been sent, the recognizer cannot change the results because of the late arrival of more strokes.

The rules for returning results with RRM_NEWLINE are similar:

•	The new line should be included with the symbol graph in the result.

•	Once a word has been sent, the recognizer cannot change the results because of the late arrival of more strokes.

wTimeOut

The wTimeOut member specifies the time-out threshold. After the time-out threshold has passed, the recognizer stops the recognition process.

Time-out occurs if more than wTimeOut milliseconds elapse between the most recent pen-up and the next pen-down. If time-out occurs, the recognition context is closed. Closing a recognition context means no more data is accepted; the existing data is processed and the results are sent to the application. This value is ignored if lPcm does not enable time-out.

In general, applications should use the value set by the user in the Control Panel. This value can be set by setting this member to RC_WDEFAULT.

The maximum value allowed is 65,534 milliseconds. If wTimeOut is set to 0xFFFF (65,535), the system-level value is used.

lPcmrectBound
rectExclude

These three members of the RC structure set the conditions for ending recognition. The lPcm member sets the flags for ending recognition, expressed as a bitwise-OR combination of PCM_ values.

The two RECT members specify inclusive and exclusive rectangles for inking. The rectangle values are in screen coordinates or, if RCO_TABLETCOORD is set, in tablet coordinates. RCO_TABLETCOORD cannot be used with ProcessWriting.

When RCRESULT is returned, the rectBound and rectExclude values are converted from screen to tablet coordinates and the RCO_TABLETCOORD flag is set.

Only pen events within rectBound are collected as part of the recognition context. If PCM_RECTBOUND is set in lPcm, the first pen-down event outside the rectangle closes the context. Dragging the pen outside the rectangle after starting inside does not close the context; the data is still collected outside the rectangle.

If PCM_RECTEXCLUDE is set in lPcm, any pen-down event within rectExclude closes the context. The event that ends pen collection mode—that is, an event outside the bounding rectangle or inside the exclusion—is entered into Windows as a mouse event. For hit-testing the rectangles, the top and left borders are included, but not the right or bottom borders.

The bounding rectangle set by InitRC is valid only until the window is resized or moved. If the window is moved or resized, the application should specify again the rectBound member in the RC structure.

guide

The guide member is a structure of the GUIDE type. It contains information that specifies the placement of guidelines in the writing area for the recognizer's use.

wRcOrient

The wRcOrient member specifies the orientation of the tablet, expressed as RCOR_ values. For a list of orientation values, see the entry for RCOR_ values in Chapter 13, "Pen Application Programming Interface Constants."

wRcDirect

The wRcDirect member informs the recognizer of the direction of writing, expressed as RCOR_ values. There are both primary and secondary directions. For example, English is written from left to right (primary) and then down the page (secondary). Chinese is often written from the top down (primary) and then right to left across the page (secondary). For a list of direction values, see the entry for RCD_ values in Chapter 13, "Pen Application Programming Interface Constants."

The high byte of the direction indicates primary direction; the low byte, secondary direction. A recognizer can choose to ignore this word and support only the natural direction of the given language. The default value is determined by the recognizer.

Not all recognizers can respond to this member.

nInkWidth
rgbInk

These two members specify the ink width and color to be used during inking. The nInkWidth member is the thickness in pixels of the pen to use during inking. If this value is 0, no ink is drawn. The current maximum value allowed is 15. The default is the ink width set in the global RC.

The rgbInk member is the color to use for inking. If this is not a solid color, it is mapped to the closest solid color. The default is the ink color set in the global RC.

dwAppParam
dwRecognizer

These two members are analogous to the dwDictParam member described below. The dwAppParam value is provided for use by the application and passed to the application by way of the lprc member in the RCRESULT structure.

The dwRecognizer value is passed to the recognizer specified in rc.hrec. Applications can use this to pass information to a private recognizer for functionality not directly supported.

These values are set to 0 by InitRC and should remain 0 if they are not used by the application or recognizer.

dwDictParam

The dwDictParam parameter is set by an application and passed on to the dictionary by the RC Manager. It is intended to provide for dictionary functionality not directly supported. For example, a dictionary can request that the application pass in a pointer to a structure that contains a given sentence. You can use this information to extend the dictionary functionality—to highlight misspelled words, for example.

If it is not used by the application, dwDictParam should be left to the value (0) set by InitRC.

rgwReserved[cwRcReservedMax]

The rgwReserved member is reserved. Applications should not change the values set by InitRC for this member.

See Also

GUIDE, PCMINFO

ALC_, RCRT_, PCM_, RCD_, RCOR_


RCRESULT [New - Windows 95]
RCRESULT

1.0    2.0      [New - Windows 95]

Applications that do not call the superseded functions RecognizeData or Recognize do not use the RCRESULT structure. In conforming to version 2.0 of the Pen API, applications instead use HRCRESULT objects, which render RCRESULT obsolete.

Note

The RCRESULT structure is provided only for compatibility with version 1.0 of the Pen API, and will not be supported in future versions.

typedef struct {

SYG syg;

UINT wResultsType;

int cSyv;

LPSYV lpsyv;

HANDLE hSyv;

int nBaseLine;

int nMidLine;

HPENDATA hpendata;

RECT rectBoundInk;

POINT pntEnd;

LPRC lprc;

} RCRESULT;

Members

syg

Symbol graph.

wResultsType

An RCRT_ value.

cSyv

Number of symbol values, not including the NULL terminator.

lpsyv

Null-terminated pointer to the recognizer's best guess.

hSyv

Globally shared handle to the symbol value specified by the lpsyv member.

nBaseLine

Zero or baseline of input writing.

nMidLine

Zero or midline of input writing.

hpendata

Handle to pen data.

rectBoundInk

Bounding rectangle for ink.

pntEnd

Point that terminated recognition.

lprc

Recognition context used.

Comments

When an application calls Recognize, RecognizeData, or ProcessWriting, the WM_RCRESULT message is sent to the appropriate window procedure when the recognizer has a result to return. The wParam parameter of the message contains the reason recognition ended (one of the REC_ codes). It is REC_OK if more results will be sent; otherwise, it is the same value for the last message returned by Recognize or RecognizeData. The lParam parameter is a far pointer to an RCRESULT structure. All of the data in the RCRESULT structure is in tablet coordinates.

 The following sections elaborate on the RCRESULT members. All of the members are allocated with GMEM_SHARE so they can be passed between processes.

syg

This member contains the raw results returned by the recognizer. These include the various possible interpretations of the pen input, the mapping of the results to the raw data, and locations of any hot spots if the result is a gesture. The syg.lpsyc member is not valid unless RCP_MAPCHAR was set in the RC structure when Recognize or RecognizeData was called.

wResultsType

This member indicates the type of recognition results, expressed as a bitwise-OR combination of RCRT_ values. The RCRT_ values are not mutually exclusive. Note that the recognizer should never have to set RCRT_GESTURETOKEYS, RCRT_ALREADYPROCESSED,  or RCRT_GESTURETRANSLATED. For a list of values, see the entry for RCRT_ values in Chapter 13, "Pen Application Programming Interface Constants."

lpsyv

This member contains the symbols that are recognized. An application should use these values to display the text or gestures recognized. The lpsyv member is the result of any dictionary search on the SYG structure or further postprocessing. It is NULL if the NULL recognizer is used.

hpendata

This member contains the raw data captured during inking.

rectBoundInk

This is the bounding rectangle of the ink drawn during recognition. It is in coordinates of the window that receives the results. If the user attempts to draw ink outside rc.rectbound, the ink will not be displayed. However, rectBoundInk is calculated as though the ink were drawn.

If data is collected outside the bounding rectangle, the rectBound member of PENDATAHEADER reflects this. (Note that rectBound applies only to pen-down points.) This means, however, that a portion of the rectBoundInk rectangle lies outside the rc.rectBound rectangle. The actual ink drawn lies in the intersection of rectBoundInk and the rc.rectBound rectangle. Before calculating the intersection, convert rectBoundInk from tablet to screen coordinates. The bounding rectangle includes the width of the ink drawn.

pntEnd

If recognition ended on a tap outside the bounding rectangle or inside the exclusive rectangle, pntEnd contains the coordinates of those points in display coordinates.

lprc

This is the RC used for recognition. Any default values (RC_WDEFAULT or RC_LDEFAULT) are replaced by the correct default value.

See Also

RC, SYG, RCRT_


RECTOFS [New - Windows 95]
RECTOFS

1.0    2.0      [New - Windows 95]

Rectangle offset for nonisometric inflation of a rectangular writing area.

typedef struct {

int dLeft;

int dTop;

int dRight;

int dBottom;

} RECTOFS;

Members

dLeft

Inflation margin leftward from left side.

dTop

Inflation margin upward from top.

dRight

Inflation margin rightward from right.

dBottom

Inflation margin downward from bottom.

Comments

Inflation margins are in screen (pixel) coordinates. To inflate a window rectangle, dLeft and dTop should be negative (moving in the negative x- and y-directions, respectively) and dRight and dBottom should be positive. To deflate the rectangle, reverse the signs of the margins.

In addition to having the basic characteristics of an edit control, an hedit or bedit control must make allowances for the input of handwriting. The client rectangle often needs to be adjusted to a larger size to allow for easier writing.

For example, the cut gesture typically extends above the selected text it is deleting. If the gesture is arbitrarily clipped off at the edge of the client window, recognition accuracy suffers. Likewise, restricting handwriting input to stay within the lines can also hinder recognition accuracy. To correct this, rectangle offsets are used in hedit and bedit controls to make the writing area slightly larger than the client window size of a normal edit control. The HE_SETINFLATE and HE_GETINFLATE wParam values of the WM_PENCTL message are used for this purpose. These messages use a RECTOFS structure as a parameter. The values in the RECTOFS structure are added to the corresponding client area to create the bounding rectangle for the ink.

The inflation does not need to be symmetrical in every direction.

See Also

WM_PENCTL, HE_SETINFLATE, HE_GETINFLATE


SKBINFO [New - Windows 95]
SKBINFO

1.0    2.0      [New - Windows 95]

Stores information about the current onscreen keyboard.

typedef struct {

HWND hwnd;

UINT nPad;

BOOL fVisible;

BOOL fMinimized;

RECT rect;

DWORD dwReserved;

} SKBINFO;

Members

hwnd

Handle of window for onscreen keyboard.

nPad

Current view of the keypad. Either SKB_FULL, SKB_BASIC, or SKB_NUMPAD for full, basic, or numeric keypad, respectively.

fVisible

TRUE if the keyboard is available and visible, FALSE otherwise.

fMinimized

TRUE if the keyboard is minimized, FALSE otherwise.

rect

Screen coordinates or the restored keyboard rectangle.

dwReserved

Must be 0.

See Also

ShowKeyboard


STRKFMT [New - Windows 95]
STRKFMT

2.0      [New - Windows 95]

Provides a method for retrieving or changing the attributes of specified strokes in an iedit control. This structure is used by the IE_GETFORMAT and IE_SETFORMAT messages.

typedef struct {

DWORD cbSize;

UINT iesf;

UINT iStrk;

PENTIP tip;

DWORD dwUser;

DWORD dwReserved;

} STRKFMT;

Members

cbSize

Size of this structure in bytes.

iesf

Stroke format flags. Note that the first three flags cannot be combined with each other by the bitwise OR operator:

Constant	Description
IESF_ALL	Assume all strokes in the control.
IESF_SELECTION	Assume all selected strokes.
IESF_STROKE	Assume the stroke specified in the iStrk member, described in "Comments" section.
IESF_PENTIP	Set both pen tip color and width.
IESF_TIPCOLOR	Set only pen tip color.
IESF_TIPWIDTH	Set only pen tip width.
iStrk

Index of a specific stroke.

tip

PENTIP structure, containing ink tip attributes.

dwUser

User data for stroke.

dwReserved

Reserved.

Comments

When sending either IE_GETFORMAT or IE_SETFORMAT, the application initializes the iesf member with bit flags, indicating:

•	The strokes in the iedit control to which the IE_ messages refer.

•	The attributes (color and/or width) of those strokes.

Setting the IESF_STROKE bit flag in iesf limits action to the single stroke identified in iStrk. Setting IESF_SELECTION references all selected strokes. Setting IESF_ALL references all strokes in the control. These flags are mutually exclusive and cannot be combined.

The application must also set the bit flags IESF_TIPCOLOR or IESF_TIPWIDTH in the iesf member of the structure. These bit flags identify the stroke attribute to which the IE_ messages refer. For convenience, the defined value IESF_PENTIP combines IESF_TIPCOLOR and IESF_TIPWIDTH to identify both color and width.

With these bit flags, an application can alter stroke color and width at the same time or alter only one attribute while leaving the other unchanged.

Sending an IE_GETFORMAT message to the control produces the following results:

•	If the requested strokes have the same color and width, the returned STRKFMT contains the common color and width in the rgb and bwidth members of its PENTIP structure. The return value from IE_GETFORMAT is 0.

•	If the requested strokes do not all share the same attribute, the returned STRKFMT contains the attribute of the last stroke in the group. The return value from IE_GETFORMAT contains the bit flags IESF_TIPCOLOR and/or IESF_TIPWIDTH to indicate the attribute in which the strokes differ.

Before using STRKFMT, an application must initialize cbSize with sizeof( STRKFMT ).

See Also

IE_GETFORMAT, IE_SETFORMAT, PENTIP


STROKEINFO [New - Windows 95]
STROKEINFO

1.0    2.0      [New - Windows 95]

Contains information about a sequence of pen data.

typedef struct {

UINT cPnt;

UINT cbPnts;

UINT wPdk;

DWORD dwTick;

} STROKEINFO;

Members

cPnt

Count of points in the stroke.

cbPnts

Used internally to contain length of compressed data. Applications should ignore this value.

wPdk

State of the stroke, expressed as a PDK_ value.

dwTick

Time at beginning of the stroke. dwTick holds the number of milliseconds that have elapsed since the system tick reference that Windows determines at startup.

Comments

The STROKEINFO structure serves two main purposes. First, it is returned by the  GetPenHwEventData functions with each piece of new data from the tablet. Second, it is used in certain pen data functions such as AddPenInputHRC, AddPointsPenData, and GetPenDataStroke as a header for each stroke. In both cases, it contains information about a sequence of data from the tablet.

For examples and further information about STROKEINFO and its members, see the section "Recognition Functions" in Chapter 8, "Writing a Recognizer."

For a list of stroke state bits, refer to the entry for PDK_ values in Chapter 13, "Pen Application Programming Interface Constants."

See Also

AddPenInputHRC, GetPenDataStroke, GetPenInput, GetPenHwEventData, InsertPenDataStroke, TargetPoints, PDK_


SYC [New - Windows 95]
SYC

1.0    2.0      [New - Windows 95]

The SYC symbol correspondence structure is best described in context with the SYG symbol graph and SYE symbol element structures. For a description of the SYC structure, see the entry for SYG below.

Note

The SYC structure is provided only for compatibility with version 1.0 of the Pen API and will not be supported in future versions.

A single shape can be identified by one or more SYC structures.

typedef struct {

UINT    wStrokeFirst;

UINT    wPntFirst;

UINT    wStrokeLast;

UINT    wPntLast;

BOOL    fLastSyc;

} SYC;

Members

wStrokeFirst

Index number of the first stroke of the correspondence.

wPntFirst

Index number of the first point in the stroke identified by wStrokeFirst.

wStrokeLast

Index number of the last stroke of the correspondence.

wPntLast

Index number of the last point in the stroke identified by wStrokeLast.

fLastSyc

TRUE if there are no more SYC structures for the current SYE (symbol element).

Comments

All indexes are zero-based, so that an index of 0 indicates the first of a sequence.

Figure 11.6 illustrates the relationship of symbol values and symbol graphs. The first line shows that a symbol value is a single SYE symbol element. A series of symbol values can be connected by the SYV_OR value to create an OR string, as the second line illustrates. This OR string begins with the SYV_BEGINOR value and ends with a symbol value followed by SYV_ENDOR. The third line shows a symbol graph that is simply a symbol value or an OR string, in either case ending with the SYV_NULL value.

See Also

RCRESULT, TrainContext, SYV_


SYE [New - Windows 95]
SYE

1.0    2.0      [New - Windows 95]

The SYE symbol element structure is best described in context with the SYG symbol graph and SYC symbol correspondence structures. For a description of the SYE structure, see the entry for SYG below.

Note

The SYE structure is provided only for compatibility with version 1.0 of the Pen API, and will not be supported in future versions.

An SYE structure contains a symbol, which can be a character, gesture, or string.

typedef struct {

SYV     syv;

LONG    lRecogVal;

CL      cl;

int     iSyc;

} SYE;

Members

syv

Symbol value.

lRecogVal

Reserved.

cl

Confidence level.

iSyc

Index into array of SYC structures. The array identifies the raw data that makes up the symbol. It is possible for several SYE structures to use the same SYC structures.


SYG [New - Windows 95]
SYG

1.0    2.0      [New - Windows 95]

A symbol graph, which represents the possible interpretations identified by the recognizer.

typedef struct {

POINT rgpntHotSpots[MAXHOTSPOT];

int cHotSpot;

int nFirstBox;

LONG lRecogVal;

LPSYE lpsye;

int cSye;

LPSYC lpsyc;

int cSyc;

SYV syv;

LONG lRecogVal;

CL cl;

int iSyc;

UINT wStrokeFirst;

UINT wPntFirst;

UINT wStrokeLast;

UINT wPntLast;

BOOL fLastSyc;

} SYG;

Members

rgpntHotSpots[MAXHOTSPOT]

Hot spots of the symbol (if any). MAXHOTSPOT is defined as 8.

cHotSpot

Number of valid hot spots in rgpntHotSpots.

nFirstBox

Row-major index to box of first character in result.

lRecogVal

Reserved.

lpsye

Pointer to array of SYE structures representing nodes of symbol graph.

cSye

Number of SYE structures in array lpsye.

lpsyc

Pointer to corresponding array of SYC symbol ink structures.

cSyc

Number of SYC structures in symbol graph.

Comments

All indexes are zero-based.

If a single entity recognized by the recognizer is mapped to a string of several symbol values, the recognizer creates multiple SYE. This is the case for recognizers that can recognize highly stylized sequences of characters—for example, "ing"—in which the individual characters are not necessarily recognized.

The nFirstBox member has no meaning for gestures. A gesture is applied to the location indicated by its hot spot.

The SYG, SYE, and SYC structures define the relationship between raw pen data and recognized results. However, in version 2.0 of the Pen API they are rarely of interest to applications for two reasons. First, API functions return recognition results without forcing the application to deal with the complexities of raw pen data. And second, SYG, SYE, and SYC apply mainly to recognizers.

All nontrivial recognizers should somehow track the pen strokes that form each character in the returned results. To be compatible with version 1.0, a recognizer must use the SYG, SYE, and SYC structures and return a symbol graph—an SYG structure—as a member of the RCRESULT structure. Version 2.0 does not mandate how a recognizer should map pen data to symbols. However, these three structures represent a viable method. Recognizer developers writing for version 2.0 may want to use the structures or create variations.

The following information applies to version 1.0 applications and recognizers, and to version 2.0 recognizers that employ symbol graphs to relate strokes to recognized symbols. For further information about SYG, SYE, and SYC, see "Returning Results" in Chapter 8, "Writing a Recognizer."

A symbol graph is a representation of the possible interpretations identified by the recognizer. The RC Manager processes the symbol graph using the dictionary path to identify the best interpretation. This best interpretation is returned in the results message along with the symbol graph.

A symbol value is a 32-bit value that represents a glyph (such as a character or a gesture) recognized by a recognizer. This is sometimes referred to as a symbol. A symbol string is an array of symbols terminated with SYV_NULL.

Each element of the symbol graph, an SYE, contains information about the recognized character—for example, bounding rectangle and hot spots. The SYC structure maps SYE structures back to the corresponding raw data. If two or more consecutive SYE structures map to the same SYC, they represent an indivisible unit. For example, the user might teach the system of "th" with the crossbar of the "t" connected to the "h." SYC structures are used primarily for training.

A version 1.0 application generally does not use the symbol graph directly. Instead, it uses the hSyv member of RCRESULT, which contains a symbol string that represents the best interpretation from the symbol graph. SYE and SYC structures work together with the HPENDATA memory block to identify strokes and meanings for ink. The following table lists the basic functions of these structures.

Structure	Description
HPENDATA	Contains raw data information: strokes, pen up, pen down, points, and so on.
SYC	A symbol character map. SYC structures delimit strokes in an HPENDATA. A single shape can be identified  by one or more SYC structures. Each SYC identifies a starting stroke, an ending stroke, a starting point, and an ending point. A flag also indicates whether subsequent SYC structures in the array contain additional strokes for the shape. (This feature is used for delayed strokes, such as the cross stroke of the letter "t.")
SYE	A symbol element. An SYE contains a symbol, which can be a character, a gesture, or a string. The symbol  is denoted by an SYV. The SYE contains an index into an array of SYC structures; this array identifies the  raw data that makes up the symbol. It is possible for several SYEs to use the same SYC structures. The  SYC structures contain indexes into the raw data.
SYV	A symbol value.
SYG	A symbol graph.
A set of SYEs and SYCs, together with an HPENDATA structure, is sufficient to define ink and specify how that ink should be interpreted. The training functions TrainContext and TrainInk use this information in training.


TARGET [New - Windows 95]
TARGET

2.0      [New - Windows 95]

Contains information about a single target.

typedef struct {

DWORD dwFlags;

DWORD idTarget;

HTRG htrgTarget;

RECTL rectBound;

DWORD dwData;

RECTL rectBoundInk;

RECTL rectBoundLastInk;

} TARGET;

Members

dwFlags

Reserved for future extensions. Must be set to 0.

idTarget

Array index to the target within rgTarget array in TARGINFO structure.

htrgTarget

Handle to the owner window that receives messages on behalf of the target.

rectBound

Bounding rectangle of the target.

dwData

Target-specific extra information to be filled during data collection.

rectBoundInk

Reserved; must be 0.

rectBoundLastInk

Reserved; must be 0.

See Also

TargetPoints, TARGINFO, WM_PENEVENT, INPPARAMS


TARGINFO [New - Windows 95]
TARGINFO

2.0      [New - Windows 95]

A set of targets.

typedef struct {

DWORD cbSize;

DWORD dwFlags;

HTRG htrgOwner;

WORD cTargets;

WORD iTargetLast;

TARGET rgTarget[1];

} TARGINFO;

Members

cbSize

Size of this structure in bytes. Note that this is the original size, which assumes only a single TARGET structure in rgTarget. The value should be sizeof( TARGINFO ).

dwFlags

Flags have been defined to get different targeting behavior depending on the needs of the calling application. These flags work as hints for the targeting algorithm. The flags are considered by the Pen API in the order in which they appear in the following list. If none of the flags are set, the stroke is not assigned to any target.

TPT_TEXTUAL

When this flag is set, Windows applies textual heuristics, such as identifying word breaks, while deciding the target to which a stroke should be assigned.

If there is no text to intersect with, the input is disregarded completely. Therefore, this option should not generally be used by itself.

TPT_INTERSECTINK

Indicates that if the stroke being targeted intersects with the ink in a target, the stroke should be assigned to that target. Intersection is determined based on the bounding rectangle of the stroke and the bounding rectangle of the pen data assigned to a target. If there is no ink to intersect with, the input is disregarded completely. Therefore, this option should not generally be used by itself.

TPT_CLOSEST

Indicates that the stroke should be targeted to the target closest to the stroke. The bounding rectangle of the stroke and the bounding rectangle of the target are specified by the rectBound element of the TARGET structure.

htrgOwner

Handle to the owner target. Use the HtrgFromHwnd and HwndFromHtrg macros to convert a target handle of HTRG type to and from an HWND type.

cTargets

Number of targets.

iTargetLast

Last target. Used by the TargetPoints function during textual heuristics. iTargetLast contains the number of the target window that last received data. The system uses this value to optimize its determination of the next target. Applications can read but should not overwrite iTargetLast.

rgTarget[1]

Variable-length array of targets.

Comments

For best results, most applications should set all hints for targeting. That is, the dwFlags member of TARGINFO should be set to TPT_DEFAULT, which is the combination of TPT_TEXTUAL | TPT_INTERSECTINK | TPT_CLOSEST.

Before using TARGINFO, an application must initialize cbSize with sizeof( TARGINFO ).

See Also

TARGET, TargetPoints


Pen Application Programming Interface Messages

This chapter describes in alphabetical order many of the messages and submessages defined by the Pen Application Programming Interface. Each entry describes a separate message organized under the following topic headings:

Topic heading	Description
Parameters	Message wParam and lParam parameters.
Return Value	Return value from the Windows SendMessage function (if applicable).
Comments	Additional information about the message.
See Also	Cross-references to related API services.


HE_CANCELCONVERT [New - Windows 95]
HE_CANCELCONVERT

[New - Windows 95]

Cancels Kana-to-Kanji conversion. Submessage of WM_PENCTL. (Japanese version only.)

Parameters

wParam

HE_CANCELCONVERT.

lParam

Reserved and must be 0.

Return Value

Returns TRUE if there are no errors; otherwise, returns FALSE.


HE_CHAROFFSET [New - Windows 95]
HE_CHAROFFSET

[New - Windows 95]

Converts the logical character position of a character in a control into a byte offset to the character. Submessage of WM_PENCTL.

Parameters

wParam

HE_CHAROFFSET.

lParam

The low-order word contains the logical character position. The high-order word is reserved and must be 0.

Return Value

If the supplied logical character position is less than the total number of logical characters in the control, the low-order word of the return value contains the requested byte offset of the position and the high-order word is 0. Otherwise, the low-order word contains the length of the text in bytes and the high word contains 0xFFFF.

Comments

This submessage is for bedit controls only. Both the logical character position and the byte offset are zero-based.

See Also

WM_PENCTL


HE_CHARPOSITION [New - Windows 95]
HE_CHARPOSITION

[New - Windows 95]

Converts a byte offset in the text buffer of a control to the logical character position, which contains the byte specified by the byte offset. Submessage of WM_PENCTL.

Parameters

wParam

HE_CHARPOSITION.

lParam

The low-order word contains the byte offset. The high word is reserved and must be 0.

Return Value

If the supplied byte offset is less than the length of the text in bytes, the low-order word of the return value contains the logical character position and the high-order word is 0; otherwise, the low-order word contains the total number of logical characters in the text of the control and the high-order word contains 0xFFFF.

Comments

This submessage is for bedit controls only. Both the byte offset and the logical character position are zero-based.

See Also

HE_CHAROFFSET, WM_PENCTL


HE_DEFAULTFONT [New - Windows 95]
HE_DEFAULTFONT

[New - Windows 95]

Switches the font of a bedit control to the default font that the bedit control selected at the time of creation. Submessage of WM_PENCTL.

Parameters

wParam

HE_DEFAULTFONT.

lParam

If the low-order word is nonzero, the control is repainted.

Return Value

The return value is undefined.

Comments

This submessage is for bedit controls only.

See Also

WM_PENCTL


HE_ENABLEALTLIST [New - Windows 95]
HE_ENABLEALTLIST

[New - Windows 95]

Enables or disables the alternate list in a bedit control. Submessage of WM_PENCTL.

Parameters

wParam

HE_ENABLEALTLIST.

lParam

If the low-order word is nonzero, the alternate list menu is enabled; otherwise, it is disabled.

Return Value

The return value is undefined.

Comments

This submessage is for bedit controls only.

See Also

HE_HIDEALTLIST, HE_SHOWALTLIST, WM_PENCTL


HE_FIXKKCONVERT [New - Windows 95]
HE_FIXKKCONVERT

[New - Windows 95]

Confirm undetermined string and close Input Method Editor (IME). Submessage of WM_PENCTL. (Japanese version only.)

Parameters

wParam

HE_FIXKKCONVERT.

lParam

Reserved and must be 0.

Return Value

Returns TRUE if there are no errors; otherwise, returns FALSE.

Comments

When in preconversion mode, the marked conversion string area is removed. Marked conversion strings are indicated in the Input Method Editor (IME) in a different shade than standard edit control text selection. When in conversion mode (no marked string), the string is confirmed and the IME is closed. Available for bedits only.


HE_GETBOXLAYOUT [New - Windows 95]
HE_GETBOXLAYOUT

[New - Windows 95]

Retrieves the box layout for a control. Submessage of WM_PENCTL.

Parameters

wParam

HE_GETBOXLAYOUT.

lParam

Address of a BOXLAYOUT structure that is filled with the current box layout for the control.

Return Value

The return value is undefined.

Comments

This submessage is for bedit controls only.

See Also

BOXLAYOUT, WM_PENCTL


HE_GETCONVERTRANGE [New - Windows 95]
HE_GETCONVERTRANGE

[New - Windows 95]

Gets the range of the marked conversion string. Submessage of WM_PENCTL. (Japanese version only.)

Parameters

wParam

HE_GETCONVERTCHAR.

lParam

Not used.

Return Value

Returns a 32-bit value with the starting character position (not byte position) of the marked conversion string in the low-order word and the position of the last character of the marked conversion string plus 1 in the high-order word.

Comments

Available for bedits only. The message returns a valid value only when in preconversion mode; otherwise, it returns 0.


HE_GETINFLATE [New - Windows 95]
HE_GETINFLATE

[New - Windows 95]

Retrieves the inflation rectangle for a control. Submessage of WM_PENCTL.

Parameters

wParam

HE_GETINFLATE.

lParam

Address of a RECTOFS structure that is filled with the current values for the inflation rectangle.

Return Value

Returns TRUE if successful; otherwise, FALSE.

Comments

For a description of how to increase or decrease the writing area of a control, see "HE_SETINFLATE Submessage" in Chapter 3, "The Writing Process."

See Also

HE_SETINFLATE, RECTOFS, WM_PENCTL


HE_GETINKHANDLE [New - Windows 95]
HE_GETINKHANDLE

[New - Windows 95]

Retrieves the ink handle for the current control. Submessage of WM_PENCTL.

Parameters

wParam

HE_GETINKHANDLE.

lParam

Unused.

Return Value

The low-order word of the return value contains a handle to the captured ink. If the return value is NULL, the control is not in ink mode.

Comments

The returned ink handle is valid only during the life of the control. The handle becomes invalid after the control is destroyed.

See Also

WM_PENCTL


HE_GETKKCONVERT [New - Windows 95]
HE_GETKKCONVERT

[New - Windows 95]

Determines if the Input Method Editor (IME) is in conversion mode. Submessage of WM_PENCTL. (Japanese version only.)

Parameters

wParam

HE_GETKKCONVERT.

lParam

Reserved and must be 0.

Return Value

Returns TRUE if the IME is in conversion mode; otherwise, returns FALSE.

Comments

Available for bedits only.


HE_GETKKSTATUS [New - Windows 95]
HE_GETKKSTATUS

[New - Windows 95]

Determines the mode of the Kana-to-Kanji conversion in the Input Method Editor (IME). Submessage of WM_PENCTL. (Japanese version only.)

Parameters

wParam

HE_GETKKSTATUS.

lParam

Reserved and must be 0.

Return Value

Returns one of the following values or FALSE:

Value	Current Status
HEKKR_PRECONVERT	In preconversion mode.
HEKKR_CONVERT	In conversion mode
HHEKKR_NOCONVERT	In nonconversion mode
Comments

The IME recognizes three modes: preconversion mode, conversion mode, and non-conversion mode. In preconversion mode, the user has entered text intended for conversion by the IME and the text is marked. When the user invokes the IME on the marked range of characters, the conversion mode is entered and the IME is active. Once the user confirms an IME conversion, the nonconversion mode (normal mode) is entered.

The term "marked" refers to the range of cells in the bedit that have been selected for character conversion. Characters marked for conversion appear differently to the user than normally selected characters.

This submessage is available for bedits only. This message can also be used to determine keyboard IME status by checking for HEKKR_CONVERT.


HE_GETUNDERLINE [New - Windows 95]
HE_GETUNDERLINE

[New - Windows 95]

Queries for the current underline mode. Submessage of WM_PENCTL.

Parameters

wParam

HE_GETUNDERLINE.

lParam

Unused.

Return Value

Returns TRUE if the underline mode is set; otherwise, FALSE.

Comments

This submessage is for hedit controls only.

See Also

WM_PENCTL


HE_HIDEALTLIST [New - Windows 95]
HE_HIDEALTLIST

[New - Windows 95]

Hides the alternate list in a bedit control, assuming an alternate list menu is being displayed. Submessage of WM_PENCTL.

Parameters

wParam

HE_HIDEALTLIST.

lParam

If the low-order word is HEAL_DEFAULT, the alternate list menu is hidden.

Return Value

The return value is undefined.

Comments

This submessage is for bedit controls only.

See Also

HE_ENABLEALTLIST, HE_SHOWTLIST, WM_PENCTL


HE_KKCONVERT [New - Windows 95]
HE_KKCONVERT

[New - Windows 95]

Starts Kana-to-Kanji conversion. Submessage of WM_PENCTL. (Japanese version only.)

Parameters

wParam

HE_KKCONVERT.

lParam

Must be one of the following values:

Value	Meaning
HEKK_DEFAULT	The first time the conversion is specified, the selected character string is replaced with the conversion result; the second time it is specified, the conversion candidate dialog box appears.
HEKK_CONVERT	The selected character string is replaced with the conversion result regardless of how many times conversion has been specified.
HEKK_CANDIDATE	Causes the conversion candidate dialog box to appear.
HEKK_DBCSCHAR	The SBCS characters (0x20 − 0x7E, 0xA1 − 0xDF) are replaced by their DBCS equivalents.
HEKK_SBCSCHAR	The DBCS characters in the selected character string or marked conversion string that have equivalent SBCS representations are replaced by their equivalent SBCS characters.
HEKK_HIRAGANA	The katakana characters (DBCS or SBCS) in the selected character string or marked conversion string are replaced with their hiragana equivalents.
HEKK_KATAKANA	The hiragana characters in the selected character string or marked conversion string are replaced with their DBCS katakana representation.
Return Value

Returns TRUE if there are no errors; otherwise, returns FALSE:

Comments

In this message, "marked conversion string" indicates the string in the Input Method Editor (IME) that is marked for conversion. Text marked for conversion is indicated by a different selection color than that used for normal text selection in a standard text edit control. Available for bedits only.


HE_PUTCONVERTCHAR [New - Windows 95]
HE_PUTCONVERTCHAR

[New - Windows 95]

Sends a character to the Input Method Editor (IME) and marks it for conversion. Submessage of WM_PENCTL. (Japanese version only.)

Parameters

wParam

HE_PUTCONVERTCHAR.

lParam

The low-order word contains the character code, which can be an SBCS or DBCS character.

Return Value

Returns TRUE if there are no errors; otherwise, returns FALSE.

Comments

Posting this message is exactly like posting a WM_CHAR message to a bedit or edit control with the exception that the posted character also acquires the attribute of being a character marked for conversion in the Input Method Editor. This sub-message is available for bedits only.


HE_SETBOXLAYOUT [New - Windows 95]
HE_SETBOXLAYOUT

[New - Windows 95]

Sets the box layout for a control. Submessage of WM_PENCTL. Submessage of WM_PENCTL.

Parameters

wParam

HE_SETBOXLAYOUT.

lParam

Address of the BOXLAYOUT structure to be set.

Return Value

Returns TRUE if successful; otherwise, returns FALSE.

Comments

This submessage is for bedit controls only.

See Also

WM_PENCTL


HE_SETCONVERTRANGE [New - Windows 95]
HE_SETCONVERTRANGE

[New - Windows 95]

Sets the range of the marked conversion string. Submessage of WM_PENCTL. (Japanese version only.)

Parameters

wParam

HE_SETIMEDEFAULT.

lParam

The low-order word contains the starting character position (not byte position) of the marked conversion string. The high-order word contains the ending character position plus 1.

Return Value

Returns TRUE if there are no errors; otherwise, returns FALSE.

Comments

Available for bedits only. If the starting character position is 0 and the ending char-acter position is −1, all the text in the control becomes the marked conversion string. If the starting character is −1, the marked conversion string area is removed. When characters are marked for conversion, the Input Method Editor is said to be in preconversion mode.

Returns FALSE if in conversion mode. If there is a selection, the selection will be cleared. The caret will be moved to the end of the marked conversion string.


HE_SETINFLATE [New - Windows 95]
HE_SETINFLATE

[New - Windows 95]

Sets the inflation rectangle for a control. Submessage of WM_PENCTL.

Parameters

wParam

HE_SETINFLATE.

lParam

Address of a RECTOFS structure specifying the inflation margins for the writing window.

Return Value

Returns TRUE if successful, or FALSE if an invalid window rectangle is specified.

Comments

This is a submessage of the WM_PENCTL message.

For a description of how to increase or decrease the writing area of a control, see "HE_SETINFLATE Submessage" in Chapter 3, "The Writing Process."

See Also

HE_GETINFLATE, RECTOFS, WM_PENCTL


HE_SETINKMODE [New - Windows 95]
HE_SETINKMODE

[New - Windows 95]

Starts ink data collection in a control. Submessage of WM_PENCTL.

Parameters

wParam

HE_SETINKMODE.

lParam

The low-order word is the initial HPENDATA object or NULL. If the initial HPENDATA is supplied, it must be relative to the top-left corner of the client rectangle of the control.

Return Value

Returns TRUE if successful; otherwise, returns FALSE.

Comments

This is a submessage of the WM_PENCTL message.

See Also

WM_PENCTL


HE_SETUNDERLINE [New - Windows 95]
HE_SETUNDERLINE

[New - Windows 95]

Sets or cancels underline mode in an hedit control. Submessage of WM_PENCTL.

Parameters

wParam

HE_SETUNDERLINE.

lParam

The low-order word is TRUE to set underline mode and FALSE to cancel it.

Return Value

Returns the current underline mode.

Comments

This submessage is for single-line hedit controls only.

See Also

WM_PENCTL


HE_SHOWALTLIST [New - Windows 95]
HE_SHOWALTLIST

[New - Windows 95]

Displays the alternate list menu for the current cell in a bedit control, assuming that alternate lists are enabled. Submessage of WM_PENCTL.

Parameters

wParam

HE_SHOWALTLIST.

lParam

If the low-order word is HEAL_DEFAULT, the alternate list menu is displayed.

Return Value

If more than one character is selected, the alternate list of the first character in the selection is displayed. If nothing is selected, the alternate list for the character to the right of the caret is displayed and the return value is TRUE.

Comments

This submessage is for bedit controls only. If more than one box is selected, the HE_SHOWALTLIST message will drop a word alternate list menu; otherwise, it will drop a character alternate list menu.

See Also

HE_ENABLEALTLIST, HE_HIDEALTLIST, WM_PENCTL


HE_STOPINKMODE [New - Windows 95]
HE_STOPINKMODE

[New - Windows 95]

Stops ink collection in a control. Submessage of WM_PENCTL.

Parameters

wParam

HE_STOPINKMODE.

lParam

If the low-order word is HEP_RECOG, the control performs recognition and displays text. If the low-order word is HEP_NORECOG (0), the control removes the ink without performing recognition. If the low-order word is HEP_WAITFORTAP, the control performs recognition when the next tap in the writing area occurs.

Return Value

Returns TRUE if successful; otherwise, returns FALSE.

Comments

This is a submessage of the WM_PENCTL message.

See Also

WM_PENCTL


HN_BEGINDIALOG [New - Windows 95]
HN_BEGINDIALOG

[New - Windows 95]

Sent by a bedit or hedit control to its parent window just before the control puts up any kind of dialog, including the lens, edit text, or garbage-detection dialogs.

The control's parent window receives this notification message through a WM_COMMAND message.

Parameters

wParam

Specifies the identifier of the hedit or bedit control.

lParam

Specifies the handle of the hedit or bedit control in the low-order word and the HN_BEGINDIALOG notification message in the high-order word.

Return Value

If the parent window returns TRUE to this notification message, the bedit or hedit control refrains from opening the dialog; otherwise, the dialog is opened. Note that the application can disable the hedit or bedit control's ability to open a dialog by specificying CIH_NOEDITTEXT in the WM_CTLINIT message.


HN_ENDDIALOG [New - Windows 95]
HN_ENDDIALOG

[New - Windows 95]

Sent by a bedit or hedit control to its parent window of the dialog when a dialog opened by the control is destroyed.

The control's parent window receives this notification message through a WM_COMMAND message.

Parameters

wParam

Specifies the identifier of the hedit or bedit control.

lParam

Specifies the handle of the hedit or bedit control in the low-order word and the HN_ENDDIALOG notification message in the high-order word.

Return Value

The return value is ignored.


HN_ENDKKCONVERT [New - Windows 95]
HN_ENDKKCONVERT

[New - Windows 95]

Sent after a bedit control has completed the Kana-to-Kanji conversion. Submessage of WM_PENCTL. (Japanese version only.)

The control's parent window receives this notification message through a WM_COMMAND message.

Parameters

wParam

Specifies the identifier of the hedit or bedit control.

lParam

Specifies the handle of the hedit or bedit control in the low-order word and the HN_ENDKKCONVERT notification message in the high-order word.

Return Value

The return value is ignored.


HN_ENDREC [New - Windows 95]
HN_ENDREC

[New - Windows 95]

Sent after an hedit or bedit control has acted upon the results of recognition from a recognition session.

The control's parent window receives this notification message through a WM_COMMAND message.

Parameters

wParam

Specifies the identifier of the hedit or bedit control.

lParam

Specifies the handle of the hedit or bedit control in the low-order word and the HN_ENDREC notification message in the high-order word.

Return Value

The return value is ignored.


HN_RESULT [New - Windows 95]
HN_RESULT

[New - Windows 95]

Sent when an hedit or bedit control receives results of inking or recognition from a recognition session, but before the control absorbs the results into its internal data structures.

The control's parent window receives this notification message through a WM_COMMAND message.

Parameters

wParam

Specifies the identifier of the hedit or bedit control.

lParam

Specifies the handle of the hedit or bedit control in the low-order word and the HN_RESULT notification message in the high-order word.

Return Value

The return value is ignored.

Comments

The application can get the results and optionally modify them using the WM_PENMISC message with the PMSC_GETSYMBOLCOUNT, PMSC_GETSYMBOLS, and the PMSC_SETSYMBOLS submessages.

See Also

WM_PENMISC


IE_CANUNDO [New - Windows 95]
IE_CANUNDO

[New - Windows 95]

Retrieves an indication of whether the control can undo the last user operation.

Parameters

wParam

Not used; must be 0.

lParam

Not used; must be 0.

Return Value

Returns one of the following values:

Constant	Description
IER_YES	The control can undo the last operation.
IER_NO	The control cannot undo the last operation or the control has security protection disallowing an undo operation.
IER_PARAMERR	wParam or lParam is invalid.


IE_DOCOMMAND [New - Windows 95]
IE_DOCOMMAND

[New - Windows 95]

Causes an ink edit control to execute a command.

Parameters

wParam

Contains one of the following command message codes:

Constant	Description
IEM_CLEAR	Clear (delete) the selection.
IEM_COPY	Copy selected strokes.
IEM_CUT	Cut selected strokes.
IEM_ERASE	Use eraser mode to erase.
IEM_LASSO	Use lasso mode to select strokes.
IEM_PASTE	Paste Clipboard contents to the iedit control.
IEM_PROPERTIES	Invoke the properties dialog box on the selected strokes.
IEM_RESIZE	Resize selected strokes.
IEM_SELECTALL	Select all the strokes in the control.
IEM_UNDO	Undo the last action.
lParam

Not used; must be 0.

Return Value

Returns IER_OK if successful; otherwise, returns one of the following:

Constant	Description
IER_PARAMERR	wParam or lParam is invalid.
IER_MEMERR	A memory error occurred.
IER_SECURITY	The control has security protection disallowing the operation.
Comments

An application can use this message to force the ink edit control to execute a valid command. For example, an application might have a toolbar button or menu item that can be used to trigger a copy command. The IE_DOCOMMAND message can be used in response to the user's pressing the button or selecting the menu item to have the iedit control copy the selected ink to the Clipboard.

The iedit control sends its parent an IN_COMMAND notification if the IEN_EDIT notify bit is set, to which the parent can respond in the usual ways. Sending a command that the iedit control cannot interpret (that is, a command code of IEM_USER or above) causes any specified notification but the iedit control takes no other action.

The IEN_EDIT bit is set by default. It should be cleared if the control's parent does not want to receive the IN_COMMAND notification message.

See Also

IE_GETCOMMAND


IE_EMPTYUNDOBUFFER [New - Windows 95]
IE_EMPTYUNDOBUFFER

[New - Windows 95]

Empties the undo buffer.

Parameters

wParam

Not used; must be 0.

lParam

Not used; must be 0.

Return Value

Returns one of the following:

Constant	Description
IER_OK	Success.
IER_PARAMERR	wParam or lParam is invalid.
IER_SECURITY	The control has security protection disallowing the operation.
Comments

If there is nothing in the undo buffer, this message returns IER_OK but does nothing else. As long as the buffer remains empty after sending IE_EMPTYUNDOBUFFER, the messages IE_CANUNDO and WM_UNDO return FALSE.

See Also

IE_CANUNDO


IE_GETAPPDATA [New - Windows 95]
IE_GETAPPDATA

[New - Windows 95]

Retrieves the application data saved in the ink edit control.

Parameters

wParam

Not used; must be 0.

lParam

Not used; must be 0.

Return Value

Returns the contents of the application data area if successful; otherwise, returns IER_PARAMERR to indicate that wParam or lParam is invalid.

Comments

An application can save any DWORD value with the ink edit control. The control does not use this data. The IE_SETAPPDATA and IE_GETAPPDATA messages provide the only means for an application to interact with the data.

See Also

IE_SETAPPDATA


IE_GETBKGND [New - Windows 95]
IE_GETBKGND

[New - Windows 95]

Retrieves the current background painting options of an ink edit control.

Parameters

wParam

Not used; must be 0.

lParam

Address of a WORD variable that receives the current background options, as given in the following list:

Constant	Description
IEB_BIT_CENTER	Center supplied bitmap in control.
IEB_BIT_STRETCH	Stretch bitmap to fit control.
IEB_BIT_TILE	Tile supplied bitmap repeatedly in control.
IEB_BIT_UL	Align supplied bitmap to upper-left corner in the control. (UL stands for "upper left.")
IEB_BRUSH	Use application-supplied brush in lParam.
IEB_DEFAULT	Do default background (use COLOR_WINDOW).
IEB_OWNERDRAW	Parent will draw background.
Return Value

If successful, returns a handle to the background bitmap or a brush, or NULL, according to the option specified in lParam; otherwise, returns IER_PARAMERR to indicate that wParam or lParam is invalid.

Comments

The returned handle is owned by the iedit control; the application should not delete it. If the application needs to preserve this information, it should copy the handle.

See Also

IE_SETBKGND, IE_GETGRIDPEN, IE_SETGRIDPEN


IE_GETCOMMAND [New - Windows 95]
IE_GETCOMMAND

[New - Windows 95]

Retrieves the menu item number of a selected command.

Parameters

wParam

Not used; must be 0.

lParam

Not used; must be 0.

Return Value

Returns the menu item number if successful; otherwise, returns one of the following:

Constant	Description
IER_PARAMERR	wParam or lParam is invalid.
IER_NOCOMMAND	Attempt to issue IE_GETCOMMAND when no command was selected.
Comments

The application sends the IE_GETCOMMAND message when it receives an IN_COMMAND notification to find out what menu item the user selected. This message can be sent only during processing of an IN_COMMAND notification. It returns the IER_NOCOMMAND error code if sent at any other time.

See Also

IE_DOCOMMAND


IE_GETCOUNT [New - Windows 95]
IE_GETCOUNT

[New - Windows 95]

Retrieves the count of strokes in the control.

Parameters

wParam

Not used; must be 0.

lParam

Not used; must be 0.

Return Value

If successful, returns the total number of strokes in the control; otherwise, returns IER_PARAMERR to indicate that wParam or lParam is invalid.

See Also

IE_GETSELCOUNT


IE_GETDRAWOPTS [New - Windows 95]
IE_GETDRAWOPTS

[New - Windows 95]

Retrieves the ink-drawing option.

Parameters

wParam

Not used; must be 0.

lParam

Not used; must be 0.

Return Value

Returns one of the following ink-drawing options:

Constant	Description
IEDO_FAST	Drawing is done as fast as possible. This is the default setting.
IEDO_NONE	No drawing is done (disabled drawing).
IEDO_SAVEUPSTROKES	Save pen-up strokes in the HPENDATA object.
Comments

IEDO_FAST and IEDO_NONE are mutually exclusive options.

See Also

IE_SETDRAWOPTS


IE_GETERASERTIP [New - Windows 95]
IE_GETERASERTIP

[New - Windows 95]

Retrieves the eraser pen tip.

Parameters

wParam

Not used; must be 0.

lParam

Address of a PENTIP structure.

Return Value

Returns IER_OK if successful; otherwise, returns IER_PARAMERR to indicate that wParam or lParam is invalid.

Comments

The PENTIP structure is filled with the current pen tip used for erasing.

See Also

PENTIP, IE_SETERASERTIP


IE_GETFORMAT [New - Windows 95]
IE_GETFORMAT

[New - Windows 95]

Retrieves the current format of a stroke or a set of strokes in an iedit control.

Parameters

wParam

Not used; must be 0.

lParam

Address of a STRKFMT structure.

Return Value

If successful, returns bit flags that indicate whether the strokes identified in the STRKFMT structure have different color or width, as described in the "Comments" section.

If an error occurs, returns one of the following values:

Constant	Description
IER_ERROR	Unknown error.
IER_PARAMERR	wParam or lParam is invalid. Also returned when there is an invalid stroke index and the IESF_STROKE option is specified in the iesf member of the STRKFMT structure.
IER_SECURITY	The control has security protection disallowing the operation.
IER_SELECTION	No valid selection when the IESF_SELECTION option is specified in the iesf member of the STRKFMT structure.
Comments

If the value in the iesf member of the STRKFMT structure has the IESF_STROKE bit set, IE_GETFORMAT refers to the single stroke identified in the iStrk member. In this case:

•	The return value is 0.

•	The bwidth and rgb members in PENTIP specified in the STRKFMT structure contain the stroke's color and width.

If either the bit IESF_SELECTION or IESF_ALL is set in iesf, IE_GETFORMAT retrieves format information for multiple strokes. In this case, the return value con-tains the IESF_TIPCOLOR or IESF_TIPWIDTH bit flags that indicate whether the multiple strokes share the same ink color and width.

For example, if the multiple requested strokes all have the same width, then

•	The IESF_TIPWIDTH bit of the return value is 0 to indicate the strokes all have the same width.

•	The bwidth member in PENTIP specified in the STRKFMT structure contains the common width.

If the strokes do not all have the same color, IE_GETFORMAT returns the following information:

•	The IESF_TIPCOLOR bit is set in the return value to indicate the strokes do not share a common color.

•	The rgb member in PENTIP specified in the STRKFMT structure contains the color of the last stroke in the group.

The caller must initialize the cbSize member of the STRKFMT structure to sizeof( STRKFMT ) before sending IE_GETFORMAT.

The supplied STRKFMT structure specifies the stroke or strokes for which the attributes are desired. The structure is filled according to the request and the actual stroke attributes.

See Also

IE_SETFORMAT, PENTIP, STRKFMT


IE_GETGESTURE [New - Windows 95]
IE_GETGESTURE

[New - Windows 95]

Retrieves the specifics of a gesture.

Parameters

wParam

Not used; must be 0.

lParam

Not used; must be 0.

Return Value

Returns an HRCRESULT of the gesture if successful; otherwise, returns one of the following:

Constant	Description
IER_PARAMERR	wParam or lParam is invalid.
IER_NOGESTURE	Indicates an attempt to issue IE_GETGESTURE when no gesture was performed.
Comments

An application sends IE_GETGESTURE when it receives an IN_GESTURE notifi-cation, to retrieve the specifics of the user's gesture. This message can be sent only during processing of an IN_GESTURE notification. It returns the error code IER_NOGESTURE if it is set at any other time.

If successful, the application receives an HRCRESULT, which can then be used to get information about the gesture specifics. This handle is still owned by the iedit control, however, and the application must neither delete the handle nor modify the data to which it refers.


IE_GETGRIDORIGIN [New - Windows 95]
IE_GETGRIDORIGIN

[New - Windows 95]

Retrieves the current origin of the rule or grid-line settings for the control.

Parameters

wParam

Not used; must be 0.

lParam

Not used; must be 0.

Return Value

Returns the x-coordinate of the origin in the low-order word and the y-coordinate of the origin in the high-order word, if successful; otherwise, returns IER_PARAMERR to indicate that wParam or lParam is invalid.

See Also

IE_GETBKGND, IE_GETGRIDORIGIN, IE_GETGRIDSIZE, IE_SETBKGND, IE_SETGRIDORIGIN, IE_SETGRIDPEN, IE_SETGRIDSIZE


IE_GETGRIDPEN [New - Windows 95]
IE_GETGRIDPEN

[New - Windows 95]

Retrieves the current GDI pen used to draw the rules or grid lines for the control.

Parameters

wParam

Not used; must be 0.

lParam

Not used; must be 0.

Return Value

If successful, returns a handle to a GDI pen that is being used to draw the grid lines. This handle can be NULL; otherwise, returns IER_PARAMERR to indicate that wParam or lParam is invalid.

Comments

The handle of the GDI pen returned remains the property of the iedit control. The application must not delete this handle.

See Also

IE_GETBKGND, IE_GETGRIDORIGIN, IE_GETGRIDSIZE, IE_SETBKGND, IE_SETGRIDORIGIN, IE_SETGRIDPEN, IE_SETGRIDSIZE


IE_GETGRIDSIZE [New - Windows 95]
IE_GETGRIDSIZE

[New - Windows 95]

Retrieves the current horizontal and vertical spacing of the rule or grid-line settings for the control.

Parameters

wParam

Not used; must be 0.

lParam

Not used; must be 0.

Return Value

If successful, the low-order word has the horizontal spacing and the high-order word has the vertical spacing; otherwise, returns IER_PARAMERR to indicate that wParam or lParam is invalid.

See Also

IE_GETBKGND, IE_GETGRIDORIGIN, IE_GETGRIDPEN, IE_SETBKGND, IE_SETGRIDORIGIN, IE_SETGRIDPEN, IE_SETGRIDSIZE


IE_GETINK [New - Windows 95]
IE_GETINK

[New - Windows 95]

Retrieves the contents of an ink edit control.

Parameters

wParam

IEGI_ALL to get the entire ink, or IEGI_SELECTION to get only the selected ink.

lParam

Not used; must be 0.

Return Value

Returns the handle to the HPENDATA structure if successful; otherwise, returns one of the following:

Constant	Description
IER_PARAMERR	wParam or lParam is invalid.
IER_MEMERR	A memory error occurred.
IER_SECURITY	The control has security protection disallowing the operation.
IER_SELECTION	Nothing is selected in the control; operation assumes a selection.
Comments

The returned HPENDATA structure becomes the property of the application, which must eventually destroy it. This handle is a copy of the handle used internally by the control. An application cannot change the control by modifying the pen data referred to by this handle, although the modified handle can subsequently be used in an IE_SETINK call, which modifies the control's contents.

See Also

IE_SETINK


IE_GETINKINPUT [New - Windows 95]
IE_GETINKINPUT

[New - Windows 95]

Retrieves the current ink input options for the control.

Parameters

wParam

Not used; must be 0.

lParam

Not used; must be 0.

Return Value

Returns the current ink input bits if successful; otherwise, returns IER_PARAMERR to indicate that wParam or lParam is invalid.

Comments

The ink input bits are as follows:

Constant	Description
IEI_MOVE	Move all ink inside the control.
IEI_RESIZE	Resize all ink to fit inside the control.
IEI_CROP	Crop all ink that falls outside the control.
IEI_DISCARD	Discard all ink if any falls outside the control.
See Also

IE_SETINKINPUT


IE_GETINKRECT [New - Windows 95]
IE_GETINKRECT

[New - Windows 95]

Retrieves the bounding rectangle of the ink.

Parameters

wParam

Not used; must be 0.

lParam

Address of a RECT structure.

Return Value

Returns IER_OK if successful; otherwise, returns IER_PARAMERR to indicate that wParam or lParam is invalid.

Comments

The RECT structure is filled with the bounding rectangle of the current ink in the control. The rectangle is in the same coordinates as the scaling mode the HPENDATA object is in.


IE_GETMENU [New - Windows 95]
IE_GETMENU

[New - Windows 95]

Retrieves a handle to an ink edit control's pop-up menu.

Parameters

wParam

Not used; must be 0.

lParam

Not used; must be 0.

Return Value

Returns the handle to the menu if successful; otherwise, returns IER_PARAMERR to indicate that wParam or lParam is invalid.

Comments

The iedit control continues to own the menu handle.

The application can perform standard menu operations upon the returned handle, including the addition, deletion, and modification of menu items. The application's changes are reflected the next time the pop-up menu is invoked.


IE_GETMODE [New - Windows 95]
IE_GETMODE

[New - Windows 95]

Retrieves the current mode the control is in.

Parameters

wParam

Not used; must be 0.

lParam

Not used; must be 0.

Return Value

If successful, returns one of the following values indicating the current control mode:

Constant	Description
IEMODE_READY	The control is ready for inking, moving strokes, tapping, resizing, and so on.
IEMODE_ERASE	The control is set to erasing mode.
IEMODE_LASSO	The control is set to lasso selection mode.
Otherwise, returns IER_PARAMERR to indicate that wParam or lParam is invalid.

See Also

IE_SETMODE


IE_GETMODIFY [New - Windows 95]
IE_GETMODIFY

[New - Windows 95]

Queries whether the contents of the control have been modified since the control was created.

Parameters

wParam

Not used; must be 0.

lParam

Not used; must be 0.

Return Value

Returns one of the following values:

Constant	Description
IER_YES	The control's contents have been modified.
IER_NO	The control's contents have not been modified.
IER_PARAMERR	wParam or lParam is invalid.
Comments

This command succeeds regardless of the security setting.

See Also

IE_SETMODIFY


IE_GETNOTIFY [New - Windows 95]
IE_GETNOTIFY

[New - Windows 95]

Retrieves the current notification options for the control.

Parameters

wParam

Not used; must be 0.

lParam

Not used; must be 0.

Return Value

If successful, returns the current notification bits, as listed here:

Constant	Description
IEN_EDIT	Require notifications of editing or command events.
IEN_FOCUS	Require notifications of focus events.
IEN_PAINT	Require notifications of painting events.
IEN_PDEVENT	Require notifications of pointing-device events (clicks and taps).
IEN_PROPERTIES	Require notifications before bringing up the properties dialog box.
IEN_SCROLL	Require notifications of scrolling events.
Otherwise, returns IER_PARAMERR to indicate that wParam or lParam is invalid.

See Also

IE_SETNOTIFY


IE_GETPAINTDC [New - Windows 95]
IE_GETPAINTDC

[New - Windows 95]

Retrieves the handle to the device context (HDC), which is used to paint an ink edit control. This HDC was supplied to the iedit control by BeginPaint; therefore, its clipping region is set according to those portions of the iedit control that have been invalidated.

Parameters

wParam

Not used; must be 0.

lParam

Not used; must be 0.

Return Value

Returns the HDC if successful; otherwise, returns one of the following:

Constant	Description
IER_PARAMERR	wParam or lParam is invalid.
IER_NOTINPAINT	Attempted IE_GETPAINTDC outside of paint notification.
Comments

The application can send this message only when the parent window is processing one of the painting notifications: IN_PREPAINT, IN_PAINT, IN_POSTPAINT, or IN_ERASEBKGND. An attempt to send it at any other time will fail, returning IER_NOTINPAINT.

The clipping region is already appropriately set when sending IE_GETPAINTDC. The HDC is in the MM_TEXT mapping mode. The HDC must not be released; the iedit control does this after returning from the painting notification.


IE_GETPDEVENT [New - Windows 95]
IE_GETPDEVENT

[New - Windows 95]

Retrieves the pointing-device event that triggered the IN_PDEVENT notification. This can be from a mouse, pen, or other device.

Parameters

wParam

Not used; must be 0.

lParam

Address of a PDEVENT structure that is filled by the control when it receives this message.

Return Value

Returns one of the following:

Constant	Description
IER_OK	Success.
IER_PARAMERR	wParam or lParam is invalid.
IER_NOPDEVENT	No event occurred.
Comments

This message can succeed only during the processing of an IN_PDEVENT notification. At all other times its use is invalid. The caller must initialize the cbSize member of the PDEVENT structure to sizeof( PDEVENT ) before sending this message.

The application can cause the event to be discarded by returning TRUE to the IN_PDEVENT notification.

See Also

IN_PDEVENT, PDEVENT


IE_GETPENTIP [New - Windows 95]
IE_GETPENTIP

[New - Windows 95]

Retrieves the default ink pen tip.

Parameters

wParam

Not used; must be 0.

lParam

Address of a PENTIP structure.

Return Value

Returns IER_OK if successful; otherwise, returns IER_PARAMERR to indicate that wParam or lParam is invalid.

Comments

The PENTIP structure is filled with the current pen tip used for default inking.

See Also

PENTIP, IE_SETPENTIP


IE_GETRECOG [New - Windows 95]
IE_GETRECOG

[New - Windows 95]

Retrieves the current recognition setting of the control.

Parameters

wParam

Not used; must be 0.

lParam

Not used; must be 0.

Return Value

If successful, returns the following recognition flags, which can be combined using the bitwise-OR operator:

Constant	Description
IEREC_ALL	All recognition enabled.
IEREC_GESTURE	Gesture recognition enabled.
IEREC_NONE	Recognition disabled.
Otherwise, returns IER_PARAMERR to indicate that wParam or lParam is invalid.

Comments

Currently, IEREC_GESTURE and IEREC_ALL are equivalent.

See Also

IE_SETRECOG


IE_GETSECURITY [New - Windows 95]
IE_GETSECURITY

[New - Windows 95]

Retrieves the current security setting of the control.

Parameters

wParam

Not used; must be 0.

lParam

Not used; must be 0.

Return Value

If successful, returns the following security flags, which can be combined using the bitwise-OR operator:

Constant	Description
IESEC_NOCOPY	Copying not allowed.
IESEC_NOCUT	Cutting, deleting, and clearing not allowed.
IESEC_NOPASTE	Pasting disabled.
IESEC_NOUNDO	Undo not permitted.
IESEC_NOINK	Inking not allowed.
IESEC_NOERASE	Erasing not allowed.
IESEC_NOGET	The IE_GETINK message is disabled.
IESEC_NOSET	The IE_SETINK message is disabled.
Otherwise, returns IER_SECURITY to indicate that the control has security pro-tection disallowing the operation.

See Also

IE_SETSECURITY


IE_GETSEL [New - Windows 95]
IE_GETSEL

[New - Windows 95]

Retrieves the selection status of a particular stroke.

Parameters

wParam

Contains the zero-based index of the stroke whose selection status is queried.

lParam

Not used; must be 0.

Return Value

Returns one of the following values:

Constant	Description
IER_YES	The stroke is selected.
IER_NO	The stroke is not selected.
IER_PARAMERR	wParam or lParam is invalid.
See Also

IE_SETSEL


IE_GETSELCOUNT [New - Windows 95]
IE_GETSELCOUNT

[New - Windows 95]

Retrieves the number of selected strokes.

Parameters

wParam

Not used; must be 0.

lParam

Not used; must be 0.

Return Value

If successful, returns the number of selected strokes; otherwise, returns IER_PARAMERR to indicate that wParam or lParam is invalid.

See Also

IE_GETSEL, IE_GETCOUNT


IE_GETSELITEMS [New - Windows 95]
IE_GETSELITEMS

[New - Windows 95]

Retrieves a list of all selected strokes in the control.

Parameters

wParam

Size of the buffer passed in.

lParam

Address of a buffer of UINT variables that will be filled with the indices of the selected strokes in the control. This buffer must be large enough to hold all requested indices. The application can ensure this by first getting the number of selected strokes with the IE_GETSELCOUNT message and then calculating the required size of the buffer.

Return Value

Returns IER_OK if successful; otherwise, returns IER_PARAMERR to indicate that wParam or lParam is invalid.

See Also

IE_GETSELCOUNT


IE_GETSTYLE [New - Windows 95]
IE_GETSTYLE

[New - Windows 95]

Retrieves the current style attributes of an ink edit control.

Parameters

wParam

Not used; must be 0.

lParam

Not used; must be 0.

Return Value

If successful, returns the following current style bits:

Constant	Description
IES_BORDER	Border drawn around control.
IES_HSCROLL	Horizontally scrollable control.
IES_VSCROLL	Vertically scrollable control.
IES_OWNERDRAW	Application will do all ink drawing.
Otherwise, returns IER_PARAMERR to indicate that wParam or lParam is invalid.


IE_SETAPPDATA [New - Windows 95]
IE_SETAPPDATA

[New - Windows 95]

Sets the application data saved in the ink edit control.

Parameters

wParam

Not used; must be 0.

lParam

Data to be saved.

Return Value

Returns the previous contents of the application data area, if successful; otherwise, returns IER_PARAMERR to indicate that wParam or lParam is invalid.

Comments

An application can save any DWORD value with the ink edit control. The control does not use this data. The IE_SETAPPDATA and IE_GETAPPDATA messages provide the only means for an application to interact with the data.

See Also

IE_GETAPPDATA


IE_SETBKGND [New - Windows 95]
IE_SETBKGND

[New - Windows 95]

Sets the background painting options for the control.

Parameters

wParam

Specifies the background options, as given in the following list:

Constant	Description
IEB_BIT_CENTER	Center bitmap in control. The lParam parameter contains bitmap.
IEB_BIT_STRETCH	Stretch bitmap to fit control. The lParam parameter contains bitmap.
IEB_BIT_TILE	Tile supplied bitmap repeatedly in control. The lParam parameter contains bitmap.
IEB_BIT_UL	Align supplied bitmap to upper-left corner in the control. (UL stands for "upper left.") The lParam parameter contains bitmap.
IEB_BRUSH	Use brush supplied in lParam.
IEB_DEFAULT	Do default background (use COLOR_WINDOW).
IEB_OWNERDRAW	Parent will draw background.
lParam

Contains a handle to the background bitmap or a brush, or is NULL, according to the specified option in wParam.

Return Value

Returns IER_OK if successful; otherwise, returns IER_PARAMERR to indicate that wParam or lParam is invalid.

Comments

The application can change the background at any time. The control is synchro-nously repainted upon any change.

The HBITMAP or HBRUSH handle, if there is one, becomes the property of the iedit control. The application must make no further use of the handle if the message returns IER_OK. If the IEB_OWNERDRAW option is selected, the parent window must process the IN_ERASEBKGND notification. If an application must place such objects as icons or metafiles in the background, it must do so either in an owner-draw capacity or during the IN_PREPAINT notification.

See Also

IE_GETBKGND, IE_GETGRIDPEN, IE_SETGRIDPEN


IE_SETDRAWOPTS [New - Windows 95]
IE_SETDRAWOPTS

[New - Windows 95]

Sets the ink drawing option.

Parameters

wParam

Contains the drawing option.

Constant	Description
IEDO_FAST	Drawing is done as fast as possible. This is the default setting.
IEDO_NONE	No drawing is done (disabled drawing).
IEDO_SAVEUPSTROKES	Save pen-up strokes in the HPENDATA object.
lParam

Not used; must be 0.

Return Value

Returns IER_OK if successful; the previous draw option is returned in the high-order word; otherwise, returns one of the following:

Constant	Description
IER_PARAMERR	wParam or lParam is invalid.
IER_OWNERDRAW	The control is an owner-draw control; setting draw options is invalid.
IER_SECURITY	The control has security protection disallowing the operation.
Comments

Unlike using the WM_SETREDRAW message, IEDO_NONE controls only the drawing of the ink. The control's background, grid lines, and so forth are redrawn as usual. By default, pen-up strokes are not saved in the HPENDATA object.


IE_SETERASERTIP [New - Windows 95]
IE_SETERASERTIP

[New - Windows 95]

Sets the eraser pen tip.

Parameters

wParam

Not used; must be 0.

lParam

Address of a PENTIP structure.

Return Value

Returns IER_OK if successful; otherwise, returns IER_PARAMERR to indicate that wParam or lParam is invalid.

Comments

The pen tip specified by PENTIP is used for erasing in the control.

See Also

PENTIP, IE_GETERASERTIP


IE_SETFORMAT [New - Windows 95]
IE_SETFORMAT

[New - Windows 95]

Sets the format of a stroke or a set of strokes in an ink edit control.

Parameters

wParam

Not used; must be 0.

lParam

Address of a STRKFMT structure.

Return Value

Returns IER_OK if successful; otherwise, returns one of the following:

Constant	Description
IER_ERROR	Unknown error.
IER_PARAMERR	wParam or lParam is invalid. Also returned when there is an invalid stroke index and the IESF_STROKE option is specified in the iesf member of the STRKFMT structure.
IER_MEMERR	A memory error occurred.
IER_SECURITY	The control has security protection disallowing the operation.
IER_SELECTION	No valid selection with the IESF_SELECTION option in the iesf member of the STRKFMT structure.
Comments

The stroke or strokes indicated by the STRKFMT structure are modified as indicated and repainted (unless drawing has been turned off using the IEDO_NONE bit in IE_SETDRAWOPTS).

The iesf member of the STRKFMT structure contains the IESF_TIPCOLOR or IESF_TIPWIDTH bit flags to selectively adjust the color or width attributes of the ink. This allows setting only the color, for example, while leaving the width unchanged. If the value in iesf has either IESF_TIPCOLOR or IESF_TIPWIDTH set, the ink in the control adopts the new color or width given in the rgb or bwidth members of the PENTIP structure identified in the tip member of STRKFMT.

The caller must initialize the cbSize member of the STRKFMT structure to sizeof( STRKFMT ) before sending this message.

See Also

IE_GETFORMAT, IE_SETDRAWOPTS, STRKFMT


IE_SETGRIDORIGIN [New - Windows 95]
IE_SETGRIDORIGIN

[New - Windows 95]

Sets the origin of the rules or grid lines.

Parameters

wParam

Not used; must be 0.

lParam

The low-order word has the x-coordinate of the origin and the high-order word has the y-coordinate of the origin.

Return Value

Returns IER_OK if successful; otherwise, returns IER_PARAMERR to indicate that wParam or lParam is invalid.

Comments

Rules and grids are painted after the background and before the ink (and the IN_PREPAINT notification), and are treated separately from both.

The default setting is for no grid lines. The grid lines act purely as guides for the user; the ink does not interact with the grid in any way. The specification of the grid lines is in the MM_TEXT mapping mode (that is, display pixel).

See Also

IE_GETBKGND, IE_GETGRIDPEN, IE_GETGRIDSIZE, IE_SETGRIDORIGIN, IE_SETGRIDPEN, IE_SETGRIDSIZE, IE_SETBKGND


IE_SETGRIDPEN [New - Windows 95]
IE_SETGRIDPEN

[New - Windows 95]

Sets the GDI pen for the background rules or grid lines.

Parameters

wParam

Not used; must be 0.

lParam

Contains a handle to a GDI pen used to draw the grid lines.

Return Value

Returns IER_OK if successful; otherwise, returns IER_PARAMERR to indicate that wParam or lParam is invalid.

Comments

Rules and grids are painted after the background and before the ink (and the IN_PREPAINT notification), and are treated separately from both. A GDI pen, if specified, becomes the property of the ink edit control and must not be deleted or otherwise used by the application. If the application needs to change the settings, it must create a new pen each time it sends the IE_SETGRIDPEN message.

The default setting is for no grid lines. The grid lines act purely as guides for the user; the ink does not interact with the grid in any way. The specification of the grid lines is in the MM_TEXT mapping mode (that is, display pixel). If the GDI pen handle is NULL, the ink edit control will use a default pen. (The default pen attributes are a solid line, a width of 1 pixel, and the window grayed text color.) The maximum grid spacing is 255 pixels.

See Also

IE_GETBKGND, IE_GETGRIDORIGIN, IE_GETGRIDPEN, IE_GETGRIDSIZE, IE_SETGRIDORIGIN, IE_SETGRIDSIZE, IE_SETBKGND


IE_SETGRIDSIZE [New - Windows 95]
IE_SETGRIDSIZE

[New - Windows 95]

Sets the vertical and horizontal spacing of the rules or grid lines.

Parameters

wParam

Not used; must be 0.

lParam

The low-order word has the horizontal spacing and the high-order word has the vertical spacing.

Return Value

Returns IER_OK if successful; otherwise, returns IER_PARAMERR to indicate that wParam or lParam is invalid.

Comments

Rules and grids are painted after the background and before the ink (and the IN_PREPAINT notification), and are treated separately from both.

The default setting is for no grid lines. The grid lines act purely as guides for the user; the ink does not interact with the grid in any way. The specification of the grid lines is in the MM_TEXT mapping mode (that is, display pixel).

See Also

IE_GETBKGND, IE_GETGRIDORIGIN, IE_GETGRIDPEN, IE_GETGRIDSIZE, IE_SETGRIDORIGIN, IE_SETGRIDPEN, IE_SETBKGND


IE_SETINK [New - Windows 95]
IE_SETINK

[New - Windows 95]

Sets the contents of an ink edit control.

Parameters

wParam

Contains IESI_REPLACE to replace any existing control contents with the supplied ink, or IESI_APPEND to append the supplied ink to the existing contents of the ink edit control.

lParam

Contains a handle to pen data with which to initialize or reinitialize the contents of the control. If NULL, the contents of the control are cleared; any pen data in the control is discarded.

Return Value

Returns IER_OK if successful; otherwise, returns one of the following:

Constant	Description
IER_PARAMERR	wParam or lParam is invalid.
IER_MEMERR	A memory error occurred.
IER_SECURITY	The control has security protection disallowing the operation.
IER_SCALE	Attempted to merge ink of incompatible scale factors.
Comments

The application can clear or change the contents of the control at any time with this function. During the creation of controls with existing contents, this message might be sent in response to the WM_CTLINIT message.

The HPENDATA handle becomes the property of the control; the application must make no further use of the handle if the message returns success. On a merge operation, the original HPENDATA is destroyed following a successful merge. If the result of IE_SETINK indicates there is no ink left in the control, the mode is reset to IEMODE_READY if the previous mode was either IEMODE_ERASE or IEMODE_LASSO. The corresponding IN_MODECHANGED notification is also sent at this time.

See Also

IE_GETINK


IE_SETINKINPUT [New - Windows 95]
IE_SETINKINPUT

[New - Windows 95]

Sets the ink input options for an ink edit control.

Parameters

wParam

Consists of one or two flags specifying the new ink input option. Any one of the following flags can be used as the wParam value. If IEI_MOVE is specified, one (and only one) additional value can combined to indicate a secondary option if all ink will not fit inside the control when moved. For example, the combi-nation IEI_MOVE|IEI_RESIZE specifies to move ink into the control and resize the control to fit if necessary. Bitwise-OR combinations of constants not including IEI_MOVE are not valid.

Constant	Description
IEI_MOVE	Move all ink inside the control.
IEI_RESIZE	Resize all ink to fit inside the control.
IEI_CROP	Crop all ink that falls outside the control.
IEI_DISCARD	Discard all ink if any falls outside the control.
lParam

Not used; must be 0.

Return Value

Returns the previous ink input bits if successful; otherwise, returns IER_PARAMERR to indicate that wParam or lParam is invalid.

Comments

An application can dynamically modify the ink input options. If more than 1 bit is set, the order of priority is as listed in the previous table.

See Also

IE_GETINKINPUT


IE_SETMODE [New - Windows 95]
IE_SETMODE

[New - Windows 95]

Sets the control to a particular mode.

Parameters

wParam

Specifies the mode to set the control to, as follows:

Constant	Description
IEMODE_READY	The control is ready for inking, moving strokes, tapping, and so forth.
IEMODE_ERASE	The control is set to erasing mode.
IEMODE_LASSO	The control is set to lasso selection mode.
lParam

Not used; must be 0.

Return Value

Returns one of the following values:

Constant	Description
IER_OK	Success.
IER_PARAMERR	wParam or lParam is invalid.
IER_PENDATA	Attempted to set erase or lasso mode with a null HPENDATA handle in the control.
See Also

IE_GETMODE


IE_SETMODIFY [New - Windows 95]
IE_SETMODIFY

[New - Windows 95]

Sets the modify bit in the control, indicating whether the contents of the control have been modified.

Parameters

wParam

The new value of the modify bit. Must be either TRUE or FALSE.

lParam

Not used; must be 0.

Return Value

Returns IER_OK if successful; otherwise, returns IER_PARAMERR to indicate that wParam or lParam is invalid.

Comments

The modify bit is set in the control whenever the user takes some action that changes the ink in the control. Such actions include drawing new ink, erasing, pasting, changing attributes, and moving ink. Note that calling a function to change the contents of the control also sets the modify bit.

To preserve the value of the modify bit during some modifying action, the appli-cation must first retrieve the bit's value with IE_GETMODIFY, then restore the value after completing the action.

This command succeeds regardless of the security setting.

See Also

IE_GETMODIFY


IE_SETNOTIFY [New - Windows 95]
IE_SETNOTIFY

[New - Windows 95]

Sets the notification options for an ink edit control.

Parameters

wParam

Consists of flags specifying the kinds of notifications required:

Constant	Description
IEN_EDIT	Require notifications of editing or command events. Notifications sent: IN_CHANGE, IN_UPDATE, IN_GESTURE, IN_COMMAND.
IEN_FOCUS	Require notifications of focus events. Notifications sent: IN_SETFOCUS, IN_KILLFOCUS.
IEN_PAINT	Require notifications of painting events. Notifications sent: IN_PREPAINT, IN_POSTPAINT.
IEN_PDEVENT	Require notifications of pointing-device events (clicks and taps). Notification sent: IN_PDEVENT.
IEN_PROPERTIES	Require notifications before bringing up the properties dialog box. Notification sent: IN_PROPERTIES.
IEN_SCROLL	Require notifications of scrolling events. Notifications sent: IN_HSCROLL, IN_VSCROLL.
lParam

Not used; must be 0.

Return Value

Returns the previous notification bits if successful; otherwise, returns IER_PARAMERR to indicate that wParam or lParam is invalid.

Comments

An application can dynamically modify the kinds of notifications and the frequency with which they are generated.

Unless otherwise specified, the parent window receives no notifications beyond the default messages sent by Windows to the parent of a child window.

See Also

IE_GETNOTIFY


IE_SETPENTIP [New - Windows 95]
IE_SETPENTIP

[New - Windows 95]

Sets the default ink pen tip.

Parameters

wParam

Not used; must be 0.

lParam

Address of a PENTIP structure.

Return Value

Returns IER_OK if successful; otherwise, returns IER_PARAMERR to indicate that wParam or lParam is invalid.

Comments

The pen tip specified by PENTIP is used for all default inking in the control. Note that the new pen tip applies only to new ink entered into the control. It does not change the attributes of existing ink in the control.

See Also

PENTIP, IE_GETPENTIP


IE_SETRECOG [New - Windows 95]
IE_SETRECOG

[New - Windows 95]

Sets the recognition options of the control.

Parameters

wParam

Contains bits designating the new recognition options, as listed here:

Constant	Description
IEREC_ALL	All recognition enabled.
IEREC_GESTURE	Gesture recognition enabled.
IEREC_NONE	Recognition disabled.
lParam

Not used; must be 0.

Return Value

Returns the previous recognition bits if successful; otherwise, returns IER_PARAMERR to indicate that wParam or lParam is invalid.

Comments

By default, all recognition is enabled. Currently, IEREC_GESTURE and IEREC_ALL are equivalent.

See Also

IE_GETRECOG


IE_SETSECURITY [New - Windows 95]
IE_SETSECURITY

[New - Windows 95]

Sets the security options of the control.

Parameters

wParam

Contains the new security bits. The high-order word is unused and must be 0. The security flags can be combined using the bitwise-OR operator.

Constant	Description
IESEC_NOCOPY	Copying not allowed.
IESEC_NOCUT	Cutting, deleting, and clearing not allowed.
IESEC_NOPASTE	Pasting disabled.
IESEC_NOUNDO	Undo not permitted.
IESEC_NOINK	Inking not allowed.
IESEC_NOERASE	Erasing not allowed.
IESEC_NOGET	The IE_GETINK message is disabled.
IESEC_NOSET	The IE_SETINK message is disabled.
lParam

Not used; must be 0.

Return Value

Returns the previous security bits if successful; otherwise, returns one of the following:

Constant	Description
IER_PARAMERR	wParam or lParam is invalid.
IER_SECURITY	The control has security protection disallowing the operation.
See Also

IE_GETSECURITY


IE_SETSEL [New - Windows 95]
IE_SETSEL

[New - Windows 95]

Sets the selection status of a particular stroke.

Parameters

wParam

Contains the zero-based index of the stroke whose selection status is to be set. A value of IX_END sets the selection status of all the strokes in the control.

lParam

lParam is TRUE to select the stroke or FALSE to remove the selection. Other values produce an IER_PARAMERR return value.

Return Value

Returns one of the following values:

Constant	Description
IER_YES	The stroke was previously selected.
IER_NO	The stroke was not previously selected.
IER_PARAMERR	wParam or lParam is invalid.
Comments

This message affects the selection status of only the specified stroke. The selection status of other strokes remains unchanged.

See Also

IE_GETSEL


IN_CHANGE [New - Windows 95]
IN_CHANGE

[New - Windows 95]

Sent after the contents of the control have been modified and repainted.

The control's parent window receives this notification message through a WM_COMMAND message if the IEN_EDIT bit has been set using the IE_SETNOTIFY message.

Parameters

wParam

Specifies the identifier of the ink edit control.

lParam

Specifies the handle of the iedit control in the low-order word and the IN_CHANGE notification message in the high-order word.

See Also

IE_SETNOTIFY


IN_CLOSE [New - Windows 95]
IN_CLOSE

[New - Windows 95]

Sent when the control is closing and about to be destroyed.

The control's parent window receives this notification message through a WM_COMMAND message.

Parameters

wParam

Specifies the identifier of the ink edit control.

lParam

Specifies the handle of the iedit control in the low-order word and the IN_CLOSE notification message in the high-order word.

Return Value

The application should return TRUE to prevent the control from being closed or FALSE for default handling.


IN_COMMAND [New - Windows 95]
IN_COMMAND

[New - Windows 95]

Sent when the user has selected an item from the pop-up menu.

The control's parent window receives this notification message through a WM_COMMAND message if the IEN_EDIT bit has been set using the IE_SETNOTIFY message.

Parameters

wParam

Specifies the identifier of the ink edit control.

lParam

Specifies the handle of the iedit control in the low-order word and the IN_COMMAND notification message in the high-order word.

Return Value

The application should return TRUE to discard the command selection or FALSE for default processing.

Comments

The application can retrieve details about the selection by using the IE_GETCOMMAND message.

See Also

IE_GETCOMMAND, IE_SETNOTIFY


IN_ERASEBKGND [New - Windows 95]
IN_ERASEBKGND

[New - Windows 95]

Sent to the parents of ink edit controls that have the IEB_OWNERDRAW option to request the painting of the control background.

The control's parent window receives this notification message through a WM_COMMAND message.

Parameters

wParam

Specifies the identifier of the ink edit control.

lParam

Specifies the handle of the ink edit control in the low-order word and the IN_ERASEBKGND notification message in the high-order word.

Comments

The application should use the IE_GETPAINTDC message to retrieve such information as the correct device context and clipping region.

See Also

IE_GETPAINTDC


IN_GESTURE [New - Windows 95]
IN_GESTURE

[New - Windows 95]

Sent when the user has performed a gesture in the iedit control.

The control's parent window receives this notification message through a WM_COMMAND message if the IEN_EDIT bit has been set using the IE_SETNOTIFY message.

Parameters

wParam

Specifies the identifier of the ink edit control.

lParam

Specifies the handle of the ink edit control in the low-order word and the IN_GESTURE notification message in the high-order word.

Return Value

The application should return TRUE to discard the gesture or FALSE for default processing.

Comments

An application can retrieve details about the gesture by using the IE_GETGESTURE message.

See Also

IE_SETNOTIFY


IN_HSCROLL [New - Windows 95]
IN_HSCROLL

[New - Windows 95]

The IN_HSCROLL notification message is sent when the user has clicked the ink edit control's horizontal scroll bar.

The control's parent window receives this notification message through a WM_COMMAND message if the IEN_SCROLL bit has been set using the IE_SETNOTIFY message. This bit is set by default and should be cleared if the control's parent does not require this notification message.

Parameters

wParam

Specifies the identifier of the ink edit control.

lParam

Specifies the handle of the ink edit control in the low-order word and the IN_HSCROLL notification message in the high-order word.

Return Value

The application should return TRUE to discard the scrolling request.

See Also

IE_SETNOTIFY


IN_KILLFOCUS [New - Windows 95]
IN_KILLFOCUS

[New - Windows 95]

Sent to inform the parent window that the control is losing the focus.

The control's parent window receives this notification message through a WM_COMMAND message if the IEN_FOCUS bit has been set using the IE_SETNOTIFY message. This bit is set by default and should be cleared if the control's parent does not require this notification message.

Parameters

wParam

Specifies the identifier of the ink edit control.

lParam

Specifies the handle of the iedit control in the low-order word and the IN_KILLFOCUS notification message in the high-order word.

Return Value

The application should return TRUE to prevent the control from losing the focus.

See Also

IE_SETNOTIFY


IN_MEMERR [New - Windows 95]
IN_MEMERR

[New - Windows 95]

Sent when the system is unable to satisfy a memory request made by the control.

The control's parent window receives this notification message through a WM_COMMAND message.

Parameters

wParam

Specifies the identifier of the ink edit control.

lParam

Specifies the handle of the ink edit control in the low-order word and the IN_MEMERR notification message in the high-order word.

Return Value

The application should return TRUE to retry the operation (generally after it frees memory). If it returns TRUE and the control still cannot perform the memory operation, another IN_MEMERR notification is generated.

Comments

The ink edit control does not display an error message of any kind. Any such error messages must be displayed by the application.


IN_MODECHANGED [New - Windows 95]
IN_MODECHANGED

[New - Windows 95]

Sent after the control mode has changed.

The control's parent window receives this notification message through a WM_COMMAND message if the IEN_EDIT bit has been set using the IE_SETNOTIFY message.

Parameters

wParam

Specifies the identifier of the ink edit control.

lParam

Specifies the handle of the ink edit control in the low-order word and the IN_MODECHANGED notification message in the high-order word.

See Also

IE_SETNOTIFY, IE_GETMODE, IE_SETMODE


IN_PAINT [New - Windows 95]
IN_PAINT

[New - Windows 95]

Sent to the parent window of an owner-draw ink edit control to indicate that the control should be painted.

The control's parent window receives this notification message through a WM_COMMAND message.

Parameters

wParam

Specifies the identifier of the ink edit control.

lParam

Specifies the handle of the ink edit control in the low-order word and the IN_PAINT notification message in the high-order word.

Comments

The application should use the IE_GETPAINTDC message to retrieve the details of the required painting.

See Also

IE_GETPAINTDC


IN_PDEVENT [New - Windows 95]
IN_PDEVENT

[New - Windows 95]

Sent when a pointing-device transition event (such as a tap, up-click, or double-tap) occurs.

The control's parent window receives this notification message through a WM_COMMAND message if the IEN_PDEVENT bit has been set using the IE_SETNOTIFY message.

Parameters

wParam

Specifies the identifier of the ink edit control.

lParam

Specifies the handle of the ink edit control in the low-order word and the IN_PDEVENT notification message in the high-order word.

Return Value

The application should return TRUE to discard the event, or FALSE for normal processing.

Comments

The application can retrieve a PDEVENT structure describing the event by sending the IE_GETPDEVENT message.

See Also

IE_GETPDEVENT, IE_SETNOTIFY


IN_POSTPAINT [New - Windows 95]
IN_POSTPAINT

[New - Windows 95]

Sent to inform the parent that painting is finished.

The control's parent window receives this notification message through a WM_COMMAND message if the IEN_PAINT bit has been set using the IE_SETNOTIFY message.

Parameters

wParam

Specifies the identifier of the ink edit control.

lParam

Specifies the handle of the ink edit control in the low-order word and the IN_POSTPAINT notification message in the high-order word.

Comments

The application can send the IE_GETPAINTDC message to retrieve a device con-text with the correct clipping region to perform any additional painting on top of the ink edit control.

See Also

IE_GETPAINTDC, IE_SETNOTIFY


IN_PREPAINT [New - Windows 95]
IN_PREPAINT

[New - Windows 95]

Sent just before the control paints the ink.

The control's parent window receives this notification message through a WM_COMMAND message if the IEN_PAINT bit has been set using the IE_SETNOTIFY message.

Parameters

wParam

Specifies the identifier of the ink edit control.

lParam

Specifies the handle of the ink edit control in the low-order word and the IN_PREPAINT notification message in the high-order word.

Comments

The application can send the IE_GETPAINTDC message to retrieve a device context with the correct clipping region to perform any additional painting before the ink edit control paints.

See Also

IE_GETPAINTDC, IE_SETNOTIFY


IN_PROPERTIES [New - Windows 95]
IN_PROPERTIES

[New - Windows 95]

Signals the iedit control's standard Properties dialog box is about to be displayed on the screen.

The control's parent window receives the IN_PROPERTIES notification message through a WM_COMMAND message if the IEN_PROPERTIES bit has been set using the IE_SETNOTIFY message. This bit is set by default and should be cleared if the control's parent does not require this notification message.

Parameters

wParam

Specifies the identifier of the ink edit control.

lParam

Specifies the handle of the ink edit control in the low-order word and the IN_PROPERTIES notification message in the high-order word.

Return Value

The application should return TRUE to avoid displaying the iedit control's standard Properties dialog box.

See Also

IE_SETNOTIFY


IN_SETFOCUS [New - Windows 95]
IN_SETFOCUS

[New - Windows 95]

Sent to inform the parent window that the control is gaining the focus.

The control's parent window receives this notification message through a WM_COMMAND message if the IEN_FOCUS bit has been set using the IE_SETNOTIFY message. This bit is set by default and should be cleared if the control's parent does not require this notification message.

Parameters

wParam

Specifies the identifier of the ink edit control.

lParam

Specifies the handle of the ink edit control in the low-order word and the IN_SETFOCUS notification message in the high-order word.

Return Value

The application should return TRUE to prevent acquiring the focus.

See Also

IE_SETNOTIFY


IN_UPDATE [New - Windows 95]
IN_UPDATE

[New - Windows 95]

Sent when the contents of the control have been modified but not yet repainted.

The control's parent window receives this notification message through a WM_COMMAND message if the IEN_EDIT bit has been set using the IE_SETNOTIFY message.

Parameters

wParam

Specifies the identifier of the ink edit control.

lParam

Specifies the handle of the ink edit control in the low-order word and the IN_UPDATE notification message in the high-order word.

See Also

IE_SETNOTIFY


IN_VSCROLL [New - Windows 95]
IN_VSCROLL

[New - Windows 95]

Sent when the user has clicked the ink edit control's vertical scroll bar.

The control's parent window receives this notification message through a WM_COMMAND message if the IEN_SCROLL bit has been set using the IE_SETNOTIFY message. This bit is set by default and should be cleared if the control's parent does not require this notification message.

Parameters

wParam

Specifies the identifier of the ink edit control.

lParam

Specifies the handle of the ink edit control in the low-order word and the IN_VSCROLL notification message in the high-order word.

Return Value

The application should return TRUE to discard the scrolling request.

See Also

IE_SETNOTIFY


PE_BEGINDATA [New - Windows 95]
PE_BEGINDATA

[New - Windows 95]

Sent to the window specified by the htrgTarget member of the TARGET structure the first time any pen data is directed toward that window. Submessage of WM_PENEVENT.

Parameters

wParam

PE_BEGINDATA

lParam

Address of a TARGET structure.

Comments

A target window can initialize the dwData member of the TARGET structure with a handle to pen data (HPENDATA), a handwriting recognition object (HRC), or some private data type. If dwData is an HPENDATA object, the HPENDATA object should be in standard scale with no OEM data. For example, the HPENDATA object can be created as follows:

CreatePenDataEx(NULL, PDTS_STANDARDSCALE, CPD_TIME, 0);

The target window informs Windows of the type of data in the dwData member of the TARGET structure by returning LRET_HPENDATA, LRET_HRC, or LRET_PRIVATE (or LRET_DONE). If the application lets the message fall down to the Windows DefWindowProc function, then the function creates a handwriting recognition object (HRC) for this target.

The window can ignore all input except gestures. In this case, it must create a handwriting recognition object and customize it to recognize only gestures.

For an example of how an application can handle PE_BEGINDATA, see the source code for PENAPP.C in Chapter 7, "A Sample Pen Application."

See Also

TARGET, WM_PENEVENT


PE_BEGININPUT [New - Windows 95]
PE_BEGININPUT

[New - Windows 95]

Begins default input processing. Submessage of WM_PENEVENT.

Parameters

wParam

PE_BEGININPUT

lParam

The high-order word is the handle of the window in which the pen first touched down, and the low-order word is the event reference identifier returned from GetMessageExtraInfo.

Return Value

Returns PCMR_OK if successful; otherwise, it returns one of the following values:

Constant	Description
PCMR_ALREADYCOLLECTING	StartPenInput has already been called for this session.
PCMR_APPTERMINATED	The application terminated input.
PCMR_ERROR	Parameter or unspecified error.
PCMR_INVALID_PACKETID	A packet identifier is invalid.
PCMR_SELECT	Press-and-hold action was detected. Collection is not started.
PCMR_TAP	A tap was detected. Collection is not started.
Comments

A control can initiate default pen-input processing by sending this message to its parent. If the parent allows the message to be processed by passing it to DefWindowProc, default pen-input behavior begins. The DoDefaultPenInput function uses this technique.

For further information about default processing, refer to Chapter 2, "Starting Out with System Defaults."

See Also

DoDefaultPenInput, WM_PENEVENT


PE_BUFFERWARNING [New - Windows 95]
PE_BUFFERWARNING

[New - Windows 95]

Generated by the pen driver component of the system when the input queue is approximately half full. When an application receives PE_BUFFERWARNING, it should immediately call GetPenInput to drain the input queue. Submessage of WM_PENEVENT.

Parameters

wParam

PE_BUFFERWARNING.

lParam

Extra information encapsulating a reference to the event and the HPCM that generated it. Applications can use the EventRefFromWpLp and HpcmFromWpLp macros to retrieve these values.

Comments

If an application receives this message, it has fallen behind in processing the input. The buffer is in danger of overflowing. The application should repeatedly call GetPenInput to gather the unprocessed pen input.

See Also

GetPenInput, WM_PENEVENT


PE_ENDDATA [New - Windows 95]
PE_ENDDATA

[New - Windows 95]

Sent at the termination of pen input to all windows specified by the htrgTarget member of the TARGET structure that have received a PE_BEGINDATA message. Submessage of WM_PENEVENT.

Parameters

wParam

PE_ENDDATA.

lParam

Address of a TARGET structure.

Comments

A target can inform the recognizer that pen input has ended and process the HRC in response to this message. If this message is allowed to fall through to the DefWindowProc function, default result processing is done if the value in the dwData member of the TARGET structure is of type HRC. EndPenInput is called followed by a call to ProcessHRC. Then the PE_RESULT submessage is sent to the target to allow the target to get results and process them.

If the dwData member of the TARGET structure has the HPENDATA or HRC type, the object is destroyed by DefWindowProc on completion of results processing.

See Also

TARGET, WM_PENEVENT


PE_ENDINPUT [New - Windows 95]
PE_ENDINPUT

[New - Windows 95]

Sent to indicate that the default collection has terminated. Submessage of WM_PENEVENT.

Parameters

wParam

PE_ENDINPUT.

lParam

Not used.

See Also

WM_PENEVENT


PE_GETINKINGINFO [New - Windows 95]
PE_GETINKINGINFO

[New - Windows 95]

Fills an INKINGINFO structure. Submessage of WM_PENEVENT.

Parameters

wParam

PE_GETINKINGINFO.

lParam

Address of an INKINGINFO structure, which is initialized with default values.

Return Value

The targeted windows in the application should return 1 to customize inking information. A return value of 0 results in default inking behavior.

Comments

Before beginning default pen input, Windows sends PE_GETINKINGINFO to all the windows specified by the htrgTarget member of the TARGET structure. (The TARGET structure is part of the TARGINFO structure created during processing of the earlier PE_SETTARGETS messages.)

The default values are the same as those used when StartInking is called with lpinkinginfo set to NULL, but the PII_SAVEBACKGROUND flag is forced on in the wFlags member of the INKINGINFO structure to automatically save and restore the inking background.

The hrgnClip member of the INKINGINFO structure temporarily contains the index of the target in the TARGINFO structure retrieved by the PE_SETTARGETS message. Note that this is an overloading of this member to identify the targets. If the htrgTarget window specified in the TARGET structure returns 1 to this message, the following actions are taken:

•	If both the PII_INKPENTIP and PII_RECTCLIP flags are set, the pen tip specified by the tip member of the INKINGINFO structure is saved and used whenever the pen goes down within the area defined by the rectClip member. In most cases, the ink color changes at or near the clipping boundary, even when the pen is dragged over it. Because inking is done on a per-segment basis, there may be a slight overlap of color near a common boundary.

•	If the width given in the tip member is 0, no ink will appear within the area specified by the rectClip member. Password fields can be implemented using this technique.

•	If the PII_SAVEBACKGROUND flag is clear (0), any ink dropped within the area specified by the rectClip member is not removed at the termination of the collection. The ink edit control, for example, uses this technique. However, the parent window can override this default behavior when it finally receives a PE_GETINKINGINFO message after all its targets have been called.

•	If the PII_INKSTOP flag is set, the rectInkStop member is folded into the region specified by the hrgnInkStop member, which is used in calls to the StartInking function. When inking stops due to a pen-down event in the rectInkStop rectangle, a WM_PENMISC message with the PMSC_INKSTOP submessage is sent to the window specified by the htrgTarget member of the TARGET structure. lParam is the same as in the PE_PENDOWN message that caused the inking to stop. As with PII_SAVEBACKGROUND, hwnd can override the preprocessed values accumulated by the targets.

For further information about PE_GETINKINGINFO, see Chapter 2, "Starting Out with System Defaults."

See Also

INKINGINFO, PE_SETTARGETS, StartInking, TARGET, TARGINFO, WM_PENEVENT


PE_GETPCMINFO [New - Windows 95]
PE_GETPCMINFO

[New - Windows 95]

Fills a PCMINFO structure, which is then used in a call to StartPenInput. Submessage of WM_PENEVENT.

Parameters

wParam

PE_GETPCMINFO.

lParam

Address of a PCMINFO structure, which is initialized with default values.

Comments

The default values are the same as those applied when StartPenInput is called with the lppcminfo parameter set to NULL:

•	Inking terminates when the time-out period elapses.

•	Inking terminates when a tap occurs outside the client rectangle of hwnd.

•	Inking does not start if the initial pen input consists of a press-and-hold gesture.

However, an exclusion region specified by the hrgnExclude member of the PCMINFO structure may have accumulated while processing PE_SETTARGETS messages. The window procedure can modify the values to customize the collection parameters before pen input begins.

If the PCM_DOPOLLING flag in the dwPcm member of the PCMINFO structure is set, it is disregarded and pen input remains in event mode.

See Also

PCMINFO, PE_SETTARGETS, StartPenInput, WM_PENEVENT


PE_MOREDATA [New - Windows 95]
PE_MOREDATA

[New - Windows 95]

Sent to the window specified by the htrgTarget member of the TARGET structure to indicate that more pen data is available for that window. Submessage of WM_PENEVENT.

Parameters

wParam

PE_MOREDATA.

lParam

Address of an INPPARAMS structure.

Comments

DefWindowProc collects the pen input in response to the PE_PENDOWN, PE_PENUP, and PE_PENMOVE messages and sends the input on a stroke-by-stroke basis to one of the targets in the TARGINFO structure. On a pen-tip transition—that is, from pen-down to pen-up or vice versa — the Windows DefWindowProc function sends a PE_MOREDATA message to the window specified by the htrgTarget member of the TARGET structure identified in the PE_BEGINDATA message.

If it receives a PE_MOREDATA message, DefWindowProc uses AddPointsPendata or AddPenInputHRC, or does nothing, depending on whether the data type in the dwData member of the TARGET structure is a handle to an HPENDATA, an HRC handle for handwriting recognition, or some private data type.

See Also

AddPenInputHRC, AddPointsPendata, INPPARAMS, PE_PENMOVE, PE_PENDOWN, PE_PENUP, TARGET, TARGINFO, WM_PENEVENT


PE_PENDOWN [New - Windows 95]
PE_PENDOWN

[New - Windows 95]

Generated by the pen driver component of the system when the pen tip touches the tablet surface. Submessage of WM_PENEVENT.

Parameters

wParam

PE_PENDOWN.

lParam

Extra information encapsulating a reference to the event and the HPCM that generated it. Applications can use the EventRefFromWpLp and HpcmFromWpLp macros to retrieve these values.

See Also

WM_PENEVENT


PE_PENMOVE [New - Windows 95]
PE_PENMOVE

[New - Windows 95]

Generated by the pen driver component of the system when the pen moves, forcing more packets into the input queue. Submessage of WM_PENEVENT.

Parameters

wParam

PE_PENMOVE.

lParam

Extra information encapsulating a reference to the event and the HPCM that generated it. Applications can use the EventRefFromWpLp and HpcmFromWpLp macros to retrieve these values.

Comments

This message is analogous to WM_MOUSEMOVE. It provides notification that the pen is moving. Like its mouse counterpart, PE_PENMOVE messages are coalesced so that only a single such message exists in the application's message queue. How-ever, the event the message represents is the first of these coalesced events, not the last event, as is the case with WM_MOUSEMOVE.

An application need not handle this message if transition events like PE_PENUP and PE_PENDOWN are sufficient notification. PE_PENMOVE is useful when an application must monitor pen movement with greater frequency than PE_PENUP or PE_PENDOWN allows.

See Also

WM_PENEVENT


PE_PENUP [New - Windows 95]
PE_PENUP

[New - Windows 95]

Generated by the pen driver component of the system when the pen tip leaves the tablet surface. Submessage of WM_PENEVENT.

Parameters

wParam

PE_PENUP.

lParam

Extra information encapsulating a reference to the event and the HPCM that generated it. Applications can use the EventRefFromWpLp and HpcmFromWpLp macros to retrieve these values.

See Also

WM_PENEVENT


PE_RESULT [New - Windows 95]
PE_RESULT

[New - Windows 95]

During the processing of the PE_ENDDATA submessage, sent to all windows specified by the htrgTarget member of the TARGET structure that have received a PE_BEGINDATA message. PE_RESULT applies only to recognition and is sent only if the value in the dwData member of the TARGET structure is of type HRC. Submessage of WM_PENEVENT.

Parameters

wParam

PE_RESULT.

lParam

HRC object for the recognition session.

Comments

A target can perform recognition-result processing in response to PE_RESULT. If it receives this message, the Windows DefWindowProc function performs default result processing. The first HRCRESULT object for the HRC is obtained using the GetResultsHRC function. The HRCRESULT handle is used to retrieve a string of symbols that are converted, one by one, into characters. The characters are then posted as WM_CHAR messages to the window specified by the htrgTarget member of the TARGET structure.

The clear, cut, copy, paste, and undo gestures are converted to WM_CLEAR, WM_CUT, WM_COPY, WM_PASTE, and WM_UNDO messages. They are posted to the htrgTarget target, together with appropriate mouse messages, so that the target can perform appropriate processing (such as selection) before applying the gestures.

See Also

TARGET, WM_PENEVENT


PE_SETTARGETS [New - Windows 95]
PE_SETTARGETS

[New - Windows 95]

Sent to an application window so that it can set its own targeting structure. Submessage of WM_PENEVENT.

Parameters

wParam

PE_SETTARGETS.

lParam

Address of a far pointer to a TARGINFO structure. (Note that lParam is a pointer to a pointer.)

Return Value

The application should return LRET_DONE to indicate that it has set up the targeting information for the child windows. A return of 0 indicates that the application is the only target. The application can also return LRET_ABORT to abort the targeting process altogether.

Comments

The DefWindowProc function enumerates all the descendants of the window specified in its first parameter and sends each one a PE_GETPCMINFO message. For every descendant that returns 1 to this message, the PCM_RECTBOUND and PCM_RECTEXCLUDE flags of the PCMINFO structure are examined. If the PCM_RECTBOUND flag is set, the descendant is included in the list of potential targets and the rectBound member in PCMINFO is copied to the rectBound member of the TARGET structure. If the PCM_RECTEXCLUDE flag is set, the rectExclude member of PCMINFO is added to an exclusion region that is passed (as the hrgnExclude member of the PCMINFO structure) to the StartInput call. If there are no descendants, or if the window procedure of hwnd returns 0, a TARGINFO structure is constructed with hwnd as the single target.

For default processing behavior, the application should allow PE_SETTARGETS to fall through to DefWindowProc. A PE_GETPCMINFO message will follow to establish targets or termination conditions (buttons, for example).

For further information about PE_SETTARGETS, see Chapter 2, "Starting Out with System Defaults."

An application can replace the default targeting with a set of targets it defines itself. In this case, the application allocates enough memory for the TARGINFO structure plus all the TARGET structures.

Example

The following example illustrates how to handle PW_SETTARGETS for n targets, where each target is in the array rgHwnd. Notice the code increases the allocation by n−1 TARGET structures, since TARGINFO already contains one TARGET structure.

DWORD cbAlloc         = sizeof(TARGINFO) + (n-1) * sizeof(TARGET);

HGLOBAL hTargets      = GlobalAlloc( GHND, cbAlloc );

LPTARGINFO lptarginfo = GlobalLock( hTargets );

lptarginfo->cbSize    = sizeof(TARGINFO);

lptarginfo->cTargets  = n;                   // Number of targets

lptarginfo->htrgOwner = HtrgFromHwnd(hwnd);  // Macro in penwin.h

lptarginfo->dwFlags   = TPT_TEXTUAL;         // For text

for (i = 0; i < n; i++)

{

HWND hwnd = (HTRG)rgHwnd[i];	// Window of this target

lptarginfo->rgTarget[i].dwFlags    = 0;	// Reserved

lptarginfo->rgTarget[i].idTarget   = i;

lptarginfo->rgTarget[i].htrgTarget = HtrgFromHwnd(hwnd);

lptarginfo->rgTarget[i].dwData = 0;

// Use screen coords of each window:

  {

// Note: rectBound is a RECTL. In 16-bit code, one has to assign each

// field separately. In 32-bit code, you can use the rectBound directly.

  RECT rect;

GetClientRect( hwnd, &rect);

ClientToScreen( hwnd, (LPPOINT)&rectBound.left);

ClientToScreen( hwnd, (LPPOINT)&rectBound.right);

  lptarginfo->rgTarget[i].rectBound.left = rect.left;

  lptarginfo->rgTarget[i].rectBound.top = rect.top;

  lptarginfo->rgTarget[i].rectBound.right = rect.right;

  lptarginfo->rgTarget[i].rectBound.bottom = rect.bottom;

  }

}

// Return our structures:

*(LPTARGINFO FAR *)lParam = lptarginfo;

See Also

PCMINFO, TARGET, TARGINFO, WM_PENEVENT


PE_TERMINATED [New - Windows 95]
PE_TERMINATED

[New - Windows 95]

Generated by the pen driver component of the system when pen input terminates. Submessage of WM_PENEVENT.

Parameters

wParam

PE_TERMINATED.

lParam

Extra information encapsulating a reason for termination and the current HPCM. Applications can use the TerminationFromWpLp and HpcmFromWpLp macros to retrieve these values.

Comments

When an application receives the PE_TERMINATED message, collection has already terminated and the HPCM handle returned from StartPenInput has become invalid. PE_TERMINATED indicates an application should perform such tasks as final results processing, repainting, and cleanup.

See Also

WM_PENEVENT


PE_TERMINATING [New - Windows 95]
PE_TERMINATING

[New - Windows 95]

Generated by the pen driver component of the system when pen input is about to terminate. Submessage of WM_PENEVENT.

Parameters

wParam

PE_TERMINATING.

lParam

Extra information encapsulating a reason for termination and the current HPCM. Applications can use the TerminationFromWpLp and HpcmFromWpLp macros to retrieve these values.

Comments

When it receives PE_TERMINATING, the application must immediately retrieve any remaining points.

See Also

WM_PENEVENT


WM_CTLINIT [New - Windows 95]
WM_CTLINIT

[New - Windows 95]

Sent to the parent of a bedit, hedit, or iedit control while the control is being created in order to get extra information about the control.

Parameters

wParam

Type of control. This parameter can be CTLINIT_BEDIT, CTLINIT_IEDIT, or CTLINIT_HEDIT.

lParam

Address of a control structure, depending on wParam. For values of CTLINIT_BEDIT, CTLINIT_HEDIT, or CTLINIT_IEDIT in wParam, lParam points to either a CTLINITBEDIT, CTLINITHEDIT, or CTLINITIEDIT structure, respectively.

Comments

Each of the CTLINIT structures has its first three members already initialized: cbSize (size of the structure), hwnd (handle to the control window), and id (child identifier of the control). The parent of the control can set appropriate values to the rest of the members in the structure and the control will then use those values when initializing itself.

See Also

CTLINITHEDIT, CTLINITBEDIT, CTLINITIEDIT


WM_GLOBALRCCHANGE [New - Windows 95]
WM_GLOBALRCCHANGE

[New - Windows 95]

See WM_PENMISCINFO.


WM_HOOKRCRESULT [New - Windows 95]
WM_HOOKRCRESULT

[New - Windows 95]

Sent to a window before WM_RCRESULT is sent to the target window.

Note

The WM_HOOKRCRESULT message is provided only for compatibility with version 1.0 of the Pen API and will not be supported in future versions.

Parameters

wParam

REC_ code indicating why recognition ended.

lParam

Address of an RCRESULT structure.

Comments

The application may examine the results in the RCRESULT structure. Changing any of the values leads to unpredictable results. The application should make a copy of any information it needs.

See Also

RCRESULT, SetRecogHook, WM_RCRESULT


WM_PENCTL [New - Windows 95]
WM_PENCTL

[New - Windows 95]

Performs several actions, including:

•	Converts a logical character position to a byte offset.

•	Converts a byte offset to a logical character position.

•	Switches the font in a bedit control to the default font.

Parameters

wParam

Submessage identifier as described in the following table. Each submessage is documented separately.

Constant	Description
HE_CANCELCONVERT	Cancels Kana-to-Kanji conversion. (Japanese version only.)
HE_CHAROFFSET	Converts logical character position of a character in the control to byte offset to the character. For bedit controls only.
HE_CHARPOSITION	Converts byte offset in the text buffer of the control to the logical character position, which contains the byte specified by the byte offset. For bedit controls only.
HE_DEFAULTFONT	Switches the font of the bedit control to the default font that the bedit selects at the time of creation. For bedit controls only.
HE_ENABLEALTLIST	Enables or disables the alternate list in a bedit control.
HE_FIXKKCONVERT	Confirm undetermined string and close Input Method Editor (IME). (Japanese version only.)
HE_GETBOXLAYOUT	Points to the BOXLAYOUT structure, which is filled with the current box layout for the control. For bedit controls only.
HE_GETCONVERTRANGE	Gets the range of the marked conversion string. (Japanese version only.)
HE_GETINFLATE	LPRECTOFS filled with current value.
HE_GETINKHANDLE	Retrieves a handle to the captured ink.
HE_GETKKCONVERT	Determines if the Input Method Editor (IME) is in pen (or keyboard) conversion mode. (Japanese version only.)
HE_GETKKSTATUS	Determines the mode of the Kana-to-Kanji conversion. (Japanese version only.)
HE_GETRC	Fills an RC structure, whose address is passed in the lParam, with current values. See the note that follows.
HE_GETUNDERLINE	Queries whether underline mode is set. For hedit controls only.
HE_HIDEALTLIST	Hides the alternate list in a bedit control, assuming it is being displayed.
HE_KKCONVERT	Starts Kana-to-Kanji conversion. (Japanese version only.)
HE_PUTCONVERTCHAR	Sends a character, marked for conversion, to the IME. (Japanese version only.)
HE_SETBOXLAYOUT	Sets a BOXLAYOUT structure. For bedit controls only.
HE_SETCONVERTRANGE	Sets the range of the marked conversion string. (Japanese version only.)
HE_SETINFLATE	Specifies adjustments to the control window to specify the size of the writing window.
HE_SETINKMODE	Starts the collection of inking.
HE_SETRC	Sets the RC structure, whose address is passed in the lParam. See the note that follows.
HE_SETUNDERLINE	Sets or cancels underline mode. For hedit controls only.
HE_SHOWALTLIST	Displays the alternate list menu in a bedit control, assuming that alternate lists are enable.
HE_STOPINKMODE	Stops the collection of ink.
Note

The HE_GETRC and HE_SETRC submessages are provided only for compatibility with version 1.0 of the Pen API and will not be supported in future versions.

lParam

Depends on wParam. See the individual HE_ submessage descriptions for more information.

Comments

Any control message (a message with the EM_ prefix) that can be sent to an edit control can also be sent to an hedit window. Most of these control messages are also supported by bedit controls.

The HE_ submessages are also common to both hedit and bedit controls except as noted in the preceding table. In a bedit control, each cell contains one logical character. Carriage return (CR) and line-feed (LF) bytes together form one logical character.

Before using the HE_SETBOXLAYOUT or HE_SETINFLATE submessages, it is often useful to retrieve the current structure associated with the control using the HE_GETBOXLAYOUT or HE_GETINFLATE submessages. You should then change the appropriate members in the retrieved structure. This procedure reduces the risk of inadvertent changes to the structure.

In older applications compatible with version 1.0 of the Pen API, placing the value RRM_SYMBOL in wResultMode of the RC structure disables all default diction-ary processing in a bedit control. The 1.0 application can perform dictionary pro-cessing on its own by retrieving the recognition results during the processing of the HN_RESULT notification and calling the DictionarySearch function.

See Also

HE_CANCELCONVERT, HE_CHAROFFSET, HE_CHARPOSITION, HE_DEFAULTFONT, HE_ENABLEALTLIST, HE_FIXKKCONVERT, HE_GETBOXLAYOUT, HE_GETIMEDEFAULT, HE_GETINFLATE, HE_GETINKHANDLE, HE_GETKKCONVERT, HE_GETKKSTATUS, HE_GETUNDERLINE, HE_SETBOXLAYOUT, HE_SETIMEDEFAULT, HE_SETINFLATE, HE_SETINKMODE, HE_SETUNDERLINE, HE_SHOWALTLIST, HE_STOPINKMODE


WM_PENEVENT [New - Windows 95]
WM_PENEVENT

[New - Windows 95]

Sent to an application after StartPenInput has initiated a pen collection.

Parameters

wParam

Submessage identifier as described in the following table. Each submessage is documented separately.

Constant	Description
PE_BEGINDATA	Initialization message to all targets.
PE_BEGININPUT	Begin default input.
PE_BUFFERWARNING	The input queue is getting full. The application should call GetPenInput.
PE_ENDDATA	Termination message to all targets.
PE_RESULT	Recognition result message to all targets.
PE_ENDINPUT	Input termination message to window.
PE_GETINKINGINFO	Get inking information.
PE_GETPCMINFO	Get input collection information.
PE_MOREDATA	Target gets more data.
PE_PENMOVE	The pen moved, placing more packets into the input queue without a tip transition. This mes-sage is coalesced with other PE_PENMOVE messages, so the Windows queue has only a single such message waiting.
PE_PENDOWN	The pen tip went down.
PE_PENUP	The pen tip went up.
PE_SETTARGETS	Set TARGINFO target data structure.
PE_TERMINATED	Pen input terminated. The HPCM handle for the current collection has become invalid.
PE_TERMINATING	Pen input is about to terminate. The application must retrieve any remaining points immediately.
lParam

Depends on wParam. In most cases, this is extra information encapsulating a reference to the event and the HPCM that generated it. These are retrieved using the EventRefFromWpLp and HpcmFromWpLp macros.

Comments

This message is not sent if polling is used—that is, if the dwPcm member of the PCMINFO structure contains the PCM_DOPOLLING flag.

See Also

GetPenInput, StartPenInput, TARGINFO


WM_PENMISC [New - Windows 95]
WM_PENMISC

[New - Windows 95]

Sent to notify an application of some pen-related change, such as a change in a bedit control. WM_PENMISC is also used to get information from a window about pen-related attributes.

Parameters

wParam

One of the following subfunctions:

PMSC_BEDITCHANGE

Indicates that system settings for bedit controls have been changed. When it receives this message, a bedit control updates its state according to the settings indicated by the BOXEDITINFO structure that lParam points to.

PMSC_GETHRC

Return a copy of the HRC handle associated with the window. lParam is unused and should be set to 0. If a window has no associated HRC structure, NULL is returned. It is the caller's responsibility to destroy any HRC the message returns.

PMSC_GETINKINGINFO

Retrieve the INKINGINFO structure associated with the window and copy it to the structure pointed to by lParam. The message is ignored if lParam is NULL.

PMSC_GETPCMINFO

Retrieve the PCMINFO structure associated with the window and copy it to the structure pointed to by lParam. If a window has no associated PCMINFO structure, NULL is returned. The message is ignored if lParam is NULL. The system initializes PCMINFO as follows:

•	dwPcm is a combination of the PCM_RECTBOUND, PCM_TIMEOUT, and PCM_TAPNHOLD flags.

•	rectBound is the client area of hwnd, in screen coordinates.

•	dwTimeout is the current writing time-out in milliseconds, as reported by GetPenMiscInfo using PMI_TIMEOUT.

•	All other members are 0.

PMSC_INKSTOP

Inking has stopped because of a pen-down event. lParam contains the HPCM handle corresponding to the collection and the event reference at which the inking stopped. An application can retrieve these values with the HpcmFromWpLp and EventRefFromWpLp macros, respectively.

PMSC_KKCTLENABLE

WM_PENMISC is broadcast when kana-kanji controls are enabled. (Japanese version only.)

PMSC_LOADPW

WM_PENMISC is broadcast when PENWIN.DLL loads or unloads. lParam is one of the following:

•	PMSCL_LOADED (PENWIN.DLL just loaded).

•	PMSCL_UNLOADED (PENWIN.DLL just unloaded).

•	PMSCL_UNLOADING (PENWIN.DLL is about to unload).

PMSC_PENUICHANGE

Broadcast to indicate that the pen user interface DLL (PENUI) has been changed. (Japanese version only.)

PMSC_SETHRC

Associate the HRC handle in lParam with the window. The window makes a copy of the HRC for itself so that the sender of the message can destroy its copy. Returns nonzero if successful; otherwise, returns 0.

PMSC_SETINKINGINFO

Associate the INKINGINFO structure pointed to by lParam with the window. Returns nonzero if successful; otherwise, returns 0.

PMSC_SETPCMINFO

Associate the PCMINFO structure pointed to by lParam with the window. The cbSize member of the structure must be initialized with sizeof( PCMINFO ). Returns nonzero if successful; otherwise, returns 0.

PMSC_SUBINPCHANGE

Indicates the character finder DLL (SUBINPUT) has been changed. (Japanese version only.)

PMSC_GETSYMBOLCOUNT

Retrieve the number of symbols contained in the last recognition result. lParam should be 0. This message should be sent by the window that received the HN_RESULT notification before returning from the notification message.

PMSC_GETSYMBOLS

Retrieve the symbols contained in the last recognition result. lParam should be a pointer to a buffer large enough to accommodate the number of symbols contained in the result followed by SYV_NULL. The number of symbols in the result can be obtained by sending the WM_PENMISC message to the window with the PMSC_GETSYMBOLCOUNT submessage. This message should be sent by the window that received the HN_RESULT notification before returning from the notification message. A nonzero value is returned to indicate success.

PMSC_SETSYMBOLS

Change the symbols for the last recognition result. lParam should be a pointer to a buffer containing the array of symbols to be set terminated by SYV_NULL. lParam may be NULL to indicate an empty result. The control receiving this message should not perform any garbage detection on results set in this manner. This allows the application to perform its own garbage detection. In the case of the bedits controls, the number of symbols set must be the same as the number of symbols obtained using the WM_PENMISC message with the PMSC_GETSYMBOLCOUNT submessage. If not, the symbols are not set. This message should be sent by the window that received the HN_RESULT notification before returning from the notifi-cation message. A nonzero value is returned to indicate success.

lParam

Depends on wParam.

See Also

BOXEDITINFO, INKINGINFO, PCMINFO


WM_PENMISCINFO [New - Windows 95]
WM_PENMISCINFO

[New - Windows 95]

Posted to all top-level windows whenever a pen system change is made.

Parameters

wParam

PMI_ value that identifies the system change.

lParam

New value, depending on wParam.

Comments

This message is broadcast to all top-level windows whenever a new global pen default is set by a call to the SetPenMiscInfo function. (Control Panel is the principal source of these changes.) A series of WM_PENMISCINFO broadcasts is typically made after a Control Panel application is closed.

In version 2.0 of the Pen API, the message parameters have been defined and the name of this message has been changed from WM_GLOBALRCCHANGE to WM_PENMISCINFO, although the value is the same for compatibility with version 1.0. The wParam and lParam parameters are the same as the parameter values provided to the SetPenMiscInfo function.

For version 1.0 compatibility, a call to the SetGlobalRC function also causes a posted broadcast of this message to all top-level windows, but the parameters are both 0. PMI_RCCHANGE may be used as an alias for 0 for wParam; however, PMI_RCCHANGE is not a valid parameter to GetPenMiscInfo or SetPenMiscInfo.

See Also

SetPenMiscInfo, GetPenMiscInfo, SetGlobalRC, PMI_


WM_RCRESULT [New - Windows 95]
WM_RCRESULT

[New - Windows 95]

Sent to an application by a recognizer with the results of a recognition.

Note

The WM_RCRESULT message is provided only for compatibility with version 1.0 of the Pen API and will not be supported in future versions.

Parameters

wParam

REC_ code indicating why recognition ended.

lParam

Address of an RCRESULT structure.

See Also

ProcessWriting, RCRESULT, Recognize, RecognizeData


Pen Application Programming Interface Constants

This chapter describes some of the many manifest constants defined by the Pen Application Programming Interface, listed alphabetically. Constants listed in this chapter are primarily those that do not contain a complete listing in any individual function or message description elsewhere in this documentation. Constants that pertain to individual functions or messages can be found with the descriptions of those functions or messages.

Each entry includes a complete description of the constant. For a comprehensive list of the Pen API constants, see Chapter 9, "Summary of the Pen Application Programming Interface," or refer to the PENWIN.H header file. Refer to the index to locate the descriptions of any of the Pen API constants.


ALC_ Alphabet Codes [New - Windows 95]
ALC_ Alphabet Codes

[New - Windows 95]

The ALC_ constants enable a subset of the active character set, depending on the current language.

For example, the French language includes "h" in the lowercase alphabet. In the same way, "£" replaces "$" if ALC_MONETARY is set in British systems. For more information about alphabets, see "Specifying an Alphabet Set" in Chapter 8 and "Alphabet" in Chapter 5.

Comments

The following ALC_ constants are are supported:

Constant	Description
ALC_ALL	All characters except Japanese characters.
ALC_ALPHA	ALC_LCALPHA | ALC_UCALPHA.
ALC_ALPHANUMERIC	ALC_LCALPHA | ALC_UCALPHA | ALC_NUMERIC.
ALC_ASCII	Seven-bit characters ASCII #20−ASCII #0x7F
ALC_DBCS	Allow double-byte character set (DBCS) variety of single-byte character set (SBCS).
ALC_DEFAULT	Default value; uses complete set of recognizable char-acters and gestures. The set of these is defined by the recognizer. It is the set of characters at or above ALC_SYSMINIMUM that the recognizer can accurately distinguish. If an application sets ALC_DEFAULT in the HRC object, and the recognizer is an alphanumeric system recognizer, the recognizer must at least support ALC_SYSMINIMUM as a default. ALC_DEFAULT should be the same character set as the complete character set for the given language minus the ALC_OTHER characters. If an application combines ALC_DEFAULT with other ALC_ values, ALC_DEFAULT is ignored.
ALC_GESTURE	Gestures.
ALC_GLOBALPRIORITY	Specifies that the global recognition priorities (from Tool Palette) are to be used during recognition. An application can control its own recognition priority in a control by clearing this flag and then setting its own priorities in the HRC.
ALC_HIRAGANA	Hiragana characters. (Japanese version only.)
ALC_JIS1	All Kanji Shift JIS level 1 characters. (Japanese version only.)
ALC_KANJI	Kanji characters, Shift JIS levels 1, 2, and 3. (Japanese version only.)
ALC_KANJIALL	ALC_ALL | ALC_HIRAGANA | ALC_KATAKANA | ALC_KANJI. (Japanese version only.)
ALC_KANJISYSMINIMUM	Minimum set of characters needed for Japanese system recognizer. Same as ALC_SYSMINIMUM | ALC_HIRAGANA | ALC_KATAKANA | ALC_JIS1. (Japanese version only.)
ALC_KATAKANA	Katakana characters. (Japanese version only.)
ALC_LCALPHA	Lowercase letters a−z.
ALC_MATH	Math symbols:  %^*()-+={}<>,/.
ALC_MONETARY	Monetary symbols:  ,.$ or appropriate currency desig-nation such as the yen or pound sterling symbol, accord-ing to the current language setting.
ALC_NONPRINT	Space, tab, carriage-return, and control glyphs.
ALC_NOPRIORITY	No priority. This value means the application has no preference for one type of symbol over another.
ALC_NUMERIC	Numerals 0−9.
ALC_OEM	Bits reserved for recognizer capabilities specific to the original equipment manufacturer (OEM).
ALC_OTHER	Other symbols:  @ # | _ ~ [ ]. That is, all other symbols not included in ALC_ALPHANUMERIC, ALC_MONETARY, ALC_MATH, and ALC_PUNC.
ALC_PUNC	Punctuation:  !-;`"?()&.,\.
ALC_RESERVED	Reserved.
ALC_SYSMINIMUM	Minimum set of characters needed for Roman alphabet system recognizers:  ALPHANUMERIC | ALC_PUNC | ALC_WHITE | ALC_GEST.
ALC_UCALPHA	Uppercase letters A−Z.
ALC_USEBITMAP	(Description follows table.)
ALC_WHITE	White space. If this value is not set in the HRC object, the recognizer should ignore any white space left between characters. Thus, ALC_WHITE is included in the ALC_DEFAULT. For example, in the zip code field of the Hform sample application, where ALC_NUMERIC | ALC_GESTURE is set, the user does not have to worry about getting any extraneous spaces.
If ALC_USEBITMAP is set, it indicates the recognizer should adopt an alphabet set defined by the application. The defined set specifies individual characters of an alphabet by setting bits in a 256-bit bitfield. The lowest bit corresponds to the first character of the alphabet, the second bit to the second character, and so forth.

An application passes the bitfield to a recognizer through the SetAlphabetHRC or SetBoxAlphabetHRC functions. The following code shows how. Assume the array rgbfSet holds the desired bit values.

HRC     hrc;                         // HRC handle

BYTE    rgbfSet[cbRcrgbfAlcMax]      // 256-bit bitfield

SetAlphabetHRC( hrc, ALC_USEBITMAP, (LPBYTE) rgbSet );

ALC_USEBITMAP can be combined with other ALC_ values using the bitwise-OR operator. An application can thus, for example, select certain letters with a defined bitmap and combine them with all numerals and punctuation.

For Asian languages other than Japanese, refer to the appropriate subsets within the language: phonetic symbols for words within the language, phonetic symbols for words outside the language, and native pictographs. For example, in Korean, ALC_HANGUEL equals ALC_KATAKANA, and ALC_HANJA equals ALC_KANJI.

For kanji and other Asian encodings, different effects are possible depending on the state of ALC_DBCS. These effects are described in the following table.

Character in	ALC_DBCS = 0	ALC_DBCS = 1
ALC_HIRAGANA	N/A	Shift JIS characters 0x8154, 0x8155, and 0x829F − 0x82F1.
ALC_JIS1	N/A	All Kanji Shift JIS level 1 characters.
ALC_KATAKANA	0xA1 - 0xDF	Shift JIS characters 0x814A, 0x814B, 0x8152, 0x8153, 0x815B, and 0x8340 − 0x8396.
ALC_KANJI	N/A	All Kanji characters, Shift JIS levels 1, 2, and 3.
The following table shows the characters in Shift-JIS in each ALC_ set supported in the Japanese version:

ALC_ value	Shift JIS Code
ALC_HIRAGANA	0x8154, 0x8155, and 0x829F − 0x82F1
ALC_JIS1	0x8156 − 0x815A, 0x889F − 0x9872
ALC_KANJI	0x8156 − 0x815A, 0x889F − 0xEAA4, 0xED40 − 0xEDFC, 0xEE40 − 0xEEFC, 0xF040 − 0xF9FC, 0xFAF0 − 0xFAFC, 0xFB40 − 0xFBFC, 0xFC40 − 0xFC4B
ALC_KATAKANA	0x814A, 0x814B, 0x8152, 0x8153, 0x815B, 0x8340 − 0x8396
ALC_LCALPHA	0x8281 − 0x829A
ALC_MATH	0x8143, 0x8144, 0x814F, 0x815E, 0x8169, 0x816A, 0x816F, 0x8170, 0x817B − 0x817E, 0x8180 − 0x8188, 0x8193, 0x8196
ALC_MONETARY	0x8143, 0x8144, 0x818F − 0x8192
ALC_NONPRINT	0x8140
ALC_NUMERIC	0x824F − 0x8258
ALC_OTHER	0x814C − 0x814E, 0x8150, 0x8151, 0x8160 − 0x8164, 0x816B, 0x816C, 0x8171 − 0x8174, 0x8179, 0x817A, 0x817F,  0x8189 − 0x818E, 0x8194, 0x8197 − 0x81FC, 0x8240 − 0x824E, 0x8259 − 0x825F, 0x827A − 0x8280, 0x829B − 0x829E, 0x82F2 − 0x82FC, 0x837F, 0x897 − 0x83FC, 0x8840 − 0x84FC, 0x8740 − 0x879D
ALC_PUNC	0x8141 − 0x8149, 0x815B − 0x815F, 0x8165 − 0x816A, 0x816D − 0x8170, 0x8175 − 0x8178, 0x817C, 0x8195
ALC_UCALPHA	0x8260 − 0x8279
ALC_WHITE	0x8140
A recognizer must not return a symbol value outside the specified subset. However, a recognizer does not have to force a match to the subset; it can instead return "unknown" if a suitable match is not found.

You can set the ALC_ value for an hedit or bedit control in a dialog box by insert-ing a special string in the .RC file's CONTROL statement. This string is in the form ALC<xxxx> where xxxx represents a case-independent hexadecimal ALC_ code, without a preceding 0x qualifier. You can append normal window text after the ALC_ entry.

The following line demonstrates setting the ALC_ value for an hedit control using a CONTROL statement:

CONTROL "ALC<402C>Dollars", IDD_PAID, "hedit", ES_LEFT | ... etc.

In the above example, the ALC<402C> value is stripped out with "Dollars" left as window text. The number 402C is the hexadecimal equivalent of:

ALC_NUMERIC | ALC_PUNC | ALC_MONETARY | ALC_GESTURE

The following example allows only kanji characters, katakana characters, and gestures; it does not specify initial window text:

CONTROL "ALC<74000>", IDD_J, "hedit", ES_LEFT | ... etc.


BXD_ Boxed Edit Control [New - Windows 95]
BXD_ Boxed Edit Control

[New - Windows 95]

The BXD_ values define the initial dimensions of the various components of a boxed edit (bedit) control. These are constants defined in terms of dialog units. They are converted to pixel dimensions by the bedit control before use.

For more information, see the entries for the BOXLAYOUT and GUIDE structures in Chapter 11, "Pen Application Programming Interface Structures."

The following table lists the BXD_ values.

Constant	Value	Description
BXD_BASEHEIGHT	13	Initial value for cyBase in GUIDE structure after conversion from dialog units to pixels.
BXD_BASEHORZ	0	Initial value for cxBase in GUIDE structure after conversion from dialog units to pixels.
BXD_CELLHEIGHT	16	Initial value for cyBox in GUIDE structure after conversion from dialog units to pixels.
BXD_CELLWIDTH	12	Initial value for cxBox in GUIDE structure after conversion from dialog units to pixels.
BXD_CUSPHEIGHT	2	Initial value for cyCusp in BOXLAYOUT structure after conversion from dialog units to pixels.
BXD_ENDCUSPHEIGHT	4	Initial value for cyEndCusp in BOXLAYOUT structure after conversion from dialog units to pixels.
BXD_MIDFROMBASE	0	Same as BXD_BASEHORZ.


BXDK_ Japanese Boxed Edit Control [New - Windows 95]
BXDK_ Japanese Boxed Edit Control

[New - Windows 95]

The BXDK_ values define the initial dimensions of the various components of a Japanese boxed edit (bedit) control. These are constants defined in terms of dialog units. They are converted to pixel dimensions by the bedit control before use.

For more information, see the entries for the BOXLAYOUT and GUIDE structures in Chapter 11, "Pen Application Programming Interface Structures."

The following table lists the BXDK_ values.

Constant	Value	Description
BXDK_BASEHEIGHT	28	Initial value for cyBase in GUIDE structure after conversion from dialog units to pixels.
BXDK_BASEHORZ	0	Initial value for cxBase in GUIDE structure after conversion from dialog units to pixels.
BXDK_CELLHEIGHT	32	Initial value for cyBox in GUIDE structure after conversion from dialog units to pixels.
BXDK_CELLWIDTH	32	Initial value for cxBox in GUIDE structure after conversion from dialog units to pixels.
BXDK_CUSPHEIGHT	28	Initial value for cyCusp in BOXLAYOUT structure after conversion from dialog units to pixels.
BXDK_ENDCUSPHEIGHT	10	Initial value for cyEndCusp in BOXLAYOUT structure after conversion from dialog units to pixels.


IDC_ Display Cursor [New - Windows 95]
IDC_ Display Cursor

[New - Windows 95]

A pen-aware display driver must define the following new cursor types.

Constant	Value	Description
IDC_ALTSELECT	32501	Upside-down standard arrow used for tap-and-hold selection.
IDC_PEN	32631	Default pen. Pen points up and to the left.
Example

You can access the tap-and-hold cursor with the following code:

HANDLE	hPenDLL = GetSystemMetrics( SM_PENWINDOW);

if (hPenDLL)

SetCursor( LoadCursor( hPenDLL, IDC_ALTSELECT ) );


PCM_ Pen Collection Mode [New - Windows 95]
PCM_ Pen Collection Mode

[New - Windows 95]

Pen collection mode values define the condition that terminates an input session. (The system is said to be in "pen collection mode" during an input session when pen movement generates input data instead of being interpreted as mouse movement.) Pen collection can be stopped on any of the following conditions set by the PCM_ values in the dwPcm member of the PCMINFO structure:

Constant	Description
PCM_ADDDEFAULTS	Combine the default termination conditions with those specified by the application.
PCM_DOPOLLING	Request polling mode, rather than the default WM_PENEVENT messages.
PCM_INVERT	Stop pen collection if the user touches the "eraser" end of the pen to the tablet. Not all tablets can detect this event.
PCM_PENUP	Stop pen collection when the pen is lifted from the tablet.
PCM_RANGE	Stop pen collection when the pen leaves tablet's range of sensitivity. Not all tablets can detect this event.
PCM_RECTBOUND	Stop when the pen is placed down outside the inclusion rectangle. The inclusion rectangle is specified in the rectBound member of the PCMINFO structure.
PCM_RECTEXCLUDE	Stop when the pen touches inside the exclusion rectangle. The exclusion rectangle is specified in the rectExclude member of the PCMINFO structure.
PCM_RGNBOUND	Stop when the pen touches outside the bounding region specified in the hrgnBound member of the PCMINFO structure.
PCM_RGNEXCLUDE	Stop when the pen touches inside the exclusion region specified in the hrgnExclude member of the PCMINFO structure.
PCM_TAPNHOLD	Enable detection of the tap-and-hold gesture.
PCM_TIMEOUT	Stop pen collection if there is no pen activity for a specified time-out. The time-out value is specified in the dwTimeout member of the PCMINFO structure.


PDC_ Pen Device Capabilities [New - Windows 95]
PDC_ Pen Device Capabilities

[New - Windows 95]

The following table lists the values for the lPdc member of the PENINFO structure:

Constant	Description
PDC_BARREL1	Barrel button 1 is present.
PDC_BARREL2	Barrel button 2 is present.
PDC_BARREL3	Barrel button 3 is present.
PDC_INTEGRATED	Tablet surface is also a display monitor.
PDC_INVERT	The tablet can detect when the "eraser" end of the pen is in contact with the tablet.
PDC_PROXIMITY	The tablet can detect when the pen is near but not in contact with the tablet surface.
PDC_RANGE	The tablet can detect when the pen leaves or enters the tablet's range of sensitivity.
PDC_RELATIVE	The pen driver can generate only relative coordinates.
For additional details, see the entry for the PENINFO structure in Chapter 11, "Pen Application Programming Interface Structures."


PDK_ State Bits for Pen Driver Kit [New - Windows 95]
PDK_ State Bits for Pen Driver Kit

[New - Windows 95]

The PDK_ values inform the system when a mouse event is being generated by pen movement, as well as the current state of any barrel buttons. This information is contained in the wPDK and wPdk members of the STROKEINFO and PENPACKET structures, respectively. The GetPenAsyncState function also accepts a PDK_ value as its only argument. The following table lists the PDK_ values:

Constant	Value	Description
PDK_NULL	0x0000	No flags set (default).
PDK_UP	0x0000	Same as PDK_NULL.
PDK_BARREL1	0x0002	Barrel button 1 is depressed.
PDK_BARREL2	0x0004	Barrel button 2 is depressed.
PDK_BARREL3	0x0008	Barrel button 3 is depressed.
PDK_DOWN	0x0001	Pen is in contact with the tablet.
PDK_SWITCHES	0x000F	All of the above.
PDK_TIPMASK	0x0001	Mask for testing PDK_DOWN.
PDK_TRANSITION	0x0010	Only has meaning if set by pen services. This bit is set if the first point in the sequence being returned is in a different pen-tip state (up or down) from the previous points returned. If set on a call to AddPointsPenData, a new stroke is created even if the previous call to AddPointsPenData appended points of the same pen state. By default, a sub-sequent call to AddPointsPenData adding points of the same state as the previous call appends the points to the last stroke instead of creating a new stroke.
PDK_EVENT	0x0010	Alias for PDK_TRANSITION.
PDK_PENIDMASK	0x0F00	Mask for bits 8−11 (see paragraph following table).
PDK_INVERTED	0x0080	Pen is upside down ("eraser" end is in contact with tablet).
PDK_INKSTOPPED	0x2000	Inking has stopped.
PDK_OUTOFRANGE	0x4000	Set if the tablet detects the pen leaving the range of detection. If set, other information in the packet is invalid.
PDK_DRIVER	0x8000	Set if event is generated by the pen driver (as opposed to the mouse driver).
For PDK_ values other than PDK_PENIDMASK, bits 8 through 11 contain the identification number of the physical pen that generated the event. Pen numbering begins at 0.

See Also

PENPACKET, STROKEINFO


PDT_ OEM-Specific Data [New - Windows 95]
PDT_ OEM-Specific Data

[New - Windows 95]

PDT_ values provide information specific to the tablet hardware. These values are used in the wPdt member of the OEMPENINFO structure.

Constant	Value	Description
PDT_NULL	0	Null value.
PDT_PRESSURE	1	Tablet can detect change in pen pressure.
PDT_HEIGHT	2	Tablet can detect height of pen above surface.
PDT_ANGLEXY	3	Tablet can detect change in pen horizontal angle.
PDT_ANGLEZ	4	Tablet can detect change in pen vertical angle.
PDT_BARRELROTATION	5	Tablet can detect rotation of pen barrel.
PDT_OEMSPECIFIC	16	Maximum number of values allowed.
For additional information, see the PENINFO and OEMPENINFO structures in Chapter 11, "Pen Application Programming Interface Structures."


PDTS_ Pen Data Scaling [New - Windows 95]
PDTS_ Pen Data Scaling

[New - Windows 95]

The PDTS_ data scaling units are used in the uScale and wPndtNew arguments of the CreatePenData and MetricScalePenData functions, respectively. These units are used for the wPndts member of the PENDATAHEADER structure. Positive x-coordinate is to the right; positive y-coordinate is down.

The following table lists the PDTS_ values. These values cannot be combined with the bitwise-OR operator.

Constant	Description
PDTS_ARBITRARY	The application has done its own scaling of the data point.
PDTS_COMPRESS2NDDERIV	The second derivative between points is stored.
PDTS_DISPLAY	Each logical unit is equivalent to a display pixel. Positive x is to the right; positive y is down.
PDTS_HIENGLISH	Each logical unit is mapped to 0.001 inch. Positive x is to the right; positive y is down.
PDTS_HIMETRIC	Each logical unit is mapped to 0.001 millimeter. Positive x is to the right; positive y is down.
PDTS_LOMETRIC	Each logical unit is mapped to 0.01 millimeter. Positive x is to the right; positive y is down.
PDTS_STANDARDSCALE	The standard scaling metric, equivalent to PDTS_HIENGLISH. Standard recognizers scale to this value.
The following table lists the PDTS_ bit settings. These bit settings can be combined using the bitwise-OR operator.

Constant	Description
PDTS_COMPRESSED	The data is compressed.
PDTS_NOCOLLINEAR	All redundant points removed.
PDTS_NOEMPTYSTROKES	All empty strokes removed.
PDTS_NOOEMDATA	OEM data removed.
PDTS_NOPENINFO	The PENINFO structure has been trimmed from the header.
PDTS_NOTICK	Timing information removed.
PDTS_NOUPPOINTS	All pen-up strokes removed.
PDTS_NOUSER	User information removed.
The following table lists the PDTS_ mask values:

Constant	Description
PDTS_COMPRESSMETHOD	Bits encode the compression scheme that is used.
PDTS_SCALEMASK	Mask scaling bits for hardware information.
For additional information, see the entries for the CompactPenData and MetricScalePenData functions in Chapter 10, "Pen Application Programming Interface Functions."


PDTT_ Pen Data Trimming [New - Windows 95]
PDTT_ Pen Data Trimming

[New - Windows 95]

PDTT_ values are used as arguments for the CompactPenData function. The following table describes the PDTT_ values:

Constant	Description
PDTT_DEFAULT	Reallocates memory block to fit data; does not trim the data.
PDTT_ALL	Removes PENINFO structure from header, all pen-up points, OEM data, and collinear points.
PDTT_COLLINEAR	Removes coincident and collinear points from the pen data.
PDTT_COMPRESS	Compresses the data without losing any information.
PDTT_DECOMPRESS	Decompresses the data.
PDTT_OEMDATA	Removes all OEM data.
PDTT_PENINFO	Removes PENINFO structure from header.
PDTT_UPPOINTS	Removes all data from pen-up points (points collected when the pen is not in contact with the tablet).
For additional information, see the CompactPenData function in Chapter 10, "Pen Application Programming Interface Functions."


PMI_ Pen Miscellaneous Information [New - Windows 95]
PMI_ Pen Miscellaneous Information

[New - Windows 95]

The PMI_ values are used as arguments for the GetPenMiscInfo and SetPenMiscInfo functions. The WM_PENMISCINFO message also uses PMI_ values in its wParam parameter.

The following table describes the PMI_ values:

Constant	Description
PMI_BEDIT	Boxed edit information.
PMI_CXTABLET	Width of tablet (in units of 0.001 inch) if present, else the width of the screen.
PMI_CYTABLET	Height of tablet (in units of 0.001 inch) if present, else the height of the screen.
PMI_ENABLEFLAGS	Flags describing whether certain Pen API features are enabled. The flags can be a combination of the following values: PWE_AUTOWRITE   Enable pen functionality where the I-Beam cursor is present.  PWE_ACTIONHANDLES   Enable action handles in controls.  PWE_INPUTCURSOR   Show cursor while writing.  PWE_LENS   Enable pop-up letter guides (that is, the lens).
PMI_INDEXFROMRGB	A standard RGB pen-tip color value from 0 to 0xFFFFFF.
PMI_PENTIP	Address of current pen-tip structure.
PMI_RGBFROMINDEX	An integer index from 0 to 15 for the standard pen-tip color table.
PMI_SAVE	Save settings to file.
PMI_SYSFLAGS	Flags describing which pen system components are loaded. The flags can be a combination of the following values: PWF_RC1   Support available for Pen API version 1.0 Recognition Context (RC) and associated functions.  PWF_PEN   Pen/tablet hardware is present.  PWF_INKDISPLAY   Ink-compatible display driver is present.  PWF_RECOGNIZER   System recognizer is present.  PWF_BEDIT   Boxed edit (bedit) control is available.  PWF_HEDIT   Handwriting edit (hedit) control is available.  PWF_IEDIT   Ink edit (iedit) control is available.  PWF_ENHANCED   Enhanced features, including gesture support and 1 millisecond timing, are available.  PWF_FULL   All components listed above are present.
PMI_SYSREC	Handle to system recognizer, if present.
PMI_TICKREF	Absolute reference time that the system uses to calculate time-stamps for strokes in pen data objects and inksets.
PMI_TIMEOUT	Time-out value to end handwriting input, in milliseconds.
PMI_TIMEOUTGEST	Time-out value to end a gesture, in milliseconds.
PMI_TIMEOUTSEL	Time-out value in milliseconds for press-and-hold gesture. The range of permissible values is 0 to 5000. If press-and-hold has been disabled, this value is 65,535.
For additional information, see the entries for the GetPenMiscInfo and SetPenMiscInfo functions in Chapter 10, "Pen Application Programming Interface Functions."


RCD_ Writing Direction [New - Windows 95]
RCD_ Writing Direction

[New - Windows 95]

RCD_ values are used in the wRcDirect member of the global RC structure. The RC structure is passed to a version 1.0 recognizer in the lpRC argument of InitRC and informs the recognizer of the writing direction. To set the writing direction differently than the default direction, call SetGlobalRC with the desired RCD_ value in wRcDirect.

Note

RCD_ constants are provided only for compatibility with version 1.0 of the Pen API and will not be supported in future versions.

The writing direction consists of both primary and secondary directions. For example, English is written from left to right (primary) and then down the page (secondary). Chinese is often written from the top down (primary) and then right to left across the page (secondary).

The high byte of the direction indicates primary direction; the low byte indicates secondary direction. A recognizer can choose to ignore this word and support only the natural direction of the given language. The default value is determined by the recognizer.

The following table lists the RCD_ values:

Constant	Description
RCD_DEFAULT	Default value.
RCD_BT	Bottom to top.
RCD_LR	Left to right.
RCD_RL	Right to left.
RCD_TB	Top to bottom.
Example

For example, the value for standard English writing direction is defined as follows:

#define wRcDirectRoman  ((RCD_LR<<8) | RCD_TB)

See Also

RC


RCO_ Recognition Options [New - Windows 95]
RCO_ Recognition Options

[New - Windows 95]

RCO_ values apply only to recognizers compatible with version 1.0 of the Pen API. They are used in the lRcOptions member of the RC structure, which specifies various options for recognition. RCO_ values can be combined with a logical-OR operator.

Constant	Description
RCO_BOXCROSS	Display a plus sign (+) at center of each box in a bedit control.
RCO_BOXED	Set if the writer is expected to write in boxes and the GUIDE structure contains valid data.
RCO_COLDRECOG	Set in results messages if the result is coming from cold recognition.
RCO_DISABLEGESMAP	Disables gesture mapping during the Recognize function call.
RCO_NOFLASHCURSOR	No flash cursor feedback.
RCO_NOFLASHUNKNOWN	If set in the RC structure and nothing was recognized, the cursor will not momentarily change to a question-mark cursor shape.
RCO_NOHIDECURSOR	If set, doesn't remove cursor while inking.
RCO_NOHOOK	Prevents application-wide and system-wide hooks from being called.
RCO_NOPOINTEREVENT	If set, the RC Manager will not try to recognize a pointer event but will pass on all data to the recog-nizer. This is useful, for example, if the application has installed a shape recognizer so the user can enter dots of ink. If the null recognizer is selected into the RC, RCO_NOPOINTEREVENT is assumed to be set.
RCO_NOSPACEBREAK	If set, indicates that the results passed back from the recognizer should be passed on to the dictionaries without breaking at space boundaries.
RCO_SAVEALLDATA	Saves all the pen data in the RCRESULT structure that is generated by the tablet, including any data for pen-up strokes and optional data such as pressure. By default, only data used by the recognizer is saved. The Microsoft recognizer collects all data from first to last pen-down stroke, including pen-up strokes in between, and any available OEM data for each stroke.
RCO_SAVEHPENDATA	Saves the pen data. If this is set, the recognizer does not delete the data when the application returns from WM_RCRESULT. It is the application's responsibility to free the pen data.
RCO_SUGGEST	If set, the following actions take place: After all dictionaries have been unsuccessfully searched with strings from the symbol graph, each dictionary is called with DIRQ_SUGGEST to allow the diction-aries to make suggestions. If a string is not yet identified by a dictionary, the null dictionary is used to create a symbol string from the symbol graph.
RCO_TABLETCOORD	If set, indicates that the members representing coordi-nate values in the RC structure are in tablet coordi-nates instead of screen coordinates. This can be used to collect recognition data on the portion of the tablet not mapped to the screen.


RCOR_ Tablet Orientation [New - Windows 95]
RCOR_ Tablet Orientation

[New - Windows 95]

RCOR_ values are used in the wRcOrient member of the global RC structure. The RC structure is passed to a version 1.0 recognizer in the lpRC argument of InitRC and informs the recognizer of the tablet orientation. The recognizer can optionally use the orientation to direct the transformation of tablet coordinates to ideal coordi-nates used for recognition.

Note

RCOR_ constants are provided only for compatibility with version 1.0 of the Pen API and will not be supported in future versions.

The following table lists the RCOR_ values:

Constant	X-coordinate	Y-coordinate
RCOR_NORMAL	X = X'	Y = Y'
RCOR_LEFT	X = yMax - Y'	Y = X'
RCOR_RIGHT	X = Y'	Y = xMax - X'
RCOR_UPSIDEDOWN	X = xMax - X'	Y = yMax - Y'
As with the preceding values, direction is provided as a clue to the recognizer. A recognizer may attempt to identify the direction of writing by itself.

See Also

RC


RCP_ User Preferences [New - Windows 95]
RCP_ User Preferences

[New - Windows 95]

RCP_ values are used in the wRcPreferences member of the global RC structure. The RC structure is passed to a version 1.0 recognizer in the lpRC argument of InitRC and informs the recognizer of the user preferences.

Note

RCP_ constants are provided only for compatibility with version 1.0 of the Pen API and will not be supported in future versions.

The following table lists the RCP_ values:

Constant	Description
RCP_LEFTHAND	User writes with left hand.
RCP_MAPCHAR	Tells a version 1.0 recognizer to fill in segmentation information in the lpsyc member of the SYG structure. This value cannot be set by the user because there is no Control Panel access to it. RCP_MAPCHAR is used by the Trainer.
See Also

RC


RCRT_ Results Type [New - Windows 95]
RCRT_ Results Type

[New - Windows 95]

RCRT_ values apply only to recognizers compatible with version 1.0 of the Pen API. They are used in the wResultsType member of the RCRESULT structure, which specifies the type of results as described in the following table:

Constant	Description
RCRT_ALREADYPROCESSED	Set by a hook if the result has already been acted upon. If an application receives a result with this bit already set, it should erase the ink and perform no other pro-cessing. An application-wide hook can set this flag. The Hform sample application demonstrates its use.
RCRT_DEFAULT	Normal return type.
RCRT_GESTURE	Result is a gesture symbol.
RCRT_NORECOG	Nothing recognized; only the data is returned. No recognition was attempted.
RCRT_NOSYMBOLMATCH	Nothing recognized. The ink drawn did not match any enabled symbols.
RCRT_PRIVATE	Recognizer-specific symbol recognized.
RCRT_UNIDENTIFIED	Result contained unidentified results.
Example

The code below shows an example of how to use RCRT_ values:

if ((lpr->wResultsType & (RCRT_NOSYMBOLMATCH | RCRT_ALREADYPROCESSED |

   RCRT_NORECOG | RCRT_PRIVATE ) ) == 0 )

{

// A gesture or character

if (lpr->wResultsType & RCRT_GESTURE)

{

.

.	// Handle Gesture

.

}

else

{

.

.	// Character results

.

}

}

else

{

.	// Handle special cases as necessary.  In general,

.	// should just ignore.  This is what hedits do.

.

}


REC_ Recognition Functions [New - Windows 95]
REC_ Recognition Functions

[New - Windows 95]

The REC_ constants specify return values from the GetPenHwEventData and GetPenHwData functions. They are also returned from the obsolete functions Recognize, RecognizeData, and ProcessWriting, and as the wParam value of the WM_RCRESULT message. Return values less than REC_DEBUG are provided for debugging purposes only and represent abnormal termination.

Constant	Description
REC_OK	This result message to be followed by other results before Recognize terminates. This is a valid wParam value for WM_RCRESULT, but it can never be the return value for Recognize.
REC_ABORT	Recognition stopped by a call to EndPenCollection with this value. The lpPnt data is not valid.
REC_BADHPENDATA	Returned if HPENDATA cannot be locked or has an invalid header. This value is also returned if HPENDATA has no data in it or if the data is in an incorrect scale or compressed.
REC_BUFFERTOOSMALL	Returned by GetPenHwEventData.
REC_BUSY	Returned if another task is currently performing recognition.
REC_DONE	Returned by RecognizeData upon normal completion.
REC_NA	Function not available.
REC_NOINPUT	Returned by RecognizeData if the buffer contains no data, or returned by Recognize if recognition ended before any data was collected. For example, a pen-down stroke may have occurred outside the bounding rectangle before any data was collected.
REC_NOTABLET	Tablet not physically present.
REC_OOM	Out-of-memory error.
REC_OVERFLOW	Data overflow during execution of the call.
REC_POINTEREVENT	Returned if the user makes contact with the tablet surface and lifts the pen before the pen tip travels a short distance. This value is also returned if the user does a press-and-hold action; that is, the pen makes contact with the tablet and remains in that position for a short period of time. REC_POINTEREVENT informs the application it should begin selection actions rather than inking or recognition. If REC_POINTEREVENT is returned, no WM_RCRESULT message is generated and no ink is displayed.
REC_TERMBOUND	Recognition ended because of a hit test outside the bounding rectangle. The pntEnd member of RCRESULT is filled with the point causing the stop.
REC_TERMEX	Recognition ended because of a hit test inside the exclusion rectangle. The pntEnd member of RCRESULT is filled with the point causing the stop.
REC_TERMOEM	Values greater than or equal to 512 reserved for recognizer-specific termination reasons.
REC_TERMPENUP	Recognition ended on pen up. ThepntEnd member of RCRESULT is filled with the pen-up point that terminated recognition.
REC_TERMRANGE	Recognition ended because the pen left the proximity range.
REC_TERMTIMEOUT	Recognition ended on time-out. (The pen was up con-tinuously for a given amount of time.)


Debugging Values

All of the values listed in the following table are in the debug version of PENWIN.DLL only. No WM_RCRESULT message is generated if these values are returned by Recognize.

Constant	Description
REC_DEBUG	All debugging return values are less than or equal to this.
REC_ALC	Invalid enabled alphabet.
REC_BADEVENTREF	Returned when the wEventRef member in the RC structure is invalid.
REC_CLVERIFY	Invalid verification level.
REC_DICT	Invalid dictionary parameters.
REC_ERRORLEVEL	Invalid error level.
REC_GUIDE	Invalid GUIDE structure.
REC_HREC	Invalid recognition handle.
REC_HWND	Invalid handle to window to send results to.
REC_INVALIDREF	Invalid data reference parameter.
REC_LANGUAGE	Returned by the recognizer when the lpLanguage member of RC contains a language that is not supported by the recognizer. Call ConfigRecognizer with the WCR_QUERYLANGUAGE subfunction to determine whether or not a particular language is supported.
REC_NOCOLLECTION	Returned by GetPenHwData if collection mode has not been set.
REC_OEM	Error values below REC_OEM (−1024) are specific to the recognizer.
REC_PCM	Invalid lPcm member in RC structure. There is no way for the recognition to end.
REC_PARAMERR	Invalid parameter.
REC_RECTBOUND	Invalid rectangle.
REC_RECTEXCLUDE	Invalid rectangle.
REC_RESULTMODE	Unsupported results mode requested.


SYV_ Symbol Values [New - Windows 95]
SYV_ Symbol Values

[New - Windows 95]

Each glyph a recognizer can identify has an associated symbol value. It is this value that is returned to the application by the recognizer.

The high-order and low-order words of a symbol value have the following meanings:

High-order word	Low-order word
0	System symbols.
1	ANSI character code.
2	Gestures.
3	Shift character codes (kanji).
4	Shapes.
5	Unicode.
6	Virtual keys.
7-0x7EFF	Reserved for future use.
0x7F00-0x7FFF	Recognizer-specific symbols.
>=0x8000	Character code for given code page. The low 15 bits of the high-order word indicate the code page.
Recognizers for the European market should return symbol values using ANSI and gesture symbol values (ANSI is the native character set for Windows in the European market). For the Japanese market, recognizers can use Shift JIS Level 1 and gestures. When writing a recognizer, bear in mind that symbol values outside these ranges cannot be interpreted by all Windows applications.


System Symbol Values

The following system symbol values are supported for recognizers:

Constant	Description
SYV_BEGINOR	Begins a list of choices; in the bedit guide, displayed as an opening brace character ({).
SYV_EMPTY	Empty.
SYV_ENDOR	Ends a list of choices. In the bedit guide, displayed as a closing brace character (}).
SYV_NULL	Null terminator.
SYV_OR	Separator for list of choices; in the bedit guide, displayed as a vertical bar (|).
SYV_SOFTNEWLINE	Translated to a space by SymbolToCharacter.
SYV_SPACENULL	Used in a symbol graph to indicate an alternative to a space.
SYV_UNKNOWN	Unrecognized glyph.


Gesture Symbol Values

All system recognizers are expected to recognize a special set of glyphs used as commands. In the following table, the "Windows Equivalent" column shows the mouse and keyboard equivalents in Windows.

Constant	Value	Description	Windows equivalent
. . .	00−0x00FF	Command gesture given. The low byte specifies which ANSI character was modified by the command gesture.	Nonstandard (usually CTRL+key).
SYV_BACKSPACE	0x00020008	Deletes character under gesture and sets insertion point.	BACKSPACE.
SYV_CLEAR	0x0002FFD5	Clears the selection.	DEL.
SYV_CLEARCHAR	0x0002FFD2	Clears the selection.	DEL.
SYV_CLEARWORD	0x0002FFDD	Deletes word or object under gesture.	Double-click, DEL.
SYV_COPY	0x0002FFDA	Copies selection to Clipboard.	CTRL+INS.
SYV_CORRECT	0x0002FFDF	Corrects selection or word under gesture.	None.
SYV_CONTEXT	0x0002FFD7	Displays a context menu	Right mouse click.
SYV_CUT	0x0002FFDB	Cuts selection and places it on Clipboard.	SHIFT+DEL.
SYV_EXTENDSELECT	0x0002FFD8	For linear selection (text), selects all text between current insertion point and point of extend-selection gesture. For nonlinear selection (objects), adds object under gesture to selection.	SHIFT+mouse click.
SYV_INSERT	0x0002FFD6	Opens the lens to allow text to be inserted.	None
SYV_KKCONVERT	0x0002FFD4	Starts Kana-to-Kanji converter. (Japanese version only.)	N/A
SYV_PASTE	0x0002FFDC	Pastes selection at point indicated by hot spot of paste gesture.	Click (place insertion point) followed by SHIFT+INS.
SYV_RETURN	0x0002000D	Enters carriage-return key.	Click, RETURN.
SYV_SPACE	0x00020020	Adds space character.	Click, SPACEBAR.
SYV_TAB	0x00020009	Enters tab.	Click, TAB.
SYV_UNDO	0x0002FFD9	Undoes previous action.	ALT+BACKSPACE.
SYV_USER	0x0002FFDE	Any circle gesture.	See the following section.


Circle Gesture Symbol Values

A circle gesture consists of a circled letter, either uppercase or lowercase. The Pen API version 2.0 does not explicitly support circle gestures. They are defined only for application or recognizer use.

The following table lists the SYV_ values for the circle gestures. Intervening values correspond to the letters between "a" and "z".

Constant	Value	Description
SYV_APPGESTUREMASK	0x00020000	Mask value for circle gestures.
SYV_CIRCLELOA	0x000224D0	Lowercase "a" circle gesture.
SYV_CIRCLELOZ	0x000224E9	Lowercase "z" circle gesture.
SYV_CIRCLEUPA	0x000224B6	Uppercase "A" circle gesture.
SYV_CIRCLEUPZ	0x000224CF	Uppercase "Z" circle gesture.


Selection Symbol Values

The following table lists the SYV_values for selection symbol gestures.

Constant	Value	Description
SYV_SELECTFIRST	0x0002FFC2	Minimum value for section SYVs.
SYV_LASSO	0x0002FFC1	Lasso selection (equivalent to double-click).
SYV_SELECTLEFT	0x0002FFC2	Select text to the left (not supported by the Microsoft Handwriting Recognizer).
SYV_SELECTRIGHT	0x0002FFC3	Select text to the right (not supported by the Microsoft Handwriting Recognizer).
SYV_SELECTLAST	0X0002FFCF	Maximum value for selection SYVs.


Shape Symbol Values

These values should be used by shape recognizers.

Constant	Value	Description
SYV_SHAPELINE	0x00040001	Shape recognized as a line.
SYV_SHAPEELLIPSE	0x00040002	Shape recognized as an ellipse.
SYV_SHAPERECT	0x00040003	Shape recognized as a rectangle.
SYV_SHAPEMIN	0x00040001	Minimum value for recognized shape SYVs.
SYV_SHAPEMAX	0x00040003	Maximum value for recognized shape SYVs.


Appendix   Differences Between Versions 1.0 and 2.0 of the Pen Application Programming Interface

Version 2.0 of the Pen Application Programming Interface (API) provides more services — and more avenues for innovation — than did version 1.0. A skimming of Chapters 10 and 11, which identify functions and structures new to version 2.0, indicates the extent of the enhancements added to the API.

However, if you have used version 1.0 of the Pen API, also known as Microsoft Windows for Pen Computing, you will find more than additional functions and other services in this release. Programming philosophy has changed as well. Partic-ularly in the area of recognition, the Pen API now allows greater freedom and responsibility for the handling and interpretation of pen input.

This appendix identifies some of the most important changes and improvements to the Pen API since version 1.0. It would require a number of pages to itemize all the improvements incorporated into version 2.0, which are described throughout this book. The purpose of this appendix is to help the developer familiar with version 1.0 to quickly identify several important areas of version 2.0 that reflect significant change. You will find that version 2.0 of the Pen API opens up new possibilities for collected ink data other than simply passing it to a recognizer.


Improvements to the bedit Control

The bedit control of version 2.0 of the Pen API has been significantly improved over that of version 1.0. The improvements aim to make text entry more convenient and more intuitive for the user. The following list briefly describes the major improvements:

•	The current insertion point is now indicated by an action handle instead of the caret of version 1.0.

•	The user can select text by dragging the insertion point action handle. Selected text appears in reverse video.

•	The user can move selected text within the control window by dragging it to a new position.

•	Single-line bedit windows can automatically scroll horizontally when the user fills either of the last two visible boxes. The last character remains visible after the scroll to help orient the user. The control window also provides scroll arrows for horizontal scrolling.

•	A single tap near the center of a character displays a list of alternative characters determined by the recognizer. Double-tapping brings up a menu with a list of alternative words that can replace the entire word above the tap. The user selects a letter or complete word by tapping the menu selection.

•	As do other controls in Microsoft Windows 95, bedit controls now provide a context menu from which the user can cut or copy a selection, paste, insert, and so forth.

•	If the user inserts a carriage return in a line of a multiline bedit, text to the right of the carriage return automatically wraps to the next line.

•	Empty cells are marked with a light-gray dot to help distinguish them from spaces.

The EM_LIMITTEXT message has a slightly different effect on bedit controls in version 2.0 of the Pen API. In version 1.0, sending EM_LIMITTEXT to a bedit control window set the number of boxes in the control as specified by the message's wParam parameter. In version 2.0, EM_LIMITTEXT sets the maximum number of bytes of text the control can hold instead of the number of boxes. For more infor-mation about EM_LIMITTEXT, see "The bedit Control" in Chapter 3, "The Writing Process."


Recognition

Version 2.0 of the Pen API significantly changes the way an application interacts with a recognizer. It allows an application to install multiple recognizers and use them selectively, first creating an HRC object for each recognizer to configure the recognition process. Version 2.0 provides many more recognition functions than did version 1.0, but places the full burden of recognition on the recognizer. All recognition functions are provided by the installed recognizer dynamic-link libraries (DLLs) and not by Windows.

The change in philosophy mentioned at the beginning of this chapter is particulary true with regard to recognition. Recognizers are now more clearly separate from the system and enjoy a corresponding freedom in their implementation. The Pen API defines the interaction between application and recognizer, but stops short of man-dating how a recognizer performs its tasks. The recognizer objects described in Chapter 8, "Writing a Recognizer," are called objects to emphasize that their forms are invisible to the application. The objects are "black box" entities, which the recognizer developer designs without restraint from the system.

For a description of the HRC object and other elements of recognition, see Chapter 5, "The Recognition Process."


The RC Structure

The core of the recognition process in version 1.0 was the RC data structure. The structure still exists in version 2.0, but it is made obsolete by the HRC object that governs the recognition process. An application can still use an RC structure when calling the obsolete version 1.0 functions ProcessWriting, InitRC, Recognize, and RecognizeData.

The following table lists the members of the RC structure. For each member, the second column describes the corresponding services in version 2.0 of the Pen API. Use this table to update your version 1.0 applications to use the new services. See the reference chapters in Part 2 for descriptions of the functions, messages, and constants cited in the table.

RC member	Equivalent service in Pen API 2.0
hrec	Return value from InstallRecognizer.
hwnd	PE_SETTARGETS message. (See "Step 2: PE_SETTARGETS Message" in Chapter 2.)
wEventRef	Return value from GetMessageExtraInfo. (See sample code in "InputWndProc" in Chapter 7.)
wRcPreferences	ConfigHREC with WCR_GETHAND or WCR_SETHAND.
lRcOptions	Various HRC functions described in Chapters 5 and 8.
lpfnYield	Not applicable in version 2.0.
lpUser	GetPenMiscInfo with PMI_USER. Cannot set new user in version 2.0.
wCountry	GetInternationalHRC or SetInternationalHRC.
wIntlPreferences	ConfigHREC with WCR_GETANSISTATE or WCR_SETANSISTATE.
lpLanguage	GetInternationalHRC or SetInternationalHRC.
rglpdf	Not applicable in version 2.0.
wTryDictionary	Not applicable in version 2.0.
clErrorLevel	Not applicable in version 2.0.
alc	GetAlphabetHRC or SetAlphabetHRC. (See "Specifying an Alphabet Set" in Chapter 8.)
alcPriority	GetAlphabetPriorityHRC or SetAlphabetPriorityHRC. Also ConfigHREC with WCR_GETALCPRIORITY or WCR_SETALCPRIORITY.
rgbfAlc	GetAlphabetHRC or SetAlphabetHRC.
wResultMode	Not applicable in version 2.0.
wTimeOut	GetPenMiscInfo or SetPenMiscInfo with PMI_TIMEOUT.
lPcm rectBound rectExclude	These three members are replaced by PE_GETPCMINFO message. (See "Step 3: PE_GETPCMINFO Message" in Chapter 2.)
guide	GetGuideHRC or SetGuideHRC.
wRcOrient	Not applicable in version 2.0.
wRcDirect	ConfigHREC with WCR_GETDIRECTION or WCR_SETDIRECTION.
nInkWidth rgbInk	These two members are replaced by GetPenMiscInfo and SetPenMiscInfo with PMI_PENTIP.
dwAppParam	Determined by recognizer.
dwDictParam	Not applicable in version 2.0.
dwRecognizer	Determined by recognizer.


The RCRESULT Structure

The RCRESULT structure provides the means for a version 1.0 recognizer to communicate results to the application. When the recognizer finishes its work, the application receives a WM_RCRESULT message containing a pointer to an RCRESULT structure. It then reads the recognizer's guesses from the structure.

In version 2.0, the RCRESULT structure is made obsolete by the HRCRESULT object. Although they have similar names, do not confuse the two or attempt to draw parallels between them. The HRCRESULT contains the recognizer's results in a format determined by the recognizer. This format most likely has nothing to do with RCRESULT. The application simply calls into the recognizer for recognition results.

For complete descriptions of the version 2.0 recognition functions, see Chapters 5 and 8 and the reference entries in Chapter 10.


Default Recognition

The version 2.0 application collects, displays, and distributes ink to the recognizer while the user is writing. The Pen API provides convenient and flexible default processing for these tasks in the DoDefaultPenInput function, which completely supersedes ProcessWriting.

Nearly all pen-based applications should take advantage of the capabilities of DoDefaultPenInput. Through a system of messages, the function allows an application to monitor and govern the recognition process, or simply accept the default decisions of DefWindowProc.

For a description of DoDefaultPenInput and the message traffic it generates, read Chapter 2, "Starting Out with System Defaults." To see DoDefaultPenInput in use, refer to the code for the PENAPP sample application presented in Chapter 7, "A Sample Pen Application."


Recognition Processing

In version 2.0, applications have much greater control over scheduling the recog-nition process. If it does not use DoDefaultPenInput, an application continuously feeds pen data to a recognizer through the AddPenInputHRC function. By calling ProcessHRC, the application can also schedule regular time slots for the recog-nizer to see the input as the user writes.

This real-time recognition processing contrasts with the recognition procedures of version 1.0, in which the application relinquished control to the obsolete Recognize function for the duration of the input session. The version 2.0 recognizer can now "cook" pen input virtually as it arrives from the pen driver, with the application determining how often and how long the recognizer has control.


Initializing and Closing a Recognizer

The recognition functions InitRecognizer and CloseRecognizer are obsolete in version 2.0 of the Pen API. In their place, two new subfunctions have been added to ConfigRecognizer. When the pen system loads a recognizer, it now calls ConfigRecognizer with the subfunction WCR_INITRECOGNIZER. In response to this call, the recognizer should perform the required initialization tasks formerly conducted by InitRecognizer.

Similarly, the system also calls ConfigRecognizer when it unloads the recognizer, this time with the subfunction WCR_CLOSERECOGNIZER. This call informs the recognizer it is being unloaded and it should conduct any required cleanup operations.

Applications based on version 2.0 do not call ConfigRecognizer. This is because the function has no argument that refers to a specific recognizer of the several that may be currently installed. Instead, version 2.0 applications call the new API function ConfigHREC to configure a recognizer or query for its capabilities. The system determines the intended recognizer and passes the call on to that recog-nizer's ConfigRecognizer function. Thus, a version 2.0 recognizer exports ConfigRecognizer, which an application accesses by calling ConfigHREC.


Word Lists and Dictionaries

Word lists are new to version 2.0. An application can select from among any number of word lists to help a recognizer verify its guesses. Word-list files must have standard text formatting to allow users to create or modify them with a text editor, but otherwise have no restrictions in size or content.

Dictionaries existed in version 1.0 as DLL files. In version 2.0, a dictionary serves a recognizer invisibly as a large word list. The application has no access to a dic-tionary except to tell the recognizer whether or not to use one. Dictionary files can have any format, but are usually compressed in some manner private to the recog-nizer.

A dictionary is thus a private (and optional) tool of a recognizer. The "system" in the name EnableSystemDictionaryHRC does not refer to the operating system, but simply emphasizes ownership. In this case, "system" means "not application."


Gestures

Version 2.0 no longer provides explicit support for user-defined gestures. The burden of recognizing and handling new gestures instead falls to the recognizer and application. The Gesture Manager (GESTMAN.EXE) and API function ExecuteGesture do not exist in version 2.0.

The standard set of "circle-letter" gestures remains, however. All version 2.0 edit controls — hedit, bedit, and iedit — respond normally to the gestures listed in the following table. An application or recognizer is free to provide support for any other gesture.

This table lists the gestures available in version 2.0 edit controls. Note that the V-circle and check-mark-circle gestures have identical behavior. The V-circle gesture is provided only to prevent confusion with the check-mark-circle gesture.

Gesture	Name	Action
	Lasso-tap	Select
	X-circle	Cut current selection
	C-circle	Copy current selection
	P-circle	Paste
	Check-mark-circle	Edit/Properties
	V-circle	Edit/Properties
	Caret-circle	Insert text
	M-circle	Display context menu
	D-circle	Clear/Delete
	S-circle	Space
	N-circle	Newline (carriage return)
	T-circle	Tab
	U-circle	Undo


Action Handles

In version 2.0, edit controls have small icons called action handles. Action handles provide the user a more intuitive and discoverable means for carrying out certain editing tasks than do gestures. With action handles, the user can:

•	Select text.

•	Cut, copy, and paste.

•	Change the insertion point.

•	Drag-and-drop a selection.

•	Access a menu of options.


On-Screen Keyboard

In version 2.0, the on-screen keyboard is an independent application named SK.EXE, which can be launched in the same way any application is launched in Windows; for example, by using the WinExec() function.

The ShowKeyboard function, which invoked the on-screen keyboard in version 1.0, is still supported but for older applications, but has been modified due to the fact that the on-screen keyboard is a separate application in version 2.0.

The WM_SKB message, available in version 1.0, is no longer sent to top-level windows when the on-screen keyboard changes.


Timing Information

The new HINKSET object allows an application to refer to stroke data completely or partially by time, rather than by coordinates. The HINKSET object is a tem-poral version of HPENDATA. It sees each stroke as an interval of time instead of a collection of physical points. See "The HINKSET Object" in Chapter 4 for a description of stroke timing and HINKSET.

Stroke timing allows a new characteristic of ink rendering called animation. Through animation, an application can control the speed at which pen data is displayed. For more information, see the description of DrawPenDataEx in Chapter 10, "Pen Application Programming Interface Functions."


Targeting

An application based on version 2.0 of the Pen API can create multiple windows and writing areas on the screen that simultaneously accept pen input. Targeting allows the application to govern the distribution of input data to the proper window.

For example, a forms application can establish targeting information for each of several controls on the screen. Even if the user writes in the controls in arbitrary order, targeting ensures the pen data arrives at the proper window procedure.

For more information on targeting, see "Step 2: PE_SETTARGETS Message" in Chapter 2, "Starting Out with System Defaults." Also see the reference sections for TARGET and TARGINFO in Chapter 11, "Pen Application Programming Interface Structures."


HPENDATA Memory Block

The internal structure of the HPENDATA memory block has changed since ver-sion 1.0. As described in "Data Within an HPENDATA Object" in Chapter 4, the stroke header no longer incorporates a STROKEINFO structure. However, to maintain compatibility with version 1.0, the GetPenDataStroke function provides a copy of a STROKEINFO structure for the requested data points.

Since the HPENDATA format may again change in future versions, applications should avoid attempting to read the memory block directly and instead rely on the appropriate HPENDATA functions described in Chapter 4, "The Inking Process."

The PENINFO structure in the block's HPENDATAHEADER has also changed since version 1.0. PENINFO contains a new member, fuOEM, that indicates the type of original equipment manufacturer (OEM) data the HPENDATA object contains.


Registry Configuration

In version 1.0, the PENWIN.INI file contained system configuration information such as the name of the default recognizer and the time-out value for selection. Version 2.0 removes configuration information from the PENWIN.INI file and instead stores it in the system registry.

For example, the following code fragment sets the fictitious recognizer RECOG1.DLL as the default system recognizer. The code presumes that RECOG1.DLL:

•	Resides in a location where Windows can find it (usually the system subdirectory).

•	Is capable of taking on the role of system recognizer.

For more information about recognizers, see Chapter 8, "Writing a Recognizer." For descriptions of the registry functions RegSetValueEx, RegCreateKey, and RegCloseKey, see the documentation included in the Win32 Software Develop-ment Kit.

    HKEY    hk;             // Key handle returned by RegCreateKey

        .

        .

        .

    // Open (or create) the registry for the parent key

    if ((lRes = RegCreateKey( HKEY_LOCAL_MACHINE,

                              (LPSTR)REGSTR_PATH_CONTROL,

                              &hk )) == ERROR_SUCCESS)

    {

        // If successful, set "RECOG1.DLL" as the system recognizer

        RegSetValueEx( hk, REGSTR_VAL_PEN_RECOG, NULL, REG_SZ,

                    (LPBYTE)(LPSTR)"RECOG1.DLL", 0 );

        // Close it

        RegCloseKey( hk );

    }

The PENREG.H header file defines values pertaining to the system registry. Note that, generally, applications should not change the system configuration, relying instead on the user to do so through the Control Panel.

For information on retrieving and setting other pen system parameters, see the reference entries for GetPenMiscInfo and SetPenMiscInfo in Chapter 10, "Pen Application Programming Interface Functions."


Appendix   Using the 32-Bit Pen Application Programming Interface

This appendix describes the 32-bit pen services provided by the PENWIN32.DLL and PKPD32.DLL libraries. With some exceptions, these dynamic-link libraries (DLLs) offer Win32™-based applications the same pen-based support as the 16-bit libraries PENWIN.DLL and PKPD.DLL without requiring the intermediate steps of thunk conversions.

The services not supported by the 32-bit Pen Application Programming Interface (API) consist mainly of outdated functions no longer required in version 2.0. These outdated functions are supported in the 16-bit Pen API only to maintain backward compatibility with version 1.0. They will not be supported in future versions.

To enable 32-bit pen services, an application must be created in a 32-bit environ-ment — that is, the compiler, linker, libraries, and header files must be of 32-bit type. Before including pertinent header files, the application must define the constant WIN32 as shown here:

#define    WIN32

#include   <windows.h>

#include   <penwin.h>

A 32-bit application links to the pen system libraries in the same way it links to any other Windows library, with either of the following methods:

•	Link to the import library PKPD32.LIB (not recommended for PENWIN32.LIB) , or

•	Explicitly load PENWIN32.DLL and PKPD32.DLL with the LoadLibrary function. After loading the libraries, the application must call GetProcAddress to obtain the address of each Pen API function it intends to use. Before termin-ating, the application should call FreeLibrary to unload the libraries from memory.

The first method should normally be used to link functions in PKPD32.LIB. This method can be used for functions in PENWIN32.LIB if it is known for certain that the application will always be run on systems that have pen services installed, in which case the application should test for the existence of pen services at startup and exit if not found.

The second method should be used for PENWIN32.DLL functions when it is anticipated that the application may be run on systems where pen services are not installed. The reason for not linking PENWIN32.LIB is to prevent the application from loading PENWIN32.DLL on a system that has not loaded pen services at startup. This could happen, for example, on a computer that has PENWIN32.DLL on the path but has not installed pen services. Loading PENWIN32.DLL dynamic-ally does not sufficiently start pen services and errors are likely to occur.

In a 32-bit application, the call

GetSystemMetrics( SM_PENWINDOWS );

returns the handle of PENWIN32.DLL. This DLL makes available some of the same resources (such as cursors) provided by the 16-bit PENWIN.DLL library.


32-Bit Functions

The following table lists the functions supported by the 32-bit Pen API. The syntax for each function remains the same as for 16-bit applications. For the description and syntax of each function, refer to Chapter 10, "Pen Application Programming Interface Functions."

The table also uses an asterisk (*) to identify the functions PKPD32.DLL exports. These functions are always available to 32-bit applications running with Windows 95, regardless of whether the PENWIN32.DLL file is present. For more informa-tion, see "Pen Kernel Functions" in Chapter 9, "Summary of the Pen Application Programming Interface."

AddInksetInterval*

AddPenDataHRC

AddPenInputHRC

AddPointsPenData*

AddWordsHWL

BoundingRectFromPoints*

CharacterToSymbol

CompressPenData*

ConfigHREC

ConfigRecognizer

CorrectWriting

CorrectWritingEx

CreateCompatibleHRC

CreateHWL

CreateInkset*

CreateInksetHRCRESULT

CreatePenData

CreatePenDataEx*

CreatePenDataHRC

CreatePenDataRegion*

DestroyHRC

DestroyHRCRESULT

DestroyHWL

DestroyInkset*

DestroyPenData*

DoDefaultPenInput

DPtoTP

DrawPenDataEx*

DuplicatePenData*

EnableGestureSetHRC

EnableSystemDictionaryHRC

EndPenInputHRC

ExtractPenDataPoints*

ExtractPenDataStrokes*

GetAlphabetHRC

GetAlphabetPriorityHRC

GetAlternateWordsHRCRESULT

GetBoxMappingHRCRESULT

GetBoxResultsHRC

GetGuideHRC

GetHotspotsHRCRESULT

GetHRECFromHRC

GetInksetInterval*

GetInksetIntervalCount*

GetInternationalHRC

GetMaxResultsHRC

GetPenAppFlags

GetPenAsyncState

GetPenDataAttributes*

GetPenDataInfo*

GetPenInput

GetPenMiscInfo

GetPenResource

GetPointsFromPenData*

GetResultsHRC

GetStrokeAttributes*

GetStrokeTableAttributes*

GetSymbolCountHRCRESULT

GetSymbolsHRCRESULT

GetVersionPenWin

GetWordlistCoercionHRC

GetWordlistHRC

HitTestPenData*

InsertPenData*

InsertPenDataPoints*

InsertPenDataStroke*

InstallRecognizer

IsPenEvent

MetricScalePenData*

OffsetPenData*

PeekPenInput

PenDataFromBuffer*

PenDataToBuffer*

ProcessHRC

ReadHWL

RedisplayPenData*

RemovePenDataStrokes*

ResizePenData*

SetAlphabetHRC

SetAlphabetPriorityHRC

SetBoxAlphabetHRC

SetGuideHRC

SetInternationalHRC

SetMaxResultsHRC

SetPenAppFlags*

SetPenMiscInfo

SetResultsHookHREC

SetStrokeAttributes*

SetStrokeTableAttributes*

SetWordlistCoercionHRC

SetWordlistHRC

StartInking

StartPenInput

StopInking

StopPenInput

SymbolToCharacter

TargetPoints

TPtoDP

TrainHREC

TrimPenData*

UnhookResultsHookHREC

UninstallRecognizer

WriteHWL


32-Bit Messages

The 32-bit Pen API does not support all the 16-bit messages described in Chap-ter 12, "Pen Application Programming Interface Messages." This section lists the messages that are supported by the 32-bit Pen API. Although most 32-bit messages behave the same way as 16-bit messages, certain WM_PENEVENT submessages behave differently.


WM_PENEVENT Submessages

The following submessages of WM_PENEVENT require different treatment in 32-bit applications:

PE_BEGININPUT

PE_BUFFERWARNING

PE_PENDOWN

PE_PENMOVE

PE_PENUP

PE_TERMINATED

PE_TERMINATING

In 16-bit applications, these submessages store different values in the high-order and low-order words of their lParam:

•	wParam = PE_ submessage number

•	LOWORD( lParam ) = event reference or termination code

•	HIWORD( lParam ) = HPCM handle

This scheme is not possible in Win32-based applications because lParam must contain a single 32-bit handle; therefore, the parameters for the submessages listed above are arranged differently in the 32-bit Pen API:

•	LOWORD( wParam ) = PE_ submessage number

•	HIWORD( wParam ) = event reference or termination code

•	lParam = HPCM handle

To extract data from the parameters, use the following macros defined in the PENWIN.H header file. These macros render the differences in the parameters transparent to an application because they automatically adjust for 16-bit or 32-bit type of programs:

Macro	Description
HpcmFromWpLp	Retrieves HPCM handle returned from StartPenInput. If the application calls DoDefaultPenInput, that function calls StartPenInput internally.
EventRefFromWpLp	Retrieves event reference value for session returned from GetMessageExtraInfo. Both DoDefaultPenInput and StartPenInput take this value as their second argument.
TerminationFromWpLp	Retrieves a PCM_ value indicating the reason for termination from the PE_TERMINATED and PE_TERMINATING submessages.
SubPenMsgFromWpLp	Retrieves PE_ submessage value.
The macros take both wParam and lParam as arguments and automatically return the desired value for both 16-bit and 32-bit applications. For example:

HPCM      hpcm;           // HPCM handle created by StartPenInput

LONG      lInfo;          // Return value from GetMessageExtraInfo

int       iRet;           // Error code

.

.

.

case WM_LBUTTONDOWN:

lInfo = GetMessageExtraInfo( );

if (IsPenEvent( msg, lInfo ))

{

iRet = DoDefaultPenInput( hwnd, LOWORD(lInfo) );

}

.

.

.

case WM_PENEVENT:

switch( SubPenMsgFromWpLp( wParam ) );

{

case PE_PENDOWN:

hpcm  = HpcmFromWpLp( wParam, lParam );

//

// Note lInfo and EventRefFromWpLp( wParam, lParam )

// contain the same event reference value.

//


List of 32-Bit Window Messages

The following table lists the WM_ window messages and corresponding sub-messages supported by the 32-bit Pen API (submessages available in the Japanese version are indicated by an asterisk):

WM_ messages	Submessages
WM_PENMISCINFO WM_PENCTL	* HE_CANCELCONVERT HE_CHAROFFSET HE_CHARPOSITION HE_DEFAULTFONT HE_ENABLEALTLIST * HE_FIXKKCONVERT HE_GETBOXLAYOUT * HE_GETCONVERTRANGE HE_GETINFLATE HE_GETINKHANDLE* HE_GETKKCONVERT * HE_GETKKSTATUS HE_GETUNDERLINE HE_HIDEALTLIST * HE_KKCONVERT * HE_PUTCONVERTCHARHE_SETBOXLAYOUT * HE_SETCONVERTRANGE HE_SETINFLATE HE_SETINKMODE HE_SETUNDERLINE HE_SHOWALTLIST HE_STOPINKMODE
WM_ messages	Submessages
WM_PENMISC	PMSC_BEDITCHANGE PMSC_GETHRC PMSC_GETINKINGINFO PMSC_GETPCMINFOPMSC_GETSYMBOLCOUNT PMSC_GETSYMBOLS PMSC_INKSTOP * PMSC_KKCTLENABLE PMSC_LOADPW * PMSC_PENUICHANGE PMSC_SETHRC PMSC_SETINKINGINFO PMSC_SETPCMINFO PMSC_SETSYMBOLS * PMSC_SUBINPCHANGE
WM_CTLINIT	CTLINIT_BEDIT CTLINIT_HEDIT CTLINIT_IEDIT
WM_PENEVENT	PE_BEGINDATA PE_BEGININPUT PE_BUFFERWARNING PE_ENDDATA PE_ENDINPUT PE_GETINKINGINFO PE_GETPCMINFO PE_MOREDATA PE_PENDOWN PE_PENMOVE PE_PENUP PE_RESULT PE_SETTARGETS PE_TERMINATED PE_TERMINATING


List of 32-Bit iedit Control Messages

The following table lists the IE_ messages available for iedit controls in 32-bit applications:

IE_CANUNDO

IE_DOCOMMAND

IE_EMPTYUNDOBUFFER

IE_GETAPPDATA

IE_GETBKGND

IE_GETCOMMAND

IE_GETCOUNT

IE_GETDRAWOPTS

IE_GETERASERTIP

IE_GETFORMAT

IE_GETGESTURE

IE_GETGRIDORIGIN

IE_GETGRIDPEN

IE_GETGRIDSIZE

IE_GETINK

IE_GETINKINPUT

IE_GETINKRECT

IE_GETMENU

IE_GETMODE

IE_GETMODIFY

IE_GETNOTIFY

IE_GETPAINTDC

IE_GETPDEVENT

IE_GETPENTIP

IE_GETRECOG

IE_GETSECURITY

IE_GETSEL

IE_GETSELCOUNT

IE_GETSELITEMS

IE_GETSTYLE

IE_SETAPPDATA

IE_SETBKGND

IE_SETDRAWOPTS

IE_SETERASERTIP

IE_SETFORMAT

IE_SETGRIDORIGIN

IE_SETGRIDPEN

IE_SETGRIDSIZE

IE_SETINK

IE_SETINKINPUT

IE_SETMODE

IE_SETMODIFY

IE_SETNOTIFY

IE_SETPENTIP

IE_SETRECOG

IE_SETSECURITY

IE_SETSEL

IE_UNDO


Appendix   Modifying the SYSTEM.INI File

This appendix describes the settings used in the SYSTEM.INI. The SYSTEM.INI file contains all of the editable information used by the Pen Application Program-ming Interface (API). All other system information concerning the Pen API version 2.0 is maintained in the Windows 95 system registry and will not require modifica-tion except by using the Control Panel Pen icon after Pen Services for Windows 95 is installed.

It is also unlikely that you will manually edit the pen entries in SYSTEM.INI in the Windows 95 environment. A setup information file (PENWIN.INF) provided by Microsoft contains the script that Windows 95 Setup uses to install Pen Services for Windows 95 as an optional system component. This script adds the entries shown in the table below to the SYSTEM.INI file. The one SYSTEM.INI entry that you may want to edit manually after Pen Services is installed is the level of non-critical errors reported. For this, you will have to manually edit the PenWinErrors entry in the [boot] section of SYSTEM.INI, using one of the values shown in the table below.

In versions of Windows previous to Windows 95, pen services were removed from a system by manually editing the SYSTEM.INI file and deleting the entries shown in the table below. This should not be done with Windows 95. Use the Control Panel Add/Remove Programs icon to remove Pen Services for Windows 95. This will automatically delete all the Pen Services entries from SYSTEM.INI.

The following table lists the pen-related entries for SYSTEM.INI

SYSTEM.INI Entry Made at Installation Time	Description
[boot]	Section name.
drivers=pen penwindows	Defines installable drivers.
PenWinErrors=1	Determines the level of non-critical errors displayed. 0 = show no errors or warnings. 1 = show errors only. 2 = show errors and warnings.
[drivers]	Section name.
pen=penc.drv	Sets the pen driver.
penwindows=penwin.dll	Pen API library.


Appendix   Accessing the Pen Device Driver

There are no specific functions in the Pen Application Programming Interface (API) for pen driver use. Instead, the pen driver functionality is implemented with install-able driver messages.

The pen driver is a 16-bit installable driver in the Microsoft Windows 95 operating system. All communication with an installable driver is through driver messages. A 16-bit application can send a message to the pen driver with the Windows API SendDriverMessage function.

Because a call to SendDriverMessage must originate from a 16-bit virtual machine, 32-bit applications cannot use SendDriverMessage to send messages directly to the pen driver. To communicate with the pen driver, a 32-bit application must provide its own 16-bit dynamic-link library (DLL) to "thunk" calls to SendDriverMessage.

The installable portion of the pen driver may not exist in future versions of Win-dows. For this reason, an application should not query for device information directly from the driver unless necessary. Instead, an application should get hardware information about an HPENDATA object by calling GetPenDataInfo or GetPenDataAttributes. These functions can apprise an application of various hardware characteristics (such as sampling rate) current when collecting the HPENDATA.


Opening the Pen Driver

Before sending a driver a message, an application must first obtain a handle to the driver with the Windows OpenDriver function. The following code demonstrates this:

HDRVR	hDrvPen;

.

.

.

hDrvPen = OpenDriver( "pen", NULL, NULL );

if( hDrvPen == NULL )

{

// The pen driver does not exist.

// Either display an error message and exit,

// or continue to function as a pen-unaware application.

}

As an example of how to send the driver messages, the following code uses the pen driver message DRV_SetPenSamplingRate to set the sampling rate to 200 points per second. A later segment of code then queries the driver to get relevant pen infor-mation.

WORD	wOldRate;

wOldRate = SendDriverMessage( hDrvPen,                 // Driver handle

                              DRV_SetPenSamplingRate,  // Message

                              200,                     // New rate in Hz

                              NULL );                  // Not applicable

.

.

.

// Get information about the pen driver

PENINFO  pi;

BOOL     PenHardwareExists;

fPenHardwareExists = SendDriverMessage( hDrvPen,

                                        DRV_GetPenInfo,

                                        (DWORD)(LPPENINFO)&pi,

                                        NULL );

When finished, an application must close the handle to the installable driver with the CloseDriver function, as shown here:

CloseDriver( hDrvPen, NULL, NULL );


Pen Driver Return Values

All the values that can be returned by the Pen Driver in response to a message are listed in the table below. These return value constants are defined in PENDRV.H.

Return Value	Description
DRV_SUCCESS	The message request was completed successfully.
DRV_FAILURE	The message request was attempted, but was not completed successfully.
DRV_BADPARAM1	The message request was not attempted because the first parameter in the message was invalid.
DRV_BADPARAM2	The message request was not attempted because the second parameter in the message was invalid.
DRV_BADSTRUCT	The message request was not attempted because a message parameter that must point to a structure was not pointing to a valid structure of the required type. For example, a message parameter that should point to a PENINFO structure does not point to a writeable block of memory large enough to contain a PENINFO structure.


Pen Driver Messages

The following table describes the pen driver messages an application can use, the parameters that must be provided with each message, and the message return values.

Pen driver message	Meaning	Parameters	Return value
DRV_Configure	Requests the driver to display a configuration dialog box.	lParam1 LOWORD is the handle to a window that will own the dialog box; lParam2 is 0.	Returns DRV_SUCCESS or, if the window handle is invalid, returns DRV_FAILURE.
DRV_GetCalibration	Instructs the driver to  fill a CALBSTRUCT structure with the cur-rent calibration settings, including size and off- set values.	lParam1 is a far pointer to a CALBSTRUCT structure to be filled; lParam2 is 0.	Returns DRV_SUCCESS or DRV_FAILURE if the installed tablet does not support re calibration. DRV_BADPARAM1 is returned if lParam1 is invalid.
DRV_GetName	Reports the name of the pen hardware.	lParam1 LOWORD is the length of the name buffer; lParam2 is a LPSTR pointer to the name buffer.	If successful, returns the number of characters copied into the name buffer, which is the number of characters in the driver name plus 1 (the string null termina-tion character is copied into the buffer).  Otherwise, returns DRV_BADPARAM1 because provided buffer length is insufficient or DRV_BADPARAM2 because the provided memory block is not a writeable block of the specified size.
DRV_GetPenInfo	Fills in the PENINFO structure pointed to by the message's lParam1 parameter with the current pen parameters. If lParam1 is set to NULL, the driver checks for the presence of a pen tablet only.	lParam1 is a far pointer to a PENINFO structure to be filled; lParam2 is 0.	Returns DRV_SUCCESS or DRV_FAILURE if no pen device is currently connected. DRV_BADPARAM1 is returned if the provided block of memory is not writeable or not large enough to contain a PENINFO structure.
DRV_GetPenSamplingRate	Returns the current sampling rate.	lParam1 is 0; lParam2 is 0.	LOWORD contains the current sampling rate.
DRV_GetVersion	Reports the Pen API version number the driver supports and the pen packet size.	lParam1 is 0; lParam2 is 0.	HIWORD contains the pen packet size in bytes. Within the LOWORD, HIBYTE contains the minor version number, LOBYTE is the major version number.
DRV_PenPlayBack	Sends an array of recorded pen packets  to the driver, which the driver then sends back  to the system as though receiving the packets  in real time from the device.	lParam1 is a far pointer to an array of pen packets to be played through the system; lParam2 LOWORD is the number of pen packets to play back, HIWORD is 0.	If successful, returns 1; if failure, returns a value less than 1.
DRV_PenPlayStart	Informs the pen driver  of the format of the  pen packet data it will receive after it receives the next DRV_PenPlayBack message. The driver  does not begin sending pen packets into the system until it receives the DRV_PenPlayBack message.	lParam1 is a far pointer to a DWORD that is updated when the driver is done playing back pen packets; lParam2 is either 0 or 1 and specifies the format of the pen packets passed to the driver (0 means version 1.0 packets and 1 means version 2.0 packets).	Returns DRV_SUCCESS or DRV_FAILURE if the pen system is already  in playback mode.
DRV_PenPlayStop	Forces the driver out of playback mode.	lParam1 is 0; lParam2 is 0.	Always returns DRV_SUCCESS (the pen driver was in play-back mode and the playback mode was successfully stopped  or the pen driver was already out of playback mode).
DRV_Query	Returns whether or not the version 2.0 pen driver supports the specified message.	lParam1 LOWORD specifies the message queried about; lParam2 is 0.	Returns DRV_SUCCESS if the message is supported  or DRV_FAILURE if it is not.
DRV_QueryConfigure	Returns whether or not the driver can provide a configuration dialog box.	lParam1 is 0; lParam2 is 0.	Returns DRV_SUCCESS if the driver provides a configuration dialog  box or DRV_FAILURE if it does not.
DRV_SetCalibration	Sets the tablet calibration.	lParam1 is a far pointer to a CALBSTRUCT structure that describes the new calibration parameters the pen  driver must use; lParam2 is 0.	Returns DRV_SUCCESS or DRV_FAILURE if the tablet does not sup- port calibration. DRV_BADPARAM1  is returned if lparam1  is not a pointer to a CALBSTRUCT structure.
DRV_SetPenSamplingDist	Sets the minimum pen sampling distance. Successive points less than the given distance do not generate new points. The distance is defined in raw tablet coordinates as the maximum of the change in x and y. The default distance is 0, which means that all pen events generate new events. A pen driver does not have to simulate non zero sampling distances. An application must use the DRV_GetPenInfo driver message to determine the actual sampling distance set. Pressing or releasing a pen barrel button gen-erates a new event, even if the pen does not move.	lParam1 HIWORD is 0; lParam1 LOWORD is a new sampling distance; lParam2 is 0.	If successful, HIWORD contains 0; LOWORD contains the previous sampling distance. Otherwise, returns DRV_FAILURE.
DRV_SetPenSamplingRate	Sets the pen sampling rate in samples per second.	lParam1 HIWORD is 0; lParam1 LOWORD is a new sampling rate; lParam2 is 0.	If successful, HIWORD contains 0; LOWORD contains the previous sampling rate. Otherwise, returns DRV_FAILURE.
The calibration driver messages use the CALBSTRUCT structure defined as follows:

typedef struct

{

int  wOffsetX;

int  wOffsetY;

int  wDistinctWidth;

int  wDistinctHeight;

} CALBSTRUCT, FAR * LPCALPSTRUCT;

The wOffsetX and wOffsetY members are the amount in tablet coordinates that need to be added to the x- and y-coordinate values returned by the hardware for proper calibration. The wDistinctWidth and wDistinctHeight members have the same meaning as in the PENINFO structure.


BLANK PAGE

IMPORTANT: This text will appear on screen, but will not print on a PostScript printer.

This page should be the last one in this file; it was inserted by running the InsertBlankPage macro.

Do not type any additional text on this page!


Glossary

A

action handle

A small icon provided in edit controls that facilitates an editing tasks such as dragging or insertion.

B

baseline

An imaginary horizontal line on which handwritten text rests. Analogous to the lines of lined notebook paper.

C

comb

A form of writing guide, such as those used in many common forms and questionnaires, consisting of a horizontal line with spaced tick marks. The guide gets its name from the resemblance of the tick marks to the teeth of a comb. The user writes in a comb guide with individual characters separated by the tick marks.

confidence level

A value assigned by a recognizer to indicate its degree of certainty in the results of a recognition. For example, in recognizing the word "clear," a recognizer assigns a confidence level to each of the five letters and can also assign a confidence level to the entire word. Word lists and dictionaries can influence confidence levels. See also recognizer.

D

dictionary

A list of words or phrases private to a recognizer. A recognizer can use its dictionaries to verify recognition guesses, as directed through the EnableSystemDictionary

G

gesture

A predefined pen motion that signifies some desired action, such as a "lasso" to select or an X to delete. See also lasso.

H

hook

A callback function provided by an application that receives certain data before the normal recipient of the data. The hook function can thus examine or modify the data before passing it on.

hot spots

Critical points on symbols, particularly gestures, identified by a recognizer during recognition. See also gesture, recognizer, symbol.

I

ink

(1) A trail of colored pixels left on the screen that marks the path of the pen's motion. (2) Input data generated by the moving pen; pen data.

inkset

An object that maps data points to time intervals. The points recorded in an inkset object may describe one or more strokes. See also stroke.

irreversible compression

A data-compression technique that produces a high degree of compression, but at the cost of lost information. After uncompression, the pen data can be redisplayed but recognition accuracy may be reduced. See also reversible compression.

L

lasso

A gesture formed by circling a section of text or other displayed data. See also gesture.

lens

A standard Windows pen interface dialog box that offers an on-screen keyboard or letter guides and is used for entering and editing text.

lossless compression

See reversible compression.

lossy compression

See irreversible compression.

O

OEM data

Data about pen pressure, angle, height, and other aspects of pen input that is collected in addition to data points. The specific OEM data collected depends on the hardware and the data it reports.

on-screen keyboard

(1) An image of a keyboard displayed on the screen. (2) The applet (Screen Keyboard or SKB) that displays the image. The user "types" on the on-screen keyboard by pressing the pen on the desired keys, as though typing on a real keyboard.

P

packet

A collection of pen data sent by the pen driver at a frequency determined by the sampling rate. Each packet contains the current coordinates of the pen, the time, and, optionally, other information. Collectively, the packets represent a digitized history of the pen's movement. See also sampling rate.

pen collection mode

The system state in which pen movement generates data, instead of being interpreted as mouse movement. Also known as input session.

pen-down stroke

Data points collected while the pen is in contact with the tablet. Together, these points comprise a stroke. See also pen state, pen tip transition, pen-up points, proximity stroke.

pen packet

See packet.

pen state

The condition of the pen relative to the tablet surface — either up or down, depending on whether the pen is in contact with the tablet.

pen tip transition

The act of touching a pen to or lifting the pen from the tablet surface. The former begins a pen-down stroke, while the latter ends a pen-down stroke and begins a pen-up stroke. See also stroke, proximity stroke.

pen-up stroke

Data points received when the pen is not in actual contact with the tablet, but near enough for the tablet to sense movement. Together, these points comprise a proximity stroke. See also pen-down points, pen state, pen tip transition, proximity stroke.

proximity stroke

A stroke formed while the pen is near but not on the tablet surface. Also called "pen-up stroke." Not all pen tablets can detect proximity strokes. See also pen tip transition, pen-up points, stroke.

R

real time

In the context of pen-based computing, real time means "while the pen is moving."

recognition function

One of the 43 Pen Application Programming Interface (API) functions exported by a recognizer dynamic-link library. See also recognizer.

recognizer

A dynamic-link library of functions that collectively serve to recognize ink data as characters, numerals, words, foreign script, or other symbols.

reentrancy

The condition in which a function is interrupted during execution and restarted from its beginning in response to another caller.

reversible compression

A data-compression technique that loses no information, so data can be redisplayed and recognized with no loss of accuracy after uncompression. See also irreversible compression.

S

sampling rate

The frequency at which the pen driver sends packets to the pen system. A typical sampling rate is 100 − 120 packets per second, but does not necessarily equal the rate of hardware interrupts generated by the pen tablet. See also packets.

Screen Keyboard

See on-screen keyboard.

SKB

See on-screen keyboard.

stroke

The pen data generated between two pen tip transitions. For example, when the pen touches the tablet (pen down), all data generated as the pen moves comprises a pen-down stroke until the pen leaves the tablet. If the tablet can sense proximity strokes, the pen movement above the tablet surface forms a separate pen-up stroke until the pen either leaves the tablet's range of sensitivity or touches down again. Thus, in noncursive printing, the letter "c" is formed as a single stroke while the letter "E" requires several pen-down strokes separated by pen-up strokes. See also pen-down points, pen tip transitions, pen-up points, proximity strokes.

symbol

An element interpreted by a recognizer from raw pen data. For example, the default system recognizer sees an individual letter or numeral as a symbol. A word is thus a string of symbols. A recognizer for cursive writing, however, may see an entire word as a single symbol without distinguishing each letter of the word. See also recognizer.

symbol correspondence

A map of the ink data that forms a recognized symbol. See also symbol element.

symbol element

An SYE structure containing a symbol value, its confidence level, and an identification of the ink data that forms the symbol. See also confidence level, symbol value.

symbol value

A numerical value that represents a recognized character or set of characters. A symbol value is internal to the recognizer and by itself has little meaning to the application. To translate a symbol value to a character such as a letter or numeral, an application must call the SymbolToCharacter function.

T

target

A window or writing area that receives pen input data.

trainer

An application that trains a recognizer. The trainer application may operate in the background, which is known as "passive training," or be activated by the user, which is "active training." See also recognizer, training.

training

The process used to update a recognizer's database so that it better reflects the individual style and writing characteristics of a particular user, thus increasing the recognizer's accuracy in handwriting interpretation. See also recognizer, trainer.


Programmer's Guide to Pen Services for Microsoft® Windows® 95 (Addendum)

This addendum to the Programmer's Guide to Pen Services for Microsoft Windows 95 contains updated information intended for international application development, particularly for Japanese pen-based applications. The changes listed in this addendum are divided by chapter and appendix.


Introduction

•	The last sentence of first paragraph should read as follows:

Following the reference, a number of appendixes provide information about the differences between versions 1.x and 2.0 of the Pen API, the 32-bit pen services, and more.


Organization

•	In the table describing the parts of the book, note that the title of Appendix A should refer to Versions 1.x and 2.0 rather than 1.0 and 2.0.


Books and Articles for Further Reading

•	The description of Ray Duncan's article, "Power Programming," in PC Magazine, should refer to version 1.x of the Pen API, not version 1.0.


Chapter 1  Overview of the Pen Application Programming Interface

•	Note the version change in the final introductory paragraph:

The architecture of version 2.0 of the Pen API remains similar to version 1.x, but its style and design differ considerably. Even if you have worked with version 1.x, you should read this chapter to understand the shift in programming philosophy in version 2.0.


Architecture of the Pen API

•	Note the version change in this paragraph from the "Windows" section.

In version 1.x of Pen Windows, the application was required to call RegisterPenApp in order to tell the system to convert all edit controls to handwriting edit (hedit) controls. With Pen API version 2.0, however, this is not necessary; all edit controls in applications are automatically converted. If the application is version-stamped as a Windows 95-based application, the conversion is automatic; otherwise, applications version-stamped as Windows 3.1-based applications require the call to RegisterPenApp that was required for Pen Windows, version 1.x.

•	Information about handwriting recognizers has been added to this paragraph in the "Recognizer" section.

Although many recognizers may be available to an application, only one serves as the system default recognizer. This is the recognizer that Windows automatically installs and calls by default. To use other recognizers, an application must first specifically install them. (For information about how to install multiple recognizers, see Chapter 5, "The Recognition Process.") The Microsoft Handwriting Recognizer (GRECO.DLL in US, RODAN.DLL in Japan) is provided as the default system recognizer on most OEM tablet installations of Microsoft pen services. GRECO.DLL recognizes all European letters, numerals, and punctuation, with emphasis on English, French, and German. RODAN.DLL recognizes Kanji, Kana, and other Japanese characters. An application can set up a different system recognizer by identifying the new file in the Windows registry. Appendix A explains how to set up a new default recognizer.

•	The following section was added at the end of the "Recognizer" section.


IME (Input Method Editor, for converting Kana to Kanji)

In Japanese Pen Services 1.1 (for Windows 3.1) special extensions to the system IME were required to convert handwritten characters to Kanji. For Windows 95, the IME has become standardized as a system DLL, with a new, extended API set. No special API set is required for use with handwriting input.

Although the IME shipped with Windows 3.1 for Pen may be used in Windows 95, it cannot be used to convert handwritten characters into Kanji. Some of the original 1.1 Pen APIs used for Kana to Kanji conversion have been updated, and remain backwardly compatible, and some new APIs have been added. For more information, see Chapter 10, "Pen Application Programming Interface Functions."


Chapter 2  Starting Out with System Defaults


Pen-Unaware Applications

•	This paragraph was added as the last in the section.

In Japan, these applets are combined into a single application called the Data Input Window (PENSKJ.EXE). In addition, an applet to set system recognition priorities (Tool Palette, PENTPJ.EXE) and an applet to train Japanese characters (Trainer, PENTRJ.EXE) are also provided.


Chapter 3  The Writing Process

•	The second introductory paragraph has been changed, as follows:

The writing process includes the various ways a user can write input to a pen-based application. These involve not only writing words and scribbling figures with a pen, but also gesturing with predefined pen movements and tapping an on-screen keyboard or Data Input Window.

•	The following Note has been added as the final item in "The hedit Control" section.

Note  The Microsoft Japanese Handwriting Recognizer (RODAN.DLL) does not support "free input" into hedit controls. An application should either use a BEDIT control or provide access to the Data Input Window—with a Lens button, for example.

•	Figure 3.1 has been renumbered as 3.1a, and a new piece of art (Figure 3.1b) has been added.

Japanese characters typically use large, separated boxes, often with a small cross at the center of each as a writing aid:

•	The version number in the first sentence of the third paragraph in the "bedit Control Messages"section has been changed.

The EM_LIMITTEXT message deserves special mention because it has changed slightly from version 1.x of the Pen API.

•	In the same section, a final bulleted item has been added to the ending list.

•	If limiting the text splits a double-byte character, the whole character is discarded.


The On-screen Keyboard

•	The following paragraph has been added after the second paragraph.

In Japan, the ShowKeyboard API has been replaced by the CorrectWritingEx function, which displays the Data Input Window.


Chapter 4  The Inking Process

•	Note the version change in this paragraph from the "Stroke Headers" section of "Data Within an HPENDATA Object."

As Figure 4.1 shows, a stroke header prefaces each collection of pen coordinates that make up a single stroke. Note that the structure of the stroke header in version 2.0 of the Pen API is different from the stroke header of version 1.x, since the stroke header now consists of a variable-length array instead of the STROKEINFO structure used in version 1.x. The current STROKEINFO structure is, nevertheless, compatible with version 1.x stroke headers.

•	Note the version change in the following Note from the "Creating an HPENDATA Object" section.

Note  	It is highly recommended that you use only the functions from version 2.0 of the Pen API. Although API from version 1.x are included for backward compatibility, it is not guaranteed that they will be supported in future versions of the Pen API.


Chapter 5  The Recognition Process


Using the HRC Functions

•	In the section "Creating the HRC," a bulleted item has been added following the third paragraph. Also, the paragraph after the bulleted list contains a change.

Either or both arguments can be NULL. Giving NULL as the first argument creates a new HRC with default settings. The next section, "Configuring the HRC," describes the default parameters, which include the following settings:

•	Recognition ends after a brief period of inactivity or when the user taps outside the target window.

•	The target window does not use guides.

•	The recognizer returns only its best guess without alternative guesses.

•	In Japan, recognition priority defaults to the settings specified by the Tool Palette applet, if it is active; otherwise the recognizer default setting is used.

Giving NULL as the second argument binds the HRC to the system default recognizer. Microsoft Windows sets the supplied file GRECO.DLL as the system default recognizer (RODAN.DLL in Japan), specified in the Microsoft Windows 95 system registry. Refer to Appendix A for an explanation of how to change the default to another recognizer.

•	The following information has been added immediately before the "Gesture" section.

ALC_KANJISYSMINIMUM	Minimum set of characters needed for Japanese system recognizer. Same as ALC_SYSMINIMUM | ALC_HIRAGANA | ALC_KATAKANA | ALC_JIS1. (Japanese version only.)
If an application does not specify alphabet configuration either through an existing HRC model or by calling the function SetBoxAlphabetHRC or SetAlphabetHRC, Windows assumes ALC_SYSMINIMUM (or ALC_KANJISYSMINIMUM) as the default alphabet configuration. For a complete list of ALC_ values, including Japanese-specific ones, see Chapter 13, "Pen Application Programming Interface Constants."


Alphabet Priority

The SetAlphabetPriorityHRC function provides a hint to the recognizer about which alphabet the user intends to use while inputting handwritten characters. Some written symbols have more than one interpretation, depending on alphabet (this is especially true in Japanese, which uses multiple alphabets). A crosslike character like the English plus sign (+) could also be interpreted as a lower case "t", katakana "na" or "me", or Kanji "juu" (the number 10), for example. Moreover, there are both SBCS and DBCS versions of English and katakana characters, corresponding to half-and full-pitch widths, so it's useful for a user or application to be able to pre-specify widths and character set preferences to minimize recognition errors.

Applications may use the SetAlphabetPriorityHRC API to set width and alphabet priority for HRC scope, or the SetPenAppFlags API to set width (DBCS or SBCS) preference for application scope. The Tool Palette application may be used to set system-wide priorities. Any priority set into an HRC supersedes application priority, which supersedes system priority as set (and if set) by the Tool Palette; in the event of not Tool Palette, the recognizer's default priority is used. The ALC_GLOBALPRIORITY bit will be set in all default HRCs, unless it is explicitly cleared with SetAlphabetPriorityHRC. To specify no priority, as opposed to default priority, an application should clear the ALC_GLOBALPRIORITY bit and set ALC_NOPRIORITY.

•	The following constant has been added to the "Gesture" section.

GST_KKCONVERT	Kana-Kanji convert. (Japanese version only)
•	In the "Unboxed Recognition" section, the following paragraphs have been changed.

An HRCRESULT object does not contain a normal text (ASCII for English) string representation of a guess. This is not possible since a guess might be made up of a gesture, shape, or other entity that has no text equivalent. Instead, an HRCRESULT contains a string of symbol values, which are 32-bit numbers type-defined as SYV.

Symbol values can represent geometric shapes, gestures, letters of the alphabet, Japanese kanji characters, musical notes, electronic symbols, or any other symbols defined by the recognizer. The Pen API provides the function SymbolToCharacter to convert the null-terminated symbol string in HRCRESULT to a normal text string.

•	In the section "Getting Results from the RCRESULT Structure," note the version change in the first sentence of this paragraph.

The RCRESULT structure applies only when an application calls either of the version 1.x recognition functions, Recognize or RecognizeData. In this case, the system sends a WM_RCRESULT message to the application. The wParam of this message contains a REC_ submessage that indicates why recognition ended. The lParam of WM_RCRESULT points to an RCRESULT structure, which contains all the results of the recognition.

•	Note the change to "text string" (formerly "ASCII string") in this paragraph.

The RCRESULT structure identifies the recognizer's "best guess," which is the guess in which the recognizer places the most confidence. With this information, an application can conveniently retrieve a text string of the best guess by calling SymbolToCharacter:


Chapter 6  Design Considerations


Recognition: Use and Misuse

•	In the section "bedit Is Better Than hedit," the following third paragraph has been added.

In Japan the bedit is almost always used for input, either directly, or via the Data Input Window.

•	In the section "Provide Easy Access to the On-screen Keyboard," the following sentence has been added after the first paragraph.

In Japan, this information is served by the Data Input Window.


Guidelines for Applications

•	The "Word Processor" section has been changed.

Although the pen does not reasonably serve to create a word-processor document for English or European languages, it can serve well for small editing tasks on an existing document, such as cut-and-paste operations, formatting changes, rewriting small amounts of text, and navigation (scrolling)....

•	In Far Eastern countries such as Japan, Korea, and China, where ideographic characters such as Kanji are used, a full-featured pen-input word processing application would greatly simplify input of text.


Chapter 7  A Sample Pen Application


Overview of PENAPP

•	In the first bulleted item following the third paragraph, the phrase "and it supports free input" has been added and the word "ANSI" has been deleted.


Window Procedures

•	The following code has been changed in the "InputWndProc" section.

#define   MAX_GUESS   5     // Maximum number of guesses

#define   MAX_CHAR    20    // Maximum number of characters per guess

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

HRCRESULT   vrghresult[MAX_GUESS];        // Array of results

SYV    vsyvSymbol[MAX_GUESS][MAX_CHAR];   // Array of symbol strings

int         vcSyv[MAX_GUESS];             // Array of string lengths

.

.

.

LRESULT CALLBACK      InputWndProc(

                           HWND hwnd,      // Window handle

                           UINT message,   // Message

                           WPARAM wParam,  // Varies

                           LPARAM lParam ) // Varies

{

   LONG            lRet = 0L;      // Initialize return code to FALSE

   HRC           hrc;              // HRC object

   HDC           hdc;

   PAINTSTRUCT   ps;

   DWORD         dwInfo;

   int           i, cGuess;

   switch (message)

   {

         .

         .

         .

case WM_LBUTTONDOWN:

//

// Two possibilities exist: user is using mouse or the pen.

// The latter case indicates the user is starting to write.

//

dwInfo = GetMessageExtraInfo();

if (IsPenEvent( message, dwInfo ))

{

    if (DoDefaultPenInput( vhwndInput, (UINT)dwInfo ) == PCMR_OK)

        lRet = TRUE;

    else

        lRet = DefWindowProc( hwnd, message, wParam, lParam );

}

break;

case WM_PENEVENT:

    switch (wParam)

    {

        case PE_GETPCMINFO:

        //

        // If using SREC recognizer, ensure session ends

        // on pen-up.

        //

        if (viMenuSel == miSample)

            ((LPPCMINFO) lParam)->dwPcm |= PCM_PENUP;

        lRet = DefWindowProc( hwnd, message, wParam, lParam );

        break;

case PE_BEGINDATA:

    //

    // Action based on current menu selection:

    //

    // 1) If currently using sample recognizer, create an HRC

    // for it and specify it in the TARGET structure pointed

    // to by lParam.  This tells DoDefaultPenInput to use

    // the sample recognizer rather than the system default.

    //

    // 2) If displaying mirror image of ink, create an

    // HPENDATA for it and specify it in the TARGET structure

    // pointed to by lParam.  This tells DoDefaultPenInput to

    // collect data into the HPENDATA block instead of

    // passing it to a recognizer.

    //

    // 3) If using the default recognizer, pass to DefWindowProc,

    // which sets the maximum number of guesses to 1 and may

    // or may not require any guide information. The Japanese

    // default recognizer (RODAN.DLL) does require a guide

    // for character recognition. The following code shows

    // how to access the HRC that DefWindowProc creates,

    // reset the number of guesses to MAX_GUESS, and set

    // up the client rectangle of the input window as a

    // single guide.

    //

    if (vhpendata)

    {

        DestroyPenData( vhpendata );

        vhpendata = 0;

    }

    switch (viMenuSel)

    {

        case miSample:

            hrc = CreateCompatibleHRC( NULL, vhrec );

            if (hrc)

            {

                ((LPTARGET) lParam)->dwData = hrc;

                lRet = LRET_HRC;

            }

            break;

        case miMirror:

            vhpendata = CreatePenData( NULL, 0,

                                    PDTS_HIENGLISH, 0 );

            if (vhpendata)

            {

                ((LPTARGET) lParam)->dwData = vhpendata;

                lRet = LRET_HPENDATA;

            }

            break;

        case miSystem:

            lRet = DefWindowProc( hwnd, message,

                                wParam, lParam );

            //

            // On return, lParam->dwData points to HRC.

            // Use it to reset max number of guesses.

            //

            SetMaxResultsHRC( ((LPTARGET) lParam)->dwData,

                            MAX_GUESS );

            {

            GUIDE guide;

            RECT rc;

            GetClientRect(vhwndInput, &rc);

            ClientToScreen(vhwndInput, (LPPOINT) &rc.left);

            ClientToScreen(vhwndInput,    (LPPOINT) &rc.right);

            guide.xOrigin = rc.left;

            guide.yOrigin = rc.top;

            guide.cxBox = rc.right - rc.left;

            guide.cyBox = rc.bottom - rc.top;

            guide.cxBase =    0;

            guide.cyBase =    guide.cyBox;

            guide.cHorzBox = 1;

            guide.cVertBox = 1;

            guide.cyMid = guide.cyBox / 2;

            SetGuideHRC(((LPTARGET) lParam)->dwData, &guide, 0);

            }

            break;

}

    break;

case PE_ENDDATA:

//

// DefWindowProc will destroy vhpendata, so if collecting

// mirror image, don't let DefWindowProc handle message

//

if (viMenuSel != miMirror)

        lRet = DefWindowProc( hwnd, message, wParam, lParam );

    break;

case PE_RESULT:

//

// At end of input, collect recognition results (if any)

// into symbol strings.  DoDefaultPenInput generates the

// PE_RESULT submessage only when using a recognizer.

// The lParam contains the HRC for the recognition process.

//

// NOTE:

//    Do not destroy HRC, even after getting results!

//    DefWindowProc takes care of destroying the object.

//

// Collect pen data for DrawRawData

vhpendata = CreatePenDataHRC( (HRC) lParam );

// Initialize array to zero

for (i = 0; i < MAX_GUESS; i++)

    vcSyv[i] = 0;

// Get number of guesses available

cGuess = GetResultsHRC( (HRC) lParam,

                    GRH_ALL,

                    (LPHRCRESULT) vrghresult,

                    MAX_GUESS );

// Get guesses (in vsyvSymbol) and their lengths (invcSyv)

if (cGuess != HRCR_ERROR)

    for (i = 0; i < cGuess; i++)

        vcSyv[i] = GetSymbolsHRCRESULT( vrghresult[i],

                            0,

                            (LPSYV) vsyvSymbol[i],

                            MAX_CHAR );

// Destroy the HRCRESULTS

for (i = 0; i < cGuess; i++)

    DestroyHRCRESULT(vrghresult[i]);

                break;

                .

                .

                .

        default:

            lRet = DefWindowProc( hwnd, message, wParam, lParam );

    }                    // End switch (message)

    return lRet;

}

•	In the "DisplayGuesses" section of the "InfoWndProc" section, the following code has changed.

VOID        DisplayGuesses( HDC hdc )                // DC handle

{

    TEXTMETRIC  tm;

    int            nX, nY;                            // Text coords

        .

        .

        .

    for (i = 0; i < MAX_GUESS; i++)

    {

        if (vcSyv[i] > 0)

        {

            SymbolToCharacter( (LPSYV) vsyvSymbol[i],

                            vcSyv[i],

                            (LPSTR) szText,

                            (LPINT) &cChar );

            for (nLen = 0; cChar > 0; cChar--)

                nLen += IsDBCSLeadByte(*(szText + nLen)) ? 2 : 1;

            TextOut( hdc, nX, nY, (LPSTR) szText, nLen );

            nY += tm.tmExternalLeading + tm.tmHeight;

        }

    }

}


Chapter 8  Writing a Recognizer


How a Recognizer Works

•	Version information has been changed in the first paragraph.

The Pen API specifies the following functions for initializing, modifying, and closing down the recognizer. Note that, in version 2.0 of the Pen API, the required function ConfigRecognizer handles all initialization and configuration tasks. The other initialization functions are obsolete in version 2.0 and should only be included in a recognizer if it is expected to work with older applications that work with a version 1.x recognizer (see the Microsoft Pen Windows, version 1.x documentation for descriptions of these functions).

Note that the table following the first paragraph should refer to version 1.x rather than 1.0.

•	In the "HRCRESULT Section," note that the GetAlternateWordsHRCRESULT function is not supported.

•	In the "Training" section, note the version changes in the following paragraph and in the table it introduces.

The following table lists the functions that a recognizer with training capabilities can export. Only TrainHREC is used by version 2.0 Pen API. The other functions are obsolete in version 2.0 and should be included in a recognizer only if it is expected to work with older applications that work with a version 1.x recognizer (see the Microsoft Pen Windows, version 1.x documentation for descriptions of these functions).

•	In the "Processing Raw Data" section of the "Interpreting Input" section, note the additional .DLL in the first sentence of the second paragraph.

The Microsoft Handwriting Recognizer (GRECO.DLL or RODAN.DLL) processes only coordinate data.

•	In the section "Segmentation of Symbols," following Figure 8.1, the final sentence has been changed.

The Pen API places few restrictions on the recognizer. At a minimum, however, a default recognizer that supports free (unboxed) input must be able to recognize discrete characters because many applications do not use boxed input.

•	In the "Results Messages" section of the "Returning Results" section, note the version change in the second bulleted item.

•	In the section "The RCRESULT Structure" in the "Returning Results" section, the note should refer to version 1.x, not 1.0. Also in this section, the "Location and Position of the Input" section, the final sentence in the first bulleted item has been changed.

The Microsoft Handwriting Recognizer (GRECO.DLL or RODAN.DLL) sets nBaseLine to 0.


Writing a Recognizer

•	In the "DestroyHRC" section, the code has been changed.

int WINAPI    DestroyHRC( HRC hrc )

{

    LPHRCinternal  lphrc = (LPHRCinternal) hrc;  // Pointer to HRC

    if (GlobalUnlock( lphrc->hglobal ) || GlobalFree(lphrc->hglobal))

        return HRCR_ERROR;

    else

        return HRCR_OK;

}


Chapter 9  Summary of the Pen Application Programming Interface


Pen API Functions

•	Note the version change in the table of function categories.

Obsolete	Obsolete functions of version 1.x maintained by version 2.0 only for compatibility reasons.
•	In the "List of Pen API Functions" section, the descriptions of several functions have been changed.

ShowKeyboard	Displays or hides the on-screen keyboard. (Not supported in Japan)
GetAlternateWordsHRCRESULT	Gets alternative guesses made by a recognizer. (Not supported in Japan)
CorrectWriting	Displays lens or Correct Text dialog box to allow user to correct text. (In Japan, this is wrapper for CorrectWritingEx)
KKConvert	Activates the Kana-to-Kanji converter. (Japanese version only.)
StartPenInput	Begins collecting into an internal buffer ink data generated by the moving pen. See also the descriptions of StartInking and DoDefaultPenInput.
Recognize	Begins recognition for a version 1.x recognizer.
RecognizeData	Delayed recognition for a version 1.x recognizer.
SetRecogHook	Installs and removes a recognition hook in version 1.x. Superseded by SetResultsHookHREC.


Pen API Structures

•	In the "List of Pen API Structures" section, the descriptions of several structures have been changed.

RC	Various information about the recognition context used by version 1.x recognition functions.
RCRESULT	Results of recognition initiated through a version 1.x recognition function.


Pen API Constants

•	The following items have been either redescribed or added to the table of constants.

CWX_	Options for CorrectWritingEx.
CWXA_	Options for CorrectWritingEx.
CWXK_	Options for CorrectWritingEx.
CWXKS_	Options for CorrectWritingEx.
CWXR_	Return types for CorrectWritingEx
GPR_	Options for GetPenResource.
REC_	Return codes from a version 1.x recognizer.


Chapter 10  Pen Application Programming
Interface Functions

•	In the second paragraph, the phrase "for example, 1.0 or 2.0" should read "for example, 1.x or 2.0."

•	The CWR_KKCONVERT constant has been removed from the dwFlags parameter of the CorrectWriting function. Also, in the same function, the final sentence has been changed as follows:

Note that in the Japanese version, CorrectWriting is supported but internally calls CorrectWritingEx, which opens a Data Input Window.

•	The first sentence of the CorrectWritingEx funtion has been changed:

Sends text to the Japanese Data Input Window to allow the user to edit text. (Japanese version only.)

In the description of the lpText parameter of CorrectWritingEx, the phrase "and gets modified by the user" has been appended to the second sentence.

•	In the description of the cbText parameter, the second sentence should read as follows:

If the source of the text is an edit control that is constrained by EM_LIMITTEXT, cbText should be set to the limiting size plus one.

•	In the Example of CompactWritingEx, the second-to-last code block has been changed.

// don't update most-recently used settings for this one-shot:

cwx.wApplyFlags |= CWXA_NOUPDATEMRU;

cwx.ixkb = CWXK_QWERTY;

cwx.rgState[CWXK_QWERTY-CWXK_FIRST] = CWXKS_ROMAHAN;

cwx.dwFlags = CWX_NOTOOLTIPS | CWX_TOPMOST;    // no distractions

•	In the GetHotspotsHRCRESULT function, the final sentence of the first Comments paragraph has been changed.

The Microsoft Handwriting Recognizer (GRECO.DLL in US, RODAN.DLL in Japan), supports this function for gesture symbols only.

•	In the GetPenAppFlags function, the three references to the RegisterPenApp function have been changed to SetPenAppFlags.

•	The GetPenResource function has been added.


GetPenResource [New - Windows 95]
GetPenResource

[New - Windows 95]

The GetPenResource function retrieves a copy of a pen services resource. (Japanese version only.)

HANDLE GetPenResource( WPARAM wParam )

Parameters

wParam

Specifies the pen services resource for which to retrieve a handle. This may be one of the following:

Constant	Description
GPR_CURSPEN	Standard pen cursor.
GPR_CURSCOPY	Copy cursor.
GPR_CURSUNKNOWN	Unknown cursor.
GPR_CURSERASE	Erase cursor.
GPR_BMCRMONO	Monochrome Return bitmap.
GPR_BMLFMONO	Monochrome LineFeed bitmap.
GPR_BMTABMONO	Monochrome Tab bitmap.
GPR_BMDELETE	Delete bitmap.
GPR_BMLENSBTN	Lens buttonface bitmap.
GPR_BMHSPMONO	Hankaku space bitmap (Japanese version only).
GPR_BMZSPMONO	Zenkaku space bitmap (Japanese version only).
Comments

An application can use this function to get a copy of a cursor or bitmap used by pen services. It is the application's responsibility to destroy the object by calling either the DestroyCursor or DeleteObject Windows API.

Return Value

•	This function returns a handle to an object, depending on the index specified by wParam if successful. Otherwise the return value is NULL.

•	The following sentence has been added to the Comments section of the SetPenAppFlags function.

If both RPA_DBCSPRIORITY and RPA_SBCSPRIORITY are specified, the RPA_SBCSPRIORITY is ignored.

•	In the TrainHREC function, the following sentence has been appended to the Comments section.

Training gestures depends on the recognizer. The Microsoft Handwriting Recognizer (GRECO.DLL in US, RODAN.DLL in Japan) does not support training for gestures.


Chapter 11  Pen Application Programming
Interface Structures

•	Note that throughout this chapter structures marked as version 1.0 should be marked as version 1.x.

•	The final sentence of the introductory paragraph has been changed.

The entry heading identifies the Pen API version, such as 1.x or 2.0, that supports the structure.

•	In the CWX structure, the description of the CWXA_CONTEXT constant has changed.

Constant	Description
CWXA_CONTEXT	Use the dwFlags member to specify context. (topmost, tooltips, period, comma)
•	Two CWX_ constant descriptions have been changed.

Constant	Description
CWX_EPERIOD	Specifies that the English period is to be used on some keys on the Data Input Window keypads. The Japanese period is used by default.
CWX_ECOMMA	Specifies that the English comma is to be used on some keys on the Data Input Window keypads. The Japanese comma is used by default.
•	The CWXK_ROMAJI constant has been removed from the list of CWXK_ constants.

•	The description of the CWXK_KANJI constant should read as follows:

Kanji finder, which provides a method of specifying a Kanji character based on its strokes.

•	The paragraph describing the rgState member of the CWX structure has been changed. The constant descriptions have also changed.

…and this member is ignored. The zero-based order is: 50-On Keyboard, QWERTY Keyboard, Numeric Keyboard, Stroke/Radical Finder, Code Finder, and Yomi Finder. On return, this member contains the updated states. Each element of the array may be CWXKS_DEFAULT, which causes the existing saved state to be used, or one of the following constant values, depending on the keyboard:

Constant	Description	Applicable Keyboards
CWXKS_HAN	Set Hankaku (single-byte) state.	Numeric
CWXKS_ZEN	Set Zenkaku (double-byte) state.	Numeric
CWXKS_ROMAHAN	Set Hankaku Romaji state.	QWERTY
CWXKS_ROMAZEN	Set Zenkaku Romaji .	QWERTY
CWXKS_HIRAZEN	Set Hiragana state.	50-On, QWERTY
CWXKS_KATAHAN	Set Hankaku Katakana state.	50-On, QWERTY
CWXKS_KATAZEN	Set Zenkaku Katakana state.	50-On, QWERTY
•	The SKBINFO structure is not available in the Japanese version of the Pen API.


Chapter 12  Pen Application Programming
Interface Messages


HE_KKCONVERT [New - Windows 95]
HE_KKCONVERT

[New - Windows 95]

Starts Kana-to-Kanji conversion. Submessage of WM_PENCTL. (Japanese version only.)

Parameters

wParam

HE_KKCONVERT.

lParam

Must be one of the following values:

Value	Meaning
HEKK_DEFAULT	The first time the conversion is specified, the selected or marked character string is replaced with the conversion result. The behavior for successive calls depends on the IME. For example, a candidate list may appear.
HEKK_CONVERT	The selected or marked character string is replaced with the conversion result; the conversion candidate list doesn't appear regardless of how many times conversion has been specified.
HEKK_CANDIDATE	The selected or marked character string is replaced with the conversion result; this causes the conversion candidate list to appear.
HEKK_DBCSCHAR	The SBCS characters (0x20 − 0x7E, 0xA1 − 0xDF) are replaced by their DBCS equivalents.
HEKK_SBCSCHAR	The DBCS characters in the selected or marked character string that have equivalent SBCS representations are replaced by their equivalent SBCS characters.
HEKK_HIRAGANA	The katakana characters (DBCS or SBCS) in the selected or marked character string are replaced with their hiragana equivalents.
HEKK_KATAKANA	The hiragana characters in the selected or marked character string are replaced with their DBCS katakana representation.
Return Value

Returns TRUE if there are no errors; otherwise, returns FALSE:

Comments

In this message, "marked character string" indicates the string that is marked for conversion. Text marked for conversion is indicated by a different selection color than that used for normal text selection in a standard text edit control. Available for bedits only.


HE_PUTCONVERTCHAR [New - Windows 95]
HE_PUTCONVERTCHAR

[New - Windows 95]

Sends a character to the control and marks it for conversion. Submessage of WM_PENCTL. (Japanese version only.)

Parameters

wParam

HE_PUTCONVERTCHAR.

lParam

The low-order word contains the character code, which can be an SBCS or DBCS character.

Return Value

Returns TRUE if there are no errors; otherwise, returns FALSE.

Comments

Posting this message is similar to posting a WM_CHAR message to a bedit control, with the exceptions that the posted character also acquires the attribute of being a character marked for conversion in the Input Method Editor, and DBCS characters may be specified in the LOWORD of lParam. This submessage is available for bedits only.


WM_PENMISC [New - Windows 95]
WM_PENMISC

[New - Windows 95]

•	The PMSC_KKCTLENABLE, PMSC_PENUICHANGE, and PMSC_SUBINPCHANGE subfunctions have been removed.


Chapter 13  Pen Application Programming
Interface Constants


ALC_Alphabet Codes

Constant	Description
ALC_KANJISYSMINIMUM	Minimum set of characters needed for Japanese system recognizer. Same as ALC_SYSMINIMUM | ALC_HIRAGANA | ALC_KATAKANA | ALC_JIS1. (Japanese version only.)


RCD_ Writing Direction

•	Note the Note: The RCD_ constants are provided only for compatibility with version 1.x the Pen API and will not be supported in future versions.


RCP_ User Preferences

•	Note the Note:  RCP_ constants are provided only for compatibility with version 1.x of the Pen API and will not be supported in future versions.


RCRT_ Results Type

•	The RCRT_ALREADYPROCESSED constant description has been changed.

Constant	Description
RCRT_DEFAULT	Normal return type.


Appendix A  Differences Between Versions 1.x and 2.0 of the Pen Application Programming Interface

Note the title change, from version 1.0 to 1.x. This change is reflected throughout this chapter and will not be mentioned here unless text has otherwise changed.


Improvements to the bedit Control

•	The final paragraph of this section has been changed.

Because Japanese and other Far Eastern languages may use double-byte characters, an application must specify double the number of bytes for EM_LIMITTEXT than applications expecting only single-byte characters (or halve the number of boxes). Note that even without explicitly limiting text with EM_LIMITTEXT, input into single-line, nonscrollable BEDIT controls is limited to the number of boxes available. For example, a 3-box postal code BEDIT allows only three characters, be they SBCS or DBCS. For more information about EM_LIMITTEXT, see "The bedit Control" in Chapter 3, "The Writing Process."

•	In the section "The RC Structure," the table following the second paragraph has been changed.

RC member	Equivalent service in Pen API 2.0
lpUser	GetPenMiscInfo with PMI_USER. Cannot set new user in version 2.0.


Gestures

•	The gesture table has been changed.

Gesture	Name	Action
	T-circle	Tab
or    or	K-circle  or  symbol-circle (drawin Right to Left)	Kana to Kanji conversion


Action Handles

•	A sentence has been added at the end of this section.

In the Japanese version, action handles can be disabled with the Control Panel.


On-Screen Keyboard

•	A sentence has been added at the end of this section.

In the Japanese version, ShowKeyboard is not available. Rather, CorrectWritingEx allows access to the Data Input Window.


Appendix B  Using the 32-Bit Pen Application Programming Interface


32-Bit Functions

•	The KKConvert function has been added to the list of functions supported by the 32-bit Pen API.


Legal Information

Information in this document is subject to change without notice. Companies, names, and data used in examples herein are fictitious unless otherwise noted. No part of this manual may be reproduced or transmitted in any form or by any means, electronic or mechanical, for any purpose without the express written permission of Microsoft Corporation.

Microsoft may have patents or pending patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in this document. The furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other intellectual property rights except as expressly provided in any written license agreement from Microsoft.

Copyright (C) 1992-1995 Microsoft Corporation. All rights reserved.

Microsoft, MS, MS-DOS, Win32, Win32s, and Windows are registered trademarks, and Windows NT is a trademark of Microsoft Corporation.

U.S. Patent No. 4955066

Portions of this documentation are provided under license from Digital Equipment Corporation. Copyright (C)  1990, 1992 Digital Equipment Corporation. All rights reserved.

DEC is a registered trademark and DECnet and Pathworks are trademarks of Digital Equipment Corporation.


Introduction
Introduction to RPC

Microsoft® Remote Procedure Call (RPC) for the C and C++ programming languages is designed to help meet the needs of developers working on the next generation of software for the MS-DOS®, Microsoft Windows®, and Microsoft Windows NT™ family of operating systems.

Microsoft RPC represents the convergence of three powerful programming models: the familiar model of developing C applications by writing procedures and libraries; the model that uses powerful computers as network servers to perform specific tasks for their clients; and the client-server model, in which the client usually manages the user interface while the server handles data storage, queries, and manipulation.

This section explains the convergence of these three powerful models in distributed computing, which delivers the ability to share computational power among the computers on a network. This section also describes the industry standard for RPC and provides an overview of Microsoft RPC components and operation.


The Programming Model

In the early days of computing, each program was written as a large monolithic chunk, filled with goto statements. Each program had to manage its own input and output to different hardware devices. As programming matured as a discipline, this monolithic code was organized into procedures, and commonly used procedures were packed in libraries for sharing and reuse. Today's RPC is the next step in the development of procedure libraries. Now procedure libraries can run on other, remote, computers.

The C programming language supports procedure-oriented programming. In C, the main procedure relates to all other procedures as black boxes. The main procedure cannot find out how procedures A, B, and X, for example, do their work. The main procedure only calls another procedure; it has no information about how that procedure is implemented.

Procedure-oriented programming languages provide simple mechanisms for specifying and writing procedures. For example, the ANSI standard C function prototype is a construct used to specify the name of a procedure, the type of the result it returns (if any), and the number, sequence, and type of its parameters. Using the function prototype is a formal way to specify an interface between procedures.

In this guide, the term procedure is synonymous with the terms subroutine and subprocedure and refers to any sequence of computer instructions that accomplishes a functional purpose. In this documentation, the term function refers to a procedure that returns a value.

Related procedures are often grouped in libraries. For example, a procedure library can include a set of procedures that perform tasks common to a single domain, such as floating-point math operations, formatted input and output, and network functions.

The procedure library is another level of packaging that makes it easy to develop applications. Procedure libraries can be shared among many applications. Libraries developed in C are usually accompanied by header files. Each program that uses the library is compiled with the header files that formally define the interface to the library's procedures.

The Microsoft RPC tools represent a general approach that allows procedure libraries written in C to run on other computers. In fact, an application can link with libraries implemented using RPC without indicating to the user that it is using RPC.


The Client-Server Model

Client-server architecture is an effective and popular design for distributed applications. In the client-server model, an application is split into two parts: a front-end client that presents information to the user, and a back-end server that stores, retrieves, and manipulates data and generally handles the bulk of the computing tasks for the client. In this model, the server is usually a more powerful computer than the client and serves as a central data store for many client computers, making the system easy to administer.

Typical examples of client-server applications include shared databases, remote file servers, and remote printer servers. The following figure illustrates the client-server model.

Network systems support the development of client-server applications through an interprocess communication (IPC) facility that allows the client and server to communicate and coordinate their work. You can use NetBIOS NCBs (network control blocks), mailslots, or named pipes to transfer information between two or more computers.

For example, the client can use an IPC mechanism to send an opcode and data to the server requesting that a particular procedure be called. The server receives and decodes the request, then calls the appropriate procedure. The server performs all the computations needed to satisfy the request, then returns the result to the client. Client-server applications are usually designed to minimize the amount of data transmitted over the network.

Using NetBIOS, mailslots, or named pipes to implement interprocess communication means learning specific details relating to network communication. Each application must manage the network-specific conditions. To write this network-specific level of code:

•	You must learn details relating to network communications and how to handle error conditions.

•	When the network includes different kinds of computers, you must translate data to different internal formats.

•	You must support communications using multiple transport interfaces.

In addition to all the possible errors that can occur on a single computer, the network has its own error conditions. For example, a connection can be lost, a server can disappear from the network, the network security service can deny access to system resources, and users can compete for and tie up system resources. Because the state of the network is always changing, an application can fail in new and interesting ways that are difficult to reproduce. For these reasons, each application must rigorously handle all possible error conditions.

When you write a client-server application, you must provide the layer of code that manages network communication. The advantage of using Microsoft RPC is that the RPC tools provide this layer for you. RPC nearly eliminates the need to write network-specific code, making it easier to develop distributed applications.

Using the remote procedure call model, RPC tools manage many of the details relating to network protocols and communication. This allows you to focus on the details of the application rather than the details of the network.


The Compute-Server Model

Networking software for personal computers has been built on the model of a powerful computer, the server, that provides specialized services to workstations, or client computers. In this model, servers are designated as file servers, print servers, or communications (modem) servers, depending on whether they are assigned to file sharing or are connected to printers or modems.

RPC represents an evolutionary step in this model. In addition to its traditional roles, a server using RPC can be designated as a computational server, or compute server. In this role, the server shares its own computational power with other computers on the network. A workstation can ask the compute server to perform computations and return the results. The client not only uses files and printers, it also uses the central processing units of other computers.


The OSF Standards for RPC

The design and technology behind Microsoft RPC is just one part of a complete environment for distributed computing defined by the Open Software Foundation (OSF), a consortium of companies formed to define that environment. The OSF requests proposals for standards, accepts comments on the proposals, votes on whether to accept the standards, and promulgates them. The components of the OSF distributed computing environment (DCE) are shown in the following figure.

In selecting the RPC standard, the OSF cited the following rationale:

•	The three most important properties of a remote procedure call are simplicity, transparency, and performance.

•	The selected RPC model adheres to the local procedure model as closely as possible. This requirement minimizes the amount of time developers spend learning the new environment.

•	The selected RPC model permits interoperability; its core protocol is well defined and can't be modified by the user.

•	The selected RPC model allows applications to remain independent of the transport and protocol on which they run, while supporting a variety of transports and protocols.

•	The selected RPC model can be easily integrated with other components of the DCE.

The OSF DCE remote procedure call standards define not only the overall approach but the language and the specific protocols to use for communications between computers, down to the format of data as it is transmitted over the network.

Microsoft's implementation of RPC is compatible with the OSF standard with minor differences. Client or server applications written using Microsoft RPC will interoperate with any DCE RPC client or server whose run-time libraries run over a supported protocol. For a list of supported protocols, see Building RPC Applications.


Microsoft RPC Components

The Microsoft RPC product includes the following major components:

•	MIDL compiler

•	Run-time libraries and header files

•	Transport interface modules

•	Name service provider

•	Endpoint supply service

In the RPC model, you can formally specify an interface to the remote procedures using a language designed for this purpose. This language is called the Interface Definition Language, or IDL. The Microsoft implementation of this language is called the Microsoft Interface Definition Language, or MIDL.

After you create an interface, you must pass it through the MIDL compiler. The MIDL compiler generates the stubs that translate local procedure calls into remote procedure calls. Stubs are placeholder functions that make the calls to the run-time library functions that manage the remote procedure call. The advantage of this approach is that the network becomes almost completely transparent to your distributed application. Your client program calls what appear to be local procedures; the work of turning them into remote calls is done for you automatically. All the code that translates data, accesses the network, and retrieves results is generated for you by the MIDL compiler, and is invisible to your application.


How RPC Works

The RPC tools make it look to users as though a client directly calls a procedure located in a remote server program. The client and server each have their own address spaces; that is, each has its own memory resource that is allocated to data used by the procedure. The following figure illustrates the RPC architecture.

As the illustration shows, the client application calls a local stub procedure instead of the actual code implementing the procedure. Stubs are compiled and linked with the client application. Instead of containing the actual code that implements the remote procedure, the client stub code:

•	Retrieves the required parameters from the client address space.

•	Translates the parameters as needed into a standard network data representation (NDR) format for transmission over the network.

•	Calls functions in the RPC client run-time library to send the request and its parameters to the server.

The server performs the following steps to call the remote procedure:

•	The server RPC run-time library functions accept the request and call the server stub procedure.

•	The server stub retrieves the parameters from the network buffer and converts them from the network transmission format to the format the server needs.

•	The server stub calls the actual procedure on the server.

The remote procedure runs, perhaps generating output parameters and a return value. When the remote procedure is complete, a similar sequence of steps returns the data to the client:

•	The remote procedure returns its data to the server stub.

•	The server stub converts output parameters to the format required for transmission over the network and returns them to the RPC run-time library functions.

•	The server RPC run-time library functions transmit the data on the network to the client computer.

The client completes the process by accepting the data over the network and returning it to the calling function:

•	The client RPC run-time library receives the remote-procedure return values and returns them to the client stub.

•	The client stub converts the data from its network data representation to the format used by the client computer. The stub writes data into the client memory and returns the result to the calling program on the client.

•	The calling procedure continues as if the procedure had been called on the same computer.

For Microsoft Windows and Microsoft Windows NT, the run-time libraries are provided in two parts: an import library, which is linked with the application; and the RPC run-time library, which is implemented as a dynamic-link library (DLL).

The server application contains calls to the server run-time library functions that register the server's interface and allow the server to accept remote procedure calls. The server application also contains the application-specific remote procedures that are called by the client applications.


Summary
Summary: RPC Extends Client-Server Computing

Microsoft RPC is an evolution of the procedural programming model familiar to all developers. It also represents a new category of specialized server and extends the model of client-server computing.

Microsoft RPC is a tool developers use to leverage the power of the single personal computer by increasing its computational capacity far beyond its own resources. With RPC, you can harness all of the CPU horsepower available on the network.

Microsoft RPC allows a process running in one address space to make a procedure call that will be executed in another address space. The call looks like a standard local procedure call but is actually made to a stub that interacts with the run-time library and performs all the steps necessary to execute the call in the remote address space.

As a tool for creating distributed applications, Microsoft RPC provides the following benefits:

•	The RPC programming model is already familiar. You can easily turn functions into remote procedures, which simplifies the development and test cycles.

•	RPC hides many details of the network interface from the developer. You don't have to understand specific network functions or low-level network protocols to implement powerful distributed applications.

•	RPC solves the data-translation problems that crop up in heterogeneous networks; individual applications can ignore this problem.

•	The RPC approach is scalable. As a network grows, applications can be distributed to more than one computer on the network.

•	The RPC model is an industry standard. The Microsoft implementation is compatible with both client and server.


About This Guide

This guide explains the Microsoft RPC programming model, standards, and tools in detail.

A Tutorial Introduction provides an overview of the development of a small distributed application. This example demonstrates all the steps in developing a distributed application, the tools you use, and the components that make up the executable programs.

The following topics deal with the underlying mechanisms that pass data from the calling application to the remote procedure. Data and Language Features demonstrates the use of standard data types. Arrays and Pointers explains what happens when pointers are used as parameters. Binding and Handles describes the binding handle, the data structure that allows the developer to bind the calling application to the remote procedure.

Memory Management offers ideas about how to manage memory on the client and server when performing remote procedure calls. Using Encoding Services describes the methods for encoding or decoding data.

The IDL and ACF Files and Run-time RPC Functions describe the Microsoft RPC tools: the Microsoft Interface Definition Language and compiler and the run-time libraries. "The IDL and ACF Files" describes the IDL and ACF files used to specify the interface to the remote procedure call and the MIDL compiler switches that control how these files are processed. "Run-time RPC Functions" describes the functions in the run-time library that applications use to manage their own client and server binding.

Building RPC Applications provides examples of how to build distributed applications on several operating system platforms.

The following topics present the material related to RPC in alphabetical order. The MIDL Reference contains a reference for each keyword in MIDL and the ACF, as well as for important language productions and concepts. The MIDL Command-Line Reference alphabetizes information on each command-line switch and switch option recognized by the MIDL compiler. RPC Data Types and Structures defines the constants, data types, and data structures used by the RPC functions. The Function Reference lists those functions.

Installing RPC discusses installing RPC in the MS-DOS, Microsoft Windows 3.x, and Microsoft Windows NT environments.

Also included are Error Codes, and MIDL Compiler Errors and Warnings.

This guide offers general information about how to use the Microsoft RPC tools to develop a distributed application. For information about Microsoft Windows, see the Microsoft Windows software development kit. For information about the Microsoft Windows NT operating system, see the Microsoft Windows NT operating system software development kit. For information about Microsoft C/C++ version 7.0, see your C programming documentation.


A Tutorial Introduction

This introduction to RPC begins with a very simple application and focuses on the differences between stand-alone C programs and distributed applications that use RPC. This sample application is not meant to be an exhaustive demonstration of the capabilities of RPC. Succeeding topics explore the rich features of the Microsoft Interface Definition Language (MIDL) and offer more detailed examples. This introductory program provides a working example that quickly demonstrates distributed applications.

The application described in this tutorial prints the words "Hello, world." The client computer makes a remote procedure call to the server and the server prints the words to its standard output.

This distributed application requires two distinct executable programs — one for the client and one for the server. Like other C programs, these client and server executables will be based on C-language source files written by the developer. Unlike most C programs, however, some of the C-language source files are automatically generated by an RPC tool: the MIDL compiler.

To make this a distributed application, you will create a file that includes a function prototype for the remote procedure. The prototype is associated with attributes that describe how the data associated with the remote procedure is to be transmitted over the network. Attributes, data, and function prototypes describe the interface between the client and server. The interface is associated with a unique identifier that distinguishes this interface from all others.

You will create a file that declares a variable, the binding handle, that the client and server use to represent their logical connection through this interface.

You will also write client and server main programs that call RPC run-time functions to establish the interface.

Don't worry if you don't understand every attribute, file, and concept mentioned in this section. Successive sections discuss all the RPC components and concepts in greater detail. The purpose of this section is to provide a quick overview of the entire territory. As you build the application, you will see all the files and all the procedural steps for even the most complex distributed application.


The Client Application

A stand-alone application that can be executed on a single computer consists of a call to a single function, called HelloProc in the following example:

/* file: helloc.c (stand-alone) */

void HelloProc(unsigned char * pszString);

void main(void)

{

unsigned char * pszString = "Hello, world";

    HelloProc(pszString);

}

The HelloProc function calls the C library function printf to display the text "Hello, world":

/* file: hellop.c */

#include <stdio.h>

void HelloProc(unsigned char * pszString)

{

    printf("%s\n", pszString);

}

HelloProc is defined in its own source file, HELLOP.C, so it can be compiled and linked with either a stand-alone application or the distributed application.


The Interface Definition Language File

The first step in creating a distributed application is to provide a way for the client and the server to find each other and communicate over the network by defining a formal interface using the Microsoft Interface Definition Language (MIDL). The interface consists of data types, function prototypes, attributes, and interface information.

Interface information is formally defined in its own file, which takes the extension IDL. For convenience, this example uses the same name, HELLO, for both the IDL file and the C-language file. You can also use separate names for the two files:

/* file: hello.idl */

[ uuid (6B29FC40-CA47-1067-B31D-00DD010662DA),

  version(1.0)

]

interface hello

{

void HelloProc([in, string] unsigned char * pszString);

}

The IDL file's constructs differ from constructs in C-language source files, but they are easy to use once you become familiar with them. The information provided in the IDL file replaces an enormous amount of network programming and is virtually all you need to coordinate the client and server applications.

The IDL file has two parts: the interface header and the interface body. The interface header includes information about the interface as a whole, such as its identifier and version number. It consists of the material enclosed in square brackets and ends with the keyword interface and the interface name. The interface header in this example includes the keywords uuid, version, and interface. The interface body contains data and function prototypes. The interface body is enclosed in braces.

The UUID is the universally unique identifier, a string of five groups of hexadecimal digits separated by hyphens. The five groups contain eight digits, four digits, four digits, four digits, and 12 digits, respectively. For example, "6B29FC40-CA47-1067-B31D-00DD010662DA" is a valid UUID. In the Microsoft Windows NT environment the UUID is also known as a GUID, or globally unique identifier. The interface UUID is generated from a utility program, uuidgen, that generates unique identifiers in the required format.

The interface body contains C-like data-type definitions and function prototypes that are augmented with attributes. Attributes appear in square brackets. The attributes describe how the data is to be transmitted over the network.

The interface body in this sample application contains the function prototype HelloProc. The single argument, pszString, is designated as an in parameter, which means it is passed from the client to the server. Parameters can also be designated as out, which are passed from the server to the client, or in, out, which are passed in both directions. These attributes tell the run-time libraries how to pass data between the client and server. The string attribute indicates that the parameter is a special case of character array.

Compile the IDL file using the MIDL compiler. The MIDL compiler generates C-language client and server stub files and a header file. The header file produced from the interface definition file HELLO.IDL is named, by default, HELLO.H. The generated header file includes the header file RPC.H and function prototypes from the IDL file. The header file RPC.H defines data and functions used by the generated header file:

/* file: hello.h (fragment) */

#include <rpc.h>

void HelloProc(unsigned char * pszString);

Rather than duplicate these function prototypes, the client source should include the header file that is generated from the IDL file:

/* file: helloc.c (distributed version) */

#include <stdio.h>

#include "hello.h"    // header file generated by the MIDL compiler

void main(void)

{

    char * pszString = "Hello, world";

    ...

    HelloProc(pszString);

    ...

}

The IDL file defines the network contract between the client and server. The network contract is a firm agreement about the sequence, types, and sizes of data that are to be passed over the network.


The Application Configuration File

As specified by the distributed computing environment (DCE) standard, you must also define an application configuration file, or ACF, that is processed by the MIDL compiler with the IDL file. The ACF contains RPC data and attributes that do not relate to transmitted data.

For example, a data object called the binding handle represents the connection between the client application and the server application. The client calls run-time functions to establish the valid binding handle; the handle can then be used by the run-time functions whenever the client application calls a remote procedure. The binding handle is not part of the function prototype and is not transmitted over the network, so it is defined in the ACF.

The ACF for the "Hello, world" program appears as follows:

/* file: hello.acf */

[ implicit_handle(handle_t hello_IfHandle)

]interface hello

{

}

The format of the ACF is similar to that of the IDL file. Attributes appear in square brackets, followed by the keyword interface and the interface name. The interface name specified in the ACF must match the interface name specified in the IDL file.

The ACF contains the attribute implicit_handle to indicate that the handle is a global variable that is accessed by the functions in the run-time library. The implicit_handle keyword is associated with the handle type and the handle name; in this example, the handle is of the MIDL data type handle_t. The handle name hello_IfHandle specified in the ACF is defined in the generated header file HELLO.H. This handle will be used in calls to the client run-time library functions.


Adding Functions RPC Requires

The RPC run-time libraries often call user-supplied functions. This approach allows the MIDL compiler to generate C code automatically while still allowing you to control how operations themselves are performed.

The user-supplied functions include functions with fixed names and names that are based on IDL-file attributes or data types. For example, whenever the run-time libraries allocate or free memory, they call the user-supplied functions midl_user_allocate and midl_user_free.

The C run-time libraries in the "Hello, world" example call the memory-allocation function midl_user_allocate and the memory-free function midl_user_free. This sample application doesn't have complex memory-management requirements, so the functions are simply implemented in terms of the C-library functions malloc and free:

void __RPC_FAR * __RPC_USER midl_user_allocate(size_t len)

{

    return(malloc(len));

}

void __RPC_USER midl_user_free(void __RPC_FAR * ptr)

{

    free(ptr);

}


Calling the Client API Functions
Calling the Client Functions

RPC supports two types of binding: automatic binding and application-managed binding. When you use automatic binding, you don't have to define a binding handle or make any calls to client run-time functions to validate the binding handle. When your application manages the handle, it must make these definitions and calls. Binding-Handle Types, explains these types in more detail.

In this tutorial, the client manages its connection to the server. The client must call run-time functions to bind to the server before calling the remote procedure and must unbind after all remote procedure calls are complete. The structure of a client application that manages its own connection to the server is described in the following code fragment. The remote procedure calls are sandwiched between calls to these client run-time library functions:

/* file: helloc.c (fragment) */

#include "hello.h"    // header file generated by the MIDL compiler

void main(void)

{

    RpcStringBindingCompose(...);

    RpcBindingFromStringBinding(...);

    HelloProc(pszString);    // make remote calls

    RpcStringFree(...);

    RpcBindingFree(...);

}

The first two run-time API calls establish the valid handle to the server. This handle is then used to make the remote procedure call. The final two run-time API calls clean up.

The Microsoft RPC functions use data structures that represent the binding, interface, protocol sequence, and endpoint. The binding is the connection between the client and server; the interface is the collection of data types and procedures made available by the server; the protocol sequence is the underlying network transport to be used for network data transfer, and the endpoint is a network name that is specific to the protocol sequence. This example uses named pipes as the protocol sequence, and the endpoint is named \pipe\hello.

In the following code illustration, the RpcStringBindingCompose function combines the protocol sequence, the network address (server name), the endpoint (pipe name), and other string elements into the form required by the next function, RpcBindingFromStringBinding. RpcStringBindingCompose also allocates memory for a character string that is large enough to hold the data. RpcBindingFromStringBinding uses the string to generate a handle that represents the binding between the client and the server.

After the remote procedure calls are complete, RpcStringFree frees memory that was allocated by RpcStringBindingCompose for the string-binding data structure. RpcBindingFree releases the handle.

The complete client application, with some code added to handle command-line input, appears as follows:

#include <stdlib.h>

#include <stdio.h>

#include <ctype.h>

#include "hello.h"    // header file generated by the MIDL compiler

void Usage(char * pszProgramName)

{

    fprintf(stderr, "Usage:  %s\n", pszProgramName);

    fprintf(stderr, " -p protocol_sequence\n");

    fprintf(stderr, " -n network_address\n");

    fprintf(stderr, " -e endpoint\n");

    fprintf(stderr, " -o options\n");

    fprintf(stderr, " -s string\n");

    exit(1);

}

void main(int argc, char **argv)

{

    RPC_STATUS status;

    unsigned char * pszUuid             = NULL;

    unsigned char * pszProtocolSequence = "ncacn_np";

    unsigned char * pszNetworkAddress   = NULL;

    unsigned char * pszEndpoint         = "\\pipe\\hello";

    unsigned char * pszOptions          = NULL;

    unsigned char * pszStringBinding    = NULL;

    unsigned char * pszString           = "Hello, world";

    unsigned long ulCode;

    int i;

    /* Allow the user to override settings with command line switches */

    for (i = 1; i < argc; i++) {

        if ((*argv[i] == '-') || (*argv[i] == '/')) {

         switch (tolower(*(argv[i]+1))) {

                case 'p':  // protocol sequence

                    pszProtocolSequence = argv[++i];

                    break;

                case 'n':  // network address

                    pszNetworkAddress = argv[++i];

                    break;

                case 'e':  // endpoint

                    pszEndpoint = argv[++i];

                    break;

                case 'o':  // options

                    pszOptions = argv[++i];

                    break;

                case 's':  // string

                    pszString = argv[++i];

                    break;

                case 'h':

                case '?':

                default:

                    Usage(argv[0]);

             }

         }

         else

           Usage(argv[0]);

}

    /* Use a convenience function to concatenate the elements of */

    /* the string binding into the proper sequence               */

    status = RpcStringBindingCompose(
     pszUuid,

     pszProtocolSequence,

     pszNetworkAddress,

     pszEndpoint,

     pszOptions,

     &pszStringBinding);

    printf("RpcStringBindingCompose returned 0x%x\n", status);

    printf("pszStringBinding = %s\n", pszStringBinding);

    if (status)

        exit(status);

    /* Set the binding handle that will */

    /* be used to bind to the server  */

    status = RpcBindingFromStringBinding(
 pszStringBinding,

 &hello_IfHandle);

    printf("RpcBindingFromStringBinding returned 0x%x\n", status);

    if (status)

exit(status);

    printf("Calling the remote procedure 'HelloProc'\n");

    printf("Print the string '%s' on the server\n", pszString);

    RpcTryExcept {

        HelloProc(pszString);  // make call with user message

        printf("Calling the remote procedure 'Shutdown'\n");

        Shutdown();  // shut down the server side

    }

    RpcExcept(1) {

        ulCode = RpcExceptionCode();

        printf("Runtime reported exception 0x%lx \n", ulCode);

    }

    RpcEndExcept

    /*  The calls to the remote procedures are complete. */

    /*  Free the string and the binding handle           */

    status = RpcStringFree(&pszStringBinding);

    printf("RpcStringFree returned 0x%x\n", status);

    if (status) {

        exit(status);

    }

    status = RpcBindingFree(&hello_IfHandle);

    printf("RpcBindingFree returned 0x%x\n", status);

    if (status)

        exit(status);

    exit(0);

}


Building the Client Application

A distributed application requires that you take an extra preliminary step before compiling and linking the C source code: compiling the IDL and ACF files using the MIDL compiler.

You must take care to identify the operating system that will build the application, the operating system(s) that will run the client and server applications, and the network protocol sequence that will be used. These choices determine the versions of the MIDL and C compilers to use, the versions of header files to include in your applications, and the versions of the RPC run-time libraries to link with your applications.

For simplicity, we will assume that this first example will use the same operating system — Microsoft Windows NT — for the build, client, and server platforms, and that the example will use named pipes as the protocol sequence.


MIDL Compilation

The IDL file HELLO.IDL and the application configuration file HELLO.ACF are compiled using the MIDL compiler:

# makefile fragment

midl hello.idl

The MIDL compiler generates the header file HELLO.H and the C-language client stub file HELLO_C.C. (The MIDL compiler also produces the server stub file HELLO_S.C, but ignore this file for now.)


C Compilation

The rest of the development process is familiar: you compile the C-language sources and link them with the RPC run-time libraries for the target platform and any other libraries required by the application. The following commands compile the sample client application:

# makefile fragment

# CC refers to the C compiler

# CFLAGS refers to C compiler switches

# CVARS refers to variables that control #ifdef directives

#

$(CC) $(CFLAGS) $(CVARS) helloc.c

$(CC) $(CFLAGS) $(CVARS) hello_c.c

Note  The compiler commands provided in this topic and in the sample applications are used with a specific software configuration that consists of the nmake utility, the Microsoft C compiler, and the Microsoft Windows NT operating system. See your compiler documentation for specific information.


Linking

The client sources are then linked with the client run-time library, the network data representation library, and the standard C run-time libraries for this platform. For a list of libraries for all platforms, see Building RPC Applications.

# makefile fragment

# LINK refers to the linker

# CONFLAGS refers to flags for console apps

# CONLIBS refers to libraries for console apps

#

client.exe : helloc.obj hello_c.obj

$(LINK) $(CONFLAGS) -out:client.exe helloc.obj hello_c.obj \

     $(CONLIBS) rpcrt4.lib

Note  The linker commands and arguments may vary for your computer configuration. See your compiler documentation for more information.


Client Build Summary

The following fragment from the nmake utility MAKEFILE shows dependencies among the files that are used to build the client application.

# makefile fragment

client.exe : helloc.obj hello_c.obj

 ...

hello.h hello_c.c : hello.idl hello.acf

 ...

helloc.obj : helloc.c hello.h

 ...

hello_c.obj : hello_c.c hello.h

 ...

The preceding example used the default filenames that are produced by the MIDL compiler. The default name for the client stub file is formed from the name of the IDL file (without extension) and the characters _C.C. If the name (without extension) is longer than six characters, some file systems may not accept the stub file name.

The stub files do not have to use the default names. You can customize the names of the client stub using the MIDL compiler switch /cstub:

midl hello.idl -cstub mystub.c

If you specify your own filenames on the MIDL compiler command line, you should use these names in subsequent compile and link commands.


The Server Application

The server side of the distributed application informs the system that its services are available, then waits for client requests.

Depending on the size of your application and your coding standards, you can choose to implement the remote procedures in one or more separate files. In this example, the main routine appears in the source file HELLOS.C, and the remote procedure is provided in a separate file named HELLOP.C.

The benefit to organizing the remote procedures in separate filesis that the procedures can be linked with a stand-alone program to debug the code before it is converted to a distributed application. After the program works as a stand-alone program, the same source files can be compiled and linked with the server application.

Like the client-application source file, the server-application source file should include the HELLO.H header file to obtain definitions for the RPC data and functions and for the interface-specific data and functions.


Calling the Server API Functions
Calling the Server Functions

In the following example, the server calls the functions RpcServerUseProtseqEp and RpcServerRegisterIf to make binding information available to the client. The server then calls the RpcServerListen function to indicate that it is waiting for client requests:

/* file: hellos.c (fragment) */

#include "hello.h"  // header file generated by the MIDL compiler

void main(void)

{

    RpcServerUseProtseqEp(...);

    RpcServerRegisterIf(...);

    RpcServerListen(...);

}

RpcServerUseProtseqEp identifies the server endpoint and the network protocol sequence. RpcServerRegisterIf registers the interface, and RpcServerListen instructs the server to start listening for client requests. The endpoint, interface, and other data structures related to binding are described in more detail in Binding and Handles.

The server application must also include two functions called by the server stubs, midl_user_allocate and midl_user_free. These functions allocate and free memory on the server when a remote procedure must pass parameters to the server. In the following example, midl_user_allocate and midl_user_free are implemented using the C-library functions malloc and free:

void __RPC_FAR * __RPC_API midl_user_allocate(size_t len)

{

    return(malloc(len));

}

void __RPC_API midl_user_free(void __RPC_FAR * ptr)

{

    free(ptr);

}

The complete code for HELLOS.C appears as follows:

#include <stdlib.h>

#include <stdio.h>

#include <ctype.h>

#include "hello.h"    // header file generated by the MIDL compiler

#define PURPOSE \

"This Microsoft RPC sample program demonstrates\n\

the use of the [string] attribute. For more information\n\

about the attributes and the RPC Functions, see the\n\

RPC Programmer's Guide and Reference.\n\n"

void Usage(char * pszProgramName)

{

    fprintf(stderr, "%s", PURPOSE);

    fprintf(stderr, "Usage:  %s\n", pszProgramName);

    fprintf(stderr, " -p protocol_sequence\n");

    fprintf(stderr, " -e endpoint\n");

    fprintf(stderr, " -m maxcalls\n");

    fprintf(stderr, " -n mincalls\n");

    fprintf(stderr, " -f flag_wait_op\n");

    exit(1);

}

void main(int argc, char * argv[])

{

    RPC_STATUS status;

    unsigned char * pszProtocolSequence = "ncacn_np";

    unsigned char * pszSecurity         = NULL;

    unsigned char * pszEndpoint         = "\\pipe\\hello";

    unsigned int    cMinCalls           = 1;

    unsigned int    cMaxCalls           = 20;

    unsigned int    fDontWait           = FALSE;

    int i;

/* Allow the user to override settings with command line switches */

for (i = 1; i < argc; i++) {

    if ((*argv[i] == '-') || (*argv[i] == '/')) {

        switch (tolower(*(argv[i]+1))) {

            case 'p':  // protocol sequence

                pszProtocolSequence = argv[++i];

                break;

            case 'e': // endpoint

                pszEndpoint = argv[++i];

                break;

            case 'm': // max concurrent calls

                cMaxCalls = (unsigned int) atoi(argv[++i]);

                break;

            case 'n': // min concurrent calls

                cMinCalls = (unsigned int) atoi(argv[++i]);

                break;

            case 'f': // flag

    fDontWait = (unsigned int) atoi(argv[++i]);

    break;

            case 'h':

            case '?':

            default:

    Usage(argv[0]);

    }

}

else

    Usage(argv[0]);

}

    status = RpcServerUseProtseqEp(

   pszProtocolSequence,

   cMaxCalls,

   pszEndpoint,

   pszSecurity);  // Security descriptor

    printf("RpcServerUseProtseqEp returned 0x%x\n", status);

    if (status)

exit(status);

    status = RpcServerRegisterIf(
 hello_ServerIfHandle,

 NULL,   // MgrTypeUuid

 NULL);  // MgrEpv; null means use default

    printf("RpcServerRegisterIf returned 0x%x\n", status);

    if (status)

exit(status);

    printf("Calling RpcServerListen\n");

    status = RpcServerListen(
     cMinCalls,

     cMaxCalls,

     fDontWait);

    printf("RpcServerListen returned: 0x%x\n", status);

    if (status)

exit(status);

    if (fDontWait) {

printf("Calling RpcMgmtWaitServerListen\n");

status = RpcMgmtWaitServerListen();  // wait operation

printf("RpcMgmtWaitServerListen returned: 0x%x\n", status);

if (status)

   exit(status);

    }

}

/* MIDL allocate and free */

void __RPC_FAR * __RPC_API midl_user_allocate(size_t len)

{

    return(malloc(len));

}

void __RPC_API midl_user_free(void __RPC_FAR * ptr)

{

    free(ptr);

}


Building the Server Application

Building the server application is very similar to building the client application.

MIDL Compilation

Assume that the server stub source file was generated with the client stub file and the header file. The MIDL compiler produces all three of these files at the same time. In the following example, it's not necessary to call the MIDL compiler twice. The MIDL compiler command line appears as follows:

# makefile fragment

midl hello.idl

C Compilation

The C source files that contain the server RPC function calls and the remote procedures are compiled with the stub source file generated by the MIDL compiler:

$(CC) $(CFLAGS) $(CVARS) hellos.c

$(CC) $(CFLAGS) $(CVARS) hellop.c

$(CC) $(CFLAGS) $(CVARS) hello_s.c

Note  The compiler commands provided in this topic and in the sample applications are used with a specific software configuration that consists of the nmake utility, the Microsoft C compiler, and the Microsoft Windows NT operating system. See your compiler documentation for specific information.

Linking

Once the C source files are compiled, the server sources are linked with the server run-time libraries and the standard C run-time libraries for the specified platform, protocol sequence (named pipes), and memory model:

# makefile fragment

# LINK refers to the linker

# CONFLAGS refers to flags for console apps

# CONLIBS refers to libraries for console apps

#

server.exe : hellos.obj hellop.obj hello_s.obj

$(LINK) $(CONFLAGS) -out:server.exe hellos.obj hellop.obj

 hello_s.obj $(CONLIBS) rpcrt4.lib

Note  The linker commands and arguments may vary for your computer configuration. See your compiler documentation for more information.


Server Build Summary

The following fragment from the nmake utility MAKEFILE shows dependencies among the files used to build the server application. The executable relies on the server source and the server stub files. All server sources rely on the header file HELLO.H:

# makefile fragment

server.exe : hellos.obj hellop.obj hello_s.obj

    ...

hello.h hello_s.c : hello.idl hello.acf

    ...

hellos.obj : hellos.c hello.h

    ...

hellop.obj : hellop.c hello.h

    ...

hello_s.obj : hello_s.c hello.h

    ...


Stopping the Server Application

A robust server application should stop listening for clients and remove the interface from the registry shut down gracefully. The two core server functions that accomplish these goals are RpcMgmtStopServerListening and RpcServerUnregisterIf.

The server function RpcServerListen does not return to the calling program until an exception occurs or until the server calls RpcMgmtStopServerListening. In Microsoft RPC, the client cannot directly call this stop-listening function. However, you can design the server application so that the user controls the server application as a service and directs another thread of the server application to call RpcMgmtStopServerListening. Or you can allow the client application to shut down the server application by making a remote procedure call to a function on the server that calls RpcMgmtStopServerListening. The following example uses the latter approach. The new remote function Shutdown is added to HELLOP.C:

/* hellop.c fragment */

#include "hello.h" //header file generated by the MIDL compiler

void Shutdown(void)

{

    RPC_STATUS status;

    status = RpcMgmtStopServerListening(NULL);

     ...

    status = RPCServerUnregisterIf(NULL, NULL, FALSE);

     ...

}

The single null parameter to RpcMgmtStopServerListening indicates that the local application should stop listening for remote procedure calls. The two null parameters to RpcServerUnregisterIf indicate that no interfaces are registered. The FALSE parameter indicates that the interface should be removed from the registry immediately.

Because it is a remote procedure, Shutdown must also be added to the interface body section of the IDL file:

/* file: hello.idl */

[ uuid (6B29FC40-CA47-1067-B31D-00DD010662DA),

  version(1.0)

]

interface hello

{

void HelloProc([in, string] char * pszString);

void Shutdown(void);

}

Finally, the client application must add the call to the Shutdown function:

/* helloc.c (fragment) */

#include "hello.h"    // header file generated by the MIDL compiler

void main(void)

{

    char * pszString = "Hello, world";

    RpcStringBindingCompose(...);

    RpcBindingFromStringBinding(...);

    HelloProc(pszString);

    Shutdown();

    RpcStringFree(...);

    RpcBindingFree(...);

}


Summary
Summary: Basic Steps in RPC Development

A distributed application consists of client-side executables and server-side executables.

The RPC development process includes two more steps than the standard development process. You must specify the interface for the remote procedure call in the IDL and ACF files, which are compiled using the MIDL compiler. The MIDL compiler produces C source files and the stub files. The development process is then the same as for any application: compile the C-language files and link the objects with libraries to create the executables.

For the "Hello, world" distributed application, the developer creates the following source files:

•	HELLOC.C

•	HELLOS.C

•	HELLOP.C

•	HELLO.IDL

•	HELLO.ACF

The MIDL compiler uses the HELLO.IDL and HELLO.ACF files to generate the client stub source file HELLO_C.C, the server stub source file HELLO_S.C, and the header file HELLO.H, which includes the RPC.H header file.

The client executable is built from the client run-time library and the following C-language header and source files:

•	HELLO.H

•	HELLOC.C

•	HELLO_C.C (stub)

The server executable is built from the server run-time library and the following C-language header and source files:

•	HELLO.H

•	HELLOS.C

•	HELLOP.C

•	HELLO_S.C (stub)

The following figure illustrates the typical application-development cycle and the extra steps required by the RPC development cycle:

The following list summarizes the tasks in the development process when you use Microsoft RPC:

1.	Create the Interface Definition Language file that specifies interface identification and the data types and function prototypes for the remote procedures.

2.	Create the application configuration file.

3.	Compile the interface definition using the MIDL compiler. The MIDL compiler generates C-language stub files and the header file for client and server.

4.	Include the header file generated by the MIDL compiler in the client and server applications.

5.	Create a server source program that calls RPC functions to make binding information available to the client, then calls RpcServerListen to start listening for client requests. Provide a method to shut down the server.

6.	Link the client with the client stub file and the RPC client run-time libraries.

7.	Link the server with the server stub file, the remote procedures, and the RPC server run-time library.


Data and Language Features

The Microsoft Interface Definition Language (MIDL) provides the set of features that extend the C programming language to support remote procedure calls. MIDL is not a flavor of C; MIDL is a strongly typed formal language that allows you to control the data transmitted over the network. MIDL is designed to be similar to C so that developers familiar with C can learn it quickly.

This topic discusses three language features: strong typing, directional attributes, and data transmission.

MIDL enforces strong typing by mandating the use of keywords that unambiguously define the size and type of data. The most visible effect of strong typing is that MIDL does not allow variables of the types int and void *.

Directional attributes describe whether the data is transmitted from client to server, server to client, or both.

The transmit_as attribute lets you convert one data type to another data type for transmission over the network. The represent_as attribute lets you control the way data is presented to the application.


Strong Typing

C is a weakly typed language. In a weakly typed language, the compiler allows operations such as assignment and comparison among variables of different types. For example, C allows the value of a variable to be cast to another type. The ability to use variables of different types in the same expression promotes flexibility as well as efficiency.

A strongly typed language imposes restrictions on operations among variables of different types. In these cases, the compiler issues an error prohibiting the operation. These strict guidelines regarding data types are designed to avoid potential errors.

The difficulty with using a weakly typed language such as C for remote procedure calls is that distributed applications can run on several different computers with different C compilers and different architectures.

When an application runs on only one computer, you don't have to be concerned with the internal data format because the data is handled in a consistent manner. But in a distributed computing environment, different computers can use different definitions for their base data types. For example, some computers define the int type so that its internal representation is 16 bits, while other computers use 32 bits. One computer architecture, known as "little endian," assigns the least significant byte of data in the lowest memory address and the most significant byte in the highest address. Another architecture assigns the least significant byte in the highest memory address associated with that data and is known as "big endian."

Remote procedure calls require strict control over parameter types. To handle data transmission and conversion over the network, MIDL strictly enforces type restrictions for data transferred over the network. For this reason, MIDL includes a set of well-defined base types.


Base Types

To prevent the problems that implementation-dependent data types can cause on varying computer architectures, MIDL defines its own base data types:

Base type	Description
boolean	Data item that can have the value TRUE or FALSE
byte	8-bit data item guaranteed to be transmitted without any change
char	8-bit unsigned character data item
double	64-bit floating-point number
float	32-bit floating-point number
handle_t	Primitive handle that can be used for RPC binding or data serializing
hyper	64-bit integer that can be declared as either signed or unsigned.  (Can also be referred to as _int64.)
long	32-bit integer that can be declared as either signed or unsigned
short	16-bit integer that can be declared as either signed or unsigned
small	8-bit integer that can be declared as either signed or unsigned
wchar_t	Wide-character type that is supported as a Microsoft extension to IDL. (To use wchar_t, you must specify the  /ms_ext switch when compiling the IDL file.)
The header file RPCNDR.H provides definitions for most of these base data types. MIDL does not recognize the keyword int for remotable objects unless it is accompanied by one of the modifiers that specify the integer's length: hyper, long, short, or small. The int keyword is optional and can be omitted.

Although void * is recognized as a generic pointer type by the ANSI C standard, MIDL restricts its usage. Each pointer used in a remote or serializing operation must point to either base types or types constructed from base types. (There is an exception: context handles are defined as void * types. For more information see Context Handles.)


Signed and Unsigned Types

Compilers that use different defaults for signed and unsigned types can cause software errors in your distributed application.

You can avoid these problems by explicitly declaring your character types as signed or unsigned.

MIDL defines the small type to take the same default sign as the char type in the target C compiler. If the compiler assumes that char is unsigned, small will also be defined as unsigned. Many C compilers let you change the default as a command-line option. For example, the Microsoft C compiler /J command-line option changes the default sign of char from signed to unsigned.

You can also control the sign of variables of type char and small with the MIDL compiler command-line switch /char. This switch allows you to specify the default sign used by your compiler. The MIDL compiler explicitly declares the sign of all char types that do not match your C-compiler default type in the generated header file.


Wide-Character Types

Microsoft RPC supports the wide-character type wchar_t. The wide-character type uses 2 bytes for each character. The ANSI C-language definition allows you to initialize long characters and long strings as follows:

wchar_t wcInitial = L'a';

wchar_t * pwszString = L"Hello, world";

This support is offered only as an extension to MIDL. To enable the use of wchar_t in remote operations, you must specify the /ms_ext switch when you compile the IDL file.


Unions

Some features of the C language, such as unions, require special MIDL keywords to support their use in remote procedure calls.

A union in the C language is a variable that holds objects of different types and sizes. The developer usually creates a variable to keep track of the types stored in the union. To operate correctly in a distributed environment, the variable that indicates the type of the union, or the "discriminant," must also be available to the remote computer. MIDL provides the switch_type and switch_is keywords to identify the discriminant type and name.

MIDL requires that the discriminant be transmitted with the union in one of two ways:

•	The union and the discriminant must be provided as parameters.

•	The union and the discriminant must be packaged in a structure.

The following example demonstrates how to provide the union and discriminant as parameters:

typedef [switch_type(short)] union {

    [case(0)]    short     sVal;

    [case(1)]    float     fVal;

    [case(2)]    char      chVal;

    [default]    ;

} DISCRIM_UNION_PARAM_TYPE;

short UnionParamProc(

    [in, switch_is(sUtype)] DISCRIM_UNION_PARAM_TYPE Union,

    [in]                    short                    sUtype);

The union in the preceding example can contain a single value: either short, float, or char. The type definition for the union includes the MIDL switch_type attribute, which specifies the type of the discriminant. Here, [switch_type(short)] specifies that the discriminant is of type short. The switch must be an integer type, but as in other type definitions, int is not recognized as a valid type unless it is accompanied by a modifier such as long, small, or short.

If the union is a member of a structure, then the discriminant must be a member of the same structure. If the union is a parameter, then the discriminant must be another parameter. The prototype for the function UnionParamProc shows the discriminant sUtype as the last parameter of the call. (The discriminant can appear in any position in the call.) The type of the parameter specified in the switch_is attribute must match the type specified in the switch_type attribute.

The following example demonstrates the use of a single structure that packages the discriminant with the union:

typedef struct {

    short utype;  /* discriminant can precede or follow union */

    [switch_is(utype)] union {

       [case(0)]   short     sVal;

       [case(1)]   float     fVal;

       [case(2)]   char      chVal;

       [default]    ;

    } u;

} DISCRIM_UNION_STRUCT_TYPE;

short UnionStructProc(

    [in] DISCRIM_UNION_STRUCT_TYPE u1);


Directional Attributes

All parameters in the function prototype must be associated with directional attributes. The three possible combinations of directional attributes are: (1) in, (2) out, and (3) in, out. They describe the way parameters are passed between calling and called procedures. Directional attributes can be omitted for Microsoft extensions mode (/ms_ext) and C-language extensions mode (/c_ext). If no directional attribute is provided for a parameter, the MIDL compiler assumes a default value of in.

Use the following example to convert the following ANSI C function prototype to a remote procedure:

void MyFunction(int i);

MIDL requires that a directional attribute be associated with the parameter in the function prototype. In addition, int is not a valid MIDL type, so the type of the argument must be changed to the specific integer type. The converted function appears in the IDL file as a remote procedure call prototype:

void MyFunction([in] short i);

An out parameter must be a pointer. In fact, the out attribute is not meaningful when applied to parameters that do not act as pointers because C function parameters are passed by value. In C, the called function receives a private copy of the parameter value; it cannot change the calling function's value for that parameter. If the parameter acts as a pointer, however, it can be used to access and modify memory. The out attribute indicates that the server function should return the value to the client's calling function, and that memory associated with the pointer should be returned in accordance with the attributes assigned to the pointer.

The following interface demonstrates the three possible combinations of directional attributes that can be applied to a parameter. The function InOutProc is defined in the IDL file as follows:

void InOutProc ([in]       short     s1,

                [in, out]  short *  ps2,

                [out]      float *  pf3);

The first parameter, s1, is in only. Its value is transmitted to the remote computer but is not returned to the calling procedure. Although the server application can change its value for s1, the value of s1 on the client is the same before and after the call.

The second parameter, ps2, is defined in the function prototype as a pointer with both in and out attributes. The in attribute indicates that the value of the parameter is passed from the client to the server; the out attribute indicates that the value pointed to by ps2 is returned to the client.

The third parameter is out only. Space is allocated for the parameter on the server but the value is undefined on entry. As mentioned above, all out parameters must be pointers.

The remote procedure changes the value of all three parameters, but only the new values of the out and in, out parameters are available to the client.

#define MAX 257

void InOutProc(short    s1,

               short * ps2,

               float * pf3)

{

    *pf3 = (float) s1 / (float) *ps2;

    *ps2 = (short) MAX - s1;

    s1++;  // in only; not changed on the client side

    return;

}

On return from the call to InOutProc, the second and third parameters are modified. The first parameter, which is in only, is unchanged.


The transmit_as Attribute

The transmit_as attribute allows you to specify a data type that will be used for transmission instead of using the data type provided. You supply routines that convert the data type to and from the type that is used for transmission. You must also supply routines to free the memory used for the data type and the transmitted type. For example, the following defines xmit_type as the transmitted data type for an application-presented type specified as type_spec:

typedef [transmit_as (xmit_type)] type_spec type;

The following table describes the four user-supplied routine names. Type is the data type known to the application, and xmit_type is the data type used for transmission:

Routine	Description
type_to_xmit	Allocates an object of the transmitted type and converts from presented type to transmitted type (caller and callee)
type_from_xmit	Converts from transmitted type to presented type (caller and callee)
type_free_inst	Frees resources used by the presented type (callee only)
type_free_xmit	Frees storage returned by the type_to_xmit routine (caller and callee)
Other than by these four user-supplied functions, the transmitted type is not manipulated by the application. The transmitted type is defined only to move data over the network. After the data is converted to the type used by the application, the memory used by the transmitted type is freed.

These user-supplied routines are provided by either the client or the server application based on the directional attributes.

If the parameter is in only, the client transmits to the server. The client needs the type_to_xmit and type_free_xmit functions. The server needs the type_from_xmit and type_free_inst functions.

For an out-only parameter, the server transmits to the client. The server needs the type_to_xmit and type_free_xmit functions, while the client needs the type_from_xmit function.

For the temporary xmit_type objects, the stub will call type_free_xmit to free any memory allocated by a call to type_to_xmit.

Certain guidelines apply to the presented type instance. If the presented type is a pointer or contains a pointer, then the type_from_xmit routine must allocate pointees of the pointers (the presented type object itself is manipulated by the stub in the usual way). For out and in, out parameters, or one of their components, of a type that contains the transmit_as attribute, the type_free_inst routine is automatically called for the data objects that have the attribute. For in parameters, the type_free_inst routine is called only if the transmit_as attribute has been applied to the parameter. If the attribute has been applied to the components of the parameter, the type_free_inst routine is not called. There are no freeing calls for the embedded data and at-most-one call (related to the top-level attribute) for an in only parameter.

For MIDL 2.0, both client and server must supply all four functions.

For example, a linked list can be transmitted as a sized array. The type_to_xmit routine walks the linked list and copies the ordered data into an array. The array elements are ordered, so the many pointers associated with the list data structure do not have to be transmitted. The type_from_xmit routine reads the array and puts its elements into a linked-list data structure.

The double-linked list DOUBLE_LINK_LIST includes data and pointers to the previous and next list elements:

typedef struct _DOUBLE_LINK_LIST {

    short sNumber;

    struct _DOUBLE_LINK_LIST * pNext;

    struct _DOUBLE_LINK_LIST * pPrevious;

} DOUBLE_LINK_LIST;

Rather than shipping the complex data structure, the transmit_as attribute can be used to send it over the network as an array. The sequence of items in the array retains the ordering of the elements in the list at a lower cost:

typedef struct _DOUBLE_XMIT_TYPE {

    short sSize;

    [size_is(sSize)] short asNumber[];

} DOUBLE_XMIT_TYPE;

The transmit_as attribute appears in the IDL file:

typedef [transmit_as(DOUBLE_XMIT_TYPE)]  DOUBLE_LINK_LIST
                                         DOUBLE_LINK_TYPE;

In the following example, ModifyListProc defines the parameter of type DOUBLE_LINK_TYPE as an in, out parameter:

void ModifyListProc([in, out] DOUBLE_LINK_TYPE * pHead)

The four user-defined functions use the name of the type in the function names and use the presented and transmitted types as parameter types, as required:

void __RPC_USER DOUBLE_LINK_TYPE_to_xmit (
     DOUBLE_LINK_TYPE __RPC_FAR * pList,
     DOUBLE_XMIT_TYPE __RPC_FAR * __RPC_FAR * ppArray);

void __RPC_USER DOUBLE_LINK_TYPE_from_xmit (

     DOUBLE_XMIT_TYPE __RPC_FAR * pArray,

     DOUBLE_LINK_TYPE __RPC_FAR * pList);

void __RPC_USER DOUBLE_LINK_TYPE_free_inst (
     DOUBLE_LINK_TYPE __RPC_FAR * pList);

void __RPC_USER DOUBLE_LINK_TYPE_free_xmit (
     DOUBLE_XMIT_TYPE __RPC_FAR * pArray);


The type_to_xmit Function

The stubs call the type_to_xmit function to convert the type that is presented by the application to the transmitted type. The function is defined as follows:

void __RPC_USER <type>_to_xmit (
     <type> __RPC_FAR *, <xmit_type> __RPC_FAR * 	__RPC_FAR *);

The first parameter is a pointer to the presented data. The second parameter is set by the function to point to the transmitted data. The function must allocate memory for the transmitted type.

In the following example, the client calls the remote procedure that has an in, out parameter of type DOUBLE_LINK_TYPE. The client stub calls the type_to_xmit function, here named DOUBLE_LINK_TYPE_to_xmit, to convert double-linked list data to a sized array.

The function determines the number of elements in the list, allocates an array large enough to hold those elements, then copies the list elements into the array. Before the function returns, the second parameter, ppArray, is set to point to the newly allocated data structure.

void __RPC_USER DOUBLE_LINK_TYPE_to_xmit (
    DOUBLE_LINK_TYPE __RPC_FAR * pList,
    DOUBLE_XMIT_TYPE __RPC_FAR * __RPC_FAR * ppArray)

{

    short cCount = 0;

    DOUBLE_LINK_TYPE * pHead = pList;  // save pointer to start

    DOUBLE_XMIT_TYPE * pArray;

    /* count the number of elements to allocate memory */

    for (; pList != NULL; pList = pList->pNext)

        cCount++;

    /* allocate the memory for the array */

    pArray = (DOUBLE_XMIT_TYPE *) MIDL_user_allocate

     (sizeof(DOUBLE_XMIT_TYPE) + (cCount * sizeof(short)));

    pArray->sSize = cCount;

    /* copy the linked list contents into the array */

    cCount = 0;

    for (i = 0, pList = pHead; pList != NULL; pList = pList->pNext)

        pArray->asNumber[cCount++] = pList->sNumber;

    /* return the address of the pointer to the array */

    *ppArray = pArray;

}


The type_from_xmit Function

The stubs call the type_from_xmit function to convert data from its transmitted type to the type that is presented to the application. The function is defined as follows:

void __RPC_USER <type>_from_xmit (
    <xmit_type> __RPC_FAR *,
    <type> __RPC_FAR *);

The first parameter is a pointer to the transmitted data. The function sets the second parameter to point to the presented data.

The type_from_xmit function must manage memory for the presented type. The function must allocate memory for the entire data structure that starts at the address indicated by the second parameter, except for the parameter itself (the stub allocates memory for the root node and passes it to the function). The value of the second parameter cannot change during the call. The function can change the contents at that address.

In this example, the function DOUBLE_LINK_TYPE_from_xmit converts the sized array to a double-linked list. The function retains the valid pointer to the beginning of the list, frees memory associated with the rest of the list, then creates a new list that starts at the same pointer. The function uses a utility function, InsertNewNode, to append a list node to the end of the list and to assign the pNext and pPrevious pointers to appropriate values.

void __RPC_USER DOUBLE_LINK_TYPE_from_xmit(

     DOUBLE_XMIT_TYPE __RPC_FAR * pArray,

     DOUBLE_LINK_TYPE __RPC_FAR * pList)

{

    DOUBLE_LINK_TYPE *pCurrent;

    int i;

    if (pArray->sSize <= 0) {  // error checking

        return;

    }

    if (pList == NULL) // if invalid, create the list head

        pList = InsertNewNode(pArray->asNumber[0], NULL);

    else {

        DOUBLE_LINK_TYPE_free_inst(pList);  // free all other nodes

        pList->sNumber = pArray->asNumber[0];

        pList->pNext = NULL;

    }

    pCurrent = pList;

    for (i = 1; i < pArray->sSize; i++)

        pCurrent = InsertNewNode(pArray->asNumber[i], pCurrent);

    return;

}


The type_free_xmit Function

The stubs call the type_free_xmit function to free memory associated with the transmitted data. After the type_from_xmit function converts the transmitted data to its presented type, the memory is no longer needed. The function is defined as follows:

void __RPC_USER <type>_free_xmit(<xmit_type> __RPC_FAR *);

The parameter is a pointer to the memory that contains the transmitted type.

In this example, the memory contains an array that is in a single structure. The function DOUBLE_LINK_TYPE_free_xmit uses the user-supplied function midl_user_free to free the memory:

void __RPC_USER DOUBLE_LINK_TYPE_free_xmit(
     DOUBLE_XMIT_TYPE __RPC_FAR * pArray)

{

     midl_user_free(pArray);

}


The type_free_inst Function

The stubs call the type_free_inst function to free memory associated with the presented type. The function is defined as follows:

void __RPC_USER <type>_free_inst(<type> __RPC_FAR *)

The parameter points to the presented type instance. This object should not be freed. For a discussion of when to call the function, see the transmit_as Attribute.

In the following example, the double-linked list is freed by walking the list to its end, then backing up and freeing each element of the list.

void __RPC_USER DOUBLE_LINK_TYPE_free_inst(
     DOUBLE_LINK_TYPE __RPC_FAR * pList)

{

    while (pList->pNext != NULL)  // go to end of the list

        pList = pList->pNext;

    pList = pList->pPrevious;

    while (pList != NULL) {  // back through the list

        midl_user_free(pList->pNext);

        pList = pList->pPrevious;

    }

}


Summary of transmit_as Attribute

The transmit_as attribute offers a way to control data marshalling without worrying about marshalling data at a low level — that is, without worrying about data sizes or byte-swapping in a heterogeneous environment. By allowing you to reduce the amount of data transmitted over the network, the transmit_as attribute can make your application more efficient.


The represent_as Attribute

The represent_as attribute allows you to specify how a particular remotable data type is represented for the application. Specify the name of the represented type for a known transmittable type, and supply the routines to convert the data type to and from the other data type. You must also supply the routines to free the memory used by the data type objects.

The represent_as attribute is similar to the transmit_as attribute. However, while transmit_as enables you to specify a data type that will be used for transmission, represent_as allows you to specify how a data type is represented for the application. The represented type need not be defined in the MIDL processed files; it can be defined at the time the stubs are compiled with the C compiler. Use the include directive in the ACF to compile the appropriate header file. For example, the following ACF defines a local represented repr_type for the given transmittable named_type:

typedef [represent_as(repr_type) [, type_attribute_list] named_type;

The following table describes the four user-supplied routines:

Routine	Description
named_type_from_local	Allocates an instance of the network type and converts from the local type to the network type
named_type_to_local	Converts from the network type to the local type
named_type_free_local	Frees memory allocated by a call to the named_type_to_local routine, but not the type itself
named_type_free_inst	Frees storage for the network type (both sides)
Other than by these four user-supplied routines, the named type is not manipulated by the application and the only type visible to the application is the represented type. The represented type name is used instead of the named type name in the prototypes and stubs generated by the compiler. You must supply the set of routines for both sides.

For temporary named_type objects, the stub will call named_type_free_inst to free any memory allocated by a call to named_type_from_local.

If the represented type is a pointer or contains a pointer, the named_type_to_local routine must allocate pointees of the pointers (the represented type object itself is manipulated by the stub in the usual way). For out and in, out parameters of a type that contain represent_as or one of its components, the named_type_free_local routine is automatically called for the data objects that contain the attribute. For in parameters, the named_type_free_local routine is only called if the represent_as attribute has been applied to the parameter. If the attribute has been applied to the components of the parameter, the *_free_local routine is not called. Freeing routines are not called for the embedded data and at-most-once call (related to the top-level attribute) for an in only parameter.

Note  It is possible to apply both the transmit_as and represent_as attributes to the same type. When marshalling data, the represent_as type conversion is applied first, and then the transmit_as conversion is applied. The order is reversed when unmarshalling data. Thus, when marshalling, *_from_local allocates an instance of a named type and translates it from a local type object to the temporary named type object. This object is the presented type object used for the *_to_xmit routine. The *_to_xmit routine then allocates a transmitted type object and translates it from the presented (named) object to the transmitted object.

An array of long integers can be used to represent a linked list. In this way, the application manipulates the list and the transmission uses an array of long integers when a list of this type is transmitted. You can begin with an array, but using a construct with an open array of long integers is more convenient. The following example shows how to do this:

/* IDL definitions */

typedef struct_lbox {

long	data;

struct_lbox *	pNext

} LOC_BOX, * PLOC_BOX;

/* The definition of the local type visible to the application, as shown above, can be omitted in the IDL file. See the include in the ACF file. */

typedef struct_xmit_lbox {

short	Size;

[size_is(Size)] long DaraArr[];

} LONGARR;

void

WireTheList( [in,out] LONGARR * pData );

/* ACF definitions */

/* If the IDL file does not have a definition for PLOC_BOX, you can still ready it for C compilation with the following include statement (notice that this is not a C include):

include "local.h";

*/

typedef [represent_as(PLOC_BOX)] LONGARR;

Note that the prototypes of the routines that use the LONGARR type are actually displayed in the STUB.H files as PLOC_BOX in place of the LONGARR type. The same is true of the appropriate stubs in the STUB_C.C file.

You must supply the folllowing four functions:

void __RPC_USER

LONGARR_from_local(

PLOC_BOX __RPC_FAR * pList,

LONGARR __RPC_FAR * _RPC_FAR * ppDataArr );

void __RPC_USER

LONGARR_to_local(

LONGARR __RPC_FAR * _RPC_FAR * ppDataArr,

PLOC_BOX __RPC_FAR * pList );

void __RPC_USER

LONGARR_free_inst(

LONGARR __RPC_FAR * pDataArr);

void __RPC_USER

LONGARR_free_local(

PLOC_BOX __RPC_FAR * pList );

The routines shown above do the following:

•	The LONGARR_from_local routine counts the nodes of the list, allocates a LONGARR object with the size sizeof(LONGARR) + Count*sizeof(long), sets the Size field to Count, and copies the data to the DataArr field.

•	The LONGARR_to_local routine creates a list with Size nodes and transfers the array to the appropriate nodes.

•	The LONGARR_free_inst routine frees nothing in this case.

•	The LONGARR_free_local routine frees all the nodes of the list.


Summary of represent_as Attribute

The represent_as attribute offers a way to present an application with a different and perhaps non-remotable data type, rather than the type that is actually transmitted between the client and server. Also, the type the application manipulates can be unknown at the time of MIDL compilation. When you choose a well-defined transmittable type, you need not be concerned about data representation in the heterogenic environment. The represent_as attribute can make your application more efficient by reducing the amount of data transmitted over the network.


Summary
Summary of Data and Attributes

MIDL was designed to solve the problem of transmitting data not only between different computers but between different computer architectures.

MIDL provides well-defined base types, replacing the implementation-dependent int type with the specific types small, short, long, and hyper. MIDL also supports the float, double, and handle_t base types.

MIDL assumes that char types are unsigned. If your C compiler assumes the use of signed char, use the MIDL compiler command-line switch /char to ensure that the header file explicitly declares all characters as unsigned.

MIDL enforces strong typing; the ANSI C generic pointer type void * is not supported, requiring the application to supply a pointer to a specific type.

MIDL also forces the parameters related to a union to be either defined as related parameters or included in the same structure.

You control the way data is transmitted over the network with the transmit_as attribute, and the way data is presented to the application with the represent_as attribute.


Arrays and Pointers

Because RPC is designed to be transparent, you can expect a remote procedure call to behave just like a local procedure call. When a pointer is a parameter, the remote procedure can access the data object the pointer refers to the same way a local procedure accesses it.

To achieve this transparency, the client stub transmits to the server both the pointer and the data object that it points to. If the remote procedure changes the data, the server must transmit the new data back to the client so the client can copy the new data over the original data.

The number of MIDL attributes relating to arrays and pointers reflects the flexibility that C affords. MIDL offers several attributes that extend C arrays and pointers to the distributed environment.


Array Attributes

There is a close relationship between arrays and pointers in the C language. When passed as a parameter to a function, an array name is treated as a pointer to the first element of the array, as in the following example:

/* fragment */

extern void f1(char * p1);

void main(void)

{

    char chArray[MAXSIZE];

    fLocal1(chArray);

}

In a local call, you can use the pointer parameter to march through memory and examine the contents of other addresses:

/* dump memory (fragment) */

void fLocal1(char * pch1)

{

    int i;

    for (i = 0; i < MAXSIZE; i++)

       printf("%c ", *pch1++);

}

When a client passes a pointer to a remote procedure in C, the client stub transmits both the pointer and the data it points to. Unless the pointer is restricted to its corresponding data, all the client's memory must be transmitted with every remote call. By enforcing strong typing in the interface definition, MIDL limits client stub processing to the data that corresponds with the specified pointer.

The size of the array and the range of array elements transmitted to the remote computer can be constant or variable. When these values are variable, and thus determined at run time, you must use attributes in the IDL file to tell the stubs how many array elements to transmit. The following MIDL attributes support array bounds:

Attribute	Description	Default
first_is	Index of the first array element transmitted	0
last_is	Index of the last array element transmitted	-
length_is	Total number of array elements transmitted	-
max_is	Highest valid array index value	-
min_is	Lowest valid array index value	0
size_is	Total number of array elements allocated for the array	-
Note  The min_is attribute is not implemented in Microsoft RPC. The minimum array index is always treated as zero.


The size_is Attribute

The size_is attribute is associated with an integer constant, expression, or variable that specifies the allocation size of the array. Consider a character array whose length is determined by user input:

/* IDL file */

[ uuid(20B309B1-015C-101A-B308-02608C4C9B53),

  version(2.0)

]

interface arraytest

{

void fArray2([in] short sSize,

             [in, out, size_is(sSize)] char achArray[*]);

}

The asterisk (*) that marks the placeholder for the variable-array dimension is optional.

The server stub must allocate memory on the server that corresponds to the memory on the client for that parameter. The variable that specifies the size must always be at least an in parameter. The in directional attribute is required so that the size value is defined on entry to the server stub. The size value provides information that the server stub requires to allocate the memory. The size parameter can also be in, out.


The length_is Attribute

The size_is attribute allows you to specify the maximum size of the array. When this is the only attribute, all elements of the array are transmitted. Rather than sending all elements of the array, you can specify the transmitted elements using the length_is attribute:

/* IDL file */

[ uuid(20B309B1-015C-101A-B308-02608C4C9B53),

  version(3.0)

]

interface arraytest

{

void fArray3([in, out, size_is(sSize), length_is(sLen)] char achArray[],
  [in] short sSize,

  [in] short SLength);

}

Size describes allocation. Length describes transmission. The number of elements transmitted must always be less than or equal to the number of elements allocated. The value associated with length_is is always less than or equal to size_is.


The first_is and last_is Attributes

You can determine the number of transmitted elements by specifying the first and last elements. Use the first_is and last_is attributes:

/* IDL file */

[ uuid(20B309B1-015C-101A-B308-02608C4C9B53),

  version(4.0)

]

interface arraytest

{

void fArray4([in, out,

              size_is(sSize),

              first_is(sFirst),

              last_is(sLast)]   char achArray[],

             [in] short sSize,

             [in] short sLast,

             [in] short sFirst) ;

}


The max_is Attribute

You can specify the valid bounds of the array using the max_is attribute.

/* IDL file */

[ uuid(20B309B1-015C-101A-B308-02608C4C9B53),

  version(5.0)

]

interface arraytest

{

void fArray5([in] short sMax,

             [in, out, max_is(sMax)]  char achArray[]);

}

Field attributes can be supplied in various combinations, as long as the stub can use the information to determine the size of the array and the number of bytes to transmit to the server. The relationships between the attributes are defined using the following formulas:

size_is = max_is + 1;

length_is = last_is - first_is + 1;

The values associated with the attributes must obey several common-sense rules based on those formulas:

•	The first_is index value cannot be smaller than zero; last_is cannot be greater than max_is.

•	Don't specify a negative size for an array. Define the first and last elements so they result in a length value of zero or greater. Define the max_is value so that the size is zero or greater. If MIDL was invoked with the _error bounds_check flag, then the stub raises an exception when the size is less than 0, or the transmitted length is less than 0.

•	You can't use the length_is and last_is attributes at the same time. You can't use the size_is and max_is attributes at the same time.

Because of the close relationship in C between arrays and pointers, MIDL also permits you to declare arrays in parameter lists using pointer notation. MIDL treats a parameter that is a pointer to a type as an array of that type if the parameter has any of the attributes commonly associated with arrays.

/* IDL file */

[ uuid(20B309B1-015C-101A-B308-02608C4C9B53)

  version(6.0)

]

interface arraytest

{

void fArray6([in, out, size_is(sSize)] char * p1,
             [in] short sSize);

void fArray7([in, out, size_is(sSize)] char achArray[],
             [in] short sSize);

}

In the preceding example, the array and pointer parameters in the functions fArray6 and fArray7 are equivalent.


Strings

You can use the string attribute for one-dimensional-character, wide-character, and byte arrays that represent text strings.

If you use the string attribute, the client stub uses the C-library functions strlen or wstrlen to count the number of characters in the string. To avoid possible inconsistencies, MIDL does not let you use the string attribute at the same time as the first_is, last_is, and size_is attributes.

As always with null-terminated strings in C, you must allow space for the null character at the end of the string. When declaring a string that will hold up to 80 characters, for example, allocate 81 characters:

/* IDL file */

[ uuid(20B309B1-015C-101A-B308-02608C4C9B53),

  version(8.0)

]

interface arraytest

{

void fArray8([in, out, string] char achArray[]);

}


Multi-Dimensional Arrays

Array attributes can also be used with multi-dimensional arrays. However, be careful to ensure that every dimension of the array has a corresponding attribute. For example:

/* IDL file */

[ uuid(20B309B1-015C-101A-B308-02608C4C9B53),

  version(2.0)

]

void arr2d( [in] short	dlsize,

[in] short	d2len,

[in,

  size_is( dlsize, ),

  length_is ( , d2len) ] long	array2d[*][30] ) ;

The array shown above is a conformant array (of size dlsize) of 30 element arrays (with d2len elements shipped for each).

The string attribute can also be used with multi-dimensional arrays. The attribute applies to the least-significant dimension, such as a conformant array of strings. You can also use multi-dimensional pointer attributes, but if you do so, the order of the attributes will be reserved because of the right-to-left behavior associated with pointers. For example:

/* IDL file */

[ uuid(20B309B1-015C-101A-B308-02608C4C9B53),

  version(2.0)

]

void arr2d( [in] short	d1len,

[in] short	d2len,

   [in] size_is(d1len, d2len) ] long  ** ptr2d) ;

In the example above, the variable ptr2d is d1len pointers to d2len pointers to long.

Be sure that a multi-dimensional array is not equivalent to multiple levels of pointers. A multi-dimensional array is a single large block of memory and should not be confused with an array of pointers. Also, ANSI C syntax only allows the most significant (leftmost) array dimension to be unspecified in a multi-dimensional array). Therefore, the following is a valid statement:

long a1[] [20]

Compare this to the following invalid statement:

long a1[20] []


Pointers

It is very efficient to use pointers as C function parameters. The pointer costs only a few bytes and can be used to access a large amount of memory. In a distributed application, however, the client and server procedures can reside in different address spaces on different computers that may not have access to the same memory.

When one of the remote procedure's parameters is a pointer to an object, the client must transmit a copy of that object and its pointer to the server. If the remote procedure modifies the object through its pointer, the server returns the pointer and its modified copy.

MIDL offers pointer attributes to minimize the amount of required overhead and the size of your application.

For example, you can specify a binary tree using the following definition:

typedef struct _treetype {

    long               lValue;

    struct _treetype * left;

    struct _treetype * right;

} TREETYPE;

TREETYPE * troot;

The contents of a tree node can be accessed by more than one pointer, making it more complicated for the RPC support code to manage the data and the pointers. The underlying stub code must resolve the various pointers to the addresses and determine whose copy of the data represents the latest and greatest version.

The amount of processing can be reduced if you guarantee that your pointer is the only way the application can access that area of memory. The pointer can still have many of the features of a C pointer. It can change between null and non-null values or stay the same. But as long as the data referenced by the pointer is unique to the pointer, you can reduce the amount of processing by the stubs. Designate such a pointer using the unique attribute.

You can further reduce the complexity if you specify that the non-null pointer to an address of valid memory will not change during the remote call. The contents of memory can change and the data returned from the server will be written into this area on the client. Designate such a pointer, known as a reference pointer, using the ref attribute.


Reference Pointers

Reference pointers are the simplest pointers and require the least amount of processing by the client stub. Reference pointers are mainly used to implement reference semantics and allow for out parameters in C.

In the example below, the value of the pointer does not change during the call. The contents of the data at the address indicated by the pointer can change.

A reference pointer has the following characteristics:

•	It always points to valid storage and never has the value NULL.

•	It never changes during a call and always points to the same storage before and after the call.

•	Data returned from the callee is written into the existing storage.

•	The storage pointed to by a reference pointer can't be accessed by any other pointer or any other name in the function.


Unique Pointers

Unique pointers can change in value, but like reference pointers, they do not cause aliasing of data — that is, the data that is accessible through the pointer is not accessible through any other name in the remote operation. This constraint saves a significant amount of processing.

The pointer itself can change from a null to a non-null value or from a non-null to a null value during the call. In the following example, the pointer is null before the call and points to a valid string after the call:

By default, the unique pointer attribute is applied to all pointers that are not parameters. In Microsoft-extensions mode, this default setting can be changed with the pointer_default attribute.

A unique pointer has the following characteristics:

•	It can have the value NULL.

•	It can change from null to non-null during the call. When the value changes to non-null, new memory is allocated on return.

•	It can change from non-null to null during the call. When the value changes to NULL, the application is responsible for freeing the memory.

•	If the value changes from one non-null value to another non-null value, the change is ignored.

•	The storage a unique pointer points to can't be accessed by any other pointer or any other name in the operation.

•	Return data is written into existing storage if the pointer does not have the value NULL.


Full Pointers

Full pointers have all the properties of unique pointers. In addition, full pointers support aliasing, which means that multiple pointers can refer to the same data, as shown in the following figure:


Pointers and Memory Allocation

The ability to change memory through pointers often requires that the server and the client allocate enough memory for the elements in the array.

Whenever a stub must allocate or free memory, it calls run-time library functions that in turn call the functions midl_user_allocate and midl_user_free. These functions are not provided as part of the run-time library. You must write your own versions of these functions and link them with your application. This design lets you decide how to manage memory.

You must write these functions to the following prototypes:

void __RPC_FAR * __RPC_API midl_user_allocate(size_t len)

void __RPC_API midl_user_free(void __RPC_FAR * ptr)

For example, the versions of these functions for an application can simply call standard library functions:

void __RPC_FAR * __RPC_API midl_user_allocate(size_t len)

{

    return(malloc(len));

}

void __RPC_API midl_user_free(void __RPC_FAR * ptr)

{

    free(ptr);

}


Program Efficiency Using Pointer Parameters

The in, out, and in, out directional attributes significantly affect the amount of stub code when they are applied to pointer parameters.


Default Pointer Types for Pointers

The MIDL compiler offers three different default cases for pointers that do not have pointer attributes at definition time:

•	Function parameters that are top-level pointers default to ref pointers.

•	Pointers embedded in structures and pointers to other pointers (non-top-level pointers) default to the type specified by the pointer_default attribute.

•	When no pointer_default attribute is supplied, non-top-level pointers default to unique pointers in Microsoft-extensions mode and to ptr in DCE-compatible mode.

A pointer returned by a function must be a unique or full pointer. The MIDL compiler reports an error if a function result is, either explicitly or by default, a reference pointer. The returned pointer always indicates new storage because there is not enough information for the stubs to determine whether there is existing storage in the caller address space for pointer-valued function results.

Functions that return a pointer value can specify a pointer attribute as a function attribute. If a pointer attribute is not present, the function return pointer uses the value provided by the pointer_default attribute.

Note  To ensure unambiguous pointer-attribute behavior, always use explicit pointer attributes when defining a pointer.


Using Arrays, Strings, and Pointers

The Doctor program is a good example of an application that demonstrates the design tradeoffs involved with array and string attributes. The Doctor program is a small sample version of a better-known program, Eliza, developed by artificial intelligence researcher Joseph Weizenbaum at MIT in the 1960s. The program mimics a therapist by using simple pattern-matching to respond to natural language input.

The Eliza program recorded the following session:

User	Eliza
Men are all alike.	In what way?
They're always bugging us about something or other.	Can you think of a specific example?
Well, my boyfriend made me come here.	Your boyfriend made you come here.
He says I'm depressed much of the time.	I am sorry to hear that you are depressed.
It's true, I am unhappy.	Do you think coming here will help you not to be unhappy?
I need some help; that much seems certain.	What would it mean to you if you got some help?
Perhaps I could learn to get along with my mother.	Tell me more about your family.
My mother takes care of me.	Who else in your family takes care of you?
My father.	Your father.
You are like my father in some ways.	What resemblance do you see?
The Doctor program can be split into client-side and server-side applications. The client side prompts the patient for input and displays the doctor's response. The server side processes the patient input and generates the doctor's response. This is a classic example of a client-server application: the client is responsible for user interaction, while the server handles the extensive computational load. Not much data is passed to and returned by the function, but the data can require a significant amount of processing so it is processed by the server.

The Doctor program uses a character array for input and returns another character array as output. We will examine the design tradeoffs of several alternative interfaces that manage these parameters.

Each section contains a short review of the attributes or the effects of combining the attributes.

Approach	Attributes or functions
Counted character arrays	size_is, length_is, ref
Stub-managed strings	string, ref, midl_user_allocate on server
Stub-managed strings	string, unique, midl_user_allocate on client and server
Function that returns a string	unique
Knowing the constraints associated with these combinations of attributes, we can examine several alternative ways to send one character array from client to server and to return another character array from server to client.


Counted Character Arrays

The size_is attribute indicates the upper bound of the array. The length_is attribute indicates the number of array elements to transmit. In addition to the array, the remote procedure prototype must include any variables representing length or size that determine the transmitted array elements (they can be separate parameters or bundled with the string in a structure). These attributes can be used with wide, byte, or character arrays just as they would be with arrays of other types.


in, out, size_is

The following function prototype uses a single-counted character array that is passed both ways: from client to server, and from server to client:

#define STRSIZE 500 //maximum string length

void Analyze(

    [in, out, length_is(*pcbSize), size_is(STRSIZE)] char  achInOut[],

    [in, out]  long *pcbSize);

As an in parameter, achInOut must point to valid storage on the client side. The developer allocates memory associated with the array on the client side before making the remote procedure call.

The stubs use the size_is parameter STRSIZE to allocate memory on the server, then use the length_is parameter pcbSize to transmit the array elements into this memory. The developer must make sure that the client code sets the length_is variable before calling the remote procedure:

/* client */

char achInOut[STRSIZE];

long cbSize;

...

gets(achInOut);                  // get patient input

cbSize = strlen(achInOut) + 1;   // transmit '\0' too

Analyze(achInOut, &cbSize);

In the previous example, the character array achInOut is also used as an out parameter. In C, the name of the array is equivalent to the use of a pointer; by default, all pointers are reference pointers, which do not change in value and which point to the same area of memory on the client before and after the call. All memory accessed by the remote procedure must fit the size specified on the client before the call or the stubs will generate an exception.

Before returning, the Analyze function on the server must reset the pcbSize variable to indicate the number of elements that the server will transmit to the client:

/* server */

Analyze(char * str, long * pcbSize)

{

   ...

   *pcbSize = strlen(str) + 1; // transmit '\0' too

   return;

}

Rather than using a single string for both input and output, you may find it more efficient and flexible to use separate parameters.


in, size_is and out, size_is

The following function prototype uses two counted strings. The developer must write code on both client and server to keep track of the character array lengths and pass parameters that tell the stubs how many array elements to transmit.

void Analyze(

    [in,  length_is(cbIn), size_is(STRSIZE)]    char  achIn[],

    [in]                                        long  cbIn,

    [out, length_is(*pcbOut), size_is(STRSIZE)] char  achOut[],

    [out]                                       long *pcbOut);

Note that the parameters that describe the array length are transmitted in the same direction as the arrays: cbIn and achIn are in parameters, while pcbOut and achOut are out parameters. As an out parameter, the parameter pcbOut must follow C convention and be declared as a pointer.

The client code counts the number of characters in the string, including the trailing zero, before calling the remote procedure:

/* client */

char achIn[STRSIZE], achOut[STRSIZE];

long cbIn, cbOut;

...

gets(achIn);                   // get patient input

cbIn = strlen(achIn) + 1;      // transmitted elements

Analyze(achIn, cbIn, achOut, &cbOut);

The remote procedure on the server supplies the length of the return buffer in cbOut:

/* server */

void Analyze(char *pchIn,

             long cbIn,

             char *pchOut,

             long *pcbOut)

{

   ...

   *pcbOut = strlen(pchOut) + 1; // transmitted elements

   return;

}

Knowing that the parameter is a string allows us to use the string attribute. The string attribute directs the stub to calculate the string size, eliminating the overhead associated with the size_is parameters.


Strings

The string attribute indicates that the parameter is a pointer to an array of type char, byte, or w_char. Like a conformant array, the size of a string parameter is determined at run time. Unlike a conformant array, the developer does not have to provide the length associated with the array. The string attribute tells the stub to determine the array size by calling strlen.

A string attribute cannot be used at the same time as the length_is or last_is attributes.

The in, string attribute combination directs the stub to pass the string from client to server only. The amount of memory allocated on the server is the same as the transmitted string size plus one.

The out, string attributes direct the stub to pass the string from server to client only. The call-by-value design of the C language insists that all out parameters must be pointers. (The key idea is that by passing the value of the address, the function can indirectly change the value stored at that address. If the value itself was passed, the function would only be able to modify its local copy of the value. For a more extensive explanation of the difference between call by value and call by reference, see any C-language programming book published by Microsoft Press.)

The out parameter must be a pointer, and by default, all pointer parameters are reference pointers. The reference pointer does not change during the call. It points to the same memory as before the call. For string pointers, the additional constraint of the reference pointer means that the client must allocate sufficient valid memory before making the remote procedure call. The stubs transmit the string indicated by the out, string attributes into the memory already allocated on the client side.


in, out, string

The following function prototype uses a single in, out, string parameter for both the input and output strings. The string first contains patient input and is then overwritten with the doctor response.

void Analyze([in, out, string, size_is(STRSIZE)] char  achInOut[]);

This example is similar to the one that employed a single-counted string for both input and output. Like that example, the size_is attribute determines the number of elements allocated on the server. The string attribute directs the stub to call strlen to determine the number of transmitted elements.

The client allocates all memory before the call:

/* client */

char achInOut[STRSIZE];

...

gets(achInOut);            // get patient input

Analyze(achInOut);

printf("%s\n", achInOut);  // display doctor response

Note that the Analyze function no longer must calculate the length of the return string, as it did in the counted-string example where the string attribute was not used. Now the length is calculated by the stubs:

/* server */

void Analyze(char *pchInOut)

{

   ...

   Respond(response, pchInOut); // don't need to call strlen

   return;                      // stubs handle size

}


in, string and out, string

The following function prototype uses two parameters: an in, string parameter and an out, string parameter.

void Analyze(

    [in, string]                       *pszInput,

    [out, string, size_is(STRSIZE)]    *pszOutput);

The first parameter is in only. This input string is only transmitted from the client to the server and is used as the basis for further processing by the server. The string is not modified and is not required again by the client, so it does not have to be returned to the client.

The second parameter, representing the doctor's response, is out only. This response string is only transmitted from the server to the client. The allocation size is provided so that the server stubs can allocate memory for it. Because pszOutput is a ref pointer, the client must have sufficient memory allocated for the string before the call. The response string is written into this area of memory when the remote procedure returns.


Multiple Levels of Pointers

You can use multiple pointers, such as a ref pointer to another ref pointer that points to the character array.

void Analyze(

   [in, string]                      char  *pszInput,

   [out, string, size_is(STRSIZE)]   char **ppszOutput);

When there are multiple levels of pointers, the attributes are associated with the pointer closest to the variable name. The client is still responsible for allocating any memory associated with the response.


Summary of Arrays and Pointers

MIDL defines three attributes that can be applied to pointers: full, unique, and reference. The different classifications help minimize the amount of processing by the stubs and make your distributed program as efficient as possible.


Binding and Handles

Binding is the process of creating a logical connection between a client and a server that the client uses to make remote procedure calls to that server. The binding between client and server is represented by a data structure called a binding handle.

A binding handle is analogous to a file handle returned by the fopen C run-time library function or a window handle returned by the function CreateWindow. Like these handles, the binding handle is opaque; your application cannot use it to directly access and manipulate data about that binding. The binding handle is a pointer or index into a data structure that is available only to the RPC run-time libraries. You provide the handle, and the run-time libraries access the appropriate data.

The client obtains a handle by calling RPC run-time functions that bind to the server, or by supplying a name or UUID to a service that provides the corresponding handle.

This section defines some characteristics of RPC binding handles and demonstrates their use in sample applications.

Note  In addition to binding handles, Microsoft RPC also supports serialization handles used to encode or decode data. These are used for serialization on a local computer and do not involve remote binding. For additional information on serialization handles, see Using Encoding Services.


Binding-Handle Types

MIDL provides several types of handles so you can select the handle type that is best suited for your application. See Using Encoding Services for additional information on using a primitive handle as a serializing handle.

•	Handles can be parameters that are passed to the remote procedure, or they can be global data structures that don't appear in the remote function prototype.

•	You can declare handles of the primitive handle type handle_t, or you can declare a handle type packaged in structures with other data.

•	Some handles are invisible to the client application and completely managed by the stubs, while others are declared, defined, and managed by the application.

•	A special type of handle, the context handle, allows you to maintain state information on the server in addition to acting as a binding handle.

The following table summarizes MIDL handle types:

Handle type	Characteristics
Primitive	A handle of the predefined type handle_t. Note that serializing handles (which are not binding handles) are also of the type handle_t. See Serialization Handles for more information.
Explicit	A handle used as a parameter to the remote procedure. The explicit handle usually appears as the first parameter for compatibility with DCE.
Implicit	A handle defined in the generated header file as a global variable that is available to the stubs. The developer defines the handle in the ACF only and does not include the handle as a parameter to the remote procedure call.
User-defined	A handle of the primitive type handle_t that is created by a user-supplied function that converts the user-defined data to the handle.
Auto	A handle that is automatically generated by the MIDL compiler and managed by the client run-time library. The client stub manages the binding and the handle; the client application does not require any explicit code to manage the binding or the handle.
Context	A handle that includes information about the state of the server. The context handle is automatically associated with specific user-defined functions on the server.
Handle characteristics can be combined in several ways, producing such types as explicit primitive, explicit user-defined, implicit primitive, and implicit user-defined handles. You can select the handle type that is best suited for your application.


Binding

The server registers its interface, then listens for requests from clients. Clients bind to the server by making calls to the RPC run-time functions. The most significant distinction between handle types is whether the application or the stub makes the calls to the RPC run-time functions to manage the binding handle. This leads to a discussion of two principal types of binding:

•	Auto binding

•	Application-managed binding

When you use auto binding and auto handles, the stubs automatically call the correct sequence of functions, and the application can't access the handle at all.

When you use application-managed binding, the client application explicitly calls a sequence of run-time functions to obtain a valid handle. The application-managed binding category includes all other types of handles besides auto handles: primitive, user-defined, and context handles.

The following figure shows this categorization of binding handles:


Auto Handles

Auto handles are useful when the application does not require a specific server and when it does not need to maintain any state information between the client and server. When you use an auto handle, you don't have to write any client application code to deal with binding and handles. You simply specify the use of the auto handle in the ACF. The stub then defines the handle and manages the binding.

For example, a time-stamp operation can be implemented using an auto handle. It makes no difference to the client application which server provides it with the time stamp. It can accept the time from any available server.

You specify the use of auto handles by including the auto_handle attribute in the ACF. The time-stamp example uses the following ACF:

/* ACF file */

[auto_handle]

interface autoh

{

}

Note  Auto handles are not supported for the Macintosh platform.

The auto handle is used by default when the ACF does not include any other handle attribute and when the remote procedures do not use explicit handles. The auto handle is also used by default when the ACF is not present.

The remote procedures are specified in the IDL file. The auto handle must not appear as an argument to the remote procedure:

/* IDL file */

[ uuid (6B29FC40-CA47-1067-B31D-00DD010662DA),

  version(1.0),

  pointer_default(unique)

]

interface autoh

{

void GetTime([out] long * time);

void Shutdown(void);

}

The benefit of the auto handle is that the developer does not have to write any code to manage the handle; the stubs manage the binding automatically. This is significantly different from the Hello, World example, where the client manages the implicit primitive handle defined in the ACF and must call several run-time functions to establish the binding handle.

Here, the stubs do all the work and the client need only include the generated header file AUTO.H to obtain the function prototypes for the remote procedures. The client application calls to the remote procedures appear just as if they were calls to local procedures:

/* auto handle client application (fragment) */

#include <stdio.h>

#include <time.h>

#include "auto.h"    // header file generated by the MIDL compiler

void main(int argc, char **argv)

{

    time_t t1;

    time_t t2;

    char * pszTime;

    ...

    RpcTryExcept {

GetTime(&t1);  // GetTime is a remote procedure

GetTime(&t2);

pszTime = ctime(&t1);

printf("time 1= %s\n", pszTime);

pszTime = ctime(&t2);

printf("time 2= %s\n", pszTime);

Shutdown();    // Shutdown is a remote procedure

}

RPCExcept(1)    {

...

}

RPCEndExcept

    exit(0);

}

The client application does not have to make any explicit calls to the client run-time functions. Those calls are managed by the client stub.

The server side of the application that uses auto handles must call the function RpcNsBindingExport to make binding information about the server available to clients. The auto handle requires a location service running on a server that is accessible to the client. The Microsoft implementation of the name service, the Microsoft Locator, manages auto handles. The server calls the following run-time functions:

/* auto handle server application (fragment) */

#include "auto.h" //header file generated by the MIDL compiler

void main(void)

{

    RpcUseProtseqEp(...);

    RpcServerRegisterIf(...);

    RpcServerInqBindings(...);

    RpcNsBindingExport(...);

    ...

}

The calls to the first two functions are similar to the Hello, World example; these functions make information about the binding available to the client. The calls to the RpcServerInqBindings and RpcNsBindingExport functions put the information in the name-service database. The call to RpcServerInqBindings fills the vector with valid data before the call to the export function. After the data has been exported to the database, the client (or client stubs) can call RpcNsBindingImportBegin and RpcNsBindingImportNext to obtain this information.

The calls to RpcServerInqBindings and RpcNsBindingExport and their associated data structures appear as follows:

RPC_BINDING_VECTOR * pBindingVector;

RPCSTATUS status;

status = RpcServerInqBindings(&pBindingVector);

status = RpcNsBindingExport(
fNameSyntaxType,      // name syntax type

pszAutoEntryName,     // nsi entry name

autoh_ServerIfHandle, // if server handle

pBindingVector,       // set in previous call

NULL);                // UUID vector

Note that the RpcServerInqBindings parameter &pBindingVector is a pointer to a pointer to RPC_BINDING_VECTOR.

The previous example demonstrates the parameters to the RpcNsBindingExport function that should be used with the Microsoft Locator, which is the Microsoft implementation of the name-service functions provided with Microsoft RPC.

For more information about the Microsoft Locator, see Run-time RPC Functions.

To remove the exported interface from the name-service database completely, the server calls RpcNsBindingUnexport:

status = RpcNsBindingUnexport(

                fNameSyntaxType,

                pszAutoEntryName,

                auto_ServerIfHandle,

                NULL);              // unexport handles only

The unexport function should be used only when the service is being permanently removed. It should not be used when the service is temporarily disabled, such as when the server is shut down for maintenance. A service can be registered with the name-service database but be unavailable because the server is temporarily off line. The client application should contain exception-handling code for such a condition. The calls to the remote procedures are surrounded by the exception-handling code.

For more information about exception handling, see Run-time RPC Functions.


Application-Initiated Binding

Applications bind to the server and obtain a handle that is used by the stubs to make remote procedure calls. When the client is finished making remote calls, the application can unbind from the server and invalidate the handle. A client application that manages its own binding and handles can obtain a handle in two ways:

•	Call RpcBindingFromStringBinding

•	Call the name-service functions RpcNsBindingImportBegin, RpcNsBindingImportNext, and RpcNsBindingImportDone

When the client explicitly calls RpcBindingFromStringBinding, the client must supply certain information to identify the server:

•	The globally unique identifier (GUID) or UUID of the object

•	The transport type over which to communicate, such as named pipes or TCP/IP

•	The network address, which for the named-pipe transport type is the server name

•	The endpoint, which for the named-pipe transport contains the pipe name

The object UUID and the endpoint information are optional.

The client or client stub communicates this identifying information to the RPC run-time library by means of a data structure called the string binding, which combines these elements using a specified syntax.

In the following examples, the pszNetworkAddress parameter and other parameters that include embedded backslashes can appear strange at first glance. In the C programming language, the backslash is an escape character, so two backslashes are needed to represent each single literal backslash character. The string-binding data structure must contain four backslash characters to represent the two literal backslash characters that precede the server name. The following example shows eight backslashes so that four literal backslash characters will appear in the string-binding data structure after processing by the sprintf function.

/* client application */

char * pszUuid = "6B29FC40-CA47-1067-B31D-00DD010662DA";

char * pszProtocol = "ncacn_np";

char * pszNetworkAddress = "\\\\\\\\servername";

char * pszEndpoint = "\\\\pipe\\\\pipename";

char * pszString;

int len = 0;

len  = sprintf(pszString, "%s", pszUuid);

len += sprintf(pszString + len, "@%s:", pszProtocolSequence);

if (pszNetworkAddress != NULL)

    len += sprintf(pszString + len, "%s", pszNetworkAddress);

len += sprintf(pszString + len, "[%s]", pszEndpoint);

In the following example, the string binding appears as follows:

6B29FC40-CA47-1067-B31D-00DD010662DA@ncacn_np:\\\\servername[\\pipe\\pipename]

The client then obtains the binding handle by calling RpcBindingFromStringBinding:

RPC_BINDING_HANDLE hBinding;

status = RpcBindingFromStringBinding(pszString, &hBinding);

...

A convenience function, RpcStringBindingCompose, assembles the object UUID, protocol sequence, network address, and endpoint into the correct syntax for the call to RpcBindingFromStringBinding. You don't have to worry about putting the ampersand and colon and the various components for each protocol sequence in the right place; you just supply the strings as parameters to the function. The run-time library even allocates the memory needed for the string binding.

char * pszNetworkAddress = "\\\\server";

char * pszEndpoint = "\\pipe\\pipename";

status = RpcStringBindingCompose(

            pszUuid,

            pszProtocolSequence,

            pszNetworkAddress,

            pszEndpoint,

            pszOptions,

            &pszString);

...

status = RpcBindingFromStringBinding(

            pszString,

            &hBinding);

...

Another convenience function, RpcBindingToStringBinding, takes a binding handle as input and produces the corresponding string binding.


Handles Managed by the Application

The handles managed by an application can be classified into two broad categories: context handles and binding handles. Context handles are used to maintain state information, while binding handles contain only information about the binding. Note that a serialization application also manages serialization handles, however, these are not binding handles. See Using Encoding Services for additional information on serialization handles.


Context Handles

A context handle contains context information created and returned by the server. Every application that uses a context handle must also specify an alternate method of binding, since an initial binding must be used before the server can return a context handle.

You create a context handle by specifying the context_handle attribute on a data-type definition in the IDL file. A context handle can also be associated with a special function called the context rundown routine, which is called by the server run-time library whenever an active binding to a client is broken unexpectedly.

In an interface that uses a context handle, if you do not also specify a primary implicit handle to contain the initial binding, the MIDL compiler generates an auto handle for you. It also generates the code in the client stub to perform auto binding.

For example, a file handle represents state information; it keeps track of the current location in the file. The file-handle parameter to a remote procedure call is packaged as a context handle. First, we define a structure that contains the file name and the file handle, as follows:

/* cxhndlp.c (fragment) */

typedef struct {

     FILE * hFile;

     char   achFile[256];

} FILE_CONTEXT_TYPE;

The IDL file defines the handle as a void * type and casts it to the required type on the server:

/* cxhndl.idl (fragment) */

typedef [context_handle] void * PCONTEXT_HANDLE_TYPE;

typedef [ref] PCONTEXT_HANDLE_TYPE * PPCONTEXT_HANDLE_TYPE;

The first remote procedure call initializes the handle and sets it to a non-null value. You must define the context with an out directional attribute in the IDL file:

/* cxhndl.idl (fragment) */

short RemoteOpen([out] PPCONTEXT_HANDLE_TYPE pphContext,

                 [in, string] unsigned char * pszFile);

The remote procedure RemoteOpen opens a file on the server:

/* cxhndlp.c (fragment)*/

short RemoteOpen(PPCONTEXT_HANDLE_TYPE pphContext,

 unsigned char         *pszFileName)

{

    FILE               *hFile;

    FILE_CONTEXT_TYPE  *pFileContext;

    if ((hFile = fopen(pszFileName, "r")) == NULL) {

        *pphContext = (PCONTEXT_HANDLE_TYPE) NULL;

return(-1);

    }

    else {

        pFileContext = (FILE_CONTEXT_TYPE *)

                       midl_user_allocate(sizeof(FILE_CONTEXT_TYPE));

        pFileContext->hFile = hFile;

        strcpy(pFileContext->achFile, pszFileName);

        *pphContext = (PCONTEXT_HANDLE_TYPE) pFileContext;

return(0);

    }

}

After the client calls RemoteOpen, the context handle contains valid data and is used as the binding handle. The client can free the explicit handle used to launch the context handle:

/* cxhndlc.c  (fragment)*/

printf("Calling the remote procedure RemoteOpen\n");

if (RemoteOpen(&phContext, pszFileName) < 0) {

printf("Unable to open %s\n", pszFileName);

Shutdown();

exit(2);

}

/* Now the context handle also manages the binding. */

status = RpcBindingFree(&hStarter);

printf("RpcBindingFree returned 0x%x\n", status);

if (status)

exit(status);

After the RemoteOpen function returns a valid, non-null context handle, subsequent calls use the context handle as an in pointer:

/* cxhndl.idl (fragment)*/

short RemoteRead(
[in] PCONTEXT_HANDLE_TYPE phContext,

[out] unsigned char  achBuf[BUFSIZE],

[out] short * pcbBuf);

short RemoteClose([in, out] PPCONTEXT_HANDLE_TYPE pphContext);

The client application reads the file until it encounters the end of the file; it then closes the file. The context handle appears as a parameter in the RemoteRead and RemoteClose functions.

/* cxhndlc.c (fragment)*/

printf("Calling the remote procedure RemoteRead\n");

while (RemoteRead(phContext, pbBuf, &cbRead) > 0) {

for (i = 0; i < cbRead; i++)

    putchar(*(pbBuf+i));

}

printf("Calling the remote procedure RemoteClose\n");

if (RemoteClose(&phContext) < 0 ) {

printf("Close failed on %s\n", pszFileName);

exit(2);

}

You must supply a context rundown routine that can be invoked when the connection is lost. A context handle will run down when the connection has closed and no RPC calls are in progress using the context handle. The context rundown routine uses the following syntax:

void type_rundown(type)

type

Specifies the context-handle type.

In the following example, the context rundown routine cleans up by closing the file handle.

/* The rundown routine is associated with the contxt handle type. */

void __RPC_USER PCONTEXT_HANDLE_TYPE_rundown(PCONTEXT_HANDLE_TYPE phContext)

{

    FILE_CONTEXT_TYPE *pFileContext;

    printf("Context rundown routine\n");

    if (phContext)

    {

    pFileContext = (FILE_CONTEXT_TYPE *) phContext;

    if (pFileContext->hFile != NULL)

        fclose(pFileContext->hFile);

    midl_user_free (phContext);

    }

}


Binding Handles

Every binding handle is either primitive or user defined, according to its data type. In addition to being primitive or user defined, every handle is either implicit or explicit, according to the way your application specifies the handle for each remote procedure call. These types combine to specify four kinds of binding handles:


Primitive Handles

A primitive handle is a handle with the data type handle_t. Ultimately, every handle is mapped to a primitive handle by the stubs.

Like a file handle or a window handle, a primitive handle is opaque; it contains information that is meaningful to the RPC run-time library but is not meaningful to your application.

The primitive handle is defined in the client source code as a handle of the base type handle_t using a statement such as the following:

handle_t hMyHandle;    // primitive handle


User-Defined Handles

A user-defined handle, also called a customized or generic handle, is a handle of a user-defined data type. You create a user-defined handle when you specify the handle attribute on a type definition in your IDL file.

You must also supply bind and unbind routines that the client stub calls at the beginning and end of each remote procedure call. The bind and unbind routines use the following function prototypes:

Function prototype	Description
handle_t type_bind(type)	Binding routine
void type_unbind(type, handle_t)	Unbinding routine
The following example shows how the user-defined handle is defined in the IDL file:

/* usrdef.idl */

[uuid(20B309B1-015C-101A-B308-02608C4C9B53),

version(1.0),

pointer_default(unique)

]

interface usrdef

{

typedef struct _DATA_TYPE {

    unsigned char * pszUuid;

    unsigned char * pszProtocolSequence;

    unsigned char * pszNetworkAddress;

    unsigned char * pszEndpoint;

    unsigned char * pszOptions;

} DATA_TYPE;

typedef [handle] DATA_TYPE * DATA_HANDLE_TYPE;

void UsrdefProc(
[in] DATA_HANDLE_TYPE  hBinding,

[in, string] unsigned char *   pszString);

void Shutdown([in] DATA_HANDLE_TYPE hBinding);

}

The user-defined bind and unbind routines appear in the client application. In the following example, the bind routine converts the string-binding information to a binding handle by calling RpcBindingFromStringBinding. The unbind routine frees the binding handle by calling RpcBindingFree.

The name of the user-defined binding handle, DATA_HANDLE_TYPE, appears as part of the name of the functions and appears as the parameter type in the function parameters:

/* This _bind routine is called by the client stub at the */

/* beginning of each remote procedure call                */

RPC_BINDING_HANDLE __RPC_USER DATA_HANDLE_TYPE_bind(DATA_HANDLE_TYPE dh1)

{

    RPC_BINDING_HANDLE hBinding;

    RPC_STATUS status;

unsigned char *pszStringBinding;

    status = RpcStringBindingCompose(
          dh1.pszUuid,

          dh1.pszProtocolSequence,

          dh1.pszNetworkAddress,

          dh1.pszEndpoint,

          dh1.pszOptions,

          &pszStringBinding);

          ...

    status = RpcBindingFromStringBinding(
          pszStringBinding,

          &hBinding);

          ...

    status = RpcStringFree(&pszStringBinding);

    ...

    return(hBinding);

}

/* This _unbind routine is called by the client stub at the end */

/* after each remote procedure call.                            */

void __RPC_USER DATA_HANDLE_TYPE_unbind(DATA_HANDLE_TYPE dh1,

                                      RPC_BINDING_HANDLE h1)

{

    RPC_STATUS status;

    status = RpcBindingFree(&h1);

    ...

}


Implicit Handles

An implicit handle is a handle that is stored in a global variable. You usually initialize the handle, then don't refer to it again until you destroy the binding. Each remote procedure call with an explicit binding-handle parameter uses the implicit handle. You create an implicit handle by specifying the implicit_handle attribute in the ACF for an interface:

/* ACF file (complete) */

[implicit_handle(handle_t hHello)

]

interface hello

{

}

The application uses the implicit handle only as a parameter to the RPC functions. The implicit handle is not used as a parameter to the remote procedure call:

status = RpcBindingFromStringBinding(

            pszStringBinding,

            &hHello);

...

status = RpcBindingFree(hHello);

...


Explicit Handles

An explicit handle is a handle that the client application specifies explicitly as a parameter to each remote procedure call. To conform to the OSF standard, the handle must be specified as the first parameter on each remote procedure. You create an explicit handle by declaring the handle as a parameter to the remote operations in the IDL file. The Hello, World example can be redefined to use an explicit handle as follows:

/* IDL file for explicit handles */

[ uuid(20B309B1-015C-101A-B308-02608C4C9B53),

  version(1.0)

]

interface hello

{

void HelloProc([in] handle_t h1,

               [in, string] char *  pszString);

}


Summary of Binding and Handles

Binding is the process of making a logical connection from a client to a server. A handle is a data structure that represents a binding. It is analogous to a file handle or a window handle.

There are two principal types of binding: automatic and application managed. Auto binding requires a locator service on the server and does not maintain state information between client and server. Application-managed binding is controlled using the string-binding data structure or the name service to obtain a handle.

Context handles maintain state information on the server. The server can supply a context rundown routine, which is called whenever an active binding to a client is broken unexpectedly.

If you use a context handle and do not specify a primary implicit handle, the MIDL compiler generates an auto handle to be used for the initial binding. It also generates the code in the client stub to perform auto binding.

Serialization handles are primitive handles used for data serialization. They cannot be used for binding.


Memory Management

With RPC, a single conceptual execution thread can be processed by two or more processing threads. These processing threads can run on the same computer or on different computers. RPC relies on the ability to simulate the client thread's address space in the server thread's address space and to return data, including new and changed data, from the server to the client memory.

Memory management in the context of RPC involves:

•	How the memory needed to simulate a single conceptual address space is allocated and deallocated in the different address spaces of the client and server's threads.

•	Which software component is responsible for managing memory — the application or the MIDL-generated stub.

•	MIDL attributes that affect memory management: directional attributes, pointer attributes, array attributes, and the ACF attributes byte_count, allocate, and enable_allocate.

As a developer, you can choose among several methods for selecting the way that memory is allocated and freed. Consider a complex data structure, such as a linked list or a tree, that consists of nodes connected with pointers. You can apply attributes that select the following models:

•	Node-by-node allocation and deallocation

•	A single, linear buffer for the entire tree allocated by the stub

•	A single, linear buffer for the entire tree allocated by the client application

•	Persistent storage on the server

Each of these models is described in detail in this chapter.

This section does not describe the use of different Intel-architecture memory models. For information about using different Intel-architecture memory models, see Building RPC Applications.


How Memory Is Allocated and Deallocated

Typically, stub code generated by the MIDL compiler calls user-supplied functions to allocate and free memory. These functions, named midl_user_allocate and midl_user_free, must be supplied by the developer and linked with the application.

All applications must supply implementations of midl_user_allocate and midl_user_free, even though the names of these functions might not appear explicitly in the stubs.

These user-supplied functions must match a specific defined function prototype but otherwise can be implemented in any way that is convenient or useful for the application.


midl_user_allocate

void __RPC_FAR * __RPC_USER midl_user_allocate (size_t cBytes);

cBytes

Specifies the count of bytes to allocate.

The midl_user_allocate function must be supplied by both client applications and server applications. Applications and generated stubs call midl_user_allocate directly or indirectly to manage allocated objects:

•	The client and server applications should call midl_user_allocate to allocate memory for the application — for example, when creating a new node.

•	The server stub calls midl_user_allocate when unmarshalling data into the server address space.

•	The client stub calls midl_user_allocate when unmarshalling data from the server that is referenced by an out pointer. Note that for in, out, unique pointers, the client stub calls midl_user_allocate only if the unique pointer value was NULL on input and changes to a non-null value during the call. If the unique pointer was non-null on input, the client stub writes the associated data into existing memory.

If midl_user_allocate fails to allocate memory, it should return a null pointer or raise a user-defined exception.

The midl_user_allocate function should return a pointer as follows:

•	For Windows NT running on Intel platforms, the pointer is 4 bytes aligned.

•	For Windows NT running on MIPS and Alpha platforms, the pointer is 8 bytes aligned.

•	For Windows 3.x and MS-DOS platforms, the pointer is 2 bytes aligned.

For example, the sample programs provided with the Win32 SDK implement midl_user_allocate in terms of the C function malloc:

void __RPC_FAR * __RPC_USER midl_user_allocate(size_t cBytes)

{

    return((void __RPC_FAR *) malloc(cBytes));

}

Note  If the Rpcss package is enabled (for example, as the result of using the enable_allocate attribute), RpcSmAllocate should be used to allocate memory on the server side. For additional information on enable_allocate, see MIDL Reference.


midl_user_free

void __RPC_USER midl_user_free(void __RPC_FAR * pBuffer);

pBuffer

Specifies a pointer to the memory that is to be freed.

The midl_user_free function must be supplied by both client applications and server applications. The midl_user_free function must be able to free all storage allocated by midl_user_allocate.

Applications and stubs call midl_user_free when dealing with allocated objects:

•	The server application should call midl_user_free to free memory allocated by the application — for example, when deleting a pointed-at node.

•	The server stub calls midl_user_free to release memory on the server after marshalling all out arguments, in, out arguments, and the function return value.

For example, the RPC Win32 sample program that displays "Hello, world" implements midl_user_free in terms of the C function free:

void __RPC_USER midl_user_free(void __RPC_FAR * p)

{

    free(p);

}

Note  If the Rpcss package is enabled (for example, as the result of using the enable_allocate attribute), RpcSmFree can be used to free memory. For additional information on enable_allocate, see MIDL Reference.


Memory-Management Models

A developer can choose from among several methods that select how memory is allocated and freed. Consider a complex data structure, such as a linked list or tree, that consists of nodes connected with pointers. You can apply attributes that select the following models:

•	Node-by-node allocation and deallocation

•	A single linear buffer allocated by the stub for the entire tree

•	A single linear buffer allocated by the client application for the entire tree

•	Persistent storage on the server

•	Rpcss Memory Management Model

Each of these models is described in detail in the following topics.


Node-by-Node Allocation and Deallocation

Node-by-node allocation and deallocation by the stubs is the default method of memory management for all parameters on both the client and the server. On the client side, the stub allocates each node with a separate call to midl_user_allocate. On the server side, rather than calling midl_user_allocate, private memory is used whenever posible. If midl_user_allocate is called, the server stubs will call midl_user_free to free the data. In most cases, using node-by-node allocation and deallocation instead of using allocate (all_nodes) will result in increased performance of the server side stubs.


Stub-Allocated Buffers

Rather than forcing a distinct call for each node of the tree or graph, you can direct the stubs to compute the size of the data and to allocate and free memory by making a single call to midl_user_allocate or midl_user_free. The ACF attribute allocate(all_nodes) directs the stubs to allocate or free all nodes in a single call to the user-supplied memory-management functions.

For example, consider the following binary tree data structure:

/* IDL file fragment */

typedef struct _TREE_TYPE {

    short sNumber;

    struct _TREE_TYPE * pLeft;

    struct _TREE_TYPE * pRight;

} TREE_TYPE;

typedef TREE_TYPE * P_TREE_TYPE;

The ACF attribute allocate(all_nodes) applied to this data type appears in the typedef declaration in the ACF as follows:

/* ACF file fragment */

typedef [allocate(all_nodes)] P_TREE_TYPE;

The allocate attribute can only be applied to pointer types. The allocate ACF attribute is a Microsoft extension to DCE IDL and requires the use of the MIDL compiler switch /ms_ext at MIDL compilation time.

When allocate(all_nodes) is applied to a pointer type, the stubs generated by the MIDL compiler traverse the specified data structure to determine the allocation size. The stubs then make a single call to allocate the entire amount of memory needed by the graph or tree. A client application can free memory much more efficiently by making a single call to midl_user_free. However, server stub performance is generally increased when using node-by-node memory allocation since the server stubs can often use private memory that requires no allocations.

For additional information, see Node-by-Node Allocation and Deallocation.


Application-Allocated Buffer

The ACF attribute byte_count directs the stubs to use a preallocated buffer that is not allocated or freed by the client support routines. The byte_count attribute is applied to a pointer or array parameter that points to the buffer. It requires a parameter that specifies the buffer size in bytes.

The client-allocated memory area can contain complex data structures with multiple pointers. Because the memory area is contiguous, the application does not have to make many calls to individually free each pointer and structure. Like the allocate(all_nodes) attribute, the memory area can be allocated or freed with one call to the memory-allocation routine or the free routine. Unlike the allocate(all_nodes) attribute, however, the buffer parameter is not managed by the client stub, but by the client application.

The buffer must be an out-only parameter. The buffer length in bytes must be an in-only parameter.

The byte_count attribute can only be applied to pointer types. The byte_count ACF attribute is a Microsoft extension to DCE IDL and requires the MIDL compiler switch /ms_ext at MIDL compilation time.

In the following example, the parameter pRoot uses byte count:

/* function prototype in IDL file (fragment) */

void SortNames(

    [in] short cNames,

    [in, size_is(cNames)] STRINGTYPE pszArray[],

    [in] short cBytes,

    [out, ref] P_TREE_TYPE pRoot  /* tree with sorted data */

);

The byte_count attribute appears in the ACF as follows:

/* ACF file (fragment) */

SortNames([byte_count(cBytes)] pRoot);

The client stub generated from these IDL and ACF files does not allocate or free the memory for this buffer. The server stub allocates and frees the buffer in a single call using the provided size parameter. If the data is too big for the specified buffer size, an exception is raised.


Persistent Storage on the Server

You can optimize your application so that the server stub does not free memory on the server at the conclusion of a remote procedure call. For example, when a context handle will be manipulated by several remote procedures, you can use the ACF attribute allocate(dont_free) to retain the allocated memory on the server.

The allocate(dont_free) attribute is added to the ACF typedef declaration in the ACF:

/* ACF file fragment */

typedef [allocate(all_nodes, dont_free)] P_TREE_TYPE;

When the allocate(dont_free) attribute is specified, the tree data structure is allocated, but not freed, by the server stub. When you make the pointers to such persistent data areas available to other routines — for example, by copying the pointers to global variables — the retained data is accessible to other server functions. The allocate(dont_free) attribute is especially useful for maintaining persistent pointer structures as part of the server state information associated with a context-handle type.


Rpcss Memory Management Model

The Rpcss package is the recommended memory management model. It provides the best overall stub performance for memory management. The default allocator/deallocator pair used by the stubs and runtime when allocating memory on behalf of the application is midl_user_allocate/midl_user_free. However, you can choose the Rpcss package instead of the default by using the ACF attribute enable_allocate.

The Rpcss package is enabled for MIDL-generated stubs automatically whenever full pointers are used, the arguments require memory allocation, or as a result of using the enable_allocate attribute. In /ms_ext mode, the Rpcss package is enabled only when the enable_allocate attribute is used. The enable_allocate attribute enables the Rpcss environment by the server side stubs. The client side is not affected in default mode; in /ms_ext mode, the client side becomes alerted to the possibility that the Rpcss package may be enabled.

When the Rpcss package is enabled, allocation of memory on the server side is accomplished with the private Rpcss memory management allocator and deallocator pair. You can allocate memory using the same mechanism by calling RpcSmAllocate (or RpcSsAllocate). Upon return from the server stub, all the memory allocated by the Rpcss package is automatically freed. The following example shows how to enable the Rpcss package:

/* ACF file fragment */

[ implicit_handle(handle_t GlobalHandle),

enable_allocate

]

{

}

/*Server management routine fragment. Replaces p=midl_user_allocate(size); */

p=RpcSsAllocate(size);	/*raises exception */

p=RpcSmAllocate(size, &status);	/*returns error code */

You can also enable the memory management environment for your application by calling the RpcSmEnableAllocate routine (and disable it by calling the RpcSmDisableAllocate routine). Once enabled, application code can allocate and deallocate memory by calling functions from the RpcSs* or RpcSm* package.


Who Manages Memory?

Generally, the stubs are responsible for packaging and unpackaging data, allocating and freeing memory, and transferring the data to and from memory. In some cases, however, the application is responsible for allocating and freeing memory. The following factors determine which component is responsible for memory management:

•	Whether the pointer is a top-level ref parameter or whether the pointer is embedded within another structure

•	Directional attributes applied to the parameter

•	Pointer attributes applied to the parameter

•	Function return values


Top-Level and Embedded Pointers

When discussing how pointers and their associated data elements are allocated in Microsoft RPC, you have to differentiate between top-level pointers and embedded pointers. It is also often useful to refer to the set of all pointers that are not top-level pointers.

Top-level pointers are those that are specified as the names of parameters in function prototypes. Top-level pointers and their referents are always allocated on the server.

Embedded pointers are pointers that are embedded in data structures, such as arrays, structures, and unions.

When embedded pointers are out-only and null on input, the server application can change their values to non-null. In this case, the client stubs allocate new memory for this data.

If the embedded pointer is not null on the client before the call, the stubs do not allocate memory on the client on return. Instead, the stubs attempt to write the memory associated with the embedded pointer into the existing memory on the client associated with that pointer, overwriting the data already there.

Out-only embedded pointers are discussed in Combining Pointer and Directional Attributes.

The term non-top-level pointers refers to all pointers that are not specified as parameter names in the function prototype, including both embedded pointers and multiple levels of nested pointers.


Directional Attributes Applied to the Parameter

The directional attributes in and out determine how the client and server allocate and free memory. The following table summarizes the effect of directional attributes on memory allocation:

Directional attribute	Memory on client	Memory on server
in	Client application must allocate before call.	Server stub allocates.
out	Client stub allocates on return.	Server stub allocates top-level pointer only; server application must allocate all embedded pointers. Server also allocates new data as needed.
in, out	Client application must allocate initial data transmitted to server; client stub allocates additional data.	Server stub allocates; server application allocates new data as needed.
The following table summarizes the effect of directional attributes on memory deallocation:

Directional attribute	Memory on client	Memory on server
(all cases)	Not freed	Freed by server stubs on return (subject to ACF attribute allocate)
Note that for out-only parameters, MIDL allocates only the memory required for the top-level pointer parameter. The generated stub does not chase, or dereference, subsequent pointers that are part of the out-only data structure. The server application must allocate and initialize all such pointers.


Length, Size, and Directional Attributes

The size-related attributes max_is and size_is determine how many array elements the server stub allocates on the server.

The length-related attributes length_is, first_is, and last_is determine how many elements are transmitted to both the server and the client.

Different directional attribute(s) can be applied to a declarator and the parameter specified by a field attribute. However, some combinations of different directional attributes can cause errors when they are applied to the declarator and to the field attribute parameter.

Consider a procedure with two parameters, an array and the transmitted length of the array. The italicized term dir_attr refers to the directional attribute applied to the parameter:

Proc1(

    [dir_attr] short * plength;

    [dir_attr, length_is(pLength)] short array[MAX_SIZE]);

The MIDL compiler behavior for each combination of directional attributes is described below:

Array	Length parameter	Stub actions during call from client to server	Stub actions on return from server to client
in	in	Transmit the length and the number of elements indicated by the parameter.	No data transmitted.
in	out	Not legal; MIDL compiler error.	Not legal; MIDL compiler error.
in	in, out	Transmit the length and the number of elements indicated by the length parameter.	Transmit the length only.
out	in	Transmit the length. If array size is fixed, allocate the array size on the server, but transmit no elements. If array size is not bound, not legal: MIDL compiler error.	Transmit the number of elements indicated by the length. Note that the length can be changed and can have a different value from the value on the client. Do not transmit the length.
out	out	Allocate space for the length parameter on the server but do not transmit the parameter. If the array size is fixed, allocate the array size on the server, but transmit no elements. If array size is not fixed, not legal: MIDL compiler error.	Transmit the length and the number of elements indicated by the length as set by the server application.
out	in, out	Transmit the length parameter. If the array size is bound, allocate the array size on the server, but transmit no elements.  If array size is not bound, not legal: MIDL compiler error.	Transmit the length. Transmit the number of array elements indicated by the length.
in, out	in	Transmit the length and the number of elements indicated by the parameter.	Do not transmit the length. Transmit the number of elements indicated by the length. Note that the length can be changed and can have a different value from the original value on the client.
in, out	out	Not legal; MIDL compiler error.	Not legal; MIDL compiler error.
in, out	in, out	Transmit the length and the number of elements indicated by the parameter.	Transmit the length and the number of elements indicated by the parameter.
In general, you should not modify the length or size parameters on the server side. If you change the length parameter, you can orphan memory. For more information, see Memory Orphaning.


Pointer Attributes Applied to the Parameter

Each pointer attribute (ref, unique, and ptr) has characteristics that affect memory allocation. The following table summarizes these characteristics:

Pointer attribute	Client	Server
Reference (ref)	Client application must allocate.	Special handling needed for for out-only non-top-level pointers.
Unique (unique)	If parameter, client application must allocate; if embedded, can be null.  Change from null to non-null causes client stub to allocate; change from non-null to null can cause orphaning.
Full (ptr)	If parameter, client application must allocate; if embedded, can be null. Change from null to non-null causes client stub to allocate; change from non-null to null can cause orphaning.
The ref attribute indicates that the pointer points to valid memory. By definition, the client application must allocate all the memory the reference pointers require.

The unique pointer can change from null to non-null. If the unique pointer changes from null to non-null, new memory is allocated on the client. If the unique pointer changes from non-null to null, orphaning can occur. For more information, see Memory Orphaning.


Combining Pointer and Directional Attributes

A few caveats apply to certain combinations of directional attributes and pointer attributes.

Embedded out-Only Reference Pointers

When you use out-only reference pointers in Microsoft RPC, the generated server stubs allocate only the first level of pointers accessible from the reference pointer. Pointers at deeper levels are not allocated by the stubs but must be allocated by the server application layer.

Consider an out-only array of reference pointers:

/* IDL file (fragment) */

typedef [ref] short * PREF;

Proc1([out] PREF array[10]);

In the preceding example, the server stub allocates memory for ten pointers and sets the value of each pointer to null. The server application must allocate the memory for the ten short integers that are referenced by the pointers and must set the ten pointers to point to the integers.

When the out-only data structure includes nested reference pointers, the server stubs allocate only the first pointer accessible from the reference pointer.

/* IDL file (fragment) */

typedef struct {

    [ref] small * psValue;

} STRUCT1_TYPE;

typedef struct {

    [ref] STRUCT1_TYPE * ps1;

} STRUCT_TOP_TYPE;

Proc2([out, ref] STRUCT_TOP_TYPE * psTop);

In the preceding example, the server stubs allocate the pointer psTop and the structure STRUCT_TOP_TYPE. The reference pointer ps1 in STRUCT_TOP_TYPE is set to null. The server stub does not allocate every level of the data structure. The server stub does not allocate the STRUCT1_TYPE or its embedded pointer, psValue.

out-Only Unique or Full Pointer Parameters Not Accepted

Out-only unique or full pointers are not accepted by the MIDL compiler. Such specifications cause the MIDL compiler to generate an error message.

The automatically generated server stub has to allocate memory for the pointer referent so that the server application can store data in that memory area. According to the definition of an out-only parameter, no information about the parameter is transmitted from client to server. In the case of a unique pointer, which can take the value NULL, the server stub doesn't have enough information to correctly duplicate the unique pointer in the server's address space, and the stub doesn't have any information about whether the pointer should point to a valid address or whether it should be set to NULL. Therefore, this combination is not allowed.

Rather than out, unique or out, ptr pointers, use in, out, unique or in, out, ptr pointers or use another level of indirection, such as a reference pointer that points to the valid unique or full pointer.


Function Return Values

Function return values are similar to out-only parameters because their data is not provided by the client application, but they are managed differently. Unlike out-only parameters, they are not required to be pointers. The remote procedure can return any valid data type except ref pointers and non-encapsulated unions.

Function return values that are pointer types are allocated by the client stub with a call to midl_user_allocate. Accordingly, only the unique or full pointer attribute can be applied to a pointer function-return type.


Memory Orphaning

When your distributed application uses an in, out, unique or in, out, ptr pointer parameter, the server side of the application can change the value of the pointer parameter to NULL. When the server subsequently returns the null value to the client, memory referenced by the pointer before the remote procedure call is still present on the client side but is no longer accessible from that pointer, except in the case of an aliased full pointer. This memory is said to be orphaned.

Memory can also be orphaned whenever the server changes an embedded pointer to a null value. For example, if the parameter points to a complex data structure such as a tree, the server side of the application can delete nodes of the tree.

Another situation that can lead to a memory leak involves conformant, varying, and open arrays containing pointers. When the server application modifies the parameter that specifies the array size or transmitted range so that it represents a smaller value, the stubs use the smaller value(s) to free memory. The array elements with larger indices than the size parameter are orphaned. Your application must free elements outside the transmitted range.

Repeated orphaning of memory on the client without freeing the unused memory can lead to a situation where the client runs out of available memory resources.


Summary
Summary of Memory Allocation Rules

The following table summarizes key rules regarding memory allocation:

MIDL element	Description
Top-level ref pointers	Must be non-null pointers.
Function return value	New memory always allocated for pointer return values.
unique, out or ptr, out pointer	Not allowed by MIDL.
Non-top-level unique, in, out or  ptr, in, out pointer that changes  from null to non-null	Client stubs allocate new memory on client on return.
Non-top-level unique, in, out pointer that changes from non-null to null	Memory is orphaned on client; client application is responsible for freeing memory and preventing leaks.
Non-top-level ptr, in, out pointer that changes from non-null to null	Memory will be orphaned on client if not aliased; client application responsible for freeing and preventing memory leaks in this case.
ref pointers	Client-application layer usually allocates.
Non-null in, out pointer	Stubs attempt to write into existing storage on client. If string and size increases beyond size allocated on the client, will cause a GP-fault on return.
The following table summarizes the effects of key IDL and ACF attributes on memory management:

MIDL feature	Client issues	Server issues
allocate (single_node),  allocate (all_nodes)	Determines whether one or many calls are made to the memory functions	Same as client, except private memory can often be used for allocate (single_node) [in] and [in,out] data
allocate(free) or allocate(dont_free)	(None; affects server)	Determines whether memory on the server is freed after each remote procedure call
array attributes max_is and size_is	(None; affects server)	Determines size of memory to be allocated
byte_count	Client must allocate buffer; not allocated or freed by client stubs	ACF parameter attribute determines size of buffer allocated on server
enable_allocate	Usually, none. However, the client may be using a different memory management environment.	Server uses a different memory management environment.  RpcSmAllocate should be used for allocations.
in attribute	Client application responsible for allocating memory for data	Allocated on server by stubs
out attribute	Allocated on client by stubs	out-only pointer must be ref pointer; allocated on server by stubs
ref attribute	Memory referenced by pointer must be allocated by client application	Top-level and first-level reference pointers managed by stubs
unique attribute	Non-null to null can result in orphaned memory; null to non-null causes client stub to call midl_user_allocate	(Affects client)
ptr attribute	(See unique)	(See unique)


Using Encoding Services

Microsoft RPC supports two methods for encoding and decoding, or "serializing," data. You can serialize on a procedure or type basis. Serialization means that the data is marshalled to and unmarshalled from buffers that you control. This differs from the traditional usage of RPC, in which the stubs and the RPC run-time library have full control of the marshalling buffers, and the process is transparent to you. You can use the buffer for storage on a permanent media, encryption, and so on. When encoding, the data is marshalled to a buffer, and the buffer is passed to you. When decoding, you supply a marshalling buffer with data in it, and the data is unmarshalled from the buffer to memory.

When you use procedure serialization, MIDL generates a serialization stub for the procedure decorated with serialization attributes. When you call this routine, you execute a serialization call instead of a remote call. The procedure arguments are marshalled to or unmarshalled from a buffer in the usual way, and you control the buffers.

In contrast, when type serialization occurs (a type is labelled with serialization attributes), MIDL generates routines to size, encode and decode objects of that type. To serialize data, you must call these routines in the appropriate way. Type serialization is a Microsoft extension and is only supported when using /ms_ext mode. By using the encode and decode attributes as interface attributes, RPC applies encoding to all the types and routines defined in the IDL file.

Note  You must supply adequately aligned buffers when using encoding services. The beginning of the buffer must be aligned at 8. For procedure serialization, each procedure call must marshal into or unmarshal from a buffer position aligned at 8. For type serialization, sizing, encoding and decoding must start at a position aligned at 8.


Procedure Encoding and Decoding

When you use procedure encoding and decoding, a procedure, rather than a type, is labeled with the encode and/or decode attribute. Rather than generating the usual remote stub, the compiler generates a serialization stub for the routine.

Just as a remote procedure must use a binding handle to make a remote call, a serialization procedure must use an encoding handle to use encoding services. If an encoding handle is not specified, a default implicit encoding handle is used to direct the call. On the other hand, if the encoding handle is specified, either as an explicit handle_t argument of the routine or by using the explicit_handle attribute, the developer must pass a valid handle as an argument of the call. For additional information on how to create a valid serialization handle, see Serialization Handles, Examples of Fixed Buffer Encoding, and Examples of Incremental Encoding.

Microsoft RPC allows for remote and serialization procedures to be mixed in one interface. Use caution when doing so, however. For implicit handles, the global implicit handle must be set to a valid binding handle before a remote call, and to a valid encoding or decoding handle before a serialization call.


Type Encoding and Decoding

The MIDL compiler generates up to three functions for each type to which the encode or decode attribute is applied. For example, for a user-defined type named MyType, the compiler generates code for the MyType_Encode, MyType_Decode, and MyType_AlignSize functions. For these functions, the compiler writes prototypes to STUB.H and source code to STUB_C.C. Generally, you can encode a MyType object with MyType_Encode and decode an object from the buffer using MyType_Decode. MyType_AlignSize is used if you need to know the size of the marshalling buffer prior to allocating it.

The following encoding function is generated by the MIDL compiler. It serializes the data for the object pointed to by pObject. The buffer is obtained according to method specified in the handle. After writing the serialized data to the buffer, you control the buffer. Note that the handle inherits the status from the previous calls and the buffers must be aligned at 8.

For an implicit handle:

void MyType_Encode (MyType __RPC_FAR * pObject);

For an explicit handle:

void MyType_Encode (handle_t Handle, MyType __RPC_FAR * pObject);

The following function deserializes the data from the application's storage into the object pointed to by pObject. You supply a marshalled buffer according to the method specified in the handle. Note that the handle may inherit the status from the previous calls and the buffers must be aligned at 8.

For an implicit handle:

void MyType_Decode (MyType __RPC_FAR * pObject);

For an explicit handle:

void MyType_Decode (handle_t Handle, MyType __RPC_FAR * pObject);

The following function returns the sum of the size in bytes of the type instance plus any padding bytes needed to align the data. This enables serializing a set of instances of the same or different types into a buffer while ensuring that the data for each object is appropriately aligned. MyType_AlignSize assumes that the instance pointed to by pObject will be marshalled into a buffer beginning at the offset aligned at 8.

For an implicit handle:

size_t MyType_AlignSize (MyType __RPC_FAR * pObject);

For an explicit handle:

size_t MyType_AlignSize (handle_t Handle, MyType __RPC_FAR * pObject);


Serialization Handles

An application uses the serializing procedures or the serializing support routines generated by the MIDL compiler in conjunction with a set of library functions to manipulate an encoding-services handle. Together, these functions provide a mechanism for customizing the way an application serializes data. For example, rather than using several I/O operations to serialize a group of objects to a stream, an application can optimize performance by serializing several objects of different types into a buffer and then writing the entire buffer in a single operation. The functions that manipulate serialization handles are independent of the type of serialization you are using.

A serializing handle is required for any serializing operation. All serializing handles must be managed explicitly by you. First, you create a valid handle with a call to one of the Mes*HandleCreate routines. Then, after the operation is complete, you release the handle with a call to MesHandleFree. Once the handle has been created or re-initialized, it represents a valid serialization context and can be used to encode or decode, depending on the type of the handle. A serialization handle can be either an encoding or decoding handle. The encoding handles are available in three styles: incremental, fixed buffer and dynamic buffer. The decoding handles are available in two styles: incremental and (fixed) buffer. A serialization handle can be used for procedure or type serialization, regardless of the handle style.


Implicit Versus Explicit Handles

You can declare a serialization handle with the primitive handle type, handle_t. The serialization handles can be explicit or implicit. An implicit handle must be specified in the ACF by using the implicit_handle attribute. Serializing procedures that do not have an explicit handle would then use the global variable corresponding to that handle in order to access a valid serializing context. When using type encoding, the generated routines supporting serialization of a particular type use the global implicit handle to access the serialization context. Note that remote routines may need to use the implicit handle as a binding handle. Be sure that the implicit handle is set to a valid serializing handle prior to making a serializing call.

An explicit handle is specified as a parameter of the serialization procedure prototype in the IDL file, or it can also be specified by using the explicit_handle attribute in the ACF. The explicit handle parameter is used to establish the proper serialization context for the procedure. To establish the correct context in the case of type serialization, the compiler generates the supporting routines that use explicit handle_t parameter as the serialization handle. You must supply a valid serializing handle when calling a serialization procedure or serialization type support routine.


Serialization Styles

There are three styles you can use to manipulate serialization handles. These are: fixed buffer, dynamic buffer, and incremental. Regardless of the style you use, you must create either an encoding or decoding handle, serialize the data, and then free the handle. The style is set by creating the handle and defining the way a buffer is manipulated. The handle maintains the appropriate context associated with each of the three serialization styles.

Fixed Buffer Serialization

When using the fixed buffer style, specify a buffer that is large enough to accommodate the encoding (marshalling) operations performed with the handle. When unmarshalling, you provide the buffer that contains all of the data to decode.

The fixed buffer style of serialization uses the following routines:

•	MesEncodeFixedBufferHandleCreate

•	MesDecodeBufferHandleCreate

•	MesBufferHandleReset

•	MesHandleFree

MidlEncodeFixBufferHandleCreate allocates the memory needed for the encoding handle and then initializes it. It has the following prototype:

RPC_STATUS RPC_ENTRY MesEncodeFixedBufferHandleCreate (

char * Buffer,	/* user-supplied buffer */

unsigned long BufferSize,	/* size of the user-supplied
/* buffer */

unsigned long *pEncodedSize,	/* pointer to size of
/* encoding */

handle_t *pHandle);	/* pointer to the new
/* handle */

The application can call the MesBufferHandleReset function to reinitialize the handle, or it can call the MesHandleFree function to free the handle's memory. To create a decoding handle corresponding to the fixed style encoding handle, you must use the MesDecodeBufferHandleCreate routine.

RPC_STATUS RPC_ENTRY MesDecodeBufferHandleCreate (

char * Buffer,	/* buffer with data to
/* decode */

unsigned long BufferSize,	/* number of bytes of
/* data to decode in buffer */

handle_t *pHandle);	/* pointer to new handle 	*/

The application calls MesHandleFree to free the encoding or decoding buffer handle.

RPC_STATUS RPC_ENTRY MesHandleFree (

handle_t Handle);	/* handle to free */

Examples of Fixed Buffer Encoding

The following section provides an example of how to use a fixed buffer style serializing handle for procedure encoding.

/*This is a fragment of the IDL file defining FooProc */

...

void __RPC_USER

FooProc( [in] handle_t Handle, 	[in,out] FooType * pFooObject,

 [in, out] BarType * pBarObject);

...

/*This is an ACF file. FooProc is defined in the IDL file */

[	explicit_handle

]

interface regress

{

[ encode,decode ]	FooProc();

}

The following excerpt represents a part of an application.

if (MesEncodeFixedBufferHandleCreate (Buffer, BufferSize,
pEncodedSize, &Handle) == RPC_S_OK)

{

...

/* Manufacture a FooObject and a BarObject */

...

/* The serialize works from the beginning of the buffer because the 	handle is in the initial state. The FooProc does the following 	when called with an encoding handle:

 - sizes all the parameters for marshalling,

 - marshalls into the buffer (and sets the internal state 	appropriately)

*/

FooProc ( Handle, pFooObject, pBarObject );

...

MesHandleFree ();

}

if (MesDecodeBufferHandleCreate (Buffer, BufferSize, &Handle) ==

RPC_S_OK)

{

/* The FooProc does the following for you when called with a decoding

handle:

 - unmarshalls the objects from the buffer into *pFooObject and 	*pBarObject

*/

FooProc ( Handle, pFooObject, pBarObject);

...

MesHandleFree ( Handle );

}

The following section provides an example of how to use a fixed buffer style serializing handle for type encoding.

/* This is an ACF file. FooType is defined in the IDL file */

[	explicit_handle

]

interface regress

{

typedef [ encode,decode ] FooType;

}

The following excerpt represents the relevant application fragments.

if (MesEncodeFixedBufferHandleCreate (Buffer, BufferSize, 	pEncodedSize, &Handle) == RPC_S_OK)

{

...

/* Manufacture a FooObject and a pFooObject */

...

FooType_Encode ( Handle, pFooObject );

...

MesHandleFree ();

}

if (MesDecodeBufferHandleCreate (Buffer, BufferSize, &Handle) ==

RPC_S_OK )

{

FooType_Decode (Handle, pFooObject);

...

MesHandleFree ( Handle );

}

Dynamic Buffer Serialization

When using the dynamic buffer style of serialization, the marshalling buffer is allocated by the stub. The data is encoded into this buffer and passed back to you. When unmarshalling, you supply the buffer that contains the data.

The dynamic buffer style of serialization uses the following routines:

•	MesEncodeDynBufferHandleCreate

•	MesDecodeBufferHandleCreate

•	MesBufferHandleReset

•	MesHandleFree

MesEncodeDynBufferHandleCreate allocates the memory needed for the encoding handle and then initializes it. It has the following prototype:

RPC_STATUS RPC_ENTRY MesEncodeDynBufferHandleCreate (

char **pBuffer,	/* pointer to buffer containing	/* encoded 	data */

unsigned long *pEncodedSize,	/* pointer to size of buffer
/* containing encoded data */

handle_t *pHandle);	/* pointer to the new handle */

The application can call the MesBufferHandleReset function to reinitialize the handle, or it can call the MesHandleFree function to free the handle's memory. To create a decoding handle corresponding to the dynamic buffer encoding handle, use the MesDecodeBufferHandleCreate routine. For prototypes of these routines, see Fixed Buffer Serialization.

Incremental Serialization

When using the incremental style, you supply three routines to manipulate the buffer when required by the stub. These routines are: Alloc, Read, and Write. The Alloc routine allocates a buffer of the required size. The Write routine writes the data into the buffer, and the Read routine retrieves a buffer that contains marshalled data. A single serialization call can make several calls to these routines.

The incremental style of serialization uses the following routines:

•	MesEncodeIncrementalHandleCreate

•	MesDecodeIncrementalHandleCreate

•	MesIncrementalHandleReset

•	MesHandleFree

The prototypes for the Alloc, Read, and Write functions that you must provide are as follows:

void __RPC_USER Alloc (

void *State,	/* application-defined pointer */

char **pBuffer,	/* returns pointer to allocated buffer */	unsigned int *pSize);	/* inputs requested bytes; outputs 	pBuffer size */

void __RPC_USER Write (

void *State,	/* application-defined pointer */

char *Buffer,	/* buffer with serialized data 	*/	unsigned int Size);	/* number of bytes to write from

Buffer */

void __RPC_USER Read (

void *State,	/* application-defined pointer */

char **pBuffer,	/* returned pointer to buffer with data	with data */

unsigned int *pSize);	/* number of bytes to read into

pBuffer */

The State input argument for all three functions is the application-defined pointer that was associated with the encoding services handle. The application can use this pointer to access the data structure containing application-specific information such as a file handle or stream pointer. Note that the stubs do not modify the State pointer other than to pass it to the Alloc, Read, and Write functions. During encoding, Alloc is called to obtain a buffer into which the data is serialized. Then, Write is called to enable the application to control when and where the serialized data is stored. When decoding, Read is called to return the requested number of bytes of serialized data from wherever the application stored it.

An important feature of the incremental style is that the handle keeps the state pointer for you. This pointer maintains the state and is never touched by the RPC code, except when passing the pointer to Alloc, Write, or Read function. The handle also maintains an internal state that makes it possible to serialize and deserialize several type instances to the same buffer by adding padding as needed for alignment. The MesIncrementalHandleReset function resets a handle to its initial state to enable reading or writing from the beginning of the buffer.

The Alloc and Write functions, along with an application-defined pointer, are associated with an encoding-services handle by a call to the MesEncodeIncrementalHandleCreate function. MesEncodeIncrementalHandleCreate allocates the memory needed for the handle and then initializes it. It has the following prototype:

RPC_STATUS RPC_ENTRY MesEncodeIncrementalHandleCreate (

void * UserState	,	/* application-defined pointer */

MIDL_ES_ALLOC Alloc,	/* pointer to Alloc function */

MIDL_ES_WRITE Write,	/* pointer to Write function */
handle_t *pHandle);	/* receives encoding services handle */

The application can call MesDecodeIncrementalHandleCreate to create a decoding handle, MesIncrementalHandleReset to reinitialize the handle, or MesHandleFree to free the handle's memory. The Read function, along with an application-defined parameter, is associated with a decoding handle by a call to the MesDecodeIncrementalHandleCreate routine. The function creates the handle and initializes it. It has the following prototype:

RPC_STATUS RPC_ENTRY MesDecodeIncrementalHandleCreate (

void * UserState	,	/* application-defined pointer */

MIDL_ES_READ Read,	/* pointer to Read function */

handle_t Handle);	/* handle to create and initialize */

The UserState, Alloc, Write, and Read parameters of MesIncrementalHandleReset can be NULL to indicate no change.

RPC_STATUS RPC_ENTRY MesIncrementalHandleReset (

handle_t Handle,	/* handle to reinitialize */

void * UserState	,	/* application-defined pointer */

MIDL_ES_ALLOC Alloc,	/* pointer to Alloc function */

MIDL_ES_WRITE Write,	/* pointer to Write function */

MIDL_ES_READ Read,	/* pointer to Read function */

MIDL_ES_CODE OpCode);	/* operations allowed */

RPC_STATUS RPC_ENTRY MesHandleFree (

handle_t Handle);	// handle to free

Examples of Incremental Encoding

The following section provides an example of how to use the incremental style serializing handle for type encoding.

/* This is an acf file. FooType is defined in the idl file */

[	explicit_handle

]

interface regress

{

typedef [ encode,decode ] FooType;

}

The following excerpt represents the relevant application fragments.

if (MesEncodeIncrementalHandleCreate (State, AllocFn, 	WriteFn, 	&Handle) == RPC_S_OK)

{

...

/* The serialize works from the beginning of the buffer because

the handle is in the initial state. The Foo_Encode does the

following:

- sizes *pFooObject for marshalling,

- calls AllocFn with the size obtained,

- marshalls into the buffer returned by Alloc, and

- calls WriteFn with the filled buffer

*/

Foo_Encode ( Handle, pFooObject );

...

}

if (MesIncrementalHandleReset (Handle, NULL, NULL, NULL, ReadFn,

MES_DECODE ) == RPC_OK)

{

/*The ReadFn is needed to reset the handle. The arguments

that are NULL do not change. You can also call

MesDecodeIncrementalHandleCreate (State, ReadFn, &Handle);

The Foo_Decode does the following:

- calls Read with the appropriate size of data to read and

receives a buffer with the data

- unmarshalls the object from the buffer into *pFooObject

*/

Foo_Decode ( Handle, pFooObject );

...

MesHandleFree ( Handle );

}


Obtaining an Encoding Identity

An application that is decoding encoded data can obtain the identity of the routine used to encode the data, prior to calling a routine to decode it. The MesInqProcEncodingId routine provides this identity. It has the following prototype:

RPC_STATUS RPC_ENTRY MesInqProcEncodingId (

handle_t Handle,	/* decoding handle */ 	PRPC_SYNTAX_IDENTIFIER pInterfaceId,	/* points
to location
the identity will be

written to*/

unsigned long __RPC_FAR * pProcNum);	/* number of
the routine

used to encode data */


The IDL and ACF Files

The MIDL design specifies two distinct files, the Interface Definition Language (IDL) file and the application configuration file (ACF). These files contain attributes that direct the generation of the C-language stub files that manage the remote procedure call. The purpose of distinguishing the files is to keep the network interface separate from characteristics that affect only the operating environment.

The IDL file specifies a network contract between the client and server — that is, the IDL file specifies what is transmitted between client and server. Keeping this information distinct from the information about the operating environment makes the IDL file portable to other environments.

The ACF specifies attributes that affect only local performance rather than the network contract.

Microsoft RPC also offers an option that allows you to combine the ACF and IDL attributes in a single IDL file. In /ms_ext mode, multiple interfaces can be combined in a single IDL file (and its ACF).

The syntax of MIDL is based on the syntax of the C programming language. Whenever a language concept in this description of MIDL is not fully defined, the C-language definition of that term is implied.

This section summarizes the attributes that are specified in the IDL and ACF files and the output files generated by the MIDL compiler. It is organized by topic. The same material is alphabetized and presented in more detail in the reference topics. For more information, see the MIDL Reference and the MIDL Command-Line Reference.


Attributes

Attributes are keywords that specify characteristics of the data in the remote procedure calls and characteristics of the interface. Most attributes appear within square brackets in the IDL and ACF files. The following table briefly describes categories of MIDL attributes that can appear in the IDL file:

Attribute category	Attributes	Description
Array attributes	max_is, size_is, first_is, last_is, length_is	Apply to the first dimension of an array
Directional attributes	in, out	Describe the direction in which the parameter is transmitted on the network; either or both in and out can be applied
Field attributes	switch_is, array attributes, pointer attributes, string, ignore	Apply to struct or union members
Function attributes	callback, call_as, idempotent, local, maybe, optimize, pointer attributes, usage attributes	Apply to the return type and characteristics of the function
Interface attributes	uuid, object, local, version, pointer_default, endpoint	Apply to the interface as a whole
Parameter attributes	Directional attributes, array attributes, pointer attributes, switch_is, string, context_handle	Describe the network-transmission characteristics of function parameters
Pointer attributes	ref, unique, iid_is, ptr	Describe characteristics of the pointer and its data
Type attributes	handle, ms_union, v1_enum,  transmit_as, switch_type, represent_as pointer attributes, field attributes	Apply to a type definition
Usage attributes	string, ignore, context_handle	Describes how the data object is used


The IDL File

The IDL file specifies an interface used by the client and the server. The interface consists of two parts, an interface header and an interface body.


Interface Header

The interface header specifies information about the interface as a whole. It must contain the uuid or local attribute, and whichever one you choose must occur exactly once. The version attribute may occur at most once. The interface header can also contain the attributes pointer_default and endpoint.

Interface attributes for imported files are optional. However, the top-level importing interface (also called the base interface) must have at least one uuid or local attribute. MIDL explicitly checks for one of these attributes.

The uuid Attribute

The uuid attribute designates a UUID that distinguishes one interface from other interfaces. The textual representation of a UUID is a string consisting of 8 hexadecimal digits followed by a hyphen, followed by 3 hyphen-separated groups of 4 hexadecimal digits, followed by a hyphen, followed by 12 hexadecimal digits. For example:

12345678-1234-ABCD-1234-0123456789AB

Use the command-line utility uuidgen to generate unique identifiers.

The version Attribute

The version attribute identifies a particular version of an interface in cases where multiple versions of the interface exist. The version keyword is followed by either a pair of decimal integers separated by a period, or a single decimal integer. The first of the two integers represents the major version number, and the second represents the minor version number of an interface. If a single integer is used, it represents the major version number. Both major and minor version numbers are short unsigned integers in the range between 0 and 65535, inclusive.

Leading zeros in a major or minor version-number specification are not significant. A version specification of 1.0001 is the same as 0001.001 and 1.1.

The endpoint Attribute

The endpoint attribute specifies a well-known port or ports (communication end-points) on which servers of the interface listen. Well-known port values are typically assigned by the central authority that owns the protocol.

The local Attribute

The local attribute, when used as an interface attribute, specifies that you want to use the MIDL compiler to generate header files only. Stubs are not generated and checks for transmissibility are omitted.

The pointer_default Attribute

The pointer_default attribute specifies the pointer attribute that is applied to an unattributed pointer specification in the IDL file, including unattributed pointers nested in structure and union fields and arrays. It is not applied to unattributed top-level pointer parameters, which default to ref.

Failing to supply a pointer_default attribute on an interface that contains an unattributed pointer results in a compile-time warning.


Interface Body

The interface body contains data types used in remote procedure calls and the function prototypes for the procedures to be executed remotely. The interface body can contain imports, pragmas, constant declarations, type declarations, and function declarations. In Microsoft-extensions mode, the MIDL compiler also allows implicit declarations in the form of variable definitions.

Base Types

Base types are the fundamental data types of MIDL. Other types in the interface must be derived from base types or from predefined types.

For example, MIDL does not allow you to specify parameters of type int orvoid * because the size of these types is not known or because the size varies among different computers. The automatically generated stubs must know the exact size of every data item to be transmitted.

The boolean type is an 8-bit data item that is implemented by the MIDL compiler as an unsigned char. In keeping with commonly followed programming practices, MIDL implements FALSE as 0 and TRUE as 1. When you use the Microsoft-extensions mode of the MIDL compiler, boolean initializations using 0 and 1 are allowed in addition to TRUE and FALSE. In DCE-compatibility mode, however, only the values TRUE and FALSE are allowed.

The byte type consists of 8 bits. The byte type is considered opaque data and consequently the value is not converted on transmission.

The char type is an unsigned 8-bit entity that maps to the unsigned char in C. MIDL translates all char types in the IDL file to unsigned char types in the generated header file. The user can change the default sign of char on the target system with the /char switch.

The handle_t type is used to declare a primitive handle in a type declaration or in a parameter list. Objects of type handle_t are not transmitted on the network.

The void keyword is valid in a function declaration or in a pointer declaration. In a function declaration, it designates a procedure with no arguments or a procedure that does not return a result. In a pointer declaration, void can only be used with the context_handle attribute.

The keyword int without a modifier is not a valid MIDL type. The hyper keyword designates a 64-bit integer. The long keyword designates a 32-bit integer. The short keyword designates a 16-bit integer. The small keyword designates an 8-bit integer. For more information, see signed and unsigned.

The float keyword designates a 32-bit floating-point number. The double keyword designates a 64-bit floating-point number. For more information, see signed and unsigned.

Predefined Types

The predefined types error_status_t and wchar_t are derived from the MIDL base types. The predefined type wchar_t is a wide-character type and is defined as an unsigned short. The predefined type error_status_t is the data type returned by the stubs when the stubs encounter a run-time error. Attributes specify how data is managed on the network. For example, when the function parameter represents a pointer, array, or union, the attributes direct the generation of stub code that packages the data for network transmission.

The import Directive

The import directive is closely related to the #include C-preprocessor macro. It directs the compiler to include, at the point of import, the data types defined in the imported files and to make them available for use in the interface. In contrast to the C #include macro, the import directive ignores procedure prototypes defined in imported files.

Pragmas

C-preprocessing directives such as #define are expanded by the C preprocessor during MIDL compilation and are not available at C-compile time. To avoid losing these C-preprocessor macro definitions, use the cpp_quote or pragma midl_echo directive. These directives take quoted strings as parameters, instructing the MIDL compiler to emit the parameter string into the generated header file in the same lexical position relative to other interface components.

Constant Declarations

Constant declarations allow you to associate a constant value with an identifier and use the identifier as part of an expression. Constant declarations are generated as #define statements in the header file. The MIDL compiler does not perform any range checking on integral expressions.

Constant declarations are limited to integral char, boolean, wchar_t, wchar_t *, char *, and void * types. The constant value is an expression whose operands are all constant integer literals, boolean expressions that are computable at compile time, or single characters or strings, depending on the const type. For more information, see const.


Structures

Normal C semantics apply to the fields of base types. Fields of more complex types, such as pointers, arrays, and other constructed types, can be modified by type or field_attributes. For more information, see struct.


Unions

Two fundamental types of discriminated unions are provided by MIDL: non-encapsulated_union and encapsulated_union. The discriminant of a non-encapsulated union is another parameter if the union is a parameter. It is another field if the union is a field of a structure. The definition of an encapsulated union is turned into a structure definition whose first field is the discriminant and whose second and last field is the union.

The Microsoft RPC MIDL compiler allows union declarations outside of typedef constructs. This feature is an extension to DCE IDL. For more information, see union, and /ms_ext.


Enumerated Types

The enum declaration is not translated into #define statements as is done by some DCE compilers but is reproduced as a C-language enum declaration in the generated header file.


Arrays

See arrays.


Type Attributes

Type attributes are the MIDL attributes that can be applied to type declarations: transmit_as, handle, ignore, switch_type, and context_handle, string, pointer attributes, and array attributes.

The transmit_as attribute instructs the compiler to associate a transmitted type with a presented type that client and server applications manipulate. You must supply the routines that carry out the conversion between the presented types and the transmitted types. Supply routines to release memory used to hold the converted data. Using the transmit_as attribute instructs the stub to call the supplied conversion routines before and after transmission. The represent_as attribute instructs the compiler to associate a local type with a transfer type that is transferred between client and server. You must supply the routines that convert between the local and the transfer types. Supply routines to release memory used to hold the converted data. Using the represent_as attribute instructs the stub to call the supplied conversion routines before and after transmission.

The handle attribute specifies that a type can occur as a user-defined, generic, or serialization handle. This feature permits the design of handles that are meaningful to the application. The user must provide binding and unbinding routines to convert between the user-defined handle type and the RPC primitive handle type handle_t. A primitive handle contains destination information meaningful to the RPC run-time libraries. A user-defined handle can only be defined in a type declaration, not in a function declaration. A parameter with the handle attribute has a double purpose. It is used to determine the binding for the call, and it is transmitted to the called procedure as a normal parameter.

The ignore attribute designates pointer fields to be ignored during the marshalling process. An ignored field is set to NULL on the receiver side when allocating memory. When used as a type attribute, the ignore attribute specifies that the ignored type can only be used as a field type.

The switch_type attribute designates the type of a union discriminator. This attribute applies only to a non-encapsulated union. The context_handle attribute allows the developer to write procedures that maintain state information between remote procedure calls. A context handle is a pointer with a context_handle attribute. A context handle with a non-null value represents saved context and serves two purposes. On the client side, it contains the information needed by the RPC run-time library to direct the call to the server. On the server side, it serves as a handle on active context.


Field Attributes

Field attributes are the attributes that can be applied to fields of an array, structure, or union: ignore, size_is, max_is, length_is, first_is, last_is, switch_is, and string, and pointer attributes. For example, field attributes are used in conjunction with array declarations to specify either the size of the array or the portion of the array that contains valid data. This is done by associating another parameter, another structure field, or a constant expression with the array.

The ignore attribute designates pointer fields to be ignored during the marshalling process. Such an ignored field is set to NULL on the receiver side.

Conformant Arrays (size_is, max_is Attributes)

An array is called conformant if its bounds are determined at run time. The size_is attribute designates the upper bound on the allocation size of the array. The max_is attribute designates the upper bound on the value of a valid array index. For more information, see arrays.

Varying and Open Arrays (length_is, first_is, last_is Attributes)

An array is called "varying" if its bounds are determined at compile time but the range of transmitted elements is determined at run time. An open array (also called a conformant varying array) is an array whose upper bound and range of transmitted elements are determined at run time. To determine the range of transmitted elements of an array, the array declaration must include a length_is, first_is, or last_is attribute.

The length_is attribute designates the number of array elements to be transmitted. The first_is attribute designates the index of the first array element to be transmitted. The last_is attribute designates the index of the last array element to be transmitted.

The switch_is Attribute

The switch_is attribute designates a union discriminator. When the union is a procedure parameter, the union discriminator must be another parameter of the same procedure. When the union is a field of a structure, the discriminator must be another field of the structure at the same level as the union field. The discriminator must be a boolean, char, integral, or enum type, or a type that resolves to one of these types. For more information, see non-encapsulated_union.

The string Attribute

The string attribute designates that a one-dimensional character or byte array or pointer to a zero-terminated character or byte stream is to be treated as a string. The string attribute only applies to one-dimensional arrays and pointers. The element type is limited to char, byte, wchar_t, or a named type that resolves to these types.


Three Pointer Types

MIDL supports three types of pointers to accommodate a wide range of applications. The three different levels are called reference, unique, and full pointers, indicated by the attributes ref, unique, and ptr, respectively. The pointer classes described by these attributes are mutually exclusive.

Pointer attributes can be applied to pointers in type definitions, function return types, function parameters, members of structures or unions, or array elements.

Embedded pointers are pointers that are members of structures or unions or elements of arrays. Embedded pointers can differ from top-level pointers depending upon directional attributes. In the in direction, embedded ref pointers are assumed to be pointing to valid storage and must not be null. This situation is recursively applicable to any ref pointers they are pointing to. In the in direction, embedded unique and full pointers may or may not be null.

Any pointer attribute placed on a parameter in the syntax of a function declaration affects only the rightmost pointer declarator for that parameter. To affect other pointer declarators, intermediate named types must be used.

Functions that return a pointer can have a pointer attribute as a function attribute. The unique and ptr attributes must be applied to function return types.

Member declarations that are pointers can specify a pointer attribute as a field attribute. A pointer attribute can also be applied as a type attribute in typedef constructs.

When no pointer attribute is specified as a field or type attribute, pointer attributes are applied according to the rules for unattributed pointer declaration, as follows:

In DCE-compatibility mode, pointer attributes are determined in the defining IDL file.  If there is a pointer_default attribute specified in the defining interface, that attribute is used. If no pointer_default attribute is present, all unattributed pointers are full pointers.

In Microsoft-extensions mode, pointer attributes can be determined by importing IDL files. Pointer attributes are applied in the following order:

1.	An explicit pointer attribute applied at the use site

2.	When the unattributed pointer is a top-level pointer parameter, the ref attribute

3.	A pointer_default attribute specified in the defining interface

4.	A pointer_default attribute specified in the base interface

5.	The unique attribute

The pointer_default interface attribute specifies the default pointer attributes to be applied to a pointer declarator in a type, parameter, or return type declaration when that declaration does not have an explicit pointer attribute applied to it. The pointer_default interface attribute does not apply to an unattributed top-level pointer of a parameter, which is assumed to be ref.


Function Declarations

The callback and local attributes can be applied as function attributes.

Callbacks are a special kind of remote call from server to client that executes as part of a conceptual single-execution thread. A callback is always issued in the context of a remote call (or callback) and is executed by the thread that issued the original remote call (or callback).

It's often desirable to place a local procedure declaration in the IDL file, just because this is the logical place to describe interfaces to a package. The local attribute indicates that a procedure declaration is not actually a remote function but a local procedure. The MIDL compiler does not generate any stubs for that function. For more information, see callback and local.


Parameter Declarations

The directional attributes in and out can be applied to parameters.

The in attribute indicates that the parameter is passed from the client to the server. The out attribute indicates that the parameter is passed from the server to the client. In DCE-compatibility mode, each parameter must have at least one explicit directional attribute. In Microsoft-extensions mode, a parameter without a directional attribute defaults to an in attribute.


Expressions

Expressions can be used as constant initializers, array bounds, and transmission-range specifiers, and union discriminators. For more information, see version.


Error Handling

Caller stubs report run-time errors to application code in one of the three following ways:

•	When the return type of a remote procedure is error_status_t, the error is returned as the procedure return value.

•	When the procedure has an out parameter of type error_status_t *, the error is returned as the value of this parameter.

•	In any other case, the stub raises an exception.

Server stubs report run-time errors to application code by raising an exception. For more information, see error_status_t, comm_status and fault_status.


The ACF

The application configuration file (ACF) has two parts: an interface header similar to the interface header in the IDL file, and a sequence of attributes with values.

The ACF specifies behavior on the local computer and does not affect the data transmitted over the network. The ACF is used to specify details of a stub to be generated. In DCE-compatibility mode, the ACF does not affect interaction between stubs but between the stub and application code.

A parameter specified in the ACF must be one of the parameters specified in the IDL file. The order of specification of the parameter in the ACF is not significant because the matching is by name, not by position. The parameter list in the ACF can be empty, even when the parameter list in the corresponding IDL signature is not. Abstract declarators (unnamed parameters) in the IDL file cause the MIDL compiler to report errors while processing the ACF because the parameter is not found.

The include Declaration

The include statement specifies one or more header files to be included into generated stub code via the C-preprocessor #include statement. The user must supply the C header file when compiling the stubs. The ACF include statement provides some flexibility in distributed application design. It is necessary for certain types, such as implicit_handle types that are not defined in the IDL or its closure under #include and import directives.

Implicit Binding Handles

When an interface contains one or more functions whose first parameter is not an explicit handle and that do not have an in or an in, out context handle bound to a remote address space, an implicit handle is needed. The implicit_handle and auto_handle attributes provide this capability.

The implicit_handle attribute specifies a global variable that is used as the RPC binding handle for all calls without a binding parameter.

The auto_handle attribute indicates that any function needing implicit handles is automatically bound. When no binding handle to a server exists just prior to calling the function for the first time, the stub automatically establishes a binding handle for the call.

Either auto_handle or implicit_handle can appear, but not both. When a function in the interface requires an implicit handle and no ACF is supplied, or the supplied ACF does not specify either implicit_handle or auto_handle, the MIDL compiler uses auto_handle and issues an informational message.

The code and nocode Attributes

If code appears in the interface attribute list, client stub code is generated for any function in the interface that does not appear in the ACF with a nocode in its function attribute list and that does not have a local attribute.

If nocode appears in the interface attribute list, stub code is generated only for functions in the interface that appear in the ACF with a code in their function attribute lists and that do not have a local attribute.

The nocode attribute is ignored when server stubs are generated. Applying nocode when generating server stubs in DCE-compatibility mode is an error. Either code or nocode can appear in an function attribute list, but not both.

The allocate Attribute

The allocate attribute allows you to customize the allocation and deallocation patterns used by the application and stubs. It can be applied to pointer types as a type attribute or as an interface attribute. When it occurs as an interface attribute, it affects all pointer parameters and types in the interface.

allocate attribute	Description
allocate(single_node)	Storage for each node on both the caller and callee side is allocated separately, by calling midl_user_allocate.
allocate(all_nodes)	The size of the total graph (or tree) is precomputed by the stub, and midl_user_allocate is called once to allocate sufficient memory for all nodes in the graph upon return from a remote call. In this case application code has to release this storage by making a single call to midl_user_free.
allocate(free)	Storage allocated for nodes on the callee side is freed by stubs upon return from the manager code.
allocate(dont_free)	Storage allocated for nodes on the server side is not deallocated by the server stub. This feature is useful for maintaining persistent pointer structures as part of the server application.
The byte_count Attribute

The byte_count ACF attribute associates a pointer parameter with another parameter that specifies the size in bytes of the memory area indicated by the pointer. Memory referenced by the pointer parameter is contiguous and is not allocated or freed by the client stubs. This feature of the byte_count attribute allows the developer to create a persistent buffer area in client memory that can be reused across multiple calls.

The parameter providing the buffer must be an out pointer parameter and the parameter providing the length in bytes must be an in parameter of integral type. The byte_count attribute cannot be specified on a parameter that has the size attributes (size_is, max_is) applied to it.


Using ACF Attributes in the IDL File

The Microsoft RPC MIDL compiler offers an operating mode that makes it possible to provide one file that contains both the IDL attributes and selected ACF attributes. You can supply the ACF attributes auto_handle and implicit_handle in the IDL file when you use the MIDL compiler switch /app_config.


MIDL Compiler Output

With the IDL and ACF files as input, the MIDL compiler generates up to five C-language source files. By default, the MIDL compiler uses the base filename of the IDL file as part of the generated stub files. When more than six characters are present in the base filename, some file systems may not accept the full stub name. The following conventions are used:

File	Default portion  of base filename	Example
IDL file	---	ABCDEFGH.IDL
Header	.H	ABCDEF.H
Client stub	_C.C	ABCDEF_C.C
Server stub	_S.C	ABCDEF_S.C


Introduction to Run-Time RPC Functions
Run-Time RPC Functions

The RPC functions are those your distributed application calls to establish a binding handle that represents the logical connection between a client and a server. The binding handle enables the RPC run-time libraries to direct a client's remote procedure call to an instance of the specified interface on a server.

Obtaining the binding handle involves several data structures or strings:

•	Protocol sequence and network address strings

•	Endpoints

•	Interface UUIDs and interface version numbers

•	Object UUIDs

•	Name-service database server entries

This section describes these data structures and strings, and the RPC functions that allow your application to manipulate them.

The name-service functions allow a server to register its interface in a database. When a server registers its interface, a client can query the database, supplying a logical name and an optional object UUID, to obtain a binding handle to the server without knowing the host name of the server.

The RPC name service makes distributed applications easy to administer. When the server side of the distributed application is moved to another computer, clients do not have to be reconfigured. As long as the database entry name and object UUIDs remain the same, client applications can access the server application as they did before. In addition, you can run several instances of the server on different hosts, thereby providing clients with random load balancing.

You can provide more than one implementation of the remote procedure calls defined in an interface. RPC maps a remote procedure call to an implementation of the procedure through a table of function pointers known as the manager entry-point vector (EPV). You can add implementations of the procedure by supplying additional manager EPVs. The client selects the appropriate implementation of the function.

You can also add security to your distributed application in two ways: by installing a security package and calling the RPC functions related to security, or by using the security features built into Windows NT transport protocols.

The set of RPC functions supported by Microsoft RPC overlaps the DCE RPC functions. The Microsoft RPC functions are optimized for use with the MS-DOS, Microsoft Windows, and Microsoft Windows NT operating systems. They are fully compatible with other Microsoft naming and calling conventions.

For a complete description of each function and data structure in Microsoft RPC, see the RPC Function Reference.


Naming Conventions for RPC Functions

RPC function names generally consist of the prefix "Rpc," an object name, and a verb that describes an operation on that object. The functions, with some exceptions, are named as follows:

RpcObjectOperation

Object

Specifies a term that identifies an RPC object; a data structure defined by the RPC function.

Operation

Specifies an operation that is performed on the object specified by Object.

Functions that operate on UUID objects omit the prefix "Rpc" and start with the object name "Uuid."

The functions provided with this version of Microsoft RPC operate on the following objects:

Object	Object in  function name	Example
Binding handle	Binding	RpcBindingFree
Endpoint	Ep	RpcEpRegister
Interface	If	RpcIfInqId
Management	Mgmt	RpcMgmtStopServerListening
Name-service group entry	NsGroup	RpcNsGroupDelete
Name-service management	NsMgmt	RpcNsMgmtEntryCreate
Name-service profile entry	NsProfile	RpcNsProfileEltAdd
Name-service server entry	NsBinding	RpcNsBindingExport
Network	Network	RpcNetworkInqProtseqs
Object, type UUID mapping	Object	RpcObjectSetType
Protocol-sequence vector	ProtseqVector	RpcProtseqVectorFree
Server	Server	RpcServerListen
String	String	RpcStringFree
String binding	StringBinding	RpcStringBindingCompose
UUID	Uuid	UuidCreate
Microsoft RPC function names are derived by converting the first character of the DCE RPC function name and every character that follows an underscore character to uppercase and then removing underscore characters. For example, the DCE function rpc_server_use_all_protseqs_if is named RpcServerUseAllProtseqsIf in Microsoft RPC.

Microsoft data-structure names are derived from the DCE names by converting all characters to uppercase and removing the trailing suffix _t. For example, the DCE data structure rpc_binding_vector_t is named RPC_BINDING_VECTOR in Microsoft RPC.

In the header files provided in Microsoft RPC, each RPC function that takes character-string parameters appears in two forms: followed by the suffix "A" and followed by the suffix "W." The "A" suffix represents the ASCII-character-string version of the function and the "W" suffix represents the wide-character-string version. The identifier UNICODE determines which version of the function is selected. The standard function name is mapped to either the ASCII or the wide-character-string version.

Wide-character versions of the RPC functions are selected when you define the identifier UNICODE. You can define the identifier either with a #define preprocessor directive or with the /D option of the Microsoft C/C++ version 7.0 compiler. For example:

#define UNICODE
main()

cl /DUNICODE filename.c

You can use the wide-character version of a function on one side of the distributed application and the ASCII version on the other side. You do not need to use the same versions of the functions with both the client and server applications. You can use both versions in the same application.


Data Structures

Obtaining the handle that represents the binding between clients and servers involves several key data structures:

•	Binding handle

•	Protocol sequence and network address string

•	Endpoint

•	Interface UUIDs and interface version number

•	Object UUID

•	Name-service database entries, including profile, group, and server entries


Binding Handle

One purpose of the RPC run-time functions is to provide the client with a binding handle to the server. A binding handle is a data structure that represents the logical connection between the client and the server.

Like a file handle or a window handle, a binding handle cannot be used to directly access and manipulate data about the binding itself. Instead, the binding handle is a unique identifier that the RPC run-time libraries use to access the appropriate data.

The components of a string binding offer a simple way to explain some of the data structures used to obtain a binding handle. Note, however, that creating a binding from a string binding is not recommended. Most applications should use the name-service functions.


String Binding

The string binding is a character string that consists of several sub-strings. The strings in a string binding represent the object UUID, the protocol sequence, the network address, the endpoint, and the endpoint options.

The object UUID is a unique identifier. The protocol sequence is a string that represents the RPC network-communications protocol. The protocol sequence also determines network-address and endpoint-naming conventions. For example, the protocol sequence ncacn_ip_tcp indicates a connection-based NCA connection over TCP/IP. For more information about protocol sequences, see Specifying the Protocol Sequence or the reference entry for PROTSEQ.

The network address indicates the server name. The endpoint indicates a communication port at that server.

The client application can itself combine these substrings into the correct
string-binding syntax, or it can call the function RpcStringBindingCompose. After a client calls RpcStringBindingCompose, it calls RpcBindingFromStringBinding to obtain the binding handle. For a complete description of the required syntax, see String Binding.

Most distributed applications should use the name-service functions instead of the string binding to obtain the binding handle. The name-service functions allow your server application to register its interface and object UUIDs, network address, and endpoint under a single logical name. These functions provide location independence and ease of administration.


Endpoint

The endpoint specifies the communication port clients use to make remote procedure calls to a server.

The server application specifies endpoint information at the same time it specifies the protocol sequence by calling the RPC routine that starts with the prefix "RpcServerUseProtseq" or "RpcServerUseAllProtseqs."

A finite number of endpoints are available for any protocol sequence. Some of these are usually assigned by the authority responsible for the protocol. The syntax of the endpoint string depends on the protocol sequence you use. For example, the endpoint for TCP/IP is a port number, and the endpoint syntax for named pipes is a valid pipe name.

The major design decision you must make regarding the endpoint is whether it is well known or dynamic. Your choice of option determines whether the distributed application or the run-time library specifies the endpoint the application will use.

Most applications should use dynamic endpoints so that an endpoint-mapping service can dynamically map a distributed application to an endpoint available for the protocol. In this way, this limited system resource can be assigned to a distributed service at run time as needed, rather than being dedicated to a distributed service when the service is developed.


Dynamic Endpoints

The number of communication ports for a particular server can be limited. For example, when you use the ncacn_nb_nb protocol sequence, indicating that RPC network communication occurs using NetBIOS over NetBEUI, less than 255 ports are available. The RPC run-time libraries allow you to assign endpoints dynamically as needed.

The application selects a dynamic endpoint in one of two ways: on the client side, it uses a null string to indicate the endpoint when it composes a string binding; on the server side, it registers the server application in the name-service database, or it calls RpcServerUseProtseq or RpcServerUseAllProtseqs to explicitly select dynamic endpoints.

The dynamic endpoint is registered in an endpoint-map database, a database that is managed by a specific service that creates and deletes elements for applications. In Windows NT, the endpoint-mapping service is called RPCSS. The dynamic endpoint expires when the server instance stops running. Call RpcEpUnregister at application termination to remove the old endpoint from the endpoint mapper database.


Well-Known Endpoints

A distributed application can specify an endpoint in a string that is used as a parameter to the function RpcServerUseProtseqEp or in a string that appears in the IDL file interface header as part of the endpoint interface attribute. Well-known endpoints are not recommended for most applications.

You can use two approaches to implement the well-known endpoint:

•	Specify all information in a string binding

•	Store the well-known endpoint in the name-service database

All the information needed to establish the binding can be written into a distributed application when you develop it. The client can specify the well-known endpoint directly in a string, call RpcStringBindingCompose to create a string that contains all the binding information, and obtain a handle by supplying this string to the function RpcBindingFromStringBinding. The client and server can be hard-coded to use a well-known endpoint, or written so that the endpoint information comes from the command line, a data file, or the IDL file.

When a server uses a well-known endpoint, the endpoint data is included as part of the name-service database server entry. When the client imports a binding handle from the server entry, the binding handle contains a complete server address that includes the well-known endpoint.


Fully and Partially Bound Handles

When you use dynamic endpoints, the run-time libraries obtain endpoint information when they need it. The run-time libraries make the distinction between a fully bound handle (one that includes endpoint information) and a partially bound handle (one that does not include endpoint information).

The client run-time library must convert the partially bound handle to a fully bound handle before the client can bind to the server. The client run-time library tries to convert the partially bound handle for the client application by obtaining the endpoint information:

•	From the client's interface specification

•	From an endpoint-mapping service running on the server

When the client tries to use a partially bound handle, the endpoint information is not available in the interface specification, and there is no endpoint-mapping service, the client does not have enough information to make its remote procedure call and that call fails. You must provide the endpoint map when your distributed application uses partially bound handles. For more information about the endpoint map, see Registering the Endpoint.

When a remote procedure call fails, the client application can call RpcBindingReset to remove out-of-date endpoint information. When the client tries to call the remote procedure, the client run-time library again tries to convert the fully bound handle to a partially bound handle.


Server-Application RPC API Calls

For most distributed applications, write your server application for calling the RPC functions in the following sequence:

1.	Use the protocol sequence(s). Call one of the following RPC functions: RpcServerUseProtseq, RpcServerUseAllProtseqs, RpcServerUseProtseqIf, RpcServerUseAllProtseqsIf, and RpcServerUseProtseqEp.

2.	Call RpcServerInqBindings to obtain the binding vector needed for subsequent calls to RpcEpRegister, RpcEpRegisterNoReplace, and RpcNsBindingExport.

3.	When you use dynamic endpoints, add the endpoints associated with the server to the endpoint-map database. Call RpcEpRegister or RpcEpRegisterNoReplace.

4.	Export to the name-service database. Call RpcNsBindingExport.

5.	Clean up data structures. Call the RPC function RpcBindingVectorFree.

6.	Register the interface. Call RpcServerRegisterIf.

7.	Listen for clients. Call RpcServerListen or RpcMgmtWaitServerListen.

When the server application is no longer actively serving clients, you usually instruct it to call RPC functions in the following sequence:

1.	Stop listening for clients. Call the RPC function RpcMgmtStopServerListening.

2.	Remove the interface. Call the RPC function RpcServerUnregisterIf.

3.	Remove endpoint-map database entries. Call the RPC function RpcEpUnregister.

When the server stops providing service for a short period of time, the server should not remove its registration from the name-service database. The RPC name-service function RpcNsBindingUnexport is called only when the service is permanently removed.


Specifying the Protocol Sequence

One of the first acts of the server application is to specify the protocol sequences over which it can communicate with clients.

The protocol sequence is a string that represents a valid combination of an RPC protocol (such as "ncacn"), a transport protocol (such as "tcp" and "nb"), and a network-address format (such as "ip"). Microsoft RPC supports the protocol sequences listed in the following list. Other protocol sequences will be supported in subsequent releases.

Protocol sequence	Description
ncacn_ip_tcp	Connection-oriented TCP/IP
ncacn_nb_tcp	NetBIOS over TCP/IP
ncacn_nb_nb	NetBIOS over NetBEUI
ncacn_np	Named pipes
ncacn_spx	Connection-oriented SPX
ncadg_ip_udp	Datagram-oriented TCP/IP
ncadg_ipx	Datagram-oriented IPX
ncalrpc	Local communication on Windows NT only
Note  Windows 95 does not support ncalrpc, ncacn_nb_ipx, and ncacn_nb_tcp. The ncacn_np protocol is supported only on the client side. You must have an authentic Novell client to use the RPC SPX transport.

The server application specifies a single protocol sequence by calling one of the functions that starts with the prefix "RpcServerUseProtseq." The server specifies all supported protocol sequences by calling RpcServerUseAllProtseqs.

The function you choose to specify protocol sequences also specifies information about the endpoint. The endpoint can be specified explicitly (RpcServerUseProtseqEp), culled from the IDL file (RpcServerUseProtseqIf, RpcServerUseAllProtseqsIf), or selected for the application by the run-time library (RpcServerUseProtseq, RpcServerUseAllProtseqs). These choices are listed following:

"Protseq" function	Description
RpcServerUseAllProtseqs	Registers all protocols using dynamic endpoints.
RpcServerUseAllProtseqsIf	Registers all protocols with endpoints from the IDL file.
RpcServerUseProtseq	Registers one protocol using a dynamic  endpoint.
RpcServerUseProtseqEp	Registers one protocol with the specified  endpoint.
RpcServerUseProtseqIf	Registers one protocol with the endpoint in  the IDL file.
The server application specifies endpoint information at the same time that it specifies the protocol sequence by calling the RPC function that starts with the prefix "RpcServerUseProtseq" or "RpcServerUseAllProtseqs." The endpoint specifies the communication port through which clients make remote procedure calls to the server. For more information about endpoints, see Endpoints.


Registering the Endpoint

When a server uses dynamic endpoints (and the client has partially bound handles), the server application should also call RpcEpRegister or RpcEpRegisterNoReplace.

The dynamic endpoints are registered after the server application has specified the use of dynamic endpoints by calling the RPC function that starts with the prefix "RpcServerUseProtseq" or "RpcServerUseAllProtseqs."

The functions RpcEpRegister and RpcEpRegisterNoReplace store information about the dynamic endpoint in a database that contains local endpoint maps. The client run-time library gets the endpoint from the database by querying using a partially bound handle and the client interface specification. This allows the client to establish a binding to a server instance.

When the server run-time library selects the endpoint, it is available to the client application through the endpoint-map database.

An endpoint map stores handles that are partially bound to local server endpoints. Each database element contains an interface specification, an object UUID (which may be nil), the protocol sequence, and the associated endpoint.

When the client makes a remote procedure call using a partially bound handle, the client's run-time library asks the endpoint map for the endpoint of a compatible server instance. The client library supplies the interface UUID and the object UUID in the partially bound handle if it exists.

The endpoint map compares the client interface UUID and the object UUID to server entries in the endpoint-map database. If both the interface UUID and the object UUID match, the endpoint map tests compatibility of the version numbers, the protocol version, and the protocol sequence, as follows:

•	The interface major version numbers must match, and the server minor version number must be greater than or equal to the client minor version number.

•	At least one transfer syntax must match.

•	The RPC protocol version must match.

•	The server must have at least one protocol sequence that matches the client.

If all tests are successful, the endpoint map returns the valid endpoint, and the client run-time library returns a fully bound binding handle.


Exporting to the RPC Name-Service Database

After specifying the protocol sequence and endpoint and registering any dynamic endpoints in the endpoint-map database, the server application registers the binding handle for the interface with the RPC name-service provider by calling RpcNsBindingExport.

In the Microsoft environment, the server application should register itself with the name-service database every time the server application is run. In the DCE environment, the server application registers with the name-service database only once, when the application is installed. The Microsoft Locator maintains its database in transient memory on the server, while the DCE name service resides in permanent, replicated storage that is relatively expensive to update.


Using the Locator

This section describes how to best use the name service feature of Microsoft RPC.


An Overview of the Name Service Entry

The name service entry consists of three distinct sections. The first section is for interfaces (UUID + version), the second section contains the object UUIDs, and the third section is for binding handles. You provide a name for the entry that will serve as a way to identify it.

When calling RpcNsBindingExport, the server specifies the name of the entry in which to place the exported information. This newly exported interface is then added to the interface section of the name service entry. Any interfaces that are already present in the name service entry remain as well. This same process is followed for object UUIDs and binding handles.

The client calls RpcNsBindingLookupBegin (or RpcNsBindingImportBegin) to search for an appropriate binding handle. The entry name, interface handle, and an object UUID are extracted. These restrict the entries from which binding handles are returned. If an entry matches the search criteria, all the binding handles in that entry are returned from RpcNsBindingImportNext.


Criteria for Name Service Entries

The following criteria are used when processing name service entries:

•	If you provide a non-NULL entry name for RpcNsBindingLookupBegin, that entry will be the only entry searched for binding handles. If you pass NULL, all entries in your logon domain will be searched. Note that this does not include trusted domains.

•	If you provide an interface handle, binding handles are returned from an entry only if the interface section of the entry contains a compatible version of that interface UUID. In other words, the major version number must be the same as your interface UUID, while the minor version number must be equal to or greater than yours.

•	If you provide an object UUID, binding handles are returned from an entry only if the object UUID section of the entry contains that particular object UUID.

If a name service entry survives the criteria described above, all the binding handles from those entries are gathered. Handles with a protocol sequence that is unsupported by the client are discarded and the remaining handles are returned to you as the output from RpcNsBindingLookupNext.


Name Service Entry Cleanup

A name service entry should contain information that does not change frequently. For this reason, do not include dynamic endpoints in your exported binding handles, since they will change at each invocation of the server and will clutter up your name service entry. Use RpcBindingReset to remove such binding handles. For example, a reasonable sequence of server operations would be as follows:

For more than one transport:

RpcServerUseProtseq();

RpcServerUseProtseq();

To place bindings in the endpoint mapper:

RpcServerInqBindings(&Vector);

RpcEpRegister(Interface, Vector);

To remove endpoints from bindings:

for (i=0; i < Vector- > Count; + + i)

{

RpcBindingReset(Vector->BindingH[i];

}

To add bindings to the name service:

RpcNsBindingExport(RPC_C_NS_SYNTAX_DEFAULT, EntryName, Interface

Vector);

RpcServerListen();

Since the Microsoft Locator service does not use many resources to export information, the examples above work well. However, Microsoft RPC also supports Digital Equipment Corporation's Cell Directory Service (CDS). This is a more robust name service. When using CDS, RpcNsBindingExport or RpcNsBindingUnexport will create a lot of network traffic for replication and distribution. Thus, the server should determine if the information already has been exported, and only export it if is has not.


What Happens During a Query

This section describes how the network handles the query when a 32-bit client looks for a name in its own domain.

When your client application calls RpcNsBindingImportBegin, the locator residing on your client computer will try to satisfy this request. If there is nothing in the cache, it will forward the request by RPC to a master locator. If the master locator finds nothing in its cache, it sends the request to all the computers in the domain using a mailslot broadcast. If there is a match, the locator on each computer will respond by a directed mailslot (for example, if a process on that computer has exported the interface). The responses are collated and the RPC is completed from the client's process locator, which will reply to the client process itself.

In a domain, the client locator searches for a master locator in the following places:

1.	On the primary domain controller, or

2.	On each backup domain controller.

If a match is not found, the client locator declares itself to be the master locator. As such, it will broadcast queries if they cannot be satisfied locally.

In a workgroup, the client locator maintains a cache of the computers whose locators have broadcasted. It uses the one that has been running the longest as the master locator. If that computer is unavailable, the next longest-broadcasting computer is used, and so on. If the client needs a master locator and the cache is empty, it replenishes the cache by sending a special mailslot broadcast that requests master locators to respond. If there are no responses, the client locator declares itself to be the master locator and will broadcast queries if they cannot be satisfied locally.

This changes if your client application is a Windows 3.x or MS-DOS program. In this case, there is no locator running on the client computer, and rpcns1.dll or rpcnslm.rpc contains the code to find a master locator. All requests are forwarded directly to the master locator.

These guidelines are valid for names in the client's domain, for example, names for "/.:/entryname". If the client requests a name from another domain through the use of "/.../DOMAIN/entryname;" the client locator forwards the request to the specified domain, which will broadcast it if it doesn't have the answer. If the domain is down or is actually a workgroup, the request will fail.

Note  Remember the following when working with entries in the name service:

•	A client cannot use the "/.../DOMAIN/entryname" syntax to find an entry in its own domain. Use the syntax "/.:/entryname". However, you can use "/.../DOMAIN/entryname" to find an entry in another domain.

•	The domain name in "/.../DOMAIN/entryname" must be upper-case. When looking for a match, the locator is case-sensitive.

•	Locator entry names are also case-sensitive.


Using CDS

If you have CDS, you can use it instead of the Locator. Change the registry entries as follows:

HKEY_LOCAL_MACHINE

Software

Microsoft

Rpc

Name Service

NetworkAddress

HKEY_LOCAL_MACHINE

Software

Microsoft

Rpc

Name Service

Endpoint

Changing these entries will point to a gateway computer that is running the nsid. This will be used as the master locator. In the event of a crash, there will be no search for a replacement.


Name Syntax

Microsoft RPC accepts names that conform to the following syntax:

/.:/name[/name...]
/.../domainname/name[/name...]

name

Specifies an identifier that can contain any character except the delimiting slash (/) character.

domainname

Specifies the name of the Windows NT domain.

A parameter that selects the name-syntax type and the string that specifies the name are supplied to many of the name-service interface (NSI) RPC functions.

Only one name-syntax type is supported by Microsoft RPC, as specified by the constant RPC_C_NS_SYNTAX_DCE. This constant is defined in the header file RPCNSI.H.

The name syntax specified by RPC_C_NS_SYNTAX_DCE is an extension of the DCE Cell Directory Service (CDS) name syntax. The ability to specify a domain name represents an extension to that syntax. There is no absolute limit on the number of names that can be separated by slash characters, as long as the overall string is less than 256 characters.

The slashes allow you to specify a logical structure to the name, but they do not correspond to a logical structure in the objects themselves.


The RPC Name-Service Database

A name service is a service that maps names to objects, usually maintaining the (name, object) pairs in a database. The name is usually a logical name that is easy for users to remember and use. For example, a name service would allow a user to use the logical name "laserprinter." The name service maps this name to the network-specific name used by the print server.

To use a simplified explanation, the RPC name service maps a name to a binding handle and maintains the (name, binding handle) mappings in the RPC name-service database. The RPC name service allows client applications to use a logical name instead of a specific protocol sequence and network address. The use of the logical name makes it easier for network administrators to install and configure your distributed application.

An RPC name-service database entry has one of the following attributes: server, group, or profile. In the Microsoft implementation, entries can have only one attribute, so these entries are also known as server entries, group entries, and profile entries.

The server entry consists of interface UUIDs, object UUIDs (needed when the server implements multiple entry points), network address, protocol sequence, and any endpoint information associated with well-known endpoints. When a dynamic endpoint is used, the endpoint information is kept in the endpoint-map database rather than the name-service database, and the endpoint is resolved like any other dynamic endpoint. Server entries are managed by functions that start with the prefix "RpcNsBinding."

The group entry can contain server entries or other group entries. Group entries are managed by functions that start with the prefix "RpcNsGroup."

The profile entry can contain profile, group, or server entries. Profile entries are managed by the functions that start with the prefix "RpcNsProfile."


Name-Service Application Guidelines

When you develop your distributed application, give your application users the ability to supply the name for registering the application in the name-service database. Provide a method, such as a data file, command-line input, or dialog box, that allows the application user or network administrator to specify the name.

The RPC name-service architecture supports various methods for organizing an application's server entries, but it is optimized for lookups. As a result, frequent updates can hinder the performance of both the name service and the application. To avoid exporting information unnecessarily, choose a design that allows the server to determine whether its information is in the name-service database. In addition, each server instance should export to its own entry name; otherwise it will be very difficult for an instance to change its supported object UUIDs or protocol sequences without disturbing another instance's information.

Following is a method that avoids these pitfalls and provides good performance, whether you use the Microsoft Locator or another name service.

Design your application so that the first time a given server instance starts up, it picks a unique server-entry name and saves this name in an .INI file along with the application's other configuration information. Then have it export its binding handles and object UUIDs, if any, to its name-service entry. Subsequent invocations of the server instance should check that the name-service entry is present and contains the correct set of object UUIDs and binding handles. A missing entry might mean that an administrator removed it, or that a power outage caused the name-service information to be lost. It is important to verify that the binding handles in the entry are correct; if an administrator adds TCP/IP support to a computer, for example, RPC servers will listen on that protocol sequence when they call RpcServerUseAllProtseqs. But if the server doesn't update the name-service entry, clients won't be informed that TCP is supported.

When the client imports, it should specify NULL as the entry name; specifying NULL causes the Microsoft Locator to search for the interface in all name-service entries in the client machine's domain or workgroup, thus finding the information for every instance.

If you use object UUIDs to represent well-known objects such as printers, you can use a variation of this method. Instead of exporting bindings to one entry, design your application so that each instance creates an entry for each supported object, such as "/.:/printers/Laser1" and "/.:/printers/Laser2." Then have the server export its binding handles to each server entry, along with the object UUID relevant to that entry.

In this case, a client can look up a resource by name by importing from the relevant server entry; it doesn't require the object UUID of the resource. If it has the resource UUID but not the name, it can import from the null entry.


Registering the Interface

After calling RpcServerUseAllProtseqs, registering dynamic endpoints in the endpoint-map database and registering your distributed application in the name service, register the interface by calling RpcServerRegisterIf once for each implementation of the interface.

Where you provide a single implementation of each function prototype specified in the interface, supply the interface handle data structure generated by the MIDL compiler and supply null pointers for the manager type and the parameters of the manager entry-point vector (EPV).

RpcServerRegisterIf sets values in the internal interface registry table. This table is used to map the interface UUID and object UUIDs to a manager EPV. The manager EPV is an array of function pointers that contains exactly one function pointer for each function prototype in the interface specified in the IDL file.

The run-time library uses the interface registry table (set by calls to the function RpcServerRegisterIf) and the object registry table (set by calls to the function RpcObjectSetType) to map interface and object UUIDs to the function pointer.

For information about supplying multiple EPVs to provide multiple implementations of the interface, see Multiple Interface Implementations.


Listening for Clients

After registering the protocol sequence, endpoint, and interface, and after advertising the availability of the server application in the name-service database, the server calls RpcServerListen to indicate to the run-time library that it is ready to accept remote procedure calls from clients.

The DCE implementation of RpcServerListen does not return to the server application until another server thread calls RpcMgmtStopServerListening. The call to RpcServerListen ties up the server-manager thread.

Microsoft has extended the DCE definition of this function. You supply a flag that indicates whether to wait or to return immediately to the server application to allow further processing. When your server application uses this option, it can call a new function, RpcMgmtWaitServerListen, to perform the wait operation.

The wait functionality prevents the server from terminating an active client operation. When the server has selected the wait option by calling RpcServerListen or RpcMgmtWaitServerListen, the server waits until all client operations are complete before shutting down the server-manager application.


Client Application RPC API Calls

To make the remote procedure call, the client must obtain a binding handle. Two approaches are used to obtain a binding handle:

•	Importing from the name-service database. The client specifies the name of the name-service database entry and obtains a binding handle.

•	Constructing individual strings that represent the client object UUID, server, protocol sequence, network address, endpoint, and options. Call the function RpcStringBindingCompose to assemble these strings into the correct syntax for a string binding, and then call RpcBindingFromStringBinding to obtain the binding handle.

For information see String Bindings.

Use the RPC name service in both client and server applications for ease of administration and maintenance.


Importing from the Name-Service Database

When the server application is registered with the name-service database, the client can obtain binding handles by using one of two equivalent methods:

•	Importing (call RpcNsBindingImportBegin, RpcNsBindingImportNext, and RpcNsBindingImportDone)

•	Looking up and selecting (call RpcNsBindingLookupBegin, RpcNsBindingLookupNext, RpcNsBindingSelect, and RpcNsBindingLookupDone).

The import method returns a single binding handle, while the lookup method returns a binding vector from which the application selects one binding handle using the function RpcNsBindingSelect.

The client queries the name service by supplying the logical name the client uses to refer to the server application. The name-service provider returns a binding handle.

The client can also choose to supply a null name (an empty string or a null pointer). In this case, the Microsoft Locator searches for name-service database entries that match the supplied interface UUID. The search varies slightly between the DCE CDS and the Microsoft Locator.

The DCE implementation of the name-service provider uses the DEFAULT_ENTRY environment variable, which is usually the name of a profile, to search for an entry that matches the interface ID specified in the import call.

The Microsoft Locator implementation of the name-service provider does not use DEFAULT_ENTRY and does not support profile entries. Instead, all entries in the primary locator (at the domain controller) are combined to form a default profile. When no matches are found in that domain, the client application can search in another domain. For more information about specifying the domain name, see Name Syntax.


Multiple Interface Implementations

You can supply more than one implementation of the remote procedure(s) specified in the IDL file. The server application calls RpcObjectSetType to map object UUIDs to type UUIDs and calls RpcServerRegisterIf to associate manager EPVs with a type UUID. When a remote procedure call arrives with its object UUID, the RPC server run-time library maps the object UUID to a type UUID. The server application then uses the type UUID and the interface UUID to select the manager EPV.

You can also specify your own function to resolve the mapping from object UUID to manager type UUID. You specify the mapping function when you call RpcObjectSetInqFn.


Entry-Point Vectors

The manager EPV is an array of function pointers that point to implementations of the functions specified in the IDL file. The number of elements in the array corresponds to the number of functions specified in the IDL file. Microsoft RPC supports multiple entry-point vectors, representing multiple implementations of the functions specified in the interface.

The MIDL compiler automatically generates a manager EPV data type for use in constructing manager EPVs. The data type is named if-name_SERVER_EPV, where if-name specifies the interface identifier in the IDL file.

The MIDL compiler automatically creates and initializes a default manager EPV on the assumption that a manager routine of the same name exists for each procedure in the interface and is specified in the IDL file.

When a server offers multiple implementations of the same interface, the server must create one additional manager EPV for each implementation. Each EPV must contain exactly one entry point (address of a function) for each procedure defined in the IDL file. The server application declares and initializes one manager EPV variable of type if-name_SERVER_EPV for each additional implementation of the interface. It registers the EPVs by calling RpcServerRegisterIf once for each supported object type.

When the client makes a remote procedure call to the server, the EPV containing the function pointer is selected based on the interface UUID and the object type. The object type is derived from the object UUID by the object-inquiry function or the table-driven mapping controlled by RpcObjectSetType.


Supplying Your Own Object-Inquiry Function

Consider a server that manages thousands of objects of many different types. Whenever the server started, the server application would have to call the function RpcObjectSetType for every one of the objects, even though clients might refer to only a few of the objects (or take a long time to refer to them). The thousands of objects are likely to be on disk, so that retrieving their types would be time consuming. Also, the internal table mapping the object UUID to the manager type UUID would essentially duplicate the mapping maintained with the objects themselves.

For convenience, the RPC function set includes the function RpcObjectSetInqFn. With this function, you provide your own object-inquiry function.

For example, you can supply your own object-inquiry function when you map objects 100 − 199 to type number 1, 200 − 299 to type number 2, and so on. The object-inquiry function can also be extended to a distributed file system, where the server application does not "know" all the files (object UUIDs) available, or when files in the file system are named by object UUIDs and you don't want to preload all object-UUID-to-type-UUID mappings.


Using Datagram Protocols

Microsoft RPC supports datagram, or connectionless, protocols; as well as connection-oriented protocols. Some of the features available when using datagram protocols are as follows:

•	Datagrams support the UDP and IPX connectionless transport protocols.

•	Because it is not necessary to establish and maintain a connection, resource overhead is less using the datagram RPC protocol.

•	Datagrams enable faster binding.

•	Datagram RPC provides guaranteed, at-most-once delivery through its non-idempotent attribute. A non-idempotent routine is one that cannot be executed more than once because it will either return different results each time, or because it modifies some state. Contrast this with an idempotent routine which also provides guaranteed delivery, but does not ensure at-most-once delivery since transmission acknowledgement is not required.

•	Datagram RPC supports the broadcast and maybe capabilities. Broadcast enables a client to issue messages to multiple servers at the same time. This allows the client to locate one of several available servers on the network, or to control multiple servers simultaneously.


Exception Handling

Microsoft RPC uses the same approach to exception handling as the Microsoft Win32 API.

With Microsoft Windows NT, the RpcTryFinally / RpcFinally / RpcEndFinally structure is equivalent to the Win32 try-finally statement. The RPC exception construct RpcTryExcept / RpcExcept / RpcEndExcept is equivalent to the Win32 try-except statement.

The exception-handler structures in Microsoft RPC are provided so they can also be supported on computers with MS-DOS and Windows 3.x. When you use the RPC exception handlers, your client-side source code is portable to Windows NT, Windows 3.x, and MS-DOS. The different RPC header files provided for each platform resolve the RpcTry and RpcExcept structures for each platform. In the Win32 environment, these macros map directly to the Win32 try-finally and try-except statements. In other environments, these macros map to other platform-specific implementations of exception handlers.

The RPC exception-handling macros provide consistent try-except support across MS-DOS, Windows 3.x, and Windows NT. With Windows NT, RPC try-except support expands into Windows NT try-except support.

When you write distributed applications for Win32 only, use the Win32 try-except and try-finally statements. If you are writing for MS-DOS and Windows 3.x, use the RPC versions of these macros.

Potential exceptions raised by these structures include the set of error codes returned by the RPC functions with the prefixes "RPC_S_" and "RPC_X" and the set of exceptions returned by Win32.

Exceptions that occur in the server application, server stub, and server run-time library (above the transport layer) are propagated to the client. This propagation feature includes multiple layers of callbacks. No exceptions are propagated from the server transport level. The following figure shows how exceptions are returned from the server to the client:

The RPC exception handlers differ slightly from the DCE exception-handling macros TRY, FINALLY, and CATCH. Various vendors provide include files that map the DCE RPC functions to the Microsoft RPC functions, including TRY, CATCH, CATCH_ALL, and ENDTRY. These header files also map the RPC_S_* error codes onto the DCE exception counterparts, rpc_s_*, and map RPC_X_* error codes to rpc_x_*. For DCE portability, use these include files.

For more information about the RPC exception handlers, see RpcExcept and RpcFinally. For more information about the Win32 exception handlers, see your Win32 API documentation.


Security

Microsoft RPC supports two different methods for adding security to your distributed application:

•	Use a security package that can be accessed using the RPC functions.

•	Use the security features built into Windows NT transport protocols.

The transport-level security method is not the preferred method. We recommend that you use RPC security because it works on all transports, across platforms, and provides a high levels of security (including Privacy).


Using Authenticated RPC

While previous versions of Microsoft RPC depended on the security built into the named pipes transport, this version also implements the transport-independent security functions from DCE RPC, using the Windows NT Security Service as the default security provider. This higher-level security enables servers to filter client requests based on an authenticated identity associated with each request.


An Overview of Authenticated RPC

To use authenticated RPC, a client passes its user security information to the runtime library. This security information is called the client credentials. The client runtime library forwards the credentials to the server run-time library. The server runtime library then passes it to the relevant security provider for verification. (In this version of Microsoft RPC, the NT Security Service is the only supported security provider. Other security providers may be added in the future.) When a call is made, the security saver ensures the credentials are valid. If so, the server stub is called and the call proceeds. Otherwise, the client is denied access and the call fails.

Authenticated RPC involves a series of tasks performed by all servers every time a client tries to connect. The server must:

1.	Extract binding information about the client from the incoming call.

2.	Extract the authentication information from the binding handle and check the credentials with the NT Security Service.

3.	Compare the client's authentication information with the access control list (ACL) on the security server's database.


Writing a Secure Server

Depending on your security provider, invalid credentials may or may not be rejected. By default, the RPC runtime library will dispatch calls. It is your responsibility to protect yourself by either:

•	Determining exactly who the client is, or

•	Using impersonation.

Note  Disable the guest account on all computers where security is a significant factor.

If you need additional information about how to write a secure server, check with the manufacturer of your security provider.


Implementing Security for Clients

To set up a binding handle for authenticated RPC, a client application calls RpcBindingSetAuthInfo. Without this call, all remote procedure calls on the binding handle will be unauthenticated. The chosen level of security and authentication applies only to that binding handle. Context handles derived from the binding handle will use the same security information, but subsequent modifications to the binding handle will not be reflected in the context handles. The security and authentication level stays in effect until another level of security is chosen, or until the process terminates. Most applications will not require a change in the security level.

The levels of security and authentication available for authenticated RPC are shown in the following table:

Authentication-Level Constant	Description
RPC_C_AUTHN_LEVEL_DEFAULT	Uses the default authentication level for the specified authentication service.
RPC_C_AUTHN_LEVEL_NONE	Performs no authentication.
RPC_C_AUTHN_LEVEL_CONNECT	Authenticates only when the client establishes a relationship with the server.
RPC_C_AUTHN_LEVEL_CALL	Authenticates only at the beginning of each remote procedure call when the server receives the request. Does not apply to remote procedure calls made using the connection-based protocol sequences (those that start with the prefix "ncacn"). If the protocol sequence in a binding handle is a connection-based protocol sequence and you specify this level, this routine instead uses the RPC_C_AUTHN_LEVEL_PKT constant.
RPC_C_AUTHN_LEVEL_PKT	Authenticates that all data received is from the expected client.
RPC_C_AUTHN_LEVEL_PKT_INTEGRITY	Authenticates and verifies that none of the data transferred between client and server has been modified.
RPC_C_AUTHN_LEVEL_PKT_PRIVACY	Authenticates all previous levels and encrypts the argument value of each remote procedure call.
Note  For Windows 95 platforms, RPC_C_AUTHN_LEVEL_CALL, RPC_C_AUTHN_LEVEL_PKT, RPC_C_AUTHN_LEVEL_PKT_INTEGRITY, and RPC_C_AUTHN_LEVEL_PKT_PRIVACY are only supported for a Windows 95 client communicating with a Windows NT server. These levels are never supported for a Windows 95 client communicating with a Windows 95 server.

The level of security required depends entirely on the application. When considering security levels, remember that the higher the protection level, the greater the overhead required to create and maintain the levels. Additionally, there are performance tradeoffs to consider. The checksum computation and encryption required by the RPC runtime library can make data protection a time-consuming operation. The more often credentials are checked, the more time it will take to get on with the business of the application. When selecting a security level, choose the elements needed by the application, mixing and matching only as required.


Windows 95 Considerations

For systems configured for NetWare clients, the server-side of the application must obtain the server principal name, and then pass this value to RpcServerRegisterAuthInfo. Use the RpcServerInqDefaultPrincName routine to obtain the server principal name. In this situation, the client calls RpcBindingSetAuthInfo in the usual manner, but a value of NULL is specified for PrincipalName. Behind the scenes, the Windows 95 runtime library queries the server to obtain the value of PrincipalName specified to RpcServerRegisterAuthInfo. This is the name that is actually used. The binding handle will be authenticated on the NetWare server.

For Windows 95, if RpcBindingSetAuthInfo is called with a NULL server principal name (as described above), the binding handle must be fully bound. If it is a dynamic endpoint in which the server registers the endpoint with the endpoint mapper, and therefore, it is not known by the client, you must use RpcEpResolveBinding to bind the handle. This is because in order to obtain the principal name from the server, the Windows 95 runtime library implicitly calls RpcMgmtInqServerPrincName; calls to management interfaces cannot be made to unbound handles. All RPC server processes have the same management interface, and registering the handle with the endpoint mapper is not sufficient to uniquely identify a server.

Note  The ncacn_np and ncalrpc security descriptors are ignored by the Windows 95 runtime library, since Windows 95 does not support the Windows NT security model.

Differences in Platforms

When developing applications for MS-DOS, you must feed in the password and credential information to RpcBindingSetAuthInfo manually. This is not the case for an NT or Windows-based platform where the password for the domain will be used. If a Windows For Workgroups or Windows 3.x workstation is not part of a domain, the user will be prompted for the password.

For MS-DOS applications, create a pointer to the SEC_WINNT_AUTH_IDENTITY structure and pass in the credential information under the AuthIdentity parameter.


Providing Client Credentials to the Server

Servers use the client's binding information to enforce security. Clients always pass a binding handle as the first parameter of a remote procedure call; however, servers cannot use the handle unless it's declared as the first parameter to remote procedures in either the IDL file or in the server's ACF. You can choose to list the binding handle in the IDL file, but this forces all clients to declare and manipulate the binding handle rather than using automatic or implicit binding if they choose. Another method is to leave the binding handles out of the IDL file and to place the explicit_handle attribute into the server's ACF. In this way, the client can use whatever type of binding is best suited to the application, while the server uses the binding handle as though it were declared explicitly.

The processs of extracting the client credentials from the binding handle is as follows:

•	RPC clients call RpcBindingSetAuthInfo and include their authentication information as part of the binding information passed to the server.

•	Usually, the server calls RpcImpersonateClient in order to behave as though it were the client. If the binding handle is not authenticated, the call fails with RPC_S_NO_CONTEXT_AVAILABLE. To obtain the client's user name, call GetUserName while impersonating.

•	The server will normally create objects with ACLs by using the Windows NT call CreatePrivateObjectSecurity. After this is accomplished, later security checks become automatic.


Security Packages

The RPC run-time API set includes several functions that let your application manage security.

A security package such as the Kerberos Authentication Protocol can be supplied as a DLL that interoperates with the Microsoft RPC run-time libraries.


Windows NT Transport Security

Although this is not the preferred method, you can add security features to your distributed application by using the security settings offered by the Windows NT named-pipe transport. These security settings are used with the Microsoft RPC functions that start with the prefixes "RpcServerUseProtseq" and "RpcServerUseAllProtseqs" and the functions RpcImpersonateClient and RpcRevertToSelf.

Note  If you are running an application that is a service and you are using NTLMSSP for security, you must add an explicit service dependency for your application. The NTLMSSP.DLL will call the Service Controller (SC) to begin the NTLMSSP service. However, an RPC application that is a service and is running as a system, must also contact the SC, unless it is connecting to another service on the same computer.


Impersonation

Impersonation is useful in a distributed computing environment when servers must pass client requests to other server processes or to the operating system. In this case, a server impersonates the client's security context. Other server processes can then handle the request as if it had been made by the original client.

For example, a client makes a request to Server A. If Server A must query Server B to complete the request, Server A impersonates client security context and makes the request to Server B on behalf of the client. Server B uses the original client's security context, rather than the security identity for Server A, to determine whether to complete the task.

The server calls RpcImpersonateClient to overwrite the security for the server thread with the client security context. RpcRevertToSelf restores the security context defined for the server thread.

When binding, the client can specify quality-of-service information about security that specifies how the server can impersonate the client. For example, one of the settings allows the client to specify that the server is not allowed to impersonate it.


Using Transport-Level Security on the Server

When you use ncacn_np or ncalrpc as the protocol sequence, the server specifies a security descriptor for the endpoint at the time it selects the protocol sequence. The security descriptor is provided as an additional parameter (an extension to the standard DCE parameters) on all functions that start with the prefixes "RpcServerUseProtseq" and "RpcServerUseAllProtseqs." The security descriptor controls whether a client can connect to the endpoint.

Each Windows NT process and thread is associated with a security token. The security token includes a default security descriptor that is used for any objects created by the process, such as the endpoint. If no security descriptor is specified when calling a function with the prefixes "RpcServerUseProtseq" and "RpcServerUseAllProtseqs," the default security descriptor from the process security token is applied to the endpoint.

To guarantee that the server application is accessible to all clients, the administrator should start the server application on a process that has a default security descriptor that can be used by all clients. In Windows NT, generally only system processes have a default security descriptor.

For more information about these functions and the functions RpcImpersonateClient and RpcRevertToSelf.


Using Transport-Level Security on the Client

The client specifies how the server impersonates the client when the client establishes the string binding. This quality-of-service information is provided as an endpoint option in the string binding. The client can specify the level of impersonation, dynamic or static tracking, and the effective-only flag.

To supply quality-of-service information for the server, the client performs the following steps:

1.	Imports a handle from the name-service database.

The client specifies the name of the name-service database entry and obtains a binding handle.

2.	Calls RpcBindingToStringBinding to obtain the protocol sequence, network address, and endpoint.

3.	Calls RpcStringBindingParse to split the string binding into its component substrings.

4.	Verifies that the protocol sequence is equal to ncacn_np or ncalrpc.

Client quality-of-service information is supported only on named pipes in Microsoft RPC.

5.	Adds the security information to the endpoint string as an option.

For more information about the syntax, see String Binding.

6.	Calls RpcStringBindingCompose to reassemble the component strings, including the new endpoint options, in the correct string-binding syntax.

7.	Calls RpcBindingFromStringBinding to obtain a new binding handle and to apply the quality-of-service information for the client.

8.	Makes remote procedure calls using the handle.

Microsoft RPC supports Windows NT security features only on ncacn_np and ncalrpc. Windows NT security options for other transports are ignored.

Note  Since it does not support the Windows NT security model, the Windows 95 runtime library ignores the security descriptors ncalrpc and ncacn_np.

The following security parameters can be associated by the client with the binding for the named-pipe transport ncacn_np or ncalrpc:

•	Identification, Impersonation, or Anonymous. Specifies the type of security used.

•	Dynamic or Static. Determines whether security information associated with a thread is a copy of the security information created at the time the remote procedure call is made (static) or a pointer to the security information (dynamic).

Static security information does not change. The dynamic setting reflects the current security settings, including changes made after the remote procedure call is made.

•	TRUE or FALSE. Specifies the value of the effective-only flag. A value of TRUE indicates that only security settings set to "on" at the time of the call are effective. A value of FALSE indicates that all security settings are available and can be modified by the application.

Any combination of these settings can be assigned to the binding, as in the following example:

"Security=Identification Dynamic True"

"Security=Anonymous Static True"

"Security=Impersonation Static False"

Default security-parameter settings vary according to the transport protocol.

For more information about the security features of Windows NT, see your Microsoft Windows NT documentation. For information about the syntax of the endpoint options, see endpoint.


Building RPC Applications

The procedure for building a distributed RPC application varies slightly, depending on the operating-system platform that you are developing on and the target platform, version of the MIDL and C or C++ compiler, and API libraries that you use. In all cases, however, the general procedure is the same: Develop the MIDL and C source files, compile the MIDL source files, then compile the C source files, and then link with the RPC and other API libraries.


Environment, Compiler, and API Set Choices

You can develop RPC applications for different target environments: MS-DOS, Microsoft Windows 3.x, and Microsoft Windows NT. You can also choose to develop the executable applications for these target environments using different build environments. Accordingly, you can choose among several development environments, MIDL and C compilers, and API sets.

Available tools and libraries are described in the following table:

Development tool	Description
MIDL for 32-bit environment	Produces C source code for 16- or 32-bit environment
C and MSVC for 16-bit environment (Microsoft C/C++ version 7.0)	Produces 16-bit object files only
C and MSVC for 32-bit environment (Win32 SDK)	Produces 32-bit object files only
Win32 API	Provided for 32-bit environment only (RPC functions are provided as 32-bit DLLs)
Windows 3.x API	Provided for 16-bit environment only (RPC functions are provided as 16-bit Windows DLLs)


General Build Procedure

Use the following procedure to develop your distributed application:

1.	Install the RPC SDK for your platform. For more information on how to install RPC, see Installing RPC.

2.	Develop the IDL file (and optional ACF) that specify the interface.

3.	Develop the C-language source files that implement and call the interface.

4.	Generate C-language stub files by compiling the IDL file and optional ACF with the MIDL compiler.

5.	Compile the C-language source and stub files with the C compiler.

6.	Link the object files with the RPC import libraries for your platform.

7.	Run the client and server distributed applications.


Developing IDL Files

This topic includes the following:

•	a description of the uuidgen utility.

•	a discussion about importing other IDL files.


The uuidgen Utility

The UUID is assigned to an interface to distinguish that interface from other interfaces. The UUID is generated from a command-line utility program, uuidgen, which creates unique identifiers in the required format using both a time identifier and a machine identifier. It guarantees that any two UUIDs produced on the same machine are unique because they are produced at different times, and that any two UUIDs produced at the same time are unique because they are produced on different machines.

The uuidgen utility generates the UUID in IDL file format or C-language format.

The textual representation of a UUID is a string consisting of eight hexadecimal digits followed by a hyphen, followed by three hyphen-separated groups of four hexadecimal digits, followed by a hyphen, followed by twelve hexadecimal digits. The following example is a valid UUID string:

6B29FC40-CA47-1067-B31D-00DD010662DA

When you run the uuidgen utility from the command line, you can use the following command switches:

uuidgen switch	Description
/i	Outputs UUID to an IDL interface template
/s	Outputs UUID as an initialized C structure
/o<filename>	Redirects output to a file; specified immediately  after the /o switch
/n<number>	Specifies the number of UUIDs to generate
/v	Displays version information about uuidgen
/h or ?	Displays command-option summary


Importing Other IDL Files

When you import IDL files using the import attribute, you reuse software. You can also port existing applications to RPC.

Microsoft RPC offers several extensions to the MIDL compiler that affect:

•	Pointer-attribute type inheritance among imported IDL files

•	How many support routines are generated

•	Where support routines are located

Note that an interface without attributes can be imported into a base IDL file. However, the interface must contain only datatypes with no procedures. If even one procedure is contained in the interface, a local or UUID attribute must be specified.

Pointer-Attribute Type Inheritance

According to the DCE specification, each IDL file must define attributes for its pointers. If an explicit attribute is not assigned to a pointer, the pointer uses the value specified by the pointer_default keyword. Some DCE implementations don't allow unattributed pointers. If a pointer does not have an explicit attribute, the IDL file must have a pointer_default specification so that the pointer attribute can be set.

In Microsoft-extensions mode, you can specify a pointer's attribute in the IDL file that imports the defining IDL file. This mode, selected using /ms_ext, allows pointers defined in one IDL file to inherit attributes that are specified in other IDL files.

In Microsoft-extensions mode, IDL files can include unattributed pointers. If neither the base nor the imported IDL files specify a pointer attribute or pointer_default, unattributed pointers are interpreted as unique pointers.

The MIDL compiler assigns pointer attributes to pointers using the following priority rules (1 is highest):

1.	Explicit pointer attributes explicitly applied to the pointer at the definition or use site

2.	Pointer_default attribute in the IDL file that defines the type

3.	Pointer_default attribute in the IDL file that imports the type

4.	Ptr (DCE-compatibility mode); unique (Microsoft-extensions mode)


Developing C Source Files

Your C-language source files must include the header file that will be generated by the MIDL compiler. By default, the generated header file has the same name as the IDL file. You can specify the name of the generated header file with the MIDL compiler command-line option midl /header. Whatever filename you choose, include the generated header file in your C source code.

The generated header file includes directives to include the following RPC header files:

Header files	Description
RPC.H	RPC types and run-time function prototypes
RPCNDR.H	byte, boolean, and small types and data-conversion function prototypes


Using the MIDL Compiler

The MIDL compiler offers a variety of command-line switches that allow you to control its input and output. This section describes some of the major command-line switches, options, and arguments that are supported in Microsoft RPC. For a complete description of each switch, see the reference documentation for the MIDL compiler.

In its default mode, the MIDL compiler generates files that are compatible with DCE RPC. In this mode, language features that are not compatible with DCE IDL are noted as warnings or errors.

Three other compiler modes can be activated with MIDL compiler switches. The modes are as follows:

Compiler mode	Description
/ms_ext	Specifies Microsoft extensions to DCE IDL compilers
/c_ext	Specifies C extension to IDL
/app_config	Supports selected ACF keywords in the IDL file, so you do not have to provide an ACF
The three compiler-mode switches permit different extensions to the DCE IDL language. Each set is independent of the other two and any combination of switches can be set. If no switch is turned on, the language and the compiler output are compatible with DCE IDL.

Each line in the following table shows one of the eight possible combinations of switch settings for the MIDL compiler:

/ms_ext	/c_ext	/app_config	Description
Off	Off	Off	DCE-compatibility mode
Off	Off	On	Allows some ACF attributes in the IDL file; otherwise DCE-compatible
Off	On	Off	DCE-compatible with Microsoft C extensions
Off	On	On	DCE-compatible with Microsoft C extensions and allow some ACF attributes in the IDL file
On	Off	Off	Allows MIDL extensions
On	Off	On	Allows MIDL extensions and allows ACF attributes in the IDL file
On	On	Off	Allows MIDL extensions and Microsoft C language extensions
On	On	On	Allows MIDL extensions, Microsoft C language extensions, and some ACF keywords in the IDL file
The following sections describe each of the compiler modes in detail.


Microsoft-Extensions Mode

The /ms_ext switch enables Microsoft extensions to the DCE IDL. The following features are supported in /ms_ext mode:

•	Static callback functions on the client

•	Explicit handle parameters in any position in the argument list rather than first only

•	Pointers to tagged declaration types

•	Expressions used as size and discriminator specifiers

•	Enumerator initialization (sparse enums)

•	wchar_t wide-character constants, strings, types, and parameters

•	cpp_quote(quoted_string) and #pragma midl_echo

•	Multiple interfaces in an IDL file

•	Definitions outside of an interface


C-Extensions Mode

C-extensions mode, selected with the /c_ext switch, allows you to use existing C header files with your distributed application. The /c_ext switch allows you to use type qualifiers, such as far and stdcall, in type definitions and function prototypes specified in the IDL file.

The /c_ext switch instructs the MIDL compiler to accept C type qualifiers in type declarations as long as the type declarations are not used in a remote procedure call. This allows the compiler to ignore int and void * declarations that would otherwise generate MIDL compiler errors.

C-extensions mode also allows most Microsoft and ANSI C declarative syntax. The following features are supported in the /c_ext compiler mode as long as they are not used in remote procedures:

•	int

•	void *

•	Declaration qualifiers in the IDL file: _ _near, near, _ _far, far, _ _cdecl, cdecl, _ _pascal, pascal, _ _loadds, loadds, _ _volatile, volatile, _ _export, export

•	Complex declarators (such as void ** _near _cdecl proc( int * _far * a[] ); )

•	Ellipses in the procedure parameter list

•	Bit fields in structures and unions

•	Non-discriminated unions

•	extern declarations

•	Enumerator initialization


Application Configuration Mode

The /app_config switch allows you to put selected ACF attributes in an IDL file so you don't have to maintain two files that describe an interface. This mode supports the use of the implicit_handle and auto_handle interface attributes in the IDL file.

The following ACF attributes can appear in the IDL file when you use the /app_config compiler mode:

•	Handle attributes in the IDL file: implicit_handle

•	auto_handle


Help

A complete listing of MIDL compiler switches and options is available when you use the MIDL compiler /help and /? switches. The switches are organized by categories.


Response Files

As an alternative to placing all the options on the command line, the MIDL compiler accepts response files that contain switches and arguments. A response file is a text file containing one or more MIDL compiler command-line options. Unlike a command line, a response file allows multiple lines of options and filenames. This is important on systems such as MS-DOS that have a hard-coded limit on the length of a command line. You can specify a MIDL response file as follows:

midl @filename

filename

Specifies the name of the response file. The response filename must immediately follow the @ character. No white space is allowed between the @ character and the response filename.

Options in a response file are interpreted as if they were present at that place in the MIDL command line.

Each argument in a response file must begin and end on the same line. The backslash character (\) cannot be used to concatenate lines.

MIDL supports command-line arguments that include one or more response files, combined with other command-line switches:

midl -pack 4 @midl1.rsp -env win32 @midl2.rsp itf.idl

The MIDL compiler does not support nested response files.


C-Compiler and C-Preprocessor Requirements

The MIDL compiler must interoperate with the C compiler and C preprocessor. The requirements for the C compiler and preprocessor are described in the following sections.


C-Preprocessor Requirements for MIDL

The MIDL compiler uses the C preprocessor during initial processing of the IDL file. The operating system used when you compile the IDL files is associated with a default C preprocessor. If you want to use a different C-preprocessor name, the MIDL compiler switch /cpp_cmd allows you to override the default C-preprocessor name:

midl /cpp_cmd cl386 filename

filename

Specifies the name of the IDL file.

During initial processing, the C preprocessor removes all preprocessor directives in the IDL file. After preprocessing, the only directive that can appear in a file is the #line directive in one of the following forms:

#line digit-sequence "filename" new-line

# digit-sequence "filename" new-line

Other directives should not appear in either the IDL file or any header file included by the IDL file. These other directives are not supported by the MIDL compiler and can cause errors. For a complete description of the line directive and other preprocessor directives, see your C-compiler documentation.

The MIDL compiler requires the C preprocessor to observe the following conventions:

•	The input file must be the last argument on the command line.

•	The preprocessor must direct output to the standard output device, stdout.

Preprocessor directives present in the IDL file do not appear in the header file generated by the MIDL compiler. For example, any values defined in the IDL file with the C #define statement are removed by the C preprocessor. These #define statements will not appear in the header file generated by the MIDL compiler. If such values are defined only in the MIDL file and are required by C source files, the C compiler will report errors when it tries to compile these source files.

Four workarounds are recommended:

•	Use cpp_quote to reproduce #define in the generated header file

•	Use const declaration specification

•	Use header files that are included in the IDL file and the C source code

•	Use enumeration constants in the IDL file

To get a declaration in the generated header file with cpp_quote, use the following statement:

cpp_quote ("#define ARRSIZE 10");

This statement results in the following line being generated in the header file:

#define ARRSIZE 10

You can reproduce manifest constants using the constant-declaration syntax:

const short ARRSIZE = 10

This syntax results in the following line being generated in the header file:

#define ARRSIZE 10

You can define separate header files that contain only preprocessor directives and include them in both the IDL file and the C source files. Although the directives will not be available in the header file generated by the MIDL compiler, the C source program can include the separate header file.

You can choose to use enumeration constants in the IDL file. Enumeration constants are not removed during the early phases of MIDL compilation by the
C-compiler preprocessor, so these constants are available in the header file generated by the MIDL compiler. For example, the statement

typedef enum midlworkaround { MAXSTRINGCOUNT = 300 };

will not be removed during MIDL compilation by the C preprocessor. The constant MAXSTRINGCOUNT is available to C source programs that include the header file generated by the MIDL compiler.


Verifying Preprocessor Options

To verify the correct operation of /cpp_opt options, invoke the C preprocessor independently before including the command line as part of the MIDL compiler command line. When called independently, the C compiler correctly reports errors caused by invalid options.

Errors in /cpp_opt switch input to the MIDL compiler can produce error messages related to the IDL file. The errors are incorrectly reported by the MIDL compiler when operating with some C compilers.

For example, invalid command-line syntax to the Microsoft C compiler can be reported as a syntax error in the IDL file when that syntax is included as part of the MIDL compiler command line. The error is not in the IDL file but in the MIDL compiler /cpp_opt input.

The following MIDL compiler command line contains the /cpp_opt switch and related options:

midl /cpp_cmd "cl" /cpp_opt /E foo.idl

The options in this command line can be verified by invoking the compiler only, as follows:

cl /E foo.idl


C-Compiler Requirements for MIDL

The MIDL compiler requires the C compiler to support a packing level of 1, 2, 4, or 8. The command-line option for Microsoft C compilers that controls packing is /Zplevel, where level is the packing level: 1, 2, 4, or 8. The following rules govern the alignment of compound types:

•	Base-type fields of size < packing level start on a (0 modulo size) address.

•	Base-type fields of size >= packing level start on a (0 modulo packing level) address.

•	The compound type itself (and any field of compound type) is aligned according to the strictest alignment requirement on any of its fields.

•	Compound types are padded to the next (0 modulo level) address. This padding appears in the size returned by the C SIZEOF macro.

For example, consider a compound type consisting of a 1-byte character, an integer 4 bytes long, and a 1-byte character:

struct mystructtype {

    char c1;  /* requires 1 byte  */

    long l2;  /* requires 4 bytes */

    char c3;  /* requires 1 byte  */

 } mystruct;

For packing level 4, the structure mystruct is aligned on a (0 mod 4) boundary and sizeof(struct mystructtype) = 12.

For packing level 2, the structure mystruct is aligned on a (0 mod 2) boundary and sizeof(struct mystructtype) = 8.


C-Compiler Requirements for Callbacks in Microsoft Windows 3.x

When you use Microsoft Visual C/C++ version 1.5 to develop your RPC application for Microsoft Windows 3.x platforms, compile with the /GA switch. The /GA switch directs the compiler to generate code that loads the DS register from the SS register on entry to a far, exported function in a protected-mode application based on Windows 3.x.

For protected-mode Microsoft Windows applications, the /GA switch allows the C compiler to generate the code for performing the housekeeping chores required when switching between tasks. This code is needed when your RPC interface contains one or more callback functions. Without this code, these callback functions can fail at run time due to an incorrect DS value.

When you use compilers other than Microsoft Visual C/C++ version 1.5, use the compiler switch that is equivalent to /GA.

The /GA switch provides, in an optimized way, the same functionality that the /Gw switch and calls to the Windows 3.x function MakeProcInstance provided for previous versions of the Microsoft C compiler and previous versions of Microsoft Windows.

When you do not compile using the /GA switch — for example, when you are using a compiler that does not support the /GA switch — your application must:

1.	Compile using the /Gw switch (or its equivalent).

2.	Add the client stub functions to the EXPORTS section of the application's DEF file.

3.	Replace function pointers in the the client stub function dispatch table with function pointers returned by MakeProcInstance.

The function dispatch table is part of the RPC_CLIENT_INTERFACE structure defined in the RPC header file RPCDCEP.H. For example, step 3 can be implemented using the following C code:

#include "hello.h"   // generated stub file

RPC_DISPATCH_FUNCTION Old, New;

HINSTANCE hInst;

RPC_CLIENT_INTERFACE * If = Hello_ClientIfHandle;

...

    for (i = 0; i < If->DispatchTable->DispatchTableCount; i++)

    {

       Old = If->DispatchTable->DispatchTable[i];

       New = (RPC_DISPATCH_FUNCTION) MakeProcInstance(Old, hInst);

       If->DispatchTable->DispatchTable[i] = New; // overwrite

    }

...


Link Libraries for MS-DOS

The following RPC client application static libraries are provided for MS-DOS:

Static library	Description
RPC.LIB	Base RPC functions and name-service functions
RPCNDR.LIB	NDR and other stub-helper functions
NDRLIB10.LIB	If you are using MIDL 1.0 on MS-DOS, you must connect to this library. All other users should disregard this library. Note that this library is meant to be a temporary solution, and MIDL 1.0 users should migrate to MIDL 2.0 at the earliest occasion.
The following RPC transports are provided for MS-DOS clients:

Pseudo-dynamic-link library	Description
RPC16C1.RPC	Client named-pipe transport
RPC16C3.RPC	Client TCP/IP transport
RPC16C5.RPC	NetBIOS transport
RPC16C6.RPC	Client SPX transport
RPCNS.RPC	Name-service functions
RPCNSLM.RPC	LAN Manager support functions
RPCNSMGM.RPC	Name-service management functions


Link Libraries for Microsoft Windows 3.x

The following RPC import libraries are provided for Microsoft Windows 16-bit clients:

Import library	Description
RPCW.LIB	RPC API and name-service functions
RPCNDRW.LIB	NDR and other stub-helper functions
The following RPC dynamic-link libraries are provided for Microsoft Windows 3.x clients:

Dynamic-link library	Description
RPCNS1.DLL	Name service
RPCRT1.DLL	Windows run-time library
RPC16C1.DLL	Client named-pipe transport
RPC16C3.DLL	Client TCP/IP transport
RPC16C5.DLL	Client NetBIOS transport


Link Libraries for Microsoft Windows NT

The following RPC import libraries are provided for Microsoft Windows NT clients and servers:

Import library	Description
RPCNDR.LIB	Helper functions
RPCNS4.LIB	Name-service functions
RPCRT4.LIB	Windows run-time functions
The following RPC libraries are provided for Microsoft Windows NT clients and servers:

Dynamic-link library	Description
RPCLTC1.DLL	Client named-pipe transport
RPCLTS1.DLL	Server named-pipe transport
RPCLTC3.DLL	Client TCP/IP transport
RPCLTS3.DLL	Server TCP/IP transport
RPCLTC5.DLL	Client NetBIOS transport
RPCLTS5.DLL	Server NetBIOS transport
RPCNS4.DLL	Name service
RPCRT4.DLL	Windows run-time library


Using the __midl Predefined Constant

When the MIDL compiler processes the input IDL and ACF files, __midl is defined by default. __midl is used for conditional compilation to attain consistency throughout the build. This phases out the use of defines in the header files, such as MIDL_PASS, and replaces them with a consistent flag.

Note that if you so choose, you can override this default by specifying the following on the command line:

-U__midl


Building 16-Bit Windows-Based Applications

You can build your 16-bit Windows-based client applications on a computer that is running Microsoft Windows 3.x, Microsoft Windows for Workgroups 3.1, or MS-DOS.

It is possible to install Microsoft RPC on Windows NT and to use this single platform for developing all server and client applications. However, cross-compilation of Windows 3.x and MS-DOS clients on Windows NT requires that you install a 16-bit C compiler in the Microsoft Windows NT environment. This development environment is not automatically installed as part of the Windows NT or Microsoft RPC installation.


Using Different Memory Models

Microsoft RPC supports the development of Microsoft Windows 3.x applications using small, medium, compact, and large memory models. You can build your application using any memory model when you use the macro definitions provided in the RPC header files.

Note  Microsoft RPC for MS-DOS supports only large-model applications.

The following table lists some of the advantages and disadvantages of the different memory models:

Memory model	Advantage	Disadvantage
Small	Best performance;  size and speed	Must add code to your application to handle the far pointers returned from remote procedures
Large	Easiest to build with the Microsoft RPC tools	Size/speed performance degradation; cannot run multiple instances
Large compiled with /Gx	Easy to build; can run multiple instances of the application	Size/speed performance degradation; limited to only one data segment


Macro Definitions

The RPC tools achieve model, calling, and naming-convention independence by associating data types and function-return types in the generated stub files and header files with definitions that are specific to each platform. These macro definitions ensure that any data types and functions that require the designation of _ _far are specified as far objects.

The following figure shows which macro definitions the MIDL compiler applies to function calls between RPC components:

The macro definitions are as follows:

Definition	Description
_ _RPC_API	Applied to calls made by the stub to the user application. Both functions are in the same executable program.
_ _RPC_FAR	Applied to standard macro definition for pointers. This macro definition should appear as part of the signature of all user-supplied functions.
_ _RPC_STUB	Applied to calls made from the run-time library to the stub. These calls can be considered private.
_ _RPC_USER	Applied to calls made by the run-time library to the user application. These cross the boundary between a DLL and an application.
RPC_ENTRY	Applied to calls made by the application or stub to the run-time library. This macro definition is applied to all RPC run-time functions.
To link correctly with the Microsoft RPC run-time libraries, stubs, and support routines, some user-supplied functions must also include these macros in the function definition. You must use the macro _ _RPC_API when you define the functions associated with memory management, user-defined binding handles, and the transmit_as attribute. You must use the macro _ _RPC_USER when you define the context-rundown routine associated with the context handle. Specify the functions as follows:

_ _RPC_USER midl_user_allocate(...)
_ _RPC_USER midl_user_free(...)
_ _RPC_USER handletype_bind(...)
_ _RPC_USER handletype_unbind(...)
_ _RPC_USER type_to_local
_ _RPC_USER type_from_local
_ _RPC_USER type_to_xmit(...)
_ _RPC_USER type_from_xmit(...)
_ _RPC_USER type_free_local
_ _RPC_USER type_free_inst(...)
_ _RPC_USER type_free_xmit(...)
_ _RPC_USER context_rundown(...)

Note  All pointer parameters in these functions must be specified using the macro
_ _RPC_FAR.

Two approaches can be used to select an application's memory model:

1.	To use a single memory model for all files, compile all source files using the same memory-model compiler switches. For example, to develop a small-model application, compile both the application and the stub source code using the C-compiler switch /AS, as in the following:

cl -c /AS myfunc.c
cl -c /AS clstub_c.c

2.	To use different memory models for the application source files and the support source files (stubs files), use the RPC macros when you define function prototypes in the IDL file. Compile the distributed-application source files using one compiler memory-model setting and compile the support files using another compiler memory-model setting. Use the same memory model for all of the files generated by the compiler.


MIDL Command-Line Reference

This section contains reference information for each command-line switch and switch option recognized by the Microsoft RPC MIDL compiler. Switch entries are arranged in alphabetical order. The topic midl describes the general command-line syntax.


midl

midl [switch [switch-options ]] filename

switch

Specifies MIDL compiler command-line switches. Switches can appear in any sequence.

switch-options

Specifies options associated with switch. Valid options are described in the reference entry for each MIDL compiler switch.

filename

Specifies the name of the IDL file. This file usually has the extension .IDL, but it can have any extension or no extension.

Remarks

The MIDL compiler processes an IDL file and an optional ACF to generate a set of output files. The attributes specified in the IDL file's interface attribute list determine whether the compiler generates source files for an RPC interface or for a custom OLE interface. The following lists show the default names of the files generated for an IDL file named name.IDL. You can use command-line switches to override these default names. Note that the name of the IDL file can have no extension, or it can have an extension other than .IDL.

By default (that is, if the interface attribute list does not contain the object or local attribute), the compiler generates the following files for an RPC interface:

•	Client stub (name_C.C)

•	Server stub (name_S.C)

•	Header file (name.H)

When the object attribute appears in the interface attribute list, you must use the /ms_ext command-line switch, and the compiler generates the following files for an OLE interface:

•	Interface proxy file (name_P.C)

•	Interface header file (name.H)

•	Interface UUID file (name_I.C)

When the local attribute appears in the interface attribute list, the compiler generates only the interface header file, name.H.

The MIDL compiler provided with Microsoft RPC invokes the C preprocessor as needed to process the IDL file. It does not automatically invoke the C compiler to compile generated files.

Note  The MIDL compiler provided with Microsoft RPC uses a different command-line syntax than the DCE IDL compiler uses.


Files Generated for an RPC Interface

The Client Stub

The client stub module provides surrogate entry points on the client for each of the operations defined in the input IDL file.

When the client application makes a call to the remote procedure, its call first goes to the surrogate routine in the client stub file. The client stub routine performs the following functions:

•	Marshals arguments. The client stub packages input arguments into a form that can be transmitted to the server.

•	Calls the client run-time library to transmit arguments to the remote address space and invoke the remote procedure in the server address space.

•	Unmarshals output arguments. The client stub unpackages output arguments and returns to the caller.

The MIDL compiler switches /client, /cstub, and /out affect the client stub file.

The Server Stub

The server stub provides surrogate entry points on the server for each of the operations defined in the input IDL file.

When a server stub routine is invoked by the RPC run-time library, it performs the following functions:

•	Unmarshals input arguments (unpacks the arguments from their transmitted formats)

•	Calls the actual implementation of the procedure on the server

•	Marshals output arguments (packages the arguments into the transmitted forms)

The MIDL compiler switches /env, /server, /sstub, and /out affect the server stub file.

The Header File

The header file contains definitions of all the data types and operations declared in the IDL file. The header file must be included by all application modules that call the defined operations, implement the defined operations, or manipulate the defined types.

The MIDL compiler switches /header and /out affect the header file.


Files Generated for an OLE Interface

This topic describes each of the files generated for a custom OLE interface, which you identify by including the object attribute in the interface attribute list of the IDL file. For OLE interfaces, the MIDL compiler combines all client and object server routines into a single interface proxy file. This file includes the surrogate entry points for both clients and servers. In addition, the MIDL compiler generates an interface header file, a private header file, and an interface UUID file. You will use all these files when creating a proxy DLL that contains the code to support the use of the interface by both client applications and object servers. You will also use the interface header file and the interface UUID file when creating the executable file for a client application that uses the interface.

The Interface Proxy File

The interface proxy file (name_P.C) is a C file that contains routines equivalent to those in the client stub, server stub, client and server files of an RPC interface. This file contains implementations of CProxyInterface and CStubInterface classes that are derived from the CProxy and CStub classes of the base interface. For example, an interface named ISomeInterface derived from the IUnknown interface is implemented in the CProxyISomeInterface and CStubISomeInterface classes derived from the CProxyIUnknown and CStubIUnknown classes.

The interface proxy file includes the following sections:

•	The implementation of a CProxyInterface class. The virtual member functions of this class provide a client application's surrogate entry points for each of the interface functions. These member functions marshal the input arguments into a transmittable form, transmit the marshalled arguments along with information that identifies the interface and the operation, and then unmarshal the return value and any output arguments when the transmitted operation returns.

•	The implementation of a CStubInterface class. The virtual member functions of this class provide an object server's surrogate entry points for each of the interface functions. These member functions unmarshal the input arguments, invoke the server's implementation of the interface function, and then marshal and transmit the return value and any output arguments. A CStubInterface class also includes a member function that is invoked by the RPC run-time library when a client application calls one of the interface functions. This routine calls the surrogate routine specified by the RPC message.

•	Marshalling and unmarshalling support routines for complex data types.

Use the /proxy MIDL compiler switch to override the default name of the interface proxy file. The /env and /out switches affect this file.

The Header Files

The interface header file (name.H) contains type definitions and function declarations based on the interface definition in the IDL file. Include this file in the source files for the proxy DLL and for client applications that use the interface.

The /header MIDL compiler switch overrides the default name of the interface header file.

The Interface UUID File

The interface UUID file defines the constant IID_Interface and initializes it to the interface's UUID specified in the IDL file. Client applications and the proxy DLL use this constant to identify the interface.

The /iid MIDL compiler switch overrides the default name of the interface UUID file.

See Also

ACF, /app_config, /c_ext, IDL, /import, /ms_ext


@

midl @response_file

response_file

Specifies the name of a response file. The response filename must immediately follow the @ character. No white space is allowed between the @ character and the response filename.

Examples

midl @midl.rsp

midl /pack 4 @midl1.rsp /env win32 @midl2.rsp itf.idl

Remarks

As an alternative to placing all the options associated with a switch on the command line, the MIDL compiler accepts response files that contain switches and arguments.

A response file is a text file containing one or more MIDL compiler command-line options. Unlike a command line, a response file allows multiple lines of options and filenames. This is important on systems such as MS-DOS, which limit the number of characters in the command line.

Options in a response file are interpreted as if they are present at that place in the MIDL command line.

Each argument in a response file must begin and end on the same line. The backslash character (\) can't be used to concatenate lines.

When it is part of a quoted string in the response file, the backslash character (\) can only be used before another backslash (\) or before a double quotation mark character ("). When it is not part of a quoted string, the backslash character can only be used before a double quotation mark character (").

MIDL supports command-line arguments that include one or more response files combined with other command-line switches.

The MIDL compiler doesn't support nested response files.

See Also

midl


/acf

midl /acf acf_filename

acf_filename

Specifies the name of the ACF. White space may or may not be present between the /acf switch and the filename.

Example

midl /acf bar.acf foo.idl

Remarks

The /acf switch allows the user to supply an explicit ACF filename. The switch also allows the use of different interface names in the IDL and ACF files.

By default, the MIDL compiler constructs the name of the ACF by replacing the IDL filename extension (usually .IDL) with .ACF. When the /acf switch is present, the ACF takes its name from the specified filename. The /acf switch applies only to the IDL file specified on the MIDL compiler command line. It does not apply to imported files.

When the /acf switch is used, the interface name in the ACF need not match the MIDL interface name. This feature allows interfaces to share an ACF specification.

When an absolute path to an ACF is not specified, the MIDL compiler searches in the current directory, directories supplied by the /I option, and directories in the INCLUDE path. If the ACF is not found, the MIDL compiler assumes there is no ACF for this interface. For more information about the sequence of directories, see  /no_def_idir switches. For more information related to /acf, see IDL.

See Also

midl,


/app_config

midl /app_config

Examples

midl /app_config foo.idl

midl /app_config /ms_ext foo.idl

midl /app_config /ms_ext /c_ext foo.idl

Remarks

The /app_config switch selects application-configuration mode, which allows you to use some ACF keywords in the IDL file. With this MIDL compiler switch, you can omit the ACF and specify an interface in a single IDL file.

This release of Microsoft RPC supports the use of the following ACF attributes in the IDL file:

•	implicit_handle

•	auto_handle

•	explicit_handle

Future releases of Microsoft RPC may support the use of other ACF attributes in the IDL file.

For more information related to the /app_config switch, see ACF and IDL.

See Also

/c_ext, midl, /ms_ext


/c_ext

midl /c_ext

Examples

midl /c_ext foo.idl

midl /c_ext /ms_ext foo.idl

midl /c_ext /ms_ext /app_config foo.idl

Remarks

The /c_ext switch selects the MIDL compiler mode that supports the use of
C-language extensions in the IDL file. The /c_ext switch makes it easier for you to use existing code and header files in your distributed application.

Many existing header files define types using qualifiers, such as far and stdcall, that are not part of the DCE IDL. DCE IDL compilers (and the MIDL compiler in DCE-compatibility mode), generate errors when they attempt to process these qualifiers. The MIDL compiler /c_ext switch allows you to compile IDL files that contain these qualifiers.

The type qualifiers do not affect the way the data is transmitted on the network.

The following C-language extensions are supported in the /c_ext compiler mode:

•	Bit fields in structures and unions

•	Comments that start with two backslash characters

•	External declarations

•	Procedures with ellipses in the parameter list

•	Type int that is not used in remote operations

•	Type void * that is not used in remote operations

•	Type qualifiers, including the form with the ANSI-conformant prefix, contain two underscore characters: _ _cdecl, cdecl, _ _const, const, _ _export, export, _ _far, far, _ _loadds, loadds, _ _near, near, _ _pascal, pascal, _ _stdcall, stdcall, _ _volatile, and volatile.

Note that directional attributes can be omitted when using /c_ext mode.

The three compiler-mode switches, /ms_ext, /c_ext, and /app_config, are independent. Any combination of these mode switches, including none or all, can be used.

For more information about declaration qualifiers, see your Microsoft C/C++ documentation.

See Also

/app_config, midl, /ms_ext


/caux

This switch is obsolete and, if used, results in an error.


/char

midl /char { signed | unsigned | ascii7 }

signed

Specifies that the default C-compiler type for char is signed. All occurrences of char not accompanied by a sign specification are generated as unsigned char.

unsigned

Specifies that the default C-compiler type for char is unsigned. All uses of small not accompanied by a sign specification are generated as signed small.

ascii7

Specifies that all char values are to be passed into the generated files without a specific sign keyword. All uses of small not accompanied by a sign specification are generated as small.

Examples

midl /char signed foo.idl

midl /char unsigned foo.idl

midl /char ascii7 foo.idl

Remarks

The /char switch helps you ensure that the MIDL compiler and C compiler operate together correctly for all char and small types. By definition, MIDL char is unsigned. Small is defined in terms of char (#define small char), and MIDL small is signed.

The /char switch directs the MIDL compiler to specify explicit signed or unsigned declarations in the generated files when the C-compiler sign declaration conflicts with the MIDL default for that type.

The following table summarizes the generated types:

midl /char option	Generated char type	Generated small type
midl /char signed	unsigned char	small
midl /char unsigned	char	signed small
midl /char ascii7	char	small
The /char signed option indicates that the C-compiler char type is signed. To match the MIDL default for char, the MIDL compiler must convert all uses of char not accompanied by a sign specification to unsigned char. The small type is not modified because this C-compiler default matches the MIDL default for small.

The /char unsigned option indicates that the C-compiler char type is unsigned. The MIDL compiler converts all uses of small not accompanied by a sign specification to signed small.

The ascii7 option indicates that no explicit sign specification is added to char types. The type small is generated as small.

To avoid confusion, you should use explicit sign specifications for char and small types whenever possible in the IDL file. Explicit sign specification is allowed only when you use the /ms_ext switch. The use of explicitly signed char types in your IDL file is not supported by DCE IDL.

For more information related to /char, see small.


/client

midl /client { stub | none }

stub

Generates the client-side files.

none

Does not generate any client-side files.

Examples

midl /client none foo.idl

midl /client stub foo.idl

Remarks

The /client switch directs the MIDL compiler to generate client-side C source files for an RPC interface. When the /client switch is not specified, the MIDL compiler generates the client stub file. This switch does not affect OLE interfaces.

The /client switch takes precedence over the /cstub switch.

See Also

/cstub, midl, /server


/confirm

midl /confirm

Examples

midl /confirm

midl /confirm @response.rsp foo.idl

Remarks

The /confirm switch instructs the compiler to display all MIDL compiler options without processing the input IDL (and optional ACF) files.

See Also

/help, midl


/cpp_cmd

midl /cpp_cmd "C_preprocessor_command"

C_preprocessor_command

Specifies the command that invokes the C preprocessor. This command allows you to override the default C preprocessor. By default, MIDL invokes the Microsoft C compiler for the build environment you are using.

Examples

midl /cpp_cmd "cl386" /cpp_opt "/E" foo.idl

midl /cpp_cmd "mycpp" /DFLAG=TRUE /Ic:\tmp foo.idl

midl /cpp_opt "/E /DFLAG=TRUE" foo.idl

Remarks

The /cpp_cmd switch specifies the C-compiler preprocessor that the MIDL compiler uses to preprocess the IDL and ACF files. When this switch is present, the C_preprocessor_command option is required.

When the specified C preprocessor does not direct its output to stdout, you must specify the C compiler switch that redirects output to stdout as part of the MIDL compiler /cpp_opt switch.

The C preprocessor is invoked by a command string that is formed from the information provided to the MIDL compiler /cpp_cmd, /cpp_opt, /D, /I, and /U switches. The following table summarizes how the command string is constructed for each combination of /cpp_cmd and /cpp_opt switches:

/cpp_cmd present?	/cpp_opt present?	Description
Yes	Yes	Invokes specified C compiler with specified options;  you must supply /E as part of /cpp_opt
Yes	No	Invokes specified C compiler with settings obtained from MIDL /I, /D, /U switches; adds C compiler /E switch
No	Yes	Invokes Microsoft C compiler with specified options;  does not use MIDL /I, /D, /U options; you must supply  /E as part of /cpp_opt
No	No	Invokes Microsoft C compiler with /E option only
When the /cpp_cmd switch is not specified, the MIDL compiler invokes the Microsoft C/C++ compiler for that environment.

When the /cpp_opt switch is not present, the MIDL compiler concatenates the string specified by the /cpp_cmd switch with the information specified by the MIDL /I, /D, and /U options. The string /E is also concatenated to the C-compiler invocation string to indicate that the C compiler should perform preprocessing only. The MIDL compiler uses the concatenated string to invoke the C preprocessor for each IDL and ACF source file.

When the /cpp_opt switch is present, the MIDL compiler concatenates the string specified by the /cpp_cmd switch with the string specified by the /cpp_opt switch. The MIDL compiler uses the concatenated string to invoke the C preprocessor for each IDL and ACF source file. When the /cpp_opt switch is present, neither the MIDL compiler options specified by the /I, /D, and /U switches nor the C compiler switch /E is concatenated with the string. You must supply the /E option as part of the string.

See Also

/cpp_opt, midl, /no_cpp


/cpp_opt

midl /cpp_opt "C_preprocessor_option"

C_preprocessor_option

Specifies a command-line option associated with the C preprocessor. You must supply the C-compiler option /E as part of the C_preprocessor_option string.

Examples

midl /cpp_cmd "cl386" /cpp_opt "/E" foo.idl

midl /cpp_cmd "mycpp" /DFLAG=TRUE /Ic:\tmp foo.idl

midl /cpp_opt "/E /DFLAG=TRUE" foo.idl

Remarks

The /cpp_opt switch specifies options to pass to the C preprocessor. The /cpp_opt switch can be used with or without the /cpp_cmd switch. The following table summarizes how the C-preprocessor command string is constructed for each combination of /cpp_cmd and /cpp_opt switches:

/cpp_cmd present?	/cpp_opt present?	Description
Yes	Yes	Invokes specified C compiler with specified options; you must supply /E as part of /cpp_opt
Yes	No	Invokes specified C compiler with settings obtained from MIDL /I, /D, /U switches; adds C-compiler /E switch
No	Yes	Invokes Microsoft C compiler with specified options; does not use MIDL /I, /D, /U options; you must supply /E as part of /cpp_opt
No	No	Invokes Microsoft C compiler with /E option only
When the /cpp_cmd switch is present and the /cpp_opt switch is not, the MIDL compiler concatenates the string specified by the cpp_cmd switch with the /I, /D, and /U options and uses this concatenated string to invoke the C preprocessor for each IDL and ACF source file.

When the /cpp_cmd switch is not present, the preprocessor option is sent to the default C preprocessor. When the /cpp_cmd switch is present, the preprocessor option is sent to the specified C preprocessor.

See Also

/cpp_cmd, midl, /no_cpp


/cstub

midl /cstub stub_file_name

stub_file_name

Specifies a filename that overrides the default client stub filename. Filenames can be explicitly quoted using double quotes (") to prevent the shell from interpreting the special characters.

Example

midl /cstub my_cstub.c foo.idl

Remarks

The /cstub switch specifies the name of the client stub file for an RPC interface. The specified filename replaces the default filename. By default, the filename is obtained by adding the extension _C.C to the name of the IDL file. This switch does not affect OLE interfaces.

When you are importing files, the specified filename applies to only one stub file — the stub file that corresponds to the IDL file specified on the command line.

If stub_file_name does not include an explicit path, the file is written to the current directory or the directory specified by the /out switch. An explicit path in stub_file_name overrides the /out switch specification.

The /client none switch takes precedence over the /cstub switch.

See Also

/header, midl, /out, /sstub


/D

midl /Dname=definition

name

Specifies a defined name that is passed to the C preprocessor when the /cpp_cmd switch is present and the /cpp_opt switch is not present.

definition

Specifies a value associated with the defined name.

Example

midl -DUNICODE foo.idl

Remarks

The /D switch defines a name and an optional value to be passed to the C preprocessor as if by a #define directive. Multiple /D directives can be used in a command line. White space between the /D switch and the defined name is optional.

When the /cpp_cmd switch is present and the /cpp_opt switch is not, the MIDL compiler concatenates the string specified by the /cpp_cmd switch with the /I, /D, and /U options and uses this concatenated string to invoke the C preprocessor for each IDL and ACF source file.

The MIDL compiler switch /D is ignored when the MIDL compiler switch /no_cpp or /cpp_opt is specified.

See Also

/cpp_cmd, /cpp_opt, /I, midl, /no_cpp, /U


/dlldata

midl /dlldata

Example

midl /dlldata data.c

Remarks

The /dlldata switch is used to specify the filename for the generated dlldata file for a proxy DLL. The default filename "dlldata.c" is used if the /dlldata switch is not specified.

The dlldata file must be linked to the proxy DLL. The dlldata file contains entry points and data structures required by the class factory for the proxy DLL. These data structures specify the object interfaces contained in the proxy DLL. The dlldata file also specifies the class ID of the class factory for the proxy DLL. This is always the UUID (IID) of the first interface of the first proxy file (by alphabetical order).

The same dlldata file should be specified when invoking MIDL on all the IDL files that will go into a particular proxy DLL. The dlldata file is created or updated during each MIDL compilation, incrementally building a list of the interfaces that will go into the proxy DLL.

See Also

midl


/env

midl /env { dos | win16 | win32 }

dos

Directs the MIDL compiler to generate stub files for an MS-DOS environment.

win16

Directs the MIDL compiler to generate stub files for the 16-bit Microsoft Windows environment such as Microsoft Windows 3.x or Microsoft Windows for Workgroups 3.1.

Note  The server-stub file is not generated when you use the MIDL compiler switch /env with either the dos or win16 option.

win32

Directs the MIDL compiler to generate stub files for a 32-bit Microsoft Windows environment such as Microsoft Windows NT.

Examples

midl /env dos foo.idl

midl /env win32 foo.idl

Remarks

The /env switch selects the environment in which the application runs. The /env switch primarily affects the packing level used for structures in that environment.

Specify the same packing-level setting for both the MIDL compiler and the C compiler.

The /env switch determines the packing level and other settings as follows:

/env	Packing level	Description
/env dos	2 or /Zp setting	_ _far precedes pointer declarations.
/env win16	2 or /Zp setting	_ _far precedes pointer declarations.
/env win32	8 or /Zp setting	No declaration qualifiers are added.
When dos is selected, _ _far precedes pointer declarations in the generated header file, and the stub files use packing-level 2 for all types involved in remote operations.

When win16 is selected, _ _far precedes pointer declarations in the generated files, stub files assume C-compiler packing-level 2 for all types involved in remote operations, and _ _export is applied to callback stubs on the client side. You must compile the stubs with the /GA option.

When win32 is selected, generated stubs assume C-compiler packing-level 8 for all types involved in remote operations.

When the 32-bit version of the MIDL compiler runs on Microsoft Windows NT, stubs are generated for the win32 environment.

The compiler applies packing-level /Zp4 to all types involved in a remote procedure call.

The /pack and /Zp switches take precedence over the /env settings.

See Also

midl, /pack, /Zp


/error

midl /error { allocation | stub_data | none | all }

allocation

Checks whether midl_user_allocate returns a null value, indicating an out-of-memory error.

stub_data

Generates a stub that catches unmarshalling exceptions on the server side and propogates them back to the client.

none

Performs no error checking.

all

Performs all error checking.

Examples

midl /error allocation foo.idl

midl /error none foo.idl

Remarks

The /error switch selects the amount of error checking to be performed by the generated stub files.

By default, the MIDL compiler generates code that checks for enum and memory-access errors. Enum errors are truncation errors caused by conversion between long enum types (32-bit integers) and short enum types (the network-data representation of enum). Memory-access errors are errors caused when array indexes are out of bounds or when a pointer exceeds the end of the buffer in marshalling code.

When you specify /error allocate, the stubs include code that raises an exception when midl_user_allocate returns 0.

The /error stub_data option prevents client data from crashing the server during unmarshalling; in effect providing a more robust method of handling the unmarshalling operation.

See Also

midl


/header

midl /header filename

filename

Specifies a header filename that overrides the default header filename. Filenames can be explicitly quoted using double quotes (") to prevent the shell from interpreting the special characters.

Example

midl /header "bar.h" foo.idl

Remarks

The /header switch specifies the name of the header file. The specified filename replaces the default filename. The default filename is obtained by replacing the IDL file extension (usually .IDL) with the extension .H. For OLE interfaces, the /header switch overrides the default name of the interface header file.

When you are importing files, the specified filename applies to only one header file— the header file that corresponds to the IDL file specified on the command line.

If filename does not include an explicit path, the file is written to the current directory or the directory specified by the /out switch. An explicit path in filename overrides the /out switch specification.

See Also

/cstub, midl, /out, /sstub, /proxy


/help
/help  (/?)

midl /help
midl /?

Example

midl /help

Remarks

The /help (/?) switch instructs the compiler to display a usage message detailing all available MIDL command-line switches and options.

The /confirm switch displays the MIDL compiler switch settings selected by the user.

See Also

/confirm, midl


/I

midl /Iinclude_path

include_path

Specifies one or more directories that contain import, include, and ACF files. White space between the /I switch and include_path is optional. Separate multiple directories with a semicolon character (;).

Example

midl /I c:\include;c:\include\h /I\include2 foo.idl

Remarks

The /I switch specifies directories to be searched for imported IDL files, included header files, and ACF files. More than one directory can appear with each /I switch, and more than one /I switch can appear with each MIDL compiler invocation. Directories are searched in the order they are specified.

The /I switch setting is also passed by the MIDL compiler to the C compiler's C preprocessor. When the /cpp_cmd switch is present and the /cpp_opt switch is not, the MIDL compiler concatenates the string specified by the /cpp_cmd switch with the /I, /D, and /U options and uses this concatenated string to invoke the C preprocessor for each IDL and ACF source file. The MIDL compiler switch /I is not passed to the preprocessor when the MIDL compiler switch /no_cpp or /cpp_opt is specified.

In Microsoft operating-system environments (Windows NT, Windows 3.x, Windows for Workgroups, and MS-DOS), directories are searched in the following sequence:

1.	Current directory

2.	Directories specified by the /I switch (in order as they appear following the switch)

3.	Directories specified by the INCLUDE environment variable

When directories are specified with the /I switch, the /no_def_idir switch instructs the MIDL compiler to ignore the current directory, ignore the directories specified by the INCLUDE environment variable, and search only the specified directories.

When no directories are specified with the /I switch, the /no_def_idir switch instructs the MIDL compiler to search only the current directory.

See Also

/acf, /cpp_cmd, /cpp_opt, midl, /no_def_idir


/iid

midl /iid filename

filename

Specifies an interface identifier filename that overrides the default interface identifier filename for an OLE interface. Filenames can be explicitly quoted using double quotes (") to prevent the shell from interpreting the special characters.

Example

midl /iid "foo_iid.c" foo.idl

Remarks

The /iid switch specifies the name of the interface identifier file for an OLE interface, overriding the default name obtained by adding _I.C to the IDL filename. The /iid switch does not affect RPC interfaces.

If filename does not include an explicit path, the file is written to the current directory or to the directory specified by the /out switch. An explicit path in filename overrides the /out switch specification.

See Also

/header, midl, /out, /proxy


/import

This switch is obsolete and if used, results in an error.


/ms_ext

midl /ms_ext

Examples

midl /ms_ext foo.idl

midl /ms_ext /app_config foo.idl

midl /ms_ext /app_config /c_ext foo.idl

Remarks

The /ms_ext switch enables Microsoft extensions to DCE IDL. The following features are supported in Microsoft-extensions mode:

•	Interface definitions for OLE objects. For more information on the files generated for OLE interfaces, see midl.

•	A callback attribute specifying a static callback function on the client

•	cpp_quote(quoted_string) and #pragma midl_echo

•	wchar_t wide-character types, constants, and strings

•	enum initialization (sparse enumerators)

•	Expressions as size and discriminator specifiers

•	Handle extensions

•	Pointer-attribute type inheritance

•	Multiple interfaces

•	Definitions outside of the interface block

Note that directional attributes can be omitted when using the /ms_ext mode.

Handle Extensions

The MIDL compiler switch /ms_ext allows Microsoft extensions to the IDL language that support multiple handle parameters and handle parameters that appear in positions other than the first, leftmost, parameter.

The following table describes the sequence of steps that the MIDL compiler goes through to resolve the binding-handle parameter in DCE-compatibility mode and in Microsoft-extensions mode:

	DCE-compatibility mode		Microsoft-extensions mode
1.	Binding handle that appears in first parameter position	1.	Leftmost explicit binding handle
2.	Leftmost in, context_handle parameter	2.	Implicit binding handle specified by implicit_handle or auto_handle
3.	Implicit binding handle specified by implicit_handle or auto_handle	3.	If no ACF present, default to use of auto_handle
4.	If no ACF present, default to use of auto_handle
DCE IDL compilers look for an explicit binding handle as the first parameter. When the first parameter is not a binding handle and one or more context handles are specified, the leftmost context handle is used as the binding handle. When the first parameter is not a handle and there are no context handles, the procedure uses implicit binding using the ACF attribute implicit_handle or auto_handle.

The Microsoft extension to the IDL allows the binding handle to be in a position other than the first parameter. The leftmost in explicit-handle parameter, whether it is a primitive, user-defined, or context handle, is the binding handle. When there are no handle parameters, the procedure uses implicit binding using the ACF attribute implicit_handle or auto_handle.

The following rules apply to both DCE-compatibility mode and Microsoft-extensions mode:

•	Auto-handle binding is used when no ACF is present.

•	Explicit in or in, out handles for an individual function pre-empt any implicit binding specified for the interface.

•	Multiple in or in, out primitive handles are not supported.

•	Multiple in or in, out explicit context handles are allowed.

•	All user-defined handle parameters except the binding-handle parameter are treated as transmissible data.

The following table contains examples and describes how the binding handles are assigned in each compiler mode:

Example	Description
void proc1( void );	No explicit handle is specified. The implicit binding handle, specified by implicit_handle or auto_handle, is used. When no ACF is present, an auto handle is used.
void proc2( [in] handle_t H,           [in] short s );	An explicit handle of type handle_t is specified. The parameter H is the binding handle for the procedure.
void proc3( [in] short s,           [in] handle_t H );	The first parameter is not a handle. In DCE-compatibility mode, implicit binding is used. An error is reported because the second parameter is expected to be transmissible, and handle_t cannot be transmitted. In Microsoft-extensions mode, the leftmost handle parameter, H, is the binding handle.
typedef [handle] short *           MY_HDL; void proc1([in] short s,           [in] MY_HDL H );	The first parameter is not a handle. In DCE-compatibility mode, implicit binding is used. The user-defined handle parameter H is treated as transmissible data.  In Microsoft-extensions mode, the leftmost handle parameter, H, is the binding handle. The stubs call the user-supplied routines MY_HDL_bind and MY_HDL_unbind.
typedef [handle] short *            MY_HDL; void proc1([in] MY_HDL H,            [in] MY_HDL p );	The first parameter is a binding handle. The parameter H is the binding-handle parameter. The second user-defined handle parameter is treated as transmissible data.
typedef [context_handle]     void * CTXT_HDL; void proc1([in] short s,       [in] long l,       [in] CTXT_HDL H ,       [in] char c);	The binding handle is a context handle. The parameter H is the binding handle.
Pointer-Attribute Type Inheritance

According to the DCE specification, each IDL file must define attributes for its pointers. If an explicit attribute is not assigned to a pointer, the pointer uses the value specified by the pointer_default keyword. DCE does not allow unattributed pointers. If a pointer does not have an explicit attribute, the IDL file must have a pointer_default specification so that the pointer attribute can be set.

In Microsoft-extensions mode, you can control pointer attributes from the base IDL file. This feature allows an IDL file to contain pointer types whose pointer attributes are not resolved until that IDL file is imported by another IDL file. These kinds of pointers are known as unattributed pointers. When neither the base nor the imported IDL files specify a pointer attribute or pointer default, unattributed pointers are interpreted as unique pointers.

The MIDL compiler assigns pointer attributes to pointers using the following priority rules (1 is highest):

1.	Explicit pointer attributes applied to the pointer at the definition or use site

2.	Pointer_default in the IDL file that defines the type

3.	Pointer_default in the IDL file that imports the type

4.	Unique in Microsoft-extensions mode; ptr in DCE-compatibility mode

Two other switches control MIDL language features: /app_config and /c_ext. These switches can be used independently of the /ms_ext switch. For more information about these compiler modes, see /app_config and /c_ext.

See Also

midl


/ms_union

midl /ms_union

Example

midl /ms_union file.idl

Remarks

The /ms_union switch controls the NDR alignment of non-encapsulated unions.

The MIDL compiler mirrors the behavior of the OSF DCE IDL compiler for non-encapsulated unions. However, because earlier versions of the MIDL compiler did not do so, the /ms_union switch provides compatibility with interfaces built on previous versions of the MIDL compiler.

The ms_union feature can be used as a command line switch (/ms_union), an IDL interface attribute, or as an IDL type attribute.

See Also

IDL, ms_union


/no_cpp

midl /no_cpp

Example

midl /no_cpp foo.idl

Remarks

The /no_cpp switch specifies that the MIDL compiler does not call the C preprocessor to preprocess the IDL file.

The /no_cpp switch takes precedence over the /cpp_cmd and /cpp_opt switches.

See Also

/cpp_cmd, /cpp_opt, /D, /I, midl, /U


/no_default_epv

midl /no_default_epv

Example

midl /no_default_epv foo.idl

Remarks

The /no_default_epv switch directs the MIDL compiler not to generate a default epv. In this case, the application must register an epv with the RpcServerRegisterIf call. Compare this switch with the /use_epv switch described earlier in this chapter.

See Also

IDL, /use_epv, RpcServerRegisterIf


/no_def_idir

midl /no_def_idir

Examples

; search only the current directory

midl /no_def_idir foo.idl

; search only the specified directories

midl /no_def_idir /I c:\c700\include foo.idl

Remarks

When directories are specified with the /I switch, the /no_def_idir switch instructs the MIDL compiler to search only the directories specified with the /I switch, ignoring the current directory and ignoring the directories specified by the INCLUDE environment variable.

When no directories are specified with the /I switch, the /no_def_idir switch instructs the MIDL compiler to search only the current directory.

See Also

/acf, /I, midl


/no_warn

midl /no_warn

Examples

midl /no_warn foo.idl

midl /W0 foo.idl

Remarks

The /no_warn switch directs the MIDL compiler to suppress warning messages. The use of the /no_warn switch is equivalent to /W0.

See Also

midl, /W, /WX


/Oi

midl /Oi
midl /Oi1

Examples

midl /Oi foo.idl

midl /Oi /ms_ext foo.idl

midl /Oi /ms_ext /c_ext foo.idl

midl /Oi1 foo.idl

Remarks

The /Oi switch specifies the fully-interpreted method to marshal stub code passed between client and server.

The /Oi1 option of this switch can be used to generate interpreted stub code if you are using version 3.51 of Windows NT. Note that this option will not work with the 3.5 version of Windows NT.

Note  Stubs generated by the MIDL compiler in the interpreted method using the /Oi switch must be compiled as either a stdcall or a cdecl procedure during the C compilation. A PASCAL or Fastcall calling convention will not work. Additionally, the server stub must be compiled as __stdcall.

The number of parameters allowed is limited to 16 parameters on all platforms. Any procedure containing more than 16 parameters will automatically be processed in /Os mode.

There are important issues to consider before deciding on the method for marshalling code. These issues concern size and performance. The MIDL 2.0 compiler provides two methods for marshalling code: fully-interpreted (/Oi) and mixed-mode (/Os). Mixed-mode is the default.

The fully-interpreted method marshals data completely offline. This considerably reduces the size of the stub code. However, it also results in decreased performance.

If performance is a concern, the mixed-mode (/Os) method can be the best approach. In this mode, the compiler chooses to marshall some parameters inline in the generated stubs. While this results in larger stub size, it offers increased performance.

To further define the level of gradiation in how data is marshalled, this version of RPC provides an optimize attribute. This attribute is used as an ACF interface attribute or operation attribute to select the marshalling mode.

See Also

/Os, optimize


/oldnames

midl /oldnames

Example

midl /oldnames foo.idl

Remarks

The /oldnames switch directs the MIDL compiler to generate interface names which do not include the version number.

The MIDL 2.0 compiler incorporates the version number of the interface into the interface name that is generated in the stub (for example,  foo_v1_0_ServerIfHandle). This naming format is consistent with the format used by the OSF DCE IDL compiler. However, it differs from the naming format used by the MIDL 1.0 compiler.  The MIDL 1.0 compiler did not include version numbers in interface names (for example,  foo_ServerIfHandle). The /oldnames switch allows you to instruct the MIDL compiler to generate interface names which do not include the version number. In this way, the format is consistent with names generated by the MIDL 1.0 compiler.

If you have server application code that was written for use with a stub generated by the MIDL 1.0 compiler, and it refers to the MIDL-generated interface name (for example, in a call to RpcServerRegisterIf), you must either change it to reference the MIDL 2.0 style of interface name or use the /oldnames switch when invoking the MIDL compiler.

See Also

IDL


/Os

midl /Os

Examples

midl /Os foo.idl

midl /Os /ms_ext foo.idl

midl /Os /ms_ext /c_ext foo.idl

Remarks

The /Os switch specifies the mixed-mode method to marshal stub code passed between client and server.

There are important issues to consider before deciding on the method for marshalling code. These issues concern size and performance. The MIDL 2.0 compiler provides two methods for marshalling code: mixed-mode (/Os) and fully-interpreted (/Oi). The fully-interpreted method marshals data completely offline. This reduces the size of the stub code considerably. However, it also results in decreased performance.

If performance is an important concern, the mixed-mode method (/Os) can be the best approach. In this mode, the compiler marshals some parameters inline in the generated stubs. While this results in larger stub size, it also offers increased performance. Because mixed-mode is the default, you need not explicitly select the /Os switch to accomplish mixed-mode marshalling.

To further define the level of gradiation in how data is marshalled, this version of RPC provides an optimize attribute. This attribute is used as an ACF interface attribute or operation attribute to select the marshalling mode.

See Also

/Oi, optimize


/out

midl /out path-specification

path-specification

Specifies the path to the directory in which the stub, header, and switch files are generated. A drive specification, an absolute directory path, or both can be specified. Paths can be explicitly quoted using double quotes (") to prevent the shell from interpreting the special characters.

Examples

midl /out c:\mydir\mysubdir\subdir2 deeper foo.idl

midl /out c:  foo.idl

midl /out \mydir\mysubdir\another foo.idl

Remarks

The /out switch specifies the default directory where the MIDL compiler writes output files. The output directory can be specified with a drive letter, an absolute path name, or both. The /out option can be used with any of the switches that enable individual output file specification.

When the /out switch is not specified, files are written to the current directory.

The default directory specified by the /out switch can be overridden by an explicit path name specified as part of the /cstub, /header, /proxy, or /sstub switch.

See Also

/cstub, /header, midl, /proxy, /sstub


/pack

midl /pack packing_level

packing_level

Specifies the packing level of structures in the target system. The packing-level value can be set to 1, 2, 4, or 8.

Examples

midl /pack 2 foo.idl

midl /pack 8 bar.idl

Remarks

The /pack switch is the same as the /Zp option. The /pack switch designates the packing level of structures in the target system. The packing-level value corresponds to the /Zp option value used by the Microsoft C/C++ version 7.0 compiler. For more information, see your Microsoft C/C++ programming documentation.

Specify the same packing level when you invoke the MIDL compiler and the C compiler. The default is 8.

For a discussion of the potential dangers in using non-standard packing levels, see the /Zp help topic.

See Also

midl, /env, /Zp


/prefix

midl /prefix { client | server | switch | all }

client

Affects only the client stub routine names.

server

Affects only the routine names called by the server stub routine.

switch

Affects an extra prototype added to the header file.

all

Affects both the client and server stub routine names.

Examples

midl /prefix client "c_" server "s_"

midl /prefix all "foo_"

midl /prefix client "bar_"

Remarks

The /prefix switch directs the MIDL compiler to add prefix strings to the client and/or server stub routine names. This can be used to allow a single program to be both a client and server of the same interface, without having the client- and server-side routine names conflict with each other. If the prefix for the client-side routines is different from the prefix for the server-side routines, the generated header file will have both client-side routine prototypes and server-side routine prototypes.

The /prefix switch is useful when a single header file will be used with stubs from multiple runs of the MIDL compiler. This forces additional routine prototypes in the header file.

In all cases, the client, server, and switch prefixes will override an all prefix.

See Also

midl


/proxy

midl /proxy proxy_file_name

proxy_file_name

Specifies a filename that overrides the default interface proxy filename. Filenames can be explicitly quoted using double quotes (") to prevent the shell from interpreting the special characters.

Example

midl /proxy my_proxy.c foo.idl

Remarks

The /proxy switch specifies the name of the interface proxy file for an OLE interface. The specified filename replaces the default filename obtained by adding _P.C to the name of the IDL file. The /proxy switch does not affect RPC interfaces.

If proxy_file_name does not include an explicit path, the file is written to the current directory or to the directory specified by the /out switch. An explicit path in proxy_file_name overrides the /out switch specification.

For a more detailed description of the interface proxy file and other files generated by the MIDL compiler, see midl.

See Also

/header, /iid, midl, /out


/rpcss

midl /rpcss

Example

midl /rpcss foo.idl

Remarks

The /rpcss switch, when specified, acts as though the enable_allocate attribute was specified on all operations of the interface. In osf mode, the server side stub enables the rpcss allocation package.  However, when using the ms_ext mode of operation, the rpcss package is enabled only if either the procedure or interface has the enable_allocate attribute or the /rpcss switch is specified on the command line.

See Also

IDL, enable_allocate, /ms_ext


/saux

This switch is obsolete and if used, results in an error.


/server

midl /server { stub | none }

stub

Generates the server-side files.

none

Does not generate server-side files.

Examples

midl /server none

midl /server stub

Remarks

When the /server switch is not specified, the MIDL compiler generates the server stub file. This switch does not affect OLE interfaces.

The none option causes no files to be generated.

The /server switch takes precedence over the /sstub switch.

See Also

/client, midl, /sstub


/sstub

midl /sstub stub_file_name

stub_file_name

Specifies a filename that overrides the default server stub filename. Filenames can be explicitly quoted using double quotes (") to prevent the shell from interpreting the special characters.

Example

midl /sstub my_sstub.c foo.idl

Remarks

The /sstub switch specifies the name of the server stub file for an RPC interface. The specified filename replaces the default filename. By default, the filename is obtained by adding _S.C to the name of the IDL file. This switch does not affect OLE interfaces.

When you are importing files, the specified filename applies to only one stub file — the stub file that corresponds to the IDL file specified on the command line.

If stub_file_name does not include an explicit path, the file is written to the current directory or the directory specified by the /out switch. An explicit path in stub_file_name overrides the /out switch specification.

The /server none switch takes precedence over the /sstub switch.

See Also

/cstub, /header, /out


/syntax_check

midl /syntax_check
midl /Zs

Examples

midl /Zs foo.idl
midl /syntax_check foo.idl

Remarks

The /syntax_check switch indicates that the compiler checks only syntax and does not generate output files. This switch overrides all other switches that specify information about output files.

You can also specify syntax-checking mode with the MIDL compiler option /Zs.

See Also

midl, /Zs


/U

midl /Uname

name

Specifies a defined name to be passed to the C preprocessor as if by a #undefine directive. The name is predefined by the C preprocessor or previously defined by the user.

Example

midl /UUNICODE foo.idl

Remarks

The /U switch removes any previous definition of a name by passing the name to the C preprocessor as if by a #undefine directive. Multiple /U directives can be used in a command line. White space between the /U switch and the undefined name is optional.

When the /cpp_cmd switch is present and the /cpp_opt switch is not, the MIDL compiler concatenates the string specified by the /cpp_cmd switch with the /I, /D, and /U options and uses this concatenated string to invoke the C preprocessor for each IDL and ACF source file. The MIDL compiler switch /U is ignored when the MIDL compiler switch /no_cpp or /cpp_opt is specified.

See Also

/cpp_cmd, /cpp_opt, /D, /I, midl, /no_cpp


/use_epv

midl /use_epv

Example

midl /use_epv foo.idl

Remarks

The /use_epv switch directs the MIDL compiler to generate server stub code that calls the server application routine through an entry point vector (epv), rather than by a static call.

Typically, applications require static linkage to the server application routine. The MIDL compiler generates such a call by default. However, if an application requires the server stub to call the server application routine by using the epv, the /use_epv switch must be specified. When the /use_epv switch is specified, the MIDL compiler generates a default epv. This default epv is then used if the application does not register another epv through the RpcServerRegisterIf call.

See Also

IDL, /no_default_epv, RpcServerRegisterIf


/W

midl /Wlevel

level

Specifies the warning level, an integer in the range 0 through 4. There is no space between the /W switch and the digit indicating the warning-level value.

Examples

midl /W2 foo.idl

midl /W4 bar.idl

Remarks

The /W switch specifies the warning level of the MIDL compiler; the warning level indicates the severity of the warning. Warning levels range from 1 to 4, with a value of zero meaning to display no warning information. The highest-severity warning is level 1. The following table describes the warnings for each warning level:

Warning level	Description	Example
W0	No warnings
W1	Severe warnings that can cause application errors	No binding handle specified, unattributed pointers, conflicting switches
W2	May cause problems in the user's operating environment	Identifier length exceeds 31 characters; no default union arm specified
W3	Reserved
W4	Lowest warning level	Non-ANSI C constructs
Warnings are different from errors. Errors cause the MIDL compiler to halt processing of the IDL file. Warnings cause the MIDL compiler to emit an informational message and continue processing the IDL file.

The warning level set by the /W switch can be used with the /WX switch to cause the MIDL compiler to halt processing of the IDL file.

The /W switch behaves the same as the /warn switch.

See Also

midl, /warn,


/warn

midl /warnlevel

level

Specifies the warning level, an integer in the range 0 through 4. There is no space between the /warn switch and the digit indicating the warning-level value.

Examples

midl /warn2 foo.idl

midl /warn4 bar.idl

Remarks

The /warn switch specifies the warning level of the MIDL compiler; the warning level indicates the severity of the warning. Warning levels range from 1 to 4, with a value of zero meaning to display no warning information. The highest severity warning is level 1. The following table describes the warnings for each warning level:

Warning level	Description	Example
0	No warnings
1	Severe warnings that can cause application errors	No binding handle specified, unattributed pointers, conflicting switches
2	May cause problems in the user's operating environment	Identifier length exceeds 31 characters; no default union arm specified
3	Reserved
4	Lowest warning level	Non-ANSI C constructs
Warnings are different from errors. Errors cause the MIDL compiler to halt processing of the IDL file. Warnings cause the MIDL compiler to emit an informational message and continue processing the IDL file.

The warning level set by the /warn switch can be used with the WX switch to cause the MIDL compiler to halt processing of the IDL file.

The /warn switch behaves the same as the /W switch.

See Also

midl


/WX

midl /WX

Examples

midl /WX foo.idl

midl /W3 /WX foo.idl

Remarks

The /WX switch instructs the MIDL compiler to handle all errors at the given warning level as errors. If the /WX switch is specified and the /Wn switch is not specified, all warnings at the default level, level 1, are treated as errors.

The /Wn switch directs the compiler to display all warnings at level n and /WX directs the compiler to handle all warnings as errors. The combination of these two switches directs the compiler to handle all warnings at level n as errors.

Errors are different from warnings. Errors cause the MIDL compiler to halt processing of the IDL file. Warnings cause the MIDL compiler to emit an informational message and continue processing the IDL file.

Warning-level zero (0) directs the MIDL compiler to suppress warning information. When the /W0 and /WX switches are combined, the MIDL compiler suppresses all warning information. In this case, the /WX switch has no effect.

See Also

midl, /W


/Zp

midl /Zppacking_level

packing_level

Specifies the packing level of structures in the target system. The packing-level value can be set to 1, 2, 4, or 8.

Example

midl /Zp4 foo.idl

Remarks

The /Zp switch is the same as the /pack option.

The /Zp switch designates the packing level of structures in the target system. The packing-level value corresponds to the /Zp option value used by the Microsoft C/C++ compiler. For more information, see your Microsoft C/C++ programming documentation.

Specify the same packing level when you invoke the MIDL compiler and the C compiler.

The default packing level used when you do not specify the /Zp or /pack switch is 8.

Note  Do not use /Zp1 or /Zp2 on MIPS or Alpha platforms, and do not use /Zp4 or /Zp8 on 16-bit platforms. Depending on the data type and memory location assigned by the C compiler at runtime, this can result in a data misalignment exception on MIPS and Alpha platforms.  On MS-DOS platforms, the C compiler will not ensure the alignment at 4 or 8, and so the application may terminate.

See Also

midl, /pack


/Zs

midl /Zs
midl /syntax_check

Examples

midl /Zs foo.idl

midl /syntax_check foo.idl

Remarks

The /Zs switch indicates that the compiler only checks syntax and does not generate output files.

This switch overrides all other switches that specify information about output files.

You can also specify syntax-checking mode with the MIDL compiler switch /syntax_check.

See Also

midl, /syntax_check


MIDL Reference

This section provides a reference entry for each keyword in the Microsoft Interface Definition Language (MIDL) and application configuration file (ACF). Reference entries are also provided for important language productions and concepts. Each reference entry includes syntax, examples, descriptions, and cross-references.

The reference entries are arranged in alphabetical order. To examine the top-level structure of these files, start with the topics ACF and IDL.


ACF

[ interface-attribute-list ] interface interface-name
{
[ include filename-list ; ... ]
[ typedef [type-attribute-list] typename; ... ]

[	[ [function-attribute-list] ] function-name(
[ [ [parameter-attribute-list] ] parameter-name ]
...
);
]
...
}

.

.

.

interface-attribute-list

Specifies a list of one or more attributes that apply to the interface as a whole. Valid attributes include auto_handle, implicit_handle, explicit_handle, and optimize, code or nocode. When two or more interface attributes are present, they must be separated by commas.

interface-name

Specifies the name of the interface. In DCE-compatibility mode, the interface name must match the name of the interface specified in the IDL file. When you use the MIDL compiler switch /acf, the interface name in the ACF and the interface name in the IDL file can be different.

filename-list

Specifies a list of one or more C-language header filenames, separated by commas. The full filename, including the extension, must be supplied.

type-attribute-list

Specifies a list of one or more attributes, separated by commas, that apply to the specified type. Valid type attributes include allocate or represent_as.

typename

Specifies a type defined in the IDL file. Type attributes in the ACF can only be applied to types previously defined in the IDL file.

function-attribute-list

Specifies a list of one or more attributes, separated by commas, that apply to the function-return type. Valid function attributes include allocate, optimize, call_as, code or nocode.

function-name

Specifies the name of the function in the IDL file.

parameter-attribute-list

Specifies a list of zero or more attributes, separated by commas, that apply to the specified parameter. Valid parameter attributes include byte_count.

parameter-name

Specifies the name of the parameter in the IDL file. Only the name of the parameter must match the IDL file specification. The sequence of parameters is not significant.

Examples

/* example 1 */

[auto_handle] interface foo1 { }

/* example 2 */

[implicit_handle(handle_t h), code] interface foo2 {}

/* example 3 */

[code]

interface foo3;

{

include "foo3a.h", "foo3b.h";

typedef [allocate(all_nodes)] TREETYPE1;

typedef [allocate(all_nodes, dont_free)] TREETYPE2;

f1([byte_count(length)] pBuffer);

}

Remarks

The application configuration file, or ACF, is one of two files that define the interface for your distributed application. The second interface-defining file is the IDL file. The IDL file contains type definitions and function prototypes that describe how data is transmitted on the network. The ACF configures your application for a particular operating environment without affecting its network characteristics.

By using the IDL and ACF files, you separate the interface specification from environment-specific settings. The IDL file is meant to be portable to any other computer. When you move your distributed application to another computer, you should be able to reuse the IDL file. Environment-specific changes are made in the ACF.

Many distributed applications require no special configuration. For such applications, use the MIDL compiler switch /app_config to supply the ACF keywords auto_handle and implicit_handle in the IDL file and omit the ACF.

The ACF corresponds to the IDL file in the following ways:

•	The interface name in the ACF must be the same as the interface name in the IDL file unless you compile with the MIDL compiler switch /acf.

•	All type names and function names in the ACF must refer to types and functions defined in the IDL file.

•	Function parameters need not appear in the same sequence in the ACF as in the IDL file, but parameter names in the ACF must match names in the IDL file.

Like the IDL file, the ACF consists of a header portion and a body portion, and in /ms_ext mode, it can contain multiple interfaces.


The ACF Header

The ACF header contains attributes that apply to the interface as a whole. Attributes applied to individual types and functions in the ACF body override the attributes in the ACF header. No attributes are required in the ACF header.

The ACF header can include one of the following attributes: auto_handle, implicit_handle, or explicit_handle. These handle attributes specify the type of handle used for implicit binding when a remote function does not have an explicit binding-handle parameter. When the ACF is not present or does not specify an auto, implicit handle, or explicit attribute, MIDL uses auto_handle for implicit binding.

Either code or nocode can appear in the interface header, and the one you choose can appear only once. When neither attribute is present, the compiler uses code as a default.


The ACF Body

The ACF body contains configuration attributes that apply to types and functions defined in the interface body of the IDL file. The ACF body can contain ACF include, typedef, function, and parameter attributes. All of these items are optional. The body of the ACF can be empty. Attributes applied to individual types and functions in the ACF body override attributes in the ACF header.

The ACF include directive specifies header files to appear in the generated header as part of a standard C-preprocessor #include statement. The ACF keyword include differs from a #include directive. The ACF keyword include causes the line "#include filename" to appear in the generated header file, while the C-language directive "#include filename" causes the contents of that file to be placed in the ACF.

The ACF typedef statement allows you to apply ACF type attributes to types previously defined in the IDL file. The ACF typedef syntax differs from the C typedef syntax.

The ACF function attributes allow you to specify attributes that apply to the function as a whole. For more information, see code, optimize, and nocode.

The ACF parameter attributes allow you to specify attributes that apply to individual parameters of the function. For more information, see byte_count.

See Also

/app_config, auto_handle, code, explicit_handle, IDL, implicit_handle, include, midl, nocode, optimize, represent_as, typedef


allocate

typedef [allocate (allocate-option-list) [, type-attribute-list] ] type-name;

allocate-option-list

Specifies one or more memory-allocation options. Select one of either single_node or all_nodes, or one of either free or dont_free, or one from each group. When you specify more than one option, separate options with commas.

type-attribute-list

Specifies other optional ACF type attributes. When you specify more than one type attribute, separate options with commas.

type-name

Specifies a type defined in the IDL file.

Examples

/* ACF file */

typedef [allocate(all_nodes, dont_free)] PTYPE1;

typedef [allocate(all_nodes)] PTYPE2;

typedef [allocate(dont_free)] PTYPE3;

Remarks

The ACF type attribute allocate allows you to customize memory allocation and deallocation for a type defined in the IDL file. Valid options are as follows:

Option	Description
all_nodes	Makes one call to allocate and free memory for all nodes
single_node	Makes many individual calls to allocate and free each node of memory
free	Frees memory on return from the server stub
dont_free	Doesn't free memory on return from the server stub
By default, the stubs may allocate storage for data referenced by a unique or full pointer by calling midl_user_allocate and midl_user_free individually for each pointer.

You can optimize the speed of your application by specifying the option all_nodes. This option directs the stub to compute the size of all memory referenced through the pointer of the specified type and to make a single call to midl_user_allocate. The stub releases the memory by making one call to midl_user_free.

The dont_free option directs the MIDL compiler to generate a server stub that does not call midl_user_free for the specified type. The dont_free option allows the pointer structures to remain accessible to the server application after the remote procedure call has completed and returned to the client.

Note that when applied to types used for in, out parameters, any parameter that is a pointer to a type qualified with the all_nodes option will cause a reallocation when the data is unmarshalled. It is the responsibility of the application to free the previously allocated memory corresponding to this parameter. For example:

typedef struct foo

{

[string] char * PFOO;

} * PFOO

void proc1 ( [in,out] PFOO * ppfoo);

The data type PFOO will be reallocated in the out direction by the stub before "unmarshalling." Therefore, the previously allocated area must be freed by the application. Otherwise, a memory leak will occur.

See Also

ACF, midl_user_allocate, midl_user_free, typedef


arrays

typedef [ [type-attr-list] ] type-specifier [pointer-decl] array-declarator;

typedef [ [type-attr-list] ] struct [ tag ] {
[ [ field-attribute-list ] ] type-specifier [pointer-decl] array-declarator;
...
}
typedef [ [type-attr-list] ] union [ tag ] {
[ case (limited-expression [ , ... ] ) ]
[ [ field_attribute-list ] ] type-specifier [pointer-decl] array-declarator;
[ [ default ]
[ [ field_attribute-list ] ] type-specifier [pointer-decl] array-declarator;
]

[ [function-attribute-list] ] type-specifier [pointer-decl] function-name(
[ [param-attr-list] ] type-specifier [pointer-decl] array-declarator
, ...
);

type-attr-list

Specifies zero or more attributes that apply to the type. Valid type attributes include handle, switch_type, transmit_as; the pointer attribute ref, unique, or ptr; and the usage attributes context_handle, string, and ignore. Separate multiple attributes with commas.

type-specifier

Specifies the type identifier, base type, struct, union, or enum type. The type specification can include an optional storage specification.

pointer-decl

Specifies zero or more pointer declarators. A pointer declarator is the same as the pointer declarator used in C, constructed from the * designator, modifiers such as far, and the qualifier const.

array-declarator

Specifies the name of the array, followed by one of the following constructs for each dimension of the array: "[ ]", "[*]", "[const1]", or "[lower...upper]" where lower and upper are constant values that represent the lower and upper bounds. The constant lower must evaluate to zero.

tag

Specifies an optional tag for the structure or union.

field-attribute-list

Specifies zero or more field attributes that apply to the structure, union member, or function parameter. Valid field attributes include first_is, last_is, length_is, max_is, size_is; the usage attributes string, and ignore; the pointer attributes ref, unique, and ptr; and the union attribute switch_type. Separate multiple field attributes with commas. Note that of the attributes listed above, first_is, last_is, and ignore are not valid for unions.

limited-expression

Specifies a C-language expression supported by MIDL. Almost all C-language expressions are supported: The MIDL compiler supports conditional expressions, logical expressions, relational expressions, and arithmetic expressions. MIDL does not allow function invocations in expressions and does not allow pre- and post-increment and -decrement operators.

function-attribute-list

Specifies zero or more attributes that apply to the function. Valid function attributes are callback, local; the pointer attribute ref, unique, or ptr; and the usage attributes string, and context_handle.

function-name

Specifies the name of the remote procedure.

param-attr-list

Specifies the directional attributes and one or more optional field attributes that apply to the array parameter. Valid field attributes include max_is, size_is, length_is, first_is, and last_is.

Examples

/* IDL file interface body */

#define MAX_INDEX 10

typedef char  ATYPE[MAX_INDEX];

typedef short BTYPE[];        // Equivalent to [*];

typedef long  CTYPE[*][10];   // [][10]

typedef float DTYPE[0..10];   // Equivalent to [11]

typedef float ETYPE[0..(MAX_INDEX)];

typedef struct {

    unsigned short size;

    unsigned short length;

    [size_is(size), length_is(length)] char string[*];

} counted_string;

void MyFunction(

     [in, out] short * pSize,

     [in, out, string, size_is(*pSize)] char a[0..*]

);

Remarks

Array declarators appear in the interface body of the IDL file as part of a general declaration, as a member of a structure or union declarator, or as a parameter to a remote procedure call.

The bounds of each dimension of the array are expressed inside a separate pair of square brackets. An expression that evaluates to n signifies a lower bound of zero and an upper bound of n − 1. If the square brackets are empty or contain a single asterisk (*), the lower bound is zero and the upper bound is determined at run time.

The array can also contain two values separated by an ellipsis that represent the lower and upper bounds of the array, as in [lower...upper]. Microsoft RPC requires a lower bound of 0. The MIDL compiler does not recognize constructs that specify nonzero lower bounds.

Arrays can be associated with the field attributes size_is, max_is, length_is, first_is, and last_is to specify the size of the array or the part of the array that contains valid data. These field attributes identify the parameter, structure field, or constant that specifies the array dimension or index.

The array must be associated with the identifier specified by the field attribute as follows: When the array is a parameter, the identifier must also be a parameter to the same function; when the array is a structure field, the identifier must be another structure field of that same structure.

An array is called "conformant" if the upper bound of any dimension is determined at run time. Only upper bounds can be determined at run time. To determine the upper bound, the array declaration must include a size_is or max_is attribute.

An array is called "varying" when its bounds are determined at compile time, but the range of transmitted elements is determined at run time. To determine the range of transmitted elements, the array declaration must include a length_is, first_is, or last_is attribute.

A conformant varying array (also called "open") is an array whose upper bound and range of transmitted elements are determined at run time.

At most, one conformant or conformant varying array can be nested in a C structure and must be the last element of the structure. Nonconformant varying arrays can occur anywhere in a structure.

Multidimensional Arrays

The user can declare types that are arrays and then declare arrays of objects of such types. The semantics of m-dimensional arrays of n-dimensional array types are the same as the semantics of m+n-dimensional arrays.

For example, the type RECT_TYPE can be defined as a two-dimensional array and the variable rect can be defined as an array of RECT_TYPE. This is equivalent to the three-dimensional array equivalent_rect:

typedef short int RECT_TYPE[10][20];

RECT_TYPE rect[15];

short int equivalent_rect[15][10][20];  // ~RECT_TYPE rect[15]

Microsoft RPC is C-oriented. Following C-language conventions, only the first dimension of a multidimensional array can be run-time − determined. Interoperation with DCE IDL arrays that support other languages is limited to:

•	Multidimensional arrays with constant (compile-time − determined) bounds.

•	Multidimensional arrays with all constant bounds except the first dimension. The upper bound and range of transmitted elements of the first dimension are run-time − dependent.

•	Any one-dimensional arrays with a lower bound of zero.

When the string attribute is used on multidimensional arrays, the attribute applies to the rightmost array.

Arrays of Pointers

Reference pointers must point to valid data. The client application must allocate all memory for an in or in, out array of reference pointers, especially when the array is associated with in, or in, out length_is, or last_is values. The client application must also initialize all array elements before the call. Before returning to the client, the server application must verify that all array elements in the transmitted range point to valid storage.

On the server side, the stub allocates storage for all array elements, regardless of the length_is or last_is value at the time of the call. This feature can affect the performance of your application.

No restrictions are placed on arrays of unique pointers. On both the client and the server, storage is allocated for null pointers. When pointers are non-null, data is placed in preallocated storage.

An optional pointer declarator can precede the array declarator.

When embedded reference pointers are out-only parameters, the server-manager code must assign valid values to the array of reference pointers. For example,

typedef [ref] short * ARefPointer;
typedef ARefPointer ArrayOfRef[10];
void proc1( [out] ArrayOfRef Parameter );

The generated stubs allocate the array and assign NULL values to all pointers embedded in the array.

See Also

first_is, IDL, last_is, length_is, max_is, ptr, ref, size_is, string, unique


auto_handle

[ auto_handle [, interface-attribute-list] ] interface interface-name

interface-attribute-list

Specifies zero or more attributes that apply to the interface as a whole, such as code or nocode. Separate interface attributes with commas.

interface-name

Specifies the name of the interface.

Examples

[auto_handle] interface MyInterface { }

[auto_handle, code] interface MyInterface { }

Remarks

The ACF attribute auto_handle directs the stub to automatically establish the binding for a function that does not have an explicit binding-handle parameter.

The auto_handle attribute appears in the interface header of the ACF. It also appears in the interface header of the IDL file when you specify the MIDL compiler switch /app_config.

When the client calls a function that uses automatic binding, and no binding to a server exists, the stub automatically establishes the binding. The binding is reused for subsequent calls to other functions in the interface that use automatic binding. The client application program does not have to declare or perform any processing relating to the binding handle.

When the ACF is not present or does not include the implicit_handle attribute, the MIDL compiler uses auto_handle and issues an informational message. The MIDL compiler also uses auto_handle if needed to establish the initial binding for a context_handle.

The auto_handle attribute can occur only if the implicit_handle or explicit_handle attribute does not occur. The auto_handle attribute can occur in the ACF or IDL interface header at most once.

See Also

ACF, /app_config, context_handle, IDL, implicit_handle


base_types

Remarks

All data transmitted on the network during a remote procedure call must resolve to a base type or predefined type.

MIDL supports the following base types: boolean, byte, char, double, float, handle_t, hyper, long, short, small, and void *. The keywords signed and unsigned can be used to qualify integer and character types. MIDL also provides the predefined types error_status_t and wchar_t.

Base types can appear as type specifiers in const declarations, typedef declarations, general declarations, and as parameter type specifiers in function declarators.

The base and predefined types have the following default signs and default sizes:

Base type	Default sign	Description
boolean	unsigned	8-bit data item
byte	- (not applicable)	8-bit data item
char	unsigned	8-bit unsigned data item
double	-	64-bit floating-point number
float	-	32-bit floating-point number
handle_t	-	Primitive handle type
hyper	signed	64-bit signed integer
long	signed	32-bit signed integer
short	signed	16-bit signed integer
small	signed	8-bit signed integer
void *	-	32-bit context handle pointer type
wchar_t	unsigned	16-bit unsigned data item
Any other types in the interface must be derived from these base or predefined types. This requirement has the following two important effects:

•	The type int cannot appear in remote functions without a size qualifier such as short, small, long or hyper.

•	The type void * cannot appear in remote functions except when it is used to define a context handle.

DCE IDL compilers do not recognize the keyword signed. You can only use the keyword unsigned when you use the MIDL compiler in DCE-compatibility mode.

See Also

byte, char, handle_t, long, /ms_ext, short, small, wchar_t


boolean

Remarks

The keyword boolean indicates that the expression or constant expression associated with the identifier takes the value TRUE or FALSE.

The boolean type is one of the base types of the IDL language. The boolean type can appear as a type specifier in const declarations, typedef declarations, general declarations, and function declarators (as a function-return-type specifier and as a parameter-type specifier). For the context in which type specifiers appear, see IDL.

See Also

base_types, IDL


broadcast

[[ [ IDL-operation-attributes ] ]] operation-attribute , ...

IDL-operation-attributes

Specifies zero or more IDL operation attributes, such as broadcast and idempotent. Operation attributes are enclosed in square brackets.

Remarks

The keyword broadcast specifies that remote procedure calls be sent to all servers on a local network. Rather than being delivered to one particular server, the routine is always broadcast to all the servers on the network. The client receives output from the first reply to return successfully. Subsequent replies are discarded.

The broadcast attribute specifies that the routine can be called multiple times and at the same time be sent to multiple servers as the result of one RPC. This is different from the idempotent attribute, which specifies that a call can be retried if it does not complete. However, an operation with the broadcast attribute is implicitly an idempotent operation. It ensures that the data for an RPC is received and processed zero or more times.

The broadcast attribute is supported only by connectionless protocols (datagrams). If a remote procedure broadcasts its call to all hosts on a local network, it must use the datagram protocol sequence ncadg_ip_udp. Note that the size of a broadcast packet is determined by the datagram service in use.

See Also

idempotent, IDL, maybe, non-idempotent


byte

Remarks

The byte keyword specifies an 8-bit data item.

A byte data item does not undergo any conversion for transmission on the network, as can occur for a char type.

The byte type is one of the base types of the interface definition language (IDL). The byte type can appear as a type specifier in const declarations, typedef declarations, general declarations, and function declarators (as a function-return-type specifier and as a parameter-type specifier). For the context in which type specifiers appear, see IDL.

See Also

base_types, char


byte_count

[ function-attribute-list ] function-name(
[byte_count(length-variable-name)] pointer-parameter-name);
...
);

function-attribute-list

Specifies zero or more ACF function attributes.

function-name

Specifies the name of the function defined in the IDL file. The function name is required.

length-variable-name

Specifies the name of the in-only parameter that specifies the size, in bytes, of the memory area referenced by pointer-parameter-name.

pointer-parameter-name

Specifies the name of the out-only pointer parameter defined in the IDL file.

Examples

/* IDL file */

void proc1([in] unsigned long length, [out] struct foo * pFoo);

/* ACF file */

proc1([byte_count(length)] pFoo);

Remarks

Note  The ACF attribute byte_count represents a Microsoft extension to DCE IDL.

The byte_count attribute is a parameter attribute that associates a size, in bytes, of the memory area indicated by the pointer.

Memory referenced by the pointer parameter is contiguous and is not allocated or freed by the client stubs. This feature of the byte_count attribute allows you to create a persistent buffer area in client memory that can be reused during more than one call to the remote procedure.

The ability to turn off the client stub memory allocation allows you to tune the application for efficiency. For example, the byte_count attribute can be used by service-provider functions that use Microsoft RPC. When a user application calls the service-provider API and provides a pointer to a buffer, the service provider can pass the buffer pointer on to the remote function and reuse the buffer during multiple remote calls without forcing the user to reallocate the memory area.

The memory area can contain complex data structures that consist of multiple pointers. Because the memory area is contiguous, the application does not have to make many calls to individually free each pointer and structure. The memory area can be allocated or freed with one call to the memory allocation or free routine.

The buffer must be an out-only parameter. The buffer length in bytes must be an in-only parameter.

Note  Specify a buffer that is large enough to contain all the out parameters. Pointers are unmarshalled on a 4-byte aligned boundary. Therefore, alignment padding that the stubs will perform must be accounted for in the space for the buffer. In addition, packing levels used during C-language compilation can vary. Use a byte count value that accounts for additional packing bytes added for the packing level used during C-language compilation.

See Also

ACF, in, length_is, out, size_is


call_as

[call_as (local-proc), [ , operation-attribute-list ] ] operation-name ;

local-proc

Specifies an operation-defined routine.

operation-attribute-list

Specifies one or more attributes that apply to the operation. Separate multiple attributes with commas.

operation-name

Specifies the named operation presented to the application.

Remarks

The call_as attribute enables a non-remotable function to be mapped to a remote function. This is particularly helpful in interfaces that have numerous non-remotable types as parameters. Rather than using many represent_as and transmit_as types, you can combine all the conversions using call_as routines. You supply the two call_as routines (client side and server side) to bind the routine between the application calls and the remote calls. The call_as attribute can be used for object interfaces, where the interface definition can be used for local calls as well as remote calls because it allows a non-remotable interface to be remoted transparently. The call_as attribute can only be used for /ms_ext mode.

For example, assume that the routine f1 in object interface IFace requires numerous conversions between the user calls and what is actually transmitted. The following examples describe the IDL and ACF files for interface IFace:

In the IDL file for interface IFace:

[local] HRESULT f1 ( <users parameter list> )

[call_as( f1 )] long Remf1 ( <remotable parameter list> );

In the ACF for interface IFace:

[call_as( f1 )] Remf1();

This would cause the generated header file to define the interface using the definition of f1, yet it would also provide stubs for Remf1:

Generated Vtable in the header file for interface IFace:

struct IFace_vtable	{

...

HRESULT ( * f1) ( <users parameter list>);

...

};

The client-side proxy would then have a typical MIDL-generated proxy for Remf1, while the server side stub for Remf1 would be the same as the typical MIDL-generated stub:

void IFace_Remf1_Stub ( . . .)

{

...

invoke IFace_f1_Stub ( <remotable parameter list> ) 	/* instead
 of IFace_f1 */

...

}

Then, the two call_as bond routines (client side and server side) must be manually coded:

HRESULT f1_Proxy ( <users parameter list> )

{

...

Remf1_Proxy ( <remotable parameter list> );

...

}

long IFace_f1_Stub ( <remotable parameter list> )

{

...

IFace_f1 ( <users parameter list> );

...

}

For object interfaces, the prototypes for the bond routines are:

For client side:

<local_return_type>  <interface>_<local_routine>_proxy
( <local_parameter_list> );

For server side:

<remote_return_type>  <interface>_<local_routine>_stub
( <remote_parameter_list> );

For non-object interfaces, the prototypes for the bond routines are:

For client side:

<local_return_type>  <local_routine> ( <local_parameter_list> );

For server side:

<local_return_type>  <interface>_v<maj>_<min>_<local_routine>
( <remote_parameter_list> );

See Also

represent_as, transmit_as


callback

[callback [ , function-attr-list] ] type-specifier [ptr-declarator] function-name(
[ [parameter-attribute-list] ] type-specifier [declarator]
, ...
);

function-attr-list

Specifies zero or more attributes that apply to the function. Valid function attributes are local; the pointer attribute ref, unique, or ptr; and the usage attributes string, ignore, and context_handle. Separate multiple attributes with commas.

type-specifier

Specifies a base_type, struct, union, enum type, or type identifier. An optional storage specification can precede type-specifier.

ptr-declarator

Specifies zero or more pointer declarators. A pointer declarator is the same as the pointer declarator used in C; it is constructed from the * designator, modifiers such as far, and the qualifier const.

function-name

Specifies the name of the remote procedure.

parameter-attribute-list

Specifies zero or more directional attributes, field attributes, usage attributes, and pointer attributes appropriate for the specified parameter type. Separate multiple attributes with commas.

declarator

Specifies a standard C declarator such as identifiers, pointer declarators, and array declarators. For more information, see pointers and arrays. The parameter-name identifier is optional.

Example

[callback] void DisplayString([in, string] char * p1);

Remarks

The callback attribute declares a static callback function that exists on the client side of the distributed application. Callback functions provide a way for the server to execute code on the client.

The callback function is useful when the server must obtain information from the client. If server applications were supported on Windows 3.x, the server could make a call to a remote procedure on the Windows 3.x server to obtain the needed information. The callback function accomplishes the same purpose. The callback allows the server to query the client for information in the context of the original call.

Callbacks are special cases of remote calls that execute as part of a single thread. A callback is issued in the context of a remote call. Any remote procedure defined as part of the same interface as the static callback function can call the callback function.

Handles cannot be used as parameters in callback functions. Because callbacks always execute in the context of a call, the binding handle used by the client to make the call to the server is also used as the binding handle from the server to the client.

Callbacks can nest to any depth.

See Also

IDL, /ms_ext


char

Remarks

The keyword char identifies a data item that has 8 bits. To the MIDL compiler, a char is unsigned by default and is synonymous with unsigned char.

In this version of Microsoft RPC, the character translation tables that convert between ASCII and EBCDIC are built into the run-time libraries and cannot be changed by the user.

The char type is one of the base types of the interface definition language (IDL). The char type can appear as a type specifier in const declarations, typedef declarations, general declarations, and function declarators (as a function-return-type specifier and a parameter-type specifier). For the context in which type specifiers appear, see IDL.

DCE IDL compilers do not accept the keyword signed applied to char types. To allow this construct, use the MIDL compiler /ms_ext switch.

See Also

base_types, byte, /char, /ms_ext, signed, string, wchar_t


code

[ code [ , ACF-interface-attributes ] ] interface interface-name
{
[ include filename-list ; ] ...
[ typedef [type-attribute-list] typename; ] ...

[ [ code [ , ACF-function-attributes ] ] function-name (
[ ACF-parameter-attributes ] parameter-name ;
...
);
]
...
}

ACF-interface-attributes

Specifies a list of one or more attributes that apply to the interface as a whole. Valid attributes include either auto_handle or implicit_handle and either code, nocode, or optimize. When two or more interface attributes are present, they must be separated by commas.

interface-name

Specifies the name of the interface. In DCE-compatibility mode, the interface name must match the name of the interface specified in the IDL file. When you use the MIDL compiler switch /acf, the interface name in the ACF and the interface name in the IDL file can be different.

filename-list

Specifies a list of one or more C-header filenames, separated by commas. You must supply the full filename, including the extension.

type-attribute-list

Specifies a list of one or more attributes, separated by commas, that apply to the specified type. Valid type attributes include allocate and represent_as.

typename

Specifies a type defined in the IDL file. Type attributes in the ACF can only be applied to types previously defined in the IDL file.

ACF-function-attributes

Specifies zero or more other attributes that apply to the function as a whole, such as comm_status. Function attributes are enclosed in square brackets. Separate multiple function attributes with commas.

function-name

Specifies the name of the function as defined in the IDL file.

ACF-parameter-attributes

Specifies ACF attributes that apply to a parameter. Note that 0, 1, or more attributes can be applied to the parameter. Separate multiple parameter attributes with commas. ACF parameter attributes are enclosed in square brackets.

parameter-name

Specifies a parameter of the function as defined in the IDL file. Each parameter for the function must be specified in the same sequence and using the same name as defined in the IDL file.

Remarks

The code attribute can appear in the ACF header, or it can be applied to an individual function.

When the code attribute appears in the ACF header, client stub code is generated for all remote functions that do not have the nocode function attribute. You can override the code attribute in the header for an individual function by specifying the nocode attribute as a function attribute.

When the code attribute appears in the remote function's attribute list, client stub code is generated for the function.

Client stub code is not generated when:

•	The ACF header includes the nocode attribute.

•	The nocode attribute is applied to the function.

•	The local attribute applies to the function in the interface file.

Either code or nocode can appear in the interface or function attribute list, and the one you choose can appear exactly once in the list.

See Also

ACF, nocode


comm_status

[comm_status [ , ACF-function-attributes ] ] function-name(
[ [ ACF-parameter-attributes ] ] parameter-name
, ...
);

[ [ ACF-function-attributes ] ] function-name(
[comm_status [ , ACF-parameter-attributes ] ] parameter-name
... );

ACF-function-attributes

Specifies zero or more ACF function attributes, such as comm_status and nocode. Function attributes are enclosed in square brackets. Note that 0, 1, or more attributes can be applied to a function. Separate multiple function attributes with commas. Note that if comm_status appears as a function attribute, it cannot also appear as a parameter attribute.

function-name

Specifies the name of the function as defined in the IDL file.

ACF-parameter-attributes

Specifies attributes that apply to a parameter. Note that 0, 1, or more attributes can be applied to the parameter. Separate multiple parameter attributes with commas. Parameter attributes are enclosed in square brackets. IDL parameter attributes, such as directional attributes, are not allowed in the ACF. Note that if comm_status appears as a parameter attribute, it cannot also appear as a function attribute.

parameter-name

Specifies the parameter for the function as defined in the IDL file. Each parameter for the function must be specified in the same sequence, using the same name as defined in the IDL file.

Remarks

The comm_status attribute can be used as either a function attribute or as a parameter attribute, but it can appear only once per function. It can be applied either to the function or to one parameter in each function.

The comm_status attribute can only be applied to functions that return the type error_status_t. When a communication error occurs during the execution of the function, an error code is returned.

When comm_status is used as a parameter attribute, the parameter must be defined in the IDL file and must be an out parameter of type error_status_t. When a communication error occurs during the execution of the function, the parameter is set to the error code. When the remote call completes successfully, the procedure sets the value.

It is possible for both the comm_status and fault_status attributes to appear in a single function, either as function attributes or parameter attributes. If both attributes are function attributes or if they apply to the same parameter, and no error occurs, the function or parameter has the value error_status_ok. Otherwise, it contains the appropriate comm_status or fault_status value. Because values returned for comm_status are different from the values returned for fault_status, the returned values are readily interpreted.

See Also

ACF, error_status_t, fault_status,


const

const const-type identifier = const-expression ;

/* IDL file typedef syntax */
[ typedef [ , type-attribute-list ] ] const const-type declarator-list;
[ typedef [ , type-attribute-list ] ] pointer-type const declarator-list;

[ [ function-attr-list ] ] type-specifier [ ptr-decl ] function-name(
[ [ parameter-attribute-list ] ] const const-type [declarator],
[ [ parameter-attribute-list ] ] pointer-type const [declarator]
, ...
);

const-type

Specifies a valid MIDL integer, character, string, or boolean type. Valid MIDL types include small, short, long, char, char *, wchar_t, wchar_t *, byte, byte *, and void *. The integer and character types can be signed or unsigned.

identifier

Specifies a valid MIDL identifier. Valid MIDL identifiers consist of up to 31 alphanumeric and/or underscore characters and must start with an alphabetic or underscore character.

const-expression

Specifies an expression, identifier, or numeric or character constant appropriate for the specified type: constant integer literals or constant integer expressions for integer constants; boolean expressions that can be computed at compilation for boolean types; single-character constants for character types; and string constants for string types. The void * type can be initialized only to NULL.

type-attribute-list

Specifies one or more attributes that apply to the type.

pointer-type

Specifies a valid MIDL pointer type.

declarator and declarator-list

Specifies standard C declarators, such as identifiers, pointer declarators, and array declarators. For more information, see pointers and arrays. The declarator-list consists of one or more declarators, separated by commas. The parameter-name identifier in the function declarator is optional.

function-attr-list

Specifies zero or more attributes that apply to the function. Valid function attributes are callback, local; the pointer attribute ref, unique, or ptr; and the usage attributes string, ignore, and context_handle.

type-specifier

Specifies a base_type, struct, union, enum type, or type identifier. An optional storage specification can precede type-specifier.

ptr-decl

Specifies zero or more pointer declarators. A pointer declarator is the same as the pointer declarator used in C. It is constructed from the * designator, modifiers such as far, and the qualifier const.

function-name

Specifies the name of the remote procedure.

parameter-attribute-list

Specifies zero or more directional attributes, field attributes, usage attributes, and pointer attributes appropriate for the specified parameter type. Separate multiple attributes with commas.

Examples

const void *  p1        = NULL;

const char    my_char1  = 'a';

const char    my_char2  = my_char1;

const wchar_t my_wchar3 = L'a';

const wchar_t * pszNote = L"Note";

const unsigned short int x = 123;

typedef [string] const char *LPCSTR;

HRESULT GetName([out] wchar_t * const pszName );

Remarks

MIDL allows you to declare constant integer, character, string, and boolean types in the interface body of the IDL file. You can use the const keyword to modify the type of a type declaration or the type of a function parameter. Const type declarations are reproduced in the generated header file as #define directives.

DCE IDL compilers do not support constant expressions. To enable constant expressions, use the MIDL compiler switch /ms_ext.

A previously defined constant can be used as the assigned value of a subsequent constant.

The value of a constant integral expression is automatically converted to the respective integer type in accordance with C conversion rules.

The value of a character constant must be a single-quoted ASCII character. When the character constant is the single-quote character itself ('), the backslash character (\) must precede the single-quote character, as in \'.

The value of a character-string constant (char *) must be a double-quoted string. Within a string, the backslash (\) character must precede a literal double-quote character ( " ), as in \". Within a string, the backslash character (\) represents an escape character. String constants can consist of up to 255 characters.

The value NULL is the only valid value for constants of type void *.

Any attributes associated with the const declaration are ignored.

The MIDL compiler does not check for range errors in const initialization. For example, when you specify "const short x = 0xFFFFFFFF;" the MIDL compiler does not report an error and the initializer is reproduced in the generated header file.

See Also

base_types, IDL, /ms_ext


context_handle

typedef [context_handle [ , type-attribute-list ] ] type-specifier declarator-list;

[context_handle [, function-attr-list ] ] type-specifier [ptr-decl] function-name(
[ [parameter-attribute-list] ] type-specifier [declarator]
, ...
);

[ [ function-attr-list ] ] type-specifier [ ptr-decl ] function-name(
[context_handle [ , parameter-attribute-list ] ] type-specifier [declarator]
, ...
);

[ void __RPC_USER context-handle-type_rundown (context-handle-type); ]

type-attribute-list

Specifies one or more attributes that apply to the type.

type-specifier

Specifies a pointer type or a type identifier. An optional storage specification can precede type-specifier.

declarator and declarator-list

Specifies standard C declarators, such as identifiers, pointer declarators, and array declarators. The declarator for a context handle must include at least one pointer declarator. For more information, see  pointers and arrays. The declarator-list consists of one or more declarators, separated by commas. The parameter-name identifier in the function declarator is optional.

function-attr-list

Specifies zero or more attributes that apply to the function. Valid function attributes are callback, local; the pointer attribute ref, unique, or ptr; and the usage attributes string, ignore, and context_handle.

ptr-decl

Specifies zero or more pointer declarators. A pointer declarator is the same as the pointer declarator used in C; it is constructed from the * designator, modifiers such as far, and the qualifier const.

function-name

Specifies the name of the remote procedure.

parameter-attribute-list

Specifies zero or more directional attributes, field attributes, usage attributes, and pointer attributes appropriate for the specified parameter type. Separate multiple attributes with commas.

context-handle-type

Specifies the identifier that specifies the context handle type as defined in a typedef declaration that takes the context_handle attribute. The rundown routine is optional.

Example

typedef [context_handle] void * PCONTEXT_HANDLE_TYPE;

short RemoteFunc1([out] PCONTEXT_HANDLE_TYPE * pCxHandle);

short RemoteFunc2([in, out] PCONTEXT_HANDLE_TYPE * pCxHandle);

void __RPC_USER PCONTEXT_HANDLE_TYPE_rundown (PCONTEXT_HANDLE_TYPE);

Remarks

The context_handle attribute identifies a binding handle that maintains context, or state information, on the server between remote procedure calls. The attribute can appear as an IDL typedef type attribute, as a function return type attribute, or as a parameter attribute.

DCE IDL compilers restrict context handles to pointers of type void *. When you use the MIDL compiler switch /ms_ext to specify the Microsoft-extensions mode, a context handle can be any pointer type selected by the user, as long as it complies with the requirements for context handles described following. The data associated with such a context handle type is not transmitted on the network, and so should only be manipulated by the server application.

Like other handle types, the context handle is opaque to the client application. Any data associated with the context handle type is not transmitted. On the server, the context handle serves as a handle on active context and all data associated with the context handle type is accessible.

To create a context handle, the client passes to the server an out, ref pointer to a context handle. (The context handle itself can have a null or non-null value, as long as its value is consistent with its pointer attributes. For example, when the context handle type has the ref attribute applied to it, it cannot have a null value.) Another binding handle must be supplied to accomplish the binding until the context handle is created. When no explicit handle is specified, implicit binding is used. When no implicit_handle attribute is present, an auto handle is used.

The remote procedure on the server creates an active context handle. The client must use that context handle as an in or in, out parameter in subsequent calls. An in-only context handle can be used as a binding handle, so it must have a non-null value. An in-only context handle does not reflect state changes on the server.

On the server, the called procedure can interpret the context handle as needed. For example, the called procedure can allocate heap storage and use the context handle as a pointer to this storage.

To close a context handle, the client passes the context handle as an in, out argument. The server must return a null context handle when it is no longer maintaining context on behalf of the caller. For example, if the context handle represents an open file and the call closes the file, the server must set the context handle to NULL and return it to the client. A null value is invalid as a binding handle on subsequent calls.

A context handle is only valid for one server. When a function has two handle parameters and the context handle is not null, the binding handles must refer to the same address space.

When a function has an in or an in, out context handle, its context handle can be used as the binding handle. In this case, implicit binding is not used and the implicit_handle or auto_handle attribute is ignored.

The following restrictions apply to context handles:

•	Context handles cannot be array elements, structure members, or union members. They can only be parameters.

•	Context handles cannot have the transmit_as or represent_as attribute.

•	Parameters that are pointers to out context handles must be ref pointers.

•	An in context handle can be used as the binding handle and cannot be null.

•	An in, out context handle can be null on input, but only if the procedure has another explicit handle parameter.

•	A context handle cannot be used with callbacks.


Server Context Rundown Routine

If communication breaks down while the server is maintaining context on behalf of the client, a cleanup routine may be needed to reset the context information. This cleanup routine is called a "context rundown routine."

The context rundown routine is optional. When it is supplied, it is called when the client terminates without requesting that the server free the context. This can occur when the client does not close the context handle, or when the client terminates abnormally.

When no context rundown routine is needed, the context_handle attribute can be applied to parameters.

When a context rundown routine is needed, the context_handle attribute must be used in a type definition. The type name determines the name of the context rundown routine. Given a context handle of type type-id, the server application must supply the context rundown routine named type-id_rundown. The signature of the routine is as follows:

void __RPC_USER type-id_rundown (type-id);

When the server terminates the context and fails to return a null context handle, the context rundown routine is not called and memory allocated by the run-time library for the maintenance of the context is not released.


Client Context Reset

When the server becomes unavailable and the client application wants to reset its context data, the client calls the RPC function RpcSsDestroyClientContext.

See Also

auto_handle, handle, handles


cpp_quote

cpp_quote("string")

string

Specifies a quoted string that is emitted in the generated header file. The string must be quoted to prevent expansion by the C preprocessor.

Examples

cpp_quote("#include \"foo.h\" ")

cpp_quote("#define UNICODE")

Remarks

The cpp_quote keyword instructs MIDL to emit the specified string, without the quote characters, into the generated header file.

C-language preprocessing directives that appear in the IDL file are eaten (that is, processed) by the C compiler's preprocessor. The #define directives in the IDL file are available during MIDL compilation but are not available to the C compiler.

For example, when the preprocessor encounters the directive "#define WINDOWS 4", the preprocessor replaces all occurrences of "WINDOWS" in the IDL file with "4". The symbol "WINDOWS" is not available during C-language compilation.

To allow the C-preprocessor macro definitions to pass through the MIDL compiler to the C compiler, use the #pragma midl_echo or cpp_quote directive. These directives instruct the MIDL compiler to generate a header file that contains the parameter string with the quotation marks removed. The #pragma midl_echo and cpp_quote directives are equivalent.

The MIDL compiler places the strings specified in the cpp_quote and pragma directives in the header file in the sequence in which they are specified in the IDL file and relative to other interface components in the IDL file. The strings should usually appear in the IDL file interface body section after all import operations.

See Also

IDL, pragma


decode

[ decode [ , interface-attribute-list] ] interface interface-name
[ decode [ , op-attribute-list] ] proc-name
typedef [decode [ , type-attribute-list] ] type-name

interface-attribute-list

Specifies other attributes that apply to the interface as a whole.

interface-name

Specifies the name of the interface.

op-attribute-list

Specifies other operational attributes that apply to the procedure, such as encode.

proc-name

Specifies the name of the procedure.

type-attribute-list

Specifies other attributes, such as encode and allocate.

typename

Specifies a type defined in the IDL file.

Remarks

The decode attribute specifies that a procedure or a type needs de-serialization support. This attribute causes the MIDL compiler to generate code that an application can use to retrieve serialized data from a buffer. The encode attribute provides serialization support, generating the code to serialize data into a buffer.

Use the encode and decode attributes in an ACF to generate serialization code for procedures or types defined in the IDL file of an interface. When used as an interface attribute, decode applies to all types and procedures defined in the IDL file. When used as a type attribute, decode applies only to the specified type. When used as an operational attribute, decode applies only to that procedure.

For more information about using this serialization support, see Using Encoding Services and encode.


double

Remarks

The double keyword designates a 64-bit floating-point number.

The double type is one of the base types of the interface definition language (IDL). The double type can appear as a type specifier in typedef declarations, general declarations, and function declarators (as a function-return-type specifier and a parameter-type specifier). For the context in which type specifiers appear, see IDL.

The double type cannot appear in const declarations.

See Also

base_types, float


enable_allocate

Remarks

The keyword enable_allocate specifies that the server stub code should enable the stub memory management environment. In default mode, the stub enables this environment automatically when the remote operation includes full pointers, or pointers that provide for the stub or the user to allocate memory, or on request when the enable_allocate attribute is used. When using ms_ext mode, the server stub enables the memory environment only when the enable_allocate attribute is used. The memory management environment must be enabled before memory can be allocated using RpcSmAllocate.

The client side stub may be sensitive to the Rpcss memory management environment. If a sensitive client stub is executed when the Rpcss package is disabled, the default user allocator/deallocators are called (for example, midl_user_allocate/midl_user_free). When enabled, the Rpcss package uses the allocator/deallocator pair from the package. In the default mode, the client is always sensitive to the Rpcss memory management environment and therefore, the enable_allocate attribute will not affect the client stubs. In the /ms_ext mode, the client is sensitive only when the enable_allocate attribute is used. Typically, the client side stub operates in the disabled environment.

See Also

ACF, RpcSmDisableAllocate, RpcSmEnableAllocate, RpcSmFree


encapsulated_union

typedef [ [type-attribute-list] ]
union [ struct-name ] switch (switch-type switch-name) [ union-name ] {
[ case (limited-expression-list ) ]
[ [ field-attribute-list ] ] type-specifier declarator-list ;
...
}

type-attribute-list

Specifies zero or more other attributes that apply to the union type. Valid type attributes include handle, transmit_as; the pointer attribute ref, unique, or ptr; and the usage attributes context_handle and ignore. Separate multiple attributes with commas.

struct-name

Specifies an optional tag that names the structure generated by the MIDL compiler.

switch-type

Specifies an int, char, enum type, or an identifier that resolves to one of these types.

switch-name

Specifies the name of the variable of type switch-type that acts as the union discriminant.

union-name

Specifies an optional identifier that names the union in the structure, generated by the MIDL compiler, that contains the union and the discriminant.

limited-expression-list

Specifies one or more C-language expressions that are supported by MIDL. Almost all C-language expressions are supported: The MIDL compiler supports conditional expressions, logical expressions, relational expressions, and arithmetic expressions. MIDL does not allow function invocations in expressions and does not allow pre- and post-increment and -decrement operators.

field-attribute-list

Specifies zero or more field attributes that apply to the union member. Valid field attributes include first_is, last_is, length_is, max_is, size_is; the usage attributes string, ignore, and context_handle; the pointer attribute unique or ptr; and, for members that are themselves nonencapsulated unions, the union attribute switch_type. Separate multiple field attributes with commas.

type-specifier

Specifies a base_type, struct, union, enum type, or type identifier. An optional storage specification can precede type-specifier.

declarator-list

One or more standard C declarators, such as identifiers, pointer declarators, and array declarators. (Function declarators and bit-field declarations are not allowed in unions that are transmitted in remote procedure calls. When you use the MIDL compiler switch /ms_ext, these declarators are allowed in unions that are not transmitted.) Separate multiple declarators with commas.

Examples

typedef union _S1_TYPE switch (long l1) U1_TYPE {

    case 1024:

        float f1;

    case 2048:

        double d2;

} S1_TYPE;

/* in generated header file */

typedef struct _S1_TYPE {

    long l1;

    union {

        float f1;

        double d2;

    } U1_TYPE;

} S1_TYPE;

Remarks

The encapsulated union is indicated by the presence of the switch keyword. This type of union is so named because the MIDL compiler automatically encapsulates the union and its discriminant in a structure for transmission during a remote procedure call.

If the union tag is missing (U1_TYPE in the example above), the compiler will generate the structure with the union field named tagged_union.

The shape of unions must be the same across platforms to ensure interconnectivity.

See Also

IDL, ms_union, non-encapsulated_union, switch_is, switch_type, union


encode

[ encode [ , interface-attribute-list] ] interface interface-name
[ encode [ , op-attribute-list] ] proc-name
typedef [encode [ , type-attribute-list] ] type-name

interface-attribute-list

Specifies other attributes that apply to the interface as a whole.

interface-name

Specifies the name of the interface.

op-attribute-list

Specifies other operational attributes that apply to the procedure, such as decode.

proc-name

Specifies the name of the procedure.

type-attribute-list

Specifies other attributes that apply to the type, such as decode and allocate.

typename

Specifies a type defined in the IDL file.

Examples

/*

    ACF file example;

    Assumes MyType1, MyType2, MyType3, MyProc1, MyProc2, MyProc3 defined

in IDL file

    MyType1, MyType2, MyProc1, MyProc2 have encode and decode

serialization support

    MyType3 and MyProc3 have encode serialization support only

*/

[ encode, implicit_handle(handle_t bh) ]	 interface regress

{

typedef [ decode ] MyType1;

typedef [ encode, decode ] MyType2;

[ decode ] MyProcc1();

[ encode ] MyProc2();

}

Remarks

The encode attribute specifies that a procedure or a data type needs serialization support. This attribute causes the MIDL compiler to generate code that an application can use to serialize data into a buffer. The decode attribute provides deserialization support, generating the code for retrieving data from a buffer.

Use the encode and decode attributes in an ACF to generate serialization code for procedures or types defined in the IDL file of an interface. When used as an interface attribute, encode applies to all the types and procedures defined in the IDL file. When used as an operational attribute, encode applies only to the specified procedure. When used as a type attribute, encode applies only to the specified type.

When the encode or decode attribute is applied to a procedure, the MIDL compiler generates a serialization stub in a similar fashion as remote stubs are generated for remote routines. A procedure can be either a remotable or a serializing procedure, but it cannot be both. The prototype of the generated routine is sent to the STUB.H file, while the stub itself goes into the STUB_C.C file.

The MIDL compiler generates two functions for each type the encode attribute applies to, and one additional function for each type the decode attribute applies to. For example, for a user-defined type named MyType, the compiler generates code for the MyType_Encode, MyType_Decode, and MyType_AlignSize functions. For these functions, the compiler writes prototypes to STUB.H and source code to STUB_C.C.

For additional information about serialization handles and encoding or decoding data, see Using Encoding Services.

See Also

decode


endpoint

endpoint("protocol-sequence:[endpoint-port]" [ , ...] )

protocol-sequence

Specifies a valid transport family name. The following names are recognized by the run-time libraries provided with Microsoft RPC:

Family string	Description
ncacn_ip_tcp	TCP/IP
ncacn_nb_nb	NetBIOS over Microsoft NetBEUI
ncacn_nb_tcp	NetBIOS over TCP
ncacn_np	Named pipes
ncacn_spx	Connection-oriented SPX
ncadg_ip_upd	Datagram-oriented TCP/IP
ncadg_ipx	Datagram-oriented IPX
ncalrpc	Local RPC communication
Note  Windows 95 does not support ncalrpc.  The ncacn_np protocol is supported only on the client side.

endpoint-port

Specifies a string that represents the endpoint designation for the specified protocol family. The syntax of the port string is specific to each protocol sequence.

Examples

endpoint("ncacn_np:[\\pipe\\rainier]")

endpoint("ncacn_ip_tcp:[1044]", "ncacn_np:[\\pipe\\shasta]")

Remarks

The endpoint attribute specifies a well-known port or ports (communication endpoints) on which servers of the interface listen for calls.

The endpoint specifies a transport family such as the TCP/IP connection-oriented protocol, a NetBIOS connection-oriented protocol, or the named-pipe connection-oriented protocol.

The protocol-sequence value determines the valid values for the endpoint-port. The MIDL compiler checks only general syntax for the endpoint-port entry. Port specification errors are reported by the run-time libraries. For information about the allowed values for each protocol sequence, see the topic for that protocol sequence.

The following protocol sequences specified by DCE are not supported by the MIDL compiler provided with Microsoft RPC: ncacn_osi_dna and ncadg_dds.

The user must correctly quote backslash characters in endpoints. This commonly occurs when the endpoint is a named pipe.

Endpoint information specified in the IDL file is used by the RPC run-time functions RpcServerUseProtseqIf and RpcServerUseAllProtseqsIf.

See Also

IDL, ncacn_dnet_nsp, ncacn_nb_nb, ncacn_np, ncacn_spx, ncalrpc


enum

enum [tag ] { identifier [=integer-value ] [ , ... ] }

tag

Specifies an optional tag for the enumerated type.

identifier

Specifies the particular enumeration.

integer-value

Specifies a constant integer value.

Examples

typedef enum {Monday=2, Tuesday, Wednesday, Thursday, Friday} workdays;

typedef enum {Clemens=21, Palmer=22, Ryan=34} pitchers;

Remarks

The keyword enum is used to identify an enumerated type. Enum types can appear as type specifiers in typedef declarations, general declarations, and function declarators (either as the function-return-type or as a parameter-type specifier). For the context in which type specifiers appear, see IDL.

With Microsoft RPC, you can assign integer values to enumerators. To enable this mode, compile with the switch /ms_ext.

When assignment operators are not provided, identifiers are mapped to consecutive integers from left to right, starting with 0. When assignment operators are provided, assigned values start from the most recently assigned value.

Like C-language enumerators, enumerator names must be unique but the enumerator values need not be.

The maximum number of identifiers is 65,535. Objects of type enum are int types, and their size is system-dependent. However, for transmission over the network, objects of enum types are treated as 2-byte objects of type unsigned short and must be positive values less than or equal to 32,767. Values outside this range cause the run-time exception RPC_X_ENUM_VALUE_OUT_OF_RANGE.

See Also

IDL, typedef, v1_enum


error_status_t

Remarks

The error_status_t keyword designates a type for an object that contains communication-status or fault-status information.

The error_status_t type is used as a part of the exception handling architecture in IDL. This type maps to an unsigned long. Applications that catch error situations have an out parameter or a return type of a procedure specified as error_status_t, and qualify the error_status_t with the comm_status or fault_status attributes in the ACF. If the parameter or return type was not qualified with the comm_status or fault_status attributes, then the parameter operates as though it were an unsigned long.

The MIDL 2.0 compiler generates stubs that contain the proper error handling architecture. However, earlier versions of the MIDL compiler handled a parameter or return type of error_status_t as though the comm_status and fault_status attributes were applied, even if they were not. With the MIDL 2.0 compiler, you must explicitly apply the comm_status and fault_status attributes to the parameter or procedure in the ACF.

The error_status_t type is one of the predefined types of the interface definition language. Predefined types can appear as type specifiers in typedef declarations, in general declarations, and in function declarators (either as the function-return-type or as parameter-type specifiers).

See Also

comm_status, fault_status, IDL


explicit_handle

[explicit_handle] {...}

Example

/* ACF File */

[explicit_handle]

{

};

Remarks

The explicit_handle attribute specifies that each procedure has, as its first parameter, a primitive handle, such as a handle_t type. This is the case even if the IDL file does not contain the handle in its parameter list. The prototypes emitted to the header file and stub routines contain the additional parameter, and that parameter is used as the handle for directing the remote call. The explicit_handle attribute affects both remote procedures and serialization procedures. For type serialization, the support routines are generated with the initial parameter as an explicit (serialization) handle. If the explicit_handle attribute is not used, the application can still specify that an operation have an explicit handle (binding or serialization) directing the call. To do so, a prototype with the first argument containing a handle type is supplied to the IDL file. Note that in /ms_ext mode, an argument that does not appear first can also be used as a handle directing the call. So, while the explicit_handle attribute is a way of giving the IDL prototype a primitive explicit_handle attribute, it doesn't necessarily require a change to the IDL file.

The explicit_handle attribute can be used as either an interface attribute or an operation attribute. As an interface attribute, it affects all the operations in the interface and all the types that require serialization support. If, however, it is used as an operation attribute, it affects only that particular operation.

See Also

ACF, auto_handle, implicit_handle


fault_status

[fault_status [ , ACF-function-attributes ] ] function-name(
[ [ ACF-parameter-attributes ] ] parameter-name
, ...
);

[ [ ACF-function-attributes ] ] function-name(
[fault_status [ , ACF-parameter-attributes ] ] parameter-name
... );

ACF-function-attributes

Specifies zero or more ACF function attributes, such as fault_status and nocode. Function attributes are enclosed in square brackets. Note that zero or more attributes can be applied to a function. Separate multiple function attributes with commas. Note that if fault_status appears as a function attribute, it cannot also appear as a parameter attribute.

function-name

Specifies the name of the function as defined in the IDL file.

ACF-parameter-attributes

Specifies attributes that apply to a parameter. Note that zero or more attributes can be applied to the parameter. Separate multiple parameter attributes with commas. Parameter attributes are enclosed in square brackets. IDL parameter attributes, such as directional attributes, are not allowed in the ACF. Note that if fault_status appears as a parameter attribute, it cannot also appear as a function attribute.

parameter-name

Specifies the parameter for the function as defined in the IDL file. Each parameter for the function must be specified in the same sequence, using the same name as defined in the IDL file.

Remarks

The fault_status attribute can be used as either a function attribute or as a parameter attribute, but it can appear only once per function. It can be applied either to the function or to one parameter in each function.

The fault_status attribute can only be applied to functions that return the type error_status_t. When the remote procedure fails in a way that causes a fault PDU to be returned, an error code is returned.

When fault_status is used as a parameter attribute, the parameter must be an out parameter of type error_status_t. If a server error occurs, the parameter is set to the error code. When the remote call completes successfully, the procedure sets the value.

The parameter associated with the fault_status attribute does not have to be specified in the IDL file. When the parameter is not specified, a new out parameter of type error_status_t is generated following the last parameter defined in the DCE IDL file.

It is possible for both the fault_status and comm_status attributes to appear in a single function, either as function attributes or parameter attributes. If both attributes are function attributes or if they apply to the same parameter, and no error occurs, the function or parameter has the value error_status_ok. Otherwise, it contains the appropriate status code value. Because values returned for fault_status are different from the values returned for comm_status, the returned values are readily interpreted.

See Also

ACF, comm_status, error_status_t


field_attributes

[ [ field-attribute-list ] ] type-specifier declarator-list;

field-attribute-list

Specifies zero or more field attributes that apply to the structure or union member, array, or function parameter. Valid field attributes include first_is, last_is, length_is, max_is, size_is; the usage attributes string, ignore, and context_handle; the pointer attribute ref, unique, or ptr; and the union attribute switch_type. Separate multiple field attributes with commas.

type-specifier

Specifies a base_type, struct, union, or enum type or type identifier. An optional storage specification can precede type-specifier.

declarator-list

Specifies one or more standard C declarators, such as identifiers, pointer declarators, and array declarators. Separate multiple declarators with commas.

Remarks

Field attributes are used in structure, union, array, and function-parameter declarators to define transmission characteristics of the declarator during a remote procedure call.

Field-attribute keywords include size_is, max_is, length_is, first_is, and last_is; the usage attributes string, ignore, and context_handle; the union switch switch_is;and the pointer attributes ref, unique, and ptr.

The field attributes size_is, max_is, length_is, first_is, and last_is specify the size or range of valid data for the declarator. These field attributes associate another parameter, structure member, union member, or constant expression with the declarator.

Field attributes that are parameters must associate with declarators that are parameters; field attributes that are members of structures or unions must associate with declarators that are members of the same structure or union.

For information about the context in which field attributes appear, see arrays, struct, and union.

See Also

arrays, first_is, IDL, last_is, length_is, max_is, size_is


first_is

first_is(limited-expression-list)

limited-expression-list

Specifies one or more C-language expressions supported by MIDL. The expression evaluates to an integer that represents the array index of the first array element to be transmitted. Separate multiple expressions with commas.

Example

void Proc1(
[in] short First,
[first_is(iFirst)] A[10]);

Remarks

The first_is attribute specifies the index of the first array element to be transmitted. If the first_is attribute is not present, or if the specified index is a negative number, array element 0 is the first element transmitted.

The first_is attribute can also help determine the values of the array indexes corresponding to the last_is or length_is attribute when these attributes are not specified. The relationship between these array indexes is as follows:

length = last - first + 1

The following relationship must also hold:

0 <= first_is <= max_is

The following relationship must hold when max_is <= 0:

first_is == 0

The first_is attribute cannot be used at the same time as the string attribute.

See Also

field_attributes, IDL, last_is, length_is, max_is, min_is, size_is


float

Remarks

The float keyword designates a 32-bit floating-point number.

The float type is one of the base types of the interface definition language (IDL). The float type can appear as a type specifier in typedef declarations, general declarations, and function declarators (as a function-return-type specifier and a parameter-type specifier). For the context in which type specifiers appear, see IDL.

The float type cannot appear in const declarations.

See Also

base_types, double.


handle

typedef [handle] typename;
handle_t __RPC_USER typename_bind (typename);
void __RPC_USER typename_unbind (typename, handle_t);

typename

Specifies the name of the user-defined binding-handle type.

Examples

typedef [handle] struct {

    char machine[8];

    char nmpipe[256];

 } h_service;

handle_t __RPC_USER h_service_bind(h_service);

void __RPC_USER h_service_unbind(h_service, handle_t);

Remarks

The handle attribute specifies a user-defined or "customized" handle type. User-defined handles permit developers to design handles that are meaningful to the application.

A user-defined handle can only be defined in a type declaration, not in a function declarator.

A parameter of a type defined by the handle attribute is used to determine the binding for the call and is transmitted to the called procedure.

The user must provide binding and unbinding routines to convert between primitive and user-defined handle types. Given a user-defined handle of type typename, the user must supply the routines typename_bind and typename_unbind. For example, if the user-defined handle type is named MYHANDLE, the routines are named MYHANDLE_bind and MYHANDLE_unbind.

If successful, the typename_bind routine should return a valid primitive binding handle and if unsuccessful, a NULL. If the routine returns NULL, the typename_unbind routine will not be called. If the binding routine returns an invalid binding handle different from NULL, the stub behavior is undefined.

When the remote procedure has a user-defined handle as a parameter or as an implicit handle, the client stubs call the binding routine before calling the remote procedure. The client stubs call the unbinding routine after the remote call.

In DCE IDL, a parameter with the handle attribute must appear as the first parameter in the remote procedure argument list. Subsequent parameters, including other handle attributes, are treated as ordinary parameters. Microsoft supports an extension to DCE IDL that allows the user-defined handle parameter to appear in positions other than the first parameter.

See Also

handles, IDL, implicit_handle, typedef


handles

Remarks

Binding handles are data objects that represent the binding between the client and the server.

MIDL supports the base type handle_t. Handles of this type are known as "primitive handles."

You can define your own handle types using the handle attribute. Handles defined in this way are known as "user-defined or customized handles" or "generic handles."

You can also define a handle that maintains state information using the context_handle attribute. Handles defined in this way are known as "context handles."

If no state information is needed and you do not choose to call the RPC run-time libraries to manage the handle, you can request that the run-time libraries provide automatic binding. This is done by using the ACF keyword auto_handle.

You can specify a global variable as the binding handle by using the ACF keyword implicit_handle.

The explicit_handle keyword is used to state that each remote function has an explicitly specified handle.

See Also

auto_handle, base_types, context_handle, explicit_handle, handle, handle_t, implicit_handle


handle_t

Remarks

The handle_t keyword declares an object to be of the primitive handle type handle_t. A primitive binding handle is a data object that can be used by the application to represent the binding.

The handle_t type is one of the predefined types of the interface definition language (IDL). It can appear as a type specifier in typedef declarations, general declarations, and function declarators (as a function-return-type specifier and a parameter-type specifier). For the context in which type specifiers appear, see IDL

In Microsoft RPC, parameters of type handle_t can occur only as in parameters. Primitive handles cannot have the unique or ptr attribute.

Parameters of type handle_t (primitive handle parameters) are not transmitted on the network.

See Also

base_types, handles


heap

The DCE ACF keyword heap is not implemented in Microsoft RPC.


hyper

Remarks

The keyword hyper indicates a 64-bit integer that can be declared as either signed or unsigned.

The hyper type is one of the base types of the interface definition language (IDL). The hyper type can appear as a type specifier in const declarations, typedef declarations, general declarations, and function declarators (as a function-return-type specifier and as a parameter-type specifier). For the context in which type specifiers appear, see IDL.

Note  For 16-bit platforms, the MIDL compiler replaces unsigned hyper integers with MIDL_uhyper. This allows interfaces with unsigned hyper integers to be defined on platforms that do not directly support 64-bit integers. MIDL_uhyper is defined in the RPC header files.

See Also

base_types


idempotent

[[ [ IDL-operation-attributes ] ]] operation-attribute , ...

IDL-operation-attributes

Specifies zero or more IDL operation attributes, such as idempotent and broadcast. Operation attributes are enclosed in square brackets.

Remarks

An idempotent operation is one that does not modify state information and returns the same results each time it is performed. Performing the routine more than once has the same effect as performing it once.

RPC supports two types of remote call semantics: calls to idempotent operations and calls to non-idempotent operations. An idempotent operation can be carried out more than once with no ill effect. Conversely, a non-idempotent operation (at-most-once) cannot be executed more than once because it will either return different results each time or because it modifies some state.

To ensure that a procedure is automatically re-executed if the call does not complete, use the idempotent attribute. If the idempotent, broadcast, or maybe attributes are not present, the procedure will use non-idempotent semantics by default. In this case, the operation is executed only once.

See Also

broadcast, IDL, maybe, non-idempotent


IDL

[ interface-attribute-list ] interface interface-name
{
[ import import-file-list ; ... ]
[ cpp_quote("string") ... ]

[ const const-type identifier = const-expression ; ... ]

[ [ typedef ] [ [type-attribute-list] ] type-specifier declarator-list; ...]

[	[ [function-attr-list] ] type-specifier [pointer-declarator] function-name(
[ [parameter-attribute-list] ] type-specifier [declarator]
, ...
);
...
]
}

.

.

.

interface-attribute-list

Specifies either the attribute uuid or the attribute local and other optional attributes that apply to the interface as a whole. The attributes endpoint, version, and pointer_default are optional. When you compile with the /app_config switch, either implicit_handle or auto_handle can also be present. Separate multiple attributes with commas. The interface-attribute-list does not have to be present for imported IDL files but must be present for the base IDL file.

interface-name

Specifies the name of the interface. The identifier must be unique or different from any type names. It also must be 17 characters or less because it is used to form the name of the interface handle. The same interface name must be supplied in the ACF, except when you compile with the /acf switch.

import-file-list

Specifies one or more IDL files to import. Separate filenames with commas.

string

Specifies a string that is emitted in the generated header file.

const-type

Specifies the name of an integer, character, boolean, void *, byte, or string (char *, byte *, wchar_t *) type. Only these types can be assigned const values in the IDL file.

identifier

Specifies a valid MIDL identifier. Valid MIDL identifiers consist of up to 31 alphanumeric and/or underscore characters and must start with an alphabetic or underscore character.

const-expression

Specifies a constant declaration. The const-expression must evaluate to the type specified by const-type. For more information, see const.

type-attribute-list

Specifies one or more attributes that apply to the type. Valid type attributes include handle, switch_type, transmit_as; the pointer attribute ref, unique, or ptr; and the usage attributes context_handle, ignore, and string. Separate multiple attributes with commas.

type-specifier

Specifies a base_type, struct, union, enum type, or type identifier. An optional storage specification can precede type-specifier.

declarator and declarator-list

Specify standard C declarators, such as identifiers, pointer declarators, and array declarators. For more information, see pointers and arrays. The declarator-list consists of one or more declarators separated by commas. The parameter declarator in the function declarator, such as the parameter name, is optional.

function-attr-list

Specifies zero or more attributes that apply to the function. Valid function attributes are callback, local; the pointer attribute ref, unique, or ptr; and the usage attributes string, ignore, and context_handle.

pointer-declarator

Specifies zero or more pointer declarators. A pointer declarator is the same as the pointer declarator used in C; it is constructed from the * designator, modifiers such as far, and the qualifier const.

function-name

Specifies the name of the remote procedure.

parameter-attribute-list

Specifies zero or more attributes appropriate for the specified parameter type. Parameter attributes can take the directional attributes in and out; the field attributes first_is, last_is, length_is, max_is, size_is, and switch_type; the pointer attribute ref, unique, or ptr; and the usage attributes context_handle and string. The usage attribute ignore cannot be used as a parameter attribute. Separate multiple attributes with commas.

Examples

[ uuid(12345678-1234-1234-1234-123456789ABC),

  version(3.1),

  pointer_default(unique)

] interface IdlGrammarExample

{

import "windows.idl", "other.idl";

const wchar_t * NAME = L"Example Program";

typedef char * PCHAR;

void DictCheckSpelling(

     [in, string] PCHAR   word,     // word to look up

     [out]        short * isPresent // 0 if not present

);

}

Remarks

The IDL file contains the specification for the interface. The interface includes the set of data types and the set of functions to be executed from a remote location. Interfaces specify the function prototypes for remote functions and for many aspects of their behavior from the point of view of interface users.

Another file, the application configuration file (ACF), contains attributes that tailor the application for a specific operating environment. For more information, see ACF.

An interface specification consists of an interface header followed by an interface body. The interface header includes an attribute list describing characteristics that apply to the interface as a whole. The interface body contains the remote data types and function prototypes.

The interface body contains zero or more import lists, constant declarations, general declarations, and function declarators.

In /ms_ext mode, an IDL file can contain multiple interfaces. Type definitions, construct declarations, and imports can occur outside of the interface body. All definitions from the main IDL file will appear in the generated header file, and all the procedures from all the interfaces in the main IDL file will generate stub routines. This enables applications that support multiple interfaces to merge IDL files into a single, combined IDL file. As a result, it requires less time to compile the files and also allows MIDL to reduce redundancies in the generated stubs. This can significantly improve object interfaces by the ability to share common code for base interfaces and derived interfaces. For non-object interfaces, the procedure names must be unique across all the interfaces. For object interfaces, the procedure names need only be unique within an interface.

The syntax for declarative constructs in the IDL file is similar to that for C. MIDL supports all Microsoft C version 7.0 declarative constructs except:

•	Older style declarators that allow a declarator to be specified without a type specifier, such as:

x (y)

short x (y)

•	Declarations with initializers (MIDL only accepts declarations that conform to the MIDL const syntax)

•	Floating-point constants

The import keyword specifies the names of one or more IDL files to import. The import directive is similar to the C include directive, except that only data types are assimilated into the importing IDL file.

The constant declaration specifies boolean, integer, character, wide-character, string, and void * constants. For more information, see const.

A general declaration is similar to the C typedef statement with the addition of IDL type attributes. In /ms_ext mode, the MIDL compiler also allows an implicit declaration in the form of a variable definition.

The function declarator is a special case of the general declaration. You can use IDL attributes to specify the behavior of the function return type and each of the parameters.

See Also

arrays, const, enum, import, in, interface, midl, out, pointers, struct, union


ignore

[ignore] pointer-member-type pointer-name;

pointer-member-type

Specifies the type of the pointer member of the structure or union.

pointer-name

Specifies the name of the pointer member that is to be ignored during marshalling.

Example

typedef struct _DBL_LINK_NODE_TYPE {

    long value;

    struct _DBL_LINK_NODE_TYPE * next;

    [ignore] struct _DBL_LINK_NODE_TYPE * previous;

} DBL_LINK_NODE_TYPE;

Remarks

The ignore attribute designates that a pointer contained in a structure or union and the object indicated by the pointer is not transmitted. The ignore attribute is restricted to pointer members of structures or unions.

The value of a structure member with the ignore attribute is undefined at the destination. An in parameter is not defined at the remote computer. An out parameter is not defined at the local computer.

The ignore attribute allows you to prevent transmisison of data. This is useful in situations such as a double-linked list. The following example includes a double-linked list that introduces data aliasing:

/* IDL file */

typedef struct _DBL_LINK_NODE_TYPE {

    long value;

    struct _DBL_LINK_NODE_TYPE * next;

    struct _DBL_LINK_NODE_TYPE * previous;

} DBL_LINK_NODE_TYPE;

void remote_op([in] DBL_LINK_NODE_TYPE * list_head);

/* application */

DBL_LINK_NODE_TYPE * p, * q

p = (DBL_LINK_NODE_TYPE *)
midl_user_allocate(sizeof(DBL_LINK_NODE_TYPE));

q = (DBL_LINK_NODE_TYPE *)
midl_user_allocate(sizeof(DBL_LINK_NODE_TYPE));

p->next = q;

q->previous = p;

p->previous = q->next = NULL;

...

remote_op(p);

Aliasing occurs in the preceding example because the same memory area is available from two different pointers in the function p and p->next->previous.

Note that ignore cannot be used as a type attribute.

See Also

pointers, ptr, ref, unique


iid_is

[ iid_is(limited-expression) ]

limited-expression

Specifies a limited expression. MIDL does not allow function invocations in expressions and does not allow pre- and post-increment and -decrement operators.

Example

HRESULT	CreateInstance(

[in] REFIID riid,

[out, iid_is(riid)] IUnknown ** ppvObject);

Remarks

The iid_is pointer attribute specifies the IID of the OLE interface pointed to by an interface pointer. You can use iid_is in attribute lists for function parameters and for structure or union members. The stubs use the IID to determine how to marshal the interface pointer. This is useful for an interface pointer that is typed as a base class parameter.

Files that use the iid_is attribute must be compiled with the MIDL compiler switch /ms_ext.

See Also

object, uuid


implicit_handle

implicit_handle(handle-type handle-name)

handle-type

Specifies the handle data type, such as the base type handle_t or a user-defined handle type.

handle-name

Specifies the name of the handle.

Example

/* ACF file */

[implicit_handle(handle_t hMyHandle)]

{

}

Remarks

The implicit_handle attribute specifies the handle used for functions that do not include an explicit handle as a procedure parameter. If the procedure is remote, the handle will be used as the binding handle for the remote call. The implicit handle may also be used to establish an initial binding for a function that uses a context handle. If the procedure is a serializing procedure, the handle is used as a serializing handle controlling the operation. In the case of type serialization, the handle is used as the serialization handle for all the serialized types.

The implicit_handle attribute specifies a global variable that contains a handle used by any function needing implicit handles.

The implicit binding handle type must be either handle_t (or a type based on handle_t) or a user-defined handle type specified with the handle attribute. The implicit serializing handle must be a type based on handle_t.

If the implicit handle type is not defined in the IDL file or in any files included and imported by the IDL file for the MIDL computer, you must supply the file containing the handle-type definition when you compile the stubs. Use the ACF include statement to include the file containing the handle-type definition.

The implicit_handle attribute can occur once, at most. The implicit_handle attribute can occur only if the auto_handle or explicit_handle attribute does not occur.

See Also

ACF, auto_handle, explicit_handle, include


import

import "filename" [ , ... ] ;

filename

Specifies the name of the IDL file to import.

Example

import "foo1.idl";

import "foo2.idl", "foo3.idl", "foo4.idl";

Remarks

The import directive is similar to the C-language preprocessor macro #include. The import directive directs the compiler to include data types defined in the imported IDL files. In contrast to the C-language #include macro, the import directive ignores procedure prototypes.

The import keyword is optional and can appear zero or more times in the IDL file. Each import keyword can be associated with more than one filename. Multiple filenames are separated by comma characters. You must enclose the filename within quotation marks and end the import statement with the semicolon character (;). Note that an interface without attributes can be imported into a base IDL file. However, the interface must contain only datatypes with no procedures. If even one procedure is contained in the interface, a local or UUID attribute must be specified.

The C-language header (.H) file generated for the interface does not directly contain the imported types but instead generates a #include directive for the header file corresponding to the imported interface. For example, when FOO.IDL imports BAR.IDL, the generated header file FOO.H includes BAR.H (FOO.H contains the directive #include BAR.H).

The import function is idempotent — that is, importing an interface more than once has the same effect as importing it once.

The behavior of the import directive is independent of the MIDL compiler mode switches /ms_ext, /c_ext, and /app_config.

See Also

IDL


in

[ [function-attribute-list] ] type-specifier [pointer-declarator] function-name(
[ in [ , parameter-attribute-list ] ] type-specifier [declarator]
, ...
);

function-attribute-list

Specifies zero or more attributes that apply to the function. Valid function attributes are callback, local, the pointer attribute ref, unique, or ptr, and the usage attributes string, ignore, and context_handle.

type-specifier

Specifies a base_type, struct, union, or enum type or type identifier. An optional storage specification can precede type-specifier.

pointer-declarator

Specifies zero or more pointer declarators. A pointer declarator is the same as the pointer declarator used in C; it is constructed from the * designator, modifiers such as far, and the qualifier const.

function-name

Specifies the name of the remote procedure.

parameter-attribute-list

Specifies zero or more attributes appropriate for the specified parameter type. Parameter attributes with the in attribute can also take the directional attribute out; the field attributes first_is, last_is, length_is, max_is, size_is and switch_type; the pointer attribute ref, unique, or ptr; and the usage attributes context_handle and string. The usage attribute ignore cannot be used as a parameter attribute. Separate multiple attributes with commas.

declarator

Specifies standard C declarators, such as identifiers, pointer declarators, and array declarators. For more information, see pointers and arrays. The parameter declarator in the function declarator, such as the parameter name, is optional.

Example

void MyFunction([in] short count);

Remarks

The in attribute indicates that a parameter is to be passed from the calling procedure to the called procedure.

A related attribute, out, indicates that a parameter is to be returned from the called procedure to the calling procedure. The in and out attributes are known as directional parameter attributes because they specify the direction in which parameters are passed. A parameter can be defined as in, out, or in, out.

The in attribute identifies parameters that are marshalled by the client stub for transmission to the server.

The in attribute is applied to a parameter by default when no directional parameter attribute is specified.

See Also

IDL, midl_user_allocate, out


include

include filenames;

filenames

Specifies the name of one or more C-language header files. The .H extension must be supplied in the MS-DOS, Windows, and Windows NT environments. Separate multiple C-language header filenames with commas.

Remarks

The body of the ACF can contain include directives, ACF typedef attributes, and ACF function and parameter attributes.

The ACF include statement specifies one or more header files included in the generated stub code. The stub code contains a C-preprocessor #include statement, and the user supplies the C-language header file when compiling the stubs. Include statements rely on the C-compiler mechanism of searching the directory structure for included files.

Note  Use the import directive rather than the include directive for system files, such as WINDOWS.H, that contain data types you want to make available to the IDL file. The import directive ignores function prototypes and allows you to use MIDL compiler switches that optimize the generation of support routines.

See Also

ACF, import, typedef


in_line

The DCE IDL keyword in_line is not supported in Microsoft RPC.

See Also

IDL


int

[type-specifier] [ signed | unsigned ] integer-modifier [ int ] declarator-list;

type-specifier

Specifies a base_type, struct, union, enum type, or type identifier. An optional storage specification can precede type-specifier.

integer-modifier

Specifies the keyword small, short, long, or hyper, which selects the size of the integer data. The size qualifier must be present.

declarator-list

Specifies one or more standard C declarators, such as identifiers, pointer declarators, and array declarators. (Function declarators and bit-field declarations are not allowed in structures that are transmitted in remote procedure calls. These declarators are allowed in structures that are not transmitted.) Separate multiple declarators with commas.

Examples

signed short int i = 0;

short int j = i;

typedef struct {

    small int         i1;

    short             i2;

    unsigned long int i3;

} INTSIZETYPE;

void MyFunc([in] long int lCount);

Remarks

The keyword int is an optional keyword that can accompany the keywords small, short, and long.

Integer types are among the base types of the interface definition language (IDL). They can appear as type specifiers in typedef declarations, general declarations, and function declarators (as a function-return-type specifier and as a parameter-type specifier). For the context in which type specifiers appear, see IDL.

The keyword int cannot be used alone. It must always appear with one of the valid integer modifiers. These modifiers specify the number of bits used to describe the integer data.

If no integer sign specification is provided, the integer type defaults to signed.

DCE IDL compilers do not allow the keyword signed to specify the sign of integer types. To allow the use of the keyword signed, use the MIDL compiler switch /ms_ext.

See Also

base_types, long, /ms_ext, short, small


__int64

The keyword __int64 specifies a valid integer supported by the MIDL compiler. For a discussion of how to use __int64, see hyper.

See Also

IDL, int


interface

[ interface-attribute-list ] interface interface-name [ : base-interface ]

/*IDL file typedef syntax */
typedef interface interface-name declarator-list

interface-attribute-list

Specifies attributes that apply to the interface as a whole. Valid interface attributes for an IDL file include endpoint, local, object, pointer_default, uuid, and version. Valid interface attributes for an ACF include encode, decode, either auto_handle or implicit_handle, and either code or nocode.

interface-name

Specifies the name of the interface. The identifier must start with an alphabetic or underscore character and can consist of up to 17 alphanumeric and underscore characters. The identifier must be 17 characters or less because it is used to form the name of the interface handle.

base-interface

Specifies the name of an interface from which this derived interface inherits member functions, status codes, and interface attributes. The derived interface does not inherit type definitions. To do this, use the import keyword to import the IDL file of the base interface.

declarator-list

Specifies standard C declarators, such as identifiers, pointer declarators, and array declarators. For more information, see pointers and arrays. The declarator-list consists of one or more declarators, separated by commas.

Examples

/* use of interface keyword in IDL file for an RPC interface */

  [ uuid (00000000-0000-0000-0000-000000000000),

    version (1.0) ]

  interface remote_if_2

  {

  }

/* use of interface keyword in ACF for an RPC interface */

  [ implicit_handle( handle_t xa_bhandle ) ]

  interface remote_if_2

  {

  }

/* use of interface keyword in IDL file for an OLE interface */

  [ object, uuid (00000000-0000-0000-0000-000000000000) ]

  interface IDerivedInterface : IBaseInterface

  {

    import "base.idl"

    Save();

  }

/* use of interface keyword to define an interface pointer type */

  typedef interface IStorage *LPSTORAGE;

Remarks

The interface keyword specifies the name of the interface. The interface name must be provided in both the IDL file and the ACF.

The interface names in the IDL file and ACF must be the same, except when you use the MIDL compiler switch /acf. For more information, see /acf.

The interface name forms the first part of the name of interface-handle data structures that are parameters to the RPC run-time functions. For more information, see RPC_IF_HANDLE.

If the interface header includes the object attribute to indicate an OLE interface, it must also include the uuid attribute and must specify the base OLE interface from which it is derived. For more information about OLE interfaces, see object.

You can also use the interface keyword with the typedef keyword to define an interface data type.

See Also

ACF, endpoint, IDL, local, pointer_default, uuid, version


last_is

[last_is( limited-expression-list )]

limited-expression-list

Specifies one or more C-language expressions supported by MIDL. The expression evaluates to an integer that represents the array index of the last array element to be transmitted. Separate multiple expressions with commas.

Example

proc1(
[in] short Last,
[in, last_is(Last)] short asNumbers[MAXSIZE]);

Remarks

The field attribute last_is specifies the index of the last array element to be transmitted. When the specified index is zero or negative, no array elements are transmitted.

The last_is attribute determines the value of the array index corresponding to the length_is attribute when length_is is not specified. The relationship between these array indexes is as follows:

length = last - first + 1

If the value of the array index specified by first_is is larger than the value specified by last_is, zero elements are transmitted.

The last_is attribute can be used only if the array has a fixed allocation size. The last_is attribute cannot be used as a field attribute at the same time as the string attribute.

When the value specified by max_is is equal to or greater than zero, the following relationship must be true:

0 <= last_is <= max_is

When min_is is greater than or equal to max_is, the following relationship must be free:

last_is <= max_is

See Also

field_attributes, first_is, IDL, length_is, max_is, size_is


length_is

[length_is( limited-expression-list )]

limited-expression-list

Specifies one or more C-language expressions that are supported by MIDL. The expression evaluates to an integer that represents the number of array elements to be transmitted. Separate multiple expressions with commas.

Examples

/* counted string holding at most "size" characters */

typedef struct {

     unsigned short size;

     unsigned short length;

     [size_is(size), length_is(length)] char string[*];

 } COUNTED_STRING_TYPE;

/* counted string holding at most 80 characters */

typedef struct {

     unsigned short length;

     [length_is(length)] char string[80];

 } STATIC_COUNTED_STRING_TYPE;

void Proc1(
[in] short iLength;

[in, length_is(iLength)] short asNumbers[10];

Remarks

The length_is attribute specifies the number of array elements to be transmitted. A non-negative value must be specified.

The length_is attribute determines the value of the array indexes corresponding to the last_is attribute when last_is is not specified. The relationship between these array indexes is as follows:

length = last - first + 1

The length_is attribute cannot be used at the same time as the last_is attribute or the string attribute.

To define a counted string with a length_is or last_is attribute, use a character array or pointer without the string attribute.

See Also

field_attributes, first_is, IDL, last_is, max_is, min_is, size_is


local

[ local [, interface-attribute-list] ] interface interface-name

[ object, uuid(string-uuid), local [, interface-attribute-list] ]
 interface interface-name

[ local [, function-attribute-list] ] function-declarator ;

interface-attribute-list

Specifies other attributes that apply to the interface as a whole. The attributes endpoint, version, and pointer_default are optional. When you compile with the /app_config switch, either implicit_handle or auto_handle can also be present. Separate multiple attributes with commas.

interface-name

Specifies the name of the interface.

string-uuid

Specifies a UUID string generated by the uuidgen utility. You can enclose the UUID string in quotes when you use the MIDL compiler switch /ms_ext.

function-attribute-list

Specifies zero or more attributes that apply to the function. Valid function attributes are callback; the pointer attribute ref, unique, or ptr; and the usage attributes string, ignore, and context_handle. Separate multiple attributes with commas.

function-declarator

Specifies the type specifier, function name, and parameter list for the function.

Examples

/* IDL file #1 */

[local] interface local_procs

{ void MyLocalProc(void);}

/* IDL file #2 */

[object,

 uuid(12345678-1234-1234-123456789ABC),

 local] interface local_object_procs

{ void MyLocalObjectProc(void);}

/* IDL file #3 */

[uuid(12345678-1234-1234-123456789ABC)]

interface mixed_procs

{

[local] void MyLocalProc(void);

void MyRemoteProc([in] short sParam);

}

Remarks

The local attribute can be applied to individual functions or to the interface as a whole.

When used in the interface header, the local attribute allows you to use the MIDL compiler as a header generator. The compiler does not generate stubs for any functions and does not ensure that the header can be transmitted.

For an RPC interface, the local attribute cannot be used at the same time as the uuid attribute. Either uuid or local must be present in the interface header, and the one you choose must occur exactly once.

For an OLE interface (identified by the object interface attribute), the interface attribute list can include the local attribute even though the uuid attribute is present.

When used in an individual function, the local attribute designates a local procedure for which no stubs are generated. Using local as a function attribute is a Microsoft extension to DCE IDL and requires the MIDL compiler switch /ms_ext.

Note that an interface without attributes can be imported into a base IDL file. However, the interface must contain only datatypes with no procedures. If even one procedure is contained in the interface, a local or UUID attribute must be specified.

See Also

IDL, /ms_ext, object, uuid


long

The long keyword designates a 32-bit integer. It can be preceded by either the keyword signed or the keyword unsigned. The int keyword is optional and can be omitted. To the MIDL compiler, a long integer is signed by default and is synonymous with signed long int.

The long integer type is one of the base types of the IDL language. The long integer type can appear as a type specifier in const declarations, typedef declarations, general declarations, and function declarators (as a function-return-type specifier and as a parameter-type specifier). For the context in which type specifiers appear, see IDL.

See Also

base_types, hyper, int, short, small


max_is

[max_is(limited-expression-list )]

limited-expression-list

Specifies one or more C-language expressions that are supported by MIDL. The expression evaluates to an integer that represents the highest valid array index. Separate multiple expressions with commas.

Examples

void Proc1(

[in] short m,

[in, max_is(m)] short a[]);  /* if m = 10,
there are 11 transmitted 	values of (a[0]...a[10])*/

void Proc2(

[in] short m,

[in, max_is(m)] short b[][20];  /* if m = 10,
the valid range for b 	is b[0...10][20] */

Remarks

The max_is attribute designates the maximum value for a valid array index. For an array of size n in C, where the first array element is element number 0, the maximum value for a valid array index is n-1.

The max_is attribute cannot be used as a field attribute at the same time as the size_is attribute.

See Also

field_attributes, IDL, min_is, size_is


maybe

[[ [ IDL-operation-attributes ] ]] operation-attribute , ...

IDL-operation-attributes

Specifies zero or more IDL operation attributes, such as maybe and idempotent. Operation attributes are enclosed in square brackets.

Remarks

The keyword maybe indicates that the remote procedure call does not need to execute every time it is called and the client does not expect a response. Note that the maybe protocol ensures neither delivery nor completion of the call.

A call with the maybe attribute cannot contain output parameters and is implicitly an idempotent call.

See Also

broadcast, idempotent, IDL, non-idempotent


midl_user_allocate

void __RPC_FAR * __RPC_API midl_user_allocate (size_t cBytes);

cBytes

Specifies the count of bytes to allocate.

Example

void __RPC_FAR * __RPC_API midl_user_allocate(size_t cBytes)

{

    return(malloc(cBytes));

}

Remarks

The midl_user_allocate function must be supplied by both client applications and server applications. Applications and generated stubs call midl_user_allocate when dealing with objects referenced by pointers:

•	The server application should call midl_user_allocate to allocate memory for the application — for example, when creating a new node.

•	The server stub calls midl_user_allocate when unmarshalling pointed-at data into the server address space.

•	The client stub calls midl_user_allocate when unmarshalling data from the server that is referenced by an out pointer. Note that for in, out, and unique pointers, the client stub calls midl_user_allocate only if the unique pointer value was NULL on input and changes to a non-null value during the call. If the unique pointer was non-null on input, the client stub writes the associated data into existing memory.

If midl_user_allocate fails to allocate memory, it must return a null pointer.

It is recommended that midl_user_allocate return a pointer that is 8 bytes aligned.

See Also

allocate, midl_user_free, pointers, ptr, ref, unique


midl_user_free

void __RPC_API midl_user_free(void __RPC_FAR * p);

Example

void __RPC_API midl_user_free(void __RPC_FAR * p)

{

    free(p);

}

Remarks

The midl_user_free function must be supplied by both client applications and server applications. The midl_user_free function must be able to free all storage allocated by midl_user_allocate.

Applications and stubs call midl_user_free when dealing with objects referenced by pointers:

•	The server application should call midl_user_free to free memory allocated by the application — for example, when deleting a specified node.

•	The server stub calls midl_user_free to release memory on the server after marshalling all out arguments, in, out arguments, and the return value.

See Also

midl_user_allocate, pointers, unique


min_is

The DCE IDL attribute min_is is not implemented in Microsoft RPC. The value of the minimum valid array index is zero.

See Also

arrays, IDL, max_is


ms_union

[..., ms_union, ...] interface-name {...}

interface-name

Specifies the name of the interface.

Example

[ms_union] long procedure (...);

Remarks

The keyword ms_union is used to control the NDR alignment of non-encapsulated unions.

The MIDL compiler in this version of Microsoft RPC mirrors the behavior of the OSF DCE IDL compiler for non-encapsulated unions. However, because earlier versions of the MIDL compiler did not do so, the /ms_union switch provides compatibility with interfaces built on previous versions of the MIDL compiler.

The ms_union feature can be used as an IDL interface attribute, an IDL type attribute, or as a command-line switch (/ms_union).

See Also

IDL, /ms_union


ncacn_dnet_nsp

endpoint("ncacn_dnet_nsp:server-name[port-name]")

server-name

Specifies the name or internet address for the server, or host, computer. The name is a character string.

port-name

Specifies a DECnet object name or object number. The object name can consist of up to 16 characters. Object numbers can be prefixed by the pound sign (#).

Examples

[   uuid(12345678-4000-2006-0000-20000000001a),

    version(1.1),

    endpoint("ncacn_dnet_nsp:node[RPC0034501]")

[   uuid(12345678-4000-2006-0000-20000000001a),

    version(1.1),

    endpoint("ncacn_dnet_nsp:node[#41]")

]

Remarks

The ncacn_dnet_nsp keyword identifies DECnet as the protocol family for the endpoint.

The syntax of the DECnet transport port string, like all port strings, is defined independently of the IDL specification. The compiler performs some syntax checking but does not guarantee that the endpoint specification is correct. Some errors may be reported at run time.

See Also

endpoint, ncacn_ip_tcp, ncacn_nb_nb, ncacn_nb_tcp, ncacn_np, ncacn_spx, ncalrpc, string_binding


ncacn_ip_tcp

endpoint("ncacn_ip_tcp:server-name[port-name]")

server-name

Specifies the name or Internet address for the server, or host, computer. The name is a character string. The Internet address is a common Internet address notation.

port-name

Specifies an optional 16-bit number. Values of less than 1024 are usually reserved. If no value is specified, the endpoint-mapping service selects a valid port-name value.

Example

[   uuid(12345678-4000-2006-0000-20000000001a),

    version(1.1),

    endpoint("ncacn_ip_tcp:rainier[1404]")

] interface foo

endpoint("ncacn_ip_tcp:128.10.2.30[1404]")

Remarks

The ncacn_ip_tcp keyword identifies TCP/IP as the protocol family for the endpoint.

Only the ncacn_spx and ncacn_ip_tcp protocols support cancels. For all other protocols, the cancel routines will return RPC_S_OK, but there will be no effect. Specifically:

RpcCancelThread will alert the specified thread, but will not interrupt a pending RPC.

RpcTestCancel will return RPC_S_OK if the current thread has been alerted.

RpcMgmtSetCancelTimeout has no visible effect.

RpcCancelThread, RpcTestCancel, and RpcMgmtSetCancelTimeout are only supported on Windows NT platforms; all other platforms return RPC_S_CANNOT_SUPPORT.

The syntax of the TCP/IP transport port string, like all port strings, is defined independently of the IDL specification. The compiler performs some syntax checking but does not guarantee that the endpoint specification is correct. Some errors may be reported at run time rather than during compilation.

See Also

endpoint, IDL, ncacn_nb_tcp, ncacn_np, ncacn_spx, ncalrpc, string_binding


ncacn_nb_nb

endpoint("ncacn_nb_nb:[port-name]")

port-name

Specifies an optional 8-bit value ranging from 0 to 255. Values of less than 0x20 are reserved. If the port-name value is not specified, the endpoint-mapping service selects the port value.

Example

[   uuid(12345678-4000-2006-0000-20000000001a),

    version(1.1),

    endpoint("ncacn_nb_nb:[100]")

]

Remarks

The ncacn_nb_nb keyword identifies NetBEUI over NetBIOS as the protocol family for the endpoint.

The syntax of the NetBIOS port string, like all port strings, is defined by the transport implementation and is independent of the IDL specification. The MIDL compiler performs limited syntax checking but does not guarantee that the endpoint specification is correct. Some classes of errors may be reported at run time rather than during compilation.

See Also

endpoint, IDL, ncacn_ip_tcp, ncacn_nb_tcp, ncacn_np, ncacn_spx, ncalrpc, string_binding


ncacn_nb_tcp

endpoint("ncacn_nb_tcp:[port-name]")

port-name

Specifies an optional 8-bit value ranging from 0 to 255. Values of less than 0x20 are reserved. If the port-name value is not specified, the endpoint-mapping service selects the port value.

Example

[   uuid(12345678-4000-2006-0000-20000000001a),

    version(1.1),

    endpoint("ncacn_nb_tcp:[100]")

]

Remarks

The ncacn_nb_tcp keyword is used to identify TCP over NetBIOS as the protocol family for the endpoint.

The syntax of the NetBIOS port string, like all port strings, is defined by the transport implementation and is independent of the IDL specification. The MIDL compiler performs limited syntax checking but does not guarantee that the endpoint specification is correct. Some classes of errors may be reported at run time rather than compile time.

See Also

endpoint, IDL, ncacn_ip_tcp, ncacn_nb_nb, ncacn_np, ncacn_spx, ncalrpc, string_binding


ncacn_np

endpoint("ncacn_np:server-name[\\pipe\\pipe-name]")

server-name

Specifies the name of the server. The server-name is optional. If the server-name is present, it must be preceded by four backslash characters, as in "\\\\myserver".

pipe-name

Specifies a valid pipe name. A valid pipe name is a string containing identifiers separated by backslash characters. The first identifier must be pipe. Each identifier must be separated by two backslash characters.

Example

[   uuid(12345678-4000-2006-0000-20000000001a),

    version(1.1),

    endpoint("ncacn_np:[\\pipe\\stove\\hat]")

]

Remarks

The ncacn_np keyword identifies named pipes as the protocol family for the endpoint.

Note  For Windows 95 platforms, ncacn_np is not supported.

The syntax of the named-pipe port string, like all port strings, is defined by the transport implementation and is independent of the IDL specification. The MIDL compiler performs limited syntax checking but does not guarantee that the endpoint specification is correct. Some classes of errors may be reported at run time rather than during compilation.

See Also

endpoint, IDL, ncacn_ip_tcp, ncacn_nb_nb, ncacn_nb_tcp, ncalrpc, string_binding


ncacn_spx

endpoint("ncacn_spx:link-address[port-name]")

link-address

Specifies 8 hexadecimal digits (4 bytes) that represent the network address and 12 hexadecimal digits (6 bytes) that represent the node address. A null string specifies the local computer.

port-name

Specifies an optional 16-bit number that represents the socket address. Values can range from 1 to 65,535. When no value is specified, the endpoint-mapping service selects a valid port-name value.

Example

[   uuid(12345678-4000-2006-0000-20000000001a),

    version(1.1),

    endpoint("ncacn_spx:[1000]")

] interface foo

Remarks

The ncacn_spx keyword identifies SPX as the protocol family for the endpoint.

The syntax of the SPX transport port string, like all port strings, is defined independently of the IDL specification. The compiler performs some syntax checking but does not guarantee that the endpoint specification is correct. Some errors may be reported at run time rather than during compilation.

When using the ncacn_spx transport, the server name is exactly the same as the Windows NT server name. However, since the names are distributed using Novell protocols, they must conform to the Novell naming conventions. If a server name is not a valid Novell name, servers will not be able to create endpoints with the ncacn_spx transport. The following is a partial list of characters prohibited in Novell server names:

"	*	+	.	/	:	;	<	=	>	?	[	]	\	|

The ncacn_spx transport is not supported by the version of NWLink supplied with MS Client 3.0.

Only the ncacn_spx and ncacn_ip_tcp protocols support cancels. For all other protocols, the cancel routines will return RPC_S_OK, but there will be no effect. Specifically:

RpcCancelThread will alert the specified thread, but will not interrupt a pending RPC.

RpcTestCancel will return RPC_S_OK if the current thread has been alerted.

RpcMgmtSetCancelTimeout has no visible effect.

RpcCancelThread, RpcTestCancel, and RpcMgmtSetCancelTimeout are only supported on Windows NT platforms; all other platforms return RPC_S_CANNOT_SUPPORT.

Note  The network and node addresses that specify the network-address portion of the ncacn_spx endpoint specification are available from the comcheck utility. With Windows NT, the network address is stored in the registry and the node address is displayed by the command net config rdr.

See Also

endpoint, IDL, ncacn_ip_tcp, ncacn_nb_nb, ncacn_nb_tcp, ncacn_np, ncalrpc, string_binding


ncadg_ip_udp

endpoint("ncadg_ip_udp:server-name[port-name]")

server-name

Specifies the name or internet address for the server, or host, computer. The name is a character string. The internet address is a common internet address notation.

port-name

Specifies an optional 16-bit number. Values of less than 1024 are usually reserved. If no value is specified, the endpoint-mapping service selects a valid port-name value.

Example

[   uuid(12345678-4000-2006-0000-20000000001a),

    version(1.1),

    endpoint("ncadg_ip_udp:rainier[1404]")

] interface foo

endpoint("ncadg_ip_udp:128.10.2.30[1404]")

Remarks

The ncadg_ip_udp keyword identifies the datagram version of TCP/IP as the protocol family for the endpoint.

The datagram protocols (ncadg_ipx and ncadg_ip_udp) have the following limitations:

They do not support callbacks. Any functions using the callback attribute will fail.

They do not support the RPC security API (RpcBindingSetAuthInfo, RpcImpersonateClient, etc.).

The syntax of the TCP/IP transport port string, like all port strings, is defined independently of the IDL specification. The compiler performs some syntax checking but does not guarantee that the endpoint specification is correct. Some errors may be reported at run time rather than during compilation.

See Also

endpoint, IDL, ncacn_nb_tcp, ncacn_np, ncacn_spx, ncalrpc, string_binding


ncadg_ipx

endpoint("ncadg_ipx:link-address[port-name]")

link-address

Specifies eight hexadecimal digits (4 bytes) that represent the network address and 12 hexadecimal digits (6 bytes) that represent the node address. A null string specifies the local computer.

port-name

Specifies an optional 16-bit number that represents the socket address. Values can range from 1 to 65535. When no value is specified, the endpoint-mapping service selects a valid port-name value.

Example

[   uuid(12345678-4000-2006-0000-20000000001a),

    version(1.1),

    endpoint("ncadg_ipx:[1000]")

] interface foo

Remarks

The ncadg_ipx keyword identifies IPX as the protocol family for the endpoint.

The syntax of the IPX transport port string, like all port strings, is defined independently of the IDL specification. The compiler performs some syntax checking but does not guarantee that the endpoint specification is correct. Some errors may be reported at run time rather than during compilation.

When using the ncadg_ipx transport, the server name is exactly the same as the Windows NT server name. However, since the names are distributed using Novell protocols, they must conform to the Novell naming conventions. If a server name is not a valid Novell name, servers will not be able to create endpoints with the ncadg_ipx transport.  The following is a partial list of characters prohibited in Novell server names:

"	*	+	.	/	:	;	<	=	>	?	[	]	\	|

The ncadg_ipx transport is supported by the version of NWLink supplied with MS Client 3.0.

The datagram protocols (ncadg_ipx and ncadg_ip_udp) have the following limitations:

They do not support callbacks. Any functions using the callback attribute will fail.

They do not support the RPC security API (RpcBindingSetAuthInfo, RpcImpersonateClient, etc.).

Only the ncacn_spx and ncacn_ip_tcp protocols support cancels. For all other protocols, the cancel routines will return RPC_S_OK, but there will be no effect. Specifically:

RpcCancelThread will alert the specified thread, but will not interrupt a pending RPC.

RpcTestCancel will return RPC_S_OK if the current thread has been alerted.

RpcMgmtSetCancelTimeout has no visible effect.

RpcCancelThread, RpcTestCancel, and RpcMgmtSetCancelTimeout are only supported on Windows NT platforms; all other platforms return RPC_S_CANNOT_SUPPORT.

Note  The network and node addresses that specify the network-address portion of the ncadg_ipx endpoint specification are available from the comcheck utility. With Windows NT, the network address is stored in the registry and the node address is displayed by the command net config rdr.

See Also

endpoint, IDL, ncacn_ip_tcp, ncacn_nb_nb, ncacn_nb_tcp, ncacn_np, ncalrpc, string_binding


ncalrpc

endpoint("ncalrpc:[port-name]")

port-name

Specifies a string that represents a Windows NT object name. The string should not contain any backslash (\) characters.

Example

[   uuid(12345678-4000-2006-0000-20000000001a),

    version(1.1),

    endpoint("ncalrpc:[myapplicationname]")

]

Remarks

The ncalrpc keyword identifies local interprocess communication as the protocol family for the endpoint. This keyword is one of the valid protocol family names that must be used with the endpoint attribute.

Note  The ncalrpc endpoint is only supported by Windows NT systems.  It is not supported by Windows 95.

The computer name must not be used with the ncalrpc keyword.

The syntax of the local interprocess-communication port string, like all port strings, is defined by the transport implementation and is independent of the IDL specification. The MIDL compiler performs limited syntax checking but does not guarantee that the endpoint specification is correct. Some classes of errors may be reported at run time rather than during compilation.

See Also

endpoint, IDL, ncacn_ip_tcp, ncacn_nb_nb, ncacn_nb_tcp, ncacn_np, ncacn_spx, string_binding


nocode

[ nocode [ , ACF-interface-attributes ] ] interface interface-name
{
[ include filename-list ; ] ...
[ typedef [type-attribute-list] typename; ] ...

[ [ nocode [ , ACF-function-attributes ] ] function-name (
[ ACF-parameter-attributes ] parameter-name ;
...
);
]
...
}

ACF-interface-attributes

Specifies a list of one or more attributes that apply to the interface as a whole. Valid attributes include either auto_handle or implicit_handle and either code or nocode. When two or more interface attributes are present, they must be separated by commas.

interface-name

Specifies the name of the interface. In DCE-compatibility mode, the interface name must match the name of the interface specified in the IDL file. When you use the MIDL compiler switch /acf, the interface name in the ACF and the interface name in the IDL file can be different.

filename-list

Specifies a list of one or more C-language header filenames, separated by commas. The full filename, including the extension, must be supplied.

type-attribute-list

Specifies a list of one or more attributes, separated by commas, that apply to the specified type. Valid type attributes include allocate.

typename

Specifies a type defined in the IDL file. Type attributes in the ACF can only be applied to types previously defined in the IDL file.

ACF-function-attributes

Specifies attributes that apply to the function as a whole, such as comm_status. Function attributes are enclosed in square brackets. Separate multiple function attributes with commas.

function-name

Specifies the name of the function as defined in the IDL file.

ACF-parameter-attributes

Specifies ACF attributes that apply to a parameter. Note that zero or more attributes can be applied to the parameter. Separate multiple parameter attributes with commas. ACF parameter attributes are enclosed in square brackets.

parameter-name

Specifies a parameter of the function as defined in the IDL file. Each parameter for the function must be specified in the same sequence and using the same name as defined in the IDL file.

Remarks

The nocode attribute can appear in the ACF header, or it can be applied to an individual function.

When the nocode attribute appears in the ACF header, client stub code is not generated for any remote function unless it has the code function attribute. You can override the nocode attribute in the header for an individual function by specifying the code attribute as a function attribute.

When the nocode attribute appears in the function's attribute list, no client stub code is generated for the function.

Client stub code is not generated when:

•	The ACF header includes the nocode attribute.

•	The nocode attribute is applied to the function.

•	The local attribute applies to the function in the interface file.

Either code or nocode can appear in a function's attribute list, and the one you choose can appear exactly once.

The nocode attribute is ignored when server stubs are generated. You cannot apply it when generating server stubs in DCE-compatibility mode.

See Also

ACF, code


non-encapsulated_union

typedef [switch_type(switch-type-specifier) [ , type-attr-list ] ] union [ tag ] {
[ case ( limited-expr-list) ]
[ [ field-attribute-list ] ] type-specifier declarator-list ;
[ [ default ]
[ [ field-attribute-list ] ] type-specifier declarator-list ;
]
}

switch-type-specifier

Specifies an integer, character, or enum type or an identifier of such a type.

type-attr-list

Specifies zero or more other attributes that apply to the union type. Valid type attributes include handle, transmit_as; the pointer attribute unique, or ptr; and the usage attributes context_handle and ignore. Separate multiple attributes with commas.

tag

Specifies an optional tag.

limited-expr-list

Specifies one or more C-language expressions that are supported by MIDL. Almost all C expressions are supported. The MIDL compiler supports conditional expressions, logical expressions, relational expressions, and arithmetic expressions. MIDL does not allow function invocations in expressions and does not allow pre- and post-increment and -decrement operators.

field-attribute-list

Specifies zero or more field attributes that apply to the union member. Valid field attributes include first_is, last_is, length_is, max_is, size_is; the usage attributes string, ignore, and context_handle; the pointer attribute ref, unique, or ptr; and, for members that are themselves unions, the union attribute switch_type. Separate multiple field attributes with commas.

type-specifier

Specifies a base_type, struct, union, enum type, or type identifier. An optional storage specification can precede type-specifier.

declarator-list

Specifies one or more standard C declarators, such as identifiers, pointer declarators, and array declarators. (Function declarators and bit-field declarations are not allowed in unions that are transmitted in remote procedure calls. These declarators are allowed in unions that are not transmitted.) Separate multiple declarators with commas.

Remarks

The non-encapsulated union is indicated by the presence of the type attribute switch_type and the field attribute switch_is.

The shape of unions must be the same across platforms to ensure interconnectivity.

For more information, see switch_is and switch_type.

See Also

field_attributes, IDL, union


non-idempotent

Non-idempotent (at most once) indicates that the remote procedure call cannot be executed more than once because it will return a different value or change a state. Non-idempotent is the default for remote procedure calls.

All non-idempotent calls are executed by the server "at most once"; that is, not at all or exactly once. The protocol used to enforce this is the callback function. Non-idempotent requests require the server to perform a callback when it receives a request from a client about which it has no information. The server makes the callback request by issuing a remote procedure call to the client. When it receives the callback, the server's boot time and the client's sequence number are used as the basis of comparison to validate the request. If a match is made, the server executes the original request. Otherwise, the request is ignored.

A non-idempotent call ensures that the data is received and processed at most one time.

See Also

broadcast, callback, idempotent, IDL, maybe


notify

[notify] ... ;

Example

[notify] ProcedureFoo;

Remarks

The notify attribute instructs the MIDL compiler to generate a server stub that contains a call to a specially-named procedure on the server side of the application. This procedure is called the notify procedure. It is called after all the output arguments have been marshalled and any memory associated with the parameters is freed.

The notify attribute is useful to develop applications acquiring resources in the server manager routine. These resources are then freed in the notify procedure after the output parameters are fully marshalled.

The notify procedure name is the name of the remote procedure suffixed by _notify. The notify procedure does not require any parameters and does not return a result. A prototype of this procedure is also generated in the header file. For example, if the IDL file contains the following:

ProcedureFoo [in] short S);

Specify the following in the ACF for MIDL to generate the notify call:

[notify] ProcedureFoo();

The generated code will contain the following call to the notify procedure:

ProcedureFoo_notify();

The header file will contain a prototype:

void ProcedureFoo_notif(void);

See Also

ACF


object

[ object, uuid(string-uuid)[ , interface-attribute-list] ]
interface interface-name : base-interface

string-uuid

Specifies a UUID string generated by the uuidgen utility. You can enclose the UUID string in quotes when you use the MIDL compiler switch /ms_ext.

interface-attribute-list

Specifies other attributes that apply to the interface as a whole.

interface-name

Specifies the name of the interface.

base-interface

Specifies the name of an OLE interface from which this derived interface inherits member functions, status codes, and interface attributes. All OLE interfaces are derived from the IUnknown interface or some other OLE interface.

Remarks

The object interface attribute identifies a custom OLE interface. An interface attribute list that does not include the object attribute indicates a DCE RPC interface. An interface attribute list for an OLE interface must include the uuid attribute, but it cannot include the version attribute.

By default, compiling an OLE interface with the MIDL compiler generates the files needed to build a proxy DLL that contains the code to support the use of the custom OLE interface by both client applications and object servers. However, if the interface attribute list for an OLE interface specifies the local attribute, the MIDL compiler generates only the interface header file.

The MIDL compiler automatically generates an interface data type for an OLE interface. As an alternative, you can use typedef with the interface keyword to explicitly define an interface data type. The interface specification can then use the interface data type in function parameters and return values, struct and union members, and other type declarations. The following example illustrates the use of an automatically generated IStream data type:

[object, uuid (ABCDEFOO-1234-1234-5678-ABCDEF123456]

interfaace IStream{

typedef IStream * LPSTREAM;

}

}

In an OLE interface, all the interface member functions are assumed to be virtual functions. A virtual function has an implicit this pointer as the first parameter. The virtual function table contains an entry for each interface member function.

Files that use the object attribute must be compiled with the /ms_ext MIDL compiler switch.

See Also

IDL, iid_is, local, /ms_ext, uuid, version


optimize

optimize ("optimization-options")

optimization-options

Specifies the method of marshalling data. Use either "s" for mixed-mode marshalling or "i" for interpreted marshalling.

Examples

optimize ("s") void FasterProcedure(...);

optimize ("i") void SmallerProcedure(...);

{

};

Remarks

The keyword optimize is used to fine-tune the level of gradation for marshalling data.

This version of RPC provides two methods for marshalling data: mixed-mode ("s") and interpreted ("i"). These methods correspond to the /Os and /Oi command-line switches. The interpreted method marshals data completely offline. While this can reduce the size of the stub considerably, performance can be affected.

If performance is a concern, the mixed-mode method can be the best approach. Mixed-mode allows the MIDL compiler to make the determination between which data will be marshalled inline and which will be marshalled by a call to an offline dynamic-link library. If many procedures use the same data types, a single procedure can be called repeatedly to marshal the data. In this way, data that is most suited to inline marshalling is processed inline while other data can be more efficiently marshalled offline.

Note that the optimize attribute can be used as an interface attribute or as an operation attribute. If it is used as an interface attribute, it sets the default for the entire interface, overriding command-line switches. If, however, it is used as an operation attribute, it affects only that operation, overriding command-line switches and the interface default.

See Also

ACF, /Oi, /Os


out

[ [function-attribute-list] ] type-specifier [pointer-declarator] function-name(
[ out [ , parameter-attribute-list ] ] type-specifier [declarator]
, ...
);

function-attribute-list

Specifies zero or more attributes that apply to the function. Valid function attributes are callback, local; the pointer attribute ref, unique, or ptr; and the usage attributes string, ignore, and context_handle.

type-specifier

Specifies a base_type, struct, union, or enum type or type identifier. An optional storage specification can precede type-specifier.

pointer-declarator

Specifies zero or more pointer declarators. A pointer declarator is the same as the pointer declarator used in C; it is constructed from the * designator, modifiers such as far, and the qualifier const.

function-name

Specifies the name of the remote procedure.

parameter-attribute-list

Specifies zero or more attributes appropriate for a specified parameter type. Parameter attributes with the out attribute can also take the directional attribute out; the field attributes first_is, last_is, length_is, max_is, size_is, and switch_type; the pointer attribute ref, unique, or ptr; and the usage attributes context_handle and string. The usage attribute ignore cannot be used as a parameter attribute. Separate multiple attributes with commas.

declarator

Specifies standard C declarators, such as identifiers, pointer declarators, and array declarators. For more information, see pointers and arrays. The parameter declarator in the function declarator, such as the parameter name, is optional.

Example

void MyFunction([out] short * pcount);

Remarks

The out attribute identifies pointer parameters that are returned from the called procedure to the calling procedure (from the server to the client).

The out attribute indicates that a parameter that acts as a pointer and its associated data in memory are to be passed back from the called procedure to the calling procedure.

The out attribute must be a pointer. DCE IDL compilers require the presence of an explicit * as a pointer declarator in the parameter declaration. Microsoft IDL offers an extension that drops this requirement and allows an array or a previously defined pointer type.

A related attribute, in, indicates that the parameter is passed from the calling procedure to the called procedure. The in and out attributes specify the direction in which the parameters are passed. A parameter can be defined as in-only, out-only, or in, out.

An out-only parameter is assumed to be undefined when the remote procedure is called and memory for the object is allocated by the server. Since top-level pointer/parameters must always point to valid storage, and therefore cannot be null, out cannot be applied to top-level unique or ptr pointers. Parameters that are ref pointers must be either in or in, out parameters.

See Also

in, ref


out_of_line

The DCE IDL keyword out_of_line is not supported in Microsoft RPC.

See Also

IDL


pipe

The DCE IDL keyword pipe is not supported in Microsoft RPC.

See Also

IDL


pointer_default

pointer_default ( ptr | ref | unique )

Example

[uuid(6B29FC40-CA47-1067-B31D-00DD010662DA),

version(3.3),

pointer_default(unique)]

interface dictionary

Remarks

The pointer_default attribute specifies the default pointer attribute for all pointers except top-level pointers that appear in parameter lists. This includes embedded pointers — pointers that appear in structures, unions, and arrays. The pointer_default attribute can also apply to pointers returned by functions.

MIDL generates an error during compilation when you do not supply a pointer attribute in an interface that includes embedded pointers.

The default does not apply to pointers that appear as top-level parameters, such as individual pointers used as function parameters. A pointer attribute must be supplied for these pointers. The default is always overridden when a pointer attribute is supplied. If all pointers are supplied with pointer attributes, the default attribute is ignored.

The pointer_default attribute is an optional attribute in the IDL file. The pointer_default attribute is required only in the interface header when:

•	A parameter with more than one asterisk (*) appears in a function.

•	A structure member or union arm with a pointer declarator does not have a pointer attribute.

•	A function returns a pointer type and does not have a pointer attribute as a function attribute.

If the pointer_default attribute appears in the interface header and is not required, it is ignored.

See Also

interface, pointers, ptr, ref, unique


pointers

MIDL supports three kinds of pointers: reference pointers, unique pointers, and full pointers. These pointers are specified by the pointer attributes ref, unique, and ptr.

A pointer attribute can be applied as a type attribute; as a field attribute that applies to a structure member, union member, or parameter; or as a function attribute that applies to the function return type. The pointer attribute can also appear with the pointer_default keyword.

To allow a pointer parameter to change in value during a remote function, you must provide another level of indirection by supplying multiple pointer declarators. The explicit pointer attribute applied to the parameter affects only the rightmost pointer declarator for the parameter. When there are multiple pointer declarators in a parameter declaration, the other declarators default to the pointer attribute specified by the pointer_default attribute. To apply different pointer attributes to multiple pointer declarators, you must define intermediate types that specify the explicit pointer attributes.

Default Pointer-Attribute Values

When no pointer attribute is associated with a pointer that is a parameter, the pointer is assumed to be a ref pointer.

When no pointer attribute is associated with a pointer that is a member of a structure or union, the MIDL compiler assigns pointer attributes using the following priority rules (1 is highest):

1.	Attributes explicitly applied to the pointer type

2.	Attributes explicitly applied to the pointer parameter or member

3.	Pointer_default attribute in the IDL file that defines the type

4.	Pointer_default attribute in the IDL file that imports the type

5.	Ptr (DCE-compatibility mode); unique (Microsoft-extensions mode)

When the IDL file is compiled using Microsoft-extensions (/ms_ext) mode, imported files can inherit pointer attributes from importing files. For more information, see import.

Function Return Types

A pointer returned by a function must be a unique pointer or a full pointer. The MIDL compiler reports an error if a function result is a reference pointer, either explicitly or by default. The returned pointer always indicates new storage.

Functions that return a pointer value can specify a pointer attribute as a function attribute. If a pointer attribute is not present, the function-result pointer uses the value provided as the pointer_default attribute.

Pointer Attributes in Type Definitions

When you specify a pointer attribute at the top level of a typedef statement, the specified attribute is applied to the pointer declarator, as expected. When no pointer attribute is specified, pointer declarators at the top level of a typedef statement inherits the pointer attribute type when used.

DCE IDL does not allow the same pointer attribute to be explicitly applied twice — for example, in both the typedef declaration and the parameter attribute list. When you use the Microsoft-extensions mode of the MIDL compiler (/ms_ext), this constraint is relaxed.

See Also

allocate, IDL, import, /ms_ext, pointer_default, ptr, ref, unique


pragma

#pragma midl_echo("string")
#pragma token-sequence
#pragma pack (n)
#pragma pack ( [push] [, id] [, n} )
#pragma pack ( [pop] [, id] [, n} )

string

Specifies a string that is inserted into the generated header file. The quotation marks are removed during the insertion process.

token-sequence

Specifies a sequence of tokens that are inserted into the generated header file as part of a #pragma directive without processing by the MIDL compiler.

n

Specifies the current pack size. Valid values are 1, 2, 4, 8, and 16.

id

Specifies the user id.

Examples

/* IDL file */

#pragma midl_echo("#define UNICODE")

cpp_quote("#define __DELAYED_PREPROCESSING__ 1")

#pragma hdrstop

#pragma check_pointer(on)

/* generated header file */

#define UNICODE

#define __DELAYED_PREPROCESSING__ 1

#pragma hdrstop

#pragma check_pointer(on)

Remarks

The #pragma midl_echo directive instructs MIDL to emit the specified string, without the quote characters, into the generated header file.

C-language preprocessing directives that appear in the IDL file are processed  by the C compiler's preprocessor. The #define directives in the IDL file are available during MIDL compilation, although not to the C compiler.

For example, when the preprocessor encounters the directive "#define WINDOWS 4", the preprocessor replaces all occurrences of "WINDOWS" in the IDL file with "4". The symbol "WINDOWS" is not available at C-compile time.

To allow the C-preprocessor macro definitions to pass through the MIDL compiler to the C compiler, use the #pragma midl_echo or cpp_quote directive. These directives instruct the MIDL compiler to generate a header file that contains the parameter string with the quotation marks removed. The #pragma midl_echo and cpp_quote directives are equivalent.

The #pragma pack directive is used by the MIDL compiler to control the packing of structures. It overrides the /Zp command-line switch. The pack (n) option sets the current pack size to a specific value: 1, 2, 4, 8, or 16. The pack (push) and pack (pop) options have the following characteristics:

•	The compiler maintains a packing stack. The elements of the packing stack include a pack size and an optional id. The stack is limited only by available memory with the current pack size at the top of the stack.

•	Pack (push) results in the current pack size pushed onto the packing stack. The stack is limited by available memory.

•	Pack (push, n) is the same as pack (push) followed by pack (n).

•	Pack (push, id) also pushes id onto the packing stack along with the pack size.

•	Pack (push, id, n) is the same as pack (push, id) followed by pack (n).

•	Pack (pop) results in popping the packing stack. Unbalanced pops cause warnings and set the current pack size to the command-line value.

•	If pack (pop, id, n) is specified, then n is ignored.

The MIDL compiler places the strings specified in the cpp_quote and pragma directives in the header file in the sequence in which they are specified in the IDL file and relative to other interface components in the IDL file. The strings should usually appear in the interface-body section of the IDL file after all import operations.

The MIDL compiler does not attempt to process #pragma directives that do not start with the prefix "midl_." Other #pragma directives in the IDL file are passed into the generated header file without changes.

See Also

cpp_quote, IDL, /Zp


ptr

pointer_default(ptr)

typedef [ ptr [ , type-attribute-list ] ] type-specifier declarator-list;

typedef struct-or-union-declarator {
[ ptr [ , field-attribute-list ] ] type-specifier declarator-list;
...}

[ ptr [ , function-attribute-list ] ] type-specifier ptr-decl function-name(
[ [ parameter-attribute-list ] ] type-specifier [declarator]
, ...
);
[ [ function-attribute-list ] ] type-specifier [ptr-decl] function-name(
[ ptr [ , parameter-attribute-list ] ] type-specifier [declarator]
, ...
);

type-attribute-list

Specifies one or more attributes that apply to the type. Valid type attributes include handle, switch_type, transmit_as; the pointer attribute ref, unique, or ptr; and the usage attributes context_handle, string, and ignore. Separate multiple attributes with commas.

type-specifier

Specifies a base_type, struct, union, or enum type or type identifier. An optional storage specification can precede type-specifier.

declarator and declarator-list

Specifies standard C declarators, such as identifiers, pointer declarators, and array declarators. For more information, see pointers and arrays. The declarator-list consists of one or more declarators separated by commas. The parameter-name identifier in the function declarator is optional.

struct-or-union-declarator

Specifies a MIDL struct or union declarator. field-attribute-list

Specifies zero or more field attributes that apply to the structure or union member or function parameter. Valid field attributes include first_is, last_is, length_is, max_is, size_is; the usage attributes string, ignore, and context_handle; the pointer attribute ref, unique, or ptr; and the union attribute switch_type. Separate multiple field attributes with commas.

function-attribute-list

Specifies zero or more attributes that apply to the function. Valid function attributes are callback, local; the pointer attribute ref, unique, or ptr; and the usage attributes string, ignore, and context_handle.

ptr-decl

Specifies at least one pointer declarator to which the ptr attribute applies. A pointer declarator is the same as the pointer declarator used in C; it is constructed from the * designator, modifiers such as far, and the qualifier const.

function-name

Specifies the name of the remote procedure.

parameter-attribute-list

Consists of zero or more attributes appropriate for the specified parameter type. Parameter attributes can take the directional attributes in and out; the field attributes first_is, last_is, length_is, max_is, size_is, and switch_type; the pointer attribute ref, unique, or ptr; and the usage attributes context_handle and string. The usage attribute ignore cannot be used as a parameter attribute. Separate multiple attributes with commas.

Examples

pointer_default(ptr)

typedef [ptr, string] unsigned char * MY_STRING_TYPE;

[ptr] char * MyFunction([in, out, unique] long * plNumber);

Remarks

The ptr attribute designates a pointer as a full pointer. The full pointer approaches the full functionality of the C-language pointer. The full pointer can have the value NULL and can change during the call from null to non-null. Storage pointed to by full pointers can be reached by other names in the application supporting aliasing and cycles. This functionality requires more overhead during a remote procedure call to identify the data referred to by the pointer, determine whether the value is NULL, and to discover if two pointers point to the same data.

Use full pointers for:

•	Remote return values.

•	Double pointers, when the size of an output parameter is not known.

•	NULL pointers.

Full (and unique) pointers cannot be used to describe the size of an array or union because these pointers can have the value NULL. This restriction by MIDL prevents an error that can result when a NULL value is used as the size.

Reference and unique pointers are assumed to cause no aliasing of data. A directed graph obtained by starting from a unique or reference pointer and following only unique or reference pointers contains neither reconvergence nor cycles.

To avoid aliasing, all pointer values should be obtained from an input pointer of the same class of pointer. If more than one pointer points to the same memory location, all such pointers must be full pointers.

In some cases, full and unique pointers can be mixed. A full pointer can be assigned the value of a unique pointer, as long as the assignment does not violate the restrictions on changing the value of a unique pointer. However, when you assign a unique pointer the value of a full pointer, you may cause aliasing.

Mixing full and unique pointers can cause aliasing, as demonstrated in the following example:

typedef struct {

    [ptr] short * pdata;          // full pointer

} GRAPH_NODE_TYPE;

typedef struct {

    [unique] graph_node * left;   // unique pointer

    [unique] graph_node * right;  // unique pointer

} TREE_NODE_TYPE;

// application code:

short a = 5;

TREE_NODE_TYPE * t;

GRAPH_NODE_TYPE g, h;

g.pdata = h.pdata = &a;

t->left = &g;

t->right = &h;

// t->left->pdata == t->right->pdata == &a

Although "t->left" and "t->right" point to unique memory locations, "t->left->pdata" and "t->right->pdata" are aliased. For this reason, aliasing-support algorithms must follow all pointers (including unique and reference pointers) that may eventually reach a full pointer.

See Also

IDL, pointer_default, pointers, ref, unique


ref

pointer_default(ref)

typedef [ ref [ , type-attribute-list ] ] type-specifier declarator-list;

typedef struct-or-union-declarator {
[ ref [ , field-attribute-list ] ] type-specifier declarator-list;
...}

[ [ function-attribute-list ] ] type-specifier [ptr-decl] function-name(
[ ref [ , parameter-attribute-list ] ] type-specifier [declarator]
, ...
);

type-attribute-list

Specifies one or more attributes that apply to the type. Valid type attributes include handle, switch_type, transmit_as; the pointer attributes ref, unique, or ptr; and the usage attributes context_handle, string, and ignore. Separate multiple attributes with commas.

type-specifier

Specifies a base_type, struct, union, or enum type or type identifier. An optional storage specification can precede type-specifier.

declarator and declarator-list

Specifies standard C declarators, such as identifiers, pointer declarators, and array declarators. For more information, see pointers and arrays. The declarator-list consists of one or more declarators separated by commas. The parameter-name identifier in the function declarator is optional.

struct-or-union-declarator

Specifies a MIDL struct or union declarator.

field-attribute-list

Specifies zero or more field attributes that apply to the structure, union member, or function parameter. Valid field attributes include first_is, last_is, length_is, max_is, size_is; the usage attributes string, ignore, and context_handle; the pointer attribute ref, unique, or ptr; and the union attribute switch_type. Separate multiple field attributes with commas.

function-attribute-list

Specifies zero or more attributes that apply to the function. Valid function attributes are callback, local; the pointer attribute ref, unique, or ptr; and the usage attributes string, ignore, and context_handle.

ptr-decl

Specifies at least one pointer declarator to which the ref attribute applies. A pointer declarator is the same as the pointer declarator used in C; it is constructed from the * designator, modifiers such as far, and the qualifier const.

function-name

Specifies the name of the remote procedure.

parameter-attribute-list

Consists of zero or more attributes appropriate for the specified parameter type. Parameter attributes can take the directional attributes in and out; the field attributes first_is, last_is, length_is, max_is, size_is, and switch_type; the pointer attribute ref, unique, or ptr; and the usage attributes context_handle and string. The usage attribute ignore cannot be used as a parameter attribute. Separate multiple attributes with commas.

Example

[unique] char * GetFirstName(

[in, ref] char * pszFullName

);

Remarks

The ref attribute identifies a reference pointer. It is used simply to represent a level of indirection.

A pointer attribute can be applied as a type attribute, as a field attribute that applies to a structure member, union member, or parameter; or as a function attribute that applies to the function return type. The pointer attribute can also appear with the pointer_default keyword.

A reference pointer has the following characteristics:

•	Always points to valid storage; never has the value NULL. A reference pointer can always be dereferenced.

•	Never changes during a call. A reference pointer always points to the same storage on the client before and after the call.

•	Does not allocate new memory on the client. Data returned from the server is written into existing storage specified by the value of the reference pointer before the call.

•	Does not cause aliasing. Storage pointed to by a reference pointer cannot be reached from any other name in the function.

A reference pointer cannot be used as the type of a pointer returned by a function.

If no attribute is specified for a top-level pointer parameter, it is treated as a reference pointer.

See Also

pointers, ptr, unique


represent_as

typedef [represent_as(repr-type) [ , type-attribute-list ] ]
named-type;

void __RPC_USER named-type_from_local (
repr-type __RPC_FAR * ,
named-type __RPC_FAR * __RPC_FAR * );

void __RPC_USER named-type_to_local (
named-type __RPC_FAR * ,
repr-type __RPC_FAR * );

void __RPC_USER named-type_free_inst (
named-type __RPC_FAR * );

void __RPC_USER named-type_free_local (
repr-type__RPC_FAR * );

named-type

Specifies the named transfer data type that is transferred between client and server.

type-attribute-list

Specifies one or more attributes that apply to the type. Valid type attributes include handle, switch_type; the pointer attribute ref, unique, or ptr; and the usage attributes string and ignore. Separate multiple attributes with commas.

repr-type

Specifies the represented local type in the target language that is presented to the client and server applications.

Examples

typedef struct _TREE_NODE_TYPE {

    unsigned short data;

    struct _TREE_NODE_TYPE * left;

    struct _TREE_NODE_TYPE * right;

} TREE_NODE_TYPE;

typedef [represent_as(TREE_NAMED_TYPE)] TREE_TYPE; /*in ACF */

void __RPC_USER TREE_TYPE_from_local(

TREE_TYPE __RPC_FAR * ,

TREE_NAMED_TYPE __RPC_FAR * __RPC_FAR *);

void __RPC_USER TREE_TYPE_to_local (

TREE_NAMED_TYPE __RPC_FAR *,

TREE_TYPE __RPC_FAR *);

void __RPC_USER TREE_TYPE_free_inst(

TREE_NAMED_TYPE __RPC_FAR *);

void __RPC_USER TREE_TYPE_free_local(

TREE_TYPE __RPC_FAR *);

Remarks

The represent_as attribute associates a named local type in the target language repr-type with a transfer type named-type that is transferred between client and server. You must supply routines that convert between the local and the transfer types and that free memory used to hold the converted data. The represent_as attribute instructs the stubs to call the user-supplied conversion routines.

The transferred type named-type must resolve to a MIDL base type, predefined type, or to a type identifier. For more information, see base_types.

The user must supply the following routines:

Routine name	Description
named_type_from_local	Allocates an instance of the network type and converts from the local type to the network type
named_type_to_local	Converts from the network type to the local type
named_type_free_local	Frees memory allocated by a call to the named_type_to_local routine, but not the type itself
named_type_free_inst	Frees storage for the network type (both sides)
The client stub calls named-type_from_local to allocate space for the transmitted type and to translate the data from the local type to the network type. The server stub allocates space for the original data type and calls named-type_to_local to translate the data from the network type to the local type.

Upon return from the application code, the client and server stubs call named-type_free_inst to deallocate the storage for network type. The client stub calls named-type_free_local to deallocate storage returned by the routine.

The following types cannot have a represent_as attribute:

•	Pipe types.

•	Types used as the base type in a pipe definition.

•	Conformant, varying, or conformant varying arrays.

•	Structures in which the last member is a conformant array (a conformant structure).

•	Pointers or types that contain a pointer.

•	Predefined types handle_t, void.

See Also

ACF, arrays, base_types, typedef


shape

The DCE IDL keyword shape is not supported in Microsoft RPC.

See Also

IDL


short

The short keyword designates a 16-bit integer. The short keyword can be preceded by either the keyword signed or the keyword unsigned. The int keyword is optional and can be omitted. To the MIDL compiler, a short integer is signed by default and is synonymous with signed short int.

The short integer type is one of the base types of the IDL language. The short integer type can appear as a type specifier in const declarations, typedef declarations, general declarations, and function declarators (as a function-return-type specifier and a parameter-type specifier). For the context in which type specifiers appear, see IDL.

See Also

base_types, IDL, int, long, small


signed

The signed keyword indicates that the most significant bit of an integer variable represents a sign bit rather than a data bit. This keyword is optional and can be used with any of the character and integer types char, wchar_t, long, short, and small.

When you use the MIDL compiler switch char, character and integer types that appear in the IDL file without explicit sign keywords can appear with the signed or unsigned keywords in the generated header file.  To avoid confusion, explicitly specify the sign of the integer and character types.

See Also

base_types, IDL, int, long, short, small, unsigned


size_is

[ size_is(limited-expression) ]

limited-expression

Specifies a C-language expression that evaluates to an integer that represents the maximum allocation size, in elements, of the leftmost dimension of an array. The MIDL compiler supports conditional expressions, logical expressions, relational expressions, and arithmetic expressions. MIDL does not allow function invocations in expressions and does not allow pre- and post-increment and -decrement operators.

Examples

void Proc1(

[in, short] m;

[in, size_is(m)] short a[]);  /* if m = 10, a[10] */

void Proc2(

[in, short] m;

[in, size_is(m)] short b[][20]);  /* if m = 10, b[10][20] */

Remarks

The size_is attribute is used to specify an expression or identifier that designates the maximum size, in elements, of an array dimension. The specified value must be non-negative. You can use either size_is or max_is (but not both in the same attribute list) to specify the size of an array whose upper bounds are determined at run time. Note, however, that the size_is attribute cannot be used on array dimensions that are fixed. The max_is attribute specifies the maximum valid array index. As a result, specifying size_is(n) is equivalent to specifying max_is(n-1).

An in or in, out conformant-array parameter with the string attribute need not have the size_is or max_is attribute. In this case, the size of the allocation is determined from the null terminator of the input string. All other conformant arrays with the string attribute must have a size_is or max_is attribute.

In an OLE interface (when the object interface attribute is specified), you can use the size_is attribute with a void * type. In this case, the declarator is treated as a pointer to an array of bytes. This usage requires using the MIDL compiler with the /ms_ext switch.

See Also

arrays, field_attributes, first_is, IDL, last_is, length_is, max_is, min_is


small

The small keyword designates an 8-bit integer number. The small keyword can be preceded by either the keyword signed or the keyword unsigned. The int keyword is optional and can be omitted. To the MIDL compiler, a small integer is signed by default and is synonymous with signed small int.

The small integer type is one of the base types of the IDL language. The small integer type can appear as a type specifier in const declarations, typedef declarations, general declarations, and function declarators (as a function-return-type specifier and as a parameter-type specifier). For the context in which type specifiers appear, see IDL.

The sign of the small type can be modified by the MIDL compiler switch /char. To avoid confusion, specify the sign of the integer type with the keywords signed and unsigned.

See Also

/char, int, long, short


string

typedef [ string [ , type-attribute-list ] ] type-specifier declarator-list;

typedef struct-or-union-declarator {
[ string [ , field-attribute-list ] ] type-specifier declarator-list;
...}

[ string [ , function-attribute-list ] ] type-specifier ptr-decl function-name(
[ [ parameter-attribute-list ] ] type-specifier [declarator]
, ...
);
[ [ function-attribute-list ] ] type-specifier [ptr-decl] function-name(
[ string [ , parameter-attribute-list ] ] type-specifier [declarator]
, ...
);

type-attribute-list

Specifies one or more attributes that apply to a type. Valid type attributes include handle, switch_type, transmit_as; the pointer attribute ref, unique, or ptr; and the usage attributes context_handle, string, and ignore. Separate multiple attributes with commas.

type-specifier

Specifies a base_type, struct, union, or enum type or type identifier. An optional storage specification can precede type-specifier.

declarator and declarator-list

Specify standard C declarators, such as identifiers, pointer declarators, and array declarators. For more information, see pointers and arrays. The declarator-list consists of one or more declarators separated by commas. The parameter-name identifier in the function declarator is optional.

struct-or-union-declarator

Specifies a MIDL struct or union declarator.

field-attribute-list

Specifies zero or more field attributes that apply to the structure, union member, or function parameter. Valid field attributes include first_is, last_is, length_is, max_is, size_is; the usage attributes string, ignore, and context_handle, the pointer attribute ref, unique, or ptr, and the union attribute switch_type. Separate multiple field attributes with commas.

function-attribute-list

Specifies zero or more attributes that apply to the function. Valid function attributes are callback, local; the pointer attribute ref, unique, or ptr; and the usage attributes string, ignore, and context_handle.

ptr-decl

Specifies an optional pointer declarator to which the string attribute applies. A pointer declarator is the same as the pointer declarator used in C; it is constructed from the * designator, modifiers such as far, and the qualifier const.

function-name

Specifies the name of the remote procedure.

parameter-attribute-list

Consists of zero or more attributes appropriate for the specified parameter type. Parameter attributes can take the directional attributes in and out; the field attributes first_is, last_is, length_is, max_is, size_is, and switch_type; the pointer attribute ref, unique, or ptr; and the usage attributes context_handle and string. The usage attribute ignore cannot be used as a parameter attribute. Separate multiple attributes with commas.

Example

/* a string type that can hold up to 80 characters */

typedef [string] char line[81];

void Proc1([in, string] char * pszName);

Remarks

The string attribute indicates that the one-dimensional char, wchar_t, byte (or equivalent) array or the pointer to such an array must be treated as a string.

The string can also be an array (or a pointer to an array) of constructs whose fields are all of the type "byte."

If the string attribute is used with an array whose bounds are determined at run time, you must also specify a size_is or max_is attribute.

The string attribute cannot be used with attributes that specify the range of transmitted elements, such as first_is, last_is, and length_is.

When used on multidimensional arrays, the string attribute applies to the rightmost array.

To define a counted string, do not use the string attribute. Use a character array or character-based pointer such as the following:

typedef struct {

    unsigned short size;

    unsigned short length;

    [size_is(size), length_is(length)] char string[*];

} counted_string;

The string attribute specifies that the stub should use a language-supplied method to determine the length of strings.

When declaring strings in C, you must allocate space for an extra character that marks the end of the string.

See Also

arrays, char, wchar_t


struct

struct [ struct-tag ] {
[ [ field-attribute-list ] ] type-specifier declarator-list;
...
}

struct-tag

Specifies an optional tag for the structure.

field-attribute-list

Specifies zero or more field attributes that apply to the structure member. Valid field attributes include first_is, last_is, length_is, max_is, size_is; the usage attributes string, ignore, and context_handle; the pointer attribute ref, unique, or ptr; and the union attribute switch_type. Separate multiple field attributes with commas.

type-specifier

Specifies a base_type, struct, union, or enum type or type identifier. An optional storage specification can precede type-specifier.

declarator-list

Specifies one or more standard C declarators, such as identifiers, pointer declarators, and array declarators. (Function declarators and bit-field declarations are not allowed in structures that are transmitted in remote procedure calls. These declarators are allowed in structures that are not transmitted.) Separate multiple declarators with commas.

Example

typedef struct _PITCHER_RECORD_TYPE {

    short flag;

    [switch_is(flag)] union PITCHER_STATISTICS_TYPE p;

} PITCHER_RECORD_TYPE;

Remarks

The struct keyword is used in a structure type specifier. The IDL structure type specifier differs from the standard C type specifier in the following ways:

•	Each structure member can be associated with optional field attributes that describe characteristics of that structure member for the purposes of a remote procedure call.

•	Bit fields and function declarators are not allowed in structures that are used in remote procedure calls. These standard C declarator constructs can be used only if the structure is not transmitted on the network.

The shape of structures must be the same across platforms to ensure interconnectivity.

See Also

arrays, base_types, /c_ext, IDL, /ms_ext, pointers


switch

switch (switch-type switch-name)

switch-type

Specifies an int, char, enum type, or an identifier that resolves to one of these types.

switch-name

Specifies the name of the variable of type switch-type that acts as the union discriminant.

Examples

typedef union _S1_TYPE switch (long l1) U1_TYPE {

    case 1024:

        float f1;

    case 2048:

        double d2;

} S1_TYPE;

/* in generated header file */

typedef struct _S1_TYPE {

    long l1;

    union {

        float f1;

        double d2;

    } U1_TYPE;

} S1_TYPE;

Remarks

The switch keyword selects the discriminant for an encapsulated_union.

See Also

IDL, non-encapsulated_union, switch_is, switch_type, union


switch_is

typedef struct [ struct-tag ] {
[ switch_is(limited-expr) [ , field-attr-list ] ] union-type-specifier declarator;
...
}

[ [function-attribute-list] ] type-specifier [pointer-declarator] function-name(
[ switch_is(limited-expr) [ , param-attr-list ] ] union-type [declarator]
, ...
);

struct-tag

Specifies an optional tag for a structure.

limited-expr

Specifies a C-language expression supported by MIDL. Almost all C-language expressions are supported. The MIDL compiler supports conditional expressions, logical expressions, relational expressions, and arithmetic expressions. MIDL does not allow function invocations in expressions and does not allow pre- and post-increment and -decrement operators.

field-attr-list

Specifies zero or more field attributes that apply to a union member. Valid field attributes include first_is, last_is, length_is, max_is, size_is; the usage attributes string, ignore, and context_handle; the pointer attribute ref, unique, or ptr; and for members that are themselves unions, the union attribute switch_type. Separate multiple field attributes with commas.

union-type-specifier

Specifies the union type identifier. An optional storage specification can precede type-specifier.

declarator and declarator-list

Specifies a standard C declarator, such as an identifier, pointer declarator, and array declarator. (Function declarators and bit-field declarations are not allowed in unions that are transmitted in remote procedure calls. These declarators are allowed in unions that are not transmitted.) Separate multiple declarators with commas.

function-attribute-list

Specifies zero or more attributes that apply to the function. Valid function attributes are callback, local; the pointer attribute ref, unique, or ptr; and the usage attributes string, ignore, and context_handle.

type-specifier

Specifies a base_type, struct, union, enum type, or type identifier. An optional storage specification can precede type-specifier.

pointer-declarator

Specifies zero or more pointer declarators. A pointer declarator is the same as the pointer declarator used in C; it is constructed from the * designator, modifiers such as far, and the qualifier const.

function-name

Specifies the name of the remote procedure.

param-attr-list

Specifies zero or more attributes appropriate for the specified parameter type. Parameter attributes can take the directional attributes in and out, the field attributes first_is, last_is, length_is, max_is, size_is, and switch_type; the pointer attribute ref, unique, or ptr; and the usage attributes context_handle and string. The usage attribute ignore cannot be used as a parameter attribute. Separate multiple attributes with commas.

union-type

Identifies the union type specifier.

Examples

typedef [switch_type(short)] union _WILLIE_UNION_TYPE {

    [case(24)]

        float fMays;

    [case(25)]

        double dMcCovey;

    [default]

        ;

} WILLIE_UNION_TYPE;

typedef struct _WINNER_TYPE {

    [switch_is(sUniformNumber)] union WILLIE_UNION_TYPE w;

    short sUniformNumber;

} WINNER_TYPE;

Remarks

The switch_is attribute specifies the expression or identifier acting as the union discriminant that selects the union member. The discriminant associated with the switch_is attribute must be defined at the same logical level as the union:

•	When the union is a parameter, the union discriminant must be another parameter.

•	When the union is a field of a structure, the discriminant must be another field of the same structure.

The sequence in a structure or a function parameter list is not significant. The union can either precede or follow the discriminant.

The switch_is attribute can appear as a field attribute or as a parameter attribute.

See Also

encapsulated_union, non-encapsulated_union, switch_type, union


switch_type

switch_type(switch-type-specifier)

switch-type-specifier

Specifies an integer, character, boolean, or enum type, or an identifier of such a type.

Examples

typedef [switch_type(short)] union _WILLIE_UNION_TYPE {

    [case(24)]

        float fMays;

    [case(25)]

        double dMcCovey;

    [default]

        ;

} WILLIE_UNION_TYPE;

typedef struct _WINNER_TYPE {

    [switch_is(sUniformNumber)] union WILLIE_UNION_TYPE w;

    short sUniformNumber;

} WINNER_TYPE;

Remarks

The switch_type attribute identifies the type of the variable used as the union discriminant. The switch type can be an integer, character, boolean, or enum type.

The switch_is attribute specifies the name of the parameter that is the union discriminant. The switch_is attribute applies to parameters or members of structures or unions.

The union and its discriminant must be specified at the same logical level. When the union is a parameter, the union discriminant must be another parameter. When the union is a field of a structure, the discriminant must be another field of the structure at the same level as the union field.

See Also

encapsulated_union, IDL, non-encapsulated_union, switch_is, union


transmit_as

typedef [transmit_as(xmit-type) [ , type-attribute-list ] ]
type-specifier declarator-list;

void __RPC_USER type-id_to_xmit (
type-id __RPC_FAR *,
xmit-type __RPC_FAR * __RPC_FAR *);

void __RPC_USER type-id_from_xmit (
xmit-type __RPC_FAR *,
type-id __RPC_FAR *);

void __RPC_USER type-id_free_inst (
type-id __RPC_FAR *);

void __RPC_USER type-id_free_xmit (
xmit-type__RPC_FAR *);

xmit-type

Specifies the data type that is transmitted between client and server.

type-attribute-list

Specifies one or more attributes that apply to the type. Valid type attributes include handle, switch_type; the pointer attribute ref, unique, or ptr; and the usage attributes string and ignore. Separate multiple attributes with commas.

type-specifier

Specifies a base_type, struct, union, enum type, or type identifier. An optional storage specification can precede type-specifier.

declarator-list

Specifies standard C declarators, such as identifiers, pointer declarators, and array declarators. For more information, see pointers and arrays. The declarator-list consists of one or more declarators separated by commas. The parameter declarator in the function declarator, such as the parameter name, is optional.

type-id

Specifies the name of the data type that is presented to the client and server applications.

Examples

typedef struct _TREE_NODE_TYPE {

    unsigned short data;

    struct _TREE_NODE_TYPE * left;

    struct _TREE_NODE_TYPE * right;

} TREE_NODE_TYPE;

typedef [transmit_as(TREE_XMIT_TYPE)] TREE_NODE_TYPE * TREE_TYPE;

void __RPC_USER TREE_TYPE_to_xmit(

TREE_TYPE __RPC_FAR * ,

TREE_XMIT_TYPE __RPC_FAR * __RPC_FAR *);

void __RPC_USER TREE_TYPE_from_xmit (

TREE_XMIT_TYPE __RPC_FAR *,

TREE_TYPE __RPC_FAR *);

void __RPC_USER TREE_TYPE_free_inst(

TREE_TYPE __RPC_FAR *);

void __RPC_USER TREE_TYPE_free_xmit(

TREE_XMIT_TYPE __RPC_FAR *);

Remarks

The transmit_as attribute instructs the compiler to associate type-id, a presented type that client and server applications manipulate, with a transmitted type xmit-type. The user must supply routines that convert data between the presented and the transmitted types; these routines must also free memory used to hold the converted data. The transmit_as attribute instructs the stubs to call the user-supplied conversion routines.

The transmitted type xmit-type must resolve to a MIDL base type, predefined type, or a type identifier. For more information, see base_types.

The user must supply the following routines:

Routine name	Description
type-id_to_xmit	Converts data from the presented type to the transmitted type
type-id_from_xmit	Converts data from the transmitted type to the presented type
type-id_free_inst	Frees storage used by the callee for the presented type
type-id_free_xmit	Frees storage used by the caller for the transmitted type
The client stub calls type-id_to_xmit to allocate space for the transmitted type and to translate the data into objects of type xmit-type. The server stub allocates space for the original data type and calls type-id_from_xmit to translate the data from its transmitted type to the presented type.

Upon return from the application code, the server stub calls type-id_free_inst to deallocate the storage for type-id on the server side. The client stub calls type-id_free_xmit to deallocate the xmit-type storage on the client side.

The following types cannot have a transmit_as attribute:

•	Context handles (types with the context_handle type attribute and types that are used as parameters with the context_handle attribute)

•	Parameters that are conformant, varying, or open arrays

•	Structures that contain conformant arrays

•	The predefined type handle_t, void

When a pointer attribute appears as one of the type attributes with the transmit_as attribute, the pointer attribute is applied to the xmit_type parameter of the type-id-to_xmit and type-id-from_xmit routines.

See Also

arrays, base_types, context_handle, IDL, typedef


typedef

/* IDL file typedef syntax */
typedef [ [ idl-type-attribute-list ] ] type-specifier declarator-list;

/* ACF typedef syntax */
typedef [ acf-type-attribute-list ] typename;

idl-type-attribute-list

Specifies one or more attributes that apply to the type. Valid type attributes in an IDL file include handle, switch_type, transmit_as; the pointer attribute ref, unique, or ptr; and the usage attributes context_handle, string, and ignore. Separate multiple attributes with commas.

type-specifier

Specifies a base_type, struct, union, enum type, or type identifier. An optional storage specification can precede type-specifier. The const keyword can precede type-specifier.

declarator-list

Specifies standard C declarators, such as identifiers, pointer declarators, and array declarators. For more information, see pointers and arrays. The declarator-list consists of one or more declarators, separated by commas.

acf-type-attribute-list

Specifies one or more attributes that apply to the type. Valid type attributes in an ACF include allocate, encode, and decode.

typename

Specifies a type defined in the IDL file.

Remarks

The IDL typedef keyword allows typedef declarations that are very similar to
C-language typedef declarations. The IDL typedef declaration is augmented to allow you to associate type attributes with the defined types. Valid type attributes include handle, switch_type, transmit_as; the pointer attribute ref, unique, or ptr; and the usage attributes context_handle, string, and ignore.

The typedef keyword in an ACF applies attributes to types that are defined in the corresponding IDL file. For example, the allocate type attribute allows you to customize memory allocation and deallocation by both the application and the stubs.

The ACF typedef statement appears as part of the ACF_body. Note that the ACF typedef syntax is different from the IDL typedef syntax and the C-language typedef syntax. No new types can be introduced in the ACF.

See Also

ACF, allocate, decode, encode, IDL


union

The union keyword appears in functions that relate to discriminated unions.

MIDL supports two types of discriminated unions: encapsulated unions and non-encapsulated unions. The encapsulated union is compatible with previous implementations of RPC (NCA version 1). The non-encapsulated union eliminates some of the restrictions of the encapsulated union and provides a more visible discriminant than the encapsulated union.

The encapsulated union is identified by the switch keyword and the absence of other union-related keywords.

The non-encapsulated union, also known as a union, is identified by the presence of the switch_is and switch_type keywords, which identify the discriminant and its type.

When you use in, out unions, be aware that changing the value of the union switch during the call can make the remote call behave differently from a local call. On return, the stubs copy the in, out parameter into memory that is already present on the client. When the remote procedure modifies the value of the union switch and consequently changes the data object's size, the stubs can overwrite valid memory with the out value. When the union switch changes the data object from a base type to a pointer type, the stubs can overwrite valid memory when they copy the pointer referent into the memory location indicated by the in value of a base type.

The shape of unions must be identical across platforms to ensure interconnectivity.

See Also

encapsulated_union, IDL, non-encapsulated_union, switch_is, switch_type


unique

pointer_default(unique)

typedef [ unique [ , type-attribute-list ] ] type-specifier declarator-list;

typedef struct-or-union-declarator {
[ unique [ , field-attribute-list ] ] type-specifier declarator-list;
...}

[ unique [ , function-attribute-list ] ] type-specifier ptr-decl function-name(
[ [ parameter-attribute-list ] ] type-specifier [declarator]
, ...
);
[ [ function-attribute-list ] ] type-specifier [ptr-decl] function-name(
[ unique [ , parameter-attribute-list ] ] type-specifier [declarator]
, ...
);

type-attribute-list

Specifies one or more attributes that apply to the type. Valid type attributes include handle, switch_type, transmit_as; the pointer attribute ref, unique, or ptr; and the usage attributes context_handle, string, and ignore. Separate multiple attributes with commas.

type-specifier

Specifies a base_type, struct, union, enum type, or type identifier. An optional storage specification can precede type-specifier.

declarator and declarator-list

Specifies standard C declarators, such as identifiers, pointer declarators, and array declarators. For more information, see pointers and arrays. The declarator-list consists of one or more declarators separated by commas. The parameter-name identifier in the function declarator is optional.

struct-or-union-declarator

Specifies a MIDL struct or union declarator. field-attribute-list

Specifies zero or more field attributes that apply to the structure member, union member, or function parameter. Valid field attributes include first_is, last_is, length_is, max_is, size_is; the usage attributes string, ignore, and context_handle; the pointer attribute ref, unique, or ptr; and the union attribute switch_type. Separate multiple field attributes with commas.

function-attribute-list

Specifies zero or more attributes that apply to the function. Valid function attributes are callback, local; the pointer attribute ref, unique, or ptr; and the usage attributes string, ignore, and context_handle.

ptr-decl

Specifies at least one pointer declarator to which the unique attribute applies. A pointer declarator is the same as the pointer declarator used in C; it is constructed from the * designator, modifiers such as far, and the qualifier const.

function-name

Specifies the name of the remote procedure.

parameter-attribute-list

Consists of zero or more attributes appropriate for the specified parameter type. Parameter attributes can take the directional attributes in and out; the field attributes first_is, last_is, length_is, max_is, size_is, and switch_type; the pointer attribute ref, unique, or ptr; and the usage attributes context_handle and string. The usage attribute ignore cannot be used as a parameter attribute. Separate multiple attributes with commas.

Example

pointer_default(unique)

typedef [unique, string] unsigned char * MY_STRING_TYPE;

[unique] char * MyFunction([in, out, unique] long * plNumber);

Remarks

The unique attribute specifies a unique pointer.

Pointer attributes can be applied as a type attribute; as a field attribute that applies to a structure member, union member, or parameter; or as a function attribute that applies to the function return type. The pointer attribute can also appear with the pointer_default keyword.

A unique pointer has the following characteristics:

•	Can have the value NULL.

•	Can change during a call from NULL to non-null, from non-null to NULL, or from one non-null value to another.

•	Can allocate new memory on the client. When the unique pointer changes from NULL to non-null, data returned from the server is written into new storage.

•	Can use existing memory on the client without allocating new memory. When a unique pointer changes during a call from one non-null value to another, the pointer is assumed to point to a data object of the same type. Data returned from the server is written into existing storage specified by the value of the unique pointer before the call.

•	Can orphan memory on the client. Memory referenced by a non-null unique pointer may never be freed if the unique pointer changes to NULL during a call and the client does not have another means of dereferencing the storage.

•	Does not cause aliasing. Like storage pointed to by a reference pointer, storage pointed to by a unique pointer cannot be reached from any other name in the function.

The stubs call the user-supplied memory-management functions midl_user_allocate and midl_user_free to allocate and deallocate memory required for unique pointers and their referents.

The following restrictions apply to unique pointers:

•	The unique attribute cannot be applied to binding-handle parameters (handle_t) and context-handle parameters.

•	The unique attribute cannot be applied to out-only top-level pointer parameters (parameters that have only the out directional attribute).

•	Unique pointers cannot be used to describe the size of an array or union arm because unique pointers can have the value NULL. This restriction prevents the error that results if a null value is used as the array size or the union-arm size.

See Also

pointer_default, pointers, ptr, ref


unsigned

The unsigned keyword indicates that the most significant bit of an integer variable represents a data bit rather than a signed bit. This keyword is optional and can be used with any of the character and integer types char, wchar_t, long, short, and small.

When you use the MIDL compiler switch /char, character and integer types that appear in the IDL file without explicit sign keywords can appear with the signed or unsigned keyword in the generated header file. To avoid confusion, explicitly specify the sign of the integer and character types.

See Also

base_types, /char, IDL, int, long, short, signed, small


uuid

uuid (string_uuid)
uuid ("string-uuid")

string-uuid

Specifies a string consisting of eight hexadecimal digits followed by a hyphen, then three groups of four hexadecimal digits each followed by a hyphen, then twelve hexadecimal digits. You can enclose the UUID string in quotes when you use the MIDL compiler switch /ms_ext.

Examples

uuid(6B29FC40-CA47-1067-B31D-00DD010662DA)

uuid("6B29FC40-CA47-1067-B31D-00DD010662DA")

Remarks

The uuid interface attribute designates a universally unique identifier (UUID) that is assigned to the interface and that distinguishes it from other interfaces. The run-time library uses the interface UUID to help establish communication between the client and server applications.The uuid attribute can appear in the interface attribute list for either an RPC interface or an OLE interface.

For an RPC interface, the interface attribute list must include either the uuid attribute or the local attribute, and the one you choose must occur exactly once. If the list includes the uuid attribute, it can also include the version attribute.

For an OLE interface (identified by the object interface attribute), the interface attribute list must include the uuid attribute, but it cannot include the version attribute. The list for an OLE interface can include the local attribute even though the uuid attribute is present.

Microsoft RPC supports an extension to DCE IDL that allows the UUID to be enclosed in double quotation marks. The quoted form is needed for
C-compiler preprocessors that interpret UUID numbers as floating-point numbers.

All UUID values should be computer-generated to guarantee uniqueness. Use the uuidgen utility to generate unique UUID values.

The UUID and version numbers of the interface are used to determine whether the client can bind to the server. For the client to bind to the server, the UUID specified in the client and server interfaces must be the same.

Note that an interface without attributes can be imported into a base IDL file. However, the interface must contain only datatypes with no procedures. If even one procedure is contained in the interface, a local or UUID attribute must be specified.

See Also

IDL, interface, local, /ms_ext, version


v1_enum

[v1_enum] enum {...}

Example

typedef [v1_enum] enum {label1, label2, ...};

Remarks

The keyword v1_enum is used to specify enumerations to be transmitted as a 32-bit entity.

Enumeration types are transmitted as 16-bits by default. When applied to an enumerator, the v1_enum attribute ensures that the enumerator is transmitted as 32-bit, rather than 16-bit.

Note that the use of the v1_enum attribute is recommended for enumerators on 32-bit systems. This increases the efficiency of marshalling and unmarshalling data when such an enumerator is embedded in structures or unions.

See Also

enum, IDL


version

version ( major-value[. minor-value] )

major-value

Specifies a short unsigned integer between 0 and 65,535, inclusive, that represents the major version number.

minor-value

Specifies a short unsigned integer between 0 and 65,535, inclusive, that represents the minor version number. The minor version value is optional. If present, the minor version value is separated from the major version number by a period character (.). If not specified, the minor version value is zero.

Remarks

The version interface attribute identifies a particular version among multiple versions of an RPC interface. With the version attribute, you ensure that only compatible versions of client and server software are allowed to bind.

The MIDL compiler does not support multiple versions of an OLE interface. As a result, an interface attribute list that includes the object attribute cannot include the version attribute. To create a new version of an existing OLE interface, use interface inheritance. A derived OLE interface has a different UUID but inherits the interface member functions, status codes, and interface attributes of the base interface.

In combination with the uuid value, the version value uniquely identifies the interface. The run-time library passes the version and uuid values to the server when the client calls a remote function. A client can bind to a server for a given interface if:

•	The uuid value is the same.

•	The major version number is the same.

•	The client's minor version number is less than or equal to the server's minor version number.

It is to your benefit and your users' benefit to retain upward compatibility among versions — that is, to modify the interface so that only the minor version number changes. You can retain upward compatibility when you add new data types that are not used by existing functions and when you add new functions without changing the interface specification for existing functions.

Change the major version number if any one of the following conditions apply:

•	If you change a data type that is used by an existing function.

•	If you change the interface specification for an existing function (such as adding or removing a parameter).

•	If you add callbacks that are called by existing functions.

Change the minor version number if all of the following conditions apply:

•	If you add type definitions or constants that are not used by any existing functions or callbacks.

•	If you do not change any existing functions and you add new functions to the interface.

•	If you add callbacks that are not called by any existing functions and the new callbacks follow any existing functions.

If your modifications qualify as an upward-compatible change to the interface, use the following procedure to modify the interface (IDL) file:

1.	Add new constant and type definitions to the interface file.

2.	Add callback functions to the end of the interface file.

3.	Add new functions to the end of the interface file.

The version attribute can occur at most once in the interface header.

When the version attribute is not present, the interface has a default version of 0.0.

The period character between the major and minor numbers is a delimiter and does not represent a decimal point. The minor number is treated as an integer. Leading zeroes are not significant. Trailing zeroes are significant.

For example, the version setting 1.11 represents a major value of one and a minor value of eleven. Version 1.11 does not represent a value between 1.1 and 1.2.

See Also

IDL, interface, uuid


void

void function (parameter-list);
return-type function(void);
typedef [context_handle] void * context-handle-type;
return-type function (...[context_handle] void * * context-handle-type...);

function

Specifies the name of the remote procedure.

parameter-list

Specifies the list of parameters passed to the function along with the associated parameter types and parameter attributes.

return-type

Specifies the name of the type returned by the function.

context-handle-type

Specifies the name of the type that takes the context_handle attribute.

Examples

void VoidFunc1(void);

void VoidFunc2([in, out] short s1);

typedef [context_handle] void * MY_CX_HNDL_TYPE;

void InitHandle([out] MY_CX_HNDL_TYPE * ppCxHndl);

Remarks

The base type void indicates a procedure with no arguments or a procedure that does not return a result value.

The pointer type void *, which in C describes a generic pointer that can be cast to represent any pointer type, is limited in MIDL to its use with the context_handle keyword.

See Also

base_types, context_handle, IDL


wchar_t

The wchar_t keyword designates a wide-character type. The wchar_t type is defined by MIDL as an unsigned short (16-bit) data object.

The MIDL compiler allows redefinition of wchar_t, but only if it is consistent with the preceding definition.

The wide-character type is one of the predefined types of MIDL. The wide-character type can appear as a type specifier in const declarations, typedef declarations, general declarations, and function declarators (as a function-return-type specifier and as a parameter-type specifier). For the context in which type specifiers appear, see IDL.

The string attribute can be applied to a pointer or array of type wchar_t.

Use the L character before a character or a string constant to designate the wide-character-type constant.

See Also

base_types, char, IDL


RPC Data Types and Structures

This section defines the following constants, data types, and data structures used by the Microsoft RPC run-time functions:

Data type/structure	Description
RPC_C_AUTHN_LEVEL*	Authentication-level constants
RPC_C_AUTHN*	Authentication-service constants
RPC_C_AUTHZ*	Authorization-service constants
GUID	Globally unique identifier (UUID)
PROTSEQ	Protocol sequence string
RPC_AUTH_IDENTITY_HANDLE	Authorization-identity handle
RPC_AUTH_KEY_RETRIEVAL_FN	Authorization-key retrieval function
RPC_AUTHZ_HANDLE	Authorization handle
RPC_BINDING_HANDLE	Binding handle
RPC_BINDING_VECTOR	Count and array of binding handles
RPC_IF_HANDLE	Interface handle
RPC_IF_ID	Interface identifier
RPC_IF_ID_VECTOR	Count and array of interface identifiers
RPC_MGR_EPV	Manager entry-point vector
RPC_NS_HANDLE	Name-service handle
RPC_OBJECT_INQ_FN	Object-inquiry function
RPC_PROTSEQ_VECTOR	Count and array of protocol sequences
RPC_STATS_VECTOR	Statistics vector
RPC_STATUS	Status
SEC_WINNT_AUTH_IDENTITY	Authentication
String binding	String representation of a binding
String UUID	Unique identifier string
UUID	Universally unique identifier
UUID_VECTOR	Count and array of unique identifiers


Authentication-Level Constants

The AuthnLevel argument represents the authentication level supplied to the RpcBindingInqAuthInfo and RpcBindingSetAuthInfo run-time functions.

The levels are listed in order of increasing authentication. Each new level adds to the authentication provided by the previous level. If the RPC run-time library does not support the specified level, it automatically upgrades to the next higher supported level.

The following constants represent valid values for the AuthnLevel argument:

Constant	Description
RPC_C_AUTHN_LEVEL_DEFAULT	Uses the default authentication level for the specified authentication service.
RPC_C_AUTHN_LEVEL_NONE	Performs no authentication.
RPC_C_AUTHN_LEVEL_CONNECT	Authenticates only when the client establishes a relationship with a server.
RPC_C_AUTHN_LEVEL_CALL	Authenticates only at the beginning of each remote procedure call when the server receives the request. Does not apply to remote procedure calls made using the connection-based protocol sequences (those that start with the prefix "ncacn"). If the protocol sequence in a binding handle is a connection-based protocol sequence and you specify this level, this routine instead uses the RPC_C_AUTHN_LEVEL_PKT constant.
RPC_C_AUTHN_LEVEL_PKT	Authenticates that all data received is from the expected client.
RPC_C_AUTHN_LEVEL_PKT _INTEGRITY	Authenticates and verifies that none of the data transferred between client and server has been modified.
RPC_C_AUTHN_LEVEL_PKT_PRIVACY	Authenticates all previous levels and encrypts the argument value of each remote procedure call.
Note  For Windows 95 platforms, RPC_C_AUTHN_LEVEL_CALL, RPC_C_AUTHN_LEVEL_PKT, RPC_C_AUTHN_LEVEL_PKT_INTEGRITY, and RPC_C_AUTHN_LEVEL_PKT_PRIVACY are only supported for a Windows 95 client communicating with a Windows NT server. These levels are never supported for a Windows 95 client communicating with a Windows 95 server.

See Also

RpcBindingInqAuthInfo, RpcBindingSetAuthInfo


Authentication-Service Constants

The AuthnSvc argument represents the authentication service supplied to the RpcBindingInqAuthInfo and RpcBindingSetAuthInfo run-time functions.

The following constants represent valid values for the AuthnSvc argument:

Constant	Value	Service
RPC_C_AUTHN_DCE_PRIVATE	1	DCE private key authentication
RPC_C_AUTHN_DCE_PUBLIC	2	DCE public key authentication  (reserved for future use)
RPC_C_AUTHN_DEC_PUBLIC	4	DEC public key authentication  (reserved for future use)
RPC_C_AUTHN_DEFAULT	0xffffffff	Default authentication service
RPC_C_AUTHN_NONE	0	No authentication
RPC_C_AUTHN_WINNT	10	NT LM SSP (NT Security Service)
Specify RPC_C_AUTHN_NONE to turn off authentication for remote procedure calls made using the binding handle.

When you specify RPC_C_AUTHN_DEFAULT, the RPC run-time library uses the RPC_C_AUTHN_DCE_PRIVATE authentication service for remote procedure calls made using the binding handle.

See Also

RpcBindingInqAuthInfo, RpcBindingSetAuthInfo


Authorization-Service Constants

The AuthzSvc argument represents the authorization service supplied to the RpcBindingInqAuthInfo and RpcBindingSetAuthInfo run-time functions.

The following constants represent valid values for the AuthzSvc argument:

Constant	Value	Service
RPC_C_AUTHZ_NONE	0	Server performs no authorization.
RPC_C_AUTHZ_NAME	1	Server performs authorization based on the client's principal name.
RPC_C_AUTHZ_DCE	2	Server performs authorization checking using the client's DCE privilege attribute certificate (PAC) information, which is sent to the server with each remote procedure call made using the binding handle. Generally, access is checked against DCE access control lists (ACLs).
See Also

RpcBindingInqAuthInfo, RpcBindingSetAuthInfo


GUID

typedef struct _GUID {
    unsigned long Data1;
    unsigned short Data2;
    unsigned short Data3;
    unsigned char Data4[8];
} GUID;

typedef GUID UUID;

Data1

Specifies the first eight hexadecimal digits of the UUID.

Data2

Specifies the first group of four hexadecimal digits of the UUID.

Data3

Specifies the second group of four hexadecimal digits of the UUID.

Data4

Specifies an array of eight elements that contains the third and final group of eight hexadecimal digits of the UUID in elements 0 and 1, and the final 12 hexadecimal digits of the UUID in elements 2 through 7.

Remarks

GUIDs are globally unique identifiers and are a Microsoft implementation of the DCE UUID.

UUIDs uniquely identify objects, such as interfaces, manager entry-point vectors, and client objects. The RPC run-time libraries use UUIDs to check for compatibility between clients and servers and to select among multiple implementations of an interface.

See Also

UUID, UUID_VECTOR


PROTSEQ

unsigned char *  Protseq[1];

Protseq

Points to a character string identifying the network protocol used to communicate between client and server.

Remarks

A protocol sequence is a character string identifying the network protocols used to establish a relationship between a client and server. The protocol sequence contains a set of options that must be defined to the RPC run-time library. There are three options in this set:

•	The RPC protocol used for communications. (Available options are ncacn and ncadg.)

•	The format used in the network address supplied in the binding. (Available options are ip, dnet, and osi.)

•	The transport protocol used for communications. (Available options are tcp, udp, nsp, dna, np, and nb.)

The following predefined strings represent valid combinations:

Protocol sequence	Description
ncacn_ip_tcp	NCA connection over TCP/IP (transmission control protocol/internet protocol)
ncacn_nb_nb	NCA connection over NetBEUI over NetBIOS
ncacn_nb_tcp	NCA connection over TCP/IP over NetBIOS
ncacn_np	NCA connection over named pipes
ncacn_spx	Connection-oriented SPX
ncadg_ip_udp	Datagram-oriented TCP/IP
ncadg_ipx	Datagram-oriented IPX
ncalrpc	Local procedure call
Note  Windows 95 does not support ncalrpc, ncacn_nb_ipx, and ncacn_nb_tcp.  The ncacn_np protocol is supported only on the client side.  You must have an authentic Novell client to use the RPC SPX transport.

A server application can use a particular protocol sequence only when the RPC run-time library and operating-system software support that protocol. A server chooses to accept remote procedure calls over some or all of the supported protocol sequences.

Several server routines allow server applications to register protocol sequences with the run-time library. Microsoft RPC functions that require a protocol-sequence argument use the data type unsigned char.

A client can use the protocol-sequence strings to construct a string binding using the RpcStringBindingCompose routine.

Note  The ncalrpc protocol sequence is supported only for Windows NT applications.

The ncacn_dnet_nsp protocol sequence is supported only for MS-DOS, Microsoft Windows 3.x, and Microsoft Windows for Workgroups 3.1 client applications. This release of Microsoft RPC does not include support for the ncacn_dnet_nsp protocol sequence with Microsoft Windows NT client or server applications.

See Also

RpcServerUseAllProtseqs, RpcServerUseAllProtseqsIf, RpcServerUseProtseq, RpcServerUseProtseqEp, RpcServerUseProtseqIf, RpcStringBindingCompose


RPC_AUTH_IDENTITY_HANDLE

typedef void *  RPC_AUTH_IDENTITY_HANDLE;

Remarks

An identity handle points to the data structure that contains the client's authentication and authorization credentials specified for remote procedure calls.

See Also

RpcBindingInqAuthInfo, RpcBindingSetAuthInfo


RPC_AUTH_KEY_RETRIEVAL_FN

typedef void (* RPC_AUTH_KEY_RETRIEVAL_FN) (
void *  Arg,
unsigned short *  	ServerPrincName,
unsigned long  KeyVer,
void * *  	Key,
RPC_STATUS *  	Status
);

Arg

Points to a user-defined argument to the user-supplied encryption key acquisition function. The RPC run-time library uses the Arg argument supplied to RpcServerRegisterAuthInfo.

ServerPrincName

Points to the principal name to use for the server when authenticating remote procedure calls. The RPC run-time library uses the ServerPrincName argument supplied to RpcServerRegisterAuthInfo.

KeyVer

Specifies the value that the RPC run-time library automatically provides for the key-version argument. When the value is 0, the acquisition function must return the most recent key available.

Key

Points to a pointer to the authentication key returned by the user-supplied function.

Status

Points to the status returned by the acquisition function when it is called by the RPC run-time library to authenticate the client RPC request. If the status is other than RPC_S_OK, the request fails and the run-time library returns the error status to the client application.

Remarks

An authorization key retrieval function specifies the address of a server-application-provided routine returning encryption keys.

See Also

RpcServerRegisterAuthInfo


RPC_AUTHZ_HANDLE

typedef void *  RPC_AUTHZ_HANDLE;

Remarks

An authorization handle points to the privileges information for the client application that made the remote procedure call.

See Also

RpcBindingInqAuthClient


RPC_BINDING_HANDLE

typedef RPC_BINDING_HANDLE handle_t;

Remarks

A binding handle is a pointer-sized opaque variable containing information that the RPC run-time library uses to access binding information. The run-time library uses binding information to establish a client-server relationship that allows the execution of remote procedure calls.

Based on the context in which a binding handle is created, the binding handle is considered a server binding handle or a client binding handle.

A server binding handle contains the information necessary for a client to establish a relationship with a specific server. Any number of RPC API run-time routines return a server binding handle that can be used for making a remote procedure call.

A client binding handle cannot be used to make a remote procedure call. The RPC run-time library creates and provides a client binding handle to a called server procedure (also called a server manager routine) as the RPC_BINDING_HANDLE parameter. The client binding handle contains information about the calling client.

The RpcBinding* and RpcNsBinding* routines return the status code RPC_S_WRONG_KIND_OF_BINDING when an application provides the incorrect binding-handle type.

An application can share a single binding handle across multiple threads of execution. The RPC run-time library manages concurrent remote procedure calls that use a single binding handle. However, the application is responsible for binding-handle concurrency control for operations that modify a binding handle. These operations include the following routines:

•	RpcBindingFree

•	RpcBindingReset

•	RpcBindingSetAuthInfo

•	RpcBindingSetObject

For example, if an application shares a binding handle across two threads of execution and resets the binding-handle endpoint in one of the threads by calling RpcBindingReset, the binding handle in the other thread is also reset. Similarly, freeing the binding handle in one thread by calling RpcBindingFree frees the binding handle in the other thread.

If you don't want concurrency, you can design an application to create a copy of a binding handle by calling RpcBindingCopy. In this case, an operation to the first binding handle has no effect on the second binding handle.

Routines requiring a binding handle as an argument show a data type of RPC_BINDING_HANDLE. Binding-handle arguments are passed by value.


Binding-Handle Use by Function

The following table contains the list of RPC run-time routines that operate on binding handles and specifies the type of binding handle allowed:

Routine	Input argument	Output argument
RpcBindingCopy	Server	Server
RpcBindingFree	Server	None
RpcBindingFromStringBinding	None	Server
RpcBindingInqAuthClient	Client	None
RpcBindingInqAuthInfo	Server	None
RpcBindingInqObject	Server or client	None
RpcBindingReset	Server	None
RpcBindingSetAuthInfo	Server	None
RpcBindingSetObject	Server	None
RpcBindingToStringBinding	Server or client	None
RpcBindingVectorFree	Server	None
RpcNsBindingExport	Server	None
RpcNsBindingImportNext	None	Server
RpcNsBindingLookupNext	None	Server
RpcNsBindingSelect	Server	Server
RpcServerInqBindings	None	Server


RPC_BINDING_VECTOR

#define rpc_binding_vector_t RPC_BINDING_VECTOR

typedef struct _RPC_BINDING_VECTOR {
unsigned long  	Count;
RPC_BINDING_HANDLE  BindingH[1];
}	RPC_BINDING_VECTOR;

Count

Specifies the number of binding handles present in the binding-handle array BindingH.

BindingH

Specifies an array of binding handles that contains Count elements.

Remarks

The binding-vector data structure contains a list of binding handles over which a server application can receive remote procedure calls.

The binding vector contains a count member (Count), followed by an array of binding-handle (BindingH) elements.

The RPC run-time library creates binding handles when a server application registers protocol sequences. To obtain a binding vector, a server application calls the RpcServerInqBindings routine.

A client application obtains a binding vector of compatible servers from the name-service database by calling the RpcNsBindingLookupNext routine.

In both routines, the RPC run-time library allocates memory for the binding vector. An application calls the RpcBindingVectorFree routine to free the binding vector.

To remove an individual binding handle from the vector, the application must set the value in the vector to NULL. When setting a vector element to NULL, the application must:

•	Free the individual binding

•	Not change the value of Count

Calling the RpcBindingFree routine allows an application to both free the unwanted binding handle and set the vector entry to a NULL value.

See Also

RpcBindingVectorFree, RpcEpRegister, RpcEpRegisterNoReplace, RpcEpUnregister, RpcNsBindingExport, RpcNsBindingLookupNext, RpcNsBindingSelect, RpcServerInqBindings


RPC_CLIENT_INTERFACE

Remarks

The RPC_CLIENT_INTERFACE data structure is part of the private interface between the run-time libraries and the stubs. Most distributed applications that use Microsoft RPC do not need this data structure.

The data structure is defined in the header file RPCDCEP.H.


RPC_DISPATCH_TABLE

Remarks

The RPC_DISPATCH_TABLE data structure is part of the private interface between the run-time libraries and the stubs. Most distributed applications that use Microsoft RPC do not need this data structure.

The data structure is defined in the header file RPCDCEP.H.


RPC_IF_HANDLE

typedef void *  RPC_IF_HANDLE;

Remarks

An interface handle is an opaque variable containing information the RPC run-time library uses to access the interface-specification data structure.

The MIDL compiler automatically creates an interface-specification data structure from each IDL file and creates a global variable of type RPC_IF_HANDLE for the interface specification.

The MIDL compiler includes an interface handle in each .H file generated for the interface.

Routines requiring the interface specification as an argument show a data type of RPC_IF_HANDLE.

The form of each interface handle name is as follows:

•	if-name_ClientIfHandle (for the client)

•	if-name_ServerIfHandle (for the server)

if-name

Specifies the interface identifier in the IDL file.

For example:

hello_ClientIfHandle

hello_ServerIfHandle

Note  	The maximum length of the interface handle name is 31 characters.

Because the _ClientIfHandle and _ServerIfHandle parts of the names require 15 characters, the if-name element can be no more than 16 characters long.


RPC_IF_ID

typedef struct _RPC_IF_ID {
UUID  Uuid;
unsigned short  VersMajor;
unsigned short  VersMinor;
}	RPC_IF_ID;

Uuid

Specifies the interface UUID.

VersMajor

Specifies the major version number, an integer from 0 to 65535, inclusive.

VersMinor

Specifies the minor version number, an integer from 0 to 65535, inclusive.

Remarks

The interface-identification (ID) data structure contains the interface UUID and major and minor version numbers of an interface. The interface identification is a subset of the data contained in the interface-specification structure.

Routines that require an interface ID structure show a data type of RPC_IF_ID. In those routines, the application is responsible for providing memory for the structure.

See Also

RpcIfInqId


RPC_IF_ID_VECTOR

typedef struct _RPC_IF_ID_VECTOR {
unsigned long  Count;
RPC_IF_ID *  IfHandl[1];
}	RPC_IF_ID_VECTOR;

Count

Specifies the number of interface-identification data structures present in the array IfHandl.

IfHandl

Specifies an array of pointers to interface-identification data structures that contains Count elements.

Remarks

The interface-identification (ID) vector data structure contains a list of interfaces offered by a server. The interface ID vector contains a count member (Count), followed by an array of pointers to interface IDs (RPC_IF_ID).

The interface ID vector is a read-only vector. To obtain a vector of the interface IDs registered by a server with the run-time library, an application calls the RpcMgmtInqIfIds routine. To obtain a vector of the interface IDs exported by a server, an application calls the RpcNsMgmtEntryInqIfIds routine.

The RPC run-time library allocates memory for the interface ID vector. The application calls the RpcIfIdVectorFree routine to free the interface ID vector.

See Also

RpcIfIdVectorFree, RpcMgmtInqIfIds, RpcNsMgmtEntryInqIfIds


RPC_MGR_EPV

typedef void RPC_MGR_EPV;

typedef _if-name_SERVER_EPV {
return-type (* Functionname) (param-list);
...	// one entry for each function in IDL file
}	if-name_SERVER_EPV;

if-name

Specifies the name of the interface indicated in the IDL file.

return-type

Specifies the type returned by the function Functionname indicated in the IDL file.

Functionname

Specifies the name of the function indicated in the IDL file.

param-list

Specifies the arguments indicated for the function Functionname in the IDL file.

Remarks

The manager entry-point vector (EPV) is an array of function pointers. The array contains pointers to the implementations of the functions specified in the IDL file. The number of elements in the array is set to the number of functions specified in the IDL file. An application can also have multiple EPVs, representing multiple implementations of the functions specified in the interface.

The MIDL compiler generates a default EPV data type named if-name_SERVER_EPV, where if-name specifies the interface identifier in the IDL file. The MIDL compiler initializes this default EPV to contain function pointers for each of the procedures specified in the IDL file.

When the server offers multiple implementations of the same interface, the server application must declare and initialize one variable of type if-name_SERVER_EPV for each implementation of the interface. Each EPV must contain one entry point (function pointer) for each procedure defined in the IDL file.

See Also

RpcServerRegisterIf


RPC_NS_HANDLE

typedef void * RPC_NS_HANDLE;

Remarks

A name-service handle is an opaque variable containing information the RPC run-time library uses to return the following RPC data from the name-service database:

•	Server binding handles

•	UUIDs of resources offered by server profile members

•	Group members

The scope of a name-service handle is from a Begin routine through the corresponding Done routine.

Applications are responsible for concurrency control of name-service handles across threads.

See Also

RpcNsBindingImportBegin, RpcNsBindingImportDone, RpcNsBindingImportNext, RpcNsBindingLookupBegin, RpcNsBindingLookupDone, RpcNsBindingLookupNext


RPC_OBJECT_INQ_FN

typedef void RPC_OBJECT_INQ_FN(
UUID *  ObjectUuid,
UUID *  TypeUuid,
RPC_STATUS *  Status);

ObjectUuid

Points to the variable that specifies the object UUID that is to be mapped to a type UUID.

TypeUuid

Points to the address of the variable that is to contain the type UUID derived from the object UUID. The type UUID is returned by the function.

Status

Points to a return value for the function.

Remarks

The developer can replace the default mapping function that maps object UUIDs to type UUIDs by calling RpcObjectSetInqFn and supplying a pointer to a function of type RPC_OBJECT_INQ_FN. The supplied function must match the function prototype specified by the type definition: a function with three parameters and the function return value of void.

See Also

RpcObjectSetInqFn


RPC_PROTSEQ_VECTOR

typedef struct _RPC_PROTSEQ_VECTOR {
unsigned long  Count;
unsigned char *  Protseq[1];
}	RPC_PROTSEQ_VECTOR;

Count

Specifies the number of protocol-sequence strings present in the array Protseq.

Protseq

Specifies an array of pointers to protocol-sequence strings. The number of pointers present is specified by the Count field.

Remarks

The protocol-sequence vector data structure contains a list of protocol sequences the RPC run-time library uses to send and receive remote procedure calls. The protocol-sequence vector contains a count member (Count), followed by an array of pointers to protocol-sequence strings (Protseq).

The protocol-sequence vector is a read-only vector. To obtain a protocol-sequence vector, a server application calls the RpcNetworkInqProtseqs routine. The RPC run-time library allocates memory for the protocol-sequence vector. The server application calls the RpcProtseqVectorFree routine to free the protocol-sequence vector.


RPC_STATS_VECTOR

typedef struct {
unsigned int	  Count;
unsigned long  Stats[1];
}	RPC_STATS_VECTOR;

Count

Specifies the number of statistics values present in the array Stats.

Stats

Specifies an array of unsigned long integers representing server statistics that contains Count elements.

Remarks

The statistics vector contains statistics from the RPC run-time library on a per-server basis. The statistics vector contains a count member (Count), followed by an array of statistics. Each array element contains an unsigned long value. The following list describes the statistics indexed by the specified constant:

Constant	Statistics
RPC_C_STATS_CALLS_IN	The number of remote procedure calls received by the server
RPC_C_STATS_CALLS_OUT	The number of remote procedure calls initiated by the server
RPC_C_STATS_PKTS_IN	The number of network packets received by the server
RPC_C_STATS_PKTS_OUT	The number of network packets sent by the server
To obtain run-time statistics, an application calls the RpcMgmtInqStats routine. The RPC run-time library allocates memory for the statistics vector. The application calls the RpcMgmtStatsVectorFree routine to free the statistics vector.


RPC_STATUS

typedef long RPC_STATUS;  // Win32 definition
typedef unsigned short RPC_STATUS;  // MS-DOS, Win16 definition

Remarks

The type RPC_STATUS represents a platform-specific status code type. The RPC_STATUS type is returned by most RPC functions and is part of the RPC_OBJECT_INQ_FN function type definition.


SEC_WINNT_AUTH_IDENTITY

For Windows 3.x and MS-DOS:

typedef struct _SEC_WINNT_AUTH_IDENTITY

char	__RPC_FAR	*	User;

char	__RPC_FAR 	*	Domain;

char	__RPC_FAR	*	Password;

SEC_WINNT_AUTH_IDENTITY

For Windows NT:

typedef struct _SEC_WINNT_AUTH_IDENTITY

unsigned short	__RPC_FAR	*	User;

unsigned long	__Userlength;

unsigned short	__RPC_FAR	*	Domain;

unsigned long	Domian Length;

unsigned short	__RPC_FAR	*	Password;

unsigned long	Password length;

SEC_WINNT_AUTH_IDENTITY,	*

PSEL_WINNT_AUTH_IDENTITY;

User

String containing the user name.

Domain

String containing the domain name or the workgroup name.

Password

String containing the user's password in the domain or workgroup.

Remarks

The SEC_WINNT_AUTH_IDENTITY structure allows you to pass a particular user name and password to the runtime library for the purpose of authentication.

For Windows 3.x and MS-DOS, the strings are ANSI; for Windows NT, the strings are Unicode. For Windows NT, the values for Userlength; DomainLength, and Password Length are the length of the corresponding string without the terminating 0X0000.


String Binding

ObjectUUID@ProtocolSequence:NetworkAddress[Endpoint,Option]

ObjectUUID

Specifies the UUID of the object operated on by the remote procedure call. At the server, the RPC run-time library maps the object type to a manager entry-point vector (an array of function pointers) to invoke the correct manager routine. For a discussion of mapping object UUIDs to manager entry-point vectors, see RpcServerRegisterIf..

ProtocolSequence

Specifies the protocol sequence for making remote procedure calls. The following protocol sequences are supported by Microsoft RPC:

•	ncacn_ip_tcp

•	ncacn_np

•	ncacn_nb_nb, ncacn_nb_tcp

•	ncacn_spx

•	ncalrpc

•	ncadg_ip_udp

•	ncadg_ipx

Note  	Windows 95 does not support ncalrpc, ncacn_nb_ipx, and ncacn_nb_tcp.  The ncacn_np protocol is supported only on the client side. The ncacn_dnet_nsp protocol sequence is supported only for MS-DOS, Microsoft Windows 3.x, and Microsoft Windows for Workgroups 3.1 client applications. This release of Microsoft RPC does not include support for the ncacn_dnet_nsp protocol sequence with Microsoft Windows NT client or server applications.

NetworkAddress

Specifies the network address of the system to receive remote procedure calls. The format and content of the network address depend on the specified protocol sequence as follows:

Protocol sequence	Network address	Example
ncacn_dnet_nsp	Area and node syntax	4.120
ncacn_ip_tcp	Common internet address notation	128.10.2.30
ncacn_ip_tcp	Host name	ko
ncacn_nb_nb, ncacn_nb_tcp	Windows NT server name	marketing
ncacn_np	Windows NT server name	\\marketing
ncacn_spx	Network number and node number	~0000000108002B30612C
ncadg_ip_udp	Host name	ko or 11.101.9.127
ncadg_ipx	Network number and node number	~0000000108002B30612C
ncalrpc	None
The network-address field is optional. When you do not specify a network address, the string binding refers to your local host. No network address should be specified when you use the ncalrpc protocol sequence.

When the specified host name is multi-homed, the function RpcBindingFromStringBinding returns a binding handle for the first host address it finds. To specify the host address, use the common internet address notation, an area node syntax, or an NSP instead of a host name.

The string representing the NSP is a percent sign followed by the letter X followed by hexadecimal digits. No separators are allowed. Because the NSP specifies the transport to be used as part of its value, any transport options in the string binding are ignored.

Endpoint

Specifies the endpoint, or address, of the process to receive remote procedure calls. An endpoint can be preceded by the keyword endpoint=. The endpoint field is optional.

The format and content of an endpoint depend on the specified protocol sequence as follows:

Protocol sequence	Endpoint	Example
ncacn_dnet_nsp	DECnet phase IV object number (must be preceded by the # character)	#17
ncacn_ip_tcp	Internet port number	1025
ncacn_nb_nb, ncacn_nb_tcp	Integer between 0 and 255. Many values between 0 and 32 are reserved by Microsoft.	100
ncacn_np	Windows NT named pipe. Name must start with "\\pipe".	\\pipe\\pipename
ncacn_spx	Integer between 1 and 65535.	5000
ncadg_ip_udp	Internet port number	1025
ncadg_ipx	Integer between 1 and 65535	5000
ncalrpc	String specifying Windows NT object name. The string cannot include any backslash characters.	my_object
Option

Specifies options associated with Endpoint. The option field is not required. Each option is specified by a {name, value} pair that uses the syntax option name=option value. Options are defined for each protocol sequence as follows:

Protocol sequence	Option name
ncacn_ip_tcp	None
ncacn_nb_nb, ncacn_nb_tcp	None
ncacn_np	Security
ncacn_spx	None
ncadg_ip_udp	None
ncadg_ipx	None
ncalrpc	Security
The Security option name, supported for the ncalrpc and ncacn_np protocol sequences, takes the following option values:

Option name	Option value
Security	{identification | anonymous | impersonation} {dynamic | static} {true | false}
If the Security option name is specified, one entry from each of the sets of Security option values must also be supplied. The option values must be separated by a single-space character. For example, the following Option fields are valid:

Security=identification dynamic true

Security=impersonation static true

The Security option values have the following meanings:

Security option value	Description
Anonymous	The client is anonymous to the server.
Dynamic	A pointer to the security token is maintained. Security settings represent current settings and include changes made after the endpoint was created.
False	Effective = FALSE; all Windows NT security settings, including those set to OFF, are included in the token.
Identification	The server has information about client but cannot impersonate.
Impersonation	The server is the client on the client's behalf.
Static	Security settings associated with the endpoint represent a copy of the security information at the time the endpoint was created. The settings do not change.
True	Effective = TRUE; only Windows NT security settings set to ON are included in the token.
For more information about Microsoft Windows NT security options, see your Microsoft Windows NT programming documentation.

Remarks

The string binding is an unsigned character string composed of strings that represent the binding object UUID, the RPC protocol sequence, the network address, and the endpoint and endpoint options. White space is not allowed in string bindings except where required by the Option syntax.

Default settings for the NetworkAddress, Endpoint, and Option fields vary according to the value of the ProtocolSequence field.

For all string-binding fields, a single backslash character (\) is interpreted as an escape character. To specify a single literal backslash character, you must supply two backslash characters (\\).

The following are examples of valid string bindings. In these examples, obj-uuid is used for convenience to represent a valid UUID in string form. Instead of showing the UUID 308FB580-1EB2-11CA-923B-08002B1075A7, the examples show obj-uuid.

obj-uuid@ncacn_dnet_nsp:took[elf_server]

obj-uuid@ncacn_dnet_nsp:took[endpoint=elf_server]

obj-uuid@ncacn_ip_tcp:16.20.16.27[2001]

obj-uuid@ncacn_ip_tcp:16.20.16.27[endpoint=2001]

obj-uuid@ncacn_nb_nb:

obj-uuid@ncacn_nb_nb:[100]

obj-uuid@ncacn_np:

obj-uuid@ncacn_np:[\\pipe\\p3,Security=impersonation static true]

obj-uuid@ncacn_np:\\\\marketing[\\pipe\\p2\\p3\\p4]

obj-uuid@ncacn_np:\\\\marketing[endpoint=\\pipe\\p2\\p3\\p4]

obj-uuid@ncacn_np:\\\\sales

obj-uuid@ncacn_np:\\\\sales[\\pipe\\p1,Security=anonymous dynamic true]

obj-uuid@ncalrpc:

obj-uuid@ncalrpc:[object1_name_demonstrating_that_these_can_be_lengthy]

obj-uuid@ncalrpc:[object2_name,Security=anonymous dynamic true]

A string binding contains the character representation of a binding handle and sometimes portions of a binding handle. String bindings are convenient for representing portions of a binding handle, but they can't be used for making remote procedure calls. They must first be converted to a binding handle by calling the RpcBindingFromStringBinding routine.

Additionally, a string binding does not contain all of the information from a binding handle. For example, the authentication information, if any, associated with a binding handle is not translated into the string binding returned by calling the RpcBindingToStringBinding routine.

During the development of a distributed application, servers can communicate their binding information to clients using string bindings to establish a client-server relationship without using the endpoint-map database or name-service database. To establish such a relationship, use the function RpcBindingToStringBinding to convert one or more binding handles from a binding-handle vector to a string binding and provide (via mail, on paper, or some other means) the string binding to the client.

See Also

RpcBindingFromStringBinding, RpcBindingToStringBinding


String UUID

A string UUID contains the character-array representation of a UUID. A string UUID is composed of multiple fields of hexadecimal characters. Each field has a fixed length, and fields are separated by the hyphen character. For example:

989C6E5C-2CC1-11CA-A044-08002B1BB4F5

When providing a string UUID as an input argument to a RPC run-time routine, enter the alphabetic hexadecimal characters as either uppercase or lowercase characters. However, when a run-time routine returns a string UUID, the hexadecimal characters are always lowercase.

See Also

UUID


UUID

typedef struct _GUID {
unsigned long Data1;
unsigned short Data2;
unsigned short Data3;
unsigned char Data4[8];
} GUID;

typedef GUID UUID;

#define uuid_t UUID

Data1

Specifies the first eight hexadecimal digits of the UUID.

Data2

Specifies the first group of four hexadecimal digits of the UUID.

Data3

Specifies the second group of four hexadecimal digits of the UUID.

Data4

Specifies an array of eight elements that contains the third and final group of four hexadecimal digits of the UUID in elements 0 and 1, and the final 12 hexadecimal digits of the UUID in elements 2 through 7.

Remarks

UUIDs uniquely identify objects such as interfaces, manager entry-point vectors, and client objects. The RPC run-time libraries use UUIDs to check for compatibility between clients and servers and to select among multiple implementations of an interface.

See Also

GUID, UUID_VECTOR


UUID_VECTOR

typedef struct _UUID_VECTOR {
unsigned long  Count;
UUID *  Uuid[1];
}	UUID_VECTOR;

Count

Specifies the number of UUIDs present in the array Uuid.

Uuid

Specifies an array of pointers to UUIDs that contains Count elements.

Remarks

The UUID vector data structure contains a list of UUIDs. The UUID vector contains a count member followed by an array of pointers to UUIDs.

An application constructs a UUID vector to contain object UUIDs to be exported or unexported from the name service.

See Also

RpcEpRegister, RpcEpRegisterNoReplace, RpcEpUnregister, RpcNsBindingExport, RpcNsBindingUnexport


Function Reference

This section contains an alphabetical list of the functions supported in this version of Microsoft® RPC. The documentation for each function includes a statement about the function's purpose, the syntax, a description of the function's input parameters, a description of its values, and additional remarks that can help you use the function in an application.

All pointers passed to RPC functions must include the _ _RPC_FAR attribute. For example, the pointer RPC_BINDING_HANDLE * becomes RPC_BINDING_HANDLE _ _RPC_FAR * and char * * Ptr becomes char _ _RPC_FAR * _ _RPC_FAR * Ptr.


DceErrorInqText
DceErrorInqText   QuickInfo

The DceErrorInqText function returns the message text for a status code.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
DceErrorInqText(
unsigned long  StatusToConvert,
unsigned char *  ErrorText);

This function is supported by both the 32-bit Windows NT and Windows 95 platforms. Note that it is supported in ANSI only on the Windows 95 platform.

Parameters

StatusToConvert

Specifies the status code to convert to a text string.

ErrorText

Returns the text corresponding to the error code.

Value	Meaning
RPC_S_OK	Operation completed successfully
RPC_S_INVALID_ARG	Unknown error code
Remarks

The DceErrorInqText routine returns a null-terminated character string message for a particular status code. If the call is not successful, DceErrorInqText returns a message as well as a failure code in Status.


MesBufferHandleReset

The MesBufferHandleReset function re-initializes the handle for buffer serialization.

#include <rpc.h>
#include <midles.h>
RPC_STATUS RPC_ENTRY
MesBufferHandleReset(
handle_t  Handle,

unsigned long  HandleStyle,

MIDL_ES_CODE  OpCode,

char  *  *  ppBuffer,

unsigned long  BufferSize,

unsigned long *  pEncodedSize);

Parameters

Handle

The handle to be initialized.

HandleStyle

Specifies the style of handle. Valid styles are MES_FIXED_BUFFER_HANDLE or MES_DYNAMIC_BUFFER_HANDLE.

OpCode

Specifies the operation. Valid operations are MES_ENCODE or MES_DECODE.

ppBuffer

For MES_DECODE, points to a pointer to the buffer containing the data to be decoded.

For MES_ENCODE, points to a pointer to the buffer for fixed buffer style, and points to a pointer to return the buffer address for dynamic buffer style.

BufferSize

Specifies the number of bytes of data to be decoded in the buffer. Note that this is used only for the fixed buffer style of serialization.

pEncodedSize

Points to the size of the completed encoding. Note that this is used only when the operation is MES_ENCODE.

Remarks

The MesBufferHandleReset routine is used by applications to re-initialize a buffer style handle and save memory allocations.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_ARG	Invalid argument
See Also

MesEncodeFixedBufferHandleCreate,  MesEncodeDynBufferHandleCreate


MesDecodeBufferHandleCreate

The MesDecodeBufferHandleCreate function creates a decoding handle and initializes it for a (fixed) buffer style of serialization.

#include <rpc.h>
#include <midles.h>
RPC_STATUS RPC_ENTRY
MesDecodeBufferHandleCreate(
char  *  Buffer,

unsigned long  BufferSize,

handle_t *  pHandle);

Parameters

Buffer

Points to the buffer containing the data to decode.

BufferSize

Specifies the number of bytes of data to decode in the buffer.

pHandle

Points to the address to which the handle will be written.

Remarks

The MesDecodeBufferHandleCreate routine is used by applications to create a serialization handle and initialize the handle for the (fixed) buffer style of decoding. When using the fixed buffer style of decoding, the user supplies a single buffer containing all the encoded data. This buffer must have an address which is aligned at 8, and must be a multiple of 8 bytes in size. Further, it must be large enough to hold all of the data to decode.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_ARG	Invalid argument
RPC_S_OUT_OF_MEMORY	Out of memory
RPC_X_INVALID_BUFFER	Invalid buffer
See Also

MesEncodeFixedBufferHandleCreate, MesHandleFree


MesDecodeIncrementalHandleCreate

The MesDecodeIncrementalHandleCreate function creates a decoding handle for the incremental style of serialization.

#include <rpc.h>
#include <midles.h>
RPC_STATUS RPC_ENTRY
MesDecodeIncrementalHandleCreate(

void *  UserState,

MIDL_ES_READ  ReadFn,
handle_t  *  pHandle);

Parameters

UserState

Points to the user-supplied state object that coordinates the Alloc, Write, and Read routines.

ReadFn

Points to the Read routine.

pHandle

Pointer to the newly-created handle.

Remarks

The MesDecodeIncrementalHandleCreate routine is used by applications to create the handle and initialize it for the incremental style of decoding. When using the incremental style of decoding, the user supplies a Read routine to provide a buffer containing the next part of the data to be decoded. The buffer must be aligned at eight, and the size of the buffer must be a multiple of eight. For additional information on the user-supplied Alloc, Write and Read routines, see Using Encoding Services.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_ARG	Invalid argument
RPC_S_OUT_OF_MEMORY	Out of memory
See Also

MesIncrementalHandleReset, MesHandleFree


MesEncodeDynBufferHandleCreate

The MesEncodeDynBufferHandleCreate function creates an encoding handle and then initializes it for a dynamic buffer style of serialization.

#include <rpc.h>
#include <midles.h>
RPC_STATUS RPC_ENTRY
MesEncodeDynBufferHandleCreate(
char  *  *  ppBuffer,

unsigned long  *  pEncodedSize,

handle_t *  pHandle);

Parameters

ppBuffer

Points to a pointer to the stub-supplied buffer containing the encoding after serialization is complete.

pEncodedSize

Specifies a pointer to the size of the completed encoding. The size will be written to the pointee by the subsequent encoding operation(s).

pHandle

Points to the address to which the handle will be written.

Remarks

The MesEncodeDynBufferHandleCreate routine is used by applications to allocate the memory and initialize the handle for the dynamic buffer style of encoding. When using the dynamic buffer style of encoding, the buffer into which all the encoded data will be placed is supplied by the stub. This buffer will be allocated by the current client memory-management mechanism.

There can be performance implications when using this style for multiple encodings with the same handle. A single buffer is returned from an encoding and data is copied from intermediate buffers. The buffers are released when necessary.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_ARG	Invalid argument
RPC_S_OUT_OF_MEMORY	Out of memory
See Also

MesBufferHandleReset, MesHandleFree


MesEncodeFixedBufferHandleCreate

The MesEncodeFixedBufferHandleCreate function creates an encoding handle and then initializes it for a fixed buffer style of serialization.

#include <rpc.h>
#include <midles.h>
RPC_STATUS RPC_ENTRY
MesEncodeFixedBufferHandleCreate(
char *  Buffer,

unsigned long  BufferSize,

unsigned long *  pEncodedSize,

handle_t *  pHandle);

Parameters

Buffer

Points to the user-supplied buffer.

BufferSize

Specifies the size of the user-supplied buffer.

pEncodedSize

Specifies a pointer to the size of the completed encoding. The size will be written to the pointee by the subsequent encoding operation(s).

pHandle

Points to the newly-created handle.

Remarks

The MesEncodeFixedBufferHandleCreate routine is used by applications to create and initialize the handle for the fixed buffer style of encoding. When using the fixed buffer style of encoding, the user supplies a single buffer into which all the encoded data is placed. This buffer must have an address which is aligned at eight, and must be a multiple of eight bytes in size. Further, it must be large enough to hold an encoding of all the data, along with an encoding header for each routine being encoded.

When the handle is used for multiple encoding operations, the encoded size is cumulative.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_ARG	Invalid argument
RPC_S_OUT_OF_MEMORY	Out of memory
See Also

MesDecodeBufferHandleCreate, MesHandleFree


MesEncodeIncrementalHandleCreate

The MesEncodeIncrementalHandleCreate function creates an encoding and then initializes it for the incremental style of serialization.

#include <rpc.h>
#include <midles.h>
RPC_STATUS RPC_ENTRY
MesEncodeIncrementalHandleCreate(

void *  UserState,

MIDL_ES_ALLOC  AllocFn,

MIDL_ES_WRITE  WriteFn,
handle_t  *  pHandle);

Parameters

UserState

Points to the user-supplied state object that coordinates the Alloc, Write, and Read routines.

AllocFn

Points to the Alloc routine.

WriteFn

Points to the Write routine.

pHandle

Points to the newly-created handle.

Remarks

The MesEncodeIncrementalHandleCreate routine is used by applications to create and initialize the handle for the incremental style of encoding or decoding. When using the incremental style of encoding, the user supplies an Alloc routine to provide an empty buffer into which the encoded data is placed, and a Write routine to call when the buffer is full or the encoding is complete. For additional information on the user-supplied Alloc, Write and Read routines, see Using Encoding Services.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_ARG	Invalid argument
RPC_S_OUT_OF_MEMORY	Out of memory
See Also

MesIncrementalHandleReset, MesHandleFree


MesHandleFree

The MesHandleFree function frees the memory allocated by the serialization handle.

#include <rpc.h>
#include <midles.h>
RPC_STATUS RPC_ENTRY
MesHandleFree(
handle_t  Handle);

Parameter

Handle

The handle to be freed.

Remarks

The MesHandleFree routine is used by applications to free the resources of the handle after encoding or decoding data.

Return Values

Value	Meaning
RPC_S_OK	Success
See Also

MesEncodeFixedBufferHandleCreate, MesDecodeBufferHandleCreate, MesEncodeDynBufferHandleCreate, MesEncodeIncrementalHandleCreate


MesIncrementalHandleReset

The MesIncrementalHandleReset function re-initializes the handle for incremental serialization.

#include <rpc.h>
#include <midles.h>
RPC_STATUS RPC_ENTRY
MesIncrementalHandleReset(

handle_t  Handle,
void  *  UserState,

MIDL_ES_ALLOC  AllocFn,

MIDL_ES_WRITE  WriteFn,

MIDL_ES_READ  ReadFn,
MIDL_ES_CODE  OpCode);

Parameters

Handle

The handle to be re-initialized.

UserState

Depending on the function, points to the user-supplied block that coordinates successive calls to the Alloc, Write, and Read routines.

AllocFn

Points to the Alloc routine. This argument can be NULL if the operation does not require it, or if the handle was previously initiated with the pointer.

WriteFn

Points to the Write routine. This argument can be NULL if the operation does not require it, or if the handle was previously initiated with the pointer.

ReadFn

Points to the Read routine. This argument can be NULL if the operation does not require it, or if the handle was previously initiated with the pointer.

OpCode

Specifies the operation. Valid operations are MES_ENCODE or MES_DECODE.

Remarks

The MesIncrementalHandleReset routine is used by applications to re-initialize the handle for the incremental style of encoding or decoding. For additional information on the user-supplied Alloc, Write and Read routines, see Using Encoding Services.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_ARG	Invalid argument
RPC_S_OUT_OF_MEMORY	Out of memory
See Also

MesEncodeIncrementalHandleCreate, MesHandleFree


MesInqProcEncodingId

The MesInqProcEncodingId function provides the identity of an encoding.

#include <rpc.h>
#include <midles.h>
RPC_STATUS RPC_ENTRY
MesInqProcEncodingId(

handle_t  Handle,
PRPC_SYNTAX_IDENTIFIER  pInterfaceId,

unsigned long  *  pProcNum);

Parameters

Handle

Specifies an encoding or decoding handle.

pInterfaceId

Points to the address in which the identity of the interface used to encode the data will be written. pInterfaceId consists of the interface UUID and the version number.

pProcNum

Specifies the number of the routine used to encode the data.

Remarks

The MesInqProcEncodingId routine is used by applications to obtain the identity of the routine used to encode the data before calling a routine to decode it. When called with an encoding handle, it returns the identity of the last encoding operation. When called with a decoding handle, it returns the identity of the next decoding operation by pre-reading the buffer.

This routine can only be used to check the identity of a procedure encoding; it cannot be used to check the identity for a type encoding.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_ARG	Invalid argument
RPC_S_OUT_OF_MEMORY	Out of memory
RPC_S_UNKNOWN_IF	Unknown interface
RPC_S_UNSUPPORTED_ TRANS_SYN	Transfer syntax not supported by server
RPC_X_INVALID_ES_ACTION	Invalid operation for a given handle
RPC_X_WRONG_ES_VERSION	Incompatible version of the serializing package
RPC_X_SS_INVALID_BUFFER	Invalid buffer


RpcAbnormalTermination
RpcAbnormalTermination   QuickInfo

The RpcAbnormalTermination function determines whether termination statements are being executed due to an exception or not.

void RpcAbnormalTermination(void);

Remarks

The RpcAbnormalTermination function should only be called from within the termination-statements section of an RpcFinally termination handler.

Return Values

Value	Meaning	Description
Zero	No exception	Termination statements are not being executed due to an exception
Nonzero	Exception	Termination statements are  being executed due to an exception
See Also

RpcFinally


RpcBindingCopy
RpcBindingCopy   QuickInfo

The RpcBindingCopy function copies binding information and creates a new binding handle.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcBindingCopy(
RPC_BINDING_HANDLE  SourceBinding,
RPC_BINDING_HANDLE *  DestinationBinding);

Parameters

SourceBinding

Specifies the server binding handle whose referenced binding information is copied.

DestinationBinding

Returns a pointer to the server binding handle that refers to the copied binding information.

Remarks

Note  Microsoft RPC supports RpcBindingCopy only in client applications, not in server applications.

The RpcBindingCopy routine copies the server-binding information referenced by the SourceBinding argument. RpcBindingCopy uses the DestinationBinding argument to return a new server binding handle for the copied binding information. RpcBindingCopy also copies the authentication information from the SourceBinding argument to the DestinationBinding argument.

An application uses RpcBindingCopy when it wants to keep a change made to binding information by one thread from affecting the binding information used by other threads.

Once an application calls RpcBindingCopy, operations performed on the SourceBinding binding handle do not affect the binding information referenced by the DestinationBinding binding handle. Similarly, operations performed on the DestinationBinding binding handle do not affect the binding information referenced by the SourceBinding binding handle.

If an application wants one thread's changes to binding information to affect the binding information used by other threads, the application should share a single binding handle across the threads. In this case, the application is responsible for binding-handle concurrency control.

When an application is finished using the binding handle specified by the DestinationBinding argument, the application should call the RpcBindingFree routine to release the memory used by the DestinationBinding binding handle and its referenced binding information.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_BINDING	Invalid binding handle
RPC_S_WRONG_KIND_OF_BINDING	Wrong kind of binding for operation
See Also

RpcBindingFree


RpcBindingFree
RpcBindingFree   QuickInfo

The RpcBindingFree function releases binding-handle resources.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcBindingFree(
RPC_BINDING_HANDLE *  Binding);

Parameter

Binding

Points to the server binding to free.

Remarks

Note  Microsoft RPC supports RpcBindingFree only in client applications, not in server applications.

The RpcBindingFree routine releases memory used by a server binding handle. Referenced binding information that was dynamically created during program execution is released as well. An application calls the RpcBindingFree routine when it is finished using the binding handle.

Binding handles are dynamically created by calling the following routines:

•	RpcBindingCopy

•	RpcBindingFromStringBinding

•	RpcServerInqBindings

•	RpcNsBindingImportNext

•	RpcNsBindingSelect

If the operation successfully frees the binding, the Binding argument returns a value of NULL.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_BINDING	Invalid binding handle
RPC_S_WRONG_KIND_OF_BINDING	Wrong kind of binding for operation
See Also

RpcBindingCopy, RpcBindingFromStringBinding, RpcBindingVectorFree, RpcNsBindingImportNext, RpcNsBindingLookupNext, RpcNsBindingSelect, RpcServerInqBindings


RpcBindingFromStringBinding
RpcBindingFromStringBinding   QuickInfo

The RpcBindingFromStringBinding function returns a binding handle from a string representation of a binding handle.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcBindingFromStringBinding(
unsigned char *  StringBinding,
RPC_BINDING_HANDLE *  Binding);

Parameters

StringBinding

Points to a string representation of a binding handle.

Binding

Returns a pointer to the server binding handle.

Remarks

The RpcBindingFromStringBinding routine creates a server binding handle from a string representation of a binding handle.

The StringBinding argument does not have to contain an object UUID. In this case, the returned binding contains a nil UUID.

If the provided StringBinding argument does not contain an endpoint field, the returned Binding argument is a partially bound binding handle.

If the provided StringBinding argument contains an endpoint field, the endpoint is considered to be a well-known endpoint.

If the provided StringBinding argument does not contain a host address field, the returned Binding argument references the local host.

An application creates a string binding by calling the RpcStringBindingCompose routine or by providing a character-string constant.

When an application is finished using the Binding argument, the application should call the RpcBindingFree routine to release the memory used by the binding handle.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_STRING_BINDING	Invalid string binding
RPC_S_PROTSEQ_NOT_SUPPORTED	Protocol sequence not supported on this host
RPC_S_INVALID_RPC_PROTSEQ	Invalid protocol sequence
RPC_S_INVALID_ENDPOINT_FORMAT	Invalid endpoint format
RPC_S_STRING_TOO_LONG	String too long
RPC_S_INVALID_NET_ADDR	Invalid network address
RPC_S_INVALID_ARG	Invalid argument
RPC_S_INVALID_NAF_ID	Invalid network-address-family ID
See Also

RpcBindingCopy, RpcBindingFree, RpcBindingToStringBinding, RpcStringBindingCompose


RpcBindingInqAuthClient
RpcBindingInqAuthClient   QuickInfo

The RpcBindingInqAuthClient function returns authentication and authorization information from an authenticated client's binding handle.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcBindingInqAuthClient(
RPC_BINDING_HANDLE	ClientBinding,
RPC_AUTHZ_HANDLE *	Privs,
unsigned char * *  ServerPrincName,
unsigned long *	  AuthnLevel,
unsigned long *	  AuthnSvc,
unsigned long *	  AuthzSvc);

This function is supported by both the 32-bit Windows NT and Windows 95 platforms.

Parameters

ClientBinding

Specifies the client binding handle of the client that made the remote procedure call. This value can be zero (see Remarks).

Privs

Returns a pointer to a handle to the privileged information for the client application that made the remote procedure call on the ClientBinding binding handle.

The server application must cast the ClientBinding binding handle to the data type specified by the AuthzSvc argument. The data referenced by this argument is read-only and should not be modified by the server application. If the server wants to preserve any of the returned data, the server must copy the data into server-allocated memory. This parameter is not used by the RPC_C_AUTHN_WINNT securing package. The returned pointer will always be NULL.

ServerPrincName

Returns a pointer to a pointer to the server principal name specified by the client application that made the remote procedure call on the ClientBinding binding handle. The content of the returned name and its syntax are defined by the authentication service in use.

Specify a null value to prevent RpcBindingInqAuthClient from returning the ServerPrincName argument. In this case, the application does not call the RpcStringFree routine.

AuthnLevel

Returns a pointer to the level of authentication requested by the client application that made the remote procedure call on the ClientBinding binding handle.

Specify a null value to prevent RpcBindingInqAuthClient from returning the AuthnLevel argument.

AuthnSvc

Returns a pointer to the authentication service requested by the client application that made the remote procedure call on the ClientBinding binding handle. For a list of the RPC-supported authentication services, see RpcMgmtInqDefaultProtectLevel.

Specify a null value to prevent RpcBindingInqAuthClient from returning the AuthnSvc argument. This parameter is not used by the RPC_C_AUTHN_WINNT security package. The returned value will always be RPC_S_AUTHZ_NONE.

AuthzSvc

Returns a pointer to the authorization service requested by the client application that made the remote procedure call on the Binding binding handle. For a list of possible returns, see RpcMgmtInqDefaultProtectLevel.

Specify a null value to prevent RpcBindingInqAuthClient from returning the AuthnSvc argument.

Remarks

A server application calls the RpcBindingInqAuthClient routine to obtain the principal name or privilege attributes of the authenticated client that made the remote procedure call. In addition, RpcBindingInqAuthClient returns the authentication service, authentication level, and server principal name specified by the client. The server can use the returned data for authorization purposes.

The RPC run-time library allocates memory for the returned ServerPrincName argument. The application is responsible for calling the RpcStringFree routine for the returned argument string.

For clients using the MIDL auto_handle or implicit_handle attribute, the server application should use zero as the value for the ClientBinding parameter.  Using zero retrieves the authentication and authorization information from the currently executing remote procedure call.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_BINDING	Invalid binding handle
RPC_S_WRONG_KIND_OF_BINDING	Wrong kind of binding for operation
RPC_S_BINDING_HAS_NO_AUTH	Binding has no authentication information
See Also

RpcBindingSetAuthInfo, RpcStringFree


RpcBindingInqAuthInfo
RpcBindingInqAuthInfo   QuickInfo

The RpcBindingInqAuthInfo function returns authentication and authorization information from a binding handle.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcBindingInqAuthInfo(
RPC_BINDING_HANDLE  Binding,
unsigned char * *  ServerPrincName,
unsigned long *	  AuthnLevel,
unsigned long *	  AuthnSvc,
RPC_AUTH_IDENTITY_HANDLE *  AuthIdentity,
unsigned long *	  AuthzSvc);

Parameters

Binding

Specifies the server binding handle from which authentication and authorization information is returned.

ServerPrincName

Returns a pointer to a pointer to the expected principal name of the server referenced in the Binding argument. The content of the returned name and its syntax are defined by the authentication service in use.

Specify a null value to prevent RpcBindingInqAuthInfo from returning the ServerPrincName argument. In this case, the application does not call the RpcStringFree routine.

AuthnLevel

Returns a pointer to the level of authentication used for remote procedure calls made using the Binding binding handle. For a list of the RPC-supported authentication levels, see the RPC data types and structures reference entry for authentication-level constants.

Specify a null value to prevent the routine from returning the AuthnLevel argument.

The level returned in the AuthnLevel argument may be different from the level specified when the client called the RpcBindingSetAuthInfo routine. This discrepancy happens when the authentication level specified by the client was not supported by the RPC run-time library and the run-time library automatically upgraded to the next higher level.

AuthnSvc

Returns a pointer to the authentication service specified for remote procedure calls made using the Binding binding handle. For a list of the RPC-supported authentication services, see RpcMgmtInqDefaultProtectLevel.

Specify a null value to prevent RpcBindingInqAuthInfo from returning the AuthnSvc argument.

AuthIdentity

Returns a pointer to a handle to the data structure that contains the client's authentication and authorization credentials specified for remote procedure calls made using the Binding binding handle.

Specify a null value to prevent RpcBindingInqAuthInfo from returning the AuthIdentity argument.

AuthzSvc

Returns a pointer to the authorization service requested by the client application that made the remote procedure call on the Binding binding handle. For a list of possible returns, see RpcMgmtInqDefaultProtectLevel.

Specify a null value to prevent RpcBindingInqAuthInfo from returning the AuthzSvc argument.

Remarks

A client application calls the RpcBindingInqAuthInfo routine to view the authentication and authorization information associated with a server binding handle. The client specifies the data by calling the RpcBindingSetAuthInfo routine.

The RPC run-time library allocates memory for the returned ServerPrincName argument. The application is responsible for calling the RpcStringFree routine for that returned argument string.

When a client application does not know a server's principal name, calling RpcBindingInqAuthInfo after making a remote procedure call provides the server's principal name. For example, clients that import from a group or profile may not know a server's principal name when calling the RpcBindingSetAuthInfo routine.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_BINDING	Invalid binding handle
RPC_S_WRONG_KIND_OF_BINDING	Wrong kind of binding for operation
RPC_BINDING_HAS_NO_AUTH	Binding has no authentication information
See Also

RpcBindingSetAuthInfo, RpcStringFree


RpcBindingInqObject
RpcBindingInqObject   QuickInfo

The RpcBindingInqObject function returns the object UUID from a binding handle.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcBindingInqObject(
RPC_BINDING_HANDLE  Binding,
UUID *  ObjectUuid);

Parameters

Binding

Specifies a client or server binding handle.

ObjectUuid

Returns a pointer to the object UUID found in the Binding argument. ObjectUuid is a unique identifier of an object to which a remote procedure call can be made.

Remarks

An application calls the RpcBindingInqObject routine to see the object UUID associated with a client or server binding handle.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_BINDING	Invalid binding handle
See Also

RpcBindingSetObject


RpcBindingReset
RpcBindingReset   QuickInfo

The RpcBindingReset function resets a binding handle so that the host is specified but the server on that host is unspecified.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcBindingReset(
RPC_BINDING_HANDLE Binding);

Parameter

Binding

Specifies the server binding handle to reset.

Remarks

A client calls the RpcBindingReset routine to disassociate a particular server instance from the server binding handle specified in the Binding argument. The RpcBindingReset routine dissociates a server instance by removing the endpoint portion of the server address in the binding handle. The host remains unchanged in the binding handle. The result is a partially bound server binding handle.

RpcBindingReset does not affect the Binding argument's authentication information, if there is any.

If a client is willing to be serviced by any compatible server instance on the host specified in the binding handle, the client calls the RpcBindingReset routine before making a remote procedure call using the Binding binding handle.

When the client makes the next remote procedure call using the reset (partially bound) binding, the client's RPC run-time library uses a well-known endpoint from the client's interface specification, if any. Otherwise, the client's run-time library automatically communicates with the endpoint-mapping service on the specified remote host to obtain the endpoint of a compatible server from the endpoint-map database. If a compatible server is located, the RPC run-time library updates the binding with a new endpoint. If a compatible server is not found, the remote procedure call fails. For calls using a connection protocol (ncacn), the RPC_S_NO_ENDPOINT_FOUND status code is returned to the client. For calls using a datagram protocol (ncadg), the RPC_S_COMM_FAILURE status code is returned to the client.

Server applications should register all binding handles by calling RpcEpRegister and RpcEpRegisterNoReplace if the server wants to be available to clients that make a remote procedure call on a reset binding handle.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_BINDING	Invalid binding handle
RPC_S_WRONG_KIND_OF_BINDING	Wrong kind of binding for operation
See Also

RpcEpRegister, RpcEpRegisterNoReplace


RpcBindingServerFromClient
RpcBindingServerFromClient   QuickInfo

The RpcBindingServerFromClient function converts a client binding handle to a server binding handle.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcBindingServerFromClient(
RPC_BINDING_HANDLE  ClientBinding,
RPC_BINDING_HANDLE *  ServerBinding);

This function is supported by both the 32-bit Windows NT and Windows 95 platforms.

Parameters

ClientBinding

Specifies the client binding handle to convert to a server binding handle.

ServerBinding

Returns a server binding handle.

Remarks

An application calls the RpcBindingServerFromClient routine to convert a client binding handle into a partially-bound server binding handle.

An application gets a client binding handle from the RPC runtime. When the RPC arrives at a server, the runtime creates a client binding handle that contains information about the calling client. This handle is passed by the runtime to the server manager routine as the first argument.

The following information pertains to the server binding handle that is returned by RpcBindingServerFromClient:

•	The returned handle is a partially bound handle. It contains a network address for the calling client, but lacks an endpoint.

•	The returned handle contains the same object UUID used by the calling client. This can be the nil UUID. For more information on how a client specifies an object UUID for a call, see RpcBindingsetObject, RpcNsBindingImportBegin, RpcNsBindingLookupBegin, and RpcBindingFromStringBinding.

•	The returned handle contains no authentication information.

Note  This routine is only supported for TCP or SPX.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_BINDING	Invalid binding handle
RPC_S_WRONG_KIND_OF_BINDING	Wrong kind of binding for operation
RPC_S_CANNOT_SUPPORT	Cannot determine the client's host (not TCP or SPX)
See Also

RpcBindingFree, RpcBindingSetObject, RpcEpRegister, RpcEpRegisterNoReplace, RpcNsBindingImportBegin, RpcNsBindingLookupBegin, RpcBindingFromStringBinding


RpcBindingSetAuthInfo
RpcBindingSetAuthInfo   QuickInfo

The RpcBindingSetAuthInfo function sets authentication and authorization information into a binding handle.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcBindingSetAuthInfo(
RPC_BINDING_HANDLE  Binding,
unsigned char *  ServerPrincName,
unsigned long  AuthnLevel,
unsigned long  AuthnSvc,
RPC_AUTH_IDENTITY_HANDLE  AuthIdentity,
unsigned long  AuthzSvc);

Parameters

Binding

Specifies the server binding handle into which authentication and authorization information is set.

ServerPrincName

Points to the expected principal name of the server referenced by the binding handle specified in the Binding argument. The content of the name and its syntax are defined by the authentication service in use.

AuthnLevel

Specifies the level of authentication to be performed on remote procedure calls made using the Binding binding handle. For a list of RPC-supported authentication levels, see the RPC data types and structures reference entry for authentication-level constants.

AuthnSvc

Specifies the authentication service to use. For a list of RPC-supported authentication services, see the RPC data types and structures reference entry for authentication-service constants.

Specify RPC_C_AUTHN_NONE to turn off authentication for remote procedure calls made using the Binding binding handle.

If RPC_C_AUTHN_DEFAULT is specified, the RPC run-time library uses the RPC_C_AUTHN_WINNT authentication service for remote procedure calls made using the Binding binding handle.

AuthIdentity

Specifies a handle for the data structure that contains the client's authentication and authorization credentials appropriate for the selected authentication and authorization service.

When using the RPC.C.AUTHN.WINNT authentication service AuthIdentity should be a pointer to a SEC.WINNT.AUTH.IDENTITY structure (defined in rpcdce.h).

Specify a null value to use the security login context for the current address space.

AuthzSvc

Specifies the authorization service implemented by the server for the interface of interest. The validity and trustworthiness of authorization data, like any application data, depends on the authentication service and authentication level selected. This parameter is ignored when using the RPC_C_AUTHN_WINNT authentication service.

For a list of constants for the AuthzSvc argument, see the RPC data types and structures reference entry for authorization-service constants.

Remarks

A client application calls the RpcBindingSetAuthInfo routine to set up a server binding handle for making authenticated remote procedure calls.

Unless a client calls RpcBindingSetAuthInfo, all remote procedure calls on the Binding binding handle are unathenticated. A client is not required to call this routine.

Note  As long as the binding handle exists, RPC maintains a pointer to AuthIdentity. Be sure it is not on the stack and is not freed until the binding handle is freed. If the binding handle is copied, or if a context handle is created from the binding handle, then the AuthIdentity pointer will also be copied.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_BINDING	Invalid binding handle
RPC_S_WRONG_KIND_OF_BINDING	Wrong kind of binding for operation
RPC_S_UNKNOWN_AUTHN_SERVICE	Unknown authentication service
See Also

RpcBindingInqAuthInfo, RpcServerRegisterAuthInfo


RpcBindingSetObject
RpcBindingSetObject   QuickInfo

The RpcBindingSetObject function sets the object UUID value in a binding handle.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcBindingSetObject(
RPC_BINDING_HANDLE  Binding,
UUID *  ObjectUuid);

Parameters

Binding

Specifies the server binding into which the ObjectUuid is set.

ObjectUuid

Points to the UUID of the object serviced by the server specified in the Binding argument. ObjectUuid is a unique identifier of an object to which a remote procedure call can be made.

Remarks

An application calls the RpcBindingSetObject routine to associate an object UUID with a server binding handle. The set-object operation replaces the previously associated object UUID with the UUID in the ObjectUuid argument.

To set the object UUID to the nil UUID, specify a null value or the nil UUID for the ObjectUuid argument.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_BINDING	Invalid binding handle
RPC_S_WRONG_KIND_OF_BINDING	Wrong kind of binding for operation
See Also

RpcBindingFromStringBinding, RpcBindingInqObject


RpcBindingToStringBinding
RpcBindingToStringBinding   QuickInfo

The RpcBindingToStringBinding function returns a string representation of a binding handle.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcBindingToStringBinding(
RPC_BINDING_HANDLE  Binding,
unsigned char * *  StringBinding);

Parameters

Binding

Specifies a client or server binding handle to convert to a string representation of a binding handle.

StringBinding

Returns a pointer to a pointer to the string representation of the binding handle specified in the Binding argument.

Specify a null value to prevent RpcBindingToStringBinding from returning the StringBinding argument. In this case, the application does not call the RpcStringFree routine.

Remarks

The RpcBindingToStringBinding routine converts a client or server binding handle to its string representation.

The RPC run-time library allocates memory for the string returned in the StringBinding argument. The application is responsible for calling the RpcStringFree routine to deallocate that memory.

If the binding handle in the Binding argument contained a nil object UUID, the object UUID field is not included in the returned string.

To parse the returned StringBinding argument, call the RpcStringBindingParse routine.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_BINDING	Invalid binding handle
See Also

RpcBindingFromStringBinding, RpcStringBindingParse, RpcStringFree


RpcBindingVectorFree
RpcBindingVectorFree   QuickInfo

The RpcBindingVectorFree function frees the binding handles contained in the vector and the vector itself.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcBindingVectorFree(
RPC_BINDING_VECTOR * *  BindingVector);

Parameters

BindingVector

Points to a pointer to a vector of server binding handles. On return, the pointer is set to NULL.

Remarks

An application calls the RpcBindingVectorFree routine to release the memory used to store a vector of server binding handles. The routine frees both the binding handles and the vector itself.

A server obtains a vector of binding handles by calling the RpcServerInqBindings routine. A client obtains a vector of binding handles by calling the RpcNsBindingLookupNext routine.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_ARG	Invalid argument
RPC_S_INVALID_BINDING	Invalid binding handle
RPC_S_WRONG_KIND_OF_BINDING	Wrong kind of binding for operation
See Also

RpcNsBindingLookupNext, RpcServerInqBindings


RpcCancelThread
RpcCancelThread   QuickInfo

The RpcCancelThread function cancels a thread.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcCancelThread(
HANDLE  ThreadHandle);

This function is supported only by 32-bit Windows NT platforms.

Parameter

ThreadHandle

Specifies the handle of the thread to cancel.

Remarks

The RpcCancelThread routine allows one client thread to cancel an RPC in progress on another client thread. When the routine is called, the server runtime is informed of the cancel operation. The server stub can determine if the call has been cancelled by calling RpcTestCancel. If the call has been cancelled, the server stub should clean up and return control to the client.

By default, the client waits forever for the server to return control after a cancel. To reduce this time, call RpcMgmtSetCancelTimeout, specifying the number of seconds to wait for a response. If the server does not return within this interval, the call fails at the client with an RPC_S_CALL_FAILED exception. The server stub continues to execute.

Note  This routine is only supported for Windows NT clients.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_ACCESS_DENIED	Thread handle does not have privilege
RPC_S_CANNOT_SUPPORT	Called by an MS-DOS or Windows 3.x client


RpcEndExcept
RpcEndExcept   QuickInfo

See

RpcExcept


RpcEndFinally
RpcEndFinally   QuickInfo

See

RpcFinally


RpcEpRegister
RpcEpRegister   QuickInfo

The RpcEpRegister function adds to or replaces server address information in the local endpoint-map database.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcEpRegister(
RPC_IF_HANDLE  IfSpec,
RPC_BINDING_VECTOR *  BindingVector,
UUID_VECTOR *  UuidVector,
unsigned char *  Annotation);

This function is supported by both the 32-bit Windows NT and Windows 95 platforms.

Parameters

IfSpec

Specifies an interface to register with the local endpoint-map database.

BindingVector

Points to a vector of binding handles over which the server can receive remote procedure calls.

UuidVector

Points to a vector of object UUIDs offered by the server. The server application constructs this vector.

A null argument value indicates there are no object UUIDs to register.

Annotation

Points to the character-string comment applied to each cross-product element added to the local endpoint-map database. The string can be up to 64 characters long, including the null terminating character. Specify a null value or a null-terminated string ("\0") if there is no annotation string.

The annotation string is used by applications for information only. RPC does not use this string to determine which server instance a client communicates with or for enumerating elements in the endpoint-map database.

Remarks

The RpcEpRegister routine adds or replaces entries in the local host's endpoint-map database. For an existing database entry that matches the provided interface specification, binding handle, and object UUID, this routine replaces the entry's endpoint with the endpoint in the provided binding handle.

A server uses RpcEpRegister rather than RpcEpRegisterNoReplace when only a single instance of the server will run on the server's host. In other words, use this routine when no more than one server instance will offer the same interface UUID, object UUID, and protocol sequence at any one time.

When entries are not replaced, stale data accumulates each time a server instance stops running without calling RpcEpUnregister. Stale entries increase the likelihood that a client will receive endpoints to nonexistent servers. The client will spend time trying to communicate with a nonexistent server before obtaining another endpoint.

Using RpcEpRegister to replace existing endpoint-map database entries reduces the likelihood that a client will be given the endpoint of a nonexistent server instance. A server application calls this routine to register endpoints specified by calling any of the following routines:

•	RpcServerUseAllProtseqs

•	RpcServerUseProtseq

•	RpcServerUseProtseqEp

A server that calls only RpcServerUseAllProtseqsIf or RpcServerUseProtseqIf does not need to call RpcEpRegister. In this case, the client's run-time library uses an endpoint from the client's interface specification to fill in a partially bound binding handle.

If the server also exports to the name-service database, the server calls RpcEpRegister with the same IfSpec, BindingVector, and UuidVector that the server uses when calling the RpcNsBindingExport routine.

For automatically started servers running over one of the connection-based protocol sequences (ncacn_np, ncacn_nb, ncacn_ip_tcp, ncacn_osi_dns), the RPC run-time library automatically generates a dynamic endpoint. In this case, the server can call RpcServerInqBindings followed by RpcEpRegister to make itself available to multiple clients. Otherwise, the automatically started server is known only to the client for which the server was started.

Each element added to the endpoint-map database logically contains the following:

•	Interface UUID

•	Interface version (major and minor)

•	Binding handle

•	Object UUID (optional)

•	Annotation (optional)

RpcEpRegister creates a cross-product from the IfSpec, BindingVector, and UuidVector arguments and adds each element in the cross-product as a separate registration in the endpoint-map database.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_NO_BINDINGS	No bindings
RPC_S_INVALID_BINDING	Invalid binding handle
RPC_S_WRONG_KIND_OF_BINDING	Wrong kind of binding for operation
See Also

RpcBindingFromStringBinding, RpcEpRegisterNoReplace, RpcEpUnregister, RpcNsBindingExport, RpcServerInqBindings, RpcServerUseAllProtseqs, RpcServerUseAllProtseqsIf, RpcServerUseProtseq, , RpcServerUseProtseqIf


RpcEpRegisterNoReplace
RpcEpRegisterNoReplace   QuickInfo

The RpcEpRegisterNoReplace function adds server-address information to the local endpoint-map database.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcEpRegisterNoReplace(
RPC_IF_HANDLE  IfSpec,
RPC_BINDING_VECTOR *  BindingVector,
UUID_VECTOR *  UuidVector,
unsigned char *  Annotation);

Parameters

IfSpec

Specifies an interface to register with the local endpoint-map database.

BindingVector

Points to a vector of binding handles over which the server can receive remote procedure calls.

UuidVector

Points to a vector of object UUIDs offered by the server. The server application constructs this vector.

A null argument value indicates there are no object UUIDs to register.

Annotation

Points to the character-string comment applied to each cross-product element added to the local endpoint-map database. The string can be up to 64 characters long, including the null terminating character. Specify a null value or a null-terminated string ("\0") if there is no annotation string.

The annotation string is used by applications for information only. RPC does not use this string to determine which server instance a client communicates with or to enumerate elements in the endpoint-map database.

Remarks

The RpcEpRegisterNoReplace routine adds entries to the local host's
endpoint-map database. This routine does not replace existing database entries.

A server uses RpcEpRegisterNoReplace rather than RpcEpRegister when multiple instances of the server will run on the same host. In other words, use this routine when more than one server instance will offer the same interface UUID, object UUID, and protocol sequence at any one time.

Because entries are not replaced when calling RpcEpRegisterNoReplace, servers must unregister themselves before they stop running. Otherwise, stale data accumulates each time a server instance stops running without calling RpcEpUnregister. Stale entries increase the likelihood that a client will receive endpoints to nonexistent servers. The client will spend time trying to communicate with a nonexistent server before obtaining another endpoint.

A server application calls RpcEpRegisterNoReplace to register endpoints specified by calling any of the following routines:

•	RpcServerUseAllProtseqs

•	RpcServerUseProtseq

•	RpcServerUseProtseqEp

A server that calls only RpcServerUseAllProtseqsIf or RpcServerUseProtseqIf is not required to call RpcEpRegisterNoReplace. In this case, the client's
run-time library uses an endpoint from the client's interface specification to fill in a partially bound binding handle.

If the server also exports to the name-service database, the server calls RpcEpRegisterNoReplace with the same IfSpec, BindingVector, and UuidVector arguments that the server uses when calling the RpcNsBindingExport routine.

For automatically started servers running over one of the connection-based protocol sequences (ncacn_np, ncacn_nb, ncacn_ip_tcp, ncacn_osi_dns), the RPC run-time library automatically generates a dynamic endpoint. In this case, the server can call RpcServerInqBindings followed by RpcEpRegisterNoReplace to make itself available to multiple clients. Otherwise, the automatically started server is known only to the client for which the server was started.

Each element added to the endpoint-map database logically contains the following:

•	Interface UUID

•	Interface version (major and minor)

•	Binding handle

•	Object UUID (optional)

•	Annotation (optional)

RpcEpRegisterNoReplace creates a cross-product from the IfSpec, BindingVector, and UuidVector arguments and adds each element in the cross-product as a separate registration in the endpoint-map database.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_NO_BINDINGS	No bindings
RPC_S_INVALID_BINDING	Invalid binding handle
RPC_S_WRONG_KIND_OF_BINDING	Wrong kind of binding for operation
See Also

RpcBindingFromStringBinding, RpcEpRegister, RpcEpUnregister, RpcNsBindingExport, RpcServerInqBindings, RpcServerUseAllProtseqs, RpcServerUseAllProtseqsIf, RpcServerUseProtseq, RpcServerUseProtseqEp, RpcServerUseProtseqIf


RpcEpResolveBinding
RpcEpResolveBinding   QuickInfo

The RpcEpResolveBinding function resolves a partially bound server binding handle into a fully bound server binding handle.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcEpResolveBinding(
RPC_BINDING_HANDLE  Binding,
RPC_IF_HANDLE  IfSpec);

Parameters

Binding

Specifies a partially bound server binding handle to resolve to a fully bound server binding handle.

IfSpec

Specifies a stub-generated data structure specifying the interface of interest.

Remarks

An application calls the RpcEpResolveBinding routine to resolve a partially bound server binding handle into a fully bound binding handle.

Resolving binding handles requires an interface UUID and an object UUID (which may be nil). The RPC run-time library asks the endpoint-mapping service on the host specified by the Binding argument to look up an endpoint for a compatible server instance. To find the endpoint, the endpoint-mapping service looks in the endpoint-map database for the interface UUID in the IfSpec argument and the object UUID in the Binding argument, if any.

How the resolve-binding operation functions depends on whether the specified binding handle is partially or fully bound. When the client specifies a partially bound handle, the resolve-binding operation has the following possible outcomes:

•	If no compatible server instances are registered in the endpoint-map database, the resolve-binding operation returns the EPT_S_NOT_REGISTERED status code.

•	If a compatible server instance is registered in the endpoint-map database, the resolve-binding operation returns a fully bound binding and the RPC_S_OK status code.

When the client specifies a fully bound binding handle, the resolve-binding operation returns the specified binding handle and the RPC_S_OK status code. The resolve-binding operation does not contact the endpoint-mapping service.

In neither the partially nor the fully bound binding case does the resolve-binding operation contact a compatible server instance.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_BINDING	Invalid binding handle
RPC_S_WRONG_KIND_OF_BINDING	Wrong kind of binding for operation
See Also

RpcBindingFromStringBinding, RpcBindingReset, RpcEpRegister, RpcEpRegisterNoReplace, RpcNsBindingImportBegin, RpcNsBindingImportDone, RpcNsBindingImportNext


RpcEpUnregister
RpcEpUnregister   QuickInfo

The RpcEpUnregister function removes server-address information from the local endpoint-map database.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcEpUnregister(
RPC_IF_HANDLE  IfSpec,
RPC_BINDING_VECTOR *  BindingVector,
UUID_VECTOR *  UuidVector);

This function is supported by both the 32-bit Windows NT and Windows 95 platforms.

Parameters

IfSpec

Specifies an interface to unregister from the local endpoint-map database.

BindingVector

Points to a vector of binding handles to unregister.

UuidVector

Points to an optional vector of object UUIDs to unregister. The server application constructs this vector. RpcEpUnregister unregisters all endpoint-map database elements that match the specified IfSpec and BindingVector arguments and the object UUID(s).

A null argument value indicates there are no object UUIDs to unregister.

Remarks

The RpcEpUnregister routine removes elements from the local host's
endpoint-map database. A server application calls this routine only when the server has previously registered endpoints and the server wants to remove that address information from the endpoint-map database.

Specifically, RpcEpUnregister allows a server application to remove its own endpoint-map database elements (server-address information) based on the interface specification or on both the interface specification and the object UUID(s) of the resource(s) offered.

The server calls the RpcServerInqBindings routine to obtain the required BindingVector argument. To unregister selected endpoints, the server can prune the binding vector prior to calling this routine.

RpcEpUnregister creates a cross-product from the IfSpec, BindingVector, and UuidVector arguments and removes each element in the cross-product from the endpoint-map database.

Use RpcEpUnregister cautiously: removing elements from the endpoint-map database may make servers unavailable to client applications that have not previously communicated with the server.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_NO_BINDINGS	No bindings
RPC_S_INVALID_BINDING	Invalid binding handle
RPC_S_WRONG_KIND_OF_BINDING	Wrong kind of binding for operation
See Also

RpcEpRegister, RpcEpRegisterNoReplace, RpcNsBindingUnexport, RpcServerInqBindings


RpcExcept
RpcExcept   QuickInfo

The RpcExcept function specifies exception handling.

RpcTryExcept
{
guarded statements,
}
RpcExcept(expression)
{
exception statements,
}
RpcEndExcept;

Parameters

guarded statements

Specifies program statements that are guarded or monitored for exceptions during execution.

expression

Specifies an expression that is evaluated when an exception occurs. If expression evaluates to a non-zero value, the exception statements are executed. If expression evaluates to a zero value, unwinding continues to the next RpcTryExcept or RpcTryFinally routine.

exception statements

Specifies statements that are executed when the expression evaluates to a non-zero value.

Remarks

If an exception does not occur, the expression and exception statements are skipped and execution continues at the statement following the RpcEndExcept keyword.

RpcExceptionCode can be used in both expression and exception statements to determine which exception occurred.

The following restrictions apply.

•	Jumping (via a goto) into guarded statements is not allowed.

•	Jumping (via a goto) into exception statements is not allowed.

•	Returning or jumping (via a goto) from guarded statements is not allowed.

•	Returning or jumping (via a goto) from exception statements is not allowed.

See Also

RpcExceptionCode, RpcFinally, RpcRaiseException


RpcExceptionCode
RpcExceptionCode   QuickInfo

The RpcExceptionCode function returns the exception code of an exception.

unsigned long
RpcExceptionCode(void);

Remarks

The RpcExceptionCode function can only be called from within the expression and exception statements of an RpcTryExcept exception handler.

Return Values

No value is returned.

See Also

RpcExcept, RpcFinally


RpcFinally
RpcFinally   QuickInfo

The RpcFinally function specifies termination handlers.

RpcTryFinally
{
guarded statements,,
}
RpcFinally
{
termination statements,,
}
RpcEndFinally;

Parameters

guarded statements

Specifies statements that are executed while exceptions are being monitored. If an exception occurs during the execution of these statements, termination statements will be executed, then unwinding continues to the next RpcTryExcept or RpcTryFinally routine.

termination statements

Specifies statements that are executed when an exception occurs. After the termination statements are complete, the exception is raised again.

Remarks

The RpcAbnormalTermination function can be used in termination statements to determine whether termination statements is being executed because an exception occurred. A non-zero return from RpcAbnormalTermination indicates that an exception occurred. A value of zero indicates that no exception occurred.

The following restrictions apply:

•	Jumping (via a goto) into guarded statements is not allowed.

•	Jumping (via a goto) into termination statements is not allowed.

•	Returning or jumping (via a goto) from guarded statements is not allowed.

•	Returning or jumping (via a goto) from termination statements is not allowed.

See Also

RpcAbnormalTermination


RpcIfIdVectorFree
RpcIfIdVectorFree   QuickInfo

The RpcIfIdVectorFree function frees the vector and the interface-identification structures contained in the vector.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcIfIdVectorFree(
RPC_IF_ID_VECTOR * *  IfIdVec);

This function is supported by both the 32-bit Windows NT and Windows 95 platforms.

Parameter

IfIdVec

Specifies the address of a pointer to a vector of interface information. On return, the pointer is set to NULL.

Remarks

An application calls the RpcIfIdVectorFree routine to release the memory used to store a vector of interface identifications. RpcIfIdVectorFree frees memory containing the interface identifications and the vector itself. On return, this routine sets the IfIdVec argument to NULL.

An application obtains a vector of interface identifications by calling the RpcNsMgmtEntryInqIfIds and RpcMgmtInqIfIds routines.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_ARG	Invalid argument
See Also

RpcIfInqId, RpcMgmtInqIfIds, RpcNsMgmtEntryInqIfIds


RpcIfInqId
RpcIfInqId   QuickInfo

The RpcIfInqId function returns the interface-identification part of an interface specification.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcIfInqId(
RPC_IF_HANDLE  RpcIfHandle,
RPC_IF_ID *  RpcIfId);

Parameters

RpcIfHandle

Specifies a stub-generated data structure specifying the interface to inquire.

RpcIfId

Returns a pointer to the interface identification. The application provides memory for the returned data.

Remarks

An application calls the RpcIfInqId routine to obtain a copy of the interface identification from the provided interface specification.

The returned interface identification consists of the interface UUID and interface version numbers (major and minor) specified in the IfSpec argument from the IDL file.

Return Value

Value	Meaning
RPC_S_OK	Success
See Also

RpcServerInqIf, RpcServerRegisterIf


RpcImpersonateClient
RpcImpersonateClient   QuickInfo

A server thread that is processing client remote procedure calls can call the RpcImpersonateClient function to impersonate the active client.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcImpersonateClient(
RPC_BINDING_HANDLE	CallHandle);

This function is supported only by 32-bit Windows NT platforms.

Parameter

CallHandle

Specifies a binding handle on the server that represents a binding to a client. The server impersonates the client indicated by this handle. If a value of zero is specified, the server impersonates the client that is being served by this server thread.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_NO_CALL_ACTIVE	No client is active on this server thread
RPC_S_CANNOT_SUPPORT	The function is not supported for either the operating system, the transport, or this security subsystem
RPC_S_NO_CONTEXT_AVAIL	The server does not have permission to impersonate the client
See Also

RpcRevertToSelf


RpcMacSetYieldInfo

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcMacSetYieldInfo(
MACYIELDCALLBACK	pfnCallback);

Parameter

pfnCallback

Pointer to a callback function.

typedef void (RPC_ENTRY *MACYIELDCALLBACK)(short *);

Remarks

The RpcMacSetYieldInfo function configures Macintosh client applications to yield to other applications during remote procedure calls.

If a yielding function is not registered, an RPC will not yield on the Mac. Register a yielding function by calling RpcMacSetYieldInfo.

The yielding function must yield until *pStatus is not equal to 1. For example:

void RPC_ENTRY MacCallbackFunc (short *pStatus)

{

MSG msg;

while (*pStatus == 1)

{

if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

}

}

Note that rpc.h must be included before winerror.h (or any files that include it, such as winbase.h, windows.h, and so on).

Return Value

Value	Meaning
RPC_S_OK	The information was set successfully.


RpcMgmtEnableIdleCleanup
RpcMgmtEnableIdleCleanup   QuickInfo

The RpcMgmtEnableIdleCleanup function closes idle resources, such as network connections, on the client. Connection-oriented protocols set five minutes as the default waiting period to determine whether a resource is idle.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcMgmtEnableIdleCleanup(void);

This function is supported by the 32-bit Windows NT, Windows 95 and Windows 3.x platforms. It is not supported by MS-DOS.

Note  RpcMgmtEnableIdleCleanup is a Microsoft extension to the DCE API set.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_OUT_OF_THREADS	Out of threads
RPC_S_OUT_OF_RESOURCES	Out of resources
RPC_S_OUT_OF_MEMORY	Out of memory
See Also

RpcServerUnregisterIf


RpcMgmtEpEltInqBegin
RpcMgmtEpEltInqBegin   QuickInfo

The RpcMgmtEpEltInqBegin function creates an inquiry context for viewing the elements in an endpoint map.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcMgmtEpEltInqBegin(
RPC_BINDING_HANDLE  EpBinding,
unsigned long  InquiryType,
RPC_IF_ID *  IfId,
unsigned long  VersOption,
UUID *  ObjectUuid,,
RPC_EP_INQ_HANDLE *  InquiryContext);

This function is supported by both the 32-bit Windows NT and Windows 95 platforms.

Parameters

EpBinding

Specifies the host whose endpoint map elements will be viewed. Specify NULL to view elements from the local host.

InquiryType

Specifies an integer value that indicates the type of inquiry to perform on the endpoint map. The following are valid inquiry types:

Value	Description
RPC_C_EP_ALL_ELTS	Returns every element from the endpoint map. The IfId, VersOption, and ObjectUuid parameters are ignored.
RPC_C_EP_MATCH_BY_IF	Searches the endpoint map for those elements that contain the interface identifier specified by the IfId and VersOption values.
RPC_C_EP_MATCH_BY_OBJ	Searches the endpoint map for those elements that contain the object UUID specified by ObjectUuid.
RPC_C_EP_MATCH_BY_BOTH	Searches the endpoint map for those elements that contain the interface identifier and object UUID specified by IfId, VersOption, and ObjectUuid.
IfId

Specifies the interface identifier of the endpoint map elements to be returned by RpcMgmtEpEltInqNext. This parameter is only used when InquiryType is either RPC_C_EP_MATCH_BY_IF or RPC_C_EP_MATCH_BY_BOTH. Otherwise, it is ignored.

VersOption

Specifies how RpcMgmtEpEltInqNext uses the IfId parameter. This parameter is only used when InquiryType is either RPC_C_EP_MATCH_BY_IF or RPC_C_EP_MATCH_BY_BOTH. Otherwise, it is ignored. The following are valid values for this parameter:

Value	Description
RPC_C_VERS_ALL	Returns endpoint map elements that offer the specified interface UUID, regardless of the version numbers.
RPC_C_VERS_COMPATIBLE	Returns endpoint map elements that offer the same major version of the specified interface UUID and a minor version greater than or equal to the minor version of the specified interface UUID.
RPC_C_VERS_EXACT	Returns endpoint map elements that offer the specified version of the specified interface UUID.
RPC_C_VERS_MAJOR_ONLY	Returns endpoint map elements that offer the same major version of the specified interface UUID and ignores the minor version.
RPC_C_VERS_UPTO	Returns endpoint map elements that offer a version of the specified interface UUID less than or equal to the specified major and minor version.
ObjectUuid

Specifies the object UUID that RpcMgmtEpEltInqNext looks for in endpoint map elements. This parameter is used only when InquiryType is either RPC_C_EP_MATCH_BY_OBJ or RPC_C_EP_MATCH_BY_BOTH.

InquiryContext

Returns an inquiry context for use with RpcMgmtEpEltInqNext and RpcMgmtEpEltInqDone.

Remarks

The RpcMgmtEpEltInqBegin routine creates an inquiry context for viewing server address information stored in the endpoint map. Using InquiryType and VersOption, an application specifies which of the following endpoint map elements are to be returned from calls to RpcMgmtEpEltInqNext:

•	All elements.

•	Those elements with the specified interface identifier.

•	Those elements with the specified object UUID.

•	Those elements with both the specified interface identifier and object UUID.

Before calling RpcMgmtEpEltInqNext, the application must first call this routine to create an inquiry context. After viewing the endpoint map elements, the application calls RpcMgmtEpEltInqDone to delete the inquiry context.

Return Values

Value	Meaning
RPC_S_OK	Success
See Also

RpcEpRegister


RpcMgmtEpEltInqDone
RpcMgmtEpEltInqDone   QuickInfo

The RpcMgmtEpEltInqDone function deletes the inquiry context for viewing the elements in an endpoint map.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcMgmtEpEltInqDone(
RPC_EP_INQ_HANDLE *  InquiryContext);

This function is supported by both the 32-bit Windows NT and Windows 95 platforms.

Parameter

InquiryContext

Specifies the inquiry context to delete and returns the value NULL.

Remarks

The RpcMgmtEpEltInqDone routine deletes an inquiry context created by RpcMgmtEpEltInqBegin. An application calls this routine after viewing local endpoint map elements using RpcMgmtEpEltInqNext.

Return Values

Value	Meaning
RPC_S_OK	Success
See Also

RpcEpRegister


RpcMgmtEpEltInqNext
RpcMgmtEpEltInqNext   QuickInfo

The RpcMgmtEpEltInqNext function returns one element from an endpoint map.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcMgmtEpEltInqNext(
RPC_EP_INQ_HANDLE  InquiryContext,,
RPC_IF_ID * Ifld,
UUID *  ObjectUuid,
unsigned char * *  Annotation);

This function is supported by both the 32-bit Windows NT and Windows 95 platforms.

Parameters

InquiryContext

Specifies an inquiry context. The inquiry context is returned from RpcMgmtEpEltInqBegin.

IfId

Returns the interface identifier of the endpoint map element.

Binding

Returns the binding handle from the endpoint map element.

ObjectUuid

Returns the object UUID from the endpoint map element.

Annotation

Returns the annotation string for the endpoint map element. When there is no annotation string in the endpoint map element, the empty string ("") is returned.

Remarks

The RpcMgmtEpEltInqNext routine returns one element from the endpoint map. Elements selected depend on the inquiry context. The selection criteria are determined by InquiryType of the RpcMgmtEpEltInqBegin routine that returned InquiryContext.

An application can view all the selected endpoint map elements by repeatedly calling RpcMgmtEpEltInqNext. When all the elements have been viewed, this routine returns an RPC_S_NO_MORE_ELEMENTS status. The returned elements are unordered.

When the respective arguments are non-NULL, the RPC run-time function library allocates memory for Binding and Annotation on each call to this routine. The application is responsible for calling RpcBindingFree for each returned Binding and RpcStringFree for each returned Annotation.

After viewing the endpoint map's elements, the application must call RpcMgmtEpEltInqDone to delete the inquiry context.

Return Values

Value	Meaning
RPC_S_OK	Success
See Also

RpcEpRegister


RpcMgmtEpUnregister
RpcMgmtEpUnregister   QuickInfo

The RpcMgmtEpUnregister function removes server address information from an endpoint map.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcMgmtEpUnregister(
RPC_BINDING_HANDLE  EpBinding,
RPC_IF_ID *  IfId,
RPC_BINDING_HANDLE  Binding,
UUID *  ObjectUuid);

This function is supported by both the 32-bit Windows NT and Windows 95 platforms.

Parameters

EpBinding

Specifies the host whose endpoint map elements are to be unregistered. To remove elements from the same host as the calling application, the application specifies NULL. To remove elements from another host, the application specifies a server binding handle for any server residing on that host. Note that the application can specify the same binding handle it is using to make other remote procedure calls.

IfId

Specifies the interface identifier to remove from the endpoint map.

Binding

Specifies the binding handle to remove.

ObjectUuid

Specifies the optional object UUID to remove. The value NULL indicates there is no object UUID to remove.

Remarks

The RpcMgmtEpUnregister routine unregisters an element from the endpoint map. A management program calls this routine to remove addresses of servers that are no longer available, or to remove addresses of servers that support objects that are no longered offered.

The EpBinding parameter must be a full binding. The object UUID associated with the EpBinding parameter must be a nil UUID. Specifying a non-nil UUID causes the routine to fail with the status code EPT_S_CANT_PERFORM_OP. Other than the host information and object UUID, all information in this argument is ignored.

An application calls RpcMgmtEpEltInqNext to view local endpoint map elements. The application can then remove the elements using RpcMgmtEpUnregister.

Note  Use this routine with caution. Removing elements from the local endpoint map may make servers unavailable to client applications that do not already have a fully bound binding handle to the server.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_CANT_PERFORM_OP	Cannot perform the requested operation
See Also

RpcEpRegister, RpcEpUnregister


RpcMgmtInqComTimeout
RpcMgmtInqComTimeout   QuickInfo

The RpcMgmtInqComTimeout function returns the binding-communications timeout value in a binding handle.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcMgmtInqComTimeout(
RPC_BINDING_HANDLE  Binding,
unsigned int *  Timeout);

Parameters

Binding

Specifies a binding.

Timeout

Returns a pointer to the timeout value from the Binding argument.

Remarks

A client application calls RpcMgmtInqComTimeout to view the timeout value in a server binding handle. The timeout value specifies the relative amount of time that should be spent to establish a binding to the server before giving up. The table below shows the timeout values.

A client calls RpcMgmtSetComTimeout to change the timeout value.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_BINDING	Invalid binding handle
RPC_S_WRONG_KIND_OF_BINDING	Wrong kind of binding for operation
See Also

RpcMgmtInqStats, RpcMgmtSetComTimeout


RpcMgmtInqDefaultProtectLevel
RpcMgmtInqDefaultProtectLevel   QuickInfo

The RpcMgmtInqDefaultProtectLevel function returns the default authentication level for an authentication service.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcMgmtInqDefaultProtectLevel(
unsigned int	  AuthnSvc,
unsigned int	 *  AuthnLevel);

Parameters

AuthnSvc

Specifies the authentication service for which to return the default authentication level. Possible values are as follows:

Value	Description
RPC_C_AUTHN_NONE	No authentication
RPC_C_AUTHN_WINNT	Windows NT authentication service
AuthnLevel

Returns the default authentication level for the specified authentication service. The authentication level determines the degree to which authenticated communications between the client and server are protected. Possible values are as follows:

Value	Description
RPC_C_AUTHN_LEVEL_DEFAULT	Uses the default authentication  level for the specified authentication service.
RPC_C_AUTHN_LEVEL_NONE	Performs no authentication.
RPC_C_AUTHN_LEVEL_CONNECT	Authenticates only when the client establishes a relationship with a server.
RPC_C_AUTHN_LEVEL_CALL	Authenticates only at the beginning of each remote procedure call when the server receives the request. Does not apply to remote procedure calls made using the connection-based protocol sequences that start with the prefix "ncacn." If the protocol sequence in a binding is a connection-based protocol sequence and you specify this level, this routine instead uses the RPC_C_AUTHN_LEVEL_PKT constant.
RPC_C_AUTHN_LEVEL_PKT	Authenticates that all data received is from the expected client.
RPC_C_AUTHN_LEVEL_PKT_ INTEGRITY	Authenticates and verifies that  none of the data transferred between client and server has been modified.
RPC_C_AUTHN_LEVEL_PKT _PRIVACY	Authenticates all previous levels and encrypts the argument value of each remote procedure call.
Note  For Windows 95 platforms, RPC_C_AUTHN_LEVEL_CALL, RPC_C_AUTHN_LEVEL_PKT, RPC_C_AUTHN_LEVEL_PKT_INTEGRITY, and RPC_C_AUTHN_LEVEL_PKT_PRIVACY are only supported for a Windows 95 client communicating with a Windows NT server. These levels are never supported for a Windows 95 client communicating with a Windows 95 server.

Remarks

An application calls the RpcMgmtInqDefaultProtectLevel routine to obtain the default authentication level for a specified authentication service.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_UNKNOWN_AUTH_SERVICE	Unknown authentication service


RpcMgmtInqIfIds
RpcMgmtInqIfIds   QuickInfo

The RpcMgmtInqIfIds function returns a vector containing the identifiers of the interfaces offered by the server.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcMgmtInqIfIds(
RPC_BINDING_HANDLE  Binding,
RPC_IF_ID_VECTOR * *  IfIdVector);

This function is supported by both the 32-bit Windows NT and Windows 95 platforms.

Parameters

Binding

To receive interface identifiers about a remote application, specify a server binding handle for that application. To receive interface information about your own application, specify a value of NULL.

IfIdVector

Returns the address of an interface identifier vector.

Remarks

An application calls the RpcMgmtInqIfIds routine to obtain a vector of interface identifiers about the specified server from the RPC run-time library.

The RPC run-time library allocates memory for the interface identifier vector. The application is responsible for calling the RpcIfIdVectorFree routine to release the memory used by this vector.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_BINDING	Invalid binding handle
RPC_S_WRONG_KIND_OF_BINDING	Wrong kind of binding for operation


RpcMgmtInqServerPrincName
RpcMgmtInqServerPrincName   QuickInfo

The RpcMgmtInqServerPrincName function returns a server's principal name.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcMgmtInqServerPrincName(
RPC_BINDING_HANDLE  Binding,
unsigned int  AuthnSvc,
unsigned char * *  ServerPrincName);

This function is supported by both the 32-bit Windows NT and Windows 95 platforms. Note that it is supported only in ANSI on the Windows 95 platform.

Parameters

Binding

To receive the principal name for a server, specify a server binding handle for that server. To receive the principal name for your own (local) application, specify a value of NULL.

AuthnSvc

Specifies the authentication service for which a principal name is returned. Possible values are as follows:

Value	Description
RPC_C_AUTHN_NONE	No authentication
RPC_C_AUTHN_WINNT	Windows NT authentication service
ServerPrincName

Returns a principal name that is registered for the authentication service in AuthnSvc by the server referenced in Binding. If multiple names are registered, only one name is returned.

Remarks

An application calls the RpcMgmtInqServerPrincName routine to obtain the principal name of a server that is registered for a specified authentication service.

The RPC run-time library allocates memory for string returned in ServerPrincName. The application is responsible for calling the RpcStringFree routine to release the memory used by this routine.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_BINDING	Invalid binding handle
RPC_S_WRONG_KIND_OF_BINDING	Wrong kind of binding for operation


RpcMgmtInqStats
RpcMgmtInqStats   QuickInfo

The RpcMgmtInqStats function returns RPC run-time statistics.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcMgmtInqStats(
RPC_BINDING_HANDLE  Binding,
RPC_STATS_VECTOR * *  Statistics);

This function is supported by both the 32-bit Windows NT and Windows 95 platforms.

Parameters

Binding

To receive statistics about a remote application, specify a server binding handle for that application. To receive statistics about your own (local) application, specify a value of NULL.

Statistics

Returns a pointer to a pointer to the statistics about the server specified by the Binding argument. Each statistic is an unsigned long value.

Remarks

An application calls the RpcMgmtInqStats routine to obtain statistics about the specified server from the RPC run-time library.

Each array element in the returned statistics vector contains an unsigned long value. The following list describes the statistics indexed by the specified constant:

Statistic	Description
RPC_C_STATS_CALLS_IN	The number of remote procedure calls received by the server
RPC_C_STATS_CALLS_OUT	The number of remote procedure calls initiated by the server
RPC_C_STATS_PKTS_IN	The number of network packets received by the server
RPC_C_STATS_PKTS_OUT	The number of network packets sent by the server
The RPC run-time library allocates memory for the statistics vector. The application is responsible for calling the RpcMgmtStatsVectorFree routine to release the memory used by the statistics vector.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_BINDING	Invalid binding handle
RPC_S_WRONG_KIND_OF_BINDING	Wrong kind of binding for operation
See Also

RpcEpResolveBinding, RpcMgmtStatsVectorFree


RpcMgmtIsServerListening
RpcMgmtIsServerListening   QuickInfo

The RpcMgmtIsServerListening function tells whether a server is listening for remote procedure calls.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcMgmtIsServerListening(
RPC_BINDING_HANDLE  Binding);

This function is supported by both the 32-bit Windows NT and Windows 95 platforms.

Parameter

Binding

To determine whether a remote application is listening for remote procedure calls, specify a server binding handle for that application. To determine whether your own (local) application is listening for remote procedure calls, specify a value of NULL.

Remarks

An application calls the RpcMgmtIsServerListening routine to determine whether the server specified in the Binding argument is listening for remote procedure calls.

RpcMgmtIsServerListening returns a true value if the server has called the RpcServerListen routine.

Return Values

Value	Meaning
RPC_S_OK	Server listening for remote procedure calls
RPC_S_SERVER_NOT_LISTENING	Server not listening for remote procedure calls
RPC_S_INVALID_BINDING	Invalid binding handle
RPC_S_WRONG_KIND_OF_BINDING	Wrong kind of binding for operation
See Also

RpcEpResolveBinding, RpcServerListen


RpcMgmtSetAuthorizationFn
RpcMgmtSetAuthorizationFn   QuickInfo

The RpcMgmtSetAuthorizationFn function establishes an authorization function for processing remote calls to a server's management routines.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcMgmtSetAuthorizationFn(
RPC_MGMT_AUTHORIZATION_FN  AuthorizationFn);

This function is supported only by 32-bit Windows NT platforms.

Parameter

AuthorizationFn

Specifies an authorization function. The RPC server run-time library automatically calls this function whenever the server runtime receives a client request to execute one of the remote management routines. The server must implement this function. Applications specify NULL to unregister a previously registered authorization function. After such a call, default authorizations are used.

Remarks

Server applications call the RpcMgmtSetAuthorizationFn routine to establish an authorization function that controls access to the server's remote management routines. When a server has not called RpcMgmtSetAuthorizationFn, or calls with a NULL value for AuthorizationFn, the server run-time library uses the following default authorizations:

Remote routine	Default authorization
RpcMgmtInqIfIds	Enabled
RpcMgmtInqServerPrincName	Enabled
RpcMgmtInqStats	Enabled
RpcMgmtIsServerListening	Enabled
RpcMgmtStopServerListening	Disabled
In the above table, "Enabled" indicates that all clients can execute the remote routine, and "Disabled" indicates that all clients are prevented from executing the remote routine.

The following example shows the prototype for authorization function that the server must implement:

typedef boolean32  (*RPC_MGMT_AUTHORIZATION_FN)

   (

   RPC_BINDING_HANDLE	ClientBinding	/* in */

   unsigned long	RequestedMgmtOperation	/* in */

   RPC_STATUS *	Status	/* out */

   );

When a client requests one of the server's remote management functions, the server run-time library calls the authorization function with ClientBinding and RequestedMgmtOperation. The authorization function uses these parameters to determine whether the calling client can execute the requested management routine.

The value for RequestedMgmtOperation depends on the remote routine requested, as shown in the following:

Called remote routine	RequestedMgmtOperation value
RpcMgmtInqIfIds	RPC_C_MGMT_INQ_IF_IDS
RpcMgmtInqServerPrincName	RPC_C_MGMT_INQ_PRINC_NAME
RpcMgmtInqStats	RPC_C_MGMT_INQ_STATS
RpcMgmtIsServerListening	RPC_C_MGMT_IS_SERVER_LISTEN
RpcMgmtStopServerListening	RPC_C_MGMT_STOP_SERVER_LISTEN
The authorization function must handle all of these values.

The authorization function returns a Boolean value to indicate whether the calling client is allowed access to the requested management function. If the authorization function returns TRUE, the management routine can execute. If the authorization function returns FALSE, the management routine cannot execute. If this is the case, the routine returns a Status value to the client:

•	If Status is either 0 (zero) or RPC_S_OK, the Status value RPC_S_ACCESS_DENIED is returned to the client by the remote management routine.

•	If the authorization function returns any other value for Status, that Status value is returned to the client by the remote management routine.

Return Values

Value	Meaning
RPC_S_OK	Success
See Also

RpcMgmtInqStats, RpcMgmtIsServerListening, RpcMgmtStopServerListening, RpcMgmtWaitServerListen


RpcMgmtSetCancelTimeout
RpcMgmtSetCancelTimeout   QuickInfo

The RpcMgmtSetCancelTimeout function sets the lower bound on the time to wait before timing out after forwarding a cancel.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcMgmtSetCancelTimeout(
signed int  Seconds);

This function is supported only by 32-bit Windows NT platforms.

Parameter

Seconds

An integer specifying the number of seconds to wait for a server to acknowledge a cancel. To specify that a client waits an indefinite amount of time, supply the value RPC_C_CANCEL_INFINITE_TIMEOUT.

Remarks

An application calls the RpcMgmtSetCancelTimeout routine to reset the amount of time the run-time library waits for a server to acknowledge a cancel. The application specifies either to wait forever or to wait a specified length of time in seconds. If the value of Seconds is 0 (zero), the call is immediately abandoned upon a cancel and control returns to the client application. The default value is RPC_C_CANCEL_INFINITE_TIMEOUT, which specifies waiting forever for the call to complete.

The value for the cancel time-out applies to all remote procedure calls made in the current thread. To change the time-out value, a multithreaded client must call this routine in each thread of execution.

Note  This routine is only supported for Windows NT clients.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_CANNOT_SUPPORT	Called from an MS-DOS or Windows 3.x client


RpcMgmtSetComTimeout
RpcMgmtSetComTimeout   QuickInfo

The RpcMgmtSetComTimeout function sets the binding-communications timeout value in a binding handle.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcMgmtSetComTimeout(
RPC_BINDING_HANDLE  Binding,
unsigned int	  Timeout);

Parameters

Binding

Specifies the server binding handle whose timeout value is set.

Timeout

Specifies the communications timeout value.

Remarks

A client application calls RpcMgmtSetComTimeout to change the communications timeout value for a server binding handle. The timeout value specifies the relative amount of time that should be spent to establish a relationship to the server before giving up. Depending on the protocol sequence for the specified binding handle, the timeout value acts only as a hint to the RPC run-time library.

After the initial relationship is established, subsequent communications for the binding handle revert to not less than the default timeout for the protocol service. This means that after setting a short initial timeout establishing a connection, calls in progress will not be timed out any more aggressively than the default.

The timeout value can be any integer value from 0 to 10. For convenience, constants are provided for certain values in the timeout range. The following table contains the RPC-defined values that an application can use for the timeout argument:

Manifest	Value	Description
RPC_C_BINDING_INFINITE_TIMEOUT	10	Keep trying to establish communications forever.
RPC_C_BINDING_MIN_TIMEOUT	0	Try the minimum amount of time for the network protocol being used. This value favors response time over correctness in determining whether the server is running.
RPC_C_BINDING_DEFAULT_TIMEOUT	5	Try an average amount of time for the network protocol being used. This value gives correctness in determining whether a server is running and gives response time equal weight. This is the default value.
RPC_C_BINDING_MAX_TIMEOUT	9	Try the longest amount of time for the network protocol being used. This value favors correctness in determining whether a server is running over response time.
Note  The values in the preceding table are not in seconds. These values represent a relative amount of time on a scale of zero to 10.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_BINDING	Invalid binding handle
RPC_S_INVALID_TIMEOUT	Invalid timeout value
RPC_S_WRONG_KIND_OF_BINDING	Wrong kind of binding for operation
See Also

RpcMgmtInqComTimeout


RpcMgmtSetServerStackSize
RpcMgmtSetServerStackSize   QuickInfo

The RpcMgmtSetServerStackSize function specifies the stack size for each server thread.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcMgmtSetServerStackSize(
unsigned int	  ThreadStackSize);

This function is supported by both 32-bit Windows NT and Windows 95 platforms.

Parameter

ThreadStackSize

Specifies the stack size in bytes allocated for each thread created by RpcServerListen. This value is applied to all threads created for the server. Select this value based on the stack requirements of the remote procedures offered by the server.

Remarks

A server application calls the RpcMgmtSetServerStackSize routine to specify the thread stack size to use when the RPC run-time library creates call threads for executing remote procedure calls. The MaxCalls argument in the RpcServerListen routine specifies the number of call threads created.

Servers that know the stack requirements of all the manager routines in the interfaces it offers can call the RpcMgmtSetServerStackSize routine to ensure that each call thread has the necessary stack size.

Calling RpcMgmtSetServerStackSize is optional. However, when used, it must be called before the server calls RpcServerListen. If a server does not call RpcMgmtSetServerStackSize, the default per thread stack size from the underlying threads package is used.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_ARG	Invalid argument
See Also

RpcServerListen


RpcMgmtStatsVectorFree
RpcMgmtStatsVectorFree   QuickInfo

The RpcMgmtStatsVectorFree function frees a statistics vector.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcMgmtStatsVectorFree(
RPC_STATS_VECTOR * *  StatsVector);

This function is supported by both the 32-bit Windows NT and Windows 95 platforms.

Parameter

StatsVector

Points to a pointer to a statistics vector. On return, the pointer is set to NULL.

Remarks

An application calls the RpcMgmtStatsVectorFree routine to release the memory used to store statistics.

An application obtains a vector of statistics by calling the RpcMgmtInqStats routine.

Return Values

Value	Meaning
RPC_S_OK	Success
See Also

RpcMgmtInqStats


RpcMgmtStopServerListening
RpcMgmtStopServerListening   QuickInfo

The RpcMgmtStopServerListening function tells a server to stop listening for remote procedure calls.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcMgmtStopServerListening(
RPC_BINDING_HANDLE  Binding);

This function is supported by both the 32-bit Windows NT and Windows 95 platforms.

Parameter

Binding

To direct a remote application to stop listening for remote procedure calls, specify a server binding handle for that application. To direct your own (local) application to stop listening for remote procedure calls, specify a value of NULL.

Remarks

An application calls the RpcMgmtStopServerListening routine to direct a server to stop listening for remote procedure calls. If DontWait was true, the application should call RpcMgmtWaitServerListen to wait for all calls to complete.

When it receives a stop-listening request, the RPC run-time library stops accepting new remote procedure calls for all registered interfaces. Executing calls are allowed to complete, including callbacks.

After all calls complete, the RpcServerListen routine returns to the caller. If DontWait is true, the application calls RpcMgmtServerListen for all calls to complete.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_BINDING	Invalid binding handle
RPC_S_WRONG_KIND_OF_BINDING	Wrong kind of binding for operation
See Also

RpcEpResolveBinding, RpcMgmtWaitServerListen, RpcServerListen


RpcMgmtWaitServerListen
RpcMgmtWaitServerListen   QuickInfo

The RpcMgmtWaitServerListen function performs the wait operation usually associated with RpcServerListen.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcMgmtWaitServerListen(void);

Remarks

Note  RpcMgmtWaitServerListen is a Microsoft extension to the DCE API set.

This function is supported by both the 32-bit Windows NT and Windows 95 platforms.

When the RpcServerListen flag parameter DontWait has a nonzero value, the RpcServerListen function returns to the server application without performing the wait operation. In this case, the wait can be performed by RpcMgmtWaitServerListen.

Applications must call RpcServerListen with a nonzero value for the DontWait parameter before calling RpcMgmtWaitServerListen.

RpcMgmtWaitServerListen returns after the server application calls RpcMgmtStopServerListening and all active remote procedure calls complete, or after a fatal error occurs in the RPC run-time library.

Return Values

Value	Meaning
RPC_S_OK	All remote procedure calls are complete.
RPC_S_ALREADY_LISTENING	Another thread has called RpcMgmtWaitServerListen and has not yet returned.
RPC_S_NOT_LISTENING	The server application must call RpcServerListen before calling RpcMgmtWaitServerListen.
See Also

RpcMgmtStopServerListening, RpcServerListen


RpcNetworkInqProtseqs
RpcNetworkInqProtseqs   QuickInfo

The RpcNetworkInqProtseqs function returns all protocol sequences supported by both the RPC run-time library and the operating system.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcNetworkInqProtseqs(
RPC_PROTSEQ_VECTOR * *  ProtSeqVector);

This function is supported by both the 32-bit Windows NT and Windows 95 platforms.

For a list of procotol sequences supported by RPC, see RPC Data Types and Structures.

Parameter

ProtSeqVector

Returns a pointer to a pointer to a protocol sequence vector.

Remarks

Note  RpcNetworkInqProtseqs is available for server applications, not client applications, using Microsoft RPC. Use RpcNetworkIsProtseqValid in client applications.

A server application calls the RpcNetworkInqProtseqs routine to obtain a vector containing the protocol sequences supported by both the RPC run-time library and the operating system. If there are no supported protocol sequences, this routine returns the RPC_S_NO_PROTSEQS status code and a ProtSeqVector argument value of NULL.

The server is responsible for calling the RpcProtseqVectorFree routine to release the memory used by the vector.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_NO_PROTSEQS	No supported protocol sequences
See Also

RpcProtseqVectorFree


RpcNetworkIsProtseqValid
RpcNetworkIsProtseqValid   QuickInfo

The RpcNetworkIsProtseqValid function tells whether the specified protocol sequence is supported by both the RPC run-time library and the operating system.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcNetworkIsProtseqValid(
unsigned char *  Protseq);

For a list of procotol sequences supported by RPC, see RPC Data Types and Structures.

Parameter

Protseq

Points to a string identifier of the protocol sequence to be checked.

If the Protseq argument is not a valid protocol sequence string, RpcNetworkIsProtseqValid returns RPC_S_INVALID_RPC_PROTSEQ.

Remarks

Note  RpcNetworkIsProtseqValid is available for client applications, not for server applications. Use RpcNetworkInqProtseqs for server applications.

An application calls the RpcNetworkIsProtseqValid routine to determine whether an individual protocol sequence is available for making remote procedure calls.

A protocol sequence is valid if both the RPC run-time library and the operating system support the specified protocols. For a list of RPC-supported protocol sequences, see String Binding.

An application calls RpcNetworkInqProtseqs to see all of the supported protocol sequences.

Return Values

Value	Meaning
RPC_S_OK	Success; protocol sequence supported
RPC_S_PROTSEQ_NOT_ SUPPORTED	Protocol sequence not supported on this host
RPC_S_INVALID_RPC_PROTSEQ	Invalid protocol sequence
See Also

RpcNetworkInqProtseqs


RpcNsBindingExport
RpcNsBindingExport   QuickInfo

The RpcNsBindingExport function establishes a name-service database entry with multiple binding handles and multiple objects for a server.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcNsBindingExport(
unsigned long  EntryNameSyntax,
unsigned char *  EntryName,
RPC_IF_HANDLE  IfSpec,
RPC_BINDING_VECTOR *  BindingVec,
UUID_VECTOR *  ObjectUuidVec);

This function is supported by both the 32-bit Windows NT and Windows 95 platforms.

Parameters

EntryNameSyntax

Specifies an unsigned long value that indicates the syntax of the next argument, EntryName.

To use the syntax specified in the registry value HKEY_LOCAL_MACHINE\Software\Microsoft\Rpc\NameService\
DefaultSyntax, provide a value of RPC_C_NS_SYNTAX_DEFAULT.

EntryName

Points to the entry name to which binding handles and object UUIDs are exported. You may not provide a null or empty string.

To use the entry name specified in the registry value HKEY_LOCAL_MACHINE\Software\Microsoft\Rpc\NameService\
DefaultEntry, provide a null pointer or an empty string. In this case, the EntryNameSyntax parameter is ignored and the run-time library uses the default syntax EntryName.

IfSpec

Specifies a stub-generated data structure specifying the interface to export. A null argument value indicates there are no binding handles to export (only object UUIDs are to be exported) and the BindingVec argument is ignored.

BindingVec

Points to server bindings to export. A null argument value indicates there are no binding handles to export (only object UUIDs are to be exported).

ObjectUuidVec

Points to a vector of object UUIDs offered by the server. The server application constructs this vector. A null argument value indicates there are no object UUIDs to export (only binding handles are to be exported).

Remarks

The RpcNsBindingExport routine allows a server application to publicly offer an interface in the name-service database for use by any client application.

To export an interface, the server application calls the RpcNsBindingExport routine with an interface and the server binding handles a client can use to access the server.

A server application also calls the RpcNsBindingExport routine to publicly offer the object UUID(s) of resource(s) it offers, if any, in the name-service database.

A server can export interfaces and objects in a single call to RpcNsBindingExport, or it can export them separately.

If the name-service database entry specified by the EntryName argument does not exist, the RpcNsBindingExport routine tries to create it. In this case, the server application must have the privilege to create the entry.

In addition to calling RpcNsBindingExport, a server that called the RpcServerUseAllProtseqs or RpcServerUseProtseq routine must also register with the local endpoint-map database by calling either the RpcEpRegister or RpcEpRegisterNoReplace routine.

A server is not required to export its interface(s) to the name-service database. When a server does not export, only clients that privately know of that server's binding information can access its interface(s). For example, a client that has the information needed to construct a string binding can call the RpcBindingFromStringBinding to create a binding handle for making remote procedure calls to a server.

Before calling the RpcNsBindingExport routine, a server must do the following:

•	Register one or more protocol sequences with the local RPC run-time library by calling one of the following routines:

•	RpcServerUseAllProtseqs

•	RpcServerUseProtseq

•	RpcServerUseAllProtseqsIf

•	RpcServerUseProtseqIf

•	RpcServerUseProtseqEp

•	Obtain a list of server bindings by calling the RpcServerInqBindings routine.

The vector returned from the RpcServerInqBindings routine becomes the Binding argument for RpcNsBindingExport. To prevent a binding from being exported, set the selected vector element to a null value.

If a server exports to the same name-service database entry multiple times, the second and subsequent calls to RpcNsBindingExport add the binding information and object UUIDs when that data is different from the binding information already in the server entry. Existing data is not removed from the entry.

To remove binding handles and object UUIDs from the name-service database, a server application calls the RpcNsBindingUnexport routine.

A server entry must have at least one binding handle to exist. As a result, exporting only UUIDs to a non-existing entry has no effect, and unexporting all binding handles deletes the entry.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_NOTHING_TO_EXPORT	Nothing to export
RPC_S_INVALID_BINDING	Invalid binding handle
RPC_S_WRONG_KIND_OF_BINDING	Wrong kind of binding for operation
RPC_S_INVALID_NAME_SYNTAX	Invalid name syntax
RPC_S_UNSUPPORTED_NAME_SYNTAX	Unsupported name syntax
RPC_S_INCOMPLETE_NAME	Incomplete name
RPC_S_NO_NS_PRIVILEGE	No privilege for name-service operation
RPC_S_NAME_SERVICE_UNAVAILABLE	Name service unavailable
See Also

RpcBindingFromStringBinding, RpcEpRegister, RpcEpRegisterNoReplace, RpcNsBindingUnexport, RpcServerInqBindings, RpcServerUseAllProtseqs, RpcServerUseAllProtseqsIf, RpcServerUseProtseq, RpcServerUseProtseqEp, RpcServerUseProtseqIf


RpcNsBindingImportBegin
RpcNsBindingImportBegin   QuickInfo

The RpcNsBindingImportBegin function creates an import context for an interface and an object.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcNsBindingImportBegin(
unsigned long  EntryNameSyntax,
unsigned char *  EntryName,
RPC_IF_HANDLE  IfSpec,
UUID *  ObjUuid,
RPC_NS_HANDLE *  ImportContext);

Parameters

EntryNameSyntax

Specifies an unsigned long value that indicates the syntax of the next argument, EntryName.

To use the syntax specified in the registry value HKEY_LOCAL_MACHINE\Software\Microsoft\Rpc\NameService\
DefaultSyntax, provide a value of RPC_C_NS_SYNTAX_DEFAULT.

EntryName

Points to an entry name at which the search for compatible binding handles begins.

To use the entry name specified in the registry value HKEY_LOCAL_MACHINE\Software\Microsoft\Rpc\NameService\
DefaultEntry, provide a null pointer or an empty string. In this case, the EntryNameSyntax parameter is ignored and the run-time library uses the default syntax EntryName.

IfSpec

Specifies a stub-generated data structure indicating the interface to import. If the interface specification has not been exported or is of no concern to the caller, specify a null value for this argument. In this case, the bindings returned are only guaranteed to be of a compatible and supported protocol sequence and to contain the specified object UUID. The desired interface may not be supported by the contacted server.

ObjUuid

Points to an optional object UUID.

For a non-nil UUID, compatible binding handles are returned from an entry only if the server has exported the specified object UUID.

When the ObjUuid argument has a null pointer value or a nil UUID, the returned binding handles contain one of the object UUIDs exported by the compatible server. If the server did not export any object UUIDs, the returned compatible binding handles contain a nil object UUID.

ImportContext

Specifies a returned name-service handle for use with the RpcNsBindingImportNext and RpcNsBindingImportDone routines.

Remarks

The RpcNsBindingImportBegin routine creates an import context for importing client-compatible binding handles for servers that offer the specified interface and object.

Before calling the RpcNsBindingImportNext routine, the client application must first call RpcNsBindingImportBegin to create an import context. The arguments to this routine control the operation of the RpcNsBindingImportNext routine.

When finished importing binding handles, the client application calls the RpcNsBindingImportDone routine to delete the import context.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_NAME_SYNTAX	Invalid name syntax
RPC_S_UNSUPPORTED_NAME_SYNTAX	Unsupported name syntax
RPC_S_INCOMPLETE_NAME	Incomplete name
RPC_S_ENTRY_NOT_FOUND	Name-service entry not found
RPC_S_NAME_SERVICE_UNAVAILABLE	Name service unavailable
RPC_S_INVALID_OBJECT	Invalid object
See Also

RpcNsBindingImportDone, RpcNsBindingImportNext


RpcNsBindingImportDone
RpcNsBindingImportDone   QuickInfo

The RpcNsBindingImportDone function signifies that a client has finished looking for a compatible server and deletes the import context.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcNsBindingImportDone(
RPC_NS_HANDLE *  ImportContext);

Parameter

ImportContext

Points to a name-service handle to free. The name-service handle ImportContext points to is created by calling the RpcNsBindingImportBegin routine.

An argument value of NULL is returned.

Remarks

The RpcNsBindingImportDone routine frees an import context created by calling the RpcNsBindingImportBegin routine.

Typically, a client application calls RpcNsBindingImportDone after completing remote procedure calls to a server using a binding handle returned from the RpcNsBindingImportNext routine. However, a client application is responsible for calling RpcNsBindingImportDone for each created import context regardless of the status returned from the RpcNsBindingImportNext routine or the success in making remote procedure calls.

Return Values

Value	Meaning
RPC_S_OK	Success
See Also

RpcNsBindingImportBegin, RpcNsBindingImportNext


RpcNsBindingImportNext
RpcNsBindingImportNext   QuickInfo

The RpcNsBindingImportNext function looks up an interface, and optionally an object, from a name-service database and returns a binding handle of a compatible server (if found).

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcNsBindingImportNext(
RPC_NS_HANDLE  ImportContext,
RPC_BINDING_HANDLE *  Binding);

Parameters

ImportContext

Specifies a name-service handle returned from the RpcNsBindingImportBegin routine.

Binding

Returns a pointer to a client-compatible server binding handle for a server.

Remarks

The RpcNsBindingImportNext routine returns one client-compatible server binding handle for a server offering the interface and object UUID specified by the IfSpec and ObjUuid arguments in the RpcNsBindingImportBegin routine. The RpcNsBindingImportNext routine communicates only with the name-service database, not directly with servers.

The returned compatible binding handle always contains an object UUID. Its value depends on the ObjUuid argument value specified in the RpcNsBindingImportBegin routine as follows:

•	If a non-nil object UUID was specified, the returned binding handle contains that object UUID.

•	If a nil object UUID or null value was specified, the object UUID returned in the binding handle depends on how the server exported object UUIDs:

•	If the server did not export any object UUIDs, the returned binding handle contains a nil object UUID.

•	If the server exported one object UUID, the returned binding handle contains that object UUID.

•	If the server exported multiple object UUIDs, the returned binding handle contains one of the object UUIDs. The import-next operation selects the returned object UUID in a non-deterministic fashion. As a result, a different object UUID can be returned for each compatible binding handle from a single server entry.

The RpcNsBindingImportNext routine selects and returns one server binding handle from the compatible binding handles found. The client application can use that binding handle to attempt to make a remote procedure call to the server. If the client fails to establish a relationship with the server, it can call the RpcNsBindingImportNext routine again.

Each time the client calls the RpcNsBindingImportNext routine, the routine returns another server binding handle. The returned binding handles are unordered.

A client application calls the RpcNsBindingInqEntryName routine to obtain the name-service database in the entry name from which the binding handle came.

When the search reaches the end of the name-service database, the routine returns a status of RPC_S_NO_MORE_BINDINGS and returns a binding argument value of NULL.

The RpcNsBindingImportNext routine allocates storage for the data referenced by the returned Binding argument. When a client application finishes with the binding handle, it must call the RpcBindingFree routine to deallocate the storage. Each call to the RpcNsBindingImportNext routine requires a corresponding call to the RpcBindingFree routine.

The client is responsible for calling the RpcNsBindingImportDone routine. RpcNsBindingImportDone deletes the import context. The client also calls the RpcNsBindingImportDone routine if the application wants to start a new search for compatible servers (by calling the RpcNsBindingImportBegin routine). The order of binding handles returned is different for each new search. This means the order in which binding handles are returned to an application can be different each time the application is run.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_NO_MORE_BINDINGS	No more bindings
RPC_S_NAME_SERVICE_UNAVAILABLE	Name service unavailable
See Also

RpcBindingFree, RpcNsBindingImportBegin, RpcNsBindingImportDone, RpcNsBindingInqEntryName, RpcNsBindingLookupBegin, RpcNsBindingLookupDone, RpcNsBindingLookupNext, RpcNsBindingSelect


RpcNsBindingInqEntryName
RpcNsBindingInqEntryName   QuickInfo

The RpcNsBindingInqEntryName function returns the entry name from which the binding handle came.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcNsBindingInqEntryName(
RPC_BINDING_HANDLE  Binding,
unsigned long  EntryNameSyntax,
unsigned char * *  EntryName);

Parameters

Binding

Specifies the binding handle whose name-service database entry name is returned.

EntryNameSyntax

Specifies an unsigned long value that indicates the syntax used in the returned argument, EntryName.

To use the syntax specified in the registry value HKEY_LOCAL_MACHINE\Software\Microsoft\Rpc\NameService\
DefaultSyntax, provide a value of RPC_C_NS_SYNTAX_DEFAULT.

EntryName

Returns a pointer to a pointer to the name of the name-service database entry in which Binding was found.

Specify a null value to prevent RpcNsBindingInqEntryName from returning the EntryName argument. In this case, the application does not call the RpcStringFree routine.

Remarks

The RpcNsBindingInqEntryName routine returns the name of the name-service database entry from which a client-compatible binding handle came.

The RPC run-time library allocates memory for the string returned in the EntryName argument. The application is responsible for calling the RpcStringFree routine to deallocate that memory.

An entry name is associated only with binding handles returned from the RpcNsBindingImportNext, RpcNsBindingLookupNext, and RpcNsBindingSelect routines.

If the binding handle specified in the Binding argument was not returned from a name-service database entry (for example, if the binding handle was created by calling RpcBindingFromStringBinding), RpcNsBindingInqEntryName returns an empty string ("\0") and an RPC_S_NO_ENTRY_NAME status code.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_BINDING	Invalid binding handle
RPC_S_NO_ENTRY_NAME	No entry name for binding
RPC_S_INVALID_NAME_SYNTAX	Invalid name syntax
RPC_S_UNSUPPORTED_NAME_SYNTAX	Unsupported name syntax
RPC_S_INCOMPLETE_NAME	Incomplete name
See Also

RpcBindingFromStringBinding, RpcNsBindingImportNext, RpcNsBindingLookupNext, RpcNsBindingSelect, RpcStringFree


RpcNsBindingLookupBegin
RpcNsBindingLookupBegin   QuickInfo

The RpcNsBindingLookupBegin function creates a lookup context for an interface and an object.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcNsBindingLookupBegin(
unsigned long  EntryNameSyntax,
unsigned char *  EntryName,
RPC_IF_HANDLE  IfSpec,
UUID *  ObjUuid,
unsigned long  BindingMaxCount,
RPC_NS_HANDLE *  LookupContext);

Parameters

EntryNameSyntax

Specifies an unsigned long value that indicates the syntax of the next argument, EntryName.

To use the syntax specified in the registry value HKEY_LOCAL_MACHINE\Software\Microsoft\Rpc\NameService\
DefaultSyntax, provide a value of RPC_C_NS_SYNTAX_DEFAULT.

EntryName

Points to an entry name at which the search for compatible bindings begins.

To use the entry name specified in the registry value HKEY_LOCAL_MACHINE\Software\Microsoft\Rpc\NameService\
DefaultEntry, provide a null pointer or an empty string. In this case, the EntryNameSyntax parameter is ignored and the run-time library uses the default syntax EntryName.

IfSpec

Specifies a stub-generated data structure indicating the interface to look up. If the interface specification has not been exported or is of no concern to the caller, specify a null value for this argument. In this case, the bindings returned are only guaranteed to be of a compatible and supported protocol sequence and to contain the specified object UUID. The desired interface may not be supported by the contacted server.

ObjUuid

Points to an optional object UUID.

For a non-nil UUID, compatible binding handles are returned from an entry only if the server has exported the specified object UUID.

For a null pointer value or a nil UUID for this argument, the returned binding handles contain one of the object UUIDs exported by the compatible server. If the server did not export any object UUIDs, the returned compatible binding handles contain a nil object UUID.

BindingMaxCount

Specifies the maximum number of bindings to return in the BindingVec argument from the RpcNsBindingLookupNext routine.

Specify a value of zero to use the default count of RPC_C_BINDING_MAX_COUNT_DEFAULT.

LookupContext

Returns a pointer to a name-service handle for use with the RpcNsBindingLookupNext and RpcNsBindingLookupDone routines.

Remarks

The RpcNsBindingLookupBegin routine creates a lookup context for locating client-compatible binding handles to servers that offer the specified interface and object.

Before calling the RpcNsBindingLookupNext routine, the client application must first call RpcNsBindingLookupBegin to create a lookup context. The arguments to this routine control the operation of the RpcNsBindingLookupNext routine.

When finished locating binding handles, the client application calls the RpcNsBindingLookupDone routine to delete the lookup context.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_NAME_SYNTAX	Invalid name syntax
RPC_S_UNSUPPORTED_NAME_SYNTAX	Unsupported name syntax
RPC_S_INCOMPLETE_NAME	Incomplete name
RPC_S_ENTRY_NOT_FOUND	Name-service entry not found
RPC_S_NAME_SERVICE_UNAVAILABLE	Name service unavailable
RPC_S_INVALID_OBJECT	Invalid object
See Also

RpcNsBindingLookupDone, RpcNsBindingLookupNext


RpcNsBindingLookupDone
RpcNsBindingLookupDone   QuickInfo

The RpcNsBindingLookupDone function signifies that a client has finished looking for compatible servers and deletes the lookup context.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcNsBindingLookupDone(
RPC_NS_HANDLE *  LookupContext);

Parameter

LookupContext

Points to the name-service handle to free. The name-service handle LookupContext points to is created by calling the routine RpcNsBindingLookupBegin.

An argument value of NULL is returned.

Remarks

The RpcNsBindingLookupDone routine frees a lookup context created by calling the RpcNsBindingLookupBegin routine.

Typically, a client application calls RpcNsBindingLookupDone after completing remote procedure calls to a server using a binding handle returned from the RpcNsBindingLookupNext routine. However, a client application is responsible for calling RpcNsBindingLookupDone for each created lookup context, regardless of the status returned from the RpcNsBindingLookupNext routine or the success in making remote procedure calls.

Return Values

Value	Meaning
RPC_S_OK	Success
See Also

RpcNsBindingLookupBegin, RpcNsBindingLookupNext


RpcNsBindingLookupNext
RpcNsBindingLookupNext   QuickInfo

The RpcNsBindingLookupNext function returns a list of compatible binding handles for a specified interface and optionally an object.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcNsBindingLookupNext(
RPC_NS_HANDLE  LookupContext,
RPC_BINDING_VECTOR * *  BindingVec);

Parameters

LookupContext

Specifies the name-service handle returned from the RpcNsBindingLookupBegin routine.

BindingVec

Returns a pointer to a pointer to a vector of client-compatible server binding handles.

Remarks

The RpcNsBindingLookupNext routine returns a vector of client-compatible server binding handles for a server offering the interface and object UUID specified by the IfSpec and ObjUuid arguments in the RpcNsBindingLookupBegin routine.

The RpcNsBindingLookupNext routine communicates only with the name-service database, not directly with servers.

The RpcNsBindingLookupNext routine traverses name-service database entries collecting client-compatible server binding handles from each entry. If the entry at which the search begins (see the EntryName argument in RpcNsBindingLookupBegin) contains binding handles as well as an RPC group and/or a profile, RpcNsBindingLookupNext returns the binding handles from EntryName before searching the group or profile. This means that RpcNsBindingLookupNext can return a partially full vector before processing the members of the group or profile. Each binding handle in the returned vector always contains an object UUID. Its value depends on the ObjUuid argument value specified in the RpcNsBindingLookupBegin routine as follows:

•	If a non-nil object UUID was specified, each returned binding handle contains that object UUID.

•	If a nil object UUID or null value was specified, the object UUID returned in each binding handle depends on how the server exported object UUIDs:

•	If the server did not export any object UUIDs, each returned binding handle contains a nil object UUID.

•	If the server exported one object UUID, each returned binding handle contains that object UUID.

•	If the server exported multiple object UUIDs, each binding handle contains one of the object UUIDs. The lookup-next operation selects the returned object UUID in a non-deterministic fashion. For this reason, a different object UUID can be returned for each compatible binding handle from a single server entry.

From the returned vector of server binding handles, the client application can employ its own criteria for selecting individual binding handles, or the application can call the RpcNsBindingSelect routine to select a binding handle. The RpcBindingToStringBinding and RpcStringBindingParse routines will be helpful for a client creating its own selection criteria.

The client application can use the selected binding handle to attempt to make a remote procedure call to the server. If the client fails to establish a relationship with the server, it can select another binding handle from the vector. When all of the binding handles in the vector have been used, the client application calls the RpcNsBindingLookupNext routine again.

Each time the client calls the RpcNsBindingLookupNext routine, the routine returns another vector of binding handles. The binding handles returned in each vector are unordered. The vectors returned from multiple calls to this routine are also unordered.

A client calls the RpcNsBindingInqEntryName routine to obtain the name-service database server entry name that the binding came from.

When the search reaches the end of the name-service database, RpcNsBindingLookupNext returns a status of RPC_S_NO_MORE_BINDINGS and returns a BindingVec argument value of NULL.

The RpcNsBindingLookupNext routine allocates storage for the data referenced by the returned BindingVec argument. When a client application finishes with the vector, it must call the RpcBindingVectorFree routine to deallocate the storage. Each call to the RpcNsBindingLookupNext routine requires a corresponding call to the RpcBindingVectorFree routine.

The client is responsible for calling the RpcNsBindingLookupDone routine. RpcNsBindingLookupDone deletes the lookup context. The client also calls the RpcNsBindingLookupDone routine if the application wants to start a new search for compatible servers (by calling the RpcNsBindingLookupBegin routine). The order of binding handles returned can be different for each new search.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_NO_MORE_BINDINGS	No more bindings
RPC_S_NAME_SERVICE_UNAVAILABLE	Name-service unavailable
See Also

RpcBindingToStringBinding, RpcBindingVectorFree, RpcNsBindingInqEntryName, RpcNsBindingLookupBegin, RpcNsBindingLookupDone, RpcStringBindingParse


RpcNsBindingSelect
RpcNsBindingSelect   QuickInfo

The RpcNsBindingSelect function returns a binding handle from a list of compatible binding handles.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcNsBindingSelect(
RPC_BINDING_VECTOR *  BindingVec,
RPC_BINDING_HANDLE *  Binding);

Parameters

BindingVec

Points to the vector of client-compatible server binding handles from which a binding handle is selected. The returned binding vector no longer references the selected binding handle, which is returned separately in the Binding argument.

Binding

Returns a pointer to a selected binding handle.

Remarks

The RpcNsBindingSelect routine chooses and returns a client-compatible server binding handle from a vector of server binding handles.

Each time the client calls the RpcNsBindingSelect routine, the routine operation returns another binding handle from the vector.

When all of the binding handles have been returned from the vector, the routine returns a status of RPC_S_NO_MORE_BINDINGS and returns a Binding argument value of NULL.

The select operation allocates storage for the data referenced by the returned Binding argument. When a client finishes with the binding handle, it should call the RpcBindingFree routine to deallocate the storage. Each call to the RpcNsBindingSelect routine requires a corresponding call to the RpcBindingFree routine.

Clients can create their own select routines implementing application-specific selection criteria. In this case, the RpcStringBindingParse routine provides access to the fields of a binding.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_NO_MORE_BINDINGS	No more bindings
See Also

RpcBindingFree, RpcNsBindingLookupNext, RpcStringBindingParse


RpcNsBindingUnexport
RpcNsBindingUnexport   QuickInfo

The RpcNsBindingUnexport function removes the binding handles for an interface and objects from an entry in the name-service database.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcNsBindingUnexport(
unsigned long  EntryNameSyntax,
unsigned char *  EntryName,
RPC_IF_HANDLE  IfSpec,
UUID_VECTOR *  ObjectUuidVec);

This function is supported by both the 32-bit Windows NT and Windows 95 platforms.

Parameters

EntryNameSyntax

Specifies an unsigned long value that indicates the syntax of the next argument, EntryName.

To use the syntax specified in the registry value HKEY_LOCAL_MACHINE\Software\Microsoft\Rpc\NameService\
DefaultSyntax, provide a value of RPC_C_NS_SYNTAX_DEFAULT.

EntryName

Points to the entry name from which to remove binding handles and object UUIDs.

IfSpec

Specifies an interface. A null argument value indicates not to unexport any binding handles (only object UUIDs are to be unexported).

ObjectUuidVec

Points to a vector of object UUIDs that the server no longer wants to offer. The application constructs this vector. A null argument value indicates there are no object UUIDs to unexport (only binding handles are to be unexported).

Remarks

The RpcNsBindingUnexport routine allows a server application to remove the following from a name-service database entry:

•	All the binding handles for a specific interface

•	One or more object UUIDs of resources

•	Both the binding handles and object UUIDs of resources

The RpcNsBindingUnexport routine unexports only the binding handles that match the interface UUID and the major and minor interface version numbers found in the IfSpec argument.

A server application can unexport the specified interface and objects in a single call to RpcNsBindingUnexport, or it can unexport them separately.

If RpcNsBindingUnexport does not find any binding handles for the specified interface, the routine returns an RPC_S_INTERFACE_NOT_FOUND status code and does not unexport the object UUIDs, if any were specified.

If one or more binding handles for the specified interface are found and unexported without error, RpcNsBindingUnexport unexports the specified object UUIDs, if any.

If any of the specified object UUIDs were not found, RpcNsBindingUnexport returns the RPC_S_NOT_ALL_OBJS_UNEXPORTED status code.

In addition to calling RpcNsBindingUnexport, a server should also call the RpcEpUnregister routine to unregister the endpoints the server previously registered with the local endpoint-map database.

A server entry must have at least one binding handle to exist. As a result, exporting only UUIDs to a non-existing entry has no effect, and unexporting all binding handles deletes the entry.

Use RpcNsBindingUnexport judiciously. To keep an automatically activated server available, you must leave its binding handles in the name-service database between the times when server processes are activated. Therefore, reserve this routine for when you expect a server to be unavailable for an extended time — for example, when it is being permanently removed from service.

Note  Name-service databases are designed to be relatively stable. In replicated name-service databases, frequent use of the RpcNsBindingExport and RpcNsBindingUnexport routines causes the name-service database to repeatedly remove and replace the same entry and can cause performance problems.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_VERS_OPTION	Invalid version option
RPC_S_NOTHING_TO_UNEXPORT	Nothing to unexport
RPC_S_INVALID_NAME_SYNTAX	Invalid name syntax
RPC_S_UNSUPPORTED_NAME_SYNTAX	Unsupported name syntax
RPC_S_INCOMPLETE_NAME	Incomplete name
RPC_S_ENTRY_NOT_FOUND	Name-service entry not found
RPC_S_NAME_SERVICE_UNAVAILABLE	Name service unavailable
RPC_S_INTERFACE_NOT_FOUND	Interface not found
RPC_S_NOT_ALL_OBJS_UNEXPORTED	Not all objects unexported
See Also

RpcEpUnregister, RpcNsBindingExport


RpcNsEntryExpandName
RpcNsEntryExpandName   QuickInfo

The RpcNsEntryExpandName function expands a name-service entry name.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcNsEntryExpandName(
unsigned long  EntryNameSyntax,
unsigned char *  EntryName,
unsigned char * *  ExpandedName);

Parameters

EntryNameSyntax

Specifies an integer value that indicates the syntax of the next argument, EntryName.

To use the syntax specified in the registry value HKEY_LOCAL_MACHINE\Software\Microsoft\Rpc\NameService\
DefaultSyntax, provide a value of RPC_C_NS_SYNTAX_DEFAULT.

EntryName

Points to the entry name to expand.

ExpandedName

Returns a pointer to a pointer to the expanded version of EntryName.

Remarks

Note  This DCE function is not supported by the Microsoft Locator version 1.0.

An application calls the RpcNsEntryExpandName routine to obtain a fully expanded entry name.

The RPC run-time library allocates memory for the returned ExpandedName argument. The application is responsible for calling the RpcStringFree routine for that returned argument string.

The returned expanded entry name accounts for local name translations and for differences in locally defined naming schemas.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INCOMPLETE_NAME	Incomplete name
See Also

RpcStringFree


RpcNsEntryObjectInqBegin
RpcNsEntryObjectInqBegin   QuickInfo

The RpcNsEntryObjectInqBegin function creates an inquiry context for a name-service database entry's objects.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcNsEntryObjectInqBegin(
unsigned long  EntryNameSyntax,
unsigned char *  EntryName,
RPC_NS_HANDLE *  InquiryContext);

Parameters

EntryNameSyntax

Specifies an integer value that indicates the syntax to use in the next argument, EntryName.

To use the syntax specified in the registry value HKEY_LOCAL_MACHINE\Software\Microsoft\Rpc\NameService\
DefaultSyntax, provide a value of RPC_C_NS_SYNTAX_DEFAULT.

EntryName

Points to the name-service database entry name for which object UUIDs are to be viewed.

InquiryContext

Returns a pointer to a name-service handle for use with the RpcNsEntryObjectInqNext and RpcNsEntryObjectInqDone routines.

Remarks

The RpcNsEntryObjectInqBegin routine creates an inquiry context for viewing the object UUIDs exported to EntryName.

Before calling the RpcNsEntryObjectInqNext routine, the application must first call RpcNsEntryObjectInqBegin to create an inquiry context.

When finished viewing the object UUIDs, the application calls the RpcNsEntryObjectInqDone routine to delete the inquiry context.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_NAME_SYNTAX	Invalid name syntax
RPC_S_UNSUPPORTED_NAME_SYNTAX	Unsupported name syntax
RPC_S_INCOMPLETE_NAME	Incomplete name
RPC_S_ENTRY_NOT_FOUND	Name-service entry not found
RPC_S_NAME_SERVICE_UNAVAILABLE	Name service unavailable
See Also

RpcNsBindingExport, RpcNsEntryObjectInqDone, RpcNsEntryObjectInqNext


RpcNsEntryObjectInqDone
RpcNsEntryObjectInqDone   QuickInfo

The RpcNsEntryObjectInqDone function deletes the inquiry context for a name-service database entry's objects.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcNsEntryObjectInqDone(
RPC_NS_HANDLE *  InquiryContext);

Parameter

InquiryContext

Points to a name-service handle specifying the object UUIDs exported to the EntryName argument specified in the RpcNsEntryObjectInqBegin routine.

An argument value of NULL is returned.

Remarks

The RpcNsEntryObjectInqDone routine frees an inquiry context created by calling the RpcNsEntryObjectInqBegin routine.

An application calls RpcNsEntryObjectInqDone after viewing exported object UUIDs using the RpcNsEntryObjectInqNext routine.

Return Values

Value	Meaning
RPC_S_OK	Success
See Also

RpcNsEntryObjectInqBegin, RpcNsEntryObjectInqNext


RpcNsEntryObjectInqNext
RpcNsEntryObjectInqNext   QuickInfo

The RpcNsEntryObjectInqNext function returns one object at a time from a name-service database entry.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcNsEntryObjectInqNext(
RPC_NS_HANDLE  InquiryContext,
UUID *  ObjUuid);

Parameters

InquiryContext

Specifies a name-service handle that indicates the object UUIDs for a name-service database entry.

ObjUuid

Returns a pointer to an exported object UUID.

Remarks

The RpcNsEntryObjectInqNext routine returns one of the object UUIDs exported to the name-service database entry specified by the EntryName argument in the RpcNsEntryObjectInqBegin routine.

An application can view all of the exported object UUIDs by repeatedly calling the RpcNsEntryObjectInqNext routine. When all the object UUIDs have been viewed, this routine returns an RPC_S_NO_MORE_MEMBERS status code. The returned object UUIDs are unordered.

The application supplies the memory for the object UUID returned in the ObjUuid argument.

After viewing the object UUIDs, the application must call the RpcNsEntryObjectInqDone routine to release the inquiry context.

The order in which object UUIDs are returned can be different for each viewing of an entry. This means that the order in which object UUIDs are returned to an application can be different each time the application is run.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_NO_MORE_MEMBERS	No more members
RPC_S_INCOMPLETE_NAME	Incomplete name
RPC_S_ENTRY_NOT_FOUND	Name-service entry not found
RPC_S_NAME_SERVICE_UNAVAILABLE	Name-service unavailable
See Also

RpcNsBindingExport, RpcNsEntryObjectInqBegin, RpcNsEntryObjectInqDone


RpcNsGroupDelete
RpcNsGroupDelete   QuickInfo#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcNsGroupDelete(
unsigned long  GroupNameSyntax,
unsigned char *  GroupName);

The RpcNsGroupDelete function deletes a group attribute.

Parameters

GroupNameSyntax

Specifies an integer value that indicates the syntax of the next parameter, GroupName.

To use the syntax specified in the registry value HKEY_LOCAL_MACHINE\Software\Microsoft\Rpc\NameService\
DefaultSyntax, provide a value of RPC_C_NS_SYNTAX_DEFAULT.

GroupName

Points to the name of the RPC group to delete.

Remarks

Note  This DCE function is not supported by the Microsoft Locator.

The RpcNsGroupDelete routine deletes the group attribute from the specified name-service database entry.

Neither the specified name-service database entry nor the group members are deleted.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_NAME_SYNTAX	Invalid name syntax
RPC_S_UNSUPPORTED_NAME_SYNTAX	Unsupported name syntax
RPC_S_INCOMPLETE_NAME	Incomplete name
RPC_S_ENTRY_NOT_FOUND	Name-service entry not found
RPC_S_NAME_SERVICE_UNAVAILABLE	Name service unavailable
See Also

RpcNsGroupMbrAdd, RpcNsGroupMbrRemove


RpcNsGroupMbrAdd
RpcNsGroupMbrAdd   QuickInfo#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcNsGroupMbrAdd(
unsigned long  GroupNameSyntax,
unsigned char *  GroupName,
unsigned long  MemberNameSyntax,
unsigned char *  MemberName);

The RpcNsGroupMbrAdd function adds an entry name to a group. If necessary, it creates the entry.

Parameters

GroupNameSyntax

Specifies an integer value that indicates the syntax of the next argument, GroupName.

To use the syntax specified in the registry value HKEY_LOCAL_MACHINE\Software\Microsoft\Rpc\NameService\
DefaultSyntax, provide a value of RPC_C_NS_SYNTAX_DEFAULT.

GroupName

Points to the name of the RPC group to receive a new member.

MemberNameSyntax

Specifies an integer value that indicates the syntax to use in the MemberName argument.

To use the syntax specified in the registry value HKEY_LOCAL_MACHINE\Software\Microsoft\Rpc\NameService\
DefaultSyntax, provide a value of RPC_C_NS_SYNTAX_DEFAULT.

MemberName

Points to the name of the new RPC group member.

Remarks

Note  This DCE function is not supported by the Microsoft Locator.

The RpcNsGroupMbrAdd adds a name-service database entry name as a member to the RPC group attribute.

If the GroupName entry does not exist, RpcNsGroupMbrAdd tries to create the entry with a group attribute and adds the group member specified by the MemberName argument. In this case, the application must have the privilege to create the entry. Otherwise, a management application with the necessary privilege should create the entry by calling the RpcNsMgmtEntryCreate routine before the application is run.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_NAME_SYNTAX	Invalid name syntax
RPC_S_UNSUPPORTED_NAME_SYNTAX	Unsupported name syntax
RPC_S_INCOMPLETE_NAME	Incomplete name
RPC_S_NAME_SERVICE_UNAVAILABLE	Name service unavailable
See Also

RpcNsGroupMbrRemove, RpcNsMgmtEntryCreate


RpcNsGroupMbrInqBegin
RpcNsGroupMbrInqBegin   QuickInfo#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcNsGroupMbrInqBegin(
unsigned long  GroupNameSyntax,
unsigned char *  GroupName,
unsigned long  MemberNameSyntax,
RPC_NS_HANDLE *  InquiryContext);

The RpcNsGroupMbrInqBegin function creates an inquiry context for viewing group members.

Parameters

GroupNameSyntax

Specifies an integer value that indicates the syntax of the next argument, GroupName.

To use the syntax specified in the registry value HKEY_LOCAL_MACHINE\Software\Microsoft\Rpc\NameService\
DefaultSyntax, provide a value of RPC_C_NS_SYNTAX_DEFAULT.

GroupName

Points to the name of the RPC group to view.

MemberNameSyntax

Specifies an integer value that indicates the syntax of the return argument, MemberName, in the RpcNsGroupMbrInqNext routine.

To use the syntax specified in the registry value HKEY_LOCAL_MACHINE\Software\Microsoft\Rpc\NameService\
DefaultSyntax, provide a value of RPC_C_NS_SYNTAX_DEFAULT.

InquiryContext

Returns a pointer to a name-service handle for use with the RpcNsGroupMbrInqNext and RpcNsGroupMbrInqDone routines.

Remarks

Note  This DCE function is not supported by the Microsoft Locator.

The RpcNsGroupMbrInqBegin routine creates an inquiry context for viewing the members of an RPC group.

Before calling the RpcNsGroupMbrInqNext routine, the application must first call RpcNsGroupMbrInqBegin to create an inquiry context.

When finished viewing the RPC group members, the application calls the RpcNsGroupMbrInqDone routine to delete the inquiry context.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_NAME_SYNTAX	Invalid name syntax
RPC_S_UNSUPPORTED_NAME_SYNTAX	Unsupported name syntax
RPC_S_INCOMPLETE_NAME	Incomplete name
RPC_S_ENTRY_NOT_FOUND	Name-service entry not found
RPC_S_NAME_SERVICE_UNAVAILABLE	Name service unavailable
See Also

RpcNsGroupMbrAdd, RpcNsGroupMbrInqDone, RpcNsGroupMbrInqNext


RpcNsGroupMbrInqDone
RpcNsGroupMbrInqDone   QuickInfo#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcNsGroupMbrInqDone(
RPC_NS_HANDLE *  InquiryContext);

The RpcNsGroupMbrInqDone function deletes the inquiry context for a group.

Parameter

InquiryContext

Points to a name-service handle to free. An argument value of NULL is returned.

Remarks

Note  This DCE function is not supported by the Microsoft Locator.

The RpcNsGroupMbrInqDone routine frees an inquiry context created by calling the RpcNsGroupMbrInqBegin routine.

An application calls RpcNsGroupMbrInqDone after viewing RPC group members using the RpcNsGroupMbrInqNext routine.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_NS_HANDLE	Invalid name-service handle
See Also

RpcNsGroupMbrInqBegin, RpcNsGroupMbrInqNext


RpcNsGroupMbrInqNext
RpcNsGroupMbrInqNext   QuickInfo#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcNsGroupMbrInqNext(
RPC_NS_HANDLE  InquiryContext,
unsigned char * *  MemberName);

The RpcNsGroupMbrInqNext function returns one entry name from a group at a time.

Parameters

InquiryContext

Specifies a name-service handle.

MemberName

Returns a pointer to a pointer to an RPC group member name.

The syntax of the returned name was specified by the MemberNameSyntax argument in the RpcNsGroupMbrInqBegin routine.

Specify a null value to prevent RpcNsGroupMbrInqNext from returning the MemberName argument. In this case, the application does not call the RpcStringFree routine.

Remarks

Note  This DCE function is not supported by the Microsoft Locator.

The RpcNsGroupMbrInqNext routine returns one member of the RPC group specified by the GroupName argument in the RpcNsGroupMbrInqBegin routine.

An application can view all the members of an RPC group set by repeatedly calling the RpcNsGroupMbrInqNext routine. When all the group members have been viewed, this routine returns an RPC_S_NO_MORE_MEMBERS status code. The returned group members are unordered.

On each call to RpcNsGroupMbrInqNext that returns a member name, the RPC run-time library allocates memory for the returned MemberName. The application is responsible for calling the RpcStringFree routine for each returned MemberName string.

After viewing the RPC group's members, the application must call the RpcNsGroupMbrInqDone routine to release the inquiry context.

The order in which group members are returned can be different for each viewing of a group. This means that the order in which group members are returned to an application can be different each time the application is run.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_NS_HANDLE	Invalid name-service handle
RPC_S_NO_MORE_MEMBERS	No more members
RPC_S_NAME_SERVICE_UNAVAILABLE	Name service unavailable
See Also

RpcNsGroupMbrInqBegin, RpcNsGroupMbrInqDone, RpcStringFree


RpcNsGroupMbrRemove
RpcNsGroupMbrRemove   QuickInfo#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcNsGroupMbrRemove(
unsigned long  GroupNameSyntax,
unsigned char *  GroupName,
unsigned long  MemberNameSyntax,
unsigned char *  MemberName);

The RpcNsGroupMbrRemove function removes an entry name from a group.

Parameters

GroupNameSyntax

Specifies an integer value that indicates the syntax of the next argument, GroupName.

To use the syntax specified in the registry value HKEY_LOCAL_MACHINE\Software\Microsoft\Rpc\NameService\
DefaultSyntax, provide a value of RPC_C_NS_SYNTAX_DEFAULT.

GroupName

Points to the name of the RPC group from which to remove the member name.

MemberNameSyntax

Specifies an integer value that indicates the syntax to use in the MemberName argument.

To use the syntax specified in the registry value HKEY_LOCAL_MACHINE\Software\Microsoft\Rpc\NameService\
DefaultSyntax, provide a value of RPC_C_NS_SYNTAX_DEFAULT.

MemberName

Points to the name of the member to remove from the RPC group attribute in the entry GroupName.

Remarks

Note  This DCE function is not supported by the Microsoft Locator.

The RpcNsGroupMbrRemove routine removes a member from the RPC group attribute in the GroupName argument.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_NAME_SYNTAX	Invalid name syntax
RPC_S_UNSUPPORTED_NAME_SYNTAX	Unsupported name syntax
RPC_S_INCOMPLETE_NAME	Incomplete name
RPC_S_ENTRY_NOT_FOUND	Name-service entry not found
RPC_S_NAME_SERVICE_UNAVAILABLE	Name service unavailable
RPC_S_GROUP_MEMBER_NOT_FOUND	Group member not found
See Also

RpcNsGroupMbrAdd


RpcNsMgmtBindingUnexport
RpcNsMgmtBindingUnexport   QuickInfo

The RpcNsMgmtBindingUnexport function removes multiple binding handles and objects from an entry in the name-service database.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcNsMgmtBindingUnexport(
unsigned long  EntryNameSyntax,
unsigned char *  EntryName,
RPC_IF_ID *  IfId,
unsigned long  VersOption,
UUID_VECTOR *  ObjectUuidVec);

Parameters

EntryNameSyntax

Specifies an integer value that indicates the syntax of the next argument, EntryName.

To use the syntax specified in the registry value HKEY_LOCAL_MACHINE\Software\Microsoft\Rpc\NameService\
DefaultSyntax, provide a value of RPC_C_NS_SYNTAX_DEFAULT.

EntryName

Points to the name of the entry from which to remove binding handles and object UUIDs.

IfId

Points to an interface identification. A null argument value indicates not to unexport any binding handles (only object UUIDs are to be unexported).

VersOption

Specifies how the RpcNsMgmtBindingUnexport routine uses the VersMajor and VersMinor fields of the IfId argument.

The following table describes valid values for the VersOption argument:

VersOption values	Description
RPC_C_VERS_ALL	Unexports all bindings for the interface UUID in IfId, regardless of the version numbers. For this value, specify 0 for both the major and minor versions in IfId.
RPC_C_VERS_IF_ID	Unexports the bindings for the compatible interface UUID in IfId with the same major version and with a minor version greater than or equal to the minor version in IfId.
RPC_C_VERS_EXACT	Unexports the bindings for the interface UUID in IfId with the same major and minor versions as in IfId.
RPC_C_VERS_MAJOR_ONLY	Unexports the bindings for the interface UUID in IfId with the same major version as in IfId (ignores the minor version). For this value, specify 0 for the minor version in IfId.
RPC_C_VERS_UPTO	Unexports the bindings that offer a version of the specified interface UUID less than or equal to the specified major and minor version. (For example, if the IfId contained V2.0 and the name-service database entry contained binding handles with the versions V1.3, V2.0, and V2.1, the RpcNsMgmtBindingUnexport routine unexports the binding handles with V1.3 and V2.0.)
ObjectUuidVec

Points to a vector of object UUIDs that the server no longer wants to offer. The application constructs this vector. A null argument value indicates there are no object UUIDs to unexport (only binding handles are to be unexported).

Remarks

The RpcNsMgmtBindingUnexport routine allows a management application to remove one of the following from a name-service database entry:

•	All the binding handles for a specified interface UUID, qualified by the interface version numbers (major and minor)

•	One or more object UUIDs of resources

•	Both binding handles and object UUIDs of resources

A management application can unexport interfaces and objects in a single call to RpcNsMgmtBindingUnexport, or it can unexport them separately.

If RpcNsMgmtBindingUnexport does not find any binding handles for the specified interface, the routine returns an RPC_S_INTERFACE_NOT_FOUND status code and does not unexport the object UUIDs, if any were specified.

If one or more binding handles for the specified interface are found and unexported without error, RpcNsMgmtBindingUnexport unexports the specified object UUIDs, if any.

If any of the specified object UUIDs were not found, RpcNsMgmtBindingUnexport returns the RPC_S_NOT_ALL_OBJS_UNEXPORTED status code.

In addition to calling RpcNsMgmtBindingUnexport, a management application should also call the RpcMgmtEpUnregister routine to unregister the servers that have registered with the endpoint-map database.

Note  Name-service databases are designed to be relatively stable. In replicated name services, frequent use of the RpcNsBindingExport and RpcNsBindingUnexport routines causes the name service to repeatedly remove and replace the same entry and can cause performance problems.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_VERS_OPTION	Invalid version option
RPC_S_NOTHING_TO_UNEXPORT	Nothing to unexport
RPC_S_INVALID_NAME_SYNTAX	Invalid name syntax
RPC_S_UNSUPPORTED_NAME_SYNTAX	Unsupported name syntax
RPC_S_INCOMPLETE_NAME	Incomplete name
RPC_S_ENTRY_NOT_FOUND	Name-service entry not found
RPC_S_NAME_SERVICE_UNAVAILABLE	Name service unavailable
RPC_S_INTERFACE_NOT_FOUND	Interface not found
RPC_S_NOT_ALL_OBJS_UNEXPORTED	Not all objects unexported
See Also

RpcMgmtEpUnregister, RpcNsBindingExport, RpcNsBindingUnexport


RpcNsMgmtEntryCreate
RpcNsMgmtEntryCreate   QuickInfo

The RpcNsMgmtEntryCreate function creates a name-service database entry.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcNsMgmtEntryCreate(
unsigned long  EntryNameSyntax,
unsigned char *  EntryName);

Parameters

EntryNameSyntax

Specifies an integer value that indicates the syntax of the next argument, EntryName.

To use the syntax specified in the registry value HKEY_LOCAL_MACHINE\Software\Microsoft\Rpc\NameService\
DefaultSyntax, provide a value of RPC_C_NS_SYNTAX_DEFAULT.

EntryName

Points to the name of the entry to create.

Remarks

Note  This DCE function is not supported by the Microsoft Locator.

The RpcNsMgmtEntryCreate routine creates an entry in the name-service database.

A management application can call RpcNsMgmtEntryCreate to create a name-service database entry for use by another application that does not itself have the necessary name-service database privileges to create an entry.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_NAME_SYNTAX	Invalid name syntax
RPC_S_UNSUPPORTED_NAME_SYNTAX	Unsupported name syntax
RPC_S_INCOMPLETE_NAME	Incomplete name
RPC_S_ENTRY_ALREADY_EXISTS	Name-service entry already exists
RPC_S_NAME_SERVICE_UNAVAILABLE	Name service unavailable
See Also

RpcNsMgmtEntryDelete


RpcNsMgmtEntryDelete
RpcNsMgmtEntryDelete   QuickInfo

The RpcNsMgmtEntryDelete function deletes a name-service database entry.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcNsMgmtEntryDelete(
unsigned long  EntryNameSyntax,
unsigned char *  EntryName);

Parameters

EntryNameSyntax

Specifies an integer value that indicates the syntax of the next argument, EntryName.

To use the syntax specified in the registry value HKEY_LOCAL_MACHINE\Software\Microsoft\Rpc\NameService\
DefaultSyntax, provide a value of RPC_C_NS_SYNTAX_DEFAULT.

EntryName

Points to the name of the entry to delete.

Remarks

The RpcNsMgmtEntryDelete routine removes an entry from the name-service database.

Management applications use this routine only when an entry is no longer needed — for example, when a server is being permanently removed from service.

Because name-service databases are designed to be relatively stable, the frequent use of the RpcNsMgmtEntryDelete routine in client or server applications can result in performance problems. Creating and deleting entries in client or server applications causes the name-service database to repeatedly remove and replace the same entry. This can lead to performance problems in replicated name-service databases.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_NAME_SYNTAX	Invalid name syntax
RPC_S_UNSUPPORTED_NAME_SYNTAX	Unsupported name syntax
RPC_S_INCOMPLETE_NAME	Incomplete name
RPC_S_ENTRY_NOT_FOUND	Name-service entry not found
RPC_S_NAME_SERVICE_UNAVAILABLE	Name service unavailable
RPC_S_NOT_RPC_ENTRY	Not an RPC entry
See Also

RpcNsMgmtEntryCreate


RpcNsMgmtEntryInqIfIds
RpcNsMgmtEntryInqIfIds   QuickInfo

The RpcNsMgmtEntryInqIfIds function returns the list of interfaces exported to a name-service database entry.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcNsMgmtEntryInqIfIds(
unsigned long  EntryNameSyntax,
unsigned char *  EntryName,
RPC_IF_ID_VECTOR * *  IfIdVec);

Parameters

EntryNameSyntax

Specifies an integer value that indicates the syntax of the next argument, EntryName.

To use the syntax specified in the registry value HKEY_LOCAL_MACHINE\Software\Microsoft\Rpc\NameService\
DefaultSyntax, provide a value of RPC_C_NS_SYNTAX_DEFAULT.

EntryName

Points to the name-service database entry name for which an interface identification vector is returned.

IfIdVec

Returns a pointer to a pointer to the interface-identification vector.

Remarks

The RpcNsMgmtEntryInqIfIds routine returns an interface-identification vector containing the interfaces of binding handles exported by a server to EntryName.

RpcNsMgmtEntryInqIfIds uses an expiration age of 0, causing an immediate update of the local copy of name-service data.

The calling application is responsible for calling the RpcIfIdVectorFree routine to release memory used by the vector.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_NAME_SYNTAX	Invalid name syntax
RPC_S_UNSUPPORTED_NAME_SYNTAX	Unsupported name syntax
RPC_S_INCOMPLETE_NAME	Incomplete name
RPC_S_ENTRY_NOT_FOUND	Name-service entry not found
RPC_S_NAME_SERVICE_UNAVAILABLE	Name service unavailable
See Also

RpcIfIdVectorFree, RpcIfInqId, RpcNsBindingExport


RpcNsMgmtHandleSetExpAge
RpcNsMgmtHandleSetExpAge   QuickInfo

The RpcNsMgmtHandleSetExpAge function sets the expiration age of a name-service handle for local copies of name-service data.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcNsMgmtHandleSetExpAge(
RPC_NS_HANDLE  NsHandle,
unsigned long  ExpirationAge);

Parameters

NsHandle

Specifies a name-service handle that an expiration age is set for. A name-service handle is returned from a name-service "begin" operation.

ExpirationAge

Specifies an integer value in seconds that sets the expiration age of local name-service data read by all "next" routines using the specified NsHandle argument.

An expiration age of 0 causes an immediate update of the local name-service data.

Remarks

The RpcNsMgmtHandleSetExpAge routine sets a handle-expiration age for a specified name-service handle (NsHandle). The expiration age is the amount of time that a local copy of data from a name-service attribute can exist before a request from the application for the attribute requires updating the local copy. When an application begins running, the RPC run-time library specifies a random value of two hours as the default expiration age. The default is global to the application. A handle-expiration age applies only to a specific name-service handle and temporarily overrides the current global expiration age.

Normally, you should avoid using RpcNsMgmtHandleSetExpAge; instead, you should rely on the application's global expiration age.

A handle-expiration age is used exclusively by name-service "next" operations (which read data from name-service attributes). A "next" operation normally starts by looking for a local copy of the attribute data being requested by an application. In the absence of a local copy, the "next" operation creates one with fresh attribute data from the name-service database. If a local copy already exists, the operation compares its actual age to the expiration age being used by the application (which in this case is the expiration age set for the name-service handle). If the actual age exceeds the handle-expiration age, the operation automatically tries to update the local copy with fresh attribute data. If updating is impossible, the old local data remains in place and the "next" operation fails, returning the RPC_S_NAME_SERVICE_UNAVAILABLE status code.

The scope of a handle-expiration age is a single series of "next" operations. The RpcNsMgmtHandleSetExpAge routine operates within the following context:

•	A "begin" operation creates a name-service handle.

•	A call to the RpcNsMgmtHandleSetExpAge routine creates an expiration age for the handle.

•	A series of "next" operations for the name-service handle uses the handle expiration age.

•	A "done" operation for the name-service handle deletes both the handle and its expiration age.

Setting the handle-expiration age to a small value causes the name-service "next" operations to frequently update local data for any name-service attribute requested by your application. For example, setting the expiration age to 0 forces the "next" operation to update local data for the name-service attribute requested by your application. Therefore, setting a small handle-expiration age can create performance problems for your application. Furthermore, if your application is using a remote name-service server, a small expiration age can adversely affect network performance for all applications.

Limit the use of RpcNsMgmtHandleSetExpAge to the following situations:

•	When you must always get accurate name-service data.

For example, during management operations to update a profile, you may need to always see the profile's current contents. In this case, before beginning to inquire about a profile, your application should call the RpcNsMgmtHandleSetExpAge routine and specify 0 for the ExpirationAge argument.

•	When a request using the default expiration age has failed, and your application needs to retry the operation.

For example, a client application using name-service "import" operations should first try to obtain bindings using the application's default expiration age. However, sometimes the "import-next" operation returns either no binding handles or an insufficient number of them. In this case, the client could retry the "import" operation and, after the RpcNsBindingImportBegin call, include a RpcNsMgmtHandleSetExpAge call and specify 0 for the ExpirationAge argument. When the client calls the "import-next" routine again, the small handle-expiration age causes the "import-next" operation to update the local attribute data.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_NAME_SERVICE_UNAVAILABLE	Name service unavailable
See Also

RpcNsBindingImportBegin, RpcNsMgmtInqExpAge, RpcNsMgmtSetExpAge


RpcNsMgmtInqExpAge
RpcNsMgmtInqExpAge   QuickInfo

The RpcNsMgmtInqExpAge function returns the global expiration age for local copies of name-service data.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcNsMgmtInqExpAge(
unsigned long *	ExpirationAge);

Parameter

ExpirationAge

Returns a pointer to the default expiration age, in seconds. This value is used by all name-service "read" operations (that is, all "next" operations).

Remarks

The RpcNsMgmtInqExpAge routine returns the expiration age that the application is using. The expiration age is the amount of time in seconds that a local copy of data from a name-service attribute can exist before a request from the application for the attribute requires updating the local copy. When an application begins running, the RPC run-time library specifies a random value of two hours as the default expiration age. The default is global to the application.

An expiration age is used by name-service "next" operations (which read data from name-service attributes). A "next" operation normally starts by looking for a local copy of the attribute data being requested by an application. In the absence of a local copy, the "next" operation creates one with fresh attribute data from the name-service database. If a local copy already exists, the operation compares its actual age to the expiration age being used by the application. If the actual age exceeds the expiration age, the operation automatically tries to update the local copy with fresh attribute data. If updating is impossible, the old local data remains in place and the "next" operation fails.

Applications normally should use only the default expiration age. For special cases, however, an application can substitute a user-supplied global expiration age for the default by calling the RpcNsMgmtSetExpAge routine. The RpcNsMgmtInqExpAge routine returns the current global expiration age, whether a default or a user-supplied value.

An application can also override the global expiration age temporarily by calling the RpcNsMgmtHandleSetExpAge routine.

Return Value

Value	Meaning
RPC_S_OK	Success
See Also

RpcNsMgmtHandleSetExpAge, RpcNsMgmtSetExpAge


RpcNsMgmtSetExpAge
RpcNsMgmtSetExpAge   QuickInfo

The RpcNsMgmtSetExpAge function modifies the application's global expiration age for local copies of name-service data.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcNsMgmtSetExpAge(
unsigned long  ExpirationAge);

Parameter

ExpirationAge

Specifies an integer value in seconds that indicates the default expiration age for local name-service data. This expiration age is applied to all name-service "read" operations (that is, all "next" operations).

An expiration age of 0 causes an immediate update of the local name-service data.

To reset the expiration age to an RPC-assigned random value of two hours, specify a value of RPC_C_NS_DEFAULT_EXP_AGE.

Remarks

The RpcNsMgmtSetExpAge routine modifies the global expiration age of an application. The expiration age is the amount of time that a local copy of data from a name-service attribute can exist before a request from the application for the attribute requires updating the local copy. When an application begins running, the RPC run-time library specifies a random value of between 8 and 12 hours as the default expiration age. The default is global to the application.

Normally, you should avoid using RpcNsMgmtSetExpAge; instead, you should rely on the default expiration age.

An expiration age is used by name-service "next" operations (which read data from name-service attributes). A "next" operation normally starts by looking for a local copy of the attribute data being requested by an application. In the absence of a local copy, the "next" operation creates one with fresh attribute data from the name-service database. If a local copy already exists, the operation compares its actual age to the expiration age being used by the application. If the actual age exceeds the expiration age, the operation automatically tries to update the local copy with fresh attribute data. If updating is impossible, the old local data remains in place and the "next" operation fails, returning the RPC_S_NAME_SERVICE_UNAVAILABLE status code.

Setting the expiration age to a small value causes the name-service "next" operations to frequently update local data for any name-service attribute requested by your application. For example, setting the expiration age to 0 forces all "next" operations to update local data for the name-service attribute requested by your application. Therefore, setting small expiration ages can create performance problems for your application and increase network traffic. Furthermore, if your application is using a remote name-service server, a small expiration age can adversely affect network performance for all applications.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_NAME_SERVICE_UNAVAILABLE	Name service unavailable
See Also

RpcNsMgmtHandleSetExpAge


RpcNsProfileDelete
RpcNsProfileDelete   QuickInfo

The RpcNsProfileDelete function deletes a profile attribute.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcNsProfileDelete(
unsigned long  ProfileNameSyntax,
unsigned char *  ProfileName);

Parameters

ProfileNameSyntax

Specifies an integer value that indicates the syntax of the next argument, ProfileName.

To use the syntax specified in the registry value HKEY_LOCAL_MACHINE\Software\Microsoft\Rpc\NameService\
DefaultSyntax, provide a value of RPC_C_NS_SYNTAX_DEFAULT.

ProfileName

Points to the name of the profile to delete.

Remarks

Note  This DCE function is not supported by the Microsoft Locator.

The RpcNsProfileDelete routine deletes the profile attribute from the specified name-service entry (ProfileName).

Neither ProfileName nor the entry names included as members in each profile element are deleted.

Use RpcNsProfileDelete cautiously; deleting a profile can have the unwanted effect of breaking a hierarchy of profiles.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_NAME_SYNTAX	Invalid name syntax
RPC_S_UNSUPPORTED_NAME_SYNTAX	Unsupported name syntax
RPC_S_INCOMPLETE_NAME	Incomplete name
RPC_S_ENTRY_NOT_FOUND	Name-service entry not found
RPC_S_NAME_SERVICE_UNAVAILABLE	Name service unavailable
See Also

RpcNsProfileEltAdd, RpcNsProfileEltRemove


RpcNsProfileEltAdd
RpcNsProfileEltAdd   QuickInfo

The RpcNsProfileEltAdd function adds an element to a profile. If necessary, it creates the entry.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcNsProfileEltAdd(
unsigned long  ProfileNameSyntax,
unsigned char *  ProfileName,
RPC_IF_ID *  IfId,
unsigned long  MemberNameSyntax,
unsigned char *  MemberName,
unsigned long  Priority,
unsigned char *  Annotation);

Parameters

ProfileNameSyntax

Specifies an integer value that indicates the syntax of the next argument, ProfileName.

To use the syntax specified in the registry value HKEY_LOCAL_MACHINE\Software\Microsoft\Rpc\NameService\
DefaultSyntax, provide a value of RPC_C_NS_SYNTAX_DEFAULT.

ProfileName

Points to the name of the profile to receive a new element.

IfId

Points to the interface identification of the new profile element. To add or replace the default profile element, specify a null value.

MemberNameSyntax

Specifies an integer value that indicates the syntax of the next argument, MemberName.

To use the syntax specified in the registry value HKEY_LOCAL_MACHINE\Software\Microsoft\Rpc\NameService\
DefaultSyntax, provide a value of RPC_C_NS_SYNTAX_DEFAULT.

MemberName

Points to a name-service entry name to include in the new profile element.

Priority

Specifies an integer value (0 through 7) that indicates the relative priority for using the new profile element during the "import" and "lookup" operations. A value of 0 is the highest priority; a value of 7 is the lowest priority.

When adding a default profile member, use a value of 0.

Annotation

Points to an annotation string stored as part of the new profile element. The string can be up to 17 characters long. Specify a null value or a null-terminated string if there is no annotation string.

The string is used by applications for informational purposes only. For example, an application can use this string to store the interface-name string specified in the IDL file.

RPC does not use the annotation string during "lookup" or "import" operations or for enumerating profile elements.

Remarks

Note  This DCE function is not supported by the Microsoft Locator.

The RpcNsProfileEltAdd routine adds an element to the profile attribute of the
name-service entry specified by the ProfileName argument.

If the ProfileName entry does not exist, RpcNsProfileEltAdd tries to create the entry with a profile attribute and adds the profile element specified by the IfId, MemberName, Priority, and Annotation arguments. In this case, the application must have the privilege to create the entry. Otherwise, a management application with the necessary privileges should create the entry by calling the RpcNsMgmtEntryCreate routine before the application is run.

If an element with the specified member name and interface identification is already in the profile, RpcNsProfileEltAdd updates the element's priority and annotation string using the values provided in the Priority and Annotation arguments.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_NAME_SYNTAX	Invalid name syntax
RPC_S_UNSUPPORTED_NAME_SYNTAX	Unsupported name syntax
RPC_S_INCOMPLETE_NAME	Incomplete name
RPC_S_NAME_SERVICE_UNAVAILABLE	Name service unavailable
See Also

RpcIfInqId, RpcNsMgmtEntryCreate, RpcNsProfileEltRemove


RpcNsProfileEltInqBegin
RpcNsProfileEltInqBegin   QuickInfo

The RpcNsProfileEltInqBegin function creates an inquiry context for viewing the elements in a profile.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcNsProfileEltInqBegin(
unsigned long  ProfileNameSyntax,
unsigned char *  ProfileName,
unsigned long  InquiryType,
RPC_IF_ID *  IfId,
unsigned long  VersOption,
unsigned long  MemberNameSyntax,
unsigned char *  MemberName,
RPC_NS_HANDLE *  InquiryContext);

Parameters

ProfileNameSyntax

Specifies an integer value that indicates the syntax of the next argument, ProfileName.

To use the syntax specified in the registry value HKEY_LOCAL_MACHINE\Software\Microsoft\Rpc\NameService\
DefaultSyntax, provide a value of RPC_C_NS_SYNTAX_DEFAULT.

ProfileName

Points to the name of the profile to view.

InquiryType

Specifies an integer value indicating the type of inquiry to perform on the profile. The following table lists valid inquiry types:

Inquiry type	Description
RPC_C_PROFILE_DEFAULT_ELT	Searches the profile for the default profile element, if any. The IfId, VersOption, and MemberName arguments are ignored.
RPC_C_PROFILE_ALL_ELTS	Returns every element from the profile. The IfId, VersOption, and MemberName arguments are ignored.
RPC_C_PROFILE_MATCH_BY_IF	Searches the profile for the elements that contain the interface identification specified by the IfId and VersOption values. The MemberName argument is ignored.
RPC_C_PROFILE_MATCH_ BY_MBR	Searches the profile for the elements that contain the member name specified by the MemberName argument. The IfId and VersOption arguments are ignored.
RPC_C_PROFILE_MATCH_ BY_BOTH	Searches the profile for the elements that contain the interface identification and member identified by the IfId, VersOption, and MemberName arguments.
IfId

Points to the interface identification of the profile elements to be returned by the RpcNsProfileEltInqNext routine.

The IfId argument is used only when specifying a value of RPC_C_PROFILE_MATCH_BY_IF or RPC_C_PROFILE_MATCH_BY_BOTH for the InquiryType argument. Otherwise, IfId is ignored and a null value can be specified.

VersOption

Specifies how the RpcNsProfileEltInqNext routine uses the IfId argument.

The VersOption argument is used only when specifying a value of RPC_C_PROFILE_MATCH_BY_IF or RPC_C_PROFILE_MATCH_BY_BOTH for the InquiryType argument. Otherwise, this argument is ignored and a 0 value can be specified.

The following table describes valid values for the VersOption argument.

Values	Description
RPC_C_VERS_ALL	Returns profile elements that offer the specified interface UUID, regardless of the version numbers. For this value, specify 0 for both the major and minor versions in IfId.
RPC_C_VERS_COMPATIBLE	Returns profile elements that offer the same major version of the specified interface UUID and a minor version greater than or equal to the minor version of the specified interface UUID.
RPC_C_VERS_EXACT	Returns profile elements that offer the specified version of the specified interface UUID.
RPC_C_VERS_MAJOR_ONLY	Returns profile elements that offer the same major version of the specified interface UUID (ignores the minor version). For this value, specify 0 for the minor version in IfId.
RPC_C_VERS_UPTO	Returns profile elements that offer a version of the specified interface UUID less than or equal to the specified major and minor version. (For example, if the IfId contained V2.0 and the profile contained elements with V1.3, V2.0, and V2.1, the RpcNsProfileEltInqNext routine returns the elements with V1.3 and V2.0.)
MemberNameSyntax

Specifies an integer value that indicates the syntax of the next argument, MemberName, and of the return argument MemberName in the RpcNsProfileEltInqNext routine.

To use the syntax specified in the registry value HKEY_LOCAL_MACHINE\Software\Microsoft\Rpc\NameService\
DefaultSyntax, provide a value of RPC_C_NS_SYNTAX_DEFAULT.

MemberName

Points to the member name that the RpcNsProfileEltInqNext routine looks for in profile elements.

The MemberName argument is used only when specifying a value of RPC_C_PROFILE_MATCH_BY_MBR or RPC_C_PROFILE_MATCH_BY_BOTH for the InquiryType argument. Otherwise, MemberName is ignored and a null value can be specified.

InquiryContext

Returns a pointer to a name-service handle for use with the RpcNsProfileEltInqNext and RpcNsProfileEltInqDone routines.

Remarks

Note  This DCE function is not supported by the Microsoft Locator.

The RpcNsProfileEltInqBegin routine creates an inquiry context for viewing the elements in a profile.

Using the InquiryType argument, an application specifies which of the following profile elements are to be returned from calls to the RpcNsProfileEltInqNext routine:

•	The default element

•	All elements

•	Elements with the specified interface identification

•	Elements with the specified member name

•	Elements with both the specified interface identification and member name

Before calling the RpcNsProfileEltInqNext routine, the application must first call RpcNsProfileEltInqBegin to create an inquiry context.

When finished viewing the profile elements, the application calls the RpcNsProfileEltInqDone routine to delete the inquiry context.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_VERS_OPTION	Invalid version option
RPC_S_INVALID_NAME_SYNTAX	Invalid name syntax
RPC_S_UNSUPPORTED_NAME_SYNTAX	Unsupported name syntax
RPC_S_INCOMPLETE_NAME	Incomplete name
RPC_S_ENTRY_NOT_FOUND	Name-service entry not found
RPC_S_NAME_SERVICE_UNAVAILABLE	Name service unavailable
See Also

RpcIfInqId, RpcNsProfileEltInqDone, RpcNsProfileEltInqNext


RpcNsProfileEltInqDone
RpcNsProfileEltInqDone   QuickInfo

The RpcNsProfileEltInqDone function deletes the inquiry context for viewing the elements in a profile.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcNsProfileEltInqDone(
RPC_NS_HANDLE *  InquiryContext);

Parameter

InquiryContext

Points to a name-service handle to free. The name-service handle InquiryContext points to is created by calling the RpcNsProfileEltInqBegin routine.

An argument value of NULL is returned.

Remarks

Note  This DCE function is not supported by the Microsoft Locator.

The RpcNsProfileEltInqDone routine frees an inquiry context created by calling the RpcNsProfileEltInqBegin routine.

An application calls RpcNsProfileEltInqDone after viewing profile elements using the RpcNsProfileEltInqNext routine.

Return Value

Value	Meaning
RPC_S_OK	Success
See Also

RpcNsProfileEltInqBegin, RpcNsProfileEltInqNext


RpcNsProfileEltInqNext
RpcNsProfileEltInqNext   QuickInfo

The RpcNsProfileEltInqNext function returns one element at a time from a profile.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcNsProfileEltInqNext(
RPC_NS_HANDLE  InquiryContext,
RPC_IF_ID *  IfId,
unsigned char * *  MemberName,
unsigned long *	  Priority,
unsigned char * *  Annotation);

Parameters

InquiryContext

Specifies a name-service handle returned from the RpcNsProfileEltInqBegin routine.

IfId

Returns a pointer to the interface identification of the profile element.

MemberName

Returns a pointer to a pointer to the profile element's member name.

The syntax of the returned name was specified by the MemberNameSyntax argument in the RpcNsProfileEltInqBegin routine.

Specify a null value to prevent RpcNsProfileEltInqNext from returning the MemberName argument. In this case, the application does not call the RpcStringFree routine.

Priority

Returns a pointer to the profile-element priority.

Annotation

Returns a pointer to a pointer to the annotation string for the profile element. If there is no annotation string in the profile element, the string "\0" is returned.

Specify a null value to prevent RpcNsProfileEltInqNext from returning the Annotation argument. In this case, the application does not need to call the RpcStringFree routine.

Remarks

Note  This DCE function is not supported by the Microsoft Locator.

The RpcNsProfileEltInqNext routine returns one element from the profile specified by the ProfileName argument in the RpcNsProfileEltInqBegin routine. Regardless of the value specified for the InquiryType argument in RpcNsProfileEltInqBegin, RpcNsProfileEltInqNext returns all the components (interface identification, member name, priority, annotation string) of a profile element.

An application can view all the selected profile entries by repeatedly calling the RpcNsProfileEltInqNext routine. When all the elements have been viewed, this routine returns a RPC_S_NO_MORE_ELEMENTS status code. The returned elements are unordered.

On each call to RpcNsProfileEltInqNext that returns a profile element, the RPC run-time library allocates memory for the returned member name and annotation string. The application is responsible for calling the RpcStringFree routine for each returned member name and annotation string.

After viewing the profile's elements, the application must call the RpcNsProfileEltInqDone routine to release the inquiry context.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INCOMPLETE_NAME	Incomplete name
RPC_S_NAME_SERVICE_UNAVAILABLE	Name service unavailable
RPC_S_NO_MORE_ELEMENTS	No more elements
See Also

RpcNsProfileEltInqBegin, RpcNsProfileEltInqDone, RpcStringFree


RpcNsProfileEltRemove
RpcNsProfileEltRemove   QuickInfo

The RpcNsProfileEltRemove function removes an element from a profile.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcNsProfileEltRemove(
unsigned long  ProfileNameSyntax,
unsigned char *  ProfileName,
RPC_IF_ID *  IfId,
unsigned long  MemberNameSyntax,
unsigned char *  MemberName);

Parameters

ProfileNameSyntax

Specifies an integer value that indicates the syntax of the next argument, ProfileName.

To use the syntax specified in the registry value HKEY_LOCAL_MACHINE\Software\Microsoft\Rpc\NameService\
DefaultSyntax, provide a value of RPC_C_NS_SYNTAX_DEFAULT.

ProfileName

Points to the name of the profile from which to remove an element.

IfId

Points to the interface identification of the profile element to be removed.

Specify a null value to remove the default profile member.

MemberNameSyntax

Specifies an integer value that indicates the syntax of the next argument, MemberName.

To use the syntax specified in the registry value HKEY_LOCAL_MACHINE\Software\Microsoft\Rpc\NameService\
DefaultSyntax, provide a value of RPC_C_NS_SYNTAX_DEFAULT.

MemberName

Points to the name-service entry name in the profile element to remove.

Remarks

Note  This DCE function is not supported by the Microsoft Locator.

The RpcNsProfileEltRemove routine removes a profile element from the profile attribute in the ProfileName entry. The RpcNsProfileEltRemove routine requires an exact match of the MemberName and IfId arguments in order to remove a profile element.

The entry (MemberName) included as a member in the profile element is not deleted.

Use RpcNsProfileEltRemove cautiously: removing elements from a profile can have the unwanted effect of breaking a hierarchy of profiles.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_NAME_SYNTAX	Invalid name syntax
RPC_S_UNSUPPORTED_NAME_SYNTAX	Unsupported name syntax
RPC_S_INCOMPLETE_NAME	Incomplete name
RPC_S_ENTRY_NOT_FOUND	Name-service entry not found
RPC_S_NAME_SERVICE_UNAVAILABLE	Name service unavailable
See Also

RpcNsProfileDelete, RpcNsProfileEltAdd


RpcObjectInqType
RpcObjectInqType   QuickInfo

The RpcObjectInqType function returns the type of an object.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcObjectInqType(
UUID *  ObjUuid,
UUID *  TypeUuid);

This function is supported by both the 32-bit Windows NT and Windows 95 platforms.

Parameters

ObjUuid

Points to the object UUID whose associated type UUID is returned.

TypeUuid

Returns a pointer to the type UUID of the ObjUuid argument.

Specify an argument value of NULL to prevent the return of a type UUID. In this way, an application can determine (from the returned status) whether ObjUuid is registered without specifying an output type UUID variable.

Remarks

A server application calls the RpcObjectInqType routine to obtain the type UUID of an object.

If the object was registered with the RPC run-time library using the RpcObjectSetType routine, the registered type is returned.

Optionally, an application can privately maintain an object/type registration. In this case, if the application has provided an object inquiry function (see RpcObjectSetInqFn), the RPC run-time library uses that function to determine an object's type.

The RpcObjectInqType routine obtains the returned type UUID as described in the following table:

Object UUID  registered	Inquiry function registered	Return  value
Yes (RpcObjectSetType)	Ignored	The object's registered type UUID
No	Yes (RpcObjectSetInqFn)	The type UUID returned from the inquiry function
No	No	The nil UUID
Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_OBJECT_NOT_FOUND	Object not found
See Also

RpcObjectSetInqFn, RpcObjectSetType


RpcObjectSetInqFn
RpcObjectSetInqFn   QuickInfo

The RpcObjectSetInqFn function registers an object-inquiry function. A null value turns off a previously registered object-inquiry function.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcObjectSetInqFn(
RPC_OBJECT_INQ_FN  InquiryFn);

This function is supported by both the 32-bit Windows NT and Windows 95 platforms.

Parameter

InquiryFn

Specifies an object-type inquiry function. When an application calls the RpcObjectInqType routine and the RPC run-time library finds that the specified object is not registered, the run-time library automatically calls RpcObjectSetInqFn to determine the object's type.

The following C-language definition for RPC_OBJECT_INQ_FN illustrates the prototype for the object-inquiry function:

typedef void ( *   RPC_OBJECT_INQ_FN) (

     UUID  *       ObjectUuid,

     UUID  *       TypeUuid,

     RPC_STATUS *  Status);

The TypeUuid and Status values are returned as the output from the RpcObjectInqType routine.

Remarks

A server application calls the RpcObjectSetInqFn routine to specify a function to determine an object's type. If an application privately maintains an object/type registration, the specified inquiry function returns the type UUID of an object.

The RPC run-time library automatically calls the inquiry function when the application calls RpcObjectInqType and the object of interest was not previously registered with the RpcObjectSetType routine.

Return Value

Value	Meaning
RPC_S_OK	Success
See Also

RpcObjectInqType, RpcObjectSetType


RpcObjectSetType
RpcObjectSetType   QuickInfo

The RpcObjectSetType function assigns the type of an object.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcObjectSetType(
UUID *  ObjUuid,
UUID *  TypeUuid);

This function is supported by both the 32-bit Windows NT and Windows 95 platforms.

Parameters

ObjUuid

Points to an object UUID to associate with the type UUID in the TypeUuid argument.

TypeUuid

Points to the type UUID of the ObjUuid argument.

Specify an argument value of NULL or a nil UUID to reset the object type to the default association of object UUID/nil type UUID.

Remarks

A server application calls the RpcObjectSetType routine to assign a type UUID to an object UUID.

By default, the RPC run-time library automatically assigns all object UUIDs with the nil type UUID. A server application that contains one implementation of an interface (one manager entry-point vector [EPV]) does not need to call RpcObjectSetType provided the server registered the interface with the nil type UUID (see RpcServerRegisterIf).

A server application that contains multiple implementations of an interface (multiple manager EPVs — that is, multiple type UUIDs) calls RpcObjectSetType once for each different object UUID/non-nil type UUID association the server supports. Associating each object with a type UUID tells the RPC run-time library which manager EPV (interface implementation) to use when the server receives a remote procecure call for a non-nil object UUID.

The RPC run-time library allows an application to set the type for an unlimited number of objects.

To remove the association between an object UUID and its type UUID (established by calling RpcObjectSetType), a server calls RpcObjectSetType again specifying a null value or a nil UUID for the TypeUuid argument. This resets the object UUID/type UUID association to the default association of object UUID/nil type UUID.

A server cannot assign a type to the nil object UUID. The RPC run-time library automatically assigns the nil object UUID a nil type UUID.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_OBJECT	Invalid object
RPC_S_ALREADY_REGISTERED	Object already registered
See Also

RpcServerRegisterIf


RpcProtseqVectorFree
RpcProtseqVectorFree   QuickInfo

The RpcProtseqVectorFree function frees the protocol sequences contained in the vector and the vector itself.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcProtseqVectorFree(
RPC_PROTSEQ_VECTOR * *  ProtSeqVector);

This function is supported by both the 32-bit Windows NT and Windows 95 platforms.

For a list of procotol sequences supported by RPC, see RPC Data Types and Structures.

Parameter

ProtSeqVector

Points to a pointer to a vector of protocol sequences. On return, the pointer is set to NULL.

Note  RpcProtseqVectorFree is available for server applications, not client applications, using Microsoft RPC.

Remarks

A server calls the RpcProtseqVectorFree routine to release the memory used to store a vector of protocol sequences and the individual protocol sequences. RpcProtseqVectorFree sets the ProtSeqVector argument to a null value.

A server obtains a vector of protocol sequences by calling the RpcNetworkInqProtseqs routine.

Return Value

Value	Meaning
RPC_S_OK	Success
See Also

RpcNetworkInqProtseqs


RpcRaiseException
RpcRaiseException   QuickInfo

Use the RpcRaiseException function to raise an exception. The RpcRaiseException function does not return to the caller.

void RPC_ENTRY
RpcRaiseException (
RPC_STATUS  Exception);

Parameter

Exception

Specifies the exception code for the exception. The following exception codes are defined:

Exception code	Description
RPC_S_ACCESS_DENIED	Access denied
RPC_S_ADDRESS_ERROR	An addressing error occurred in  the RPC server
RPC_S_ALREADY_LISTENING	Server already listening
RPC_S_ALREADY_REGISTERED	Object already registered
RPC_S_BINDING_HAS_NO_AUTH	Binding has no authentication
RPC_S_BINDING_INCOMPLETE	The binding handle is a required parameter.
RPC_S_BUFFER_TOO_SMALL	Insufficient buffer
RPC_S_CALL_CANCELLED	The remote procedure call exceeded the cancel timeout and was canceled.
RPC_S_CALL_FAILED	Call failed
RPC_S_CALL_FAILED_DNE	Call failed and did not execute
RPC_S_CALL_IN_PROGRESS	Call already in progress for this thread
RPC_S_CANNOT_SUPPORT	Operation is not supported
RPC_S_CANT_CREATE_ENDPOINT	Cannot create endpoint
RPC_S_COMM_FAILURE	Unable to communicate with the server
RPC_S_DUPLICATE_ENDPOINT	Endpoint already exists
RPC_S_ENTRY_ALREADY_EXISTS	Name-service entry already exists
RPC_S_ENTRY_NOT_FOUND	Name-service entry not found
RPC_S_FP_DIV_ZERO	A floating-point operation in the server caused a division by zero
RPC_S_FP_OVERFLOW	Floating-point overflow has  occurred in the RPC server
RPC_S_FP_UNDERFLOW	Floating-point underflow has occurred in the server
RPC_S_GROUP_MEMBER_NOT_FOUND	Group member not found
RPC_S_INCOMPLETE_NAME	Incomplete name
RPC_S_INTERFACE_NOT_FOUND	Interface not found
RPC_S_INTERNAL_ERROR	Internal error
RPC_S_INVALID_ARG	Invalid argument
RPC_S_INVALID_AUTH_IDENTITY	Invalid authentication
RPC_S_INVALID_BINDING	Invalid binding handle
RPC_S_INVALID_BOUND	Invalid bound
RPC_S_INVALID_ENDPOINT_FORMAT	Invalid endpoint format
RPC_S_INVALID_INQUIRY_CONTEXT	Invalid inquiry context
RPC_S_INVALID_INQUIRY_TYPE	Invalid inquiry type
RPC_S_INVALID_LEVEL	Invalid parameter
RPC_S_INVALID_NAF_IF	Invalid network-address family ID
RPC_S_INVALID_NAME_SYNTAX	Invalid name syntax
RPC_S_INVALID_NET_ADDR	Invalid network address
RPC_S_INVALID_NETWORK_OPTIONS	Invalid network options
RPC_S_INVALID_OBJECT	Invalid object
RPC_S_INVALID_RPC_PROTSEQ	Invalid protocol sequence
RPC_S_INVALID_SECURIT_DESC	Invalid security descriptor
RPC_S_INVALID_STRING_BINDING	Invalid string binding
RPC_S_INVALID_STRING_UUID	Invalid string UUID
RPC_S_INVALID_TAG	Invalid tag
RPC_S_INVALID_TIMEOUT	Invalid timeout value
RPC_S_INVALID_VERS_OPTION	Invalid version option
RPC_S_MAX_CALLS_TOO_SMALL	Maximum-calls value too small
RPC_S_NAME_SERVICE_UNAVAILABLE	Name service unavailable
RPC_S_NO_BINDINGS	No bindings
RPC_S_NO_CALL_ACTIVE	No remote procedure active in this thread
RPC_S_NO_CONTEXT_AVAILABLE	No security context is available to perform impersonation
RPC_S_NO_ENDPOINT_FOUND	No endpoint found
RPC_S_NO_ENTRY_NAME	No entry name for binding
RPC_S_NO_ENV_SETUP	No environment variable is set up
RPC_S_NO_INTERFACES	No interfaces are registered
RPC_S_NO_INTERFACES_EXPORTED	No interfaces have been exported
RPC_S_NO_MORE_BINDINGS	No more bindings
RPC_NO_MORE_ELEMENTS	There are no more elements.
RPC_S_NO_MORE_MEMBERS	No more members
RPC_S_NO_NS_PRIVILEGE	No privilege for name-service operation
RPC_S_NO_PRINC_NAME	No principal name is registered
RPC_S_NO_PROTSEQS	No supported protocol sequences
RPC_S_NO_PROTSEQS_REGISTERED	No protocol sequences registered
RPC_S_NOT_ALL_OBJS_UNEXPORTED	Not all objects unexported
RPC_S_NOT_CANCELLED	The thread is not canceled
RPC_S_NOT_LISTENING	Server not listening
RPC_S_NOT_RPC_ERROR	The status code requested is not  valid
RPC_S_NOTHING_TO_EXPORT	Nothing to export
RPC_S_NOTHING_TO_UNEXPORT	Nothing to unexport
RPC_S_OBJECT_NOT_FOUND	Object not found
RPC_S_OK	Success
RPC_S_OUT_OF_MEMORY	Out of memory
RPC_S_OUT_OF_RESOURCES	Out of resources
RPC_S_OUT_OF_THREADS	Out of threads
RPC_S_PROCNUM_OUT_OF_RANGE	Procedure number is out of range
RPC_S_PROTOCOL_ERROR	An RPC protocol error occurred
RPC_S_PROTSEQ_NOT_FOUND	Protocol sequence not found
RPC_S_PROTSEQ_NOT_SUPPORTED	Protocol sequence not supported
RPC_S_SERVER_OUT_OF_MEMORY	Server out of memory
RPC_S_SERVER_TOO_BUSY	Server too busy
RPC_S_SERVER_UNAVAILABLE	The server is unavailable
RPC_S_STRING_TOO_LONG	String too long
RPC_S_TYPE_ALREADY_REGISTERED	Type UUID already registered
RPC_S_UNKNOWN_AUTHN_LEVEL	Unknown authentication level
RPC_S_UNKNOWN_AUTHN_SERVICE	Unknown authentication service
RPC_S_UNKNOWN_AUTHN_TYPE	Unknown authentication type
RPC_S_UNKNOWN_IF	Unknown interface
RPC_S_UNKNOWN_MGR_TYPE	Unknown manager type
RPC_S_UNSUPPORTED-TRANS_SYN	Transfer syntax is not supported by the server
RPC_S_UNSUPPORTED_NAME_SYNTAX	Unsupported name syntax
RPC_S_UNSUPPORTED_TYPE	Unsupported UUID type
RPC_S_UUID_LOCAL_ONLY	The UUID that is only valid for this computer has been allocated
RPC_S_UUID_NO_ADDRESS	No network address is available to use to construct a UUID
RPC_S_WRONG_KIND_OF_BINDING	Wrong kind of binding for operation
RPC_S_ZERO_DIVIDE	Attempt to divide an integer by zero
RPC_X_BAD_STUB_DATA	The stub received bad data
RPC_X_BYTE_COUNT_TOO_SMALL	Byte count is too small
RPC_X_ENUM_VALUE_OUT_OF RANGE	The enumeration value is out of range
RPC_X_ENUM_VALUE_TOO_LARGE	The enumeration value is out of range
RPC_X_INVALID_BOUND	Specified bounds of an array  inconsistent
RPC_X_INVALID_TAG	Discriminant value does not match any case values; no default case
RPC_X_NO_MEMORY	Insufficient memory available to set up necessary data structures
RPC_X_NO_MORE_ENTRIES	List of servers available for AutoHandle binding has been exhausted
RPC_X_NULL_REF_POINTER	A null reference pointer was passed to the stub
RPC_X_SS_BAD_ES_VERSION	The operation for the serializing handle  is not valid
RPC_X_SS_CANNOT_GET_CALL_HANDLE	The stub is unable to get the remote procedure call handle
RPC_X_SS_CHAR_TRANS_OPEN_FAIL	File designated by DCERPCCHARTRANS cannot be opened
RPC_X_SS_CHAR_TRANS_SHORT_FILE	File containing character-translation  table has fewer than 512 bytes
RPC_X_SS_CONTEXT_DAMAGED	Only raised on caller side; UUID in in, out context handle changed during call
RPC_X_SS_CONTEXT_MISMATCH	Only raised on callee side; UUID in in  handle does not correspond to any known context
RPC_X_SS_HANDLES_MISMATCH	The binding handles passed to a remote procedure call don't match
RPC_X_SS_IN_NULL_CONTEXT	Null context handle passed in in parameter position
RPC_X_SS_INVALID_BUFFER	The buffer is not valid for the operation.
RPC_X_SS_WRONG_ES_VERSION	The software version is incorrect
RPC_X_SS_WRONG_STUB_VERSION	The stub version is incorrect
Remarks

The RpcRaiseException routine raises an exception; this exception can then be handled by the exception handler.

Return Values

No value is returned.

See Also

RpcAbnormalTermination, RpcExcept, RpcFinally


RpcRevertToSelf
RpcRevertToSelf   QuickInfo

After calling RpcImpersonateClient and completing any tasks that require client impersonation, the server calls RpcRevertToSelf to end impersonation and to reestablish its own security identity.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcRevertToSelf (void);

This function is supported only by 32-bit Windows NT platforms.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_NO_CALL_ACTIVE	Server does not have a client to impersonate
RPC_S_CANNOT_SUPPORT	Not supported for this operating system, this transport, or this security subsystem
See Also

RpcImpersonateClient


RpcServerInqBindings
RpcServerInqBindings   QuickInfo

The RpcServerInqBindings function returns the binding handles over which remote procedure calls can be received.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcServerInqBindings(
RPC_BINDING_VECTOR * *  BindingVector);

This function is supported by both the 32-bit Windows NT and Windows 95 platforms.

Parameter

BindingVector

Returns a pointer to a pointer to a vector of server binding handles.

Remarks

A server application calls the RpcServerInqBindings routine to obtain a vector of server binding handles. Binding handles are created by the RPC run-time library when a server application calls the following routines to register protocol sequences:

•	RpcServerUseAllProtseqs

•	RpcServerUseProtseq

•	RpcServerUseAllProtseqsIf

•	RpcServerUseProtseqIf

•	RpcServerUseProtseqEp

The returned binding vector can contain binding handles with dynamic endpoints or binding handles with well-known endpoints, depending on which of the above routines the server application called.

A server uses the vector of binding handles for exporting to the name service, for registering with the local endpoint-map database, or for conversion to string bindings.

If there are no binding handles (no registered protocol sequences), this routine returns the RPC_S_NO_BINDINGS status code and a BindingVector argument value of NULL.

The server is responsible for calling the RpcBindingVectorFree routine to release the memory used by the vector.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_NO_BINDINGS	No bindings
See Also

RpcBindingVectorFree, RpcEpRegister, RpcEpRegisterNoReplace, RpcNsBindingExport, RpcServerUseAllProtseqs, RpcServerUseAllProtseqsIf, RpcServerUseProtseq, RpcServerUseProtseqEp, RpcServerUseProtseqIf


RpcServerInqDefaultPrincName

The RpcServerInqDefaultPrincName function obtains the default principal name from the server.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcServerInqDefaultPrincName(
unsigned long  AuthnSvc,
RPC_CHAR * *  PrincName,
);

This function is supported only by Windows 95 platforms.

Parameters

AuthnSvc

Specifies an authentication service to use when the server receives a request for a remote procedure call.

PrincName

Points to the principal name to use for the server when authenticating remote procedure calls using the service specified by the AuthnSvc argument. The content of the name and its syntax are defined by the authentication service in use.

Remarks

In a NetWare-only environment, server application calls the RpcServerInqDefaultPrincName routine to obtain the name of the NetWare server when authenticated RPC is required. The value obtained from this routine is then passed to RpcServerRegisterAuthInfo.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_OUT_OF_MEMORY	Insufficient memory to complete the operation
See Also

RpcBindingSetAuthInfo, RpcServerRegisterAuthInfo


RpcServerInqIf
RpcServerInqIf   QuickInfo

The RpcServerInqIf function returns the manager entry-point vector (EPV) registered for an interface.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcServerInqIf(
RPC_IF_HANDLE  IfSpec,
UUID *  MgrTypeUuid,
RPC_MGR_EPV * *  MgrEpv);

This function is supported by both the 32-bit Windows NT and Windows 95 platforms.

Parameters

IfSpec

Specifies the interface whose manager EPV is returned.

MgrTypeUuid

Points to the manager type UUID whose manager EPV is returned.

Specifying an argument value of NULL (or a nil UUID) signifies to return the manager EPV registered with IfSpec and the nil manager type UUID.

MgrEpv

Returns a pointer to the manager EPV for the requested interface.

Remarks

A server application calls the RpcServerInqIf routine to determine the manager EPV for a registered interface and manager type UUID.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_UNKNOWN_IF	Unknown interface
RPC_S_UNKNOWN_MGR_TYPE	Unknown manager type
See Also

RpcServerRegisterIf


RpcServerListen
RpcServerListen   QuickInfo

The RpcServerListen function tells the RPC run-time library to listen for remote procedure calls.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcServerListen(
unsigned int	  MinimumCallThreads,
unsigned int	  MaxCalls,
unsigned int	  DontWait);

This function is supported by both the 32-bit Windows NT and Windows 95 platforms.

Parameters

MinimumCallThreads

Specifies the minimum number of call threads.

MaxCalls

Specifies the recommended maximum number of concurrent remote procedure calls the server can execute. To allow efficient performance, the RPC run-time libraries interpret the MaxCalls parameter as a suggested limit rather than as an absolute upper bound.

Use RPC_C_LISTEN_MAX_CALLS_DEFAULT to specify the default value.

DontWait

Specifies a flag controlling the return from RpcServerListen. A value of non-zero indicates that RpcServerListen should return immediately after completing function processing. A value of zero indicates that RpcServerListen should not return until RpcMgmtStopServerListening has been called and all remote calls have completed.

Remarks

Note  The Microsoft RPC implementation of RpcServerListen includes two new, additional parameters that do not appear in the DCE specification: DontWait and MinimumCallThreads.

A server calls the RpcServerListen routine when the server is ready to process remote procedure calls. RPC allows a server to simultaneously process multiple calls. The MaxCalls argument recommends the maximum number of concurrent remote procedure calls the server should execute.

The MaxCalls value should be equal to or greater than the largest MaxCalls value specified to the routines RpcServerUseProtseq, RpcServerUseProtseqEp, RpcServerUseProtseqIf, RpcServerUseAllProtseqs, and RpcServerUseAllProtseqsIf.

A server application is responsible for concurrency control between the server manager routines because each routine executes in a separate thread.

When the DontWait parameter has a value of zero, the RPC run-time library continues listening for remote procedure calls (that is, the routine does not return to the server application) until one of the following events occurs:

•	One of the server application's manager routines calls the RpcMgmtStopServerListening routine.

•	A client calls a remote procedure provided by the server that directs the server to call RpcMgmtStopServerListening.

•	A client calls RpcMgmtStopServerListening with a binding handle to the server.

Once it receives a stop-listening request, the RPC run-time library stops accepting new remote procedure calls for all registered interfaces. Executing calls are allowed to complete, including callbacks.

After all calls complete, the RpcServerListen routine returns to the caller.

When the DontWait parameter has a non-zero value, RpcServerListen returns to the server immediately after processing all the instructions associated with the function. You can use the RpcMgmtWaitServerListen routine to perform the "wait" operation usually associated with RpcServerListen.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_ALREADY_LISTENING	Server already listening
RPC_S_NO_PROTSEQS_REGISTERED	No protocol sequences registered
RPC_S_MAX_CALLS_TOO_SMALL	Maximum calls value too small
See Also

RpcMgmtStopServerListening, RpcMgmtWaitServerListen, RpcServerRegisterIf, RpcServerUseAllProtseqs, RpcServerUseAllProtseqsIf, RpcServerUseProtseq, RpcServerUseProtseqEp, RpcServerUseProtseqIf


RpcServerRegisterAuthInfo
RpcServerRegisterAuthInfo   QuickInfo

The RpcServerRegisterAuthInfo function registers authentication information with the RPC run-time library.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcServerRegisterAuthInfo(
unsigned char *  ServerPrincName,
unsigned long  AuthnSvc,
RPC_AUTH_KEY_RETRIEVAL_FN  GetKeyFn,
void *  Arg);

This function is supported by both the 32-bit Windows NT and Windows 95 platforms.

Parameters

ServerPrincName

Points to the principal name to use for the server when authenticating remote procedure calls using the service specified by the AuthnSvc argument. The content of the name and its syntax are defined by the authentication service in use.

AuthnSvc

Specifies an authentication service to use when the server receives a request for a remote procedure call.

GetKeyFn

Specifies the address of a server-application-provided routine that returns encryption keys.

Specify a NULL argument value to use the default method of encryption-key acquisition. In this case, the authentication service specifies the default behavior. Set this parameter to NULL when using the RPC_C_AUTHN_WINNT authentication service.

Authentication service	GetKeyFn	Arg	Run-time behavior
RPC_C_AUTHN_DCE_PRIVATE	NULL	Non-null	Uses default method of encryption-key acquisition from specified key table; specified argument is passed to default acquisition function
RPC_C_AUTHN_DCE_PRIVATE	Non-null	NULL	Uses specified encryption-key acquisition function to obtain keys from default key table
RPC_C_AUTHN_DCE_PRIVATE	Non-null	Non-null	Uses specified encryption-key acquisition function to obtain keys from specified key table; specified argument is passed to acquisition function
RPC_C_AUTHN_DEC_PUBLIC	Ignored	Ignored	Reserved for future use
RPC_C_AUTHN_WINNT	Ignored	Ignored	Does not support
The following C-language definition for RPC_AUTH_KEY_RETRIEVAL_FN illustrates the prototype for RpcServerRegisterAuthInfo:

typedef void (* RPC_AUTH_KEY_RETRIEVAL_FN)(

    void * arg, /* in */

    unsigned char * ServerPrincName, /* in */

    unsigned int key_ver, /* in */

    void * * key, /* out */

    unsigned int * status /* out */);

The RPC run-time library passes the ServerPrincName argument value from RpcServerRegisterAuthInfo as the ServerPrincName argument value to the GetKeyFn acquisition function.

The RPC run-time library automatically provides a value for the key version (KeyVer) argument. For a KeyVer argument value of zero, the acquisition function must return the most recent key available.

The retrieval function returns the authentication key in the Key argument.

If the acquisition function called from RpcServerRegisterAuthInfo returns a status other than RPC_S_OK, RpcServerRegisterAuthInfo fails and returns an error code to the server application.

If the acquisition function called by the RPC run-time library while authenticating a client's remote procedure call request returns a status other than RPC_S_OK, the request fails and the RPC run-time library returns an error code to the client application.

Arg

Points to an argument to pass to the GetKeyFn routine, if specified.

Remarks

A server application calls the RpcServerRegisterAuthInfo routine to register an authentication service to use for authenticating remote procedure calls. A server calls this routine once for each authentication service and/or principal name the server wants to register.

The authentication service specified by a client application (using RpcBindingSetAuthInfo or RpcServerRegisterAuthInfo) must be one of the authentication services specified by the server application. Otherwise, the client's remote procedure call fails and an RPC_S_UNKNOWN_AUTHN_SERVICE status code is returned.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_UNKNOWN_AUTHN_SERVICE	Unknown authentication service
See Also

RpcBindingSetAuthInfo


RpcServerRegisterIf
RpcServerRegisterIf   QuickInfo

The RpcServerRegisterIf function registers an interface with the RPC run-time library.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcServerRegisterIf(
RPC_IF_HANDLE  IfSpec,
UUID *  MgrTypeUuid,
RPC_MGR_EPV *  MgrEpv);

This function is supported by both the 32-bit Windows NT and Windows 95 platforms.

Parameters

IfSpec

Specifies a MIDL-generated data structure indicating the interface to register.

MgrTypeUuid

Points to a type UUID to associate with the MgrEpv argument. Specifying a null argument value (or a nil UUID) registers IfSpec with a nil type UUID.

MgrEpv

Specifies the manager routines' entry-point vector (EPV). To use the
MIDL-generated default EPV, specify a null value.

Remarks

A server can register an unlimited number of interfaces with the RPC run-time library. Registration makes an interface available to clients using a binding handle to the server.

To register an interface, the server application code calls the RpcServerRegisterIf routine. For each implementation of an interface offered by a server, it must register a separate manager EPV.

To register an interface, the server provides the following information:

•	Interface specification

The interface specification is a data structure that the MIDL compiler generates. The server specifies the interface using the IfSpec argument.

•	Manager type UUID and manager EPV

The manager type UUID and the manager EPV determine which manager routine executes when a server receives a remote procedure call request from a client.

The server specifies the manager type UUID and EPV using the MgrTypeUuid and MgrEpv arguments. Note that when specifying a non-nil manager type UUID, the server must also call the RpcObjectSetType routine to register objects of this non-nil type.


Specifying the Manager EPV

If the routine names used by a manager correspond to those of the interface definition, you can register this manager using the default EPV of the interface generated by the MIDL compiler. You can also register a manager using a server-application-supplied EPV.


The Default Manager EPV

By default, the MIDL compiler uses the procedure names from an interface's IDL file to generate a manager EPV, which the compiler places directly into the server stub. This default EPV is statically initialized using the procedure names declared in the interface definition.

To register a manager using the default EPV, specify NULL as the value of the MgrEpv argument (a null EPV).


Server-Supplied Manager EPVs

A server can (and sometimes must) create and register a non-null manager EPV for an interface. To select a server-application-supplied EPV, pass a non-null EPV whose value has been declared by the server as the value of the MgrEpv argument. A non-null value for the MgrEpv argument always overrides a default EPV in the server stub.

The MIDL compiler automatically generates a manager EPV data type (RPC_MGR_EPV) for a server application to use in constructing manager EPVs. A manager EPV must contain exactly one entry point (function address) for each procedure defined in the IDL file.

A server must supply a non-null EPV in the following cases:

•	When the names of manager routines differ from the procedure names declared in the interface definition.

•	When the server uses the default EPV for registering another implementation of the interface.

A server declares a manager EPV by initializing a variable of type
if-name_SERVER_EPV for each implementation of the interface.


Registering Only One Manager of an Interface

When a server offers only one implementation of an interface, the server calls the RpcServerRegisterIf routine only once. In the simplest case, the server uses the default manager EPV. (The exception is when the manager uses routine names that differ from those declared in the interface.)

For the simple case, you supply the following values in the RpcServerRegisterIf call:

•	Manager EPVs

To use the default EPV, you specify a null value for the MgrEpv argument.

•	Manager type UUID

When using the default EPV, you can register the interface with a nil manager type UUID by supplying either a null value or a nil UUID for the MgrTypeUuid argument. In this case, all remote procedure calls, regardless of the object UUID in their binding handle, are dispatched to the default EPV, assuming no RpcObjectSetType calls have been made.

You can also provide a non-nil manager type UUID. In this case, you must also call the RpcObjectSetType routine.


Registering Multiple Implementations of an Interface

To offer multiple implementations of an interface, a server must register each implementation by calling the RpcServerRegisterIf routine separately. For each implementation a server registers, it supplies the same IfSpec argument but a different pair of MgrTypeUuid and MgrEpv arguments.

In the case of multiple managers, use the RpcServerRegisterIf routine as follows:

•	Manager EPVs

To offer multiple implementations of an interface, a server must:

•	Create a non-null manager EPV for each additional implementation.

•	Specify a non-null value for the MgrEpv argument in the RpcServerRegisterIf routine.

Please note that the server can also register with the default manager EPV.

•	Manager type UUID

Provide a manager type UUID for each EPV of the interface. The nil type UUID (or null value) for the MgrTypeUuid argument can be specified for one of the manager EPVs. Each type UUID must be different.


Rules for Invoking Manager Routines

The RPC run-time library dispatches an incoming remote procedure call to a manager that offers the requested RPC interface. When multiple managers are registered for an interface, the RPC run-time library must select one of them. To select a manager, the RPC run-time library uses the object UUID specified by the call's binding handle.

The run-time library applies the following rules when interpreting the object UUID of a remote procedure call:

•	Nil object UUIDs

A nil object UUID is automatically assigned the nil type UUID (it is illegal to specify a nil object UUID in the RpcObjectSetType routine). Therefore, a remote procedure call whose binding handle contains a nil object UUID is automatically dispatched to the manager registered with the nil type UUID, if any.

•	Non-nil object UUIDs

In principle, a remote procedure call whose binding handle contains a non-nil object UUID should be processed by a manager whose type UUID matches the type of the object UUID. However, identifying the correct manager requires that the server has specified the type of that object UUID by calling the RpcObjectSetType routine.

If a server fails to call the RpcObjectSetType routine for a non-nil object UUID, a remote procedure call for that object UUID goes to the manager EPV that services remote procedure calls with a nil object UUID (that is, the nil type UUID).

Remote procedure calls with a non-nil object UUID in the binding handle cannot be executed if the server assigned that non-nil object UUID a type UUID by calling the RpcObjectSetType routine but did not also register a manager EPV for that type UUID by calling the RpcServerRegisterIf routine.

Object UUID of call	Server set type for object UUID?	Server registered EPV type?	Dispatching action
Nil	Not applicable	Yes	Uses the manager with the nil type UUID.
Nil	Not applicable	No	Error (RPC_S_UNSUPPORTED_TYPE); rejects the remote procedure call.
Non-nil	Yes	Yes	Uses the manager with the same type UUID.
Non-nil	No	Ignored	Uses the manager with the nil type UUID; if no manager with the nil type UUID, error (RPC_S_UNSUPPORTEDTYPE); rejects the remote procedure call.
Non-nil	Yes	No	Error (RPC_S_UNSUPPORTEDTYPE); rejects the remote procedure call.
The object UUID of the call is the object UUID found in a binding handle for a remote procedure call.

The server sets the type of the object UUID by calling RpcObjectSetType to specify the type UUID for an object.

The server registers the type for the manager EPV by calling RpcServerRegisterIf using the same type UUID.

The nil object UUID is always automatically assigned the nil type UUID. It is illegal to specify a nil object UUID in the RpcObjectSetType routine.


Dispatching a Remote Procedure Call to a Server-Manager Routine

The following tables show the steps taken by the RPC run-time library to dispatch a remote procedure call to a server-manager routine.

Assume a simple case where the server registers the default manager EPV, as described in the following tables:

Interface registry table

Interface UUID	Manager type UUID	Entry-point vector
uuid1	Nil	Default EPV
Object registry table

Object UUID	Object type
Nil	Nil
(Any other object UUID)	Nil
Mapping the binding handle to an entry-point vector

Interface UUID (from client binding handle)	Object UUID  (from client  binding handle)	Object type (from object registry table)	Manager EPV  (from interface registry table)
uuid1	Nil	Nil	Default EPV
Same as above	uuidA	Nil	Default EPV
The following steps describe the actions taken by the RPC server run-time library:

1.	The server calls RpcServerRegisterIf to associate an interface it offers with the nil manager type UUID and with the MIDL-generated default manager EPV. This call adds an entry in the interface registry table. The interface UUID is contained in the IfSpec argument.

2.	By default, the object registry table associates all object UUIDs with the nil type UUID. In this example, the server does not call RpcObjectSetType.

3.	The server run-time library receives a remote procedure code containing the interface UUID the call belongs to and the object UUID from the call's binding handle.

See the following function reference entries for discussions of how an object UUID is set into a binding handle:

•	RpcNsBindingImportBegin

•	RpcNsBindingLookupBegin

•	RpcBindingFromStringBinding

•	RpcBindingSetObject

4.	Using the interface UUID from the remote procedure call, the server's
run-time library locates that interface UUID in the interface registry table.

If the server did not register the interface using RpcServerRegisterIf, the remote procedure call returns to the caller with an RPC_S_UNKNOWN_IF status code.

5.	Using the object UUID from the binding handle, the server's run-time library locates that object UUID in the object registry table. In this example, all object UUIDs map to the nil object type.

6.	The server's run-time library locates the nil manager type in the interface registry table.

7.	Combining the interface UUID and nil type in the interface registry table resolves to the default EPV, which contains the server-manager routines to be executed for the interface UUID found in the remote procedure call.

Assume that the server offers multiple interfaces and multiple implementations of each interface, as described in the following tables:

Interface registry table

Interface UUID	Manager type UUID	Entry-point vector
uuid1	Nil	epv1
uuid1	uuid3	epv4
uuid2	uuid4	epv2
uuid2	uuid7	epv3
Object registry table

Object UUID	Object type
uuidA	uuid3
uuidB	uuid7
uuidC	uuid7
uuidD	uuid3
uuidE	uuid3
uuidF	uuid8
Nil	Nil
(Any other UUID)	Nil
Mapping the binding handle to an entry-point vector

Interface UUID (from client binding handle)	Object UUID (from client binding handle)	Object type  (from object registry table)	Manager EPV (from interface registry table)
uuid1	Nil	Nil	epv1
uuid1	uuidA	uuid3	epv4
uuid1	uuidD	uuid3	epv4
uuid1	uuidE	uuid3	epv4
uuid2	uuidB	uuid7	epv3
uuid2	uuidC	uuid7	epv3
The following steps describe the actions taken by the server's run-time library as depicted in the preceding tables when called by a client with interface UUID uuid2 and object UUID uuidC:

1.	The server calls RpcServerRegisterIf to associate the interfaces it offers with the different manager EPVs. The entries in the interface registry table reflect four calls of RpcServerRegisterIf to offer two interfaces, with two implementations (EPVs) for each interface.

2.	The server calls RpcObjectSetType to establish the type of each object it offers. In addition to the default association of the nil object to a nil type, all other object UUIDs not explicitly found in the object registry table also map to the nil type UUID.

In this example, the server calls the RpcObjectSetType routine six times.

3.	The server run-time library receives a remote procedure call containing the interface UUID the call belongs to and an object UUID from the call's binding handle.

4.	Using the interface UUID from the remote procedure call, the server's
run-time library locates the interface UUID in the interface registry table.

5.	Using the object UUID from the binding handle, uuidC, the server's run-time library locates the object UUID in the object registry table and finds that it maps to type uuid7.

6.	The server's run-time library locates the manager type by combining the interface UUID, uuid2, and type uuid7 in the interface registry table. This resolves to epv3, which contains the server-manager routine to be executed for the remote procedure call.

The routines in epv2 will never be executed because the server has not called the RpcObjectSetType routine to add any objects with a type UUID of uuid4 to the object registry table.

A remote procedure call with interface UUID uuid2 and object UUID uuidF returns to the caller with an RPC_S_UNKNOWN_MGR_TYPE status code because the server did not call the RpcServerRegisterIf routine to register the interface with a manager type of uuid8.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_TYPE_ALREADY_REGISTERED	Type UUID already registered
See Also

RpcBindingFromStringBinding, RpcBindingSetObject, RpcNsBindingExport, RpcNsBindingImportBegin, RpcNsBindingLookupBegin, RpcObjectSetType, RpcServerUnregisterIf


RpcServerUnregisterIf
RpcServerUnregisterIf   QuickInfo

The RpcServerUnregisterIf function unregisters an interface from the RPC run-time library.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcServerUnregisterIf(
RPC_IF_HANDLE  IfSpec,
UUID *  MgrTypeUuid,
unsigned int	  WaitForCallsToComplete);

This function is supported by both the 32-bit Windows NT and Windows 95 platforms.

Parameters

IfSpec

Specifies the interface to unregister.

Specify a null value to unregister all interfaces previously registered with the type UUID value specified in the MgrTypeUuid argument.

MgrTypeUuid

Points to the type UUID of the manager entry-point vector (EPV) to unregister. The value of MgrTypeUuid should be the same value as was provided in a call to the RpcServerRegisterIf routine.

Specify a null value to unregister the interface specified in the IfSpec argument for all previously registered type UUIDs.

Specify a nil UUID to unregister the MIDL-generated default manager
EPV. In this case, all manager EPVs registered with a non-nil type UUID remain registered.

WaitForCallsToComplete

Specifies a flag that indicates whether to unregister immediately or to wait until all current calls are complete.

Specify a value of zero to disregard calls in progress and unregister immediately. Specify any non-zero value to wait until all active calls complete.

Remarks

A server calls the RpcServerUnregisterIf routine to remove the association between an interface and a manager EPV.

Specify the manager EPV to remove in the MgrTypeUuid argument by providing the type UUID value that was specified in a call to the RpcServerRegisterIf routine. Once unregistered, an interface is no longer available to client applications.

When an interface is unregistered, the RPC run-time library stops accepting new calls for that interface. Executing calls on the interface are allowed to complete, including callbacks.

The following table summarizes the behavior of RpcServerUnregisterIf:

IfSpec	MgrTypeUuid	Behavior
Non-null	Non-null	Unregisters the manager EPV associated with the specified arguments.
Non-null	NULL	Unregisters all manager EPVs associated with the IfSpec argument.
NULL	Non-null	Unregisters all manager EPVs associated with the MgrTypeUuid argument.
NULL	NULL	Unregisters all manager EPVs. This call has the effect of preventing the server from receiving any new remote procedure calls because all the manager EPVs for all interfaces have been unregistered.
Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_UNKNOWN_MGR_TYPE	Unknown manager type
RPC_S_UNKNOWN_IF	Unknown interface
See Also

RpcServerRegisterIf


RpcServerUseAllProtseqs
RpcServerUseAllProtseqs   QuickInfo

The RpcServerUseAllProtseqs function tells the RPC run-time library to use all supported protocol sequences for receiving remote procedure calls.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcServerUseAllProtseqs(
unsigned int	  MaxCalls,
void *  SecurityDescriptor);

This function is supported by both the 32-bit Windows NT and Windows 95 platforms.

For a list of procotol sequences supported by RPC, see RPC Data Types and Structures.

Parameters

MaxCalls

Specifies the maximum number of concurrent remote procedure call requests the server can accept.

The RPC run-time library guarantees that the server can accept at least this number of concurrent call requests. The actual number can be greater and can vary for each protocol sequence.

Use RPC_C_PROTSEQ_MAX_REQS_DEFAULT to specify the default value.

SecurityDescriptor

Points to an optional parameter provided for the Microsoft Windows NT security subsystem.

Remarks

Note  The Microsoft RPC implementation of RpcServerUseAllProtseqs includes a new, additional parameter, SecurityDescriptor, that does not appear in the DCE specification.

A server application calls the RpcServerUseAllProtseqs routine to register all of the supported protocol sequences with the RPC run-time library. To receive remote procedure calls, a server must register at least one protocol sequence with the RPC run-time library.

For each protocol sequence registered by a server, the RPC run-time library creates one or more binding handles through which the server receives remote procedure call requests. The RPC run-time library creates different binding handles for each protocol sequence. Each binding handle contains an endpoint dynamically generated by the RPC run-time library or the operating system.

The MaxCalls argument allows the server to specify the maximum number of concurrent remote procedure call requests the server wants to be able to handle.

After registering protocol sequences, a server typically calls the following routines:

•	RpcServerInqBindings to obtain a vector containing all of the server's binding handles.

•	RpcEpRegister or RpcEpRegisterNoReplace to register the binding handles with the endpoint-mapping service. During implementation and debugging, server developers can communicate their binding information to clients using string bindings. This allows them to establish a client-server relationship without using the endpoint-map database or name-service database.

To establish such a relationship, use RpcBindingToStringBinding to convert one or more binding handles in the binding-handle vector to a string binding and provide, via mail, on paper, or by some other means, the string binding to the client.

•	RpcNsBindingExport to place the binding handles in the name-service database for access by any client.

•	RpcBindingVectorFree to free the vector of server binding handles.

•	RpcServerRegisterIf to register the interfaces offered by the server with the RPC run-time library. This is a required call.

•	RpcServerListen to begin receiving remote procedure call requests. This is a required call.

To selectively register protocol sequences, a server calls the RpcServerUseProtseq, RpcServerUseProtseqIf, or RpcServerUseProtseqEp routine.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_NO_PROTSEQS	No supported protocol sequences
RPC_S_OUT_OF_MEMORY	Insufficient memory available
RPC_S_INVALID_SECURITY_DESC	Security descriptor invalid
See Also

RpcBindingToStringBinding, RpcBindingVectorFree, RpcEpRegister, RpcEpRegisterNoReplace, RpcNsBindingExport, RpcServerInqBindings, RpcServerListen, RpcServerRegisterIf, RpcServerUseAllProtseqsIf, RpcServerUseProtseq, RpcServerUseProtseqEp, RpcServerUseProtseqIf


RpcServerUseAllProtseqsIf
RpcServerUseAllProtseqsIf   QuickInfo

The RpcServerUseAllProtseqsIf function tells the RPC run-time library to use all the specified protocol sequences and endpoints in the interface specification for receiving remote procedure calls.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcServerUseAllProtseqsIf(
unsigned int  MaxCalls,
RPC_IF_HANDLE  IfSpec,
void *  SecurityDescriptor);

This function is supported by both the 32-bit Windows NT and Windows 95 platforms.

For a list of procotol sequences supported by RPC, see RPC Data Types and Structures.

Parameters

MaxCalls

Specifies the maximum number of concurrent remote procedure call requests the server can accept.

The RPC run-time library guarantees that the server can accept at least this number of concurrent call requests. The actual number can be greater and can vary for each protocol sequence.

Use RPC_C_PROTSEQ_MAX_REQS_DEFAULT to specify the default value.

IfSpec

Specifies the interface containing the protocol sequences and corresponding endpoint information to use in creating binding handles.

SecurityDescriptor

Points to an optional parameter provided for the Microsoft Windows NT security subsystem.

Remarks

Note  The Microsoft RPC implementation of RpcServerUseAllProtseqsIf includes a new, additional parameter, SecurityDescriptor, that does not appear in the DCE specification.

A server application calls the RpcServerUseAllProtseqsIf routine to register with the RPC run-time library all the protocol sequences and associated endpoint-address information provided in the IDL file.

To receive remote procedure call requests, a server must register at least one protocol sequence with the RPC run-time library.

For each protocol sequence registered by a server, the RPC run-time library creates one or more binding handles through which the server receives remote procedure call requests. The RPC run-time library creates different binding handles for each protocol sequence.

The MaxCalls argument allows the server to specify the maximum number of concurrent remote procedure call requests the server wants to handle.

See RpcServerUseAllProtseqs for the list of routines a server typically calls after calling RpcServerUseAllProtseqsIf.

To register selected protocol sequences specified in the IDL file, a server calls the RpcServerUseProtseqIf routine.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_NO_PROTSEQS	No supported protocol sequences
RPC_S_INVALID_ENDPOINT_FORMAT	Invalid endpoint format
RPC_S_OUT_OF_MEMORY	Out of memory
RPC_S_DUPLICATE_ENDPOINT	Endpoint is duplicate
RPC_S_INVALID_SECURITY_DESC	Security descriptor invalid
RPC_S_INVALID_RPC_PROTSEQ	RPC protocol sequence invalid
See Also

RpcBindingVectorFree, RpcEpRegister, RpcEpRegisterNoReplace, RpcNsBindingExport, RpcServerInqBindings, RpcServerListen, RpcServerRegisterIf, RpcServerUseAllProtseqs, RpcServerUseProtseq, RpcServerUseProtseqEp, RpcServerUseProtseqIf


RpcServerUseProtseq
RpcServerUseProtseq   QuickInfo

The RpcServerUseProtseq function tells the RPC run-time library to use the specified protocol sequence for receiving remote procedure calls.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcServerUseProtseq(
unsigned char *  ProtSeq,
unsigned int	  MaxCalls,
void *  SecurityDescriptor);

This function is supported by both the 32-bit Windows NT and Windows 95 platforms.

For a list of procotol sequences supported by RPC, see RPC Data Types and Structures.

Parameters

ProtSeq

Points to a string identifier of the protocol sequence to register with the RPC run-time library.

MaxCalls

Specifies the maximum number of concurrent remote procedure call requests the server wants to handle.

The RPC run-time library guarantees that the server can accept at least this number of concurrent call requests. The actual number can be greater, depending on the selected protocol sequence.

Use RPC_C_PROTSEQ_MAX_REQS_DEFAULT to specify the default value.

SecurityDescriptor

Points to an optional parameter provided for the Microsoft Windows NT security subsystem.

Remarks

Note  The Microsoft RPC implementation of RpcServerUseProtseq includes a new, additional parameter, SecurityDescriptor, that does not appear in the DCE specification.

A server application calls the RpcServerUseProtseq routine to register one protocol sequence with the RPC run-time library. To receive remote procedure call requests, a server must register at least one protocol sequence with the RPC run-time library. A server application can call RpcServerUseProtseq multiple times to register additional protocol sequences.

For each protocol sequence registered by a server, the RPC run-time library creates one or more binding handles through which the server receives remote procedure call requests. The RPC run-time library creates different binding handles for each protocol sequence. Each binding handle contains an endpoint dynamically generated by the RPC run-time library.

The MaxCalls argument allows the server to specify the maximum number of concurrent remote procedure call requests the server wants to handle.

See RpcServerUseAllProtseqs for the list of routines a server typically calls after calling RpcServerUseProtseq.

To register all protocol sequences, a server calls the RpcServerUseAllProtseqs routine.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_PROTSEQ_NOT_SUPPORTED	Protocol sequence not supported on this host
RPC_S_INVALID_RPC_PROTSEQ	Invalid protocol sequence
RPC_S_OUT_OF_MEMORY	Out of memory
RPC_S_INVALID_SECURITY_DESC	Security descriptor invalid
See Also

RpcBindingVectorFree, RpcEpRegister, RpcEpRegisterNoReplace, RpcNetworkIsProtseqValid, RpcNsBindingExport, RpcServerInqBindings, RpcServerListen, RpcServerRegisterIf, RpcServerUseAllProtseqs, RpcServerUseAllProtseqsIf, RpcServerUseProtseqEp, RpcServerUseProtseqIf


RpcServerUseProtseqEp
RpcServerUseProtseqEp   QuickInfo

The RpcServerUseProtseqEp function tells the RPC run-time library to use the specified protocol sequence combined with the specified endpoint for receiving remote procedure calls.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcServerUseProtseqEp(
unsigned char *  Protseq,
unsigned int	  MaxCalls,
unsigned char *  Endpoint,
void *  SecurityDescriptor);

This function is supported by both the 32-bit Windows NT and Windows 95 platforms.

For a list of procotol sequences supported by RPC, see RPC Data Types and Structures.

Parameters

Protseq

Points to a string identifier of the protocol sequence to register with the RPC run-time library.

MaxCalls

Specifies the maximum number of concurrent remote procedure call requests the server wants to handle.

The RPC run-time library guarantees that the server can accept at least this number of concurrent call requests. The actual number can be greater, depending on the selected protocol sequence.

Use RPC_C_PROTSEQ_MAX_REQS_DEFAULT to specify the default value.

Endpoint

Points to the endpoint-address information to use in creating a binding for the protocol sequence specified in the Protseq argument.

SecurityDescriptor

Points to an optional parameter provided for the Microsoft Windows NT security subsystem.

Remarks

Note  The Microsoft RPC implementation of RpcServerUseProtseqEp includes a new, additional parameter, SecurityDescriptor, that does not appear in the DCE specification.

A server application calls the RpcServerUseProtseqEp routine to register one protocol sequence with the RPC run-time library. With each protocol sequence registration, RpcServerUseProtseqEp includes the specified endpoint-address information.

To receive remote procedure call requests, a server must register at least one protocol sequence with the RPC run-time library. A server application can call this routine multiple times to register additional protocol sequences and endpoints.

For each protocol sequence registered by a server, the RPC run-time library creates one or more binding handles through which the server receives remote procedure call requests.

The MaxCalls argument allows the server to specify the maximum number of concurrent remote procedure call requests the server wants to be able to handle.

See RpcServerUseAllProtseqs for the list of routines a server typically calls after calling RpcServerUseProtseqEp.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_PROTSEQ_NOT_SUPPORTED	Protocol sequence not supported on this host
RPC_S_INVALID_RPC_PROTSEQ	Invalid protocol sequence
RPC_S_INVALID_ENDPOINT_FORMAT	Invalid endpoint format
RPC_S_OUT_OF_MEMORY	Out of memory
RPC_S_DUPLICATE_ENDPOINT	Endpoint is duplicate
RPC_S_INVALID_SECURITY_DESC	Security descriptor invalid
See Also

RpcBindingVectorFree, RpcEpRegister, RpcEpRegisterNoReplace, RpcNsBindingExport, RpcServerInqBindings, RpcServerListen, RpcServerRegisterIf, RpcServerUseAllProtseqs, RpcServerUseAllProtseqsIf, RpcServerUseProtseq, RpcServerUseProtseqIf


RpcServerUseProtseqIf
RpcServerUseProtseqIf   QuickInfo

The RpcServerUseProtseqIf function tells the RPC run-time library to use the specified protocol sequence combined with the endpoints in the interface specification for receiving remote procedure calls.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcServerUseProtseqIf(
unsigned char *  Protseq,
unsigned int	  MaxCalls,
RPC_IF_HANDLE  IfSpec,
void *  SecurityDescriptor);

This function is supported by both the 32-bit Windows NT and Windows 95 platforms.

For a list of procotol sequences supported by RPC, see RPC Data Types and Structures.

Parameters

Protseq

Points to a string identifier of the protocol sequence to register with the RPC run-time library.

MaxCalls

Specifies the maximum number of concurrent remote procedure call requests the server wants to be able to handle.

The RPC run-time library guarantees that the server can accept at least this number of concurrent call requests. The actual number can be greater, depending on the selected protocol sequence.

Use RPC_C_PROTSEQ_MAX_REQS_DEFAULT to specify the default value.

IfSpec

Specifies the interface containing endpoint information to use in creating a binding for the protocol sequence specified in the Protseq argument.

SecurityDescriptor

Points to an optional parameter provided for the Microsoft Windows NT security subsystem.

Remarks

Note  The Microsoft RPC implementation of RpcServerUseProtseqIf includes a new, additional parameter, SecurityDescriptor, that does not appear in the DCE specification.

A server application calls the RpcServerUseProtseqIf routine to register one protocol sequence with the RPC run-time library. With each protocol-sequence registration, the routine includes the endpoint-address information provided in the IDL file.

To receive remote procedure call requests, a server must register at least one protocol sequence with the RPC run-time library. A server application can call this routine multiple times to register additional protocol sequences.

For each protocol sequence registered by a server, the RPC run-time library creates one or more binding handles through which the server receives remote procedure call requests.

The MaxCalls argument allows the server to specify the maximum number of concurrent remote procedure call requests the server wants to be able to handle.

See RpcServerUseAllProtseqs for the list of routines a server typically calls after calling RpcServerUseProtseqIf.

To register all protocol sequences from the IDL file, a server calls the RpcServerUseAllProtseqsIf routine.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_PROTSEQ_NOT_FOUND	The endpoint for this protocol sequence not specified in the IDL file
RPC_S_PROTSEQ_NOT_SUPPORTED	Protocol sequence not supported on this host
RPC_S_INVALID_RPC_PROTSEQ	Invalid protocol sequence
RPC_S_INVALID_ENDPOINT_FORMAT	Invalid endpoint format
RPC_S_OUT_OF_MEMORY	Out of memory
RPC_S_INVALID_SECURITY_DESC	Security descriptor invalid
See Also

RpcBindingVectorFree, RpcEpRegister, RpcEpRegisterNoReplace, RpcNsBindingExport, RpcServerInqBindings, RpcServerListen, RpcServerRegisterIf, RpcServerUseAllProtseqs, RpcServerUseAllProtseqsIf, RpcServerUseProtseq, RpcServerUseProtseqEp


RpcSmAllocate

The RpcSmAllocate function allocates memory within the RPC stub memory management function and returns a pointer to the allocated memory or NULL.

#include <rpc.h>
void * RPC_ENTRY
RpcSmAllocate(

size_t Size

RPC_STATUS* pStatus);

Parameters

Size

Specifies the size of memory to allocate (in bytes).

pStatus

Specifies a pointer to the returned status.

Remarks

The RpcSmAllocate routine allows an application to allocate memory within the RPC stub memory management environment. Prior to calling RpcSmAllocate, the memory management environment must already be established. For memory management called within the stub, the server stub itself may establish the necessary environment. See RpcSmEnableAllocate for more information. When using RpcSmAllocate to allocate memory not called from the stub, the application must call RpcSmEnableAllocate to establish the required memory management environment.

The RpcSmAllocate routine returns a pointer to the allocated memory if the call is successful. Otherwise, a NULL is returned.

When the stub establishes the memory management, it frees any memory allocated by RpcSmAllocate. The application can free such memory before returning to the calling stub by calling RpcSmFree.

By contrast, when the application establishes the memory management, it must free any memory allocated. It does so by calling either RpcSmFree or RpcSmDisableAllocate.

To manage the same memory within the stub memory management environment, multiple threads can call RpcSmAllocate and RpcSmFree. In this case, the threads must share the same stub memory management thread handle. Applications pass thread handles from thread to thread by calling RpcSmGetThreadHandle and RpcSmSetThreadHandle.

See Memory Management for a complete discussion of the various memory management conditions supported by RPC.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_OUT_OF_MEMORY	Out of Memory
See Also

RpcSmEnableAllocate, RpcSmDisableAllocate, RpcSmFree, RpcSmGetThreadHandle, RpcSmSetThreadHandle


RpcSmClientFree

The RpcSmClientFree function frees memory returned from a client stub.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcSmClientFree(
void  *  NodeToFree);

Parameter

NodeToFree

Specifies a pointer to memory returned from a client stub.

Remarks

The RpcSmClientFree routine releases memory allocated and returned from a client stub. The memory management handle of the thread calling this routine must match the handle of the thread that made the RPC call. Use RpcSmGetThreadHandle and RpcSmSetThreadHandle to pass handles from thread to thread.

Note that using RpcSmClientFree allows a routine to free dynamically-allocated memory returned by an RPC call without knowing the memory management environment from which it was called.

Return Value

Value	Meaning
RPC_S_OK	Success
See Also

RpcSmFree, RpcSmGetThreadHandle, RpcSmSetClientAllocFree, RpcSmSetThreadHandle, RpcSmSwapClientAllocFree


RpcSmDestroyClientContext

The RpcSmDestroyClientContext function reclaims the client memory resources for a context handle and makes the context handle NULL.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcSmDestroyClientContext(
void* *  ContextHandle);

Parameter

ContextHandle

Specifies the context handle that can no longer be used.

Remarks

The RpcSmDestroyClientContext routine is used by client applications to reclaim resources used for an inactive context handle. Applications can call RpcSmDestroyClientContext after a communications error makes the context handle unusable.

Note that when this routine reclaims the memory resources, it also makes the context handle NULL.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_X_SS_CONTEXT_MISMATCH	Invalid handle
See Also

RpcSmFree, RpcSmGetThreadHandle, RpcSmSetClientAllocFree, RpcSmSetThreadHandle, RpcSmSwapClientAllocFree


RpcSmDisableAllocate

The RpcSmDisableAllocate function frees resources and memory within the stub memory management environment.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcSmDisableAllocate (void);

Remarks

The RpcSmDisableAllocate routine frees all the resources used by a call to RpcSmEnableAllocate. It also releases memory that was allocated by a call to RpcSmAllocate after the call to RpcSmEnableAllocate.

Note that RpcSmEnableAllocate and RpcSmDisableAllocate must be used together as matching pairs.

Return Value

Value	Meaning
RPC_S_OK	Success
See Also

RpcSmAllocate, RpcSmEnableAllocate


RpcSmEnableAllocate

The RpcSmEnableAllocate function establishes the stub memory management environment.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcSmEnableAllocate (void);

Remarks

In cases where the stub memory management is not enabled by the server stub itself, the RpcSmEnableAllocate routine is called by applications to establish the stub memory management environment. This environment must be established prior to making a call to RpcSmAllocate. In default mode, for server manager code called from the stub, the memory management environment may be established by the server stub itself by using pointer manipulation or the enable_allocate attribute. For ms_ext or c_ext modes, the environment is established only upon request by using the enable_allocate attribute (see The MIDL Reference.) Otherwise, call RpcSmEnableAllocate before calling RpcSmAllocate. See Memory Management for a complete discussion of the memory management conditions used by RPC. RpcSmGetThreadHandle and RpcSmSetThreadHandle

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_OUT_OF_MEMORY	Out of memory
See Also

RpcSmAllocate, RpcSmDisableAllocate


RpcSmFree

The RpcSmFree function releases memory allocated by RpcSmAllocate.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcSmFree(
void  *  NodeToFree);

Parameter

NodeToFree

Specifies a pointer to memory allocated by RpcSmAllocate or RpcSsAllocate.

Remarks

The RpcSmFree routine is used by applications to free memory allocated by RpcSmAllocate. In cases where the stub allocates the memory for the application, the RpcSmFree routine can also be used to release memory. See Memory Management for a complete discussion of memory management conditions supported by RPC.

Note that the handle of the thread calling RpcSmFree must match the handle of the thread that allocated the memory by calling RpcSmAllocate. Use RpcSmGetThreadHandle and RpcSmSetThreadHandle to pass handles from thread to thread.

Return Value

Value	Meaning
RPC_S_OK	Success
See Also

RpcSmAllocate, RpcSmGetThreadHandle, RpcSmSetThreadHandle


RpcSmGetThreadHandle

The RpcSmGetThreadHandle function returns a thread handle, or NULL, for the stub memory management environment.

#include <rpc.h>
RPC_SS_THREAD_HANDLE RPC_ENTRY
RpcSmGetThreadHandle (
RPC_STATUS *  pStatus)

Parameter

pStatus

Specifies a pointer to the returned status.

Remarks

The RpcSmGetThreadHandle routine is called by applications to obtain a thread handle for the stub memory management environment. A thread used to manage memory for the stub memory management environment uses RpcSmGetThreadHandle to receive a handle for its memory environment. In this way, another thread that calls RpcSmSetThreadHandle by using this handle can then use the same memory management environment.

The same memory management thread handle must be used by multiple threads calling RpcSmAllocate and RpcSmFree in order to manage the same memory. Before spawning new threads to manage the same memory, the thread that established the memory management environment (parent thread) calls RpcSmGetThreadHandle to obtain a thread handle for this environment. Then, the spawned threads call RpcSmSetThreadHandle with the new manager handle provided by the parent thread.

Note that the RpcSmGetThreadHandle routine is usually called by a server manager procedure before additional threads are spawned. The stub sets up the memory management environment for the manager procedure ,and the manager calls RpcSmGetThreadHandle to make this environment available to the other threads.

A thread can also call RpcSmGetThreadHandle and RpcSmSetThreadHandle to save and restore its memory management environment.

Return Value

Value	Meaning
RPC_S_OK	Success
See Also

RpcSmAllocate, RpcSmFree, RpcSmSetThreadHandle


RpcSmSetClientAllocFree

The RpcSmSetClientAllocFree function enables the memory allocation and release mechanisms used by the client stubs.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcSmSetClientAllocFree(
RPC_CLIENT_ALLOC  *  pfnAllocate,
RPC_CLIENT_FREE  *  pfnFree);

Parameters

pfnAllocate

Specifies the routine used to allocate memory.

pfnFree

Specifies the routine used to release memory and used with the routine specified by pfnAllocate.

Remarks

By overriding the default routines used by the client stub to manage memory, the RpcSmSetClientAllocFree routine establishes the memory allocation and memory freeing mechanisms. Note that the default routines are free and malloc, unless the remote call occurs within manager code. In this case, the default memory management routines are RpcSmFree and RpcSmAllocate.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_OUT_OF_MEMORY	Out of memory
See Also

RpcSmAllocate, RpcSmFree


RpcSmSetThreadHandle

The RpcSmSetThreadHandle function sets a thread handle for the stub memory management environment.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcSmSetThreadHandle (
RPC_SS_THREAD_HANDLE  Handle);

Parameter

Handle

Specifies a thread handle returned by a call to RpcSmGetThreadHandle.

Remarks

The RpcSmSetThreadHandle routine is called by an application to set a thread handle for the stub memory management environment. A thread used to manage memory for the stub memory management environment calls RpcSmGetThreadHandle to obtain a handle for its memory environment. In this way, another thread that calls RpcSmSetThreadHandle by using this handle can then use the same memory management environment.

The same memory management thread handle must be used by multiple threads calling RpcSmAllocate and RpcSmFree in order to manage the same memory. Before spawning new threads to manage the same memory, the thread that established the memory management environment (parent thread) calls RpcSmGetThreadHandle to obtain a thread handle for this environment. Then, the spawned threads call RpcSmSetThreadHandle with the new manager handle provided by the parent thread.

Note that the RpcSmSetThreadHandle routine is usually called by a thread spawned by a server manager procedure. The stub sets up the memory management environment for the manager procedure ,and the manager calls RpcSmGetThreadHandle to obtain a thread handle. Then, each spawned thread calls RpcSmGetThreadHandle to get access to the manager's memory management environment.

A thread can also call RpcSmGetThreadHandle and RpcSmSetThreadHandle to save and restore its memory management environment.

Return Value

Value	Meaning
RPC_S_OK	Success
See Also

RpcSmAllocate, RpcSmGetThreadHandle, RpcSmFree


RpcSmSwapClientAllocFree

The RpcSmSwapClientAllocFree function exchanges the memory allocation and release mechanisms used by the client stubs with one supplied by the client.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcSmSwapClientAllocFree(
RPC_CLIENT_ALLOC  *  pfnAllocate,
RPC_CLIENT_FREE  *  pfnFree,
RPC_CLIENT_ALLOC **  pfnOldAllocate,
RPC_CLIENT_FREE  **  pfnOldFree);

Parameters

pfnAllocate

Specifies a new routine to allocate memory.

pfnFree

Specifies a new routine to release memory.

pfnOldAllocate

Returns the previous routine to allocate memory before the call to this routine.

pfnOldFree

Returns the previous routine to release memory before the call to this routine.

Remarks

The RpcSmSwapClientAllocFree routine exchanges the current memory allocation and memory freeing mechanisms with those supplied by the client.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_ARG	Invalid argument(s)
See Also

RpcSmAllocate, RpcSmFree, RpcSmSetClientAllocFree


RpcSsAllocate

The RpcSsAllocate function allocates memory within the RPC stub memory management function, and returns a pointer to the allocated memory or NULL.

#include <rpc.h>
void __RPC_FAR * RPC_ENTRY
RpcSsAllocate(
size_t  Size);

Parameter

Size

Specifies the size of memory to allocate (in bytes).

Remarks

The RpcSsAllocate routine allows an application to allocate memory within the RPC stub memory management function. Prior to calling RpcSsAllocate, the memory management environment must already be established. For memory management called within the stub, the stub itself usually establishes the necessary environment. See Chapter 8 , "Memory Management," for a complete discussion of the various memory management conditions supported by RPC. When using RpcSsAllocate to allocate memory not called from the stub, the application must call RpcSsEnableAllocate to establish the required memory management environment.

The RpcSsAllocate routine returns a pointer to the allocated memory, if the call was successful. Otherwise, it raises an exception.

When the stub establishes the memory management, it frees any memory allocated by RpcSsAllocate. The application can free such memory before returning to the calling stub by calling RpcSsFree.

By contrast, when the application establishes the memory management, it must free any memory allocated. It does so by calling either RpcSsFree or RpcSsDisableAllocate.

To manage the same memory within the stub memory management environment, multiple threads can call RpcSsAllocate and RpcSsFree. In this case, the threads must share the same stub memory management thread handle. Applications pass thread handles from thread to thread by calling RpcSsGetThreadHandle and RPCSsSetThreadHandle.

Note  The RpcSsAllocate routine raises exceptions, while the RpcSmAllocate routine returns the error code.

Return Value

Value	Meaning
RPC_S_OUT_OF_MEMORY	Out of memory
See Also

RpcSmAllocate, RpcSsDisableAllocate, RpcSsEnableAllocate, RpcSsFree, RpcSsGetThreadHandle, RpcSsSetThreadHandle


RpcSsDestroyClientContext
RpcSsDestroyClientContext   QuickInfo

The RpcSsDestroyClientContext function destroys a context handle no longer needed by the client without contacting the server.

#include <rpc.h>
void RPC_ENTRY
RpcSsDestroyClientContext(
void  * * ContextHandle,
);

Parameter

ContextHandle

Specifies the context handle to be destroyed. The handle is set to NULL before RpcSsDestroyClientContext returns.

Remarks

RpcSsDestroyClientContext is used by the client application to reclaim the memory resources used to maintain a context handle on the client. This function is used when ContextHandle is no longer valid, such as when a communication failure has occurred and the server is no longer available. The context handle is set to NULL.

Do not use RpcSsDestroyClientContext to replace a server function that closes the context handle.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_X_SS_CONTEXT_MISMATCH	Invalid context handle
See Also

RpcBindingReset


RpcSsDisableAllocate

The RpcSsDisableAllocate function frees resources and memory within the stub memory management environment.

#include <rpc.h>
void RPC_ENTRY
RpcSsDisableAllocate (void);

Remarks

The RpcSsDisableAllocate routine frees all the resources used by a call to RpcSsEnableAllocate. It also releases memory that was allocated by a call to RpcSsAllocate after the call to RpcSsEnableAllocate.

RpcSsEnableAllocate and RpcSsDisableAllocate must be used together as matching pairs.

See Also

RpcSmDisableAllocate, RpcSsAllocate, RpcSsEnableAllocate


RpcSsEnableAllocate

The RpcSsEnableAllocate function establishes the stub memory management environment.

#include <rpc.h>
void RPC_ENTRY
RpcSsEnableAllocate (void);

Remarks

In cases where the stub memory management is not enabled by the stub itself, the RpcSsEnableAllocate routine is called by applications to establish the stub memory management environment. This environment must be established prior to making a call to RpcSsAllocate. For server manager code called from the stub, the memory management environment is usually established by the stub itself. Otherwise, call RpcSsEnableAllocate before calling RpcSsAllocate. See Memory Management for a complete discussion of the memory management conditions used by RPC. To learn how spawned threads use a stub memory management environment, see RpcSsGetThreadHandle and RpcSsSetThreadHandle later in this section.

Note  The RpcSsEnableAllocate routine raises exceptions, while the RpcSmEnableAllocate routine returns the error code.

Return Value

Value	Meaning
RPC_S_OUT_OF_MEMORY	Out of memory
See Also

RpcSmEnableAllocate, RpcSsAllocate, RpcSsDisableAllocate


RpcSsFree

The RpcSsFree function releases memory allocated by RpcSsAllocate.

#include <rpc.h>
void RPC_ENTRY
RpcSsFree(
void *	NodeToFree);

Parameter

NodeToFree

Specifies a pointer to memory allocated by RpcSsAllocate or RpcSmAllocate.

Remarks

The RpcSsFree routine is used by applications to free memory allocated by RpcSsAllocate. In cases where the stub allocates the memory for the environment, the RpcSsFree routine can also be used to release memory. See Memory Management for a complete discussion of memory management conditions supported by RPC.

Note that the handle of the thread calling RpcSsFree must match the handle of the thread that allocated the memory by calling RpcSsAllocate. Use RpcSsGetThreadHandle and RpcSsSetThreadHandle to pass handles from thread to thread.

See Also

RpcSmFree, RpcSsAllocate, RpcSsGetThreadHandle, RpcSsSetThreadHandle


RpcSsGetThreadHandle

The RpcSsGetThreadHandle function returns a thread handle for the stub memory management environment.

#include <rpc.h>
RPC_SS_THREAD_HANDLE RPC_ENTRY
RpcSsGetThreadHandle (void);

Remarks

The RpcSsGetThreadHandle routine is called by applications to obtain a thread handle for the stub memory management environment. A thread used to manage memory for the stub memory management environment uses RpcSsGetThreadHandle to receive a handle for its memory environment. In this way, another thread that calls RpcSsSetThreadHandle by using this handle can then use the same memory management environment.

The same thread handle must be used by multiple threads calling RpcSsAllocate and RpcSsFree in order to manage the same memory. Before spawning new threads to manage the same memory, the thread that established the memory management environment (parent thread) calls RpcSsGetThreadHandle to obtain a thread handle for this environment. Then, the spawned threads call RpcSsSetThreadHandle with the handle provided by the parent thread.

The RpcSsGetThreadHandle routine is usually called by a server manager procedure before additional threads are spawned. The stub sets up the memory management environment for the manager procedure, and the manager calls RpcSsGetThreadHandle to make this environment available to the other threads.

A thread can also call RpcSsGetThreadHandle and RpcSsSetThreadHandle to save and restore its memory management environment.

Note  The RpcSsGetThreadHandle routine raises exceptions, while the RpcSmGetThreadHandle routine returns the error code.

Return Value

Value	Meaning
RPC_S_OK	Success
See Also

RpcSmGetThreadHandle, RpcSsAllocate, RpcSsFree, RpcSsSetThreadHandle


RpcSsSetClientAllocFree

The RpcSsSetClientAllocFree function enables the memory allocation and release mechanisms used by the client stubs.

#include <rpc.h>
void RPC_ENTRY
RpcSsSetClientAllocFree(
RPC_CLIENT_ALLOC *  pfnAllocate,
RPC_CLIENT_FREE  *  pfnFree);

Parameters

pfnAllocate

Specifies the routine used to allocate memory.

pfnFree

Specifies the routine used to release memory and used with the routine specified by pfnAllocate.

Remarks

By overriding the default routines used by the client stub to manage memory, the RpcSsSetClientAllocFree routine establishes the memory allocation and memory freeing mechanisms. Note that the default routines are free and malloc, unless the remote call occurs within manager code. In this case, the default memory management routines are RpcSsFree and RpcSsAllocate.

Note that when this routine reclaims the memory resources, it also makes the context handle NULL.

Note  The RpcSsSetClientAllocFree routine raises exceptions, while the RpcSmSetClientAllocFree routine returns the error code.

Return Value

Value	Meaning
RPC_S_OUT_OF_MEMORY	Out of memory
See Also

RpcSmSetClientAllocFree, RpcSsAllocate, RpcSsFree


RpcSsSetThreadHandle

The RpcSsSetThreadHandle function sets a thread handle for the stub memory management environment.

#include <rpc.h>
void RPC_ENTRY
RpcSsSetThreadHandle (
RPC_SM_THREAD_HANDLE  Handle);

Parameter

Handle

Specifies a thread handle returned by a call to RpcSsGetThreadHandle.

Remarks

The RpcSsSetThreadHandle routine is called by an application to set a thread handle for the stub memory management environment. A thread used to manage memory for the stub memory management environment calls RpcSsGetThreadHandle to obtain a handle for its memory environment. In this way, another thread that calls RpcSsSetThreadHandle by using this handle can then use the same memory management environment.

The same thread handle must be used by multiple threads calling RpcSsAllocate and RpcSsFree in order to manage the same memory. Before spawning new threads to manage the same memory, the thread that established the memory management environment (parent thread) calls RpcSsGetThreadHandle to obtain a thread handle for this environment. Then, the spawned threads call RpcSsSetThreadHandle with the handle provided by the parent thread.

The RpcSsSetThreadHandle routine is usually called by a thread spawned by a server manager procedure. The stub sets up the memory management environment for the manager procedure, and the manager calls RpcSsGetThreadHandle to obtain a thread handle. Then, each spawned thread calls RpcSsGetThreadHandle to get access to the manager's memory management environment.

A thread can also call RpcSsGetThreadHandle and RpcSsSetThreadHandle to save and restore its memory management environment.

Note  The RpcSsSetThreadHandle routine raises exceptions, while the RpcSmSetThreadHandle routine returns the error code.

See Also

RpcSmSetThreadHandle, RpcSsAllocate, RpcSsFree, RpcSsGetThreadHandle


RpcSsSwapClientAllocFree

The RpcSsSwapClientAllocFree function exchanges the memory allocation and release mechanisms used by the client stubs with one supplied by the client.

#include <rpc.h>
void RPC_ENTRY
RpcSsSwapClientAllocFree(
RPC_CLIENT_ALLOC*  pfnAllocate,
RPC_CLIENT_FREE*  pfnFree,
RPC_CLIENT_ALLOC**  pfnOldAllocate,
RPC_CLIENT_FREE**  pfnOldFree);

Parameters

pfnAllocate

Specifies a new routine to allocate memory.

pfnFree

Specifies a new routine to release memory.

pfnOldAllocate

Returns the previous routine to allocate memory before the call to this routine.

pfnOldFree

Returns the previous routine to release memory before the call to this routine.

Remarks

The RpcSsSwapClientAllocFree routine exchanges the current memory allocation and memory freeing mechanisms with those supplied by the client.

Note  The RpcSsSwapClientAllocFree routine raises exceptions, while the RpcSmSwapClientAllocFree routine returns the error code.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_OUT_OF_MEMORY	Out of memory
See Also

RpcSmSwapClientAllocFree, RpcSsAllocate, RpcSsFree, RpcSsSetClientAllocFree


RpcStringBindingCompose
RpcStringBindingCompose   QuickInfo

The RpcStringBindingCompose function combines the components of a string binding into a string binding.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcStringBindingCompose(
unsigned char *  ObjUuid,
unsigned char *  ProtSeq,
unsigned char *  NetworkAddr,
unsigned char *  EndPoint,
unsigned char *  Options,
unsigned char * *  StringBinding);

Parameters

ObjUuid

Points to a NULL-terminated string representation of an object UUID. For example, the string "6B29FC40-CA47-1067-B31D-00DD010662DA" represents a valid UUID.

ProtSeq

Points to a NULL-terminated string representation of a protocol sequence. For more information, see the RPC data types and structures reference entry for string binding. For a list of procotol sequences supported by RPC, see RPC Data Types and Structures.

NetworkAddr

Points to a NULL-terminated string representation of a network address. The network-address format is associated with the protocol sequence. For more information, see the RPC data types and structures reference entry for string binding.

EndPoint

Points to a NULL-terminated string representation of an endpoint. The endpoint format and content are associated with the protocol sequence. For example, the endpoint associated with the protocol sequence ncacn_np is a pipe name in the format "\pipe\pipename". For more information, see the RPC data types and structures reference entry for string binding.

Options

Points to a NULL-terminated string representation of network options. The option string is associated with the protocol sequence. For more information, see the RPC data types and structures reference entry for string binding.

StringBinding

Returns a pointer to a pointer to a NULL-terminated string representation of a binding handle.

Specify a null value to prevent RpcStringBindingCompose from returning the StringBinding argument. In this case, the application does not call the RpcStringFree routine. For more information, see the RPC data types and structures reference entry for string binding.

Remarks

An application calls the RpcStringBindingCompose routine to combine the components of a string-binding handle into a string-binding handle.

The RPC run-time library allocates memory for the string returned in the StringBinding argument. The application is responsible for calling the RpcStringFree routine to deallocate that memory.

Specify a null argument value or provide an empty string ("\0") for each input string that has no data.

Literal backslash characters within C-language strings must be quoted. The actual C string for the server name appears as "\\\\servername", and the actual C string for a pipe name appears as "\\pipe\\pipename".

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_STRING_UUID	String representation of the UUID not valid.
See Also

RpcBindingFromStringBinding, RpcBindingToStringBinding, RpcStringBindingParse, RpcStringFree


RpcStringBindingParse
RpcStringBindingParse   QuickInfo

The RpcStringBindingParse function returns the object UUID part and the address parts of a string binding as separate strings.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcStringBindingParse(
unsigned char *  StringBinding,
unsigned char * *  ObjectUuid ,
unsigned char * *  ProtSeq ,
unsigned char * *  NetworkAddr ,
unsigned char * *  EndPoint ,
unsigned char * *  NetworkOptions);

Parameters

StringBinding

Points to a NULL-terminated string representation of a binding.

ObjectUuid

Returns a pointer to a pointer to a NULL-terminated string representation of an object UUID.

Specify a null value to prevent RpcStringBindingParse from returning the ObjectUuid argument. In this case, the application does not call the RpcStringFree routine.

ProtSeq

Returns a pointer to a pointer to a NULL-terminated string representation of a protocol sequence. For a list of procotol sequences supported by RPC, see RPC Data Types and Structures. Specify a null value to prevent RpcStringBindingParse from returning the ProtSeq argument. In this case, the application does not call the RpcStringFree routine.

NetworkAddr

Returns a pointer to a pointer to a NULL-terminated string representation of a network address.

Specify a null value to prevent RpcStringBindingParse from returning the NetworkAddr argument. In this case, the application does not call the RpcStringFree routine.

EndPoint

Returns a pointer to a pointer to a NULL-terminated string representation of an endpoint.

Specify a null value to prevent RpcStringBindingParse from returning the EndPoint argument. In this case, the application does not call the RpcStringFree routine.

NetworkOptions

Returns a pointer to a pointer to a NULL-terminated string representation of network options.

Specify a null value to prevent RpcStringBindingParse from returning the NetworkOptions argument. In this case, the application does not call the RpcStringFree routine.

Remarks

An application calls the RpcStringBindingParse routine to parse a string representation of a binding handle into its component fields.

The RPC run-time library allocates memory for each component string returned. The application is responsible for calling the RpcStringFree routine once for each returned string to deallocate the memory for that string.

If any field of the StringBinding argument is empty, the RpcStringBindingParse routine returns an empty string ("\0") in the corresponding output argument.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_STRING_BINDING	Invalid string binding
See Also

RpcBindingFromStringBinding, RpcBindingToStringBinding, RpcStringBindingCompose, RpcStringFree


RpcStringFree
RpcStringFree   QuickInfo

The RpcStringFree function frees a character string allocated by the RPC run-time library.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcStringFree(
unsigned char * *  String);

Parameter

String

Points to a pointer to the character string to free.

Remarks

The RpcStringFree routine deallocates the memory containing a NULL-terminated character string returned by the RPC run-time library.

An application is responsible for calling RpcStringFree once for each character string allocated and returned by calls to other RPC run-time library routines.

Return Value

Value	Meaning
RPC_S_OK	Success
See Also

RpcBindingToStringBinding, RpcNsBindingInqEntryName, RpcStringBindingParse


RpcTestCancel
RpcTestCancel   QuickInfo

The RpcTestCancel function checks for a cancel indication.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcTestCancel(
);

This function is supported only by 32-bit Windows NT platforms.

Remarks

An application server stub calls the RpcTestCancel routine to determine whether the call has been cancelled. If the call has been cancelled, RPC_S_OK is returned; otherwise, another value is returned.

This routine should be called periodically by the server stub so that it can respond to cancels in a timely fashion. If the routine returns RPC_S_OK, the stub should clean up its data structures and return to the client.

Return Values

Value	Meaning
RPC_S_OK	Call has been cancelled
Other values	Call has not been cancelled


RpcTryExcept
RpcTryExcept   QuickInfo

See

RpcExcept


RpcTryFinally
RpcTryFinally   QuickInfo

See

RpcFinally


RpcWinSetYieldInfo

The RpcWinSetYieldInfo function configures Microsoft Windows 3.x client applications to yield to other applications during remote procedure calls.

 #include <rpc.h>
RPC_STATUS
RpcWinSetYieldInfo(HWND	hWnd,
BOOL  fCustomYield,
WORD  wMsg,
DWORD  dwOtherInfo);

This function is only supported by Windows 3.x applications.

Parameters

hWnd

Identifies the application window that receives messages relating to yielding. Applications should usually specify the parent window of the dialog box.

Standard yield applications receive messages for both the start and end of the yield period. Custom yield applications receive messages that indicate when the RPC operation has completed.

fCustomYield

Specifies the yielding method. The following values are defined:

Value	Yield method
TRUE	Custom yield
FALSE	Standard yield
wMsg

Specifies the message that is posted by the RPC run-time library to notify the application of RPC events. The message value should be in the range beginning with WM_USER. If a zero value is specified, no message is posted.

For standard-yield applications, the message indicates the beginning or end of the yield period. This allows the application to refrain from performing operations that are illegal during an RPC operation. Standard-yield applications use the following values of wParam and lParam with this message:

Parameter	Value	Description
wParam	1	Yield period beginning
wParam	0	Yield period ending
lParam	−	Unused
For a custom-yield application, the wMsg message notifies the application that the RPC operation is complete. When the application receives this message, it should immediately return control to the RPC run-time library by having the callback function return. The values of wParam and lParam are set to zero and are not used.

dwOtherInfo

Specifies additional information about the yielding behavior.

For standard-yield applications, dwOtherInfo contains an optional HANDLE to an application-supplied dialog-box resource. This handle is passed as the second parameter to the DialogBoxIndirect function. If the handle specified by dwOtherInfo is zero, the default dialog box supplied by the RPC run-time library is used. For more informatin about DialogBoxIndirect, see your Windows API reference documentation.

For custom-yield applications, dwOtherInfo contains the procedure-instance address of the application-supplied callback function.

Remarks

The RpcWinSetYieldInfo function supports two yielding methods:

•	Standard yield method. The RPC run-time library provides a standard modal dialog box that includes a single push-button control with an IDCANCEL ID. The dialog box prevents direct user input, such as mouse and keyboard events, from being sent to the application. The application continues to receive messages while the dialog box is present. The IDCANCEL message indicates that the application user wants to end the remote procedure.

•	Custom yield method. The application provides a callback function that the RPC run-time library calls while a remote operation is in progress. The callback function must retrieve messages from the message queue (including mouse and keyboard messages) and must process messages (both queued and non-queued). The RPC run-time library posts a message to the application's queue when the RPC operation is complete. The callback function returns a boolean value to the RPC run-time library.

When a conventional RPC client application makes a remote procedure call, the MIDL-generated stub calls the RPC run-time library and the library calls the appropriate transport. These calls are synchronous and block until the server side sends back a response. In the cooperatively multitasked Windows 3.x environment, an active, blocked application prevents Windows and other Windows applications from running. The RpcWinSetYieldInfo function allows you to direct the application to yield to Windows and other Windows applications while waiting for an RPC operation to finish.

Windows RPC client applications can be organized into three classes that correspond to levels of yielding support: no yielding, standard yielding, and custom yielding.

•	Some applications do not yield. RPC calls block until completion.

•	Standard-yield applications are RPC-aware applications that yield but do not need to perform special handling.

•	Custom-yield applications are those that are RPC aware and want to perform special handling while an RPC operation is in progress.

You can replace the provided dialog-box resource with an application-specified dialog-box resource. The resource must use the same style as the default and must contain a single push-button control with an IDCANCEL ID. The dialog-box function is part of the RPC run-time library and cannot be replaced.

To yield in a well-behaved manner from within the context of a pending RPC operation, applications must observe the following rules:

•	Do not make another RPC call. If the RPC run-time library detects that a new call is being made during the yielding period, it returns an error to the caller. This is particularly important if the application makes RPC calls in response to common messages, such as WM_PAINT.

•	Do not exit the application. Do not close the window specified by the hWnd handle parameter. Your application can process WM_CLOSE messages in the window procedure and not call DefWindowProc during the yielding period. For more information about DefWindowProc, see your Windows API reference documentation.

•	Return FALSE in response to WM_QUERYENDSESSION messages. Alternatively, a custom-yield application can use this message as a signal to cause YieldFunctionName to return FALSE to the RPC run-time library and end the yielding period.

There is no guarantee that any code that supports yielding will be invoked. Whether or not an application yields depends on the specific call, the current state of the underlying system, and the implementation of the underlying RPC transport. Applications should not rely on this code to do anything other than manage yielding.

The RpcWinSetYieldInfo function can be called more than once by an application. Each call simply replaces the information stored in the previous calls.

Yielding is not necessary for Win32 applications. Environments that support Win32 applications are preemptively multitasked and are multithreaded. For efficiency, a Win32-only application should not call RpcWinSetYieldInfo.

Return Values

Value	Meaning
RPC_S_OK	The information was set successfully.
RPC_S_OUT_OF_MEMORY	Memory could not be allocated to store the information for this task.
See Also

DefWindowProc, DialogBoxIndirect, MakeProcInstance, YieldFunctionName


RpcWinSetYieldTimeout

The RpcWinSetYieldTimeout function configures the amount of time an RPC call will wait for the server to respond before invoking the application's RPC yielding mechanism. This function is only supported by Windows 3.x applications.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
RpcWinSetYieldTimeout (
unsigned int	Timeout );

Parameter

Timeout

Specifies the timeout value in milliseconds.  If this function is not called, the default is 500 milliseconds.

Remarks

Depending on the type of yielding specified in RpcWinSetYieldInfo, this can either produce a dialog box or signal the application.

If the Timeout value is small, the yielding mechanism can be invoked too often.  This results in loss of performance.  Conversely, if the value specified for Timeout is too large, the application and system will be frozen for the timeout period.  To avoid this, use timeouts in the range of 500 to 2000 milliseconds.

The RpcWinSetYieldTimeout function can be called more than once by an application.  Each call simply replaces the information stored in the previous calls.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_CANNOT_SUPPORT	RpcWinSetYieldInfo must be called prior to RpcWinSetYieldTimeout.
See Also

RpcWinSetYieldInfo


UuidCompare
UuidCompare   QuickInfo

The UuidCompare function compares two UUIDs.

#include <rpc.h>
signed int RPC_ENTRY
UuidCompare(
UUID *  Uuid1,
UUID *  Uuid2,
RPC_STATUS *  Status);

Parameters

Uuid1

Specifies a pointer to a UUID. This UUID is compared with the UUID specified in the Uuid2 argument.

Uuid2

Specifies a pointer to a UUID. This UUID is compared with the UUID specified in the Uuid1 argument.

Status

Returns any errors that may occur, and will normally be set by the function to RPC_S_OK upon return.

Remarks

An application calls the UuidCompare routine to compare two UUIDs and determine their order. To determine order, one of the following is returned:

Returned Value	Meaning
-1	The Uuid1 argument is less than the Uuid2 argument.
0	The Uuid1 argument is equal to the Uuid2 argument.
1	The Uuid1 argument is greater than the Uuid2 argument.
See Also

UuidCreate


UuidCreate
UuidCreate   QuickInfo

The UuidCreate function creates a new UUID.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
UuidCreate(
UUID *  Uuid);

Parameter

Uuid

Returns a pointer to the created UUID.

Remarks

An application calls the UuidCreate routine to create a new UUID.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_UUID_NO_ADDRESS	Cannot get Ethernet or token-ring hardware address for this computer
See Also

UuidFromString, UuidToString


UuidCreateNil
UuidCreateNil   QuickInfo

The UuidCreateNil function creates a nil-valued UUID.

#include <rpc.h>
RPC_ENTRY
UuidCreateNil(
UUID *  Nil_Uuid,
RPC_STATUS *  Status);

Parameters

Nil_Uuid

Returns a nil-valued UUID.

Status

Returns any errors that may occur. The parameter is typically set by the function to RPC_S_OK upon return.

Remarks

An application calls the UuidCreateNil routine to create a nil-valued UUID.


UuidEqual
UuidEqual   QuickInfo

The UuidEqual function determines if two UUIDs are equal.

#include <rpc.h>
int RPC_ENTRY
UuidEqual(
UUID *  Uuid1,
UUID *  Uuid2,
RPC_STATUS *  Status);

Parameters

Uuid1

Specifies a pointer to a UUID. This UUID is compared with the UUID specified in the Uuid2 argument.

Uuid2

Specifies a pointer to a UUID. This UUID is compared with the UUID specified in the Uuid1 argument.

Status

Returns any errors that may occur, and will normally be set by the function to RPC_S_OK upon return.

Remarks

An application calls the UuidEqual routine to compare two UUIDs and determine whether they are equal. Upon completion, one of the following is returned:

Returned Value	Meaning
TRUE	The Uuid1 argument is equal to the Uuid2 argument.
FALSE	The Uuid1 argument is not equal to the Uuid2 argument.
See Also

UuidCreate


UuidFromString
UuidFromString   QuickInfo

The UuidFromString function converts a string to a UUID.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
UuidFromString(
unsigned char *  StringUuid,
UUID *  Uuid);

Parameters

StringUuid

Points to a string representation of a UUID.

Uuid

Returns a pointer to a UUID in binary form.

Remarks

An application calls the UuidFromString routine to convert a string UUID to a binary UUID.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_INVALID_STRING_UUID	The string UUID is invalid
See Also

UuidToString


UuidHash
UuidHash   QuickInfo

The UuidHash function creates a hash value for a UUID.

#include <rpc.h>
unsigned short RPC_ENTRY
UuidHash(
UUID *  Uuid,
RPC_STATUS *  Status);

Parameters

Uuid

Specifies the UUID for which a hash value is created.

Status

Returns any errors that may occur, and will normally be set by the function to RPC_S_OK upon return.

Remarks

An application calls the UuidHash routine to generate a hash value for a specified UUID. The hash value returned is implementation dependent and may vary from implementation to implementation.

See Also

UuidCreate


UuidIsNil
UuidIsNil   QuickInfo

The UuidIsNil function determines if a UUID is a nil-valued UUID.

#include <rpc.h>
int RPC_ENTRY
UuidIsNil(
UUID *  Uuid,
RPC_STATUS *  Status);

Parameters

Uuid

Specifies a UUID to test for nil value.

Status

Returns any errors that may occur, and will typically be set by the function to RPC_S_OK upon return.

Remarks

An application calls the UuidIsNil routine to determine whether the specified UUID is a nil-valued UUID. This routine acts as though the application called the UuidCreateNil routine, and then called the UuidEqual routine to compare the returned nil-value UUID to the UUID specified in the Uuid argument.

Upon completion, one of the following is returned:

Returned Value	Meaning
TRUE	The Uuid argument is a nil-valued UUID.
FALSE	The Uuid argument is not a nil-valued UUID.
See Also

UuidCreate


UuidToString
UuidToString   QuickInfo

The UuidToString function converts a UUID to a string.

#include <rpc.h>
RPC_STATUS RPC_ENTRY
UuidToString(
UUID *  Uuid,
unsigned char * *  StringUuid);

Parameters

Uuid

Points to a binary UUID.

StringUuid

Returns a pointer to a pointer to the string representation of the UUID specified in the Uuid argument.

Specify a null value to prevent UuidToString from returning the StringUuid argument. In this case, the application does not call the RpcStringFree routine.

Remarks

An application calls UuidToString to convert a binary UUID to a string UUID. The RPC run-time library allocates memory for the string returned in the StringUuid argument. The application is responsible for calling the RpcStringFree routine to deallocate that memory.

Return Values

Value	Meaning
RPC_S_OK	Success
RPC_S_OUT_OF_MEMORY	No memory
See Also

RpcStringFree, UuidFromString


YieldFunctionName

YieldFunctionName is a placeholder name for the application-supplied function name provided as a parameter to the RpcWinSetYieldInfo routine.

BOOL FAR PASCAL  YieldFunctionName(void);

Remarks

The callback function must retrieve messages from the message queue (including mouse and keyboard messages) and must process messages, both queued and non-queued.

YieldFunctionName should return TRUE when the application is notified that the RPC operation has completed (by receiving the wMsg message). It is an error for YieldFunctionName to return TRUE if it has not been notified that the RPC operation has completed.

YieldFunctionName should return FALSE if the user wants to cancel the RPC operation in progress. The RPC run-time library then attempts to abort the current operation, which is likely to result in the RPC call returning an error to the application. Note that due to race conditions, the operation can complete successfully even if YieldFunctionName returns FALSE.

See Also

RpcWinSetYieldInfo


Installing RPC

Microsoft® RPC consists of two products: one for developing distributed applications and one for executing distributed applications. Using the RPC development tools, you can develop RPC distributed applications in C/C++ on a computer with a Microsoft® Windows NT™ operating system. Distributed applications developed using RPC technology can be executed as servers in the Windows NT environment and as clients in the Windows NT, Windows 3.x, MS-DOS®, and Macintosh environments. The RPC user environment, which consists of the RPC run-time files and libraries, must be installed on servers and workstations that run RPC distributed applications.

Once RPC is installed, you can configure the network transport protocols and the name-service provider that RPC uses.

This section contains information on the following topics:

•	Installing the RPC development tools

•	Installing RPC for executing distributed applications

•	Configuring the RPC name-service provider

•	Starting RPC services and utilities

•	Network-transport information for RPC


Installing the RPC Programming Environment

You develop RPC distributed applications on the 32-bit Windows NT platform. While the 16-bit MIDL compiler is not supported in this version of RPC, you can develop 16-bit code by doing the following:

1.	Use the 32-bit MIDL compiler installed as part of Win32 SDK Setup.

2.	Select the MS-DOS or Windows 3.x option of the MIDL /env command line switch.

3.	Compile your MS-DOS or Windows 3.x application and RPC stubs using your 16-bit development environment.

When the Win32 SDK is installed, the RPC development environment and the run-time libraries are automatically installed. For the Windows NT platform, no additional installation is required.

Note  See Building RPC Applications for information about various build environments.

When you install the 16-bit SDK, you install the following:

•	Header files and libraries needed to build RPC applications for MS-DOS and Windows 3.x.

•	Sample RPC programs for MS-DOS and Windows 3.x.

•	Run-time RPC and .DLL files for MS-DOS and Windows 3.x.

•	MIDL compiler for Microsoft Windows NT

When you install the Win32 SDK, you install the following:

•	C/C++ language header files (.H for the RPC run-time libraries) and run-time libraries (.LIB and .DLL) for Microsoft Windows NT

•	Sample programs for Microsoft Windows NT

•	RPC reference Help files

•	The uuidgen utility

When you install Windows NT, you install the following:

•	RPC Run-time .DLLs

•	RPC Locator and RPC Endpoint-mapping services


Microsoft Windows NT

The Microsoft Win32 SDK contains the Microsoft Windows NT and Microsoft Windows 95 APIs. When the Win32 SDK is installed, Microsoft RPC is also installed.


Windows/MS-DOS Client Applications

To develop client-side distributed applications for MS-DOS and Microsoft Windows 3.x, you must install the Microsoft Windows 3.x/MS-DOS version of the RPC toolkit. Microsoft RPC development for MS-DOS and Microsoft Windows requires:

•	Microsoft C/C++ version 7.0 or MSVC++ version 1.x

•	One of the following:

•	Microsoft Windows version 3.x with Microsoft LAN Manager version 2.2

•	Microsoft Windows 3.x with a Windows Sockets-compliant TCP/IP stack

•	Microsoft Windows 3.x with Workgroup Connection 3.1

•	Microsoft Windows for Workgroups 3.11 with NetBEUI or the Microsoft TCP/IP-32 stack

•	Microsoft Windows 3.x with NetWare 3.x or 4.x

•	Microsoft Windows for Workgroups 3.11 with NetWare 3.x or 4.x software

The Setup program for installing RPC for Windows prompts you to specify one of two installation options: Install All Files or Custom Install. The Install All Files option quickly installs all the RPC files; all you have to do is select a NetBIOS protocol and a name-service provider. With the Custom Install option, you can specify all information about the setup.

To start the RPC Setup program for a Windows/MS-DOS Client

1.	Insert the Setup disk in drive A.

2.	From the File menu, choose Run.

3.	In the Run box, type a:\setup and choose OK.

After the Microsoft RPC dialog box is displayed, the Name Service Installation Options dialog box appears.

4.	Choose Install Default Name Service Provider or Install Custom Name Service Provider, and then choose Continue.

When you choose Install Default Name Service Provider, the default name-service provider, the Microsoft Locator, is installed. The Microsoft Locator works in Microsoft Windows NT domains.

When you choose Install Custom Name Service Provider, complete the Define Network Address dialog box to install the DCE Cell Directory Service as your name-service provider. The DCE Cell Directory Service is the name-service provider used with DCE servers.

•	In the Network box, type the network address. The network address is the name of the host computer that runs the NSI daemon (NSID).

The host computer that runs the NSID acts as a gateway to the DCE Cell Directory Service, passing name-service interface function calls between computers that run Microsoft operating systems and DCE computers. The network address can be 80 characters or less — for example, 11.1.9.169 is a valid address.

5.	In the Installations Options dialog box, select the Install All Files option or the Custom Install option.

•	If you choose Install All Files, carry out the following procedure, "To run RPC Setup using the Install All Files option."

•	If you choose Custom Install, skip to To run RPC Setup using the Custom Install option.

To run RPC Setup using the Install All Files option

When you start the RPC Setup program and choose the Install All Files option, the Base Directory Path dialog box appears.

1.	In the Path box, type the path where you want to install the RPC directory.

It is a good idea to install the RPC files into the same location as your 16-bit C compiler. Otherwise, you must set the environment variables INCLUDE, LIB, and PATH to point to the directories that contain the RPC header files, libraries, and DLLs and binaries.

2.	Choose OK.

The Custom NetBIOS Protocols dialog box appears.

3.	In the Custom NetBIOS Protocols dialog box, select one of the following protocols:

•	Select Microsoft NetBEUI NetBIOS Protocol to install the NetBEUI NetBIOS protocol.

•	Select TCP/IP NetBIOS Protocol to install the TCP/IP protocol.

•	Select Custom NetBIOS Protocol if your computer uses more than one network card or more than one protocol. When you choose the Custom NetBIOS protocol, the NetBIOS Custom Protocol Mapping dialog box appears. Use the Current Mappings box to build a list of NetBIOS protocol mappings that associate the protocol you specify with a LAN adapter number. Add and delete NetBIOS protocol mappings using the New and Delete buttons.

To add a NetBIOS protocol, choose New. In the Protocol box, type the name of the protocol using the protocol names "nb" and "tcpip." In the LAN Adapter # box, type the LAN adapter number. You can use LAN adapter (lana) numbers 0 through 9. If your configuration has only one card and protocol, the LAN adapter number is usually 0. For more information about NetBIOS settings, see Network-Transport Information for RPC.

To delete a NetBIOS protocol, select the protocol from the Current Mappings box and choose Delete.

To run RPC Setup using the Custom Install option

When you start the RPC Setup program and choose the Custom Install option, the SDK Tools Options dialog box appears.

1.	In the Base Installation Path box, choose Path to change the location where the RPC directory is installed.

The Path box automatically displays the path to the Microsoft C/C++ version 7.0 directory. If you type a different path, it should point to the same location as this directory. Otherwise, you must set the environment variables INCLUDE, LIB, and PATH to point to the directories that contain the RPC header files, libraries, and DLLs and binaries.

2.	In the Installation Options box, select one or more of the following files to install:

•	MS-DOS Libraries and Include Files. If you are developing a distributed application that will be used on MS-DOS clients, you must install these libraries and include files.

•	Windows Libraries and Include Files. If you are developing a distributed application that will be used on Windows clients, you must install these libraries.

•	Online Help Files. The Help files are not needed to develop applications. They are designed to answer questions during the development process.

3.	Choose Continue.

The Run-Time Custom Install Options dialog box appears.

4.	In the Run-Time Custom Install Options dialog box, set one or more of the following options:

•	Under Registry Data File Path, choose Set Location to specify the location of the configuration file. The configuration file contains all of the configurable RPC components, which you can modify at a later time. Type the path in the Path box. The default is the root directory.

•	In the MS-DOS Options box, set the MS-DOS configuration options. If you did not install MS-DOS libraries and include files in the previous step, don't modify this section.

Select the MS-DOS Run-time Support box to install the MS-DOS run-time libraries. This box must be marked if you will be programming or executing RPC in MS-DOS.

Under Runtime DLL Path, choose Set Location to specify the path where the DLLs are stored. Type the path in the Path box. Choose OK.

•	To install Windows run-time libraries, select the Windows Run-time Support box. If you are programming in Microsoft Windows, you must install Windows run-time libraries.

•	Under Network Drivers, select the Load All box to install all drivers.

Choose the Set Location button to specify the drivers your distributed application uses. Select the protocol adapters you want to install. To select more than one driver, hold down the CTRL key as you select additional drivers. To undo your selection, choose Reset Selection.

5.	Choose Continue.

The Custom NetBios Protocols dialog box appears.

6.	Follow step 3 in To run RPC Setup using the Install All Files option.


Writing Macintosh Client Applications

To develop client-side applications for the Macintosh, you must have the following:

•	Visual C++ for the Macintosh. The RPC runtime has been compiled using Visual C++, version 2.0, cross development tools. In order to use rpc.lib, you must link against the C runtime and swapper library (swap.lib) provided with Visual C++, version 2.0.

•	Macintosh RPC SDK, which can be found in the mac_rpc directory. Note that the current rpc.lib is native 68K. We currently do not provide a native Power Mac library. RPC runs in emulation on Power Macs.

•	The target computer must have a microprocessor of 68020 or later, and it must be running System 7.0 or later.

Note  There is no Macintosh support for the Windows 95 platform.

To set up the Windows NT server:

•	Current supported protocols for the Macintosh are ADSP and TCP/IP. In order to use ADSP, the Windows NT server must have both the AppleTalk protocol and Services for Macintosh.

To write an RPC client:

1.	If you use atexit to perform cleanup at shutdown, do not call any RPC APIs in your exit processing function.

2.	If a yielding function is not registered, an RPC will not yield on the Macintosh. Register a yielding function by calling RpcMacSetYieldInfo.

void RPC_ENTRY MacCallbackFunc(short *pStatus)

{

  MSG msg;

  while (*pStatus == 1)

  {

if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

  }

}

3.	Most client-side APIs that are supported by Windows 3.x are also supported by the Macintosh. The following APIs are not supported by the Macintosh:

•	RpcNs* APIs

•	RpcMgmt* APIs

•	RpcWinSetYieldInfo (replaced by RpcMacSetYieldInfo)

The only authentication service currently supported for the Macintosh is RPC_C_AUTHN_WINNT.

The following protocol sequences are supported:

•	ADSP:ncacn_at_dsp

•	TCP:ncacn_ip_tcp


Installing RPC for Distributed-Application Users

When you use an RPC application on a Windows 3.x or MS-DOS system, the RPC run-time executables must be copied to the Windows 3.x or MS-DOS machines that will be using the application.

Microsoft RPC provides two utility programs to create RPC run-time installation disks to accompany your distributed application. These utilities provide the Setup program and the Microsoft RPC run-time libraries for use with Microsoft Windows/MS-DOS and MS-DOS. The RPC run-time libraries are automatically installed with Windows NT and no further RPC installation is required.

Microsoft RPC provides the following run-time installation utilities:

•	The WRUNDISK.BAT utility, which creates a Microsoft Windows/MS-DOS run-time installation disk

•	The DRUNDISK.BAT utility, which creates an MS-DOS-only run-time installation disk


installing: RPC
Creating RPC Install Disks for Windows NT Servers and Clients

When Windows NT is installed on a server or client, the RPC run-time files are automatically installed as well. No further RPC installation is required.

However, to run MS-DOS or Microsoft Windows 16-bit clients on Windows NT, your application's install program must install the proper Windows/MS-DOS client DLLs.


Creating RPC Install Disks for Windows Clients

The WRUNDISK.BAT utility copies the RPC run-time libraries from an installed Microsoft Win32 SDK to create a Microsoft Windows/MS-DOS run-time install disk.

To create RPC install disks for a Windows client

1.	Copy the compressed files from the Microsoft Win32 SDK directory \MSTOOLS\RPC_DOS\DISK1 to a floppy disk or directory on your hard disk.

2.	Insert a formatted, blank floppy disk in the destination drive.

3.	At the MS-DOS prompt, type:

wrundisk source destination

source

Specifies the path to the disk or directory that contains the compressed files provided in the Microsoft Win32 SDK directory \MSTOOLS\RPC_DOS\DISK1.

destination

Specifies the name of the drive that contains the formatted, blank floppy disk. For example, the command

wrundisk c:\nt\mstools\rpc_dos\disk1 a:

copies the compressed files to a floppy disk in drive A.

Your application user can then use the Setup program on the run-time install disk to install the RPC run-time libraries.


Creating RPC Install Disks for MS-DOS Clients

The DRUNDISK.BAT utility copies files from an installed Microsoft Win32 SDK to create an MS-DOS-only run-time install disk. To ensure that all MS-DOS loadable transports are present on the run-time install disk, you must select all loadable transports at the time you install the Microsoft Win32 SDK.

To create RPC install disks for an MS-DOS client

1.	Insert a formatted, blank floppy disk in the destination drive.

2.	At the MS-DOS prompt, type:

drundisk directory destination

directory

Specifies the name of the directory that contains all loadable transport (.RPC) files and all name-service DLLs — for example,
C:\LANMAN.DOS\NETPROG

destination

Specifies the name of the drive that contains the formatted, blank floppy disk. For example, the command

drundisk c:\lanman.dos\netprog a:

copies the MS-DOS run-time libraries, the loadable transport files, and the name-service DLLs from the C drive to the floppy disk in drive A.

Your application user can then use the Setup program on the run-time install disk to install the RPC run-time libraries.


Configuring the Name-Service Provider

When a server registers its distributed application using a name-service provider, other computers using a name-service provider that want to interoperate with the server must use the same name-service provider as that of the server. Microsoft RPC interoperates with the Microsoft Locator and any name-service provider that adheres to the Microsoft RPC name-service interface (NSI) — for example, the DCE Cell Directory Service accessed through the DEC NSID.

In Microsoft RPC, the Microsoft Locator is the default name-service provider. It is designed for use in Windows environments.


Reconfiguring the Name Service for Microsoft Windows NT

When you install Microsoft Windows NT, the Microsoft Locator is automatically selected as the name-service provider. You can change the name-service provider through the Windows NT Control Panel.

To configure the name-service provider for Windows NT

1.	In the Control Panel, choose the Networks icon.

The Networks dialog box appears.

2.	In the Networks dialog box, choose Add Software.

3.	In the Network Software list, select Remote Procedure Call (RPC) Service, and then choose Configure.

The RPC Name Service Provider Configuration dialog box appears.

4.	In the RPC Name Service Provider Configuration dialog box, select a name-service provider from the list.

•	When you choose the Microsoft Locator, choose OK and the configuration process is complete.

•	When you choose the DCE Cell Directory Service, in the Network Address box type the name of the host computer that runs the NSI daemon (NSID), and then choose OK.

The host computer that runs the NSID acts as a gateway to the DCE Cell Directory Service, passing name-service interface function calls between computers that run Microsoft operating systems and DCE computers. A network address can be up to 80 characters — for example, 11.1.9.169 is a valid address.

Note  You must have Digital Equipment Corporation's DCE DCS product to configure the DCE CDS as your name-service provider. See the documentation provided by Digital Equipment Corporation for information about DCE CDS.


Reconfiguring the Name Service for Windows/MS-DOS

When you install the Win32 SDK for Windows/MS-DOS, you specify a name-service provider. You can change the name-service provider you specified by editing the RPCREG.DAT configuration file, which contains the name-service-provider parameters and RPC protocol settings. Use a text editor to change name-service provider entries.

To reconfigure the Microsoft Locator name-service provider

1.	Open the RPCREG.DAT file using a text editor.

RPCREG.DAT is in the root directory unless you specified a different path during the Setup program.

2.	Set the following values for the registry entries:

Registry entry	Value
Software\Microsoft\RPC \NameService\Protocol	The protocol sequence for the protocol you are using. The default is ncacn_np.
Software\Microsoft\RPC\ NameService\NetworkAddress	The name of the computer running the Locator that is used by clients during name-service lookup operations. The default is the primary domain controller.
Software\Microsoft\RPC\ NameService\Endpoint	The name of the endpoint used by the name service. The default is \pipe\locator.
3.	Save and close the file.

To configure the DCE CDS name-service provider

•	You must have Digital Equipment Corporation's DCE DCS product to configure the DCE CDS as your name-service provider. See the documentation provided by Digital Equipment Corporation for information about DCE CDS.


Configuring the Security Server

Use the following to configure the security server for RPC:

1.	Start Windows NT and choose the Control Panel icon.

2.	In the Control Panel, choose the Networks icon.

The Network Settings dialog box appears.

3.	In the Installed Network Software list, select RPC Configuration.

The RPC Configuration dialog box appears.

4.	In the Security Service Provider list, select from one or more security providers.

5.	Select OK.


Starting and Stopping RPC Services and Utilities on Microsoft Windows NT

On Microsoft Windows NT, the Microsoft Locator and the endpoint-mapping service are automatically started by the RPC run-time libraries when necessary. You can stop the Locator or the endpoint-mapping service on a machine. They will be restarted, as necessary, by the RPC run-time libraries.

Note  Only administrators can start the RPC Locator and Endpoint-mapping services once they are stopped.

To stop and start the RPC endpoint-mapping service

1.	From the Control Panel, select Services.

The Services dialog box appears.

2.	In the Service box, select Remote Procedure Call (RPC) Service and choose Start or Stop.

To stop and start the Microsoft Locator

1.	From the Control Panel, select Services.

The Services dialog box appears.

2.	In the Service box, select Remote Procedure Call (RPC) Locator and choose Start or Stop.


Network-Transport Information for RPC

This section contains information describing the Windows NT registry entries and information relating to SPX1IPX installations.

Registry Information

When you install Microsoft Windows NT or you run the Windows/MS-DOS Setup programs, the RPC protocol information you specify is stored in the registry file. The Windows NT registry entries are automatically configured and no further configuration is necessary. With MS-DOS and Windows 3.1, use a text editor to change entries in the RPCREG.DAT file:

Registry entry	Description
SOFTWARE\Microsoft\Rpc\ NameService\DefaultSyntax	Specifies the default syntax that is used by the RPC functions RpcNsBindingImportBegin and RpcNsBindingExport. This registry entry corresponds to the DCE environment variable RPC_DEFAULT_ENTRY_SYNTAX.
SOFTWARE\Microsoft\Rpc\ NameService\NetworkAddress	Specifies the address of the computer running the Locator that is used by clients during name-service lookup operations. The default setting is the primary domain controller.
SOFTWARE\Microsoft\Rpc\ NameService\ServerNetworkAddress	Specifies the address of the computer running the Locator that is used by servers during name-service export operations. Default is PDC (Windows NT only).
SOFTWARE\Microsoft\Rpc\ NameService\Endpoint	Specifies the endpoint used by the name service.
SOFTWARE\Microsoft\Rpc\ NameService\Protocol	Specifies the protocol used by the name service.
SOFTWARE\Microsoft\Rpc\ ClientProtocols\ncacn_np	Specifies the name of the RPC client transport DLL for named pipes.
SOFTWARE\Microsoft\Rpc\ ClientProtocols\ncacn_ip_tcp	Specifies the name of the RPC client transport DLL for TCP/IP.
SOFTWARE\Microsoft\Rpc\ ClientProtocols\ncacn_nb_nb	Specifies the name of the RPC client transport DLL for NetBEUI over NetBIOS.
SOFTWARE\Microsoft\Rpc\ ClientProtocols\ncalrpc	Specifies the name of the RPC client transport DLL for local RPC (Windows NT only).
SOFTWARE\Microsoft\Rpc\ ServerProtocols\ncacn_np	Specifies the name of the RPC server transport DLL for named pipes.
SOFTWARE\Microsoft\Rpc\ ServerProtocols\ncacn_ip_tcp	Specifies the name of the RPC server transport DLL for TCP/IP.
SOFTWARE\Microsoft\Rpc\ ServerProtocols\ncacn_nb_nb	Specifies the name of the RPC server transport DLL for NetBEUI.
SOFTWARE\Microsoft\Rpc\ ServerProtocols\ncalrpc	Specifies the name of the RPC server transport DLL for local RPC (Windows NT only).
SOFTWARE\Microsoft\Rpc\NetBios	Consists of mapping strings that map protocols to NetBIOS lana numbers. For NetBIOS information, see the following section.
The Microsoft RPC Setup program automatically maps protocol strings to NetBIOS lana numbers and writes these settings in the registry. These mappings work as long as you only have one network card and one network protocol. If you have more than one network card and network protocol, or if you change your network configuration after installing Microsoft RPC, you must update the registry to indicate the new correspondences between protocol strings and NetBIOS lana numbers.

For Microsoft Windows NT, the mapping string appears in the registry tree under \SOFTWARE\Microsoft\Rpc\NetBios. For MS-DOS and Windows, the mapping string appears in the registry file RPCREG.DAT.

The mapping string uses the following syntax:

ncacn_nb_protocol digit=lana_number

protocol

Specifies the protocol type. The valid protocol values are as follows:

Protocol	Protocol type
nb	NetBEUI
tcp	TCP/IP
digit

Specifies a unique number associated with each instance of a protocol. Use the value 0 for the first instance of a protocol and use the next consecutive number for each additional instance of that protocol. For example, assign the value ncacn_nb_nb0 to the first NetBEUI entry; assign the value ncacn_nb_nb1 to the second NetBEUI entry.

lana_number

Specifies the NetBIOS lana number.

A unique lana number is associated with each network adapter present in the computer. For LAN Manager networks, the lana numbers for each network card are available in the configuration files LANMAN.INI and PROTOCOL.INI. For more information about the lana number, see your network documentation.

For example, the following mapping string describes a configuration that uses the NetBEUI protocol over an adapter card that is assigned lana number 0:

ncacn_nb_nb0=0

When you install a second card that supports both XNS and NetBEUI protocols, the mapping strings appear as follows:

ncacn_nb_tcp0=0

ncacn_nb_nb1=1

SPX/IPX Installation

When using the ncacn_spx and ncadg_ipx transports, the server name is exactly the same as the Windows NT server name. However, since the names are distributed using Novell protocols, they must conform to the Novell naming conventions. If a server name is not a valid Novell name, servers will not be able to create endpoints with the ncacn_spx or ncadg_ipx transports.

A valid Novell server name contains only the characters between 0x20 and 0x7f. Lowercase characters are changed to uppercase. The following characters cannot be used:

"*,./:;<=>?[]\|]

To maintain compatibility with the first version of Windows NT, ncacn_spx and ncadg_ipx also allow you to use a special format of the server name known as the tilde name. The tilde name consists of a tilde, followed by the server's eight-digit network number, and then followed by its twelve-digit Ethernet address. Tilde names have an advantage in that they do not require any name service capabilities. Thus, if you are connected to a server, the tilde name will work.

The following tables contain two sample configurations used to illustrate the points described above:

Component	Configured As
Windows NT Server	NWCS
Windows NT Client	NWCS
Windows 3.x/MS-DOS Client	NetWare Redirector
The configuration in the table above requires that you have NetWare file servers or routers on your network. It will produce the best performance because the server names are stored in the NetWare Bindery.

Component	Configured As
Windows NT Server	SAP Agent
Windows NT Client	IPX/SPX
Windows 3.x/MS-DOS Client	IPX/SPX
The second configuration works in an environment that does not contain NetWare file servers or routers (for example, a network of two computers: a Windows NT server and an MS-DOS client). Name resolution, which is accomplished during the first call over a binding handle, will be slightly slower than the first configuration. In addition, the second configuration results in more traffic generated over the network.

To implement name resolution, when an RPC server uses an SPX or IPX endpoint, the server name and endpoint are registered as a SAP server of type 640 (hexadecimal). To resolve a server name, the RPC client sends a SAP request for all services of the same type, and then scans the list of responses for the name of the server. This process occurs during the first RPC call over each binding handle. For additional information on the SAP protocol for Novell, see your NetWare documentation.


Error Codes

RPC functions can return the following Win32 error codes:

Manifest	Description
EPT_S_CANT_CREATE	The endpoint-map database cannot be created.
EPT_S_CANT_PERFORM_OP	The operation cannot be performed.
EPT_S_INVALID_ENTRY	The entry is invalid.
EPT_S_NOT_REGISTERED	There are no more endpoints available from the endpoint-map database.
RPC_S_ACCESS_DENIED	The user does not have sufficient privilege to complete the operation.
RPC_S_ADDRESS_ERROR	An addressing error has occurred on the server.
RPC_S_ALREADY_LISTENING	The server is already listening.
RPC_S_ALREADY_REGISTERED	The object UUID has already been registered.
RPC_S_BINDING_HAS_NO_AUTH	The binding does not contain any authentication information.
RPC_S_BINDING_INCOMPLETE	The binding handle is a required parameter.
RPC_S_BUFFER_TOO_SMALL	The buffer used to transmit data is too small.
RPC_S_CALL_CANCELLED	The remote procedure call exceeded the cancel timeout and was cancelled.
RPC_S_CALL_FAILED	The remote procedure call failed.
RPC_S_CALL_FAILED_DNE	The remote procedure call failed and did not execute.
RPC_S_CALL_IN_PROGRESS	A remote procedure call is already in progress for this thread.
RPC_S_CANNOT_SUPPORT	The requested operation is not supported.
RPC_S_CANT_CREATE_ENDPOINT	The endpoint cannot be created.
RPC_S_COMM_FAILURE	Unable to communicate with the server.
RPC_S_DUPLICATE_ENDPOINT	The endpoint is a duplicate.
RPC_S_ENTRY_ALREADY_EXISTS	The entry already exists.
RPC_S_ENTRY_NOT_FOUND	The entry is not found.
RPC_S_FP_DIV_ZERO	A floating-point operation at the server has caused a divide by zero.
RPC_S_FP_OVERFLOW	A floating-point overflow has occurred at the server.
RPC_S_FP_UNDERFLOW	A floating-point underflow occurred at the server.
RPC_S_GROUP_MEMBER_NOT_FOUND	The group member has not been found.
RPC_S_INCOMPLETE_NAME	The entry name is incomplete.
RPC_S_INTERFACE_NOT_FOUND	The interface has not been found.
RPC_S_INTERNAL_ERROR	An internal error has occurred in a remote procedure call.
RPC_S_INVALID_ARG	The specified argument is not valid.
RPC_S_INVALID_AUTH_IDENTITY	The security context is invalid.
RPC_S_INVALID_BINDING	The binding handle is invalid.
RPC_S_INVALID_BOUND	The array bounds are invalid.
RPC_S_INVALID_ENDPOINT_FORMAT	The endpoint format is invalid.
RPC_S_INVALID_LEVEL	The level parameter is invalid.
RPC_S_INVALID_NAF_ID	The network-address family is invalid.
RPC_S_INVALID_NAME_SYNTAX	The name syntax is invalid.
RPC_S_INVALID_NET_ADDR	The network address is invalid.
RPC_S_INVALID_NETWORK_OPTIONS	The network options are invalid.
RPC_S_INVALID_OBJECT	The object is invalid.
RPC_S_INVALID_RPC_PROTSEQ	The RPC protocol sequence is invalid.
RPC_S_INVALID_SECURITY_DESC	The security descriptor is not in the valid format.
RPC_S_INVALID_STRING_BINDING	The string binding is invalid.
RPC_S_INVALID_STRING_UUID	The string UUID is invalid.
RPC_S_INVALID_TAG	The discriminant value does not match any of the case values. There is no default case.
RPC_S_INVALID_TIMEOUT	The timeout value is invalid.
RPC_S_INVALID_VERS_OPTION	The version option is invalid.
RPC_S_MAX_CALLS_TOO_SMALL	The maximum number of calls is too small.
RPC_S_NAME_SERVICE_UNAVAILABLE	The name service is unavailable.
RPC_S_NO_BINDINGS	There are no bindings.
RPC_S_NO_CALL_ACTIVE	There is no remote procedure call active in this thread.
RPC_S_NO_CONTEXT_AVAILABLE	No security context is available to allow impersonation.
RPC_S_NO_ENDPOINT_FOUND	No endpoint has been found.
RPC_S_NO_ENTRY_NAME	The binding does not contain an entry name.
RPC_S_NO_ENV_SETUP	No environment variable  is set up.
RPC_S_NO_INTERFACES	No interfaces are registered.
RPC_S_NO_INTERFACES_EXPORTED	No interfaces have been exported.
RPC_S_NO_MORE_BINDINGS	There are no more bindings.
RPC_S_NO_MORE_ELEMENTS	There are no more elements.
RPC_S_NO_MORE_MEMBERS	There are no more members.
RPC_S_NO_NS_PRIVILEGE	There is no privilege for a  name-service operation.
RPC_S_NO_PRINC_NAME	No principal name is registered.
RPC_S_NO_PROTSEQS	There are no protocol sequences.
RPC_S_NO_PROTSEQS_REGISTERED	No protocol sequences have been registered.
RPC_S_NOT_ALL_OBJS_UNEXPORTED	Not all objects are unexported.
RPC_S_NOT_CANCELLED	The thread is not cancelled.
RPC_S_NOT_LISTENING	The server is not listening.
RPC_S_NOT_RPC_ERROR	The status code requested is not valid.
RPC_S_NOTHING_TO_EXPORT	There is nothing to export.
RPC_S_OBJECT_NOT_FOUND	The object UUID has not been found.
RPC_S_OK	The call has completed successfully.
RPC_S_OUT_OF_MEMORY	The needed memory is not available.
RPC_S_OUT_OF_RESOURCES	Not enough resources are available to complete this operation.
RPC_S_OUT_OF_THREADS	The RPC run-time library was not able to create another thread.
RPC_S_PROCNUM_OUT_OF_RANGE	The procedure number is out of range.
RPC_S_PROTOCOL_ERROR	An RPC protocol error has occurred.
RPC_S_PROTSEQ_NOT_FOUND	The RPC protocol sequence has not been found.
RPC_S_PROTSEQ_NOT_SUPPORTED	The RPC protocol sequence is not supported.
RPC_S_SEC_PKG_ERROR	There is an error with the security package.
RPC_S_SERVER_NOT_LISTENING	The server is not listening for remote procedure calls.
RPC_S_SERVER_OUT_OF_MEMORY	The server has insufficient memory to complete this operation.
RPC_S_SERVER_TOO_BUSY	The server is too busy to complete this operation.
RPC_S_SERVER_UNAVAILABLE	The server is unavailable.
RPC_S_STRING_TOO_LONG	The string is too long.
RPC_S_TYPE_ALREADY_REGISTERED	The type UUID has already been registered.
RPC_S_UNKNOWN_AUTHN_LEVEL	The authentication level is unknown.
RPC_S_UNKNOWN_AUTHN_SERVICE	The authentication service is unknown.
RPC_S_UNKNOWN_AUTHN_TYPE	The authentication type is unknown.
RPC_S_UNKNOWN_AUTHZ_SERVICE	The authorization service is unknown.
RPC_S_UNKNOWN_IF	The interface is unknown.
RPC_S_UNKNOWN_MGR_TYPE	The manager type is unknown.
RPC_S_UNSUPPORTED_AUTHN_LEVEL	The authentication level is not supported.
RPC_S_UNSUPPORTED_NAME_SYNTAX	The name syntax is not supported.
RPC_S_UNSUPPORTED_TRANS_SYN	The transfer syntax is not supported by the server.
RPC_S_UNSUPPORTED_TYPE	The type UUID is not supported.
RPC_S_UUID_LOCAL_ONLY	The UUID that is only valid for this computer has been allocated.
RPC_S_UUID_NO_ADDRESS	No network address is available for constructing a UUID.
RPC_S_WRONG_KIND_OF_BINDING	The binding handle is not the correct type.
RPC_S_ZERO_DIVIDE	The server has attempted an integer divide by zero.
RPC_X_BAD_STUB_DATA	The stub has received bad data.
RPC_X_BYTE_COUNT_TOO_SMAL	The byte count is too small.
RPC_X_ENUM_VALUE_OUT_OF_RANGE	The enumeration value is out of range.
RPC_X_ENUM_VALUE_TOO_LARGE	The enumeration constant must be less than 65535.
RPC_X_INVALID_BOUND	The specified bounds of an array are inconsistent.
RPC_X_INVALID_TAG	The discriminant value does not match any of the case values. There is no default case.
RPC_X_NO_MEMORY	Insufficient memory is available.
RPC_X_NO_MORE_ENTRIES	The list of servers available for the auto_handle binding has been exhausted.
RPC_X_NULL_REF_POINTER	A null reference pointer has been passed to the stub.
RPC_X_SS_BAD_ES_VERSION	The operation for the serializing handle is not valid.
RPC_X_SS_CANNOT_GET_CALL_HANDLE	The stub is unable to get the call handle.
RPC_X_SS_CHAR_TRANS_OPEN_FAIL	The file designated by DCERPCCHARTRANS cannot be opened.
RPC_X_SS_CHAR_TRANS_SHORT_FILE	The file containing the character-translation table has fewer than 512 bytes.
RPC_X_SS_CONTEXT_DAMAGED	The context handle changed during a call. Only raised on the client side.
RPC_X_SS_CONTEXT_MISMATCH	The context handle does not match any known context handles.
RPC_X_SS_HANDLES_MISMATCH	The binding handles passed to a remote procedure call do not match.
RPC_X_SS_IN_NULL_CONTEXT	A null context handle is passed in an in parameter position.
RPC_X_SS_INVALID_BUFFER	The buffer is not valid for the operation.
RPC_X_SS_WRONG_ES_VERSION	The software version is incorrect.
RPC_X_SS_WRONG_STUB_VERSION	The stub version is incorrect.


MIDL Compiler Errors and Warnings

This section lists MIDL compiler error and warning messages.

An error or warning message sometimes specifies the name of one or more MIDL compiler mode switches. The MIDL compiler accepts an IDL file when you use some mode switches but generates errors for the same file when you do not use mode switches. For example, abstract declarators are valid in Microsoft-extensions mode but generate errors when the /ms_ext switch is not specified.

Command-line errors appear in the following format:

Command line error : MIDLnnnn : <error text>

[<additional error information>]

The additional-error information field provides context-specific information about the error. The information in this field depends on the error message. For example, when an unresolved type-declaration error occurs, the additional-information field displays the name of the type that could not be resolved.

Compile-time warnings appear in the following format:

<FileName>(line#) : warning MIDLnnnn :

<warning text>

[optional context information] :

Compile-time errors appear in the following format:

<FileName>(line#) : error MIDLnnnn :

<error text>

[optional context information] :

Optional context information refers to the context in which the error occurred. The MIDL compiler reports this information to help you quickly find the error in the IDL file. Context information is generated when the MIDL compiler discovers an error during semantic analysis of type and procedure signatures.

MIDL1000 : missing source file name

No input file has been specified in the MIDL compiler command line.

MIDL1001 : cannot open input file

The input file specified could not be opened.

MIDL1002 : error while reading input file

The system returned an error while reading the input file.

MIDL1003 : error returned by the C preprocessor

The preprocessor returned an error. The error message is directed to the output stream.

MIDL1004 : cannot execute C preprocessor

The operating system reported an error when it tried to spawn the preprocessor. With MS-DOS, this error can occur when the argument list exceeds 128 bytes. You can reduce the size of the argument list by using a response file.

MIDL1005 : cannot find C preprocessor

The MIDL compiler cannot locate the preprocessor in the specified path or in the path specified by the PATH environment variable.

MIDL1006 : invalid C preprocessor executable

The specified preprocessor is not executable or has an invalid executable-file format.

MIDL1007 : switch specified more than once on command line

A switch has been redefined. The redefined switch is displayed after the error message.

MIDL1008 : unknown switch

An unknown switch has been specified on the command line.

MIDL1009 : unknown argument ignored

The MIDL compiler does not recognize the command-line argument as either a switch, a switch argument, or a filename. The compiler discards the unknown argument and attempts to continue processing.

MIDL1010 : switch not implemented

The switch is defined as part of the IDL compiler but is not implemented in Microsoft RPC.

MIDL1011 : argument(s) missing for switch

The switch expected an argument and the argument is not present. Check the syntax documentation for the specified switch.

MIDL1012 : argument illegal for switch /

The argument supplied to the specified switch is illegal.

MIDL1013 : illegal syntax for switch

Several command-line switches require a space between the switch and the argument, while other switches require no space between the switch and the argument. The specified command line violates the defined syntax for that switch.

MIDL1014 : /no_cpp overrides /cpp_cmd and /cpp_opt

The cpp_opt command has been supplied along with the /no_cpp switch. The /no_cpp switch takes precedence over the other switches.

MIDL1015 : /no_warn overrides warning-level switch

The no_warn option has been specified along with the warning-level switch W1, W2, or W3. The /no_warn switch takes precedence over all other warning-level switches.

MIDL1016 : cannot create intermediate file

The system returned an error when the compiler tried to create an intermediate file.

MIDL1018 : out of system file handles

The MIDL compiler ran out of file handles while opening a file. This error can occur if too many import files are open and the compiler tries to open an IDL file or an intermediate file.

MIDL1020 : cannot open response file

The specified response file could not be opened. The file probably does not exist.

MIDL1021 : illegal character(s) found in response file

A non-printable character has been detected in the response file. The response file should contain valid MIDL command-line switches and arguments.

MIDL1023 : nested invocation of response files is illegal

A response file cannot contain the @ command that directs the MIDL compiler to process another response file. Although there is no limit on the number of response files, response files cannot be nested.

MIDL2000 : must specify /c_ext for abstract declarators

Abstract declarators represent a Microsoft extension to RPC and are not defined in DCE RPC. To compile a file that includes abstract declarators, you must use the /c_ext switch.

MIDL2001 : instantiation of data is illegal; you must use "extern" or "static"

Declaration and initialization in the IDL file are not compatible with DCE RPC. To instantiate data, use the Microsoft extensions to RPC by compiling with either the /ms_ext or /c_ext compiler switch.

MIDL2002 : compiler stack overflow

The compiler ran out of stack space while processing the IDL file. This problem can occur when the compiler is processing a complex declaration or expression. To solve the problem, simplify the complex declaration or expression.

MIDL2003 : redefinition

This error message can appear under the following circumstances: a type has been redefined; a procedure prototype has been redefined; a member of a structure or union of the same name already exists; a parameter of the same name already exists in the prototype.

MIDL2004 : [auto_handle] binding will be used for procedure

No handle type has been defined as the default handle type. The compiler assumes that an auto handle will be used as the binding handle for the specified procedure.

MIDL2005 : out of memory

The compiler ran out of memory during compilation. Reduce the size or complexity of the IDL file or allocate more memory to the process.

MIDL2006 : recursive definition

A structure or union has been recursively defined. This error can occur when a pointer specification in a nested structure definition is missed.

MIDL2007 : import ignored; file already imported

Importing an IDL file is an idempotent operation. All but the first import operation are ignored.

MIDL2008 : sparse enums require /c_ext or /ms_ext switch

Assigning to enumeration constants is not compatible with DCE RPC. To use the extensions to RPC that permit assigning values to enumeration constants, use the /c_ext or /ms_ext switch.

MIDL2009 : undefined symbol

An undefined symbol has been used in an expression. This error can occur when you use an enum label that is not defined.

MIDL2010 : type used in ACF file not defined in IDL file

An undefined type is being used.

MIDL2011 : unresolved type declaration

The type reported in the additional-information field has not been defined elsewhere in the IDL file.

MIDL2012 : use of wide-character constants requires /ms_ext or /c_ext

Wide-character constants are a Microsoft extension to DCE IDL. To enable the use of the data type wchar_t, use the MIDL compiler switch /ms_ext or /c_ext.

MIDL2013 : use of wide-character strings requires /ms_ext or /c_ext

Wide-character string constants are a Microsoft extension to DCE IDL. To enable the use of the data type wchar_t, use the MIDL compiler switch /ms_ext or
/c_ext.

MIDL2014 : inconsistent redefinition of type wchar_t

The type wchar_t has been redefined as a type that is not equivalent to unsigned short.

MIDL2017 : syntax error

The compiler detected a syntax error at the specified line.

MIDL2018 : cannot recover from earlier syntax errors; aborting compilation

The MIDL compiler automatically tries to recover from syntax errors by adding or removing syntactic elements. This message indicates that despite these attempts to recover, the compiler detected too many errors. Correct the specified error(s) and recompile.

MIDL2019 : unknown pragma option

The specified C pragma is not supported in MIDL. Remove the pragma from the IDL file.

MIDL2020 : feature not implemented

The MIDL feature, although part of the language definition, is not implemented in Microsoft RPC and is not supported by the MIDL compiler. For example, the following language features are not implemented: bitset, pipe, and the international character type. The unimplemented language feature appears in the additional-information field of the error message.

MIDL2021 : type not implemented

The specified data type, although a legal MIDL keyword, is not implemented in Microsoft RPC.

MIDL2022 : non-pointer used in a dereference operation

A data type that is not a pointer has been associated with pointer operations. You cannot access the object through the specified non-pointer.

MIDL2023 : expression has a divide by zero

The constant expression contains a divide by zero.

MIDL2024 : expression uses incompatible types

The left and right sides of the operator in an expression are of incompatible types.

MIDL2025 : non-array expression uses index operator

The expression uses the array-indexing operation on a data item that is not of the array type.

MIDL2026 : left-hand side of expression does not evaluate to struct/union/enum

The direct or indirect reference operator "." or "->" has been applied to a data object that is not a structure, union, or enum. You cannot obtain a direct or indirect reference using the specified object.

MIDL2027 : constant expression expected

A constant expression was expected in the syntax. For example, array bounds require a constant expression. The compiler issues this error message when the array bound is defined with a variable or undefined symbol.

MIDL2028 : expression cannot be evaluated at compile time

The compiler cannot evaluate an expression at compile time.

MIDL2029 : expression not implemented

A feature that was supported in previous releases of the MIDL compiler is not supported in the version of the compiler supplied with Microsoft RPC. Remove the specified feature.

MIDL2030 : no [pointer_default] specified, assuming [unique] for all unattributed pointers

The MIDL compiler offers three different default cases for pointers that do not have pointer attributes. Function parameters that are top-level pointers default to ref pointers. Pointers embedded in structures and pointers to other pointers (not top-level pointers) default to the type specified by the pointer_default attribute. When no pointer_default attribute is supplied, these non-top-level pointers default to unique pointers. This error message indicates the last case: no pointer_default attribute is supplied and there is at least one non-top-level pointer that will be treated as a unique pointer.

MIDL2031 : [out] only parameter cannot be a pointer to an open structure

An out-only parameter has been used as a pointer to a structure, known as an open structure, whose transmitted range and size are determined at run time. The server stub does not know how much space to allocate for an open structure. Use a pointer to a pointer to the open structure and ensure that the server application allocates sufficient space for it.

MIDL2032 : [out] only parameter cannot be an unsized string

An array with the string attribute has been declared as an out-only parameter without any size specification. The server stub needs size information to allocate memory for the string. You can remove the string attribute and add the size_is attribute, or you can change the parameter to an in, out parameter.

MIDL2033 : [out] parameter is not a pointer

All out parameters must be pointers, in keeping with the call-by-value convention of the C programming language. The out directional parameter indicates that the server transmits a value to the client. With the call-by-value convention, the server can transmit data to the client only if the function argument is a pointer.

MIDL2034 : open structure cannot be a parameter

A structure or union is truncated when the last element of that structure or union is a conformant array.

MIDL2035 : [out] context handle/generic handle must be specified as a pointer to that handle type

A context-handle or user-defined handle parameter with the out directional attribute must be a pointer to a pointer.

MIDL2036 : [context_handle] must not derive from a type that has the [transmit_as] attribute

Context handles must be transmitted as context-handle types. They cannot be transmitted as other types.

MIDL2037 : cannot specify a variable number of arguments to a remote procedure

Remote procedure calls that specify the number of variable arguments at compile time are not compatible with the DCE RPC definition. You cannot use a variable number of arguments in Microsoft RPC.

MIDL2038 : named parameter cannot be "void"

A parameter with the base type void is specified with a name.

MIDL2040 : cannot use [comm_status] on both a parameter and a return type

Both the procedure and one of its parameters have the comm_status attribute. The comm_status attribute specifies that only one data object can be of type error_status_t at a time.

MIDL2041 : [local] attribute on a procedure requires /ms_ext

A procedure uses the local attribute as a function attribute, which is not compatible with DCE RPC. To enable the Microsoft RPC extensions, use the MIDL compiler switch /ms_ext.

MIDL2042 : field deriving from a conformant array must be the last member of the structure

The structure contains a conformant array that is not the last element in the structure. The conformant array must appear as the last structure element.

MIDL2043 : duplicate [case] label

A duplicate case label has been specified. The duplicate label is displayed.

MIDL2044 : no [default] case specified for discriminated union

A discriminated union has been specified without a default case.

MIDL2045 : attribute expression cannot be resolved

The expression associated with the attribute cannot be resolved. This error usually occurs when a variable that appears in the expression is not defined. For example, the error can occur when the variable s is not defined and is used by the attribute size_is(s).

MIDL2046 : attribute expression must be of integral type

The specified attribute variable or expression must be an integral type. This error occurs when the attribute-expression type does not resolve to an integer.

MIDL2047 : [byte_count] requires /ms_ext

The byte_count attribute represents an extension to DCE RPC. To enable the Microsoft RPC extensions, use the MIDL compiler switch /ms_ext.

MIDL2048 : [byte_count] can be applied only to out parameters of pointer type

The byte_count attribute can only be applied to out parameters, and all out parameters must be pointer types.

MIDL2049 : [byte_count] cannot be specified on a pointer to a conformant array or structure

The byte_count attribute cannot be applied to a conformant array or structure.

MIDL2050 : parameter specifying the byte count is not [in]

The value associated with the byte_count must be transmitted from the client to the server; it must be an in parameter. The byte_count parameter does not need to be an in, out parameter.

MIDL2051 : parameter specifying the byte count is not an integral type

The value associated with the byte count must be the integer type small, short, or long.

MIDL2052 : [byte_count] cannot be specified on a parameter with size attributes

The byte_count attribute cannot be used with other size attributes such as size_is or length_is.

MIDL2053 : [case] expression is not constant

The expression specified for the case label is not a constant.

MIDL2054 : [case] expression is not of integral type

The expression specified for the case label is not an integer type.

MIDL2055 : specifying [context handle] on a type other than void * requires /ms_ext

For DCE RPC compatibility, the context handle must be a pointer of type void *. To use the Microsoft RPC extensions that allow context handles to be associated with types other than void *, use the MIDL compiler switch /ms_ext.

MIDL2056 : cannot specify more than one parameter with each of comm_status/fault_status

The comm_status attribute may only appear once, and the fault_status attribute may only appear once per procedure.

MIDL2057 : error_status_t parameter must be an [out] only pointer parameter

The error-code type error_status_t is transmitted from server to client and therefore must be specified as an out parameter. Due to the constraints in the C programming language, all out parameters must be pointers.

MIDL2058 : endpoint syntax error

The endpoint syntax is incorrect.

MIDL2059 : inapplicable attribute

The specified attribute cannot be applied in this construct. For example, the string attribute applies to char arrays or char pointers and cannot be applied to a structure that consists of two short integers:

typedef [string] struct foo {

    short x;

    short y;

};

MIDL2060 : [allocate] requires /ms_ext

The allocate attribute represents a Microsoft extension that is not defined as part of DCE RPC. To enable the Microsoft extensions, use the /ms_ext switch.

MIDL2061 : invalid [allocate] mode

An invalid mode for the allocate attribute construct has been specified. The four valid modes are single_node, all_nodes, on_null, and always.

MIDL2062 : length attributes cannot be applied with string attribute

When the string attribute is used, the generated stub files call the strlen function to determine the string length. Don't use the length attribute and the string attribute for the same variable.

MIDL2063 : [last_is] and [length_is] cannot be specified at the same time

Both last_is and length_is have been specified for the same array. These attributes are related as follows: length = last - first + 1. Because each value can be derived from the other, don't specify both.

MIDL2064 : [max_is] and [size_is] cannot be specified at the same time

Both max_is and size_is have been specified for the same array. These attributes are related as follows: max = size + 1. Because each value can be derived from the other, don't specify both.

MIDL2065 : no [switch_is] attribute specified at use of union

No discriminant has been specified for the union. The switch_is attribute indicates the discriminant used to select among the union fields.

MIDL2066 : no [uuid] specified for interface

No UUID has been specified for the interface.

MIDL2067 : cannot specify both [local] and [uuid] as interface attributes

The local and UUID keywords cannot be used at the same time, except on [object] interfaces.

MIDL2068 : type mismatch between length and size attribute expressions

The length and size attribute expressions must be of the same types. For example, this warning is issued when the attribute variable for the size_is expression is of type unsigned long and the attribute variable for the length_is expression is of type long.

MIDL2069 : [string] attribute must be specified "byte", "char", or "wchar_t" array or pointer

A string attribute cannot be applied to a pointer or array whose base type is not a byte, char, or struct in which the members are all of the byte or char type.

MIDL2070 : mismatch between the type of the [switch_is] expression and the switch type of the union

If the union switch_type is not specified, the switch type is the same type as the switch_is field.

MIDL2071 : [transmit_as] cannot be applied to a type that derives from a context handle

Context handles cannot be transmitted as other types.

MIDL2072 : [transmit_as] must specify a transmissible type

The specified transmit_as type derives from a type that cannot be transmitted by Microsoft RPC, such as void, void *, or int. Use a defined RPC base type; in the case of int, add size specifiers like small, short, or long to qualify the int.

MIDL2073 : transmitted type must not be a pointer or derive from a pointer

The transmitted type cannot be a pointer or derive from a pointer.

MIDL2074 : presented type must not derive from a conformant/varying array, its pointer equivalent, or a conformant/varying structure

The type to which transmit_as has been applied cannot derive from a conformant array or structure (an array or structure whose size is determined at run time).

MIDL2075 : [uuid] format is incorrect

The UUID format does not conform to specification. The UUID must be a string that consists of five sequences of hexadecimal digits of length 8, 4, 4, 4, and 12 digits. "12345678-1234-ABCD-EF01-28A49C28F17D" is a valid UUID. Use the function UuidCreate or a utility to generate a valid UUID.

MIDL2076 : uuid is not a hex number

The UUID specified for the interface contains characters that are invalid in a hexadecimal number representation. The characters 0 through 9 and A through F are valid in a hexadecimal representation.

MIDL2077 : interface name specified in the ACF file does not match that specified in the IDL file

In this compiler mode, the name that follows the interface keyword in the ACF must be the same as the name that follows the interface keyword in the IDL file. The interface names in the IDL and ACF files can be different when you compile with the MIDL compiler switch /acf.

MIDL2078 : conflicting attributes

Conflicting attributes have been specified. This error often occurs when two attributes are mutually exclusive. For example, the attributes code and nocode cannot be used at the same time.

MIDL2080 : [local] procedure cannot be specified in ACF file

A local procedure has been specified in the ACF. The local procedure can only be specified in the IDL file.

MIDL2081 : specified type is not defined as a handle

The type specified in the implicit_handle attribute is not defined as a handle type. Change the type definition or the type name specified by the attribute.

MIDL2082 : procedure undefined

An attribute has been applied to a procedure in the ACF and that procedure is not defined in the IDL file.

MIDL2083 : this parameter does not exist in the IDL file

A parameter specified in the ACF does not exist in the definition in the IDL file. All parameters, functions, and type definitions that appear in the ACF must correspond to parameters, functions, and types previously defined in the IDL file.

MIDL2084 : this array bounds construct is not supported

MIDL currently supports array-bounds constructs of the form Array[Lower .. Upper] only when the constant that specifies the lower bound of the array resolves to the value zero.

MIDL2085 : array bound specification is illegal

The user specification of array bounds for the fixed-size array is illegal. For example:

typedef short Array[-1]

MIDL2087 : pointee / array does not derive any size

A conformant array has been specified without any size specification. You can specify the size with the max_is or size_is attribute.

MIDL2088 : badly formed character constant

The end-of-line character is not allowed in character constants.

MIDL2089 : end of file found in comment

The end-of-file character has been encountered in a comment.

MIDL2090 : end of file found in string

The end-of-file character has been encountered in a string.

MIDL2091 : identifier length exceeds 31 characters

Identifiers are limited to 31 alphanumeric characters. Identifier names longer than 31 characters are truncated.

MIDL2092 : end of line found in string

The end-of-line character has been encountered in the string. Verify that you have included the double-quote character that terminates the string.

MIDL2093 : string constant exceeds limit of 255 characters

The string exceeded the maximum allowable length of 255 characters.

MIDL2094 : constant too big

The constant is too large to be represented internally.

MIDL2095 : error in opening file

The operating system reported an error while trying to open an output file. This error can be caused by a name that is too long for the file system or by a duplicate filename.

MIDL2096 : [out] only parameter must not derive from a top-level [unique] or [ptr] pointer/array

A unique pointer cannot be an out-only parameter. By definition, a unique pointer can change from null to non-null. No information about the out-only parameter is passed from client to server.

MIDL2097 : attribute is not applicable to this non-rpcable union

The switch_is and switch_type attributes apply to a union that is transmitted as part of a remote procedure call.

MIDL2098 : expression used for a size attribute must not derive from an [out] only parameter

The value of an out-only parameter is not transmitted to the server and cannot be used to determine the length or size of the in parameter.

MIDL2099 : expression used for a length attribute for an [in] parameter cannot derive from an [out] only parameter

The value of an out-only parameter is not transmitted to the server and cannot be used to determine the length or size of the in parameter.

MIDL2100 : use of "int" needs /c_ext

MIDL is a strongly typed language. All parameters transmitted over the network must be derived from one of the MIDL base types. The type int is not defined as part of MIDL. Transmitted data must include a size specifier: small, short, or long. Data that is not transmitted over the network can be included in an interface; use the /c_ext switch.

MIDL2101 : struct/union field must not be void

Fields in a structure or union must be declared to be of a specific base type supported by MIDL or a type that is derived from the base types. Void types are not allowed in remote operations.

MIDL2102 : array element must not be void

An array element cannot be void.

MIDL2103 : use of type qualifiers and/or modifiers needs /c_ext

Type modifiers such as _cdecl and _far can be compiled only if you specify the
/c_ext switch.

MIDL2104 : struct/union field must not derive from a function

The fields of a structure or union must be MIDL base types or types that are derived from these base types. Functions are not legal in structure or union fields.

MIDL2105 : array element must not be a function

An array element cannot be a function.

MIDL2106 : parameter must not be a function

The parameter to a remote procedure must be a variable of a specified type. A function cannot be a parameter to the remote procedure.

MIDL2107 : struct/union with bit fields needs /c_ext

You must specify the MIDL compiler switch /c_ext to allow bit fields on data that is not transmitted in a remote procedure call.

MIDL2108 : bit field specification on a type other that "int" is a non ANSI-compatible extension

The ANSI C programming language specification does not allow bit fields to be applied to non-integer types.

MIDL2109 : bit field specification can be applied only to simple, integral types

The ANSI C programming language specification does not allow bit fields to be applied to non-integer types.

MIDL2110 : struct/union field must not derive from handle_t or a context_handle

Context handles cannot be transmitted as part of another structure. They must be transmitted as context handles.

MIDL2111 : array element must not derive from handle_t or a context handle

Context handles cannot be transmitted as part of an array.

MIDL2112 : this specification of union needs /c_ext

A union that appears in the interface definition must be associated with the discriminant or declared as local. Data that is not transmitted over the network can be implicitly declared as local when you use the /c_ext switch.

MIDL2113 : parameter deriving from an "int" must have size specifier "small", "short", or "long" with the "int"

The type int is not a valid MIDL type unless it is accompanied by a size specification. Use one of the size specifiers small, short, or long.

MIDL2114 : type of the parameter cannot derive from void or void*

MIDL is a strongly typed language. All parameters transmitted over the network must be derived from one of the MIDL base types. MIDL does not support void as a base type. You must change the declaration to a valid MIDL type.

MIDL2115 : parameter deriving from a struct/union containing bit fields is not supported

Bit fields are not defined as a valid data type by DCE RPC.

MIDL2116 : use of a parameter deriving from a type containing type-modifiers/type-qualifiers needs /c_ext

Such keywords as far, near, const, and volatile can appear in the IDL file only when you activate the /c_ext extension to the MIDL compiler.

MIDL2117 : parameter must not derive from a pointer to a function

The RPC run-time libraries transmit a pointer and its associated data between client and server. Pointers to functions cannot be transmitted as parameters because the function cannot be transmitted over the network.

MIDL2118 : parameter must not derive from a non-rpcable union

The union must be associated with a discriminant. Use the switch_is and switch_type attributes.

MIDL2119 : return type derives from an "int". You must use size specifiers with the "int"

The type int is not a valid MIDL type unless it is accompanied by a size specification. Use one of the size specifiers small, short, or long.

MIDL2120 : return type must not derive from a void pointer

MIDL is a strongly typed language. All parameters transmitted over the network must be derived from one of the MIDL base types. Void types are not defined as part of MIDL. You must change the declaration to a valid MIDL type.

MIDL2121 : return type must not derive from a struct/union containing bit-fields

Bit fields are not defined as a valid data type by DCE RPC.

MIDL2122 : return type must not derive from a non-rpcable union

The union must be associated with a discriminant. Use the switch_is and switch_type attributes.

MIDL2123 : return type must not derive from a pointer to a function

The RPC run-time libraries transmit a pointer and its associated data between client and server. Pointers to functions cannot be transmitted as parameters because RPC does not define a method to transmit the associated function over the network.

MIDL2124 : compound initializers are not supported

DCE RPC supports simple initialization only. The structure or array cannot be initialized in the IDL file.

MIDL2125 : ACF attributes in the IDL file need the /app_config switch

A Microsoft extension allows you to specify ACF attributes in the IDL file. Use the /app_config switch to activate this extension.

MIDL2126 : single line comment needs /ms_ext or /c_ext

Single-line comments that use two backslash characters (\\) represent a Microsoft extension to DCE RPC. You must use one of the mode-extension switches for a single-line comment.

MIDL2127 : [version] format is incorrect

The interface version number in the interface header must be specified in the format major.minor, where each number can range from 0 to 65535.

MIDL2128 : "signed" needs /ms_ext or /c_ext

The use of the signed keyword is a Microsoft extension to DCE RPC. You must use one of the mode-extension switches to activate this extension.

MIDL2129 : mismatch in assignment type

The type of the variable does not match the type of the value that is assigned to the variable.

MIDL2130 : declaration must be of the form: const <type><declarator> = <initializing expression>

The declaration is not compatible with DCE RPC syntax. Use the /ms_ext or /c_ext MIDL compiler mode switch.

MIDL2131 : declaration must have "const"

Declarations in the IDL file must be constant expressions that use the keyword const. For example:

const short x = 2;

MIDL2132 : struct/union/enum must not be defined in a parameter type specification

The structure, union, or enumerated type must be explicitly specified outside of the function prototype.

MIDL2133 : [allocate] attribute must be applied only on non-void pointer types

The allocate attribute is designed for complex pointer-based data structures. When the allocate attribute is specified, the stub file traverses the data structure to compute the total size of all objects accessible from the pointer and all other pointers in the data structure. Change the type to a non-void pointer type or remove the allocate attribute and use another method to determine its allocation size, such as the sizeof operator.

MIDL2134 : array or equivalent pointer construct cannot derive from a non-encapsulated union

Each union must be associated with a discriminant. Arrays of unions are not permitted because they do not provide the associated discriminant. Arrays of structures are permitted because each structure consists of the union and its discriminant.

MIDL2135 : field must not derive from an error_status_t type

The error_status_t type can only be used as a parameter or a return type. It cannot be embedded in the field of a structure or union.

MIDL2136 : union has at least one arm without a case label

The union declaration does not match the required MIDL syntax for the union. Each union arm requires a case label or default label that selects that union arm.

MIDL2137 : a parameter or a return value must not derive from a type which has [ignore] applied to it

The ignore attribute is a field attribute that can only be applied to fields, such as fields of structures and arrays. The ignore attribute indicates that the stub should not dereference the pointer during transmission and is not allowed when it conflicts with other attributes that must be dereferenced, such as out parameters and function return values.

MIDL2138 : pointer already has a pointer-attribute applied to it

Only one of the pointer attributes, ref, unique, or ptr, can be applied to a pointer.

MIDL2139 : field/parameter must not derive from a structure that is recursive through a ref pointer

By definition, a reference pointer cannot be set to NULL. A recursive data structure defined with a reference pointer has no null elements and by convention is non-terminating. Use a unique pointer attribute to allow the data structure to specify a null element or redefine the data structure as a non-recursive data structure.

MIDL2140 : use of field deriving from a void pointer needs /c_ext

The type void * and other types and type qualifiers that are not supported by DCE IDL are only allowed in the IDL file when you use the MIDL compiler switch /c_ext. Redefine the pointer type or recompile using the /c_ext switch.

MIDL2141 : use of this attribute needs /ms_ext

This language feature is a Microsoft extension to DCE IDL. You must specify the MIDL compiler switch /ms_ext.

MIDL2142 : use of wchar_t needs /ms_ext or /c_ext

The wide-character type represents an extension to DCE IDL. The MIDL compiler accepts the wide-character type only when you specify the /ms_ext or /c_ext switch.

MIDL2143 : unnamed fields need /ms_ext or /c_ext

DCE IDL does not support the use of unnamed structures or unions embedded in other structures or unions. In DCE IDL, all such embedded fields must be named. To enable this Microsoft extension to IDL, supply the MIDL compiler switch /ms_ext or /c_ext.

MIDL2144 : unnamed fields can derive only from struct/union types

The Microsoft extension to the DCE IDL that supports unnamed fields applies only to structures and unions. You must assign a name to the field or redefine the field to comply with this restriction.

MIDL2145 : field of a union cannot derive from a varying/conformant array or its pointer equivalent

The conformant array cannot appear alone in the union but must be accompanied by the value that specifies the size of the array. Instead of using the array as the union arm, use a structure that consists of the conformant array and the identifier that specifies the size.

MIDL2146 : no [pointer_default] attribute specified, assuming [ptr] for all unattributed pointers in interface

The DCE IDL implementation specifies that all pointers in each IDL file must be associated with pointer attributes. When an explicit pointer attribute is not assigned to the parameter or pointer type and no pointer_default attribute is specified in the IDL file, the full pointer attribute ptr is associated with the pointer. You can change the pointer attributes by using explicit pointer attributes, by specifying a pointer_default attribute, or by specifying the /ms_ext switch to change the default for unattributed pointers to unique.

MIDL2147 : initializing expression must resolve to a constant expression

The use of initializing expressions is limited to constant expressions in all MIDL compiler modes. The expression must be resolvable at compile time. Specify a literal constant, or an expression that resolves to a constant, rather than a variable.

MIDL2148 : attribute expression must be of type integer, char, byte, boolean or enum

The specified type does not resolve to a valid switch type. Use an integer, character, byte, boolean, or enum type, or a type that is derived from one of these types.

MIDL2149 : illegal constant

The specified constant is out of the valid range for the specified type.

MIDL2150 : attribute not implemented; ignored

The attribute specified is not implemented in this release of Microsoft RPC. The MIDL compiler continues processing the IDL file as if the attribute were not present.

MIDL2151 : return value must not derive from a [ref] pointer

Function return values that are defined to be pointer types must be specified as unique or full pointers. Reference pointers cannot be used.

MIDL2152 : attribute expression must be a variable name or a pointer dereference expression in this mode. You must specify the /ms_ext switch

The DCE IDL compiler requires the size associated with the size_is attribute to be specified by a variable or pointer variable. To enable the Microsoft extension that allows the size_is attribute to be defined by a constant expression, use the /ms_ext switch.

MIDL2153 : parameter must not derive from a recursive non-encapsulated union

A union must include a discriminant, so a union cannot have another union as an element. A union can be embedded in another union only when it is part of a structure that includes the discriminant.

MIDL2154 : binding-handle parameter cannot be [out] only

The handle parameter identified by the MIDL compiler as the binding handle for this operation must be an in parameter. Out-only parameters are undefined on the client stub, and the binding handle must be defined on the client.

MIDL2155 : pointer to a handle cannot be [unique] or [ptr]

The unique and full pointer attributes allow the value NULL. The binding handle cannot be null. Use the ref attribute to derive the binding-handle parameter from reference pointers.

MIDL2156 : parameter that is not a binding handle must not derive from handle_t

The primitive handle type handle_t is not a valid data type that is transmitted over the network. Change the parameter type to a type other than handle_t or remove the parameter.

MIDL2157 : unexpected end of file found

The MIDL compiler found the end of the file before it was able to successfully resolve all syntactical elements of the file. Verify that the terminating right brace character (}) is present at the end of the file, or check the syntax.

MIDL2158 : type deriving from handle_t must not have [transmit_as] applied to it

The primitive handle type handle_t is not transmitted over the network.

MIDL2159 : [context_handle] must not be applied to a type that has [handle] applied to it

The context_handle and handle attributes cannot be applied to the same type.

MIDL2160 : [handle] must not be specified on a type deriving from void or void *

A type specified with the handle attribute can be transmitted over the network, but the type void * is not a transmissible type. The handle type must resolve to a type that derives from the valid base types.

MIDL2161 : parameter must have either [in], [out] or [in,out] in this mode. You must specify /ms_ext or /c_ext

The DCE IDL compiler requires all parameters to have explicit directional parameters. To use the Microsoft extensions to DCE IDL, where you can omit explicit directional attributes, use the MIDL compiler switch /ms_ext or /c_ext.

MIDL2162 : [transmit_as] must not be specified on void type

The transmit_as attribute applies only to pointer types. Use the type void * in place of void.

MIDL2163 : void must be specified on the first and only parameter specification

The keyword void incorrectly appears with other function parameters. To specify a function without parameters, the keyword void must be the only element of the parameter list, as in the following example:

void Foo(void)

MIDL2164 : [switch_is] must be specified only on a type deriving from a non-encapsulated union

The switch_is keyword is incorrectly applied. It can only be used with non-encapsulated union types. For more information, see the syntax section in the reference entry for non-encapsulated unions.

MIDL2165 : stringable structures are not implemented in this version

DCE IDL allows the attribute string to apply to a structure whose elements consist only of characters, bytes, or types that resolve to characters or bytes. This functionality is not supported in Microsoft RPC. The string attribute cannot be applied to the structure as a whole; it can be applied to each individual array.

MIDL2166 : switch type can only be integral, char, byte, boolean or enum

The specified type does not resolve to a valid switch type. Use an integer, character, byte, boolean, or enum type, or a type that is derived from one of these types.

MIDL2167 : [handle] must not be specified on a type deriving from handle_t

A handle type must be defined using one and only one of the handle types or attributes. Use the primitive type handle_t or the attribute handle, but not both. The user-defined handle type must be transmissible, but the handle_t type is not transmitted on the network.

MIDL2168 : parameter deriving from handle_t must not be an [out] parameter

A handle of the primitive type handle_t is meaningful only to the side of the application in which it is defined. The type handle_t is not transmitted on the network.

MIDL2169 : expression specifying size or length attributes derives from [unique] or [ptr] pointer dereference

Although the unique and full pointer attributes allow pointers to have null values, the expression that defines the size or length attribute must never have a null value. When pointers are used, MIDL constrains expressions to ref pointers.

MIDL2170 : "cpp_quote" requires /ms_ext

The cpp_quote attribute is a Microsoft extension to DCE IDL. Use the MIDL compiler switch /ms_ext.

MIDL2171 : quoted uuid requires /ms_ext

The ability to specify a UUID value within quotation marks is a Microsoft extension to DCE IDL. Use the MIDL compiler switch /ms_ext.

MIDL2172 : return type cannot derive from a non-encapsulated union

The non-encapsulated union cannot be used as a function return type. To return the union type, specify the union type as an out or in, out parameter.

MIDL2173 : return type cannot derive from a conformant structure

The size of the return type must be a constant. You cannot specify as a return type a structure that contains a conformant array even when the structure also includes its size specifier. To return the conformant structure, specify the structure as an out or in, out parameter.

MIDL2174 : [transmit_as] must not be applied to a type deriving from a generic handle

In this release, the handle and transmit_as attributes cannot be combined on the same type.

MIDL2175 : [handle] must not be applied to a type that has [transmit_as] applied to it

In this release, the handle and transmit_as attributes cannot be combined on the same type.

MIDL2176 : type specified for the const declaration is invalid

Const declarations are limited to integer, character, wide-character, string, and boolean types.

MIDL2177 : operand to the sizeof operator is not supported

The MIDL compiler supports the sizeof operation for simple types only.

MIDL2178 : this name already used as an const identifier name

The identifier has previously been used to identify a constant in a const declaration. Change the name of one of the identifiers so that the identifiers are unique.

MIDL2179 : inconsistent redefinition of type error_status_t

The type error_status_t must resolve to the type unsigned long. Other type definitions cannot be used.

MIDL2180 : [case] value out of range of switch type

The value associated with the switch statement case is out of range for the specified switch type. For example, this error occurs when a long integer value is used in the case statement for a short integer type.

MIDL2181 : parameter deriving from wchar_t needs /ms_ext

The wide-character type wchar_t is a Microsoft extension to DCE IDL. Use the MIDL compiler switch /ms_ext.

MIDL2182 : this interface has only callbacks

Callbacks are valid only in the context of a remote procedure call. The interface must include at least one function prototype for a remote procedure call that does not include the callback attribute.

MIDL2183 : redundantly specified attribute; ignored

The specified attribute has been applied more than once. Multiple instances of the same attribute are ignored.

MIDL2184 : context handle type used for an implicit handle

A type that was defined using the context_handle attribute has been specified as the handle type in an implicit_handle attribute. The attributes cannot be combined in this way.

MIDL2185 : conflicting options specified for [allocate]

The options specified for the ACF attribute allocate represent conflicting directives. For example, specify either the option all_nodes or the option single_node, but not both.

MIDL2186 : error while writing to file

An error occurred while writing to the file. This condition can be caused by errors relating to disk space, file handles, file-access restrictions, and hardware failures.

MIDL2187 : no switch type found at definition of union, using the [switch_is] type

The union definition does not include an explicit switch_type attribute. The type of the variable specified by the switch_is attribute is used as the switch type.

MIDL2188 : semantic check incomplete due to previous errors

The MIDL compiler makes two passes over the input file(s) to resolve any forward declarations. Due to errors encountered during the first pass, checking for the second pass has not been performed. Unreported errors relating to forward declarations may still be present in the file.

MIDL2189 : handle parameter or return type is not supported on a [callback] procedure

A callback procedure occurs in the context of a call from a client to the server and uses the same binding handle as the original call. Explicit binding-handle parameters or return types are not permitted in callback functions.

MIDL2192 : [context_handle] must not derive from handle_t

The three handle characteristics — the type handle_t, the attribute handle, and the attribute context_handle — are mutually exclusive. Only one can be applied to a type or parameter at a time.

MIDL2193 : array size exceeds 65536 bytes

On some Microsoft platforms, the maximum transmissible data size is 64K. Redesign your application so that all transmitted data fits within the maximum transmissible size.

MIDL2194 : field of a non-encapsulated union cannot be another non-encapsulated union

Unions that are transmitted as part of a remote procedure call require an associated data item, the discriminant, that selects the union arm. Unions nested in other unions do not offer a discriminant; as a result, they cannot be transmitted in this form. Create a structure that consists of the union and its discriminant.

MIDL2195 : pointer attribute(s) applied on an embedded array; ignored

A pointer attribute can be applied to an array only when the array is a top-level parameter. Other pointer attributes applied to arrays embedded in other data structures are ignored.

MIDL2196 : [allocate] is illegal on a type that has [transmit_as] applied to it

The transmit_as and allocate attributes cannot both be applied to the same type. The transmit_as attribute distinguishes between presented and transmitted types, while the allocate attribute assumes that the presented type is the same as the transmitted type.

MIDL2198 : [implicit_handle] type undefined; assuming primitive handle

The handle type specified in the ACF is not defined in the IDL file. The MIDL compiler assumes that the handle type resolves to the primitive handle type handle_t. Add the handle attribute to the type definition if you want the handle to behave like a user-defined, or generic, handle.

MIDL2199 : array element must not derive from error_status_t

In this release of Microsoft RPC, the type error_status_t can only appear as a parameter or a return type. It cannot appear in arrays.

MIDL2200 : [allocate] illegal on a type deriving from a primitive/generic/context handle

By design, the ACF attribute allocate cannot be applied to handle types.

MIDL2201 : transmitted or presented type must not derive from error_status_t

In this release of Microsoft RPC, the type error_status_t cannot be used with the transmit_as attribute.

MIDL2202 : discriminant of a union must not derive from a field with [ignore] applied to it

A union used in a remote procedure call must be associated with another data item, called the discriminant, that selects the union arm. The discriminant must be transmitted. The ignore attribute cannot be applied to the union discriminant.

MIDL2203 : [nocode] must be specified with "/server none" in this mode

Some DCE IDL compilers generate an error when the nocode attribute is applied to a procedure in an interface for which server stub files are being generated. Because the server must support all operations, nocode must not be applied to a procedure in this mode or you must use the MIDL compiler switch /server none to explicitly specify that no server routines are to be generated.

MIDL2204 : no remote procedures specified, no client/server stubs will be generated

The provided interface does not have any remote procedures, so only header files will be generated.

MIDL2205 : too many default cases specified for encapsulated union

An encapsulated union may only have one default: arm.

MIDL2206 : union specification with no fields is illegal

Unions must have at least one field.

MIDL2207 : value out of range

The provided case value is out of the range of the switch type.

MIDL2208 : [context_handle] must be applied on a pointer type

Context handles must always be pointer types. DCE specifies that all context handles must be typed as "void *".

MIDL2209 : return type must not derive from handle_t

Handle_t may not be returned.

MIDL2210 : [handle] must not be applied to a type deriving from a context handle

A type may not be both a context handle and a generic handle.

MIDL2211 : field deriving from an \"int\" must have size specifier \"small\", \"short\", or \"long\" with the \"int\"

The use of "int" is not remotable, since the size of "int" may be different accross machines.

MIDL2212 : field must not derive from a void or void *

Void and void * are not remotable types.

MIDL2213 : field must not derive from a struct containing bit-fields

bit fields in structs are not remotable.

MIDL2214 : field must not derive from a non-rpcable union

A union must be specified as a non-encapsulated union or encapsulated union in order to be remoted. Ordinary C unions lack the discriminant needed to remote the union.

MIDL2215 : field must not derive from a pointer to a function

Pointers to functions may not be remoted.

MIDL2216 : cannot use [fault_status] on both a parameter and a return type

[fault_status] may only be used once per procedure, although [comm_status] may be used independently.

MIDL2217 : return type too complicated for /Oi, using /Os

Large by-value return types may only be handled by /Os optimization stubs. The stubs for this routine will be generated using /Os optimization.

MIDL2218 : generic handle type too large for /Oi, using /Os

Large by-value generic handle types may only be handled by /Os optimization stubs. The stubs for this routine will be generated using /Os optimization.

MIDL2219 : [allocate(all_nodes)] on an [in,out] parameter may orphan the original memory

Use of [allocate(all_nodes)] on an [in,out] parameter must re-allocate contiguous memory for the [out] direction, thus orphaning the [in] parameter. This usage is not recommended.

MIDL2220 : cannot have a [ref] pointer as a union arm

Ref pointers must always point to valid memory, but an [in,out] union with a ref pointer may return a ref pointer when the [in] direction used another type.

MIDL2222 : use of [comm_status] or [fault_status] not supported for /Oi, using /Os

[comm_status] and [fault_status] may only be handled by /Os optimization stubs. The stubs for this routine will be generated using /Os optimization.

MIDL2223 : use of an unknown type for [represent_as] not supported for /Oi, using /Os

Use of a represent_as with a local type that is not defined in the idl file or an imported idl file may only be handled by /Os optimization stubs. The stubs for this routine will be generated using /Os optimization.

MIDL2224 : array types with [transmit_as] or [represent_as] not supported on return type for /Oi, using /Os

Returning an array with [transmit_as] or [represent_as] applied may only be handled by /Os optimization stubs. The stubs for this routine will be generated using /Os optimization.

MIDL2226 : [callback] requires /ms_ext

[callback] is a Microsoft extension and requires use of the /ms_ext switch.

MIDL2227 : circular interface dependency

This interface uses itself (directly or indirectly) as a base interface.

MIDL2228 : only IUnknown may be used as the root interface

Currently, all interfaces must have IUnknown as the root interface.

MIDL2229 : [IID_IS] may only be applied to pointers to interfaces

[iid_is] can only be applied to interface pointers, although they may be specified as IUnknown *.

MIDL2230 : interfaces may only be used in pointer-to-interface constructs

Interface names may not be used except as base interfaces or interface pointers.

MIDL2231 : interface pointers must have a UUID/IID

The base type of the iid_is expression must be a UUID/GUID/IID type.

MIDL2232 : definitions and declarations outside of interface body requires /ms_ext

Putting declarations and definitions outside of any interface body is a Microsoft extension and requires the use of the /ms_ext switch.

MIDL2233 : multiple interfaces in one file requires /ms_ext

Using multiple interfaces in a single idl file is a Microsoft extension and requires the use of the /ms_ext switch.

MIDL2234 : only one of [implicit_handle], [auto_handle], or [explicit_handle] allowed

Each interface may only have one of the above.

MIDL2235 : [implicit_handle] references a type which is not a handle

Implicit handles must be of one of the handle types.

MIDL2236 : [object] procs may only be used with "/env win32"

[object] interfaces may not be used with 16-bit environments.

MIDL2237 : [callback] with -env dos/win16 not supported for /Oi, using /Os

Callbacks in 16-bit environments may only be handled by /Os optimization stubs. The stubs for this routine will be generated using /Os optimization.

MIDL2238 : float/double not supported as top-level parameter for /Oi, using /Os

Float and double as parameters may only be handled by /Os optimization stubs. The stubs for this routine will be generated using /Os optimization. Float and double within structs/arrays/etc. May still be handled with /Oi.

MIDL2239 : pointers to context handles may not be used as return values

Context handles must be used as direct return values, not indirect return values.

MIDL2240 : procedures in an object interface must return an HRESULT

All non-[local] procedures in an object interface must return an HRESULT/SCODE.

MIDL2241 : duplicate UUID

UUIDs must be unique.

MIDL2242 : [object] interfaces must derive from other [object] interfaces

Interface inheritance is only allowed using object interfaces.

MIDL2243 : [IID_IS] expression must be a pointer to IID structure

The base type of the iid_is expression must be a UUID/GUID/IID type.

MIDL2244 : [call_as] type must be a [local] procedure

Tthe target of a call_as, if defined, must have [local] applied.

MIDL2245 : undefined [call_as] must not be used in an object interface [call_as]: in_list

Another routine defined in the ACf is attempting to use the same call_as routine as the previous routine.

MIDL2246 : [auto_handle] may not be used with [encode] or [decode]

[encode] and [decode] may only be used with explicit handles or implicit handles.

MIDL2247 : normal procs are not allowed in an interface with [encode] or [decode]

Interfaces containing [encode] or [decode] procedures may not also have remoted procedures.

MIDL2248 : top-level conformance or variance not allowed with [encode] or [decode]

Types that have top-level conformance or variance may not use type serialization, since there is no way to provide sizing/lengthing. Structs containing them are, however, allowed.

MIDL2249 : [out] parameters may not have \"const\"

Since an [out] parameter is altered, it may not have const.

MIDL2250 : return values may not have \"const\"

Since a function value is set, it must not have const.

MIDL2251 : multiple calling conventions illegal

Only one calling convention may be applied to a single procedure.

MIDL2252 : attribute illegal on [object] procedure

The above attribute only applies to procedures in interfaces that do not have [object].

MIDL2253 : [out] interface pointers must use double indirection

Since the altered value is the pointer to the interface, there must be another level of indirection above it to allow it to be returned.

MIDL2254 : procedure used twice as the caller in [call_as]

A given [local] procedure may only be used once as the target of a [call_as], in order to avoid name clashes.

MIDL2255 : [call_as] target must have [local] in an object interface

The target of a call_as must be a defined, [local] procedure in the current interface.

MIDL2256 : [code] and [nocode] may not be used together

These two attributes are contradictory, and may not be used together.

MIDL2257 : [maybe] procedures may not have a return value or [out] params

Since [maybe] procedures may never return, there is no way to get returned values.

MIDL2258 : pointer to function must be used

Although function type definitions are allowed in /c_ext mode, they may only be used as pointers to functions (and may never be remoted).

MIDL2259 : functions may not be passed in an RPC operation

Functions and function pointers may not be remoted.

MIDL2260 : hyper/double not supported as return value for /Oi, using /Os

Hyper and double return values may only be handled by /Os optimization stubs. The stubs for this routine will be generated using /Os optimization.

MIDL2261 : #pragma pack( pop ) without matching #pragma pack( push )

#pragma pack(push) and #pragma pack(pop) must appear in matching pairs. At least one too many #pragma pack(push)'s were specified.

MIDL2262 : stringable structure fields must be byte/char/wchar_t

[string] may only be applied to a struct whose fields are all of type byte, or a type definition equivalent of byte.

MIDL2263 : [notify] not supported for /Oi, using /Os

The [notify] attribute may only be processed by /Os optimization stubs.

MIDL2264 : handle parameter or return type is not supported on a procedure in an [object] interface

Handles may not be used with [object] interfaces.

MIDL2265 : ANSI C only allows the leftmost array bound to be unspecified

In an conformant array, ANSI C only allows the leftmost ( most significant ) array bound to be unspecified. If multiple dimensions are conformant, MIDL will attempt to put a "1" in the other conformant dimensions. If the other dimensions are defined in a different typedef, this may not be possible. Try putting all the array dimensions on the use of the array to avoid this. In any case, beware of the array indexing calculations done by the compiler; you may need to do your own calculations using the actual sizes.


 MANDEL

This directory contains the files for the sample distributed application "mandel":

File	Description
README.TXT	Readme file for the MANDEL sample
MDLRPC.IDL	Interface definition language file
MDLRPC.ACF	Attribute configuration file
MANDEL.C	Client main program
MANDEL.H	Client global data
REMOTE.C	Client code that calls remote procedures
RPC.ICO	Client icon
MANDEL.DEF	Client module definition file
MANDEL.RC	Client resource script file
SERVER.C	Server main program
CALC.C	Remote procedures
MAKEFILE	nmake utility for Windows NT
MAKEFILE.WIN	nmake utility for Win 3.x
BUILDING CLIENT AND SERVER APPLICATIONS FOR MICROSOFT WINDOWS NT:

The following environment variables should be set for you already.

  set CPU=i386
  set INCLUDE=c:\mstools\h
  set LIB=c:\mstools\lib
  set PATH=c:\winnt\system32;c:\mstools\bin;

For mips, set CPU=mips                                                    For alpha, set CPU=alpha

Build the sample distributed application:

  nmake cleanall
  nmake

This builds the executable programs client.exe and server.exe for Microsoft Windows NT.

BUILDING THE CLIENT APPLICATION FOR WINDOWS 3.x

After installing the Microsoft Visual C/C++ version 1.50 development environment and the Microsoft RPC version 2.0 toolkit on a Windows NT computer, you can build the sample client application from Windows NT.

  nmake -f makefile.win cleanall
  nmake -f makefile.win

This builds the client application client.exe.

You can also execute the Microsoft Visual C/C++ compiler under MS-DOS. This requires a two-step build process.

Step One: Compile the .IDL files under Windows NT

     nmake -a -f makefile.win yield.h

Step Two: Compile the C sources (stub and application) under MS-DOS.

     nmake -f makefile.win

RUNNING THE CLIENT AND SERVER APPLICATIONS

On the server, enter

  server

On the client, enter

  net start workstation
  client

Note  The client and server applications can run on the same Microsoft Windows NT computer when you use different screen groups.  If you run the client on the Microsoft MS-DOS and Windows computer, choose the Run command from the File menu in the Microsoft Windows 3.x Program Manager and enter client.exe.

Several command line switches are available to change settings for the server program. For a listing of switches available from the server program, enter

  server -?


 MAKEFILE   (MANDEL RPC Sample)

#*************************************************************#

#**                                                         **#

#**                 Microsoft RPC Examples                  **#

#**               Mandelbrot RPC Application                **#

#**            Copyright(c) Microsoft Corp. 1991            **#

#**                                                         **#

#*************************************************************#

# The same source code is used to build either a standalone

# or an RPC version of the Microsoft Windows (R) Mandelbrot

# sample application.  The flag RPC determines which version

# is built.  To build a standalone version, use the commands:

#     >nmake cleanall

#     >set NOTRPC=1

#     >nmake

# To build the RPC version, use the commands:

#     >nmake cleanall

#     >set NOTRPC=

#     >nmake

!include <ntwin32.mak>

!ifdef NOTRPC

RPCFLAG =

!else

RPCFLAG = -DRPC

!endif

.c.obj:

   $(cc) $(cdebug) $(cflags) $(cvars) $(RPCFLAG) $<

# Targets

# The RPC version produces client and server executables.

# The standalone version produces a single exe file, "mandel".

!ifndef NOTRPC

all: client.exe server.exe

!else

all: mandel.exe

!endif

mandel.exe: mandel.obj remote.obj mandel.def mandel.rbj calc.obj

    $(link) $(linkdebug) $(guiflags) -out:mandel.exe -map:mandel.map \

      mandel.obj remote.obj calc.obj mandel.rbj $(guilibs)

client.exe: mandel.obj remote.obj mandel.def mandel.rbj mdlrpc_c.obj

    $(link) $(linkdebug) $(guiflags) -out:client.exe -map:client.map \

      mandel.obj remote.obj mdlrpc_c.obj \

      mandel.rbj rpcrt4.lib $(guilibs)

server.exe: server.obj calc.obj mdlrpc_s.obj

    $(link) $(linkdebug) $(conflags) -out:server.exe -map:server.map \

      server.obj calc.obj mdlrpc_s.obj \

      rpcrt4.lib $(conlibs)

# Update the resource if necessary

mandel.rbj: mandel.rc mandel.h

    rc -r mandel.rc

    cvtres -$(CPU) mandel.res -o mandel.rbj

# Object file dependencies

# server only built for RPC version; always needs mdlrpc.h

server.obj: server.c mandel.h mdlrpc.h

# Compile differently for RPC, standalone versions

!ifndef NOTRPC

mandel.obj: mandel.c mandel.h mdlrpc.h

remote.obj: remote.c mandel.h mdlrpc.h

calc.obj  : calc.c mandel.h mdlrpc.h

!else

mandel.obj: mandel.c mandel.h

remote.obj: remote.c mandel.h

calc.obj  : calc.c mandel.h

!endif

# client stub

mdlrpc_c.obj : mdlrpc_c.c mdlrpc.h

# server stub file

mdlrpc_s.obj : mdlrpc_s.c mdlrpc.h

# Stubs and header file from the IDL file

mdlrpc.h mdlrpc_c.c mdlrpc_s.c: mdlrpc.idl mdlrpc.acf

    midl -oldnames -cpp_cmd $(cc) -cpp_opt "-E" mdlrpc.idl

clean:

    -del client.exe

    -del server.exe

    -del mandel.exe

cleanall:  clean

    -del *.obj

    -del *.map

    -del *.res

    -del *.rbj

    -del mdlrpc_*.c

    -del mdlrpc.h


 MANDEL.H   (MANDEL RPC Sample)

/****************************************************************************

    MANDEL.H -- Constants and function definitions for MANDEL.C

    Copyright (C) 1990, 1992 Microsoft Corporation

****************************************************************************/

/* Constants */

#ifdef WIN16

#define APIENTRY        PASCAL

#define UNREFERENCED_PARAMETER

#endif

#define IDM_ABOUT        100

#define IDM_ZOOMIN       101

#define IDM_ZOOMOUT      105

#define IDM_TOP          106

#define IDM_REDRAW       107

#define IDM_EXIT         108

#define IDM_CONTINUOUS   109

#define IDM_PROTSEQ      110

#define IDD_PROTSEQNAME  111

#define IDM_SERVER       112

#define IDD_SERVERNAME   113

#define IDM_ENDPOINT     114

#define IDD_ENDPOINTNAME 115

#define IDM_BIND         116

#define IDM_GO           117

#define IDM_1LINE        200

#define IDM_2LINES       201

#define IDM_4LINES       202

#define WIDTH            300

#define HEIGHT           300

#define LINES              4

#define BUFSIZE         1200     // (HEIGHT * LINES)

#define MAX_BUFSIZE     4800     // (BUFSIZE * sizeof(short))

#define POLL_TIME        2000

#define CNLEN             25     // computer name length

#define UNCLEN       CNLEN+2     // \\computername

#define PATHLEN           260    // Path

#define MSGLEN            300    // arbitrary large number for message size

#define MAXPROTSEQ         20    // protocol sequence

#define NCOLORS           11

#define SVR_TABLE_SZ      20

// Status of connection to server

#define SS_DISCONN         0

#define SS_IDLE            1

#define SS_READPENDING     2

#define SS_PAINTING        3

#define SS_LOCAL           4

#define MINPREC       5.0E-9

#define MAXPREC       5.0E-3

#define WM_DOSOMEWORK   (WM_USER+0)

#define WM_PAINTLINE    (WM_USER+1)

#define EXCEPT_MSG      "The remote procedure raised an exception.\n\

Check your connection settings."

/* Data Structures */

typedef struct _svr_table {

    char    name[UNCLEN];       // name of remote server

    int     hfPipe;             // RPC handle

    int     iStatus;            // status of connection

    int     cPicture;           // picture id for this line

    DWORD   dwLine;             // line we're drawing

    int     cLines;             // lines in this chunk

} svr_table;

#ifndef RPC                     // If RPC, the following data would be

                                // defined in the IDL file

typedef struct _cpoint {

    double    real;

    double    imag;

} CPOINT;

typedef CPOINT * PCPOINT;

typedef struct _LONGRECT {

    long    xLeft;

    long    yBottom;

    long    xRight;

    long    yTop;

} LONGRECT;

typedef LONGRECT *PLONGRECT;

typedef unsigned short LINEBUF[BUFSIZE];

#endif

typedef struct _calcbuf {

    LONGRECT  rclDraw;

    double    dblPrecision;

    DWORD     dwThreshold;

    CPOINT    cptLL;

} CALCBUF;

/* Function Prototypes */

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int);

BOOL InitApplication(HANDLE);

BOOL InitInstance(HANDLE, int);

LONG APIENTRY MainWndProc(HWND, UINT, UINT, LONG);

BOOL APIENTRY About(HWND, UINT, UINT, LONG);

BOOL APIENTRY Protseq(HWND, UINT, UINT, LONG);

BOOL APIENTRY Server(HWND, UINT, UINT, LONG);

BOOL APIENTRY Endpoint(HWND, UINT, UINT, LONG);

#ifdef RPC

RPC_STATUS Bind(HWND);

#endif

void CountHistogram(void);

BOOL InitRemote(HWND);

BOOL CheckDrawStatus(HWND);

void SetNewCalc(CPOINT, double, RECT);

void IncPictureID(void);

void ResetPictureID(void);

BOOL CheckDrawingID(int);

DWORD QueryThreshold(void);

// buffer routines

BOOL TakeDrawBuffer(void);

LPVOID LockDrawBuffer(void);

void UnlockDrawBuffer(void);

void ReturnDrawBuffer(void);

void FreeDrawBuffer(void);

#ifndef RPC                     // If RPC, MandelCalc() would be

                                // defined in the IDL file

void MandelCalc(PCPOINT   pcptLL,

                PLONGRECT prcDraw,

                double    precision,

                DWORD     ulThreshold,

                LINEBUF * pbBuf);

#endif


 CALC.C   (MANDEL RPC Sample)

/****************************************************************************

                   Microsoft RPC Version 2.0

           Copyright Microsoft Corp. 1992, 1993, 1994

                        mandel Example

    FILE:       calc.c

    PURPOSE:    Server side of the RPC distributed application Mandel

    FUNCTIONS:  MandelCalc() - Do the calculations for the Windows

                               Mandelbrot Set distributed drawing program.

****************************************************************************/

#include <stdlib.h>

#include <stdio.h>

#include <windows.h>

#ifdef RPC

#include "mdlrpc.h"

#endif

#include "mandel.h"

short calcmand(double, double, short);

void MandelCalc(PCPOINT    pcptLL,

                PLONGRECT  prcDraw,

                double     precision,

                DWORD      ulThreshold,

                LINEBUF *  pbBuf)

{

    DWORD   h, height, width;

    double  dreal, dimag, dimag2;

    short   maxit = 0;

    short * pbPtr;

    pbPtr = *pbBuf;   // LINEBUF is an array of shorts

    dreal = pcptLL->real + ((double)prcDraw->xLeft * precision);

    dimag = pcptLL->imag + ((double)prcDraw->yBottom * precision);

    maxit = (short) ulThreshold;

    height = (prcDraw->yTop - prcDraw->yBottom) + 1;

    width = (prcDraw->xRight - prcDraw->xLeft) + 1;

    for ( ; width > 0; --width, dreal += precision) {

        for (dimag2 = dimag, h = height; h > 0; --h, dimag2 += precision) {

            if ((dreal > 4.0) || (dreal < -4.0) ||

                (dimag2 > 4.0) || (dimag2 < -4.0))

                *(pbPtr++) = 0;

            else

                *(pbPtr++) = calcmand(dreal, dimag2, maxit);

        }

    }

}

/* C version of the assembly language program */

short calcmand(double dreal,

               double dimag,

               short  maxit)

{

    double x, y, xsq, ysq;

    short k;

    k = maxit;

    x = dreal;

    y = dimag;

    while (1) {

        xsq = x * x;

        ysq = y * y;

        y = 2.0 * x * y + dimag;

        x = (xsq - ysq) + dreal;

        if (--k == 0)

            return((short) (maxit - k));

        if ((xsq + ysq) > 4.0)

            return((short) (maxit - k));

    }

}


 MANDEL.C   (MANDEL RPC Sample)

/****************************************************************************

                   Microsoft RPC Version 2.0

           Copyright Microsoft Corp. 1992, 1993, 1994

                        mandel Example

    FILE:       mandel.c

    PURPOSE:    Client side of the RPC distributed application

    COMMENTS:   Main code for the Windows Mandelbrot Set distributed

                drawing program.

****************************************************************************/

#include <stdio.h>

#include <stdlib.h>

#include <ctype.h>

#include <string.h>

#include <time.h>

#include <windows.h>      // Required for all Windows applications

#include <windowsx.h>     // Allow portability from Win16, Win32

#ifdef RPC

#include "mdlrpc.h"       // header file generated by the MIDL compiler

#endif

#include "mandel.h"

/* data structures */

#ifdef RPC

char szTitle[] = "Mandelbrot RPC";

#else

char szTitle[] = "Mandelbrot Standalone";

#endif

CPOINT      cptUL = { (double) -2.05, (double) 1.4 };

double      dPrec = (double) .01;

HANDLE      hInst;         // current instance

HWND        hWND;          // Main window handle

svr_table   SvrTable;

int         iLines = LINES;

int         fContinueZoom = TRUE;

int         fZoomIn       = TRUE;

// split current picture into 16 regions

// zoom on most complex region;  region with most colors represented

int         Histogram[4][4][NCOLORS+1] = {0};

int         ColorCount[4][4] = {0};

int         Max[4][4] = {0};

int         iHistMaxI = 2;

int         iHistMaxJ = 3;

RECT        rcZoom;

BOOL        fRectDefined = FALSE;

#ifdef RPC

int             fBound = FALSE;     // flag indicates whether bound to svr

unsigned char * pszUuid             = NULL;

unsigned char pszProtocolSequence[MAXPROTSEQ] = "ncacn_np";

unsigned char pszEndpoint[PATHLEN]            = "\\pipe\\mandel";

unsigned char * pszOptions          = NULL;

unsigned char * pszStringBinding;

unsigned char   pszNetworkAddress[UNCLEN+1] = {'\0'};

#endif

/* function prototypes */

void     DoSomeWork(HWND, BOOL);

void     InitHistogram(void);

void     CalcHistogram(int, int, DWORD, DWORD);

void     PaintLine(HWND, svr_table *, HDC, int);

void     DrawRect(HWND, PRECT, BOOL, HDC);

COLORREF MapColor(DWORD, DWORD);

/*

 *  FUNCTION: WinMain(HANDLE, HANDLE, LPSTR, int)

 *

 *  PURPOSE: Calls initialization function, processes message loop

 *

 *  COMMENTS:

 *

 *      Windows recognizes this function by name as the initial entry point

 *      for the program.  This function calls the application initialization

 *      routine, if no other instance of the program is running, and always

 *      calls the instance initialization routine.  It then executes a message

 *      retrieval and dispatch loop that is the top-level control structure

 *      for the remainder of execution.  The loop is terminated when a WM_QUIT

 *      message is received, at which time this function exits the application

 *      instance by returning the value passed by PostQuitMessage().

 *

 *      If this function must abort before entering the message loop, it

 *      returns the conventional value NULL.

 */

int WINAPI WinMain(

    HINSTANCE hInstance,            /* current instance         */

    HINSTANCE hPrevInstance,        /* previous instance        */

    LPSTR lpCmdLine,                /* command line             */

    int nCmdShow)                   /* show-window type (open/icon) */

{

    MSG msg;

    UNREFERENCED_PARAMETER(lpCmdLine);

    if (!hPrevInstance)  /* Other instances of app running? */

        if (!InitApplication(hInstance))  /* Initialize shared things */

            return(FALSE);  /* Exits if unable to initialize */

    /* Perform initializations that apply to a specific instance */

    if (!InitInstance(hInstance, nCmdShow))

        return(FALSE);

    /* Acquire and dispatch messages until a WM_QUIT message is received. */

    while (GetMessage(&msg,        /* message structure              */

                      (HWND)NULL,  /* handle of window receiving the message */

                      0,           /* lowest message to examine      */

                      0))          /* highest message to examine     */

    {

        TranslateMessage(&msg);    /* Translates virtual key codes   */

        DispatchMessage(&msg);     /* Dispatches message to window   */

    }

    return(msg.wParam);  /* Returns the value from PostQuitMessage */

}

/*

 *  FUNCTION: InitApplication(HANDLE)

 *

 *  PURPOSE: Initializes window data and registers window class

 *

 *  COMMENTS:

 *

 *      This function is called at initialization time only if no other

 *      instances of the application are running.  This function performs

 *      initialization tasks that can be done once for any number of running

 *      instances.

 *

 *      In this case, we initialize a window class by filling out a data

 *      structure of type WNDCLASS and calling the Windows RegisterClass()

 *      function.  Since all instances of this application use the same window

 *      class, we only need to do this when the first instance is initialized.

 */

BOOL InitApplication(HANDLE hInstance)    /* current instance */

{

    WNDCLASS  wc;

    /* Fill in window class structure with parameters that describe the       */

    /* main window.                                                           */

    wc.style = 0;                       /* Class style(s).                    */

    wc.lpfnWndProc = (WNDPROC)MainWndProc;

                                        /* Function to retrieve messages for  */

                                        /* windows of this class.             */

    wc.cbClsExtra = 0;                  /* No per-class extra data.           */

    wc.cbWndExtra = 0;                  /* No per-window extra data.          */

    wc.hInstance = hInstance;           /* Application that owns the class.   */

    wc.hIcon = LoadIcon(hInstance, "RPC_ICON");

    wc.hCursor = LoadCursor(0, IDC_ARROW);

    wc.hbrBackground = GetStockObject(WHITE_BRUSH);

    wc.lpszMenuName =  "MandelMenu";    /* Name of menu resource in .RC file. */

    wc.lpszClassName = "MandelClass";   /* Name used in call to CreateWindow. */

    /* Register the window class and return success/failure code. */

    return(RegisterClass(&wc));

}

/*

 *  FUNCTION:  InitInstance(HANDLE, int)

 *

 *  PURPOSE:  Saves instance handle and creates main window.

 *

 *  COMMENTS:

 *

 *      This function is called at initialization time for every instance of

 *      this application.  This function performs initialization tasks that

 *      cannot be shared by multiple instances.

 *

 *      In this case, we save the instance handle in a static variable and

 *      create and display the main program window.

 */

BOOL InitInstance(HANDLE   hInstance,   /* Current instance identifier.       */

                  int      nCmdShow)    /* Param for first ShowWindow() call. */

{

    HMENU           hMenu;

    RECT            rc;

    /* Save the instance handle in static variable, which will be used in  */

    /* many subsequence calls from this application to Windows.            */

    hInst = hInstance;

    /* Create a main window for this application instance.  */

    hWND = CreateWindow(

               "MandelClass",        /* See RegisterClass() call.          */

               szTitle,              /* Text for window title bar.         */

               WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_BORDER | WS_MINIMIZEBOX,

               CW_USEDEFAULT,        /* Default horizontal position.       */

               CW_USEDEFAULT,        /* Default vertical position.         */

               WIDTH,                /* Default width.                     */

               HEIGHT,               /* Default height.                    */

               (HWND) NULL,          /* Overlapped windows have no parent. */

               (HMENU) NULL,         /* Use the window class menu.         */

               hInstance,            /* This instance owns this window.    */

               (LPVOID) NULL         /* Pointer not needed.                */

           );

    /* If window could not be created, return "failure" */

    if (!hWND)

        return(FALSE);

    /* Make the window visible; update its client area; and return "success" */

    ShowWindow(hWND, nCmdShow);  /* Show the window                */

    UpdateWindow(hWND);          /* Sends WM_PAINT message         */

    rc.top = rc.left = 0;

    rc.bottom = HEIGHT-1;

    rc.right = WIDTH-1;

    SetNewCalc(cptUL, dPrec, rc);

    hMenu = GetMenu(hWND);

#ifndef RPC

    EnableMenuItem(hMenu, IDM_SERVER, MF_GRAYED);  /* disable option */

#endif

    return(TRUE);               /* Returns the value from PostQuitMessage */

}

/*

 *  FUNCTION: MainWndProc(HWND, unsigned, WORD, LONG)

 *

 *  PURPOSE:  Processes messages

 *

 *  MESSAGES:

 *      WM_COMMAND    - application menu

 *      WM_DESTROY    - destroy window

 *

 *  COMMENTS:

 */

LONG APIENTRY MainWndProc(

    HWND hWnd,               /* window handle               */

    UINT message,            /* type of message             */

    UINT wParam,             /* additional information      */

    LONG lParam)             /* additional information      */

{

    DLGPROC lpProc;          /* pointer to the dialog box function */

    PAINTSTRUCT ps;

    HDC hdc;

    static HDC     hdcMem;

    static HBITMAP hbmMem;

    static int     width;

    static int     height;

    RECT           rc;

    static BOOL    fButtonDown = FALSE;

    static POINT   pSelected;

    POINT          pMove;

    int            iWidthNew;

    int            iHeightNew;

    static int     miOldLines;

    double         scaling;

    switch (message) {

    case WM_CREATE:

#ifdef WIN16

        RpcWinSetYieldInfo (hWnd, FALSE, 0, 0L); // To make TCP/IP happy

#else

        PostMessage(hWnd, WM_COMMAND, IDM_BIND, 0L);    // bind to server

#endif

        if (!InitRemote(hWnd))

            return(FALSE);

        InitHistogram();

        hdc = GetDC(hWnd);

        hdcMem = CreateCompatibleDC(hdc);

        GetWindowRect(hWnd, &rc);

        width = rc.right - rc.left;

        height = rc.bottom - rc.top;

        hbmMem = CreateCompatibleBitmap(hdc, width, height);

        SelectObject(hdcMem, hbmMem);

        ReleaseDC(hWnd,hdc);

        rc.left = rc.top = 0;

        rc.right = width+1;

        rc.bottom = height + 1;

        FillRect(hdcMem, &rc, GetStockObject(WHITE_BRUSH));

        CheckMenuItem(GetMenu(hWnd), IDM_4LINES, MF_CHECKED);

        CheckMenuItem(GetMenu(hWnd), IDM_CONTINUOUS, MF_CHECKED);

        miOldLines = IDM_4LINES;  // save to uncheck

        break;

    case WM_PAINT:

        hdc = BeginPaint(hWnd, &ps);

        BitBlt(hdc,

               ps.rcPaint.left,

               ps.rcPaint.top,

               ps.rcPaint.right - ps.rcPaint.left,

               ps.rcPaint.bottom - ps.rcPaint.top,

               hdcMem,

               ps.rcPaint.left,

               ps.rcPaint.top,

               SRCCOPY);

        EndPaint(hWnd, &ps);

        break;

    case WM_COMMAND:  // message: command from application menu

        switch(wParam) {

        case IDM_BIND:

#ifdef RPC

            if (Bind(hWnd) != RPC_S_OK)

                PostMessage(hWnd, WM_DESTROY, 0, 0L);

#endif

            break;

        case IDM_ABOUT:

            lpProc = MakeProcInstance(About, hInst);

            DialogBox(hInst,       // current instance

                      "AboutBox",  // resource to use

                      hWnd,        // parent handle

                      lpProc);     // About() instance address

            FreeProcInstance(lpProc);

            break;

        case IDM_ZOOMOUT:

            if (dPrec > (double)MAXPREC)  // don't allow the zoom out

                break;

            rcZoom.left = WIDTH/4 + (WIDTH/8);  // center square

            rcZoom.top   = HEIGHT/4 + (HEIGHT/8);

            rcZoom.right = rcZoom.left + (WIDTH/4);

            rcZoom.bottom = rcZoom.top + (HEIGHT/4);

            cptUL.real -= (rcZoom.left * dPrec); // inverse of zoom in

            cptUL.imag += (rcZoom.top * dPrec);

            iWidthNew = (rcZoom.right - rcZoom.left + 1);

            iHeightNew = (rcZoom.bottom - rcZoom.top + 1);

            scaling = ((double) ((iWidthNew > iHeightNew) ? iWidthNew : iHeightNew) / (double) width);

            dPrec /= scaling;

            rc.left = rc.top = 0;

            rc.bottom = height - 1;

            rc.right = width - 1;

            SetNewCalc(cptUL, dPrec, rc);

            fRectDefined = FALSE;

            DoSomeWork(hWnd, FALSE);

            break;

        case IDM_ZOOMIN:  // zoom in on selected rectangle

            // if no rectangle, don't zoom in

            if (!fRectDefined)

                break;

            if (dPrec < (double)MINPREC)  // don't allow zoom in

                break;

            DrawRect(hWnd, &rcZoom, TRUE, hdcMem);  // draw new rect

            // calculate new upper-left

            cptUL.real += (rcZoom.left * dPrec);

            cptUL.imag -= (rcZoom.top * dPrec);

            iWidthNew = (rcZoom.right - rcZoom.left + 1);

            iHeightNew = (rcZoom.bottom - rcZoom.top + 1);

            scaling = ((double) ((iWidthNew > iHeightNew) ? iWidthNew : iHeightNew) / (double) width);

            dPrec *= scaling;

            rc.left = rc.top = 0;

            rc.bottom = height - 1;

            rc.right = width - 1;

            SetNewCalc(cptUL, dPrec, rc);

            IncPictureID();

            fRectDefined = FALSE;

            DoSomeWork(hWnd, FALSE);

            break;

        case IDM_CONTINUOUS:  // continuous zoom in

            if (fContinueZoom == TRUE) {

                CheckMenuItem(GetMenu(hWnd), IDM_CONTINUOUS, MF_UNCHECKED);

                fContinueZoom = FALSE;

            }

            else {

                CheckMenuItem(GetMenu(hWnd), IDM_CONTINUOUS, MF_CHECKED);

                fContinueZoom = TRUE;

            }

            break;

        case IDM_REDRAW:

            if (fContinueZoom == TRUE)

                InitHistogram();

            rc.left = rc.top = 0;

            rc.right = width+1;

            rc.bottom = height + 1;

            FillRect(hdcMem, &rc, GetStockObject(WHITE_BRUSH));

            InvalidateRect(hWnd, NULL, TRUE);

            rc.left = rc.top = 0;

            rc.bottom = height - 1;

            rc.right = width - 1;

            SetNewCalc( cptUL, dPrec, rc);

            fRectDefined = FALSE;

            DoSomeWork(hWnd, FALSE);

            break;

        case IDM_EXIT:

            DestroyWindow(hWnd);

            FreeDrawBuffer();

            break;

        case IDM_TOP:

            cptUL.real = (double) -2.05;

            cptUL.imag = (double) 1.4;

            dPrec = .01;

            rc.left = rc.top = 0;

            rc.bottom = height - 1;

            rc.right = width - 1;

            SetNewCalc(cptUL, dPrec, rc);

            ResetPictureID();  // incremented past original

            fRectDefined = FALSE;

            DoSomeWork(hWnd, FALSE);

            break;

        case IDM_1LINE:

        case IDM_2LINES:

        case IDM_4LINES:

            CheckMenuItem(GetMenu(hWnd), miOldLines, MF_UNCHECKED);

            miOldLines = wParam;

            switch(wParam) {

            case IDM_1LINE:

                iLines = 1;

                break;

            case IDM_2LINES:

                iLines = 2;

                break;

            case IDM_4LINES:

                iLines = 4;

                break;

            }

            CheckMenuItem(GetMenu(hWnd), miOldLines, MF_CHECKED);

            break;

#ifdef RPC

        case IDM_PROTSEQ:

            lpProc = MakeProcInstance(Protseq, hInst);

            DialogBox(hInst,        // current instance

                      "ProtseqBox", // resource to use

                      hWnd,         // parent handle

                      lpProc);      // Server instance address

            FreeProcInstance(lpProc);

            break;

        case IDM_SERVER:

            lpProc = MakeProcInstance(Server, hInst);

            DialogBox(hInst,         // current instance

                      "ServerBox",   // resource to use

                      hWnd,          // parent handle

                      lpProc);       // Server  instance address

            FreeProcInstance(lpProc);

            break;

        case IDM_ENDPOINT:

            lpProc = MakeProcInstance(Endpoint, hInst);

            DialogBox(hInst,        // current instance

                      "EndpointBox",// resource to use

                      hWnd,         // parent handle

                      lpProc);      // Server instance address

            FreeProcInstance(lpProc);

            break;

#endif

        case IDM_GO:

        SetTimer(hWnd, 1, POLL_TIME, NULL);  // set timer for polls

            EnableMenuItem(GetMenu(hWnd), IDM_GO, MF_GRAYED);	// disable GO

            break;

        default:  // Lets Windows process it

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

        }

        break;

    case WM_DESTROY:  // message: window being destroyed

        PostQuitMessage(0);

        DeleteDC(hdcMem);

        DeleteObject(hbmMem);

        break;

    case WM_DOSOMEWORK:  // do another slice of calculation work

        DoSomeWork(hWnd, FALSE);

        break;

    case WM_PAINTLINE:  // The shared buffer contains a line of data; draw it

        PaintLine(hWnd,

                  &SvrTable,

                  hdcMem,

                  height);

        break;

    case WM_TIMER:  // timer means we should do another slice of work

        DoSomeWork(hWnd, TRUE);

        break;

    case WM_LBUTTONDOWN:  // left button down; start to define a zoom rectangle

        if (fRectDefined)

            DrawRect(hWnd, &rcZoom, FALSE, hdcMem);  // undraw old rectangle

        // initialize rectangle

        rcZoom.left = rcZoom.right = pSelected.x = LOWORD(lParam);

        rcZoom.top = rcZoom.bottom = pSelected.y = HIWORD(lParam);

        // draw the new rectangle

        DrawRect(hWnd, &rcZoom, TRUE, hdcMem);

        fRectDefined = TRUE;

        fButtonDown = TRUE;

        SetCapture(hWnd);  // capture all mouse events

        break;

    case WM_MOUSEMOVE:  // mouse move

        // if the button is down, change the rect

        if (!fButtonDown)

            break;

        DrawRect(hWnd, &rcZoom, FALSE, hdcMem);  // undraw old rect

        pMove.x = LOWORD(lParam);

        pMove.y = HIWORD(lParam);

        // update the selection rectangle

        if (pMove.x <= pSelected.x)

            rcZoom.left = pMove.x;

        if (pMove.x >= pSelected.x)

            rcZoom.right = pMove.x;

        if (pMove.y <= pSelected.y)

            rcZoom.top = pMove.y;

        if (pMove.y >= pSelected.y)

            rcZoom.bottom = pMove.y;

        DrawRect(hWnd, &rcZoom, TRUE, hdcMem);  // draw new rect

        break;

    case WM_LBUTTONUP:  // button up; end selection

        fButtonDown = FALSE;

        ReleaseCapture();

        break;

    default:  // Passes it on if unproccessed

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

    }

    return(0L);

}

/*

 *  FUNCTION: About(HWND, unsigned, WORD, LONG)

 *

 *  PURPOSE:  Processes messages for "About" dialog box

 *

 *  MESSAGES:

 *

 *      WM_INITDIALOG - initialize dialog box

 *      WM_COMMAND    - Input received

 *

 *  COMMENTS:

 *

 *      No initialization is needed for this particular dialog box, but TRUE

 *      must be returned to Windows.

 *

 *      Wait for user to click on "Ok" button, then close the dialog box.

 */

BOOL APIENTRY About(

    HWND hDlg,              /* window handle of the dialog box */

    UINT message,           /* type of message                 */

    UINT wParam,            /* message-specific information    */

    LONG lParam)

{

    UNREFERENCED_PARAMETER(lParam);

    switch (message) {

    case WM_INITDIALOG:     /* message: initialize dialog box  */

        return(TRUE);

    case WM_COMMAND:        /* message: received a command     */

        if (wParam == IDOK || wParam == IDCANCEL)

        {

            EndDialog(hDlg, TRUE);    /* Exits the dialog box  */

            return(TRUE);

        }

        break;

    }

    return(FALSE);          /* Didn't process a message        */

}

/*

 *  FUNCTION: Protseq(HWND, unsigned, WORD, LONG)

 *

 *  PURPOSE:  Processes messages for "Protseq" dialog box

 *

 *  MESSAGES:

 *

 *      WM_INITDIALOG - initialize dialog box

 *      WM_COMMAND    - Input received

 *

 *  COMMENTS:

 *

 *      No initialization is needed for this particular dialog box, but TRUE

 *      must be returned to Windows.

 *

 *      Wait for user to click on "Ok" button, then close the dialog box.

 */

BOOL APIENTRY Protseq(

    HWND hDlg,               /* window handle of the dialog box */

    UINT message,            /* type of message             */

    UINT wParam,             /* message-specific information    */

    LONG lParam)

{

    UNREFERENCED_PARAMETER(lParam);

#ifdef RPC

    switch (message) {

    case WM_INITDIALOG:    // message: initialize dialog box

        SetDlgItemText((HANDLE)hDlg, IDD_PROTSEQNAME, pszProtocolSequence);

        return(TRUE);

    case WM_COMMAND:       // message: received a command

        switch(wParam) {

        case IDCANCEL:     // System menu close command?

            EndDialog(hDlg, FALSE);

            return(TRUE);

        case IDOK:         // "OK" box selected?

            GetDlgItemText(hDlg, IDD_PROTSEQNAME, pszProtocolSequence, MAXPROTSEQ);

            if (Bind(hDlg) != RPC_S_OK) {

                EndDialog(hDlg, FALSE);

                return(FALSE);

            }

        KillTimer(hWND, 1);  // stop timer for polls

            EnableMenuItem(GetMenu(hWND), IDM_GO, MF_ENABLED);	// enable GO

            EndDialog(hDlg, TRUE);

            return(TRUE);

        }

    }

#endif

    return(FALSE);  // Didn't process a message

}

/*

 *  FUNCTION: Server(HWND, unsigned, WORD, LONG)

 *

 *  PURPOSE:  Processes messages for "Server" dialog box

 *

 *  MESSAGES:

 *

 *      WM_INITDIALOG - initialize dialog box

 *      WM_COMMAND    - Input received

 *

 *  COMMENTS:

 *

 *      No initialization is needed for this particular dialog box, but TRUE

 *      must be returned to Windows.

 *

 *      Wait for user to click on "Ok" button, then close the dialog box.

 */

BOOL APIENTRY Server(

    HWND hDlg,               /* window handle of the dialog box */

    UINT message,            /* type of message             */

    UINT wParam,             /* message-specific information    */

    LONG lParam)

{

    UNREFERENCED_PARAMETER(lParam);

#ifdef RPC

    switch (message) {

    case WM_INITDIALOG:      /* message: initialize dialog box */

        SetDlgItemText(hDlg, IDD_SERVERNAME, pszNetworkAddress);

        return(TRUE);

    case WM_COMMAND:         /* message: received a command    */

        switch(wParam) {

        case IDCANCEL:       /* System menu close command?     */

            EndDialog(hDlg, FALSE);

            return(TRUE);

        case IDOK:            /* "OK" box selected?            */

            GetDlgItemText( hDlg, IDD_SERVERNAME, pszNetworkAddress, UNCLEN);

            if (Bind(hDlg) != RPC_S_OK) {

                EndDialog(hDlg, FALSE);

                return(FALSE);

            }

        KillTimer(hWND, 1);  // stop timer for polls

            EnableMenuItem(GetMenu(hWND), IDM_GO, MF_ENABLED);	// enable GO

            EndDialog(hDlg, TRUE);

            return(TRUE);

        }

    }

#endif

    return(FALSE);           /* Didn't process a message      */

}

/*

 *  FUNCTION: Endpoint(HWND, unsigned, WORD, LONG)

 *

 *  PURPOSE:  Processes messages for "Endpoint" dialog box

 *

 *  MESSAGES:

 *

 *      WM_INITDIALOG - initialize dialog box

 *      WM_COMMAND    - Input received

 *

 *  COMMENTS:

 *

 *      No initialization is needed for this particular dialog box, but TRUE

 *      must be returned to Windows.

 *

 *      Wait for user to click on "Ok" button, then close the dialog box.

 */

BOOL APIENTRY Endpoint(

    HWND hDlg,               /* window handle of the dialog box */

    UINT message,            /* type of message             */

    UINT wParam,             /* message-specific information    */

    LONG lParam)

{

    UNREFERENCED_PARAMETER(lParam);

#ifdef RPC

    switch (message) {

    case WM_INITDIALOG:    // message: initialize dialog box

        SetDlgItemText(hDlg, IDD_ENDPOINTNAME, pszEndpoint);

        return(TRUE);

    case WM_COMMAND:       // message: received a command

        switch(wParam) {

        case IDCANCEL:

            EndDialog(hDlg, FALSE);

            return(TRUE);

        case IDOK:

            GetDlgItemText(hDlg, IDD_ENDPOINTNAME, pszEndpoint, PATHLEN);

            if (Bind(hDlg) != RPC_S_OK) {

                EndDialog(hDlg, FALSE);

                return(FALSE);

            }

        KillTimer(hWND, 1);  // stop timer for polls

            EnableMenuItem(GetMenu(hWND), IDM_GO, MF_ENABLED);	// enable GO

            EndDialog(hDlg, TRUE);

            return(TRUE);

        }

    }

#endif

    return(FALSE);  // Didn't process a message

}

/*

 *  DoSomeWork --

 *

 *  This function does our work for us. It does it in little pieces, and

 *  will schedule itself as it sees fit.

 */

void

DoSomeWork(HWND    hwnd,

           BOOL    fTimer)

{

    static WORD   wIteration = 0;

    if (fTimer) {

        wIteration++;

        // on every nth tick, we send out a poll

        if (wIteration == 120) {  // tune this?

            wIteration = 0;

            return;

        }

        // on the half-poll, we check for responses

        if ((wIteration == 2) || (wIteration == 10)) {

            return;

        }

    }

    if (CheckDrawStatus(hwnd))

        SendMessage(hwnd, WM_DOSOMEWORK, 0, 0L);

    return;

}

/*

 *  DrawRect --

 *

 *  This function draws (or undraws) the zoom rectangle.

 */

void

DrawRect(HWND      hwnd,

         PRECT     prc,

         BOOL      fDrawIt,

         HDC       hdcBM)

{

    HDC     hdc;

    DWORD   dwRop;

    hdc = GetDC(hwnd);

    if (fDrawIt)

        dwRop = NOTSRCCOPY;

    else

        dwRop = SRCCOPY;

    // top side

    BitBlt(hdc, prc->left, prc->top, (prc->right - prc->left) + 1,

           1, hdcBM, prc->left, prc->top, dwRop);

    // bottom side

    BitBlt(hdc, prc->left, prc->bottom, (prc->right - prc->left) + 1,

           1, hdcBM, prc->left, prc->bottom, dwRop);

    // left side

    BitBlt(hdc,prc->left, prc->top, 1, (prc->bottom - prc->top) + 1,

           hdcBM, prc->left, prc->top, dwRop);

    // right side

    BitBlt(hdc,prc->right, prc->top, 1, (prc->bottom - prc->top) + 1,

           hdcBM, prc->right, prc->top, dwRop);

    ReleaseDC(hwnd, hdc);

}

/*

 *  PaintLine --

 *

 *  This function paints a buffer of data into the bitmap.

 */

void

PaintLine(HWND        hwnd,

          svr_table * pst,

          HDC         hdcBM,

          int         cHeight)

{

    LPWORD  pwDrawData;

    int     y;

    int     x;

    DWORD   dwThreshold;

    RECT    rc;

    WORD    lines;

    lines  = (WORD) pst->cLines;

    // picture ID had better match, or else we skip it

    if (CheckDrawingID(pst->cPicture))

    {

        // figure out our threshold

        dwThreshold = QueryThreshold();

        // get a pointer to the draw buffer

        pwDrawData = (LPWORD) LockDrawBuffer();

        if (pwDrawData == NULL) {

            ReturnDrawBuffer();

            return;

        }

        // starting x coordinate

        x = (int) pst->dwLine;

        // now loop through the rectangle

        while (lines-- > 0)

        {

            // bottom to top, since that's the order of the data in the buffer

            y = (int) cHeight-1;

            while (y >= 0)

            {

                // draw a pixel

                SetPixel(hdcBM, x,y, MapColor(*pwDrawData, dwThreshold));

                if (fContinueZoom == TRUE)

                    CalcHistogram(x, y, *pwDrawData, dwThreshold);

                // now increment buffer pointer and y coord

                y--;

                pwDrawData++;

            }

            // increment X coordinate

            x++;

        }

        // figure out the rectangle to invalidate

        rc.top = 0;

        rc.bottom = cHeight;

        rc.left = (int)(pst->dwLine);

        rc.right = (int)(pst->dwLine) + pst->cLines;

        UnlockDrawBuffer();

        // and invalidate it on the screen so we redraw it

        InvalidateRect(hwnd, &rc, FALSE);

    }

    // free this for someone else to use

    ReturnDrawBuffer();

    // and change the pipe state, if necessary

    if (pst->iStatus == SS_PAINTING)

        pst->iStatus = SS_IDLE;

}

#define CLR_BLACK       RGB(0,0,0)

#define CLR_DARKBLUE    RGB(0,0,127)

#define CLR_BLUE        RGB(0,0,255)

#define CLR_CYAN        RGB(0,255,255)

#define CLR_DARKGREEN   RGB(0,127,0)

#define CLR_GREEN       RGB(0,255,0)

#define CLR_YELLOW      RGB(255,255,0)

#define CLR_RED         RGB(255,0,0)

#define CLR_DARKRED     RGB(127,0,0)

#define CLR_WHITE       RGB(255,255,255)

#define CLR_PALEGRAY    RGB(194,194,194)

#define CLR_DARKGRAY    RGB(127,127,127)

static COLORREF ColorMapTable[] = {     // size = NCOLORS

    CLR_DARKBLUE,

    CLR_BLUE,

    CLR_CYAN,

    CLR_DARKGREEN,

    CLR_GREEN,

    CLR_YELLOW,

    CLR_RED,

    CLR_DARKRED,

    CLR_WHITE,

    CLR_PALEGRAY,

    CLR_DARKGRAY};

/*

 *  MapColor --

 *

 *  This function maps an iteration count into a corresponding RGB color.

 */

COLORREF

MapColor(DWORD  dwIter,

         DWORD  dwThreshold)

{

    /* if it's beyond the threshold, call it black */

    if (dwIter >= dwThreshold) {

        return(CLR_BLACK);

    }

    /* get a modulus based on the number of colors */

    dwIter = (dwIter / 3) % NCOLORS; // 11;

    /* and return the appropriate color */

    return(ColorMapTable[dwIter]);

}

/*

 * CalcHistogram --

 *

 * This function is used to select the region that is the

 * most complex and will be used to zoom in for the next picture;

 * it contains the most colors.  The number of colors are counted.

 */

void

CalcHistogram(int    x,

              int    y,

              DWORD  dwIter,

              DWORD  dwThreshold)

{

    /* if it's beyond the threshold, call it black */

    if (dwIter >= dwThreshold) {

        Histogram[x/(WIDTH/4)][y/(HEIGHT/4)][NCOLORS]++;

        return;

    }

    /* get a modulus based on the number of colors */

    dwIter = (dwIter / 3) % NCOLORS; // 11;

    /* and bump the count for the appropriate color */

    Histogram[x/(WIDTH/4)][y/(HEIGHT/4)][dwIter]++;  // region of map

    return;

}

/*

 * InitHistogram --

 *

 * This function initializes the histogram data structures.

 */

void InitHistogram(void)

{

    int i, j, k;

    for (i = 0; i < 4; i++)

        for (j = 0; j < 4; j++)

            for (k = 0; k <= NCOLORS; k++)

                Histogram[i][j][k] = 0;  // count of colors

}

/*

 * CountHistogram --

 *

 * This function determines the number of colors represented

 * within a region.  The region with the most colors is

 * selected using the maxi and maxj values.  X and Y coordinates

 * corresponding to these regions are stored in the HistRegion

 * table and are used for the next picture.

 */

void CountHistogram(void)

{

    int i, j, k;

    /* count the number of colors in each region */

    /* find the color that dominates each region */

    for (i = 0; i < 4; i++) {

        for (j = 0; j < 4; j++) {

            ColorCount[i][j] = 0;

            Max[i][j] = 0;

            for (k = 0; k <= NCOLORS; k++) {

                if (Histogram[i][j][k] > Max[i][j])

                    Max[i][j] = Histogram[i][j][k];

                if (Histogram[i][j][k] != 0)  // count of colors

                    ColorCount[i][j]++;

            }

        }

    }

    iHistMaxI = 0;

    iHistMaxJ = 0;

    /* if several regions have the same number of colors,        */

    /* select the region with the most variety: the smallest max */

    for (i = 0; i < 4; i++) {

        for (j = 0; j < 4; j++) {

            if (   (ColorCount[i][j] >= ColorCount[iHistMaxI][iHistMaxJ])

                && (Max[i][j] < Max[iHistMaxI][iHistMaxJ]) ) {

                iHistMaxI = i;

                iHistMaxJ = j;

            }

        }

    }

    InitHistogram();  // initialize for next time

}

#ifdef RPC

void __RPC_FAR * __RPC_API midl_user_allocate(size_t len)

{

    UNREFERENCED_PARAMETER(len);

    return(NULL);

}

void __RPC_API midl_user_free(void __RPC_FAR * ptr)

{

    UNREFERENCED_PARAMETER(ptr);

    return;

}

/*

 *  FUNCTION: Bind(HWND)

 *

 *  PURPOSE:  Make RPC API calls to bind to the server application

 *

 *  COMMENTS:

 *

 *      The binding calls are made from InitInstance() and whenever

 *      the user changes the server name or endpoint. If the bind

 *      operation is successful, the global flag fBound is set to TRUE.

 *

 *      The global flag fBound is used to determine whether to call

 *      the RPC API function RpcBindingFree.

 */

RPC_STATUS Bind(HWND hWnd)

{

    RPC_STATUS status;

    char pszFail[MSGLEN];

    if (fBound == TRUE) {  // unbind only if bound

        status = RpcStringFree(&pszStringBinding);

        if (status) {

            sprintf(pszFail, "RpcStringFree failed 0x%x", status);

            MessageBox(hWnd,

                       pszFail,

                       "RPC Sample Application",

                       MB_ICONSTOP);

            return(status);

        }

        status = RpcBindingFree(&hMandel);

        if (status) {

            sprintf(pszFail, "RpcBindingFree failed 0x%x", status);

            MessageBox(hWnd,

                       pszFail,

                       "RPC Sample Application",

                       MB_ICONSTOP);

            return(status);

        }

        fBound = FALSE;  // unbind successful; reset flag

    }

    status = RpcStringBindingCompose(pszUuid,

                                     pszProtocolSequence,

                                     pszNetworkAddress,

                                     pszEndpoint,

                                     pszOptions,

                                     &pszStringBinding);

    if (status) {

        sprintf(pszFail, "RpcStringBindingCompose returned: (0x%x)\nNetwork Address = %s\n",

              status, pszNetworkAddress);

        MessageBox(hWnd, pszFail, "RPC Sample Application", MB_ICONINFORMATION);

        return(status);

    }

    status = RpcBindingFromStringBinding(pszStringBinding,

                                         &hMandel);

    if (status) {

        sprintf(pszFail, "RpcBindingFromStringBinding returned: (0x%x)\nString = %s\n",

             status, pszStringBinding);

        MessageBox(hWnd, pszFail, "RPC Sample Application", MB_ICONINFORMATION);

        return(status);

    }

    fBound = TRUE;  // bind successful; reset flag

    return(status);

}

#endif

/* end mandel.c */


 REMOTE.C   (MANDEL RPC Sample)

/****************************************************************************

                   Microsoft RPC Version 2.0

           Copyright Microsoft Corp. 1992, 1993, 1994

                        mandel Example

    FILE:      remote.c

    PURPOSE:   Client side of the RPC distributed application Mandel

    COMMENTS:  Code to do the remote calculations for the Windows

               Mandelbrot Set distributed drawing program.

               Information coming into this module (via API calls) is

               based on upper-left being (0,0) (the Windows standard).

               We translate that to lower-left is (0,0) before we ship

               it out onto the net, and we do reverse translations

               accordingly.

               The iteration data is passed back to the main window

               procedure (by means of a WM_PAINTLINE message) which

               draws the picture.

               A word about the shared buffer: multiple buffers could

               be used, but a single one is used. The buffer is requested

               in this code, and then released after the data has been

               drawn (in PaintLine() in mandel.c). So long as the painting

               is done quickly, this is efficient.

****************************************************************************/

#include <stdlib.h>

#include <stdio.h>

#include <string.h>

#include <windows.h>

#ifdef RPC

#include "mdlrpc.h"

#endif

#include "mandel.h"

/*

 * External variables

 */

extern int          fBound;

extern svr_table    SvrTable;    // the server table

extern int          iLines;

extern double       dPrec;

extern int          fContinueZoom;

extern int          fZoomIn;

extern int          iHistMaxI;

extern int          iHistMaxJ;

extern RECT         rcZoom;

extern BOOL         fRectDefined;

/*

 * Picture information

 */

int             cPictureID = 0;    // picture id, in case we reset in the middle

static CPOINT   cptLL;             // upper-left

static double   dPrecision;        // precision of draw

static LONGRECT rclPicture;        // rectangle defining client window

static DWORD    dwCurrentLine;     // next line to be drawn

static DWORD    dwThreshold;       // threshold for iterations

/*

 * Function prototypes for local procs

 */

DWORD CalcThreshold(double);

/*

 *  InitRemote --

 *

 *  This function initializes everything for our remote connections.

 *  It gets the local wksta name (making sure the wksta is started)

 *  and it creates the mailslot with which to collect replies to our poll.

 *

 *  RETURNS

 *      TRUE    - initialization succeeded

 *      FALSE   - initialization failed, can't go on

 */

BOOL InitRemote(HWND hWnd)

{

#ifndef RPC

    UNREFERENCED_PARAMETER(hWnd);

#endif

    // set up our local entry

    strcpy(SvrTable.name, "Local machine");

    SvrTable.iStatus = SS_LOCAL;

    // good, we succeeded

    return(TRUE);

}

/*

 *  CheckDrawStatus --

 *

 *  This function does a check of all buffers being drawn.

 *

 *  If it finds an idle pipe, and there is work to be done, it assigns

 *      a line, and writes out the request.

 *  If it finds a read-pending pipe, it checks if the read has completed.

 *      If it has, it is read and a message is sent so the read data can

 *      be processed.

 *

 *  RETURNS

 *      TRUE    - we did a piece of work

 *      FALSE   - we could not find any work to do.

 */

BOOL CheckDrawStatus(HWND hwnd)

{

    CALCBUF     cb;

    LPVOID      pbBuf;

    while(TRUE) {

        // Check the status

        switch(SvrTable.iStatus) {

        case SS_PAINTING:

            break;

        case SS_IDLE:

            break;

        case SS_LOCAL:

            // Do a chunk of work locally

#ifdef RPC

            if (fBound == FALSE)

                break;

#endif

            if ((long) dwCurrentLine > rclPicture.xRight) {

                if (fContinueZoom == TRUE) {

                    if ((fZoomIn == TRUE) && (dPrec < (double)MINPREC))

                        fZoomIn = FALSE;  // start zooming out

                    if ((fZoomIn == FALSE) && (dPrec > (double)MAXPREC))

                        fZoomIn = TRUE;

                    if (fZoomIn) {

                        CountHistogram();

                        rcZoom.top    = iHistMaxJ * (WIDTH/4);

                        rcZoom.bottom = rcZoom.top + (WIDTH/4) - 1;

                        rcZoom.left   = iHistMaxI * (HEIGHT/4);

                        rcZoom.right  = rcZoom.left + (HEIGHT/4) - 1;

                        fRectDefined = TRUE;

                        PostMessage(hwnd, WM_COMMAND, IDM_ZOOMIN, 0L);

                    }

                    else

                        PostMessage(hwnd, WM_COMMAND, IDM_ZOOMOUT, 0L);

                }

                break;

            }

            if (TakeDrawBuffer() == FALSE)

                break;

            pbBuf = LockDrawBuffer();

            cb.rclDraw.xLeft = dwCurrentLine;

            cb.rclDraw.xRight = dwCurrentLine + iLines - 1;

            cb.rclDraw.yTop = rclPicture.yTop;

            cb.rclDraw.yBottom = rclPicture.yBottom;

            RpcTryExcept {

                MandelCalc(&cptLL,

                           &(cb.rclDraw),

                           dPrecision,

                           dwThreshold,

                           (LINEBUF *) pbBuf);

            }

            RpcExcept(1) {

                char szFail[MSGLEN];

            	sprintf (szFail, "%s (0x%x)\n", EXCEPT_MSG, RpcExceptionCode());

                MessageBox(hwnd,

                           szFail,

                           "Remote Procedure Call",

                           MB_ICONINFORMATION);

        KillTimer(hwnd, 1);  // stop timer for polls

            EnableMenuItem(GetMenu(hwnd), IDM_GO, MF_ENABLED);	// enable GO

            UnlockDrawBuffer();

    ReturnDrawBuffer();

        return(FALSE);

            }

            RpcEndExcept

            UnlockDrawBuffer();

            SvrTable.cPicture = cPictureID;

            SvrTable.dwLine = dwCurrentLine;

            SvrTable.cLines = iLines;

            PostMessage(hwnd, WM_PAINTLINE, 0, 0L);

            dwCurrentLine += iLines;

            return(TRUE);

        }

        return(FALSE);

    }

}

/*

 *  SetNewCalc --

 *

 *  This sets up new information for a drawing and

 *  updates the drawing ID so any calculations in progress will not

 *  be mixed in.

 */

void SetNewCalc(CPOINT cptUL, double dPrec, RECT rc)

{

    // First, translate from upper left to lower left

    cptLL.real = cptUL.real;

    cptLL.imag = cptUL.imag - (dPrec * (rc.bottom - rc.top));

    // Now the precision

    dPrecision = dPrec;

    // The rectangle. Once again, translate.

    rclPicture.xLeft = (long) rc.left;

    rclPicture.xRight = (long) rc.right;

    rclPicture.yBottom = (long) rc.top;

    rclPicture.yTop = (long) rc.bottom;

    // Current line, start of drawing

    dwCurrentLine = rclPicture.xLeft;

    dwThreshold = CalcThreshold(dPrecision);

}

void IncPictureID(void)

{

    cPictureID++;

}

void ResetPictureID(void)

{

    cPictureID = 0;

}

/*

 *  CheckDrawing --

 *

 *  Just a sanity check here -- a function to check to make sure that we're

 *  on the right drawing

 */

BOOL CheckDrawingID(int id)

{

    return((id == cPictureID) ? TRUE : FALSE);

}

/*

 *  TakeDrawBuffer ensures only one pipe read at a time.

 *  LockDrawBuffer locks the handle and returns a pointer.

 *  UnlockDrawBuffer unlocks the handle.

 *  ReturnDrawBuffer lets another pipe read go.

 *  FreeDrawBuffer ensures the allocated buffer is freed upon exit.

 */

static BOOL fBufferTaken = FALSE;

static HANDLE hSharedBuf = (HANDLE) NULL;

BOOL TakeDrawBuffer(void)

{

    if (fBufferTaken) {

        return(FALSE);

    }

    if (hSharedBuf == (HANDLE) NULL) {

        hSharedBuf = LocalAlloc(LMEM_MOVEABLE, MAX_BUFSIZE);

        if (hSharedBuf == (HANDLE) NULL)

            return(FALSE);

    }

    fBufferTaken = TRUE;

    return(TRUE);

}

LPVOID LockDrawBuffer(void)

{

    if (hSharedBuf == (HANDLE) NULL)

        return(NULL);

    return(LocalLock(hSharedBuf));

}

void UnlockDrawBuffer(void)

{

    LocalUnlock(hSharedBuf);

}

void ReturnDrawBuffer(void)

{

    fBufferTaken = FALSE;

}

void FreeDrawBuffer(void)

{

    if (hSharedBuf != (HANDLE) NULL)

        LocalFree(hSharedBuf);

}

/*

 *  CalcThreshold --

 *

 *  We need an iteration threshold beyond which we give up. We want it to

 *  increase the farther we zoom in. This code generates a threshold value

 *  based on the precision of drawing.

 *

 *  RETURNS

 *      threshold calculated based on precision

 */

DWORD CalcThreshold(double precision)

{

    DWORD   thres = 25;

    double  multiplier = (double) 100.0;

    /* for every 100, multiply by 2 */

    while ((precision *= multiplier) < (double)1.0)

        thres *= 2;

    return(thres);

}

/*

 *  QueryThreshold --

 *

 *  Callback for finding out what the current drawing's threshold is.

 */

DWORD QueryThreshold(void)

{

    return(dwThreshold);

}


 SERVER.C   (MANDEL RPC Sample)

/****************************************************************************

                   Microsoft RPC Version 2.0

           Copyright Microsoft Corp. 1992, 1993, 1994

                         mandel Example

    FILE:       server.c

    USAGE:      server  -p protocol_sequence

                        -e endpoint

                        -m max calls

                        -n min calls

                        -f flag for RpcServerListen

    PURPOSE:    Server side of RPC distributed application mandel

    FUNCTIONS:  main() - registers interface and listen for clients

****************************************************************************/

#include <stdlib.h>

#include <stdio.h>

#include <ctype.h>

#include "mdlrpc.h"    // header file generated by MIDL compiler

void Usage(char * pszProgramName)

{

    fprintf(stderr, "Usage:  %s\n", pszProgramName);

    fprintf(stderr, " -p protocol_sequence\n");

    fprintf(stderr, " -e endpoint\n");

    fprintf(stderr, " -m maxcalls\n");

    fprintf(stderr, " -n mincalls\n");

    fprintf(stderr, " -f flag_wait_op\n");

    exit(1);

}

void _CRTAPI1 main(int argc, char * argv[])

{

    RPC_STATUS status;

    unsigned char * pszProtocolSequence = "ncacn_np";

    unsigned char * pszSecurity         = NULL;

    unsigned char * pszEndpoint         = "\\pipe\\mandel";

    unsigned int    cMinCalls           = 1;

    unsigned int    cMaxCalls           = 20;

    unsigned int    fDontWait           = FALSE;

    int i;

    /* allow the user to override settings with command line switches */

    for (i = 1; i < argc; i++) {

        if ((*argv[i] == '-') || (*argv[i] == '/')) {

            switch (tolower(*(argv[i]+1))) {

            case 'p':  // protocol sequence

                pszProtocolSequence = argv[++i];

                break;

            case 'e':

                pszEndpoint = argv[++i];

                break;

            case 'm':

                cMaxCalls = (unsigned int) atoi(argv[++i]);

                break;

            case 'n':

                cMinCalls = (unsigned int) atoi(argv[++i]);

                break;

            case 'f':

                fDontWait = (unsigned int) atoi(argv[++i]);

                break;

            case 'h':

            case '?':

            default:

                Usage(argv[0]);

            }

        }

        else

            Usage(argv[0]);

    }

    status = RpcServerUseProtseqEp(pszProtocolSequence,

                                   cMaxCalls,

                                   pszEndpoint,

                                   pszSecurity);  // Security descriptor

    printf("RpcServerUseProtseqEp returned 0x%x\n", status);

    if (status) {

        exit(status);

    }

    status = RpcServerRegisterIf(mdlrpc_ServerIfHandle, // interface to register

                                 NULL,   // MgrTypeUuid

                                 NULL);  // MgrEpv; null means use default

    printf("RpcServerRegisterIf returned 0x%x\n", status);

    if (status) {

        exit(status);

    }

    printf("Calling RpcServerListen\n");

    status = RpcServerListen(cMinCalls,

                             cMaxCalls,

                             fDontWait);

    printf("RpcServerListen returned: 0x%x\n", status);

    if (status) {

        exit(status);

    }

    if (fDontWait) {

        printf("Calling RpcMgmtWaitServerListen\n");

        status = RpcMgmtWaitServerListen();  //  wait operation

        printf("RpcMgmtWaitServerListen returned: 0x%x\n", status);

        if (status) {

            exit(status);

        }

    }

} // end main()

/*********************************************************************/

/*                MIDL allocate and free                             */

/*********************************************************************/

void __RPC_FAR * __RPC_API midl_user_allocate(size_t len)

{

    return(malloc(len));

}

void __RPC_API midl_user_free(void __RPC_FAR * ptr)

{

    free(ptr);

}

/* end server.c */


 INTEROP

/*************************************************************/ /**                                                         **/ /**                    Microsoft RPC Examples               **/ /**               OSF DCE Interop Sample Application        **/ /**                Copyright(c) Microsoft Corp. 1993-1994   **/ /**                                                         **/ /*************************************************************/

Overview: ---------

This is a small demo RPC application.  It is designed to be portable between OSF DCE RPC and Microsoft RPC platforms.

The most important part of the demo is the header file dceport.h.  This header file maps OSF DCE RPC APIs and data structures to the Microsoft RPC equivalents.

The program just sends simple messages (strings) from the client to the server.

Building on Windows/NT ----------------------

The following environment variables should be set for you already.

  set CPU=i386
  set INCLUDE=c:\mstools\h
  set LIB=c:\mstools\lib
  set PATH=c:c:\winnt\system32;\mstools\bin;

For mips, set CPU=mips For alpha, set CPU=alpha

Build the sample distributed application:

  nmake cleanall
  nmake

Building on MS-DOS Systems --------------------------

After installing the Microsoft Visual C/C++ version 1.50 development  environment and the Microsoft RPC version 2.0 toolkit on a Windows NT computer, you can build the sample client application from Windows NT.

  nmake -f makefile.dos cleanall
  nmake -f makefile.dos

This builds the client application callc.exe.

You may also execute the Microsoft Visual C/C++ compiler under MS-DOS. This requires a two step build process.

  Step One: Compile the .IDL files under Windows NT
     nmake -a -f makefile.dos msg.h

  Step Two: Compile the C sources (stub and application)
     nmake -f makefile.dos

Building on DCE Systems ________________________

You need to copy the following files to the DCE machine: client.c server.c manager.c msg.idl msg.acf makefile.dce

  make -f makefile.dce cleanall all

Note: You will probably need to change the CFLAGS and LIBS variables in makefile.dce to match your platform.

Using the program: ------------------

The basic example:

Run   server
on the server machine.

Run:   client -n <server name> -s "Hi, I'm a client"
on the client machine to send the message.

Run:   client -n <server name> -s "Okay, stop this example" -x
on the client to send the message and cause the server to stop.

You can use fixed endpoints by adding the -e switch:

server -e 3452 client -e 3452 -n <server name> -s "Hi, I'm a client" client -e 3452 -n <server name> -s "Okay, stop this example" -x

You can run the demo over a different protocol by adding a -t switch to both the client and server:

server -t ncacn_np client -t ncacn_np -n <server name> -s "Hi, I'm a client" client -t ncacn_np -n <server name> -s "Okay, stop this example" -x

Options: --------

The -h switch displays a usage message.

The -s <message> switch is used to change with message sent from the client

    to the server.  Without it the message "Hello World" is sent.

The -n <server_name> switch is used for specifying a server machine.

    Without it the server is assumed to run on the same machine.

The -e <endpoint> switch is used to specify a fixed endpoint to be used.

    Without it a dynamic endpoint will be used and registered with the
    endpoint mapper.

The -t <protseq> switch is used to specify which protocol to use.  Without

    it the protocol sequence "ncacn_ip_tcp" will be used.


 MAKEFILE   (INTEROP RPC Sample)

#*************************************************************#

#**                                                         **#

#**                 Microsoft RPC Examples                  **#

#**                 OSF DCE Interop Application             **#

#**            Copyright(c) Microsoft Corp. 1993            **#

#**                                                         **#

#*************************************************************#

!include <ntwin32.mak>

!if "$(CPU)" == "i386"

cflags = $(cflags:G3=Gz)

cflags = $(cflags:Zi=Z7)

!endif

all : client.exe server.exe

# Make the client

client : client.exe

client.exe : client.obj msg_c.obj midluser.obj

    $(link) $(linkdebug) $(conflags) -out:client.exe -map:client.map \

      client.obj msg_c.obj midluser.obj \

      rpcrt4.lib $(conlibs)

# client main program

client.obj : client.c msg.h

   $(cc) $(cdebug) $(cflags) $(cvars) $*.c

# client stub

msg_c.obj : msg_c.c msg.h

   $(cc) $(cdebug) $(cflags) $(cvars) $*.c

# Make the server executable

server : server.exe

server.exe : server.obj manager.obj msg_s.obj midluser.obj

    $(link) $(linkdebug) $(conflags) -out:server.exe -map:server.map \

      server.obj manager.obj msg_s.obj midluser.obj \

      rpcrt4.lib $(conlibsmt)

# server main program

server.obj : msg.h

   $(cc) $(cdebug) $(cflags) $(cvarsmt) $*.c

# remote procedures

manager.obj : msg.h

   $(cc) $(cdebug) $(cflags) $(cvarsmt) $*.c

# server stub

msg_s.obj : msg_s.c msg.h

   $(cc) $(cdebug) $(cflags) $(cvarsmt) $*.c

# midl_user* routines

midluser.obj : midluser.c

   $(cc) $(cdebug) $(cflags) $(cvarsmt) $*.c

# Stubs and header file from the IDL file

msg.h msg_s.c msg_c.c : msg.idl msg.acf

    midl -cpp_cmd $(cc) -cpp_opt "-E" msg.idl

# Clean up everything

cleanall : clean

    -del *.exe

# Clean up everything but the .EXEs

clean :

    -del *.obj

    -del *.map

    -del msg_?.c

    -del msg.h


 DCEPORT.H   (INTEROP RPC Sample)

/*++

Copyright (c) 1993-1994 Microsoft Corporation

Module Name:

    dceport.h

Abstract:

    Include file defining types and macros which map DCE RPC APIs to

    Microsoft RPC APIs.  Useful when porting DCE RPC applications to MS RPC.

--*/

#ifndef DCEPORT_H

#define DCEPORT_H

#ifdef __cplusplus

extern "C" {

#endif

/*

** Define various idl types

*/

#define idl_char                unsigned char

#define idl_boolean             unsigned char

#define idl_byte                unsigned char

#define idl_small_int           char

#define idl_usmall_int          unsigned char

#define idl_short_int           signed short

#define idl_ushort_int          unsigned short

#define idl_long_int            long

#define idl_ulong_int           unsigned long

#define boolean32               unsigned long

#define unsigned32              unsigned long

#define unsigned16              unsigned short

#define idl_true                1

#define idl_false               0

#define unsigned_char_t         unsigned char

typedef unsigned char __RPC_FAR *unsigned_char_p_t;

typedef void __RPC_FAR          *idl_void_p_t;

#ifndef _ERROR_STATUS_T_DEFINED

typedef unsigned long error_status_t;

#define _ERROR_STATUS_T_DEFINED

#endif

/*

** Define various DCE RPC types

*/

#define rpc_if_handle_t             RPC_IF_HANDLE

#define rpc_ns_handle_t             RPC_NS_HANDLE

#define rpc_authz_handle_t          RPC_AUTHZ_HANDLE

#define rpc_auth_identity_handle_t  RPC_AUTH_IDENTITY_HANDLE

#define rpc_sm_thread_handle_t      RPC_SS_THREAD_HANDLE

#define rpc_mgr_epv_t               RPC_MGR_EPV __RPC_FAR *

#define rpc_object_inq_fn_t         RPC_OBJECT_INQ_FN __RPC_FAR *

#define rpc_auth_key_retrieval_fn_t RPC_AUTH_KEY_RETRIEVAL_FN

#define rpc_mgmt_authorization_fn_t RPC_MGMT_AUTHORIZATION_FN

/*

** Define rpc_binding_vector_t to match DCE

*/

#ifdef rpc_binding_vector_t

#undef rpc_binding_vector_t

#endif

typedef struct

{

     unsigned long           count;

     handle_t                binding_h[1];

} rpc_binding_vector_t, __RPC_FAR *rpc_binding_vector_p_t;

/*

** Define rpc_protseq_vector_t to match DCE

*/

typedef struct

{

    unsigned long           count;

    unsigned char *         protseq[1];

} rpc_protseq_vector_t, __RPC_FAR *rpc_protseq_vector_p_t;

/*

** Define rpc_stats_vector_t to match DCE

*/

typedef struct

{

    unsigned long           count;

    unsigned long           stats[1];

} rpc_stats_vector_t, __RPC_FAR *rpc_stats_vector_p_t;

/*

** Define uuid_t to match DCE

*/

#ifdef uuid_t

#undef uuid_t

#endif

typedef struct

{

    unsigned long            time_low;

    unsigned short           time_mid;

    unsigned short           time_hi_and_version;

    unsigned char            clock_seq_hi_and_reserved;

    unsigned char            clock_seq_low;

    unsigned char            node[6];

} uuid_t, __RPC_FAR *uuid_p_t;

/*

** Define uuid_vector_t to match DCE

*/

#ifdef uuid_vector_t

#undef uuid_vector_t

#endif

typedef struct

{

     unsigned long           count;

     uuid_p_t                uuid[1];

} uuid_vector_t, __RPC_FAR *uuid_vector_p_t;

/*

** Define rpc_if_id_t and rpc_if_id_p_t to match DCE

*/

typedef struct

{

    uuid_t                   uuid;

    unsigned short           vers_major;

    unsigned short           vers_minor;

} rpc_if_id_t, __RPC_FAR *rpc_if_id_p_t;

/*

** Define rpc_if_id_vector_t to match DCE

*/

typedef struct

{

    unsigned long           count;

    rpc_if_id_p_t           if_id[1];

} rpc_if_id_vector_t, __RPC_FAR *rpc_if_id_vector_p_t;

/*

** The MinThreads parameters to RpcServerListen()

** is not part of the DCE API rpc_server_listen().

** This is the default value.

*/

#define rpc_c_listen_min_threads_default 1

/*

** Define various constants

*/

#define rpc_c_ns_syntax_default            RPC_C_NS_SYNTAX_DEFAULT

#define rpc_c_ns_syntax_dce                RPC_C_SYNTAX_DCE

#define rpc_c_ns_default_exp_age           RPC_C_DEFAULT_EXP_AGE

#define rpc_c_protseq_max_reqs_default     RPC_C_PROTSEQ_MAX_REQS_DEFAULT

#define rpc_c_protseq_max_calls_default    RPC_C_PROTSEQ_MAX_REQS_DEFAULT

#define rpc_c_listen_max_calls_default     RPC_C_LISTEN_MAX_CALLS_DEFAULT

#define rpc_c_ep_all_elts                  RPC_C_EP_ALL_ELTS

#define rpc_c_ep_match_by_if               RPC_C_EP_MATCH_BY_IF

#define rpc_c_ep_match_by_obj              RPC_C_EP_MATCH_BY_OBJ

#define rpc_c_ep_match_by_both             RPC_C_EP_MATCH_BY_BOTH

#define rpc_c_vers_all                     RPC_C_VERS_ALL

#define rpc_c_vers_compatible              RPC_C_VERS_COMPATIBLE

#define rpc_c_vers_exact                   RPC_C_VERS_EXACT

#define rpc_c_vers_major_only              RPC_C_VERS_MAJOR_ONLY

#define rpc_c_vers_upto                    RPC_C_VERS_UPTO

#define rpc_c_profile_default_elt          RPC_C_PROFILE_DEFAULT_ELT

#define rpc_c_profile_all_elts             RPC_C_PROFILE_ALL_ELTS

#define rpc_c_profile_match_by_if          RPC_C_PROFILE_MATCH_BY_IF

#define rpc_c_profile_match_by_mbr         RPC_C_PROFILE_MATCH_BY_MBR

#define rpc_c_profile_match_by_both        RPC_C_PROFILE_MATCH_BY_BOTH

#define rpc_c_binding_min_timeout          RPC_C_BINDING_MIN_TIMEOUT

#define rpc_c_binding_default_timeout      RPC_C_BINDING_DEFAULT_TIMEOUT

#define rpc_c_binding_max_timeout          RPC_C_BINDING_MAX_TIMEOUT

#define rpc_c_binding_infinite_timeout     RPC_C_BINDING_INFINITE_TIMEOUT

#define rpc_c_stats_calls_in               RPC_C_STATS_CALLS_IN

#define rpc_c_stats_calls_out              RPC_C_STATS_CALLS_OUT

#define rpc_c_stats_pkts_in                RPC_C_STATS_PKTS_IN

#define rpc_c_stats_pkts_out               RPC_C_STATS_PKTS_OUT

#define rpc_c_mgmt_inq_if_ids              RPC_C_MGMT_INQ_IF_IDS

#define rpc_c_mgmt_inq_princ_name          RPC_C_MGMT_INQ_PRINC_NAME

#define rpc_c_mgmt_inq_stats               RPC_C_MGMT_INQ_STATS

#define rpc_c_mgmt_inq_server_listen       RPC_C_MGMT_INQ_SERVER_LISTEN

#define rpc_c_mgmt_stop_server_listen      RPC_C_MGMT_STOP_SERVER_LISTEN

#define rpc_c_mgmt_cancel_infinite_timeout RPC_C_CANCEL_INFINITE_TIMEOUT

/*

** Define DCE API equivalents

*/

#define rpc_binding_copy(source,dest,status) \

                *(status) = RpcBindingCopy(source,dest)

#define rpc_binding_free(binding,status) *(status) = RpcBindingFree(binding)

#define rpc_binding_from_string_binding(string_binding,binding,status) \

                *(status) = RpcBindingFromStringBinding(string_binding,binding)

#define rpc_binding_inq_auth_client(binding,privs,princ_name,protect_level, \

                authn_svc,authz_svc,status) \

                *(status) = RpcBindingInqAuthClient(binding,privs,princ_name, \

                protect_level,authn_svc,authz_svc)

#define rpc_binding_inq_auth_info(binding,princ_name,protect_level,\

                authn_svc,auth_identity,authz_svc,status) \

                *(status) = RpcBindingInqAuthInfo(binding,princ_name, \

                protect_level,authn_svc,auth_identity,authz_svc)

#define rpc_binding_inq_object(binding,object_uuid,status) \

                *(status) = RpcBindingInqObject(binding,\

                (UUID __RPC_FAR *)object_uuid)

#define rpc_binding_reset(binding,status) *(status) = RpcBindingReset(binding)

#define rpc_binding_server_from_client(cbinding,sbinding,status) \

                *(status) = RpcBindingServerFromClient(cbinding,sbinding)

#define rpc_binding_set_auth_info(binding,princ_name,protect_level,\

                authn_svc,auth_identity,authz_svc,status) \

                *(status) = RpcBindingSetAuthInfo(binding,princ_name,\

                protect_level,authn_svc,auth_identity,authz_svc)

#define rpc_binding_set_object(binding,object_uuid,status) \

                *(status) = RpcBindingSetObject(binding,\

                (UUID __RPC_FAR *)object_uuid)

#define rpc_binding_to_string_binding(binding,string_binding,status) \

                *(status) = RpcBindingToStringBinding(binding,string_binding)

#define rpc_binding_vector_free(binding_vector,status) \

                *(status) = RpcBindingVectorFree(\

                (RPC_BINDING_VECTOR __RPC_FAR * __RPC_FAR *)binding_vector)

#define rpc_ep_register(if_spec,binding_vec,object_uuid_vec,annotation,\

                status)\

                *(status) = RpcEpRegister(if_spec,\

                (RPC_BINDING_VECTOR __RPC_FAR *)binding_vec, \

                (UUID_VECTOR __RPC_FAR *)object_uuid_vec, annotation)

#define rpc_ep_register_no_replace(if_spec,binding_vec,object_uuid_vec,\

                annotation,status) \

                *(status) = RpcEpRegisterNoReplace(if_spec,\

                (RPC_BINDING_VECTOR __RPC_FAR *)binding_vec,\

                (UUID_VECTOR __RPC_FAR *)object_uuid_vec,annotation)

#define rpc_ep_resolve_binding(binding_h,if_spec,status) \

                *(status) = RpcEpResolveBinding(binding_h,if_spec)

#define rpc_ep_unregister(if_spec,binding_vec,object_uuid_vec,status) \

                *(status) = RpcEpUnregister(if_spec,\

                (RPC_BINDING_VECTOR __RPC_FAR *)binding_vec,\

                (UUID_VECTOR __RPC_FAR *)object_uuid_vec)

#define rpc_if_id_vector_free(if_id_vector,status) \

                *(status) = RpcIfIdVectorFree(\

                (RPC_IF_ID_VECTOR __RPC_FAR * __RPC_FAR *)if_id_vector)

#define rpc_if_inq_id(if_spec,if_id,status) \

                *(status) = RpcIfInqId(if_spec,(RPC_IF_ID __RPC_FAR *)if_id)

#define rpc_if_register_auth_info(if_spec,princ_name,protect_level,\

                authn_svc,auth_identity,authz_svc,status) \

                *(status) = RpcIfRegisterAuthInfo(if_spec,princ_name,\

                protect_level,authn_svc,auth_identity,authz_svc)

#define rpc_mgmt_ep_elt_inq_begin(ep_binding,inquiry_type,if_id,vers_option,\

                object_uuid,inquiry_context,status) \

                *(status) = RpcMgmtEpEltInqBegin(ep_binding,inquiry_type,if_id,\

                vers_option,object_uuid,inquiry_context)

#define rpc_mgmt_ep_elt_inq_done(inquiry_context,status) \

                *(status) = RpcMgmtEpEltInqDone(inquiry_context)

#define rpc_mgmt_ep_elt_inq_next(inquiry_context,if_id,binding,object_uuid,\

                annotation,status) \

                *(status) = RpcMgmtEpEltInqNext(inquiry_context,if_id,binding,\

                object_uuid,annotation)

#define rpc_mgmt_ep_unregister(ep_binding,if_id,binding,object_uuid,status) \

                *(status) = RpcMgmtEpUnregister(ep_binding,if_id,binding,\

                object_uuid)

#define rpc_mgmt_inq_com_timeout(binding,timeout,status) \

                *(status) = RpcMgmtInqComTimeout(binding,timeout)

#define rpc_mgmt_inq_dflt_protect_level(authn_svc,level,status) \

                *(status) = RpcMgmtInqDefaultProtectLevel(authn_svc,level)

#define rpc_mgmt_inq_if_ids(binding,if_id_vector,status) \

                *(status) = RpcMgmtInqIfIds((bindings),\

                (RPC_IF_ID_VECTOR __RPC_FAR * __RPC_FAR *)(if_id_vector))

#define rpc_mgmt_inq_server_princ_name(binding,authn_svc,princ_name,status) \

                *(status) = RpcMgmtInqServerPrincName(binding,authn_svc,\

                princ_name)

#define rpc_mgmt_inq_stats(binding,statistics,status) \

                *(status) = RpcMgmtInqStats(binding,\

                (RPC_STATS_VECTOR __RPC_FAR * __RPC_FAR *)statistics)

#define rpc_mgmt_is_server_listening(binding,status) \

                ( ((*(status) = RpcMgmtIsServerListening(binding)) == RPC_S_OK) \

                ? (1) : (*(status) == RPC_S_NOT_LISTENING) \

                ? (*(status) = RPS_S_OK, 0) : (0) )

#define rpc_mgmt_set_authorization_fn(authz_fn,status) \

                *(status) = RpcMgmtSetAuthorizathionFn(authz_fn)

#define rpc_mgmt_set_cancel_timeout(seconds,status) \

                *(status) = RpcMgmtSetCancelTimeout(seconds)

#define rpc_mgmt_set_com_timeout(binding,timeout,status) \

                *(status) = RpcMgmtSetComTimeout(binding,timeout)

#define rpc_mgmt_set_server_stack_size(size,status) \

                *(status) = RpcMgmtSetServerStackSize(size)

#define rpc_mgmt_stats_vector_free(stats,status) \

                *(status) = RpcMgmtStatsVectorFree(\

                (RPC_STATS_VECTOR __RPC_FAR * __RPC_FAR *)stats)

#define rpc_mgmt_stop_server_listening(binding,status) \

                *(status) = RpcMgmtStopServerListening(binding)

#define rpc_network_inq_protseqs(prots,status) \

                *(status) = RpcNetworkInqProtseqs(\

                (RPC_PROTSEQ_VECTOR __RPC_FAR * __RPC_FAR *)prots)

#define rpc_network_is_protseq_valid(protseq,status) \

                *(status) = RpcNetworkIsProtseqValid(protseq)

/*

** Define NSI equivalents

*/

#define rpc_ns_binding_export(name_syntax,entry_name,if_spec,\

                binding_vector, uuid_vector,status) \

                *(status) = RpcNsBindingExport(name_syntax,entry_name,\

                if_spec, (RPC_BINDING_VECTOR *)binding_vector,\

                (UUID_VECTOR __RPC_FAR *)uuid_vector)

#define rpc_ns_binding_import_begin(name_syntax,entry_name,if_spec,\

                object_uuid,import_context,status) \

                *(status) = RpcNsBindingImportBegin(name_syntax,entry_name,\

                if_spec,(UUID __RPC_FAR *)object_uuid,import_context)

#define rpc_ns_binding_import_done(import_context,status) \

                *(status) = RpcNsBindingImportDone(import_context)

#define rpc_ns_binding_import_next(import_context,binding,status) \

                *(status) = RpcNsBindingImportNext(import_context,binding)

#define rpc_ns_binding_inq_entry_name(binding,name_syntax,entry_name,status)\

                *(status) = RpcNsBindingInqEntryName(binding,name_syntax,\

                entry_name)

#define rpc_ns_binding_lookup_begin(name_syntax,entry_name,if_spec,\

                object_uuid,max_count,lookup_context,status) \

                *(status) = RpcNsBindingLookupBegin(name_syntax,entry_name,\

                if_spec,(UUID __RPC_FAR *)object_uuid,max_count,lookup_context)

#define rpc_ns_binding_lookup_done(lookup_context,status) \

                *(status) = RpcNsBindingLookupDone(lookup_context)

#define rpc_ns_binding_lookup_next(lookup_context,binding_vector,status) \

                *(status) = RpcNsBindingLookupNext(lookup_context, \

                (RPC_BINDING_VECTOR __RPC_FAR * __RPC_FAR *)binding_vector)

#define rpc_ns_binding_select(binding_vector,binding,status) \

                *(status) = RpcNsBindingSelect(\

                (RPC_BINDING_VECTOR __RPC_FAR *)binding_vector,binding)

#define rpc_ns_binding_unexport(name_syntax,entry_name,if_spec,\

                uuid_vector,status) \

                *(status) = RpcNsBindingUnexport(name_syntax,entry_name,\

                if_spec, (UUID_VECTOR __RPC_FAR *)uuid_vector)

#define rpc_ns_entry_expand_name(name_syntax,entry_name,expanded_name,\

                status)\

                *(status) = RpcNsEntryExpandName(name_syntax,entry_name,\

                expanded_name)

#define rpc_ns_entry_object_inq_begin(name_syntax,entry_name,\

                inquiry_context,status)\

                *(status) = RpcNsEntryObjectInqBegin(name_syntax,\

                entry_name,inquiry_context)

#define rpc_ns_entry_object_inq_done(inquiry_context,status) \

                *(status) = RpcNsEntryObjectInqDone(inquiry_context)

#define rpc_ns_entry_object_inq_next(inquiry_context,object_uuid,status) \

                *(status) = RpcNsEntryObjectInqNext(inquiry_context,\

                (UUID __RPC_FAR *)object_uuid)

#define rpc_ns_group_delete(name_syntax,group_name,status) \

                *(status) = RpcNsGroupDelete(name_syntax,group_name)

#define rpc_ns_group_mbr_add(name_syntax,group_name,member_name_syntax,\

                member_name,status) \

                *(status) = RpcNsGroupMbrAdd(name_syntax,group_name,\

                member_name_syntax,member_name)

#define rpc_ns_group_mbr_inq_begin(name_syntax,group_name,member_name_syntax,\

                inquiry_context,status) \

                *(status) = RpcNsGroupMbrInqBegin(name_syntax,group_name,\

                member_name_syntax,inquiry_context)

#define rpc_ns_group_mbr_inq_done(inquiry_context,status) \

                *(status) = RpcNsGroupMbrInqDone(inquiry_context)

#define rpc_ns_group_mbr_inq_next(inquiry_context,member_name,status) \

                *(status) = RpcNsGroupMbrInqNext(inquiry_context,member_name)

#define rpc_ns_group_mbr_remove(name_syntax,group_name,member_name_syntax,\

                member_name,status) \

                *(status) = RpcNsGroupMbrRemove(name_syntax,group_name,\

                member_name_syntax,member_name)

#define rpc_ns_mgmt_binding_unexport(name_syntax,entry_name,if_id,vers_option,\

                uuid_vector,status) \

                *(status) = RpcNsMgmtBindingUnexport(name_syntax,entry_name,\

                (RPC_IF_ID __RPC_FAR *)if_id,vers_option,\

                (UUID_VECTOR __RPC_FAR *)uuid_vector)

#define rpc_ns_mgmt_entry_create(name_syntax,entry_name,status) \

                *(status) = RpcNsMgmtEntryCreate(name_syntax,entry_name)

#define rpc_ns_mgmt_entry_delete(name_syntax,entry_name,status) \

                *(status) = RpcNsMgmtEntryDelete(name_syntax,entry_name)

#define rpc_ns_mgmt_entry_inq_if_ids(name_syntax,entry_name,if_id_vector,\

                status) \

                *(status) = RpcNsMgmtEntryInqIfIds(name_syntax,entry_name,\

                (RPC_IF_ID_VECTOR __RPC_FAR * __RPC_FAR *)if_id_vector)

#define rpc_ns_mgmt_handle_set_exp_age(ns_handle,expiration_age,status) \

                *(status) = RpcNsMgmtHandleSetExpAge(ns_handle,expiration_age)

#define rpc_ns_mgmt_inq_exp_age(expiration_age,status) \

                *(status) = RpcNsMgmtInqExpAge(expiration_age)

#define rpc_ns_mgmt_set_exp_age(expiration_age,status) \

                *(status) = RpcNsMgmtSetExpAge(expiration_age)

#define rpc_ns_profile_delete(name_syntax,profile_name,status) \

                *(status) = RpcNsProfileDelete(name_syntax,profile_name)

#define rpc_ns_profile_elt_add(name_syntax,profile_name,if_id,\

                member_name_syntax,member_name,priority,annotation,status) \

                *(status) = RpcNsProfileEltAdd(name_syntax,profile_name,\

                (RPC_IF_ID __RPC_FAR *)if_id,member_name_syntax,member_name,\

                priority,annotation)

#define rpc_ns_profile_elt_inq_begin(name_syntax,profile_name,inquiry_type,\

                if_id,if_vers_option,member_name_syntax,\

                member_name,inquiry_context,status) \

                *(status) = RpcNsProfileEltInqBegin(name_syntax,profile_name,\

                inquiry_type,(RPC_IF_ID __RPC_FAR *)if_id,if_vers_option,\

                member_name_syntax,member_name,inquiry_context)

#define rpc_ns_profile_elt_inq_done(inquiry_context,status) \

                *(status) = RpcNsProfileEltInqDone(inquiry_context)

#define rpc_ns_profile_elt_inq_next(inquiry_context,if_id,member_name,\

                priority,annotation,status) \

                *(status) = RpcNsProfileEltInqNext(inquiry_context,\

                (RPC_IF_ID __RPC_FAR *)if_id,member_name,priority,annotation)

#define rpc_ns_profile_elt_remove(name_syntax,profile_name,if_id,\

                member_name_syntax,member_name,status) \

                *(status) = RpcNsProfileEltRemove(name_syntax,profile_name,\

                (RPC_IF_ID __RPC_FAR *)if_id,member_name_syntax,member_name)

#define rpc_object_inq_type(object_uuid,type_uuid,status) \

                *(status) = RpcObjectInqType((UUID __RPC_FAR *)object_uuid,\

                (UUID __RPC_FAR *)type_uuid)

#define rpc_object_set_inq_fn(inq_fn,status) \

                *(status) = RpcObjectSetInqFn(inq_fn)

#define rpc_object_set_type(object_uuid,type_uuid,status) \

                *(status) = RpcObjectSetType((UUID __RPC_FAR *)object_uuid,\

                (UUID __RPC_FAR *)type_uuid)

#define rpc_protseq_vector_free(protseq_vector,status) \

                *(status) = RpcProtseqVectorFree( \

                (RPC_PROTSEQ_VECTOR __RPC_FAR * __RPC_FAR *)protseq_vector)

#define rpc_server_inq_bindings(binding_vector,status) \

                *(status) = RpcServerInqBindings(\

                (RPC_BINDING_VECTOR __RPC_FAR * __RPC_FAR *)binding_vector)

#define rpc_server_inq_if(if_spec,type_uuid,mgr_epv,status) \

                *(status) = RpcServerInqIf(if_spec,(UUID __RPC_FAR *)type_uuid,\

                (RPC_MGR_EPV __RPC_FAR *)mgr_epv)

#define rpc_server_listen(max_calls,status) \

                *(status) = RpcServerListen(rpc_c_listen_min_threads_default,\

                max_calls,0)

#define rpc_server_register_auth_info(princ_name,auth_svc,get_key_func,arg,\

                status) \

                *(status) = RpcServerRegisterAuthInfo(princ_name,auth_svc,\

                get_key_func,arg)

#define rpc_server_register_if(if_spec,type_uuid,mgr_epv,status) \

                *(status) = RpcServerRegisterIf(if_spec,\

                (UUID __RPC_FAR *)type_uuid,(RPC_MGR_EPV __RPC_FAR *)mgr_epv)

#define rpc_server_unregister_if(if_spec,type_uuid,status) \

                *(status) = RpcServerUnregisterIf(if_spec,(UUID *)type_uuid,0)

#define rpc_server_use_all_protseqs(max_call_requests,status) \

                *(status) = RpcServerUseAllProtseqs(max_call_requests,0)

#define rpc_server_use_all_protseqs_if(max_call_requests,if_spec,status) \

                *(status) = RpcServerUseAllProtseqsIf(max_call_requests,\

                if_spec,0)

#define rpc_server_use_protseq(protseq,max_call_requests,status) \

                *(status) = RpcServerUseProtseq(protseq,max_call_requests,0)

#define rpc_server_use_protseq_ep(protseq,max_call_requests,endpoint,status)\

                *(status) = RpcServerUseProtseqEp(protseq,max_call_requests,\

                endpoint,0)

#define rpc_server_use_protseq_if(protseq,max_call_requests,if_spec,status) \

                *(status) = RpcServerUseProtseqIf(protseq,max_call_requests,\

                if_spec,0)

#define rpc_sm_alloce(size,status) *(status) = RpcSmAllocate(size)

#define rpc_sm_client_free(ptr,status) *(status) = RpcSmClientFree(ptr)

#define rpc_sm_destroy_client_context(context,status) \

                *(status) = RpcSmDestroyClientContext(context)

#define rpc_sm_disable_allocate(status) *(status) = RpcSmDisableAllocate()

#define rpc_sm_enable_allocate(status) *(status) = RpcSmEnableAllocate()

#define rpc_sm_free(ptr,status) *(status) = RpcSmFree(ptr)

#define rpc_sm_get_thread_handle(status) RpcSmGetThreadHandle(status)

#define rpc_sm_set_client_alloc_free(alloc,free,status) \

                *(status) = RpcSmSetClientAllocFree(alloc,free)

#define rpc_sm_set_thread_handle(id,status) \

                *(status) = RpcSmSetThreadHandle(id)

#define rpc_sm_swap_client_alloc_free(alloc,free,old_alloc,old_free,status) \

                *(status) = RpcSmSwapClientAllocFree(alloc,free \

                old_alloc, old_free)

#define rpc_string_binding_compose(object_uuid,protseq,netaddr,endpoint,\

                options,binding,status) \

                *(status) = RpcStringBindingCompose(object_uuid,protseq,\

                netaddr,endpoint,options,binding)

#define rpc_string_binding_parse(string_binding,object_uuid,protseq,netaddr,\

                endpoint,options,status) \

                *(status) = RpcStringBindingParse(string_binding,\

                object_uuid,protseq,netaddr,endpoint,options)

#define rpc_string_free(string,status) *(status) = RpcStringFree(string)

#define uuid_compare(uuid1,uuid2,status) \

                UuidCompare((UUID __RPC_FAR *)(uuid1),\

                            (UUID __RPC_FAR *)(uuid2),(status))

#define uuid_create(uuid,status) \

                *(status) = UuidCreate((UUID __RPC_FAR *)uuid)

#define uuid_create_nil(uuid,status) \

                *(status) = UuidCreateNil((UUID __RPC_FAR *)uuid)

#define uuid_equal(uuid1,uuid2,status) \

                UuidEqual((UUID __RPC_FAR *)(uuid1), \

                          (UUID __RPC_FAR *)(uuid2), (status))

#define uuid_from_string(string,uuid,status) \

                *(status) = UuidFromString(string,(UUID __RPC_FAR *)uuid)

#define uuid_hash(uuid,status) \

                UuidHash((UUID __RPC_FAR *)(uuid),(status))

#define uuid_is_nil(uuid,status) \

                UuidIsNil((UUID __RPC_FAR *)(uuid), (status))

#define uuid_to_string(uuid,string,status)\

                *(status) = UuidToString((UUID __RPC_FAR *)uuid,string)

#define true  1

#define false 0

/*

** Define exception handling equivalents

**

*/

#if defined (__RPC_WIN16__) || defined (__RPC_DOS__)

#define TRY                                       \

    {                                                \

    int _exception_mode_finally;                     \

    int _exception_code;                             \

    ExceptionBuff exception;                         \

    _exception_code = RpcSetException(&exception);   \

    if (!_exception_code)                            \

    {

#define CATCH_ALL                                 \

        _exception_mode_finally = false;             \

        RpcLeaveException();                         \

        }                                            \

        else                                         \

        {

/*

 * #define CATCH(X)                               \

 *   }else if ((unsigned long)RpcExceptionCode()==(unsigned long)X) {

 */

#define FINALLY                                   \

        _exception_mode_finally = true;              \

        RpcLeaveException();                         \

        } {

#define ENDTRY                                    \

          }                                               \

        if (_exception_mode_finally && _exception_code)  \

            RpcRaiseException(_exception_code);           \

        }

#endif /* WIN16 or DOS */

#if defined (__RPC_WIN32__)

#define TRY             try {

/*

 * #define CATCH(X)        \

 *                      } except (GetExceptionCode() == X ? \

 *                        EXCEPTION_EXECUTE_HANDLER : \

 *                        EXCEPTION_CONTINUE_SEARCH) {

 */

#define CATCH_ALL       } except (EXCEPTION_EXECUTE_HANDLER) {

#define FINALLY         } finally {

#define ENDTRY          }

#endif /* WIN32 */

#define RAISE(v)   RpcRaiseException(v)

#define RERAISE    RpcRaiseException(RpcExceptionCode())

#define THIS_CATCH RpcExceptionCode()

/*

** DCE Status code mappings

*/

#ifndef rpc_s_ok

#define rpc_s_ok                        RPC_S_OK

#endif

#ifndef error_status_ok

#define error_status_ok                 RPC_S_OK

#endif

#define ept_s_cant_perform_op           EPT_S_CANT_PERFORM_OP

#define ept_s_invalid_entry             EPT_S_INVALID_ENTRY

#define ept_s_not_registered            EPT_S_NOT_REGISTERED

#define rpc_s_already_listening         RPC_S_ALREADY_LISTENING

#define rpc_s_already_registered        RPC_S_ALREADY_REGISTERED

#define rpc_s_binding_has_no_auth       RPC_S_BINDING_HAS_NO_AUTH

#define rpc_s_binding_imcomplete        RPC_S_BINDING_IMCOMPLETE

#define rpc_s_call_cancelled            RPC_S_CALL_CANCELLED

#define rpc_s_call_failed               RPC_S_CALL_FAILED

#define rpc_s_cant_bind_socket          RPC_S_CANNOT_BIND

#define rpc_s_cant_create_socket        RPC_S_CANT_CREATE_ENDPOINT

#define rpc_s_comm_failure              RPC_S_COMM_FAILURE

#define rpc_s_connect_no_resources      RPC_S_OUT_OF_RESOURCES

#define rpc_s_cthread_create_failed     RPC_S_OUT_OF_THREADS

#define rpc_s_endpoint_not_found        RPC_S_NO_ENDPOINT_FOUND

#define rpc_s_entry_already_exists      RPC_S_ENTRY_ALREADY_EXISTS

#define rpc_s_entry_not_found           RPC_S_ENTRY_NOT_FOUND

#define rpc_s_fault_addr_error          RPC_S_ADDRESS_ERROR

#define rpc_s_fault_fp_div_by_zero      RPC_S_FP_DIV_ZERO

#define rpc_s_fault_fp_overflow         RPC_S_FP_OVERFLOW

#define rpc_s_fault_fp_underflow        RPC_S_FP_UNDERFLOW

#define rpc_s_fault_int_div_by_zero     RPC_S_ZERO_DIVIDE

#define rpc_s_fault_invalid_bound       RPC_S_INVALID_BOUND

#define rpc_s_fault_invalid_tag         RPC_S_INVALID_TAG

#define rpc_s_fault_remote_no_memory    RPC_S_SERVER_OUT_OF_MEMORY

#define rpc_s_fault_unspec              RPC_S_CALL_FAILED

#define rpc_s_incomplete_name           RPC_S_INCOMPLETE_NAME

#define rpc_s_interface_not_found       RPC_S_INTERFACE_NOT_FOUND

#define rpc_s_internal_error            RPC_S_INTERNAL_ERROR

#define rpc_s_inval_net_addr            RPC_S_INVALID_NET_ADDR

#define rpc_s_invalid_arg               RPC_S_INVALID_ARG

#define rpc_s_invalid_binding           RPC_S_INVALID_BINDING

#define rpc_s_invalid_endpoint_format   RPC_S_INVALID_ENDPOINT_FORMAT

#define rpc_s_invalid_naf_id            RPC_S_INVALID_NAF_IF

#define rpc_s_invalid_name_syntax       RPC_S_INVALID_NAME_SYNTAX

#define rpc_s_invalid_rpc_protseq       RPC_S_INVALID_RPC_PROTSEQ

#define rpc_s_invalid_string_binding    RPC_S_INVALID_STRING_BINDING

#define rpc_s_invalid_timeout           RPC_S_INVALID_TIMEOUT

#define rpc_s_invalid_vers_option       RPC_S_INVALID_VERS_OPTION

#define rpc_s_max_calls_too_small       RPC_S_MAX_CALLS_TOO_SMALL

#define rpc_s_mgmt_op_disallowed        RPC_S_ACCESS_DENIED

#define rpc_s_name_service_unavailable  RPC_S_NAME_SERVICE_UNAVAILABLE

#define rpc_s_no_bindings               RPC_S_NO_BINDINGS

#define rpc_s_no_entry_name             RPC_S_NO_ENTRY_NAME

#define rpc_s_no_interfaces             RPC_S_NO_INTERFACES

#define rpc_s_no_interfaces_exported    RPC_S_NO_INTERFACES_EXPORTED

#define rpc_s_no_memory                 RPC_S_OUT_OF_MEMORY

#define rpc_s_no_more_elements          RPC_X_NO_MORE_ENTRIES

#define rpc_s_no_more_bindings          RPC_S_NO_MORE_BINDINGS

#define rpc_s_no_more_members           RPC_S_NO_MORE_MEMBERS

#define rpc_s_no_ns_permission          RPC_S_ACCESS_DENIED

#define rpc_s_no_princ_name             RPC_S_NO_PRINC_NAME

#define rpc_s_no_protseqs               RPC_S_NO_PROTSEQS

#define rpc_s_no_protseqs_registered    RPC_S_NO_PROTSEQS_REGISTERED

#define rpc_s_not_rpc_tower             RPC_S_CANNOT_SUPPORT

#define rpc_s_not_supported             RPC_S_CANNOT_SUPPORT

#define rpc_s_not_authorized            RPC_S_ACCESS_DENIED

#define rpc_s_nothing_to_unexport       RPC_S_NOTHING_TO_UNEXPORT

#define rpc_s_object_not_found          RPC_S_OBJECT_NOT_FOUND

#define rpc_s_protocol_error            RPC_S_PROTOCOL_ERROR

#define rpc_s_protseq_not_supported     RPC_S_PROTSEQ_NOT_SUPPORTED

#define rpc_s_server_too_busy           RPC_S_SERVER_TOO_BUSY

#define rpc_s_string_too_long           RPC_S_STRING_TOO_LONG

#define rpc_s_type_already_registered   RPC_S_TYPE_ALREADY_REGISTERED

#define rpc_s_unknown_authn_service     RPC_S_UNKNOWN_AUTHN_SERVICE

#define rpc_s_unknown_authz_service     RPC_S_UNKNOWN_AUTHZ_SERVICE

#define rpc_s_unknown_if                RPC_S_UNKNOWN_IF

#define rpc_s_unknown_mgr_type          RPC_S_UNKNOWN_MGR_TYPE

#define rpc_s_unknown_reject            RPC_S_CALL_FAILED_DNE

#define rpc_s_unsupported_name_syntax   RPC_S_UNSUPPORTED_NAME_SYNTAX

#define rpc_s_unsupported_type          RPC_S_UNSUPPORTED_TYPE

#define rpc_s_wrong_boot_time           RPC_S_CALL_FAILED_DNE

#define rpc_s_wrong_kind_of_binding     RPC_S_WRONG_KIND_OF_BINDING

#define uuid_s_ok                       RPC_S_OK

#define uuid_s_internal_error           RPC_S_INTERNAL_ERROR

#define uuid_s_invalid_string_uuid      RPC_S_INVALID_STRING_UUID

#define uuid_s_no_address               RPC_S_UUID_NO_ADDRESS

/*

** DCE Exception mappings

*/

#define rpc_x_comm_failure              RPC_S_COMM_FAILURE

#define rpc_x_connect_no_resources      RPC_S_OUT_OF_RESOURCES

#define rpc_x_entry_not_found           RPC_S_ENTRY_NOT_FOUND

#define rpc_x_incomplete_name           RPC_S_INCOMPLETE_NAME

#define rpc_x_invalid_arg               RPC_S_INVALID_ARG

#define rpc_x_invalid_binding           RPC_S_INVALID_BINDING

#define rpc_x_invalid_bound             RPC_X_INVALID_BOUND

#define rpc_x_invalid_endpoint_format   RPC_S_INVALID_ENDPOINT_FORMAT

#define rpc_x_invalid_naf_id            RPC_S_INVALID_NAF_IF

#define rpc_x_invalid_name_syntax       RPC_S_INVALID_NAME_SYNTAX

#define rpc_x_invalid_rpc_protseq       RPC_S_INVALID_RPC_PROTSEQ

#define rpc_x_invalid_tag               RPC_X_INVALID_TAG

#define rpc_x_invalid_timeout           RPC_S_INVALID_TIMEOUT

#define rpc_x_no_memory                 RPC_X_NO_MEMORY

#define rpc_x_object_not_found          RPC_S_OBJECT_NOT_FOUND

#define rpc_x_protocol_error            RPC_S_PROTOCOL_ERROR

#define rpc_x_protseq_not_supported     RPC_S_PROTSEQ_NOT_SUPPORTED

#define rpc_x_server_too_busy           RPC_S_SERVER_TOO_BUSY

#define rpc_x_ss_char_trans_open_fail   RPC_X_SS_CHAR_TRANS_OPEN_FAIL

#define rpc_x_ss_char_trans_short_file  RPC_X_SS_CHAR_TRANS_SHORT_FILE

#define rpc_x_ss_context_damaged        RPC_X_SS_CONTEXT_DAMAGED

#define rpc_x_ss_context_mismatch       RPC_X_SS_CONTEXT_MISMATCH

#define rpc_x_ss_in_null_context        RPC_X_SS_IN_NULL_CONTEXT

#define rpc_x_string_too_long           RPC_S_STRING_TOO_LONG

#define rpc_x_unknown_if                RPC_S_UNKNOWN_IF

#define rpc_x_unknown_mgr_type          RPC_S_UNKNOWN_MGR_TYPE

#define rpc_x_unsupported_name_syntax   RPC_S_UNSUPPORTED_NAME_SYNTAX

#define rpc_x_unsupported_type          RPC_S_UNSUPPORTED_TYPE

#define rpc_x_wrong_boot_time           RPC_S_CALL_FAILED_DNE

#define rpc_x_wrong_kind_of_binding     RPC_S_WRONG_KIND_OF_BINDING

#define uuid_x_internal_error           RPC_S_INTERNAL_ERROR

#ifdef __cplusplus

}

#endif

#endif /* DCEPORT_H */


 CLIENT.C   (INTEROP RPC Sample)

/*************************************************************/

/**                                                         **/

/**                 Microsoft RPC Examples                  **/

/**                 OSF DCE Sample Application              **/

/**             Copyright(c) Microsoft Corp. 1992           **/

/**                                                         **/

/*************************************************************/

#include <stdlib.h>

#include <stdio.h>

#include <string.h>

#include <ctype.h>

#include "msg.h"        /* header file generated by M/IDL compiler */

#if defined(__RPC_WIN32__) || defined(__RPC_DOS__)

/*

 On MS platforms we must include the dceport.h header file

 which maps OSF DCE style APIs to MS style APIs.

*/

#include "dceport.h"

#else

#include <pthread.h>

#endif

#ifndef _CRTAPI1

#define _CRTAPI1

#endif

void Usage()

{

  printf("Usage : client -n <server_name>\n");

  printf("               -t <transport>   - optional, default ncacn_ip_tcp\n");

  printf("               -e <endpoint>    - optional, should match server\n");

  printf("               -s <message>     - optional, send a different message\n");

  printf("               -x               - use to stop the server\n");

  exit(1);

}

int _CRTAPI1

main(int argc, char *argv[])

{

    unsigned32 status;

    unsigned char * pszProtocolSequence = (unsigned char *)"ncacn_ip_tcp";

    unsigned char * pszNetworkAddress   = NULL;

    unsigned char * pszEndpoint         = NULL;

    unsigned char * pszStringBinding    = NULL;

    unsigned char * pszMessage          = (unsigned char *)"Hello World";

    int fStopServer = 0;

    int i;

    printf ("Microsoft RPC Demo - OSF DCE Interop Message Client\n");

    for (i = 1; i < argc; i++) {

        if ((*argv[i] == '-') || (*argv[i] == '/')) {

            switch (tolower(*(argv[i]+1))) {

            case 'n':  /* network address */

                pszNetworkAddress = (unsigned char *)argv[++i];

                break;

            case 't':  /* protocol sequence */

                pszProtocolSequence = (unsigned char *)argv[++i];

                break;

            case 'e':  /* network endpoint */

                pszEndpoint = (unsigned char *)argv[++i];

                break;

            case 's':  /* update message */

                pszMessage = (unsigned char *)argv[++i];

                break;

            case 'x':  /* stop the server */

                fStopServer = 1;

                break;

            case 'h':

            case '?':

            default:

                Usage();

            }

        }

        else

            Usage();

    }

    rpc_string_binding_compose(0,   /* no object uuid */

                               pszProtocolSequence,

                               pszNetworkAddress,

                               pszEndpoint,

                               0,  /* no options */

                               &pszStringBinding,

                               &status);

    if (status) {

        printf("rpc_string_binding_compose returned 0x%x\n", status);

        return(status);

    }

    rpc_binding_from_string_binding(pszStringBinding,

                                    &interop_binding_handle,

                                    &status);

    if (status) {

        printf("rpc_binding_from_string_binding returned 0x%x\n", status);

        return(status);

    }

    rpc_string_free(&pszStringBinding,&status);

    if (status) {

        printf("rpc_string_free returned 0x%x\n", status);

        return(status);

    }

    TRY {

       ClientMessage(pszMessage);

       printf("Message sent okay\n");

       if (fStopServer)

           {

           ShutdownServer();

           printf("Server shutdown\n");

           }

    }

    CATCH_ALL {

       printf("RPC raised exception 0x%x\n", THIS_CATCH);

    }

    ENDTRY

    rpc_binding_free(&interop_binding_handle, &status);

    if (status) {

        printf("rpc_binding_free returned 0x%x\n", status);

        return(status);

    }

    return(0);

}


 MANAGER.C   (INTEROP RPC Sample)

/*************************************************************/

/**                                                         **/

/**                 Microsoft RPC Examples                  **/

/**                 OSF DCE Interop Application             **/

/**             Copyright(c) Microsoft Corp. 1993           **/

/**                                                         **/

/*************************************************************/

#include <stdio.h>

#include "msg.h"    /* header file generated by M/IDL compiler */

#if defined(__RPC_WIN32__) || defined(__RPC_DOS__)

#include "dceport.h"

#endif

/*

 * Print out client messages

 */

void ClientMessage(unsigned char *message)

{

    printf("%s\n", message);

    return;

}

/*

 * The client can stop the server by calling this operation.

 */

void ShutdownServer()

{

    unsigned32 status;

    rpc_mgmt_stop_server_listening(0, &status);

    if (status)

        {

        printf("rpc_mgmt_stop_server_listening returns 0x%x\n", status);

        }

    return;

}


 MIDLUSER.C   (INTEROP RPC Sample)

/*************************************************************/

/**                                                         **/

/**                 Microsoft RPC Examples                  **/

/**            OSF DCE Interop Sample Application           **/

/**             Copyright(c) Microsoft Corp. 1993           **/

/**                                                         **/

/*************************************************************/

#include <stdlib.h>

#include "msg.h"

/*

 * These are used in Microsoft clients and servers for stub memory allocation

 */

void __RPC_FAR * __RPC_USER MIDL_user_allocate(size_t size)

{

    return malloc(size);

}

void __RPC_USER MIDL_user_free(void __RPC_FAR *p)

{

    free(p);

}


 SERVER.C   (INTEROP RPC Sample)

/*************************************************************/

/**                                                         **/

/**                 Microsoft RPC Examples                  **/

/**                 OSF DCE Interop Application             **/

/**             Copyright(c) Microsoft Corp. 1993           **/

/**                                                         **/

/*************************************************************/

#include <stdlib.h>

#include <stdio.h>

#include <ctype.h>

#include "msg.h"    /* header file generated by M/IDL compiler */

#if defined(__RPC_WIN32__) || defined(__RPC_DOS__)

/*

 On MS platforms we must include the dceport.h header file

 which maps OSF DCE style APIs to MS style APIs.

 Currently, we must also define a common interface handle name.

*/

#include "dceport.h"

#else

#include <pthread.h>

#endif

#ifndef _CRTAPI1

#define _CRTAPI1

#endif

void Usage()

{

  printf("Usage : server -e <endpoint>   - optional endpoint\n");

  printf("               -t <transport>  - optional, default ncacn_ip_tcp\n");

  exit(1);

}

int _CRTAPI1

main(int argc, char *argv[])

{

    unsigned32 status;

    unsigned char * pszProtocolSequence = (unsigned char *)"ncacn_ip_tcp";

    unsigned char * pszEndpoint         = NULL;

    unsigned int    cMaxCalls           = 20;

    rpc_binding_vector_p_t pbvBindings  = NULL;

    int i;

    printf ("Microsoft RPC Demo - OSF DCE Interop Message Server\n");

    for (i = 1; i < argc; i++) {

        if ((*argv[i] == '-') || (*argv[i] == '/')) {

            switch (tolower(*(argv[i]+1))) {

            case 'e':

                pszEndpoint = (unsigned char *)argv[++i];

                break;

            case 't':

                pszProtocolSequence = (unsigned char *)argv[++i];

                break;

            case 'h':

            case '?':

            default:

                Usage();

            }

        }

        else

            Usage();

    }

    if (pszEndpoint != NULL)

        {

        /*

         Since we have an explict endpoint, use it and

         wait for client requests.

        */

        rpc_server_use_protseq_ep(pszProtocolSequence,

                                   cMaxCalls,

                                   pszEndpoint,

                                   &status);

        if (status) {

            printf("rpc_server_use_protseq_ep returned 0x%x\n", status);

            return status;

            }

        }

    else

        {

        /*

         No explict endpoint, use the protocol sequence and register

         the endpoint with the endpoint mapper.

        */

        rpc_server_use_protseq(pszProtocolSequence,

                               cMaxCalls,

                               &status);

        if (status) {

            printf("rpc_server_use_protseq returned 0x%x\n", status);

            return status;

            }

        rpc_server_inq_bindings(&pbvBindings, &status);

        if (status) {

            printf("rpc_server_inq_bindings returned 0x%x\n", status);

            return status;

            }

        rpc_ep_register(interop_v1_0_s_ifspec,

                        pbvBindings,

                        0,

                        0,

                        &status);

        if (status) {

            printf("rpc_ep_register returned 0x%x\n", status);

            return status;

            }

        }

    rpc_server_register_if(interop_v1_0_s_ifspec,

                           0,

                           0,

                           &status);

    if (status) {

        printf("rpc_server_register_if returned 0x%x\n", status);

        return status;

    }

    printf("RPC server ready\n");

    rpc_server_listen(cMaxCalls,&status);

    if (status) {

        printf("rpc_server_listen returned: 0x%x\n", status);

        return status;

    }

    rpc_server_unregister_if(interop_v1_0_s_ifspec,

                             0,

                             &status);

    if (status) {

        printf("rpc_server_unregister_if returned 0x%x\n", status);

        return status;

    }

    if (pszEndpoint == NULL)

        {

        /*

         Unregister from endpoint mapper

         */

        rpc_ep_unregister(interop_v1_0_s_ifspec,

                          pbvBindings,

                          0,

                          &status);

        if (status) {

            printf("rpc_ep_unregister returned 0x%x\n", status);

            return status;

            }

        rpc_binding_vector_free(&pbvBindings, &status);

        if (status) {

            printf("rpc_binding_vector_free returned 0x%x\n", status);

            return status;

            }

        }

}


 CLUUID

This directory contains the files for the sample distributed application "cluuid":

File          Description

README.TXT    Readme file for the cluuid sample CLUUID.IDL    Interface definition language file CLUUID.ACF    Attribute configuration file CLUUIDC.C     Client main program CLUUIDS.C     Server main program CLUUIDP.C     Remote procedures MAKEFILE      Nmake file to build for NT MAKEFILE.DOS  Nmake file to build for MS-DOS

This sample program demonstrates how to supply multiple implementations of the remote procedure specified in the interface.  It also demonstrates how the client selects among the implementations by providing a client object uuid.

The server calls RpcObjectSetType to associate a client object uuid with the object uuid in the Object Registry Table. The server initializes a manager entry point vector (manager epv) and then calls RpcRegisterIf to associate the interface uuid and the object uuid with the manager epv in the Interface Registry Table.

When the client makes a remote procedure call, the client object uuid is mapped to the object uuid in the Object Registry Table.  The resulting object uuid and the interface uuid are mapped to a manager entry point vector in the Interface Registry Table.

By default, in this example, the server registers two implementations of the "hello, world" function HelloProc and HelloProc2.  The HelloProc2 implementation is associated with the object uuid "11111111-1111-1111-1111-111111111111". When the client makes a procedure call with a null uuid, the client's request is mapped to the original HelloProc.  When the client makes a procedure call with the client object uuid "11111111-1111-1111-1111-11111111111", the client's request is mapped to HelloProc2 (which prints the string in reverse).

------------------------------------------- BUILDING CLIENT AND SERVER APPLICATIONS FOR MICROSOFT WINDOWS NT: -------------------------------------------

The following environment variables should be set for you already.              set CPU=i386
  set INCLUDE=c:\mstools\h
  set LIB=c:\mstools\lib
  set PATH=c:\winnt\system32;c:\mstools\bin;

For mips, set CPU=mips                                                        For alpha, set CPU=alpha
Build the sample distributed application:

  nmake cleanall
  nmake

This builds the executable programs cluuidc.exe (client) and cluuids.exe (server).

----------------------------------------------------------------------- BUILDING THE CLIENT APPLICATION FOR MS-DOS -----------------------------------------------------------------------

After installing the Microsoft Visual C/C++ version 1.50 development  environment and the Microsoft RPC version 2.0 toolkit on a Windows NT computer, you can build the sample client application from Windows NT.

  nmake -f makefile.dos cleanall
  nmake -f makefile.dos

This builds the client application cluuidc.exe.

You may also execute the Microsoft Visual C/C++ compiler under MS-DOS. This requires a two step build process.

  Step One: Compile the .IDL files under Windows NT
     nmake -a -f makefile.dos cluuid.h

  Step Two: Compile the C sources (stub and application) under MS-DOS
     nmake -f makefile.dos

------------------------------------------ RUNNING THE CLIENT AND SERVER APPLICATIONS ------------------------------------------

On the server, enter

  cluuids

On the client, enter

  net start workstation
  cluuidc

To call the second implementation of the function, on the client, enter

  cluuidc -u "11111111-1111-1111-1111-111111111111"

Note:  The client and server applications can run on the same Microsoft Windows NT computer when you use different screen groups.

Several command line switches are available to change settings for this program. For a listing of the switches available from the client program, enter

  cluuidc -?

For a listing of switches available from the server  program, enter

  cluuids -?


 MAKEFILE   (CLUUID RPC Sample)

#*************************************************************#

#**                                                         **#

#**                 Microsoft RPC Examples                  **#

#**                   cluuid Application                    **#

#**            Copyright(c) Microsoft Corp. 1992            **#

#**                                                         **#

#*************************************************************#

!include <ntwin32.mak>

all : cluuidc cluuids

# Make the client side application cluuidc

cluuidc : cluuidc.exe

cluuidc.exe : cluuidc.obj cluuid_c.obj

    $(link) $(linkdebug) $(conflags) -out:cluuidc.exe \

      cluuidc.obj cluuid_c.obj \

      rpcrt4.lib $(conlibs)

# cluuidc main program

cluuidc.obj : cluuidc.c cluuid.h

   $(cc) $(cdebug) $(cflags) $(cvars) $*.c

# cluuidc stub

cluuid_c.obj : cluuid_c.c cluuid.h

   $(cc) $(cdebug) $(cflags) $(cvars) $*.c

# Make the server side application

cluuids : cluuids.exe

cluuids.exe : cluuids.obj cluuidp.obj cluuid_s.obj

    $(link) $(linkdebug) $(conflags) -out:cluuids.exe \

      cluuids.obj cluuid_s.obj cluuidp.obj \

      rpcrt4.lib $(conlibsmt)

# cluuid server main program

cluuids.obj : cluuids.c cluuid.h

   $(cc) $(cdebug) $(cflags) $(cvarsmt) $*.c

# remote procedures

cluuidp.obj : cluuidp.c cluuid.h

   $(cc) $(cdebug) $(cflags) $(cvarsmt) $*.c

# cluuids stub file

cluuid_s.obj : cluuid_s.c cluuid.h

   $(cc) $(cdebug) $(cflags) $(cvarsmt) $*.c

# Stubs and header file from the IDL file

cluuid.h cluuid_c.c cluuid_s.c : cluuid.idl cluuid.acf

    midl -oldnames -use_epv -no_cpp cluuid.idl

# Clean up everything

cleanall : clean

    -del *.exe

# Clean up everything but the .EXEs

clean :

    -del *.obj

    -del *.map

    -del cluuid_c.c

    -del cluuid_s.c

    -del cluuid.h


 CLUUIDC.C   (CLUUID RPC Sample)

/****************************************************************************

                   Microsoft RPC Version 2.0

           Copyright Microsoft Corp. 1992, 1993, 1994

                       Cluuid Example

    FILE:        cluuidc.c

    USAGE:       cluuidc  -n network_address

                          -p protocol_sequence

                          -e endpoint

                          -o options

                          -s string_displayed_on_server

                          -u client object uuid

    PURPOSE:     Client side of RPC distributed application

    FUNCTIONS:   main() - binds to server and calls remote procedure

    COMMENTS:    This distributed application prints a string such as

                 "hello, world" on the server. The client manages its

                 connection to the server. The client uses the implicit

                 binding handle ImpHandle defined in the file cluuid.h.

****************************************************************************/

#include <stdio.h>

#include <stdlib.h>

#include <ctype.h>

#include "cluuid.h"    // header file generated by MIDL compiler

void Usage(char * pszProgramName)

{

    fprintf(stderr, "Usage:  %s\n", pszProgramName);

    fprintf(stderr, " -p protocol_sequence\n");

    fprintf(stderr, " -n network_address\n");

    fprintf(stderr, " -e endpoint\n");

    fprintf(stderr, " -o options\n");

    fprintf(stderr, " -s string\n");

    fprintf(stderr, " -u uuid\n");

    exit(1);

}

void _CRTAPI1 main(int argc, char **argv)

{

    RPC_STATUS status;

    unsigned char * pszUuid             = NULL;

    unsigned char * pszProtocolSequence = "ncacn_np";

    unsigned char * pszNetworkAddress   = NULL;

    unsigned char * pszEndpoint         = "\\pipe\\cluuid";

    unsigned char * pszOptions          = NULL;

    unsigned char * pszStringBinding    = NULL;

    unsigned char * pszString           = "hello, world";

    unsigned long ulCode;

    int i;

    /* allow the user to override settings with command line switches */

    for (i = 1; i < argc; i++) {

        if ((*argv[i] == '-') || (*argv[i] == '/')) {

            switch (tolower(*(argv[i]+1))) {

            case 'p':  // protocol sequence

                pszProtocolSequence = argv[++i];

                break;

            case 'n':  // network address

                pszNetworkAddress = argv[++i];

                break;

            case 'e':

                pszEndpoint = argv[++i];

                break;

            case 'o':

                pszOptions = argv[++i];

                break;

            case 's':

                pszString = argv[++i];

                break;

            case 'u':

                pszUuid = argv[++i];

                break;

            case 'h':

            case '?':

            default:

                Usage(argv[0]);

            }

        }

        else

            Usage(argv[0]);

    }

    /* Use a convenience function to concatenate the elements of  */

    /* the string binding into the proper sequence.               */

    status = RpcStringBindingCompose(pszUuid,

                                     pszProtocolSequence,

                                     pszNetworkAddress,

                                     pszEndpoint,

                                     pszOptions,

                                     &pszStringBinding);

    printf("RpcStringBindingCompose returned 0x%x\n", status);

    printf("pszStringBinding = %s\n", pszStringBinding);

    if (status) {

        exit(status);

    }

    /* Set the binding handle that will be used to bind to the server. */

    status = RpcBindingFromStringBinding(pszStringBinding,

                                         &ImpHandle);

    printf("RpcBindingFromStringBinding returned 0x%x\n", status);

    if (status) {

        exit(status);

    }

    printf("Calling the remote procedure 'HelloProc'\n");

    printf("  print the string '%s' on the server\n", pszString);

    RpcTryExcept {

        HelloProc(pszString);  /* make call with user message */

        printf("Calling the remote procedure 'Shutdown'\n");

        Shutdown();             // shut down the server side

    }

    RpcExcept(1) {

        ulCode = RpcExceptionCode();

        printf("Runtime reported exception 0x%lx = %ld\n", ulCode, ulCode);

    }

    RpcEndExcept

    /*  The calls to the remote procedures are complete. */

    /*  Free the string and the binding handle           */

    status = RpcStringFree(&pszStringBinding);  // remote calls done; unbind

    printf("RpcStringFree returned 0x%x\n", status);

    if (status) {

        exit(status);

    }

    status = RpcBindingFree(&ImpHandle);  // remote calls done; unbind

    printf("RpcBindingFree returned 0x%x\n", status);

    if (status) {

        exit(status);

    }

    exit(0);

}

/*********************************************************************/

/*                 MIDL allocate and free                            */

/*********************************************************************/

void __RPC_FAR * __RPC_USER midl_user_allocate(size_t len)

{

    return(malloc(len));

}

void __RPC_USER midl_user_free(void __RPC_FAR * ptr)

{

    free(ptr);

}

/* end file cluuidc.c */


 CLUUIDP.C   (CLUUID RPC Sample)

/****************************************************************************

                   Microsoft RPC Version 2.0

           Copyright Microsoft Corp. 1992, 1993, 1994

                         Cluuid Example

    FILE:       cluuidp.c

    PURPOSE:    Remote procedures that are linked with the server

                side of RPC distributed application

    FUNCTIONS:  HelloProc() - prints "hello, world" or other string

                HelloProc2() - prints string backwards

    COMMENTS:   This sample program demonstrates how to supply

                multiple implementations of the remote procedure

                specified in the interface. It also demonstrates

                how the client selects among the implementations

                by providing a client object uuid.

                The server calls RpcObjectSetType to associate a

                client object uuid with the object uuid in the

                Object Registry Table. The server initializes a

                manager entry point vector (manager epv) and

                then calls RpcRegisterIf to associate the interface

                uuid and the object uuid with the manager epv in the

                Interface Registry Table.

                When the client makes a remote procedure call,

                the client object uuid is mapped to the object uuid

                in the Object Registry Table. The resulting

                object uuid and the interface uuid are mapped to

                a manager entry point vector in the Interface

                Registry Table.

                By default, in this example, the server registers

                two implementations of the "hello, world" function

                HelloProc and HelloProc2.  The HelloProc2

                implementation is associated with the object uuid

                "11111111-1111-1111-1111-111111111111". When

                the client makes a procedure call with a null

                uuid, the client's request is mapped to the

                original HelloProc.  When the client makes a

                procedure call with the client object uuid

                "11111111-1111-1111-1111-11111111111", the

                client's request is mapped to HelloProc2 (which

                prints the string in reverse).

****************************************************************************/

#include <stdlib.h>

#include <stdio.h>

#include <string.h>

#include "cluuid.h"    // header file generated by MIDL compiler

void HelloProc(unsigned char * pszString)

{

    printf("%s\n", pszString);

}

void HelloProc2(unsigned char * pszString)

{

    printf("%s\n", strrev(pszString));

}

void Shutdown(void)

{

    RPC_STATUS status;

    printf("Calling RpcMgmtStopServerListening\n");

    status = RpcMgmtStopServerListening(NULL);

    printf("RpcMgmtStopServerListening returned: 0x%x\n", status);

    if (status) {

        exit(status);

    }

    printf("Calling RpcServerUnregisterIf\n");

    status = RpcServerUnregisterIf(NULL, NULL, FALSE);

    printf("RpcServerUnregisterIf returned 0x%x\n", status);

    if (status) {

        exit(status);

    }

}

/* end of file cluuidp.c */


 CLUUIDS.C   (CLUUID RPC Sample)

/****************************************************************************

                   Microsoft RPC Version 2.0

           Copyright Microsoft Corp. 1992, 1993, 1994

                      Cluuid Example

    FILE:       cluuids.c

    USAGE:      cluuids  -p protocol_sequence

                         -e endpoint

                         -m max calls

                         -n min calls

                         -f flag for RpcServerListen

                         -1 client object uuid

                         -2 manager epv uuid

    PURPOSE:    Server side of RPC distributed application hello

    FUNCTIONS:  main() - registers server as RPC server

    COMMENTS:   Print "hello, world" on the server.

                When you supply a type UUID, the client must

                supply the same UUID.

****************************************************************************/

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <ctype.h>

#include "cluuid.h"    // header file generated by MIDL compiler

// the second implementation of the remote procedure

extern void HelloProc2(unsigned char * pszString);

#define PURPOSE \

"This Microsoft RPC Version 2.0 sample program demonstrates how\n\

to supply multiple implementations of the remote procedure\n\

specified in the interface. It also demonstrates how the client\n\

selects among the implementations by providing a client object uuid.\n\n"

#define NULL_UUID_STRING "00000000-0000-0000-0000-000000000000"

void Usage(char * pszProgramName)

{

    fprintf(stderr, "%s", PURPOSE);

    fprintf(stderr, "Usage:  %s\n", pszProgramName);

    fprintf(stderr, " -p protocol_sequence\n");

    fprintf(stderr, " -e endpoint\n");

    fprintf(stderr, " -m maxcalls\n");

    fprintf(stderr, " -n mincalls\n");

    fprintf(stderr, " -f flag_wait_op\n");

    fprintf(stderr, " -1 client uuid\n");

    fprintf(stderr, " -2 manager uuid\n");

    exit(1);

}

/* main:  register the interface, start listening for clients */

void _CRTAPI1 main(int argc, char * argv[])

{

    RPC_STATUS status;

    UUID MgrTypeUuid, ClientUuid;

    unsigned char * pszProtocolSequence = "ncacn_np";

    unsigned char * pszSecurity         = NULL;

    unsigned char * pszClientUuid       = NULL_UUID_STRING;

    unsigned char * pszMgrTypeUuid      = "11111111-1111-1111-1111-111111111111";

    unsigned char * pszEndpoint         = "\\pipe\\cluuid";

    unsigned int    cMinCalls           = 1;

    unsigned int    cMaxCalls           = 20;

    unsigned int    fDontWait           = FALSE;

    int i;

    cluuid_SERVER_EPV epv2;    // the mgr_epv for the 2nd implementation

    /* allow the user to override settings with command line switches */

    for (i = 1; i < argc; i++) {

        if ((*argv[i] == '-') || (*argv[i] == '/')) {

            switch (tolower(*(argv[i]+1))) {

            case 'p':  // protocol sequence

                pszProtocolSequence = argv[++i];

                break;

            case 'e':

                pszEndpoint = argv[++i];

                break;

            case 'm':

                cMaxCalls = (unsigned int) atoi(argv[++i]);

                break;

            case 'n':

                cMinCalls = (unsigned int) atoi(argv[++i]);

                break;

            case 'f':

                fDontWait = (unsigned int) atoi(argv[++i]);

                break;

            case '1':

                pszMgrTypeUuid = argv[++i];

                break;

            case '2':

                pszClientUuid = argv[++i];

                break;

            case 'h':

            case '?':

            default:

                Usage(argv[0]);

            }

        }

        else

            Usage(argv[0]);

    }

    status = RpcServerUseProtseqEp(pszProtocolSequence,

                                   cMaxCalls,

                                   pszEndpoint,

                                   pszSecurity);  // Security descriptor

    printf("RpcServerUseProtseqEp returned 0x%x\n", status);

    if (status) {

        exit(status);

    }

    status = UuidFromString(pszClientUuid, &ClientUuid);

    printf("UuidFromString returned 0x%x = %d\n", status, status);

    if (status) {

        exit(status);

    }

    status = UuidFromString(pszMgrTypeUuid, &MgrTypeUuid);

    printf("UuidFromString returned 0x%x = %d\n", status, status);

    if (status) {

        exit(status);

    }

    if (strcmp (pszMgrTypeUuid, NULL_UUID_STRING) == 0) {

        printf("Register object using non-null uuid %s\n", pszMgrTypeUuid);

        exit(1);

    }

    if (strcmp (pszClientUuid, NULL_UUID_STRING) == 0) {

        printf("Register object using non-null uuid %s\n", pszMgrTypeUuid);

        ClientUuid = MgrTypeUuid;

    }

    RpcObjectSetType(&ClientUuid, &MgrTypeUuid);  // associate type UUID with nil UUID

    printf("RpcObjectSetType returned 0x%x\n", status);

    if (status) {

        exit(status);

    }

    status = RpcServerRegisterIf(cluuid_ServerIfHandle, // interface to register

                                 NULL,   // MgrTypeUuid

                                 NULL);  // MgrEpv; null means use default

    printf("RpcServerRegisterIf returned 0x%x\n", status);

    if (status) {

        exit(status);

    }

    /* register the second manager epv and associate it with the

       specified uuid.  the second uuid must be non-null so that

       it will not conflict with the NULL uuid already registered

       for this interface

    */

    epv2.HelloProc = HelloProc2;

    epv2.Shutdown = Shutdown;

    status = RpcServerRegisterIf(cluuid_ServerIfHandle, // interface to register

                                 &MgrTypeUuid,  // MgrTypeUuid

                                 &epv2);        // 2nd manager epv

    printf("RpcServerRegisterIf returned 0x%x\n", status);

    if (status) {

        exit(status);

    }

    printf("Calling RpcServerListen\n");

    status = RpcServerListen(cMinCalls,

                             cMaxCalls,

                             fDontWait);

    printf("RpcServerListen returned: 0x%x\n", status);

    if (status) {

        exit(status);

    }

    if (fDontWait) {

        printf("Calling RpcMgmtWaitServerListen\n");

        status = RpcMgmtWaitServerListen();  //  wait operation

        printf("RpcMgmtWaitServerListen returned: 0x%x\n", status);

        if (status) {

            exit(status);

        }

    }

} // end main()

/*********************************************************************/

/*                 MIDL allocate and free                            */

/*********************************************************************/

void __RPC_FAR * __RPC_USER midl_user_allocate(size_t len)

{

    return(malloc(len));

}

void __RPC_USER midl_user_free(void __RPC_FAR * ptr)

{

    free(ptr);

}

/* end file cluuids.c */


Copyright Notice

This document is provided for informational purposes only, and Microsoft Corporation makes no warranties, either express or implied, in this document. The entire risk of the use or the results of the use of this document remains with the user. Companies, names, and data used in examples herein are fictitious unless otherwise noted. No part of this document may be reproduced or transmitted in any form or by any means, electronic or mechanical, for any purpose, without the express written permission of Microsoft Corporation.

© 1995 Microsoft Corporation. Portions Copyright Intel/Microsoft 1992-93. All Rights Reserved.


Introduction

The Microsoft Windows Telephony application programming interface (API) provides services that enable an application developer to add telephone communications to applications developed for the Microsoft Win32 (API). This guide is intended to help experienced programmers learn the application programming interface for Telephony under the Windows operating system.

This document is intended to be used by developers familiar with the Win32 programming environment. Previous development experience with telecommunications or other telephony applications is helpful but not necessary.


Document Overview

This guide presents general information about how to develop telephonic applications and offers specific information about the functions, messages, and data types of the Telephony API (TAPI). Following the introduction, this guide is divided into three parts:

Part I, "Telephony Basics", describes what Windows Telephony is, how it can be used within Windows applications, and how to use the Software Development Kit (SDK).

•	Chapter 1, "Overview of Telephony", explains Windows Telephony's position within the Windows Open Services Architecture (WOSA) environment and describes the TAPI programming model.

•	Chapter 2, "The Telephony Programming Model", explains the concepts programmers should know before they begin development of telephonic applications. It includes sections that describe the uses of Assisted Telephony, Telephony's device classes, addresses, and other topics.

•	Chapter 3, "Programming Telephony Applications: Getting Started", outlines the elements of the Windows Telephony SDK.

•	Chapter 4, "Programming with Assisted Telephony", tells how to add basic telephonic functionality to applications that don't require the flexibility or control provided by the full Telephony API. This chapter also provides a complete listing of the Assisted Telephony functions, messages, and data types. Readers whose development goals do not include the creation of new applications with a variety of telephonic functions may need to read no further than this chapter.

Part II, "Telephony Programmer's Guide", explains the concepts associated with developing Telephony functionality within applications.

•	Chapter 5, "Concepts of Line Devices," explains one of the two device classes defined by TAPI: the line device. (The data functions, data types, and messages for the other device class, the phone device, are detailed in chapters 11-13.)

•	Chapter 6, "Programming a TAPI Application", refers to the source code of a telephonic application (supplied with the Windows Telephony SDK) to illustrate how to create a functional Windows application.

•	Chapter 7, "Supplementary Line Functions", describes some of the more advanced functions used to create telephonic applications, include media monitoring, media control, and call conferencing.

•	Chapter 8, "Multiple-Application Programming Considerations", details what developers need to know when programming more than one application to work together or among other applications.

•	Chapter 9, "Programming with Phone Devices", describes the phone device class and the functions TAPI provides to use phone devices.

Part III, "Telephony: Reference", contains several chapters of detailed reference information about the functions, messages, or data types that are used by the Telephony API. These chapters, which also constitute the online TAPI reference (a Windows Help file), are the following:

•	Chapter 10," Line Device Functions"

•	Chapter 11, "Line Device Messages"

•	Chapter 12, "Line Device Data Structures"

•	Chapter 13, "Line Device Constants"

•	Chapter 14, "Phone Device Functions"

•	Chapter 15, "Phone Device Messages"

•	Chapter 16, "Phone Device Data Structures"

•	Chapter 17, "Phone Device Constants"

Part IV, "Appendices", contains sections of supplementary reference information for using TAPI:

•	Appendix A, "TAPI Quick Function Reference", lists the functions of TAPI, a brief description of each, and the nature of each function's reply callback: synchronous or asynchronous.

•	Appendix B, "Windows Telephony Configuration Parameters", describes the purpose of the TELEPHON.INI file and why telephony applications need to communicate with it.

•	Appendix C, "Call States and Events", describes the call states through which a call transitions as it is established or disconnected.

•	Appendix D, "Glossary of Telephony Terminology", defines terms useful to developers of TAPI applications.


Telephony API for Windows 95

To provide improvements and better serve clients, Windows Telephony includes the following extensions in Windows 95:

Plug and Play — Class installers, including the Telephony class installer, have the ability to cause Telephony service providers to be added or removed from the Telephony system without user interaction with the Telephony control panel. Also, service providers are able to dynamically create new devices without restarting the entire Telephony system.

User interface improvements and commonality — The "Change Options and Redial" functionality and the ability to select Telephony locations and calling cards are common to all telephony applications. A common dialog is accessible to all applications through TAPI, so that this function looks the same in all applications and users have to learn it only once.

Access to additional information — Applications can present information to the user not previously been exposed, such as the list of country codes.

Elimination of application calls directly into Telephony control panel — All access to control panel functions by Win32 applications is through TAPI.

VoiceView support — Support for alternate voice/data support in modems with the addition of the VoiceView media mode to the existing media modes supported in TAPI.


Telephony API Version 1.4, Changes and Additions

For Windows 95, TAPI includes a number of new functions and messages as well as some changes to existing structures and constants. The following list these new items:

Functions
lineTranslateDialog	New
lineGetCountry	New
lineGetAppPriority	New
lineSetAppPriority	New
lineAddProvider	New
lineConfigProvider	New
lineRemoveProvider	New
lineGetProviderList	New
lineConfigDialogEdit	New
lineReleaseUserUserInfo	New
Messages
LINE_CREATE	New
PHONE_CREATE	New
LINE_ADDRESSSTATE	Changed
LINE_CALLSTATE	Changed
LINE_LINEDEVSTATE	Changed
PHONE_STATE	Changed
Structures
LINEADDRESSCAPS	Changed
LINECARDENTRY	Changed
LINECOUNTRYLIST	New
LINECOUNTRYENTRY	New
LINEDEVCAPS	Changed
LINELOCATIONENTRY	Changed
LINEPROVIDERLIST	New
LINEPROVIDERENTRY	New
PHONEBUTTONINFO	Changed


Document Conventions

The type conventions used in this document are as follows:

Bold text	Bold letters indicate terms, such function and structure names, that you must use exactly as shown.
ALL CAPS	All capitals typically indicate terms, such as message and constant names, that must be used exactly as shown.
Italic text	In introductory and explanatory text, italicized words indicate that a key term or concept is being introduced. In function and message descriptions, italics indicates a placeholder for which you are expected to provide a value or the name of a variable name.
Monospaced text	Monospaced type indicates code samples and data-structure definitions.


Related Documentation

Other documentation that will help you understand the Telephony services as they apply to Windows includes:

•	Microsoft Win32 Programmer's Reference.

•	The Windows Telephony Service Provider Programmer's Guide, which provides information on how to write a Windows Telephony service provider.


Overview of Telephony

What Is Telephony?

Telephony is a technology that integrates computers with the telephone network. With telephony, people can use their computers to take advantage of a wide range of sophisticated communications features and services over a telephone line.

The Telephony application programming interface (TAPI) lets programmers develop applications that provide personal telephony to users. TAPI supports both speech and data transmission, allows for a variety of terminal devices, and supports complex connection types and call-management techniques such as conference calls, call waiting, and voice mail. TAPI allows all elements of telephone usage—from the simple dial-and-speak call to international e-mail—to be controlled within applications developed for the Microsoft Win32 application programming interface.


Using Telephony in Applications

Telephony capabilities help people get the most from telecommunications systems, allowing them to more efficiently manage their voice calls and control their data-transfer operations. You can use TAPI to bring this efficiency to any application — database manager, spreadsheet, word processor, personal information manager — any application that can benefit by sending and receiving data through the telephone network.

TAPI gives you a consistent set of tools for incorporate these features into your applications:

•	Connect directly to the telephone network rather than rely on a separate communications application

•	Dial phone numbers automatically

•	Transmit documents as files, facsimiles, or electronic mail

•	Access data from news retrieval and other information services

•	Setup and manage conference calls

•	Receive, store, and sort voice mail

•	Use caller-ID to automate the handling of incoming calls

•	Control the operations of a remote computer

•	Compute collaboratively over telephone lines

TAPI provides your application with access to the telephone network, you provide your users with access to these features. This means you choose and create a user interface that is consistent with the rest of your application. For example, if you use drag and drop extensively, you could let the user send files or facsimiles through the telephone to a colleague by dragging the icon of the file to an icon representing the colleague's destination. Similarly, you could let the user initiate conference calls by dragging three or four names from an electronic directory into a "Conference box" and clicking a "Connect" command. You choose the interface, and let TAPI carry out the work needed to make and manage the telephone connections.


Telephone Network Services

TAPI provides access to a variety of telephone network services. Although these services may use different technologies to establish calls and transmit voice and data, TAPI makes these service-specific details transparent to applications. This means you can create applications that can take advantage of any available service without including service-specific code in your application.

Historicaly, most telephone connections in the world have been of the type POTS, or "Plain Old Telephone Service." Most POTS calls are transmitted digitally except while in the local loop—the part of the telephone network between the telephone and the telephone company's central switching office. Within this loop, human speech from a household telephone is usually transmitted in analog format and the digital data from a computer must first be converted to analog by a modem. Digital networks are gradually replacing analog in the local loop.

Using TAPI for POTS is straight-forward because POTS is comparatively simple. It normally uses only one type of information (such as data or voice) per call, supports one channel per line, and so on. The vast majority of uses for TAPI are still POTS, and most telephony programmers will use TAPI only for POTS applications.

But TAPI is not restricted to POTS. TAPI also lets you make connections over other types of networks. More advanced kinds of data transmission methods are being developed, refined, and installed. For example, one important digital service is Integrated Services Digital Network (ISDN), which is expected to grow significantly in availability. ISDN networks have these advantages over POTS:

•	All digital

•	Less prone to error

•	Faster data transmission, with speeds up to 128 kilobytes per second on basic service

•	From 3 to 32 channels for simultaneous transmission of voice and data

•	An international standard

On ISDN networks, error rates are lower than with analog transmission because data travels from one end of the ISDN network to the other in digital format. Speeds of up to 128 Kbps are possible on Basic Rate Interface (BRI-ISDN) standard lines and much higher on Primary Rate Interface (PRI-ISDN) standard lines. By contrast, today's maximum dial-up modem data rates of 28.8 Kbps. When ISDN connections become more widespread, users will be able to send data to the recipient simultaneously with a voice call to that or another person. Each ISDN line, depending on its transmission rate, provides at least three channels (two for voice or data and one strictly for data or signaling information) and as many as 32 channels, for simultaneous, independently operated transmission of voice and data. BRI-ISDN lines provide two 64-Kbps "B" channels (B channels carry voice or data) and one 16-Kbps "D" channel (D channels carry signaling information or packet data). The PRI-ISDN lines for the U.S., Canada, and Japan have twenty-three 64-Kbps B channels and one 64-Kbps D channel. The European PRI standard offers thirty B channels and two D channels.

TAPI can also be used with other digital networks such as T1/E1 and Switched 56 service. With Switched 56, some local and long-distance telephone companies provide signaling at 56 Kbps over dial-up telephone lines. Switched 56 is quickly becoming available throughout the U.S. and in many other countries. It requires special equipment, and though its connection capabilities are limited to calls to other specially equipped facilities, its high speed and pricing make it a reasonable choice for many data communications needs. Switched 56 is used for data calls only.

TAPI can also be used with other services such as CENTREX, which provides a set of centralized network services (such as conferencing) without the need to install special equipment. With CENTREX, you pay for the use of telephone-company equipment over regular telephone lines. In addition, TAPI can be used with digital Private Branch Exchanges (PBXs) and key systems. Because TAPI is independent of the underlying telephone network, programming a PBX application using TAPI is the same as programming a POTS application using TAPI. An application that was originally programmed for a POTS environment can be used within a PBX environment with no changes to the application's source code.


Telephony Components

Based on the Windows Open Services Architecture (WOSA) model, Windows Telephony consists of the TAPI dynamic link library (which implements and manages the TAPI functions) and one or more telephone network service providers. The TAPI dynamic link library provides a device-independent interface for carrying out telephony tasks. Service providers are dynamic link libraries that carry out low-level and possibly device-specific actions needed to complete telephony tasks through hardware devices such as fax boards, ISDN cards, telephones, and modems. Applications link to and call functions in the TAPI dynamic link library only; they never call the service providers directly.

A third component, a support-service application called TAPIEXE.EXE, provides an execution context for the TAPI dynamic link library to carry out duties such as allocating memory or accessing data structures that have been swapped out to disk. This internal, system-only application runs in memory when running telephony applications, but does not create a window or appear in the task list. The TAPI dynamic link library automatically loads and unloads the application as needed.

When an application calls a TAPI function, the TAPI dynamic link library processes the call and routes a request to the appropriate service provider. To receive requests from the TAPI dynamic link library, the service provider must implement the Telephony service provider interface (TSPI). A service provider can provide different levels of the service provider interface: basic, supplementary, or extended. For example, a simple service provider might provide basic telephony service, such as support for outgoing calls, through a Hayes-compatible modem. An custom service provider, written by a third party vendor, might provide a full range of incoming and outgoing call support through modems other than Hayes-compatible or even through devices other than a modem.

A user can install any number service providers on a computer as long as the service providers do not attempt to access the same hardware device. The user associates the hardware and the service provider when installing. Some service providers may be capable of accessing multiple devices. In some cases, the user may need to install an device driver along with the service provider.

Applications use the TAPI functions to determine which services are available on the given computer. The TAPI dynamic link library determines what service providers are available and provides information about their capabilities to the applications. In this way, any number of applications can request services from the same service provider; the TAPI dynamic link library manages all access to the service provider.

As long as an application does not depend on optional features, the applications can, without modification, use any services to carry out telephony tasks, even services made available after the application is developed. This is because the application always accesses the many different services through TAPI which translates the requests the application makes into the actual protocols and interfaces required.

The Telephony SPI is beyond the scope of this book. For more information bout the TSPI and service providers, see the Telephony Service Provider Programmer's Reference.


Media Stream

The media stream consists of the information exchanged over a call. TAPI by itself provides control only for line and phone devices and does not give access to the content of the media stream. To manage the media stream, an application uses Win32 functions, such as the Communication, Wave Audio, or Media Control Interface (MCI) functions. For example, an application that provides an interface for managing fax or data transmission uses the TAPI functions to control and monitor the line over which bits are sent, but uses the Communications functions to transmits the actual data.

In the same manner, the media stream in a speech call (where speech refers exclusively to human speech) is produced and controlled not by TAPI, but by one human talking to another. However, the line on which that call is established and monitored, and the call itself, remain in control of the TAPI application. (Note that voice is considered to be any signal that can travel over a 3.1 kHz-bandwidth channel.)


Special Hardware

Some of the more advanced capabilities of TAPI require that an application be able, for example, to retrieve data from telephones. Most telephones cannot be connected directly to computers to control speech calls and thus are currently incapable of supporting Telephony functions beyond the passive role they play in POTS. In the future, users will install and configure telephone sets like other peripheral devices. The sets will be accompanied by cards that will control the flow of information between the computer and the telephone. Client-server configurations will also be possible that allow users to take advantage of telephonic services by connecting over a LAN to a server that has such a board and associated software installed.


Physical Connections

Lines and phones can be connected in a variety of ways to the desktop computer and the telephone network. The following examples show a selection of configurations that could be supported by a service provider. Note that some of the telephone hardware required to implement some of these example is not yet widely available.

A phone-centric connection consists of a single POTS line in which the computer is connected to the switch through the desktop phone set. Such phone sets typically connect to the computer through one of its serial ports. When an application requests an action, the corresponding service provider sends telephony commands, which are often based on the Hayes AT command set (ANSI/TIA/EIA-602), over the serial connection to the telephone. This configuration is limited because it generally provides only line control.The computer does not have access to the media stream.

A computer-centric connection uses a computer add-in card or external box that is connected to both the telephone network and the phone set. The service provider can easily integrate modem and fax functions, as well as the use of the telephone as an audio I/O device.

A BRI-ISDN connection is similar tot he computer-centric connection but allows for using the two B-channels in a variety of line configurations. A service provider can treat this connection in a number of ways:

•	A single line device with a pool of two channels, allowing both channels to be combined for establishing 128 Kbps calls.

•	Two separate line devices, each with exclusive use of a single B-channel.

•	Two separate line devices, each drawing up to two channels from a shared pool of two B-channels.

•	Three line devices: one for each of the two B-channels and one for the combination.

In the latter two models, channels may be assigned to different line devices at different times.

In client-server networks, a pool of telephone ports attached to a server may be shared among multiple client computers using a local area network. The ports may be configured to assign a maximum number of line devices (the quota) to each client workstation. It is not unusual for the sum of all quotas to exceed the total number of lines.

Also, the assignment of lines through ports is dynamic. For example, a client computer with a quota of 2 may use ports 1 and 2 at one time and ports 7 and 11 at a later time.

The service provider for the pool may model this arrangement by giving each client workstation access to two line devices. This implies that the device IDs (which are fixed) for each client are 0 and 1. If the application later requests information for device 0 and again for device 1, it must assume that the device capabilities for each device is constant, since that is the Windows device model. For server-based devices that are pooled as described in the example above, this constancy holds only for line devices that have identical device capabilities.

A LAN-based server might have multiple telephone-line connections to the switch. TAPI operations invoked at any of the client computers are forwarded over the LAN to the server. The server uses third-party call control between the server and the switch to implement the client's call-control requests.

This model offers a lower cost per computer for call control if the LAN is already in use, and it also offers reduced cost for media stream access if shared devices such as voice digitizers, fax and/or data modems, and interactive voice response cards are installed in the server. The digitized media streams can be carried over the LAN, although real-time transfer of media may be problematic with some LAN technologies due to inconsistent throughput.

A LAN-based host can be connected to the switch using a switch-to-host link. TAPI operations invoked at any of the client computers are forwarded over the LAN to the host, which uses a third-party switch-to-host link protocol to implement the client's call-control requests.

Note that it is also possible for a private branch exchange (PBX) to be directly connected to the LAN, and for the server functions to be integrated into the PBX. Within this model, different sub-configurations are possible:

•	To provide personal telephony to each desktop, the service provider could model the PBX line associated with the computer (on a desktop) as a single line device with one channel. Each client computer would have one line device available.

•	Each third-party station can be modeled as a separate line device to allow applications to control calls on other stations. (In a PBX, a station is anything to which a wire leads from the PBX). This enables the application to control calls on other stations. This solution requires that the application open each line it wants to manipulate or monitor, which may be satisfactory if only a small number of lines is of interest, but may generate excessive overhead if a large number of lines is involved.

•	Model the set of all third-party stations as a single line device with one address (one phone number) assigned to it per station. Only a single device is to be opened, providing monitoring and control of all addresses (all stations) on the line. To originate a call on any of these stations, the application must only specify the station's address to the function that makes the call. No extra lin opening operations are required. However, this modeling implies that all stations have the same line-device capabilities, although their address capabilities could be different.

A potential advantage of this model is a lowered cost per computer if the LAN is already in use, but a limitation would be a possible lack of media-stream access by the computers.

The computer in use need not be a desktop computer. It can also be a laptop or other portable computer connected to the telephone network over a wireless connection.

In a shared telephony connection, the computer's connection may be shared by other telephony equipment, such as the telephone set shown below. For an application to operate properly in this arrangement, neither the application nor the service provider can assume that there are no other active devices on the line.


The Telephony Programming Model

About the Telephony Programming Model

The Telephony application programming interface (TAPI) simplifies the development of telephonic applications by hiding the complexities of low-level communications programming. TAPI accomplishes this by abstracting telephony services to make them independent of the underlying telephone network and of the way the computer is connected to the switch and phone set. Connections to the switch may be established in a variety of arrangements including directly from the user's workstation or through a server on a local area network. Regardless of their nature, telephony devices and connections are handled in a single, consistent manner, allowing developers to apply the same programming techniques to a broad range of communications functions.

This chapter is meant for developers of applications that use the Telephony API. If you plan to use only Assisted Telephony in your application, this chapter may be skipped.


Telephony API

Telephony services are divided into Assisted Telephony services and the services provided by the full Telephony API. In general, the full Telephony API is used to implement powerful telephonic applications and Assisted Telephony is used to add minimal but useful telephonic functionality to non-telephony applications. Telephony's services are divided into the groups shown in the following illustration:


Assisted Telephony

A valuable feature of Windows Telephony is the small set of functions called Assisted Telephony. Assisted Telephony is designed to make the establishment of voice calls and of media calls available to any Windows application, not just those dedicated to telephonic functionality. In other words, Assisted Telephony lets applications make telephone calls without needing to be aware of the details of the services of the full Telephony API. It extends telephony to word processors, spreadsheets, databases, personal information managers, and other non-Telephony applications.

The programming model of Assisted Telephony fits within the programming model of Windows. Assisted Telephony merely adds four functions to those already available to the developer in other APIs such as the Win32 SDK.

For example, adding the Assisted Telephony function tapiRequestMakeCall to a spreadsheet lets users automatically dial telephone numbers stored in the spreadsheet (or in a connected database).

The power of Assisted Telephony can be illustrated by the following example. A spreadsheet application can incorporate functions that dial a telephone number for a speech call. As long as the application needs none of the detailed call control provided by the full Telephony API, Assisted Telephony is the easiest and most efficient way to give it telephonic functionality. Functionality beyond dialing such as the transmission and reception of data would require additional data-transfer APIs, including the communications functions of the Comm API.

Because Assisted Telephony and the full Telephony API are used and implemented in different ways, it is not advised to mix Assisted Telephony function calls and Telephony API function calls within a single application.


Service Levels

All the functionality of Assisted Telephony exists in the full Telephony API, but Assisted Telephony has its own set of commands. Thus, the Telephony interface consists of all Telephony's functions except those of Assisted Telephony. Applications whose telephony functionality goes beyond the most basic call control or are meant to handle inbound calls must be built using Telephony. The Telephony API defines three levels of service:

•	The elementary level of service is called Basic Telephony and provides a minimum set of functions that corresponds to "Plain Old Telephone Service" (POTS). TAPI service providers are required to support all Basic Telephony functions.

•	The next service level is Supplementary Telephony service, which provides advanced switch features such as hold, transfer, and so on. All supplementary services are optional; that is, the service provider is not required to support them.

•	At the Extended Telephony level, the API provides well-defined API extension mechanisms that enable application developers to access service provider-specific functions not directly defined by the Telephony API.


Basic Telephony Services

Basic Services are a minimal subset of the Windows Telephony specification. Since all service providers must support the functions of Basic Services, applications that use only these functions will work with any TAPI service provider. The functionality contained in Basic Telephony roughly corresponds to the features of POTS.

Today, many programmers will use only the services provided by Basic Telephony. But others, such as those writing code for PBX phone systems, will need the functions of Supplementary Telephony. Soon, the demand for ISDN and other network services, along with advancements in telephone equipment, will drive even greater usage of Supplementary Telephony.

For a list of the functions of Basic Telephony, please see Appendix A, "Quick Function Reference."

Because control of phone devices is not assumed to be offered by all service providers, phone-device services are considered to be "optional." That is, they are not a part of Basic Telephony. For a list of phone-device services, please read the following section on Supplementary Telephony services, and for more information on phone devices, see the section "Device Classes" later in this chapter.


Supplementary Telephony Services

Supplementary Telephony Services are the collection of all the services defined by the API other than those included in the Basic Telephony subset. It includes all so-called "supplementary" features found on modern PBXs, such as hold, transfer, conference, park, and so on. All supplementary features are considered optional; that is, the service provider decides which of these services it does or does not provide.

An application can query a line or phone device for the set of supplementary services it provides using functions such as lineGetDevCaps or lineGetAddressCaps. Note that a single supplementary service may consist of multiple function calls and messages. It is important to point out that the Telephony API, and not the service provider developer, defines the behavior of each of these supplementary features. A service provider should provide a Supplementary Telephony service only if it can implement the exact meaning as defined by the API. If not, the feature should be provided as an Extended Telephony service.

As mentioned under Basic Telephony Services above, phone-device services are considered "optional." Therefore, all phone-device services are part of Supplementary Telephony. For a list of the functions of Supplementary Telephony, please see Appendix A, "Quick Function Reference."


Extended Telephony Services

The API contains a mechanism that allows service-provider vendors to extend the Telephony API using device-specific extensions. Extended Services (or Device-Specific Services) include all extensions to the API defined by a particular service provider. Since the API defines the extension mechanism only, the definition of the Extended-Service behavior must be completely specified by the service provider.

TAPI's extension mechanism allows service-provider vendors to define new values for some enumeration types and bit flags and to add fields to most data structures. The interpretation of extensions is keyed off the service provider's Extension ID, an identifier for the specification of the set of extensions supported, which may cross several manufacturers. Special functions and messages such as lineDevSpecific and phoneDevSpecific are provided in the API to allow an application to directly communicate with a service provider. The parameters for each function are also defined by the service provider.

Vendors are not required to register in order to be assigned Extension IDs. Instead, a utility is provided that allows the generation of Extension IDs locally. This unique ID is composed of an Ethernet-adapter address, a random number, and the time of day. An ID is assigned to a set of extensions (before distribution), not to each individual instance of an implementation of those extensions. A tool called EXTIDGEN.EXE is provided within the Win32 SDK that allows service provider authors to generate these IDs.


Extending Data Structures and Types

A range of values is reserved to accommodate future extensions to the Basic and Supplementary TAPI function set. The "Extensibility" section in the data structure entry in the online TAPI reference and in the later chapters of this guide tells the amount by which the data structure can be extended. For a list of the functions used for extending Telephony, please see Appendix A, "Quick Function Reference."


Version Parameters

Every function that takes a dwAPIVersion or similar parameter must set this parameter to either the highest API version supported by the application or the API version negotiated using the lineNegotiateAPIVersion or phoneNegotiateAPIVersion function on a particular device. Use the following table as a guide:

lineGetAddressCaps	Use version returned by lineNegotiateAPIVersion
lineGetCountry	Use highest version supported by the application
lineGetDevCaps	Use version returned by lineNegotiateAPIVersion
lineGetProviderList	Use highest version supported by the application
lineGetTranslateCaps	Use highest version supported by the application
lineNegotiateAPIVersion	Use highest version supported by the application
lineNegotiateExtVersion	Use version returned by lineNegotiateAPIVersion
lineOpen	Use version returned by lineNegotiateAPIVersion
lineTranslateAddress	Use highest version supported by the application
lineTranslateDialog	Use highest version supported by the application
phoneGetDevCaps	Use version returned by phoneNegotiateAPIVersion
phoneNegotiateAPIVersion	Use highest version supported by the application
phoneNegotiateExtVersion	Use version returned by phoneNegotiateAPIVersion
phoneOpen	Use version returned by phoneNegotiateAPIVersion


Device Classes

Device classes simplify development by letting programmers treat devices that have similar properties in a similar manner. Real-world devices such as telephones, modems, and telephone lines belong to device classes. Applications access devices belonging to a given class using the same functions.

An application never needs to know which service provider controls which device.

Device classes help make TAPI extensible by providing a framework from which to classify and support new equipment.

Application developers should keep in mind the existence of other applications that share telephony services, as explained in Chapter 8, "Multiple-Application Programming."

There are two device classes: line device and phone device.

It also defines two sets of functions and messages, one used for line devices and one used for phone devices.

The line device class is a device-independent representation of a physical line device, such as a modem. It can contain one or more identical communications channels (used for signaling and/or information) between the application and the switch or network. Since channels belonging to a single line have identical capabilities, they are interchangeable. In many cases (as with POTS), a service provider will model a line as having only one channel. Other technologies, like ISDN, offer more channels, and the service provider should treat them accordingly.

A service provider may allow an application to request that multiple channels be combined in a single call (as, for example, when ISDN "B" channels are combined into "H" channels) to give the call wider bandwidth, using a technique often referred to as inverse multiplexing. This added bandwidth enables the call to transmit more information at the same time. For most current telephonic purposes, inverse multiplexing is not necessary.

In POTS, it is normally necessary to assign one channel per line, but with ISDN, a line's channels are dynamically allocated when an application makes or answers a call. Because these channels have identical capabilities and are interchangeable, the application need not identify which channel is to be used in a given function call. Channels are owned and assigned by the service provider for the line device in a way that is transparent to applications. This channel management is a method of abstraction that eliminates the need to introduce the naming of channels by TAPI.

Just as a line device class is an abstraction of a physical line device, the phone device class represents a device-independent abstraction of a telephone set. TAPI treats line and phone devices as devices that are independent of each other. In other words, you can use a phone (device) without using an associated line, and you can use a line (device) without using a phone.

Service providers that fully implement this independence can offer uses for these devices not defined by traditional telephony protocols. For example, a person can use the handset of the desktop's phone as a waveform audio device for voice recording or playback, perhaps without the switch's knowledge that the phone is in use. In such an implementation, lifting the local phone handset need not automatically send an offhook signal to the switch.

This independence also allows an application to ring the local telephone in a manner that is independent of inbound calls. The capabilities of service providers is limited by the capabilities of the hardware and software used to interconnect the switch, the phone, and the computer.


Addresses to Lines Assignments

An address is the telephone number, complete with national or international codes, of a telephone, fax machine, or other device that can receive calls. Addresses can be dialed by a human or stored in an electronic directory for retrieval and use by a telephony application. For more complete information on addresses assignments, channels, and lines, please see Chapter 5, "Line Devices."

The local assignment of an address to a line (that is controlled in TAPI) takes place in the setup operation for the service provider. This can be done using the Control Panel to configure the service provider or by calling the lineConfigDialog function from within the application. On the local side of the central office, everything about a line is controlled by a service provider, such as whether there are multiple addresses and what these addresses are.

Usually, there is exactly one address per line, with the following exceptions:

•	Multiple Addresses with POTS.  In POTS, multiple addresses work only with systems that support distinctive ringing or are connected to a "DID trunk." (DID—direct inward dialing—is an extra-fee service provided by the phone company.) With DID in a multi-user voice mail system, the dialed number is signaled to the system on the DID trunk before the call rings. This allows the system to play the called party's pre-stored announcement message and to store any incoming messages in the correct voice mail box.

On a residential line with "distinctive ringing service," different ringing patterns correspond to multiple numbers assigned to the same line.

•	Multiple Addresses with ISDN.  ISDN was designed to allow simultaneous multiple addresses. It does that by providing multiple channels, each of which can have its own address. On an ISDN network, "call offering" (which means a call-setup message has been sent from the switch) takes place before ringing, so the call can be redirected before it is answered. The lineAccept function means "start ringing" for ISDN. For POTS, it means that some application has accepted responsibility for the call and has presented it to the user.


Call Control

The developer's view of telephony is one in which telephone lines and phone sets are logically connected through TAPI. This logical connection also provides a point of termination for the telephone line. The physical connection can be made at the desktop, or at a LAN-based host or server, where a LAN protocol "extends" the connection of the phone lines or phone to the client application. TAPI uses a first-party call-control model on the logically terminated line as well as control of the associated phone device, if any.

Applications access Telephony API services using a first-party call control model. This means that the application controls telephone calls as if it is an endpoint (the initiator or the recipient) of the call. The application can make calls, be notified about inbound calls, answer inbound calls, invoke switch features such as hold, transfer, conference, pickup, and park, and can detect and generate DTMF tones for signaling remote equipment. An application can also use TAPI functions to monitor call related activities occurring in the system.

In contrast, third-party call control means that the controlling application does not act as an endpoint of the call. A third-party call-control model allows an application to establish or answer a call between any two parties—the application does not act as either of these parties.

A service provider may implement TAPI's line and phone functions by treating the set of all stations on the switch as a single line device to which multiple phone numbers are assigned. Each phone number on the line device maps to one of the stations on the switch—that is, calls passing through the switch can reach a local station by using its address (telephone number). The application can answer calls or make calls, selecting any one of the addresses on the line device as the origination number. Although the application appears to be the originating party, a call is actually established between the station whose address was selected by its originating number and the other party. However, this implementation is a type of third-party call control and is not a design goal of TAPI, which emphasizes first-party call control applications.


Media Access

The media mode is the form in which data is transmitted on a line. The four main types of media mode are voice, speech, facsimile, and data. With TAPI, calls can be established independently of the call's media mode.

The media stream is the actual stream of information that travels on the line. Phone devices and calls on line devices are capable of carrying media streams. The Telephony-API line and phone device classes provide a wide range of control operations for these devices, but access to the media stream itself is not provided by TAPI. Instead, the application must use other APIs for the Windows environments to access or manage these media streams. These APIs include the Waveform API, the Comm API, and the MCI (Media Control Interface). (The Waveform API is used for multi-media programming, the MCI provides a high-level generalized interface for controlling media devices, and the Comm API is the set of communications functions provided by the Win32 SDK.)

For example, for line devices, an application can use TAPI to establish a connection to another station. Once the connection is established, the application can then use the Waveform API (or the MCI Waveaudio API) on the associated device to play back (send) and record (receive) audio data over the connection. Similarly, if the connection's media stream is from a modem, an application would use the modem configuration extensions of the Comm API to control the media stream.

To provide TAPI and media-stream access to either a phone or a call on a line device, the service provider must implement both the Telephony SPI and the appropriate media stream SPI or DDI (device-driver interface). The service provider can support lines and phones simultaneously.

Since these device classes and media stream interfaces function independently of one another, coordination of their usage must occur at the application level. Multiple applications that share calls and media streams in nontrivial ways will likely need to coordinate their activities at the application level to prevent conflicting usage of TAPI and the media stream API in use. For more information on preventing conflicts, please see Chapter 8, "Multiple-Application Programming."

TAPI reports changes in the type of media stream (voice, fax, data modem, and so on) to participating applications. This process is sometimes referred to as call classification. The mechanism used to determine the type of media stream is specific to the service-provider. For example, a service provider may filter the media stream for energy or tones that characterize the media type, or it may use distinctive ringing, information exchanged in messages over the network, or knowledge about the caller or called ID to make this determination.

TAPI also provides limited support for control of the media stream on a call, particularly in server-based networks. The actual data does not pass through TAPI, but TAPI can be used to a limited extent to control functions that control the media stream. This control is provided to avoid latency (delay) problems that could arise in client-server configurations for which the application is forced to use the stream's media API. An application can request actions on a call's media stream if these actions are to be triggered by events normally reported by TAPI, such as the detection of a tone or DTMF digit, or the transition of a call to a specified call state.

For example, an application can request that a call's media stream be suspended (with lineSetMediaControl) when a # DTMF digit is detected on the call, and that the media stream be resumed when a * DTMF digit is detected. Note that some implementations or configurations will be unable to provide any media-control functions or media access to the phone or line. Providing media control is optional to the service provider; it should provide performance benefits primarily for client-server implementations. Since it is optional and since only limited control is provided, its usage is generally discouraged. If possible, applications should use the media stream's control functions instead.


Application Notifications

The programming model for Windows Telephony matches the standard programming model for the Windows environment with regard to device naming, the use of sections and entries in the TELEPHON.INI file, and function calling conventions. But it deviates from this model in one important way—the synchronous/asynchronous operational model, which is a callback scheme through which applications are notified of the success or failure of function calls and other events.


Function Callbacks

The mechanism used by TAPI to notify applications of events is based on function callbacks, and TAPI defines the parameter profile for these callbacks. When an event occurs, the application's callback function is invoked from within the application's thread (at the time the application calls the GetMessage function), providing a normal, fully functional execution environment in which all Windows APIs can be safely invoked.

The reply callback made to the application carries the request ID and an error indication. Valid error indications for this reply are identical to those that are returned synchronously for the associated request, or zero for success. Only the application that issued the request will receive the reply callback, but when the request causes changes in the state of the device or call, other interested applications may also receive event-related messages.

TAPI guarantees that a reply callback is made for every request that operates asynchronously, and it defines which functions are notified synchronously and which are notified asynchronously. (See the section "Introduction: Synchronous/Asynchronous Operation" later in this chapter.)


Information Returned by Functions

An application receives two kinds of information as a result of a function call: the function's return value, and values written to data locations specified by the function's arguments.

If the function's return value is zero, the application knows that the function has completed synchronously. In this case, any values written as a result of the function call are reliable and can be used immediately. However, if the return value is positive, the function has not yet completed but it will complete asynchronously, at which time TAPI notifies the application by sending it an asynchronous reply message (or reply callback) for the function. Once the application receives this message (and the message indicates success), any values returned by the function are considered to be reliable. However, before the message is received, the application should consider these values suspect and should not use them. Also, because asynchronous reply messages can take varying lengths of time to be sent, the application may not receive them in the same order in which it called their functions. This is why an application must retain the request IDs of its requests in progress so that it can identify and correctly respond to incoming asynchronous reply messages.


Example Illustrating the Programming Model

Consider a Windows-based application that can make either voice or data (modem) calls. Although these calls could be made simultaneously if a telephone line were in place for each device (the telephone and the modem), assume that there is only one line, so calls are placed one at a time.

For this discussion, a line is defined as a physical telephone line leading from the wall to the telephone company's switch, and a line device (such as a fax or modem) is a local device on the telephone line. Also, this example is restricted to POTS; the telephone line is a standard, two-wire twisted-pair cable that carries an analog signal and constitutes a single channel.

The line devices attached to the computer are visible to the application as instances of the line device class, which is defined by TAPI. The physical telephone is visible to the application as an instance of the phone device class. This application therefore must be able to execute two types of calls: voice and data. One strength of the TAPI programming model is the way its abstraction into classes exploits the similarities between these different types of calls.

For a more in-depth discussion of this process and related ones, see Chapter 6, "TAPI Applications."


Determining the Call Type (Media Mode)

Before an application uses any telephony services, it needs to interact with the user to know what kind of call to make. To do this, the standard Win32 API functions are used to build the menus or dialogs needed to gather the user input that tells your application what to do. In this example, the user specifies the transmission of data, so the application will make a call that transmits a specified file to another user.


Initializing TAPI

Before placing a call, an application must establish a means of communication between itself and TAPI. This process consists of telling TAPI the address of a chosen callback function within the application. This is the function that is notified by TAPI when relevant external events occur. The application passes the pointer to its callback function to TAPI with the lineInitialize function. One of the values lineInitialize returns is the number of line devices available to the application. In this example, that number is one, and the line's ID in Telephony's zero-based scheme is 0. The application must establish this communication link (with lineInitialize) regardless of the type of call to be placed or received.


Obtaining a Line

Next, the application needs to obtain a handle to a capable telephone line. The application opens the line with lineOpen, but before doing this, it must make sure that the line can support the desired type of call. Invoking the lineGetDevCaps function returns that information to the application in a data structure of type LINEDEVCAPS. If data calls were not supported, this fact could be reported to the user in a dialog box. The application does not need to use lineGetDevCaps before every call, because a line's capabilities should remain static. If the local telephonic configuration (as expressed in .INI files) changes, TAPI notifies applications, which can then call lineGetDevCaps to see what has changed.

One of the values returned by lineGetDevCaps (as a field in the LINEDEVCAPS structure) is the number of addresses assigned to the specified line device. In this example, a single device has a single address.

Ownership of a call is a type of privilege. Applications obtain owner or monitor privilege to new incoming calls by specifying the desired privilege as a parameter of lineOpen. The privilege with which a line is opened remains in effect for subsequent calls used by that application on that line. An application always has owner privileges on calls it creates. When the application opens a line to place calls (as opposed to taking inbound calls) it invokes lineOpen with the privilege LINECALLPRIVILEGE_NONE, which insulates the application from incoming calls while allowing outgoing calls. The other privileges used with the lineOpen function are only for incoming calls.


Placing the Call

Once the application has opened the line device, it places the call with lineMakeCall, specifying the address (phone number and area code) in the lpszDestAddress parameter and the media mode (datamodem, in this case) in the lpCallParams parameter. This function returns a positive "request ID" if the function will be completed asynchronously, or a negative error number if an error has occurred. Negative return values describe specific error states. LINEERR_CALLUNAVAIL, for example, means that the line is probably in use (someone else already has an active call). If dialing completes successfully, callbacks are made to the application to inform it about the call's progress. Applications typically use these messages to display status reports to the user.

Later, when the lineMakeCall function has successfully set up the call, the application receives a LINE_REPLY message (the asynchronous reply to lineMakeCall). At this point there is not necessarily a connection to the remote station, just an established call at the local end—perhaps indicated by a dialtone. This LINE_REPLY message informs the application that the call handle returned by lineMakeCall is valid.

TAPI's programming model treats data calls similarly to voice calls, as shown by the fact that the same function is used to make calls of both types. If LINEBEARERMODE_DATA is specified in a field of the lpCallParams parameter of lineMakeCall, the call is set up to send data. Speech transmission can be chosen by using a different value. And if NULL is specified, a default 3.1 kHz voice call is established, which can support the speech, fax, and modem media modes.

Note  TAPI should not be used for fax transmissions. Instead, use the functions available through MAPI, the Microsoft Messaging API.

As the call is placed, it passes through a number of states, each of which results in a LINE_CALLSTATE message sent to the application. These states include dialtone, dialing, ringback, and, if connection succeeds, LINECALLSTATE_CONNECTED. (To see the complete list of call states, refer to the LINECALLSTATE structure in Chapter 12, "Line Device Structures.") After the message indicating the connected state is received, the application can begin sending data.


Sending Data

If the line is available (not busy) and the connection is established, the data can be sent. The application accomplishes this by giving control back to the user, who, using a dialog box, specifies the file to send and initiates data transmission. Though TAPI functions continue to manage the opened line and the call in progress, actual transmission is started and controlled by non-TAPI functions. In this case, for example, the Comm API of the Win32 SDK could be used to control the media stream.

If the application were setting up a speech call, its actions would be similar. Once the call is established, the duty of data transmission is transferred outside of TAPI to the people who wish to speak, although the line and call continue to be monitored by the application using TAPI functions.


Ending the Call

When the modem transmission is finished, the application receives a LINE_CALLSTATE message, which informs it that the state of a line device has changed. In this example, a remote disconnect has occurred. The application disconnects the call at the local end (it "goes on-hook") with lineDrop. Alternatively, the application itself may choose to end the call by invoking lineDrop before receiving the remote-disconnect message.

Here are the steps that might be used to end a call, close the line, and leave TAPI:

1.	The application calls lineDrop, which places the call in the IDLE state. The call still exists, and the application still has its handle. Now the application can examine the call-information record, if desired.

2.	The application calls lineDeallocateCall to release the call handle for the finished call. The call no longer exists.

3.	If the application expects no more calls on the line, it uses lineClose to close the line. At this point, there will be no more incoming or outgoing calls on that line.

4.	The application invokes lineShutdown to end the use of TAPI's functions for the current session.


Synchronous/Asynchronous Operation

The interactive nature of telephony requires that TAPI be a real-time operating environment. Many of TAPI's functions are required to complete quickly and return their results to the application synchronously. Other functions (such as dialing) may not be able to complete as quickly and therefore operate asynchronously. Any given operation always completes either synchronously or asynchronously, and both types of operation are explained below. A list of all TAPI functions, which states whether each one completes synchronously or asynchronously, appears in Appendix A, "Quick Function Reference."


Synchronous Functions

An operation that completes synchronously performs all of its processing in the function call made by the application. The function returns different values depending on its success or failure:

•	Synchronous Success.  If the request or service corresponding to the function has been carried out successfully, the function returns zero, indicating success. Any values written as a result of the function call are reliable and can be used immediately.

•	Synchronous Failure.  If the function detects an error and the request is not carried out, a negative error number is returned to identifies the error.


Asynchronous Functions

An operation that completes asynchronously performs part of its processing in the function call made by the application and the remainder of it in an independent execution thread after the application has returned from the function call. To ensure completion of the call's processing, the service provider vectors the request to another active entity in the system—such as a LAN server, add-in hardware, a switch, or a network—and then returns to the application. At this time, either a negative error result or a positive request ID is returned to the application.

At the time of asynchronous completion (the service provider has received an interrupt from the hardware, meaning that a message must be delivered), the service provider calls TAPI.DLL through a callback function and reports that "Event X has just taken place. Deliver an appropriate message to all concerned applications." To minimize the processing done during interrupt context, TAPI.DLL posts a message to TAPIEXE.EXE. When TAPIEXE.EXE receives this message, it calls TAPI.DLL, which in turn posts a Windows message. When the application that requested the asynchronous operation receives this message from Windows, a special message-class function in TAPI.DLL is invoked, which calls the line or phone callback function registered by the application. Through this mechanism, the application's callback function is invoked from within the application's own context (thread of control).

When the asynchronous portion of the operation completes, a LINE_REPLY (or PHONE_REPLY) callback message is sent to the application. This callback message contains, as one of its parameters, the request ID returned by the function call. This request ID allows the application to determine which original request has completed. (Applications should remember the request IDs of all their requests in progress so that reply messages can be properly handled.) A second parameter to the LINE_REPLY (or PHONE_REPLY) message is the asynchronous return value. This is either a negative value (for an error) or 0 if the operation completed successfully. For asynchronous operations, any of the return values may be returned as part of the function return or as the dwParam2 parameter in the _REPLY message. The value 0, which indicates success, will only be returned in the LINE_REPLY message, and never as the function's return value.

The initialize functions (lineInitialize and phoneInitialize) tell TAPI where to send these messages, or reply callbacks, to the application. This mechanism is explained in Chapter 6, "TAPI Applications."


The Meaning of SUCCESS

When an operation returns a SUCCESS indication (either synchronously upon function return for synchronous operations, or asynchronously through a LINE_REPLY or PHONE_REPLY message for asynchronous operations), the following is assumed to be true:

•	The function has successfully progressed to a point that is defined by the API on a function-by-function basis. After that point has been reached, either the operation is completely done, or it will be in a state such that independent state messages will inform the application about subsequent progress.

For example, a service provider's implementation of lineMakeCall should return SUCCESS no later than when the call enters the proceeding call state. Ideally, the provider should indicate SUCCESS as soon as possible, such as when the call enters the dialtone call state (if applicable). Once SUCCESS has been returned to the application, LINE_CALLSTATE messages will inform the application about the progress of the call. Service providers that delay returning the lineMakeCall SUCCESS indication, say, until after dialing is complete, must be aware that this places that provider at a disadvantage because the usability at the application level may be severely limited. For example, it would not be possible for a user to cancel the call setup request in progress until after dialing is complete and all digits had been sent to the switch.

•	Functions that return information (such as lineGetCallInfo) return SUCCESS only when the requested information is available to the application. Functions that return handles (to lines or calls), can return SUCCESS only after the handle is valid. No callback messages should be sent about that line or call prior to the SUCCESS indication of the function that caused its creation. The service provider is responsible for suppressing such messages.

•	Functions that enable certain permanent conditions (such as lineMonitorDigits) return SUCCESS only after the condition is enabled, not when the condition is removed again (for example, not when all digit monitoring has completed).

•	Call-control functions (such as lineHold or lineSetupTransfer, but not lineMakeCall) return SUCCESS when the operation is completed. Some telephone networks do not provide acknowledgment (positive or negative) about the completion of certain requests made by service providers. In such situations, the service provider must decide upon success or failure of the request. Therefore, SUCCESS may indicate that the service provider has initiated actions to fulfill the request, but not necessarily anything more. For example, the provider may receive no affirmative acknowledgment to its request from the switch, although it has already sent a success message to the application.


Request Recipient Services

Two kinds of applications are needed to run Assisted Telephony. Assisted Telephony Clients are applications that use Assisted Telephony by calling the functions that have the prefix "tapi." An example of such a client application would be a spreadsheet to which a Dial... menu command or toolbar button is added. For more information about the uses and functions of Assisted Telephony, see Chapter 4, "Assisted Telephony."

Assisted Telephony Servers are applications that can execute Telephony API functions that result from another application's call to a "tapi"-prefixed function. To make itself known as an Assisted Telephony server, such an application registers as one using the function lineRegisterRequestRecipient.

The functions of Assisted Telephony (which begin with the prefix tapi) are known as request functions. Assisted Telephony applications that process these requests—Assisted Telephony servers—are called request recipients.


Assisted Telephony Requests

Applications that use Assisted Telephony services only initiate requests that are temporarily queued by TAPI.DLL. It is the request recipient application that retrieves these requests and executes them on behalf of the Assisted Telephony application. The tapiRequestMakeCall function requests the establishment of a voice call. The requesting application does not control the call.

TAPI allows the user to establish different or the same request recipient applications for each of these services. An application becomes a request recipient by registering with lineRegisterRequestRecipient, which can also be used to deregister the application for the specified services. The application selects which services it wants to handle in the dwRequestMode parameter of lineRegisterRequestRecipient. If multiple applications register for the same services, a priority scheme is used to allow the user to select which application is preferred for handling requests. This priority scheme is identical to that used for call hand-off and the routing of incoming calls based on a list of filenames in the [HandoffPriorities] section of the TELEPHON.INI file.


Processing Assisted Telephony Requests

The process with which requests are delivered and serviced is as follows:

1.	When TAPI.DLL receives an Assisted Telephony request, it checks for a request recipient, that is, an application currently registered to process that type of request. If so, the request is queued, and the highest-priority application that has registered for that request's service is sent a LINE_REQUEST message. The message notifies the request recipient that a new request has arrived, and it carries an indication of the request's mode.

2.	If TAPI.DLL cannot find a currently running application to process such a request, it tries to launch an application that has been registered as capable of doing so. This registration information is recorded in the [HandoffPriorities] section of the TELEPHON.INI configuration file. TAPI.DLL tries to launch applications in the order in which they are listed in the [HandoffPriorities] section. (See the following step.)

If no application is currently registered, TAPI.DLL examines the list of request-processing applications on the associated entry in the [HandoffPriorities] section of TELEPHON.INI. If the associated line is missing from the file, if there are no applications listed on it, or if none of the applications in the list can be launched, the request is rejected with the error TAPIERR_NOREQUESTRECIPIENT.

When a request recipient is launched (whether or not it has been launched by TAPI.DLL) it is its duty to call lineRegisterRequestRecipient during the startup process and register itself as a request recipient.

3.	If one or more applications are listed in the entry, TAPI begins with the first listed application (highest priority), and attempts to launch it using the LoadModule or WinExec function. If the attempt to launch the application fails, TAPI.DLL attempts to launch the next application in the list. When any application launches successfully, TAPI.DLL simply queues the request and returns a success indication to the application even though the request hasn't yet been signaled to the request recipient.

Once the request recipient application is launched, it calls lineRegisterRequestRecipient, which causes a LINE_REQUEST message to be sent, signalling that the request is queued. If for some reason the launched application never registers, the request remains queued and remains in the queue indefinitely until an application registers for that type of request.

4.	If TAPI.DLL finds such a registered application already running or successfully launches one, it queues the request, sending a LINE_REQUEST message to the server application, and returns a success indication for the function call to the Assisted Telephony application. This success message states only that the request has been accepted and queued, not that it has been successfully executed.

5.	When the server application is ready to process a request, it calls the function lineGetRequest. This lets it receive any information it needs, such as an address to dial. It then processes the request, using the Telephony API functions (such as lineMakeCall and lineDrop) that would otherwise be used to place the call. Invoking lineGetRequest removes the request from TAPI.DLL, and the request parameters are copied in an application-allocated request buffer. The size and interpretation of the contents of the buffer depend on the request mode.

6.	If TAPI.DLL cannot launch an application capable of serving as a request recipient, the Assisted Telephony call fails and returns the error TAPIERR_NOREQUESTRECIPIENT.


Notes on Request Recipient Operations

The following information concerns systems on which Assisted Telephony requests are processed:

•	The default TELEPHON.INI file should list a call manager application in the priority list for tapiRequestMakeCall. It would be helpful, but not essential, for the call manager application to have a menu option that allows users to set it to the highest priority.

•	When an Assisted Telephony recipient application is launched automatically by TAPI.DLL and if it is the only TAPI application in the system, this action initializes TAPI.DLL. If the Assisted Telephony recipient application initializes and shuts down the line device before registering for Assisted Telephony requests, TAPI is shut down as well, and the Assisted Telephony request is lost. Assisted Telephony requests might also be lost when another TAPI application that is launched performs an initialize and shutdown.


Passthrough Mode

Windows 95 defines a new LINEBEARERMODE_PASSTHROUGH value (0x00000040). When a call is active in LINEBEARERMODE_PASSTHROUGH, the service provider gives direct access to the attached hardware for control by the application. This mode is for use by applications desiring temporary direct control over asynchronous modems, accessed via the Win32 comm functions, for the purpose of configuring or using special features not otherwise supported by the service provider, such as facsimile (Class 1, 2, etc.). This bearer mode is supported by the Universal Modem Driver (UNIMODEM) service provider included with Windows 95.

Service providers that support LINEBEARERMODE_PASSTHROUGH indicate it in the dwBearerModes field of the LINEDEVCAPS structure. When LINEBEARERMODE_PASSTHROUGH is indicated, the Unimodem service provider will also include in the DevSpecific area of the LINEDEVCAPS structure the registry key used to access information about the modem associated with the line device, in the following format:

struct {
    DWORD dwContents;   // Set to 1 (indicates containing key)
    DWORD dwKeyOffset;  // Offset to key from start of this
                        // structure (not from start of
                        // LINEDEVCAPS structure). 8 in
                        // our case.
    BYTE rgby[...];     // place containing null-terminated
                        // registry key.
}

For example:

    00000001 00000008 74737953 435c6d65  ........System\C
    65727275 6f43746e 6f72746e 7465536c  urrentControlSet
    7265535c 65636976 6c435c73 5c737361  urrentControlSet
    65646f4d 30305c6d xx003030 xxxxxxxx  Modem\0000.

This registry key could then be opened using this function:

RegOpenKey(HKEY_LOCAL_MACHINE, pszDevSpecificRegKey, &phkResult)

Passthrough mode is invoked most often using the lineMakeCall function, by setting the LINEBEARERMODE_PASSTHROUGH bit in the dwBearerMode field of the LINECALLPARAMS structure pointed to by the lpCallParams parameter. When this is done, the service provider will open the serial port to the modem and immediately place the call into LINECALLSTATE_CONNECTED. The application can then use the lineGetID function with the device class "comm/datamodem" to obtain an open Win32 file handle to read from and write to the comm port.

Passthrough mode can be invoked in response to an incoming call as well. Generally, applications will invoke passthrough mode while the call is in LINECALLSTATE_OFFERING, before the call has been answered. Instead of calling lineAnswer, the applications calls lineSetCallParams, passing LINEBEARERMODE_PASSTHROUGH as the dwBearerMode parameter. When this is done, as with lineMakeCall, the call will immediately be placed into LINECALLSTATE_CONNECTED by the service provider, and the application can obtain a handle to the open port using lineGetID. lineSetCallParams may be called when the call is in LINECALLSTATE_OFFERING, LINECALLSTATE_ACCEPTED, or LINECALLSTATE_CONNECTED.

Passthrough mode is normally terminated by calling lineDrop on the call handle obtained from lineMakeCall or the first LINE_CALLSTATE message (if the call was an incoming call). The service provider will close the port, and restore the modem to its default state. The application must call CloseHandle on the handle it received from lineGetID.

Passthrough mode can also be terminated by calling lineSetCallParams with the dwBearerMode parameter set to LINEBEARERMODE_VOICE. The media mode set by lineSetMediaMode is presumed to be in effect. If LINEMEDIAMODE_DATAMODEM is active, the service provider will take over the call as though it was a datamodem call already in progress; if lineDrop is subsequently called, the service provider will issue the appropriate modem commands or interface state changes to drop a data call.


Assisted Telephony

About Assisted Telephony

Assisted telephony provides very basic telephony functionality to primarily non-telephonic applications. If your application needs extensive telephonic control or is meant to handle incoming calls, skip this chapter.


Call Requests

Assisted Telephony provides telephony-enabled applications with an easy-to-use mechanism for making phone calls without requiring the developer to become fully telephony literate.

The tapiRequestMakeCall function requests a voice call between the user and a remote party specified by its phone number. The request is made to TAPI, which passes it to an application that is registered as a recipient of such requests. This recipient is a call-manager application.

After the application has made the request, the call is controlled entirely from the call-manager application because Assisted Telephony applications cannot manage calls. Since the more complex aspects of telephony and all user-interface operations are handled by the call-manager application, telephony-enabled applications need not be modified in any substantial way. In fact, applications that allow this operation to be invoked from their built-in script language may not need to be modified at all.

The tapiGetLocationInfo function returns to the application the country code and city (area) code which the user has set in the current location parameters in the Telephony control panel. The application may use this information to assist the user in forming proper canonical telephone numbers, such as by offering these as defaults when new numbers are entered in a phone book entry or database record.

The Assisted Telephony server application is also known as a request recipient. For more information about request recipients, see Chapter 2, "The Telephony Programming Model."


Using Assisted Telephony

You might use assisted telephony to in a word-processing application. Consider a word-processing application that has a button with a caption of "George." When the user selects a telephone number in a document and clicks this button, the application sends a request (tapiRequestMakeCall) to the call-control application, which dials the number and notifies the user of the call's status.


Reference

Following is a list of the functions, messages, and data types used by Assisted Telephony.


Functions

 The following functions are used by Assisted Telephony.


tapiRequestMakeCall

[New - Windows 95]

LONG tapiRequestMakeCall(LPCSTR lpszDestAddress, LPCSTR lpszAppName,
    LPCSTR lpszCalledParty, LPCSTR lpszComment);

Requests the establishment of a voice call. A call-manager application is responsible for establishing the call on behalf of the requesting application, which is then controlled by the user's call-manager application.

·	Returns zero if the request is successful or a negative error number if an error has occurred. Possible error return value are:

TAPIERR_NOREQUESTRECIPIENT	TAPIERR_INVALDESTADDRESS
TAPIERR_REQUESTQUEUEFULL	TAPIERR_INVALPOINTER
lpszDestAddress

Specifies a pointer to a memory location where the NULL-terminated destination address of the call request is located. The address can use the canonical address format (address formats are discussed in Chapter 5, "Concepts of Line Devices") or the dialable address format. Validity of the specified address is not checked by this operation. The maximum length of the address is TAPIMAXDESTADDRESSSIZE characters, which includes the NULL terminator.

lpszAppName

Specifies a pointer to a memory location where the ASCII NULL-terminated user-friendly application name of the call request is located. This pointer may be left NULL if the application does not wish to supply an application name. The maximum length of the address is TAPIMAXAPPNAMESIZE characters, which includes the NULL terminator. Longer strings are truncated.

lpszCalledParty

Specifies a pointer to a memory location where the ASCII NULL-terminated called party name for the called party of the call is located. This pointer may be left NULL if the application does not wish to supply this information. The maximum length of the string is TAPIMAXCALLEDPARTYSIZE characters, which includes the NULL terminator. Longer strings are truncated.

lpszComment

Specifies a pointer to a memory location where the ASCII NULL-terminated comment about the call is located. This pointer may be left NULL if the application does not wish to supply a comment. The maximum length of the address is TAPIMAXCOMMENTSIZE characters, which includes the NULL terminator. Longer strings are truncated.

A telephony-enabled application can request that a call be placed on its behalf by invoking tapiRequestMakeCall, providing only the destination address for the call. This request is forwarded to the user's call-control application, which places the call on behalf of the original application. A default call-control application is provided as part of Windows Telephony. Users can replace this with a call-control application of their choice.

Invoking tapiRequestMakeCall when no call control application is running returns the TAPIERR_NOREQUESTRECIPIENT error indication. If the call control application is not running, TAPI.DLL will attempt to launch the highest-priority call control application (which is listed for RequestMakeCall in TELEPHON.INI). Invoking this function when the Assisted TAPI request queue is full returns the TAPIERR_REQUESTQUEUEFULL error.


tapiRequestMediaCall

The tapiRequestMediaCall function is nonfunctional in Win32 -based applications and obsolete for all classes of Windows-based applications. It should not be used.


tapiGetLocationInfo

[New - Windows 95]

LONG tapiGetLocationInfo(LPCSTR lpszCountryCode, LPCSTR lpszCityCode);

Returns the country code and city (area) code which the user has set in the current location parameters in the Telephony control panel. The application may use this information to assist the user in forming proper canonical telephone numbers, such as by offering these as defaults when new numbers are entered in a phone book entry or database record.

·	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are TAPIERR_REQUESTFAILED.

lpszCountryCode

Specifies a pointer to a memory location where a NULL-terminated ASCII string specifying the country code for the current location is to be returned. The application should allocate at least 8 bytes of storage at this location to hold the string (TAPI.DLL will not return more than 8 bytes, including the terminating NULL). An empty string (\0) will be returned if the country code has not been set for the current location.

lpszCityCode

Specifies a pointer to a memory location where a NULL-terminated ASCII string specifying the city (area) code for the current location is to be returned. The application should allocate at least 8 bytes of storage at this location to hold the string (TAPI.DLL will not return more than 8 bytes, including the terminating NULL). An empty string (\0) will be returned if the city code has not been set for the current location.


tapiRequestDrop

The tapiRequestDrop function is nonfunctional in Win32 -based applications and obsolete for all classes of Windows-based applications. It should not be used.


Messages

The following messages are used by Assisted Telephony.


TAPI_REPLY

The TAPI_REPLY message is nonfunctional in Win32 -based applications and obsolete for all classes of Windows-based applications. It should not be used.


Constants

The following constants are used by Assisted Telephony.


TAPI Error Values

TAPIERR_INVALDESTADDRESS	The pointer to the destination address is not valid, is NULL, or the destination address string is too long.
TAPIERR_INVALPOINTER	The pointer does not reference a valid memory location. One or more of the pointers lpszDestAddress, lpszAppName, lpszCalledParty, or lpszComment have been specified but are invalid.
TAPIERR_NOREQUESTRECIPIENT	No recipient application is available to handle the request. The user should start the recipient application and try again.
TAPIERR_REQUESTFAILED	The request failed for unspecified reasons.
TAPIERR_REQUESTQUEUEFULL	A recipient application is active, but the request queue is full or there is insufficient memory to expand the queue. The application can try again later.
Any other TAPIERR_ values are nonfunctional in Win32-based applications and must not be used.


Line Devices

About Line Devices

A line device is a physical device such as a fax board, a modem, or an ISDN card that is connected to an actual telephone line. Line devices support telephonic capabilities by allowing applications to send or receive information to or from a telephone network. A line device is the logical representation of a physical line device, one of the two device classes supported by TAPI. This chapter describes line devices and explains how to use the line functions that access these devices.


What is a Line Device?

A line device is a physical device such as a fax board, a modem, or an ISDN card that is connected to an actual telephone line (although the device may not be physically connected to the computer on which the telephony application is running). Line devices support telephonic capabilities by allowing applications to send or receive information to or from a telephone network. A line device contains a set of one or more homogeneous channels that can be used to establish calls.

Within TAPI applications, a line device is the logical representation of a physical line device. Although "line" often connotes something with two endpoints, it is possible to abstract a line device to a single point because TAPI views it only as a point of entry to the line that leads to the switch.

Although the three lines in the preceding illustration are composed of different hardware and used for different functions, they are abstracted to the same device type and governed by the same rules. Note that the telephone represents not a phone device but a line device used for voice calls. When using this line device for incoming or outgoing calls, the application would also need to open and control an instance of the phone-device class, which is described in detail in later chapters.

TAPI requires that every TAPI-capable line device support all of Basic Telephony. If an application needs to use capabilities beyond those of Basic Telephony (namely Supplementary or Extended Telephony), it must first determine the line device's capabilities, which can vary according to network configuration (client versus client-server), hardware, service-provider software, and the telephone network.  The lineNegotiateAPIVersion function allows the application to identify the set of Extended capabilities supported on a line device, and the lineNegotiateExtVersion function allows for different versions of that set to be used. The function lineGetDevCaps returns the telephonic capabilities implemented through the use of the Supplementary and Extended (if any) TAPI functions of a given line device in a data structure of the type LINEDEVCAPS.


Lines, Channels, and Addresses

In POTS, exactly one channel exists on a line, and this is used exclusively for voice. With ISDN, at least three (and as many as 30 or more) channels can exist on a line simultaneously. Currently, most TAPI functionality involves POTS applications that handle a single line using its single channel because ISDN hardware is not yet widespread. In POTS, an application that wants to transmit data would communicate over one line, and a voice application would communicate over another line—both of these applications could use the same line, but if so, not at the same time.

In general, one line has exactly one address (telephone number). In cases where lines carry two or more channels, each channel may have its own address, which means that a line has as many addresses as it has channels. TAPI assigns Address IDs to these different addresses to make it easier to manipulate them.


Multiple Addresses on a Single Channel

Some installations support the assignment of more than one address to a single channel. On POTS lines, multiple addresses are made possible by various systems, such as "DID" (direct inward dialing) or "distinctive ringing," which are extra-fee services provided by the telephone company.

Many large corporations use DID for incoming calls. Before a call is connected, its destination extension number is signaled to the PBX, which causes the extension to ring instead of the operator's phone. An example of distinctive ringing in a private home would be if the parents used one address, the children another, and a fax machine a third. Because only one line connects the house to the telephone network, all phones ring when a call appears, but the ring pattern will be different depending on the number dialed by the calling party. With distinctive ringing, the people know who the incoming call is meant for, and the fax machine answers its calls by recognizing its own ringing style.

In ISDN, the various B channels might not have separate addresses. Because these B channels might be on the same address, it is the service provider (and not the application or a person who has dialed the number) that assigns calls to these channels.


ISDN Subaddresses

Subaddressing is a capability provided on ISDN lines that allows more information than just a single telephone number to be used when dialing. This additional information may specify an individual telephone extension to ring or, in a computing environment, a particular application to be alerted. Other parameters that can be passed can describe the required aspects of a requested modem connection, such as rate and timing.


Addresses and Address Identifiers

Each line device is assigned one or more addresses. An address corresponds to a telephone directory number, and it is actually assigned twice: First, by the telephone company at the switch, and second, by the user while configuring the local system. If a telephone number is changed at the switch, the user will normally need to assign the new number at the local system, although some systems may be sophisticated enough to perform the reassignment without human control.

After addresses have been assigned to lines, TAPI assigns address IDs to addresses. An address ID is a number between 0 and the number of addresses on the line minus one. Because each address depends on its line to exist, the address's ID is meaningful only in the context of the associated line device. For this reason, an address name consists of not only the address ID, but also an identifier of the line. It serves as a kind of shorthand, an easy way for programmers to identify addresses.


Address Configurations

The relationship of an address to a line (and to other local addresses) is known as its configuration. The network or switch can configure address-to-line assignments in several ways. The main types of address configurations recognized by TAPI are:

1.	Private. The address is assigned to one line device only. An inbound call for this address is offered (the switch informs the desktop computer of an incoming call) at one line device only.

2.	Bridged. A bridged address is a single address assigned to more than one line device. (Different switch vendors have different names for address bridging, such as "multiple appearance directory number" (MADN), "bridged appearance," or "shared appearance.") An incoming call on a bridged address will be offered on all lines associated with the address. The network of lines connected together is known as the "bridge." Different variations of bridged behavior are possible:

•	Bridged-Exclusive. Connecting one of the bridged lines to a remote party causes the address to appear "in use" to all other members of the bridge.

•	Bridged-New. Connecting one of the bridged lines to a remote party does not preclude the other lines from using the bridged address to answer or make calls. However, a new call appearance is allocated to another of the connected lines.

•	Bridged-Shared. If one line is connected to a remote party, other bridged lines that use the address automatically enter into a multi-party conference call on the existing call.

3.	Monitored. The line indicates the busy or idle status of the address, but the line cannot use the address for answering or making calls.


Address-Related Functions and Messages

Different line devices may have different capabilities and so may their addresses. Additionally, switching features and capabilities may be different for different addresses. An application calls the function lineGetAddressCaps to determine the telephony capabilities of each address and then receives this information in a data structure of the type LINEADDRESSCAPS. In a similar way, an application can call LineGetDevCaps for a line device to determine the number of addresses assigned to the line, as well as other information.

TAPI's device-query capability and status and event reporting mechanisms give an application the information it needs to manage the different kinds of bridged-address arrangements. For example, the application can determine whether a bridged station has answered a call by tracking the status changes and call-state event changes on the address. (Call states are explained in Appendix C, "Call States and Events.")

Normally, addresses on a line device are identified by their address IDs. However, TAPI lets applications that make outgoing calls use alternate address types for the originating address, such as dialable format (see the following section), or naming mechanisms specific to a given service provider. This can be accomplished through API extensions that are based on switch-assigned station IDs. A useful function for this purpose is lineGetAddressID, which retrieves the ID of an address specified in an alternate format.


Address Formats

Each address ID corresponds to a directory number through which incoming calls can be placed to the address. Similarly, making outbound calls typically requires that a directory number—the address—be supplied to identify the party being called.


Storing Numbers in Electronic Address Books

Many users choose to dial people, fax machines, bulletin boards, and other entities by selecting their names from an address book. The actual number that is dialed depends on the geographic location of the user and the way the line device to be used is connected. For example, a desktop computer may have access to two lines, one connected to a PBX, the other to the telephone company's central office. When making a call to the same party, different numbers may have to be used. (To dial through the PBX, for example, the computer may need to dial '9' to "get out," or a different prefix may be needed for a call made through the central office.) Or, a user may make calls from a portable computer and want to use a single, static address book even when calling from different locations or telephony environments. TAPI's address translation capabilities let the user inform the computer of the current location and the desired line device for the call. TAPI then handles any dialing differences, requiring no changes to the user's address book. An application uses the lineTranslateAddress function to convert an address from the canonical address format to the dialable address format (see the next section).

A related topic is the handling of international call progress monitoring, which is the process of listening for audible tones such as dialtone, special information tones, busy signals, and ringback tones to determine the state of a call (its "progress" through the network). Because the cadences and frequencies of call-progress tones vary from country to country, the service provider must know what call progress to follow when making an international outbound call. Therefore, applications specify the destination country code when placing outgoing calls.


Canonical Addresses

The canonical address format is intended to be a universally constant directory number. For this reason, numbers in address books are best stored using canonical format. A canonical address is an ASCII string with the following structure:

+ CountryCode Space [(AreaCode) Space] SubscriberNumber | Subaddress ^ Name CRLF ...

The components of this structure are given in the following table:

+	Equivalent to ASCII Hex (2B). It indicates that the number that follows it uses the canonical format.
CountryCode	A variably sized string containing one or more of the digits 0-9. The CountryCode is delimited by the following Space. It identifies the country in which the address is located.
Space	Exactly one ASCII space character (0x20). It is used to delimit the end of the CountryCode part of an address.
AreaCode	A variably sized string containing zero or more of the digits 0-9. AreaCode is the area code part of the address and is optional. If the area code is present, it must be preceded by exactly one ASCII left parenthesis character (0x28), and be followed by exactly one ASCII right parenthesis character (0x29) and one ASCII Space character (0x20).
SubscriberNumber	A variably sized string containing one or more of the digits 0-9. It may include other formatting characters as well, including any of the dialing control characters described in the Dialable Address Format:
	AaBbCcDdPpTtWw*#!,@$?
	The subscriber number should not contain the left parenthesis or right parenthesis character (which are used only to delimit the area code), nor should it contain the "|", "^", or CRLF characters (which are used to begin following fields). Most commonly, non-digit characters in the subscriber number would include only spaces, periods ("."), and dashes ("-"). Any allowable non-digit characters which appear in the subscriber number will be omitted from the DialableString returned by the lineTranslateAddress function, but will be retained in the DisplayableString.
|	ASCII Hex (7C). If this optional character is present, the information following it up to the next + | ^ CRLF, or the end of the canonical address string is treated as subaddress information, as for an ISDN subaddress.
Subaddress	A variably sized string containing a subaddress. The string is delimited by + | ^ CRLF or the end of the address string. During dialing, subaddress information is passed to the remote party. It can be such things as an ISDN subaddress or an email address.
^	ASCII Hex (5E). If this optional character is present, the information following it up to the next CRLF or the end of the canonical address string is treated as an ISDN name.
Name	A variably sized string treated as name information. Name is delimited by CRLF or the end of the canonical address string and may contain other delimiters. During dialing, name information is passed to the remote party.
CRLF	ASCII Hex (0D) followed by ASCII Hex (0A), and is optional. If present, it indicates that another canonical number is following this one. It is used to separate multiple canonical addresses as part of a single address string (inverse multiplexing).
	For example, the canonical representation of the main switchboard telephone number at Microsoft Corporation would be:
	+1 (206) 882-8080


Dialable Addresses

The dialable address format describes a number that can be dialed on the given line. A dialable address contains part addressing information and is part navigational in nature. Any input string which does not begin with a "+" character is presumed to be not in canonical format and therefore in dialable address format, and is returned to the application unmodified. A dialable address is an ASCII string with the following structure:

DialableNumber | Subaddress ^ Name CRLF ...

where:

DialableNumber	digits and modifiers 0-9 A-D * # , ! W w P p T t @ $ ? ; delimited by | ^ CRLF or the end of the dialable address string. The plus sign (+) is a valid character in dialable strings. It indicates that the phone number is a fully-qualified international number.
	Within the DialableNumber, note the following definitions:
	0-9 A-D * #  ASCII characters corresponding to the DTMF and/or pulse digits.
!	ASCII Hex (21). Indicates that a hookflash (one-half second on hook, followed by one-half second off-hook before continuing) is to be inserted in the dial string.
P p	ASCII Hex (50) or Hex (70). Indicates that pulse dialing is to be used for the digits following it.
T t	ASCII Hex (54) or Hex (74). Indicates that tone (DTMF) dialing is to be used for the digits following it.
,	ASCII Hex (27). Indicates that dialing is to be paused. The duration of a pause is device specific and can be retrieved from the line's device capabilities. Multiple commas can be used to provide longer pauses.
W w	ASCII Hex (57) or Hex (77). An uppercase or lowercase W indicates that dialing should proceed only after a dial tone has been detected.
@	ASCII Hex (40). Indicates that dialing is to "wait for quiet answer" before dialing the remainder of the dialable address. This means to wait for at least one ringback tone followed by several seconds of silence.
$	ASCII Hex (24). It indicates that dialing the billing information is to wait for a "billing signal" (such as a credit card prompt tone).
?	ASCII Hex (3F). It indicates that the user is to be prompted before continuing with dialing. The provider does not actually do the prompting, but the presence of the "?" forces the provider to reject the string as invalid, alerting the application to the need to break it into pieces and prompt the user in-between.
;	ASCII Hex (3B). If placed at the end of a partially specified dialable address string, it indicates that the dialable number information is incomplete and more address information will be provided later. ";" is only allowed in the DialableNumber portion of an address.
|	ASCII Hex (7C), and is optional. If present, the information following it up to the next + | ^ CRLF, or the end of the dialable address string is treated as subaddress information (as for an ISDN subaddress).
Subaddress	A variably sized string containing a subaddress. The string is delimited by the next + | ^ CRLF or the end of the address string. When dialing, subaddress information is passed to the remote party. It can be for an ISDN subaddress, an email address, and so on.
^	ASCII Hex (5E), and is optional. If present, the information following it up to the next CRLF or the end of the dialable address string is treated as an ISDN name.
Name	A variably sized string treated as name information. Name is delimited by CRLF or the end of the dialable address string. When dialing, name information is passed to the remote party.
CRLF	ASCII Hex (0D) followed by ASCII Hex (0A). If present, this optional character indicates that another dialable number is following this one. It is used to separate multiple dialable addresses as part of a single address string (for inverse multiplexing).
The lineTranslateAddress function and related support functions are used to translate an address from canonical format to dialable format. An application might not use this function to dial a number but it might use it to generate and display for verification a number that could be dialed. Also, it can compute the local time at the destination address from the country code and area code.

The application uses lineTranslateAddress to specify both the line device upon which it intends to dial the call and a canonical address, and the function returns the dialable number and the country code. Because the line device may have specific dialing requirements, it is part of the context needed for an accurate translation.

The user's location also plays a role in address translation. Information related to the current location, such as the country code, area code, and outside line access codes is entered by the user through the Telephony applet in the Control Panel. The Subaddress and Name fields, if present in the address, are unmodified by the translation. Alphabetic characters in the number, such as in 1-800-FOR-TAPI, are not translated by the lineTranslateAddress function due to the different standardizations in use in different countries, but they may be translated by applications themselves.

Although an application can use dialable addresses returned by lineTranslateAddress, it is not limited to them and can compose its own dialable numbers.


Initialization and Shutdown

For an application to use any of TAPI's basic or supplementary line functions, it needs a connection to TAPI.DLL through which it can receive messages. The application establishes this connection, using either the lineInitialize or the phoneInitialize function. One of the parameters passed to TAPI in these function calls is a pointer to the application's callback function. After initialization, TAPI uses this pointer to notify the application of the asynchronous completion of functions and other events occuring on devices which the application has opened. Following are specifics about the initialization process:

•	The initialization functions are not device-related. When an application calls an initialization function, TAPI does not act on a line or phone device or an abstraction thereof.

•	The first time an initialization function is called in a telephony session, TAPI also sets up the telephony environment. Among the tasks it performs are loading TAPI.DLL and TAPIEXE.EXE, and loading the device drivers (Telephony service providers and ancillary components) specified in TELEPHON.INI. In addition, the communication link described above is established between TAPI and the calling application. After environment-related tasks are completed, calling an initialization function only passes a pointer to a callback function.

•	The INIFILECORRUPT error can be returned if TAPI.DLL determines that the TELEPHON.INI contains an invalid entry. When this error occurs (in lineInitialize and phoneInitialize, or another function), the user should identify and resolve the problem. It may be necessary to rebuild the entire INI file or a portion of it, which can be done through the Telephony Control Panel.

For example, the LINEERR_NODRIVER ("the driver was not installed") error indicates either that a service provider that was previously installed can no longer be found or that some subsidiary component of a service provider (such as a VxD) cannot be found. When this error is encountered, the application should advise the user to correct the problem with the Driver Setup function within the Telephony Control Panel.

•	Although each application needs only one callback function, it can call an initialization function more than once to specify other callback functions.

•	The functions lineInitialize and phoneInitialize are the only two callbacks defined in TAPI. This means that they are the only two functions that can pass the pointer of a callback function to TAPI. All subsequent TAPI functions, when completing asynchronously, result in calls to this callback function. (There is one exception: In Assisted Telephony, the functions tapiRequestMediaCall and tapiRequestDrop use Windows messages to return call statuses to the application that is placing the call.)

•	Both lineInitialize and lineShutdown (and the corresponding phone functions) operate synchronously. That is, these functions return a success or failure indication, not an asynchronous Request ID. They cannot finish asynchronously because, at the time they are called, TAPI has no pointer to use for sending messages to the application. Not until they complete is this pointer (to a callback function) available to TAPI.

Upon completion, the lineInitialize function returns two pieces of information to the application: an application handle and the number of available line devices.

•	The application handle represents the application's usage of TAPI. That is, to TAPI, it represents the application. TAPI functions that use line or call handles (explained later in this chapter) do not require the application handle, because this handle is derived from the specified line, phone, or call handle.

•	The lineInitialize function also returns the number of line devices available to the application through TAPI. Line devices are identified by their device identifier (device ID). Valid device IDs range from zero to one less than the number of line devices. For example, if lineInitialize reports that there are two line devices in a system, the valid line-device IDs are 0 and 1.

Once an application is finished calling TAPI's line functions, it calls lineShutdown and passes its application handle to terminate its usage of TAPI. This allows TAPI to free any resources assigned to the application.


Calls

Unlike line devices and addresses, calls are dynamic. A call represents a connection between two (or more) addresses. The originating address (the caller) is the address from which the call originates, and the destination address (the called) identifies the remote end point or station with which the originator wishes to communicate.

Zero, one, or more calls can exist on a single address at any given time. A familiar example of multiple calls on a single address is call waiting: During a conversation with one party, a subscriber with call waiting is alerted that another party is trying to call. The subscriber can flash the phone to answer the second caller (which automatically places the first party on hold) and then toggle between the two parties by flashing. In this example, the subscriber has two calls on one address on the line. Since the person at the telephone handset can be talking to only one remote party at a time, only one call is active per line at any point in time. The telephone switch keeps the other calls on hold. With a line able to encompass more than one channel, different configurations can allow multiple active calls on a line at the same time.


Call Handles

TAPI identifies a specific call by means of the call's handle, and TAPI.DLL assigns call handles as required. One call handle exists for every call owned or monitored by an application, and an application can obtain call handles in a number of well defined ways. Certain TAPI functions create new calls. As they do so, they return any new call's handle to the application. Sometimes, call handles are provided unsolicited in callbacks made to the application from TAPI.DLL, as is the case with inbound calls or calls being handed off by other applications.

For every call, one handle exists per application—unique call handles are provided to each application by TAPI. This means that different applications with handles to the same call use different handles for it, which limits the scope of a call handle to a single application. In addition, the service provider may assign a unique call ID to a call (unrelated to the call's handle), which is used to track the call across transfers. Whether or not a service provider can assign call IDs to calls is a device capability.

The privileges of an application for a given call are maintained by TAPI.DLL and are not the property of an application's handle for the call. (For information about call privileges, see Chapter 6, "TAPI Applications.") Resources such as memory are allocated dynamically for each call for each application that is given a handle to the call. These resources are not automatically deallocated when the call is dropped since the application may still find it useful to extract information from the call (such as for logging purposes). Therefore, applications must dispose of their call handle when they have finished using it by calling the lineDeallocateCall function.


Version Negotiation

Over time, different versions may exist for TAPI.DLL, applications, and service providers for a line or phone. New versions may define new features, new fields to data structures, and so on. Version numbers therefore indicate how to interpret various data structures.

To allow optimal interoperability of different versions of applications, versions of TAPI.DLL itself, and versions of service providers by different vendors, TAPI provides a simple, two-step version negotiation mechanism for applications. Two different versions must be agreed on by the application, TAPI.DLL, and the service provider for each line device. The first is the version number for Basic and Supplementary Telephony and is referred to as the API version. The other is for provider-specific extensions, if any, and is referred to as the extension version. The format of the data structures and data types used by TAPI's basic and supplementary features is defined by the API version, while the extension version determines the format of the data structures defined by the vendor-specific extensions.

Version negotiation proceeds in two phases. In the first phase, the API version number is negotiated and the extension ID associated with any vendor-specific extensions supported on the device is obtained. In the second phase, the extension version is negotiated. If the application does not use any API extensions, it skips the second phase and extensions are not activated by the service provider. If the application does wish to use extensions, but the service provider's extensions (the extension ID) are not recognized by the application, the application should skip the negotiation for extension version as well. Each vendor has its own set of legal (recognized) versions for each set of extension specifications it distributes.

The lineNegotiateAPIVersion function is used to negotiate the API version number to use. It also retrieves the extension ID supported by the line device, returning zeros if no extensions are supported. With this function call, the application provides the API version range it is compatible with. TAPI.DLL in turn negotiates with the line's service provider to determine which API version range it supports. TAPI.DLL next selects a version number (typically, although not necessarily, the highest version number) in the overlapping version range that the application, the DLL, and the service provider have supplied. This number is returned to the application, along with the extension ID that defines the extensions available from that line's service provider.

If the application wishes to use the extensions defined by the returned extension ID, it must first call lineNegotiateExtVersion to negotiate the extension version. In a similar negotiation phase, the application specifies the already-agreed-upon API version and the extension version range it supports. TAPI.DLL passes this information to the service provider for the line. The service provider checks the API version and the extension version range against its own, and selects the appropriate extension version number, if one exists.

When the application later calls lineGetDevCaps, it returns a set of device capabilities for the line that correspond to the results of version negotiation. These include the line's device capabilities consistent with the API version and the line's device-specific capabilities consistent with the extension version. The application must specify both of these version numbers when it opens a line. At that point, the application, the DLL, and the service provider are committed to using the agreed-upon versions. If device-specific extensions are not to be used, the extension version should be specified as zero.

In an environment where multiple applications open the same line device, the first application to open the line device selects the versions for all future applications that wish to use the line (service providers do not support multiple versions simultaneously.) Similarly, an application that opens multiple line devices may find it easier to operate all line devices under the same API version number.


TAPI Applications

About TAPI Applications

This chapter explains what you need to know to program basic telephonic functionality using the line-device class functions.


Establishing a Link

Before an application can call the functions of Windows Telephony for using a line device, it must take the following steps:

•	Initialize the TAPI environment and TAPI's functions (enable function callbacks) with an initialization function. Invoking this function also informs the application of the number of line devices available.

•	Negotiate the API version, and if necessary, negotiate the Extensions version.

An application must take the preceding steps for each line device it intends to use. Each line initialization gives TAPI dynamic link library a pointer to callback function within the application that uses the line.

Applications should not invoke phoneInitialize without subsequently opening a phone (at least for monitoring). If the application is not monitoring and not using any devices, it should call phoneShutdown so that memory resources allocated by the TAPI dynamic link library can be released if unneeded, and library itself can be unloaded from memory while not needed.


Opening Lines

After having obtained the capabilities of a line, an application must open the line device before it can access telephony functions on that line. (Because a line device is an abstraction of a line as defined by Telephony, "opening a line" and "opening a line device" can be used interchangeably.) When a line device has been opened successfully, the application receives a handle for it. The application can then use that line to take inbound calls, make outbound calls, or monitor call activities on the line for logging purposes.

To open a line device for any purpose—monitoring or control—the application calls the function lineOpen. (Later, when the application is finished with the line device, it can close it with lineClose.)

The function lineOpen can be invoked in one of two ways:

•	A specific line device is selected by means of its line-device ID (the parameter dwDeviceID). The lineOpen request will open the specified line device. Applications interested in handling inbound calls typically use specific line devices because the application has been notified which line is carrying or is expected to carry the inbound call. When a line device has been opened successfully, the application is returned a handle representing the open line.

•	The application can specify that it wants to use any line device that has certain properties. In this case, the application uses the value LINEMAPPER instead of a specific line-device ID as a parameter for lineOpen. The application also specifies which properties it needs on the call in parameters to lineOpen. The function opens any available line device that supports the specified call parameters. This attempt, of course, may fail. If successful, the caller can determine the line-device ID by calling lineGetID, specifying the handle (lphLine) to the open line device returned by lineOpen.

An application that has successfully opened a line device can use it to make an outbound call except when the line supports only inbound calls.


Selecting One or More Lines

An application can open one or more lines for various purposes. For example, it can open one line for monitoring calls and another line for making outgoing calls. If several lines are available, the application can choose to open any or all of them. To decide which of several line devices to use, determine the capabilities of each one with lineGetDevCaps. This tells whether the line supports the functionality needed by the calls to be made or received—such as their required media mode. This function is also used to get the name of the line.

Because opening a line merely means obtaining a handle to the line (hLine) with a given privilege, an application can obtain more than one handle to the same line. In other words, an application can open the same line many times, also called opening different instances of the line. For example, a line may simultaneously be opened once for monitoring calls, a second time for accepting incoming calls as their owner, and a third time for making outgoing calls.

After choosing a suitable line (or lines), the application uses lineOpen, either specifying a certain line or using LINEMAPPER, as explained in the previous section.


Specifying Media Modes

The ability of an application to deal with inbound calls or to be the target of call handoffs on a line is determined by the value used for the dwMediaModes parameter of the lineOpen function. With this function, the application indicates its interest in monitoring calls or receiving ownership of inbound calls of one or more specific media modes, or of any (unspecified) media mode, as described in the following cases:

•	An inbound call of a certain media mode is given to the application that has opened the line device for that particular media mode. A single application may specify multiple flags simultaneously to handle multiple media modes.

•	An application that wants to handle calls for which the actual media mode present has not yet been determined would turn on the unknown media bit as a parameter of lineOpen.

•	An application that wants to handle calls of any media mode would indicate this capability by turning on all of the media bits that are supported on the line (which can be obtained from LINEDEVCAPS).

All applications that have opened a line device in any mode are notified about certain general statuses and events occurring on the line device or its addresses. These include the line being taken out of service, the line going back into service, the line being under maintenance, an address coming in use or going idle, and an open or close operation being executed on the line. An application that does not care about certain message can use the lineSetStatusMessages function to filter the message. Most such status messages are disabled by default; an application would need to call lineSetStatusMessages to enable them.

The media modes specified with lineOpen add to the default value for the provider's media mode monitoring for initial inbound call type determination. This means that the dwMediaMode settings of all applications with the line open are "or'd" together, and that union becomes the default media detection on the line. The lineMonitorMedia function modifies the mask that controls LINE_MONITORMEDIA messages but does not affect the default media detection enabled on new incoming calls. It is necessary for an application using lineMonitorMedia to call it to establish media monitoring on every new call in which it is interested.


Requesting Call Privileges

In addition to media mode, an application can specify the call privileges it wants for the calls provided to it. With privileges, an application specifies whether it wants to monitor calls or own them. For an inbound call, only one application is selected as the owner, although all applications with monitor interest in the call are also notified about the incoming call. The usual privileges an application specifies are summarized in the following list:

•	If the application only wants to monitor calls, it specifies LINECALLPRIVILEGE_MONITOR. The application will also receive monitor handles to outgoing calls placed by other applications (an application receives owner handles for outgoing calls it places itself). It will also receive MONITOR handles for calls it places itself on other instances of the same line.

•	If the application wants to make outbound calls only, it specifies LINECALLPRIVILEGE_NONE. An application that has NONE selected will not be automatically informed of incoming calls. However, it can also become aware of calls on the line with LINE_ADDRESSSTATE(numCalls) or LINEDEVSTATE(numCalls) messages. It can then call lineGetNewCalls.

•	If the application wants to accept incoming calls of a specific media mode (or modes), it specifies LINECALLPRIVILEGE_OWNER and one or more relevant LINEMEDIAMODE_ settings.

•	If the application is willing to control unclassified calls (incoming calls of as-yet unknown media mode), it specifies LINECALLPRIVILEGE_OWNER and LINEMEDIAMODE_UNKNOWN.

•	In other cases, the application should specify the media mode it is interested in handling and set dwPrivilege to LINECALLPRIVILEGE_OWNER.

An application that wants to be informed of all calls on the line regardless of whether it can become an owner on the call can set both the LINECALLPRIVILEGE_OWNER and LINECALLPRIVILEGE_MONITOR bits. It will get call handles with owner privileges for incoming calls for which it is the highest priority application for the highest priority media mode on the call, and monitor privileges for all other incoming and outgoing calls.

An application that has successfully opened a line device can always initiate calls using lineMakeCall, lineUnpark, linePickup, lineSetupConference (with a NULL hCall parameter), as well as use lineForward (assuming that doing so is allowed by the device capabilities, line state, and so on).


Application Priority

Conflicts can arise if multiple applications open the same line device for the same media mode. These conflicts are resolved with a priority scheme by which the user assigns relative priorities to the applications. This is usually done through a Control Panel applet or a Preferences menu in a telephonic application. Note the following points about this mechanism:

•	Only the highest priority application for a given media mode ever receives ownership (unsolicited) of a call of that media mode.

•	Although ownership is usually received when an inbound call first arrives or when a call is handed off, any application (including a lower priority one) can later acquire ownership by using the function lineGetNewCalls or lineGetConfRelatedCalls.

The user can assign relative priorities to the modules (the applications and the DLLs) that use TAPI. The resulting configuration information is stored in a standard format in the TELEPHON.INI file. For more information about using TELEPHON.INI, see Appendix B, "Telephony Configuration Parameters."

For in-depth information about the way applications receive calls in a multi-application environment, see Chapter 8, "Multiple-Application Programming."


Using lineOpen

An application can open a number of lines as well as negotiating API and extension versions. The application can call the lineOpen function with LINECALLPRIVILEGE_MONITOR privilege, meaning that it will only monitor, not own, incoming calls on all the lines opened.

An application could open a line with the intent of owning incoming calls by specifying LINECALLPRIVILEGE_OWNER as the privilege and a media mode other than NONE. The application could actually specify a number of media modes in this parameter by "or-ing" the bit flags for each of the desired media modes. In that case, the application would be notified of incoming calls in any of the specified media modes, and it receives those calls as their owner. (Actually, another application that is also registered to receive calls of that media mode would receive the call instead, if it has a higher priority as designated in the TELEPHON.INI file.) This notification arrives in a call-state message that specifies, among other information, which line is carrying the incoming call. For example, by specifying LINEMEDIAMODE_INTERACTIVEVOICE, the application would be notified of incoming calls of the interactive voice media type (voice calls with a person on the local end of the line).


Preparing to Accept Assisted Telephony Requests

An application to be used as a recipient of Assisted Telephony requests must register its ability to do so. This is done with the lineRegisterRequestRecipient function, in which TRUE is specified as the value for the parameter bEnable. (Specifying FALSE de-registers the application as a request recipient, which it should do when it has determined that its recipient duties are through for the current session.)

When registering, the application must also specify the type(s) of request it can handle. Possible values of requests are LINEREQUESTMODE_MAKECALL, to show that the application will handle tapiRequestMakeCall requests. For more information about servicing Assisted Telephony requests, see the section "Performing Request Recipient Duties" later in this chapter.


Receiving Information

An application receives information in two ways: solicited and unsolicited. Solicited information is requested by the application through a function call such as lineGetDevCaps or lineGetAddressCaps. Unsolicited information arrives in the form of messages—most importantly call-state messages. Often, the two mechanisms are used together, as when an application receives a LINE_CALLSTATE message, after which it checks the information contained in the LINECALLINFO structure by calling lineGetCallInfo.

An application can call lineGetDevCaps to learn more about available lines. The application determines the names of the lines and the number of addresses on those lines. (An important factor in the configuration of lines and addresses is the way the service provider chooses to map lines and addresses. Though the application has no control over this mapping, it can determine the details of the mapping by calling functions such as lineGetDevCaps.) Later, using this information, the application could allow the user to choose which line (and address) to use for an outgoing call, restricting the lines it displays (in a dialog box, for example) to those that support a specific media mode. As an example, an application designed to be used only for faxing may choose to let the user select only lines that support fax transmission.

Call lineGetAddressCaps to obtain information for a given address. The application can use the names of the addresses to let the user choose them in a popup menu, but other information is also reported, such as whether caller-ID is supported, what kinds of call states can be produced, and how many active calls can exist on that address.


Changes in the Status of a Line Device

The status of a line device can change for many reasons, some as a result of requests submitted by the local application, and some as a result of actions performed by the switch or by the application (or person) at the other end of the connection.

In either case, an application is notified about these changes with the LINE_LINEDEVSTATE callback message, which indicates the status item (the attribute of the line device) that has changed. The application can choose the line status items for which it wants to be notified using the function lineSetStatusMessages. The messages controlled by invoking lineSetStatusMessages are LINE_LINEDEVSTATE and LINE_ADDRESSSTATE.

In addition, an application can determine the current status of an address by calling lineGetAddressStatus, which returns its information in a structure of the type LINEADDRESSSTATUS. It can also see the complete status of the specified open line device by calling lineGetLineDevStatus, which returns its information in a structure of the type LINEDEVSTATUS.


Callback and Call State Functions

When a TAPI application initializes its connection to the line service with the function lineInitialize, it gives a pointer to the callback function it uses for that line service. This pointer applies to all lines subsequently opened with the same application handle. The callback function obtains a large amount of information for the application, including asynchronous replies, indications of Assisted Telephony requests, or messages resulting from ongoing monitoring of a line. These messages include indications that the status of a line, address, or call has changed; indication that media, tone, or digit monitoring has detected the requested event; and indication that information about a call has changed.

The callback function does not ned to support all messages. Unsupported messages are the ones whose names are immediately followed by a break statement. For example:

case LINE_GATHERDIGITS:
   break;

You can enhance functionality by enabling it to handle these unsupported call-state messages.

To keep the size of the callback function manageable, the processing of call-state messages is performed in separate functions which respond to all call-state messages received by the application. It is in these functions that call-state transitions (such as from connected to idle) are made known as notification of the actual call states.


Receiving Calls

After an application has opened a line device and, while doing so, registered a privilege other than none, and a media mode, it is notified when a call arrives on that line. Specifically, applications that have the line open with LINECALLPRIVILEGE_MONITOR will receive a LINE_CALLSTATE message for every call that arrives on the line. An application that has opened the line with LINECALLPRIVILEGE_OWNER receives a LINE_CALLSTATE message only if it has become an owner of the call or is the target of a directed handoff. In this notification, TAPI gives the application a handle to the incoming call, and the application keeps this handle until the application deallocates the call.

Applications are informed of call arrivals and all other call-state events with the LINE_CALLSTATE callback message. This message provides the call handle, the application's privilege to the call, and the call's new state. For an unanswered inbound call, the call state is offering. An application can invoke lineGetCallInfo to obtain information about an offering call before accepting it. This function call also causes the call information in the LINECALLINFO data structure to be updated. By knowing the call state and other information, the application can determine whether the call needs to be answered.

The call information stored in LINECALLINFO includes, among other things, the following items:

•	bearer mode, rate  This is the bearer mode (voice, data) and data rate (in bits per second) of the call, for digital data calls.

•	media mode  The current media mode of the call. Unknown is the mode specified if this information is unknown, and the other set bits indicate which media modes might possibly exist on the call. For more information about this, see Chapter 8, "Multiple-Application Programming."

•	call origin  Indicates whether the call originated from an internal caller, an external caller, or an unknown caller.

•	reason for the call  Describes "why" the call is occurring. Possible reasons are:

•	direct call

•	transferred from another number

•	busy—forwarded from another number

•	unconditionally forwarded from another number

•	the call was picked up from another number

•	a call completion request

•	a callback reminder

The reason for the call is given as unknown if this information is not known.

•	caller-ID  Identifies the originating party of the call. This can be in a variety of (name or number) formats, determined by what the switch or network provides.

•	called-ID  Identifies the party originally dialed by the caller.

•	connected-ID  Identifies the party to which the call was actually connected. This may be different from the called party if the call was diverted.

•	redirection-ID  Identifies to the caller the number towards which diversion was invoked.

•	redirecting-ID  Identifies to the diverted-to user the party from which diversion was invoked.

•	user-to-user information  User-to-user information sent by the remote station (ISDN).

The LINE_CALLSTATE message also notifies monitoring applications about the existence and state of outbound (and inbound) calls established by other applications or established manually by the user—for example, on an attached phone device (if the telephony hardware and the service provider support monitoring of actions on external equipment). The call state of such calls reflects the actual state of the call as follows: An inbound call for which ownership is given to another application is indicated to the monitor applications as initially being in the offering state. An outbound call placed by another application would normally first appear to the monitoring applications in the dialtone state.

The fact that a call is offered does not necessarily imply that the user is being alerted. Once alerting (ringing) has begun, a separate LINE_LINEDEVSTATE callback message is sent with a ringing indication to inform the application. It may be necessary, in some telephony environments, for the application to accept the call (with lineAccept) before ringing starts. The application can determine whether or not this is necessary by checking the LINEADDRCAPFLAGS_ACCEPTTOALERT bit.

Depending on the telephony environment, not all the information about a call may be available at the time the call is initially offered. For example, if caller ID is provided by the network between the first and second ring, caller ID will be unknown at the time the call is first offered. When it becomes known shortly thereafter, a LINE_CALLINFO callback message notifies the application about the change in party-ID information of the call.


Incoming Calls and Line Privileges

An application cannot refuse ownership of a call for which it receives an owner handle. Whether the call is delivered to the application with owner or monitor privileges is decided before the call arrives—at the time the application opens the line on which the call is established by the remote caller.

If the application opens the line with lineOpen with the parameter dwPrivilege set to LINECALLPRIVILEGE_MONITOR, it automatically receives a handle with monitoring privileges for all incoming calls on the line. It can then choose to become an owner by calling lineSetCallPrivilege. The fact that it indicated MONITOR when it opened the line does not prevent it from later becoming an owner with lineSetCallPrivilege or by originating a call with lineMakeCall (an application is always an owner of calls it places regardless of the privilege specified with lineOpen).

When an incoming call has been offered to an application and the application is an owner of the call, the application can answer the call with lineAnswer. Once the call has been answered, its call state typically transitions to connected, at which time information can be exchanged over the call.

An application can receive handles to incoming calls only for monitoring. You can modify the application (specifically, the parameters for lineOpen) to change the privileges with which it initially opens lines.


Securing a Call

If a new call arrives while another call exists on the line or address, similar notification and call information may be supplied following the same mechanism as for any incoming call. If an application does not want any interference by outside events for a call from the switch or phone network, it should secure the call. Securing a call can be done at the time the call is made with a parameter to lineMakeCall, or later (when the call already exists) with lineSecureCall. The call will be secure until the call is disconnected. Securing a call may be useful, for example, when certain network tones (such as those for call waiting) could disrupt a call's media stream, such as fax.


Logging Call Information

An application can call the function lineGetCallInfo to obtain information about a call. Although this function fills the LINECALLINFO structure with a large amount of data, applications need to maintain other items, such as the start and stop time of the call.

Developers of applications that log call information should note the following guidelines when designing those applications:

•	Free the call's handle (hCall) when the call goes idle—that is, when a LINECALLSTATE_IDLE message is received for the call. At any point in the call's existence prior to its deallocation, monitoring applications can retrieve information about the call.

•	To keep the call's log sheet complete, log the fact that the call has gone idle.

•	Some applications may also need to update the user interface to show that important events have occurred, such as the fact that a fax is being received. This functionality is driven by the call-state messages received in the newCallState routine described earlier in this chapter.

For more information about call logging, see Chapter 8, "Multiple-Application Programming."


Establishing a Call

Once an application has determined that a given line offers the needed set of capabilities, and then opens that line, it can access telephony functions for either incoming or outgoing calls on the line. The usual way to place a call on that line is to invoke lineMakeCall, specifying the line handle and a dialable destination address.


Address Translation

Applications can provide users with location independence and take advantage of calling-card information managed by Windows Telephony by storing telephone numbers in the Canonical address format. Before a Canonical address can be used in placing a call, it must be converted (translated) into the Dialable address format using the lineTranslateAddress function.

To do this, the lineTranslateAddress function starts by examining the settings in TELEPHON.INI to find the user's location, including the country and area code. It then produces a valid dialing sequence by removing unnecessary portions of the number (such as the country code or area code) and adding other digits such as a long distance prefix or a digit used to dial out of a local PBX.

To avoid inadvertent misdialing, such as if the user has changed locations but has not yet informed Windows Telephony of the change, an application may want to present the output of this function call to the user in a dialog box. The user can then confirm the translated address or change it if it is incorrect.


Toll Lists

In some locations in North America, all calls placed to the local area code are local calls. In other locations, some calls placed to the local area code are long distance, and need a "1" to be dialed. The first three digits of the address (the prefix) determine whether or not a call within the local area code is a toll call.

A toll list is a list of prefixes in the local area code whose addresses must be dialed as long distance addresses, and are assessed long distance charges. With Windows Telephony, a toll list can be built in one of two ways:

1.	The user can add or remove prefixes manually with the the Telephony Control Panel.

2.	The user can add or remove prefixes dynamically after a telephone call to that prefix fails for one of these reasons: When the call was dialed, the "1" prefix was missing and necessary or present and unnecessary. This dynamic process works as follows:

The application knows by the value of the LINETRANSLATERESULT_INTOLLLIST and LINETRANSLATERESULT_NOTINTOLLLIST bits in the LINETRANSLATEOUTPUT structure (returned by lineTranslateAddress) whether an address with the dialed prefix is already in the toll list. The application can then let the user add or remove (whichever applies) this prefix from the toll list. Adding and removing are both peformed using the lineSetTollList function.


Dialing the Call

The lineMakeCall function first attempts to obtain a call appearance on an address on the line, then waits for a dial tone, and finally dials the specified address. (A call appearance is a connection to the switch over which a call can be made. Once the connection is established, the call appearance exists, even if no call is placed. After the call is established, the call appearance remains in existence until the call transitions to the idle state.) (If calls controlled by other applications exist on the line, these calls would normally have to be on hold, and would typically be forced to stay on hold until the application either drops its call or places it on hold.) If dialing is successful, a handle to a call with owner privileges is returned to the application.

Before invoking lineMakeCall, an application can set up parameters for the call and store them in the data structure LINECALLPARAMS. A pointer to this structure is then used as a parameter of lineMakeCall. In the fields of LINECALLPARAMS, the application can specify the quality of service requested from the network as well as a variety of ISDN call setup parameters. If no LINECALLPARAMS structure is supplied to lineMakeCall, a default POTS voice-grade call is requested with a set of default values. However, it is a good idea to use LINECALLPARAMS so that monitoring applications can report this call information (such as the identification of the called party) accurately.

The call's origination address also appears in LINECALLPARAMS. Using this field, the application can specify the address on the line where it wants the call to originate. It can do so by specifying an address ID, though in some configurations it is more practical to identify the originating address by its directory number.

Note  Do not mix function calls of the Telephony API with the functions of Assisted Telephony. The actions requested by lineMakeCall would happen automatically with the Assisted Telephony function calls tapiRequestMakeCall. But once an application has reached this state by using the calls of the Telephony API, it makes no sense to revert to an Assisted Telephony function call (such as tapiRequestMakeCall), because doing so would cause TAPI to repeat already performed actions. At this stage, therefore, simply calling lineMakeCall causes less overhead.

Once dialing is complete and the call is being established, it passes through a number of different states. These states (the progress of the call) are provided to the application with LINE_CALLSTATE callback messages. This mechanism lets the application track whether the call is reaching the called party. It is important that every telephony application base its behavior on the information received in these messages, and not on any other assumptions about a call's state. An application must not assume that a requested state change has occurred until notification of that state change arrives. Note that it can be helpful to display user-friendly interpretations of call states as indicators of a call's progress, especially for calls expected to pass through states slowly.

If special call setup parameters are to be taken into consideration, the application must supply them to lineMakeCall. Call setup parameters are required for actions such as the following:

•	requesting a special bearer mode, bandwidth, or media mode for the call,

•	sending user-to-user information (with ISDN),

•	securing the call,

•	blocking sending of caller ID to the called party,

•	taking the phone offhook automatically at the originator and/or the called party.


Calling Card Information

The importance of a "calling card" rests in the different dialing procedures required by the various calling cards. The routine FInitCallingCardInfo provides TAPI with the information it needs to display a dialog box, from which the user can choose a calling card. (The "calling card" numbered 0 means "use the default dialing rules for the country you are in.") The routine returns, among other information, the user's location (country and area code), the number of calling cards registered for this user in the TELEPHON.INI file, and the preferred calling card for that location. This calling card information is applied by the lineTranslateAddress function and does not happen automatically through lineMakeCall.

Typically, an application would prepare a menu choice for the user, such as whether to make a call with the default carrier, to override the default carrier and use a given calling code, or simply to use another specific dialing sequence.


Using Multiple Addresses Simultaneously

The dialable number format (dialing formats are described in Chapter Concepts of Line Devices) allows multiple destination addresses to be supplied at once. This ability can be useful if the service provider offers some form of inverse multiplexing by setting up calls to each of the specified destinations and then managing the information stream as a single high-bandwidth media stream. The application perceives this group of calls as a single call because it receives only a single call handle representing the aggregate of the individual phone calls.

It is also possible to support inverse multiplexing at the application level. To do this, the application would set up a series of individual calls and synchronize their media streams.


Delayed Dialing

The application can also use lineMakeCall to allocate a call appearance or to dial just part of the full number. Later, it can complete dialing using lineDial. When the number provided is incomplete, dialing some of the digits may be delayed by placing a ';' (semicolon) at the end of the number. The lineDial function is used in cases in which the application needs to send address information to the switch on an existing call, such as dialing the address of a party to which the call will be transferred.

Note  An application should make sure that "incremental dialing" (providing the number in small pieces) is supported before attempting to use it. This support is indicated by the LINEADDRCAPFLAGS_PARTIALDIAL bit in the dwAddrCapFlags field in the LINEADDRESSCAPS structure, which is returned by lineGetAddressCaps.

The main reasons for an application to use delayed dialing are if the ? character appears in a dialable address or if the service provider does not support one or more of the call progress detection control characters. These characters, which can occur in a dialable address, are W (wait for dial tone); @ (wait for quiet answer); and $ (wait for calling-card prompt tone). These and all other characters used in address strings are discussed in greater detail in Chapter 5, "Concepts of Line Devices."

The provider indicates which "wait for" dial string modifiers it supports in the following bits in the dwDevCapFlags field within the LINEDEVCAPS structure returned by lineGetDevCaps:

•	LINEDEVCAPFLAGS_DIALBILLING

•	LINEDEVCAPFLAGS_DIALQUIET

•	LINEDEVCAPFLAGS_DIALDIALTONE

The ? can be placed in the string (either directly by the application or by the address translator with the function lineTranslateAddress) if it is known that the user needs to listen for an undetectable tone before dialing can proceed. Every provider should treat ? as requiring the dial string to be "rejected."

The lineTranslateAddress function returns bits, in the dwTranslateResults field of the LINETRANSLATEOUTPUT structure, that indicate whether any of the four potentially offending modifiers occur in the dialable string output from that translation operation. These bits give the application an idea of whether the dialable string might need to be scanned for unsupported modifiers:

•	LINETRANSLATERESULT_DIALBILLING

•	LINETRANSLATERESULT_DIALQUIET

•	LINETRANSLATERESULT_DIALDIALTONE

•	LINETRANSLATERESULT_DIALPROMPT

If the application tries to send an unsupported modifier or a ? to the provider, it receives an error indicating which offending modifier occured first within the string:

•	LINEERR_DIALBILLING

•	LINEERR_DIALQUIET

•	LINEERR_DIALDIALTONE

•	LINEERR_DIALPROMPT

The application can choose to pre-scan dialable strings for unsupported characters. Or it can pass the "raw" string from lineTranslateAddress directly to the provider as part of lineMakeCall (or lineDial or any other function that passes a dialable address as a parameter) and then let the service provider generate an error to tell it which unsupported modifier occurs first in the string.

When the application is told (or finds) that an unsupported dial modifier is in the dialable string, it must take the following steps:

1.	Locate the offending modifier in the string;

2.	Isolate the characters occuring in the string to the left of the offending modifier;

3.	Append a semicolon to the end of the partial string;

4.	Reissue the dialing command using the partial string;

5.	Prompt the user to listen for the audible tones indicating when it is OK to proceed with dialing;

6.	Reissue the remainder of the dialable string (the portion following the offending modifier).

Note that in step 6 it is possible for another error to occur, since it is possible for multiple unsupported characters to occur within a single dialable string. Therefore, the application should repeat this process to dial the number in stages.


Tracking Asynchronous Requests

The function lineMakeCall is one of many functions that operate asynchronously. If an application manages only one line, it can use one state record, a struct containing all the information needed to track one outstanding asynchronous request. State records contain information such as the Request ID, the type of request, and pointers to allocated data that may need to be freed later.

But some applications have to manage more than one line—for example, to manage more than one outgoing call at the same time. To do so, they need to track the different asynchronous requests possible on each of those lines, and must therefore create an array of state records, one for each of the outstanding asynchronous operations (such as multiple invocations of lineMakeCall).

When a reply arrives that shows an asynchronous function has completed, the application matches the incoming Request ID with a Request ID in the array, and does whatever that specific call needs at that point. You can design one function to handle the reply that indicates completion of the outstanding asynchronous lineMakeCall request. The success or failure of the asynchronous request is recorded in the requestResult field of the state struct.


Performing Request Recipient Duties

If the application is an Assisted Telephony server—that is, if it receives and handles requests from Assisted Telephony client applications—it must ensure that it uses the correct parameters when executing requests. (The terms "Assisted Telephony server" and "request recipient (application)" can be used interchangeably. ) When doing so, these steps are followed:

•	The request recipient first receives a LINE_REQUEST message informing it that requests may exist for it in the request queue. This tells the application to call lineGetRequest and keep calling it until the queue is drained (if the request is for making a new call), or to drop an existing call. This message does not contain the parameters for the request, except in the case of a request to drop an existing call.

•	If the request is to make a new call, the Assisted Telephony server uses the lineGetRequest function to retrieve the full request, which includes the request's parameters. The server now has all the information it needs, such as the number to dial or the identification of the maker of the request. First, however, the server must allocate the memory needed to store this information.

•	Finally, the server executes the request by invoking the appropriate Telephony API function or set of functions.


Call Handle Manipulation

When an application makes a call, a handle to the call with owner privileges is returned to the application. When the application is notified about an inbound call, it is given a handle to the call with either owner privilege or monitor privilege, depending on the privilege previously requested with lineOpen. It can also receive a handoff from another application, in which case it would receive owner privilege.

An application's call handle and associated privileges remain valid until the application takes an explicit action to change them or if it receives a LINE_CLOSE message, which closes the line. In this case, all handles to calls on the line instantly become invalid.

After a call reverts to the idle state, the application is still allowed to read the call's information structure and status. When the application has no further use for the call (and its information), it should deallocate the call handle by invoking lineDeallocateCall, which is discussed in following sections.

For more information about call logging and handing off calls to other applications, see Chapter 8, "Multiple-Application Programming."


Dropping Calls

To terminate a call, the application uses lineDrop on the call. This has the effect of hanging up on (disconnecting) the call, which makes it possible to make another call on the line. The lineDrop function is also used to abandon a call attempt in progress. If the remote party disconnects a call, the local application receives a LINE_CALLSTATE message with a call state of disconnected. If the local application disconnects a call, the call becomes idle, but its handle is not automatically deallocated (the application must call lineDeallocateCall). An application should check the dwCallFeatures field in LINECALLSTATUS to determine whether or not it is legal to invoke lineDrop at a particular time.


Deallocating Call Handles

A call handle remains valid after the call has been dropped. This enables applications to use operations such as lineGetCallInfo to retrieve call information for logging purposes. Once an application knows it has all the information it needs about a call and it has received a LINE_CALLSTATE(LINECALLSTATE_IDLE) message, it should call lineDeallocateCall to free system-allocated memory related to the call. The application must itself free memory that it allocated for its own purposes.

The way to free an idle call is to deallocate its handle with lineDeallocateCall. The application's duty to free a call is independent of the reason the call went idle. That is, the handle must be deallocated whether it was the local or the remote application that dropped it. If an application is the owner of the call, it can deallocate the call's handle only if the call is in the idle state. If monitoring the call, it can deallocate the call handle at any time.

It is better to process the LINE_CALLSTATE(LINECALLSTATE_IDLE) message (and all other call-state notifications) consistently in one location regardless of its cause.


Reclaiming Memory Resources

The TAPI dynamic link library allocates memory for each call for each application that has a handle to the call. It is likely that service providers will allocate memory to hold call information as well. Deallocation of an application's call handle allows the library and the service provider to reclaim these memory resources. An application's handle for a call becomes void after a successful deallocation.

An application's attempt to deallocate the handle of a non-idle call for which it is the only owner will fail. The application should either first hand off ownership and change its privilege to monitor, or simply try to change its privilege to monitor (in case there are other owners) or clear the call by dropping it—which places the call into the idle state—and then deallocate its handle.


Closing Line Devices

After an application is finished using a line device, it should close the device by calling lineClose on the line-device handle. After the line has been closed, the application's handle for the line device is no longer valid. A LINE_LINEDEVSTATE message is sent to other interested applications to inform them about the state change on the line.

In certain environments, it may be desirable for a line device that is currently open by an application to be forcibly reclaimed (possibly by the use of some control applet) from the application's control. This feature can be used to prevent a single misbehaved application or user from monopolizing a line. It is also used when the user wants to reconfigure the line parameters, and has told the service provider directly through its Setup function in the Telephony Control Panel that the provider should forcibly close the line. When this occurs, an application receives a LINE_CLOSE message for the open line device that was forcibly closed.


Exiting Telephony

The lineShutdown function disconnects the application from the Telephony API. If this function is called when the application has lines open or calls active, the call handles are deleted and the equivalent of a call to the lineClose function is automatically performed on each open line. (It is better for applications to explicitly close all open lines before invoking lineShutdown.) If shutdown is performed while asynchronous requests are outstanding, those requests are canceled.

An application that has registered as an Assisted Telephony request recipient should de-register itself by calling lineRegisterRequestRecipient, using the value FALSE for the bEnable parameter.


Setting a Terminal for Phone Conversations

The user's desktop computer may have access to multiple devices that are individually selectable and used to conduct interactive voice conversations. One of these devices is the telephone itself, complete with lamps, buttons, display, ringer, and a voice I/O device (handset, speakerphone, or headset). The user's computer may also have a separate voice I/O device (such as a headset, or microphone/speaker combination attached to a sound card) for use with phone conversations. TAPI enables the user to select where to route the information sent by the switch over the line, address, or call. The switch normally expects this destination to be one of its phone sets, and sends ring requests, lamp events (for stimulus phones), display data, and voice data as appropriate.

The phone in turn sends hookswitch events, button press events (for stimulus phones), and voice data back to the switch. The line portion of TAPI makes lamp events, display events, and ring events available, either as "functional" return codes to TAPI's various operations or as unsolicited functional call-status messages sent to the application callback. TAPI's implementation is responsible for mapping the functional API level to the underlying stimulus or functional messages used by the telephony network. In functional telephony environments, TAPI's functions are mapped to the functional protocol.


Modes of Operation: Functional and Stimulus

The "functional" mode of operation differs from the "stimulus" mode in the way meaning is attributed to events. For example, a given telephone has a button labeled "Transfer." When this button is pressed, one of two things can happen: the phone can send a message to the switch stating that the Transfer button was pressed, or it can send a message stating that "button number 18" was pressed. In the functional model, the button's function is indicated. It allows more flexibility in the phone hardware, because the switch doesn't need to know anything about the layout of the buttons, but the telephone will likely be more expensive, because it has more intelligence.

The stimulus model means that the event is simply indicated in a more raw, hardware fashion, such as by button number—even down to separate button-up and button-down events. In a stimulus-based system, telephones can cost less, but more intelligence is required in the switch so that it can recognize different types of telephones and translate their buttons into features. The stimulus model can provide more flexibility because different people can configure their phone buttons to mean different things through switch programming rather than by changing the phone itself.


Event Routing

Although not described in the "Supplementary Line Functions" chapter, event routing is a part of the supplementary line services and is not a basic function.

With the lineSetTerminal function, the application can control or suppress the routing of specified low-level events (exchanged between the switch and the station) to a device. With lineSetTerminal, the application specifies the terminal device to which these events (such as line, address, or call media-stream events) are routed.

The routing of the different classes of events can be individually controlled, allowing separate terminals to be specified for each event class. Event classes include lamps, buttons, display, ringer, hookswitch, and media stream.

For example, the media stream of a call (voice, for example) can be sent to any transducer device if the service provider and the hardware is capable of doing so. In general, a "transducer" means the same as what is referred to as a "hookswitch" device in the Telephony Phone API—something that has a microphone and a speaker. Ring events from the switch to the phone can be mapped into a visual alert on the computer's screen or they can be routed to a phone device. Lamp events and display events can be ignored or routed to a phone device (which appears to behave as a normal phone set). Finally, button presses at a phone device may or may not be passed to the line. In any case, this routing of low-level signals from the line does not affect the operation of the line portion of TAPI, which always maps low-level events to their functional equivalent. To determine the terminals a line device has available (and their capabilities), consult the line device's capabilities with lineGetDevCaps.

Assume initially that the application has suppressed the routing of all events (with lineSetTerminal), and the user selects a headset as the current I/O device. An incoming call sends a LINE_CALLSTATE message, and a LINE_LINEDEVSTATE message with the ringing indication. Since routing of all events is suppressed, ring events are not routed to the phone, so ringing is suppressed. Instead, the application notifies the user with a pop-up dialog box and a system beep in the headset.

The user decides to answer the call. Since the user's current I/O device is the headset, the telephony application invokes lineSetTerminal on the incoming call to route the call's media to the headset and answer the call. The application may also invoke lineSetTerminal to route lamp and display information events to the phone set so that it will behave as usual.

As a second example, assume that an incoming call is alerting at the user's computer. Instead of selecting the answer option with the mouse, the user decides to just pick up the phone's handset to answer the call. The offhook status at the phone sends a callback message to the application. The application can interpret this status as a request by the user to select the phone handset to conduct the conversation. The application then invokes lineSetTerminal to route the voice data on the call to the phone set.


Supplementary Line Functions

About Supplementary Line Functions

In Windows Telephony, supplementary functions are functions whose form and functionality has been defined by the API description, but which are not required in basic Telephony. They are functions that developers of telephony applications and service providers may choose to implement to suit the design of their custom products. That is, in contrast to Basic Telephony functions, Supplementary Telephony functions are optional.

This chapter describes the Supplementary functions used with TAPI-defined line devices. For convenience, they are grouped into general functional categories.


Bearer Mode and Rate

The notion of bearer mode corresponds to the quality of service requested from the network for establishing a call. It is important to keep the concept of bearer mode separate from that of media mode. The media mode of a call describes the type of information that is exchanged over a specific call of a given bearer mode. As an example, the analog telephone network (PSTN) provides only 3.1 kHz voice-grade quality of service—this is its bearer mode. However, a call with this bearer mode can support a variety of different media modes such as voice, fax, or data modem. In other words, media modes require certain bearer modes. TAPI manages the bearer modes only by passing the bearer mode parameters on to the network. Media modes are fully managed through the appropriate media stream APIs, although some limited support is provided in TAPI.

The bearer mode of a call is specified when the call is set up, or is provided when the call is offered. With line devices able to represent channel pools, it is possible for a service provider to allow calls to be established with wider bandwidth. The rate (or bandwidth) of a call is specified separately from the bearer mode, allowing an application to request arbitrary data rates.

The bearer modes defined in TAPI are:

•	Voice  Regular 3.1 kHz analog voice service. Bit integrity is not assured.

•	Speech  G.711 speech transmission on the call.

•	Multiuse  As defined by ISDN.

•	Data  Unrestricted data transfer. The data rate is specified separately.

•	Alternate speech and data  The alternate transfer of speech and unrestricted data on a call (ISDN).

•	Non call-associated signaling  This provides a clear signaling path from the application to the service provider.

Although support for changing a call's bearer mode or bandwidth is limited in networks today, TAPI provides an operation to request a change in the bearer mode or the data-rate parameters of an existing call. This function is lineSetCallParams.


Call Monitoring

Call monitoring includes media, digit, and tone monitoring.


Media Monitoring

When a call is in the connected state, information can be transported over the call. A call's media mode provides an indication of the type of information (for example, its data type, or higher-level protocol) of this media stream. TAPI allows applications to be provided with a callback notification about changes in a call's media mode. The notification provides an indication of the call's new media mode. Note that the service provider decides how it wants to make this determination. For example, the service provider could use signal processing of the media stream to determine the media mode, or it could rely on distinctive ringing patterns assigned to different media streams, or on information elements passed in an out-of-band signaling protocol. Independent of how the media mode determination is achieved, the application is simply informed about media mode changes on an existing call.

The media modes defined by TAPI include:

•	Unknown  The media mode of the call is not currently known—the call is unclassified.

•	Interactive voice  Voice energy was detected on the call, and the call is handled as an interactive voice call with a person at the application's end.

•	Automated voice  Voice energy was detected on the call, and the call is handled as a voice call but with no person at the application's end, such as with an answering machine application.

•	Data modem  A modem session on the call. Note that current modem protocols require the called station to initiate the handshake. For an inbound data modem call, the application can typically make no positive detection. How the service provider makes this determination is its choice. For example, a period of silence just after answering an inbound call may be used as a heuristic to decide that this might be a data modem call.

•	G3 fax  A group 3 fax session on the call.

•	TDD  The call's media stream uses the Telephony Devices for the Deaf protocol.

•	G4 fax  A group 4 fax session on the call.

•	Digital data  A digital data stream of unspecified format.

•	Teletex, Videotex, Telex, Mixed  These correspond to the telematic services of the same names.

•	ADSI  An Analog Display Services Interface session on the call. ADSI enhances voice calls with alphanumeric information downloaded to the phone and the use of soft buttons on the phone.

An application can enable or disable media monitoring on a specified call with lineMonitorMedia. The application specifies which media modes it is interested in monitoring, and when media monitoring is enabled, the detection of a media mode change causes the application to be notified with the LINE_MONITORMEDIA callback message. This callback message provides the call handle on which the media mode change was detected as well as the new media mode.

There is a distinction between the media mode of a call as reported by lineGetCallInfo and the media mode event reports by LINE_MONITORMEDIA messages. A call's media mode is determined exclusively by owner applications of the call and is not automatically changed by media monitoring events. The one exception is the initial media mode determination that may be performed by the TAPI dynamic link library to select the first owner of a call. One could argue that in this case, the library is the owner of the call.

Default media mode monitoring is performed for the media modes for which the line device has been opened. This allows an inbound call's media mode to be determined before the call is handed to an application based on what the applications demand. Note that the scope of the media monitoring of a call is bound by the lifetime of the call. Media monitoring on a call ends as soon the call disconnects or goes idle.

An application can obtain device IDs for various Windows device classes associated with an opened line by calling lineGetID. This function takes a line handle, address, or call handle and a device class description. It returns the device ID for the device of the given device class that is associated with the open line device, address, or call. If the device class is "tapi/line," then the device ID of the line device is returned. If the device class is "mci/wave," then the device ID of an mci waveaudio device is returned (if supported), which allows activities such as the recording or playback of audio over the call on the line.

The application can use the returned device ID with the corresponding media API to query the device's capabilities and subsequently open the media device. For example, if your application needs to use the line as a waveform device, it must first call waveInGetDevCaps and/or waveOutGetDevCaps to determine the waveform capabilities of the device. The typical wave form data format supported by telephony in North America is 8-bit m-law at 8000 samples per second, although the wave device driver can convert this sample rate and companding to other more common multimedia audio formats.

To subsequently open a line device for audio playback using the waveform API, an application calls waveOutOpen. The implementation of waveOutOpen is device specific, and there is a variety of options for implementing this function.


Digit Monitoring

Digit monitoring monitors the call for digits. TAPI allows digits to be signaled according to two methods (digit modes):

•	Pulse  Digits are signaled as pulse or rotary sequences. For detection, these pulses manifest themselves as nothing more than sequences of audible clicks. Valid pulse digits are '0' through '9'.

•	DTMF  Digits are signaled as DTMF (Dual Tone Multiple Frequency) tones. Valid DTMF digits are '0' through '9', 'A'. 'B', 'C', 'D', '*', and '#'. Both the beginning and the down edge of DTMF digits can be monitored.

An application can enable or disable digit monitoring on a specified call with lineMonitorDigits. When digit monitoring is enabled, detected digits cause the application to be notified with the LINE_MONITORDIGITS callback message. This callback message provides the call handle on which the digit was detected as well as the digit value and the digit mode. The scope of digit monitoring is bound by the lifetime of the call. Digit monitoring on a call ends as soon as the call disconnects or goes idle.


Tone Monitoring

Tone monitoring monitors the media stream of a call for specified tones. A tone is described by its component frequencies and cadence. An implementation of the API may allow several different tones to be monitored simultaneously. An application can "tag" each tone in order to be able to distinguish the different tones for which it requests detection.

An application can enable or disable tone monitoring on a specified call with lineMonitorTones. With this function, the application specifies which tones to detect on a specified call. When tone monitoring is enabled, detected digits cause the application to be notified with the LINE_MONITORTONE callback message. This callback message provides the call handle on which the tone was detected as well as the application's "tag" for the tone.

The scope of tone monitoring is bound by the lifetime of the call. Tone monitoring on a call ends as soon the call disconnects or goes idle.

Note that the monitoring of tones, digits, or media modes often requires the use of resources of which the service provider may only have a finite amount. A request for monitoring may be rejected if resources are not available. For the same reason, an application should disable any unnecessary monitoring.


Media Control

An application can request the execution of a limited set of media-control operations on the call's media stream triggered by telephony events. Although an application is encouraged to use the media API specifically defined for the media mode, media control can yield a significant performance improvement for client-server implementations. The lineSetMediaControl function is used to set up a call's media stream for media control by allowing an application to specify a list of tuples specifying a telephony event and the associated media-control action. The telephony events that can trigger media-control activities are:

•	Detection of a digit  The application provides a list of specific digits and the media-control action that each of them triggers.

•	Detection of a media mode  The application provides a list of media modes and the media-control actions that a transition into the media mode triggers.

•	Detection of a specified tone  The application specifies a list of tones and the media-control action that each tone detection triggers.

•	Detection of a call state  The application specifies a list of call states and the media-control action that each transition to the call state triggers.

The media-control actions listed below are defined generically for the different media modes. Not all media streams may provide meaningful interpretations of the media-control actions. The operations should map well to audio streams.

•	Start  Starts the media stream.

•	Reset  Resets the media stream.

•	Pause  Stops or pauses the media stream.

•	Resume  Starts or resumes the media stream.

•	Rate up  Increases the rate (speed) of the media stream by an implementation-defined amount.

•	Rate down  Decreases the rate of the media stream by an implementation-defined amount.

•	Rate normal  Returns the rate to normal.

•	Volume up  Increases the volume (amplitude) of the media stream.

•	Volume down  Decreases the volume of the media stream.

•	Volume normal  Returns the volume to normal.

The scope of media control is bound by the lifetime of the call. Media control on a call ends as soon the call disconnects or goes idle. Only a single media-control request can be outstanding on a call across all applications.


Digit Gathering

Besides enabling digit monitoring and being notified of digits one at a time, an application can also request that multiple digits be collected in a buffer. Only when the buffer is full or when some other termination condition is met is the application notified. Digit gathering is useful for functions such as credit card number collection. It is peformed when an application calls lineGatherDigits, specifying a buffer to fill with digits. Digit gathering terminates when one of the following conditions is true:

•	The requested number of digits has been collected.

•	One of multiple termination digits is detected. The termination digits are specified to lineGatherDigits, and the termination digit is placed in the buffer as well.

•	One of two timeouts expires. The timeouts are a first digit timeout, specifying the maximum duration before the first digit must be collected, and an inter-digit timeout, specifying the maximum duration between successive digits.

•	Digit gathering is canceled explictly by lineGatherDigits again with either another set of parameters to start a new gathering request or by using a NULL digit buffer parameter to cancel.

When terminated for any reason, a LINE_GATHERDIGITS message is sent to the application that requested the digit gathering. Note that only a single digit gathering request can be outstanding on a call at any given time across all applications that are owners of the call.

Note that digit gathering and digit monitoring may be enabled on the same call at the same time. In that case, the application will receive a LINE_MONITORDIGITS message for each detected digit and a separate LINE_GATHERDIGITS message when the buffer is sent back.


Generating Inband Digits and Tones

Once a call is in the connected state, information can be transmitted over it. Two functions are provided that allow end-to-end inband signaling between the application and remote station equipment such as an answering machine. One function is lineGenerateDigits, which generates inband digits on a call, signaling them over the voice channel. Digits can be signaled as either rotary/pulse sequences or as DTMF tones. The other function is lineGenerateTone, which enables the application to generate one of a variety of multi-frequency tones inband (over the media stream). This generates telephony tones, such as ringback, beep, and busy, as well as arbitrary multi-frequency, multi-cadenced tones.

Only one digit or tone generation can be in progress on a call at any one time. When digit or tone generation completes, a LINE_GENERATE message is sent to the application that requested the generation. In the case where multiple digits are generated, only a single message is sent back after all digits have been generated. Calling lineGenerateDigits or lineGenerateTone while digit or tone generation is in progress will abort the generation currently in progress and send the LINE_GENERATE message to the application whose generation was aborted with a cancel indication.


Call Operations

The call operations include acceptence, rejection, redirecting, holding, forwarding, parking, pick up, and completion.


Call Accept, Reject, and Redirect

In environments like ISDN, call offering is separate from alerting. In fact, after a call has been offered to an application, a time window exists during which the application has a number of options:

•	It can answer the call using lineAnswer, which immediately answers the call.

•	It can accept the call using lineAccept, which initiates alerting to both the caller (as ringback), and the called party (as ring).

•	It can reject the offering call using lineDrop, which reverts the offering call to the idle state.

•	It can redirect the call using lineRedirect, which deflects the offering call to another address. The call reverts to the idle state.


Call Hold

Most PBXs can associate multiple calls with a single line. A call can be placed on hard hold, which frees the user's line/address to make other calls. An application can place a call on hard hold by calling lineHold. An application may retrieve a call on hard hold by calling lineUnhold.

Hard hold is different from a consultation hold. A call is automatically placed on consultation hold, for example, when a call is prepared for transfer or conference.


Call Transfer

TAPI provides two mechanisms for call transfer: blind transfer and consultation transfer.

•	In blind transfer (or single-step transfer), an existing call is transferred to a specified destination address in one phase using lineBlindTransfer.

•	In a consultation transfer, the existing call is first prepared for transfer to another address using lineSetupTransfer. This places the existing call on consultation hold, and identifies the call as the target for the next transfer-completion request. lineSetupTransfer also allocates a consultation call that can be used to establish the consultation call with the party to which the call will be transferred. The application can dial the extension of the destination party on the consultation call (using lineDial), or it can drop and deallocate the consultation call and instead activate an existing held call (using lineUnhold), if supported by the switch.

While the initial call is on consultation hold and the consultation call is active, the application can toggle between these calls using lineSwapHold.

Finally, the application completes the transfer in one of two ways using lineCompleteTransfer:

•	Transfer the call on transfer hold to the destination party. Both calls will revert to the idle state.

•	Enter a three-way conference. A new call handle is created to represent the conference and this handle is returned to the application.


Call Conference

Conference calls are calls that include more than two parties simultaneously. They can be set up using either a switch-based conference bridge or an external server-based bridge. Typically, only switch-based conferencing will allow the level of conference control provided by the API. In server-based conference calls all participating parties dial into the server which mixes all the media streams together and sends each participant the mix; there may be no notion of individual parties in the conference call, only that of a single call between the application and the bridge server.

A conference call can be established in a number of ways, depending on device capabilities:

•	A conference call may begin as a regular two-party call, such as a call established with lineMakeCall. Once the two-party call exists, additional parties can be added, one at a time. Calling lineSetupConference prepares a given call for the addition of another party, and this action establishes the conference call. This operation takes the original two-party call as input, allocates a conference call, connects the original call to the conference, and allocates a consultation call whose handle is returned to the application.

Note that the capabilities of the addressed line device may limit the number of parties conferenced in a single call and whether or not a conference starts out with a normal two-party call.

The application can then use lineDial on the consultation call to establish a connection to the next party to be added. lineDrop can be used to abandon this call attempt. The third party is added with the function lineAddToConference, which specifies both the conference call and the consultation call.

•	A three-way conference call can be established by resolving a transfer request for three-way conference. In this scenario, a two-party call is established as either an inbound or outbound call. Next the call is placed on transfer hold with the function lineSetupTransfer which returns a consultation call handle. After a period of consultation, the application may have the option to resolve the transfer setup by selecting the three-way conference option which conferences all three parties together in a conference call with lineCompleteTransfer with the conference option (instead of the transfer option). Under this option, a conference call handle representing the conference call is allocated and returned to the application.

•	A conference call may need to be established with lineSetupConference without an existing two-party call. This returns a handle for the conference call and allocates a consultation call. After a period of consultation, the consultation call can be added with lineAddToConference. Additional parties are added with linePrepareAddToConference followed by lineAddToConference.

To add additional parties to an existing conference call, the application uses linePrepareAddToConference. When calling this function, the application supplies the handle of an existing conference call. The function allocates a consultation call that can later be added to the conference call and returns a consultation call handle to the application. This conference call is then placed on conference hold. Once the consultation call exists, it can be added to the existing conference call with lineAddToConference.

Once a call becomes a member of a conference call, the member's call state reverts to conferenced. The state of the conference call typically becomes connected. The call handle to the conference call and all the added parties remain valid as individual calls. LINE_CALLSTATE events can be received about all calls. For example, if one of the members disconnects by hanging up, an appropriate call-state message may inform the application of this fact; such a call is no longer a member of the conference.

As is the case with call transfer, the application may toggle between the consultation call and the conference call using lineSwapHold.

Use the call handle for the member calls to later remove the call from the conference. Do this by calling lineRemoveFromConference on the call handle. Note that this operation is not commonly available in its fully general form. Some switches may not allow it at all, or only allow the most recently added party to be removed. The line's device capabilities describe which type of lineRemoveFromConference is possible.


Removing a Party

When canceling the consultation call to the third party for a conference call or when removing the third party in a previously established conference call, the service provider (and switch) may release the conference bridge and revert the call back to a normal two-party call. If this is the case, hConfCall will transition to the idle state, and the only remaining participating call will transition to the connected state.


Call Park

Two forms of call parking are provided: directed call park and non-directed call park. In directed call park, the application specifies the destination address where the call is to be parked. This roughly behaves like a call transfer to the destination address, but it doesn't alert or time out as a transfer would.

In non-directed call park, the switch returns to the application the address where it parked the call. In either case, the function linePark is used to park a call. A parked call can later be retrieved with lineUnpark. The application specifies the park address to lineUnpark which returns a call handle to the unparked call. Appropriate LINE_CALLSTATE messages will be sent to the application as the call is reconnected.


Call Forwarding

Forwarding affects the treatment by the switch or network of incoming calls destined for a given address. The application can specify call forwarding conditions based on the origin of the call (internal, external, selective based on caller ID), the status of the address (busy, no answer, unconditionally), and the destination address where calls are to be forwarded. When the specified conditions are met for an incoming call, the switch deflects the incoming call to the specified destination number. Because the switch performs the forwarding action, the application will typically not know when a call has been forwarded.

The lineForward function provides a combination of call forwarding (by setting call-forwarding requests) and a do-not-disturb feature. LineForward can also cancel any or all of the forwarding requests currently in effect. Some switches require that a call be established to the forwarding address in order for call forwarding to be initiated. On such systems, lineForward allocates a consultation call and returns the handle for it to the application. The consultation call can be used as any other call. After the connection is established, forwarding confirmation is received from the switch, the call is dropped (using lineDrop), and forwarding is in effect. A LINE_ADDRESSSTATE message with a forwarding indication informs the application about changes in an address' forwarding status.

Note that it may be impossible for a service provider to know at all times what forwarding is in effect for an address. Forwarding may be canceled or changed in ways that make it impossible for a service provider to be informed of this fact.


Call Pickup

Call pickup allows an application to answer a call that is alerting at another address. The application invokes linePickup by identifying the target of the pickup and is returned a call handle for the picked-up call. There are several ways to specify the target of the pickup request. First, specify the address (extension) of the alerting party. Second, if no extension is specified and the switch allows it, the application can pick up any ringing phone in its pickup group. Third, some switches require a group ID to identify the group to which the ringing extensions belongs.

After the call has been picked up, it is diverted to the application and the application is sent appropriate LINE_CALLSTATE messages for the call. An application can invoke lineGetCallInfo to find out information about the picked-up call, if provided by the switch.


Call Completion

When making an outbound call, the unavailability of certain resources may prevent the call from reaching the connected state, as when the destination party is busy or doesn't answer. Unavailable resources include trunk circuits as well as the destination party's station. The lineCompleteCall function lets the application specify how it wants to complete a call that cannot be completed normally—this is called "placing a call-completion request." The application has the following options:

•	Camp on to queue the call until the call can be completed.

•	Call back requests the called station to return the call when the station returns to idle. Answering the call-back may automatically re-initiate (redial) the connection request.

•	Intrude allows the application to barge in to the existing call.

•	Message (also known as "leave word calling") allows the application to send one of a small number of predefined messages to the destination. These messages can be text shown on the phone's display, a voice message left for the user, and so forth.

A call completion request can be canceled with lineUncompleteCall. Multiple call completion requests can potentially be outstanding for a given address at any one time. To identify individual requests, the implementation returns a completion ID. When a call completion request completes and results in a new call, the call completion ID is available in the LINECALLINFO data structure returned by lineGetCallInfo. Canceling a call completion request in progress also uses this call completion ID.


Extended Line Functions

Extended Line Services (or device-specific line services) include all service-provider defined extensions to the API. The API defines a mechanism that enables service-provider vendors to extend TAPI using device-specific extensions. The API only defines the extension mechanism, and by doing so provides access to device-specific extensions, but the API does not define their behavior. Behavior is completely defined by the service provider.

TAPI consists of scalar and bit-flag constant definitions, data structures, functions, and callback messages. Procedures are defined that enable a vendor to extend most of these as follows:

For extensible scalar data constants, a service-provider vendor may define new values in a specified range. As most data constants are DWORDs, typically the range 0x00000000 through 0x7FFFFFFF is reserved for common future extensions, while 0x80000000 through 0xFFFFFFFF are available for vendor-specific extensions. The assumption is that a vendor would define values that are natural extensions of the data types defined by the API.

For extensible bit-flag data constants, a service-provider vendor may define new values for specified bits. As most bit-flag constants are DWORDs, typically a specific number of the lower bits are reserved for common extensions while the remaining upper bits are available for vendor-specific extensions. Common bit flags are assigned from bit zero up; vendor-specific extensions should be assigned from bit 31 down. This provides maximum flexibility in assigning bit positions to common extensions versus vendor-specific extensions. A vendor is expected to define new values that are natural extensions of the bit flags defined by the API.

Extensible data structures have a variably sized field that is reserved for device-specific use. Being variably sized, the service provider decides the amount of information and the interpretation. A vendor that defines a device-specific field is expected to make these natural extensions of the original data structure defined by the API.

Two functions, lineDevSpecific and lineDevSpecificFeature, and two related messages, LINE_DEVSPECIFIC and LINE_DEVSPECIFICFEATURE, provide a vendor-specific extension mechanism. The lineDevSpecific function and associated LINE_DEVSPECIFIC message enables an application to access device-specific line, address, or call features that are unavailable with the Basic or Supplementary Telephony services. The parameter profile of the lineDevSpecific function is generic in that little interpretation of the parameters is made by the API. The interpretation of the parameters is defined by the service provider and must be understood by an application that uses them. The parameters are simply passed through TAPI from the application to the service provider. An application that relies on device-specific extensions will not generally work with other service providers; however, applications written to the Basic and Supplementary Telephony Services will work with the extended service provider.

For convenience, a more specialized escape function is also provided. It is similar to lineDevSpecific, but places interpretation on some of the parameters. This more specialized function lineDevSpecificFeature, which is a device-specific escape function to allow sending switch features to the switch. The message LINE_DEVSPECIFICFEATURE is the device-specific message sent to the application's callback as an indication of features sent to the switch. This function and its associated message allow an application to emulate button presses at the line's feature phone. As feature phones and the meanings of their buttons are vendor-specific, feature invocation using lineDevSpecificFeature is also vendor specific.

As mentioned earlier, there is no central registry for manufacturer IDs. Instead, a unique ID generator (EXTIDGEN) is made available.


Multiple-Application Programming

About Multiple-Application Programming

Windows Telephony applications may be designed to cooperate with each other, or they may act independently of one another. These TAPI applications will at times operate with non-TAPI applications built to support TAPI functionality, such as media-stream control applications. All these applications must be able to work together, or at least function independently in a cooperative way. To achieve this, TAPI defines mechanisms that let applications coordinate their telephony and phone activities while maintaining a high degree of flexibility.

The roles played by Telephony's major components are described in various sections of this chapter. Application writers can not only learn about TAPI's functioning from these sections, but can apply that knowledge directly when designing TAPI applications. For example, the "Unknown" application (defined in the following section) performs specific duties in media-mode probing and call handoffs. It is important to note and understand these duties before writing an Unknown application.


Event-Driven Environment

Like all Windows applications, Windows Telephony applications operate in the event-driven model used by Windows. In Telephony, the most important events are call-state transitions. The service provider and TAPI dynamic link library report call states to applications for particular calls. Interested applications, which know the previous state of the call, could infer call-state transitions from call states.

All running applications receive information—call-state messages—about all the calls in which they are interested. At times, several applications will have interest in the same call or calls, as monitors or owners of those calls. Incoming call-state events often cause applications to take actions on calls, and because those actions sometimes involve a shared call, one application must react to the knowledge that another has taken a certain step. Examples include the case where one application shows interest in owning (having control of) a call currently owned by your application, or drops a call co-owned by your application.

The Telephony system was designed to minimize "race" situations—in which the timing of competing function calls from different applications makes a difference. Awareness of the principles and the guidelines described in this chapter should help minimize possible competition.


Definitions

The following concepts are important for understanding the material presented in this chapter.

Initial Media Modes

On a network other than ISDN, service providers usually do not know the media mode of an arriving call. For such calls, the service provider indicates a number of initial media modes, from which the correct one is eventually selected during the next step—the probing process. The initial media mode(s) identified by the service provider as being possible on the call will be reflected in the dwMediaMode field of the LINECALLINFO data structure, which the application can obtain by calling lineGetCallInfo after the initial LINE_CALLSTATE message announcing a new call is received.

Call Control

Having control of a call means that the application has received a LINE_CALLSTATE message stating that it has become an owner of the call. With this event, the application acquires a handle to the call with owner privileges. A way for a monitoring application to obtain call control (ownership) is to call lineSetCallPrivilege in order to set its call privilege to owner.

Call Monitor

An application that has a handle to a call with monitor privileges is a monitor of that call. Such an application cannot control the existence or other aspects of the call, but it can record (log) facts about the call. The application can also reset its call privilege to owner, thus becoming an owner of the call, in the event that the application determines (by monitoring media modes or other events) that it should take control.

Call Owner

An application that has control of a call is an owner of that call. An application can become an owner of a call in several ways, all discussed in this chapter. A call can have several owners simultaneously, although the usual situation is for only one application to be the owner of a call.

Probing

Probing is the sending of signals on the phone line as an attempt to determine an incoming call's media mode. This search for the media mode is conducted only by applications. Some service providers may also be configured to do some amount of probing automatically to narrow down the initial media modes reported on a new call.

The "Unknown" Application

An application that has opened a line requesting ownership privilege for calls of as-yet undetermined, or UNKNOWN media mode, is referred to as the Unknown application. (The LINEMEDIAMODE_UNKNOWN bit is set in the dwMediaMode field of the LINECALLINFO structure, along with other bits indicating other modes that are potentially present on the call.) An application that does this may actually be capable of handling calls of a number of different media modes. Alternatively, it may simply act as a traffic director, passing calls on to other applications that can use calls of the specific media modes.


Call Ownership

The mechanism with which applications control calls is based on the concept of ownership. At any given time, one or more applications can own a call. While an application has ownership of a call, it is allowed to manipulate the call in ways that affect the state of the call. An application that does not own a call (but has a handle to it) is a monitor of the call and is prevented from manipulating it. It can only perform status- and information-query operations on that call. While one or more applications are owners of a call, still other applications can be monitoring the call.

Ownership of a call is assigned to applications according to the following rules:

•	An application that makes an outgoing call is the initial sole owner of that call. Other applications monitoring the line will be informed of the outgoing call at the time the first LINE_CALLSTATE message is received. Usually, this notification occurs when dial tone is initially detected.

•	Ownership of an incoming call is assigned to one application only. This assignment avoids the situation in which, depending on timing, different applications may seize control at different times, causing unpredictable results.

•	An application that is currently an owner of a call can pass ("hand off") ownership to another application that has the call's line open. While handing off ownership of a call, the original owner application can specify the new media type of the call. When the handoff succeeds, the original application remains an owner of the call, and it can then choose to either deallocate its handle (if it is no longer interested in the call), change to being a monitor (using lineSetCallPrivilege), or remain an owner (although doing so is discouraged). The original application's privilege is not automatically changed by lineHandoff. More information on the two types of call handoffs (directed and media-mode) can be found later in this chapter.

•	If a target application for the handoff is found, and if it is already a co-owner of the call, it will see no effect caused by the handoff although it will receive a LINE_CALLSTATE message. This message repeats the fact that it is an owner to alert it that another application has explicitly asked it to take control of the call. The application initiating the handoff is informed about the success of the handoff.

•	If there is no target application for the requested handoff and the call is active, an error is returned. No handoff takes place.

•	Handing off a call between applications never affects the state of the physical call as perceived by the switch or the service provider.

•	An application that does not have (but wants) ownership of a call may request ownership. The application can select calls based on a number of criteria, ranging from all calls on a particular line or address (a phone number assigned to the line, using lineGetNewCalls), to calls related to a specified call (using lineGetConfRelatedCalls). An application that calls lineGetNewCalls or lineGetConfRelatedCalls will always receive a monitor handle. If it wants to become an owner of a call it receives, it must then call lineSetCallPrivilege. If it determines that it is not interested in one or more of the calls to which it receives handles using lineGetNewCalls or lineGetConfRelatedCalls, it must call lineDeallocateCall for each such handle to release the internal resources maintained to track the call ownership.

•	Any application that asks for ownership receives it; any application that is offered ownership cannot refuse it. An application that becomes an owner through a handoff actually becomes a co-owner of the call. When the call is initially presented by the provider, the initial owner is the sole owner of the call.

•	The originally owning applications are informed about the existence of every new owner. Monitoring applications are informed as well.

Note that with co-owned calls (calls simultaneously owned by more than one application), no protection is offered to prevent the applications from interfering with each other. For this reason, maintaining ownership after a handoff or after ownership is taken by another application is discouraged.

Since media streams are not managed by the Windows Telephony API, call handoff does not handle the handoff of the call's media stream. Media-stream handoff must be carried out using commands from an appropriate media-control API or directly coordinated between the applications involved.


Handling Incoming Calls

When multiple applications are running simultaneously, an appropriate one must be found to become the initial owner of each incoming call. In general, incoming calls reach their destination, or "target" application, in two or three steps: First, the service provider learns of the new call and passes it to the TAPI dynamic link library which gives the call to the appropriate application. Finally, applications conduct probing, if necessary, which can cause the call to be handed off between applications one or more times. These steps are described below. Sometimes applications perform further probing, a case which is also covered in the following description.


Duties of the Service Provider

The service provider determines the media modes.


Determining Initial Media Modes

When a service provider learns of the appearance of a call, its first task is to determine the call's media mode to the best of its ability. (It has received "ringing voltage" on a POTS line or, in the case of EPBX or ISDN, a protocol message indicating that a call is incoming.) It may be able to tell the single correct media mode or it may only be able to narrow down the possibilities to a certain few. These first media mode settings are called initial media modes, and following are the considerations used for setting initial media mode bits:

•	Service Provider Setup  The service provider has been configured to work with only a single media mode or certain media modes.

•	Hardware Limitations  Hardware limitations are usually reflected in the service provider's configuration, but the media modes could be further restricted by a particular card in use.

•	Call to lineOpen  Possible media modes are limited by what applications have requested in their invocation of the lineOpen function. TAPI combines all of the media modes requested by applications and indicates the sum of them to the service provider in a call to TSPI_lineSetDefaultMediaDetection. For example, a telephony device and its service provider may be able to handle Group 3 facsimile calls, but if no application is running to handle such calls, the provider would know not to bother with probing for fax or reporting fax calls to TAPI. (The TAPI dynamic link library does not automatically launch an application to handle a particular type of incoming call.)

•	Caller ID and Direct Inward Dialing  With Direct Inward Dialing (DID) at the called address, the switch supplies the service provider with the digits that were dialed (the called address). The service provider can be configured to associate particular called addresses with particular media modes. Likewise, it could associate calls from particular numbers as being associated with particular media modes, although this is much less commonly used.

•	Distinctive Ringing  The ring pattern of the incoming call may match a predetermined pattern (of several possible at the called address) that is reserved for calls of a certain media mode. If, for example, the incoming call is using ring pattern 2, the service provider knows it to be a fax call (based on configuration information supplied by the user).

•	ISDN  On an ISDN network, the provider may analyze the call's protocol frames to determine the media mode. If the call is indicated as a 3.1kHz Voice call, it is still possible that the actual media mode on the call is analog datamodem, Group 3 fax, text telephone, or any of several other voiceband modulated signals, in addition to human voice; it is only with digital data signals that the media mode would necessarily be clearly defined—for example as Group 4 fax—at call setup time in ISDN.

•	Auto Answer and Probe  Some providers give the user an option to let the service provider autoanswer the call and do some of the probing itself. In this process, TAPI gives the call the correct application with the correct media mode already identified.

These tools may be enough to make a final and accurate determination of the media mode. In any case, when the service provider passes the new call to TAPI, it sends a LINE_CALLSTATE message and includes in the message all that it knows about the call's media mode(s). The following sections give details on the possible cases.


Known Media Mode

When the service provider knows the media of the call unambiguously, one flag is set in LINECALLINFO.dwMediaMode. The media mode cannot be the single bit LINEMEDIAMODE_UNKNOWN, which is a different scenario. TAPI gives ownership of the call to the highest priority application that has opened a line for this media mode. It also gives call handles with monitor privileges to all other monitor applications on the line.


Unknown Media Mode

Even when the service provider does not know the exact media mode of the call, it might still know which media modes are possible. In this case, the service provider sets a combination of likely media mode bit flags, including LINEMEDIAMODE_UNKNOWN and passes the call to TAPI. The service provider sets these bits both in the dwMediaMode field of the LINECALLINFO record and in the dwParam3 parameter of the first LINE_CALLSTATE message it sends to TAPI.

The service provider considers only the media modes for which applications have opened the line with owner privileges (it becomes aware of these media modes through the TSPI_SetDefaultMediaDetection call) and which it is capable of handling. TAPI informs the provider about the union of all the lines that have been opened with a specified media mode. The provider can use this union to enable only the appropriate media mode detections for which applications are interested. If no applications have opened the line for ownership, the provider will not consider any media modes. Incoming calls are still delivered to TAPI, but no initial owner is possible. In this case, monitoring applications will still be informed of the call, and if none of them changes their privilege to owner and answers the call, the call will remain unanswered.


Duties of the TAPI Dynamic Link Library

The TAPI dynamic link library does not perform probing; that is, it does not send signals on phone lines in order to determine a call's media mode. TAPI does try to deliver the call to an application that can do probing. The way in which TAPI gives calls to applications is determined by several factors, the most important of which are the media mode bits that have been set and the running applications that can (or cannot) handle calls of those media modes.

TAPI's behavior can be divided into two main scenarios: 1) One Media Mode Bit Is Set and 2) The UNKNOWN Bit Is Set. These cases are described in the following sections.


Only One Media Mode Bit Is Set

If only one media-mode bit (not the UNKNOWN bit) has been set in the dwMediaMode field of the LINECALLINFO data structure, TAPI distributes calls by following a consistent procedure based on the current state of the system and on information saved by the user in the TELEPHON.INI file. These are the steps it takes:

•	The TAPI dynmaic link library is notified by the service provider that a call is arriving.

•	The TAPI library uses the information in the [HandoffPriorities] section of TELEPHON.INI to know which applications have been listed—possibly through a Preferences option in the application's user interface—as being interested in calls having the incoming call's media mode.

The first such application listed, reading left to right, is the highest priority application. If that application is currently running and has the arriving call's line open for that media mode, it is given ownership of the call. If it is not running or it does not have that line open, TAPI.DLL again uses the information in TELEPHON.INI to find an interested application in the correct state, and it gives the call to it.

•	If none of the applications listed in TELEPHON.INI are in the proper state, TAPI looks for other applications that are currently executing and have the line open for that media mode (though they are not listed in TELEPHON.INI). The relative priority among these unlisted applications is arbitrary and not necessarily associated with the sequence in which they were launched or opened the line.

•	Every application that has the line open for monitoring also receives a handle to a call, and any of them could step up, claim ownership (by calling lineSetCallPrivilege), and answer the call. However, this behavior could result in "race conditions" and unpredictable call handling, and is therefore discouraged.

•	If no application becomes an owner of the call, the call is eventually dropped. Calls can be dropped by TAPI only if no owner is found for the call and the call state is not idle or offering. The calling party can also drop the call. (On an ISDN network, this event becomes known when a "call-disconnect" frame is received.) If the call is not explicitly dropped, it can go idle after the expiration of a timeout based on the absence of ringing. (The service provider would need to assume that the call has been dropped by the calling party, and implement the timeout.) Because there were no applications that could take the call successfully, this situation usually means that the incoming call reached a wrong number.


The UNKNOWN Bit Is Set

If the LINEMEDIAMODE_UNKNOWN bit is on in param3 of the first LINE_CALLSTATE message delivered by the service provider, the call is treated differently depending on whether an application prepared to accept calls of unknown media type has opened the line. These two possible cases (an Unknown application is running, or is not) are described in this section:


An "Unknown" Application Is Running

If at least one Unknown application has opened the line, the TAPI dynamic link library gives an ownership handle for the incoming call to the highest priority Unknown application. It also passes monitoring handles to the other applications that have the line open for monitoring. The Unknown application receives a LINE_CALLSTATE message with dwParam3 set to owner.

This Unknown application can then try to perform media determination itself, or use the assistance of the other media applications, allowing them to perform "probes" for their media mode(s), if appropriate. The Unknown application can pass the call to another media application using lineHandoff. The Unknown application would examine LINECALLINFO.dwMediaMode to determine the possible remaining candidate media. In doing so, it uses the highest priority media to determine the initial handoff target. It calls lineHandoff, specifying the single highest priority destination media mode as the target.

The following is the default priority of media modes, listed in order from first tried to last tried when used during media-type handoffs:

Order	Media Mode
1	LINEMEDIAMODE_INTERACTIVEVOICE
2	LINEMEDIAMODE_DATAMODEM
3	LINEMEDIAMODE_G3FAX
4	LINEMEDIAMODE_TDD
5	LINEMEDIAMODE_G4FAX
6	LINEMEDIAMODE_DIGITALDATA
7	LINEMEDIAMODE_TELETEX
8	LINEMEDIAMODE_VIDEOTEX
9	LINEMEDIAMODE_TELEX
10	LINEMEDIAMODE_MIXED
11	LINEMEDIAMODE_ADSI
AUTOMATEDVOICE is a media mode that has no meaningful distinction with INTERACTIVEVOICE at this level, and is therefore not listed.

If the handoff fails, the Unknown application should clear that media mode flag in LINECALLINFO.dwMediaMode. This action moves the probe for the call one step closer to a final determination of the media mode. If the handoff indicates TARGETSELF, it means that the Unknown application is the highest priority application for the media mode for which it was trying to hand off the call, so it should go ahead and do the probing itself.

If the handoff indicates SUCCESS, it means that a different application is the highest priority application for the media mode for which the call was being handed off. The Unknown application should deallocate the call handle or change to being a monitor while the new owner has control and proceeds with probing.

The receiving application controls the call. If the probe is successful, it should set the correct media mode bit. If the probe fails, the application should clear the failed media mode bit in LINECALLINFO and hand the call off to the next highest priority application. If no more media mode bits are set, the handoff fails, because no suitable owner application exists for the call.

Eventually, the media mode may be identified through monitoring or successful probing, though the UNKNOWN bit still may be set in dwMediaMode in the data structure LINECALLINFO. In this case, the application that has received the call cannot be sure that it is the highest priority application for the identified media mode. It is now the duty of that application to ensure that the call goes to the highest priority application. To do so, it follows these steps:

•	It calls lineSetMediaMode, which writes into the dwMediaMode field of the call to turn off the UNKNOWN bit and specify the newly identified media mode bit.

•	It calls lineHandoff to return the call to TAPI. The TAPI dynamic link library is not explicitly specified in this command, but rather a media-type handoff is performed, through which the TAPI library knows that it must look for other applications to find the highest priority application for that media mode.

•	If this application is itself the highest priority application for this media mode, it receives a LINEERR_TARGETSELF return value (for the lineHandoff function call). This error means "No, you already are the highest priority application for that media mode." The application never loses control of the call, and it continues handling the call normally. If the lineHandoff succeeds, then there was a higher priority application for the identified media mode, and the application that called lineHandoff should deallocate its handle or change to being a monitor while the highest-priority application handles the call.

As long as the UNKNOWN bit is still on, the receiving application still does not know that the highest-priority media mode is present on the call, so it still needs to probe for it. It only considers the media mode to be present if the UNKNOWN bit is off—only then can it use the call as a call of that media mode.


Using Media Priorities while Probing

Unknown applications should take care to use default priorities given in the preceding table when probing for applications to take calls of unknown media modes. One reason to do this is to protect human callers from hearing unpleasant fax or modem signals. If, for example, both the INTERACTIVEVOICE and the G3FAX bits are set in LINEMEDIAMODE_, a human caller may still be on the other end of the line. The application should wait to start probing for a fax (with a fax tone) until it is sure that the call is not a voice call. The way to be sure is to probe first for voice, which occurs automatically if following the order stated in the default media-mode list.

However, while probing for high-priority media modes, it is a good idea to turn media monitoring on. This feature, invoked by calling lineMonitorMedia, detects signals that indicate other media. For example, one application may be playing an outgoing "leave a message" voice message while the incoming call starts sending a fax "calling" tone and waits for a handshake. In order not to lose the fax call, the local application needs to be monitoring for this tone while playing the voice message. Determining the lower-priority media (the fax call) while actively probing for the higher-priority media (voice) is not only a safer method—it helps prevent the loss of a call—it is efficient because it can shorten the probing process.


No "Unknown" Application Is Running

If no Unknown application has the line open, the TAPI dynamic link library itself assumes the role of a simplistic Unknown application. The TAPI library first passes an owner handle for the call to the highest priority application that is registered for the highest-priority media mode for which a media mode flag is set in LINECALLINFO.dwMediaMode. If there is no such application, the media mode flag is cleared, and TAPI tries the highest priority application for the next highest-priority media mode. If there is such an application, it can try to make a determination for the highest priority media mode in LINECALLINFO.dwMediaMode.

If no application is found to become the initial owner of a call, the call remains in the offering state until a monitor application becomes an owner through lineSetCallPrivilege, or until the call is abandoned by the calling party and is transitioned (by the service provider) to the idle state, at which time all monitoring applications deallocate their handles to the call.


Duties of the Media Application

The media mode application that receives a call as a handoff target first checks the bit flags of LINECALLINFO.dwMediaMode. If only a single media mode flag is set, the call is officially of that media mode, and the application can act accordingly.

If the UNKNOWN and other media mode flags are set, the media mode of the call is officially UNKNOWN, but is assumed to be one of the media modes for which a flag is set in LINECALLINFO. The application should now probe for the highest priority media mode.

If more than one bit is set in LINECALLINFO and the call has not been answered, the application must perform a lineAnswer to continue probing. If the call has already been answered, the application can continue probing without having to first answer the call.

If the probe succeeds (either for the highest-priority media mode or for another one), the application should set LINECALLINFO.dwMediaMode to the single media mode that was recognized. If the actual media mode is this expected media mode, the application can act accordingly. Otherwise—if it makes a determination of another media mode—it must first attempt to hand off the call in case it is not the highest priority application for the detected media mode.

If the probe fails, the application should clear the flag for that media mode in LINECALLINFO.dwMediaMode, and hand the call off to the Unknown application. It should also deallocate its call handle or revert back to monitoring the call. At this point, the fate of the call is determined by the steps described under the preceding sections of this chapter—depending on whether or not an Unknown application is active.

If the attempt to hand off the call to the UNKNOWN application fails, this means that no unknown application is running. It is then the responsibility of the application that currently owns the call to attempt to hand it off to the next-highest-priority media mode (while leaving the UNKNOWN bit turned on in LINECALLINFO.dwMediaModes). If that handoff fails, the application should turn off that media bit, and attempt the next higher-priority bit, until the handoff succeeds or all of the bits are off except for the UNKNOWN bit.

If none of the media modes were determined to be the actual one, only the UNKNOWN flag will remain set in LINECALLINFO.dwMediaMode at the time the media application attempts to hand the call off to UNKNOWN. The final lineHandoff invocation will fail if the application is the only remaining owner of the call. This failure informs the application that it should drop the call and then deallocate the call's handle. At this point, the call is abandoned.


Receiving Incoming Calls

Once the target application has been determined, it is given the call. The following points pertain to the target application as it accepts and answers calls:


Accepting and Answering Calls

On a POTS network, the only reason for an application to call lineAccept is to inform other applications that it has accepted responsibility to present the call to the user. Similarly, on an ISDN line, the effect of accepting a call is to make other applications aware that some application has accepted responsibility for handling the call.

On an ISDN network, accepting a call also informs the switch that the application will present the call to the user (by alerting the user for example, by ringing or by "popping up" a dialog box). If the LINEADDRCAPFLAGS_ACCEPTTOALERT bit is set, the application must perform a lineAccept on the call or the call will not ring. If the application fails to call lineAccept quickly enough (the timeout may be as short as three seconds on some ISDN networks), the network will assume that the station is powered off or disconnected and act accordingly, such as by deflecting the call (if Forward on No Answer is activated) or sending a disconnect message to the calling station.

Accepting a call is not the same as answering a call. Answering calls, in POTS, simply means to go offhook. On an ISDN line, it means to tell the switch to place the call in a connected state. Before answering, there is no physical connection for the call between the switch and the destination, though the call is connected from the caller to the switch.

Sometimes a call has already been answered when a new application takes control of it. This can occur, for example, when one application discovers that it is not the highest priority application for a call of a given media mode, and it hands the call off. If the first application has already answered the call, the receiving application takes control of an answered call. It should treat the call normally—that is, as if it had answered the call itself. Another example is when a user instructs an application to operate on an existing call. In this case, the application seizes the call. Again, it should treat the call as if it had answered it.


Waiting a Minimum Number of Rings

The lineGetNumRings function can be used by any application to determine the number of times an inbound call on the given address should ring before the call is to be answered. Waiting a certain number of rings allows callers to be spared the charge of a call connection if it seems that the call will not be answered by the desired party (usually a person). This feature is sometimes called toll-saver support. Applications can use the functions lineGetNumRings and lineSetNumRings in combination to provide a mechanism to support toll-saver features for multiple independent applications.

Any application that receives a handle for a call in the offering state and a LINE_LINEDEVSTATE ringing message should wait a number of rings equal to the number returned by lineGetNumRings before answering the call in order to honor the toll-saver settings across all applications. The function lineGetNumRings returns the minimum number of rings any application has specified with the function lineSetNumRings. Since this number may vary dynamically, an application should call lineGetNumRings each time it has the option to answer a call—that is, when it is the owner of a call still in the offering state. A separate LINE_LINEDEVSTATE ringing message is sent to the application for each ring cycle.

If the service provider is set to auto-answer calls, it answers after a certain number of rings. Service providers do not have access to the minimum-ring information established by lineSetNumRings, and therefore will make their own determination of when to automatically answer an incoming call. When a call has been so answered by a service provider, it will be initially delivered to the owning application already in the connected state, so the application will not need to be concerned with counting rings or with answering the call.


Taking Ownership of a Call

In general, when one application learns that another application wants ownership of a call, it simply relinquishes ownership of the call to that other application. Although there can be many co-owners of a call, it should be a transitory state for there to be multiple owners.

In one specific case, it is valid for an application to actively take ownership of a call owned by another application. This is when the application is instructed to do so by the user—perhaps through a user interface. For example, a fax application may be instructed by a user to break into that same user's existing voice call and use the call to send a fax. In this case, the fax application takes ownership from the previous owner, the application that was controlling the voice call.

An application can forcibly become owner of a call by taking the following steps:

•	Obtain a handle to the call with monitor privilege. If the desired call is one for which the application does not yet have a handle, it should request a handle with lineGetNewCalls. If the application is already a co-owner of the call and wants to become sole owner, it should start by calling lineSetCallPrivilege with the parameter dwCallPrivilege set to LINECALLPRIVILEGE_MONITOR. This action, which relinquishes ownership of the call (temporarily, in this case), is seen by other applications as the departure of an owner.

•	Call lineSetCallPrivilege with the parameter dwCallPrivilege set to LINECALLPRIVILEGE_OWNER for the call. Other applications see a new owner coming on line by receiving a LINE_CALLINFO message stating that the number of owners has increased and the number of monitors has changed; the bit LINECALLINFOSTATE_NUMOWNERINCR is on. These applications should yield the call to the new owner but there is no guarantee that they will do so. If the other existing owners do relinquish ownership, the new owner can proceed with what it intended to do on the call.

Note  There is no way to shield a call from another application's attempt to become an owner of it, nor is there any reason to do so. Once an application is informed that another application has become an owner, it should draw its activities on the call to an orderly close, and then relinquish ownership, because such changes in ownership are almost always done at the explicit direction of the user.


Relinquishing a Call

An application can relinquish ownership of a call by invoking lineSetCallPrivilege to change to a monitor application, or simply by using lineDeallocateCall to indicate that it has no further interest in the call. If the application is the sole owner of the call and cannot hand off ownership to another application, TAPI will not permit it to change to being a monitor or to deallocate its call handle—in this situation, the application has no choice but to drop the call.


Control of the Media Stream

An application that has just obtained a call may not immediately receive control of the media stream, and may need to wait until the previous owner application relinquishes it. Though this may take time, any application with control of the media stream should transfer control when it sees that a new owner has come on line (the number of owners has increased).

The procedures for transferring control of an active media stream differ for every media-control API. The API may allow only one application to have a media-stream device (such as a COM port used for data transfer) open. In this case, it is important that the current owner relinquish control of a media stream device before handing off the call. But with some other types of media such as WAV audio, several applications (and several devices) can have the media stream open at the same time. This makes it unnecessary to close the media stream before the handoff, and perhaps not at all.


Call Handoffs

After an application has acquired ownership of the call, ownership can be transferred to another application. Why would this be necessary? Normally, to allow the call's media mode to be changed. In this case, the highest priority application for the new media mode should take and handle the call. Media mode changing usually occurs because of one of these causes:

•	User Command  Through a user interface or through Windows messages, the application learns that the local user wants to change media mode. For example, the user has told the new "target" application (which is not yet an owner) to obtain an existing voice call for transmitting data. The target application must now take control of the call. In this case, the current owner notices the number of owners increase, and then relinquishes its control of the call.

Alternatively, the user could instruct the current owner of the call to hand it off to an application that can handle the new media mode.

•	Media Mode Change  The service provider can detect a media mode change with lineMonitorMedia. As an example of this, the local application is playing a recorded voice message to the caller. During this message, the caller spontaneously decides to transmit a fax calling tone, and the local application can respond accordingly by changing the media mode to fax and, if necessary, handing the call off to a fax application.

Another way this can work is for a monitoring application to enable media mode monitoring, and, when the media mode in which it is interested is detected on a call, it can request ownership of the call. This mechanism makes it unnecessary for every application to monitor every call for every media mode.

•	Remote Party Command  The remote party can interactively indicate a change in media modes during an existing call. For example, the local application is using lineMonitorDigits to monitor DTMF input by the remote caller. Through this monitoring, the caller indicates, for example, that a fax is about to be sent. Other ways the caller can control local applications is with commands received on other data connections and through ISDN user-user information messages.

A call handoff will have one of these outcomes:

•	the call is given to another application (SUCCESS),

•	the handing-off application is itself the target (TARGETSELF),

•	the handoff fails (TARGETNOTFOUND).

If the application that is receiving the handed-off call already has a call handle to the call, this old call handle is used. Otherwise a new call handle is created. In either case, the application ends up with owner privileges to the call. Whenever the handing-off application is not the same as the target application, the target is informed about the handoff in a LINE_CALLSTATE message with dwParam3 set to LINECALLPRIVILEGE_OWNER, as if it were receiving a new call.

Note  The LINE_CALLSTATE parameter dwParam3 is set to owner only if the LINE_CALLSTATE message is being sent to an application that is the initial owner of a new call, is the target of a handoff, or was previously a monitor or an owner of the call. The parameter dwParam3 can be set to monitor only if the LINE_CALLSTATE message is sent to the application when it is presented a new call for monitoring. In all other cases (such as when the application already has a handle to the call, and its ownership state is not being changed), dwParam3 is set to 0.

If the current owner application is told to change modes, it does so by handing off the call to an application used for the target media mode. The two types of call handoffs are described in the following sections:


Directed Handoffs

A directed handoff takes place when the target application is known by name to the original application. This situation would occur, for example, among a set of applications written by the same vendor. Control of directed handoffs can usually be configured by the user. With such a handoff, the call is given to the specified application if it has opened the line on which the call exists. The media mode specified at the time the application opened the line is ignored. One common example is a voice call followed by fax transmission in the same call. Directed handoff would most often be used by applications from the same developer that are linked in other ways as well.

Directed handoff may also be used in future versions of Windows as part of the process of arbitrating multiple applications waiting for incoming calls of the same media mode, with the selection of the application to handle the call being based on data-link or higher level protocol detection rather than media mode. An example of its use would be an incoming datamodem line with applications such as remote takeover, bulletin board, remote network access, and remote email access all waiting for calls simultaneously.


Media Mode Handoffs

A media mode handoff takes place when there is a new, targeted media mode, usually when the owning application determines that the media mode needed for the call is not present or is about to change. The process for a media-dependent handoff can be a probing process if the UNKNOWN bit is on, and is virtually the same as for the initial assignment of a call to an application. The difference is the fact that lineHandoff can have only one media-mode bit set.

Because only a single media mode bit can be specified, the call is given to the highest priority application for that media mode. However, it is possible that more than one media mode is to be considered for the handoff. In this case, the handing-off application should specify the highest-priority of the possible media modes as a parameter for lineHandoff. If an applications specifies the UNKNOWN bit when performing a media-mode handoff and the handoff fails, this means that no Unknown application is currently running. The handing off application should then try to hand the call off to the highest priority application registered for the next higher media mode.

The receiving application is now responsible for the call. It now probes for the call's actual media mode. If the call's media mode matches that handled by the application, it must ensure that it is the highest-priority application registered for that media mode. If so, it keeps the call and processes it normally. If not, it hands the call off to another application registered for that media mode.

If, however, the probe for that media mode fails, the application probes again, attempting the remaining media-mode possibilities. It determines these by examining the dwMediaMode field in the LINECALLINFO structure. But first, using the lineSetMediaMode function, the owning application turns off the bit for the current (disproved) media mode in the dwMediaMode field.

This process of probing and handing off continues, and the remaining media modes are eliminated one by one. Along the way, one of the applications may see that the media mode it handles is on the call, and the handoff is successful. The application should now perform a final lineSetMediaMode to set the correct media mode and clear all other media-mode bits. This informs other interested applications of the correct media mode. These other applications receive a LINE_CALLINFO message stating that the call's media mode has changed. To determine the correct media mode, they invoke lineGetCallInfo and examine the dwMediaMode field in the LINECALLINFO structure.

It is the responsibility of the owning application to cycle through media modes to find the highest-priority application. TAPI does this cycling only on the initial incoming call to find the first owner. It does not do it when lineHandoff is called.

To sum up the media-mode handoff process, TAPI does not check for other media bits during lineHandoff. TAPI only attempts to hand off to the single media mode indicated in the parameter to lineHandoff. It is up to the application to turn off the bit corresponding to the media mode that failed to hand off, and to try other media modes until the handoff succeeds or all the possible media modes are exhausted. If it gets to a point where all of the bits are off except for UNKNOWN, it must abandon the call by calling lineDrop and then deallocating the handle.


Logging Calls

Logging a call simply means actively recording the actions and states of a monitored call into a file on a disk. (An application that owns a call is also a monitor of that call.) Though limited call logging is performed by the call manager provided with Windows Telephony, any application can be programmed to log a call that it is monitoring.

TAPI facilitates logging by allowing applications to monitor calls and by collecting information from other applications that are controlling calls. TAPI writes the information it collects into the LINECALLINFO structure, which can then be read by applications.


Sources of Log Information

Information useful to call logging (which is saved by TAPI) originates in the following sources. This information is placed in the LINECALLINFO data structure.

• 	Initialization Function:  In an application's call of the initialization function (lineInitialize), it provides information such as the application's name. An application should ensure that the information it provides with the initialization command is accurate so that its activities are reflected correctly in the call log.

•	The LINECALLPARAMS data structure (used in the function lineMakeCall): This structure stores information such as the name of the called party, the originating address, and the destination address. This structure is passed to TAPI by any application that originates a call.

•	The Service Provider:  The service provider supplies many items that can be logged such as caller's ID.

•	The LINE_CALLSTATE messages that pertain to a given call are an important source of logging information because they indicate whether the call successfully connected or was abandoned because of a busy signal, no answer, network congestion, or other causes.

The start time, end time, and duration of a call are not recorded by TAPI. A logging application that wants to log this information must record the time by checking the system clock when certain LINE_CALLSTATE messages (such as CONNECTED, DISCONNECTED, and IDLE) are received, and then derive the related time log information.


Using the LINECALLINFO Data Structure

The LINECALLINFO structure stores a large amount of information about a call, and is thus an important source of data. Generally, a logging application reads from LINECALLINFO and write this information into its log file.

A separate LINECALLINFO structure exists for every inbound and outbound call. Information in this structure is obtained by an application with lineGetCallInfo. An application typically reads the information from LINECALLINFO at the following times:

•	when the application first receives a handle for a call in the LINE_CALLSTATE message.

•	each time the application receives notification in a LINE_CALLINFO message that LINECALLINFO has changed. Whenever any part of the structure changes, a LINE_CALLINFO message is sent to the application indicating which information item has changed.

Both the LINE_CALLSTATE message and the LINE_CALLINFO message also supply the call's handle as a parameter.

Much of the information held in LINECALLINFO remains fixed for the duration of the call. Information about a call that changes dynamically, such as call progress status, is available in the LINECALLSTATUS structure, which is returned with the function call lineGetCallStatus. Other information needed by logging applications that is not stored in LINECALLINFO is call start time, call stop time, and the call's duration, which it determines by checking the system time when the corresponding LINE_CALLSTATE messages are received.

LINECALLINFO stays intact after the call is disconnected, so the logging application can later read it in order to write additional information into the log. LINECALLINFO remains available only until the last application that had a handle for the call (owner and monitor handles) deallocates its handle.


Deallocating a Call

If an application is finished with a call and another application wants the call, the call can be handed off. But if no other applications want to take ownership, there is nothing to do but deallocate the call's handle. This is done with lineDeallocateCall. A call handle is no longer valid after it has been deallocated.

In contrast, dropping (disconnecting) a call puts the call in the idle state, which means that the local end of the connection is on hook. If the other end of the connection drops the call, the call transitions to the disconnected state, not the idle state. Typically, once an application receives a call-state message indicating the disconnected state, it immediately drops the call, causing it to become idle. Although the call is in the idle state, any handles to it held by applications remain valid until they are deallocated. If the call was never answered (the local end never went off hook), it may revert to the idle state without being dropped.

An application cannot deallocate a call if it is the sole owner and the call's state is not idle. This is because TAPI tries to ensure that there is always at least one owner for every active call. If the application is the sole owner and the call is not idle, the error message LINEERR_INVALCALLSTATE is returned. If an application needs to circumvent this restriction, it can do so by dropping the call first (with lineDrop) and then deallocating its handle. This prevents an application from deallocating its handle which would result in a call disconnect. By making the application do an explicit drop, it can inform the user (in a dialog box) that the call is about to be disconnected.

If releasing the ownership handle results in the call's having no more handles, TAPI calls the service provider function TSPI_lineCloseCall. When this function is invoked on a call that is not yet idle, it is up to the service provider to drop the call.

Note  An application that has monitor privileges for a call can always deallocate its handle for the call. Deallocating a call does not affect the call state of the physical call, but it does release the internal resources (memory) related to the call.

An application should deallocate the handle to a call it owns in these two cases:

•	Idle call state  If an application receives a LINE_CALLSTATE message indicating that the call has transitioned to the idle state, and has already gathered all the information it needs about the call, it should deallocate the call handle immediately.

•	Handoff  The application has handed off the call (or has otherwise relinquished call ownership to another application) or has set its call privilege to monitor, and has no interest in monitoring or logging the call.

Note that failure to deallocate call handles in a timely way can result in system failure and lost calls due to unnecessary consumption of memory and other resources.


Closing Lines

An application should close a line it has open in the following cases:

•	Before Exiting  An application should always close all lines it has open before it becomes inactive.

•	For non-TAPI Applications  TAPI applications should cooperate with non-TAPI applications that use media stream devices such as COM ports. If your TAPI device is a serial device accessed through a COM port (such as a modem) and the line is open, the service provider needs to have the COM port open. But with the COM port open, non-TAPI Windows applications and DOS applications are prevented from accessing the COM port. Therefore, a TAPI application should open the line (and keep it open) only if it is waiting for incoming calls or it is actively engaged in placing an outgoing call.

Non-Telephony communications applications may need to share resources with Telephony applications.

The data structure LINEDEVCAPS contains a capabilities bit (LINEDEVCAPFLAGS_CLOSEDROP) that tells whether closing a line while a call is still active causes calls on the line to be dropped. If TRUE, calling lineClose drops (clears) all calls on the line if the application is the sole owner of those calls. If the bit is set to FALSE, lineClose does not automatically drop any calls still active on the line.

Therefore, an application can examine LINEDEVCAPS to detect in advance whether closing a line will cause this active call to be dropped. The application should warn all appropriate users that the call is about to be dropped, perhaps by displaying an OK/Cancel dialog box that lets the user keep the line open.

For example, if a desktop computer and a phoneset are both connected directly to an analog line (in a party-line configuration), the service provider should set the flag to FALSE, as the offhook phone would automatically keep the call active even after the computer powers down.

As another example, a user of Microsoft Windows is speaking on the phone on a call owned by an active application. The user decides to leave the office for the day and shuts down Windows. Windows in turn shuts down the active telephony application, which attempts to close the lines it has open. Whether the call is automatically hung up depends on whether the LINEDEVCAPFLAGS_CLOSEDROP bit in LINEDEVCAPS is set or not and whether the phone is off hook.

If other applications are monitoring the call, the service provider will not even be informed that one application has closed the line. It is only when the last application that has a handle to the call closes the line that the service provider is informed (with TSPI_lineClose). At that point, it is up to the service provider to handle any remaining calls. If the service provider is required to drop the calls, it should do so but it should first warn applications about this requirement with the LINEDEVCAPFLAGS_CLOSEDROP flag.

Closing an application should ideally perform the following cleanup tasks:

•	Dispose of all calls.

•	Close all open lines and phones.

•	Shut down the usage of the Telephony API.

Failure to do so may leave calls in indeterminate states.


Learning About Existing Calls at Application Startup

Applications can become aware of existing calls on the line at the time of application startup with lineGetNewCalls. This function gives the application handles (with monitor privilege) to all the calls on the line or address for which it did not already have handles.

An example of the usefulness of this mechanism is when a user starts a fax application during a voice call, having decided to send a fax. The new fax application needs to discover the existing call (using lineGetNewCalls) to request ownership of the call in order to send the fax.


Media Mode Updating

A call's media mode as stated in LINECALLINFO.dwMediaMode and a media mode message (LINE_MONITORMEDIA) sent from the service provider to the application can and often will differ. An application could use lineMonitorMedia to enable monitoring for particular media modes, and use any resulting LINE_MONITORMEDIA messages as guidance in determining what the calling party might be probing for or what the Unknown application should probe for first. LINE_MONITORMEDIA messages report events on the line (such as probes being received from the remote station) and not "hard" decisions about media modes. When an application determines that a call involves a particular media mode, it calls lineSetMediaMode to update LINECALLINFO.dwMediaMode and inform other applications of this update.


Communication Between Applications

Applications can communicate with each other by writing to and reading from a field in a specified call's information record, the LINECALLINFO data structure. With lineSetAppSpecific, any owner application can write to the application-specific field called dwAppSpecific. It is uninterpreted by the Telephony API or any of its service providers. This field's usage is entirely controlled by applications.

The field can be read from the LINECALLINFO record returned by lineGetCallInfo. However, lineSetAppSpecific must be used to set the field so that changes become visible to other applications. When this field is changed, all other applications with call handles are sent a LINE_CALLINFO message with an indication that the dwAppSpecific field has changed.


Special Cases

The following sections describe situations that could occur in multiple-application environments.


A Call Without an Owner

What happens to an incoming call if no applications have the line open with owner privilege? First, TAPI informs all monitoring applications on the line about the call. If no monitoring application switches to owner privilege to answer the call, the service provider eventually drops the call.

The following steps describe what normally happens if a line has only monitoring applications, a call comes in, and no applications answer the call. Assume that the service provider is not configured to answer new calls by itself.

•	The service provider passes the call handle to TAPI.

•	TAPI passes monitor handles to the monitor applications.

•	TAPI determines that the call is in the offering (not connected) state and lets the call "sit."

•	The remote party eventually hangs up, and the call reverts to the idle call state since it was never connected.

•	The monitors are notified that the call is idle and deallocate their handles if they have not already done so.

•	The last deallocation causes a TSPI_lineCloseCall.

Although the call in this example was never answered, its appearance and disappearance may have been significant to the applications monitoring the line. On a network that offers caller-ID, a user may wish to screen incoming calls, recording who has called without necessarily answering every call. Monitoring applications can help accomplish this without ever needing to answer a call.


The Call Is Answered Elsewhere

This scenario is similar to the first one, but the user answers the phone elsewhere on the line, and this answer is detected by the provider through the hardware. The call is reported as being in the connected state, though it is not connected to any application on the local computer. The call eventually goes idle, at which point each application (monitor as well as all owner applications) must deallocate its handle.

These are the steps of Scenario 2, in which a line has only monitoring applications,  the service provider is configured to not answer new calls by itself, and a call comes in.

•	The service provider passes the call handle to TAPI.

•	TAPI passes monitor handles to the monitor applications.

•	TAPI determines that the call in the offering (not connected) state and lets the call "sit."

•	The user picks up a ringing downline phone, and the call becomes connected.

•	All monitoring applications are sent a corresponding LINE_CALLSTATE message.

•	The user eventually hangs up the downline phone, and the call reverts to the idle state.

•	The monitor applications are notified the call is idle and deallocate their handles, if they have not already done so.

•	The last deallocation causes a TSPI_lineCloseCall.


Auto-Answer by the Service Provider

In this scenario, the provider is set up to auto-answer a new call. The provider answers it and determines the call's media mode. It then informs TAPI of the call. Since no applications decide to take ownership, TAPI cannot pass the call to any application.

A line has only monitoring applications. The service provider is configured to auto-answer all new calls. At this point, a call comes in.

These are the steps:

•	The service provider passes the call handle to TAPI.

•	TAPI passes monitor handles to the monitor applications (the call is in the connected state).

•	TAPI realizes that the call is connected, but there are, so far, no potential owners.

•	TAPI must do a TSPI_lineDrop to cause the call to revert to idle.

•	The monitor applications are notified that the call is idle and deallocate their handles if they have not already done so.

•	The last deallocation causes a TSPI_lineCloseCall.

This last example illustrates an important point for writers of monitoring applications. It is not a good idea to wait monitor for incoming calls you later want to own. It is better to open the line as an owner, because there might not be enough time to change your privilege from monitor to owner before TAPI drops the call.


Phone Devices

About Phone Devices

A phone device is one of the two device classes supported by TAPI. This chapter describes phone devices and explains how to use the TAPI phone functions to access these devices.


The Phone Device

A device that supports the phone device class as a device that includes some or all of the following elements:

•	Hookswitch/Transducer  This is a means for audio input and output. The Telephony API recognizes that a phone device may have several transducers, which can be activated and deactivated (taken offhook or placed onhook) under application or manual user control. TAPI identifies three types of hookswitch devices common to many phone sets:

Handset  The traditional mouth-and-ear piece combination that must be manually lifted from a cradle and held against the user's ear.

Speakerphone  Enables the user to conduct calls hands-free. The hookswitch state of a speakerphone can usually be changed both manually and by the API. The speakerphone may be internal or external to the phone device. The speaker part of a speakerphone allows multiple listeners.

Headset  Enables the user to conduct calls hands-free. The hook switch state of a headset can usually be changed both manually and by the API.

A hookswitch must be offhook to allow audio data to be sent to and/or received by the corresponding transducer.

•	Volume Control/Gain Control/Mute  Each hookswitch device is the pairing of a speaker and a microphone component. The API provides for volume control and muting of speaker components and for gain control or muting of microphone components.

•	Ringer  A means for alerting users, usually through a bell. A phone device may be able to ring in a variety of modes or patterns.

•	Display  A mechanism for visually presenting messages to the user. A phone display is characterized by its number of rows and columns.

•	Buttons  An array of buttons. Whenever the user presses a button on the phone set, the API reports that the corresponding button was pressed. Button-Lamp IDs identify a button and lamp pair. Of course, it is possible to have button-lamp pairs with either no button or no lamp. Button-lamp IDs are integer values that range from 0 to the maximum number of button-lamps available on the phone device, minus one. Each button belongs to a button class. Classes include call appearance buttons, feature buttons, keypad buttons, and local buttons.

•	Lamps  An array of lamps (such as LEDs) individually controllable from the API. Lamps can be lit in different modes by varying the on and off frequency. The button-lamp ID identifies the lamp.

•	Data Areas  Memory areas in the phone device where instruction code or data can be downloaded to and/or uploaded from. The downloaded information would affect the behavior (or in other words, program) the phone device.

TAPI allows an application to monitor and control elements of the phone device. The most useful elements for an application are the hookswitch devices. The phone set can act as an audio I/O device (to the computer) with volume control, gain control and mute, a ringer (for alerting the user), data areas (for programming the phone), and perhaps a display, though the computer's display is more capable. The application writer is discouraged from directly controlling or using phone lamps or phone buttons, since lamp and button capabilities can vary widely among phone sets, and applications can quickly become tailored to specific phone sets.

There is no guaranteed core set of services supported by all phone devices as there is for line devices (the Basic Telephony services). Therefore, before an application can use a phone device, the application must first determine the exact capabilities of the phone device. Telephony capability varies with the configuration (client versus client-server), the telephone hardware, and the service-provider software. Applications should make no assumptions as to what telephony capabilities are available. An application determines the device capabilities of a phone device by calling the phoneGetDevCaps function. A phone's device capabilities indicate which of these elements exist for each phone device present in the system and what their capabilities are. Although strongly oriented towards real-life telephone sets, this abstraction can provide a meaningful implementation (or subset thereof) for other devices as well. Take as an example a separate headset directly connected and controllable from the computer and operated as a phone device. Hookswitch changes can be triggered by detection of voice energy (offhook) or a period of silence (onhook); ringing can be emulated by the generation of an audible signal into the headset; a display can be emulated through text-to-speech conversion.

Note that a phone device need not be realized in hardware, but can instead be emulated in software using a mouse- or keyboard-driven graphical command interface and the computer's speaker or sound system. Such a "soft phone" can be an application that uses TAPI. It can also be a service provider, which can be listed as a phone device available to other applications through the API, and as such is assigned a phone device ID.

Depending on the environment and configuration, phone sets can be shared devices between the application and the switch. Some minor provision is made in the API where the switch may temporarily suspend the API's control of a phone device.


Initialization and Shutdown

For an application to use any of TAPI's 30 supplementary phone functions, it needs a connection to TAPI.DLL, through which it can receive messages. The application establishes this connection using the phoneInitialize function. One of the parameters passed to TAPI.DLL in these function calls is a pointer to the application's callback function. After initialization, TAPI uses this pointer to notify the application of the asynchronous completion of functions.

The phoneInitialize function returns two pieces of information to the application: an application handle, and the number of phone devices. The application handle represents the application's usage of TAPI. The TAPI functions that use phone handles do not require the application handle, as this handle is derived from the specified phone handle.

The second piece of information returned by phoneInitialize is the number of phone devices available to the application through the Telephony API. Phone devices are identified by their device identifier (device ID). Valid device IDs range from zero to the number of phone devices minus one. For example, if phoneInitialize reports that there are two phone devices in a system, then valid phone device IDs are 0 and 1. Once an application is finished using the phone functions of TAPI, it invokes phoneShutdown, passing its application handle to shut down its usage of TAPI. This allows TAPI to free any resources assigned to the application.

Both phoneInitialize and phoneShutdown operate synchronously. That is, these functions either return a success or failure indication, and never return an asynchronous Request ID.


Opening and Closing Phone Devices

After determining the capabilities of a phone device, an application must open the device before it can access functions on that phone. After a phone device has been successfully opened, the application is returned a handle representing the open phone. A phone device can be opened in different modes, thus providing a structured way of sharing a phone device.

The function phoneOpen opens the specified phone device to give the application access to functions on the phone. A phone device is identified to phoneOpen by means of its device ID, which is passed as the parameter dwDeviceID.


Operating Modes and Privileges

The application can request one of two operating modes when opening a phone device. These modes reflect the privileges the application requests for the device:

•	Opening a phone for monitor privileges lets the application determine the status of the phone device. Messages are sent to the application's callback function when status changes on the phone device are detected.

•	An application that opens a phone device for owner privileges can use operations that modify the state of the phone device. Owner privilege automatically includes full monitor privileges as well. At any time, a given phone device can be open only once for owner privileges, but multiple times for monitor privileges. All phoneSet operations require owner privileges, while all phoneGet operations require only monitor privileges.


Device IDs

Other TAPI phone functions use a handle to an open phone device to identify the open phone device. The only functions for phone devices that take a phone device ID parameter (as opposed to a phone handle) are the phoneGetDevCaps and phoneOpen functions. An application can retrieve the phone's device ID by using the function phoneGetID with the phone handle as a parameter.

An application can also obtain device IDs for various Windows device classes associated with an opened phone by invoking phoneGetID. See Chapter 9, "Device Classes" device class names.

This function takes a phone handle and a device class description. It returns the device ID for the device of the given device class that is associated with the open phone device. If the device class is "tapi/phone," the device ID of the phone device is returned.

In contrast with line devices, for which the basic line services provide the equivalent of POTS, no minimum guaranteed set of functions is defined for phone devices. While each phone device provides at least the functions and messages described in this section, they do not offer any actual operations on the physical phone device.


Closing the Phone Device

The function phoneClose closes the specified phone device. The phone device may also be forcibly closed after the user has modified the configuration of that phone or its driver. If the user wants the configuration changes to be effective immediately (as opposed to after the next system restart), and they affect the application's current view of the device (such as a change in device capabilities), then a service provider may forcibly close the phone device.

Note that these messages can also be sent unsolicited as a result of the phone device being reclaimed in some other manner. An application should therefore be prepared to handle unsolicited PHONE_CLOSE messages. At the time the phone device is closed, any outstanding asynchronous replies pertaining to that device are suppressed.


Hookswitch Devices

A phone device may have multiple hookswitch devices. (A hookswitch is the switch that connects or disconnects a device from the phone line. On a telephone, for example, this is the switch that is automatically activated when a user lifts the receiver from the cradle to get a new dial tone.) The Telephony API defines three types of hookswitch devices for a phone: handset, speakerphone, and headset. Each hookswitch device has a speaker and a microphone component, and operates in one of four hookswitch modes:

•	Onhook  The hookswitch device is onhook, and both its microphone and speaker are disabled.

•	Microphone only  The hookswitch device is offhook, its microphone is enabled, and its speaker is mute.

•	Speaker only  The hookswitch device is offhook, its microphone is mute, and its speaker is enabled.

•	Microphone and speaker  The hookswitch device is offhook, and both microphone and speaker are enabled.

The phoneSetHookSwitch function is used to set the hookswitch mode of one or more of the hookswitch devices of an open phone device. For example, to mute or unmute the microphone or speaker component of a hookswitch device, use phoneSetHookSwitch with the appropriate hookswitch mode. The function phoneGetHookSwitch can be used to query the hookswitch mode of a hookswitch device of an open phone device.

When the mode of a phone's hookswitch device is changed manually, for example by lifting the handset from its cradle, a PHONE_STATE message is sent to the application's callback to notify the application about the state change. Parameters to this message provide an indication of the change.

The volume of the speaker component of a hookswitch device can be set with phoneSetVolume. Note that volume setting is different from mute in that muting a speaker and later unmuting it will preserve the volume setting of the speaker. The phoneGetVolume function can be used to return the current volume setting of a hookswitch device's speaker of an open phone device.

The microphone component of a hookswitch device can also be gain controlled. Note that gain setting is different from mute in that muting a microphone and later unmuting it will preserve the gain setting of the microphone. Use phoneSetGain to set the gain of a hookswitch device's microphone of an open phone device, and phoneGetGain to return the gain setting of a hookswitch device's microphone of an opened phone.

When the volume or gain of a phone's hookswitch device is changed, a PHONE_STATE message is sent to the application's callback function to notify the application about the state change. Parameters to this message provide an indication of the change.


Display

The Telephony API provides access to a phone's display. The display is modeled as an alphanumeric area with rows and columns. A phone's device capabilities indicate the size of a phone's display as the number of rows and the number of columns. Both these numbers are zero if the phone device does not have a display. Use phoneSetDisplay to write information to the display of an open phone device, and phoneGetDisplay to retrieve the current contents of a phone's display.

When the display of a phone device is changed, a PHONE_STATE message is sent to the application's callback function to notify the application about the state change. Parameters to this message provide an indication of the change.


Ring

A single phone may be able to ring with different ring modes. Given the wide variety of ring modes available, ring modes are identified by means of their ring mode number. A ring mode number ranges from zero to the number of available ring modes minus one.

The functions an application would use to control a phone device's ring modes are phoneSetRing, which rings an open phone device according to a given ring mode, and phoneGetRing, which returns the current ring mode of an opened phone device.

When the ring mode of a phone device is changed, a PHONE_STATE message is sent to the application's callback function to notify the application about the state change. Parameters to this message provide an indication of the change.


Buttons

The Telephony API models a phone's buttons and lamps as button-lamp pairs. A button with no lamp next to it or a lamp with no button is specified using a "dummy" indicator for the missing lamp or button. A button with multiple lamps is modeled by using multiple button-lamp pairs.

Information associated with a phone button can be set and retrieved. When a button is pressed, a PHONE_BUTTON message is sent to the application's callback function. The parameters of this message are a handle to the phone device and the button-lamp ID of the button that was pressed. The keypad buttons '0' through '9', '*', and '#' are assigned the fixed button-lamp IDs 0 through 11.

The functions associated with buttons are phoneSetButtonInfo, which sets the information associated with a button on a phone device, and phoneGetButtonInfo, which returns information associated with a button on a phone device. The PHONE_BUTTON message is sent to an application's callback when a button on the phone is pressed.

The information associated with a button does not carry any semantic meaning as far as TAPI is concerned. It is useful for device-specific applications that understand the meaning of this information for a given phone device, or for display to the user, such as online help.


Lamps

The lamps on a phone device can be lit in a variety of different lighting modes. Unlike ringing patterns, lamp modes are more uniform across phone sets of different vendors. A common set of lamp modes is defined by the API. A lamp identified by its lamp-button ID can be lit in a given lamp mode. A lamp can also be queried for its current lamp mode.

The TAPI functions used for lamps are phoneSetLamp, which lights a lamp on a specified open phone device in a given lamp lighting mode, and phoneGetLamp, which returns the current lamp mode of the specified lamp.

When a lamp of a phone device is changed, a PHONE_STATE message is sent to the application's callback function to notify the application about the state change. Parameters to this message provide an indication of the change.


Data Areas

Some phone sets support the notion of downloading data from or uploading data to the phone device, which allows the phone set to be programmed in a variety of ways. The Telephony API models these phone sets as having one or more download or upload areas. Each area is identified by a number that ranges from zero to the number of data areas available on the phone minus one. Sizes of each area may vary. The format of the data itself is device-specific.

The TAPI phoneSetData function downloads a buffer of data to a given data area in the phone device, and the phoneGetData function uploads the contents of a given data area in the phone device to a buffer.

When a data area of a phone device is changed, a PHONE_STATE message is sent to the application's callback function to notify the application about the state change. Parameters to this message provide an indication of the change.


Status

Most of the get and set operations deal with one component of information only. The phoneGetStatus function returns complete status information about a phone device to an application.

As mentioned earlier, whenever a status item changes on the phone device, a PHONE_STATE message is sent to the application's callback function. This message's parameters include a handle to the phone device and an indication of the status item that changed.

An application can use phoneSetStatusMessages to select the specific status changes for which it wants to be notified through the callback. Correspondingly, phoneGetStatusMessages returns the status changes for which the application wants to be notified.


Extended-Telephony Phone Functions

The Extended Phone Services (or Device-Specific Phone Services) include all extensions to the Telephony API defined by the service provider. TAPI defines a mechanism that enables service-provider vendors to extend TAPI using device-specific extensions. TAPI defines only the extension mechanism, and by doing so provides access to device-specific extensions. The Telephony API does not define their behavior, which is completely defined by the service provider.

TAPI consists of scalar and bit-flag data constant definitions, data structures, functions, and callback messages. Procedures are defined that enable a vendor to extend most of these as follows:


Scalar Data Constants

For extensible scalar data constants, a service-provider vendor may define new values in a specified range. Since most data constants are DWORDs, the range 0x00000000 through 0x7FFFFFFF is typically reserved for common future extensions, while 0x80000000 through 0xFFFFFFFF is available for vendor-specific extensions. The assumption is that a vendor would define values that are natural extensions of the data types defined by the API.


Bit-Flag Data Constants

For extensible bit-flag data constants, a service-provider vendor may define new values for specified bits. Since most bit-flag constants are DWORDs, a specific number of the lower bits are usually reserved for common extensions, while the remaining upper bits are available for vendor-specific extensions. Common bit flags are assigned from bit zero up, and vendor-specific extensions should be assigned from bit 31 down. This scheme provides maximum flexibility in assigning bit positions to common extensions, as opposed to vendor-specific extensions. A vendor is expected to define new values that are natural extensions of the bit flags defined by the API.

Extensible data structures have a variably sized field that is reserved for device-specific use. Because the field is variably sized, the service provider decides the field's amount of information and interpretation. A vendor that defines a device-specific field is expected to make these natural extensions of the original data structure defined by the API.


Functions and Messages

The phoneDevSpecific function and its associated PHONE_DEVSPECIFIC message enable an application to access device-specific phone features that are unavailable through the common Telephony services for phones. In other words, phoneDevSpecific is the device-specific escape function that allows vendor-dependent extensions, and PHONE_DEVSPECIFIC is the device-specific message that is sent to the application's callback function.

The parameter profile of the phoneDevSpecific function is generic in that little interpretation of the parameters is made by the Telephony API. Rather, the interpretation of the parameters is defined by the service provider and must be understood by an application that uses them. The parameters are simply passed through by TAPI.DLL from the application to the service provider. An application that relies on device-specific extensions will usually not work with other service providers, but applications written to the common telephony phone services will work with the extended service provider.


Line Device Functions

About Line Device Functions

This chapter contains an alphabetical list of the functions in the Telephony Applications Programming Interface (API).

The information for each function includes a list of the valid call states on entry of the function and typical call state transitions when the request completes. Note that the actual states in which a function may be performed may be further limited by the capabilities of the service provider; applications must check the dwCallFeatures field in the LINECALLSTATUS structure, the dwAddressFeatures field in the LINEADDRESSSTATUS structure, and the dwLineFeatures field in the LINEDEVSTATUS structure to determine whether or not a function is permitted at that point in time.


Reference

Following are the Telephony API functions.


lineAccept

[New - Windows 95]

LONG lineAccept(HCALL hCall, LPCSTR lpsUserUserInfo, DWORD dwSize)

Accepts the specified offered call. It may optionally send the specified user-to-user information to the calling party.

•	Returns a positive request ID if the function will be completed asynchronously, or a negative error number if an error has occurred. The dwParam2 parameter of the corresponding LINE_REPLY callback message is zero if the function is successful or it is a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALCALLHANDLE	LINEERR_RESOURCEUNAVAIL
LINEERR_INVALCALLSTATE	LINEERR_OPERATIONUNAVAIL
LINEERR_NOTOWNER	LINEERR_UNINITIALIZED
LINEERR_INVALPOINTER	LINEERR_OPERATIONFAILED
LINEERR_NOMEM	LINEERR_USERUSERINFOTOOBIG
hCall

Specifies a handle to the call to be accepted. The application must be an owner of the call. Call state of hCall must be offering.

lpsUserUserInfo

Specifies a pointer to a string containing user-to-user information to be sent to the remote party as part of the call accept. This pointer can be left NULL if no user-to-user information is to be sent. User-to-user information is only sent if supported by the underlying network (see LINEDEVCAPS). The protocol discriminator field for the user-user information, if required, should appear as the first byte of the buffer pointed to by lpsUserUserInfo, and must be accounted for in dwSize.

dwSize

Specifies the size in bytes of the user-to-user information in lpsUserUserInfo. If lpsUserUserInfo is NULL, no user-to-user information is sent to the calling party and dwSize is ignored.

The lineAccept function is used in telephony environments like Integrated Services Digital Network (ISDN) that allow alerting associated with incoming calls to be separate from the initial offering of the call. When a call comes in, it is first offered. For some small amount of time, the application may have the option to reject the call using lineDrop, redirect the call to another station using lineRedirect, answer the call using lineAnswer, or accept the call using lineAccept. After a call has been successfully accepted, alerting at both the called and calling device begins. After a call has been accepted by an application, the call state typically transitions to accepted.

Alerting is reported to the application by the LINE_LINEDEVSTATE message with the ringing indication.

The lineAccept function may also be supported by non-ISDN service providers. The call state transition to accepted can be used by other applications as an indication that another application has claimed responsibility for the call and has presented the call to the user.

The application has the option to send user-to-user information at the time of the accept. Even if user-to-user information is sent, there is no guarantee that the network will deliver this information to the calling party. An application should consult a line's device capabilities to determine whether call accept is available.


lineAddProvider

[New - Windows 95]

LONG lineAddProvider(LPCSTR lpszProviderFilename, HWND hwndOwner,
    LPDWORD lpdwPermanentProviderID)

Installs a new Telephony Service Provider into the Telephony system.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_INIFILECORRUPT	LINEERR_NOMEM
LINEERR_INVALPARAM	LINEERR_OPERATIONFAILED
LINEERR_INVALPOINTER
lpszProviderFilename

Specifies a pointer to a NULL-terminated string containing the pathname of the service provider to be added.

hwndOwner

Specifies a handle to a window to which the any dialogs which need to be displayed as part of the installation process (e.g., by the service provider's TSPI_providerInstall function) would be attached.

lpdwPermanentProviderID

Specifies a pointer to a DWORD-sized memory location into which TAPI writes the permanent provider ID of the newly-installed service provider.

During this function call, TAPI checks to insure that it can access the service provider by calling its TSPI_providerInstall function; if this is unsuccessful (if the DLL or function cannot be found, or if TSPI_providerInstall returns an error), the function fails and the provider is not added to the telephony system. If this is successful, and the Windows Telephony system is active (one or more applications have called lineInitialize), TAPI will attempt to activate the service provider by calling TSPI_providerEnumDevices and TSPI_providerInit (and other startup functions). If these functions fail, the provider will have been installed but not activated. If the activation succeeds, applications will be informed of any new devices created via LINE_CREATE or PHONE_CREATE messages, or by a LINE_LINEDEVSTATE message requesting reinitialization (if the application does not support the CREATE messages).

This function copies no files − not the service provider DLL itself nor any supporting files; it is the responsibility of the application managing the addition of the provider to insure that the provider is installed in a directory where it can be found by TAPI (e.g., \WINDOWS, \WINDOWS\SYSTEM, or elsewhere on the path), and that all other files necessary for operation.

Although this is a new function which older applications would not be expected to call, for backward compatibility, they should not be prevented from doing so; the function will work the same way for all applications.


lineAddToConference

[New - Windows 95]

LONG lineAddToConference(HCALL hConfCall, HCALL hConsultCall)

Adds the call specified by hConsultCall to the conference call specified by hConfCall.

•	Returns a positive request ID if the function will be completed asynchronously, or a negative error number if an error has occurred. dwParam2 of the corresponding LINE_REPLY callback message is zero if the function is successful or it is a negative error number if an error has occurred. Possible return values are:

LINEERR_CONFERENCEFULL	LINEERR_NOTOWNER
LINEERR_INVALCONFCALLHANDLE	LINEERR_OPERATIONUNAVAIL
LINEERR_INVALCALLHANDLE	LINEERR_OPERATIONFAILED
LINEERR_INVALCALLSTATE	LINEERR_RESOURCEUNAVAIL
LINEERR_NOMEM	LINEERR_UNINITIALIZED
hConfCall

Specifies a handle to the conference call. The application must be an owner of this call. Any monitoring (media, tones, digits) on a conference call applies only to the hConfCall, not to the individual participating calls. Call state of hConfCall must be onHoldPendingConference or onHold.

hConsultCall

Specifies a handle to the call to be added to the conference call. The application must be an owner of this call. This call cannot be a parent of another conference or a participant in any conference. Depending on the device capabilities indicated in LINEADDRESSCAPS, the hConsultCall may not necessarily have been established using lineSetupConference or linePrepareAddToConference. Call state of hConsultCall must be connected or onHold. The valid call states for the hConsultCall parameter also include proceeding and ringback. Many PBXes allow calls to be added to conferences before they are actually answered.

If LINEERR_INVALCALLHANDLE is returned, the specified call handle for the added call is invalid, hConsultCall is a parent of another conference or already a participant in a conference, hConsultCall cannot be added for other reasons (such as, it must have been established using lineSetupConference or linePrepareAddToConference), or hConsultCall and hConfCall are calls on different open lines.

The call handle of the added party remains valid after adding the call to a conference. Its state typically changes to conferenced while the state of the conference call typically becomes connected. Using lineGetConfRelatedCalls, you can obtain a list of call handles that are part of the same conference call as the specified call. The specified call is either a conference call or a participant call in a conference call. New handles are generated for those calls for which the application does not already have handles, and the application is granted monitor privilege to those calls. The handle to an individual participating call can be used later to remove that party from the conference call using lineRemoveFromConference.

Note that if lineGetConfRelatedCalls is called immediately after lineAddToConference, it may not return a complete list of related calls because TAPI.DLL waits to receive a LINE_CALLSTATE message indicating that the call has entered LINECALLSTATE_CONFERENCED before it considers the call to actually be part of the conference (that is, the conferenced state is confirmed by the service provider). Once the application has received the LINE_CALLSTATE message, lineGetConfRelatedCalls returns complete information. Note that all calls that are part of a conference must exist on the same open line.

The call states of the calls participating in a conference are not independent. For example, when dropping a conference call, all participating calls may automatically become idle. An application should consult the line's device capabilities to determine what form of conference removal is available. The application should track the LINE_CALLSTATE messages to determine what happened to the calls involved.

The conference call is established either by lineSetupConference or lineCompleteTransfer. The call added to a conference is typically established using lineSetupConference or linePrepareAddToConference. Some switches may allow adding arbitrary calls to the conference, and such a call may have been set up using lineMakeCall and be on (hard) hold. The application may examine the dwAddrCapFlags field of the LINEADDRESSCAPS structure to determine the permitted operations.


lineAnswer

[New - Windows 95]

LONG lineAnswer(HCALL hCall, LPCSTR lpsUserUserInfo, DWORD dwSize)

Answers the specified offering call.

•	Returns a positive request ID if the function will be completed asynchronously, or a negative error number if an error has occurred. The dwParam2 parameter of the corresponding LINE_REPLY callback message is zero if the function is successful or it is a negative error number if an error has occurred. Possible return values are:

LINEERR_INUSE	LINEERR_OPERATIONUNAVAIL
LINEERR_INVALCALLHANDLE	LINEERR_OPERATIONFAILED
LINEERR_INVALCALLSTATE	LINEERR_RESOURCEUNAVAIL
LINEERR_INVALPOINTER	LINEERR_UNINITIALIZED
LINEERR_NOMEM	LINEERR_USERUSERINFOTOOBIG
LINEERR_NOTOWNER
hCall

Specifies a handle to the call to be answered. The application must be an owner of this call. Call state of hCall must be offering or accepted.

lpsUserUserInfo

Specifies a pointer to a string containing user-to-user information to be sent to the remote party at the time of answering the call. This pointer can be left NULL if no user-to-user information is to be sent. User-to-user information is only sent if supported by the underlying network (see LINEDEVCAPS). The protocol discriminator field for the user-user information, if required, should appear as the first byte of the buffer pointed to by lpsUserUserInfo, and must be accounted for in dwSize.

dwSize

Specifies the size in bytes of the user-to-user information in lpsUserUserInfo. If lpsUserUserInfo is NULL, no user-to-user information is sent to the calling party and dwSize is ignored.

When a new call arrives, applications with an interest in the call are sent a LINE_CALLSTATE message to provide the new call handle and to inform the application about the call's state and the privileges to the new call (such as monitor or owner). The application with owner privilege for the call can answer this call using lineAnswer. After the call has been successfully answered, the call typically transitions to the connected state. Initially, only one application is given owner privilege to the inbound call.

In some telephony environments (like ISDN), where user alerting is separate from call offering, the application may have the option to accept a call prior to answering or to reject or redirect the offering call.

If a call comes in (is offered) at the time another call is already active, the new call is connected to by invoking lineAnswer. The effect this has on the existing active call depends on the line's device capabilities. The first call may be unaffected, it may automatically be dropped, or it may automatically be placed on hold. The appropriate LINE_CALLSTATE messages report state transitions to the application about both calls.

The application has the option to send user-to-user information at the time of the answer. Even if user-to-user information can be sent, there is no guarantee that the network will deliver this information to the calling party. An application should consult a line's device capabilities to determine whether sending user-to-user information upon answering the call is available.


lineBlindTransfer

[New - Windows 95]

LONG lineBlindTransfer(HCALL hCall, LPCSTR lpszDestAddress,
    DWORD dwCountryCode)

Performs a blind or single-step transfer of the specified call to the specified destination address.

•	Returns a positive request ID if the function will be completed asynchronously, or a negative error number if an error has occurred. The dwParam2 parameter of the corresponding LINE_REPLY callback message is zero if the function is successful or it is a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALCALLHANDLE	LINEERR_INVALCOUNTRYCODE
LINEERR_INVALCALLSTATE	LINEERR_INVALPOINTER
LINEERR_NOMEM	LINEERR_OPERATIONUNAVAIL
LINEERR_NOTOWNER	LINEERR_RESOURCEUNAVAIL
LINEERR_INVALADDRESS	LINEERR_UNINITIALIZED
LINEERR_ADDRESSBLOCKED	LINEERR_OPERATIONFAILED
hCall

Specifies a handle to the call to be transferred. The application must be an owner of this call. Call state of hCall must be connected.

lpszDestAddress

Specifies a pointer to a NULL-terminated string identifying where the call is to be transferred to. The destination address uses the standard dialable number format.

dwCountryCode

Specifies the country code of the destination. This is used by the implementation to select the call progress protocols for the destination address. If a value of zero is specified, a default call-progress protocol defined by the service provider is used.

If LINEERR_INVALADDRESS is returned, no dialing has occured.

Blind transfer differs from a consultation transfer in that no consultation call is made visible to the application. After the blind transfer successfully completes, the specified call is typically cleared from the application's line, and it transitions to the idle state. Note that the application's call handle remains valid after the transfer has completed. The application must deallocate its handle when it is no longer interested in the transferred call. It uses lineHandoff for this purpose.


lineClose

[New - Windows 95]

LONG lineClose(HLINE hLine)

Closes the specified open line device.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALLINEHANDLE	LINEERR_RESOURCEUNAVAIL
LINEERR_NOMEM	LINEERR_UNINITIALIZED
LINEERR_OPERATIONFAILED	LINEERR_OPERATIONUNAVAIL
hLine

Specifies a handle to the open line device to be closed. After the line has been successfully closed, this handle is no longer valid.

If an application calls lineClose while it still has active calls on the opened line, the application's ownership of these calls is revoked. If the application was the sole owner of these calls, the calls are dropped as well. It is good programming practice for an application to dispose of the calls it owns on an opened line by explicity relinquishing ownership and/or by dropping these calls prior to closing the line.

If the close was successful, a LINE_LINEDEVSTATE message is sent to all applications that are monitoring the line status of open/close changes. Outstanding asynchronous replies are suppressed.

Service providers may find it useful or necessary to forcibly reclaim line devices from an application that has the line open. This may be useful to prevent a misbehaved application from monopolizing the line device for too long. If this happens, a LINE_CLOSE message is sent to the application, specifying the line handle of the line device that was closed.

The lineOpen function allocates resources to the invoking application, and applications may be prevented from opening a line if resources are unavailable. Therefore, an application that only occasionally uses a line device (such as for making outbound calls) should close the line to free resources and allow other applications to open the line.


lineCompleteCall

[New - Windows 95]

LONG lineCompleteCall(HCALL hCall, LPDWORD lpdwCompletionID,
    DWORD dwCompletionMode, DWORD dwMessageID)

Specifies how a call that could not be connected normally should be completed instead. The network or switch may not be able to complete a call because network resources are busy or the remote station is busy or doesn't answer. The application can request that the call be completed in one of a number of ways.

•	Returns a positive request ID if the function will be completed asynchronously, or a negative error number if an error has occurred. The dwParam2 parameter of the corresponding LINE_REPLY callback message is zero if the function is successful or it is a negative error number if an error has occurred. Possible return values are:

LINEERR_COMPLETIONOVERRUN	LINEERR_NOMEM
LINEERR_INVALCALLCOMPLMODE	LINEERR_NOTOWNER
LINEERR_INVALCALLSTATE	LINEERR_OPERATIONUNAVAIL
LINEERR_INVALCALLHANDLE	LINEERR_OPERATIONFAILED
LINEERR_INVALMESSAGEID	LINEERR_RESOURCEUNAVAIL
LINEERR_INVALPOINTER	LINEERR_UNINITIALIZED
hCall

Specifies a handle to the call whose completion is requested. The application must be an owner of the call. Call state of hCall must be busy, ringback.

lpdwCompletionID

Specifies a pointer to a DWORD-sized memory location. The completion ID is used to identify individual completion requests in progress. A completion ID becomes invalid and may be reused after the request completes or after an outstanding request is canceled.

dwCompletionMode

Specifies the way in which the call is to be completed. Note that dwCompletionMode is allowed to have only a single flag set. This parameter uses the following LINECALLCOMPLMODE_ constants:

LINECALLCOMPLMODE_CAMPON

Queues the call until the call can be completed. The call remains in the busy state while queued.

LINECALLCOMPLMODE_CALLBACK

Requests the called station to return the call when it returns to idle.

LINECALLCOMPLMODE_INTRUDE

Adds the application to the existing physical call at the called station (barge in).

LINECALLCOMPLMODE_MESSAGE

Leave a short predefined message for the called station ("Leave Word Calling"). The message to be sent is specified by dwMessageID.

dwMessageID

Specifies the message that is to be sent when completing the call using LINECALLCOMPLMODE_MESSAGE. This ID selects the message from a small number of predefined messages.

This function is considered complete when the request has been accepted by the network or switch; not when the request is fully completed in the way specified. After this function completes, the call typically transitions to idle. When the called station or network enters a state where the call can be completed as requested, the application will be notified by a LINE_CALLSTATE message with the call state equal to offering. The call's LINECALLINFO record lists the reason for the call as CALLCOMPLETION and provide the completion ID as well. It is possible to have multiple call completion requests outstanding at any given time; the maximum number is device dependent. The completion ID is also used to refer to each individual request so requests can be canceled by calling lineUncompleteCall.


lineCompleteTransfer

[New - Windows 95]

LONG lineCompleteTransfer(HCALL hCall, HCALL hConsultCall,
    LPHCALL lphConfCall, DWORD dwTransferMode)

Completes the transfer of the specified call to the party connected in the consultation call.

•	Returns a positive request ID if the function will be completed asynchronously, or a negative error number if an error has occurred. The dwParam2 parameter of the corresponding LINE_REPLY callback message is zero if the function is successful or it is a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALCALLHANDLE	LINEERR_NOTOWNER
LINEERR_INVALCALLSTATE	LINEERR_OPERATIONUNAVAIL
LINEERR_INVALCONSULTCALLHANDLE	LINEERR_OPERATIONFAILED
LINEERR_INVALTRANSFERMODE	LINEERR_RESOURCEUNAVAIL
LINEERR_INVALPOINTER	LINEERR_UNINITIALIZED
LINEERR_NOMEM
hCall

Specifies a handle to the call to be transferred. The application must be an owner of this call. Call state of hCall must be onHold, onHoldPendingTransfer.

hConsultCall

Specifies a handle to the call that represents a connection with the destination of the transfer. The application must be an owner of this call. Call state of hConsultCall must be connected, ringback, busy, or proceeding.

lphConfCall

Specifies a pointer to a memory location where an HCALL handle can be returned. If dwTransferMode is LINETRANSFERMODE_CONFERENCE, the newly created conference call is returned in lphConfCall and the application becomes the sole owner of the conference call. Otherwise, this parameter is ignored by TAPI.DLL.

dwTransferMode

Specifies how the initiated transfer request is to be resolved. This parameter uses the following LINETRANSFERMODE_ constants:

LINETRANSFERMODE_TRANSFER

Resolve the initiated transfer by transferring the initial call to the consultation call.

LINETRANSFERMODE_CONFERENCE

Resolve the initiated transfer by conferencing all three parties into a three-way conference call. A conference call is created and returned to the application.

The LINE_REPLY message sent in response to a call to the lineCompleteTransfer function is based on the status of the call specified by the hCall parameter.

This operation completes the transfer of the original call, hCall, to the party currently connected by hConsultCall. The consultation call will typically have been dialed on the consultation call allocated as part of lineSetupTransfer, but it may be any call to which the switch is capable of transferring hCall.

The transfer request can be resolved either as a transfer or as a three-way conference call. When resolved as a transfer, the parties connected by hCall and hConsultCall are connected to each other, and both hCall and hConsultCall are typically cleared from the application's line and transition to the idle state. Note that the application's call handle remains valid after the transfer has completed. The application must deallocate its handle with lineHandoff when it is no longer interested in the transferred call.

When resolved as a conference, all three parties enter into a conference call. Both existing call handles remain valid but will transition to the conferenced state. A conference call handle will be created and returned, and it will transition to the connected state.

If lineGetConfRelatedCalls is called immediately after lineCompleteTransfer with the result that the calls are conferenced, lineGetConfRelatedCalls may not return a complete list of related calls. This is because TAPI.DLL waits to receive a LINE_CALLSTATE message indicating that the call has entered LINECALLSTATE_CONFERENCED before it considers the call to actually be part of the conference. That is, it waits for the service provider to confirm the conferenced state. Once the application has received the LINE_CALLSTATE message, lineGetConfRelatedCalls returns complete information.

It may also be possible to perform a blind transfer of a call using lineBlindTransfer.


lineConfigDialog

[New - Windows 95]

LONG lineConfigDialog(DWORD dwDeviceID, HWND hwndOwner,
    LPCSTR lpszDeviceClass)

Causes the provider of the specified line device to display a dialog (attached to hwndOwner of the application) to allow the user to configure parameters related to the line device.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_BADDEVICEID	LINEERR_NOMEM
LINEERR_INUSE	LINEERR_OPERATIONFAILED
LINEERR_INVALDEVICECLASS	LINEERR_RESOURCEUNAVAIL
LINEERR_INVALPARAM	LINEERR_UNINITIALIZED
LINEERR_INVALPOINTER	LINEERR_OPERATIONUNAVAIL
LINEERR_NODEVICE
dwDeviceID

Specifies the line device to be configured.

hwndOwner

Specifies a handle to a window to which the dialog is to be attached.

lpszDeviceClass

Specifies a pointer to a NULL-terminated string that identifies a device class name. This device class allows the application to select a specific subscreen of configuration information applicable to that device class. This parameter is optional and can be left NULL or empty, in which case the highest level configuration is selected.

The lineConfigDialog function causes the service provider to display a modal dialog (attached to hwndOwner of the application) to allow the user to configure parameters related to the line specified by dwDeviceID. The lpszDeviceClass parameter allows the application to select a specific subscreen of configuration information applicable to the device class in which the user is interested; the permitted strings are the same as for lineGetID. For example, if the line supports the Comm API, passing "COMM" as lpszDeviceClass causes the provider to display the parameters related specifically to Comm (or, at least, start at the corresponding point in a multilevel configuration dialog chain, so the user doesn't have to "dig" to find the parameters of interest).

The lpszDeviceClass parameter would be "tapi/line" , "", or NULL to cause the provider to display the highest level configuration for the line.


lineConfigDialogEdit

[New - Windows 95]

LONG lineConfigDialogEdit (DWORD dwDeviceID, HWND hwndOwner,
    LPCSTR lpszDeviceClass, LPVOID const lpDeviceConfigIn,
    DWORD dwSize, LPVARSTRING lpDeviceConfigOut)

Causes the provider of the specified line device to display a dialog (attached to hwndOwner of the application) to allow the user to configure parameters related to the line device.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_BADDEVICEID	LINEERR_OPERATIONFAILED
LINEERR_INVALDEVICECLASS	LINEERR_RESOURCEUNAVAIL
LINEERR_INVALPARAM	LINEERR_STRUCTURETOOSMALL
LINEERR_INVALPOINTER	LINEERR_UNINITIALIZED
LINEERR_NODRIVER	LINEERR_OPERATIONUNAVAIL
LINEERR_NOMEM	LINEERR_NODEVICE
dwDeviceID

Specifies the line device to be configured.

hwndOwner

Specifies a handle to a window to which the dialog is to be attached.

lpszDeviceClass

Specifies a pointer to a NULL-terminated string that identifies a device class name. This device class allows the application to select a specific subscreen of configuration information applicable to that device class. This parameter is optional and can be left NULL or empty, in which case the highest level configuration is selected.

lpDeviceConfigIn

Specifies a pointer to the opaque configuration data structure that was returned by lineGetDevConfig (or a previous invocation of lineConfigDialogEdit) in the variable portion of the VARSTRING structure.

dwSize

Specifies the number of bytes in the structure pointed to by lpDeviceConfigIn. This value will have been returned in the dwStringSize field in the VARSTRING structure returned by lineGetDevConfig or a previous invocation of lineConfigDialogEdit.

lpDeviceConfigOut

Specifies a pointer to the memory location of type VARSTRING where the device configuration structure is returned. Upon successful completion of the request, this location is filled with the device configuration. The dwStringFormat field in the VARSTRING structure will be set to STRINGFORMAT_BINARY. Prior to calling lineGetDevConfig (or a future invocation of lineConfigDialogEdit), the application should set the dwTotalSize field of this structure to indicate the amount of memory available to TAPI for returning information.

If LINEERR_STRUCTURETOOSMALL is returned, the dwTotalSize field of the VARSTRING structure pointed to by lpDeviceConfigOut does not specify enough memory to contain the entire configuration structure. The dwNeededSize field has been set to the amount required. To the extent that user entries were reflected in information that could not be returned due to insufficient space, those edits are lost; applications should therefore allocate the maximum amount of space that may be needed by the device class to return its configuration structure (see documentation for the device class for further information).

The lineConfigDialogEdit function causes the service provider to display a modal dialog (attached to hwndOwner of the application) to allow the user to configure parameters related to the line specified by dwDeviceID.

The lpszDeviceClass parameter allows the application to select a specific subscreen of configuration information applicable to the device class in which the user is interested; the permitted strings are the same as for lineGetID. For example, if the line supports the Comm API, passing "COMM" as lpszDeviceClass causes the provider to display the parameters related specifically to Comm (or, at least, start at the corresponding point in a multilevel configuration dialog chain, so the user doesn't have to "dig" to find the parameters of interest).

The lpszDeviceClass parameter would be "tapi/line" , "", or NULL to cause the provider to display the highest level configuration for the line.

The difference between this function and lineConfigDialog is the source of the parameters to edit and the result of the editing. In lineConfigDialog, the parameters edited are those currently in use on the device (or set for use on the next call), and any changes made have (to the maximum extent possible) an immediate impact on any active connection; also, the application must use lineGetDevConfig to fetch the result of parameter changes from lineConfigDialog. With lineConfigDialogEdit, the parameters to edit are passed in from the application, and the results are returned to the application, with no impact on active connections; the results of the editing are returned with this function, and the application does not need to call lineGetDevConfig. Thus, lineConfigDialogEdit permits an application to provide the ability for the user to set up parameters for future calls without having an impact on any active call. Note, however, the output of this function can be passed to lineSetDevConfig to affect the current call or next call.

Although this is a new function which older applications would not be expected to call, for backward compatibility, they should not be prevented from doing so; the function will work the same way for all applications.


lineConfigProvider

[New - Windows 95]

LONG lineConfigProvider(HWND hwndOwner, DWORD dwPermanentProviderID)

Causes a service provider to display its configuration dialog.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_INIFILECORRUPT	LINEERR_NOMEM
LINEERR_INVALPARAM	LINEERR_OPERATIONFAILED
hwndOwner

Specifies a handle to a window to which the configuration dialog (displayed by TSPI_providerConfig) will be attached.

dwPermanentProviderID

Specifies the permanent provider ID of the service provider to be configured.

This is basically a straight pass-through to TSPI_providerConfig.

Although this is a new function which older applications would not be expected to call, for backward compatibility, they should not be prevented from doing so; the function will work the same way for all applications.


lineDeallocateCall

[New - Windows 95]

LONG lineDeallocateCall(HCALL hCall)

Deallocates the specified call handle.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALCALLHANDLE	LINEERR_OPERATIONFAILED
LINEERR_INVALCALLSTATE	LINEERR_RESOURCEUNAVAIL
LINEERR_NOMEM	LINEERR_UNINITIALIZED
hCall

Specifies the call handle to be deallocated. An application with monitoring privileges for a call can always deallocate its handle for that call. An application with owner privilege for a call can deallocate its handle except when the application is the sole owner of the call and the call is not in the idle state. The call handle is no longer valid after it has been deallocated.

The deallocation does not affect the call state of the physical call. It does, however, release internal resources related to the call. If the application is the sole owner of a call and the call is not in the idle state, LINEERR_INVALCALLSTATE is returned. In this case, the application can first drop the call using lineDrop and deallocate its call handle afterwards. An application that has monitor privilege for a call can always deallocate its handle for the call.

When the lineDeallocateCall function deallocates a call handle, it also suspends further processing of any outstanding LINE_REPLY messages for the call. An application must be designed not to wait indefinately for LINE_REPLY messages for each corresponding call to an asynchronous function if it also uses the lineDeallocateCall function to deallocate handles.


lineDevSpecific

[New - Windows 95]

LONG lineDevSpecific(HLINE hLine, DWORD dwAddressID, HCALL hCall,
    LPVOID lpParams, DWORD dwSize)

Enables service providers to provide access to features not offered by other TAPI functions. The meaning of the extensions are device specific, and taking advantage of these extensions requires the application to be fully aware of them.

•	Returns a positive request ID if the function will be completed asynchronously, or a negative error number if an error has occurred. The dwParam2 parameter of the corresponding LINE_REPLY callback message is zero if the function is successful or it is a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALADDRESSID	LINEERR_OPERATIONUNAVAIL
LINEERR_INVALCALLHANDLE	LINEERR_OPERATIONFAILED
LINEERR_INVALLINEHANDLE	LINEERR_RESOURCEUNAVAIL
LINEERR_INVALPOINTER	LINEERR_UNINITIALIZED
LINEERR_NOMEM
Additional return values are device specific.

hLine

Specifies a handle to a line device. This parameter is required.

dwAddressID

Specifies an address ID on the given line device.

hCall

Specifies a handle to a call. This parameter is optional, but if it is specified, the call it represents must belong to the hLine line device. Call state of hCall is device specific.

lpParams

Specifies a pointer to a memory area used to hold a parameter block. The format of this parameter block is device specific and its contents are passed by TAPI.DLL to or from the service provider.

dwSize

The size in bytes of the parameter block area.

This operation is part of the Extended Telephony services. It provides access to a device-specific feature without defining its meaning. This operation is only available if the application has successfully negotiated a device-specific extension version.

This function provides a generic parameter profile. The interpretation of the parameter structure is device specific. Whether dwAddressID and/or hCall are expected to be valid is device-specific. If specified, they must belong to hLine. Indications and replies sent back the application that are device specific should use the LINE_DEVSPECIFIC message.

A service provider can provide access to device-specific functions by defining parameters for use with this function. Applications that want to make use of these device-specific extensions should consult the device-specific (in this case meaning vendor specific) documentation that describes what extensions are defined. An application that relies on these device-specific extensions will typically not be able to work with other service provider environments.


lineDevSpecificFeature

[New - Windows 95]

LONG lineDevSpecificFeature(HLINE hLine, DWORD dwFeature,
    LPVOID lpParams, DWORD dwSize)

Enables service providers to provide access to features not offered by other TAPI functions. The meaning of these extensions are device specific, and taking advantage of these extensions requires the application to be fully aware of them.

•	Returns a positive request ID if the function will be completed asynchronously, or a negative error number if an error has occurred. The dwParam2 parameter of the corresponding LINE_REPLY callback message is zero if the function is successful or it is a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALFEATURE	LINEERR_OPERATIONUNAVAIL
LINEERR_INVALLINEHANDLE	LINEERR_OPERATIONFAILED
LINEERR_INVALPOINTER	LINEERR_RESOURCEUNAVAIL
LINEERR_NOMEM	LINEERR_UNINITIALIZED
Additional return values are device specific.

hLine

Specifies a handle to the line device.

dwFeature

Specifies the feature to invoke on the line device. This parameter uses the PHONEBUTTONFUNCTION_ constants.

lpParams

Specifies a pointer to a memory area used to hold a feature-dependent parameter block. The format of this parameter block is device specific and its contents are passed through by TAPI.DLL to or from the service provider.

dwSize

Specifies the size of the buffer in bytes.

This operation is part of the Extended Telephony services. It provides access to a device-specific feature without defining its meaning. This operation is only available if the application has successfully negotiated a device-specific extension version.

This function provides the application with phone feature-button emulation capabilities. When an application invokes this operation, it specifies the equivalent of a button-press event. This method of invoking features is device dependent, as TAPI does not define their meaning. Note that an application that relies on these device-specific extensions will typically not work with other service provider environments.

Note also that the structure pointed to by lpParams should not contain any pointers since they would not be properly translated (thunked) when running a 16-bit application in a 32-bit version of TAPI.DLL and vice versa.


lineDial

[New - Windows 95]

LONG lineDial(HCALL hCall, LPCSTR lpszDestAddress, DWORD dwCountryCode)

Dials the specified dialable number on the specified call.

•	Returns a positive request ID if the function will be completed asynchronously, or a negative error number if an error has occurred. The dwParam2 parameter of the corresponding LINE_REPLY callback message is zero if the function is successful or it is a negative error number if an error has occurred. Possible return values are:

LINEERR_ADDRESSBLOCKED	LINEERR_INVALPOINTER
LINEERR_DIALBILLING	LINEERR_NOMEM
LINEERR_DIALDIALTONE	LINEERR_NOTOWNER
LINEERR_DIALPROMPT	LINEERR_OPERATIONFAILED
LINEERR_DIALQUIET	LINEERR_OPERATIONUNAVAIL
LINEERR_INVALCALLHANDLE	LINEERR_RESOURCEUNAVAIL
LINEERR_INVALCALLSTATE	LINEERR_UNINITIALIZED
LINEERR_INVALCOUNTRYCODE
hCall

Specifies a handle to the call on which a number is to be dialed. The application must be an owner of the call. Call state of hCall can be any state except idle and disconnected.

lpszDestAddress

Specifies the destination to be dialed using the standard dialable number format.

dwCountryCode

Specifies the country code of the destination. This is used by the implementation to select the call progress protocols for the destination address. If a value of zero is specified, a service provider-defined default call progress protocol is used.

If LINEERR_INVALADDRESS is returned, no dialing has been done. If LINEERR_DIALBILLING, LINEERR_DIALQUIET, LINEERR_DIALDIALTONE, or LINEERR_DIALPROMPT is returned, none of the actions otherwise performed by lineDial have occured; for example, none of the dialable addresses prior to the offending character has been dialed, no hookswitch state has changed, and so on.

The lineDial function is used for dialing on an existing call appearance. For example, after a call has been set up for transfer or conference, a consultation call is automatically allocated, and the lineDial function would be used to perform the dialing of this consultation call. Note that lineDial may be invoked multiple times in the course of multi-stage dialing, if the line's device capabilities allows it. Also, multiple addresses may be provided in a single dial string separated by CRLF. Service providers that provide inverse multiplexing can establish individual physical calls with each of the addresses and can return a single call handle to the aggregate of all calls to the application. All addresses would use the same country code.

Dialing is considered complete after the address has been passed to the service provider; not after the call is finally connected. Service providers that provide inverse multiplexing may allow multiple addresses to be provided at once. The service provider sends LINE_CALLSTATE messages to the application to inform it about the progress of the call. To abort a call attempt while a call is being established, the invoking application should use lineDrop.

An application can set the lpszDestAddress parameter of the lineDial function to the addess of an empty string to indicate that dialing is complete, but only if the previous calls to the lineMakeCall and lineDial functions have had the strings specified by lpszDestAddress terminated with semicolons.


lineDrop

[New - Windows 95]

LONG lineDrop(HCALL hCall, LPCSTR lpsUserUserInfo, DWORD dwSize)

Drops or disconnects the specified call. The application has the option to specify user-to-user information to be transmitted as part of the call disconnect.

•	Returns a positive request ID if the function will be completed asynchronously, or a negative error number if an error has occurred. The dwParam2 parameter of the corresponding LINE_REPLY callback message is zero if the function is successful or it is a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALCALLHANDLE	LINEERR_OPERATIONUNAVAIL
LINEERR_NOMEM	LINEERR_OPERATIONFAILED
LINEERR_NOTOWNER	LINEERR_RESOURCEUNAVAIL
LINEERR_INVALPOINTER	LINEERR_USERUSERINFOTOOBIG
LINEERR_INVALCALLSTATE	LINEERR_UNINITIALIZED
hCall

Specifies a handle to the call to be dropped. The application must be an owner of the call. Call state of hCall can be any state except idle.

lpsUserUserInfo

Specifies a pointer to a string containing user-to-user information to be sent to the remote party as part of the call disconnect. This pointer can be left NULL if no user-to-user information is to be sent. User-to-user information is only sent if supported by the underlying network (see LINEDEVCAPS). The protocol discriminator field for the user-user information, if required, should appear as the first byte of the buffer pointed to by lpsUserUserInfo, and must be accounted for in dwSize.

dwSize

Specifies the size in bytes of the user-to-user information in lpsUserUserInfo. If lpsUserUserInfo is NULL, no user-to-user information is sent to the calling party and dwSize is ignored.

When invoking lineDrop, related calls may sometimes be affected as well. For example, dropping a conference call may drop all individual participating calls. LINE_CALLSTATE messages are sent to the application for all calls whose call state is affected. A dropped call typically transitions to the idle state. Invoking lineDrop on a call in the offering state rejects the call. Not all telephone networks provide this capability.

A call in the onholdpending state will typically revert to the connected state. When dropping the consultation call to the third party for a conference call or when removing the third party in a previously established conference call, the provider (and switch) may release the conference bridge and revert the call back to a normal two-party call. If this is the case, hConfCall transitions to the idle state, and the only remaining participating call will transition to the connected state. Some switches automatically "unhold" the other call.

The application has the option to send user-to-user information at the time of the drop. Even if user-to-user information can be sent, there is no guarantee that the network will deliver this information to the remote party.

Note that in various bridged or party-line configurations when multiple parties are on the call, lineDrop may not actually clear the call.


lineForward

[New - Windows 95]

LONG lineForward(HLINE hLine, DWORD bAllAddresses, DWORD dwAddressID,
    LPLINEFORWARDLIST const lpForwardList, DWORD dwNumRingsNoAnswer,
    LPHCALL lphConsultCall, LPLINECALLPARAMS const lpCallParams)

Forwards calls destined for the specified address on the specified line, according to the specified forwarding instructions. When an originating address (dwAddressID) is forwarded, the specified incoming calls for that address are deflected to the other number by the switch. This function provides a combination of forward and do-not-disturb features. This function can also cancel forwarding currently in effect.

•	Returns a positive request ID if the function will be completed asynchronously, or a negative error number if an error has occurred. The dwParam2 parameter of the corresponding LINE_REPLY callback message is zero if the function is successful or it is a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALLINEHANDLE	LINEERR_NOMEM
LINEERR_INVALADDRESSID	LINEERR_OPERATIONUNAVAIL
LINEERR_INVALADDRESS	LINEERR_OPERATIONFAILED
LINEERR_INVALCOUNTRYCODE	LINEERR_RESOURCEUNAVAIL
LINEERR_INVALPOINTER	LINEERR_STRUCTURETOOSMALL
LINEERR_INVALPARAM	LINEERR_UNINITIALIZED
hLine

Specifies a handle to the line device.

bAllAddresses

Specifies whether all originating addresses on the line or just the one specified is to be forwarded. If TRUE, all addresses on the line are forwarded and dwAddressID is ignored; if FALSE, only the address specified as dwAddressID is forwarded.

dwAddressID

Specifies the address on the specified line whose incoming calls are to be forwarded. This parameter is ignored if bAllAddresses is TRUE.

lpForwardList

Specifies a pointer to a variably sized data structure that describes the specific forwarding instructions, of type LINEFORWARDLIST.

dwNumRingsNoAnswer

Specifies the number of rings before a call is considered a "no answer." If dwNumRingsNoAnswer is out of range, the actual value is set to the nearest value in the allowable range.

lphConsultCall

Specifies a pointer to an HCALL location. In some telephony environments, this location is loaded with a handle to a consultation call that is used to consult the party that is being forwarded to, and the application becomes the initial sole owner of this call. This pointer must be valid even in environments where call forwarding does not require a consultation call. This handle will be set to NULL if no consultation call is created.

lpCallParams

Specifies a pointer to a structure of type LINECALLPARAMS. This pointer is ignored unless lineForward requires the establishment of a call to the forwarding destination (and lphConsultCall is returned, in which case lpCallParams is optional). If NULL, default call parameters are used. Otherwise, the specified call parameters are used for establishing hConsultCall.

A successful forwarding indicates only that the request has been accepted by the service provider, not that forwarding is set up at the switch. A LINE_ADDRESSSTATE (forwarding) message provides confirmation for forwarding having been set up at the switch.

Forwarding of the address(es) remains in effect until this function is called again. The most recent forwarding list replaces the old one. Forwarding can be canceled by specifying a NULL pointer as lpForwardList. If a NULL destination address is specified for an entry in the forwarding list, the operation acts as a do-not-disturb.

Forwarding status of an address may also be affected externally; for example, by administrative actions at the switch or by a user from another station. It may not be possible for the service provider to be aware of this state change, and it may not be able to keep in synchronization with the forwarding state known to the switch.

Since a service provider may not know the forwarding state of the address "for sure" (that is, it may have been forwarded or unforwarded in an unknown way), lineForward will succeed unless it fails to set the new forwarding instructions. In other words, a request that all forwarding be canceled at a time that there is no forwarding in effect will be successful. This is because there is no "unforwarding"—you can only change the previous set of forwarding instructions.

The success or failure of this operation does not depend on the previous set of forwarding instructions, and the same is true when setting different forwarding instructions. The provider should "unforward everything" prior to setting the new forwarding instructions. Since this may take time in analog telephony environments, a provider may also want to compare the current forwarding with the new one, and only issue instructions to the switch to get to the final state (leaving unchanged forwarding unaffected).

Invoking lineForward when LINEFORWARDLIST has dwNumEntries set to zero has the same effect as providing a NULL lpForwardList parameter. It cancels all forwarding currently in effect.


lineGatherDigits

[New - Windows 95]

LONG lineGatherDigits(HCALL hCall, DWORD dwDigitModes, LPSTR lpsDigits,
    DWORD dwNumDigits, LPCSTR lpszTerminationDigits,
    DWORD dwFirstDigitTimeout, DWORD dwInterDigitTimeout)

Initiates the buffered gathering of digits on the specified call. The application specifies a buffer in which to place the digits and the maximum number of digits to be collected.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALCALLHANDLE	LINEERR_NOMEM
LINEERR_INVALCALLSTATE	LINEERR_NOTOWNER
LINEERR_INVALDIGITMODE	LINEERR_OPERATIONUNAVAIL
LINEERR_INVALDIGITS	LINEERR_OPERATIONFAILED
LINEERR_INVALPARAM	LINEERR_RESOURCEUNAVAIL
LINEERR_INVALPOINTER	LINEERR_UNINITIALIZED
LINEERR_INVALTIMEOUT
hCall

Specifies a handle to the call on which digits are to be gathered. The application must be an owner of the call. Call state of hCall can be any state.

dwDigitModes

Specifies the digit mode(s) to be monitored. Note that dwDigitModes is allowed to have one or more flags set. This parameter uses the following LINEDIGITMODE_ constants:

LINEDIGITMODE_PULSE

Detect digits as audible clicks that are the result of the use of rotary pulse sequences. Valid digits for pulse mode are '0' through '9'.

LINEDIGITMODE_DTMF

Detect digits as DTMF tones. Valid digits for DTMF mode are '0' through '9', 'A', 'B', 'C', 'D', '*', '#'.

lpsDigits

Specifies a pointer to the buffer where detected digits are to be stored as ASCII characters. Digits may not show up in the buffer one at a time as they are collected. Only after a LINE_GATHERDIGITS message is received should the content of the buffer be assumed to be valid. If lpsDigits is NULL, the digit gathering currently in progress on the call is terminated and dwNumDigits is ignored. Otherwise, lpsDigits is assumed to have room for dwNumDigits digits.

dwNumDigits

Specifies the number of digits to be collected before a LINE_GATHERDIGITS message is sent to the application. The dwNumDigits parameter is ignored when lpsDigits is NULL. This function fails if dwNumDigits is zero.

lpszTerminationDigits

Specifies a NULL-terminated string of termination digits as ASCII characters. If one of the digits in the string is detected, that termination digit is appended to the buffer, digit collection is terminated, and the LINE_GATHERDIGITS message is sent to the application.
Valid characters for pulse mode are '0' through '9'. Valid characters for DTMF mode are '0' through '9', 'A', 'B', 'C', 'D', '*', '#'. If this pointer is NULL, or if it points to an empty string, the function behaves as though no termination digits were supplied.

dwFirstDigitTimeout

Specifies the time duration in milliseconds in which the first digit is expected. If the first digit is not received in this timeframe, digit collection is aborted and a LINE_GATHERDIGITS message is sent to the application. The buffer only contains the NULL character, indicating that no digits were received and the first digit timeout terminated digit gathering. The call's line-device capabilities specifies the valid range for this parameter or indicates that timeouts are not supported.

dwInterDigitTimeout

Specifies the maximum time duration in milliseconds between consecutive digits. If no digit is received in this timeframe, digit collection is aborted and a LINE_GATHERDIGITS message is sent to the application. The buffer only contains the digits collected up to this point followed by a NULL character, indicating that an interdigit timeout terminated digit gathering. The call's line-device capabilities specifies the valid range for this parameter or indicates that timeouts are not supported.

Digit collection is terminated when the requested number of digits has been collected. It is also terminated when one of the digits detected matches a digit in szTerminationDigits before the specified number of digits has been collected. The detected termination digit is also placed in the buffer and the partial buffer is returned.

Another way of cancelling digit collection is when one of the timeouts expires. The dwFirstDigitTimeout expires if the first digit is not received in this time period. The dwInterDigitTimout expires if the second, third, (and so forth) digit is not received within that time period from the previously detected digit, and a partial buffer is returned.

A fourth method for terminating digit detection is by calling this function again while collection is in progress. The old collection session is terminated, any digits collected up to that point are copied to the buffer supplied from the previous call to this function, and the buffer is delivered when the LINE_GATHERDIGITS message is sent to the application. The mechanism for terminating digit gathering without initiating another gathering of the digits is by invoking this function with lpsDigits equal to NULL.

This function is considered successful if digit collection has been correctly initiated, not when digit collection has terminated. In all cases where a partial buffer is returned, valid digits (if any) are followed by an ASCII NULL character.

Although this function can be invoked in any call state, digits can typically only be gathered while the call is in the connected state.

The message LINE_GATHERDIGITS is sent only to the application that initiated the request. It is also sent when partial buffers are returned because of timeouts or matching termination digits, or when the request is canceled by another lineGatherDigits request on the call. Only one gather-digits request can be active on a call at any given time across all applications that are owners of the call. Given the asynchronous behavior of the operation, an application that issues multiple lineGatherDigits in quick succession may be able to do so and receive several LINE_GATHERDIGITS messages later. While this would be unusual application behavior, the application will be able to count the number of these messages to allow cancel messages to be matched with the earlier requests. In any case, only the most recent request should be assumed to be valid.

An application can use lineMonitorDigits to enable or disable unbuffered digit detection. Each time a digit is detected in this fashion, a LINE_MONITORDIGITS message is sent to the application. Both buffered and unbuffered digit detection can be enabled for the same call simultaneously.

Gathering of digits on a conference call applies only to the hConfCall, not to the individual participating calls.

If the lineGatherDigits function is used to cancel a previous request to gather digits, the function copies any digits collected up to that point to the buffer specified in the original function call and sends a LINE_GATHERDIGITS message to the application, regardless of whether the lpszDigits parameter in the second call specifies a NULL or different address.


lineGenerateDigits

[New - Windows 95]

LONG lineGenerateDigits(HCALL hCall, DWORD dwDigitMode,
    LPCSTR lpszDigits, DWORD dwDuration)

Initiates the generation of the specified digits on the specified call as inband tones using the specified signaling mode. Invoking this function with a NULL value for lpszDigits aborts any digit generation currently in progress. Invoking lineGenerateDigits or lineGenerateTone while digit generation is in progress aborts the current digit generation or tone generation and initiates the generation of the most recently specified digits or tone.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALCALLHANDLE	LINEERR_NOTOWNER
LINEERR_INVALCALLSTATE	LINEERR_OPERATIONUNAVAIL
LINEERR_INVALDIGITMODE	LINEERR_OPERATIONFAILED
LINEERR_INVALPOINTER	LINEERR_RESOURCEUNAVAIL
LINEERR_NOMEM	LINEERR_UNINITIALIZED
hCall

Specifies a handle to the call. The application must be an owner of the call. Call state of hCall can be any state.

dwDigitMode

Indicates the format to be used for signaling these digits. Note that dwDigitMode is allowed to have only a single flag set. This parameter uses the following LINEDIGITMODE_ constants:

LINEDIGITMODE_PULSE

Uses pulse/rotary for digit signaling. Valid digits for pulse mode are '0' through '9'.

LINEDIGITMODE_DTMF

Uses DTMF tones for digit signaling. Valid digits for DTMF mode are '0' through '9', 'A', 'B', 'C', 'D', '*', '#'.

lpszDigits

Specifies a pointer to a NULL-terminated character buffer that contains the digits to be generated. Valid characters for pulse mode are '0' through '9' and ',' (comma). Valid characters for DTMF mode are '0' through '9', 'A', 'B', 'C', 'D', '*', '#', and ',' (comma). A comma injects an extra delay between the signaling of the previous and next digits it separates. The duration of this pause is configuration defined, and the line's device capabilities indicates what this duration is. Multiple commas may be used to inject longer pauses. Invalid digits are ignored during the generation, rather than being reported as an error. The exclamation character (!) is a valid character in the string specifed by the lpszDigits parameter for both DTMF and pulse mode. This character causes a "hookflash" operation, as described for dialable addresses.

dwDuration

Specifies both the duration in milliseconds of DTMF digits and pulse and DTMF inter-digit spacing. A value of zero will use a default value. The dwDuration parameter must be within the range specified by MinDialParams and MaxDialParams in LINEDEVCAPS. If out of range, the actual value is set to the nearest value in the range.

The lineGenerateDigits function is considered to have completed successfully when the digit generation has been successfully initiated, not when all digits have been generated. In contrast to lineDial, which dials digits in a network-dependent fashion, lineGenerateDigits guarantees to produce the digits as inband tones over the voice channel using DTMF or hookswitch dial pulses when using pulse. The lineGenerateDigits function is generally not suitable for making calls or dialing. It is intended for end-to-end signaling over an established call.

After all digits in lpszDigits have been generated, or after digit generation has been aborted or canceled, a LINE_GENERATE message is sent to the application.

Only one inband generation request (tone generation or digit generation) is allowed to be in progress per call across all applications that are owners of the call. Digit generation on a call is cancelled by initiating either another digit generation request or a tone generation request. To cancel the current digit generation, the application can invoke lineGenerateDigits and specify NULL for the lpszDigits parameter.

Depending on the service provider and hardware, the application may monitor the digits it generates itself. If that is not desired, the application can disable digit monitoring while generating digits.


lineGenerateTone

[New - Windows 95]

LONG lineGenerateTone(HCALL hCall, DWORD dwToneMode,
    DWORD dwDuration, DWORD dwNumTones,
    LPLINEGENERATETONE const lpTones)

Generates the specified inband tone over the specified call. Invoking this function with a zero for dwToneMode aborts the tone generation currently in progress on the specified call. Invoking lineGenerateTone or lineGenerateDigits while tone generation is in progress aborts the current tone generation or digit generation and initiates the generation of the newly specified tone or digits.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALCALLHANDLE	LINEERR_NOTOWNER
LINEERR_INVALCALLSTATE	LINEERR_OPERATIONUNAVAIL
LINEERR_INVALPOINTER	LINEERR_OPERATIONFAILED
LINEERR_INVALTONEMODE	LINEERR_RESOURCEUNAVAIL
LINEERR_INVALTONE	LINEERR_UNINITIALIZED
LINEERR_NOMEM
hCall

Specifies a handle to the call on which a tone is to be generated. The application must be an owner of the call. Call state of hCall can be any state.

dwToneMode

Defines the tone to be generated. Tones can be either standard or custom. A custom tone is composed of a set of arbitrary frequencies. A small number of standard tones are predefined. The duration of the tone is specified with dwDuration for both standard and custom tones. Note that dwToneMode can only have one bit set. If no bits are set (the value 0 is passed), tone generation is cancelled. This parameter uses the following LINETONEMODE_ constants:

LINETONEMODE_CUSTOM

The tone is a custom tone, defined by the specified frequencies.

LINETONEMODE_RINGBACK

The tone to be generated is ring tone. The exact ringback tone is service provider defined.

LINETONEMODE_BUSY

The tone is a standard (station) busy tone. The exact busy tone is service provider defined.

LINETONEMODE_BEEP

The tone is a beep, as used to announce the beginning of a recording. The exact beep tone is service provider defined.

LINETONEMODE_BILLING

The tone is billing information tone such as a credit card prompt tone. The exact billing tone is service provider defined.

A value of zero for dwToneMode cancels tone generation.

dwDuration

Specifies duration in milliseconds during which the tone should be sustained. A value of zero for dwDuration uses a default duration for the specified tone. Default values are:

CUSTOM:	infinite
RINGBACK:	infinite
BUSY:	infinite
BEEP:	infinite
BILLING:	fixed (single cycle)

dwNumTones

Specifies the number of entries in the lpTones array. This field is ignored if dwToneMode is not equal to CUSTOM.

lpTones

Specifies a pointer to a LINEGENERATETONE array that specifies the tone's components. This parameter is ignored for non-custom tones. If lpTones is a multi-frequency tone, the various tones are played simultaneously.

lineGenerateTone is considered to have completed successfully when the tone generation has been successfully initiated, not when the generation of the tone is done. The function allows the inband generation of several predefined tones, such as ring back, busy tones, and beep. It also allows for the fabrication of custom tones by specifying their component frequencies, cadence and volume. Since these tones are generated as inband tones, the call would typically have to be in the connected state for tone generation to be effective. When the generation of the tone is complete, or when tone generation is canceled, a LINE_GENERATE message is sent to the application.

Only one inband generation request (tone generation or digit generation) is allowed to be in progress per call across all applications that are owners of the call. This implies that if tone generation is currently in progress on a call, invoking lineGenerateDigits cancels the tone generation.

If the LINEERR_INVALPOINTER error value is returned, the specified lpTones parameter is invalid or the value specified by the dwNumTones parameter is too large.


lineGetAddressCaps

[New - Windows 95]

LONG lineGetAddressCaps(HLINEAPP hLineApp, DWORD dwDeviceID,
    DWORD dwAddressID, DWORD dwAPIVersion, DWORD dwExtVersion,
    LPLINEADDRESSCAPS lpAddressCaps)

Queries the specified address on the specified line device to determine its telephony capabilities.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_BADDEVICEID	LINEERR_NOMEM
LINEERR_INCOMPATIBLEAPIVERSION	LINEERR_OPERATIONFAILED
LINEERR_INCOMPATIBLEEXTVERSION	LINEERR_RESOURCEUNAVAIL
LINEERR_INVALADDRESSID	LINEERR_STRUCTURETOOSMALL
LINEERR_INVALAPPHANDLE	LINEERR_UNINITIALIZED
LINEERR_INVALPOINTER	LINEERR_OPERATIONUNAVAIL
LINEERR_NODRIVER	LINEERR_NODEVICE
hLineApp

Specifies the handle to the application's registration with TAPI.

dwDeviceID

Specifies the line device containing the address to be queried.

dwAddressID

Specifies the address on the given line device whose capabilities are to be queried.

dwAPIVersion

Specifies the version number of the Telephony API to be used. The high-order word contains the major version number; the low-order word contains the minor version number.

dwExtVersion

Specifies the version number of the service provider-specific extensions to be used. This number can be left zero if no device-specific extensions are to be used. Otherwise, the high-order word contains the major version number; the low-order word contain the minor version number.

lpAddressCaps

Specifies a pointer to a variably sized structure of type LINEADDRESSCAPS. Upon successful completion of the request, this structure is filled with address capabilities information. Prior to calling lineGetAddressCaps, the application should set the dwTotalSize field of this structure to indicate the amount of memory available to TAPI.DLL for returning information.

Valid address IDs range from zero to one less than the number of addresses returned by lineGetDevCaps. The version number to be supplied is the version number that was returned as part of the line's device capabilities by lineGetDevCaps.


lineGetAddressID

[New - Windows 95]

LONG lineGetAddressID(HLINE hLine, LPDWORD lpdwAddressID,
    DWORD dwAddressMode, LPCSTR lpsAddress, DWORD dwSize)

Returns the address ID associated with an address in a different format on the specified line.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALLINEHANDLE	LINEERR_OPERATIONUNAVAIL
LINEERR_INVALADDRESSMODE	LINEERR_OPERATIONFAILED
LINEERR_INVALPOINTER	LINEERR_RESOURCEUNAVAIL
LINEERR_INVALADDRESS	LINEERR_UNINITIALIZED
LINEERR_NOMEM
hLine

Specifies a handle to the open line device.

lpdwAddressID

Specifies a pointer to a DWORD-sized memory location where the address ID is returned.

dwAddressMode

Specifies the address mode of the address contained in lpsAddress. The dwAddressMode parameter is allowed to have only a single flag set. This parameter uses the following LINEADDRESSMODE_ constants:

LINEADDRESSMODE_DIALABLEADDR

The address is specified by its dialable address. The lpsAddress parameter is the dialable address or canonical address format.

lpsAddress

Specifies a pointer to a data structure holding the address assigned to the specified line device. The format of the address is determined by dwAddressMode. Since the only valid value is LINEADDRESSMODE_DIALABLEADDR, lpsAddress uses the common dialable number format and is NULL-terminated.

dwSize

Specifies the size of the address contained in lpsAddress.

This function is used to map a phone number (address) assigned to a line device back to its dwAddressID in the range 0 to the number of addresses minus one returned in the line's device capabilities. The lineMakeCall function allows the application to make a call by specifying a line handle and an address on the line. The address can be specified as a dwAddressID, as a phone number, or as a device-specific name or identifier. Using a phone number may be practical in environments where a single line is assigned multiple addresses. Note that LINEADDRESSMODE_ADDRESSID may not be used with lineGetAddressID.


lineGetAddressStatus

[New - Windows 95]

LONG lineGetAddressStatus(HLINE hLine, DWORD dwAddressID,
    LPLINEADDRESSSTATUS lpAddressStatus)

Allows an application to query the specified address for its current status.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALADDRESSID	LINEERR_RESOURCEUNAVAIL
LINEERR_INVALLINEHANDLE	LINEERR_STRUCTURETOOSMALL
LINEERR_INVALPOINTER	LINEERR_UNINITIALIZED
LINEERR_NOMEM	LINEERR_OPERATIONUNAVAIL
LINEERR_OPERATIONFAILED
hLine

Specifies a handle to the open line device.

dwAddressID

Specifies an address on the given open line device. This is the address to be queried.

lpAddressStatus

Specifies a pointer to a variably sized data structure of type LINEADDRESSSTATUS. Prior to calling lineGetAddressStatus, the application should set the dwTotalSize field of this structure to indicate the amount of memory available to TAPI.DLL for returning information.


lineGetAppPriority

[New - Windows 95]

LONG lineGetAppPriority(LPCSTR lpszAppFilename, DWORD dwMediaMode,
    LPLINEEXTENSIONID const lpExtensionID, DWORD dwRequestMode,
    LPVARSTRING lpExtensionName, LPDWORD lpdwPriority)

Allows an application to determine whether or not it is in the handoff priority list for a particular media mode or Assisted Telephony request mode, and, if so, its position in the priority list.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_INIFILECORRUPT	LINEERR_INVALREQUESTMODE
LINEERR_INVALAPPNAME	LINEERR_NOMEM
LINEERR_INVALMEDIAMODE	LINEERR_OPERATIONFAILED
LINEERR_INVALPOINTER	LINEERR_STRUCTURETOOSMALL
lpszAppFilename

Specifies a pointer to a string containing the application executable module filename (without directory information). The parameter must specify a filename in the 8.3 format. Long filenames cannot be used.

dwMediaMode

Specifies the media mode for which the priority information is to be obtained. The value may be one of the LINEMEDIAMODE_ constants, or an extended media mode value defined by a service provider; only a single bit may be on. The value 0 should be used if checking application priority for Assisted Telephony requests.

lpExtensionID

Specifies a pointer to structure of type LINEEXTENSIONID. This parameter is referenced only if dwMediaModes specifies a value in the range 0x01000000 through 0x80000000 (extended media modes). This parameter is ignored if dwMediaMode is 0 or specifies a LINEMEDIAMODE_ value.

dwRequestMode

If the dwMediaMode parameter is 0, this parameter specifies the Assisted Telephony request mode for which priority is to be checked. It must be either LINEREQUESTMODE_MAKECALL or LINEREQUESTMODE_MEDIACALL. This parameter is ignored if dwMediaMode is non-zero.

lpExtensionName

If dwMediaMode specifies an extended media mode, this parameter must specify a pointer to a memory location into which a VARSTRING structure will be written by TAPI. This structure will contain the "friendly name" of the extended media mode associated with the specified media mode value and extension ID, if one exists. This parameter is ignored if dwMediaMode is 0 or specifies a LINEMEDIAMODE_ value. Prior to calling lineGetAppPriority, the application should set the dwTotalSize field of this structure to indicate the amount of memory available to TAPI for returning information.

lpdwPriority

Specifies a pointer to a DWORD-size memory location into which TAPI will write the priority of the application for the specified media or request mode. The value 0 will be returned if the application is not in the stored priority list and is does not currently have any line device open with ownership requested of the specified media mode or having registered for the specified request mode. The value -1 (0xFFFFFFFF) is returned if the application has the line open for the specified media mode or has registered for the specified requests,  but the application is not in the stored priority list (i.e., it is in the temporary priority list only). Otherwise, the value will indicate the application's position in the list (with 1 being highest priority, and increasing values indicating decreasing priority).

If LINEERR_INVALMEDIAMODE is returned, the value specified in dwMediaMode is not 0, not a valid extended media mode, and not a LINEMEDIAMODE_ constant, or more than one bit is on in the parameter value.

Although this is a new function which older applications would not be expected to call, for backward compatibility, they should not be prevented from doing so; the function will work the same way for all applications.


lineGetCallInfo

[New - Windows 95]

LONG lineGetCallInfo(HCALL hCall, LPLINECALLINFO lpCallInfo)

This operation enables an application to obtain fixed information about the specified call.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALCALLHANDLE	LINEERR_RESOURCEUNAVAIL
LINEERR_INVALPOINTER	LINEERR_STRUCTURETOOSMALL
LINEERR_NOMEM	LINEERR_UNINITIALIZED
LINEERR_OPERATIONFAILED	LINEERR_OPERATIONUNAVAIL
hCall

Specifies a handle to the call to be queried. Call state of hCall can be any state.

lpCallInfo

Specifies a pointer to a variably sized data structure of type LINECALLINFO. Upon successful completion of the request, this structure is filled with call-related information. Prior to calling lineGetCallInfo, the application should set the dwTotalSize field of this structure to indicate the amount of memory available to TAPI.DLL for returning information.

A separate LINECALLINFO structure exists for every inbound or outbound call. The structure contains primarily fixed information about the call. An application would typically be interested in checking this information when it receives its handle for a call by the LINE_CALLSTATE message, or each time it receives notification by a LINE_CALLINFO message that parts of the call information structure have changed. These messages supply the handle for the call as a parameter.


lineGetCallStatus

[New - Windows 95]

LONG lineGetCallStatus(HCALL hCall, LPLINECALLSTATUS lpCallStatus)

Returns the current status of the specified call.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALCALLHANDLE	LINEERR_RESOURCEUNAVAIL
LINEERR_INVALPOINTER	LINEERR_STRUCTURETOOSMALL
LINEERR_NOMEM	LINEERR_UNINITIALIZED
LINEERR_OPERATIONFAILED	LINEERR_OPERATIONUNAVAIL
hCall

Specifies a handle to the call to be queried. Call state of hCall can be any state.

lpCallStatus

Specifies a pointer to a variably sized data structure of type LINECALLSTATUS. Upon successful completion of the request, this structure is filled with call status information. Prior to calling lineGetCallStatus, the application should set the dwTotalSize field of this structure to indicate the amount of memory available to TAPI.DLL for returning information.

The lineGetCallStatus function returns the dynamic status of a call, whereas lineGetCallInfo returns primarily static information about a call. Call status information includes the current call state, detailed mode information related to the call while in this state (if any), as well as a list of the available API functions the application can invoke on the call while the call is in this state. An application would typically be interested in requesting this information when it receives notification about a call state change by the LINE_CALLSTATE message.


lineGetConfRelatedCalls

[New - Windows 95]

LONG lineGetConfRelatedCalls(HCALL hCall, LPLINECALLLIST lpCallList)

Returns a list of call handles that are part of the same conference call as the specified call. The specified call is either a conference call or a participant call in a conference call. New handles are generated for those calls for which the application does not already have handles, and the application is granted monitor privilege to those calls.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALCALLHANDLE	LINEERR_OPERATIONFAILED
LINEERR_NOCONFERENCE	LINEERR_RESOURCEUNAVAIL
LINEERR_INVALPOINTER	LINEERR_STRUCTURETOOSMALL
LINEERR_NOMEM	LINEERR_UNINITIALIZED
hCall

Specifies a handle to a call. This is either a conference call or a participant call in a conference call. For a conference parent call, call state of hCall can be any state. For a conference participant call, it must be in the conferenced state.

lpCallList

Specifies a pointer to a variably sized data structure of type LINECALLLIST. Upon successful completion of the request, call handles to all calls in the conference call are returned in this structure. The first call in the list is the conference call, the other calls are the participant calls. The application is granted monitor privilege to those calls for which it does not already have handles; the privileges to calls in the list for which the application already has handles is unchanged. Prior to calling lineGetConfRelatedCalls, the application should set the dwTotalSize field of this structure to indicate the amount of memory available to TAPI.DLL for returning information.

The specified call can either be a conference call handle or a handle to a participant call. For example, a consultation call that has not yet been added to a conference call is not part of a conference. The first entry in the list that is returned is the conference call handle, the other handles are all the participant calls. The specified call is always one of the calls returned in the list. Calls in the list to which the application does not already have a call handle are assigned monitor privilege; privileges to calls for which the application already has handles are unchanged. The application can use lineSetCallPrivilege to change the privilege of the call.

Note that if lineGetConfRelatedCalls is called immediately after a call is added to a conference using lineAddToConferenceor lineCompleteTransfer, lineGetConfRelatedCalls may not return a complete list of related calls because TAPI.DLL waits to receive a LINE_CALLSTATE message indicating that the call has entered LINECALLSTATE_CONFERENCED before it considers the call to actually be part of the conference (that is, the conferenced state is confirmed by the service provider). Once the application has received the LINE_CALLSTATE message, lineGetConfRelatedCalls returns complete information.

The application can invoke lineGetCallInfo and lineGetCallStatus for each call in the list to determine the call's information and status, respectively.


lineGetCountry

[New - Windows 95]

LONG lineGetCountry (DWORD dwCountryID, DWORD dwAPIVersion,
    LPLINECOUNTRYLIST lpLineCountryList)

Fetches the stored dialing rules and other information related to a specified country, the first country in the country list, or all countries.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_INCOMPATIBLEAPIVERSION	LINEERR_NOMEM
LINEERR_INIFILECORRUPT	LINEERR_OPERATIONFAILED
LINEERR_INVALCOUNTRYCODE	LINEERR_STRUCTURETOOSMALL
LINEERR_INVALPOINTER
dwCountryID

Specifies the country ID (not the country code) of the country for which information is to be obtained. If the value 1 is specified, information on the first country in the country list is obtained. If the value 0 is specified, information on all countries is obtained (which may require a great deal of memory − 20Kbytes or more).

dwAPIVersion

Indicates the highest version of TAPI supported by the application (not necessarily the value negotiated by lineNegotiateAPIVersion on some particular line device).

lpLineCountryList

Specifies a pointer to a location to which a LINECOUNTRYLIST structure will be loaded. Prior to calling lineGetCountry, the application should set the dwTotalSize field of this structure to indicate the amount of memory available to TAPI for returning information.

Although this is a new function which older applications would not be expected to call, for backward compatibility, they should not be prevented from doing so; the function will work the same way for all applications.


lineGetDevCaps

[New - Windows 95]

LONG lineGetDevCaps(HLINEAPP hLineApp, DWORD dwDeviceID,
    DWORD dwAPIVersion, DWORD dwExtVersion, LPLINEDEVCAPS lpLineDevCaps)

Queries a specified line device to determine its telephony capabilities. The returned information is valid for all addresses on the line device.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_BADDEVICEID	LINEERR_NOMEM
LINEERR_INCOMPATIBLEAPIVERSION	LINEERR_OPERATIONFAILED
LINEERR_INCOMPATIBLEEXTVERSION	LINEERR_RESOURCEUNAVAIL
LINEERR_INVALAPPHANDLE	LINEERR_STRUCTURETOOSMALL
LINEERR_INVALPOINTER	LINEERR_UNINITIALIZED
LINEERR_NODRIVER	LINEERR_OPERATIONUNAVAIL
LINEERR_NODEVICE
hLineApp

Specifies the handle to the application's registration with TAPI.

dwDeviceID

Specifies the line device to be queried.

dwAPIVersion

Specifies the version number of the Telephony API to be used. The high-order word contains the major version number; the low-order word contains the minor version number. This number is obtained by lineNegotiateAPIVersion.

dwExtVersion

Specifies the version number of the service provider-specific extensions to be used. This number is obtained by lineNegotiateExtVersion. It can be left zero if no device-specific extensions are to be used. Otherwise, the high-order word contains the major version number; the low-order word contains the minor version number.

lpLineDevCaps

Specifies a pointer to a variably sized structure of type LINEDEVCAPS. Upon successful completion of the request, this structure is filled with line device capabilities information. Prior to calling lineGetDevCaps, the application should set the dwTotalSize field of this structure to indicate the amount of memory available to TAPI.DLL for returning information.

Before using lineGetDevCaps, the application must negotiate the API version number to use, and, if desired, the extension version to use.

The API and extension version numbers are those under which TAPI.DLL and the service provider must operate. If version ranges do not overlap, the application, API, or service-provider versions are incompatible and an error is returned.

One of the fields in the LINEDEVCAPS structure returned by this function contains the number of addresses assigned to the specified line device. The actual address IDs used to reference individual addresses vary from zero to one less than the returned number. The capabilities of each address may be different. Use lineGetAddressCaps for each available <dwDeviceID, dwAddressID> combination to determine the exact capabilities of each address.


lineGetDevConfig

[New - Windows 95]

LONG lineGetDevConfig (DWORD dwDeviceID, LPVARSTRING lpDeviceConfig,
    LPCSTR lpszDeviceClass)

Returns an "opaque" data structure object the contents of which are specific to the line (service provider) and device class. The data structure object stores the current configuration of a media-stream device associated with the line device.

•	Returns zero if the function is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_BADDEVICEID	LINEERR_NODRIVER
LINEERR_INVALDEVICECLASS	LINEERR_OPERATIONUNAVAIL
LINEERR_INVALPOINTER	LINEERR_RESOURCEUNAVAIL
LINEERR_STRUCTURETOOSMALL	LINEERR_OPERATIONFAILED
LINEERR_NOMEM	LINEERR_UNINITIALIZED
LINEERR_NODEVICE
dwDeviceID

Specifies the line device to be configured.

lpDeviceConfig

Specifies a pointer to the memory location of type VARSTRING where the device configuration structure is returned. Upon successful completion of the request, this location is filled with the device configuration. The dwStringFormat field in the VARSTRING structure will be set to STRINGFORMAT_BINARY. Prior to calling lineGetDevConfig, the application should set the dwTotalSize field of this structure to indicate the amount of memory available to TAPI.DLL for returning information.

lpszDeviceClass

Specifies a pointer to a NULL-terminated ASCII string that specifies the device class of the device whose configuration is requested. Valid device class lineGetID strings are the same as those specified for the function.

Call states are device specific.

This function can be used to retrieve a data structure from TAPI that specifies the configuration of a media stream device associated with a particular line device. For example, the contents of this structure could specify data rate, character format, modulation schemes, and error control protocol settings for a "datamodem" media device associated with the line.

Typically, an application will call lineGetID to identify the media stream device associated with a line, and then call lineConfigDialog to allow the user to set up the device configuration. It could then call lineGetDevConfig, and save the configuration information in a phone book (or other database) associated with a particular call destination. When the user later wishes to call the same destination again, lineSetDevConfig can be used to restore the configuration settings selected by the user. The functions lineSetDevConfig, lineConfigDialog, and lineGetDevConfig can be used, in that order, to allow the user to view and update the settings.

The exact format of the data contained within the structure is specific to the line and media stream API (device class), is undocumented, and is undefined. The structure returned by this function cannot be directly accessed or manipulated by the application, but can only be stored intact and later used in lineSetDevConfig to restore the settings. The structure also cannot necessarily be passed to other devices, even of the same device class (although this may work in some instances, it is not guaranteed).


lineGetIcon

[New - Windows 95]

LONG lineGetIcon(DWORD dwDeviceID, LPCSTR lpszDeviceClass,
    LPHICON lphIcon)

Allows an application to retrieve a service line device-specific (or provider-specific) icon for display to the user.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_BADDEVICEID	LINEERR_OPERATIONFAILED
LINEERR_INVALPOINTER	LINEERR_RESOURCEUNAVAIL
LINEERR_INVALDEVICECLASS	LINEERR_UNINITIALIZED
LINEERR_NOMEM	LINEERR_NODEVICE
dwDeviceID

Specifies the line device whose icon is requested.

lpszDeviceClass

Specifies a pointer to a NULL-terminated string that identifies a device class name. This device class allows the application to select a specific sub-icon applicable to that device class. This parameter is optional and can be left NULL or empty, in which case the highest-level icon associated with the line device rather than a specified media stream device would be selected.

lphIcon

Specifies a pointer to a memory location in which the handle to the icon is returned.

The lineGetIcon function causes the provider to return a handle (in lphIcon) to an icon resource (obtained from LoadIcon) that is associated with the specified line. The icon handle is for a resource associated with the provider. The application must use CopyIcon if it wishes to reference the icon after the provider is unloaded, which is unlikely to happen as long as the application has the line open.

lpszDeviceClass allows the provider to return different icons based on the type of service being referenced by the caller. The permitted strings are the same as for lineGetID. For example, if the line supports the Comm API, passing "COMM" as lpszDeviceClass causes the provider to return an icon related specifically to the Comm device functions of the service provider.

The parameters "tapi/line", "a", or NULL may be used to request the icon for the line service. If the provider does not return an icon, TAPI.DLL substitutes a generic Windows Telephony line device icon.


lineGetID

[New - Windows 95]

LONG lineGetID(HLINE hLine, DWORD dwAddressID, HCALL hCall,
    DWORD dwSelect, LPVARSTRING lpDeviceID, LPCSTR lpszDeviceClass)

Returns a device ID for the specified device class associated with the selected line, address, or call.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALLINEHANDLE	LINEERR_NOMEM
LINEERR_INVALADDRESSID	LINEERR_OPERATIONUNAVAIL
LINEERR_INVALCALLHANDLE	LINEERR_OPERATIONFAILED
LINEERR_INVALCALLSELECT	LINEERR_RESOURCEUNAVAIL
LINEERR_INVALPOINTER	LINEERR_STRUCTURETOOSMALL
LINEERR_NODEVICE	LINEERR_UNINITIALIZED
hLine

Specifies a handle to an open line device.

dwAddressID

Specifies an address on the given open line device.

hCall

Specifies a handle to a call.

dwSelect

Specifies whether the requested device ID is associated with the line, address or a single call. The dwSelect parameter can only have a single flag set. This parameter uses the following LINECALLSELECT_ constants:

LINECALLSELECT_LINE

Selects the specified line device. The hLine parameter must be a valid line handle; hCall and dwAddressID are ignored.

LINECALLSELECT_ADDRESS

Selects the specified address on the line. Both hLine and dwAddressID must be valid; hCall is ignored.

LINECALLSELECT_CALL

Selects the specified call. hCall must be valid; hLine and dwAddressID are both ignored.

lpDeviceID

Specifies a pointer to a memory location of type VARSTRING, where the device ID is returned. Upon successful completion of the request, this location is filled with the device ID. The format of the returned information depends on the method used by the device class API for naming devices. Prior to calling lineGetID, the application should set the dwTotalSize field of this structure to indicate the amount of memory available to TAPI.DLL for returning information.

lpszDeviceClass

Specifies a pointer to a NULL-terminated ASCII string that specifies the device class of the device whose ID is requested. Valid device class strings are those used in the SYSTEM.INI section to identify device classes.

This function can be used to retrieve a line-device ID when given a line handle. This is useful after a line device has been opened using LINEMAPPER as a device ID in order to determine the real line-device ID of the opened line. This function can also be used to obtain the device ID of a phone device or media device (for device classes such as COM, wave, MIDI, phone, line, or NDIS) associated with a call, address or line. This ID can then be used with the appropriate API (such as phone, midi, wave) to select the corresponding media device associated with the specified call.

See Chapter 9, "Device Classes" for device class names.

A vendor that defines a device-specific media mode also needs to define the corresponding device-specific (proprietary) API to manage devices of the media mode. To avoid collisions on device class names assigned independently by different vendors, a vendor should select a name that uniquely identifies both the vendor and, following it, the media type. For example: "intel/video".


lineGetLineDevStatus

[New - Windows 95]

LONG lineGetLineDevStatus(HLINE hLine, LPLINEDEVSTATUS lpLineDevStatus)

Enables an application to query the specified open line device for its current status.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALLINEHANDLE	LINEERR_RESOURCEUNAVAIL
LINEERR_INVALPOINTER	LINEERR_STRUCTURETOOSMALL
LINEERR_NOMEM	LINEERR_UNINITIALIZED
LINEERR_OPERATIONFAILED	LINEERR_OPERATIONUNAVAIL
hLine

Specifies a handle to the open line device to be queried.

lpLineDevStatus

Specifies a pointer to a variably sized data structure of type LINEDEVSTATUS. Upon successful completion of the request, this structure is filled with the line's device status. Prior to calling lineGetLineDevStatus, the application should set the dwTotalSize field of this structure to indicate the amount of memory available to TAPI.DLL for returning information.

An application uses lineGetLineDevStatus to query the line device for its current line status. This status information applies globally to all addresses on the line device. Use lineGetAddressStatus to determine status information about a specific address on a line.


lineGetNewCalls

[New - Windows 95]

LONG lineGetNewCalls(HLINE hLine, DWORD dwAddressID, DWORD dwSelect,
     LPLINECALLLIST lpCallList)

Returns call handles to calls on a specified line or address for which the application currently does not have handles. The application is granted monitor privilege to these calls.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALADDRESSID	LINEERR_OPERATIONFAILED
LINEERR_INVALCALLSELECT	LINEERR_RESOURCEUNAVAIL
LINEERR_INVALLINEHANDLE	LINEERR_STRUCTURETOOSMALL
LINEERR_INVALPOINTER	LINEERR_UNINITIALIZED
LINEERR_NOMEM
hLine

Specifies a handle to an open line device.

dwAddressID

Specifies an address on the given open line device.

dwSelect

Specifies the selection of calls that are requested. Note that dwSelect can only have one bit set. This parameter uses the following LINECALLSELECT_ constants:

LINECALLSELECT_LINE

Selects calls on the specified line device. The hLine parameter must be a valid line handle; dwAddressID is ignored.

LINECALLSELECT_ADDRESS

Selects calls on the specified address on the specified line device. Both hLine and dwAddressID must be valid.

lpCallList

Specifies a pointer to a variably sized data structure of type LINECALLLIST. Upon successful completion of the request, call handles to all selected calls are returned in this structure. Prior to calling lineGetNewCalls, the application should set the dwTotalSize field of this structure to indicate the amount of memory available to TAPI.DLL for returning information.

An application can use lineGetNewCalls to obtain handles to calls for which it currently has no handles. The application can select the calls for which handles are to be returned by basing this selection on scope (calls on a specified line, or calls on a specified address). For example, an application can request call handles to all calls on a given address for which it currently has no handle. The application is always given monitor privilege to the new call handles. Also, when opening a line, an application uses this function to become aware of existing calls.

The application can invoke lineGetCallInfo and lineGetCallStatus for each call in the list to determine the call's information and status, respectively. It can use lineSetCallPrivilege to change its privilege to owner.


lineGetNumRings

[New - Windows 95]

LONG lineGetNumRings(HLINE hLine, DWORD dwAddressID,
    LPDWORD lpdwNumRings)

Determines the number of rings an inbound call on the given address should ring prior to answering the call.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALADDRESSID	LINEERR_OPERATIONFAILED
LINEERR_INVALLINEHANDLE	LINEERR_RESOURCEUNAVAIL
LINEERR_INVALPOINTER	LINEERR_UNINITIALIZED
LINEERR_NOMEM
hLine

Specifies a handle to the open line device.

dwAddressID

Specifies an address on the line device.

lpdwNumRings

Specifies the number of rings that is the minimum of all current lineSetNumRings requests.

The lineGetNumRings and lineSetNumRings functions, when used in combination, provide a mechanism to support the implementation of toll-saver features across multiple independent applications.

An application that receives a handle for a call in the offering state and a LINE_LINEDEVSTATE ringing message should wait a number of rings equal to the number returned by lineGetNumRings before answering the call in order to honor the toll-saver settings across all applications. The lineGetNumRings function returns the minimum of all application's number of rings specified by lineSetNumRings. Since this number may vary dynamically, an application should invoke lineGetNumRings each time it has the option to answer a call. If no application has called lineSetNumRings, the number or rings returned is 0xFFFFFFFF. A separate LINE_LINEDEVSTATE ringing message is sent to the application for each ring cycle.

If call classification is performed by TAPI.DLL of answering all calls of unknown media mode and filtering the media stream, TAPI.DLL honors this number as well.

Note that this operation is purely informational and does not in itself affect the state of any calls on the line device.


lineGetProviderList

[New - Windows 95]

LONG lineGetProviderList (DWORD dwAPIVersion,
    LPLINEPROVIDERLIST lpProviderList)

Returns a list of service providers currently installed in the telephony system.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_INCOMPATIBLEAPIVERSION	LINEERR_NOMEM
LINEERR_INIFILECORRUPT	LINEERR_OPERATIONFAILED
LINEERR_INVALPOINTER	LINEERR_STRUCTURETOOSMALL
dwAPIVersion

Indicates the highest version of TAPI supported by the application (not necessarily the value negotiated by lineNegotiateAPIVersion on some particular line device).

lpProviderList

Specifies a pointer to a memory location where TAPI will return a LINEPROVIDERLIST structure. Prior to calling lineGetProviderList, the application should set the dwTotalSize field of this structure to indicate the amount of memory available to TAPI for returning information.

Although this is a new function which older applications would not be expected to call, for backward compatibility, they should not be prevented from doing so; the function will work the same way for all applications.


lineGetRequest

[New - Windows 95]

LONG lineGetRequest(HLINEAPP hLineApp, DWORD dwRequestMode,
    LPVOID lpRequestBuffer)

Retrieves the next by-proxy request for the specified request mode.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALAPPHANDLE	LINEERR_NOTREGISTERED
LINEERR_INVALPOINTER	LINEERR_OPERATIONFAILED
LINEERR_INVALREQUESTMODE	LINEERR_RESOURCEUNAVAIL
LINEERR_NOMEM	LINEERR_UNINITIALIZED
LINEERR_NOREQUEST
hLineApp

Specifies the application's usage handle for the line portion of TAPI.

dwRequestMode

Specifies the type of request that is to be obtained. Note that dwRequestMode can only have one bit set. This parameter uses the following LINEREQUESTMODE_ constants:

LINEREQUESTMODE_MAKECALL

A tapiRequestMakeCall request.

lpRequestBuffer

Specifies a pointer to a memory buffer where the parameters of the request are to be placed. The size of the buffer and the interpretation of the information placed in the buffer depends on the request mode. The application-allocated buffer is assumed to be of sufficient size to hold the request.

If dwRequestMode is LINEREQUESTMODE_MAKECALL, interpret the content of the request buffer using the LINEREQMAKECALL structure.

If dwRequestMode is LINEREQUESTMODE_MEDIACALL, interpret the content of the request buffer using the LINEREQMEDIACALL structure.

A telephony-enabled application can request that a call be placed on its behalf by invoking tapiRequestMakeCall. These requests are queued by TAPI.DLL and the highest priority application that has registered to handle the request is sent a LINE_REQUEST message with indication of the mode of the request that is pending. Typically, this application is the user's call-control application. The LINE_REQUEST message indicates that zero or more requests may be pending for the registered application to process; after receiving LINE_REQUEST, it is the responsibility of the recipient application to call lineGetRequest until LINEERR_NOREQUEST is returned, indicating that no more requests are pending.

Next, the call-control application that receives this message invokes lineGetRequest, specifying the request mode and a buffer that is large enough to hold the request. The call-control application then interprets and executes the request.

After execution of lineGetRequest, TAPI.DLL purges the request from its internal queue, making room available for a subsequent request. It is therefore possible for a new LINE_REQUEST message to be received immediately upon execution of lineGetRequest, should the same or another application issue another request. It is the responsibility of the request recipient application to handle this scenario by some mechanism (for example, by making note of the additional LINE_REQUEST and deferring a subsequent lineGetRequest until processing of the preceeding request completes, by getting the subsequent request and buffer as necessary, or by another appropriate means).

Note that the subsequent LINE_REQUEST should not be ignored because it will not be repeated by TAPI.DLL.


lineGetStatusMessages

[New - Windows 95]

LONG lineGetStatusMessages(HLINE hLine, LPDWORD lpdwLineStates,
    LPDWORD lpdwAddressStates)

This operation enables an application to query which notification messages the application is set up to receive for events related to status changes for the specified line or any of its addresses.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALLINEHANDLE	LINEERR_OPERATIONFAILED
LINEERR_INVALPOINTER	LINEERR_RESOURCEUNAVAIL
LINEERR_NOMEM	LINEERR_UNINITIALIZED
hLine

Specifies a handle to the line device.

lpdwLineStates

Specifies a bit array that identifies for which line device status changes a message is to be sent to the application. If a flag is TRUE, that message is enabled; if FALSE, it is disabled. Note that multiple flags can be set. This parameter uses the following LINEDEVSTATE_ constants:

LINEDEVSTATE_OTHER

Device-status items other than those listed below have changed. The application should check the current device status to determine which items have changed.

LINEDEVSTATE_RINGING

The switch tells the line to alert the user.

LINEDEVSTATE_CONNECTED

The line was previously disconnected and is now connected to TAPI.

LINEDEVSTATE_NUMCOMPLETIONS

The number of outstanding call completions on the line device has changed.

LINEDEVSTATE_DISCONNECTED

This line was previously connected and is now disconnected from TAPI.

LINEDEVSTATE_MSGWAITON

The "message waiting" indicator is turned on.

LINEDEVSTATE_MSGWAITOFF

The "message waiting" indicator is turned off.

LINEDEVSTATE_INSERVICE

The line is connected to TAPI. This happens when TAPI is first activated or when the line wire is physically plugged in and in service at the switch while TAPI is active.

LINEDEVSTATE_OUTOFSERVICE

The line is out of service at the switch or physically disconnected. TAPI cannot be used to operate on the line device.

LINEDEVSTATE_MAINTENANCE

Maintenance is being performed on the line at the switch. TAPI cannot be used to operate on the line device.

LINEDEVSTATE_OPEN

The line has been opened by some application.

LINEDEVSTATE_CLOSE

The line has been closed by some application.

LINEDEVSTATE_NUMCALLS

The number of calls on the line device has changed.

LINEDEVSTATE_TERMINALS

The terminal settings have changed.

LINEDEVSTATE_ROAMMODE

The roam mode of the line device has changed.

LINEDEVSTATE_BATTERY

The battery level has changed significantly (cellular).

LINEDEVSTATE_SIGNAL

The signal level has changed significantly (cellular).

LINEDEVSTATE_DEVSPECIFIC

The line's device-specific information has changed.

LINEDEVSTATE_REINIT

Items have changed in the configuration of line devices. To become aware of these changes (for example, the appearance of new line devices) the application should reinitialize its use of TAPI. The hDevice parameter parameter of the LINE_LINEDEVSTATE message is left NULL for this state change as it applies to any of the lines in the system.

LINEDEVSTATE_LOCK

The locked status of the line device has changed.

lpdwAddressStates

Specifies a bit array that identifies for which address status changes a message is to be sent to the application. If a flag is TRUE, that message is enabled; if FALSE, disabled. Multiple flags can be set. This parameter uses the following LINEADDRESSSTATE_ constants:

LINEADDRESSSTATE_OTHER

Address-status items other than those listed below have changed. The application should check the current address status to determine which items have changed.

LINEADDRESSSTATE_DEVSPECIFIC

The device-specific item of the address status has changed.

LINEADDRESSSTATE_INUSEZERO

The address has changed to idle (it is now in use by zero stations).

LINEADDRESSSTATE_INUSEONE

The address has changed from being idle or from being in use by many bridged stations to being in use by just one station.

LINEADDRESSSTATE_INUSEMANY

The monitored or bridged address has changed from being in use by one station to being used by more than one station.

LINEADDRESSSTATE_NUMCALLS

The number of calls on the address has changed. This is the result of events such as a new inbound call, an outbound call on the address, or a call changing its hold status.

LINEADDRESSSTATE_FORWARD

The forwarding status of the address has changed, including the number of rings for determining a "no answer" condition. The application should check the address status to determine details about the address's current forwarding status.

LINEADDRESSSTATE_TERMINALS

The terminal settings for the address have changed.

TAPI defines a number of messages that notify applications about events occurring on lines and addresses. An application may not be interested in receiving all address and line status change messages. The lineSetStatusMessages function can be used to select which messages the application wants to receive. By default, address status and line status reporting is disabled.


lineGetTranslateCaps

[New - Windows 95]

LONG lineGetTranslateCaps(HLINEAPP hLineApp, DWORD dwAPIVersion,
    LPLINETRANSLATECAPS lpTranslateCaps)

Returns address translation capabilities.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_INCOMPATIBLEAPIVERSION	LINEERR_NOMEM
LINEERR_INIFILECORRUPT	LINEERR_OPERATIONFAILED
LINEERR_INVALAPPHANDLE	LINEERR_RESOURCEUNAVAIL
LINEERR_INVALPOINTER	LINEERR_STRUCTURETOOSMALL
LINEERR_NODRIVER	LINEERR_UNINITIALIZED
hLineApp

Specifies the application handle returned by lineInitialize.

dwAPIVersion

Indicates the version of TAPI negotiated by lineNegotiateAPIVersion.

lpTranslateCaps

Specifies a pointer to a location to which a LINETRANSLATECAPS structure will be loaded. Prior to calling lineGetTranslateCaps, the application should set the dwTotalSize field of this structure to indicate the amount of memory available to TAPI.DLL for returning information.

If an application has not yet called the lineInitialize function, it can set the hLineApp parameter to NULL and the dwDevice parameter to 0 when calling the lineGetTranslateCaps function.


lineHandoff

[New - Windows 95]

LONG lineHandoff(HCALL hCall, LPCSTR lpszFileName, DWORD dwMediaMode)

Gives ownership of the specified call to another application. The application can be either specified directly by its file name or indirectly as the highest priority application that handles calls of the specified media mode.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALCALLHANDLE	LINEERR_OPERATIONFAILED
LINEERR_INVALMEDIAMODE	LINEERR_TARGETNOTFOUND
LINEERR_INVALPOINTER	LINEERR_TARGETSELF
LINEERR_NOMEM	LINEERR_UNINITIALIZED
LINEERR_NOTOWNER
hCall

Specifies a handle to the call to be handed off. The application must be an owner of the call. Call state of hCall can be any state.

lpszFileName

Specifies a pointer to a NULL-terminated ASCII string. If this pointer parameter is non-NULL, it contains the file name of the application that is the target of the handoff. If NULL, the handoff target is the highest priority application that has opened the line for owner privilege for the specified media mode. A valid file name does not include the path of the file.

dwMediaMode

Specifies the media mode used to identify the target for the indirect handoff. The dwMediaMode parameter indirectly identifies the target application that is to receive ownership of the call. This parameter is ignored if lpszFileName is not NULL. Only a single flag may be set in the dwMediaMode parameter at any one time. This parameter uses the following LINEMEDIAMODE_ constants:

LINEMEDIAMODE_UNKNOWN

The target application is the one that handles calls of unknown media mode (unclassified calls).

LINEMEDIAMODE_INTERACTIVEVOICE

The target application is the one that handles calls with the interactive voice media mode (live conversations).

LINEMEDIAMODE_AUTOMATEDVOICE

Voice energy is present on the call and the voice is locally handled by an automated application.

LINEMEDIAMODE_DATAMODEM

The target application is the one that handles calls with the data modem media mode.

LINEMEDIAMODE_G3FAX

The target application is the one that handles calls with the group 3 fax media mode.

LINEMEDIAMODE_TDD

The target application is the one that handles calls with the TDD (Telephony Devices for the Deaf) media mode.

LINEMEDIAMODE_G4FAX

The target application is the one that handles calls with the group 4 fax media mode.

LINEMEDIAMODE_DIGITALDATA

The target application is the one that handles calls that are digital data calls.

LINEMEDIAMODE_TELETEX

The target application is the one that handles calls with the teletex media mode.

LINEMEDIAMODE_VIDEOTEX

The target application is the one that handles calls with the videotex media mode.

LINEMEDIAMODE_TELEX

The target application is the one that handles calls with the telex media mode.

LINEMEDIAMODE_MIXED

The target application is the one that handles calls with the ISDN mixed media mode.

LINEMEDIAMODE_ADSI

The target application is the one that handles calls with the ADSI (Analog Display Services Interface) media mode.

LINEMEDIAMODE_VOICEVIEW

The media mode of the call is VoiceView.

If LINEERR_TARGETNOTFOUND is returned, a target for the call handoff was not found. This may occur if the named application did not open the same line with the LINECALLPRIVILEGE_OWNER bit in the dwPrivileges parameter of lineOpen. Or, in the case of media-mode handoff, no application has opened the same line with the LINECALLPRIVILEGE_OWNER bit in the dwPrivileges parameter of lineOpen and with the media mode specified in the dwMediaMode parameter having been specified in the dwMediaModes parameter of lineOpen.

Call handoff allows ownership of a call to be passed among applications. There are two types of handoff. In the first type, if the application knows the file name of the target application, it can simply specify the file name of that application. If an instance of the target application has opened the line device, ownership of the call will be passed to the other application; otherwise, the handoff will fail and an error is returned. This form of handoff will succeed if the call handle is handed off to the same file name as the application requesting the handoff.

The second type of handoff is based on media mode. In this case, the application indirectly specifies the target application by means of a media mode. The highest priority application that has currently opened the line device for that media mode is the target for the handoff. If there is no such application, the handoff fails and an error is returned.

The lineHandoff function does not change the media mode of a call. To change the media mode of a call, the application should use lineSetMediaMode on the call, specifying the new media mode. This changes the call's media as stored in the call's LINECALLINFO structure.

If handoff is successful, the receiving application will receive a LINE_CALLSTATE message for the call. This message indicates that the receiving application has owner privilege to the call (dwParam3). In addition, the number of owners and/or monitors for the call may have changed. This is reported by the LINE_CALLINFO message, and the receiving application can then invoke lineGetCallStatus and lineGetCallInfo to retrieve more information about the received call.

The receiving application should first check the media mode in LINECALLINFO. If only a single media mode flag is set, the call is officially of that media mode, and the application can act accordingly. If UNKNOWN and other media mode flags are set, then the media mode of the call is officially UNKNOWN but is assumed to be of one of the media modes for which a flag is set in LINECALLINFO. The application should assume that it ought to probe for the highest priority media mode.

If the probe succeeds (either for that media mode or for another one), the application should set the media mode field in LINECALLINFO to just the single media mode that was recognized. If the media mode is for that media mode, the application can act accordingly; otherwise, if it makes a determination for another media mode, it must first hand off the call to that media mode.

If the probe fails, the application should clear the corresponding media mode flag in LINECALLINFO and hand off the callback, specifying dwMediaMode as LINEMEDIAMODE_UNKNOWN. It should also deallocate its call handle (or revert back to monitoring).

If none of the media modes succeeded in making a determination, only the UNKNOWN flag will remain set in the media mode field of LINECALLINFO at the time the media application attempts to hand off the call back to UNKNOWN. The final lineHandoff will fail if the application is the only remaining owner of the call. This informs the application that it should drop the call and deallocate its handle, in which case the call is abandoned. The privileges of the invoking application to the call are unchanged by this operation, but the application can change its privileges to a call with lineSetCallPrivilege.


lineHold

[New - Windows 95]

LONG lineHold(HCALL hCall)

Places the specified call on hold.

•	Returns a positive request ID if the function will be completed asynchronously or a negative error number if an error has occurred. The dwParam2 parameter of the corresponding LINE_REPLY callback message is zero if the function is successful or it is a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALCALLHANDLE	LINEERR_OPERATIONUNAVAIL
LINEERR_INVALCALLSTATE	LINEERR_OPERATIONFAILED
LINEERR_NOMEM	LINEERR_RESOURCEUNAVAIL
LINEERR_NOTOWNER	LINEERR_UNINITIALIZED
hCall

Specifies a handle to the call to be placed on hold. The application must be an owner of the call. Call state of hCall must be connected.

The call on hold is temporarily disconnected allowing the application to use the line device for making or answering other calls. The lineHold function performs a so-called "hard hold" of the specified call (as opposed to a "consultation call"). A call on hard hold typically cannot be transferred or included in a conference call, but a consultation call can. Consultation calls are initiated using lineSetupTransfer, lineSetupConference, or linePrepareAddToConference.

After a call has been successfully placed on hold, the call state typically transitions to onHold. A held call is retrieved by lineUnhold. While a call is on hold, the application may receive LINE_CALLSTATE messages about state changes of the held call. For example, if the held party hangs up, the call state may transition to disconnected.


lineInitialize

[New - Windows 95]

LONG lineInitialize(LPHLINEAPP lphLineApp, HINSTANCE hInstance,
    LINECALLBACK lpfnCallback, LPCSTR lpszAppName, LPDWORD lpdwNumDevs)

Initializes the application's use of TAPI.DLL for subsequent use of the line abstraction. It registers the application's specified notification mechanism and returns the number of line devices available to the application. A line device is any device that provides an implementation for the line-prefixed functions in the Telephony API.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALAPPNAME	LINEERR_OPERATIONFAILED
LINEERR_INIFILECORRUPT	LINEERR_RESOURCEUNAVAIL
LINEERR_INVALPOINTER	LINEERR_REINIT
LINEERR_NODRIVER	LINEERR_NODEVICE
LINEERR_NOMEM	LINEERR_NOMULTIPLEINSTANCE
lphLineApp

Specifies a pointer to a location that is filled with the application's usage handle for TAPI.

hInstance

Specifies the instance handle of the client application or DLL.

lpfnCallback

Specifies the address of a callback function that is invoked to determine status and events on the line device, addresses, or calls. For more information see lineCallbackFunc.

lpszAppName

Specifies a pointer to a NULL-terminated ASCII string that contains only displayable ASCII characters. If this parameter is not NULL, it contains an application-supplied name of the application. This name is provided in the LINECALLINFO structure to indicate, in a user-friendly way, which application originated, or originally accepted or answered the call. This information can be useful for call logging purposes. If lpszAppName is NULL, the application's file name is used instead.

lpdwNumDevs

Specifies a pointer to a DWORD-sized location. Upon successful completion of this request, this location is filled with the number of line devices available to the application.

If LINEERR_REINIT is returned and TAPI reinitialization has been requested, for example as a result of adding or removing a Telephony service provider, then lineInitialize requests are rejected with this error until the last application shuts down its usage of the API (using lineShutdown), at which time the new configuration becomes effective and applications are once again permitted to call lineInitialize.

If the LINEERR_INVALPARAM error value is returned, the specified hInstance parameter is invalid.

The application can refer to individual line devices by using line device IDs that range from zero to dwNumDevs minus one. An application should not assume that these line devices are capable of anything beyond what is specified by the Basic Telephony subset without first querying their device capabilities by lineGetDevCaps and lineGetAddressCaps.

Applications should not invoke lineInitialize without subsequently opening a line (at least for monitoring). If the application is not monitoring and not using any devices, it should call lineShutdown so that memory resources allocated by TAPI.DLL can be released if unneeded, and TAPI.DLL itself can be unloaded from memory while not needed.

Another reason for performing a lineShutdown is that if a user changes the device configuration (adds or removes a line or phone), there is no way for TAPI to notify an application that has a line or phone handle open at the time. Once a reconfiguration has taken place, causing a LINEDEVSTATE_REINIT message to be sent, no applications can open a device until all applications have performed a lineShutdown.

If any service provider fails to initialize properly, this function fails and returns the error indicated by the service provider.


lineCallbackFunc

[New - Windows 95]

VOID FAR PASCAL lineCallbackFunc(DWORD hDevice, DWORD dwMsg,
    DWORD dwCallbackInstance, DWORD dwParam1, DWORD dwParam2,
    DWORD dwParam3)

The lineCallbackFunc function is a placeholder for the application-supplied function name.

hDevice

Specified a handle to either a line device or a call associated with the callback. The nature of this handle (line handle or call handle) can be determined by the context provided by dwMsg. Applications must use the DWORD type for this parameter since using the HANDLE type may generate an error.

dwMsg

Specifies a line or call device message.

dwCallbackInstance

Specifies callback instance data passed back to the application in the callback. This DWORD is not interpreted by TAPI.

dwParam1

Specifies a parameter for the message.

dwParam2

Specifies a parameter for the message.

dwParam3

Specifies a parameter for the message.

For information about parameters values passed to this function, see Chapter 11, "Line Device Messages."

All callbacks occur in the application's context. The callback function must reside in a dynamic link library (DLL) or application module.


lineMakeCall

[New - Windows 95]

LONG lineMakeCall(HLINE hLine, LPHCALL lphCall, LPCSTR lpszDestAddress,
    DWORD dwCountryCode, LPLINECALLPARAMS const lpCallParams)

Places a call on the specified line to the specified destination address. Optionally, call parameters can be specified if anything but default call setup parameters are requested.

•	Returns a positive request ID if the function will be completed asynchronously, or a negative error number if an error has occurred. The dwParam2 parameter of the corresponding LINE_REPLY callback message is zero if the function is successful or it is a negative error number if an error has occurred. Possible return values are:

LINEERR_ADDRESSBLOCKED	LINEERR_INVALLINEHANDLE
LINEERR_BEARERMODEUNAVAIL	LINEERR_INVALLINESTATE
LINEERR_CALLUNAVAIL	LINEERR_INVALMEDIAMODE
LINEERR_DIALBILLING	LINEERR_INVALPARAM
LINEERR_DIALDIALTONE	LINEERR_INVALPOINTER
LINEERR_DIALPROMPT	LINEERR_INVALRATE
LINEERR_DIALQUIET	LINEERR_NOMEM
LINEERR_INUSE	LINEERR_OPERATIONFAILED
LINEERR_INVALADDRESS	LINEERR_OPERATIONUNAVAIL
LINEERR_INVALADDRESSID	LINEERR_RATEUNAVAIL
LINEERR_INVALADDRESSMODE	LINEERR_RESOURCEUNAVAIL
LINEERR_INVALBEARERMODE	LINEERR_STRUCTURETOOSMALL
LINEERR_INVALCALLPARAMS	LINEERR_UNINITIALIZED
LINEERR_INVALCOUNTRYCODE	LINEERR_USERUSERINFOTOOBIG
hLine

Specifies a handle to the open line device on which a call is to be originated.

lphCall

Specifies a pointer to an HCALL handle. The handle is only valid after the LINE_REPLY message is received by the application indicating that the lineMakeCall function successfully completed. Use this handle to identify the call when invoking other telephony operations on the call. The application will initially be the sole owner of this call. This handle is void if the function returns an error (synchronously or asynchronously by the reply message).

lpszDestAddress

Specifies a pointer to the destination address. This follows the standard dialable number format. This pointer can be NULL for non-dialed addresses (as with a hot phone) or when all dialing will be performed using lineDial. In the latter case, lineMakeCall allocates an available call appearance that would typically remain in the dialtone state until dialing begins. Service providers that have inverse multiplexing capabilities may allow an application to specify multiple addresses at once.

dwCountryCode

Specifies the country code of the called party. If a value of zero is specified, a default is used by the implementation.

lpCallParams

Specifies a pointer to a LINECALLPARAMS structure. This structure allows the application to specify how it wants the call to be set up. If NULL is specified, a default 3.1kHz voice call is established and an arbitrary origination address on the line is selected. This structure allows the application to select elements such as the call's bearer mode, data rate, expected media mode, origination address, blocking of caller ID information, and dialing parameters.

If LINEERR_INVALLINESTATE is returned, the line is currently not in a state in which this operation can be performed. A list of currently valid operations can be found in the dwLineFeatures field (of the type LINEFEATURE_) in the LINEDEVSTATUS structure. Calling lineGetLineDevStatus updates the information in LINEDEVSTATUS. If LINEERR_DIALBILLING, LINEERR_DIALQUIET, LINEERR_DIALDIALTONE, or LINEERR_DIALPROMPT is returned, none of the actions otherwise performed by lineMakeCall have occured; for example, none of the dialable address prior to the offending character has been dialed, no hookswitch state has changed, and so on.

After dialing has completed, several LINE_CALLSTATE messages are usually sent to the application to notify it about the progress of the call. No generally valid sequence of call-state transitions is specified, as no single fixed sequence of transitions can be guaranteed in practice. A typical sequence may cause a call to transition from dialtone, dialing, proceeding, ringback, to connected. With non-dialed lines, the call may typically transition directly to connected state.

An application has the option to specify an originating address on the specified line device. A service provider that models all stations on a switch as addresses on a single line device allows the application to originate calls from any of these stations using lineMakeCall.

The call parameters allow the application to make non-voice calls or request special call setup options that are not available by default.

An application can partially dial using lineMakeCall and continue dialing using lineDial. To abandon a call attempt, use lineDrop.

After lineMakeCall returns a SUCCESS reply callback message to the application, a LINE_CALLSTATE message is sent to the application to indicate the current state of the call. This state will not necessarily be LINECALLSTATE_DIALTONE.


lineMonitorDigits

[New - Windows 95]

LONG lineMonitorDigits(HCALL hCall, DWORD dwDigitModes)

Enables and disables the unbuffered detection of digits received on the call. Each time a digit of the specified digit mode(s) is detected, a message is sent to the application indicating which digit has been detected.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALCALLHANDLE	LINEERR_OPERATIONUNAVAIL
LINEERR_INVALCALLSTATE	LINEERR_OPERATIONFAILED
LINEERR_INVALDIGITMODE	LINEERR_RESOURCEUNAVAIL
LINEERR_NOMEM	LINEERR_UNINITIALIZED
hCall

Specifies a handle to the call on which digits are to be detected. Call state of hCall can be any state except idle or disconnected.

dwDigitModes

Specifies the digit mode(s) that are to be monitored. If dwDigitModes is zero, digit monitoring is cancelled. This parameter can have multiple flags set, and uses the following LINEDIGITMODE_ constants:

LINEDIGITMODE_PULSE

Detect digits as audible clicks that are the result of rotary pulse sequences. Valid digits for pulse are '0' through '9'.

LINEDIGITMODE_DTMF

Detect digits as DTMF tones. Valid digits for DTMF are '0' through '9', 'A', 'B', 'C', 'D', '*', and '#'.

LINEDIGITMODE_DTMFEND

Detect and provide application notification of DTMF down edges. Valid digits for DTMF are '0' through '9', 'A', 'B', 'C', 'D', '*', and '#'.

This function is considered successful if digit monitoring has been correctly initiated; not when digit monitoring has terminated. Digit monitoring remains in effect until it is explicitly disabled by calling lineMonitorDigits with dwDigitModes set to zero, until the call transitions to idle, or when the application deallocates its call handle for the call. Although this function can be invoked in any call state, digits are usually detected only while the call is in the connected state.

Each time a digit is detected, a LINE_MONITORDIGITS message is sent to the application passing the detected digit as a parameter.

An application can use lineMonitorDigits to enable or disable unbuffered digit detection. It can use lineGatherDigits for buffered digit detection. After buffered digit gathering is complete, a LINE_GATHERDIGITS message is sent to the application. Both buffered and unbuffered digit detection can be enabled on the same call simultaneously.

Monitoring of digits on a conference call applies only to the hConfCall, not to the individual participating calls.


lineMonitorMedia

[New - Windows 95]

LONG lineMonitorMedia(HCALL hCall, DWORD dwMediaModes)

Enables and disables the detection of media modes on the specified call. When a media mode is detected, a message is sent to the application.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALCALLHANDLE	LINEERR_OPERATIONUNAVAIL
LINEERR_INVALCALLSTATE	LINEERR_OPERATIONFAILED
LINEERR_INVALMEDIAMODE	LINEERR_RESOURCEUNAVAIL
LINEERR_NOMEM	LINEERR_UNINITIALIZED
hCall

Specifies a handle to the call. Call state of hCall can be any state except idle.

dwMediaModes

Specifies the media modes to be monitored. A value of zero for the dwMediaModes parameter cancels all media mode detection. This parameter can have multiple flags set. This parameter uses the following LINEMEDIAMODE_ constants:

LINEMEDIAMODE_INTERACTIVEVOICE

The application wants to handle calls of the interactive voice media type (it manages live voice calls).

LINEMEDIAMODE_AUTOMATEDVOICE

Voice energy is present on the call and the voice is locally handled by an automated application.

LINEMEDIAMODE_DATAMODEM

The application wants to handle calls with the data modem media mode.

LINEMEDIAMODE_G3FAX

The application wants to handle calls of the group 3 fax media type.

LINEMEDIAMODE_TDD

The application wants to handle calls with the TDD (Telephony Devices for the Deaf) media mode.

LINEMEDIAMODE_G4FAX

The application wants to handle calls of the group 4 fax media type.

LINEMEDIAMODE_DIGITALDATA

The application wants to handle calls of the digital data media type

LINEMEDIAMODE_TELETEX

The application wants to handle calls with the teletex media mode.

LINEMEDIAMODE_VIDEOTEX

The application wants to handle calls with the videotex media mode.

LINEMEDIAMODE_TELEX

The application wants to handle calls with the telex media mode.

LINEMEDIAMODE_MIXED

The application wants to handle calls with the ISDN mixed media mode.

LINEMEDIAMODE_ADSI

The application wants to handle calls with the ADSI (Analog Display Services Interface) media mode.

LINEMEDIAMODE_VOICEVIEW

The media mode of the call is VoiceView.

The media modes specified with lineOpen relate only to enabling the detection of these media modes by the service provider for the purpose of handing off new incoming calls to the proper application. They do not impact any of the media-mode notification messages that are expected because of a previous invocation of lineMonitorMedia.

This function is considered successful if media-mode monitoring has been correctly initiated, not when media mode monitoring has terminated. Media monitoring for a given media mode remains in effect until it is explicitly disabled by calling lineMonitorMedia with a dwMediaModes parameter set to zero, until the call transitions to idle, or when the application deallocates its call handle for the call. The lineMonitorMedia function is primarily an event reporting mechanism. The media mode of call, as indicated in LINECALLINFO, is not affected by the service provider's detection of the media mode. Only the controlling application can change a call's media mode.

Default media monitoring performed by the service provider corresponds to the union of all media modes specified on lineOpen.

Although this function can be invoked in any call state, a call's media mode can typically only be detected while the call is certain call states. These states may be device specific. For example, in ISDN, a message may indicate the media mode of the media stream before the media stream exists. Similarly, distinctive ringing or the called ID information about the call can be used to identify the media mode of a call. Otherwise, the call may have to be answered (call in the connected state) to allow a service provider to determine the call's media mode by filtering the media stream. Since filtering a call's media stream implies a computational overhead, applications should disable media monitoring when not required. By default, media monitoring is enabled for newly inbound calls, since a call's media mode selects the application that should handle the call.

An outbound application that deals with voice media modes may want to monitor the call for silence (a tone) to distinguish who or what is at the called end of a call. For example, a person at home may answer calls with just a short "hello." A person in the office may provide a longer greeting, indicating name and company name. An answering machine may typically have an even longer greeting.

Because media-mode detection enabled by lineMonitorMedia is implemented as a read-only operation of the call's media stream, it is not disruptive.

Monitoring of media on a conference call applies only to the hConfCall, not to the individual participating calls


lineMonitorTones

[New - Windows 95]

LONG lineMonitorTones(HCALL hCall, LPLINEMONITORTONE	const lpToneList,
    DWORD dwNumEntries)

Enables and disables the detection of inband tones on the call. Each time a specified tone is detected, a message is sent to the application.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALCALLHANDLE	LINEERR_OPERATIONFAILED
LINEERR_INVALCALLSTATE	LINEERR_RESOURCEUNAVAIL
LINEERR_INVALTONE	LINEERR_UNINITIALIZED
LINEERR_NOMEM	LINEERR_INVALPOINTER
LINEERR_OPERATIONUNAVAIL
hCall

Specifies a handle to the call on whose voice channel tones are to be monitored.  Call state of hCall can be any state except idle.

lpToneList

Specifies a list of tones to be monitored, of type LINEMONITORTONE. Each tone in this list has an application-defined tag field that is used to identify individual tones in the list report a tone detection. Tone monitoring in progress is canceled or changed by calling this operation with either NULL for lpToneList or with another tone list.

dwNumEntries

Specifies the number of entries in lpToneList. This parameter is ignored if lpToneList is NULL.

This function is successful if tone monitoring has been correctly initiated, not when tone monitoring has terminated. Tone monitoring will remain in effect until it is explicitly disabled by calling lineMonitorTones with another tone list (or NULL), until the call transitions to idle, or when the application deallocates its call handle for the call.

Although this function can be invoked in any call state, tones can typically only be detected while the call is in the connected state. Tone detection typically requires computational resources. Depending on the service provider and other activities that compete for such resources, the number of tones that can be detected may vary over time. Also, an equivalent amount of resources may be consumed for monitoring a single triple frequency tone versus three single frequency tones. If resources are overcommitted, the LINEERR_RESOURCEUNAVAIL error is returned.

Note that lineMonitorTones is also used to detect silence. Silence is specified as a tone with all zero frequencies.

Monitoring of tones on a conference call applies only to the hConfCall, not to the individual participating calls

If the LINEERR_INVALPOINTER error value is returned, the specified lpToneList parameter is invalid or the value specified by the dwNumEntries parameter is too large.


lineNegotiateAPIVersion

[New - Windows 95]

LONG lineNegotiateAPIVersion(HLINEAPP hLineApp, DWORD dwDeviceID,
    DWORD dwAPILowVersion, DWORD dwAPIHighVersion,
    LPDWORD lpdwAPIVersion, LPLINEEXTENSIONID lpExtensionID)

Allows an application to negotiate an API version to use.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_BADDEVICEID	LINEERR_NODRIVER
LINEERR_INCOMPATIBLEAPIVERSION	LINEERR_OPERATIONFAILED
LINEERR_INVALAPPHANDLE	LINEERR_RESOURCEUNAVAIL
LINEERR_INVALPOINTER	LINEERR_UNINITIALIZED
LINEERR_NOMEM	LINEERR_OPERATIONUNAVAIL
LINEERR_NODEVICE
hLineApp

Specifies the handle to the application's registration with TAPI.

dwDeviceID

Specifies the line device to be queried.

dwAPILowVersion

Specifies the least recent API version the application is compliant with. The high-order word is the major version number; the low-order word is the minor version number.

dwAPIHighVersion

Specifies the most recent API version the application is compliant with. The high-order word is the major version number; the low-order word is the minor version number.

lpdwAPIVersion

Specifies a pointer to a DWORD-sized location that contains the API version number that was negotiated. If negotiation is successful, this number will be in the range between dwAPILowVersion and dwAPIHighVersion.

lpExtensionID

Specifies a pointer to a structure of type LINEEXTENSIONID. If the service provider for the specified dwDeviceID supports provider-specific extensions, then, upon a successful negotiation, this structure is filled with the extension ID of these extensions. This structure contains all zeros if the line provides no extensions. An application can ignore the returned parameter if it does not use extensions.

Use lineInitialize to determine the number of line devices present in the system. The device ID specified by dwDeviceID varies from zero to one less than the number of line devices present.

The lineNegotiateAPIVersion function is used to negotiate the API version number to use. It also retrieves the extension ID supported by the line device, and it returns zeros if no extensions are supported. If the application wants to use the extensions defined by the returned extension ID, it must call lineNegotiateExtVersion to negotiate the extension version to use.

The API version number negotiated is that under which TAPI can operate. If version ranges do not overlap, the application and API or service provider versions are incompatible and an error is returned.


lineNegotiateExtVersion

[New - Windows 95]

LONG lineNegotiateExtVersion(HLINEAPP hLineApp, DWORD dwDeviceID,
    DWORD dwAPIVersion, DWORD dwExtLowVersion, DWORD dwExtHighVersion,
    LPDWORD lpdwExtVersion)

Allows an application to negotiate an extension version to use with the specified line device. This operation need not be called if the application does not support extensions.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_BADDEVICEID	LINEERR_NOMEM
LINEERR_INCOMPATIBLEAPIVERSION	LINEERR_NODRIVER
LINEERR_INCOMPATIBLEEXTVERSION	LINEERR_OPERATIONFAILED
LINEERR_INVALAPPHANDLE	LINEERR_RESOURCEUNAVAIL
LINEERR_INVALPOINTER	LINEERR_UNINITIALIZED
LINEERR_NODEVICE	LINEERR_OPERATIONUNAVAIL
hLineApp

Specifies the handle to the application's registration with TAPI.

dwDeviceID

Specifies the line device to be queried.

dwAPIVersion

Specifies the API version number that was negotiated for the specified line device using lineNegotiateAPIVersion.

dwExtLowVersion

Specifies the least recent extension version of the extension ID returned by lineNegotiateAPIVersion that the application is compliant with. The high-order word is the major version number; the low-order word is the minor version number.

dwExtHighVersion

Specifies the most recent extension version of the extension ID returned by lineNegotiateAPIVersion that the application is compliant with. The high-order word is the major version number; the low-order word is the minor version number.

lpdwExtVersion

Specifies a pointer to a DWORD-sized location that contains the extension version number that was negotiated. If negotiation is successful, this number will be in the range between dwExtLowVersion and dwExtHighVersion.

Use lineInitialize to determine the number of line devices present in the system. The device ID specified by dwDeviceID varies from zero to one less than the number of line devices present.

lineNegotiateAPIVersion is used to negotiate the API version number to use. It also retrieves the extension ID supported by the line device, which is zeros if no extensions are provided. Version numbers should be incremented by one for each release. Leaving gaps in release version numbering may cause unexpected results.

If the application wants to use the extensions defined by the returned extension ID, it must call lineNegotiateExtVersion to negotiate the extension version to use.

The extension version number negotiated is that under which the application and service provider must both operate. If version ranges do not overlap, the application and service provider versions are incompatible and an error is returned.


lineOpen

[New - Windows 95]

LONG lineOpen(HLINEAPP hLineApp, DWORD dwDeviceID, LPHLINE lphLine,
    DWORD dwAPIVersion, DWORD dwExtVersion, DWORD dwCallbackInstance,
    DWORD dwPrivileges, DWORD dwMediaModes,
    LPLINECALLPARAMS const lpCallParams)

Opens the line device specified by its device ID and returns a line handle for the corresponding opened line device. This line handle is used in subsequent operations on the line device.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_ALLOCATED	LINEERR_LINEMAPPERFAILED
LINEERR_BADDEVICEID	LINEERR_NODRIVER
LINEERR_INCOMPATIBLEAPIVERSION	LINEERR_NOMEM
LINEERR_INCOMPATIBLEEXTVERSION	LINEERR_OPERATIONFAILED
LINEERR_INVALAPPHANDLE	LINEERR_RESOURCEUNAVAIL
LINEERR_INVALMEDIAMODE	LINEERR_STRUCTURETOOSMALL
LINEERR_INVALPOINTER	LINEERR_UNINITIALIZED
LINEERR_INVALPRIVSELECT	LINEERR_REINIT
LINEERR_NODEVICE	LINEERR_OPERATIONUNAVAIL
hLineApp

Specifies a handle to the application's registration with TAPI.

dwDeviceID

Identifies the line device to be opened. It can either be a valid device ID or the value:

LINEMAPPER

This value is used to open a line device in the system that supports the properties specified in lpCallParams. The application can use lineGetID to determine the ID of the line device that was opened.

lphLine

Specifies a pointer to an HLINE handle, which is then loaded with the handle representing the opened line device. Use this handle to identify the device when invoking other functions on the open line device.

dwAPIVersion

Specifies the API version number under which the application and Telephony API have agreed to operate. This number is obtained with lineNegotiateAPIVersion.

dwExtVersion

Specifies the extension version number under which the application and the service provider agree to operate. This number is zero if the application does not use any extensions. This number is obtained with lineNegotiateExtVersion.

dwCallbackInstance

Specifies user-instance data passed back to the application's callback. This parameter is not interpreted by the Telephony API.

dwPrivileges

Specifies the privilege the application wants for the calls it is notified for. This parameter can have multiple flags set, and it uses the following LINECALLPRIVILEGE_ constants:

LINECALLPRIVILEGE_NONE

The application wants to make only outbound calls.

LINECALLPRIVILEGE_MONITOR

The application only wants to monitor inbound and outbound calls.

LINECALLPRIVILEGE_OWNER

The application wants to own inbound calls of the types specified in dwMediaModes.

LINECALLPRIVILEGE_MONITOR + LINECALLPRIVILEGE_OWNER

The application wants to own inbound calls of the types specified in dwMediaModes, but if it cannot be an owner of a call, it wants to be a monitor.

Other flag combinations return the LINEERR_INVALPRIVSELECT error.

dwMediaModes

Specifies the media mode(s) of interest to the application. The dwMediaModes parameter is used to register the application as a potential target for inbound call and call handoff for the specified media mode. This parameter is meaningful only if the bit LINECALLPRIVILEGE_OWNER in dwPrivileges is set (and ignored if it is not). This parameter uses the following LINEMEDIAMODE_ constants:

LINEMEDIAMODE_UNKNOWN

The application wants to handle calls of unknown media type (unclassified calls).

LINEMEDIAMODE_INTERACTIVEVOICE

The application wants to handle calls of the interactive voice media type. That is, it manages voice calls with the human user on this end of the call.

LINEMEDIAMODE_AUTOMATEDVOICE

Voice energy is present on the call. The voice is locally handled by an automated application.

LINEMEDIAMODE_DATAMODEM

The application wants to handle calls with the data-modem media mode.

LINEMEDIAMODE_G3FAX

The application wants to handle calls of the group 3 fax media type.

LINEMEDIAMODE_TDD

The application wants to handle calls with the TDD (Telephony Devices for the Deaf) media mode.

LINEMEDIAMODE_G4FAX

The application wants to handle calls of the group 4 fax media type.

LINEMEDIAMODE_DIGITALDATA

The application wants to handle calls of the digital-data media type.

LINEMEDIAMODE_TELETEX

The application wants to handle calls with the teletex media mode.

LINEMEDIAMODE_VIDEOTEX

The application wants to handle calls with the videotex media mode.

LINEMEDIAMODE_TELEX

The application wants to handle calls with the telex media mode.

LINEMEDIAMODE_MIXED

The application wants to handle calls with the ISDN mixed media mode.

LINEMEDIAMODE_ADSI

The application wants to handle calls with the ADSI (Analog Display Services Interface) media mode.

LINEMEDIAMODE_VOICEVIEW

The media mode of the call is VoiceView.

lpCallParams

Specifies a pointer to a structure of type LINECALLPARAMS. This pointer is only used if LINEMAPPER is used; otherwise lpCallParams is ignored. It describes the call parameter that the line device should be able to provide.

If LINEERR_ALLOCATED is returned, the line cannot be opened due to a "persistent" condition, such as that of a serial port being exclusively opened by another process. If LINEERR_RESOURCEUNAVAIL is returned, the line cannot be opened due to a dynamic resource overcommitment such as in DSP processor cycles or memory. This overcommitment may be transitory, caused by monitoring of media mode or tones, and changes in these activities by other applications may make it possible to reopen the line within a short time period. If LINEERR_REINIT is returned and TAPI reinitialization has been requested, for example as a result of adding or removing a Telephony service provider, then lineOpen requests are rejected with this error until the last application shuts down its usage of the API (using lineShutdown), at which time the new configuration becomes effective and applications are once again permitted to call lineInitialize.

Opening a line always entitles the application to make calls on any address available on the line. The ability of the application to deal with inbound calls or to be the target of call handoffs on the line is determined by the dwMediaModes parameter. The lineOpen function registers the application as having an interest in monitoring calls or receiving ownership of calls that are of the specified media modes. If the application just wants to monitor calls, then it can specify LINECALLPRIVILEGE_MONITOR. If the application just wants to make outbound calls, it can specify LINECALLPRIVILEGE_NONE. If the application is willing to control unclassified calls (calls of unknown media mode), it can specify LINECALLPRIVILEGE_OWNER and LINEMEDIAMODE_UNKNOWN. Otherwise, the application should specify the media mode it is interested in handling.

The media modes specified with lineOpen add to the default value for the provider's media mode monitoring for initial inbound call type determination. The lineMonitorMedia function modifies the mask that controls LINE_MONITORMEDIA messages. If a line device is opened with owner privilege and an extension media mode is not registered in TELEPHON.INI, then the error LINEERR_INVALMEDIAMODE is returned.

An application that has successfully opened a line device can always initiate calls using lineMakeCall, lineUnpark, linePickup, lineSetupConference (with a NULL hCall), as well as use lineForward (assuming that doing so is allowed by the device capabilities, line state, and so on).

Note that a single application may specify multiple flags simultaneously to handle multiple media modes. Conflicts may arise if multiple applications open the same line device for the same media mode. These conflicts are resolved by a priority scheme in which the user assigns relative priorities to the applications. Only the highest priority application for a given media mode will ever receive ownership (unsolicited) of a call of that media mode. Ownership can be received when an inbound call first arrives or when a call is handed off.

Note that any application (including any lower priority application) can always acquire ownership with lineGetNewCalls or lineGetConfRelatedCalls. If an application opens a line for monitoring at a time that calls exist on the line, LINE_CALLSTATE messages for those existing calls are not automatically generated to the new monitoring application. The application can query the number of current calls on the line to determine how many calls exist, and, if it wants, it can call lineGetNewCalls to obtain handles to these calls.

An application that handles automated voice should also select the interactive voice open mode and be assigned the lowest priority for interactive voice. The reason for this is that service providers will report all voice media modes as interactive voice. If media mode determination is not performed by the application for the UNKNOWN media type, and no interactive voice application has opened the line device, voice calls would be unable to reach the automated voice application, but be dropped instead.

The same application, or different instantiations of the same application, may open the same line multiple times with the same or different parameters.

When an application opens a line device it must specify the negotiated API version and, if it wants to use the line's extensions, it should specify the line's device-specific extension version. These version numbers should have been obtained with lineNegotiateAPIVersion and lineNegotiateExtVersion. Version numbering allows the mixing and matching of different application versions with different API versions and service provider versions.

LINEMAPPER allows an application to select a line indirectly—by means of the services it wants from it. When opening a line device using LINEMAPPER, the following is true: All fields from beginning of the LINECALLPARAMS data structure through dwAddressMode are relevant. If dwAddressMode is LINEADDRESSMODE_ADDRESSID it means that any address on the line is acceptable, otherwise if dwAddressMode is LINEADDRESSMODE_DIALABLEADDR, indicating that a specific originating address (phone number) is searched for, or if it is a provider-specific extension, then dwOrigAddressSize/Offset and the portion of the variable part they refer to are also relevant. If dwAddressMode is a provider-specific extension additional information may be contained in the dwDeviceSpecific variably sized field.


linePark

[New - Windows 95]

LONG linePark(HCALL hCall, DWORD dwParkMode, LPCSTR lpszDirAddress,
    LPVARSTRING lpNonDirAddress)

Parks the specified call according to the specified park mode.

•	Returns a positive request ID if the function will be completed asynchronously, or a negative error number if an error has occurred. The dwParam2 parameter of the corresponding LINE_REPLY callback message is zero if the function is successful or it is a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALADDRESS	LINEERR_NOTOWNER
LINEERR_INVALCALLHANDLE	LINEERR_OPERATIONUNAVAIL
LINEERR_INVALCALLSTATE	LINEERR_OPERATIONFAILED
LINEERR_INVALPARKMODE	LINEERR_RESOURCEUNAVAIL
LINEERR_INVALPOINTER	LINEERR_STRUCTURETOOSMALL
LINEERR_NOMEM	LINEERR_UNINITIALIZED
hCall

Specifies a handle to the call to be parked. The application must be an owner of the call. Call state of hCall must be connected.

dwParkMode

Specifies the park mode with which the call is to be parked. This parameter can have only a single flag set, and it uses the following LINEPARKMODE_ constants:

LINEPARKMODE_DIRECTED

The application specifies at which address the call is to be parked in lpszDirAddress.

LINEPARKMODE_NONDIRECTED

This operation reports to the application where the call has been parked in lpNonDirAddress.

lpszDirAddress

Specifies a pointer to a NULL-terminated string that indicates the address where the call is to be parked when using directed park. The address is in dialable number format. This parameter is ignored for nondirected park.

lpNonDirAddress

Specifies a pointer to a structure of type VARSTRING. For nondirected park, the address where the call is parked is returned in this structure. This parameter is ignored for directed park. Within the VARSTRING structure, dwStringFormat must be set to STRINGFORMAT_ASCII (an ASCII string buffer containing a NULL-terminated string), and the terminating NULL must be accounted for in the dwStringSize. Prior to calling linePark, the application should set the dwTotalSize field of this structure to indicate the amount of memory available to TAPI.DLL for returning information.

With directed park, the application determines the address at which it wants to park the call. With nondirected park, the switch determines the address and provides this to the application. In either case, a parked call can be unparked by specifying this address.

The parked call typically enters the idle state after it has been successfully parked and the application should then deallocate its handle to the call. If the application performs a lineUnpark on the parked call, a new call handle will be created for the unparked call even if the application has not deallocated its old call handle.

Some switches may remind the user after a call has been parked for some long amount of time. The application will see an offering call with a call reason set to reminder.

On a nondirected park, if the dwTotalSize member in the VARSTRING structure does not specify a sufficient amount of memory to receive the park address, the corresponding reply message returns a LINEERR_STRUCTURETOOSMALL error value. In such cases, there is no way to retrieve the complete park address.


linePickup

[New - Windows 95]

LONG linePickup(HLINE hLine, DWORD dwAddressID, LPHCALL lphCall,
    LPCSTR lpszDestAddress, LPCSTR lpszGroupID)

Picks up a call alerting at the specified destination address and returns a call handle for the picked-up call. If invoked with NULL for the lpszDestAddress parameter, a group pickup is performed. If required by the device, lpszGroupID specifies the group ID to which the alerting station belongs.

•	Returns a positive request ID if the function will be completed asynchronously, or a negative error number if an error has occurred. The dwParam2 parameter of the corresponding LINE_REPLY callback message is zero if the function is successful or it is a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALADDRESS	LINEERR_NOMEM
LINEERR_INVALADDRESSID	LINEERR_OPERATIONUNAVAIL
LINEERR_INVALGROUPID	LINEERR_OPERATIONFAILED
LINEERR_INVALLINEHANDLE	LINEERR_RESOURCEUNAVAIL
LINEERR_INVALPOINTER	LINEERR_UNINITIALIZED
hLine

Specifies a handle to the open line device on which a call is to be picked up.

dwAddressID

Specifies the address on hLine at which the pickup is to be originated.

lphCall

Specifies a pointer to a memory location where the handle to the picked up call will be returned. The application will be the initial sole owner of the call.

lpszDestAddress

Specifies a pointer to a NULL-terminated character buffer that contains the address whose call is to be picked up. The address is in standard dialable address format.

lpszGroupID

Specifies a pointer to a NULL-terminated character buffer containing the group ID to which the alerting station belongs. This parameter is required on some switches to pick up calls outside of the current pickup group.

Note that lpszGroupID can be specified by itself with a NULL pointer for lpszDestAddress. Alternatively, lpszGroupID can be specified in addition to lpszDestAddress, if required by the device.

When a call has been picked up successfully, the application is notified by the LINE_CALLSTATE message about call state changes. The LINECALLINFO structure supplies information about the call that was picked up. It will list the reason for the call as pickup. This structure is available using lineGetCallInfo.

If LINEADDRCAPFLAGS_PICKUPCALLWAIT is TRUE, linePickup can be used to pick up a call for which the user has audibly detected the call-waiting signal but for which the provider is unable to perform the detection. This gives the user a mechanism to "answer" a waiting call even though the service provider was unable to detect the call-waiting signal. Both lpszDestAddress and lpszGroupID pointer parameters must be NULL to pick up a call-waiting call. The linePickup function will create a new call handle for the waiting call and pass that handle to the user. dwAddressID will most often be zero (particularly in single-line residential cases).

Once linePickup has been used to pick up the second call, lineSwapHold can be used to toggle between them. lineDrop can be used to drop one (and toggle to the other), and so forth. If the user wants to drop the current call and pick up the second call, they should call lineDrop when they get the call-waiting beep, wait for the second call to ring, and then call lineAnswer on the new call handle. The LINEADDRFEATURE_PICKUP flag in the dwAddressFeatures field in LINEADDRESSSTATUS indicates when pickup is actually possible.


linePrepareAddToConference

[New - Windows 95]

LONG linePrepareAddToConference(HCALL hConfCall, LPHCALL lphConsultCall,
    LPLINECALLPARAMS const lpCallParams)

Prepares an existing conference call for the addition of another party.

•	Returns a positive request ID if the function will be completed asynchronously, or a negative error number if an error has occurred. The dwParam2 parameter of the corresponding LINE_REPLY callback message is zero if the function is successful or it is a negative error number if an error has occurred. Possible return values are:

LINEERR_BEARERMODEUNAVAIL	LINEERR_INVALPOINTER
LINEERR_CALLUNAVAIL	LINEERR_INVALRATE
LINEERR_CONFERENCEFULL	LINEERR_NOMEM
LINEERR_INUSE	LINEERR_NOTOWNER
LINEERR_INVALADDRESSMODE	LINEERR_OPERATIONUNAVAIL
LINEERR_INVALBEARERMODE	LINEERR_OPERATIONFAILED
LINEERR_INVALCALLPARAMS	LINEERR_RATEUNAVAIL
LINEERR_INVALCALLSTATE	LINEERR_RESOURCEUNAVAIL
LINEERR_INVALCONFCALLHANDLE	LINEERR_STRUCTURETOOSMALL
LINEERR_INVALLINESTATE	LINEERR_USERUSERINFOTOOBIG
LINEERR_INVALMEDIAMODE	LINEERR_UNINITIALIZED
hConfCall

Specifies a handle to a conference call. The application must be an owner of this call. Call state of hConfCall must be connected.

lphConsultCall

Specifies a pointer to an HCALL handle. This location is then loaded with a handle identifying the consultation call to be added. Initially, the application will be the sole owner of this call.

lpCallParams

Specifies a pointer to call parameters to be used when establishing the consultation call. This parameter may be set to NULL if no special call setup parameters are desired.

If LINEERR_INVALLINESTATE is returned, the line is currently not in a state in which this operation can be performed. A list of currently valid operations can be found in the dwLineFeatures field (of the type LINEFEATURE_) in the LINEDEVSTATUS structure. (Calling lineGetLineDevStatus updates the information in LINEDEVSTATUS.)

A conference call handle can be obtained with lineSetupConference or with lineCompleteTransfer that is resolved as a three-way conference call. The function linePrepareAddToConference typically places the existing conference call in the onHoldPendingConference state and creates a consultation call that can be added later to the existing conference call with lineAddToConference.

The consultation call can be canceled using lineDrop. It may also be possible for an application to swap between the consultation call and the held conference call with lineSwapHold.


lineRedirect

[New - Windows 95]

LONG lineRedirect(HCALL hCall, LPCSTR lpszDestAddress,
    DWORD dwCountryCode)

Redirects the specified offering call to the specified destination address.

•	Returns a positive request ID if the function will be completed asynchronously, or a negative error number if an error has occurred. The dwParam2 parameter of the corresponding LINE_REPLY callback message is zero if the function is successful or it is a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALADDRESS	LINEERR_NOTOWNER
LINEERR_INVALCALLHANDLE	LINEERR_OPERATIONUNAVAIL
LINEERR_INVALCALLSTATE	LINEERR_OPERATIONFAILED
LINEERR_INVALCOUNTRYCODE	LINEERR_RESOURCEUNAVAIL
LINEERR_INVALPOINTER	LINEERR_UNINITIALIZED
LINEERR_NOMEM
hCall

Specifies a handle to the call to be redirected. The application must be an owner of the call. Call state of hCall must be offering.

lpszDestAddress

Specifies a pointer to the destination address. This follows the standard dialable number format.

dwCountryCode

Specifies the country code of the party the call is redirected to. If a value of zero is specified, a default is used by the implementation.

Call redirection allows an application to deflect an offering call to another address without first answering the call. Call redirect differs from call forwarding in that call forwarding is performed by the switch without the involvement of the application; redirection can be done on a call-by-call basis by the application, for example, driven by caller ID information. It differs from call transfer in that transferring a call requires the call first be answered.

After a call has been successfully redirected, the call typically transitions to idle.

Besides redirecting an incoming call, an application may have the option to accept the call using lineAccept, reject the call using lineDrop, or answer the call using lineAnswer. The availability of these operations is dependent on device capabilities.


lineRegisterRequestRecipient

[New - Windows 95]

LONG lineRegisterRequestRecipient(HLINEAPP hLineApp,
    DWORD dwRegistrationInstance, DWORD dwRequestMode, DWORD bEnable)

Registers the invoking application as a recipient of requests for the specified request mode.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALAPPHANDLE	LINEERR_OPERATIONFAILED
LINEERR_INVALREQUESTMODE	LINEERR_RESOURCEUNAVAIL
LINEERR_NOMEM	LINEERR_UNINITIALIZED
hLineApp

Specifies the application's usage handle for the line portion of TAPI.

dwRegistrationInstance

Specifies an application-specific DWORD that is passed back as a parameter of the LINE_REQUEST message. This message notifies the application that a request is pending. This parameter is ignored if bEnable is set to zero. This parameter is examined by TAPI only for registration, not for deregistration. The dwRegistrationInstance value used while deregistering need not match the dwRegistrationInstance used while registering for a request mode.

dwRequestMode

Specifies the type(s) of request for which the application registers. One or both bits may be set. This parameter uses the following LINEREQUESTMODE_ constants:

LINEREQUESTMODE_MAKECALL

A tapiRequestMakeCall request.

bEnable

If TRUE, the application registers; if FALSE, the application deregisters for the specified request modes.

A telephony-enabled application can request that a call be placed on its behalf by invoking tapiRequestMakeCall. Additionally, other applications can request that information be logged with a given call. tapiRequestMakeCall requests are queued by TAPI.DLL, and the highest priority application that has registered to handle the request is sent a LINE_REQUEST message with an indication of the mode of the request that is pending. This application is typically the user's call-control application.

Next, the call-control application that receives this message invokes lineGetRequest, specifying the request mode and a buffer that is large enough to hold the request.The call-control application then interprets and executes the request.

The recipient application is also automatically deregistered for all requests when it does a lineShutdown.


lineReleaseUserUserInfo

[New - Windows 95]

LONG lineReleaseUserUserInfo (HCALL hCall)

Informs the service provider that the application has processed the user-user information contained in the LINECALLINFO structure, and that subsequently received user-user information can now be written into that structure. The service provider will send a LINE_CALLINFO message indicating LINECALLINFOSTATE_USERUSERINFO when new information is available.

•	Returns a positive request ID if the function will be completed asynchronously or a negative error number if an error has occurred. The dwParam2 parameter of the corresponding LINE_REPLY callback message is zero if the function is successful or it is a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALCALLHANDLE	LINEERR_OPERATIONFAILED
LINEERR_NOMEM	LINEERR_RESOURCEUNAVAIL
LINEERR_NOTOWNER	LINEERR_UNINITIALIZED
LINEERR_OPERATIONUNAVAIL
hCall

Specifies a handle to the call. The application must be an owner of the call. Call state of hCall can be any state.

The lineReleaseUserUserInfo function allows the application to control the flow of incoming user-user information on an ISDN connection. When a new, complete user-user information message is received, the service provider informs the application using a LINE_CALLINFO message (specifying LINECALLINFOSTATE_USERUSERINFO). Any number of applications may examine the information (using lineGetCallInfo), but the application owning the call controls when the information is released so that subsequent information can be reported. The service provider will not overwrite previous user-user information in LINECALLINFO with newer information until after lineReleaseUserUserInfo has been called. It is the responsibility of the service provider to buffer subsequently received user-user information until the previous information is released by the application owning the call.

Although this is a new function which older applications would not be expected to call, for backward compatibility, they should not be prevented from doing so; the function will work the same way for all applications.


lineRemoveFromConference

[New - Windows 95]

LONG lineRemoveFromConference(HCALL hCall)

Removes the specified call from the conference call to which it currently belongs. The remaining calls in the conference call are unaffected.

•	Returns a positive request ID if the function will be completed asynchronously, or a negative error number if an error has occurred. The dwParam2 parameter of the corresponding LINE_REPLY callback message is zero if the function is successful or it is a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALCALLHANDLE	LINEERR_OPERATIONUNAVAIL
LINEERR_INVALCALLSTATE	LINEERR_OPERATIONFAILED
LINEERR_NOMEM	LINEERR_RESOURCEUNAVAIL
LINEERR_NOTOWNER	LINEERR_UNINITIALIZED
hCall

Specifies a handle to the call to be removed from the conference. The application must be an owner of this call. Call state of hCall must be conferenced.

This operation removes a party that currently belongs to a conference call. After the call has been successfully removed, it may be possible to further manipulate it using its handle. The availability of this operation and its result are likely to be limited in many implementations. For example, in many implementations, only the most recently added party may be removed from a conference, and the removed call may be automatically dropped (becomes idle). Consult the line's device capabilities to determine the available effects of removing a call from a conference.

If the removal of a participant from a conference is supported, the participant call, after it is removed from the conference, will enter the call-state listed in the dwRemoveFromConfState field in LINEADDRESSCAPS.


lineRemoveProvider

[New - Windows 95]

LONG lineRemoveProvider (DWORD dwPermanentProviderID, HWND hwndOwner)

Removes an existing Telephony Service Provider from the Telephony system.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_INIFILECORRUPT	LINEERR_NOMEM
LINEERR_INVALPARAM	LINEERR_OPERATIONFAILED
dwPermanentProviderID

Specifies the permanent provider ID of the service provider to be removed.

hwndOwner

Specifies a handle to a window to which the any dialogs which need to be displayed as part of the removal process (e.g., a confirmation dialog by the service provider's TSPI_providerRemove function) would be attached.

If the call to TSPI_providerRemove is successful, and the telephony system is active at the time, TAPI calls TSPI_lineShutdown and/or TSPI_phoneShutdown on the service provider (depending on which device types are active). Any line or phone handles still held by applications on associated devices are forcibly closed with LINE_CLOSE or PHONE_CLOSE messages (it is preferable for service providers themselves to issue these messages as part of TSPI_providerRemove, after verification with the user). The devices previously under the control of that provider are then marked as "unavailable", so that any future attempts by applications to reference them by device ID result in LINEERR_NODRIVER.

Although this is a new function which older applications would not be expected to call, for backward compatibility, they should not be prevented from doing so; the function will work the same way for all applications.


lineSecureCall

[New - Windows 95]

LONG lineSecureCall(HCALL hCall)

Secures the call from any interruptions or interference that may affect the call's media stream.

•	Returns a positive request ID if the function will be completed asynchronously, or a negative error number if an error has occurred. The dwParam2 parameter of the corresponding LINE_REPLY callback message is zero if the function is successful or it is a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALCALLHANDLE	LINEERR_OPERATIONUNAVAIL
LINEERR_INVALCALLSTATE	LINEERR_OPERATIONFAILED
LINEERR_NOMEM	LINEERR_RESOURCEUNAVAIL
LINEERR_NOTOWNER	LINEERR_UNINITIALIZED
hCall

Specifies a handle to the call to be secured. The application must be an owner of the call. Call state of hCall can be any state.

A call can be secured to avoid interference. For example, in an analog environment, call-waiting tones may destroy a fax or modem session on the original call. The function lineSecureCall allows an existing call to be secured. The lineMakeCall function provides the option to secure the call from the time of call setup. The securing of a call remains in effect for the duration of the call.


lineSendUserUserInfo

[New - Windows 95]

LONG lineSendUserUserInfo(HCALL hCall, LPCSTR lpsUserUserInfo,
    DWORD dwSize)

Send user-to-user information to the remote party on the specified call.

•	Returns a positive request ID if the function will be completed asynchronously, or a negative error number if an error has occurred. The dwParam2 parameter of the corresponding LINE_REPLY callback message is zero if the function is successful or it is a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALCALLHANDLE	LINEERR_OPERATIONUNAVAIL
LINEERR_INVALCALLSTATE	LINEERR_OPERATIONFAILED
LINEERR_INVALPOINTER	LINEERR_RESOURCEUNAVAIL
LINEERR_NOMEM	LINEERR_USERUSERINFOTOOBIG
LINEERR_NOTOWNER	LINEERR_UNINITIALIZED
hCall

Specifies a handle to the call on which to send user-to-user information. The application must be an owner of the call. Call state of hCall must be connected, offering, accepted, or ringback.

lpsUserUserInfo

Specifies a pointer to a string containing user-to-user information to be sent to the remote party. User-to-user information is only sent if supported by the underlying network (see LINEDEVCAPS). The protocol discriminator field for the user-user information, if required, should appear as the first byte of the buffer pointed to by lpsUserUserInfo, and must be accounted for in dwSize.

dwSize

Specifies the size in bytes of the user-to-user information in lpsUserUserInfo.

This function can be used to send user-to-user information at any time during a connected call. If the size of the specified information to be sent is larger than what may fit into a single network message (as in ISDN), the service provider is responsible for dividing the information into a sequence of chained network messages (using "more data").

User-to-user information can also be sent as part of call accept, call reject, call redirect, and when making calls. User-to-user information can also be received. The received information is available through the call's call-information record. Whenever user-to-user information arrives after call offering or prior to call disconnect, a LINE_CALLINFO message with a UserUserInfo parameter will notify the application that user-to-user information in the call-information record has changed. If multiple network messages are chained, the information is assembled by the service provider and a single message is sent to the application.


lineSetAppPriority

[New - Windows 95]

LONG lineSetAppPriority(LPCSTR lpszAppFilename, DWORD dwMediaMode,
    LPLINEEXTENSIONID const lpExtensionID, DWORD dwRequestMode,
    LPCSTR lpszExtensionName, DWORD dwPriority)

Allows an application to set its priority in the handoff priority list for a particular media mode or Assisted Telephony request mode or to remove itself from the priority list.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_INIFILECORRUPT	LINEERR_INVALREQUESTMODE
LINEERR_INVALAPPNAME	LINEERR_NOMEM
LINEERR_INVALMEDIAMODE	LINEERR_OPERATIONFAILED
LINEERR_INVALPARAM	LINEERR_RESOURCEUNAVAIL
LINEERR_INVALPOINTER
lpszAppFilename

Specifies a pointer to a string containing the application executable module filename (without directory information). The parameter must specify a filename in the 8.3 format. Long filenames cannot be used.

dwMediaMode

Specifies the media mode for which the priority of the application is to be set. The value may be one of the LINEMEDIAMODE_ constants, or an extended media mode value defined by a service provider; only a single bit may be on. The value 0 should be used to set the application priority for Assisted Telephony requests.

lpExtensionID

Specifies a pointer to structure of type LINEEXTENSIONID. This parameter is referenced only if dwMediaModes specifies a value in the range 0x01000000 through 0x80000000 (extended media modes). This parameter is ignored if dwMediaMode is 0 or specifies a LINEMEDIAMODE_ value.

dwRequestMode

If the dwMediaMode parameter is 0, this parameter specifies the Assisted Telephony request mode for which priority is to be set. It must be either LINEREQUESTMODE_MAKECALL or LINEREQUESTMODE_MEDIACALL. This parameter is ignored if dwMediaMode is non-zero.

lpszExtensionName

If dwMediaMode specifies an extended media mode, this parameter may point to a null-terminated ASCII string specifying a friendly name for the extended media mode. If the pointer is NULL, any existing name is preserved, or, if a new entry is being created in the priority list, the friendly name will be set to the empty string. This parameter is ignored if dwMediaMode is 0 or specifies a LINEMEDIAMODE_ value.

dwPriority

Specifies the new priority for the application. If the value 0 is passed, the application is removed from the priority list for the specified media or request mode (if it was already not present, no error is generated). If the value 1 is passed, the application is inserted as the highest-priority application for the media or request mode (and removed from a lower-priority position, if it was already in the list). Any other value generates an error.

If LINEERR_INVALMEDIAMODE is returned, the value specified in dwMediaMode is not 0, not a valid extended media mode, and not a LINEMEDIAMODE_ constant, or more than one bit is on in the parameter value.

This function updates to stored priority list. If the telephony system is initialized, it also sets the current, active priorities for applications then running; the new priority will be used on the next incoming call or lineHandoff based on media mode.

Although this is a new function which older applications would not be expected to call, for backward compatibility, they should not be prevented from doing so; the function will work the same way for all applications.


lineSetAppSpecific

[New - Windows 95]

LONG lineSetAppSpecific(HCALL hCall, DWORD dwAppSpecific)

This operation enables an application to set the application-specific field of the specified call's call-information record.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALCALLHANDLE	LINEERR_RESOURCEUNAVAIL
LINEERR_NOMEM	LINEERR_UNINITIALIZED
LINEERR_NOTOWNER	LINEERR_OPERATIONUNAVAIL
LINEERR_OPERATIONFAILED
hCall

Specifies a handle to the call whose application-specific field needs to be set. The application must be an owner of the call. Call state of hCall can be any state.

dwAppSpecific

Specifies the new content of the dwAppSpecific field for the call's LINECALLINFO structure. This value is not interpreted by the Telephony API.

The application-specific field in the LINECALLINFO data structure that exists for each call is not interpreted by the Telephony API or any of its service providers. Its usage is entirely defined by the applications. The field can be read from the LINECALLINFO record returned by lineGetCallInfo. However, lineSetAppSpecific must be used to set the field so that changes become visible to other applications. When this field is changed, all other applications with call handles are sent a LINE_CALLINFO message with an indication that the dwAppSpecific field has changed.


lineSetCallParams

[New - Windows 95]

LONG lineSetCallParams(HCALL hCall, DWORD dwBearerMode, DWORD dwMinRate,
    DWORD dwMaxRate, LPLINEDIALPARAMS const lpDialParams)

Allows an application to change bearer mode and/or the rate parameters of an existing call.

•	Returns a positive request ID if the function will be completed asynchronously, or a negative error number if an error has occurred. The dwParam2 parameter of the corresponding LINE_REPLY callback message is zero if the function is successful or it is a negative error number if an error has occurred. Possible return values are:

LINEERR_BEARERMODEUNAVAIL	LINEERR_NOTOWNER
LINEERR_INVALBEARERMODE	LINEERR_OPERATIONUNAVAIL
LINEERR_INVALCALLHANDLE	LINEERR_OPERATIONFAILED
LINEERR_INVALCALLSTATE	LINEERR_RATEUNAVAIL
LINEERR_INVALPOINTER	LINEERR_RESOURCEUNAVAIL
LINEERR_INVALRATE	LINEERR_UNINITIALIZED
LINEERR_NOMEM
hCall

Specifies a handle to the call whose parameters are to be changed. The application must be an owner of the call. Call state of hCall can be any state except idle and disconnected.

dwBearerMode

Specifies the new bearer mode for the call. This parameter can have only a single bit set, and it uses the following LINEBEARERMODE_ constants:

LINEBEARERMODE_VOICE

This is a regular 3.1kHz analog voice-grade bearer service. Bit integrity is not assured. Voice can support fax and modem media modes.

LINEBEARERMODE_SPEECH

This corresponds to G.711 speech transmission on the call. The network may use processing techniques such as analog transmission, echo cancellation, and compression/decompression. Bit integrity is not assured. Speech is not intended to support fax and modem media modes.

LINEBEARERMODE_MULTIUSE

The multi-use mode defined by ISDN.

LINEBEARERMODE_DATA

The unrestricted data transfer on the call. The data rate is specified separately.

LINEBEARERMODE_ALTSPEECHDATA

The alternate transfer of speech or unrestricted data on the same call (ISDN).

LINEBEARERMODE_NONCALLSIGNALING

This corresponds to a non-call-associated signaling connection from the application to the service provider or switch (treated as a media stream by the Telephony API).

dwMinRate

Specifies a lower bound for the call's new data rate. The application is willing to accept a new rate as low as this one.

dwMaxRate

Specifies an upper bound for the call's new data rate. This is the maximum data rate the application can accept. If an exact data rate is required, dwMinRate and dwMaxRate should be equal.

lpDialParams

Specifies a pointer to the new dial parameters for the call, of type LINEDIALPARAMS. This parameter can be left NULL if the call's current dialing parameters are to be used.

This operation is used to change the parameters of an existing call. Examples of its usage include changing the bearer mode and/or the data rate of an existing call.


lineSetCallPrivilege

[New - Windows 95]

LONG lineSetCallPrivilege(HCALL hCall, DWORD dwCallPrivilege)

This operation sets the application's privilege to the specified privilege.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALCALLHANDLE	LINEERR_OPERATIONFAILED
LINEERR_INVALCALLSTATE	LINEERR_RESOURCEUNAVAIL
LINEERR_INVALCALLPRIVILEGE	LINEERR_UNINITIALIZED
LINEERR_NOMEM
hCall

Specifies a handle to the call whose privilege is to be set. Call state of hCall can be any state.

dwCallPrivilege

Specifies the privilege the application wants to have for the specified call. Only a single flag can be set. This parameter uses the following LINECALLPRIVILEGE_ constants:

LINECALLPRIVILEGE_MONITOR

The application requests monitor privilege to the call. These privileges allow the application to monitor state changes and to query information and status about the call.

LINECALLPRIVILEGE_OWNER

The application requests owner privilege to the call. These privileges allow the application to manipulate the call in ways that affect the state of the call.

If the application is the sole owner of a non-idle call and wants to change its privilege to monitor, a LINEERR_INVALCALLSTATE error is returned. If the application wants to, it can first drop the call using lineDrop to make the call transition to the idle state and then change its privilege.


lineSetCurrentLocation

[New - Windows 95]

LONG lineSetCurrentLocation(HLINEAPP hLineApp, DWORD dwLocation)

This operation sets the location used as the context for address translation.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_INIFILECORRUPT	LINEERR_NOMEM
LINEERR_INVALAPPHANDLE	LINEERR_OPERATIONFAILED
LINEERR_INVALLOCATION	LINEERR_RESOURCEUNAVAIL
LINEERR_NODRIVER	LINEERR_UNINITIALIZED
hLineApp

Specifies the application handle returned by lineInitialize.

dwLocation

Specifies a new value for the CurrentLocation entry in the [Locations] section of TELEPHON.INI. It must contain a valid permanent ID of a Location entry in the [Locations] section, as obtained from lineGetTranslateCaps. If it is valid, the CurrentLocation entry is updated.

If an application has not yet called the lineInitialize function, it can set the hLineApp parameter to NULL and the dwDevice parameter to 0 when calling the lineSetCurrentLocation function.


lineSetDevConfig

[New - Windows 95]

LONG lineSetDevConfig (DWORD dwDeviceID, LPVOID const lpDeviceConfig,
    DWORD dwSize, LPCSTR lpszDeviceClass)

Allows the application to restore the configuration of a media stream device on a line device to a setup previously obtained using lineGetDevConfig. For example, the contents of this structure could specify data rate, character format, modulation schemes, and error control protocol settings for a "datamodem" media device associated with the line.

•	Returns zero if the function is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_BADDEVICEID	LINEERR_NODRIVER
LINEERR_INVALDEVICECLASS	LINEERR_OPERATIONUNAVAIL
LINEERR_INVALPOINTER	LINEERR_OPERATIONFAILED
LINEERR_INVALPARAM	LINEERR_RESOURCEUNAVAIL
LINEERR_INVALLINESTATE	LINEERR_UNINITIALIZED
LINEERR_NOMEM	LINEERR_NODEVICE
dwDeviceID

Specifies the line device to be configured.

lpDeviceConfig

Specifies a pointer to the opaque configuration data structure that was returned by lineGetDevConfig in the variable portion of the VARSTRING structure.

dwSize

Specifies the number of bytes in the structure pointed to by lpDeviceConfig. This value will have been returned in the dwStringSize field in the VARSTRING structure returned by lineGetDevConfig.

lpszDeviceClass

Specifies a pointer to a NULL-terminated ASCII string that specifies the device class of the device whose configuration is to be set. Valid device class strings are the same as those specified for the lineGetID function.

Call states are device specific.

Typically, an application will call lineGetID to identify the media stream device associated with a line, and then call lineConfigDialog to allow the user to set up the device configuration. It could then call lineGetDevConfig and save the configuration information in a phone book or other database associated with a particular call destination. When the user later wants to call the same destination again, this function lineSetDevConfig can be used to restore the configuration settings selected by the user. lineSetDevConfig, lineConfigDialog, and lineGetDevConfig can be used, in that order, to allow the user to view and update the settings.

The exact format of the data contained within the structure is specific to the line and media stream API (device class), is undocumented, and is undefined. The application must treat it as "opaque" and not manipulate the contents directly. Generally, the structure can be sent using this function only to the same device from which it was obtained. Certain Telephony service providers may, however, permit structures to be interchanged between identical devices (that is, multiple ports on the same multi-port modem card). Such interchangability is not guaranteed in any way, even for devices of the same device class.

Note that some service providers may permit the configuration to be set while a call is active, and others may not.


lineSetMediaControl

[New - Windows 95]

LONG lineSetMediaControl(HLINE hLine, DWORD dwAddressID, HCALL hCall,
    DWORD dwSelect, LPLINEMEDIACONTROLDIGIT const lpDigitList,
    DWORD dwDigitNumEntries, LPLINEMEDIACONTROLMEDIA	 const lpMediaList,
    DWORD dwMediaNumEntries, LPLINEMEDIACONTROLTONE const lpToneList,
    DWORD dwToneNumEntries,
    LPLINEMEDIACONTROLCALLSTATE const lpCallStateList,
    DWORD dwCallStateNumEntries)

Enables and disables control actions on the media stream associated with the specified line, address, or call. Media control actions can be triggered by the detection of specified digits, media modes, custom tones, and call states.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALADDRESSID	LINEERR_NOMEM
LINEERR_INVALCALLHANDLE	LINEERR_NOTOWNER
LINEERR_INVALCALLSELECT	LINEERR_OPERATIONUNAVAIL
LINEERR_INVALCALLSTATELIST	LINEERR_OPERATIONFAILED
LINEERR_INVALDIGITLIST	LINEERR_RESOURCEUNAVAIL
LINEERR_INVALLINEHANDLE	LINEERR_UNINITIALIZED
LINEERR_INVALMEDIALIST	LINEERR_INVALPOINTER
LINEERR_INVALTONELIST
hLine

Specifies a handle to an open line device.

dwAddressID

Specifies an address on the given open line device.

hCall

Specifies a handle to a call. The application must be an owner of the call.  Call state of hCall can be any state.

dwSelect

Specifies whether the media control requested is associated with a single call, is the default for all calls on an address, or is the default for all calls on a line. This parameter can only have a single flag set, and it uses the following LINECALLSELECT_ constants:

LINECALLSELECT_LINE

Selects the specified line device. The hLine parameter must be a valid line handle; hCall and dwAddressID are ignored.

LINECALLSELECT_ADDRESS

Selects the specified address on the line. Both hLine and dwAddressID must be valid; hCall is ignored.

LINECALLSELECT_CALL

Selects the specified call. hCall must be valid; hLine and dwAddressID are both ignored.

lpDigitList

Specifies a pointer to the array that contains the digits that are to trigger media control actions, of type LINEMEDIACONTROLDIGIT. Each time a digit listed in the digit list is detected, the specified media control action is carried out on the call's media stream.

Valid digits for pulse mode are '0' through '9'. Valid digits for DTMF mode are '0' through '9', 'A', 'B', 'C', 'D', '*', '#'.

dwDigitNumEntries

Specifies the number of entries in the lpDigitList.

lpMediaList

Specifies a pointer to an array with entries of type LINEMEDIACONTROLMEDIA. The array has dwMediaNumEntries entries. Each entry contains a media mode to be monitored, media-type specific information (such as duration), and a media control field. If a media mode in the list is detected, the corresponding media control action is performed on the call's media stream.

dwMediaNumEntries

Specifies the number of entries in lpMediaList.

lpToneList

Specifies a pointer to an array with entries of type LINEMEDIACONTROLTONE. The array has dwToneNumEntries entries. Each entry contains a description of a tone to be monitored, duration of the tone, and a media-control field. If a tone in the list is detected, the corresponding media control action is performed on the call's media stream.

dwToneNumEntries

Specifies the number of entries in lpToneList.

lpCallStateList

Specifies a pointer to an array with entries are of type LINEMEDIACONTROLCALLSTATE. The array has dwCallStateNumEntries entries. Each entry contains a call state and a media control action. Whenever the given call transitions into one of the call states in the list, the corresponding media control action is invoked.

dwCallStateNumEntries

Specifies the number of entries in lpCallStateList.

This function is considered successful if media control has been correctly initiated, not when any media control has taken effect. Media control in progress is changed or is canceled by calling this function again with either different parameters or NULLs. If one or more of the parameters lpDigitList, lpMediaList, lpToneList, and lpCallStateList are NULL, then the corresponding digit, media mode, tone, or call state-triggered media control is disabled. To modify just a portion of the media control parameters while leaving the remaining settings in effect, the application should invoke lineSetMediaControl supplying the previous parameters for those portions that must remain in effect, and new parameters for those parts that are to be modified.

If hCall is selected and the call terminates or the application deallocates its handle, media control on that call is canceled.

All applications that are owners of the call are in principle allowed to make media control requests on the call. Only a single media control request can be outstanding on a call across all applications that own the call. Each time lineSetMediaControl is called, the new request overrides any media control then in effect on the call, whether set by the calling application or any other owning application.

Depending on the service provider and other activities that compete for such resources, the amount of simultaneous detections that can be made may vary over time. If service provider resources are overcommitted, the LINEERR_RESOURCEUNAVAIL error is returned.

Whether or not media control is supported by the service provider is a device capability.


lineSetMediaMode

[New - Windows 95]

LONG lineSetMediaMode(HCALL hCall, DWORD dwMediaModes)

Sets the media mode(s) of the specified call in its LINECALLINFO structure.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALCALLHANDLE	LINEERR_OPERATIONFAILED
LINEERR_INVALMEDIAMODE	LINEERR_RESOURCEUNAVAIL
LINEERR_NOMEM	LINEERR_UNINITIALIZED
LINEERR_OPERATIONUNAVAIL
hCall

Specifies a handle to the call whose media mode is to be changed. The application must be an owner of the call. Call state of hCall can be any state.

dwMediaModes

Specifies the new media mode(s) for the call. As long as the UNKNOWN media mode flag is set, other media mode flags may be set as well. This is used to identify a call's media mode as not fully determined, but narrowed down to one of a small set of specified media modes. If the UNKNOWN flag is not set, only a single media mode can be specified. This parameter uses the following LINEMEDIAMODE_ constants:

LINEMEDIAMODE_UNKNOWN

The target application is the one that handles calls of unknown media mode (unclassified calls).

LINEMEDIAMODE_INTERACTIVEVOICE

The target application is the one that handles calls with the interactive voice media mode (live conversations).

LINEMEDIAMODE_AUTOMATEDVOICE

Voice energy is present on the call, and the voice is locally handled by an automated application.

LINEMEDIAMODE_DATAMODEM

The target application is the one that handles calls with the data modem media mode.

LINEMEDIAMODE_G3FAX

The target application is the one that handles calls with the group 3 fax media mode.

LINEMEDIAMODE_TDD

The target application is the one that handles calls with the TDD (Telephony Devices for the Deaf) media mode.

LINEMEDIAMODE_G4FAX

The target application is the one that handles calls with the group 4 fax media mode.

LINEMEDIAMODE_DIGITALDATA

The target application is the one that handles calls that are digital data calls.

LINEMEDIAMODE_TELETEX

The target application is the one that handles calls with the teletex media mode.

LINEMEDIAMODE_VIDEOTEX

The target application is the one that handles calls with the videotex media mode.

LINEMEDIAMODE_TELEX

The target application is the one that handles calls with the telex media mode.

LINEMEDIAMODE_MIXED

The target application is the one that handles calls with the ISDN mixed media mode.

LINEMEDIAMODE_ADSI

The target application is the one that handles calls with the ADSI (Analog Display Services Interface) media mode.

LINEMEDIAMODE_VOICEVIEW

The media mode of the call is VoiceView.

This function changes the call's media mode in its LINECALLINFO structure. Typical usage of this operation is either to set a call's media mode to a specific known media mode or to exclude possible media modes as long as the call's media mode is officially unknown (the UNKNOWN media mode flag is set).


lineSetNumRings

[New - Windows 95]

LONG lineSetNumRings(HLINE hLine, DWORD dwAddressID, DWORD dwNumRings)

Sets the number of rings that must occur before an incoming call is answered. This function can be used to implement a toll-saver-style function. It allows multiple independent applications to each register the number of rings. The function lineGetNumRings returns the minimum number of all number of rings requested. It can be used by the application that answers inbound calls to determine the number of rings it should wait before answering the call.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALLINEHANDLE	LINEERR_OPERATIONFAILED
LINEERR_INVALADDRESSID	LINEERR_RESOURCEUNAVAIL
LINEERR_NOMEM	LINEERR_UNINITIALIZED
hLine

Specifies a handle to the open line device.

dwAddressID

Specifies an address on the line device.

dwNumRings

Specifies the number of rings before a call should be answered in order to honor the toll-saver requests from all applications.

The lineGetNumRings and lineSetNumRings functions, when used in combination, provide a mechanism to support the implementation of toll-saver features across multiple independent applications. If no application ever calls lineSetNumRings, lineGetNumRings will return 0xFFFFFFFF.

An application that is the owner of a call in the offering state and that received a LINE_LINEDEVSTATE ringing message should wait a number of rings equal to the number returned by lineGetNumRings before answering the call in order to honor the toll-saver settings across all applications. A separate LINE_LINEDEVSTATE ringing message is sent to the application for each ring cycle, so the application should count these messages. If this call disconnects before being answered, and another call comes in shortly thereafter, the LINE_CALLSTATE message should allow the application to determine that ringing is related to the second call.

If call classification is performed by TAPI.DLL by means of answering inbound calls of unknown media mode and filtering the media stream, TAPI.DLL will honor this number as well.

Note that this operation is purely informational and does not affect the state of any calls on the line device.


lineSetStatusMessages

[New - Windows 95]

LONG lineSetStatusMessages(HLINE hLine, DWORD dwLineStates,
    DWORD dwAddressStates)

Enables an application to specify which notification messages the application wants to receive for events related to status changes for the specified line or any of its addresses.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALADDRESSSTATE	LINEERR_OPERATIONFAILED
LINEERR_INVALLINEHANDLE	LINEERR_RESOURCEUNAVAIL
LINEERR_INVALLINESTATE	LINEERR_UNINITIALIZED
LINEERR_NOMEM	LINEERR_OPERATIONUNAVAIL
hLine

Specifies a handle to the line device.

dwLineStates

Specifies a bit array that identifies for which line-device status changes a message is to be sent to the application. This parameter uses the following LINEDEVSTATE_ constants:

LINEDEVSTATE_OTHER

Device-status items other than those listed below have changed. The application should check the current device status to determine which items have changed.

LINEDEVSTATE_RINGING

The switch tells the line to alert the user.

LINEDEVSTATE_CONNECTED

The line was previously disconnected and is now connected to TAPI.

LINEDEVSTATE_DISCONNECTED

This line was previously connected and is now disconnected from TAPI.

LINEDEVSTATE_MSGWAITON

The "message waiting" indicator is turned on.

LINEDEVSTATE_MSGWAITOFF

The "message waiting" indicator is turned off.

LINEDEVSTATE_INSERVICE

The line is connected to TAPI. This happens when TAPI is first activated, or when the line wire is physically plugged in and in service at the switch while TAPI is active.

LINEDEVSTATE_OUTOFSERVICE

The line is out of service at the switch or physically disconnected. TAPI cannot be used to operate on the line device.

LINEDEVSTATE_MAINTENANCE

Maintenance is being performed on the line at the switch. TAPI cannot be used to operate on the line device.

LINEDEVSTATE_OPEN

The line has been opened by some application.

LINEDEVSTATE_CLOSE

The line has been closed by some application.

LINEDEVSTATE_NUMCALLS

The number of calls on the line device has changed.

LINEDEVSTATE_NUMCOMPLETIONS

The number of outstanding call completions on the line device has changed.

LINEDEVSTATE_TERMINALS

The terminal settings have changed.

LINEDEVSTATE_ROAMMODE

The roam mode of the line device has changed.

LINEDEVSTATE_BATTERY

The battery level has changed significantly (cellular).

LINEDEVSTATE_SIGNAL

The signal level has changed significantly (cellular).

LINEDEVSTATE_DEVSPECIFIC

The line's device-specific information has changed.

LINEDEVSTATE_REINIT

Items have changed in the configuration of line devices. To become aware of these changes (as with the appearance of new line devices) the application should reinitialize its use of TAPI. New lineInitialize and lineOpen requests are denied until applications have shut down their usage of TAPI. The hDevice parameter of the LINE_LINEDEVSTATE message is left NULL for this state change as it applies to any of the lines in the system. Because of the critical nature of LINEDEVSTATE_REINIT, such messages cannot be masked, so the setting of this bit is ignored and the messages are always delivered to the application.

LINEDEVSTATE_LOCK

The locked status of the line device has changed.

dwAddressStates

Specifies a bit array that identifies for which address status changes a message is to be sent to the application. This parameter uses the following LINEADDRESSSTATE_ constants:

LINEADDRESSSTATE_OTHER

Address-status items other than those listed below have changed. The application should check the current address status to determine which items have changed.

LINEADDRESSSTATE_DEVSPECIFIC

The device-specific item of the address status has changed.

LINEADDRESSSTATE_INUSEZERO

The address has changed to idle (it is now in use by zero stations).

LINEADDRESSSTATE_INUSEONE

The address has changed from idle or from being in use by many bridged stations to being in use by just one station.

LINEADDRESSSTATE_INUSEMANY

The monitored or bridged address has changed from being in use by one station to being used by more than one station.

LINEADDRESSSTATE_NUMCALLS

The number of calls on the address has changed. This is the result of events such as a new inbound call, an outbound call on the address, or a call changing its hold status.

LINEADDRESSSTATE_FORWARD

The forwarding status of the address has changed (including the number of rings for determining a no answer condition). The application should check the address status to determine details about the address's current forwarding status.

LINEADDRESSSTATE_TERMINALS

The terminal settings for the address have changed.

TAPI defines a number of messages that notify applications about events occurring on lines and addresses. An application may not be interested in receiving all address and line status change messages. lineSetStatusMessages can be used to select which messages the application wants to receive. By default, address and line status reporting is disabled.


lineSetTerminal

[New - Windows 95]

LONG lineSetTerminal(HLINE hLine, DWORD dwAddressID, HCALL hCall,
    DWORD dwSelect, DWORD dwTerminalModes, DWORD dwTerminalID,
    DWORD bEnable)

Enables an application to specify which terminal information related to the specified line, address, or call is to be routed. lineSetTerminal can be used while calls are in progress on the line to allow an application to route these events to different devices as required.

•	Returns a positive request ID if the function will be completed asynchronously, or a negative error number if an error has occurred. The dwParam2 parameter of the corresponding LINE_REPLY callback message is zero if the function is successful or it is a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALADDRESSID	LINEERR_NOMEM
LINEERR_INVALCALLHANDLE	LINEERR_OPERATIONUNAVAIL
LINEERR_INVALCALLSELECT	LINEERR_OPERATIONFAILED
LINEERR_INVALLINEHANDLE	LINEERR_RESOURCEUNAVAIL
LINEERR_INVALTERMINALID	LINEERR_UNINITIALIZED
LINEERR_INVALTERMINALMODE
hLine

Specifies a handle to an open line device.

dwAddressID

Specifies an address on the given open line device.

hCall

Specifies a handle to a call. Call state of hCall can be any state, if dwSelect is CALL.

dwSelect

Specifies whether the terminal setting is requested for the line, the address, or just the specified call. If line or address is specified, events either apply to the line or address itself or serves as a default initial setting for all new calls on the line or address. This parameter uses the following LINECALLSELECT_ constants:

LINECALLSELECT_LINE

Selects the specified line device. The hLine parameter must be a valid line handle; hCall and dwAddressID are ignored.

LINECALLSELECT_ADDRESS

Selects the specified address on the line. Both hLine and dwAddressID must be valid; hCall is ignored.

LINECALLSELECT_CALL

Selects the specified call. hCall must be valid; hLine and dwAddressID are both ignored.

dwTerminalModes

Specifies the class(es) of low-level events to be routed to the given terminal. This parameter uses the following LINETERMMODE_ constants:

LINETERMMODE_BUTTONS

The button presses from the terminal to the line.

LINETERMMODE_DISPLAY

The display events from the line to the terminal.

LINETERMMODE_LAMPS

The lamp lighting events from the line to the terminal.

LINETERMMODE_RINGER

The ring requests from the line to the terminal.

LINETERMMODE_HOOKSWITCH

The hookswitch events between the terminal and the line.

LINETERMMODE_MEDIATOLINE

This is the unidirectional media stream from the terminal to the line associated with a call on the line. Use this value when routing of both unidirectional channels of a call's media stream can be controlled independently.

LINETERMMODE_MEDIAFROMLINE

This is the unidirectional media stream from the line to the terminal associated with a call on the line. Use this value when routing of both unidirectional channels of a call's media stream can be controlled independently.

LINETERMMODE_MEDIABIDIRECT

This is the bidirectional media stream associated with a call on the line and the terminal. Use this value when routing of both unidirectional channels of a call's media stream cannot be controlled independently. Note that MEDIABIDIRECT is mutually exclusive with MEDIATOLINE and MEDIAFROMLINE

dwTerminalID

Specifies the device ID of the terminal device where the given events are to be routed. Terminal IDs are small integers in the range of 0 to one less than dwNumTerminals, where dwNumTerminals, and the terminal modes each terminal is capable of handling, are returned by lineGetDevCaps. Note that these terminal IDs have no relation to other device IDs and are defined by the service provider using device capabilities.

bEnable

If TRUE, dwTerminalID is valid and the specified event classes are routed to or from that terminal. If FALSE, these events are not routed to or from the terminal device with ID equal to dwTerminalID.

An application can use this function to route certain classes of low-level line events to the specified terminal device or to suppress the routing of these events. For example, voice may be routed to an audio I/O device (headset); lamps and display events may be routed to the local phone device, and button events and ringer events may be suppressed altogether.

This function can be called at any time, even when a call is active on the given line device. This allows a user to switch from using the local phone set to another audio I/O device. This function may be called multiple times to route the same events to multiple terminals simultaneously. To reroute events to a different terminal, the application should first disable routing to the existing terminal and then route the events to the new terminal.

Terminal ID assignments are made by the line's service provider. Device capabilities indicate only which terminal IDs the service provider has available. Service providers that do not support this type of event routing would indicate that they have no terminal devices (dwNumTerminals in LINEDEVCAPS would be zero).

Invoking lineSetTerminal on a line or address affects all existing calls on that line or address, but does not affect calls on other addresses. It also sets the default for future calls on that line or address. A line or address that has multiple connected calls active at one time may have different routing in effect for each call.

Disabling the routing of low-level events to a terminal when these events are not currently routed to or from that terminal will not necessarily generate an error so long after the function succeeds (the specified events are not routed to or from that terminal).

TAPI routes call progress tones and messages to the same location as set by the lineSetTerminal function for "media". For example, if audio signals are going to the phone, then so will busy signals (analog) or Q.931 messages indicating busy (digital).


lineSetTollList

[New - Windows 95]

LONG lineSetTollList(HLINEAPP hLineApp, DWORD dwDeviceID,
    LPCSTR lpszAddressIn, DWORD dwTollListOption)

Manipulates the toll list.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_BADDEVICEID	LINEERR_NODRIVER
LINEERR_INVALAPPHANDLE	LINEERR_NOMEM
LINEERR_INVALADDRESS	LINEERR_OPERATIONFAILED
LINEERR_INVALPARAM	LINEERR_RESOURCEUNAVAIL
LINEERR_INIFILECORRUPT	LINEERR_UNINITIALIZED
LINEERR_INVALLOCATION
hLineApp

Specifies the application handle returned by lineInitialize.

dwDeviceID

Specifies the device ID for the line device upon which the call is intended to be dialed, so that variations in dialing procedures on different lines can be applied to the translation process.

lpszAddressIn

Specifies a pointer to a NULL-terminated ASCII string containing the address from which the prefix information is to be extracted for processing. This parameter must not be NULL, and it must be in the canonical address format.

dwTollListOption

Specifies the toll list operation to be performed. Only a single flag can be set. This parameter uses the following LINETOLLLISTOPTION_ constants:

LINETOLLLISTOPTION_ADD

Causes the prefix contained within the string pointed to by lpszAddressIn to be added to the toll list for the current location.

LINETOLLLISTOPTION_REMOVE

Causes the prefix to be removed from the toll list of the current location. If toll lists are not used or relevant to the country indicated in the current location, the operation has no affect.

If an application has not yet called the lineInitialize function, it can set the hLineApp parameter to NULL and the dwDevice parameter to 0 when calling the lineSetTollList function.


lineSetupConference

[New - Windows 95]

LONG lineSetupConference(HCALL hCall, HLINE hLine, LPHCALL lphConfCall,
    LPHCALL lphConsultCall, DWORD dwNumParties,
    LPLINECALLPARAMS const lpCallParams)

Sets up a conference call for the addition of the third party.

•	Returns a positive request ID if the function will be completed asynchronously, or a negative error number if an error has occurred. The dwParam2 parameter of the corresponding LINE_REPLY callback message is zero if the function is successful or it is a negative error number if an error has occurred. Possible return values are:

LINEERR_BEARERMODEUNAVAIL	LINEERR_UNINITIALIZED
LINEERR_CALLUNAVAIL	LINEERR_INVALMEDIAMODE
LINEERR_CONFERENCEFULL	LINEERR_INVALPOINTER
LINEERR_INUSE	LINEERR_INVALRATE
LINEERR_INVALADDRESSMODE	LINEERR_NOMEM
LINEERR_INVALBEARERMODE	LINEERR_NOTOWNER
LINEERR_INVALCALLHANDLE	LINEERR_OPERATIONUNAVAIL
LINEERR_INVALCALLSTATE	LINEERR_OPERATIONFAILED
LINEERR_INVALCALLPARAMS	LINEERR_RATEUNAVAIL
LINEERR_INVALLINEHANDLE	LINEERR_RESOURCEUNAVAIL
LINEERR_INVALLINESTATE	LINEERR_STRUCTURETOOSMALL
LINEERR_USERUSERINFOTOOBIG
hCall

Specifies the initial call that identifies the first party of a conference call. In some environments (as described in device capabilities), a call must exist in order to start a conference call, and the application must be an owner of this call. In other telephony environments, no call initially exists, hCall must be left NULL, and hLine must be specified to identify the line on which the conference call is to be initiated. Call state of hCall must be connected.

hLine

Specifies a handle to the line. This handle is used to identify the line device on which to originate the conference call if hCall is NULL. The hLine parameter is ignored if hCall is non-NULL.

lphConfCall

Specifies a pointer to an HCALL handle. This location is then loaded with a handle identifying the newly created conference call. The application will be the initial sole owner of this call. Call state of hConfCall is not applicable.

lphConsultCall

Specifies a pointer to an HCALL handle. When setting up a call for the addition of a new party, a new temporary call (consultation call) is automatically allocated. Initially, the application will be the sole owner for this call.

dwNumParties

Specifies the expected number of parties in the conference call. This number is passed to the service provider. The service provider is free to do as it pleases with this number: ignore it, use it as a hint to allocate the right size conference bridge inside the switch, and so on.

lpCallParams

Specifies a pointer to call parameters to be used when establishing the consultation call. This parameter may be set to NULL if no special call setup parameters are desired.

If LINEERR_INVALLINESTATE is returned, the line is currently not in a state in which this operation can be performed. A list of currently valid operations can be found in the dwLineFeatures field (of the type LINEFEATURE) in the LINEDEVSTATUS structure. (Calling lineGetLineDevStatus updates the information in LINEDEVSTATUS.) If LINEERR_INVALMEDIAMODE is returned, check for supported media modes on the line in the dwMediaModes field in the LINEDEVCAPS structure.

lineSetupConference provides two ways to establish a new conference call, depending on whether a normal two-party call is required to pre-exist or not. When setting up a conference call from an existing two-party call, the hCall parameter is a valid call handle that is initially added to the conference call by the lineSetupConference request; hLine is ignored. On switches where conference call setup does not start with an existing call, hCall must be NULL and hLine must be specified to identify the line device on which to initiate the conference call. In either case, a consultation call is allocated for connecting to the party that is to be added to the call. The application can then use lineDial to dial the address of the other party.

The conference call typically transitions into the onHoldPendingConference state, the consultation call into the dialtone state, and the initial call (if there is one) into the conferenced state.

A conference call can also be set up by a lineCompleteTransfer that is resolved into a three-way conference. The application may be able to toggle between the consultation call and the conference call using lineSwapHold.

A consultation call can be canceled by invoking lineDropon it. When dropping a consultation call, the existing conference call typically transitions back to the connected state. The application should observe the LINE_CALLSTATE messages to determine exactly what happens to the calls. For example, if the conference call reverts back to a regular two-party call, the conference call will become idle and the original participant call may revert to connected.

If an application specifies the handle of the conference call in a call to the lineUnhold function, the conference call state is set to idle.


lineSetupTransfer

[New - Windows 95]

LONG lineSetupTransfer(HCALL hCall, LPHCALL lphConsultCall,
    LPLINECALLPARAMS const lpCallParams)

Initiates a transfer of the call specified by hCall. It establishes a consultation call, lphConsultCall, on which the party can be dialed that can become the destination of the transfer. The application acquires owner privilege to lphConsultCall.

•	Returns a positive request ID if the function will be completed asynchronously, or a negative error number if an error has occurred. The dwParam2 parameter of the corresponding LINE_REPLY callback message is zero if the function is successful or it is a negative error number if an error has occurred. Possible return values are:

LINEERR_BEARERMODEUNAVAIL	LINEERR_INVALRATE
LINEERR_CALLUNAVAIL	LINEERR_NOMEM
LINEERR_INUSE	LINEERR_NOTOWNER
LINEERR_INVALADDRESSMODE	LINEERR_OPERATIONFAILED
LINEERR_INVALBEARERMODE	LINEERR_OPERATIONUNAVAIL
LINEERR_INVALCALLHANDLE	LINEERR_RATEUNAVAIL
LINEERR_INVALCALLPARAMS	LINEERR_RESOURCEUNAVAIL
LINEERR_INVALCALLSTATE	LINEERR_STRUCTURETOOSMALL
LINEERR_INVALLINESTATE	LINEERR_UNINITIALIZED
LINEERR_INVALMEDIAMODE	LINEERR_USERUSERINFOTOOBIG
LINEERR_INVALPOINTER
hCall

Specifies the handle of the call to be transferred. The application must be an owner of the call. Call state of hCall must be connected.

lphConsultCall

Specifies a pointer to an HCALL handle. This location is then loaded with a handle identifying the temporary consultation call. When setting up a call for transfer, another call (a consultation call) is automatically allocated to enable the application to dial the address (using lineDial) of the party to where the call is to be transferred. The originating party can carry on a conversation over this consultation call prior to completing the transfer. Call state of hConsultCall is not applicable.

This transfer procedure may not be valid for some line devices. The application may need to ignore the new consultation call and unhold an existing held call (using lineUnhold) to identify the destination of the transfer. On switches that support cross-address call transfer, the consultation call may exist on a different address than the call to be transferred. It may also be necessary that the consultation call be set up as an entirely new call, by lineMakeCall, to the destination of the transfer. Which forms of transfer are available are specified in the call's address capabilities.

lpCallParams

Specifies a pointer to call parameters to be used when establishing the consultation call. This parameter may be set to NULL if no special call setup parameters are desired.

This function sets up the transfer of the call specified by hCall. The setup phase of a transfer establishes a consultation call that enables the application to send the address of the destination (the party to be transferred to) to the switch, while the call to be transferred is kept on hold. This new call is referred to as a consultation call (hConsultCall) and can be dropped or otherwise manipulated independently of the original call.

When the consultation call has reached the dialtone call state, the application may proceed transferring the call either by dialing the destination address and tracking its progress, or by unholding an existing call. The transfer of the original call to the selected destination is completed using lineCompleteTransfer.

While the consultation call exists, the original call typically transitions to the onholdPendingTransfer state. The application may be able to toggle between the consultation call and the original call by using lineSwapHold. A consultation call can be canceled by invoking lineDrop on it. After dropping a consultation call, the original call will typically transition back to the connected state. If the call state of the original call is onHoldPendingTransfer, the lineUnhold function can be used to recover the call. In this case, the call state of the consultation call is set to idle.

The application may also transfer calls in a single step, without having to deal with the intervening consultation call by using lineBlindTransfer.


lineShutdown

[New - Windows 95]

LONG lineShutdown(HLINEAPP hLineApp)

Shuts down the application's usage of the line abstraction of API.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALAPPHANDLE	LINEERR_RESOURCEUNAVAIL
LINEERR_NOMEM	LINEERR_UNINITIALIZED
hLineApp

Specifies the application's usage handle for the line API.

If this function is called when the application has lines open or calls active, the call handles are deleted and TAPI.DLL automatically performs the equivalent of a lineClose on each open line. However, it is recommended that applications explicitly close all open lines before invoking lineShutdown. If shutdown is performed while asynchronous requests are outstanding, those requests will be cancelled.


lineSwapHold

[New - Windows 95]

LONG lineSwapHold(HCALL hActiveCall, HCALL hHeldCall)

Swaps the specified active call with the specified call on consultation hold.

•	Returns a positive request ID if the function will be completed asynchronously, or a negative error number if an error has occurred. The dwParam2 parameter of the corresponding LINE_REPLY callback message is zero if the function is successful or it is a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALCALLHANDLE	LINEERR_OPERATIONUNAVAIL
LINEERR_INVALCALLSTATE	LINEERR_OPERATIONFAILED
LINEERR_NOMEM	LINEERR_RESOURCEUNAVAIL
LINEERR_NOTOWNER	LINEERR_UNINITIALIZED
hActiveCall

Specifies the handle to the active call. The application must be an owner of the call. Call state of hActiveCall must be connected.

hHeldCall

Specifies the handle to the consultation call. The application must be an owner of the call. Call state of hHeldCall can be onHoldPendingTransfer, onHoldPendingConference, onHold .

Swapping the active call with the call on consultation hold allows the application to alternate or toggle between these two calls. This is typical in call waiting.


lineTranslateAddress

[New - Windows 95]

LONG lineTranslateAddress(HLINEAPP hLineApp, DWORD dwDeviceID,
    DWORD dwAPIVersion, LPCSTR lpszAddressIn, DWORD dwCard,
    DWORD dwTranslateOptions, LPLINETRANSLATEOUTPUT lpTranslateOutput)

This operation translates the specified address into another format.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_BADDEVICEID	LINEERR_INVALPOINTER
LINEERR_INCOMPATIBLEAPIVERSION	LINEERR_NODRIVER
LINEERR_INIFILECORRUPT	LINEERR_NOMEM
LINEERR_INVALADDRESS	LINEERR_OPERATIONFAILED
LINEERR_INVALAPPHANDLE	LINEERR_RESOURCEUNAVAIL
LINEERR_INVALCARD	LINEERR_STRUCTURETOOSMALL
LINEERR_INVALPARAM	LINEERR_UNINITIALIZED
hLineApp

Specifies the application handle returned by lineInitialize.

dwDeviceID

Specifies the device ID for the line device upon which the call is intended to be dialed, so that variations in dialing procedures on different lines can be applied to the translation process.

dwAPIVersion

Indicates the version of TAPI negotiated by lineNegotiateAPIVersion.

lpszAddressIn

Specifies a pointer to a NULL-terminated ASCII string containing the address from which the information is to be extracted for translation. Must be in either the canonical address format, or an arbitrary string of dialable digits (non-canonical). This parameter must not be NULL. If the AddressIn contains a subaddress or name field, or additional addresses separated from the first address by ASCII CR and LF characters, only the first address is translated, and the remainder of the string is returned to the application without modification.

dwCard

Specifies the credit card to be used for dialing. This field in only valid if the CARDOVERRIDE bit is set in dwTranslateOptions. This field specifies the permanent ID of a Card entry in the [Cards] section of TELEPHON.INI (as obtained from lineTranslateCaps) which should be used instead of the PreferredCardID specified in the definition of the CurrentLocation. It does not cause the PreferredCardID parameter of the current Location entry in TELEPHON.INI to be modified; the override applies only to the current translation operation. This field is ignored if the CARDOVERRIDE bit is not set in dwTranslateOptions.

dwTranslateOptions

Specifies the associated operations to be performed prior to the translation of the address into a dialable string. This parameter uses the following LINETRANSLATEOPTION_ constants:

LINETRANSLATEOPTION_CARDOVERRIDE

If this bit is set, dwCard specifies the permanent ID of a Card entry in the [Cards] section of TELEPHON.INI (as obtained from lineTranslateCaps) which should be used instead of the PreferredCardID specified in the definition of the CurrentLocation. It does not cause the PreferredCardID parameter of the current Location entry in TELEPHON.INI to be modified; the override applies only to the current translation operation. The dwCard field is ignored if the CARDOVERRIDE bit is not set.

LINETRANSLATEOPTION_CANCELCALLWAITING

If a Cancel Call Waiting string is defined for the location, setting this bit will cause that string to be inserted at the beginning of the dialable string. This is commonly used by datamodem and fax applications to prevent interruption of calls by call waiting beeps. If no Cancel Call Waiting string is defined for the location, this bit has no affect. Note that applications using this bit are advised to also set the LINECALLPARAMFLAGS_SECURE bit in the dwCallParamFlags field of the LINECALLPARAMS structure passed in to lineMakeCall via the lpCallParams parameter, so that if the line device uses a mechanism other than dialable digits to supress call interrupts that that mechanism will be invoked.

LINETRANSLATEOPTION_FORCELOCAL

If the number is local but would have been translated as a long distance call (LINETRANSLATERESULT_INTOLLLIST bit set in the LINETRANSLATEOUTPUT structure), this option will force it to be translated as local. This is a temporary override of the toll list setting.

LINETRANSLATEOPTION_FORCELD

If the address could potentially have been a toll call, but would have been translated as a local call (LINETRANSLATERESULT_NOTINTOLLLIST bit set in the LINETRANSLATEOUTPUT structure), this option will force it to be translated as long distance. This is a temporary override of the toll list setting.

lpTranslateOutput

Specifies a pointer to an application-allocated memory area to contain the output of the translation operation, of type LINETRANSLATEOUTPUT. Prior to calling lineTranslateAdress, the application should set the dwTotalSize field of this structure to indicate the amount of memory available to TAPI.DLL for returning information.

If an application has not yet called the lineInitialize function, it can set the hLineApp parameter to NULL and the dwDevice parameter to 0 when calling the lineTranslateAddress function.


lineTranslateDialog

[New - Windows 95]

LONG lineTranslateDialog (HLINEAPP hLineApp, DWORD dwDeviceID,
    DWORD dwAPIVersion, HWND hwndOwner, LPCSTR lpszAddressIn)

Displays an application-modal dialog which allows the user to change the current location, adjust location and calling card parameters, and see the effect on a phone number about to be dialed.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

LINEERR_BADDEVICEID	LINEERR_INVALPARAM
LINEERR_INCOMPATIBLEAPIVERSION	LINEERR_INVALPOINTER
LINEERR_INIFILECORRUPT	LINEERR_NODRIVER
LINEERR_INUSE	LINEERR_NOMEM
LINEERR_INVALADDRESS	LINEERR_OPERATIONFAILED
LINEERR_INVALAPPHANDLE	LINEERR_UNINITIALIZED
hLineApp

Specifies the application handle returned by lineInitialize.

dwDeviceID

Specifies the device ID for the line device upon which the call is intended to be dialed, so that variations in dialing procedures on different lines can be applied to the translation process.

dwAPIVersion

Indicates the highest version of TAPI supported by the application (not necessarily the value negotiated by lineNegotiateAPIVersion on the line device indicated by dwDeviceID).

hwndOwner

Specifies a handle to a window to which the dialog is to be attached.

lpszAddressIn

Specifies a pointer to a NULL-terminated ASCII string containing a phone number which will be used, in the lower portion of the dialog, to show the effect of the user's changes to the location parameters. The number must be in canonical format; if non-canonical, the phone number portion of the dialog will not be displayed. This pointer can be left NULL, in which case the phone number portion of the dialog will not be displayed. If the AddressIn contains a subaddress or name field, or additional addresses separated from the first address by ASCII CR and LF characters, only the first address is used in the dialog.

If LINEERR_INUSE is returned, the dialog is already displayed by another application, and cannot be open more than once. TAPI brings the existing dialog to the front. This error indicates that any particulars related to the address passed in by the current application have not been handled, since that address was not processed by the function.

The application must call lineGetTranslateCaps after this function to obtain any changes the user made to the telephony address translation parameters, and call lineTranslateAddress to obtain a dialable string based on the user's new selections.

If any function related to address translation (e.g., lineGetTranslateCaps or lineTranslateAddress) returns LINEERR_INIFILECORRUPT, the application should call lineTranslateDialog. lineTranslateDialog will detect the errors and correct them, and report the action taken to the user. Note that LINEERR_INIFILECORRUPT will be returned the first time any of these functions are used after installation of Windows 95, because the parameters will be uninitialized (lineTranslateDialog will take care of initializing them, using the user-specified default country to select the default country code).

Although this is a new function which older applications would not be expected to call, for backward compatibility, they should not be prevented from doing so; the full range of API versions supported by TAPI (0x00010003 to 0x00010004) should work the same way.

If an application has not yet called the lineInitialize function, it can set the hLineApp parameter to NULL and the dwDevice parameter to 0 when calling the lineTranslateDialog function.


lineUncompleteCall

[New - Windows 95]

LONG lineUncompleteCall(HLINE hLine, DWORD dwCompletionID)

Cancels the specified call competion request on the specified line.

•	Returns a positive request ID if the function will be completed asynchronously, or a negative error number if an error has occurred. The dwParam2 parameter of the corresponding LINE_REPLY callback message is zero if the function is successful or it is a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALLINEHANDLE	LINEERR_OPERATIONFAILED
LINEERR_INVALCOMPLETIONID	LINEERR_RESOURCEUNAVAIL
LINEERR_NOMEM	LINEERR_UNINITIALIZED
LINEERR_OPERATIONUNAVAIL
hLine

Specifies a handle to the line device on which a call completion is to be canceled.

dwCompletionID

Specifies the completion ID for the request that is to be canceled.


lineUnhold

[New - Windows 95]

LONG lineUnhold(HCALL hCall)

Retrieves the specified held call.

•	Returns a positive request ID if the function will be completed asynchronously, or a negative error number if an error has occurred. The dwParam2 parameter of the corresponding LINE_REPLY callback message is zero if the function is successful or it is a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALCALLHANDLE	LINEERR_OPERATIONUNAVAIL
LINEERR_INVALCALLSTATE	LINEERR_OPERATIONFAILED
LINEERR_NOMEM	LINEERR_RESOURCEUNAVAIL
LINEERR_NOTOWNER	LINEERR_UNINITIALIZED
hCall

Specifies the handle to the call to be retrieved. The application must be an owner of this call. Call state of hCall must be onHold, onHoldPendingTransfer, or onHoldPendingConference.


lineUnpark

[New - Windows 95]

LONG lineUnpark(HLINE hLine, DWORD dwAddressID, LPHCALL lphCall,
    LPCSTR lpszDestAddress)

Retrieves the call parked at the specified address and returns a call handle for it.

•	Returns a positive request ID if the function will be completed asynchronously, or a negative error number if an error has occurred. The dwParam2 parameter of the corresponding LINE_REPLY callback message is zero if the function is successful or it is a negative error number if an error has occurred. Possible return values are:

LINEERR_INVALADDRESS	LINEERR_OPERATIONUNAVAIL
LINEERR_INVALADDRESSID	LINEERR_OPERATIONFAILED
LINEERR_INVALLINEHANDLE	LINEERR_RESOURCEUNAVAIL
LINEERR_INVALPOINTER	LINEERR_UNINITIALIZED
LINEERR_NOMEM
hLine

Specifies a handle to the open line device on which a call is to unparked.

dwAddressID

Specifies the address on hLine at which the unpark is to be originated.

lphCall

Specifies a pointer to the location of type HCALL where the handle to the unparked call is returned. This handle is unrelated to any other handle which might have been previously associated with the retrieved call, such as the handle that might have been associated with the call when it was originally parked. The application will be the initial sole owner of this call.

lpszDestAddress

Specifies a pointer to a NULL-terminated character buffer that contains the address where the call is parked. The address is in standard dialable address format.


Constants


Line Error Constants

This section lists the line error constants returned by the line functions.

LINEERR_ADDRESSBLOCKED

The specified address is blocked from being dialed on the specified call.

LINEERR_ALLOCATED

The line cannot be opened due to a "persistent" condition, such as that of a serial port being exclusively opened by another process.

LINEERR_BADDEVICEID

The specified device ID or line device ID (such as in a dwDeviceID parameter) is invalid or out of range.

LINEERR_BEARERMODEUNAVAIL

The call's bearer mode cannot be changed to the specified bearer mode.

LINEERR_CALLUNAVAIL

All call appearances on the specified address are currently in use.

LINEERR_COMPLETIONOVERRUN

The maximum number of outstanding call completions has been exceeded.

LINEERR_CONFERENCEFULL

The maximum number of parties for a conference has been reached, or the requested number of parties cannot be satisfied.

LINEERR_DIALBILLING

The dialable address parameter contains dialing control characters that are not processed by the service provider.

LINEERR_DIALQUIET

The dialable address parameter contains dialing control characters that are not processed by the service provider.

LINEERR_DIALDIALTONE

The dialable address parameter contains dialing control characters that are not processed by the service provider.

LINEERR_DIALPROMPT

The dialable address parameter contains dialing control characters that are not processed by the service provider.

LINEERR_INCOMPATIBLEAPIVERSION

The application requested an API version or version range that is either incompatible or cannot be supported by the Telephony API implementation and/or corresponding service provider.

LINEERR_INCOMPATIBLEEXTVERSION

The application requested an extension version range that is either invalid or cannot be supported by the corresponding service provider.

LINEERR_INIFILECORRUPT

The file TELEPHON.INI cannot be read or understood properly by TAPI.DLL because of internal inconsistencies or formatting problems. For example, the [Locations], [Cards], or [Countries] section of TELEPHON.INI may be corrupted or inconsistent.

LINEERR_INUSE

The line device is in use and cannot currently be configured, allow a party to be added, allow a call to be answered, allow a call to be placed, or allow a call to be transferred.

LINEERR_INVALADDRESS

A specified address is either invalid or not allowed. If invalid, the address contains invalid characters or digits, or the deistination address contains dialing control characters (W, @, $, or ?) that are not supported by the service provider. If not allowed, the specified address is either not assigned to the specified line or is not valid for address redirection.

LINEERR_INVALADDRESSID

The specified address ID is either invalid or out of range.

LINEERR_INVALADDRESSMODE

The specified address mode is invalid.

LINEERR_INVALADDRESSSTATE

dwAddressStates contains one or more bits that are not LINEADDRESSSTATE_ constants.

LINEERR_INVALAPPHANDLE

The application handle (such as specified by a hLineApp parameter) or the appliction registration handle is invalid.

LINEERR_INVALAPPNAME

The specified application name is invalid. If an application name is specified by the application, it is assumed that the string does not contain any non-displayable characters, and is zero-terminated.

LINEERR_INVALBEARERMODE

The specified bearer mode is invalid.

LINEERR_INVALCALLCOMPLMODE

The specified completion is invalid.

LINEERR_INVALCALLHANDLE

The specified call handle is not valid. For example, the handle is not NULL but does not belong to the given line. In some cases, the specified call device handle is invalid.

LINEERR_INVALCALLPARAMS

The specified call parameters are invalid.

LINEERR_INVALCALLPRIVILEGE

The specified call privilege parameter is invalid.

LINEERR_INVALCALLSELECT

The specified select parameter is invalid.

LINEERR_INVALCALLSTATE

The current state of a call is not in a valid state for the requested operation.

LINEERR_INVALCALLSTATELIST

The specified call state list is invalid.

LINEERR_INVALCARD

The permanent card ID specified in dwCard could not be found in any entry in the [Cards] section of TELEPHON.INI.

LINEERR_INVALCOMPLETIONID

The completion ID is invalid.

LINEERR_INVALCONFCALLHANDLE

The specified call handle for the conference call is invalid or is not a handle for a conference call.

LINEERR_INVALCONSULTCALLHANDLE

The specified consultation call handle is invalid.

LINEERR_INVALCOUNTRYCODE

The specified country code is invalid.

LINEERR_INVALDEVICECLASS

The line device has no associated device for the given device class, or the specified line does not support the indicated device class.

LINEERR_INVALDIGITLIST

The specified digit list is invalid.

LINEERR_INVALDIGITMODE

The specified digit mode is invalid.

LINEERR_INVALDIGITS

The specified termination digits are not valid.

LINEERR_INVALFEATURE

The dwFeature parameter is invalid.

LINEERR_INVALGROUPID

The specified group ID is invalid.

LINEERR_INVALLINEHANDLE

The specified call, device, line device, or line handle is invalid.

LINEERR_INVALLINESTATE

The device configuration may not be changed in the current line state. The line may be in use by another application or a dwLineStates parameter contains one or more bits that are not LINEDEVSTATE_ constants. The LINEERR_INVALLINESTATE value can also indicate that the device is DISCONNECTED or OUTOFSERVICE. These states are indicated by setting the bits corresponding to the LINEDEVSTATUSFLAGS_CONNECTED and LINEDEVSTATUSFLAGS_INSERVICE values to 0 in the dwDevStatusFlags member of the LINEDEVSTATUS structure returned by the lineGetLineDevStatus function.

LINEERR_INVALLOCATION

The permanent location ID specified in dwLocation could not be found in any entry in the [Locations] section of TELEPHON.INI.

LINEERR_INVALMEDIALIST

The specified media list is invalid.

LINEERR_INVALMEDIAMODE

The list of media types to be monitored contains invalid information, the specified media mode parameter is invalid, or the service provider does not support the specified media mode. The media modes supported on the line are listed in the dwMediaModes field in the LINEDEVCAPS structure.

LINEERR_INVALMESSAGEID

The number given in dwMessageID is outside the range specified by the dwNumCompletionMessages field in the LINEADDRESSCAPS structure.

LINEERR_INVALPARAM

A parameter (such as dwTollListOption, dwTranslateOptions, dwNumDigits, or a structure pointed to by lpDeviceConfig) contains invalid values, a country code is invalid, a window handle is invalid, or the specified forward list parameter contains invalid information.

LINEERR_INVALPARKMODE

The specified park mode is invalid.

LINEERR_INVALPOINTER

One or more of the specified pointer parameters (such as lpCallList, lpdwAPIVersion, lpExtensionID, lpdwExtVersion, lphIcon, lpLineDevCaps, and lpToneList) are invalid, or a required pointer to an output parameter is NULL.

LINEERR_INVALPRIVSELECT

An invalid flag or combination of flags was set for the dwPrivileges parameter.

LINEERR_INVALRATE

The specified bearer mode is invalid.

LINEERR_INVALREQUESTMODE

The specified request mode is invalid.

LINEERR_INVALTERMINALID

The specified terminal mode parameter is invalid.

LINEERR_INVALTERMINALMODE

The specified terminal modes parameter is invalid.

LINEERR_INVALTIMEOUT

Timeouts are not supported or the values of either or both of the parameters dwFirstDigitTimeout or dwInterDigitTimeout fall outside the valid range specified by the call's line-device capabilities.

LINEERR_INVALTONE

The specified custom tone does not represent a valid tone or is made up of too many frequencies or the specified tone structure does not describe a valid tone.

LINEERR_INVALTONELIST

The specified tone list is invalid.

LINEERR_INVALTONEMODE

The specified tone mode parameter is invalid.

LINEERR_INVALTRANSFERMODE

The specified transfer mode parameter is invalid.

LINEERR_LINEMAPPERFAILED

LINEMAPPER was the value passed in the dwDeviceID parameter, but no lines were found that match the requirements specified in the lpCallParams parameter.

LINEERR_NOCONFERENCE

The specified call is not a conference call handle or a participant call.

LINEERR_NODEVICE

The specified device ID, which was previously valid, is no longer accepted because the associated device has been removed from the system since TAPI was last initialized. Alternately, the line device has no associated device for the given device class.

LINEERR_NODRIVER

Either TAPIADDR.DLL could not be located or the telephone service provider for the specified device found that one of its components is missing or corrupt in a way that was not detected at initialization time. The user should be advised to use the Telephony Control Panel to correct the problem.

LINEERR_NOMEM

Insufficient memory to perform the operation, or unable to lock memory.

LINEERR_NOMULTIPLEINSTANCE

A Telephony Service Provider which does not support multiple instances is listed more than once in the [Providers] section of TELEPHON.INI. The application should advise the user to use the Telephony Control Panel to remove the duplicated driver.

LINEERR_NOREQUEST

There currently is no request pending of the indicated mode, or the application is no longer the highest-priority application for the specified request mode.

LINEERR_NOTOWNER

The application does not have owner privilege to the specified call(s).

LINEERR_NOTREGISTERED

The application is not registered as a request recipient for the indicated request mode.

LINEERR_OPERATIONFAILED

The operation failed for an unspecified or unknown reason.

LINEERR_OPERATIONUNAVAIL

The operation is not available, such as for the given device or specified line.

LINEERR_RATEUNAVAIL

The service provider currently does not have enough bandwidth available for the specified rate.

LINEERR_REINIT

If TAPI reinitialization has been requested, for example as a result of adding or removing a Telephony service provider, then lineInitialize or lineOpen requests are rejected with this error until the last application shuts down its usage of the API (using lineShutdown), at which time the new configuration becomes effective and applications are once again permitted to call lineInitialize.

LINEERR_RESOURCEUNAVAIL

Insufficient resources to complete the operation. For example, a line cannot be opened due to a dynamic resource overcommitment.

LINEERR_STRUCTURETOOSMALL

The dwTotalSize field indicates insufficient space to contain the fixed portion of the specified structure.

LINEERR_TARGETNOTFOUND

A target for the call handoff was not found. This may occur if the named application did not open the same line with the LINECALLPRIVILEGE_OWNER bit in the dwPrivileges parameter of lineOpen. Or, in the case of media-mode handoff, no application has opened the same line with the LINECALLPRIVILEGE_OWNER bit in the dwPrivileges parameter of lineOpen and with the media mode specified in the dwMediaMode parameter having been specified in the dwMediaModes parameter of lineOpen.

LINEERR_TARGETSELF

The application invoking this operation is the target of the indirect handoff.

LINEERR_UNINITIALIZED

The operation was invoked before any application called lineInitialize.

LINEERR_USERUSERINFOTOOBIG

The string containing user-to-user information exceeds the maximum number of bytes specified in the dwUUIAcceptSize, dwUUIAnswerSize, dwUUIDropSize, dwUUIMakeCallSize, or dwUUISendUserUserInfoSize field of LINEDEVCAPS, or the string containing user-to-user information is too long.


Line Device Messages

About Line Device Messages

This chapter contains a list of the messages in the Telephony API. Messages are used to notify the application of the occurrence of asynchronous events. All of these messages are sent to the application-supplied callback function, lineCallbackFunc, in the application's context. When an application uses lineInitialize or phoneInitialize, it specifies a callback function by passing its pointer as a parameter.

The callback message always contains a handle to the relevant object (phone, line, or call). The parameter profile for callbacks contains a multi-purpose handle parameter which is used for passing a handle to the relevant phone, line, or call. The callback function can determine the type of the handle from the message that was passed to the callback.

Certain messages are used to notify the application about a change in an object's status. These messages provide the object handle and give an indication of which status item has changed. The application can call the appropriate "get status" function of the object to obtain the object's full status.

When an event occurs, messages or callbacks may be sent to zero, one, or more applications. The target applications for a message are determined by a number of different factors including the meaning of the message, the application's privilege to the object, whether or not the application initiated the request for which the message is a direct result, and the message masking that has been set by the application. Note the following points about messages:

•	Asynchronous reply messages are only sent to the application that originated the request and cannot be masked.

•	Messages that signal the completion of digit or tone generation or the gathering of digits are only sent to the application that requested the digit or tone generation.

•	Messages that indicate line or address state changes are sent to all applications that have opened the line.

•	Messages that indicate call state and call information changes are sent to all applications that are owners for the call and to monitoring applications that have not masked these messages.

•	Messages that signal a digit detection, tone detection, or media mode detection are sent to all applications (owners or monitors) that have not masked the event.

For more information about the lineCallbackFunc function, see Chapter 10, "Line Device Functions."


Reference

Following are the Telephony API messages.


LINE_ADDRESSSTATE

[New - Windows 95]

LINE_ADDRESSSTATE
dwDevice = (DWORD) hLine;
dwCallbackInstance = (DWORD) hCallback;
dwParam1 = (DWORD) idAddress;
dwParam2 = (DWORD) AddressState;
dwParam3 = (DWORD) 0;

Sent when the status of an address changes on a line that is currently open by the application. The application can invoke lineGetAddressStatus to determine the current status of the address.

•	No return value.

dwDevice

Specifies a handle to the line device.

dwCallbackInstance

Specifies the callback instance supplied when opening the line.

dwParam1

Specifies the address ID of the address that changed status.

dwParam2

Specifies the address state that changed. Can be a combination of these values:

LINEADDRESSSTATE_OTHER

Address-status items other than those listed below have changed. The application should check the current address status to determine which items have changed.

LINEADDRESSSTATE_DEVSPECIFIC

The device-specific item of the address status has changed.

LINEADDRESSSTATE_INUSEZERO

The address has changed to idle (it is now in use by zero stations).

LINEADDRESSSTATE_INUSEONE

The address has changed from idle or from being used by many bridged stations to being used by just one station.

LINEADDRESSSTATE_INUSEMANY

The monitored or bridged address has changed from being used by one station to being used by more than one station.

LINEADDRESSSTATE_NUMCALLS

The number of calls on the address has changed. This is the result of events such as a new inbound call, an outbound call on the address, or a call changing its hold status.

LINEADDRESSSTATE_FORWARD

The forwarding status of the address has changed, including the number of rings for determining a no answer condition. The application should check the address status to determine details about the address's current forwarding status.

LINEADDRESSSTATE_TERMINALS

The terminal settings for the address have changed.

LINEADDRESSSTATE_CAPSCHANGE

Indicates that, due to configuration changes made by the user or other circumstances, one or more of the fields in the LINEADDRESSCAPS structure for the address have changed. The application should use lineGetAddressCaps to read the updated structure. Applications which support API versions less than 0x00010004 will receive a LINEDEVSTATE_REINIT message, requiring them to shutdown and reinitialize their connection to TAPI in order to obtain the updated information.

dwParam3

Unused.

This message is sent to any application that has opened the line device and that has enabled this message. The sending of this message for the various status items can be controlled and queried using lineGetStatusMessages and lineSetStatusMessages. By default, address status reporting is disabled.


LINE_CALLINFO

[New - Windows 95]

LINE_CALLINFO
dwDevice = (DWORD) hCall;
dwCallbackInstance = (DWORD) hCallback;
dwParam1 = (DWORD) CallInfoState;
dwParam2 = (DWORD) 0;
dwParam3 = (DWORD) 0;

Sent when the call information about the specified call has changed. The application can invoke lineGetCallInfo to determine the current call information.

•	No return value.

dwDevice

Specifies a handle to the call.

dwCallbackInstance

Specifies the callback instance supplied when opening the call's line.

dwParam1

Specifies the call information item that has changed. Can be a combination of these values:

LINECALLINFOSTATE_OTHER

Information items other than those listed below have changed. The application should check the current call information to determine which items have changed.

LINECALLINFOSTATE_DEVSPECIFIC

The device-specific field of the call-information record has changed.

LINECALLINFOSTATE_BEARERMODE

The bearer mode field of the call-information record has changed.

LINECALLINFOSTATE_RATE

The rate field of the call-information record has changed.

LINECALLINFOSTATE_MEDIAMODE

The media mode field of the call-information record has changed.

LINECALLINFOSTATE_APPSPECIFIC

The application-specific field of the call-information record has changed.

LINECALLINFOSTATE_CALLID

The call ID field of the call-information record has changed.

LINECALLINFOSTATE_RELATEDCALLID

The related call ID field of the call-information record has changed.

LINECALLINFOSTATE_ORIGIN

The origin field of the call-information record has changed.

LINECALLINFOSTATE_REASON

The reason field of the call-information record has changed.

LINECALLINFOSTATE_COMPLETIONID

The completion ID field of the call-information record has changed.

LINECALLINFOSTATE_NUMOWNERINCR

The number of owner fields in the call-information record was increased.

LINECALLINFOSTATE_NUMOWNERDECR

The number of owner fields in the call-information record was decreased.

LINECALLINFOSTATE_NUMMONITORS

The number of monitors fields in the call-information record has changed.

LINECALLINFOSTATE_TRUNK

The trunk field of the call-information record has changed.

LINECALLINFOSTATE_CALLERID

One of the callerID-related fields of the call-information record has changed.

LINECALLINFOSTATE_CALLEDID

One of the calledID-related fields of the call-information record has changed.

LINECALLINFOSTATE_CONNECTEDID

One of the cconnectedID-related fields of the call-information record has changed.

LINECALLINFOSTATE_REDIRECTIONID

One of the redirectionID-related fields of the call-information record has changed.

LINECALLINFOSTATE_REDIRECTINGID

One of the redirectingID-related fields of the call-information record has changed.

LINECALLINFOSTATE_DISPLAY

The display field of the call-information record has changed.

LINECALLINFOSTATE_USERUSERINFO

The user-to-user information of the call-information record has changed.

LINECALLINFOSTATE_HIGHLEVELCOMP

The high-level compatibility field of the call-information record has changed.

LINECALLINFOSTATE_LOWLEVELCOMP

The low-level compatibility field of the call-information record has changed.

LINECALLINFOSTATE_CHARGINGINFO

The charging information of the call-information record has changed.

LINECALLINFOSTATE_TERMINAL

The terminal mode information of the call-information record has changed.

LINECALLINFOSTATE_DIALPARAMS

The dial parameters of the call-information record has changed.

LINECALLINFOSTATE_MONITORMODES

One or more of the digit, tone, or media monitoring fields in the call-information record has changed.

dwParam2

Unused.

dwParam3

Unused.

A LINE_CALLINFO message with a NumOwnersIncr, NumOwnersDecr, and/or NumMonitorsChanged indication is sent to applications that already have a handle for the call. This can be the result of another application changing ownership or monitorship to a call with  lineOpen, lineClose, lineShutdown, lineSetCallPrivilege, lineGetNewCalls, and lineGetConfRelatedCalls.

These LINE_CALLINFO messages are not sent when a notification of a new call is provided in a LINE_CALLSTATE message, since the call information already reflects the correct number of owners and monitors at the time the LINE_CALLSTATE messages are sent. LINE_CALLINFO messages are also suppressed in the case where a call is offered by TAPI to monitors through the LINECALLSTATE_UNKNOWN mechanism.

Note also that the application which causes a change in the number of owners or monitors (for example, by invoking lineDeallocateCall or lineSetCallPrivilege) will not itself receive a message indicating that the change has been done.

No LINE_CALLINFO messages are sent for a call after the call has entered the idle state. Specifically, changes in the number of owners and monitors are not reported as applications deallocate their handles for the idle call.


LINE_CALLSTATE

[New - Windows 95]

LINE_CALLSTATE
dwDevice = (DWORD) hCall;
dwCallbackInstance = (DWORD) hCallback;
dwParam1 = (DWORD) CallState;
dwParam2 = (DWORD) CallStateDetail;
dwParam3 = (DWORD) CallPrivilege;

Sent when the status of the specified call has changed. Several such messages will typically be received during the lifetime of a call. Applications are notified of new incoming calls with this message; the new call will be in the offering state. The application can use lineGetCallStatus to retrieve more detailed information about the current status of the call.

•	No return value.

dwDevice

Specifies a handle to the call.

dwCallbackInstance

Specifies the callback instance supplied when opening the call's line.

dwParam1

Specifies the new call state. This parameter must be one and only one of the following LINECALLSTATE_ values:

LINECALLSTATE_IDLE

The call is idle—no call actually exists.

LINECALLSTATE_OFFERING

The call is being offered to the station, signaling the arrival of a new call. In some environments, a call in the offering state does not automatically alert the user. Alerting is done by the switch instructing the line to ring; it does not affect any call states.

LINECALLSTATE_ACCEPTED

The call was offering and has been accepted. This indicates to other (monitoring) applications that the current owner application has claimed responsibility for answering the call. In ISDN, this also indicates that alerting to both parties has started.

LINECALLSTATE_DIALTONE

The call is receiving a dial tone from the switch, which means that the switch is ready to receive a dialed number.

LINECALLSTATE_DIALING

Destination address information (a phone number) is being sent to the switch over the call. Note that lineGenerateDigits does not place the line into the dialing state.

LINECALLSTATE_RINGBACK

The call is receiving ringback from the called address. Ringback indicates that the other station has been reached and is being alerted.

LINECALLSTATE_BUSY

The call is receiving a busy tone. Busy tone indicates that the call cannot be completed—either a circuit (trunk) or the remote party's station are in use.

LINECALLSTATE_SPECIALINFO

Special information is sent by the network. Special information is typically sent when the destination cannot be reached.

LINECALLSTATE_CONNECTED

The call has been established and the connection is made. Information is able to flow over the call between the originating address and the destination address.

LINECALLSTATE_PROCEEDING

Dialing has completed and the call is proceeding through the switch or telephone network.

LINECALLSTATE_ONHOLD

The call is on hold by the switch.

LINECALLSTATE_CONFERENCED

The call is currently a member of a multi-party conference call.

LINECALLSTATE_ONHOLDPENDCONF

The call is currently on hold while it is being added to a conference.

LINECALLSTATE_ONHOLDPENTRANSFER

The call is currently on hold awaiting transfer to another number.

LINECALLSTATE_DISCONNECTED

The remote party has disconnected from the call.

LINECALLSTATE_UNKNOWN

The state of the call is not known. This may be due to limitations of the call-progress detection implementation.

dwParam2

Specifies call-state-dependent information.

If dwParam1 is LINECALLSTATE_BUSY, dwParam2 contains details about the busy mode. This parameter uses the following LINEBUSYMODE_ constants:

LINEBUSYMODE_STATION

The busy signal indicates that the called party's station is busy. This is usually signaled by means of a "normal" busy tone.

LINEBUSYMODE_TRUNK

The busy signal indicates that a trunk or circuit is busy. This is usually signaled with a "long" busy tone.

LINEBUSYMODE_UNKNOWN

The busy signal's specific mode is currently unkown, but may become known later.

LINEBUSYMODE_UNAVAIL

The busy signal's specific mode is unavailable and will not become known.

If dwParam1 is LINECALLSTATE_DIALTONE, dwParam2 contains the details about the dialtone mode. This parameter uses the following LINEDIALTONEMODE_ constants:

LINEDIALTONEMODE_NORMAL

This is a "normal" dialtone, which typically is a continuous tone.

LINEDIALTONEMODE_SPECIAL

This is a special dialtone indicating that a certain condition is currently in effect.

LINEDIALTONEMODE_INTERNAL

This is an internal dialtone, as within a PBX.

LINEDIALTONEMODE_EXTERNAL

This is an external (public network) dialtone.

LINEDIALTONEMODE_UNKNOWN

The dialtone mode is currently unknown, but may become known later.

LINEDIALTONEMODE_UNAVAIL

The dialtone mode is unavailable and will not become known.

If dwParam1 is LINECALLSTATE_SPECIALINFO, dwParam2 contains the details about the special information mode. This parameter uses the following LINESPECIALINFO_ constants:

LINESPECIALINFO_NOCIRCUIT

This special information tone preceeds a "no circuit" or emergency announcement (trunk blockage category).

LINESPECIALINFO_CUSTIRREG

This special information tone preceeds a vacant number, AIS, Centrex number change and non-working station, access code not dialed or dialed in error, or manual intercept operator message (customer irregularity category).

LINESPECIALINFO_REORDER

This special information tone preceeds a reorder announcement (equipment irregularity category).

LINESPECIALINFO_UNKNOWN

Specifics about the special information tone are currently unknown but may become known later.

LINESPECIALINFO_UNAVAIL

Specifics about the special information tone are unavailable and will not become known.

If dwParam1 is LINECALLSTATE_DISCONNECTED, dwParam2 contains details about the disconnect mode. This parameter uses the following LINEDISCONNECTMODE_ constants:

LINEDISCONNECTMODE_NORMAL

This is a "normal" disconnect request by the remote party, the call was terminated normally.

LINEDISCONNECTMODE_UNKNOWN

The reason for the disconnect request is unknown.

LINEDISCONNECTMODE_REJECT

The remote user has rejected the call.

LINEDISCONNECTMODE_PICKUP

The call was picked up from elsewhere.

LINEDISCONNECTMODE_FORWARDED

The call was forwarded by the switch.

LINEDISCONNECTMODE_BUSY

The remote user's station is busy.

LINEDISCONNECTMODE_NOANSWER

The remote user's station does not answer.

LINEDISCONNECTMODE_BADADDRESS

The destination address in invalid.

LINEDISCONNECTMODE_UNREACHABLE

The remote user could not be reached.

LINEDISCONNECTMODE_CONGESTION

The network is congested.

LINEDISCONNECTMODE_INCOMPATIBLE

The remote user's station equipment is incompatible for the type of call requested.

LINEDISCONNECTMODE_UNAVAIL

The reason for the disconnect is unavailable and will not become known later.

If dwParam1 is LINECALLSTATE_CONFERENCED, dwParam2 contains the hConfCall of the parent call of the conference of which the subject hCall is a member. If the call specified in dwParam2 was not previously considered by the application to be a parent conference call (hConfCall), the application must do so as a result of this message. If the application does not have a handle to the parent call of the conference (because it has previously called lineDeallocateCall on that handle, dwParam2 will be set to null.)

dwParam3

If zero, this parameter indicates that there has been no change in the application's privilege for the call.

If non-zero, it specifies the application's privilege to the call. This will occur in the following situations: (1) The first time that the application is given a handle to this call; (2) When the application is the target of a call handoff (even if the application already was an owner of the call). This parameter uses the following LINECALLPRIVILEGE_ constants:

LINECALLPRIVILEGE_MONITOR

The application has monitor privilege.

LINECALLPRIVILEGE_OWNER

The application has owner privilege.

This message is sent to any application that has a handle for the call. Note that the LINE_CALLSTATE message also notifies applications that monitor calls on a line about the existence and state of outbound calls established by other applications or manually by the user (for example, on an attached phone device). The call state of such calls reflects the actual state of the call, which will not be offering. By examining the call state, the application can determine whether the call is an inbound call that needs to be answered or not.

A LINE_CALLSTATE message with an unknown call state may be sent to a monitoring application as the result of a successful lineMakeCall, lineForward, lineUnpark, lineSetupTransfer,  linePickup, lineSetupConference, or linePrepareAddToConference that has been requested by another application. At the same time that the requesting application is sent a LINE_REPLY (success) for the requested operation, any monitoring applications on the line will be sent the LINE_CALLSTATE (unknown) message. A LINE_CALLSTATE indicating the "real" call state of the newly generated call will be sent (using information provided by the service provider) to the requesting and monitoring applications shortly thereafter.

A LINE_CALLSTATE (unknown) message is sent to monitoring applications only if lineCompleteTransfer causes calls to be resolved into a three-way conference.

For backward compatibility, older applications will not be expecting any particular value in dwParam2 of a LINECALLSTATE_CONFERENCED message. TAPI will therefore pass the parent call hConfCall in dwParam2 regardles of the API version of the application receiving the message. In the case of a conference call initiated by the service provider, the older application will not be aware that the parent call has become a conference call unless it happens to spontaneously examine other information (e.g., call lineGetConfRelatedCalls)

The LINE_CALLSTATE message may receive the LINECONNECTEDMODE_ACTIVE or LINECONNECTEDMODE_INACTIVE and the LINEOFFERINGMODE_ACTIVE or LINEOFFERINGMODE_INACTIVE values depending on the state of the corresponding call.

This message cannot be disabled.


LINE_CLOSE

[New - Windows 95]

LINE_CLOSE
dwDevice = (DWORD) hLine;
dwCallbackInstance = (DWORD) hCallback;
dwParam1 = (DWORD) 0;
dwParam2 = (DWORD) 0;
dwParam3 = (DWORD) 0;

Sent when the specified line device has been forcibly closed. The line device handle or any call handles for calls on the line are no longer valid once this message has been sent.

•	No return value.

dwDevice

Specifies a handle to the line device that was closed. This handle is no longer valid.

dwCallbackInstance

Specifies the callback instance supplied when opening the line.

dwParam1

Unused.

dwParam2

Unused.

dwParam3

Unused.

This message is only sent to any application after an open line has been forcibly closed. This may be done to prevent a single application from monopolizing a line device for too long. Whether or not the line can be reopened immediately after a forced close is device-specific.

A line device may also be forcibly closed after the user has modified the configuration of that line or its driver. If the user wants the configuration changes to be effective immediately (as opposed to after the next system restart), and they affect the application's current view of the device (such as a change in device capabilities), then a service provider may forcibly close the line device.


LINE_CREATE

[New - Windows 95]

dwDevice = (DWORD) 0;
dwCallbackInstance = (DWORD) 0;
dwParam1 = (DWORD) idDevice;
dwParam2 = (DWORD) 0;
dwParam3 = (DWORD) 0;

Sent to inform the application of the creation of a new line device.

•	No return value.

dwDevice

Unused.

dwCallbackInstance

Unused.

dwParam1

Specifies the dwDeviceID of the newly-created device.

dwParam2

Unused.

dwParam3

Unused.

Older applications (which negotiated an API version prior to the creation of this feature) are sent a LINE_LINEDEVSTATE message specifying LINEDEVSTATE_REINIT, which requires them to shut down their use of the API and call lineInitialize again to obtain the new number of devices. Unlike previous versions of TAPI, however, this version does not require all applications to shut down before allowing applications to reinitialize; reinitialization can take place immediately when a new device is created (complete shutdown is still required when a service provider is removed from the system).

Applications supporting this and subsequent versions of the API are sent a LINE_CREATE message. This informs them of the existence of the new device and its new device ID. The application can then choose whether or not to attempt working with the new device at its leisure. This message will be sent to all applications supporting this or subsequent versions of the API which have called lineInitialize, including those that do not have any line devices open at the time.

Although TAPI ordinarily sends the LINE_CREATE message when an application creates a line, it will instead send the LINE_LINEDEVSTATE message with the LINEDEVSTATE_REINIT value set if the application is creating its first line and has not yet called the lineNegotiateAPIVersion or other function to set the API version. In such cases, TAPI assumes that the application is an old version and can not correctly process the LINE_CREATE message.


LINE_DEVSPECIFIC

[New - Windows 95]

LINE_DEVSPECIFIC
dwDevice = (DWORD) hLineOrCall;
dwCallbackInstance = (DWORD) hCallback;
dwParam1 = (DWORD) DeviceSpecific1;
dwParam2 = (DWORD) DeviceSpecific2;
dwParam3 = (DWORD) DeviceSpecific3;

Sent to notify the application about device-specific events occurring a line, address or call. The meaning of the message and the interpretation of the parameters is device specific.

•	No return value.

dwDevice

Specifies a handle to either a line device or call. This is device specific.

dwCallbackInstance

Specifies the callback instance supplied when opening the line.

dwParam1

Device specific.

dwParam2

Device specific.

dwParam3

Device specific.

This message is used by a service provider in conjunction with the lineDevSpecific function. Its meaning is device specific.


LINE_DEVSPECIFICFEATURE

[New - Windows 95]

LINE_DEVSPECIFICFEATURE
dwDevice = (DWORD) hLineOrCall;
dwCallbackInstance = (DWORD) hCallback;
dwParam1 = (DWORD) DeviceSpecific1;
dwParam2 = (DWORD) DeviceSpecific2;
dwParam3 = (DWORD) DeviceSpecific3;

Sent to notify the application about device-specific events occurring on a line, address or call. The meaning of the message and the interpretation of the parameters is device specific.

•	No return value.

dwDevice

Specifies a handle to either a line device or call. This is device specific.

dwCallbackInstance

Specifies the callback instance supplied when opening the line.

dwParam1

Device specific.

dwParam2

Device specific.

dwParam3

Device specific.

This message is used by a service provider in conjunction with the lineDevSpecificFeature function. Its meaning is device specific.


LINE_GATHERDIGITS

[New - Windows 95]

LINE_GATHERDIGITS
dwDevice = (DWORD) hCall;
dwCallbackInstance = (DWORD) hCallback;
dwParam1 = (DWORD) GatherTermination;
dwParam2 = (DWORD) 0;
dwParam3 = (DWORD) 0;

Sent when the current buffered digit-gathering request has terminated or is canceled. The digit buffer may be examined after this message has been received by the application.

•	No return value.

dwDevice

Specifies a handle to the call.

dwCallbackInstance

Specifies the callback instance supplied when opening the line.

dwParam1

Specifies the reason why digit gathering was terminated. This parameter must be one and only one of the following LINEGATHERTERM_ constants:

LINEGATHERTERM_BUFFERFULL

The requested number of digits has been gathered. The buffer is full.

LINEGATHERTERM_TERMDIGIT

One of the termination digits matched a received digit. The matched termination digit is the last digit in the buffer.

LINEGATHERTERM_FIRSTTIMEOUT

The first digit timeout expired. The buffer contains no digits.

LINEGATHERTERM_INTERTIMEOUT

The inter-digit timeout expired. The buffer contains at least one digit.

LINEGATHERTERM_CANCEL

The request was canceled by this application, by another application, or because the call terminated.

dwParam2

Unused.

dwParam3

Unused.

This message is only sent to the application that initiated the digit gathering on the call using lineGatherDigits.

If the lineGatherDigits function is used to cancel a previous request to gather digits, TAPI sends a LINE_GATHERDIGITS message with dwParam1 set to LINEGATHERTERM_CANCEL to the application indicating that originally specified buffer contains the digits gathered up to the cancellation.


LINE_GENERATE

[New - Windows 95]

LINE_GENERATE
dwDevice = (DWORD) hCall;
dwCallbackInstance = (DWORD) hCallback;
dwParam1 = (DWORD) GenerateTermination;
dwParam2 = (DWORD) 0;
dwParam3 = (DWORD) 0;

Sent to notify the application that the current digit or tone generation has terminated. Note that only one such generation request can be in progress an a given call at any time. This message is also sent when digit or tone generation is canceled.

•	No return value.

dwDevice

Specifies a handle to the call.

dwCallbackInstance

Specifies the callback instance supplied when opening the line.

dwParam1

Specifies the reason why digit or tone generation was terminated. This parameter must be one and only one of the following LINEGENERATETERM_ constants:

LINEGENERATETERM_DONE

The requested number of digits have been generated, or the requested tones have been generated for the requested duration.

LINEGENERATETERM_CANCEL

The digit or tone generation request was canceled by this application, by another application, or because the call terminated.

dwParam2

Unused.

dwParam3

Unused.

This message is only sent to the application that requested the digit or tone generation.


LINE_LINEDEVSTATE

[New - Windows 95]

LINE_LINEDEVSTATE
dwDevice = (DWORD) hLine;
dwCallbackInstance = (DWORD) hCallback;
dwParam1 = (DWORD) DeviceState;
dwParam2 = (DWORD) DeviceStateDetail1;
dwParam3 = (DWORD) DeviceStateDetail2;

Sent when the state of a line device has changed. The application can invoke lineGetLineDevStatus to determine the new status of the line.

•	No return value.

dwDevice

Specifies a handle to the line device. This parameter is NULL when dwParam1 is LINEDEVSTATE_REINIT.

dwCallbackInstance

Specifies the callback instance supplied when opening the line. If the dwParam1 parameter is LINEDEVSTATE_REINIT, the dwCallbackInstance parameter is not valid and is set to zero.

dwParam1

Specifies the line device status item that has changed. The parameter can be a combination of the following LINEDEVSTATE_ constants:

LINEDEVSTATE_OTHER

Device-status items other than those listed below have changed. The application should check the current device status to determine which items have changed.

LINEDEVSTATE_RINGING

The switch tells the line to alert the user.

LINEDEVSTATE_CONNECTED

The line was previously disconnected and is now connected to TAPI.

LINEDEVSTATE_DISCONNECTED

This line was previously connected and is now disconnected from TAPI.

LINEDEVSTATE_MSGWAITON

The "message waiting" indicator is turned on.

LINEDEVSTATE_MSGWAITOFF

The "message waiting" indicator is turned off.

LINEDEVSTATE_NUMCOMPLETIONS

The number of outstanding call completions on the line device has changed.

LINEDEVSTATE_INSERVICE

The line is connected to TAPI. This happens when TAPI is first activated, or when the line wire is physically plugged in and in service at the switch while TAPI is active.

LINEDEVSTATE_OUTOFSERVICE

The line is out of service at the switch or physically disconnected. TAPI cannot be used to operate on the line device.

LINEDEVSTATE_MAINTENANCE

Mainatenance is being performed on the line at the switch. TAPI cannot be used to operate on the line device.

LINEDEVSTATE_OPEN

The line has been opened by another application.

LINEDEVSTATE_CLOSE

The line has been closed by another application.

LINEDEVSTATE_NUMCALLS

The number of calls on the line device has changed.

LINEDEVSTATE_TERMINALS

The terminal settings have changed.

LINEDEVSTATE_ROAMMODE

The roaming state of the line device has changed.

LINEDEVSTATE_BATTERY

The battery level has changed significantly (cellular).

LINEDEVSTATE_SIGNAL

The signal level has changed significantly (cellular).

LINEDEVSTATE_DEVSPECIFIC

The line's device-specific information has changed.

LINEDEVSTATE_REINIT

Items have changed in the configuration of line devices. To become aware of these changes (as with the appearance of new line devices), the application should reinitialize its use of TAPI. The dwDevice parameter is left NULL for this state change as it applies to any of the lines in the system. This message with the LINEDEVSTATE_REINIT bit set is only sent to applications that have opened a line. That is, if an application has only called lineInitialize but has not yet opened any device, and a LINEDEVSTATE_REINIT message is sent, this message is not sent to that application.

LINEDEVSTATE_LOCK

The locked status of the line device has changed. (For more information, refer to the description of the LINEDEVSTATUSFLAGS_LOCKED bit of the LINEDEVSTATUSFLAGS_ constants.)

LINEDEVSTATE_CAPSCHANGE

Indicates that, due to configuration changes made by the user or other circumstances, one or more of the fields in the LINEDEVCAPS structure for the address have changed. The application should use lineGetDevCaps to read the updated structure.

LINEDEVSTATE_CONFIGCHANGE

Indicates that configuration changes have been made to one or more of the media devices associated with the line device. The application, if it desires, may use lineGetDevConfig to read the updated information.

LINEDEVSTATE_TRANSLATECHANGE

Indicates that, due to configuration changes made by the user or other circumstances, one or more of the fields in the LINETRANSLATECAPS structure have changed. The application should use lineGetTranslateCaps to read the updated structure.

LINEDEVSTATE_COMPLCANCEL

Indicates that the call completion identified by the completion ID contained in parameter dwParam2 of the LINE_LINEDEVSTATE message has been externally cancelled and is no longer considered valid (if that value were to be passed in a subsequent call to lineUncompleteCall, the function would fail with LINEERR_INVALCOMPLETIONID).

dwParam2

The interpretation of this parameter depends on the value of dwParam1. If dwParam1 is LINEDEVSTATE_RINGING, dwParam2 contains the ring mode with which the switch instructs the line to ring. Valid ring modes are numbers in the range one to dwNumRingModes, where dwNumRingModes is a line device capability.

If dwParam1 is LINEDEVSTATE_REINIT, and the message was issued by TAPI as a result of translation of a new API message into a REINIT message, then dwParam2 contains the dwMsg parameter of the original message (e.g., LINE_CREATE or LINE_LINEDEVSTATE). If dwParam2 is zero, this indicates that the REINIT message is a "real" REINIT message that requires the application to call lineShutdown at its earliest convenience.

dwParam3

The interpretation of this parameter depends on the value of dwParam1. If dwParam1 is LINEDEVSTATE_RINGING, dwParam3 contains the ring count for this ring event. The ring count starts at zero.

If dwParam1 is LINEDEVSTATE_REINIT, and the message was issued by TAPI as a result of translation of a new API message into a REINIT message, then dwParam3 contains the dwParam1 parameter of the original message (e.g., LINEDEVSTATE_TRANSLATECHANGE or some other LINEDEVSTATE_ value, if dwParam2 is LINE_LINEDEVSTATE, or the new device ID, if dwParam2 is LINE_CREATE).

The sending of this message can be controlled with lineSetStatusMessages. An application can indicate status item changes about which it wants to be notified. By default, all status reporting will be disabled except for LINEDEVSTATE_REINIT, which cannot be disabled. This message is sent to all applications that have a handle to the line, including those that called lineOpen with the dwPrivileges parameter set to LINECALLPRIVILEGE_NONE, LINECALLPRIVILEGE_OWNER, LINECALLPRIVILEGE_MONITOR, or permitted combinations of these.


LINE_MONITORDIGITS

[New - Windows 95]

LINE_MONITORDIGITS
dwDevice = (DWORD) hCall;
dwCallbackInstance = (DWORD) hCallback;
dwParam1 = (DWORD) Digit;
dwParam2 = (DWORD) DigitMode;
dwParam3 = (DWORD) 0;

Sent when a digit is detected. The sending of this message is controlled with the lineMonitorDigits function.

•	No return value.

dwDevice

Specifies a handle to the call.

dwCallbackInstance

Specifies the callback instance supplied when opening the call's line.

dwParam1

The low-order byte contains the last digit received in ASCII.

dwParam2

Specifies the digit mode that was detected. This parameter must be one and only one of the following LINEDIGITMODE_ constants:

LINEDIGITMODE_PULSE

Detect digits as audible clicks that are the result of rotary pulse sequences. Valid digits for pulse are '0' through '9'.

LINEDIGITMODE_DTMF

Detect digits as DTMF tones. Valid digits for DTMF are '0' through '9', 'A', 'B', 'C', 'D', '*', and '#'.

LINEDIGITMODE_DTMFEND

Detect and provide application notification of DTMF down edges. Valid digits for DTMF are '0' through '9', 'A', 'B', 'C', 'D', '*', and '#'.

dwParam3

Unused.

This message is sent to the application that has enabled digit monitoring.


LINE_MONITORMEDIA

[New - Windows 95]

LINE_MONITORMEDIA
dwDevice = (DWORD) hCall;
dwCallbackInstance = (DWORD) hCallback;
dwParam1 = (DWORD) MediaMode;
dwParam2 = (DWORD) 0;
dwParam3 = (DWORD) 0;

Sent when a change in the call's media mode is detected. The sending of this message is controlled with the lineMonitorMedia function.

•	No return value.

dwDevice

Specifies a handle to the call.

dwCallbackInstance

Specifies the callback instance supplied when opening the line.

dwParam1

Specifies the new media mode. This parameter must be one and only one of the following LINEMEDIAMODE_ constants:

LINEMEDIAMODE_INTERACTIVEVOICE

The presence of voice energy has been detected and the call is treated as an interactive call with humans on both ends.

LINEMEDIAMODE_AUTOMATEDVOICE

The presence of voice energy has been detected and the call is locally handled by an automated application.

LINEMEDIAMODE_DATAMODEM

A datamodem session has been detected.

LINEMEDIAMODE_G3FAX

A group 3 fax has been detected.

LINEMEDIAMODE_TDD

A TDD (Telephony Devices for the Deaf) session has been detected.

LINEMEDIAMODE_G4FAX

A group 4 fax has been detected.

LINEMEDIAMODE_DIGITALDATA

Digital data has been detected.

LINEMEDIAMODE_TELETEX

A teletex session has been detected. Teletex is one of the telematic services.

LINEMEDIAMODE_VIDEOTEX

A videotex session has been detected. Videotex is one the telematic services.

LINEMEDIAMODE_TELEX

A telex session has been detected. Telex is one the telematic services.

LINEMEDIAMODE_MIXED

A mixed session has been detected. Mixed is one the telematic services.

LINEMEDIAMODE_ADSI

An ADSI (Analog Display Services Interface) session has been detected.

LINEMEDIAMODE_VOICEVIEW

The media mode of the call is VoiceView.

dwParam2

Unused.

dwParam3

Unused.

This message is sent to the application that has enabled media monitoring for the media mode detected.


LINE_MONITORTONE

[New - Windows 95]

LINE_MONITORTONE
dwDevice = (DWORD) hCall;
dwCallbackInstance = (DWORD) hCallback;
dwParam1 = (DWORD) dwAppSpecific;
dwParam2 = (DWORD) 0;
dwParam3 = (DWORD) 0;

Sent when a tone is detected. The sending of this message is controlled with the lineMonitorTones function.

•	No return value.

dwDevice

Specifies a handle to the call.

dwCallbackInstance

Specifies the callback instance supplied when opening the call's line.

dwParam1

Specifies the application-specific dwAppSpecific field of the LINEMONITORTONE structure for the tone that was detected.

dwParam2

Unused.

dwParam3

Unused.

This message is only sent to the application that has requested the tone be monitored.


LINE_REPLY

[New - Windows 95]

LINE_REPLY
dwDevice = (DWORD) 0;
dwCallbackInstance = (DWORD) hCallback;
dwParam1 = (DWORD) idRequest;
dwParam2 = (DWORD) Status;
dwParam3 = (DWORD) 0;

Sent to report the results of function calls that completed asynchronously.

•	No return value.

dwDevice

Not used.

dwCallbackInstance

Returns the application's callback instance.

dwParam1

Specifies the request ID for which this is the reply.

dwParam2

Specifies the success or error indication. The application should cast this parameter into a LONG. Zero indicates success; a negative number indicates an error.

dwParam3

Unused.

Functions that operate asynchronously return a positive request ID value to the application. This request ID is returned with the reply message to identify the request that was completed. The other parameter for this message carries the success or failure indication. Possible errors are the same as those defined by the corresponding function. This message cannot be disabled.

In some cases, an application may fail to receive the LINE_REPLY message corresponding to a call to an asynchronous function. This occurs if the corresponding call handle is deallocated before the message has been received.


LINE_REQUEST

[New - Windows 95]

LINE_REQUEST
dwDevice = (DWORD) 0;
dwCallbackInstance = (DWORD) hRegistration;
dwParam1 = (DWORD) RequestMode;
dwParam2 = (DWORD) RequestModeDetail1;
dwParam3 = (DWORD) RequestModeDetail2;

Sent report the arrival of a new request from another application.

•	No return value.

dwDevice

Not used.

dwCallbackInstance

Specifies the registration instance of the application specified on lineRegisterRequestRecipient.

dwParam1

Specifies the request mode of the newly pending request. This parameter uses the following LINEREQUESTMODE_ constants:

LINEREQUESTMODE_MAKECALL

A tapiRequestMakeCall request.

dwParam2

If dwParam1 is set to LINEREQUESTMODE_DROP, dwParam2 contains the hWnd of the application requesting the drop. Otherwise, dwParam2 is unused.

dwParam3

If dwParam1 is set to LINEREQUESTMODE_DROP, the low-order word of dwParam3 contains the wRequestID as specified by the application requesting the drop. Otherwise, dwParam3 is unused.

This message is sent to the highest priority application that has registered for the corresponding request mode. This callback message indicates the arrival of an Assisted Telephony request of the specified request mode. If dwParam1 is LINEREQUESTMODE_MAKECALL or LINEREQUESTMODE_MEDIACALL, the application can invoke lineGetRequest using the corresponding request mode to receive the request. If dwParam1 is LINEREQUESTMODE_DROP, the message contains all of the information the request recipient needs in order to perform the request.


Line Device Structures

About Line Device Structures

This chapter describes the data structures used by the Telephony API. They are listed in alphabetical order.


Memory Allocation

Memory for all data structures used by the API must be allocated by the application. The application passes a pointer to the API function that returns the information and the function fills the data structure with the requested information. If the operation is asynchonous, then the information is not available until the asynchonous reply message indicates success.

All data structures used to pass information between the application and the Telephony API are "flattened." This means that data structures do not contain pointers to substructures that contain variably sized components of information. Instead, data structures that are used to pass variable amounts of information back to the application have the following meta structure:

  DWORD  dwTotalSize;
  DWORD  dwNeededSize;
  DWORD  dwUsedSize;

    <fixed size fields>

  DWORD  dw<VarSizeField1>Size;
  DWORD  dw<VarSizeField1>Offset;

    <fixed size fields>

  DWORD  dw<VarSizeField2>Size;
  DWORD  dw<VarSizeField2>Offset;

    <common extensions>

    <var sized field1>

    <var sized field2>

The dwTotalSize field is the size in bytes allocated to this data structure. It marks the end of the data structure and is set by the application before it invokes the function that uses this data structure. The function will not read or write beyond this size. An application must set the dwTotalSize field to indicate the total number of bytes allocated for TAPI.DLL to return the contents of the structure.

The dwNeededSize field is filled in by TAPI.DLL. It indicates how many bytes are needed to return all the information requested. The existence of variably sized fields often makes it impossible for the application to estimate the data structure size it needs to allocate. This field simply returns the number of bytes actually needed for the infomation. This number could be smaller than, equal to, or larger than dwTotalSize, and it includes space for the dwTotalSize field itself. If larger, the returned structure is only partially filled. If the fields the application is interested in are available in the partial structure, nothing else must be done. Otherwise, the application should allocate a structure at least the size of dwNeededSize and invoke the function again. Usually, enough space will be available this time to return all the information, although it is possible the size could have increased again.

The dwUsedSize field is filled in by TAPI if it returns information to the application to indicate the actual size in bytes of the portion of the data structure that contains useful information. If, for example, a structure was allocated too small and the truncated field is a variably sized field, dwNeededSize will be larger than dwTotalSize, and the truncated field will be left empty. The dwUsedSize field could therefore be smaller than dwTotalSize. Partial field values are not returned.

Following this header is the fixed part of the data structure. It contains regular fields and size/offset pairs that describe the actual variably sized fields. The offset field contains the offset in bytes of the variably sized field from the beginning of the record. The size field contains the size in bytes of the variably sized field. If a variably sized field is empty, then the size field is zero and the offset is set to zero. Variably sized field that would be truncated if the total structure size is insufficient are left empty. That is, their size field is set to zero and the offset is set to zero. The variably sized fields follow the fixed fields.


Variably Sized Data Structures

When variably sized data structures are used to transmit information between TAPI.DLL and the application, the application is responsible for allocating the necessary memory. The amount of memory allocated must be at least large enough for the fixed portion of the data structure, and is set by the application in the dwTotalSize field of the data structure. The dwUsedSize and dwNeededSize fields are filled in by TAPI.DLL. If dwTotalSize is less than the size of the fixed portion, then  LINEERR/ PHONEERR_STRUCTURETOOSMALL is returned. If a function returns success, then all the fields in the fixed portion have been filled in. dwUsedSize and dwNeededSize can be compared to determine if all variable parts have been filled in, and how much space would be required to fill them all in.

If dwNeededSize is equal to dwUsedSize, then all fixed and variable parts have been filled in. If dwNeededSize is larger than dwUsedSize, some variable parts may have been filled in, but exactly which variably sized fields have been filled in is undefined. No variable part is ever truncated, and variable parts that would have been truncated due to insufficient space are indicated by having both of their corresponding "Offset" and "Size" parts set to zero. If these are not both zero (and no error was returned), they indicate the offset and size of valid, non-truncated variable-part data.

An application can always guarantee that all variable parts are filled in by allocating and indicating dwNeededSize bytes for the structure and calling the "Get" function again until the function returns success and dwNeededSize "covers" dwUsedSize. This should happen on the second try except for race conditions that cause changes in the size of variable parts between calls, which should be a rare occurrence.

Note  All ASCII, DBCS, and Unicode strings that occur in variable-sized structures should be NULL-terminated according to normal C string handling conventions.


Extensibility

Provisions are made for extending constants and structures both in a device-independent way and in a device-specific (vendor-specific) way. In constants that are scalar enumerations, a range of values is reserved for future common extensions. The remainder of values are identified as device specific. A vendor can define meanings for these values in any way desired. Their interpretation is keyed to the extension ID provided in the LINEDEVCAPS data structure. For constants that are defined as bit flags, a range of low-order bits are reserved, where the high-order bits can be extension specific. It is recommended that extended values and bit arrays use bits from the highest value or high-order bit down. This leaves the option to move the border between the common portion and extension portion if there is a need to do so in the future. Extensions to data structures are assigned a variably sized field with size/offset being part of the fixed part. TAPI describes for each data structures what device-specific extensions are allowed.

In addition to recognizing a specific extension ID, the application must negotiate the extension version number that the application and the service provider will operate under. This is done in the second version negotiation phase of the lineGetDevCaps function.

An extension ID is a globally unique identifier. There is no central registry for extension IDs. Instead, they are generated locally by the manufacturer by a utility that is available with the toolkit. The number is made up of parts such as a unique LAN address, time of day, and random number, to guarantee global uniqueness. Globally Unique Identifiers are designed to be distinguishable from HP/DEC universally unique identifiers and are thus fully compatible with them.


Reference

Following are the Telephony API structures.


LINEADDRESSCAPS

[New - Windows 95]

typedef struct lineaddresscaps_tag {
  DWORD  dwTotalSize;
  DWORD  dwNeededSize;
  DWORD  dwUsedSize;

  DWORD  dwLineDeviceID;

  DWORD  dwAddressSize;
  DWORD  dwAddressOffset;

  DWORD  dwDevSpecificSize;
  DWORD  dwDevSpecificOffset;

  DWORD  dwAddressSharing;
  DWORD  dwAddressStates;
  DWORD  dwCallInfoStates;
  DWORD  dwCallerIDFlags;
  DWORD  dwCalledIDFlags;
  DWORD  dwConnectedIDFlags;
  DWORD  dwRedirectionIDFlags;
  DWORD  dwRedirectingIDFlags;
  DWORD  dwCallStates;
  DWORD  dwDialToneModes;
  DWORD  dwBusyModes;
  DWORD  dwSpecialInfo;
  DWORD  dwDisconnectModes;

  DWORD  dwMaxNumActiveCalls;
  DWORD  dwMaxNumOnHoldCalls;
  DWORD  dwMaxNumOnHoldPendingCalls;
  DWORD  dwMaxNumConference;
  DWORD  dwMaxNumTransConf;

  DWORD  dwAddrCapFlags;
  DWORD  dwCallFeatures;
  DWORD  dwRemoveFromConfCaps;
  DWORD  dwRemoveFromConfState;
  DWORD  dwTransferModes;
  DWORD  dwParkModes;

  DWORD  dwForwardModes;
  DWORD  dwMaxForwardEntries;
  DWORD  dwMaxSpecificEntries;
  DWORD  dwMinFwdNumRings;
  DWORD  dwMaxFwdNumRings;

  DWORD  dwMaxCallCompletions;
  DWORD  dwCallCompletionConds;
  DWORD  dwCallCompletionModes;
  DWORD  dwNumCompletionMessages;
  DWORD  dwCompletionMsgTextEntrySize;
  DWORD  dwCompletionMsgTextSize;
  DWORD  dwCompletionMsgTextOffset;
  DWORD  dwAddressFeatures;
} LINEADDRESSCAPS, FAR *LPLINEADDRESSCAPS;

The LINEADDRESSCAPS structure describes the capabilities of a specified address.

dwTotalSize

The total size in bytes allocated to this data structure.

dwNeededSize

The size in bytes for this data structure that is needed to hold all the returned information.

dwUsedSize

The size in bytes of the portion of this data structure that contains useful information.

dwLineDeviceID

Specifies the device ID of the line device with which this address is associated.

dwAddressSize
dwAddressOffset

The size in bytes of the variably sized address field and the offset in bytes from the beginning of this data structure.

dwDevSpecificSize
dwDevSpecificOffset

The size in bytes of the variably sized device-specific field and the offset in bytes from the beginning of this data structure.

dwAddressSharing

Specifies the sharing mode of the address. Values are:

LINEADDRESSSHARING_PRIVATE

An address with private sharing mode is only assigned to a single line or station.

LINEADDRESSSHARING_BRIDGEDEXCL

An address with a bridged-exclusive sharing mode is assigned to one or more other lines or stations. The exclusive portion refers to the fact that only one of the bridged parties can be connected with a remote party at any given time.

LINEADDRESSSHARING_BRIDGEDNEW

An address with a bridged-new sharing mode is assigned to one or more other lines or stations. The new portion refers to the fact that activities by the different bridged parties result in the creation of new calls on the address.

LINEADDRESSSHARING_BRIDGEDSHARED

An address with a bridged-shared sharing mode is also assigned to one or more other lines or stations. The shared portion refers to the fact that if one of the bridged parties is connected with a remote party, the remaining bridged parties can share in the conversation (as in a conference) by activating that call appearance.

LINEADDRESSSHARING_MONITORED

An address with a monitored address mode simply monitors the status of that address. The status is either idle or in use. The message LINE_ADDRESSSTATE notifies the application about these changes.

dwAddressStates

This field contains the address states changes for which the application may get notified in the LINE_ADDRESSSTATE callback message. It uses the following LINEADDRESSSTATE_ constants:

LINEADDRESSSTATE_OTHER

Address-status items other than those listed below have changed. The application should check the current address status to determine which items have changed.

LINEADDRESSSTATE_DEVSPECIFIC

The device-specific item of the address status has changed.

LINEADDRESSSTATE_INUSEZERO

The address has changed to idle (it is not in use by any stations).

LINEADDRESSSTATE_INUSEONE

The address has changed from being idle or from being in use by many bridged stations to being in use by just one station.

LINEADDRESSSTATE_INUSEMANY

The monitored or bridged address has changed to being in use by one station to being used by more than one station.

LINEADDRESSSTATE_NUMCALLS

The number of calls on the address has changed. This is the result of events such as a new inbound call, an outbound call on the address, or a call changing its hold status.

LINEADDRESSSTATE_FORWARD

The forwarding status of the address has changed, including the number of rings for determining a "no answer" condition. The application should check the address status to retrieve details about the address's current forwarding status.

LINEADDRESSSTATE_TERMINALS

The terminal settings for the address have changed.

LINEADDRESSSTATE_CAPSCHANGE

Indicates that, due to configuration changes made by the user or other circumstances, one or more of the fields in the LINEADDRESSCAPS structure for the address have changed. The application should use lineGetAddressCaps to read the updated structure. If a service provider sends a LINE_ADDRESSSTATE message containing this value to TAPI, TAPI will pass it along to applications which have negotiated this or a subsequent API version; applications negotiating a previous API version will receive LINE_LINEDEVSTATE messages specifying LINEDEVSTATE_REINIT, requiring them to shutdown and reinitialize their connection to TAPI in order to obtain the updated information.

dwCallInfoStates

This field describes the call information elements that are meaningful for all calls on this address. An application may get notified about changes in some of these states in LINE_CALLINFO messages. It uses the following LINECALLINFOSTATE_ constants:

LINECALLINFOSTATE_OTHER

Call-information items other than those listed below have changed. The application should check the current call information to determine which items have changed.

LINECALLINFOSTATE_DEVSPECIFIC

The device-specific field of the call-information.

LINECALLINFOSTATE_BEARERMODE

The bearer mode field of the call-information record.

LINECALLINFOSTATE_RATE

The rate field of the call-information record.

LINECALLINFOSTATE_MEDIAMODE

The media-mode field of the call-information record.

LINECALLINFOSTATE_APPSPECIFIC

The application-specific field of the call-information record.

LINECALLINFOSTATE_CALLID

The call ID field of the call-information record.

LINECALLINFOSTATE_RELATEDCALLID

The related call ID field of the call-information record.

LINECALLINFOSTATE_ORIGIN

The origin field of the call-information record.

LINECALLINFOSTATE_REASON

The reason field of the call-information record.

LINECALLINFOSTATE_COMPLETIONID

The completion ID field of the call-information record.

LINECALLINFOSTATE_NUMOWNERINCR

The number of owner field in the call-information record was increased.

LINECALLINFOSTATE_NUMOWNERDECR

The number of owner field in the call-information record was decreased.

LINECALLINFOSTATE_NUMMONITORS

The number of monitors field in the call-information record has changed.

LINECALLINFOSTATE_TRUNK

The trunk field of the call-information record has changed.

LINECALLINFOSTATE_CALLERID

One of the callerID-related fields of the call-information record has changed.

LINECALLINFOSTATE_CALLEDID

One of the calledID-related fields of the call-information record has changed.

LINECALLINFOSTATE_CONNECTEDID

One of the connectedID-related fields of the call-information record has changed.

LINECALLINFOSTATE_REDIRECTIONID

One of the redirectionID-related fields of the call-information record has changed.

LINECALLINFOSTATE_REDIRECTINGID

One of the redirectingID-related fields of the call-information record has changed.

LINECALLINFOSTATE_DISPLAY

The display field of the call-information record.

LINECALLINFOSTATE_USERUSERINFO

The user-to-user information of the call-information record.

LINECALLINFOSTATE_HIGHLEVELCOMP

The high-level compatibility field of the call-information record.

LINECALLINFOSTATE_LOWLEVELCOMP

The low-level compatibility field of the call-information record.

LINECALLINFOSTATE_CHARGINGINFO

The charging information of the call-information record.

LINECALLINFOSTATE_TERMINAL

The terminal mode information of the call-information record.

LINECALLINFOSTATE_DIALPARAMS

The dial parameters of the call-information record.

LINECALLINFOSTATE_MONITORMODES

One or more of the digit, tone, or media monitoring fields in the call-information record has changed.

dwCallerIDFlags
dwCalledIDFlags
dwConnectedIDFlags
dwRedirectionIDFlags
dwRedirectingIDFlags

These fields describe the various party ID information types that may be provided for calls on this address. It uses the following LINECALLPARTYID_ constants:

LINECALLPARTYID_BLOCKED

Caller ID information for the call has been blocked by the caller but would otherwise have been available.

LINECALLPARTYID_OUTOFAREA

Caller ID information for the call is not available since it is not propagated all the way by the network.

LINECALLPARTYID_NAME

The caller ID information for the call is the caller's name (from a table maintained inside the switch). It is provided in the caller ID name variably sized field.

LINECALLPARTYID_ADDRESS

The caller ID information for the call is the caller's number and is provided in the caller ID variably sized field.

LINECALLPARTYID_PARTIAL

Caller ID information for the call is valid but is limited to partial number information.

LINECALLPARTYID_UNKNOWN

Caller ID information is currently unknown; it may become known later.

LINECALLPARTYID_UNAVAIL

Caller ID information is unavailable and will not become known later.

dwCallStates

This field describes the various call states that can possibly be reported for calls on this address. This parameter uses the following LINECALLSTATE_ constants:

LINECALLSTATE_IDLE

The call is idle—no call exists.

LINECALLSTATE_OFFERING

The call is being offered to the station, signaling the arrival of a new call. In some environments, a call in the offering state does not automatically alert the user; alerting is done by the switch instructing the line to ring. It does not affect any call states.

LINECALLSTATE_ACCEPTED

The call was offering and has been accepted. This indicates to other (monitoring) applications that the current owner application has claimed responsibility for answering the call. In ISDN, this also initiates alerting to both parties.

LINECALLSTATE_DIALTONE

The call is receiving a dial tone from the switch, which means that the switch is ready to receive a dialed number.

LINECALLSTATE_DIALING

Destination address information (a phone number) is being sent to the switch over the call. Note that the operation lineGenerateDigits does not place the line into the dialing state.

LINECALLSTATE_RINGBACK

The call is receiving ringback from the called address. Ringback indicates that the other station has been reached and is being alerted.

LINECALLSTATE_BUSY

The call is receiving a busy tone. Busy tone indicates that the call cannot be completed—either a circuit (trunk) or the remote party's station are in use.

LINECALLSTATE_SPECIALINFO

Special information is sent by the network. Special information is typically sent when the destination cannot be reached.

LINECALLSTATE_CONNECTED

The call has been established and the connection is made. Information is able to flow over the call between the originating address and the destination address.

LINECALLSTATE_PROCEEDING

Dialing has completed and the call is proceeding through the switch or telephone network.

LINECALLSTATE_ONHOLD

The call is on hold by the switch.

LINECALLSTATE_CONFERENCED

The call is currently a member of a multiparty conference call.

LINECALLSTATE_ONHOLDPENDCONF

The call is currently on hold while it is being added to a conference.

LINECALLSTATE_ONHOLDPENDTRANSF

The call is currently on hold awaiting transfer to another number.

LINECALLSTATE_DISCONNECTED

The remote party has disconnected from the call.

LINECALLSTATE_UNKNOWN

The state of the call is not known. This may be due to limitations of the call progress detection implementation.

dwDialToneModes

This field describes the various dialtone modes that can possibly be reported for calls made on this address. This field is meaningful only if the dialtone call state can be reported. It uses the following LINEDIALTONEMODE_ constants:

LINEDIALTONEMODE_NORMAL

This is a "normal" dialtone which typically is a continuous tone.

LINEDIALTONEMODE_SPECIAL

This is a special dialtone indicating a certain condition is currently in effect.

LINEDIALTONEMODE_INTERNAL

This is an internal dialtone, as within a PBX.

LINEDIALTONEMODE_EXTERNAL

This is an external (public network) dialtone.

LINEDIALTONEMODE_UNKNOWN

The dialtone mode is currently unknown but may become known later.

LINEDIALTONEMODE_UNAVAIL

The dialtone mode is unavailable and will not become known.

wBusyModes

This field describes the various busy modes that can possibly be reported for calls made on this address. This field is meaningful only if the busy call state can be reported. It uses the following LINEBUSYMODE_ constants:

LINEBUSYMODE_STATION

The busy signal indicates that the called party's station is busy. This is usually signaled with a "normal" busy tone.

LINEBUSYMODE_TRUNK

The busy signal indicates that a trunk or circuit is busy. This is usually signaled with a "long" busy tone.

LINEBUSYMODE_UNKNOWN

The busy signal's specific mode is currently unknown but may become known later.

LINEBUSYMODE_UNAVAIL

The busy signal's specific mode is unavailable and will not become known.

dwSpecialInfo

This field describes the various special information types that can possibly be reported for calls made on this address. This field is meaningful only if the specialInfo call state can be reported. It uses the following LINESPECIALINFO_ constants:

LINESPECIALINFO_NOCIRCUIT

This special information tone preceeds a no circuit or emergency announcement (trunk blockage category).

LINESPECIALINFO_CUSTIRREG

This special information tone preceeds a vacant number, AIS, Centrex (™)  number change and nonworking station, access code not dialed or dialed in error, manual intercept operator message (customer irregularity category).

LINESPECIALINFO_REORDER

This special information tone preceeds a reorder announcement (equipment irregularity category).

LINESPECIALINFO_UNKNOWN

Specifics about the special information tone are currently unknown but may become known later.

LINESPECIALINFO_UNAVAIL

Specifics about the special information tone are unavailable and will not become known.

dwDisconnectModes

This field describes the various disconnect modes that can possibly be reported for calls made on this address. This field is meaningful only if the disconnected call state can be reported. It uses the following LINEDISCONNECTMODE_ constants:

LINEDISCONNECTMODE_NORMAL

This is a "normal" disconnect request by the remote party; the call was terminated normally.

LINEDISCONNECTMODE_UNKNOWN

The reason for the disconnect request is unknown.

LINEDISCONNECTMODE_REJECT

The remote user has rejected the call.

LINEDISCONNECTMODE_PICKUP

The call was picked up from elsewhere.

LINEDISCONNECTMODE_FORWARDED

The call was forwarded by the switch.

LINEDISCONNECTMODE_BUSY

The remote user's station is busy.

LINEDISCONNECTMODE_NOANSWER

The remote user's station does not answer.

LINEDISCONNECTMODE_BADADDRESS

The destination address in invalid.

LINEDISCONNECTMODE_UNREACHABLE

The remote user could not be reached.

LINEDISCONNECTMODE_CONGESTION

The network is congested.

LINEDISCONNECTMODE_INCOMPATIBLE

The remote user's station equipment is incompatible with the type of call requested.

LINEDISCONNECTMODE_UNAVAIL

The reason for the disconnect is unavailable and will not become known later.

dwMaxNumActiveCalls

This field contains the maximum number of active call appearances that the address can handle. This number does not include calls on hold or calls on hold pending transfer or conference.

dwMaxNumOnHoldCalls

This field contains the maximum number of call appearances at the address that can be on hold.

dwMaxNumOnHoldPendingCalls

This field contains the maximum number of call appearances at the address that can be on hold pending transfer or conference.

dwMaxNumConference

This field contains the maximum number of parties that can be conferenced in a single conference call on this address.

dwMaxNumTransConf

This field specifies the number of parties (including "self") that can be added in a conference call that is initiated as a generic consultation call using lineSetupTransfer.

dwAddrCapFlags

This field contains a series of packed bit flags that describe a variety of address capabilities. It uses the following LINEADDRCAPFLAGS_ constants:

LINEADDRCAPFLAGS_FWDNUMRINGS

Specifies whether the number of rings for a "no answer" can be specified when forwarding calls on no answer.

LINEADDRCAPFLAGS_PICKUPGROUPID

Specifies whether or not a group ID is required for call pickup.

LINEADDRCAPFLAGS_SECURE

Specifies whether or not calls on this address can be made secure at call-setup time.

LINEADDRCAPFLAGS_BLOCKIDDEFAULT

Specifies whether the network by default sends or blocks caller ID information when making a call on this address. If TRUE, ID information is blocked by default; if FALSE, ID information is transmitted by default.

LINEADDRCAPFLAGS_BLOCKIDOVERRIDE

Specifies whether the default setting for sending or blocking of caller ID information can be overridden per call. If TRUE, override is possible; if FALSE, override is not possible.

LINEADDRCAPFLAGS_DIALED

Specifies whether an destination address can be dialed on this address for making a call. TRUE if a destination address must be dialed; FALSE if the destination address is fixed (as with a "hot phone").

LINEADDRCAPFLAGS_ORIGOFFHOOK

Specifies whether the originating party's phone can automatically be taken offhook when making calls.

LINEADDRCAPFLAGS_DESTOFFHOOK

Specifies whether the called party's phone can automatically be forced offhook when making calls.

LINEADDRCAPFLAGS_FWDCONSULT

Specifies whether call forwarding involves the establishment of a consultation call.

LINEADDRCAPFLAGS_SETUPCONFNULL

Specifies whether setting up a conference call starts out with an initial call (FALSE) or with no initial call (TRUE).

LINEADDRCAPFLAGS_AUTORECONNECT

Specifies whether dropping a consultation call automatically reconnects to the call on consultation hold. TRUE if reconnect happens automatically; otherwise, FALSE.

LINEADDRCAPFLAGS_COMPLETIONID

Specifies whether the completion IDs returned by lineCompleteCall are useful and unique. TRUE is useful; otherwise, FALSE.

LINEADDRCAPFLAGS_TRANSFERHELD

Specifies whether a (hard) held call can be transferred. Often, only calls on consultation hold may be able to be transferred.

LINEADDRCAPFLAGS_CONFERENCEHELD

Specifies whether a (hard) held call can be conferenced to. Often, only calls on consultation hold may be able to be added to as a conference call.

LINEADDRCAPFLAGS_ PARTIALDIAL

Specifies whether partial dialing is available.

LINEADDRCAPFLAGS_FWDSTATUSVALID

Specifies whether the forwarding status in the LINEADDRESSSTATUS structure for this address is valid.

LINEADDRCAPFLAGS_ FWDINTEXTADDR

Specifies whether internal and external calls can be forwarded to different forwarding addresses. This flag is meaningful only if forwarding of internal and external calls can be controlled separately. It is TRUE if internal and external calls can be forwarded to different destination addresses; otherwise, FALSE.

LINEADDRCAPFLAGS_ FWDBUSYNAADDR

Specifies whether call forwarding for busy and for no answer can use different forwarding addresses. This flag is meaningful only if forwarding for busy and for no answer can be controlled separately. It is TRUE if forwarding for busy and for no answer can use different destination addresses; otherwise, FALSE.

LINEADDRCAPFLAGS_ACCEPTTOALERT

TRUE if an offering call must be accepted using lineAccept in order to start alerting the users at both ends of the call; otherwise, FALSE. Typically, this is only used with ISDN.

LINEADDRCAPFLAGS_CONFDROP

TRUE if invoking lineDrop on a conference call parent also has the side effect of dropping (disconnecting) the other parties involved in the conference call; FALSE if dropping a conference call still allows the other parties to talk among themselves.

LINEADDRCAPFLAGS_ PICKUPCALLWAIT

TRUE if linePickup can be used to pickup a call detected by the user as a "call waiting" call; otherwise FALSE.

dwCallFeatures

This field specifies the switching capabilities or features available for all calls on this address using the LINECALLFEATURE_ constants. This member represents the call-related features which may possibly be available on an address (static availability as opposed to dynamic availability). Invoking a supported feature requires the call to be in the proper state and the underlying line device to be opened in a compatible mode. A zero in a bit position indicates that the corresponding feature is never available. A one indicates that the corresponding feature may be available if the application has the right privileges to the call and the call is in the appropriate state for the operation to be meaningful. This field allows an aplication to discover which call features can be (and which can never be) supported by the address.

dwRemoveFromConfCaps

This field specifies the address's capabilities for removing calls from a conference call. It uses the following LINEREMOVEFROMCONF_ constants:

LINEREMOVEFROMCONF_NONE

Parties cannot be removed from the conference call.

LINEREMOVEFROMCONF_LAST

Only the most recently added party can be removed from the conference call.

LINEREMOVEFROMCONF_ANY

Any participating party can be removed from the conference call.

dwRemoveFromConfState

This field uses the LINECALLSTATE_ constants to specify the state of the call after it has been removed from a conference call.

dwTransferModes

This field specifies the address's capabilities for resolving transfer requests. It uses the following LINETRANSFERMODE_ constants:

LINETRANSFERMODE_TRANSFER

Resolve the initiated transfer by transferring the initial call to the consultation call.

LINETRANSFERMODE_CONFERENCE

Resolve the initiated transfer by conferencing all three parties into a three-way conference call. A conference call is created and returned to the application.

dwParkModes

This field specifies the different call park modes available at this address. It uses the LINEPARKMODE_ constants:

LINEPARKMODE_DIRECTED

Specifies directed call park. The address where the call is to be parked must be supplied to the switch.

LINEPARKMODE_NONDIRECTED

Specifies nondirected call park. The address where the call is parked is selected by the switch and provided by the switch to the application.

dwForwardModes

This field specifies the different modes of forwarding available for this address. It uses the following LINEFORWARDMODE_ constants:

LINEFORWARDMODE_UNCOND

Forward all calls unconditionally, irrespective of their origin. Use this value when unconditional forwarding for internal and external calls cannot be controlled separately. Unconditional forwarding overrides forwarding on busy and/or no answer conditions.

LINEFORWARDMODE_UNCONDINTERNAL

Forward all internal calls unconditionally. Use this value when unconditional forwarding for internal and external calls can be controlled separately.

LINEFORWARDMODE_UNCONDEXTERNAL

Forward all external calls unconditionally. Use this value when unconditional forwarding for internal and external calls can be controlled separately.

LINEFORWARDMODE_UNCONDSPECIFIC

Forward all calls that originated at a specified address unconditionally (selective call forwarding).

LINEFORWARDMODE_BUSY

Forward all calls on busy, irrespective of their origin. Use this value when forwarding for internal and external calls on busy and on no answer cannot be controlled separately.

LINEFORWARDMODE_BUSYINTERNAL

Forward all internal calls on busy. Use this value when forwarding for internal and external calls on busy and on no answer can be controlled separately.

LINEFORWARDMODE_BUSYEXTERNAL

Forward all external calls on busy. Use this value when forwarding for internal and external calls on busy and on no answer can be controlled separately.

LINEFORWARDMODE_BUSYSPECIFIC

Forward all calls that originated at a specified address on busy (selective call forwarding).

LINEFORWARDMODE_NOANSW

Forward all calls on no answer, irrespective of their origin. Use this value when call forwarding for internal and external calls on no answer cannot be controlled separately.

LINEFORWARDMODE_NOANSWINTERNAL

Forward all internal calls on no answer. Use this value when forwarding for internal and external calls on no answer can be controlled separately.

LINEFORWARDMODE_NOANSWEXTERNAL

Forward all external calls on no answer. Use this value when forwarding for internal and external calls on no answer can be controlled separately.

LINEFORWARDMODE_NOANSWSPECIFIC

Forward all calls that originated at a specified address on no answer (selective call forwarding).

LINEFORWARDMODE_BUSYNA

Forward all calls on busy/no answer, irrespective of their origin. Use this value when forwarding for internal and external calls on busy and on no answer cannot be controlled separately.

LINEFORWARDMODE_BUSYNAINTERNAL

Forward all internal calls on busy/no answer. Use this value when call forwarding on busy and on no answer cannot be controlled separately for internal calls.

LINEFORWARDMODE_BUSYNAEXTERNAL

Forward all external calls on busy/no answer. Use this value when call forwarding on busy and on no answer cannot be controlled separately for internal calls.

LINEFORWARDMODE_BUSYNASPECIFIC

Forward all calls that originated at a specified address on busy/no answer (selective call forwarding).

dwMaxForwardEntries

Specifies the maximum number of entries that can be passed to lineForward in the lpForwardList parameter.

dwMaxSpecificEntries

Specifies the maximum number of entries in the lpForwardList parameter passed to lineForward that can contain forwarding instructions based on a specific caller ID (selective call forwarding). This field is zero if selective call forwarding is not supported.

dwMinFwdNumRings

Specifies the minimum number of rings that can be set to determine when a call is officially considered "no answer."

dwMaxFwdNumRings

Specifies the maximum number of rings that can be set to determine when a call is officially considered "no answer." If this number of rings cannot be set, then dwMinFwdNumRings and dwMaxNumRings will be equal.

dwMaxCallCompletions

Specifies the maximum number of concurrent call completion requests that can be outstanding on this line device. Zero implies that call completion is not available.

dwCallCompletionCond

Specifies the different call conditions under which call completion can be requested. This field uses the following  LINECALLCOMPLCOND_ constants:

LINECALLCOMPLCOND_BUSY

Complete the call under the busy condition.

LINECALLCOMPLCOND_NOANSWER

Complete the call under the ringback no answer condition.

dwCallCompletionModes

Specifies the way in which the call can be completed. This field uses the following LINECALLCOMPLCOND_ constants:

LINECALLCOMPLMODE_CAMPON

Queues the call until the call can be completed.

LINECALLCOMPLMODE_CALLBACK

Requests the called station to return the call when it returns to idle.

LINECALLCOMPLMODE_INTRUDE

Adds the application to the existing call at the called station if busy (barge in).

LINECALLCOMPLMODE_MESSAGE

Leave a short predefined message for the called station (Leave Word Calling). A specific message can be identified.

dwNumCompletionMessages

Specifies the number of call completion messages that can be selected from when using the LINECALLCOMPLMODE_MESSAGE option. Individual messages are identified by values in the range 0 through one less than dwNumCompletionMessages.

dwCompletionMsgTextEntrySize

Specifies the size in bytes of each of the call completion text descriptions pointed at by dwCompletionMsgTextSize/Offset.

dwCompletionMsgTextSize
dwCompletionMsgTextOffset

The size in bytes and the offset in bytes from the beginning of this data structure of the variably sized field containing descriptive text about each of the call completion messages. Each message is dwCompletionMsgTextEntrySize bytes long. The string format of these textual descriptions is indicated by dwStringFormat in the line's device capabilities.

dwAddressFeatures

This field specifies the features available for this address using the LINEADDRFEATURE_ constants. Invoking a supported feature requires the address to be in the proper state and the underlying line device to be opened in a compatible mode. A zero in a bit position indicates that the corresponding feature is never available. A one indicates that the corresponding feature may be available if the address is in the appropriate state for the operation to be meaningful. This field allows an application to discover which address features can be (and which can never be) supported by the address.

Device-specific extensions should use the DevSpecific (dwDevSpecificSize and dwDevSpecificOffset) variably sized area of this data structure.

Older applications will have been compiled without this field in the LINEADDRESSCAPS structure, and using a SIZEOF LINEADDRESSCAPS smaller than the new size. The application passes in a dwAPIVersion parameter with the lineGetAddressCaps function, which can be used for guidance by TAPI in handling this situation. If the application passes in a dwTotalSize less than the size of the fixed portion of the structure as defined in the dwAPIVersion specified, LINEERR_STRUCTURETOOSMALL will be returned. If sufficient memory has been allocated by the application, before calling TSPI_lineGetAddressCaps, TAPI will set the dwNeededSize and dwUsedSize fields to the fixed size of the structure as it existed in the specified API version.

New service providers (which support the new API version) must examine the API version passed in. If the API version is less than the highest version supported by the provider, the service provider must not fill in fields not supported in older API versions, as these would fall in the variable portion of the older structure.

New applications must be cognizant of the API version negotiated, and not examine the contents of fields in the fixed portion beyond the original end of the fixed portion of the structure for the negotiated API version.


LINEADDRESSSTATUS

[New - Windows 95]

typedef struct lineaddressstatus_tag {
  DWORD  dwTotalSize;
  DWORD  dwNeededSize;
  DWORD  dwUsedSize;

  DWORD  dwNumInUse;
  DWORD  dwNumActiveCalls;
  DWORD  dwNumOnHoldCalls;
  DWORD  dwNumOnHoldPendCalls;
  DWORD  dwAddressFeatures;

  DWORD  dwNumRingsNoAnswer;
  DWORD  dwForwardNumEntries;
  DWORD  dwForwardSize;
  DWORD  dwForwardOffset;

  DWORD  dwTerminalModesSize;
  DWORD  dwTerminalModesOffset;

  DWORD  dwDevSpecificSize;
  DWORD  dwDevSpecificOffset;
} LINEADDRESSSTATUS, FAR *LPLINEADDRESSSTATUS;

The LINEADDRESSSTATUS structure describes the current status of an address.

dwTotalSize

The total size in bytes allocated to this data structure.

dwNeededSize

The size in bytes for this data structure that is needed to hold all the returned information.

dwUsedSize

The size in bytes of the portion of this data structure that contains useful information.

dwNumInUse

Specifies the number of stations that are currently using the address.

dwNumActiveCalls

The number of calls on the address that are in call states other than idle, onhold, onholdpendingtransfer, and onholdpendingconference.

dwNumOnHoldCalls

The number of calls on the address in the onhold state.

dwNumOnHoldPendCalls

The number of calls on the address in the onholdpendingtransfer or onholdpendingconference state.

dwAddressFeatures

This field specifies the address-related API functions that can be invoked on the address in its current state. It uses the following LINEADDRFEATURE_ constants:

LINEADDRFEATURE_FORWARD

The address can be forwarded.

LINEADDRFEATURE_MAKECALL

An outbound call can be placed on the address.

LINEADDRFEATURE_PICKUP

A call can be picked up at the address.

LINEADDRFEATURE_SETMEDIACONTROL

Media control can be set on this address.

LINEADDRFEATURE_SETTERMINAL

The terminal modes for this address can be set.

LINEADDRFEATURE_SETUPCONF

A conference call with a NULL initial call can be set up at this address.

LINEADDRFEATURE_UNCOMPLETECALL

Call completion requests can be canceled at this address.

LINEADDRFEATURE_UNPARK

Calls can be unparked using this address.

dwNumRingsNoAnswer

Specifies the number of rings set for this address before an unanswered call is considered as no answer.

dwForwardNumEntries

Specifies the number of entries in the array referred to by dwForwardSize and dwForwardOffset.

dwForwardSize
dwForwardOffset

The size in bytes and the offset in bytes from the beginning of this data structure of the variably sized field that describes the address's forwarding information. This information is an array of dwForwardNumEntries elements, of type LINEFORWARD. The offsets of the addresses in the array are relative to the beginning of the LINEADDRESSSTATUS structure. The offsets dwCallerAddressOffset and dwDestAddressOffset in the variably sized field of type LINEFORWARD pointed to by dwForwardSize and dwForwardOffset are relative to the beginning of the LINEADDRESSSTATUS data structure (the "root" container).

dwTerminalModesSize
dwTerminalModesOffset

The size in bytes and the offset in bytes from the beginning of this data structure of the variably sized device field containing an array with DWORD-sized entries, that use the LINETERMMODE_ constants. This array is indexed by terminal IDs, in the range from zero to one less than dwNumTerminals. Each entry in the array specifies the current terminal modes for the corresponding terminal set with the lineSetTerminal function for this address. Values are:

LINETERMMODE_LAMPS

These are lamp events sent from the line to the terminal.

LINETERMMODE_BUTTONS

These are button-press events sent from the terminal to the line.

LINETERMMODE_DISPLAY

This is display information sent from the line to the terminal.

LINETERMMODE_RINGER

This is ringer-control information sent from the switch to the terminal.

LINETERMMODE_HOOKSWITCH

These are hookswitch events sent between the terminal and the line.

LINETERMMODE_MEDIATOLINE

This is the unidirectional media stream from the terminal to the line associated with a call on the line. Use this value when the routing of both unidirectional channels of a call's media stream can be controlled independently.

LINETERMMODE_MEDIAFROMLINE

This is the unidirectional media stream from the line to the terminal associated with a call on the line. Use this value when the routing of both unidirectional channels of a call's media stream can be controlled independently.

LINETERMMODE_MEDIABIDIRECT

This is the bidirectional media stream associated with a call on the line and the terminal. Use this value when the routing of both unidirectional channels of a call's media stream cannot be controlled independently.

dwDevSpecificSize
dwDevSpecificOffset

The size in bytes and the offset in bytes from the beginning of this data structure of the variably sized device-specific field.

Device-specific extensions should use the DevSpecific (dwDevSpecificSize and dwDevSpecificOffset) variably sized area of this data structure.

This data structure is returned by lineGetAddressStatus. When items in this data structure change as a consequence of activities on the address, a LINE_ADDRESSSTATE message is sent to the application. A parameter to this message is the address state, the constant LINEADDRESSSTATE_, which is an indication that the status item in this record that changed.


LINECALLINFO

[New - Windows 95]

typedef struct linecallinfo_tag {
  DWORD  dwTotalSize;
  DWORD  dwNeededSize;
  DWORD  dwUsedSize;

  HLINE  hLine;
  DWORD  dwLineDeviceID;
  DWORD  dwAddressID;

  DWORD  dwBearerMode;
  DWORD  dwRate;
  DWORD  dwMediaMode;

  DWORD  dwAppSpecific;
  DWORD  dwCallID;
  DWORD  dwRelatedCallID;
  DWORD  dwCallParamFlags;
  DWORD  dwCallStates;

  DWORD  dwMonitorDigitModes;
  DWORD  dwMonitorMediaModes;
  LINEDIALPARAMS  DialParams;

  DWORD  dwOrigin;
  DWORD  dwReason;
  DWORD  dwCompletionID;
  DWORD  dwNumOwners;
  DWORD  dwNumMonitors;

  DWORD  dwCountryCode;
  DWORD  dwTrunk;

  DWORD  dwCallerIDFlags;
  DWORD  dwCallerIDSize;
  DWORD  dwCallerIDOffset;
  DWORD  dwCallerIDNameSize;
  DWORD  dwCallerIDNameOffset;

  DWORD  dwCalledIDFlags;
  DWORD  dwCalledIDSize;
  DWORD  dwCalledIDOffset;
  DWORD  dwCalledIDNameSize;
  DWORD  dwCalledIDNameOffset;

  DWORD  dwConnectedIDFlags;
  DWORD  dwConnectedIDSize;
  DWORD  dwConnectedIDOffset;
  DWORD  dwConnectedIDNameSize;
  DWORD  dwConnectedIDNameOffset;

  DWORD  dwRedirectionIDFlags;
  DWORD  dwRedirectionIDSize;
  DWORD  dwRedirectionIDOffset;
  DWORD  dwRedirectionIDNameSize;
  DWORD  dwRedirectionIDNameOffset;

  DWORD  dwRedirectingIDFlags;
  DWORD  dwRedirectingIDSize;
  DWORD  dwRedirectingIDOffset;
  DWORD  dwRedirectingIDNameSize;
  DWORD  dwRedirectingIDNameOffset;

  DWORD  dwAppNameSize;
  DWORD  dwAppNameOffset;
  DWORD  dwDisplayableAddressSize;

  DWORD  dwDisplayableAddressOffset;

  DWORD  dwCalledPartySize;
  DWORD  dwCalledPartyOffset;

  DWORD  dwCommentSize;
  DWORD  dwCommentOffset;

  DWORD  dwDisplaySize;
  DWORD  dwDisplayOffset;

  DWORD  dwUserUserInfoSize;
  DWORD  dwUserUserInfoOffset;

  DWORD  dwHighLevelCompSize;
  DWORD  dwHighLevelCompOffset;

  DWORD  dwLowLevelCompSize;
  DWORD  dwLowLevelCompOffset;

  DWORD  dwChargingInfoSize;
  DWORD  dwChargingInfoOffset;

  DWORD  dwTerminalModesSize;
  DWORD  dwTerminalModesOffset;

  DWORD  dwDevSpecificSize;
  DWORD  dwDevSpecificOffset;
} LINECALLINFO, FAR *LPLINECALLINFO;

The LINECALLINFO structure contains information about a call. This information remains relatively fixed for the duration of the call and is obtained with lineGetCallInfo. If a part of the structure does change, then a LINE_CALLINFO message is sent to the application indicating which information item has changed. Dynamically changing information about a call, such as call progress status, is available in the LINECALLSTATUS structure, returned with the function lineGetCallStatus.

dwTotalSize

The total size in bytes allocated to this data structure.

dwNeededSize

The size in bytes for this data structure that is needed to hold all the returned information.

dwUsedSize

The size in bytes of the portion of this data structure that contains useful information.

hLine

Specifies the handle for the line device with which this call is associated.

dwLineDeviceID

Specifies the device ID of the line device with which this call is associated.

dwAddressID

Specifies the address ID of the address on the line on which this call exists.

dwBearerMode

Specifies the current bearer mode of the call. This field uses the following LINEBEARERMODE_ constants:

LINEBEARERMODE_VOICE

This is a regular 3.1kHz analog voice grade bearer service. Bit integrity is not assured. Voice can support fax and modem media modes.

LINEBEARERMODE_SPEECH

This corresponds to G.711 speech transmission on the call. The network may use processing techniques such as analog transmission, echo cancellation, and compression/decompression. Bit integrity is not assured. Speech is not intended to support fax and modem media modes.

LINEBEARERMODE_MULTIUSE

The multi-use mode defined by ISDN.

LINEBEARERMODE_DATA

The unrestricted data transfer on the call. The data rate is specified separately.

LINEBEARERMODE_ALTSPEECHDATA

The alternate transfer of speech or unrestricted data on the same call (ISDN).

LINEBEARERMODE_NONCALLSIGNALING

A non-call-associated signaling connection from the application to the service provider or switch (treated as a "media stream" by TAPI).

LINEBEARERMODE_PASSTHROUGH

When a call is active in LINEBEARERMODE_PASSTHROUGH, the service provider gives direct access to the attached hardware for control by the application. This mode is used primarily by applications desiring temporary direct control over asynchronous modems, accessed via the Win32 comm functions, for the purpose of configuring or using special features not otherwise supported by the service provider.

dwRate

Specifies the rate of the call's data stream in bps (bits per second).

dwMediaMode

Specifies the media mode of the information stream currently on the call. This is the media mode as determined by the owner of the call, which is not necessarily the same as that of the last LINE_MONITORMEDIA message. This field is not directly affected by the LINE_MONITORMEDIA messages. It uses the following LINEMEDIAMODE_ constants:

LINEMEDIAMODE_UNKNOWN

A media stream exists but its mode is not known. This corresponds to a call with an unclassified media type. In typical analog telephony environments, an inbound call's media mode may be unknown until after the call has been answered and the media stream has been filtered to make a determination.

LINEMEDIAMODE_INTERACTIVEVOICE

The presence of voice energy is detected on the call and the call is treated as an interactive call with humans on both ends.

LINEMEDIAMODE_AUTOMATEDVOICE

The presence of voice energy is detected on the call and the voice is locally handled by an automated application.

LINEMEDIAMODE_DATAMODEM

A data modem session is detected on the call.

LINEMEDIAMODE_G3FAX

A group 3 fax is being sent or received on the call.

LINEMEDIAMODE_TDD

A TDD (Telephony Devices for the Deaf) session on the call.

LINEMEDIAMODE_G4FAX

A group 4 fax is being sent or received over the call.

LINEMEDIAMODE_DIGITALDATA

Digital data being sent or received over the call.

LINEMEDIAMODE_TELETEX

A teletex session on the call. Teletex is one of the telematic services.

LINEMEDIAMODE_VIDEOTEX

A videotex session on the call. Videotex is one the telematic services.

LINEMEDIAMODE_TELEX

A telex session on the call. Telex is one the telematic services.

LINEMEDIAMODE_MIXED

A mixed session on the call. Mixed is one the ISDN telematic services.

LINEMEDIAMODE_ADSI

An ADSI (Analog Display Services Interface) session on the call.

dwAppSpecific

This field is uninterpreted by the API implementation and service provider. It can be set by any owner application of this call with the operation lineSetAppSpecific.

dwCallID

In some telephony environments, the switch or service provider may assign a unique identifier to each call. This allows the call to be tracked across transfers, forwards, or other events. The domain of these call IDs and their scope is service-provider defined. The dwCallID field makes this unique identifier available to the applications.

dwRelatedCallID

Telephony environments that use the call ID often may find it necessary to relate one call to another. The dwRelatedCallID field may be used by the service provider for this purpose.

dwCallParamFlags

Specifies a collection of call-related parameters when the call is outbound. These are same call parameters specified in lineMakeCall, of type LINECALLPARAMFLAGS_. Values are:

LINECALLPARAMFLAGS_SECURE

The call is currently secure. This flag is also updated if the call is later secured through lineSecureCall.

LINECALLPARAMFLAGS_IDLE

The call started out using an idle call.

LINECALLPARAMFLAGS_BLOCKID

The originator identity was concealed (block caller ID presentation to the remote party).

LINECALLPARAMFLAGS_ORIGOFFHOOK

The originator's phone was automatically taken offhook.

LINECALLPARAMFLAGS_DESTOFFHOOK

The called party's phone was automatically taken offhook.

dwCallStates

Specifies the call states for which the application may be notified on this call, of type LINECALLSTATE_. dwCallStates is constant in LINECALLINFO and does not change depending on the call state. Values are:

LINECALLSTATE_IDLE

The call is idle—no call exists.

LINECALLSTATE_OFFERING

The call is being offered to the station signaling the arrival of a new call. In some environments, a call in the offering state does not automatically alert the user; alerting is done by the switch instructing the line to ring. It does not affect any call states.

LINECALLSTATE_ACCEPTED

The call was offering and has been accepted. This indicates to other (monitoring) applications that the current owner application has claimed responsibility for answering the call. In ISDN, this also initiates alerting to both parties.

LINECALLSTATE_DIALTONE

The call is receiving a dial tone from the switch, which means that the switch is ready to receive a dialed number.

LINECALLSTATE_DIALING

Destination address information (a phone number) is being sent to the switch over the call. Note that the operation lineGenerateDigits does not place the line into the dialing state.

LINECALLSTATE_RINGBACK

The call is receiving ringback from the called address. Ringback indicates that the other station has been reached and is being alerted.

LINECALLSTATE_BUSY

The call is receiving a busy tone. Busy tone indicates that the call cannot be completed—either a circuit (trunk) or the remote party's station are in use.

LINECALLSTATE_SPECIALINFO

Special information is sent by the network. Special information is typically sent when the destination cannot be reached.

LINECALLSTATE_CONNECTED

The call has been established, the connection is made. Information is able to flow over the call between the originating address and the destination address.

LINECALLSTATE_PROCEEDING

Dialing has completed and the call is proceeding through the switch or telephone network.

LINECALLSTATE_ONHOLD

The call is on hold by the switch.

LINECALLSTATE_CONFERENCED

The call is currently a member of a multiparty conference call.

LINECALLSTATE_ONHOLDPENDCONF

The call is currently on hold while it is being added to a conference.

LINECALLSTATE_ONHOLDPENDTRANSF

The call is currently on hold awaiting transfer to another number.

LINECALLSTATE_DISCONNECTED

The remote party has disconnected from the call.

LINECALLSTATE_UNKNOWN

The state of the call is not known. This may be due to limitations of the call progress detection implementation.

dwMonitorDigitsModes

Specifies the various digit modes for which monitoring is currently enabled, of type LINEDIGITMODE_. Values are:

LINEDIGITMODE_PULSE

Uses pulse/rotary for digit signaling.

LINEDIGITMODE_DTMF

Uses DTMF tones for digit signaling.

LINEDIGITMODE_DTMFEND

Uses DTMF tones for digit detection, and also detects the down edges.

dwMonitorMediaModes

Specifies the various media modes for which monitoring is currently enabled, of type LINEMEDIAMODE_. Values are:

LINEMEDIAMODE_INTERACTIVEVOICE

The presence of voice energy on the call and the call is treated as an interactive call with humans on both ends.

LINEMEDIAMODE_AUTOMATEDVOICE

The presence of voice energy on the call and the voice is locally handled by an automated application.

LINEMEDIAMODE_DATAMODEM

A data modem session on the call.

LINEMEDIAMODE_G3FAX

A group 3 fax is being sent or received over the call.

LINEMEDIAMODE_TDD

A TDD (Telephony Devices for the Deaf) session on the call.

LINEMEDIAMODE_G4FAX

A group 4 fax is being sent or received over the call.

LINEMEDIAMODE_DIGITALDATA

Digital data is being sent or received over the call.

LINEMEDIAMODE_TELETEX

A teletex session on the call. Teletex is one of the telematic services.

LINEMEDIAMODE_VIDEOTEX

A videotex session on the call. Videotex is one the telematic services.

LINEMEDIAMODE_TELEX

A telex session on the call. Telex is one the telematic services.

LINEMEDIAMODE_MIXED

A mixed session on the call. Mixed is one the ISDN telematic services.

LINEMEDIAMODE_ADSI

An ADSI (Analog Display Services Interface) session on the call.

DialParams

Specifies the dialing parameters currently in effect on the call, of type LINEDIALPARAMS. Unless these parameters are set by either lineMakeCall or lineSetCallParams, their values will be the same as the defaults used in the LINEDEVCAPS.

dwOrigin

Identifies where the call originated from. This field uses the following LINECALLORIGIN_ constants:

LINECALLORIGIN_OUTBOUND

The call is an outbound call.

LINECALLORIGIN_INTERNAL

The call is inbound and originated internally (on the same PBX, for example).

LINECALLORIGIN_EXTERNAL

The call is inbound and originated externally.

LINECALLORIGIN_UNKNOWN

The call is an inbound call and its origin is currently unknown but may become known later.

LINECALLORIGIN_UNAVAIL

The call is an inbound call. Its origin is not available and will never become known for this call.

LINECALLORIGIN_CONFERENCE

The call handle is for a conference call, that is, the application's connection to the conference bridge in the switch.

dwReason

Specifies the reason why the call occurred. This field uses the following LINECALLREASON_ constants:

LINECALLREASON_DIRECT

This is a direct call.

LINECALLREASON_FWDBUSY

This call was forwarded from another extension that was busy at the time of the call.

LINECALLREASON_FWDNOANSWER

The call was forwarded from another extension that didn't answer the call after some number of rings.

LINECALLREASON_FWDUNCOND

The call was forwarded unconditionally from another number.

LINECALLREASON_PICKUP

The call was picked up from another extension.

LINECALLREASON_UNPARK

The call was retrieved as a parked call.

LINECALLREASON_REDIRECT

The call was redirected to this station.

LINECALLREASON_CALLCOMPLETION

The call was the result of a call completion request.

LINECALLREASON_TRANSFER

The call has been transferred from another number. Party ID information may indicate who the caller is and where the call was transferred from.

LINECALLREASON_REMINDER

The call is a reminder (or "recall") that the user has a call parked or on hold for potentially a long time.

LINECALLREASON_UNKNOWN

The reason for the call is currently unknown but may become known later.

LINECALLREASON_UNAVAIL

The reason for the call is unavailable and will not become known later.

dwCompletionID

The completion ID for the incoming call if it is the result of a completion request that terminates. This ID is meaningful only if dwReason is LINECALLREASON_CALLCOMPLETION.

dwNumOwners

The number of application modules with different call handles with owner privilege for the call.

dwNumMonitors

The number of application modules with different call handles with monitor privilege for the call.

dwCountryCode

The country code of the destination party. Zero if unknown.

dwTrunk

The number of the trunk over which the call is routed. This field is used for both inbound and outgoing calls. dwTrunk should be set to 0xFFFFFFFF if it is unknown.

dwCallerIDFlags

Determines the validity and content of the caller party ID information. The caller is the originator of the call. This field uses the following LINECALLPARTYID_ constants:

LINECALLPARTYID_BLOCKED

Caller ID information for the call has been blocked by the caller but would otherwise have been available.

LINECALLPARTYID_OUTOFAREA

Caller ID information for the call is not available since it is not propagated all the way by the network.

LINECALLPARTYID_NAME

The caller ID information for the call is the caller's name (from a table maintained inside the switch). It is provided in the caller ID name variably sized field.

LINECALLPARTYID_ADDRESS

The caller ID information for the call is the caller's number and is provided in the caller ID variably sized field.

LINECALLPARTYID_PARTIAL

Caller ID information for the call is valid but is limited to partial number information.

LINECALLPARTYID_UNKNOWN

Caller ID information is currently unknown but it may become known later.

LINECALLPARTYID_UNAVAIL

Caller ID information is unavailable and will not become known later.

dwCallerIDSize
dwCallerIDOffset

The size in bytes of the variably sized field containing the caller party ID number information, and the offset in bytes from the beginning of this data structure.

dwCallerIDNameSize
dwCallerIDNameOffset

The size in bytes of the variably sized field containing the caller party ID name information, and the offset in bytes from the beginning of this data structure.

dwCalledIDFlags

Determines the validity and content of the called-party ID information. The called party corresponds to the orignally addressed party. This field uses the following LINECALLPARTYID_ constants:

LINECALLPARTYID_BLOCKED

Called ID information for the call has been blocked by the caller but would otherwise have been available.

LINECALLPARTYID_OUTOFAREA

Caller ID information for the call is not available since it is not propagated all the way by the network.

LINECALLPARTYID_NAME

The called ID information for the call is the caller's name (from a table maintained inside the switch). It is provided in the called ID name variably sized field.

LINECALLPARTYID_ADDRESS

The called ID information for the call is the caller's number and is provided in the called ID variably sized field.

LINECALLPARTYID_PARTIAL

Called ID information for the call is valid but is limited to partial number information.

LINECALLPARTYID_UNKNOWN

Called ID information is currently unknown but it may become known later.

LINECALLPARTYID_UNAVAIL

Called ID information is unavailable and will not become known later.

dwCalledIDSize
dwCalledIDOffset

The size in bytes of the variably sized field containing the called-party ID number information, and the offset in bytes from the beginning of this data structure.

dwCalledIDNameSize
dwCalledIDNameOffset

The size in bytes of the variably sized field containing the called-party ID name information, and the offset in bytes from the beginning of this data structure.

dwConnectedFlags

Determines the validity and content of the connected party ID information. The connected party is the party that was actually connected to. This may be different from the called-party ID if the call was diverted. This field uses the following LINECALLPARTYID_ constants:

LINECALLPARTYID_BLOCKED

Connected party ID information for the call has been blocked by the caller but would otherwise have been available.

LINECALLPARTYID_OUTOFAREA

Connected ID information for the call is not available as it is not propagated all the way by the network.

LINECALLPARTYID_NAME

The connected party ID information for the call is the caller's name (from a table maintained inside the switch). It is provided in the connected ID name variably sized field.

LINECALLPARTYID_ADDRESS

The connected party ID information for the call is the caller's number and is provided in the connected ID variably sized field.

LINECALLPARTYID_PARTIAL

Connected party ID information for the call is valid but is limited to partial number information.

LINECALLPARTYID_UNKNOWN

Connected party ID information is currently unknown but it may become known later.

LINECALLPARTYID_UNAVAIL

Connected party ID information is unavailable and will not become known later.

dwConnectedIDSize
dwConnectedIDOffset

The size in bytes of the variably sized field containing the connected party ID number information, and the offset in bytes from the beginning of this data structure.

dwConnectedIDNameSize
dwConnectedIDNameOffset

The size in bytes of the variably sized field containing the connected party ID name information, and the offset in bytes from the beginning of this data structure.

dwRedirectionIDFlags

Determines the validity and content of the redirection party ID information. The redirection party identifies to the calling user the number towards which diversion was invoked. This field uses the following LINECALLPARTYID_ constants:

LINECALLPARTYID_BLOCKED

Redirection party ID information for the call has been blocked by the caller but would otherwise have been available.

LINECALLPARTYID_OUTOFAREA

Redirection ID information for the call is not available since it is not propagated all the way by the network.

LINECALLPARTYID_NAME

The redirection party ID information for the call is the caller's name (from a table maintained inside the switch). It is provided in the redirection ID name variably sized field.

LINECALLPARTYID_ADDRESS

The redirection party ID information for the call is the caller's number and is provided in the redirection ID variably sized field.

LINECALLPARTYID_PARTIAL

Redirection party ID information for the call is valid but is limited to partial number information.

LINECALLPARTYID_UNKNOWN

Redirection ID information is currently unknown but it may become known later.

LINECALLPARTYID_UNAVAIL

Redirection ID information is unavailable and will not become known later.

dwRedirectionIDSize
dwRedirectionIDOffset

The size in bytes of the variably sized field containing the redirection party ID number information, and the offset in bytes from the beginning of this data structure.

dwRedirectionIDNameSize
dwRedirectionIDNameOffset

The size in bytes of the variably sized field containing the redirection party ID name information, and the offset in bytes from the beginning of this data structure.

dwRedirectingIDFlags

Determines the validity and content of the redirecting party ID information. The redirecting party identifies to the diverted-to user the party from which diversion was invoked. This field uses the following LINECALLPARTYID_ constants:

LINECALLPARTYID_BLOCKED

Redirecting party ID information for the call has been blocked by the caller but would otherwise have been available.

LINECALLPARTYID_OUTOFAREA

Redirecting ID information for the call is not available since it is not propagated all the way by the network.

LINECALLPARTYID_NAME

The redirecting party ID information for the call is the caller's name (from a table maintained inside the switch). It is provided in the redirecting ID name variably sized field.

LINECALLPARTYID_ADDRESS

The redirecting party ID information for the call is the caller's number and is provided in the redirecting ID variably sized field.

LINECALLPARTYID_PARTIAL

Redirecting party ID information for the call is valid but is limited to partial number information.

LINECALLPARTYID_UNKNOWN

Redirecting ID information is currently unknown but it may become known later.

LINECALLPARTYID_UNAVAIL

Redirecting ID information is unavailable and will not become known later.

dwRedirectingIDSize
dwRedirectingIDOffset

The size in bytes of the variably sized field containing the redirecting party ID number information, and the offset in bytes from the beginning of this data structure.

dwRedirectingIDNameSize
dwRedirectingIDNameOffset

The size in bytes of the variably sized field containing the redirecting party ID name information, and the offset in bytes from the beginning of this data structure.

dwAppNameSize
dwAppNameOffset

The size in bytes and the offset in bytes from the beginning of this data structure of the variably sized field holding the user-friendly application name of the application that first originated, accepted, or answered the call. This is the name that an application can specify on lineInitialize. If the application specifies no such name, then the application's file name is used instead.

dwDisplayableAddressSize
dwDisplayableAddressOffset

The displayable string is used for logging purposes. The information is obtained from LINECALLPARAMS for functions that intiate calls. The function lineTranslateAddress returns appropriate information to be placed in this field in the dwDisplayableAddressSize and dwDisplayableAddressOffset fields of the LINETRANSLATEOUTPUT structure.

dwCalledPartySize
dwCalledPartyOffset

The size in bytes of the variably sized field holding a user-friendly description of the called party, and the offset in bytes from the beginning of this data structure. This information can be specified on lineMakeCall and can be optionally specified in the lpCallParams whenever a new call is established. It is useful for call logging purposes.

dwCommentSize
dwCommentOffset

The size in bytes of the variably sized field holding a comment about the call provided by the application that originated the call using lineMakeCall, and the offset in bytes from the beginning of this data structure. This information can be optionally specified in the lpCallParams whenever a new call is established.

dwDisplaySize
dwDisplayOffset

The size in bytes of the variably sized field holding raw display information, and the offset in bytes from the beginning of this data structure. Depending on the telephony environment, a service provider may extract functional information from this for presentation in a more functional way.

dwUserUserInfoSize
dwUserUserInfoOffset

The size in bytes of the variably sized field holding user-to-user information, and the offset in bytes from the beginning of this data structure The protocol discriminator field for the user-user information, if used, appears as the first byte of the data pointed to by dwUserUserInfoOffset, and is accounted for in dwUserUserInfoSize.

dwHighLevelCompSize
dwHighLevelCompOffset

The size in bytes of the variably sized field holding high-level compatibility information, and the offset in bytes from the beginning of this data structure. The format of this information is specified by other standards (ISDN Q.931).

dwLowLevelCompSize
dwLowLevelCompOffset

The size in bytes of the variably sized field holding low-level compatibility information, and the offset in bytes from the beginning of this data structure The format of this information is specified by other standards (ISDN Q.931).

dwChargingInfoSize
dwChargingInfoOffset

The size in bytes of the variably sized field holding charging information, and the offset in bytes from the beginning of this data structure The format of this information is specified by other standards (ISDN Q.931).

dwTerminalModesSize
dwTerminalModesOffset

The size in bytes of the variably sized device field containing an array with DWORD-sized entries, and the offset in bytes from the beginning of this data structure. The set of LINETERMMODE_ constants is indexed by terminal IDs, in the range from zero to one less than dwNumTerminals. Each entry in the array specifies the current terminal modes for the corresponding terminal set with the lineSetTerminal operation for this call's media stream. Values are:

LINETERMMODE_LAMPS

These are lamp events sent from the line to the terminal.

LINETERMMODE_BUTTONS

These are button-press events sent from the terminal to the line.

LINETERMMODE_DISPLAY

This is display information sent from the line to the terminal.

LINETERMMODE_RINGER

This is ringer-control information sent from the switch to the terminal.

LINETERMMODE_HOOKSWITCH

These are hookswitch event sent between the terminal and the line.

LINETERMMODE_MEDIATOLINE

This is the unidirectional media stream from the terminal to the line associated with a call on the line. Use this value when the routing of both unidirectional channels of a call's media stream can be controlled independently.

LINETERMMODE_MEDIAFROMLINE

This is the unidirectional media stream from the line to the terminal associated with a call on the line. Use this value when the routing of both unidirectional channels of a call's media stream can be controlled independently.

LINETERMMODE_MEDIABIDIRECT

This is the bidirectional media stream associated with a call on the line and the terminal. Use this value when the routing of both the unidirectional channels of a call's media stream cannot be controlled independently.

dwDevSpecificSize
dwDevSpecificOffset

The size in bytes of the variably sized field holding device-specific information., and the offset in bytes from the beginning of this data structure.

Device-specific extensions should use the DevSpecific (dwDevSpecificSize and dwDevSpecificOffset) variably sized area of this data structure.

The LINECALLINFO data structure contains relatively fixed information about a call. This structure is returned with lineGetCallInfo. When information items in this data structure have changed, a LINE_CALLINFO message is sent to the application. A parameter to this message is the information item or field that changed.

The dwAppSpecific field can be used by applications to tag calls by using lineSetAppSpecific. This field is uninterpreted by TAPI or service providers. It is initially set to zero.


LINECALLLIST

[New - Windows 95]

typedef struct linecalllist_tag {
  DWORD  dwTotalSize;
  DWORD  dwNeededSize;
  DWORD  dwUsedSize;

  DWORD  dwCallsNumEntries;
  DWORD  dwCallsSize;
  DWORD  dwCallsOffset;
} LINECALLLIST, FAR *LPLINECALLLIST;

The LINECALLLIST structure describes a list of call handles. A structure of this type is returned by the functions lineGetNewCalls and lineGetConfRelatedCalls.

dwTotalSize

The total size in bytes allocated to this data structure.

dwNeededSize

The size in bytes for this data structure that is needed to hold all the returned information.

dwUsedSize

The size in bytes of the portion of this data structure that contains useful information.

dwCallsNumEntries

Specifies the number of handles in the hCalls array.

dwCallsSize
dwCallsOffset

The size in bytes and the offset in bytes from the beginning of this data structure of the variably sized field (which is an array of HCALL-sized handles).

No extensions.


LINECALLPARAMS

[New - Windows 95]

typedef struct linecallparams_tag {  // Defaults:
  DWORD  dwTotalSize;          // ---------

  DWORD  dwBearerMode;        // voice
  DWORD  dwMinRate;          // (3.1kHz)
  DWORD  dwMaxRate;          // (3.1kHz)
  DWORD  dwMediaMode;          // interactiveVoice

  DWORD  dwCallParamFlags;      // 0
  DWORD  dwAddressMode;        // addressID
  DWORD  dwAddressID;          // (any available)

  LINEDIALPARAMS DialParams;      // (0, 0, 0, 0)

  DWORD  dwOrigAddressSize;      // 0
  DWORD  dwOrigAddressOffset;

  DWORD  dwDisplayableAddressSize;  // 0
  DWORD  dwDisplayableAddressOffset;

  DWORD  dwCalledPartySize;      // 0
  DWORD  dwCalledPartyOffset;

  DWORD  dwCommentSize;        // 0
  DWORD  dwCommentOffset;

  DWORD  dwUserUserInfoSize;      // 0
  DWORD  dwUserUserInfoOffset;

  DWORD  dwHighLevelCompSize;      // 0
  DWORD  dwHighLevelCompOffset;

  DWORD  dwLowLevelCompSize;      // 0
  DWORD  dwLowLevelCompOffset;

  DWORD  dwDevSpecificSize;      // 0
  DWORD  dwDevSpecificOffset;
} LINECALLPARAMS, FAR *LPLINECALLPARAMS;

The LINECALLPARAMS structure describes parameters supplied when making calls using lineMakeCall. The LINECALLPARAMS structure is also used as a parameter in other operations. The comments on the right indicate the default values used when this structure is not provided to lineMakeCall.

dwTotalSize

The total size in bytes allocated to this data structure. This size should be big enough to hold all the fixed and variably sized portions of this data structure.

dwBearerMode

Specifies the bearer mode for the call. This field uses the following LINEBEARERMODE_ constants:

LINEBEARERMODE_VOICE

This is a regular 3.1kHz analog voice grade bearer service. Bit integrity is not assured. Voice can support fax and modem media modes.

LINEBEARERMODE_SPEECH

This corresponds to G.711 speech transmission on the call. The network may use processing techniques such as analog transmission, echo cancellation, and compression/decompression. Bit integrity is not assured. Speech is not intended to support fax and modem media modes.

LINEBEARERMODE_MULTIUSE

The multi-use mode defined by ISDN.

LINEBEARERMODE_DATA

The unrestricted data transfer on the call. The data rate is specified separately.

LINEBEARERMODE_ALTSPEECHDATA

The alternate transfer of speech or unrestricted data on the same call (ISDN).

LINEBEARERMODE_NONCALLSIGNALING

This corresponds to a non-call-associated signaling connection from the application to the service provider or switch (treated as a "media stream" by the Telephony API).

LINEBEARERMODE_PASSTHROUGH

When a call is active in LINEBEARERMODE_PASSTHROUGH, the service provider gives direct access to the attached hardware for control by the application. This mode is used primarily by applications desiring temporary direct control over asynchronous modems, accessed via the Win32 comm functions, for the purpose of configuring or using special features not otherwise supported by the service provider.

If dwBearerMode is 0, default value is LINEBEARERMODE_VOICE.

dwMinRate
dwMaxRate

Specifies the data rate range requested for the call's data stream in bps (bits per second). When making a call, the service provider attempts to provide the highest available rate in the requested range. If a specific data rate is required, both min and max should be set to that value. If an application works best with one rate but is able the degrade to lower rates, the application should specify these as the max and min rates respectively. If dwMaxRate is 0, default value is as specified by the dwMaxRate member of the LINEDEVCAPS structure. This is the maximum rate supported by device.

dwMediaMode

Specifies the expected media mode of the call. This field uses the following LINEMEDIAMODE_ constants:

LINEMEDIAMODE_UNKNOWN

A media stream exists but its mode is not known. This would correspond to a call with an unclassified media type. In typical analog telephony environments, an inbound call's media mode may be unknown until after the call has been answered and the media stream has been filtered to make a determination.

LINEMEDIAMODE_INTERACTIVEVOICE

The presence of voice energy on the call and the call is treated as an interactive call with humans on both ends.

LINEMEDIAMODE_AUTOMATEDVOICE

The presence of voice energy on the call and the voice is locally handled by an automated application.

LINEMEDIAMODE_DATAMODEM

A data modem session on the call.

LINEMEDIAMODE_G3FAX

A group 3 fax is being sent or received over the call.

LINEMEDIAMODE_TDD

A TDD (Telephony Devices for the Deaf) session on the call.

LINEMEDIAMODE_G4FAX

A group 4 fax is being sent or received over the call.

LINEMEDIAMODE_DIGITALDATA

Digital data is being sent or received over the call.

LINEMEDIAMODE_TELETEX

A teletex session on the call. Teletex is one of the telematic services.

LINEMEDIAMODE_VIDEOTEX

A videotex session on the call. Videotex is one the telematic services.

LINEMEDIAMODE_TELEX

A telex session on the call. Telex is one the telematic services.

LINEMEDIAMODE_MIXED

A mixed session on the call. Mixed is one the ISDN telematic services.

LINEMEDIAMODE_ADSI

An ADSI (Analog Display Services Interface) session on the call.

If dwMediaMode is 0, the default value is LINEMEDIAMODE_INTERACTIVEVOICE.

dwCallParamFlags

These flags specify a collection of Boolean call-setup parameters. This field uses the following LINECALLPARAMFLAGS_ constants:

LINECALLPARAMFLAGS_SECURE

The call should be set up as secure.

LINECALLPARAMFLAGS_IDLE

The call should get an idle call appearance.

LINECALLPARAMFLAGS_BLOCKID

The originator identity should be concealed (block caller ID).

LINECALLPARAMFLAGS_ORIGOFFHOOK

The originator's phone should be automatically taken offhook.

LINECALLPARAMFLAGS_DESTOFFHOOK

The called party's phone should be automatically be taken offhook.

dwAddressMode

Specifies the mode by which the originating address is specified. The dwAddressMode field cannot be LINEADDRESSMODE_ADDRESSID for the function call lineOpen. This field uses the following LINEADDRESSMODE_ constants:

LINEADDRESSMODE_ADDRESSID

The address is specified with a small integer in the range 0 to dwNumAddresses minus one, where dwNumAddresses is the value in the line's LINEDEVCAPS structure. The selected address is specified in the dwAddressID field.

LINEADDRESSMODE_DIALABLEADDR

The address is specified with its dialable address. The address is contained in the dwOrigAddressSize, dwOrigAddressOffset variably sized field.

If dwAddressMode is 0, the default value is LINEADDRESSMODE_ADDRESSID.

dwAddressID

Specifies the address ID of the originating address if dwAddressMode is set to LINEADDRESSMODE_ADDRESSID.

DialParams

Specifies dial parameters to be used on this call, of type LINEDIALPARAMS. When a value of zero is specified for this field, the default value for the field is used as specified in the DefaultDialParams member of the LINEDEVCAPS structure. If a non-zero value is specified for a field which is outside the range specified by the corresponding fields in MinDialParams and MaxDialParams in the LINEDEVCAPS structure, the nearest value within the valid range is used instead.

dwOrigAddressSize
dwOrigAddressOffset

The size in bytes of the variably sized field holding the originating address, and the offset in bytes from the beginning of this data structure. The format of this address is dependent on the dwAddressMode field.

dwDisplayableAddressSize
dwDisplayableAddressOffset

The displayable string is used for logging purposes. The content of these fields is recorded in the dwDisplayableAddressOffset and dwDisplayableAddressSize fields of the call's LINECALLINFO message.  lineTranslateAddress returns appropriate information to be placed in this field in the dwDisplayableAddressSize and dwDisplayableAddressOffset fields of the LINETRANSLATEOUTPUT structure.

dwCalledPartySize
dwCalledPartyOffset

The size in bytes of the variably sized field holding called-party information, and the offset in bytes from the beginning of this data structure. This information can be specified by the application that makes the call and is made available in the call's information structure for logging purposes. The format of this field is that of dwStringFormat, as specified in LINEDEVCAPS.

dwCommentSize
dwCommentOffset

The size in bytes of the variably sized field holding comments about the call, and the offset in bytes from the beginning of this data structure. This information can be specified by the application the makes the call and is made available in the call's information structure for logging purposes. The format of this field is that of dwStringFormat, as specified in LINEDEVCAPS.

dwUserUserInfoSize
dwUserUserInfoOffset

The size in bytes of the variably sized field holding user-to-user information, and the offset in bytes from the beginning of this data structure. The protocol discriminator field for the user-user information, if required, should appear as the first byte of the data pointed to by dwUserUserInfoOffset, and must be accounted for in dwUserUserInfoSize.

dwHighLevelCompSize
dwHighLevelCompOffset

The size in bytes of the variably sized field holding high-level compatibility information, and the offset in bytes from the beginning of this data structure

dwLowLevelCompSize
dwLowLevelCompOffset

The size in bytes of the variably sized field holding low-level compatibility information, and the offset in bytes from the beginning of this data structure.

dwDevSpecificSize
dwDevSpecificOffset

The size in bytes of the variably sized field holding device-specific information, and the offset in bytes from the beginning of this data structure

Device-specific extensions should use the DevSpecific (dwDevSpecificSize and dwDevSpecificOffset) variably sized area of this data structure.

This structure is used as a parameter to lineMakeCall when setting up a call. Its fields allow the application to specify the quality of service requested from the network as well as a variety of ISDN call-setup parameters. If no LINECALLPARAMS structure is supplied to lineMakeCall, a default POTS voice-grade call is requested with the default values listed above.

Note that the fields DialParams through dwDevSpecificOffset are ignored when an lpCallParams parameter is specified with the function lineOpen.


LINECALLSTATUS

[New - Windows 95]

typedef struct linecallstatus_tag {
  DWORD  dwTotalSize;
  DWORD  dwNeededSize;
  DWORD  dwUsedSize;

  DWORD  dwCallState;
  DWORD  dwCallStateMode;
  DWORD  dwCallPrivilege;
  DWORD  dwCallFeatures;

  DWORD  dwDevSpecificSize;
  DWORD  dwDevSpecificOffset;
} LINECALLSTATUS, FAR *LPLINECALLSTATUS;

The LINECALLSTATUS structure describes the current status of a call. The information in this structure, as returned with lineGetCallStatus, depends on the device capabilities of the address, the ownership of the call by the invoking application, and the current state of the call being queried.

dwTotalSize

The total size in bytes allocated to this data structure.

dwNeededSize

The size in bytes for this data structure that is needed to hold all the returned information.

dwUsedSize

The size in bytes of the portion of this data structure that contains useful information.

dwCallState
dwCallStateMode

The dwCallState field specifies the current call state of the call. The interpretation of the dwCallStateMode field is call-state-dependent. It specifies the current mode of the call while in its current state (if that state defines a mode). This field uses the following LINECALLSTATE_ constants:

LINECALLSTATE_IDLE

The call state mode is unused.

LINECALLSTATE_OFFERING

The call state mode is unused.

LINECALLSTATE_ACCEPTED

The call state mode is unused.

LINECALLSTATE_DIALTONE

The call state mode, of type LINEDIALTONEMODE_. Values are:

LINEDIALTONEMODE_NORMAL

This is a "normal" dialtone which typically is a continuous tone.

LINEDIALTONEMODE_SPECIAL

This is a special dialtone indicating a certain condition is currently in effect.

LINEDIALTONEMODE_INTERNAL

This an internal dialtone, as within a PBX.

LINEDIALTONEMODE_EXTERNAL

This is an external (public network) dialtone.

LINEDIALTONEMODE_UNKNOWN

The dialtone mode is not currently known but may become known later.

LINEDIALTONEMODE_UNAVAIL

The dialtone mode is unavailable and will not become known.

LINECALLSTATE_DIALING

Call state mode is unused.

LINECALLSTATE_RINGBACK

Call state mode is unused.

LINECALLSTATE_BUSY

The call state mode is of type LINEBUSYMODE_. Values are:

LINEBUSYMODE_STATION

The busy signal indicates that the called party's station is busy. This is usually signaled with a "normal" busy tone.

LINEBUSYMODE_TRUNK

The busy signal indicates that a trunk or circuit is busy. This is usually signaled with a "long" busy tone.

LINEBUSYMODE_UNKNOWN

The busy signal's specific mode is currently unknown but may become known later.

LINEBUSYMODE_UNAVAIL

The busy signal's specific mode is unavailable and will not become known.

LINECALLSTATE_SPECIALINFO

The call state mode is of type LINESPECIALINFO_. Values are:

LINESPECIALINFO_NOCIRCUIT

This special information tone preceeds a no circuit or emergency announcement (trunk blockage category).

LINESPECIALINFO_CUSTIRREG

This special information tone preceeds a vacant number, AIS, Centrex number change and nonworking station, access code not dialed or dialed in error, or manual intercept operator message (customer irregularity category).

LINESPECIALINFO_REORDER

This special information tone preceeds a reorder announcement (equipment irregularity category).

LINESPECIALINFO_UNKNOWN

Specifics about the special information tone are currently unknown but may become known later.

LINESPECIALINFO_UNAVAIL

Specifics about the special information tone are unavailable and will not become known.

LINECALLSTATE_CONNECTED

Call state mode is unused.

LINECALLSTATE_PROCEEDING

Call state mode is unused.

LINECALLSTATE_ONHOLD

Call state mode is unused.

LINECALLSTATE_CONFERENCED

Call state mode is unused.

LINECALLSTATE_ONHOLDPENDCONF

Call state mode is unused.

LINECALLSTATE_ONHOLDPENDTRANSF

Call state mode is unused.

LINECALLSTATE_DISCONNECTED

Call state mode is of type LINEDISCONNECTMODE_. Values are:

LINEDISCONNECTMODE_NORMAL

This is a "normal" disconnect request by the remote party. The call was terminated normally.

LINEDISCONNECTMODE_UNKNOWN

The reason for the disconnect request is unknown.

LINEDISCONNECTMODE_REJECT

The remote user has rejected the call.

LINEDISCONNECTMODE_PICKUP

The call was picked up from elsewhere.

LINEDISCONNECTMODE_FORWARDED

The call was forwarded by the switch.

LINEDISCONNECTMODE_BUSY

The remote user's station is busy.

LINEDISCONNECTMODE_NOANSWER

The remote user's station does not answer.

LINEDISCONNECTMODE_BADADDRESS

The destination address in invalid.

LINEDISCONNECTMODE_UNREACHABLE

The remote user could not be reached.

LINEDISCONNECTMODE_CONGESTION

The network is congested.

LINEDISCONNECTMODE_INCOMPATIBLE

The remote user's station equipment is incompatible with the type of call requested.

LINEDISCONNECTMODE_UNAVAIL

The reason for the disconnect is unavailable and will not become known later.

LINECALLSTATE_UNKNOWN

Call state mode is unused.

dwCallPrivilege

Specifies the application's privilege for this call. This field uses the following LINECALLPRIVILEGE_ constants. Values are:

LINECALLPRIVILEGE_MONITOR

The application has monitor privilege.

LINECALLPRIVILEGE_OWNER

The application has owner privilege.

dwCallFeatures

These flags indicate which Telephony API functions can be invoked on the call, given the availability of the feature in the device capabilities, the current call state, and call ownership of the invoking application. A zero indicates the corresponding feature cannot be invoked by the application on the call in its current state; a one indicates the feature can be invoked. This field uses LINECALLFEATURE_ constants.

dwDevSpecificSize
dwDevSpecificOffset

The size in bytes of the variably sized device-specific field, and the offset in bytes from the beginning of this data structure.

Device-specific extensions should use the DevSpecific (dwDevSpecificSize and dwDevSpecificOffset) variably sized area of this data structure.

The application is sent a LINE_CALLSTATE message whenever the call state of a call changes. This message only provides the new call state of the call. Additional status about a call is available with lineGetCallStatus.

The members of the LINECALLSTATUS structure may be set to the LINECONNECTEDMODE_ACTIVE or LINECONNECTEDMODE_INACTIVE and the LINEOFFERINGMODE_ACTIVE or LINEOFFERINGMODE_INACTIVE values depending on the state of the corresponding call.


LINECARDENTRY

[New - Windows 95]

typedef struct linecardentry_tag {
  DWORD  dwPermanentCardID;
  DWORD  dwCardNameSize;
  DWORD  dwCardNameOffset;
  DWORD  dwCardNumberDigits;
  DWORD  dwSameAreaRuleSize;
  DWORD  dwSameAreaRuleOffset;
  DWORD  dwLongDistanceRuleSize;
  DWORD  dwLongDistanceRuleOffset;
  DWORD  dwInternationalRuleSize;
  DWORD  dwInternationalRuleOffset;
  DWORD  dwOptions;
} LINECARDENTRY, FAR *LPLINECARDENTRY;

The LINECARDENTRY structure describes a calling card.

dwPermanentCardID

The permanent ID that identifies the card.

dwCardNameSize
dwCardNameOffset

Contains a NULL-terminated ASCII string (size includes the NULL) that describes the card in a user-friendly manner.

dwCardNumberDigits

Specifies the number of digits in the existing card number. The card number itself is not return for security reasons (it is stored in scrambled form by TAPI). The application can use this to insert filler bytes into a text control in "password" mode to show that a number exists.

dwSameAreaRuleSize
dwSameAreaRuleOffset

Specifies the offset in bytes from the beginning of the LINETRANSLATECAPS structure and the total number of bytes in the dialing rule defined for calls to numbers in the same area code. The rule is a null-terminated ASCII string.

dwLongDistanceRuleSize
dwLongDistanceRuleOffset

Specifies the offset in bytes from the beginning of the LINETRANSLATECAPS structure and the total number of bytes in the dialing rule defined for calls to numbers in the other areas in the same country. The rule is a null-terminated ASCII string.

dwInternationalRuleSize
dwInternationalRuleOffset

Specifies the offset in bytes from the beginning of the LINETRANSLATECAPS structure and the total number of bytes in the dialing rule defined for calls to numbers in other countries. The rule is a null-terminated ASCII string.

dwOptions

Indicates other settings associated with this calling card, using the LINECARDOPTION_ set of constants.

Older applications will have been compiled without knowledge of these new fields, and using a SIZEOF LINECARDENTRY smaller than the new size. Since this is an array in the variable portion of a LINETRANSLATECAPS structure, it is imperitive that older applications receive LINECARDENTRY structures in the format they previously expected, or they will not be able to index through the array properly. The application passes in a dwAPIVersion parameter with the lineGetTranslateCaps function, which can be used for guidance by TAPI in handling this situation. lineGetTranslateCaps should use the LINECARDENTRY fields and size that match the indicated API version, when building the LINETRANSLATECAPS structure to be returned to the application.

No extensions.


LINECOUNTRYENTRY

[New - Windows 95]

typedef struct linecountryentry_tag {
  DWORD  dwCountryID;
  DWORD  dwCountryCode;
  DWORD  dwNextCountryID;
  DWORD  dwCountryNameSize;
  DWORD  dwCountryNameOffset;
  DWORD  dwSameAreaRuleSize;
  DWORD  dwSameAreaRuleOffset;
  DWORD  dwLongDistanceRuleSize;
  DWORD  dwLongDistanceRuleOffset;
  DWORD  dwInternationalRuleSize;
  DWORD  dwInternationalRuleOffset;
} LINECOUNTRYENTRY, FAR *LPLINECOUNTRYENTRY;

The LINECOUNTRYENTRY structure provides the information for a single country entry. An array of 1 or more of these structures is returned as part of the LINECOUNTRYLIST structure returned by the function lineGetCountry.

dwCountryID

Specifies the country ID of the entry. The country ID is an internal identifier which allows multiple entries to exist in the country list with the same country code (for example, all countries in North America and the Caribbean share country code 1, but require separate entries in the list).

dwCountryCode

Specifies the actual country code of the country represented by the entry (i.e., the digits that would be dialed in an international call). Only this value should ever be displayed to users (country IDs should never be displayed, as they would be confusing).

dwNextCountryID

Specifies the country ID of the next entry in the country list. Because country codes and IDs are not assigned in any regular numeric sequence, the country list is a single linked list, with each entry pointing to the next. The last country in the list has a dwNextCountryID value of 0. When the LINECOUNTRYLIST structure is used to obtain the entire list, the entries in the list will be in sequence as linked by their dwNextCountryID fields.

dwCountryNameSize
dwCountryNameOffset

The size in bytes and the offset in bytes from the beginning of the LINECOUNTRYLIST structure of a null-terminated string giving the name of the country.

dwSameAreaRuleSize
dwSameAreaRuleOffset

The size in bytes and the offset in bytes from the beginning of the LINECOUNTRYLIST structure of a null-terminated ASCII string containing the dialing rule for direct-dialed calls to the same area code.

dwLongDistanceRuleSize
dwLongDistanceRuleOffset

The size in bytes and the offset in bytes from the beginning of the LINECOUNTRYLIST structure of a null-terminated ASCII string containing the dialing rule for direct-dialed calls to other areas in the same country.

dwInternationalRuleSize
dwInternationalRuleOffset

The size in bytes and the offset in bytes from the beginning of the LINECOUNTRYLIST structure of a null-terminated ASCII string containing the dialing rule for direct-dialed calls to other countries.

Not extensible.

Because this structure is returned by a new function, backward compatibility is not an issue at this time.


LINECOUNTRYLIST

[New - Windows 95]

typedef struct linecountrylist_tag {
    DWORD  dwTotalSize;
    DWORD  dwNeededSize;
    DWORD  dwUsedSize;

    DWORD  dwNumCountries;
    DWORD  dwCountryListSize;
    DWORD  dwCountryListOffset;
} LINECOUNTRYLIST, FAR *LPLINECOUNTRYLIST;

The LINECOUNTRYLIST structure describes a list of countries. A structure of this type is returned by the function lineGetCountry.

dwTotalSize

The total size in bytes allocated to this data structure.

dwNeededSize

The size in bytes for this data structure that is needed to hold all the returned information.

dwUsedSize

The size in bytes of the portion of this data structure that contains useful information.

dwNumCountries

Specifies the number of LINECOUNTRYENTRY structures present in the array denominated by dwCountryListSize and dwCountryListOffset.

dwCountryListSize
dwCountryListOffset

The size in bytes and the offset in bytes from the beginning of this data structure of an array of LINECOUNTRYENTRY elements which provide the information on each country.

Not extensible.

Because this structure is returned by a new function, backward compatibility is not an issue at this time.


LINEDEVCAPS

[New - Windows 95]

typedef struct linedevcaps_tag {
  DWORD  dwTotalSize;
  DWORD  dwNeededSize;
  DWORD  dwUsedSize;

  DWORD  dwProviderInfoSize;
  DWORD  dwProviderInfoOffset;

  DWORD  dwSwitchInfoSize;
  DWORD  dwSwitchInfoOffset;

  DWORD  dwPermanentLineID;
  DWORD  dwLineNameSize;
  DWORD  dwLineNameOffset;
  DWORD  dwStringFormat;

  DWORD  dwAddressModes;
  DWORD  dwNumAddresses;
  DWORD  dwBearerModes;
  DWORD  dwMaxRate;
  DWORD  dwMediaModes;

  DWORD  dwGenerateToneModes;
  DWORD  dwGenerateToneMaxNumFreq;
  DWORD  dwGenerateDigitModes;
  DWORD  dwMonitorToneMaxNumFreq;
  DWORD  dwMonitorToneMaxNumEntries;
  DWORD  dwMonitorDigitModes;
  DWORD  dwGatherDigitsMinTimeout;
  DWORD  dwGatherDigitsMaxTimeout;

  DWORD  dwMedCtlDigitMaxListSize;
  DWORD  dwMedCtlMediaMaxListSize;
  DWORD  dwMedCtlToneMaxListSize;
  DWORD  dwMedCtlCallStateMaxListSize;

  DWORD  dwDevCapFlags;
  DWORD  dwMaxNumActiveCalls;
  DWORD  dwAnswerMode;
  DWORD  dwRingModes;
  DWORD  dwLineStates;

  DWORD  dwUUIAcceptSize;
  DWORD  dwUUIAnswerSize;
  DWORD  dwUUIMakeCallSize;
  DWORD  dwUUIDropSize;
  DWORD  dwUUISendUserUserInfoSize;
  DWORD  dwUUICallInfoSize;

  LINEDIALPARAMS  MinDialParams;
  LINEDIALPARAMS  MaxDialParams;
  LINEDIALPARAMS  DefaultDialParams;

  DWORD  dwNumTerminals;
  DWORD  dwTerminalCapsSize;
  DWORD  dwTerminalCapsOffset;
  DWORD  dwTerminalTextEntrySize;
  DWORD  dwTerminalTextSize;
  DWORD  dwTerminalTextOffset;

  DWORD  dwDevSpecificSize;
  DWORD  dwDevSpecificOffset;

  DWORD  dwLineFeatures;
} LINEDEVCAPS, FAR *LPLINEDEVCAPS;

The LINEDEVCAPS structure describes the capabilities of a line device.

dwTotalSize

The total size in bytes allocated to this data structure.

dwNeededSize

The size in bytes for this data structure that is needed to hold all the returned information.

dwUsedSize

The size in bytes of the portion of this data structure that contains useful information.

dwProviderInfoSize
dwProviderInfoOffset

The size in bytes of the variably sized field containing service provider information, and the offset in bytes from the beginning of this data structure. The dwProviderInfoSize/Offset field is intended to provide information about the provider hardware and/or software, such as the vendor name and version numbers of hardware and software. This information can be useful when a user needs to call customer service with problems regarding the provider.

dwSwitchInfoSize
dwSwitchInfoOffset

The size in bytes of the variably sized device field containing switch information, and the offset in bytes from the beginning of this data structure. The dwSwitchInfoSize/Offset field is intended to provide information about the switch to which the line device is connected, such as the switch manaufacturer, the model name, the software version, and so on. This information can be useful when a user needs to call customer service with problems regarding the switch.

dwPermanentLineID

Specifies the permanent DWORD identifier by which the line device is known in the system's configuration. It is a permanent name for the line device. This permanent name (as opposed to dwDevice ID) does not change as lines are added or removed from the system. It can therefore be used to link line-specific information in INI files (or other files) in a way that is not affected by adding or removing other lines.

dwLineNameSize
dwLineNameOffset

The size in bytes of the variably sized device field containing user configurable name for this line device, and the offset in bytes from the beginning of this data structure. This name can be configured by the user when configuring the line device's service provider, and is provided for the user's convenience.

dwStringFormat

Specifies the string format used with this line device. This field uses the following STRINGFORMAT_ constants:

STRINGFORMAT_ASCII

The ASCII string format using one byte per character.

STRINGFORMAT_DBCS

The DBCS string format using two bytes per character.

STRINGFORMAT_UNICODE

The unicode string format using two bytes per character.

dwAddressModes

Specifies the mode by which the originating address is specified. This field uses the LINEADDRESSMODE_ constants.

dwNumAddresses

Specifies the number of addresses associated with this line device. Individual addresses are referred to by address IDs. Address IDs range from zero to one less than the value indicated by dwNumAddresses.

dwBearerModes

This flag array indicates the different bearer modes that the address is able to support. It uses the following LINEBEARERMODE_ constants:

LINEBEARERMODE_VOICE

This is a regular 3.1kHz analog voice grade bearer service. Bit integrity is not assured. Voice can support fax and modem media modes.

LINEBEARERMODE_SPEECH

This corresponds to G.711 speech transmission on the call. The network may use processing techniques such as analog transmission, echo cancellation and compression/decompression. Bit integrity is not assured. Speech is not intended to support fax and modem media modes.

LINEBEARERMODE_MULTIUSE

The multi-use mode defined by ISDN.

LINEBEARERMODE_DATA

The unrestricted data transfer on the call. The data rate is specified separately.

LINEBEARERMODE_ALTSPEECHDATA

The alternate transfer of speech or unrestricted data on the same call (ISDN).

LINEBEARERMODE_NONCALLSIGNALING

This corresponds to a non-call-associated signaling connection from the application to the service provider or switch (treated as a "media stream" by the Telephony API).

LINEBEARERMODE_PASSTHROUGH

When a call is active in LINEBEARERMODE_PASSTHROUGH, the service provider gives direct access to the attached hardware for control by the application. This mode is used primarily by applications desiring temporary direct control over asynchronous modems, accessed via the Win32 comm functions, for the purpose of configuring or using special features not otherwise supported by the service provider.

dwMaxRate

This field contains the maximum data rate in bits per second for information exchange over the call.

dwMediaModes

This flag array indicates the different media modes the address is able to support. It uses the following LINEMEDIAMODE_ constants:

LINEMEDIAMODE_UNKNOWN

A media stream exists but its mode is not known. This corresponds to a call with an unclassified media type. In typical analog telephony environments, an inbound call's media mode may be unknown until after the call has been answered and the media stream filtered to make a determination.

LINEMEDIAMODE_INTERACTIVEVOICE

The presence of voice energy on the call and the call is treated as an interactive call with humans on both ends.

LINEMEDIAMODE_AUTOMATEDVOICE

The presence of voice energy on the call and the voice is locally handled by an automated application.

LINEMEDIAMODE_DATAMODEM

A data modem session on the call.

LINEMEDIAMODE_G3FAX

A group 3 fax is being sent or received over the call.

LINEMEDIAMODE_TDD

A TDD (Telephony Devices for the Deaf) session on the call.

LINEMEDIAMODE_G4FAX

A group 4 fax is being sent or received over the call.

LINEMEDIAMODE_DIGITALDATA

Digital data being transmitted over the call.

LINEMEDIAMODE_TELETEX

A teletex session on the call. Teletex is one of the telematic services.

LINEMEDIAMODE_VIDEOTEX

A videotex session on the call. Videotex is one the telematic services.

LINEMEDIAMODE_TELEX

A telex session on the call. Telex is one the telematic services.

LINEMEDIAMODE_MIXED

A mixed session on the call. Mixed is one the ISDN telematic services.

LINEMEDIAMODE_ADSI

An ADSI (Analog Display Services Interface) session on the call.

dwGenerateToneModes

Specifies the different kinds of tones that can be generated on this line. This field uses the following LINETONEMODE_ constants:

LINETONEMODE_CUSTOM

The tone is a custom tone defined by the specified frequencies.

LINETONEMODE_RINGBACK

The tone to be generated is ringback tone.

LINETONEMODE_BUSY

The tone is a standard (station) busy tone.

LINETONEMODE_BEEP

The tone is a beep, as used to announce the beginning of a recording.

LINETONEMODE_BILLING

The tone is billing information tone such as a credit card prompt tone.

dwGenerateToneMaxNumFreq

This field contains the maximum number of frequencies that can be specified in describing a general tone using the LINEGENERATETONE data structure when generating a tone using lineGenerateTone. A value of zero indicates that tone generation is not available.

dwGenerateDigitModes

This field specifies the digit modes than can be generated on this line. It uses the following LINEDIGITMODE_ constants:

LINEDIGITMODE_PULSE

Generate digits as pulse/rotary pulse sequences.

LINEDIGITMODE_DTMF

Generate digits as DTMF tones.

dwMonitorToneMaxNumFreq

This field contains the maximum number of frequencies that can be specified in describing a general tone using the LINEMONITORTONE data structure when monitoring a general tone using lineMonitorTones. A value of zero indicates that tone monitor is not available.

dwMonitorToneMaxNumEntries

This field contains the maximum number of entries that can be specified in a tone list to lineMonitorTones.

dwMonitorDigitModes

This field specifies the digit modes than can be detected on this line. It uses the following LINEDIGITMODE_ constants:

LINEDIGITMODE_PULSE

Detect digits as audible clicks that are the result of rotary pulse sequences.

LINEDIGITMODE_DTMF

Detect digits as DTMF tones.

LINEDIGITMODE_DTMFEND

Detect the down edges of digits detected as DTMF tones.

dwGatherDigitsMinTimeout
dwGatherDigitsMaxTimeout

These fields contain the minimum and maximum values in milliseconds that can be specified for both the first digit and inter-digit timeout values used by lineGatherDigits. If both these field are zero, timeouts are not supported.

dwMedCtlDigitMaxListSize
dwMedCtlMediaMaxListSize
dwMedCtlToneMaxListSize
dwMedCtlCallStateMaxListSize

These fields contain the maximum number of entries that can be specified in the digit list, the media list, the tone list, and the call state list parameters of lineSetMediaControl respectively.

dwDevCapFlags

This field specifies various Boolean device capabilities. It uses the following LINEDEVCAPFLAGS_ constants:

LINEDEVCAPFLAGS_CROSSADDRCONF

Specifies whether calls on different addresses on this line can be conferenced.

LINEDEVCAPFLAGS_HIGHLEVCOMP

Specifies whether high-level compatibility information elements are supported on this line.

LINEDEVCAPFLAGS_LOWLEVCOMP

Specifies whether low-level compatibility information elements are supported on this line.

LINEDEVCAPFLAGS_MEDIACONTROL

Specifies whether media-control operations are available for calls at this line.

LINEDEVCAPFLAGS_MULTIPLEADDR

Specifies whether lineMakeCall or lineDial are able to deal with multiple addresses at once (such as for inverse multiplexing).

LINEDEVCAPFLAGS_CLOSEDROP

Specifies what happens when an open line is closed while the application has calls active on the line. If TRUE, then a lineClose will drop (that is, clear) all calls on the line if the application is the sole owner of those calls. Knowing the setting of this flag ahead of time makes it possible for the application to display an OK/Cancel dialog box for the user, warning that the active call will be lost. If CLOSEDROP is FALSE, a lineClose will not automatically drop any calls that are still active on the line if the service provider knows that some other device can keep the call alive. For example, if an analog line has the computer and phoneset both connect directly to them (in a party-line configuration), the service provider should set the flag to FALSE, as the offhook phone will automatically keep the call active even after the computer powers down.

LINEDEVCAPFLAGS_DIALBILLING

LINEDEVCAPFLAGS_DIALQUIET

LINEDEVCAPFLAGS_DIALDIALTONE

These flags indicate whether the "$", "@", or "W" dialable string modifier is supported for a given line device.  It is TRUE if the modifier is supported; otherwise, FALSE. The "?" (prompt user to continue dialing) is never supported by a line device. These flags allow an application to determine "up front" which modifiers would result in the generation of a LINEERR. The application has the choice of pre-scanning dialable strings for unsupported characters, or passing the "raw" string from lineTranslateAddress directly to the provider as part of lineMakeCall (lineDial, etc.) and let the function generate an error to tell it which unsupported modifier occurs first in the string.

dwMaxNumActiveCalls

This field provides the maximum number of (minimum bandwidth) calls that can be active (connected) on the line at any one time. The actual number of active calls may be lower if higher bandwidth calls have been established on the line.

dwAnswerMode

This field specifies the effect on the active call when answering another offering call on a line device. This field uses the following LINEANSWERMODE_ constants:

LINEANSWERMODE_NONE

Answering another call on the same line has no effect on the existing active call(s) on the line.

LINEANSWERMODE_DROP

The currently active call will be automatically dropped.

LINEANSWERMODE_HOLD

The currently active call will automatically be placed on hold.

dwRingModes

This field contains the number of different ring modes that can be reported in the LINE_LINEDEVSTATE message with the ringing indication. Different ring modes range from one to dwRingModes. Zero indicates no ring.

dwLineStates

This field specifies the different line status components for which the application may be notified in a LINE_LINEDEVSTATE message on this line. It uses the following LINEDEVSTATE_ constants:

LINEDEVSTATE_OTHER

Device-status items other than those listed below have changed. The application should check the current device status to determine which items have changed.

LINEDEVSTATE_RINGING

The switch tells the line to alert the user.

LINEDEVSTATE_CONNECTED

The line was previously disconnected and is now connected to TAPI.

LINEDEVSTATE_DISCONNECTED

This line was previously connected and is now disconnected from TAPI.

LINEDEVSTATE_MSGWAITON

The "message waiting" indicator is turned on.

LINEDEVSTATE_MSGWAITOFF

The "message waiting" indicator is turned off.

LINEDEVSTATE_NUMCOMPLETIONS

The number of outstanding call completions on the line device has changed.

LINEDEVSTATE_INSERVICE

The line is connected to TAPI. This happens when TAPI is first activated or when the line wire is physically plugged in and in service at the switch while TAPI is active.

LINEDEVSTATE_OUTOFSERVICE

The line is out of service at the switch or physically disconnected. TAPI cannot be used to operate on the line device.

LINEDEVSTATE_MAINTENANCE

Maintenance is being performed on the line at the switch. TAPI cannot be used to operate on the line device.

LINEDEVSTATE_OPEN

The line has been opened.

LINEDEVSTATE_CLOSE

The line has been closed.

LINEDEVSTATE_NUMCALLS

The number of calls on the line device has changed.

LINEDEVSTATE_TERMINALS

The terminal settings have changed.

LINEDEVSTATE_ROAMMODE

The roam mode of the line device has changed.

LINEDEVSTATE_BATTERY

The battery level has changed significantly (cellular).

LINEDEVSTATE_SIGNAL

The signal level has changed significantly (cellular).

LINEDEVSTATE_DEVSPECIFIC

The line's device-specific information has changed.

LINEDEVSTATE_REINIT

Items have changed in the configuration of line devices. To become aware of these changes (such as for the appearance of new line devices), the application should reinitialize its use of TAPI. The hDevice parameter is left NULL for this state change as it applies to any of the lines in the system.

LINEDEVSTATE_LOCK

The locked status of the line device has changed.

LINEDEVSTATE_CAPSCHANGE

Indicates that, due to configuration changes made by the user or other circumstances, one or more of the fields in the LINEDEVCAPS structure for the address have changed. The application should use lineGetDevCaps to read the updated structure. If a service provider sends a LINE_LINEDEVSTATE message containing this value to TAPI, TAPI will pass it along to applications which have negotiated this or a subsequent API version; applications negotiating a previous API version will receive LINE_LINEDEVSTATE messages specifying LINEDEVSTATE_REINIT, requiring them to shutdown and reinitialize their connection to TAPI in order to obtain the updated information.

LINEDEVSTATE_CONFIGCHANGE

Indicates that configuration changes have been made to one or more of the media devices associated with the line device. The application, if it desires, may use lineGetDevConfig to read the updated information. If a service provider sends a LINE_LINEDEVSTATE message containing this value to TAPI, TAPI will pass it along to applications which have negotiated this or a subsequent API version; applications negotiating a previous API version will not receive any notification.

LINEDEVSTATE_TRANSLATECHANGE

Indicates that, due to configuration changes made by the user or other circumstances, one or more of the fields in the LINETRANSLATECAPS structure have changed. The application should use lineGetTranslateCaps to read the updated structure. If a service provider sends a LINE_LINEDEVSTATE message containing this value to TAPI, TAPI will pass it along to applications which have negotiated this or a subsequent API version; applications negotiating a previous API version will receive LINE_LINEDEVSTATE messages specifying LINEDEVSTATE_REINIT, requiring them to shutdown and reinitialize their connection to TAPI in order to obtain the updated information.

LINEDEVSTATE_COMPLCANCEL

Indicates that the call completion identified by the completion ID contained in parameter dwParam2 of the LINE_LINEDEVSTATE message has been externally cancelled and is no longer considered valid (if that value were to be passed in a subsequent call to lineUncompleteCall, the function would fail with LINEERR_INVALCOMPLETIONID). If a service provider sends a LINE_LINEDEVSTATE message containing this value to TAPI, TAPI will pass it along to applications which have negotiated this or a subsequent API version; applications negotiating a previous API version will not receive any notification.

LINEDEVSTATE_REMOVED

Indicates that the device is being removed from the system by the service provider (most likely through user action, via a control panel or similar utility). A LINE_LINEDEVSTATE message with this value will normally be immediately followed by a LINE_CLOSE message on the device. Subsequent attempts to access the device prior to TAPI being reinitialized will result in LINEERR_NODEVICE being returned to the application. If a service provider sends a LINE_LINEDEVSTATE message containing this value to TAPI, TAPI will pass it along to applications which have negotiated this or a subsequent API version; applications negotiating a previous API version will not receive any notification.

dwUUIAcceptSize

This field specifies the maximum size of user-to-user information that can be sent during a call accept.

dwUUIAnswerSize

This field specifies the maximum size of user-to-user information that can be sent during a call answer.

dwUUIMakeCallSize

This field specifies the maximum size of user-to-user information that can be sent during a make call.

dwUUIDropSize

This field specifies the maximum size of user-to-user information that can be sent during a call drop.

dwUUISendUserUserInfoSize

This field specifies the maximum size of user-to-user information that can be sent separately any time during a call with lineSendUserUserInfo.

dwUUICallInfoSize

This field specifies the maximum size of user-to-user information that can be received in the LINECALLINFO structure.

MinDialParams
MaxDialParams

These fields contain the minimum and maximum values for the dial parameters in milliseconds that can be set for calls on this line. Dialing parameters can be set to values in this range. The granularity of the actual settings is service provider-specific.

DefaultDialParams

This field contains the default dial parameters used for calls on this line. These parameter values can be overridden on a per-call basis.

dwNumTerminals

Specifies the number of terminals that can be set for this line device, its addresses, or its calls. Individual terminals are referred to by terminal IDs and range from zero to one less than the value indicated by dwNumTerminals.

dwTerminalCapsSize
dwTerminalCapsOffset

The size in bytes and the offset in bytes from the beginning of this data structure of the variably sized device field containing an array with entries of type LINETERMCAPS. This array is indexed by terminal IDs, in the range from zero to dwNumTerminals minus one. Each entry in the array specifies the terminal device capabilities of the corresponding terminal.

dwTerminalTextEntrySize

Specifies the size in bytes of each of the terminal text descriptions pointed at by dwTerminalTextSize/Offset.

dwTerminalTextSize
dwTerminalTextOffset

The size in bytes of the variably sized field containing descriptive text about each of the line's available terminals, and the offset in bytes from the beginning of this data structure  Each message is dwTerminalTextEntrySize bytes long. The string format of these textual descriptions is indicated by dwStringFormat in the line's device capabilities.

dwDevSpecificSize
dwDevSpecificOffset

The size in bytes of the variably sized device-specific field, and the offset in bytes from the beginning of this data structure

dwLineFeatures

This field specifies the features available for this line using the LINEFEATURE_ constants. Invoking a supported feature requires the line to be in the proper state and the underlying line device to be opened in a compatible mode. A zero in a bit position indicates that the corresponding feature is never available. A one indicates that the corresponding feature may be available if the line is in the appropriate state for the operation to be meaningful. This field allows an application to discover which line features can be (and which can never be) supported by the device.

Device-specific extensions should use the DevSpecific (dwDevSpecificSize and dwDevSpecificOffset) variably sized area of this data structure.

Older applications will have been compiled without this field in the LINEDEVCAPS structure, and using a SIZEOF LINEDEVCAPS smaller than the new size. The application passes in a dwAPIVersion parameter with the lineGetDevCaps function, which can be used for guidance by TAPI in handling this situation. If the application passes in a dwTotalSize less than the size of the fixed portion of the structure as defined in the dwAPIVersion specified, LINEERR_STRUCTURETOOSMALL will be returned. If sufficient memory has been allocated by the application, before calling TSPI_lineGetDevCaps, TAPI will set the dwNeededSize and dwUsedSize fields to the fixed size of the structure as it existed in the specified API version.

New service providers (which support the new API version) must examine the API version passed in. If the API version is less than the highest version supported by the provider, the service provider must not fill in fields not supported in older API versions, as these would fall in the variable portion of the older structure.

New applications must be cognizant of the API version negotiated, and not examine the contents of fields in the fixed portion beyond the original end of the fixed portion of the structure for the negotiated API version.

If the LINEBEARERMODE_DATA bit is set in dwBearerModes member, the dwMaxRate member indicates the maximum rate of digital transmission on the bearer channel. The dwMaxRate member of the LINEDEVCAPS structure can contain valid values even if the dwBearerModes member of the LINEDEVCAPS structure is not set to LINEBEARERMODE_DATA.

If LINEBEARERMODE_DATA is not set in dwBearerModes, but the LINEBEARERMODE_VOICE value is set and the LINEMEDIAMODE_DATAMODEM value is set in the dwMediaModes member, the dwMaxRate member indicates the maximum SYNCHRONOUS (DCE) bit rate on the phone line for the attached modem or functional equivalent. For example, if the modem's fastest modulation speed is V.32bis at 14,400bps, dwMaxRate will equal 14400. This is not the fastest DTE port rate (which would most likely be 38400, 57600, or 115200), but the fastest bit rate the modem supports on the phone line.

The application must be careful to check to see that LINEBEARERMODE_DATA is not set, in order to avoid misinterpreting the dwMaxRate member. It is likely to be 64000 or higher if LINEBEARERMODE_DATA is set.

It should also be noted that if the modem has not been specifically identified (for example, it is a "generic" modem), the figure indicated is a "best guess" based on examination of the modem.


LINEDEVSTATUS

[New - Windows 95]

typedef struct linedevstatus_tag {
  DWORD  dwTotalSize;
  DWORD  dwNeededSize;
  DWORD  dwUsedSize;

  DWORD  dwNumOpens;
  DWORD  dwOpenMediaModes;
  DWORD  dwNumActiveCalls;
  DWORD  dwNumOnHoldCalls;
  DWORD  dwNumOnHoldPendCalls;
  DWORD  dwLineFeatures;
  DWORD  dwNumCallCompletions;
  DWORD  dwRingMode;
  DWORD  dwSignalLevel;
  DWORD  dwBatteryLevel;
  DWORD  dwRoamMode;

  DWORD  dwDevStatusFlags;

  DWORD  dwTerminalModesSize;
  DWORD  dwTerminalModesOffset;

  DWORD  dwDevSpecificSize;
  DWORD  dwDevSpecificOffset;
} LINEDEVSTATUS, FAR *LPLINEDEVSTATUS;

The LINEDEVSTATUS structure describes the current status of a line device.

dwTotalSize

The total size in bytes allocated to this data structure.

dwNeededSize

The size in bytes for this data structure that is needed to hold all the returned information.

dwUsedSize

The size in bytes of the portion of this data structure that contains useful information.

dwNumOpens

Specifies the number of active opens on the line device.

dwOpenMediaModes

This bit array indicates for which media modes the line device is currently open.

dwNumActiveCalls

The number of calls on the line in call states other than idle, onhold, onholdpendingtransfer, and onholdpendingconference.

dwNumOnHoldCalls

The number of calls on the line in the onhold state.

dwNumOnHoldPendingCalls

The number of calls on the line in the onholdpendingtransfer or onholdpendingconference states.

dwLineFeatures

This field specifies the line-related API functions that are currently available on this line. It uses the following LINEFEATURE_ constants:

LINEFEATURE_DEVSPECIFIC

Device-specific operations can be used on the line.

LINEFEATURE_DEVSPECIFICFEAT

Device-specific features can be used on the line.

LINEFEATURE_FORWARD

Forwarding of all addresses can be used on the line.

LINEFEATURE_MAKECALL

An outbound call can be placed on this line using an unspecified address.

LINEFEATURE_SETMEDIACONTROL

Media control can be set on this line.

LINEFEATURE_SETTERMINAL

Terminal modes for this line can be set.

dwNumCallCompletions

Specifies the number of outstanding call completion requests on the line.

dwRingMode

Specifies the current ring mode on the line device.

dwBatteryLevel

Specifies the current battery level of the line device hardware. This is a value in the range 0x00000000 (battery empty) to 0x0000FFFF (battery full).

dwSignalLevel

Specifies the current signal level of the connection on the line. This is a value in the range 0x00000000 (weakest signal) to 0x0000FFFF (strongest signal).

dwRoamMode

Specifies the current roam mode of the line device. It uses the following LINEROAMMODE_ constants:

LINEROAMMODE_UNKNOWN

The roam mode is currently unknown but may become known later.

LINEROAMMODE_UNAVAIL

The roam mode is unavailable and will not be known.

LINEROAMMODE_HOME

The line is connected to the home network node.

LINEROAMMODE_ROAMA

The line is connected to the Roam-A carrier and calls are charged accordingly.

LINEROAMMODE_ROAMB

The line is connected to the Roam-B carrier and calls are charged accordingly.

dwDevStatusFlags

The size in bytes of this data structure that contains useful information, of type LINEDEVSTATUSFLAGS_.

LINEDEVSTATUSFLAGS_CONNECTED

Specifies whether the line is connected to TAPI. If TRUE, the line is connected and API is able to operate on the line device. If FALSE, the line is disconnected and the application is unable to control the line device using TAPI.

LINEDEVSTATUSFLAGS_LOCKED

This bit is most often used with line devices associated with cellular phones. Many cellular phones have a security mechanism that requires the entry of a password to enable the phone to place calls. This bit may be used to indicate to applications that the phone is locked and cannot place calls until the password is entered on the user interface of the phone, so that the application can present an appropriate alert to the user.

LINEDEVSTATUSFLAGS_MSGWAIT

This field indicates whether the line has a message waiting. If TRUE, a message is waiting; if FALSE, no message is waiting.

LINEDEVSTATUSFLAGS_INSERVICE

This field indicates whether the line is in service. If TRUE, the line is in service; if FALSE, the line is out of service.

dwTerminalModesSize
dwTerminalModesOffset

The size in bytes of the variably sized device field containing an array with DWORD-sized entries, and the offset in bytes from the beginning of this data structure. This array is indexed by terminal IDs, in the range from zero to dwNumTerminals minus one. Each entry in the array specifies the current terminal modes for the corresponding terminal set using the lineSetTerminal operation for this line. It uses the following LINETERMMODE_ constants:

LINETERMMODE_LAMPS

These are lamp events sent from the line to the terminal.

LINETERMMODE_BUTTONS

These are button-press events sent from the terminal to the line.

LINETERMMODE_DISPLAY

This is display information sent from the line to the terminal.

LINETERMMODE_RINGER

This is ringer-control information sent from the switch to the terminal.

LINETERMMODE_HOOKSWITCH

These are hookswitch event sent between the terminal and the line.

LINETERMMODE_MEDIATOLINE

This is the unidirectional media stream from the terminal to the line associated with a call on the line. Use this value when the routing of both unidirectional channels of a call's media stream can be controlled independently.

LINETERMMODE_MEDIAFROMTERM

This is the unidirectional media stream from the line to the terminal associated with a call on the line. Use this value when the routing of both unidirectional channels of a call's media stream can be controlled independently.

LINETERMMODE_MEDIABIDIRECT

This is the bidirectional media stream associated with a call on the line and the terminal. Use this value when the routing of both unidirectional channels of a call's media stream cannot be controlled independently.

dwDevSpecificSize
dwDevSpecificOffset

The size in bytes of the variably sized device-specific field, and the offset in bytes from the beginning of this data structure.

Device-specific extensions should use the DevSpecific (dwDevSpecificSize and dwDevSpecificOffset) variably sized area of this data structure.


LINEDIALPARAMS

[New - Windows 95]

typedef struct linedialparams_tag {
  DWORD  dwDialPause;
  DWORD  dwDialSpeed;
  DWORD  dwDigitDuration;
  DWORD  dwWaitForDialtone;
} LINEDIALPARAMS, FAR *LPLINEDIALPARAMS;

The LINEDIALPARAMS structure specifies a collection of dialing-related fields.

dwDialPause

Specifies the duration in milliseconds of a comma in the dialable address.

dwDialSpeed

Specifies the inter-digit time period in milliseconds between successive digits.

dwDigitDuration

Specifies the duration in milliseconds of a digit.

dwWaitForDialtone

Specifies the maximum amount of time that should be waited for dialtone when a 'W' is used in the dialable address.

No extensions.

When a value of zero is specified for a field, the default value for that field is used. If a non-zero value is specified for a field which is outside the range specified by the corresponding fields in MinDialParams and MaxDialParams in the LINEDEVCAPS structure, the nearest value within the valid range is used instead.

The lineMakeCall function allows an application to adjust the dialing parameters to be used for the call. The lineSetCallParams function can be used to adjust the dialing parameters of an existing call. The LINECALLINFO structure lists the call's current dialing parameters.


LINEEXTENSIONID

[New - Windows 95]

typedef struct lineextensionid_tag {
  DWORD  dwExtensionID0;
  DWORD  dwExtensionID1;
  DWORD  dwExtensionID2;
  DWORD  dwExtensionID3;
} LINEEXTENSIONID, FAR *LPLINEEXTENSIONID;

The LINEEXTENSIONID structure describes an extension ID. Extension IDs are used to identify service provider-specific extensions for line devices.

dwExtensionID0
dwExtensionID1
dwExtensionID2
dwExtensionID3

These four DWORD-sized fields together specify a universally unique extension ID that identifies a line device class extension.

No extensions.

Extension IDs are generated using an SDK-provided generation utility.


LINEFORWARD

[New - Windows 95]

typedef struct lineforward_tag {
  DWORD  dwForwardMode;

  DWORD  dwCallerAddressSize;
  DWORD  dwCallerAddressOffset;

  DWORD  dwDestCountryCode;
  DWORD  dwDestAddressSize;
  DWORD  dwDestAddressOffset;
} LINEFORWARD, FAR *LPLINEFORWARD;

The LINEFORWARD structure describes an entry of the forwarding instructions.

dwForwardMode

Specifies the types of forwarding. dwForwardMode can have only a single bit set. This field uses the following  LINEFORWARDMODE_ constants:

LINEFORWARDMODE_UNCOND

Forward all calls unconditionally, irrespective of their origin. Use this value when unconditional forwarding for internal and external calls cannot be controlled separately. Unconditional forwarding overrides forwarding on busy and/or no answer conditions.

LINEFORWARDMODE_UNCONDINTERNAL

Forward all internal calls unconditionally. Use this value when unconditional forwarding for internal and external calls can be controlled separately.

LINEFORWARDMODE_UNCONDEXTERNAL

Forward all external calls unconditionally. Use this value when unconditional forwarding for internal and external calls can be controlled separately.

LINEFORWARDMODE_UNCONDSPECIFIC

Unconditionally forward all calls that originated at a specified address (selective call forwarding).

LINEFORWARDMODE_BUSY

Forward all calls on busy, irrespective of their origin. Use this value when forwarding for internal and external calls both on busy and on no answer cannot be controlled separately.

LINEFORWARDMODE_BUSYINTERNAL

Forward all internal calls on busy. Use this value when forwarding for internal and external calls on busy and on no answer can be controlled separately.

LINEFORWARDMODE_BUSYEXTERNAL

Forward all external calls on busy. Use this value when forwarding for internal and external calls on busy and on no answer can be controlled separately.

LINEFORWARDMODE_BUSYSPECIFIC

Forward on busy all calls that originated at a specified address (selective call forwarding).

LINEFORWARDMODE_NOANSW

Forward all calls on no answer, irrespective of their origin. Use this value when call forwarding for internal and external calls on no answer cannot be controlled separately.

LINEFORWARDMODE_NOANSWINTERNAL

Forward all internal calls on no answer. Use this value when forwarding for internal and external calls on no answer can be controlled separately.

LINEFORWARDMODE_NOANSWEXTERNAL

Forward all external calls on no answer. Use this value when forwarding for internal and external calls on no answer can be controlled separately.

LINEFORWARDMODE_NOANSWSPECIFIC

Forward all calls that originated at a specified address on no answer (selective call forwarding).

LINEFORWARDMODE_BUSYNA

Forward all calls on busy/no answer, irrespective of their origin. Use this value when forwarding for internal and external calls on both busy and on no answer cannot be controlled separately.

LINEFORWARDMODE_BUSYNAINTERNAL

Forward all internal calls on busy/no answer. Use this value when call forwarding on busy and on no answer cannot be controlled separately for internal calls.

LINEFORWARDMODE_BUSYNAEXTERNAL

Forward all external calls on busy/no answer. Use this value when call forwarding on busy and on no answer cannot be controlled separately for internal calls.

LINEFORWARDMODE_BUSYNASPECIFIC

Forward on busy/no answer all calls that originated at a specified address (selective call forwarding).

LINEFORWARDMODE_UNKNOWN

Calls are forwarded, but the conditions under which forwarding will occur are not known at this time. It is possible that the conditions may become known at a future time.

LINEFORWARDMODE_UNAVAIL

Calls are forwarded, but the conditions under which forwarding will occur are not known, and will never be known by the service provider.

dwCallerAddressSize
dwCallerAddressOffset

The size in bytes of the variably sized address field containing the address of a caller to be forwarded, and the offset in bytes from the beginning of the containing data structure. dwCallerAddressSize/Offset is set to zero if dwForwardMode is not one of the following: LINEFORWARDMODE_BUSYNASPECIFIC, LINEFORWARDMODE_NOANSWSPECIFIC, LINEFORWARDMODE_UNCONDSPECIFIC, or LINEFORWARDMODE_BUSYSPECIFIC.

dwDestCountryCode

Specifies the country code of the destination address to which the call is to be forwarded.

dwDestAddressSize
dwDestAddressOffset

The size in bytes  of the variably sized address field containing the address of the address where calls are to be forwarded, and the offset in bytes from the beginning of the containing data structure.

No extensions.

Each entry in the LINEFORWARD structure specifies a forwarding request.


LINEFORWARDLIST

[New - Windows 95]

The LINEFORWARDLIST structure describes a list of forwarding instructions.

typedef struct lineforwardlist_tag {
  DWORD  dwTotalSize;

  DWORD  dwNumEntries;
  LINEFORWARD  ForwardList[1];
} LINEFORWARDLIST, FAR *LPLINEFORWARDLIST;

The LINEFORWARDLIST structure contains the following fields:

dwTotalSize

Specifies the total size in bytes of the data structure.

dwNumEntries

Specifies number of entries in the array specified as ForwardList[ ].

ForwardList[ ]

Specifies an array of forwarding instruction. The array's entries are of type LINEFORWARD.

No extensions.

The LINEFORWARDLIST structure defines the forwarding parameters requested for forwarding calls on an address or on all addresses on a line.


LINEGENERATETONE

[New - Windows 95]

typedef struct linegeneratetone_tag {
  DWORD  dwFrequency;
  DWORD  dwCadenceOn;
  DWORD  dwCadenceOff;
  DWORD  dwVolume;
} LINEGENERATETONE, FAR *LPLINEGENERATETONE;

The LINEGENERATETONE structure contains information about a tone to be generated.

dwFrequency

Specifies the frequency in Hertz of this tone component. A service provider may adjust (round up or down) the frequency specified by the application to fit its resolution.

dwCadenceOn

Determines the "on" duration in milliseconds of the cadence of the custom tone to be generated. Zero means no tone is generated.

dwCadenceOff

Determines the "off" duration in milliseconds of the cadence of the custom tone to be generated. Zero means no off time, that is, a constant tone.

dwVolume

Determines the volume level at which the tone is to be generated. A value of 0x0000FFFF represents full volume, and a value of 0x00000000 is silence.

No extensions.

This structure is only used for the generation of tones. It is not used for tone monitoring.


LINELOCATIONENTRY

[New - Windows 95]

typedef struct linelocationentry_tag {
  DWORD  dwPermanentLocationID;
  DWORD  dwLocationNameSize;
  DWORD  dwLocationNameOffset;
  DWORD  dwCountryCode;

  DWORD  dwCityCodeSize;

  DWORD  dwCityCodeOffset;

  DWORD  dwPreferredCardID;
  DWORD  dwLocalAccessCodeSize;
  DWORD  dwLocalAccessCodeOffset;
  DWORD  dwLongDistanceAccessCodeSize;
  DWORD  dwLongDistanceAccessCodeOffset;
  DWORD  dwTollPrefixListSize;
  DWORD  dwTollPrefixListOffset;
  DWORD  dwCountryID;
  DWORD  dwOptions;
  DWORD  dwCancelCallWaitingSize;
  DWORD  dwCancelCallWaitingOffset;
} LINELOCATIONENTRY, FAR *LPLINELOCATIONENTRY;

The LINELOCATIONENTRY structure describes a location used to provide an address translation context.

dwPermanentLocationID

The permanent ID that identifies the location.

dwLocationNameSize
dwLocationNameOffset

Contains a NULL-terminated ASCII string (size includes the NULL) that describes the location in a user-friendly manner.

dwCountryCode

Specifies the country code of the location.

dwPreferredCardID

Specifies the preferred calling card when dialing from this location.

dwCityCodeSize
dwCityCodeOffset

Contains a NULL-terminated ASCII string specifying the city/area code associated with the location (the size includes the NULL). This information, along with the country code, can be used by applications to "default" entry fields for the user when entering phone numbers, to encourage the entry of proper canonical numbers.

dwLocalAccessCodeSize
dwLocalAccessCodeOffset

The size in bytes and the offset in bytes from the beginning of the LINETRANSLATECAPS structure of a null-terminated ASCII string containing the access code to be dialed before calls to addresses in the local calling area.

dwLongDistanceAccessCodeSize
dwLongDistanceAccessCodeOffset

The size in bytes and the offset in bytes from the beginning of the LINETRANSLATECAPS structure of a null-terminated ASCII string containing the access code to be dialed before calls to addresses outside the local calling area.

dwTollPrefixListSize
dwTollPrefixListOffset

The size in bytes and the offset in bytes from the beginning of the LINETRANSLATECAPS structure of a null-terminated ASCII string containing the toll prefix list for the location. The string will contain only prefixes consisting of the digits "0" through "9", separated from each other by a single "," (comma) character.

dwCountryID

Specifies the country ID of the country selected for the location. This can be used with the lineGetCountry function to obtain additional information about the specific country, such as the country name (the dwCountryCode field cannot be used for this purpose because country codes are not unique).

dwOptions

Indicates options in effect for this location, with values taken from the LINELOCATIONOPTION_ set of constants.

dwCancelCallWaitingSize
dwCancelCallWaitingOffset

The size in bytes and the offset in bytes from the beginning of the LINETRANSLATECAPS structure of a null-terminated ASCII string containing the dial digits and modifier characters that should be prefixed to the dialable string (after the pulse/tone character) when an application sets the LINETRANSLATEOPTION_CANCELCALLWAITING bit in the dwTranslateOptions parameter of lineTranslateAddress. If no prefix is defined, this may be indicated by dwCancelCallWaitingSize being set to 0, or by it being set to 1 and dwCancelCallWaitingOffset pointing to an empty string (single null byte).

No extensions.

Older applications will have been compiled without knowledge of these new fields, and using a SIZEOF LINELOCATIONENTRY smaller than the new size. Since this is an array in the variable portion of a LINETRANSLATECAPS structure, it is imperitive that older applications receive LINELOCATIONENTRY structures in the format they previously expected, or they will not be able to index through the array properly. The application passes in a dwAPIVersion parameter with the lineGetTranslateCaps function, which can be used for guidance by TAPI in handling this situation. lineGetTranslateCaps should use the LINELOCATIONENTRY fields and size that match the indicated API version, when building the LINETRANSLATECAPS structure to be returned to the application.


LINEMEDIACONTROLCALLSTATE

[New - Windows 95]

typedef struct linemediacontrolcallstate_tag {
  DWORD  dwCallStates;
  DWORD  dwMediaControl;
} LINEMEDIACONTROLCALLSTATE, FAR *LPLINEMEDIACONTROLCALLSTATE;

The LINEMEDIACONTROLCALLSTATE structure describes a media action to be executed when detecting transitions into one or more call states.

dwCallStates

Specifies one or more call states. This field uses the following LINECALLSTATE_ constants:

LINECALLSTATE_IDLE

The call is idle—no call exists.

LINECALLSTATE_OFFERING

The call is being offered to the station, signaling the arrival of a new call. In some environments, a call in the offering state does not automatically alert the user. Alerting is done by the switch instructing the line to ring, and it does not affect any call states.

LINECALLSTATE_ACCEPTED

The call was offering and has been accepted. This indicates to other (monitoring) applications that the current owner application has claimed responsibility for answering the call. In ISDN, this also initiates alerting to both parties.

LINECALLSTATE_DIALTONE

The call is receiving a dial tone from the switch, which means that the switch is ready to receive a dialed number.

LINECALLSTATE_DIALING

Destination address information (a phone number) is being sent to the switch over the call. Note that the operation lineGenerateDigits does not place the line into the dialing state.

LINECALLSTATE_RINGBACK

The call is receiving ringback from the called address. Ringback indicates that the other station has been reached and is being alerted.

LINECALLSTATE_BUSY

The call is receiving a busy tone. Busy tone indicates that the call cannot be completed because either a circuit (trunk) or the remote party's station are in use.

LINECALLSTATE_SPECIALINFO

Special information is sent by the network. Special information is typically sent when the destination cannot be reached.

LINECALLSTATE_CONNECTED

The call has been established, and the connection is made. Information is able to flow over the call between the originating address and the destination address.

LINECALLSTATE_PROCEEDING

Dialing has completed and the call is proceeding through the switch or telephone network.

LINECALLSTATE_ONHOLD

The call is on hold by the switch.

LINECALLSTATE_CONFERENCED

The call is currently a member of a multiparty conference call.

LINECALLSTATE_ONHOLDPENDCONF

The call is currently on hold while it is being added to a conference.

LINECALLSTATE_ONHOLDPENDTRANSF

The call is currently on hold awaiting transfer to another number.

LINECALLSTATE_DISCONNECTED

The remote party has disconnected from the call.

LINECALLSTATE_UNKNOWN

The state of the call is not known. This may be due to limitations of the call-progress detection implementation.

dwMediaControl

Specifies the media-control action. This field uses the following LINEMEDIACONTROL_ constants:

LINEMEDIACONTROL_NONE

No change is to be made to the media stream.

LINEMEDIACONTROL_RESET

Reset the media stream. Equivalent to an end-of-input. All buffers are released.

LINEMEDIACONTROL_PAUSE

Temporarily pause the media stream.

LINEMEDIACONTROL_RESUME

Start or resume a paused media stream.

LINEMEDIACONTROL_RATEUP

The speed of the media stream is increased by some stream-defined quantity.

LINEMEDIACONTROL_RATEDOWN

The speed of the media stream is decreased by some stream-defined quantity.

LINEMEDIACONTROL_RATENORMAL

The speed of the media stream is returned to normal.

LINEMEDIACONTROL_VOLUMEUP

The amplitude of the media stream is increased by some stream-defined quantity.

LINEMEDIACONTROL_VOLUMEDOWN

The amplitude of the media stream is decreased by some stream-defined quantity.

LINEMEDIACONTROL_VOLUMENORMAL

The amplitude of the media stream is returned to normal.

No extensions.

The LINEMEDIACONTROLCALLSTATE structure defines a triple <call state(s), media-control action>. An array of these triples is passed to the lineSetMediaControl function to set the media-control actions triggered by the transition to the call state of the given call. When a transition to a listed call state is detected, the corresponding action on the media stream is invoked.


LINEMEDIACONTROLDIGIT

[New - Windows 95]

typedef struct linemediacontroldigit_tag {
  DWORD      dwDigit;
  DWORD      dwDigitModes;
  DWORD      dwMediaControl;
} LINEMEDIACONTROLDIGIT, FAR *LPLINEMEDIACONTROLDIGIT;

The LINEMEDIACONTROLDIGIT structure describes a media action to be executed when detecting a digit. It is used as as entry in an array.

dwDigit

The low-order byte of this DWORD specifies the digit in ASCII whose detection is to trigger a media action. Valid digits depend on the media mode.

dwDigitModes

Specifies the digit mode(s) that are to be monitored. This field uses the following LINEDIGITMODE_ constants:

LINEDIGITMODE_PULSE

Detect digits as audible clicks that are the result of rotary pulse sequences. Valid digits for pulse are '0' through '9'.

LINEDIGITMODE_DTMF

Detect digits as DTMF tones. Valid digits for DTMF are '0' through '9', 'A', 'B', 'C', 'D', '*', and '#'.

LINEDIGITMODE_DTMFEND

Detect and provide application notification of DTMF down edges. Valid digits for DTMF are '0' through '9', 'A', 'B', 'C', 'D', '*', and '#'.

dwMediaControl

Specifies the media-control action. This field uses the following LINEMEDIACONTROL_ constants:

LINEMEDIACONTROL_NONE

No change is to be made to the media stream.

LINEMEDIACONTROL_RESET

Reset the media stream. Equivalent to an end-of-input. All buffers are released.

LINEMEDIACONTROL_PAUSE

Temporarily pause the media stream.

LINEMEDIACONTROL_RESUME

Start or resume a paused media stream.

LINEMEDIACONTROL_RATEUP

The speed of the media stream is increased by some stream-defined quantity.

LINEMEDIACONTROL_RATEDOWN

The speed of the media stream is decreased by some stream-defined quantity.

LINEMEDIACONTROL_RATENORMAL

The speed of the media stream is returned to normal.

LINEMEDIACONTROL_VOLUMEUP

The amplitude of the media stream is increased by some stream-defined quantity.

LINEMEDIACONTROL_VOLUMEDOWN

The amplitude of the media stream is decreased by some stream-defined quantity.

LINEMEDIACONTROL_VOLUMENORMAL

The amplitude of the media stream is returned to normal.

No extensions.

The LINEMEDIACONTROLMEDIA structure defines a triple <digit, digit mode(s), media-control action>. An array of these triples is passed to the lineSetMediaControl function to set the media-control actions triggered by digits detected on a given call. When a listed digit is detected, then the corresponding action on the media stream is invoked.


LINEMEDIACONTROLMEDIA

[New - Windows 95]

typedef struct linemediacontrolmedia_tag {
  DWORD      dwMediaModes;
  DWORD      dwDuration;
  DWORD      dwMediaControl;
} LINEMEDIACONTROLMEDIA, FAR *LPLINEMEDIACONTROLMEDIA;

The LINEMEDIACONTROLMEDIA structure describes a media action to be executed when detecting a media-mode change. It is used as as entry in an array.

dwMediaModes

Specifies one or more media modes. This field uses the following LINEMEDIAMODE_ constants:

LINEMEDIAMODE_UNKNOWN

A media stream exists but its mode is not known. This would correspond to a call with an unclassified media type. In typical analog telephony environments, an inbound call's media mode may be unknown until after the call has been answered and the media stream filtered to make a determination.

LINEMEDIAMODE_INTERACTIVEVOICE

The presence of voice energy on the call and the call is treated as an interactive call with humans on both ends.

LINEMEDIAMODE_AUTOMATEDVOICE

The presence of voice energy on the call and the voice is locally handled by an automated application.

LINEMEDIAMODE_DATAMODEM

A data modem session on the call.

LINEMEDIAMODE_G3FAX

A group 3 fax is being sent or received over the call.

LINEMEDIAMODE_TDD

A TDD (Telephony Devices for the Deaf) session on the call.

LINEMEDIAMODE_G4FAX

A group 4 fax is being sent or received over the call.

LINEMEDIAMODE_DIGITALDATA

Digital data is being sent or received over the call.

LINEMEDIAMODE_TELETEX

A teletex session on the call. Teletex is one of the telematic services.

LINEMEDIAMODE_VIDEOTEX

A videotex session on the call. Videotex is one the telematic services.

LINEMEDIAMODE_TELEX

A telex session on the call. Telex is one the telematic services.

LINEMEDIAMODE_MIXED

A mixed session on the call. Mixed is one the ISDN telematic services.

LINEMEDIAMODE_ADSI

An ADSI (Analog Display Services Interface) session on the call.

dwDuration

Specifies the duration in milliseconds during which the media mode should be present before the application should be notified or media-control action should be taken.

dwMediaControl

Specifies the media-control action. This field uses the following LINEMEDIACONTROL_ constants:

LINEMEDIACONTROL_NONE

No change is to be made to the media stream.

LINEMEDIACONTROL_RESET

Reset the media stream. Equivalent to an end-of-input. All buffers are released.

LINEMEDIACONTROL_PAUSE

Temporarily pause the media stream.

LINEMEDIACONTROL_RESUME

Start or resume a paused media stream.

LINEMEDIACONTROL_RATEUP

The speed of the media stream is increased by some stream-defined quantity.

LINEMEDIACONTROL_RATEDOWN

The speed of the media stream is decreased by some stream-defined quantity.

LINEMEDIACONTROL_RATENORMAL

The speed of the media stream is returned to normal.

LINEMEDIACONTROL_VOLUMEUP

The amplitude of the media stream is increased by some stream-defined quantity.

LINEMEDIACONTROL_VOLUMEDOWN

The amplitude of the media stream is decreased by some stream-defined quantity.

LINEMEDIACONTROL_VOLUMENORMAL

The amplitude of the media stream is returned to normal.

No extensions.

The LINEMEDIACONTROLMEDIA structure defines a triple <media mode(s), duration, media-control action>. An array of these triples is passed to the lineSetMediaControl function to set the media-control actions triggered by media-mode changes for a given call. When a change to a listed media mode is detected, then the corresponding action on the media stream is invoked.


LINEMEDIACONTROLTONE

[New - Windows 95]

typedef struct linemediacontroltone_tag {
  DWORD  dwAppSpecific;
  DWORD  dwDuration;
  DWORD  dwFrequency1;
  DWORD  dwFrequency2;
  DWORD  dwFrequency3;
  DWORD  dwMediaControl;
} LINEMEDIACONTROLTONE, FAR *LPLINEMEDIACONTROLTONE;

The LINEMEDIACONTROLTONE structure describes a media action to be executed when a tone has been detected. It is used as an entry in an array.

dwAppSpecific

This field is used by the application for tagging the tone. When this tone is detected, the value of the dwAppSpecific field is passed back to the application.

dwDuration

Specifies the duration in milliseconds during which the tone should be present before a detection is made.

dwFrequency1
dwFrequency2
dwFrequency3

Specifies the frequency in Hertz of a component of the tone. If fewer than three frequencies are needed in the tone, a value of zero should be used for the unused frequencies. A tone with all three frequencies set to zero is interpreted as silence and can be use for silence detection.

dwMediaControl

Specifies the media-control action. This field uses the following LINEMEDIACONTROL_ constants:

LINEMEDIACONTROL_NONE

No change is to be made to the media stream.

LINEMEDIACONTROL_RESET

Reset the media stream. Equivalent to an end-of-input. All buffers are released.

LINEMEDIACONTROL_PAUSE

Temporarily pause the media stream.

LINEMEDIACONTROL_RESUME

Start or resume a paused media stream.

LINEMEDIACONTROL_RATEUP

The speed of the media stream is increased by some stream-defined quantity.

LINEMEDIACONTROL_RATEDOWN

The speed of the media stream is decreased by some stream-defined quantity.

LINEMEDIACONTROL_RATENORMAL

The speed of the media stream is returned to normal.

LINEMEDIACONTROL_VOLUMEUP

The amplitude of the media stream is increased by some stream-defined quantity.

LINEMEDIACONTROL_VOLUMEDOWN

The amplitude of the media stream is decreased by some stream-defined quantity.

LINEMEDIACONTROL_VOLUMENORMAL

The amplitude of the media stream is returned to normal.

No extensions.

The LINEMEDIACONTROLTONE structure defines a tuple <tone, media-control action>. An array of these tuples is passed to the lineSetMediaControl function to set media-control actions triggered by media-mode changes for a given call. When a change to a listed media mode is detected, the corresponding action on the media stream is invoked.

A tone with all frequencies set to zero corresponds to silence. An application can thus monitor the call's information stream for silence.


LINEMONITORTONE

[New - Windows 95]

typedef struct linemonitortone_tag {
  DWORD  dwAppSpecific;
  DWORD  dwDuration;
  DWORD  dwFrequency1;
  DWORD  dwFrequency2;
  DWORD  dwFrequency3;
} LINEMONITORTONE, FAR *LPLINEMONITORTONE;

The LINEMONITORTONE structure describes a tone to be monitored. This is used as an entry in an array.

dwAppSpecific

This field is used by the application for tagging the tone. When this tone is detected, the value of the dwAppSpecific field is passed back to the application.

dwDuration

Specifies the duration in milliseconds during which the tone should be present before a detection is made.

dwFrequency1
dwFrequency2
dwFrequency3

Specifies the frequency in Hertz of a component of the tone. If fewer than three frequencies are needed in the tone, a value of zero should be used for the unused frequencies. A tone with all three frequencies set to zero is interpreted as silence and can be use for silence detection.

No extensions.

The LINEMONITORTONE structure defines a tone for the purpose of detection. An array of tones is passed to the lineMonitorTones function which monitors these tones and send a LINE_MONITORTONE message to the application when a detection is made.

A tone with all frequencies set to zero corresponds to silence. An application can thus monitor the call's information stream for silence.


LINEPROVIDERENTRY

[New - Windows 95]

typedef struct lineproviderentry_tag {
  DWORD  dwPermanentProviderID;
  DWORD  dwProviderFilenameSize;
  DWORD  dwProviderFilenameOffset;
} LINEPROVIDERENTRY, FAR *LPLINEPROVIDERENTRY;

The LINEPROVIDERENTRY structure provides the information for a single service provider entry. An array of these structures is returned as part of the LINEPROVIDERLIST structure returned by the function lineGetProviderList.

dwPermanentProviderID

Specifies the permanent provider ID of the entry.

dwProviderFilenameSize
dwProviderFilenameOffset

The size in bytes and the offset in bytes from the beginning of the LINEPROVIDERLIST structure of a null-terminated ASCII string containing the filename (pathname) of the service provider DLL (.TSP) file.

Not extensible.


LINEPROVIDERLIST

[New - Windows 95]

typedef struct lineproviderlist_tag {
  DWORD  dwTotalSize;
  DWORD  dwNeededSize;
  DWORD  dwUsedSize;

  DWORD  dwNumProviders;
  DWORD  dwProviderListSize;
  DWORD  dwProviderListOffset;
} LINEPROVIDERLIST, FAR *LPLINEPROVIDERLIST;

The LINEPROVIDERLIST structure describes a list of service providers. A structure of this type is returned by the function lineGetProviderList.

dwTotalSize

The total size in bytes allocated to this data structure.

dwNeededSize

The size in bytes for this data structure that is needed to hold all the returned information.

dwUsedSize

The size in bytes of the portion of this data structure that contains useful information.

dwNumProviders

Specifies the number of LINEPROVIDERENTRY structures present in the array denominated by dwProviderListSize and dwProviderListOffset.

dwProviderListSize
dwProviderListOffset

The size in bytes and the offset in bytes from the beginning of this data structure of an array of LINEPROVIDERENTRY elements which provide the information on each service provider.

Not extensible.


LINEREQMAKECALL

[New - Windows 95]

typedef struct linereqmakecall_tag {
  char  szDestAddress[TAPIMAXDESTADDRESSSIZE];
  char  szAppName[TAPIMAXAPPNAMESIZE];
  char  szCalledParty[TAPIMAXCALLEDPARTYSIZE];
  char  szComment[TAPIMAXCOMMENTSIZE];
} LINEREQMAKECALL, FAR *LPLINEREQMAKECALL;

The LINEREQMAKECALL structure describes a tapiRequestMakeCall request.

szDestAddress[TAPIMAXADDRESSSIZE]

Specifies the NULL-terminated destination address of the make-call request. The address can use the canonical address format or the dialable address format. The maximum length of the address is TAPIMAXDESTADDRESSSIZE characters, which includes the NULL terminator. Longer strings are truncated.

szAppName[TAPIMAXAPPNAMESIZE]

Specifies the ASCII NULL-terminated user-friendly application name or file name of the application that originated the request. The maximum length of the address is TAPIMAXAPPNAMESIZE characters, which includes the NULL terminator.

szCalledParty[TAPIMAXCALLEDPARTYSIZE]

Specifies the ASCII NULL-terminated user-friendly called-party name. The maximum length of the called-party information is TAPIMAXCALLEDPARTYSIZE characters, which includes the NULL terminator.

szComment[TAPIMAXCOMMENTSIZE]

Specifies the ASCII NULL-terminated comment about the call request. The maximum length of the comment string is TAPIMAXCOMMENTSIZE characters, which includes the NULL terminator.

No extensions.

The szDestAddress field contains the address of the remote party; the other fields are useful for logging purposes. An application must use this structure to interpret the request buffer it received from lineGetRequest with the LINEREQUESTMODE_MAKECALL request mode.


LINETERMCAPS

[New - Windows 95]

typedef struct linetermcaps_tag {
  DWORD  dwTermDev;
  DWORD  dwTermModes;
  DWORD  dwTermSharing;
} LINETERMCAPS, FAR *LPLINETERMCAPS;

The LINETERMCAPS structure describes the capabilities of a line's terminal device.

dwTermDev

Specifies the device type of the terminal. This field uses the following LINETERMDEV_ constants:

LINETERMDEV_PHONE

The terminal is a phone set.

LINETERMDEV_HEADSET

The terminal is a headset

LINETERMDEV_SPEAKER

The terminal is an external speaker and microphone.

dwTermModes

Specifies the terminal mode(s) the terminal device is able to deal with. This field uses the following LINETERMMODE_ constants:

LINETERMMODE_BUTTONS

These are button-press events sent from the terminal to the line.

LINETERMMODE_LAMPS

These are lamp events sent from the line to the terminal.

LINETERMMODE_DISPLAY

This is display information sent from the line to the terminal.

LINETERMMODE_RINGER

This is ringer-control information sent from the switch to the terminal.

LINETERMMODE_HOOKSWITCH

These are hookswitch events sent from the terminal to the line.

LINETERMMODE_MEDIATOLINE

This is the unidirectional media stream from the terminal to the line associated with a call on the line. Use this value when the routing of both unidirectional channels of a call's media stream can be controlled independently.

LINETERMMODE_MEDIAFROMLINE

This is the unidirectional media stream from the line to the terminal associated with a call on the line. Use this value when the routing of both unidirectional channels of a call's media stream can be controlled independently.

LINETERMMODE_MEDIABIDIRECT

This is the bidirectional media stream associated with a call on the line and the terminal. Use this value when the routing of both unidirectional channels of a call's media stream cannot be controlled independently.

dwTermSharing

Specifies how the terminal device is shared between line devices. This field uses the following LINETERMSHARING_ constants:

LINETERMSHARING_PRIVATE

The terminal device is private to a single line device.

LINETERMSHARING_SHAREDEXCL

The terminal device can be used by multiple lines. The last line device to do a lineSetTerminal to the terminal for a given terminal mode will have exclusive connection to the terminal for that mode.

LINETERMSHARING_SHAREDCONF

The terminal device can be used by multiple lines. The lineSetTerminal requests of the various terminals end up being "merged" at the terminal.

No extensions.


LINETRANSLATECAPS

[New - Windows 95]

typedef struct linetranslatecaps_tag {
  DWORD  dwTotalSize;
  DWORD  dwNeededSize;
  DWORD  dwUsedSize;

  DWORD  dwNumLocations;
  DWORD  dwLocationListSize;
  DWORD  dwLocationListOffset;

  DWORD  dwCurrentLocationID;
  DWORD  dwNumCards;
  DWORD  dwCardListSize;
  DWORD  dwCardListOffset;

  DWORD  dwCurrentPreferredCardID;
} LINETRANSLATECAPS, FAR *LPLINETRANSLATECAPS;

The LINETRANSLATECAPS structure describes the address translation capabilities.

dwTotalSize

The total size in bytes allocated to this data structure.

dwNeededSize

The size in bytes for this data structure that is needed to hold all the returned information.

dwUsedSize

The size in bytes of the portion of this data structure that contains useful information.

dwNumLocations

The number of entries in the LocationList. It includes all locations defined, including 0 (default).

dwLocationListSize
dwLocationListOffset

List of locations known to address translation. The list consists of a sequence of LINELOCATIONENTRY structures. The dwLocationListOffset field points to the first byte of the first LINELOCATIONENTRY structure, and the dwLocationListSize field indicates the total number of bytes in the entire list.

dwCurrentLocationID

This is the dwPermanentLocationID from the LINELOCATIONENTRY for the Current Location.

dwNumCards

The number of entries in the CardList.

dwCardListSize
dwCardListOffset

List of calling cards known to address translation. It includes only non-hidden card entries and always includes card 0 (direct dial). The list consists of a sequence of LINECARDENTRY structures. The dwCardListOffset field points to the first byte of the first LINECARDENTRY structure, and the dwCardListSize field indicates the total number of bytes in the entire list.

dwCurrentPreferredCardID

This is the dwPreferredCardID from the LINELOCATIONENTRY for the Current Location.

No extensions.


LINETRANSLATEOUTPUT

[New - Windows 95]

typedef struct linetranslateoutput_tag {
  DWORD  dwTotalSize;
  DWORD  dwNeededSize;
  DWORD  dwUsedSize;

  DWORD  dwDialableStringSize;
  DWORD  dwDialableStringOffset;
  DWORD  dwDisplayableStringSize;
  DWORD  dwDisplayableStringOffset;

  DWORD  dwCurrentCountry;
  DWORD  dwDestCountry;
  DWORD  dwTranslateResults;
} LINETRANSLATEOUTPUT, FAR *LPLINETRANSLATEOUTPUT;

The LINETRANSLATEOUTPUT structure describes the result of an address translation.

dwTotalSize

The total size in bytes allocated to this data structure.

dwNeededSize

The size in bytes for this data structure that is needed to hold all the returned information.

dwUsedSize

The size in bytes of the portion of this data structure that contains useful information.

dwDialableStringSize
dwDialableStringOffset

Contains the translated output which can be passed to lineMakeCall, lineDial, or other function requiring a dialable string. The output is always a null-terminated ASCII string (null is accounted for in Size). Ancillary fields such as name and subaddress are included in this output string if they were in the input string. This string may contain private information such as calling card numbers. It should not be displayed to the user, to prevent inadvertent visibility to unauthorized persons.

dwDisplayableStringSize
dwDisplayableStringOffset

Contains the translated output which can be displayed to the user for confirmation. It will be identical to DialableString, except that calling card digits will be replaced with the "friendly name" of the card enclosed within bracket characters (for example, "[AT&T Card]"), and ancillary fields such as name and subaddress will be removed. It should normally be safe to display this string in call-status dialog boxes without exposing private information to unauthorized persons. This information is also appropriate to include in call logs.

dwCurrentCountry

Contains the country code configured in CurrentLocation. This value may be used to control the display by the application of certain user interface elements, local call progress tone detection, and for other purposes.

dwDestCountry

Contains the destination country code of the translated address. This value may be passed to the dwCountryCode parameter of lineMakeCall and other dialing functions (so that the call progress tones of the destination country such as a busy signal will be properly detected). This field is set to 0 if the destination address passed to lineTranslateAddress is not in canonical format.

dwTranslateResults

Indicates the information derived from the translation process, which may assist the application in presenting user-interface element. This field uses the following LINETRANSLATERESULT_ constants:

LINETRANSLATERESULT_CANONICAL

Indicates that the input string was in valid canonical format.

LINETRANSLATERESULT_INTERNATIONAL

If this bit is on, the call is being treated as an international call (country code specified in the destination address is the different from the country code specified for the CurrentLocation).

LINETRANSLATERESULT_LONGDISTANCE

If this bit is on, the call is being treated as a long distance call (country code specified in the destination address is the same but area code is different from those specified for the CurrentLocation).

LINETRANSLATERESULT_LOCAL

If this bit is on, the call is being treated as a local call (country code and area code specified in the destination address are the same as those specified for the CurrentLocation).

LINETRANSLATERESULT_INTOLLLIST

If this bit is on, the local call is being dialed as long distance because the country has toll calling and the prefix appears in the TollPrefixList of the CurrentLocation.

LINETRANSLATERESULT_NOTINTOLLLIST

If this bit is on, the country supports toll calling but the prefix does not appear in the TollPrefixList, so the call is dialed as a local call.  Note that if both INTOLLIST and NOTINTOLLIST are off, the current country does not support toll prefixes, and user-interface elements related to toll prefixes should not be presented to the user; if either such bit is on, the country does support toll lists, and the related user-interface elements should be enabled.

LINETRANSLATERESULT_DIALBILLING

Indicates that the returned address contains a "$".

LINETRANSLATERESULT_DIALQUIET

Indicates that the returned address contain a "@".

LINETRANSLATERESULT_DIALDIALTONE

Indicates that the returned address contains a "W".

LINETRANSLATERESULT_DIALPROMPT

Indicates that the returned address contains a "?".

No extensions.


Line Device Constants

About Line Device Constants

This chapter describes the constants used by the Telephony API. They are listed in alphabetical order.


Reference

Following are the Telephony API constants.


LINEADDRCAPFLAGS_ Constants

[New - Windows 95]

The LINEADDRCAPFLAGS__bit-flag constants are used in the dwAddrCapFlags field of the LINEADDRESSCAPS data structure to describe various Boolean address capabilities.

LINEADDRCAPFLAGS_FWDNUMRINGS

Specifies whether the number of rings for a no answer can be specified when forwarding calls on no answer. If TRUE, the valid range is provided in LINEADDRESSCAPS.

LINEADDRCAPFLAGS_PICKUPGROUPID

Specifies whether a group ID is required for call pickup.

LINEADDRCAPFLAGS_SECURE

Specifies whether calls on this address can be made secure at call-setup time.

LINEADDRCAPFLAGS_BLOCKIDDEFAULT

Specifies whether the network by default sends or blocks caller ID information when making a call on this address. If TRUE, ID information is blocked by default; if FALSE, ID information is transmitted by default.

LINEADDRCAPFLAGS_BLOCKIDOVERRIDE

Specifies whether the default setting for sending or blocking of caller ID information can be overridden per call. If TRUE, override is possible; if FALSE, override is not possible.

LINEADDRCAPFLAGS_DIALED

Specifies whether a destination address can be dialed on this address for making a call. TRUE if a destination address must be dialed; FALSE if the destination address is fixed (as with a "hot phone").

LINEADDRCAPFLAGS_ORIGOFFHOOK

Specifies whether the originating party's phone can automatically be taken offhook when making calls.

LINEADDRCAPFLAGS_DESTOFFHOOK

Specifies whether the called party's phone can automatically be forced offhook when making calls.

LINEADDRCAPFLAGS_FWDCONSULT

Specifies whether call forwarding involves the establishment of a consultation call.

LINEADDRCAPFLAGS_SETUPCONFNULL

Specifies whether setting up a conference call starts out with an initial call (FALSE) or with no initial call (TRUE).

LINEADDRCAPFLAGS_AUTORECONNECT

Specifies whether dropping a consultation call automatically reconnects to the call on consultation hold. TRUE if reconnect happens automatically; otherwise, FALSE.

LINEADDRCAPFLAGS_COMPLETIONID

Specifies whether the completion IDs returned by lineCompleteCall are useful and unique. TRUE if useful; otherwise, FALSE.

LINEADDRCAPFLAGS_TRANSFERHELD

Specifies whether a hard-held call can be transferred. Often, only calls on consultation hold can be transferred.

LINEADDRCAPFLAGS_TRANSFERMAKE

Specifies whether an entirely new call can be established for use as a consultation call on transfer.

LINEADDRCAPFLAGS_CONFERENCEHELD

Specifies whether a hard-held call can be conferenced to. Often, only calls on consultation hold can be added to as a conference call.

LINEADDRCAPFLAGS_CONFERENCEMAKE

Specifies whether an entirely new call can be established for use as a consultation call (to add) on conference.

LINEADDRCAPFLAGS_PARTIALDIAL

Specifies whether partial dialing is available.

LINEADDRCAPFLAGS_FWDSTATUSVALID

Specifies whether the forwarding status in the LINEADDRESSSTATUS structure for this address is valid or is at most a "best estimate," given absence of accurate confirmation by the switch or network.

LINEADDRCAPFLAGS_FWDINTEXTADDR

Specifies whether internal and external calls can be forwarded to different forwarding addresses. This flag is meaningful only if forwarding of internal and external calls can be controlled separately. This flag is TRUE if internal and external calls can be forwarded to different destination addresses; otherwise, it is FALSE.

LINEADDRCAPFLAGS_FWDBUSYNAADDR

Specifies whether call forwarding for busy and for no answer can use different forwarding addresses. This flag is meaningful only if forwarding for busy and for no answer can be controlled separately. This flag is TRUE if forwarding for busy and for no answer can use different destination addresses; otherwise, it is FALSE.

LINEADDRCAPFLAGS_ACCEPTTOALERT

TRUE if an offering call must be accepted using lineAccept in order to start alerting the users at both ends of the call; otherwise, FALSE. This is typically only used with ISDN.

LINEADDRCAPFLAGS_CONFDROP

TRUE if lineDrop on a conference call parent also has the side effect of dropping (that is, disconnecting) the other parties involved in the conference call; FALSE if dropping a conference call still allows the other parties to talk among themselves.

LINEADDRCAPFLAGS_PICKUPCALLWAIT

TRUE if linePickup can be used to pickup a call detected by the user as a call waiting call; otherwise, FALSE.

No extensibility. All 32 bits are reserved.


LINEADDRESSMODE_ Constants

[New - Windows 95]

The LINEADDRESSMODE_ bit-flag constants describe various ways of identifying an address on a line device.

LINEADDRESSMODE_ADDRESSID

The address is specified with a small integer in the range 0 to dwNumAddresses minus one, where dwNumAddresses is the value in the line's device capabilities.

LINEADDRESSMODE_DIALABLEADDR

The address is specified through its phone number.

The high-order 16 bits can be assigned for device-specific extensions. The low-order 16 bits are reserved.

This constant is used to select an address on a line on which to originate a call. The usual model would select the address by means of its address ID. Address IDs are the mechanism used to identify addresses throughout TAPI. However, in some environments, when making a call, it is often more practical to identify a call's originating address by phone number rather than by address ID. One example is in the possible modeling of large numbers of stations (third party) on the switch by means of one line device with many addresses. The line represents the set of all stations, and each station is mapped to an address with its own primary phone number and address ID.


LINEADDRESSSHARING_ Constants

[New - Windows 95]

The LINEADDRESSSHARING_ bit-flag constants describe various ways an address can be shared between lines.

LINEADDRESSSHARING_PRIVATE

The address is private to the user's line; it is not assigned to any other station.

LINEADDRESSSHARING_BRIDGEDEXCL

The address is bridged to one or more other stations. The first line to activate a call on the line will have exclusive access to the address and calls that may exist on it. Other lines will not be able to use the bridged address while it is in use.

LINEADDRESSSHARING_BRIDGEDNEW

The address is bridged with one or more other stations. The first line to activate a call on the line will have exclusive access to only the corresponding call. Other applications that use the address will result in new and separate call appearances.

LINEADDRESSSHARING_BRIDGEDSHARED

The address is bridged with one or more other lines. All bridged parties can share in calls on the address, which then functions as a conference.

LINEADDRESSSHARING_MONITORED

This is an address whose idle/busy status is made available to this line.

No extensibility. All 32 bits are reserved.

The way in which an address is shared across lines can affect the behavior of that address. LINE_CALLSTATE and LINE_ADDRESSSTATE messages are sent to the application in response to activities by the bridging stations. It is through these messages that an application can track the status of the address.


LINEADDRESSSTATE_ Constants

[New - Windows 95]

The LINEADDRESSSTATE_ bit-flag constants describe various address status items.

LINEADDRESSSTATE_OTHER

Address-status items other than those listed below have changed. The application should check the current address status to determine which items have changed.

LINEADDRESSSTATE_DEVSPECIFIC

The device-specific item of the address status has changed.

LINEADDRESSSTATE_INUSEZERO

The address has changed to idle (it is not in use by any stations).

LINEADDRESSSTATE_INUSEONE

The address has changed from idle or in use by many bridged stations to being in use by just one station.

LINEADDRESSSTATE_INUSEMANY

The monitored or bridged address has changed from being in use by one station to being in use by more than one station.

LINEADDRESSSTATE_NUMCALLS

The number of calls on the address has changed. This is the result of events such as a new inbound call, an outbound call on the address, or a call changing its hold status. This flag covers changes in any of the fields dwNumActiveCalls, dwNumOnHoldCalls and dwNumOnHoldPendingCalls in the LINEADDRESSSTATUS structure. The application should check all three of these fields when it receives a LINE_ADDRESSSTATE (numCalls) message.

LINEADDRESSSTATE_FORWARD

The forwarding status of the address has changed, including possibly the number of rings for determining a no answer condition. The application should check the address status to determine details about the address's current forwarding status.

LINEADDRESSSTATE_TERMINALS

The terminal settings for the address have changed.

LINEADDRESSSTATE_CAPSCHANGE

Indicates that, due to configuration changes made by the user or other circumstances, one or more of the fields in the LINEADDRESSCAPS structure for the address have changed. The application should use lineGetAddressCaps to read the updated structure. If a service provider sends a LINE_ADDRESSSTATE message containing this value to TAPI, TAPI will pass it along to applications which have negotiated this or a subsequent API version; applications negotiating a previous API version will receive LINE_LINEDEVSTATE messages specifying LINEDEVSTATE_REINIT, requiring them to shutdown and reinitialize their connection to TAPI in order to obtain the updated information.

No extensibility. All 32 bits are reserved.

An application is notified about changes to these status items in the LINE_ADDRESSSTATE message. The address's device capabilities indicate which address state changes can possibly be reported for this address.


LINEADDRFEATURE_ Constants

[New - Windows 95]

The LINEADDRFEATURE_ constants list the operations that can be invoked on an address.

LINEADDRFEATURE_FORWARD

The address can be forwarded.

LINEADDRFEATURE_MAKECALL

An outbound call can be placed on the address.

LINEADDRFEATURE_PICKUP

A call can be picked-up at the address.

LINEADDRFEATURE_SETMEDIACONTROL

Media control can be set on this address.

LINEADDRFEATURE_SETTERMINAL

The terminal modes for this address can be set.

LINEADDRFEATURE_SETUPCONF

A conference call with a NULL initial call can be set up at this address.

LINEADDRFEATURE_UNCOMPLETECALL

Call completion requests can be canceled at this address.

LINEADDRFEATURE_UNPARK

Calls can be unparked using this address.

No extensibility. All 32 bits are reserved.

This constant is used both in LINEADDRESSCAPS (returned by lineGetAddressCaps) and in LINEADDRESSSTATUS (returned by lineGetAddressStatus). LINEADDRESSCAPS reports the availability of the address features by the service provider (mainly the switch) for a given address. An application would make this determination when it initializes. The LINEADDRESSSTATUS structure reports, for a given address, which address features can actually be invoked while the address is in the current state. An application would make this determination dynamically after address-state changes, typically caused by call-related activities on the address.


LINEANSWERMODE_ Constants

[New - Windows 95]

The LINEANSWERMODE_ bit-flag constants describe how an existing active call on a line device is affected by answering another offering call on the same line.

LINEANSWERMODE_NONE

Answering another call on the same line has no effect on the existing active call(s) on the line.

LINEANSWERMODE_DROP

The currently active call will automatically be dropped.

LINEANSWERMODE_HOLD

The currently active call will automatically be placed on hold.

No extensibility. All 32 bits are reserved.

If a call comes in (is offered) at the time another call is already active, the new call is connected to by invoking lineAnswer. The effect this has on the existing active call depends on the line's device capabilities. The first call may be unaffected, it may automatically be dropped, or it may automatically be placed on hold.


LINEBEARERMODE_ Constants

[New - Windows 95]

The LINEBEARERMODE_ bit-flag constants describe different bearer modes of a call. When an application makes a call, it can request a specific bearer mode. These modes are used to select a certain quality of service for the requested connection from the underlying telephone network. Bearer modes available on a given line are a device capability of the line.

LINEBEARERMODE_VOICE

This is a regular 3.1kHz analog voice grade bearer service. Bit integrity is not assured. Voice can support fax and modem media modes.

LINEBEARERMODE_SPEECH

This corresponds to G.711 speech transmission on the call. The network may use processing techniques such as analog transmission, echo cancellation, and compression/decompression. Bit integrity is not assured. Speech is not intended to support fax and modem media modes.

LINEBEARERMODE_MULTIUSE

The multi-use mode defined by ISDN.

LINEBEARERMODE_DATA

The unrestricted data transfer on the call. The data rate is specified separately.

LINEBEARERMODE_ALTSPEECHDATA

The alternate transfer of speech or unrestricted data on the same call (ISDN).

LINEBEARERMODE_NONCALLSIGNALING

This corresponds to a non-call-associated signaling connection from the application to the service provider or switch (treated as a "media stream" by TAPI).

LINEBEARERMODE_PASSTHROUGH

When a call is active in LINEBEARERMODE_PASSTHROUGH, the service provider gives direct access to the attached hardware for control by the application. This mode is used primarily by applications desiring temporary direct control over asynchronous modems, accessed via the Win32 comm functions, for the purpose of configuring or using special features not otherwise supported by the service provider.

The high-order 16 bits can be assigned for device-specific extensions. The low-order 16 bits are reserved.

Note that bearer mode and media mode are different notions. The bearer mode of a call is an indication of the quality of the telephone connection as provided primarily by the network. The media mode of a call is an indication of the type of information stream that is exchanged over that call. Group 3 fax or data modem are media modes that use a call with a 3.1kHz voice bearer mode.


LINEBUSYMODE_ Constants

[New - Windows 95]

The LINEBUSYMODE_ bit-flag constants describe different busy signals that the switch or network may generate. These busy signals typically indicate that a different resource that is required to make a call is currently in use.

LINEBUSYMODE_STATION

The busy signal indicates that the called party's station is busy. This is usually signaled with a "normal" busy tone.

LINEBUSYMODE_TRUNK

The busy signal indicates that a trunk or circuit is busy. This is usually signaled with a "fast" busy tone.

LINEBUSYMODE_UNKNOWN

The busy signal's specific mode is currently unknown but may become known later.

LINEBUSYMODE_UNAVAIL

The busy signal's specific mode is unavailable and will not become known.

The high-order 16 bits can be assigned for device-specific extensions. The low-order 16 bits are reserved.

Note that busy signals may be sent as inband tones or out-of-band messages. TAPI makes no assumption about the specific signaling mechanism.


LINECALLCOMPLCOND_ Constants

[New - Windows 95]

The LINECALLCOMPLCOND_ bit-flag constants describe the conditions under which a call can be completed.

LINECALLCOMPLCOND_BUSY

Completion of the call under busy conditions.

LINECALLCOMPLCOND_NOANSWER

Completion of the call under ringback no answer conditions.

No extensibility. All 32 bits are reserved.


LINECALLCOMPLMODE_ Constants

[New - Windows 95]

The LINECALLCOMPLMODE_ bit-flag constants describe different ways in which a call can be completed.

LINECALLCOMPLMODE_CAMPON

Queues the call until the call can be completed.

LINECALLCOMPLMODE_CALLBACK

Requests the called station to return the call when it returns to idle.

LINECALLCOMPLMODE_INTRUDE

Adds the application to the existing call at the called station (barge in).

LINECALLCOMPLMODE_MESSAGE

Leave a short predefined message for the called station (Leave Word Calling). The message to be sent is specified separately.

No extensibility. All 32 bits are reserved.


LINECALLFEATURE_ Constants

[New - Windows 95]

The LINECALLFEATURE_ constants list the operations that can be invoked on a call using this API.

Each of the LINECALLFEATURE_ values correspond to the TAPI operations with the same name. The list is not repeated here.

No extensibility. All 32 bits are reserved.

This constant is used both in LINEADDRESSCAPS (returned by lineGetAddressCaps) and in LINECALLSTATUS (returned by lineGetCallStatus). LINEADDRESSCAPS reports the availability of the call features on the specified address. An application would use this information when it initializes to determine what it may be able to do later when calls exist. For the specified call, LINECALLSTATUS reports which call features can be invoked while the call is in the current call state. The latter takes call privileges into account. An application would make this determination dynamically, after call state changes.

The LINECALLFEATURE_RELEASEUSERUSER value is new. No backward compatibility considerations. A service provider may elect to return this value in relevant fields (in LINEADDRESSCAPS and LINECALLSTATUS) even when older API versions have been negotiated on the line device.


LINECALLINFOSTATE_ Constants

[New - Windows 95]

The LINECALLINFOSTATE_ bit-flag constants describe various call information items about which an application may be notified in the LINE_CALLINFO message.

LINECALLINFOSTATE_OTHER

Call information items other than those listed below have changed. The application should check the current call information to determine which items have changed.

LINECALLINFOSTATE_DEVSPECIFIC

The device-specific field of the call-information record.

LINECALLINFOSTATE_BEARERMODE

The bearer mode field of the call-information record.

LINECALLINFOSTATE_RATE

The rate field of the call-information record.

LINECALLINFOSTATE_MEDIAMODE

The media-mode field of the call-information record.

LINECALLINFOSTATE_APPSPECIFIC

The application-specific field of the call-information record.

LINECALLINFOSTATE_CALLID

The call ID field of the call-information record.

LINECALLINFOSTATE_RELATEDCALLID

The related call ID field of the call-information record.

LINECALLINFOSTATE_ORIGIN

The origin field of the call-information record.

LINECALLINFOSTATE_REASON

The reason field of the call-information record.

LINECALLINFOSTATE_COMPLETIONID

The completion ID field of the call-information record.

LINECALLINFOSTATE_NUMOWNERINCR

The number of owner field in the call-information record was increased.

LINECALLINFOSTATE_NUMOWNERDECR

The number of owner field in the call-information record was decreased.

LINECALLINFOSTATE_NUMMONITORS

The number of monitors field in the call-information record has changed.

LINECALLINFOSTATE_TRUNK

The trunk field of the call-information record.

LINECALLINFOSTATE_CALLERID

One of the callerID-related fields of the call-information record.

LINECALLINFOSTATE_CALLEDID

One of the calledID-related fields of the call-information record.

LINECALLINFOSTATE_CONNECTEDID

One of the cconnectedID-related fields of the call-information record.

LINECALLINFOSTATE_REDIRECTIONID

One of the redirectionID-related fields of the call-information record.

LINECALLINFOSTATE_REDIRECTINGID

One of the redirectingID-related fields of the call-information record.

LINECALLINFOSTATE_DISPLAY

The display field of the call-information record.

LINECALLINFOSTATE_USERUSERINFO

The user-to-user information of the call-information record.

LINECALLINFOSTATE_HIGHLEVELCOMP

The high level compatibility field of the call-information record.

LINECALLINFOSTATE_LOWLEVELCOMP

The low level compatibility field of the call-information record.

LINECALLINFOSTATE_CHARGINGINFO

The charging information of the call-information record.

LINECALLINFOSTATE_TERMINAL

The terminal mode information of the call-information record.

LINECALLINFOSTATE_DIALPARAMS

The dial parameters of the call-information record.

LINECALLINFOSTATE_MONITORMODES

One or more of the digit, tone, or media monitoring fields in the call-information record.

No extensibility. All 32 bits are reserved.

When changes occur in this data structure, a LINE_CALLINFO message is sent to the application. The parameters to this message are a handle to the call and an indication of the information item that has changed. The LINEADDRESSCAPS data structure also indicates which of these call information elements are valid for every call on the address.


LINECALLORIGIN_ Constants

[New - Windows 95]

The LINECALLORIGIN_ constants describe the origin of a call.

LINECALLORIGIN_OUTBOUND

The call originated from this station as an outbound call.

LINECALLORIGIN_INTERNAL

The call originated as an inbound call at a station internal to the same switching environment.

LINECALLORIGIN_EXTERNAL

The call originated as an inbound call on an external line.

LINECALLORIGIN_UNKNOWN

The call origin is currently unknown but may become known later.

LINECALLORIGIN_UNAVAIL

The call origin is not available and will never become known for this call.

LINECALLORIGIN_CONFERENCE

The call handle is for a conference call, that is, it is the application's connection to the conference bridge in the switch.

LINECALLORIGIN_INBOUND

The call originated as an inbound call, but the service provider is unable to determine whether it came from another station on the same switch or from an external line.

No extensibility. All 32 bits are reserved.

The origin of a call is stored in the dwOrigin field of the call's LINECALLINFO structure.

For backward compatibility, it is the responsibility of the service provider to examine the negotiated API version on the line, and to not use the LINECALLORIGIN_INBOUND value if it is not supported on the negotiated version (LINECALLORIGIN_UNAVAIL may be substituted).


LINECALLPARAMFLAGS_ Constants

[New - Windows 95]

The LINECALLPARAMFLAGS_ constants describe various status flags about a call.

LINECALLPARAMFLAGS_SECURE

The call should be set up as secure.

LINECALLPARAMFLAGS_IDLE

The call should be originated on an idle call appearance and not join a call in progress. When using the lineMakeCall function, if the LINECALLPARAMFLAGS_IDLE value is not set and there is an existing call on the line, the function breaks into the existing call if necessary to make the new call. If there is no existing call, the function makes the new call as specified.

LINECALLPARAMFLAGS_BLOCKID

The originator identity should be concealed (block caller ID).

LINECALLPARAMFLAGS_ORIGOFFHOOK

The originator's phone should be automatically taken offhook.

LINECALLPARAMFLAGS_DESTOFFHOOK

The called party's phone should be automatically be taken offhook.

No extensibility. All 32 bits are reserved.


LINECALLPARTYID_ Constants

[New - Windows 95]

The LINECALLPARTYID_ bit-flag constants describe the nature of the information available about the parties involved in a call.

LINECALLPARTYID_BLOCKED

Party ID information is not available because it has been blocked by the remote party.

LINECALLPARTYID_OUTOFAREA

Caller ID information for the call is not available since it is not propagated all the way by the network.

LINECALLPARTYID_NAME

Party ID information consists of the party's name (as, for example, from a directory kept inside the switch).

LINECALLPARTYID_ADDRESS

Party ID information consists of the party's address in either canonical address format or dialable address format.

LINECALLPARTYID_PARTIAL

Party ID information is valid but it is limited to partial information only.

LINECALLPARTYID_UNKNOWN

Party ID information is currently unknown but may become known later.

LINECALLPARTYID_UNAVAIL

Party ID information is not available and will not become available later. Information may be unavailable for unspecified reasons. For example, the information was not delivered by the network, it was ignored by the service provider, and so forth.

No extensibility. All 32 bits are reserved.

For each of the possible parties involved in a call, the LINECALLPARTYID_ constants describes how the party ID information is formatted. This information is supplied in the LINECALLINFO data structure.


LINECALLPRIVILEGE_ Constants

[New - Windows 95]

The LINECALLPRIVILEGE_ bit-flag constants describe the kinds of access rights or privileges an application with a call handle may have to the corresponding call.

LINECALLPRIVILEGE_NONE

The application has no privileges to the call. The application's handle is void and should not be used.

LINECALLPRIVILEGE_MONITOR

The application has monitor privileges to the call. These privileges allow the application to monitor state changes and query information and status about the call.

LINECALLPRIVILEGE_OWNER

The application has owner privileges to the call. These privileges allow the application to manipulate the call in ways that affect the state of the call.

No extensibility. All 32 bits are reserved.

When a call handle is first provided to an application or whenever call privileges of that application are modified, the LINE_CALLSTATE message is sent to the application. When an application hands off a call, and if the receiving application does not already have a handle with owner privileges, then this message informs the application about its new privileges to the call.


LINECALLREASON_ Constants

[New - Windows 95]

The LINECALLREASON_ bit-flag constants describe the reason for a call.

LINECALLREASON_DIRECT

This is a direct inbound or outbound call.

LINECALLREASON_FWDBUSY

This call was forwarded from another extension that was busy at the time of the call.

LINECALLREASON_FWDNOANSWER

The call was forwarded from another extension that didn't answer the call after some number of rings.

LINECALLREASON_FWDUNCOND

The call was forwarded unconditionally from another number.

LINECALLREASON_PICKUP

The call was picked up from another extension.

LINECALLREASON_UNPARK

The call was retrieved as a parked call.

LINECALLREASON_REDIRECT

The call was redirected to this station.

LINECALLREASON_CALLCOMPLETION

The call was the result of a call completion request.

LINECALLREASON_TRANSFER

The call has been transferred from another number.

LINECALLREASON_REMINDER

The call is a reminder (or "recall") that the user has a call parked or on hold for (potentially) a long time.

LINECALLREASON_UNKNOWN

The reason for the call is currently unknown but may become known later.

LINECALLREASON_UNAVAIL

The reason for the call is unavailable and will not become known later.

LINECALLREASON_INTRUDE

The call intruded onto the line, either by a call completion action invoked by another station or by operator action. Depending on switch implementation, the call may appear either in the connected state, or conferenced with an existing active call on the line.

LINECALLREASON_PARKED

The call was parked on the address. Usually, it appears initially in the onhold state.

No extensibility. All 32 bits are reserved.

The LINECALLREASON_ constants are used in the dwReason field of the LINECALLINFO data structure.

For backward compatibility, it is the responsibility of the service provider to examine the negotiated API version on the line, and to not use these LINECALLREASON_ values if not supported on the negotiated version (LINECALLREASON_UNAVAIL may be substituted).


LINECALLSELECT_ Constants

[New - Windows 95]

The LINECALLSELECT_ bit-flag constants describe which calls are to be selected.

LINECALLSELECT_LINE

Selects calls on the specified line device.

LINECALLSELECT_ADDRESS

Selects call on the specified address.

LINECALLSELECT_CALL

Selects related calls to the specified call. For example, the parties in a conference call.

No extensibility. All 32 bits are reserved.

This constant is used in lineGetNewCalls and to specify a selection (scope) of the calls that are requested.


LINECALLSTATE_ Constants

[New - Windows 95]

The LINECALLSTATE_ bit-flag constants describe the call states a call can be in.

LINECALLSTATE_IDLE

The call is idle—no call exists.

LINECALLSTATE_OFFERING

The call is being offered to the station, signaling the arrival of a new call. In some environments, a call in the offering state does not automatically alert the user since alerting is done by the switch instructing the line to ring. It does not affect any call states.

LINECALLSTATE_ACCEPTED

The call was offering and has been accepted. This indicates to other (monitoring) applications that the current owner application has claimed responsibility for answering the call. In ISDN, this also initiates alerting to both parties.

LINECALLSTATE_DIALTONE

The call is receiving a dial tone from the switch, which means that the switch is ready to receive a dialed number.

LINECALLSTATE_DIALING

Destination address information (a phone number) is being sent to the switch over the call. Note that lineGenerateDigits does not place the line into the dialing state.

LINECALLSTATE_RINGBACK

The call is receiving ringback from the called address. Ringback indicates that the other station has been reached and is being alerted.

LINECALLSTATE_BUSY

The call is receiving a busy tone. A busy tone indicates that the call cannot be completed—either a circuit (trunk) or the remote party's station are in use.

LINECALLSTATE_SPECIALINFO

Special information is sent by the network. Special information is typically sent when the destination cannot be reached.

LINECALLSTATE_CONNECTED

The call has been established and the connection is made. Information is able to flow over the call between the originating address and the destination address.

LINECALLSTATE_PROCEEDING

Dialing has completed and the call is proceeding through the switch or telephone network.

LINECALLSTATE_ONHOLD

The call is on hold by the switch.

LINECALLSTATE_CONFERENCED

The call is currently a member of a multi-party conference call.

LINECALLSTATE_ONHOLDPENDCONF

The call is currently on hold while it is being added to a conference.

LINECALLSTATE_ONHOLDPENDTRANSFER

The call is currently on hold awaiting transfer to another number.

LINECALLSTATE_DISCONNECTED

The remote party has disconnected from the call.

LINECALLSTATE_UNKNOWN

The state of the call is not known. This may be due to limitations of the call-progress detection implementation.

The high-order 8 bits can define a device-specific substate of any of the predefined states, provided that one of the LINECALLSTATE_ bits defined above is also set. The low-order 24 bits are reserved for predefined states.

The LINECALLSTATE_ constants are used as parameters by the LINE_CALLSTATE message sent to the application. The message carries the new call state that the call transitioned to. These constants are also used as fields in the LINECALLSTATUS structure returned by the lineGetCallStatus function.


LINECARDOPTION_ Constants

[New - Windows 95]

The LINECARDOPTION_ constants define values used in the dwOptions field of the LINECARDENTRY structure returned as part of the LINETRANSLATECAPS structure returned by lineGetTranslateCaps. The LINECARDOPTION_ constant has the following values:

LINECARDOPTION_PREDEFINED

This calling card is one of the predefined calling card definitions included by Microsoft with Windows Telephony. It cannot be removed entirely using Dial Helper; if the user attempts to remove it, it will become HIDDEN. It thus continues to be accessible for copying of dialing rules.

LINECARDOPTION_HIDDEN

This calling card has been hidden by the user. It is not shown by Dial Helper in the main listing of available calling cards, but will be shown in the list of cards from which dialing rules can be copied.

Not extensible. All 32 bits are reserved.


LINECONNECTEDMODE_ Constants

[New - Windows 95]

The LINECONNECTEDMODE_ bit-flag constants describe different substates of a connected call. A mode is available as call status to the application after the call state transitions to connected, and within the LINE_CALLSTATE message indicating the call is in LINECALLSTATE_CONNECTED. These values are used when the call is on an address that is shared (bridged) with other stations (see the LINEADDRESSSHARING_ constants), primarily electronic key systems. The LINECONNECTEDMODE_ constants have the following values:

LINECONNECTEDMODE_ACTIVE

Indicates that the call is connected at the current station (the current station is a participant in the call). If the call state mode is 0 (zero), the application should assume that the value is "active" (which would be the situation on a non-bridged address). The mode may switch between ACTIVE and INACTIVE during a call if the user joins and leaves the call through manual action.  In such a bridged situation, a lineDrop or lineHold operation may possibly not actually drop the call or place it on hold, since the status of other stations on the call may govern (e.g., attempting to "hold" a call when other stations are particating won't be possible); instead, the call may simply be changed to the INACTIVE mode if it remains CONNECTED at other stations.

LINECONNECTEDMODE_INACTIVE

Indicates that the call is active at one or more other stations, but the current station is not a participant in the call.  If the call state mode is ZERO, the application should assume that the value is "active" (which would be the situation on a non-bridged address). A call in the INACTIVE state may be joined using the lineAnswer. Many operations which are valid in calls in the CONNECTED state may be impossible in the INACTIVE mode, such as monitoring for tones and digits, since the station is not actually participating in the call; monitoring is usually suspended (although not cancelled) while the call is in the INACTIVE mode.

Not extensible. All 32 bits are reserved.

For backward compatibility, it is the responsibility of the service provider to examine the negotiated API version on the line, and to not use these LINECONNECTEDMODE_ values if not supported on the negotiated version. It should be noted that applications which are not cognizant of LINECONNECTEDMODE_ will most likely assume that a call that is in LINECALLSTATE_CONNECTED is in LINECONNECTEDMODE_ACTIVE.

The LINECONNECTEDMODE_ACTIVE and LINECONNECTEDMODE_INACTIVE values are used when the call is on an address that is shared with other stations (bridged; see LINEADDRESSSHARING_ constants), primarily electronic key systems. If the connected call state mode is "active," it means that the call is connected at the current station (the current station is a participant in the call). If the call state mode is "inactive," the call is active at one or more other stations, but the current station is not a participant in the call. If the call state mode is ZERO, the application should assume that the value is "active" (which would be the situation on a non-bridged address). The mode may switch between ACTIVE and INACTIVE during a call if the user joins and leaves the call through manual action.

In such a bridged situation, a lineDrop or lineHold operation may possibly not actually drop the call or place it on hold, since the status of other stations on the call may govern (for example, attempting to "hold" a call when other stations are particating will not be possible); instead, the call may simply be changed to the INACTIVE mode if it remains connected at other stations. A call in the INACTIVE state may be joined using the lineAnswer.

Many operations which are valid in calls in the connected state may be impossible in the INACTIVE mode, such as monitoring for tones and digits, since the station is not actually participating in the call; monitoring is usually suspended (although not cancelled) while the call is in the INACTIVE mode.


LINEDEVCAPFLAGS_ Constants

[New - Windows 95]

The LINEDEVCAPFLAGS_ bit-flag constants are a collection of Booleans describing various line device capabilities.

LINEDEVCAPFLAGS_CROSSADDRCONF

Specifies whether calls on different addresses on this line can be conferenced.

LINEDEVCAPFLAGS_HIGHLEVCOMP

Specifies whether high-level compatibility information elements are supported on this line.

LINEDEVCAPFLAGS_LOWLEVCOMP

Specifies whether low-level compatibility information elements are supported on this line.

LINEDEVCAPFLAGS_MEDIACONTROL

Specifies whether media-control operations are available for calls at this line.

LINEDEVCAPFLAGS_MULTIPLEADDR

Specifies whether lineMakeCall or lineDial are able to deal with multiple addresses at once (as for inverse multiplexing).

LINEDEVCAPFLAGS_CLOSEDROP

Specifies what happens when an open line is closed while the application has calls active on the line. If TRUE and used with the lineClose function, directs TAPI to forcibly drop calls when the last owner closes the line. The CLOSEDROP bit applies to external devices that keep the line open (such as a phone) and does not affect TAPI's behavior. Knowing the setting of this flag ahead of time makes it possible for the application to display an [OK]/[Cancel] dialog box for the user, warning that the active call will be lost. If CLOSEDROP is FALSE, a lineClose will not automatically drop any calls still active on the line if the service provider knows that some other device can keep the call alive. For example, if an analog line has the computer and phoneset both connect directly to them (in a party-line configuration), the service provider should set the flag to FALSE, as the offhook phone will automatically keep the call active even after the computer powers down.

LINEDEVCAPFLAGS_DIALBILLING

LINEDEVCAPFLAGS_DIALQUIET

LINEDEVCAPFLAGS_DIALDIALTONE

These flags indicate whether the "$", "@", or "W" dialable string modifier is supported for a given line device. It is TRUE if the modifier is supported; otherwise, FALSE. The "?" (prompt user to continue dialing) is never supported by a line device. These flags allow an application to determine "up front" which modifiers would result in the generation of a LINEERR. The application has the choice of pre-scanning dialable strings for unsupported characters or of passing the "raw" string from lineTranslateAddress directly to the provider as part of functions such as lineMakeCall or lineDial and let the function generate an error to tell it which unsupported modifier occurs first in the string.

No extensibility. All 32 bits are reserved.


LINEDEVSTATE_ Constants

[New - Windows 95]

The LINEDEVSTATE_ bit-flag constants describe various line status events.

LINEDEVSTATE_OTHER

Device-status items other than those listed below have changed. The application should check the current device status to determine which items have changed.

LINEDEVSTATE_RINGING

The switch tells the line to alert the user.

LINEDEVSTATE_CONNECTED

The line was previously disconnected and is now connected to TAPI.

LINEDEVSTATE_DISCONNECTED

This line was previously connected and is now disconnected from TAPI.

LINEDEVSTATE_MSGWAITON

The "message waiting" indicator is turned on.

LINEDEVSTATE_MSGWAITOFF

The "message waiting" indicator is turned off.

LINEDEVSTATE_INSERVICE

The line is connected to TAPI. This happens when TAPI is first activated or when the line wire is physically plugged in and in-service at the switch while TAPI is active.

LINEDEVSTATE_OUTOFSERVICE

The line is out of service at the switch or physically disconnected. TAPI cannot be used to operate on the line device.

LINEDEVSTATE_MAINTENANCE

Maintenance is being performed on the line at the switch. TAPI cannot be used to operate on the line device.

LINEDEVSTATE_OPEN

The line has been opened by another application.

LINEDEVSTATE_CLOSE

The line has been closed by another application.

LINEDEVSTATE_NUMCALLS

The number of calls on the line device has changed.

LINEDEVSTATE_NUMCOMPLETIONS

The number of outstanding call completions on the line device has changed.

LINEDEVSTATE_TERMINALS

The terminal settings have changed. This may happen, for example, if multiple line devices share terminals among them (for example, two lines sharing a phone terminal).

LINEDEVSTATE_ROAMMODE

The roam mode of the line device has changed.

LINEDEVSTATE_BATTERY

The battery level has changed significantly (cellular).

LINEDEVSTATE_SIGNAL

The signal level has changed significantly (cellular).

LINEDEVSTATE_DEVSPECIFIC

The line's device-specific information has changed.

LINEDEVSTATE_REINIT

Items have changed in the configuration of line devices. To become aware of these changes (as for the appearance of new line devices) the application should reinitialize its use of TAPI.

LINEDEVSTATE_LOCK

The locked status of the line device has changed. (For more information, refer to the description of the LINEDEVSTATUSFLAGS_LOCKED bit in the LINEDEVSTATUSFLAGS_ constants.)

LINEDEVSTATE_CAPSCHANGE

Indicates that, due to configuration changes made by the user or other circumstances, one or more of the fields in the LINEDEVCAPS structure for the address have changed. The application should use lineGetDevCaps to read the updated structure. If a service provider sends a LINE_LINEDEVSTATE message containing this value to TAPI, TAPI will pass it along to applications which have negotiated this or a subsequent API version; applications negotiating a previous API version will receive LINE_LINEDEVSTATE messages specifying LINEDEVSTATE_REINIT, requiring them to shutdown and reinitialize their connection to TAPI in order to obtain the updated information.

LINEDEVSTATE_CONFIGCHANGE

Indicates that configuration changes have been made to one or more of the media devices associated with the line device. The application, if it desires, may use lineGetDevConfig to read the updated information. If a service provider sends a LINE_LINEDEVSTATE message containing this value to TAPI, TAPI will pass it along to applications which have negotiated this or a subsequent API version; applications negotiating a previous API version will not receive any notification.

LINEDEVSTATE_TRANSLATECHANGE

Indicates that, due to configuration changes made by the user or other circumstances, one or more of the fields in the LINETRANSLATECAPS structure have changed. The application should use lineGetTranslateCaps to read the updated structure. If a service provider sends a LINE_LINEDEVSTATE message containing this value to TAPI, TAPI will pass it along to applications which have negotiated this or a subsequent API version; applications negotiating a previous API version will receive LINE_LINEDEVSTATE messages specifying LINEDEVSTATE_REINIT, requiring them to shutdown and reinitialize their connection to TAPI in order to obtain the updated information.

LINEDEVSTATE_COMPLCANCEL

Indicates that the call completion identified by the completion ID contained in parameter dwParam2 of the LINE_LINEDEVSTATE message has been externally cancelled and is no longer considered valid (if that value were to be passed in a subsequent call to lineUncompleteCall, the function would fail with LINEERR_INVALCOMPLETIONID). If a service provider sends a LINE_LINEDEVSTATE message containing this value to TAPI, TAPI will pass it along to applications which have negotiated this or a subsequent API version; applications negotiating a previous API version will not receive any notification.

LINEDEVSTATE_REMOVED

Indicates that the device is being removed from the system by the service provider (most likely through user action, via a control panel or similar utility). A LINE_LINEDEVSTATE message with this value will normally be immediately followed by a LINE_CLOSE message on the device. Subsequent attempts to access the device prior to TAPI being reinitialized will result in LINEERR_NODEVICE being returned to the application. If a service provider sends a LINE_LINEDEVSTATE message containing this value to TAPI, TAPI will pass it along to applications which have negotiated this or a subsequent API version; applications negotiating a previous API version will not receive any notification.

No extensibility. All 32 bits are reserved.


LINEDEVSTATUSFLAGS_ Constants

[New - Windows 95]

The LINEDEVSTATUSFLAGS_ bit-flag constants describe a collection of Boolean line device status items.

LINEDEVSTATUSFLAGS_CONNECTED

Specifies whether the line is connected to TAPI. If TRUE, the line is connected and TAPI is able to operate on the line device. If FALSE, the line is disconnected and the application is unable to control the line device through TAPI.

LINEDEVSTATUSFLAGS_MSGWAIT

Indicates whether the line has a message waiting. If TRUE, a message is waiting; if FALSE, no message is waiting.

LINEDEVSTATUSFLAGS_INSERVICE

Indicates whether the line is in service. If TRUE, the line is in service; if FALSE, the line is out of service.

LINEDEVSTATUSFLAGS_LOCKED

Indicates whether the line is locked or unlocked. This bit is most often used with line devices associated with cellular phones. Many cellular phones have a security mechanism that requires the entry of a password to enable the phone to place calls. This bit may be used to indicate to applications that the phone is locked and cannot place calls until the password is entered on the user interface of the phone so that the application can present an appropriate alert to the user.

No extensibility. All 32 bits are reserved.

LINEDEVSTATUSFLAGS_ constants are used within the dwDevStatusFlags field of the LINEDEVSTATUS data structure.


LINEDIALTONEMODE_ Constants

[New - Windows 95]

The LINEDIALTONEMODE_ bit-flag constants describe different types of dialtones. A special dialtone typically carries a special meaning (as with message waiting).

LINEDIALTONEMODE_NORMAL

This is a "normal" dialtone which typically is a continuous tone.

LINEDIALTONEMODE_SPECIAL

This is a special dialtone indicating that a certain condition (known by the switch or network) is currently in effect. Special dial tones typically use an interrupted tone. As with a normal dial tone, this indicates that the switch is ready to receive the number to be dialed.

LINEDIALTONEMODE_INTERNAL

This is an internal dialtone, as within a PBX.

LINEDIALTONEMODE_EXTERNAL

This is an external (public network) dialtone.

LINEDIALTONEMODE_UNKNOWN

The dialtone mode is not currently known but may become known later.

LINEDIALTONEMODE_UNAVAIL

The dialtone mode is unavailable and will not become known.

The high-order 16 bits can be assigned for device-specific extensions. The low-order 16 bits are reserved.

The LINEDIALTONEMODE_ constants are used within the LINECALLSTATUS data structure for a call in the dialtone state.


LINEDIGITMODE_ Constants

[New - Windows 95]

The LINEDIGITMODE_ constants describe different types of inband digit generation.

LINEDIGITMODE_PULSE

Uses rotary pulse sequences to signal digits. Valid digits are '0' through '9'.

LINEDIGITMODE_DTMF

Uses DTMF tones to signal digits. Valid digits are '0' through '9', '*', '#', 'A', 'B', 'C', and 'D'.

LINEDIGITMODE_DTMFEND

Uses DTMF tones to signal digits and detect the down edges. Valid digits are '0' through '9', '*', '#', 'A', 'B', 'C', and 'D'.

No extensibility. All 32 bits are reserved.

A digit mode can be specified when generating or detecting digits. Note that pulse digits are generated by making and breaking the local loop circuit. These pulses are absorbed by the switch. The remote end merely observes this as a series of inband audio clicks. Detecting digits sent as pulses must therefore be able to detect these sequences of 1 to 10 audible clicks.


LINEDISCONNECTMODE_ Constants

[New - Windows 95]

The LINEDISCONNECTMODE_ bit-flag constants describe different reasons for a remote disconnect request. A disconnect mode is available as call status to the application after the call state transitions to disconnected.

LINEDISCONNECTMODE_NORMAL

This is a "normal" disconnect request by the remote party. The call was terminated normally.

LINEDISCONNECTMODE_UNKNOWN

The reason for the disconnect request is unknown but may become known later.

LINEDISCONNECTMODE_REJECT

The remote user has rejected the call.

LINEDISCONNECTMODE_PICKUP

The call was picked up from elsewhere.

LINEDISCONNECTMODE_FORWARDED

The call was forwarded by the switch.

LINEDISCONNECTMODE_BUSY

The remote user's station is busy.

LINEDISCONNECTMODE_NOANSWER

The remote user's station does not answer.

LINEDISCONNECTMODE_BADADDRESS

The destination address is invalid.

LINEDISCONNECTMODE_UNREACHABLE

The remote user could not be reached.

LINEDISCONNECTMODE_CONGESTION

The network is congested.

LINEDISCONNECTMODE_INCOMPATIBLE

The remote user's station equipment is incompatible with the type of call requested.

LINEDISCONNECTMODE_UNAVAIL

The reason for the disconnect is unavailable and will not become known later.

LINEDISCONNECTMODE_NODIALTONE

A dial tone was not detected within a service-provider defined timeout, at a point during dialing when one was expected (such as at a "W" in the dialable string). This can also occur without a service-provider-defined timeout period or without a value specified in the dwWaitForDialTone member of the LINEDIALPARAMS structure.

The high-order 16 bits can be assigned for device-specific extensions. The low-order 16 bits are reserved.

A remote disconnect request for a given call results in the call state transitioning to the disconnected state and a LINE_CALLSTATE message is sent to the application. The LINEDISCONNECTMODE_ information provides details about the remote disconnect request. It is available in the call's LINECALLSTATUS structure when the call is in the disconnected state. While a call is in this state, the application is still allowed to query the call's information and status. For example, user-to-user information that is received as part of the remote disconnect is available then. The application can clear a disconnected call by dropping the call.

For backward compatibility, it is the responsibility of the service provider to examine the negotiated API version on the line, and to not use this LINEDISCONNECTMODE_ value if it is not supported on the negotiated version (LINEDISCONNECTMODE_NORMAL or _UNKNOWN could be used instead).


LINEERR_ Constants

[New - Windows 95]

This is the list of error codes that TAPI may return when invoking operations on lines, addresses, or calls. Consult the individual function descriptions to determine which of these error codes a particular function may return.

The values 0xC0000000 through 0xFFFFFFFF are available for device-specific extensions. The values 0x80000000 through 0xBFFFFFFF are reserved, while 0x00000000 through 0x7FFFFFFF are used as request IDs.

If an application gets an error return that it does not specifically handle (such as an error defined by a device-specific extension), it should treat the error as a LINEERR_OPERATIONFAILED (for an unspecified reason).


LINEFEATURE_ Constants

[New - Windows 95]

The LINEFEATURE_ constants list the operations that can be invoked on a line using this API.

LINEFEATURE_DEVSPECIFIC

Device-specific operations can be used on the line.

LINEFEATURE_DEVSPECIFICFEAT

Device-specific features can be used on the line.

LINEFEATURE_FORWARD

Forwarding of all addresses can be used on the line.

LINEFEATURE_MAKECALL

An outbound call can be placed on this line using an unspecified address.

LINEFEATURE_SETMEDIACONTROL

Media control can be set on this line.

LINEFEATURE_SETTERMINAL

Terminal modes for this line can be set.

No extensibility. All 32 bits are reserved.

The LINEFEATURE_ constants are used in LINEDEVSTATUS (returned by lineGetLineDevStatus). LINEDEVSTATUS reports, for a given line, which line features can actually be invoked while the line is in the current state. An application would make this determination dynamically after line state changes, typically caused by address or call-related activities on the line.


LINEFORWARDMODE_ Constants

[New - Windows 95]

The LINEFORWARDMODE_ bit-flag constants describe the conditions under which calls to an address can be forwarded.

LINEFORWARDMODE_UNCOND

Forward all calls unconditionally, irrespective of their origin. Use this value when unconditional forwarding for internal and external calls cannot be controlled separately. Unconditional forwarding overrides forwarding on busy and/or no answer conditions.

LINEFORWARDMODE_UNCONDINTERNAL

Forward all internal calls unconditionally. Use this value when unconditional forwarding for internal and external calls can be controlled separately.

LINEFORWARDMODE_UNCONDEXTERNAL

Forward all external calls unconditionally. Use this value when unconditional forwarding for internal and external calls can be controlled separately.

LINEFORWARDMODE_UNCONDSPECIFIC

Unconditionally forward all calls that originated at a specified address (selective call forwarding).

LINEFORWARDMODE_BUSY

Forward all calls on busy, irrespective of their origin. Use this value when forwarding for internal and external calls on busy and on no answer cannot be controlled separately.

LINEFORWARDMODE_BUSYINTERNAL

Forward all internal calls on busy. Use this value when forwarding for internal and external calls on busy and on no answer can be controlled separately.

LINEFORWARDMODE_BUSYEXTERNAL

Forward all external calls on busy. Use this value when forwarding for internal and external calls on busy and on no answer can be controlled separately.

LINEFORWARDMODE_BUSYSPECIFIC

Forward on busy all calls that originated at a specified address (selective call forwarding).

LINEFORWARDMODE_NOANSW

Forward all calls on no answer, irrespective of their origin. Use this value when call forwarding for internal and external calls on no answer cannot be controlled separately.

LINEFORWARDMODE_NOANSWINTERNAL

Forward all internal calls on no answer. Use this value when forwarding for internal and external calls on no answer can be controlled separately.

LINEFORWARDMODE_NOANSWEXTERNAL

Forward all external calls on no answer. Use this value when forwarding for internal and external calls on no answer can be controlled separately.

LINEFORWARDMODE_NOANSWSPECIFIC

Forward on no answer all calls that originated at a specified address (selective call forwarding).

LINEFORWARDMODE_BUSYNA

Forward all calls on busy/no answer, irrespective of their origin. Use this value when forwarding for internal and external calls on busy and on no answer cannot be controlled separately.

LINEFORWARDMODE_BUSYNAINTERNAL

Forward all internal calls on busy/no answer. Use this value when call forwarding on busy and on no answer cannot be controlled separately for internal calls.

LINEFORWARDMODE_BUSYNAEXTERNAL

Forward all external calls on busy/no answer. Use this value when call forwarding on busy and on no answer cannot be controlled separately for internal calls.

LINEFORWARDMODE_BUSYNASPECIFIC

Forward on busy/no answer all calls that originated at a specified address (selective call forwarding).

LINEFORWARDMODE_UNKNOWN

Calls are forwarded, but the conditions under which forwarding will occur are not known at this time. It is possible that the conditions may become known at a future time.

LINEFORWARDMODE_UNAVAIL

Calls are forwarded, but the conditions under which forwarding will occur are not known, and will never be known by the service provider.

No extensibility. All 32 bits are reserved.

The bit flags defined by LINEFORWARDMODE_ are not orthogonal. Unconditional forwarding ignores any specific condition such as busy or no answer. If unconditional forwarding is not in effect, then forwarding on busy and on no answer can be controlled separately or not separately. If controlled separately, the LINEFORWARDMODE_BUSY and LINEFORWARDMODE_NOANSW flags can be used separately. If not controlled separately, the flag LINEFORWARDMODE_BUSYNA must be used. Similarly, if forwarding of internal and external calls can be controlled separately, then LINEFORWARDMODE_INTERNAL and LINEFORWARDMODE_EXTERNAL flags can be used separately; otherwise the combination is used.

Address capabilities indicate which forwarding mode(s) are available for each address assigned to a line. An application can use lineForward to set forwarding conditions at the switch.

For backward compatibility, it is the responsibility of the service provider to examine the negotiated API version on the line, and to not use these LINEFORWARDMODE_ values if i not supported on the negotiated version.


LINEGATHERTERM_ Constants

[New - Windows 95]

The LINEGATHERTERM_ bit-flag constants describe the conditions under which buffered digit gathering is terminated.

LINEGATHERTERM_BUFFERFULL

The requested number of digits has been gathered. The buffer is full.

LINEGATHERTERM_TERMDIGIT

One of the termination digits matched a received digit. The matched termination digit is the last digit in the buffer.

LINEGATHERTERM_FIRSTTIMEOUT

The first digit timeout expired. The buffer contains no digits.

LINEGATHERTERM_INTERTIMEOUT

The inter-digit timeout expired. The buffer contains at least one digit.

LINEGATHERTERM_CANCEL

The request was canceled by this application, by another application, or because the call terminated.

No extensibility. All 32 bits are reserved.


LINEGENERATETERM_ Constants

[New - Windows 95]

The LINEGENERATETERM_ bit-flag constants describe the conditions under which digit or tone generation is terminated.

LINEGENERATETERM_DONE

The requested number of digits or requested tones have been generated for the requested duration.

LINEGENERATETERM_CANCEL

The digit or tone generation request was canceled by this application, by another application, or because the call terminated. This value may also be returned when digit or tone generation cannot be completed due to internal failure of the service provider.

No extensibility. All 32 bits are reserved.


LINELOCATIONOPTION_ Constants

[New - Windows 95]

The LINELOCATIONOPTION_ constants define values used in the dwOptions field of the LINELOCATIONENTRY structure returned as part of the LINETRANSLATECAPS structure returned by lineGetTranslateCaps.

LINELOCATIONOPTION_PULSEDIAL

The default dialing mode at this location is pulse dialing. If this bit is set, lineTranslateAddress will insert a "P" dial modifier at the beginning of the dialable string returned when this location is selected. If this bit is not set, lineTranslateAddress will insert a "T" dial modifier at the beginning of the dialable string.

Not extensible. All 32 bits are reserved.


LINEMEDIACONTROL_ Constants

[New - Windows 95]

The LINEMEDIACONTROL_ bit-flag constants describe a set of generic operations on media streams. The interpretations are determined by the media stream. The line device must have the media-control capability for any media-control operations to be effective.

LINEMEDIACONTROL_NONE

No change is to be made to the media stream.

LINEMEDIACONTROL_START

Start the media stream.

LINEMEDIACONTROL_RESET

Reset the media stream. Equivalent to an end-of-input. All buffers are released.

LINEMEDIACONTROL_PAUSE

Temporarily pause the media stream.

LINEMEDIACONTROL_RESUME

Resume a paused media stream.

LINEMEDIACONTROL_RATEUP

The speed of the media stream is increased by some stream-defined quantity.

LINEMEDIACONTROL_RATEDOWN

The speed of the media stream is decreased by some stream-defined quantity.

LINEMEDIACONTROL_RATENORMAL

The speed of the media stream is returned to normal.

LINEMEDIACONTROL_VOLUMEUP

The amplitude of the media stream is increased by some stream-defined quantity.

LINEMEDIACONTROL_VOLUMEDOWN

The amplitude of the media stream is decreased by some stream-defined quantity.

LINEMEDIACONTROL_VOLUMENORMAL

The amplitude of the media stream is returned to normal.

The high-order 16 bits can be assigned for device-specific extensions. The low-order 16 bits are reserved.

Media control is provided to improve performance of actions on media streams in response to telephony-related events. The application should normally manage a media stream through the media-specific API. The media-control functionality provided here is not intended to replace the native media APIs.

Media-control actions can be associated with the detection of digits, the detection of tones, the transition into a call state, and the detection of a media mode. Consult a line's device capabilities to determine whether media control is available on a line.


LINEMEDIAMODE_ Constants

[New - Windows 95]

The LINEMEDIAMODE_ constants describe media modes (the data type of a media stream) on calls.

LINEMEDIAMODE_UNKNOWN

A media stream exists but its mode is not currently known and may become known later. This would correspond to a call with an unclassified media type. In typical analog telephony environments, an inbound call's media mode may be unknown until after the call has been answered and the media stream has been filtered to make a determination.

If the unknown media-mode flag is set, other media flags may also be set. This is used to signify that the media is unknown but that it is likely to be one of the other selected media modes.

LINEMEDIAMODE_INTERACTIVEVOICE

The presence of voice energy on the call, and the call is treated as an interactive call with humans on both ends.

LINEMEDIAMODE_AUTOMATEDVOICE

The presence of voice energy on the call and the voice is locally handled by an automated application.

LINEMEDIAMODE_DATAMODEM

A data modem session on the call.

LINEMEDIAMODE_G3FAX

A group 3 fax is being sent or received over the call.

LINEMEDIAMODE_TDD

A TDD (Telephony Devices for the Deaf) session on the call.

LINEMEDIAMODE_G4FAX

A group 4 fax is being sent or received over the call.

LINEMEDIAMODE_DIGITALDATA

Digital data is being sent or received over the call.

LINEMEDIAMODE_TELETEX

A teletex session on the call. Teletex is one of the telematic services.

LINEMEDIAMODE_VIDEOTEX

A videotex session on the call. Videotex is one the telematic services.

LINEMEDIAMODE_TELEX

A telex session on the call. Telex is one the telematic services.

LINEMEDIAMODE_MIXED

A mixed session on the call. Mixed is one the ISDN telematic services.

LINEMEDIAMODE_ADSI

An ADSI (Analog Display Services Interface) session on the call.

LINEMEDIAMODE_VOICEVIEW

The media mode of the call is VoiceView.

The high-order 8 bits can be assigned for device-specific extensions. The low-order 24 bits are reserved.

Note that bearer mode and media mode are different notions. The bearer mode of a call is an indication of the quality of the telephone connection as provided primarily by the network. The media mode of a call is an indication of the type of information stream that is exchanged over that call. Group 3 fax or data modem are media modes that use a call with a 3.1kHz voice bearer mode.

For backward compatibility, it is the responsibility of the service provider to examine the negotiated API version on the line, and to not use this LINEMEDIAMODE_ value if not supported on the negotiated version.


LINEOFFERINGMODE_ Constants

[New - Windows 95]

The LINEOFFERINGMODE_ bit-flag constants describe different substates of an offering call. A mode is available as call status to the application after the call state transitions to offering, and within the LINE_CALLSTATE message indicating the call is in LINECALLSTATE_OFFERING. These values are used when the call is on an address that is shared (bridged) with other stations (see the LINEADDRESSSHARING_ constants), primarily electronic key systems.

LINEOFFERINGMODE_ACTIVE

Indicates that the call is alerting at the current station (will be accompanied by LINEDEVSTATE_RINGING messages), and if any application is set up to automatically answer, it may do so. If the call state mode is ZERO, the application should assume that the value is "active" (which would be the situation on a non-bridged address).

LINEOFFERINGMODE_INACTIVE

Indicates that the call is being offered at more than one station, but the current station is not alerting (e.g., it may be an attendant station where the offering status is advisory, such as blinking a light); software at the station set for automatic answering should preferably not answer the call, since this should be the perogative at the primary (alerting) station, but lineAnswer may be used to connect the call.

Not extensible. All 32 bits are reserved.

For backward compatibility, it is the responsibility of the service provider to examine the negotiated API version on the line, and to not use these LINEOFFERINGMODE_ values if not supported on the negotiated version. It should be noted that applications which are not cognizant of LINEOFFERINGMODE_ will most likely assume that a call that is in LINECALLSTATE_OFFERING is in LINEOFFERINGMODE_ACTIVE.

The LINEOFFERINGMODE_ACTIVE and LINEOFFERINGMODE_INACTIVE values are used when the call is on an address that is shared with other stations (bridged; see LINEADDRESSSHARING_ constants), primarily electronic key systems. If the offering call state mode is "active," it means that the call is alerting at the current station (will be accompanied by LINEDEVSTATE_RINGING messages), and if any application is set up to automatically answer, it may do so. If the call state mode is "inactive," the call is being offered at more than one station, but the current station is not alerting (e.g., it may be an attendant station where the offering status is advisory, such as blinking a light); software at the station set for automatic answering should preferably not answer the call, since this should be the perogative at the primary (alerting) station, but lineAnswer may be used to connect the call. If the call state mode is ZERO, the application should assume that the value is "active" (which would be the situation on a non-bridged address).


LINEPARKMODE_ Constants

[New - Windows 95]

The LINEPARKMODE_ bit-flag constants describe different ways of parking calls.

LINEPARKMODE_DIRECTED

Specifies directed call park. The address where the call is to be parked must be supplied to the switch.

LINEPARKMODE_NONDIRECTED

Specifies nondirected call park. The address where the call is parked is selected by the switch and provided by the switch to the application.

No extensibility. All 32 bits are reserved.

The LINEPARKMODE_ constants are used when parking a call. Consult a line's address device capabilities to find out which park mode is available.


LINEREMOVEFROMCONF_ Constants

[New - Windows 95]

The LINEREMOVEFROMCONF_ scalar constants describe how parties participating in a conference call can be removed from a conference call.

LINEREMOVEFROMCONF_NONE

Parties cannot be removed from the conference call.

LINEREMOVEFROMCONF_LAST

Only the most recently added party can be removed from the conference call

LINEREMOVEFROMCONF_ANY

Any participating party can be removed from the conference call.

No extensibility. All 32 bits are reserved.


LINEREQUESTMODE_ Constants

[New - Windows 95]

The LINEREQUESTMODE_ bit-flag constants describe different types of telephony requests that can be made from one application to another.

LINEREQUESTMODE_MAKECALL

A tapiRequestMakeCall request.

No extensibility. All 32 bits are reserved.


LINEROAMMODE_ Constants

[New - Windows 95]

The LINEROAMMODE_ bit-flag constants describe the roaming status of a line device.

LINEROAMMODE_UNKNOWN

The roam mode is currently unknown but may become known later.

LINEROAMMODE_UNAVAIL

The roam mode is unavailable and will not be known.

LINEROAMMODE_HOME

The line is connected to the home network node.

LINEROAMMODE_ROAMA

The line is connected to the Roam-A carrier and calls are charged accordingly.

LINEROAMMODE_ROAMB

The line is connected to the Roam-B carrier and calls are charged accordingly.

No extensibility. All 32 bits are reserved.


LINESPECIALINFO_ Constants

[New - Windows 95]

The LINESPECIALINFO_ bit-flag constants describes special information signals that the network may use to report various reporting and network observation operations. They are special coded tone sequences transmitted at the beginning of network advisory recorded announcements.

LINESPECIALINFO_NOCIRCUIT

This special information tone preceeds a no circuit or an emergency announcement (trunk blockage category).

LINESPECIALINFO_CUSTIRREG

This special information tone preceeds a vacant number, AIS, Centrex (™)  number change and nonworking station, access code not dialed or dialed in error, or manual intercept operator message (customer irregularity category). LINESPECIALINFO_CUSTIRREG is also reported when billing information is rejected and when the dialed address is blocked at the switch.

LINESPECIALINFO_REORDER

This special information tone preceeds a reorder announcement (equipment irregularity category). LINESPECIALINFO_REORDER is also reported when the telephone is kept offhook too long.

LINESPECIALINFO_UNKNOWN

Specifics about the special information tone are currently unknown but may become known later.

LINESPECIALINFO_UNAVAIL

Specifics about the special information tone are unavailable and will not become known.

The high-order 16 bits can be assigned for device-specific extensions. The low-order 16 bits are reserved.

Special information tones are defined for advisory messages and are not normally used for billing or supervisory purpose.


LINETERMDEV_ Constants

[New - Windows 95]

The LINETERMDEV_ bit-flag constants describe different types of terminal devices.

LINETERMDEV_PHONE

The terminal is a phone set.

LINETERMDEV_HEADSET

The terminal is a headset.

LINETERMDEV_SPEAKER

The terminal is an external speaker and microphone.

No extensibility. All 32 bits are reserved.

These constants are used to characterize a line's terminal device and help an application to determine the nature of a terminal device.


LINETERMMODE_ Constants

[New - Windows 95]

The LINETERMMODE_ bit-flag constants describe different types of events on a phone line that can be routed to a terminal device.

LINETERMMODE_BUTTONS

These are button-press events sent from the terminal to the line.

LINETERMMODE_LAMPS

These are lamp events sent from the line to the terminal.

LINETERMMODE_DISPLAY

This is display information sent from the line to the terminal.

LINETERMMODE_RINGER

This is ringer-control information sent from the switch to the terminal.

LINETERMMODE_HOOKSWITCH

These are hookswitch events sent from the terminal to the line.

LINETERMMODE_MEDIATOLINE

This is the unidirectional media stream from the terminal to the line associated with a call on the line. Use this value when the routing of both unidirectional channels of a call's media stream can be controlled independently.

LINETERMMODE_MEDIAFROMLINE

This is the unidirectional media stream from the line to the terminal associated with a call on the line. Use this value when the routing of both unidirectional channels of a call's media stream can be controlled independently.

LINETERMMODE_MEDIABIDIRECT

This is the bidirectional media stream associated with a call on the line and the terminal. Use this value when the routing of both unidirectional channels of a call's media stream cannot be controlled independently.

No extensibility. All 32 bits are reserved.

These constants describe the classes of control and information streams that can be routed directly between a line device and a terminal device (such as a phone set).


LINETERMSHARING_ Constants

[New - Windows 95]

The LINETERMSHARING_ bit-flag constants describe different ways in which a terminal can be shared between line devices, addresses, or calls.

LINETERMSHARING_PRIVATE

The terminal device is private to a single line device.

LINETERMSHARING_SHAREDEXCL

The terminal device can be used by multiple lines. The last line device to do a lineSetTerminal to the terminal for a given terminal mode will have exclusive connection to the terminal for that mode.

LINETERMSHARING_SHAREDCONF

The terminal device can be used by multiple lines. The lineSetTerminal requests of the various terminals end up being "merged" or conferenced at the terminal.

No extensibility. All 32 bits are reserved.

These constants describe the classes of control and information streams that can be routed directly between a line device and a terminal device (such as a phone set).


LINETOLLLISTOPTION_ Constants

[New - Windows 95]

The LINETOLLLISTOPTION_ bit-flag constants describe options for manipulating a toll list.

LINETOLLLISTOPTION_ADD

A prefix is to be added to the toll list.

LINETOLLLISTOPTION_REMOVE

A prefix is to be removed from the toll list.

No extensibility. All 32 bits are reserved.


LINETONEMODE_ Constants

[New - Windows 95]

The LINETONEMODE_ constants describe different selections that are used when generating line tones.

LINETONEMODE_CUSTOM

The tone is a custom tone defined by its component frequencies, of type LINEGENERATETONE.

LINETONEMODE_RINGBACK

The tone is ringback tone. Exact definition is service-provider defined.

LINETONEMODE_BUSY

The tone is a busy tone. Exact definition is service-provider defined.

LINETONEMODE_BEEP

The tone is a beep, such as that used to announce the beginning of a recording. Exact definition is service-provider defined.

LINETONEMODE_BILLING

The tone is a billing information tone such as a credit card prompt tone. Exact definition is service-provider defined.

The high-order 16 bits can be assigned for device-specific extensions. The low-order 16 bits are reserved.

These constants are used to define tones to be generated inband over a call to the remote party. Note that tone detection of non-custom tones does not use these constants.


LINETRANSFERMODE_ Constants

[New - Windows 95]

The LINETRANSFERMODE_ bit-flag constants describe different ways of resolving call transfer requests.

LINETRANSFERMODE_TRANSFER

The transfer is resolved by transferring the initial call to the consultation call. Both calls will become idle to the application.

LINETRANSFERMODE_CONFERENCE

The transfer is resolved by establishing a three-way conference between the application, the party connected to the initial call, and the party connected to the consultation call. A conference call is created when this option is selected.

No extensibility. All 32 bits are reserved.


LINETRANSLATEOPTION_ Constants

[New - Windows 95]

The LINETRANSLATEOPTION_ bit-flag constant describes an option used by address translation.

LINETRANSLATEOPTION_CARDOVERRIDE

The default calling card is to be overriden with a specified one.

LINETRANSLATEOPTION_CANCELCALLWAITING

If a Cancel Call Waiting string is defined for the location, setting this bit will cause that string to be inserted at the beginning of the dialable string. This is commonly used by datamodem and fax applications to prevent interruption of calls by call waiting beeps. If no Cancel Call Waiting string is defined for the location, this bit has no affect. Note that applications using this bit are advised to also set the LINECALLPARAMFLAGS_SECURE bit in the dwCallParamFlags field of the LINECALLPARAMS structure passed in to lineMakeCall via the lpCallParams parameter, so that if the line device uses a mechanism other than dialable digits to supress call interrupts that that mechanism will be invoked.

LINETRANSLATEOPTION_FORCELOCAL

If the number is local but would have been translated as a long distance call (LINETRANSLATERESULT_INTOLLLIST bit set in the LINETRANSLATEOUTPUT structure), this option will force it to be translated as local. This is a temporary override of the toll list setting.

LINETRANSLATEOPTION_FORCELD

If the address could potentially have been a toll call, but would have been translated as a local call (LINETRANSLATERESULT_NOTINTOLLLIST bit set in the LINETRANSLATEOUTPUT structure), this option will force it to be translated as long distance. This is a temporary override of the toll list setting.

No extensibility. All 32 bits are reserved.


LINETRANSLATERESULT_ Constants

[New - Windows 95]

The LINETRANSLATERESULT_ bit-flag constants describe various results of an address translation.

LINETRANSLATERESULT_CANONICAL

Indicates that the input string was in valid canonical format.

LINETRANSLATERESULT_INTERNATIONAL

Indicates that the call is being treated as an international call (country code specified in the destination address is the different from the country code specified for the CurrentLocation).

LINETRANSLATERESULT_LONGDISTANCE

Indicates that the call is being treated as a long distance call (country code specified in the destination address is the same but area code is different from those specified for the CurrentLocation).

LINETRANSLATERESULT_LOCAL

Indicates that the call is being treated as a local call (country code and area code specified in the destination address are the same as those specified for the CurrentLocation).

LINETRANSLATERESULT_INTOLLLIST

Indicates that the local call is being dialed as long distance because the country has toll calling and the prefix appears in the TollPrefixList of the CurrentLocation.

LINETRANSLATERESULT_NOTINTOLLLIST

Indicates that the country supports toll calling but the prefix does not appear in the TollPrefixList, so the call is dialed as a local call. Note that if both INTOLLIST and NOTINTOLLIST are off, the current country does not support toll prefixes, and user-interface elements related to toll prefixes should not be presented to the user; if either such bit is on, the country does support toll lists, and the related user-interface elements should be enabled.

LINETRANSLATERESULT_DIALBILLING

Indicates that the returned address contains a "$".

LINETRANSLATERESULT_DIALQUIET

Indicates that the returned address contain a "@".

LINETRANSLATERESULT_DIALDIALTONE

Indicates that the returned address contains a "W".

LINETRANSLATERESULT_DIALPROMPT

Indicates that the returned address contains a "?".

No extensibility. All 32 bits are reserved.


Phone Device Reference

Following are the functions, messages, structures, and constants used with TAPI phone devices.


Functions

Following are the TAPI phone functions.


phoneClose

[New - Windows 95]

LONG phoneClose(HPHONE hPhone)

Closes the specified open phone device.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

PHONEERR_INVALPHONEHANDLE	PHONEERR_NOMEM
PHONEERR_OPERATIONFAILED	PHONEERR_RESOURCEUNAVAIL
PHONEERR_OPERATIONUNAVAIL	PHONEERR_UNINITIALIZED
hPhone

Specifies a handle to the open phone device to be closed. If the function is successful, the handle is no longer valid.

After the open phone device has been successfully closed, the implementation sends a PHONE_CLOSE message to the application. Note that these messages can also be sent unsolicited as a result of the phone device being reclaimed somehow. An application should therefore be prepared to handle these unsolicited close messages. At the time the phone device is closed, any outstanding asynchronous replies are suppressed.


phoneConfigDialog

[New - Windows 95]

LONG phoneConfigDialog(HPHONE dwDeviceID, HWND hwndOwner,
    LPCSTR lpszDeviceClass)

Causes the provider of the specified phone device to display a modal dialog (attached to the application's hwndOwner) that allows the user to configure parameters related to the phone device specified by dwDeviceID.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

PHONEERR_BADDEVICEID	PHONEERR_NOMEM
PHONEERR_INUSE	PHONEERR_OPERATIONFAILED
PHONEERR_INVALPARAM	PHONEERR_OPERATIONUNAVAIL
PHONEERR_INVALDEVICECLASS	PHONEERR_RESOURCEUNAVAIL
PHONEERR_INVALPOINTER	PHONEERR_UNINITIALIZED
PHONEERR_NODEVICE
dwDeviceID

Specifies the phone device to be configured.

hwndOwner

Specifies a handle to a window to which the dialog is to be attached.

lpszDeviceClass

Specifies a pointer to a NULL-terminated string that identifies a device class name. This device class allows the application to select a specific subscreen of configuration information applicable to that device class. This parameter is optional and can be left NULL or empty, in which case the highest level configuration is selected.

The lpszDeviceClass parameter allows the application to select a specific subscreen of configuration information applicable to the device class in which the user is interested; the permitted strings are the same as for phoneGetID. For example, if the phone supports the wave API, passing "wave/in" as lpszDeviceClass would cause the provider to display the parameters related specifically to wave (or at least to start at the corresponding point in a multilevel configuration dialog chain, eliminating the need to search for relevant parameters).

lpszDeviceClass should be "tapi/phone", "", or NULL to cause the provider to display the highest level configuration for the phone.


phoneDevSpecific

[New - Windows 95]

LONG phoneDevSpecific(HPHONE hPhone, LPVOID lpParams, DWORD dwSize)

Is used as a general extension mechanism to enable a Telephony API implementation to provide features not described in the other TAPI functions. The meanings of these extensions are device specific.

•	Returns a positive request ID if the function will be completed asynchronously or a negative error number if an error has occurred. The dwParam2 parameter of the corresponding PHONE_REPLY callback message is zero if the function is successful or it is a negative error number if an error has occurred. Possible return values are:

PHONEERR_INVALPHONEHANDLE	PHONEERR_NOMEM
PHONEERR_INVALPOINTER	PHONEERR_RESOURCEUNAVAIL
PHONEERR_OPERATIONUNAVAIL	PHONEERR_UNINITIALIZED
PHONEERR_OPERATIONFAILED
Additional return values are device specific.

hPhone

Specifies a handle to a phone device.

lpParams

Specifies a pointer to a memory area used to hold a parameter block. Its interpretation is device specific. The contents of the parameter block is passed unchanged to or from the service provider by TAPI.

dwSize

The size in bytes of the parameter block area.

This operation provides a generic parameter profile. The interpretation of the parameter block is device specific. Indications and replies that are device specific should use the PHONE_DEVSPECIFIC message.

A service provider can provide access to device-specific functions by defining parameters for use with this operation. Applications that want to make use of these device-specific extensions should consult the device-specific (vendor-specific) documentation that describes which extentions are defined. Note that an application that relies on these device-specific extensions will typically not be portable to work with other service-provider environments.


phoneGetButtonInfo

[New - Windows 95]

LONG phoneGetButtonInfo(HPHONE hPhone, DWORD dwButtonLampID,
    LPPHONEBUTTONINFO lpButtonInfo)

Returns information about the specified button.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

PHONEERR_INVALPHONEHANDLE	PHONEERR_NOMEM
PHONEERR_INVALBUTTONLAMPID	PHONEERR_RESOURCEUNAVAIL
PHONEERR_INVALPOINTER	PHONEERR_OPERATIONFAILED
PHONEERR_INVALPHONESTATE	PHONEERR_STRUCTURETOOSMALL
PHONEERR_OPERATIONUNAVAIL	PHONEERR_UNINITIALIZED
hPhone

Specifies a handle to the open phone device.

dwButtonLampID

Specifies a button on the phone device.

lpButtonInfo

Specifies a pointer to a variably sized structure of type PHONEBUTTONINFO. This data structure describes the mode, the function, and provides additional descriptive text corresponding to the button.


phoneGetData

[New - Windows 95]

LONG phoneGetData(HPHONE hPhone, DWORD dwDataID, LPVOID lpData,
    DWORD dwSize)

Uploads the information from the specified location in the open phone device to the specified buffer.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

PHONEERR_INVALPHONEHANDLE	PHONEERR_NOMEM
PHONEERR_INVALPOINTER	PHONEERR_RESOURCEUNAVAIL
PHONEERR_INVALPHONESTATE	PHONEERR_OPERATIONFAILED
PHONEERR_INVALDATAID	PHONEERR_UNINITIALIZED
PHONEERR_OPERATIONUNAVAIL
hPhone

Specifies a handle to the open phone device.

dwDataID

Specifies where in the phone device the buffer is to be uploaded from.

lpData

Specifies a pointer to the memory buffer where the data is to be uploaded.

dwSize

Specifies the size of the data buffer in bytes.

The function uploads a maximum of dwSize bytes from the phone device into the memory area pointed to by lpData. If dwSize is zero, nothing is copied. The size of each data area is listed in the phone's device capabilities.


phoneGetDevCaps

[New - Windows 95]

LONG phoneGetDevCaps(HPHONEAPP hPhoneApp, DWORD dwDeviceID,
    DWORD dwAPIVersion, DWORD dwExtVersion, LPPHONECAPS lpPhoneCaps)

Queries a specified phone device to determine its telephony capabilities.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

PHONEERR_INVALAPPHANDLE	PHONEERR_INVALPOINTER
PHONEERR_BADDEVICEID	PHONEERR_OPERATIONFAILED
PHONEERR_INCOMPATIBLEAPIVERSION	PHONEERR_OPERATIONUNAVAIL
PHONEERR_INCOMPATIBLEEXTVERSION	PHONEERR_NOMEM
PHONEERR_STRUCTURETOOSMALL	PHONEERR_RESOURCEUNAVAIL
PHONEERR_NODRIVER	PHONEERR_UNINITIALIZED
PHONEERR_NODEVICE
hPhoneApp

Specifies the handle to the application's registration with TAPI.

dwDeviceID

Specifies the phone device to be queried.

dwAPIVersion

Specifies the version number of the Telephony API to be used. The high-order word contains the major version number; the low-order word contains the minor version number. This number is obtained with the function phoneNegotiateAPIVersion.

dwExtVersion

Specifies the version number of the service provider-specific extensions to be used. This number is obtained with the function phoneNegotiateExtVersion. It can be left zero if no device-specific extensions are to be used. Otherwise, the high-order word contains the major version number; the low-order word contains the minor version number.

lpPhoneCaps

Specifies a pointer to a variably sized structure of type PHONECAPS. Upon successful completion of the request, this structure is filled with phone device capabilities information.

Before using phoneGetDevCaps, the application must negotiate the TAPI version number to use, and optionally, the extension version to use.

TAPI and extension version numbers are those under which TAPI, Telephony DLL, and service provider must operate. If version ranges do not overlap, the application and API or service-provider versions are incompatible and an error is returned.


phoneGetDisplay

[New - Windows 95]

LONG phoneGetDisplay(HPHONE hPhone, LPVARSTRING lpDisplay)

Returns the current contents of the specified phone display.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

PHONEERR_INVALPHONEHANDLE	PHONEERR_RESOURCEUNAVAIL
PHONEERR_INVALPOINTER	PHONEERR_OPERATIONFAILED
PHONEERR_INVALPHONESTATE	PHONEERR_STRUCTURETOOSMALL
PHONEERR_OPERATIONUNAVAIL	PHONEERR_UNINITIALIZED
PHONEERR_NOMEM
hPhone

Specifies a handle to the open phone device.

lpDisplay

Specifies a pointer to the memory location where the display content is to be stored, of type VARSTRING.

The lpDisplay memory area should be at least (dwNumRows * dwNumColumns) elements in size to receive all of the display information. dwNumRows and dwNumColumns are available in the PHONECAPS structure returned by phoneGetDevCaps.


phoneGetGain

[New - Windows 95]

LONG phoneGetGain(HPHONE hPhone, DWORD dwHookSwitchDev,
    LPDWORD lpdwGain)

Returns the gain setting of the microphone of the specified phone's hookswitch device.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

PHONEERR_INVALPHONEHANDLE	PHONEERR_NOMEM
PHONEERR_INVALPOINTER	PHONEERR_RESOURCEUNAVAIL
PHONEERR_INVALPHONESTATE	PHONEERR_OPERATIONFAILED
PHONEERR_INVALHOOKSWITCHDEV	PHONEERR_UNINITIALIZED
PHONEERR_OPERATIONUNAVAIL
hPhone

Specifies a handle to the open phone device.

dwHookSwitchDev

Identifies the hookswitch device whose gain level is queried. Note that dwHookSwitchDev can have at most one bit set. This parameter uses the following PHONEHOOKSWITCHDEV_ constants:

PHONEHOOKSWITCHDEV_HANDSET

This is the phone's handset.

PHONEHOOKSWITCHDEV_SPEAKER

This is the phone's speakerphone or adjunct.

PHONEHOOKSWITCHDEV_HEADSET

This is the phone's headset.

lpdwGain

Specifies a pointer to a DWORD-sized location containing the current gain setting of the hookswitch microphone component. dwGain specifies the volume level of the hookswitch device. This is a number in the range 0x00000000 (silence) to 0x0000FFFF (maximum volume). The actual granularity and quantization of gain settings in this range are service provider specific.


phoneGetHookSwitch

[New - Windows 95]

LONG phoneGetHookSwitch(HPHONE hPhone, LPDWORD lpdwHookSwitchDevs)

Returns the current hookswitch mode of the specified open phone device.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

PHONEERR_INVALPHONEHANDLE	PHONEERR_NOMEM
PHONEERR_INVALPOINTER	PHONEERR_RESOURCEUNAVAIL
PHONEERR_INVALPHONESTATE	PHONEERR_OPERATIONFAILED
PHONEERR_OPERATIONUNAVAIL	PHONEERR_UNINITIALIZED
hPhone

Specifies a handle to the open phone device.

lpdwHookSwitchDevs

Specifies a pointer to a DWORD-sized location to be filled with the mode of the phone's hookswitch devices. If a bit position is FALSE, the corresponding hookswitch device is on-hook; if TRUE, the microphone and/or speaker part of the corresponding hookswitch device is offhook. To find out whether the microphone and/or speaker are enabled, the application can use phoneGetStatus. This parameter uses the following PHONEHOOKSWITCHDEV_ constants:

PHONEHOOKSWITCHDEV_HANDSET

This is the phone's handset.

PHONEHOOKSWITCHDEV_SPEAKER

This is the phone's speakerphone or adjunct.

PHONEHOOKSWITCHDEV_HEADSET

This is the phone's headset.

After the hookswitch state of a device changes, and if hookswitch monitoring is enabled, the application is sent a PHONE_STATE message.


phoneGetIcon

[New - Windows 95]

LONG phoneGetIcon(DWORD dwDeviceID, LPCSTR lpszDeviceClass,
    LPHICON lphIcon)

Allows an application to retrieve a service phone device-specific (or provider-specific) icon that can be displayed to the user.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

PHONEERR_BADDEVICEID	PHONEERR_RESOURCEUNAVAIL
PHONEERR_INVALPOINTER	PHONEERR_OPERATIONFAILED
PHONEERR_INVALDEVICECLASS	PHONEERR_UNINITIALIZED
PHONEERR_NOMEM	PHONEERR_NODEVICE
dwDeviceID

Specifies the phone device whose icon is requested.

lpszDeviceClass

Specifies a pointer to a NULL-terminated string that identifies a device class name. This device class allows the application to select a specific sub-icon applicable to that device class. This parameter is optional and can be left NULL or empty, in which case the highest-level icon associated with the phone device rather than a specified media stream device would be selected.

lphIcon

Specifies a pointer to a memory location in which the handle to the icon is returned.

phoneGetIcon causes the provider to return a handle (in lphIcon) to an icon resource (obtained from LoadIcon) associated with the specified phone. The icon handle will be for a resource associated with the provider; the application must use CopyIcon if it wishes to reference the icon after the provider is unloaded, which is unlikely to happen as long as the application has the phone open.

lpszDeviceClass allows the provider to return different icons based on the type of service being referenced by the caller. The permitted strings are the same as for phoneGetID. For example, if the phone supports the Comm API, passing "COMM" as lpszDeviceClass causes the provider to return an icon related specifically to the Comm device functions of the service provider.

The parameters "tapi/phone", "", or NULL may be used to request the icon for the phone service. If the provider does not return an icon, TAPI substitutes a generic Windows Telephony phone device icon.


phoneGetID

[New - Windows 95]

LONG phoneGetID(HPHONE hPhone, LPVARSTRING lpDeviceID,
    LPCSTR lpszDeviceClass)

Returns a device ID for the given device class associated with the specified phone device.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

PHONEERR_INVALPHONEHANDLE	PHONEERR_NOMEM
PHONEERR_INVALPOINTER	PHONEERR_RESOURCEUNAVAIL
PHONEERR_INVALDEVICECLASS	PHONEERR_UNINITIALIZED
PHONEERR_OPERATIONFAILED	PHONEERR_STRUCTURETOOSMALL
PHONEERR_OPERATIONUNAVAIL
hPhone

Specifies a handle to an open phone device.

lpDeviceID

Specifies a pointer to a data structure of type VARSTRING where the device ID is returned. Upon successful completion of the request, this location is filled with the device ID. The format of the returned information depends on the method used by the device class (API) for naming devices.

lpszDeviceClass

Specifies a pointer to a NULL-terminated string that specifies the device class of the device whose ID is requested. Valid device class strings are those used in the SYSTEM.INI section to identify device classes.

This function can be used to retrieve a phone device ID given a phone handle. It can also be used to obtain the device ID of the media device (for device classes such as COM, wave, MIDI, phone, line, or NDIS) associated with the opened phone device. The names of these device class are not case sensitive. This ID can then be used with the appropriate media API to select the corresponding device.

See Chapter 9, "Device Classes" for device class names.

A vendor that defines a device-specific media mode also needs to define the corresponding device-specific (proprietary) API to manage devices of the media mode. To avoid collisions on device class names assigned independently by different vendors, a vendor should select a name that uniquely identifies both the vendor and, following it, the media type. For example: "intel/video".


phoneGetLamp

[New - Windows 95]

LONG phoneGetLamp(HPHONE hPhone, DWORD dwButtonLampID,
    LPDWORD lpdwLampMode)

Returns the current lamp mode of the specified lamp.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

PHONEERR_INVALPHONEHANDLE	PHONEERR_NOMEM
PHONEERR_INVALBUTTONLAMPID	PHONEERR_RESOURCEUNAVAIL
PHONEERR_INVALPOINTER	PHONEERR_OPERATIONFAILED
PHONEERR_INVALPHONESTATE	PHONEERR_UNINITIALIZED
PHONEERR_OPERATIONUNAVAIL
hPhone

Specifies a handle to the open phone device.

dwButtonLampID

Specifies the ID of the lamp to be queried.

lpdwLampMode

Specifies a pointer to a memory location that will hold the lamp mode status of the given lamp. Note that lpdwLampMode can have at most one bit set. This parameter uses the following PHONELAMPMODE_ constants:

PHONELAMPMODE_BROKENFLUTTER

Broken flutter is the superposition of flash and flutter.

PHONELAMPMODE_FLASH

Flash means slow on and off.

PHONELAMPMODE_FLUTTER

Flutter means fast on and off.

PHONELAMPMODE_OFF

The lamp is off.

PHONELAMPMODE_STEADY

The lamp is continuously lit.

PHONELAMPMODE_WINK

The lamp is winking.

PHONELAMPMODE_UNKNOWN

The lamp mode is currently unknown.

PHONELAMPMODE_DUMMY

This value is used to describe a button/lamp position that has no corresponding lamp.

Phone sets that have multiple lamps per button should be modeled using multiple button/lamps pairs. Each extra button/lamp pair should use a DUMMY button.


phoneGetRing

[New - Windows 95]

LONG phoneGetRing(HPHONE hPhone, LPDWORD lpdwRingMode,
    LPDWORD lpdwVolume)

Enables an application to query the specified open phone device as to its current ring mode.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

PHONEERR_INVALPHONEHANDLE	PHONEERR_NOMEM
PHONEERR_INVALPHONESTATE	PHONEERR_RESOURCEUNAVAIL
PHONEERR_INVALPOINTER	PHONEERR_OPERATIONFAILED
PHONEERR_OPERATIONUNAVAIL	PHONEERR_UNINITIALIZED
hPhone

Specifies a handle to the open phone device.

lpdwRingMode

Specifies the ringing pattern with which the phone is ringing. Zero indicates that the phone is not ringing.

lpdwVolume

Specifies the volume level with which the phone is ringing. This is a number in the range 0x00000000 (silence) to 0x0000FFFF (maximum volume). The actual granularity and quantization of volume settings in this range are service-provider specific.

The service provider defines the actual audible ringing patterns corresponding to each of phone's ring modes.


phoneGetStatus

[New - Windows 95]

LONG phoneGetStatus(HPHONE hPhone, LPPHONESTATUS lpPhoneStatus)

Enables an application to query the specified open phone device for its overall status.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

PHONEERR_INVALPHONEHANDLE	PHONEERR_NOMEM
PHONEERR_INVALPOINTER	PHONEERR_RESOURCEUNAVAIL
PHONEERR_OPERATIONFAILED	PHONEERR_STRUCTURETOOSMALL
PHONEERR_OPERATIONUNAVAIL	PHONEERR_UNINITIALIZED
hPhone

Specifies a handle to the open phone device to be queried.

lpPhoneStatus

Specifies a pointer to a variably sized data structure of type PHONESTATUS, which is loaded with the returned information about the phone's status.

An application can use this function to determine the current state of an open phone device. The status information describes information about the phone device's hookswitch devices, ringer, volume, display, and lamps of the open phone.


phoneGetStatusMessages

[New - Windows 95]

LONG phoneGetStatusMessages(HPHONE hPhone, LPDWORD lpdwPhoneStates,
    LPDWORD lpdwButtonModes, LPDWORD lpdwButtonStates)

Returns which phone-state changes on the specified phone device will generate a callback to the application.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

PHONEERR_INVALPHONEHANDLE	PHONEERR_NOMEM
PHONEERR_INVALPOINTER	PHONEERR_RESOURCEUNAVAIL
PHONEERR_OPERATIONFAILED	PHONEERR_UNINITIALIZED
hPhone

Specifies a handle to the open phone device to be monitored.

lpdwPhoneStates

Specifies a pointer to a PHONESTATE_ constant. These flags specify the set of phone status changes and events for which the application wishes to receive notification messages. The lpdwPhoneStates parameter can return a value with zero, one, or multiple bits set. Monitoring can be individually enabled and disabled for:

PHONESTATE_OTHER

Phone-status items other than those listed below have changed. The application should check the current phone status to determine which items have changed.

PHONESTATE_CONNECTED

The connection between the phone device and TAPI was just made. This happens when TAPI is first invoked or when the wire connecting the phone to the computer is plugged in while TAPI is active.

PHONESTATE_DISCONNECTED

The connection between the phone device and TAPI was just broken. This happens when the wire connecting the phone set to the computer is unplugged while TAPI is active.

PHONESTATE_OWNER

The number of owners for the phone device has changed.

PHONESTATE_MONITORS

The number of monitors for the phone device has changed.

PHONESTATE_DISPLAY

The display of the phone has changed.

PHONESTATE_LAMP

A lamp of the phone has changed.

PHONESTATE_RINGMODE

The ring mode of the phone has changed.

PHONESTATE_RINGVOLUME

The ring volume of the phone has changed.

PHONESTATE_HANDSETHOOKSWITCH

The handset hookswitch state has changed.

PHONESTATE_HANDSETVOLUME

The handset's speaker volume setting has changed.

PHONESTATE_HANDSETGAIN

The handset's microphone gain setting has changed.

PHONESTATE_SPEAKERHOOKSWITCH

The speakerphone's hookswitch state has changed.

PHONESTATE_SPEAKERVOLUME

The speakerphone's speaker volume setting has changed.

PHONESTATE_SPEAKERGAIN

The speakerphone's microphone gain setting state has changed.

PHONESTATE_HEADSETHOOKSWITCH

The headset's hookswitch state has changed.

PHONESTATE_HEADSETVOLUME

The headset's speaker volume setting has changed.

PHONESTATE_HEADSETGAIN

The headset's microphone gain setting has changed.

PHONESTATE_SUSPEND

The application's use of the phone is temporarily suspended.

PHONESTATE_RESUME

The application's use of the phone device is resumed after having been suspended for some time.

PHONESTATE_DEVSPECIFIC

The phone's device-specific information has changed.

PHONESTATE_REINIT

Items have changed in the configuration of phone devices. To become aware of these changes (as with the appearance of new phone devices) the application should reinitialize its use of TAPI. The hDevice parameter of the PHONE_STATE message is left NULL for this state change, as it applies to any of the phones in the system.

PHONESTATE_CAPSCHANGE

Indicates that, due to configuration changes made by the user or other circumstances, one or more of the fields in the PHONECAPS structure have changed. The application should use phoneGetDevCaps to read the updated structure. If a service provider sends a PHONE_STATE message containing this value to TAPI, TAPI will pass it along to applications which have negotiated this or a subsequent API version; applications negotiating a previous API version will receive PHONE_STATE messages specifying PHONESTATE_REINIT, requiring them to shutdown and reinitialize their connection to TAPI in order to obtain the updated information.

PHONESTATE_REMOVED

Indicates that the device is being removed from the system by the service provider (most likely through user action, via a control panel or similar utility). A PHONE_STATE message with this value will normally be immediately followed by a PHONE_CLOSE message on the device. Subsequent attempts to access the device prior to TAPI being reinitialized will result in PHONEERR_NODEVICE being returned to the application. If a service provider sends a PHONE_STATE message containing this value to TAPI, TAPI will pass it along to applications which have negotiated this or a subsequent API version; applications negotiating a previous API version will not receive any notification.

lpdwButtonModes

Specifies a pointer to a . These flags specify the set of phone-button modes for which the application wishes to receive notification messages. The lpdwButtonModes parameter can return a value with zero, one, or multiple bits set. This parameter uses the following PHONEBUTTONMODE_ constants:

PHONEBUTTONMODE_CALL

The button is assigned to a call appearance.

PHONEBUTTONMODE_FEATURE

The button is assigned to requesting features from the switch, such as hold, conference, and transfer.

PHONEBUTTONMODE_KEYPAD

The button is one of the twelve keypad buttons, '0' through '9', '*', and '#'.

PHONEBUTTONMODE_LOCAL

The button is a local function button, such as mute or volume control.

PHONEBUTTONMODE_DISPLAY

The button is a "soft" button associated with the phone's display. A phone set can have zero or more display buttons.

lpdwButtonStates

Specifies a pointer to a DWORD-sized location that contains flags specifying the set of phone button state changes for which the application wishes to receive notification messages. The lpdwButtonStates field can return a value with zero, one or multiple bits set. This parameter uses the following PHONEBUTTONSTATE_ constants:

PHONEBUTTONSTATE_UP

The button is in the "up" state.

PHONEBUTTONSTATE_DOWN

The button is in the "down" state (pressed down).

PHONEBUTTONSTATE_UNKNOWN

Indicates that the up or down state of the button is not known at this time, but may become known at a future time.

PHONEBUTTONSTATE_UNAVAIL

Indicates that the up or down state of the button is not known to the service provider, and will not become known at a future time.

An application can use this function to query the generation of the corresponding messages. Message generation can be controlled by phoneSetStatusMessages. All phone status messages are disabled by default.


phoneGetVolume

[New - Windows 95]

LONG phoneGetVolume(HPHONE hPhone, DWORD dwHookSwitchDev,
    LPDWORD lpdwVolume)

Returns the volume setting of the specified phone's hookswitch device.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

PHONEERR_INVALPHONEHANDLE	PHONEERR_NOMEM
PHONEERR_INVALPHONESTATE	PHONEERR_RESOURCEUNAVAIL
PHONEERR_INVALPOINTER	PHONEERR_OPERATIONFAILED
PHONEERR_INVALHOOKSWITCHDEV	PHONEERR_UNINITIALIZED
PHONEERR_OPERATIONUNAVAIL
hPhone

Specifies a handle to the open phone device.

dwHookSwitchDev

Identifies a single hookswitch device whose volume level is queried. This parameter uses the following PHONEHOOKSWITCHDEV_ constants:

PHONEHOOKSWITCHDEV_HANDSET

This is the phone's handset.

PHONEHOOKSWITCHDEV_SPEAKER

This is the phone's speakerphone or adjunct.

PHONEHOOKSWITCHDEV_HEADSET

This is the phone's headset.

lpdwVolume

Specifies a pointer to a DWORD-sized location containing the current volume setting of the hookswitch device. dwVolume specifies the volume level of the hookswitch device. This is a number in the range 0x00000000 (silence) to 0x0000FFFF (maximum volume). The actual granularity and quantization of volume settings in this range are service-provider specific.


phoneInitialize

[New - Windows 95]

LONG phoneInitialize(LPHPHONEAPP lphPhoneApp, HINSTANCE hInstance,
    PHONECALLBACK lpfnCallback, LPCSTR lpszAppName,

    LPDWORD lpdwNumDevs)

Initializes the application's use of TAPI for subsequent use of the phone functions in the Telephony API. It registers the application's specified notification mechanism and returns the number of phone devices that are available to the application.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

PHONEERR_INVALAPPNAME	PHONEERR_INIFILECORRUPT
PHONEERR_INVALPOINTER	PHONEERR_NOMEM
PHONEERR_OPERATIONFAILED	PHONEERR_REINIT
PHONEERR_RESOURCEUNAVAIL	PHONEERR_NODEVICE
PHONEERR_NODRIVER
lphPhoneApp

Specifies a pointer to a location that is filled with the application's usage handle for TAPI.

hInstance

Specifies the instance handle of the client application or DLL.

lpfnCallback

Specifies the address of a callback function to be invoked related to status and events on the phone device.

lpszAppName

Specifies a pointer to a NULL-terminated ASCII string that contains displayable characters. If this parameter is non-NULL, it contains an application-supplied name of the application. This name is provided in the PHONESTATUS structure to indicate, in a user-friendly way, which application is the current owner of the phone device. This information can be useful for logging and status reporting purposes. If lpszAppName is NULL, the application's file name will be used instead.

lpdwNumDevs

Specifies a pointer to DWORD-sized memory location. This location is loaded with the number of phone devices available to the application.

The application can refer to individual phone devices by using phone device IDs that range from zero to dwNumDevs minus one. An application should not assume that these phone devices are capable of anything beyond what is specified by the Assisted Telephony subset without first querying their device capabilities with the function phoneGetDevCaps.

Applications should not invoke phoneInitialize without subsequently opening a phone (at least for monitoring). If the application is not monitoring and not using any devices, it should call phoneShutdown so that memory resources allocated by TAPI can be released if unneeded, and TAPI itself can be unloaded from memory while not needed.

Another reason for performing a phoneShutdown is that if a user changes the device configuration (adds or removes a line or phone), there is no way for TAPI to notify an application that has a line or phone handle open at the time. Once a reconfiguration has taken place, causing a PHONESTATE_REINIT message to be sent, no applications can open a device until all applications have performed a phoneShutdown.

If any service provider fails to initialize properly, this function fails and returns the error indicated by the service provider.

If the LINEERR_INVALPARAM error value is returned, the specified hInstance parameter is invalid.


phoneCallbackFunc

[New - Windows 95]

VOID FAR PASCAL phoneCallbackFunc(HANDLE hDevice, DWORD dwMsg,
    DWORD dwCallbackInstance, DWORD dwParam1, DWORD dwParam2,
    DWORD dwParam3)

phoneCallbackFunc is a placeholder for the application-supplied function name.

hDevice

Specified a handle to a phone device associated with the callback.

dwMsg

Specifies a line or call device message.

dwCallbackInstance

Specifies callback instance data passed back to the application in the callback. This DWORD is not interpreted by TAPI.

dwParam1

Specifies a parameter for the message.

dwParam2

Specifies a parameter for the message.

dwParam3

Specifies a parameter for the message.

For more information about the parameters passed to this callback function, see "Messages" later in this chapter.

All callbacks occur in the application's context. The callback function must reside in a dynamic link library (DLL) or application module and be exported in the module-definition file.


phoneNegotiateAPIVersion

[New - Windows 95]

LONG phoneNegotiateAPIVersion(HPHONEAPP hPhoneApp, DWORD dwDeviceID,
    DWORD dwAPILowVersion, DWORD dwAPIHighVersion,
    LPDWORD lpdwAPIVersion, LPPHONEEXTENSIONID lpExtensionID)

Allows an application to negotiate an API version to use for the specified phone device.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

PHONEERR_INVALAPPHANDLE	PHONEERR_OPERATIONFAILED
PHONEERR_BADDEVICEID	PHONEERR_OPERATIONUNAVAIL
PHONEERR_NODRIVER	PHONEERR_NOMEM
PHONEERR_INVALPOINTER	PHONEERR_RESOURCEUNAVAIL
PHONEERR_INCOMPATIBLEAPIVERSION	PHONEERR_UNINITIALIZED
PHONEERR_NODEVICE
hPhoneApp

Specifies the handle to the application's registration with TAPI.

dwDeviceID

Specifies the phone device to be queried.

dwAPILowVersion

Specifies the least recent API version the application is compliant with. The high-order word is the major version number, the low-order word is the minor version number.

dwAPIHighVersion

Specifies the most recent API version the application is compliant with. The high-order word is the major version number, the low-order word is the minor version number.

lpdwAPIVersion

Specifies a pointer to a DWORD-sized location that contains the API version number that was negotiated. If negotiation is successful, this number will be in the range dwAPILowVersion and dwAPIHighVersion.

lpExtensionID

Specifies a pointer to a structure of type PHONEEXTENSIONID. If the service provider for the specified dwDeviceID supports provider-specific extensions, this structure is filled with the extension ID of these extensions when negotiation is successful. This structure contains all zeros if the line provides no extensions. An application can ignore the returned parameter if it does not use extensions.

phoneNegotiateAPIVersion is used to negotiate the API version number to use with the specified phone device. It returns the extension ID supported by the phone device; zeros if no extensions are provided.

If the application wants to use the extensions defined by the returned Extension ID, it must call phoneNegotiateExtVersion to negotiate the extension version to use.

Use phoneInitialize to determine the number of phone devices present in the system. The device ID specified by dwDeviceID varies from zero to one less than the number of phone devices present.

The API version number negotiated is that under which TAPI can operate. If version ranges do not overlap, the application, API, or service-provider versions are incompatible and an error is returned.


phoneNegotiateExtVersion

[New - Windows 95]

LONG phoneNegotiateExtVersion(HPHONEAPP hPhoneApp, DWORD dwDeviceID,
    DWORD dwAPIVersion, DWORD dwExtLowVersion, DWORD dwExtHighVersion,
    LPDWORD lpdwExtVersion)

Allows an application to negotiate an extension version to use with the specified phone device. This operation need not be called if the application does not support extensions.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

PHONEERR_INVALAPPHANDLE	PHONEERR_OPERATIONFAILED
PHONEERR_BADDEVICEID	PHONEERR_OPERATIONUNAVAIL
PHONEERR_NODRIVER	PHONEERR_NOMEM
PHONEERR_INCOMPATIBLEAPIVERSION	PHONEERR_RESOURCEUNAVAIL
PHONEERR_INCOMPATIBLEEXTVERSION	PHONEERR_UNINITIALIZED
PHONEERR_INVALPOINTER	PHONEERR_NODEVICE
hPhoneApp

Specifies the handle to the application's registration with TAPI.

dwDeviceID

Specifies the phone device to be queried.

dwAPIVersion

Specifies the API version number that was negotiated for the specified phone device using phoneNegotiateAPIVersion.

dwExtLowVersion

Specifies the least recent extension version of the Extension ID returned by phoneNegotiateAPIVersion that the application is compliant with. The high-order word is the major version number; the low-order word is the minor version number.

dwExtHighVersion

Specifies the most recent extension version of the Extension ID returned by phoneNegotiateAPIVersion that the application is compliant with. The high-order word is the major version number; the low-order word is the minor version number.

lpdwExtVersion

Specifies a pointer to a DWORD-sized location that contains the extension version number that was negotiated. If negotiation is successful, this number will be in the range dwExtLowVersion and dwExtHighVersion.

The function phoneNegotiateAPIVersion is used to negotiate the API version number to use. It returns the extension ID supported by the phone device, or zeros if no extensions are provided.

If the application wants to use the extensions defined by the returned Extension ID, it must call phoneNegotiateExtVersion to negotiate the extension version to use.

Use phoneInitialize to determine the number of phone devices present in the system. The device ID specified by dwDeviceID varies from zero to one less than the number of phone devices present.

The extension version number negotiated is that under which the application and service provider must both operate. If version ranges do not overlap, the application and service-provider versions are incompatible and an error is returned.


phoneOpen

[New - Windows 95]

LONG phoneOpen(HPHONEAPP hPhoneApp, DWORD dwDeviceID, LPHPHONE lphPhone,
    DWORD dwAPIVersion, DWORD dwExtVersion, DWORD dwCallbackInstance,
    DWORD dwPrivilege)

Opens the specified phone device. A phone device can be opened using either owner privilege or monitor privilege. An application that opens the phone with owner privilege can control the phone's lamps, display, ringer, and hookswitch(es). An application that opens the phone device with monitor privilege is notified only about events that occur at the phone, such as hookswitch changes or button presses, in messages sent to its window or callback. Ownership of a phone device is exclusive. In other words, only one application can have a phone device opened with owner privilege at a time. The phone device can, however, be opened multiple times with monitor privilege.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

PHONEERR_ALLOCATED	PHONEERR_NODRIVER
PHONEERR_BADDEVICEID	PHONEERR_NOMEM
PHONEERR_INCOMPATIBLEAPIVERSION	PHONEERR_OPERATIONFAILED
PHONEERR_INCOMPATIBLEEXTVERSION	PHONEERR_OPERATIONUNAVAIL
PHONEERR_INVALAPPHANDLE	PHONEERR_RESOURCEUNAVAIL
PHONEERR_INVALPOINTER	PHONEERR_UNINITIALIZED
PHONEERR_INVALPRIVILEGE	PHONEERR_REINIT
PHONEERR_INUSE	PHONEERR_NODEVICE
PHONEERR_INIFILECORRUPT
hPhoneApp

Specifies a handle to the application's registration with TAPI.

dwDeviceID

Identifies the phone device to be opened.

lphPhone

Specifies a pointer to an HPHONE handle, which identifies the open phone device. Use this handle to identify the device when invoking other phone control functions.

dwAPIVersion

Specifies the API version number under which the application and Telephony API have agreed to operate. This number is obtained from phoneNegotiationAPIVersion.

dwExtVersion

Specifies the extension version number under which the application and the service provider agree to operate. This number is zero if the application does not use any extensions. This number is obtained from phoneNegotiateExtVersion.

dwCallbackInstance

Specifies user instance data passed back to the application's callback. This parameter is not interpreted by the Telephony API.

dwPrivilege

Specifies the privilege requested. The dwPrivilege parameter can have only one bit set. This parameter uses the following PHONEPRIVILEGE_ constants:

PHONEPRIVILEGE_MONITOR

An application that opens a phone device with this privilege is informed about events and state changes occurring on the phone. The application cannot invoke any operations on the phone device that would change its state.

PHONEPRIVILEGE_OWNER

An application that opens a phone device in this mode is allowed to change the state of the lamps, ringer, display, and hookswitch devices of the phone. Having owner privilege to a phone device automatically includes monitor privilege as well.

When opening a phone device with monitor privileges, the application is sent messages when events occur that change the status of the phone. Messages sent to the application include PHONE_BUTTON and PHONE_STATE. The latter provides an indication of the phone's status item that has changed.

When opening a phone with owner privilege, the phone device can be manipulated in ways that affect the state of the phone device. An application should only open a phone using owner privilege if it actively wants to manipulate the phone device, and it should close the phone device when done to allow other applications to control the phone.

When an application opens a phone device, it must specify the negotiated API version and, if it wants to use the phone's extensions, the phone's device-specific extension version. This version numbers should have been obtained with the function phoneNegotiateAPIVersion and phoneNegotiateExtVersion. Version numbering allows the mix and match of different application versions with different API versions and service-provider versions.


phoneSetButtonInfo

[New - Windows 95]

LONG phoneSetButtonInfo(HPHONE hPhone, DWORD dwButtonLampID,
    LPPHONEBUTTONINFO const lpButtonInfo)

Sets information about the specified button on the specified phone.

•	Returns a positive request ID if the function will be completed asynchronously or a negative error number if an error has occurred. The dwParam2 parameter of the corresponding PHONE_REPLY callback message is zero if the function is successful or it is a negative error number if an error has occurred. Possible return values are:

PHONEERR_INVALBUTTONLAMPID	PHONEERR_OPERATIONFAILED
PHONEERR_INVALPHONEHANDLE	PHONEERR_STRUCTURETOOSMALL
PHONEERR_INVALPOINTER	PHONEERR_UNINITIALIZED
PHONEERR_NOTOWNER	PHONEERR_NOMEM
PHONEERR_OPERATIONUNAVAIL	PHONEERR_RESOURCEUNAVAIL
hPhone

Specifies a handle to the open phone device. The application must be the owner of the phone device.

dwButtonLampID

Specifies a button on the phone device.

lpButtonInfo

Specifies a pointer to a variably sized structure of type PHONEBUTTONINFO. This data structure describes the mode, the function, and provides additional descriptive text about the button.


phoneSetData

[New - Windows 95]

LONG phoneSetData(HPHONE hPhone, DWORD dwDataID, LPVOID const lpData,
    DWORD dwSize)

Downloads the information in the specified buffer to the opened phone device at the selected data ID.

•	Returns a positive request ID if the function will be completed asynchronously or a negative error number if an error has occurred. The dwParam2 parameter of the corresponding PHONE_REPLY callback message is zero if the function is successful or it is a negative error number if an error has occurred. Possible return values are:

PHONEERR_INVALPHONEHANDLE	PHONEERR_OPERATIONUNAVAIL
PHONEERR_NOTOWNER	PHONEERR_NOMEM
PHONEERR_INVALDATAID	PHONEERR_RESOURCEUNAVAIL
PHONEERR_INVALPHONESTATE	PHONEERR_OPERATIONFAILED
PHONEERR_INVALPOINTER	PHONEERR_UNINITIALIZED
hPhone

Specifies a handle to the open phone device. The application must be the owner of the phone.

dwDataID

Specifies where in the phone device the buffer is to be downloaded.

lpData

Specifies a pointer to the memory location where the data is to be downloaded from.

dwSize

Specifies the size of the buffer in bytes.

The function downloads a maximum of dwSize bytes from lpData to the phone device. The format of the data, its meaning to the phone device, and the meaning of the data ID are service-provider specific. The data in the buffer or the selection of a data ID may act as commands to the phone device.


phoneSetDisplay

[New - Windows 95]

LONG phoneSetDisplay(HPHONE hPhone, DWORD dwRow, DWORD dwColumn,
    LPCSTR lpsDisplay, DWORD dwSize)

Causes the specified string to be displayed on the specified open phone device.

•	Returns a positive request ID if the function will be completed asynchronously or a negative error number if an error has occurred. The dwParam2 parameter of the corresponding PHONE_REPLY callback message is zero if the function is successful or it is a negative error number if an error has occurred. Possible return values are:

PHONEERR_INVALPHONEHANDLE	PHONEERR_OPERATIONUNAVAIL
PHONEERR_NOTOWNER	PHONEERR_OPERATIONFAILED
PHONEERR_INVALPHONESTATE	PHONEERR_UNINITIALIZED
PHONEERR_INVALPOINTER	PHONEERR_NOMEM
PHONEERR_INVALPARAM	PHONEERR_RESOURCEUNAVAIL
hPhone

Specifies a handle to the open phone device. The application must be the owner of the phone.

dwRow

Specifies the row on the display where the new text is to be displayed.

dwColumn

Specifies the column position on the display where the new text is to be displayed.

lpsDisplay

Specifies a pointer to the memory location where the display content is stored. The display information must have the format specified in the dwStringFormat field of the phone's device capabilities.

dwSize

Specifies the size in bytes of the information pointed to by lpsDisplay.

The specified display information is written to the phone's display, starting at the specified positions. This operation overwrites previously displayed information. If the amount of information exceeds the size of the display, the information will be truncated. The amount of information that can be displayed is at most (dwNumRows * dwNumColumns) elements in size. dwNumRows and dwNumColumns are available in the PHONECAPS structure, which is returned by phoneGetDevCaps; they are zero-based.


phoneSetGain

[New - Windows 95]

LONG phoneSetGain(HPHONE hPhone, DWORD dwHookSwitchDev, DWORD dwGain)

Sets the gain of the microphone of the specified hookswitch device to the specified gain level.

•	Returns a positive request ID if the function will be completed asynchronously or a negative error number if an error has occurred. The dwParam2 parameter of the corresponding PHONE_REPLY callback message is zero if the function is successful or it is a negative error number if an error has occurred. Possible return values are:

PHONEERR_INVALPHONEHANDLE	PHONEERR_NOMEM
PHONEERR_NOTOWNER	PHONEERR_RESOURCEUNAVAIL
PHONEERR_INVALPHONESTATE	PHONEERR_OPERATIONFAILED
PHONEERR_INVALHOOKSWITCHDEV	PHONEERR_UNINITIALIZED
PHONEERR_OPERATIONUNAVAIL
hPhone

Specifies a handle to the open phone device. The application must be the owner of the phone.

dwHookSwitchDev

Identifies the hookswitch device whose microphone's gain is to be set. The dwHookswitchDev parameter can only have a single bit set. This parameter uses the following PHONEHOOKSWITCHDEV_ constants:

PHONEHOOKSWITCHDEV_HANDSET

This is the phone's handset.

PHONEHOOKSWITCHDEV_SPEAKER

This is the phone's speakerphone or adjunct.

PHONEHOOKSWITCHDEV_HEADSET

This is the phone's headset.

dwGain

Specifies a pointer to a DWORD-sized location containing the current gain setting of the device. dwGain specifies the gain level of the hookswitch device. This is a number in the range 0x00000000 (silence) to 0x0000FFFF (maximum volume). The actual granularity and quantization of gain settings in this range are service-provider specific. A value for dwGain that is out of range is set to the nearest value in the range.


phoneSetHookSwitch

[New - Windows 95]

LONG phoneSetHookSwitch(HPHONE hPhone, DWORD dwHookSwitchDevs,
    DWORD dwHookSwitchMode)

Sets the hook state of the specified open phone's hookswitch devices to the specified mode. Only the hookswitch state of the hookswitch devices listed is affected.

•	Returns a positive request ID if the function will be completed asynchronously or a negative error number if an error has occurred. The dwParam2 parameter of the corresponding PHONE_REPLY callback message is zero if the function is successful or it is a negative error number if an error has occurred. Possible return values are:

PHONEERR_INVALPHONEHANDLE	PHONEERR_OPERATIONUNAVAIL
PHONEERR_NOTOWNER	PHONEERR_NOMEM
PHONEERR_INVALHOOKSWITCHDEV	PHONEERR_RESOURCEUNAVAIL
PHONEERR_INVALHOOKSWITCHMODE	PHONEERR_OPERATIONFAILED
PHONEERR_INVALPHONESTATE	PHONEERR_UNINITIALIZED
hPhone

Specifies a handle to the open phone device. The application must be the owner of the phone.

dwHookSwitchDevs

Specifies the device(s) whose hookswitch mode is to be set. This parameter uses the following PHONEHOOKSWITCHDEV_ constants:

PHONEHOOKSWITCHDEV_HANDSET

This is the phone's handset.

PHONEHOOKSWITCHDEV_SPEAKER

This is the phone's speakerphone or adjunct.

PHONEHOOKSWITCHDEV_HEADSET

This is the phone's headset.

dwHookSwitchMode

Specifies the hookswitch mode to set. The dwHookSwitchMode parameter can have only a single bit set. This parameter uses the following PHONEHOOKSWITCHMODE_ constants:

PHONEHOOKSWITCHMODE_ONHOOK

The device's microphone and speaker are both onhook.

PHONEHOOKSWITCHMODE_MIC

The device's microphone is active, the speaker is mute.

PHONEHOOKSWITCHMODE_SPEAKER

The device's speaker is active, the microphone is mute.

PHONEHOOKSWITCHMODE_MICSPEAKER

The device's microphone and speaker are both active.

The hookswitch mode is the same for all devices specified. If different settings are desired, this function can be invoked multiple times with a different set of parameters. A PHONE_STATE message is sent to the application after the hookswitch state has changed.


phoneSetLamp

[New - Windows 95]

LONG phoneSetLamp(HPHONE hPhone, DWORD dwButtonLampID, DWORD dwLampMode)

Causes the specified lamp to be lit on the specified open phone device in the specified lamp mode.

•	Returns a positive request ID if the function will be completed asynchronously or a negative error number if an error has occurred. The dwParam2 parameter of the corresponding PHONE_REPLY callback message is zero if the function is successful or it is a negative error number if an error has occurred. Possible return values are:

PHONEERR_INVALPHONEHANDLE	PHONEERR_OPERATIONUNAVAIL
PHONEERR_NOTOWNER	PHONEERR_NOMEM
PHONEERR_INVALBUTTONLAMPID	PHONEERR_RESOURCEUNAVAIL
PHONEERR_INVALPHONESTATE	PHONEERR_OPERATIONFAILED
PHONEERR_INVALLAMPMODE	PHONEERR_UNINITIALIZED
hPhone

Specifies a handle to the open phone device. The application must be the owner of the phone.

dwButtonLampID

Identifies the button whose lamp is to be lit.

dwLampMode

Specifies how the lamp is to be lit. The dwLampMode parameter can have only a single bit set. This parameter uses the following PHONELAMPMODE_ constants:

PHONELAMPMODE_BROKENFLUTTER

Broken flutter is the superposition of flash and flutter.

PHONELAMPMODE_FLASH

Flash means slow on and off.

PHONELAMPMODE_FLUTTER

Flutter means fast on and off.

PHONELAMPMODE_OFF

The lamp is off.

PHONELAMPMODE_STEADY

The lamp is continuously lit.

PHONELAMPMODE_WINK

The lamp is winking.

PHONELAMPMODE_DUMMY

This value is used to describe a button/lamp position that has no corresponding lamp.


phoneSetRing

[New - Windows 95]

LONG phoneSetRing(HPHONE hPhone, DWORD dwRingMode, DWORD dwVolume)

Rings the specified open phone device using the specified ring mode and volume.

•	Returns a positive request ID if the function will be completed asynchronously or a negative error number if an error has occurred. The dwParam2 parameter of the corresponding PHONE_REPLY callback message is zero if the function is successful or it is a negative error number if an error has occurred. Possible return values are:

PHONEERR_INVALPHONEHANDLE	PHONEERR_NOMEM
PHONEERR_NOTOWNER	PHONEERR_RESOURCEUNAVAIL
PHONEERR_INVALPHONESTATE	PHONEERR_OPERATIONFAILED
PHONEERR_INVALRINGMODE	PHONEERR_UNINITIALIZED
PHONEERR_OPERATIONUNAVAIL
hPhone

Specifies a handle to the open phone device. The application must be the owner of the phone device.

dwRingMode

Specifies the ringing pattern with which to ring the phone. This parameter must be within the range of 0 to the value of the dwNumRingModes field in the PHONECAPS structure. If dwNumRingModes is 0, the ring mode of the phone cannot be controlled; if dwNumRingModes is 1, a value of 0 for dwRingMode indicates that the phone should not be rung (silence), and other values from 1 to dwNumRingModes are valid ring modes for the phone device.

dwVolume

Specifies the volume level with which the phone is ringing. This is a number in the range 0x00000000 (silence) to 0x0000FFFF (maximum volume). The actual granularity and quantization of volume settings in this range are service-provider specific. A value for dwVolume that is out of range is set to the nearest value in the range.

The service provider defines the actual audible ringing patterns corresponding to each of the phone's ring modes.


phoneSetStatusMessages

[New - Windows 95]

LONG phoneSetStatusMessages(HPHONE hPhone, DWORD dwPhoneStates,
    DWORD dwButtonModes, DWORD dwButtonStates)

Enables an application to monitor the specified phone device for selected status events.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

PHONEERR_INVALPHONEHANDLE	PHONEERR_NOMEM
PHONEERR_INVALPHONESTATE	PHONEERR_RESOURCEUNAVAIL
PHONEERR_INVALBUTTONMODE	PHONEERR_OPERATIONFAILED
PHONEERR_INVALBUTTONSTATE	PHONEERR_UNINITIALIZED
PHONEERR_OPERATIONUNAVAIL
hPhone

Specifies a handle to the open phone device to be monitored.

dwPhoneStates

These flags specify the set of phone status changes and events for which the application wishes to receive notification messages. This parameter can have zero, one, or more bits set. This parameter uses the following PHONESTATE_ constants:

PHONESTATE_OTHER

Phone-status items other than those listed below have changed. The application should check the current phone status to determine which items have changed.

PHONESTATE_CONNECTED

The connection between the phone device and TAPI was just made. This happens when TAPI is first invoked or when the wire connecting the phone to the PC is plugged in while TAPI is active.

PHONESTATE_DISCONNECTED

The connection between the phone device and TAPI was just broken. This happens when the wire connecting the phone set to the PC is unplugged while TAPI is active.

PHONESTATE_OWNER

The number of owners for the phone device has changed.

PHONESTATE_MONITORS

The number of monitors for the phone device has changed.

PHONESTATE_DISPLAY

The display of the phone has changed.

PHONESTATE_LAMP

A lamp of the phone has changed.

PHONESTATE_RINGMODE

The ring mode of the phone has changed.

PHONESTATE_RINGVOLUME

The ring volume of the phone has changed.

PHONESTATE_HANDSETHOOKSWITCH

The handset hookswitch state has changed.

PHONESTATE_HANDSETVOLUME

The handset's speaker volume setting has changed.

PHONESTATE_HANDSETGAIN

The handset's microphone gain setting has changed.

PHONESTATE_SPEAKERHOOKSWITCH

The speakerphone's hookswitch state has changed.

PHONESTATE_SPEAKERVOLUME

The speakerphone's speaker volume setting has changed.

PHONESTATE_SPEAKERGAIN

The speakerphone's microphone gain setting state has changed.

PHONESTATE_HEADSETHOOKSWITCH

The headset's hookswitch state has changed.

PHONESTATE_HEADSETVOLUME

The headset's speaker volume setting has changed.

PHONESTATE_HEADSETGAIN

The headset's microphone gain setting has changed.

PHONESTATE_SUSPEND

The application's use of the phone is temporarily suspended.

PHONESTATE_RESUME

The application's use of the phone device is resumed after having been suspended for some time.

PHONESTATE_DEVSPECIFIC

The phone's device-specific information has changed.

PHONESTATE_REINIT

Items have changed in the configuration of phone devices. To become aware of these changes (as with the appearance of new phone devices) the application should reinitialize its use of TAPI. New phoneInitialize and phoneOpen requests are denied until applications have shut down their usage of TAPI. The hDevice parameter of the PHONE_STATE message is left NULL for this state change, since it applies to any of the lines in the system. Because of the critical nature of PHONESTATE_REINIT, such messages cannot be masked, so the setting of this bit is ignored and the messages are always delivered to the application.

PHONESTATE_CAPSCHANGE

Indicates that, due to configuration changes made by the user or other circumstances, one or more of the fields in the PHONECAPS structure have changed. The application should use phoneGetDevCaps to read the updated structure. If a service provider sends a PHONE_STATE message containing this value to TAPI, TAPI will pass it along to applications which have negotiated this or a subsequent API version; applications negotiating a previous API version will receive PHONE_STATE messages specifying PHONESTATE_REINIT, requiring them to shutdown and reinitialize their connection to TAPI in order to obtain the updated information.

PHONESTATE_REMOVED

Indicates that the device is being removed from the system by the service provider (most likely through user action, via a control panel or similar utility). A PHONE_STATE message with this value will normally be immediately followed by a PHONE_CLOSE message on the device. Subsequent attempts to access the device prior to TAPI being reinitialized will result in PHONEERR_NODEVICE being returned to the application. If a service provider sends a PHONE_STATE message containing this value to TAPI, TAPI will pass it along to applications which have negotiated this or a subsequent API version; applications negotiating a previous API version will not receive any notification.

dwButtonModes

These flags specify the set of phone-button modes for which the application wishes to receive notification messages. This parameter can have zero, one, or more bits set. This parameter uses the following PHONEBUTTONMODE_ constants:

PHONEBUTTONMODE_CALL

The button is assigned to a call appearance.

PHONEBUTTONMODE_FEATURE

The button is assigned to requesting features from the switch, such as hold, conference, and transfer.

PHONEBUTTONMODE_KEYPAD

The button is one of the twelve keypad buttons, '0' through '9', '*', and '#'.

PHONEBUTTONMODE_LOCAL

The button is a local function button, such as mute or volume control.

PHONEBUTTONMODE_DISPLAY

The button is a "soft" button associated with the phone's display. A phone set can have zero or more display buttons.

dwButtonStates

These flags specify the set of phone-button state changes for which the application wishes to receive notification messages. If the dwButtonModes parameter is 0, dwButtonStates is ignored. If dwButtonModes has one or more bits set, this parameter must also have at least one bit set. This parameter uses the following PHONEBUTTONSTATE_ constants:

PHONEBUTTONSTATE_UP

The button is in the "up" state.

PHONEBUTTONSTATE_DOWN

The button is in the "down" state (pressed down).

PHONEBUTTONSTATE_UNKNOWN

Indicates that the up or down state of the button is not known at this time, but may become known at a future time.

PHONEBUTTONSTATE_UNAVAIL

Indicates that the up or down state of the button is not known to the service provider, and will not become known at a future time.

An application can use this function to enable or disable the generation of the corresponding messages. All phone status messages are disabled by default.


phoneSetVolume

[New - Windows 95]

LONG phoneSetVolume(HPHONE hPhone, DWORD dwHookSwitchDev,
    DWORD dwVolume)

Sets the volume of the speaker component of the specified hookswitch device to the specified level.

•	Returns a positive request ID if the function will be completed asynchronously or a negative error number if an error has occurred. The dwParam2 parameter of the corresponding PHONE_REPLY callback message is zero if the function is successful or it is a negative error number if an error has occurred. Possible return values are:

PHONEERR_INVALPHONEHANDLE	PHONEERR_NOMEM
PHONEERR_NOTOWNER	PHONEERR_RESOURCEUNAVAIL
PHONEERR_INVALPHONESTATE	PHONEERR_OPERATIONFAILED
PHONEERR_INVALHOOKSWITCHDEV	PHONEERR_UNINITIALIZED
PHONEERR_OPERATIONUNAVAIL
hPhone

Specifies a handle to the open phone device. The application must be the owner of the phone.

dwHookSwitchDev

Identifies the hookswitch device whose speaker's volume is to be set.

PHONEHOOKSWITCHDEV_HANDSET

This is the phone's handset.

PHONEHOOKSWITCHDEV_SPEAKER

This is the phone's speakerphone or adjunct.

PHONEHOOKSWITCHDEV_HEADSET

This is the phone's headset.

dwVolume

Specifies the current volume setting of the device. dwVolume specifies the volume level of the hookswitch device. This is a number in the range 0x00000000 (silence) to 0x0000FFFF (maximum volume). The actual granularity and quantization of volume settings in this range are service-provider specific. A value for dwVolume that is out of range is set to the nearest value in the range.


phoneShutdown

[New - Windows 95]

LONG phoneShutdown(HPHONEAPP hPhoneApp)

Shuts down the application's usage of TAPI's phone abstraction.

•	Returns zero if the request is successful or a negative error number if an error has occurred. Possible return values are:

PHONEERR_INVALAPPHANDLE	PHONEERR_NOMEM
PHONEERR_UNINITIALIZED	PHONEERR_RESOURCEUNAVAIL
hPhoneApp

Specifies the application's usage handle for TAPI.

If this function is called when the application has open phone devices. These devices will be closed.


Messages

Following are the TAPI phone messages.


PHONE_BUTTON

[New - Windows 95]

PHONE_BUTTON
hPhone = (HPHONE) hPhoneDevice;
dwCallbackInstance = (DWORD) hCallback;
dwParam1 = (DWORD) idButtonOrLamp;
dwParam2 = (DWORD) ButtonMode;
dwParam3 = (DWORD) ButtonState;

Sent to notify the application that button press monitoring is enabled if it has detected a button press on the local phone.

•	No return value.

hPhone

Specifies a handle to the phone device.

dwCallbackInstance

Specifies the application's callback instance provided when opening the phone device.

dwParam1

Specifies the button/lamp ID of the button that was pressed. Note that button IDs 0 through 11 are always the KEYPAD buttons, with '0' being button ID 0, '1' being button ID 1 (and so on through button ID 9), and with '*' being button ID 10, and '#' being button ID 11. Additional information about a button ID is available with phoneGetDevCaps and phoneGetButtonInfo.

dwParam2

Specifies the button mode of the button. This parameter uses the following PHONEBUTTONMODE_ constants:

PHONEBUTTONMODE_CALL

The button is assigned to a call appearance.

PHONEBUTTONMODE_FEATURE

The button is assigned to requesting features from the switch, such as hold, conference, and transfer.

PHONEBUTTONMODE_KEYPAD

The button is one of the twelve keypad buttons, '0' through '9', '*', and '#'.

PHONEBUTTONMODE_LOCAL

The button is a local function button, such as mute or volume control.

PHONEBUTTONMODE_DISPLAY

The button is a "soft" button associated with the phone's display. A phone set can have zero or more display buttons.

dwParam3

Specifies whether this is a button-down event or a button-up event. This parameter uses the following PHONEBUTTONSTATE_ constants:

PHONEBUTTONSTATE_UP

The button is in the "up" state.

PHONEBUTTONSTATE_DOWN

The button is in the "down" state (pressed down).

PHONEBUTTONSTATE_UNKNOWN

Indicates that the up or down state of the button is not known at this time, but may become known at a future time.

PHONEBUTTONSTATE_UNAVAIL

Indicates that the up or down state of the button is not known to the service provider, and will not become known at a future time.

A PHONE_BUTTON message is sent whenever a button changes state. An application is guaranteed that for each button down event, it will eventually be sent a corresponding button up event. Note that a service provider that is incapable of detecting the actual button up is required to generate the button up message shortly after the button down message for each button press.


PHONE_CLOSE

[New - Windows 95]

PHONE_CLOSE
hPhone = (HPHONE) hPhoneDevice;
dwCallbackInstance = (DWORD) hCallback;
dwParam1 = (DWORD) 0;
dwParam2 = (DWORD) 0;
dwParam3 = (DWORD) 0;

Sent when an open phone device has been forcibly closed as part of resource reclamation. The device handle is no longer valid once this message has been sent.

•	No return value.

hPhone

Specifies a handle to the open phone device that was closed. The handle is no longer valid after this message has been sent

dwCallbackInstance

Specifies the application's callback instance provided when opening the phone device.

dwParam1

Unused.

dwParam2

Unused.

dwParam3

Unused.

This message is only sent to an application after an open phone has been forcibly closed. This may be done to prevent a single application from monopolizing a phone device for too long. Whether the phone can be reopened immediately after a forced close is device-specific.

An open phone device may also be forcibly closed after the user has modified the configuration of that phone or its driver. If the user wants the configuration changes to be effective immediately (as opposed to after the next system restart), and these changes affect the application's current view of the device (such as a change in device capabilities), then a service provider may forcibly close the phone device.


PHONE_CREATE

[New - Windows 95]

PHONE_CREATE
hPhone = (HPHONE) hPhoneDev;
dwCallbackInstance = (DWORD) 0;
dwParam1 = (DWORD) idDevice;
dwParam2 = (DWORD) 0;
dwParam3 = (DWORD) 0;

Set to inform applications of the creation of a new phone device.

•	No return value.

hPhone

Unused.

dwCallbackInstance

Unused.

dwParam1

Specifies the dwDeviceID of the newly-created device.

dwParam2

Unused.

dwParam3

Unused.

Older applications (which negotiated an API version prior to the creation of this feature) are sent a PHONE_STATE message specifying PHONESTATE_REINIT, which requires them to shut down their use of the API and call phoneInitialize again to obtain the new number of devices. Unlike previous versions of TAPI, however, this version does not require all applications to shut down before allowing applications to reinitialize; reinitialization can take place immediately when a new device is created (complete shutdown is still required when a service provider is removed from the system).

Applications supporting this and subsequent versions of the API are sent a PHONE_CREATE message. This informs them of the existence of the new device and its new device ID. The application can then choose whether or not to attempt working with the new device at its leisure. This message will be sent to all applications supporting this or subsequent versions of the API which have called phoneInitialize, including those that do not have any line devices open at the time.


PHONE_DEVSPECIFIC

[New - Windows 95]

PHONE_DEVSPECIFIC
hPhone = (HPHONE) hPhoneDevice;
dwCallbackInstance = (DWORD) hCallback;
dwParam1 = (DWORD) DeviceSpecific1;
dwParam2 = (DWORD) DeviceSpecific2;
dwParam3 = (DWORD) DeviceSpecific3;

The implementation sends this message to an application's callback to notify the application about device-specific events occurring at the phone. The meaning of the message and the interpretation of the parameters is implementation-defined.

•	No return value.

hPhone

Specifies a handle to the phone device.

dwCallbackInstance

Specifies the application's callback instance provided when opening the phone device.

dwParam1

Device specific.

dwParam2

Device specific.

dwParam3

Device specific.


PHONE_REPLY

[New - Windows 95]

PHONE_REPLY
hPhone = (HPHONE) 0;
dwCallbackInstance = (DWORD) hCallback;
dwParam1 = (DWORD) idRequest;
dwParam2 = (DWORD) Status;
dwParam3 = (DWORD) 0;

This message is sent to an application's callback to report the results of function call that completed asynchronously.

•	No return value.

hDevice

Unused.

dwCallbackInstance

Returns the application's callback instance.

dwParam1

Specifies the request ID for which this is the reply.

dwParam2

Specifies the success or error indication. The application should cast this parameter into a LONG. Zero indicates success; a negative number indicates an error.

dwParam3

Unused.

Functions that operate asynchronously return a positive request ID value to the application. This request ID is returned with the reply message to identify the request that was completed. The other parameter for this message carries the success or failure indication. Possible errors are the same as those defined by the corresponding function. This message cannot be disabled.


PHONE_STATE

[New - Windows 95]

PHONE_STATE
hPhone = (HPHONE) hPhoneDevice;
dwCallbackInstance = (DWORD) hCallback;
dwParam1 = (DWORD) PhoneState;
dwParam2 = (DWORD) PhoneStateDetails;
dwParam3 = (DWORD) 0;

The service provider sends this message to an application's callback function whenever the status of a phone device changes.

•	No return value.

hPhone

Specifies a handle to the phone device.

dwCallbackInstance

Specifies the application's callback instance provided when opening the phone device.

dwParam1

Specifies the phone state that has changed. This parameter uses the following PHONESTATE_ constants:

PHONESTATE_OTHER

Phone-status items other than those listed below have changed. The application should check the current phone status to determine which items have changed.

PHONESTATE_CONNECTED

The connection between the phone device and TAPI was just made. This happens when TAPI is first invoked or when the wire connecting the phone to the computer is plugged in with TAPI active.

PHONESTATE_DISCONNECTED

The connection between the phone device and TAPI was just broken. This happens when the wire connecting the phone set to the computer is unplugged while TAPI is active.

PHONESTATE_OWNER

The number of owners for the phone device has changed.

PHONESTATE_MONITORS

The number of monitors for the phone device has changed.

PHONESTATE_DISPLAY

The display of the phone has changed.

PHONESTATE_LAMP

A lamp of the phone has changed.

PHONESTATE_RINGMODE

The ring mode of the phone has changed.

PHONESTATE_RINGVOLUME

The ring volume of the phone has changed.

PHONESTATE_HANDSETHOOKSWITCH

The handset hookswitch state has changed.

PHONESTATE_HANDSETVOLUME

The handset's speaker volume setting has changed.

PHONESTATE_HANDSETGAIN

The handset's microphone gain setting has changed.

PHONESTATE_SPEAKERHOOKSWITCH

The speakerphone's hookswitch state has changed.

PHONESTATE_SPEAKERVOLUME

The speakerphone's speaker volume setting has changed.

PHONESTATE_SPEAKERGAIN

The speakerphone's microphone gain setting state has changed.

PHONESTATE_HEADSETHOOKSWITCH

The headset's hookswitch state has changed.

PHONESTATE_HEADSETVOLUME

The headset's speaker volume setting has changed.

PHONESTATE_HEADSETGAIN

The headset's microphone gain setting has changed.

PHONESTATE_SUSPEND

The application's use of the phone device is temporarily suspended.

PHONESTATE_RESUME

The application's use of the phone device is resumed after having been suspended for some time.

PHONESTATE_DEVSPECIFIC

The phone's device-specific information has changed.

PHONESTATE_REINIT

Items have changed in the configuration of phone devices. To become aware of these changes (as with the appearance of new phone devices), the application should reinitialize its use of TAPI. The hDevice parameter of the PHONE_STATE message is left NULL for this state change as it applies to any of the phones in the system. This message with the PHONESTATE_REINIT bit set is only sent to applications that have opened a phone; that is, if an application has only called phoneInitialize but not yet opened any device and a PHONESTATE_REINIT message is sent, then the message is not sent to that application.

PHONESTATE_CAPSCHANGE

Indicates that, due to configuration changes made by the user or other circumstances, one or more of the fields in the PHONECAPS structure have changed. The application should use phoneGetDevCaps to read the updated structure.

PHONESTATE_REMOVED

Indicates that the device is being removed from the system by the service provider (most likely through user action, via a control panel or similar utility). A PHONE_STATE message with this value will normally be immediately followed by a PHONE_CLOSE message on the device. Subsequent attempts to access the device prior to TAPI being reinitialized will result in PHONEERR_NODEVICE being returned to the application. If a service provider sends a PHONE_STATE message containing this value to TAPI, TAPI will pass it along to applications which have negotiated this or a subsequent API version; applications negotiating a previous API version will not receive any notification.

dwParam2

Specifies phone-state-dependent information detailing the status change. This field is not used if multiple flags are set in dwParam1, since multiple status items have changed. The application should invoke phoneGetStatus to obtain complete set of information.

If dwParam1 is PHONESTATE_OWNER, dwParam2 contains the new number of owners.

If dwParam1 is PHONESTATE_MONITORS, dwParam2 contains the new number of monitors.

If dwParam1 is PHONESTATE_LAMP, dwParam2 contains the button/lamp ID of the lamp that has changed.

If dwParam1 is PHONESTATE_RINGMODE, dwParam2 contains the new ring mode.

If dwParam1 is PHONESTATE_HANDSET, SPEAKER or HEADSET, dwParam2 contains the new hookswitch mode of that hookswitch device. This parameter uses the following PHONEHOOKSWITCHMODE_ constants:

PHONEHOOKSWITCHMODE_ONHOOK

The device's microphone and speaker are both onhook.

PHONEHOOKSWITCHMODE_MIC

The device's microphone is active, the speaker is mute.

PHONEHOOKSWITCHMODE_SPEAKER

The device's speaker is active, the microphone is mute.

PHONEHOOKSWITCHMODE_MICSPEAKER

The device's microphone and speaker are both active.

dwParam3

Unused.

Sending this message to the callback function can be controlled and queried using phoneSetStatusMessages and phoneGetStatusMessages. By default, this message is disabled for all state changes except for PHONESTATE_REINIT, which cannot be disabled. This message is sent to all applications that have a handle to the phone, including those that called phoneOpen with the dwPrivileges parameter set to PHONEPRIVILEGE_OWNER or PHONEPRIVILEGE_MONITOR.

A PHONE_STATE message with an Owners and/or Monitors indication is sent to applications that already have a handle for the phone. This can be the result of another application changing ownership or monitorship of the phone device with phoneOpen, phoneClose or phoneShutdown.


Structures

Following are the TAPI phone structures.


PHONEBUTTONINFO

[New - Windows 95]

typedef struct phonebuttoninfo_tag {
  DWORD  dwTotalSize;
  DWORD  dwNeededSize;
  DWORD  dwUsedSize;
  DWORD  dwButtonMode;
  DWORD  dwButtonFunction;
  DWORD  dwButtonTextSize;
  DWORD  dwButtonTextOffset;
  DWORD  dwDevSpecificSize;
  DWORD  dwDevSpecificOffset;
  DWORD  dwButtonState;
} PHONEBUTTONINFO, FAR *LPPHONEBUTTONINFO;

The PHONEBUTTONINFO structure contains information about a button on a phone device.

dwTotalSize

The total size in bytes allocated to this data structure.

dwNeededSize

The size in bytes for this data structure that is needed to hold all the returned information.

dwUsedSize

The size in bytes of the portion of this data structure that contains useful information.

dwButtonMode

Defines the mode or general usage class of the button. This parameter uses the following PHONEBUTTONMODE_ constants:

PHONEBUTTONMODE_DUMMY

This value is used to describe a button/lamp position that has no corresponding button but has only a lamp.

PHONEBUTTONMODE_CALL

The button is assigned to a call appearance.

PHONEBUTTONMODE_FEATURE

The button is assigned to requesting features from the switch, such as hold, conference, and transfer.

PHONEBUTTONMODE_KEYPAD

The button is one of the twelve keypad buttons, '0' through '9', '*', and '#'.

PHONEBUTTONMODE_LOCAL

The button is a local function button, such as mute or volume control.

PHONEBUTTONMODE_DISPLAY

The button is a "soft" button associated with the phone's display. A phone set can have zero or more display buttons.

dwButtonFunction

Specifies the function assigned to the button. This field uses the PHONEBUTTONFUNCTION_ constants.

dwButtonTextSize
dwButtonTextOffset

The size in bytes of the variably sized field containing descriptive text for this button., and the offset in bytes from the beginning of this data structure.  The format of this information is as specified in the dwStringFormat field of the phone's device capabilities.

dwDevSpecificSize
dwDevSpecificOffset

The size in bytes of the variably sized device-specific field, and the offset in bytes from the beginning of this data structure.

dwButtonState

For the phoneGetButtonInfo function, this field indicates the current state of the button, using the PHONEBUTTONSTATE_ constants. This field is ignored by the phoneSetButtonInfo function.

Device-specific extensions should use the DevSpecific (dwDevSpecificSize and dwDevSpecificOffset) variably sized area of this data structure.

Older applications will have been compiled without this field in the PHONEBUTTONINFO structure, and using a SIZEOF PHONEBUTTONINFO smaller than the new size. The application passes in a dwAPIVersion parameter with the phoneOpen function, which can be used for guidance by TAPI in handling this situation. If the application passes in a dwTotalSize less than the size of the fixed portion of the structure as defined in the dwAPIVersion specified, PHONEERR_STRUCTURETOOSMALL will be returned. If sufficient memory has been allocated by the application, before calling TSPI_phoneGetButtonInfo, TAPI will set the dwNeededSize and dwUsedSize fields to the fixed size of the structure as it existed in the specified API version.

New service providers (which support the new API version) must examine the API version passed in. If the API version is less than the highest version supported by the provider, the service provider must not fill in fields not supported in older API versions, as these would fall in the variable portion of the older structure.

New applications must be cognizant of the API version negotiated, and not examine the contents of fields in the fixed portion beyond the original end of the fixed portion of the structure for the negotiated API version.


PHONECAPS

[New - Windows 95]

typedef struct phonecaps_tag {
  DWORD  dwTotalSize;
  DWORD  dwNeededSize;
  DWORD  dwUsedSize;
  DWORD  dwProviderInfoSize;
  DWORD  dwProviderInfoOffset;
  DWORD  dwPhoneInfoSize;
  DWORD  dwPhoneInfoOffset;
  DWORD  dwPermanentPhoneID;
  DWORD  dwPhoneNameSize;
  DWORD  dwPhoneNameOffset;
  DWORD  dwStringFormat;
  DWORD  dwPhoneStates;
  DWORD  dwHookSwitchDevs;
  DWORD  dwHandsetHookSwitchModes;
  DWORD  dwSpeakerHookSwitchModes;
  DWORD  dwHeadsetHookSwitchModes;
  DWORD  dwVolumeFlags;
  DWORD  dwGainFlags;
  DWORD  dwDisplayNumRows;
  DWORD  dwDisplayNumColumns;
  DWORD  dwNumRingModes;
  DWORD  dwNumButtonLamps;
  DWORD  dwButtonModesSize;
  DWORD  dwButtonModesOffset;
  DWORD  dwButtonFunctionsSize;
  DWORD  dwButtonFunctionsOffset;
  DWORD  dwLampModesSize;
  DWORD  dwLampModesOffset;
  DWORD  dwNumSetData;
  DWORD  dwSetDataSize;
  DWORD  dwSetDataOffset;
  DWORD  dwNumGetData
  DWORD  dwGetDataSize;
  DWORD  dwGetDataOffset;
  DWORD  dwDevSpecificSize;

  DWORD  dwDevSpecificOffset;
} PHONECAPS, FAR *LPPHONECAPS;

The PHONECAPS structure describes the capabilities of a phone device.

dwTotalSize

The total size in bytes allocated to this data structure.

dwNeededSize

The size in bytes for this data structure that is needed to hold all the returned information.

dwUsedSize

The size in bytes of the portion of this data structure that contains useful information.

dwProviderInfoSize
dwProviderInfoOffset

The size in bytes of the variably sized field containing service provider-specific information, and the offset in bytes from the beginning of this data structure.

The dwProviderInfoSize/Offset field is intended to provide information about the provider hardware and/or software, such as the vendor name and version numbers of hardware and software. This information can be useful when a user needs to call customer service with problems regarding the provider.

dwPhoneInfoSize
dwPhoneInfoOffset

The size in bytes of the variably sized device field containing phone-specific information, and the offset in bytes from the beginning of this data structure.

The dwPhoneInfoSize/Offset field is intended to provide information about the attached phone device, such as the phone-device manufacturer, the model name, the software version, and so on. This information can be useful when a user needs to call customer service with problems regarding the phone.

dwPermanentPhoneID

Specifies the permanent DWORD identifier by which the phone device is known in the system's configuration.

dwPhoneNameSize
dwPhoneNameOffset

The size in bytes of the variably sized device field containing user configurable name for this phone device,  and the offset in bytes from the beginning of this data structure This name can be configured by the user when configuring the phone device's service provider and is provided for the user's convenience.

dwStringFormat

Specifies the string format to be used with this phone device. This parameter uses the following STRINGFORMAT_ constants:

STRINGFORMAT_ASCII

This is ASCII string format using one byte per character.

STRINGFORMAT_DBCS

This is DBCS string format using two bytes per character.

STRINGFORMAT_UNICODE

This is unicode string format using two bytes per character.

dwPhoneStates

Specifies the state changes for this phone device for which the application can be notified in a PHONE_STATE callback message. This parameter uses the following PHONESTATE_ constants:

PHONESTATE_OTHER

Phone-status items other than those listed below have changed. The application should check the current phone status to determine which items have changed.

PHONESTATE_CONNECTED

The connection between the phone device and TAPI was just made. This happens when TAPI is first invoked or when the wire connecting the phone to the PC is plugged in with TAPI active.

PHONESTATE_DISCONNECTED

The connection between the phone device and TAPI was just broken. This happens when the wire connecting the phone set to the PC is unplugged while TAPI is active.

PHONESTATE_OWNER

The number of owners for the phone device has changed.

PHONESTATE_MONITORS

The number of monitors for the phone device has changed.

PHONESTATE_DISPLAY

The display of the phone has changed.

PHONESTATE_LAMP

A lamp of the phone has changed.

PHONESTATE_RINGMODE

The ring mode of the phone has changed.

PHONESTATE_RINGVOLUME

The ring volume of the phone has changed.

PHONESTATE_HANDSETHOOKSWITCH

The handset hookswitch state has changed.

PHONESTATE_HANDSETVOLUME

The handset's speaker volume setting has changed.

PHONESTATE_HANDSETGAIN

The handset's microphone gain setting has changed.

PHONESTATE_SPEAKERHOOKSWITCH

The speakerphone's hookswitch state has changed.

PHONESTATE_SPEAKERVOLUME

The speakerphone's speaker volume setting has changed.

PHONESTATE_SPEAKERGAIN

The speakerphone's microphone gain setting state has changed.

PHONESTATE_HEADSETHOOKSWITCH

The headset's hookswitch state has changed.

PHONESTATE_HEADSETVOLUME

The headset's speaker volume setting has changed.

PHONESTATE_HEADSETGAIN

The headset's microphone gain setting has changed.

PHONESTATE_SUSPEND

The application's use of the phone is temporarily suspended.

PHONESTATE_RESUME

The application's use of the phone device is resumed after having been suspended for some time.

PHONESTATE_DEVSPECIFIC

The phone's device-specific information has changed.

PHONESTATE_REINIT

Items have changed in the configuration of phone devices. To become aware of these changes (as for the appearance of new phone devices) the application should reinitialize its use of TAPI.

PHONESTATE_CAPSCHANGE

Indicates that, due to configuration changes made by the user or other circumstances, one or more of the fields in the PHONECAPS structure have changed. The application should use phoneGetDevCaps to read the updated structure.

PHONESTATE_REMOVED

Indicates that the device is being removed from the system by the service provider (most likely through user action, via a control panel or similar utility). A PHONE_STATE message with this value will normally be immediately followed by a PHONE_CLOSE message on the device. Subsequent attempts to access the device prior to TAPI being reinitialized will result in PHONEERR_NODEVICE being returned to the application. If a service provider sends a PHONE_STATE message containing this value to TAPI, TAPI will pass it along to applications which have negotiated this or a subsequent API version; applications negotiating a previous API version will not receive any notification.

dwHookSwitchDevs

This field specifies the phone's hookswitch devices. This parameter uses the following PHONEHOOKSWITCHDEV_ constants:

PHONEHOOKSWITCHDEV_HANDSET

This is the ubiquitous, handheld, ear- and mouthpiece.

PHONEHOOKSWITCHDEV_SPEAKER

A built-in loudspeaker and microphone. This could also be an externally connected adjunct to the telephone set.

PHONEHOOKSWITCHDEV_HEADSET

This is a headset connected to the phone set.

dwHandsetHookSwitchModes
dwSpeakerHookSwitchModes
dwHeadsetHookSwitchModes

This field specifies the phone's hookswitch mode capabilities of the handset, speaker, or headset, respectively. The field is only meaningful if the hookswitch device is listed in dwHookSwitchDevs. This parameter uses the following PHONEHOOKSWITCHMODE_ constants:

PHONEHOOKSWITCHMODE_ONHOOK

The device's microphone and speaker are both onhook.

PHONEHOOKSWITCHMODE_MIC

The device's microphone is active, the speaker is mute.

PHONEHOOKSWITCHMODE_SPEAKER

The device's speaker is active, the microphone is mute.

PHONEHOOKSWITCHMODE_MICSPEAKER

The device's microphone and speaker are both active.

dwVolumeFlags

This field specifies the volume setting capabilities of the phone device's speaker components. If the bit in position PHONEHOOKSWITCHDEV_ is TRUE, the volume of the corresponding hookswitch device's speaker component can be adjusted with phoneSetVolume; otherwise FALSE.

dwGainFlags

This field specifies the gain setting capabilities of the phone device's microphone components. If the bit position PHONEHOOKSWITCHDEV_ is TRUE, the volume of the corresponding hookswitch device's microphone component can be adjusted with phoneSetGain; otherwise FALSE.

dwDisplayNumRows

This field specifies the display capabilities of the phone device by describing the number of rows in the phone display. dwDisplayNumRows and dwDisplayNumColumns are both zero for a phone device without a display.

dwDisplayNumColumns

This field specifies the display capabilities of the phone device by describing the number of columns in the phone display. dwDisplayNumRows and dwDisplayNumColumns are both zero for a phone device without a display.

dwNumRingModes

This field specifies the ring capabilities of the phone device. The phone is able to ring with dwNumRingModes different ring patterns, identified as 1, 2, thru dwNumRingModes minus one. If the value of this field is zero, applications have no control over the ring mode of the phone. If the value of this field is greater than zero, it indicates the number of ring modes in addition to silence that are supported by the service provider. A value of 0 in the lpdwRingMode parameter of phoneGetRing or the dwRingMode parameter of phoneSetRing indicates silence (the phone is not ringing or should not be rung), and dwRingMode values of 1 to dwNumRingModes are valid ring modes for the phone device.

dwNumButtonLamps

This field specifies the number of button/lamps on the phone device that are detectable in TAPI. Button/lamps are identified by their ID. Valid button/lamp IDs range from zero to dwNumButtonLamps minus one. The keypad buttons '0', through '9', '*', and '#' are assigned the IDs 0 through 12.

dwButtonModesSize
dwButtonModesOffset

The size in bytes and the offset from the beginning of this data structure in bytes of the variably sized field containing the button modes of the phone's buttons. The array is indexed by button/lamp ID. This parameter uses the following PHONEBUTTONMODE_ constants:

PHONEBUTTONMODE_DUMMY

This value is used to describe a button/lamp position that has no corresponding button, but has only a lamp. If the phone provides any non-DUMMY buttons, the PHONE_BUTTON message will be sent to the application if a button is pressed at the phone device.

PHONEBUTTONMODE_CALL

The button is assigned to a call appearance.

PHONEBUTTONMODE_FEATURE

The button is assigned to requesting features from the switch, such as hold, conference, and transfer.

PHONEBUTTONMODE_KEYPAD

The button is one of the twelve keypad buttons, '0' through '9', '*', and '#'.

PHONEBUTTONMODE_LOCAL

The button is a local function button, such as mute or volume control.

PHONEBUTTONMODE_DISPLAY

The button is a "soft" button associated with the phone's display. A phone set can have zero or more display buttons.

dwButtonFunctionsSize
dwButtonFunctionsOffset

The size in bytes of the variably sized field containing the button modes of the phone's buttons, and the offset in bytes from the beginning of this data structure. This field uses the values specified by the PHONEBUTTONFUNCTION_ constants. The array is indexed by button/lamp ID.

dwLampModesSize
dwLampModesOffset

The size in bytes of the variably sized field containing the lamp modes of the phone's lamps, and the offset in bytes from the beginning of this data structure. The array is indexed by button/lamp ID. This parameter uses the following PHONELAMPMODE_ constants:

PHONELAMPMODE_BROKENFLUTTER

Broken flutter is the superposition of flash and flutter.

PHONELAMPMODE_FLASH

Flash means slow on and off.

PHONELAMPMODE_FLUTTER

Flutter means fast on and off.

PHONELAMPMODE_OFF

The lamp is off.

PHONELAMPMODE_STEADY

The lamp is continuously lit.

PHONELAMPMODE_WINK

The lamp is winking.

PHONELAMPMODE_DUMMY

This value is used to describe a button/lamp position that has no corresponding lamp.

dwNumSetData

The number of different download areas in the phone device. The different areas are referred to using the data IDs 0, 1, …, dwNumSetData minus one. If this field is zero, the phone does not support the download capability.

dwSetDataSize
dwSetDataOffset

The size in bytes of the variably sized field containing the sizes (in bytes) of the phone's download data areas, and the offset in bytes from the beginning of this data structure. This is an array with DWORD-sized elements indexed by data ID.

dwNumGetData

The number of different upload areas in the phone device. The different areas are referred to using the data IDs 0, 1, …, dwNumGetData minus one. If this field is zero, the phone does not support the upload capability.

dwGetDataSize
dwGetDataOffset

The size in bytes of the variably sized field containing the sizes (in bytes) of the phone's upload data areas, and the offset in bytes from the beginning of this data structure. This is an array with DWORD-sized elements indexed by data ID.

dwDevSpecificSize
dwDevSpecificOffset

The size in bytes of the variably sized device-specific field, and the offset in bytes from the beginning of this data structure

Device-specific extensions should use the DevSpecific (dwDevSpecificSize and dwDevSpecificOffset) variably sized area of this data structure.


PHONEEXTENSIONID

[New - Windows 95]

typedef struct phoneextensionid_tag {
  DWORD  dwExtensionID0;
  DWORD  dwExtensionID1;
  DWORD  dwExtensionID2;
  DWORD  dwExtensionID3;
} PHONEEXTENSIONID, FAR *LPPHONEEXTENSIONID;

The PHONEEXTENSIONID structure describes an extension ID. Extension IDs are used to identify service provider-specific extensions for phone device classes.

dwExtensionID0
dwExtensionID1
dwExtensionID2
dwExtensionID3

These four DWORD-sized fields together specify a universally unique extension ID that identifies a phone device class extension.

No extensibility.

Extension IDs are generated using an SDK-provided generation utility.


PHONESTATUS

[New - Windows 95]

typedef struct phonestatus_tag {
  DWORD  dwTotalSize;
  DWORD  dwNeededSize;
  DWORD  dwUsedSize;
  DWORD  dwStatusFlags;
  DWORD  dwNumOwners;
  DWORD  dwNumMonitors;
  DWORD  dwRingMode;
  DWORD  dwRingVolume;
  DWORD  dwHandsetHookSwitchMode;
  DWORD  dwHandsetVolume;
  DWORD  dwHandsetGain;
  DWORD  dwSpeakerHookSwitchMode;
  DWORD  dwSpeakerVolume;
  DWORD  dwSpeakerGain;
  DWORD  dwHeadsetHookSwitchMode;
  DWORD  dwHeadsetVolume;
  DWORD  dwHeadsetGain;
  DWORD  dwDisplaySize;
  DWORD  dwDisplayOffset;
  DWORD  dwLampModesSize;
  DWORD  dwLampModesOffset;
  DWORD  dwOwnerNameSize;
  DWORD  dwOwnerNameOffset;
  DWORD  dwDevSpecificSize;
  DWORD  dwDevSpecificOffset;
} PHONESTATUS, FAR *LPPHONESTATUS;

The PHONESTATUS structure describes the current status of a phone device.

dwTotalSize

The total size in bytes allocated to this data structure.

dwNeededSize

The size in bytes for this data structure that is needed to hold all the returned information.

dwUsedSize

The size in bytes of the portion of this data structure that contains useful information.

dwStatusFlags

This field provides a set of status flags for this phone device. This parameter uses the following PHONESTATUSFLAGS_ constants:

PHONESTATUSFLAGS_CONNECTED

Specifies whether the phone is currently connected to TAPI. TRUE if connected; FALSE otherwise.

PHONESTATUSFLAGS_SUSPENDED

Specifies whether TAPI's manipulation of the phone device is suspended. TRUE if suspended; FALSE otherwise. An application's use of a phone device may be temporarily suspended when the switch wants to manipulate the phone in a way that cannot tolerate interference from the application.

dwNumOwners

The number of application modules with owner privilege for the phone.

dwNumMonitors

The number of application modules with monitor privilege for the phone.

dwRingMode

Specifies the current ring mode of a phone device.

dwRingVolume

Specifies the current ring volume of a phone device. This is a value between 0x00000000 (silence) and 0x0000FFFF (maximum volume).

dwHandsetHookSwitchMode

Specifies the current hookswitch mode of the phone's handset. This parameter uses the following PHONEHOOKSWITCHMODE_ constants:

PHONEHOOKSWITCHMODE_ONHOOK

The device's microphone and speaker are both onhook.

PHONEHOOKSWITCHMODE_MIC

The devicer's microphone is active, the speaker is mute.

PHONEHOOKSWITCHMODE_SPEAKER

The device's speaker is active, the microphone is mute.

PHONEHOOKSWITCHMODE_MICSPEAKER

The device's microphone and speaker are both active.

dwHandsetVolume

Specifies the current speaker volume of the phone's handset device. This is a value between 0x00000000 (silence) and 0x0000FFFF (maximum volume).

dwHandsetGain

Specifies the current microphone gain of the phone's handset device. This is a value between 0x00000000 (silence) and 0x0000FFFF (maximum gain).

dwSpeakerHookSwitchMode

Specifies the current hookswitch mode of the phone's speakerphone. This parameter uses the following PHONEHOOKSWITCHMODE_ constants:

PHONEHOOKSWITCHMODE_ONHOOK

The device's microphone and speaker are both onhook.

PHONEHOOKSWITCHMODE_MIC

The devicer's microphone is active, the speaker is mute.

PHONEHOOKSWITCHMODE_SPEAKER

The device's speaker is active, the microphone is mute.

PHONEHOOKSWITCHMODE_MICSPEAKER

The device's microphone and speaker are both active.

dwSpeakerVolume

Specifies the current speaker volume of the phone's speaker device. This is a value between 0x00000000 (silence) and 0x0000FFFF (maximum volume).

dwSpeakerGain

Specifies the current microphone gain of the phone's speaker device. This is a value between 0x00000000 (silence) and 0x0000FFFF (maximum gain).

dwHeadsetHookSwitchMode

Specifies the current hookswitch mode of the phone's headset. This parameter uses the following PHONEHOOKSWITCHMODE_ constants:

PHONEHOOKSWITCHMODE_ONHOOK

The device's microphone and speaker are both onhook.

PHONEHOOKSWITCHMODE_MIC

The devicer's microphone is active, the speaker is mute.

PHONEHOOKSWITCHMODE_SPEAKER

The device's speaker is active, the microphone is mute.

PHONEHOOKSWITCHMODE_MICSPEAKER

The device's microphone and speaker are both active.

dwHeadsetVolume

Specifies the current speaker volume of the phone's headset device. This is a value between 0x00000000 (silence) and 0x0000FFFF (maximum volume).

dwHeadsetGain

Specifies the current microphone gain of the phone's headset device. This is a value between 0x00000000 (silence) and 0x0000FFFF (maximum gain).

dwDisplaySize
dwDisplayOffset

The size in bytes of the variably sized field containing the phone's current display information, and the offset in bytes, from the beginning of this data structure.

dwLampModesSize
dwLampModesOffset

The size in bytes of the variably sized field containing the phone's current lamp modes, and the offset in bytes from the beginning of this data structure.

dwOwnerNameSize
dwOwnerNameOffset

The size in bytes of the variably sized field containing the name of the application that is the the current owner of the phone device, and the offset in bytes from the beginning of this data structure. The name is the application name provided by the application when it invoked with phoneInitialize. If no application name was supplied, the application's file name is used instead. If the phone currently has no owner, dwOwnerNameSize is zero.

dwDevSpecificSize
dwDevSpecificOffset

The size in bytes of the variably sized device-specific field, and the offset in bytes from the beginning of this data structure

Device-specific extensions should use the DevSpecific (dwDevSpecificSize and dwDevSpecificOffset) variably sized area of this data structure.


VARSTRING

[New - Windows 95]

typedef struct varstring_tag {
  DWORD  dwTotalSize;
  DWORD  dwNeededSize;
  DWORD  dwUsedSize;
  DWORD  dwStringFormat;
  DWORD  dwStringSize;
  DWORD  dwStringOffset;
} VARSTRING, FAR *LPVARSTRING;

The VARSTRING structure is used for returning variably sized strings. It is used both by the line device class and the phone device class.

dwTotalSize

The total size in bytes allocated to this data structure.

dwNeededSize

The size in bytes for this data structure that is needed to hold all the returned information.

dwUsedSize

The size in bytes of the portion of this data structure that contains useful information.

dwStringFormat

Specifies the format of the string. This parameter uses the following STRINGFORMAT_ constants:

STRINGFORMAT_ASCII

This is ASCII string format using one byte per character. The actual string is a NULL-terminated ASCII string with the terminating NULL accounted for in the string size.

STRINGFORMAT_DBCS

This is DBCS string format using one or two bytes per character.

STRINGFORMAT_UNICODE

This is unicode string format using two bytes per character.

STRINGFORMAT_BINARY

This is an array of unsigned characters that could be used for numeric values.

dwStringSize
dwStringOffset

The size in bytes of the variably sized device field containing the string information, and the offset in bytes from the beginning of this data structure, .

No extensibility.

If a string cannot be returned in a variable structure, the dwStringSize and dwStringOffset members are set in one of these ways:

•	dwStringSize and dwStringOffset members are both set to zero.

•	dwStringOffset is nonzero and dwStringSize is zero.

•	dwStringOffset is nonzero, dwStringSize is 1, and the byte at the given offset is 0.


Constants

Following are the TAPI phone constants.


PHONEBUTTONFUNCTION_ Constants

[New - Windows 95]

The PHONEBUTTONFUNCTION_ scalar constants describe the functions commonly assigned to buttons on telephone sets.

PHONEBUTTONFUNCTION_UNKNOWN

A "dummy" function assignment that indicates that the exact function of the button is unknown or has not been assigned.

PHONEBUTTONFUNCTION_CONFERENCE

Initiates a conference call or adds a call to a conference call.

PHONEBUTTONFUNCTION_TRANSFER

Initiates a call transfer or completes the transfer of a call.

PHONEBUTTONFUNCTION_DROP

Drops the active call.

PHONEBUTTONFUNCTION_HOLD

Places the active call on hold.

PHONEBUTTONFUNCTION_RECALL

Unholds a call.

PHONEBUTTONFUNCTION_DISCONNECT

Disconnects a call, such as after initiating a transfer.

PHONEBUTTONFUNCTION_CONNECT

Reconnects a call that is on consultation hold.

PHONEBUTTONFUNCTION_MSGWAITON

Turns on a message waiting lamp.

PHONEBUTTONFUNCTION_MSGWAITOFF

Turns off a message waiting lamp.

PHONEBUTTONFUNCTION_SELECTRING

Allows the user to select the ring pattern of the phone.

PHONEBUTTONFUNCTION_ABBREVDIAL

The number to dialed will be indicated using a short, abbreviated number consisting of one or a few digits.

PHONEBUTTONFUNCTION_FORWARD

Initiates or changes call forwarding to this phone.

PHONEBUTTONFUNCTION_PICKUP

Picks up a call ringing on another phone.

PHONEBUTTONFUNCTION_RINGAGAIN

Initiates a request to be notified if a call cannot be completed normally because of a busy or no answer.

PHONEBUTTONFUNCTION_PARK

Parks the active call on another phone, placing it on hold there.

PHONEBUTTONFUNCTION_REJECT

Rejects an inbound call before the call has been answered.

PHONEBUTTONFUNCTION_REDIRECT

Redirects an inbound call to another extension before the call has been answered.

PHONEBUTTONFUNCTION_MUTE

Mutes the phone's microphone device.

PHONEBUTTONFUNCTION_VOLUMEUP

Increases the volume of audio through the phone's handset speaker or speakerphone.

PHONEBUTTONFUNCTION_VOLUMEDOWN

Decreases the volume of audio through the phone's handset speaker or speakerphone.

PHONEBUTTONFUNCTION_SPEAKERON

Turns the phone's external speaker on.

PHONEBUTTONFUNCTION_SPEAKEROFF

Turns the phone's external speaker off.

PHONEBUTTONFUNCTION_FLASH

Generates the equivalent of a on-hook/off-hook sequence. A flash typically indicates that any digits typed next are to be understood as commands to the switch. On many switches, places an active call on consultation hold.

PHONEBUTTONFUNCTION_DATAON

Indicates that the next call is a data call.

PHONEBUTTONFUNCTION_DATAOFF

Indicates that the next call is not a data call.

PHONEBUTTONFUNCTION_DONOTDISTURB

Places the phone in "do not disturb" mode; incoming calls receive a busy signal or are forwarded to an operator or voicemail system.

PHONEBUTTONFUNCTION_INTERCOM

Connect to the intercom to broadcast a page.

PHONEBUTTONFUNCTION_BRIDGEDAPP

Selects a particular appearance of a bridged address.

PHONEBUTTONFUNCTION_BUSY

Makes the phone appear "busy" to incoming calls.

PHONEBUTTONFUNCTION_CALLAPP

Selects a particular call appearance.

PHONEBUTTONFUNCTION_DATETIME

Causes the phone to display current date and time; this information would be sent by the switch.

PHONEBUTTONFUNCTION_DIRECTORY

Calls up directory service from the switch.

PHONEBUTTONFUNCTION_COVER

Forwards all calls destined for this phone to another phone used for coverage.

PHONEBUTTONFUNCTION_CALLID

Requests display of caller ID on the phone's display.

PHONEBUTTONFUNCTION_LASTNUM

Redials last number dialed.

PHONEBUTTONFUNCTION_NIGHTSRV

Places the phone in the mode it is configured for during night hours.

PHONEBUTTONFUNCTION_SENDCALLS

Sends all calls to another phone used for coverage; same as PHONEBUTTONFUNCTION_COVER.

PHONEBUTTONFUNCTION_MSGINDICATOR

Controls the message indicator lamp.

PHONEBUTTONFUNCTION_REPDIAL

Repertory dialing—the number to be dialed is provided as a shorthand following pressing of this button.

PHONEBUTTONFUNCTION_SETREPDIAL

Programs the shorthand-to-phone number mappings accessible by means of repertory dialing (the "REPDIAL" button).

PHONEBUTTONFUNCTION_SYSTEMSPEED

The number to be dialed is provided as a shorthand following pressing of this button. The mappings for system speed dialing are configured inside the switch.

PHONEBUTTONFUNCTION_STATIONSPEED

The number to be dialed is provided as a shorthand following pressing of this button. The mappings for station speed dialing are specific to this station (phone).

PHONEBUTTONFUNCTION_CAMPON

Camps-on an extension that returns a busy indication. When the remote station returns to idle, the phone will be rung with a distinctive patterns. Picking up the local phone re-initiates the call.

PHONEBUTTONFUNCTION_SAVEREPEAT

When pressed while a call or call attempt is active, it will remember that call's number or command. When pressed while no call is active (such as during dialtone), it repeats the most saved command.

PHONEBUTTONFUNCTION_QUEUECALL

Queues a call to an outside number after it encounters a trunk-busy indiction. When a trunk becomes later available, the phone will be rung with a distinctive pattern. Picking up the local phone re-initiates the call.

PHONEBUTTONFUNCTION_NONE

A "dummy" function assignment that indicates that the button does not have a function.

Values in the range 0x80000000 to 0xFFFFFFFF can be assigned for device-specific extensions; values in the range 0x00000000 to 0x7FFFFFFF are reserved.

The PHONEBUTTONFUNCTION_ constants have values commonly found on current telephone sets. These button functions can be used to invoke the corresponding function from the switch using lineDevSpecificFeature. Note that TAPI does not define the semantics of the button functions; it only provides access to the corresponding function. The behavior associated with each of the function values above is generic and may vary based on the telephony environment.


PHONEBUTTONMODE_ Constants

[New - Windows 95]

The PHONEBUTTONMODE_ bit-flag constants describe the button classes.

PHONEBUTTONMODE_DUMMY

This value is used to describe a button/lamp position that has no corresponding button but has only a lamp.

PHONEBUTTONMODE_CALL

The button is assigned to a call appearance.

PHONEBUTTONMODE_FEATURE

The button is assigned to requesting features from the switch, such as hold, conference, and transfer.

PHONEBUTTONMODE_KEYPAD

The button is one of the twelve keypad buttons, '0' through '9', '*', and '#'.

PHONEBUTTONMODE_LOCAL

The button is a local function button, such as mute or volume control.

PHONEBUTTONMODE_DISPLAY

The button is a "soft" button associated with the phone's display. A phone set can have zero or more display buttons.

No extensibility. All 32 bits are reserved.

This enumeration type is used in the PHONECAPS data structure to describe the meaning associated with the phone's buttons.


PHONEBUTTONSTATE_ Constants

[New - Windows 95]

The PHONEBUTTONSTATE_ bit-flag constants describe the button's positions.

PHONEBUTTONSTATE_UP

The button is in the "up" state.

PHONEBUTTONSTATE_DOWN

The button is in the "down" state (pressed down).

PHONEBUTTONSTATE_UNKNOWN

Indicates that the up or down state of the button is not known at this time, but may become known at a future time.

PHONEBUTTONSTATE_UNAVAIL

Indicates that the up or down state of the button is not known to the service provider, and will not become known at a future time.

No extensibility. All 32 bits are reserved.

For backward compatibility, it is the responsibility of the service provider to examine the negotiated API version on the phone, and to not use these PHONEBUTTONSTATE_ values if not supported on the negotiated version.


PHONEERR_ Constants

[New - Windows 95]

This is the list of error codes that the implementation may return when invoking operations on phone devices. Consult the individual function descriptions to determine which of these error codes each function may return.

PHONEERR_ALLOCATED

The specified resource is already allocated.

PHONEERR_BADDEVICEID

The specified device ID is invalid or out of range.

PHONEERR_INCOMPATIBLEAPIVERSION

The application requested an API version or version range that cannot be supported by the Telephony API implementation and/or corresponding service provider.

PHONEERR_INCOMPATIBLEEXTVERSION

The application requested an extension version or version range that cannot supported by the service provider.

PHONEERR_INIFILECORRUPT

Because of internal inconsistencies or formatting problems in the file TELEPHON.INI, it cannot be read and understood properly by TAPI.

PHONEERR_INIFILECORRUPT

The TELEPHON.INI file was corrupted.

PHONEERR_INUSE

The device is currently in use. The device cannot be configured.

PHONEERR_INVALAPPHANDLE

The application's specified usage handle or registration handle is invalid.

PHONEERR_INVALAPPNAME

The specified application name is invalid. If an application name is specified by the application, it is assumed that the string does not contain any non-displayable characters and is NULL-terminated.

PHONEERR_INVALBUTTONLAMPID

The specified button/lamp ID is out of range or invalid.

PHONEERR_INVALBUTTONMODE

The button mode parameter is invalid.

PHONEERR_INVALBUTTONSTATE

The button states parameter is invalid.

PHONEERR_INVALDATAID

The specified data ID is invalid.

PHONEERR_INVALDEVICECLASS

The specified phone does not support the indicated device class.

PHONEERR_INVALHOOKSWITCHDEV

The hookswitch device parameter is invalid.

PHONEERR_INVALHOOKSWITCHMODE

The hookswitch mode parameter is invalid.

PHONEERR_INVALLAMPMODE

The specified lamp mode parameter is invalid.

PHONEERR_INVALPARAM

A parameter, such as a row or column value or a window handle, is invalid or out of range.

PHONEERR_INVALPHONEHANDLE

The specified device handle is invalid.

PHONEERR_INVALPHONESTATE

The phone device is not in a valid state for the requested operation.

PHONEERR_INVALPOINTER

One or more of the specified pointer parameters are invalid.

PHONEERR_INVALPRIVILEGE

The dwPrivilege parameter is invalid.

PHONEERR_INVALRINGMODE

The ring mode parameter is invalid.

PHONEERR_NODEVICE

The specified device ID, which was previously valid, is no longer accepted because the associated device has been removed from the system since TAPI was last initialized.

PHONEERR_NODRIVER

The telephone service provider for the specified device found that one of its components is missing or corrupt in a way that was not detected at initialization time. The user should be advised to use the Telephony Control Panel to correct the problem.

PHONEERR_NOMEM

Insufficient memory to complete the requested operation, or unable to allocate or lock memory.

PHONEERR_NOTOWNER

The application does not have owner privilege to the specified phone device.

PHONEERR_OPERATIONFAILED

The operation failed for an unspecified reason.

PHONEERR_OPERATIONUNAVAIL

The operation is not available.

PHONEERR_REINIT

If TAPI reinitialization has been requested, for example as a result of adding or removing a Telephony service provider, then phoneInitialize or phoneOpen requests are rejected with this error until the last application shuts down its usage of the API (using phoneShutdown), at which time the new configuration becomes effective and applications are once again permitted to call phoneInitialize

PHONEERR_RESOURCEUNAVAIL

The operation cannot be completed because of resource overcommitment.

PHONEERR_STRUCTURETOOSMALL

The specified phone caps structure is too small.

PHONEERR_UNINITIALIZED

The operation was invoked before any application called phoneInitialize.

The values 0xC0000000 through 0xFFFFFFFF are available for device-specific extensions; the values 0x80000000 through 0xBFFFFFFF are reserved; and 0x00000000 through 0x7FFFFFFF are used as request IDs.

If an application gets an error return that it does not specifically handle (such as an error defined by a device-specific extension), it should treat the error as a PHONEERR_OPERATIONFAILED (for an unspecified reason).


PHONEHOOKSWITCHDEV_ Constants

[New - Windows 95]

The PHONEHOOKSWITCHDEV_ bit-flag constants describe various audio I/O devices each with its own hookswitch controllable from the computer.

PHONEHOOKSWITCHDEV_HANDSET

This is the ubiquitous, handheld, ear- and mouthpiece.

PHONEHOOKSWITCHDEV_SPEAKER

This is a built-in loudspeaker and microphone. This could also be an externally connected adjunct speaker to the telephone set.

PHONEHOOKSWITCHDEV_HEADSET

This is a headset connected to the phone set.

No extensibility. All 32 bits are reserved.

These constants are used in the PHONECAPS data structure to indicate the hookswitch device capabilities of a phone device. The PHONESTATUS structure reports the state of the phone's hookswitch devices. The function phoneSetHookSwitch and phoneGetHookSwitch use it as a parameter to select the phone's I/O device.


PHONEHOOKSWITCHMODE_ Constants

[New - Windows 95]

The PHONEHOOKSWITCHMODE_ bit-flag constants describe the microphone and speaker components of a hookswitch device.

PHONEHOOKSWITCHMODE_ONHOOK

The device's microphone and speaker are both onhook.

PHONEHOOKSWITCHMODE_MIC

The devicer's microphone is active, the speaker is mute.

PHONEHOOKSWITCHMODE_SPEAKER

The device's speaker is active, the microphone is mute.

PHONEHOOKSWITCHMODE_MICSPEAKER

The device's microphone and speaker are both active.

PHONEHOOKSWITCHMODE_UNKNOWN

The device's hookswitch mode is currenly unknown.

No extensibility. All 32 bits are reserved.

These constants are used to provide individual level of control over the microphone and speaker components of a phone device.


PHONELAMPMODE_ Constants

[New - Windows 95]

The PHONELAMPMODE_ bit-flag constants describe various ways in which a phone's lamp can be lit.

PHONELAMPMODE_DUMMY

This value is used to describe a button/lamp position that has no corresponding lamp.

PHONELAMPMODE_OFF

The lamp is off.

PHONELAMPMODE_STEADY

Steady means the lamp is continuously lit.

PHONELAMPMODE_WINK

Wink means normal rate on and off.

PHONELAMPMODE_FLASH

Flash means slow on and off.

PHONELAMPMODE_FLUTTER

Flutter means fast on and off.

PHONELAMPMODE_BROKENFLUTTER

Broken flutter is the superposition of flash and flutter.

PHONELAMPMODE_UNKNOWN

The lamp mode is currently unknown.

The high-order 16 bits can be assigned for device-specific extensions. The low-order 16 bits are reserved.

Where the exact on and off cadences may differ across phone sets from different vendors, mapping of actual lamp lighting patterns for most phones onto the values listed above should be straightforward.


PHONEPRIVILEGE_ Constants

[New - Windows 95]

The PHONEPRIVILEGE_ bit-flag constants describe the various ways in which a phone device can be opened.

PHONEPRIVILEGE_MONITOR

An application that opens a phone device with the monitor privilege is informed about events and state changes occurring on the phone. The application cannot invoke any operations on the phone device that would change its state, so only status operations can be invoked. Multiple applications can monitor a phone device at any given time.

PHONEPRIVILEGE_OWNER

An application that opens a phone device with the owner privilege is allowed to change the state of the lamps, ringer, display, hookswitch, and data blocks of the phone. Opening a phone device in owner mode also provides monitoring of the phone device. Only one application is allowed to be the owner of a phone device at any given time.

No extensibility. All 32 bits are reserved.


PHONESTATE_ Constants

[New - Windows 95]

The PHONESTATE_ bit-flag constants describe various status items for a phone device.

PHONESTATE_OTHER

Phone-status items other than those listed below have changed. The application should check the current phone status to determine which items have changed.

PHONESTATE_CONNECTED

The connection between the phone device and TAPI was just made. This happens when TAPI is first invoked or when the wire connecting the phone to the PC is plugged in with TAPI active.

PHONESTATE_DISCONNECTED

The connection between the phone device and TAPI was just broken. This happens when the wire connecting the phone set to the PC is unplugged while TAPI is active.

PHONESTATE_OWNER

The number of owners for the phone device.

PHONESTATE_MONITORS

The number of monitors for the phone device.

PHONESTATE_DISPLAY

The display of the phone has changed.

PHONESTATE_LAMP

A lamp of the phone has changed.

PHONESTATE_RINGMODE

The ring mode of the phone has changed.

PHONESTATE_RINGVOLUME

The ring volume of the phone has changed.

PHONESTATE_HANDSETHOOKSWITCH

The handset hookswitch state has changed.

PHONESTATE_HANDSETVOLUME

The handset's speaker volume setting has changed.

PHONESTATE_HANDSETGAIN

The handset's microphone gain setting has changed.

PHONESTATE_SPEAKERHOOKSWITCH

The speakerphone's hookswitch state has changed.

PHONESTATE_SPEAKERVOLUME

The speakerphone's speaker volume setting has changed.

PHONESTATE_SPEAKERGAIN

The speakerphone's microphone gain setting state has changed.

PHONESTATE_HEADSETHOOKSWITCH

The headset's hookswitch state has changed.

PHONESTATE_HEADSETVOLUME

The headset's speaker volume setting has changed.

PHONESTATE_HEADSETGAIN

The headset's microphone gain setting has changed.

PHONESTATE_SUSPEND

The application's use of the phone is temporarily suspended.

PHONESTATE_RESUME

The application's use of the phone device is resumed after having been suspended for some time.

PHONESTATE_DEVSPECIFIC

The phone's device-specific information has changed.

PHONESTATE_REINIT

Items have changed in the configuration of phone devices. To become aware of these changes (as for the appearance of new phone devices), the application should reinitialize its use of TAPI.

PHONESTATE_CAPSCHANGE

Indicates that, due to configuration changes made by the user or other circumstances, one or more of the fields in the PHONECAPS structure have changed. The application should use phoneGetDevCaps to read the updated structure. If a service provider sends a PHONE_STATE message containing this value to TAPI, TAPI will pass it along to applications which have negotiated this or a subsequent API version; applications negotiating a previous API version will receive PHONE_STATE messages specifying PHONESTATE_REINIT, requiring them to shutdown and reinitialize their connection to TAPI in order to obtain the updated information.

PHONESTATE_REMOVED

Indicates that the device is being removed from the system by the service provider (most likely through user action, via a control panel or similar utility). A PHONE_STATE message with this value will normally be immediately followed by a PHONE_CLOSE message on the device. Subsequent attempts to access the device prior to TAPI being reinitialized will result in PHONEERR_NODEVICE being returned to the application. If a service provider sends a PHONE_STATE message containing this value to TAPI, TAPI will pass it along to applications which have negotiated this or a subsequent API version; applications negotiating a previous API version will not receive any notification.

No extensibility. All 32 bits are reserved.


PHONESTATUSFLAGS_ Constants

[New - Windows 95]

The PHONESTATUSFLAGS_ bit-flag constants describe a variety of phone device status information.

PHONESTATUSFLAGS_CONNECTED

Specifies whether the phone is currently connected to TAPI. TRUE if connected, FALSE otherwise.

PHONESTATUSFLAGS_SUSPENDED

Specifies whether TAPI's manipulation of the phone device is suspended. TRUE if suspended, FALSE otherwise. An application's use of a phone device may be temporarily suspended when the switch wants to manipulate the phone in a way that cannot tolerate interference from the application.

No extensibility. All 32 bits are reserved.


STRINGFORMAT_ Constants

[New - Windows 95]

The STRINGFORMAT_ enumeration constants describe different string formats.

STRINGFORMAT_ASCII

Specifies standard ASCII character format using one byte per character.

STRINGFORMAT_DBCS

Specifies standard DBCS character format using two bytes per character.

STRINGFORMAT_UNICODE

Specifies standard Unicode character format using two bytes per character.

STRINGFORMAT_BINARY

This is an array of unsigned characters; could be used for numeric values.

No extensibility. All 32 bits are reserved.


Device Classes

About Device Classes

A device class is a group of related physical devices or device drivers through which applications send and receive the information or data that makes up a call. Every device class has a device class name that uniquely identifies the class and provides information about the programming interface and commands that can be used to open and communicate with the devices in the class.

The telephony application programming interface (TAPI) associates devices from one or more device classes to each line or phone device. You access one of these devices by retrieving the device identifier for the device using the lineGetID or phoneGetID function. You supply the device class name, and the function returns the specific port name, device name, device handle, or device identifier that you need to open and access the device. The format of the information returned depends on the device class and is described in subsequent sections of this chapter.

Note  The device identifier definitions apply to 16-bit and 32-bit TAPI. In some cases, the data type of a media handle in the device identifier definition may be different than that specified by the Microsoft® Windows® version 3.x or Microsoft® Win32® application programming interface (API). For example, Windows 3.x and Win32 define wave device identifiers with the UINT type, but TAPI defines this device identifier with the DWORD type. In such cases, you should cast the media handle to the appropriate data type when using it with the Windows version 3.x or Win32 API.

You also use device class names with the lineConfigDialog and phoneConfigDialog functions to enable the user to set configuration options for the given device, with the lineGetIcon and phoneGetIcon functions to retrieve an icon to represent the given device, and with the lineGetDevConfig and lineSetDevConfig functions to directly retrieve and set configuration options for the given device.

By default, there are the following device class names.

comm	Communications port.
comm/datamodem	Modem through a communications port.
wave/in	Wave audio device (input only).
wave/out	Wave audio device (output only).
midi/in	Midi sequencer (input only).
midi/out	Midi sequencer (output only).
tapi/line	Line device.
tapi/phone	Phone device.
ndis	Network device.
tapi/terminal	Terminal device.
These names are not case sensitive, so you can use any combination of uppercase and lowercase letters.

Additional device classes and device class names may be available on a given system. In general, if a device does not belong to one of the default device classes, the manufacturer typically defines a new device class and assigns a unique device class name. You need to check the documentation for the device to determine what additional device classes are available for it. Note, however, that although the device class and media mode are related, they are not the same. A media mode describes a format of information on a call, and a device class defines the programming interface used to manage that information. So, even if a manufacturer defines a new media mode, it is not necessarily true that the manufacturer also needs to define a new device class to support the mode.

The format of the configuration data used with the lineSetDevConfig and lineGetDevConfig functions also depends on the device class. In general, you use lineGetDevConfig to save a copy of the current device configuration data and then later use lineSetDevConfig with the saved configuration data to restore the device configuration to the previous state. This is a convenient way to temporarily change the configuration without requiring the user to manually restore it to the previous state. Because the exact format of the device configuration data may be different with each service provider, you should not use lineSetDevConfig and lineGetDevConfig to manipulate the device configuration data directly. Some formats are provided for information only.


comm

The comm device class consists of communications ports. You access these devices by using the Win32 file and communications functions.

The lineGetID and phoneGetID functions fill a VARSTRING structure, setting the dwStringFormat member to the STRINGFORMAT_ASCII value and appending a null-terminated string that specifies the name of the communication port (such as COM1). You use this port name in a call to the CreateFile function to open the communication device for the line or phone.


comm/datamodem

The comm/datamodem device class consists of modem devices. You access these devices by using the Win32 file and communications functions. Devices in this class are associated with line devices that support the LINEMEDIAMODE_DATAMODEM media mode, which is specified in the dwMediaModes member of the LINEDEVCAPS structure for the line device.

The lineGetID and phoneGetID functions fill a VARSTRING structure, setting dwStringFormat to the STRINGFORMAT_BINARY value and appending these additional members.

HANDLE hComm;            // handle of open comm. device
CHAR   szDeviceName[1];  // name of comm. device

The hComm member is the handle of the open communications port. This member is NULL if the port is not yet open or if the dwSelect parameter of lineGetID is not the LINECALLSELECT_CALL value. If a call is active, the service provider typically opens the port itself to get direct control of the communications hardware, but is only required to return a valid handle if the line is connected. The service provider opens the port using the FILE_FLAG_OVERLAPPED value and then configures the port using the settings specified by the lineSetDevConfig function. You can set additional configuration options for the device by using Win32 functions with the returned handle.

The szDeviceName member is a null-terminated ASCII string that specifies the name of the communications port associated with the line, address, or call.

If hComm is a valid handle, you can use it in subsequent calls to Win32 file functions, such as ReadFile and WriteFile, to send and receive data on the call. When you are finished using the communications port and preferably before you use the lineDeallocateCall function to deallocate the call, you must close the port by using the CloseHandle function.

When using the lineGetDevConfig and lineSetDevConfig functions, some service providers require that the configuration data for this device class have the following format.

typedef struct  tagDEVCFG  {
  DEVCFGHDR   dfgHdr;
  COMMCONFIG  commconfig;
} DEVCFG, *PDEVCFG, FAR* LPDEVCFG;

// Device setting information
typedef struct  tagDEVCFGDR  {
  DWORD       dwSize;
  DWORD       dwVersion;
  WORD        fwOptions;
  WORD        wWaitBong;
} DEVCFGHDR;

Contains device configuration information for use with the lineGetDevConfig and lineSetDevConfig functions.

dwSize

Sum of the size of the DEVCFGHDR structure and the actual size of COMMCONFIG structure.

dwVersion

Version number of the Unimodem DevConfig structure. This member can be MDMCFG_VERSION (0x00010003).

fwOptions

Option flags that appear on the Unimodem Option page. This member can be a combination of these values:

TERMINAL_PRE (1)	Displays the preterminal screen.
TERMINAL_POST (2)	Displays the post terminal screen.
MANUAL_DIAL (4)	Dials the phone manually, if capable of doing so.
LAUNCH_LIGHTS (8)	Displays the modem tray icon.
Only the LAUNCH_LIGHTS value is set by default.

wWaitBong

Number of seconds (in two seconds granularity) to replace the wait for credit tone ($).

commconfig

COMMCONFIG structure that can be used with the Win32 communications and MCX functions.


wave/in

The wave/in device class consists of audio devices for low-level wave audio input. You access these devices by using the wave functions, which are described in the Microsoft Win32 Software Development Kit (SDK). Devices in this class are associated with line devices that support the LINEMEDIAMODE_AUTOMATEDVOICE media modem which is specified in the dwMediaModes member of the LINEDEVCAPS structure for the line device.

The lineGetID and phoneGetID functions fill a VARSTRING structure, setting the dwStringFormat member to the STRINGFORMAT_BINARY value and appending this additional member.

DWORD DeviceId;  // identifier of audio device

The DeviceId member is the identifier of a closed audio device. You use this identifier in a call to the waveInOpen function to open the device for input. You can use the resulting device handle to record digitized audio data from the line or phone device.

Although a "wave" device class also exists for low-level wave audio devices, you should always use the wave/in device class for low-level wave input.


wave/out

The wave/out device class consists of audio devices for low-level wave audio output. You access these devices by using the wave functions, which are described in the Win32 SDK. Devices in this class are associated with line devices that support the LINEMEDIAMODE_AUTOMATEDVOICE media mode, which is specified in the dwMediaModes member of the LINEDEVCAPS structure for the line device.

The lineGetID and phoneGetID functions fill a VARSTRING structure, setting the dwStringFormat member to the STRINGFORMAT_BINARY value and appending this additional member.

DWORD DeviceId;  // identifier of audio device

The DeviceId member is the identifier of a closed audio device. You use this identifier in a call to the waveOutOpen function to open the device for output. You can use the resulting device handle to play digitized audio data at the line or phone device.

Although a "wave" device class also exists for low-level wave audio devices, you should always use the wave/out device class for low-level wave output.


midi/in

The midi/in device class consists of MIDI sequencers that are used for input. You access these devices by using the MIDI functions, which are described in the Win32 SDK.

The lineGetID and phoneGetID functions fill a VARSTRING structure, setting the dwStringFormat member to the STRINGFORMAT_BINARY value and appending this additional member.

DWORD DeviceId;  // identifier of MIDI device

The DeviceId member is the identifier of a closed MIDI device. You use this identifier in a call to the midiInOpen function to open the device for input. You can use the resulting device handle to record MIDI data from the line or phone device.


midi/out

The midi/out device class consists of MIDI sequencers that are used for output. You access these devices by using the MIDI functions, which are described in the Win32 SDK.

The lineGetID and phoneGetID functions fill a VARSTRING structure, setting the dwStringFormat member to the STRINGFORMAT_BINARY value and appending this additional member.

DWORD DeviceId;  // identifier of MIDI device

The DeviceId member is the identifier of a closed MIDI device. You use this identifier in a call to the midiOutOpen function to open the device for output. You can use the resulting device handle to play MIDI data at the line or phone device.


tapi/line

The tapi/line device class consists of all line devices. You access these devices using the TAPI line functions.

The lineGetID function fills a VARSTRING structure, setting the dwStringFormat member to the STRINGFORMAT_BINARY value and appending this additional member.

DWORD dwDeviceI;  // line device identifier

The dwDeviceId member is the identifier of the line device associated with the line handle given by lineGetID.

The phoneGetID function also fills a VARSTRING structure, setting dwStringFormat to STRINGFORMAT_BINARY and appending this additional member.

DWORD adwDeviceIds[];  // array of line device identifiers

The adwDeviceIds member is an array containing the device identifiers of all line devices that are associated with the phone device. If there are no associated line devices, phoneGetID returns the PHONEERR_INVALDEVICECLASS value.


tapi/phone

The tapi/phone device class consists of all phone devices. You access these devices by using the TAPI phone functions.

The phoneGetID function fills a VARSTRING structure, setting the dwStringFormat member to the STRINGFORMAT_BINARY value and appending this additional member.

DWORD dwDeviceI;  // phone device identifier

The dwDeviceId member is the identifier of the phone device associated with the phone handle given by phoneGetID.

The lineGetID function also fills a VARSTRING structure, setting dwStringFormat to STRINGFORMAT_BINARY and appending this additional member.

DWORD adwDeviceIds[];  // array of phone device identifiers

The adwDeviceIds member is an array containing the device identifiers of all phone devices that are associated with the given line device. If there are no associated phone devices, lineGetID returns the LINEERR_INVALDEVICECLASS value.


ndis

The ndis device class consists of devices that can be associated with network driver interface specification (NDIS) media access control (MAC) drivers to support network communications. You access these devices by using functions.

The lineGetID and phoneGetID functions fill a VARSTRING structure, setting the dwStringFormat member to the STRINGFORMAT_BINARY value and appending these additional members.

HANDLE  hDevice;          // NDIS connection identifier
CHAR    szDeviceType[1];  // name of device

The hDevice member is the identifier to pass to a MAC, such as the asynchronous MAC for dial-up networking, to associate a network connection with the call/modem connection. The szDeviceType member is a null-terminated ASCII string specifying the name of the device associated with the identifier. For more information, see documentation about writing NDIS MAC drivers for use with dial-up networking.


tapi/terminal

The tapi/terminal device class consists of the phone devices associated with each terminal on a line or the terminal on each line associated with a phone device. You access these devices by using the TAPI line or phone functions.

The lineGetID function fills a VARSTRING structure, setting the dwStringFormat member to the STRINGFORMAT_BINARY value and appending this additional member.

DWORD adwDeviceId[];  // array of phone device identifiers

The adwDeviceId member is an array of phone device identifiers. There is one array element for each terminal specified by the dwNumTerminals member in the LINEDEVCAPS structure for the given line device. Each element specifies the identifier of the phone device associated with the corresponding terminal on the line. If there is no phone device associated with a terminal, the element is set to  − 1 (0xFFFFFFFF).

The phoneGetID function fills a VARSTRING structure, setting the dwStringFormat member to the STRINGFORMAT_BINARY value and appending this additional member.

DWORD adwTerminalID[];  // array of terminal identifiers

The adwTerminalID member is an array of terminal identifiers. There is one array element for each line device identifier specified by the lineInitialize function. Each array element contains the terminal identifier associated with the phone device for the given line device. If there is no phone device, the element is set to  − 1 (0xFFFFFFFF). The terminal identifiers range in value from zero to one less than the number specified by the dwNumTerminals member in the LINEDEVCAPS structure.


Quick Function Reference

Assisted Telephony

The assisted telephony functions are:

tapiRequestMakeCall	Submits a request to place a voice call.
tapiRequestMediaCall	Obsolete. Do not use.
tapiRequestDrop	Obsolete. Do not use.
tapiGetLocationInfo	Returns country code and city/area code information.
These functions do not return until after making a call to the application's reply callback function and therefore are considered synchronous.


Basic Telephony Services

The Basic Telephony functions are listed below by category. A function is identified as "asynchronous" if it might return before making a call to the application's reply callback function. Otherwise, the function is considered synchronous.

TAPI Initialization and Shutdown

lineInitialize	Initializes the Telephony API line abstraction for use by the invoking application. Synchronous.
lineShutdown	Shuts down the application's use of the line Telephony API. Synchronous.
Line Version Negotiation

lineNegotiateAPIVersion	Allows an application to negotiate an API version to use. Synchronous.
Line Status and Capabilities

lineGetDevCaps	Returns the capabilities of a given line device. Synchronous.
lineGetDevConfig	Returns configration of a a media stream device. Synchronous.
lineGetLineDevStatus	Returns current status of the specified open line device. Synchronous.
lineSetDevConfig	Sets the configuration of the specified media stream device. Synchronous.
lineSetStatusMessages	Specifies the status changes for which the application wants to be notified. Synchronous.
lineGetStatusMessages	Return the application's current line and address status message settings. Synchronous.
lineGetID	Retrieves a device ID associated with the specified open line, address, or call. Synchronous.
lineGetIcon	Allows an application to retrieve an icon for display to the user.  Synchronous.
lineConfigDialog	Causes the provider of the specified line device to display a dialog that allows the user to configure parameters related to the line device.  Synchronous.
Addresses

lineGetAddressCaps	Returns the telephony capabilities of an address. Synchronous.
lineGetAddressStatus	Returns current status of a specified address. Synchronous.
lineGetAddressID	Retrieves the address ID of an address specified using an alternate format. Synchronous.
Opening and Closing Line Devices

lineOpen	Opens a specified line device for providing subsequent monitoring and/or control of the line. Synchronous.
lineClose	Closes a specified opened line device. Synchronous.
Address Formats

lineTranslateAddress	Translates between an address in canonical format and an address in dialable format.  Synchronous.
lineSetCurrentLocation	Sets the location used as the context for address translation.  Synchronous.
lineSetTollList	Manipulates the toll list. Synchronous.
lineGetTranslateCaps	Returns address translation capabilities.  Synchronous.
Call States and Events

lineGetCallInfo	Returns mostly constant information about a call. Synchronous.
lineGetCallStatus	Returns complete call status information for the specified call. Synchronous.
lineSetAppSpecific	Sets the application-specific field of a call's information structure. Synchronous.
Request Recipient Services

These functions are used only in support of assisted telephony.

lineRegisterRequestRecipient	Registers or deregisters the application as a request recipient for the specified request mode. Synchronous.
lineGetRequest	Gets the next request from the Telephony DLL.  Synchronous.
Making Calls

lineMakeCall	Makes an outbound call and returns a call handle for it. Asynchronous.
lineDial	Dials (parts of one or more) dialable addresses. Asynchronous.
Answering Inbound Calls

lineAnswer	Answers an inbound call. Asynchronous.
Toll Saver Support

lineSetNumRings	Indicates the number of rings after which inbound calls are to be answered. Synchronous.
lineGetNumRings	This function returns the minimum number of rings requested with lineSetNumRings. Synchronous.
Call Privilege Control

lineSetCallPrivilege	Sets the application's privilege to the privilege specified.  Synchronous.
Call Drop

lineDrop	Disconnects a call, or abandons a call attempt in progress. Asynchronous.
lineDeallocateCall	Deallocates the specified call handle. Synchronous.
Call Handle Manipulation

lineHandoff	Hands off call ownership and/or changes an application's privileges to a call. Synchronous.
lineGetNewCalls	Returns call handles to calls on a specified line or address for which the application does not yet have handles.  Synchronous.
lineGetConfRelatedCalls	Returns a list of call handles that are part of the same conference call as the call specified as a parameter. Synchronous.


Supplementary Telephony Services

The supplementary telephony functions are listed below by category. Line services are listed first, phone services next. A function is identified as "asynchronous" if it might return before making a call to the application's reply callback function. Otherwise, the function is considered synchronous.


Line Services

Bearer Mode and Rate

lineSetCallParams	Requests a change in the call parameters of an existing call. Synchronous.
Media Monitoring

lineMonitorMedia	Enables or disables media mode notification on a specified call. Synchronous.
Digit Monitoring and Gathering

lineMonitorDigits	Enables or disables digit detection notification on a specified call. Synchronous.
lineGatherDigits	Performs the buffered gathering of digits on a call. Synchronous.
Tone Monitoring

lineMonitorTones	Specifies which tones to detect on a specified call. Synchronous.
Media Control

lineSetMediaControl	Sets up a call's media stream for media control. Synchronous.
lineSetMediaMode	Sets the media mode(s) of the specified call in its LINECALLINFO structure.  Synchronous.
Generating Inband Digits and Tones

lineGenerateDigits	Generates inband digits on a call. Synchronous.
lineGenerateTone	Generates a given set of tones inband on a call. Synchronous.
Call Accept and Redirect

lineAccept	Accepts an offered call and start alerting both caller (ringback) and called party (ring). Asynchronous.
lineRedirect	Redirects an offering call to another address. Asynchronous.
Call Reject

lineDrop	See table for Basic Telephony. Asynchronous.
Call Hold

lineHold	Places the specified call on hard hold. Asynchronous.
lineUnhold	Retrieves a held call. Asynchronous.
Making Calls

lineSecureCall	Secures an existing call from interference by other events such as call-waiting beeps on data connections. Asynchronous.
Call Transfer

lineSetupTransfer	Prepares a specified call for transfer to another address. Asynchronous.
lineCompleteTransfer	Transfers a call that was set up for transfer to another  call, or enter a three-way conference. Asynchronous.
lineBlindTransfer	Transfers a call to another party. Asynchronous.
lineSwapHold	Swaps the active call with the call currently on consultation hold. Asynchronous.
Call Conference

lineSetupConference	Prepares a given call for the addition of another party. Asynchronous.
linePrepareAddToConference	Prepares to add a party to an existing conference call by allocating a consultation call that can later be added to the conference call that is placed on conference hold. Asynchronous.
lineAddToConference	Adds a consultation call to an existing conference call. Asynchronous.
lineRemoveFromConference	Removes a party from a conference call. Asynchronous.
Call Park

linePark	Parks a given call at another address. Asynchronous.
lineUnpark	Retrieves a parked call. Asynchronous.
Call Forwarding

lineForward	Sets or cancels call forwarding requests. Asynchronous.
Call Pickup

linePickup	Picks up a call that is alerting at another number. Picks up a call alerting at another destination address and returns a call handle for the picked up call (linePickup can also be used for call waiting). Asynchronous.
Sending Information to Remote Party

lineSendUserUserInfo	Sends user-to-user information to the remote party on the specified call. Asynchronous.
Call Completion

lineCompleteCall	Places a call completion request. Asynchronous.
lineUncompleteCall	Cancels a call completion request. Asynchronous.
Setting a Terminal for Phone Conversations

lineSetTerminal	Specifies the terminal device to which the specified line, address events or call media stream events are routed. Asynchronous.


Phone Services

TAPI Initialization and Shutdown

phoneInitialize	Initializes the Telephony API phone abstraction for use by the invoking application. Synchronous.
phoneShutdown	Shuts down the application's use of the phone Telephony API. Synchronous.
Phone Version Negotiation

phoneNegotiateAPIVersion	Allows an application to negotiate an API version to use. Synchronous.
Opening and Closing Phone Devices

phoneOpen	Opens the specified phone device, giving the application either owner or monitor privileges. Synchronous.
phoneClose	Closes a specified open phone device. Synchronous.
Phone Status and Capabilities

phoneGetDevCaps	Returns the capabilities of a given phone device. Synchronous.
phoneGetID	Returns a device ID for the given device class associated with the specified phone device. Synchronous.
phoneGetIcon	Allows an application to retrieve an icon for display to the user. Synchronous.
phoneConfigDialog	Causes the provider of the specified phone device to display a dialog that allows the user to configure parameters related to the phone device. Synchronous.
Hookswitch Devices

phoneSetHookSwitch	Sets the hookswitch mode of one or more of the hookswitch devices of an open phone device. Asynchronous.
phoneGetHookSwitch	Queries the hookswitch mode of a hookswitch device of an open phone device. Synchronous.
phoneSetVolume	Sets the volume of a hookswitch device's speaker of an open phone device. Asynchronous.
phoneGetVolume	Returns the volume setting of a hookswitch device's speaker of an open phone device. Synchronous.
phoneSetGain	Sets the gain of a hookswitch device's mic of an open phone device. Asynchronous.
phoneGetGain	Returns the gain setting of a hookswitch device's mic of an opened phone. Synchronous.
Display

phoneSetDisplay	Writes information to the display of an open phone device. Asynchronous.
phoneGetDisplay	Returns the current contents of a phone's display. Synchronous.
Ring

phoneSetRing	Rings an open phone device according to a given ring mode. Asynchronous.
phoneGetRing	Returns the current ring mode of an opened phone device. Synchronous.
Buttons

phoneSetButtonInfo	Sets the information associated with a button on a phone device. Asynchronous.
phoneGetButtonInfo	Returns information associated with a button on a phone device. Synchronous.
Lamps

phoneSetLamp	Lights a lamp on a specified open phone device in a given lamp lighting mode. Asynchronous.
phoneGetLamp	Returns the current lamp mode of the specified lamp. Synchronous.
Data Areas

phoneSetData	Downloads a buffer of data to a given data area in the phone device. Asynchronous.
phoneGetData	Uploads the contents of a given data area in the phone device to a buffer. Synchronous.
Status

phoneSetStatusMessages	Specifies the status changes for which the application wants to be notified. Synchronous.
phoneGetStatusMessages	Returns the status changes for which the application wants to be notified. Synchronous.
phoneGetStatus	Returns the complete status of an open phone device. Synchronous.


Extended Telephony Services

The extended telephony functions for both line and phone devices are listed below by category.

Extended Line Services

lineNegotiateExtVersion	Allows an application to negotiate an extension version to use with the specified line device. Asynchronous.
lineDevSpecific	Device-specific escape function. Synchronous.
lineDevSpecificFeature	Device-specific escape function to allow sending switch features to the switch. Asynchronous.
Extended Phone Services

phoneDevSpecific	Device-specific escape function to allow vendor dependent extensions. Asynchronous.
phoneNegotiateExtVersion	Allows an application to negotiate an extension version to use with the specified phone device. Synchronous.


Telephony Configuration Parameters

About Telephony Coniguration Parameters

Note  The TELEPHON.INI file is used for backward compatibility with existing 16-bit Telephony applications. Win32-based applications should never attempt to access this file directly. Instead use functions such as lineGetAppPriority and lineSetAppPriority to get and set configuration information.

This appendix specifies the configuration parameters associated with Windows Telephony. These parameters are manipulated by Control Panel applets, Telephony service providers, and Telephony applications. Much of the configuration information related to TAPI, such as the default priorities users wish to assign to applications () , is stored in the TELEPHON.INI file. A small amount of information is stored in the file WIN.INI. Priorities are used to determine which of two or more applications capable of accepting an incoming call of a given media mode (such as "datamodem") actually receives the call. Telephony applications should offer a Preferences option that, according to the application design, can let users reset the current application's priority. These settings remain constant in TELEPHON.INI until changed by a later edit.

Note  The only section of TELEPHON.INI that is of interest to application programmers is the [HandoffPriorities] section. All other sections of TELEPHON.INI are to be modified only by service providers or Telephony Control Panel applets, and should not be modified in any way by Telephony applications.

In the TELEPHON.INI file, filenames that are either longer than the standard 8.3 filename format or use characters that are not valid in the 8.3 format must be enclosed in double quotation marks. Any filename without quotes is assumed to be a standard 8.3 filename.


WIN.INI

Most Windows Telephony parameters are stored in TELEPHON.INI. The entry in WIN.INI is to inform Telephony service providers and applications of the last date and time that TELEPHON.INI was changed, and so the WM_WININICHANGE messages can be issued to inform active applications and drivers of changes. The section consists of a single entry.

[Windows Telephony]
TelephonINIChanged=yyyy-mm-dd hh:mm:ss

For example,

TelephonINIChanged=1993-06-03 16:48:56

would indicate that TELEPHON.INI was last updated on June 3, 1993, at 4:48:56 p.m.

This document is the specification for the configuration parameters associated with Windows Telephony. These parameters are manipulated by Control Panel applets, Telephony service providers, and Telephony applications.


Providers

The "[Providers]" section of TELEPHON.INI specifies the permanent provider IDs and filenames of installed Telephony service providers. This information is used so that TAPI can identify and load each provider.

This section uses the following format:

[Providers]
NumProviders=<count>
NextProviderID=<nextPPID>
ProviderID<index>=<PPID>
ProviderFilename<index>=<filename>

For example:

[Providers]
NumProviders=2
NextProviderID=5
ProviderID0=3
ProviderFilename0=UNIMODEM.TSP
ProviderID1=4
ProviderFilename1=PDI-1000.TSP

The NumProviders entry indicates how many service providers are installed (and how many ProviderID<index> and ProviderFilename<index> entries appear in the section). The NextProviderID entry indicates the Permanent Provider ID (<nextPPID>) that will be assigned to the next provider to be installed. Both parameters are set to 0 when Telephony is installed; the values are subsequently controlled by any software that installs or removes service providers, such as the Windows Telephony Control Panel.

The ProviderID<index> entry (one per provider) assigns a permanent <PPID> to a Telephony service provider; this ID is used to link parameters in other sections and files to the provider information. These entries are created by any software that installs or removes service providers, such as the Windows Telephony Control Panel.

The ProviderFilename<index> (one per provider) identifies the filename (in \WINDOWS\SYSTEM) of the service provider DLL. These entries are created by any software that installs or removes service providers, such as the Telephony Control Panel.

In both the ProviderID<index> and ProviderFilename<index> entries, <index> takes values from 0 to one less than <count> (as specified in NumProviders). These entries are renumbered as providers are deleted, but the permanent provider IDs are not changed.


Provider-Specific Sections

For each telephony service provider defined in the [Providers] section, there must be a [Provider<PPID>] section. The <PPID> value is the Permanent Provider ID defined for that service provider in the corresponding ProviderID<index>=<PPID> entry in the [Providers] section. For example, corresponding to an entry such as "ProviderID2=278" there would be a section named "[Provider278]".

It is the responsibility of the service provider to create its provider-specific section in TELEPHON.INI at the time the TSPI_providerInstall function is called. It is also the responsibility of the provider to delete its provider-specific section in TELEPHON.INI at the time the TSPI_providerRemove function is called. The provider may update the information in the section whenever TSPI_providerConfig, TSPI_lineConfigDialog, or TSPI_phoneConfigDialog is called, or at other times when appropriate. Only the service provider writes entries in its provider-specific section; neither TAPI nor any other Windows Telephony component writes any entries to provider-specific section. TAPI reads only two entries in the provider-specific section—NumLines and NumPhones (defined below)—and all other entries in the section are the responsibility of the provider.

Every provider-specific section in TELEPHON.INI specifies, at a minimum, the number of lines and phones supported (or currently configured, for providers which support multiple devices) by that provider. This section consists, at a minimum, of the following:

[Provider<PPID>]
NumLines=<count>
NumPhones=<count>

For example:

[Provider3]
NumLines=1
NumPhones=0

The service provider may include any other entries in its section which are necessary to fulfill the responsibilities of the provider as specified in the Windows Telephony Service Provider Interface Specification, or for other private configuration purposes. In particular, it is the responsibility of the service provider to provide unique device IDs for every line and phone device, which are valid over a long span of time.

The 32-bit permanent device IDs which appear on the Telephony API and SPI (as with the LINEDEVCAPS and PHONECAPS structures) are made up of a combination of the permanent provider ID (high word, range 0 to 32767) and the permanent device ID (low word, range of 0 to 32767). If the provider supports multiple line or phone devices, it must provide a way to maintain unique IDs. One mechanism to accomplish this would be to define the following entries in the provider section:

NextLineID=<PLID>
NextPhoneID=<PFID>
LineID<index>=<PLID>
PhoneID<index>=<PFID>

If no Phone devices are supported by the provider, then only the "Line" entries need be included, and vice-versa (however, NumLines and NumPhones must always be included). NextLineID and NextPhoneID would be used (like NextProviderID) to indicate the next permanent ID to be used (in an increasing fashion to minimize reusing of ID values).

The LineID<index> and PhoneID<index> entries provide convenient, permanent "partial ID" tags that are independent of the permanent Provider ID assigned. If this scheme of partial ID tags is used, it is suggested that other device-specific parameters (such as the "friendly name" of a device) be linked on the basis of the permanent ID tag; this way, it is not necessary to renumber those other parameters if a line or phone is deleted. For example, if the third line device on a provider has permament line ID 257, and has a couple of additional parameters, they could be stored in TELEPHON.INI as follows:

LineID3=257
LineName257="Microsoft ATSP"
LinePortDevice257="COM4"
LineInitString257="ATM2L0X0"

Of course, this tagging of additional parameters is not necessary if the provider supports one, and only one, device. In that case, only the NumLines and NumPhones entries need be included; other parameters can have arbitrary, non-indexed names. Also, providers may choose to use an entirely different mechanism for assigning permanent device IDs as long as the requirements that the IDs be unique and contain the permanent provider ID in their high-order word are obeyed.


Handoff Priorities

The "[HandoffPriorities]" section of TELEPHON.INI specifies the priority of applications to handle incoming calls and call handoffs of particular media types and for Assisted Telephony requests. It should be modified only by the writer of the telephonic application.

When a call is initially received or handed off, TAPI checks the applications that have the line open to determine which of them expressed interest in calls of the current media mode (specified by the provider or application handing off the call). If more than one application has the line open and is interested in calls of the current media mode, TAPI checks the priorities specified in this section to determine which application will get the call. For each media type, applications are listed in the "[HandoffPriorities]" section of TELEPHON.INI in order of preference (earlier ones in the list are preferred over later ones). In other words, TAPI attempts first to choose as the target of the handoff the first listed application that has the line open for that media type.

Applications can also be targets of handoffs without being listed. Among unlisted applications, the order of preference is arbitrary, but listed applications are preferred to unlisted applications. There is no direct association between the media modes for which applications are registered and particular media stream APIs; it is up to the application to know which API is used to access a particular media stream.

Likewise, when a Assisted Telephony request is received, TAPI checks the applications that have registered to process that type of request. If more than one application has has registered for that type of request, TAPI checks the priorities specified in this section to determine which application will be signalled to process the request (with the highest priority being assigned to the first listed application under that request type, and proceeding in the order listed). If none of the open, interested applications are listed in the corresponding request entry in this section (or if there is no entry for that request type), the application to receive the request indication is arbitrary.

If no application is registered to handle the request type (for a tapiRequestMakeCall or tapiRequestMediaCall), TAPI attempts to launch the applications listed in this section, in order, until one of them successfully starts up. The request then remains pending until an application (perhaps the one that launched) registers to receive it.


Handoff Priorities Entries

Users may manipulate the entries in [HandoffPriorities] directly, although it's better that they use the Preferences settings of Telephony-aware applications. Such applications should be capable of adding entries to [HandoffPriorities] for all the media modes and request types they support, and of rearranging the application names in entries in the section (to set themselves as the highest priority, for example). Entries in the [HandoffPriorities] section are not manipulated through the Telephony control panel.

The [HandoffPriorities] section has the following format:

[HandoffPriorities]
RequestMakeCall=[<appname>[,<appname>]...]
RequestMediaCall=[<appname>[,<appname>]...]
unknown=[<appname>[,<appname>]...]
interactivevoice=[<appname>[,<appname>]...]
automatedvoice=[<appname>[,<appname>]...]
g3fax=[<appname>[,<appname>]...]
g4fax=[<appname>[,<appname>]...]
datamodem=[<appname>[,<appname>]...]
teletex=[<appname>[,<appname>]...]
videotex=[<appname>[,<appname>]...]
telex=[<appname>[,<appname>]...]
mixed=[<appname>[,<appname>]...]
tdd=[<appname>[,<appname>]...]
adsi=[<appname>[,<appname>]...]
digitaldata=[<appname>[,<appname>]...]
NumExtends=<count>
extend<index>=<extid0>,<extid1>,<extid2>,<extid3>,<bit>,"<friendlyname>"
    [,<appname>[,<appname>]...]

where each <appname> is the module filename of a Windows Telephony application.

The first two entries correspond to the request types defined in LINEREQUESTMODE (LINEREQUESTMODE_DROP requests are automatically routed to the same application which handles LINEREQUESTMODE_MEDIACALL requests, since only media calls can be dropped in Assisted Telephony; therefore, the same priorities apply to both).

The next 13 entries correspond to the standard LINEMEDIAMODEs defined in the Telephony API Specification.

NumExtends provides a count of the number of extend<index> lines which follow (with <index> taking values from 0 through <count>-1). By default, it is set to 0. It may be adjusted by any application which adds or deletes an extended media mode.

Each extend<index> line gives the four DWORDs of the Extension Identifier for the extension set, a bit identifier corresponding to the LINEMEDIAMODE bit assigned in that extension set, a friendly name for the media mode (assigned by the provider or application, based on a priori knowledge), and the application priorities.

Note  If an application expects to use an extended media mode, it must ensure that TELEPHON.INI contains an entry defining that media mode. Otherwise, TAPI may not be able to handle incoming calls or call handoffs properly for that (extended) media mode.

<extid0>, <extid1>, <extid2>, and <extid3> shall each be expressed as exactly eight ASCII hex digits. For example, if the EXTIDGEN program outputs an extension ID as:

dwExtensionID0 = 0xA2A9E740;
dwExtensionID1 = 0xA0A51068;
dwExtensionID2 = 0x968A0800;
dwExtensionID3 = 0x2B312E8A;

the extension ID would be specified in an extend<index> entry as:

extend<index>=A2A9E740,A0A51068,968A0800,2B312E8A,...

<bit> shall be a single decimal digit with a value from 1 to 8. These identifiers correspond to the following bit values in LINEMEDIAMODE (which are the only values available for assignment to proprietary media modes in provider extensions):

1    0x80000000
2    0x40000000
3    0x20000000
4    0x10000000
5    0x08000000
6    0x04000000
7    0x02000000
8    0x01000000

The following steps are used to add a new extend<index> entry:

1.	If <count> is already equal to 32767, no more extend<index> can be added.

2.	Obtain <extid0>, <extid1>, <extid2>, <extid3>, <bit>, and <friendlyname> from a priori knowledge.

3.	Add an extend<index> entry to the section, with <index> set to the value of <count>.

4.	Increment <count> by 1. Update the extends entry to show the new value of <count>.

5.	Update TelephonINIChanged, and issue a WM_WININICHANGE message.

The following steps are used to delete an extend<index> entry:

1.	Scan the extend<index> entries to find the entry to be deleted. If it is the last extend<index> (<index> is equal to <count>-1), skip step 2.

2.	Copy the information for all higher-numbered extend<index> entries to one lower value of <index> (for example, copy extend6 to extend5). This will leave the highest-numbered extend<index> entry duplicating the next to highest-numbered extend<index> entry.

3.	Delete the highest numbered extend<index> entry (<index> equal to <count>-1)

4.	Decrement <count> by 1.

5.	Update the extends entry to show the new value of <count>.

6.	Update TelephonINIChanged, and issue a WM_WININICHANGE message.

Note that duplicate entries in the [HandoffPriorities] section are not allowed. For example, if two (or more) entries exist in TELEPHON.INI such as

G3fax=<some stuff>
G3fax=<more stuff>

or,

extension<index>=<extension ID>,bit, <some stuff>
extensiony=<extension ID>,bit, <more stuff>

actual application priorities for these media modes are arbitrary.

Also note that leading "0x" as in "0x <extensionID> is not allowed in the TELEPHON.INI file format.


Locations

The "[Locations]" section of TELEPHON.INI specifies the locations that are defined by the user. A Location includes a user-defined name, the prefixes necessary to obtain access to an "outside line" at the location, the country code and area/city code of the location, the preferred dialing method for calls placed at the location, and additional information about dialing calls. This information is maintained by the Telephony Control Panel applet.

This section will have the following format:

[Locations]
Locations=<count>,<nextID>
Location<index>=<id>,"<friendlyname>","<localprefix>","<LDprefix>",
"<areacode>",<countrycode>,<preferredcardid>,<hint>,
    <insertareacode>,"<tollprefixes>"
CurrentLocation=<id>,<hint>

For example:

[Locations]
Locations=3,458
Location0=0,"Default Location","","","206",1,0,0,1,""
Location1=233,"Seattle Office","9,","9,","206",1,0,0,
    1,"223,224,233,281,282,283,284,285,286,287,..."
Location2=457,"Boston Office","9","8","617",1,2,2,1,
    ""
CurrentLocation=233,1

The Locations entry indicates how many locations are defined (and how many Location<index> entries appear in the section) with the <count> parameter, and the next permanent location ID to be assigned with the <nextID> parameter. Both parameters are set to 0 when Telephony is installed; the value is subsequently controlled by the Locations function of the control panel.

Each Location<index> entry identifies a location, and gives its permanent ID (used to link parameters in other files to the location). "<index>" takes values from 0 to one less than <count>. These entries may be renumbered as locations are deleted. Location0 is the "Default Location", and can never be removed; its <id> is always 0, its name should not be changed, but all of the other parameters may be changed by the user.

Within each Location<index> entry, the individual fields have the following meanings:

<id> is the permanent ID for the location, which is used to link parameters to other files to the location. Once a permanent ID is assigned to a location, it is never changed. These IDs shall be in the range 0 to 32767 (when 32767 is used, <nextID> shall wrap to 0).

"<friendlyname>" is the user-assigned name for the location, entered through the Telephony control panel. It must be enclosed in quotation marks, and must not contain quotation marks.

"<localprefix>" is the dialable string to be dialed before all calls determined to be "local" (same country, same area code, not in the toll list).

"<LDprefix>" is the dialable string to be dialed before all calls that are not local (different country, different area code, or in the toll list).

"<areacode>" is the area/city code associated with the current location. If this is empty, the current country is presumed to have a flat numbering system without city codes (all local numbers unique throughout the country). This is used in determining whether the canonical number is local or long distance.

<countrycode> is the country code associated with the current location. This is linked to an entry in the "[Countries]" section to determine the dialing procedures when the selected dialing method is "Direct" (CallingCard permanent ID 0); if the code does not match an entry in the [Countries] section, then canonical translation fails and the number is returned unmodified. It is also used in determining whether the canonical number is local or long distance. This value is returned with the lineTranslateAddress function of the Telephony API.

<preferredcardid> is the preferred dialing method which will be preselected when the user requests a dialing operation. It must match one of the permanent IDs of an entry in the [Cards] section; if it does not, it is presumed to be 0 ("Direct").

<hint> indicates the number of the Card<index> entry which matched <preferredcardid> at the time this Location<index> was last modified; to save time, the DLL can check this entry first when trying to find the information on the Card<index>, before scanning all cards (which should only be necessary after a card entry is removed).

<insertareacode> shall have a value of 0 or 1. 0 indicates that toll calls should not include the area code before the local number; 1 indicates that toll calls should have the area code before the local number. This is applicable only when <countrycode> is 1 (North America), the country code and area code being dialed are the same as for the current location, and the prefix of the local number appears in <tollprefixes>.

"<tollprefixes>" is a list of three-digit prefixes for calls which receive special treatment. If the country code for the current location is 1, the country code and area code being dialed are the same as for the current location, and the prefix of the local number matches an entry in this list, then the number will be dialed according to the <longdistance> dialing rule rather than the <samearea> dialing rule. The inclusion of the area code as part of the local number can be controlled by the <insertareacode> parameter. The entries within the list consist of three-digit numbers, separated by comma characters (0x2C), preferably sorted in ascending numeric order.

The CurrentLocation entry gives the <id> of the location at which the user is presently located. The value should match an <id> in an existing Location<index> entry; if it does not, the current location should be assumed to be the default location (permanent ID 0). CurrentLocation should be set to "0,0" when TELEPHON.INI is first created. The <hint> parameter indicates the number of the Location<index> entry which matched <id> at the time CurrentLocation was last set; to save time, the DLL can check this entry first when trying to find the information on the CurrentLocation, before scanning all locations (which should only be necessary after a location is removed).


Calling Cards

The "[Cards]" section of TELEPHON.INI specifies information related to a method of dialing telephone calls. This method may, or may not, include an associated telephone calling card number (the dialing methods are referred to generically as "calling cards" because use of a calling card is the most frequent reason for using an alternative dialing procedure). The calling card numbers are scrambled to provide security against non-determined, casual observation (for example, someone looking at the TELEPHON.INI file with a text editor); greater security will depend on system-level file or system access security (such as in case a notebook computer is stolen).

This section will have the following format:

[Cards]
Cards=<count>,<nextID>
Card<index>=<id>,"<friendlyname>","<scrambledcardnum>",
    "<samearea>","<longdistance>","<international>",<hidden>

For example:

[Cards]
Cards=5,4
Card0=0,"None (Direct Dial)","","","","",0
Card1=1,"AT&T via 10288","438 293 482 1938",
    "102880FG$H","102880FG$H","1028801EFG$H",0
Card2=2,"AT&T via 1-800-321-0288","",
    "18003210288$FG$H","18003210288$FG$H",
    "18003210288$01EFG$H",1
Card3=3,"Direct With Security Code",
    "","G","1FG,3948","011EFG,3948",0
Card4=4,"USA Direct from Italy","549 304 593 2049",
    "","","P1721011$TFG$H",0

The Cards entry indicates how many locations are defined (and how many Card<index> entries appear in the section) with the <count> parameter, and the next permanent card ID to be assigned with the <nextID> parameter. The values of these parameters are controlled by the Telephony control panel. Their initial settings when Telephony is installed is dependent on the number of predefined Card<index> entries shipped.

Each Card<index> entry identifies a card, giving its permanent ID (used to link parameters in other files to the card). "<index>" takes values from 0 to one less than <count>. These entries may be renumbered as cards are deleted. Card0 shall not be removable or modifiable by the user; it is a placeholder used to indicate that the direct dialing rules for the country specified in CurrentLocation should be used for dialing.

The parameters included in each Cardx entry are as follows:

<id> is the permanent ID associated with this card, assigned by the control panel. Once assigned, it is never changed. It is used to link the <preferredcardid> for a Location<index> entry to the associated card in a manner insensitive to the insertion and remove of Card<index> entries. These IDs shall always be in the range of 0 to 32767.

"<friendlyname>" is the user-assigned name for the card. It must be enclosed in quotation marks and may not contain quotation marks.

"<scrambledcardnum>" is the card number associated with this entry (if any; it may be "" for a Card<index> entry which actually specifies alternative direct dial rules). The contents are scrambled in order to provide security from accidental viewing.

"<samearea>", "<longdistance>", and "<international>" are the dialable string templates for the three classes of calls (same area code, different area code but same country, and different country code, respectively). The contents of these strings should be selected from the following list (spaces, hyphens, periods, and parentheses may be included for formatting purposes):

0-9	Dialable digits

A-D	Dialable digits

#	Dial DTMF "#"

*	Dial DTMF "*"

T	DTMF dial subsequent digits

P	Pulse dial subsequent digits

!	Hook flash

,	Pause during dialing

W	Wait for second dial tone

@	Wait for quiet answer

$	Wait for "bong" tone

?	Prompt user before proceeding

E	Insert country code

F	Insert area code

G	Insert subscriber number

H	Insert calling card number

I	Insert area code (area codes are optional; used in country entries only)

<hidden> determines whether or not this entry should be displayed in lists of available dialing methods displayed to the user by applications. These are delivered to applications by the lineGetTranslateCaps function. Values are as follows:

Value	Meaning
0	Not hidden. The value can be set by the user.
1	Not hidden. The value can only be set by the application (it cannot be deleted).
2	Hidden. The value can be set by the user.
3	Hidden. The value can only be set by the application (it cannot be deleted).
The function lineGetTranslateCaps will not return to the application entries for calling cards which have this parameter set to 1 and which have a null card number field.


Countries

The "[Countries]" section of TELEPHON.INI specifies the well-known direct dialing procedures for calls placed within specific countries. The contents of this section are shipped with Windows Telephony, are not intended to be edited by the user, and could, in future releases, be moved to a compressed binary file for quick access; however, the information is contained in the TELEPHON.INI file, at least in the initial release, to facilitate user editing (under the guidance of Microsoft Product Support Services) if problems are discovered.

This section will have the following format:

[Countries]
Country<index>=<countrycode>,<nextcountry>,"<name>","<samearea>",
    "<longdistance>","<international>"

For example:

[Countries]
Country1=1,100,"North America and Caribbean","G","1FG","011EFG"
Country100=1,101,"United States of America","G","1FG","011EFG"
Country101=1,102,"Anguilla","G","1FG","011EFG"
Country102=1,103,"Antigua","G","1FG","011EFG"
Country103=1,104,"Bahamas","G","1FG","011EFG"
Country104=1,105,"Barbados","G","1FG","011EFG"
Country105=1,106,"Bermuda","G","1FG","011EFG"
    ...
Country98=98,0,"Iran","G","0FG","00EFG"

There are two kinds of entries in the [Countries] section. The first, known as "primary" entries, are indicated by the <countrycode> parameter equaling the value of <index>. Primary entries specify the name of a World Numbering Plan Area as specified in CCITT Recommendation E.163, and include the direct dialing rules applicable to that numbering plan area. The second type of entries, known as "secondary" entries, are indicated by the <countrycode> parameter not being equal to the value of <index>. Secondary entries are used to specify countries which are contained within multi-country World Numbering Plan Areas (e.g, "1" for North America and Caribbean).

The <nextcountry> parameter is used by the lineTranslateCaps function when reading in the [Countries] section to build the table of countries in the LINETRANSLATECAPS structure. Country codes are non-contiguous, and this parameter allows the lineTranslateCaps function to read in the entries without either guessing at country codes or having to read in the entire section at once and parsing out the entries itself. The last country in the list shall have its <nextcountry> parameter set to 0.

"<samearea>", "<longdistance>", and "<international>" are the dialable string templates for the three classes of calls which may be direct dialed from this country. A parameter should be left empty ("") if that type of call cannot be direct dialed. The permitted contents of these strings are the same as specified above in the [Cards] section.


Call States and Events

About Call States and Events

A connection is not fully established until both parties are communicating. To reach that point, the establishment of the call goes through several stages, as does the clearing (termination) of the call. A call's events cause it to transition through call states as it comes into existence, is used to exchange information, and terminates. These call-state transitions result from both solicited and unsolicited events. A solicited event is one caused by the application controlling the call (as when it invokes TAPI operations), while unsolicited events are caused by the switch, the telephone network, the user pressing buttons on the local phone, or the actions of the remote party. Some operations on line devices, addresses, and calls may first require that the line, address, or call upon which they operate be in certain specific states.

Different call states indicate that connections exist to different parts of the switch. For example, a dial tone is a particular state of a switch that means the computer is ready to receive digits.

Whenever a call changes state, TAPI reports the new state to the application in a callback. This programming model, therefore, is one in which the application reacts to the events reported to it, as opposed to a rigid call-state model. In other words, call-state notification tells the application what the call's new state is, instead of reporting the occurrence of specific events and assuming that the application will be able to deduce the transitions between two states.


Call State Definitions

Some of the call states and events defined by TAPI are exclusive to inbound or outbound call processing, while others occur in both cases. Several of these call states provide additional information that can be used by the application. For example, the busy state signifies that a call cannot be completed because a resource between the originator and the destination is unavailable, as when an intermediate switch has reached its capacity and cannot handle an additional call. Information supplied with the busy state includes station busy or trunk busy. Station busy means that the destination's station is busy (the phone is offhook), while trunk busy means that a circuit in the switch or network is busy. The call states defined by TAPI are listed below:

Call State	Description
idle	This corresponds to the "null" state:  No "activity exists" on the call, which means that no call is currently active.
offering (inbound)	When the switch informs the computer of the arrival of a new incoming call, that call is in the offering state. Note that offering is not the same as causing a phone or computer to ring. When a call is offered, the computer is not necessarily instructed to alert the user.
	Example: An incoming call on a shared call appearance is offered to all stations that share the appearance, but typically only the station that has the appearance as its primary address is instructed to ring. If that station does not answer after some amount of time, the bridging stations may be instructed to ring as well.
accepted (inbound)	An application has taken responsibility for an incoming call. In ISDN, the accepted state is entered when the called party equipment sends a message to the switch indicating that it is willing to present the call to the called person; this has the side effect of alerting the users at both sides of the call: the caller's and the called party's. An incoming call can always be immediately answered without first being separately accepted.
dial tone (outbound)	Indicates that the switch is ready to receive a dialable number. In most telephony environments, this state is entered when audible dial tone is detected by the line device. Additional information includes:
— normal dial tone	The "normal" or everyday dial tone, usually a continuous tone.
— special dial tone	A special dial tone is often used to signal certain conditions such as message-waiting. This is usually an interrupted dial tone.
dialing (outbound)	The originator is dialing digits on the call. The dialed digits are collected by the switch.
proceeding (outbound)	The call is proceeding through the network. This occurs after dialing is complete and before the call reaches the dialed party, as indicated by ringback, busy, or answer.
special info (outbound)	The call is receiving a special information signal. A special information signal precedes a prerecorded announcement indicating why a call cannot be completed. Such announcements can be of these types:
— no circuit	A no-circuit or emergency announcement.
— customer irregularity	This typically means that the dialed number is not correct.
— reorder	A reorder or equipment-irregularity announcement.
busy (outbound)	The call is receiving a busy signal. Busy indicates that some resource is not available and the call cannot be normally completed at this time. Additional information consists of:
— station busy	The station at the other end is off-hook.
— trunk busy	The network is congested. This usually produces a "fast busy" signal.
ringback (outbound)	The station to be called has been reached, and the destination's switch is generating a ring tone back to the originator. A ringback means that the destination address is being alerted to the call.
connected (inbound and outbound)	Information is being exchanged over the call.
on hold (inbound and outbound)	The call is currently held by the switch. This frees the physical line, which allows another call to use the line.
conferenced (inbound and outbound)	The call is a member of a conference call and is logically in the connected state (to the conference bridge). A call in the conferenced state refers to a conference call (in the connected, onHold, ... state).
on hold pending conference (inbound and outbound)	The conference call is currently on hold and waiting for the user to add another party.
on hold pending transfer (inbound and outbound)	The call is on hold in preparation of being transferred.
disconnected (inbound and outbound)	The call has been disconnected by the remote party.
unknown (inbound and outbound)	The call exists, but its state is currently unknown. This may be the result of poor call progress detection by the service provider. A call state message with the callstate set to unknown may also be generated to inform the TAPI DLL about a new call at a time that that the actual call state of the call is not exactly known.
Although under normal circumstances an outbound call is likely to transition to connected through a number of intermediate states (dial tone, dialing, proceeding, ringback), other paths are often possible. For example, the ringback state may be skipped, as when a hot phone (or other non-dialed phone) transitions directly to connected.

An application should always process call-state event notifications. Call-state transitions valid for one switch or configuration may be invalid for another. For example, consider a line from the switch that (using a simple Y-connector) physically terminates both at the computer and at a separate phone set, creating a party line configuration between the computer and the phone set. The computer termination and, therefore, the application using TAPI, may not know of the activities on the line handled by the phone set. That is, the line may be in use without the service provider being aware of it. An application that wants to make an outbound call will succeed in allocating a call appearance from the API, but this results in sharing the active call on the line. In this case, blindly sending a DTMF dial string without first checking for a dial tone may not result in intended (or polite) behavior.


Obtaining Call State Information

Using the function lineGetCallStatus, an application can receive complete call status information for the specified call as a data structure of type LINECALLSTATUS. The function lineGetCallInfo returns mostly constant information about a call as a data structure of the type LINECALLINFO. The message LINE_CALLSTATE is sent unsolicited to an application to notify it about changes in a call's state.

The call-information data structure maintained for each call contains an application-specific field that applications can read from and write to. This field is not interpreted by TAPI. Applications can use it to "tag" calls in application-specific ways. Writing to this field so that the change is visible to other applications can be done with the function lineSetAppSpecific.


 Preliminary Outline

The guide to writing Extended MAPI clients and providers is in its preliminary state of conception. Many of the topics have not yet been written; other topics have not yet been reviewed for technical accuracy. This outline is included to show readers how the MAPI Programmer's Guide will be organized and to give some idea of future content. The chapters that are presented in this release are not the final versions of this material; there may be inaccuracies and missing information. Future builds of the MAPI SDK Help will include up-to-date and technically correct Extended MAPI guide information as it becomes available.

Chapter 1 - Concepts and Architecture

Chapter 2 - Introduction to MAPI Programming

Chapter 3 - Programming with CMC

Chapter 4 - Programming with Simple MAPI

Chapter 5 - About MAPI Objects

Chapter 6 - About MAPI Interfaces

Chapter 7 - About MAPI Properties

Chapter 8 - Programming with Extended MAPI

About Event Notification

Managing Memory

Handling Errors

Session Identity

Administering Profiles and Message Services

Chapter 9 - Using Tables

Chapter 10 - Using Folders

Chapter 11 - Using Messages

Chapter 12 - Using Attachments

Chapter 13 - Using Support Objects

Chapter 14 - Using Status Objects

Chapter 15 - Using Profile Sections

Chapter 16 - Programming Extended MAPI Clients

Chapter 17 - Considerations for Service Providers

Chapter 18 - Programming Address Book Providers

Chapter 19 - Programming Message Store Providers

Chapter 20 - Programming Transport Providers

Chapter 21 - Building Custom Forms


 About This Book

The MAPI Programmer's Guide is one volume in the set of documentation that accompanies the MAPI Software Development Kit (SDK). The MAPI SDK documentation will be included with the BackOffice Software Development Kit (SDK) documentation.


 Intended Audience

The MAPI Programmer's Guide is written for C and C++ developers with a wide range of needs and experience. The MAPI Programmer's Guide targets developers with limited messaging knowledge as well as developers of workgroup applications or specialized messaging system services. Because the intended audience is so varied, some chapters may apply to some developers and not others. An attempt was made to organize the book in such a way as to make it easy for readers to locate relevant material and avoid what was not applicable.

For developers intending to write basic messaging applications or enhance an application with messaging functionality, no prerequisite knowledge is necessary. For developers intending to create full-scale workgroup applications or specialized messaging system services, a background in messaging and a familiarity with the Component Object Model (COM) is recommended.


 How This Book is Organized

The MAPI Programmer's Guide is organized in chapters, beginning with a discussion of key concepts and architecture. Chapter 2 is an introduction to MAPI programming, including information that is applicable to developers of client applications and service providers. The next two chapters are tutorials for application developers writing with the Simple MAPI and CMC set of API functions. Chapters 5, 6, and 7 describe the basic building blocks of the Extended MAPI environment: objects, interfaces, and properties. Chapter 8 is an introduction to programming with Extended MAPI, presenting topics that apply to all Extended MAPI developers. The next several chapters are devoted to using specific objects. Each chapter contains a description of the interfaces and properties the object supports and information about how the object is typically used.

Chapter 16 teaches developers how to program Extended MAPI client applications. After this chapter, the material focuses on service providers. There is one chapter that applies to all developers of service providers and then individual chapters for each specific type of service provider. The last chapter discusses how to build custom forms.


 Document Conventions

This manual uses the following typographic conventions:

Convention	Description
monospaced text	Examples and program code appear in a non proportional typeface.
Bold text	Literal expressions that must be typed exactly as shown, such as function names, structure names, and keywords, appear in this bold typeface. Visual Basic custom control error messages appear in bold typeface.
Italic text	Italic text indicates new terms and variable expressions, such as parameters, where you fill in the actual value.
CAPITAL LETTERS	Filenames, directory names, paths, and MAPI function flags and error messages appear in capital letters.
(  )	In syntax statements, parentheses enclose one or more parameters that you pass to a function.
[ ]	Brackets enclose optional syntax items. Type only  the syntax within the brackets, not the brackets themselves.
	The line-continuation character indicates that code continued from one line to the next should be typed all on one line. For example: SharedExtensionsDir= \\SERVER1\SHARE1\MAILEXTS


 For More Information

For more information about OLE 2.0 programming, see Inside OLE 2, by Kraig Brockschmidt, and the OLE 2.0 Programmer's Reference, Volumes 1 and 2, published by Microsoft Press. For more information about Visual Basic programming, see your Microsoft Visual Basic documentation.


 Concepts and Architecture

As business becomes more competitive, the success of an organization increasingly depends on how quickly, smoothly, and efficiently people within that organization work together. The key to a successful organization is how well that organization manages and distributes information. Networking is an important part of teamwork because it enables fast and efficient information exchange. But networking is only part of the solution; organizations must also keep track of the information and manage its distribution. Electronic messaging systems provide these capabilities.

Electronic messaging has become critically important to enterprise computing. In fact, many organizations are looking to their electronic messaging system to take on the role of a central communications backbone, used not only for electronic-mail (e-mail) messages, but to integrate all types of information. Electronic messaging provides a way for users in organizations to retrieve information from a variety of sources, to exchange information automatically, and to store, filter, and organize the information locally or across a network.

Today, powerful enterprise-wide workgroup applications that manage group scheduling, forms routing, order processing, and project management are built on electronic messaging systems. Several different messaging systems are offered by different vendors, and a wide range of applications have been built to use them. But each of these messaging systems have different programming interfaces, making it difficult for one application to interact with several of them at once.

To solve this problem, Microsoft, along with more than 100 independent software vendors (ISVs), messaging system providers, corporate developers, and consultants from around the world, has created the Messaging Application Programming Interface (MAPI). MAPI is a messaging architecture that enables multiple applications to interact with multiple messaging systems seamlessly across a variety of hardware platforms.

MAPI is made up of a set of common application programming interfaces and a dynamic link library (DLL) component. The interfaces are used to create and access diverse messaging applications and messaging systems, offering a uniform yet separate environment for development and use and providing true independence for both. The DLL contains the MAPI subsystem which manages the interaction between front-end messaging applications and back-end messaging systems and provides a common user interface for frequent tasks. The MAPI subsystem acts as a central clearinghouse to unify the various messaging systems and shield clients from their differences.


 About MAPI Features

MAPI has several key features that enable it to provide a consistent way for developers to work with and use different messaging systems in a seamless fashion. First, MAPI is an open programming interface. An open programming interface provides services in a generic way, allowing its users to add any necessary customization. MAPI is open so that the widest variety of applications and service providers now and in the future can take advantage of this set of common interfaces. MAPI can serve all levels and types of applications, from the word processing application with minimal messaging needs to the complex workgroup application with more demanding needs. In fact, any application that has to either exchange information in a particular format, store information, or retrieve information using a set of criteria or restrictions, can benefit from using the MAPI programming interface.

Second, MAPI provides separation between the programming interface used by the messaging applications and the programming interface used by the back-end messaging system service providers. MAPI has been implemented as the messaging component of an open architecture known as the Microsoft® Windows Open Services Architecture (WOSA). WOSA standards are being developed in the areas of database, directory, security, and messaging technology. The WOSA programming interfaces allow developers to write applications and back-end services with the confidence that these products can be easily connected in a distributed computing environment.

Separating the interfaces enables a single application to use multiple messaging systems using a common, Windows-based user interface. This is a great benefit to users; they can select from a variety of systems, depending on their needs at any one time. For example, the same messaging application can receive messages from a fax, a bulletin board system, a host-based messaging system, and a LAN-based system. Messages from all of these systems can arrive in one universal inbox. Having a single application handling all of these systems not only reduces development costs but also reduces costs for application purchases, user training, and system administration.

Programmers also benefit from this separation because it removes dependencies placed on the application by the messaging system and vice versa. Programmers no longer have to take into account the idiosyncrasies of another component. They focus only on their component, whether it be a messaging system service provider or a messaging application, and MAPI handles the rest, thereby reducing development time and costs.

The third feature in the set involves cross platform support, which allows one version of an application to be run on a variety of machines. MAPI applications can be run on the 16-bit Windows 3.x platforms, the 16 and 32-bit platforms available on Windows 95 and Windows NT, and the Macintosh. Because communication in an organization typically includes fax, host-based messaging services such as DEC All-In-1, voice mail, public communications services such as AT&T EasyLink, CompuServe, MCI MAIL, and other types of services, MAPI supports more than local area network (LAN) − based messaging systems. Drivers can be written for all of these services and can be installed by users according to their needs, providing true independence from specific transport providers.

The fourth feature focuses on the depth and usability of the programming interface. MAPI is aimed at the powerful, new market of workgroup applications - applications that demand more of their messaging systems. To satisfy this market, MAPI offers much more than basic messaging in the programming interface. For example, with MAPI's programming interface, applications can format messages using fonts and color, preprocess messages according to predefined rules, and present customized views of messages and other information.

Last, MAPI is integrated with the operating system. Integration with the Windows family of operating systems enables all developers of Windows-based applications to have access to a consistent and available interface. This approach is similar to the approach used by the Windows printing system. Just as a word-processing program can print to many different printers through the Windows printing system as long as the necessary drivers are installed, so can any MAPI-compliant application communicate with any messaging system as long as the appropriate drivers, or service providers, are installed.


 About the MAPI Architecture

MAPI defines a modular architecture, as is shown in the figure below. At one end are the messaging, or client, applications. These applications are known as client applications because they are clients of the MAPI subsystem. There are basically three types of client applications; their differences are discussed in the next section. Underneath the client applications is the MAPI subsystem and related component, the MAPI spooler. The MAPI subsystem is made up of the programming interface and the common user interface. The MAPI spooler is a separate process responsible for sending messages to the appropriate messaging system.

Between the MAPI components and the underlying messaging systems sit service providers. Service providers are the drivers that sit between the world of unique messaging systems and the MAPI standard. Service providers translate requests from MAPI-complaint client applications into tasks a specific messaging system can understand. When a task is complete, the service providers translate again, converting status and information that is messaging system-specific to a MAPI format. As with client applications, there are different types of service providers. Each type handles a different messaging system service. The address book provider, for example, works with directory information while the transport provider handles message transmission and reception. Service providers are discussed more in later sections.

Figure 1.  MAPI Architecture.


 About Client Applications

MAPI client applications are divided into three categories:

•	Messaging-aware applications

•	Messaging-enabled applications

•	Messaging-based workgroup applications

A messaging-aware application does not require the services of a messaging system, but includes messaging options as an additional feature. For example, a word processing application can add a "Send" command to its File menu, enabling the user to send a document to another user.

A messaging-enabled application requires the services of a messaging system and typically runs on a network or an on-line service. An example of a messaging-enabled application is Microsoft Mail.

A more advanced client application is the messaging-based workgroup, or workflow, application. The workgroup application requires full access to a wide range of messaging system services, including storage, addressing, and transport services. These applications are designed to operate over a network without users having to manage the applications' network interaction. Examples of such applications include work flow automation programs and bulletin board services.

MAPI supports each of these types of client applications by providing in its subsystem different levels of programming interfaces. This multi-level programming interface is described in the following section.


 About the MAPI Subsystem

The MAPI subsystem contains two main parts: a part that responds to messaging calls from client applications and a part that provides an implementation of common user interface components. Within the first part is a comprehensive applications programming interface (API) called Extended MAPI. In spite of its name, Extended MAPI is not an extension of another API set. Extended MAPI is a powerful, object-oriented interface, a low level abstraction based on the OLE Component Object Model. Extended MAPI defines a set of objects that share structure and behavior, enabling developers to work with these objects in a consistent manner.

Extended MAPI has a large feature set. Application developers can use Extended MAPI to, for example, provide access to message or recipient properties, customize messages and address books, receive or send event notifications, or search through message databases for messages of a particular type. Although all types of client applications can use Extended MAPI, typically only workgroup applications and service providers need and want its power and complexity. Messaging-aware and messaging-enabled applications can get by on a simpler, more restrictive API.

To support a wider audience, MAPI built three other API sets on top of Extended MAPI: Common Messaging Calls (CMC), Simple MAPI, and OLE Messaging. Simpler to use and understand, these API sets provide messaging functionality through either C standard function calls or Visual Basic. As a client application developer, you can choose the API that is most suitable for your needs.

Figure 2 illustrates how Simple MAPI, OLE Messaging, and CMC are layered between Extended MAPI and client applications. Some client applications call directly into Extended MAPI while others call into Simple MAPI, OLE Messaging, or CMC. Calls to these higher level APIs are forwarded to Extended MAPI.

Figure 2.  MAPI's Messaging APIs.


 About the MAPI Spooler

The MAPI spooler is a separate process, responsible for sending messages to the appropriate messaging system, that is built with the MAPI subsystem DLL. The MAPI spooler plays a vital role in message receipt and delivery. When the messaging system is unavailable, the spooler stores the messages and automatically forwards them at a later time. This ability to hold onto or send data when necessary is known as store and forward, a critical feature in environments where remote connections are common and network traffic is high. The spooler runs as a background process, doing much of its work when client applications are idle, thus improving performance.

The MAPI spooler's has additional responsibilities related to message distribution. These extra duties include:

•	Keeping track of the recipient types that are handled by specific transport providers.

•	Sending new message notifications to client applications.

•	Invoking message preprocessing and postprocessing.

•	Generating message delivery reports.

•	Maintaining status on processed recipients.


 About Service Providers

Between the MAPI subsystem and the messaging systems are the various service providers. Service providers are links from MAPI client applications to an underlying messaging system. There are several types of service providers, but not all types are common. Most messaging systems include three types of services—message store, address book or directory, and message transport. MAPI supports each type of service independently, allowing a vendor to offer one or custom service providers. For example, a vendor might want to create an address book provider that uses a corporate telephone book directory of employees or create a message store provider that uses an existing database.

Service providers are typically written by software developers with specialized knowledge or experience with a messaging system. In many cases, this is the company or organization which promotes a specific messaging system. For instance, CompuServe would write address, message store, and transport providers for the CompuServe Information Service. MAPI supplies two of its own service providers: a message store provider known as the Personal Message Store (PST) and an address book provider known as the Personal Address Book (PAB). These providers can be used in isolation, as the only message store or address book providers, or in combination with other service providers.

The service providers work with MAPI to create and send messages in the following way. Messages are created using a form that is appropriate for the specific type, or class, of message. Most messages are created with the standard form that comes with the MAPI subsystem. Users address a message to one or more users or group of users, also called recipients, and enter the message's text, or body. Each recipient might be associated with an installed address book provider or have no known association. This latter type of recipient is known as a custom recipient. Custom recipients might be either temporary entries, lasting only until the message is submitted, or they might be permanent entries if they are saved in the PAB.

When the message is ready for submission, the MAPI subsystem checks to make sure each recipient represents a valid address for one of the installed transport providers. If there is a question, any ambiguous names are assigned to the appropriate address book provider to resolve. The message is placed in the outbound message store queue and the MAPI spooler takes over. The spooler finds an appropriate transport provider to handle the transmission. If the transport is available, the spooler transfers the message and the transport delivers it. If the transport is unavailable, the spooler either holds on to the message until the transport provider becomes available or sends it to another appropriate provider.

The following sections go into more detail about the different types of service providers.


 About Address Book Providers

Address book providers handle access to address list and directory information. Address list information is made up of address entries called recipients, which are users who receive messages. A recipient may be an individual messaging user or a group of users who are commonly addressed together, called a distribution list. MAPI provides containers for organizing this information. Depending on the approach of the address book provider, the data can be held in either a single container or multiple containers and the containers can be organized as a flat list or hierarchically.

Although multiple address book providers can be installed simultaneously, MAPI integrates all the information supplied by the address book providers into a single address book, presenting a unified view to the client application. The integrated list shows the top-level containers displayed by each of the installed address book providers. Most address book providers will expose a few containers (typically one to three) at the top level for inclusion in the top level of MAPI's integrated address book. For example, an address book provider might make available "All Users" and "Local Users" as two containers at the top level.

When you use Extended MAPI, you can view the contents of address book containers and, in some cases depending on the address book provider, add new entries and modify existing entries. The PAB is a special address book container because it allows users to store copies of frequently used addresses. The PAB also maintains entries for recipients who are not in the main address book of the underlying messaging system. These custom recipients may be created for the duration of the session only or be stored in the PAB for greater longevity.

Figure 3 shows typical MAPI address book organization.


 About Message Store Providers

In a typical messaging environment, users and applications can generate a large number of messages that must be saved and organized in some manner. Each message store provider implements a hierarchical system for saving and organizing messages known as a message store. Like address book providers, message store providers also use MAPI containers for organization. Message stores containers, known as folders, can contain messages and other folders. Folders provide the means for sorting and filtering messages and for customizing their view in the user interface display. Special folders called search-results folders hold links to messages in other folders that satisfy search criteria entered by a user. Search-results folders allow users to look for messages that arrived before the first of May or were sent by John Smith, for example.

MAPI messages contain the text that makes up the body of the message, information that allows the message to be sent, and possibly one or more attachments. The body of the message can be in plain text or formatted, using special fonts, colors, or styles. An attachment is additional data related to and transported with a message in the form of a file, another message, or an OLE object.

Messages that can be stored in the message store include those received from other users or applications as well as those currently being composed by the user. If a message is copied into multiple folders, each copy appears as a separate message and can be copied, deleted, or modified individually. Some message store providers allow messages, once received, to be changed and stored back in their folders. For example, a user could rotate a fax message that arrived upside down and store it right side up for later viewing.

The hierarchical message store architecture is shown in the figure below.

Figure 4.  Message Store Hierarchy.


 About Transport Providers

Transport providers handle message transmission and reception; they control the interaction between the MAPI spooler and the underlying messaging system and implement security if necessary. They also take care of any pre-processing and post-processing tasks that are necessary. Multiple transport providers may be installed for a single session; there is typically one transport provider for every active messaging system.

Clients communicate with the transport provider via the MAPI spooler. The spooler sends messages to and accepts messages from the transport provider. Incoming messages are delivered to the appropriate message store provider. When possible, calls to the transport provider are made when client applications are idle. Transport providers and the MAPI spooler operate in the background except at logon time and when asked by the client application to flush the transmit and receive queues.

Transport providers register with MAPI to handle one or more particular types of addresses. When a message is ready to be sent, the MAPI spooler looks at each recipient and determines which transport provider should handle the transmission. Depending on the type of recipient, the MAPI spooler can even call upon more than one transport provider. If the spooler's first choice is unavailable, and another transport provider has also registered to handle the specific recipient type, the spooler sends the message to the alternate provider. If the unavailable transport is the only one that can handle the recipient, there is no choice except to wait until a connection with that provider can be reestablished.

Some messaging systems are secure systems; all potential users are required to enter a set of valid credentials before access is permitted. MAPI prevents unauthorized access to such secure messaging systems by having the transport provider validate credentials at logon time.


 About the MAPI User Interface

MAPI provides a set of common dialog boxes that offer a consistent way for users to interact with messaging systems. Simple MAPI, CMC, and OLE Messaging client applications are presented with these dialogs automatically. Extended MAPI clients and service providers have the choice between using the MAPI dialog boxes or implementing their own. Unless there are very customized needs, it makes sense to take advantage of the MAPI user interface. Developers will save time and give their users tools that are consistent across applications and messaging systems.

The MAPI user interface provides many different dialog boxes, some for session start up, some for addressing, some for message composition. The message composition dialog box is used to create interpersonal messages; to create messages of other types you can use special dialog boxes, or forms, that may be provided by the originator of the message type. Implementing and displaying these special forms is discussed in detail in the chapter on building custom forms.


 Introduction to MAPI Programming

This chapter presents some of the issues that are important to consider before beginning serious development work. The chapter is divided into three sections, starting with information about installing and using the MAPI Software Development Kit (SDK). The next section presents information of interest primarily to client application developers: how to choose between the four client APIs (Extended or Simple MAPI, CMC, and OLE Messaging) and how to create a client application that takes advantage of more than one client API. The last section describes the logon process and how profiles and message services are created and configured.


 Installing the MAPI SDK

The MAPI Software Development Kit (SDK) includes tools to help you develop your providers and your message service. You can install and use the MAPI SDK on any computer that meets the minimum qualifications for Microsoft Windows version 3.1 (enhanced mode only), Microsoft Windows NT, or Windows 95. Before installing the MAPI SDK, you must verify that the computer contains a Microsoft Windows SDK and either a Microsoft Windows-compatible C or C++ compiler.

The MAPI SDK contains the following components:

•	MAPI setup program

•	MAPI header files

•	MAPI libraries and DLLs

•	MAPI executable files

•	Sample client applications and service provider DLLs

•	MAPI spooler

•	Help files


 Using the MAPI Setup Program

The setup program, SETUP.EXE, installs the MAPI SDK. SETUP.EXE decompresses and copies the SDK software from the SDK CD to your hard disk and adds a MAPI program group to your Program Manager window.

1.	Insert Disk 1 or the CD-ROM disc into the appropriate drive.

2.	Using the Windows File Manager, select the CD drive and double-click the SETUP.EXE file in the root directory. SETUP.EXE will automatically perform the rest of the installation.

SETUP.EXE decompresses and copies the SDK software from the SDK disks or CD-ROM to your local disk and adds a MAPI program group to your Program Manager window.

SETUP.EXE asks whether you want a complete or a custom installation. Selecting a complete installation copies all of the MAPI files to the appropriate directories. Selecting a custom installation allows you to select specific files. SETUP.EXE displays information about each individual component and prompts you for a decision on whether or not to install each one.


 Using the Samples

The MAPI SDK contains a variety of samples and tools in C, C++, and Visual Basic. There are samples for each type of client application and service provider, including several different transport providers and a hook provider. There are tools for accessing properties and tables. For configuration, MAPI provides two applications: a Control Panel applet for full configuration support and the Profile Wizard.

The following table lists the MAPI SDK samples and tools by name and provides a brief description:

MAPI SDK Component	Description
PROPVU.DLL	Tool for displaying and changing properties.
SAMPLE.AB	Sample address book provider written in C.
SAMPLE.MS	Sample message store provider written in C.
SAMPLE.XP	Sample transport provider written in C.
ABVIEW.DLL	Tool for displaying and changing address book objects.
MDBVIEW.DLL	Tool for displaying and changing message store objects.


 Issues Affecting Client Applications

These next two sections apply to developers of new or existing client applications. As a client application developer, you have a choice between one or more sets of APIs. The first section will help you to decide which of the sets is right for your application. The second section discusses how to merge Extended MAPI with another API in your application.


 Selecting a Client Programming Interface

Choosing between one of the four client APIs might be an easy decision for some client developers. Maybe you only know one language and you have no time to learn another. Depending on the language, your choice may be automatically narrowed further. Maybe you have a time limit for adding messaging capabilities to your existing application. A time limit for implementation suggests a simple API, such as Simple MAPI or CMC. Maybe you need to write a complex workgroup application. Extended MAPI is the API of choice for complex applications.

Each of these situations are fairly straightforward. In fact, deciding between Extended MAPI and one of the layered APIs should be an easy choice. When your application heavily depends on messaging, use Extended MAPI. Extended MAPI applications have more direct contact with and control over the underlying messaging system services like address books, message stores, and transports. Applications that can benefit from Extended MAPI functionality include shared group applications like schedulers and calendars, work flow and message management applications, electronic mail clients, rules-based inbox managers, or Electronic Data Interchange (EDI) clients.

Simple MAPI and CMC offer programmers a fast, easy way to build basic messaging applications from scratch or add messaging functionality to existing applications. The features provided by the two client interfaces is nearly identical, but CMC is bit more compact, combining multiple features in a single function. Both interfaces provide a straightforward function call interface that enables users to create, send, receive, reply to, forward, and edit messages. .

The following table lists all of the functions in the CMC and Simple MAPI APIs together with the features that they provide.

Purpose	Simple MAPI Function	CMC Function
Establish a session	MAPILogon	cmc_logon
Terminate a session	MAPILogoff	cmc_logoff
Free memory	MAPIFreeBuffer	cmc_free
Send a message with or without a user interface	MAPISendMail	cmc_send
Send a message with a user interface	MAPISendDocuments	cmc_send_documents
Find messages that match a set of search criteria	MAPIFindNext	cmc_list
Save a message	MAPISaveMail	cmc_act_on
Delete a message	MAPIDeleteMail	cmc_act_on
Assign recipients to a message	MAPIAddress	cmc_look_up
Show recipient details	MAPIDetails	cmc_look_up
Resolve ambiguous names in recipient list	MAPIResolveName	cmc_look_up
Retrieve configuration data.	-	cmc_query_configuration
The main difference between the two APIs is that CMC is designed to be independent of the operating system and underlying messaging system hardware. CMC was developed in conjunction with the X.400 Application Programming Interface Association (XAPIA) standards organization and electronic mail vendors and users. Where Simple MAPI works on Windows-based platforms only, CMC is available for Windows, MS-DOS, Macintosh, and Unix systems. Therefore, CMC is a good choice for client applications that need to use multiple messaging systems on multiple platforms. Simple MAPI is a good choice for single platform Windows-based client applications that require a feature CMC lacks or that need to be compatible with an existing Simple MAPI application.

The remaining choice, OLE Messaging, is an object oriented API used primarily by Visual Basic and Visual C/C++ client application developers. OLE Messaging provides programmable objects that publish properties and methods which can then be managed by Visual Basic and Visual Basic for Applications programs. OLE Messaging is based on the capabilities provided by OLE Automation. In terms of messaging functionality, it offers more than CMC and Simple MAPI offer, but less than what Extended MAPI offers. OLE Messaging is a good choice for Visual Basic applications or applications that require a moderate amount of messaging support.

To summarize, the following table shows how each of the client APIs differ:

Issues	CMC	Simple MAPI	Extended MAPI	OLE Messaging
Messaging support	low	low	high	medium
Prerequisite knowledge	none	none	COM and OLE	OLE automation and Visual Basic programmable objects
Forms support	none	none	full support	some support
Language support	C and C++	C, C++, Visual Basic	C and C++	C, C++, Visual Basic
Platform support	cross-platform	Windows-based	Windows-based	cross-platform


 Using Multiple Client Programming Interfaces

Most client applications will use one client API - either OLE Messaging, Simple MAPI, CMC or Extended MAPI. However, some clients will want to take advantage of what more than one client API has to offer. These clients will want to use Extended MAPI for some tasks and a simpler API for others. The MAPI architecture allows client applications to do this fairly easily by providing several API functions for converting between the environments.

One common conversion task involves identifiers. Identifiers are used throughout MAPI to uniquely represent a component, such as a message or a service provider. Extended MAPI uses a structure called an entry identifier; OLE Messaging and Simple MAPI use a string called a message identifier. Message identifiers can be simple or compound.

The following API functions are available for translating between the different identifiers used by the different client API sets:

•	HrSzFromEntryID

•	HrComposeMessageID

•	HrEntryIDFromSz

•	HrComposeEID

•	HrDecomposeEID

•	HrComposeMsgID

•	HrDecomposeMsgID

HrSzFromEntryID turns an entry identifier into a string that can be used with either OLE Messaging or Simple MAPI. The HrComposeMessageID function, provides the same functionality in a more general way.

HrEntryIDFromSz translates a string into an entry identifier. The string may an either a simple or compound OLE Messaging or Simple MAPI identifier. If a compound message identifier is to be converted, the HrComposeEID function works better than HrEntryIDFromSz. HrEntryIDFromSz will succeed, but subsequent uses of the resulting entry identifier will fail.

For translating between CMC and Extended MAPI identifiers, use HrComposeEID and HrDecomposeEID. These functions can handle binary message identifiers that require string versions. Use HrDecomposeEID with care; it is an expensive call.

The HrComposeMsgID and HrDecomposeMsgID functions translate between the entry identifier that is created by HrComposeEID and a string suitable for OLE Messaging and Simple MAPI. These functions require an Extended MAPI session handle. Therefore, if your application was not started with the Extended MAPI logon API function, MAPILogonEx, you will need to translate your current session handle into an Extended MAPI session handle.

It is possible to convert CMC and Simple MAPI sessions into Extended MAPI sessions by calling one of two API functions: ScMAPIXFromCMC or ScMAPIXFromSMAPI. To convert CMC sessions into Extended MAPI sessions, use ScMAPIXFromCMC. To convert Simple MAPI sessions, use ScMAPIXFromSMAPI. Both functions take a your current session handle as input and return a pointer to an Extended MAPI session object. Session objects are discussed in more detail later in the chapter called "Using Session Objects." Note that there is no way to convert an Extended MAPI session into a CMC or Simple MAPI session. There is also no way to convert a CMC session into a Simple MAPI session.

When you are using multiple client APIs, exercise caution when interpreting return values. Client APIs do not share the same set of return values. Nor do they return the same type of values. For example, Simple MAPI functions return unsigned long values while Extended MAPI functions and methods return data structures known as HRESULTs. Both values are based on a numeric code which, in many cases, is the same for both caller types. However, there are a few cases where they are different. The following table lists the differences; refer to the section on error handling in the "Introduction to Extended MAPI Programming" and the MAPI Programmer's Reference for more information.

Simple MAPI Return Value	Extended MAPI Return Value
MAPI_E_NOT_SUPPORTED	MAPI_E_NO_SUPPORT MAPI_E_INTERFACE_NOT_SUPPORTED MAPI_E_INVALID_PARAMETER MAPI_E_VERSION
MAPI_E_DISK_FULL	MAPI_E_NOT_ENOUGH_DISK
MAPI_E_NETWORK_FAILURE	MAPI_E_NETWORK_ERROR
MAPI_E_USER_ABORT	MAPI_E_USER_CANCEL
MAPI_E_ACCESS_DENIED	MAPI_E_NO_ACCESS
MAPI_E_AMBIGUOUS_RECIPIENT	MAPI_E_AMBIGUOUS_RECIP


 About Message Services and Profiles

Some users require the services of several messaging systems, each with three or more service providers. Because it is cumbersome to have to install and configure each of these service providers individually, MAPI has created the concept of a message service. Message services help users install and configure their service providers. To create a message service, a developer writes a single setup program to install the related service providers and write to MAPI's configuration file, MAPISVC.INF, and a message service entry point program to handle the configuration of each provider.

The MAPISVC.INF file contains information relating to the configuration of all message services and service providers installed on the computer workstation. It is organized in hierarchical sections, with each level linked to the next. At the top are three sections; one listing message service help files, one listing the most important, or default, message services, and one listing all of the services on the workstation. The next level contains sections for each message service and the last level contains sections for each service provider in a service. MAPI requires developers of service providers and message services to add certain entries to MAPISVC.INF; other entries may be added at the developer's discretion. Most of the information in MAPISVC.INF ends up in one or more profiles, a collection of configuration information for a user's preferred set of message services. Because a workstation can have multiple users and a single user can have multiple sets of preferences, many profiles can exist on a workstation. Each profile describes a different set of message services. Having multiple profiles enables a user to work, for example, at home with one set of message services and at the office with a different set.

Profiles are created at message service installation or logon time by a client application that provides configuration support. MAPI provides two such client applications: the Control Panel applet and the Profile Wizard. The Control Panel applet is a full service configuration application that allows users to create, delete, edit, and copy profiles as well as make modifications to the entries within a profile. The Profile Wizard is a simple application whose goal is to make adding a message service to a profile as easy as possible. The Profile Wizard consists of a series of dialogs, called property pages, that prompt the user through the process of installing and configuring a service. The user is prompted only for values for the most critical settings; all other settings inherit default values. Once the profile has been created, users are not allowed to make changes.

Whereas the Control Panel applet is always invoked through the Control Panel, there are a variety of scenarios that can cause the Profile Wizard to be called. Client applications can call the Profile Wizard to create a default profile at logon time when one has not yet been created. Rather than re-implementing code to add a profile, the Control Panel applet or another client application can rely on the functionality already in the Profile Wizard. A message service, in its entry point function, can call the Profile Wizard when the service needs to be added to the default profile. Message services that use the Profile Wizard must write an extra entry point function and a standard Windows dialog procedure. The Profile Wizard calls the entry point function to retrieve the service's configuration dialog box while the dialog procedure handles the messages that are generated when this dialog box is in use.

Profiles are organized in a similar way to the MAPISVC.INF file. There are linked hierarchical sections with service providers owning sections in the lowest level, message services owning sections in the middle level, and MAPI owning sections in the highest level. Each section is identified with an unique identifier known as a MAPIUID. The MAPI sections contain information internal to MAPI, such the identifiers of all of the message service profile sections and links to each of the other sections. Each message service section stores links to its provider sections and each provider section stores a link to its service section.

Figure 1 below illustrates contents of two typical profiles. Sam has two profiles on his computer, one for home use and one for office use. The home profile contains three message services. Message Service X is a single provider service for address book management. Message Services Y and Z have three providers - an address book provider, a message store provider, and a transport provider. Sam's Work Profile contains two different message services; each of which has an address book provider, a message store provider, and a transport provider.

Figure 1  Relating Profiles to Message Services and Service Providers.

Some profiles, depending on the platform, are password-protected. Password protection is only supported on platforms that do not provide user account security. It may be desirable to password protect profiles if it is important to ensure single user access. Note, however, that while password-protected profiles can only be changed by valid users, anyone with access to the system can delete them. This is because profiles are not considered critical components; they can be easily recreated.

Figure 2 shows the pieces that make up a message service. The message service code for installation and configuration of each of its three service providers resides in a single DLL file. This code reads information from the profile at logon time, adding missing information if necessary with or without the help of the user. Requests from a client application to view or change configuration settings for any of the providers are handled by this common code.

Figure 2  Message Services, the Profile, and Service Providers.


 Establishing a Session

Before any calls can be made to an underlying messaging system, client applications must establish a session, or connection, with the MAPI subsystem. Sessions are initiated when a user logs on, a process that consists of accessing a valid profile, validating messaging system credentials, and insuring that all of the profile's message services are properly configured.

Some of the message services in the profile may require credentials, such as passwords, to be entered. Passwords can either be saved in the profile or entered by the user with every logon. Passwords are optional features in MAPI. Whether or not they are required and how they are implemented depends on the messaging system and the platform. Some platforms support security based on user operating system accounts; others do not.

MAPI also supports unified logon, in which a single initial logon to the messaging system gains a user access to multiple workgroup applications. When working with unified logon, users do not have to enter a name and password for each application they want to use.

The following table lists the MAPI platforms and whether or not each type implements user account security.

MAPI Platform	User Account Security
Windows 95	yes
Windows NT	yes
Windows 3.x	no
Windows for Workgroups 3.x	no
MS-DOS	no
Macintosh	no
One of the most important parts of the logon process is determining if all of the message services in the profile are properly configured. The profile is the initial source for configuration information. If information for a particular message service is missing, the logon process tries to prompt the user to supply it, an attempt which is not always successful for two reasons. Prompting the user requires the display of a dialog box. It is possible for clients to disallow the display of a user interface by passing a flag into the logon call. Another cause for failure is when the user cancels this user interface before entering the needed information.

When a logon process fails once, the user is informed and given the opportunity to retry or correct the error condition. Once again, a user interface will be displayed, if possible, and the user will be asked to enter whatever data is necessary to complete the process. If this second attempt proves unsuccessful, MAPI disables all providers in that message service for the duration of the session. In effect, the whole service is disabled. This is done because if one provider fails logon, typically other providers will also fail.

Sometimes the logon process will fail due to an invalid path for a necessary resource, an incompatible version of MAPI, an unavailable messaging server, or data corruption.

Clients can specify one of two types of sessions to be established in the logon call. Either an individual session or a shared session can be established. Individual sessions are private connections; there is a one-to-one relationship between a client application and the profile it is using. A shared session allows multiple client applications on a computer workstation to work from the same profile. Shared sessions are established once but can be "used" by other client applications who ask to use them. The profile and credentials are specified only with the initial logon.

Clients can log on multiple times as the same user or as multiple users. MAPI does not prevent this. Some service providers, however, might not be as flexible, returning the error value MAPI_E_SESSION_LIMIT on subsequent logon attempts. Service providers with underlying hardware limitations may be required to enforce a session limit.

To summarize, this flowchart illustrates how the logon process works with the profile to establish a session.

Figure 3  Flow of logon process.


 Platform Issues

When using the MAPI SDK to create a client application or a service provider, there are platform issues to keep in mind. The degree of interoperability between clients and message services depends on the platforms the clients and message services used for development. Also, the platform that holds the MAPI SDK installation is also a factor.

Message services support clients that are written for one of the following platforms:

•	Windows NT (32-bit)

•	Windows 95 (32-bit)

•	Win16 (16-bit compatibility mode running on Windows NT or Windows 95)

Selecting a development platform affects writers of both message services and clients. Message service writers should develop in an environment so that they will be able to be used by a wide variety of clients. Client implementors should choose an environment that will allow them to use the message services they want.

If you have installed the MAPI SDK under Windows NT, you will be able to create message services that will run on Windows NT, Windows 95, or in a 16-bit compatibility mode environment. Client written in either the Windows NT or 16-bit environments will be able to access your service.

If you have installed the MAPI SDK under Windows 95, your future message service will run on either Windows 95 or in 16-bit compatibility mode. Client written in either the Windows 95 or 16-bit environments will be able to access your service.

Clients written for either of the 32-bit platforms or for the 16-bit compatibility mode environment can access two types of message services: those written for the 32-bit platforms and single source services. Single source services are built with a single set of source files from which binaries can be built to run on any of the platforms: Windows NT, Windows 95, or Win16.

If you target all three platforms using the single-source approach, you can take advantage of a special set of API functions provided by MAPI to reduce the amount of 16 bit-specific work. MAPI has ported a few dozen Win32 API functions to 16 bit. With these functions, you can write your code as if you were writing with the standard Win32 library of API functions. However, you compile for the 16 bit environment using some special built-in support. All of the sample services installed with the MAPI SDK are single source services written using these APIs. Refer to the MAPI Programmer's Reference for complete descriptions of the MAPI Win32 functions.

If you are planning to write for either Windows NT or Windows 95, it makes sense to write a message service that will operate on both 32 bit platforms, thereby increasing its usability. Targeting both 32 bit platforms is easy to do because the additional code required for the second platform is minimal.

If you have installed the MAPI SDK in the 16-bit environment, your message service will only be able to run in that environment. You will only be able to support the 16 bit environment on Windows 3.1+ because MAPI does not support the 32-bit subset, Win32s.


 Programming with CMC

This chapter contains conceptual information for programming with the CMC application programming interface (API). You should understand the material in this chapter before writing applications that use the CMC APIs. This chapter covers concepts needed for sending and receiving messages as well as dealing with addresses and message attachments.


 About CMC

The Common Messaging Calls (CMC) client interface is a set of ten functions that enables developers to add simple messaging capabilities to their applications quickly. For example, an application can send a message with a single CMC function call and receive a message with two CMC function calls.

Because CMC is built on top of the core MAPI subsystem, it shares the MAPI advantage of messaging service independence. The CMC API is especially valuable because it is also independent of the operating system and the underlying hardware used by the messaging service, providing a common messaging interface that can be used in virtually any environment. The CMC API is therefore a good choice for a messaging API when the client application must run on multiple platforms and provide simple messaging services on each of these platforms.

Although the Microsoft CMC implementation is built on top of a MAPI implementation, it is important to note that other implementations of CMC from other vendors may not be. In this document, "CMC" and "CMC implementation" should be taken to mean "Microsoft's implementation of the CMC API using MAPI APIs."

The CMC API was developed in conjunction with the X.400 API Association (XAPIA) standards organization and with a group of e-mail vendors and users. It is supported on Microsoft Windows, MS-DOS, OS/2, Macintosh, and UNIX platforms. Because CMC is supported on several different platforms, an application written to the CMC standard can be ported to other platforms. In contrast, MAPI is a Windows-only standard.

The CMC API works as a layer between a messaging-enabled application and a messaging service. The messaging service in turn can support multiple messaging protocol services, each using different messaging formats and protocols, for example, X.400, RFC 822, and Simple Mail Transport Protocol. The design of the CMC interface specifies that its functions be independent of the messaging protocol services. However, the API does enable developers to use extensions to invoke protocol-specific functions. For more information, see Using CMC Extensions.A directory, a submission queue, and a receiving mailbox are the three messaging service components in the CMC API model.

Using the directory, the messaging-enabled application can look up information about users of connected messaging services and can resolve users' names to actual addresses. Some services may also provide an interface enabling users to create recipient lists for messages or find out details about specific recipients.

The CMC implementation assigns a submission queue for each messaging-enabled application. By doing so, CMC provides each application with synchronous submission of messages to the underlying messaging service; once a call to send a message has returned, the calling application is guaranteed that the submission process has completed (although no guarantee is made about whether the message was successfully delivered). When the call has returned, the CMC implementation has all further responsibility for submitting the message to the underlying messaging system.

On the receiving side, a mailbox receives all messages for a user. The messaging service maintains mailboxes on behalf of messaging users. These mailboxes are accessible to users of messaging-enabled applications who have the proper permissions. With the CMC API, the application can retrieve summaries of the contents of a mailbox, along with identifiers for the particular messages summarized. The application can use these identifiers to select and retrieve individual messages.


 CMC Programming Basics

The CMC API supports three principal tasks: sending messages, retrieving messages, and looking up addressing information.

♦	To send a message, a messaging-enabled application

1.	Establishes a session with the messaging service either through the cmc_logon function or interactively by sending the CMC_LOGON_UI_ALLOWED flag value with the cmc_send function.

2.	Submits a message to the submission queue. Usually, a messaging-enabled application does so through a cmc_send function. If a messaging-enabled application uses cmc_send, it must first create a CMC_message structure to pass to the cmc_send function. The messaging-enabled application can also use the more limited cmc_send_documents function to send a message; this function is primarily used to send messages or files from macro languages.

3.	Closes the session by using the cmc_logoff function.

♦	To retrieve a message, a messaging-enabled application

1.	Establishes a session by using the cmc_logon function.

2.	Retrieves a summary of mailbox information by using the cmc_list function.

3.	Retrieves an individual message by using the cmc_read function.

4.	Optionally, enables a user to act on the message in the mailbox (for example, delete it or move it to another folder) using the cmc_act_on function.

5.	Releases memory allocated by CMC by using the cmc_free function.

6.	Closes the session by using the cmc_logoff function.

♦	To look up names and address information in the directory, a messaging-enabled application

1.	Establishes a session either through the cmc_logon function or interactively by sending the CMC_LOGON_UI_ALLOWED flag value with the cmc_look_up function.

2.	Translates a user's display name (what the user sees) into a messaging address (what the underlying message system uses) by using cmc_look_up. With this function, the application can also request that the standard CMC addressing dialog box be used to view recipient-specific details or create addressing lists.

3.	Releases memory allocated by CMC by using the cmc_free function.

4.	Closes the session by using the cmc_logoff function.

Note that these tasks do not have to be performed in isolation from each other. For example, a messaging-enabled application can establish a session once with a call to the cmc_logon function and use the resulting CMC session for the duration of the user's interaction with the application. During that time, the application can make many CMC calls to perform messaging tasks such as send messages, receive them, make directory queries.

The CMC API uses a fixed set of API functions, data structures, and data types. The API functions are the functions that your application calls to carry out messaging tasks. The data structures are the groupings of information that your application must provide to the CMC APIs, and are sometimes returned by the CMC APIs. The data types are basic elements that comprise the data structures. They each have a specific range of values and specific memory storage characteristics (Boolean, floating point, and so on) and can have specific operations performed on them.

The CMC API functions listed in alphabetic order:

Action	Function	Description
Sending messages	cmc_send	Sends a message.
	cmc_send_documents	Sends a message. This function is string based and is usually used in macro language calls.
Receiving messages	cmc_act_on	Performs an action on a specified message.
	cmc_list	Lists summary information about messages meeting specified criteria.
	cmc_read	Returns a specified message.
Looking up names	cmc_look_up	Looks up addressing information.
Administration	cmc_free	Frees memory allocated by the messaging service.
	cmc_logoff	Terminates a session with the messaging service.
	cmc_logon	Establishes a session with the messaging service.
	cmc_query_configuration	Determines information about the installed CMC service.
The CMC data structures listed in alphabetic order:

Data structure name	Description
CMC_attachment	Message attachment structure
CMC_counted_string	String with an explicit length designation
CMC_extension	Extension structure
CMC_message	Message structure
CMC_message_reference	Message-reference structure
CMC_message_summary	Message-summary structure
CMC_object_identifier	Object-identifier structure
CMC_recipient	Originator or recipient structure
CMC_time	Time structure
The CMC data types listed in alphabetic order:

Data type name	Description
CMC_boolean	Value indicating logical true or false
CMC_buffer	Pointer to a data item
CMC_enum	Data type containing a value from an enumeration
CMC_flags	Container for flag bit values
CMC_return_code	Return value indicating either that a function succeeded or why it failed
CMC_session_id	Unique identifier for a session
CMC_string	Character-string pointer
CMC_ui_id	User-interface handle
Complete reference information for all CMC API functions, structures, and data types is provided in the CMC API Function Referencetopic.


 Starting a CMC Session

CMC function calls occur within the context of a messaging session. Your application establishes a session with a call to the cmc_logon function. The cmc_logon function checks the user's credentials for the messaging service, sets session attributes, and returns a session identifier for use in later CMC calls. Session attributes include character set and version number for the CMC API. Currently, there is no support for sharing sessions among applications in the CMC API. Your application terminates a session with a call to the cmc_logoff function.

CMC session identifiers can be interchanged through function calls among CMC, MAPI, Simple MAPI, and Extended MAPI. For example, you can cast the session identifier returned from cmc_logon to the LPMAPISESSION value and use it to access the methods in the IMAPISession interface. Likewise, you can cast the LPMAPISESSION value returned by the MAPILogon function to a CMC_session_id (or LHANDLE), used in CMC (or Simple MAPI) function calls. This allows client applications to use CMC for the bulk of their messaging tasks without sacrificing access to the MAPI functions should they be needed.

Client applications can also use the cmc_query_configuration function (described following) to determine logon identity and messaging options before calling the cmc_logon function.


 Addressing Messages

Addressing messages with CMC is a matter of using the cmc_look_up function to find addresses that your application can then use with the cmc_send function. Using cmc_look_up, your application can search for names in the address book and resolve names into the addresses used by the underlying messaging system.

Both cmc_look_up and cmc_send make heavy use of  the CMC_recipient structure. The cmc_look_up function uses it on input to receive the name of the recipient you are trying to look up. On output, cmc_look_up passes back an array of CMC_recipient structures that contain the results of the search. The cmc_send function uses a CMC_recipient structure to receive the address or addresses of the recipients of the message being sent.


 Sending Messages

Sending messages with CMC involves building a CMC_message structure and passing it to the cmc_send function. Your application fills out different fields in the CMC_message depending on the parameters you use to invoke cmc_send. For example, if you pass the CMC_LOGON_UI_ALLOWED flag to cmc_send, then your application does not need to provide a list of recipients, a subject line, or a message body because CMC will query the user for that information.

When your application calls the cmc_send function, it must provide a session identifier, a pointer to a CMC_message structure, any flags you desire, an optional user interface identifier if the flags include the CMC_LOGON_UI_ALLOWED flag, and optional extensions. Once cmc_send returns, your application has no further responsibility for sending the message.


 Receiving Messages

Receiving messages with CMC is slightly more complex than sending messages:

♦	To receive a message

1.	Call the cmc_list function to obtain an array of message summaries.

2.	Choose a specific message reference from that array and pass it to the cmc_read function to retrieve the corresponding message.

3.	Call the cmc_free function to release the storage allocated for the array when your application no longer needs it.

There are a number of ways your application can invoke cmc_list in order to control the sorts of messages listed by the API. For example, the application could pass in the string "CMC: NDR" in the message_type parameter to obtain a list of non-delivery reports, or could include the CMC_LIST_UNREAD_ONLY flag in the list_flags parameter to obtain a list of unread messages.


 Using CMC Extensions

The data structures and functions defined by CMC can be expanded through the use of extensions to add fields to data structures and parameters to function calls.

Extensions have two roles in CMC messaging. First, they are a mechanism to provide features not common across all messaging services. Second, they enable extension of CMC in the future while also minimizing backward-compatibility issues. Use caution when using extensions in your application to take advantage of features specific to a messaging service. Reliance on specific features limits the portability of your application across messaging services; also, such features may not be preserved properly when a message passes through multiple gateways in a mixed messaging network. If you do use extensions in your application, your code should test for the presence of the extensions and gracefully handle the absence of the extensions. Doing so will make your application portable to other CMC implementations.

Extensions are grouped into extension sets. Extension sets have unique identifiers (defined constants) assigned to them that represent the set as a whole and that represent the individual extensions in the set. These identifiers are assigned by the X.400 API Association, which guarantees that there are no conflicts between identifiers in officially recognized extension sets. There are also provisions for allowing a CMC implementation to define its own extensions without obtaining identifiers from the X.400 API Association. If this is done, applications which use those extensions may not be portable to other CMC implementations.

The CMC common extension set contains those function and data extensions that are common to most messaging services but are not in the CMC base specification. The common extension set is identified by the CMC_XS_COM constant. Individual extensions in the common extension set are identified by constants whose names start with CMC_X_COM. For a full list of common extension declarations, see the CMC API Function Referencetopic

A generic data structure, CMC_extension, has been defined as a basis from which to create these extensions. A CMC_extension structure consists of an item code identifying the extension, an item data type holding the length of extension data or the data itself, an item reference that points to where the extension value is stored or that is NULL if there is no related item storage, and flag values for the extension. The item code field identifies a particular extension and so determines the meanings of values in the other fields.

The syntax for the CMC_extension structure is as follows:

typedef struct {

CMC_uint32	item_code;

CMC_uint32	item_data;

CMC_buffer	item_reference;

CMC_flags	extension_flags;

} CMC_extension

Extensions that are additional parameters to a function call can be either input or output parameters. That is, an extension can be passed either as an input parameter from a messaging application to CMC or as an output parameter from CMC to an application. If an extension is an input parameter, the application in question allocates memory for the extension structure and any other structures associated with the extension. If an extension is an output parameter, CMC allocates the storage for the extension result, if necessary, and the application must free the allocated storage with a call to the cmc_free function.

The general procedure for using extensions is:

1.	Create a CMC_extension structure and fill in the fields in the structure according to the extension you want to use.

2.	Pass a pointer to that structure in a call to a CMC function which can use it. The CMC function will use the information in the extension structure to enable additional functionality beyond the functionality defined for that CMC function in the X.400 API Association's CMC specification. The exact nature of the additional functionality is documented in the documentation for the extension set you are using, which should be obtained from the extension set vendor.

3.	Retrieve any return values from the fields in the extension structure if the CMC function uses the extension structure to pass values back to your application.


 Administering with CMC

Your application needs to perform a small number of administrative tasks when using CMC. These tasks are

•	Querying the CMC implementation to determine what features it supports.

•	Releasing memory that was allocated by CMC.

•	Terminating CMC sessions when the application no longer needs them.

You can get information about the CMC implementation by calling the cmc_query_configuration function. The application must pass in an item code that specifies the type of configuration information for the cmc_query_configuration function to return. The application must also pass in a pointer to a buffer where the cmc_query_configuration function can pass back the requested information. It is the application's responsibility to ensure that the buffer is large enough to hold data of the requested type.

In some circumstances, the application will have to release memory that has been allocated by CMC. CMC provides a single function, cmc_free, for releasing memory that it has allocated. That memory is typically the result of a CMC function. For example, the cmc_look_up function allocates an array of CMC_recipient structures to hold the results of an address book search. The application is responsible for calling the cmc_free function on that array after it is no longer needed. To free memory allocated by CMC, the application only needs to pass a pointer to the memory to the cmc_free function.

The application should not try to free the memory itself. The memory is not guaranteed to be in a single contiguous block, so one call to an underlying memory management function (such as the C run time library function malloc) is not guaranteed to free all of the memory that CMC has allocated. A memory leak will result if the application does this. The cmc_free function will make all the necessary memory management calls to properly free the memory CMC has allocated.

When your application no longer needs any messaging services, it should use the cmc_logoff function to close the CMC session that it obtained with the cmc_logon function. Depending on the nature of your application and whether it is possible to establish a CMC session without the user's assistance, it may make sense to close the session as soon as a group of messaging calls are finished. For other applications it may make more sense to establish one CMC session when the application starts and retain it until the application exits.


 CMC Programming Examples

This topic includes example code that illustrates the following common messaging operations:

•	Logging on and off and using cmc_query_configuration to get system information

•	Sending the same message using the cmc_send and cmc_send_documents functions

•	Listing, reading, and deleting the first unread message in the Inbox

•	Looking up a specific recipient and getting recipient details from the address book

•	Specifying use of the common extensions during a session logon

The following code example demonstrates how an application logs on and off and uses cmc_query_configuration to get system information:

/* Local variables used */

CMC_return_code Status;

CMC_boolean     UI_available;

CMC_session_id  Session;

/* Find out if user interface (UI) is available with this

   implementation before starting.*/

Status = cmc_query_configuration(

              0,                      /* No session handle         */

              CMC_CONFIG_UI_AVAIL,    /* See if UI is available.   */

              (void *)&UI_available,  /* Return value              */

              NULL);                  /* No extensions             */

    /* Error handling */

/* Log onto system using UI. */

Status = cmc_logon(

              NULL,                   /* Default service           */

              NULL,                   /* Prompt for user name      */

              NULL,                   /* Prompt for password       */

              NULL,                   /* Default character set     */

              0,                      /* Default UI ID             */

              CMC_VERSION,            /* Version 1 CMC calls       */

              CMC_LOGON_UI_ALLOWED |  /* Full logon UI             */

              CMC_ERROR_UI_ALLOWED,   /* Use UI to display errors. */

              &Session,               /* Returned session ID       */

              NULL);                  /* No extensions             */

    /* Error handling */

/* Do various CMC calls. */

/* Log off from the implementation. */

Status = cmc_logoff(

              Session,            /* Session ID                    */

              0,                  /* No UI will be used.           */

              0,                  /* No flags                      */

              NULL);              /* No extensions                 */

    /* Error handling */

The following code example demonstrates how an application sends a message, using first the cmc_send and then the cmc_send_documents function:

/* Local variables used */

CMC_attachment  Attach;

CMC_session_id  Session;

CMC_message     Message;

CMC_recipient   Recip[2];

CMC_return_code Status;

CMC_time        t_now;

/* Build recipient list with two recipients.  Add one "To" recipient. */

Recip[0].name       = "Bob Weaver";       /* Send to Bob Weaver.      */

Recip[0].name_type  = CMC_TYPE_INDIVIDUAL;/* Bob's a person.          */

Recip[0].address    = NULL;               /* Look_up Bob's address.   */

Recip[0].role       = CMC_ROLE_TO;        /* He's a "To" recipient.   */

Recip[0].recip_flags= 0;                  /* Not the last element     */

Recip[0].recip_extensions = NULL;         /* No recipient extensions  */

/* Add one "Cc" recipient. */

Recip[1].name       = "Mary Yu";           /* Send to Mary Yu.        */

Recip[1].name_type  = CMC_TYPE_INDIVIDUAL; /* Mary's a person.        */

Recip[1].address    = NULL;                /* Look_up Mary's address. */

Recip[1].role       = CMC_ROLE_CC;         /* She's a "Cc" recipient. */

Recip[1].recip_flags= CMC_RECIP_LAST_ELEMENT;/* Last recip't element  */

Recip[1].recip_extensions = NULL;          /* No recipient extensions */

/*  Attach a file. */

Attach.attach_title = "stock.wks";         /* Original filename       */

Attach.attach_type  = NULL;                /* No specific type        */

Attach.attach_filename  = "tmp22.tmp";     /* File to attach          */

Attach.attach_flags   = CMC_ATT_LAST_ELEMENT;  /* Last attachment     */

Attach.attach_extensions = NULL;           /* No attachment extension */

/*  Put it together in the message structure. */

Message.message_reference   = NULL;     /* Ignored on cmc_send calls. */

Message.message_type        = NULL;     /* Interpersonal message type */

Message.subject             = "Stock";    /* Message subject          */

Message.time_sent           = t_now;    /* Ignored on cmc_send calls. */

Message.text_note           = "Time to buy";   /* Message note        */

Message.recipients          = Recip;      /* Message recipients       */

Message.attachments         = &Attach;    /* Message attachments      */

Message.message_flags       = 0;          /* No flags                 */

Message.message_extensions  = NULL;       /* No message extensions    */

/*  Send the message. */

Status = cmc_send(

              Session,         /* Session ID - set with logon call   */

              &Message,        /* Message structure                  */

              0,               /* No flags                           */

              0,               /* No UI will be used.                */

              NULL);           /* No extensions                      */

    /* Error handling */

/* Now do the same thing with the send documents call and UI. */

Status = cmc_send_documents(

              "to:Bob Weaver,cc:Mary Yu",      /* Message recipients  */

              "Stock",                         /* Message subject     */

              "Time to buy",                   /* Message note        */

              CMC_LOGON_UI_ALLOWED |

              CMC_SEND_UI_REQUESTED |

              CMC_ERROR_UI_ALLOWED,/* Flags (allow various UIs)  */

              "stock.wks",         /* File to attach             */

              "tmp22.tmp",         /* Filename to carry on attachment */

              ",",                 /* Multivalue delimiter       */

              0);                  /* Default UI ID              */

    /* Error handling */

The following code example demonstrates how an application can list, retrieve, and delete the first unread message in the inbox:

/* Local variables used */

CMC_message_summary     *pMsgSummary;

CMC_message             *pMessage;

CMC_uint32              iCount;

CMC_session_id          Session;

CMC_return_code         Status;

/* Read the first unread message and delete it. */

iCount  = 5;

Status = cmc_list(

              Session,               /* Session handle                */

              NULL,                  /* List ALL message types.       */

              CMC_LIST_UNREAD_ONLY,  /* Get only unread messages.     */

              NULL,                  /* Starting at the top           */

              &iCount,               /* Input/output message count    */

              0,                     /* No UI will be used.           */

              &pMsgSummary,          /* Return message summary list.  */

              NULL);                 /* No extensions                 */

    /* Error handling */

Status = cmc_read(

              Session,                            /* Session ID       */

              pMsgSummary->message_reference,     /* Message to read  */

              CMC_MSG_AND_ATT_HDRS_ONLY,    /* Don't get attach files.*/

              &pMessage,                          /* Returned message */

              0,                                  /* No UI            */

              NULL);                              /* No extensions    */

    /* Error handling */

Status = cmc_act_on(

              Session,                           /* Session ID        */

              pMsgSummary->message_reference,    /* Message to delete */

              CMC_ACT_ON_DELETE,                 /* Message to read   */

              0,                                 /* No flags          */

              0,                                 /* No UI             */

              NULL);                             /* No extensions     */

    /* Error handling */

/* Free the memory returned by the implementation. */

Status = cmc_free(pMsgSummary);

Status = cmc_free(pMessage);

/* Do the same thing without the list call, because the read call can

   get the first unread message. */

Status = cmc_read(

             Session,                  /* Session ID                  */

             NULL,                     /* Read the first message.     */

             CMC_READ_FIRST_UNREAD_MESSAGE | /* Get first unread msg. */

             CMC_MSG_AND_ATT_HDRS_ONLY,/* Don't get attach files.     */

             &pMessage,                /* Returned message            */

             0,                        /* No UI                       */

             NULL);                    /* No extensions               */

    /* Error handling */

Status = cmc_act_on(

              Session,                           /* Session ID        */

              pMessage->message_reference,       /* Message to delete */

              CMC_ACT_ON_DELETE,                 /* Message to read   */

              0,                                 /* No flags          */

              0,                                 /* No UI             */

              NULL);                             /* No extensions     */

    /* Error handling */

/* Free the memory returned by the implementation. */

Status = cmc_free(pMessage);

The following code example demonstrates how an application looks up a specific recipient and gets details on that recipient from the address book:

/* Local variables used */

CMC_session_id  Session;

CMC_recipient   *pRecipient;

CMC_recipient   Recip;

CMC_return_code Status;

CMC_uint32      cCount;

/* Look up a name to pick correct recipient. */

Recip.name       = "Bob Weaver";           /* Send to Bob Weaver.     */

Recip.name_type  = CMC_TYPE_INDIVIDUAL;    /* Bob's a person.         */

Recip.address    = NULL;                   /* Look_up Bob's address.  */

Recip.role       = 0;                      /* Role not used           */

Recip.recip_flags      = 0;                /* No flag values          */

Recip.recip_extensions = NULL;             /* No recipient extensions */

Status = cmc_look_up(

              Session,                     /* Session handle          */

              &Recip,                      /* Name to look up         */

              CMC_LOOKUP_RESOLVE_UI |      /* Resolve names using UI. */

              CMC_ERROR_UI_ALLOWED,        /* Display errors using UI.*/

              0,                           /* Default UI ID           */

              &cCount,                     /* Only want one back      */

              &pRecipient,                 /* Returned recipient ptr  */

              NULL);                       /* No extensions           */

/* Display details stored for this recipient. */

Status = cmc_look_up(

              Session,                    /* Session handle           */

              pRecipient,                 /* Name to get details on   */

              CMC_LOOKUP_DETAILS_UI |     /* Show details UI.         */

              CMC_ERROR_UI_ALLOWED,       /* Display errors using UI. */

              0,                          /* Default UI ID            */

              0,                          /* No limit on return count */

              NULL,                       /* No records returned      */

              NULL);                      /* No extensions            */

/* Free the memory returned by the implementation. */

cmc_free(pRecipient);

The following code example demonstrates how an application specifies use of the common extensions during a session logon:

/* Local variables used */

CMC_return_code     Status;

CMC_session_id      Session;

CMC_extension       Extension;

CMC_extension       Extensions[10]; /* show how to handle multiple */

CMC_X_COM_support   Supported[2];

CMC_uint16          index;

CMC_boolean         UI_available;

/* Find out if the common extension set is supported, but

   COM_X_CONFIG_DATA support is not required. */

Supported[0].item_code =  CMC_XS_COM;

Supported[0].flags =      0;

Supported[1].item_code =  CMC_X_COM_CONFIG_DATA;

Supported[1].flags =      CMC_X_COM_SUP_EXCLUDE;

Extension.item_code =         CMC_X_COM_SUPPORT_EXT;

Extension.item_data =         2;

Extension.item_reference =    Supported;

Extension.extension_flags =   CMC_EXT_LAST_ELEMENT;

Status = cmc_query_configuration(

              0,                         /* No session handle       */

              CMC_CONFIG_UI_AVAIL,       /* See if UI is available. */

              &UI_available,             /* Return value            */

              &Extension);               /* Pass in extensions.     */

    /* Error handling */

if (Supported[0].flags & CMC_X_COM_NOT_SUPPORTED)

    return FALSE;    /* Common extensions I need are not available. */

/* Log onto system and get the data extensions for this session.    */

Supported[0].item_code =  CMC_XS_COM;

Supported[0].flags =      0;

Supported[1].item_code =  CMC_X_COM_CONFIG_DATA;

Supported[1].flags =      CMC_X_COM_SUP_EXCLUDE;

Extension.item_code =         CMC_X_COM_SUPPORT_EXT;

Extension.item_data =         2;

Extension.item_reference =    Supported;

Extension.extension_flags =   CMC_EXT_REQUIRED | CMC_EXT_LAST_ELEMENT;

Status = cmc_logon(

              NULL,                   /* Default service             */

              NULL,                   /* Prompt for user name.       */

              NULL,                   /* Prompt for password.        */

              NULL,                   /* Default character set       */

              0,                      /* Default UI ID               */

              CMC_VERSION,            /* Version 1 CMC calls         */

              CMC_LOGON_UI_ALLOWED |  /* Full logon UI               */

              CMC_ERROR_UI_ALLOWED,   /* Use UI to display errors.   */

              &Session,               /* Returned session ID         */

              &Extension);            /* Logon extensions            */

    /* Error handling */

if (Supported[0].flags & CMC_X_COM_NOT_SUPPORTED)

    return FALSE;    /* Common extensions I need are not available.  */

    /* The common data extensions will be used for this session.     */

/* Example of how to free data returned from the CMC implementation in

   function output extensions.  */

for (index = 0; 1; index++) {

    if (Extensions[index].extension_flags & CMC_EXT_OUTPUT) {

        if (cmc_free(Extensions[index].item_reference) != CMC_success){

            /* Handle unexpected error here. */

        }

    }

    if (Extensions[index].extension_flags & CMC_EXT_LAST_ELEMENT)

         break;

}

/* Do various CMC calls. */

/* Log off from the implementation. */

Status = cmc_logoff(

              Session,              /* Session ID                   */

              0,                    /* No UI will be used.          */

              0,                    /* No flags                     */

              NULL);                /* No extensions                */

    /* Error handling */


 Programming with Simple MAPI

This chapter describes how and why your client would use the Simple MAPI functions to add messaging functionality to an application. The topics in this chapter cover the major areas of functionality that a Simple MAPI application needs to implement, such as:

•	Initializing your client so that it can use the Simple MAPI functions.

•	Creating messages.

•	Managing attachments.


 About Simple MAPI

Simple MAPI provides a set of functions that enables Microsoft Windows applications to quickly add a basic level of messaging. Simple MAPI is intended for applications that are concerned with the easy exchange of datafiles and messages.

Because Simple MAPI is only intended for the Microsoft Windows environment and offers limited functionality, it is recommended primarily for backward compatibility with older applications. You are encouraged to use CMC or Extended MAPI for development of new applications whenever possible.You should link Simple MAPI applications with either the MAPI.DLL or the MAPI32.DLL library, depending on whether you are writing for 16-bit or 32-bit Windows platforms.

Simple MAPI contains 12 high-level functions that allow you to send, address, receive, and reply to messages. Messages sent using Simple MAPI can even include file attachments and OLE objects. Windows applications whose primary purpose is not messaging, such as spreadsheets, word processors, or applications that require only basic messaging can use Simple MAPI to quickly and easily provide messaging functionality.

Simple MAPI has several features that make it a good option for applications that do not have extensive messaging needs:

•	Simple MAPI takes advantage of the MAPI subsystem to maintain independence from the underlying messaging system and network.

•	Simple MAPI gives you freedom to define your own message types as well as the content of messages, and flexibility in the management of stored messages.

•	Simple MAPI includes an optional common user interface (dialog boxes), so with little effort you can make your applications look consistent with each other and with other Windows-based applications. Through these dialog boxes, your users can address, compose, and send messages. Using the common dialog boxes is not mandatory, however, so if your application does not need a user interface, you can call the Simple MAPI functions without displaying any dialog boxes.

•	Although designed to be called from C programs, you can call the functions with little or no parameter modification from application-specific and standalone scripting packages such as Visual Basic, Actor, Smalltalk, and Object Vision.

If you are writing a new application, you should implement it using Extended MAPI or CMC. However, using Extended MAPI involves learning about objects, interfaces, and the Component Object Model, and it might be that your application only needs the limited messaging functionality available with Simple MAPI. In that case, you should use CMC, since it has the same functionality as Simple MAPI and it works on Microsoft Windows NT, Microsoft Windows for Workgroups 3.1, and Microsoft Windows 95. You should only use Simple MAPI for maintainance of older applications that were written using it.


 Initializing a Client

Before starting a Simple MAPI messaging session you need to initialize your client. Initializing your Simple MAPI client involves checking the computer's WIN.INI file to determine whether Simple MAPI is available, loading the correct dynamic link library (DLL) that contains the Simple MAPI functions, and setting a pointer to each function.

♦	To initialize your client

1.	Determine that Simple MAPI is available by checking the [MAIL] section in the computer's WIN.INI file for the MAPI entry. This entry will have a value of 1 if Simple MAPI is installed, or 0 if uninstalled.

2.	Load the correct DLL for your operating system by calling the Windows LoadLibrary function as follows:

hlibMAPI = LoadLibrary("MAPI.DLL");    // 16 bit clients

hlibMAPI = LoadLibrary("MAPI32.DLL");  // 32 bit clients

The two DLLs for Simple MAPI are MAPI.DLL for 16-bit clients and MAPI32.DLL for 32-bit clients.

3.	Set the pointer variable to the actual address of the MAPILogon function as follows:

lpfnMAPILogon = (LPFNMAPILOGON) GetProcAddress
(hlibMAPI, "MAPILogon")))

Similar defined constants exist for the other Simple MAPI functions, so your application simply needs to set the value of the function pointers using GetProcAddress as in the previous example.


 Starting a Simple MAPI Session

Most MAPI calls are made in the context of a session, defined as an active connection between a client application and the MAPI subsystem. Each session uses a particular profile that specifies the set of available messaging services and the providers to manage those services. Before your application can send or receive messages, it needs to log on and establish a session.

There are two types of session, temporary and persistent. A temporary session exists only for the lifetime of a single Simple MAPI call. A persistent session exists until the session is explicitly closed. Establishing a temporary session is referred to as implicit logon; establishing a persistent session is called explicit logon. Applications can use a persistent session for all of the calls that require the same set of providers and a temporary session for single calls that do not require the same context.

Note  Some messaging systems might allow a limited number of sessions, so your application must be able to handle a return value of MAPI_E_TOO_MANY_SESSIONS. This value can be returned when a user is logged on to the system through an email application and a mail-enabled application attempts to log on with a different identity.


 Sharing Sessions

Workgroup applications should all be able to work from the same profile without presenting logon or profile-selection dialog boxes when each application begins. To make this possible, MAPI introduces the idea of a shared session that is established once but can be used by other applications. Only one shared session can exist on a given computer at a time. The shared session can be used with any profile. If your application must use a non-shareable session (that is, your application needs to be guaranteed that no other applications will use its session), then it must use the MAPILogon function in the Extended MAPI API, which has a broader range of functionality than the Simple MAPI logon function.

By default, Simple MAPI attempts to use the shared session if it exists. If no shared session exists, Simple MAPI will create a new shared session when your application calls MAPILogon. If your application logs on with the MAPI_NEW_SESSION flag, then Simple MAPI will create a new shared session for your application to use regardless of whether one already exists.

The session handles returned to applications using a shared session are not the same. Each application, regardless of whether it is using a unique session or a shared session, has its own unique handle. Session handles are not valid across tasks, even when those handles represent the same shared session.


 Explicit Logon

Applications log on explicitly by calling MAPILogon. MAPILogon automatically opens the default address book for the Simple MAPI caller. When MAPILogon returns to the Simple MAPI client, the session is ready to service all messaging requests. The default message store provider is loaded and opened by the first Simple MAPI call that needs the message store.

The session handle produced by MAPILogon represents the MAPI session that the application can use in further Simple MAPI calls. This session handle is passed to most Simple MAPI calls and can also be used with  Extended MAPI. The support method ScMAPIXFromSMAPI, prototyped in the MAPI.H file, converts a Simple MAPI session handle into an Extended MAPI session object pointer.

Simple MAPI function calls produce status codes that provide information about the success of a call. These status codes are unsigned long values. Successful calls return SUCCESS_SUCCESS. Unsuccessful calls return error codes starting with MAPI_E_, such as MAPI_E_INSUFFICIENT_MEMORY.


 Implicit Logon

Applications log on implicitly by using a 0 session handle when calling Simple MAPI functions. Not all of the Simple MAPI functions allow the session handle to be 0; these calls cannot be made outside of an established session. For example, MAPIDeleteMail can only delete a message from a pre-existing session; a 0 session handle causes the MAPIDeleteMail function to return an error.

When the session handle is 0, Simple MAPI function calls use another common parameter, flFlags, to determine how to create the temporary session. If flFlags is set to MAPI_NEW_SESSION, the call tries to establish a new session, either programmatically if possible or with a logon dialog box. If MAPI_NEW_SESSION is not set, the call tries to use the shared session. If the call cannot establish a temporary session or use the shared session, it will return an error value.

When the call completes, the state of the mail system is as it was before the call was made. That is, the implicit session opened for the call is closed by the time the call returns.


 Passwords

Whether a password is required for your application to log on depends on the operating system which is running on the computer. If the operating system integrates messaging system credential checking into the initial system logon, then your application need not provide a password to MAPILogon. If not, then a password is required from the user or from a cache location implemented by the application.  Microsoft Windows NT and Microsoft Windows 95 do not require passwords for MAPILogon since the user's initial logon to the operating system suffices for both. Applications running with Microsoft Windows for Workgroups are required to provide a password for MAPILogon.


 Logon User Interface

Client applications can log on either by displaying a logon dialog box to provide user interaction or by providing necessary credentials (profile name and password if necessary) programmatically. If your application requires user interaction, you can use the common dialog box provided by Simple MAPI or create your own. However, it is recommended that you use the standard MAPI dialog boxes whenever possible to promote a consistent look and ease of use.

The presence or absence of the MAPI_LOGON_UI value in the flFlags parameter to MAPILogon controls the logon dialog box display.

♦	To force the dialog box to be displayed

Set the flFlags parameter to contain MAPI_LOGON_UI and set the lpszProfileName and lpszPassword parameters to NULL as follows:

flFlags |= MAPI_LOGON_UI;

MAPILogon ((ULONG) hWnd, NULL, NULL, flFlags, 0, &lhSession);

If you provide a value for lpszProfileName (and lpszPassword if necessary), MAPILogon attempts to establish a session without a user interface. Only if this attempt fails will MAPILogon display the logon dialog box to allow the user to enter new credentials.


 Specifying a Profile During Logon

The MAPILogon call behaves differently depending on whether your application specifies a profile name. Normally a profile name is required. If your application specifies NULL for the lpszProfileName parameter in the MAPILogon call, MAPI first checks for an existing shared session. If possible, the shared session is used. If there is no shared session or if it cannot be used, the call to MAPILogon will fail.

Simple MAPI applications can use this behavior to test for the presence of an existing shared session before creating one of their own.


 Ending a Simple MAPI Session

♦	To end a Simple MAPI session

1.	Use the MAPILogoff function to close a session when it is no longer needed.

2.	Call MAPIFreeBuffer to release any buffers that were allocated by Simple MAPI calls and returned to your application for its use. Calling MAPILogoff does not cause buffers allocated by Simple MAPI calls to be released. Your application has that responsibility.


 Composing Messages

Composing a message implies either the creation of a new message or the forwarding of or replying to an existing message. The new message may contain new material. Replying to existing messages involves creating a new message and copying the contents of the original message to it. All new messages can specify a return recipt as well.

♦	To create a new message

1.	Allocate a MapiMessage structure.

2.	Fill in its fields with values appropriate for the message the user wants to send.

3.	Submit it to the messaging system using the MAPISendMail function.

♦	To forward an existing message

1.	Retrieve the message using the MAPIReadMail function.

2.	Modify the message as appropriate for forwarding:

•	Put one or more new recipients' addresses in the message's lpRecips field.

•	Modify the subject line to indicate that the message has been forwarded.

•	Allow the user to edit the message body to add their own comments.

3.	Submit it to the messaging system using the MAPISendMail function.

♦	To reply to a message

1.	Retrieve the message using the MAPIReadMail function.

2.	Modify the message as appropriate for replying:

•	Put the original sender's address into the lpRecips field.

•	Change the subject line to indicate that the message is a reply to an earlier message.

•	Allow the user to edit the message body to add their own comments.

3.	Submit it to the MAPISendMail function.

When your application submits a message with MAPISendMail, it has the option of requesting a return receipt. Return receipts are automatically generated messages that senders receive to inform them that messages they sent, for which a return receipt was requested, were delivered successfully to the recipient.

♦	To request a return receipt

Include the MAPI_RECEIPT_REQUESTED flag in the flFlags member of the MapiMessage structure:

// MapiMessage mymessage; declared and initialized elsewhere.

mymessage.flFlags |= MAPI_RECEIPT_REQUESTED;


 Using Message Headers

Message headers form the "envelope" of a message. The message header contains all the information about the recipients of the message, as well as a subject for the message.

Addressing messages involves three major tasks:

•	Generating lists of recipients for different recipient classes. There should be separate lists of addresses for primary recipients, carbon copy (CC) recipients, and blind carbon copy (BCC) recipients.

•	Checking names that the user enters against the address book to resolve them into actual addresses.

•	Getting details about address book entries to help the user choose between ambiguous entries.

Creating a subject line is a simple matter of generating a text string containing the subject.


 Generating Recipient Lists

Use the MAPIAddress function to generate a list of recipients for a message. If some of the recipients are known already, for example when forwarding a message, your application can pass in an initial array of MapiRecipDesc structures which the user can then modify.

The MAPIAddress function always displays a dialog box where the user can modify the list of recipients. If your application needs to generate a recipient list without presenting a dialog box, it should get recipients' names or addresses through some other means, using the MAPIResolveName function if necessary.

A successful call to the MAPIAddress function produces a buffer containing one or more MapiRecipDesc structures that your application must release with the MAPIFreeBuffer function when the buffer is no longer needed.


 Checking Names

Checking names is the process of using the MAPIResolveName function to take a recipient's display name (usually their real name or something derived from their real name) or partial display name and retrieve the address book entry corresponding to it.

♦	To check names

Your application should call MAPIResolveName. Your application has the option of allowing the display of addressing dialog boxes while resolving the name by including the MAPI_DIALOG flag in the flFlags parameter. If the MAPI_DIALOG flag is not present and the recipient's display name resolves to more than one address book entry, MAPIResolveName will return the error code MAPI_E_AMBIG_RECIP.

If the MAPI_DIALOG flag is present, Simple MAPI will present the user with a dialog box to resolve the ambiguity. If the MAPI_AB_NOMODIFY flag is also present, then the properties of addresses displayed in this dialog box will not be modifiable, even if the addresses are stored in the user's Personal Address Book.

Like MAPIAddress, a successful call to MAPIResolveName produces a buffer containing one or more MapiRecipDesc structures that must be released with a call to MAPIFreeBuffer.


 Getting Details About a User

The MAPIDetails function presents a dialog box to the user that displays the properties of an address book entry. This dialog box cannot be suppressed. Like the MAPIResolveName function, the MAPIDetails function supports the MAPI_AB_NOMODIFY flag to prevent modification of the properties displayed in the dialog box. The MAPIDetails function is most often used with this flag when the user needs more information about an address in order to resolve an ambiguity. The function is most often used without the MAPI_AB_NOMODIFY flag when the user needs to create or edit entries in the Personal Address Book.


 Displaying and Editing Addresses

The MapiRecipDesc structure, which describes a recipient, contains both the recipient's address and the recipient's "friendly name". The address, contained in the lpszAddress member, contains the address that the messaging system uses to deliver the message. This can take a number of forms, depending on what type of address it is. All addresses are of the form [AddressType][Email Address]. For example, an internet address could be SMTP:jdoe@microsoft.com, while a fax gateway address could be FAX:206-555-1212.

The friendly name, stored in the lpszName member, typically contains the recipient's actual name or some variation on it. Whenever possible, the messaging system places a value in this member when a message is retrieved from a message store. However, not all addresses can be assigned a friendly name. For example, a fax gateway address might not correspond to a specific person, so the address book might not contain a name associated with that address. Similarly, the nature of internet addresses is such that the messaging system might not be able to determine a friendly name for messages that come into the system through an internet gateway; the address book cannot contain entries for every valid internet address, and the format of internet addresses does not mandate that a friendly name be attached to them.

Your application should display friendly names to the user when they are available. When they are not, it is acceptable to display the actual address instead. When forwarding or replying to a message, your application should never allow the user to edit the friendly name or address fields of a MapiRecipDesc that the messaging system has returned with a message. Both friendly names and addresses should be treated as indivisible entities.

When displaying a message to the user, your application should make a distinction between different types of recipients that might be present in the message's lpOriginator and lpRecips members. The lpOriginator member contains the address and friendly name of the individual who sent the message. Your application should display this recipient (note that the originator of a message is still called a recipient because both originators and actual recipients are described by MapiRecipDesc structures) such that the user is aware of this recipient's role.

Recipients stored in the lpRecips member can have one of four different roles. The ulRecipClass member of the MapiRecipDesc structure stores this information:

Role	Description
MAPI_TO	The recipient is one of those who the original message was primarily addressed to.
MAPI_CC	The recipient received a carbon copy of the original message.
MAPI_BCC	The recipient received a blind carbon copy of the original message.
MAPI_ORIG	The recipient sent the message.
In practice, MAPI_BCC and MAPI_ORIG are less common than the others. MAPI_BCC should only occur if the user reading the message is the one who received a blind carbon copy. The semantics of MAPI_BCC are such that no one besides the originator and a MAPI_BCC recipient should ever know that the recipient received the message. MAPI_ORIG should only occur if the user sent a message to himself or herself.


 Using the Subject

Using the subject when displaying a message is simple; the subject is simply a null terminated string stored in the lpszSubject member of a MapiMessage structure.

When replying to or forwarding a message, it is customary for your application to modify the subject line. The subject of a reply to a message should begin with the string "RE:", or an appropriate localized equivalent. Similarly, forwarded messages should have subject lines that begin with "FW:" or an appropriate localized equivalent. If the subject line already begins with "RE:" or "FW:", your application should not add it again.


 Sending Messages

♦	To send a message

1.	Create a MapiMessage structure to contain the message.

2.	Create one or more MapiRecipDesc structures describing the recipients of the message and place them in the lpRecips field of the message structure.

3.	Create a text string containing the subject, if any, and place it in the lpszSubject field of the message structure.

4.	Create a text string containing the message text, if any, and place it in the lpszNoteText field of the message structure.

5.	Create an array of MapiFileDesc structures, if necessary, to contain any attachments and placce it in the lpFiles field of the message structure.

6.	Submit the message with the MAPISendMail function.

Sending messages may involve more or less effort on the part of your application, depending on the way you invoke various Simple MAPI functions to perform the above steps. See the Programming Examples topic for more information.


 Handling Attachments

Simple MAPI handles attachments by means of an array of MapiFileDesc structures pointed to by the lpFiles member of a message structure. The nFileCount member of the message structure indicates the length of the array, with a value of 0 indicating no attachments.

Simple MAPI recognizes three types of attachments: data files, editable OLE objects, and static OLE objects. The value of the flFlags member of a MapiFileDesc structure informs Simple MAPI of the type of attachment it describes. Each attachment has a nPosition member that stores its position within the message. The position is an index into the message's lpszNoteText member (which can be treated as an array of characters). The attachment will appear at the character at its position in the message; that is, the attachment will be rendered in place of the character lpszNoteText[nPosition]. The special value -1 (0xFFFFFFFF) indicates that the attachment is not rendered in this way; in this case, the application that receives the message is responsible providing the user with a way of accessing the attachment. Note that the position is a character position within the text note, not a byte offset into the text note. This is an important distinction when double byte character sets are in use.

Note  The attachment should be rendered instead of the character stored in lpszNoteText[nPosition]. The actual value of lpszNoteText[nPosition] should be completely immaterial to the way the message is displayed to the user.

♦	To add attachments to a message, your application needs to do the following

1.	Allocate an array of MapiFileDesc structures, one for each attachment.

2.	Set the members of each array element to values appropriate for the data files or OLE objects that are being attached.

3.	Set the message's nFileCount member to the number of attachments.

4.	Set the message's lpFiles member to the address of the first element of the array of MapiFileDesc structures.

♦	To handle attachments in a message your application has received, your application needs to do the following

1.	Scan the attachments in the array of MapiFileDesc structures and note their character positions.

2.	When displaying the message text for the user, place graphic representations of data file attachments or OLE objects at the appropriate positions.

3.	Provide a mechanism for the user to interact with the attachments. You might choose to implement a point-and-click interface, or allow users to select actions such as saving and opening from a menu.


 Message Options

Simple MAPI supports a few options for messages and for sending messages. Some of these options are accessed through members of the MapiMessage structure, and some through parameters to the MAPISendMail function.


 MapiMessage

The lpszMessageType member indicates the type of the message. The most common type is the interpersonal message, or IPM. A NULL value for lpszMessageType or a pointer to an empty string indicates an interpersonal message. Applications can use this field to define their own message types. Be aware that not all messaging systems support message types other than IPM. Those messaging systems will ignore lpszMessageType.

The lpszMessageType member is also used to indicate when a message is a non-delivery report (NDR). The messaging system formats the non-delivery for a message type as "REPORT." plus the message type plus ".NDR". For example, if your application uses a message type of  "mytype", the NDR for such a message will have "REPORT.mytype.NDR" as its lpszMessageType string. For applications that deal with multiple types of message, your application can compare the last four characters of the lpszMessageType string against ".NDR" to determine whether the message is a non-delivery report. Naturally, it would be a bad idea for your application to choose a string that ends in ".NDR" as its internal message type. Note that while non-delivery reports generated by MAPI follow this convention, non-delivery reports generated by transport providers for external mail delivery systems might not.

The flFlags member can be used to request a receipt and to detect the read or unread and sent or unsent status of a message. When sending a message, your application can set the MAPI_RECEIPT_REQUESTED flag to request a receipt. When reading a message, your application can test for the MAPI_UNREAD flag to determine whether the message has not yet been read. Similiarly, your application can test for the MAPI_SENT flag to determine whether the message has been sent. When saving a previously unsaved message, your application should set the MAPI_UNREAD and MAPI_SENT flags as appropriate for the message.


 MAPISendMail

The MAPISendMail function supports options through its flFlags parameter. Your application can set the following flags when sending a message:

Flag	Description
MAPI_LOGON_UI	Allow s a logon interface if required. This flag should be set if your application is using an implicit session.
MAPI_NEW_SESSION	Prevents Simple MAPI from using an existing shared session if one is present.
MAPI_DIALOG	Displays a dialog box which allows the user to create a message. This flag should be set if your application does not have a MapiMessage structure already constructed, or if the user is composing a message interactively.


 Programming Examples

The code examples in this chapter are provided to illustrate these concepts in detail. Additional code examples can be found in the SMPCLI application included with the MAPI SDK. SMPCLI is not a typical Simple MAPI application in that it exists solely to illustrate every Simple MAPI function. It is good for illustrating the use of all the Simple MAPI APIs, but it is not good for illustrating typical use of those APIs in real situations.

The following three examples show how an application can send and receive messages with varying degrees of control. The first example sends a message very simply, leaving creation of the message's contents almost entirely up to Simple MAPI through user interaction. The second example takes more control over creation of the message and demonstrates how to use the MAPIResolveName function to check that addresses are valid before sending. The third example shows how to receive and display a message. Comments are placed above sections that benefit from explanation.


 Sending a Message Simply

This example shows the simplest way of sending a message. An essentially blank message is created and passed to MAPISendMail with parameters that cause Simple MAPI to use dialog boxes to create the content of the message. First, the application defines the variables it needs. Note that a real application would almost certainly not hard-code the attachment pathname or filename in the MapiFileDesc structure.

// Example 1:

// Send a mail message containing a file and prompt for

// recipients, subject, and note text.

ULONG err;

MapiFileDesc attachment = {0,         // ulReserved, must be 0

                           0,         // no flags; this is a data file

                           (ULONG)-1, // position not specified

                           "c:\\tmp\\tmp.wk3",  // pathname

                           "budget17.wk3",      // original filename

                           NULL};               // MapiFileTagExt unused

// Create a blank message. Most members are set to NULL or 0 because

// MAPISendMail will let the user set them.

MapiMessage note = {0,            // reserved, must be 0

                    NULL,         // no subject

                    NULL,         // no note text

                    NULL,         // NULL = interpersonal message

                    NULL,         // no date; MAPISendMail ignores it

                    NULL,         // no conversation ID

                    0L,           // no flags, MAPISendMail ignores it

                    NULL,         // no originator, this is ignored too

                    0,            // zero recipients

                    NULL,         // NULL recipient array

                    1,            // one attachment

                    &attachment}; // the attachment structure

Next, the application calls MAPISendMail and stores the return status so it can detect whether the call succeeded. A real application should use a more sophisticated error reporting mechanism than the printf function.

err = MAPISendMail (0L,          // use implicit session.

                    0L,          // ulUIParam; 0 is always valid

                    &note,       // the message being sent

                    MAPI_DIALOG, // allow the user to edit the message

                    0L);         // reserved; must be 0

if (err != SUCCESS_SUCCESS )

    printf("Unable to send the message\n");


 Controlled Sending of a Message

This example shows how an application can take more control over a message it sends by specifying more of the contents of the message, validating addresses before sending, and by denying a sending interface to the user. Again, the application starts by defining the variables it needs.

// Example 2:

// Send a mail message containing a spreadsheet and a short note

// to Sally Jones and copy the Marketing group. Don't prompt the user.

ULONG err;

MapiRecipDesc recips[2],     // this message needs two recipients.

             *tempRecip[2];  // for use by MAPIResolveName

// create the same file attachment as in the previous example.

MapiFileDesc attachment = {0, 0, (ULONG)-1, "c:\\budget17.wk3", "budget17.wk3", NULL};

The application then uses MAPIResolveName to generate MapiRecipDesc structures for the recipients of the message. It could create them directly, as in the previous example, but then no error checking is possible. Since this application is creating and sending the message without any interaction from the user, it is important to make sure the addresses are valid before sending the message.

// get Sally Jones as the MAPI_TO recipient:

err = MAPIResolveName(0L,            // implicit session

                      0L,            // no UI handle

                      "Sally Jones", // friendly name

                      0L,            // no flags, no UI allowed

                      0L,            // reserved; must be 0

                      &tempRecip[0]);// where to put the result

if(err == SUCCESS_SUCCESS)

    { // memberwise copy the appropriate fields in the returned

      // recipient descriptor.

        recips[0].ulReserved   = tempRecip[0]->ulReserved;

        recips[0].ulRecipClass = MAPI_TO;

        recips[0].lpszName     = tempRecip[0]->lpszName;

        recips[0].lpszAddress  = tempRecip[0]->lpszAddress;

        recips[0].ulEIDSize    = tempRecip[0]->ulEIDSize;

        recips[0].lpEntryID    = tempRecip[0]->lpEntryID;

    }

else

    printf("Error: Sally Jones didn't resolve to a single address\r\n");

// get the Marketing alias as the MAPI_CC recipient:

err = MAPIResolveName(0L,            // implicit session

                      0L,            // no UI handle

                      "Marketing",   // friendly name

                      0L,            // no flags, no UI allowed

                      0L,            // reserved; must be 0

                      &tempRecip[1]);// where to put the result

if(err == SUCCESS_SUCCESS)

    { // memberwise copy the appropriate fields in the returned

      // recipient descriptor.

        recips[1].ulReserved   = tempRecip[1]->ulReserved;

        recips[1].ulRecipClass = MAPI_CC;

        recips[1].lpszName     = tempRecip[1]->lpszName;

        recips[1].lpszAddress  = tempRecip[1]->lpszAddress;

        recips[1].ulEIDSize    = tempRecip[1]->ulEIDSize;

        recips[1].lpEntryID    = tempRecip[1]->lpEntryID;

    }

else

    printf("Error: Marketing didn't resolve to a single address\r\n");

Now the application creates the message. Again, a real application would almost certainly not hard-code the actual values of the MapiMessage's members.

MapiMessage note = {0, "Budget Proposal", "Here is my budget proposal.\r\n", NULL, NULL, NULL, 0, NULL, 2, recips, 1, &attachment};

Again, send the message and record the return value. This time no user interface is displayed. After the MAPISendMail call, the MapiRecipDesc structures allocated by MAPIResolveName must be released.

err = MAPISendMail (0L,    // use implicit session.

                    0L,    // ulUIParam; 0 is always valid

                    &note, // the message being sent

                    0L,    // do not allow the user to edit the message

                    0L);   // reserved; must be 0

if (err != SUCCESS_SUCCESS )

    printf("Unable to send the message\n");

MAPIFreeBuffer(tempRecips[0]);  // release the recipient descriptors

MAPIFreeBuffer(tempRecips[1]);


 Receiving and Displaying Messages

The following example function shows how an application can receive a message with Simple MAPI. To simplify the example, this example assumes that a character interface is being used.

First the application defines needed variables and logs on to get a session handle. Unlike when sending a message, the Simple MAPI functions for reading messages can't log on implicitly and require an explicit session handle.

ULONG ReadNextUnreadMsg()

{

ULONG err;

LHANDLE lhSession;      // Need a session for MAPIFindNext.

CHAR rgchMsgID[513];    // Message IDs should be >= 512 CHARs + a null.

MapiMessage *lpMessage; // Used to get a message back from MAPIReadMail.

int i,                  // Ubiquitous loop counter.

    totalLength;        // Number of characters printed on a line.

err = MAPILogon(0L,               // ulUIParam; 0 always valid.

               "c:\pst\myprofil.pro",// Real app wouldn't hardcode this.

               NULL,              // No password needed.

               0L,                // Use shared session.

               0L,                // Reserved; must be 0.

               &lhSession);       // Session handle.

if (err != SUCCESS_SUCCESS)       // Make sure MAPILogon succeeded.

{

    printf("Error: could not log on\r\n");

    return(err);

}

Next the application searches for the first unread message in the default folder in the store (probably the user's Inbox). Since there might not be any unread messages in the folder, the application first tests the return code from MAPIFindNext against MAPI_E_NO_MESSAGES before checking against SUCCESS_SUCCESS. If the call is successful, the application will have a valid message ID to use to retrieve the first unread message.

// find the first unread message

err = MAPIFindNext(lhSession, // explicit session required

                   0L,        // always valid ulUIParam

                   NULL,      // NULL specifies interpersonal messages

                   NULL,      // seed message ID; NULL=get first message

                   MAPI_LONG_MSGID | // needed for 512 byte rgchMsgID.

                   MAPI_UNREAD_ONLY, // only get unread messages.

                   0L,        // reserved; must be 0

                   rgchMsgID);// buffer to get back a message ID.

if (err == MAPI_E_NO_MESSAGES) // make sure a message was found

{

    printf("No unread messages.\r\n");

    return(err);

}

if (err != SUCCESS_SUCCESS)    // make sure MAPIFindNext didn't fail

{

    printf("Error while searching for messages\r\n");

    return(err);

}

The application can now be sure it is safe to retrieve the message. However, it is still a good idea to check the return code from MAPIReadMail. If the call fails, the memory pointed to by the application's lpMessage pointer will not be accessible by the application. The application should not try to display a message at that location. Note that this example sets the MAPI_SUPPRESS_ATTACH flag so the returned message will not have any attachments in it and Simple MAPI will not create any temporary files for them.

// retrieve the message

err = MAPIReadMail(lhSession,   // Explicit session required.

                   0L,          // Always valid ulUIParam.

                   rgchMsgID,   // The message found by MAPIFindNext.

                   MAPI_SUPPRESS_ATTACH, // TO DO: handle attachments.

                   0L,          // Reserved; must be 0.

                   &lpMessage); // Location of the returned message.

if(err != SUCCESS_SUCCESS)      // Make sure MAPIReadMail succeeded.

{

    printf("Error retrieving message %s\r\n",rgchMsgID);

    return(err);

}

Now the application can display the message. As is customary, it begins by displaying the addressing information attached to the message before displaying the subject line and message body. When displaying the addressing information, it is best if the application can display friendly names. However, since friendly names are not always available, the application must verify that each recipient structure's lpszName member points to a valid string, and that the string is not a null string.

// Display the sender's name or address; use the friendly name

// if it is present.

if((lpMessage->lpOriginator->lpszName != NULL) &&

   lpMessage->lpOriginator->lpszName[0] != '\0')

    printf("From: %s\r\n",lpMessage->lpOriginator->lpszName);

else

    printf("From: %s\r\n",lpMessage->lpOriginator->lpszAddress);

Displaying the recipients' addresses is complicated by the desire to avoid breaking a receipient's name or address across two lines. This code could be further improved by differentiating between recipients based on their ulRecipClass member so that they could be properly displayed as To, CC, or BCC recipients. As this code shows, handling recipient data can be the most complex part of reading a message.

// Display the recipients' names or addresses.  To Do: enhance

// this code to separate the recipients into lists of MAPI_TO,

// MAPI_CC, and MAPI_BCC recipients for separate display.

if(lpMessage->nRecipCount == 0)

    printf("Warning: no recipients present for this message\r\n");

else

    for(i = 0; i < lpMessage->nRecipCount; i++) // For each recipient...

    {

        // This code uses lstrlen to calculate the length of strings and

        // to validate that the strings have some content, since the

        // length is needed anyway. This avoids the more verbose checks

        // as were done for lpMessage->lpOriginator->lpszName earlier.

        // lpszT references a name or address; simplifies later code.

        // length is the length of the name or address.

        LPSTR lpszT = lpMessage->lpRecips[i]->lpszName;

        int length = lstrlen(lpszT);

        if(i == 0) // First recipient; need to do some initialization.

        {

            printf("Recipients:");

            totalLength = 11;      // since strlen("Recipients:") = 11.

        }

        // Decide whether to use the friendly name or the address.

        if(length == 0)

            length = lstrlen(lpszT=lpMessage->lpRecips[i]->lpszAddress);

        // Verify that the line has room for this name or address. If

        // not, print a CR LF pair to go to the next line.

        if(totalLength + length + 1 > LINE_WIDTH)

        {

            printf("\r\n");

            totalLength = 0;

        }

        printf(" %s",lpszT);      // Finally, print the name or address.

        totalLength += length + 1;// Maintain the line length.

        // If there are more addresses, separate them with semicolons.

        if(i < (lpMessage->nRecipCount - 1))

        {

            printf(";");

            totalLength++;

        }

    }

Now the application displays the subject line and message body, if they are present. Note that the message text can be printed with a simple call to printf. Since the message was read with the MAPI_SUPPRESS_ATTACH flag set, there are guaranteed not to be any attachments in it.

// Display the subject and message body. Not printing anything for the

// subject is fine, but something should always be printed for the

// message body since it is the last thing that this function displays.

if(lpMessage->lpszSubject    != NULL &&   // Standard validity check

   lpMessage->lpszSubject[0] != '\0')

    printf("Subject: %s\r\n",lpMessage->lpszSubject);

if(lpMessage->lpszNoteText    != NULL &&  // Standard validity check

   lpMessage->lpszNoteText[0] != '\0')

    printf("Message Text:\r\n%s",lpMessage->lpszNoteText;

else

    printf("No message text.\r\n");

Finally, the application releases the storage that MAPIReadMail allocated for the message, closes the session, and returns a successful return code.

MAPIFreeBuffer(lpMessage);

MAPILogoff(lhSession,    // The session.

           0L,           // 0 always valid for ulUIParam.

           0L,           // No logoff flags.

           0L);          // Reserved; must be 0.

return SUCCESS_SUCCESS;  // Inform the caller of our success.

} // End of ReadNextUnreadMsg.


 About MAPI Objects

Now it is time to move into the object oriented world of programming with Extended MAPI. Programming with Extended MAPI is similar to programming with any other object oriented API. With Extended MAPI, you will implement some objects and use other objects. Where Extended MAPI differs from the standard object oriented methodology is in its special use of objects.

Extended MAPI, as mentioned previously, is based on the Component Object Model (COM) introduced with OLE. The Component Object Model is a specification that defines an environment for sharing code and data across processes. COM objects are unique because their public methods belong to one or more MAPI interfaces, or collections of related functions. Outsiders obtain access to COM objects only through pointers to these interfaces. MAPI interfaces define how objects behave and operate within the COM world.

MAPI defines many types, or classes, of objects, each type characterized by the interfaces it supports. Depending on whether you are creating a client application or a service provider, you will implement some objects and use others. When you implement an object, you provide the code for its interface methods. When you use an object, you make calls to the methods.

The following table defines the types of MAPI objects that clients and service providers work with in a typical session. You may recognize some of these types from the architectural discussion in Chapter 1.

MAPI Object Type	Description
Property	An object that describes a set of attributes for a MAPI object, these are the object's private data members
Table	An object that provides access to an object's private data in row and column format, similar to a database table
Container	An object that provides access to a collection of objects
Message	An object that can be sent to one or more recipients with a messaging system
Folder	An object that acts as a container for messages
Attachment	An object that contains additional data, such as a file, to be associated with a message
Message Store	An object that acts as a database of messages, organized hierarchically
Mail User	An object that describes an individual recipient of a message.
Distribution List	An object that describes a grouping of individual message recipients
Address Book	An object that acts as a database of recipients
Profile Section	An object that describes a particular message service or service provider
Session	An object created by the MAPI subsystem and passed to clients to represent a connection to underlying messaging systems
Support	An object created by the MAPI subsystem and passed to service providers to help them take care of client requests
Status	An object that is used to obtain access to the state of a session resource, such as the MAPI spooler or a service provider
Advise Sink	An object that provides a callback to be invoked when a particular object experiences a change or an error occurs
Logon	An object created by a service provider and passed to the MAPI subsystem for handling event notification and client requests
Provider	An object created by a service provider and passed to the MAPI subsystem for handling provider logon and shut down.
Form Server	An object for managing a user's interaction with a custom dialog box for entering data
Form Container	An object that provides access to information about a custom dialog box
Some of these types of objects have single implementations while other types have multiple implementations. For example, when a user logs on to MAPI, a session object is created that represents a connection with the messaging systems accessed through the message services listed in the profile. Each session has only one session object.

Property objects, on the other hand, are instantiated many times during the course of a session. Property objects describe the private data of other MAPI objects. For example, every message object includes in its private data one or more recipients. This data is accessible only through the interface methods implemented in the property object. Properties are explained in more detail in Chapter 7, "About MAPI Properties".

Table objects are another example of frequently implemented MAPI objects. Table objects make it possible to view properties in row and column format. Each row in the table represents a MAPI object and each column represents the value of one of the object's properties. There are many types of tables, named for the type of objects that are represented in the tables' rows. For example, the service providers table lists properties for all of the service providers in the current session. The status table lists the properties for status objects. Status objects are implemented by MAPI and service providers to provide access to status information. For more detail about MAPI tables, see Chapter 9, "Using Tables."

Some objects have the concept of access, meaning that when you open an object, you are granted a particular level of access. Only if you are granted read-write access will you be allowed to make changes and save those changes permanently. The level of access that you are given when you open an object depends on the specific object being opened, the access level you request, the service provider processing the open call, and your own individual access rights. MAPI allows you to request a type of access by defining the MAPI_MODIFY for read-write access and the MAPI_BEST_ACCESS flag for the highest level of access that the service provider can allow. Remember that you are only requesting a particular level of access; the final say is up to the service provider. That is, if a service provider does not  allow changes to be made to its objects, setting the MAPI_MODIFY flag will never have an effect.


 About Object Relationships

MAPI objects are related in several different ways. Some objects have a hierarchical relationship. The association between message stores, folders, messages, and attachments is an example of this type of relationship. A message store contains folders which contain messages which contain attachments. Other objects have a sibling relationship, where the objects share properties and behavior. For example, there are two types of container objects: folders and address book containers. Both of these objects allow users to set search criteria, to open sub-objects (that is, objects contained within them), and to retrieve two types of tables: a contents table and a hierarchical table.

Figure 1 below shows hierarchical and sibling relationships of some of the MAPI objects from the client's perspective. The session object is at the top of the tree because it is through the session that the client gains access to all other objects. The next level includes the message stores table, a table object that lists properties for all of the message store providers in the current session, and the MAPI address book, a composite object that supplies access to all of the address book providers. The message stores table and address book are used to access the objects implemented by particular service providers, shown next, in hierarchical order.

Figure 1.  Sibling and Hierarchical Relationships Between Objects.

Another kind of relationship involves inheritance, the process by which one object acquires the data and methods of another object, enabling objects to be built as a collection of standard components. All COM objects support inheritance to some degree. Interfaces implemented by COM objects inherit from a single interface called IUnknown. Some interfaces inherit directly from IUnknown; other interfaces inherit from IUnknown through another interface. Inheritance enables an object's user to call methods in both the interfaces the object supports directly and the interfaces it inherits as if they belonged to the same interface. To the user, the difference is transparent.

For example, Figure 2 below shows a client application making two calls to a MAPI folder object, an object that supports the IMAPIFolder interface. IMAPIFolder inherits from the property object interface, IMAPIProp, which inherits from IUnknown. One of the calls, GetProps, belongs to the IMAPIProp interface. The other call, CreateMessage, belongs to IMAPIFolder. However, the client application doesn't know or care that these calls belong to different interfaces. The client simply directs the calls to the folder object.

Figure 2.  Inheritance Between Objects.


 Implementing MAPI Objects

MAPI objects are implemented using C data structures or C++ classes, depending on the language and the API set you are using for your client application or service provider. Service providers are written with C or C++ and the Extended MAPI API; client applications can use any of the three supported languages and the four supported API sets. If you are creating a new client application or service provider with Extended MAPI and you are vacillating between languages, use C++. Why? C++ is better because Extended MAPI is an object oriented technology and C++ lends itself more readily to object oriented development. Your code will be simpler and more straightforward making maintenance easier. Also, the syntax descriptions in The MAPI Programmer's Reference and the sample code in this volume are in C++. However, if you are proficient only in C and lack the time and resources to learn C++, don't worry. C clients and service providers work just fine.

When you define a MAPI object in C, you need to explicitly include a pointer to a virtual table, or Vtable, as the first member of your object. The Vtable is an array of ordered function pointers; there is one pointer for every method in each interface supported by your object. The order of the pointers must follow the order of the methods in the interface specification. Each function pointer in the Vtable is set to the address of the actual implementation of the method. In C++, the Vtable is set up for you by the compiler. In C, it is not.

Figure 3 illustrates how this works. An object wanting to use an interface retrieves a pointer to the interface. This interface pointer points to the Vtable pointer stored as the first member of the object implementing the interface. The Vtable pointer points to the actual Vtable and each member of the Vtable pointers to code implementing one of the methods in the interface..

Figure 3.  Internal Representation of a MAPI Object.

Now for an example to help clarify. Suppose you're defining an object that supports the fictional IFootBall interface. IFootBall, like all good MAPI interfaces, derives from IUnknown. IFootBall has three methods that are defined in the following order: Fumble, Pass, GetTouchDown.

You would define this object in C++ as follows. The IUnknown methods appear first followed by the IFootBall methods. Data and methods specific to the object, such as the reference count, follow.

class  CFootBall : public IFootBall
{
public:
// IUnknown virtual methods
    HRESULT QueryInterface
              (REFIID                     riid,
               LPVOID *                   ppvObj);
    ULONG   AddRef();
    ULONG   Release();

// IFootBall virtual methods
    HRESULT   Fumble();
    HRESULT   Pass();
    HRESULT   GetTouchDown();

// Other methods specific to this object
    BOOL IsGameOver();
    ULONG GetScore();

// Constructors and destructors
public :
    CFootBall ();
    ~CFootBall ();

// Data members
private :
    LONG                m_cRef;
    CSportObj *         m_pSportObj ;
};

The C implementation is more complex because of the added Vtable layer. The FOOTBALL object contains a pointer to its Vtable and private data and methods. The Vtable is initialized with the addresses of the implementation of these methods in the order specified by the interface.

typedef struct _FOOTBALL
{
    FOOTBALL_Vtbl FAR *lpVtbl;

//  Other methods specific to this object
    BOOL IsGameOver();
    ULONG GetScore();

//  Private data members
    LONG                m_cRef;
    CSportObj *         m_pSportObj ;
} FOOTBALL;

//  Vtable data structure

FOOTBALL_Vtbl vtblFTBALL =
{
IFootBall_QueryInterface,
IFootBall_AddRef,
IFootBall_Release,
IFootBall_Fumble
IFootBall_Pass,
IFootBall_GetTouchDown,
}

//  Code to initialize Vtable and data members

FOOTBALL * lpFootBall;

lpFootBall->lpVtbl = &vtblFTBALL;

lpFootBall->m_cRef = 1;

lpFootBall->m_pSportObj = lpSport;


 Using MAPI Objects

Using an object means calling methods in one of the interfaces implemented by the object. You make interface method calls indirectly through a pointer to the interface implementation. Interface pointers are returned by the QueryInterface method in IUnknown, by a method provided by a different object, or by an API function provided by MAPI. Many of the methods and API functions for instantiating objects return an interface pointer as an output parameter.

If you are using objects written in C++, you can use the pointer directly to make a method call as follows:

lpObj->Method(parm1, parm2, ...parmX);

However, in C, you would need to call the method indirectly, through the Vtable pointer, as follows:

lpObj->lpVtbl->Method(lpObj, parm1, parm2, ...parmX);

Notice the addition of the object pointer as the first parameter to the method call. The C++ compiler implicitly adds a pointer to the object you are calling as the first parameter to every method call. This pointer is known as the this pointer. Since in C there is no such pointer; you must add it as the first parameter in the parameter list for every method that you call.


 Identifying MAPI Objects

Many MAPI objects are identified by what is known as an entry identifier. Entry identifiers are data structures that contain two values: one that uniquely identifies the object instance itself and one that uniquely identifies the service provider that owns the object. The value that identifies the provider is known as a UID, or unique identifier. Service providers inform MAPI of their UID when they are initially loaded.

When clients make a call to MAPI or a service provider to request an operation on an object, they pass the entry identifier of the object as one of the call's parameters. The recipient of the call uses the entry identifier to determine who is responsible for the object and can handle the request.

Entry identifiers may be short-term or long-term. Short-term entry identifiers are valid only for the life of the session or until the memory for them is explicitly freed. Long-term entry identifiers are stored on disk, enabling them to last from session to session.


 About MAPI Interfaces

MAPI interfaces, as stated earlier, are collections of related functions. Interfaces provide a binary standard for object interaction and are what is known in the C++ world as abstract base classes. This means that only the prototypes of the methods are defined; the interface name, method names, and method parameters are specified, but there are no actual implementations. It is up to the object inheriting the interface to provide its own implementation. Sometimes this object is a service provider object; sometimes it is a client object; often it is an object provided with the MAPI subsystem.

MAPI interfaces define a contract between the object implementing the interface and the object using the implementation. This contract can be loose or tight, depending on the method. A loose contract allows a method to return MAPI_E_NO_SUPPORT, indicating no functionality. A tight contract disallows the MAPI_E_NO_SUPPORT return value; all implementations of the method must provide some functionality. For example, the IMAPIStatus::FlushQueues method makes sense only for transport providers. However, message store providers also implement status objects and the IMAPIStatus interface, using a loose contract. Message store providers return MAPI_E_NO_SUPPORT in their FlushQueues implementation.


 About Interface Relationships

As mentioned in the discussion about objects, all MAPI interfaces ultimately derive from the base COM interface, IUnknown. The MAPI inheritance hierarchy is fairly straightforward. There are only three base interfaces, or interfaces that other interfaces can inherit: IUnknown, IMAPIProp, and IMAPIContainer. Most interfaces are direct descendants of IUnknown, some inherit from IMAPIProp, and a few inherit from IMAPIContainer.

Figure 1.  MAPI Interface Hierarchy


 About IUnknown

IUnknown, as the top of the interface hierarchy, is implemented in all MAPI objects. IUnknown provides mechanisms for obtaining an interface implementation and controlling its lifetime with three methods: QueryInterface, AddRef, and Release. QueryInterface enables potential users of an object to find out if the object supports a particular interface. If the object does support the interface, QueryInterface returns a pointer to it. AddRef and Release make sure that an object is not freed while it is still being used, keeping a tally known as a reference count.

The following illustration shows how QueryInterface works. The person on the left is the caller; the person on the right is the object with the implementation of QueryInterface. The caller asks for an interface that supports specific functionality, in this case, baseball. Because the object doesn't support the interface, the caller receives nothing in return. However, when the caller asks a second time for a supported interface (that is, football), the object returns an interface pointer  that can be the basis for further interaction between the caller and the object. In this example, the ball represents the interface pointer.

Figure 2.  How the QueryInterface method works.

Now, to translate the conceptual into code. The following example shows how QueryInterface would be implemented in C++ for an object that supports the fictional MAPI Football interface. To provide a more interesting example, the IFootball interface inherits from the ISports interface which inherits from IUnknown, rather than directly inheriting from IUnknown. Notice that the same pointer can be returned for any of the interfaces.

HRESULT CFootball::QueryInterface (REFIID   riid,

                                   LPVOID * ppvObj)

{

    // Always set out parameter to NULL

    *ppvObj = NULL;

    // Is the caller asking for one of my interfaces?

    if (riid == IID_IFootball || riid == IID_ISports ||

        riid == IID_IUnknown)

    {

        // Yes - return pointer and increment reference count

        *ppvObj = (LPVOID)this;

        AddRef();

        return NOERROR;

    }

    // No - return error.

    return E_NOINTERFACE;

}

The AddRef and Release methods control the reference count of an object. The reference count defines the object's lifetime. Without reference counting, the object would never know when it was safe to free its memory. As long as the reference count is greater than zero, the object's memory will not be freed.

There are a few basic reference counting rules. All methods or API functions that return interface pointers must call AddRef to increment the reference count. All implementations of methods that receive interface pointers must call Release to decrement the count when the pointer is no longer needed. Release checks for an existing reference count, freeing the memory associated with the interface only if the count is 0. The following code samples show how to implement AddRef and Release for the CFootball object. For a detailed description of COM reference counting, refer to the OLE 2.0 Programmer's Reference.

//

ULONG CFootball::AddRef()

{

    // Increment the object's internal counter

    ++m_cRef;

    return m_cRef;

}

ULONG CFootball::Release()

{

    // Decrement the object's internal counter

    ULONG ulRefCountT = --m_cRef;

    // Deallocate if ref count is 0. Destructor frees memory

    if (0 == m_cRef)

    {

        delete this;

    }

    return ulRefCountT;

}


 Selecting Interfaces to Implement

Because MAPI provides so many interfaces, it can be difficult to determine exactly which interfaces to implement and which interfaces to use. Typically the type of MAPI component you are writing and the feature set it provides determines the set of interfaces you will need to implement and use.

Service providers implement many more interfaces than clients, who are primarily users of interfaces, rather than implementors. The typical client application will only have to implement one interface: IMAPIAdviseSink. IMAPIAdviseSink is used to send event notifications. If your client also works with custom forms, you'll have to implement these additional interfaces: IMAPIFormAdviseSink, IMAPIMessageSite, IMAPIViewAdviseSink, and IMAPIViewContext.

Address book, message store, and transport providers all implement their own flavor of provider interface and logon interface. The provider interfaces are called IABProvider, IMSProvider, and IXPProvider, respectively; the logon interfaces are called IABLogon, IMSLogon, and IXPLogon. All of the provider interfaces are used in the same way as the logon interfaces. MAPI uses the provider interfaces to start up and shut down a service provider and the logon interfaces to handle requests from clients. However, because there are tasks that are specific to the type of service provider, the provider and logon interfaces cannot be identical. Refer to the discussion in "Considerations for Service Providers" or to the MAPI Programmer's Reference for details about the implementation of these interfaces.

Address book providers also implement IABContainer, IDistList, IMAPITable, and IMailUser and the interfaces a few of these interfaces derive from: IMAPIContainer and IMAPIProp.

Message store providers also implement the base interfaces IMAPIContainer and IMAPIProp as well as IMsgStore, IMAPIFolder, IMessage, IAttach, IMAPITable, and IMAPIStatus.

Transport providers typically implement only two additional interfaces: IMAPIProp, and IMAPIStatus. Remote transport providers also implement IMAPIFolder and IMAPITable.

A few miscellaneous interfaces exist to support custom components such as form servers, message class handlers, and message hook providers. IMAPIForm and IPersistMessage are implemented by form servers; ISpoolerHook is implemented by hook providers.


 Selecting Interfaces to Use

The group of MAPI interfaces that you should use depends on the type of component that you are writing and the features you are including. Most clients and service providers frequently use IMAPITable and IMAPIProp and occasionally use IMAPIProgress. This is where the commonality between the two component types ends. Clients use a great many different interfaces, some implemented by MAPI and others implemented by service providers. MAPI provides clients with the IAddrBook interfaces for integrated address book access, the IMAPISession interface for general session access, and the IMAPIStatus interface for monitoring session status.

Clients can interact with service providers either indirectly, through IMAPISession, or directly through a variety of interfaces implemented by particular service providers. To make direct contact with address book providers, clients call the IABContainer, IDistList, and IMailUser interfaces. To access a message store provider directly, clients call IAttach, IMAPIFolder, IMessage, and IMsgStore. Clients also interact directly with service providers through their implementation of IMAPIStatus.

Clients that implement special features use other interfaces. For example, clients that perform profile and message service configuration use IProfAdmin, IMsgServiceAdmin, and IProviderAdmin and clients that display custom forms use IMAPIForm, IPersistMessage, IMAPIFormContainer, IMAPIFormInfo, and IMAPIFormMgr.

Service providers typically use only a few interfaces. They use IMAPISupport, a large interface implemented by MAPI to help service providers handle requests from clients. IMAPISupport has many methods, some of which are applicable to all service providers and others that apply only to specific types. See the MAPI Programmer's Reference for detailed information about the methods in IMAPISupport. Service providers that send event notifications also use IMAPIAdviseSink.

Some service providers use ITableData and IPropData, two utility interfaces implemented by MAPI. ITableData allows service providers to manage the underlying data of a table while IPropData allows service providers to set object and property access. Both of these interfaces are optional; service providers are not required to use them.

Transport providers that support the Transmission-Neutral Encapsulation Format (TNEF) for transferring properties use the ITnef interface supplied by MAPI.


 About MAPI Properties

There are two ways to define MAPI properties. First, there's the universal way as specified in Webster's Dictionary and introduced in the previous chapter "About Objects." Webster's Dictionary defines a property as an attribute common to all members of a class. In the MAPI environment, "members of a class" translates to instances of a MAPI object type. A property is used to describe a MAPI object of a particular type. For example, the message body, list of recipients, and message subject are properties of every MAPI message object.

The other definition is the object oriented COM way of looking at MAPI properties. MAPI properties are implemented as MAPI objects themselves. Like all MAPI objects, property objects implement an interface that derives from the IUnknown interface, in this case the IMAPIProp interface. However, MAPI property objects are special because they are never used by themselves as stand alone objects. Instead they are included in the objects they describe. That is, every MAPI message object includes a property object to provide access to its properties; included among them are the message body, list of recipients, and message subject.

Objects that include property objects implement interfaces that inherit from IMAPIProp. Most of the interfaces that inherit from IMAPIProp have their own set of unique methods like the IMessage interface, the interface implemented by message objects. However, some interfaces do not have any additional methods. An object that implements one of these interfaces is basically just a property object that offers access to its own set of properties. The only methods available to you with this type of object are the methods of IMAPIProp and IUnknown. An example of this special type of property object is the attachment object. Attachment objects implement the IAttach interface, which has no unique methods of its own. Client applications use attachment objects to access the properties of message attachments, such as the actual data and filename of the attachment.

The methods of IMAPIProp provide access not only to the property's value, but also to data that describes the value. Every property has an associated type and identifier, a combination known as the property's tag.

If you are familiar with C++, you could equate a C++ object's private data to a set of properties. An external user of a C++ object can only access the private data through one or more methods that the object defines as public. An external user of a MAPI object that supports a set of MAPI properties can only access those properties through one or more methods in its IMAPIProp implementation.

Figure 1 illustrates the structure of a MAPI message object, a typical example of an object that supports properties. Message objects implement the methods of the IMessage, IMAPIProp, and IUnknown interfaces. These methods are all public; message objects may or may not also have private method implementations. The properties and associated property tag information is kept private. In spite of the fact that there are three separate interfaces, from the client's perspective, there is only one set of methods. The pointer that the client gets back after making a call to instantiate a message object can be used to call any of the methods in any of the interfaces.

Figure 1  Layout of an object that supports properties.

Properties are used extensively throughout the MAPI architecture. MAPI defines a large set of properties, assigning each property a name, an identifier, and a type. Setting the value in some cases is up to the service provider, in some cases is up to the client, and in some cases it is up to MAPI. Some properties are read-only; once they have an initial value they cannot change. Other properties are read-write. The ability to change a read-write property may be based on your access to the property. That is, some properties are read-only to clients and read-write to service providers. Still other properties are what is known as computed; service providers set their value from the value of another property. Clients, or other users of the property, have read-only access to computed properties.

Because the MAPI architecture is open and extensible, it is possible to define new, custom properties that are accessed in the same way that the standard, predefined properties are accessed. It may be desirable to define new properties to support a custom message class or to supplement the standard set for an existing message class.

Property data is displayed using another type of MAPI object, the table. MAPI tables consist of rows that represent individual objects supporting the properties and columns that contain property values. For example, the status table is used to present session status information to clients. Each service provider contributes a row to the table. Each column in the row contains a value for a property that the service provider supports that is relevant to the status of the session.

Some properties apply to a variety of MAPI objects. In fact, any mail user or distribution list property can also appear on a message. To provide an alternate example, MAPI defines a property known as a display name which is a string that is used to represent an object in a dialog box. Folders, message stores, service providers, forms, and mail user and distribution list recipients all support the display name property, PR_DISPLAY_NAME. Other properties are specific to one type of object, such as the attachment method property, PR_ATTACH_METHOD. Attachment method is a property that describes the method by which data is associated with a message. This property applies only to MAPI attachment objects.

Properties can be short term, existing only for the duration of the current session, or long term, stored persistently and available throughout multiple sessions. MAPI objects can store their properties either with the data of the object or in the profile.

This chapter is divided into two main sections. The first section focuses on the data and methods of MAPI property objects. The second section goes into detail about implementing and using MAPI properties in your client or service provider.


 Property Value Data Structures

The property value, or SPropValue, data structure is used to describe each MAPI property. The SPropValue structure is made up of three pieces: the property tag, some bytes for alignment, and the property value.

The property tag is a 32-bit unsigned integer that contains the property's unique identifier in the high order 16 bits and the property's type in the low order 16 bits.

The alignment field is designed for computers that require 8-byte alignment for 8-byte values. You can allocate an array of property values on an 8-byte boundary and cause the array to automatically have the proper byte alignment. If you write code on such computers, you should use memory allocation routines that allocate the SPropValue arrays on 8-byte boundaries.

The property value is a union of type PV. Depending on the type of property, its value varies. Some properties are single integers, some are character strings, some can be MAPI objects themselves.

The SPropValue data structure is defined as follows.

typedef struct _SPropValue

{

ULONG	ulPropTag;

ULONG	dwAlignPad;

union _PV	Value;

} SPropValue, FAR *LPSPropValue;

This section discusses each of the fields in the SPropValue structure in detail, describing their purpose and organization. More information about how the structure is used and implemented is covered in the "Working with Properties" sections, later in this chapter.As mentioned above, each property has a type, an identifier, and a value. These pieces of data are stored in an SPropValue data structure, which is defined as follows:


 About Property Tags

Property tags, as mentioned above, they contain a unique identifier and a type. They are the first member of the SPropValue data structure and are structured as follows:

MAPI defines a set of property tags for use by clients and service providers. If necessary, new property tags can be created if the predefined ones are insufficient. MAPI's property tags are represented by constants stored in the MAPITAGS.H header file. These constants follow a naming convention for consistency and ease of use. All property tags begin with the prefix "PR_."

A few macros are available to help manipulate the property tag data structure, among them PROP_TYPE, PROP_ID, and PROP_TAG. PROP_TYPE extracts the property type from the property tag; PROP_ID extracts the identifier. PROP_TAG builds the property tag from a property type and identifier.

These next sections describe property identifiers and types in detail.


 About Property Identifers

Property identifiers are used to indicate what a property is used for and who is responsible for it. Property identifiers are divided by MAPI into ranges; where an identifier falls in the range indicates its use and ownership.

The range of property identifiers runs from 0001 through 3FFF. Property identifiers 0000 and FFFF are reserved in all cases, meaning that these identifiers must remain unused. The range for MAPI's sole use runs from 0001 to 3FFF. The range 4000 to 7FFF belongs to message and recipient properties. Beyond 8000 is the range for what is known as named properties, or properties that have a name associated with their identifier. Service providers use named properties to customize their property set.

Service providers can use the range 0x67F0 thru 0x67FF to define secure properties. Secure properties have values that are hidden and encrypted, a useful way for storing passwords and other information that requires additional protection.

Some properties are defined as being either transmittable or non-transmittable. Transmittable properties are transferred with a message; non-transmittable properties are not transferred with a message. Non-transmittable properties usually contain information that is of local value for the current session. Another messaging system would not be able to use the non-transmittable properties. For example, the property that says when a message has been received is specific to the message. The concept of transmittable properties applies primarily to transport providers. To easily determine whether a property tag is transmittable or not, use the FIsTransmittable macro (see the MAPITAGS.H header file).

The following table summarizes the different ranges for property identifiers, describing who is responsible for the properties in each range.

Range	Owner	Type of Property
0001 - 0BFF	MAPI	Message envelope properties
0C00 - 0DFF	MAPI	Recipient properties
0E00 - 0FFF	MAPI	Non-transmittable message properties
1000 - 2FFF	MAPI	Message content properties
3000 - 3FFF	MAPI	Properties for objects other than messages and recipients
4000 - 57FF	Transport providers	Message envelope properties
5800 - 5FFF	Transport providers	Recipient properties
6000 - 65FF	User	Non-transmittable message properties
6600 - 67FF	Any service provider	Internal non-transmittable properties invisible to clients
6800 - 7BFF	Creators of custom message classes	Message content properties
7C00 - 7FFF	Creators of custom message classes	Non-transmittable message properties.
8000 - FFFE	User	Properties identified only by name, through the methods in IMAPIProp for mapping property names to identifiers
The range between 3000 and 3FFF is reserved for properties that are not related to either messages or recipients. MAPI divides this range into sub-ranges by types of object; the following table shows this further breakdown.

Identifier Range	Contents
3000 - 33FF	Common properties, such as display name and entry identifier.
3400 - 35FF	Message store properties
3600 - 36FF	Container properties
3700 - 38FF	Attachment properties
3900 - 39FF	Address book properties
3A00 - 3BFF	Mail user properties
3C00 - 3CFF	Distribution list properties
3D00 - 3DFF	Profile properties
3E00 - 3FFF	Status object properties


 About Property Types

Property types represent the format of the property value, the underlying data type. The set of property types defined by MAPI is included in the MAPIDEFS.H header file. These types are represented by constants that follow a similar naming convention as the one for property tags. All property types have two parts; the first part is the prefix "PT_" and the second part is a string describing the actual type, such as LONG or STRING8.

Unlike property identifiers, new property types cannot be created. New properties must be defined using the existing types.

Property types may be single or multi-valued. A single value property contains one value of its type such as a single integer, Boolean, character string, sized array of bytes, or data structure.

A multi-value property contains multiple values of the same type. To represent a multi-value property, the flag MV_FLAG is combined with the property type in a logical OR operation. The following diagram illustrates the structure of a multi-valued property of type PT_LONG. The value is no longer a single variable; it is made up of a pointer that points to an array of values and a count of the number of values in the array.

Figure 2    A Multi-valued property

MAPI recommends that service providers and clients support both single and multi-valued properties because doing so enables a wider variety of MAPI components to be used.

Some of the property types have special meaning and use. The property type PT_UNSPECIFIED is used for properties whose type is unknown. You can specify this type in calls to IMAPIProp::GetProps to retrieve these properties and find out their types. The correct type will replace the PT_UNSPECIFIED.

The PT_OBJECT type represents a property that is a separate object. The hierarchy table property of a message store, the PR_CONTAINER_HIERARCHY property, is a MAPI table object. Clients can access this table object property either by calling IMAPIProp::OpenProperty or IMAPIContainer::GetHierarchyTable.

There are three types of string properties: PT_STRING8 for 8 bit ANSI character strings, PT_UNICODE for double byte character strings, and PT_TSTRING for representing either of the first two types. String properties are available in the character set appropriate to their user's environment. For example, if the user is running in a Unicode environment, all PT_TSTRING properties become type PT_UNICODE. If the user is running in an environment with single-character (ANSI) strings, all PT_TSTRING properties become type PT_STRING8. Service providers that can support both Unicode environments and ANSI environments can achieve more widespread distribution than providers who cannot. Double byte character set strings terminate with a single 8-bit byte and are characterized as PT_STRING8.

String properties can be quite large, making it impossible to retrieve their values using the standard GetProps method. The body of a message, stored in the PR_BODY property, can be one of the largest string properties. In fact, some service providers this property to 4096 bytes, but other service provider implementations have no such limit. It is necessary to use the IStream interface to retrieve message bodies and other large string properties. To access an IStream pointer, call the IMAPIProp::OpenProperty method. To determine the size of a large string property, call IStream::Seek with the flag STREAM_SEEK_END. Be warned that this is not a fast operation.

The following code shows how to access the contents of a file using a stream object and setting

a large string property using OpenProperty.

The OpenStreamOnFile function opens and initializes a stream object with the contents of a file.

    LPSTREAM pSrcStrm, pDstStrm;

    HRESULT hResult = OpenStreamOnFile (MAPIAllocateBuffer,

                                MAPIFreeBuffer,

                                STGM_CREATE | STGM_READWRITE |

                                STGM_DIRECT | STGM_SHARE_EXCLUSIVE,

                                pszDestFile, NULL, &pDstStrm);

    if (SUCCEEDED(hResult))

    {

        // Open the source stream in the attachment object

        hResult = m_pAttachObj->OpenProperty (PR_ATTACH_DATA_BIN,

                                              (LPIID)&IID_IStream,

                                              0,

                                              0,

                                              (LPUNKNOWN *)&pSrcStrm);

        if (SUCCEEDED(hResult))

        {

            // How big is it?

            STATSTG StatInfo;

            pSrcStrm->Stat (&StatInfo, STATFLAG_NONAME);

            // Copy it all

            hResult = pSrcStrm->CopyTo (pDstStrm, StatInfo.cbSize, NULL, NULL);

            pSrcStrm->Release();

        }

        pDstStrm->Release();

    }

When large string properties are included in a table, the entire value might not be visible. This is because MAPI allows table implementors to truncate these property values at 256 bytes.

The following diagram illustrates a property value structure with all of the potential property types. Notice that not all of the single-valued types have multi-value equivalents.

Figure 3    An SPropValue Property Structure with a List of Valid Property Types

For a comprehensive description of each of these types, refer to the MAPI Programmer's Reference.


 Property Interfaces

So far, only one MAPI interface for property access has been mentioned - IMAPIProp. However, there is another interface, IPropData, that enables callers to retrieve and set the access rights for a property and for the object that supports the property and to add to the list of an object's supported properties. IPropData, implemented by MAPI, is a utility interface that inherits from IMAPIProp. This section discusses how each of these property interfaces are used and provides some tips for implementation that can be used generically by most client applications and service providers.


 About IMAPIProp

The IMAPIProp interface allows you to manipulate the properties of a MAPI object. There are methods for copying properties, making changes and saving those changes, mapping between property names and their identifiers, and retrieving information about a prior error.

Because it is a base interface for so many objects, IMAPIProp is one of the most frequently implemented and used interfaces in MAPI. The implementation of its methods varies from object to object. In other words, an implementation of IMAPIProp for a profile section object will be different than one for a message. Some objects permit no changes to any of their properties, for example, while other objects allow some of the values of their properties to be modified. Some methods will provide less functionality for one object than for another, returning MAPI_E_NO_SUPPORT or MAPI_E_TOO_COMPLEX in response to unsupported or overly difficult requests. Clients using IMAPIProp need to be prepared for all levels of support, and service providers implementing IMAPIProp need to know what is expected of them by clients.


 About IPropData

The IPropData interface provides the ability to retrieve and change the access for a property and its encompassing object. MAPI provides an implementation of IPropData that service providers can use by calling the API function CreateIProp. The main advantage to using IPropData over IMAPIProp, besides the additional methods, is that it saves you from having to implement IMAPIProp. You can use the implementation provided by MAPI.

The IPropData methods are listed in the following table:

Method	Description
HrSetObjAccess	Sets access rights for an object.
HrAddObjProps	Adds object type properties to an object.
HrSetPropAccess	Sets access rights for a property.
HrGetPropAccess	Gets access rights for a property.
HrAddObjProps registers property tags for object type properties  (that is, type PT_OBJECT). When clients call this method, they need to check the property problem array to determine if there were problems. Typically, the only problem that occurs is lack of memory. To add an object property, the target object must have read-write access. Any attempt to add an object type property to an object with read-only access will result in MAPI_E_NO_ACCESS being returned.

By default, an object has read-write access. That is, if you never call HrSetObjAccess, there will be no restrictions on your ability to make changes. Every property in the object will also have read-write access. If you want a read-only object, but you need to add properties to it, start with read-write access. Call HrAddObjProps to add the properties and then set the access to read-only by calling HrSetObjAccess. If you want an object that has read-write access to some properties and read-only access to others, call HrSetObjAccess to set the object's access to read-write and HrSetPropAccess to set individual properties to read-only access.

You can also use the HrSetPropAccess method to set the state of a property to clean or dirty. This is useful for determining when a particular property value changes. The bits in the flags parameter to this method are positional with respect to the property tag array parameter. Each bit corresponds to a bit in the property tag array.

The HrGetPropAccess method for retrieving access rights works in two ways. It will return the access level for individual properties or for all of the object's properties. If a property has been deleted, you won't find it in the property tag array that is returned. If you ask for a deleted property, you will get back zero for the access, meaning that no bit is set.


 Working with Properties

Working with MAPI properties is much like working with any piece of data; common operations include reading and writing, saving changes, and copying the data from one object to another. One of the more special operations you as a service provider can perform is to associate a name with a property identifier. Clients and other providers can use the name to refer to the property directly, without regard to its identifier. Another operation, available with other MAPI objects as well, enables the retrieval of detailled information about a prior error.

This section covers in detail these operations from the perspective of both the property implementor and its user.


 Retrieving Properties

Retrieving a property involves either making an IMAPIProp interface method call or a call to HrGetOneProp, an API function provided by MAPI. The IMAPIProp::GetPropList method retrieves a list of the properties supported by an object, an array of property tags is returned. The IMAPIProp::GetProps method is used most frequently to retrieve a property value structure for one or more small properties.

For large string properties or properties of type PT_OBJECT, IMAPIProp::OpenProperty must be used. When you call OpenProperty, you ask for access to an interface (other than IMAPIProp) that can better retrieve the property value. Callers typically ask for a pointer to an IStream interface implementation. IStream provides byte level access to data and allows such operations as seek, write, and read.

MAPI provides the HrGetOneProp helper function for retrieving one property only at a time. HrGetOneProp is useful when the target object exists on the local machine. If the target object is not locally available, avoid using HrGetOneProp. The result will be too many remote calls.

When you call GetProps, you pass in one or more property tags. A special property tag, PR_NULL, can be specified to indicate that you want to retrieve all of the properties for the object. An optional input parameter is a flag that requests all string properties to be returned in Unicode format. GetProps passes back an array of SPropValue data structures and a count of the number of structures in the array. A successful call can result in a return value of either S_OK or MAPI_W_ERRORS_RETURNED. The MAPI_W_ERRORS_RETURNED value is used when not all of the properties you requested could be returned. Depending on the implementation of GetProps, textual information describing the error is usually placed in the Value field of the SPropValue data structure instead of the real value for the inaccessible property.

As a property user, you will often want to retrieve a property value. Sometimes all you will have access to is a pointer to a MAPI property object; other times you will also have some property data, such as an identifier. Property values are typically accessed through the GetProps method or the HrGetOneProp API function. These calls requires as input a property tag. If you only have access to the identifier part of the tag, specify PT_UNSPECIFIED for the type in your call. If you have access to neither the type or the identifier in a property tag, call IMAPIProp::GetPropList. If you have a property name, a call to IMAPIProp::GetIDsFromNames will return the associated identifier that you can use in your GetProps or HrGetOneProp call.

Note  Secure properties are not automatically available with other properties in a GetProps, HrGetOneProp, or GetPropList call. Secure properties must be explicitly requested by property identifier.


 Copying Properties

There are two IMAPIProp methods for copying properties between objects. IMAPIProp::CopyTo copies or moves all of the properties from one object to another; CopyProps copies or moves a selected set.

The CopyTo method has a facility for specifying individual or object properties that you do not want to include in the copy operation. Individual properties to be excluded are specified in a property tag array; object properties to be excluded are specified in an interface identifier array. One use for this exclusion feature is to avoid copying the properties of an object that are specific to that instance of the object. For example, if you are copying the properties of one message to another message, you will probably want each message to have a unique time stamp for when it was sent. Also, you might want each message to have its own set of file attachments. To avoid copying the date and time of submission, specify PR_MESSAGE_DELIVERY_TIME in the property tag array. To avoid copying the attachments of the first message, specify IID_IAttach in the interface identifier array. If you specify a base interface in the interface identifier array, all of the interfaces that derive from it are also excluded.

Note  Do not ever exclude the IUnknown interface in your CopyTo call. Because IUnknown is at the top of the inheritance, excluding it will cause nothing to be copied.

When you are implementing CopyTo or CopyProps, show a progress dialog box if possible. These operations can take a long time. MAPI provides a progress object that you can use by calling the IMAPISupport::DoProgressDialog method. To request a progress dialog box when you are calling one of these methods, pass in the MAPI_DIALOG flag.

The MAPI_DECLINE_OK flag passed to IMAPIProp::CopyTo is used mostly when MAPI calls your provider to avoid recursion. This flag gives your provider an opportunity to avoid doing the work and to delegate the work to MAPI. This flag is normally not used by clients.

Sometimes a copy operation is too complicated to handle. Of course, as an implementor, you must try to retrieve as many of your properties as possible from wherever they are stored as quickly as possible. If you cannot complete a request, return MAPI_E_DECLINE_COPY. Callers need to be prepared to receive this return value and take an alternate course of action.

CopyTo passes back a property problem array that sometimes holds error information. If the method succeeds, the array will be empty. Ignore the ulIndex member in the SPPropProblemArray.

If you're going to be copying properties that are unique to a particular type of object, make sure that your source and destination objects are of the same type. You do not want to inadvertently copy the delivery time property, PR_DELIVER_TIME, to an address book object, for example. MAPI does not prevent clients and service providers from associating properties with objects

The PropCopyMore function, which copies a single value at a time, must be used with caution. It is possible to allocate many small blocks of memory, leading to a fragmented memory condition. Consider using ScCopyProps which copies values in bulk instead if you can. ScCopyProps copies property values that are possibly built from disjointed blocks of memory. After a call to ScCopyProps, you will have a new copy of a valid property array. If you need to store this array on disk, you will need to call ScRelocProps twice; once to adjust the addresses before writing the data operation and then again during the read operation. The ScRelocProps function assumes that the property value array was originally allocated in a single allocation.


 Setting Property Data

When you want to set property values, call IMAPIProp::SetProps or HrSetOneProp. The parameters for SetProps are similar to the parameters for GetProps, only the caller supplies a property value array containing the new property values.

As an implementor of SetProps, you may want to allow your callers to change a property type. You can form a new property tag from an existing identifier and the new property type your callers pass in. For example, address book providers might support changing the home telephone number property from PT_UNICODE to PT_MV_UNICODE when the user adds a second home telephone number.

MAPI provides the HrSetOneProp helper function for setting one property at a time. Use HrSetOneProp only if you are sure that your target object is local; this function can be expensive when used with remote objects.


 Defining New Properties

In spite of the wealth of properties supplied by MAPI for provider use, it may be necessary to define new properties. Service providers can define new properties for their own internal use or for public use by clients and other providers. If you are contemplating defining a new public property for an existing MAPI object or message class, think carefully. One of the primary benefits of using MAPI is that it defines standard identifiers and formats for a large number of message service elements, enabling users to seamlessly mix and match service providers. Service providers that use non-standard properties do not work as well with other service providers. This argument does not apply, of course, to newly created message classes because each message class constitutes a separate name space for message content properties or to properties meant to be used internally.

Remember that when you are defining new properties, you must work with the property types that are already defined. New property types cannot be added and existing types cannot be modified or deleted. Simple, small properties, such as single-character or 16-bit integer properties, can be stored in any appropriate type. For example, integers may be stored as ULONG and strings may be stored as PT_STRING8.

For your new property's type, use PT_BINARY to indicate a counted byte array. This property type is handy when you want to extend the types of data that can be stored in an object. Bytes are transmitted in sequence and no assumptions are made about the meaning of the data. When your application reads data out of such a property, the data is unchanged from how it was stored.

Property identifiers must fall in predefined ranges. Assigning an identifier to your property in the appropriate range helps prevent collisions between properties defined by different vendors or users. If a new property is for a new message class, assign an identifier in the 6800-7BFF range if the property is to be transmitted or in the 7C00-7FFF range if the property is not to be transmitted. Use the named property facility to define new transmittable properties for an existing message class. The identifier range of 8000 and greater is reserved for named properties. Named properties are described in more detail in the next section. If the new provider will be a non-transmittable property to be used internally only, assign an identifier in the 7C00-7FFF range.


 Using Named Properties

MAPI provides a facility for assigning names to properties and mapping these names to unique identifiers. As mentioned in the previous section, the named property facility is one way for service providers to define new properties and extend the MAPI property set. After the names of these new properties are published, the properties can be used by clients and other providers without regard to the values of their identifiers. The names can be common names, such as "message address," or unusual names, specific to your service provider. Because each name has a unique identifier associated with it, there is no need to worry about name duplication.

MAPI allows properties to be grouped into property sets, represented by a globally unique identifier, or GUID. There are two property sets that are defined by MAPI: PS_MAPI and PS_PUBLIC_STREAM. Properties defined by MAPI belong to the PS_MAPI property set; properties that are involved in the promotion of document properties belong to the PS_PUBLIC_STREAM property set. Any property belonging to the PS_PUBLIC_STRINGS property set will override a property with the same name in another property set.

The IMAPIProp interface methods, GetNamesFromIDs and GetIDsFromNames, map between property identifiers for named properties and their names. Names are stored in the MAPINAMEID structure either as character strings or as numeric identifiers. The MAPINAMEID structure is used to associate a property name with a globally unique identifier, or GUID, that identifies a property set. The MAPINAMEID structure is defined as follows:

typedef struct _MAPINAMEID

{

LPGUID    lpguid;

ULONG     ulKind;

union {

LONG   lID;

LPWSTR lpwstrName;

} Kind;

} MAPINAMEID, FAR *LPMAPINAMEID;

When calling GetIDsFromNames to retrieve property identifiers for named properties, it is necessary to convert between wide and narrow character sets. The lppPropTags parameter for GetNamesFromIDs can point to NULL, in which case you get all the names back. You can also pass in NULL for the lpPropSetGuid parameter which enables you to retrieve all of the names for all of the property identifiers. That is, the method returns all known mappings.

Objects that provide name-to-identifier mapping of their properties often support a binary property called PR_MAPPING_SIGNATURE. The value of a PR_MAPPING_SIGNATURE property is a MAPIUID structure. Supporting this property provides a shortcut for working with named properties. If two objects have the same mapping signature, they represent the same property and belong to the same property set. Users can compare two named properties simply by checking the value of the PR_MAPPING_SIGNATURE property. They do not have to translate the names of the properties into identifiers and compare them. This is helpful for clients that implement their own copy operation involving named properties and for service providers that implement IMAPIProp::CopyTo and CopyProps.

When named properties are moved or copied, the name remains constant. Clients can preserve names during a move or copy operation by adjusting property identifiers to match the name-to-identifier mapping of the destination object. An exception to this rule is when the source and destination objects have the same mapping signature. Only IDs in the range of 0x8000 to 0xFFFE use name-to-identifier mapping. MAPI expects a store provider which chooses to support named-properties in contents tables of folders, to use the same name-to-identifier mapping for all objects in a folder. A store provider which chooses to support named properties in contents tables of search folders must use the same name-to-identifier mapping for all objects in the store.


 Handling Property Errors

When you are implementing a property object, try to accomplish as much of the requested work as possible, even when errors occur. If a call involves processing multiple properties, such as IMAPIProp::CopyTo, and errors occur on only some of the properties, return the value MAPI_W_ERRORS_RETURNED. This warning indicates that the call was successful, but there were a few problems. Some of the methods pass back an array containing data for each of the properties that were processed; other methods pass back an array of property problem data structures, called SPropProblem structures.

In implementations of methods that pass back an array, set the property type entry for the failing property to PT_ERROR and the property value entry to the appropriate error code. For example, suppose your implementation of IMAPIProp::GetProps is asked to retrieve ten properties and you can only access eight. You should return the warning MAPI_W_ERRORS_RETURNED, set the property type of the two inaccessible properties to PT_ERROR, and set the property value to an error code MAPI_E_NO_ACCESS.

The property problem data structure is defined as follows:

typedef struct _SPropProblem {

ULONG	ulIndex;

ULONG	ulPropTag;

SCODE	scode;

} SPropProblem, FAR *LPSPropProblem;

The property problem array contains multiple property problem data structures plus a count of the number of structures. For more information about the IMAPIProp interface and the SPropProblem and SPropProblemArray data structures, see the MAPI Programmer's Reference.


 Programming with MAPI

This chapter discusses topics that apply to client and service provider writers using the full set of MAPI interfaces and API functions. The topics are not arranged in any particular order; they are simply tips and information that may be of interest to anyone programming with Extended MAPI.


 Using Entry Identifiers

A service provider uses a piece of binary data known as an entry identifier to refer to one of its objects. In the Address Book, for instance, entry identifiers are used to identify messaging users, distribution lists, and containers. To clients and other service providers, entry identifiers are simply binary data. Only the service provider that has assigned the identifier understands what is inside.

Entry identifiers come in two types: short-term and long-term. Short-term entry identifiers are fast to construct, but their uniqueness is guaranteed only over the life of the current session on the current workstation. Short-term entry identifiers are used for display in tables, where it is necessary to provide data quickly for browsing.

Long term entry identifiers are slower to construct, but they are long lasting. There are two types of long term identifiers: temporaland positional. Entry identifiers that last over time are known as temporal identifiers. Entry identifiers that last across computer workstations are known as positional. The only entry identifiers that are both temporary and positional are the identifiers created for custom recipients.


 Validating Data

As implementors and users of interface methods, you need to validate all types of data from simple integer values to object pointers. Depending on the source of the data and its type, MAPI provides guidelines for validation. Standard guidelines work to ensure consistent and accurate validation, an important feature that helps to promote interoperability between MAPI components. This section describes those guidelines for validating both data passed to your methods and data that is returned from methods that you call.


 Validating Parameters

When a method that you have implemented is called, there are two types of validation you can perform: debug and full. If you perform debug validation, you display the values of the parameters given to you and provide verbose information should there be errors. If you perform full validation, you call either the ValidateParameters or UlValidateParameters API function. The level you choose to perform depends on who you expect to call your interface method. When the expected caller is MAPI or a service provider, you can feel safe with debug validation. When the expected caller is a client, full validation is recommended. The model imposed is that within a session, service providers are dependable components and that the parameters passed by these components can be assumed to be valid. Clients are not always as dependable.

MAPI follows these guidelines as well in its interface implementations, providing debug validation in those interface implementations that are called internally or by service providers and full validation in interface implementations that are called by clients. The validation in API functions and the utility interfaces (ITableData and IPropData) is more lenient; only debug validation is provided.

The two API functions that MAPI provides for full validation implement the same functionality. The function you use in your validation code depends on the return type of the method you are validating. ValidateParameters is used for parameters passed to methods that return HRESULT values; UlValidateParameters is used for parameters passed to methods that return ULONG values. Both functions examine the validity of read and write pointers, structures, and reserved flags. If there is a size limit on parameters, the incoming size is also inspected.

The parameters to these functions differ slightly depending on whether you are making the calls using C or C++. This is because of the existence of the extra first parameter added to all method calls made in C: a pointer to the current object. In C++, this is the implicit this pointer. The first parameter in both languages is a constant that represents the method to be validated; valid values are defined in the MAPIVAL.H header file. The second parameter is the address of the beginning of the parameter list to be validated. If you are making this call in C, this is the address of the object pointer. In C++, this is the first argument.

For example, IMAPIProp::SetProps is a method that returns an HRESULT value and requires three parameters: a count of property value structures, a pointer to a property value array, and the address of a pointer to a property problem array. Because this method returns an HRESULT value, ValidateParameters is the appropriate function to call. If you are validating these parameters in a C implementation of SetProps, your parameter list would contain the extra first parameter and your call to ValidateParameters would be made as follows:

STDMETHODIMP Message_SetProps(LPMESSAGE lpMessage, ULONG cValues,
LPSPropValue lpPropArray, LPSPropProblemArray FAR *lppProblems)

{

/* Validate the Message object */

/* Validate remaining parameters, using standard MAPI validation. */

ValidateParameters (IMAPIProp_SetProps, &lpMessage)

}

In C++, this example would be written as follows. The parameter list has the standard three parameters beginning with cValues which becomes the second parameter passed to ValidateParameters.

STDMETHODIMP CMessage::SetProps(ULONG cValues,

LPSPropValue lpPropArray, LPSPropProblemArray FAR *lppProblems)

{

/* Validate the CMessage object */

/* Validate remaining parameters, using standard MAPI validation. */

ValidateParameters (IMAPIProp_SetProps, cValues)

}

The following table lists the interfaces that can be validated by ValidateParameters and UlValidateParameters. Assume that all of the methods for these interfaces can be validated.

IABContainer	IABLogon
IABProvider	IDistList
IMAPIAdviseSink	IMAPIContainer
IMAPIControl	IMAPIFolder
IMAPIProps	IMAPIStatus
IMAPITable	IMessage
IMsgStore	IMSLogon
IMSProvider	IStream
IXPLogonr	IXPProvider
IUnknown


 Validating Object Pointers

The need to validate object pointers arises when you make calls to retrieve MAPI objects or when you make private method calls within your client or service provider. It is always a good idea to validate these pointers. However, unlike parameter validation, MAPI does not provide a single API function to use. Instead there is a recommended series of steps that you can choose from to ensure that the object pointers you are given are accurate. Not all steps are appropriate for all situations; the Vtable verification step, for example, is unnecessary in C++. These steps are as follows:

1.	Check that the object pointer points to the correct amount of writeable memory.

2.	Check that the Vtable of the object contains the expected number of readable entries.

3.	Check that one or more methods in the Vtable have the expected address.

4.	Check that the object's reference count is non-zero.

MAPI provides two API functions for validating pointer memory: IsBadWritePtr and IsBadReadPtr. The following C code sample illustrates how to validate an object pointer using all of the steps outlined above and these two API functions.

if (IsBadWritePtr(lpMyObject, sizeof(MYOBJECT)))

return failure

if (IsBadReadPtr(lpMyObject->lpVtbl, size(MYOBJECT_Vtbl)))

return failure

if (lpMyObject->lpVtbl->SetProps != MYOBJECT_SetProps)

return failure

if (lpMyObject-> cRef == 0)

return failure


 Validating Data Structures

Standard MAPI data structures are often passed between methods. MAPI provides several API functions to check the validity of these structures. The following table describes the common functions used by clients and service providers to validate MAPI data structures:

Validation Function	Purpose
FBadColumnSet	Validates an array of property tags.
FBadEntryList	Validates a list of entry identifiers.
FBadProp	Validates a single property value.
FBadPropTag	Validates a single property tag.
FBadRestriction	Validates a restriction.
FBadRglpNameID	Validates an array of name identifiers.
FBadRglpszW	Validates an array of Unicode strings.
FBadRow	Validates a single row in a table.
FBadRowSet	Validates a set of rows in a table.
FBadSortOrderSet	Validates a sort order for a table.


Multi-Threading in MAPI
 Threading in MAPI

MAPI is designed to be thread-safe. To ensure safety with objects that you as a service provider get back, you must follow these rules:

Objects that will be used on a different thread from the one on which they were created must use CoMarshallInterace to move between threads.

When using asynchronous notification, wrap your advise sink objects using the API function HrWrapAdviseSink. Wrapping your advise sinks in this way guarantees that your advise method will be called on the same thread that was used to call MAPIInitialize. This is an optional procedure, but recommended procedure. Avoiding it will cause you to never know on which thread you will be called.


 About Event Notification

Event notification is the communication of information between two MAPI objects. One object registers an interest in learning of a change or error, called an event, that may take place in another object. After the event occurs, the first object is informed, or notified. The object receiving the notification is called the advise sink; the object responsible for the notification is called the advise source. MAPI advise sink objects implement the IMAPIAdviseSink interface, which contains a single method, OnNotify. The advise source notifies the advise sink by calling OnNotify and passing a notification data structure that contains information about the event. OnNotify can perform tasks in response to the notification, such as updating data in memory or refreshing a screen display.

Typically client applications implement advise sink objects and service providers implement the advise source. Unlike the advise sink, which is a particular type of MAPI object, the advise source may be one of the many different types of MAPI objects that supports event notification. To name a few, advise source objects include sessions, tables, message stores, address book objects, and folders. All advise source objects contain two methods to handle notification registration: Advise and Unadvise. Clients call Advise when they want to register for a notification and Unadvise when they want to cancel the registration. Advise returns a non-zero connection number to represent the registration.

There are nine types of notifications that can be sent to an advise sink. Some of these are specific to a particular advise source; others are sent by most or all advise source objects. Clients can register for one or more of these types using the constant that MAPI has defined for the specific type. The only exception is the status object notification. This is an internal MAPI notification; clients cannot register for it and service providers cannot generate it. The following table describes the set of events and lists the advise source objects that can support them. The event constant is included with the event type.

Event Type	Description	Supporting Objects
Critical error (fnevCriticalError)	A global error or event has occurred, such as a session shut down in progress.	Logon, session, all types of message store and address book objects, table, status
Object modified (fnevObjectModified)	A MAPI object has changed.	Folders, messages, all types of address book objects
Object created (fnevObjectCreated)	A MAPI object has been created.	Folders, messages, all types of address book objects
Object moved (fnevObjectMoved)	A MAPI object has been moved.	Folders, messages, all types of address book objects
Object deleted (fnevObjectDeleted)	A MAPI object has been deleted.	Folders, messages, all types of address book objects
Object copied (fnevObjectCopied)	A MAPI object has been copied.	Folders, messages, all types of address book objects
Extended event (fnevExtended)	An internal event defined by a particular service provider has occurred.	Any advise source object
Search complete (fnevSearchComplete)	A search operation has finished and the results of the search are available.	Tables, folders
Status object modified (fnevStatusObjectModified)	Information in a MAPI status object has changed.	Status
New mail (fnevNewMail)	A message has been delivered and is waiting to be processed.	Message store, folders
Supporting event notification can be complicated, depending on the number of events supported and the number of registered advise sinks. Service providers can handle it themselves or accept help from MAPI. There are three methods in the IMAPISupport interface that keep track of all the registrations for a particular advise source and send the appropriate notifications when necessary. To use IMAPISupport to manage registration, service providers forward their Advise and Unadvise calls to the IMAPISupport::Subscribe and IMAPISupport::Unsubscribe methods. When an event occurs, service providers call IMAPISupport::Notify to ask MAPI to notify all registered advise sinks.

Figure 1 illustrates the flow of calls between clients, service providers, and MAPI that constitute the event notification process. Dotted lines are used to indicate optional lines of communication.

Figure 1.  Event notification.

When registering for notifications, clients have a few options. For objects that are related hierarchically, such as message stores and folders, they can register with the child object or the parent object. A registration on a child object causes a notification to be sent only when the event occurs within that object while a registration on a parent object causes a notification when the event occurs on the parent object and/or any of its child objects. Address books and message stores accept registration for events affecting their child objects. For example, clients can register with a message store object to receive notifications about changes affecting any or all of its folders.

Clients can register directly with a service provider or indirectly through MAPI, using the session object. Direct registration is when the client calls the Advise method in the object that will experience the event and send the notification. Indirect registration is when the client calls the Advise method in the session object, passing in the entry identifier of the real advise source object. IMAPISession::Advise can accept registration for events that affect the session object itself or another object. When an entry identifier is specified, IMAPISession::Advise forwards the call to the Advise method in the appropriate advise source object. The resulting notifications are generated by the service provider rather than by the MAPI session object.


 Managing Memory

Knowing how and when to allocate and free memory is an important part of programming with Extended MAPI. MAPI provides three API functions that manage memory in a consistent way. When both clients and service providers use these functions, the issue of who "owns" (that is, knows how to release) a particular block of memory disappears. A client making a service provider method call need not pass a buffer large enough to hold a return value of any size. The service provider can simply allocate the appropriate amount of memory and the client can later release at will, independent of the service provider.

MAPIAllocateBuffer, MAPIAllocateMore, and MAPIFreeBuffer are the three functions that enable client applications and service providers to exchange blocks of memory. These functions manage memory using double linked lists. MAPIAllocateBuffer is called to initially allocate memory for a buffer; MAPIAllocateMore can allocate a subsequent block of memory that is linked to the initial block at a later time. Assume when calling these allocators that the returned buffer is appropriately aligned for the architecture.

The chaining of allocations supported by MAPIAllocateMore simplifies the handling of complex memory objects for clients. An array of property values, for example, can consist of numerous blocks of memory linked together by pointers that can be released with a single call to the third function, MAPIFreeBuffer. Whenever a block of memory is returned from a call, MAPIFreeBuffer must be used to release it. MAPIFreeBuffer releases the initial block and any subsequent blocks.

Whenever possible, allocate all of the necessary memory with a single call to MAPIAllocateBuffer. MAPIAllocateMore exists merely as a convenience. However, if you do use MAPIAllocateMore to allocate additional memory for a buffer, always free it by passing the buffer allocated with MAPIAllocateBuffer to MAPIFreeBuffer. Ignor any errors returned from MAPIFreeBuffer. The function almost always succeeds, and in the rare case that an error is returned, there is little the caller can do about it.

Note:  Clients call the MAPIAllocateBuffer and MAPIAllocateMore functions directly, while providers must make an indirect call, retrieving the function pointers through a call to IMAPISupport::GetMemAllocRoutines.

MAPI also supports the use of the OLE interface, IMalloc, for memory management. The MAPIGetDefaultMalloc function returns an OLE allocator object which allows you to call IMalloc interface methods. The main advantage to using the IMalloc methods for managing memory is that you can reallocate an existing buffer. The MAPI memory functions do not support reallocation.

When allocating a a property value array, allocate the structures using MAPIAllocateBuffer for the main part and either have enough extra in the original allocation for all the members, or use MAPIAllocateMore to allocate them. For the SRowList and ADRLIST structures, the requirement is that the property value array be allocated separately.

The recommendation of allocating all memory for a buffer whenever possible with a single MAPIAllocateBuffer call does not apply when using the address list, or ADRLIST, and row set, or SRowSet, data structures: These two structures are exceptions to the standard rules for allocating and releasing memory. They contain multiple levels of structures and are designed to enable individual members to be added or removed. Therefore, each entry is a separate allocation. Where most structures are freed with one call to MAPIFreeBuffer, each individual entry in an ADRLIST or SRowSet structure must be freed with its own call to MAPIFreeBuffer.

Figure 2 illustrates the layout of an ADRLIST data structure, indicating the separate memory allocations required. The dotted lines show memory that can be allocated and released with one call.

Figure 2.  Memory management for ADRLIST structures.

MAPI provides two API functions, FreePadrlist and FreePRows, that can save you some work freeing these data structures. FreePadrlist frees the memory for the ADRLIST structure plus all associated memory for the structure members; FreePRows does the same for the SRowSet structure.

In addition to specifying how to allocate and free memory, MAPI defines a model for knowing when memory passed between public interface method and API function calls should be freed. The model applies only to memory allocated for parameters that are not pointers to interfaces, such as strings and pointers to structures. When allocating and freeing non-MAPI related memory internally within your client application or service provider, you can use whatever mechanism makes sense.

The model defines parameters as one of three types. They may be input parameters, set by the caller with information to be used by the called function or method, output parameters, set by the called function or method and returned to the caller, or input-output parameters, a combination of the two types. The follow table explains the rules for allocating and releasing memory for these types of parameters:

Type	Memory Allocation	Memory Release
input	Caller is responsible and may use any mechanism.	Caller is responsible and may use any mechanism.
output	Called function is responsible and must use MAPIAllocateBuffer.	Called function is responsible and must use MAPIFreeBuffer.
input-output	Caller is responsible for the initial allocation and callee may reallocate if necessary using MAPIAllocateMore.	Called function is responsible for initial freeing if reallocation is necessary. Caller must free the final return value.
During failure conditions, implementors of interface methods need to pay attention to output and input-output parameters since the caller generally has no way to clean them up. If you return an error, then each output or input-output parameter must either be left at the value initialized by the caller or set to a value that can be cleaned up without any action on the part of the caller. For example, an output pointer-parameter of void ** ppv must be left as it was on input or can be set to NULL (*ppv = NULL).


Handling Errors

The MAPICODE.H header file contains many of the values that you might want to return from an interface method or might see when you call an interface method. Success is defined as both S_OK and SUCCESS_SUCCESS, where S_OK is typically used with OLE and Extended MAPI and SUCCESS_SUCCESS is used with Simple MAPI. All of the warning and error values consist of three parts separated by underscores. The first part is the prefix MAPI, the second part is W for warning and E for error, and the third part is a string that describes the actual condition. For example, MAPI_E_TOO_COMPLEX indicates an error that occurred because the implementation could not handle the request whereas MAPI_W_PARTIAL_COMPLETION is a warning generated when a method has succeeded in doing some of the work requested, but not all.

Success, warning, and error values are returned using a 32-bit number known as a result handle, or HRESULT. HRESULTs are really not handles to anything; they are merely a 32-bit value with several fields encoded in the value. A zero result indicates success and a non-zero result indicates failure.

HRESULTs work differently depending on the platform you are using. On 16-bit platforms, an HRESULT is generated from a 32-bit value known as a status code, or SCODE. On 32-bit platforms, an HRESULT is the same as an SCODE; they are synonymous. In fact, the SCODE is no longer used. MAPI on 32-bit platforms works solely with HRESULTs.

SCODES on 16-bit platforms are divided into four fields: a severity code, a context field, a facility field, and an error code. The format of an SCODE on a 16-bit platform is shown below; the numbers indicate bit positions:

HRESULTs on 32-bit platforms have the following format:

The severity code in the 16-bit SCODE and the high order bit in the HRESULT indicates whether the return value represents success or failure. If set to zero, the value indicates success. If set to 1, it indicates failure.

In the 16-bit version of the SCODE, the context field is reserved as are the R, C, N, and r bits in the HRESULT.

The facility field in both versions indicates the area of responsibility for the error. There are currently five facilities: FACILITY_NULL, FACILITY_ITF, FACILITY_DISPATCH, FACILITY_RPC, and FACILITY_STORAGE. If new facilities are necessary, Microsoft allocates them because they need to be unique. Most SCODEs and HRESULTs set the facility field to FACILITY_ITF, indicating an interface method error. The following table describes the various facility fields:

Facility	Description
FACILITY_NULL	For broadly applicable common status codes such as. S_OK; value is zero
FACILITY_ITF	For most status codes returned from interface methods; value is defined by the interface. That is, two SCODEs or HRESULTs with exactly the same 32-bit value returned from two different interfaces might have different meanings.
FACILITY_DISPATCH	For late binding IDispatch interface errors.
FACILITY_RPC	For status codes returned from remote procedure calls
FACILITY_STORAGE	For status codes returned from IStorage or IStream method calls relating to structured storage. Status codes whose code (lower 16 bits) value is in the range of DOS error codes (that is, less than 256) have the same meaning as the corresponding DOS error.
The code field is a unique number that is assigned to represent the error or warning.


 Using Macros for Error Handling

MAPI defines several macros for making it easier to work with SCODEs on 16-bit platforms and HRESULTs on both platforms. Some of the macros and functions below provide conversion between the two datatypes and are quite useful in code that runs only on 16-bit platforms, codes that runs on both 16-bit and 32-bit platforms, and 16-bit code that is being ported to a 32-bit platform. These same macros are meaningless in 32-bit environments and are available to provide compatibility and make porting easier.

The set of macros are listed below; refer to The MAPI Programmer's Reference for complete descriptions of each.

Macro	Description
GetScode	Returns an SCODE given an HRESULT
ResultFromScode	Returns an HRESULT given an SCODE
MakeResult	Returns an HRESULT given an SCODE that represents an error
MAKE_SCODE	Returns an SCODE given an HRESULT
HrFailed	Tests an HRESULT for a warning or error condition
HRESULT_CODE	Extracts the error code part of the HRESULT
HRESULT_FACILITY	Extracts the facility from the HRESULT
HRESULT_SEVERITY	Extracts the severity bit from the SEVERITY
SCODE_CODE	Extracts the error code part of the SCODE
SCODE_FACILITY	Extracts the facility from the SCODE
SCODE_SEVERITY	Extracts the severity field from the SCODE
SUCCEEDED	Tests the severity of the SCODE or HRESULT - returns TRUE if the severity is zero and FALSE if it is one
FAILED	Tests the severity of the SCODE or HRESULT - returns TRUE if the severity is one and FALSE if it is zero
Note  Calling MakeResult for S_OK  verification carries a performance penalty. You should not routinely use MakeResult for successful results. GetScode and MakeResult are externally defined and not MAPI support functions. You will not find them in the table of support functions passed to your provider, but in a separate DLL that you can link with your provider.


 Strategies for Error Handling

Because interface methods are virtual, it is not possible to know, as a caller, the full set of values that may be returned from any one call. One implementation of a method may return five values; another may return eight. The MAPI Programmer's Reference lists a few values that may be returned for each method; these are the values that you must check for and handle in your code because they have special meanings. Other values may be returned, but since they are not meaningful, you do not need to write special code to handle those. A simple check for zero or not zero is adequate.

A few of the interface methods return warnings. If a method that you call can return a warning, use the HrFailed macro to test the return value rather than a check for zero or not zero. Warnings, like success codes, equate to zero. If you do not use the macro, you will miss these codes.

Although most interface methods and functions return HRESULTs, some functions, primarily those defined for Simple MAPI, return unsigned long values. Also, some methods used in the MAPI environment come from OLE and return OLE error values rather than MAPI error values. Keep in mind the following guidelines when making calls:

•	Never rely on or use the return values from IUnknown::AddRef or IUnknown::Release. These return values are for diagnostic purposes only.

•	IUnknown::QueryInterface always returns generic OLE errors where the facility is FACILITY_NULL or FACILITY_RPC, rather than MAPI errors.

•	All other interface methods return MAPI interface errors with a facility of FACILITY_ITF, or FACILITY_RPC or FACILITY_NULL errors.

•	Simple MAPI calls return Simple MAPI errors rather than SCODEs or HRESULTs.

•	No Extended MAPI call ever returns a Simple MAPI error.

If you work with both clients that use both Simple and Extended MAPI API calls, you should be aware that although the underlying values for some of the errors are different, the constants defined for them are quite similar. For example, when you make a call to an unsupported feature in Simple MAPI, you receive the error MAPI_E_NOT_SUPPORTED. When you make the same type of call in Extended MAPI, you receive one of four possible errors: MAPI_E_NO_SUPPORT, MAPI_E_INTERFACE_NOT_SUPPORTED, MAPI_E_INVALID_PARAMETER, or MAPI_E_VERSION. The table below points out these similarities and differences.

Simple MAPI Return Value	Extended MAPI Return Value
MAPI_E_NOT_SUPPORTED	MAPI_E_NO_SUPPORT MAPI_E_INTERFACE_NOT_SUPPORTED MAPI_E_INVALID_PARAMETER MAPI_E_VERSION
MAPI_E_DISK_FULL	MAPI_E_NOT_ENOUGH_DISK
MAPI_E_NETWORK_FAILURE	MAPI_E_NETWORK_ERROR
MAPI_E_USER_ABORT	MAPI_E_USER_CANCEL
MAPI_E_ACCESS_DENIED	MAPI_E_NO_ACCESS
MAPI_E_AMBIGUOUS_RECIPIENT	MAPI_E_AMBIGUOUS_RECIP


 Using Extended Errors

As an implementor of interface methods, you can choose to simply return success (S_OK) and failure (MAPI_E_CALL_FAILED) or differentiate between error conditions, returning as many error values as make sense for the situation. If your method requires a return value that is not defined by MAPI in the MAPICODE.H header file, you can use a special value - MAPI_E_EXTENDED_ERROR. MAPI_E_EXTENDED_ERROR indicates to the caller that more information about the error is available; the caller retrieves that information by calling the GetLastError method on the same object that returned MAPI_E_EXTENDED_ERROR.

Many MAPI objects implement interfaces that include the GetLastError method. GetLastError returns a single MAPIERROR structure that, in theory, includes a concatenation of all of the errors generated by the previous method call.  As a caller, it is wise not to depend on having this extra error information available because object implementors are not required to provide it. However, it is strongly recommended that whenever implementors return MAPI_E_EXTENDED_ERROR, they make it possible for callers to retrieve a MAPIERROR structure with useful information about the error.

Because GetLastError is also an API function that is part of the Win32 SDK, it can be easy to forget that in the MAPI world, GetLastError is an interface method and can only be called on MAPI objects. Another easy mistake to make is calling GetLastError on the wrong object. GetLastError must be called on the object that generated the error. For example, if you make a session call, and MAPI forwarded the call to a service provider to do the work, you may be tempted to call GetLastError on the service provider object. This is wrong; you must call IMAPISession::GetLastError, the session object's method.


 Deferring Errors

Some interface methods accept the MAPI_DEFERRED_ERRORS flag as an input parameter. When this flag is set, the method does not have to return immediately with a value; it can let the caller know the result of the call at some later time.

Deferring errors makes implementation easier and processing faster. Rather than handling many requests and returning a value for each, deferring errors allows the calls to be bundled. Processing many requests at once cuts down on network traffic, therely improving performance. Deferring errors is especially useful in calls to delete or copy properties, which can be quite lengthy operations.

Because some operations can take time, service providers may choose to process certain calls in a deferred manner regardless of whether the MAPI_DEFERRED_ERRORS flag was set on the call. Deferring errors in these situations is preferable to rejecting the call and returning MAPI_E_TOO_COMPLEX because of time or resource constraints.

When you have set the MAPI_DEFERRED_ERRORS flag, you must be prepared to receive the return information at any time, possibly when it is too late to do anything about it or after you no longer have any data about the original request.


 Session Identity

Every Extended MAPI session has the concept of a primary identity which describes who it is. The definition of primary identity is different depending on the message service. For example, many services designate an address book recipient as the identity for the session.

There are a set of properties associated with supplying an identity:PR_IDENTITY_DISPLAY_NAME, PR_IDENTITY_SEARCH_KEY, and PR_IDENTITY_ENTRYID. These properties are essential for configuration when the provider has an identity.

Not every service provider can supply an identity; service providers that do not have an identity set their PR_RESOURCE_FLAGS property in the MAPISVC.INF file to STATUS_NO_PRIMARY_IDENTITY. Service providers that can supply the primary identity set their PR_RESOURCE_FLAGS property to STATUS_PRIMARY_IDENTITY. When a profile is built and MAPI determines identity for the session, the first service provider that has claimed primary identity is granted it. The STATUS_PRIMARY_IDENTITY bit for the PR_RESOURCE_FLAGS property for the other service providers is turned off. If the service provider with primary identity is deleted from the profile, the next provider in line assumes the role. cannot be used to supply an identity.


 Administering Profiles and Message Services

Profile administration is an important part of MAPI, for without valid profiles, logon cannot occur and a session cannot be established. Profile administration ensures the validity of each profile on the workstation and provides a means for updating obsolete information. Client applications can either avoid supporting administration by relying on the applications that MAPI supplies, the Control Panel applet and the Profile Wizard, or provide some level of support. To enable client applications to implement administrative support for their users, MAPI has implemented four interfaces:

•	IProfAdmin

•	IProfSect

•	IMsgServiceAdmin

•	IProviderAdmin

IProfAdmin and IProfSect work with profiles and are used by both clients and service providers. IProfAdmin is used to create, copy, or delete profiles while IProfSect is used to access and modify profile properties.

IMsgServiceAdmin and IProviderAdmin are for clients only; they deal with message services and the service providers within those services. IMsgServiceAdmin enables clients to modify their profile's message service sections; IProviderAdmin enables clients to add or delete service provider sections.

Clients and service providers access pointers to these interfaces in a variety of ways. The OpenProfileSection method implemented in the IMAPISupport, IMAPISession, and IProviderAdmin interfaces returns a pointer to an IProfSect implementation. IMAPISession also includes a method, AdminServices, for providing clients with access to an IMsgServiceAdmin pointer.

The API function MAPIAdminProfiles, callable by both clients and service providers, returns an IProfAdmin pointer. To access the IProviderAdmin interface, clients must call IMsgServiceAdmin::AdminProviders method pointer. Message services receive an IProviderAdmin pointer when their entry point function is called; it is one of the input parameters for the prototype.

Figure 3 illustrates all of the different calls that can be made to provide access to a profile containing message service and service provider information.

Figure 3.  Interface Methods and Functions for Profile Administration.

These next sections describe how to use the administration interfaces to manage profiles and message services.


 Using IProfAdmin

The methods of IProfAdmin allow users to create, copy, and delete profiles, and to change passwords. Call IProfAdmin::CreateProfile to create a new profile. CreateProfile accepts a set of option flags that provide MAPI with information. For example, set the MAPI_DEFAULT_SERVICE flag if the new profile should contain the message services listed in the [Default Services] section of the MAPISVC.INF file. Set the MAPI_DIALOG flag to allow the display of a user interface so that the user can enter configuration information if necessary. CreateProfile calls the entry point function for each message service to be added to the profile, asking that each service's configuration property sheets be displayed. If a user interface is disallowed, the message services remain unconfigured.

The IProfAdmin::ChangeProfilePassword method allows you to change a profile's password. Keep in mind that this method is unsupported on 32-bit platforms; you will receive the error MAPI_E_NO_SUPPORT.

When you call IProfAdmin::DeleteProfile to delete a profile, MAPI calls the entry point function of every message service in the profile with the ulContext parameter set to MSGSERVICE_DELETE as the context. The calls to the entry point functions occur before the services are physically removed from the profile. If the profile to be deleted is currently being used, DeleteProfile will wait until a later safer time to delete it.

The IProfAdmin::SetDefaultProfile method marks a profile as the default. The default profile is the one that is used at logon time when a client calls the API function MAPILogonEx and sets the MAPI_USE_DEFAULT flag. To set a new default profile, SetDefaultProfile sets the PR_DEFAULT_PROFILE property for the new default profile and removes the setting for the previous default profile.

Note  A word of caution about modifying profiles. There are no safeguards to protect you from adversely modifying a profile that is in use. MAPI will prevent you from deleting the profile, but will not prevent you from deleting every message service in it, causing every message service provider to stop and unpredictable results to occur.


 Using IMsgServiceAdmin

The methods of IMsgServiceAdmin allow clients to access other objects, such as the message services table and a provider administration object. Clients retrieve IMsgServiceAdmin pointers either through the session object with a call to IMAPISession::AdminServices or by calling IProfAdmin::AdminServices. Most messaging clients use the session object; special configuration clients, such as the Control Panel applet, use the profile administration object.

Clients can use the GetMsgServiceTable method to access a MAPI table object containing properties of all of the message services in the current profile. One of the properties included in the table is the PR_SERVICE_UID property, the unique identifier for the service. Another property, PR_SERVICE_NAME, comes from the [Services] section in MAPISVC.INF. The value for this property should never be changed or localized. PR_SERVICE_NAME can be used to programmatically identify the type of message service. The PR_RESOURCE_FLAGS property describes the message service's capabilities. Once a client calls GetMsgServiceTable to access a view of the message services table, any changes that occur to message services within the profile will not be reflected in the view. Refer to the Chapter 9, "Using Tables," for more information about the message service table.

Another table object, the providers table, is accessible with the GetProviderTable method. The providers table lists all of the service providers for a message service and includes the following properties in its column display:

•	PR_PROVIDER_DISPLAY

•	PR_PROVIDER_ORDINAL

•	PR_RESOURCE_TYPE

•	PR_RESOURCE_FLAGS

Clients can use the information in the providers table to change the transport order, the order in which transports are called to deliver messages. When you change the transport order with a call to MsgServiceTransportOrder, you must pass in a list of all of the transports in the profile. It is not possible to switch the position of a few transports by passing in only those few. The MsgServiceTransportOrder call overrides the transport provider preferences as indicated by the STATUS_XP_PREFER_LAST bit in the provider's PR_RESOURCE_FLAGS property.

Whether or not clients are allowed to change anything about the service providers that belong to the service is up to the service itself. Typically, clients are not allowed to add service providers to or delete service providers from a service. Also, clients are not allowed to open and modify profile sections that belong to service providers and message services. This is because service providers are encouraged to store private information such as credentials in their profile sections.

When IMsgServiceAdmin::CreateMsgService is called to add a message service to the profile, MAPI first copies all of the relevant information in the MAPISVC.INF file and then calls the message service's entry point function with the ulContext parameter set to MSGSERVICE_CREATE. CreateMsgService creates a provider section in the profile for every provider section in MAPISVC.INF. Once the message service has been added, clients must call GetMsgServiceTable to access its unique identifier.

Call IMsgServiceAdmin::ConfigureMsgService to configure a newly added message service. Like many of the method calls in MAPI, ConfigureMsgService accepts a flag that specifies whether a user interface can be displayed. Clients can ask that property sheets never be displayed, that property sheets appear only if the service requires additional configuration, or have them appear regardless of whether additional configuration is required. ConfigureMsgService configures all of the service providers in a message service. To configure a single service provider, call IMAPIStatus::SettingsDialog instead.

IMsgServiceAdmin::CopyMsgService lets clients copy a message service to the same profile or a different profile. When a message service is copied, the new instance of the service is configured in exactly the same way as the original. Sometimes CopyMsgService returns the error MAPI_E_ACCESS_DENIED. The most common cause of this error return is a message service that does not allow itself to be duplicated.

Clients that want to delete a message service from a profile must first locate its unique identifier in the message services table and then call IMsgServiceAdmin::DeleteMsgService. Before removing information from the profile, DeleteMsgService calls the message service's entry point function to give the service an opportunity to clean up.

Message services can designate a service provider to be the supplier of the primary identity for a profile by calling IMAPISupport::SetPrimaryIdentity. Not every service provider can become the supplier of a profile's identity because some providers have no notion of identity. Such service providers set the STATUS_NO_PRIMARY_IDENTITY bit in the PR_RESOURCE_FLAGS property.

Usually within a message service, every provider that can supply an identity has the same notion of it. Typically, an address book recipient entry identifier serves as the primary identity. Service providers that can supply an identity set the STATUS_PRIMARY_IDENTITY bit in the PR_RESOURCE_FLAGS property along with setting the PR_IDENTITY_DISPLAY_NAME, PR_IDENTITY_SEARCH_KEY, PR_IDENTITY_ENTRYID properties. Providers that supply identity set these properties and include them when they are building a row entry for the status table.

About the MAPI Samples

About the Sample Client

The MAPI SDK includes a sample MAPI client application written in C++ called CLIENT. The CLIENT was written to illustrate most of the typical tasks MAPI clients perform.

This sample client allows users to submit and retrieve messages from any underlying messaging system and includes the following features:

•	Manipulation of multiple message stores

•	Reply, reply to all, and forwarding features

•	Full configuration support

•	OLE style drag and drop

The user interface is implemented with the common controls provided with Windows 95. The hierarchy table, for example, is implemented with a tree view control. This implementation enables each item in the table to be associated with a label and a bitmap.

To help with debugging, the CLIENT has a built-in tracing mechanism called TraceResult. You'll notice its use throughout the code fragments.

The CLIENT defines several object classes to wrap calls to the MAPI interfaces. There are two objects that work with message stores: CStoreClient and CStoreView. For each message store provider in the user's profile, the CLIENT instantiates one CStoreClient and one CStoreView. The CStoreClient object handles the management of the message store by wrapping calls made to the various interfaces: IMAPISession, IMsgStore, IMessage, and IFolder. The CStoreView object handles the user interface for the message store.

The code excerpts from the CLIENT are not exact copies due to space limitations. Logic that did not directly relate to the topic being discussed was not included in the documentation. Also not included were lengthy comments, debug statements, error handling blocks, and code that related more to user interface programming than MAPI programming. The goal of the MAPI Programmer's Guide is to focus on individual MAPI-related topics and to provide a task-oriented approach to MAPI programming. Using the sample code verbatim would lessen readability and introduce a level of unneeded complexity. The entire sample client, including all source and header files, is included with the MAPI SDK.

About the Sample Message Store Providers

About the Sample Address Book Providers

About the Sample Transport Providers


 Using Tables

This chapter describes how tables are implemented and used. Beginning with a definition and an overview of common features, the chapter continues with a description of the interfaces that are used to access a table's underlying data and the data structures that are passed to the interface methods. The next part covers common table operations, such as sorting, defining a column set, and building restrictions. The last section provides information about each type of table, including the properties that appear in the columns.

As with the other chapters that discuss MAPI objects, this chapter presents tables from both the user's and the implementor's viewpoint. Tables are implemented by MAPI and by service providers to be used by clients and service providers. Therefore, service providers have a dual role as user and implementor. Which role a service provider assumes at any one time depends on the situation and the type of table. The next section delves deeper into describing the different types of MAPI tables and their implementation.


 About Tables

MAPI tables are used for looking at the properties of other MAPI objects in a structured way A table can be thought of as a two-dimensional array, the two dimensions being rows and columns. Each row represents a MAPI object; each column represents a property of the object. A MAPI table resembles the traditional database table in that it has many of the same characteristics - the data is presented in row and column format, a cursor keeps track of the current position, and the client or provider using the table has the ability to establish search criteria and a sort order to create a customized view.

A MAPI table is different than most other MAPI objects in that it does not support a set of its own properties. Its purpose is to display the properties of other MAPI objects. The interface that it implements, IMAPITable, inherits directly from the IUnknown interface and not from the IMAPIProp interface. IMAPITable provides read-only access to the property data, enabling multiple simultaneous views of the data. Users cannot change the actual property data, they can only change the way it is presented.

Figure 1 following shows one of the frequent uses of a table in MAPI - to display the the contents of a folder. Two messages are shown; each message has several properties. A message is divided into two parts to separate the properties that describe the message and the actual message data. The descriptive properties include the name of the recipient and the sender, represented by the display name property, or PR_DISPLAY_NAME, and the sender name property, or PR_SENDER_NAME. The date and subject of the message are the other descriptive properties. The date value comes from the PR_ORIGINAL_DELIVERY_TIME property and the subject from the PR_SUBJECT property. Because the message uses a plain text format, it is stored in the PR_BODY property. Message text using the rich text format is stored in another property. The PR_ENTRYID property stores the internal identifier of the message. The column set of the contents table, or set of properties that the user wants to see, has been limited to four of these properties, sorted in order by entry identifier.

Figure 1  Contents table for a folder.

There are many different types of tables. Tables are differentiated by the information that they present.  Some tables present information about a single object; other tables present information collected from multiple objects. An example of the first type of table is the recipients table. Message store providers supply clients with a recipients table for every message that contains information about all of the recipients for that particular message. An example of the second type is the providers table. The providers table is implemented by MAPI to supply service providers with information about all of the service providers in the current session. Whereas a typical session involves many messages and many recipients tables, there is only one providers table.

You can determine the implementor of most tables by the table type. As mentioned above, recipients tables are always implemented by the implementor of messages, a message store provider. Attachment tables, which also contain message information are also implemented by message store providers. MAPI implements several different tables, some for use by clients, some by service providers, and some by both. The message stores table is used by clients to retrieve information about the various message store providers installed in the current profile. Display tables are used by service providers to help with user interface implementation. The message services and profiles tables can be used by either clients or service providers to support message service configuration.

As stated above, the type of table usually determines its implementor. However, MAPI defines two types of tables that are implemented by both address book and message store providers. Contents tables hold the contents of address book containers when implemented by address book providers and folders when implemented by message store providers. Hierarchy tables show the hierarchy of the integrated address book when implemented by address book providers and the message store hierarchy when implemented by message store providers.

Some tables are static, meaning that once they are instantiated they will not change. Although the underlying property data might change, the table's view of it does not. Other tables are more dynamic; the view is updated when the underlying data changes. The message stores table is an example of a dynamic table. It always reflects what is in the profile. If a client's user edits the profile, changing the default message store, for example, the values of the PR_DEFAULT_STORE properties for the affected message stores are updated in the table view.

MAPI defines several data structures that are useful for working with tables. There is one data structure to represent a single row and another to represent a set of rows. This data structure is used frequently in table operations. Other data structures are used in specific operations, such as sorting and specifying restrictions. The next section describes these data structures in detail.


 Table Data Structures

There are three structures that are used to describe table data: one for the actual data in a row and two for data related to how that data is shown to the user. The row set, or SRowSet, is a hierarchical data structure that contains the data for each row. The sort order set, or SSortOrder, is a hierarchical data structure that describes the order in which the rows of a table are displayed. The SRestriction data structure is used to establish search criteria.


 About Row Sets

Table data is organized using a hierarchy of data structures. At the top of the hierarchy is the row set, or SRowSet data structure. Each SRowSet is made up of an array of row, or SRow structures and a count of the number of row structures in the array. Each SRow contains an array of property values, or SPropValue structures and, again, a count of the number of structures in the array. The SPropValue array contains the property tags and values for the properties in the columns of the table.

The following diagram illustrates the bottom two layers of the hierarchy, starting with the SRow:

Figure 2  An SRow data structure


 About Sort Order Sets

The sort order set data structure, SSetOrderSet, contains information about the ordering of data in a table. It is usedfor both regular sorting and categorized sorting and contains an array of sort order (SSortOrder) data structures. Other members of the structure specify the number of sort order structures included, and the number of categories that are included and should be expanded when the table is displayed. Sort order sets are defined as follows:

typedef struct _SSortOrderSet

{

  ULONG       cSorts;

  ULONG       cCategories;

  ULONG       cExpanded;

  SSortOrder  aSort[];

} SSetOrderSet, FAR * LPSSortOrderSet;

The SSortOrder data structure is made up of a property tag and a constant that indicates whether the table should be in ascending or descending order or, for categorized tables, whether the property should become a separate category. SSortOrder structures are defined as follows:

typedef struct _SSortOrder

{

  ULONG  ulPropTag;

  ULONG  ulOrder;

} SSetOrder, FAR * LPSSortOrder;


 About Restrictions

Building restrictions allows you to specify exactly how much and what type of data you wish to include in a table view. Restrictions are built using the SRestriction data structure which containsa union of more specialized restriction structures and an indicator of the type of structure included in the union.

The SRestriction data structure is defined as follows:

typedef struct _SRestriction

{

  ULONG  rt;

  union  {

      SComparePropsRestriction  resCompareProps;

      SAndRestriction           resAnd;

      SOrRestriction            resOr;

      SNotRestriction           resNot;

      SContentRestriction       resContent;

      SPropertyRestriction      resProperty;

      SBitMaskRestriction       resBitMask;

      SSizeRestriction          resSize;

      SExistRestriction         resExist;

      SSubRestriction           resSub;

      SCommentRestriction       resComment;

}  res;

} SRestriction;

To illustrate how the structures involved in building a restriction fit together, consider the SAndRestriction data structure. The SAndRestriction data structure allows you to compare two or more restriction structures using the logical AND operator. To build a logical AND restriction, you specify RES_AND in the rt, or restriction type, field and include the appropriate number of pointers to the SRestriction data structures to be compared.

Figure 3   An SRestriction data structure of type RES_AND

Some common restrictions include the bit mask restriction, stored in the SBitMaskRestriction structure, for testing if all of the bits in a flag are on or off, and the comment restriction, stored in the SCommentRestriction structure, for associating a name with a set of named properties. Clients might want to use the comment restriction for viewing hidden text in a word processing document. The SSubRestriction structure is used to place a subobject restriction on a table. Subobject restrictions are useful operations that allow you, for example, to search for all messages from a particular recipient or for all attachments in a search-results folder. The property restriction, stored in the SPropertyRestriction structure, allows you to compare the value of a property with another value and exclude those rows that have values which do not match. A property restriction can be used, for example, to search for a particular type of attachment, such as an executable file.


 About IMAPITable

MAPI tables implement the IMAPITable interface. IMAPITable is a read-only interface, meaning that its methods do not allow any modifications to the table data. Because service providers as well as MAPI implement many different types of tables to be used by other providers and clients, IMAPITable is one of the most commonly implemented and used interfaces in MAPI.

As stated earlier, there are many types of tables and each type has its own IMAPITable implementation. The differences in implementation are apparent in the work that each method does and the amount of support each method provides. For example, consider the difference between a hierarchy table, which is a multi-level list of rows, and the providers table, which is a flat list. Multi-level tables can expand and contract their view; single level tables do neither. Therefore, hierarchy tables will fully implement the GetCollapseState and SetCollapseState methods in IMAPITable and the providers table will return MAPI_E_NO_SUPPORT.

For more information on using and implementing IMAPITable, see the MAPI Programmer's Reference The "Working with Tables" section describes how to implement frequent tasks.


 About ITableData

There is another interface, ITableData, that MAPI implements to help service providers access and maintain the underlying data upon which the table view is based. ITableData is a read-write interface, allowing users to add, delete, and change the data displayed in the rows. Like IMAPITable, ITableData does not support any of its own properties and inherits directly from IUnknown. MAPI provides two different interfaces for table access to allow users to simultaneously view and modify table data.

Service providers call the API function CreateTable to instantiate a table data object and retrieve a pointer to an ITableData interface implementation. One of the parameters to CreateTable is an array of property tags specifying the properties that should be included in the table. Each property tag includes a property type and identifier. The property type cannot be PT_UNSPECIFIED, PT_ERROR, or PT_NULL.

The ITableData interface operates with an index column, a property that is used to locate rows for modification. Specifying a multi-valued property for the index column is not possible.

Figure 4 shows the relationship between IMAPITable and ITableData. The service provider object on the left controls the underlying data using ITableData. Each time a client requests a view of the data, the service provider creates a unique MAPI table object based on the request and returns a pointer to the IMAPITable implementation.

Figure 4.  Relationship between IMAPITable and ITableData.

The ITableData methods are summarized in the following table..

Method	Description
HrGetView	Returns a MAPI table object
HrModifyRow	Adds or modifies a row in a table
HrDeleteRow	Deletes a row from a table
HrQueryRow	Returns the specified property values for a row in a table
HrEnumRow	Returns all of the property values for a row in a table
HrModifyRows	Adds or modifies multiple rows in a table
HrNotify	Requests a table notification be sent
HrInsertRow	Inserts a row into a table
HrDeleteRows	Deletes multiple rows in a table
When clients make calls to retrieve tables from service providers, service providers can call the ITableData::HrGetView method. HrGetView returns a table object that can be sorted or restricted.

ITableData defines separate methods for operating on a single row or operating on multiple rows. For example, the HrDeleteRows method will delete as many rows as are specified on input. If a particular row is not found, the method skips it. The number of successfully deleted rows is stored in the cRowsDeleted output parameter passed back. A single notification is generated, regardless of the number of rows deleted.

Both HrModifyRow and HrModifyRows will make changes to existing rows. If the target row does not exist, a row is added.

The HrEnumRow method uses the internal sequential number assigned to each row when it is added to the table to get rows out of a table in the order that they were put in.

The HrInsertRow method is used to insert a row at a specified position.

The HrNotify method can be used to generate a notification to all MAPI table objects that share a view of the data. A table modified notification is sent for all rows that match the property values passed into HrNotify as an input parameter. A notification is sent regardless of whether the data actually changed. When display tables, or tables that show information about user interface controls, receive this type of notification, they reload the data associated with the control.


 Working with Tables

Working with a MAPI table is like working with a relational database table. Many of the table operations, such as setting search criteria, retrieving rows, rearranging the view, are typical database table operations. Sometimes these operations take a long time. As a table user, consider allowing the implementor to process asynchronously and take advantage of deferred errors. As an implementor, bear in mind that there is no way to show progress on these operations. Therefore, try to make your implementations as efficient as possible.

This section covers in detail these common operations from the perspective of the table user and the table implementor.


 Setting Columns

All tables have a group of properties that make up their default column set. For most tables, you have the choice of accepting this default set of columns or modifying it, removing certain columns or adding new ones. Modifying the column set of a table is known as setting columns, a task that is performed through the IMAPITable::SetColumns method.

To retrieve rows from a table, you call IMAPITable::QueryRows. If you make the call to QueryRows before you call IMAPITable::SetColumns to modify the column set, the columns that you will be returned will be those in the default column set. Some tables, like the session table, do allow column set modification. Whenever you call QueryRows on the session table, you will always get back the same set of columns.

In addition to the default column set, some tables have a required set. This is the group of properties that must be present in every row of the table. As a table implementor, you must provide these columns, and as a table user, you are guaranteed that these columns will be present. Sometimes there is overlap between column sets when the default and required sets are the same. Tables that do not allow you to modify their column set, like many MAPI tables, operate this way.

As a table implementor, the set of columns that you permit your caller to pass as an input parameter to SetColumns will typically be the set of columns that you return in your IMAPITable::QueryColumns implementation. However, you can allow other columns to be specified if you are able to add them dynamically to your default column set. If extra columns are specified that you cannot handle, you can return PT_ERROR in the appropriate member of the property problem array when your caller calls IMAPITable::GetLastError.

SetColumns can be prompted to work asynchronously or synchronously; however, table implementors can reject the request and return MAPI_E_NO_SUPPORT. Table users set the TBL_BATCH flag in their SetColumns call to request that it work asynchronously.If the table implementor supports asynchronous column modification, SetColumns will return before the operation completes. Upon completion, a table notification is sent and, upon receipt of this notification, the user can assume that the column set is now as requested.

The HrAddColumnsEx API function allows you to modify the current column set of a table, much like SetColumns.  However, HrAddColumnsEx differs from SetColumns in that it never removes columns. This call only adds to the beginning of the current set. Whatever was in the column set before the call will still be there after the call, positioned after the newly added columns. HrAddColumnsEx is used most frequently to add to the column set of recipient tables.


 Displaying Multi-Valued Columns

A multi-valued column is a column that contains the value for a multi-valued property. Multi-valued properties are displayed in a table in one of two ways:

•	As a single row, with all of the values appearing in the column. This is the default.

•	As a series of single valued properties appearing in multiple rows. The values of the other columns in the row are duplicated. If a row contains more than one column with multiple values, for example, two columns with M and N values respectively, then M*N instances of the row appear in the table. Each multi-valued property should have as many rows as it has values.

As a table user, you request a multiple row display by setting the MVI_FLAG flag in the property type and applying the MVI_PROP macro to the property tag

As an implementor, you do not have to support the alternative of using multiple rows to display multi-valued properties. You may return MAPI_E_TOO_COMPLEX when a caller requests it. However, the rule of thumb is if the underlying data for your table is based on multi-valued properties, you should support this alternative.


 Working with String Properties

String property values can be represented in tables using standard 8 byte characters, property type PT_STRING8, or 16 byte Unicode characters, property type PT_UNICODE. Table implementors are free to choose exactly how much Unicode support they offer. Because Unicode adds value to both clients and service providers by extending the feature set, supporting Unicode wherever possible is recommended. All of the MAPI table object implementations support Unicode.

Many table methods accept a flag that dictates whether or string property values are expected to be Unicode. On input, specifying the MAPI_UNICODE flag indicates to the table implementor that all string property values passed in with the call are Unicode strings and have property types of PT_UNICODE. On output, this flag indicates that all returned string property values should be Unicode strings, if possible. Whether the flag has a meaning for input or output depends on the method. Table implementors that do not support Unicode and are passed the MAPI_UNICODE flag return MAPI_E_BAD_CHAR_WIDTH.

The values for string properties can be very long. When a lengthy string property is returned to you as a table user, its size might or might not be truncated, depending on the implementor. Most table implementors truncate a column containing a string property to 255 bytes. However, when the same lengthy string property is returned to you as a user of the object to which the property belongs, its entire size is available. Truncation of string property values affects only its display in a table.

Limiting string properties to 255 bytes may or may not impact any restrictions that are built. Some implementors allow a restriction to be built that matches against the entire property value, and other implementors allow the match to occur only on the first 255 bytes. Depending on the implementor, you may be able to build a restriction that matches against the entire property rather than the first 255 bytes.


 Table Positioning

MAPI tables have two resources for determining and establishing a position. One of the resources is the cursor, a built-in indicator of the current position. Cursors cannot be changed by a table's user; they are set by the table's implementor to always reflect the user's present position.

The other resource is the bookmark, an indicator of any position in the table. Bookmarks are used to mark a particular position in a table, enabling you to return to that position at a later time. Using bookmarks can make your table operations faster.

A call to IMAPITable::CreateBookmark establishes a bookmark at the current position. Table implementors are required to at least provide bookmarks for thecurrent position, the beginning of the table, and the end of the table. Other bookmarks are optional. To position the cursor using a required bookmark, pass one of the following constants to either IMAPITable::SeekRow or IMAPITable::FindRow: BOOKMARK_CURRENT, BOOKMARK_BEGINNING, or BOOKMARK_END. Because bookmarks are limited resources, it is important to free them by calling IMAPITable::FreeBookmark. At times CreateBookmark might be unable to allocate sufficient memory, in which case the error MAPI_E_UNABLE_TO_COMPLETE is returned.

The IMAPITable::SeekRow or IMAPITable::SeekRowApprox methods change a table's position. SeekRow moves the cursor to a position determined by an established bookmark and a specified number of rows; SeekRowApprox uses a fraction to determine where to move the cursor. SeekRow is useful when you want to position your table ten rows from the current position, for example, or when you want to start over at the beginning. SeekRowApprox is useful for implementing a scroll bar; it lets you move to the row that is one third of the rows from the beginning of the table, for example.

The IMAPITable::QueryPosition method returns the row at the position indicated by a specified fraction. QueryPosition is used to get the row that is one-third of the way into the table, for example. It can also be used for scroll bar implementation. Implementations of QueryPosition and SeekRowApprox can be quite expensive on categorized tables if the implementations choose to be accurate.


 Retrieving Rows

Users of tables typically interact with the table data by retrieving one or more rows in a predefined order. There are three available methods to use to retrieve rows from a table: IMAPITable::QueryRows, ITableData::HrQueryRow, and HrQueryAllRows.

Clients call IMAPITable::QueryRows to retrieve one or more rows at a time, beginning with the current cursor position. The properties that you get back are either the ones that you have specified in a SetColumns call or the ones included in the table's default column set, if SetColumns has not been called.

Service providers call ITableData::HrQueryRow to retrieve a specific row with all of the properties associated with the row.

All table users can call HrQueryAllRows, a helper function that combines the functionality of the SetColumns, SortTable, Restrict, and QueryRows. HrQueryAllRows always calls SeekRow to get to the beginning of the table before starting its processing. If you want to retrieve all of the rows of a table, this function offers a valuable shortcut. However, it is possible to run out of memory when you are retrieving rows from a table with this function. To process an entire table while limiting the amount of memory consumed, set the crowsMax parameter to a reasonable number and call HrQueryAllRows in a loop. This parameter limits the number of rows that are returned with each call. The position of the cursor upon return from HrQueryAllRows is undefined. However, usually it will be at the bottom of the table.

After you have retrieved a row, be careful to check for unexpected or invalid column values, such as PT_ERROR or MAPI_E_NOT_FOUND. Sometimes properties are included in the column set of a table in spite of the fact that they are not supported. The table implementor places a value in the column to indicate that there is no valid value. This is a different error than a column missing from a table altogether.


 Expanding the View

All tables support to some degree ways to create customized views. Customized views are created by building restrictions, specifying a sort order, or defining a column set. Restrictions, sometimes called search criteria, narrow the view of the data. For example, if the table you are using contains the contents of a large folder, there may be many hundreds of messages in it. Maybe you are interested in looking only at the most recent messages or the ones from a particular recipient. Building a restriction on the table enables you to do just that. The data for these rows remains unchanged; it is just not part of your view. MAPI provides many different ways to build restrictions, such as specifying a bitmask or a property type as a basis for comparison. Some tables support all restriction types; other tables support only a few.

Rows can be displayed as flat or as multi-level lists. Most tables are flat lists of rows; only two tables, the hierarchy table and the categorized contents table, are multi-level. Multi-level tables provide two views of their data: an expanded view and a collapsed view. When a top level row is expanded, it is marked with a minus sign and all of its lower level rows are visible. When a top row is collapsed, it is marked with a plus sign and none of its lower level rows are visible. Many hierarchy tables that display message store contents use this feature to allow users to view the messages within many sets of folders without having to scroll.

The IMAPITable methods, SetCollapseSet and GetCollapseState, help you to work with data associated with the state of the display. GetCollapseState allows you to save data that enables you to recreate a multi-level display; SetCollapseState recreates the display based on this saved data. The data that you save includes:

•	the row where you should begin rebuilding the collapsed or expanded state

•	all of the plus and minus indicators at all table depths

•	the top row for the current view.

The PR_INSTANCE_KEY property for the row where you begin rebuilding the display is stored in the lpbInstanceKey parameter passed to GetCollapseState; this property is used to set the bookmark that identifies this row for the SetCollapseState method.

As an implementor of SetCollapseState, operate as if you had been asked to reload your table. This method reestablishes the state of the display to the state that exists with the last GetCollapseState call. You are responsible for keeping the sort order and restrictions exactly the same as they were before the call. Also, you must return a bookmark in the lpbkLocation parameter that corresponds to the row specified by the instance key parameter passed to GetCollapseState. If this row no longer exists, pass back BOOKMARK_BEGINNING in lpbkLocation. The caller should free the bookmark by calling IMAPITable::FreeBookmark.

The ExpandRow and CollapseRow methods allow the state of a row to be modified. As implementors of these methods, you do not have to send a notification on a top level row indicating that the value of its PR_ROW_TYPE property has changed. If clients maintain the data, they can update their copy of the lower level rows when making the ExpandRow or CollapseRow call.

When ExpandRow is called, the top level row to undergo the expansion is represented by the instance key specified in the pbInstanceKey parameter. The returned row set is inserted in the table after this row. No notification is generated by these rows appearing in the table. If the expanded section is larger than the value of the ulRowCount parameter, then only ulRowCount rows are returned. The expand state is not saved across restrictions.

If ExpandRow cannot return all of the requested rows because of insufficient memory, the total number of rows that were added is returned in the lpulMoreRows parameter. This output parameter returns the number of additional rows that would have been returned if resource limits had not been exceeded. If the contents of lpulMoreRows is non-zero, then the position in the table is adjusted to the first of the rows that could not be returned.

When CollapseRow is called, the number of rows removed, including top level and lower level rows, is returned in the contents of the pulRowCount parameter. No notification is generated when these rows disappear from the table.

A bookmark pointing to a row which is collapsed out of the view is still valid. If used, it is positioned at the next visible row. The call on which such a bookmark is used returns MAPI_W_POSITION_CHANGED. Your implementation of CollapseRow can move the bookmark at the time of collapse or the time of use. If the position is changed at the time of collapse, you must set and return a bit with the bookmark to indicate whether its position has changed since its last use.


 Sorting Tables

Specifying a sort order involves supplying one or more columns whose values dictate the order in which the rows of your table are displayed. Maybe youwant to see all of your messages in alphabetic order by subject so that all of the threads of a conversation are together. The sort feature on MAPI tables enables you to customize your view in this way. A special type of sorting, called categorization, is available with contents tables. Categorization sorts data by groups, or categories.

The rows that you retrieve can be sorted using IMAPITable::SetColumns or IMAPITable::SortTable. SetColumns establishes an initial sort order using the columns that it includes in the table. When a call is made to retrieve the rows, they will appear in this order. Tables that do not allow their column set to be altered often have a default sort order. The providers and message service tables, for example, are sorted by PR_DISPLAY_NAME.

SortTable establishes a subsequent sort order, sometimes using columns that appear in the table view, sometimes using columns that do not appear in the view, and sometimes using predefined categories. SortTable sorts rows in ascending or descending order, depending on your choice as a caller. All NULL entries are placed last.

The instance key, or PR_INSTANCE_KEY property, uniquely identifies each row in a table. PR_INSTANCE_KEY is a required column in most tables. Instance keys are unique to each table instance; two views of the same table do not share instance keys. The PR_INSTANCE_KEY property is used as an index column, for notification, and, if the table supports it, for categorization.

All implementations of SortTable allow users to define a sort order based on columns that are currently part of the view. Some implementations will add value by supporting a sort on inactive columns or categories. Implementations that cannot support these additional features can return MAPI_E_TOO_COMPLEX if asked to perform an unsupported sort.

Whenever SortTable fails, the sort order that was in effect before the failure will still be in effect.

If you are planning to limit your column set, build a restriction, and request a sort, make sure you do those tasks in that exact order. That is, call SetColumns before Restrict and Restrict before SortTable. This limits the number of rows and columns that will be sorted, thereby improving performance.


 Using Categorized Tables

A categorized table is a table that organizes its data into named groups. Categorization is a feature that some contents tables support.

To request a categorized table, call SortOrder specifying the properties that you want to use as categories in the array of SSortOrder data structures. Categories may be in either ascending or descending order. The cCategories field in the SSortOrderSet data structure should be set to the number of categories that you have specified and the cExpanded field should be set to the number of categories that are initially displayed in their expanded state.

After SortOrder completes, you can call SetColumns to define the columns that you would like to include in your view. You can specify any of the columns from the SSortOrder array or columns that were not included in the array. The ordering of the columns in the SSortOrder structure and in the SetColumns call do not have to match.

When you call QueryRows to retrieve your data, each row will have a PR_ROW_TYPE property associated with it. PR_ROW_TYPE is a 32-bit value that indicates whether a row is a lower-level data row (TBL_LEAF_ROW) or a top level category row which should be shown as expanded (TBL_EXPANDED_CATEGORY) or collapsed (TBL_COLLAPSED_CATEGORY).

There will be a category heading row containing one or more of the categorization properties. All other properties, except for PR_INSTANCE_KEY and PR_ROW_TYPE, are not returned. The top-level category rows contain only the category properties in the following pattern: the most top level row contains the first category, the second level row contains two categories, and the third level row contains three categories. This pattern continues until the category list is exhausted.

To implement SortTable for categorization, begin by expanding the first category, and keep expanding the categories in the order they appear in the SSortOrder array until the number expanded equals the value of cExpanded. The rest of the remaining categories are collapsed. If the cExpanded field is equal to zero, only the rows containing the top-level category names are visible. If the cExpanded field is equal to one less than the number of categories, then all of the category rows are visible and non of the lower-level non-category rows are visible. If the cExpanded field is equal to the number of categories, then the table is fully expanded.

The PR_INSTANCE_KEY property will change on a row in a table that is categorized by a multi-value column after a call to SortTable, SetColumns, or Restrict. This is because the data for a multi-value column might be included in multiple rows, with one row for every value. When a table is categorized ona column that contains a single value property, the value of its PR_INSTANCE_KEY property remains constant.

The PR_DEPTH property indicates a level of a row. PR_DEPTH is set to 0 for top-level categorization rows and 1 for second-level categorization rows. For each level, the PR_DEPTH value increases by one. Lower-level data rows have a value of n where n is the number of categories for PR_DEPTH.

The PR_UNREAD_COUNT property, a computed property that contains the number of data rows in a category, is included as a column on a category row. This is the only property that appears on a category row that cannot be used for a category. If an attempt is made to define PR_UNREAD_COUNT as a category in the SortTable; the table implementor should return MAPI_E_INVALID_PARAMETER from the SortTable call.


 Building Restrictions

One of the most common ways users work with tables is to search for data that matches specific search criteria. Users specify search criteria by building restrictions. As described earlier in the "About Restrictions" section, there are many types of restrictions, each represented with its own unique data structure. When you set a restriction, you select the data structure that applies to the type of restriction you are building, fill an instance of the structure with the appropriate data, and pass it in your call to IMAPITable::Restrict or IMAPITable::FindRow.

The IMAPITable::Restrict method applies the restriction to the table without retrieving any rows. To see the results of a Restrict call, you must call IMAPITable::QueryRows. IMAPITable::FindRow, however, applies the restriction and retrieves a row, returning the next matching row in the table. Restrict is used when you want to work with the rows that result from applying a restriction for an extended length of time whereas FindRow applies a temporary restriction, in existence only for the duration of the call.

Content restrictions use the concept of fuzzy level to describe the degree of exactness or looseness that is applied when searching text. The ulFuzzyLevel parameter in the SContentRestriction data structure can have six different values as follows:

Fuzzy Level	Description
FL_FULLSTRING	The exact string is searched for as a strict match on the entire property.
FL_SUBSTRING	A match occurs if the string occurs anywhere within the property.
FL_PREFIX	A match occurs only if the string occurs at the beginning of the property. This flag if present, takes precedence over FL_FULLSTRING.
FL_IGNORECASE	The comparison ignores differences in the case of letters.
FL_IGNORENONSPACE	The comparison ignores differences in non-spacing characters or in diacritics.
FL_LOOSE	Loose matching.
These constants can be OR'ed together. For example, FL_SUBSTRING | FL_IGNORECASE results in a loose match substring.

Providers can choose to ignore the FL_IGNORECASE and the FL_IGNORENONSPACE values. In fact, the degree of support for fuzzy levels is implementation-specific. Therefore, when you call Restrict or FindRow and pass in an unsupported fuzzy level, you will most likely get back the error MAPI_E_TOO_COMPLEX.

MAPI supports a limited form of regular expression notation for use in building restrictions. A regular expression specifies a set of character strings. A member of this set of strings is said to match the regular expression. An ordinary character is a one-character regular expression that matches itself.

You form regular expressions using special characters like the period ".", asterisk "*", and opening bracket"[". If you want to use a special character literal (that is, without its regular meaning) in a regular expression, you must quote it by preceding it with a backslash, "\". A backslash (\) followed by any special character is a one-character regular expression that matches the special character itself. MAPI interprets special characters in strings as regular expressions only when the relational operator is RELOP_RE, so do not be tempted to quote the special characters everywhere.

Characters that are considered special, except when they appear within brackets, include:

•	period (.)

•	asterisk (*)

•	opening bracket ([)

•	backslash (\)

Other characters are special under certain circumstances. These characters are as follows:

•	The caret (^), which is special at the beginning of an entire regular expression or when it immediately follows an opening bracket([]).

•	The dollar sign ($), which is special at the end of an entire regular expression.

The period is a one character regular expression that matches any character except the new line character. A non-empty character string enclosed in brackets is a one-character regular expression that matches any single character in that string. If, however, the first character of the string is a caret (^), the one-character regular expression matches any character except the new line character and the remaining characters in the string.

The asterisk (*) has this special meaning only if it occurs first in the string. The dash (-) can be used to indicate a range of consecutive ASCII characters; for example, [0-9] is equivalent to [0123456789]. The dash loses this special meaning if it occurs first or last in the string. The closing bracket (]) does not terminate such a string when it is the first character within it for example, []a-f], matches either a closing bracket (]) or one of the letters "a" through "f". The period, asterisk, opening bracket, and backslash lose their special meaning within such a string of characters.

Use the following rules to construct regular expressions from one-character regular expressions:

1.	A one-character regular expression matches itself.

2.	A one-character regular expression followed by an asterisk (*) is a regular expression that matches zero or more occurrences of the one-character regular expression. If there is any choice, the longest leftmost string that permits a match is chosen.

3.	A one-character regular expression followed by \{m\}, \{m,\}, or \{m,n\} is a regular expression that matches a range of occurrences of the one-character regular expression. The values of m and n must be nonnegative integers less than 255; \{m\} matches exactly m occurrences; \{m,\} matches at least m occurrences; \{m,n\} matches any number of occurrences between m and n, inclusive. Whenever a choice exists, the regular expression matches as many occurrences as possible.

4.	A concatenation of regular expressions is a regular expression that matches the concatenation of the strings matched by each component of the regular expression.

5.	A regular expression enclosed between the character sequences \( and \) is a regular expression that matches whatever the original regular expression matches. See 2.6 for a discussion of why this is useful.

6.	The \n expression matches the same string of characters that was matched by an expression enclosed between \( and \) earlier in the same regular expression. Here n is a digit; the subexpression specified is that expression beginning with the nth occurrence of \( counting from the left. For example, the expression matches a line consisting of two repeated appearances of the same string.

Finally, you can constrain an entire regular expression to match only an initial segment or final segment of a line (or both):

1.	A caret (^) at the beginning of an entire regular expression constrains that regular expression to match an initial segment of a line.

2.	A dollar sign ($) at the end of an entire regular expression constrains that regular expression to match a final segment of a line. The construction ^entire regular expression$ constrains the entire regular expression to match the entire line.


 Table Notifications

Users can register to be notified when a change to a table occurs by creating an advise sink object and calling IMAPITable::Advise. Typical changes that cause notifications to be sent include the addition or deletion of a row or column and any critical error.

Table implementors can manage the registration and generation of notifications by hand or rely on the helper methods in IMAPISupport. Either way, when you send a table notification, set the ulEventType field in the NOTIFICATION structure to TABLE_NOTIFICATION and include a TABLE_NOTIFICATION data structure in the info field. Set the propIndex field to the value of the PR_INSTANCE_KEY property for the affected row and the propPrior field to the value of the PR_INSTANCE_KEY property for the row preceding the affected row. The SRow structure contains all of the property data for the affected row. The properties that are included in the SRow structure are ordered using the column set that was established from the previous IMAPITable::SetColumns call. Both the property values and the property tags are in this order.

The TABLE_NOTIFICATION data structure is defined as follows:

typedef struct _TABLE_NOTIFICATION

{

         ULONG       ulTableEvent;
         HRESULT     hResult;
         SPropValue  propIndex;
         SProvValue  propPrior;
         SRow        row;

}   TABLE_NOTIFICATION;

There are several different event types that you can specify in the ulTableEvent field. As an advise sink implementing IMAPIAdviseSink::OnNotify, you should be prepared to handle all of these. A TABLE_CHANGED event is a somewhat nebulous event indicating that only something about the table has changed, but no details are available. The table's state is as it was before the event. All instance keys (PR_INSTANCE_KEY properties), bookmarks, and current positioning are still valid. A TABLE_CHANGED event is sent when, for example, the underlying data is stored in a database and the database is replaced.

The TABLE_ERROR event is sent when a critical error occurs, usually during an asynchronous operation. Errors during calls to IMAPITable::SortTable, SetColumns, or Restrict can generate this type of event. The IMAPITable::GetLastError method cannot provide any further information about the error because it was not returned as the result of a method call.

The TABLE_RELOAD event indicates a need to re-read the data and start over. When clients receive this event, they should assume that nothing about the table is still valid. All bookmarks, instance keys, status and positioning information are obsolete.

The TABLE_RESTRICT_DONE, TABLE_SETCOL_DONE, and TABLE_SORT_DONE events signal the end of an asynchronous operation - either to set a restriction, set columns, or perform a sort on the table.

The TABLE_ROW_ADDED notification is sent when a new row has been added to the table. The propPrior instance key is for the row above where the row was added. As a client receiving this event, bear in mind that although the data in the propPrior and SRow fields was correct when the notification was generated, it might no longer be correct when you receive the notification. Between the time the notification was generated and the time that it was sent, other changes might have occurred.

The TABLE_ROW_DELETED event identifies a row that is no longer part of the table. The TABLE_NOTIFICATION structure does not contain a value for the propPrior field for this event.

The TABLE_ROW_MODIFIED event identifies a changed row. The SRow structure contains new data for the row. If the affected row is now the first row in the table, the value of the propPrior field is PR_NULL. Clients receiving this event must duplicate the entire SRow structure if they want to keep a copy of the properties included in the structure. Multiple TABLE_ROW_MODIFIED events should be in chronological order with respect to the view that is seen by the user.

Now, for a couple of warnings. First, because of the asynchronous nature of event notification, the data passed in the TABLE_NOTIFICATION structure may not be the most current information about the state of the table. Clients may be aware of changed or added rows before they are officially notified.

Second, although the order of the properties that are returned in the TABLE_NOTIFICATION structure should be the order that you specified in your last SetColumns call, do not assume that this is the case. Senders of table notifications are not required to follow any rules when ordering these properties.

Third, table notifications are only sent for rows that are part of the view. That is, if a row is excluded due to a restriction or because the table is in a collapsed state, no notification will be sent if that row changes.


 Types of Tables

MAPI defines many different tables to enable you to readily access and manipulate the important properties of many types of objects. These next sections focus on these different types and their own unique characteristics. Each section includes the following information, if appropriate:

•	methods for instantiation and how to retrieve the IMAPITable interface pointer

•	typical implementor

•	typical user

•	properties for the required columns

•	properties for the default columns

•	properties for the default sort order

•	characteristics specific to the table


Attachment Tables
 Attachment Table

The attachment table describes the attachment objects that are associated with a submitted message or a message under composition. Attachment tables are implemented by message store providers and used by clients, who call IMessage::GetAttachmentTable to retrieve a pointer to the table object.

Attachment tables have three required columns: PR_ATTACH_NUM, PR_RECORD_KEY, and PR_RENDERING_POSITION. Message store providers are free to add other columns.

PR_ATTACH_NUM is a nontransmittable property that contains a value for uniquely identifying an attachment within a message. PR_ATTACH_NUM is often used as an index into the rows of the table. While an attachment table is open, the value of PR_ATTACH_NUM remains constant.

A common property for many objects, PR_RECORD_KEY is used in attachment tables to alsoidentify an attachment. Unlike PR_ATTACH_NUM, PR_RECORD_KEY has the same scope as a long term entry identifier; it remains available and valid even after the message is closed and reopened.

PR_RENDERING_POSITION is an offset in characters that identifies where a client should display the attachment within a message. Not all attachments use PR_RENDERING_POSITION. A value of  0xFFFFFFFF indicates that an alternate method for rendering the attachment should be used.

The attachment table is dynamic, so it can change while it is open. That is, if the client creates or deletes an attachment, or modifies one of the properties in the column set, the changes will be reflected in the table. However, only attachments that have been saved are included in the table.

Attachment tables, when initially opened, are not necessarily sorted in any particular order.


Contents Tables
 Contents Table

The contents table lists information about child objects, such as messaging users, distribution lists, and messages, that are contained in a parent object, such as an address book container, or folder. The information contained in a contents table is used to display address book recipients and messages to users of client applications.

Address book and message store providers implement contents tables as part of the IMAPIContainer interface that address book container objects and folder objects support. To create a contents table, clients call IMAPIContainer::GetContentsTable. This method accepts as input several flags that specify preferences. The MAPI_DEFERRED_ERRORS flag indicates to the service provider that any errors encountered during the table creation do not need to be reported until some later time. This allows the call to succeed, returning some or all of the data. For information on dealing with deferred errors, see the "Handling Errors" section in Chapter 8.

The MAPI_ASSOCIATED flag, applicable only to message store contents tables, indicates that only associated entries should be included in the new table. Message store contents tables have two types of entries: standard and associated. When a client creates a message, a flag can be set on the IMAPIFolder::CreateMessage call to indicate that the new message is somehow special. Perhaps it contains hidden data or is an alternate representation of a standard message. Associated and standard messages are stored separately, and clients ask for one or the other when creating contents tables.

In addition to the use of the MAPI_ASSOCIATED flag, there are a few other differences between the address book contents tables and message store contents tables. With message store contents tables, a given column is empty if the message store does not support the associated message property.

All contents tables use the PR_INSTANCE_KEY property as the index.

Contents tables have a lengthy list of required columns. Some of the columns are required by both types of contents tables; other columns are specific to address books or message stores. The following table lists all of the required columns and the table or tables in which they belong.

Column	Address Book	Message Store
PR_ADDRTYPE	X
PR_CLIENT_SUBMIT_TIME		X
PR_DISPLAY_NAME	X
PR_DISPLAY_CC		X
PR_DISPLAY_TO		X
PR_DISPLAY_TYPE	X
PR_ENTRYID	X	X
PR_HASATTACH		X
PR_INSTANCE_KEY	X	X
PR_LAST_MODIFICATION_TIME		X
PR_MAPPING_SIGNATURE		X
PR_MESSAGE_CLASS		X
PR_MESSAGE_DELIVERY_TIME		X
PR_MESSAGE_FLAGS		X
PR_MESSAGE_SIZE		X
PR_MSG_STATUS		X
PR_NORMALIZED_SUBJECT		X
PR_OBJECT-TYPE	X	X
PR_PARENT_ENTRYID		X
PR_PRIORITY		X
PR_RECORD_KEY		X
PR_SENDER_NAME		X
PR_SENSITIVITY		X
PR_STORE_ENTRYID		X
PR_STORE_RECORD_KEY		X
PR_SUBJECT		X
There are a few more properties that are not part of the required column set, but are often included in address book contents tables. These optional columns are:

PR_EMAIL_ADDRESS	PR_SEND_RICH_KEY
PR_SEARCH_KEY	PR_TRANSMITABLE_DISPLAY_NAME
Message store providers must include PR_PARENT_DISPLAY for search-results folders contents tables.

This list of properties does not include all the properties that can be included in a contents table. Clients may request other properties; it is up to the service provider as to whether the table can include them.


Display Tables
 Display Table

The display table describes how to show a dialog box. Each row represents a control on the dialog box; each column represents a property of the control. One of the common ways that display tables are used in MAPI is for the display of configuration property sheets. With a display table, you can copy property data from your local workstation to a server workstation and have the server control a display of the data on your workstation. Building a display table is similar to creating a program with a scripting language.

Display tables are implemented by MAPI and used mostly by service providers, with occasional use by clients. To build a display table, you fill in one or more display table page, or DTPAGE. data structures and pass them along with several other parameters to the API function, BuildDisplayTable.

BuildDisplayTable returns to callers a pointer to a MAPI table object and, if desired, a pointer to a read-write table data object as well. Clients who require access to the table can be given the IMAPITable pointer to the read-only view. The table data object is returned only if a valid ITableData pointer is passed into the call. Service providers that do not require access to the underlying data can pass NULL.

The DTPAGE data structure, used to describe the dialog box, includes a count of the number of controls that appear on the dialog box, the name of the dialog resource, and a pointer to an array of display table control, or DTCTL, data structures.

The DTCTL data structure contains a constant that indicates the control type, a set of flags, an item identifier, a character filter for edit or combo box controls, notification data, and a union of different control type data structures. Each control type structure holds information specific to the type of control. The control type corresponds to the PR_CONTROL_TYPE property; the set of flags corresponds to the PR_CONTROL_FLAGS property.

Each of the controls in a display table has notification data associated with it.

The DTCTL data structure is defined as follows:

typedef struct

{

  ULONG       ulCtlType;

  ULONG       ulCtlFlags;

  LPBYTE      lpbNotif;

  ULONG       cbNotif;

  LPTSTR      lpszFilter;

  ULONG       ulItemID;

  union  {

      LPVOID             lpv;

      LPDTBLLABEL        lplabel;

      LPDTBLEDIT         lpedit;

      LPDTBLLBX          lplbx;

      LPDTBLCOMBOBOX     lpcombobox;

      LPDTBLDLLBX        lpdllbx;

      LPDTBLCHECKBOX     lpcheckbox;

      LPDTBLGROUPBOX     lpgroupbox;

      LPDTBLBUTTON       lpbutton;

      LPDTBLRADIOBUTTON  lpradiobutton;

      LPDTBLMVLISTBOX    lpmvlistbox;

      LPDTBLMVDDLBX      lpmvddlbx;

      LPDTBLPAGE         lppage;

  }  ctl;

} DTCTL, FAR *LPDTCTL;

Because there are so many different types of control objects that represent the rows in a display table, there is no generic way to handle a table notification when it is received. The processing that occurs when you receive a notification depends on the type of object that has been affected.

The following table describes how all of the possible control types handle a table notification. The display table control types are listed by their structure names.

Display Table Control Type	Recommended Action
DTBLBUTTON	Retrieve the button's value.
DTBLCHECKBOX	Reread the value for ulPRPropertyName.
DTBLCOMBOBOX	Open the table, reread all of the rows including the value for ulPRPropertyName.
DTBLDDLBX	Reopen the table, read all of the rows, and call GetProps to retrieve the values for ulPRDisplayProperty and the ulPRSetProperty properties
DTBLEDIT	Reread the property tag and redisplay.
DTBLGROUPBOX	Ignor the notification.
DTBLLABEL	Ignor the notification.
DTBLLBX and ulPRSetProperty is PR_NULL (multi-select list box)	If one of the columns is an entry identifier, this is considered to be the same as if you're looking at the contents table of a distribution list of an address book container, for example, a details display on a distribution list. There is no concept of selection. Simply refresh the list box. Do not close or reload the object.
DTBLLBX and ulPRSetProperty is not PR_NULL (single selection list box)	Read the set property and try to identify it.
DTBLMVDDLBOX (list box with multi-value string properties)	Reread the property and re-populate the list box.
DTBLMVLISTBOX	Reread the property and re-populate the list box.
DTBLPAGE	If ulbLpszComponent is non-zero, there is an encapsulated string that points to a help file. No notifications on this control; everything is static.
DTBLRADIOBUTTON	The ulcButtons field contains the number of buttons in the group. The ulPropTag field is the name of the property associated with the buttons. When a notification is received, reread the ulPropTag and make the appropriate selection on the controls.
There are eight properties that are part of the required column set for display tables.

PR_XPOS	PR_YPOS
PR_DELTAX	PR_DELTAY
PR_CONTROL_TYPE	PR_CONTROL_FLAGS
PR_CONTROL_STRUCTURE	PR_CONTROL_ID


Hierarchy Tables
 Hierarchy Table

The hierarchy table displays information about child objects, such as messages, folders, messaging users, and distribution lists, that are contained in the current container. Each row of a hierarchy table contains a set of columns holding information about one child container. Hierarchy tables are used by message store providers to show a tree of folders and subfolders and by address book providers to show a tree of containers within the address book. Clients retrieve a hierarchy table by calling the IMAPIContainer::GetHierarchyTable method.

The hierarchy table can include all columns visible in the current table view, but for many tables the initial set of columns are those that most implementations can produce quickly. Typically, this is the default column set.

All hierarchy table implementations must include at least the following properties in their default column set:

PR_COMMENT	PR_DEPTH
PR_DISPLAY_NAME	PR_ENTRYID
PR_STATUS
In addition to these columns, address book hierarchy tables must include the following properties:

PR_CONTAINER_FLAGS	PR_DISPLAY_TYPE
PR_INSTANCE_KEY	PR_OBJECT_TYPE
An optional property for address book hierarchy tables is the PR_AB_PROVIDER_ID property.

Message store hierarchy tables include these properties in their required column set:

PR_FOLDER_TYPE	PR_SUBFOLDERS


Message Services Tables
 Message Services Table

The message services table lists information about the message services in the current profile. There is one message services table for every MAPI session. The message services table is a static table, meaning that once it has been created, it will not reflect any changes in underlying data of the table. The message services table is implemented by MAPI and used by special purpose clients that provide configuration support. Clients retrieve a message services table object by calling IMsgServiceAdmin::GetMsgServicesTable.

There are eight properties that are part of the required column set for the message services table.

PR_DISPLAY_NAME	PR_INSTANCE_KEY
PR_RESOURCE_FLAGS	PR_SERVICE_DLL_NAME
PR_SERVICE_ENTRY_NAME	PR_SERVICE_NAME
PR_SERVICE_SUPPORT_FILES	PR_SERVICE_UID
The PR_INSTANCE_KEY property is the index for the table; the default sort column is PR_DISPLAY_NAME.

The PR_SERVICE_NAME property is a required entry in the [Services] section in MAPISVC.INF. The value for this property will never be changed or localized. PR_SERVICE_NAME can be used to programmatically identify the message service.

The PR_RESOURCE_FLAGS property describes the message service's capabilities.


 Message Stores Table

The message stores table lists information about message store providers in the current profile. There is one message stores table for each session that is implemented by MAPI. Clients access this table by calling IMAPISession::GetMsgStoresTable.

This table is indexed by PR_INSTANCE_KEY and there is no default sort order.

There are ten properties that are part of the required column set for the message stores table.

PR_DEFAULT_STORE	PR_DISPLAY_NAME
PR_ENTRYID	PR_INSTANCE_KEY
PR_MDB_PROVIDER	PR_OBJECT_TYPE
PR_PROVIDER_DISPLAY	PR_RECORD_KEY
PR_RESOURCE_FLAGS	PR_RESOURCE_TYPE


One-Off Tables
 One-Off Table

The one-off table lists the templates that an address book provider supports for creating custom recipient addresses. Address book providers implement one-off tables in their IABLogon::GetOneOffTable method which MAPI calls when the user of a client application elects to create a custom recipient.

Custom recipients are individual recipients or distribution lists that do not as yet belong to any of the address book providers in the current profile. These custom recipients are created using dialog box templates supplied by an address book provider.

Once open, MAPI keeps the one-off table open. When the address book provider makes changes to the table, notifications are sent to the client.

The following properties are part of the required column set in one-off tables:

PR_ADDRTYPE	PR_DEPTH
PR_DISPLAY_NAME	PR_DISPLAY_TYPE
PR_ENTRYID	PR_INSTANCE_KEY
PR_SELECTABLE


 Outgoing Queue Table

The outgoing queue table lists all of the outgoing messages for a message store. Message store providers implement the outgoing queue tables for the MAPI spooler to use. Clients do not use this table. To retrieve a pointer to an outgoing queue table, the MAPI spooler calls the IMsgStore::GetOutgoingQueue method.

There is a requirement that messages be preprocessed and submitted to the transport provider in the same order as they were sent by the client. The MAPI spooler is designed to accept messages from the message store in ascending order of submission time. Because of this requirement, there may be some delay before some messages appear in the outgoing queue table.

Message stores should either allow sorting on the outgoing queue table so that the MAPI spooler can sort the messages by submission time, or the default sort order should be by ascending submission time.

It is the responsibility of the message store provider to set up notifications for the outgoing message queue and ensure that the notification callback function is called when the contents of the queue change.

The following properties are required columns in outgoing queue tables.

PR_CLIENT_SUBMIT_TIME	PR_DISPLAY_BCC
PR_DISPLAY_CC	PR_DISPLAY_TO
PR_ENTRYID	PR_MESSAGE_FLAGS
PR_MESSAGE_SIZE	PR_PRIORITY
PR_SENDER_NAME	PR_SUBJECT
PR_SUBMIT_FLAGS


 Profile Table

The profile table lists information about all profiles associated with a particular client application. MAPI implements the profile table for use by clients. A pointer to the table is returned when clients call the IProfAdmin::GetProfileTable method.

There is one profile table for every session. The profile table is a static table, meaning that if profiles are added or deleted during the session, the table will not change.

As with most table implementations, if GetProfileTable is called and there are no profiles available to the client, a table object is returned with zero rows in the table.

The following properties make up the required column set for the profile table:

PR_DEFAULT_PROFILE	PR-DISPLAY_NAME


 Providers Table

The providers table lists information about service providers for client use. There are two different providers tables. The IMsgServiceAdmin::GetProviderTable method creates a MAPI table object that holds all of the providers for the current profile. The IProviderAdmin::GetProviderTable method creates a table that stores all of the service providers for a message service.

The following properties are required in the column sets of providers tables:

PR_INSTANCE_KEY	PR_DISPLAY_NAME
PR_PROVIDER_DISPLAY	PR_PROVIDER_DLL_NAME
PR_PROVIDER_ORDINAL	PR_PROVIDER_UID
PR_RESOURCE_FLAGS	PR_RESOURCE_TYPE
PR_SERVICE_NAME	PR_SERVICE_UID
To display the current transport order, build a restriction to retrieve only those rows with the PR_RESOURCE_TYPE property set to MAPI_TRANSPORT_PROVIDER. Then sort the table on the PR_PROVIDER_ORDINAL property and retrieve all of the rows, using the IMAPITable::QueryRows method or the API function HrQueryAllRows.

To change the transport order, apply the same restriction and retrieve the rows. Create an array of values from the PR_PROVIDER_UID property that represents the unique identifiers for the tranport providers. When the identifiers are in the desired order, pass them to the IMsgServiceAdmin::MsgServiceTransportOrder method.

Providers that have been deleted, or are in use but have been marked for deletion, are not included in the providers table. Once a providers table has been returned to a client, it will not reflect changes to the environment, such as the addition or deletion of a provider.


 Receive Folder Table

The receive folder table lists information for all of the folders designated as receive folders for a message store. A receive folder is a folder where incoming messages of a particular message class are placed. Message store providers implement receive folder tables and clients use them by making a call to the IMsgStore::GetReceiveFolderTable method.

Receive folder tables have three properties in their required column set:

PR_ENTRYID	PR_MESSAGE_CLASS
PR_RECORD_KEY


Recipients Tables
 Recipients Table

The recipients table lists information about all of the recipients for a message. Both messages under composition and received messages are included in the table. Message store providers implement recipients tables and clients use them. Clients access a recipients table by making a call to the IMessage::GetRecipientsTable method. Changes to a recipients table can be made by calling the IMessage::ModifyRecipients method. A warning when calling ModifyRecipients - you must specify every column that you want to appear in the table and not just the changed ones. ModifyRecipients will delete all columns that you do not specify.

Any message store provider that supports message transmission, as indicated by the STORE_SUBMIT_OK bit being set in the provider's PR_STORE_SUPPORT_MASK property, should offer support for a particular set of restrictions in the recipients table implementation. The AND, OR, EXISTS, and Property restrictions are among the restrictions that should be available to recipients table users. Only the equal and not equal operators need to be supported on the Property restriction. These restrictions must work with the following properties:

PR_ADDRTYPE	PR_EMAIL_ADDRESS
PR_RECIPIENT_TYPE	PR_RESPONSIBILITY
PR_SPOOLER_STATUS	PR_TRANSPORT_STATUS
Categorization and sorting are optional features.

Recipients tables have a different column set depending on whether the message has been submitted. All messages should include the following properties in their recipients tables:

PR_DISPLAY_NAME	PR_ENTRYID
PR_RECIPIENT_TYPE	PR_ROWID
The optional properties are as follows:

PR_DISPLAY_TYPE	PR_OBJECT_TYPE
PR_SPOOLER_STATUS
Submitted messages should include these additional properties in their required column set:

PR_ADDRTYPE	PR_CLIENT_SUBMIT_TIME
PR_SENDER_ENTRYID	PR_RESPONSIBILITY
PR_SENDER_NAME	PR_TRANSPORT_STATUS
Depending on a provider's implementation, additional columns might be in the table.


 Status Table

The status table lists information relating to the state of the current session. There is one status table for every session that includes information provided by MAPI and service providers. MAPI provides data for three rows: one for the MAPI subsystem, one for the MAPI spooler, and one for the integrated address book. Because transport providers are required to supply status information to the status table, there is one row for every active transport provider. Address book and message store providers can choose whether or not to provide status table support.

To use the status table, clients call the IMAPISession::GetStatusTable method. Status table information can be used in a variety of ways. For example, it is possible to open the service provider's status object by passing the value of the PR_ENTRYID property to the IMAPISession::OpenEntry method. The status object supports the IMAPIStatus interface, so use its methods to change a service provider password, flush the message queue, display a configuration property sheet, or confirm status with the provider directly. Status table information can also be used to build a dialog box to inform clients of progress during a lengthy operation.

Service providers who do support the status table use the IMAPISupport::ModifyStatusRow method to create and update their row. Whenever a change occurs to their row, all advise sink objects registered to receive status table notifications must be notified. Service providers can call the IMAPISupport::Notify method if they are using MAPI's notification utility or call each advise sink's IMAPIAdviseSink::OnNotify method directly.

The status table has a large number of required properties. Besides these required properties, service providers can choose whether or not to store other properties. PR_IDENTITY_SEARCH_KEY is a property that some service providers may elect to include. The basic set of required properties is:

PR_DISPLAY_NAME	PR_ENTRYID
PR_IDENTITY_DISPLAY	PR_IDENTITY_ENTRYID
PR_INSTANCE_KEY	PR_OBJECT_TYPE
PR_PROVIDER_DISPLAY	PR_PROVIDER_DLL_NAME
PR_RESOURCE_FLAGS	PR_RESOURCE_METHODS
PR_RESOURCE_TYPE	PR_ROWID
PR_STATUS_CODE	PR_STATUS_STRING


 Using Status Objects

This chapter describes what a status object is, how it is implemented, and how it is used. It is divided into two parts following a brief introduction. The first part describes the IMAPIStatus interface and the second part describes the properties that are supported by a status object.


 About Status Objects

Status objects are MAPI objects that support the IMAPIStatus interface. In a typical session, there are several different status objects - some implemented by MAPI, others implemented by service providers. MAPI provides three different status objects: one that represents the overall subsystem, one that represents the MAPI spooler, and one that represents the integrated address book. The MAPI spooler's status object reflects the status of all of the transport providers currently operating. Transport providers are required to supply a status object; it is optional for other service providers.

Status objects are used by clients to learn about the state of session resources. There are two ways a client can access a status object, directly through a service provider's OpenStatusEntry method implemented in the logon object or indirectly through the session. Accessing a status object through the session is a two step process. Clients call IMAPISession::GetStatusTable to access the status table, a listing of all of the available status objects, and then use one of the columns on the table, PR_ENTRYID, to open the specific status object with IMAPISession::OpenEntry.


 About IMAPIStatus

The IMAPIStatus interface contains four methods, only one of which service providers are required to support. Service providers must support the ValidateState method; the SettingsDialog, ChangePassword, and FlushQueues methods are optional. Service providers may return MAPI_E_NO_SUPPORT from the optional methods. The following table briefly describes each of these methods:

Method	Description
ChangePassword	Changes a provider-specific password
FlushQueues	Forces a synchronous upload or download of messages
SettingsDialog	Generates a provider-specific configuration dialog
ValidateState	Confirms the status of a provider
Service provider status objects implement ChangePassword. ChangePassword changes a service provider password programmatically, without user interaction.

The MAPI spooler status object implements FlushQueues. FlushQueues is an instruction to the MAPI spooler to synchronously give all outgoing messages to the appropriate transport provider or accept all incoming messages from a transport provider. Clients call this method when they want to send or receive messages right away.

Service provider status objects implement SettingsDialog. SettingsDialog asks a service provider to display a property sheet, which is a dialog box that presents configuration options. It is allowable for service providers to refuse to display a property sheet and return MAPI_E_NO_SUPPORT. However, this is not the recommended course of action. Service providers can implement their own provider sheet or ask MAPI to help by calling IMAPISupport::DoConfigDialog. The DoConfigDialog method builds a property sheet for display from a display table and configuration data passed in as input parameters.

Service providers can present a read-only property sheet, disallowing any changes of configuration options, or make the property sheet read-write, allowing some or all of the options to be modified. Clients calling the SettingsDialog method can request read-only access by setting the UI_READONLY flag, however, this is only a request and it is up to the service provider to ultimately determine what the access will be.

All status objects implement the ValidateState method. ValidateState prompts a status object to check on its state. The meaning of the phrase "check on its state" varies depending on the particular status object implementation. The MAPI subsystem's ValidateState method validates all of the resources owned by service providers and the subsystem itself. The MAPI spooler's ValidateState method performs a logon of all of the transports, regardless of whether they were already logged on. The MAPI address book's ValidateState method checks the entries in its profile section.

Transport status objects might be passed several option flags in their ValidateState call. For example, clients can dynamically reconfigure a transport by making the appropriate changes and then passing the CONFIG_CHANGED flag to ValidateState. Some service providers display a progress dialog box if the validation is expected to take a long time - an optional, but helpful feature.

One of the properties of the status object, PR_RESOURCE_METHODS, indicates which of these IMAPIStatus methods are supported. PR_RESOURCE_METHODS is a bitmask; there is one bit that corresponds to each of the IMAPIStatus methods. When the bit for a particular method is set, that method is operational. Clients check the value of the PR_RESOURCE_METHODS property to determine which of the IMAPIStatus methods are fully implemented for a particular status object before making calls.


 About Status Object Properties

The following table lists all of the required properties associated with a status object. All of these properties appear in the status table.

PR_DISPLAY_NAME	PR_ENTRYID
PR_IDENTITY_DISPLAY	PR_PROVIDER_DLL_NAME
PR_IDENTITY_ENTRYID	PR_RESOURCE_FLAGS
PR_IDENTITY_SEARCH_KEY	PR_RESOURCE_TYPE
PR_INSTANCE_KEY	PR_ROWID
PR_OBJECT_TYPE	PR_STATUS_CODE
PR_PROVIDER_DISPLAY	PR_STATUS_STRING
Status object implementors can also, as an option, provide the PR_STORE_RECORD_KEY property.

The PR_RESOURCE_TYPE property indicates the type of MAPI component, or resource, that has implemented the status object. The values used to set PR_RESOURCE_TYPE are the following constants:

MAPI_AB	MAPI_STORE_PROVIDER
MAPI_AB_PROVIDER	MAPI_SUBSYSTEM
MAPI_PROFILE_PROVIDER	MAPI_TRANSPORT_PROVIDER
MAPI_SPOOLER
The PR_RESOURCE_METHODS property is used to indicate which of the IMAPIStatus methods have full support for a particular status object. The property consists of a bitmask - one bit for each method. If the bit for a method is set, an implementation for the method exists and can be called. If the bit for the method is not set, the implementation, if called, will return MAPI_E_NO_SUPPORT.

The PR_RESOURCE_FLAGS property is a common property that describes many objects, among them the status object. There are several flags that apply only to status objects. For example, the STATUS_DEFAULT_STORE flag is meaningful for message store providers. If set, it indicates that this message store operates as the default message store. Conversely, STATUS_NO_DEFAULT_STORE indicates that a message store cannot be a default store.

The STATUS_PRIMARY_IDENTITY and STATUS_NO_PRIMARY_IDENTITY flags can be used to indicate whether or not a service provider supplies identity information for the session. If STATUS_PRIMARY_IDENTITY is set, the entry identifier stored in the PR_IDENTITY_ENTRYID property for this status object is the primary identity for the session.

Other flags include STATUS_DEFAULT_OUTBOUND, STATUS_OWN_STORE, STATUS_SIMPLE_STORE, STATUS_TEMP_SECTION and STATUS_XP_PREFER_LAST.

All status objects can set the PR_STATUS_CODE property to STATUS_AVAILABLE, STATUS_OFFLINE, or STATUS_FAILURE. STATUS_AVAILABLE indicates that the service provider or MAPI resource is operational. STATUS_OFFLINE indicates that only local data or services are available. STATUS_FAILURE indicates problems. When STATUS_FAILURE is set, the service provider may soon be shut down, ending the current session.

Transport providers can also set PR_STATUS_CODE to:

STATUS_INBOUND_ACTIVE	STATUS_OUTBOUND_ACTIVE
STATUS_INBOUND_ENABLED	STATUS_OUTBOUND_ENABLED
STATUS_INBOUND_FLUSH	STATUS_OUTBOUND_FLUSH
The inbound flags relate to the transport's ability to receive messages and the actions it can take on those messages. The outbound flags relate to the sending of messages. The ENABLED setting indicates that a transport provider can deliver messages to or accept messages from the MAPI spooler. The ACTIVE setting indicates that a transport provider is currently receiving or sending a message. The FLUSH setting relates to "foreground" message reception and transmission.


 Considerations for Service Providers

This chapter discusses topics that should apply to most, if not all, types of service providers. Starting with a brief description of the types of files that service providers support, the chapter continues with a discussion of issues pertaining to message service design and configuration. The next section involves session start up and shut down and the tasks that all service providers must perform. Details specific to one or more types of service providers are covered in the chapters that relate to the particular service provider. The last group of sections describe a variety of tasks that are common to all service providers, such as construction of entry identifiers, sending event notifications, and validating parameters.


 Guidelines for Service Providers

Each service provider should have three header files: one public header file and two internal files. The public header file should be used for configuration and for documenting properties and their values. One of the internal header files should include all necessary public MAPI headers and should be shared by all of the service provider source files. The other internal file should define resource identifiers.

Executable file names for service providers should not exceed six characters. This is to allow a suffix to be appended to the end of the name to identify the platform.


 Implementing a Message Service

Message services, as defined previously, are groupings of one or more related service providers that share installation and configuration code. Service providers can choose to remain as standalone providers, as single-provider message services, or can become members of multiple provider message services. Some of the sample service providers in the MAPI SDK operate as single-provider services. MAPI recommends that all service providers be associated with a message service to make installation and configuration easier for the users of their client applications.

When you implement a message service, you need to create a simple setup program to install the service providers that belong to the service and some software for configuration support. The amount and complexity of the configuration software you will need depends on your message service. The following sections offer suggestions for designing a message service and information about creating the software required to support installation and configuration.


 Message Service Design

There are several issues involved with designing message services. First, decide how many service providers will be included in the service. Message services can include either one provider or several. The guideline is that if the message service has multiple providers, these providers should be related in some way. This guideline exists to prevent a provider DLL from being arbitrarily added to an existing message service. The existing service cannot be expected to have all of the information that it needs to configure the new provider and without this information, the provider might not work. To properly integrate the new provider, the service would have to reverse engineer the provider's configuration information and rewrite a great deal of the service configuration code.

An alternative to integrating unrelated providers in a message service is adding them to a profile. For example, suppose your default profile contains a message service with a transport provider and a message store, and you would like to add the capabilities provided by the MAPI SDK sample personal message store. Rather than integrating the sample store into your service, potentially causing problems, add it to your default profile. MAPI will handle the integration.

The other issues involve the organization of the one or more DLL files that are to be used for the message service. Message services can be implemented in one or more DLLs. To simplify coding, installation, and configuration, it is recommended that message services use a single DLL. However, this is not a requirement. Some services use one DLL for message service-specific code and one DLL for each of the providers in the service.

Other services share a DLL. Only related services, or services that have something in common, such as the need to share database code, should share a DLL. If you are planning to implement a message service with another service in the same DLL file, remember that each entry point function in the DLL must have a unique name and that a single DLL cannot include two or more providers of the same type. A single DLL cannot include two or more providers of the same type. That is, only one message store provider, one transport, one address book, and one hook is allowed per DLL. This restriction is because MAPI stores only one entry point per provider type. If your service must include multiple providers of one type, either have them share an entry point or reside in separate DLLs.

The message service DLL can be given any name that is six characters or less. The six character restriction is enforced to allow MAPI to concatenate characters onto the end of the filename to indicate the target platform. If the DLL runs on a 32-bit platform, the characters "32" are concatenated onto the filename; if the DLL runs on a 16-bit platform, nothing is concatenated and the filename remains as originally named. A similar convention applies to provider DLL names.

For example, suppose you build two versions of a message service called TEST, one for a 16 bit platform and the other for a 32 bit platform. The TEST service has one provider that resides in its own DLL, MYAB. The 16 bit versions of the DLLs would be called TEST.DLL and MYAB.DLL while the 32 bit versions would be called TEST32.DLL and MYAB32.DLL.

The message service setup program writes the names of the service and provider DLLs into the MAPISVC.INF file so that they are available for MAPI to use for loading. The message service DLL file is specified using the PR_SERVICE_DLL_NAME property and each provider DLL file is specified using the PR_PROVIDER_DLL_NAME property. Only the base file name and extension is included in MAPISVC.INF.


 Message Service Installation

The first step towards implementing a message service involves creating a setup program for installation. The setup program copies the files that make up your service, such as the provider DLLs, to the local drive, creates a default profile, and adds entries to the MAPISVC.INF and WIN.INI files. Depending on the state of your workstation, MAPISVC.INF may already exist. You can use the MERGEINI utility to append your entries, held in a temporary file, to the existing MAPISVC.INF file. Invoke MERGEINI as follows:

MERGEINI C:\MAPI\TMP.INI -m -q

The easiest way to create a default profile is to invoke one of MAPI's configuration applications, either the Profile Wizard or the Control Panel applet. However, there are no set rules. Setup programs can choose not to involve the user in the process at all by creating the profile programmatically. When you create the profile, make sure that you do not store anything that would be hard or impossible to recreate. Profiles are considered an expendable part of the MAPI architecture. There are no utilities for profile recovery, for moving profiles from one machine to another, for off-line backup, or for individual or global restoration from backup copies. If your profile is password-protected and a user loses the password, the profile must be deleted and a new profile created to take its place.

The entries that you add to MAPISVC.INF are made up of required and optional configuration properties that relate to the message service and its service providers. The required properties include the names of the DLL files in the service and the name of the configuration entry point function for the service.

If your message service is a single provider service, it is wise to store all of entries in the provider section in MAPISVC.INF. Accessing the provider section is faster and more direct. If your message service is a multiple provider service, store the entries in the service section. Since all of the service providers in your service will need access to the same information, it is better to have it in one place. Having one copy eliminates the problem of keeping multiple copies in sync and saves space.

Do not store any passwords or other credentials that require extra protection in MAPISVC.INF. Instead, either do not store them at all or store them as secure properties in the profile. When passwords are not kept in the profile, the user must enter them with every logon. Storing passwords as secure properties in the profile provides the additional protection that passwords require, such as encryption, and makes logging on easier for users.

The entries that are added to the WIN.INI file specify non-default settings for standard MAPI components, such as the DLL files that contain the standard MAPI user interface and profile provider. If your message service intends to use the standard MAPI components, your setup program need not modify the WIN.INI file.

Refer to the MAPI Programmer's Reference for details about the specific MAPISVC.INF and WIN.INI entries to include in your message service setup program.


 Message Service Configuration

Supporting the configuration of a message service involves writing at least one entry point function, publishing the name of that function in the MAPISVC.INF file, and creating one or more property sheets for showing configuration data. MAPI's Control Panel applet and other configuration clients make a call to this entry point function to display the property sheets. If message services want to also support the Profile Wizard, there are three additional requirements: another entry point function, a standard Windows dialog procedure, and an enhanced message service entry point function.

The following sections describe how to create these entry point functions, the Profile Wizard dialog procedure, and the configuration property sheets.

Creating a Message Service Entry Point Function

The message service entry point function manages service and provider profile data and handles configuration requests from MAPI and client applications. Creating an entry point function is not required, but it is strongly recommended. Without it, MAPI will run, but your service or your service's users will need to perform extra tasks to make up for its absence. For example, a message service that does not store anything in the profile for security reasons would not need an entry point function. However, because MAPI needs access to configuration data to load the service, the user must be required to enter all of the data with every logon.

Message service entry point functions can provide support for interactive configuration, programmatic configuration, or both. As a minimum, these functions are expected to be able to store and retrieve properties from the profile sections that are associated with the message service. Interactive configuration involves the display of one or more property sheets - at least one for the message service and optionally one for each configurable service provider in the service.

Programmatic configuration involves using an array of property values to change configuration options and publishing information about these properties in a public header file. The header file contains property tags and valid settings for each property in the array. For example, the following header file specifies two properties for a fictional message service - one to define a file and the other to uniquely identify the service:

/* Property tag definitions   */

#define PR_MY_FILE	PROP_TAG(PT_TSTRING, 0X6604)

#define PR_MY_UID	PROP_TAG(PT_BINARY, 0X6601)

/*

*  PR_MY_FILE is the full path name of the file for my address list.

*

*  PR_MY_UID is the unique identifier for my service. If you run

*  multiple instances of my service, each instance must have different

*  PR_MY_UIDs.

Programmatic configuration is important because it enables message service implementors that are writing special installation programs to configure their service in a totally automated fashion. If your message service will support MAPI's Profile Wizard application, programmatic configuration is required. If your message service does not support the Profile Wizard, programmatic configuration is optional.

All message service entry point functions use the MSGSERVICEENTRY prototype defined by MAPI as follows:

HRESULT (STDAPICALLTYPE MSGSERVICEENTRY)
     (HINSTANCE hInstance, LPMALLOC lpMalloc, LPMAPISIP lpMAPISup,
      ULONG ulUIParam, ULONG ulFlags, ULONG ulContext, ULONG cValues,
      LPSPropValue lpProps, LPPROVIDERADMIN lpProviderAdmin,
      LPMAPIERROR FAR * lppMapiError)

Message service entry functions receive pointers to a support object, an OLE style allocator, a provider administration object, a set of option flags, and an array of property values. Your entry point function will typically be invoked after your caller, MAPI or a configuration client, has performed or is in the act of performing some operation. The particular operation will be told to you in the ulContext parameter.

There are seven different operations, each represented by a constant. Depending on the operation and your service, the entry point function might perform extensive processing or merely return S_OK. Two operations that usually require very little work are the MSG_SERVICE_INSTALL and MSG_SERVICE_UNINSTALL operations. The ulContext parameter will be set to MSG_SERVICE_INSTALL after your caller has run the installation program provided by your message service. The entry point function can either return immediately with S_OK or can perform any necessary post-installation processing.

When ulContext is set to MSG_SERVICE_UNINSTALL, typically the user has selected an option on a dialog box to remove your message service from the workstation. By the time the entry point function is called, either the user has finished removing your service or has canceled the removal. If the removal completed successfully, your entry point function can delete any message service-related files or data. If the removal was canceled, query the user to make sure that the choice to cancel was intentional, and, if so, return MAPI_E_USER_CANCEL.

The other operations fall into two categories: operations that apply to a profile that contains or will contain your message service and operations that apply to your message service. The MSG_SERVICE_CREATE, MSG_SERVICE_CONFIGURE, and MSG_SERVICE_DELETE operations apply to a profile. With MSG_SERVICE_CREATE, your message service is being added to a profile. With MSG_SERVICE_CONFIGURE, your message service is being configured; one or more of the entries in the profile might change. Your implementation of the create and configure operations will depend on the settings of the flags parameter, ulFlags. These flags influence whether a user interface should be involved in the operation, which is sometimes a requirement. The SERVICE_UI_ALWAYS flag indicates that the user always wants a user interface. If this flag is not set during message service creation, your entry point function should fail.

The handling of the MSG_SERVICE_CONFIGURE operation is more complicated. If the lpProps parameter contains enough data to successfully configure the service, or if neither the SERVICE_UI_ALWAYS or SERVICE_UI_ALLOWED flags are set, your entry point function should complete the configuration programmatically if it can and not display any user interface. However, if SERVICE_UI_ALLOWED is set and lpProps is either empty, contains insufficient data, or your entry point function is not written to handle programmatic configuration, you should display a dialog box to allow the user to handle the configuration.

The ulContext parameter is set to MSG_SERVICE_DELETE when your message service is removed from a profile. Deletion occurs on a per-instance basis − other instances of the service either in the same profile or a different profile are unaffected and the service can still be added to profiles. Your service entry function should handle this call by returning immediately with a success code.

When a service is copied, MAPI does not make a call to your entry point function. The configuration settings remain as they were in the original service.

The last two values for ulContext, MSG_SERVICE_PROVIDER_CREATE and MSG_SERVICE_PROVIDER_DELETE, are specified when your caller is trying to add a service provider to your message service or delete a service provider from your message service. Not all message services support this functionality. If your service does not provide this support, return MAPI_E_NO_SUPPORT. If your service does provide this support, use the IProviderAdmin pointer passed into the call in the lpProviderAdmin parameter to call either the CreateProvider or DeleteProvider method.

Note  Do not call MAPIInitialize or MAPIUninitialize in your entry point function. This can lead to a possible deadlock situation. Since both MAPI and OLE may start threads.

Creating Property Sheets

Property sheets can be created using the Windows 95 property sheet API or with a display table. The display table route spares you from having to work with the Windows user interface, reducing your development time.

Creating a Profile Wizard Entry Point Function

The Profile Wizard calls your Profile Wizard entry point function to retrieve information to be displayed in its user interface. This entry point function follows the SERVICEWIZARDENTRY prototype, as is defined below:

ULONG (STDAPICALLTYPE SERVICEWIZARDENTRY)
(HINSTANCE hProviderDLLInstance, LPCSTR *lpcsResourceName,
FARPROC *lpDlgProc, LPMAPIPROP lpMAPIProp);

The Profile Wizard passes in a pointer to an IMAPIProp interface implementation. This property object provides access to all of the configuration properties. There are two output parameters: a dialog box resource and a pointer to your dialog procedure. You should keep a reference to your IMAPIProp implementation handy while the configuration user interface is visible.

Your Profile Wizard entry point function typically displays a single dialog box resource that may contain multiple dialog boxes within it. This resource includes all of the controls for all of the property pages. When called, the function reveals only the controls for the current page. As the Profile Wizard moves from page to page, your function must hide all of the controls for the old page and expose the controls for the new page.

Creating a Profile Wizard Dialog Procedure

The Profile Wizard dialog procedure is a standard Windows procedure that functions as a callback invoked by the Profile Wizard. This dialog procedure handles the events that occur during the display of your property pages.

The Profile Wizard creates a dialog frame with three buttons (Back, Next or Finish, and Cancel) and a fixed size area into which you display your dialog. Any Windows messages or events that occur within this fixed area will go directly to your Profile Wizard dialog procedure.

Make sure that your property pages are always available because it is possible for the Profile Wizard to proceed in either a forward or backward direction, generating a WM_INITDIALOG message more than once. However, because the Profile Wizard is a single instance application, your dialog procedure does not have to be prepared to display multiple instances of itself. Information can be safely stored in static variables.


 Common Entry Point Functions and Methods

Service providers, regardless of their type, implement an entry point function into their DLL, and two interfaces, one for initialization and the other to control the logon session. The interfaces are named according to the type of service provider implementing them. The suggested names for the entry point functions for the types of service providers differ to allow one DLL file to contain any combination of service providers. However, because the entry point function is a prototype, these names may be selected by the service providers. The following table lists the functions as they are defined and the two interfaces:

Type of Service Provider	DLL Entry Point Function	Provider  Interface	Logon  Interface
Address book	ABProviderInit	IABProvider	IABLogon
Message store	MSProviderInit	IMSProvider	IMSLogon
Transport	XPProviderInit	IXPProvider	IXPLogon
The DLL entry point function performs three tasks. It checks the version of the service provider interface to make sure MAPI is using a version that is compatible with the version that you are using, initializes some global variables, and instantiates a provider object. A pointer to that object is returned for MAPI's use.

The implementations of the provider and logon interfaces across providers is not identical, but similar. All providers include in their provider object a method for logging on and for shutting down. The message store provider adds two other methods - one for spooler logon and one to compare message store identifiers.

The logon object, however, is less similar across providers. The address book and message store logon objects resemble one another in that they share a common set of methods, the address book provider adding a few more methods. The greatest difference lies in the transport provider's implementation. The IXPLogon interface includes only one method, OpenStatusEntry, that is part of the other two logon interfaces. All of the other transport logon object methods are unique to transport providers.

To give you an idea of the range of difference between the number and type of methods in each of these service provider interfaces, the following table lists the methods for each:

Object	Address Book Provider	Message Store Provider	Transport Provider
Provider (IxxProvider interface)	Shutdown, Logon	Shutdown, Logon, SpoolerLogon, CompareStoreIDs	Shutdown,  TransportLogon
Logon (IxxLogon interface)	GetLastError, Logoff, OpenEntry, CompareEntryIDs, Advise, Unadvise, OpenStatusEntry, OpenTemplateID, GetOneOffTable, PrepareRecips	GetLastError, Logoff, OpenEntry, CompareEntryIDs,  Advise, Unadvise, OpenStatusEntry	AddressTypes, Idle, RegisterOptions, TransportNotify, TransportLogoff, SubmitMessage, EndMessage, Poll, StartMessage, OpenStatusEntry, ValidateState, FlushQueues


 DLL Entry Point Function

MAPI begins the process of starting your service provider by looking in the profile to locate the name of your DLL file. All service providers are required to register their DLL file name in the profile. After calling the Windows API function LoadLibrary to launch your service provider DLL, MAPI calls your DLL entry point function. MAPI can call LoadLibrary each time it uses the DLL, regardless of whether it is already loaded, or MAPI can remember internally which DLLs are loaded and only load DLLs when necessary. In either case, MAPI does the appropriate number of FreeLibrary calls when it is done with the DLL.

The DLL for a service provider can have additional functions beyond those necessary for MAPI support. For example, a message system might include administration functions in the same DLL. Such external uses should call LoadLibrary before using code in the DLL and eventually FreeLibrary to remove the DLL from memory after use. Do not count on MAPI keeping the DLL in memory for such functions.

When your DLL entry point function completes, your service provider has been configured and loaded and has identified itself to MAPI. MAPI makes this call at different times depending on the type of service provider and the type of client. When Simple MAPI clients, for example, call MAPILogon to begin a session, the default address book and message store providers are automatically started. Address book and message store providers that are used by Extended MAPI clients are started after the logon process, when explicit calls to the session object are made. Clients call IMAPISession::OpenMsgStore to load a message store provider and IMAPISession::OpenAddressBook to load the integrated address book. Transport providers are not loaded until they are needed to handle the submission or receipt of a message.

A DLL entry point function has two main tasks: to check the version of the service provider interface (SPI) that MAPI is using against your version and to create a provider object. This function has a lengthy parameter list which is the same for every service provider entry point function. For example, the ABPROVIDERINIT prototype for address book providers is defined as follows. Notice that the name of the returned provider object is tailored to the type of service provider; the other entry point functions use lppMSProvider or lppXPProvider, depending on their type.

HRESULT ABProviderInit (STDMAPIINITCALLTYPE ABPROVIDERINIT)
(HINSTANCE hInstance, LPMALLOC lpMalloc,
 LPALLOCATEBUFFER lpAllocateBuffer, LPALLOCATEMORE lpAllocateMore,
 LPFREEBUFFER lpFreeBuffer, ULONG ulFlags, ULONG ulMAPIVer,
 ULONG FAR *lpulProviderVer, LPABPROVIDER FAR *lppABProvider)

As with the message service entry function, the DLL entry point function receives an OLE allocator, the MAPI allocators, and a set of flags. The other parameters are specific to the this entry point function. First, MAPI includes the number of your SPI version and the number of MAPI's version. Service provider interface version checking allows the service provider interface to expand to meet future requirements, while maintaining as much forward and backward compatibility as possible between software made by different companies at different times. The burden of compatibility checking is placed on the software with the higher version number, as it is the one that knows the capabilities of both versions.

The MAPI header files declare CURRENT_SPI_VERSION as the latest version of the SPI. If your version, passed in the lpulProviderVer parameter, is the same or lower than the version of the interface that MAPI passes in, the version check should succeed. However, if you are using a less recent version, you should fail the call, returning MAPI_E_VERSION. This way MAPI and service providers jointly define the range of SPI version numbers they can handle, and if nothing matches, then service provider start up fails. In the MAPI 1.0 timeframe this is of little practical use, but in future versions of MAPI it will be more useful.

MAPI's version information is a 32-bit unsigned integer broken into three parts:

•	Bits 31-24 are major version byte.

•	Bits 23-16 are a minor version byte.

•	Bits 15-0 are a minor minor version word.

The version of the provider interface documented in the MAPI header files is always known as CURRENT_SPI_VERSION, whose value changes from time to time. Knowing multiple version numbers is useful for service providers that choose to support more than one version of the MAPI SPI.

Microsoft periodically changes and releases for external users major and minor numbers. Micro version number is used internally to Microsoft, and should be zero in all external versions of the interface.

The last parameter in the DLL entry point function is an output parameter - a pointer to a provider object's IXXProvider interface implementation. The DLL entry point function must create one of these objects and return a pointer to it in this last parameter. MAPI uses the provider object throughout the session for routing requests from the client.


 Service Provider Logon

When your DLL entry point function returns, MAPI uses the provider object to call its logon method. The logon method is called Logon for address book and message store providers and TransportLogon for transport providers. These methods are defined for the three provider types as follows, with the address book provider version appearing first.

HRESULT Logon (LPMAPISUP lpMAPISup, ULONG ulUIParam,
LPTSTR lpszProfileName, ULONG FAR *lpulFlags,
ULONG FAR *lpulcbSecurity, LPBYTE FAR *lppbSecurity,
LPMAPIERROR FAR lppMAPIError, LPABLOGON FAR *lppABLogon)

HRESULT Logon (LPMAPISUP lpMAPISup, ULONG ulUIParam,
LPTSTR lpszProfileName, ULONG cbEntryID, LPENTRYID lpEntryID,
ULONG FAR *lpulFlags, LPCIID lpInterface,
ULONG FAR *lpcbSpoolSecurity, LPMAPIERROR FAR lppMAPIError,
LPMSLOGON FAR *lppMSLogon, LPMDB FAR *lppMDB)

HRESULT TransportLogon (LPMAPISUP lpMAPISup, ULONG ulUIParam,
LPTSTR lpszProfileName, ULONG FAR *lpulFlags,
LPMAPIERROR FAR lppMAPIError, LPXPLOGON FAR *lppXPLogon)

Notice that some of the parameters are the same across all three prototypes. Every method receives a pointer to a support object, for example. The implementation of this support object varies, depending on which type of provider you are. MAPI provides three different implementations of IMAPISupport, each one tailored to the specific type of service provider. Therefore, if you are an address book provider, for example, you will get a support object that includes implementations of the GetOneOffTable, Address, and Details methods but not the ReadReceipt and PrepareSubmit methods. These latter two methods are included for a message store provider support object.

All logon methods also receive the name of the current profile, a window handle, and a set of flags as input parameters and pass back as output parameters a pointer to a MAPIERROR structure for extended error information and a pointer to a newly created logon object. The other parameters are specific to the type of provider. For information about the portions of the logon method that are provider type-specific, refer to the chapters that relate to programming that type of provider.

One of the basic tasks performed by every logon method is to increment the reference count on the support object. It is critical that you increment the support object's reference count by calling IMAPISupport::AddRef.  If this step is omitted, MAPI will release the support object and unload your service provider.

Checking the Configuration

Another task involves verifying your provider's configuration. Verifying configuration involves checking the settings for options that are required for your provider to operate successfully. The particular settings that you check depends on your service provider. For example, a message store provider might need to locate its message store, check credentials, and register a row in the status table.

You can retrieve configuration settings for your service provider from the profile by calling IMAPISupport::OpenProfileSection. If the profile does not contain all of the settings that your service provider requires, in some cases you can display a user interface to ask. the user to supply the necessary information.. Whether or not you can display a user interface depends on the value of the flags passed in with the call. If a user interface is not permitted or the user cannot supply the information, your service provider cannot be configured and you should return MAPI_E_UNCONFIGURED. A slight variation to this problem occurs when the user cancels the configuration dialog box. In this case, return MAPI_E_USER_CANCEL rather than MAPI_E_UNCONFIGURED.

When you return MAPI_E_UNCONFIGURED, MAPI calls your DLL entry point function again, asking it to locate the required information. If the information can be located, MAPI will call your logon method again. A user interface is never allowed on this second call; all of the necessary data must be passed in. If the information cannot be located, depending on how important your service provider is, the session may terminate.

Registering a Unique Identifier

Every logon method creates a logon object and returns a pointer to that object. MAPI identifies each logon object with a unique identifier, or UID, that is registered as part of the logon method implementation. The UID represents a service provider and is contained within the entry identifier for every object that the service provider owns. MAPI uses the MAPIUID to route calls to the correct provider.To register a UID, providers call IMAPISupport::SetProviderUID in the logon method. Most service providers define a static constant.

Some providers register one UID; others register several. Because a single provider can have several logon objects active concurrently, it is recommended that if your service provider can instantiate multiple logon objects, register a unique identifier for each one. This increases the accuracy with which MAPI matches entry identifiers to service providers and saves you some work . When every logon object has its own unique identifier, MAPI can guarantee that any request it routes a logon object can be handled by that object. When logon objects share UIDs, MAPI routes the request to the first instance of the UID it finds. If, in this case, the logon object receiving the request determines that it cannot process the entry identifier, it should pass the request on to the service provider's next logon object before returning an error. If your service provider has only one logon object, or none of the logon objects can service the request, then an error return is in order.


 Constructing Entry Identifiers

A service provider uses a piece of binary data known as an entry identifier to refer to one of its object. In the Address Book, for instance, entry identifiers are used to identify mail users, distribution lists, and containers. To clients and other service providers, entry identifiers are just binary data. Only the service provider that has assigned the identifier understands what is inside.

Entry identifiers come in two types: short-term and long-term. Short-term entry identifiers can be generated quickly, but their uniqueness is guaranteed only over the life of the current session on the current workstation. Short-term entry identifiers are used in tables. There are two types of long term identifiers: temporal and positional. Entry identifiers that last over time are known as temporary identifiers. Entry identifiers that last across computer workstations are known as positional. The only entry identifiers that are both temporary and positional are the identifiers created for custom recipients.

The ENTRYID data structure is used to define an entry identifier. ENTRYID data structures contain an array of flags that describe the identifier and the binary data. The data is made up of a 16 byte MAPIUID field that represents the service provider and a variable amount of other data that is specific to the object. The ENTRYID structure is defined as follows:

typedef struct {

BYTE   abFlags[4];

BYTE	   ab[MAPI_DIM];

} ENTRYID, FAR *LPENTRYID;

The first 4-byte flags, of which the last three bytes must be zero, describe the type and use of the entry identifier. For example, the value MAPI_THISSESSION indicates that the entry identifier cannot be used to identify objects belonging to other sessions and MAPI_SHORTTERM indicates that this identifier is a short term entry identifier. If you are constructing a long term identifier, these flags must be clear. Clients expect to be able to check the first byte to determine the entry identifier's longevity. A zero indicates a long term identifier and a non-zero indicates a short term identifier.

The next 16 bytes make up a MAPIUID structure that identifies the service provider responsible for creating the entry identifier. When an application calls an OpenEntry method, MAPI uses the MAPIUID to determine which service provider DLL to call. The MAPIUID structure contains a type order independent entry identifier. If you are using a profile that must work on two different processors, each with a different byte order, use the MAPIUID structure to describe items.

An updated version of a service provider DLL should use the same MAPIUID as the previous version. Since a message saved in the message store has the entry identifier of the sender stored with it, keeping the same MAPIUID allows a user to reply to a message received months earlier when the user had an earlier version of the provider DLL.

The rest of the ab member contains anything that makes sense for your provider. Because a service provider has to be forward and backward compatible with itself, one of the items that makes sense for many providers is version information. Many providers change the format of their entry identifiers from version to version. By storing a version indicator, you can quickly determine the format to use for deciphering any particular entry identifier.

Another helpful piece of information for many providers is an indicator, or hint, of how to locate the object represented by the entry identifier. For example, you could store the disk offset for the last place an entry was stored in a data file. Because hints are only valid for a limited period of time (say, between compresses of a global tree structure that happens only after 128 people are removed from the tree), the entry identifier would also need enough data to determine if the hint is still valid, and to locate the entry even if the hint is out of date. Because hints can change with time, two entry identifiers obtained at different times for the same entry can have different binary values. Call the CompareEntryIDs methods found on many objects to determine if two entry identifiers actually refer to the same object.

Whenever a user changes names or moves to a different machine, keep long term identifiers constant. The more far-reaching an identifier is, the more valid it is. For cross-platform operation, such as use on different byte order machines, you might choose to store all of your entry identifier data in a particular byte order and have the software on one platform always swap bytes. Alternatively, you could choose to indicate the byte order by encoding the format in the entry identifier, and write code on both machines for handling data in either byte order.

If you create entry identifiers that change whenever a move or modify operation is performed, generate notifications to inform clients of these events.


 Supporting Notifications

Support for notifications, although common and very useful, is entirely optional. If you are writing a message store or address book provider, mostly likely you will support table notifications for your contents and hierarchy table implementations and notifications on one or more of your other objects. Transport providers typically rely on the MAPI spooler to generate notifications for events that they produce. You can handle the work of keeping track of the registrations and sending the necessary notifications within your advise source objects or you can take advantage of functionality MAPI provides. The IMAPISupport interface contains three methods that can help service providers implement notification support: Subscribe, Unsubscribe, and Notify.

Remember that clients call the Advise method of an advise source object to register for notifications and Unadvise to deregister. To use the IMAPISupport notification methods, create a notification key, or NOTIFKEY data structure, from the entry identifier representing the advise source object. The notification key is binary data that is used by MAPI to identify an advise source object across processes. Pass this key to IMAPISupport::Subscribe in your Advise implementation. Subscribe will call IMAPIAdviseSink::AddRef, enabling MAPI to hold onto the advise sink pointer until the Unadvise call is made, before returning with a non-zero connection number that you can pass back to the advise sink. You can release the client's advise sink at any time after the Advise call. However, this is not true of the connection number. You need to wait until the client makes the Unadvise call before you release the connection number.

When it is time to send a notification, pass your notification key and an array of notification structures containing event data in a call to IMAPISupport::Notify. Service providers make one call for every advise source for which an event has occurred. This might seem like a lot of calls, but calls to Notify are not time consuming. If there are no registered advise sinks for the event, Notify ignores the call. When you initialize your notification structures, set all unused members to zero to help clients create smaller, faster, and less error-prone OnNotify implementations. For information about how to fill in the individual notification data structures, see the MAPI Programmer's Reference.

Service providers can send notifications at any convenient time; there are no rules as to their timing. This can result in clients receiving notifications for events as they are occurring, after they have occurred, or sometimes before they have occurred. It is also possible for clients to receive notifications from an advise source after they have called Unadvise to remove their registration.

Notifications on messages are sent either when changes are saved or when the message object is released. Until the notification is sent, no changes are visible in the message store. Note that anyone involved in the session can make changes that cause a notification to be sent: the MAPI subsystem or any client application. Calling the Unadvise method on the object that previously received your Advise call does not necessarily guarantee that you will no longer get notified by this object. Be careful in your notification callback.

When advise sinks call your Unadvise method, forward the call on to MAPI's Unsubscribe method in the support object. MAPI will free the advise sink object at this time by calling its Release method. Y

Notifications are almost always asynchronous. MAPI does not disallow synchronous notification, however, and service providers who want to implement their notifications synchronously are free to do so. However, all advise sinks, including MAPI, expect asynchronous notification and have no way to request otherwise.


 Supporting Status

The status table is a way for service providers to expose status and other dynamic information to clients. Supporting the status table is an option for address book and message store providers; for transport providers it is a requirement. Transport providers must support the following three status table operations:

•	creating a row in the table

•	updating a row in the table

•	providing information to clients about data not stored in the status table row

To add a row to the status table, pass an array of property value structures in a call to  IMAPISupport::ModifyStatusRow. This call is typically made when your service provided is loaded. The property value structures are used to define the columns to be maintained for your row.

When one of the properties that are included in your row is modified, you must update the status table so that MAPI can notify all interested clients of the change. Updating the status table is accomplished with a call to IMAPISupport::Notify.

Service providers are required to include several properties in the property value array that they pass to ModifyStatusRow. Beyond this required set, other properties can be included. Including additional properties in a status table row is optional and up to the provider.

The basic set of required properties are:

PR_DISPLAY_NAME	PR_ENTRYID
PR_IDENTITY_DISPLAY	PR_IDENTITY_ENTRYID
PR_INSTANCE_KEY	PR_OBJECT_TYPE
PR_PROVIDER_DISPLAY	PR_PROVIDER_DLL_NAME
PR_RESOURCE_FLAGS	PR_RESOURCE_METHODS
PR_RESOURCE_TYPE	PR_ROWID
PR_STATUS_CODE	PR_STATUS_STRING
There are two ways for clients to access a service provider's status object. One of the ways is through the logon object's OpenStatusEntry method. OpenStatusEntry exists in every service provider's logon object. If you support a status object, you will return a pointer to it when your OpenStatusEntry method is called.

The other way is for clients to call IMAPISession::OpenEntry with an entry identifier from the status table that represents your status object. MAPI will route the call to the logon object belonging to the provider that owns the entry identifier by invoking the OpenStatusEntry method. If you are passed the MAPI_MODIFY flag, you are being asked to return an object with read-write access. This is only a suggestion; if you do not allow status object modification, you can return a read-only object.


 Using the MAPI Idle Functions

The idle engine is a set of API functions that service providers can use for making the best use of idle time. You create a callback function that contains whatever tasks you feel should occur when the MAPI subsystem is idle. When MAPI detects idle time, it invokes this callback function. The callback function follows the FNIDLE prototype, as defined below:

BOOL (STDAPICALLTYPE FNIDLE) (LPVOID lpvContext)

Use the FtgRegisterIdleRoutine to register your callback function with MAPI. The input parameters include an optional priority, a block of memory that is passed to your callback function as input, an amount of time to be used as the service provider sees fit, and a set of option flags.

You can specify a priority in the priIdle parameter that controls how your idle function runs or specify zero if priority is not an issue. Compression or searches should be assigned negative priorities. Tasks that occur once should be assigned positive priorities.

There can be more than one idle function during a session. If you want to rank your idle routines, use positive numbers.

On 32 bit systems, your callback function may be called back on a different thread than the one you used for registering it.

The DeregisterIdleRoutine function allows you to deregister a callback function that is active. Realize that the callback function could be invoked at any time during the deregister call, even if DeregisterIdleRoutine has returned. This is because DeregisterIdleRoutine is an asynchronous operation.

The ChangeIdleRoutine function modifies some or all of the characteristics of a callback function. The characteristics that can be modified include the function itself, and/or its priority, time setting, input parameter, and any of the options set with the flags parameter.


 Using Structured Storage

Any service provider that accesses large properties needs to use the structured storage interfaces defined initially by OLE. The IStorage interface provides high level access to a structured block of storage and the IStream interface performs the low level tasks, such as reading and writing bytes from the storage.

Most likely only message store providers will ever need to implement one of these interfaces, typically IStream. Because attachments are usually large files or objects themselves, they cannot be managed using the GetProps and SetProps methods in the standard property object. Attachments require the use of streams.

If your attachment is a file and you want to provide access to it using the methods defined for IStream, call OpenStreamOnFile. This function allows you to access the file through a newly created stream object.

To create a storage object that implements the IStorage interface and works with an implementation of either IStream or another OLE storage interface, ILockBytes, call the MAPI API function HrIStorageFromStream.  MAPI will create a storage object that operates with the lower level storage interface.

Because the IStorage methods return OLE error values, you will need to call MapStorageSCode to translate these values into MAPI error codes.

If your attachment is a message, and you have a readable storage object available, you can call IMAPIProp::OpenProperty to open the attachment with a source interface of IID_IMessage. This will result in your getting a message object. Then you can call OpenIMsgOnIStg to layer this message object on top of a storage object.

The OpenIMsgOnIStg function allows you to specify a callback that is invoked by the new message object when its reference count becomes zero. This can be useful if there is some final processing that needs to be done before the message is completely removed.

This technique is useful when you want to embed a message in an OLE compound document or create a message from arbitrary data in the file system. To accomplish the latter goal, producing a message from data in the file system, first call the OLE helper function CreateDocfile to create a storage object. Next pass a pointer to the storage object to OpenIMsgOnIStg. OpenIMsgOnIStg creates a message object that accesses its properties using the IStorage methods.

The message object that you get back from this scenario is different than the message object that is created by message store providers. You cannot use this message object in calls to IMsgStore interface methods, for example, such as IMsgStore::SubmitMessage.


 Developing a Transport Provider

This chapter describes the transport provider's role in the MAPI message system and describes the implementation details necessary to develop features common to all transport providers. Implementation details necessary to add TNEF, remote, X.400, and EDI capabilities to transport providers are covered in separate chapters.

‹Tell the reader what they can expect out of this chapter: overview, how to implement must and optional features, provide a pointer to the other chapters they need, such as the specific follow-on XP chapters. Also let them know what they should have already boned up on before they got to this point.


 Transport Provider's Role in the MAPI Subsystem

Message transport provider dynamic link libraries (DLLs) provide the interface between the MAPI spooler and that part of the underlying messaging system(s) responsible for message sending and receiving. The MAPI spooler and the transport provider work together to handle the responsibilities of sending a message or receiving a message. Multiple transports can be installed on the same system, but MAPI supplies the one spooler required.

Client applications do not communicate directly with the transport; rather, the MAPI spooler sends outgoing messages to the appropriate transport and delivers incoming messages to the appropriate message store. The MAPI spooler does its work and makes its calls to transport providers when foreground applications are idle. After displaying dialog boxes when the transport provider is first logged on, transport providers operate in the background unless called by the client to flush send and receive queues.

Transport providers have the following responsibilities in a MAPI message system:

•	Register the address types the transport provider handles.

•	Register message and recipient options specific to the transport provider.

•	Perform any verification of credentials required by the messaging system.

•	Access outbound messages using the message object passed to it by the MAPI spooler.

•	Translate message format as required by the underlying messaging system.

•	Notify the MAPI spooler which recipients of an outgoing message the transport provider has accepted responsibility for handling.

•	Inform the MAPI spooler when an incoming message needs to be handled.

•	Pass incoming message data to the MAPI spooler by using message objects.

•	Fill in all required MAPI message properties on incoming messages.

•	Deletes the message from the underlying messaging system after delivery.

•	Provide status information for the MAPI spooler and client applications.


 Transport Provider-MAPI Spooler Operational Model

Transport provider initialization, startup, processing, shutdown and deinitialization is accomplished by a series of calls from the MAPI spooler to the transport provider. The calls are sequenced as follows:

1.	The MAPI spooler calls the XPProviderInit function, passes a support object, gets the provider object, and performs the version handshake.

2.	The MAPI spooler calls the IXPProvider::TransportLogon method of the XPProvider object. A session is established between the spooler and the transport with the credentials in the current section of the profile. The provider returns a logon object.

3.	The MAPI spooler calls the IXPLogon::AddressTypes function. The transport returns a list of the UIDs and email address types it cares about.

4.	The MAPI spooler calls the IXPLogon::RegisterOptions function for recipient options. The transport returns a list of the available per-recipient options for any of the email address types for which it indicated interest in the AddressTypes call.

5.	The MAPI spooler calls the RegisterOptions function for message options. The transport returns a list of the available per-message options for any of the email address types for which it indicated interest in the AddressTypes call.

6.	The MAPI spooler calls the IXPLogon::TransportNotify function to enable message transmission and/or reception.

7.	If requested by the transport provider in its return for the TransportLogon call, the MAPI spooler periodically calls the IXPLogon::Idle method.

8.	The MAPI spooler and transport send and receive messages (see Message Submission Model and Message Reception Model). The MAPI spooler services transport requests and calls on support, message, and attachment objects.

9.	The MAPI spooler calls the TransportNotify method to disable message transmission and/or reception.

10.	The MAPI spooler releases the logon and provider objects. See IXPProvider::Shutdown for more information.


 Message Submission Model

Message submission is accomplished by a series of calls from the MAPI spooler to the transport provider. The calls are sequenced as follows:

1.	The spooler calls IXPLogon::SubmitMessage, with passing in an IMessage instance, to begin the process.

2.	The transport then places a reference value (a transport-defined value used in future references to this message) in the location referenced in SubmitMessage.

3.	The transport provider accesses the message data by using the passed IMessage instance. For each recipient in the passed IMessage for which it has accepted responsibility, the transport provider sets the PR_RESPONSIBILITY property, and then returns.

4.	The transport provider can use the IMAPISupport::StatusRecips method to indicate if it recognizes any recipients that cannot be delivered to, or to create a standard delivery report. StatusRecips is a convenience for transports that have determined that some of the recipients cannot be delivered to or have received delivery information from their underlying messaging system that the user or mail client application might find useful.

5.	The MAPI spooler's call to IXPLogon::EndMessage is the final responsibility hand-off for the message from the MAPI spooler to the transport provider.

6.	The MAPI spooler may use IXPLogon::TransportNotify to abort message processing during the SubmitMessage or EndMessage calls.

Message Reception Model

The transport provider can tell the MAPI spooler whether it must be polled for incoming mail or whether it performs a callback to the spooler — by calling IMAPISupport::SpoolerNotify— when incoming mail is available by setting the SP_LOGON_POLL flag with its return for IXPProvider::TransportLogon. After learning that incoming mail is available, the spooler (at a convenient time) opens a new message and asks the transport provider to store the received message properties into the message.

This process works as follows:

1.	Available messages are indicated by either the transport provider calling IMAPISupport::SpoolerNotify or by the MAPI spooler calling IXPLogon::Poll.

2.	The MAPI spooler calls IXPLogon::StartMessage to initiate the process.

3.	The transport provider places a reference value in the location referenced in StartMessage.

4.	The transport provider stores the message data by using the passed IMessage instance.

5.	The transport provider calls the IMAPIProp::SaveChanges method on the IMessage instance and returns from StartMessage.

6.	The MAPI spooler calls IXPLogon::TransportNotify if it must stop message import.


 Required Features Transport Providers Must Implement

All MAPI transport providers must implement certain required features, the most important of which are as follows:

•	Your transport provider must follow the general guidelines for working with MAPI and other service providers as described elsewhere in this programming guide.

•	Your transport provider must expose to MAPI its XPProviderInit initialization function.

•	Your transport provider must expose to MAPI its implementation of the IXPProvider and IXPLogon interfaces.

•	Your Transport provider must expose to MAPI and client applications its implementation of the IMAPIStatus interface.

For more detailed information on implementing the preceding function and interfaces, see the MAPI Programmer's Reference.


 Working with MAPI and Other Providers

MAPI service providers of any kind must follow certain guidelines to work with other MAPI components. Each service provider must:

•	Use the proper Provider and Logon objects to initialize your provider.

•	Return a dispatch table of provider entry points to the messaging system upon initialization.

•	Register a MAPI status table row for each resource owned by a provider.

•	Use the IMAPISupport::NewUID method to obtain valid Unique Identifiers (UIDs).

•	Support the common MAPI interfaces on objects returned by your provider.

•	Use the MAPI memory allocation functions for memory freed by client applications.

•	Optionally support event notification for interested client applications.

•	Maintain a profile, if necessary, to store credentials to the underlying messaging system.

•	Use the IMAPISupport::RegisterPreprocessor method to register any message preprocessing functions.

•	Include the proper header files (including MAPISPI.H) to define common constants, structures, interfaces, and return values.


 Initializing the Transport Provider

The transport-spooler interface defines calls the MAPI spooler makes to a transport provider. Transport providers implement these routines in a DLL. The first direct entry point in the DLL used by the MAPI spooler is the transport provider initialization function XPProviderInit. For more information on how to implement your provider's initialization function, see MAPI Programmer's Reference.

MAPI uses the operating system routine GetProcAddress to get the address of the provider's initialization routine and then calls that routine. The name of the initialization routine is based on what type of service provider is being called, MSProviderInit for message stores, ABProviderInit for address books, or XPProviderInit for transports. The names are different so that one DLL can contain any combination of providers.

The MAPISPI.H header file has a type definition for the function prototype of each type of initialization function, and a predefined procedure name for each initialization routine. By naming the initialization routines in your C files with the same names used by GetProcAddress and using a straight forward export declaration in your DLL.DEF file, you automatically get type checking of the parameters on your initialization routine. See the sample provider source code for examples.

Note  XX in the prototype is AB, MS, or XP depending on the provider type.

Also, if a provider's initialization call succeeds but returns an service provider interface version number too small for MAPI to handle, MAPI immediately calls the Release method of the provider object and proceeds as if the initialization call had failed with MAPI_E_VERSION. This way MAPI and the provider jointly define the range of service provider interface version numbers they can handle, and if nothing matches then provider loading simply fails with a MAPI_E_VERSION return value.

The last step in getting access to service provider resources is to log onto the service provider. You access the logon methods from the MSProvider, ABProvider, or XPProvider object returned from the initialization routine. This is the call where credentials (if used) are checked, dialog boxes may be allowed, and so on. The logon methods have different parameters and slightly different functions, depending on the type of provider.

If a second store, address book, or transport session is opened on the same DLL, process, and MAPI session, a second provider object is not created. Instead the first provider object is used to log on to the second store, address book, or transport. Thus, multiple transport sessions, stores or address books can be opened from a single provider object. MAPI creates a second provider object if two MAPI sessions are used on the same process.


 Releasing the Transport Provider

Here are the processing steps when MAPI or the MAPI spooler finish using a transport logon object.

1.	MAPI or the MAPI spooler calls the transport provider's IXPLogon::TransportLogoff method.

2.	The transport provider invalidates all objects opened within the object and not yet released, including status objects, by calling the IMAPISupport::MakeInvalid method.

3.	The MAPI support object Release method removes the provider's row from the status table and removes from internal tables any UIDs set that were set with the IMAPISupport::SetProviderUID method. It decrements the count of known logon objects active on this provider object, and if the count reaches zero MAPI calls IXPProvider::Shutdown and Release on the provider object. If this was the last known provider object using this DLL on this process, MAPI remembers internally to call FreeLibrary on the DLL at some later time. Memory for the MAPI support object is freed and the support object Release method returns.

4.	The TransportLogoff method returns S_OK.

5.	MAPI or the MAPI spooler calls Release on the transport provider's logon object. The memory for the object is discarded.

6.	MAPI or the MAPI spooler calls FreeLibrary on the provider DLL.

For robustness, the logon and provider objects should be able to handle final Release calls on themselves without first having their TransportLogoff or Shutdown methods called. If Release is called in such cases, transport providers should treat the calls as if TransportLogoff or Shutdown had been called with a zero argument followed by Release.


 Implementing the FlushQueues Method

The MAPI spooler uses the IXPLogon::FlushQueues method to download and upload a batch of messages to and from a transport provider. Typically, the MAPI spooler will flush the queues for all transports that are logged onto the session, starting with the first transport as set in the transport order section of the user's profile. Transport providers must handle the FlushQueues call as described in the following sequence of steps to allow proper message processing and to allow external resources such as modems to be used by other transport providers as part of the MAPI spooler's FlushQueues operation.

Step	Component	Implementation
1.	MAPI spooler	Calls the IXPLogon::FlushQueues method for the first transport listed in the transport order of the user's profile, passing the requested flags in the ulFlags parameter. FlushQueues is called once with all flags set for the entire upload and download operation.
2.	Transport Provider	The transport provider needs to do a number of things before returning from the FlushQueues call. If previously submitted messages are being deferred, the IMAPISupport::SpoolerNotify method should be called with the NOTIFY_SENT_DEFERRED flag set. If the transport provider uses an external resource such as a modem, the connection to the external resource should be established. The STATUS_OUTBOUND_FLUSH bit in the PR_STATUS_CODE property of the transport provider's status row must be set using the IMAPISupport::ModifyStatusRow method. The transport provider should then return S_OK for the FlushQueues call.
3.	MAPI spooler	Checks the transport provider's status row for the STATUS_OUTBOUND_FLUSH bit and calls IXPLogon::SubmitMessage for the first message in the queue.
4.	Transport provider	Handles the message and returns from the SubmitMessage call.
5.	MAPI spooler	If the transport provider returns S_OK from SubmitMessage, the MAPI spooler calls IXPLogon::EndMessage for the message as it does with regular message sending. If the transport provider returns a value other than S_OK from SubmitMessage, the MAPI spooler handles the value appropriately before calling EndMessage, or before calling SubmitMessage again.
6.	Transport provider	Returns from EndMessage with its message processing status in the lpulFlags parameter.
7.	MAPI spooler and transport provider	The SubmitMessage-EndMessage loop continues until all messages in the queue have been downloaded. After the last EndMessage call, the transport provider should free any external resources so they can be used by other transport providers to flush their queues.
8.	MAPI spooler	Notifies the transport provider that it is has finished downloading messages by calling the transport's IXPLogon::TransportNotify method with the NOTIFY_END_OUTBOUND_FLUSH flag set.
9.	Transport provider	The STATUS_INBOUND_FLUSH bit in the PR_STATUS_CODE property of the transport provider's status row must be set using ModifyStatusRow.
10.	MAPI spooler	Checks the transport provider's status row for the STATUS_INBOUND_FLUSH bit and calls IXPLogon::StartMessage.
11.	Transport provider	Processes the message and returns from StartMessage. If the transport provider has other messages to upload, it should call SpoolerNotify with the NOTIFY_NEWMAIL flag set.  If the transport provider has no messages to upload, it should call IMAPIProp::SaveChanges on the message the MAPI spooler passed in StartMessage and return.  The transport provider must then clear the STATUS_INBOUND_FLUSH bit in the PR_STATUS_CODE property of its status row using ModifyStatusRow. When the transport provider is done uploading messages it should ensure that all external resources have been released so they are available for use by other transport providers.
14.	MAPI spooler	Continues calling StartMessage until SaveChanges is called on a message. After the transport provider has finished uploading, the MAPI spooler calls TransportNotify with the NOTIFY_END_INBOUND_FLUSH flag set. The MAPI spooler then calls FlushQueues for the next transport provider listed in the transport order of the user's profile.
If a client application calls IMAPIStatus::FlushQueues on a transport provider's status object, the transport provider should set the appropriate bit in its status row with ModifyStatusRow. The MAPI spooler then calls the provider's IXPLogon::FlushQueues method at the MAPI spooler's convenience. When the provider's IXPLogon::FlushQueues method is called as a result of a client application's IMAPIStatus::FlushQueues call, the operation occurs asynchronously to the client application. Otherwise IXPLogon::FlushQueues works synchronously with the MAPI spooler.

A transport provider can stop the FlushQueues operation at any time by clearing the STATUS_OUTBOUND_FLUSH and STATUS_INBOUND_FLUSH bits in its status row. If the MAPI spooler is shutting down and wants to end the FlushQueues operation it calls TransportNotify with both the NOTIFY_END_INBOUND_FLUSH and NOTIFY_END_OUTBOUND_FLUSH flags set. The transport provider should release all external resources and return.

For more information on specific implementation details, see the reference entries for the methods in the MAPI Programmer's Reference.


 Interacting with the Spooler

The MAPI spooler does its work and makes its calls to transport providers when foreground applications are idle. After displaying dialog boxes when the transport provider is first logged on, transport providers operate in the background unless called by the client to flush send and receive queues. To reduce disturbance to foreground processing, transport providers should repeatedly call back to the MAPI spooler to release the CPU whenever they are performing long operations. Transport providers for 16-bit Windows platforms should take particular care to break up any operation that takes more than 0.2 seconds.

Transport providers can independently decide to flush a queue, and use the STATUS_INBOUND_FLUSH and STATUS_OUTBOUND_FLUSH bits in the PR_STATUS_CODE property of its status row to inform the MAPI spooler that it wants an inordinate amount of attention so that it can get the job done. The status row is update using the IMAPISupport::ModifyStatusRow method.

Since network activity often takes more than 0.2 seconds, transport providers should, whenever possible, use asynchronous network requests. This allows them to initiate a request, release the CPU by calling back to the MAPI spooler, and when the MAPI spooler again gives them control, they check to see if their network request has completed. If it has not yet completed they again release the CPU by calling back to the MAPI spooler with the IMAPISupport::SpoolerYield method.

During message processing (between IXPLogon::SubmitMessage and IXPLogon::EndMessage and during IXPLogon::StartMessage) the transport typically makes many calls on objects exposed to it by the MAPI spooler. As part of its handling of these objects, the MAPI spooler helps the transport behave appropriately as a background process by yielding on its own when appropriate. A transport requiring the disabling of this behavior or requiring time-critical processing can declare a critical section to the MAPI spooler using the IMAPISupport::SpoolerNotify support object method. In this case, the CPU is released only on explicit SpoolerYield calls by the transport until the transport ends critical section processing with another call to SpoolerNotify.


 Setting Properties on Inbound Messages

The client applications within the MAPI message system expect a number of properties in any received message. When the transport provider brings a message into MAPI, it should set these properties, since it is either the only process with the necessary information to do so, or is at least the best source of the information.

Providers are encouraged to set the values for all of these properties in incoming messages.

Property Name	Description
PR_SUBJECT	Subject of message.
PR_BODY	Text body of the message.
PR_MESSAGE_DELIVERY_TIME	Date/Time message was delivered
PR_SENDER_NAME	Display name of originator of message.
PR_SENDER_ENTRYID	Address Book EntryID of originator of message.
PR_SENDER_SEARCH_KEY	Address Book search key of originator of message.
PR_CLIENT_SUBMIT_TIME	The time that the message was submitted to its messaging system by the sender's mail client.
PR_SENT_REPRESENTING_NAME	Name of representative delegate for sending.
PR_SENT_REPRESENTING_ENTRYID	Address Book EntryID of sending delegate.
PR_SENT_REPRESENTING_SEARCH_KEY	Address Book search key of sending delegate.
PR_RCVD_REPRESENTING_NAME	Name of representative delegate for receiving.
PR_RCVD_REPRESENTING_ENTRYID	Address Book EntryID of receiving delegate.
PR_RCVD_REPRESENTING_SEARCH_KEY	Address Book search key of receiving delegate.
PR_REPLY_RECIPIENT_NAMES	List of delegated recipient display names, separated by semicolon/space "; ".
PR_REPLY_RECIPIENT_ENTRIES	List of delegated recipients for a reply.
PR_MESSAGE_TO_ME	Indicates that the recipient was specifically named as a "To" recipient (not in a group).
PR_MESSAGE_CC_ME	Indicates that the recipient was specifically named as a "Cc" recipient (not in a group).
PR_MESSAGE_RECIP_ME	Indicates that the recipient was specifically named as a "To", "Cc" or "Bcc" recipient (not in a group).
Providers which have no apparent mappings can set PR_SENT_REPRESENTING_??? to the same values as PR_SENDER_???, PR_RCVD_REPRESENTING_??? to the same values as PR_RECEIVED_BY_???, and build the PR_REPLY_RECIPIENT_??? based on PR_SENDER_???.

ENTRYID or ENTRYLIST properties can be generated if necessary using the IMAPISupport::CreateOneOff method.The XXX_SEARCH_KEY properties may be generated by concatenating the PR_ADDRTYPE property assocated with a user, a colon ':', and the PR_EMAIL_ADDRESS property assocated with the user, then folding the result to uppercase. The Windows API CharUpperBuff is a convenient function to use for this purpose.


 Using the Support Object

MAPI provides an implementation of the IMAPISupport interface with the support object service providers receive during logon. Transport Providers can call the following IMAPISupport methods:

IMAPISupport::Address
IMAPISupport::CreateOneOff
IMAPISupport::DoConfigPropSheet
IMAPISupport::GetLastError
IMAPISupport::GetMemAllocRoutines
IMAPISupport::GetSvcConfigSupportObj
IMAPISupport::IStorageFromStream
IMAPISupport::MakeInvalid
IMAPISupport::ModifyStatusRow
IMAPISupport::NewUID
IMAPISupport::Notify
IMAPISupport::OpenAddressBook
IMAPISupport::OpenEntry
IMAPISupport::OpenProfileSection
IMAPISupport::RegisterPreprocessor
IMAPISupport::SpoolerNotify
IMAPISupport::SpoolerYield
IMAPISupport::StatusRecips
IMAPISupport::Subscribe
IMAPISupport::Unsubscribe
IMAPISupport::WrapStoreEntryID


 Providing Status

Service providers expose status and other dynamic information to applications using the MAPI status table. When an application establishes a session with a provider, the provider creates a row in this table for each resource owned by it. A message store provider, for instance, should create a row for each message store it opens when it is being logged on. MAPI manages the table interface and notifies client applications of status changes. Service providers must update MAPI's table when a change occurs, and must support application calls to obtain information not exposed in the table.

Each provider must support three operations on status table entries:

•	Create a row in the status table.

•	Update a row in the status table.

•	Service an application request for further status information.

The information that a provider gives MAPI appears as a single row in a IMAPITable object. When status changes , the provider should call IMAPISupport::ModifyStatusRow to inform the messaging subsystem of the change. The subsystem broadcasts the notification to interested MAPI clients. Transport providers implement the IMAPIStatus interface to provide client applications with a way to query for more information than is contained in the status table.

STATUS_DEFAULT_OUTBOUND	Indicates any message going through this transport provider uses this identity, unless overridden with the PR_SENT_REPRESENTING_NAME property (for additional information on this property, see Chapter 11, "Messages"). Always on in exactly one status row for each transport provider.
STATUS_DEFAULT_STORE	Indicates this message store is the default for use by Simple MAPI.
STATUS_PRIMARY_IDENTITY	Indicates the entry ID in this row's PR_IDENTITY_ENTRYID column is the primary identity for this session.


 Optional Features Transport Providers Can Implement

Optional features transport providers can implement include the following:

•	Register message and recipient options specific to the transport provider.

•	Perform any verification of credentials required by the messaging system.

•	Support event notification for interested client applications.

•	Maintain a profile, if necessary, to store credentials to the underlying messaging system.

•	Display configuration property sheets to allow users to configure the transport provider's settings.

•	Provide message delivery reports to client applications.


 Implementing Security

Each transport provider is responsible for implementing an appropriate level of security for access to its underlying messaging system. Each incoming or outgoing message sent through a transport by the MAPI spooler is handled in the context of a provider logon session. The transport provider may display a logon dialog box to the user that prompts for a user's credentials before establishing such a connection. Alternatively, the transport provider could store the user's previously entered credentials in the secure property range within a profile section and use them for access without prompting.

When implementing your transport provider's security, remember the following:

•	With multiple installed service providers, there can be a multitude of names and passwords associated with a user.

•	MAPI allows multiple sessions with multiple identities. Providers are encouraged to support multiple sessions but are not required to do so.

•	Each session with a transport provider is associated by MAPI with a discrete section in the user's profile. The provider can use the IMAPISupport::OpenProfileSection method to gain access to this section, which can be used to store any information associated with this session, including credentials.

•	With multiple installed transport providers, it is not necessarily true that the user only has a single email-address. A user can have a separate e-mail-address for each installed transport provider, or different addresses for each session on a single provider.

For more information on storing credentials in profile sections, see the reference entry for the IProfSect interface.


 Displaying Configuration Property Sheets

Transport providers use the IMAPISupport::DoConfigPropSheet method to implement configuration property sheets; for more information, see MAPI Programmer's Reference.


 Providing Message Delivery Reports

Sometimes messages are sent to transport provider that it doesn't understand. How the transport provider determines whether message delivery or nondelivery reports are sent to client applications is an implementation detail specific to individual transport providers. Once it has been determined that a report is to be sent to client applications, transport providers use the IMAPISupport::StatusRecips method to notify MAPI.


 Developing Transports that Support TNEF

To promote interoperability between messaging systems that support different sets of MAPI features, MAPI provides the Transport Neutral Encapsulation Format (TNEF) as a standard way to transfer data. This format encapsulates MAPI properties not supported by an underlying messaging system into a binary stream that can be transferred along with the message when a transport provider sends it. The transport provider that receives the message can then decode the binary stream to retrieve all the properties of the original message and make them available to client applications.

MAPI supplies an implementation of the ITnef interface for use by MAPI transport providers when working with TNEF objects created with the OpenTnefStream or OpenTnefStreamEx functions.

The ITnef interface provides the following methods: ITnef::AddProps, ITnef::EncodeRecips, ITnef::ExtractProps, ITnef::Finish, ITnef::FinishComponent, ITnef::OpenTaggedBody, ITnef::SetProps

For more information on using the ITnef interface, see MAPI Programmer's Reference, Volume 1.


 TNEF Processing Overview

The process that a transport provider uses to send a message that includes a TNEF stream is as follows. The message properties that are supported by the underlying messaging system are set. The ITnef interface is obtained and used to encapsulate into a TNEF stream the message properties not supported by the messaging system. The ITnef interface is used to insert tags describing the rendering information of any message attachments into the message body. then the message is sent.

Transport providers receiving messages containing TNEF streams use the following process to retrieve the encapuslated properties. First the properties supported by the underlying message system are written into a new message. Then the ITnef interface is used to decode the TNEF stream and write the ecapuslated properties into the new message. Then the message body is parsed to reunite the attachments with their rendering information in the message body.

Two examples of TNEF usage follow. The first example, peer to peer, describes how a transport represents an entire message in a single file. The second example, custom processing, describes how TNEF uses custom encoding of attachments to allow the underlying messaging system to use its own method of transporting attachments.


 Peer to Peer

When a message is submitted, the transport provider can choose to create a file that is used to contain the message storage during transmission. Next a stream interface is wrapped around the file. The transport provider then writes out the envelope properties to the stream in a tagged format that allows the properties to be easily decoded by receiving transport providers..

A TNEF object is obtained by passing the stream interface into the OpenTnefStream function. The transport provider gets a list of all defined properties for the message by calling the IMAPIProp::GetPropList method. The transport provider then excludes all non-transmittable properties and all properties that it has encoded in the message envelope. ITnef::AddProps is called to encode the remaining properties, including all attachments. After all the requested properties are added, ITnef::Finish is called to encode the message into the stream. Finally, the tagged message body is obtained by calling the ITnef::OpenTaggedBody method. This tagged body is written out to the outbound stream. The transport provider calls IUnknown::Release to release the TNEF object and transmits the message.

On receipt of an inbound message, the transport provider decodes the message envelope properties into the message. Once the message properties are decoded, the TNEF data is wrapped into a stream object and passed to OpenTnefStream. The transport provider then decodes the information in the TNEF data by calling the ITnef::ExtractProps method. It is important to note that anything decoded by the TNEF object will overwrite properties decoded from the message envelope, that is, TNEF will overwrite the existing properties in a message. After the properties have been extracted into the message, the decorated message body is processed with a call to ITnef::OpenTaggedBody. The body is opened, written, and saved. The TNEF objects are released by calling IUnknown::Release and the message is saved with a call to IMAPIProp::SaveChanges.


 Custom Processing

Custom processing can be used when a transport wants to transmit attachments separately or via the underlying messaging systems attachment model. TNEF uses a mechanism that allows the transport writer to send the attachments apart from the message and reconnect them on the receiving side.

Custom processing is similar to the peer to peer method up to the point when the ITnef::AddProps is called. Instead of a single call, the transport provider makes multiple calls to ITnef::AddProps. The first call is made to add only the properties on the message via the TNEF_PROP_MESSAGE_ONLY flag.

After the message properties are added, the transport provider customizes the attachment processing using one of two options.

The first, and recommended, option is to make one call to ITnef::AddProps and one call to ITnef::SetProps for each attachment. The ITnef::AddProps call passes in TNEF_PROP_EXCLUDE flag with a property tag array that contains the PR_ATTACH_DATA_xxx property and an attachment identifier that specifies the attachment to be processed. ITnef::SetProps is called for each attachment that has a property tag of PR_ATTACH_TRANSPORT_NAME and a unique value that identifies the attachment as transported by the underlying message system. The remaining outbound TNEF processing is the same as in the peer to peer example. On the receiving side, the message is created as described above, the TNEF is decoded, and the tagged body is processed. Then the transport provider checks each attachment looking for the PR_ATTACH_TRANSPORT_NAME property. When an attachment is found with that property, the transport provider uses that property's value to reattach the attachment data to the message. The message is then saved and delivered.

The second option for customizing attachment processing uses a single call to ITnef::AddProps, passing in the TNEF_PROP_CONTAINED flag and with the lpvData parameter pointing to a string that is used as the value for the PR_ATTACH_TRANSPORT_NAME property. The purpose of this call is to exclude the PR_ATTACH_DATA_BIN property and add the PR_ATTACH_DATA_xxx property.

With this alternate model, the inbound TNEF processing is the same as in the peer to peer example.


 Encoding Recipient Tables

The encoding of a recipient table into the TNEF stream is rarely necessary. In general, the recipient properties are transmitted in the containing envelope. When inclusion of the recipient table is necessary, TNEF can be prompted to encode the recipient table as a part of its normal processing. This is done during the initial phase of TNEF processing. If a transport wants to include the recipient table in the TNEF stream, ITnef::EncodeRecips is called. If no table was passed in the lpRecipTable parameter, TNEF gets the recipient table from the message, queries the column set, and process every row of the table into the TNEF stream. If a table is supplied at the time of the call, TNEF uses that table in its current state.

A secondary method is available for those transports that do not need special processing of the recipient table. This alternate method is implemented by calling ITnef::AddProps with the PR_MESSAGE_RECIPIENTS property specified in the inclusion list. This is equivalent to calling ITnef::EncodeRecips and passing in NULL for the lpRecipTable parameter.


 Tagged Message Text

Tagged message text is used by TNEF to resolve attachment positions in the parent message. This is done by adding a place holder into the message text at the position of the attachment. This place holder, or attachment tag, describes the attachment in such a way that TNEF knows how to resolve the attachment and its position. The tags are formatted as follows:

[[ <Object Title> : <KeyNum> in <Stream Name> ]]
[[ <File Name> : <KeyNum> in <Transport Name> ]]

The <Object Title>or <File Name> are variables contain values that are taken from the attachment itself. In most cases, these values come from the PR_ATTACHMENT_TITLE property. In cases where those values are not available, the title is defaulted by TNEF based on the attachment type.

The <KeyNum> is a variable containing the textual representation of the attachment key assigned to the attachment by TNEF. The base value of the key is passed in to the OpenTnefStream call. This value must not be non-zero.

The last field is either the stream name passed into the OpenTnefStream call or the value of the PR_ATTACH_TRANSPORT_NAME property.

The tagging of the message body is performed when a transport provider asks for a tagged message body by calling ITnef::OpenTaggedBody. When reading from the tagged body stream, TNEF replaces the single character that was in the message body at the index provided in the PR_RENDERING_POSITION property with the appropriate tag. When writing to the tagged body stream, TNEF checks the incoming data for tags, finds the associated attachment and replaces the tag with a single space character.

Note that by using tagged message bodies, a transport provider can preserve the positioning of attachments regardless of most changes made to the message body by underlying messaging systems.


 Developing a Remote Transport Provider

This chapter will describe the remote transport architecture and provide how-to information for developing a remote transport provider.


 Remote Transport Architecture

Remote transport writers need a way to be able to execute special slow link functionality. The following section outlines MAPIs remote architecture and discusses the functionality that MAPI transport providers can implement. Specifically, MAPI provides support for remote transport providers to:

•	download headers

•	mark messages for download and deletion

•	provide download status

•	allow direct connect and disconnect control

MAPI remote architecture consists of the parts and subsystems shown here:


 Remote Viewer Application

This is a client application that is designed to work with remote transports. Remote viewer applications can check the MAPI status table for transports that have registered themselves as remote transport providers, and adjust their user interface appropriately. Remote client applications are expected to utilize a special folder that contains header information about messages in the user's Inbox. The header information is stored locally and can be used to selectively mark messages for download or deletion.


 Remote Transport Provider

Remote transport provider have the STATUS_REMOTE_ACCESS bit set in the PR_STATUS_CODE property of their provider's row in the status table. A remote transport provider may also wish to set some of the other status bits to control the flow of mail both incoming and outgoing.

Remote transport providers must also include in the status row the  PR_HEADER_FOLDER_ENTRYID property. This property indicates the entry identifier of the folder that is used for downloading by remote client applications. This entry identifier is registered with MAPI when the transport provider is initialized. When the user opens the folder, the remote viewer application calls the IMAPISession::OpenEntry method passing in the folder's entry identifier. MAPI then forwards the call to the transport provider which registered the folder's entry identifier. The transport should return a view of the contents of the folder. This folder's contents table should contain the list of messages in the folder.

The folder is expected to be a flat list with no subfolders. While the existence of subfolders should not cause client application problems, these folders are not displayed. Opening the folder does not cause the folder's contents to be downloaded. In this way message headers can be downloaded and looked at off-line or at a later time. Remote transport providers might want to provide some sort of local cache or storage facility for the downloaded message headers. Remote transport providers are encouraged to fully support the methods of the IMAPITable interface for the folder's contents table.

Remote transport providers must support the methods of the IMAPIStatus and IMAPIFolder interfaces.


 MAPI Form Architecture

This chapter provides an overview of the MAPI form architecture.

Note  Because the MAPI forms architecture is based on the OLE component object model, developing form container applications or form server applications requires knowledge of OLE programming. For more information on OLE, see the OLE Programmer's Reference.


 MAPI Form Components

A typical MAPI environment in which forms are used consists of the following components:

Component	Description
MAPI	Enables messaging in a networked environment.
MAPI service providers	Provide basic messaging services to MAPI clients.
MAPI client applications	Provide the user interface that enables users to interact with forms. Microsoft Exchange is one example of a MAPI client.
MAPI form interfaces	Used exclusively by form objects and form registry providers.
Form registry providers	Manage the storage and activation of form objects.
Form objects	Display and handle form interaction.
Each component is described in further detail following.


 MAPI

Within the MAPI messaging system, a form object is treated no differently than any other MAPI object. MAPI enables client applications to work with form registry providers in the same manner that client applications work with other service providers.

This is usually a property sheet for a message or a data-entry form that enables users to enter structured information. However, it can be any user interface that is associated with a message class.

Because forms are types of messages, they exhibit properties and behavior that is consistent with MAPI message objects. Because forms can have properties (also called "fields"), controls, and a display rendering that is application-specific, forms are manipulated through a set of MAPI interfaces that are specific for forms. The actual definition of a form is stored in a form registry, which is discussed later in this chapter.

To incorporate forms within your application, you use MAPI form functions to create and access forms and form properties. For more information on these interfaces, see the Forms API section later in this chapter. Like basic messages, MAPI forms contain some predefined properties such as the form's sender, the form's intended recipient, and when it was sent. Forms can also contain any number of custom properties that are specific to the form. For example a "Bug Report" form might contain fields for Bug Type, Bug Severity, and Product Version.

MAPI interfaces are separate from the MAPI form interfaces. Although the two sets of interfaces are part of the same specification, there is very little interaction or dependence between them. To a MAPI client, calling MAPI form interfaces is the same as calling any MAPI functions. You still need to establish a MAPI session, identify the correct providers in the MAPI profile, and so on.


 MAPI Service Providers

Form objects have the same access to the services of MAPI address book providers, message store providers, and transport providers, as any other client application in a MAPI messaging environment. Additionally, service providers can be developed to provide special handling for the properties and message classes of particular form objects.


 MAPI Client Applications

Client applications display and interact with form objects just as they do with other message objects. Client applications that use the MAPI form interfaces can provide additional interaction with form registry providers and form objects.


 MAPI Form Interfaces

MAPI defines the following interfaces for use in developing form objects and form registry providers:

Interface Name	Description
IMAPIForm	Manipulates form objects and handles form object commands.
IMAPIFormAdviseSink	Determines if the form object can handle the next message and changes the next or previous state of the form object.
IMAPIFormContainer	Supports installation, de-installation, and resolution of form objects against a specific form container.
IMAPIFormFactory	Supports the use of configurable run-time form objects in distributed computing environments.
IMAPIFormInfo	Enables client applications to work with properties that are specific to a message class.
IMAPIFormMgr	Enables client applications to get information about form objects, activates form objects, and installs form objects in the messaging system.
IMAPIMessageSite	Used to manipulate messages associated with form objects.
IMAPIViewAdviseSink	Notifies client applications that an event has occurred in the form object.
IMAPIViewContext	Used to respond to "Next", "Previous", and "Delete" commands in the form object.
IPersistMessage	Used to save, initialize, and load form objects to and from message storage.
For more information on the methods of the MAPI form interfaces, see MAPI Programmer's Reference, Volume 1.


 Form Registry Providers

To help organize form objects and make them easily accessible to client applications throughout the organization, the MAPI form architecture includes form registries, which support the installation, administration, replication, and use of form objects.

Although developers can implement their own form registry providers, most environments will use the form registry provider implemented by Microsoft.


 Forms Objects

•	Form Objects. Instantiated objects created by form servers or form clients. These can include objects that represent the forms themselves, or they can be "support" objects such as view context objects, message site objects, and form info objects. In most cases, form clients and form servers communicate through objects rather than through direct communication.

•	Form Servers.  Form-specific code that manages a user's interaction with a form. Form servers are sometimes referred to as "message class handlers" or "form handlers." Every form has at least one form server associated with it.

A MAPI form is simply a type of MAPI message. That is, it belongs to a particular message class with a Class ID. From a programmer's perspective, most forms have two components:

•	A user interface that enables users to interact with form objects.

•	A form server that manages the user's interaction with the message.

Most users know only about the form's user interface—they never see the form server. Usually, a form's user interface appears as a frame window or popup window that renders the property values of the message.


 Developing MAPI Form Objects

Developing a form object includes the following steps:

1.	Determine the properties that constitute the form object's property set.

2.	Name each property.

3.	Name the new property set.

4.	Generate a unique message class identifier (CLSID) for the form object.

5.	Create a configuration file for the form object.

6.	Write code to handle the user's interaction with the form object.


 Legal Notice

Information in this document is subject to change without notice. Companies, names, and data used in examples herein are fictitious unless otherwise noted. No part of this document may be reproduced or transmitted in any form or by any means, electronic or mechanical, for any purpose, without the express written permission of Microsoft Corporation.

Microsoft may have patents or pending patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in this document. The furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other intellectual property rights except as expressly provided in any written license agreement from Microsoft.

© 1995 Microsoft Corporation. All rights reserved.

Microsoft, Microsoft Press, MS-DOS, Visual Basic, Windows, and Win32 are registered trademarks, and Visual C++ and Windows NT are trademarks of Microsoft Corporation.

Unicode is a registered trademark of Unicode, Incorporated.


 About This Book

MAPI Programmer's Reference, Volume 1, one of three books accompanying the Messaging Application Programming Interface (MAPI) Software Development Kit (SDK), provides a complete reference to the interfaces used with Extended MAPI objects. This book should be used together with MAPI Programmer's Reference, Volume 2, and MAPI Programmer's Guide to develop messaging-based applications and services.


 Intended Audience

MAPI Programmer's Reference, Volume 1, is written for C and C++ developers with a range of needs and experience with messaging. For those developers who want to use MAPI to augment their applications with messaging features, no specific prerequisite knowledge is required. However, for workgroup developers who plan to use MAPI to create full-scale messaging applications, to create extensions or customized solutions to existing products, or to create messaging services, a background in OLE programming is recommended.


How Volume 1 is Organized
 How This Book Is Organized

This book's contents are organized as follows:

•	Chapter 1, "Understanding Extended MAPI Interfaces and Methods," introduces the basic design and use of MAPI interfaces, including interface inheritance and object accessibility, common features of all interfaces, input and output parameter usage, flag usage, method similarity, parameter commonality, and return value approach.

•	Chapter 2, "Extended MAPI Interfaces," consists of an alphabetic listing of all interfaces that developers can implement using MAPI.


 How Interface Reference Entries Are Structured

The documentation for each interface consists of an introductory section that includes a brief description of the interface's purpose followed by an "At a Glance" table, which contains the following information:

Specified in header file:	The header file where the interface is defined and that must be included when you compile your source code.
Object that supplies this interface:	The object implementing the interface.
Corresponding pointer type:	The pointer type for the object implementing the interface.
Implemented by:	A list of the applications that must provide an implementation of this interface for other applications or MAPI to call.
Called by:	A list of the applications that typically call the methods of this interface.
After the "At a Glance" table, a table follows that lists all the methods of this interface in vtable order. A vtable is an array of function pointers created by the compiler containing one function pointer for each method of a MAPI object. The methods are listed in the same order that they are declared. Methods derived from other interfaces are not shown in the "Vtable Order" table but can be used in the same way as documented in the interface that defines them.

Following the "Vtable Order" table, the interface's methods are then covered in alphabetical order. For each method, the documentation includes a brief purpose statement for the method followed by this information:

Heading	Content
Syntax	The syntax for the method.
Parameters	A description of each parameter of the method.
Return Values	A description of each value that the method can return.
Comments	A description of why and how the method is used.
See Also	Cross-references to other topics in MAPI Programmer's Reference, Volume 1, MAPI Programmer's Reference, Volume 2, and MAPI Programmer's Guide that can help you use this method.


 Document Conventions

The following typographical conventions are used throughout this book:

Typographical  Convention	Meaning
Bold	Indicates an interface, method, structure, or other keyword in MAPI, Microsoft® Windows®, the OLE application programming interface, C, or C++. For example, SpoolerYield is a MAPI method. Within discussions of syntax, bold type indicates that the text must be entered exactly as shown.
italic	Indicates placeholders, most often method or function parameters; these placeholders stand for information that must be supplied by the implementation or the user. For example, lpMAPIError is a MAPI method parameter. In addition, italics are used to highlight the first use of terms and to emphasize meaning.
UPPERCASE	Indicates MAPI flags, return values, and properties. For example, MAPI_UNICODE is a flag, S_OK is a return value, and PR_DISPLAY_NAME is a property. In addition, uppercase letters indicate filenames, segment names, registers, and terms used at the operating-system command level.
monospace	Indicates source code, structure syntax, examples, user input, and program output. For example: ptbl->SortTable(pSort, TBL_BATCH);
SMALL CAPITALS	Indicate the names of keys on the keyboard. When you see a plus sign ( + ) between two key names, you should hold down the first key while pressing the second. The carriage return key, sometimes marked as a bent arrow on the keyboard, is called ENTER.
Note  The interface syntax in this book follows the variable-naming convention known as Hungarian notation, invented by the programmer Charles Simonyi. Variables are prefixed with lowercase letters that indicate their data type. For example, lpszProfileName is a long pointer to a zero-terminated string name ProfileName. For more information about Hungarian notation, see Programming Windows by Charles Petzold.


 For More Information

For information on MAPI not covered in this book, see MAPI Programmer's Guide and MAPI Programmer's Reference, Volume 2, both contained within the MAPI SDK. MAPI Programmer's Guide provides a conceptual overview of the MAPI architecture and describes a wide range of programming tasks illustrated with extensible and reusable sample code. MAPI Programmer's Reference, Volume 2 provides a complete reference to Extended MAPI functions, macros, structures, data types, properties, and return values and to the Simple MAPI and CMC programming models. It also includes a glossary of MAPI terms.

For more information about OLE programming, see Inside OLE, Second Edition, by Kraig Brockschmidt (Redmond, WA: Microsoft Press®, 1995) and OLE Programmer's Reference, Volume One and Volume Two, in the Microsoft Win32® SDK, published on CD-ROM by the Microsoft Developer Network (MSDN) and by Microsoft Visual C++™.

For more information about the Microsoft Windows programming environment, see Microsoft Windows SDK for Microsoft Windows, Version 3.1. Another good source is Programming Windows by Charles Petzold (Redmond, WA: Microsoft Press, 1990).

For more information about Windows 95 programming, see the Microsoft Windows 95 SDK.

For more information about Windows NT™ programming, see the Microsoft Windows NT SDK.


 Understanding Extended MAPI Interfaces and Methods

This chapter covers the following concepts that are integral to working with MAPI interfaces and methods:

•	How MAPI supports the OLE component object model (COM).

•	The MAPI interface hierarchy.

•	How MAPI interfaces are implemented and used.

•	Conventions for working with MAPI methods, such as, C calling convention, method similarities, parameter commonalities, input, output, and input-output parameters, flag usage, and method return values.

This chapter does not provide a full explanation of MAPI architecture and concepts; for a more complete conceptual discussion of MAPI, see MAPI Programmer's Guide.


 MAPI Objects

A MAPI object is somewhat different from a C++ object, although you can effectively use C++ objects to implement MAPI objects. A MAPI object is a C data structure or C++ class that supports a set of properties and subscribes to the component object model (COM) introduced with OLE. A binary standard for objects, the COM dictates that objects support one or more interfaces, or groups of related functions. These interfaces are derived from a base interface, IUnknown, that defines methods for interface query and reference counting. Interface query is the OLE mechanism for determining an object's capabilities — that is, what interfaces it supports. When a client application or service provider queries for an interface that an object has implemented, a pointer to that interface is returned, and the application can call interface methods through the pointer.

When an object supports an interface, it provides implementations for all of the methods specified in the interface. The object can provide a unique implementation of a method or delegate to another, previously defined implementation from which the object is derived. To use an object, you obtain a pointer to it; the pointer enables you to call methods belonging to one of the interfaces the object supports.

MAPI objects are simpler than most COM objects because they typically support only one interface deriving from IUnknown rather than several. However, because an interface can derive from IUnknown indirectly through another interface, a MAPI object can support methods from multiple interfaces. For example, the address-book container object (in other words, the address book container), supports the IABContainer interface. IABContainer derives from the IMAPIContainer interface, which derives from the IMAPIProp interface, which ultimately derives from IUnknown. Therefore, the address book container supports, in addition to the methods it uniquely implements, all those methods implemented by those interfaces from which its main interface is derived.


 MAPI Interfaces

As with other interfaces that support the OLE component object model, a MAPI interface is a group of related functions. MAPI defines each interface's methods, specifying their parameter type and order, without always providing implementations for the methods. What supplies the implementation — MAPI, a client application, or a service provider — depends on the purpose of the interface, the interaction between the MAPI client application and MAPI service provider, and the service provider's particular feature set.

Besides the lack of a guaranteed implementation, an interface such as a MAPI interface that adheres to the component object model also participates in interface query, as previously described. All component object model interfaces inherit from IUnknown, either directly or indirectly. When you implement an object with an interface that inherits from another interface, you must implement all of the methods specified for both the inherited interface and the derived interface. When you call an object, it is important to know the inheritance hierarchy so that when you obtain a pointer to an object, you know what methods are available.

Note  For more information about the IUnknown interface and about programming with the component object model, see Inside OLE, Second Edition, by Kraig Brockschmidt (Redmond, WA: Microsoft Press, 1995) and OLE Programmer's Reference, Volume One and Volume Two, in the Microsoft Win32 SDK, published on CD-ROM by the Microsoft Developer Network (MSDN) and by Microsoft Visual C++.


 MAPI Inheritance Hierarchy

The MAPI inheritance hierarchy is very simple and straightforward. Most MAPI objects inherit directly from IUnknown. Some inherit from the properties interface, IMAPIProp, and a few inherit from the container interface, IMAPIContainer, as shown in the following figure.


 Implementing and Using MAPI Interfaces

MAPI interfaces can be understood from three different perspectives: what implements them, what uses (that is, calls) them, and what they are used for.


 What Implements the MAPI Interfaces

Some interfaces are implemented by both MAPI and service providers. For example, the IMAPIProp and IMAPITable interfaces are implemented by MAPI and all service providers. This functionality enables service provider developers to write their own implementations for interfaces that MAPI must also implement. Service providers can wrap method calls and pass them to MAPI if they choose to use MAPI's implementation instead. When multiple implementations of an interface are available, access is controlled by the function pointers returned for the object that exposes the interface. The following table describes what implements the MAPI interfaces.

Implemented by	Interfaces
MAPI	IAddrBook, IMAPIControl, IMAPIProgress, IMAPIProp, IMAPISession, IMAPISupport, IMAPITable, IMsgServiceAdmin, IProfAdmin, IProfSect, IPropData, IProviderAdmin, ITableData, ITnef
Client applications	IMAPIAdviseSink, IMAPIViewContext
Address book providers	IABContainer, IABLogon, IABProvider, IDistList, IMailUser, IMAPIContainer, IMAPIProp, IMAPITable
Message store providers	IAttach, IMAPIContainer, IMAPIFolder, IMAPIProp, IMAPIStatus, IMAPITable, IMessage, IMsgStore, IMSLogon, IMSProvider
Transport providers	IMAPIProp, IMAPIStatus, IMAPITable, IXPLogon, IXPProvider, ITnef
Message hook providers	ISpoolerHook
Form registry providers	IMAPIFormContainer, IMAPIFormInfo, IMAPIFormMgr
Forms	IMAPIForm, IPersistMessage, IMAPIFormAdviseSink, IMAPIMessageSite, IMAPIViewAdviseSink, IMAPIViewContext, IMAPIFormFactory


 What Uses the MAPI Interfaces

The following table describes what implementations can call which interfaces and identifies the MAPI header file where each interface is defined.

Used by	Interfaces	MAPI  header file
Client applications only	IMAPISession, IAddrBook, IProfAdmin, IMsgServiceAdmin	MAPIX.H
Service providers only	IMAPISupport, IABProvider, IMSProvider, IXPProvider, IABLogon, IMSLogon, IXPLogon	MAPISPI.H
All implementations — MAPI, clients, and providers	IAttach, IABContainer, IDistList, IMAPIAdviseSink, IMAPIControl, IMAPIContainer, IMAPIFolder, IMAPIProgress, IMAPIProp, IMAPIStatus, IMAPITable, IMailUser, IMessage, IMsgStore, IProfSect, IPropData, IProviderAdmin, ISpoolerHook, ITableData, ITnef	MAPIDEFS.H, MAPIHOOK.H, MAPIUTIL.H, and TNEF.H
Form objects	IMAPIForm, IMAPIFormAdviseSink, IMAPIFormContainer, IMAPIFormFactory, IMAPIFormInfo, IMAPIFormMgr, IMAPIMessageSite, IPersistMessage, IMAPIViewAdviseSink, IMAPIViewContext	MAPIFORM.H


 What the MAPI Interfaces Are Used For

The following table describes MAPI interfaces based on the actions they are used for.

Used for	Interfaces
Working with address books	IABContainer, IABLogon, IABProvider, IAddrBook, IAttach, IDistList, IMailUser, IMAPIContainer, IMAPIProp, IMAPITable
Working with message stores	IAttach, IMAPIContainer, IMAPIFolder, IMAPIProp, IMAPIStatus, IMAPITable, IMessage, IMsgStore, IMSLogon, IMSProvider
Working with transports	IXPLogon, IXPProvider, ITnef
Working with forms	IMAPIForm, IMAPIFormAdviseSink, IMAPIFormContainer, IMAPIFormFactory, IMAPIFormInfo, IMAPIFormMgr, IMAPIMessageSite, IPersistMessage, IMAPIViewAdviseSink, IMAPIViewContext
Working with profiles	IMsgServiceAdmin, IProfAdmin, IProfSect, IProviderAdmin
Managing logon	IIABLogon, IMAPISession, IMSLogon, IXPLogon
Working with tables	IMAPITable, ITableData
Working with properties	IMAPIProp, IPropData
Determining object status	IMAPIStatus
Working with notifications	IMAPIAdviseSink, IMAPIFormAdviseSink
Supporting service providers	IMAPISupport
Working with message hooks	ISpoolerHook


 Some Conventions for Working with MAPI Methods

The following topics provide information on some conventions common to all MAPI methods. Learning about these similarities helps in learning and applying the MAPI programming model consistently throughout your program.


 Calling MAPI Methods Using C

All MAPI interfaces are documented using C++ and OLE conventions. When you call an interface method from a C language program, you must add a parameter to the list of parameters that are documented in the MAPI reference. The additional parameter, which must be the first parameter in the argument list, supplies information to the C language program that is provided by the C++ program's this pointer.

For example, consider the IABLogon interface method GetOneOffTable. In C++, the call syntax is as follows:

lpABLogon->GetOneOffTable(lppTable);

When you call this method from a C program, you must add a pointer as the first parameter to the ABLogon object, and the call syntax is through the vtable as follows:

hResult = lpABLogon->lpVtbl->GetOneOffTable(lpABLogon, lppTable)


 Method Similarities

Some MAPI interfaces have methods with the same names as methods defined for other interfaces; GetLastError and OpenEntry, methods which both appear in multiple interfaces, are two such examples. In most cases, such methods take the same arguments and have the same functionality for all interfaces that define them, the only difference being that they work on different objects. For example, the IABContainer::CopyEntries and IDistList::CopyEntries methods work in the same way, but one works on a container object and one works on a distribution list object. In such cases, you should always call the method using a pointer to the most specific object. For example, if you want to copy a folder it is more efficient to call CopyFolder using a pointer to the actual folder object than it is to call CopyFolder using a pointer to the message store's support object.

In the case of IMAPIStatus::ValidateState and IXPLogon::ValidateState, although the two identically named methods take the same arguments, they have completely different functionality. They are implemented and called differently because one method is used by client applications and the other by the MAPI spooler.

In other cases, although the method names are the same, they take different arguments and have different functionality. This is true for most of the interfaces that deal with forms. Because the object type through which the method is being called must match the this pointer (the first parameter of all MAPI methods), calls are passed through to the correct method in such cases.

The following three tables provide an overview of the similarities and differences for like-named methods. For specific implementation details, see the reference entry for a particular method.

The following methods have the same parameters and the same functionality in each interface in which they are found, but each version of the method works on a different object.

Methods	Interfaces
CopyEntries	IABContainer, IDistList
CopyFolder	IMAPIFolder, IMAPISupport
CopyMessages	IMAPIFolder, IMAPISupport
CreateEntry	IABContainer, IDistList
CreateOneOff	IAddrBook, IMAPISupport
DeleteEntries	IABContainer, IDistList
Details	IAddrBook, IMAPISupport
FlushQueues	IMAPIStatus, IXPLogon
GetLastError	IABLogon, IMAPIControl, IMAPIFormContainer, IMAPIProp, IMAPISession, IMAPISupport, IMAPITable, IMsgServiceAdmin, IMSLogon, IProfAdmin, IProviderAdmin
GetOneOffTable	IABLogon, IMAPISupport
GetProviderTable	IMsgServiceAdmin, IProviderAdmin
NewEntry	IAddrBook, IMAPISupport
OpenAddressBook	IMAPISession, IMAPISupport
OpenStatusEntry	IABLogon, IMSLogon, IXPLogon
OpenTemplateID	IABLogon, IMAPISupport
PrepareRecips	IABLogon, IAddrBook
ResolveNames	IABContainer, IDistList
Shutdown	IABProvider, IMSProvider, IXPProvider
Unadvise	IABLogon, IAddrBook, IMAPIForm, IMAPISession, IMAPITable, IMsgStore, IMSLogon
The following method has the same parameters in each interface but different functionality.

Method	Interface
ValidateState	IMAPIStatus, IXPLogon
The following methods have different parameters in each interface and different functionality.

Method	Interface
AdminServices	IMAPISession, IProfAdmin
CalcFormPropSet	IMAPIFormContainer, IMAPIFormInfo, IMAPIFormManager
Logoff	IABLogon, IMAPISession, IMSLogon
Logon	IABProvider, IMSProvider, IXPLogon
OpenFormContainer	IMAPIFormInfo, IMAPIFormMgr
ResolveMessageClass	IMAPIFormContainer, IMAPIFormMgr
ResolveMultiple MessageClasses	IMAPIFormContainer, IMAPIFormMgr
SetProps	IMAPIProp, ITnef
The following table lists methods found in multiple interfaces that don't fall into the earlier categories.

Methods	Interfaces	Comments
Advise	IABLogon, IAddrBook, IMAPIForm, IMAPISession, IMAPITable, IMsgStore, IMSLogon	The IMAPIForm and IMAPITable versions of Advise take different parameters and have different functionality from the other Advise methods and from each other. The other methods all take the same parameters but work on different objects.
CompareEntryIDs	IABLogon, IAddrBook, IMAPISession, IMAPISupport, IMsgStore, IMSLogon, IMSProvider	All versions take the same parameters, but each works on a different type of object. Method functionality is slightly different when comparing methods for different objects.
OpenEntry	IABLogon, IAddrBook, IMAPIContainer, IMAPISession, IMAPISupport, IMsgStore, IMSLogon	Same parameters, but each version of the method works on a different object. Method functionality is slightly different when comparing methods for different objects.
OpenProfileSection	IMAPISession, IMAPISupport, IMsgServiceAdmin, IProviderAdmin	The IMAPISupport:: OpenProfileSection method takes different parameters and has slightly different functionality from the other versions of the method. The other versions of the method take the same parameters but work on different objects, and among the other methods functionality is slightly different when comparing methods for different objects.
SubmitMessage	IMAPIMessageSite, IMessage, IXPLogon	IXPLogon has different parameters and different functionality from the others. IMAPIMessageSite and IMessage take the same parameters but work on different objects and have completely different functionality.


 Parameter Commonalities

Many MAPI methods take similar parameters as arguments. Learning about these similarities helps in learning and applying the MAPI programming model. Shown here are the more commonly used parameters and the way in which each is used throughout the MAPI methods.

Parameter	Usage
lpInterface	Pointer to the interface to be used.
ulUIParam	Handle of the window where the action is taking place.
ulFlags	Flags passed in.
lpulFlags	Flags passed in and passed back on return.
lpMAPIError	Pointer to a MAPIERROR structure.
lpMessage	Pointer to a message object.
lpProblems	Pointer to an array of problems returned on operations involving properties.
lpProgress	Pointer to a progress object.
lpTable	Pointer to a table object.
lpUnk	Pointer to an object returned from a call to a QueryInterface method.
lpPropTagArray	Pointer to an array of property tags.
lpEntryID	Pointer to an entry identifier for an object.
lpulConnection	Pointer to the connection number used to register a notification.


 Input, Output, and Input-Output Parameters

In the parameter descriptions, this documentation has adopted the convention of indicating whether a parameter is an input, output, or input-output parameter. The distinction is important for knowing how to efficiently manage memory.

As previously stated, the memory management model employed in MAPI is an enhancement of the rules specified in OLE's component object model. As with OLE, these rules apply only to calls made to public interface methods, and within the public method, only to memory allocated for parameters that are not pointers to interfaces, such as strings and pointers to structures. When internally allocating and freeing memory not related to MAPI processes within your client application or provider, you can use whatever mechanism makes sense.

Parameters fall into one of three groups. They can be input parameters, set by the calling application with information to be used by the called method, output parameters, set by the called method and returned to the calling application, or input-output parameters, a combination of the two groups. The MAPI memory management model dictates how memory for these groups of parameters is allocated and freed as follows:

Parameter group	Allocating memory	Freeing memory
Input	Calling application is responsible for allocating memory and can use any mechanism.	Calling application is responsible for freeing memory and can use any mechanism.
Output	Called application is responsible for allocating memory and must use the MAPIAllocateBuffer function.	Called application is responsible for freeing memory and must use the MAPIFreeBuffer function.
Input-output	Calling application is responsible for the initial allocation; called application can reallocate memory if necessary using the MAPIAllocateMore function.	Called application is responsible for initial memory freeing if reallocation is necessary. Calling application must free the final return value.
When a process fails, providers need to pay attention to output and input-output parameters, because the calling application generally has no way to release the memory for the failed process. If a function returns a value indicating failure, then each output or input-output parameter must either be left at the value initialized by the calling application or set to a value for which memory will be released without any action on the part of the calling application. For example, a provider must leave an output pointer parameter of void ** ppv as it was on input; otherwise, it must set the returned pointer to NULL (*ppv = NULL).


 Flag Usage

MAPI methods (as well as MAPI functions and structures) make extensive use of bitmasks to pass flags so that bits can be set to control how an operation is performed. The most common usage of bitmasks is in ulFlags parameters, but you will find them used in other parameters as well.

MAPI has predefined all of the allowable flags as constants. These constants take the form of all uppercase letters with each word separated by an underscore, for example MAPI_UNICODE. Your application should only set the bits in the bitmask by passing in the constants allowed for that parameter; it should not set the bits itself or define its own flags. The only valid flags for a particular parameter of a given method are the ones that are listed under the parameter description. Passing any other flags, or setting any other bits by hand, will result in the error code MAPI_E_UNKNOWN_FLAGS being returned.

For example, IMessage::SetReadFlag takes a single parameter, ulFlags. The allowable flags are CLEAR_READ_FLAG, GENERATE_RECEIPT_ONLY, MAPI_DEFERRED_ERRORS, and SUPPRESS_RECEIPT. You would set the bit for CLEAR_READ_FLAG like this:

pMessage->SetReadFlag(CLEAR_READ_FLAG);

Some methods take a ulFlags parameter in which all of the bits are reserved for MAPI's use. In such cases, the parameter description will read "Reserved; must be zero." Passing any value other than zero in such parameters results in the MAPI_E_UNKNOWN_FLAGS error being returned. If more than one flag is defined for a parameter, any combination of flags can be passed using the logical-OR operator, unless the documentation for that parameter specifically mentions that some flags are mutually exclusive. For example, you would set all of the flags for SetReadFlag like this:

pMessage->SetReadFlag(CLEAR_READ_FLAG |
GENERATE_RECEIPT_ONLY | MAPI_DEFERRED_ERRORS |
SUPPRESS_RECEIPT);

The called method then examines each relevant bit of the ulFlags parameter to see if you set that bit.


 Return Values

All MAPI methods return HRESULTs. Your implementation should return S_OK (zero) on success, and one of the predefined MAPI return values (nonzero) for failure or warning conditions. The return values for each method are documented as part of the method's reference entry. Additionally, Extended MAPI Return Values groups the errors that are common to most MAPI methods.


 Extended MAPI Interfaces

This chapter consists of an alphabetic listing of all interfaces that developers can implement using Extended MAPI.


 IABContainer : IMAPIContainer

[New - Windows 95]

The IABContainer interface provides further access to address book containers. IABContainer can make such changes as creating, copying, and deleting entries, in addition to performing bulk searches. Address book providers must implement all methods of this interface. Providers might return MAPI_E_NO_SUPPORT, however, if their address book does not support certain operations. For example, an address book that did not support the copying of entries would return MAPI_E_NO_SUPPORT when its IABContainer::CopyEntries method was called.

At a Glance

Specified in header file:	MAPIDEFS.H
Object that supplies this interface:	Address book container
Corresponding pointer type:	LPABCONT
Implemented by:	Address book providers
Called by:	Extended MAPI client applications
Vtable Order

CreateEntry	Creates a new entry in a modifiable address book container.
CopyEntries	Copies one or more entries into a modifiable address book container.
DeleteEntries	Removes one or more entries from a modifiable address book container.
ResolveNames	Resolves entries from an address book container.


 IABContainer::CopyEntries

[New - Windows 95]

Copies one or more entries, typically messaging users or distribution lists, into an address book container that supports modification.

Syntax

HRESULT CopyEntries(LPENTRYLIST lpEntries, ULONG ulUIParam, LPMAPIPROGRESS lpProgress, ULONG ulFlags)

Parameters

lpEntries

Input parameter pointing to an array of ENTRYLIST structures containing entry identifiers to copy into the container.

ulUIParam

Input parameter containing the handle of the window the dialog box is modal to. The ulUIParam parameter must be zero if the AB_NO_DIALOG flag is set in the ulFlags parameter.

lpProgress

Input parameter pointing to the address of a progress object that contains client-supplied progress information to be displayed in a progress user interface during a lengthy copy operation. If NULL is passed in the lpProgress parameter, MAPI provides progress information. The lpProgress parameter is ignored if the AB_NO_DIALOG flag is set in the ulFlags parameter.

ulFlags

Input parameter containing a bitmask of flags that control how the copy operation is performed. If no flags are set, the entry is created. The following flags can be set:

AB_NO_DIALOG

Suppresses display of progress information. If this flag is not set, progress information is displayed.

CREATE_CHECK_DUP_LOOSE

Indicates a loose level should be used for duplicate entry checking, which returns more duplicate matches than using the flag CREATE_CHECK_DUP_STRICT. For example, a provider can define a loose match as the same display name, while defining a strict match as the same display name and the same e-mail address.

CREATE_CHECK_DUP_STRICT

Indicates a strict level should be used for duplicate entry checking, which returns fewer duplicate matches than using the flag CREATE_CHECK_DUP_LOOSE. For example, a provider can define a loose match as the same display name, while defining a strict match as the same display name and the same e-mail address.

CREATE_REPLACE

Duplicate entries replace entries in the container of which they are duplicates.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_W_PARTIAL_COMPLETION

The call succeeded, but one or more of the entries could not be copied. Use the HR_FAILED macro to test for this warning, but the call should be handled as a successful return.

Comments

Use the IABContainer::CopyEntries method to copy entries from one container to another. Copying entries with IABContainer::CopyEntries is the preferred way to copy entries between containers, even if there is only one entry in the container, because the copy operation is done within the provider rather than under client application control. Using the IABContainer::CopyEntries copy operation is functionally equivalent to creating new entries in the target container using calls to the following sequence of methods for each entry in the entry list: IABContainer::CreateEntry, IMAPIProp::SaveChanges, and IUnknown::Release.

Address book providers must support all the flags that can be set in the ulFlags parameter; however, your provider is free to determine what the semantics of CREATE_CHECK_DUP_LOOSE and CREATE_CHECK_DUP_STRICT mean within the context of its implementation. Providers that cannot determine whether the entry is a duplicate should allow the entry to be copied.

If the CREATE_CHECK_DUP_LOOSE and CREATE_CHECK_DUP_STRICT flags are set, and the implementation does not copy the entry because it is a duplicate, the MAPI_W_PARTIAL_COMPLETION warning is not returned. The MAPI_W_PARTIAL_COMPLETION warning is only returned when a nonduplicate entry cannot be copied.

If the CREATE_CHECK_DUP_LOOSE, CREATE_CHECK_DUP_STRICT, and CREATE_REPLACE flags are not set, then the entry is copied, even if it is a duplicate.

See Also

ENTRYLIST structure, IABContainer::CreateEntry method, IMAPIProgress : IUnknown interface, IMAPIProp::SaveChanges method


 IABContainer::CreateEntry

[New - Windows 95]

Creates a new entry in an address book container supporting modification. A new container entry can be a messaging user, a distribution list, or another container.

Syntax

HRESULT CreateEntry(ULONG cbEntryID, LPENTRYID lpEntryID, ULONG ulCreateFlags, LPMAPIPROP FAR * lppMAPIPropEntry)

Parameters

cbEntryID

Input parameter containing the number of bytes in the lpEntryID parameter.

lpEntryID

Input parameter pointing to the entry identifier of an existing entry that is copied to create the new entry.

ulCreateFlags

Input parameter containing a bitmask of flags that control how entry creation is performed. The following flags can be set:

CREATE_CHECK_DUP_LOOSE

Indicates a loose level should be used for duplicate entry checking, which returns more duplicate matches than using the flag CREATE_CHECK_DUP_STRICT. For example, a provider can define a loose match as the same display name, while defining a strict match as the same display name and the same e-mail address.

CREATE_CHECK_DUP_STRICT

Indicates a strict level should be used for duplicate entry checking, which returns fewer duplicate matches than using the flag CREATE_CHECK_DUP_LOOSE. For example, a provider can define a loose match as the same display name, while defining a strict match as the same display name and the same e-mail address.

CREATE_REPLACE

Duplicate entries replace entries in the container of which they are duplicates.

lppMAPIPropEntry

Output parameter pointing to the variable that receives a pointer to the newly created object.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Use the IABContainer::CreateEntries method to create a new entry in the specified container and return a pointer to the newly created object. The types of entries that can be created within a container are defined by the container's PR_CREATE_TEMPLATES property. The PR_CREATE_TEMPLATES property can be retrieved by passing it in the ulPropTag parameter when calling the IMAPProp::OpenProperty method.

Client applications can't assume that they can access the entry identifier returned in the lppMAPIPropEntry parameter until after the IMAPIProp::SaveChanges method has been called.

Address book providers must support all the flags that can be set in the ulFlags parameter; however, your provider is free to determine what the semantics of CREATE_CHECK_DUP_LOOSE and CREATE_CHECK_DUP_STRICT mean within the context of its implementation. Providers that cannot determine whether the entry is a duplicate should allow the entry to be created.

If the CREATE_CHECK_DUP_LOOSE and CREATE_CHECK_DUP_STRICT flags are set, and the implementation does not create the entry because it is a duplicate, the MAPI_W_PARTIAL_COMPLETION warning is not returned. The MAPI_W_PARTIAL_COMPLETION warning is only returned when a nonduplicate entry cannot be created.

If the CREATE_CHECK_DUP_LOOSE, CREATE_CHECK_DUP_STRICT, and CREATE_REPLACE flags are not set, then the entry is created, even if it is a duplicate.

The duplicate checking operation, although the flags are passed in with CreateEntry, does not occur until SaveChanges is called.

Errors such as MAPI_E_COLLISION, that can occur when the entry is created, are returned on the SaveChanges call, not from CreateEntry.

See Also

IABContainer::CopyEntries method, IMAPIProp::OpenProperty method, IMAPIProp::SaveChanges method, PR_CREATE_TEMPLATES property


 IABContainer::DeleteEntries

[New - Windows 95]

Removes recipients from an address book or other container that enables the user to delete entries. The removed recipients are typically messaging users, distribution lists, or containers.

Syntax

HRESULT DeleteEntries(LPENTRYLIST lpEntries, ULONG ulFlags)

Parameters

lpEntries

Input parameter pointing to an array of ENTRYLIST structures containing entry identifiers for the recipients being deleted.

ulFlags

Reserved; must be zero.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_W_PARTIAL_COMPLETION

The call succeeded, but one or more of the entries could not be deleted. Use the HR_FAILED macro to test for this warning, but the call should be handled as a successful return.


 IABContainer::ResolveNames

[New - Windows 95]

Resolves entries from an address book container.

Syntax

HRESULT ResolveNames(LPSPropTagArray lpPropTagArray, ULONG, ulFlags, LPADRLIST lpAdrList, LPFlagList lpFlagList)

Parameters

lpPropTagArray

Input parameter pointing to a SPropTagArray structure containing the properties required for each recipient name being resolved. To request that the default set of property columns for the container's contents table be returned in the address list, send a value of NULL in the lpPropTagArray parameter.

ulFlags

Input parameter containing a bitmask of flags controlling the type of the text in the returned strings. The following flag can be set:

MAPI_UNICODE

Indicates the returned strings of the default column set are to be in Unicode™ format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

lpAdrList

Input-output parameter that on input points to an ADRLIST structure containing the list of recipients whose names need to be resolved. On output, the lpAdrList parameter returns the list of resolved names.

lpFlagList

Input-output parameter containing a list of values; each value corresponds to an entry in the address list in the lpAdrList parameter and provides the name-resolution status for that particular entry. The values in lpFlagList are in the same order as the entries in the lpAdrList parameter. The following flags can be set:

MAPI_AMBIGUOUS

Indicates that the corresponding entry in the recipient list is resolved, but that it did not resolve to a unique entry identifier. If this flag is returned, other containers should ignore this entry.

MAPI_RESOLVED

Indicates that the corresponding entry in the recipient list has been resolved to a unique entry identifier. If this flag is returned, other containers should ignore this entry.

MAPI_UNRESOLVED

Indicates that the corresponding entry in the recipient list is unresolved. Another container can attempt to resolve this entry.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_BAD_CHARWIDTH

Either the MAPI_UNICODE flag was set and the implementation does not support Unicode, or MAPI_UNICODE was not set and the implementation only supports Unicode.

MAPI_E_NO_SUPPORT

The address book provider does not support bulk name resolution using this method.

Comments

Address book providers use the IABContainer::ResolveNames method to resolve unresolved names in an address book container. When a client application calls IAddrBook::ResolveNames, MAPI's implementation calls IABContainer::ResolveNames for each address book provider. Address book providers that want to perform bulk name resolutions should implement this method. Address book providers that don't implement IABContainer::ResolveNames resolve names by restricting the container's contents table using the PR_ANR property in the SPropertyRestriction structure. For more information on using restrictions to resolve names, see MAPI Programmer's Guide.

Address book providers that do implement IABContainer::ResolveNames take the address list passed in the lpAdrList parameter and try to resolve all the recipients that have their corresponding MAPI_UNRESOLVED flag set in the lpFlagList parameter. Entries in the lpAdrList parameter that are lacking the PR_ENTRYID property are considered unresolved.

The array of flags ResolveNames returns in the lpFlagList parameter is used to track the results of the name resolution operation; the array shows for each recipient name whether it is resolved, unresolved, or matches more than one recipient. If, after looking at an unresolved entry, your container can match that entry uniquely, your provider should also set the flag for that entry in lpFlagList to MAPI_RESOLVED and add the PR_ENTRYID property for that entry to that entry's ADRENTRY structure in the address list in the lpAdrList parameter. The entry identifier added in such a case does not have to be permanent. If your container contains more than one entry that matches a given unresolved entry, then your provider should set the flag for that entry in lpFlagList to MAPI_AMBIGUOUS and leave that entry's ADRENTRY alone.

If a provider can't return all the properties requested for the unresolved recipient, and these properties don't exist in the ADRENTRY structure passed in, it should set the property type of each property not returned to PT_ERROR. Any property columns that are already included with a recipient entry should be retained if that entry is resolved.

If your provider is replacing an ADRENTRY, it should first free the ADRENTRY using the MAPIFreeBuffer function, then allocate the replacement ADRENTRY using the MAPIAllocateBuffer function.

MAPI needs certain properties to submit a message and will call providers to get those properties as part of its IAddrBook::PrepareRecips and IMAPISupport::ExpandRecips implementations. Providers implementing ResolveNames can eliminate the MAPI callbacks on PrepareRecips and ExpandRecips, and thus improve performance for message submission, by returning the following property columns when they resolve recipient names:

PR_ADDRTYPE

The address type of the entry.

PR_DISPLAY_NAME

The display name of the recipient.

PR_EMAIL_ADDRESS

The e-mail address of the recipient.

PR_ENTRYID

The entry identifier for the object.

PR_OBJECT_TYPE

Indicates the type of the MAPI object.

PR_SEARCH_KEY

The search key used to identify the message within tables.

PR_TRANSMITTABLE_DISPLAY_NAME

The transmittable display name for the recipient.

Clients applications can also use the returned property columns in their IMessage::ModifyRecipients calls.

See Also

ADRENTRY structure, ADRLIST structure, IAddrBook::PrepareRecips method, IAddrBook::ResolveName method, IMAPISupport::ExpandRecips method, IMessage::ModifyRecipients method, PR_ANR property, SPropertyRestriction structure


 IABLogon : IUnknown

[New - Windows 95]

The IABLogon interface is used to access resources in an address book provider object.

At a Glance

Specified in header file:	MAPISPI.H
Object that supplies this interface:	Address-book logon object
Corresponding pointer type:	LPABLOGON
Implemented by:	Address book providers
Called by:	MAPI
Vtable Order

GetLastError	Returns information about the last error that occurred for an address book object.
Logoff	Logs an application off the address book provider.
OpenEntry	Opens a container or recipient object and returns a pointer to the object to provide further access.
CompareEntryIDs	Compares two entry identifiers to determine if they refer to the same object in the address book.
Advise	Registers an object for notifications about changes within the address book.
Unadvise	Removes a registration for notifications previously established with a call to the IABLogon::Advise method.
OpenStatusEntry	Opens a status object.
OpenTemplateID	Enables this provider to generate for another address book provider an interface for an object within the current address book provider.
GetOneOffTable	Returns the table of custom recipient address templates that can be used for creating recipients for a message.
PrepareRecips	Converts short-term entry identifiers to long-term entry identifiers, updates those recipients that belong to this address book provider, and, if necessary, retrieves those recipients' permanent entry identifiers along with any additional properties requested .


 IABLogon::Advise

[New - Windows 95]

Registers an object for notifications about changes within the address book.

Syntax

HRESULT Advise(ULONG cbEntryID, LPENTRYID lpEntryID, ULONG ulEventMask, LPMAPIADVISESINK lpAdviseSink, ULONG FAR * lpulConnection)

Parameters

cbEntryID

Input parameter containing the number of bytes in the entry identifier pointed to by the lpEntryID parameter.

lpEntryID

Input parameter pointing to the entry identifier of the object about which notifications should be generated. This object can be a folder, a message, or any other object in the message store.

ulEventMask

Input parameter containing an event mask of the types of notification events occurring for the object for which MAPI will generate notifications to filter specific cases. Each event type has a structure associated with it that holds additional information about the event. The following table lists the possible event types along with their corresponding data structures:

Notification event type	Corresponding data structure
fnevCriticalError	ERROR_NOTIFICATION
fnevObjectCreated	OBJECT_NOTIFICATION
fnevObjectDeleted	OBJECT_NOTIFICATION
fnevObjectModified	OBJECT_NOTIFICATION
fnevObjectCopied	OBJECT_NOTIFICATION
fnevTableModified	TABLE_NOTIFICATION
fnevStatusObjectModified	STATUS_OBJECT_NOTIFICATION
lpAdviseSink

Input parameter pointing to the advise sink object to be called when an event for the object occurs about which notification has been requested.

lpulConnection

Output parameter pointing to a variable that upon a successful return holds the connection number for this notification registration. The connection number must be nonzero.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_INVALID_ENTRYID

The service provider is not able to use the entry identifier passed in the lpEntryID parameter.

MAPI_E_NO_SUPPORT

The service provider either does not support changes to its objects or does not support notification of changes.

MAPI_E_UNKNOWN_ENTRYID

A service provider could not be found to handle the entry identifier.

Comments

Use the IABLogon::Advise method to register an address book object for notification callbacks. MAPI will forward this call to the service provider active on the session that is responsible for the object indicated by the entry identifier in the lpEntryID parameter. Whenever a change occurs to the indicated object, the provider checks to see what event mask bit has been set in the ulEventMask parameter and thus what type of change has occurred. If a bit is set, then the provider calls the IMAPIAdviseSink::OnNotify method for the advise sink object indicated by the lpAdviseSink parameter to report the event. Data passed in the notification structure to the OnNotify routine describes the event.

The call to OnNotify can occur during the call that changes the object, or at any following time. On systems that support multiple threads of execution, the call to OnNotify can occur on any thread. For a way to turn a call to OnNotify that might happen at an inopportune time into one that is safer to handle, your client should use the HrThisThreadAdviseSink function.

To provide notifications, the service provider implementing Advise needs to keep a copy of the pointer to the advise sink object; to do so, it calls the IUnknown::AddRef method for the advise sink object to maintain the object pointer until notification registration is canceled with a call to the IABLogon::Unadvise method. The Advise implementation should assign a connection number to the notification registration and call AddRef on this connection number before returning it in the lpulConnection parameter. Service providers can release the advise sink object before the registration is canceled, but they must not release the connection number until Unadvise has been called. After a call to Advise has succeeded and before Unadvise has been called, client applications must be prepared for the advise sink object to be released. Clients should therefore release their advise sink object after Advise returns, unless they have a specific long-term use for it.

See Also

HrThisThreadAdviseSink function, IABLogon::Unadvise method, IMAPIAdviseSink::OnNotify method, NOTIFICATION structure


 IABLogon::CompareEntryIDs

[New - Windows 95]

Compares two entry identifiers to determine if they refer to the same service provider object. MAPI only passes this call to a service provider if the unique identifiers (UIDs) in both entry identifiers to be compared are handled by that provider.

Syntax

HRESULT CompareEntryIDs(ULONG cbEntryID1, LPENTRYID lpEntryID1, ULONG cbEntryID2, LPENTRYID lpEntryID2, ULONG ulFlags, ULONG FAR * lpulResult)

Parameters

cbEntryID1

Input parameter containing the number of bytes in the lpEntryID1 parameter.

lpEntryID1

Input parameter pointing to the first entry identifier to be compared.

cbEntryID2

Input parameter containing the number of bytes in the lpEntryID2 parameter.

lpEntryID2

Input parameter pointing to the second entry identifier to be compared.

ulFlags

Reserved; must be zero.

lpulResult

Output parameter pointing to a variable that receives the result of the comparison; this variable is TRUE if the two entry identifiers refer to the same object and FALSE otherwise.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Use the IABLogon::CompareEntryIDs method to compare two entry identifiers for a given service provider object and determine whether they refer to the same object. If the two entry identifiers refer to the same object, then CompareEntryIDs sets the lpulResult parameter to TRUE; if they refer to different objects, CompareEntryIDs sets lpulResult to FALSE.

CompareEntryIDs is useful because an object can have more than one valid entry identifier; such a situation could occur, for example, trying to compare a short-term entry identifier with a long-term entry identifier.


 IABLogon::GetLastError

[New - Windows 95]

Returns a MAPIERROR structure containing information about the last error that occurred for the address book object.

Syntax

HRESULT GetLastError(HRESULT hResult, ULONG ulFlags, LPMAPIERROR FAR * lppMAPIError)

Parameters

hResult

Input parameter containing the result returned for the last call on the session object that returned an error.

ulFlags

Input parameter containing a bitmask of flags controlling the type of the returned strings. The following flag can be set:

MAPI_UNICODE

Indicates the strings returned in the MAPIERROR structure returned in the lppMAPIError parameter are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

lppMAPIError

Output parameter pointing to a pointer to the returned MAPIERROR structure containing version, component, and context information for the error. The lppMAPIError parameter can be set to NULL if there is no MAPIERROR structure to return.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_BAD_CHARWIDTH

Either the MAPI_UNICODE flag was set and the implementation does not support Unicode, or MAPI_UNICODE was not set and the implementation only supports Unicode.

Comments

Use the IABLogon::GetLastError method to retrieve information to display as a message to the user regarding the last error returned from a method call on the session object.

To release all the memory allocated by MAPI, client applications need only call the MAPIFreeBuffer function for the MAPIERROR structure.

The return value from GetLastError must be S_OK for the application to make use of the MAPIERROR structure. Even if the return value is S_OK, it is still possible that a MAPIERROR structure won't be returned. If the implementation cannot determine what the last error was, or if a MAPIERROR structure is not available for that error, a pointer to NULL is returned in the lppMAPIError parameter instead.

See Also

MAPIERROR structure, MAPIFreeBuffer function


 IABLogon::GetOneOffTable

[New - Windows 95]

Returns the table of custom recipient address templates that can be used for creating recipients for a message.

Syntax

HRESULT GetOneOffTable(ULONG ulFlags, LPMAPITABLE FAR * lppTable)

Parameters

ulFlags

Input parameter containing a bitmask of flags. The following flag can be set:

MAPI_UNICODE

Indicates the passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

lppTable

Output parameter pointing to a pointer to the returned table object that contains a list of custom recipient addresses supported by this provider for general uses, such as filling in the recipient fields of a message.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_BAD_CHARWIDTH

Either the MAPI_UNICODE flag was set and the implementation does not support Unicode, or MAPI_UNICODE was not set and the implementation only supports Unicode.

MAPI_E_NO_SUPPORT

The address book provider doesn't have any custom recipient tables.

Comments

MAPI calls the IABLogon::GetOneOffTable method to make templates for creating new custom recipient addresses (also called one-off addresses) available to client applications. These custom recipient addresses, created by the user based on dialog box templates, can be used to send individual messages to recipients.

The following properties must be available as columns:

PR_ADDRTYPE

The address type of the entry. If this address type is only determined by user selection, then it should contain a zero-length string.

PR_DEPTH

How far to indent the display name in the list. A value of zero means the display name is indented all the way to the left.

PR_DISPLAY_NAME

The display name that shows up in the listbox of items that can be created.

PR_DISPLAY_TYPE

The display type of the entry, usually DT_MAILUSER.

PR_ENTRYID

The entry identifier that gets passed into IABContainer::CreateEntry, IABContainer::OpenEntry, and IAddrBook::NewEntry.

PR_INSTANCE_KEY

The index column for the row.

PR_SELECTABLE

Indicates whether or not this item can be selected from the list box to create a custom recipient address. MAPI allows a provider to group items visually by indenting and allowing certain rows to function as headings by being unselectable.

For example, if you had several templates to build X.400 addresses, you could display them this way:

FAX templates (depth 0, not selectable)

Local (depth 1, selectable)

Long-distance (depth 1, selectable)

MAPI keeps this table open and changes to this table should be handled through table notifications. If your provider changes the table, it should call the IMAPIAdviseSink::OnNotify method with the appropriate event masks for any client applications that have registered for changes on that table.

Setting the MAPI_UNICODE flag in the ulFlags parameter does the following:

•	Sets the string type to Unicode for data returned for the initial active columns of the custom recipient table by the IMAPITable::QueryColumns method. The initial active columns for a custom recipient table are those columns the QueryColumns method returns before the application that contains the custom recipient table calls the IMAPITable::SetColumns method.

•	Sets the string type to Unicode for data returned for the initial active rows of the custom recipient table by the IMAPITable::QueryRows method. The initial active rows for a custom recipient table are those rows QueryRows returns before the application that contains the custom recipient table calls the IMAPITable::SetColumns method.

•	Controls the property types of the sort order specification returned by the IMAPITable::QuerySortOrder method before the application that contains the custom recipient table calls the IMAPITable::SortTable method.

See Also

BuildDisplayTable function, IABContainer::CreateEntry method, IAddrBook::NewEntry method, IMAPISupport::GetOneOffTable method


 IABLogon::Logoff

[New - Windows 95]

Logs the client application off the address book provider.

Syntax

HRESULT Logoff(ULONG ulFlags)

Parameters

ulFlags

Reserved; must be zero.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Address book providers use the IABLogon::Logoff method to forcibly shut down the address book. IABLogon::Logoff is called in the following situations:

•	While MAPI is logging off a client application after a call to the IMAPISession::Logoff method.

•	While MAPI is logging off an address book provider. In this case, IABLogon::Logoff is called as part of MAPI's processing the IUnknown::Release method of the support object that the address book provider creates while it is processing an IUnknown::Release method call on an address book object.

See Also

IABProvider::Logon method


 IABLogon::OpenEntry

[New - Windows 95]

Opens a container or recipient object and returns a pointer to the object to provide further access. A recipient can be either a messaging user or a distribution list.

Syntax

HRESULT OpenEntry(ULONG cbEntryID, LPENTRYID lpEntryID, LPCIID lpInterface, ULONG ulFlags, ULONG FAR * lpulObjType, LPUNKNOWN FAR * lppUnk)

Parameters

cbEntryID

Input parameter containing the number of bytes in the lpEntryID parameter.

lpEntryID

Input parameter pointing to the entry identifier for the container or recipient object to be opened.

lpInterface

Input parameter pointing to the interface identifier (IID) for the object. Passing NULL for the lpInterface parameter indicates the MAPI interface for the object will be returned. The lpInterface parameter can also be set to an identifier for another appropriate interface for the object.

ulFlags

Input parameter containing a bitmask of flags used to control how the object is opened. The following flags can be set:

MAPI_BEST_ACCESS

Indicates the object should be opened with the maximum privileges allowed to the user. For example, if the client application has write privilege, open the object with write privilege; if the client application has read-only privilege, open the object with read-only privilege. The client application can learn the privilege by getting the property PR_ACCESS_LEVEL.

MAPI_DEFERRED_ERRORS

Indicates the call is allowed to succeed even if the underlying object is not accessible to the calling application. If the object is not accessible, some subsequent call to the object might return an error.

MAPI_MODIFY

Requests write access. By default, objects are created with read-only access, and client applications should not assume that write access was granted.

lpulObjType

Output parameter pointing to a variable where the object type for the opened object is stored.

lppUnk

Output parameter pointing to a variable where the pointer to the opened object is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NO_ACCESS

An attempt to modify a read-only object or an attempt to access an object for which the user has insufficient permissions.

MAPI_E_UNKNOWN_ENTRYID

The object indicated in the lpEntryID parameter is not recognized. This return value is typically returned if the address book provider that the object is contained within is not open.

MAPI_E_NOT_FOUND

The object indicated in the lpEntryID parameter does not exist.

Comments

MAPI uses the IABLogon::OpenEntry method to open a container or recipient Your provider only receives an OpenEntry call for entry identifiers which MAPI has determined belong to your provider. Your provider returns a pointer that provides further access to the object to be opened. Default behavior is to open the object as read-only, unless the call sets the MAPI_MODIFY or MAPI_BEST_ACCESS flag in the ulFlags parameter. If your provider does not allow modification for the object requested, then it should return the value MAPI_E_NO_ACCESS.

The lpInterface parameter indicates which interface should be used on the opened object. Passing NULL in lpInterface indicates the standard MAPI interface for that type of object should be used. The address book provider can implement other interfaces for the object if needed by passing the interface identifier for the interface that should be returned.

If MAPI passes NULL for the lpEntryID parameter, it indicates that your provider should open root container in its container hierarchy.


 IABLogon::OpenStatusEntry

[New - Windows 95]

Opens a status object.

Syntax

HRESULT OpenStatusEntry(LPCIID lpInterface, ULONG ulFlags, ULONG FAR * lpulObjType, LPMAPISTATUS FAR * lppMAPIStatus)

Parameters

lpInterface

Input parameter pointing to the interface identifier (IID) to be used for the returned object. Passing NULL for the lpInterface parameter indicates the MAPI interface for the object will be returned, in this case the IMAPIStatus interface. The lpInterface parameter can also be set to an identifier for another appropriate interface for the object.

ulFlags

Input parameter containing a bitmask of flags used to control how the status entry is opened. The following flag can be set:

MAPI_MODIFY

Requests write access. By default, objects are created with read-only access, and client applications should not assume that write access was granted.

lpulObjType

Output parameter pointing to a variable that holds the type of the opened object.

lppEntry

Output parameter pointing to a variable where the pointer to the returned object is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Message store providers use the IABLogon::OpenStatusEntry method to open a status object. This status object is then used to enable client applications to call IMAPIStatus methods; for example, clients can use the IMAPIStatus::SettingsDialog method to reconfigure the message-store logon session or the IMAPIStatus::ValidateState method to validate the state of the message-store logon session.

See Also

IMAPIStatus : IMAPIProp interface, IMAPIStatus::SettingsDialog method, IMAPIStatus::ValidateState method


 IABLogon::OpenTemplateID

[New - Windows 95]

Allows your provider to bind code to data in a foreign address book provider.

Syntax

HRESULT OpenTemplateID(ULONG cbTemplateID, LPENTRYID lpTemplateID, ULONG ulTemplateFlags, LPMAPIPROP lpMAPIPropData, LPCIID lpInterface, LPMAPIPROP FAR * lppMAPIPropNew, LPMAPIPROP lpMAPIPropSibling)

Parameters

cbTemplateID

Input parameter containing the number of bytes in the lpTemplateID parameter. This value is obtained from the address book entry's PR_TEMPLATEID property.

lpTemplateID

Input parameter pointing to the template identifier for the template to be used. This value is obtained from the address book entry's PR_TEMPLATEID property.

ulTemplateFlags

Input parameter containing a bitmask of flags controlling how the address book entry is opened. The following flag can be set:

FILL_ENTRY

Indicates this is the first time this entry is being created in the foreign provider's address book and that the address book provider should copy all relevant properties, including name to identifier mapping, to the object pointed to by the lpMAPIPropData parameter. Your provider must perform this operation.

lpMAPIPropData

Input parameter pointing to the property object that is linked to the code in address book provider. This is the object that receives the template information from the address book provider. This object must support the interface being requested in the lpInterface parameter and it must be set to read-write access.

lpInterface

Input parameter pointing to the interface identifier that is being used for both the property objects in lppMAPIPropData and lppMAPIPropNew parameters. Passing NULL in the lpInterface parameter indicates the return value is cast to the standard interface for the address-book entry, which can be assumed to be IID_IMailUser.

lppMAPIPropNew

Output parameter pointing to a variable where the pointer to the interface indicated by the lpInterface parameter is stored.

lpMAPIPropSibling

Reserved; must be NULL.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_UNKNOWN_ENTRYID

The template identifier passed in is unrecognized by your provider.

Comments

Address book providers use the IABLogon::OpenTemplateID method to bind code that exists in their address book provider to data that is contained in the foreign address book provider. This functionality allows your provider to update the properties in the entry passed in the lpTemplateID parameter.

Any address book provider that can contain entries with template identifiers copied from other containers can check for the PR_TEMPLATEID property after calls to the IABContainer::OpenEntry or IABLogon::CreateEntry methods. If the address book entry contains the PR_TEMPLATEID property, the provider calls IMAPISupport::OpenTemplateID so that the address book provider responsible for the entry has the opportunity to update the entry.

If the FILL_ENTRY flag is passed in the ulFlags parameter, the address book provider must set all properties on the entry.

If your provider doesn't recognize the entry identifier passed in the lpTemplateID parameter, it should return MAPI_E_UNKNOWN_ENTRYID.

See Also

PR_TEMPLATEID property, IMAPISupport::OpenTemplateID method, IPropData : IMAPIProp interface


 IABLogon::PrepareRecips

[New - Windows 95]

Prepares a recipient list for later use by the messaging system. Converts recipients' short-term entry identifiers to long-term entry identifiers, updates those recipients that belong to this address book provider, and, if necessary, retrieves those recipients' permanent entry identifiers along with any additional properties requested.

Syntax

HRESULT PrepareRecips(ULONG ulFlags, LPSPropTagArray lpPropTagArray, LPADRLIST lpRecipList)

Parameters

ulFlags

Reserved; must be zero.

lpPropTagArray

Input parameter pointing to a counted array of property tags for the properties that require updating by the calling application. The lpPropTagArray parameter can be NULL.

lpRecipList

Input parameter pointing to an ADRLIST structure holding the list of recipients.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NOT_FOUND

The requested object does not exist.

Comments

The IABLogon::PrepareRecips method is called to ensure that all recipients your address book provider recognizes have permanent entry identifiers and that they have all the properties requested in the lpPropTagArray parameter. Within an individual recipient entry, the requested properties are ordered first, followed by any additional properties that were already present for the entry. If one or more of the requested properties are not recognized by your provider, it should set their property types to PT_ERROR and their property values either to MAPI_E_NOT_FOUND or to another value giving a more specific reason why the property is not available to the calling application.

Like the ADRLIST structure, each SPropValue property value structure passed in the lpPropTagArray parameter must be separately allocated using MAPIAllocateBuffer and MAPIAllocateMore such that it can be freed individually. If the provider must allocate additional space for any SPropValue structure, for example to store the data for a string property, it can use MAPIAllocateBuffer to allocate additional space for the full property-tag array, use the MAPIFreeBuffer function to free the original property-tag array, and then use MAPIAllocateMore to allocate any additional memory required.

See Also

ADRLIST structure, IMAPIProp::GetProps method, IMessage::ModifyRecipients method, PR_ENTRYID property, PT_ERROR property type, SPropValue structure, SRowSet structure


 IABLogon::Unadvise

[New - Windows 95]

Removes an object's registration for notification of address book changes previously established with a call to the IABLogon::Advise method.

Syntax

HRESULT Unadvise(ULONG ulConnection)

Parameters

ulConnection

Input parameter containing the number of the registration connection returned by IABLogon::Advise.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

The IABLogon::Unadvise method releases the pointer to the advise sink object passed in the lpAdviseSink parameter in the previous call to IABLogon::Advise and thereby cancels a notification registration. As part of discarding the pointer to advise sink object, the object's IUnknown::Release method is called. Generally, Release is called during the Unadvise call, but if another thread is in the process of calling IMAPIAdviseSink::OnNotify on the advise sink object, the Release call is delayed until the OnNotify method returns.

See Also

IABLogon::Advise method, IMAPIAdviseSink::OnNotify method


 IABProvider : IUnknown

[New - Windows 95]

The IABProvider interface provides a method to log onto an address book provider object and a method to invalidate an address book provider object.

At a Glance

Specified in header file:	MAPISPI.H
Object that supplies this interface:	Address book provider
Corresponding pointer type:	LPABPROVIDER
Implemented by:	Address book providers
Called by:	MAPI
Vtable Order

Shutdown	Closes your provider's address book object in an orderly fashion.
Logon	Logs MAPI onto one instance of your address book provider.


 IABProvider::Logon

[New - Windows 95]

Logs MAPI onto one instance of your address book provider.

Syntax

HRESULT Logon(LPMAPISUP lpMAPISup, ULONG ulUIParam, LPTSTR lpszProfileName, ULONG ulFlags, ULONG FAR * lpulcbSecurity, LPBYTE FAR * lppbSecurity, LPMAPIERROR FAR * lppMAPIError, LPABLOGON FAR * lppABLogon)

Parameters

lpMAPISup

Input parameter pointing to the MAPI support object, which is an object that provides access to functions required by providers.

ulUIParam

Input parameter containing the handle of the window the dialog box is modal to. MAPI passes in the value from the MAPILogon call

lpszProfileName

Input parameter pointing to a string containing the profile name of the user.

ulFlags

Input parameter containing a bitmask of flags used to control the logon. The following flags can be set:

AB_NO_DIALOG

Indicates that the provider should not display a dialog box during logon. If this flag is not set, the provider can display a dialog box to prompt the user for information that is not already contained with the profile specified in the lpszProfileName parameter.

MAPI_DEFERRED_ERRORS

Indicates the call is allowed to succeed even if the underlying object is not accessible to the calling application. If the object is not accessible, some subsequent call to the object might return an error.

MAPI_UNICODE

Indicates the passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

lpulcbSecurity

Input-output parameter pointing to a variable containing the size, in bytes, of the security credentials structure for which a pointer is returned in the lppbSecurity parameter. On input the value must be nonzero, on output the value must be zero. In both cases the pointers must be valid.

lppbSecurity

Input-output parameter pointing to a variable where the pointer to the buffer containing the security credentials is stored. On input the value must be nonzero, on output the value must be zero. In both cases the pointers must be valid.

lppMAPIError

Output parameter pointing to a pointer to the returned MAPIERROR structure. A value of NULL can be returned if there is no MAPIERROR structure to return.

lppABLogon

Output parameter pointing to the address of a variable in which the address book provider passes back its logon object.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_UNCONFIGURED

The profile does not contain enough information for the logon to complete. MAPI calls the provider's message service entry function.

MAPI_E_USER_CANCEL

The user canceled the operation, typically by clicking the cancel button in a dialog box.

Comments

When a client application calls the IMAPISession::OpenAddressBook method, MAPI loads your address book provider into memory and then calls the IABProvider::Logon method each time your provider is added to the client application's profile. The address book provider should, during the processing of each IABProvider::Logon call, use the IMAPISupport::SetProviderUID method to register the set of supported unique identifiers (UIDs). MAPI uses these UIDs for comparison to the UIDs found in entry identifiers so as to route calls from various objects that use entry identifiers. For example, routing OpenEntry calls to the correct address-book logon object. If your provider is logged in more than once to the same address-book provider object, and your provider's UID is constant, then your provider can provide a means to route an entry identifier used on any provider logon object to the correct logon context within your provider. For more information on using multiple logon objects, see MAPI Programmer's Guide.

The MAPI support object exists to provide access to functions needed by the address book and other providers. The support object can be different for each logon session; your address book provider should use the current object, indicated by the lpMAPISup parameter, for its session. Your provider must call the IUnknown::AddRef method on the support object if the IABProvider::Logon call is successful, otherwise your provider is unloaded.

The local name of the user's profile in the lpszProfileName parameter is provided as a convenience for address book providers. It can be used in error dialog boxes, logon screens, or in other user interfaces where you want to show the user the name of the profile. If you want your provider to keep and use this profile name, the provider must copy it to storage that your provider has allocated. The profile name is displayed in the character set of the user's application as indicated by the presence or absence of the MAPI_UNICODE flag in the ulFlags parameter.

The address book provider should create an address-book logon object and return a pointer to it in the lppABLogon parameter. MAPI uses this logon object on several subsequent calls, for example, when it calls the IABLogon::OpenEntry and IABLogon::Logoff methods for your provider.

An address book provider that needs to log on to an underlying messaging system or directory service can use the MAPI support method IMAPISupport::OpenProfileSection for saving and retrieving security credential sets about this particular logon session. If your provider finds that all the required information is not in the profile it should return MAPI_E_UNCONFIGURED so that the provider's message service entry function gets called by MAPI.

If your provider requires a password during logon, a logon dialog box is displayed, unless the AB_NO_DIALOG flag was set in the ulFlags parameter. If the user cancels the logon process, typically by clicking the cancel button in the dialog box, your provider should return the value MAPI_E_USER_CANCEL.

When MAPI logs on to your provider, the MAPI spooler also logs on to your provider. The values in the lpulcbSecurity and lppbSecurity parameters are copied in from the MAPI spooler's logon. These values are used to allow multiple logons to share the same security context. On output the values for the lpulcbSecurity and lppbSecurity parameters must be allocated with MAPIAllocateBuffer.

See Also

IABLogon::Logoff method, IABLogon::OpenEntry method, IMAPISupport::OpenProfileSection method, IMAPISupport::SetProviderUID method, MSGSERVICEENTRY function prototype


 IABProvider::Shutdown

[New - Windows 95]

Closes your provider's address book object in an orderly fashion.

Syntax

HRESULT Shutdown (ULONG lpulFlags)

Parameters

lpulFlags

Reserved; must be a pointer to zero.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

When MAPI calls your provider's IABLogon::Shutdown method, your provider is free to do whatever it needs to do when it shuts down. Shutdown is only called after your final logon object is released.


 IAddrBook : IMAPIProp

[New - Windows 95]

The IAddrBook interface supports operations such as displaying address-book dialog boxes, opening containers within the address book, and resolving display names to messaging recipients.

At a Glance

Specified in header file:	MAPIX.H
Object that supplies this interface:	Address book object
Corresponding pointer type:	LPADRBOOK
Implemented by:	MAPI
Called by:	Client applications, service providers
Vtable Order

OpenEntry	Opens a container, messaging user, or distribution list object.
CompareEntryIDs	Compares two address book entry identifiers to determine if they refer to the same object.
Advise	Registers for notifications on changes to objects within the address book.
Unadvise	Removes a registration for notification on address book changes previously established with a call to the IAddrBook::Advise method.
CreateOneOff	Creates an entry identifier for a custom recipient address.
NewEntry	Displays a dialog box for creating new entries within containers or custom recipient addresses within messages.
ResolveName	Displays a dialog box for locating a recipient given a partial name.
Address	Displays an addressing dialog box.
Details	Displays a details dialog box on a particular entry in an address book.
RecipOptions	Displays a modal per-recipient options dialog box on a particular recipient.
QueryDefaultRecipOpt	Returns the available recipient options for a particular messaging address type, with defaults.
GetPAB	Returns the directory designated as the personal address book (PAB).
SetPAB	Designates a particular container to be the personal address book.
GetDefaultDir	Returns the default directory for the address book container.
SetDefaultDir	Chooses a different directory as the default directory for the address book container.
GetSearchPath	Returns the search path that is used in ResolveNames methods.
SetSearchPath	Sets the path that is used in ResolveNames methods.
PrepareRecips	Prepares a recipient list for later use by the messaging system.


 IAddrBook::Address

[New - Windows 95]

Displays an addressing dialog box.

Syntax

HRESULT Address(ULONG FAR * lpulUIParam, LPADRPARM lpAdrParms, LPADRLIST FAR * lppAdrList)

Parameters

lpulUIParam

Input-output parameter containing the handle of the parent window of the dialog box. A window handle must always be passed in on input. If the DIALOG_SDI flag is set in the ADDRPARM structure, then on output the window handle of the modeless dialog box is returned.

lpAdrParms

Input-output parameter pointing to an ADRPARM structure that controls the presentation and behavior of the addressing dialog box.

lppAdrList

Input-Output parameter pointing to a variable where the pointer to an ADRLIST structure holding the recipient list updated by IAddrBook::Address is stored. lppAdrList can be NULL on input.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Use the IAddrBook::Address method to pass the current list of recipients in a message and return a list updated using the MAPI addressing dialog box. A client application passes the current list of recipients for a message, possibly empty, in the lppAdrList parameter when calling Address, and Address returns in lppAdrList an ADRLIST structure holding an updated list of recipients. Client applications can use the updated list to set the recipients of a message by using the IMessage::ModifyRecipients method.

The recipient entries in the passed and returned ADRLIST structures consist of ADRENTRY structures, with each one holding an individual recipient that is organized by which type of recipient it holds, as indicated by the recipient's PR_RECIPIENT_TYPE property. The possible types are MAPI_TO (that is, a primary recipient), MAPI_CC (that is, a recipient that receives a copy of a message), and MAPI_BCC (that is, a recipient that receives a copy of a message without other recipients being made aware).

ADRLIST structures can hold both resolved and unresolved recipient entries. An unresolved entry does not have a PR_ENTRYID property. Applications that enable users to type recipient names directly into a message, in addition to choosing names from a predetermined list, create unresolved entries by creating an ADRENTRY with just the PR_DISPLAY_NAME and the PR_RECIPIENT_TYPE properties. A resolved entry will at least contain the following properties: PR_ENTRYID, PR_RECIPIENT_TYPE, PR_DISPLAY_NAME, PR_ADDRTYPE, and PR_DISPLAY_TYPE.

The ADRLIST structure holding the address list must be separately allocated using the MAPIAllocateBuffer function. If the Address method needs to pass a larger ADRLIST structure on output than is passed in by the calling application, or if NULL is passed in the lppAdrList parameter on input, then Address allocates a larger buffer for the ADRLIST structure it returns using MAPIAllocateBuffer and returns this buffer's address in the lppAdrList parameter. Address frees the old buffer by using the MAPIFreeBuffer function.

Each SPropValue property value structure is also separately allocated by using MAPIAllocateBuffer. The Address method allocates additional property value structures and frees old ones as appropriate.

Address returns immediately if the DIALOG_SDI flag was set in the ADRPARM structure in the lpAdrParms parameter.

See Also

ADRENTRY structure, ADRLIST structure, ADRPARM structure, FreePadrlist function, FreeProws function, IMAPITable::QueryRows method, IMessage::ModifyRecipients method, MAPIAllocateBuffer function, MAPIAllocateMore function, MAPIFreeBuffer function, SPropValue structure, SRowSet structure


 IAddrBook::Advise

[New - Windows 95]

Registers an object for notifications about changes within the address book.

Syntax

HRESULT Advise(ULONG cbEntryID, LPENTRYID lpEntryID, ULONG ulEventMask, LPMAPIADVISESINK lpAdviseSink, ULONG FAR * lpulConnection)

Parameters

cbEntryID

Input parameter containing the number of bytes in the entry identifier pointed to by the lpEntryID parameter.

lpEntryID

Input parameter pointing to the entry identifier of the object about which notifications should be generated. This object can be a folder, a message, or any other object in the message store.

ulEventMask

Input parameter containing an event mask of the types of notification events occurring for the object for which MAPI will generate notifications to filter specific cases. Each event type has a structure associated with it that holds additional information about the event. The following table lists the possible event types along with their corresponding data structures:

Notification event type	Corresponding data structure
fnevCriticalError	ERROR_NOTIFICATION
fnevObjectCreated	OBJECT_NOTIFICATION
fnevObjectDeleted	OBJECT_NOTIFICATION
fnevObjectModified	OBJECT_NOTIFICATION
fnevObjectCopied	OBJECT_NOTIFICATION
fnevTableModified	TABLE_NOTIFICATION
fnevStatusObjectModified	STATUS_OBJECT_NOTIFICATION
lpAdviseSink

Input parameter pointing to the advise sink object to be called when a event for the object occurs about which notification has been requested.

lpulConnection

Output parameter pointing to a variable that holds the connection number for this notification registration upon a successful return. The connection number must be nonzero.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_INVALID_ENTRYID

The service provider is not able to use the entry identifier passed in the lpEntryID parameter.

MAPI_E_NO_SUPPORT

The service provider either does not support changes to its objects or does not support notification of changes.

MAPI_E_UNKNOWN_ENTRYID

A service provider could not be found to handle the entry identifier.

Comments

Use the IAddrBook::Advise method to register an address book object for notification callbacks. MAPI will forward this call to the service provider that is active on the session and is responsible for the object indicated by the entry identifier in the lpEntryID parameter. Whenever a change occurs to the indicated object, the provider checks to see what event mask bit has been set in the ulEventMask parameter and thus what type of change has occurred. If a bit is set, then the provider calls the IMAPIAdviseSink::OnNotify method for the advise sink object indicated by the lpAdviseSink parameter to report the event. Data passed in the notification structure to the OnNotify routine describes the event.

The call to OnNotify can occur during the call that changes the object, or at any following time. On systems that support multiple threads of execution, the call to OnNotify can occur on any thread. For a way to turn a call to OnNotify that might happen at an inopportune time into one that is safer to handle, your client should use the HrThisThreadAdviseSink function.

To provide notifications, the service provider implementing Advise needs to keep a copy of the pointer to the advise sink object; to do so, it calls the IUnknown::AddRef method for the advise sink object to maintain the object pointer until notification registration is canceled with a call to the IAddrBook::Unadvise method. The Advise implementation should assign a connection number to the notification registration and call AddRef on this connection number before returning it in the lpulConnection parameter. Service providers can release the advise sink object before the registration is canceled, but they must not release the connection number until Unadvise has been called. After a call to Advise has succeeded and before Unadvise has been called, client applications must be prepared for the advise sink object to be released. Clients should therefore release their advise sink object after Advise returns, unless they have a specific long-term use for it.

See Also

HrThisThreadAdviseSink function, IAddrBook::Unadvise method, IMAPIAdviseSink::OnNotify method, NOTIFICATION structure


 IAddrBook::CompareEntryIDs

[New - Windows 95]

Compares two entry identifiers to determine if they refer to the same service provider object. MAPI only passes this call to a service provider if the unique identifiers (UIDs) in both entry identifiers to be compared are handled by that provider.

Syntax

HRESULT CompareEntryIDs(ULONG cbEntryID1, LPENTRYID lpEntryID1, ULONG cbEntryID2, LPENTRYID lpEntryID2, ULONG ulFlags, ULONG FAR * lpulResult)

Parameters

cbEntryID1

Input parameter containing the number of bytes in the lpEntryID1 parameter.

lpEntryID1

Input parameter pointing to the first entry identifier to be compared.

cbEntryID2

Input parameter containing the number of bytes in the lpEntryID2 parameter.

lpEntryID2

Input parameter pointing to the second entry identifier to be compared.

ulFlags

Reserved; must be zero.

lpulResult

Output parameter pointing to a variable that receives the result of the comparison; this variable is TRUE if the two entry identifiers refer to the same object and FALSE otherwise.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_UNKNOWN_ENTRYID

The requested entry identifier does not exist.

Comments

Use the IAddrBook::CompareEntryIDs method to compare two entry identifiers for a given address book provider object and determine whether they refer to the same object. If the two entry identifiers refer to the same object, then CompareEntryIDs sets the lpulResult parameter to TRUE; if they refer to different objects, CompareEntryIDs sets lpulResult to FALSE.

CompareEntryIDs is useful because an object can have more than one valid entry identifier; such a situation could occur, for example, after a new version of a service provider is installed.

If CompareEntryIDs returns an error, the calling application should make no assumptions about the comparison and should take the most conservative approach based on what your application is trying to do. CompareEntryIDs might fail if, for example, no provider has registered for one of the entry identifiers. If your application compares message-store entry identifiers when one or both of the stores has not yet opened, CompareEntryIDs returns the value MAPI_E_UNKNOWN_ENTRYID.


 IAddrBook::CreateOneOff

[New - Windows 95]

Creates an entry identifier for a custom recipient address.

Syntax

HRESULT CreateOneOff(LPTSTR lpszName, LPTSTR lpszAdrType, LPTSTR lpszAddress, ULONG ulFlags, ULONG FAR * lpcbEntryID, LPENTRYID FAR * lppEntryID)

Parameters

lpszName

Input parameter pointing to a string containing the display name of the recipient. lpszName can be NULL.

lpszAdrType

Input parameter pointing to a string containing the e-mail address type of the recipient; examples of e-mail address types are FAX, SMTP, X500, and so on. lpszAdrType cannot be NULL.

lpszAddress

Input parameter pointing to a string containing the e-mail address of the recipient. lpszAddress cannot be NULL.

ulFlags

Input parameter containing a bitmask of flags controlling the type of the passed-in strings. The following flag can be set:

MAPI_UNICODE

Indicates the passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

lpcbEntryID

Output parameter pointing to a variable in which the IAddrBook::CreateOneOff method returns the number of bytes in the entry identifier pointed to by the lppEntryID parameter.

lppEntryID

Output parameter pointing to a variable where the pointer to the entry identifier of the custom recipient address that has been created is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Service providers use the IAddrBook::CreateOneOff method to create an entry identifier for a custom recipient. A custom recipient is a message recipient that the user does not choose from an address book but specifies by typing in the recipient name. This entry identifier can be used as a valid recipient on a message.

When the provider is done using the entry identifier returned by CreateOneOff, it should free the allocated memory by using the MAPIFreeBuffer function.

See Also

MAPIFreeBuffer function


 IAddrBook::Details

[New - Windows 95]

Displays a details dialog box on a particular entry in an address book.

Syntax

HRESULT Details(ULONG FAR * lpulUIParam, LPFNDISMISS lpfnDismiss, LPVOID lpvDismissContext, ULONG cbEntryID, LPENTRYID lpEntryID, LPFNBUTTON lpfButtonCallback, LPVOID lpvButtonContext, LPTSTR lpszButtonText, ULONG ulFlags)

Parameters

lpulUIParam

Output parameter containing the handle to the parent window for the dialog box.

lpfnDismiss

Input parameter pointing to the address of a function based on the DISMISSMODELESS function prototype that is called when the modeless variety of the details dialog box is dismissed.

lpvDismissContext

Input parameter that is passed to the function specified by the lpfnDismiss parameter.

cbEntryID

Input parameter containing the number of bytes in the lpEntryID parameter.

lpEntryID

Input parameter pointing to the entry identifier for which the object's details are displayed.

lpfButtonCallback

Input parameter pointing to a pointer to a button callback function that adds a button to a dialog box.

lpvButtonContext

Input parameter pointing to data used as a parameter for the button callback function pointed to by the lpfButtonCallback parameter.

lpszButtonText

Input parameter pointing to a string containing the text to be applied to the button mentioned previously if that button is extensible. The lpszButtonText parameter should be NULL if an extensible button is not needed.

ulFlags

Input parameter containing a bitmask of flags controlling the type of the text for lpszButtonText. The following flag can be set:

MAPI_UNICODE

Indicates the passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Client applications use the IMAPISupport::Details methods to display a details dialog box on a particular entry in an address book. The lpfButtonCallback, lpvButtonContext, and lpButtonText parameters can be used to add a button it has defined to the addressing dialog box. When the button is chosen, MAPI calls the callback function pointed to by lpfButtonCallback, passing both the entry identifier of the chosen button and the data in lpvButtonContext. If an extensible button is not needed, lpszButtonText should be NULL.

The lpfnDismiss parameter is used to support the modeless version of the details address book. When the user dismisses the address book, MAPI calls IAddrBook::Details. The dismiss function used with Details is based on the function prototype DISMISSMODELESS.

See Also

DISMISSMODELESS function prototype, IAddrBook::Address method, IAddrBook::Details method, LPFNBUTTON function prototype


 IAddrBook::Details, LPFNBUTTON

[New - Windows 95]

The LPFNBUTTON function prototype represents a client application callback function that MAPI calls to hook to an optional button control on an address book dialog box. This button is typically a Details button.

Syntax

SCODE (STDMETHODCALLTYPE FAR * LPFNBUTTON)(ULONG ulUIParam, LPVOID lpvContext, ULONG cbEntryID, LPENTRYID lpSelection, ULONG ulFlags)

Parameters

ulUIParam

Input parameter specifying an implementation-specific 32-bit value normally used for passing user interface information to a function. For example, in Microsoft Windows this parameter is the parent window handle for the dialog box and is of type HWND (cast to a ULONG). A value of zero is always valid.

lpvContext

Input parameter specifying a pointer to an arbitrary value passed to the callback function when MAPI calls it. This value can represent an address of significance to the client application. Typically, for C++ code, lpvContext represents a pointer to the address of a C++ object.

cbEntryID

Input parameter specifying the size, in bytes, of the identifier indicated by lpSelection.

lpSelection

Input parameter specifying a pointer to an ENTRYID structure defining the selection within the dialog box.

ulFlags

Reserved; must be zero.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

This hook function can be used by a client application to define a button on the details dialog box. The client passes a pointer to the callback function in calls to IAdrBook::Details. When the dialog box is displayed and the user selects the defined button, MAPI calls this function.

See Also

BuildDisplayTable function, ENTRYID structure, IAddrBook::Details method


 IAddrBook::GetDefaultDir

[New - Windows 95]

Returns the default directory for the address book container.

Syntax

HRESULT GetDefaultDir(ULONG FAR * lpcbEntryID, LPENTRYID FAR * lppEntryID)

Parameters

lpcbEntryID

Output parameter pointing to a variable containing the number of bytes in the lpEntryID parameter.

lppEntryID

Output parameter pointing to a variable that receives a pointer to the default directory's entry identifier.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

The default directory is the directory the user sees displayed in the address book when the address book is first opened. MAPI determines the default directory if one has never been set by a previous call to the IAddrBook::SetDefaultDir method. MAPI selects the default directory by locating the first entry that contains names and is not the personal address book. If there are none, then the personal address book is set as the default directory.

Calls made to GetDefaultDir return a pointer in the lppEntryID parameter to the entry identifier of the default directory. MAPI allocates memory for this entry identifier with the MAPIAllocateBuffer function and your application must release it with the MAPIFreeBuffer function when done.

To set the default directory, your application calls the IAddrBook::SetDefaultDir method. Your application doesn't need to call the IMAPIProp::SaveChanges method to make directory changes permanent.

See Also

IAddrBook::SetDefaultDir method, MAPIAllocateBuffer function, MAPIFreeBuffer function, PR_CONTAINER_FLAGS property


 IAddrBook::GetPAB

[New - Windows 95]

Returns the directory designated as the personal address book (PAB).

Syntax

HRESULT GetPAB(ULONG FAR * lpcbEntryID, LPENTRYID FAR * lppEntryID)

Parameters

lpcbEntryID

Output parameter pointing to a variable containing the number of bytes in the entry identifier pointed to by the lppEntryID parameter.

lppEntryID

Output parameter pointing to a variable that receives a pointer to the personal address book's entry identifier. Returns a value of zero if no containers can be established as the personal address book.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

MAPI establishes a default personal address book if one has never been set in the profile. The default is determined by choosing the first container in the hierarchy that allows modifications.

Calls made to IAddrBook::GetPAB return the entry identifier of the personal address book's container in the lppEntryID parameter. MAPI allocates the memory for this entry identifier with the MAPIAllocateBuffer function and your application must release it with the MAPIFreeBuffer function when done.

See Also

MAPIAllocateBuffer function, MAPIFreeBuffer function, PR_CONTAINER_FLAGS property


 IAddrBook::GetSearchPath

[New - Windows 95]

Returns the search path that is used in ResolveNames methods.

Syntax

HRESULT GetSearchPath(ULONG ulFlags, LPSRowSet FAR * lppSearchPath)

Parameters

ulFlags

Input parameter containing a bitmask of flags used to control the type of the strings returned in the search path. The following flag can be set:

MAPI_UNICODE

Indicates the returned strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

lppSearchPath

Output parameter pointing to the variable that receives an SRowSet structure containing information about the search path. If there are no containers in the hierarchy, zero is returned in the SRowSet.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Use the IAddrBook::GetSearchPath method to get the search path that is used in ResolveNames methods. If SetSearchPath has never been called, GetSearchPath build a search path by working through the address book's hierarchy tables (this is the default behavior of GetSearchPath). The search path starts with the first address book with read-write access, usually the user's personal address book, followed by every address book container that has a PR_DISPLAY_TYPE property set to the DT_GLOBAL flag. (If a container's PR_DISPLAY_TYPE is set to DT_GLOBAL, it indicates that it contains a global address list which holds recipients.) If GetSearchPath does not find a global address book using this search path, then the default directory is added to the search path list, providing that the default directory is not the first container with read-write access.

If SetSearchPath has been called, GetSearchPath forms a search path using the address book containers that have been stored in the user's profile. The search path obtained from the user's profile is validated against the hierarchy table for the session's address book before GetSearchPath returns the search path to the calling application. After the first call to SetSearchPath, subsequent calls to SetSearchPath must be used to modify the search path returned by GetSearchPath. In other words, your application does not receive the default search path after the first call to SetSearchPath.

See Also

IAddrBook::SetSearchPath method, SRowSet structure


 IAddrBook::NewEntry

[New - Windows 95]

Displays a dialog box for creating new entries within containers or custom recipient addresses within messages.

Syntax

HRESULT NewEntry(ULONG ulUIParam, ULONG ulFlags, ULONG cbEIDContainer, LPENTRYID lpEIDContainer, ULONG cbEIDNewEntryTpl, LPENTRYID lpEIDNewEntryTpl, ULONG FAR * lpcbEIDNewEntry, LPENTRYID FAR * lppEIDNewEntry)

Parameters

ulUIParam

Input parameter containing the handle to the window that the dialog box is modal to.

ulFlags

Reserved; must be zero.

cbEIDContainer

Input parameter containing the number of bytes in the entry identifier in the lpEIDContainer parameter.

lpEIDContainer

Input parameter pointing to the container where the new custom recipient address will be added. If the value in cbEIDContainer is zero, NewEntry returns a recipient entry identifier and a list of templates as if your application called IAddrBook::CreateOneOff.

cbEIDNewEntryTpl

Input parameter containing the number of bytes in the entry identifier in the lpEIDNewEntryTpl parameter.

lpEIDNewEntryTpl

Input parameter pointing to a template to be used to create the new custom recipient address. If the value in cbEIDNewEntryTpl is zero, passing NULL in the lpEIDNewEntryTpl parameter displays a dialog box enabling the user to select an address-creation template from among the address types that can be created in the container.

lpcbEIDNewEntry

Output parameter pointing to a variable containing the number of bytes in the entry identifier in the lppEIDNewEntry parameter.

lppEIDNewEntry

Output parameter pointing to a variable where the pointer to the entry identifier for the new custom recipient address is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

The IAddrBook::NewEntry method can be used in several different modes. To add a custom recipient address directly to the open message and not to a modifiable container, your provider passes zero in the cbEIDContainer parameter and NULL in the lpEIDContainer parameter. To display a dialog box enabling the user to select a template for adding custom recipients to a modifiable container, your application passes zero in the cbEIDNewEntryTpl parameter and NULL in the lpEIDNewEntryTpl parameter.

To create an entry in a modifiable address book and not get the entry identifier back, pass the container's entry identifier in the lpEIDContainer, zero in cbEIDContainer, and NULL for the rest of the parameters.

To open a specific custom-recipient dialog box directly, so that users enter custom recipients in their personal address books using a predetermined template, your application uses the following series of calls. First, it calls the IAddrBook::OpenEntry method and passes in either the entry identifier of a modifiable container or zero. Doing so opens the root folder of the address book container. Next, your application calls the IABContainer::OpenProperty method and passes the PR_CREATE_TEMPLATES property in the ulPropTag parameter so that it can open the property. Doing this returns a table object that lists the types of objects that can be created in the address book container. Your application finds in this table the entry identifier for the template you want new entries to be created with. Then, your application calls NewEntry and passes NULL in the lpEIDContainer parameter and the entry identifier for the entry-creation template you want used in the lpEIDNewEntryTpl parameter.

Calls made to NewEntry return the entry identifier of the new custom recipient address in the lppEIDNewEntry parameter (unless your application passed NULL in lppEIDNewEntry). Your client application is responsible for freeing the returned entry identifier by calling the MAPIFreeBuffer function.

See Also

IAddrBook::OpenEntry method, IMAPIProp::OpenProperty method, PR_CREATE_TEMPLATES property


 IAddrBook::OpenEntry

[New - Windows 95]

Opens a container or recipient object and returns a pointer to the object to provide further access. A recipient can be either a messaging user or a distribution list.

Syntax

HRESULT OpenEntry(ULONG cbEntryID, LPENTRYID lpEntryID, LPCIID lpInterface, ULONG ulFlags, ULONG FAR * lpulObjType, LPUNKNOWN FAR * lppUnk)

Parameters

cbEntryID

Input parameter containing the number of bytes in the lpEntryID parameter.

lpEntryID

Input parameter pointing to the address of the entry identifier for the opened object.

lpInterface

Input parameter pointing to the interface identifier (IID) for the object. The value NULL indicates the MAPI interface for the given object will be returned. The parameter can also be set to an identifier for another appropriate interface for the object.

ulFlags

Input parameter containing a bitmask of flags used to control how the object is opened. The following flags can be set:

MAPI_BEST_ACCESS

Indicates the object should be opened with the maximum privileges allowed to the user. For example, if the client application has write privilege, open the object with write privilege; if the client application has read-only privilege, open the object with read-only privilege. The client application can learn the privilege by getting the property PR_ACCESS_LEVEL.

MAPI_DEFERRED_ERRORS

Indicates the call is allowed to succeed even if the underlying object is not accessible to the calling application. If the object is not accessible, some subsequent call to the object might return an error.

MAPI_MODIFY

Requests write access. By default, objects are created with read-only access, and client applications should not assume that write access was granted.

lpulObjType

Output parameter pointing to a variable where the object type for the opened object is stored.

lppUnk

Output parameter pointing to a variable where the pointer to the opened object is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NO_ACCESS

An attempt to modify a read-only object or an attempt to access an object for which the user has insufficient permissions.

MAPI_E_UNKNOWN_ENTRYID

The object indicated in the lpEntryID parameter is not recognized. This return value is typically returned if the address book provider that the object is contained within is not open.

MAPI_E_NOT_FOUND

The object indicated in the lpEntryID parameter does not exist.

Comments

Use the IAddrBook::OpenEntry method to open a container or recipient. Default behavior is to open the object as read-only, unless the call sets the MAPI_MODIFY or MAPI_BEST_ACCESS flag in the ulFlags parameter. If the address book provider does not allow modification for the object requested, then it returns MAPI_E_NO_ACCESS.

The lpInterface parameter indicates which interface should be used on the opened object. Passing NULL in lpInterface indicates the standard MAPI interface for that type of object should be used.

The calling application should check the value returned in the lpulObjType parameter to determine that the object type returned is what was expected. Commonly, after the application checks the type of the object, it then casts the pointer in the lppUnk parameter into a message object pointer, a folder object pointer, or another appropriate object pointer.


 IAddrBook::PrepareRecips

[New - Windows 95]

Prepares a recipient list for later use by the messaging system. Converts recipients' short-term entry identifiers to long-term entry identifiers, updates those recipients that belong to this address book provider, and, if necessary, retrieves those recipients' permanent entry identifiers along with any additional properties requested.

Syntax

HRESULT PrepareRecips(ULONG ulFlags, LPSPropTagArray lpPropTagArray, LPADRLIST lpRecipList)

Parameters

ulFlags

Reserved; must be zero.

lpPropTagArray

Input parameter pointing to a counted array of property tags for the properties that require updating by the calling application. The lpPropTagArray parameter can be NULL.

lpRecipList

Input parameter pointing to an ADRLIST structure holding the list of recipients.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NOT_FOUND

The requested object does not exist.

Comments

The IAddrBook::PrepareRecips method is called to ensure that all recipients your address book provider recognizes have permanent entry identifiers and that they have all the properties requested in the lpPropTagArray parameter. Within an individual recipient entry, the requested properties are ordered first, followed by any additional properties that were already present for the entry. If one or more of the requested properties are not recognized by your provider, it should set their property types to PT_ERROR and their property values either to MAPI_E_NOT_FOUND or to another value giving a more specific reason why the property is not available to the calling application.

Like the ADRLIST structure, each SPropValue property value structure passed in the lpPropTagArray parameter must be separately allocated using MAPIAllocateBuffer and MAPIAllocateMore such that it can be freed individually. If the provider must allocate additional space for any SPropValue structure, for example to store the data for a string property, it can use MAPIAllocateBuffer to allocate additional space for the full property-tag array, use the MAPIFreeBuffer function to free the original property-tag array, and then use MAPIAllocateMore to allocate any additional memory required.

See Also

ADRLIST structure, IMAPIProp::GetProps method, IMessage::ModifyRecipients method, PR_ENTRYID property, PT_ERROR property type, SPropValue structure, SRowSet structure


 IAddrBook::QueryDefaultRecipOpt

[New - Windows 95]

Returns the available recipient options for a particular messaging address type, with defaults.

Syntax

HRESULT QueryDefaultRecipOpt(LPTSTR lpszAdrType, ULONG ulFlags, ULONG FAR * lpcValues, LPSPropValue FAR * lppOptions)

Parameters

lpszAdrType

Input parameter pointing to a string containing the messaging address type for which the options dialog box should be displayed; examples of e-mail address types are FAX, SMTP, X500, and so on. The lpszAdrType parameter's value must not be NULL.

ulFlags

Input parameter containing a bitmask of flags used to control the type of the passed-in strings. The following flag can be set:

MAPI_UNICODE

Indicates the passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

lpcValues

Output parameter pointing to a variable containing the number of returned property values in the lppOptions parameter.

lppOptions

Output parameter pointing to a pointer to SPropValue structures containing available recipient options and their defaults.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Use the IAddrBook::QueryDefaultRecipOpt method to return the recipient options available for a particular messaging address type and set those options to the default values. Recipient options are the properties of a recipient that govern its behavior after an application submits a message. Recipient options are usually, but not always, specific to a particular address type.

Client applications call the IAddrBook::QueryDefaultRecipOpt method to get the set of default recipient options for a particular recipient type. These options are registered by transport providers using the IXPLogon::RegisterOptions method. If client applicants want to display a dialog box to enable the user to select recipient options, call the IAddrBook::RecipOptions method. In addition to being applied to recipients, such options can be applied to an entire message as a default for all the message's recipients; for more information, see the IMAPISession::MessageOptions method.

See Also

IAddrBook::RecipOptions method, IMAPISession::MessageOptions method, IMAPISession::QueryDefaultMessageOpt method


 IAddrBook::RecipOptions

[New - Windows 95]

Displays a modal per-recipient options dialog box on a particular recipient.

Syntax

HRESULT RecipOptions(ULONG ulUIParam, ULONG ulFlags, LPADRENTRY lpRecip)

Parameters

ulUIParam

Input parameter containing the handle of the window the dialog box is modal to.

ulFlags

Reserved; must be zero.

lpRecip

Input parameter pointing to the ADRENTRY structure for the recipient whose options are to be displayed or set.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_W_ERRORS_RETURNED

The call succeeded overall, but there are no recipient options for this type of recipient. Use the HR_FAILED macro to test for this warning, but the call should be handled as a successful return. .

Comments

Use the IAddrBook::RecipOptions method to display a dialog box to get settings for recipient options from the user. Recipient options are the properties of a recipient governing its behavior after the application submits a message. Recipient options are usually, but not always, specific to a particular address type. The IAddrBook::RecipOptions method returns a new ADRENTRY structure containing the recipient options selected by the user.

If you want to get the set of default recipient options without presenting a dialog box to the user, call the IAddrBook::QueryDefaultRecipOpt method instead. If any recipient options are changed on a RecipOptions call, MAPI frees the old SPropValue property value structures for those options within the recipient's ADRENTRY structure and allocates new ones.

The PR_DISPLAY_NAME, PR_ADDRTYPE and PR_ENTRYID properties must be present for any recipient entry. Other useful properties for recipient option ADRENTRY structures are PR_SEARCH_KEY and PR_EMAIL_ADDRESS.

If there are no recipient options available for the address type indicated in the lpRecip parameter, the warning MAPI_W_ERRORS_RETURNED is returned, indicating there was an error returned for the RecipOptions call. Calling the IMAPIProp::GetLastError method returns a text string describing the warning.

In addition to being applied to recipients, such options can be applied to an entire message, as a default for all the message's recipients; for more information, see the IMAPISession::MessageOptions method.

See Also

ADRENTRY structure, IAddrBook::QueryDefaultRecipOpt method, IMAPISession::MessageOptions method, IMAPISession::QueryDefaultMessageOpt method, SPropValue structure


 IAddrBook::ResolveName

[New - Windows 95]

Displays a dialog box for locating a recipient given a partial name.

Syntax

HRESULT ResolveName(ULONG ulUIParam, ULONG ulFlags, LPTSTR lpszNewEntryTitle, LPADRLIST lpAdrList);

Parameters

ulUIParam

Input parameter whose usage depends on the platform. On Windows platforms, the ulUIParam parameter is the handle to the main window of the calling application, cast to a ULONG.

ulFlags

Input parameter that is a bitmask of flags that determine whether a name-resolution dialog box is displayed. The following flag can be set:

MAPI_DIALOG

Displays a dialog box to provide status or prompt the user for additional information, such as recipients, sending options, or name resolution. If this flag is not set, no dialog box is displayed.

lpszNewEntryTitle

Input parameter pointing to a string containing text for the title of the control in the name-resolution dialog box that prompts the user to enter a recipient entry. The title string contents vary depending on the entry type. The lpszNewEntryTitle parameter can be NULL.

lpAdrList

Input parameter pointing to a list of names to be matched to recipients.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_AMBIGUOUS_RECIP

The requested recipient matched more than one entry identifier. Usually this value is returned when a dialog box allowing the user to select the correct recipient could not be displayed because the MAPI_DIALOG flag was not set in the ulFlags parameter.

MAPI_E_NOT_FOUND

The name doesn't match any recipients.

Comments

The IAddrBook::ResolveName method goes through the address list, and finds all the names not yet resolved, resolves them, and returns the appropriately modified recipient address list. The address list can be one that was originally created using the IAddrBook::Address method.

Entries in the lpAdrList parameter that are lacking the PR_ENTRYID property are considered unresolved.

If a name cannot be resolved because there are multiple matches and because the client application has instructed MAPI not to display a name-resolution dialog box (by not setting the MAPI_DIALOG flag in the ulFlags parameter), ResolveName returns the value MAPI_E_AMBIGUOUS_RECIP in the lpAdrList parameter. If a name cannot be resolved because there are no matches for it, ResolveName returns the value MAPI_E_NOT_FOUND in lpAdrList. If there are some names with multiple matches and some names without matches, ResolveName can return either error value.

See Also

ADRLIST structure, IABContainer::ResolveNames method, IAddrBook::Address method


 IAddrBook::SetDefaultDir

[New - Windows 95]

Chooses a different directory as the default directory for the address book container.

Syntax

HRESULT SetDefaultDir(ULONG cbEntryID, LPENTRYID lpEntryID)

Parameters

cbEntryID

Input parameter containing the number of bytes in the lpEntryID parameter.

lpEntryID

Input parameter pointing to the entry identifier of the default directory.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

The default directory is the directory the user sees displayed in the address book when the address book is first opened. The IAddrBook::SetDefaultDir method sets the default directory in the profile. The directory is saved within the profile between instances of a session, so after a call to the IMAPISession::Logoff method, subsequent calls to the MAPILogonEx function during the same session return the same default directory as previously set, as long as that directory still exists.

Your application doesn't need to call the IAddrBook::SaveChanges method to make the directory change permanent.

See Also

IAddrBook::GetDefaultDir method, IAddrBook::GetSearchPath method, IMAPISession::Logoff method, MAPILogonEx function


 IAddrBook::SetPAB

[New - Windows 95]

Designates a particular container to be the personal address book.

Syntax

HRESULT SetPAB(ULONG cbEntryID, LPENTRYID lpEntryID)

Parameters

cbEntryID

Input parameter containing the number of bytes in the lpEntryID parameter.

lpEntryID

Input parameter pointing to the entry identifier of the personal address book. If NULL is passed, the IAddrBook::SetPAB method returns the value MAPI_E_INVALID_ENTRYID.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Use the IAddrBook::SetPAB method to designate a particular container to be the personal address book. This is the container where new entries are added. The directory is saved between instances of a session, so after a call to the IMAPISession::Logoff method, subsequent calls to the MAPILogonEx function during the same session return the same default directory as previously set, as long as that directory still exists.

Your application doesn't need to call the IMAPIProp::SaveChanges method to make the personal address book change permanent.

See Also

IAddrBook::GetPAB method, IAddrBook::GetSearchPath method, PR_CONTAINER_FLAGS property


 IAddrBook::SetSearchPath

[New - Windows 95]

Sets the path that is used in ResolveNames methods.

Syntax

HRESULT SetSearchPath(ULONG ulFlags, LPSRowSet lpSearchPath)

Parameters

ulFlags

Reserved; must be zero.

lpSearchPath

Input parameter pointing to the SRowSet structure used to hold information about the search path.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_MISSING_REQUIRED_COLUMN

The SRowSet structure must contain the PR_ENTRYID property as the first column in the row set.

Comments

The IAddrBook::SetSearchPath method saves changes made to the container search order that is used for ResolveNames methods. The directory is saved between instances of a session, so after a call to the IMAPISession::Logoff method, subsequent calls to the MAPILogonEx function during the same session return the same default directory as previously set, as long as that directory still exists.

Your application doesn't need to call the IMAPIProp::SaveChanges method to make the search path changes permanent.

See Also

IAddrBook::GetDefaultDir method, IAddrBook::GetPAB method, IAddrBook::GetSearchPath method, PR_CONTAINER_FLAGS property


 IAddrBook::Unadvise

[New - Windows 95]

Removes an object's registration for notification of address book changes previously established with a call to the IAddrBook::Advise method.

Syntax

HRESULT Unadvise(ULONG ulConnection)

Parameters

ulConnection

Input parameter containing the number of the registration connection returned by IAddrBook::Advise.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Client applications use the IAddrBook::Unadvise method to release the pointer to the advise sink object that was passed in the lpAdviseSink parameter in the previous call to IAddrBook::Advise, thereby canceling a notification registration. As part of discarding the pointer to advise sink object, the object's IUnknown::Release method is called. Generally, Release is called during the Unadvise call, but if another thread is in the process of calling IMAPIAdviseSink::OnNotify on the advise sink object, the Release call is delayed until the OnNotify method returns.

See Also

IAddrBook::Advise method, IMAPIAdviseSink::OnNotify method


 IAttach : IMAPIProp

[New - Windows 95]

The IAttach interface has no unique methods of its own; methods inherited from the IMAPIProp interface can be called through IAttach for use with attachment objects. For more information about using attachment objects, see MAPI Programmer's Guide.

At a Glance

Specified in header file:	MAPIDEFS.H
Object that supplies this interface:	Attachment object
Corresponding pointer type:	LPATTACH
Implemented by:	Message store providers
Called by:	Client applications
Vtable Order

No unique methods


 IDistList : IMAPIContainer

[New - Windows 95]

The IDistList interface is used to provide further access to distribution lists within address book containers that are modifiable. IDistList can make such changes as creating, copying and deleting distribution lists, in addition to performing bulk searches. The methods of the IDistList interface are identical to those of the IABContainer interface and are not redocumented here. For further information on using the methods shown in the IDistList vtable section, see the reference entries for IABContainer. For more information on working with distribution list objects, see MAPI Programmer's Guide.

At a Glance

Specified in header file:	MAPIDEFS.H
Object that supplies this interface:	Distribution list object
Corresponding pointer type:	LPDISTLIST
Implemented by:	Address book providers
Called by:	Extended MAPI client applications
Vtable Order

CreateEntry	Creates a new distribution list in an address book container that supports modification.
CopyEntries	Copies one or more distribution lists into an address book container that supports modification.
DeleteEntries	Removes distribution lists from the address book container.
ResolveNames	Resolves entries from an address book container.


 IMailUser : IMAPIProp

[New - Windows 95]

The IMailUser interface has no unique methods of its own; methods inherited from the IMAPIProp interface can be called through IMailUser for use with mail user objects. For more information about using mail user objects, see MAPI Programmer's Guide.

At a Glance

Specified in header file:	MAPIDEFS.H
Object that supplies this interface:	Messaging user object
Corresponding pointer type:	LPMAILUSER
Implemented by:	Address book providers
Called by:	Client applications
Vtable Order

No unique methods


 IMAPIAdviseSink : IUnknown

[New - Windows 95]

The IMAPIAdviseSink interface is used to implement an advise sink for receiving notification events. Typically, the client application creates a different advise sink object each time it registers an object for notification about changes to another object (that is, for each call to an Advise method). The application chooses what data is retained in the advise sink object's internal data structures, and it controls what the IMAPIAdviseSink::OnNotify method does when a notification event occurs. For more information on IMAPIAdviseSink::OnNotify, see its reference entry.

At a Glance

Specified in header file:	MAPIDEFS.H
Object that supplies this interface:	Advise sink object
Corresponding pointer type:	LPMAPIADVISESINK
Implemented by:	Client applications
Called by:	Service providers and MAPI
Vtable Order

OnNotify	Informs a client application that one or more notification events of the type indicated by the event mask passed in a previous Advise call has occurred.


 IMAPIAdviseSink::OnNotify

[New - Windows 95]

Informs a client application that one or more notification events of the type indicated by the event mask passed in a previous Advise call has occurred.

Syntax

HRESULT OnNotify(ULONG cNotif, LPNOTIFICATION lpNotifications)

Parameters

cNotif

Input parameter containing the number of NOTIFICATION structures pointed to by the lpNotifications parameter.

lpNotifications

Input parameter pointing to the NOTIFICATION structures that describe the events that have occurred.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Service providers call the IMAPIAdviseSink::OnNotify method of a client application's advise sink object when changes occur to an object or a table for which notifications have been requested.

Each notification describes a separate event. In the lpNotifications parameter, the client application passes a NOTIFICATION structure; the type of each specific event is indicated within a substructure of that NOTIFICATION. The contents of the NOTIFICATION thus vary depending on the event type; not all members of the NOTIFICATION are used for each event type. The following table lists the possible event types along with their corresponding substructures within NOTIFICATION:

Notification event type	Corresponding data structure
fnevCriticalError	ERROR_NOTIFICATION
fnevNewMail	NEWMAIL_NOTIFICATION
fnevObjectCreated	OBJECT_NOTIFICATION
fnevObjectDeleted	OBJECT_NOTIFICATION
fnevObjectModified	OBJECT_NOTIFICATION
fnevObjectCopied	OBJECT_NOTIFICATION
fnevSearchComplete	OBJECT_NOTIFICATION
fnevTableModified	TABLE_NOTIFICATION
fnevStatusObjectModified	STATUS_OBJECT_NOTIFICATION
fnevExtended	EXTENDED_NOTIFICATION
The application should not modify or free the NOTIFICATION structure passed to OnNotify. The data in the structure is valid only until the OnNotify returns.

The notifications generated by a single MAPI call, such as a call to the IMAPIFolder::CopyMessages method, can be delivered in one or multiple calls to OnNotify depending upon the provider implementation and on memory constraints. The notifications of multiple MAPI calls can be also combined and delivered in one call to OnNotify, depending upon the provider implementation.

A typical advise sink object is one associated with a dialog box with which a user browses the contents of a folder in a message store. Commonly, such an advise sink object has internal data structures that reference the dialog box on the screen and data structures describing the contents of the dialog box. The OnNotify method of such an advise sink object typically sends a Windows message to the dialog box indicating how it should update itself.

During an Advise call, the IUnknown::AddRef method is called to update the reference count for the advise sink object. The application retains the notification connection number returned in the ulConnection parameter by Advise. When the application no longer requires notifications, it calls the Unadvise method, which then calls the IUnknown::Release method of the advise sink object. Generally, Release is called during the Unadvise call, but if another thread is in the process of calling OnNotify on the advise sink object, the Release call is delayed until the OnNotify method returns.

The timing of a call to OnNotify depends on your provider's implementation. It can occur during the MAPI call that caused the event, or it can occur at some later time. On systems that support multiple threads of execution, calls to OnNotify can occur in a different execution thread than the Advise call that registered the notification. For a way to turn a call to OnNotify that might happen at an inopportune time into one that is safer to handle, your provider should use the HrThisThreadAdviseSink function.

For more information about setting up and stopping notifications, see the reference entries for the Advise and Unadvise methods for any of the following interfaces: IABLogon, IAddrBook, IMAPIForm, IMAPISession, IMAPITable, IMsgStore, and IMSLogon.

See Also

HrAllocAdviseSink function, HrThisThreadAdviseSink function, IMAPISupport::Notify method, NOTIFICATION structure


 IMAPIContainer : IMAPIProp

[New - Windows 95]

The IMAPIContainer interface manages high-level operations on container objects such as address books, distribution lists, and folders. The IMAPIFolder, IABContainer and IDistList interfaces are derived from IMAPIContainer.

At a Glance

Specified in header file:	MAPIDEFS.H
Object that supplies this interface:	Folder, address book container, or distribution list
Corresponding pointer type:	LPMAPICONTAINER
Implemented by:	Message store, address book, and remote transport providers
Called by:	Client applications
Vtable Order

GetContentsTable	Returns a pointer to the contents table of a container.
GetHierarchyTable	Returns a pointer to a hierarchy table object, which holds hierarchically grouped information about the child containers in the current container.
OpenEntry	Opens a message or child container object contained in the currently open container and returns a pointer to the object to provide further access.
SetSearchCriteria	Sets the search criteria for a particular search-results container.
GetSearchCriteria	Obtains the search criteria for a particular search results container.


 IMAPIContainer::GetContentsTable

[New - Windows 95]

Returns a pointer to the contents table of a container.

Syntax

HRESULT GetContentsTable(ULONG ulFlags, LPMAPITABLE FAR * lppTable)

Parameters

ulFlags

Input parameter containing a bitmask of flags used to control how the contents table is returned. The following flags can be set:

MAPI_ASSOCIATED

Used with folders, but not address book containers or distribution lists. Indicates the provider should return the table of associated entries rather than the standard table. The "associated entries" contents table is completely separate from the standard contents table, and client applications can (for example) use this table to retrieve forms and views.

MAPI_DEFERRED_ERRORS

Indicates the call is allowed to succeed even if the underlying object is not accessible to the calling application. If the object is not accessible, some subsequent call to the object might return an error.

MAPI_UNICODE

Indicates the returned strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

lppTable

Output parameter pointing to a variable where the pointer to the contents table is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_BAD_CHARWIDTH

Either the MAPI_UNICODE flag was set and the implementation does not support Unicode, or MAPI_UNICODE was not set and the implementation only supports Unicode.

MAPI_E_NO_SUPPORT

The table has no content.

Comments

Use the IMAPIContainer::GetContentsTable method to get a pointer to the contents table for a container. The returned table contains the default column set for that table. To examine the information the contents table holds, your application can use the methods of the IMAPITable interface.

Address book contents tables  typically contain the following property columns:

PR_ADDRTYPE

The address type for the entry.

PR_DISPLAY_NAME

The object's display name.

PR_DISPLAY_TYPE

Integer mapping the entry to its associated icon or other display element.

PR_ENTRYID

The object's entry identifier.

PR_INSTANCE_KEY

The search key for the row.

PR_OBJECT_TYPE

Indicate the type of the MAPI object.

Folder contents tables  typically contain the following property columns:

PR_CLIENT_SUBMIT_TIME

Contains the time the message sender marked the message for submission.

PR_DISPLAY_TO

The names of the message's primary recipients.

PR_ENTRYID

The object's entry identifier.

PR_HASATTACH

Indicates whether the message contains any attachments.

PR_INSTANCE_KEY

The search key for the row.

PR_LAST_MODIFICATION_TIME

The data and time when the object was last modified.

PR_MAPPING_SIGNATURE

Contains the mapping signature for named properties of the object.

PR_MESSAGE_CLASS

Contains a text string identifying the sender-defined message class for the message.

PR_MESSAGE_DELIVERY_TIME

Contains the date and time when the message was delivered by a transport provider.

PR_MESSAGE_FLAGS

Contains a bitmask of flags indicating the current state of the message.

PR_MESSAGE_SIZE

The approximate size, in bytes, of the data transferred if the message is moved from one message store to another.

PR_MSG_STATUS

Contains a bitmask of client application or service provider-defined flags describing the status of the message.

PR_NORMALIZED_SUBJECT

The subject of a message with any reply of forwarding prefixes removed.

PR_OBJECT_TYPE

The type of an object, such as folder, message, distribution list, and so on.

PR_PARENT_ENTRYID

The entry identifier containing the message object.

PR_PRIORITY

The relative priority of a message.

PR_RECORD_KEY

A unique binary-comparable identifier for an object.

PR_SENDER_NAME

The message sender's display name as set by the transport provider handling the message.

PR_SENSITIVITY

The message sender's opinion about the sensitivity of the message.

PR_STORE_ENTRYID

The unique entry identifier for the message store where the object resides.

PR_STORE_RECORD_KEY

A unique binary-comparable identifier for the message store in which the object resides.

PR_SUBJECT

The subject of a message.

Providers that implement GetContentsTable must also support client application calls to the IMAPIProp::OpenProperty method attempting to open the PR_CONTAINER_CONTENTS property. Providers must also return PR_CONTAINER_CONTENTS with any IMAPIProp::GetProps or IMAPIProp::GetPropList calls.

Strings in contents table columns returned by GetContentsTable might be truncated at 255 characters by service providers. To determine whether a string within a column is truncated, a client application should check all strings exactly 255 characters in length by opening the column entry from which the string came and checking the corresponding property. Depending on your application's implementation, restrictions and sorting operations can apply to an entire string or to the truncated version of that string.

Setting the MAPI_UNICODE flag in the ulFlags parameter does the following:

•	Sets the string type to Unicode for data returned for the initial active columns of the contents table by the IMAPITable::QueryColumns method. The initial active columns for a contents table are those columns the QueryColumns method returns before the application that contains the content stable calls the IMAPITable::SetColumns method.

•	Sets the string type to Unicode for data returned for the initial active rows of the contents table by the IMAPITable::QueryRows method. The initial active rows for a contents table are those rows QueryRows returns before the application that contains the contents table calls the IMAPITable::SetColumns method.

•	Controls the property types of the sort order specification returned by the IMAPITable::QuerySortOrder method before the application that contains the contents table calls the IMAPITable::SortTable method.

See Also

IMAPIProp::GetPropList method, IMAPIProp::GetProps method, IMAPIProp::OpenProperty method, IMAPITable : IUnknown interface, PR_CONTAINER_CONTENTS property


 IMAPIContainer::GetHierarchyTable

[New - Windows 95]

Returns a pointer to a hierarchy table object, which holds hierarchically grouped information about the child containers in the current container.

Syntax

HRESULT GetHierarchyTable(ULONG ulFlags, LPMAPITABLE FAR * lppTable)

Parameters

ulFlags

Input parameter containing a bitmask of flags used to control how information is returned from the table. The following flags can be set:

CONVENIENT_DEPTH

Fills the hierarchy table with containers from one or more levels. The PR_DEPTH property in each row indicates the depth, relative to the open container, of the given child container. The open container's immediate child containers are at depth zero. If the flag CONVENIENT_DEPTH is not given, the table contains the immediate child containers only.

MAPI_DEFERRED_ERRORS

Indicates the call is allowed to succeed even if the underlying object is not accessible to the calling application. If the object is not accessible, some subsequent call to the object might return an error.

MAPI_UNICODE

Indicates the returned strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

lppTable

Output parameter pointing to a variable where the pointer to the hierarchy table is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_BAD_CHARWIDTH

Either the MAPI_UNICODE flag was set and the implementation does not support Unicode, or MAPI_UNICODE was not set and the implementation only supports Unicode.

MAPI_E_NO_SUPPORT

The table has contents but no folders.

Comments

Use the IMAPIContainer::GetHierarchyTable method to get a pointer to a hierarchy table object, which holds information about the child containers in the current container. To examine the information the hierarchy table holds, your application can use the methods of the IMAPITable interface.

Each row of the hierarchy table contains a set of columns holding information about one child container. The hierarchy table can include all columns visible in the current table view, but for many tables the initial active columns are those that most implementations can produce quickly. The initial active columns for a hierarchy table are those columns the IMAPITable::QueryColumns method returns before the application that contains the hierarchy table calls the IMAPITable::SetColumns method. The initial active columns for a newly opened address book hierarchy table must include at least the following property columns:

PR_CONTAINER_FLAGS

Flags describing the address book container.

PR_DEPTH

The relative depth of indentation of the child container's name in the hierarchy table. The depth is zero-based, with zero being leftmost.

PR_DISPLAY_NAME

The child container's display name.

PR_DISPLAY_TYPE

Integer mapping the entry to its associated icon or other display element.

PR_ENTRYID

The child container's entry identifier.

PR_INSTANCE_KEY

The search key for the row.

PR_OBJECT_TYPE

Indicate the type of the MAPI object.

PR_AB_PROVIDER_ID

Identifier indicating the address book provider responsible for the data in the address book.

Hierarchy tables for folders typically include the following property columns:

PR_DEPTH

The relative depth of indentation of the child container's name in the hierarchy table. The depth is zero-based, with zero being leftmost.

PR_DISPLAY_NAME

The child container's display name.

PR_COMMENT

A messaging user- defined comment about the purpose or content of the child container.

PR_ENTRYID

The child container's entry identifier.

PR_INSTANCE_KEY

The search key for the row.

PR_STATUS

A bitmask of flags defining the child container's status. PR_STATUS only applies to folders.

PR_SUBFOLDERS

A property that contains TRUE if the child container contains subfolders, and FALSE otherwise. PR_SUBFOLDERS only applies to folders.

PR_FOLDER_TYPE

A property that indicates whether the child container is a root folder, a normal folder, or a search-results folder. PR_FOLDER_TYPE only applies to folders.

PR_SUBJECT

The subject of the entry.

Providers that implement GetHierarchyTable must also support client application calls to the IMAPIProp::OpenProperty method attempting to open the PR_CONTAINER_HIERARCHY property. Providers must also return PR_CONTAINER_HIERARCHY with any IMAPIProp::GetProps or IMAPIProp::GetPropList call.

Strings in hierarchy table columns returned by GetHierarchyTable might be truncated at 255 characters by service providers. To determine whether a string within a column is truncated, a client application should check all strings exactly 255 characters in length by opening the column entry from which the string came and checking the corresponding property. Depending on a provider's implementation, restrictions and sorting operations can apply to an entire string or to the truncated version of that string.

Setting the MAPI_UNICODE flag in the ulFlags parameter does the following:

•	Sets the string type to Unicode for data returned for the initial active columns of the hierarchy table by the IMAPITable::QueryColumns method. The initial active columns for a hierarchy table are those columns the QueryColumns method returns before the application that contains the hierarchy table calls the IMAPITable::SetColumns method.

•	Sets the string type to Unicode for data returned for the initial active rows of the hierarchy table by the IMAPITable::QueryRows method. The initial active rows for a hierarchy table are those rows QueryRows returns before the application that contains the hierarchy table calls the IMAPITable::SetColumns method.

•	Controls the property types of the sort order specification returned by the IMAPITable::QuerySortOrder method before the application that contains the hierarchy table calls the IMAPITable::SortTable method.

See Also

IMAPIProp::GetPropList method, IMAPIProp::GetProps method, IMAPITable : IUnknown interface, PR_CONTAINER_HIERARCHY property


 IMAPIContainer::GetSearchCriteria

[New - Windows 95]

Obtains the search criteria for a particular search results container.

Syntax

HRESULT GetSearchCriteria(ULONG ulFlags, LPSRestriction FAR * lppRestriction, LPENTRYLIST FAR * lppContainerList, ULONG FAR * lpulSearchState)

Parameters

ulFlags

Input parameter containing a bitmask of flags. The following flag can be set:

MAPI_UNICODE

Indicates the passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

lppRestriction

Output parameter pointing to a pointer to a structure holding the restriction criteria that defines the conditions of the search. If your application passes NULL in the lppRestriction parameter, the IMAPIContainer::GetSearchCriteria method returns no restriction set.

lppContainerList

Output parameter pointing to a pointer to a structure that lists the entry identifiers included in the search. If your application passes NULL in the lppContainerList parameter, GetSearchCriteria doesn't return an entry identifier list.

lpulSearchState

Output parameter containing a bitmask of flags used to indicate the current state of the search. If your application sends NULL in the lpulSearchState parameter, GetSearchCriteria doesn't return any flags. The following flags can be set for lpulSearchState:

SEARCH_FOREGROUND

Indicates the search will run at high priority relative to other searches. If this flag is not set it means that the search will run at normal priority relative to other searches.

SEARCH_REBUILD

Indicates the search is in the CPU-intensive mode of its operation, attempting to bring in all current messages that match the criteria. If this flag is not set it means that the CPU-intensive part of the search's operation is over. This flag only has meaning if the search is active (SEARCH_RUNNING is set).

SEARCH_RECURSIVE

Indicates the search will look in indicated folders and all their subfolders for matching messages. If this flag is not set it means that only the folders explicitly included in the last call to SetSearchCriteria on this search folder will be looked in for matching messages.

SEARCH_RUNNING

Indicates the search is active (live) and its contents table is being updated to reflect database changes in the store. If this flag is not set it means the search is inactive and its contents table is static.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_BAD_CHARWIDTH

Either the MAPI_UNICODE flag was set and the implementation does not support Unicode, or MAPI_UNICODE was not set and the implementation only supports Unicode.

MAPI_E_NOT_INITIALIZED

The application did not set its search criteria before IMAPIFolder::GetSearchCriteria was called.

Comments

Use the IMAPIContainer::GetSearchCriteria method to obtain the search criteria for a particular search-results container. A search-results container is a folder that contains the findings of a query that searched for information based on specific criteria. The search criteria is created using the IMAPIContainer::SetSearchCriteria method. GetSearchCriteria is primarily used with folders; address book providers only need to implement GetSearchCriteria if they provide the advanced search capabilities associated with the PR_SEARCH property. For more information on implementing advanced search dialog boxes with address books, see MAPI Programmer's Guide.

A call to GetSearchCriteria can only be used on folders of type FOLDER_SEARCH. If GetSearchCriteria is called before your application sets search criteria for the search-results folder, GetSearchCriteria returns the value MAPI_E_NOT_INITIALIZED.

When your application is done with the data structures returned by GetSearchCriteria in the lppRestriction and lppContainerList parameters, it should call the MAPIFreeBuffer function to release the structures — one call to release each structure.

See Also

IMAPIContainer::SetSearchCriteria method, IMAPIFolder::CreateFolder method, MAPIFreeBuffer function, PR_SEARCH property


 IMAPIContainer::OpenEntry

[New - Windows 95]

Opens a message or child container object contained in the currently open container and returns a pointer to the object to provide further access.

Syntax

HRESULT OpenEntry(ULONG cbEntryID, LPENTRYID lpEntryID, LPCIID lpInterface, ULONG ulFlags, ULONG FAR * lpulObjType, LPUNKNOWN FAR * lppUnk)

Parameters

cbEntryID

Input parameter containing the number of bytes in the entry identifier pointed to by the lpEntryID parameter.

lpEntryID

Input parameter pointing to the entry identifier of the object to be opened.

lpInterface

Input parameter pointing to the interface identifier for the indicated object. Passing NULL in the lpInterface parameter indicates that the return value is cast to the standard interface for the indicated object. The lpInterface parameter can also be set to an appropriate interface identifier for the object being opened.

ulFlags

Input parameter containing a bitmask of flags used to control how the object is opened. The following flags can be used:

MAPI_BEST_ACCESS

Indicates the object should be opened with the maximum privileges allowed to the user. For example, if the client application has write privilege, open the object with write privilege; if the client application has read-only privilege, open the object with read-only privilege. The client application can learn the privilege by getting the property PR_ACCESS_LEVEL.

MAPI_DEFERRED_ERRORS

Indicates the call is allowed to succeed even if the underlying object is not accessible to the calling application. If the object is not accessible, some subsequent call to the object might return an error.

MAPI_MODIFY

Requests write access. By default, objects are created with read-only access, and client applications should not assume that write access was granted.

lpulObjType

Output parameter pointing to a variable where the object type for the opened object is stored.

lppUnk

Output parameter pointing to a variable where the pointer to the opened object is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NO_ACCESS

An attempt to modify a read-only object or an attempt to access an object for which the user has insufficient permissions.

MAPI_E_UNKNOWN_ENTRYID

The object indicated in the lpEntryID parameter is not recognized. This return value is typically returned if the message store or address book provider that the object is contained within is not open.

MAPI_E_NOT_FOUND

The object indicated in the lpEntryID parameter does not exist.

Comments

Use the IMAPIContainer::OpenEntry method to open a message or child container contained in the currently open container. The entry identifier in the lpEntryID parameter indicates which object to open. IMAPIContainer::OpenEntry returns a pointer to the opened object. Client applications are guaranteed to be able to open entries that are within the container using the IMAPIContainer::OpenEntry call. Default behavior is to open the object as read-only, unless the call sets the MAPI_MODIFY or MAPI_BEST_ACCESS flag in the ulFlags parameter; in that case your provider should return a modifiable object. If your provider does not allow modification for the object requested, then it should return the value MAPI_E_NO_ACCESS.

The lpInterface parameter indicates which interface should be used on the opened object. Passing NULL in lpInterface indicates the standard MAPI interface for that type of object should be used. The address book provider can implement other interfaces for the object if needed by passing the interface identifier for the interface that should be returned.

If your application passes NULL for the lpEntryID parameter, it indicates the service provider should open the top-level container in its container hierarchy (that is, the root folder). Your application should check the value in the lpulObjType parameter to verify the returned object has the expected object type. After performing this check, your application should cast the address returned in the lppUnk parameter to the address of a message or folder object pointer.


 IMAPIContainer::SetSearchCriteria

[New - Windows 95]

Sets the search criteria for a particular search-results container.

Syntax

HRESULT SetSearchCriteria(LPSRestriction lpRestriction, LPENTRYLIST lpContainerList, ULONG ulSearchFlags)

Parameters

lpRestriction

Input parameter pointing to a structure holding the restriction criteria that define the conditions of the search. If your application passes NULL in the lpRestriction parameter, then the most recently used search criteria for this search-results folder are used again. Your application should not pass NULL in lpRestriction for the first search within a container.

lpContainerList

Input parameter pointing to a structure that lists the entry identifiers to be included in the search. If your application passes NULL in the lpContainerList parameter, then the most recently used entry identifiers for this search-results folder are included in the new search. Your application should not pass NULL in lpContainerList for the first search within a container.

ulSearchFlags

Input parameter containing a bitmask of flags used to control how the search is performed. The following flags can be set:

BACKGROUND_SEARCH

Indicates that the search will run at normal priority relative to other searches. This flag cannot be set at the same time as FOREGROUND_SEARCH.

FOREGROUND_SEARCH

Indicates the search has foreground priority. This flag cannot be set at the same time as BACKGROUND_SEARCH.

RECURSIVE_SEARCH

Searches indicated folders and all their subfolders. Cannot be set at the same time as SHALLOW_SEARCH.

RESTART_SEARCH

Indicates that a search which is inactive should be restarted. In addition to restarting an inactive search, this flag must be passed in on the first call to SetSearchCriteria in order to initiate a search. This flag cannot be set at the same time as STOP_SEARCH.

SHALLOW_SEARCH

Indicates the search will only look in the indicated folders for matching messages. This flag cannot be set at the same time as RECURSIVE_SEARCH.

STOP_SEARCH

Stops an ongoing search (if any). Cannot be set at the same time as RESTART_SEARCH.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Use the IMAPIContainer::SetSearchCriteria method to set the search criteria for a particular search-results folder within a container. A search-results folder is a folder that contains the findings of a query that searches for information based on specific criteria. A call to SetSearchCriteria can only be performed for folders of type FOLDER_SEARCH. Address books providers do not set up their search criteria using SetSearchCriteria; they set restrictions on the contents table for the address book container. For more information on setting search criteria on address book containers, see MAPI Programmer's Guide.

An application generally accomplishes a search through a sequence of MAPI calls. First, the application must create a search-results folder by using IMAPIFolder::CreateFolder to create a folder and to specify for the folder a type of FOLDER_SEARCH. Next, the application calls the SetSearchCriteria method to define the search criteria and to initiate the search. Finally, the application browses through the search results by using the IMAPIContainer::GetContentsTable method on the search-results folder to obtain a table that describes the messages in the folder.

A search-results folder only contains links to the messages that meet the search criteria; the actual messages are still stored in their original locations. The only unique data contained in the search-results folder is a contents table view consisting of the merged contents of the message store after the restriction has been applied. A search operation only works against this merged contents table, it does not search through other search-results folders. The results of the search only returns the messages that match the search criteria; the folder hierarchy is not returned.

The search criteria define the conditions of the search, including the search keys, the folders to be searched, any conditional operations using the logical-OR, logical-AND, and logical-NOT operators, and so on.

The restrictions that set search criteria for SetSearchCriteria can contain subobject restrictions for a message's recipient table and attachment tables. A subobject restriction is a search restriction on an object held within the object being searched (for example, an attachment within a message); such a restriction is held in an SSubRestriction structure. The PR_MESSAGE_RECIPIENTS and PR_MESSAGE_ATTACHMENTS properties are used when requesting subobject restrictions. For instance, suppose a client application needs to create a search-results folder whose contents are messages containing attached files with extension ".MSS." In this case, the application sets a search criterion by using an SSubRestriction structure for the PR_MESSAGE_ATTACHMENTS property that points to an SPropertyRestriction structure holding a property restriction of PR_ATTACH_EXTENSION = MSS. Service providers that do not support subobject restrictions should return the value MAPI_E_TOO_COMPLEX for attempted subobject restrictions.

If your application sets the FOREGROUND_SEARCH flag in the ulSearchFlags parameter, the provider performs the indicated search at high priority, possibly degrading the performance of the client application. If your application does not set FOREGROUND_SEARCH, the provider performs the search in the background. In either case, MAPI immediately returns control to the calling application after finishing the search.

An application can use SetSearchCriteria to change the search criteria of a search already in progress — it can specify new restrictions, new lists of folders to search, and a new search priority (for example, a background search can be made high priority). Changes in search priority do not cause an existing search to begin again, but other changes to the search criteria can cause a search to begin again.

When an application is through using a search-results folder, it can delete the folder or leave it for later use. If your application deletes the search-results folder, the provider only deletes the message links contained in the folder; it does not delete any messages from their parent folders.

Providers should support open, copy, move, and delete operations on the items within their search folders. For more information on supporting these operations, see the reference entries for IMAPIContainer::OpenEntry and the IMAPIFolder interface. These operations apply to items within the search folder, not the search folder itself. Items cannot be created within, or copied into, search folders.

Providers can use the following idle functions for idle time processing: FtgRegisterIdleRoutine, DeregisterIdleRoutine, EnableIdleRoutine, and ChangeIdleRoutine.

See Also

ChangeIdleRoutine function, DeregisterIdleRoutine function, EnableIdleRoutine function, FtgRegisterIdleRoutine function, IMAPIContainer::GetContentsTable method, IMAPIContainer::OpenEntry method, IMAPIFolder::CreateFolder method, IMAPIFolder : IMAPIContainer interface, SPropertyRestriction structure, SRestriction structure, SSubRestriction structure


 IMAPIControl : IUnknown

[New - Windows 95]

The IMAPIControl interface is used to activate and change the state of controls defined by display tables and configuration property sheets, as well as message and recipient option dialog boxes. The most common usage is for enabling button controls. To get a control object supporting the IMAPIControl interface, call IMAPIProp::OpenProperty on the display table containing the control. For more information on working with display tables and control objects, see MAPI Programmer's Guide.

At a Glance

Specified in header file:	MAPIDEFS.H
Object that supplies this interface:	Control object
Corresponding pointer type:	LPMAPICONTROL
Implemented by:	Service providers
Called by:	Client applications, MAPI
Vtable Order

GetLastError	Returns a MAPIERROR structure containing information about the last error that occurred for a control object.
Activate	Activates a control object.
GetState	Retrieves the state of the control (that is, whether it is enabled or disabled).


 IMAPIControl::Activate

[New - Windows 95]

Activates a control object.

Syntax

HRESULT Activate(ULONG ulFlags, ULONG ulUIParam)

Parameters

ulFlags

Reserved; must be zero.

ulUIParam

Input parameter containing a handle to the parent window that the dialog box is modal to.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Client applications call the IMAPIControl::Activate method to activate a control object. Usually, the control is a button in a dialog box or property sheet. In the ulUIParam parameter, your client should pass the handle for the window the dialog box is modal to. Your application should not call Activate if the MAPI_DISABLED value was returned in the lpulState parameter when IMAPIControl::GetState was called.

See Also

IMAPIControl::GetState method


 IMAPIControl::GetLastError

[New - Windows 95]

Returns a MAPIERROR structure containing information about the last error that occurred for the session object.

Syntax

HRESULT GetLastError(HRESULT hResult, ULONG ulFlags, LPMAPIERROR FAR * lppMAPIError)

Parameters

hResult

Input parameter containing the result returned for the last call on the session object that returned an error.

ulFlags

Input parameter containing a bitmask of flags. The following flag can be set:

MAPI_UNICODE

Indicates the strings returned in the MAPIERROR structure returned in the lppMAPIError parameter are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

lppMAPIError

Output parameter pointing to a pointer to the returned MAPIERROR structure containing version, component, and context information for the error. The lppMAPIError parameter can be set to NULL if there is no MAPIERROR structure to return.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_BAD_CHARWIDTH

Either the MAPI_UNICODE flag was set and the implementation does not support Unicode, or MAPI_UNICODE was not set and the implementation only supports Unicode.

Comments

Use the IMAPIControl::GetLastError method to retrieve information to display as a message to the user regarding the last error returned from a method call on the control object.

To release all the memory allocated by MAPI, client applications need only call the MAPIFreeBuffer function for the MAPIERROR structure.

The return value from GetLastError must be S_OK for the application to make use of the MAPIERROR structure. Even if the return value is S_OK, it is still possible that a MAPIERROR structure won't be returned. If the implementation cannot determine what the last error was, or if a MAPIERROR structure is not available for that error, a pointer to NULL is returned in the lppMAPIError parameter instead.

See Also

MAPIERROR structure, MAPIFreeBuffer function


 IMAPIControl::GetState

[New - Windows 95]

Retrieves the state of the control (that is, whether it is enabled or disabled).

Syntax

HRESULT GetState(ULONG ulFlags, ULONG FAR * lpulState)

Parameters

ulFlags

Reserved; must be zero.

lpulState

Output parameter containing the value used to indicate the state of the control. One of the following values can be set:

MAPI_DISABLED

Indicates that the control should be disabled and unselectable.

MAPI_ENABLED

Indicates that the control should be enabled.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Client applications call the IMAPIControl::GetState method to retrieve the state of a control object — that is, whether the control is enabled or disabled. Usually, the control is a button in a dialog box. In the case of a button, if it is enabled it can respond to a mouse click or key press; if it is disabled, it is displayed as grayed and cannot be selected by the user.

See Also

IMAPIControl::Activate method


 IMAPIFolder : IMAPIContainer

[New - Windows 95]

The IMAPIFolder interface is used to perform operations on folders such as creating, copying, and deleting messages and subfolders.

At a Glance

Specified in header file:	MAPIDEFS.H
Object that supplies this interface:	Folder object
Corresponding pointer type:	LPMAPIFOLDER
Implemented by:	Message store providers
Called by:	Client applications
Vtable Order

CreateMessage	Creates a new message within a folder.
CopyMessages	Copies or moves one or more messages between two folders.
DeleteMessages	Deletes one or more messages from a folder.
CreateFolder	Creates a new folder as a subfolder within the message store.
CopyFolder	Copies or moves a folder from its current parent folder to another.
DeleteFolder	Deletes a subfolder from the given folder.
SetReadFlags	Sets or clears the read flags for the messages in a folder, and manages the sending of read receipts.
GetMessageStatus	Obtains the status associated with a message in a folder — for example, whether that message is marked for deletion.
SetMessageStatus	Sets the status associated with a message in a particular folder — for example, whether that message is marked for deletion.
SaveContentsSort	Sets the default sort order for a folder's contents table.
EmptyFolder	Deletes all items from a folder without deleting the folder itself.


 IMAPIFolder::CopyFolder

[New - Windows 95]

Copies or moves one or more messages in the current folder to another.

Syntax

HRESULT CopyFolder(ULONG cbEntryID, LPENTRYID lpEntryID, LPCIID lpInterface, LPVOID lpDestFolder, LPTSTR lpszNewFolderName, ULONG ulUIParam, LPMAPIPROGRESS lpProgress, ULONG ulFlags)

Parameters

cbEntryID

Input parameter containing the number of bytes in the entry identifier pointed to by the lpEntryID parameter.

lpEntryID

Input parameter pointing to the entry identifier of the folder to copy or move.

lpInterface

Input parameter pointing to the interface identifier (IID) for the destination folder object indicated in the lpDestFolder parameter. Passing NULL for the lpInterface parameter indicates the MAPI interface for the destination folder object will be returned. Client applications must pass NULL. Message store providers can also set the lpInterface parameter to an identifier for another appropriate interface for the destination folder object. For example, a message can be copied with IID_IUnknown, IID_IMAPIProp, IID_IMAPIContainer, or IID_IMAPIFolder.

lpDestFolder

Input parameter pointing to the open destination folder where the folder identified in the lpEntryID parameter is copied or moved.

lpszNewFolderName

Input parameter pointing to a string containing the name to be given to the newly created or moved folder. If the client application passes NULL in the lpszNewFolderName parameter, the name of the newly created or moved folder is the same as the name of the original.

ulUIParam

Input parameter containing the handle to the window the dialog box is modal to. The ulUIParam parameter is ignored unless the client application sets the FOLDER_DIALOG flag in the ulFlags parameter and passes NULL in the lpProgress parameter.

lpProgress

Input parameter pointing to a progress object that contains client-supplied progress information. If NULL is passed in the lpProgress parameter, the progress information is provided by MAPI. The lpProgress parameter is ignored unless the FOLDER_DIALOG flag is set in the ulFlags parameter.

ulFlags

Input parameter containing a bitmask of flags used to control how the copy or move operation is accomplished. The following flags can be set:

COPY_SUBFOLDERS

Indicates that all subfolders are included in the copy operation. This is optional for copy operations and is implied for move operations.

FOLDER_DIALOG

Displays a progress-information user interface while the operation proceeds.

FOLDER_MOVE

Indicates that the folder is to be moved. If this flag is not set, the folder will be copied.

MAPI_DECLINE_OK

Informs the provider that if it chooses not to implement IMAPIFolder::CopyFolder, that it can immediately return MAPI_E_DECLINE_COPY.

MAPI_UNICODE

Indicates the passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_BAD_CHARWIDTH

Either the MAPI_UNICODE flag was set and the implementation does not support Unicode, or MAPI_UNICODE was not set and the implementation only supports Unicode.

MAPI_E_COLLISION

The name of the folder being moved is the same as the name of a sub-folder in the destination folder. Folder names must be unique.

MAPI_E_DECLINE_COPY

Indicates that the provider has chosen not to implement this operation.

MAPI_E_FOLDER_CYCLE

The source object directly or indirectly contains the destination object. Significant work might have been performed before this condition was discovered so the source and destination object might be partially modified.

MAPI_W_PARTIAL_COMPLETION

The call succeeded, but not all entries were successfully copied. Use the HR_FAILED macro to test for this warning, but the call should be handled as a successful return.

Comments

Message store providers use the IMAPIFolder::CopyFolder method to copy or move folders from one location to another. The folder being copied or moved is added to the destination folder as a subfolder. Only one folder can be copied or moved at a time.

CopyFolder allows simultaneous renaming and moving of folders and the copying or moving of the subfolders of the affected folder. To copy or move all subfolders nested within the copied or moved folder, the client application passes the COPY_SUBFOLDERS flag in the ulFlags parameter.

To allow copy or move operations involving more than one folder to continue even if one or more folders specified for the operation do not exist or have already been moved elsewhere, and thus cannot be copied or moved, a message store provider should attempt to complete the operation as best it can for each folder specified. The provider should stop the operation without completing it only in the case of failures it cannot control, such as running out of memory or disk space, message store corruption, and so on.

If CopyFolder successfully completes the copy or move operation for every folder requested by the client application, it returns the value S_OK. If one or more folders cannot be copied or moved, CopyFolder returns the value MAPI_W_PARTIAL_COMPLETION. If CopyFolder returns a different value, such as MAPI_E_NOT_ENOUGH_MEMORY, that indicates the call did not complete, though it might already have copied or moved one or more folders without being able to continue. The calling application cannot proceed on the assumption that an error return implies no work was done.

If an entry identifier for a folder that doesn't exist is passed in the lpEntryID parameter, CopyFolder returns MAPI_W_PARTIAL_COMPLETION or MAPI_E_NOT_FOUND, depending on a message store's implementation.


 IMAPIFolder::CopyMessages

[New - Windows 95]

Copies or moves one or more messages between two folders.

Syntax

HRESULT CopyMessages(LPENTRYLIST lpMsgList, LPCIID lpInterface, LPVOID lpDestFolder, ULONG ulUIParam, LPMAPIPROGRESS lpProgress, ULONG ulFlags)

Parameters

lpMsgList

Input parameter pointing to an array of ENTRYLIST structures that identify the message or messages to be copied or moved.

lpInterface

Input parameter pointing to the interface identifier (IID) for the destination folder object indicated in the lpDestFolder parameter. Passing NULL for the lpInterface parameter indicates the MAPI interface for the destination folder object will be returned. Client applications must pass NULL. Message store providers can also set the lpInterface parameter to an identifier for another appropriate interface for the destination folder object. For example, a message can be copied with IID_IUnknown, IID_IMAPIProp, IID_IMAPIContainer, or IID_IMAPIFolder.

lpDestFolder

Input parameter pointing to the open destination folder where the messages identified in the lpMsgList parameter are to be copied or moved.

ulUIParam

Input parameter containing the handle of the window the dialog box is modal to. The ulUIParam parameter is ignored unless the client application sets the MESSAGE_DIALOG flag in the ulFlags parameter and passes NULL in the lpProgress parameter.

lpProgress

Input parameter pointing to a progress object that contains client-supplied progress information. If NULL is passed in the lpProgress parameter, the progress information is provided by MAPI. The lpProgress parameter is ignored unless the MESSAGE_DIALOG flag is set in the ulFlags parameter.

ulFlags

Input parameter containing a bitmask of flags used to control how the copy or move operation is accomplished. The following flags can be set:

MAPI_DECLINE_OK

Informs the provider that if it chooses not to implement IMAPIFolder::CopyMessage, that it can immediately return MAPI_E_DECLINE_COPY.

MESSAGE_DIALOG

Displays a progress-information user interface as the operation proceeds.

MESSAGE_MOVE

Moves messages. If this flag is not set, the method copies messages.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_DECLINE_COPY

Indicates that the service provider has chosen not to implement this operation.

MAPI_W_PARTIAL_COMPLETION

The call succeeded, but not all entries were successfully copied. Use the HR_FAILED macro to test for this warning; however, the call should be handled as a successful return

Comments

Message store providers use the IMAPIFolder::CopyMessages method to copy or move messages from one folder to another. Your provider can move or copy the messages in any order. This functionality is especially useful in the case of search-results folders for which the provider can group the messages by parent folder.

Messages that do not exist, have already been moved elsewhere, are open with read-write access, or are currently submitted, cannot be copied or moved. However, to allow copy or move operations involving more than one message to continue even if one or more messages specified for the operation cannot be copied or moved, a message store provider should attempt to complete the operation as best it can for each message specified. The provider should stop the operation without completing it only in case of failures it cannot control, such as running out of memory or disk space, message store corruption, and so on.

If CopyMessages successfully completes the copy or move operation for every message requested by the client application, S_OK is returned. If one or more messages cannot be copied or moved, CopyMessages returns the value MAPI_W_PARTIAL_COMPLETION. If CopyMessages returns a different value, such as MAPI_E_NOT_ENOUGH_MEMORY, that indicates the call did not complete, though it might already have copied or moved one or more messages without being able to continue. The calling application cannot proceed on the assumption that an error return implies no work was done.


 IMAPIFolder::CreateFolder

[New - Windows 95]

Creates a new folder as a subfolder within the message store.

Syntax

HRESULT CreateFolder(ULONG ulFolderType, LPTSTR lpszFolderName, LPTSTR lpszFolderComment, LPCIID lpInterface, ULONG ulFlags, LPMAPIFOLDER FAR * lppFolder)

Parameters

ulFolderType

Input parameter indicating the type of folder to create. Your message store provider should pass in the ulFolderType parameter to one of the following values:

FOLDER_GENERIC

Indicates a generic folder should be created.

FOLDER_SEARCH

Indicates a search folder should be created.

lpszFolderName

Input parameter pointing to a string containing the name to be given to the new folder.

lpszFolderComment

Input parameter pointing to a string containing the comment to be associated with the new folder. This string becomes the value of the folder's PR_COMMENT property. If NULL is passed in the lpszFolderComment parameter, the folder has no initial comment.

lpInterface

Input parameter indicating the interfaces identifier that should be used for the folder being returned in the lppFolder parameter. Passing NULL for the lpInterface parameter indicates IID_IMAPIFolder is to be used. Client applications must pass NULL. Message store providers can also set the lpInterface parameter to any of the interfaces IMAPIFolder is derived from, that is: IID_IUnknown, IID_IMAPIProp, or IID_IMAPIContainer.

ulFlags

Input parameter containing a bitmask of flags used to control the creation of the folder. The following flags can be set:

MAPI_DEFERRED_ERRORS

Indicates the call is allowed to succeed even if the underlying object is not accessible to the calling application. If the object is not accessible, some subsequent call to the object might return an error.

MAPI_UNICODE

Indicates the passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

OPEN_IF_EXISTS

Allows the method to succeed, even if the folder already exists, by returning a new folder object for the existing folder. Note that message stores that allow sibling folders to have the same name might fail to open an existing folder if more than one exists with the name supplied in the lpszFolderName parameter.

lppFolder

Output parameter pointing to a variable where the pointer to the newly created folder object is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_BAD_CHARWIDTH

Either the MAPI_UNICODE flag was set and the implementation does not support Unicode, or MAPI_UNICODE was not set and the implementation only supports Unicode.

MAPI_E_COLLISION

A folder with the name given in the lpszFolderName parameter already exists. Folder names must be unique.

Comments

Message store providers use the IMAPIFolder::CreateFolder method to create new normal and search-results folders in a message store. Root folders cannot be created. Most message store providers require the name of the new folder to be unique with respect to the names of its sibling folders. Client applications should be able to handle the value MAPI_E_COLLISION returned if this rule is not followed.

To determine the entry identifier of the newly created folder, your implementation calls the IMAPIProps::GetProps method to read the new folder's PR_ENTRYID property while the folder is still open.

See Also

IMAPIProp::GetProps method


 IMAPIFolder::CreateMessage

[New - Windows 95]

Creates a new message within a folder.

Syntax

HRESULT CreateMessage(LPCIID lpInterface, ULONG ulFlags, LPMESSAGE FAR * lppMessage)

Parameters

lpInterface

Input parameter indicating the interfaces identifier that should used for the message being returned in the lppMessage parameter. Passing NULL for the lpInterface parameter indicates IID_IMessage is to be used. Client applications must pass NULL. Message store providers can also set the lpInterface parameter to any of the interfaces IMessage is derived from, that is: IID_IUnknown, or IID_IMAPIProp.

ulFlags

Input parameter containing a bitmask of flags used to control how the message is created. The following flags can be set:

MAPI_ASSOCIATED

Indicates that an associated item should be created.

MAPI_DEFERRED_ERRORS

Indicates the call is allowed to succeed even if the underlying object is not accessible to the calling application. If the object is not accessible, some subsequent call to the object might return an error.

lppMessage

Output parameter pointing to a variable where the pointer to the newly created message object is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Message store providers use the IMAPIFolder::CreateMessage method to create a new message in a folder.

The MAPI_ASSOCIATED flag should be set in the ulFlags parameter to create objects associated with the folder and listed in the associated contents table. Associated entries allow client applications to associate invisible data with a folder.

Although a new message has a unique PR_RECORD_KEY property, its PR_ENTRYID property might not be available until a client application saves the message by using the IMAPIProp::SaveChanges method. This potential unavailability stems from the fact that some message store providers generate the entry identifier when the message is created and others wait to do so until the message has been saved. The latter functionality is typical; that is, a new message usually does not appear in a folder contents table until a client application calls the SaveChanges method to save changes.

If a folder is deleted before a new message within it is saved, the results of a call to CreateMessage are undefined.

See Also

IMAPIProp::SaveChanges method


 IMAPIFolder::DeleteFolder

[New - Windows 95]

Deletes a subfolder from the given folder.

Syntax

HRESULT DeleteFolder(ULONG cbEntryID, LPENTRYID lpEntryID, ULONG ulUIParam, LPMAPIPROGRESS lpProgress, ULONG ulFlags)

Parameters

cbEntryID

Input parameter containing the number of bytes in the entry identifier pointed to by the lpEntryID parameter.

lpEntryID

Input parameter pointing to the entry identifier of the folder to delete.

ulUIParam

Input parameter containing the handle of the window the dialog box is modal to. The ulUIParam parameter is ignored unless the FOLDER_DIALOG flag is set in the ulFlags parameter and NULL is passed in the lpProgress parameter.

lpProgress

Input parameter pointing to a progress object that contains client-supplied progress information. If NULL is passed in the lpProgress parameter, the progress information is provided by MAPI. The lpProgress parameter is ignored unless the FOLDER_DIALOG flag is set in the ulFlags parameter.

ulFlags

Input parameter containing a bitmask of flags used to control the deletion of the folders. The following flags can be set:

DEL_FOLDERS

Deletes all subfolders of the subfolder indicated in the lpEntryID parameter.

DEL_MESSAGES

Deletes all messages in the folder indicated in the lpEntryID parameter.

FOLDER_DIALOG

Displays a progress-information user interface while the operation proceeds.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_HAS_FOLDERS

The folder being deleted contains folders and the DEL_FOLDERS flag was not set. The folder was not deleted.

MAPI_E_HAS_MESSAGES

The folder being deleted contains messages and the DEL_MESSAGES flag was not set. The folder containing the messages was not deleted.

MAPI_W_PARTIAL_COMPLETION

The call succeeded, but not all of the entries were successfully deleted. Use the HR_FAILED macro to test for this warning, though the call should be handled as a successful return.

Comments

Message store providers use the IMAPIFolder::DeleteFolder method to delete a subfolder of a folder. If the message store provider so indicates, DeleteFolder can also delete all messages or all subfolders in a subfolder, or both. To delete all messages in a subfolder, the client application sets the DEL_MESSAGES flag in the ulFlags parameter; to delete all subfolders in a subfolder, the client application sets the DEL_FOLDERS flag in ulFlags. However, no flag need be set to delete any associated items, such as views or form definitions, from a folder.

To allow deletions of more than one subfolder to continue even if one or more subfolders marked for deletion by the calling application do not exist or have been moved elsewhere, and thus cannot be deleted, a message store provider should attempt to complete the deletion as best it can for each subfolder specified. The provider should stop the deletion without completing it only in the case of failures it cannot control, such as running out of memory or disk space, message store corruption, and so on.

If DeleteFolder successfully deletes every folder marked for deletion, it returns the value S_OK. If one or more folders cannot be deleted, DeleteFolder returns the value MAPI_W_PARTIAL_COMPLETION or MAPI_E_NOT_FOUND, depending on the message store's implementation. If DeleteFolder returns a different value, such as MAPI_E_NOT_ENOUGH_MEMORY, that indicates the call did not complete; it might have already deleted one or more folders or messages without being able to continue. The calling application cannot proceed on the assumption that an error return implies no work was done.

During a DeleteFolder call, messages that are being processed by the MAPI spooler are not deleted, nor does the message store provider attempt to call the IMsgStore::AbortSubmit method on such messages. A message being processed by the MAPI spooler is left in the folder in which it resides. This functionality might prevent one or more folders from being deleted because they still have contents.


 IMAPIFolder::DeleteMessages

[New - Windows 95]

Deletes one or more messages from a folder.

Syntax

HRESULT DeleteMessages(LPENTRYLIST lpMsgList, ULONG ulUIParam, LPMAPIPROGRESS lpProgress, ULONG ulFlags)

Parameters

lpMsgList

Input parameter pointing to an array of ENTRYLIST structures that identify the message or messages to delete.

ulUIParam

Input parameter containing the handle to the window the dialog box is modal to. The ulUIParam parameter is ignored unless the MESSAGE_DIALOG flag is set in the ulFlags parameter and NULL is passed in the lpProgress parameter.

lpProgress

Input parameter pointing to a progress object that contains client-supplied progress information. If NULL is passed in the lpProgress parameter, the progress information is provided by MAPI. The lpProgress parameter is ignored unless the MESSAGE_DIALOG flag is set in the ulFlags parameter.

ulFlags

Input parameter containing a bitmask of flags used to control how the messages are deleted. The following flag can be set:

MESSAGE_DIALOG

Displays a progress-information user interface as the operation proceeds.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_W_PARTIAL_COMPLETION

The call succeeded, but not all of the entries were successfully deleted. Use the HR_FAILED macro to test for this warning, though the call should be handled as a successful return.

Comments

Message store providers use the IMAPIFolder::DeleteMessages method to delete messages from a folder.

Messages that do not exist, have been moved elsewhere, are open with read-write access, or are currently submitted, cannot be deleted. However, to allow deletions of more than one message to continue even if one or more messages marked for deletion by the calling application cannot be deleted, a message store provider should attempt to complete the deletion as best it can for each message specified. The provider should stop the deletion without completing it only in the case of failures it cannot control, such as running out of memory or disk space, message store corruption, and so on.

If DeleteMessages successfully deletes every message marked for deletion, it returns the value S_OK. If one or more messages cannot be deleted, DeleteMessages returns the value MAPI_W_PARTIAL_COMPLETION or MAPI_E_NOT_FOUND depending on the message store's implementation. If DeleteMessages returns a different value, such as MAPI_E_NOT_ENOUGH_MEMORY, that indicates that call did not complete; it might already have deleted one or more messages without being able to continue. The calling application cannot proceed on the assumption that an error return implies no work was done.

During a DeleteMessages call, submitted messages are not deleted, nor does the message store provider attempt to call the IMsgStore::AbortSubmit method on such messages. The message is left in the folder in which it resides.


 IMAPIFolder::EmptyFolder

[New - Windows 95]

Deletes all items from a folder without deleting the folder itself.

Syntax

HRESULT EmptyFolder(ULONG ulUIParam, LPMAPIPROGRESS lpProgress, ULONG ulFlags)

Parameters

ulUIParam

Input parameter containing the handle of the window the dialog box is modal to. The ulUIParam parameter is ignored unless the FOLDER_DIALOG flag is set in the ulFlags parameter and NULL is passed in the lpProgress parameter.

lpProgress

Input parameter pointing to a progress object that contains client-supplied progress information. If NULL is passed in the lpProgress parameter, the progress information is provided by MAPI. The lpProgress parameter is ignored unless the FOLDER_DIALOG flag is set in the ulFlags parameter.

ulFlags

Input parameter containing a bitmask of flags used to control how deletion is performed for the messages and subfolders of a folder. The following flags can be set:

DEL_ASSOCIATED

Subfolders are deleted in their entirety, including all subfolders and associated items. The DEL_ASSOCIATED flag only has meaning for the top-level folder acted on by the call.

FOLDER_DIALOG

Displays a progress-information user interface while the operation proceeds.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_W_PARTIAL_COMPLETION

The call succeeded, but some entries were successfully deleted. Use the HR_FAILED macro to test for this warning, though the call should be handled as a successful return.

Comments

Message store providers use the IMAIPIFolder::EmptyFolder method to delete all of a folder's contents without deleting the folder itself.

When the calling application sets the DEL_ASSOCIATED flag in the ulFlags parameter, EmptyFolder deletes all messages, subfolders, and associated information of a folder; a folder's associated information includes such items as views and form definitions. When the calling application does not set DEL_ASSOCIATED, EmptyFolder does not delete associated information. The DEL_ASSOCIATED flag only has meaning for the top-level folder acted on by the call.

If EmptyFolder successfully deletes all subfolders and messages, it returns the value S_OK. If one or more items cannot be deleted, EmptyFolder returns the value MAPI_W_PARTIAL_COMPLETION. If EmptyFolder returns a different value, such as MAPI_E_NOT_ENOUGH_MEMORY, that indicates the call did not complete, it might already have deleted one or more messages or subfolders without being able to continue. The calling application cannot proceed on the assumption that an error return implies that no work was done.

During an EmptyFolder call, submitted messages are not deleted, nor does the message store provider attempt to call the IMsgStore::AbortSubmit method on such messages. The message is left in the folder in which it resides.


 IMAPIFolder::GetMessageStatus

[New - Windows 95]

Obtains the status associated with a message in a particular folder — for example, whether that message is marked for deletion.

Syntax

HRESULT GetMessageStatus(ULONG cbEntryID, LPENTRYID lpEntryID, ULONG ulFlags, ULONG FAR * lpulMessageStatus)

Parameters

cbEntryID

Input parameter containing the number of bytes in the entry identifier pointed to by the lpEntryID parameter.

lpEntryID

Input parameter pointing to the entry identifier for the message whose status is obtained.

ulFlags

Reserved; must be zero.

lpulMessageStatus

Output parameter pointing to a variable receiving a bitmask of flags indicating the message's status. Bits 5 through 15 are reserved and must be zero; bits 16 through 31 are available for application-specific use.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Message store providers use the IMAPIFolder::GetMessageStatus method to find out the status of a message. GetMessageStatus returns status information in the lpulMessageStatus parameter.

How your application sets, clears, and uses the message status bits in lpulMessageStatus depends entirely on your application's implementation, except that bits 5 through 15 are reserved and must be zero. In the interpersonal message (IPM) subtree, MAPI reserves bits 16 through 31 for use by the IPM client application. Users can choose which IPM client they will use. Applications that store their messages in other subtrees can use bits 16 through 31 for their own purposes.

See Also

IMAPIFolder::SetMessageStatus method


 IMAPIFolder::SaveContentsSort

[New - Windows 95]

Sets the default sort order for a folder's contents table.

Syntax

HRESULT SaveContentsSort(LPSSortOrderSet lpSortCriteria, ULONG ulFlags)

Parameters

lpSortCriteria

Input parameter pointing to an SSortOrderSet structure containing the sort criteria for the default sort order.

ulFlags

Input parameter containing a bitmask of flags used to control how the default sort order is set. The following flags can be set:

RECURSIVE_SORT

Indicates the default sort order should be for the indicated folder and all of its subfolders.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NO_SUPPORT

The operation is not supported by one or more service providers.

Comments

Message store providers use the IMAPIFolder::SaveContentsSort method to set the default sort order for a folder's contents table. The IMAPIContainer::GetContentsTable method uses this default sort order; before returning a folder's contents table, GetContentsTable sorts it by using the default sort order. Not all message store providers support SaveContentsSort; such providers return MAPI_E_NO_SUPPORT.

See Also

IMAPIContainer::GetContentsTable method, SSortOrderSet structure


 IMAPIFolder::SetMessageStatus

[New - Windows 95]

Sets the status associated with a message in a particular folder — for example, whether that message is marked for deletion.

Syntax

HRESULT SetMessageStatus(ULONG cbEntryID, LPENTRYID lpEntryID, ULONG ulNewStatus, ULONG ulNewStatusMask, ULONG FAR * lpulOldStatus)

Parameters

cbEntryID

Input parameter containing the number of bytes in the entry identifier pointed to by the lpEntryID parameter.

lpEntryID

Input parameter pointing to the entry identifier for the message whose status is set.

ulNewStatus

Input parameter containing a bitmask of flags used to set the status of a message within a folder in the message store. These flags are set by the bitmask in the ulNewStatusMask parameter.

ulNewStatusMask

Input parameter containing a bitmask of flags used to set the bitmask in the ulNewStatus parameter. For each bit set in the ulNewStatusMask parameter mask, the corresponding bit in ulNewStatus is set or cleared for the message within the message store.

lpulOldStatus

Output parameter pointing to a variable that receives the previous value of the message status flags.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Message store providers use the IMAPIFolder::SetMessageStatus method to set the status associated with a message in a folder.

Some message store providers use SetMessageStatus to enable applications to negotiate a message lockout operation among themselves. To do so, client applications choose a bit for the lockout bit. Your provider sets the lockout bit using SetMessageStatus and examines the previous value in the lpulOldStatus parameter to determine if the application caused the chosen bit to be set. By using the bitmask, applications can use other bits in the ulNewStatus parameter to track message status without interfering with the lockout bit.

See Also

IMAPIFolder::GetMessageStatus method


 IMAPIFolder::SetReadFlags

[New - Windows 95]

Sets or clears the read flags for the messages in a folder, and manages the sending of read receipts.

Syntax

HRESULT SetReadFlags(LPENTRYLIST lpMsgList, ULONG ulUIParam, LPMAPIPROGRESS lpProgress, ULONG ulFlags)

Parameters

lpMsgList

Input parameter pointing to an array of ENTRYLIST structures that identify the message or messages for which to set the read flags. If the client application passes NULL in the lpMsgList parameter, all messages are processed.

ulUIParam

Input parameter containing the handle of the window the dialog box is modal to. The ulUIParam parameter is ignored unless the client application sets the MESSAGE_DIALOG flag in the ulFlags parameter and passes NULL in the lpProgress parameter.

lpProgress

Input parameter pointing to a progress object that contains client-supplied progress information. If NULL is passed in the lpProgress parameter, the progress information is provided by MAPI. The lpProgress parameter is ignored unless the FOLDER_DIALOG flag is set in the ulFlags parameter.

ulFlags

Input parameter containing a bitmask of flags used to control the setting of each message's read flag — that is, each message's MSGFLAG_READ flag in its PR_MESSAGE_FLAGS property — and the processing of read receipts. The following flags can be set in the ulFlags parameter:

CLEAR_READ_FLAG

Resets the MSGFLAG_READ flag. No read receipt is sent.

MESSAGE_DIALOG

Displays a progress-information user interface while the operation proceeds.

GENERATE_RECEIPT_ONLY

Generates a read receipt but does not change the state of the MSGFLAG_READ flag in PR_MESSAGE_FLAGS.

MAPI_DEFERRED_ERRORS

Indicates the call is allowed to succeed even if the underlying object is not accessible to the calling application. If the object is not accessible, some subsequent call to the object might return an error.

SUPPRESS_RECEIPT

Indicates the messaging system should not send a read receipt for each message, but that each message should be marked as read. If the MSGFLAG_READ bit is already set, do nothing.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NO_SUPPRESS

The message store provider does not support the suppression of read receipts.

MAPI_W_PARTIAL_COMPLETION

The call succeeded, but not all the entries were successfully processed. Use the HR_FAILED macro to test for this warning, though the call should be handled as a successful return.

Comments

Message store providers use the IMAPIFolder::SetReadFlags method to set or clear the read flags for the messages in a folder, and to manage the sending of read receipts, when messages are being moved or copied from one message store to another. SetReadFlags sets or clears the MSGFLAG_READ bit in the PR_MESSAGE_FLAGS property.

Messages that do not exist, have been moved elsewhere, are open with read-write access, or are currently submitted, cannot have their read flags set. However, to allow read-flag setting operations involving more than one message to continue even if one or more messages specified cannot have their read flags set, a message store provider should attempt to complete the operation as best it can for each message specified. The provider should stop the operation without completing it only in the case of failures it cannot control, such as running out of memory or disk space, message store corruption, and so on.

If none of the flags are set in the ulFlags parameter, the following rules apply:

•	If the MSGFLAG_READ bit is already set, do nothing.

•	If the PR_READ_RECEIPT_REQUESTED bit is set, send the read receipt and set the MSGFLAG_READ bit.

MAPI_E_INVALID_PARAMETER is returned if any of the following combinations are set in ulFlags:

•	SUPPRESS_RECEIPT | CLEAR_READ_FLAG

•	SUPPRESS_RECEIPT | CLEAR_READ_FLAG | GENERATE_RECEIPT_ONLY

•	CLEAR_READ_FLAG | GENERATE_RECEIPT_ONLY

If both SUPPRESS_RECEIPT and GENERATE_RECEIPT_ONLY are set in ulFlags, the PR_READ_RECEIPT_REQUESTED bit, if it is set, is turned off, and a read receipt should not be sent.

Note  Providers can optimize report behavior so that a client application's setting a message attribute to get a read or delivery report is only a request and the provider can support not sending read or delivery reports. However, some message stores do not support the suppression of read reports for some messages. If the client application calls SetReadFlag on such a message with the SUPPRESS_RECEIPT flag set in the ulFlags parameter, SetReadFlag returns the value MAPI_E_NO_SUPPRESS; in this case, MAPI does not mark the message as read and does not generate a report.

If SetReadFlags successfully completes processing for every message specified, it returns the value S_OK. If one or more messages cannot be processed, SetReadFlags returns the value MAPI_W_PARTIAL_COMPLETION. If SetReadFlags returns a different value, such as MAPI_E_NOT_ENOUGH_MEMORY, that indicates the call did not compete; it might already have processed one or more messages without being able to continue. The calling application cannot proceed on the assumption that an error return implies that no work was done.

See Also

IMessage::SetReadFlag method, PR_MESSAGE_FLAGS property


 IMAPIForm : IUnknown

[New - Windows 95]

The IMAPIForm interface is implemented by form servers for the benefit of form viewers.

At a Glance

Specified in header file:	MAPIFORM.H
Object that supplies this interface:	Form object
Corresponding pointer type:	LPMAPIFORM
Implemented by:	Form object
Called by:	Form viewers
Vtable Order

SetViewContext	Sets a form view context as the current view context.
GetViewContext	Returns the current view context for a form.
ShutdownForm	Closes a form.
DoVerb	Requests that a form object perform one of its verbs.
Advise	Registers a form viewer for notification on changes to a form.
Unadvise	Removes a form viewer's registration for notification of form changes.


 IMAPIForm::Advise

[New - Windows 95]

Registers a form viewer for notification on changes to a form object.

Syntax

HRESULT Advise(LPMAPIVIEWADVISESINK pAdvise, ULONG FAR * pulConnection)

Parameters

pAdvise

Input parameter pointing to the view advise-sink object to be called when an event for the form object occurs about which notification has been requested.

pulConnection

Output parameter pointing to a variable where the connection number for the notification registration is stored. The connection number must be nonzero.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Form viewers call the IMAPIForm::Advise method to register for notification callbacks when changes occur on the form. The form server's implementation of Advise keeps a copy of the pointer to the view advise-sink object passed in the pAdvise parameter and uses that pointer with its notification callbacks. The form server implementation should call the IUnknown::AddRef method on the view advise-sink object to retain the object until notification registration is canceled. The Advise implementation assigns a nonzero connection number to the notification registration, which is returned in the pulConnection parameter.

To cancel a notification registration, your form viewer calls the IMAPIForm::Unadvise method. During the call to Unadvise, or shortly thereafter, the saved pointer to the view advise-sink object in pAdvise is released.

See Also

IMAPIForm::Unadvise method, IMAPIViewAdviseSink : IUnknown interface


 IMAPIForm::DoVerb

[New - Windows 95]

Requests a form object perform one of its verbs.

Syntax

HRESULT DoVerb(LONG iVerb, LPMAPIVIEWCONTEXT lpViewContext, ULONG hwndParent, LPCRECT lprcPosRect)

Parameters

iVerb

Input parameter containing the number of the verb to be performed.

lpViewContext

Input parameter pointing to a view context object. This parameter can be NULL.

hwndParent

Input parameter containing the handle of the parent window the dialog box is modal to. This parameter should be NULL if the dialog box is not modal.

lprcPosRect

Input parameter pointing to a RECT structure used to display the form's window.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

OLEOBJ_S_CANNOT_DOVERB_NOW

Indicates that the verb is valid, but that the object cannot perform the operation now.

Comments

Form viewers call the IMAPIForm::DoVerb method to request an object to perform one of its verbs. Typical form server implementations of DoVerb contain a switch statement that tests the valid values for the iVerb parameter.

The lpViewContext parameter can be NULL. If a view context is passed in the lpViewContext parameter, the form must use this view context for the duration of the verb processing rather than the view context passed in an earlier call to the IMAPIForm::SetViewContext method. The view context should not be saved.

Some verbs, such as Print, are expected to be modal with respect to the DoVerb call (that is, the printing must be finished before the DoVerb call returns). Non-modal verbs can be made to act like modal verbs by passing in a view context object in the lpViewContext parameter whose IMAPIViewContext::GetViewStatus call returns the VCSTATUS_MODAL flag.

The handle in the hwndParent parameter must be assumed to have a life span of the DoVerb call, but because it can be destroyed immediately upon the call's return, forms should not save the handle.

The RECT structure used by the form's window can be obtained using the Windows GetWindowRect function.

See Also

IMAPIForm::SetViewContext method, IMAPIViewContext::GetViewStatus method


 IMAPIForm::GetViewContext

[New - Windows 95]

Returns the current view context for the form object.

Syntax

HRESULT GetViewContext(LPMAPIVIEWCONTEXT FAR * ppViewContext)

Parameters

ppViewContext

Output parameter pointing to a variable where the pointer to the view context object is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

S_FALSE

The form object doesn't have a view context.

See Also

IMAPIForm::SetViewContext method, IMAPIViewContext : IUnknown interface


 IMAPIForm::SetViewContext

[New - Windows 95]

Sets a form view context as the current view context for the form object.

Syntax

HRESULT SetViewContext(LPMAPIVIEWCONTEXT pViewContext)

Parameters

pViewContext

Input parameter pointing to the view context object to be set as current.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Form viewers call the IMAPIForm::SetViewContext method to set a particular form view context to be current. A typical implementation of SetViewContext sets up a view advise-sink object by calling the IMAPIViewContext::SetAdviseSink method, so that notifications can be received for the view context, and calls the IMAPIViewContext::GetViewStatus method to determine which status flags have been set for the view context to be set as current.

A form can have only one view context at a time. If a previous view context exists, the implementation must call IMAPIViewContext::SetAdviseSink, passing in NULL in the pmnvs parameter, before returning from the SetViewContext call.

The implementation can also perform other actions based on the GetViewStatus flags returned. For example, if the VCSTATUS_NEXT and VCSTATUS_PREV flags are set, the implementation can enable Next and Previous buttons for the view context.

See Also

IMAPIViewContext::GetViewStatus method, IMAPIViewContext::SetAdviseSink method


 IMAPIForm::ShutdownForm

[New - Windows 95]

Closes a form object.

Syntax

HRESULT Close(ULONG ulSaveOptions)

Parameters

ulSaveOptions

Input parameter containing a flag used to control how or whether the form's contents are saved when the form is closed. The following mutually exclusive flags can be set:

SAVEOPTS_NOSAVE

Indicates form data should not be saved.

SAVEOPTS_PROMPTSAVE

Prompts the user to save data related to the form if the form has changed.

SAVEOPTS_SAVEIFDIRTY

Indicates data related to the form should be saved if the form has changed. Forms can choose to implement this as either SAVEOPTS_NOSAVE or SAVEOPTS_SAVEIFDIRTY if no user interface is currently being displayed.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Form viewers call the IMAPIForm::ShutdownForm method to close a form object. A typical form server's implementation of ShutdownForm goes through the following process:

1.	Calls the IUnknown::AddRef method for the form's IPersistMessage object so it isn't released before processing is finished.

2.	Handles saving form data as indicated by the flag set in the ulSaveOptions parameter.

3.	Destroys the form's window.

4.	Releases the form's subobjects.

5.	Calls the IMAPIViewAdviseSink::OnClose method to update notifications.

6.	Calls IMAPIViewContext::SetAdviseSink, setting the advise sink pointer to NULL.

7.	Calls the MAPIFreeBuffer function to release the form's properties.

8.	Releases the IPersistMessage object for which it added a reference in Step 1.

9.	Releases all viewer and message site interfaces.

10.	Returns S_OK.

Form viewers can choose to ignore errors returned by ShutdownForm and release the form interface after making the call.

See Also

IMAPIViewAdviseSink::OnShutdown method


 IMAPIForm::Unadvise

[New - Windows 95]

Removes a form viewer's registration for notification of form object changes previously established with a call to the IMAPIForm::Advise method.

Syntax

HRESULT Unadvise(ULONG ulConnection)

Parameters

ulConnection

Input parameter containing the number of the registration connection previously returned by a call to IMAPIForm::Advise.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Form viewers call the IMAPIForm::Unadvise method to cancel notifications for a form object. To do so, Unadvise releases the pointer to the view advise-sink object passed in the pAdvise parameter in the previous call to IMAPIForm::Advise. As part of discarding the pointer to the view advise sink, the view advise sink's IUnknown::Release method is called. Generally, Release is called during Unadvise, but if another thread is in the process of calling one of the IMAPIViewAdviseSink methods for the view advise-sink object, the Release call is delayed until the method call returns.

See Also

IMAPIForm::Advise method, IMAPIViewAdviseSink : IUnknown interface


 IMAPIFormAdviseSink : IUnknown

[New - Windows 95]

The IMAPIFormAdviseSink interface is implemented by form objects, which receive notifications from form viewers. Although part of the form object, IMAPIFormAdviseSink is not an interface on a form object. Hence, client applications should not expect to use the QueryInterface method from a form object to query for this interface.

At a Glance

Specified in header file:	MAPIFORM.H
Object that supplies this interface:	Form advise-sink object
Corresponding pointer type:	LPMAPIFORMADVISESINK
Implemented by:	Form object
Called by:	Form viewers
Vtable Order

OnChange	Notifies a form about a new status for handling commands that activate the next or previous message handled by the form.
OnActivateNext	Identifies whether the message class of the next message can be handled by the current form.


 IMAPIFormAdviseSink::OnActivateNext

[New - Windows 95]

Identifies whether the message class of the next message to be displayed can be handled by the current form object.

Syntax

HRESULT OnActivateNext(LPCSTR lpszMessageClass, ULONG ulMessageStatus, ULONG ulMessageFlags, LPPERSISTMESSAGE FAR * ppPersistMessage)

Parameters

lpszMessageClass

Input parameter pointing to the string naming the message class of the form.

ulMessageStatus

Input parameter containing a bitmask of client application- or service provider-defined flags, copied from the PR_MSG_STATUS property of the message, that provides information on the state of the message.

ulMessageFlags

Input parameter pointing to a bitmask of flags, copied from the PR_MESSAGE_FLAGS property of the message, that indicates the current state of the message.

ppPersistMessage

Output parameter pointing to a variable where the pointer to the IPersistMessage object used for the new form is stored. A pointer to NULL can be returned if the current form object can be used to display the next message.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

S_FALSE

The form does not handle the message class.

Comments

Form viewers call the IMAPIFormAdviseSink::OnActivateNext method to find out if the message class of a message can be handled by the current form object. The form object should return NULL in the ppPersistMessage parameter and an HRESULT of S_OK if the message class is handled by the current form object. If the form object cannot handle the message's class, it should return S_FALSE. If the form object can activate message classes other than the base class or the currently loaded class, it should return S_OK and a pointer to the IPersistMessage object of the appropriate form object for that message class in the ppPersistMessage parameter. The message in question is then loaded by the form viewer using the IPersistMessage::Load method of that object.

See Also

IPersistMessage::Load method


 IMAPIFormAdviseSink::OnChange

[New - Windows 95]

Notifies a form object about a change in the viewer's status.

Syntax

HRESULT OnChange(ULONG ulDir)

Parameters

ulDir

Input parameter containing a bitmask of flags for handling changes to the form's viewer status. The value can contain the following flags:

VCSTATUS_READONLY

The delete, submit, and move operations should be disabled.

VCSTATUS_NEXT

Indicates that there is a next message in the viewer.

VCSTATUS_PREV

Indicates that there is a previous message in the viewer.

VCSTATUS_INTERACTIVE

If this flag is not set, indicates the form should suppress displaying user interface even in response to a verb which might otherwise cause user interface to be displayed.

VCSTATUS_MODAL

Indicates the form is to be modal to the viewer.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Form viewers call the IMAPIFormAdviseSink::OnChange method to notify the form object about a change in the viewer status. Normally the only change is setting or clearing the VCSTATUS_NEXT or VCSTATUS_PREVIOUS flags based on the presence or absence of a next or previous message in the viewer. The form object then enables or disables any next or previous actions it supports.

The values for VCSTATUS_MODAL and VCSTATUS_INTERACTIVE cannot change values in a view context once it has been created.

See Also

IMAPIViewContext::ActivateNext method


 IMAPIFormContainer : IUnknown

[New - Windows 95]

The IMAPIFormContainer interface creates and manages form registries within folders. This interface is used to create application-specific form registries.

At a Glance

Specified in header file:	MAPIFORM.H
Object that supplies this interface:	Form container object
Corresponding pointer type:	LPMAPIFORMCONTAINER
Implemented by:	Form registry providers
Called by:	Client applications
Vtable Order

InstallForm	Installs a form into a form registry.
RemoveForm	Removes a particular form from the form registry.
ResolveMessageClass	Resolves a message class to a form within a form container and returns a form information object for that form.
ResolveMultipleMessageClasses	Resolves group message classes to their forms within a form container and returns an array of form information objects for those forms.
CalcFormPropSet	Returns an array of the properties used by all forms installed within a form container.
GetDisplay	Returns the display name of a form container.


 IMAPIFormContainer::CalcFormPropSet

[New - Windows 95]

Returns an array of the properties used by all forms installed within a form container.

Syntax

HRESULT CalcFormPropSet(ULONG ulFlags, LPMAPIFORMPROPARRAY FAR * ppResults)

Parameters

ulFlags

Input parameter containing a bitmask of flags used to control how the property array in the ppResults parameter is returned. The following flags can be set:

MAPI_UNICODE

Indicates the passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

FORM_PROPSET_INTERSECTION

Indicates the returned array contains the intersection of the forms' properties.

FORM_PROPSET_UNION

Indicates the returned array contains the union of the forms' properties.

ppResults

Output parameter pointing to a variable where the pointer to the returned MAPIFORMPROPARRAY array is stored. This array contains the properties used by the forms.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_BAD_CHARWIDTH

Either the MAPI_UNICODE flag was set and the implementation does not support Unicode, or MAPI_UNICODE was not set and the implementation only supports Unicode.

Comments

Client applications call the IMAPIFormContainer::CalcFormPropSet method to obtain an array of properties used by all forms installed within a form container. CalcFormPropSet either takes an intersection or a union of these forms' property sets, depending on the flag set in the ulFlags parameter, and returns a MAPIFORMPROPARRAY structure containing information on the resulting group of properties. Passing the PROPSET_UNION flag in ulFlags obtains the results from a union; passing the PROPSET_INTERSECTION flag obtains the results from an intersection.

If a client passes the MAPI_UNICODE flag in ulFlags, all strings returned are Unicode. Form registry providers that do not support Unicode strings should return MAPI_E_BAD_CHARWIDTH if MAPI_UNICODE is passed.

CalcFormPropSet acts as does the IMAPIFormMgr::CalcFormPropSet method, except that it operates on every form registered in a particular container.

See Also

IMAPIFormMgr::CalcFormPropSet method, SMAPIFormPropArray structure


 IMAPIFormContainer::GetDisplay

[New - Windows 95]

Returns the display name of a form container.

Syntax

HRESULT GetDisplay(ULONG ulFlags, LPTSTR FAR * pszDisplayName)

Parameters

ulFlags

Input parameter containing a bitmask of flags. The following flag can be set:

MAPI_UNICODE

Indicates returned strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

pszDisplayName

Output parameter pointing to a string containing the display name of the form container.

Return Values

S_OK

The call succeeded and has returned the expected value or values.


 IMAPIFormContainer::InstallForm

[New - Windows 95]

Installs a form into a form container.

Syntax

HRESULT InstallForm(ULONG ulUIParam, ULONG ulFlags, LPCTSTR szCfgPathName)

Parameters

ulUIParam

Input parameter containing the handle of the parent window that the dialog box is modal to if the ulFlags parameter contains the MAPI_DIALOG flag. This parameter can be NULL if the MAPI_DIALOG flag is not also passed.

ulFlags

Input parameter containing a bitmask of flags used to control the installation of the form. The following flags can be set:

MAPI_DIALOG

Displays a dialog box to provide status or prompt the user for additional information. If this flag is not set, no dialog box is displayed.

MAPI_UNICODE

Indicates the passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

MAPIFORM_OVERWRITEONCONFLICT

Indicates a previous definition of the form is to be replaced with the definition of the form being installed.

szCfgPathName

Input parameter containing the path to the forms configuration file that describes the form and its implementation.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_EXTENDED_ERROR

An implementation error occurred; call IMAPIFormContainer::GetLastError to get the MAPIERROR structure associated with the error.

MAPI_E_USER_CANCEL

The user canceled the installation of the form, typically by clicking the cancel button in the dialog box.

Comments

Client applications call the IMAPIFormContainer::InstallForm method to install a form into a specific form container. The szCfgPathName parameter must contain the path of a form configuration file (that is, a file with the .CFG extension) that describes the form and its implementation. The ulFlags parameter specifies:

•	That a user interface enabling the user installing the form to specify details of installation is displayed, if the MAPI_DIALOG flag is set.

•	That the previous form definition is overlaid with the form being installed, if the MAPIFORM_OVERWRITEONCONFLICT flag is set. Otherwise the form installation is merged with the current form description, if one exists.

•	That the path to the form configuration file is a Unicode string, if the MAPI_UNICODE flag is set.

Form registry providers implementing InstallForm should fill in a MAPIERROR structure and return MAPI_E_EXTENDED_ERROR if any of the following conditions occur:

•	The configuration file is not found

•	The configuration file is not readable

•	The configuration file is invalid.

Client applications should call IMAPIFormContainer::GetLastError if InstallForm returns MAPI_E_EXTENDED_ERROR and check the returned MAPIERROR structure to determine the condition causing the error.


 IMAPIFormContainer::RemoveForm

[New - Windows 95]

Removes a particular form from the form container.

Syntax

HRESULT RemoveForm(LPCSTR szMessageClass)

Parameters

szMessageClass

Input parameter containing a string naming the message class of the form to be removed from the registry. Message class names are always ANSI strings, never Unicode.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NOT_FOUND

The message class passed in the szMessageClass parameter does not the match the message class for any forms in the form registry.


 IMAPIFormContainer::ResolveMessageClass

[New - Windows 95]

Resolves a message class to a form within a form container and returns a form information object for that form.

Syntax

HRESULT ResolveMessageClass(LPCSTR szMessageClass, ULONG ulFlags, LPMAPIFORMINFO FAR * ppforminfo)

Parameters

szMessageClass

Input parameter containing a string naming the message class of the form being resolved.

ulFlags

Input parameter containing a bitmask of flags used to control how the message class is resolved. The following flag can be set:

MAPIFORM_EXACTMATCH

Indicates that only message class strings that are an exact match should be resolved.

ppforminfo

Output parameter pointing to a variable where a pointer to the returned form information object is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NOT_FOUND

The message class passed in the szMessageClass parameter does not match the message class for any forms in the form container.

Comments

Client applications call the IMAPIFormContainer::ResolveMessageClass method to resolve a message class to a form within a form container. The form information object returned in the ppforminfo parameter provides further access to the form's properties.

To resolve a message class to a form, your application passes in the name of the message class to be resolved, for example, IPM.HelpDesk.Software. To force the resolution to be exact, that is, to prevent resolution to a superclass of the message class, the MAPIFORM_EXACTMATCH flag can be passed in the ulFlags parameter.

Message class names are always ANSI strings, never Unicode.

The class identifier for the resolved message class is returned as part of the form information object. Client applications should not assume that the class identifier exists in the OLE registry until after the client has called either the IMAPIFormMgr::PrepareForm method or the IMAPIFormMgr::CreateForm method.

See Also

IMAPIFormInfo : IMAPIProp interface, IMAPIFormMgr::CreateForm method, IMAPIFormMgr::PrepareForm method


 IMAPIFormContainer::ResolveMultipleMessageClasses

[New - Windows 95]

Resolves group message classes to their forms within a form container and returns an array of form information objects for those forms.

Syntax

HRESULT ResolveMultipleMessageClasses (LPSMESSAGECLASSARRAY pMsgClassArray, ULONG ulFlags, LPSMAPIFORMINFOARRAY FAR * ppfrminfoarray)

Parameters

pMsgClassArray

Input parameter pointing to an array containing the message classes to be resolved.

ulFlags

Input parameter containing a bitmask of flags used to control how the message classes are resolved. The following flag can be set:

MAPIFORM_EXACTMATCH

Indicates that only message class strings that are an exact match should be resolved.

ppfrminfoarray

Output parameter pointing to a variable where the pointer to an array of form information objects is stored. If the client application passes NULL in the pMsgClassArray parameter, the ppfrminfoarray contains form information objects for all forms in the registry.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Client applications call the IMAPIFormContainer::ResolveMultipleMessageClasses method to resolve a group of message classes to forms within a form container. The array of form information objects returned in the ppforminfoarray parameter provides further access to each of the forms' properties. If a message class cannot be resolved to a form, NULL is returned for that message class. So although the method returns S_OK, applications should not assume that all message classes have been successfully resolved; applications should check the values in the returned array.

Your application passes in an array of message class names to be resolved. To force the resolution to be exact, that is, to prevent resolution to a superclass of the message class, the MAPIFORM_EXACTMATCH flag can be passed in the ulFlags parameter.

Message class names are always ANSI strings, never Unicode.

See Also

IMAPIFormContainer::ResolveMessageClass method


 IMAPIFormFactory : IUnknown

[New - Windows 95]

The IMAPIFormFactory interface supports the use of configurable run-time forms in distributed computing environments. This interface is based on the OLE IClassFactory interface, and objects implementing IMAPIFormFactory should also inherit from IClassFactory. For more information on IClassFactory, see OLE Programmer's Reference, Volume One, and Inside OLE, Second Edition.

At a Glance

Specified in header file:	MAPIFORM.H
Object that supplies this interface:	Form factory object
Corresponding pointer type:	LPMAPIFORMFACTORY
Implemented by:	Form servers
Called by:	Form viewers
Vtable Order

CreateClassFactory	Returns a class factory object for a form.
LockServer	Keeps an open form server in memory.


 IMAPIFormFactory::CreateClassFactory

[New - Windows 95]

Returns a class factory object for a form.

Syntax

HRESULT CreateClassFactory(REFCLSID clsidForm, ULONG ulFlags, LPCLASSFACTORY FAR * lppClassFactory)

Parameters

clsidForm

Input parameter indicating the message-class identifier of the form for which to create the class factory.

ulFlags

Reserved; must be zero.

lppClassFactory

Output parameter pointing to a variable where the returned class factory object is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

The IMAPIFormFactory::CreateClassFactory method is used to obtain a class factory for a specific form from a form runtime package. The same object can be returned by CreateClassFactory on multiple calls for the same message class identifier; creating a new instance is not required. The class factory returned will be used to generate a new instance of the form..


 IMAPIFormFactory::LockServer

[New - Windows 95]

Keeps an open form server in memory.

Syntax

HRESULT LockServer(ULONG ulFlags, ULONG fLockServer)

Parameters

ulFlags

Reserved; must be zero.

fLockServer

Input parameter indicating TRUE if the lock count is to be incremented, FALSE otherwise.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Form viewers call the IMAPIFormFactory::LockServer method to keep an open form-server application in memory. Keeping the form server in memory improves its performance when form objects are created and released frequently.


 IMAPIFormInfo : IMAPIProp

[New - Windows 95]

The IMAPIFormInfo interface gives client applications access to useful properties particular to form definition. By keeping form information in a separate object, the form registry provider can describe a form to a client without activating the form itself.

Unlike most interfaces defined in the MAPIFORM.H file, IMAPIFormInfo inherits from the IMAPIProp interface, as it exports most form information through calls to the IMAPIProp::GetProps method.

At a Glance

Specified in header file:	MAPIFORM.H
Object that supplies this interface:	Form information object
Corresponding pointer type:	LPMAPIFORMINFO
Implemented by:	Form registry providers
Called by:	Client applications
Vtable Order

CalcFormPropSet	Returns a pointer to the complete set of properties published by a form.
CalcVerbSet	Returns a pointer to the complete set of verbs used by a form.
MakeIconFromBinary	Builds an icon from an icon property of a form.
SaveForm	Saves a description of the current form in a configuration file with the given filename.
OpenFormContainer	Returns a pointer to the form container object in which the current form is registered.


 IMAPIFormInfo::CalcFormPropSet

[New - Windows 95]

Returns a pointer to the complete set of properties published by a form.

Syntax

HRESULT CalcFormPropSet (ULONG ulFlags, LPMAPIFORMPROPARRAY FAR * ppFormPropArray)

Parameters

ulFlags

Input parameter containing a bitmask of flags. The following flag can be set:

MAPI_UNICODE

Indicates the returned strings are to be in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

ppFormPropArray

Output parameter pointing to a variable where the pointer to the array of returned properties is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.


 IMAPIFormInfo::CalcVerbSet

[New - Windows 95]

Returns a pointer to the complete set of verbs published by a form.

Syntax

HRESULT CalcVerbSet(ULONG ulFlags, LPMAPIVERBARRAY FAR * ppMAPIVerbArray)

Parameters

ulFlags

Input parameter containing a bitmask of flags. The following flag can be set:

MAPI_UNICODE

Indicates the strings are returned in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

ppMAPIVerbArray

Output parameter pointing to a variable where the pointer to the returned SMAPIVerbArray structure is stored. The SMAPIVerbArray structure contains the form's verbs.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Client applications call the IMAPIFormInfo::CalcVerbSet method to obtain a pointer to the set of verbs used by a form. Within the SMAPIVerbArray structure returned in the ppMAPIVerbArray parameter, the verbs are returned in order of index number; each verb's index is found in its lVerb member.

See Also

SMAPIVerbArray structure


 IMAPIFormInfo::MakeIconFromBinary

[New - Windows 95]

Builds an icon from an icon property of a form.

Syntax

HRESULT MakeIconFromBinary(ULONG nPropID, HICON FAR * phicon)

Parameters

nPropID

Input parameter containing the property identifier for an icon property.

phicon

Output parameter pointing to the returned icon.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Client applications call the IMAPIFormInfo::MakeIconFromBinary method to build an icon from an icon property of a form. In the nPropID parameter, MakeIconFromBinary takes the property identifier of any of the icon properties of a form and builds an icon that can be displayed in table views that include property columns for icons.


 IMAPIFormInfo::OpenFormContainer

[New - Windows 95]

Returns a pointer to the form container object in which the current form is registered.

Syntax

HRESULT OpenFormContainer (LPMAPIFORMCONTAINER FAR * ppformcontainer)

Parameters

ppformcontainer

Output parameter pointing to a variable where the pointer to the returned form container object is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.


 IMAPIFormInfo::SaveForm

[New - Windows 95]

Saves a description of the current form in a configuration file with the given filename.

Syntax

HRESULT SaveForm(LPCTSTR szFileName)

Parameters

szFileName

Input parameter containing a string to name the form descriptor message file where the form description is saved. This filename must have the .FDM extension.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_EXTENDED_ERROR

The configuration file could not be written.

Comments

Client applications call the IMAPIFormInfo::SaveForm method to save a description of the current form in a file with the given filename. SaveForm creates a configuration file, and the filename passed in the szFileName parameter must have the .FDM extension.

Forms can be reinstalled later by being selected from a list of form descriptor messages in a dialog box displayed by form registry providers. The recommended extension for form descriptor messages is "FDM."


 IMAPIFormMgr : IUnknown

[New - Windows 95]

The IMAPIFormMgr interface is used by form-viewer client applications to get information about and activate form servers.

At a Glance

Specified in header file:	MAPIFORM.H
Object that supplies this interface:	Form manager object
Corresponding pointer type:	LPMAPIFORMMGR
Implemented by:	Forms registry providers
Called by:	Form viewers
Vtable Order

LoadForm	Launches a form so as to open an existing message.
ResolveMessageClass	Resolves a message class to a form within a form registry and returns a form information object for that form.
ResolveMultipleMessageClasses	Resolves group message classes to their forms within a form registry and returns an array of form information objects for those forms.
CalcFormPropSet	Returns an array of the properties published by a group of forms.
CreateForm	Launches a form so as to create a new message based on that form.
SelectForm	Presents a dialog box that enables the user to select a form, then returns a form information object describing that form.
SelectMultipleForms	Presents a dialog box that enables the user to select multiple forms, then returns an array of form information objects describing the forms.
SelectFormContainer	Presents a dialog box that enables the user to select the form registry into which to install a form, then returns an interface for the registry object the user selected.
OpenFormContainer	Opens an IMAPIFormContainer interface on a specific form container.
PrepareForm	Downloads a form for launching.
IsInConflict	Determines whether the form can handle its own conflicts.


 IMAPIFormMgr::CalcFormPropSet

[New - Windows 95]

Returns an array of the properties used by a group of forms.

Syntax

HRESULT CalcFormPropSet (LPSMAPIFORMINFOARRAY pfrminfoarray, ULONG ulFlags, LPMAPIFORMPROPARRAY FAR * ppResults)

Parameters

pfrminfoarray

Input parameter pointing to an array of form information objects identifying the forms for which to return published properties.

ulFlags

Input parameter containing a bitmask of flags used to control how the property array in the ppResults parameter is returned. The following flags can be set:

MAPI_UNICODE

Indicates the passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

FORM_PROPSET_INTERSECTION

Indicates that the returned array contains the intersection of the form's properties.

FORM_PROPSET_UNION

Indicates that the returned array contains the union of the form's properties.

ppResults

Output parameter pointing to a variable where the pointer to the returned SMAPIFormPropArray structure is stored. This array contains the properties published by the forms.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_BAD_CHARWIDTH

Either the MAPI_UNICODE flag was set and the implementation does not support Unicode, or MAPI_UNICODE was not set and the implementation only supports Unicode.

Comments

Client applications call the IMAPIFormContainer::CalcFormPropSet method to obtain an array of the properties used by a group of forms. CalcFormPropSet either takes an intersection or a union of these forms' property sets, depending on the flag set in the ulFlags parameter, and returns an SMAPIFormPropArray structure containing information on the resulting group of properties. Passing the PROPSET_UNION flag in ulFlags obtains the results from a union; passing the PROPSET_INTERSECTION flag obtains the results from an intersection.

If a client passes the MAPI_UNICODE flag in ulFlags, all strings returned are Unicode. Form registry providers that do not support Unicode strings should return MAPI_E_BAD_CHARWIDTH if MAPI_UNICODE is passed.

See Also

SMAPIFormPropArray structure


 IMAPIFormMgr::CreateForm

[New - Windows 95]

Launches a form so as to create a new message based on that form.

Syntax

HRESULT CreateForm(ULONG ulUIParam, ULONG ulFlags, IMAPIFormInfo pfrminfoToActivate, REFIID refiidToAsk, LPVOID FAR * ppvObj)

Parameters

ulUIParam

Input parameter containing a handle to the main window of the calling application, cast to a ULONG. The ulUIParam parameter is used in this case to display a progress user interface while the form is being loaded. The ulUIParam parameter is ignored unless the MAPI_DIALOG flag is set in the ulFlags parameter.

ulFlags

Input parameter containing a bitmask of flags used to control the loading of the form. The following flag can be set:

MAPI_DIALOG

Displays a dialog box to provide status or prompt the user for additional information. If this flag is not set, no dialog box is displayed.

pfrminfoToActivate

Input parameter pointing to the form information object used to launch the form.

refiidToAsk

Input parameter pointing to the interface identifier (IID) for the interface to be returned on the form object created. The refiidToAsk parameter must not be NULL.

ppvObj

Output parameter pointing to a variable where the pointer to the interface returned is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NO_INTERFACE

The requested interfaced is not supported by the form object.

Comments

Client applications call the IMAPIFormMgr::CreateForm method to launch a form so as to create a new message based on the form. CreateForm launches the form by creating an instance of its form server for that form as described in the given form information object. If required, CreateForm will call IMAPIFormMgr::PrepareForm to download the form server code to the user's disk.

The pfrminfoToActivate parameter must point to a form information object for the form that has been correctly resolved.

After the form has been launched, the calling application must set up a message using the IPersistMessage interface and can optionally set up an IMAPIViewContext for the form. For more information on forms launching, see MAPI Programmer's Guide.

See Also

IMAPIViewContext : IUnknown interface, IPersistMessage : IUnknown interface


 IMAPIFormMgr::IsInConflict

[New - Windows 95]

Determines whether the form can handle its own conflicts.

HRESULT IsInConflict(ULONG ulMessageFlags, ULONG ulMessageStatus, LPCSTR szMessageClass)

Parameters

ulMessageFlags

Input parameter pointing to a bitmask of flags, copied from the PR_MESSAGE_FLAGS property of a message, that indicates the current state of the message.

ulMessageStatus

Input parameter containing a bitmask of client application- or service provider-defined flags, copied from the PR_MSG_STATUS property of a message, that provides further information on the state of the message.

szMessageClass

Input parameter containing a string naming the message's message class.

Return Values

S_OK

The form does not handle its own conflicts.

S_FALSE

The form handles its own conflicts, or the message is not in conflict.

Comments

Client applications call the IMAPIFormMgr::IsInConflict method to discover if a particular form does not handle its own conflicts. IsInConflict checks the bitmasks in the ulMessageFlags and ulMessageStatus parameters for the presence of a conflict flag. If a conflict flag is set, IsInConflict resolves the message class passed in the szMessageClass parameter and returns S_OK if the form does not handle its own conflicts. S_FALSE is returned if the form handles its own conflicts.

A form that does not handle its own conflicts must be launched using IMAPIForm::LoadForm and cannot reuse an existing form object.

See Also

IMAPIFormAdviseSink::OnActivateNext method, PR_MESSAGE_FLAGS property, PR_MSG_STATUS property


 IMAPIFormMgr::LoadForm

[New - Windows 95]

Launches a form so as to open an existing message.

Syntax

HRESULT LoadForm(ULONG ulUIParam, ULONG ulFlags, LPCSTR lpszMessageClass, ULONG ulMessageStatus, ULONG ulMessageFlags LPMAPIFOLDER pFolderFocus, LPMAPIMESSAGESITE pMessageSite, LPMESSAGE pmsg, LPMAPIVIEWCONTEXT pViewContext, REFIID riid, LPVOID FAR * ppvObj)

Parameters

ulUIParam

Input parameter containing a handle to the main window of the calling application, cast to a ULONG. The ulUIParam parameter is used in this case to display a progress user interface while the form is being loaded. The ulUIParam parameter is ignored unless the MAPI_DIALOG flag is set in the ulFlags parameter.

ulFlags

Input parameter containing a bitmask of flags used to control the loading of the form. The following flag can be set:

MAPI_DIALOG

Displays a dialog box to provide status or prompt the user for additional information. If this flag is not set, no dialog box is displayed.

MAPIFORM_EXACTMATCH

Indicates that only message class strings that are an exact match should be resolved.

lpszMessageClass

Input parameter pointing to the message class for the message to be loaded. If NULL is passed in this parameter, the message class is determined from the message pointed to by the pmsg parameter.

ulMessageStatus

Input parameter containing a bitmask of client application- or service provider-defined flags, copied from the PR_MSG_STATUS property of the message, that provides information on the state of the message. Must be set if lpszMessageClass is nonnull, otherwise this parameter is ignored.

ulMessageFlags

Input parameter containing a bitmask of flags, copied from the PR_MESSAGE_FLAGS property of the message, that indicates the current state of the message. Must be set if lpszMessageClass is nonnull; otherwise this parameter is ignored.

pFolderFocus

Input parameter pointing to the folder containing the message. pFolderFocus can be NULL if a folder doesn't exit.

pMessageSite

Input parameter pointing to the message site of the message.

pmsg

Input parameter pointing to the message.

pViewContext

Input parameter pointing to the view context for the message. The pViewContext parameter can be NULL.

riid

Input parameter containing the interface identifier (IID) of the requested interface for the returned form object. The refiidToAsk parameter must not be NULL.

ppvObj

Output parameter pointing to a variable where the pointer to the returned interface is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NO_INTERFACE

The form does not support the requested interface.

MAPI_E_NOT_FOUND

The message class passed in the lpszMessageClass parameter does not match the message class for any forms in the form registry.

Comments

Client applications call the IMAPIFormMgr::LoadForm method to launch a form so as to create a form object for an existing message. LoadForm launches the form object, loads the message into the form object, sets up the view context if necessary, and returns the requested interface for the form object.

The pFolderFocus parameter points to the folder containing the message. If the message is embedded within another message, pFolderFocus should be NULL. If NULL is passed in the lpszMessageClass parameter, then the implementation will obtain the message class and the PR_MSG_STATUS and PR_MESSAGE_FLAGS properties. If a message class string is provided in lpszMessageClass, then the implementation should set the flags in ulMessageStatus and ulMessageFlags.

See Also

PR_MESSAGE_FLAGS property, PR_MSG_STATUS property


 IMAPIFormMgr::OpenFormContainer

[New - Windows 95]

Opens an IMAPIFormContainer interface on a specific form container.

Syntax

HRESULT OpenFormContainer(HFRMREG hfrmreg, LPUNKNOWN lpunk, LPMAPIFORMCONTAINER FAR * lppfcnt)

Parameters

hfrmreg

Input parameter containing an HFRMREG enumeration indicating the form registry to open. A HFRMREG enumeration is an enumeration specific to a form registry provider. Possible HFRMREG values include:

HFRMREG_DEFAULT

Indicates a convenient registry container.

HFRMREG_ENTERPRISE

Indicates the public folder registry.

HFRMREG_FOLDER

Indicates a folder registry container.

HFRMREG_PERSONAL

Indicates the container for the default message store.

HFRMREG_LOCAL

Indicates the local registry container.

lpunk

Input parameter pointing to the object for which the interface is opened. The lpunk parameter must be NULL unless the value for the hfrmreg parameter requires an object pointer.

lppfcnt

Output parameter pointing to a variable where the pointer to the returned form container object is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NO_INTERFACE

The object pointed to by the lpUnk parameter does not support the required interface.

Comments

Client applications call the IMAPIFormMgr::OpenFormContainer method to open an IMAPIFormContainer interface for a specific form container. This interface can then be used for installing and removing forms.

If the value in the hfrmreg parameter is HFRMREG_FOLDER case, which indicates a folder container, the interface identifier used in the lpunk parameter must be non-null and must allow QueryInterface calls to a IMAPIFolder interface.

A call to OpenFormContainer or the MAPIOpenLocalFormContainer function must be used to open the local registry container; IMAPIFormMgr::SelectFormContainer cannot be used to allow the user to select the local form container.

See Also

IMAPIFormContainer::InstallForm method, IMAPIFormMgr::SelectFormContainer method, MAPIOpenLocalFormContainer function


 IMAPIFormMgr::PrepareForm

[New - Windows 95]

Downloads a form for launching.

Syntax

HRESULT PrepareForm(ULONG ulUIParam, ULONG ulFlags, LPMAPIFORMINFO pfrmiInfo)

Parameters

ulUIParam

Input parameter containing a handle to the main window of the calling application, cast to a ULONG. The ulUIParam parameter is used in this case to display a progress user interface while the form is downloaded. The ulUIParam parameter is ignored unless the MAPI_DIALOG flag is set in the ulFlags parameter.

ulFlags

Input parameter containing a bitmask of flags used to control how the form is downloaded. The following flag can be set:

MAPI_DIALOG

Displays a dialog box to provide status or prompt the user for additional information. If this flag is not set, no dialog box is displayed.

pfrmiInfo

Input parameter pointing to a form information object for the form to be downloaded.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Client applications call the IMAPIFormMgr::PrepareForm method to download a form from the form registry for launching. Most clients do not need to call PrepareForm as both the IMAPIFormMgr::CreateForm and IMAPIFormMgr::LoadForm methods call PrepareForm if necessary.

PrepareForm can be used by clients to obtain the dynamic-link libraries (DLLs) and other files associated with a form in order to modify them. If the modified form is to be loaded back into its form registry, the form must be reinstalled.

See Also

IMAPIFormMgr::CreateForm method, IMAPIFormMgr::LoadForm method


 IMAPIFormMgr::ResolveMessageClass

[New - Windows 95]

Resolves a message class to a form within the form registry and returns a form information object for that form.

Syntax

HRESULT ResolveMessageClass(LPCSTR szMsgClass, ULONG ulFlags, LPMAPIFOLDER pFolderFocus, LPMAPIFORMINFO FAR * ppResult)

Parameters

szMsgClass

Input parameter containing a string naming the message class to be resolved.

ulFlags

Input parameter containing a bitmask of flags used to control how the message class is resolved. The following flag can be set:

MAPIFORM_EXACTMATCH

Indicates that only message class strings that are an exact match should be resolved.

pFolderFocus

Input parameter pointing to the folder containing the message being resolved. The pFolderFocus parameter can be NULL.

ppResult

Output parameter pointing to a variable where the pointer to a returned form information object is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NOT_FOUND

The message class passed in the szMessageClass parameter does not the match the message class for any forms in the form registry.

Comments

Client applications call the IMAPIFormMgr::ResolveMessageClass method to resolve a message class to a form within the form registry. The form information object returned in the ppResult parameter provides further access to the form's properties. Your application passes in the name of the message class to be resolved, for example, IPM.HelpDesk.Software. The MAPIFORM_EXACTMATCH flag can be passed in the ulFlags parameter to force the resolution to be exact, that is, prohibiting resolution to super classes of the message class. The pFolderFocus parameter should contain the folder containing the message being resolved; it can, however, be NULL, in which case the message-class resolution process does not search a folder registry container.

The order of the containers searched is dependent on the implementation of the form registry provider. The default registry searches the local container, the folder container for the passed-in folder, the personal container registry, and finally, the enterprise registry container.

Message class names are always ANSI strings, never Unicode.

The class identifier for the resolved message class is returned as part of the form information object. Client applications should not assume that the class identifier exists in the OLE registry until after the client has called either the IMAPIFormMgr::PrepareForm method or the IMAPIFormMgr::CreateForm method.

See Also

IMAPIFormInfo : IMAPIProp interface, IMAPIFormMgr::CreateForm method, IMAPIFormMgr::PrepareForm method


 IMAPIFormMgr::ResolveMultipleMessageClasses

[New - Windows 95]

Resolves group message classes to their forms within the form registry and returns an array of form information objects for those message classes.

Syntax

HRESULT ResolveMultipleMessageClasses(LPSMESSAGECLASSARRAYpMsgClasses, ULONG ulFlags, LPMAPIFOLDER pFolderFocus, LPSMAPIFORMINFOARRAY FAR * ppfrminfoarray)

Parameters

pMsgClasses

Input parameter pointing to an array containing the message classes to be resolved.

ulFlags

Input parameter containing a bitmask of flags used to control how the message classes are resolved. The following flag can be set:

MAPIFORM_EXACTMATCH

Indicates that only message class strings that are an exact match should be resolved.

pFolderFocus

Input parameter pointing to the folder containing the form whose message class is to be resolved. The pFolderFocus parameter can be NULL.

ppfrminfoarray

Output parameter pointing to a variable where the pointer to an array of form information objects describing the forms and their locations is stored. If the client application passes NULL in the pMsgClasses parameter, the ppfrminfoarray contains information for all forms in the registry.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Client applications call the IMAPIFormMgr::ResolveMultipleMessageClasses method to resolve a group of message classes to forms within the form registry. The array of form information objects returned in the ppforminfoarray parameter provides further access to each of the forms' properties. If a message class cannot be resolved to a form, NULL is returned for that message class. So although the method returns S_OK, applications should not assume that all message classes have been successfully resolved; applications should check the values in the returned array.

Your application passes in an array of message class names to be resolved. The MAPIFORM_EXACTMATCH flag can be passed in the ulFlags parameter to force the resolution to be exact, that is, preventing resolution to super classes of the message class.

Message class names are always ANSI strings, never Unicode.

See Also

IMAPIFormMgr::ResolveMessageClass method


 IMAPIFormMgr::SelectForm

[New - Windows 95]

Presents a dialog box that enables the user to select a form, then returns a form information object describing that form.

Syntax

HRESULT SelectForm(ULONG ulUIParam, ULONG ulFlags, LPCTSTR pszTitle, LPMAPIFOLDER pfld, LPMAPIFORMINFO FAR * ppfrminfoReturned)

Parameters

ulUIParam

Input parameter containing a handle to the main window of the calling application, cast to a ULONG. The ulUIParam parameter is used in this case to display the dialog box.

ulFlags

Input parameter containing a bitmask of flags. The following flag can be set:

MAPI_UNICODE

Indicates the passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

pszTitle

Input parameter pointing to a string containing the caption of the dialog box. If the pszTitle parameter is NULL, the form registry provider supplies a default caption.

pfld

Input parameter pointing to the folder from which to select the form. If the pfld parameter is NULL, the form can be selected from the local, personal, or enterprise form container.

ppfrminfoReturned

Output parameter pointing to a pointer to the returned form information object.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_BAD_CHARWIDTH

Either the MAPI_UNICODE flag was set and the implementation does not support Unicode, or MAPI_UNICODE was not set and the implementation only supports Unicode.

MAPI_E_USER_CANCEL

The user canceled the dialog box.

Comments

Client applications call the IMAPIFormMgr::SelectForm method to first present a dialog box that enables the user to select a form and then to retrieve a form information object describing the selected form. The dialog box constrains the user to select a single form.

The SelectForm dialog box only displays forms that are not hidden (that is, that have their hidden properties clear). If a client passes the MAPI_UNICODE flag in the ulFlags parameter, all strings are Unicode. Form registry providers that do not support Unicode strings should return MAPI_E_BAD_CHARWIDTH if MAPI_UNICODE is passed.


 IMAPIFormMgr::SelectMultipleForms

[New - Windows 95]

Presents a dialog box that enables the user to select multiple forms, then returns an array of form information objects describing the forms.

Syntax

HRESULT SelectMultipleForms(ULONG ulUIParam, ULONG ulFlags, LPCTSTR pszTitle, LPMAPIFOLDER pfld, LPMAPIFORMINFOARRAY pfrminfoarray, LPMAPIFORMINFOARRAY FAR * ppfrminfoarray)

Parameters

ulUIParam

Input parameter containing a handle to the main window of the calling application, cast to a ULONG. The ulUIParam parameter is used in this case to display the dialog box.

ulFlags

Input parameter containing a bitmask of flags. The following flag can be set:

MAPI_UNICODE

Indicates the passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

pszTitle

Input parameter pointing to a string containing the caption of the dialog box. If the pszTitle parameter is NULL, the form registry provider supplies a default caption.

pfld

Input parameter pointing to the folder from which to select the forms. If the pfld parameter is NULL, the forms are selected from the local, personal, or enterprise form container.

pfrminfoarray

Input parameter pointing to an array of form information objects which are preselected for the user.

ppfrminfoarray

Output parameter pointing to a variable where the pointer to the returned array of form information objects describing the selected forms is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_BAD_CHARWIDTH

Either the MAPI_UNICODE flag was set and the implementation does not support Unicode, or MAPI_UNICODE was not set and the implementation only supports Unicode.

MAPI_E_USER_CANCEL

The user canceled the dialog box.

Comments

Client applications call the IMAPIFormMgr::SelectMultipleForms method to first present a dialog box that enables the user to select multiple forms and then to retrieve an array of form information objects describing the selected forms.

The SelectMultipleForms dialog box displays all forms independent of their hiddenness. If a client passes the MAPI_UNICODE flag in the ulFlags parameter, all strings are Unicode. Form registry providers that do not support Unicode strings should return MAPI_E_BAD_CHARWIDTH if MAPI_UNICODE is passed.


 IMAPIFormMgr::SelectFormContainer

[New - Windows 95]

Presents a dialog box that enables the user to select a form registry container and return an interface for the container object the user selected.

Syntax

HRESULT SelectFormContainer(ULONG ulUIParam, ULONG ulFlags, LPMAPIFORMCONTAINER FAR * lppfcnt)

Parameters

ulUIParam

Input parameter containing a handle to the main window of the calling application, cast to a ULONG. The ulUIParam parameter is used in this case to display the dialog box.

ulFlags

Input parameter containing a bitmask of flags used to control how the registry is selected. The following flags can be set:

MAPIFORM_SELECT_ALL_REGISTRIES

Indicates selection can be made from all for registry containers. This is the default action.

MAPIFORM_SELECT_FOLDER_REGISTRIES_ONLY

Indicates selection can be made only from folder registry containers.

MAPIFORM_SELECT_NON_FOLDER_REGISTRIES_ONLY

Indicates selection can be made only from form registry containers not associated with folders.

lppfcnt

Output parameter pointing to a variable where the pointer to the returned interface for the registry object the user selected is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

The IMAPIFormMgr::SelectFormContainer method is commonly used to select a form container into which a form is installed. SelectFormContainer cannot be used to select the local application form registry, which is HFRMREG_LOCAL.


 IMAPIMessageSite : IUnknown

[New - Windows 95]

The IMAPIMessageSite interface manipulates messages and is implemented by the form viewer code that responds to such manipulation.

At a Glance

Specified in header file:	MAPIFORM.H
Object that supplies this interface:	Message site object
Corresponding pointer type:	LPMAPIMESSAGESITE
Implemented by:	Form viewers
Called by:	Form objects
Vtable Order

GetSession	Returns the MAPI session in which the current message was created or opened.
GetStore	Returns the message store containing the current message, if such a store exists.
GetFolder	Returns the folder in which the current message was created or opened, if such a folder exists.
GetMessage	Returns the current message.
GetFormManager	Returns a form manager interface which the form can use to launch another form.
NewMessage	Creates a new message.
CopyMessage	Copies the current message to a folder.
MoveMessage	Moves the current message to a folder.
DeleteMessage	Deletes the current message.
SaveMessage	Requests that the current message be saved.
SubmitMessage	Requests that the current message be submitted to the MAPI spooler.
GetSiteStatus	Returns information from the message site object about the capabilities of the message site on the message.


 IMAPIMessageSite::CopyMessage

[New - Windows 95]

Copies the current message to a folder.

Syntax

HRESULT CopyMessage(LPMAPIFOLDER pFolderDestination)

Parameters

pFolderDestination

Input parameter pointing to the folder where the message is copied.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NO_SUPPORT

The operation is not supported by this message site.

Comments

Form servers call the IMAPIMessageSite::CopyMessage method to copy the current message to a new folder. CopyMessage does not change the message currently being displayed to the user, and no interface on the new message is returned to the form.

A typical implementation of CopyMessage does the following:

1.	Creates the new message to be copied to.

2.	Calls IPersistMessage::Save(pMsgNew, FALSE).

3.	Calls IPersistMessage::SaveCompleted(NULL).

4.	Calls SaveChanges on the new message.

See Also

IMAPIProp::SaveChanges method, IPersistMessage::Save method, IPersistMessage::SaveCompleted method


 IMAPIMessageSite::DeleteMessage

[New - Windows 95]

Deletes the current message.

Syntax

HRESULT DeleteMessage(LPMAPIVIEWCONTEXT pViewContext, LPCRECT prcPosRect)

Parameters

pViewContext

Input parameter pointing to a view context object.

prcPosRect

Input parameter pointing to the RECT structure containing the current form's window size and position. This window rectangle is used by the next form displayed.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NO_SUPPORT

The operation is not supported by this message site.

Comments

Form servers call the IMAPIMessageSite::DeleteMessage method to delete the message the form is currently attached to. If a form viewer's implementation of DeleteMessage moves to the next message after deleting a message, the implementation is required to call IMAPIViewContext::ActivateNext passing the VCDIR_DELETE flag prior to performing the actual deletion. If a form viewer's implementation of DeleteMessage moves the message, it must save changes to the message if it has been modified.

Following the return of DeleteMessage, form objects must check for a new message and then dismiss themselves if none exists. Form servers wanting to determine whether the message is deleted or whether it is being moved to a deleted items folder can check for the DELETE_IS_MOVE flag on the return from a call to the IMAPIMessageSite::GetSiteStatus method.

A typical implementation of DeleteMessage does the following:

1.	If moving the message, call IPersistMessage::Save(NULL,TRUE).

2.	Call IMAPIViewContext::ActivateNext(VCDIR_DELETE).

3.	If the ActivateNext call failed, return. If ActivateNext returned S_FALSE, call IPersistMessage::HandsOffMessage.

4.	Delete or move the message.

See Also

IMAPIMessageSite::GetSiteStatus method, IMAPIViewContext::ActivateNext method, IPersistMessage::HandsOffMessage method, IPersistMessage::Save method


 IMAPIMessageSite::GetFolder

[New - Windows 95]

Returns the folder in which the current message was created or opened, if one exists.

Syntax

HRESULT GetFolder(LPMAIFOLDER FAR * ppFolder)

Parameters

ppFolder

Output parameter pointing to a pointer to the returned folder.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

S_FALSE

There was no folder for the message.


 IMAPIMessageSite::GetFormManager

[New - Windows 95]

Returns a form manager interface, which the form can use to launch another form.

Syntax

HRESULT GetFormManager(LPMAPIFORMMGR FAR * ppFormMgr)

Parameters

ppFormMgr

Output parameter pointing to a pointer to the returned form manager interface.

Return Values

S_OK

The call succeeded and has returned the expected value or values.


 IMAPIMessageSite::GetMessage

[New - Windows 95]

Returns the current message.

Syntax

HRESULT GetMessage(LPMESSAGE FAR * ppmsg)

Parameters

ppmsg

Output parameter pointing to a pointer to the returned interface for the message.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

S_FALSE

No message currently exists for the form.

Comments

Form objects call the IMAPIMessageSite::GetMessage method to obtain a message interface for the current message. This is the same message as was passed in with either the IPersistMessage::InitNew, IPersistMessage::Load, or the IPersistMessage::SaveCompleted methods.

GetMessage returns S_FALSE if no message currently exists. This can occur after calls to IPersistMessage::HandsOffMessage or before the next call to IPersistMessage::Load or IPersistMessage::SaveCompleted has been made.

See Also

IPersistMessage : IUnknown interface


 IMAPIMessageSite::GetSession

[New - Windows 95]

Returns the MAPI session in which the current message was created or opened.

Syntax

HRESULT GetSession(LPMAPISESSION FAR * ppSession)

Parameters

ppSession

Output parameter pointing to a variable where the pointer to the returned session object is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

S_FALSE

No session exists for the current message.


 IMAPIMessageSite::GetSiteStatus

[New - Windows 95]

Returns information from the message site object about the capabilities of the message site on the message.

Syntax

HRESULT GetSiteStatus(ULONG FAR * lpulStatus)

Parameters

lpulStatus

Output parameter pointing to a variable in which a bitmask of flags giving information on message status is returned. The following flags can be set:

VCSTATUS_COPY

Indicates the message can be copied.

VCSTATUS_DELETE

Indicates the message can be deleted.

VCSTATUS_DELETE_IS_MOVE

Indicates the delete operation on the message is really a move to a deleted items folder.

VCSTATUS_MOVE

Indicates the message can be moved.

VCSTATUS_NEWMESSAGE

Indicates a new message can be created.

VCSTATUS_SAVE

Indicates the message can be saved.

VCSTATUS_SUBMIT

Indicates the message can be submitted.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Form objects call the IMAPIMessageSite::GetSiteStatus method to obtain the message site's capabilities on the message. The flags returned in the lpulStatus parameter provide information on the message site; typically they are used to enable or disable menu commands based on the capabilities of the message site's implementation. If a new message is loaded into a form by the IPersistMessage::SaveCompleted method or the IPersistMessage::Load method, the status flags must be rechecked. Some message sites, particularly read-only sites, cannot permit messages to be saved or deleted.

See Also

IPersistMessage::Load method, IPersistMessage::SaveCompleted method


 IMAPIMessageSite::GetStore

[New - Windows 95]

Returns the message store containing the current message, if such a store exists.

Syntax

HRESULT GetStore(LPMDB FAR * ppStore)

Parameters

ppStore

Output parameter pointing to a variable where the pointer to the message store is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

S_FALSE

There is no store containing the message.


 IMAPIMessageSite::MoveMessage

[New - Windows 95]

Moves the current message to a folder.

Syntax

HRESULT MoveMessage(LPFOLDER pFolderDestination, LPMAPIVIEWCONTEXT pViewContext, LPCRECT prcPosRect)

Parameters

pFolderDestination

Input parameter pointing to the folder where the message is moved.

pViewContext

Input parameter pointing to a view context object.

prcPosRect

Input parameter pointing to the RECT structure used by the form's window. The next form displayed also uses this window rectangle.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NO_SUPPORT

The operation is not supported by this message site.

Comments

Form objects call the IMAPIMessageSite::MoveMessage method to move the current message to a new folder. A form viewer's implementation of MoveMessage is required to call IMAPIViewContext::ActivateNext, passing the VCDIR_MOVE flag prior to actually moving the form to a new folder. Following the return of MoveMessage, form objects must check for a current message and then dismiss themselves if none exists.

The RECT structure used by the form's window can be obtained using the Windows GetWindowRect function.

See Also

IMAPIViewContext::ActivateNext method


 IMAPIMessageSite::NewMessage

[New - Windows 95]

Creates a new message.

Syntax

HRESULT NewMessage(ULONG fComposeInFolder, LPMAPIFOLDER pFolderFocus, LPPERSISTMESSAGE pPersistMessage, LPMESSAGE FAR * ppMessage, LPMAPIMESSAGESITE FAR * ppMessageSite, LPMAPIVIEWCONTEXT FAR * ppViewContext)

Parameters

fComposeInFolder

Input parameter indicating in which folder the message should be composed. If FALSE, pFolderFocus is ignored and the form viewer implementation can compose the message in any folder. If TRUE, and NULL is passed in the pFolderFocus parameter, the message is composed in the current folder. If TRUE and a non-null value is passed in pFolderFocus, the message is composed in the folder pointed to by the pFolderFocus parameter.

pFolderFocus

Input parameter pointing to the folder where the new message is created.

pPersistMessage

Input parameter pointing to the IPersistMessage object for the new form.

ppMessage

Output parameter pointing to a pointer to the new message.

ppMessageSite

Output parameter pointing to a pointer to the message site object.

ppViewContext

Output parameter pointing to a pointer to a view context appropriate for passing to a new form with the new message. NULL can be passed in the ppViewContext parameter if the form implements its own view context.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Form objects call the IMAPIMessageSite::NewMessage method to enable a form to create a new message. The form uses NewMessage to get a new message and the associated message site from its view. It can then modify the new message and either aggregate the message site or pass the message site directly to the new form object.

An associated view context can also be obtained by passing in a non-null value in the ppViewContext parameter. This view context can be used directly or it can be aggregated and passed to the new message. If a complete implementation is expected, NULL should be passed in the ppViewContext parameter.

See Also

IMAPIViewContext : IUnknown interface


 IMAPIMessageSite::SaveMessage

[New - Windows 95]

Requests that the current message be saved.

Syntax

HRESULT SaveMessage()

Parameters

None.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Form objects call the IMAPIMessageSite::SaveMessage method to request that a message be saved. After being saved, the message generates the normal IPersistMessage object behavior.


 IMAPIMessageSite::SubmitMessage

[New - Windows 95]

Requests that the current message be submitted to the MAPI spooler.

Syntax

HRESULT SubmitMessage(ULONG ulFlags)

Parameters

ulFlags

Input parameter containing a bitmask of flags used to control how a message is submitted. The following flag can be set:

FORCE_SUBMIT

Indicates MAPI should submit the message even if it might not be sent right away.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Form objects call the IMAPIMessageSite::SubmitMessage method to request that a message be submitted to the MAPI spooler. The message site should call the IPersistMessage::HandsOffMessage method prior to submitting the message. The message need not have previously been saved, as SubmitMessage should cause the message to be saved if it has been modified. Following the return of SubmitMessage, form objects must check for a current message and then dismiss themselves if none exists.

See Also

IPersistMessage::HandsOffMessage method


 IMAPIProgress : IUnknown

[New - Windows 95]

The IMAPIProgress interface is used by providers to provide client applications with information to update progress-information user interfaces, which indicate the progress towards completion of a lengthy operation, such as the copying of folders between message stores. MAPI and client applications implement progress objects and then pass those objects to provider-implemented methods such as IMAPIFolder::CopyFolder, which take progress objects as input parameters.

At a Glance

Specified in header file:	MAPIDEFS.H
Object that supplies this interface:	Progress object
Corresponding pointer type:	LPMAPIPROGRESS
Implemented by:	MAPI and client applications
Called by:	Providers
Vtable Order

Progress	Updates the progress-information user interface with status on the progress made towards completion of the operation in question.
GetFlags	Returns the flag settings from the progress object for the level of operation on which progress information is calculated.
GetMax	Returns the maximum setting for the whole operation from the progress object.
GetMin	Returns the minimum setting for the whole operation from the progress object.
SetLimits	Sets the minimum value of items operated on, the maximum value of items operated on, and the flags that control how progress information is calculated for the operation in question.


 IMAPIProgress::GetFlags

[New - Windows 95]

Returns the flag settings from the progress object for the level of operation on which progress information is calculated.

Syntax

HRESULT GetFlags(ULONG FAR * lpulFlags)

Parameters

lpulFlags

Output parameter containing a bitmask of flags used to control the level of operation on which progress information is calculated. The following flag can be returned:

MAPI_TOP_LEVEL

Uses the values in the IMAPIProgress::Progress method's ulCount (the item being operated on) and ulTotal (total items to operate on) parameters to increment progress being made on the operation. For example, if you were copying a folder that contained 15 subfolders and the MAPI_TOP_LEVEL flag is set in the lpulFlags parameter, progress will increment for each subfolder copied: 1 of 15, 2 of 15, 3 of 15, and so on.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Use the IMAPIProgress::GetFlags method to get the flag settings from the progress object for the level of operation on which progress information is calculated. This value, retrieved from GetFlag's lpulFlags parameter, is set using the IMAPIProgress::SetLimits method. Your application uses this value to control the level of operation for which progress information is given. For instance, if you copy a folder containing 15 subfolders and the MAPI_TOP_LEVEL flag is set in lpulFlags, progress is calculated in terms of subfolders copied: 1 of 15, 2 of 15, 3 of 15, and so on. If the MAPI_TOP_LEVEL flag is not set in lpulFlags, the copying of the 15 subfolders is considered a single operation and progress is calculated as a percentage of the total operation: 20 percent, 40 percent, 60 percent, and so on.

See Also

IMAPIProgress::SetLimits method


 IMAPIProgress::GetMax

[New - Windows 95]

Returns the maximum setting for the whole operation from the progress object.

Syntax

HRESULT GetMax(ULONG FAR * lpulMax)

Parameters

lpulMax

Output parameter pointing to a variable containing the maximum number of items in the operation.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Use the IMAPIProgress::GetMax method to obtain the maximum setting from the progress object. The value in IMAPIProgress::GetMax's lpulMax parameter is set using the IMAPIProgress::SetLimits method. The values in lpulMax and the lpulMin parameter obtained through the IMAPIProgress::GetMin method are used by the IMAPIProgress::Progress method to calculate the number that is used as the value in Progress's ulValue parameter. This calculation is done by comparing lpulMin and lpulMax and expressing the comparison as a percentage.

See Also

IMAPIProgress::GetMin method, IMAPIProgress::Progress method, IMAPIProgress::SetLimits method


 IMAPIProgress::GetMin

[New - Windows 95]

Returns the minimum setting for the whole operation from the progress object.

Syntax

HRESULT GetMin(ULONG FAR * lpulMin)

Parameters

lpulMin

Output parameter pointing to a variable containing the minimum number of items in the operation.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Use the IMAPIProgress::GetMin method to obtain the minimum setting from the progress object. The value in IMAPIProgress::GetMin's lpulMin parameter is set using the IMAPIProgress::SetLimits method. The values in lpulMin and the lpulMax parameter obtained through the IMAPIProgress::GetMax method are used by the IMAPIProgress::Progress method to calculate the number that is used as the value in Progress's ulValue parameter. This calculation is done by comparing lpulMin and lpulMax and expressing the comparison as a percentage.

See Also

IMAPIProgress::GetMin method, IMAPIProgress::Progress method, IMAPIProgress::SetLimits method


 IMAPIProgress::Progress

[New - Windows 95]

Updates the progress-information user interface with status on the progress made towards completion of the operation.

Syntax

HRESULT Progress(ULONG ulValue, ULONG ulCount, ULONG ulTotal)

Parameters

ulValue

Input parameter containing a number indicating the percentage, relative to ulCount and ulTotal if the MAPI_TOP_LEVEL flag is set in IMAPIProgress::SetLimits, or that expresses the comparison of the values in the lpulMin and lpulMax parameters of the SetLimits method if the MAPI_TOP_LEVEL flag is not set on SetLimits.

ulCount

Input parameter containing the number of the item currently being operated on.

ulTotal

Input parameter containing the total number of items to be operated on.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Service providers use the IMAPIProgress::Progress method to update the progress-information user interface for the progress object passed in by a client application. Progress's ulCount parameter is the number of the current item being operated on; its ulTotal parameter is the total number of items to be operated on. For example, if 10 folders are being copied and 4 of them have already been copied, then 5 should be sent in the ulCount parameter and 10 should be sent in the ulTotal parameter.

If the MAPI_TOP_LEVEL flag has been set in the lpulFlags parameter of IMAPIProgress::SetLimits, then ulValue is expressed as a percentage based on the values in the ulCount and the ulTotal parameters. For example, if ulCount is 20 and ulTotal is 50, then ulValue is 40 and indicates 40 percent completion. If MAPI_TOP_LEVEL is not set, then ulValue is expressed as a percentage based on the lpulMax and the lpulMin parameters of SetLimits. For example, if lpulMax is 100 and lpulMin is 0, ulValue is 100 and indicates 100 percent.

If your application is copying all messages within a single folder, then the value in the ulTotal parameter should indicate the total number of messages being copied. If your application is copying a folder, then the value in ulTotal should be the number of subfolders within the folder, not the number of subfolders plus the number of messages. If the folder to be copied contains no subfolders and only messages, the value in ulTotal should be set to 1.

See Also

IMAPIProgress::SetLimits method


 IMAPIProgress::SetLimits

[New - Windows 95]

Sets the minimum value of items operated on, the maximum value of items operated on, and the flags that control how progress information is calculated for the operation in question.

Syntax

HRESULT SetLimits(LPULONG lpulMin, LPULONG lpulMax, LPULONG lpulFlags)

Parameters

lpulMin

Input parameter pointing to a variable containing the minimum number of items in the operation.

lpulMax

Input parameter pointing to a variable containing the maximum number of items in the operation.

lpulFlags

Input parameter containing a bitmask of flags used to control the level of operation on which progress information is calculated. The following flag can be set:

MAPI_TOP_LEVEL

Uses the values in the IMAPIProgress::Progress method's ulCount (the item being operated on) and ulTotal (total items to operate on) parameters to increment progress being made on the operation. For example, if you were copying a folder that contained 15 subfolders and the MAPI_TOP_LEVEL flag is set in the lpulFlags parameter, progress will increment for each subfolder copied: 1 of 15, 2 of 15, 3 of 15, and so on.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Client applications use the IMAPIProgress::SetLimits method to establish the values that control how operation progress is calculated for the progress-information user interface. Service providers should not call SetLimits to change the values if they are passed a progress object by a client application; they should use the values passed to them.

The lpulFlags parameter is used to control the level of operation for which progress information is given. For instance, if you copy a folder containing 15 subfolders and the MAPI_TOP_LEVEL flag is set in lpulFlags, progress is calculated in terms of subfolders copied: 1 of 15, 2 of 15, 3 of 15, and so on. If the MAPI_TOP_LEVEL flag is not set in lpulFlags, the copying of the 15 subfolders is considered a single operation and progress is calculated as a percentage of the total operation: 20 percent, 40 percent, 60 percent, and so on.

The values in the lpulMin and lpulMax parameters are used by the IMAPIProgress::Progress method to calculate the number that is used as the value in Progress's ulValue parameter if the MAPI_TOP_LEVEL flag is not passed in the lpulFlags parameter.. This calculation is done by comparing lpulMin and lpulMax and expressing the comparison as a percentage.

See Also

IMAPIProgress::Progress method


 IMAPIProp : IUnknown

[New - Windows 95]

The IMAPIProp interface is the core interface for working with properties for all MAPI objects.

At a Glance

Specified in header file:	MAPIDEFS.H
Object that supplies this interface:	No object supplies this interface directly.
Corresponding pointer type:	LPMAPIPROP
Implemented by:	All service providers
Called by:	All applications
Vtable Order

GetLastError	Returns information about the last error that occurred for an object.
SaveChanges	Makes permanent any changes made to an object since the last save operation.
GetProps	Retrieves the property values of one or more properties of an object.
GetPropList	Returns a list of all the properties of an object.
OpenProperty	Opens an interface on a property of an object.
SetProps	Sets the property value of one or more properties of an object.
DeleteProps	Deletes the given list of properties.
CopyTo	Copies or moves all properties of a source object to destination object.
CopyProps	Copies a selected set of properties from a source object to a destination object.
GetNamesFromIDs	Provides property names, given a list of property identifiers.
GetIDsFromNames	Provides property identifiers, given a list of property names.


 IMAPIProp::CopyProps

[New - Windows 95]

Copies or moves a selected set of properties from the source object to a given destination object. (The source object is the object on which the call to the IMAPIProp::CopyProps method is made.)

Syntax

HRESULT CopyProps(LPSPropTagArray lpIncludeProps, ULONG ulUIParam, LPMAPIPROGRESS lpProgress, LPCIID lpInterface, LPVOID lpDestObj, ULONG ulFlags, LPSPropProblemArray FAR * lppProblems)

Parameters

lpIncludeProps

Input parameter pointing to an SPropTagArray structure holding a counted array of property tags indicating the properties to be copied or moved from this object to the destination object. The lpIncludeProps parameter value cannot be NULL.

ulUIParam

Input parameter containing the handle of the window the dialog box is modal to. In this case, it is used to indicate the dialog box where progress information is displayed.

lpProgress

Input parameter pointing to a progress object that contains client- or provider-supplied progress information. If NULL is sent in the lpProgress parameter, the progress information is provided by MAPI. The lpProgress parameter is ignored unless the MAPI_DIALOG flag is set in the ulFlags parameter.

lpInterface

Input parameter pointing to the interface identifier for the interface of the destination object to which properties are being copied as indicated in the lpDestObj parameter. lpInterface must not be NULL.

lpDestObj

Input parameter pointing to the open destination object.

ulFlags

Input parameter containing a bitmask of flags used to control how the copy or move operation is performed. The following flags can be set:

MAPI_DECLINE_OK

Used by MAPI to limit recursion within MAPI's CopyProps implementation. Informs the provider that if it chooses not to implement IMAPIProp::CopyProps, that it should immediately return MAPI_E_DECLINE_COPY.

MAPI_DIALOG

Displays a dialog box to provide progress information for the copy operation.

MAPI_MOVE

Indicates a move operation. The default operation is copying.

MAPI_NOREPLACE

Indicates that existing properties in the destination object should not be overwritten. The default action is to overwrite existing properties.

lppProblems

Output parameter pointing to a variable where the pointer to an SPropProblemArray structure is stored. If a value of NULL is passed in the lppProblems parameter, no property problem array is returned.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_DECLINE_COPY

Indicates that the provider has chosen not to implement the copy operation.

MAPI_E_COLLISION

A sibling folder in the destination object already has the name in the PR_DISPLAY_NAME property being copied from the source object.

MAPI_E_FOLDER_CYCLE

The source object directly or indirectly contains the destination object. Significant work might have been performed before this condition was discovered, so the source and destination object might be partially modified.

MAPI_E_INTERFACE_NOT_SUPPORTED

An appropriate interface cannot be obtained.

MAPI_E_NO_ACCESS

An attempt to modify a read-only object or an attempt to access an object for which the user has insufficient permissions.

The following values can be returned in the SPropProblemArray structure, but not as a return value for CopyProps:

MAPI_E_BAD_CHARWIDTH

Either the MAPI_UNICODE flag was set and the implementation does not support Unicode, or MAPI_UNICODE was not set and the implementation only supports Unicode.

MAPI_E_COMPUTED

The property can't be written because it is computed by the destination object's provider. This is not a severe error; allow the process to continue.

MAPI_E_INVALID_TYPE

The property type is invalid.

MAPI_E_UNEXPECTED_TYPE

The type of the property value is not the type expected by the calling application.

Comments

Use the IMAPIProp::CopyProps method to copy or move to the destination object those properties designated in the SPropTagArray structure passed in the lpIncludeProps parameter that are present in the source object. When copying properties between like objects, for example between two message objects, the interface identifiers and the object types must be the same for both the source and the destination object. If any of the copied or moved properties already exist in the destination object, the existing properties are overwritten by the new, unless the MAPI_NOREPLACE flag is set in the ulFlags parameter. Existing information in the destination object that is not overwritten by copied or moved data is not deleted or modified.

For message objects, the PR_MESSAGE_RECIPIENTS and PR_MESSAGE_ATTACHMENTS properties can be included in the SPropTagArray structure passed in lpIncludeProps to permit copying or moving of message recipients and attachments, respectively. For folder objects, the PR_CONTAINER_HIERARCHY, PR_CONTAINER_CONTENTS, and PR_FOLDER_ASSOCIATED_CONTENTS properties can be included in the lpIncludeProps SPropTagArray structure to permit copying or moving of subfolders, messages, or associated objects from a source folder to a destination object. If subfolders are copied or moved, they are copied or moved in their entirety, regardless of the use of properties indicated by the SPropTagArray structure in the source object itself.

If the source object directly or indirectly contains the destination object, the overall call fails and returns the value MAPI_E_FOLDER_CYCLE. Some implementations, however, perform significant work before discovering this error and leave the source and destination objects partially modified, so applications should try to avoid such calls. If the same pointer is used for both the source and destination objects, MAPI_E_NO_ACCESS is returned.

The interface of the destination object, indicated in the lpInterface parameter, is usually exactly the same interface as that for the source object. If lpInterface is set to NULL, then the value MAPI_E_INVALID_PARAMETER is returned for CopyProps. If an acceptable interface is given in the lpInterface parameter but an invalid pointer is passed in the lpDestObj parameter, the results are unpredictable, with the most likely result being that the calling application stops.

If the MAPI_DIALOG flag is not set in the ulFlags parameter, then CopyProps ignores the ulUIParam and lpProgress parameters and no progress-information user interface is provided. If a client application sets the MAPI_DIALOG flag in the ulFlags parameter and passes a value of NULL in the lpProgress parameter, then the provider is responsible for generating a progress-information user interface. If a client application sets the MAPI_DIALOG flag in the ulFlags parameter and passes a progress object in the lpProgress parameter, the provider uses the information supplied by the progress object to display progress information.

If the call succeeds overall but there are problems with copying or moving some of the selected properties, the value S_OK is returned and an SPropProblemArray structure is returned in the lppProblems parameter. The SPropProblemArray structure contains details about each property problem. In some cases, a CopyProps call can successfully set some of the requested properties, but not others; in these cases, exactly which properties were not successfully copied or moved can be determined from the SPropProblemArray structure. If message recipients or attachments cannot be copied or moved, the PR_MESSAGE_RECIPIENTS or PR_MESSAGE_ATTACHMENTS property is returned in the SPropProblemArray structure.

The value returned in the lppProblems parameter is only valid if the call returns S_OK. When S_OK is returned, check the values returned in the SPropProblemArray structure. If an error occurs on the call, then the SPropProblemArray structure is not filled in; call IMAPIProp::GetLastError to get the MAPIERROR structure for the error.

The calling application must free the returned SPropProblemArray structure by calling the MAPIFreeBuffer function, but this should only be done if CopyProps returns with S_OK.

See Also

IMAPIFolder::CopyMessages method, IMAPIProp::CopyTo method, IMAPIProp::GetLastError method, SPropProblemArray structure, SPropTagArray structure


 IMAPIProp::CopyTo

[New - Windows 95]

Copies or moves all properties of the source object to a destination object, except for a given set of properties that are excluded from the copy or move operation. (The source object is the object on which the call to the IMAPIProp::CopyTo method is made.)

Syntax

HRESULT CopyTo(ULONG ciidExclude, LPCIID rgiidExclude, LPSPropTagArray lpExcludeProps, ULONG ulUIParam, LPMAPIPROGRESS lpProgress, LPCIID lpInterface, LPVOID lpDestObj, ULONG ulFlags, LPSPropProblemArray FAR * lppProblems)

Parameters

ciidExclude

Input parameter containing the number of interfaces to be excluded when copying or moving properties.

rgiidExclude

Input parameter containing an array of interface identifiers indicating interfaces that should not be used when copying or moving supplemental information to the destination object.

lpExcludeProps

Input parameter pointing to the SPropTagArray structure containing the property identifiers of the properties that should not be copied or moved to the destination object. Passing a value of NULL in the lpExcludeProps parameter indicates all properties are to be copied or moved. Passing zero in the cValues member of the lpExcludeProps SPropTagArray structure results in the value MAPI_E_INVALID_PARAMETER being returned.

ulUIParam

Input parameter containing the handle of the window the dialog box is modal to. In this case it is used to indicate the dialog box where progress information is displayed.

lpProgress

Input parameter pointing to a progress object that contains client- or provider-supplied progress information. If NULL is sent in the lpProgress parameter, the progress information is provided by MAPI. The lpProgress parameter is ignored unless the MAPI_DIALOG flag is set in the ulFlags parameter.

lpInterface

Input parameter pointing to the interface identifier for the interface of the destination object to which properties are being copied.

lpDestObj

Input parameter pointing to the open destination object.

ulFlags

Input parameter containing a bitmask of flags used to control how the copy or move operation is to be performed. The following flags can be set:

MAPI_DECLINE_OK

Used by MAPI to limit recursion within MAPI's CopyTo implementation. Informs the provider that if it chooses not to implement IMAPIProp::CopyTo, that it should immediately return MAPI_E_DECLINE_COPY.

MAPI_DIALOG

Displays a dialog box to provide progress information for the copy operation.

MAPI_MOVE

Indicates a move operation. The default operation is copying.

MAPI_NOREPLACE

Indicates that existing properties in the destination object should not be overwritten. The default action is to overwrite existing properties.

lppProblems

Output parameter pointing to a variable where the pointer to an SPropProblemArray structure is stored. If a value of NULL is passed in the lppProblems parameter, no property problem array is returned.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_DECLINE_COPY

Indicates that the provider has chosen not to implement the copy operation.

MAPI_E_COLLISION

A sibling folder in the destination object already has the name in the PR_DISPLAY_NAME property being copied from the source object.

MAPI_E_FOLDER_CYCLE

The source object directly or indirectly contains the destination object. Significant work might have been performed before this condition was discovered, so the source and destination object might be partially modified.

MAPI_E_INTERFACE_NOT_SUPPORTED

An appropriate interface cannot be obtained.

MAPI_E_NO_ACCESS

An attempt to modify a read-only object or an attempt to access an object for which the user has insufficient permissions.

The following values can be returned in the SPropProblemArray structure, but not as a return value for CopyTo:

MAPI_E_BAD_CHARWIDTH

Either the MAPI_UNICODE flag was set and the implementation does not support Unicode, or MAPI_UNICODE was not set and the implementation only supports Unicode.

MAPI_E_COMPUTED

The property can't be written because it is computed by the destination object's provider. This is not a severe error; allow the process to continue.

MAPI_E_INVALID_TYPE

The property type is invalid.

MAPI_E_UNEXPECTED_TYPE

The type of the property value is not the type expected by the calling application.

Comments

Use the IMAPIProp::CopyTo method to copy or move all properties of the source object to the destination object, except for a given set of properties that are excluded from the copy or move operation. Any objects contained in the source object and any subobjects of the source object are included in the copy or move operation.

If any of the copied or moved properties already exist in the destination object, the existing properties are overwritten by the new, unless the MAPI_NOREPLACE flag is set in the ulFlags parameter. Existing information in the destination object that is not overwritten by copied or moved data is not deleted or modified.

To exclude some properties from the copy or move operation, pass their property identifiers in the lpExcludeProps parameter. Passing in a specific value causes any property in the source object whose identifier matches that value to be excluded from being copied or moved to the destination object. For example, passing in a value of PROP_TAG(PT_LONG, 0x8002) excludes both the properties PROP_TAG(PT_STRING8, 0x8002) and PROP_TAG(PT_OBJECT, 0x8002).

For message objects, the PR_MESSAGE_RECIPIENTS and PR_MESSAGE_ATTACHMENTS properties can be included in the SPropTagArray structure passed in lpExcludeProps to prevent copying or moving message recipients and attachments, respectively. For folder objects, the PR_CONTAINER_HIERARCHY, PR_CONTAINER_CONTENTS, and PR_FOLDER_ASSOCIATED_CONTENTS properties can be included in the lpExcludeProps SPropTagArray structure to prevent copying or moving of subfolders, messages, or associated objects from the source folder to the destination object. If subfolders are copied or moved, they are copied or moved in their entirety, regardless of the use of properties indicated by the SPropTagArray structure in the source object itself.

Providers implementing CopyTo should not attempt to set any known read-only properties in the destination object and should ignore MAPI_E_COMPUTED errors returned in the SPropProblemArray structure.

If the source object directly or indirectly contains the destination object, the overall call fails and returns the value MAPI_E_FOLDER_CYCLE. Some implementations, however, perform significant work before discovering this error and leave the source and destination objects partially modified, so applications should try to avoid such calls. If the same pointer is used for both the source and destination objects, MAPI_E_NO_ACCESS is returned.

The interface of the destination object, indicated in the lpInterface parameter, is usually exactly the same interface as that for the source object. If lpInterface is set to NULL, then the value MAPI_E_INVALID_PARAMETER is returned for CopyTo. If an acceptable interface is given in the lpInterface parameter but an invalid pointer is passed in the lpDestObj parameter, the results are unpredictable, with the most likely result being that the calling application stops.

Some objects contain supplemental information beyond that, which can be accessed with the interface pointer in the lpInterface parameter. To copy or move such information, a provider's IMAPIProp::CopyTo implementation first uses IUnknown::QueryInterface on the destination object to see if it can accept the extra data. Conversely, if the calling application is aware of supplemental information and requires that CopyTo not copy or move it, the application can specify in the array passed in the rgiidExclude parameter interface identifiers for the properties that CopyTo should not copy or move. For example, if the application wants to copy messages, but not embedded objects within the messages, it can pass IID_IMessage in the exclude array. CopyTo ignores any interfaces listed in rgiidExclude that it doesn't recognize.

Note  When you use the rgiidExclude parameter to exclude an interface, you also exclude all interfaces derived from that interface. For example, excluding IMAPIProp also excludes IMAPIFolder, IMessage, IAttach, and so on. If all known interfaces are excluded, CopyTo returns the error value MAPI_E_INTERFACE_NOT_SUPPORTED. For that reason, you should not pass IID_IUnknown or IID_IMAPIProp in rgiidExclude.

If the MAPI_DIALOG flag is not set in the ulFlags parameter, then CopyTo ignores the ulUIParam and lpProgress parameters and no progress-information user interface is provided. If a client application sets the MAPI_DIALOG flag in the ulFlags parameter and passes a value of NULL in the lpProgress parameter, then the provider is responsible for generating a progress-information user interface. If a client application sets the MAPI_DIALOG flag in the ulFlags parameter and passes a progress object in the lpProgress parameter, the provider uses the information supplied by the progress object to display progress information.

If the call succeeds overall but there are problems with copying or moving some of the selected properties, the value S_OK is returned and an SPropProblemArray structure is returned in the lppProblems parameter. The SPropProblemArray structure contains details about each property problem. In some cases, a CopyTo call can successfully set some of the requested properties, but not others; in these cases, exactly which properties were not successfully copied or moved can be determined from the SPropProblemArray structure. If message recipients or attachments cannot be copied or moved, the PR_MESSAGE_RECIPIENTS or PR_MESSAGE_ATTACHMENTS property is returned in the SPropProblemArray structure.

The value returned in the lppProblems parameter is only valid if the call returns S_OK. When S_OK is returned, check the values returned in the SPropProblemArray structure. If an error occurs on the call, then the SPropProblemArray structure is not filled in; call IMAPIProp::GetLastError to get the MAPIERROR structure for the error.

If an error occurs on the CopyTo call, do not use of free the SPropProblemArray structure. Applications should ignore the ulIndex member in property problem sets returned by CopyTo.

The calling application must free the returned SPropProblemArray structure by calling the MAPIFreeBuffer function, but this should only be done if CopyTo returns with S_OK.

See Also

IMAPIFolder::CopyMessages method, IMAPIProp::GetLastError method, SPropProblemArray structure, SPropTagArray structure


 IMAPIProp::DeleteProps

[New - Windows 95]

Deletes the given list of properties.

Syntax

HRESULT DeleteProps(LPSPropTagArray lpPropTagArray, LPSPropProblemArray FAR * lppProblems)

Parameters

lpPropTagArray

Input parameter pointing to an SPropTagArray structure containing the properties to be deleted. The lpPropTagArray parameter must not be NULL. The property type in each property tag is ignored, and only the property identifier is used. Passing zero in the cValues member of the SPropTagArray structure results in the value MAPI_E_INVALID_PARAMETER being returned.

lppProblems

Output parameter pointing to a variable where the pointer to an SPropProblemArray structure is stored. If a value of NULL is passed in the lppProblems parameter, no property problem array is returned.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NO_ACCESS

An attempt to modify a read-only object or an attempt to access an object for which the user has insufficient permissions.

Comments

Use the IMAPIProps::DeleteProps method to delete properties from an object. Not all objects allow deletion of properties. If the DeleteProps call fails completely, its HRESULT returns with a nonzero value.

If the call succeeds overall but there are problems with deleting some of the selected properties, the value S_OK is returned and an SPropProblemArray structure is returned in the lppProblems parameter. The SPropProblemArray structure contains details about each property problem. In some cases, a DeleteProps call can successfully set some of the requested properties, but not others; in these cases, exactly which properties were not successfully deleted can be determined from the SPropProblemArray structure. If message recipients or attachments cannot be deleted, the PR_MESSAGE_RECIPIENTS or PR_MESSAGE_ATTACHMENTS property is returned in the SPropProblemArray structure.

The value returned in the lppProblems parameter is only valid if the call returns S_OK. When S_OK is returned, check the values returned in the SPropProblemArray structure. If an error occurs on the call, then the SPropProblemArray structure is not filled in; call IMAPIProp::GetLastError to get the MAPIERROR structure for the error.

The calling application must free the returned SPropProblemArray structure by calling the MAPIFreeBuffer function, but this should only be done if DeleteProps returns with S_OK.

See Also

IMAPIProp::GetProps method, IMAPIProp::SaveChanges method, MAPIFreeBuffer function, SPropTagArray structure


 IMAPIProp::GetIDsFromNames

[New - Windows 95]

Provides property identifiers, given a list of property names.

Syntax

HRESULT GetIDsFromNames(ULONG cPropNames, LPMAPINAMEID FAR * lppPropNames, ULONG ulFlags, LPSPropTagArray FAR * lppPropTags)

Parameters

cPropNames

Input parameter containing the number of pointers to MAPNAMEID structures returned in the lppPropNames parameter. If the lppPropNames parameter has a value of NULL, the value in the cPropNames parameter must be zero.

lppPropNames

Input parameter pointing to an array of pointers to MAPINAMEID structures containing names of properties. A value of NULL requests property identifiers for all property names about which the object has information. If MAPI_CREATE is set in ulFlags, lppPropNames must not be NULL.

ulFlags

Input parameter containing a bitmask of flags that controls how the property identifiers are returned. The following flag can be set:

MAPI_CREATE

Allocates a property identifier for each named property in lppPropNames that is not registered in the name-to-identifier mapping table and internally registers the identifier in this table.

lppPropTags

Output parameter pointing to a variable where the pointer to the array of existing or newly assigned property identifiers is stored. The property types are set to PT_UNSPECIFIED.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NO_SUPPORT

The operation is not supported by MAPI or by one or more service providers.

MAPI_E_NOT_ENOUGH_MEMORY

Insufficient memory was available to complete the operation.

MAPI_E_TOO_BIG

Indicates that the operation cannot be performed because too many properties tags are being returned.

MAPI_W_ERRORS_RETURNED

The call succeeded overall, but one or more properties could not be accessed and were returned with a property type of PT_ERROR and an identifier of zero. Use the HR_FAILED macro to test for this warning, but the call should be handled as a successful return.

Comments

Use the IMAPIProp::GetIDsFromNames method to get an array of property tags that holds the property identifiers for the named properties. The returned property tags are in the same order as the names passed in the LPMAPINAMEID array in the lppPropNames parameter. GetIDsFromNames returns the type portion of each tag as PT_UNSPECIFIED; call IMAPIProp::SetProps to set them.

Message store providers wanting to extend property sets typically implement the GetIDsFromNames and IMAPIProp::GetNamesFromIDs methods for message and folder objects. Other interfaces derived from IMAPIProp typically return the value MAPI_E_NO_SUPPORT for calls to these methods.

Only identifiers in the range of 0x8000 to 0xFFFE use name-to-identifier mapping. MAPI expects a store provider that supports named properties in folder contents tables to use the same name-to-identifier mapping for all objects in a folder. A store provider that supports named properties in search folders' contents tables must use the same name-to-identifier mapping for all objects in the message store. Objects that support name-to-identifier mapping often contain an additional binary property, PR_MAPPING_SIGNATURE (a MAPIUID structure). If two objects have mapping signatures and both signatures have the same value, those objects use the same name-to-identifier mapping.

Applications that move or copy objects with named properties must preserve names during such operations by adjusting property identifiers to match the name-to-identifier mapping of the destination object. The exception is if the source and destination objects have the same value for the PR_MAPPING_SIGNATURE property, in which case the application can skip this step.

If a name set with GetIDsFromNames does not have an identifier, GetIDsFromNames returns the value MAPI_W_ERRORS_RETURNED and in the appropriate entry of the property tag array returns a property tag with a type of PT_ERROR and an identifier of zero. If a name sent with GetIDsFromNames does not have an identifier and the MAPI_CREATE flag was set in the ulFlags parameter, the GetIDsFromNames call allocates an identifier for the name and internally registers the identifier in the name-to-identifier mapping table. When the value in the lppPropNames parameter is NULL, MAPI returns all identifiers defined for the entire PR_MAPPING_SIGNATURE (the value in the cPropNames parameter must also be zero if NULL is passed in the lppPropNames parameter). If the number of defined identifiers in the store exceeds the implementation limit, MAPI_E_TOO_BIG is returned and client applications should query by identifier.

See Also

IMAPIProp::GetNamesFromIDs method, MAPINAMEID structure, MAPIUID structure


 IMAPIProp::GetLastError

[New - Windows 95]

Returns a MAPIERROR structure containing information about the last error that occurred for the object.

Syntax

HRESULT GetLastError(HRESULT hResult, ULONG ulFlags, LPMAPIERROR FAR * lppMAPIError)

Parameters

hResult

Input parameter containing the result returned for the last call on the session object that returned an error.

ulFlags

Input parameter containing a bitmask of flags controlling the type of the returned strings. The following flag can be set:

MAPI_UNICODE

Indicates the strings returned in the MAPIERROR structure returned in the lppMAPIError parameter are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

lppMAPIError

Output parameter pointing to a pointer to the returned MAPIERROR structure containing version, component, and context information for the error. The lppMAPIError parameter can be set to NULL if there is no MAPIERROR structure to return.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_BAD_CHARWIDTH

Either the MAPI_UNICODE flag was set and the implementation does not support Unicode, or MAPI_UNICODE was not set and the implementation only supports Unicode.

Comments

Use the IMAPIProp::GetLastError method to retrieve information to display as a message to the user regarding the last error returned from a method call on the session object.

To release all the memory allocated by MAPI, client applications need only call the MAPIFreeBuffer function for the MAPIERROR structure.

The return value from GetLastError must be S_OK for the application to make use of the MAPIERROR structure. Even if the return value is S_OK, it is still possible that a MAPIERROR structure won't be returned. If the implementation cannot determine what the last error was, or if a MAPIERROR structure is not available for that error, a pointer to NULL is returned in the lppMAPIError parameter instead.

See Also

MAPIERROR structure, MAPIFreeBuffer function


 IMAPIProp::GetNamesFromIDs

[New - Windows 95]

Provides property identifiers, given a list of property names.

Syntax

HRESULT GetNamesFromIDs(LPSPropTagArray FAR * lppPropTags, LPGUID lpPropSetGuid, ULONG ulFlags, ULONG FAR * lpcPropNames, LPMAPINAMEID FAR * FAR * lpppPropNames)

Parameters

lppPropTags

Output parameter pointing to a variable where the pointer to an SPropTagArray structure of property tags, including the identifiers for which names are needed, is stored. Passing zero in the cValues member of the SPropTagArray structure results in the value MAPI_E_INVALID_PARAMETER being returned. lppPropTags can be a pointer to NULL, in which case all of the names are returned.

lpPropSetGuid

Input parameter pointing to a globally unique identifier (GUID) for the property set. To get all of the names, pass in the value PS_PUBLIC_STRINGS and NULL for the lppPropNames parameter.

ulFlags

Input parameter containing a bitmask of flags used to control how names are mapped. The following flags can be used:

MAPI_NO_IDS

Indicates that identifiers are not returned.

MAPI_NO_STRINGS

Indicates that strings are not returned.

lpcPropNames

Output parameter pointing to a variable containing the number of strings in the lpppPropNames parameter.

lpppPropNames

Input or output parameter pointing to a variable pointer to an array of pointers to MAPINAMEID structures containing names of properties. It is an input parameter if it points to a value. If it points to NULL, all of the GUIDs for the property set are returned.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NO_SUPPORT

The operation is not supported by MAPI or by one or more service providers.

MAPI_W_ERRORS_RETURNED

The call succeeded overall, but one or more properties could not be accessed and were returned with a property type of PT_ERROR. Use the HR_FAILED macro to test for this warning, but the call should be handled as a successful return.

Comments

Use the IMAPIProp::GetNamesFromIDs method to get an array of pointers to Unicode strings that are the names of the indicated properties. While access to a property is mainly by property identifier, there are some applications that also need to associate names in Unicode string format with some properties in their objects.

GetNamesFromIDs ignores the property type in each property tag sent in the lppPropTags parameter — only the property identifier is significant. If a specified identifier does not have a Unicode name, GetNamesFromIDs returns a NULL in that identifier's place in the structure returned in the lpppPropNames parameter and also returns the value MAPI_W_ERRORS_RETURNED. If the value in the lppPropTags parameter is NULL, then the method allocates a new property tag array and returns all names and identifiers mapped for the object. The returned buffer for these strings is freed by calling the MAPIFreeBuffer function.

There are two distinguished GUIDs which identify interesting property sets: PS_MAPI and PS_PUBLIC_STRINGS.

If you want to use a MAPI folder as a container for string properties, use the PS_PUBLIC_STRINGS as the property set for storing the ad-hoc document property strings. Applications that want to get the public names within the container call GetNamesFromIDs with a pointer to a NULL property tag array and a GUID of PS_PUBLIC_STRINGS and set the MAPI_NO_IDS flag in the ulFlags parameter.

Applications that want to get all the registrations should set ulFlags to zero and pass in a NULL property tag array and a NULL GUID. If NULL is passed in an SPropTagArray structure it must be freed by calling the MAPIFreeBuffer function.

See Also

IMAPIProp::GetIDsFromNames method, MAPIFreeBuffer function, MAPINAMEID structure, SPropTagArray structure


 IMAPIProp::GetPropList

[New - Windows 95]

Returns a list of all the properties of an object.

Syntax

HRESULT GetPropList(ULONG ulFlags, LPSPropTagArray FAR * lppPropTagArray)

Parameters

ulFlags

Input parameter containing a bitmask of flags controlling the format of the returned property tags. The following flag can be set:

MAPI_UNICODE

Indicates the returned strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

lppPropTagArray

Output parameter pointing to a variable where the pointer to the returned SPropTagArray structure is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Use the IMAPIProp::GetPropList method to get the property tag for each property of an object. If no properties exist for the object, GetPropList returns a property tag array containing just a count, and that count must have a value of zero. Properties of type PT_OBJECT are returned by GetPropList.

Some service providers exclude those properties from the list of returned properties for which the calling application does not have access.

The calling application must free the property tag structure pointed to by the lppPropTagArray parameter by calling the MAPIFreeBuffer function.

If the object supports Unicode, string properties are returned with the preferred character width, either PT_UNICODE or PTSTRING8. If the object does not support Unicode, GetPropList returns MAPI_E_BAD_CHARWIDTH, even if there are no string properties defined for the object.

See Also

MAPIFreeBuffer function


 IMAPIProp::GetProps

[New - Windows 95]

Retrieves the property values of one or more properties of an object.

Syntax

HRESULT GetProps(LPSPropTagArray lpPropTagArray, ULONG ulFlags, ULONG FAR * lpcValues, LPSPropValue FAR * lppPropArray)

Parameters

lpPropTagArray

Input parameter pointing to an SPropTagArray structure containing the property tags of the properties whose values are to be retrieved. If a value of NULL is passed in the lpPropTagArray parameter, then values for all properties of the object are returned. If zero is passed in the cValues member of the SPropTagArray structure, the value MAPI_E_INVALID_PARAMETER is returned.

ulFlags

Input parameter containing a bitmask of flags controlling the type of the text for the returned prop value if you pass in PT_UNSPECIFIED in the property tag array. The following flag can be set:

MAPI_UNICODE

Indicates the returned strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

lpcValues

Output parameter pointing to a variable in which is placed the number of properties for which tags are returned in the lppPropArray parameter. lpcValues is always equal to the size of the property value array, unless lppPropArray is NULL.

lppPropArray

Output parameter pointing to a pointer to the returned SPropValue array of property values.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

The following values can be returned in the SPropProblemArray, but not as a return value for SetProps:

MAPI_E_INVALID_ENTRYID

The named properties are not supported.

MAPI_E_NOT_ENOUGH_MEMORY

Insufficient memory was available to complete the operation. You should open the property to get the data.

MAPI_E_NOT_FOUND

The requested object does not exist.

MAPI_E_OBJECT_DELETED

The folder has been deleted since it was opened.

MAPI_W_ERRORS_RETURNED

The call succeeded overall, but one or more properties could not be accessed and were returned with a property type of PT_ERROR. Use the HR_FAILED macro to test for this warning, but the call should be handled as a successful return.

Comments

Use the IMAPIProp::GetProps method to get the property values of one or more properties from an object. Your application should first set up a counted array of property tags in an SPropTagArray structure and then call the IMAPIProp::GetProps method on the object for whose properties it requires property values.

The order of the properties in the SPropValue structure returned in the lppPropArray parameter exactly matches the order in which the SPropTagArray structure in the lpPropTagArray parameter requested the properties. If property types are specified in the SPropTagArray structure in lpPropTagArray, then the returned property values in the SPropValue structure returned in lppPropArray have types that exactly match the requested types, unless an error is returned instead.

If the calling application has the property identifier of a property for which it requires information but not the property type, it can pass in a property tag formed from the identifier and the property type PT_UNSPECIFIED. The actual type of the returned property will be indicated in the returned SPropValue structure.

When your application requires access to the contents of properties with property type PT_OBJECT, it should use the IMAPIProp::OpenProperty method. It is not an error to request the value of a property of type PT_OBJECT by using IMAPIProp::GetProps, but the data in the returned SPropValue structure contains no useful information. To request values for secure properties, your application must explicitly request the properties by identifier; secure properties' values are not returned when you pass NULL in the lppPropTagArray parameter.

Providers must allocate memory for the SPropValue structure in lpPropTagArray using the MAPIAllocateBuffer function; any additional memory needed for the structure's members is allocated using the MAPIAllocateMore function. The calling process must free the returned SPropValue structure by calling MAPIFreeBuffer but should only do so if GetProps returns S_OK or the warning MAPI_W_ERRORS_RETURNED.

When access to one or more properties fails, for example when the specified properties do not exist, GetProps returns the warning MAPI_W_ERRORS_RETURNED. The calling process should check the property tag of each of the returned properties to determine for which access failed. Those for which access failed have their property type set to PT_ERROR, and their values indicate which error occurred.

If a property for which a property value is requested does not exist, GetProps returns an individual SPropValue structure containing the value MAPI_E_NOT_FOUND. If none of the properties for which values are requested exist, as in the case of an empty profile section, your service provider should allocate an LPSPropTagArray pointer with every property tag set to the appropriate error value and return MAPI_W_ERRORS_RETURNED.

If no properties exist, and the calling application has requested values for all properties by passing NULL in the lpPropTagArray parameter, GetProps returns S_OK, sets the count value in the cValues member of the SPropTagArray structure to zero, and returns a zero length in the lpcValues parameter and NULL in the lppPropArray parameter. GetProps must not return multivalued properties with cValues set to zero.

If GetProps encounters an individual string or binary property that is too large (typically 4K or 8K) to conveniently be returned, GetProps marks that property with property type PT_ERROR, sets its value to MAPI_E_NOT_ENOUGH_MEMORY, and returns MAPI_W_ERRORS_RETURNED. Call IMAPIProp::OpenProperty to get the data within the property.

If the MAPI_UNICODE flag is set in the ulFlags parameter, then any string properties not specified to be returned in 8-bit format are returned in Unicode format. If MAPI_UNICODE is not set, string properties with unspecified types are returned in 8-bit format. String properties with unspecified types occur when GetProps is called with a NULL value for the lpPropTagArray parameter and when the property type PT_UNSPECIFIED is passed for a property type in the lpPropTagArray parameter's SPropTagArray structure. Providers that do not support string format conversion should return PT_ERROR for the property type and MAPI_E_BAD_CHARWIDTH for the property value.

See Also

IMAPIProp::OpenProperty method, MAPIAllocateBuffer function, MAPIAllocateMore function, MAPIFreeBuffer function, SPropTagArray structure, SPropValue structure


 IMAPIProp::OpenProperty

[New - Windows 95]

Opens an interface on a property of an object.

Syntax

HRESULT OpenProperty(ULONG ulPropTag, LPCIID lpiid, ULONG ulInterfaceOptions, ULONG ulFlags, LPUNKNOWN FAR * lppUnk)

Parameters

ulPropTag

Input parameter containing the property tag for the property for which an interface is required. A complete property tag should be passed.

lpiid

Input parameter pointing to the interface identifier to be used. Must not be NULL.

ulInterfaceOptions

Input parameter indicating interface-specific behavior.

ulFlags

Input parameter containing a bitmask of flags used to control how the property is opened. The following flags can be set:

MAPI_CREATE

If the property does not exist, it should be created. If the property does exist, the current data in the property should be discarded. When you set MAPI_CREATE, you should also set MAPI_MODIFY.

MAPI_DEFERRED_ERRORS

Indicates the call is allowed to succeed even if the underlying object is not accessible to the calling application. If the object is not accessible, some subsequent call to the object might return an error.

MAPI_MODIFY

Requests write access. The default interface is read-only. MAPI_MODIFY must be set when MAPI_CREATE is also set.

lppUnk

Output parameter pointing to a variable where the pointer to the newly created interface pointer is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_INTERFACE_NOT_SUPPORTED

The requested interface is not supported for this property.

MAPI_E_NO_ACCESS

An attempt to modify a read-only object or an attempt to access an object for which the user has insufficient permissions.

MAPI_E_NO_SUPPORT

The operation is not supported by MAPI or by one or more service providers.

MAPI_E_NOT_FOUND

The requested object does not exist and the MAPI_CREATE flag was not set in the ulFlags parameter.

Comments

Use the IMAPIProp::OpenProperty method to open an interface to access a specified property. Using this method is the only way to access a property of type PT_OBJECT, and this method can also be used for other properties (typically, large string and binary properties) depending on the implementation.

When opening an interface for an object with OpenProperty, your application uses an interface identifier (IID) to identify the interface.

The interface identifier IID_IStream is used for string and binary properties, and the interface identifier IID_IMessage is used when opening a PR_ATTACH_DATA_OBJ property for a message; a PR_ATTACH_DATA_OBJ property contains an embedded OLE object or embedded message data. The IID_IStreamDocFile interface identifier can be used for those properties that are known to be a document file encoding of an IStorage object.

To identify the property to open, a complete property tag should be passed in the ulPropTag parameter. Using a property type of PT_UNSPECIFIED in a property tag passed with ulPropTag returns the value MAPI_E_INVALID_PARAMETER.

Note  Applications using an IStream interface to access double byte character set (DBCS) text should not seek or call IStream::SetSize on the stream other than with a zero position or size variable. Also, the application should not rely upon the value of the plibNewPosition output parameter. Applications should not call the IMAPIProp::GetProps, IMAPIProp::SetProps, or IMAPIProp::DeleteProps method or perform other calls that affect an open property while a property is open with an IStream interface. Violation of these rules can cause implementations to behave poorly, stop, or lose data.

The implementation of multiple openings of the same property are undefined and provider-dependent.

When a client application requires the ability to write to a stream it is opening, the client application should set the MAPI_MODIFY flag in the ulFlags parameter, whether or not the MAPI_CREATE flag is set in ulFlags. Some providers return the value MAPI_E_INVALID_PARAMETER when an application attempts to create a stream without setting the MAPI_MODIFY flag. If the MAPI_CREATE flag is set, MAPI_MODIFY must also be set.

The calling application is responsible for recasting the interface pointer returned in the lppUnk parameter to the one appropriate for the interface specified in the lpiid parameter. The calling application should release the opened interface when done using it.

Message store providers can limit access to certain properties and property types and to specific interfaces on those properties. If a requested interface is not available on the given property, OpenProperty returns the error MAPI_E_INTERFACE_NOT_SUPPORTED.

See Also

HrIStorageFromStream function, IMAPIProp::DeleteProps method, IMAPIProp::GetProps method, IMAPIProp::SetProps method, IMAPISupport::IStorageFromStream method


 IMAPIProp::SaveChanges

[New - Windows 95]

Makes permanent any changes made to an object since the last save operation.

Syntax

HRESULT SaveChanges(ULONG ulFlags)

Parameters

ulFlags

Input parameter containing a bitmask of flags used to control what happens to the object when the IMAPIProp::SaveChanges method is called. If no flags are set, the client application wants to commit changes to the object but will make no further calls to the object except for calling Release. If a provider returns an error in this case, it is because the provider couldn't save the changes. If neither KEEP_OPEN_READWRITE or KEEP_OPEN_READONLY are set, the results are implementation-specific; some providers treat it as equivalent to passing KEEP_OPEN_READWRITE, while others can choose to interpret it like KEEP_OPEN_READONLY, while others actually go to the effort of shutting down the object. The following flags can be set:

FORCE_SAVE

Writes changes to the object and closes it. Write permission must have previously been granted for the operation to succeed. This flag only forces the save if MAPI_E_OBJECT_CHANGED was returned from a preceding SaveChanges call. It overrides the previous changes made to the object.

KEEP_OPEN_READONLY

Indicates the client application wants to commit changes and keep the object open for reading. This flag informs the provider that the client application does not want to modify the object and does not intend to call SaveChanges again. If the provider cannot keep the object open for read-only access, then the entire call fails, changes are not saved, and MAPI_E_NO_ACCESS is returned.

The provider can choose to leave the object open for READ/WRITE access. However, the provider cannot close off all access to the object when this flag is given.

This flag is meant to suggest to the provider that the client does not intend to make further modifications to the object. A client that passes KEEP_OPEN_READONLY and then calls IMAPIProp::SetProps followed by a call to SaveChanges can expect the application to crash in some provider implementations.

KEEP_OPEN_READWRITE

Indicates that the client application wants to commit changes and keep the object open for read-write access. This usually occurs when the object was initially opened for read-write access. After calling SaveChanges, the client can choose to make further changes to the object. If the provider cannot keep the object open for read-only access, then the entire call fails, changes are not saved, and MAPI_E_NO_ACCESS is returned.

After receiving such an error, the client continues to have read-write access and might pass KEEP_OPEN_READONLY or no KEEP_OPEN_* flags. It is up to the provider to decide if it can fully support this flag. In no case can a provider leave the object in a read-only state when the KEEP_OPEN_READWRITE flag is given.

MAPI_DEFERRED_ERRORS

Indicates the call is allowed to succeed even if the underlying object is not accessible to the calling application. If the object is not accessible, some subsequent call to the object might return an error.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NO_ACCESS

An attempt to modify a read-only object or an attempt to access an object for which the user has insufficient permissions.

MAPI_E_OBJECT_CHANGED

The object has changed since it was opened.

MAPI_E_OBJECT_DELETED

The object has been deleted since it was opened.

Comments

Use the IMAPIProp::SaveChanges method to make changes permanent for some objects, specifically messages, attachments, address book containers, and messaging users. Other objects, such as folders, message stores, and profile sections, make changes permanent immediately without calling SaveChanges.

Some message store implementations do not show newly created messages in a folder until the client application saves the message changes using SaveChanges and releases the message objects using IUnknown::Release. In addition, some object implementations cannot generate a PR_ENTRYID property for a newly created object until after SaveChanges has been called, and some can only do so after SaveChanges has been called with the KEEP_OPEN_READONLY flag set in the ulFlags parameter.

Furthermore, changes to properties, such as the message subject, that are cached in a folder's summary table cannot be processed until your application has called SaveChanges and in some situations Release as well.

When making bulk changes, such as saving attachments to multiple messages, your application should defer error processing by setting the MAPI_DEFERRED_ERRORS flag in the ulFlags parameter. In the case of saving attachments to multiple messages, MAPI_DEFERRED_ERRORS should be set for each attachment modification and for all but the last message modification; the constant should be omitted from the SaveChanges call on the last message so that errors can be returned. (Providers can in fact return errors before the last modification is made in this case, or they can ignore this constant altogether.) If the KEEP_OPEN_READWRITE and KEEP_OPEN_READONLY flags are set on the same call as MAPI_DEFERRED_ERRORS, providers probably will ignore MAPI_DEFERRED_ERRORS. If MAPI_DEFERRED_ERRORS is not set in the ulFlags parameter, one of the previously deferred errors are returned for the SaveChanges call.

Standard client application behavior when saving changes to an object for which a preceding call to SaveChanges has returned MAPI_E_OBJECT_CHANGED is a normal save operation rather than a forced save and examination of any returned error code. If the original object has been modified, the application usually warns the user, who can either request the changes be saved or save the message somewhere else. If the original message has been deleted, the application warns the user, who can save the message somewhere else.

If the user deletes an open object, the client application is unable to force a save, even when the FORCE_SAVE flag has been set in the ulFlags parameter.

If SaveChanges returns an error, then the object whose changes were to be saved remains open, regardless of the flags set in the ulFlags parameter.


 IMAPIProp::SetProps

[New - Windows 95]

Sets the property value of one or more properties of an object.

Syntax

HRESULT SetProps(ULONG cValues, LPSPropValue lpPropArray, LPSPropProblemArray FAR * lppProblems)

Parameters

cValues

Input parameter containing the number of values in the lpPropArray parameter. The cValues parameter must not be zero.

lpPropArray

Input parameter pointing to an array of SPropValue structures holding property values.

lppProblems

Output parameter pointing to a variable where the pointer to an SPropProblemArray structure is stored. If a value of NULL is passed in the lppProblems parameter, no property problem array is returned.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

The following values can be returned in the SPropProblemArray structure, but not as a return value for SetProps:

MAPI_E_BAD_CHARWIDTH

Either the MAPI_UNICODE flag was set and the implementation does not support Unicode, or MAPI_UNICODE was not set and the implementation only supports Unicode.

MAPI_E_COMPUTED

The property can't be written because it is computed by the destination object's provider.

MAPI_E_INVALID_TYPE

The property type is invalid.

MAPI_E_NO_ACCESS

An attempt to modify a read-only object or an attempt to access an object for which the user has insufficient permissions.

MAPI_E_UNEXPECTED_TYPE

The type of the property value is not the type expected by the calling application.

Comments

Use the IMAPIProp::SetProps method to set the property values of properties. A call to SetProps passes a number of SPropValue structures. The property tag in each structure indicates which property is having its value set, and the property value in each structure indicates what should be stored as the property's value.

If a SetProps call passes a tag for a nonexistent property and the implementation supports the creation of new properties, SetProps adds the new property to the object. Any previous value stored with the property identifier used for the new property is discarded. Depending on the implementation, your application can also change the property type and value of a stored property together at one time by passing a property tag containing a different type than was previously used with a given property identifier.

Any property with a property tag of PR_NULL or a property type of PT_ERROR is ignored by SetProps; no value is set and no problem report is generated for the property. Properties with a property type of PT_OBJECT cannot be set using SetProps, attempts to pass a property value array containing properties of type PT_OBJECT result in the value MAPI_E_INVALID_PARAMETER being returned. Furthermore, your application cannot set multivalued properties with zero values in the cValues member of the SPropValue structure. Calls to set zero-valued multivalued properties should return the value MAPI_E_INVALID_PARAMETER.

If the call succeeds overall but there are problems with setting some of the selected properties, the value S_OK is returned and an SPropProblemArray structure is returned in the lppProblems parameter. The SPropProblemArray structure contains details about each property problem. In some cases, a SetProps call can successfully set some of the requested properties, but not others; in these cases, exactly which properties were not successfully set can be determined from the SPropProblemArray structure. For example, if a property type is invalid or not supported, the SetProps call returns the value MAPI_E_INVALID_TYPE for that property in the SPropProblemArray structure.

The value returned in the lppProblems parameter is only valid if the call returns S_OK. When S_OK is returned, check the values returned in the SPropProblemArray structure. If an error occurs on the call, then the SPropProblemArray structure is not filled in and the calling application should not use or free the SPropProblemArray structure; call IMAPIProp::GetLastError to get the MAPIERROR structure for the error.

The calling application must free the returned SPropProblemArray structure by calling the MAPIFreeBuffer function, but this should only be done if SetProps returns with S_OK.

Note that a return value that indicates success does not necessarily indicate that the property-setting operation was successful. Some providers cache SetProps calls on the client side of the provider until they receive a call that requires provider intervention, such as a call to the IMAPIProp::SaveChanges or IMAPIProp::GetProps methods. When such a call is received, the client attempts to transmit the cached information to the provider and the client can receive error codes related to the earlier calls. For information about how a specific service provider implements SetProps, see the provider's documentation.

See Also

IMAPIProp::GetProps method, IMAPIProp::SaveChanges method, MAPIFreeBuffer function, SPropProblemArray structure, SPropValue structure


 IMAPISession : IUnknown

[New - Windows 95]

The IMAPISession interface is used to manage objects associated with a MAPI logon session.

At a Glance

Specified in header file:	MAPIX.H
Object that supplies this interface:	Session object
Corresponding pointer type:	LPMAPISESSION
Implemented by:	MAPI
Called by:	Client applications
Vtable Order

GetLastError	Returns information about the last error that occurred for the session object.
GetMsgStoresTable	Returns a table that provides information about each of the message stores configured in the session's profile.
OpenMsgStore	Opens a message store and returns a pointer that provides further access to the open store.
OpenAddressBook	Opens an address book and returns a pointer that provides further access.
OpenProfileSection	Opens a section of the current profile and returns a pointer that provides further access to the profile object.
GetStatusTable	Gets the status table for a given client-application session.
OpenEntry	Opens an object by using its entry identifier.
CompareEntryIDs	Compares two entry identifiers to determine whether they refer to the same object.
Advise	Registers your application for notifications on changes to the session object.
Unadvise	Removes a registration for notification of changes previously established with a call to the IMAPISession::Advise method.
MessageOptions	Displays a modal dialog box showing the message options for a particular message.
QueryDefaultMessageOpt	Returns the available message options and their default settings for a particular e-mail address type.
EnumAdrTypes	Returns the e-mail address types for which a transport provider has registered support.
QueryIdentity	Returns an entry identifier representing the primary identity for a MAPI session.
Logoff	Ends a MAPI session.
SetDefaultStore	Sets the default message store provider.
AdminServices	Administers configuration changes to the profile.
ShowForm	Displays a message form for editing and sending.
PrepareForm	Creates a message instance for use by ShowForm.


 IMAPISession::AdminServices

[New - Windows 95]

Administers configuration changes to the profile.

Syntax

HRESULT AdminServices(ULONG ulFlags, LPSERVICEADMIN FAR * lppServiceAdmin)

Parameters

ulFlags

Reserved; must be zero.

lppServiceAdmin

Output parameter pointing to a variable where the pointer to the returned service-administration object is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Use the IMAPISession::AdminServices method to acquire a pointer to an IMsgServicesAdmin interface. Once your application has the pointer to the interface, it can call IMsgServicesAdmin methods to change the message service configuration within a profile. Changes made to the IMsgServicesAdmin methods will not affect the current running session. If profile configuration was the primary purpose for creating the session, log on using the MAPI_NO_MAIL flag.

See Also

IMsgServiceAdmin : IUnknown interface, IProfAdmin::AdminServices method


 IMAPISession::Advise

[New - Windows 95]

Registers your application for notifications on changes to the session object.

Syntax

HRESULT Advise(ULONG cbEntryID, LPENTRYID lpEntryID, ULONG ulEventMask, LPMAPIADVISESINK lpAdviseSink, ULONG FAR * lpulConnection)

Parameters

cbEntryID

Input parameter containing the number of bytes in the entry identifier pointed to by the lpEntryID parameter.

lpEntryID

Input parameter pointing to the entry identifier of the session object about which notifications should be generated. An entry identifier of a status object cannot be used. A value of NULL can be used to detect logoffs from shared sessions.

ulEventMask

Input parameter containing an event mask of the types of notification events occurring for the object for which MAPI will generate notifications to filter specific cases. The following table lists the possible event types along with their corresponding data structures:

Notification event type	Corresponding data structure
fnevCriticalError	ERROR_NOTIFICATION
lpAdviseSink

Input parameter pointing to an advise sink object to be called when an event for the session object occurs about which notification has been requested. This advise sink object must have already been allocated.

lpulConnection

Output parameter pointing to a variable that on a successful return holds the connection number for the notification registration. The connection number must be nonzero.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_INVALID_ENTRYID

The service provider is not able to use the entry identifier passed in the lpEntryID parameter.

MAPI_E_NO_SUPPORT

The service provider either does not support changes to its objects or does not support notification of changes.

MAPI_E_UNKNOWN_ENTRYID

A service provider could not be found to handle the entry identifier.

Comments

Use the IMAPISession::Advise method to register a session object for notification callbacks. MAPI will forward this call to the service provider active on the session that is responsible for the object indicated by the entry identifier in the lpEntryID parameter. Whenever a change occurs to the indicated object, the provider checks to see what event mask bit has been set in the ulEventMask parameter and thus what type of change has occurred. If a bit is set, then the provider calls the IMAPIAdviseSink::OnNotify method for the advise sink object indicated by the lpAdviseSink parameter to report the event. Data passed in the notification structure to the OnNotify routine describes the event.

The call to OnNotify can occur during the call that changes the object, or at any following time. On systems that support multiple threads of execution, the call to OnNotify can occur on any thread. For a way to turn a call to OnNotify that might happen at an inopportune time into one that is safer to handle, your client should use the HrThisThreadAdviseSink function.

To provide notifications, the service provider implementing Advise needs to keep a copy of the pointer to the advise sink object; to do so, it calls the IUnknown::AddRef method for the advise sink object to maintain the object pointer until notification registration is canceled with a call to the IMAPISession::Unadvise method. The Advise implementation should assign a connection number to the notification registration and call AddRef on this connection number before returning it in the lpulConnection parameter. Service providers can release the advise sink object before the registration is canceled, but they must not release the connection number until Unadvise has been called. After a call to Advise has succeeded and before Unadvise has been called, client applications must be prepared for the advise sink object to be released. Clients should therefore release their advise sink object after Advise returns unless they have a specific long term use for it.

See Also

ERROR_NOTIFICATION structure, HrThisThreadAdviseSink function, IMAPIAdviseSink::OnNotify method, IMAPISession::Unadvise method


 IMAPISession::CompareEntryIDs

[New - Windows 95]

Compares two entry identifiers to determine if they refer to the same service provider object. MAPI only passes this call to a service provider if the unique identifiers (UIDs) in both entry identifiers to be compared are handled by that provider.

Syntax

HRESULT CompareEntryIDs(ULONG cbEntryID1, LPENTRYID lpEntryID1, ULONG cbEntryID2, LPENTRYID lpEntryID2, ULONG ulFlags, ULONG FAR * lpulResult)

Parameters

cbEntryID1

Input parameter containing the number of bytes in the entry identifier pointed to by the lpEntryID1 parameter.

lpEntryID1

Input parameter pointing to the first entry identifier to be compared.

cbEntryID2

Input parameter containing the number of bytes in the entry identifier pointed to by the lpEntryID2 parameter.

lpEntryID2

Input parameter pointing to the second entry identifier to be compared.

ulFlags

Reserved; must be zero.

lpulResult

Output parameter pointing to a variable that receives the result of the comparison; this variable is TRUE if the two entry identifiers refer to the same object and FALSE otherwise.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_UNKNOWN_ENTRYID

The requested entry identifier does not exist.

Comments

Use the IMAPISession::CompareEntryIDs method to compare two entry identifiers for a given service provider object and determine whether they refer to the same object. If the two entry identifiers refer to the same object, then CompareEntryIDs sets the lpulResult parameter to TRUE; if they refer to different objects, CompareEntryIDs sets lpulResult to FALSE.

CompareEntryIDs is useful because an object can have more than one valid entry identifier; such a situation could occur, for example, after a new version of a service provider is installed.

If CompareEntryIDs returns an error, the calling application should make no assumptions about the comparison and should take the most conservative approach based on what your application is trying to do. CompareEntryIDs might fail if, for example, no provider has registered for one of the entry identifiers. If your application compares message-store entry identifiers when one or both of the stores has not yet opened, CompareEntryIDs returns the value MAPI_E_UNKNOWN_ENTRYID.


 IMAPISession::EnumAdrTypes

[New - Windows 95]

Returns the e-mail address types for which a transport provider has registered support.

Syntax

HRESULT EnumAdrTypes(ULONG ulFlags, ULONG FAR * lpcAdrTypes, LPTSTR FAR * FAR * lpppszAdrTypes)

Parameters

ulFlags

Input parameter containing a bitmask of flags controlling the type of the returned strings. The following flag can be set:

MAPI_UNICODE

Indicates the returned strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

lpcAdrTypes

Output parameter pointing to the number of strings indicating e-mail address types returned in the lpppszAdrTypes parameter.

lpppszAdrTypes

Output parameter pointing to a variable where the array of pointers to strings containing e-mail address types (such as FAX, SMTP, X500, and so on) is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Use the IMAPISession::EnumAdrTypes method to determine which address types are supported by the transport providers loaded on a given session. The list of address types returned by EnumAddrTypes depends on what providers are loaded at the time. For example, if a transport provider is not open, the address types that the unopened provider supports do not appear in the list.

Your application should release the string array pointed to by the lpppszAdrTypes parameter when done with them by calling the MAPIFreeBuffer function.

See Also

MAPIFreeBuffer function


 IMAPISession::GetLastError

[New - Windows 95]

Returns a MAPIERROR structure containing information about the last error that occurred for the session object.

Syntax

HRESULT GetLastError(HRESULT hResult, ULONG ulFlags, LPMAPIERROR FAR * lppMAPIError)

Parameters

hResult

Input parameter containing the result returned for the last call on the session object that returned an error.

ulFlags

Input parameter containing a bitmask of flags controlling the type of the returned strings. The following flag can be set:

MAPI_UNICODE

Indicates the strings returned in the MAPIERROR structure returned in the lppMAPIError parameter are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

lppMAPIError

Output parameter pointing to a pointer to the returned MAPIERROR structure containing version, component, and context information for the error. The lppMAPIError parameter can be set to NULL if there is no MAPIERROR structure to return.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_BAD_CHARWIDTH

Either the MAPI_UNICODE flag was set and the implementation does not support Unicode, or MAPI_UNICODE was not set and the implementation only supports Unicode.

Comments

Use the IMAPISession::GetLastError method to retrieve information to display as a message to the user regarding the last error returned from a method call on the session object.

To release all the memory allocated by MAPI, client applications need only call the MAPIFreeBuffer function for the MAPIERROR structure.

The return value from GetLastError must be S_OK for the application to make use of the MAPIERROR structure. Even if the return value is S_OK, it is still possible that a MAPIERROR structure won't be returned. If the implementation cannot determine what the last error was, or if a MAPIERROR structure is not available for that error, a pointer to NULL is returned in the lppMAPIError parameter instead.

See Also

MAPIERROR structure, MAPIFreeBuffer function


 IMAPISession::GetMsgStoresTable

[New - Windows 95]

Returns a table that provides information about each of the message stores configured in the session's profile.

Syntax

HRESULT GetMsgStoresTable(ULONG ulFlags, LPMAPITABLE FAR * lppTable)

Parameters

ulFlags

Input parameter containing a bitmask of flags controlling the type of the returned strings. The following flag can be set:

MAPI_UNICODE

Indicates the returned strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

lppTable

Output parameter pointing to a variable where the returned table object is stored. The table object contains message store information.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_BAD_CHARWIDTH

Either the MAPI_UNICODE flag was set and the implementation does not support Unicode, or MAPI_UNICODE was not set and the implementation only supports Unicode.

Comments

Use the IMAPISession::GetMsgStoresTable method to retrieve a table holding information about each open message store configured in the session's profile. The message-store information table contains the following required property columns:

PR_DEFAULT_STORE

If this column has an entry, and its value is true, it indicates that this message store is where the MAPI spooler delivers incoming messages. One and only one message store per profile has this value set to true.

PR_DISPLAY_NAME

The display name of the message store resource listed in the current row.

PR_ENTRYID

The entry identifier for the message store resource listed in the current row. This entry identifier is used to open the resource with the IMAPISession::OpenMsgStore method. This is a long-term entry identifier, except in the case of a message store not fully configured in the profile.

PR_INSTANCE_KEY

The index column for the row.

PR_PROVIDER_DISPLAY

The display name of the service provider.

PR_RECORD_KEY

This is the unique identifier for the message store object.

PR_RESOURCE_TYPE

For messages stores, the resource type value is MAPI_STORE_PROVIDER.

The message-store information table can also contain the following optional columns:

PR_MDB_PROVIDER

Indicates the provider type that furnished the underlying data for the message store.

PR_RESOURCE_FLAGS

Contains message service-specific flags for the message store.

The default column set includes all of the columns defined for the table.

The message store information table is updated during the session to reflect changes to the profile. The changes include addition of new, permanent message stores to the table, removal of existing stores, and changes in which message store is the default. Client applications should register for notification of such changes.

Setting the MAPI_UNICODE flag in the ulFlags parameter does the following:

•	Sets the string type to Unicode for data returned for the initial active columns of the message-store information table by the IMAPITable::QueryColumns method. The initial active columns for a message-store information table are those columns the QueryColumns method returns before the application that contains the message-store information table calls the IMAPITable::SetColumns method.

•	Sets the string type to Unicode for data returned for the initial active rows of the message-store information table by the IMAPITable::QueryRows method. The initial active rows for a message-store information table are those rows QueryRows returns before the application that contains the message-store information table calls the IMAPITable::SetColumns method.

•	Controls the property types of the sort order specification returned by the IMAPITable::QuerySortOrder method before the application that contains the message store information table calls the IMAPITable::SortTable method.

See Also

IMAPISession::OpenMsgStore method, IMAPITable::QueryColumns method, IMAPITable::QueryRows method, IMAPITable::QuerySortOrder method, IMAPITable::SetColumns method, IMAPITable::SortTable method


 IMAPISession::GetStatusTable

[New - Windows 95]

Gets the status table for a given client-application session.

Syntax

HRESULT GetStatusTable(ULONG ulFlags, LPMAPITABLE FAR * lppTable)

Parameters

ulFlags

Input parameter containing a bitmask of flags controlling the type of the returned strings. The following flag can be set:

MAPI_UNICODE

Indicates the returned strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

lppTable

Output parameter pointing to a pointer to the returned status table object.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Use the IMAPISession::GetStatusTable method to open the status table object which contains information about everything that is going on in the session. There is one status table for each MAPI session. The only way to get a status object is by calling IMAPISession::OpenEntry on an entry identifier within the status table returned from GetStatusTable. The status table contains at least the following property columns:

PR_DISPLAY_NAME

Name of the component.

PR_ENTRYID

Unique identifier for the object.

PR_IDENTITY_DISPLAY

The display name for the service provider as defined by the service provider.

PR_INSTANCE_KEY

The search key for the row.

PR_OBJECT_TYPE

Indicates the type of the MAPI object.

PR_PROVIDER_DLL_NAME

Filename of the provider DLL.

PR_PROVIDER_DISPLAY

The display name of the service provider.

PR_RESOURCE_METHODS

Flags indicating which methods are supported by the associated status object.

PR_RESOURCE_FLAGS

Flags describing the resource.

PR_RESOURCE_TYPE

Indicates what type of service provider this provider is.

PR_ROWID

Contains a unique identifier for the row.

PR_STATUS_CODE

Status of the component

The following properties are optional:

PR_IDENTITY_ENTRYID

Entry identifier of the user on this resource.

PR_IDENTITY_SEARCH_KEY

The search key used to locate the service provider.

PR_STATUS_STRING

String to describe what the state of the component is. If absent, the default value is used based on PR_STATUS_CODE.

The default column set includes all of the columns defined for the table.

Setting the MAPI_UNICODE flag in the ulFlags parameter does the following:

•	Sets the string type to Unicode for data returned for the initial active columns of the status table by the IMAPITable::QueryColumns method. The initial active columns for a status table are those columns the QueryColumns method returns before the application that contains the status table calls the IMAPITable::SetColumns method.

•	Sets the string type to Unicode for data returned for the initial active rows of the status table by the IMAPITable::QueryRows method. The initial active rows for a status table are those rows QueryRows returns before the application that contains the status table calls the IMAPITable::SetColumns method.

•	Controls the property types of the sort order specification returned by the IMAPITable::QuerySortOrder method before the application that contains the message store information table calls the IMAPITable::SortTable method.

See Also

IMAPITable::QueryColumns method, IMAPITable::QueryRows method, IMAPITable::QuerySortOrder method, IMAPITable::SetColumns method, IMAPITable::SortTable method


 IMAPISession::Logoff

[New - Windows 95]

Ends a MAPI session.

Syntax

HRESULT Logoff(ULONG ulUIParam, ULONG ulFlags, ULONG ulReserved)

Parameters

ulUIParam

Input parameter whose usage depends on the platform. On Windows platforms, the ulUIParam parameter is the handle to the main window of the calling application, cast to a ULONG.

ulFlags

Input parameter containing a bitmask of flags used to control the logoff process. The following flags can be set:

MAPI_LOGOFF_SHARED

Indicates that all applications logged in using the shared session are notified of the shared logoff and can log off if they want to. Any application that uses the shared session can set this flag. If the specified session is not part of the shared session, this flag is ignored.

MAPI_LOGOFF_UI

Indicates that a logoff dialog box (some implementations of MAPI might request confirmation of logoff if operations are pending) should be displayed. If this flag is not set, logoff proceeds without displaying a dialog box.

ulReserved

Reserved; must be zero.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Use the IMAPISession::Logoff method to end a MAPI session. Calling Logoff implicitly invalidates the session object. IMAPISession::Logoff is similar to the Simple MAPI function MAPILogoff, except that IMAPISession::Logoff doesn't release the session and it returns an HRESULT rather than a ULONG.

If the MAPI_LOGOFF_SHARED flag is set in the ulFlags parameter, notifications are sent to all client applications using the shared session indicating that they should also log off.

After Logoff has been called, the calling application should immediately release the session object by calling the IUnknown::Release method. After calling Logoff, a call to Release is the only valid call for the session object.

See Also

MAPILogoff function


 IMAPISession::MessageOptions

[New - Windows 95]

Displays a modal dialog box showing the message options for a particular message. You can edit the message options in the dialog box.

Syntax

HRESULT MessageOptions(ULONG ulUIParam, ULONG ulFlags, LPTSTR lpszAdrType, LPMESSAGE lpMessage)

Parameters

ulUIParam

Input parameter containing the handle to the window that the dialog box is modal to.

ulFlags

Input parameter containing a bitmask of flags controlling the type of the strings. The following flag can be set:

MAPI_UNICODE

Indicates the passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

lpszAdrType

Input parameter pointing to a string containing the messaging address type for which the options dialog box should be displayed; examples of e-mail address types are FAX, SMTP, X500, and so on. If all registered address types should be shown, your application should pass NULL in the lpszAdrType parameter. The lpszAdrType parameter's value must not be zero.

lpMessage

Input parameter pointing to the message for which a dialog box is to be displayed.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NOT_FOUND

No options were registered for the message.

Comments

Use the IMAPISession::MessageOptions method to get from the user a set of preferences governing message options for the message. Message option changes made by the user only become persistent after the application calls IMAPIProp::SaveChanges on the message. Changes made to the message options for the message do not affect the default options for that address type. These options are usually messaging service elements specific to a transport provider.


 IMAPISession::OpenAddressBook

[New - Windows 95]

Opens the MAPI address book and returns a pointer that provides further access.

Syntax

HRESULT OpenAddressBook(ULONG ulUIParam, LPCIID lpInterface, ULONG ulFlags, LPADRBOOK FAR * lppAdrBook)

Parameters

ulUIParam

Input parameter containing the handle to the window that the address book window is modal to.

lpInterface

Input parameter pointing to the interface identifier for the address book object. Passing NULL in the lpInterface parameter indicates that the return value is cast to the standard interface for the address book object.

ulFlags

Input parameter containing a bitmask of flags used to control the return of the columns. The following flag can be set:

AB_NO_DIALOG

Suppresses display of dialog boxes while underlying address book providers are initialized during logon. If AB_NO_DIALOG is not set in the ulFlags parameter, address book providers can prompt the user to correct the logon name or password, to insert a disk, or to perform other actions necessary to establish connections.

lppAdrBook

Output parameter pointing to a variable where the pointer to the returned address book object is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_W_ERRORS_RETURNED

The call succeeded, but one or more of the address book providers could not be loaded. Use the HR_FAILED macro to test for this warning, but the call should be handled as a successful return.

Comments

Use the IMAPISession::OpenAddressBook method during the logon process to get access to an address book. The returned pointer to the address book can then be used to open address book containers, find messaging users, and display addressing dialog boxes.

This method can return MAPI_W_ERRORS_RETURNED if it cannot load an address book provider This is a warning, not an error, and should be handled as a successful return. Even if all of the address book providers failed to load, OpenAddressBook succeeds and returns MAPI_W_ERRORS_RETURNED and an address book object in the lppAdrBook parameter. Even when no address book providers are loaded, your application can still use the IAddrBook interface, and must release it when done.

Your application can call the IMAPISession::GetLastError method on the session object to obtain a MAPIERROR structure containing information about the address book providers that failed to load. If more than one provider failed to load, a single MAPIERROR structure is returned that contains an aggregation of the strings returned by each provider.

See Also

IMAPISession::GetLastError method, MAPIERROR structure


 IMAPISession::OpenEntry

[New - Windows 95]

Opens an object given its entry identifier.

Syntax

HRESULT OpenEntry(ULONG cbEntryID, LPENTRYID lpEntryID, LPCIID lpInterface, ULONG ulFlags, ULONG FAR * lpulObjType, LPUNKNOWN FAR * lppUnk)

Parameters

cbEntryID

Input parameter containing the number of bytes in the entry identifier pointed to by the lpEntryID parameter.

lpEntryID

Input parameter pointing to the entry identifier of the object to be opened.

lpInterface

Input parameter pointing to the interface identifier for the indicated object. Passing NULL in the lpInterface parameter indicates that the return value is cast to the standard interface for the indicated object. The lpInterface parameter can also be set to an appropriate interface identifier for the object being opened.

ulFlags

Input parameter containing a bitmask of flags used to control how the object is opened. The following flags can be used:

MAPI_BEST_ACCESS

Indicates the object should be opened with the maximum privileges allowed to the user. For example, if the client application has write privilege, open the object with write privilege; if the client application has read-only privilege, open the object with read-only privilege. The client application can learn the privilege by getting the property PR_ACCESS_LEVEL.

MAPI_DEFERRED_ERRORS

Indicates the call is allowed to succeed even if the underlying object is not accessible to the calling application. If the object is not accessible, some subsequent call to the object might return an error.

MAPI_MODIFY

Requests write access. By default, objects are created with read-only access, and client applications should not assume that write access was granted.

lpulObjType

Output parameter pointing to a variable where the object type for the opened object is stored.

lppUnk

Output parameter pointing to a variable where the pointer to the opened object is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NO_ACCESS

An attempt to modify a read-only object or an attempt to access an object for which the user has insufficient permissions.

MAPI_E_UNKNOWN_ENTRYID

The object indicated in the lpEntryID parameter is not recognized. This return value is typically returned if the message store or address book provider that the object is contained within is not open.

MAPI_E_NOT_FOUND

The object indicated in the lpEntryID parameter does not exist.

Comments

Use the IMAPISession::OpenEntry method to open objects. Using IMAPISession::OpenEntry is slower than using the IMsgStore::OpenEntry method or the IAddrBook::OpenEntry method, but IMAPISession::OpenEntry is useful if the calling application does not have information on where to locate the object. The IMAPISession::OpenEntry call returns a pointer that provides further access to the object to be opened. Default behavior is to open the object as read-only, unless the call sets the MAPI_MODIFY or MAPI_BEST_ACCESS flag in the ulFlags parameter.

In the MAPI implementation running with Windows, MAPI provides a status table with information about each of the installed service providers. In each row of the status table, a status object is available with information about a particular service provider. Calling OpenEntry with the entry identifier of a status object found in the status table is the only way to open that status object.

Calling OpenEntry and passing in the entry identifier for a message store in the lpEntryID parameter, as your application does when it does not have information on where that message store is located, is equivalent to calling the IMAPISession::OpenMsgStore method with the MDB_NO_DIALOG flag set in its ulFlags parameter, which, without displaying a logon dialog box, opens that message store and returns a pointer to it. When opening a message store, flags set in OpenEntry's ulFlags parameter map to OpenMsgStore flags as follows:

OpenEntry flag	OpenMsgStore equivalent
MAPI_BEST_ACCESS	MAPI_BEST_ACCESS
MAPI_MODIFY	MDB_WRITE
MAPI_DEFERRED_ERRORS	MAPI_DEFERRED_ERRORS
The calling application should check the value returned in the lpulObjType parameter to determine that the object type returned is what was expected. Commonly, after the application checks the type of the object, it then casts the pointer in the lppUnk parameter into a message object pointer, a folder object pointer, or another appropriate object pointer.

See Also

IAddrBook::OpenEntry method, IMAPISession::OpenMsgStore method, IMsgStore::OpenEntry method


 IMAPISession::OpenMsgStore

[New - Windows 95]

Opens a message store and returns a pointer that provides further access to the open store.

Syntax

HRESULT OpenMsgStore(ULONG ulUIParam, ULONG cbEntryID, LPENTRYID lpEntryID, LPCIID lpInterface, ULONG ulFlags, LPMDB FAR * lppMDB)

Parameters

ulUIParam

Input parameter whose usage depends on the platform. On Windows platforms, the ulUIParam parameter is the handle to the main window of the calling application, cast to a ULONG.

cbEntryID

Input parameter containing the number of bytes in the entry identifier pointed to by the lpEntryID parameter.

lpEntryID

Input parameter pointing to the entry identifier of the message store to be opened. The lpEntryID parameter must be non-null.

lpInterface

Input parameter pointing to the interface identifier for the indicated message-store object. Passing NULL in the lpInterface parameter indicates that the return value is cast to the standard interface for a message store object.

ulFlags

Input parameter containing a bitmask of flags used to control how the message store is accessed. The following flags can be used:

MAPI_BEST_ACCESS

Indicates the object should be opened with the maximum privileges allowed to the user. For example, if the client application has write privilege, open the object with write privilege; if the client application has read-only privilege, open the object with read-only privilege. The client application can learn the privilege by getting the property PR_ACCESS_LEVEL.

MAPI_DEFERRED_ERRORS

Indicates the call is allowed to succeed even if the underlying object is not accessible to the calling application. If the object is not accessible, some subsequent call to the object might return an error.

MDB_NO_DIALOG

Prevents display of logon dialog boxes. If this flag is set, the error code MAPI_E_LOGON_FAILED is returned if logon is unsuccessful. If this flag is not set, the message store provider can prompt the user to correct the name or password, to insert a disk, or to perform other actions necessary to establish connection to the store.

MDB_NO_MAIL

Indicates the message store should not be used for sending or receiving mail. The flag signals MAPI to not notify the MAPI spooler that this message store is being opened.

MDB_TEMPORARY

Used to log the store on so that information can be retrieved programmatically from the profile section. Instructs MAPI that the store is not to be added to the message stores information table and that the store cannot be made permanent.

MDB_WRITE

Requests write access.

lppMDB

Output parameter pointing to a variable where the pointer to the message store object is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NO_ACCESS

An attempt to modify a read-only object or an attempt to access an object for which the user has insufficient permissions.

MAPI_E_NOT_FOUND

The message store indicated in the lpEntryID parameter does not exist.

MAPI_W_ERRORS_RETURNED

The call succeeded, but the message store provider has information available. Use the HR_FAILED macro to test for this warning, but the call should be handled as a successful return. Call IMAPISession::GetLastError to get the information from the provider.

Comments

Use the IMAPISession::OpenMsgStore method during the logon process to get access to a particular message store using the entry identifier from the message store table. The default behavior is to open the object as read-only, unless an application sets the MDB_WRITE flag in the ulFlags parameter.

Note the following points about the default behavior of opening a message store as read-only:

•	The STORE_MODIFY_OK and the STORE_CREATE_OK bits in the PR_STORE_SUPPORT_MASK property return false for the store object. This return occurs only when a message store is opened as read-only using OpenMsgStore, not in other read-only scenarios.

•	Calling the IMAPISession::OpenEntry method or the IMAPIProp::OpenProperty method with the flag MAPI_MODIFY, which requests write access, fails.

•	Calls to the following methods fail: IMAPIFolder::CreateMessage, IMAPIFolder::DeleteMessages, IMAPIFolder::CreateFolder, IMAPIFolder::DeleteFolder, IMAPIFolder::SetMessageStatus, IMAPIProp::SetProps, IMAPIProps::DeleteProps.

•	Calls to the following methods fail if the copying destination is within the same read-only message store as the copying source: IMAPIFolder::CopyMessages, IMAPIFolder::CopyFolder, IMAPIFolder::CopyTo.


 IMAPISession::OpenProfileSection

[New - Windows 95]

Opens a section of the current profile and returns a pointer that provides further access to the profile object.

Syntax

HRESULT OpenProfileSection(LPMAPIUID lpUID, LPCIID lpInterface, ULONG ulFlags, LPPROFSECT FAR * lppProfSect)

Parameters

lpUID

Input parameter pointing to the MAPIUID structure holding the MAPI unique identifier (MAPIUID) that identifies the profile section.

lpInterface

Input parameter pointing to the interface identifier used to open the profile section. Passing NULL in the lpInterface parameter indicates that the return value is cast to the standard interface for a profile section. The lpInterface parameter can also be set to an appropriate interface identifier. Valid interface identifiers are IID_IMAPIProp and IID_IProfSect.

ulFlags

Input parameter containing a bitmask of flags used to control access to the profile section. The following flags can be set:

MAPI_DEFERRED_ERRORS

Indicates the call is allowed to succeed even if the underlying object is not accessible to the calling application. If the object is not accessible, some subsequent call to the object might return an error.

MAPI_MODIFY

Requests write access. By default, objects are created with read-only access, and client applications should not assume that write access was granted.

lppProfSect

Output parameter pointing to a variable that receives the pointer to the open profile object.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NO_ACCESS

An attempt to modify a read-only profile section or an attempt to access an object for which the user has insufficient permissions.

MAPI_E_NOT_FOUND

The requested object does not exist.

Comments

Use the IMAPISession::OpenProfileSection method to open a profile section for reading information from and writing information to the active profile for the session. A profile section object supporting the IProfSect interface is returned in the lppProfSect parameter. The default behavior is to open the profile section as read-only, unless an application sets the MAPI_MODIFY flag in the ulFlags parameter. Profile sections belonging to service providers cannot be opened by calls to the IMAPISession::OpenProfileSection method.

More than one method call can open a profile section with read-only access at a time, but only one method call can open a profile section with read-write access at a time. If any other application has the profile section open, a read-write open operation fails and returns the value MAPI_E_NO_ACCESS. A read-only open operation fails if the section is open for writing.

If an OpenProfileSection call opens a nonexistent profile section by passing the MAPI_MODIFY flag in the ulFlags parameter, the call creates the section. If an OpenProfileSection call attempts to open a nonexistent section with read-only access, the value MAPI_E_NOT_FOUND is returned.

All open operations should be as brief as possible, but an application that is writing to a profile section can keep it open while displaying a modification dialog box.

See Also

IMAPIProp : IUnknown interface, IProfSect : IMAPIProp interface, MAPIUID structures


 IMAPISession::PrepareForm

[New - Windows 95]

Creates a message instance for use by ShowForm.

Syntax

HRESULT PrepareForm(LPCIID lpInterface, LPMESSAGE lpMessage, ULONG FAR * lpulMessageToken)

Parameters

lpInterface

Input parameter pointing to the interface identifier (IID) for a message object. Passing NULL for the lpInterface parameter indicates the MAPI interface for the message object will be returned. A client application can also pass in lpInterface IID_IMessage, which is the only valid IID for the message object.

lpMessage

Input parameter pointing to the message object.

lpulMessageToken

Output parameter pointing to the returned message token, which must be passed in the following IMAPISession::ShowForm call.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Use the IMAPISession::PrepareForm method to create a message instance for use by the IMAPISession::ShowForm method. Client applications should only have a single reference to the message passed in PrepareForm's lpMessage parameter. If the call to PrepareForm succeeds, the client application must release the message, then call ShowForm and pass in the ulMessageToken parameter the message token returned in PrepareForm's lpulMessageToken parameter. Failure to do so causes memory leaks.

See Also

IMAPISession::ShowForm method


 IMAPISession::QueryDefaultMessageOpt

[New - Windows 95]

Returns the available message options and their default setting for a particular e-mail address type.

Syntax

HRESULT QueryDefaultMessageOpt(LPTSTR lpszAdrType, ULONG ulFlags, ULONG FAR * lpcValues, LPSPropValue FAR * lppOptions)

Parameters

lpszAdrType

Input parameter pointing to a string containing the e-mail address type in question; examples of e-mail address types are FAX, SMTP, X500, and so on.

ulFlags

Input parameter containing a bitmask of flags controlling the type of the strings. The following flag can be set:

MAPI_UNICODE

Indicates the passed-in and the returned strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

lpcValues

Output parameter pointing to the number of property values returned in the lppOptions parameter.

lppOptions

Output parameter pointing to a variable where the pointer to the array of SPropValue structures is stored. The SPropValue structures contain available message options and their default values.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Use the IMAPISession::QueryDefaultMessageOpt method to find out what message options are available for a particular e-mail address type. The returned SPropValue property value array includes the property identifier for each message option and its default property value, if there is one.

Message options are properties of a message that control its behavior after it is submitted to the transport provider; they are part of the message envelope, not its content. They are not usually specific to a particular address type.


 IMAPISession::QueryIdentity

[New - Windows 95]

Returns an entry identifier representing the primary identity for a user for a MAPI session.

Syntax

HRESULT QueryIdentity(ULONG FAR * lpcbEntryID, LPENTRYID FAR * lppEntryID)

Parameters

lpcbEntryID

Output parameter pointing to a variable in which the IMAPISession::QueryIdentity method returns the number of bytes in the entry identifier pointed to by the lppEntryID parameter.

lppEntryID

Output parameter pointing to a variable where the pointer to the newly created entry identifier is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_W_NO_SERVICE

The call succeeded, but no provider can provide the primary identifier. Use the HR_FAILED macro to test for this warning, although the call should be handled as a successful return.

Comments

Use the IMAPSession::QueryIdentity method to retrieve a user's primary identity for the current session. The primary identity is a string that represents the user of a MAPI session.

Each messaging service provider that MAPI has information about establishes an identity for each of its users. This identity can be established when a client application logs onto the service. However, because MAPI supports connections to multiple service providers for each MAPI session, there is no firm definition of a particular user's identity for the MAPI session as a whole; a user's identity depends on which service is involved. Service providers that utilize the functionality provided by primary identities should set the STATUS_PRIMARY_IDENTITY bit in the PR_RESOURCE_FLAGS property. Client applications can call the IMsgServiceAdmin::SetPrimaryIdentity method to designate one of the many identities established for a user by messaging service providers as the primary identity for that user.

The QueryIdentity method provides applications a convenient way to retrieve this primary identity. Once your application has a user's primary identity, it can call the session object's IMAPISession::OpenEntry method and query the resulting interface to obtain properties associated with that primary identity from the returned entry identifiers, such as the display name or e-mail address. Sophisticated applications that are aware of the service provider, or the providers within whose context they operate, can browse the status table to determine users' identities in the context of the current service providers rather than using QueryIdentity. More traditional applications, which assume a single identity for a session, use QueryIdentity to obtain a user's primary identity.

QueryIdentity returns the best information MAPI can locate for the user's primary identity for a session. Ideally, this is the PR_IDENTITY_ENTRYID property from the status row tagged with STATUS_PRIMARY_IDENTITY, although there are other possibilities:

•	If no provider can provide a primary identifier, QueryIdentity succeeds with the warning MAPI_W_NO_SERVICE and returns a hard-coded entry identifier in the lppEntryID parameter.

•	If some rows make available the PR_IDENTITY_ENTRYID property but no row is tagged with STATUS_PRIMARY_IDENTITY, QueryIdentity returns the first entry identifier found.

•	If a row is tagged with STATUS_PRIMARY_IDENTITY but holds no entry identifier, QueryIdentity returns a custom-recipient entry identifier built with other information from that row.

When the client application has finished using the entry identifier for the primary identity returned by QueryIdentity, it should free the memory that held it by using the MAPIFreeBuffer function.

See Also

IMAPISession::OpenEntry method, IMsgServiceAdmin::SetPrimaryIdentity method, MAPIFreeBuffer function


 IMAPISession::SetDefaultStore

[New - Windows 95]

Sets the default message store provider.

Syntax

HRESULT SetDefaultStore(ULONG ulFlags, ULONG cbEntryID, LPENTRYID lpEntryID)

Parameters

ulFlags

Input parameter containing a bitmask of flags used to control the setting of the default message store. The flags used for the ulFlags parameter are mutually exclusive, so only one flag can be set for each call to the IMAPISession::SetDefaultStore method. The following flags can be set:

MAPI_DEFAULT_STORE

Sets the STATUS_DEFAULT_STORE flag of the PR_RESOURCE_FLAGS column of the status table.

MAPI_PRIMARY_STORE

Sets the STATUS_PRIMARY_STORE flag of the PR_RESOURCE_FLAGS column of the status table. Indicates the store that client applications should try to use when they log on. If the primary store is not the default store, client applications should set it to be so.

MAPI_SECONDARY_STORE

Sets the STATUS_SECONDARY_STORE flag of the PR_RESOURCE_FLAGS column of the status table. Indicates the store that client applications should try to use if the primary store is not available. If the client application cannot open the primary store it should open the secondary store and set it to be the default store.

MAPI_SIMPLE_STORE_PERMANENT

Causes the STATUS_SIMPLE_STORE flag of the PR_RESOURCE_FLAGS column of the status table to be set.

MAPI_SIMPLE_STORE_TEMPORARY

Causes the STATUS_SIMPLE_STORE flag of the PR_RESOURCE_FLAGS column of the status table to be set.

cbEntryID

Input parameter containing the number of bytes in the entry identifier pointed to by the lpEntryID parameter.

lpEntryID

Input parameter pointing to the entry identifier of the message store object intended as the default. If your application sends a value of NULL in the lpEntryID parameter, no message store is selected for the default.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Use the IMAPISession::SetDefaultStore method to make a single Extended MAPI call to reset the default store that message store operations take place in.

Information on which message store is the default is kept in the message-store information table. Information in this table is consistent with information in the status table; the message-store information table has a PR_RESOURCE_FLAGS property column with the same values as the PR_RESOURCE_FLAGS property column in the status table.

When either the MAPI_DEFAULT_STORE or the MAPI_SIMPLE_STORE_PERMANENT flag is set changing the default store, the profile is updated along with any message-store information table or status table open for the profile. Whenever a change is made to the message store default setting, the following notifications are generated:

•	An fnevTableModified event notification is issued for each of the affected rows in both the message-store table and the status table.

•	An internal notification is issued to the MAPI spooler. Operations already in progress are completed without change; new operations involving the default message store, such as message downloading, are processed for the new default store.

No special message store capabilities are required for the simple store. However, setting the default store fails if the target store does not set the STORE_SUBMIT_OK, STORE_CREATE_OK, and STORE_MODIFY_OK bits in the PR_STORE_SUPPORT_MASK property.

See Also

PR_RESOURCE_FLAGS property, PR_STORE_SUPPORT_MASK property, TABLE_NOTIFICATION structure


 IMAPISession::ShowForm

[New - Windows 95]

Displays a message form for editing and sending.

Syntax

HRESULT ShowForm(ULONG ulUIParam, LPMDB lpMsgStore, LPMAPIFOLDER lpParentFolder, LPCIID lpInterface, ULONG ulMessageToken, LPMESSAGE lpMessageSent, ULONG ulFlags, ULONG ulMessageStatus, ULONG ulMessageFlags, ULONG ulAccess, LPSTR lpszMessageClass)

Parameters

ulUIParam

Input parameter containing the handle for the window in which the form is displayed.

lpMsgStore

Input parameter pointing to the message store where the folder pointed to by the lpParentFolder parameter resides.

lpParentFolder

Input parameter pointing to the folder in which the message was created.

lpInterface

Reserved; must be NULL.

ulMessageToken

Input parameter containing the message token returned in the preceding call to the IMAPISession::PrepareForm method. The same token returned by the PrepareForm call must be passed in ShowForm, or the message object will not be released.

lpMessageSent

Reserved; must be NULL.

ulFlags

Input parameter containing a bitmask of flags used to control how the message is saved after being sent. The following flags can be set:

MAPI_NEW_MESSAGE

Indicates that the message has not previously been saved (i.e. IMAPIProp::SaveChanges has not been called on the message).

MAPI_POST_MESSAGE

Indicates that the message should be saved to the parent folder for the message. The message is not processed for sending, but posted to the folder instead. If this flag is not set, the message is copied to the Outbox and processed for sending.

ulMessageStatus

Input parameter containing a bitmask of client application- or service provider-defined flags, copied from the PR_MSG_STATUS property of the message referenced to the message in the ulMessageToken parameter. The flags provide information on the state of the message.

ulMessageFlags

Input parameter pointing to a bitmask of flags, copied from the PR_MESSAGE_FLAGS property of the message referenced to the message in the ulMessageToken parameter. The flags indicate the current state of the message.

ulAccess

Input parameter containing flags copied from the PR_ACCESS_LEVEL property of the message referenced to the message in the ulMessageToken parameter. The flags indicate the level of read-write access permitted on the message.

lpszMessageClass

Input parameter pointing to a string naming the message class of the message referenced to the message in the ulMessageToken parameter. This string is copied from the PR_MESSAGE_CLASS property of that message.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_USER_CANCEL

The user canceled the operation.

Comments

Use the IMAPISession::ShowForm method together with IMAPISession::PrepareForm to display a message form for editing or sending. Client applications should only have a single reference to the message passed in PrepareForm's lpMessage parameter. If the call to PrepareForm succeeds, the client application must release the message, then call ShowForm and pass in the ulMessageToken parameter the message token returned in PrepareForm's lpulMessageToken parameter. Failure to do so causes memory leaks.

See Also

IMAPISession::PrepareForm method


 IMAPISession::Unadvise

[New - Windows 95]

Removes an object's registration for notification of changes previously established with a call to the IMAPISession::Advise method.

Syntax

HRESULT Unadvise(ULONG ulConnection)

Parameters

ulConnection

Input parameter containing the number of the registration connection previously returned by a call to the IMAPISession::Advise method.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Client applications use the IMAPISession::Unadvise method to release the pointer to the advise sink object passed in the lpAdviseSink parameter in the previous call to IMAPISession::Advise and thereby cancel a notification registration. As part of discarding the pointer to the advise sink object, the object's IUnknown::Release method is called. Generally, Release is called during the Unadvise call, but if another thread is in the process of calling IMAPIAdviseSink::OnNotify on the advise sink object, the Release call is delayed until the OnNotify method returns.

See Also

IMAPIAdviseSink::OnNotify method, IMAPISession::Advise method


 IMAPIStatus : IMAPIProp

[New - Windows 95]

The IMAPIStatus interface is used by providers to support client application requests for information that is not maintained in the status table. Clients can call one of the logon object's OpenStatusEntry methods to retrieve a pointer to a provider status object. With a status object pointer, clients can call one of the four methods in the IMAPIStatus interface: ValidateState, SettingsDialog, ChangePassword, or FlushQueues. However, providers are only required to support ValidateState; they can return MAPI_E_NO_SUPPORT from their implementations of the other three methods.

At a Glance

Specified in header file:	MAPIDEFS.H
Object that supplies this interface:	Status object
Corresponding pointer type:	LPMAPISTATUS
Implemented by:	Service providers
Called by:	Client applications
Vtable Order

ValidateState	Confirms the external status information available for a service provider by checking with the service provider itself.
SettingsDialog	Displays a dialog box enabling the user to change the configuration of the active service provider.
ChangePassword	Changes a provider-specific password.
FlushQueues	Forces all messages waiting to be sent or received by a particular transport provider to be uploaded or downloaded synchronously.


 IMAPIStatus::ChangePassword

[New - Windows 95]

Changes a provider-specific password for the provider. A user interface is never displayed.

Syntax

HRESULT ChangePassword(LPTSTR lpOldPass, LPTSTR lpNewPass, ULONG ulFlags)

Parameters

lpOldPass

Input parameter pointing to a string containing the old password.

lpNewPass

Input parameter pointing to a string containing the new password.

ulFlags

Input parameter containing a bitmask of flags controlling the type of the password strings. The following flag can be set:

MAPI_UNICODE

Indicates the passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NO_ACCESS

The password is wrong or invalid.

MAPI_E_NO_SUPPORT

The STATUS_CHANGE_PASSWORD bit is not set in the PR_RESOURCE_METHODS property.

See Also

PR_RESOURCE_METHODS property


 IMAPIStatus::FlushQueues

[New - Windows 95]

Forces all messages waiting to be sent or received by a particular transport provider to be uploaded or downloaded synchronously.

Syntax

HRESULT FlushQueues(ULONG ulUIParam, ULONG cbTargetTransport, LPENTRYID lpTargetTransport, ULONG ulFlags)

Parameters

ulUIParam

Input parameter containing the handle of the window the dialog box is modal to.

cbTargetTransport

Input parameter containing the number of bytes in the lpTargetTransport parameter. Only valid when called by the MAPI spooler's status object. To flush all queues pass a value of zero.

lpTargetTransport

Input parameter pointing to the entry identifier of the transport provider for which message queues are to be flushed (that is, emptied by uploading or downloading). Only valid when called from the MAPI spooler's status object. To flush all queues pass a value of NULL.

ulFlags

Input parameter containing a bitmask of flags used to control message queue flushing. The following flags can be set:

FLUSH_ASYNC_OK

Notifies the MAPI spooler that the queues can be flushed asynchronously and return before the operation is complete. This flag only applies to the MAPI spooler's status object. Client applications can register for notifications on the MAPI spooler's status row to receive notifications when the operation is complete.

FLUSH_DOWNLOAD

Indicates the inbound message queue or queues should be flushed.

FLUSH_FORCE

Indicates the transport provider should process this request if possible, even if doing so is time-consuming. Asynchronous transports cannot respond to unforced IXPLogon::FlushQueues and IMAPIStatus::FlushQueues method calls.

FLUSH_NO_UI

Indicates the transport provider should not display user interface components. This flag is used only by the MAPI spooler; transport providers ignore this flag.

FLUSH_UPLOAD

Indicates the outbound message queue or queues should be flushed.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_BUSY

Another operation is in progress; it should be allowed to complete, or it should be stopped, before another operation is attempted.

MAPI_E_NO_SUPPORT

The STATUS_FLUSH_QUEUES bit is not set in the PR_RESOURCE_METHODS property.

Comments

Use the IMAPIStatus::FlushQueues method to force all messages in a particular transport provider's inbound or outbound message queue to be uploaded or downloaded. FlushQueues is only available from the status object. Queues are flushed synchronously when FlushQueues is called to the MAPI spooler and asynchronously when called to a specific transport.

Unless the FLUSH_NO_UI flag is set in the ulFlags parameter, the MAPI spooler displays a user interface indicating progress during the flushing operation. Transport providers ignore requests for user interface. FlushQueues processing can take a long time; MAPI_E_BUSY should be returned for asynchronous requests so that client applications can continue. Transport providers can ignore FlushQueues requests and return MAPI_E_NO_SUPPORT if they cannot handle them.

See Also

PR_RESOURCE_METHODS property


 IMAPIStatus::SettingsDialog

[New - Windows 95]

Displays a dialog box enabling the user to change the configuration of the active service provider.

Syntax

HRESULT SettingsDialog(ULONG ulUIParam, ULONG ulFlags)

Parameters

ulUIParam

Input parameter containing the handle to the window the dialog box is modal to.

ulFlags

Input parameter containing a bitmask of flags used to control how the configuration dialog box is displayed. The following flags can be set:

UI_READONLY

Suggests the provider not allow users to change provider settings. This flag can be ignored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NO_SUPPORT

The STATUS_SETTINGS_DIALOG bit is not set in the PR_RESOURCE_METHOD property.

Comments

Use the IMAPIStatus::SettingsDialog method to have a service provider display a user interface for configuration, usually for the user to make changes to property sheets. A call to SettingsDialog commonly displays a user interface, so SettingsDialog should only be used by interactive applications.


 IMAPIStatus::ValidateState

[New - Windows 95]

Confirms the external status information available for a service provider by checking with the service provider itself.

Syntax

HRESULT ValidateState(ULONG ulUIParam, ULONG ulFlags)

Parameters

ulUIParam

Input parameter containing the handle of the window the dialog box is modal to.

ulFlags

Input parameter containing a bitmask of flags used to control the status check for the service provider. The following flags can be set:

ABORT_XP_HEADER_OPERATION

Indicates that the user has requested that the operation be canceled (typically by pressing the cancel button). The transport has the option to continue working on the operation, or the transport can abort the operation and return MAPI_E_USER_CANCELED.

CONFIG_CHANGED

When the MAPI spooler is called with the flag set, it validates the state of currently loaded transports by calling the transport's IXPLogon::AddressTypes and IMAPISession::MessageOptions methods at its next convenient time. Also provides the MAPI spooler an opportunity to correct critical transport failures without forcing the client applications to log off and then log on again. When a specific transport is called with this flag set, the transport calls IMAPISupport::SpoolerNotify to notify the MAPI spooler if its profile section has been updated.

FORCE_XP_CONNECT

Indicates that the user selected a connect operation. When this flag is used with the REFRESH_XP_HEADER_CACHE or PROCESS_XP_HEADER_CACHE flags, the connect action occurs without caching.

FORCE_XP_DISCONNECT

Indicates that the user selected a disconnect operation. When this flag is used with the REFRESH_XP_HEADER_CACHE or PROCESS_XP_HEADER_CACHE flags, the disconnect action occurs without caching.

PROCESS_XP_HEADER_CACHE

Indicates that entries in the header cache table should be processed and that all messages marked as MSGSTATUS_REMOTE_DOWNLOAD should be downloaded and that all messages marked as MSGSTATUS_REMOTE_DELETE should be deleted. Messages that have both MSGSTATUS_REMOTE_DOWNLOAD and MSGSTATUS_REMOTE_DELETE set should be moved.

REFRESH_XP_HEADER_CACHE

Indicates that a new list of mailbag headers should be downloaded and that all message status marks should be cleared.

SUPPRESS_UI

Prevents the provider from displaying user interface components.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_BUSY

Another operation is in progress; it should be allowed to complete, or it should be stopped, before another operation is attempted.

MAPI_E_NO_SUPPORT

The STATUS_VALIDATE_STATE bit is not set in the PR_RESOURCE_METHODS property.

MAPI_E_USER_CANCEL

The user canceled the operation, typically by clicking the cancel button in the dialog box. This flag is only returned by remote transport providers.

Comments

Use the IMAPIStatus::ValidateState method to have a service provider check its internal state and ensure that this internal state is consistent with its status table row settings. ValidateState calls can take a long time.


 IMAPISupport : IUnknown

[New - Windows 95]

MAPI provides a support object for all service providers as a part of the registration process during service provider logon. Some methods of the MAPI support object provide functionality used by all provider types; for example, the GetLastError method is used by all providers. Other methods of the support object are specific to one provider type; for example, the CopyMessages method is only used by message store providers. Methods that are not implemented for a particular provider return MAPI_E_NO_SUPPORT when called.

MAPI creates a separate support object for each provider. When a provider makes calls to methods of the IMAPISupport interface, it should use the same support object passed in the lpMAPISup parameter when MAPI logged the provider onto that session. Providers working with more than one support object should maintain consistency between support objects and the session they are linked with.

The following table indicates which methods are implemented for particular providers.

Method	Address book provider	Message store provider	Transport provider
Address	•
CompareEntryIDs	•	•	•
CompleteMsg		•
CopyFolder		•
CopyMessages		•
CreateOneOff	•	•	•
Details	•
DoConfigPropsheet	•	•	•
DoCopyProps		•
DoCopyTo		•
DoProgressDialog	•	•
DoSentMail		•
ExpandRecips		•
GetLastError	•	•	•
GetMemAllocRoutines	•	•	•
GetOneOffTable	•
GetSvcConfigSupportObj	•	•	•
IStorageFromStream	•	•	•
MakeInvalid	•	•	•
ModifyProfile		•
ModifyStatusRow	•	•	•
NewEntry	•
NewUID	•	•	•
Notify	•	•	•
OpenAddressBook		•	•
OpenEntry	•	•	•
OpenProfileSection	•	•	•
OpenTemplateID	•
PrepareSubmit		•
ReadReceipt		•
RegisterPreprocessor			•
SetProviderUID	•	•
SpoolerNotify		•	•
SpoolerYield			•
StatusRecips			•
StoreLogoffTransports		•
Subscribe	•	•	•
Unsubscribe	•	•	•
WrapStoreEntryID	•	•	•
At a Glance

Specified in header file:	MAPISPI.H
Object that supplies this interface:	Support object
Corresponding pointer type:	LPMAPISUP
Implemented by:	MAPI
Called by:	Providers
Vtable Order

GetLastError	Returns information about the last error that occurred for the support object.
GetMemAllocRoutines	Retrieves the addresses of the three MAPI memory allocation functions, MAPIAllocateBuffer, MAPIAllocateMore, and MAPIFreeBuffer.
Subscribe	Sets up a subscription for notification of changes.
Unsubscribe	Remove an object's subscription for notification of changes.
Notify	Notifies interested applications about changes to an object that the provider owns.
ModifyStatusRow	Creates the status table column values for the service providers.
OpenProfileSection	Opens a section of the current profile and returns a pointer that provides further access.
RegisterPreprocessor	Registers a preprocessor function for a transport provider.
NewUID	Returns a new, unique MAPI identifier (a MAPIUID) for an item.
MakeInvalid	Invalidates an object derived from the IUnknown interface.
SpoolerYield	Allows the transport provider to permit the MAPI spooler to give processing time to Windows.
SpoolerNotify	Informs the MAPI spooler that the transport provider needs servicing.
CreateOneOff	Creates an entry identifier for a custom recipient.
SetProviderUID	Informs MAPI of the MAPI unique identifier (MAPIUID) assigned to the service provider using this support object.
CompareEntryIDs	Compares two entry identifiers to determine if they refer to the same support object.
OpenTemplateID	Allows runtime binding of one address book provider's code to the data in another address book provider.
OpenEntry	Opens an object given its entry identifier.
GetOneOffTable	Returns the table of custom recipient address templates that can be created onto a message.
Address	Displays MAPI's default addressing dialog box.
Details	Displays details about an address book entry using MAPI's default user interface.
NewEntry	Creates a new address book entry using MAPI's default user interface.
DoConfigPropsheet	Enables service providers to display property sheets using MAPI's default user interface. Primarily used for configuration.
CopyMessages	Copies or moves messages from the current folder to another folder.
CopyFolder	Copies or moves a folder to a destination folder.
DoCopyTo	Copies or moves all the properties of the source object to a destination object, except for given properties that are excluded from the operation.
DoCopyProps	Copies or moves a set of properties from the source object to a destination object.
DoProgressDialog	Provides a default implementation of the IMAPIProgress interface for use by service providers.
ReadReceipt	Generates a read or nonread report for a message.
PrepareSubmit	Prepares a message for submission to the MAPI spooler.
ExpandRecips	Completes all recipient lists and expands certain distribution lists for the transmission of a message.
DoSentMail	Generates a sentmail message for an open message.
OpenAddressBook	Opens the address book and returns a pointer that provides further access.
CompleteMsg	Calls the MAPI spooler to complete message delivery processing.
StoreLogoffTransports	Specifies the orderly release of the message store to the MAPI spooler.
StatusRecips	Generates delivery and nondelivery reports on behalf of transport providers.
WrapStoreEntryID	Maps the private entry identifier of a message store object to an entry identifier more useful to the messaging system.
ModifyProfile	Makes a message store provider's profile section permanent.
IStorageFromStream	Implements an IStorage object on an IStream object.
GetSvcConfigSupportObj	Creates a new support object for use by calls to a messaging service provider's configuration entry point function.


 IMAPISupport::Address

[New - Windows 95]

Displays MAPI's default addressing dialog box.

Syntax

HRESULT Address(ULONG FAR * lpulUIParam, LPADRPARM lpAdrParms, LPADRLIST FAR * lppAdrList)

Parameters

lpulUIParam

Input-output parameter containing the handle of the parent window of the dialog box. A window handle must always be passed in on input. If the DIALOG_SDI flag is set in the ADRPARM structure, then on output the window handle of the modeless dialog is returned.

lpAdrParms

Input-output parameter pointing to an ADRPARM structure that controls the presentation and behavior of the addressing dialog box.

lppAdrList

Input-output parameter pointing to a variable where the pointer to an ADRLIST structure holding the recipient list updated by IAddrBook::Address is stored. lppAdrList can be NULL on input.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Use the IMAPISupport::Address method to pass the current list of recipients in a message and return a list updated using the MAPI addressing dialog box. A client application passes the current list of recipients for a message, possibly empty, in the lppAdrList parameter when calling Address, and Address returns in lppAdrList an ADRLIST structure holding an updated list of recipients. Client applications can use the updated list to set the recipients of a message by using the IMessage::ModifyRecipients method.

The recipient entries in both the passed and returned ADRLIST structures consist of ADRENTRY structures, with each holding an individual recipient that are organized by which type of recipient they hold, as indicated by the recipient's PR_RECIPIENT_TYPE property. The possible types are MAPI_TO (that is, a primary recipient), MAPI_CC (that is, a recipient that receives a copy of a message), and MAPI_BCC (that is, a recipient that receives a copy of a message without other recipients being made aware).

ADRLIST structures can hold both resolved and unresolved recipient entries. An unresolved entry does not have a PR_ENTRYID property. Applications that enable users to type recipient names directly into a message, in addition to choosing names from a predetermined list, create unresolved entries by creating an ADRENTRY with just the PR_DISPLAY_NAME and the PR_RECIPIENT_TYPE properties. A resolved entry will at least contain the following properties: PR_ENTRYID, PR_RECIPIENT_TYPE, PR_DISPLAY_NAME, PR_ADDRTYPE, and PR_DISPLAY_TYPE.

Your provider should use the pointers to the MAPI memory allocation functions passed in during provider initialization to allocate memory. Memory for the ADRLIST structure passed by Address on output and each property value structure held within that ADRLIST must be allocated with the MAPIAllocateBuffer function. If, on output, Address needs to pass a larger ADRLIST structure than is passed in by the calling application, or if NULL is passed in the lppAdrList parameter on input, then Address allocates a larger buffer for the ADRLIST structure it returns using MAPIAllocateBuffer and returns this buffer's address in the lppAdrList parameter. Address frees the old buffer by calling the MAPIFreeBuffer function.

Each SPropValue property value structure is also separately allocated by using MAPIAllocateBuffer. The Address method allocates additional property value structures and frees old ones as appropriate.

Address returns immediately if the DIALOG_SDI flag was set in the ADRPARM structure in the lpAdrParms parameter.

See Also

ADRENTRY structure, ADRLIST structure, ADRPARM structure, FreePadrlist function, FreeProws function, IMAPISupport::GetMemAllocRoutines method, IMAPITable::QueryRows method, IMessage::ModifyRecipients method, MAPIAllocateBuffer function, MAPIAllocateMore function, MAPIFreeBuffer function, SPropValue structure, SRowSet structure


 IMAPISupport::CompareEntryIDs

[New - Windows 95]

Compares two entry identifiers to determine if they refer to the same service provider object.

Syntax

HRESULT CompareEntryIDs(ULONG cbEntryID1, LPENTRYID lpEntryID1, ULONG cbEntryID2, LPENTRYID lpEntryID2, ULONG ulFlags, ULONG FAR * lpulResult)

Parameters

cbEntryID1

Input parameter containing the number of bytes in the entry identifier pointed to by the lpEntryID1 parameter.

lpEntryID1

Input parameter pointing to the first entry identifier to be compared.

cbEntryID2

Input parameter containing the number of bytes in the entry identifier pointed to by the lpEntryID2 parameter.

lpEntryID2

Input parameter pointing to the second entry identifier to be compared.

ulFlags

Reserved; must be zero.

lpulResult

Output parameter pointing to a Boolean variable that receives the result of the comparison; this variable is TRUE if the two entry identifiers refer to the same object and FALSE otherwise.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_UNKNOWN_ENTRYID

The requested entry identifier does not exist.

Comments

Use the IMAPISupport::CompareEntryIDs method to compare two entry identifiers for a given service provider object and determine whether they refer to the same object. If the two entry identifiers refer to the same object, then CompareEntryIDs sets the lpulResult parameter to TRUE; if they refer to different objects, CompareEntryIDs sets lpulResult to FALSE.

CompareEntryIDs is useful because an object can have more than one valid entry identifier; such a situation can occur, for example, after a new version of a service provider is installed.

If CompareEntryIDs returns an error, the provider should make no assumptions about the comparison and should take the most conservative approach based on what your provider is trying to do. CompareEntryIDs can fail if, for example, no provider has registered for one of the entry identifiers. If your provider compares message-store entry identifiers when one or both of the stores has not yet opened, CompareEntryIDs returns the value MAPI_E_UNKNOWN_ENTRYID.


 IMAPISupport::CompleteMsg

[New - Windows 95]

Calls the MAPI spooler to complete message delivery processing. Used only by message store providers that are tightly coupled with transport providers.

Syntax

HRESULT CompleteMsg(ULONG ulFlags, ULONG cbEntryID, LPENTRYID lpEntryID)

Parameters

ulFlags

Reserved; must be zero.

cbEntryID

Input parameter containing the number of bytes in the entry identifier pointed to by the lpEntryID parameter.

lpEntryID

Input parameter pointing to the entry identifier of the message that needs to be delivered.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Message store providers use the IMAPISupport::CompleteMsg method to instruct the MAPI spooler to complete the post-processing of a message. CompleteMsg is available to all message store providers, but should only be called by those stores that are tightly coupled with transport providers, and even then only in the following circumstances:

•	When the message in question required preprocessing.

•	When the message store provider can handle all recipients, the transport provider the message store is coupled with can handle all recipients of this message without involving the MAPI spooler, and the MAPI spooler's transport order indicates that the transport can handle all of the recipients.


 IMAPISupport::CopyFolder

[New - Windows 95]

Copies or moves a folder to a destination folder.

Syntax

HRESULT CopyFolder(LPCIID lpSrcInterface, LPVOID lpSrcFolder, ULONG cbEntryID, LPENTRYID lpEntryID, LPCIID lpInterface, LPVOID lpDestFolder, LPSTR lpszNewFolderName, ULONG ulUIParam, LPMAPIPROGRESS lpProgress, ULONG ulFlags)

Parameters

lpSrcInterface

Input parameter pointing to the interface identifier of the source folder.

lpSrcFolder

Input parameter pointing to the source folder for the folder whose entry identifier is passed in the lpEntryID parameter.

cbEntryID

Input parameter containing the number of bytes in the entry identifier pointed to by the lpEntryID parameter.

lpEntryID

Input parameter pointing to the entry identifier of the folder to be copied or moved.

lpInterface

Reserved; must be NULL.

lpDestFolder

Input parameter pointing to the open destination folder where the folder identified in the lpEntryID parameter is to be copied or moved.

lpszNewFolderName

Input parameter pointing to a string containing the name to be given to the newly created or moved folder. If your message store provider passes NULL in the lpszNewFolderName parameter, the name of the newly created or moved folder is the same as the name of the original.

ulUIParam

Input parameter containing the handle of the window the dialog box is modal to. The ulUIParam parameter is ignored unless your provider sets the FOLDER_DIALOG flag in the ulFlags parameter and passes NULL in the lpProgress parameter.

lpProgress

Input parameter pointing to a progress object that contains client-supplied progress information. If NULL is passed in the lpProgress parameter, the progress information is provided by MAPI. The lpProgress parameter is ignored unless the FOLDER_DIALOG flag is set in the ulFlags parameter.

ulFlags

Input parameter containing a bitmask of flags used to control how the copy or move operation is accomplished. The following flags can be set:

COPY_SUBFOLDERS

Indicates that all subfolders are included in the copy operation. This is optional for copy operations and is implied for move operations.

FOLDER_DIALOG

Displays a progress-information user interface while the operation proceeds.

FOLDER_MOVE

Indicates that the folder is to be moved. If this flag is not set, the folder will be copied.

MAPI_UNICODE

Indicates the passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_COLLISION

The first folder being created as a result of the copy or move operation is the same as the source folder. The operation stops without completing.

MAPI_W_PARTIAL_COMPLETION

The call succeeded, but not everything was copied or moved.

Comments

Message store providers use the IMAPISupport::CopyFolder method to copy or move folders from one location to another. The folder being copied or moved is added to the destination folder as a subfolder; the destination folder can be in a message store other than that where the folder being copied or moved currently resides. Only one folder can be copied or moved at a time; messages contained in the copied or moved folder are not copied or moved at the same time as the folder.

CopyFolder allows simultaneous renaming and moving of folders and the copying or moving of the subfolders of the affected folder. To copy or move all subfolders nested within the copied or moved folder, your application passes the COPY_SUBFOLDERS flag in the ulFlags parameter.

To allow copy or move operations involving more than one folder to continue even if one or more folders specified for the operation do not exist or have already been moved elsewhere and thus cannot be copied or moved, a message store provider should attempt to complete the operation as best it can for each folder specified. The provider should stop the operation without completing it only in the case of failures it cannot control, such as running out of memory or disk space, message store corruption, and so on.

If CopyFolder successfully completes the copy or move operation for every folder , it returns the value S_OK. If one or more folders cannot be copied or moved, CopyFolder returns the value MAPI_W_PARTIAL_COMPLETION. If CopyFolder returns a different value, such as MAPI_E_NOT_ENOUGH_MEMORY, that indicates the call did not complete; it might already have copied or moved one or more folders without being able to continue. The calling application cannot function on the assumption that an error return implies that no work was done.

If an entry identifier for a folder that doesn't exist is passed in the lpEntryID parameter, CopyFolder returns MAPI_W_PARTIAL_COMPLETION.


 IMAPISupport::CopyMessages

[New - Windows 95]

Copies or moves messages from the current folder to another folder.

Syntax

HRESULT CopyMessages(LPCIID lpSrcInterface, LPVOID lpSrcFolder, LPENTRYLIST lpMsgList, LPCIID lpDestInterface, LPVOID lpDestFolder, ULONG ulUIParam, LPMAPIPROGRESS lpProgress, ULONG ulFlags)

Parameters

lpSrcInterface

Input parameter pointing to the interface identifier of the source folder from which messages are being copied or moved.

lpSrcFolder

Input parameter pointing to the source folder from which messages are being copied or moved.

lpMsgList

Input parameter pointing to an array of ENTRYLIST structures that identify the message or messages to be copied or moved.

lpDestInterface

Input parameter pointing to the interface identifier for the destination folder to which messages are being copied or moved.

lpDestFolder

Input parameter pointing to the open destination folder where the messages identified in the lpMsgList parameter are to be copied or moved.

ulUIParam

Input parameter containing the handle of the window that the dialog box is modal to. The ulUIParam parameter is ignored unless your provider sets the MESSAGE_DIALOG flag in the ulFlags parameter and passes NULL in the lpProgress parameter.

lpProgress

Input parameter pointing to a progress object that contains client- or provider-supplied progress information. If NULL is passed in the lpProgress parameter, the progress information is provided by MAPI. The lpProgress parameter is ignored unless the MESSAGE_DIALOG flag is set in the ulFlags parameter.

ulFlags

Input parameter containing a bitmask of flags used to control how the copy or move operation is accomplished. The following flags can be set:

MESSAGE_DIALOG

Displays a progress-information user interface as the operation proceeds.

MESSAGE_MOVE

Moves messages. If this flag is not set, the function copies messages.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_USER_CANCEL

The user canceled the operation, typically by clicking the Cancel button in a dialog box.

Comments

Message store providers use the IMAPISupport::CopyMessages method to call MAPI to move or copy messages from one folder to another as specified by the client application. As part of the CopyMessages call, the message store provider can specify that MAPI display a user interface showing progress information.


 IMAPISupport::CreateOneOff

[New - Windows 95]

Creates an entry identifier for a custom recipient.

Syntax

HRESULT CreateOneOff (LPTSTR lpszName, LPTSTR lpszAdrType, LPTSTR lpszAddress, ULONG ulFlags, ULONG FAR * lpcbEntryID, LPENTRYID FAR * lppEntryID)

Parameters

lpszName

Input parameter pointing to a string containing the display name of the recipient. lpszName can be NULL.

lpszAdrType

Input parameter pointing to a string containing the e-mail address type of the recipient; examples of e-mail address types are FAX, SMTP, X500, and so on. lpszAdrType cannot be NULL.

lpszAddress

Input parameter pointing to a string containing the e-mail address of the recipient. lpszAddress cannot be NULL.

ulFlags

Input parameter containing a bitmask of flags controlling the type of the passed-in strings. The following flag can be set:

MAPI_UNICODE

Indicates the passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

lpcbEntryID

Output parameter pointing to a variable in which the IMAPISupport::CreateOneOff method returns the number of bytes in the entry identifier pointed to by the lppEntryID parameter.

lppEntryID

Output parameter pointing to a variable where the pointer to the entry identifier of the custom recipient address that has been created is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Service providers use the IMAPISupport::CreateOneOff method to create an entry identifier for a custom recipient. A custom recipient is a message recipient that the user does not choose from an address book but specifies by typing in the recipient name. This entry identifier can be used as a valid recipient on a message.

When the provider is done using the entry identifier returned by CreateOneOff, it should free the allocated memory by using the MAPIFreeBuffer function.

See Also

MAPIFreeBuffer function


 IMAPISupport::Details

[New - Windows 95]

Displays a details dialog box on a particular entry in an address book.

Syntax

HRESULT Details(ULONG FAR * lpulUIParam, LPFNDISMISS lpfnDismiss, LPVOID lpvDismissContext, ULONG cbEntryID, LPENTRYID lpEntryID, LPFNBUTTON lpfButtonCallback, LPVOID lpvButtonContext, LPTSTR lpszButtonText, ULONG ulFlags)

Parameters

lpulUIParam

Output parameter containing the handle to the parent window for the dialog box.

lpfnDismiss

Input parameter pointing to the address of a function based on the DISMISSMODELESS function prototype that is called when the modeless variety of the details dialog box is dismissed.

lpvDismissContext

Input parameter that is passed to the function specified by the lpfnDismiss parameter.

cbEntryID

Input parameter containing the number of bytes in the lpEntryID parameter.

lpEntryID

Input parameter pointing to the entry identifier for which the object's details are displayed.

lpfButtonCallback

Input parameter pointing to a pointer to a button callback function that adds a button to a dialog box.

lpvButtonContext

Input parameter pointing to data used as a parameter for the button callback function pointed to by the lpfButtonCallback parameter.

lpszButtonText

Input parameter pointing to a string containing the text to be applied to the button mentioned previously if that button is extensible. The lpszButtonText parameter should be NULL if an extensible button is not needed.

ulFlags

Input parameter containing a bitmask of flags controlling the type of the text for lpszButtonText. The following flag can be set:

MAPI_UNICODE

Indicates the passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Providers use the IMAPISupport::Details methods to display a details dialog box on a particular entry in an address book. The lpfButtonCallback, lpvButtonContext, and lpButtonText parameters can be used to add a button it has defined to the addressing dialog box. When the button is chosen, MAPI calls the callback function pointed to by lpfButtonCallback, passing both the entry identifier of the chosen button and the data in lpvButtonContext. If an extensible button is not needed, lpszButtonText should be NULL.

The lpfnDismiss parameter is used to support the modeless version of the details address book. When the user dismisses the address book, MAPI calls IMAPISupport::Details. The dismiss function used with Details is based on the function prototype DISMISSMODELESS.

See Also

DISMISSMODELESS function prototype, IMAPISupport::Address method


 IMAPISupport::Details, LPFNBUTTON

[New - Windows 95]

The LPFNBUTTON function prototype represents a service provider callback function that MAPI calls to hook to an optional button control on an address book dialog box. This button is typically a Details button.

Syntax

SCODE (STDMETHODCALLTYPE FAR * LPFNBUTTON)(ULONG ulUIParam, LPVOID lpvContext, ULONG cbEntryID, LPENTRYID lpSelection, ULONG ulFlags)

Parameters

ulUIParam

Input parameter specifying an implementation-specific 32-bit value normally used for passing user interface information to a function. For example, in Microsoft Windows this parameter is the parent window handle for the dialog box and is of type HWND (cast to a ULONG). A value of zero is always valid.

lpvContext

Input parameter specifying a pointer to an arbitrary value passed to the callback function when MAPI calls it. This value can represent an address of significance to the client application. Typically, for C++ code, lpvContext represents a pointer to the address of a C++ object.

cbEntryID

Input parameter specifying the size, in bytes, of the identifier indicated by lpSelection.

lpSelection

Input parameter specifying a pointer to an ENTRYID structure defining the selection within the dialog box.

ulFlags

Reserved; must be zero.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

This hook function can be used by a service provider to define a button on the details dialog box. The provider passes a pointer to the callback function in calls to IMAPISupport::Details. When the dialog box is displayed and the user selects the defined button, MAPI calls this function.

See Also

ENTRYID structure, IMAPISupport::Details method


 IMAPISupport::DoConfigPropsheet

[New - Windows 95]

Enables service providers to display property sheets using MAPI's default user interface. Primarily used for configuration.

Syntax

HRESULT DoConfigPropsheet(ULONG ulUIParam, ULONG ulFlags, LPTSTR lpszTitle, LPMAPITABLE lpDisplayTable, LPMAPIPROP lpConfigData, ULONG ulTopPage)

Parameters

ulUIParam

Input parameter containing the handle of the window that the property sheets are modal to.

ulFlags

Reserved; must be zero.

lpszTitle

Input parameter pointing to the string that contains the title of the property-sheet dialog box.

lpDisplayTable

Input parameter pointing to the display table that contains information about the controls in the property sheet.

lpConfigData

Input parameter pointing to the property object containing the default values for the properties that are used to build the display table in the lpDisplayTable parameter.

ulTopPage

Input parameter containing a zero-based index to the default top page of the property sheet.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Service providers use the IMAPISupport::DoConfigPropSheet method to display configuration property sheets. DoConfigPropSheet can be called as part of the implementation of IMAPIStatus::SettingsDialog or from a button used to display details on properties. It can also be called from the entry point for a messaging service.

The display table that is passed in the lpDisplayTable parameter can be built using the BuildDisplayTable function, or using any other method convenient for the provider.

Microsoft strongly recommends that service providers use property sheets for their configuration user interface so that users can benefit from a consistent Windows interface.

See Also

BuildDisplayTable function, CreateIProp function, IABProvider::Logon method, IMAPIProp : IUnknown interface, IMAPIStatus::SettingsDialog method, IMsgServiceAdmin : IUnknown interface, IMSProvider::Logon method, IXPProvider::TransportLogon method


 IMAPISupport::DoCopyProps

[New - Windows 95]

Copies or moves a selected set of properties from the source object to a given destination object. (The source object is the object on which the call to the IMAPISupport::DoCopyProps method is made.)

Syntax

HRESULT DoCopyProps(LPCIID lpSrcInterface, LPVOID lpSrcObj, LPSPropTagArray lpIncludeProps, ULONG ulUIParam, LPMAPIPROGRESS lpProgress, LPCIID lpDestInterface, LPVOID lpDestObj, ULONG ulFlags, LPSPropProblemArray FAR * lppProblems)

Parameters

lpSrcInterface

Input parameter pointing to the interface identifier of the source object from which the properties are being copied or moved.

lpSrcObj

Input parameter pointing to the source object from which the properties are being copied or moved.

lpIncludeProps

Input parameter pointing to an SPropTagArray structure holding a counted array of property tags indicating the properties to be copied or moved. The lpIncludeProps parameter value cannot be NULL.

ulUIParam

Input parameter containing the handle of the window the progress-information user interface is modal to.

lpProgress

Input parameter pointing to a progress object that contains client- or provider-supplied progress information. If NULL is sent in the lpProgress parameter, the progress information is provided by MAPI. The lpProgress parameter is ignored unless the MAPI_DIALOG flag is set in the ulFlags parameter.

lpDestInterface

Input parameter pointing to the interface identifier for the destination object to which properties are being copied or moved.

lpDestObj

Input parameter pointing to the open destination object.

ulFlags

Input parameter containing a bitmask of flags used to control how the copy or move operation is to be performed. The following flags can be set:

MAPI_DIALOG

Displays a dialog box to provide status or prompt the user for additional information, such as recipients, sending options, or name resolution. If this flag is not set, no dialog box is displayed.

MAPI_MOVE

Indicates a move operation. The default operation is copying.

MAPI_NOREPLACE

Indicates that existing properties in the destination object should not be overwritten. The default action is to overwrite existing properties.

lppProblems

Output parameter pointing to a variable where the pointer to a SPropProblemArray structure is stored. If a value of NULL is passed in the lppProblems parameter, no property problem array is returned.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_DECLINE_COPY

Indicates that the provider has chosen not to implement the copy operation.

MAPI_E_COLLISION

A sibling folder in the destination object already has the name in the PR_DISPLAY_NAME property being copied from the source object.

MAPI_E_FOLDER_CYCLE

The source object directly or indirectly contains the destination object. Significant work might have been performed before this condition was discovered so the source and destination object might be partially modified.

MAPI_E_INTERFACE_NOT_SUPPORTED

An appropriate interface cannot be obtained.

MAPI_E_NO_ACCESS

An attempt to modify a read-only object or an attempt to access an object for which the user has insufficient permissions.

The following values can be returned in the SPropProblemArray structure, but not as a return value for DoCopyProps:

MAPI_E_BAD_CHARWIDTH

Either the MAPI_UNICODE flag was set and the implementation does not support Unicode, or MAPI_UNICODE was not set and the implementation only supports Unicode.

MAPI_E_COMPUTED

The property can't be written because it is computed by the destination object's provider. This is not a severe error; allow the process to continue.

MAPI_E_INVALID_TYPE

The property type is invalid.

MAPI_E_UNEXPECTED_TYPE

The type of the property value is not the type expected by the calling application.

Comments

Message store providers use the IMAPISupport::DoCopyProps method to copy or move to the destination object those properties designated in the SPropTagArray structure passed in the lpIncludeProps parameter that are present in the source object. When copying properties between like objects, for example between two message objects, the interface identifiers and the object types must be the same for both the source and the destination object. If any of the copied or moved properties already exist in the destination object, the existing properties are overwritten by the new, unless the MAPI_NOREPLACE flag is set in the ulFlags parameter. Existing information in the destination object that is not overwritten by copied or moved data is not deleted or modified.

For message objects, the PR_MESSAGE_RECIPIENTS and PR_MESSAGE_ATTACHMENTS properties can be included in the SPropTagArray structure passed in lpIncludeProps to permit copying or moving of message recipients and attachments, respectively. For folder objects, the PR_CONTAINER_HIERARCHY, PR_CONTAINER_CONTENTS, and PR_FOLDER_ASSOCIATED_CONTENTS properties can be included in the lpIncludeProps SPropTagArray structure to permit copying or moving of subfolders, messages, or associated objects from a source folder to a destination object. If subfolders are copied or moved, they are copied or moved in their entirety, regardless of the use of properties indicated by the SPropTagArray in the source object itself.

If the source object directly or indirectly contains the destination object, the overall call fails and returns the value MAPI_E_FOLDER_CYCLE. Some implementations, however, perform significant work before discovering this error and leave the source and destination objects partially modified, so applications should try to avoid such calls. If the same pointer is used for both the source and destination objects, MAPI_E_NO_ACCESS is returned.

The interface of the destination object, indicated in the lpInterface parameter, is usually exactly the same interface as that for the source object. If lpInterface is set to NULL, then the value MAPI_E_INVALID_PARAMETER is returned for DoCopyProps. If an acceptable interface is given in the lpInterface parameter but an invalid pointer is passed in the lpDestObj parameter, the results are unpredictable, with the most likely result being that the calling application stops.

If the MAPI_DIALOG flag is not set in the ulFlags parameter, then DoCopyProps ignores the ulUIParam and lpProgress parameters and no progress-information user interface is provided. If a client application sets the MAPI_DIALOG flag in the ulFlags parameter and passes a value of NULL in the lpProgress parameter, then the provider is responsible for generating a progress-information user interface. If a client application sets the MAPI_DIALOG flag in the ulFlags parameter and passes a progress object in the lpProgress parameter, the provider uses the information supplied by the progress object to display progress information.

If the call succeeds overall but there are problems with copying or moving some of the selected properties, the value S_OK is returned and an SPropProblemArray structure is returned in the lppProblems parameter. The SPropProblemArray structure contains details about each property problem. In some cases, a DoCopyProps call can successfully set some of the requested properties, but not others; in these cases, exactly which properties were not successfully copied or moved can be determined from the SPropProblemArray structure. If message recipients or attachments cannot be copied or moved, the PR_MESSAGE_RECIPIENTS or PR_MESSAGE_ATTACHMENTS property is returned in the SPropProblemArray structure.

The value returned in the lppProblems parameter is only valid if the call returns S_OK. When S_OK is returned, check the values returned in the SPropProblemArray structure. If an error occurs on the call, then the SPropProblemArray structure is not filled in; call IMAPISupport::GetLastError to get the MAPIERROR structure for the error.

The calling application must free the returned SPropProblemArray structure by calling the MAPIFreeBuffer function, but this should only be done if DoCopyProps returns with S_OK.

See Also

IMAPISupport::CopyMessages method, IMAPISupport::DoCopyTo method, SPropProblemArray structure, SPropTagArray structure


 IMAPISupport::DoCopyTo

[New - Windows 95]

Copies or moves all properties of the source object to a destination object, except for a given set of properties that are excluded from the copy or move operation. (The source object is the object on which the call to the IMAPISupport::DoCopyTo method is made.)

Syntax

HRESULT DoCopyTo(LPCIID lpSrcInterface, LPVOID lpSrcObj, ULONG ciidExclude, LPCIID rgiidExclude, LPSPropTagArray lpExcludeProps, ULONG ulUIParam, LPMAPIPROGRESS lpProgress, LPCIID lpDestInterface, LPVOID lpDestObj, ULONG ulFlags, LPSPropProblemArray FAR * lppProblems)

Parameters

lpSrcInterface

Input parameter pointing to the interface identifier of the source object from which properties and objects are being copied or moved.

lpSrcObj

Input parameter pointing to the source object from which the properties and objects are being copied or moved.

ciidExclude

Input parameter containing the number of interfaces to be excluded when copying or moving properties.

rgiidExclude

Input parameter containing an array of interface identifiers indicating interfaces that should not be used when copying or moving supplemental information to the destination object.

lpExcludeProps

Input parameter pointing to the SPropTagArray structure containing the property identifiers of the properties that should not be copied or moved to the destination object. Passing a value of NULL in the lpExcludeProps parameter indicates all properties are to be copied or moved. Passing zero in the cValues member of the lpExcludeProps SPropTagArray structure results in the value MAPI_E_INVALID_PARAMETER being returned.

ulUIParam

Input parameter containing the handle of the window the dialog box is modal to. In this case it is used to indicate the user interface where progress information is displayed.

lpProgress

Input parameter pointing to a progress object that contains client- or provider-supplied progress information. If NULL is sent in the lpProgress parameter, the progress information is provided by MAPI. The lpProgress parameter is ignored unless the MAPI_DIALOG flag is set in the ulFlags parameter.

lpInterface

Input parameter pointing to the interface identifier for the interface of the destination object to which properties are being copied.

lpDestObj

Input parameter pointing to the open destination object.

ulFlags

Input parameter containing a bitmask of flags used to control how the copy or move operation is to be performed. The following flags can be set:

MAPI_DECLINE_OK

Used by MAPI to limit recursion within MAPI's CopyTo implementation. Informs the provider that if it chooses not to implement IMAPISupport::DoCopyTo, that it should immediately return MAPI_E_DECLINE_COPY.

MAPI_DIALOG

Displays a user interface to provide progress information for the copy operation.

MAPI_MOVE

Indicates a move operation. The default operation is copying.

MAPI_NOREPLACE

Indicates that existing properties in the destination object should not be overwritten. The default action is to overwrite existing properties.

lppProblems

Output parameter pointing to a variable where the pointer to a SPropProblemArray structure is stored. If a value of NULL is passed in the lppProblems parameter, no property problem array is returned.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_DECLINE_COPY

Indicates that the provider has chosen not to implement the copy operation.

MAPI_E_COLLISION

A sibling folder in the destination object already has the name in the PR_DISPLAY_NAME property being copied from the source object.

MAPI_E_FOLDER_CYCLE

The source object directly or indirectly contains the destination object. Significant work might have been performed before this condition was discovered so the source and destination object might be partially modified.

MAPI_E_INTERFACE_NOT_SUPPORTED

An appropriate interface cannot be obtained.

MAPI_E_NO_ACCESS

An attempt to modify a read-only object or an attempt to access an object for which the user has insufficient permissions.

The following values can be returned in the SPropProblemArray structure, but not as a return value for DoCopyTo:

MAPI_E_BAD_CHARWIDTH

Either the MAPI_UNICODE flag was set and the implementation does not support Unicode, or MAPI_UNICODE was not set and the implementation only supports Unicode.

MAPI_E_COMPUTED

The property can't be written because it is computed by the destination object's provider. This is not a severe error; allow the process to continue.

MAPI_E_INVALID_TYPE

The property type is invalid.

MAPI_E_UNEXPECTED_TYPE

The type of the property value is not the type expected by the calling application.

Comments

Message store providers use the IMAPISupport::DoCopyTo method to copy or move all properties of the source object to the destination object, except for a given set of properties that are excluded from the copy or move operation. Any objects contained in the source object and any subobjects of the source object are included in the copy or move operation.

If any of the copied or moved properties already exist in the destination object, the existing properties are overwritten by the new, unless the MAPI_NOREPLACE flag is set in the ulFlags parameter. Existing information in the destination object that is not overwritten by copied or moved data is not deleted or modified.

To exclude some properties from the copy or move operation, pass their property identifiers in the lpExcludeProps parameter. Passing in a specific value causes any property in the source object whose identifier matches that value to be excluded from being copied or moved to the destination object. For example, passing in a value of PROP_TAG(PT_LONG, 0x8002) excludes both the properties PROP_TAG(PT_STRING8, 0x8002) and PROP_TAG(PT_OBJECT, 0x8002).

For message objects, the PR_MESSAGE_RECIPIENTS and PR_MESSAGE_ATTACHMENTS properties can be included in the SPropTagArray structure passed in lpExcludeProps to prevent copying or moving message recipients and attachments, respectively. For folder objects, the PR_CONTAINER_HIERARCHY, PR_CONTAINER_CONTENTS, and PR_FOLDER_ASSOCIATED_CONTENTS properties can be included in the lpExcludeProps SPropTagArray structure to prevent copying or moving of subfolders, messages, or associated objects from the source folder to the destination object. If subfolders are copied or moved, they are copied or moved in their entirety, regardless of the use of properties indicated by the SPropTagArray in the source object itself.

Providers implementing DoCopyTo should not attempt to set any known read-only properties in the destination object and should ignore MAPI_E_COMPUTED errors returned in the SPropProblemArray structure.

If the source object directly or indirectly contains the destination object, the overall call fails and returns the value MAPI_E_FOLDER_CYCLE. Some implementations, however, perform significant work before discovering this error and leave the source and destination objects partially modified, so applications should try to avoid such calls. If the same pointer is used for both the source and destination objects, MAPI_E_NO_ACCESS is returned.

The interface of the destination object, indicated in the lpInterface parameter, is usually exactly the same interface as that for the source object. If lpInterface is set to NULL, then the value MAPI_E_INVALID_PARAMETER is returned for DoCopyTo. If an acceptable interface is given in the lpInterface parameter but an invalid pointer is passed in the lpDestObj parameter, the results are unpredictable, with the most likely result being that the calling application stops.

Some objects contain supplemental information beyond that, which can be accessed with the interface pointer in the lpInterface parameter. To copy or move such information, a provider's IMAPISupport::DoCopyTo implementation first uses IUnknown::QueryInterface on the destination object to see if it can accept the extra data. Conversely, if the calling application is aware of supplemental information and requires that DoCopyTo not copy or move it, the application can specify in the array passed in the rgiidExclude parameter interface identifiers for the properties that DoCopyTo should not copy or move. For example, if the application wants to copy messages, but not embedded objects within the messages, it can pass IID_IMessage in the exclude array. DoCopyTo ignores any interfaces listed in rgiidExclude that it doesn't recognize.

Note  When you use the rgiidExclude parameter to exclude an interface, you also exclude all interfaces derived from that interface. For example, excluding IMAPIProp also excludes IMAPIFolder, IMessage, IAttach, and so on. If all known interfaces are excluded, DoCopyTo returns the error value MAPI_E_INTERFACE_NOT_SUPPORTED. For that reason, you should not pass IID_IUnknown or IID_IMAPIProp in rgiidExclude.

If the MAPI_DIALOG flag is not set in the ulFlags parameter, then DoCopyTo ignores the ulUIParam and lpProgress parameters and no progress-information user interface is provided. If a client application sets the MAPI_DIALOG flag in the ulFlags parameter and passes a value of NULL in the lpProgress parameter, then the provider is responsible for generating a progress-information user interface. If a client application sets the MAPI_DIALOG flag in the ulFlags parameter and passes a progress object in the lpProgress parameter, the provider uses the information supplied by the progress object to display progress information.

If the call succeeds overall but there are problems with copying or moving some of the selected properties, the value S_OK is returned and an SPropProblemArray structure is returned in the lppProblems parameter. The SPropProblemArray structure contains details about each property problem. In some cases, a DoCopyTo call can successfully set some of the requested properties, but not others; in these cases, exactly which properties were not successfully copied or moved can be determined from the SPropProblemArray structure. If message recipients or attachments cannot be copied or moved, the PR_MESSAGE_RECIPIENTS or PR_MESSAGE_ATTACHMENTS property is returned in the SPropProblemArray structure.

The value returned in the lppProblems parameter is only valid if the call returns S_OK. When S_OK is returned, check the values returned in the SPropProblemArray structure. If an error occurs on the call, then the SPropProblemArray structure is not filled in; call IMAPISupport::GetLastError to get the MAPIERROR structure for the error.

If an error occurs on the DoCopyTo call, do not use or free the SPropProblemArray structure. Applications should ignore the ulIndex member in property problem sets returned by DoCopyTo.

The calling application must free the returned SPropProblemArray structure by calling the MAPIFreeBuffer function, but this should only be done if DoCopyTo returns with S_OK.

See Also

IMAPISupport::CopyFolder method, IMAPISupport::CopyMessages method, SPropProblemArray structure, SPropTagArray structure


 IMAPISupport::DoProgressDialog

[New - Windows 95]

Provides a default implementation of the IMAPIProgress interface for use by service providers.

Syntax

HRESULT DoProgressDialog(ULONG ulUIParam, ULONG ulFlags, LPMAPIPROGRESS FAR * lppProgress)

Parameters

ulUIParam

Input parameter containing the handle of the window the dialog box is modal to.

ulFlags

Input parameter containing a bitmask of flags indicating how progress information is to be calculated. The following flag can be set:

MAPI_TOP_LEVEL

Uses the values in the IMAPIProgress::Progress method's ulCount (the item being operated on) and ulTotal (total items to operate on) parameters to increment progress being made on the operation. For example, if you were copying a folder that contained 10 subfolders and the MAPI_TOP_LEVEL flag is set in the lpulFlags parameter, progress will increment for each subfolder copied: 1 of 10, 2 of 10, 3 of 10, and so on.

lppProgress

Output parameter pointing to a variable where the pointer to the progress object is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Message store providers use the IMAPISupport::DoProgressDialog method in concert with the methods of the IMAPIProgress interface to calculate progress information and display the result in a user interface when requested to do so by a client application. A pointer to a progress object supporting the IMAPIProgress interface is returned in the lppProgress parameter.

See Also

IMAPIProgress : IUnknown interface


 IMAPISupport::DoSentMail

[New - Windows 95]

Generates a sentmail message for an open message. This method is only valid when called from within the MAPI spooler's process.

Syntax

HRESULT DoSentMail(ULONG ulFlags, LPMESSAGE lpMessage)

Parameters

ulFlags

Reserved; must be zero.

lpMessage

Input parameter pointing to the open message for which a sent-mail message should be generated.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Message store providers call the IMAPISupport::DoSentMail method as part of the implementation of the IMsgStore::FinishedMsg method. FinishedMsg is called by the MAPI spooler when it has finished processing the message. DoSentMail should be one of the last lines of code in a message store's FinishedMsg implementation. FinishedMsg should unlock the message and only have one reference count to the message when this DoSentMail call is made. After DoSentMail returns, the message will have been fully released.

The MAPI spooler's implementation of DoSentMail does the following:

•	Determines whether the message is to be deleted after sending by checking the message for the PR_DELETE_AFTER_SUBMIT property.

•	Determines the location of the sent-mail folder.

•	Initiates message hook processing for any hooks set on the sent-mail folder.

•	Moves the message to the sent-mail folder, deleted-items folder, or to another folder as specified by any message hooks.

•	Releases the message.

See Also

IMsgStore::FinishedMsg method


 IMAPISupport::ExpandRecips

[New - Windows 95]

Completes all recipient lists and expands certain distribution lists for the transmission of a message.

Syntax

HRESULT ExpandRecips(LPMESSAGE lpMessage, ULONG FAR * lpulFlags)

Parameters

lpMessage

Input parameter pointing to an open message object that has read-write access.

lpulFlags

Output parameter pointing to a variable that receives a bitmask of flags controlling what occurs after recipient entries are resolved. The following flag can be set:

NEEDS_PREPROCESSING

Indicates the message needs preprocessing before sending.

NEEDS_SPOOLER

Indicates that the messages store should have the MAPI spooler send the message rather than the message store's tightly coupled transport.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Message store providers use the IMAPISupport::ExpandRecips method to prompt MAPI to resolve all recipient entries and distribution lists in the recipient list for a particular message. The process of completing recipient entries and distribution lists involves expanding certain personal distribution lists to their component recipients, replacing all changed display names (for example, names that have been altered) with the original names, marking any duplicate entries, and resolving all custom recipient addresses. ExpandRecips expands any distribution lists that have the e-mail address type of MAPIPDL.

After MAPI reads and updates the recipient list for the message indicated in the lpMessage parameter, MAPI checks to see if the message needs preprocessing, and if it does, sets the NEEDS_PREPROCESSING flag and returns it in the lpulFlags parameter.

Message store providers should always call ExpandRecips as part of processing a message, and it should be one of the first calls made as part of a provider's IMessage::SubmitMessage implementation.

See Also

IMessage::SubmitMessage method


 IMAPISupport::GetLastError

[New - Windows 95]

Returns a MAPIERROR structure containing information about the last error that occurred for the support object.

Syntax

HRESULT GetLastError(HRESULT hResult, ULONG ulFlags, LPMAPIERROR FAR * lppMAPIError)

Parameters

hResult

Input parameter containing the result returned for the last call on the session object that returned an error.

ulFlags

Input parameter containing a bitmask of flags controlling the type of the returned strings. The following flag can be set:

MAPI_UNICODE

Indicates the strings returned in the MAPIERROR structure returned in the lppMAPIError parameter are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

lppMAPIError

Output parameter pointing to a pointer to the returned MAPIERROR structure containing version, component, and context information for the error. The lppMAPIError parameter can be set to NULL if there is no MAPIERROR structure to return.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_BAD_CHARWIDTH

Either the MAPI_UNICODE flag was set and the implementation does not support Unicode, or MAPI_UNICODE was not set and the implementation only supports Unicode.

Comments

Use the IMAPISupport::GetLastError method to retrieve information to display as a message to the user regarding the last error returned from a method call on the support object.

To release all the memory allocated by MAPI, providers need only call the MAPIFreeBuffer function for the MAPIERROR structure.

The return value from GetLastError must be S_OK for the provider to make use of the MAPIERROR structure. Even if the return value is S_OK, it is still possible that a MAPIERROR structure won't be returned. If the implementation cannot determine what the last error was, or if a MAPIERROR structure is not available for that error, a pointer to NULL is returned in the lppMAPIError parameter instead.

See Also

MAPIERROR structure, MAPIFreeBuffer function


 IMAPISupport::GetMemAllocRoutines

[New - Windows 95]

Retrieves the addresses of the three MAPI memory allocation functions, MAPIAllocateBuffer, MAPIAllocateMore, and MAPIFreeBuffer.

Syntax

HRESULT GetMemAllocRoutines(LPALLOCATEBUFFER FAR * lppAllocateBuffer, LPALLOCATEMORE FAR * lppAllocateMore, LPFREEBUFFER FAR * lppFreeBuffer)

Parameters

lppAllocateBuffer

Output parameter pointing to a variable where the pointer to the MAPIAllocateBuffer function is stored.

lppAllocateMore

Output parameter pointing to a variable where the pointer to the MAPIAllocateMore function is stored.

lppFreeBuffer

Output parameter pointing to a variable where the pointer to the MAPIFreeBuffer function is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Service providers use the IMAPISupport::GetMemAllocRoutines method to get the addresses of the three memory allocation functions passed in on your provider's initialization call. For the syntax of each function, see its reference entry.

See Also

MAPIAllocateBuffer function, MAPIAllocateMore function, MAPIFreeBuffer function


 IMAPISupport::GetOneOffTable

[New - Windows 95]

Returns the table of custom recipient address templates that can be created onto a message.

Syntax

HRESULT GetOneOffTable(ULONG ulFlags, LPMAPITABLE FAR * lppTable)

Parameters

ulFlags

Input parameter containing a bitmask of flags controlling the format of returned data. The following flag can be set:

MAPI_UNICODE

Indicates the returned strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

lppTable

Output parameter pointing to a variable where the pointer to the returned table object is stored. The table contains a complete list of all custom recipient addresses supported within the current MAPI session..

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Address book providers use the IMAPISupport::GetOneOffTable method to retrieve the list of available new custom recipient addresses (also called one-off addresses) relevant to the current MAPI session. A custom recipient address, which is typed by the user, can be used once to send an individual message. Providers use the returned custom recipient table to identify the kinds of entries that can be added to their address book container.

The five property columns required in a table of custom recipients are as follows:

PR_DISPLAY_NAME

Indicates the custom template name, such as Microsoft Fax Template or Internet Form.

PR_ENTRYID

Indicates the entry identifier used to identify a particular template.

PR_DEPTH

Indicates how to indent the display name of the template; its value is a LONG that is zero-based, with zero meaning no indentation.

PR_SELECTABLE

A bitmask of selection flags indicating how the entry can be used.

PR_ADDRTYPE

Indicates the custom recipient address types that are added to your provider's custom recipient table.

Setting the MAPI_UNICODE flag in the ulFlags parameter does the following:

•	Sets the string type to Unicode for data returned for the initial active columns of the custom recipient table by the IMAPITable::QueryColumns method. The initial active columns for a custom recipient table are those columns the QueryColumns method returns before the application that contains the custom recipient table calls the IMAPITable::SetColumns method.

•	Sets the string type to Unicode for data returned for the initial active rows of the custom recipient table by the IMAPITable::QueryRows method. The initial active rows for a custom recipient table are those rows QueryRows returns before the application that contains the custom recipient table calls the IMAPITable::SetColumns method.

•	Controls the property types of the sort order specification returned by the IMAPITable::QuerySortOrder method before the application that contains the custom recipient table calls the IMAPITable::SortTable method.

If your provider registers for notification of changes to its custom recipient table, it will also receive notifications of changes made to other provider's custom recipient tables. Your provider can then support new address types that are added during the current session

See Also

IABContainer::CreateEntry method, IMAPISupport::NewEntry method, PR_CREATE_TEMPLATES property


 IMAPISupport::GetSvcConfigSupportObj

[New - Windows 95]

Creates a new support object for use by calls to a messaging service provider's configuration entry point function.

Syntax

HRESULT GetSvcConfigSupportObj(ULONG ulFlags, LPMAPISUP FAR * lppSvcSupport)

Parameters

ulFlags

Reserved; must be zero.

lppSvcSupport

Output parameter pointing to a pointer to the newly created support object.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Use the IMAPISupport::GetSvcConfigSupportObj method to acquire a pointer to a support object that can be used for a messaging service's implementation of the MSGSERVICEENTRY function prototype. An entry point function based on MSGSERVICEENTRY is called by methods of the IMsgServiceAdmin interface and allows messaging services to configure themselves or perform other actions when an application changes the profile. The primary action of such a function is to furnish a dialog box in which the user can change messaging service settings. A MSGSERVICEENTRY-based function can also support configuration by a client application through a property value array passed through the IMsgServiceAdmin::ConfigureMsgService method.

See Also

IMsgServiceAdmin::CreateMsgService method, IProfAdmin : IUnknown interface, MSGSERVICEENTRY function prototype


 IMAPISupport::IStorageFromStream

[New - Windows 95]

Implements an IStorage object on an IStream object.

Syntax

HRESULT IStorageFromStream(LPUNKNOWN lpUnkIn, LPCIID lpInterface, ULONG ulFlags, LPSTORAGE FAR * lppStorageOut)

Parameters

lpUnkIn

Input parameter pointing to the IUnknown object for the object that implements the stream object.

lpInterface

Input parameter pointing to the interface identifier for the object that implements the stream object. Any of the following values can be passed in the lpInterface parameter: NULL, &IID_IStream, or &IID_ILockBytes. Passing NULL in lpInterface is the same as passing &IID_IStream.

ulFlags

Input parameter containing a bitmask of flags controlling how the storage is to be created relative to the stream; the default is that the storage has read access and occurs within the stream starting at position zero. The following flags can be set:

STGSTRM_CREATE

Creates a new storage for the stream object.

STGSTRM_CURRENT

Starts storage at the current position of the stream.

STGSTRM_MODIFY

Allows the calling implementation to write to the returned storage.

STGSTRM_RESET

Starts storage at position zero.

lppStorageOut

Output parameter pointing to a variable where the pointer to the returned IStorage object is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Providers that don't implement the OLE IStorage interface themselves use the IMAPISupport::IStorageFromStream method to implement IStorage. IStorage must be implemented by any message store that supports streams to hold binary properties, because MAPI guarantees client applications that such message stores support IStorage to store these binary properties.

When handling a call from the IMAPIProp::OpenProperty method to open an IStorage interface on a property, as indicated by an interface identifier of IID_ISTORAGE having been passed, the provider first opens an OLE stream object with read-write access for the property, then internally marks the property stream as an IStorage object, generates an IStorage interface from the support function, and returns the MAPI-generated IStorage interface to the calling application.

A newly created IStorage object returned by IStorageFromStream calls the IUnknown::AddRef method to add a reference for the stream to the stream reference count, then releases the reference when the storage is released. Providers that support interfaces in addition to IStorage (for instance, an administrative interface for all object properties) must wrap the IStorage object returned by IStorageFromStream using their own IUnknown::QueryInterface method.

Message store providers should not allow a property to be opened as a stream with IMAPIProp::OpenProperty calls if it was created using IStorage. With one exception, message stores can use IID_IStreamDocfile to stream an IStorage object from one container to another, but they must pass IID_IStreamDocfile in the OpenProperty method's lpInterface parameter. Messages store providers should also not allow a property to be opened as a storage object if it was created using the OLE IStream interface.

For more information on OLE programming, see Inside OLE, Second Edition, by Kraig Brockschmidt, and OLE Programmer's Reference, Volume One and Volume Two.

See Also

IMAPIProp::OpenProperty method


 IMAPISupport::MakeInvalid

[New - Windows 95]

Invalidates an object derived from the IUnknown interface.

Syntax

HRESULT MakeInvalid(ULONG ulFlags, LPVOID lpObject, ULONG ulRefCount, ULONG cMethods)

Parameters

ulFlags

Reserved; must be zero.

lpObject

Input parameter pointing to the object to be invalidated. Its interface must be derived from IUnknown.

ulRefCount

Input parameter indicating the object's present reference count.

cMethods

Input parameter indicating the number of methods in the object's vtable (that is, the table used for dispatching calls to object methods).

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Service providers use the IMAPISupport::MakeInvalid method to invalidate an object, typically when a provider is shutting down. But a provider can call MakeInvalid at any time; for instance, if a client application releases an object without releasing some of its subobjects, a provider can call MakeInvalid immediately to release those subobjects. The object to be invalidated must be derived from the IUnknown interface or from an interface derived from IUnknown.

Note  Your application must own any object it attempts to invalidate with MakeInvalid. In addition, it must update the cMethods parameter if it changes the number of methods in the vtable for the object to be invalidated, as is the usual result of a MakeInvalid call.

The object passed to MakeInvalid must have been allocated by using the MAPIAllocateBuffer function and must be at least 16 bytes long. The number of methods for the object, as indicated in cMethods, must be at least 3 and should not be more than 2000.

MAPI handles calls to MakeInvalid by replacing the object's vtable with a stub vtable of similar size, in which the IUnknown::AddRef and IUnknown::Release methods perform as expected but any other methods fail, returning the value MAPI_E_INVALID_OBJECT.

Providers can call MakeInvalid and then perform any shutdown work, such as discarding associated data structures, that it would normally do if it were to release the object. Code to support the object does not need to be kept in memory because MAPI frees the memory by calling MAPIFreeBuffer and then releases the object. Providers can release their resources, call MakeInvalid, and then forget about the invalidated object. Client applications are required to release any memory associated with the object.

See Also

MAPIAllocateBuffer function


 IMAPISupport::ModifyProfile

[New - Windows 95]

Makes a message store provider's profile section permanent.

Syntax

HRESULT ModifyProfile(ULONG ulFlags)

Parameters

ulFlags

Input parameter containing a bitmask of flags controlling how the store logs onto the profile. The following flags can be set:

MDB_TEMPORARY

Advises MAPI that the store is temporary and should not be added to the message stores information table. S_OK is returned immediately.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Message store providers use the IMAPISupport::ModifyProfile method to prompt MAPI to modify their profile information. When a message store provider calls IMAPISupport::ModifyProfile, MAPI adds the profile section associated with that provider resource to the list of installed message-store provider resources MAPI's doing so causes the message store resource to be listed in the table returned by a call to the IMAPISession::GetMsgStoresTable method and makes it possible to open the resource without displaying a dialog box. If the MDB_TEMPORARY flag is set, MAPI does nothing and the method returns with S_OK immediately.

See Also

IMAPISession::GetMsgStoresTable method


 IMAPISupport::ModifyStatusRow

[New - Windows 95]

Creates the status table column values for the service providers.

Syntax

HRESULT ModifyStatusRow(ULONG cValues, LPSPropValue lpColumnVals, ULONG ulFlags)

Parameters

cValues

Input parameter containing the number of columns in the status row to be passed to MAPI.

lpColumnVals

Input parameter pointing to an SPropValue structure containing the property values used to define the columns in the status row to be passed to MAPI.

ulFlags

Input parameter containing a bitmask of flags controlling how information defining the status row is to be processed. The following flag can be set:

STATUSROW_UPDATE

Directs MAPI to merge the service providers' status information.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Service providers call the IMAPISupport::ModifyStatusRow method to enter a row in the status table at logon. Providers should call IMAPISupport::ModifyStatusRow during their logon process. The STATUSROW_UPDATE flag should be set with each subsequent ModifyStatusRow call. Doing so informs MAPI that only the columns being changed are passed in the lpColumnVals parameter.

ModifyStatusRow provides MAPI with the information necessary to build the initial status table. During ModifyStatusRow processing, MAPI copies the data in the lpColumnVals parameter defining status table columns and from this data creates the status table. MAPI requires service providers to pass the following column values in the lpColumnVals parameter:

•	PR_PROVIDER_DISPLAY

•	PR_RESOURCE_METHODS

•	PR_STATUS_CODE

The following column values are required if the service provider lists its user identity in the status table:

•	PR_IDENTITY_ENTRYID

•	PR_IDENTITY_DISPLAY

•	PR_IDENTITY_SEARCH_KEY

The following column values are provided by the messaging subsystem; the provider should not pass them in lpColumnVals:

•	PR_ENTRYID

•	PR_OBJECT_TYPE

•	PR_PROVIDER_DLL_NAME

•	PR_RESOURCE_FLAGS

•	PR_RESOURCE_TYPE

•	PR_ROWID

The following optional column values can be passed by service providers in lpColumnVals:

•	PR_DISPLAY_NAME

•	PR_STATUS_STRING

Although not required, the values for PR_DISPLAY_NAME and PR_STATUS_STRING are computed by MAPI if they are not provided by service providers.

MAPI displays all these properties in the status table, and applications can retrieve them by opening the provider's status object.


 IMAPISupport::NewEntry

[New - Windows 95]

Displays a dialog box for creating new entries within containers or custom recipient addresses within messages.

Syntax

HRESULT NewEntry(ULONG ulUIParam, ULONG ulFlags, ULONG cbEIDContainer, LPENTRYID lpEIDContainer, ULONG cbEIDNewEntryTpl, LPENTRYID lpEIDNewEntryTpl, ULONG FAR * lpcbEIDNewEntry, LPENTRYID FAR * lppEIDNewEntry)

Parameters

ulUIParam

Input parameter containing the handle to the window that the dialog box is modal to.

ulFlags

Reserved; must be zero.

cbEIDContainer

Input parameter containing the number of bytes in the entry identifier in the lpEIDContainer parameter.

lpEIDContainer

Input parameter pointing to the container where the new custom recipient address will be added. If the value in cbEIDContainer is zero, NewEntry returns a recipient entry identifier and a list of templates as if your provider called IMAPISupport::CreateOneOff.

cbEIDNewEntryTpl

Input parameter containing the number of bytes in the entry identifier in the lpEIDNewEntryTpl parameter.

lpEIDNewEntryTpl

Input parameter pointing to a template to be used to create the new custom recipient address. If the value in cbEIDNewEntryTpl is zero, passing NULL in the lpEIDNewEntryTpl parameter displays a dialog box enabling the user to select an address-creation template from among the address types that can be created in the container.

lpcbEIDNewEntry

Output parameter pointing to a variable containing the number of bytes in the entry identifier in the lppEIDNewEntry parameter.

lppEIDNewEntry

Output parameter pointing to a variable where the pointer to the entry identifier for the new custom recipient address is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

The IMAPISupport::NewEntry method can be used in several different modes. To add a custom recipient address directly to the open message and not to a modifiable container, your provider passes zero in the cbEIDContainer parameter and NULL in the lpEIDContainer parameter. To display a dialog box enabling the user to select a template for adding custom recipients to a modifiable container, your provider passes zero in the cbEIDNewEntryTpl parameter and NULL in the lpEIDNewEntryTpl parameter.

To create an entry in a modifiable address book and not get the entry identifier back, pass the container's entry identifier in the lpEIDContainer, zero in cbEIDContainer, and NULL for the rest of the parameters.

To open a specific custom-recipient dialog box directly, so that users enter custom recipients in their personal address books using a predetermined template, your provider uses the following series of calls. First, it calls the IMAPISupport::OpenEntry method and passes in either the entry identifier of a modifiable container or zero. Doing so opens the root folder of the address book container. Next, your provider calls the IABContainer::OpenProperty method and passes the PR_CREATE_TEMPLATES property in the ulPropTag parameter so that it can open the property. Doing this returns a table object that lists the types of objects that can be created in the address book container. Your provider finds in this table the entry identifier for the template you want new entries to be created with. Then, your provider calls NewEntry and passes NULL in the lpEIDContainer parameter and the entry identifier for the entry-creation template you want used in the lpEIDNewEntryTpl parameter.

Calls made to NewEntry return the entry identifier of the new custom recipient address in the lppEIDNewEntry parameter (unless your provider passed NULL in lppEIDNewEntry). Your provider is responsible for freeing the returned entry identifier by calling the MAPIFreeBuffer function.

See Also

IMAPIProp::OpenProperty method, IMAPISupport::OpenEntry method, PR_CREATE_TEMPLATES property


 IMAPISupport::NewUID

[New - Windows 95]

Returns a new, unique MAPI identifier (a MAPIUID) for an item.

Syntax

HRESULT NewUID(LPMAPIUID lpMuid)

Parameters

lpMuid

Points to the 16 bytes of memory where the new MAPIUID structure will be placed.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Service providers use the IMAPISupport::NewUID method in a wide variety of situations where they need to generate a long-term unique tag for an item. A message store provider, for instance, might call NewUID to obtain a unique identifier to place in the PR_SEARCH_KEY property of a newly created message to enable searching within tables.

Each service provider has its own MAPIUID, which is used to distinguish entry identifiers created by that provider. When you create your provider, you should choose a MAPIUID for your provider and hard-code it, as opposed to obtaining it from NewUID during provider initialization. By doing so, you ensure your provider will have the same MAPIUID on all systems. Use the UUIDGEN.EXE utility program to generate the MAPIUID.

See Also

MAPIUID structure


 IMAPISupport::Notify

[New - Windows 95]

Notifies interested applications about changes to an object that the provider owns.

Syntax

HRESULT Notify(LPNOTIFKEY lpKey, ULONG cNotification, LPNOTIFICATION lpNotifications, ULONG FAR * lpulFlags)

Parameters

lpKey

Input parameter pointing to a key for the object for which notification status is reported. The lpKey parameter provides a unique key to the object and cannot be NULL.

cNotification

Input parameter containing the number of notifications in the lpNotifications parameter.

lpNotifications

Input parameter pointing to an array of NOTIFICATION structures holding notifications to be broadcast.

lpulFlags

Input-output parameter containing a bitmask of flags used to control the notification. On input, the following flag can be set by the provider:

MAPI_UNICODE

Indicates the passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

On output, the following flag can be set by the MAPI notification engine:

NOTIFY_CANCELED

Indicates a callback function canceled a synchronous notification.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Service providers use the IMAPISupport::Notify method to call MAPI's notification engine. The notification engine is responsible for copying the structures indicated by the lpNotifications parameter into memory that is accessible to the process that requires notifications before calling the callback function that broadcasts the notifications, and for releasing that memory. The provider calling Notify does not need to allocate memory; MAPI performs all necessary memory allocation.

Providers can use only the notification events and event structures defined by MAPI; to support a custom notification event that does not fit easily into the other structures defined by MAPI, a provider can use an event of the fnevExtended type. For more information on the event types that can be used to trigger notifications, see the reference entry for the NOTIFICATION structure.

The notification key passed for the object whose notification status is reported in Notify's lpKey parameter should be the same as the key formerly passed for that object in the lpKey of the IMAPISupport::Subscribe method that set up notification subscription. This key is similar to PR_RECORD_KEY in that it is binary-comparable and can be used to ensure that the correct object is used. The notification engine uses this key to find the objects that are registered for notifications about the identified object.

Many notification structures include the entry identifier of the object receiving notifications; providers should be careful to pass the long-term entry identifier for this object to provide an entry identifier useful to all applications registered for notifications.

When a provider instructs the notification engine to broadcast a notification held in an ERROR_NOTIFICATION or NEWMAIL_NOTIFICATION structure and the error or new message string indicated by the structure is in Unicode format, the provider must set the MAPI_UNICODE flag in the ulFlags member of the NOTIFICATION structure. If in such a case the error or new message string is in 8-bit format, the provider should not set MAPI_UNICODE. The MAPI_UNICODE flag only applies to the strings within the notification structures.

For asynchronous notifications, Notify returns before the callback functions are made to the application registered for notifications. For synchronous notifications, Notify makes the callbacks before returning so the calling implementation can determine whether a process is active by checking whether the NOTIFY_CANCELED flag is set. If any callback function has returned CALLBACK_DISCONTINUE, the MAPI notification engine stops sending notifications and returns NOTIFY_CANCELED in the Notify method's lpulFlags parameter. Providers can then stop making notifications for that process. If zero is returned in lpulFlags, the process is still active and the provider should continue to send notifications as appropriate.

Providers using synchronous notifications must be careful to avoid deadlock situations.

See Also

IMAPISupport::Subscribe method, IMAPISupport::UnSubscribe method, NOTIFICATION structure, NOTIFKEY structure, PR_RECORD_KEY property


 IMAPISupport::OpenAddressBook

[New - Windows 95]

Opens the address book and returns a pointer that provides further access.

Syntax

HRESULT OpenAddressBook(LPCIID lpInterface, ULONG ulFlags, LPADRBOOK FAR * lppAdrBook)

Parameters

lpInterface

Input parameter pointing to the interface identifier for the address book. Passing NULL in the lpInterface parameter indicates that the return value is cast to the standard interface for the address book. The lpInterface parameter can also be set to an IID_IAddrBook.

ulFlags

Reserved; must be zero.

lppAdrBook

Output parameter pointing to a pointer to the returned address book object.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_W_ERRORS_RETURNED

The call succeeded, but one or more of the address book providers could not be loaded. Use the HR_FAILED macro to test for this warning, although the call should be handled as a successful return.

Comments

Tightly coupled message store and transport providers use the IMAPISupport::OpenAddressBook method to get access to an address book. The returned pointer to the address book can then be used to open address book containers, find messaging users, and display addressing dialog boxes.

This method can return MAPI_W_ERRORS_RETURNED if it cannot load an address book provider. This is a warning, not an error, and should be handled as a successful return. Even if all of the address book providers failed to load, OpenAddressBook succeeds and returns MAPI_W_ERRORS_RETURNED and an address book object in the lppAdrBook parameter. Even when no address book providers are loaded, your provider can still use the IAddrBook interface, and must release it when done.

Your provider can call the IMAPISupport::GetLastError method on the support object to obtain a MAPIERROR structure containing information about the address book providers that failed to load. If more than one provider failed to load, a single MAPIERROR structure is returned that contains an aggregation of the strings returned by each provider.

See Also

IAddrBook : IMAPIProp interface, IMAPISession::OpenAddressBook method


 IMAPISupport::OpenEntry

[New - Windows 95]

Opens an object given its entry identifier.

Syntax

HRESULT OpenEntry(ULONG cbEntryID, LPENTRYID lpEntryID, LPCIID lpInterface, ULONG ulOpenFlags, ULONG FAR * lpulObjType, LPUNKNOWN FAR * lppUnk)

Parameters

cbEntryID

Input parameter containing the number of bytes in the entry identifier pointed to by the lpEntryID parameter.

lpEntryID

Input parameter pointing to the entry identifier of the object to be opened.

lpInterface

Input parameter pointing to the interface identifier for the indicated object. Passing NULL in the lpInterface parameter indicates that the return value is cast to the standard interface for the indicated object.

ulOpenFlags

Input parameter containing a bitmask of flags used to control how the object is opened. The following flags can be set:

MAPI_BEST_ACCESS

Indicates the object should be opened with the maximum privileges allowed to the user. For example, if the client application has write privilege, open the object with write privilege; if the client application has read-only privilege, open the object with read-only privilege. The client application can learn the privilege by getting the property PR_ACCESS_LEVEL.

MAPI_DEFERRED_ERRORS

Indicates the call is allowed to succeed even if the underlying object is not accessible to the calling application. If the object is not accessible, some subsequent call to the object might return an error.

MAPI_MODIFY

Requests write access. By default, objects are created with read-only access, and client applications should not assume that write access was granted.

lpulObjType

Output parameter pointing to a variable that receives the object type for the opened object.

lppUnk

Output parameter pointing to a variable where the pointer to the opened object is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NO_ACCESS

An attempt to modify a read-only object or an attempt to access an object for which the user has insufficient permissions.

MAPI_E_UNKNOWN_ENTRYID

The object indicated in the lpEntryID parameter is not recognized. This return value is typically returned if the message store or address book provider that the object is contained within is not open.

MAPI_E_NOT_FOUND

The object indicated in the lpEntryID parameter does not exist.

Comments

Service providers use the IMAPISupport::OpenEntry method to open objects. Default behavior is to open the object as read-only, unless the call sets the MAPI_MODIFY or MAPI_BEST_ACCESS flag in the ulFlags parameter. Unlike IMAPISession::OpenEntry, your provider cannot open the root folder by passing NULL in the lpEntryID parameter of IMAPISupport::OpenEntry.

The calling application should check the value returned in the lpulObjType parameter to determine that the object type returned is what was expected. Commonly, after the application checks the type of the object, it then casts the pointer in the lppUnk parameter into a message object pointer, a folder object pointer, or another appropriate object pointer. In order to open address book objects, you must open the address book first.

If your application passes an entry identifier in the lpEntryID parameter that belongs to a container, such as a message store or address book, which is not currently open, the call might fail and return the value MAPI_E_UNKNOWN_ENTRYID.


 IMAPISupport::OpenProfileSection

[New - Windows 95]

Opens a section of the current profile and returns a pointer that provides further access.

Syntax

HRESULT OpenProfileSection(LPMAPIUID lpUid, ULONG ulFlags, LPPROFSECT FAR * lppProfileObj)

Parameters

lpUid

Input parameter pointing to the MAPIUID structure holding the MAPI unique identifier (MAPIUID) that identifies the profile section. Passing NULL for the lpUid parameter opens a profile section containing service provider information and credentials for the current provider session.

ulFlags

Input parameter containing a bitmask of flags used to control how the profile section is opened. The following flags can be set:

MAPI_BEST_ACCESS

Indicates the object should be opened with the maximum privileges allowed to the user. For example, if the client application has write privilege, open the object with write privilege; if the client application has read-only privilege, open the object with read-only privilege. The client application can learn the privilege by getting the property PR_ACCESS_LEVEL.

MAPI_DEFERRED_ERRORS

Indicates the call is allowed to succeed even if the underlying object is not accessible to the calling application. If the object is not accessible, some subsequent call to the object might return an error.

MAPI_MODIFY

Requests write access. By default, objects are created with read-only access, and client applications should not assume that write access was granted.

lppProfileObj

Output parameter pointing to a variable where the pointer to the returned profile section object is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NO_ACCESS

An attempt to modify a read-only object or an attempt to access an object for which the user has insufficient permissions.

MAPI_E_NOT_FOUND

The requested object does not exist.

MAPI_E_UNKNOWN_FLAGS

Reserved or unsupported flags were used, and therefore the operation did not complete.

Comments

Service providers use the IMAPISupport::OpenProfileSection method to open a property interface on a section of the profile. A profile section object supporting the IProfSect interface is returned in the lppProfSect parameter. Providers can use an OpenProfileSection call to make their configuration information available to other applications. To do so, your provider passes a MAPIUID in the lpUid parameter for the profile section that is known to other applications or providers.

The default behavior for OpenProfileSection is to open the profile section object as read-only, unless an application sets the MAPI_MODIFY flag in the ulFlags parameter. If an OpenProfileSection call attempts to open a nonexistent section with read-only access, the value MAPI_E_NOT_FOUND is returned.

If an OpenProfileSection call opens a nonexistent profile section with read-write access by passing the MAPI_MODIFY flag in the ulFlags parameter, the call creates the section.

Profile section operations shouldn't be held open any longer than necessary, but a provider that is writing to a profile section can keep it open while displaying a configuration property sheet.

See Also

IMAPIProp : IUnknown interface, IProfSect : IMAPIProp interface, MAPIUID structure


 IMAPISupport::OpenTemplateID

[New - Windows 95]

Allows runtime binding of one address book provider's code to the data in another address book provider. OpenTemplateID is only used for interaction between address book providers.

Syntax

HRESULT OpenTemplateID(ULONG cbTemplateID, LPENTRYID lpTemplateID, ULONG ulTemplateFlags, LPMAPIPROP lpMAPIPropData, LPCIID lpInterface, LPMAPIPROP FAR * lppMAPIPropNew, LPMAPIPROP lpMAPIPropSibling)

Parameters

cbTemplateID

Input parameter containing the number of bytes in the lpTemplateID parameter. This value is obtained from the address book entry's PR_TEMPLATEID property.

lpTemplateID

Input parameter pointing to the template identifier for the template to be used. This value is obtained from the address book entry's PR_TEMPLATEID property.

ulTemplateFlags

Input parameter containing a bitmask of flags controlling how the address book entry is opened. The following flag can be set:

FILL_ENTRY

Indicates this is the first time this entry is being created in your provider's address book and that the foreign address book provider should copy all relevant properties, including name to identifier mapping, to the object pointed to by the lpMAPIPropData parameter. The foreign provider must perform this operation.

lpMAPIPropData

Input parameter pointing to the property object that is linked to the data in your address book provider. This is the object that receives the template information from the foreign address book provider. This object must support the interface being requested in the lpInterface parameter and it must be set to read-write access.

lpInterface

Input parameter pointing to the interface identifier that is being used for both the property objects in lppMAPIPropData and lppMAPIPropNew parameters. Passing NULL in the lpInterface parameter indicates the return value is cast to the standard interface for the address-book entry, which can be assumed to be IID_IMailUser.

lppMAPIPropNew

Output parameter pointing to a variable where the pointer to the interface indicated by the lpInterface parameter is stored.

lpMAPIPropSibling

Reserved; must be NULL.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_UNKNOWN_ENTRYID

The other service provider doesn't exist.

Comments

Address book providers use the IMAPISupport::OpenTemplateID method to bind code that exists in a foreign address book provider to data that is contained in your address book provider. Your address book provider only needs to call OpenTemplateID if the address book entry that was previously obtained from a foreign address book provider has the PR_TEMPLATEID property. The values contained within PR_TEMPLATEID are passed in the OpenTemplateID method's cbTemplateID and lpTemplateID parameter. The foreign address book provider uses those values to determine which code to bind to your data.

Any address book provider that can contain entries with template identifiers copied from other containers should check for the PR_TEMPLATEID property after calls to the IABContainer::OpenEntry or IABLogon::CreateEntry methods. If the address book entry contains the PR_TEMPLATEID property, OpenTempalteID should be called so that the foreign address book provider has the opportunity to update the entry. If the FILL_ENTRY flag is passed in the ulFlags parameter, the foreign address book provider sets all properties on the entry. If the provider updates an entry without performing other operations, it can return the same interface for the OpenTemplateID call that was passed to it in the lpInterface parameter.

If OpenTemplateID fails with MAPI_E_UNKNOWN_ENTRYID, your provider should try to continue by treating the object as read-only.

See Also

IABLogon::OpenTemplateID method, IPropData : IMAPIProp interface, PR_TEMPLATEID property


 IMAPISupport::PrepareSubmit

[New - Windows 95]

Prepares a message for submission to the MAPI spooler.

Syntax

HRESULT PrepareSubmit(LPMESSAGE lpMessage, ULONG FAR * lpulFlags)

Parameters

lpMessage

Input parameter pointing to the message to prepare.

lpulFlags

On input, reserved; must be zero. On output, must be NULL.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Message store providers use the IMAPISupport::PrepareSubmit method to prepare a message for submission to the MAPI spooler. Store providers call PrepareSubmit in response to a call to the IMessage::SubmitMessage method by a client application. The PrepareSubmit call should be made soon after the client application calls IMessage::SubmitMessage. Message store providers that need to ensure that the MAPI spooler is synchronized with the client application as part of their PrepareSubmit implementation should call IMAPISupport::SpoolerNotify, passing the NOTIFY_READYTOSEND flag in the ulFlags parameter.

Message store providers call the IMAPIFolder::GetMessageStatus method to check the status of a message. If a message has its status set to MSGSTATUS_RESEND, the recipient list is checked and the PR_RESPONSIBILITY bit is set to true for all recipients that don't have MAPI_SUBMITTED set. The IMessage::ModifyRecipients method is then called to remove the recipients from the list that have already received the message.

See Also

IMAPIFolder::GetMessageStatus method, IMessage::SubmitMessage method


 IMAPISupport::ReadReceipt

[New - Windows 95]

Generates a read or nonread report for a message.

Syntax

HRESULT ReadReceipt(ULONG ulFlags, LPMESSAGE lpReadMessage, LPMESSAGE FAR * lppEmptyMessage)

Parameters

ulFlags

Input parameter containing a bitmask of flags used to control how the read report is generated. The following flag can be set:

MAPI_NON_READ

Indicates that a non-read report is generated.

lpReadMessage

Input parameter pointing to the newly read message.

lppEmptyMessage

Input-output parameter pointing to a variable where the pointer to the newly created message that will be used as the read or nonread report is stored. On input the message store provider passes in the newly created method. MAPI then returns the changed message; only the contents of the message are changed, not the parameter's value.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Message store providers use the IMAPISupport::ReadReceipt method to call MAPI to generate a read or nonread report for the message indicated by the lpReadMessage parameter and to place the pointer to the resulting report in the lppEmptyMessage parameter. Setting the MAPI_NON_READ flag in the ulFlags parameter generates a nonread report. ReadReciept is typically called in response to a message being read, but also when a message is moved or copied. ReadReceipt is not called when a message is deleted. Providers can also call ReadReciept in response to calls to IMessage::SetReadFlag, but the read or non-read report should only be sent once. Providers need to keep track of the read status and should not send multiple reports for a single message.

If the lppEmptyMessage parameter references a valid message when MAPI returns from ReadReceipt, the store provider should call IMessage::SubmitMessage followed by Release on the message.

Providers can select whether to hide or display read and nonread reports generated by stores in their folders. Storing read and nonread reports in hidden folders allows the provider to implement tighter security.

If ReadReciept fails, the message should be released without being submitted. Providers can choose to store the message's status and try to generate the read or nonread report later.

See Also

IMAPIFolder::DeleteMessages method, IMessage::SubmitMessage method, PR_READ_RECEIPT_REQUESTED property


 IMAPISupport::RegisterPreprocessor

[New - Windows 95]

Registers a preprocessor function for a transport provider.

Syntax

HRESULT RegisterPreprocessor(LPMAPIUID lpMuid, LPTSTR lpszAdrType, LPTSTR lpszDLLName, LPSTR lpszPreprocess, LPSTR lpszRemovePreprocessInfo, ULONG ulFlags)

Parameters

lpMuid

Input parameter pointing to the MAPIUID structure holding the MAPI unique identifier (MAPIUID) that identifies the entry identifier that the function handles. lpMuid can be NULL.

lpszAdrType

Input parameter pointing to a string containing the e-mail address type for the messages the preprocessor function operates on; examples of e-mail address types are FAX, SMTP, X500, and so on. lpszAdrType can be NULL or empty.

lpszDLLName

Input parameter pointing to a string containing the name of the DLL containing the entry point for the preprocessor function.

lpszPreprocess

Input parameter pointing to a string containing the name of the preprocessor function. lpszPreprocess can be NULL.

lpszRemovePreprocessInfo

Input parameter pointing to a string containing the name of the function that removes preprocessor information. lpszRemovePreprocessInfo can be NULL.

ulFlags

Reserved; must be zero.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Transport providers use the IMAPISupport::RegisterPreprocessor method to register their preprocessor and postprocessing functions. Preprocessor functions must be registered before they can be called by the MAPI spooler prior to allowing the message to be sent.

The lpMuid and lpszAdrType parameters are used to match the preprocessor function with specific address types. If both lpMuid and lpszAdrType are non-NULL, matching occurs if either MAPIUID or the address type match. If lpMuid is NULL and lpszAdrType is non-NULL, then matching only occurs on the address type. If lpMuid is non-NULL and lpszAdrType is NULL, then matching only occurs on the specific MAPIUID and for any address type. If both are NULL, then the message is preprocessed.

The lpszPreprocess, lpszRemovePreprocessInfo and lpszDLLName parameters should all point to strings that can be used in conjunction with calls to the GetProcAddress function so that the preprocessor's DLL entry point is called correctly.

Preprocessors are transport-order specific; that is, if a transport ahead of your transport in MAPI's transport order is able to handle the message, then your provider's preprocessor won't get called.

See Also

MAPIUID method, PreprocessMessage function, RemovePreprocessInfo function


 IMAPISupport::SetProviderUID

[New - Windows 95]

Informs MAPI of the MAPI unique identifier (MAPIUID) assigned to the service provider using this support object.

Syntax

HRESULT SetProviderUID(LPMAPIUID lpProviderID, ULONG ulFlags)

Parameters

lpProviderID

Input parameter pointing to the MAPIUID structure holding the MAPIUID identifying the service provider object.

ulFlags

Reserved; must be zero.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Service providers use the IMAPISupport::SetProviderUID method to inform MAPI that they handle all globally unique identifiers (GUID) as indicated by the MAPIUID structure passed in the lpProvider parameter. MAPI uses the provider MAPIUID when sending outbound messages to the MAPI spooler or when routing instructions from client applications to the appropriate providers (for example, a call to the IMAPISupport::OpenEntry method to open a particular object belonging to a particular service provider).

A call to SetProviderUID should be made at logon to provide a MAPIUID for the provider for the logon session, although SetProviderUID can also be called later.

If a provider supports access to its entries with a variety of provider identifiers, it can make multiple calls to SetProviderUID. This call is additive in that it always adds a MAPIUID, even if one already exists. It never subtracts a MAPIUID and once one is created, it cannot be removed.

See Also

MAPIUID structure


 IMAPISupport::SpoolerNotify

[New - Windows 95]

Informs the MAPI spooler that the provider needs servicing.

Syntax

HRESULT SpoolerNotify(ULONG ulFlags, LPVOID lpvData)

Parameters

ulFlags

Input parameter containing a bitmask of flags used to control how the transport provider is serviced. The following flags can be set:

NOTIFY_CONFIG_CHANGE

Indicates to the MAPI spooler that the transport's configuration has changed. Causes the MAPI spooler to call the transport's IXPLogon::AddressTypes and IMAPISession::MessageOptions methods at the next convenient time.

NOTIFY_CRITICAL_ERROR

Indicates that the transport provider has encountered an unrecoverable error situation and that the provider requires the MAPI spooler to stop message processing and deinitialize the transport. If the transport provider chooses to call the IMAPISupport::SpoolerNotify method with NOTIFY_CRITICAL_ERROR during an IXPLogon::StartMessage or IXPLogon::SubmitMessage method call, it should return from the StartMessage or SubmitMessage call immediately after the SpoolerNotify call with an appropriate error code.

NOTIFY_CRITSEC

Indicates the transport provider cannot allow the MAPI 	spooler to automatically yield to Windows during processing of calls made by the transport provider to the MAPI spooler. The transport provider will either yield when it can or begin automatically yielding again later. The transport provider's IXPLogon::Idle and IXPLogon::Poll methods should not be called. The lpvData parameter is undefined and should be set to NULL.

NOTIFY_NEWMAIL

Indicates the transport provider has new incoming messages the MAPI spooler should request. The message download occurs at the next available time. The lpvData parameter is undefined and should be set to NULL.

NOTIFY_NEWMAIL_RECEIVED

Indicates the lpvData parameter points to a new mail notification structure. Used for transports that are tightly coupled with message stores. This flag is ignored if the message store logged on with the MAPI_NO_MAIL flags set.

NOTIFY_NONCRIT

Indicates the transport provider needs to end the critical section it declared earlier. The lpvData parameter is undefined and should be set to NULL.

NOTIFY_READYTOSEND

Indicates the transport provider has recovered from a condition that caused it to fail earlier (see the possible return values for the IXPLogon::SubmitMessage method) and is again ready to accept messages. When set by a message store provider, this flag indicates that the MAPI spooler should synchronize with the client application's session. The lpvData parameter is undefined and should be set to NULL.

NOTIFY_SENTDEFERRED

Indicates the transport provider has completed some part of the process of sending a deferred message and requests to be notified at the next IXPLogon::SubmitMessage method call. The entry identifier of the deferred message is contained in an SBinary structure pointed to by the lpvData parameter.

lpvData

Input parameter pointing to a notification structure holding data associated with the notification. The meaning of the data in the lpvData parameter depends on what flags are set in the ulFlags parameter; for more information on what lpvData can hold, see the preceding descriptions for the ulFlags flags.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Transport providers use the IMAPISupport::SpoolerNotify method to notify the MAPI spooler to handle processing of a new message. A transport provider can call IMAPISupport::SpoolerNotify at any time.

When a message store tightly coupled with a transport calls SpoolerNotify, the MAPI spooler opens the message and begins processing the hook function that handles new messages. This process culminates in the MAPI spooler calling the IMsgStore::NotifyNewMail method to inform the message store about its own new message.

The notification structure pointed to by lpvData is sent to the MAPI spooler by MAPI. Note that only the NOTIFY_SENT_DEFERRED and NOTIFY_CRITICAL_ERROR flags for ulFlags have data associated with them. These two flags must not be set with the same SpoolerNotify call, although any other combination of flags can be used.

If a transport provider places one of its processes within a critical section, it should set the NOTIFY_CRITSEC flag in ulFlags. For example, a remote transport provider uploading messages might need to display a dialog box so the user can select a telephone number to dial to establish the remote connection. If the transport provider displays the dialog box using its own function, it should declare a critical section before looping through the dialog box function. After the user closes the dialog box and the dialog box function terminates, the transport should end the critical section.

In response to receiving NOTIFY_CRITSEC with a SpoolerNotify call, the MAPI spooler stops making calls to the transport provider until the provider notifies it that the critical section has ended. Furthermore, a transport provider can return the value MAPI_E_BUSY for any calls made to update its status for an open status object while it has a critical section open.

If a transport provider has changed its configuration, it should set the NOTIFY_CONFIG_CHANGED flag in the ulFlags parameter so that the MAPI spooler can reconfigure the transport on IXPLogon::AddressTypes and IMAPISession::MessageOptions method calls.

Message store providers that need to ensure that the MAPI spooler is synchronized with the client application as part of their IMAPISupport::PrepareSubmit implementation should call SpoolerNotify, passing the NOTIFY_READYTOSEND flag in the ulFlags parameter.

See Also

IMsgStore::NotifyNewMail method, IXPLogon::StartMessage method, IXPLogon::SubmitMessage method


 IMAPISupport::SpoolerYield

[New - Windows 95]

Allows the transport provider to permit the MAPI spooler to give processing time to Windows.

Syntax

HRESULT SpoolerYield(ULONG ulFlags)

Parameters

ulFlags

Reserved; must be zero.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_W_CANCEL_MESSAGE

Indicates that the user wants to stop the transfer of an incoming or outgoing message regardless of how many recipients might already have received it.

Comments

Transport providers use the IMAPISupport::SpoolerYield method to allow the MAPI spooler to give up processing to Windows. Transports typically make this call when they are performing lengthy operations and that can be paused. This functionality allows foreground applications to run during long transport provider operations.

During the processing of a SpoolerYield call, the MAPI spooler might detect a number of conditions that it signals to the transport provider in the SpoolerYield return value. If SpoolerYield returns with MAPI_W_CANCEL_MESSAGE, the MAPI spooler has determined that the message should no longer be sent. Your provider should return MAPI_E_USER_CANCEL to the calling process and exit if possible.


 IMAPISupport::StatusRecips

[New - Windows 95]

Generates delivery reports and nondelivery reports on behalf of transport providers.

Syntax

HRESULT StatusRecips(LPMESSAGE lpMessage, LPADRLIST lpRecipList)

Parameters

lpMessage

Input parameter pointing to the message for which a report is to be generated.

lpRecipList

Input parameter pointing to an ADRLIST structure holding a set of recipients for which delivery or nondelivery information is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Transport providers use the IMAPISupport::StatusRecips method to notify MAPI that delivery or nondelivery reports should be sent for a set of one or more recipients. A delivery report is a report that indicates a message has been delivered to a recipient; a nondelivery report is a report that a message could not be delivered to a recipient.

Transport providers can call StatusRecips multiple times during the processing of a message. However, transport providers that call StatusRecips for an open message should do their best to collect all delivery and nondelivery information for the message recipients and call StatusRecips for that recipient list. A single point of collection is important because each time a transport provider calls StatusRecips, MAPI can generate delivery and nondelivery reports, so multiple StatusRecips calls for one recipient can result in multiple identical reports being sent.

A provider should store properties relating to message delivery or nondelivery in the ADRLIST structure indicated by the lpRecipList parameter. The following properties are required for both delivery reports and nondelivery reports:

PR_MESSAGE_CLASS

Message class. This information is added to the report name; for example, for subject class X, the nondelivery report (NDR) name is REPORT.X.NDR and the delivery report (DR) name is REPORT.X.DR.

PR_REPORT_TEXT

Optional text generated by the messaging system. For a nondelivery report, this text indicates the reason for nondelivery.

PR_REPORT_TIME

Usually, the date and time when the message was delivered or deemed to be undeliverable. The information provided by PR_REPORT_TIME depends on the implementation.

PR_ROWID

Row in the recipient table where the recipient of the message for which the report is being generated appears. The MAPI spooler copies this row into the recipient table of the report.

PR_SEARCH_KEY

Contains a binary-comparable key that uniquely identifies the message object.

The following additional property is required for delivery reports:

PR_MESSAGE_DELIVERY_TIME

Contains the date and time the message was delivered.

The following additional property is required for nondelivery reports:

PR_NDR_DIAGNOSTIC_CODE

Contains diagnostic values identifying delivery problems.

MAPI adds additional properties to the final delivery or nondelivery report.

A provider should allocate memory for the ADRLIST structure in lpRecipList using the MAPIAllocateBuffer and MAPIAllocateMore functions. MAPI releases the memory by calling the MAPIFreeBuffer function.

See Also

ADRLIST structure, IMAPISupport::Address method, IMAPISupport::SpoolerNotify method, IXPLogon::EndMessage method, MAPIAllocateBuffer function, MAPIAllocateMore function, MAPIFreeBuffer function


 IMAPISupport::StoreLogoffTransports

[New - Windows 95]

Specifies the orderly release of the message store to the MAPI spooler.

Syntax

HRESULT StoreLogoffTransports(ULONG FAR * lpulFlags)

Parameters

lpulFlags

Input-output parameter containing a bitmask of flags used to control how message store logoff occurs.

On input, all flags for this parameter are mutually exclusive; a client application can set only one per call. The following flags can be set on input for lpulFlags:

LOGOFF_ABORT

Indicates any transport activity on this store should be stopped before logoff. Control is returned to the client application after the activity is stopped and the MAPI spooler has logged off the store. If any transport activity is taking place, the logoff does not occur and no change in MAPI spooler or transport behavior occurs. If transport activity is quiet, the MAPI spooler releases the store. This flag is set by the store provider.

LOGOFF_NO_WAIT

Indicates the message store closing should not wait for messages from the transport providers before closing. All outbound mail that is ready to be sent, is sent; if this store has the default inbox, any in-process message is received, and then further reception is disabled. When all activity is completed, the MAPI spooler releases the store and control is returned to the client application immediately. This flag is set by the store provider.

LOGOFF_ORDERLY

Indicates the message store closing should not wait for information from the transport providers before closing. Any message being processed by the store is completed and no new messages are processed. When all activity is completed, the MAPI spooler releases the store and control is returned to the store provider immediately. This flag is set by the store provider.

LOGOFF_PURGE

Works the same as LOGOFF_NO_WAIT. LOGOFF_PURGE returns control to the client application after completion. This flag is set by the store provider.

LOGOFF_QUIET

Indicates that if any transport provider activity is taking place, the logoff does not occur and the type of activity is returned as a flag on output. This flag is set by the store provider.

On output, the MAPI spooler can return more than one flag. The following flags can be set on output for lpulFlags:

LOGOFF_COMPLETE

Indicates the logoff can complete. All resources associated with the store have been released and the object has been invalidated. The MAPI spooler has performed or will perform all requests. Only the Release method should be called at this point. LOGOFF_COMPLETE is returned by the store provider.

LOGOFF_INBOUND

Indicates a message is currently coming into the store from one or more transport providers. This flag is returned by the store provider.

LOGOFF_OUTBOUND

Indicates a message is currently being sent from the store by one or more transport providers. This flag is returned by the store provider.

LOGOFF_OUTBOUND_QUEUE

Indicates there are currently messages in the outbound queue for the store. This flag is returned by the store provider.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Message store providers use the IMAPISupport::StoreLogoffTransports method to give client applications some control over how MAPI handles transport provider activity as the message store is closing.

Before a StoreLogoffTransports call occurs, a client application calls the IMsgStore::StoreLogoff method and sets flags in its lpulFlags parameter to indicate how the client application requires the message store to be shut down. A message store provider should use these IMsgStore::StoreLogoff flags set by the client as input values for the StoreLogoffTransports method's lpulFlags parameter. The status returned from a client application call to the IMsgStore::StoreLogoff method is usually the same status that the message store provider then sends on the call to StoreLogoffTransports.

If the client application calls the IUnknown::Release method on a message store object without calling the IMsgStore::StoreLogoff method first, the message store provider involved should set the LOGOFF_ABORT flag in the lpulFlags parameter for StoreLogoffTransports.

If another process has the store to be logged off open for the same profile, MAPI ignores a call to StoreLogoffTransports and returns the value LOGOFF_COMPLETE in lpulFlags.

The behavior of the store provider following the return from StoreLogoffTransports should be based on the value of lpulFlags, which indicates system status and conveys client instructions on logoff behavior.

See Also

IMsgStore::StoreLogoff method, IXPLogon::FlushQueues method


 IMAPISupport::Subscribe

[New - Windows 95]

Sets up a subscription for notification events with the MAPI notification engine.

Syntax

HRESULT Subscribe(LPNOTIFKEY lpKey, ULONG ulEventMask, ULONG ulFlags, LPMAPIADVISESINK lpAdviseSink, ULONG FAR * lpulConnection)

Parameters

lpKey

Input parameter pointing to the NOTIFKEY structure for the object whose changes should generate notifications. The lpKey parameter provides a unique key to the object and cannot be NULL.

ulEventMask

Input parameter containing an event mask of the types of notification events occurring for the object for which MAPI will generate notifications. The event types are combined in a bitmask to filter specific cases. Each event type has a structure associated with it that holds additional information about the event. The following table lists the possible event types along with their corresponding data structures:

Notification event type	Corresponding data structure
fnevCriticalError	ERROR_NOTIFICATION
fnevNewMail	NEWMAIL_NOTIFICATION
fnevObjectCreated	OBJECT_NOTIFICATION
fnevObjectDeleted	OBJECT_NOTIFICATION
fnevObjectModified	OBJECT_NOTIFICATION
fnevObjectCopied	OBJECT_NOTIFICATION
fnevSearchComplete	OBJECT_NOTIFICATION
fnevTableModified	TABLE_NOTIFICATION
fnevStatusObjectModified	STATUS_OBJECT_NOTIFICATION
fnevExtended	EXTENDED_NOTIFICATION
ulFlags

Input parameter containing a bitmask of flags used to control how notification occurs. The following flag can be set:

NOTIFY_SYNC

Indicates that all notification callbacks should be made before the Notify method returns to the calling implementation. If this flag is not set, notification callbacks are queued to the registered processes and started when those processes gain control of the CPU.

lpAdviseSink

Input parameter pointing to an advise sink object created by the calling application to be called when an event for the object occurs about which notification has been requested.

lpulConnection

Output parameter pointing to a variable that upon a successful return holds the connection number for the notification subscription.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Service providers use the IMAPISupport::Subscribe method to receive notification of changes to objects from MAPI's notification engine. A provider can make one call to Subscribe for every call to its HrAllocAdviseSink function. The MAPI notification engine is a convenience for provider writers; providers can choose to use it as the basis for their implementation of Advise and Unadvise methods, or they can use their own.

To use the MAPI notification engine, providers must create a key for the object for which notifications should be generated and place that key in the lpKey parameter. The notification engine uses this key after notification subscription is set up to search for any callbacks registered for the corresponding object. The value of the key must be unique to the item being registered; any value that uniquely identifies the object and is easily regenerated each time the object changes is acceptable. However, a key must be provided; NULL cannot be sent in lpKey. A NOTIFKEY structure is used in lpKey so your provider can map different entry identifiers to the same object using the same key.

Once notification subscription is set up, a provider, when calling IMAPISupport::Notify to signal that a notification event has taken place, should provide the notification key in Notify's lpKey parameter.

The NOTIFY_SYNC flag in the Subscribe ulFlags parameter indicates whether the client application requested synchronous or asynchronous notifications. The notification engine records this information and issues the appropriate type of callback when the provider calls Notify. Synchronous notifications can never be requested on behalf of client applications; they are only for internal service provider use, for situations where careful sequencing of access to provider data structures is necessary.

There are limitations on what a synchronous callback function can do:

•	It cannot cause another synchronous notification to be generated.

•	It cannot display a user interface.

Although a synchronous callback function is called with the same parameters as an asynchronous callback function, its possible return values are predetermined. A synchronous callback function can return the value CALLBACK_DISCONTINUE, indicating that MAPI should immediately stop processing the callbacks for this notification, something an asynchronous callback function cannot do. If a callback function returns CALLBACK_DISCONTINUE, MAPI does not queue additional eligible notifications but calls Notify and sets the NOTIFY_CANCELED flag in its lpulFlags parameter.

A synchronous callback function can also stop callback processing by returning the CALLBACK_DISCONTINUE flag in the HrAllocAdviseSink function's lppAdviseSink parameter.

See Also

HrAllocAdviseSink function, IMAPIAdviseSink::OnNotify method, IMAPISupport::Notify method, NOTIFICATION structure, NOTIFKEY structure


 IMAPISupport::Unsubscribe

[New - Windows 95]

Removes an object's subscription for notification of changes previously established with a call to the IMAPISupport::Subscribe method.

Syntax

HRESULT Unsubscribe(ULONG ulConnection)

Parameters

ulConnection

Input parameter containing the number of the registration connection previously returned by a call to the IMAPISupport::Subscribe method.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NOT_FOUND

The connection number passed in does not exist.

Comments

Providers use the IMAPISupport::Unsubscribe method to cancel a notification subscription. Unsubscribe does so by releasing the pointer to the advise sink object passed in the lpAdviseSink parameter in the previous call to Subscribe. As part of discarding the pointer to the advise sink object, the object's IUnknown::Release method is called. Generally, Release is called during the Unsubscribe call, but if another thread is in the process of calling IMAPIAdviseSink::OnNotify on the advise sink object, the Release call is delayed until the OnNotify method returns.

The MAPI notification engine is a convenience for provider writers; providers can choose to use it as the basis for their implementation of Advise and Unadvise methods, or they can use their own.

See Also

IMAPIAdviseSink::OnNotify method, IMAPISupport::Subscribe method


 IMAPISupport::WrapStoreEntryID

[New - Windows 95]

Maps the private entry identifier of a message store object to an entry identifier more useful to the messaging system.

Syntax

HRESULT WrapStoreEntryID(ULONG cbOrigEntry, LPENTRYID lpOrigEntry, ULONG FAR * lpcbWrappedEntry, LPENTRYID FAR * lppWrappedEntry)

Parameters

cbOrigEntry

Input parameter containing the number of bytes in the lpOrigEntry parameter.

lpOrigEntry

Input parameter pointing to the private entry identifier for the message store resource.

lpcbWrappedEntry

Output parameter pointing to a variable that contains the number of bytes in the lppWrappedEntry parameter.

lppWrappedEntry

Output parameter pointing to a pointer to the new identifier to which MAPI has mapped the message store provider's private entry identifier.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Message store providers use the IMAPISupport::WrapStoreEntryID method to have MAPI generate a wrapped entry identifier to allow the opening of an entry if the store is not opened.

To allow storage of a message store's PR_STORE_ENTRYID properties by the messaging system, MAPI must map the store's private entry identifier to an identifier useful to the messaging system. MAPI returns the wrapped version in response to any property requests for PR_STORE_ENTRYID. In other words, when a client application calls the IMAPIProps::GetProps method to retrieve PR_STORE_ENTRYID, instead of returning the store resource's entry identifier directly, the provider calls WrapStoreEntryID.

One use of WrapStoreEntryID is to allow an entry in the store to be opened if the store is not already open. In such cases, a valid entry identifier for the entry must be passed in the OpenEntry call.

Calls to the IMSProvider::Logon and IMSLogon::CompareEntryIDs methods always obtain the store's private entry identifier; the wrapped version is used only between client applications and MAPI.

The memory for the entry identifier returned in the lppWrappedEntry parameter must be freed using the MAPIFreeBuffer function after the provider is done with the entry identifier.

See Also

IMAPIProp::GetProps method, IMAPISupport::CompareEntryIDs method, IMSLogon::CompareEntryIDs method, IMSProvider::Logon method, MAPIFreeBuffer function


 IMAPITable : IUnknown

[New - Windows 95]

The IMAPITable interface is used for working with MAPI table objects.

At a Glance

Specified in header file:	MAPIDEFS.H
Object that supplies this interface:	Table object
Corresponding pointer type:	LPMAPITABLE
Implemented by:	Service providers
Called by:	Client applications, service providers
Vtable Order

GetLastError	Returns information about the last error that occurred for a table object.
Advise	Registers an implementation for notification on changes to a table object.
Unadvise	Removes a table's registration for notification of changes previously established with a call to the Advise method.
GetStatus	Returns the status and type of a table.
SetColumns	Sets the order of columns in table rows to be returned by the IMAPITable::QueryRows method.
QueryColumns	Returns either the current list of columns for a table or the full list of columns available for the table.
GetRowCount	Returns the total number of rows in a table.
SeekRow	Moves the cursor to a specific position in a table.
SeekRowApprox	Finds an approximate fractional position in a table.
QueryPosition	Retrieves the row within a table where the cursor is currently positioned, based on a fractional value indicating the cursor position.
FindRow	Finds the next row in the table that contains a property matching the specified criteria.
Restrict	Applies a restriction to a table, reducing the rows visible to only those matching the restriction criteria.
CreateBookmark	Marks the current position of the table cursor so that an implementation can return to that position even when the table is updated.
FreeBookmark	Releases a bookmark from memory.
SortTable	Sorts table rows based on the sort criteria provided.
QuerySortOrder	Retrieves the current sort order for a table.
QueryRows	Returns one or more rows from a table, beginning at the current cursor position.
Abort	Stops any asynchronous operations currently in progress for a table.
ExpandRow	Expands a collapsed table category and adds the rows of that category to the table view.
CollapseRow	Collapses a table category and removes it from the table view.
WaitForCompletion	Suspends an implementation while asynchronous operations occur on a table.
GetCollapseState	Returns the data necessary to rebuild the current table view.
SetCollapseState	Reestablishes the expanded or collapsed state of the table view that was saved by a call to the IMAPITable::GetCollapseState method.


 IMAPITable::Abort

[New - Windows 95]

Stops any asynchronous operations currently in progress for a table.

Syntax

HRESULT Abort()

Parameters

None

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_UNABLE_TO_ABORT

The operation is in progress and could not be canceled.

Comments

Use the IMAPITable::Abort method to stop any asynchronous operation that is in progress on a table. To detect asynchronous operations currently in progress, your implementation can call the IMAPITable::GetStatus method.

If a call to the IMAPITable::Restrict method is interrupted by a call to Abort, whatever is in the table at the time the Abort call is processed remains in the table. If a call to the IMAPITable::SortTable method is interrupted by a call to Abort, the order of rows in the table is not changed from their order before the sort operation.

If the background operation cannot be stopped or if it completes before Abort returns, Abort returns MAPI_E_UNABLE_TO_ABORT.

See Also

IMAPITable::GetStatus method, IMAPITable::Restrict method, IMAPITable::SortTable method


 IMAPITable::Advise

[New - Windows 95]

Registers an implementation for notification on changes to a table object.

Syntax

HRESULT Advise(ULONG ulEventMask, LPMAPIADVISESINK lpAdviseSink, ULONG FAR * lpulConnection)

Parameters

ulEventMask

Input parameter containing an event mask of the types of notification events occurring for the object for which MAPI will generate notifications to filter specific cases. Each event type has a structure associated with it that holds additional information about the event. The only possible event type for this parameter is fnevTableModified; the corresponding data structure is TABLE_NOTIFICATION.

lpAdviseSink

Input parameter pointing to an advise sink object to be called when a event for the session object occurs about which notification has been requested. This advise sink object must have already been allocated.

lpulConnection

Output parameter pointing to a variable that on a successful return holds the connection number for the notification registration. The connection number must be nonzero

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NO_SUPPORT

The service provider either does not support changes to its objects or does not support notification of changes.

Comments

Use the IMAPITable::Advise method to register a table object implemented in a service provider for notification callbacks. Whenever a change occurs to the indicated object, the provider checks to see what event mask bit has been set in the ulEventMask parameter and thus what type of change has occurred. If a bit is set, then the provider calls the IMAPIAdviseSink::OnNotify method for the advise sink object indicated by the lpAdviseSink parameter to report the event. Data passed in the notification structure to the OnNotify routine describes the event.

The call to OnNotify can occur during the call that changes the object, or at any following time. On systems that support multiple threads of execution, the call to OnNotify can occur on any thread. For a way to turn a call to OnNotify that might happen at an inopportune time into one that is safer to handle, your client should use the HrThisThreadAdviseSink function.

To provide notifications, the service provider implementing Advise needs to keep a copy of the pointer to the advise sink object; to do so, it calls the IUnknown::AddRef method for the advise sink object to maintain the object pointer until notification registration is canceled with a call to the IMAPITable::Unadvise method. The Advise implementation should assign a connection number to the notification registration and call AddRef on this connection number before returning it in the lpulConnection parameter. Service providers can release the advise sink object before the registration is canceled, but they must not release the connection number until Unadvise has been called. After a call to Advise has succeeded and before Unadvise has been called, client applications must be prepared for the advise sink object to be released. Clients should therefore release their advise sink object after Advise returns unless they have a specific long-term use for it.

Because of the asynchronous behavior of notification, implementations that change the column settings can receive notifications with information organized by the previous column order. For instance, a table row might be returned for a message that has just been deleted from the container. Such a notification is sent when the column setting change has been made and information about it sent but the notification table view has not been updated with that information yet.

See Also

HrThisThreadAdviseSink function, IMAPIAdviseSink::OnNotify method, IMAPITable::Unadvise method, NOTIFICATION structure, TABLE_NOTIFICATION structure


 IMAPITable::CollapseRow

[New - Windows 95]

Collapses a table category and removes it from the table view.

Syntax

HRESULT CollapseRow(ULONG cbInstanceKey, LPBYTE pbInstanceKey, ULONG ulFlags, ULONG FAR * lpulRowCount)

Parameters

cbInstanceKey

Input parameter containing the number of bytes in the pbInstanceKey parameter.

pbInstanceKey

Input parameter pointing to a variable containing the instance key (that is, the PR_INSTANCE_KEY property) for the categorization row.

ulFlags

Reserved; must be zero.

lpulRowCount

Output parameter pointing to a variable containing the total number of rows, including heading and data rows, that are being removed from the table view.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NOT_FOUND

The category row does not exist.

Comments

Use the IMAPITable::CollapseRow method to collapse a table category and remove it from the table view. The rows are collapsed at the row containing the PR_INSTANCE_KEY passed in the pbInstanceKey parameter. The number of rows that are removed from the view is returned in the lpulRowCount parameter.

Providers must not generate notifications on rows that are collapsed out of the table view.

See Also

IMAPITable::ExpandRow method, IMAPITable::GetCollapseState method, IMAPITable::QuerySortOrder method, IMAPITable::SetCollapseState method, IMAPITable::SortTable method, SSortOrderSet structure


 IMAPITable::CreateBookmark

[New - Windows 95]

Marks the current position of the table cursor so that an implementation can return to that position even when the table is updated.

Syntax

HRESULT CreateBookmark(BOOKMARK FAR * lpbkPosition)

Parameters

lpbkPosition

Output parameter pointing to a variable that receives a 32-bit bookmark value that can later be passed in a call to the IMAPITable::SeekRow method.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_UNABLE_TO_COMPLETE

The requested operation could not be completed.

Comments

Use the IMAPITable::CreateBookmark method to create a bookmark, which is used to retain information about a position in a table so as to return to that position. The bookmarked position is associated with the object at that row in the table.

Because of the memory expense of maintaining cursor positions in this way, an implementation can limit the number of bookmarks permitted. If an implementation has done so and an attempt is made to create a bookmark that would surpass the number allowed, the call to CreateBookmark returns MAPI_E_UNABLE_TO_COMPLETE.

A bookmark pointing to a row that is no longer in the table view can still be used. If an application attempts to move the cursor to such a bookmark, the cursor moves to the next visible row and stops there. A call using a bookmark pointing to a collapsed row returns MAPI_W_POSITION_CHANGED. Providers can move bookmarks for positions collapsed out of view either at the time of use or at the time the row is collapsed. If a bookmark is moved at the time the row is collapsed, a bit must be retained in the bookmark that indicates whether the bookmark has moved since its last use or, if it has never been used, since its creation.

CreateBookmark can allocate memory for the bookmark it creates. An implementation must release the resources for the bookmark by calling the IMAPITable::FreeBookmark method.

See Also

IMAPITable::FreeBookmark method, IMAPITable::SeekRow method


 IMAPITable::ExpandRow

[New - Windows 95]

Expands a collapsed table category and adds the rows of that category to the table view.

Syntax

HRESULT ExpandRow(ULONG cbInstanceKey, LPBYTE pbInstanceKey, ULONG ulRowCount, ULONG ulFlags, LPSRowSet FAR * lppRows, ULONG FAR * lpulMoreRows)

Parameters

cbInstanceKey

Input parameter containing the number of bytes in the pbInstanceKey parameter.

pbInstanceKey

Input parameter pointing to a variable containing the instance key (that is, the PR_INSTANCE_KEY property) for the categorization row.

ulRowCount

Input parameter containing the maximum number of rows to return in the lppRows parameter.

ulFlags

Reserved; must be zero.

lppRows

Output parameter pointing to a variable where the returned SRowSet structure is stored. The SRowSet holds the set of new rows inserted into the table view after the row indicated by the pbInstanceKey parameter. The lppRows parameter can be NULL if the ulRowCount parameter is zero.

lpulMoreRows

Output parameter pointing to a variable holding the total number of rows added to the table.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NOT_FOUND

The row containing the instance key specified in the pbInstanceKey parameter doesn't exist.

Comments

Use the IMAPITable::ExpandRow method to expand a collapsed table category, adding its rows to the table view. The position of the bookmark value BOOKMARK_CURRENT is moved to the row immediately following the last row in the SRowSet structure returned in the lppRows parameter. If zero rows were requested, or zero rows were returned, the position of BOOKMARK_CURRENT is set to the row following the row specified in the pbInstanceKey parameter.

Providers must not generate notifications on rows that are collapsed out of the table view.

See Also

IMAPITable::CollapseRow method


 IMAPITable::FindRow

[New - Windows 95]

Finds the next row in the table that contains a property matching the specified criteria.

Syntax

HRESULT FindRow(LPSRestriction lpRestriction, BOOKMARK BkOrigin, ULONG ulFlags)

Parameters

lpRestriction

Input parameter pointing to a SRestriction structure containing the property to search for.

BkOrigin

Input parameter indicating the bookmark from which the search originates. A bookmark can be created using the IMAPITable::CreateBookmark method, or one of the following predefined values can be used:

BOOKMARK_BEGINNING

Seeks to the beginning of the table.

BOOKMARK_CURRENT

Seeks to the row in the table where the cursor is located.

BOOKMARK_END

Seeks to the end of the table.

ulFlags

Input parameter containing a bitmask of flags controlling the direction of the search. The following flag can be set:

DIR_BACKWARD

Searches backward from the bookmark.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_INVALID_BOOKMARK

The bookmark is invalid because it has been removed or because it is beyond the last row requested.

MAPI_E_NOT_FOUND

No rows were found that matched the restriction.

MAPI_W_POSITION_CHANGED

The call succeeded, but the bookmark used in the operation is no longer on the same row as when it was last used, or if it hasn't been used, the bookmark is no longer in the same position as when it was created. Use the HR_FAILED macro to test for this warning, but the call should be handled as a successful return.

Comments

Service providers use the IMAPITable::FindRow method to support scrolling based on strings typed by the user, especially in list boxes within addressing dialog boxes. In this type of scrolling, users enter progressively longer prefixes of a desired string value, and the client application periodically issues a FindRow call to jump to the first row that matches the prefix. Which direction the cursor jumps depends on which direction the search is set to run.

To use FindRow, a bookmark must be set. The string search can originate from any bookmark, including from the preset bookmarks indicating the current position, the beginning of the table, and the end of the table. If there is a large number of rows in the table, the search operation can be slow.

Clients use a restriction to find a string prefix; a restriction is a test conducted against a table to filter the rows of the table according to the criteria of the test. The restriction that clients should use for a scrolling prefix is as follows: For forward searching on a column sorted in ascending order, and for backward searching on a column sorted in descending order, pass in the lpRestriction parameter an SPropertyRestriction structure with relation RELOP_GE and the appropriate property tag and prefix value using the format tag GE prefix value.

Note  The type of prefix searching performed by FindRows is only useful when the search follows the same direction as the table organization. Implementers of the IMAPITable interface should note that in order to achieve the desired behavior, the comparison function implied by the RELOP_GE sent in the property restriction structure should be the same comparison function on which the table sort order is based.

Usually, FindRow searches forward from the specified bookmark. The calling implementation can set the search to move backward from the bookmark by setting the DIR_BACKWARD flag in the ulFlags parameter. Searching forward starts from the current bookmark; searching backward starts from the row prior to the bookmark. The end position of the search is just before the first row found that satisfied the restriction. FindRow returns the data of the found row.

If the row pointed to by the bookmark in the BkOrigin parameter no longer exists in the table and the table cannot establish a new position for the bookmark, FindRow returns MAPI_E_INVALID_BOOKMARK. If the row pointed to by BkOrigin no longer exists and the table is able to establish a new position for the bookmark, FindRow returns MAPI_W_POSITION_CHANGED.

If the bookmark used in BkOrigin is either BOOKMARK_BEGINNING or BOOKMARK_END, FindRow does not return an error value if no matching row is found. If the bookmark used in BkOrigin is BOOKMARK_CURRENT, FindRow can return MAPI_W_POSITION_CHANGED but not MAPI_E_INVALID_BOOKMARK, because there is always a current cursor position.

The PR_INSTANCE_KEY property column is required for all tables, and all implementations of FindRow are required to support calls seeking a row based on the PR_INSTANCE_KEY.

See Also

IMAPITable::CreateBookmark method, SPropertyRestriction structure, SRestriction structure


 IMAPITable::FreeBookmark

[New - Windows 95]

Releases a bookmark from memory.

Syntax

HRESULT FreeBookmark(BOOKMARK bkPosition)

Parameters

bkPosition

Input parameter containing a token representing the bookmark to be freed, as obtained from a call to the IMAPITable::CreateBookmark method.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Use the IMAPITable::FreeBookmark method to release a bookmark that is no longer needed. The bookmark is no longer valid after this call. When MAPI frees a table from memory, it also frees all associated bookmarks.

If the calling implementation passes one of the three predefined bookmarks to FreeBookmark to be freed, FreeBookmark ignores it and returns no error.

See Also

IMAPITable::CreateBookmark method


 IMAPITable::GetCollapseState

[New - Windows 95]

Returns the data necessary to rebuild the current table view.

Syntax

HRESULT GetCollapseState(ULONG ulFlags, ULONG cbInstanceKey, LPBYTE lpbInstanceKey, ULONG FAR * lpcbCollapseState, LPBYTE FAR * lppbCollapseState)

Parameters

ulFlags

Reserved; must be zero.

cbInstanceKey

Input parameter containing the size, in bytes, of the lpbInstanceKey parameter.

lpbInstanceKey

Input parameter pointing to the instance key (that is, the PR_INSTANCE_KEY property) identifying the row location within the table at which the current collapsed or expanded state should be rebuilt. The lpbInstanceKey parameter cannot be NULL; a selected row must be passed in.

lpcbCollapseState

Output parameter pointing to a variable containing the size, in bytes, of the lppbCollapseState parameter.

lppbCollapseState

Output parameter pointing to a variable where the pointer to structures containing data describing the current table view is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_BUSY

Another operation is in progress; it should be allowed to complete, or it should be stopped before this operation is attempted.

MAPI_E_NO_SUPPORT

The operation is not supported by one or more service providers.

Comments

Use the IMAPITable::GetCollapseState method to get the data necessary to rebuild a table view to its current collapsed or expanded state. Use GetCollapseState and the IMAPITable::SetCollapseState method together to present to the user, upon opening a table in your implementation, a table that in its expanded or collapsed state can be recognized as the table the user formerly viewed. Implementations of GetCollapseState commonly store the entire current state of all nodes of a table in the lppbCollapseState parameter.

To restore the expanded or collapsed state retrieved by GetCollapseState, your implementation calls SetCollapseState and rebuilds the stored state using the information in the structures saved in the lppbCollapseState parameter.

See Also

IMAPITable::SetCollapseState method


 IMAPITable::GetLastError

[New - Windows 95]

Returns a MAPIERROR structure containing information about the last error that occurred for a table object.

Syntax

HRESULT GetLastError(HRESULT hResult, ULONG ulFlags, LPMAPIERROR FAR * lppMAPIError)

Parameters

hResult

Input parameter containing the result returned for the last call on the table object that returned an error.

ulFlags

Input parameter containing a bitmask of flags controlling the type of the returned strings. The following flag can be set:

MAPI_UNICODE

Indicates the strings returned in the MAPIERROR structure returned in the lppMAPIError parameter are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

lppMAPIError

Output parameter pointing to a pointer to the returned MAPIERROR structure containing version, component, and context information for the error. The lppMAPIError parameter can be set to NULL if there is no MAPIERROR structure to return.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_BAD_CHARWIDTH

Either the MAPI_UNICODE flag was set and the implementation does not support Unicode, or MAPI_UNICODE was not set and the implementation only supports Unicode.

Comments

Use the IMAPITable::GetLastError method to retrieve information to display as a message to the user regarding the last error returned from a method call on the table object.

To release all the memory allocated by MAPI for the MAPIERROR structure, client applications need only call the MAPIFreeBuffer function.

The return value from GetLastError must be S_OK for an implementation to make use of the MAPIERROR structure. Even if the return value is S_OK, it is still possible that a MAPIERROR structure won't be returned. If the implementation cannot determine what the last error was, or if a MAPIERROR structure is not available for that error, a pointer to NULL is returned in the lppMAPIError parameter instead.

See Also

MAPIERROR structure, MAPIFreeBuffer function


 IMAPITable::GetRowCount

[New - Windows 95]

Returns the total number of rows in a table.

Syntax

HRESULT GetRowCount(ULONG ulFlags, ULONG FAR * lpulCount)

Parameters

ulFlags

Reserved; must be zero.

lpulCount

Output parameter pointing to a variable holding the total number of rows in the table view.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_BUSY

Another operation is in progress; it should be allowed to complete, or it should be stopped, before this operation is attempted.

MAPI_E_NO_SUPPORT

The operation is not supported by one or more service providers.

MAPI_W_APPROX_COUNT

The call succeeded, but an approximate row count was returned because the exact row count could not be determined. Use the HR_FAILED macro to test for this warning, but the call should be handled as a successful return.

Comments

Use the IMAPITable::GetRowCount method to find out how many rows a table holds before making a call to the IMAPITable::QueryRows method to return rows of data from that table. If the row count returned in the lpulCount parameter is less than 20, QueryRows can be called on the whole table. If the row count returned in lpulCount is greater than 20, the calling implementation might limit the rows to be returned with QueryRows.

Some providers do not support GetRowCount and return MAPI_E_NO_SUPPORT. If GetRowCount is not supported, the client application should call the IMAPITable::QueryPosition method to determine the current cursor position in the table. QueryPosition retrieves the fractional position of the cursor within the table.

If GetRowCount cannot determine a table's exact row count (that is, if the value returned in the lpulCount parameter is approximate and not exact), it returns MAPI_W_APPROX_COUNT. This result can occur on systems in which an exact count expends too much memory to perform, for example in systems that use large tables that are sparsely populated.

When GetRowCount is temporarily unable to return the number of rows in a table, it returns MAPI_E_BUSY. This result can occur because of asynchronous operations in progress. If a client application deduces from a return value of MAPI_E_BUSY that asynchronous operations are in progress, it can call the asynchronous method IMAPITable::WaitForCompletion, then once the asynchronous operations are complete retry the call to GetRowCount. Another way to detect whether asynchronous operations are in progress is to call the IMAPITable::GetStatus method, which returns the status and type of a table.

See Also

IMAPITable::GetStatus method, IMAPITable::QueryPosition method, IMAPITable::QueryRows method, IMAPITable::WaitForCompletion method


 IMAPITable::GetStatus

[New - Windows 95]

Returns the status and type of a table.

Syntax

HRESULT GetStatus(ULONG FAR * lpulTableStatus, ULONG FAR * lpulTableType)

Parameters

lpulTableStatus

Output parameter pointing to a variable in which the status of the table is placed. One of the following values can be returned:

TBLSTAT_COMPLETE

No operations are in progress.

TBLSTAT_QCHANGED

The contents of the table have changed. This status is not returned for changes occurring as a result of calls that sort or restrict the table; rather, it indicates unexpected changes.

TBLSTAT_SORTING

A sort operation is in progress.

TBLSTAT_SORT_ERROR

An error occurred during sorting.

TBLSTAT_SETTING_COLS

A column-setting operation is in progress.

TBLSTAT_SETCOL_ERROR

An error occurred while columns were being set.

TBLSTAT_RESTRICTING

A restriction operation is in progress.

TBLSTAT_RESTRICT_ERROR

An error occurred during restricting.

lpulTableType

Output parameter pointing to a variable in which the type of the table is placed. There are three table types:

TBLTYPE_DYNAMIC

The table's contents are dynamic and can change as the underlying data changes.

TBLTYPE_SNAPSHOT

The table is static, and the contents do not change when the underlying data changes.

TBLTYPE_KEYSET

The rows within the table are fixed, but the values within these rows are dynamic and can change as the underlying data changes.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Use the IMAPTable::GetStatus method to gather information on the type and current status of a table. GetStatus can be used in conjunction with the IMAPITable::Restrict method to poll the status of updates to the table occurring as the result of a new restriction (a restriction is a test conducted against a table to filter table rows according to the criteria of the test). In addition, GetStatus can be used with the IMAPITable::SortTable method to monitor the status of a sort operation and with the IMAPITable::SetColumns method to see when a column-setting operation has completed.

See Also

IMAPITable::Restrict method, IMAPITable::SetColumns method, IMAPITable::SortTable method


 IMAPITable::QueryColumns

[New - Windows 95]

Returns either the current list of columns for a table or the full list of columns available for the table.

Syntax

HRESULT QueryColumns(ULONG ulFlags, LPSPropTagArray FAR * lpPropTagArray)

Parameters

ulFlags

Input parameter containing a bitmask of flags used to control what table column information is returned. The following flag can be set:

TBL_ALL_COLUMNS

Returns all available columns.

lpPropTagArray

Output parameter pointing to a variable where the returned SPropTagArray structure containing a counted array of property tags is placed. Each property tag identifies a particular table column.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_BUSY

Another operation is in progress; it should be allowed to complete, or it should be stopped, before this operation is attempted.

Comments

Use the IMAPITable::QueryColumns method to get any one of the following:

•	The current list of table columns for a table view as set when the table was created

•	The current list of columns for a table view as set by a call to the IMAPITable::SetColumns method

•	The full list of columns available for the table

To retrieve the entire set of columns available for the table view, your implementation should set the TBL_ALL_COLUMNS flag in the ulFlags parameter. Otherwise, QueryColumns returns the provider's current table columns, typically those columns that are cached. You can retrieve additional columns by calling IMAPITable::SetColumns.

To free the memory holding the structure returned in the lpPropTagArray parameter, your implementation uses the MAPIFreeBuffer function.

See Also

IMAPITable::SetColumns method, MAPIFreeBuffer function, SPropTagArray structure


 IMAPITable::QueryPosition

[New - Windows 95]

Retrieves the row within a table where the cursor is currently positioned, based on a fractional value indicating the cursor position.

Syntax

HRESULT QueryPosition(ULONG FAR * lpulRow, ULONG FAR * lpulNumerator, ULONG FAR * lpulDenominator)

Parameters

lpulRow

Output parameter pointing to the variable in which the current row number is placed. The row number is zero-based, with the first row in the table being zero.

lpulNumerator

Output parameter pointing to the variable in which is placed the numerator of the fraction representing the table position.

lpulDenominator

Output parameter pointing to the variable in which is placed the denominator of the fraction representing the table position. The lpulDenominator parameter cannot be zero.

Comments

Use the IMAPITable::QueryPosition method to determine the current row based on a fractional value that approximates the position of the scroll box in the scroll bar based on the number of rows in the table. For example, in a table containing 100 rows, if the scroll box indicates a cursor position 3/4 into the table, QueryPosition returns a value of 75 in the lpulNumerator parameter, 100 in the lpulDenominator parameter, and 75/100 in the lpulRow parameter. The value in lpulDenominator is not guaranteed to be the number of rows in the table, and QueryPosition cannot identify the exact row that the cursor is positioned in. MAPI defines the current row as the next row to be read.

Note that calculation of the QueryPosition return values can expend large amounts of memory in cases where the implementation must provide a useful cursor position value for a large categorized table. If QueryPosition cannot determine the current row, it returns a value of 0xFFFFFFFF in the lpulRow parameter; this result can occur on systems where the QueryPosition calculation requires too much memory to perform. Applications that receive such a return should call the IMAPITable::SeekRowApprox method to retrieve an approximate fractional value for the cursor position.

Calling SeekRowApprox with the same fraction as returned by QueryPosition does not necessarily reposition the cursor to the same row.

See Also

IMAPITable::SeekRowApprox method


 IMAPITable::QueryRows

[New - Windows 95]

Returns one or more rows from a table, beginning at the current cursor position.

Syntax

HRESULT QueryRows(LONG lRowCount, ULONG ulFlags, LPSRowSet FAR * lppRows)

Parameters

lRowCount

Input parameter containing the number of rows requested.

ulFlags

Input parameter containing a bitmask of flags used to control how rows are returned. The following flag can be set:

TBL_NOADVANCE

Prevents the cursor from advancing, so that the position value BOOKMARK_CURRENT is always returned.

lppRows

Output parameter pointing to a variable where the pointer to the returned SRowSet structure is stored. The SRowSet holds the set of table rows returned.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_BUSY

Another operation is in progress; it should be allowed to complete, or it should be stopped, before this operation is attempted.

Comments

Use the IMAPITable::QueryRows method to get rows of data from a table.

If the value in the lRowCount parameter is positive, rows are read starting at the current position and reading forward. If the value in the lRowCount parameter is negative, the cursor position moves backward the indicated number of rows and then the rows are read in forward order.

The cRows member in the SRowSet structure returned in the lppRows parameter indicates the number of rows returned. If zero rows are returned, the cursor was already positioned at the beginning or end of the table. Fewer rows might be returned than are requested if memory or implementation limits are reached or in situations when QueryRows reaches the beginning or end of the table before returning all requested rows. Service providers cannot return zero rows unless the current position is at the beginning or end of the table. If fewer rows than requested are returned, the implementation acts as if a smaller value was passed in the lRowCount parameter.

QueryRows supports inclusion of one or more property tags of PR_NULL to reserve empty property-value slots in the SPropValue arrays within the lppRows SRowSet. This functionality enables calling implementations that must later add properties to the SRowSet to avoid having to copy a new SPropValue to the SRowSet before adding a new property.

Upon completion of a QueryRows call, the table cursor is positioned by default at the row following the last row returned. However, if the TBL_NOADVANCE flag is set in the ulFlags parameter, the table cursor is positioned at the first of the returned rows.

The columns returned in each row contain properties as previously specified by a call to the IMAPITable::SetColumns method. If no SetColumns call has been made, the columns returned reflect the default column set for that particular type of table. The number of properties and their ordering is the same for each table row. If a property does not exist in a row, the property value column returned holds a property type of PT_ERROR and a property value of MAPI_E_NOT_FOUND. Other errors in reading individual properties are indicated in a similar manner following the model used by the IMAPIProps::GetProps method.

If the calling application requests zero rows, then QueryRows returns the value MAPI_E_INVALID_PARAMETER. If an asynchronous operation is in progress, a call to QueryRows can return MAPI_E_BUSY. If a client application receives MAPI_E_BUSY in such a situation, it can call the asynchronous method IMAPITable::WaitForCompletion, then once the asynchronous operation is complete retry the call to QueryRows.

For most complex MAPI data structures, your implementation uses the MAPIFreeBuffer function to free the structure by freeing the top level pointer. QueryRows is an exception to this general behavior. Memory used for the properties held in the SRow structures that make up the SRowSet in the lppRows parameter and for the rgPropVals members of the ADRENTRY structures is separately allocated for each row, and memory for each row must be separately freed by a call to MAPIFreeBuffer. The SRowSet structure itself must also be freed. Thus, to free all the memory returned for 10 rows requires 11 calls to MAPIFreeBuffer. This process might seem complex, but freeing memory for each row separately enables client applications to free different rows at different times. When a call to QueryRows returns zero, however, indicating the beginning or end of the table, only the SRowSet structure itself needs to be freed.

See Also

ADRENTRY structure, FreeProws function, HrQueryAllRows function, IMAPIProp::GetProps method, IMAPITable::SetColumns method, IMAPITable::WaitForCompletion method, MAPIFreeBuffer function, SRow structure, SRowSet structure


 IMAPITable::QuerySortOrder

[New - Windows 95]

Retrieves the current sort order for a table.

Syntax

HRESULT QuerySortOrder(LPSSortOrderSet FAR * lppSortCriteria)

Parameters

lppSortCriteria

Output parameter pointing to a variable where the pointer to the returned SSortOrderSet structure holding the current sort order is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_BUSY

Another operation is in progress; it should be allowed to complete, or it should be stopped, before another operation is attempted.

Comments

Use the IMAPITable::QuerySortOrder method to retrieve the current sort order for a table. The sort order is returned in an SSortOrderSet structure.

For the following cases, QuerySortOrder returns an SSortOrderSet structure holding zero columns:

•	If the table is unsorted.

•	If the provider does not have information on how the table is sorted.

•	If the provider cannot express the sort order within the capabilities of an SSortOrderSet structure.

In cases where a client application has called IMAPITable::SortTable with a SSortOrderSet structure containing zero columns, the sort order is removed and the default sort order is applied. Subsequent calls to QuerySortOrder can return zero or more columns as being sorted, depending on the implementation of the service provider. More columns than are in the present view can be returned.

To free the returned SSortOrderSet structure, the application uses the MAPIFreeBuffer function.

See Also

IMAPITable::SortTable method, MAPIFreeBuffer function, SSortOrderSet structure


 IMAPITable::Restrict

[New - Windows 95]

Applies a restriction to a table, reducing the rows visible to only those matching the restriction criteria.

Syntax

HRESULT Restrict(LPSRestriction lpRestriction, ULONG ulFlags)

Parameters

lpRestriction

Input parameter pointing to an SRestriction structure defining the conditions of the restriction. Passing NULL in the lpRestriction parameter removes the current restriction criteria.

ulFlags

Input parameter containing a bitmask of flags used to control how returns are made when asynchronous operations are in progress. The following flags can be set:

TBL_ASYNC

Starts the operation asynchronously and returns before the operation completes.

TBL_BATCH

Defers evaluation until the results of the operation are required.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_BUSY

Another operation is in progress; it should be allowed to complete, or it should be stopped, before another operation is attempted.

Comments

Use the IMAPITable::Restrict method to set a restriction on a table view. MAPI discards the previous restriction, if any. A restriction should be thought of as a filter; it does not remove the underlying data. Rather, it simply filters the data so only some rows are seen. To discard the current restriction without creating a new one, pass NULL in the lpRestriction parameter.

A restriction on a column of multivalued properties works just as does a restriction on a column of single-valued properties. To reference columns of multivalued properties on which a restriction is to operate, the restriction must have the MVI_FLAG flag set. This requirement seems straightforward, but it means that an SPropertyRestriction structure can have a ulPropTag member different from prop.ulPropTag.

Restrictions on a column of multivalued properties without the MVI_FLAG being set will treat the column's values as a totally ordered tuple. A comparison of two multivalued columns compares the column elements in order, reporting the relation of the columns at the first inequality, and returns equality only if the columns compared contain the same values in the same order. If one column has fewer values than the other, the reported relation is that of a null value to the other value.

A call to Restrict completes its operation before returning, unless different behavior in situations where asynchronous operations are in progress is indicated by the flag set in the ulFlags parameter. If the TBL_BATCH flag is set in ulFlags, an application can defer the restriction operation until it requires the results. If the TBL_ASYNC flag is set in ulFlags, the Restrict operation can begin synchronously and return before the operation completes.

Asynchronous calls in progress when a Restrict call is required can be stopped by using the IMAPITable::Abort method. Most implementations of Restrict return the value MAPI_E_BUSY if a call is made to start an asynchronous restriction operation while a previous asynchronous call is still running.

All bookmarks for a table are discarded when a call to Restrict is made, and the BOOKMARK_CURRENT bookmark, indicating the current cursor position, is set to the beginning of the table.

Note that service providers must not generate notifications for table rows that are hidden from view by calls to Restrict.

See Also

IMAPITable::Abort method, IMAPITable::FindRow method, IMAPITable::GetRowCount method, IMAPITable::QueryRows method, SPropertyRestriction structure


 IMAPITable::SeekRow

[New - Windows 95]

Moves the cursor to a specific position in a table.

Syntax

HRESULT SeekRow(BOOKMARK bkOrigin, LONG lRowCount, LONG FAR * lplRowsSought)

Parameters

bkOrigin

Input parameter indicating the bookmark position from which the seek operation starts seeking. A bookmark can be created using the IMAPITable::CreateBookmark method, or one of the following predefined values can be used:

BOOKMARK_BEGINNING

Seeks from the beginning of the table.

BOOKMARK_CURRENT

Seeks from the row in the table where the cursor is located.

BOOKMARK_END

Seeks from the end of the table.

lRowCount

Input parameter indicating the signed number of rows to move, starting from the bookmark in the BkOrigin parameter.

lplRowsSought

Output parameter pointing to a variable in which the number of rows actually searched through is returned. Passing NULL in the lplRowsSought parameter indicates that a number of rows searched need not be returned.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_BUSY

Another operation is in progress; it should be allowed to complete, or it should be stopped, before another operation is attempted.

MAPI_E_INVALID_BOOKMARK

The bookmark is invalid because it has been removed or because it is beyond the last row requested.

MAPI_W_POSITION_CHANGED

The call succeeded, but the bookmark used in the operation is no longer on the same row as when it was last used, or if it hasn't been used, the bookmark is no longer in the same position as when it was created. Use the HR_FAILED macro to test for this warning, although the call should be handled as a successful return.

Comments

Use the IMAPITable::SeekRow method to establish a new BOOKMARK_CURRENT position for the cursor. The lRowCount parameter indicates the number of rows the cursor moves. The number of rows in the lRowCount parameter should be kept to less than 50; use the IMAPITable::SeekRowApprox method if you need to seek past a larger number of rows.

If the resulting position is beyond the last row of the table, the cursor is positioned after the last row; if the resulting position is before the first row of the table, the cursor is placed at the beginning of the first row. To indicate a backward move for SeekRow, pass a negative value in the lRowCount parameter. To seek to the beginning of the table, pass zero in the lRowCount parameter and the flag BOOKMARK_BEGINNING in the bkOrigin parameter. If there are large numbers of rows in the table, the seek operation can be slow.

SeekRow returns the number of rows actually searched through, positive or negative, in the variable pointed to by the lplRowsSought parameter. In normal operation, it should return the same value for lplRowsSought as passed in for the lRowCount parameter, unless the search reached the beginning or end of the table.

The operation of SeekRow can be slower than otherwise if the calling application requires a number of rows to be returned in the lplRowsSought parameter. If the calling application does not require a return count, it should pass NULL for the lplRowsSought parameter.

If the row pointed to by bkOrigin no longer exists in the table and the provider cannot establish a new position for the bookmark, SeekRow returns the value MAPI_E_INVALID_BOOKMARK. If the row pointed to by bkOrigin no longer exists and the provider is able to establish a new position for the bookmark, SeekRow returns the value MAPI_W_POSITION_CHANGED.

A bookmark pointing to a row that is no longer in the table view can still be used. If an application attempts to move the cursor to such a bookmark, the cursor moves to the next visible row and stops there. A call using a bookmark pointing to a collapsed row returns the value MAPI_W_POSITION_CHANGED. Providers can move bookmarks for positions collapsed out of view either at the time of use or at the time the row is collapsed. If a bookmark is moved at the time the row is collapsed, a bit must be retained in the bookmark that indicates whether the bookmark has moved since its last use or, if it has never been used, since its creation.

See Also

IMAPITable::CreateBookmark method, IMAPITable::FindRow method, IMAPITable::QueryRows method, IMAPITable::SeekRowApprox method


 IMAPITable::SeekRowApprox

[New - Windows 95]

Moves the cursor to an approximate fractional position in a table.

Syntax

HRESULT SeekRowApprox(ULONG ulNumerator, ULONG ulDenominator)

Parameters

ulNumerator

Input parameter pointing to the variable indicating the numerator of the fraction representing the table position. If the ulNumerator parameter is zero, it points to the beginning of the table regardless of the value of the fraction's denominator. If the ulNumerator value is equal to the value in the ulDenominator parameter, the cursor is positioned after the last table row.

ulDenominator

Input parameter pointing to the variable in which the denominator of the fraction representing the table position is placed. The ulDenominator parameter cannot be zero.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_BUSY

Another operation is in progress; it should be allowed to complete, or it should be stopped, before another operation is attempted.

Comments

Use the IMAPITable::SeekRowApprox method to provide the data used to support scroll bar implementations. For example, if the user positions the scroll box 2/3 down the scroll bar, the calling application can model that action by calling SeekRowApprox and passing in an equivalent fractional value using the ulNumerator and ulDenominator parameters. The SeekRowApprox search is always absolute from the beginning of the table. To move to the end of the table, the values in the ulNumerator and ulDenominator parameters must be the same. Any numbering scheme can be used based on what is convenient for your application; 9/10, 90/100, or 900/1000.

The cursor position in a table after a call to SeekRowApprox is heuristically the fraction and might not be exact. For example, certain providers can implement a table on top of a binary tree, treating the table's halfway point as the top of the tree for performance reasons. If the tree is not balanced, then the halfway point used might not be exactly halfway through the table.


 IMAPITable::SetCollapseState

[New - Windows 95]

Reestablishes the expanded or collapsed state of the table view that was saved by a call to the IMAPITable::GetCollapseState method.

Syntax

HRESULT SetCollapseState(ULONG ulFlags, ULONG cbCollapseState, LPBYTE pbCollapseState, BOOKMARK FAR * lpbkLocation)

Parameters

ulFlags

Reserved; must be zero.

cbCollapseState

Input parameter containing the number of bytes in the pbCollapseState parameter.

pbCollapseState

Input parameter pointing to the structures containing the saved table view.

lpbkLocation

Output parameter pointing to a bookmark identifying the row location within the table at which the indicated table state should be rebuilt. This bookmark identifies the same row or rows pointed to by the instance key held in the lpbInstanceKey parameter on the call to the IMAPITable::GetCollapseState method.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_BUSY

Another operation is in progress; it should be allowed to complete, or it should be stopped before this operation is attempted.

MAPI_E_UNABLE_TO_COMPLETE

The requested operation could not be completed.

Comments

Use the IMAPITable::SetCollapseState method to reestablish the expanded or collapsed state of the table view that was saved by a call to the IMAPITable::GetCollapseState method. Use SetCollapseState and GetCollapseState together to present to the user, upon opening a table in your application, a table that in its expanded or collapsed state can be recognized as the table the user formerly viewed.

To restore an entire table state, SetCollapseState uses the structures pointed to in the pbCollapseState parameter, which hold a restriction or sort order that defines the table view.

To call SetCollapseState, an application must have previously used GetCollapseState. It is expected that the column state should be the same as was saved in the GetCollapseState call; if the client application fails to reset the columns, the results of the operation are unpredictable.

Note that service providers must not generate notifications for table rows that are hidden from view by calls to SetCollapseState.

See Also

IMAPITable::CreateBookmark method, IMAPITable::FreeBookmark method, IMAPITable::GetCollapseState method


 IMAPITable::SetColumns

[New - Windows 95]

Sets the order of columns in table rows to be returned by the IMAPITable::QueryRows method.

Syntax

HRESULT SetColumns(LPSPropTagArray lpPropTagArray, ULONG ulFlags)

Parameters

lpPropTagArray

Input parameter pointing to an SPropTagArray structure containing a counted array of property tags. Each property tag identifies a particular table column. Passing zero properties in the lpPropTagArray parameter results in the IMAPITable::SetColumns method returning the value MAPI_E_INVALID_PARAMETER.

ulFlags

Input parameter containing a bitmask of flags used to control the return of an asynchronous call to SetColumns, for example, when SetColumns is used in notification. The following flags can be set:

TBL_ASYNC

Starts the operation asynchronously and returns before the operation completes.

TBL_BATCH

Defers evaluation until the results of the operation are required.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_BUSY

Another operation is in progress; it should be allowed to complete, or it should be stopped, before another operation is attempted.

Comments

Use the IMAPITable::SetColumns method to control the order of the property values returned for each table row by an IMAPITable::QueryRows call. Some service providers allow a SetColumns call to order only table columns that are part of the available columns for a table view. Other providers allow a SetColumns call to order all table columns, including properties that are not in the original column set.

SetColumns supports inclusion of one or more PR_NULL property types in the property tag array in the lpPropTagArray parameter. Such property tags are used by QueryRows to reserve empty slots in SPropValue arrays in the SRowSet structure that represents the table rows it returns. This functionality enables calling applications that must later add properties to this SRowSet to avoid having to copy a new SPropValue array before adding a new property.

To provide multiple row instances for a multivalued property with SetColumns, your application applies the MVI_FLAG flag to a table column's property type. To do so, it specifies MVI_PROP(ulPropTag) in the SPropTagArray structure in lpPropTagArray instead of a single-valued property tag. MVI_FLAG is only meaningful for multivalued properties; it sets both bits, including MVI_INSTANCE. MAPI ignores MVI_FLAG if it is applied to a single-valued property.

If a call to SetColumns changes the order of table columns that contain multivalued instance properties, the call can change the number of rows in the table. This situation is the only one in which a SetColumns call can change the number of table rows. If a SetColumns call changes the number of rows in a table, all bookmarks for the table are discarded. If a call to SetColumns adds or removes one or more columns, the call can change the column set.

A call to SetColumns completes its operation before returning, unless different behavior in situations where asynchronous operations are in progress is indicated by the flag set in the ulFlags parameter. If the TBL_BATCH flag is set in ulFlags, an application can defer setting table columns until it requires the results of the operation. If the TBL_ASYNC flag is set in ulFlags, the SetColumns operation can begin synchronously and return before completing. When the TBL_BATCH flag is set on asynchronous operations, providers should return a property type of PT_ERROR and a value of NULL for columns that are not supported.

When a SetColumns call is required, asynchronous calls in progress can be stopped by using the IMAPITable::Abort method. Most applications of SetColumns return the value MAPI_E_BUSY if a call is made to start an asynchronous operation while a previous asynchronous call is still running.

Note that service providers must not generate notifications for table rows that are hidden from view by calls to Restrict. When sending table notifications, providers must order the properties in their column set in the same order as the column set was in when the request for notification was created.

See Also

HrQueryAllRows function, IMAPITable::Abort method, IMAPITable::GetRowCount method, IMAPITable::QueryColumns method, IMAPITable::QueryRows method, IMAPITable::Restrict method, IMAPITable::SortTable method, SPropTagArray structure, SPropValue structure, SRowSet structure, TABLE_NOTIFICATION structure


 IMAPITable::SortTable

[New - Windows 95]

Sorts table rows based on the sort criteria provided.

Syntax

HRESULT SortTable(LPSSortOrderSet lpSortCriteria, ULONG ulFlags)

Parameters

lpSortCriteria

Input parameter pointing to an SSortOrderSet structure containing sort criteria to be applied. Passing an SSortOrderSet containing zero columns indicates your application doesn't require the table to be sorted or doesn't care about the table's sort order.

ulFlags

Input parameter containing a bitmask of flags used to control the return of an asynchronous call to the IMAPITable::SortTable method. The following flags can be set:

TBL_ASYNC

Starts the operation asynchronously and returns before the operation completes.

TBL_BATCH

Defers evaluation until the results of the operation are required.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_BUSY

Another operation is in progress; it should be allowed to complete, or it should be stopped, before another operation is attempted.

MAPI_E_NO_SUPPORT

The service provider either does not support changes to its objects or does not support notification of changes.

MAPI_E_TOO_COMPLEX

Although the client application has passed valid parameters, the specified sort operation, typically a sub-restriction, is too complex for the implementation and could not be performed.

Comments

Use the IMAPITable::SortTable method to reorder the rows in a table view.

MAPI does not require service providers to be able to sort tables. To indicate table sorting is unavailable, providers should return the value MAPI_E_NO_SUPPORT for a SortTable call.

Address book providers commonly do not support table sorting. Message store providers commonly support sorting to the extent that they retain the sort order of folders that results when a sort operation is applied to a full table (that is, a table with no restrictions).

Some implementations allow sorting to be done on any table column. Some require that sorting only affect the current list of columns for a table view; in such an implementation, columns not set in the table view are not affected by a SortOrder call. Some applications require that only active columns be sorted. If a sort operation is requested for a column that cannot be sorted, the value MAPI_E_TOO_COMPLEX is returned.

Calling SortTable with zero columns in the SSortOrderSet structure in the lpSortCriteria parameter indicates your application doesn't require the table affected to be sorted or doesn't require information on the table's sort order. The set of currently active columns is returned. When your application passes zero columns in lpSortCriteria for a particular table, it can still call IMAPITable::QuerySortOrder to get the current sort order for that table.

A sort operation performed on a column of multivalued properties without MVI_FLAG being set will treat the column's values as a totally ordered tuple. A comparison of two multivalued columns compares the column elements in order, reporting the relation of the columns at the first inequality, and returns equality only if the columns compared contain the same values in the same order. If one column has fewer values than the other, the reported relation is that of a null value to the other value.

A call to SortTable completes its operation before returning, unless different behavior in situations where asynchronous operations are in progress is indicated by the flag set in the ulFlags parameter. If the TBL_BATCH flag is set in ulFlags, an application can defer the restriction operation until it requires the results. If the TBL_ASYNC flag is set in ulFlags, the SortTable operation can begin synchronously and return before the operation completes.

Asynchronous calls in progress when a SortTable call is required can be stopped by using the IMAPITable::Abort method. Most implementations of SortTable return the value MAPI_E_BUSY if a call is made to start an asynchronous restriction operation while a previous asynchronous call is still running.

All bookmarks for a table are invalidated and should be deleted when a call to SortTable is made, and the BOOKMARK_CURRENT bookmark, indicating the current cursor position, should be set to the beginning of the table.

SortTable can return the value MAPI_E_TOO_COMPLEX under any of the following conditions:

•	The implementation does not support the sort order requested in the ulOrder member of the SSortOrderSet.

•	The number of columns to be sorted, as specified in the cSorts member in the SSortOrderSet, is larger than the implementation can handle.

•	A sort operation is requested for a property column that the implementation cannot sort.

•	A sort operation is requested, as indicated by a property tag in the SSortOrderSet, based on a property that is not in the available or active set and the application does not support sorting on properties not in the available set.

•	One property is specified multiple times in a sort order set, as indicated by multiple instances of the same property tag, and the application cannot perform such a sort operation.

•	A sort operation based on multivalued property columns is requested using the MVI flag and the application does not support sorting on multivalued properties.

•	A property tag for a property in the lpSortCriteria SSortOrderSet specifies a property or type that the application does not support.

•	A sort operation other than one that proceeds through the table from the PR_RENDERING_POSITION property forward is specified for an attachment table that only supports this type of sorting.

For best performance, implementations of SortTable should establish their column sets with SetColumns and then their restrictions with Restrict, before sorting the table.

See Also

IMAPITable::Abort method, IMAPITable::GetRowCount method, IMAPITable::QueryColumns method, IMAPITable::QuerySortOrder method, IMAPITable::SetColumns method, SSortOrderSet structure


 IMAPITable::Unadvise

[New - Windows 95]

Removes a table's registration for notification changes previously established with a call to the IMAPITable::Advise method.

Syntax

HRESULT Unadvise(ULONG ulConnection)

Parameters

ulConnection

Input parameter containing the number of the registration connection previously returned by a call to IMAPITable::Advise.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Use the IMAPITable::Unadvise method to cancel notifications for the table object. To do so, Unadvise releases the pointer to the advise sink object passed in the lpAdviseSink parameter in the previous call to IMAPITable::Advise. As part of discarding the pointer to the advise sink, the advise sink's IUnknown::Release method is called. Generally, Release is called during the Unadvise call, but if another thread is in the process of calling IMAPIAdviseSink::OnNotify for the advise sink, the Release call is delayed until the OnNotify method returns.

See Also

IMAPIAdviseSink::OnNotify method, IMAPITable::Advise method


 IMAPITable::WaitForCompletion

[New - Windows 95]

Suspends an application while asynchronous operations occur on a table.

Syntax

HRESULT WaitForCompletion(ULONG ulFlags, ULONG ulTimeout, ULONG FAR * lpulTableStatus)

Parameters

ulFlags

Reserved; must be zero.

ulTimeout

Input parameter indicating the maximum number of milliseconds to wait for asynchronous operations to complete. If the operations do not complete in the time specified, the IMAPITable::WaitForCompletion method should return the value MAPI_E_TIMEOUT. If 0xFFFFFFFF is sent in the ulTimeout parameter, your application pauses until the operation completes, however long that takes.

lpulTableStatus

Output parameter pointing to a variable in which is placed the most recent status of the table for which WaitForCompletion is called. If your application passes NULL in the lpulTableStatus parameter, no status information is returned. If a nonzero HRESULT is returned, including MAPI_E_TIMEOUT, the contents of the lpulTableStatus parameter are undefined.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NO_SUPPORT

The operation is not supported by MAPI or by one or more service providers.

MAPI_E_TIMEOUT

The operation did not complete in the specified time.

Comments

Use the IMAPITable::WaitForCompletion method to suspend your application as any asynchronous operations currently underway for a table are processed. WaitForCompletion can allow the asynchronous operations either to complete or to run for a number of milliseconds, as indicated by the ulTimeout parameter, before being interrupted. To detect asynchronous operations in progress, your application uses the IMAPITable::GetStatus method.

See Also

IMAPITable::GetRowCount method, IMAPITable::GetStatus method, IMAPITable::Restrict method, IMAPITable::SetColumns method, IMAPITable::SortTable method


 IMAPIViewAdviseSink : IUnknown

[New - Windows 95]

The IMAPIViewAdviseSink interface is implemented by form viewers. Its methods are called by a form to notify a viewer that some event has occurred in the form.

At a Glance

Specified in header file:	MAPIFORM.H
Object that supplies this interface:	View advise sink object
Corresponding pointer type:	LPMAPIVIEWADVISESINK
Implemented by:	Form viewers
Called by:	Forms
Vtable Order

OnShutdown	Notifies a form viewer that a form is being closed.
OnNewMessage	Notifies a form viewer that either a new or an existing message has been loaded in a form.
OnPrint	Notifies a form viewer of the printing status of a form.
OnSubmitted	Notifies a form viewer that a message composed using a particular form has been submitted to the MAPI spooler.
OnSaved	Notifies a form viewer that a message composed using a particular form has been saved.


 IMAPIViewAdviseSink::OnShutdown

[New - Windows 95]

Notifies a form viewer that a form is being closed.

Syntax

HRESULT OnShutdown()

Parameters

None

Return Values

S_OK

The call succeeded.


 IMAPIViewAdviseSink::OnNewMessage

[New - Windows 95]

Notifies a form viewer that either a new or an existing message has been loaded in a form.

Syntax

HRESULT OnNewMessage()

Parameters

None

Return Values

S_OK

The call succeeded.

Comments

A form calls the IMAPIViewAdviseSink::OnNewMessage method whenever a message is loaded in the form using either the IPersistMessage::InitNew or IPersistMessage::Load method. A viewer will often elect to release any IMAPIForm interfaces it has open at this point because the existing form object no longer points to the message the viewer was formerly viewing.

See Also

IMAPIForm : IUnknown interface, IPersistMessage::InitNew method, IPersistMessage::Load method


 IMAPIViewAdviseSink::OnPrint

[New - Windows 95]

Notifies a form viewer of the printing status of a form.

Syntax

HRESULT OnPrint(ULONG dwPageNumber, HRESULT hrStatus)

Parameters

dwPageNumber

Input parameter holding the number of the last page printed.

hrStatus

Input parameter holding an HRESULT variable showing the status of the print job. The following values can be used to indicate status:

S_FALSE

The printing job is finished successfully.

S_OK

The printing job is in progress.

FAILED

The printing job was terminated due to a failure.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_USER_CANCEL

The user canceled the operation, typically by clicking the cancel button in a dialog box.

Comments

A form calls the IMAPIViewAdviseSink::OnPrint method while printing to inform the current view of printing progress. If the printing job involves multiple pages, OnPrint can be called after each page is printed with the page number for the last page printed in the dwPageNumber parameter and S_OK in the hrStatus parameter to indicate that the printing job is proceeding. When the printing job is complete, OnPrint should be called with the page number of the last page printed in dwPageNumber and S_FALSE in hrStatus.


 IMAPIViewAdviseSink::OnSaved

[New - Windows 95]

Notifies a form viewer that the message in the form object has been saved.

Syntax

HRESULT OnSaved()

Parameters

None

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

A form object calls the IMAPIViewAdviseSink::OnSaved method after the current message has been successfully saved. Its doing so permits viewers to update their windows to reflect changes to the message.


 IMAPIViewAdviseSink::OnSubmitted

[New - Windows 95]

Notifies a form viewer that the current message has been submitted to the MAPI spooler.

Syntax

HRESULT OnSubmitted()

Parameters

None

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

A form object calls the IMAPIViewAdviseSink::OnSubmitted method after a call to IMAPIMessageSite::SubmitMessage has returned successfully. After OnSubmitted is called, viewers can work on the assumption the message has been updated and can update their windows.

See Also

IMAPIMessageSite::SubmitMessage method


 IMAPIViewContext : IUnknown

[New - Windows 95]

The IMAPIViewContext interface is implemented by form viewers to support form commands that activate the next or previous message, or that print or save the current message.

At a Glance

Specified in header file:	MAPIFORM.H
Object that supplies this interface:	View context object
Corresponding pointer type:	LPMAPIVIEWCONTEXT
Implemented by:	Form viewers
Called by:	Form objects
Vtable Order

SetAdviseSink	Registers a form object for notifications of changes to a view's status state.
ActivateNext	Activates the next or previous message in a view.
GetPrintSetup	Retrieves the current print setup so as to print the current message.
GetSaveStream	Retrieves the stream to place a textized version of the current message.
GetViewStatus	Retrieves the current viewer status state.


 IMAPIViewContext::ActivateNext

[New - Windows 95]

Activates the next or previous message in a view.

Syntax

HRESULT ActivateNext(ULONG ulDir, LPCRECT prcPosRect)

Parameters

ulDir

Input parameter containing a status value indicating which next message to activate. The value can be one of the following flags:

VCDIR_DELETE

Activates the next message because the current message has been deleted.

VCDIR_MOVE

Activates the next message because the current message has been moved.

VCDIR_NEXT

Activates the next message in the view order.

VCDIR_PREV

Activates the previous message in the view order.

prcPosRect

Input parameter pointing to a RECT structure used to display the next message.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

S_FALSE

The call succeeded but a different type of form was opened; call the IMAPIForm::ShutdownForm method for your form object.

Comments

Form objects call the IMAPIViewContext::ActivateNext method to change the current message being displayed to the user. The ulDir parameter is used to inform the form viewer of the reason for the change in the current message status. The VCDIR_NEXT and VCDIR_PREVIOUS flags correspond to users choosing the next or previous commands. These operations normally correspond to moving up or down one message in the form viewer's list of messages. VCDIR_DELETE and VCDIR_MOVE are set by the IMAPIMessageSite::DeleteMessage or IMAPIMessagesSite::MoveMessage methods. Implementations of these methods call ActivateNext with the appropriate direction and then perform the requested operation on the message if the ActivateNext call did not fail. Form viewers typically allow users to specify the direction to be moved.

Upon return from ActivateNext, form objects must check for a current message and go through normal shutdown if a message is not present. If a next message is displayed, the form uses the window rectangle passed in the prcPosRect parameter.

See Also

IMAPIViewContext::GetViewStatus method


 IMAPIViewContext::GetPrintSetup

[New - Windows 95]

Retrieves the current print setup so as to print the current message.

Syntax

HRESULT GetPrintSetup(ULONG ulFlags, LPFORMPRINTSETUP FAR * lppFormPrintSetup)

Parameters

ulFlags

Input parameter containing a bitmask of flags. The following flag can be set:

MAPI_UNICODE

Indicates the returned strings are to be in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

lppFormPrintSetup

Output parameter pointing to where the pointer to the returned FORMPRINTSETUP structure holding information on the print setup is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Form objects call the IMAPIViewContext::GetPrintSetup method to retrieve the current print setup. A form object should pass the MAPI_UNICODE flag in the ulFlags parameter if Unicode strings are required for the hDevMode and hDevName members of the FORMPRINTSETUP structure returned in the lppFormPrintSetup parameter. Otherwise, GetPrintSetup returns the contents of these members as ANSI strings. The returned FORMPRINTSETUP structure must be freed by the calling form object using the MAPIFreeBuffer function.

See Also

FORMPRINTSETUP structure


 IMAPIViewContext::GetSaveStream

[New - Windows 95]

Retrieves the stream to place a textized version of the current message.

Syntax

HRESULT GetSaveStream(ULONG FAR * pulFlags, ULONG FAR * pulFormat, LPSTREAM FAR * ppstm)

Parameters

pulFlags

Output parameter pointing to a bitmask of flags used to indicate the format of the saved text. The following flag can be used.

MAPI_UNICODE

Indicates the returned text is in Unicode format. If the MAPI_UNICODE flag is not set, the text is in ANSI format.

pulFormat

Output parameter pointing to a bitmask of flags used to control additional formatting characteristics. The following flags can be set:

SAVE_FORMAT_RICHTEXT

The message is textized using rich text format.

SAVE_FORMAT_TEXT

The message is textized using plain text format.

ppstm

Output parameter pointing to a pointer to where the textized version of the message is to be written.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

The IMAPIViewContext::GetSaveStream method is used to support the Save As verb set for form viewers. A stream interface is returned to the form object. Form objects are not permitted to write any data before the seek pointer on entry, and must leave the seek pointer at the end of the textized message when done. The message should be fully textized into the stream prior to returning from the IMAPIForm::DoVerb call.


 IMAPIViewContext::GetViewStatus

[New - Windows 95]

Retrieves the current viewer status state.

Syntax

HRESULT GetViewStatus(ULONG FAR * lpulStatus)

Parameters

lpulStatus

Output parameter pointing to a variable in which a bitmask of flags giving information on view status is returned. The following flags can be set:

VCSTATUS_DELETE

Indicates the form can delete the message.

VCSTATUS_INTERACTIVE

Indicates the form should suppress displaying user interface even in response to a verb which might otherwise cause user interface to be displayed.

VCSTATUS_MODAL

Indicates the form is to be modal to the viewer.

VCSTATUS_NEXT

Indicates there is a next form.

VCSTATUS_PREV

Indicates there is a previous form.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Form servers call the IMAPIViewContext::GetViewStatus method to determine whether there are more messages to be activated in a form view in either or both directions — that is, in the direction in which a Next command activates messages, in the direction in which a Previous command activates messages, or in both directions. The value in the lpulStatus parameter is used to determine whether VCSTATUS_NEXT and VCSTATUS_PREVIOUS are valid parameters for IMAPIViewContext::ActivateNext. If VCSTATUS_DELETE is set, but not VCSTATUS_READONLY, then the message can be deleted using the IMAPIMessageSite::DeleteMessage method. Typically, form viewer applications disable menu commands and buttons if next and previous are not valid for the context. The lpulStatus values are dynamic and can be changed by the view context's calling the IMAPIFormAdviseSink::OnChange method.

The VCSTATUS_MODAL flag is set if the form must be modal to the window whose handle is passed in with the IMAPIForm::DoVerb call. If VCSTATUS_MODAL is set, the form can use the thread on which the former call to the IMAPIForm::DoVerb method was made until the form closes. If VCSTATUS_MODAL is not set, the form should not be modal to the window indicated by the passed handle and must not use the thread.

See Also

IMAPIForm::DoVerb method, IMAPIFormAdviseSink::OnChange method, IMAPIMessageSite::DeleteMessage method, IMAPIMessageSite::GetSiteStatus method, IMAPIViewContext::ActivateNext method


 IMAPIViewContext::SetAdviseSink

[New - Windows 95]

Registers a form object for notifications of changes to a view's status state.

Syntax

HRESULT SetAdviseSink(LPMAPIFORMADVISESINK pmvns)

Parameters

pmvns

Input parameter pointing to a form advise-sink object.

Return Values

S_OK

The call succeeded.

Comments

Form objects call the IMAPIViewContext::SetNotifySink method to register a form for notification on changes to that which is the next or previous message within a particular view context. When called with NULL in the pmvns parameter, SetNotifySink cancels a previous registration.


 IMessage : IMAPIProp

[New - Windows 95]

The IMessage interface is used for managing messages, attachments, and recipients.

At a Glance

Specified in header file:	MAPIDEFS.H
Object that supplies this interface:	Message object
Corresponding pointer type:	LPMESSAGE
Implemented by:	Message store providers
Called by:	Client applications
Vtable Order

GetAttachmentTable	Returns the attachment table for a message.
OpenAttach	Opens an attachment.
CreateAttach	Creates a new attachment in a message.
DeleteAttach	Deletes an attachment from a message.
GetRecipientTable	Returns the recipient table in a message.
ModifyRecipients	Adds, deletes, or modifies recipients in a message.
SubmitMessage	Saves all changes to a message and marks the message as ready to be submitted to the MAPI spooler.
SetReadFlag	Sets or clears the read flags for a message, and manages the sending of read notifications.


 IMessage::CreateAttach

[New - Windows 95]

Creates a new attachment in a message.

Syntax

HRESULT CreateAttach(LPCIID lpInterface, ULONG ulFlags, ULONG FAR * lpulAttachmentNum, LPATTACH FAR * lppAttach)

Parameters

lpInterface

Input parameter pointing to the interface identifier (IID) for the returned attachment object. Passing NULL for the lpInterface parameter indicates that IID_IAttach is used. Client applications must pass NULL. Message store providers can also set the lpInterface parameter to IID_IUnknown, IID_IMAPIProp, or IID_IMessage.

ulFlags

Input parameter containing a bitmask of flags used to control how the attachment is created. The following flag can be set:

MAPI_DEFERRED_ERRORS

Indicates the call is allowed to succeed even if the underlying object is not accessible to the calling application. If the object is not accessible, some subsequent call to the object might return an error.

lpulAttachmentNum

Output parameter pointing to a variable receiving an index number identifying the newly created attachment. This number is valid only within the message.

lppAttach

Output parameter pointing to a variable where the pointer to the open attachment object is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Message store providers use the IMessage::CreateAttach method to create a new attachment within a message. An index number uniquely identifying the attachment within the message is returned, along with a pointer to the open attachment. The index number and the pointer are needed to access and refer to the attachment after it has been created.


 IMessage::DeleteAttach

[New - Windows 95]

Deletes an attachment from a message.

Syntax

HRESULT DeleteAttach(ULONG ulAttachmentNum, ULONG ulUIParam, LPMAPIPROGRESS lpProgress, ULONG ulFlags)

Parameters

ulAttachmentNum

Input parameter containing the index number of the attachment to be deleted. This index number uniquely identifies the attachment within the message but is valid only within the message.

ulUIParam

Input parameter containing the handle of the window the dialog box is modal to. The ulUIParam parameter is ignored unless the client application sets the ATTACH_DIALOG flag in the ulFlags parameter and passes NULL in the lpProgress parameter.

lpProgress

Input parameter pointing to a progress object that contains client-supplied progress information. If NULL is passed in the lpProgress parameter, the progress information is provided by MAPI. The lpProgress parameter is ignored unless the ATTACH_DIALOG flag is set in the ulFlags parameter.

ulFlags

Input parameter containing a bitmask of flags used to control what happens when the attachment is deleted. The following flag can be set:

ATTACH_DIALOG

Causes a progress-information user interface to be displayed as the operation proceeds.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Message store providers use the IMessage::DeleteAttach method to delete an attachment from within a message. Prior to calling DeleteAttach to delete the attachment, client applications should call the IUnknown::Release method on all pointers to the attachment and its streams. A deleted attachment is not permanently deleted until the IMAPIProp::SaveChanges method has been called for the message that held the attachment.

See Also

IMAPIProp::SaveChanges method


 IMessage::GetAttachmentTable

[New - Windows 95]

Returns the attachment table for a message.

Syntax

HRESULT GetAttachmentTable(ULONG ulFlags, LPMAPITABLE FAR * lppTable)

Parameters

ulFlags

Input parameter containing a bitmask of flags controlling the type of the text in the returned strings. The following flag can be set:

MAPI_UNICODE

Indicates the returned strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

lppTable

Output parameter pointing to a variable where the pointer to the returned attachment-table object is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Message store providers use the IMessage::GetAttachmentTable method to acquire a pointer to a message's attachment table, which lists all the attachments within a message. The attachment table for either a sent message or a message under composition contains one row for each attachment.

The attachment table must contain the following required property columns:

PR_ATTACH_NUM

The index number of the attachment within the message. It is used to identify the attachment when the attachment is opened with the IMessage::OpenAttach method. Within a client application session, an attachment's PR_ATTACH_NUM property remains constant as long as the message is open. However, PR_ATTACH_NUM is only valid during a message session and is not unique across sessions.

PR_RECORD_KEY

Uniquely identifies the attachment object within a message. It remains unique across sessions so that it stays the same after the message containing the attachment is closed and reopened.

PR_RENDERING_POSITION

Identifies where within the text of the message MAPI should render the attachment.

The table can contain additional property columns depending on a message store provider's implementation. Any potential for restrictions on the table is also determined by a store provider's implementation, so client applications should not be designed with the expectation that restrictions are supported in all cases.

Attachments don't necessarily appear in the attachment table until IMAPIProp::SaveChanges is called on the message. The attachment table can change while it is open if the application calls the IMessage::CreateAttach or IMessage:: DeleteAttach method to create or delete an attachment, or if an attachment is modified such that its properties change in the attachment table, and SaveChanges is called for the message.

Attachment tables, when initially opened, are not necessarily sorted in any particular order.

Setting the MAPI_UNICODE flag in the ulFlags parameter does the following:

•	Sets the string type to Unicode for data returned for the initial active columns of the attachment table by the IMAPITable::QueryColumns method. The initial active columns for an attachment table are those columns the QueryColumns method returns before the application that contains the attachment table calls the IMAPITable::SetColumns method.

•	Sets the string type to Unicode for data returned for the initial active rows of the attachment table by the IMAPITable::QueryRows method. The initial active rows for an attachment table are those rows QueryRows returns before the application that contains the attachment table calls the IMAPITable::SetColumns method.

•	Controls the property types of the sort order specification returned by the IMAPITable::QuerySortOrder method before the application that contains the attachment table calls the IMAPITable::SortTable method.

See Also

IMessage::CreateAttach method, IMessage::DeleteAttach method, IMessage::OpenAttach method


 IMessage::GetRecipientTable

[New - Windows 95]

Returns the recipient table in a message.

Syntax

HRESULT GetRecipientTable(ULONG ulFlags, LPMAPITABLE FAR * lppTable)

Parameters

ulFlags

Input parameter containing a bitmask of flags used to control the return of the table. The following flags can be set:

MAPI_DEFERRED_ERRORS

Indicates the call is allowed to succeed even if the underlying object is not accessible to the calling application. If the object is not accessible, some subsequent call to the object might return an error.

MAPI_UNICODE

Indicates the returned strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

lppTable

Output parameter pointing to a variable where the pointer to the returned table object is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Message store providers use the IMessage::GetRecipientsTable method to get a list of the recipients for a message. Changes to the recipient table can be made by calling the IMessage::ModifyRecipients method.

The recipient table for a received message or a message under composition contains one row for each recipient of the message.

The table will have at least the following columns:

PR_DISPLAY_NAME

The display name for the recipient.

PR_ENTRYID

The entry identifier for the recipient.

PR_RECIPIENT_TYPE

The recipient type, one of MAPI_TO, MAPI_CC, or MAPI_BCC.

PR_ROWID

Identifies a recipient in the table for modification or deletion operations. The PR_ROWID of a given recipient is only valid as long as the message is open.

Messages that have been sent also contain the following property columns:

PR_ADDRTYPE

The address type for the recipient.

PR_SENDER_NAME

The display name associated with the entry identifier in the PR_SENDER_ENTRYID property.

PR_SENDER_ENTRYID

The entry identifier of the sender.

PR_CLIENT_SUBMIT_TIME

The time that the message was submitted.

Depending on a provider's implementation, additional columns might be in the table.

Most messaging system providers recognize only three recipient types: MAPI_TO, MAPI_CC, and MAPI_BCC. MAPI specifies constant values for these types and updates the PR_DISPLAY_TO, PR_DISPLAY_CC, and PR_DISPLAY_BCC properties of the message appropriately when the IMAPIProp::SaveChanges method is called.

MAPI and client applications use an additional recipient type, MAPI_SUBMITTED, for sending delivery reports and resend messages to message store recipients that are created as a result of expansion or transmission of the original message recipients. These recipients can appear in a delivery report indicating that a recipient name is resolved to a group included from an outside messaging system, or if one or more members of a group of recipients generates such a report. Recipients indicated by the MAPI_SUBMITTED type can also appear in a message when an effort is made to resend a message to one or more of the recipients named in a nondelivery report.

The initial active columns for a newly opened recipient table, that is those columns that IMAPITable::QueryRows returns in data if the application does not perform an IMAPITable::SetColumns call, include all available columns. Restrictions on the table are specific to a provider's implementation, so client applications should not work on the expectation that restrictions are supported in all cases. The application can change this table while it is open by calling the IMessage::ModifyRecipients method. When you are modifying the recipient list you must call the IMAPITable::QueryColumns, IMAPITable::SetColumns, and IMAPITable::QueryRows methods for each column that you want in the list — not just the modifications — because ModifyRecipients deletes from the recipient list all columns that you do not specify.

Setting the MAPI_UNICODE flag in the ulFlags parameter does the following:

•	Sets the string type to Unicode for data returned for the initial active columns of the recipient table by the IMAPITable::QueryColumns method. The initial active columns for a recipient's table are those columns the QueryColumns method returns before the application that contains the recipient's table calls the IMAPITable::SetColumns method.

•	Sets the string type to Unicode for data returned for the initial active rows of the recipient table by the IMAPITable::QueryRows method. The initial active rows for a recipient table are those rows QueryRows returns before the application that contains the recipient table calls the IMAPITable::SetColumns method.

•	Controls the property types of the sort order specification returned by the IMAPITable::QuerySortOrder method before the application that contains the recipient table calls the IMAPITable::SortTable method.

See Also

IMAPIProp::SaveChanges method, IMAPITable::QueryRows method, IMessage::ModifyRecipients method


 IMessage::ModifyRecipients

[New - Windows 95]

Adds, deletes, or modifies recipients in a message.

Syntax

HRESULT ModifyRecipients(ULONG ulFlags, LPADRLIST lpMods)

Parameters

ulFlags

Input parameter containing a bitmask of flags used to control how the recipients table is modified — that is, how recipients are added, deleted, or modified. If zero is passed for the ulFlags parameter, the entire recipient table is replaced with the table passed in the lpMods parameter. The following flags can be set for the ulFlags parameter:

MODRECIP_ADD

Adds all recipients to the current table.

MODRECIP_MODIFY

Replaces the entire row with the rows you specify.

MODRECIP_REMOVE

Removes the recipients using the PR_ROWID property as an index.

lpMods

Input parameter pointing to an ADRLIST structure containing a table of recipients to be added, deleted, or modified in the message.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Message store providers use the IMessage::ModifyRecipients method to make changes to a message's recipient table.

The IMAPISupport::Address method returns ADRLIST structures that are the standard MAPI recipient tables; client applications should send the same type of table in the lpMods parameter of ModifyRecipients to modify, add to, or delete recipients from the existing recipient table. You can also pass in the recipient list returned from IMessage::GetRecipientTable. When you are modifying the recipient list, you must call the IMAPITable::QueryColumns, IMAPITable::SetColumns, and IMAPITable::QueryRows methods for each column that you want in the list — not just the modifications — because ModifyRecipients deletes from the recipient list all columns that you do not specify.

The default behavior of ModifyRecipients if all bits in the bitmask passed in the ulFlags parameter are set to zero is to replace the entire existing recipient table with the list passed in the lpMods parameter. When calling ModifyRecipients with the MODRECIP_MODIFY flag set in the ulFlags parameter, ModifyRecipients instead replaces each entire recipient row with the associated row in the ADRLIST structure passed in the lpMods parameter.

Following are some rules for setting the properties of the recipients in the table passed in the lpMods parameter:

•	The presence of a property of type PT_NULL in the lpMods table returns an error value for the ModifyRecipients call.

•	Any recipient property with type PT_ERROR is ignored by ModifyRecipients.

•	The PR_ROWID property, identifying a particular recipient table row, must be provided for recipients in the lpMods table when the MODRECIP_REMOVE or MODRECIP_MODIFY flag is set in the ulFlags parameter.

•	The PR_ROWID property must not be provided for lpMods table recipients when the MODRECIP_ADD flag or zero is set in the ulFlags parameter.

•	An unresolved recipient entry in lpMods must contain only the PR_DISPLAY_NAME and PR_RECIPIENT_TYPE properties.

•	A resolved recipient entry must contain the PR_DISPLAY_NAME, PR_ADDRTYPE, PR_ENTRYID and PR_RECIPIENT_TYPE properties.

•	The PR_EMAIL_ADDRESS property, containing a messaging address for a recipient, does not have to be present for resolved recipients in the lpMods table, but it can be.

•	If the lpProps member of the ADRENTRY structure is NULL, the provider should ignore that entry.

A client application can store in a message's recipient table both resolved and unresolved entries. However, if a message with unresolved entries in its recipient table is submitted to the MAPI spooler, it causes a nondelivery report to be created and sent to the user who sent the message.

If for a recipient in the lpMods table either the PR_ADDRTYPE property, giving a recipient's address type, or the PR_EMAIL_ADDRESS property, giving a recipient's messaging address, is not consistent with the address of the recipient identified by the PR_ENTRYID property, the address where the message with the modified recipient table is delivered is undefined. The message might be delivered to the addresses specified in the PR_ADDRTYPE and PR_EMAIL_ADDRESS properties or to the recipient identified by the PR_ENTRYID property, or it might be returned as undeliverable because of the ambiguity of the address information.

The ADRLIST structure passed in the lpMods parameter must be allocated as an SRowSet structure is. ModifyRecipients does not free the ADRLIST structure nor any of its substructures. The ADRLIST structure and each SPropValue structure must be separately allocated by using the MAPIAllocateBuffer function such that each can be freed individually. If the method requires additional space for any SPropValue structure, it can replace the SPropValue with a new one that can later be freed by the calling application using the MAPIFreeBuffer function. The original SPropValue structure will also be freed by MAPIFreeBuffer.

See Also

ADRENTRY structure, ADRLIST structure, IAddrBook::Address method, IMAPISupport::Address method, MAPIAllocateBuffer function, MAPIFreeBuffer function, SPropValue structure


 IMessage::OpenAttach

[New - Windows 95]

Opens an attachment.

Syntax

HRESULT OpenAttach(ULONG ulAttachmentNum, LPCIID lpInterface, ULONG ulFlags, LPATTACH FAR * lppAttach)

Parameters

ulAttachmentNum

Input parameter containing the index number of the attachment to be opened. This index number uniquely identifies the attachment within the message but is valid only within the message.

lpInterface

Input parameter pointing to the interface identifier (IID) for the returned attachment object. Passing NULL for the lpInterface parameter indicates that IID_IAttach is used. Client applications must pass NULL. Message store providers can also set the lpInterface parameter to IID_IUnknown, IID_IMAPIProp, or IID_IMessage.

ulFlags

Input parameter containing a bitmask of flags used to control how the attachment is opened. The following flags can be set:

MAPI_BEST_ACCESS

Indicates the object should be opened with the maximum privileges allowed to the user. For example, if the client application has read-write privilege, the object is opened with read-write privilege; if the client application has read-only privilege, the object is opened with read-only privilege. The client application can retrieve the privilege level by getting the property PR_ACCESS_LEVEL.

MAPI_DEFERRED_ERRORS

Indicates the call is allowed to succeed even if the underlying object is not accessible to the calling application. If the object is not accessible, some subsequent call to the object might return an error.

MAPI_MODIFY

Requests read-write access. By default, objects are created with read-only access, and client applications should not work on the assumption that read-write access was granted.

lppAttach

Output parameter pointing to a variable where the pointer to the open attachment object is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Message store providers use the IMessage::OpenAttach method to open an attachment within a message. A client application can open an attachment by first locating the PR_ATTACH_NUM property for that attachment (that is, the attachment's index number) in the table that is returned from the IMessage::GetAttachmentTable method, and then passing this PR_ATTACH_NUM value in the ulAttachmentNum parameter of OpenAttach. OpenAttach returns in the lppAttach parameter a pointer that provides further access to the open attachment.

Each attachment in a message has a different PR_ATTACH_NUM value, which is only valid within the message. The PR_ATTACH_NUM value is only unique within a message; messages in a store can have attachments with the same PR_ATTACH_NUM values as other messages. For example, an implementation can assign the value of zero to the first attachment in every message.

The expected behavior for opening multiple instances of the same attachment in the same message is undefined and specific to a particular provider's implementation.


 IMessage::SetReadFlag

[New - Windows 95]

Sets or clears the read flags for a message, and manages the sending of read notifications.

Syntax

HRESULT SetReadFlag(ULONG ulFlags)

Parameters

ulFlags

Input parameter containing a bitmask of flags used control the setting of a message's read flag — that is, the message's MSGFLAG_READ flag in its PR_MESSAGE_FLAGS property — and the processing of read notifications. The following flags can be set:

CLEAR_READ_FLAG

Resets the MSGFLAG_READ flag.

GENERATE_RECEIPT_ONLY

Generates a read notification but does not change the state of the MSGFLAG_READ flag in PR_MESSAGE_FLAGS.

MAPI_DEFERRED_ERRORS

Indicates the call is allowed to succeed even if the underlying object is not accessible to the calling application. If the object is not accessible, some subsequent call to the object might return an error.

SUPPRESS_RECEIPT

Indicates the messaging system should not send a read notification for each message, but that each message should be marked as read.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NO_SUPPRESS

The message store provider does not support the suppression of read notifications.

Comments

Message store providers use the IMessage::SetReadFlag method to mark a message as read and, optionally, to send a read notification for that message. A read notification is only sent if the user who sent the message requested it. Applications generally cannot determine if the originator requested a read notification. After setting the read flag (that is, setting the MSGFLAG_READ flag in the message's PR_MESSAGE_FLAGS property), SetReadFlag calls the IMAPIProp::SaveChanges method on the message.

If none of the flags are set in the ulFlags parameter, the following rules apply:

•	If the MSGFLAG_READ bit is already set, do nothing.

•	If the PR_READ_RECEIPT_REQUESTED bit is set, send the read notification and set the MSGFLAG_READ bit.

MAPI_E_INVALID_PARAMETER is returned if any of the following combinations are set in ulFlags:

•	SUPPRESS_RECEIPT | CLEAR_READ_FLAG

•	SUPPRESS_RECEIPT | CLEAR_READ_FLAG | GENERATE_RECEIPT_ONLY

•	CLEAR_READ_FLAG | GENERATE_RECEIPT_ONLY

If both SUPPRESS_RECEIPT and GENERATE_RECEIPT_ONLY are set in ulFlags, the PR_READ_RECEIPT_REQUESTED bit, if it is set, is turned off, and a read notification should not be sent.

Note  Providers can optimize report behavior so that a client application's setting a message attribute to get a read notification or delivery report is only a request and the provider can support not sending read notifications or delivery reports. However, some message stores do not support the suppression of read notifications for some messages. If the client application calls SetReadFlag on such a message with the SUPPRESS_RECEIPT flag set in the ulFlags parameter, SetReadFlag returns the value MAPI_E_NO_SUPPRESS; in this case, MAPI does not mark the message as read and does not generate a report or notification.

See Also

IMAPIContainer::OpenEntry method, IMAPIFolder::SetReadFlags method, IMAPIProp::GetProps method, IMAPIProp::SaveChanges method, PR_MESSAGE_FLAGS property


 IMessage::SubmitMessage

[New - Windows 95]

Saves all changes to a message and marks the message as ready for sending.

Syntax

HRESULT SubmitMessage(ULONG ulFlags)

Parameters

ulFlags

Reserved; must be zero.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NO_RECIPIENTS

Indicates that the message's recipient list is empty.

Comments

Message store providers use the IMessage::SubmitMessage method to indicate to transport providers that a message is ready for sending.

After a message is successfully saved and submitted, the pointers to the message and all its associated subobjects (messages, folders, attachments, streams, tables, and so on) are no longer valid. MAPI does not permit any further operations on these pointers, except for calling the objects' IUnknown::Release methods. In other words, MAPI is designed such that after SubmitMessage is called a client application should release the message object and all associated subobjects. However, if SubmitMessage returns an error value indicating missing or invalid fields in the message, such as results when a message is sent with no recipients listed, then MAPI keeps the message open and all pointers remain valid.

To attempt to cancel a send operation, your client must get and store a pointer to the entry identifier of the message before the message is submitted, because the entry identifier is invalidated after the message has been submitted. Once your client has this entry identifier pointer, it then passes it as the lpEntryId parameter of the IMsgStore::AbortSubmit method.

A message might stay in a message store for some time before the underlying messaging system can take responsibility for it. This occurs because MAPI passes messages to the underlying messaging system in the order in which they are marked for sending. However, the order of receipt at the destination is in the underlying messaging system's control and is not guaranteed to match the order in which messages were sent.

See Also

IMsgStore::AbortSubmit method


 IMsgServiceAdmin : IUnknown

[New - Windows 95]

The IMsgServiceAdmin interface is used to make changes to a message service within a profile. You can get a pointer to an IMsgServiceAdmin interface in two ways: by calling the IMAPISession::AdminServices method or by calling the IProfAdmin::AdminServices method. If your application is primarily concerned with profile configuration, for example if it is a control panel, then IProfAdmin::AdminServices is the preferred way to get the IMsgServiceAdmin interface because it does not log the providers onto the MAPI session. If your application requires the ability to make changes to the active profile, then IMAPISession::AdminServices should be called to get the pointer to the IMsgServiceAdmin interface. Applications that are modifying the profile that is active for the session should be designed with the awareness that although MAPI does not allow a profile that is in use to be deleted, there are no safeguards to prevent an application from removing all of the message services within the profile.

At a Glance

Specified in header file:	MAPIX.H
Object that supplies this interface:	Message-service administration object
Corresponding pointer type:	LPSERVICEADMIN
Implemented by:	MAPI
Called by:	Client applications
Vtable Order

GetLastError	Returns information about the last error that occurred for the message-service administration object.
GetMsgServiceTable	Returns a table object listing the message services installed in a profile.
CreateMsgService	Adds a message service to the current profile.
DeleteMsgService	Deletes a message service and its associated profile sections from the profile.
CopyMsgService	Copies a message service into a profile.
RenameMsgService	Renames a message service that cannot be copied.
ConfigureMsgService	Enables the user to reconfigure the message service using the service's configuration property sheet.
OpenProfileSection	Opens a section of the current profile and returns a pointer that provides further access to the profile object.
MsgServiceTransportOrder	Sets the order in which transport providers are called to deliver a message.
AdminProviders	Returns a pointer providing access to a provider administration object.
SetPrimaryIdentity	Designates a message service as the supplier of the primary identity for the profile.
GetProviderTable	Returns a table object listing the service providers installed in a profile.


 IMsgServiceAdmin::AdminProviders

[New - Windows 95]

Enumerates and changes the service providers belonging to a message service.

Syntax

HRESULT AdminProviders(LPMAPIUID lpUID, ULONG ulFlags, LPPROVIDERADMIN FAR * lppProviderAdmin)

Parameters

lpUID

Input parameter pointing to the MAPIUID structure holding the unique identifier for the message service. This MAPIUID is typically obtained from the PR_SERVICE_UID property column in the message-service administration table.

ulFlags

Input parameter containing a bitmask of flags controlling the type of the string. The following flag can be set:

MAPI_UNICODE

Indicates the passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

lppProviderAdmin

Output parameter pointing to a variable where the pointer to the returned provider administration object is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NOT_FOUND

The MAPIUID does not exist.

Comments

Use the IMsgServiceAdmin::AdminProviders method to get a pointer to a provider administration object so that the methods of the IProviderAdmin interface can be called for that object. Client applications cannot make changes to service providers; all a client application can do is determine the providers within a message service and determine each provider's MAPIUID. The types of changes that can be made to a message service while the profile is in use are implementation-specific; however, most message services do not support changes such as adding and deleting providers while the profile is in use.

See Also

IProviderAdmin : IUnknown interface, MAPIUID structure


 IMsgServiceAdmin::ConfigureMsgService

[New - Windows 95]

Enables the user to reconfigure the message service using the service's configuration property sheet.

Syntax

HRESULT ConfigureMsgService(LPMAPIUID lpUID, ULONG ulUIParam, ULONG ulFlags, ULONG cValues, LPSPropValue lpProps)

Parameters

lpUID

Input parameter pointing to the MAPIUID structure holding the unique identifier for the message service to be configured.

ulUIParam

Input parameter containing a handle of the window the dialog box is modal to; in this case, the ulUIParam parameter is the handle for the window to serve as the parent window for the configuration property sheet.

ulFlags

Input parameter containing a bitmask of flags used to control the display of the property sheet. The following flags can be set:

MAPI_UNICODE

Indicates the passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

MSG_SERVICE_UI_READ_ONLY

Indicates the service's configuration user interface should display the current configuration but not enable the user to change it. Most message services ignore this flag.

SERVICE_UI_ALLOWED

Displays the message service's configuration property sheet only if the service is not completely configured.

SERVICE_UI_ALWAYS

Requires the message service display a configuration dialog box. If SERVICE_UI_ALWAYS is not set, a configuration dialog box can still be displayed if SERVICE_UI_ALLOWED is set and valid configuration information is not available from the property value array in the lpProps parameter. Either SERVICE_UI_ALLOWED or SERVICE_UI_ALWAYS must be set to allow a user interface to be displayed.

cValues

Input parameter containing the number of property values in the SPropValue structure pointed to by the lpProps parameter. The cValues parameter should be set to zero if there are no properties.

lpProps

Input parameter pointing to an SPropValue structure containing the property values of the properties to be displayed to the user in the property sheet. The lpProps parameter should be NULL if message service is being configured without displaying the property sheet to the user.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_EXTENDED_ERROR

An error specific to a message service. Call the IMsgServiceAdmin::GetLastError method to get the MAPIERROR structure describing the error.

MAPI_E_NOT_FOUND

The MAPIUD does not match an existing message service.

MAPI_E_NOT_INTIALIZED

The message service does not have a message-service entry function.

MAPI_E_USER_CANCEL

The user canceled the operation, typically by clicking the Cancel button in the dialog box.

Comments

Use the IMsgServiceAdmin::ConfigureMsgService method to display the configuration property sheet for a message service so that client application users can configure the message service in their profiles. The MAPIUID used in the lpUID parameter is typically retrieved from the message-service administration table by calling the IMsgServiceAdmin::GetMsgServiceTable method after the message service has been created with the IMsgServiceAdmin::CreateMsgService method.

Client applications can also configure the message service programmatically, that is without displaying the property sheet to the user. This can only be done if the message service's property identifiers and property values are known in advance. If an application is programmatically configuring the service and the property sheets should not be displayed, then neither the SERVICE_UI_ALLOWED nor the SERVICE_UI_ALWAYS flag should be set in the ulFlags parameter. If an application is not doing programmatic configuration, or if the programmatic configuration does not completely configure the service, set the SERVICE_UI_ALLOWED flag in ulFlags. If an application is doing programmatic configuration but only to establish the default settings and the user will be able to change the settings, set the SERVICE_UI_ALWAYS flag in ulFlags.

To allow programmatic configuration, message services typically prepare a header file that includes constants for all of the required and optional properties and their values.

See Also

MAPIUID structure, SPropValue structure


 IMsgServiceAdmin::CopyMsgService

[New - Windows 95]

Copies a message service into a profile.

Syntax

HRESULT CopyMsgService(LPMAPIUID lpUID, LPTSTR lpszDisplayName, LPCIID lpInterfaceToCopy, LPCIID lpInterfaceDst, LPVOID lpObjectDst, ULONG ulUIParam, ULONG ulFlags)

Parameters

lpUID

Input parameter pointing to the MAPIUID structure holding the unique identifier for the message service to be copied.

lpszDisplayName

Input parameter pointing to a string containing the display name for the message service to be copied.

lpInterfaceToCopy

Input parameter pointing to the interface identifier (IID) for the profile section object into which the message service is to be copied. Passing NULL for the lpInterfaceToCopy parameter indicates the identifier for the profile-section object interface, IID_IProfSect, is used. The lpInterfaceToCopy parameter can also be set to an identifier for an appropriate interface, for example IID_IMAPIProp or IID_IUnknown.

lpInterfaceDst

Input parameter pointing to the IID for the session or message-service administration object indicated in the lpObjectDst parameter. Passing NULL for the lpInterfaceDst parameter indicates the MAPI session interface identifier, IID_IMAPISession, is used. The lpInterfaceDst parameter can also be set to IID_IMsgServiceAdmin.

lpObjectDst

Input parameter pointing to a pointer to a session or message-service administration object; the type of object should correspond to the interface identifier passed in lpInterfaceDst. Valid object pointers are LPMAPISESSION and LPSERVICEADMIN.

ulUIParam

Input parameter containing the handle to the window the dialog box is modal to.

ulFlags

Input parameter containing a bitmask of flags controlling the type of the string. The following flag can be set:

MAPI_UNICODE

Indicates the passed-in string is in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

SERVICE_UI_ALLOWED

Displays the message service's configuration property sheet only if the service is not completely configured.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NOT_FOUND

The MAPIUID does not refer to an existing message service.

MAPI_E_NO_ACCESS

The message service is already in the profile and does not allow multiple instances of itself.

Comments

Use the IMsgServiceAdmin::CopyMsgService method to copy a message service into a profile section. The client application must previously have obtained an interface to the target profile, but it does not have to be logged onto the profile. The target profile is not necessarily the same as the source profile. Client applications can copy messages services within a profile or from one profile to another. The message service's entry point function does not get called on either the source or the destination of the copy operation. After the copy operation, the configuration settings of the service remain unchanged; call the IMsgServiceAdmin::ConfigureMsgService method to configure the copied message service.

See Also

IMsgServiceAdmin::ConfigureMsgService method, MAPIUID structure


 IMsgServiceAdmin::CreateMsgService

[New - Windows 95]

Adds a message service to the current profile.

Syntax

HRESULT CreateMsgService(LPTSTR lpszService, LPTSTR lpszDisplayName, ULONG ulUIParam, ULONG ulFlags)

Parameters

lpszService

Input parameter pointing to a string containing the message service name, using which client applications can find in the MAPISVC.INF file the information necessary to create the message service. This message service name must appear in the [Services] section of MAPISVC.INF.

lpszDisplayName

Input parameter pointing to a string containing the display name for the message service. The lpszDisplayName parameter is ignored because service providers set the PR_DISPLAY_NAME property in MAPISVC.INF themselves.

ulUIParam

Input parameter containing the handle of the window the dialog box is modal to.

ulFlags

Input parameter containing a bitmask of flags used to control the installation of the message service. The following flags can be set:

SERVICE_UI_ALLOWED

Displays the message service's configuration property sheet only if the service is not completely configured.

MAPI_UNICODE

Indicates the passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NOT_FOUND

The message service name is not in the [Services] section of MAPISVC.INF.

Comments

Use the IMsgServiceAdmin::CreateMsgService method to add a message service to the current profile. Your client application passes the name of the service to add in the lpszService parameter.

If the service has defined an entry point function, it is called so the service can perform any service-specific configuration tasks. If the SERVICE_UI_ALLOWED flag is set in the ulFlags parameter, the message service being installed can display a user interface to enable the user to configure its settings. The list of providers and the properties for each provider that make up a message service are contained within the MAPISVC.INF file. CreateMsgService first creates a new profile section for the message service and then copies all of the information from the MAPISVC.INF file for that service into the profile, creating new sections for each service provider. After all of the information has been copied from MAPISVC.INF, the message service's entry function is called with the MSG_SERVICE_CREATE value set in the ulContext parameter . If the SERVICE_UI_ALLOWED flag is set in the CreateMsgService method's ulFlags parameter, then the values in the ulUIParam and ulFlags parameters are also passed when the service provider's message service entry function is called. Service providers are expected to display their configuration property sheets so that the user can configure the message service.

CreateMsgService does not return the MAPIUID for the message service that was added to the profile. To retrieve the MAPIUID, call the IMsgServiceAdmin::GetMsgServiceTable method to get the message service administration table. Search for the message service by the PR_SERVICE_NAME property. Then retrieve the service's PR_SERVICE_UID property. You then pass that MAPIUID in the lpUid parameter when calling the IMsgServiceAdmin::ConfigureMsgService method to configure the service.


 IMsgServiceAdmin::DeleteMsgService

[New - Windows 95]

Deletes a message service and its associated profile sections.

Syntax

HRESULT DeleteMsgService(LPMAPIUID lpuid)

Parameters

lpuid

Input parameter pointing to the MAPIUID structure holding the unique identifier for the message service being deleted.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NOT_FOUND

The MAPIUID does not match an existing message service.

Comments

Use the IMsgServiceAdmin::DeleteMsgService method to delete a message service from a profile. To retrieve the MAPIUID for the message service, call the IMsgServiceAdmin::GetMsgServiceTable method to get the message-service administration table. Search for the message service by the PR_SERVICE_NAME property. Then retrieve the service's PR_SERVICE_UID property. You then pass that MAPIUID in the lpUid parameter when calling DeleteMsgService. DeleteMsgService removes all profile sections related to the message service.

If the service has defined a message-service entry function, it is called with the MSG_SERVICE_DELETE value set in the ulContext parameter before the profile sections are removed so that the service can perform any service-specific tasks. First the service is deleted, then the service's profile section skeleton is deleted. The message service entry function is not called again after the service has been deleted.

See Also

MAPIUID structure


 IMsgServiceAdmin::GetLastError

[New - Windows 95]

Returns information about the last error that occurred for the message-service administration object.

Syntax

HRESULT GetLastError(HRESULT hResult, ULONG ulFlags, LPMAPIERROR FAR * lppMAPIError)

Parameters

hResult

Input parameter containing the result returned for the last call on the session object that returned an error.

ulFlags

Input parameter containing a bitmask of flags controlling the type of the returned strings. The following flag can be set:

MAPI_UNICODE

Indicates the strings returned in the MAPIERROR structure returned in the lppMAPIError parameter are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

lppMAPIError

Output parameter pointing to a pointer to the returned MAPIERROR structure containing version, component, and context information for the error. The lppMAPIError parameter can be set to NULL if there is no MAPIERROR structure to return.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_BAD_CHARWIDTH

Either the MAPI_UNICODE flag was set and the implementation does not support Unicode, or MAPI_UNICODE was not set and the implementation only supports Unicode.

Comments

Use the IMsgServiceAdmin::GetLastError method to retrieve information to display as a message to the user regarding the last error returned from a method call on the message-service administration object.

To release all the memory allocated by MAPI, client applications need only call the MAPIFreeBuffer function for the MAPIERROR structure.

The return value from GetLastError must be S_OK for the application to make use of the MAPIERROR structure. Even if the return value is S_OK, it is still possible that a MAPIERROR structure won't be returned. If the implementation cannot determine what the last error was, or if a MAPIERROR structure is not available for that error, a pointer to NULL is returned in the lppMAPIError parameter instead.

See Also

MAPIERROR structure, MAPIFreeBuffer function


 IMsgServiceAdmin::GetMsgServiceTable

[New - Windows 95]

Returns a table object listing the message services installed in a profile.

Syntax

HRESULT GetMsgServiceTable(ULONG ulFlags, LPMAPITABLE FAR * lppTable)

Parameters

ulFlags

Input parameter containing a bitmask of flags controlling the type of the strings returned in the table's default column set. The following flag can be set:

MAPI_UNICODE

Indicates the returned strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

lppTable

Output parameter pointing to a variable where the pointer to the returned table object is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Use the IMsgServiceAdmin::GetMsgServiceTable method to get a pointer to a table object that lists the message services currently installed in a profile. The columns of the message services table contain the current information for the following properties:

PR_DISPLAY_NAME

The name of the message service as given by the service. Some implementations enable the user to change this name.

PR_SERVICE_NAME

A particular message service's name as found in the MAPISVC.INF file (for example, "Microsoft Exchange Services"). This name, which is fixed and permanent, can be used to access entries in MAPISVC.INF.

PR_RESOURCE_FLAGS

Flags describing the message service's capabilities.

PR_SERVICE_DLL_NAME

The dynamic-link library (DLL) for a particular service's entry function.

PR_SERVICE_ENTRY_NAME

The name of a service's entry function, in 8-bit format.

PR_SERVICE_UID

A unique identifier for the profile section that contains any further properties maintained by this service. This is the property column containing the MAPIUID that the IMsgServiceAdmin::DeleteMsgService and IMsgServiceAdmin::ConfigureMsgService methods use to perform their operations.

PR_SERVICE_SUPPORT_FILES

A list of the names of the support files that are required for this message service.

PR_INSTANCE_KEY

A search key for an instance of a particular MAPI object.

Once a message-service administration table has been returned, it does not reflect changes being made to the profile, such as adding or deleting providers. Calls to the IMAPITable::Advise calls method for the message-service administration table return S_OK, but no changes are made to the table. If no profile exists, GetMsgServiceTable does not return an error; a table object supporting the IMAPITable interface is returned. If you call the IMAPITable::QueryRows method on that table, zero rows are returned.

Client applications that are configuring or deleting messages services using the IMsgServiceAdmin::ConfigureMsgService or IMsgService::DeleteMsgService method typically call GetMsgServicesTable to get the MAPIUID structure stored in the PR_SERVICE_UID property for the service they are working with.

Setting the MAPI_UNICODE flag in the ulFlags parameter does the following:

•	Sets the string type to Unicode for data returned for the initial active columns of the message-service administration table by the IMAPITable::QueryColumns method. The initial active columns for a message-service administration table are those columns the QueryColumns method returns before the application that contains the message-service administration table calls the IMAPITable::SetColumns method.

•	Sets the string type to Unicode for data returned for the initial active rows of the message-service administration table by the IMAPITable::QueryRows method. The initial active rows for a message-service administration table are those rows QueryRows returns before the application that contains the message-service administration table calls the IMAPITable::SetColumns method.

•	Controls the property types of the sort order specification returned by the IMAPITable::QuerySortOrder method before the application that contains the message-service administration table calls the IMAPITable::SortTable method.

See Also

IMsgServiceAdmin::ConfigureMsgService method, IMsgServiceAdmin::DeleteMsgService method


 IMsgServiceAdmin::GetProviderTable

[New - Windows 95]

Returns a table object listing the service providers installed in a profile.

Syntax

HRESULT GetProviderTable(ULONG ulFlags, LPMAPITABLE FAR * lppTable)

Parameters

ulFlags

Input parameter containing a bitmask of flags controlling the type of the strings returned in the table's default column set. The following flag can be set:

MAPI_UNICODE

Indicates the returned strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

lppTable

Output parameter pointing to a variable where the pointer to the returned provider table object is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Use the IMsgServiceAdmin::GetProviderTable method to get a pointer to a table object that lists all of the address book, message store, transport, and message hook providers currently installed in a profile. The columns of the provider table contain the current information for the following properties:

PR_DISPLAY_NAME

The provider's name as given by the provider.

PR_INSTANCE_KEY

A search key for an instance of a particular MAPI object.

PR_PROVIDER_DISPLAY

The name of the provider as given by the messaging service. This name is not localizable and is a reliable way to search on a particular provider.

PR_PROVIDER_DLL_NAME

The dynamic-link library (DLL) for a particular provider.

PR_PROVIDER_ORDINAL

A number computed by MAPI that identifies the order in which the providers are listed in the profile.

PR_PROVIDER_UID

Identifies a particular instance of a provider.

PR_RESOURCE_FLAGS

Flags describing the capabilities of the provider.

PR_RESOURCE_TYPE

An enumeration describing the type of the provider. This property can be used to determine all the providers of a particular type that are installed within a profile.

PR_SERVICE_NAME

The name of the message service as given by the message service. This name is not localizable and is a reliable way to search on a particular service.

PR_SERVICE_UID

Identifies a particular instance of a message service.

Providers that have been deleted, or are in use but have been marked for deletion, are not returned in the provider administration table. Once a provider administration table has been returned, it does not reflect changes being made to the profile, such as adding or deleting providers. Calls to the IMAPITable::Advise method for the provider administration table return S_OK, but no changes are made to the table. If no provider exists, GetProviderTable does not return an error; a table object supporting the IMAPITable interface is returned. If you call the IMAPITable::QueryRows method on that table, zero rows are returned.

The provider table's PR_PROVIDER_ORDINAL property can be used to restrict sort operations on the table. The first transport provider in the list has PR_PROVIDER_ORDINAL set to 0, the next provider to 1, and so on; this functionality enables your client application to retrieve the table with the list of providers set to the correct order. This list of providers can then be used to select the order of transport providers by calling the IMsgServiceAdmin::MsgServiceTransportOrder method. To display the order, restrict the table on the PR_RESOURCE_TYPE==MAPI Transport Provider. Then sort the table by PR_PROVIDER_ORDINAL. Then call IMAPITable::QueryRows to get the rows of the table. These can also all be made in a single call to the HrQueryAllRows function with all of the appropriate data structures passed in. This information for setting the transport order can only be obtained by calling IMsgServiceAdmin::GetProviderTable.

Setting the MAPI_UNICODE flag in the ulFlags parameter does the following:

•	Sets the string type to Unicode for data returned for the initial active columns of the provider administration table by the IMAPITable::QueryColumns method. The initial active columns for a provider administration table are those columns the QueryColumns method returns before the application that contains the provider administration table calls the IMAPITable::SetColumns method.

•	Sets the string type to Unicode for data returned for the initial active rows of the provider administration table by the IMAPITable::QueryRows method. The initial active rows for a provider administration table are those rows QueryRows returns before the application that contains the provider administration table calls the IMAPITable::SetColumns method.

•	Controls the property types of the sort order specification returned by the IMAPITable::QuerySortOrder method before the application that contains the provider administration table calls the IMAPITable::SortTable method.

See Also

IMsgServiceAdmin::GetMsgServiceTable method, IMsgServiceAdmin::MsgServiceTransportOrder method, IProviderAdmin::GetProviderTable method


 IMsgServiceAdmin::MsgServiceTransportOrder

[New - Windows 95]

Sets the order in which transport providers are called to deliver a message.

Syntax

HRESULT MsgServiceTransportOrder(ULONG cUID, LPMAPIUID lpUIDList, ULONG ulFlags)

Parameters

cUID

Input parameter containing the number of unique identifiers in the lpUIDList parameter.

lpUIDList

Input parameter pointing to a counted array of MAPIUID structures holding unique identifiers that contains one identifier for each transport provider configured in the current profile.

ulFlags

Reserved; must be zero.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_BUSY

The value in the cUID parameter differs from the number of transports actually in the profile.

MAPI_E_NOT_FOUND

One or more of the UIDs passed in lpUIDList parameter does not refer to a transport currently in the profile.

Comments

Use the IMsgServiceAdmin::MsgServiceTransportOrder method to set the delivery order of transport providers within a profile. The lpUIDList parameter must contain the sorted list of transport-provider entry identifiers that was obtained from the PR_PROVIDER_UID property of the table returned from the IMsgServiceAdmin::GetProviderTable method. You must pass in the complete list.

SetTransportOrder overrides transport provider preferences such as the STATUS_XP_PREFER_LAST bit in the PR_RESOURCE_FLAGS property.

See Also

MAPIUID structure


 IMsgServiceAdmin::OpenProfileSection

[New - Windows 95]

Opens a section of the current profile and returns a pointer that provides further access to the profile object.

Syntax

HRESULT OpenProfileSection(LPMAPIUID lpUID, LPCIID lpInterface, ULONG ulFlags, LPPROFSECT FAR * lppProfSect)

Parameters

lpUID

Input parameter pointing to the MAPIUID structure holding the MAPI unique identifier that identifies the profile section. The lpUID parameter must not be NULL.

lpInterface

Input parameter pointing to the interface identifier used to open the profile section. Passing NULL in the lpInterface parameter indicates that the return value is cast to the standard interface for a profile section. The lpInterface parameter can also be set to an appropriate interface identifier. Valid interface identifiers are IID_IMAPIProp and IID_IProfSect.

ulFlags

Input parameter containing a bitmask of flags used to control access to the profile section. The following flags can be set:

MAPI_DEFERRED_ERRORS

Indicates the call is allowed to succeed even if the underlying object is not accessible to the calling application. If the object is not accessible, some subsequent call to the object might return an error.

MAPI_MODIFY

Requests read-write access. By default, objects are created with read-only access, and client applications should not work on the assumption that read-write access was granted.

lppProfSect

Output parameter pointing to a variable that receives the pointer to the open profile object.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NO_ACCESS

An attempt to modify a read-only profile section or an attempt to access an object for which the user has insufficient permissions.

MAPI_E_NOT_FOUND

The requested object does not exist.

Comments

Use the IMsgServiceAdmin::OpenProfileSection method to open a profile section for reading information from and writing information to the active profile for the session. A profile section object supporting the IProfSect interface is returned in the lppProfSect parameter. The default behavior is to open the profile section as read-only, unless an application sets the MAPI_MODIFY flag in the ulFlags parameter. Profile sections belonging to service providers cannot be opened by calls to the IMsgServiceAdmin::OpenProfileSection method.

If an OpenProfileSection call opens a nonexistent profile section by passing the MAPI_MODIFY flag in the ulFlags parameter, the call creates the section. If an OpenProfileSection call attempts to open a nonexistent section with read-only access, MAPI_E_NOT_FOUND is returned.

All open operations should be as brief as possible, but an application that is writing to a profile section can keep it open while displaying a modification dialog box.

See Also

IMAPIProp : IUnknown interface, IMAPISession::OpenProfileSection method, IProfSect : IMAPIProp interface, MAPIUID structure


 IMsgServiceAdmin::RenameMsgService

[New - Windows 95]

Renames a message service that cannot be copied.

Syntax

HRESULT RenameMsgService(LPMAPIUID lpUID, ULONG ulFlags, LPTSTR lpszDisplayName)

Parameters

lpUID

Input parameter pointing to the MAPIUID structure holding the unique identifier for the message service being renamed.

ulFlags

Reserved; must be zero.

lpszDisplayName

Input parameter pointing to a string containing the new display name for the message service.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NO_SUPPORT

This method always returns this value.

Comments

Use the IMsgServiceAdmin::RenameMsgService method to rename a message service that cannot be copied.

See Also

MAPIUID structure


 IMsgServiceAdmin::SetPrimaryIdentity

[New - Windows 95]

Designates each service provider belonging to the message service as being the supplier of the primary identifier for the profile.

Syntax

HRESULT SetPrimaryIdentity(LPMAPIUID lpUID, ULONG ulFlags)

Parameters

lpUID

Input parameter pointing to the MAPIUID structure holding the unique identifier for the message service whose primary identity is to be set. This MAPIUID is typically obtained from the PR_RESOURCE_UID property column in the message-service administration table.

ulFlags

Reserved; must be zero.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NO_ACCESS

The method attempted to designate a service as primary which has the PR_NO_PRIMARY bit set in the PR_RESOURCE_FLAGS property.

Comments

Use the IMsgServiceAdmin::SetPrimaryIdentity method to set the primary identity for each provider in the messaging service indicated by the lpUID parameter. The primary identity for a message service is the identity of the user logged onto the message service and is represented by the entry identifier returned by a call to the IMAPISession::QueryIdentity method.

Each messaging service provider that MAPI has information about establishes an identity for each of its users. This identity can be established when a client application logs onto the service. However, because MAPI supports connections to multiple service providers for each MAPI session, there is no firm definition of a particular user's identity for the MAPI session as a whole; a user's identity depends on which service is involved. Service providers that utilize the functionality provided by primary identities should set the STATUS_PRIMARY_IDENTITY bit in the PR_RESOURCE_FLAGS property. Client applications can call the IMsgServiceAdmin::SetPrimaryIdentity method to designate one of the many identities established for a user by messaging service providers as the primary identity for that user.

If the calling application passes NULL in the lpUID parameter, the primary identity for the indicated message service is cleared. Calls to SetPrimaryIdentity fail and return MAPI_E_NO_ACCESS if the service designated in lpUID has the SERVICE_NO_PRIMARY_IDENTITY flag set for its PR_RESOURCE_FLAGS property, meaning that service providers cannot be used to supply an identity.

See Also

IMAPISession::QueryIdentity method, MAPIUID structure


 IMsgStore : IMAPIProp

[New - Windows 95]

The IMsgStore interface provides access to message store information.

At a Glance

Specified in header file:	MAPIDEFS.H
Object that supplies this interface:	Message store object
Corresponding pointer type:	LPMDB
Implemented by:	Message store providers
Called by:	Client applications, the MAPI spooler, MAPI
Vtable Order

Advise	Registers your application for notifications on changes within the message store.
Unadvise	Removes an object's registration for notification of message store changes previously established with a call to the IMsgStore::Advise method.
CompareEntryIDs	Compares two entry identifiers to determine if they refer to the same object in the message store.
OpenEntry	Opens a folder or message in the message store given its entry identifier.
SetReceiveFolder	Sets the receive folder for a particular message class.
GetReceiveFolder	Obtains the receive folder that has been set to receive messages for a particular message class and related information about the message reception behavior of that message class.
GetReceiveFolderTable	Returns a table that shows property settings for all receive folders for the message store, including which message classes the folders are associated with.
StoreLogoff	Enables the orderly logoff of a message store under client application control.
AbortSubmit	Attempts to remove a message from the message store's outgoing queue.
GetOutgoingQueue	Returns the message store's outgoing queue table. This method is called only by the MAPI spooler.
SetLockState	Allows the MAPI spooler to lock or unlock a message.
FinishedMsg	Called only by the MAPI spooler when message processing is complete.
NotifyNewMail	Notifies the message store that a new message has arrived. This method is called only by the MAPI spooler.


 IMsgStore::AbortSubmit

[New - Windows 95]

Attempts to remove a message from the message store's outgoing queue.

Syntax

AbortSubmit(ULONG cbEntryID, LPENTRYID lpEntryID, ULONG ulFlags)

Parameters

cbEntryID

Input parameter containing the number of bytes in the entry identifier pointed to by the lpEntryID parameter.

lpEntryID

Input parameter pointing to the entry identifier of the message that is to be removed from the message queue.

ulFlags

Reserved; must be zero.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NOT_IN_QUEUE

The message is no longer in the message store's outgoing queue, typically because it has already been sent.

MAPI_E_UNABLE_TO_ABORT

The message is locked by the MAPI spooler and the operation cannot be aborted.

Comments

Message store providers use the IMsgStore::AbortSubmit method to attempt to remove a submitted message from the message store's outgoing queue. Calling AbortSubmit for a message in the store is the only action that a client can perform on a message after it has been submitted. If possible, the AbortSubmit call removes the message from the submission queue. However, depending on how the underlying messaging system is implemented, it might not be possible to cancel the sending of the message.

See Also

IMessage::SubmitMessage method


 IMsgStore::Advise

[New - Windows 95]

Registers your client application for notifications on changes within the message store.

Syntax

HRESULT Advise(ULONG cbEntryID, LPENTRYID lpEntryID, ULONG ulEventMask, LPMAPIADVISESINK lpAdviseSink, ULONG FAR * lpulConnection)

Parameters

cbEntryID

Input parameter containing the number of bytes in the entry identifier pointed to by the lpEntryID parameter.

lpEntryID

Input parameter pointing to the entry identifier of the object about which notifications should be generated. This object can be a folder or a message. Alternatively, if the client application sets the cbEntryID parameter to zero and passes NULL for lpEntryID, the advise sink is set up to provide notifications about changes to the entire message store.

ulEventMask

Input parameter containing an event mask of the types of notification events occurring for the object for which MAPI will generate notifications to filter specific cases. Each event type has a structure associated with it that holds additional information about the event. The following table lists the possible event types along with their corresponding data structures:

Notification event type	Corresponding data structure
fnevCriticalError	ERROR_NOTIFICATION
fnevNewMail	NEWMAIL_NOTIFICATION
fnevObjectCreated	OBJECT_NOTIFICATION
fnevObjectDeleted	OBJECT_NOTIFICATION
fnevObjectModified	OBJECT_NOTIFICATION
fnevObjectCopied	OBJECT_NOTIFICATION
fnevSearchComplete	OBJECT_NOTIFICATION
lpAdviseSink

Input parameter pointing to the advise sink object to be called when an event for the object occurs about which notification has been requested.

lpulConnection

Output parameter pointing to a variable that upon a successful return holds the connection number for the notification registration. The connection number must be nonzero.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Message store providers use the IMsgStore::Advise method to register an object implemented in a message store provider for notification callbacks. Whenever a change occurs to the indicated object, the provider checks to see what event mask bit has been set in the ulEventMask parameter and thus what type of change has occurred. If a bit is set, then the provider calls the IMAPIAdviseSink::OnNotify method for the advise sink object indicated by the lpAdviseSink parameter to report the event. Data passed in the notification structure to the OnNotify method describes the event.

The call to OnNotify can occur during the call that changes the object, or at any following time. On systems that support multiple threads of execution, the call to OnNotify can occur on any thread. For a way to turn a call to OnNotify that might happen at an inopportune time into one that is safer to handle, your client should use the HrThisThreadAdviseSink function.

To provide notifications, the service provider implementing Advise needs to keep a copy of the pointer to the advise sink object; to do so, it calls the IUnknown::AddRef method for the advise sink object to maintain the object pointer until notification registration is canceled with a call to the IMsgStore::Unadvise method. The Advise implementation should assign a connection number to the notification registration and call AddRef on this connection number before returning it in the lpulConnection parameter. Service providers can release the advise sink object before the registration is canceled, but they must not release the connection number until Unadvise has been called. After a call to Advise has succeeded and before Unadvise has been called, client applications must be prepared for the advise sink object to be released. Clients should therefore release their advise sink object after Advise returns unless they have a specific long-term use for it.

See Also

HrThisThreadAdviseSink function, IMAPIAdviseSink::OnNotify method, IMsgStore::Unadvise method, NOTIFICATION structure


 IMsgStore::CompareEntryIDs

[New - Windows 95]

Compares two entry identifiers to determine if they refer to the same service provider object. MAPI only passes this call to a service provider if the unique identifiers (UIDs) in both entry identifiers to be compared are handled by that provider.

Syntax

HRESULT CompareEntryIDs(ULONG cbEntryID1, LPENTRYID lpEntryID1, ULONG cbEntryID2, LPENTRYID lpEntryID2, ULONG ulFlags, ULONG FAR * lpulResult)

Parameters

cbEntryID1

Input parameter containing the number of bytes in the entry identifier pointed to by the lpEntryID1 parameter.

lpEntryID1

Input parameter pointing to the first entry identifier to be compared.

cbEntryID2

Input parameter containing the number of bytes in the entry identifier pointed to by the lpEntryID2 parameter.

lpEntryID2

Input parameter pointing to the second entry identifier to be compared.

ulFlags

Reserved; must be zero.

lpulResult

Output parameter pointing to a variable that receives the result of the comparison; this variable is TRUE if the two entry identifiers refer to the same object, and FALSE otherwise.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Message store providers use the IMsgStore::CompareEntryIDs method to compare two entry identifiers for a given message store entry and determine whether they refer to the same object. If the two entry identifiers refer to the same object, then CompareEntryIDs sets the lpulResult parameter to TRUE; if they refer to different objects, CompareEntryIDs sets lpulResult to FALSE.

CompareEntryIDs is useful because an object can have more than one valid entry identifier; such a situation can occur, for example, after a new version of a message store provider is installed.

See Also

MAPIUID structure


 IMsgStore::FinishedMsg

[New - Windows 95]

Called only by the MAPI spooler when message processing is complete.

Syntax

HRESULT FinishedMsg(ULONG ulFlags, ULONG cbEntryID, LPENTRYID lpEntryID)

Parameters

ulFlags

Reserved; must be zero.

cbEntryID

Input parameter containing the number of bytes in the entry identifier pointed to by the lpEntryID parameter.

lpEntryID

Input parameter pointing to the entry identifier of the message for which processing is finished.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NO_SUPPORT

This error value is returned if the method is called by any process other than the MAPI spooler.

Comments

The MAPI spooler calls the IMsgStore::FinishedMsg method when it has finished processing a message. When MAPI calls a message store provider's FinishedMsg implementation, the provider should unlock a message for which processing is complete and, if the PR_DELETE_AFTER_SUBMIT bit is set in the PR_MESSAGE_FLAGS property, delete the message from the folder in which it was last stored. The message store provider should then call the IMAPISupport::DoSentMail method. The MAPI spooler never passes the entry identifier for an unlocked message to FinishedMsg.

See Also

IMAPISupport::DoSentMail method


 IMsgStore::GetOutgoingQueue

[New - Windows 95]

Returns a pointer to the message store's outgoing queue table. This method is called only by the MAPI spooler.

Syntax

HRESULT GetOutgoingQueue(ULONG ulFlags, LPMAPITABLE FAR * lppTable)

Parameters

ulFlags

Reserved; must be zero.

lppTable

Output parameter pointing to a variable where the pointer to the returned outgoing queue table is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

The MAPI spooler uses the IMsgStore::GetOutgoingQueue method to get a pointer to the table showing the queue of outgoing messages for a message store.

Message store providers must present the following required property columns in the outgoing queue table:

PR_CLIENT_SUBMIT_TIME

The time when the message sender marked the message for submission.

PR_DISPLAY_BCC

The display name of a message recipient of the blind carbon-copy type.

PR_DISPLAY_CC

The display name of a carbon copy recipient.

PR_DISPLAY_TO

The primary message recipients.

PR_ENTRYID

The entry identifier for the object.

PR_MESSAGE_FLAGS

Flags indicating the current state of the message.

PR_MESSAGE_SIZE

The approximate size in bytes of the message if it is moved from one message store to another.

PR_PRIORITY

The priority of the message.

PR_SENDER_NAME

The message sender's display name. The property corresponds to the PR_SENDER_ENTRYID property.

PR_SUBJECT

The subject of the message.

PR_SUBMIT_FLAGS

The locked or preprocessing status of the message.

Due to the requirements that messages be preprocessed and that they be submitted to a transport provider in the same order that the client application called the IMessage::SubmitMessage method for them, some messages marked for sending by client applications might not appear in the outgoing queue table immediately.

The MAPI spooler is designed to accept messages from the message store in ascending order of submission time. Messages stores should either allow sorting on the outgoing queue table so that the MAPI spooler can sort the messages by submission time, or the default sort order should be by ascending submission time.

It is the responsibility of the message store provider to set up notifications for the outgoing message queue and ensure the notification callback function is called when the contents of the queue change.

See Also

IMessage::SubmitMessage method


 IMsgStore::GetReceiveFolder

[New - Windows 95]

Obtains the receive folder that has been set to receive messages for a particular message class and related information about the message reception behavior of that message class.

Syntax

HRESULT GetReceiveFolder(LPTSTR lpszMessageClass, ULONG ulFlags, ULONG FAR * lpcbEntryID, LPENTRYID FAR * lppEntryID, LPTSTR FAR * lppszExplicitClass)

Parameters

lpszMessageClass

Input parameter pointing to a string containing the name of the message class the client application requires information about, for instance IPM.Note.Phone. If the client passes NULL or an empty string in the lpszMessageClass parameter, the GetReceiveFolder method returns the default receive folder for the message store.

ulFlags

Input parameter containing a bitmask of flags controlling the type of the passed and returned strings. The following flag can be set:

MAPI_UNICODE

Indicates the passed-in and returned strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

lpcbEntryID

Output parameter pointing to a variable containing the number of bytes in the entry identifier in the lppEntryID parameter.

lppEntryID

Output parameter pointing to a variable where the pointer to the entry identifier returned for the requested receive folder is stored.

lppszExplicitClass

Output parameter pointing to a pointer to a string containing the name of the message class that explicitly sets as its receive folder the folder indicated by the entry identifier returned in the lppEntryID parameter. This message class name should either be that of the class named in the lpszMessageClass parameter or of a superclass of that class. Passing in NULL indicates that no message class name should be returned and that the folder identified in lppEntryID is the default receive folder for the message store.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Message store providers use the IMsgStore::GetReceiveFolder method to obtain the entry identifier of the folder where a client application puts messages of a specific class when they are received. If the message class indicated in the lpszMessageClass parameter does not explicitly set a receive folder, then GetReceiveFolder returns in the lppszExplicitClass parameter the name of the first superclass of that message class that does explicitly set a receive folder and in lppEntryID the entry identifier of the receive folder that superclass sets.

For example, suppose the receive folder of the message class IPM.Note has been set to the entry identifier of the Inbox and an application calls GetReceiveFolder on the message class IPM.Note.Phone. If IPM.Note.Phone does not have an explicit receive folder set, GetReceiveFolder returns the entry identifier of the Inbox in the lppEntryID parameter and IPM.Note in the lppszExplicitClass parameter.

If the client application calls GetReceiveFolder for a message class and has not set a receive folder for that message class, the value returned in the lppszExplicitClass is either a zero-length string, a string in Unicode format, or a string in 8-bit format depending on whether the client set the MAPI_UNICODE flag in the ulFlags parameter.

A default receive folder, obtained by passing NULL in the lpszMessageClass parameter, always exists for every message store.

The client application should call the MAPIFreeBuffer function when it is done with the entry identifier returned in the lppEntryID parameter to free the memory that holds that entry identifier. It should also call MAPIFreeBuffer when it is done with the message class string returned in the lppszExplicitClass parameter to free the memory that holds that string.

See Also

MAPIFreeBuffer function


 IMsgStore::GetReceiveFolderTable

[New - Windows 95]

Returns a table that shows property settings for all receive folders for the message store, including which message classes the folders are associated with.

Syntax

HRESULT GetReceiveFolderTable(ULONG ulFlags, LPMAPITABLE FAR * lppTable)

Parameters

ulFlags

Input parameter containing a bitmask of flags used to control how the table is returned. The following flags can be set:

MAPI_DEFERRED_ERRORS

Indicates the call is allowed to succeed even if the underlying object is not accessible to the calling application. If the object is not accessible, some subsequent call to the object might return an error.

MAPI_UNICODE

Indicates the returned strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

lppTable

Output parameter pointing to a variable where the pointer to the returned receive folder table is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Message store providers use the IMsgStore::GetReceiveFolderTable method to get a table showing the property settings for all receive folders in the store, including which message classes the receive folders are associated with. A receive folder is the folder where incoming messages are placed. The table returned contains information for one receive folder in each of its rows and contains the following property columns:

PR_MESSAGE_CLASS

The message class that explicitly sets this folder as its receive folder.

PR_RECORD_KEY

The record key of this receive folder, used in restrictions and comparisons. A record key is a binary-comparable unique identifier.

PR_ENTRYID

The entry identifier of this row's receive folder.

Your message store provider should implement the receive folder table such that it supports setting restrictions to filter for particular values of PR_RECORD_KEY to allow easy access to particular receive folders.

Setting the MAPI_UNICODE flag in the ulFlags parameter does the following:

•	Sets the string type to Unicode for data returned for the initial active columns of the receive folder table by the IMAPITable::QueryColumns method. The initial active columns for a receive folder table are those columns the QueryColumns method returns before the application that contains the receive folder table calls the IMAPITable::SetColumns method.

•	Sets the string type to Unicode for data returned for the initial active rows of the receive folder table by the IMAPITable::QueryRows method. The initial active rows for a receive folder table are those rows QueryRows returns before the application that contains the receive folder table calls the IMAPITable::SetColumns method.

•	Controls the property types of the sort order specification returned by the IMAPITable::QuerySortOrder method before the application that contains the receive folder table calls the IMAPITable::SortTable method.

See Also

IMAPITable::QueryColumns method, IMAPITable::QueryRows method, IMAPITable::QuerySortOrder method, IMAPITable::SetColumns method


 IMsgStore::NotifyNewMail

[New - Windows 95]

Notifies the message store that a new message has arrived. This method is called only by the MAPI spooler.

Syntax

HRESULT NotifyNewMail(LPNOTIFICATION lpNotification)

Parameters

lpNotification

Input parameter pointing to the NOTIFICATION structure holding the new-message notification.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

A message store provider implements the IMsgStore::NotifyNewMail method so that the MAPI spooler can notify the provider that it has received a message for delivery to the store. Although the MAPI spooler handles all notifications of changes that are sent to the message store provider, the provider is responsible for notifying client applications. After the MAPI spooler calls a message store's NotifyNewMail implementation, the store provider can then inform any client applications that have registered for new mail notification (that is, that have included the fnevNewMail event type in the ulEventMask parameter passed in their IMsgStore::Advise calls) about the new message. Message stores are free to implement their own client notification scheme; one way is to use the IMAPISupport::Subscribe and IMAPISupport::Unsubscribe methods.

The MAPI spooler allocates memory for the NOTIFICATION structure that holds information about the new-message notification, and that memory should not be released, kept, or modified by the message store. If a store must use the NOTIFICATION structure it must copy it; the utility function ScCopyNotifications is provided as one way to perform the copy operation.

See Also

IMAPISupport::Subscribe method, IMAPISupport::Unsubscribe method, NOTIFICATION structure, ScCopyNotifications function


 IMsgStore::OpenEntry

[New - Windows 95]

Opens a folder or a message in the message store given its entry identifier.

Syntax

HRESULT OpenEntry(ULONG cbEntryID, LPENTRYID lpEntryID, LPCIID lpInterface, ULONG ulFlags, ULONG FAR * lpulObjType, LPUNKNOWN FAR * lppUnk)

Parameters

cbEntryID

Input parameter containing the number of bytes in the entry identifier pointed to by the lpEntryID parameter.

lpEntryID

Input parameter pointing to the entry identifier of the folder or message to be opened. The root folder of the store can be opened either with its entry identifier, as with any other folder, or by passing NULL for the lpEntryID parameter.

lpInterface

Input parameter pointing to the interface identifier for the indicated object. Passing NULL in the lpInterface parameter indicates that the return value is cast to the standard interface for the indicated object. The lpInterface parameter can also be set to an appropriate interface identifier for the object being opened.

ulFlags

Input parameter containing a bitmask of flags used to control how the object is opened. The following flags can be set:

MAPI_BEST_ACCESS

Indicates the object should be opened with the maximum privileges allowed to the user. For example, if the client application has read-write privilege, the object is opened with read-write access; if the client application has read-only privilege, the object is opened with read-only access. The client application can retrieve the privilege level by getting the property PR_ACCESS_LEVEL.

MAPI_DEFERRED_ERRORS

Indicates the call is allowed to succeed even if the underlying object is not accessible to the calling application. If the object is not accessible, some subsequent call to the object might return an error.

MAPI_MODIFY

Requests read-write access. By default, objects are created with read-only access, and client applications should not work under the assumption that read-write access was granted.

lpulObjType

Output parameter pointing to a variable where the object type for the opened object is stored.

lppUnk

Output parameter pointing to a variable where the pointer to the opened object is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NO_ACCESS

An attempt to modify a read-only object or an attempt to access an object for which the user has insufficient permissions.

Comments

Message store providers use the IMsgStore::OpenEntry method to open a folder or a message in the message store. The calling application passes in the entry identifier of the object to open, and OpenEntry returns a pointer in the lppUnk parameter that provides further access to the object. OpenEntry's behavior is to open the object as read-only, unless the call sets the MAPI_MODIFY or MAPI_BEST_ACCESS flag in the ulFlags parameter.

Although the client application can use IMsgStore::OpenEntry to open any folder or message, it is usually faster if the calling application instead uses the IMAPIContainer::OpenEntry method on the folder containing the object being opened.

The calling application should check the value returned in the lpulObjType parameter to determine that the object type returned is what was expected. Commonly, after the application checks the type of the object, it then casts the pointer in the lppUnk parameter into a message object pointer, a folder object pointer, or another appropriate object pointer.

See Also

IMAPIContainer::OpenEntry method


 IMsgStore::SetLockState

[New - Windows 95]

Allows the MAPI spooler to lock or unlock a message.

Syntax

HRESULT SetLockState(LPMESSAGE lpMessage, ULONG ulLockState)

Parameters

lpMessage

Input parameter pointing to the message to be locked or unlocked.

ulLockState

Input parameter containing a value indicating whether the MAPI spooler is locking or unlocking the message. One of the following values can be used with the ulLockState parameter:

MSG_LOCKED

Locks the message.

MSG_UNLOCKED

Releases a previous lock on the message.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

The MAPI spooler uses the IMsgStore::SetLockState method to lock a message while it is in the process of sending the message. The reason the MAPI spooler locks the message is so that calls to the IMsgStore::AbortSubmit method cannot succeed. SetLockState also provides the MAPI spooler with a mechanism to unlock messages that it has previously locked. If the MAPI spooler passes the MSG_LOCKED value in the ulLockState parameter, the message affected is locked; if the MAPI spooler passes the MSG_UNLOCKED value in ulLockState, the message affected is unlocked.

Usually, when the MAPI spooler uses SetLockState to lock a message, it only locks the oldest message — that is, the next message queued for it to send. If the oldest message in the queue is waiting for a temporarily unavailable transport provider, and the next message in the queue is to use a different transport provider, then the MAPI spooler can begin processing the later message. It begins processing by locking that message using SetLockState.

The message store provider can call the IMAPIProp::SaveChanges method as a part of its response to the SetLockState call so that any changes made to the message before the SetLockState call was received are saved.

The MAPI spooler unlocks the message as part of its implementation prior to calling the IMsgStore::FinishedMsg method.

See Also

IMsgStore::AbortSubmit method, IMsgStore::FinishedMsg method


 IMsgStore::SetReceiveFolder

[New - Windows 95]

Sets the receive folder for a particular message class.

Syntax

HRESULT SetReceiveFolder(LPTSTR lpszMessageClass, ULONG ulFlags, ULONG cbEntryID, LPENTRYID lpEntryID)

Parameters

lpszMessageClass

Input parameter pointing to a string containing the name of the message class for which the receive folder should be set. If a client application passes NULL or an empty string in the lpszMessageClass parameter, it sets the message class's receive folder to the default for the message store. The receive folder is the folder in which incoming messages are placed.

ulFlags

Input parameter containing a bitmask of flags controlling the type of the text in the passed-in strings. The following flag can be set:

MAPI_UNICODE

Indicates the passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

cbEntryID

Input parameter containing the number of bytes in the entry identifier pointed to by the lpEntryID parameter.

lpEntryID

Input parameter pointing to the entry identifier of the folder to be set as the receive folder. Passing NULL in lpEntryID indicates that the current receive folder setting is replaced with the message store's default.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Message store providers use the IMsgStore::SetReceiveFolder method to set or change the receive folder for a particular message class. With SetReceiveFolder, an application can, by using successive calls, specify a different receive folder for each message class that has been defined or specify that incoming messages for multiple message classes all be directed to the same folder. An application can, for example, have its own class of messages arrive in its own folder. For instance, a fax application can designate a folder where the message store provider should place incoming faxes and one in which the store provider places outgoing faxes.

If an error occurs while calling SetReceiveFolder, the receive folder setting remains unchanged.

If SetReceiveFolder changes the receive folder setting with lpEntryID set to NULL, indicating the default receive folder should be set, SetReceiveFolder returns the value S_OK even if there was no existing setting for the indicated message class.


 IMsgStore::StoreLogoff

[New - Windows 95]

Enables the orderly logoff of a message store under client application control.

Syntax

HRESULT StoreLogoff(ULONG FAR * lpulFlags)

Parameters

lpulFlags

Input-output parameter containing a bitmask of flags used to control logoff from the message store. On input, all flags set for this parameter are mutually exclusive; your client application must specify only one flag per call. A client can set the following flags on input:

LOGOFF_ABORT

Indicates any transport activity on this store should be stopped before logoff. Control is returned to the client application after the activity is stopped. If any transport provider activity is taking place, the logoff does not occur and no change in the behavior of the MAPI spooler or transport providers occurs. If transport provider activity is quiet, the MAPI spooler releases the store. This flag is set by the client application.

LOGOFF_NO_WAIT

Indicates the message store closing should not wait for messages from the transport providers before closing. All outbound mail that is ready to be sent, is sent; if this store contains the default Inbox, any in-process message is received, and then further reception is disabled. When all activity is completed, the MAPI spooler releases the store and control is returned to the client application immediately.

LOGOFF_ORDERLY

Indicates the message store closing should not wait for information from the transport providers before closing. Any message being processed by the store is completed, and no new messages are processed. When all activity is completed, the MAPI spooler releases the store and control is returned to the store provider immediately.

LOGOFF_PURGE

Works the same as LOGOFF_NO_WAIT, but also calls the IXPLogon::FlushQueues method or the IMAPIStatus::FlushQueues method for the appropriate transport providers. The LOGOFF_PURGE flag returns control to the client application after completion.

LOGOFF_QUIET

Indicates that if any transport provider activity is taking place, the logoff does not occur.

Flags are not returned on output because the message store provider has already been released.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Client applications use the IMsgStore::StoreLogoff method to exert some control over how transport providers log off when the message store object is released. After StoreLogoff returns with S_OK, any further calls to StoreLogoff are ignored.

The client can either set requirements about message store and transport provider interaction at message store release by setting the appropriate flags, or it can allow MAPI to either stop sending messages at message store release or to complete sending prior to message store release.

A client is only allowed to control transport provider logoff if it is the only application using the message store. If another client is still using the store, the store object is immediately released and control is returned to the client application.

Message store providers use StoreLogoff as a way to record the flags that the client application requires passed to the IMAPISupport::StoreLogoffTransports method. However, store providers should not actually make the StoreLogoffTransports call until the reference count on the message store object drops to zero, during the final release of the message store object. Multiple calls to StoreLogoffTransports simply overwrite the saved flags.

If no clients call StoreLogoff before the reference count on the message store reaches zero, the store provider should set the LOGOFF_ABORT flag in the ulFlags that it passes on the call to StoreLogoffTransports.

See Also

IMAPIStatus::FlushQueues method, IMAPISupport::StoreLogoffTransports method, IXPLogon::FlushQueues method


 IMsgStore::Unadvise

[New - Windows 95]

Removes an object's registration for notification of message store changes previously established with a call to the IMsgStore::Advise method.

Syntax

HRESULT Unadvise(ULONG ulConnection)

Parameters

ulConnection

Input parameter containing the number of the registration connection previously returned by a call to IMsgStore::Advise.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Message store providers use the IMsgStore::Unadvise method to cancel notifications for a message store object. To do so, Unadvise releases the pointer to the advise sink object passed in the lpAdviseSink parameter in the previous call to IMsgStore::Advise. As part of discarding the pointer to the advise sink, the advise sink's IUnknown::Release method is called. Generally, Release is called during the Unadvise call, but if another thread is in the process of calling the IMAPIAdviseSink::OnNotify method for the advise sink object, the Release call is delayed until the OnNotify method returns.

See Also

IMAPIAdviseSink::OnNotify method, IMsgStore::Advise method


 IMSLogon : IUnknown

[New - Windows 95]

The message-store logon object is the part of an open message store provider that is called directly by MAPI. There is a one-to-one correspondence between the message-store logon object called by MAPI and the message store object called by client applications; you can think of the logon and store objects as one object exposing two interfaces. The two objects are created together and freed together.

At a Glance

Specified in header file:	MAPISPI.H
Object that supplies this interface:	Message-store logon object
Corresponding pointer type:	LPMSLOGON
Implemented by:	Message store providers
Called by:	MAPI
Vtable Order

GetLastError	Returns information about the last error that occurred for the message-store logon object.
Logoff	Logs the message store provider off.
OpenEntry	Opens a folder or a message within the message store given its entry identifier.
CompareEntryIDs	Compares two entry identifiers to determine if they refer to the same object in the message store.
Advise	Registers a message store provider for notifications on changes within the message store.
Unadvise	Removes an object's registration for notification of message store changes previously established with a call to the IMSLogon::Advise method.
OpenStatusEntry	Opens a status object.


 IMSLogon::Advise

[New - Windows 95]

Registers a message store provider for notifications on changes within the message store.

Syntax

HRESULT Advise(ULONG cbEntryID, LPENTRYID lpEntryID, ULONG ulEventMask, LPMAPIADVISESINK lpAdviseSink, ULONG FAR * lpulConnection)

Parameters

cbEntryID

Input parameter containing the number of bytes in the entry identifier pointed to by the lpEntryID parameter.

lpEntryID

Input parameter pointing to the entry identifier of the object about which notifications should be generated. This object can be a folder, a message, or any other object in the message store. Alternatively, if MAPI sets the cbEntryID parameter to zero and passes NULL for lpEntryID, the advise sink is set up to provide notifications about changes to the entire message store.

ulEventMask

Input parameter containing an event mask of the types of notification events occurring for the object for which MAPI will generate notifications to filter specific cases. Each event type has a structure associated with it that holds additional information about the event. The following table lists the possible event types along with their corresponding data structures:

Notification event type	Corresponding data structure
fnevCriticalError	ERROR_NOTIFICATION
fnevNewMail	NEWMAIL_NOTIFICATION
fnevObjectCreated	OBJECT_NOTIFICATION
fnevObjectDeleted	OBJECT_NOTIFICATION
fnevObjectModified	OBJECT_NOTIFICATION
fnevObjectCopied	OBJECT_NOTIFICATION
fnevSearchComplete	OBJECT_NOTIFICATION
fnevStatusObjectModified	STATUS_OBJECT_NOTIFICATION
lpAdviseSink

Input parameter pointing to an advise sink object to be called when a event for the session object occurs about which notification has been requested. This advise sink object must have already been allocated.

lpulConnection

Output parameter pointing to a variable that on a successful return holds the connection number for the notification registration. The connection number must be nonzero.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NO_SUPPORT

The operation is not supported by MAPI or by one or more service providers.

Comments

Message store providers use the IMSLogon::Advise method to register an object implemented in a message store provider for notification callbacks. Whenever a change occurs to the indicated object, the provider checks to see what event mask bit has been set in the ulEventMask parameter and thus what type of change has occurred. If a bit is set, then the provider calls the IMAPIAdviseSink::OnNotify method for the advise sink object indicated by the lpAdviseSink parameter to report the event. Data passed in the notification structure to the OnNotify routine describes the event.

The call to OnNotify can occur during the call that changes the object, or at any following time. On systems that support multiple threads of execution, the call to OnNotify can occur on any thread. For a way to turn a call to OnNotify that might happen at an inopportune time into one that is safer to handle, your client should use the HrThisThreadAdviseSink function.

To provide notifications, the service provider implementing Advise needs to keep a copy of the pointer to the advise sink object; to do so, it calls the IUnknown::AddRef method for the advise sink object to maintain the object pointer until notification registration is canceled with a call to the IMSLogon::Unadvise method. The Advise implementation should assign a connection number to the notification registration and call AddRef on this connection number before returning it in the lpulConnection parameter. Service providers can release the advise sink object before the registration is canceled, but they must not release the connection number until Unadvise has been called. After a call to Advise has succeeded and before Unadvise has been called, providers must be prepared for the advise sink object to be released. Providers should therefore release their advise sink object after Advise returns unless they have a specific long-term use for it.

See Also

HrThisThreadAdviseSink function, IMAPIAdviseSink::OnNotify method, IMSLogon::Unadvise method, NOTIFICATION structure


 IMSLogon::CompareEntryIDs

[New - Windows 95]

Compares two entry identifiers to determine if they refer to the same service provider object. MAPI only passes this call to a service provider if the unique identifiers (UIDs) in both entry identifiers to be compared are handled by that provider.

Syntax

HRESULT CompareEntryIDs(ULONG cbEntryID1, LPENTRYID lpEntryID1, ULONG cbEntryID2, LPENTRYID lpEntryID2, ULONG ulFlags, ULONG FAR * lpulResult)

Parameters

cbEntryID1

Input parameter containing the number of bytes in the entry identifier pointed to by the lpEntryID1 parameter.

lpEntryID1

Input parameter pointing to the first entry identifier to be compared.

cbEntryID2

Input parameter containing the number of bytes in the entry identifier pointed to by the lpEntryID2 parameter.

lpEntryID2

Input parameter pointing to the second entry identifier to be compared.

ulFlags

Reserved; must be zero.

lpulResult

Output parameter pointing to a variable that receives the result of the comparison; this variable is TRUE if the two entry identifiers refer to the same object, and FALSE otherwise.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Message store providers use the IMSLogon::CompareEntryIDs method to compare two entry identifiers for a given message store entry and determine whether they refer to the same object. If the two entry identifiers refer to the same object, then CompareEntryIDs sets the lpulResult parameter to TRUE; if they refer to different objects, CompareEntryIDs sets lpulResult to FALSE.

CompareEntryIDs is useful because an object can have more than one valid entry identifier; such a situation can occur, for example, after a new version of a message store provider is installed.


 IMSLogon::GetLastError

[New - Windows 95]

Returns a MAPIERROR structure containing information about the last error that occurred for the message store object.

Syntax

HRESULT GetLastError(HRESULT hResult, ULONG ulFlags, LPMAPIERROR FAR * lppMAPIError)

Parameters

hResult

Input parameter containing the result returned for the last call on the session object that returned an error.

ulFlags

Input parameter containing a bitmask of flags controlling the type of the returned strings. The following flag can be set:

MAPI_UNICODE

Indicates the strings returned in the MAPIERROR structure returned in the lppMAPIError parameter are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

lppMAPIError

Output parameter pointing to a pointer to the returned MAPIERROR structure containing version, component, and context information for the error. The lppMAPIError parameter can be set to NULL if there is no MAPIERROR structure to return.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_BAD_CHARWIDTH

Either the MAPI_UNICODE flag was set and the implementation does not support Unicode, or MAPI_UNICODE was not set and the implementation only supports Unicode.

Comments

Use the IMSLogon::GetLastError method to retrieve information to display as a message to the user regarding the last error returned from a method call on the session object.

To release all the memory allocated by MAPI for the MAPIERROR structure, client applications need only call the MAPIFreeBuffer function.

The return value from GetLastError must be S_OK for the application to make use of the MAPIERROR structure. Even if the return value is S_OK, it is still possible that a MAPIERROR structure won't be returned. If the implementation cannot determine what the last error was, or if a MAPIERROR structure is not available for that error, a pointer to NULL is returned in the lppMAPIError parameter instead.

See Also

MAPIERROR structure, MAPIFreeBuffer function


 IMSLogon::Logoff

[New - Windows 95]

Logs the message store provider off.

Syntax

HRESULT Logoff(ULONG FAR * lpulFlags)

Parameters

lpulFlags

Reserved; must be a pointer to zero.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Message store providers use the IMSLogon::Logoff method to forcibly shut down the message store. IMSLogon::Logoff is called in the following situations:

•	While MAPI is logging off a client application after a call to the IMAPISession::Logoff method.

•	While MAPI is logging off a message store provider. In this case, IMSLogon::Logoff is called as part of MAPI's processing the IUnknown::Release method of the support object that the message store provider creates while it is processing a IMsgStore::StoreLogoff or IUnknown::Release method call on a message store object.

See Also

IMAPISession::Logoff method, IMAPISupport : IUnknown interface, IMsgStore::StoreLogoff method, IMSProvider::Logon method, MAPIFreeBuffer function


 IMSLogon::OpenEntry

[New - Windows 95]

Opens a folder or a message in the message store given its entry identifier.

Syntax

HRESULT OpenEntry(ULONG cbEntryID, LPENTRYID lpEntryID, LPCIID lpInterface, ULONG ulOpenFlags, ULONG FAR * lpulObjType, LPUNKNOWN FAR * lppUnk)

Parameters

cbEntryID

Input parameter containing the number of bytes in the entry identifier pointed to by the lpEntryID parameter.

lpEntryID

Input parameter pointing to the address of the entry identifier of the folder or message to be opened.

lpInterface

Input parameter pointing to the interface identifier (IID) for the folder or object. Passing NULL for the lpInterface parameter indicates the MAPI interface for the object will be returned. The lpInterface parameter can also be set to an identifier for another appropriate interface for the object.

ulOpenFlags

Input parameter containing a bitmask of flags used to control how the object is opened. The following flags can be set:

MAPI_BEST_ACCESS

Indicates the object should be opened with the maximum privileges allowed to the user. For example, if the client application has read-write privilege, the object is opened with read-write access; if the client application has read-only privilege, the object is opened with read-only access. The client application can retrieve the privilege level by getting the property PR_ACCESS_LEVEL.

MAPI_DEFERRED_ERRORS

Indicates the call is allowed to succeed even if the underlying object is not accessible to the calling application. If the object is not accessible, some subsequent call to the object might return an error.

MAPI_MODIFY

Requests read-write access. By default, objects are created with read-only access, and client applications should not work on the assumption that read-write access was granted.

lpulObjType

Output parameter pointing to a variable where the object type for the opened object is stored.

lppUnk

Output parameter pointing to a variable where the pointer to the opened object is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

MAPI calls the IMSLogon::OpenEntry method to open a folder or a message in the message store. MAPI passes in the entry identifier of the object to open; your message store provider should return a pointer providing further access to the object in the lppUnk parameter.

Before MAPI calls IMSLogon::OpenEntry, it first determines that the given message or folder entry identifier matches one registered by this message store provider. For more information on how store providers register entry identifiers, see the reference entry for the IMAPISupport::SetProviderUID method.

IMSLogon::OpenEntry is identical to the IMsgStore::OpenEntry method of the message store object but is called by MAPI when processing an IMAPISession::OpenEntry method call instead of being called by the client application. Objects opened using IMSLogon::OpenEntry should be treated exactly the same as objects opened with the message store object; in particular, objects opened using this call should be invalidated when the message store object is released.

See Also

IMAPISupport::SetProviderUID method, IMsgStore::OpenEntry method


 IMSLogon::OpenStatusEntry

[New - Windows 95]

Opens a status object.

Syntax

HRESULT OpenStatusEntry(LPCIID lpInterface, ULONG ulFlags, ULONG FAR * lpulObjType, LPVOID FAR * lppEntry)

Parameters

lpInterface

Input parameter pointing to the interface identifier (IID) to be used for the returned object. Passing NULL for the lpInterface parameter indicates the MAPI interface for the object will be returned, in this case the IMAPIStatus interface. The lpInterface parameter can also be set to an identifier for another appropriate interface for the object.

ulFlags

Input parameter containing a bitmask of flags used to control how the status entry is opened. The following flag can be set:

MAPI_MODIFY

Requests read-write access. By default, objects are created with read-only access, and client applications should not work on the assumption that read-write access was granted.

lpulObjType

Output parameter pointing to a variable that holds the type of the opened object.

lppEntry

Output parameter pointing to a variable where the pointer to the returned object is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Message store providers use the IMSLogon::OpenStatusEntry method to open a status object. This status object is then used to enable client applications to call IMAPIStatus methods; for example, clients can use the IMAPIStatus::SettingsDialog method to reconfigure the message-store logon session or the IMAPIStatus::ValidateState method to validate the state of the message-store logon session.

See Also

IMAPIStatus : IMAPIProp interface, IMAPIStatus::SettingsDialog method, IMAPIStatus::ValidateState method


 IMSLogon::Unadvise

[New - Windows 95]

Removes an object's registration for notification of message store changes previously established with a call to the IMSLogon::Advise method.

Syntax

HRESULT Unadvise(ULONG ulConnection)

Parameters

ulConnection

Input parameter containing the number of the registration connection previously returned by a call to IMSLogon::Advise.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Message store providers use the IMSLogon::Unadvise method to cancel notifications for a message store object. To do so, Unadvise releases the pointer to the advise sink object passed in the lpAdviseSink parameter in the previous call to IMSLogon::Advise. As part of discarding the pointer to the advise sink, the advise sink's IUnknown::Release method is called. Generally, Release is called during the Unadvise call, but if another thread is in the process of calling the IMAPIAdviseSink::OnNotify method for the advise sink object, the Release call is delayed until the OnNotify method returns.

See Also

IMAPIAdviseSink::OnNotify method, IMSLogon::Advise method


 IMSProvider : IUnknown

[New - Windows 95]

The IMSProvider interface provides access to a message store provider through a message-store provider object. This message-store provider object is returned by the MSProviderInit entry point function of the message store provider's dynamic-link library (DLL). The object is primarily used by client applications or the MAPI spooler to open message stores.

MAPI uses one message-store provider object for all the message stores opened by the provider implementing the provider object for the current MAPI session. If a second MAPI session logs onto any open stores, MAPI calls MSProviderInit a second time to create a new message-store provider object for that session to use.

A message-store provider object must contain the following to operate correctly:

•	A pointer to the lpMalloc for use by all stores opened using this provider object.

•	The lpfAllocateBuffer, lpfAllocateMore, and lpfFreeBuffer routine pointers to the MAPIAllocateBuffer, MAPIAllocateMore, and MAPIFreeBuffer memory allocation functions.

•	A linked list of all the stores opened using this provider object and not yet closed.

At a Glance

Specified in header file:	MAPISPI.H
Object that supplies this interface:	Message-store provider object
Corresponding pointer type:	LPMSPROVIDER
Implemented by:	Message store providers
Called by:	MAPI
Vtable Order

Shutdown	Closes down a message store provider in an orderly fashion.
Logon	Logs MAPI onto one instance of a message store provider.
SpoolerLogon	Logs the MAPI spooler onto a message store.
CompareStoreIDs	Compares two message store entry identifiers to determine if they refer to the same store object.


 IMSProvider::CompareStoreIDs

[New - Windows 95]

Compares two message-store entry identifiers to determine if they refer to the same store object.

Syntax

HRESULT CompareStoreIDs(ULONG cbEntryID1, LPENTRYID lpEntryID1, ULONG cbEntryID2, LPENTRYID lpEntryID2, ULONG ulFlags, ULONG FAR * lpulResult)

Parameters

cbEntryID1

Input parameter containing the number of bytes in the entry identifier pointed to by the lpEntryID1 parameter.

lpEntryID1

Input parameter pointing to the first entry identifier to be compared.

cbEntryID2

Input parameter containing the number of bytes in the entry identifier pointed to by the lpEntryID2 parameter.

lpEntryID2

Input parameter pointing to the second entry identifier to be compared.

ulFlags

Reserved; must be zero.

lpulResult

Output parameter pointing to a variable that receives the result of the comparison; this variable is TRUE if the two entry identifiers refer to the same object, and FALSE otherwise.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

MAPI calls the IMSProvider::CompareStoreIDs method while processing a call to the IMAPISession::OpenMsgStore method; it calls CompareStoreIDs at this point to determine which section in the profile, if any, is associated with the message store being opened. A CompareStoreIDs call can be made when no message stores are open for a particular store provider. In addition, MAPI also calls CompareStoreIDs while processing a call made by the message store provider to the IMAPISupport::OpenProfileSection method.

The entry identifiers compared in the CompareStoreIDs call are both for the current message store provider's dynamic link library (DLL) and unwrapped store entry identifiers. For more information on wrapping store entry identifiers, see the reference entry for the IMAPISupport::WrapStoreEntryID method.

Comparing entry identifiers is useful because an object can have more than one valid entry identifier; such a situation can occur, for example, after a new version of a message store provider is installed.

See Also

IMAPISession::OpenMsgStore method, IMAPISupport::OpenProfileSection method, IMAPISupport::WrapStoreEntryID method


 IMSProvider::Logon

[New - Windows 95]

Logs MAPI onto one instance of a message store provider.

Syntax

HRESULT Logon(LPMAPISUP lpMAPISup, ULONG ulUIParam, LPTSTR lpszProfileName, ULONG cbEntryID, LPENTRYID lpEntryID, ULONG ulFlags, LPCIID lpInterface, ULONG FAR * lpcbSpoolSecurity, LPBYTE FAR * lppbSpoolSecurity, LPMAPIERROR FAR * lppMAPIError, LPMSLOGON FAR * lppMSLogon, LPMDB FAR * lppMDB)

Parameters

lpMAPISup

Input parameter pointing to the MAPI support object for the message store.

ulUIParam

Input parameter containing the handle of the window the logon dialog box is modal to.

lpszProfileName

Input parameter pointing to a string containing the name of the profile being used for the store provider logon. This string can be displayed in dialog boxes, written out to a log file, or simply ignored. It must be in Unicode format if the MAPI_UNICODE flag is set in the ulFlags parameter.

cbEntryID

Input parameter containing the number of bytes in the entry identifier pointed to by the lpEntryID parameter.

lpEntryID

Input parameter pointing to the entry identifier for the message store. Passing NULL in lpEntryID indicates that a message store has not yet been selected and that dialog boxes enabling the user to select a message store can be presented.

ulFlags

Input parameter containing a bitmask of flags used to control the logon. The following flags can be set:

MAPI_DEFERRED_ERRORS

Indicates the call is allowed to succeed even if the underlying object is not accessible to the calling application. If the object is not accessible, some subsequent call to the object might return an error.

MAPI_UNICODE

Indicates the passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

MDB_NO_DIALOG

Prevents display of logon dialog boxes. If this flag is set, the error value MAPI_E_LOGON_FAILED is returned if logon is unsuccessful. If this flag is not set, the message store provider can prompt the user to correct the name or password, to insert a disk, or to perform other actions necessary to establish connection to the store.

MDB_NO_MAIL

Indicates the message store should not be used for sending or receiving mail. The flag signals MAPI to not notify the MAPI spooler that this message store is being opened. If this flag is set, and the message store is tightly coupled with a transport provider, then the provider does not need to call the IMAPISupport::SpoolerNotify method.

MDB_TEMPORARY

Logs the store on so that information can be retrieved programmatically from the profile section. This flag instructs MAPI that the store is not to be added to the message store table and that the store cannot be made permanent. If this flag is set, message store providers do not need to call the IMAPISupport::ModifyProfile method.

MDB_WRITE

Requests read-write access.

lpInterface

Input parameter pointing to the interface identifier (IID) for the message store to be logged onto. Passing NULL for the lpInterface parameter indicates the MAPI interface for the message store will be returned — that is, the IMsgStore interface. The lpInterface parameter can also be set to an identifier for another appropriate interface for the message store, for example IID_IUnknown or IID_IMAPIProp.

lpcbSpoolSecurity

Output parameter pointing to the variable in which the store provider returns the size, in bytes, of the validation data in the lppbSpoolSecurity parameter.

lppbSpoolSecurity

Output parameter pointing to a variable where the pointer to the validation data to be returned is stored. This validation data is provided so the IMSProvider::SpoolerLogon method can log the MAPI spooler onto the same store as the message store provider.

lppMAPIError

Output parameter pointing to a variable where the pointer to the returned MAPIERROR structure, if any, is stored. The lppMAPIError parameter can be set to NULL if there is no MAPIERROR structure to return.

lppMSLogon

Output parameter pointing to a variable where the pointer to the message-store logon object for MAPI to log onto is stored.

lppMDB

Output parameter pointing to a variable where the pointer to the message store object for the MAPI spooler and client applications to log onto is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_LOGON_FAILED

A logon session could not be established.

MAPI_E_UNCONFIGURED

The profile does not contain enough information for the logon to complete. MAPI calls the provider's message service entry function.

MAPI_E_USER_CANCEL

The user canceled the operation, typically by clicking the Cancel button in the dialog box.

MAPI_W_ERRORS_RETURNED

The call succeeded, but the message store provider has error information available. Use the HR_FAILED macro to test for this warning, but the call should be handled as a successful return. Call IMAPISession::GetLastError to get the error information from the provider.

Comments

MAPI uses the IMSProvider::Logon method to do the majority of processing necessary to obtain access to a message store. Message store providers validate any user credentials necessary to access a particular store and return a message store object in the lppMDB parameter that the MAPI spooler and client applications can use.

In addition to the message store object returned for client and MAPI spooler use, the provider also returns a message-store logon object for MAPI's use in controlling this store. The message-store logon object and the message store object should be tightly linked inside your provider so each can affect the other. Usage of the store object and the logon object should be identical; there should be a one-to-one correspondence between the logon object and the store object such that the objects act as if they are one object exposing two interfaces. The two objects should also be created together and freed together.

The MAPI support object, created by MAPI and passed to the provider in the lpMAPISup parameter, provides access to functions in MAPI required by the provider. These functions include functions that save and retrieve profile information, access address books, and so on. The lpMAPISup pointer can be different for each store that is opened. While processing calls for a message store after logon, the store provider should use the lpMAPISup variable appropriate for that store. For any Logon call that opens a message store and succeeds in creating a message-store logon object, the provider must save a pointer to the MAPI support object in the store logon object and must call the IUnknown::AddRef method to add a reference for the support object.

The ulUIParam parameter should be used if the provider presents dialog boxes during the Logon call. However, dialog boxes should not be presented if the ulFlags parameter contains the MDB_NO_DIALOG flag. If a user interface is called but ulFlags does not allow it, or if for some other reason the user interface cannot be displayed, the provider should return the error value MAPI_E_LOGON_FAILED. If Logon displays a dialog box and the user cancels logon, typically by clicking the Cancel button in the dialog box, your provider should return the value MAPI_E_USER_CANCEL.

The lpEntryID parameter can either be NULL or point to an unwrapped store entry identifier previously created by this message store. If lpEntryID points to an unwrapped entry identifier, that entry identifier can come from one of several places:

•	It can be an entry identifier that the store provider previously wrapped and wrote to the profile section as a PR_ENTRYID property.

•	It can be an entry identifier that the provider previously wrapped and returned to a calling application as a PR_STORE_ENTRYID property.

•	It can be an entry identifier that the provider previously wrapped and returned to a calling application as the PR_ENTRYID property of a message store object.

In any of these cases, it is possible that the entry identifier was created on a different computer than the one currently being used.

Within this entry identifier, the current store provider should have put all the information needed to identify and locate the message store. This information can include network volume names, phone numbers, user account names, and so on. If the connection to the store cannot be made using the data in the entry identifier, then the store provider should display a dialog box that enables the user to select the store to be opened. A dialog box might be required, for example, if a server has been renamed, an account name has changed, or portions of the network are not running.

When lpEntryID is NULL, the message store to use has not yet been selected. The provider can still access a store without displaying a selection dialog box if it supports further methods to specify the store. For example, the provider can check its initialization file, or it can look for additional properties that were placed in its or the message service's profile section at configuration.

If your provider finds that all the required information is not in the profile, it should return MAPI_E_UNCONFIGURED so that the provider's message service entry function is called by MAPI to enable the user to select the store, or even to create one, and to enter an account name and password as needed. MAPI automatically creates a new profile section for a new store; this new profile section can be temporary or permanent, depending on how it has been added. If the store provider calls the IMAPISupport::ModifyProfile method, the new profile section becomes permanent and the store added to the list of message stores returned by the IMAPISession::GetMsgStoresTable method.

The lpInterface parameter specifies the IID of the interface required for the newly opened store object. Passing NULL in lpInterface specifies that the MAPI message store interface, IMsgStore, is required. Passing the message-store object IID, IID_IMsgStore, also specifies that the MAPI message store interface is required. If IID_IUnknown is passed in lpInterface, the provider should open the store using whatever interface derived from IUnknown that is best for the provider; again, this is typically the MAPI message store interface. When IID_IUnknown is passed, after the open operation succeeds the calling application uses the IUnknown::QueryInterface method to select an interface.

The IMSProvider::Logon call should return sufficient information, such as a path to the store and credentials for accessing the store, to allow the MAPI spooler to log onto the same store the store provider does without presenting any user interface. The parameters lpcbSpoolSecurity and lppbSpoolSecurity are used to return this information. The provider allocates the memory for this data by passing a pointer to a buffer in the MSProviderInit function's lpfAllocateBuffer parameter; the provider places the size of this buffer in lpcbSpoolSecurity.

MAPI frees this buffer when appropriate. If the MAPI spooler's logon to the store can be accomplished from the information in the profile section alone, the provider can return NULL in lppbSpoolSecurity, and zero for the information's size in lpcbSpoolSecurity. The MAPI spooler logon occurs as part of a different process than the store logon; because the buffer holding the passed information gets copied between processes, it might not be in memory at the same location for the MAPI spooler process as for the store provider process. Therefore, your provider shouldn't put addresses into the buffer. For more information on MAPI spooler logon, see the reference entry for the IMSProvider::SpoolerLogon method.

Most store providers use the IMAPISession::OpenProfileSection method of the support object passed in the lpMAPISup parameter for saving and retrieving user credentials and options. OpenProfileSection enables a store provider to save additional arbitrary information in a profile section and associate it with logon for a particular resource. For example, a store provider can save the user account name and password associated with a resource and any paths or other necessary information needed to access that resource for its logon.

Properties with property identifiers 0x6600 through 0x67FF are secure properties available to the provider for its own use to store private data in profile sections. For more information on the uses of properties in profile section objects, see the reference entry for the IProfSect : IMAPIProp interface.

In addition to any private data in properties with identifiers 0x6600 through 0x67FF, the store provider should provide information for the PR_RESOURCE_DISPLAY and PR_DISPLAY_NAME properties in its profile section. It should place in PR_RESOURCE_DISPLAY the display name of the provider itself — for example, Microsoft Personal Information Store. In PR_DISPLAY_NAME, the provider places an identifying string displayed to users so they can distinguish this message store from others they might have access to. Commonly, server names, user account names, or paths are used in PR_DISPLAY_NAME.

Some profile section properties are visible in the message stores table; others are visible during setup, installation, and configuration of the MAPI subsystem. The provider typically provides information for these visible properties both for a new profile section, which does not yet include saved credentials or private information, and when it finds that property information has changed. For more information on profile sections, see the reference entry for IMAPISupport::OpenProfileSection.

After successfully logging on a user, and before returning to MAPI, the store provider should create the array of properties for the status row for the resource and call IMAPISupport::ModifyStatusRow.

Logon calls that open message stores already open for the current MAPI session skip much of the processing described previously. These calls do not create status rows, do not return message-store logon objects, do not use AddRef for the MAPI support object, and do not return data for MAPI spooler logon. These calls do return S_OK and do return a message store object with the interface requested by the client.

To detect such calls, the provider should maintain a list in the message-store provider object of stores already open for this provider object. When processing a Logon call, the provider should scan this list of open stores and determine if the store to be logged onto is already open. If it is, user credentials do not need to be checked and dialog box display should be avoided if possible. If dialog boxes must be displayed, your provider should check information returned to see whether a store has been opened a second time. In addition, your provider should check for duplicate openings using lpEntryID at the beginning of Logon call processing.

Standard processing for a Logon call that accesses an open store is as follows:

1.	Your provider calls AddRef for the existing store object if the new interface being requested is the same as the interface for the existing store. Otherwise, it calls QueryInterface to get the new interface. If the new interface isn't one your store supports, your provider should return the error value MAPI_E_INTERFACE_NOT_SUPPORTED.

2.	Your provider returns a pointer to the required interface of the existing store object in lppMDB.

3.	Your provider returns NULL in lppMSLogon.

4.	Your provider should not open the profile for the support object passed in on the call. Neither should it register a provider unique identifier (UID), register a status row, nor return MAPI spooler logon data.

5.	Your provider should not call AddRef for the support object, because it does not require a pointer to the object.

Whenever possible, providers should return appropriate error and warning strings for Logon calls because doing so greatly eases the burden of users in figuring out why something did not work. To do so, your provider sets the members in the MAPIERROR structure. MAPI looks for, uses, and releases the MAPIERROR structure if it is returned by your provider.

Memory for this MAPIERROR structure should be allocated using the buffer passed in lpfAllocateBuffer on the MSProviderInit call. Any error strings contained in the returned structure should be in Unicode format if MAPI_UNICODE is set in ulFlags; otherwise, they should be in the appropriate 8-bit string character set for the platform.

See Also

IMAPISession::GetMsgStoresTable method, IMAPISession::OpenMsgStore method, IMAPISession::OpenProfileSection method, IMAPISupport::ModifyProfile method, IMAPISupport::ModifyStatusRow method, IMsgStore : IMAPIProp interface, IMSProvider::SpoolerLogon method, IProfSect : IMAPIProp interface, MAPIERROR structure, MSProviderInit function


 IMSProvider::Shutdown

[New - Windows 95]

Closes down a message store provider in an orderly fashion.

Syntax

HRESULT Shutdown(ULONG FAR * lpulFlags)

Parameters

lpulFlags

Reserved; must be a pointer to zero.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

MAPI calls the IMSProvider::Shutdown method just prior to releasing the message-store provider object. MAPI releases all logon objects for a provider before calling Shutdown for that provider.


 IMSProvider::SpoolerLogon

[New - Windows 95]

Logs the MAPI spooler onto a message store.

Syntax

HRESULT SpoolerLogon(LPMAPISUP lpMAPISup, ULONG ulUIParam, LPTSTR lpszProfileName, ULONG cbEntryID, LPENTRYID lpEntryID, ULONG ulFlags, LPCIID lpInterface, ULONG cbSpoolSecurity, LPBYTE lpbSpoolSecurity, LPMAPIERROR FAR * lppMAPIError, LPMSLOGON FAR * lppMSLogon, LPMDB FAR * lppMDB)

Parameters

lpMAPISup

Input parameter pointing to the MAPI support object for the message store.

ulUIParam

Input parameter containing the handle of the window the logon dialog box is modal to.

lpszProfileName

Input parameter pointing to a string containing the name of the profile being used for the MAPI spooler logon. This string can be displayed in dialog boxes, written out to a log file, or simply ignored. It must be in Unicode format if the MAPI_UNICODE flag is set in the ulFlags parameter.

cbEntryID

Input parameter containing the number of bytes in the entry identifier pointed to by the lpEntryID parameter.

lpEntryID

Input parameter pointing to the entry identifier for the message store. Passing NULL in the lpEntryID parameter indicates that a message store has not yet been selected and that dialog boxes enabling the user to select a message store can be presented.

ulFlags

Input parameter containing a bitmask of flags used to control the logon. The following flags can be set:

MAPI_DEFERRED_ERRORS

Indicates the call is allowed to succeed even if the underlying object is not accessible to the calling application. If the object is not accessible, some subsequent call to the object might return an error.

MAPI_UNICODE

Indicates the passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

MDB_NO_DIALOG

Prevents display of logon dialog boxes. If this flag is set, the error value MAPI_E_LOGON_FAILED is returned if logon is unsuccessful. If this flag is not set, the message store provider can prompt the user to correct the name or password, to insert a disk, or to perform other actions necessary to establish connection to the store.

MDB_WRITE

Requests read-write access.

lpInterface

Input parameter pointing to the interface identifier (IID) for the message store to be logged onto. Passing NULL for the lpInterface parameter indicates the MAPI interface for the message store will be returned — that is, the IMsgStore interface. The lpInterface parameter can also be set to an identifier for another appropriate interface for the message store, for example IID_IUnknown or IID_IMAPIProp.

cbSpoolSecurity

Input parameter pointing to the variable in which the store provider returns the size, in bytes, of validation data in the lppbSpoolSecurity parameter.

lpbSpoolSecurity

Input parameter pointing to a variable where the pointer to validation data to be returned is stored. The SpoolerLogon method uses this data to log the MAPI spooler onto the same store as the message store provider previously logged onto using the IMSProvider::Logon method.

lppMAPIError

Output parameter pointing to a variable where the pointer to the returned MAPIERROR structure, if any, is stored. The lppMAPIError parameter can be set to NULL if there is no MAPIERROR structure to return.

lppMSLogon

Output parameter pointing to a variable where the pointer to the message-store logon object for MAPI to log onto is stored.

lppMDB

Output parameter pointing to a variable where the pointer to the message store object for the MAPI spooler and client applications to log onto is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_UNCONFIGURED

The profile does not contain enough information for the logon to complete. MAPI calls the provider's message service entry function.

MAPI_W_ERRORS_RETURNED

The call succeeded, but the message store provider has error information available. Use the HR_FAILED macro to test for this warning, but the call should be handled as a successful return. Call IMAPISession::GetLastError to get the error information from the provider.

Comments

The MAPI spooler calls the IMSProvider::SpoolerLogon method to log onto a message store. The MAPI spooler should use the message store object returned by the message store provider in the lppMDB parameter during and after logon.

For consistency with the IMSProvider::Logon method, the provider also returns a message-store logon object in the lppMSLogon parameter. Usage of the store object and the logon object are identical for usual store logon, because there is a one-to-one correspondence between the logon object and the store object; you can think of the logon and store objects as one object exposing two interfaces. The two objects are created together and freed together.

The store provider should internally mark the returned message store object to indicate that the store is being used by the MAPI spooler. Some of the methods for this store object behave differently than for the message store object provided to client applications. Keeping this internal mark is the most common way of triggering the behavior specific to the MAPI spooler.

See Also

IMSProvider::Logon method, MAPIERROR structure


 IPersistMessage : IUnknown

[New - Windows 95]

The IPersistMessage interface is implemented by form objects to save, initialize, and load messages to and from forms. IPersistMessage works similarly to the OLE IPersistStorage interface; for more information on the IPersistStorage methods, and working with storage objects in general, see Inside OLE, Second Edition, and OLE Programmer's Reference, Volume One.

At a Glance

Specified in header file:	MAPIFORM.H
Object that supplies this interface:	Persist message object
Corresponding pointer type:	LPPERSISTMESSAGE
Implemented by:	Form objects
Called by:	Form viewers
Vtable Order

GetClassID	Returns a form's message class identifier.
IsDirty	Checks a form for changes made since the form was last saved.
InitNew	Provides a form with a base message on which to build a new message.
Load	Loads a form from a specified message.
Save	Saves a revised form back to the message from which it was loaded or created.
SaveCompleted	Returns a message to a form after a save or submission operation.
HandsOffMessage	Causes a message to release its storage object.


 IPersistMessage::GetClassID

[New - Windows 95]

Returns a form's message class identifier.

Syntax

HRESULT GetClassID(LPCLSID lpClassID)

Parameters

lpClassID

Input parameter pointing to the returned class identifier.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

For more information on working with class identifiers of storage objects, see the documentation for the IPersistStorage methods in OLE Programmer's Reference, Volume One.


 IPersistMessage::HandsOffMessage

[New - Windows 95]

Causes a form to release its message object.

Syntax

HRESULT HandsOffMessage()

Parameters

None

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

For more information on working with the hands-off state of storage objects, see OLE Programmer's Reference, Volume One.


 IPersistMessage::InitNew

[New - Windows 95]

Provides a form with a base message on which to build a new message.

Syntax

HRESULT InitNew( LPMAPIMESSAGESITE pMessageSite, LPMESSAGE pMessage)

Parameters

pMessageSite

Input parameter pointing to the message site the form uses to compose a new message.

pMessage

Input parameter pointing to the message the form uses to compose a new message.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Form viewers call the IPersistMessage::InitNew method to set up a form with a message site and a message so as to compose a new message within the form. When a message is loaded in a form with InitNew, it can be assumed that the following required properties, and no others, have been set by form server implementations:

PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED, PR_READ_RECEIPT_REQUESTED, PR_IMPORTANCE, PR_PRIORITY, PR_SENSITIVITY, PR_SENTMAIL_ENTRYID, PR_DELETE_AFTER_SUBMIT.

For more information on initializing new storage objects, see OLE Programmer's Reference, Volume One.


 IPersistMessage::IsDirty

[New - Windows 95]

Checks a form for changes made since the form was last saved.

Syntax

HRESULT IsDirty()

Parameters

None

Return Values

S_OK

The form is dirty.

S_FALSE

The form is not dirty.

Comments

For more information, see the documentation for the IPersistStorage methods in OLE Programmer's Reference, Volume One.


 IPersistMessage::Load

[New - Windows 95]

Loads a form from a specified message.

Syntax

HRESULT Load( LPMESSAGESITE pMessageSite, LPMESSAGE pMessage, ULONG ulMessageStatus, ULONG ulMessageFlags)

Parameters

pMessageSite

Input parameter pointing to the specified message to be loaded.

pMessage

Input parameter pointing to the message from which the message is loaded.

ulMessageStatus

Input parameter containing a bitmask of client application − or service provider − defined flags, copied from the message's PR_MSG_STATUS property, that provides information on the state of the message.

ulMessageFlags

Input parameter containing a bitmask of flags, copied from the message's PR_MESSAGE_FLAGS property, that indicates the current state of the message.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Form viewers call the IPersistMessage::Load method to load a form from a specified message. Load is used to read an existing message. Flags and status bits set in the existing message's PR_MESSAGE_FLAGS and PR_MSG_STATUS properties are preserved in the new message.

For more information on loading storage objects, see OLE Programmer's Reference, Volume One.

See Also

PR_MESSAGE_FLAGS property, PR_MSG_STATUS property


 IPersistMessage::Save

[New - Windows 95]

Saves a revised form back to the message from which it was loaded or created.

Syntax

HRESULT Save(LPMESSAGE pMessage, ULONG fSameAsLoad)

Parameters

pMessage

Input parameter pointing to a message.

fSameAsLoad

Input parameter indicating whether the message the pMessage parameter points to is the message from which the form was loaded or created.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Form viewers call the IPersistMessage::Save method to save a revised form back to the message from which it was loaded or created. The form must not commit changes to this message; changes are committed by the form server implementation that calls the save method.

For more information on saving storage objects, see the documentation on the IPersistStorage methods in OLE Programmer's Reference, Volume One.


 IPersistMessage::SaveCompleted

[New - Windows 95]

Returns a message to a form after a save or submission operation.

Syntax

HRESULT SaveCompleted( LPMESSAGE pMessage)

Parameters

pMessage

Input parameter pointing to the message.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Form viewers call the IPersistMessage::SaveCompleted method at the end of a save request or a failed dismissive operation such as save or delete. SaveCompleted returns the saved message to the form in which it was composed. Note that there is no reason to suppose the IPersistMessage interface used is the same interface as was held for the message at the beginning of the save operation. However, the interface is for the same message object.

For more information on saving storage objects, see the documentation on the IPersistStorage methods in OLE Programmer's Reference, Volume One.


 IProfAdmin : IUnknown

[New - Windows 95]

The IProfAdmin interface supports administration of profiles.

At a Glance

Specified in header file:	MAPIX.H
Object that supplies this interface:	Profile object
Corresponding pointer type:	LPPROFADMIN
Implemented by:	MAPI
Called by:	Client applications
Vtable Order

GetLastError	Returns information about the last error that occurred for the profile object.
GetProfileTable	Returns a table listing all profiles associated with a particular client application.
CreateProfile	Creates a new profile.
DeleteProfile	Deletes a profile.
ChangeProfilePassword	Changes the password for a profile.
CopyProfile	Copies a profile.
RenameProfile	Renames a profile.
SetDefaultProfile	Sets the default profile for a client application.
AdminServices	Enumerates and changes the message services in a profile.


 IProfAdmin::AdminServices

[New - Windows 95]

Enumerates and changes the message services in a profile.

Syntax

HRESULT AdminServices(LPTSTR lpszProfileName, LPTSTR lpszPassword, ULONG ulUIParam, ULONG ulFlags, LPSERVICEADMIN FAR * lppServiceAdmin)

Parameters

lpszProfileName

Input parameter pointing to a string containing the profile name. This parameter must not be NULL.

lpszPassword

Input parameter pointing to a string containing the profile password. If a client application passes NULL in the lpszPassword parameter and the profile requires a password to open, the profile provider displays a dialog box prompting the user for the password if the MAPI_DIALOG flag is set in the ulFlags parameter.

ulUIParam

Input parameter containing the handle of the window the dialog box is modal to.

ulFlags

Input parameter containing a bitmask of flags. The following flags can be set:

MAPI_UNICODE

Indicates the passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

MAPI_DIALOG

Displays a dialog box prompting the user for the correct password. If this flag is not set, no dialog box is displayed.

lppServiceAdmin

Output parameter pointing to a variable where the pointer to the message-service administration object is stored. The message-service administration object is used to change message service settings in the profile indicated in the lpszProfileName parameter.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_LOGON_FAILED

The specified profile doesn't exist, or the password was wrong and a dialog box could not be displayed to the user requesting the correct password because the MAPI_DIALOG flag was not set in the ulFlags parameter.

MAPI_E_USER_CANCEL

The user canceled the operation, typically by clicking the Cancel button in the dialog box.

Comments

Use the IProfAdmin::AdminServices method to obtain a message-service administration object so as to make configuration changes to the message services within a profile. Applications that only perform configuration should use IProfAdmin::AdminServices rather than the IMAPISession::AdminServices method because the IProfAdmin method creates no session object and loads no service providers. To make other changes, applications should use IMAPISession::AdminServices.

Applications calling IProfAdmin::AdminServices must specify an existing profile in lpszProfileName. When the specified profile does not exist, the call returns MAPI_E_LOGON_FAILED.

Profile providers are required to support names and passwords up to 64 characters in length. Profile providers are required to support the following characters in profile name and password strings:

•	All alphanumeric characters, including accent characters and the underscore character.

•	Embedded spaces, but not leading or trailing spaces.

Profile providers can support additional characters in profile and password names.

Profile providers are not required to implement support for profile passwords. Additionally, profile passwords are not supported on all operating system platforms; on platforms that do not support profile passwords, lpszPassword can be NULL or a pointer to a zero-length string. Currently, Windows NT™ and Windows 95 do not support passwords; Windows version 3.1 does.

See Also

IMAPISession::AdminServices method


 IProfAdmin::ChangeProfilePassword

[New - Windows 95]

Changes the password for a profile.

Syntax

HRESULT ChangeProfilePassword(LPTSTR lpszProfileName, LPTSTR lpszOldPassword, LPTSTR lpszNewPassword, ULONG ulFlags)

Parameters

lpszProfileName

Input parameter pointing to a string containing the name of the profile whose password is to be changed.

lpszOldPassword

Input parameter pointing to a string containing the original password.

lpszNewPassword

Input parameter pointing to a string containing the new password.

ulFlags

Input parameter containing a bitmask of flags controlling the type of the strings. The following flag can be set:

MAPI_UNICODE

Indicates the passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_LOGON_FAILED

The password is incorrect.

MAPI_E_NO_SUPPORT

The operating system platform does not support passwords.

Comments

Use the IProfAdmin::ChangeProfilePassword method to replace one profile password string with another. ChangeProfilePassword never displays a user interface.

Profile providers are not required to implement support for profile passwords. MAPI_E_NO_SUPPORT is returned if the operating system platform does not support passwords. Currently, Windows NT and Windows 95 do not support passwords; Windows version 3.1 does.


 IProfAdmin::CopyProfile

[New - Windows 95]

Copies a profile.

Syntax

HRESULT CopyProfile(LPTSTR lpszOldProfileName, LPTSTR lpszOldPassword, LPTSTR lpszNewProfileName, ULONG ulUIParam, ULONG ulFlags)

Parameters

lpszOldProfileName

Input parameter pointing to a string containing the name of the profile to be copied.

lpszOldPassword

Input parameter pointing to a string containing the password of the profile to be copied.

lpszNewProfileName

Input parameter pointing to a string containing the name of the new profile to be created.

ulUIParam

Input parameter containing the handle of the window the dialog box is modal to.

ulFlags

Input parameter containing a bitmask of flags used to control how the profile is copied. The following flags can be set:

MAPI_DIALOG

Displays a dialog box prompting the user for the correct password. If this flag is not set, no dialog box is displayed.

MAPI_UNICODE

Indicates the passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_ACCESS_DENIED

The new profile name is the same as an existing profile.

MAPI_E_LOGON_FAILED

The old password is incorrect, and a dialog box could not be displayed to the user requesting the correct password, because the MAPI_DIALOG flag was not set in the ulFlags parameter.

MAPI_E_NOT_FOUND

The specified profile does not exist.

MAPI_E_USER_CANCEL

The user canceled the operation, typically by clicking the Cancel button in the dialog box.

Comments

The IProfAdmin::CopyProfile method makes a copy of the profile indicated in the lpszOldProfileName parameter and names the copy using the string given in the lpszNewProfileName parameter. Copying a profile leaves the copy with the same password as the original.

Profile providers are required to support names and passwords up to 64 characters in length. Profile providers are required to support the following characters in profile name and password strings:

•	All alphanumeric characters, including accent characters and the underscore character.

•	Embedded spaces, but not leading or trailing spaces.

Profile providers can support additional characters in profile and password names.

Profile providers are not required to implement support for profile passwords. Additionally, profile passwords are not supported on all operating system platforms; on platforms that do not support profile passwords, lpszPassword can be NULL or a pointer to a zero-length string. Currently, Windows NT and Windows 95 do not support passwords; Windows version 3.1 does.

If a client application passes NULL in lpszOldPassword and the profile requires a password to open, the profile provider must display a dialog box prompting the user to provide a password. If the wrong password is supplied in lpszOldPassword and the MAPI_DIALOG flag is not set in the ulFlags parameter, the call returns MAPI_E_LOGON_FAILED instead of prompting the user to provide the correct password.


 IProfAdmin::CreateProfile

[New - Windows 95]

Creates a new profile.

Syntax

HRESULT CreateProfile(LPTSTR lpszProfileName, LPTSTR lpszPassword, ULONG ulUIParam, ULONG ulFlags)

Parameters

lpszProfileName

Input parameter pointing to a string containing the name of the new profile.

lpszPassword

Input parameter pointing to a string containing the password of the new profile.

ulUIParam

Input parameter containing the handle to the window the dialog box is modal to.

ulFlags

Input parameter containing a bitmask of flags used to control how the profile is created. The following flags can be set:

MAPI_DEFAULT_SERVICES

Indicates that MAPI should populate the new profile with message services as indicated by the [Default Services] section in the MAPISVC.INF file.

MAPI_DIALOG

Displays each service provider's configuration property sheets. If this flag is not set, then all the message services added by this call are unconfigured.

MAPI_UNICODE

Indicates the passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NO_ACCESS

The specified profile already exists.

Comments

Client applications call the IProfAdmin::CreateProfile method to create a new profile. CreateProfile can be used during client installation, at which point it can read data from a configuration file to fill its input parameters. CreateProfile is also used by clients that enable users to create new profiles; in such a case, the parameters receive input from a dialog box displayed by the client.

If the MAPI_DEFAULT_SERVICES flag is set in the ulFlags parameter, the message-service entry function is called for each message service in the [Default Services] section in the MAPISVC.INF file. The message service entry function is called with the MSG_SERVICE_CREATE value set in the ulContext parameter . If both the MAPI_DIALOG and MAPI_DEFAULT_SERVICES flags are set in the CreateProfile method's ulFlags parameter, then the values in the ulUIParam and ulFlags parameters are also passed when the service provider's message-service entry function is called. Service providers should display their configuration property sheets so that the user can configure the message service. The message-service entry function is only called after all available information from the MAPISVC.INF file has been added to the profile.

Profile providers are required to support names and passwords up to 64 characters in length. Profile providers are required to support the following characters in profile name and password strings:

•	All alphanumeric characters, including accent characters and the underscore character.

•	Embedded spaces, but not leading or trailing spaces.

Profile providers can support additional characters in profile and password names.

Profile providers are not required to implement support for profile passwords. Additionally, profile passwords are not supported on all operating system platforms; on platforms that do not support profile passwords, lpszPassword can be NULL or a pointer to a zero-length string. Currently, Windows NT and Windows 95 do not support passwords; Windows version 3.1 does.

If a profile with the same name as passed in the lpszProfileName parameter already exists, CreateProfile returns MAPI_E_NO_ACCESS.

See Also

IMsgServiceAdmin::ConfigureMsgService method, IMsgServiceAdmin::CreateMsgService method, MSGSERVICEENTRY function prototype


 IProfAdmin::DeleteProfile

[New - Windows 95]

Deletes a profile.

Syntax

HRESULT DeleteProfile(LPTSTR lpszProfileName, ULONG ulFlags)

Parameters

lpszProfileName

Input parameter pointing to a string containing the name of the profile to be deleted.

ulFlags

Input parameter containing a bitmask of flags controlling the type of the string. The following flag can be set:

MAPI_UNICODE

Indicates the passed-in string is in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NOT_FOUND

The specified profile does not exist.

Comments

Use the IProfAdmin::DeleteProfile method to delete profiles. If the profile indicated in the lpszProfileName parameter does not exist, MAPI_E_NOT_FOUND is returned. If the profile to be deleted is in use by an application when DeleteProfile is called, S_OK is returned, but the profile is not deleted immediately. Instead, MAPI marks the profile for deletion and deletes it after all applications have logged off the profile.

The message-service entry function is called for each message service in the MAPISVC.INF file before each service is removed from the profile. The message-service entry function is called with the MSG_SERVICE_DELETE value set in the ulContext parameter . First the service is deleted, and then the service's profile section skeleton is deleted. The message-service entry function is not called again after the service has been deleted.

No password is required to delete a profile.

See Also

IMsgServiceAdmin::DeleteMsgService method, MSGSERVICEENTRY function prototype


 IProfAdmin::GetLastError

[New - Windows 95]

Returns a MAPIERROR structure containing information about the last error that occurred for the profile administration object.

Syntax

HRESULT GetLastError(HRESULT hResult, ULONG ulFlags, LPMAPIERROR FAR * lppMAPIError)

Parameters

hResult

Input parameter containing the result returned for the last call on the session object that returned an error.

ulFlags

Input parameter containing a bitmask of flags controlling the type of the returned strings. The following flag can be set:

MAPI_UNICODE

Indicates the strings returned in the MAPIERROR structure returned in the lppMAPIError parameter are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

lppMAPIError

Output parameter pointing to a pointer to the returned MAPIERROR structure containing version, component, and context information for the error. The lppMAPIError parameter can be set to NULL if there is no MAPIERROR structure to return.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_BAD_CHARWIDTH

Either the MAPI_UNICODE flag was set and the implementation does not support Unicode, or MAPI_UNICODE was not set and the implementation only supports Unicode.

Comments

Use the IProfAdmin::GetLastError method to retrieve information to display as a message to the user regarding the last error returned from a method call on the profile administration object.

To release all the memory allocated by MAPI for the MAPIERROR structure, client applications need only call the MAPIFreeBuffer function.

The return value from GetLastError must be S_OK for the application to make use of the MAPIERROR structure. Even if the return value is S_OK, it is still possible that a MAPIERROR structure won't be returned. If the implementation cannot determine what the last error was, or if a MAPIERROR structure is not available for that error, a pointer to NULL is returned in the lppMAPIError parameter instead.

See Also

MAPIERROR structure, MAPIFreeBuffer function


 IProfAdmin::GetProfileTable

[New - Windows 95]

Returns a table listing all profiles associated with a particular client application.

Syntax

HRESULT GetProfileTable(ULONG ulFlags, LPMAPITABLE FAR * lppTable)

Parameters

ulFlags

Input parameter containing a bitmask of flags controlling the type of the returned strings in the table's default column set. The following flag can be set:

MAPI_UNICODE

Indicates the returned strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

lppTable

Output parameter pointing to a variable where the pointer to the returned table object is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

A client application calls the IProfAdmin::GetProfileTable method to get a table containing rows listing information for each profile that has been created for use with that client. The columns of the profile table contain current information for the following properties:

PR_DISPLAY_NAME

The name of a particular profile. To log onto this profile, your client passes this name to the MAPILogonEx function.

PR_DEFAULT_PROFILE

A value indicating whether this profile is the default profile. If this column is present, its value must also be TRUE.

Profiles that have been deleted, or are in use but have been marked for deletion, are not returned in the profile table. Once a profile table has been returned, it does not reflect changes being made to the profile, such as adding or deleting profiles. IMAPITable::Advise calls on the profile table return S_OK, but no changes are made to the table. If no profile exists, GetProfileTable does not return an error; a table object supporting the IMAPITable interface is returned. If you call the IMAPITable::QueryRows method on that table, zero rows are returned.

Setting the MAPI_UNICODE flag in the ulFlags parameter does the following:

•	Sets the string type to Unicode for data returned for the initial active columns of the profile table by the IMAPITable::QueryColumns method. The initial active columns for a profile table are those columns the QueryColumns method returns before the application that contains the profile table calls the IMAPITable::SetColumns method.

•	Sets the string type to Unicode for data returned for the initial active rows of the profile table by the IMAPITable::QueryRows method. The initial active rows for a profile table are those rows QueryRows returns before the application that contains the profile table calls the IMAPITable::SetColumns method.

•	Controls the property types of the sort order specification returned by the IMAPITable::QuerySortOrder method before the application that contains the profile table calls the IMAPITable::SortTable method.

See Also

IMAPITable : IUnknown interface, MAPILogonEx function


 IProfAdmin::RenameProfile

[New - Windows 95]

Renames a profile.

Syntax

HRESULT RenameProfile(LPTSTR lpszOldProfileName, LPTSTR lpszOldPassword, LPTSTR lpszNewProfileName, ULONG ulUIParam, ULONG ulFlags)

Parameters

lpszOldProfileName

Input parameter pointing to a string containing the name of the profile to be renamed.

lpszOldPassword

Input parameter pointing to a string containing the password of the profile to be renamed. If NULL is passed in the lpszOldPassword parameter, and the profile requires a password, the profile provider will display a dialog box prompting the user for the password.

lpszNewProfileName

Input parameter pointing to a string containing the name of the profile to be renamed.

ulUIParam

Input parameter containing the handle of the window the dialog box is modal to.

ulFlags

Input parameter containing a bitmask of flags controlling the rename operation. The following flags can be set:

MAPI_DIALOG

Displays a dialog box prompting the user for the correct password. If this flag is not set, no dialog box is displayed.

MAPI_UNICODE

Indicates the passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_USER_CANCEL

The user canceled the operation, typically by clicking the Cancel button in the dialog box.

MAPI_E_LOGON_FAILED

The password is incorrect.

Comments

The IProfAdmin::RenameProfile method takes the profile name in the lpszOldProfileName parameter and replaces it with the profile name in the lpszNewProfileName parameter. Renaming the profile does not change the password. If the profile to be renamed is in use by an application when RenameProfile is called, S_OK is returned, but the profile is not renamed immediately. Instead, MAPI marks the profile for renaming and renames it after all applications have logged off the profile.

Profile providers are required to support names and passwords up to 64 characters in length. Profile providers are required to support the following characters in profile name and password strings:

•	All alphanumeric characters, including accent characters and the underscore character.

•	Embedded spaces, but not leading or trailing spaces.

Profile providers can support additional characters in profile and password names.

Profile providers are not required to implement support for profile passwords. Additionally, profile passwords are not supported on all operating system platforms; on platforms that do not support profile passwords, lpszOldPassword can be NULL or a pointer to a zero-length string. Currently, Windows NT and Windows 95 do not support passwords; Windows version 3.1 does.

If a client application passes NULL in lpszOldPassword and the profile requires a password to open, the profile provider must display a dialog box prompting the user to provide a password. If the wrong password is supplied in lpszOldPassword and the MAPI_DIALOG flag is not set in the ulFlags parameter, the call returns MAPI_E_LOGON_FAILED instead of prompting the user to provide the correct password.


 IProfAdmin::SetDefaultProfile

[New - Windows 95]

Sets the default profile for a client application.

Syntax

HRESULT SetDefaultProfile(LPTSTR lpszProfileName, ULONG ulFlags)

Parameters

lpszProfileName

Input parameter pointing to a string containing the name of the new default profile. If your client application passes either NULL or a pointer to a zero-length string in the lpszProfileName parameter, there will not be any default profile and any existing default profile setting is removed.

ulFlags

Input parameter containing a bitmask of flags controlling the type of the string. The following flag can be set:

MAPI_UNICODE

Indicates the passed-in string is in Unicode format. If the MAPI_UNICODE flag is not set, the string is in 8-bit format.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NOT_FOUND

The specified profile does not exist.

Comments

Use the IProfAdmin::SetDefaultProfile method to set the name of the profile to be used as the default profile when a particular client application logs onto a MAPI session. This is the profile that is used when applications pass the MAPI_USE_DEFAULT flag when calling the MAPILogonEx function. SetDefaultProfile also changes the PR_DEFAULT_PROFILE property within the profile.

See Also

IProfAdmin::GetProfileTable method, MAPILogon function, MAPILogonEx function, PR_DEFAULT_PROFILE property


 IProfSect : IMAPIProp

[New - Windows 95]

The IProfSect interface is used to work with properties of profile section objects by calling methods of the IMAPIProp interface. IProfSect does not have any unique methods of its own, but you can call the IMAPIProp methods on a profile section object with the following restrictions.

The profile section object does not support a transaction model, so all changes made to a profile section following calls to the IProfSect::CopyProps and IProfSect::CopyTo methods occur immediately. Calls to the IProfSect::SaveChanges method succeed but don't actually save any changes. One consequence of this implementation is that when property sheets or dialog boxes work on a profile section object directly, changes made by the user occur instantly. Rather than providing a direct implementation of this sort, service providers should instead implement their property sheets and dialog boxes using copies of the profile section object as following:

1.	Open the profile section with the IMAPISupport::OpenProfileSection method.

2.	Get an IPropData object.

3.	Use the IProfSect::CopyTo method to copy properties from the profile section to the IPropData object.

4.	Use the IPropData object as the source object for the data in the lpConfigData parameter of the IMAPISupport::DoConfigPropSheet method used to display your configuration user interface.

5.	When the user saves changes to the property sheet, call the IMAPIProp::CopyTo method to copy the properties from the IPropData object to the profile section.

Profile section objects also do not support named properties; both the IProfSect::GetIDsFromNames and IProfSect::GetNamesFromIDs methods return MAPI_E_NO_SUPPORT if called on a profile section object.

Calls to the IProfSect::SetProps method on properties in the range above x8000 return PT_ERROR as the property type.

Profile sections also reserve the range 0X67F0 to 0X67FF as secure properties. Service providers can use this range to store passwords and other provider specific credentials. Properties in this range are not returned in the complete list of properties when NULL is passed in the lpPropTag parameter of the IProfSect::GetProps method, nor are they returned in the lppPropTagArray parameter of the IProfSect::GetPropList method. Secure properties must be requested specifically by their identifier.

For more information on working with profile section objects, see MAPI Programmer's Guide.

At a Glance

Specified in header file:	MAPIX.H
Object that supplies this interface:	Profile section object
Corresponding pointer type:	LPPROFSECT
Implemented by:	Profile providers
Called by:	Client applications
Vtable Order

No unique methods.


 IPropData : IMAPIProp

[New - Windows 95]

Client applications and service providers use the IPropData interface to add properties to an object and to get and set access rights for objects and properties. The IPropData interface is derived from IMAPIProp and does not have an object type of its own. To get an IPropData interface, call the QueryInterface method passing in an interface identifier of IID_IPropData. For additional information about using the IPropData interface to manage data associated with IMAPIProp interfaces, see MAPI Programmer's Guide.

At a Glance

Specified in header file:	MAPIUTIL.H
Object that supplies this interface:	This interface has no object type of its own.
Corresponding pointer type:	LPPROPDATA
Implemented by:	MAPI
Called by:	Client applications, service providers
Vtable Order

HrSetObjAccess	Sets the access rights for an object.
HrSetPropAccess	Sets the access rights for the specified properties, and also sets the state of the object relative to the IPROP_CLEAN or IPROP_DIRTY flags.
HrGetPropAccess	Returns the access rights currently set for the specified properties.
HrAddObjProps	Adds properties of type PT_OBJECT to an object.


 IPropData::HrAddObjProps

[New - Windows 95]

Adds properties of type PT_OBJECT to an object.

Syntax

HRESULT HrAddObjProps(LPSPropTagArray lpPropTagArray, LPSPropProblemArray FAR * lppProblems)

Parameters

lpPropTagArray

Input parameter pointing to an SPropTagArray structure containing an array of property tags indicating the properties to be added to the object.

lppProblems

Output parameter pointing to a variable where the pointer to the returned SPropProblemArray structure is stored. This structure indicates the properties that couldn't be accessed and should be checked when the method returns. If a pointer to NULL is passed in the lppProblems parameter, then no SPropProblemArray is returned even if some properties were not added to the object.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NO_ACCESS

The object has been set to not allow read-write access.

MAPI_E_INVALID_TYPE

A property type other than PT_OBJECT was passed in the SPropTagArray structure.

MAPI_W_PARTIAL_COMPLETION

Some, but not all of the properties, were added.

Comments

Use the IPropData::HrAddObjProps method to add properties to an object. The properties being added in the SPropTagArray structure in the lpPropTagArray parameter must be of type PT_OBJECT. If properties of types other than PT_OBJECT are added, the call returns MAPI_E_INVALID_TYPE.

If the HrAddObjProps call returns MAPI_W_PARTIAL_COMPLETION and a pointer to an SPropProblemArray structure in the lppProblems parameter, check the returned SPropProblemArray structure to find out which properties were not added. The SPropProblemArray structure must be freed by calling the MAPIFreeBuffer function.

If the object has previously been set to disallow read-write access, MAPI_E_NO_ACCESS is returned. To obtain read-write access, first call the IPropData::SetObjAccess method passing in the IPROP_READWRITE flag in the ulAccess parameter. Then call HrAddObjProps to add properties to the object.

See Also

MAPIFreeBuffer function, SPropProblemArray structure, SPropTagArray structure


 IPropData::HrGetPropAccess

[New - Windows 95]

Returns the access rights currently set for the specified properties.

Syntax

HRESULT HrGetPropAccess(LPSPropTagArray FAR * lppPropTagArray, ULONG FAR * FAR * lprgulAccess)

Parameters

lppPropTagArray

Input-output parameter that on input contains an SPropTagArray structure indicating the property tags for which to return access rights. If a pointer to NULL is passed in lppPropTagArray, then access rights for all properties on the object are sought. On output, lppPropTagArray points to a variable where the returned SPropTagArray structure is stored. This returned SPropTagArray structure contains the access rights for the specified properties.

lprgulAccess

Output parameter pointing to a variable where an array of bitmasks of flags is returned. Each bitmask indicates the access rights of one of the individual properties returned in the SPropTagArray. For each property tag, the following flags can be returned:

IPROP_CLEAN

Indicates that the property hasn't been modified.

IPROP_DIRTY

Indicates that the property has been modified.

IPROP_READONLY

Indicates that the property is read-only.

IPROP_READWRITE

Indicates that the property is read-write.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Use the IPropData::HrGetPropAccess method to get the access rights for each property of an object. HrGetPropAccess is also used to check whether a property has been modified or deleted. If a property you requested has already been deleted, it will not be returned in the SPropTagArray structure; zero is returned instead. If you passed a pointer to NULL in the lppPropTagArray parameter, the deleted property will not be returned in the array. If a property has been modified, its IPROP_DIRTY flag will be set.

See Also

SPropTagArray structure


 IPropData::HrSetObjAccess

[New - Windows 95]

Sets the access rights for an object.

Syntax

HRESULT HrSetObjAccess(ULONG ulAccess)

Parameters

ulAccess

Input parameter containing a bitmask of flags used to set the access rights of the object. One of the following flags can be set:

IPROP_READONLY

Indicates that the properties on the object are read-only.

IPROP_READWRITE

Indicates that the properties on the object are read-write.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Use the IPropData::HrSetObjAccess method to set the access rights for an object. By default, all MAPI objects have read-write access set when they are created. If you want to set access rights on individual properties, first set the access rights on the object by calling HrSetObjAccess with the IPROP_READWRITE flag set in the ulAccess parameter. Then call IPropData::HrSetPropAccess to set the access for the properties.

See Also

IPropData::HrGetPropAccess method, IPropData::HrSetPropAccess method


 IPropData::HrSetPropAccess

[New - Windows 95]

Sets the access rights for the specified properties, and also sets the state of the object relative to the IPROP_CLEAN or IPROP_DIRTY flags.

Syntax

HRESULT HrSetPropAccess(LPSPropTagArray lpPropTagArray, ULONG FAR * rgulAccess)

Parameters

lpPropTagArray

Input parameter pointing to an SPropTagArray structure containing an array of property tags indicating the properties affected by the access flags in the array of bitmasks in the rgulAccess parameter.

rgulAccess

Input parameter containing an array of bitmasks of flags used to set the access rights of the properties listed in the SPropTagArray structure in the lpPropTagArray parameter. For each property tag, the following flags can be set:

IPROP_CLEAN

Sets the individual property to an unmodified state.

IPROP_DIRTY

Sets the individual property to a modified state.

IPROP_READONLY

Sets the individual property to read-only.

IPROP_READWRITE

Sets the individual property to read-write.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NO_ACCESS

An attempt to modify a read-only object or an attempt to access an object for which the user has insufficient permissions.

Comments

Use the IPropData::HrSetPropAccess method to set the access rights for each individual property in the SPropTagArray structure in the lpPropTagArray parameter. These rights are set based on the flags set in the corresponding bitmasks in the rgulAccess parameter. By default, all MAPI properties have read-write access set when they are created.

The valid flag combinations for the bitmask in the rgulAccess parameter are shown in the following table.

IPROP_READONLY	IPROP_READWRITE	IPROP_CLEAN	IPROP_DIRTY
•		•
•			•
	•	•
	•		•
The flags IPROP_READONLY and IPROP_READWRITE are mutually exclusive, as are the flags IPROP_CLEAN and IPROP_DIRTY. If any flag combinations are set other than those listed directly previously, HrSetPropAccess returns MAPI_E_INVALID_PARAMETER.

See Also

IPropData::HrSetPropAccess method, SPropTagArray structure


 IProviderAdmin : IUnknown

[New - Windows 95]

The IProviderAdmin interface is used to manage the service providers within a message service. You can get a pointer to an IProviderAdmin interface in two ways: by calling the IMsgServices::AdminProviders method or from within a provider's message-service entry function. Client applications calling methods of the IProviderAdmin interface are not allowed to create or delete providers; all such changes made to a message service must be made from within the context of a message-service entry function. Most message services do not allow providers to be added or deleted while the profile is in use. The results are unpredictable if you make changes to the profile section of a service that doesn't support changes.

At a Glance

Specified in header file:	MAPIDEFS.H
Object that supplies this interface:	Provider administration object
Corresponding pointer type:	LPPROVIDERADMIN
Implemented by:	MAPI
Called by:	Client applications, message-service entry function
Vtable Order

GetLastError	Returns information about the last error that occurred for a provider administration object.
GetProviderTable	Returns a table object listing the service providers in a message service.
CreateProvider	Adds a service provider to a message service.
DeleteProvider	Deletes a service provider from a message service.
OpenProfileSection	Opens a section of the current profile and returns a pointer that provides further access to the profile object.


 IProviderAdmin::CreateProvider

[New - Windows 95]

Adds a service provider to a message service.

Syntax

HRESULT CreateProvider(LPTSTR lpszProvider, ULONG cValues, LPSPropValue lpProps, ULONG ulUIParam, ULONG ulFlags, MAPIUID FAR * lpUID)

Parameters

lpszProvider

Input parameter pointing to a string containing the name of the provider to be added to the message service.

cValues

Input parameter containing the number of property values in the SPropValue structure pointed to by the lpProps parameter.

lpProps

Input parameter pointing to an SPropValue structure containing the property values of the properties associated with this provider object.

ulUIParam

Input parameter containing the handle of the window the dialog box is modal to. The ulUIParam parameter is used if the MAPI_DIALOG flag is set in the ulFlags parameter.

ulFlags

Input parameter containing a bitmask of flags controlling the type of the string. The following flag can be set:

MAPI_UNICODE

Indicates the passed-in string is in Unicode format. If the MAPI_UNICODE flag is not set, the string is in 8-bit format.

lpUID

Output parameter pointing to the MAPIUID structure holding the unique identifier for the provider to be added.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_USER_CANCEL

The user canceled the operation, typically by clicking the Cancel button in the dialog box.

Comments

Use the IProviderAdmin::CreateProvider method to add a provider to a message service. The string in the lpszProvider parameter must be for a provider that belongs to the message service. MAPI does not verify that they do in fact match; if they don't, the call succeeds, but the results are unpredictable. Most message services do not allow providers to be added or deleted while the profile is in use.

The message-service entry function for the message service is called with the MSG_SERVICE_PROVIDER_CREATE value set in the ulContext parameter. If the MAPI_DIALOG flag is set in the CreateProvider method's ulFlags parameter, then the values in the ulUIParam and ulFlags parameters are also passed when the service provider's message-service entry function is called. Service providers should display their configuration property sheets so that the user can configure the message service.

The message-service entry function is only called after all available information from the MAPISVC.INF file has been added to the profile.

See Also

MAPIUID structure, MSGSERVICEENTRY function prototype, SPropValue structure


 IProviderAdmin::DeleteProvider

[New - Windows 95]

Deletes a service provider from a message service.

Syntax

HRESULT DeleteProvider(LPMAPIUID lpUID)

Parameters

lpUID

Input parameter pointing to the MAPIUID structure holding the unique identifier for the provider being deleted.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NOT_FOUND

The MAPIUID was not recognizable.

Comments

Use the IProviderAdmin::DeleteProvider method to delete from a message service the provider indicated by the unique identifier in the lpUID parameter. Most message services do not allow providers to be added or deleted while the profile is in use. If the provider to be deleted is in use by an application when DeleteProvider is called, S_OK is returned, but the provider is not deleted immediately. Instead, MAPI marks the provider for deletion and deletes it after all applications have logged off the provider.

The message-service entry function is called for the message service before the provider is removed from the service. The message-service entry function is called with the MSG_SERVICE_PROVIDER_DELETE value set in the ulContext parameter . First the provider is deleted, then the provider's profile section skeleton is deleted. The message service entry function is not called again after the provider has been deleted.

See Also

MAPIUID structure, MSGSERVICEENTRY function prototype


 IProviderAdmin::GetLastError

[New - Windows 95]

Returns a MAPIERROR structure containing information about the last error that occurred for the provider administration object.

Syntax

HRESULT GetLastError(HRESULT hResult, ULONG ulFlags, LPMAPIERROR FAR * lppMAPIError)

Parameters

hResult

Input parameter containing the result returned for the last call on the provider administration object that returned an error.

ulFlags

Input parameter containing a bitmask of flags controlling the type of the returned strings. The following flag can be set:

MAPI_UNICODE

Indicates the strings returned in the MAPIERROR structure returned in the lppMAPIError parameter are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

lppMAPIError

Output parameter pointing to a pointer to the returned MAPIERROR structure containing version, component, and context information for the error. The lppMAPIError parameter can be set to NULL if there is no MAPIERROR structure to return.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_BAD_CHARWIDTH

Either the MAPI_UNICODE flag was set and the implementation does not support Unicode, or MAPI_UNICODE was not set and the implementation only supports Unicode.

Comments

Use the IProviderAdmin::GetLastError method to retrieve information to display as a message to the user regarding the last error returned from a method call on the provider administration object.

To release all the memory allocated by MAPI for the MAPIERROR structure, client applications need only call the MAPIFreeBuffer function.

The return value from GetLastError must be S_OK for the application to make use of the MAPIERROR structure. Even if the return value is S_OK, it is still possible that a MAPIERROR structure won't be returned. If the implementation cannot determine what the last error was, or if a MAPIERROR structure is not available for that error, a pointer to NULL is returned in the lppMAPIError parameter instead.

See Also

MAPIERROR structure, MAPIFreeBuffer function


 IProviderAdmin::GetProviderTable

[New - Windows 95]

Returns a table object listing the service providers in a message service.

Syntax

HRESULT GetProviderTable(ULONG ulFlags, LPMAPITABLE FAR * lppTable)

Parameters

ulFlags

Input parameter containing a bitmask of flags controlling the strings in the default column set of the table. The following flag can be set:

MAPI_UNICODE

Indicates the returned strings are to be in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

lppTable

Output parameter pointing to a variable where the pointer to the returned table object is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Use the IProviderAdmin::GetProviderTable method to get a pointer to a table object that lists all of the address book, message store, transport, and message hook providers currently installed as part of a message service. The columns of the provider table contain the current information for the following properties:

PR_DISPLAY_NAME

The provider's name as given by the provider.

PR_INSTANCE_KEY

A search key for an instance of a particular MAPI object.

PR_PROVIDER_DISPLAY

The name of the provider as given by the message service. This name is not localizable and is a reliable way to search on a particular provider.

PR_PROVIDER_DLL_NAME

The dynamic-link library (DLL) for a particular provider.

PR_PROVIDER_UID

Identifies a particular instance of a provider.

PR_RESOURCE_TYPE

An enumeration describing the type of the provider. This property can be used to determine all the providers of a particular type that are installed within a profile.

PR_SERVICE_NAME

The name of the message service as given by the message service. This name is not localizable and is a reliable way to search on a particular service.

PR_SERVICE_UID

Identifies a particular instance of a message service.

The following properties are computed only for transport providers:

PR_PROVIDER_ORDINAL

A number computed by MAPI that identifies the order in which the providers are listed in the profile.

PR_RESOURCE_FLAGS

Flags describing the capabilities of the provider.

The provider table's PR_PROVIDER_ORDINAL property can be used to restrict sort operations on the table. The first transport provider in the list has PR_PROVIDER_ORDINAL set to 0, the next provider to 1, and so on; this functionality enables your client application to retrieve the table with the list of providers set to the correct order.

Providers that have been deleted, or are in use but have been marked for deletion, are not returned in the provider administration table. Once a provider administration table has been returned, it does not reflect changes being made to the profile, such as adding or deleting providers. IMAPITable::Advise calls on the provider administration table return S_OK, but no changes are made to the table. If no provider exists, GetProviderTable does not return an error; a table object supporting the IMAPITable interface is returned. If you call IMAPITable::QueryRows on that table, zero rows are returned.

Setting the MAPI_UNICODE flag in the ulFlags parameter does the following:

•	Sets the string type to Unicode for data returned for the initial active columns of the provider administration table by the IMAPITable::QueryColumns method. The initial active columns for a provider administration table are those columns the QueryColumns method returns before the application that contains the provider administration table calls the IMAPITable::SetColumns method.

•	Sets the string type to Unicode for data returned for the initial active rows of the provider administration table by the IMAPITable::QueryRows method. The initial active rows for a provider administration table are those rows QueryRows returns before the application that contains the provider administration table calls the IMAPITable::SetColumns method.

•	Controls the property types of the sort order specification returned by the IMAPITable::QuerySortOrder method before the application that contains the provider administration table calls the IMAPITable::SortTable method.

See Also

IMAPITable::QueryColumns method, IMAPITable::QueryRows method, IMAPITable::QuerySortOrder method, IMAPITable::SetColumns method, IMsgServiceAdmin::GetProviderTable method


 IProviderAdmin::OpenProfileSection

[New - Windows 95]

Opens a section of the current profile and returns a pointer that provides further access to the profile object.

Syntax

HRESULT OpenProfileSection(LPMAPIUID lpUID, LPCIID lpInterface, ULONG ulFlags, LPPROFSECT FAR * lppProfSect)

Parameters

lpUID

Input parameter pointing to the MAPIUID structure holding the unique identifier for the profile section. For client applications, the lpUID parameter must not be NULL. Providers can pass NULL to get the MAPIUID when calling from their message-service entry function.

lpInterface

Input parameter pointing to the interface identifier (IID) for the profile section object. Passing NULL for the lpInterface parameter indicates the identifier for the MAPI profile-section object interface, IID_IProfSect, is used. The lpInterface parameter can also be set to an identifier for an appropriate interface, for example IID_IMAPIProp or IID_IProfSect.

ulFlags

Input parameter containing a bitmask of flags used to control how the profile section is opened. The following flags can be set:

MAPI_DEFERRED_ERRORS

Indicates the call is allowed to succeed even if the underlying object is not accessible to the calling application. If the object is not accessible, some subsequent call to the object might return an error.

MAPI_MODIFY

Requests read-write access. By default, objects are created with read-only access; providers should not work under the assumption that read-write access was granted. Client applications are not allowed read-write access to provider sections of the profile.

lppProfSect

Output parameter pointing to a variable where the pointer to the open profile-section object is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NO_ACCESS

An attempt to modify a read-only profile section or an attempt to access an object for which the user has insufficient permissions.

MAPI_E_NOT_FOUND

The requested object does not exist.

Comments

Use the IProviderAdmin::OpenProfileSection method to open a profile section for reading information from and writing information to the active profile for the session. A profile section object supporting the IProfSect interface is returned in the lppProfSect parameter. The default behavior is to open the profile section as read-only, unless an application sets the MAPI_MODIFY flag in the ulFlags parameter. Client applications cannot open profile sections belonging to service providers using the IProviderAdmin::OpenProfileSection method.

More than one method call can open a profile section with read-only access at a time, but only one method call can open a profile section with read-write access at a time. If any other application has the profile section open, a read-write open operation fails and returns the value MAPI_E_NO_ACCESS. A read-only open operation fails if the section is open for writing.

If an OpenProfileSection call opens a nonexistent profile section by passing the MAPI_MODIFY flag in the ulFlags parameter, the call creates the section. If an OpenProfileSection call attempts to open a nonexistent section with read-only access, MAPI_E_NOT_FOUND is returned.

All open operations should be as brief as possible, but an application that is writing to a profile section can keep it open while displaying a modification dialog box.

See Also

IMAPIProp : IUnknown interface, IProfSect : IMAPIProp interface, MAPIUID structure


 ISpoolerHook : IUnknown

[New - Windows 95]

The ISpoolerHook interface enables your message hook provider to reroute messages before they go to their destination.

At a Glance

Specified in header file:	MAPIHOOK.H
Object that supplies this interface:	Message-hook provider object
Corresponding pointer type:	LPSPOOLERHOOK
Implemented by:	Message-hook providers
Called by:	The MAPI spooler
Vtable Order

InboundMsgHook	Informs the MAPI spooler that it should allow the message hook provider to reroute a message from the default Inbox to another folder.
OutboundMsgHook	Informs the MAPI spooler that it should allow the message hook provider to reroute a message from the default Sent Items folder to another folder.


 ISpoolerHook::InboundMsgHook

[New - Windows 95]

Informs the MAPI spooler that it should allow the message hook provider to reroute a message from the default Inbox to another folder.

Syntax

HRESULT InboundMsgHook(LPMESSAGE lpMessage, LPMAPIFOLDER lpFolder, LPMDB lpMDB,  ULONG FAR * lpulFlags, ULONG FAR * lpcbEntryID, LPBYTE FAR * lppEntryID)

Parameters

lpMessage

Input parameter pointing to the message to be rerouted.

lpFolder

Input parameter pointing to the parent folder of the message in its message store.

lpMDB

Input parameter pointing to the message store containing the folder and message.

lpulFlags

Output parameter containing a bitmask of flags used to control how the MAPI spooler responds to the hook for the message indicated in the lpMessage parameter. The following flags can be set:

HOOK_CANCEL

Indicates any subsequent hook functions should not be called for this message. If your hook closes, moves, or deletes the message, you should set this flag.

HOOK_DELETE

Indicates that the message should be deleted without being moved.

lpcbEntryID

Input-output parameter pointing to a variable containing the size, in bytes, of the entry identifier of the folder where the message will be moved.

lppEntryID

Input-output parameter pointing to a variable where the pointer to the entry identifier of the folder where the message will be moved is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Message hook providers use the ISpoolerHook::InboundMsgHook method to reroute a message from the default Inbox to another folder. Before moving the message to another folder or message store, your message hook provider should call the IUnknown::QueryInterface method on the message object to make sure your provider can get an interface for the message that is compatible with your provider's implementation.

Before rerouting messages, message hook providers must replace the passed-in entry identifier in the lppEntryID parameter with the entry identifier of the new target folder. The MAPI spooler moves the message to the indicated folder for your provider, unless another hook function replaces your folder entry identifier. If your hook requires that its operation be the final action on the message, it can set the HOOK_CANCEL flag in lpulFlags before returning. If your provider replaces the lppEntryID entry identifier, it must call the MAPIFreeBuffer function to free the previous one. The copy of the entry identifier that your provider stores in lppEntryID should be allocated using the MAPIAllocateBuffer function.

If the message hook provider's implementation must move the message to another folder itself, it should close the message, place zero in the lpcbEntryID parameter, and free the entry identifier in the lppEntryID parameter, if lppEntryID is not already NULL. The hook then sets lppEntryID to NULL and then places a pointer to the message's new parent folder in lpFolder. Message hook providers that move the message must set the HOOK_CANCEL flag in the lpulFlags parameter.

If your hook deletes a message, it should close the message, place zero in lpcbEntryID, and place NULL in lppEntryID after freeing the existing entry identifier if need be. It then deletes the message and returns the HOOK_CANCEL flag in the lpulFlags parameter. Alternatively, it can combine the HOOK_CANCEL and HOOK_DELETE flags in lpulFlags using the logical-OR operator.

The MAPI spooler calls hook providers in the order in which they are specified in the provider section of the profile, as it does transport providers. The MAPI spooler releases the message-hook provider object at session shutdown. If your provider called the IUnknown::AddRef method for a session at initialization, it should call the IUnknown::Release method to release the session and any objects, such as message stores, it opened and maintained during the session.


 ISpoolerHook::OutboundMsgHook

[New - Windows 95]

Informs the MAPI spooler that it should allow the message hook provider to reroute a message from the default Sent Items folder to another folder.

Syntax

HRESULT OutboundMsgHook(LPMESSAGE lpMessage, LPMAPIFOLDER lpFolder, LPMDB lpMDB, ULONG FAR * lpulFlags, ULONG FAR * lpcbEntryID, LPBYTE FAR * lppEntryID)

Parameters

lpMessage

Input parameter pointing to the message to be rerouted.

lpFolder

Input parameter pointing to the parent folder of the message in its message store.

lpMDB

Input parameter pointing to the message store containing the folder and message.

lpulFlags

Output parameter containing a bitmask of flags used to control how the MAPI spooler responds to the hook for the message indicated in the lpMessage parameter. The following flags can be set:

HOOK_CANCEL

Indicates any subsequent hook functions should not be called for this message. If your hook closes, moves, or deletes the message, you should set this flag.

HOOK_DELETE

Indicates that the message should be deleted without being moved.

lpcbEntryID

Input-output parameter pointing to a variable containing the size, in bytes, of the entry identifier of the folder where the message will be moved.

lppEntryID

Input-output parameter pointing to a variable where the pointer to the entry identifier of the folder where the message will be moved is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Message hook providers use the ISpoolerHook::OutboundMsgHook method to reroute a message from the default Sent Items folder to another folder. Before moving the message to another folder or message store, your message hook provider should call the IUnknown::QueryInterface method on the message object to make sure your provider can get an interface for the message that is compatible with your provider's implementation.

Before rerouting messages, message hook providers must replace the passed-in entry identifier in the lppEntryID parameter with the entry identifier of the new target folder. The MAPI spooler moves the message to the indicated folder for your provider, unless another hook function replaces your folder entry identifier. If your hook requires that its operation be the final action on the message, it can set the HOOK_CANCEL flag in lpulFlags before returning. If your provider replaces the lppEntryID entry identifier, it must call the MAPIFreeBuffer function to free the previous one. The copy of the entry identifier that your provider stores in lppEntryID should be allocated using the MAPIAllocateBuffer function.

If the message hook provider's implementation must move the message to another folder itself, it should close the message, place zero in the lpcbEntryID parameter, and free the entry identifier in the lppEntryID parameter, if lppEntryID is not already NULL. The hook then sets lppEntryID to NULL and then places a pointer to the message's new parent folder in lpFolder. Message hook providers that move the message must set the HOOK_CANCEL flag in the lpulFlags parameter.

If your hook deletes a message, it should close the message, place zero in lpcbEntryID, and place NULL in lppEntryID after freeing the existing entry identifier if need be. It then deletes the message and returns the HOOK_CANCEL flag in the lpulFlags parameter. Alternatively, it can combine the HOOK_CANCEL and HOOK_DELETE flags in lpulFlags using the logical-OR operator.

The MAPI spooler calls hook providers in the order in which they are specified in the provider section of the profile, as it does transport providers. The MAPI spooler releases the message-hook provider object at session shutdown. If your provider called the IUnknown::AddRef method for a session at initialization, it should call the IUnknown::Release method to release the session and any objects, such as message stores, it opened and maintained during the session.


 ITableData : IUnknown

[New - Windows 95]

The ITableData interface provides utility methods for working with tables.

At a Glance

Specified in header file:	MAPIUTIL.H
Object that supplies this interface:	Table data object
Corresponding pointer type:	LPTABLEDATA
Implemented by:	MAPI
Called by:	Client applications and service providers
Vtable Order

HrGetView	Creates a new view for a table.
HrModifyRow	Modifies a row in a table, or adds a row to a table.
HrDeleteRow	Delete a row from a table.
HrQueryRow	Returns all properties of a specified row in a table and its row index in that table.
HrEnumRow	Returns the properties contained in a row of a table.
HrNotify	Finds a particular row so as to send a notification about that row.
HrInsertRow	Inserts a row into a table.
HrModifyRows	Modifies multiple rows in a table, or adds multiple rows to a table.
HrDeleteRows	Deletes multiple rows from a table.


 ITableData::HrDeleteRow

[New - Windows 95]

Deletes a row from a table.

Syntax

HRESULT HrDeleteRow(LPSPropValue lpSPropValue)

Parameters

lpSPropValue

Input parameter pointing to an SPropValue structure that holds the property value for the property that indicates the index number of the row to be deleted. This property value must contain the same index column as was used for the ulPropTagIndexColumn parameter of the call to the CreateTable function when the table was created.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NOT_FOUND

The SPropValue structure requested does not match a corresponding row in the table.

Comments

The ITableData::HrDeleteRow method is used to delete a table row. To perform this deletion, HrDeleteRow takes in the lpSPropValue parameter the property value for the property indicating the row's index number and uses this index value to locate and delete the row from the underlying table and from any open views for the table. This property value must contain the same index column as was used for the ulPropTagIndexColumn parameter of the CreateTable call when the table was created. If no row with that index number exists, MAPI_E_NOT_FOUND is returned.

After the row is deleted, notifications are sent to all applications that have an open view on the table and that have registered to receive notifications for table modifications.

Deleting a row does not reduce the columns available to existing views or subsequently opened views, even if the deleted row was the last row with a value for a specific column.

See Also

CreateTable function, ITableData::HrDeleteRows method, ITableData::HrModifyRow method, SPropValue structure, TABLE_NOTIFICATION structure


 ITableData::HrDeleteRows

[New - Windows 95]

Deletes multiple rows from a table.

Syntax

HRESULT HrDeleteRows(ULONG ulFlags, LPSRowSet lprowsetToDelete, ULONG FAR * cRowsDeleted)

Parameters

ulFlags

Input parameter containing a bitmask of flags used to control how table rows are deleted. The following flag can be set:

TAD_ALL_ROWS

Deletes all rows from the underlying table data and all corresponding table views, and sends a single TABLE_RELOAD notification to all table views registered for notifications.

lprowsetToDelete

Input parameter pointing to an SRowSet structure containing a counted array of index properties, each of which indicates a row to be deleted. Each row must have an index property that is unique among all rows for this table to be deleted. This parameter can be NULL if the TAD_ALL_ROWS flag is set in the ulFlags parameter.

cRowsDeleted

Output parameter containing a variable that holds the number of rows deleted.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

The ITableData::HrDeleteRows method finds and deletes multiple table rows. To perform this deletion, HrDeleteRows locates and deletes each row corresponding to an index property in the SRowSet passed in the lprowsetToDelete parameter. These property values must contain the same index columns as were used for the ulPropTagIndexColumn parameter of the call to the CreateTable function when the table was created. HrDeleteRows returns in the cRowsDeleted parameter the number of rows actually deleted. It does not return an error for rows that were not found. For example, if none of the rows requested can be found, a value of zero is returned in cRowsDeleted. If the TAD_ALL_ROWS flag is set in the ulFlags parameter, all rows in the table are deleted.

After the rows are deleted, a single notification is sent to each application that has an open view on the table and that has registered to receive notifications for table modifications.

Deleting rows does not reduce the columns available to existing table views or subsequently opened table views, even if the rows deleted were the last with values for a specific column.

See Also

CreateTable function, ITableData::HrDeleteRow method, ITableData::HrModifyRows method, SRowSet structure, TABLE_NOTIFICATION structure


 ITableData::HrEnumRow

[New - Windows 95]

Returns the properties contained in a row of a table.

Syntax

HRESULT HrEnumRow(ULONG ulRowNumber, LPSRow FAR * lppSRow)

Parameters

ulRowNumber

Input parameter indicating the row number. The value in the ulRowNumber parameter can be any value from 0 through n − 1, where n is the total number of rows in the table.

lppSRow

Output parameter pointing to a variable where the pointer to a returned SRow structure holding property information about the row is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

The ITableData::HrEnumRow method returns the full property set for the row indicated in ulRowNumber. Rows can be enumerated with multiple calls to this method. The rows are returned based on the chronological order that they were added to the table. This chronological order is maintained for the life of the table object.

If the row number indicated in the ulRowNumber parameter does not exist, NULL is returned in the SRow structure and the method returns S_OK.

MAPI allocates memory for the returned SRow structure using the MAPIAllocateBuffer function when the table is created. The calling process must release this memory by calling the MAPIFreeBuffer function when done.

See Also

MAPIAllocateBuffer function, MAPIFreeBuffer function, SRow structure


 ITableData::HrGetView

[New - Windows 95]

Creates a new view for a table.

Syntax

HRESULT HrGetView(LPSSortOrderSet lpSSortOrderSet, CALLERRELEASE FAR * lpfCallerRelease, ULONG ulCallerData, LPMAPITABLE FAR * lppMAPITable)

Parameters

lpSSortOrderSet

Input parameter pointing to the SSortOrderSet structure holding the sort order to be used as the default sort order for the view. If NULL is passed in the lpSSortOrderSet parameter, no initial sorting is done.

lpfCallerRelease

Input parameter pointing to a callback function to be called when the view is released. This callback function is passed the data contained in the ulCallerData parameter. If NULL is passed in the lpfCallerRelease parameter, no callback is made.

ulCallerData

Input parameter containing the 32-bit data that the calling process requires to be saved with the new view and returned in the release callback.

lppMAPITable

Output parameter pointing to a variable where the pointer to the newly created view is stored. This is the table that a service provider passes to a client application.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

The ITableData::HrGetView method creates a new view for a table. All rows and columns of the table are initially visible in the view; no restriction is applied to the table. When a sort order is specified in lpSSortOrderSet, the view is sorted according to the specified order and the cursor is placed at the beginning of the first row.

When the calling process requires more complex initial conditions for a view than can be produced by sorting, it should set a sort order, set a restriction, and then return the view to the client application.

When the table object is released, the callback function — based on the CALLERRELEASE function prototype — specified in the lpfCallerRelease parameter is called with the data contained in the ulCallerData parameter, a pointer to the table data object to which the view applies, and the pointer to the table object being released.

See Also

CALLERRELEASE function prototype, IMAPITable : IUnknown interface, SSortOrderSet structure


 ITableData::HrGetView, CALLERRELEASE

[New - Windows 95]

The CALLERRELEASE function prototype defines a client-application callback function that releases a table data object.

Syntax

void CALLERRELEASE(ULONG ulCallerData, LPTABLEDATA lpTblData, LPMAPITABLE lpVue)

Parameters

ulCallerData

Input parameter specifying data about the calling client application.

lpTblData

Input parameter specifying a pointer to the ITableData interface for the table data object.

lpVue

Input parameter specifying a pointer to the IMAPITable interface that provides the display table. This is the table object passed in the ITableData::HrGetView method in the lppMAPITable parameter.

Return Values

None

Comments

Client applications use the CALLERRELEASE function prototype to create a callback that allows them to release views on the underlying table data object without having to keep track of that object. After all of the views on that table data object are released, implementations of ITableData::HrGetView call the client application's CALLERRELEASE function and then release the table data object underlying the views.

See Also

IMAPITable : IUnknown interface, ITableData::HrGetView method


 ITableData::HrInsertRow

[New - Windows 95]

Inserts a row into a table.

Syntax

HRESULT HrInsertRow(ULONG uliRow, LPSRow lpSRow)

Parameters

uliRow

Input parameter indicating the number of the table row before which the new row will be inserted. The uliRow parameter can hold row numbers from 0 through n, where n is the total number of rows in the table; passing n in uliRow results in the row being appended to the end of the table.

lpSRow

Input parameter pointing to the SRow structure containing the set of properties for the row being inserted in the table.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_INVALID_PARAMETER

A row already exists with the same index column.

Comments

The ITableData::HrInsertRow method inserts a row into a table. Passing a value of 0 through n − 1 in the uliRow parameter results in the new row being inserted above the table row with the given number. Passing a value of n in uliRow results in the new row being appended to the table's end.

One of the property columns in the SRow structure in the lpSRow parameter must be a column holding the index property of the row to be inserted, which uniquely identifies the row within the table. If the value for the index column already exists, MAPI_E_INVALID_PARAMETER is returned. If there is no current row with that value, HrInsertRow adds the new row. The property columns in the SRow do not have to be in the same order as the property columns in the table.

After the row is inserted, notifications are sent to all applications that have an open view on the table and that have registered to receive notifications for table modifications. Notifications are not sent if the rows have been restricted out of the view on the table.

See Also

SRow structure, TABLE_NOTIFICATION structure


 ITableData::HrModifyRow

[New - Windows 95]

Modifies a row in a table, or adds a row to a table.

Syntax

HRESULT HrModifyRow(LPSRow lpSRow)

Parameters

lpSRow

Input parameter pointing to the SRow structure containing the set of properties for the row to be added or modified. This row must contain the same index column as was used for the ulPropTagIndexColumn parameter of the call to the CreateTable function when the table was created.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_INVALID_PARAMETER

The passed-in row does not have an index column.

Comments

The ITableData::HrModifyRow method modifies one row of a table or adds one row to a table. The SRow structure specified in the lpSRow parameter contains the properties for the row to be added or modified.

One of the property columns in the SRow must be a column holding the index column of the row to be modified or added, this index column must be the same one as was used for the ulPropTagIndexColumn parameter of the CreateTable call when the table was created. HrModifyRow replaces with the new row any row in the table that has the same index value as that in the SRow. If there is no current row with the index value, HrModifyRow adds the new row to the end of the table.

The property columns in the SRow do not have to be in the same order as the property columns in the table. The SRow can also include properties for which there are no current columns in the table; MAPI adds new columns to the table as needed.

Rows are modified and inserted for all views on the table object. Doing so can involve adding the row to or removing it from a view based on a restriction in effect for the view. Columns added because the SRow includes properties for which there are no current columns become available to existing views but are not included in the views' currently active columns. However, added columns are active in views opened after their addition. After a row is inserted, notifications are sent to all applications that have an open view on the table and that have registered to receive notifications for table modifications.

Any text or string properties placed in a client application table must be in the client's character set, whether 8-bit or Unicode. MAPI's table implementation does not handle character set conversions.

See Also

SRow structure, TABLE_NOTIFICATION structure


 ITableData::HrModifyRows

[New - Windows 95]

Modifies multiple rows in a table, or adds multiple rows to a table.

Syntax

HRESULT HrModifyRows(ULONG ulFlags, LPSRowSet lpSRowSet)

Parameters

ulFlags

Reserved; must be zero.

lpSRowSet

Input parameter pointing to the SRowSet structure containing the set of rows to be added or modified.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_INVALID_PARAMETER

One or more of the passed-in rows does not have an index column. If this error is returned, no rows are changed.

Comments

The ITableData::HrModifyRows method modifies the table rows indicated in the SRowSet structure passed in the lpSRowSet parameter. If no current table rows match the rows in the SRowSet, HrModifyRows adds the rows to the table.

Each row in the SRowSet must have a property column holding the index property of that row, which uniquely identifies the row within the table. These property columns must contain the same index columns as were used for the ulPropTagIndexColumn parameter of the call to the CreateTable function when the table was created. If one of the rows has a different index column, MAPI_E_INVALID PARAMETER is returned and no rows are changed. HrModifyRows replaces with the SRowSet rows any rows in the table that have the same index values. If there are no current rows with the same values, HrModifyRows adds the new rows to the end of the table.

The property columns in the SRowSet do not have to be in the same order as the property columns in the table. The SRowSet can also include properties for which there are no current columns in the table; MAPI adds new columns to the table as needed.

If any views are open for the table, the added or modified rows are inserted or moved appropriately in each view. Doing so can involve adding the rows to or removing them from a view based on a restriction in effect for the view. Columns added because the SRowSet includes properties for which there are no current columns become available to existing views but are not included in the views' currently active columns. However, added columns are active in views opened after their addition. After the rows are removed, a single notification is sent to each application that has an open view on the table and that has registered to receive notifications for table modifications.

Notifications to views on the table object are made in one batch, but if more than eight notifications are to be sent a single TABLE_CHANGED notification is sent instead.

Any text or string properties placed in a client application table must be in the client's character set, whether 8-bit or Unicode. MAPI's table implementation does not handle character set conversions.

MAPI copies appropriate data from the specified SRowSet structure.

See Also

SRowSet structure


 ITableData::HrNotify

[New - Windows 95]

Finds a particular row so as to send a notification about that row.

Syntax

HRESULT HrNotify(ULONG ulFlags, ULONG cValues, LPSPropValue lpSPropValue)

Parameters

ulFlags

Reserved; must be zero.

cValues

Input parameter containing the number of property values in the SPropValue structure pointed to by the lpSPropValue parameter.

lpSPropValue

Input parameter pointing to an SPropValue structure used to identify a particular row, whose properties must exactly match those passed in the SPropValue.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Calling the ITableData::HrNotify method results in a detailed notification of type fnevTableModifed for the table row whose property values match those passed in lpSPropValue, even when the values within that row haven't changed. If the property values for the identified row have not changed, the existing row information is sent in the fnevTableModifed notification. In the case of a change to a display table row for an edit control, your client application should reload the data associated with the control.

See Also

SPropValue structure, TABLE_NOTIFICATION structure


 ITableData::HrQueryRow

[New - Windows 95]

Returns all properties of a specified row in a table and its row index in that table.

Syntax

HRESULT HrQueryRow(LPSPropValue lpSPropValue, LPSRow FAR * lppSRow, ULONG FAR * lpuliRow)

Parameters

lpSPropValue

Input parameter pointing to an SPropValue structure that holds an index property specifying the row for which to return properties.

lppSRow

Output parameter pointing to a variable where the pointer to a returned SRow structure holding all properties for the specified row is stored.

lpuliRow

Output parameter pointing to the address where the index number of the row is returned. This is the row's index number in the table. If no row number is required, NULL should be passed in the lpuliRow parameter.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_INVALID_PARAMETER

The SPropValue structure passed in does not contain the index column.

Comments

The ITableData::HrQueryRow method returns the full property set for the row indicated by the index property in the lpSPropValue parameter, and it returns the row index that this row occupies in the table.

MAPI uses, but does not modify, the passed-in SPropValue structure. If the calling application allocated memory for this structure, the calling application must free it after the HrQueryRow call returns.

MAPI allocates memory for the returned SRow structure using the MAPIAllocateBuffer function when the table is created. The calling application must release this memory by calling the MAPIFreeBuffer function when done.

See Also

MAPIAllocateBuffer function, MAPIFreeBuffer function, SPropValue structure, SRow structure


 ITnef : IUnknown

[New - Windows 95]

The ITnef interface provides methods for encapsulating those MAPI properties not supported by a messaging system into binary streams that can accompany messages through transport provider handling and through gateways. The format used for this encapsulation is Transport-Neutral Encapsulation Format (TNEF). The target transport provider can then decode the encapsulation to retrieve all the properties of the original message.

At a Glance

Specified in header file:	TNEF.H
Object that supplies this interface:	TNEF object
Corresponding pointer type:	LPTNEF
Implemented by:	MAPI
Called by:	Transport providers, message store providers, and gateways
Vtable Order

AddProps	Allows the calling implementation to add properties to be included in the encapsulation of a message or an attachment.
ExtractProps	Extracts the properties from a TNEF encapsulation.
Finish	Finishes processing for all TNEF operations that are queued and waiting.
OpenTaggedBody	Opens a stream interface on the decorated message text of an encapsulated message.
SetProps	Sets the value of one or more properties for an encapsulated message or attachment without modifying the original message or attachment.
EncodeRecips	Forces the encoding of the recipient table in the TNEF data stream for a message.
FinishComponent	Processes individual components from a message one component at a time into a TNEF stream.


 ITnef::AddProps

[New - Windows 95]

Allows the calling implementation to add properties to be included in the encapsulation of a message or an attachment.

Syntax

HRESULT AddProps(ULONG ulFlags, ULONG ulElemID, LPVOID lpvData, LPSPropTagArray lpPropList)

Parameters

ulFlags

Input parameter containing a bitmask of flags used to control how properties are included in or excluded from encapsulation. The following flags can be set:

TNEF_PROP_ATTACHMENTS_ONLY

Applies the properties in the lpPropList parameter that are part of attachments within the message.

TNEF_PROP_CONTAINED

Encodes only properties from the attachment specified by the ulElemID parameter. If the lpvData parameter is non-null, then the data pointed to will be written into the attachment's encapsulation in the transport file indicated in the PR_ATTACH_TRANSPORT_NAME property.

TNEF_PROP_CONTAINED_TNEF

Encodes only properties from the message or attachment specified by the ulElemID parameter. The value in the lpvData parameter must be an ISTREAMTNEF pointer.

TNEF_PROP_EXCLUDE

Encodes all properties not specified in the lpPropList parameter.

TNEF_PROP_INCLUDE

Encodes all properties specified in the lpPropList parameter.

TNEF_PROP_MESSAGE_ONLY

Encodes only those properties specified in lpPropList that are part of the message itself.

ulElemID

Input parameter indicating the value of an attachment's PR_ATTACH_NUM property, which contains a number that uniquely identifies the attachment within its parent message. The ulElemID parameter is used when special handling is requested for an attachment. The ulElemID parameter should be zero unless the TNEF_PROP_CONTAINED or the TNEF_PROP_CONTAINTAINED_TNEF flag was set in the ulFlags parameter.

lpvData

Input parameter pointing to a buffer holding attachment data that is used to replace the data of the attachment specified in the ulElemID parameter. The lpvData parameter should be NULL unless the TNEF_PROP_CONTAINED or the TNEF_PROP_CONTAINTAINED_TNEF flag was set in the ulFlags parameter.

lpPropList

Input parameter pointing to the list of properties to include in or exclude from encapsulation.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Transport providers, message store providers, and gateways call the ITnef::AddProps method to list properties to be included in or excluded from the TNEF encapsulation of a message or an attachment. Using successive calls, the provider or gateway can specify a list of properties to add and encode or to exclude from being encoded. Providers and gateways can also use AddProps to provide information on any special handling attachments should be given.

ITnef::AddProps is only supported for TNEF objects opened with the TNEF_ENCODE flag for the OpenTnefStream or OpenTnefStreamEx function.

Note that no actual TNEF encoding happens for AddProps until the ITnef::Finish method is called. This functionality means that pointers passed into AddProps must remain valid until after the call to Finish is made. At that point, all objects and data passed in with AddProps calls can be released or freed.

See Also

ITnef::Finish method, OpenTnefStream function, OpenTnefStreamEx function, PR_ATTACH_TRANSPORT_NAME property


 ITnef::EncodeRecips

[New - Windows 95]

Forces the encoding of the recipient table in the TNEF data stream for a message.

Syntax

HRESULT EncodeRecips(ULONG ulFlags, LPMAPITABLE lpRecipientTable)

Parameters

ulFlags

Reserved; must be zero.

lpRecipientTable

Input parameter pointing to the recipient table for which the view is to be encoded. The lpRecipientTable parameter can be NULL.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Transport providers, message store providers, and gateways call the ITenf::EncodeRecips method to perform TNEF encoding for a particular recipient-table view. Such encoding is useful, for instance, if your transport provider, message store provider, or gateway requires a particular column set, sort order, or restriction for the recipient table.

Your provider or gateway passes the table view to be encoded in the lpRecipientTable parameter. The TNEF implementation encodes the recipient table with the given view, using the given column set, sort order, restrictions, and position. If your provider or gateway passes NULL in lpRecipientTable, TNEF gets the recipient table from the message being encoded, using the IMessage::GetRecipientTable method, and processes every row of the table into the TNEF stream using the current column set.

Calling EncodeRecips with NULL in lpRecipientTable thus encodes all message recipients and is equivalent to calling the ITnef::AddProps method with the TNEF_PROP_INCLUDE flag in the ulFlags parameter and the PR_MESSAGE_RECIPIENTS property specified in the lpPropList parameter.

See Also

IMessage::GetRecipientTable method, ITnef::AddProps method, PR_MESSAGE_RECIPIENTS property


 ITnef::ExtractProps

[New - Windows 95]

Extracts the properties from a TNEF encapsulation.

Syntax

HRESULT ExtractProps(ULONG ulFlags, LPSPropTagArray lpPropList, LPSTnefProblemArray FAR * lpProblems)

Parameters

ulFlags

Input parameter containing a bitmask of flags used to control how properties are decoded. The following flags can be set:

TNEF_PROP_EXCLUDE

Decodes all properties not specified in the lpPropList parameter.

TNEF_PROP_INCLUDE

Decodes all properties specified in the lpPropList parameter.

lpPropList

Input parameter pointing to the list of properties to include in or exclude from the decoding operation.

lpProblems

Output parameter pointing to a variable where the pointer to a STnefProblemArray structure is stored. If NULL is passed in the lppProblems parameter, no property problem array is returned. The STnefProblemArray indicates which properties were not encoded properly.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_CORRUPT_DATA

Data being decoded into a stream is corrupted.

Comments

Transport providers, message store providers, and gateways call the ITnef::ExtractProps method to extract (that is, decode) properties from the encapsulation of a message or an attachment that was passed to the OpenTnefStream function. The calling provider or gateway can specify a list of properties to decode. Providers and gateways can also use ExtractProps to provide information on any special handling attachments should be given. Once decoding is done, the original message passed into OpenTnefStream is repopulated with the decoded properties. Subsequent ExtractProps calls will go back to the message and extract the new list of properties.

Unlike with the ITnef::AddProps method, which queues requested actions until the ITnef::Finish method is called, properties are decoded when the ExtractProps call is made. For that reason, the target message for encapsulation decoding should be relatively empty. Existing properties in the target message are overwritten by encapsulated properties.

ExtractProps is only supported on objects opened with the TNEF_DECODE flag set on OpenTnefStream or the OpenTnefStreamEx function.

The TNEF implementation reports TNEF stream encoding problems without halting the ExtractProps process. The STnefProblemArray structure returned in the lppProblems parameter indicates which TNEF attributes or MAPI properties, if any, could not be processed. The value returned in the scode member of the STnefProblemArray structure indicates the specific problem. Your provider or gateway can work on the assumption that all properties or attributes for which ExtractProps does not return a problem report were processed successfully.

One exception is that if, during the decoding of a TNEF stream, a property in the MAPI encapsulation block cannot be processed and leaves the stream unreliable, then decoding of the encapsulation block is halted and a problem is reported. The report for this type of problem contains a value of 0L for the ulPropTag member, a value of attMAPIProps or attAttachment for the ulAttribute member, and a value of MAPI_E_UNABLE_TO_COMPLETE for the scode member. Note that the decoding of the stream is not halted, just the decoding of the MAPI encapsulation block. The stream decoding continues with the next attribute block.

If your provider or gateway does not work with problem arrays, it can pass NULL in lppProblems; in this case, no problem array is returned.

The value returned in the lppProblems parameter is only valid if the call returns S_OK. When S_OK is returned, check the values returned in the STnefProblemArray structure. If an error occurs on the call, then the STnefProblemArray structure is not filled in and the calling provider or gateway should not use or free the STnefProblemArray structure.

Your provider or gateway must release the memory for the STnefProblemArray by calling the MAPIFreeBuffer function.

See Also

ITnef::AddProps method, ITnef::Finish method, ITnef::SetProps method, MAPIFreeBuffer function, OpenTnefStream function, OpenTnefStreamEx function, STnefProblemArray structure


 ITnef::Finish

[New - Windows 95]

Finishes processing for all TNEF operations that are queued and waiting.

Syntax

HRESULT Finish(ULONG ulFlags, WORD FAR * lpKey, LPSTnefProblemArray FAR * lpProblem)

Parameters

ulFlags

Reserved; must be zero.

lpKey

Output parameter pointing to the PR_ATTACH_NUM key property. The TNEF encapsulation object uses this key to match an attachment to its attachment placement tag within a message. This key should be unique across messages.

lpProblem

Output parameter pointing to a variable where the pointer to a STnefProblemArray structure is stored. If NULL is passed in the lppProblems parameter, no property problem array is returned. The STnefProblemArray indicates which properties were not encoded properly.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Transport providers, message store providers, and gateways call the ITnef::Finish method to perform the encoding of all the properties requested in calls to the ITnef::AddProps and ITnef::SetProps methods. If the TNEF object was opened with the TNEF_ENCODE flag, all properties processed on the Finish call are encoded into the encapsulation stream passed to the TNEF object. After the Finish call, the pointer to the encapsulation stream is set to the end of the TNEF data. If the provider or gateway is to use the TNEF stream data, it must reset the stream pointer to the beginning of the TNEF stream data.

Finish is only supported on objects opened with the TNEF_ENCODE flag set for the OpenTnefStream or OpenTnefStreamEx function.

The TNEF implementation reports TNEF stream encoding problems without halting the Finish process. The STnefProblemArray structure returned in the lppProblems parameter indicates which TNEF attributes or MAPI properties, if any, could not be processed. The value returned in the scode member of the STnefProblemArray structure indicates the specific problem. Your provider or gateway can work on the assumption that all properties or attributes for which Finish does not return a problem report were processed successfully.

If your provider or gateway does not work with problem arrays, it can pass NULL in lppProblems; in this case, no problem array is returned.

The value returned in the lppProblems parameter is only valid if the call returns S_OK. When S_OK is returned, check the values returned in the STnefProblemArray structure. If an error occurs on the call, then the STnefProblemArray structure is not filled in and the calling provider or gateway should not use or free the STnefProblemArray structure.

Your provider or gateway must release the memory for the STnefProblemArray by calling the MAPIFreeBuffer function.

See Also

ITnef::AddProps method, MAPIFreeBuffer function, OpenTnefStream function, OpenTnefStreamEx function, PR_ATTACH_NUM property, STnefProblemArray structure


 ITnef::FinishComponent

[New - Windows 95]

Processes individual components from a message one component at a time into a TNEF stream.

Syntax

HRESULT FinishComponent(ULONG ulFlags, ULONG ulComponentID, LPSPropTagArray lpCustomPropList, LPSPropValue lpCustomProps, LPSPropTagArray lpPropList, LPSTnefProblemArray FAR * lppProblems)

Parameters

ulFlags

Input parameter containing a bitmask of flags used to determine for which component to finish processing. One of the other of the following flags must be set:

TNEF_COMPONENT_ATTACHMENT

Indicates that an attachment object is encoded; the value in the ulComponentID parameter refers to the PR_ATTACH_NUM property of the attachment being processed.

TNEF_COMPONENT_MESSAGE

Indicates that the message-level properties are encoded.

ulComponentID

Input parameter containing either zero to indicate processing for a message or the value of the PR_ATTACH_NUM property of the attachment to be processed. If TNEF_COMPONENT_MESSAGE is set in the ulFlags parameter, ulComponentID must be zero.

lpCustomPropList

Input parameter pointing to a SPropTagArray structure that identifies the properties passed in the lpCustomProps parameter. There must be a one-to-one correspondence between each of the property values in lpCustomProps and a property tag in the lpCustomPropList parameter.

lpCustomProps

Input parameter pointing to an SPropValue structure containing the properties to include in the encapsulation object.

lpPropList

Input parameter pointing to an SPropTagArray structure containing the properties that are to be encoded.

lppProblems

Output parameter pointing to a variable where the pointer to a STnefProblemArray structure is stored. If NULL is passed in the lppProblems parameter, no property problem array is returned. The STnefProblemArray indicates which properties were not encoded properly.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Transport providers, message store providers, and gateways call the ITnef::FinishComponent method to perform TNEF processing for one component, either a message or an attachment, as indicated by the flag set in the ulFlags parameter.

For component processing to be enabled, the calling provider or gateway must have passed the TNEF_COMPONENT_ENCODING flag in ulFlags for either the OpenTnefStream function or the OpenTnefStreamEx function.

Passing values in the lpCustomPropList and lpCustomProps parameters performs component encoding equivalent to that done by the ITnef::SetProps method. Passing a value in the lpPropList parameter performs component encoding equivalent to that done by the ITnef::AddProps method with the TNEF_PROP_INCLUDE flag set in ulFlags. Passing such values enables you to perform encodings with a single call rather than multiple calls.

The TNEF implementation reports TNEF stream encoding problems without halting the FinishComponent process. The STnefProblemArray structure returned in the lppProblems parameter indicates which TNEF attributes or MAPI properties, if any, could not be processed. The value returned in the scode member of the STnefProblemArray structure indicates the specific problem. Your provider or gateway can work on the assumption that all properties or attributes for which FinishComponent does not return a problem report were processed successfully.

If your provider or gateway does not work with problem arrays, it can pass NULL in lppProblems; in this case, no problem array is returned.

The value returned in the lppProblems parameter is only valid if the call returns S_OK. When S_OK is returned, check the values returned in the STnefProblemArray structure. If an error occurs on the call, then the STnefProblemArray structure is not filled in and the calling provider or gateway should not use or free the STnefProblemArray structure.

Your provider or gateway must release the memory for the STnefProblemArray by calling the MAPIFreeBuffer function.

See Also

ITnef::AddProps method, ITnef::SetProps method, MAPIFreeBuffer function, OpenTnefStream function, OpenTnefStreamEx function, SPropTagArray structure, STnefProblemArray structure


 ITnef::OpenTaggedBody

[New - Windows 95]

Opens a stream interface on the decorated message text of an encapsulated message.

Syntax

HRESULT OpenTaggedBody(LPMESSAGE lpMessage, ULONG ulFlags, LPSTREAM FAR * lppStream)

Parameters

lpMessage

Input parameter pointing to the message the stream is associated with. This message is not required to be the same message passed in on the call to the OpenTnefStream or OpenTnefStreamEx function.

ulFlags

Input parameter containing a bitmask of flags used to control the opening of the stream interface. The following flags can be set:

MAPI_CREATE

If the property does not exist, it should be created. If the property does exist, the current data in the property should be discarded. When you set the MAPI_CREATE flag, you should also set the MAPI_MODIFY flag.

MAPI_MODIFY

Requests read-write access. The default interface is read-only. MAPI_MODIFY must be set when MAPI_CREATE is also set.

lppStream

Output parameter pointing to a variable where the pointer is stored to a stream object that contains the text from the PR_BODY property of the passed-in encapsulated message and that supports the IStream interface.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Transport providers, message store providers, and gateways call the ITnef::OpenTaggedBody method to open a stream interface on the text of an encapsulated message (that is, on a TNEF object).

As part of its processing, ITnef::OpenTaggedBody either inserts or parses attachment tags that indicate the position of any attachments or OLE objects within the message text. The attachment tags are in the following format:

[[ attachment name : n in attachment container name ]]

where attachment name describes the attachment object, n is a number that is sequential, incrementing from the value passed in the lpKey parameter of the OpenTnefStream or OpenTnefStreamEx function, and attachment container name describes the physical component where the attachment object resides.

OpenTaggedBody reads out message text and inserts an attachment tag wherever an attachment object originally appeared in the text. The original message text is not changed.

When a stream is passed a message that has tags, the tags are stripped out and the attachment objects are relocated in the position of the tags in the stream.

See Also

OpenTnefStream function, OpenTnefStreamEx function, PR_BODY property


 ITnef::SetProps

[New - Windows 95]

Sets the value of one or more properties for an encapsulated message or attachment without modifying the original message or attachment.

Syntax

HRESULT SetProps(ULONG ulFlags, ULONG ulElemID, ULONG cValues, LPSPropValue lpProps)

Parameters

ulFlags

Input parameter containing a bitmask of flags used to control how properties' values are set. The following flag can be set:

TNEF_PROP_CONTAINED

Encodes only properties from the message or attachment specified by the ulElemID parameter.

ulElemID

Input parameter indicating the value of an attachment's PR_ATTACH_NUM property.

cValues

Input parameter containing the number of property values in the SPropValue structure pointed to by the lpProps parameter.

lpProps

Input parameter pointing to an SPropValue structure containing the property values of the properties to be set.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Transport providers, message store providers, and gateways call the ITnef::SetProps method to set properties to be included in the encapsulation of a message or an attachment without modifying the original message or attachment. Any properties set with this call override existing properties in the encapsulated message.

SetProps is only supported on TNEF objects that have previously been opened with the TNEF_ENCODE flag for the OpenTnefStream or OpenTnefStreamEx function. Any number of properties can be set with this call.

Note that no actual TNEF encoding for SetProps happens until after the ITnef::Finish method is called. This functionality means that pointers passed into SetProps must remain valid until after the call to Finish is made. At that point, all objects and data passed into SetProps calls can be released or freed.

See Also

ITnef::Finish method, OpenTnefStream function, OpenTnefStreamEx function, PR_ATTACH_NUM property, SPropValue structure


 IXPLogon : IUnknown

[New - Windows 95]

The IXPLogon interface is used to provide the MAPI spooler access into a transport provider.

At a Glance

Specified in header file:	MAPISPI.H
Object that supplies this interface:	Transport logon object
Corresponding pointer type:	LXPLOGON
Implemented by:	Transport providers
Called by:	The MAPI spooler
Vtable Order

AddressTypes	Indicates to the MAPI spooler what types of recipients a transport provider can handle.
RegisterOptions	Informs the messaging system about the options provided by a transport provider for a messaging address type.
TransportNotify	Signals in a transport provider session the occurrence of an event for the MAPI spooler about which the transport provider has requested notification.
Idle	Calls a transport provider at a point when the system is idle to perform low-priority operations.
TransportLogoff	Terminates a transport provider session with the MAPI spooler.
SubmitMessage	Indicates to the transport provider that the MAPI spooler has a message for the provider to deliver.
EndMessage	Informs the transport provider that the MAPI spooler has completed its send pass for this provider.
Poll	Allows a transport provider to indicate when it has one or more incoming messages available. This method is called periodically by the MAPI spooler.
StartMessage	Indicates that the transport provider should start downloading into a message.
OpenStatusEntry	Returns an IMAPIStatus object. This method is called by the MAPI spooler when a client application calls an OpenEntry method against the entry identifier in the transport provider's subsystem status-table row.
ValidateState	Has a transport provider check its external status. This method is called by the MAPI spooler.
FlushQueues	Requests that transport operations occur quickly. This method is called by the MAPI spooler.


 IXPLogon::AddressTypes

[New - Windows 95]

Indicates to the MAPI spooler what types of recipients a transport provider can handle.

Syntax

HRESULT AddressTypes(ULONG FAR * lpulFlags, ULONG FAR * lpcAdrType, LPTSTR FAR * FAR * lpppszAdrTypeArray, ULONG FAR * lpcMAPIUID, LPUID FAR * FAR * lpppUIDArray)

Parameters

lpulFlags

Output parameter containing a bitmask of flags. The following flag can be set:

MAPI_UNICODE

Indicates the returned strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

lpcAdrType

Output parameter pointing to a variable containing the number of entries in the array pointed to by the lpppAdrTypeArray parameter.

lpppszAdrTypeArray

Output parameter pointing to a variable where the transport provider places an array of pointers to strings that identify recipient types.

lpcMAPIUID

Output parameter pointing to a variable containing the number of entries in the array pointed to by the lpppUIDArray parameter.

lpppUIDArray

Output parameter pointing to a variable where the transport provider places an array of pointers to MAPIUID structures that identify recipient types.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

The MAPI spooler calls the IXPLogon::AddressTypes method immediately after a transport provider returns from a call to the IXPProvider::TransportLogon method so that the transport can indicate what types of recipients it can handle. To indicate this, the transport provider should pass in the lpppszAdrTypeArray parameter a pointer to an array of pointers to strings, or instead pass in the lpppUIDArray parameter a pointer to an array of pointers to MAPIUID structures, or pass values in both parameters.

These two arrays are used for different identification processes. MAPI and the MAPI spooler use the MAPIUID structures in the array referred to by lpppUIDArray to identify those recipient entry identifiers that are directly handled by the transport or by the messaging system to which the transport connects. Neither MAPI nor the MAPI spooler performs expansion of addresses with entry identifiers containing any of these MAPIUID structures; these structures are only used for recipient type identification.

The MAPI spooler uses each of the strings in the lpppszAdrTypeArray parameter for a comparison test when deciding which transport should handle which recipients for an outbound message. If a message recipient's PR_ADDRTYPE property exactly matches a string identifying one of the messaging address types supplied by the transport, the transport can handle that recipient.

In the event multiple transport providers can handle the same type of recipient, MAPI selects a transport based on the transport priority order indicated in the client application's profile. To determine which transport to use, the MAPI spooler scans all provider-specified MAPIUID structures in priority order, then all provider-specified address type values in priority order. The first transport to match a particular recipient in this scan gets the first opportunity to handle this recipient. If that transport does not handle the recipient, the MAPI spooler continues the scan so as to find a transport for any recipient not yet handled. The scan continues until no further matches are found, at which point a nondelivery report is generated for any recipient that was not handled.

If the provider always supports a particular set of recipient types, the address type and MAPIUID arrays passed by the transport provider can be static. If the transport provider needs to dynamically construct these arrays, it can use the support object that was passed in the call to TransportLogon directly previous to allocate memory, although this is not strictly necessary.

The memory used for the address type and MAPIUID arrays should remain allocated until the final call to the IXPLogon::TransportLogoff method is performed, at which time the transport provider can free the memory if necessary. The contents of these structures should not be altered by the transport provider after returning from the TransportLogoff call.

A transport provider that can handle any type of recipient can return NULL in lpppszAdrTypeArray. LAN-based messaging systems that support a variety of gateways commonly do this. Such a transport should be installed last in the MAPI and MAPI spooler priority order of transports within the profile.

A transport provider that does not support outbound messages dispatched to it based on address type should return a single zero-length string in the lpppAdrTypeArray parameter. If a transport provider doesn't support anything, then it should pass NULL for the MAPIUID and an empty string for the address type.

For more information on working with address types, see MAPI Programmer's Guide.

See Also

IXPLogon::TransportLogoff method, IXPProvider::TransportLogon method, MAPIUID structure


 IXPLogon::EndMessage

[New - Windows 95]

Informs the transport provider that the MAPI spooler has completed its send pass for this provider.

Syntax

HRESULT EndMessage(ULONG ulMsgRef, ULONG FAR * lpulFlags)

Parameters

ulMsgRef

Input parameter containing a 32-bit reference value, specific to this message, obtained in an earlier call to the IXPLogon::SubmitMessage method.

lpulFlags

Output parameter containing a bitmask of flags used to indicate to the MAPI spooler what it should do with the message. If no flags are set, the message has been sent. The following flags can be set:

END_DONT_RESEND

Indicates the transport provider has all the information it needs about this message for now. When the transport provider requires more information or when it has completed sending the message, it notifies the MAPI spooler by calling the IMAPISupport::SpoolerNotify method with the NOTIFY_SENTDEFERRED flag and by passing the message's entry identifier.

END_RESEND_LATER

Indicates that the transport provider isn't sending the message now for reasons that are not error conditions and that it should be called again later to send the message.

END_RESEND_NOW

Indicates the transport provider needs to restart the message passed to it in a IMessage::SubmitMessage method call.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

The MAPI spooler calls the IXPLogon::EndMessage method after completing the processing involved in providing extended delivery or nondelivery information.

Once this call returns, the value in the ulMsgRef parameter is considered to be no longer valid. The transport provider can reuse the same value on a future message.

All objects opened by the transport during the transfer of a message should be released before returning from the EndMessage call, with the exception of the IMessage object the MAPI spooler passes to the transport. The IMessage object passed by the MAPI spooler is invalid after the EndMessage call.

See Also

IMAPISupport::SpoolerNotify method, IMessage::SubmitMessage method, IXPLogon::SubmitMessage method


 IXPLogon::FlushQueues

[New - Windows 95]

Requests that transport operations occur quickly. This method is called by the MAPI spooler.

Syntax

HRESULT FlushQueues(ULONG ulUIParam, ULONG cbTargetTransport, LPENTRYID lpTargetTransport, ULONG ulFlags)

Parameters

ulUIParam

Input parameter containing the handle to the window that the dialog box is modal to.

cbTargetTransport

Reserved; must be zero.

lpTargetTransport

Reserved; must be NULL.

ulFlags

Input parameter containing a bitmask of flags used to control message queue flushing. The following flags can be set:

FLUSH_DOWNLOAD

Indicates the inbound message queue or queues should be flushed.

FLUSH_FORCE

Indicates the transport provider should process this request if possible, even if doing so is time-consuming.

FLUSH_NO_UI

Indicates the transport provider should not display user interface components.

FLUSH_UPLOAD

Indicates the outbound message queue or queues should be flushed.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

The MAPI spooler calls IXPLogon::FlushQueues to advise the transport provider that the MAPI spooler is about to begin processing messages. The transport provider should call IMAPISupport::ModifyStatusRow to set an appropriate bit for its state in the PR_STATUS_CODE property of its status row. After updating its status row the transport provider should return S_OK for the FlushQueues call. The MAPI spooler will then start sending messages with the operation being synchronous to the MAPI spooler.

To support its implementation of IMAPIStatus::FlushQueues, the MAPI spooler calls IXPLogon::FlushQueues on all logon objects for all active transport providers running in a profile session. When a transport provider's FlushQueues method is call as a result of a client application calling IMAPIStatus::FlushQueues, the message processing occurs asynchrousously to the client application.

See Also

IMAPIStatus::FlushQueues method


 IXPLogon::Idle

[New - Windows 95]

Calls a transport provider at a point when the system is idle to perform low-priority operations.

Syntax

HRESULT Idle(ULONG ulFlags)

Parameters

ulFlags

Reserved; must be zero.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

If requested, by passing the XP_LOGON_SP flag in the call to the IXPProvider::TransportLogon method that opened the current session, the MAPI spooler periodically calls the IXPLogon::Idle method during times when the system is idle. At such a time, the transport provider can perform background operations that are not appropriate during other calls, or which need to occur on a regular basis.

See Also

IXPProvider::TransportLogon method


 IXPLogon::OpenStatusEntry

[New - Windows 95]

Opens a status object to get information about or modify the transport-provider logon session. This method is called by the MAPI spooler.

Syntax

HRESULT OpenStatusEntry(LPCIID lpInterface, ULONG ulFlags, ULONG FAR * lpulObjType, LPMAPISTATUS FAR * lppEntry)

Parameters

lpInterface

Input parameter pointing to the interface identifier (IID) for the transport logon object. Passing NULL for the lpInterface parameter indicates the MAPI interface for the object will be returned, in this case the IMAPIStatus interface. The lpInterface parameter can also be set to an identifier for another appropriate interface for the object.

ulFlags

Input parameter containing a bitmask of flags used to control how the status entry is opened. The following flag can be set:

MAPI_MODIFY

Requests read-write access. The default interface is read-only.

lpulObjType

Output parameter pointing to a variable that holds the type of the opened object.

lppEntry

Output parameter pointing to a variable where the pointer to the returned status object.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

The IXPLogon::OpenStatusEntry method opens an object with the IMAPIStatus interface associated with this particular transport logon. This object is then used to enable client applications to call IMAPIStatus methods, for example to reconfigure the logon session (using the IMAPIStatus::SettingsDialog method) or to validate the state of the logon session (using the IMAPIStatus::ValidateState method).

See Also

IMAPIStatus : IMAPIProp interface


 IXPLogon::Poll

[New - Windows 95]

Checks whether a transport provider has one or more incoming messages available. This method is called periodically by the MAPI spooler.

Syntax

HRESULT Poll(ULONG FAR * lpulIncoming)

Parameters

lpulIncoming

Output parameter indicating the existence of incoming messages. A nonzero value indicates that there are incoming messages.

Returned Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

The MAPI spooler periodically calls the IXPLogon::Poll method if the transport indicates it must be polled for new messages by passing the LOGON_SP_POLL flag to the call to the IXPProvider::TransportLogon method at the beginning of a session. If the transport provider indicates in response to the Poll call that there are one or more inbound messages available for it to process, the MAPI spooler calls the IXPLogon::StartMessage method to allow the transport to process the first incoming message. The transport indicates incoming messages by setting the value in Poll's lpulIncoming parameter to nonzero.

See Also

IXPLogon::StartMessage method, IXPProvider::TransportLogon method


 IXPLogon::RegisterOptions

[New - Windows 95]

Informs the messaging system about the options provided by a transport provider for a messaging address type.

Syntax

HRESULT RegisterOptions(ULONG FAR * lpulFlags, ULONG FAR * lpcOptions, LPOPTIONDATA FAR * lppOptions)

Parameters

lpulFlags

Output parameter containing a bitmask of flags. The following flag can be set:

MAPI_UNICODE

Indicates the returned strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

lpcOptions

Output parameter pointing to a variable containing the number of options contained in the structure returned in the lppOptions parameter.

lppOptions

Output parameter pointing to a variable where the pointer to the returned OPTIONDATA structure is stored. The OPTIONDATA structure contains information for this messaging address type.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

If anything other than S_OK is returned, the provider is logged off.

Comments

The MAPI spooler calls the IXPLogon::RegisterOptions method to get the options for messages and recipients supported by a transport provider for a particular messaging address type. These options are then registered with MAPI so they can be displayed in options dialog boxes.

RegisterOptions returns in the lppOptions parameter pointers to one or two OPTIONDATA structures for each supported messaging address type, depending on whether the provider is registered for both recipient and message options, recipient options only, or message options only. If a provider is registered for both option types, RegisterOptions writes one structure containing option information for message recipients and one containing option information for messages. For each structure, the ulFlags member indicates whether the options apply to a recipient or a message.

For an example of the use of OPTIONDATA, consider a transport provider that handles recipients for both Microsoft Mail and Microsoft Mail for the Macintosh. If the provider is registered for both recipient and message options, it provides two pairs of OPTIONDATA structures, one pair for each platform. The MAPI spooler can use these structures to determine what options are valid for each platform. Once it has this option information, the MAPI spooler prompts the user with a dialog box to retrieve the setting the user wants for each option.

MAPI also uses the options registered on the RegisterOptions call to resolve message and recipient options. MAPI does so by using a callback function of type OPTIONCALLBACK that the transport provider supplies; this callback function retrieves a wrapped IMAPIProp interface that manages the provider's message and recipient properties.

The provider is responsible for memory management. If memory is allocated for one or more OPTIONDATA structures during this call, the provider should free the memory upon logoff.

See Also

IXPLogon::RegisterOptions method, OPTIONCALLBACK function prototype, OPTIONDATA structure


 IXPLogon::RegisterOptions, OPTIONCALLBACK

[New - Windows 95]

The OPTIONCALLBACK function prototype is used by a transport provider to implement a callback function that MAPI calls to retrieve a wrapped IMAPIProp interface that manages the provider's properties.

Syntax

SCODE OPTIONCALLBACK (HINSTANCE hInst, LPMALLOC lpMalloc, ULONG ulFlags, ULONG cbOptionData, LPBYTE lpbOptionData, LPMAPISUP lpMAPISup, LPMAPIPROP lpDataSource, LPMAPIPROP FAR * lppWrappedSource, LPMAPIERROR FAR * lppMAPIError)

Parameters

hInst

Input parameter containing the hinstance for this transport provider's dynamic link library (DLL) as returned from the LoadLibrary function call made by MAPI.

lpMalloc

Input parameter specifying a pointer to a standard memory allocator.

ulFlags

Input parameter specifying a bitmask of flags indicating the type of options being processed. The following flags can be set:

OPTION_TYPE_MESSAGE

Indicates message options.

OPTION_TYPE_RECIPIENT

Indicates recipient options.

cbOptionData

Input parameter containing the size, in bytes, of the data pointed to by the lpbOptionData parameter.

lpbOptionData

Input parameter pointing to transport-provider option data for the recipient or message. This data is contained in the OPTIONDATA structure that was passed in the IXPLogon::RegisterOptions call that registered the options.

lpMAPISup

Input parameter pointing to a MAPI support object that the provider can use to call the methods of the IMAPISupport interface.

lpDataSource

Input parameter pointing to an IMAPIProp interface that MAPI wraps for the transport provider's use.

lppWrappedSource

Output parameter pointing to a variable where the pointer to the wrapped IMAPIProp interface returned by the transport provider is stored.

lppMAPIError

Output parameter pointing to a variable where the pointer to a returned MAPIERROR structure, if any, is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

The transport provider's OPTIONCALLBACK function is called by MAPI if a transport provider has previously registered message options with the IXPLogon::RegisterOptions method. Transport providers that do not define message or recipient options do not need to implement this callback function.

MAPI passes a wrapped IMAPProp interface in the lpDataSource parameter. The transport should build a display table, set any properties, and then pass that display table back to MAPI in a wrapped IMAPIProp interface in the lppWrappedSource parameter. MAPI uses this IMAPIProp interface to display properties in the message or recipient options dialog box that is displayed to users. When users make selections in the dialog box resulting in an IMAPIProp::OpenProperty call on the PR_DETAILS_TABLE property, the transport provider gets the call and should display the display table. The transport provider must call the IMAPIProp::SetProps method followed by the IMAPIProp::SaveChanges method on any changes the user made to the display table.

For more information on how to create display tables and how to implement OPTIONCALLBACK, see MAPI Programmer's Guide.

See Also

IMAPIProp : IUnknown interface, IMAPISupport : IUnknown interface, IXPLogon::RegisterOptions method


 IXPLogon::StartMessage

[New - Windows 95]

Initiates the transfer of an incoming message from the transport provider to the MAPI spooler.

Syntax

HRESULT StartMessage(ULONG ulFlags, LPMESSAGE lpMessage, ULONG FAR * lpulMsgRef)

Parameters

ulFlags

Reserved; must be zero.

lpMessage

Input parameter pointing to a message object with read-write access, representing the incoming message, which is used by the transport to access and manipulate the message. This object remains valid until after the transport returns from the call to the IXPLogon::StartMessage method.

lpulMsgRef

Output parameter pointing to a variable in which the transport returns the 32-bit reference value it assigned to this message. This value is initialized to 1 by the MAPI spooler before calling the transport.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

The MAPI spooler calls the IXPLogon::StartMessage method to initiate the transfer of an incoming message from the transport provider to the MAPI spooler. Before the transport starts to use the message object, it should store a message reference into the unsigned long pointed to by the lpulMsgRe parameter for potential use by a call to the IXPLogon::TransportNotify method.

During a StartMessage call, the MAPI spooler processes methods for objects opened during the transfer of the message and any attachments. This processing can take a long time. Transport providers on 16-bit Windows platforms should call the IMAPISupport::SpoolerYield callback function for the MAPI spooler frequently during this processing to release CPU time for other system tasks.

All recipients in the recipient table created by the transport for the message must contain all required addressing properties. If necessary, the transport provider can construct a custom recipient to represent a particular message recipient. However, if the provider can produce a recipient entry that includes more information, it should do so. For example, in the case where a transport has enough information about an address book provider's recipient format that it can build a valid entry identifier for a recipient for that address book provider, it should build the entry identifier.

If any nontransmittable properties are received, the transport should not store them in the new message. However, the transport should store in the message all transmittable properties required for the message.

If the incoming message is to be a delivery report or a nondelivery report and the transport is unable to use the IMAPISupport::StatusRecips method to generate the report from the original message, the transport should itself populate the passed message with the appropriate properties.

To save the incoming message in the appropriate MAPI message store after processing, the transport calls the IMAPIProp::SaveChanges method. If the transport provider doesn't have any messages, it can stop the incoming message by returning from the StartMessage call without calling SaveChanges.

All objects opened by the transport during a StartMessage call should be released before returning. However, the transport should not release the message object originally passed by the MAPI spooler in lpMessage.

If an error is returned from StartMessage, the message in process is released without having changes saved and is lost. The transport provider should pass the flag NOTIFY_CRITICAL_ERROR with a call to the IMAPISupport::SpoolerNotify method and call the IXPLogon::Poll method to notify the MAPI spooler that the transport provider is in a severe error condition.

For more information on interacting with the MAPI spooler, see MAPI Programmer's Guide.

See Also

IMAPIProp::SaveChanges method, IMAPISupport::SpoolerNotify method, IMAPISupport::SpoolerYield method, IMAPISupport::StatusRecips method, IMessage::GetRecipientTable method, IXPLogon::Poll method, IXPLogon::TransportNotify method


 IXPLogon::SubmitMessage

[New - Windows 95]

Indicates to the transport provider that the MAPI spooler has a message for the provider to deliver.

Syntax

HRESULT SubmitMessage(ULONG ulFlags, LPMESSAGE lpMessage, ULONG FAR * lpulMsgRef, ULONG FAR * lpulReturnParm)

Parameters

ulFlags

Input parameter containing a bitmask of flags used to control how a message is submitted. The following flag can be set:

BEGIN_DEFERRED

Indicates the MAPI spooler is calling a transport provider with a message whose entry identifier was passed from the transport provider (by using the IMAPISupport::SpoolerNotify method's NOTIFY_SENTDEFERRED flag).

lpMessage

Input parameter pointing to a message object with read-write access, representing the message to be sent, which is used by the transport to access and manipulate the message. This object remains valid until after the transport returns from a subsequent call to the IXPLogon::EndMessage method.

lpulMsgRef

Output parameter pointing to a variable in which the transport returns the 32-bit reference value it assigned to this message. The MAPI spooler passes this reference value in subsequent calls for this message. The value is initialized to zero by the MAPI spooler before calling the transport.

lpulReturnParm

Output parameter pointing to a variable in which corresponds to the MAPI_E_WAIT or MAPI_E_NETWORK_ERROR error values returned by SubmitMessage.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_BUSY

The transport can't handle the message because it is performing another operation. Use this return value to indicate that no processing occurred and that the MAPI spooler should not call IXPLogon::EndMessage. The MAPI spooler will try again later.

MAPI_E_CANCEL

On a previous call to the IXPLogon::SpoolerNotify method, the transport requested that the MAPI spooler resubmit the message. Since then, conditions have changed, and the message should not be resent. The MAPI spooler will go on to handle something else.

MAPI_E_NETWORK_ERROR

A network error prevented successful completion of the operation. The value in the lpulReturnParm parameter should be set to the number of seconds before the MAPI spooler resubmits the message.

MAPI_E_NOT_ME

The transport provider cannot handle this message. The MAPI spooler should try to find another transport provider for it. Use this return value to indicate that no processing occurred and that the MAPI spooler should not call IXPLogon::EndMessage.

MAPI_E_WAIT

A temporary problem prevents the transport from handling the message. The value in lpulReturnParm should be set to the number of seconds before the MAPI spooler resubmits the message.

Comments

The MAPI spooler calls the IXPLogon::SubmitMessage method when it has a message for the transport to carry. The message is passed to the transport provider using the lpMessage parameter.

If the transport is ready to accept the message, it should return a reference value by using the lpulMsgRef parameter, process the passed object, and return the appropriate value, usually S_OK. If the transport is not prepared to handle the transfer, it should return an error value and, optionally, another MAPI return value in the lpulReturnParm parameter to indicate how long the MAPI spooler should wait before resubmitting the message.

A transport provider's implementation of this method can:

•	Put the message to be sent into an internal queue to wait for transmission, possibly copying it to local storage, and return.

•	Attempt to perform the actual transmission and return when the transmission has completed, either successfully or unsuccessfully.

•	Determine whether or not to send the message after checking the resource involved. In this case, if the resource is free, the transport can lock the resource, prepare the message, and submit it. If the resource is busy, the transport can prepare the message and defer sending to a later time.

The preferred technique depends on the transport provider and the expected number of processes competing for system resources.

During a SubmitMessage call, the transport controls the transfer of message data from the message object. However, the transport provider should assign a 32-bit reference value to the message, to which it returns a pointer in the lpulMsgRef parameter, before transferring data. It does so because at any point during the process the MAPI spooler can call the IXPLogon::TransportNotify method with the NOTIFY_CANCEL_MESSAGE flag set to signal the transport that it should release any open objects and stop message transfer.

The transport should not send any nontransmittable properties of the message. When it finds such a property, it should go on to process the next one. The transport should make every effort not to display MAPI_P1 recipient information as part of the transmitted message content, using such recipient information only for addressing purposes.

During a SubmitMessage call, the MAPI spooler processes methods for objects opened during the transfer of the message and any attachments. This processing can take a long time. Transport providers running on 16-bit Windows platforms should call the IMAPISupport::SpoolerYield callback function for the MAPI spooler frequently during this processing to release CPU time for other system tasks.

All message recipients are visible in the recipient table of the message originally passed by the MAPI spooler. The transport should process only those recipients that it can handle based on entry identifier, address type, or both and that do not already have their PR_RESPONSIBILITY property set to TRUE. A PR_RESPONSIBILITY already set to TRUE means that another transport provider handles that recipient. When the transport has completed sufficient processing of a recipient to determine whether it can handle messages for that recipient, it should set that recipient's PR_RESPONSIBILITY to TRUE in the passed message. Usually, the transport makes this determination after message delivery is complete.

Typically, the transport does not return from a SubmitMessage call until it has completed the transfer of message data. If no error is returned, the next call from the MAPI spooler to the transport is a call to the IXPLogon::EndMessage method.

If an error is returned from SubmitMessage, the MAPI spooler releases the message in process without saving changes. If the transport requires message changes be saved, it must call the IMAPIProp::SaveChanges method on the message before returning.

In case of errors occurring because of transport problems, the MAPI spooler retains the message but delays resubmitting it to the transport based on the value returned in the lpulRetunParm parameter. The transport provider must fill in that value if its return from SubmitMessage is MAPI_E_WAIT or MAPI_E_NETWORK_ERROR. If a severe error condition is occurring, the transport provider must call the IMAPISupport::SpoolerNotify method with the NOTIFY_CRITICAL_ERROR flag.

See Also

IMAPIProp::SaveChanges method, IMAPISupport::SpoolerNotify method, IMAPISupport::SpoolerYield method, IXPLogon::EndMessage method, IXPLogon::TransportNotify method


 IXPLogon::TransportLogoff

[New - Windows 95]

Terminates a transport provider session with the MAPI spooler.

Syntax

HRESULT TransportLogoff(ULONG ulFlags)

Parameters

ulFlags

Reserved; must be zero.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Returning any value other than S_OK causes the transport to be logged off anyway.

Comments

The MAPI spooler calls the IXPLogon::TransportLogoff method to terminate a transport session for a particular user. Before calling TransportLogoff, the MAPI spooler discards any data about supported messaging address types for this session that had been passed in the IXPLogon::AddressTypes method.

The transport provider should be prepared to accept a call to TransportLogoff at any time. If a message is in process, the transport should stop the sending process.

The transport should release all resources allocated for the current transport session. If it has allocated any memory for this session with the MAPIAllocateBuffer function, it should free the memory by using the MAPIFreeBuffer function. Any memory allocated by the transport to satisfy calls to the AddressTypes, IXPLogon::RegisterOptions, and IMAPISession::MessageOptions methods can be safely released at this time.

Usually, a provider should, on completing a TransportLogoff call, first invalidate its logon object by calling the IMAPISupport::MakeInvalid method and then release its support object. The transport's implementation of TransportLogoff should release the support object last, because when the support object is released, the MAPI spooler can also release the provider object itself.

See Also

IMAPISession::MessageOptions method, IMAPISupport::MakeInvalid method, IMAPISupport::SpoolerYield method, IXPLogon::AddressTypes method, IXPLogon::RegisterOptions method, MAPIAllocateBuffer function, MAPIFreeBuffer function


 IXPLogon::TransportNotify

[New - Windows 95]

Signals in a transport provider session the occurrence of an event for the MAPI spooler about which the transport provider has requested notification.

Syntax

HRESULT TransportNotify(ULONG FAR * lpulFlags, LPVOID FAR * lppvData)

Parameters

lpulFlags

Input-output parameter containing a bitmask of flags used to signal notification events. The following flags can be set on input and must be returned unchanged on output:

NOTIFY_ABORT_DEFERRED

Notifies the transport that a message for which it accepted responsibility is being canceled. Only transports that support deferral need to support this flag. The lppvData parameter points to the entry identifier of the message. Messages that have not been processed by the MAPI spooler can still be canceled by calling the IMsgStore::AbortSubmit method.

NOTIFY_BEGIN_INBOUND

Indicates inbound messages can now be accepted for this transport provider session. The MAPI spooler regularly calls the IXPLogon::Poll method if the transport provider set the flag LOGON_SP_POLL with the IXPProvider::TransportLogon call at logon. Once the NOTIFY_BEGIN_INBOUND flag is set, the MAPI spooler honors the NOTIFY_NEWMAIL flag passed in the call to the IMAPISupport::SpoolerNotify method. The status table row for the transport session should be updated before returning by calling the IMAPISupport::ModifyStatusRow method. The NOTIFY_BEGIN_INBOUND flag is mutually exclusive with NOTIFY_END_INBOUND.

NOTIFY_BEGIN_INBOUND_FLUSH

Signals the transport provider to cycle through inbound mail as quickly as possible. This flag is set by the MAPI spooler. To comply with this notification, the transport provider should set the flag STATUS_INBOUND_FLUSH bit in the PR_STATUS_CODE property of its status table row as soon as it can, using the IMAPISupport::ModifyStatus Row method. Until the end of this inbound messaging cycle, that is when the transport determines it has downloaded all it can or when it has received an IXPLogon::TransportNotify method call with the flag NOTIFY_END_INBOUND_FLUSH, the transport provider should not call the IMAPISupport::SpoolerYield method or otherwise give up cycles to the operating system that can be used to speed delivery of all incoming messages. At the end of the inbound flush operation, the transport should clear the STATUS_INBOUND_FLUSH bit in the PR_STATUS_CODE property of its status row using the IMAPISupport::SpoolerNotify method.

NOTIFY_BEGIN_OUTBOUND

Indicates outbound operations can now occur for this transport provider session. If there are any messages to be set for this transport provider, a call to the IXPLogon::SubmitMessage method follows. The status table row for the transport session should be updated before returning. The NOTIFY_BEGIN_OUTBOUND flag is mutually exclusive with NOTIFY_END_OUTBOUND.

NOTIFY_BEGIN_OUTBOUND_FLUSH

Works similarly to NOTIFY_BEGIN_INBOUND_FLUSH but refers to outbound mail, and the appropriate status flag is STATUS_OUTBOUND_FLUSH.

NOTIFY_CANCEL_MESSAGE

Indicates the MAPI spooler must cancel transfer of a message for which the lppvData parameter points to the ulMsgRef parameter (the 32-bit value obtained with the IXPLogon::SubmitMessage method call). The NOTIFY_CANCEL_MESSAGE flag can be set without the transport provider having returned from the IXPLogon::StartMessage, IXPLogon::SubmitMessage, or IXPLogon::EndMessage method call associated with the message. The transport provider must return from the entry point that is handling the canceled message as soon as possible.

For an in-process incoming message, the transport provider should retain the incoming message wherever it is presently stored and pass it in at the next convenient time. The message object data already stored for the incoming message is discarded.

If the transport provider did not update the ulMsgRef parameter at StartMessage or SubmitMessage time, ulMsgRef has a value of 0 for outbound messages (set with SubmitMessage) or 1 for inbound messages (set with StartMessage).

NOTIFY_END_INBOUND

Indicates inbound operations must cease for this transport provider session. The MAPI spooler ceases to use the IXPLogon::Poll method and ignores the NOTIFY_NEWMAIL flag set with the IMAPISupport::SpoolerNotify method for this session. In-process messages should not be aborted. The status table row for the transport session should be updated by calling the IMAPISupport::ModifyStatusRow method before returning. The NOTIFY_END_INBOUND flag is mutually exclusive with NOTIFY_BEGIN_INBOUND.

NOTIFY_END_INBOUND_FLUSH

Notifies the transport provider to come out of flush mode. This flag is set by the MAPI spooler. Setting this flag does not indicate the transport provider should stop downloading, but that downloading should be done in the background. The status table row for the transport session should be updated by calling the IMAPISupport::ModifyStatusRow method when the transport provider can comply with this notification.

NOTIFY_END_OUTBOUND

Indicates outbound operations must cease for this transport provider session. The MAPI spooler ceases to call the IXPLogon::SubmitMessage method and ignores the NOTIFY_READYTOSEND flag set with the IMAPISupport::SpoolerNotify method. If there is an in-process message, it should not be stopped (to stop a message, use the NOTIFY_CANCEL_MESSAGE flag). The status table row for the transport session should be updated by calling the IMAPISupport::ModifyStatusRow method before returning. The NOTIFY_END_INBOUND flag is mutually exclusive with NOTIFY_BEGIN_OUTBOUND.

NOTIFY_END_OUTBOUND_FLUSH

Works similarly to NOTIFY_END_INBOUND_FLUSH but refers to outbound mail, and the appropriate status flag is STATUS_OUTBOUND_FLUSH.

lppvData

Output parameter pointing to a variable where the pointer to event-specific data is stored. For more information on what the lppvData parameter holds, see the descriptions for the flags for the lpulFlags parameter.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

The MAPI spooler calls the IXPLogon::TransportNotify method to signal to the transport the occurrence of events about which notification has been requested. These events include the MAPI spooler's requiring the cancellation of transfer for a message, the beginning or ending of inbound or outbound transport operations, and the beginning or ending of an operation to clear either an incoming message queue or an outgoing message queue.

When the user tries to cancel a message that the transport provider has previously deferred, the MAPI spooler calls TransportNotify passing in both the NOTIFY_ABORT_DEFERRED flag and the NOTIFY_CANCEL_MESSAGE flag in the ulFlags parameter. If the MAPI spooler is logging off and still has deferred messages in the queue, it passes only the NOTIFY_ABORT_DEFERRED flag in ulFlags when it calls TransportNotify.

The provider must synchronize access to its data on this call, because the MAPI spooler can invoke this method from another thread of execution or from a procedure for a different window.

See Also

IMAPISupport::SpoolerNotify method, IMAPISupport::SpoolerYield method, IMsgStore::AbortSubmit method, IXPLogon::EndMessage method, IXPLogon::Poll method, IXPLogon::StartMessage method, IXPLogon::SubmitMessage method, IXPLogon::TransportNotify method, IXPProvider::TransportLogon method


 IXPLogon::ValidateState

[New - Windows 95]

Has a transport provider check its external status. This method is called by the MAPI spooler.

Syntax

HRESULT ValidateState(ULONG ulUIParam, ULONG ulFlags)

Parameters

ulUIParam

Input parameter containing the handle to the window that the dialog box is modal to.

ulFlags

Input parameter containing a bitmask of flags used to control the status check for the transport. The following flags can be set:

ABORT_XP_HEADER_OPERATION

Indicates that the user canceled the operation, typically by pressing the Cancel button in a dialog box. The transport has the option to continue working on the operation, or the transport can abort the operation and return MAPI_E_USER_CANCELED.

CONFIG_CHANGED

Validates the state of currently loaded transports by causing the MAPI spooler to call the transport's IXPLogon::AddressTypes and IMAPISsession::MessageOptions methods. This flag also provides the MAPI spooler an opportunity to correct critical transport failures without forcing the client applications to log off and then log on again.

FORCE_XP_CONNECT

Indicates that the user selected a connect operation. When this flag is used with the REFRESH_XP_HEADER_CACHE or PROCESS_XP_HEADER_CACHE flag, the connect action occurs without caching.

FORCE_XP_DISCONNECT

Indicates that the user selected a disconnect operation. When this flag is used with the REFRESH_XP_HEADER_CACHE or PROCESS_XP_HEADER_CACHE flag, the disconnect action occurs without caching.

PROCESS_XP_HEADER_CACHE

Indicates that entries in the header cache table should be processed, that all messages marked as MSGSTATUS_REMOTE_DOWNLOAD should be downloaded, and that all messages marked as MSGSTATUS_REMOTE_DELETE should be deleted. Messages that have both MSGSTATUS_REMOTE_DOWNLOAD and MSGSTATUS_REMOTE_DELETE set should be moved.

REFRESH_XP_HEADER_CACHE

Indicates that a new list of mailbag headers should be downloaded, and that all message status marks should be cleared.

SUPPRESS_UI

Prevents the provider from displaying user interface components.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_BUSY

Another operation is in progress; it should be allowed to complete, or it should be stopped, before this operation is attempted.

MAPI_E_NO_SUPPORT

The remote transport provider does not support a user interface, and the client application should display the dialog box itself.

MAPI_E_USER_CANCEL

The user canceled the operation, typically by clicking the Cancel button in a dialog box.

Comments

The MAPI spooler calls the IXPLogon::ValidateState method to support calls to the IMAPIStatus::ValidateState method, for the status object. The transport should respond to the IXPLogon::ValidateState call exactly as if the MAPI spooler had opened a status object for the current logon session and then called ValidateState on that object.

To support its implementation of IMAPIStatus::ValidateState, the MAPI spooler calls IXPLogon::ValidateState on all logon objects for all active transport providers running in this profile session.

See Also

IMAPISession::MessageOptions method, IMAPIStatus::ValidateState method, IXPLogon::AddressTypes method


 IXPProvider : IUnknown

[New - Windows 95]

The IXPProvider interface is used to initialize a transport provider object and to shut down the object when it is no longer needed.

At a Glance

Specified in header file:	MAPISPI.H
Object that supplies this interface:	Transport provider object
Corresponding pointer type:	LPXPROVIDER
Implemented by:	Transport providers
Called by:	The MAPI spooler
Vtable Order

Shutdown	Closes down a transport provider in an orderly fashion.
TransportLogon	Establishes a session in which a user logs onto a transport provider.


 IXPProvider::Shutdown

[New - Windows 95]

Closes down a transport provider in an orderly fashion.

Syntax

HRESULT Shutdown (ULONG FAR * lpulFlags)

Parameters

lpulFlags

Reserved; must be zero.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

The MAPI spooler calls the IXPProvider::Shutdown method just prior to releasing a transport provider object. MAPI will have released all logon objects on a provider before calling Shutdown.

See Also

XPProviderInit function


 IXPProvider::TransportLogon

[New - Windows 95]

Establishes a session with the MAPI spooler for the transport provider.

Syntax

HRESULT TransportLogon(LPMAPISUP lpMAPISup, ULONG ulUIParam, LPTSTR lpszProfileName, ULONG FAR * lpulFlags, LPMAPIERROR FAR * lppMAPIError, LPXPLOGON FAR * lppXPLogon)

Parameters

lpMAPISup

Input parameter pointing to the transport provider's support object for callback functions within MAPI and the MAPI spooler for this session. This object remains valid until the transport provider object releases it.

ulUIParam

Input parameter containing the handle to the window the dialog box is modal to. The ulUIParam parameter can be non-null, for example when called with the LOGON_SETUP flag.

lpszProfileName

Input parameter pointing to a string containing the profile name of the user. The lpszProfileName parameter is used primarily when a dialog box must be presented.

lpulFlags

Input-output parameter containing a bitmask of flags used to control how the logon session is established. The following flags can be set on input by the MAPI spooler:

LOGON_NO_CONNECT

Indicates the user account is logging onto this transport provider for purposes other than transmission and reception of messages. The transport provider should not attempt to make any connections.

LOGON_NO_DIALOG

Indicates that no dialog box should be displayed even if the currently saved user credentials are invalid or insufficient for logon.

LOGON_NO_INBOUND

Indicates the transport provider does not need to initialize for reception of messages and should not accept incoming messages. The MAPI spooler usually sets this flag. The MAPI spooler can use IXPLogon::TransportNotify method to signal the transport provider to enable inbound message processing.

LOGON_NO_OUTBOUND

Indicates the transport provider does not need to initialize for sending messages, as the MAPI spooler does not provide any. If the client application requires a connection to a remote provider during the composition of a message so that it can make IXPLogon::AddressTypes or IXPLogon::RegisterOptions method calls, the transport provider should make the connection. The MAPI spooler usually sets this flag. The MAPI spooler can use the IXPLogon::TransportNotify method to signal the transport provider when outbound operations can begin.

MAPI_UNICODE

Indicates the passed-in string for the profile name is in Unicode format. If the MAPI_UNICODE flag is not set, the string is in 8-bit format.

The following flags can be set by the transport provider on output:

LOGON_SP_IDLE

Requests that the MAPI spooler frequently call the transport provider's IXPLogon::Idle method for idle-time processing.

LOGON_SP_POLL

Requests that the MAPI spooler frequently call the IXPLogon::Poll method on the returned logon object to check for new messages. If this flag is not set, the MAPI spooler only checks for new messages when the transport provider calls the IMAPISupport::SpoolerNotify method to indicate it should do so. A transport provider effectively becomes send-only by not setting this flag and by not notifying the MAPI spooler of message receipt.

LOGON_SP_RESOLVE

Requests that the MAPI spooler resolve to full addresses all message addresses for recipients not covered by this transport provider, so that the transport provider can construct a reply path for all recipients.

MAPI_UNICODE

Indicates the returned strings in the MAPIERROR structure, if any, are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

lppMAPIError

Output parameter pointing to a variable where the pointer to the returned MAPIERROR structure, if any, is stored. The MAPIERROR structure contains version, component, and context information for the error. The lppMAPIError parameter can be set to NULL if there is no MAPIERROR structure to return.

lppXPLogon

Output parameter pointing to a variable where the pointer to the returned transport logon object is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_UNCONFIGURED

The profile does not contain enough information for the logon to complete. MAPI calls the provider's message-service entry function.

MAPI_E_USER_CANCEL

The user canceled the operation, typically by clicking the Cancel button in the dialog box.

Comments

The MAPI spooler calls the IXPProvider::TransportLogon method to establish a logon session with a user. Most transport providers use the IMAPISupport::OpenProfileSection method provided with the support object pointed to by the lpMAPISup parameter for saving and retrieving user identity information, server addresses, or credentials. Using this method enables a transport provider to save arbitrary information and associate it with a logon to a particular resource. For example, a provider can use OpenProfileSection to save the account name and password associated with a particular session and any server names or other necessary information needed to access resources for that session. MAPI hides information associated with a resource from outside access. The profile section made available through lpMAPISup is segregated by the MAPI spooler so that data related to this user context is separated from data for other contexts.

The transport provider must call IUnknown::AddRef on the support object and keep a copy of the pointer to this object as part of the logon object.

The display name of the user's profile in the lpszProfileName parameter is provided so that the transport provider can use it in error messages or logon dialog boxes. If the provider retains this name, it must be copied to storage allocated by the provider.

Transports that are tightly coupled with other service providers might need to do additional work at logon to establish the proper credentials required for operations between companion providers.

Usually, transports are opened when the user first logs onto a profile. Because the first logon to a profile thus generally precedes logon to any message store, the MAPI spooler usually calls TransportLogon with both the LOGON_NO_INBOUND and LOGON_NO_OUTBOUND flags set in the lpulFlags parameter. Later, when the appropriate message stores are available in the profile session, the MAPI spooler calls the IXPLogon::TransportNotify method to initiate inbound and outbound operations for the transport.

Passing the LOGON_NO_CONNECT flag in the lpulFlags parameter signals offline operation of the transport. This value indicates that no external connection is to be made; if the transport provider cannot establish a session without an external connection, it should return an error value for the logon.

A transport provider should set the LOGON_SP_IDLE flag in lpulFlags at initialization time to support any scheduled connections and to handle automatic operations, such as automatic message downloading, timed message downloading, or timed message submission. If this flag is set, the MAPI spooler calls the IXPLogon::Idle method when system idle time occurs to initiate such operations. The MAPI spooler does not call Idle at a regular interval; rather, it is called only during true idle time, so providers should not make any assumptions about how frequently their Idle method will be called. Providers that support such operations should supply the correct configuration user interface in their provider property sheet.

If the transport logon succeeds, the transport provider should return in the lppXPLogon parameter a pointer to a logon object for the MAPI spooler to use for further transport-provider access. If TransportLogon displays a logon dialog box and the user cancels logon, typically by clicking the Cancel button in the dialog box, your provider should return MAPI_E_USER_CANCEL.

If your provider finds that all the required information is not in the profile, it should return MAPI_E_UNCONFIGURED so that MAPI calls the provider's message-service entry function.

See Also

IMAPISupport::OpenProfileSection method, IMAPISupport::SpoolerNotify method, IXPLogon::AddressTypes method, IXPLogon::Idle method, IXPLogon::Poll method, IXPLogon::RegisterOptions method, IXPLogon::TransportNotify method, MAPIERROR structure


 About This Book

MAPI Programmer's Reference, Volume 2, one of three books accompanying the Messaging Application Programming Interface (MAPI) Software Development Kit (SDK), provides a complete reference to Extended MAPI functions, data structures, data types, properties, and return values and to the Simple MAPI and Common Messaging Calls (CMC) programming models. It also documents how to develop key configuration files for Extended MAPI; illustrates Transport-Neutral Encapsulation Format (TNEF), a serialization of Extended MAPI properties; describes Extended MAPI implementations of 32-bit Windows® functions; and provides a glossary of MAPI terms. This book should be used together with MAPI Programmer's Reference, Volume 1, and MAPI Programmer's Guide to develop messaging-based applications and services.


 Intended Audience

MAPI Programmer's Reference, Volume 2, is written for C and C++ developers with a range of needs and experience with messaging. For those developers who want to use MAPI to augment their applications with messaging features, no specific prerequisite knowledge is required. However, for workgroup developers who plan to use MAPI to create full-scale messaging applications, extensions or customized solutions for existing products, or message services, a background in OLE programming is recommended.


 How This Book Is Organized

This book's contents are organized as follows:

•	Chapter 1, "Introduction," introduces concepts basic to using Extended MAPI functions, data structures, macros, data types, properties, and return values, including usage of input and output function parameters, function parameter commonality, and flag usage.

•	Chapter 2, "Common Messaging Calls (CMC)," provides a complete reference to the CMC application programming interface (API), including documentation on CMC functions, data structures, data types, and data extensions.

•	Chapter 3, "Simple MAPI," provides a complete reference to Simple MAPI, including documentation for Simple MAPI functions and structures for C and C++ and functions and data types for Visual Basic®.

•	Chapter 4, "Essential Extended MAPI Functions," documents those Extended MAPI functions that are essential to implementing and using Extended MAPI. Functions are described in alphabetic order.

•	Chapter 5, "Extended MAPI Properties," documents the Extended MAPI properties in alphabetic order.

•	Chapter 6, "Extended MAPI Structures and Simple Data Types," documents the Extended MAPI data structures and data types in alphabetic order. It also provides documentation for macros that create structures with the structures they create.

•	Chapter 7, "Additional Extended MAPI Functions," documents Extended MAPI functions specific to certain purposes that are not of general use in Extended MAPI development. Functions are described in alphabetic order.

•	Chapter 8, "MAPISVC.INF File Format and WIN.INI File Format," documents the MAPISVC.INF file, the central database for MAPI configuration information. It also covers MAPI entries to the WIN.INI initialization file for the Microsoft® Windows operating system; these entries indicate the existence of various MAPI components and provide information about their configuration.

•	Chapter 9, "Transport-Neutral Encapsulation Format (TNEF)," documents TNEF and includes examples of TNEF encoding.

•	Chapter 10, "Configuration File Format," describes the format of a MAPI configuration file, a file created by a form developer to define a MAPI form.

•	Appendix A, "Extended MAPI Return Values," provides information on the Extended MAPI return values that represent error conditions that cause method and function calls to fail and that cannot be dealt with using conventional error handling. Other Extended MAPI error values are documented with the methods or functions that return them.

•	Appendix B, "Extended MAPI Versions of 32-Bit Windows Functions" documents MAPI implementations of certain 32-bit Windows functions.

•	Appendix C, "Mapping of X.400 P2 Attributes to Extended MAPI Properties," maps attributes used by the X.400 message-handling standard to the corresponding Extended MAPI properties.

•	The glossary defines the MAPI terms used most often throughout the MAPI SDK documentation.


 Document Conventions

The following typographical conventions are used throughout this book:

Typographical convention	Meaning
Bold	Indicates an interface, method, structure, or other keyword in MAPI, the Microsoft Windows operating system, the OLE application programming interface, C, or C++. For example, IMAPISupport::SpoolerYield is a MAPI method. Within discussions of syntax, bold type indicates that the text must be entered exactly as shown.
italic	Indicates placeholders, most often method or function parameters; these placeholders stand for information that must be supplied by the implementation or the user. For example, ulFlags is a MAPI function parameter. In addition, italics are used to highlight the first use of terms and to emphasize meaning.
UPPERCASE	Indicates MAPI flags, return values, and properties. For example, MAPI_UNICODE is a flag, S_OK is a return value, and PR_DISPLAY_NAME is a property. In addition, uppercase letters indicate filenames, segment names, registers, and terms used at the operating-system command level.
monospace	Indicates source code, structure syntax, examples, user input, and program output. For example: ptbl->SortTable(pSort, TBL_BATCH);
SMALL CAPITALS	Indicate the names of keys on the keyboard. When you see a plus sign ( + ) between two key names, you should hold down the first key while pressing the second. The carriage return key, sometimes marked as a bent arrow on the keyboard, is called ENTER.
Note  The interface syntax in this book follows the variable-naming convention known as Hungarian notation, invented by the programmer Charles Simonyi. Variables are prefixed with lowercase letters that indicate their data type. For example, lpszProfileName is a long pointer to the null-terminated string name ProfileName. For more information about Hungarian notation, see Programming Windows 3.1 by Charles Petzold, and Code Complete, by Steve McConnell.


 For More Information

For information on MAPI not covered in this book, see MAPI Programmer's Guide and MAPI Programmer's Reference, Volume 1, both contained within the MAPI SDK. MAPI Programmer's Guide provides a conceptual overview of the MAPI architecture and describes a wide range of programming tasks illustrated with extensible and reusable sample code. MAPI Programmer's Reference, Volume 1, provides a complete reference to the interfaces and methods used with Extended MAPI objects.

For more information about OLE programming, see Inside OLE, Second Edition, by Kraig Brockschmidt (Redmond, WA: Microsoft Press®, 1995), and OLE Programmer's Reference, Volume One and Volume Two, in the Microsoft Win32® SDK, published on CD-ROM by the Microsoft Developer Network (MSDN) and by Microsoft Visual C++™.

For more information about programming for 32-bit Windows, see the Win32 SDK. For more information about programming for 16-bit Windows, see the Microsoft Windows SDK for Windows version 3.1, published on CD-ROM by MSDN and by Visual C++. Another good general source on Windows programming is Programming Windows 3.1, by Charles Petzold (Redmond, WA: Microsoft Press, 1992), and a good handbook on practical software development in Code Complete, by Steve McConnell (Redmond, WA: Microsoft Press, 1993).

For more information about C and C++ programming, see the documentation for Visual C++, also published on CD-ROM by MSDN and by Visual C++.


 Introduction

This chapter covers concepts integral to working with Extended MAPI, particularly Extended MAPI functions and structures. It does not provide a full explanation of MAPI architecture and concepts; for a more complete conceptual discussion of MAPI, see MAPI Programmer's Guide.


 Essential Functions vs. Additional Functions

Functions documented in Chapter 4, "Essential Extended MAPI Functions" are those functions that are basic to MAPI development and without which MAPI-based programs cannot be created. Functions documented in Chapter 7, "Additional Extended MAPI Functions," are listed there as general information for developers but are rarely used in development with MAPI.


 Some Conventions for Working with Extended MAPI Functions and Structures

The following topics provide information on some conventions common to Extended MAPI functions and to Extended MAPI structures. Learning about these similarities helps in learning and applying the MAPI programming model consistently throughout your program.


 Function Parameter Commonalities

Many MAPI functions take similar parameters as arguments. Learning about these similarities helps in learning and applying the MAPI programming model. Shown here are the more commonly used parameters and the way in which each is used throughout the MAPI functions.

Parameter	Usage
lpInterface	Pointer to the interface to be used.
ulUIParam	Handle of the window where the action is taking place.
ulFlags	Flags passed in.
lpulFlags	Flags passed in and passed back on return.
lpMAPIError	Pointer to a MAPIERROR structure.
lpMessage	Pointer to a message object.
lpProblems	Pointer to an array of problems returned on operations involving properties.
lpProgress	Pointer to a progress object.
lpTable	Pointer to a table object.
lpUnk	Pointer to an object returned from a call to a QueryInterface method.
lpPropTagArray	Pointer to an array of property tags.
lpEntryID	Pointer to an entry identifier for an object.
lpulConnection	Pointer to the connection number used to register a notification.


 Input, Output, and Input-Output Parameters

In descriptions of function parameters, MAPI Programmer's Reference, Volume 2, has adopted the convention of indicating whether a parameter is an input, output, or input-output parameter. The distinction is important for knowing how to efficiently manage memory.

As discussed in MAPI Programmer's Reference, Volume 1, the memory management model employed in MAPI is an enhancement of the rules specified in OLE's component object model. When internally allocating and freeing memory not related to MAPI processes within your client application or service provider, you can use whatever mechanism makes sense.

Parameters fall into one of three groups. They may be input parameters, set by the calling implementation with information to be used by the called function, output parameters, set by the called function and returned to the calling implementation, or input-output parameters, a combination of the two groups. The MAPI memory management model dictates how memory for these groups of parameters is allocated and freed as follows:

Parameter group	Allocating memory	Freeing memory
Input	Calling implementation is responsible for allocating memory and can use any mechanism.	Calling implementation is responsible for freeing memory and can use any mechanism.
Output	Called implementation is responsible for allocating memory and must use the MAPIAllocateBuffer function.	Called implementation is responsible for freeing memory and must use the MAPIFreeBuffer function.
Input-output	Calling implementation is responsible for the initial allocation; called implementation can reallocate memory if necessary using the MAPIAllocateMore function.	Called implementation is responsible for initial memory freeing if reallocation is necessary. Calling implementation must free the final return value.
When a process fails, providers need to pay attention to output and input-output parameters because the calling implementation generally has no way to release the memory for the failed process. If a function returns a value indicating failure, then each output or input-output parameter must either be left at the value initialized by the calling implementation or set to a value for which memory will be released without any action on the part of the calling application. For example, a provider must leave an output pointer parameter of void ** ppv as it was on input; otherwise, it must set the returned pointer to NULL (*ppv = NULL).


 Flag Usage for Functions and Structures

MAPI functions and structures (as well as MAPI methods) make extensive use of bitmasks to pass flags so that bits can be set to control how an operation is performed. The most common usage of bitmasks is in ulFlags parameters, but you will find them used in other parameters and structure members as well.

MAPI has predefined all of the allowable flags as constants. These constants take the form of all uppercase letters with each word separated by an underscore, for example MAPI_UNICODE. Your client or provider should only set the bits in the bitmask by passing in the constants allowed for that parameter; it should not set the bits itself or define its own flags. The only valid flags for a particular parameter of a given function, or a particular member of a given structure, are the ones that are listed under the parameter or member description. Passing any other flags, or setting any other bits by hand, will result in the error code MAPI_E_UNKNOWN_FLAGS being returned.

For example, IMessage::SetReadFlag takes a single parameter, ulFlags. The allowable flags are CLEAR_READ_FLAG, MAPI_DEFERRED_ERRORS, and SUPPRESS_RECEIPT. You set the bit for CLEAR_READ_FLAG like this:

pMessage->SetReadFlag(CLEAR_READ_FLAG);

Some functions take a ulFlags parameter in which all of the bits are reserved for MAPI's use. In such cases, the parameter description will read "Reserved; must be zero." Passing any value other than zero in such parameters results in the MAPI_E_UNKNOWN_FLAGS error being returned. If more than one flag is defined for a parameter, any combination of flags can be passed using the logical-OR operator, unless the documentation for that parameter specifically mentions that some flags are mutually exclusive. For example, you set all of the flags for SetReadFlag like this:

pMessage->SetReadFlag(CLEAR_READ_FLAG | MAPI_DEFERRED_ERRORS | SUPPRESS_RECEIPT);

The called function then examines each relevant bit of the ulFlags parameter to see if that bit is set.


 Common Messaging Calls (CMC)

The Common Messaging Calls (CMC) applications programming interface (API) is designed to provide simple and convenient set of functions to applications that need basic messaging services. CMC provides for all the major messaging functions an application should need, such as accessing message stores for sending and receiving messages, and addressing and name resolution services. The functions in the CMC API are typically high level functions and can each be used in several different ways depending on the arguments to the functions. The CMC API isolates the calling application from needing to know anything about the underlying messaging system or transport mechanism used to implement the CMC API itself.

Most CMC functions use both input and output parameters. Input parameters provide information that the CMC implementation uses to perform the tasks needed by the calling application. Output parameters are used by the CMC implementation to pass information back from a CMC function. Some functions have parameters used for both input and output.

Data structures and symbolic constants for CMC and its extensions are discussed in this document. The C language definitions of them can be found in the following header files:

Header file name	Header file contents
XCMC.H	CMC data structure and symbolic constants.
XCMCEXT.H	Common CMC extension data structures and symbolic contstants.
XCMCMSXT.H	Microsoft CMC extension data structures and symbolic constants.


 CMC Functions

The following functions are implemented in compliance with the X.400 API Association's Common Messaging Call API specification. These functions make heavy use of extensions, which are discussed later in this document.


 cmc_act_on

[New - Windows 95]

Performs the specified operation on a message.

Syntax

CMC_return_code cmc_act_on (CMC_session_id session, CMC_message_reference *message_reference, CMC_enum operation, CMC_flags act_on_flags, CMC_ui_id ui_id, CMC_extension FAR *act_on_extensions)

Parameters

session

Input parameter containing a session identifier that represents a MAPI session. The value in the session parameter must be a valid session handle, not zero.

message_ reference

Input parameter pointing to a message reference that identifies the message to be acted upon. A null pointer or a pointer to a message reference of length zero is invalid for any operation requiring a message reference. If the message reference is invalid, the cmc_act_on function returns CMC_E_INVALID_MESSAGE_REFERENCE.

operation

Input parameter containing an enumeration variable that identifies the operation to perform on the message. Possible values for this variable are:

CMC_ACT_ON_DELETE

Marks the specified message for deletion from the mailbox. This operation requires a valid message_reference parameter.

CMC_ACT_ON_EXTENDED

Indicates the operation to be performed is specified in the act_on_extensions parameter.

act_on_flags

Input parameter containing a bitmask of option flags. The following flag can be set:

CMC_ERROR_UI_ALLOWED

Displays a dialog box on encountering recoverable errors. If this flag is not set, cmc_act_on does not display a dialog box and returns an error code instead.

ui_id

Input parameter containing a handle that cmc_act_on uses to present a user interface to resolve processing questions.

act_on_extensions

Input-output parameter pointing to an array of CMC_extension structures containing function extensions. On input, this array contains MAPI extensions to the standard cmc_act_on function. A value of NULL for the act_on_extensions parameter indicates that the caller has no extensions for cmc_act_on and is expecting no extensions.

On output, cmc_act_on writes to the array new information about its processing. It writes NULL if it generates no output extensions.

Return Values

CMC_E_FAILURE

There was a general failure that does not fit the description of any other return code.

CMC_E_INSUFFICIENT_MEMORY

Insufficient memory was available to complete the requested operation.

CMC_E_INVALID_ENUM

A CMC_enum value is invalid.

CMC_E_INVALID_FLAG

A flag set using a flags parameter was invalid.

CMC_E_INVALID_MESSAGE_REFERENCE

The specified message reference is invalid or no longer valid (for example, it has been deleted).

CMC_E_INVALID_PARAMETER

A function parameter was invalid.

CMC_E_INVALID_SESSION_ID

The specified session identifier is invalid or no longer valid (for example, after logging off).

CMC_E_INVALID_UI_ID

The specified user-interface identifier is invalid or no longer valid.

CMC_E_MESSAGE_IN_USE

The requested action cannot be completed at this time because the message is in use.

CMC_E_UNSUPPORTED_ACTION

The requested action is not supported by the current implementation.

CMC_E_UNSUPPORTED_FLAG

The flag requested is not supported.

CMC_E_UNSUPPORTED_FUNCTION_EXT

The function extension requested is not supported.

See Also

CMC_extension structure


 cmc_free

[New - Windows 95]

Frees memory allocated by the messaging system through another CMC function.

Syntax

CMC_return_code cmc_free (CMC_buffer memory)

Parameters

memory

Input parameter pointing to memory previously allocated by the message service through a CMC function. The cmc_free function ignores a parameter value of NULL. After this function completes, the pointer to memory is invalid, and the application cannot reference it again.

Return Values

CMC_E_FAILURE

There was a general failure that does not fit the description of any other return code.

CMC_E_INVALID_MEMORY

A memory pointer passed is invalid.

Comments

Results of the cmc_free function are unpredictable if your application calls it with a base pointer to a memory block not allocated by the message service, a base pointer to a memory block already freed, or a nonbase pointer to a complex structure written by another CMC function.

The CMC functions cmc_list, cmc_look_up, cmc_query_configuration, and cmc_read can provide your application with a base pointer to a complex structure containing several levels of pointers. Your application should free the entire structure or structure array by calling cmc_free with the base pointer.

See Also

cmc_list function, cmc_look_up function, cmc_query_configuration function, cmc_read function


 cmc_list

[New - Windows 95]

Lists summary information for messages that meet application-specified criteria.

Syntax

CMC_return_code cmc_list (CMC_session_id session, CMC_string message_type, CMC_flags list_flags, CMC_message_reference *seed, CMC_uint32 FAR *count,CMC_ui_id ui_id, CMC_message_result FAR * FAR *result, CMC_extension FAR *list_extensions)

Parameters

session

Input parameter containing an opaque session identifier that represents a MAPI session object indicating a session with the messaging system. If the session identifier is invalid, this function returns CMC_E_INVALID_SESSION_ID.

message_type

Input parameter pointing to the ASCII name of the type of message for which this function lists information. If the cmc_list function does not recognize the specified message type, it returns CMC_E_UNRECOGNIZED_MESSAGE_TYPE. If the function receives a value of NULL for the message type, it lists information for all available message types.

list_flags

Input parameter containing a bitmask of flags. The following flags can be set:

CMC_ERROR_UI_ALLOWED

Displays a dialog box on encountering recoverable errors. If this flag is not set, cmc_list does not display a dialog box and returns an error code instead.

CMC_LIST_COUNT_ONLY

Lists only a count of messages meeting the specified criteria, not any actual summary information. If this flag is not set, the function lists summary information in the array.

CMC_LIST_MSG_REFS_ONLY

Writes only message reference information to the array pointed to by the result parameter. If this flag is not set, cmc_list writes information to all members of the structures in the array.

CMC_LIST_UNREAD_ONLY

Lists unread messages only. If this flag is not set, the function can list both read and unread messages.

seed

Input parameter pointing to a message reference that identifies the message after which cmc_list should begin to search. A value of NULL for this parameter indicates that the function should start the search with the first message in the mailbox. A pointer to a message reference of length zero is invalid and causes cmc_list to return CMC_E_INVALID_MESSAGE_REFERENCE.

count

Input-output parameter containing a message count. On input, this parameter specifies a pointer to the maximum number of messages for which cmc_list should provide summary information. A value of zero specifies no maximum.

On output, the count parameter specifies the location to which cmc_list writes the number of messages for which it provides summary information. If no messages match the search criteria, or if the mailbox is empty, cmc_list writes zero.

ui_id

Input parameter containing the handle of a user interface for cmc_list to present to help resolve processing questions.

result

Output parameter pointing to the location to which cmc_list writes the address of the array of CMC_message_summary structures that it has written.

list_extensions

Input-output parameter pointing to an array of CMC_extension structures specifying function extensions. On input, this array contains MAPI extensions to the standard cmc_list function. A value of NULL for the list_extensions parameter indicates that the client application has no extensions for cmc_list and is expecting no extensions.

On output, cmc_list writes to the array new information about its processing of the message summaries. It writes NULL if it generates no output extensions.

Return Values

CMC_E_FAILURE

There was a general failure that does not fit the description of any other return code.

CMC_E_INSUFFICIENT_MEMORY

Insufficient memory was available to complete the requested operation.

CMC_E_INVALID_FLAG

A flag set using a flags parameter was invalid.

CMC_E_INVALID_MESSAGE_REFERENCE

The specified message reference is invalid or no longer valid (for example, it has been deleted).

CMC_E_INVALID_PARAMETER

A function parameter was invalid.

CMC_E_INVALID_SESSION_ID

The specified session identifier is invalid or no longer valid (for example, after logging off).

CMC_E_INVALID_UI_ID

The specified user-interface identifier is invalid or no longer valid.

CMC_E_UNRECOGNIZED_MESSAGE_TYPE

The specified message type is not supported by the current implementation.

CMC_E_UNSUPPORTED_FLAG

The flag requested is not supported.

CMC_E_UNSUPPORTED_FUNCTION_EXT

The function extension requested is not supported.

Comments

Your application can specify a cmc_list search to start with a certain message or to start at the beginning of the mailbox. It can also specify the maximum number of messages to list. The cmc_list function writes the summary information for the specified messages in an array of CMC_message_summary structures. Using the message references in these structures, the application can then make calls to the cmc_read and cmc_act_on functions for additional processing.

Before cmc_list writes message summary information, it must allocate memory for the structure array to contain the information. When this memory is no longer needed, your application should free the entire array with a call to the cmc_free function.

See Also

cmc_act_on function, CMC_extension structure, cmc_free function, CMC_message_summary structure, cmc_read function


 cmc_logoff

[New - Windows 95]

Logs a client application off a service provider.

Syntax

CMC_return_code cmc_logoff (CMC_session_id session, CMC_ui_id ui_id, CMC_flags logoff_flags, CMC_extension FAR *logoff_extensions)

Parameters

session

Input parameter containing an opaque session identifier that represents a MAPI session object indicating a session with the messaging system. If the session identifier is invalid, the cmc_logoff function returns CMC_E_INVALID_SESSION_ID. After cmc_logoff returns, the session identifier is invalid.

ui_id

Input parameter containing the handle of a user interface for cmc_logoff to present to help resolve processing questions.

logoff_flags

Input parameter containing a bitmask of flags. The following flags can be set:

CMC_ERROR_UI_ALLOWED

Displays a dialog box on encountering recoverable errors. If this flag is not set, cmc_logoff does not display a dialog box and returns an error code instead.

CMC_LOGOFF_UI_ALLOWED

Indicates cmc_logoff can display a user interface for other purposes than displaying error messages while logging the user off from the session.

logoff_extensions

Input-output parameter pointing to an array of CMC_extension structures containing function extensions. On input, this array contains MAPI extensions to the standard cmc_logoff function. A value of NULL for the logoff_extensions parameter indicates that the client application has no extensions for cmc_logoff and is expecting no extensions.

On output, cmc_logoff writes to the array new information about the logoff operation. It writes NULL if it generates no output extensions.

Return Values

CMC_E_FAILURE

There was a general failure that does not fit the description of any other return code.

CMC_E_INSUFFICIENT_MEMORY

Insufficient memory was available to complete the requested operation.

CMC_E_INVALID_FLAG

A flag set using a flags parameter was invalid.

CMC_E_INVALID_PARAMETER

A function parameter was invalid.

CMC_E_INVALID_SESSION_ID

The specified session identifier is invalid or no longer valid (for example, after logging off).

CMC_E_INVALID_UI_ID

The specified user-interface identifier is invalid or no longer valid.

CMC_E_UNSUPPORTED_FLAG

The flag requested is not supported.

CMC_E_UNSUPPORTED_FUNCTION_EXT

The function extension requested is not supported.

CMC_E_USER_NOT_LOGGED_ON

The user is not logged on and the CMC_LOGON_UI_ALLOWED flag is not set.

See Also

CMC_extension structure


 cmc_logon

[New - Windows 95]

Logs a client application onto a service provider.

Syntax

CMC_return_code cmc_logon (CMC_string service, CMC_string user, CMC_string password, CMC_object_identifier character_set, CMC_ui_id ui_id, CMC_uint16 caller_CMC_version, CMC_flags logon_flags, CMC_session_id FAR *session, CMC_extension FAR *logon_extensions)

Parameters

service

Input parameter pointing to the location of the service provider for the CMC implementation. Passing NULL for the service parameter indicates either that the client application is requesting logon to a service provider that does not require a service name, or that the client is requesting the CMC implementation's logon user interface.

user

Input parameter pointing to a MAPI profile name identifying the client application. Passing NULL for the user parameter indicates either that the client is requesting logon to a service provider that does not require a user name, or that the client is requesting the CMC implementation's user interface to prompt for a name.

password

Input parameter pointing to a MAPI profile password required for access to the CMC implementation. Passing NULL for the service parameter indicates either that the client is requesting logon to a service provider that does not require a password, or that the client is requesting the CMC implementation's user interface to prompt for a password.

character_set

Input parameter pointing to an object identifier for the character set used by the client application. The application can call the cmc_query_configuration function to retrieve the available values. The CMC implementation requires a non-null value for the character_set parameter.

ui_id

Input parameter containing the handle of a user interface for the cmc_logon function to present to help resolve processing questions or prompt for logon.

caller_CMC_ version

Input parameter containing the client application's CMC version number, multiplied by 100. For example, version 1 is specified as the integer 100.

logon_flags

Input parameter containing a bitmask of flags. The following flags can be set:

CMC_COUNTED_STRING_TYPE

Indicates the string type the calling application or provider uses for CMC interactions is length-first. If this flag is not set, the function treats all strings as null-terminated strings.

CMC_ERROR_UI_ALLOWED

Displays a dialog box on encountering recoverable errors. If this flag is not set, cmc_logon does not display a dialog box and returns an error instead.

CMC_LOGON_UI_ALLOWED

Displays a dialog box to prompt for logon if required. If this flag is not set, cmc_logon does not display a dialog box and returns an error if the user does not supply enough information.

session

Output parameter pointing to the location to which cmc_logon writes an opaque session identifier. This identifier represents a MAPI session object indicating a session with the messaging system.

logon_extensions

Input-output parameter pointing to an array of CMC_extension structures specifying function extensions. On input, this array contains MAPI extensions to the standard cmc_logon function. A value of NULL for the logon_extensions parameter indicates that the client application has no extensions for cmc_logon and is expecting no extensions.

On output, cmc_logon writes to the array new information about the logon operation. It writes NULL if it generates no output extensions.

Return Values

CMC_E_COUNTED_STRING_UNSUPPORTED

This implementation does not support the counted-string type.

CMC_E_FAILURE

There was a general failure that does not fit the description of any other return code.

CMC_E_INSUFFICIENT_MEMORY

Insufficient memory was available to complete the requested operation.

CMC_E_INVALID_FLAG

A flag set using a flags parameter was invalid.

CMC_E_INVALID_PARAMETER

A function parameter was invalid.

CMC_E_INVALID_UI_ID

The specified user-interface identifier is invalid or no longer valid.

CMC_E_LOGON_FAILURE

The service, user name, or password specified were invalid, so logon cannot be completed.

CMC_E_PASSWORD_REQUIRED

A password is required on this message service.

CMC_E_SERVICE_UNAVAILABLE

The service requested is unavailable.

CMC_E_UNSUPPORTED_CHARACTER_SET

The character set requested is not supported.

CMC_E_UNSUPPORTED_FLAG

The flag requested is not supported.

CMC_E_UNSUPPORTED_FUNCTION_EXT

The function extension requested is not supported.

CMC_E_UNSUPPORTED_VERSION

The version specified in the call cannot be supported by the current implementation.

Comments

The cmc_logon function can, at the client application's option, either prompt through a user interface or proceed without any user interaction. It writes a session identifier that the application can use in subsequent calls to the CMC implementation.

See Also

CMC_extension structure, cmc_query_configuration function


 cmc_look_up

[New - Windows 95]

Looks up addressing information in a directory provided by a specified service provider.

Syntax

CMC_return_code cmc_look_up (CMC_session_id session, CMC_recipient FAR *recipient_in, CMC_flags look_up_flags, CMC_ui_id ui_id, CMC_uint32 FAR *count, CMC_recipient FAR * FAR *recipient_out, CMC_extension FAR *look_up_extensions)

Parameters

session

Input parameter containing an opaque session identifier that represents a MAPI session object that represents a session with the messaging system. If the session identifier is invalid, the cmc_look_up function returns the CMC_E_INVALID_SESSION_ID error code .

recipient_in

Input parameter pointing to an array of CMC_recipient structures containing recipient data. The cmc_look_up function interprets the array depending on the flags that the client application has set using the look_up_flags parameter. Possible interpretations are as following:

•	If the application has set one of the flags for name resolution, cmc_look_up obtains the name to resolve from the name member of the first structure in the array. The function checks the corresponding name-type member to discover what resolution should be performed. The cmc_look_up function ignores all recipient structures except the first in the array.

•	If the application has set the CMC_LOOKUP_DETAILS_UI flag, the information in the array must resolve to only one recipient. If it does not, cmc_look_up returns CMC_E_AMBIGUOUS_RECIPIENT. The cmc_look_up function ignores all recipient structures except the first in the array.

•	If the application has set the CMC_LOOKUP_ADDRESSING_UI flag, cmc_look_up displays the recipients specified in the recipient array in the address-list user interface.

look_up_flags

Input parameter containing a bitmask of flags. The following flags can be set:

CMC_COUNTED_STRING_TYPE

Indicates the string type the calling application or provider uses for CMC interactions is length-first. If this flag is not set, the function treats all strings as null-terminated strings.

CMC_ERROR_UI_ALLOWED

Displays a dialog box on encountering recoverable errors. If this flag is not set, cmc_look_up does not display a dialog box and returns an error code instead.

CMC_LOGON_UI_ALLOWED

Displays a dialog box to prompt for logon if required. If this flag is not set, cmc_look_up does not display a dialog box and returns an error if the user does not supply enough information.

CMC_LOOKUP_ADDRESSING_UI

Displays a user interface to allow creation of a recipient list for addressing a message and general directory browsing. The recipient list passed to the function is the original recipient list for the user interface. The function returns the list of recipients created by the user. This flag is optional for implementations to support.

CMC_LOOKUP_DETAILS_UI

Displays a details user interface for the recipient pointed to in the recipient_in parameter. This user interface only acts on the first recipient in the list. If the recipient name indicated resolves to more than one address, cmc_look_up does not display the details user interface and returns the error CMC_E_AMBIGUOUS_RECIPIENT.

CMC_LOOKUP_RESOLVE_IDENTITY

Returns a recipient record for the identity of the current user of the messaging system. If no unique identity can be determined, the implementation carries out ambiguous name resolution to determine the address of the current user.

CMC_LOOKUP_RESOLVE_PREFIX_SEARCH

Indicates the search method should be prefix. In a prefix search, all names matching the prefix string, beginning at the first character of the name, are considered matches. If this flag is not set, the search method should be exact-match. CMC implementations must support simple prefix searching. The availability of wildcard or substring searches is optional.

CMC_LOOKUP_RESOLVE_UI

Attempts to resolve ambiguous names by presenting a name-resolution dialog box to the user. If this flag is not set, resolutions that do not result in a single name return the error CMC_E_AMBIGUOUS_RECIPIENT for services that must resolve to a single name. Services that can return multiple names return a list  as indicated by other function parameters. Support for this flag is optional.

ui_id

Input parameter containing the handle of a user interface for cmc_look_up to present to help resolve processing questions.

count

Input or output parameter containing a maximum name count. On input, this parameter specifies a pointer to the maximum number of names for which cmc_look_up can find addressing information. A value of zero specifies no maximum.

On output, the count parameter specifies the location to which cmc_look_up writes the number of names that it actually writes to the location indicated by the recipient_out parameter. If no names are written, cmc_look_up writes zero to the count parameter.

recipient_out

Output parameter pointing to the location to which cmc_look_up writes an array of one or more CMC_recipient structures containing addressing details for the recipients in the array passed in the recipient_in parameter.

look_up_extensions

Input-output parameter pointing to an array of CMC_extension structures specifying function extensions. On input, this array contains MAPI extensions to the standard cmc_look_up function. A value of NULL for the look_up_extensions parameter indicates that the client application has no extensions for cmc_look_up and is expecting no extensions.

On output, cmc_look_up writes to the array new information about the lookup operation. It writes NULL if it generates no output extensions.

Return Values

CMC_E_AMBIGUOUS_RECIPIENT

The recipient name is ambiguous. Multiple matches were found.

CMC_E_FAILURE

There was a general failure that does not fit the description of any other return code.

CMC_E_INSUFFICIENT_MEMORY

Insufficient memory was available to complete the requested operation.

CMC_E_INVALID_FLAG

A flag set using a flags parameter was invalid.

CMC_E_INVALID_PARAMETER

A function parameter was invalid.

CMC_E_INVALID_SESSION_ID

The specified session identifier is invalid or no longer valid (for example, after logging off).

CMC_E_INVALID_UI_ID

The specified user-interface identifier is invalid or no longer valid.

CMC_E_LOGON_FAILURE

The service, user name, or password specified were invalid, so logon cannot be completed.

CMC_E_NOT_SUPPORTED

The operation requested is not supported by the current implementation.

CMC_E_RECIPIENT_NOT_FOUND

One or more of the specified recipients were not found.

CMC_E_UNSUPPORTED_DATA_EXT

The data extension requested is not supported.

CMC_E_UNSUPPORTED_FLAG

The flag requested is not supported.

CMC_E_UNSUPPORTED_FUNCTION_EXT

The function extension requested is not supported.

CMC_E_USER_CANCEL

The operation was canceled by the user.

CMC_E_USER_NOT_LOGGED_ON

The user is not logged on and the CMC_LOGON_UI_ALLOWED flag is not set.

Comments

A client application calls the cmc_look_up function to resolve a display name to a messaging address or to prompt the user to choose among multiple resolved names. A client can also use this function to display a user interface for creation of recipient lists or to display recipient details.

The cmc_look_up function can write multiple addresses. Before it writes addressing information, it must allocate memory for the structure array to contain the information. When this memory is no longer needed, your application should free the entire array with a call to cmc_free.

See Also

CMC_extension structure, cmc_free function, CMC_recipient structure


 cmc_query_configuration

[New - Windows 95]

Determines configuration information for the installed CMC implementation.

Syntax

CMC_return_code cmc_query_configuration (CMC_session_id session, CMC_enum item, CMC_buffer reference, CMC_extension FAR *config_extensions)

Parameters

session

Input parameter containing an opaque session identifier that represents a MAPI session object indicating a session with the messaging system. If this parameter is set to zero, there is no session and the cmc_query_configuration function returns the default logon information to the buffer indicated by the reference parameter. If the session parameter is set to a nonzero value, cmc_query_configuration returns configuration information as determined by the session. If the value provided for the session parameter is invalid, cmc_query_configuration returns CMC_E_INVALID_SESSION_ID.

item

Input parameter containing an enumerated variable that identifies the configuration information required by the client application. The cmc_query_configuration function will write different pointers for reference depending on the value of the item parameter. Possible item values are:

CMC_CONFIG_CHARACTER_SET

Indicates the reference parameter should be a pointer to a CMC_object_identifier structure array. The cmc_query_configuration function returns a pointer to the array of object identifier strings that indicate character sets for the current implementation. The cmc_query_configuration function ends the array with a null CMC_object_identifier structure.The first object identifier in the array is the default character set used if the calling client application or service provider does not specify one explicitly. The calling client or provider uses this object identifier at logon to specify that the implementation use a different character set than the default.

CMC_CONFIG_DEFAULT_SERVICE

Indicates the reference parameter should be a pointer to a CMC_string data type. The cmc_query_configuration function writes a pointer to the default service name, if available, followed by a null character. The cmc_query_configuration function returns NULL if no default service name is available.

The calling client or provider can use this string, along with the one returned by CMC_CONFIG_DEFAULT_USER, as defaults when asking the user for the service name, user name, and password. The string is returned in the implementation default character set.

CMC_CONFIG_DEFAULT_USER

Indicates the reference parameter should be a pointer to a CMC_string data type, into which cmc_query_configuration returns a pointer to the default user name, if available, followed by a null character. The cmc_query_configuration function returns NULL if no default user name is available.The calling client or provider can use this string, along with the one returned by CMC_CONFIG_DEFAULT_SERVICE, as defaults when asking the user for the provider name, user name, and password. The string is returned in the implementation default character set.

CMC_CONFIG_LINE_TERM

Indicates the reference parameter should be a pointer to a CMC_enum variable, which is set to a value of CMC_LINE_TERM_CRLF if the line delimiter is a carriage return followed by a line feed, CMC_LINE_TERM_LF if the line delimiter is a line feed, or CMC_LINE_TERM_CR if the line delimiter is a carriage return.

CMC_CONFIG_REQ_PASSWORD

Indicates the reference parameter should be a pointer to a CMC_enum variable, which is set to a value of CMC_REQUIRED_NO if the password is not required to log on, CMC_REQUIRED_OPT if the password is optional to log on, or CMC_REQUIRED_YES if the password is required to log on.

CMC_CONFIG_REQ_SERVICE

Indicates the reference parameter should be a pointer to a CMC_enum variable, which is set to a value of CMC_REQUIRED_NO if the service name is not required to log on, CMC_REQUIRED_OPT if the service name is optional to log on, or CMC_REQUIRED_YES if the service name is required to log on.

CMC_CONFIG_REQ_USER

Indicates the reference parameter should be a pointer to a CMC_enum variable, which is set to a value of CMC_REQUIRED_NO if the user name is not required to log on, CMC_REQUIRED_OPT if the user name is optional to log on, or CMC_REQUIRED_YES if the user name is required to log on.

CMC_CONFIG_SUP_COUNTED_STR

Indicates the reference parameter should be a pointer to a CMC_boolean variable, which is set to TRUE if the CMC_COUNTED_STRING_TYPE flag is supported during logon.

CMC_CONFIG_SUP_NOMKMSGREAD

Indicates the reference parameter should be a pointer to a CMC_boolean variable, which will be set to TRUE if the cmc_read supports the CMC_DO_NOT_MARK_AS_READ flag.

CMC_CONFIG_UI_AVAIL

Indicates the reference parameter should be a pointer to a CMC_boolean variable, which will be set to TRUE if there is a user interface provided by the CMC implementation.

CMC_CONFIG_VER_IMPLEM

Indicates the reference parameter should be a pointer to a CMC_uint16 variable, which is set to the version number for the implementation, multiplied by 100. For example, version 1.01 returns 101.

CMC_CONFIG_VER_SPEC

Indicates the reference parameter should be a pointer to a CMC_uint16 variable, which is set to the CMC specification version number for the implementation, multiplied by 100. For example, version 1.00 returns 100.

reference

Output parameter pointing to the buffer to which cmc_query_configuration writes configuration information. The value of reference depends on the value of item, as previously described.

config_extensions

Input-output parameter pointing to an array of CMC_extension structures specifying function extensions. On input, this array contains MAPI extensions to the standard cmc_query_configuration function. A value of NULL for the config_extensions parameter indicates that the client application has no extensions for cmc_query_configuration and is expecting no extensions.

On output, cmc_query_configuration writes to the array new information about the query configuration operation. It writes NULL if it generates no output extensions.

Return Values

CMC_E_FAILURE

There was a general failure that does not fit the description of any other return code.

CMC_E_INSUFFICIENT_MEMORY

Insufficient memory was available to complete the requested operation.

CMC_E_INVALID_ENUM

A CMC_enum value is invalid.

CMC_E_INVALID_PARAMETER

A function parameter was invalid.

CMC_E_NOT_SUPPORTED

The operation requested is not supported by the current implementation.

CMC_E_UNSUPPORTED_FUNCTION_EXT

The function extension requested is not supported.

Comments

Your application must cast the reference parameter to the CMC_buffer type before calling cmc_query_configuration. The application must allocate sufficient memory to contain the information passed in the item parameter. When this memory is no longer needed, your application should free this memory with a call to the cmc_free function.

See Also

CMC_extension structure, cmc_free function, cmc_read function


 cmc_read

[New - Windows 95]

Reads a specified message.

Syntax

CMC_return_code cmc_read (CMC_session_id session, CMC_message_reference *message_reference, CMC_flags read_flags, CMC_message FAR * FAR *message, CMC_ui_id ui_id, CMC_extension FAR *read_extensions)

Parameters

session

Input parameter containing an opaque session identifier that represents a MAPI session object indicating a session with the messaging system. If the value provided for the session parameter is invalid, the cmc_read function returns CMC_E_INVALID_SESSION_ID.

message_reference

Input parameter pointing to a CMC_message_reference structure containing the message reference of the message to be retrieved. A NULL value for this parameter indicates that cmc_read should retrieve the first message in the mailbox. If the message reference is invalid, cmc_read returns CMC_E_INVALID_MESSAGE_REFERENCE.

read_flags

Input parameter containing a bitmask of flags. The following flags can be set:

CMC_DO_NOT_MARK_AS_READ

Does not mark messages as read when they are returned. This flag also suppresses sending of receipt reports. The calling client application or service provider can query the implementation to see if it supports this flag by passing the CMC_CONFIG_SUP_NOMKMSGREAD value in the cmc_query_configuration function.

CMC_ERROR_UI_ALLOWED

Displays a dialog box on encountering recoverable errors. If this flag is not set, cmc_read does not display a dialog box and returns an error code instead.

CMC_MSG_AND_ATT_HDRS_ONLY

Indicates that the attach_filename fields areundefined when cmc_read returns and that they should be ignored. The calling client or provider can be used to reduce the amount of data transferred. If clear, the attach_filename fields are returned as usual.Note that if the CMC_MSG_TEXT_NOTE_AS_FILE value is set in the message to indicate the first attachment contains the text note, cmc_read returns the attach_filename field for that attachment regardless of the setting of this flag.

CMC_READ_FIRST_UNREAD_MESSAGE

Returns the first message that is not marked as read. If this flag is not set, cmc_read should return the first message in the mailbox, whether it is marked as read or not. This flag can only be set when passing a null message reference to receive the first message in the mailbox.

message

Output parameter pointing to the location to which cmc_read writes the CMC_message structure containing the message it has read. The function writes attachment data in files, and the CMC_message structure indicates the names of those files in its attachments member. If the application has set the CMC_MSG_AND_ATT_HDRS_ONLY flag, the function does not indicate any attachment files.

ui_id

Input parameter containing the handle of a user interface for cmc_read to present to help resolve processing questions.

read_extensions

Input-output parameter pointing to an array of CMC_extension structures specifying function extensions. On input, this array contains MAPI extensions to the standard cmc_read function. A value of NULL for the read_extensions parameter indicates that the client application has no extensions for cmc_read and is expecting no extensions.

On output, cmc_read writes to the array new information about the read operation. It writes NULL if it generates no output extensions.

Return Values

CMC_E_ATTACHMENT_OPEN_FAILURE

The specified attachment was found but could not be opened, or the attachment file could not be created.

CMC_E_ATTACHMENT_READ_FAILURE

The specified attachment was found and opened, but there was an error reading it.

CMC_E_ATTACHMENT_WRITE_FAILURE

The attachment file was created successfully, but there was an error writing it.

CMC_E_DISK_FULL

Insufficient disk space was available to complete the requested operation (this can refer to local or shared disk space).

CMC_E_FAILURE

There was a general failure that does not fit the description of any other return code.

CMC_E_INSUFFICIENT_MEMORY

Insufficient memory was available to complete the requested operation.

CMC_E_INVALID_FLAG

A flag set using a flags parameter was invalid.

CMC_E_INVALID_MESSAGE_REFERENCE

The specified message reference is invalid or no longer valid (for example, it has been deleted).

CMC_E_INVALID_PARAMETER

A function parameter was invalid.

CMC_E_INVALID_SESSION_ID

The specified session identifier is invalid or no longer valid (for example, after logging off).

CMC_E_INVALID_UI_ID

The specified user-interface identifier is invalid or no longer valid.

CMC_E_TOO_MANY_FILES

The current implementation cannot support the number of files specified.

CMC_E_UNABLE_TO_NOT_MARK_READ

The CMC_DO_NOT_MARK_AS_READ flag cannot be supported.

CMC_E_UNSUPPORTED_FLAG

The flag requested is not supported.

CMC_E_UNSUPPORTED_FUNCTION_EXT

The function extension requested is not supported.

Comments

The cmc_read function only reads the first message in the mailbox if the application passes a null message-reference value.

After processing, cmc_read writes the data from the message into the CMC_message structure. Unless your application has set the flag CMC_DO_NOT_MARK_AS_READ on input, the message will be marked as read when cmc_read returns. If the application has set the input flag CMC_MSG_AND_ATT_HDRS_ONLY, cmc_read writes only message and attachment headers on output.

The cmc_read function can write multiple addresses. Before it writes message information, it must allocate memory for the structure to contain that information. When this memory is no longer needed, your application should free all structures in the array with a call to the cmc_free function.

See Also

CMC_extension structure, cmc_free function, CMC_message structure, CMC_message_reference structure, cmc_query_configuration function


 cmc_send

[New - Windows 95]

Sends a message.

Syntax

CMC_return_code cmc_send (CMC_session_id session, CMC_message FAR *message, CMC_flags send_flags, CMC_ui_id ui_id, CMC_extension FAR *send_extensions)

Parameters

session

Input parameter containing an opaque session identifier that represents a MAPI session object indicating a session with the messaging system. If the value provided for the session parameter is invalid, the cmc_send function returns the CMC_E_INVALID_SESSION_ID.

message

Input parameter pointing to a CMC_message structure identifying the message to be sent. If the application has not set the flag CMC_SEND_UI_REQUESTED in the send_flags parameter, the message structure must specify at least one primary, carbon-copy (CC), or blind carbon-copy (BCC) recipient. All other structure members are optional. The cmc_send function ignores the time_sent and message_reference members.

send_flags

Input parameter containing a bitmask of flags. The following flags can be set:

CMC_COUNTED_STRING_TYPE

Indicates the string type the calling application or provider uses for CMC interactions is length-first. If this flag is not set, the function treats all strings as null-terminated strings.

CMC_ERROR_UI_ALLOWED

Displays a dialog box on encountering recoverable errors. If this flag is not set, cmc_send does not display a dialog box and returns an error code instead.

CMC_LOGON_UI_ALLOWED

Displays a dialog box to prompt for logon if required. If this flag is not set, cmc_send does not display a dialog box and returns an error if the user does not supply enough information.

CMC_SEND_UI_REQUESTED

Displays a dialog box to prompt for recipients, message field information, and other sending options. If this flag is not set, cmc_send does not display a dialog box but must specify at least one recipient.

ui_id

Input parameter containing the handle of a user interface for cmc_send to present to help resolve processing questions, prompt the user for additional information, or verify provided information.

send_extensions

Input-output parameter pointing to an array of CMC_extension structures specifying function extensions. On input, this array contains MAPI extensions to the standard cmc_send function. A value of NULL for the send_extensions parameter indicates that the client application has no extensions for cmc_send and is expecting no extensions.

On output, cmc_send returns to the array new information about the send operation. It returns NULL if it generates no output extensions.

Return Values

CMC_E_AMBIGUOUS_RECIPIENT

The recipient name is ambiguous. Multiple matches were found.

CMC_E_ATTACHMENT_NOT_FOUND

The specified attachment was not found as specified.

CMC_E_ATTACHMENT_OPEN_FAILURE

The specified attachment was found but could not be opened, or the attachment file could not be created.

CMC_E_ATTACHMENT_READ_FAILURE

The specified attachment was found and opened, but there was an error reading it.

CMC_E_ATTACHMENT_WRITE_FAILURE

The attachment file was created successfully, but there was an error writing it.

CMC_E_COUNTED_STRING_UNSUPPORTED

This implementation does not support the counted-string type.

CMC_E_FAILURE

There was a general failure that does not fit the description of any other return code.

CMC_E_INSUFFICIENT_MEMORY

Insufficient memory was available to complete the requested operation.

CMC_E_INVALID_FLAG

A flag set using a flags parameter was invalid.

CMC_E_INVALID_MESSAGE_PARAMETER

One of the parameters in the message was invalid.

CMC_E_INVALID_PARAMETER

A function parameter was invalid.

CMC_E_INVALID_SESSION_ID

The specified session identifier is invalid or no longer valid (for example, after logging off).

CMC_E_INVALID_UI_ID

The specified user-interface identifier is invalid or no longer valid.

CMC_E_LOGON_FAILURE

The service, user name, or password specified were invalid, so logon cannot be completed.

CMC_E_RECIPIENT_NOT_FOUND

One or more of the specified recipients were not found.

CMC_E_TEXT_TOO_LARGE

The size of the text string passed to the current implementation is too large.

CMC_E_TOO_MANY_FILES

The current implementation cannot support the number of files specified.

CMC_E_TOO_MANY_RECIPIENTS

The current implementation cannot support the number of recipients specified.

CMC_E_UNSUPPORTED_DATA_EXT

The data extension requested is not supported.

CMC_E_UNSUPPORTED_FLAG

The flag requested is not supported.

CMC_E_UNSUPPORTED_FUNCTION_EXT

The function extension requested is not supported.

CMC_E_USER_CANCEL

The operation was canceled by the user.

CMC_E_USER_NOT_LOGGED_ON

The user is not logged on and the CMC_LOGON_UI_ALLOWED flag is not set.

Comments

The cmc_send function can, at the application's option, either use an interface, like a dialog box, to prompt the user for message creation or proceed without any user interaction. A successful return from this function does not necessarily imply recipient validation.

Your application can optionally provide recipient list, subject text, attachments, and note text for the message. If your application does not provide the required message elements, the cmc_send function can prompt the user for them if a user interface is available. If the application provides one or more recipients, the function can send the message without prompting the user. If the application provides optional parameters and requests a dialog box, the parameters provide the initial values for the dialog box.

The following conditions apply to the CMC_message structure members:

message_type

To specify an interpersonal message, use a pointer to the string "CMC:IPM". If your application provides a pointer value of NULL or a pointer to an empty string, cmc_send uses the default string CMC:IPM.

subject

A pointer value of NULL indicates no subject text.

text _note

A pointer value of NULL indicates no message text. If your application does pass a non-null value to indicate a text note that exceeds the limits of the service provider, the provider can demote the text to an attachment. Alternatively, it can cause cmc_send to return CMC_E_TEXT_TOO_LARGE.

recipients

A pointer value of NULL indicates no recipients. If your application passes a non-null value to indicate recipients in excess of the number of recipients that the service provider allows per message, cmc_send returns CMC_E_TOO_MANY_RECIPIENTS.

Note that the CMC_recipient structure pointed to by recipients can include either the recipient's name, an address, or a name and address pair. If your application specifies only a name, cmc_send resolves the name to an address using name resolution rules defined by the CMC implementation. If your application specifies only an address, cmc_send uses this address for delivery and for the recipient display name. Finally, if your application specifies a name and address pair, cmc_send does not resolve the name.

The cmc_send function does not require a recipient of type originator to send a message.

attachments

A pointer value of NULL indicates no attachments. If your application passes a non-null value to indicate attachments in excess of the number of attachments that the service provider allows per message, cmc_send returns CMC_E_TOO_MANY_FILES.

The cmc_send function reads the attachment files before it returns. Thus the user can freely change or delete attachment files without affecting the message.

message_flags

Bitmask of message flags. The following flag can be set:

CMC_MSG_TEXT_NOTE_AS_FILE

Indicates that the text_note member is ignored and the text note is contained in the file referred to by the first attachment. If this flag is clear, the text note is contained in the text_note member.

See Also

CMC_extension structure, CMC_message structure, CMC_recipient structure


 cmc_send_documents

[New - Windows 95]

Sends a document.

Syntax

CMC_return_code cmc_send_documents (CMC_string recipient_addresses, CMC_string subject, CMC_string text_note, CMC_flags send_doc_flags, CMC_string file_paths, CMC_string file_names, CMC_string delimiter, CMC_ui_id ui_id)

Parameters

recipient_addresses

Input parameter pointing to the address of the document recipient. When the application specifies multiple recipients, it should separate the strings using the character specified by the delimiter parameter. The cmc_send_documents function assumes a recipient to be a primary recipient unless the address is prefixed by CC: (carbon copy) or BCC: (blind carbon copy). The application can also use the prefix TO: for consistency. Passing NULL in the recipient_addresses parameter indicates that cmc_send_documents should present a dialog box to prompt for recipients.

subject

Input parameter pointing to the subject of the document. Passing NULL in the subject parameter indicates no subject text.

text_note

Input parameter pointing to the text note carried with the document. Passing NULL in the text_note parameter indicates no text note.

send_doc_flags

Input parameter containing a bitmask of flags controlling how documents are sent. The following flags can be set:

CMC_COUNTED_STRING_TYPE

Indicates the string type the calling application or provider uses for CMC interactions is length-first. If this flag is not set, the function treats all strings as null-terminated strings.

CMC_ERROR_UI_ALLOWED

Displays a dialog box on encountering recoverable errors. If this flag is not set, cmc_send_documents does not display a dialog box and returns an error code instead.

CMC_FIRST_ATTACH_AS_TEXT_NOTE

Sends the first attachment as the message text note. If not set, the text_note field contains the text note.

CMC_LOGON_UI_ALLOWED

Displays a dialog box to prompt for logon if required. If this flag is not set, cmc_send_documents does not display a dialog box and returns an error if the user does not supply enough information.

CMC_SEND_UI_REQUESTED

Displays a dialog box to prompt for recipients, message field information, and other sending options. If this flag is not set, cmc_send_documents does not display a dialog box but must specify at least one recipient.

file_paths

Input parameter pointing to the actual path name for the attachment file. When the application specifies multiple path names, it should separate the names using the character indicated by the delimiter parameter.

attach_titles

Input parameter pointing to the title of the attachment displayed for the recipient. When the application specifies multiple titles, it should separate the titles using the character indicated by the delimiter parameter.

delimiter

Input parameter pointing to a character used to delimit the names in the file_paths, attach_titles, and recipient_addresses strings. The application should choose a character that is not used in operating system filenames or recipient names. This parameter cannot be NULL.

ui_id

Input parameter containing the handle of a user interface for cmc_send_documents to present to help resolve processing questions or prompt the user for additional information as required.

Return Values

CMC_E_ATTACHMENT_NOT_FOUND

The specified attachment was not found as specified.

CMC_E_ATTACHMENT_OPEN_FAILURE

The specified attachment was found but could not be opened, or the attachment file could not be created.

CMC_E_ATTACHMENT_READ_FAILURE

The specified attachment was found and opened, but there was an error
reading it.

CMC_E_ATTACHMENT_WRITE_FAILURE

The attachment file was created successfully, but there was an error writing it.

CMC_E_COUNTED_STRING_NOT_SUPPORTED

CMC_E_FAILURE

There was a general failure that does not fit the description of any other return code.

CMC_E_INSUFFICIENT_MEMORY

Insufficient memory was available to complete the requested operation.

CMC_E_INVALID_FLAG

A flag set using a flags parameter was invalid.

CMC_E_INVALID_PARAMETER

A function parameter was invalid.

CMC_E_INVALID_UI_ID

The specified user-interface identifier is invalid or no longer valid.

CMC_E_LOGON_FAILURE

The service, user name, or password specified were invalid, so logon cannot be completed.

CMC_E_RECIPIENT_NOT_FOUND

One or more of the specified recipients were not found.

CMC_E_TEXT_TOO_LARGE

The size of the text string passed to the current implementation is too large.

CMC_E_TOO_MANY_FILES

The current implementation cannot support the number of files specified.

CMC_E_TOO_MANY_RECIPIENTS

The current implementation cannot support the number of recipients specified.

CMC_E_UNSUPPORTED_FLAG

The flag requested is not supported.

CMC_E_USER_CANCEL

The operation was canceled by the user.

CMC_E_USER_NOT_LOGGED_ON

The user is not logged on and the CMC_LOGON_UI_ALLOWED flag is not set.

Comments

The cmc_send_documents function is primarily useful for calls from a scripting language application, such as a spreadsheet application using macros, that cannot handle data structures. The cmc_send_documents function tries to establish a session without a logon user interface. If this is not possible, it prompts for logon information to establish a session. Before the function returns, it closes the session.


 CMC Structures and Simple Data Types

The following data structures and simple data types are used by the CMC implementation for passing information into and out of CMC functions. Wherever possible, you should use these types to maintain compatibility with different CMC implementations.


 BYTE

[New - Windows 95]

BYTE is an unsigned character data type for binary data.

Syntax

typedef unsigned char	BYTE;


 CMC_attachment

[New - Windows 95]

A CMC_attachment structure holds a CMC message attachment.

Syntax

typedef struct

{

CMC_string	attach_title;

CMC_object_identifier attach_type;

CMC_string	attach_filename;

CMC_flags attach_flags;

CMC_extension FAR	*attach_extensions;

} CMC_attachment;

Members

attach_title

Optional title for the attachment, for example the original filename of the attachment.

attach_type

Object identifier that specifies the attachment type. Two attachment types have been defined for use by client applications:

CMC_ATT_OID_BINARY

Indicates data in a file is treated as binary data. This attachment type is the default.

CMC_ATT_OID_TEXT

Indicates data in a file is treated as a text string. This attachment type assumes that data exists in the character set for the session on input and maps to the character set for the session on output, if possible.

A NULL value for attach_type designates an attachment of an undefined type.

attach_filename

Name of the file in which attachment content is located. The location of the file depends on the CMC implementation, which ensures access by the client application.

attach_flags

Bitmask of flags that describe attachment options. The following flags can be set:

CMC_ATT_APP_OWNS_FILE

Indicates on output that the application owns the attachment and is responsible for deleting it. This flag is ignored on input. If the flag is not set, it indicates on output that the CMC implementation owns the file and the application can only read it.

CMC_ATT_LAST_ELEMENT

Identifies the last structure in an array of CMC_attachment structures. The structure with this flag set must be at the end of the array. If this flag is clear for any structure, that structure is not the last array element.

attach_extensions

Pointer to the first CMC_extension structure in an array of per-attachment extensions.  A pointer value of NULL indicates that no extensions are present.

Comments

A CMC_message structure, which holds information about a CMC message, contains a pointer to an array of one or more CMC_attachment structures defining attachments for the message. The last attachment structure should have the CMC_ATT_LAST_ELEMENT flag set in its attach_flags member.

See Also

CMC_extension structure, CMC_message structure


 CMC_boolean

[New - Windows 95]

CMC_boolean is a CMC unsigned integer data type that is a Boolean value.

Syntax

typedef 	CMC_uint16 	CMC_boolean;

Comments

The CMC_boolean data type can hold the symbolic constants CMC_TRUE and CMC_FALSE. The C interface denotes FALSE by using 0 and TRUE by using any other integer. CMC denotes CMC_FALSE by 0, in line with C interface usage. However, CMC_TRUE specifically refers to the integer 1.


 CMC_buffer

[New - Windows 95]

CMC_buffer is a CMC data type that is a pointer to a memory storage location of an undefined type and size.

Syntax

typedef 	void *CMC_buffer;

Comments

The size of a void pointer is specific to the platform.


 CMC_counted_string

[New - Windows 95]

A CMC_counted_string structure is an optional structure that supports character sets that allow embedded null characters. The structure contains a counted string and explicitly defines the length of the string.

Syntax

typedef struct {

CMC_uint32	length;

char	 string[1];

} CMC_counted_string;

Members

length

Length, in bytes, of the string specified by the string member.

string

An array of characters that make up the string. CMC does not require the string to be null-terminated.

Comments

If a client application uses counted strings instead of null-terminated strings, it must set the CMC_COUNTED_STRING_TYPE flag in the cmc_logon function's logon_flags parameter when logging on to a MAPI session through cmc_logon. The data pointed to by a string of type CMC_string is then assumed to be defined as a CMC_counted_string structure.

To determine the character set of characters in a string, the CMC implementation looks at the session context. CMC implementations always attempt to map all strings passed to the client application to the character set for the session. If no session context has been created, CMC interprets the string by using its default character set.

See Also

CMC_string data type


 CMC_enum

[New - Windows 95]

CMC_enum is a CMC data type that is an enumerated data value.

Syntax

typedef 	CMC_sint32	CMC_enum;

Comments

A variable of this type contains a value selected from an enumeration.


 CMC_extension

[New - Windows 95]

A CMC_extension structure holds a CMC data extension for use by the CMC API functions and data structures. A CMC data extension adds parameters to functions or members to data structures.

Syntax

typedef struct {

CMC_uint32 item_code;

CMC_uint32 item_data;

CMC_buffer item_reference;

CMC_flags extension_flags;

} CMC_extension;

Members

item_code

Code that uniquely identifies extended functionality for a function or data structure. The item_code member is the dispatch mechanism for the extension that is invoked. The client application puts the extension code in this member before calling a CMC function. The possible extensions are:

CMC_X_COM_ATTACH_CHARPOS
CMC_X_COM_CAN_SEND_RECIP
CMC_X_COM_CONFIG_DATA
CMC_X_COM_PRIORITY
CMC_X_COM_RECIP_ID
CMC_X_COM_SAVE_MESSAGE
CMC_X_COM_SENT_MESSAGE
CMC_X_COM_SUPPORT_EXT
CMC_X_COM_TIME_RECEIVED
CMC_X_MS_ADDRESS_UI
CMC_X_MS_ATTACH_DATA
CMC_X_MS_FUNCTION_FLAGS
CMC_X_MS_MESSAGE_DATA
CMC_X_MS_SESSION_FLAGS

These extensions are identified by the extension identifier CMC_XC_COM. For definitions of these extensions, see CMC Data Extensions.

item_data

Item data for the extension. Depending on the value of item_code, the item_data member might hold the length of the item value, the item value itself, or other information about the item. The specification of the extension describes the interpretation of this member.

item_reference

Item reference for the extension. This value is a pointer to the storage location of the item value. It is NULL if there is no related item storage. The specification of the extension describes the interpretation of this member.

extension_flags

Bitmask of extension flags. The following flags can be set:

CMC_EXT_LAST_ELEMENT

Identifies the last structure in an array of CMC_extension structures. The structure with this flag set must be at the end of the array. If this flag is clear for any structure, that structure is not the last array element.

CMC_EXT_OUTPUT

Indicates for an output extension that the extension structure contains a pointer to implementation-allocated memory that the client application must release with the cmc_free function. If this flag is clear, the implementation has not allocated memory for the extension that the application needs to free. This flag is always clear for structure extensions.

CMC_EXT_REQUIRED

Indicates an error is returned if this extension cannot be supported. If this flag is clear, it enables the CMC implementation to provide any level of support, including no support, of the extension.

Comments

Extensions are used to add functionality to the CMC API. For example, a client application might implement the cmc_act_on function to allow saving a partially completed message in the receive folder (the Inbox) for later updating and sending. To pass the structure defining this partially completed message to CMC and receive back the resulting message reference, the application might use the CMC_X_COM_SAVE_MESSAGE extension.

An extension can be either an input extension or an output extension; that is, it can be passed either as input from a client application to CMC or as output from CMC to a client application. Whether the information contained in an extension is input or output is implied by the extension item code. For input extensions, the application in question allocates memory for the extension structure and any other structures associated with the extension. For output extensions, storage for the extension result, if necessary, is allocated by a CMC function.

For output extensions, a client application must free the allocated storage with a call to the cmc_free function. A client must call cmc_free once for each pointer returned in the item_reference member of every CMC_extension structure in the array.

CMC does not require explicit release of a data extension structure, because CMC releases such structures along with the structures that contains them. For example, CMC implicitly releases the message extension array created by the cmc_read function when calling cmc_free for the enclosing CMC_message message structure.

See Also

cmc_act_on function, cmc_free function, CMC_message structure, cmc_read function


 CMC_flags

[New - Windows 95]

CMC_flags is a CMC data type that is a bitmask of flags. These flags' meanings depend on the context in which the client application uses the flags.

Syntax

typedef	CMC_uint32	CMC_flags;

Comments

A bitmask of this type contains 32 flag bits. The CMC implementation reserves the upper 16 bits for definition by the CMC specification. Any unused bits among the upper 16 must be clear. The implementation reserves the lower 16 flag bits for definition by a CMC data extension.

The meanings of these CMC flags depend on the context in which the client application uses them. CMC reserves all undocumented flags. Unspecified flags should always be clear (that is, set to zero).


 CMC_message

[New - Windows 95]

A CMC_message structure holds information about a CMC message.

Syntax

typedef struct {

CMC_message_reference	*message_reference;

CMC_string	message_type;

CMC_string subject;

CMC_time	 time_sent;

CMC_string text_note;

CMC_recipient *recipients;

CMC_attachment	*attachments;

CMC_flags message_flags;

CMC_extension *message_extensions;

} CMC_message;

Members

message_reference

Pointer to the message reference, which is a counted string (that is, a CMC_counted_string structure). The message reference is a unique identifier for a message within a mailbox.

message_type

Pointer to a string that identifies the type of the message. Three different string identifiers are available:

•	Object identifiers, which are used for types identified by object identifiers, as defined in CCITT Recommendation X.208.

•	CMC registered values, which are used for types defined in the CMC specification.

•	Bilaterally defined values, which are used for types that are unregistered. CMC does not ensure that bilaterally defined values are unique.

For a complete list of CMC message types, see "Comments."

subject

Pointer to a string describing the subject of the message.

time_sent

CMC_time structure containing the date and time when the client application submits the message to the CMC implementation.

text_note

Pointer to the text note string of the message. If the value of this member is NULL, there is no text note. If the CMC_MSG_TEXT_NOTE_AS_FILE flag is set for the message_flags member, the text note is in the first attachment to the message. For information on text note format, see "Comments."

recipients

Pointer to the first CMC_recipient structure in an array of structures defining the message recipients.

attachments

Pointer to the first CMC_attachment structure in an array of structures defining the attachments to the message.

message_flags

Bitmask of message flags. The following flags can be set:

CMC_MSG_LAST_ELEMENT

Identifies the last structure in an array of CMC_message structures. The structure with this flag set must be at the end of the array. If this flag is clear for any structure, that structure is not the last array element.

CMC_MSG_READ

Indicates that the message has been read. If the flag is clear, the message has not been read.

CMC_MSG_TEXT_NOTE_AS_FILE

Indicates that the text_note member is ignored and the text note is contained in the file referred to by the first attachment. If this flag is clear, the text note is contained in the text_note member.

CMC_MSG_UNSENT

Indicates that the application has not sent the message, for example when the message is a draft. The sender can create such a message with the CMC_X_COM_SAVE_MESSAGE data extension. If this flag is clear, the application has sent the message.

message_extensions

Pointer to the first structure in an array of CMC_extension structures representing the message extensions.

Comments

 The format of each CMC message type possible in the message_type member is shown in the following syntax. In this syntax, white space can be any combination of tabs or spaces. An asterisk (*) indicates one or more of the denoted tokens (separated by white space) is valid. Strings within quotes are case-insensitive.

message_type_value	::= oid | cmc_reg | bilat_def

oid	::= "OID:" object_identifier

cmc_reg	::= "CMC:" cmc_registered_value

bilat_def	::= "BLT:" string

object_identifier	::= object_id_component*

object_id_component	::= integer

cmc_registered_value	::= "IPM"| "IP RN" | "IP NRN" | "DR" | "NDR"

The registered values provided for cmc_registered_value are defined as follows:

CMC: IPM

Interpersonal message. An interpersonal message is a memo-like message containing a recipient list, an optional subject, an optional text note, and zero or more attachments. The CMC_message structure is optimized to accommodate a message with the registered value IPM.

CMC: IP RN

Receipt notification for an interpersonal message. A receipt notification indicates the recipient has read a message.

CMC: IP NRN

Nonreceipt notification for an interpersonal message. A nonreceipt notification indicates a message has been removed from the recipient's mailbox without being read. For instance, the service or user has discarded the message or it has been automatically forwarded to another recipient.

CMC: DR

Delivery report. A delivery report indicates the service was able to deliver a message to its recipient.

CMC: NDR

Nondelivery report. A nondelivery report indicates the messaging service was not able to deliver a message to its recipient.

As the syntax preceding indicates, the oid type identifier indicates a type identified by object identifier, the cmc_reg type identifier indicates a type identified by a CMC registered value, and the bilat_def type identifier indicates a type identified by a bilaterally defined value. Following are examples of valid type identifiers:

OID: 1 2 840 113556 3 2 850

CMC: IPM

BLT: my special message type

Developers can format type identifiers as they want; the CMC implementation also defines a type identifier format that allows a client application to easily compare strings. The CMC implementation always returns type identifiers in this format, which does the following:

•	Separates all tokens with a whitespace.

•	Converts all white space to a single space.

•	Converts the type identifiers OID, CMC, and BLT to uppercase.

The CMC implementation does not define what it will do with type identifier strings that are not in this format.

The formats of messages with the preceding registered values within a CMC_message structure depend on the messaging protocols employed by the messaging system. Often, non-IPM messages take the form of a program-generated message, which follows a memo-like format similar to an IPM format but serves instead to convey information about a previously sent message.

Note  The CMC message types correspond to X.400 message types, but non-X.400 message services can use them. Thus, the CMC implementation applies these types generically.

Note that some implementations only support the interpersonal message type (CMC: IPM). Some implementations might treat messages of types other than IPM as IPM messages or might generate an error for such messages.

For the text_note member, the format of the text note is a sequence of paragraphs, whether it is passed in memory or in a file. Each paragraph is terminated with the appropriate line terminator for the platform: CR (carriage return) for Macintosh, LF (linefeed) for UNIX, and CR/LF for MS-DOS and Windows. The CMC implementation can word-wrap long lines (paragraphs). Note that there is no guaranteed format fidelity. For example, the CMC read functions can return a long paragraph as a series of shorter paragraphs.

See Also

CMC_attachment structure, CMC_extension structure, CMC_recipient structure, cmc_send function, CMC_time structure


 CMC_message_reference

[New - Windows 95]

A CMC_message_reference structure is a CMC_counted_string structure containing a message reference, which is the mailbox identifier for a message.

Syntax

typedef	CMC_counted_string	CMC_message_reference;

Comments

The CMC implementation only guarantees the message reference to be valid for the life of the session. The message reference is specific to the mailbox; CMC does not guarantee that the reference has any correspondence to a message identifier used by the messaging system. At any time during the current session, the client application can copy the message reference.


 CMC_message_summary

[New - Windows 95]

A CMC_message_summary structure holds a CMC message summary

Syntax

typedef struct {

CMC_message_reference	*message_reference;

CMC_string	message_type;

CMC_string	subject;

CMC_time	 time_sent;

CMC_uint32	byte_length;

CMC_recipient	*originator;

CMC_flags	summary_flags;

CMC_extension	*message_summary_extensions;

} CMC_message_summary;

Members

message_reference

Pointer to the message reference, a CMC_counted_string structure containing the mailbox identifier for a message. The message reference is unique within a mailbox.

message_type

Pointer to a string that identifies the type of the message. See CMC_message for details.Three different string identifiers are available:

•	Object identifiers, which are used for types identified by object identifiers, as defined in CCITT Recommendation X.208.

•	CMC registered values, which are used for types defined in the CMC specification.

•	Bilaterally defined values, which are used for types that are unregistered. CMC does not ensure that bilaterally defined values are unique.

subject

Pointer to a string describing the subject of the message.

time_sent

CMC_time structure containing the date and time when the client application submits the message to the CMC implementation.

byte_length

Message size, in bytes. The value should include the size of all the associated features of the message — attachments, envelope and heading fields, and so on. A client application can supply an approximate message size or, if the message size is unknown or unavailable, the value CMC_LENGTH_UNKNOWN.

originator

Pointer to a CMC_recipient structure indicating the message sender.

summary_flags

Bitmask of message summary flags. The following flags can be set:

CMC_SUM_LAST_ELEMENT

Identifies the last structure in an array of CMC_message_summary structures. The structure with this flag set must be at the end of the array. If this flag is clear for any structure, that structure is not the last array element.

CMC_SUM_READ

Indicates that the message has been read. If the flag is clear, the message has not been read.

CMC_SUM_UNSENT

Indicates that the application has not sent the message, for example when the message is a draft. If this flag is clear, the application has sent the message.

message_summary_extensions

Pointer to the first structure in an array of CMC_extension structures representing the message-summary data extensions, if any.

See Also

CMC_extension structure


 CMC_object_identifier

[New - Windows 95]

CMC_object_identifier is a data type that is a CMC object identifier string.

Syntax

typedef	CMC_string	CMC_object_identifier;

Comments

An identifier of this type is globally unique. Its syntax must match the number form defined in CCITT Recommendation X.208. This syntax is:

object_identifier	::= object_id_component*

object_id_component	::= integer

The following is an example of an object identifier:

1 2 840 113556 3 2 850

Note  The format of the object identifier string is the same as that used in the OID message type. For more information on message types, see the reference entry for the CMC_message structure.

See Also

CMC_message structure


 CMC_recipient

[New - Windows 95]

A CMC_recipient structure holds information about a messaging user, either a message recipient or the message sender.

Syntax

typedef struct {

CMC_string	name;

CMC_enum	 name_type;

CMC_string	address;

CMC_enum role;

CMC_flags recip_flags;

CMC_extension *recip_extensions;

} CMC_recipient;

Members

name

Pointer to a string that identifies the recipient or sender display name. When the CMC implementation resolves the name to an address, it determines whether it should interpret the name as the name of an individual first and then as the name of a group if the individual name is not found, or vice versa.

name_type

Enumeration that indicates whether the structure holds information for a message recipient or a message sender. Enumeration possibilities include:

CMC_TYPE_GROUP

Indicates the recipient or sender name belongs to a distribution list.

CMC_TYPE_INDIVIDUAL

Indicates the recipient or sender name belongs to an individual messaging user.

CMC_TYPE_UNKNOWN (0)

Indicates an unknown recipient or originator name.

The name_type member is meaningful only if the name member is present. The CMC implementation sets name_type on output. On input, the name_type information can be used to optimize resolution of the name.

address

Pointer to a recipient or sender address string in a format recognized by the messaging system. CMC does not define the format of the string. This member therefore accommodates any string notations supported by the CMC implementation, as configured at installation.

role

Enumeration that indicates the role of the message recipient or sender. Enumeration possibilities include:

CMC_ROLE_AUTHORIZING_USER

Indicates the authorizing user of the message.

CMC_ROLE_BCC

Indicates a blind carbon copy (BCC) recipient.

CMC_ROLE_CC

Indicates a carbon copy (CC) recipient.

CMC_ROLE_ORIGINATOR

Indicates the sender of the message.

CMC_ROLE_TO

Indicates a primary recipient.

recip_flags

Bitmask of recipient flags. The following flags can be set:

CMC_RECIP_IGNORE

Indicates the messaging system should ignore the specified recipient. This flag is useful for reusing an incoming message's recipient list for a reply. If this flag is clear, it indicates that the recipient should not be ignored.

CMC_RECIP_LAST_ELEMENT

Identifies the last structure in an array of CMC_recipient structures. The structure with this flag set must be at the end of the array. If this flag is clear for any structure, that structure is not the last array element.

CMC_RECIP_LIST_TRUNCATED

Indicates that the messaging system has not written all recipient or originator structures requested. The client application uses this flag only for the cmc_look_up function when the complete list of recipients matching the search name cannot be written. The function only sets this flag in the last structure in the array of CMC_recipient structures. If the flag is clear, cmc_look_up has written a complete recipient array.

recip_extensions

Pointer to the first structure in an array of CMC_extension structures that hold the recipient or sender data extensions, if any.

Comments

If a message service does not support carbon copy recipients, it can convert such a recipient to a primary recipient. Services that cannot support blind carbon-copy recipients should reject associated messages. If a user designates the same recipient in more than one role, the message service requires multiple recipient entries, each differing from the others in role.

On output, the CMC implementation writes an array of CMC_recipient structures in a certain order. The message sender's structure should be the first element in the array, followed by the primary, carbon copy, and blind carbon-copy recipient structures grouped together in that order. If there is an authorizing user structure, it should be the final element in the array. The CMC implementation does not require ordering of the CMC_recipient structures on input.

See Also

CMC_extension structure, cmc_look_up function


 CMC_return_code

[New - Windows 95]

CMC_return_code is a data type that is a 32-bit value that a CMC function returns.

Syntax

typedef	 CMC_uint32	CMC_return_code;

Comments

A nonzero return value for a CMC function indicates an error and is associated with one of the defined CMC return codes. A return value of zero for a function indicates success. The CMC implementation reserves values in the low-order 16 bits of the return code for standard CMC-defined error codes. The CMC implementation reserves values in the high-order 16 bits for error codes that it defines specifically.

CMC client applications can resolve errors within the scope of the CMC implementation. For example, an application can resolve errors by prompting the user with a dialog box defined through the CMC user interface. If the error remains unresolved after the dialog box has closed, CMC sets the CMC_ERROR_UI_DISPLAYED flag in the error to indicate that a dialog box regarding the error has already been displayed.


 CMC_session_id

[New - Windows 95]

CMC_session_id is a data type that is a 32-bit CMC session identifier.

Syntax

typedef 	uint32	CMC_session_id;

Comments

The context identified by the session identifier contains per-session information, such as the character set in use and handles for any open sessions with underlying message services. The cmc_logon function creates the CMC session identifier, and the cmc_logoff function deletes it.

See Also

cmc_logoff function, cmc_logon function


 CMC_string

[New - Windows 95]

CMC_string is a CMC data type that is a pointer to a character string.

Syntax

typedef	 char 	*CMC_string;

Comments

By default, the CMC implementation interprets the string that this data type points to as a null-terminated array of characters. The chosen character set determines the width of a character and the corresponding null-terminating character.

If a client application uses counted strings instead of null-terminated strings, it must set the CMC_COUNTED_STRING_TYPE flag in the logon_flags parameter when logging onto a MAPI session through cmc_logon. The data pointed to by a string of type CMC_string is then defined as a CMC_counted_string structure.

To determine the character set of characters in the string, the CMC implementation looks at the session context. CMC always attempts to map all strings passed to the client application to the character set for the session. If there is no session context created before the client application call, the CMC implementation interprets the string by using its default character set.

See Also

CMC_counted_string structure, cmc_logon function


 CMC_time

[New - Windows 95]

A CMC_time structure holds a time value in CMC-compatible form for use in a message.

Syntax

typedef struct{

CMC_sint8	second;

CMC_sint8	minute;

CMC_sint8	hour;

CMC_sint8	day;

CMC_sint8	month;

CMC_sint8	year;

CMC_sint8	isdst;

CMC_sint8 	unused1;

CMC_sint16	tmzone;

CMC_sint16	unused2;

} CMC_time;

Members

second

Seconds; possible values range from 0 through 59.

minute

Minutes; possible values range from 0 through 59.

hour

Hours since midnight; possible values range from 0 through 23.

day

Day of the month; possible values range from 1 through 31.

month

Months since January; possible values range from 0 through 11.

year

Years since 1900.

isdst

Value for daylight savings time. A nonzero value means daylight savings time is in force.

unused1

Reserved. Do not use.

tmzone

Time zone, measured in minutes relative to Greenwich mean time. The value CMC_NO_TIMEZONE indicates that time zone information is not available.

unused2

Reserved. Do not use.

Comments

The CMC time implementation is based on the assumption that all time values reflect the appropriate local time. For example, the time_sent members in the CMC_message and CMC_message_summary structures reflect the local time of the sender's location.

See Also

CMC_message structure, CMC_message_summary structure


 CMC_ui_id

[New - Windows 95]

CMC_ui_id is a data type that is a CMC user interface handle.

Syntax

typedef CMC_uint32	CMC_ui_id;

Comments

The CMC implementation uses a data value of this type for passing user interface information to CMC functions. For example, in a Windows-based environment, the parent window handle for the client application is a data value of this type.

A value of NULL for CMC_ui_id is always valid. The CMC implementation defines appropriate default behavior.


 CMC_X_COM_configuration

[New - Windows 95]

A CMC_X_COM_configuration structure holds configuration data written by the cmc_query_configuration function for the CMC_X_COM_CONFIG_DATA data extension.

Syntax

typedef struct {

CMC_uint16	ver_spec;

CMC_uint16	ver_implem;

CMC_object_identifier	*character_set;

CMC_enum	line_term;

CMC_string	default_service;

CMC_string	default_user;

CMC_enum	req_password;

CMC_enum	req_service;

CMC_enum	req_user;

CMC_boolean	ui_avail;

CMC_boolean	sup_nomkmsgread;

CMC_boolean	sup_counted_str;

} CMC_X_COM_configuration;

Members

ver_spec

CMC specification version number.

ver_implem

CMC version number multiplied by 100. For example, version 1.00 is represented as 100.

character_set

Pointer to a CMC_object_identifier structure.

line_term

Enumerated value that indicates the type of line delimiter for the message.

default_service

Pointer to a string identifying the default message service.

default_user

Pointer to a string identifying the default user name.

req_password

Enumerated value that indicates if a password is required.

req_service

Enumerated value that indicates if the message service name is required for logon.req_user

Enumerated value that indicates if the messaging user name is required for logon.ui_avail

Boolean value that is TRUE if the CMC implementation in use provides a user interface and FALSE otherwise.

sup_nomkmsgread

Boolean value that is TRUE if the cmc_read function supports the CMC_DO_NOT_MARK_AS_READ flag and FALSE otherwise.

sup_counted_str

Boolean value that is TRUE if the cmc_logon function supports the CMC_COUNTED_STRING_TYPE flag and FALSE otherwise.

Comments

 The definition for each of the structure members corresponds to the data that the cmc_query_configuration function writes to its reference parameter for the corresponding value of its item parameter. The client application can free the CMC_X_COM_configuration structure with one call to the cmc_free function.

See Also

cmc_free function, cmc_logon function, CMC_object_identifier data type, cmc_query_configuration function, cmc_read function, CMC_X_COM_CONFIG_DATA extension


 CMC_X_COM_support

[New - Windows 95]

A CMC_X_COM_support structure holds information about MAPI support for a particular CMC data extension or extension set.

Syntax

typedef struct {

CMC_uint32 item_code;

CMC_flags flags;

} CMC_X_COM_support;

Members

item_code

Code for the CMC data extension whose support the application is querying about. The client application sets this member to the item code of the extension the application is querying during a call to the cmc_logon function. The possible extensions are:

CMC_X_COM_ATTACH_CHARPOS
CMC_X_COM_CAN_SEND_RECIP
CMC_X_COM_CONFIG_DATA
CMC_X_COM_PRIORITY
CMC_X_COM_RECIP_ID
CMC_X_COM_SAVE_MESSAGE
CMC_X_COM_SENT_MESSAGE
CMC_X_COM_SUPPORT_EXT
CMC_X_COM_TIME_RECEIVED
CMC_X_MS_ADDRESS_UI
CMC_X_MS_ATTACH_DATA
CMC_X_MS_FUNCTION_FLAGS
CMC_X_MS_MESSAGE_DATA
CMC_X_MS_SESSION_FLAGS

flags

Bitmask of extension code flags. The following flags can be set:

 CMC_X_COM_SUPPORTED

Indicates the CMC implementation supports this extension. For extension sets, this flag indicates the CMC implementation supports the required function and structure extensions in the set.

CMC_X_COM_NOT_SUPPORTED

Indicates the CMC implementation does not support this extension. If this flag applies to an extension set containing both function and structure extensions, it indicates the CMC implementation does not support some function and structure extensions in the set. If this flag applies to a structure extension or an extension set containing structure extensions, it indicates the CMC implementation will not attach the structure extensions to structures for the current session.

CMC_X_COM_DATA_EXT_SUPPORTED

Indicates the CMC implementation supports all required structure extensions for an extension set, but not all required function extensions. If cmc_logon sets this flag, which applies to extension sets only, as opposed to individual extensions.

CMC_X_COM_FUNC_EXT_SUPPORTED

Indicates the CMC implementation supports all required function extensions for a set, but not all required structure extensions. The client application must explicitly request them.

See Also

CMC_extension structure, cmc_logon function, CMC_X_COM_SUPPORT_EXT extension


 LONG

[New - Windows 95]

LONG is a data type that is a 32-bit signed integer.

Syntax

typedef long	LONG;


 CMC Data Extensions

The functionality of the CMC data structures and functions can be augmented through the use of CMC data extensions. Data extensions are used to add additional fields to data structures and additional parameters to a function.

A standard generic data structure, CMC_extension, specifies the item code, item data, item reference, and a set of flags. The item code is the name of the extension and is used to identify it. The item data, depending on the item code, holds either the length of the item value, the item value itself, or other information about the item. The item reference points to where the extension value is stored or is NULL if there is no related item storage. The flags are set to zero or to values that describe options for the extension. To use an extension in a CMC function, a client application sets the item code member of a CMC_extension structure to a valid name and passes the structure as part of the parameter list.

Extensions that are additional parameters to a function can be either input or output parameters. If the extension is passed as an input parameter, the calling client application or service provider allocates memory for the CMC_extension structure and any other structures that are associated with the extension. If the extension is passed as an output parameter, CMC allocates the storage for the extension result and the caller frees it by calling the cmc_free function.

This section documents the CMC common extension set, the extensions that are common to most message services but are not in the CMC base specification. The extensions are listed in alphabetical order. Each reference entry describes the purpose of the extension.


 CMC_X_COM_ATTACH_CHARPOS

[New - Windows 95]

CMC_X_COM_ATTACH_CHARPOS is a CMC extension that supports display of a representation of a graphical attachment in message text note. The extension holds the character position for the representation.

Input Usage

item_data

Zero-based character offset of the attachment within the message text. Note that this offset is a character offset, not a byte offset (an important distinction when multibyte character sets are in use).

item_reference

NULL.

extension_flags

All flags used with the CMC_extension structure are valid. No further flags are defined.

Output Usage

item_data

Zero-based character offset of the attachment.

item_reference

Unchanged.

extension_flags

Unchanged.

Adds to

The CMC_attachment structure

Comments

At logon, CMC passes the CMC_X_COM_ATTACH_CHARPOS code and any flags in a CMC_X_COM_support structure. Doing so indicates that CMC supports the corresponding extension and that the client application can attach the extension to the CMC_attachment structure during the session.

See Also

CMC_attachment structure, CMC_extension structure, CMC_X_COM_support structure


 CMC_X_COM_CAN_SEND_RECIP

[New - Windows 95]

CMC_X_COM_CAN_SEND_RECIP is a CMC extension that checks whether the message service is ready to send to the specified recipient.

Input Usage

item_data

Zero.

item_reference

NULL. On input, the cmc_look_up function's recipient_inparameter contains the recipient about which the message service is being queried. If there is more than one recipient passed in recipient_in, cmc_look_up only looks at the first recipient.

extension_flags

All flags used with the CMC_extension structure are valid. No further flags are defined.

Output Usage

item_data

Bitmask of extension flags. The following flags can be set:

CMC_X_COM_DEFER

Indicates the message service will accept the message but defer it until a transport provider is ready.

CMC_X_COM_NOT_READY

Indicates no transport provider is available for the specified recipient type.

CMC_X_COM_READY

Indicates the message can be sent immediately.

item_reference

Unchanged.

extension_flags

Unchanged.

Adds to

The cmc_look_up function

See Also

CMC_extension structure, cmc_look_up function


 CMC_X_COM_CONFIG_DATA

[New - Windows 95]

CMC_X_COM_CONFIG_DATA is a CMC extension that obtains all available configuration information.

Input Usage

item_data

Zero.

item_reference

NULL.

extension_flags

All flags used with the CMC_extension structure are valid. No further flags are defined.

Output Usage

item_data

Unchanged.

item_reference

Pointer to a CMC_X_COM_configuration structure containing all the information available from the cmc_query_configuration function.

extension_flags

Bitmask of extension flags. If the call successfully returns a structure, the function sets the flagCMC_EXT_OUTPUT.

Adds to

The cmc_query_configuration function

See Also

CMC_extension structure, cmc_query_configuration function, CMC_X_COM_configuration structure


 CMC_X_COM_PRIORITY

[New - Windows 95]

CMC_X_COM_PRIORITY is a CMC extension indicating message priority.

Input Usage

item_data

Bitmask of extension flags. The following flags can be set:

CMC_X_COM_LOW

Indicates low message priority.

CMC_X_COM_NORMAL

Indicates a normal priority for the message.

CMC_X_COM_URGENT

Indicates high message priority.

item_reference

NULL.

extension_flags

All flags used with the CMC_extension structure are valid. No further flags are defined.

Output Usage

item_data

Bitmask of extension flags that describe the urgency of the message. The following flags can be set:

CMC_X_COM_LOW

Indicates low message priority.

CMC_X_COM_NORMAL

Indicates a normal priority for the message.

CMC_X_COM_URGENT

Indicates high message priority.

item_reference

Unchanged.

extension_flags

Unchanged.

Adds to

The CMC_message and CMC_message_summary structures

Comments

At logon, the CMC implementation passes CMC_X_COM_PRIORITY in the item_code member of a CMC_X_COM_support structure to indicate that the extension should be attached to the CMC_message structure during the session.

See Also

CMC_extension structure, CMC_message structure, CMC_message_summary structure, CMC_X_COM_support structure


 CMC_X_COM_RECIP_ID

[New - Windows 95]

CMC_X_COM_RECIP_ID is a CMC extension that adds a unique recipient identifier to a CMC_recipient structure for the recipients of a message.

Input Usage

item_data

Length of the recipient identifier.

item_reference

Pointer to the CMC_recipient structure holding the recipient identifier.

extension_flags

All flags used with the CMC_extension structure are valid. No further flags are defined.

Output Usage

item_data

Length  of the recipient identifier.

item_reference

Pointer to the CMC_recipient structure holding the recipient identifier.

extension_flags

Unchanged.

Adds to

The CMC_recipient structure

Comments

The CMC implementation handles the CMC_X_COM_RECIP_ID extension during recipient name resolution. The client application can use this to avoid further name resolution during sending in some message services. In this way the client application can reuse the recipient identifier returned by a previous call to cmc_look_up by attaching it to a recipient structure that the message service would otherwise try to resolve.

At logon, the client application passes the CMC_X_COM_RECIP_ID item_code in the CMC_X_COM_SUPPORT_EXT array  to indicate that the CMC implementation should attach recipent identifiers to CMC_recipient structures during the session.

See Also

CMC_extension structure, CMC_recipient structure, CMC_X_COM_support structure


 CMC_X_COM_SAVE_MESSAGE

[New - Windows 95]

CMC_X_COM_SAVE_MESSAGE is a CMC extension that saves a message (that is, a CMC_message structure) to the receive folder (the Inbox).

Input Usage

item_data

Zero.

item_reference

Pointer to the CMC_message structure to save to the receive folder. To indicate that an unsent message has not been sent, the CMC implementation sets the CMC_MSG_UNSENT flag in this structure. To indicate that the operation to be performed is contained in a CMC_X_COM_SAVE_MESSAGE extension, the cmc_act_on function's operation parameter must be set to the CMC_ACT_ON_EXTENDED flag.

extension_flags

All flags used with the CMC_extension structure are valid. No further flags are defined. To indicate that the CMC implementation should carry out a save action rather than a deletion, the flag CMC_EXT_REQUIRED must be set.

Output Usage

item_data

Unchanged.

item_reference

Pointer to the message reference of the message saved to the receive folder (the Inbox). The client application must free this pointer using the cmc_free function.

extension_flags

If cmc_act_on has successfully saved the message and returned the message reference, the CMC_EXT_OUTPUT flag is set.

Adds to

The cmc_act_on function

See Also

cmc_act_on function, CMC_extension structure, CMC_message structure, CMC_message_reference structure


 CMC_X_COM_SENT_MESSAGE

[New - Windows 95]

CMC_X_COM_SENT_MESSAGE is a CMC extension that creates a CMC_message structure containing information for the message just sent.

Input Usage

item_data

Zero.

item_reference

NULL.

extension_flags

All flags used with the CMC_extension structure are valid. No further flags are defined.

Output Usage

item_data

Unchanged.

item_reference

Pointer to a CMC_message structure containing information for the message just sent. The client application must free this pointer by calling the cmc_free function.

extension_flags

If the item_reference parameter contains a pointer to a message, the CMC_EXT_OUTPUT flag is set.

Adds to

The cmc_send function

Comments

CMC_X_COM_SAVE_MESSAGE is used to obtain information when the CMC_message structure is set by CMC rather than by the client application.

See Also

CMC_extension structure, cmc_free function, CMC_message structure, cmc_send function


 CMC_X_COM_SUPPORT_EXT

[New - Windows 95]

CMC_X_COM_SUPPORT_EXT is a CMC extension that client applications use to query the CMC implementation about the extensions it supports. If the implementation supports any extensions, it must support CMC_X_COM_SUPPORT_EXT.

Input Usage

item_data

Count of items in an array pointed to by item_reference.

item_reference

Pointer to the first element in an array of CMC_X_COM_support structures listing extensions the application requests the CMC implementation to support. The flag for the structures used on input is CMC_X_COM_SUP_EXCLUDE, defined for CMC_X_COM_support.

extension_flags

All flags used with CMC are valid. No further flags are defined.

Output Usage

item_data

Unchanged.

item_reference

The CMC implementation sets the flags in the structures to indicate support for the extension. The implementation does not set these flags if CMC_X_COM_SUP_EXCLUDE was set on input.

extension_flags

Unchanged.

Adds to

cmc_query_configuration, cmc_logon

Comments

Client applications can use this extension before establishing a session to get preliminary information about support before logging on. When an application uses the extension with cmc_logon, it indicates which data extensions the client wants added to the data structures for the session.

Note  The CMC implementation supports different extensions, based on the service with which the client application creates a session. Thus client applications should use CMC_X_COM_SUPPORT_EXT at logon to verify extension support.

See Also

CMC_extension structure, cmc_logon function, cmc_query_configuration function, CMC_X_COM_support structure


 CMC_X_COM_TIME_RECEIVED

[New - Windows 95]

CMC_X_COM_TIME_RECEIVED is a CMC extension that provides a CMC_time structure that holds the delivery time of a message.

Input Usage

CMC ignores this extension on input.

Output Usage

item_data

Zero.

item_reference

Pointer to the CMC_time structure that holds the time the message was received.

extension_flags

NULL.

Adds to

The CMC_message and CMC_message_summary structures

Comments

At logon, the CMC implementation passes the CMC_X_COM_TIME_RECEIVED extension in the item_code member of a CMC_X_COM_support structure to indicate that the extension should be attached to the CMC_message and CMC_message_summary structures during the session.

See Also

CMC_extension structure, CMC_message structure, CMC_message_summary structure, CMC_time structure, CMC_X_COM_support structure


 CMC_X_MS_ADDRESS_UI

[New - Windows 95]

CMC_X_MS_ADDRESS_UI is a CMC extension that adds options to the address-book dialog box.

Input Usage

item_data

Number of edit boxes in the dialog box.

item_reference

Pointer to an array of two strings that are the caption for the address-book dialog box To not provide a label, the client application sets the label string to NULL. and the label for the recipient box if there is only one recipient list.

extension_flags

All flags used with the CMC_extension structure are valid. No further flags are defined.

Output Usage

item_data

Unchanged.

item_reference

Unchanged.

extension_flags

Unchanged.

Adds to

The cmc_look_up function

See Also

CMC_extension structure, cmc_look_up function


 CMC_X_MS_ATTACH_DATA

[New - Windows 95]

CMC_X_MS_ATTACH_DATA is a CMC extension that holds bitmasks of flags used to provide data on message attachments.

Input Usage

item_data

Bitmask of attachment flags. The following flags can be set:

CMC_X_MS_ATTACH_OLE

Indicates the CMC implementation supports OLE attachments.

CMC_X_MS_ATTACH_OLE_STATIC

Indicates the CMC implementation supports static OLE attachments.

item_reference

Unchanged.

extension_flags

All flags used with the CMC_extension structure are valid. No further flags are defined.

Output Usage

item_data

Bitmask of attachment flags. The messaging system can set the following flags:

CMC_X_MS_ATTACH_OLE

Indicates the CMC implementation supports OLE attachments.

CMC_X_MS_ATTACH_OLE_STATIC

Indicates the CMC implementation supports static OLE attachments.

item_reference

Unchanged.

extension_flags

Unchanged.

Adds to

The CMC_attachment structure

See Also

CMC_attachment structure, CMC_extension structure


 CMC_X_MS_FUNCTION_FLAGS

[New - Windows 95]

CMC_X_MS_FUNCTION_FLAGS is a CMC extension that holds bitmasks of flags used for CMC functions that serve purposes other than session handling.

Input Usage

item_data

Bitmask of extension flags. The following flags can be set:

CMC_X_MS_AB_NO_MODIFY

Indicates the user should not modify the address book.

CMC_X_MS_LIST_GUARANTEE_FIFO

Indicates the message store lists message identifiers in order by time received.

CMC_X_MS_READ_BODY_AS_FILE

Indicates the recipient should read the body of the message as a file.

CMC_X_MS_READ_ENV_ONLY

Indicates the recipient is to read the message envelope only.

item_reference

NULL.

extension_flags

All flags used with the CMC_extension structure are valid. No further flags are defined.

Output Usage

extension_flags

Unchanged.

item_data

Unchanged.

item_reference

Unchanged.

Adds to

The cmc_read, cmc_look_up, and cmc_list functions

See Also

CMC_extension structure, cmc_list function, cmc_look_up function, cmc_read function


 CMC_X_MS_MESSAGE_DATA

[New - Windows 95]

CMC_X_MS_MESSAGE_DATA is a CMC extension that holds a bitmask of flags that provide extra data regarding messages.

Input Usage

item_data

Bitmask of extension flags. The following flag can be set:

CMC_X_MS_MSG_RECEIPT_REQ

Indicates the message sender requests notification of message receipt.

item_reference

Pointer to the conversation thread.

extension_flags

All flags used with the CMC_extension structure are valid. No further flags are defined.

Output Usage

item_data

Bitmask of extension flags. The following flag can be set:

CMC_X_MS_MSG_RECEIPT_REQ

Indicates the message sender requests notification of message receipt.

item_reference

Pointer to the location of the conversation thread.

extension_flags

Unchanged.

Adds to

The CMC_message structure

See Also

CMC_extension structure, CMC_message structure


 CMC_X_MS_SESSION_FLAGS

[New - Windows 95]

CMC_X_MS_SESSION_FLAGS is a CMC extension that holds a bitmask of flags used to provide information about session logon and logoff.

Input Usage

item_data

Bitmask of logon and logoff flags. The following flags can be set:

 CMC_X_MS_FORCE_DOWNLOAD

Indicates the message sender requests a forced download. This flag is only valid for logon.

CMC_X_MS_LOGOFF_UI

Indicates the message sender requests a logon dialog box.

item_reference

NULL.

extension_flags

All flags used with the CMC_extension structure are valid. No further flags are defined.

Output Usage

item_data

Unchanged.

item_reference

Unchanged.

extension_flags

Unchanged.

Adds to

The cmc_list, cmc_logon, cmc_look_up, and cmc_send functions

See Also

CMC_extension structure, cmc_list function, cmc_logon function, cmc_look_up function, cmc_send function


 CMC_XS_COM

[New - Windows 95]

CMC_XS_COM is a CMC extension identifier used for all extensions in the common extension set, that is the extensions that are common to most message services but are not in the CMC base specification. For a full list of common extension declarations, see the CMC header file.

See Also

cmc_logon function, cmc_query_configuration function, CMC_X_COM_SUPPORT_EXT extension


 CMC_XS_MS

[New - Windows 95]

CMC_XS_MS is a CMC extension identifier used for all extensions in the Microsoft extension set. For a full list of Microsoft extensions, see CMC_X_COM_SUPPORT_EXT.

See Also

cmc_logon function, cmc_query_configuration function, CMC_X_COM_SUPPORT_EXT extension


 Simple MAPI

Simple MAPI is a set of functions and related data structures that help you add messaging functionality to C, C++, or Visual Basic Windows applications. The Simple MAPI functions are available in C and C++ and Visual Basic versions. This chapter describes the functions and structures for C and C++ applications; the next chapter describes the functions and structures for Visual Basic applications.

The following table provides an overview of the Simple MAPI functions.

Simple MAPI function	Description
MAPIAddress	Addresses a message
MAPIDeleteMail	Deletes a message
MAPIDetails	Displays a recipient-details dialog box
MAPIFindNext	Returns the identifier of the first or next message of a specified type.
MAPIFreeBuffer	Frees memory allocated by the messaging system.
MAPILogoff	Ends a session with the messaging system.
MAPILogon	Establishes a messaging session
MAPIReadMail	Reads a message.
MAPIResolveName	Displays a dialog box to resolve an ambiguous recipient name
MAPISaveMail	Saves a message.
MAPISendDocuments	Sends a standard message using a dialog box.
MAPISendMail	Sends a message, allowing greater flexibility than MAPISendDocuments in message generation.


 Simple MAPI Functions for C and C++

To use the Simple MAPI functions, compile your source code with MAPI.H. MAPI.H contains definitions for all of the functions, return value constants, and data types. To call a Simple MAPI function, load MAPI.DLL and use the GetProcAddress function to acquire an entry point. The function calling conventions should be FAR PASCAL.

All strings passed to all MAPI calls and returned by all MAPI calls are null-terminated and must be specified in the current character set or code page of the caller's operating system process.


 MAPIAddress

[New - Windows 95]

The MAPIAddress function creates or modifies a set of address list entries.

Syntax

ULONG FAR PASCAL MAPIAddress (LHANDLE lhSession, ULONG ulUIParam, LPTSTR lpszCaption, ULONG nEditFields, LPTSTR lpszLabels, ULONG nRecips, lpMapiRecipDesc lpRecips, FLAGS flFlags, ULONG ulReserved, LPULONG lpnNewRecips, lpMapiRecipDesc FAR * lppNewRecips)

Parameters

lhSession

Input parameter specifying either a session handle that represents a Simple MAPI session or zero. If the lhSession parameter is zero, MAPI logs on the user and creates a session that exists only for the duration of the call. The temporary session may be an existing shared session or a new one. If necessary, a logon dialog box is displayed.

ulUIParam

Input parameter specifying either a parent window handle or zero, indicating that if a dialog is displayed, it is application modal. If ulUIParam contains a parent window handle, it is of type HWND (cast to a ULONG). If no dialog box is displayed during the call, the ulUIParam parameter is ignored.

lpszCaption

Input parameter specifying either a pointer to the caption for the address list dialog box, NULL, or an empty string. When lpszCaption is NULL or an points to an empty string, the MAPIAddress function uses the default caption "Address Book."

nEditFields

Input parameter specifying the number of edit controls that should be present in the address list. The values 0 through 4 are valid. If nEditFields is 4, each recipient class supported by the underlying messaging system has an edit control.If the nEditFields parameter is set to zero, only address list browsing is allowed. Values of 1, 2, or 3 control the number of edit controls present. If nEditFields is 4, each recipient class supported by the underlying messaging system has an edit control.

However, if the number of recipient classes in the lpRecips array is greater than the value of nEditFields, the number of classes in lpRecips is used to indicate the number of edit controls instead of the value of nEditFields. If the nEditFields parameter is set to 1 and more than one kind of entry exists in lpRecips, then lpszLabels is ignored.

Entries selected for the different controls are differentiated by the ulRecipClass field in the returned recipient structure.

lpszLabels

Input parameter specifying a pointer to a string to be used as an edit control label in the address list dialog box. When nEditFields is set to any value other than 1, this parameter is ignored and should be NULL or point to an empty string. Also, if the caller requires the default control label "To," the lpszLabels parameter should be NULL or point to an empty string.

nRecips

Input parameter specifying the number of entries in the array indicated by lpRecips. If the nRecips parameter is zero, the lpRecips parameter is ignored.

lpRecips

Input parameter specifying a pointer to an array of MapiRecipDesc structures defining the initial recipient entries to be used to populate the address list dialog box. The entries do not need to be grouped by recipient class; they are differentiated by the values of the ulRecipClass members of the MapiRecipDesc structures in the array. If the number of different recipient classes is greater than the value indicated by the nEditFields parameter, the nEditFields and lpszLabels parameters are ignored.

flFlags

Input parameter specifying a bitmask of option flags. The following flags can be set:

MAPI_LOGON_UI

Indicates that a dialog box should be displayed to prompt for logon if required. When the MAPI_LOGON_UI flag is not set, the application does not display a logon dialog box and returns an error if the user is not logged on.

MAPI_NEW_SESSION

Indicates an attempt should be made to create a new session rather than acquire the environment's shared session.  If the MAPI_NEW_SESSION flag is not set, the function uses an existing shared session.

ulReserved

Reserved for future use; must be zero.

lpnNewRecips

Output parameter specifying a pointer to the number of entries in the lppNewRecips recipient output array. If the lpnNewRecips parameter is zero, the lppNewRecips parameter is ignored.

lppNewRecips

Output parameter specifying a pointer to an array of MapiRecipDesc structures containing the the final list of recipients. This array is allocated by MAPIAddress, can not be NULL, and must be freed using MAPIFreeBuffer, even if there are no new recipients. Recipients are grouped by recipient class in the following order: MAPI_TO, MAPI_CC, MAPI_BCC.

Return Values

The following table return values are possible from the MAPIAddress function. If any error occurs, no memory was allocated and you do not need to call MAPIFreeBuffer.

MAPI_E_FAILURE

One or more unspecified errors occurred while addressing the message.No list of recipient entrieswas returned.

MAPI_E_INSUFFICIENT_MEMORY

There was insufficient memory to proceed. No list of recipient entries was returned.

MAPI_E_INVALID_EDITFIELDS

The value of the nEditFields parameter was outside the range of 0 through 4. No list of recipient entries was returned.

MAPI_E_INVALID_RECIPS

One or more of the recipients in the address list was not valid. No list of recipient entries was returned.

MAPI_E_INVALID_SESSION

An invalid session handle was used for the lhSession parameter. No list of recipient entries was returned.

MAPI_E_LOGIN_FAILURE

There was no default logon, and the user failed to log on successfully when the logon dialog box was displayed. No list of recipient entries was returned.

MAPI_E_NOT_SUPPORTED

The operation was not supported by the underlying messaging system.

MAPI_E_USER_ABORT

The user canceled one of the dialog boxes. No list of recipient entries was returned.

SUCCESS_SUCCESS

The function successfully return a list of recipient entries.

Comments

This function displays a standard address list dialog box to show an initial set of zero or more recipients. The user can choose new entries to add to the set or make changes to existing entries. This dialog box cannot be suppressed, but the caller can set dialog box characteristics. The changed set of recipients is returned to the caller.

Before the MAPIAddress function writes new or changed recipient information, it must allocate memory for the structure array that will contain the information. Memory is also allocated as part of preloading the address book, regardless of whether new or changed recipient data is written. Clients must call the MAPIFreeBuffer function to free this memory after the MAPIAddress function returns.

See Also

MAPIFreeBuffer function
MAPILogon function
MapiRecipDesc structure


 MAPIDeleteMail

[New - Windows 95]

The MAPIDeleteMail function deletes a message.

Syntax

ULONG FAR PASCAL MAPIDeleteMail (LHANDLE lhSession, ULONG ulUIParam, LPTSTR lpszMessageID, FLAGS flFlags, ULONG ulReserved)

Parameters

lhSession

Input parameter specifying a session handle that represents a valid Simple MAPI session. The value of the lhSession parameter must represent a valid session; it cannot be zero.

ulUIParam

Input parameter specifying either a parent window handle or zero, indicating that if a dialog is displayed, it is application modal. If ulUIParam contains a parent window handle, it is of type HWND (cast to a ULONG). If no dialog box is displayed during the call, the ulUIParam parameter is ignored.

lpszMessageID

Input parameter specifying the identifier for the message to be deleted. This identifier is messaging system-specific and will be invalid when the MAPIDeleteMail function successfully returns.

flFlags

Reserved for future use; must be zero.

ulReserved

Reserved for future use; must be zero.

Return Values

The possible return values for the MAPIDeleteMail function and their meanings are as follows:

MAPI_E_FAILURE

One or more unspecified errors occurred while deleting the message. No message was deleted.

MAPI_E_INSUFFICIENT_MEMORY

There was insufficient memory to proceed. No message was deleted.

MAPI_E_INVALID_MESSAGE

An invalid message identifier was passed in for the lpszMessageID parameter. No message was deleted.

MAPI_E_INVALID_SESSION

An invalid session handle was passed in for the lhSession parameter. No message was deleted.

SUCCESS_SUCCESS

The function successfully deleted the message.

Comments

To find the message to be deleted, call the MAPIFindNext function before calling MAPIDeleteMail. Because message identifiers are opaque, messaging system-specific, and can be invalidated at any time, the MAPIDeleteMail function considers a message identifier to be valid only for the current session. The MAPIDeleteMail function handles invalid message identifiers by returning the MAPI_E_INVALID_MESSAGE value.

See Also

MAPIFindNext function
MAPILogon function
MAPISaveMail function


 MAPIDetails

[New - Windows 95]

The MAPIDetails function displays a dialog box containing the details of a selected address list entry.

Syntax

ULONG FAR PASCAL MAPIDetails (LHANDLE lhSession, ULONG ulUIParam, lpMapiRecipDesc lpRecip, FLAGS flFlags, ULONG ulReserved)

Parameters

lhSession

Input parameter specifying either a session handle that represents a Simple MAPI session or zero. If the lhSession parameter is zero, MAPI logs on the user and creates a session that exists only for the duration of the call. The temporary session may be an existing shared session or a new one. If additional information is required from the user to successfully complete the logon, a dialog box is displayed.

ulUIParam

Input parameter specifying either a parent window handle or zero, indicating that if a dialog is displayed, it is application modal. If ulUIParam contains a parent window handle, it is of type HWND (cast to a ULONG). If no dialog box is displayed during the call, the ulUIParam parameter is ignored.

lpRecip

Input parameter specifying a pointer to the recipient for which details are to be displayed. The MAPIDetails function ignores all members of this MapiRecipDesc structure except ulEIDSize and lpEntryID. If ulEIDSize is non-zero, the MAPIDetails function resolves the recipient entry. If ulEIDSize is zero, the MAPIDetails function returns MAPI_E_AMBIGUOUS_RECIP.

flFlags

Input parameter specifying a bitmask of option flags. The following flags can be set:

MAPI_AB_NOMODIFY

Indicates the caller is requesting that the dialog be read-only, prohibiting changes. MAPIDetails may or may not honor the request.

MAPI_LOGON_UI

Indicates that a dialog box should be displayed to prompt for logon if required. When the MAPI_LOGON_UI flag is not set, the application does not display a logon dialog box and returns an error if the user is not logged on.

MAPI_NEW_SESSION

Indicates an attempt should be made to create a new session rather than acquire the environment's shared session.  If the MAPI_NEW_SESSION flag is not set, the function uses an existing shared session.

ulReserved

Reserved for future use; must be zero.

ReturnValues

The possible return values for the MAPIDetails function and their meanings are as follows:

MAPI_E_AMBIGUOUS_RECIPIENT

The dialog box could not be displayed because the ulEIDSize member of the lpRecips parameter was zero.

MAPI_E_FAILURE

One or more unspecified errors occurred. No dialog box was displayed.

MAPI_E_INSUFFICIENT_MEMORY

There was insufficient memory to proceed. No dialog box was displayed.

MAPI_E_INVALID_RECIPS

The recipient specified in lpRecips was unknown. No dialog box was displayed.

MAPI_E_LOGIN_FAILURE

There was no default logon, and the user failed to log on successfully when the logon dialog box was displayed. No dialog box was displayed.

MAPI_E_NOT_SUPPORTED

The operation was not supported by the underlying messaging system.

MAPI_E_USER_ABORT

The user canceled either the logon dialog box or the details dialog box.

SUCCESS_SUCCESS

The function successfully displayed the details dialog box.

Comments

The MAPIDetails function presents a dialog box that shows the details of a particular address list entry. The display name and address are the minimum attributes that are displayed in the dialog box; more information may be shown, depending on the address book provider. The details dialog box cannot be suppressed, but the caller can request that it be read-only or modifiable.

Details can only be shown for resolved address list entries. An entry is resolved if the ulEIDSize member of the MapiRecipDesc structure is nonzero. Entries are resolved when they are returned by the MAPIAddress or MAPIResolveName functions and as the result being recipients of read mail.

See Also

MAPIAddress function
MAPILogon function
MapiRecipDesc structure
MAPIResolveName function


 MAPIFindNext

[New - Windows 95]

The MAPIFindNext function retrieves the next (or first) message identifier of a specified type of incoming message.

Syntax

ULONG FAR PASCAL MAPIFindNext (LHANDLE lhSession, ULONG ulUIParam, LPTSTR lpszMessageType, LPTSTR lpszSeedMessageID, FLAGS flFlags, ULONG ulReserved, LPTSTR lpszMessageID)

Parameters

lhSession

Input parameter specifying a session handle that represents a Simple MAPI session. The value of the lhSession parameter must represent a valid session; it cannot be zero.

ulUIParam

Input parameter specifying either a parent window handle or zero, indicating that if a dialog is displayed, it is application modal. If ulUIParam contains a parent window handle, it is of type HWND (cast to a ULONG). If no dialog box is displayed during the call, the ulUIParam parameter is ignored.

lpszMessageType

Input parameter specifying a pointer to a string identifying the message class to search. To find an interpersonal message (IPM), specify NULL in lpszMessageType or have it point to an empty string. Messaging systems whose only supported message class is IPM may ignore this parameter.

lpszSeedMessageID

Input parameter specifying a pointer to a string containing the message identifier seed for the request. If the lpszSeedMessageID parameter is NULL or points to an empty string, the MAPIFindNext function retrieves the first message that matches the type specified in the lpszMessageType parameter.

flFlags

Input parameter specifying a bitmask of option flags. The following flags can be set:

MAPI_GUARANTEE_FIFO

Indicates the message identifiers returned should be in the order of time received. MAPIFindNext calls may take longer if this flag is set. Some implementations cannot honor this request and return MAPI_E_NO_SUPPORT.

MAPI_LONG_MSGID

Indicates that the returned message identifier is expected to be 512 characters. If this flag is set, the lpszMessageID parameter must be large enough to accomodate 512 characters.

Older versions of MAPI supported smaller message identifiers and did not include this flag. MAPIFindNext will succeed without this flag set as long as lpszMessageID is large enough to hold the message identifier. If lpszMessageID cannot hold the message identifier, MAPIFindNext will fail.

MAPI_UNREAD_ONLY

Indicates that only unread messages of the specified type should be enumerated. When this flag is not set, MAPIFindNext can return any message of the specified type.

ulReserved

Reserved for future use; must be zero.

lpszMessageID

Output parameter specifying a pointer to the returned message identifier. The caller is responsible for allocating the memory. To ensure compatibility, allocate 512 characters and set MAPI_LONG_MSGID in flFlags. A smaller buffer will only be sufficient if the returned message identifier will always be 64 characters or less.

Return Values

The possible return values for the MAPIFindNext function and their meanings are as follows:

MAPI_E_FAILURE

One or more unspecified errors occurred while matching the message type. The call failed before message type matching could take place.

MAPI_E_INSUFFICIENT_MEMORY

There was insufficient memory to proceed. No message was found.

MAPI_E_INVALID_MESSAGE

An invalid message identifier was passed in for lpszSeedMessageID. No message was found.

MAPI_E_INVALID_SESSION

An invalid session handle was passed in for lhSession. No message was found.

MAPI_E_NO_MESSAGES

A matching message could not be found.

SUCCESS_SUCCESS

MAPIFindNext successfully returned the message identifier.

Comments

The MAPIFindNext function allows a client application to enumerate messages of a given type. MAPIFindNext can be called repeatedly to list all messages in the folder. Message identifiers returned from the MAPIFindNext function can be used in other Simple MAPI calls to retrieve message contents and delete messages. MAPIFindNext is for processing incoming messages, not for managing received messages.

The MAPIFindNext function looks for messages in the folder in which new messages of the specified type are delivered. MAPIFindNext calls can be made only in the context of a valid Simple MAPI session established with MAPILogon.

When lpszSeedMessageID is NULL or points to an empty string, MAPIFindNext returns the message identifier for the first message of the type specified with lpszMessageType. When lpszSeedMessageID contains a valid identifier, MAPIFindNext returns the next matching message of the type specified with lpszMessageType. Repeated calls to MAPIFindNext ultimately result in a return of MAPI_E_NO_MESSAGES, which means the enumeration is complete.

Message type matching is done against message class strings. All message types whose names match (up to the length specified in the lpszMessageType parameter) are returned.

Because message identifiers are messaging system-specific and can be invalidated at any time, message identifiers are valid only for the current session. If the message identifier passed in with lpszSeedMessageID is invalid, MAPIFindNext returns MAPI_E_INVALID_MESSAGE.

See Also

MAPILogon function


 MAPIFreeBuffer

[New - Windows 95]

The MAPIFreeBuffer function frees memory allocated by the messaging system.

Syntax

ULONG FAR PASCAL MAPIFreeBuffer (LPVOID pv)

Parameters

pv

Input parameter specifying a pointer to memory allocated by the messaging system. This pointer is returned by the MAPIReadMail, MAPIAddress, and MAPIResolveName functions.

Return Values

The possible return values for the MAPIFreeBuffer function and their meanings are as follows:

MAPI_E_FAILURE

One or more unspecified errors occurred and the memory could not be freed.

SUCCESS_SUCCESS

MAPIFreeBuffer successfully freed the memory.

See Also

MAPILogoff function


 MAPILogoff

[New - Windows 95]

The MAPILogoff function ends a session with the messaging system.

Syntax

ULONG FAR PASCAL MAPILogoff (LHANDLE lhSession, ULONG ulUIParam, FLAGS flFlags, ULONG ulReserved)

Parameters

lhSession

Input parameter specifying a handle for the Simple MAPI session to be terminated. Session handles are returned by MAPILogon and invalidated by MAPILogoff.The value of the lhSession parameter must represent a valid session; it cannot be zero.

ulUIParam

Input parameter specifying either a parent window handle or zero, indicating that if a dialog is displayed, it is application modal. If ulUIParam contains a parent window handle, it is of type HWND (cast to a ULONG). If no dialog box is displayed during the call, the ulUIParam parameter is ignored.

flFlags

Reserved for future use; must be zero.

ulReserved

Reserved for future use; must be zero.

Return Values

The possible return values for the MAPILogoff function and their meanings are as follows:

MAPI_E_FAILURE

One or more unspecified errors occurred.

MAPI_E_INSUFFICIENT_MEMORY

There was insufficient memory to proceed. The session was not terminated.

MAPI_E_INVALID_SESSION

An invalid session handle was used for the lhSession parameter. The session was not terminated.

SUCCESS_SUCCESS

MAPILogoff successfully ended the session.

See Also

MAPILogon function


 MAPILogon

[New - Windows 95]

The MAPILogon function begins a Simple MAPI session, loading the default message store and address book providers.

Syntax

ULONG FAR PASCAL MAPILogon (ULONG ulUIParam, LPTSTR lpszProfileName, LPTSTR lpszPassword, FLAGS flFlags, ULONG ulReserved, LPLHANDLE lplhSession)

Parameters

ulUIParam

Input parameter specifying either a parent window handle or zero, indicating that if a dialog is displayed, it is application modal. If ulUIParam contains a parent window handle, it is of type HWND (cast to a ULONG). If no dialog box is displayed during the call, the ulUIParam parameter is ignored.

lpszProfileName

Input parameter specifying a pointer to a null-terminated profile name string, limited to 256 characters or less. This is the profile to use when logging on. If the lpszProfileName parameter is NULL or points to an empty string, and the flFlags parameter is set to MAPI_LOGON_UI, the MAPILogon function displays a logon dialog box with an empty name field.

lpszPassword

Input parameter specifying a pointer to a null-terminated credential string, limited to 256 characters or less. If the messaging system does not require password credentials, or if it requires that the user enter them, lpszPassword should be NULL or point to an empty string. When the user must enter credentials, flFlags must be set to MAPI_LOGON_UI to allow a logon dialog box to be displayed.

flFlags

Input parameter specifying a bitmask of option flags. The following flags can be set:

MAPI_FORCE_DOWNLOAD

Indicates an attempt should be made to download all of the user's messages before returning. If the MAPI_FORCE_DOWNLOAD flag is not set, messages may be downloaded in the background after the function call returns.

MAPI_LOGON_UI

Indicates that a logon dialog box should be displayed to prompt for logon information. If the user needs to provide information to enable a successful log on, MAPI_LOGON_UI must be set.

MAPI_NEW_SESSION

Indicates an attempt should be made to create a new session rather than acquire the environment's shared session.  If the MAPI_NEW_SESSION flag is not set, the function uses an existing shared session.

ulReserved

Reserved for future use; must be 0.

lplhSession

Output parameter specifying a Simple MAPI session handle.

Return Values

The possible return values for the MAPILogon function and their meanings are as follows:

MAPI_E_FAILURE

One or more unspecified errors occurred during sign-on. No session handle was returned.

MAPI_E_INSUFFICIENT_MEMORY

There was insufficient memory to proceed. No session handle was returned.

MAPI_E_LOGIN_FAILURE

There was no default logon, and the user failed to log on successfully when the logon dialog box was displayed. No session handle was returned.

MAPI_E_TOO_MANY_SESSIONS

The user had too many sessions open simultaneously. No session handle was returned.

MAPI_E_USER_ABORT

The user canceled the logon dialog box. No session handle was returned.

SUCCESS_SUCCESS

A Simple MAPI session was successfully established.

Comments

The MAPILogon function begins a session with the messaging system, returning a handle that can be used in subsequent MAPI calls to explicitly provide user credentials to the messaging system. To request the display of a sign-in dialog box if the credentials presented fail to validate the session, set the flFlags parameter to MAPI_LOGON_UI.

Your application can test for an existing session by calling MAPILogon with a NULL value for lpszProfileName, a NULL value for lpszPassword and not setting the MAPI_LOGON_UI flag in flFlags. If there is an existing session, the call will succeed and will return a valid LHANDLE for the session. Otherwise, the call will fail.

See Also

MAPILogoff function


 MAPIReadMail

[New - Windows 95]

The MAPIReadMail function retrieves a message for reading.

Syntax

ULONG FAR PASCAL MAPIReadMail (LHANDLE lhSession, ULONG ulUIParam, LPTSTR lpszMessageID, FLAGS flFlags,  ULONG ulReserved, lpMapiMessage FAR *lppMessage)

Parameters

lhSession

Input parameter specifying a handle to a Simple MAPI session. The value of the lhSession parameter must represent a valid session; it cannot be zero.

ulUIParam

Input parameter specifying either a parent window handle or zero, indicating that if a dialog is displayed, it is application modal. If ulUIParam contains a parent window handle, it is of type HWND (cast to a ULONG). If no dialog box is displayed during the call, the ulUIParam parameter is ignored.

lpszMessageID

Input parameter specifying a pointer to a message identifier string for the message to be read. The string is allocated by the caller.

flFlags

Input parameter specifying a bitmask of option flags. The following flags can be set:

MAPI_BODY_AS_FILE

Indicates MAPIReadMail should write the message text to a temporary file and add it as the first attachment in the attachment list.

MAPI_ENVELOPE_ONLY

Indicates MAPIReadMail should read the message header only. File attachments are not copied to temporary files, and neither temporary file names or message text are written. Setting this flag makes MAPIReadMail processing faster.

MAPI_PEEK

Indicates MAPIReadMail does not mark the message as read. Marking a message as read affects its appearance in the user interface and generates a read receipt. If the messaging system does not support this flag, MAPIReadMail always marks the message as read. If MAPIReadMail encounters an error, it leaves the message unread.

MAPI_SUPPRESS_ATTACH

Indicates MAPIReadMail should not copy file attachments, but should write message text into the MapiMessage structure. The function ignores this flag if the calling application has set the MAPI_ENVELOPE_ONLY flag. Setting the MAPI_SUPPRESS_ATTACH flag is a performance enhancement.

ulReserved

Reserved for future use; must be zero.

lppMessage

Output parameter specifying a pointer to the location where the message is written. Messages are written to a MapiMessage structure; which can be freed with a single call to MAPIFreeBuffer.

When neither MAPI_ENVELOPE_ONLY or MAPI_SUPPRESS_ATTACH is set, attachments are written to temporary files pointed to by the lpFiles MapiMessage structure member. It is the caller's responsibility to delete these files when they are no longer needed.

Return Values

The possible return values for the MAPIReadMail function and their meanings are as follows:

MAPI_E_ATTACHMENT_WRITE_FAILURE

An attachment could not be written to a temporary file. Check directory permissions.

MAPI_E_DISK_FULL

An attachment could not be written to a temporary file because there was not enough space left on the disk.

MAPI_E_FAILURE

One or more unspecified errors occurred while reading the message.

MAPI_E_INSUFFICIENT_MEMORY

There was insufficient memory to read the message.

MAPI_E_INVALID_MESSAGE

An invalid message identifier was passed in for the lpszMessageID parameter.

MAPI_E_INVALID_SESSION

An invalid session handle was passed in for the lhSession parameter. No message was retrieved.

MAPI_E_TOO_MANY_FILES

There were too many file attachments in the message; the message could not be read.

MAPI_E_TOO_MANY_RECIPIENTS

There were too many recipients of the message; the message could not be read.

SUCCESS_SUCCESS

The message was successfully read.

Comments

MAPIReadMail returns one message, breaking the message content into the same parameters and structures used in the MAPISendMail function. MAPIReadMail fills a block of memory with the MapiMessage structure containing message elements, such as the subject, message class, delivery time, and the sender. File attachments are saved to temporary files, and the names are returned to the caller in the message structure. Recipients, attachments, and contents are copied from the message before the function returns to the caller, so later changes to the files do not affect the contents of the message.

A flag is provided to specify that only envelope information is to be returned from the call. Another flag (in the MapiMessage structure) specifies whether the message is marked as sent or unsent.

The caller is responsible for freeing the MapiMessage structure by calling the MAPIFreeBuffer function and deleting any files associated with attachments included with the message.

Before calling MAPIReadMail, use MAPIFindNext to verify that the message to be read is the one you want to be read. Because message identifiers are system-specific and opaque and can be invalidated at any time, the MAPIReadMail function considers a message identifier to be valid only for the current MAPI session.

See Also

MAPIFreeBuffer function
MAPILogon function
MapiMessage structure


 MAPIResolveName

[New - Windows 95]

The MAPIResolveName function transforms a message recipient's name as entered by a user to an unambiguous address list entry.

Syntax

ULONG FAR PASCAL MAPIResolveName (LHANDLE lhSession, ULONG ulUIParam, LPTSTR lpszName, FLAGS flFlags, ULONG ulReserved, lpMapiRecipDesc FAR * lppRecip)

Parameters

lhSession

Input parameter specifying either a handle that represents a Simple MAPI session or zero. If the lhSession parameter is zero, MAPI logs on the user and creates a session that exists only for the duration of the call. The temporary session may be an existing shared session or a new one. If necessary, the logon dialog box is displayed.

ulUIParam

Input parameter specifying either a parent window handle or zero, indicating that if a dialog is displayed, it is application modal. If ulUIParam contains a parent window handle, it is of type HWND (cast to a ULONG). If no dialog box is displayed during the call, the ulUIParam parameter is ignored.

lpszName

Input parameter specifying a pointer to the name to be resolved.

flFlags

Input parameter specifying a bitmask of option flags. The following flags can be set:

MAPI_AB_NOMODIFY

Indicates the caller is requesting that the dialog be read-only, prohibiting changes. MAPIResolveName ignores this flag if MAPI_DIALOG is not set.

MAPI_DIALOG

Indicates that a dialog box should be displayed for name resolution. If this flag is not set and the name cannot be resolved, the function returns the MAPI_E_AMBIGUOUS_RECIPIENT value.

MAPI_LOGON_UI

Indicates that a dialog box should be displayed to prompt for logon if required. When the MAPI_LOGON_UI flag is not set, the application does not display a logon dialog box and returns an error if the user is not logged on.

MAPI_NEW_SESSION

Indicates an attempt should be made to create a new session rather than acquire the environment's shared session.  If the MAPI_NEW_SESSION flag is not set, the function uses an existing shared session.

ulReserved

Reserved for future use; must be zero.

lppRecip

Output parameter specifying a pointer to a recipient structure if the resolution results in a single match. The recipient structure contains the resolved name and related information. Memory for this structure must be freed using MAPIFreeBuffer.

Return Values

If MAPIResolveName returns an error, it is not necessary to deallocate memory with MAPIFreeBuffer. The possible return values for the MAPIResolveName function and their meanings are as follows:

MAPI_E_AMBIGUOUS_RECIPIENT

The recipient requested has not or could not be resolved to a unique address list entry.

MAPI_E_FAILURE

One or more unspecified errors occurred and the name was not resolved.

MAPI_E_INSUFFICIENT_MEMORY

There was insufficient memory to proceed. The name was not resolved.

MAPI_E_LOGIN_FAILURE

There was no default logon, and the user failed to log on successfully when the logon dialog box was displayed. The name was not resolved.

MAPI_E_NOT_SUPPORTED

The operation was not supported by the underlying messaging system.

MAPI_E_USER_ABORT

The user canceled one of the dialog boxes; the name was not resolved.

SUCCESS_SUCCESS

The name was successfully resolved.

Comments

The MAPIResolveName function resolves a message recipient's name (as entered by a user) to an unambiguous address list entry, optionally prompting the user to choose between possible entries, if necessary. A recipient descriptor structure containing fully resolved information about the entry is allocated and returned. The caller should free the MAPIRecipDesc structure at some point by calling the MAPIFreeBuffer function.

See Also

MAPIFreeBuffer function
MAPILogon function
MapiRecipDesc structure


 MAPISaveMail

[New - Windows 95]

The MAPISaveMail function saves a message into the message store.

Syntax

ULONG FAR PASCAL MAPISaveMail (LHANDLE lhSession, ULONG ulUIParam, lpMapiMessage lpMessage, FLAGS flFlags,  ULONG ulReserved, LPTSTR lpszMessageID)

Parameters

lhSession

Input parameter specifying either a handle for a Simple MAPI session or zero. The lhSession parameter must not be zero if the lpszMessageID parameter contains a valid message identifier. However, if lpszMessageID does not contain a valid message identifier, and lhSession is zero, MAPI logs on the user and creates a session that exists only for the duration of the call. The temporary session may be an existing shared session or a new one. If necessary, the logon dialog box is displayed.

ulUIParam

Input parameter specifying either a parent window handle or zero, indicating that if a dialog is displayed, it is application modal. If ulUIParam contains a parent window handle, it is of type HWND (cast to a ULONG). If no dialog box is displayed during the call, the ulUIParam parameter is ignored.

lpMessage

Input parameter specifying a pointer to a MapiMessage structure containing the contents of the message to be saved. The lpOriginator member is ignored. Applications can either ignor the flFlags member, or, if the message has never been saved, can set the MAPI_SENT and MAPI_UNREAD bits.

flFlags

Input parameter specifying a bitmask of option flags. The following flags can be set:

MAPI_LOGON_UI

Indicates that a dialog box should be displayed to prompt for logon if required. When the MAPI_LOGON_UI flag is not set, the application does not display a logon dialog box and returns an error if the user is not logged on. The MAPISaveMail function ignores this flag if the lpszMessageID parameter is empty.

MAPI_LONG_MSGID

Indicates that the returned message identifier is expected to be 512 characters. If this flag is set, the lpszMessageID parameter must be large enough to accomodate 512 characters.

MAPI_NEW_SESSION

Indicates an attempt should be made to create a new session rather than acquire the environment's shared session.  If the MAPI_NEW_SESSION flag is not set, the function uses an existing shared session.

ulReserved

Reserved for future use; must be 0.

lpszMessageID

Input-output parameter specifying a either a pointer to the message identifier to be replaced by the save operation or an empty string, indicating that a new message is to be created. The string must be allocated by the caller  and must be able to hold at least 512 characters if the flFlags parameter is set to MAPI_LONG_MSGID. If the flFlags parameter is not set to MAPI_LONG_MSGID, the message identifier string can hold 64 characters.

Return Values

The possible return values for the MAPISaveMail function and their meanings are as follows:

MAPI_E_FAILURE

One or more unspecified errors occurred while saving the message; no message was saved.

MAPI_E_INSUFFICIENT_MEMORY

There was insufficient memory to save the message; no message was saved.

MAPI_E_INVALID_MESSAGE

An invalid message identifier was passed in for the lpszMessageID parameter; no message was saved.

MAPI_E_INVALID_SESSION

An invalid session handle was passed for the lhSession parameter; no message was saved.

MAPI_E_LOGIN_FAILURE

There was no default logon, and the user failed to log on successfully when the logon dialog box was displayed. No message was saved.

MAPI_E_NOT_SUPPORTED

The operation was not supported by the underlying messaging system.

MAPI_E_USER_ABORT

The user canceled one of the dialog boxes; no message was saved.

SUCCESS_SUCCESS

MAPISaveMail saved the message successfully.

Comments

MAPISaveMail saves a message, optionally replacing an existing message. Before calling MAPISaveMail, use MAPIFindNext to verify that the message to be saved is the one you want saved. The elements of the message identified by the lpszMessageID parameter are replaced by the elements in the lpMessage parameter. If the lpszMessageID parameter is empty, a new message is created. All replaced messages are saved in their appropriate folders. New messages are saved in the folder appropriate for incoming messages of that class.

Not all messaging systems support storing messages. If the underlying message system does not support message storage, the MAPISaveMail function returns the MAPI_E_NOT_SUPPORTED value.

Because message identifiers are system-specific and opaque and can be invalidated at any time, the MAPISaveMail function considers a message identifier to be valid only for the current MAPI session. The MAPISaveMail function handles invalid message identifiers by returning the MAPI_E_INVALID_MESSAGE value.

See Also

MAPILogon function
MAPIMessage data type


 MAPISendDocuments

[New - Windows 95]

The MAPISendDocuments function sends a standard message with one or more attached files and a cover note. The cover note is a dialog box that allows the user to enter a list of recipients and an optional message. MAPISendDocuments differs from MAPISendMail in that it allows less flexibility in message generation.

Syntax

ULONG FAR PASCAL MAPISendDocuments (ULONG ulUIParam, LPTSTR lpszDelimChar, LPTSTR lpszFullPaths, LPTSTR lpszFileNames, ULONG ulReserved)

Parameters

ulUIParam

Input parameter specifying either a parent window handle or zero, indicating that if a dialog is displayed, it is application modal. If ulUIParam contains a parent window handle, it is of type HWND (cast to a ULONG). If no dialog box is displayed during the call, the ulUIParam parameter is ignored.

lpszDelimChar

Input parameter specifying a pointer to a character that the caller uses to delimit the names pointed to by the lpszFullPaths and lpszFileNames parameters. The caller should select a character for the delimiter that is not used in operating system filenames.

lpszFullPaths

Input parameter specifying a pointer to a string containing a list of full pathnames (including drive letters) to attachment files. This list is formed by concatenating correctly formed filepaths separated by the character specified in the lpszDelimChar parameter and followed by a null terminator. An example of a valid list is:

C:\TMP\TEMP1.DOC;C:\TMP\TEMP2.DOC

The files specified in this parameter are added to the message as file attachments. If this parameter is NULL or contains an empty string, the Send Note dialog box is displayed with no attached files.

lpszFileNames

Input parameter specifying a pointer to a null-terminated list of the original filenames as they should appear in the message. When multiple names are specified, the list is formed by concatenating the filenames separated by the character specified in the lpszDelimChar parameter and followed by a null terminator. An example is:

TEMP3.DOC;TEMP4.DOC

If there is no value for the lpszFileNames parameter or if it is empty, the MAPISendDocuments function sets the filenames set to the filename values indicated by lpszFullPaths.

ulReserved

Reserved for future use; must be zero.

Return Values

The possible return values for the MAPISendDocuments function and their meanings are as follows:

MAPI_E_ATTACHMENT_OPEN_FAILURE

One or more files in the lpszFilePaths parameter could not be located. No message was sent.

MAPI_E_ATTACHMENT_WRITE_FAILURE

An attachment could not be written to a temporary file. Check directory permissions.

MAPI_E_FAILURE

One or more unspecified errors occurred while sending the message. It is not known if the message was sent.

MAPI_E_INSUFFICIENT_MEMORY

There was insufficient memory to proceed.

MAPI_E_LOGIN_FAILURE

There was no default logon, and the user failed to log on successfully when the logon dialog box was displayed. No message was sent.

MAPI_E_USER_ABORT

The user canceled one of the dialog boxes; no message was sent.

SUCCESS_SUCCESS

MAPISendDocuments sent the message successfully.

Comments

The MAPISendDocuments function sends a standard message, always displaying a cover note dialog box so that the user can provide recipients and other sending options.The function tries to establish a session using the messaging system's shared session. If no shared session exists, it prompts for logon information to establish a session. Before the function returns, it closes the session.

Message attachments can include the active document or all the currently open documents in the client application that called MAPISendDocuments. The function is used primarily for calls from a macro or scripting language, often found in applications such as spreadsheet or word-processing programs.

The MAPISendDocuments function creates as many file attachments as there are paths specified by the lpszFullPaths parameter in spite of the fact that there may be different numbers of filepaths and filenames. The function caller is responsible for deleting temporary files created when using this function.

See Also

MAPISendMail function


 MAPISendMail

[New - Windows 95]

The MAPISendMail function sends a message. MAPISendMail differs from MAPISendDocuments in that it allows greater flexibility in message generation.

Syntax

ULONG FAR PASCAL MAPISendMail (LHANDLE lhSession, ULONG ulUIParam, lpMapiMessage lpMessage, FLAGS flFlags, ULONG ulReserved)

Parameters

lhSession

Input parameter specifying either a handle to a Simple MAPI session or zero. If the lhSession parameter is zero, MAPI logs on the user and creates a session that exists only for the duration of the call. The temporary session may be an existing shared session or a new one. If necessary, the logon dialog box is displayed.

ulUIParam

Input parameter specifying either a parent window handle or zero, indicating that if a dialog is displayed, it is application modal. If ulUIParam contains a parent window handle, it is of type HWND (cast to a ULONG). If no dialog box is displayed during the call, the ulUIParam parameter is ignored.

lpMessage

Input parameter specifying a pointer to a MapiMessage structure containing the message to be sent. If the MAPI_DIALOG flag is not set, the nRecipCount and lpRecips members must be valid for successful message delivery. Client applications can set the flFlags member to MAPI_RECEIPT_REQUESTED to ask for a read report. All other members are ignored and unused pointers should be NULL.

flFlags

Input parameter specifying a bitmask of option flags. The following flags can be set:

MAPI_DIALOG

Indicates that a dialog box should be displayed to prompt the user for recipients and other sending options. When MAPI_DIALOG is not set, at least one recipient must be specifieid.

MAPI_LOGON_UI

Indicates that a dialog box should be displayed to prompt for logon if required. When the MAPI_LOGON_UI flag is not set, the application does not display a logon dialog box and returns an error if the user is not logged on. The MAPISaveMail function ignores this flag if the lpszMessageID parameter is empty.

MAPI_NEW_SESSION

Indicates an attempt should be made to create a new session rather than acquire the environment's shared session. If the MAPI_NEW_SESSION flag is not set, the function uses an existing shared session.

ulReserved

Reserved for future use; must be zero.

Return Values

The possible return values for the MAPISendMail function and their meanings are as follows:

MAPI_E_AMBIGUOUS_RECIPIENT

A recipient matched more than one of the recipient descriptor structures and MAPI_DIALOG was not set. No message was sent.

MAPI_E_ATTACHMENT_NOT_FOUND

The specified attachment was not found. No message was sent.

MAPI_E_ATTACHMENT_OPEN_FAILURE

The specified attachment could not be open; no message was sent.

MAPI_E_BAD_RECIPTYPE

The type of a recipient was not MAPI_TO, MAPI_CC, or MAPI_BCC. No message was sent.

MAPI_E_FAILURE

One or more unspecified errors occurred; no message was sent.

MAPI_E_INSUFFICIENT_MEMORY

There was insufficient memory to proceed. No message was sent.

MAPI_E_LOGIN_FAILURE

There was no default logon, and the user failed to log on successfully when the logon dialog box was displayed. No message was sent.

MAPI_E_TEXT_TOO_LARGE

The text in the message was too large to sent; the message was not sent.

MAPI_E_TOO_MANY_FILES

There were too many file attachments; no message was sent.

MAPI_E_TOO_MANY_RECIPIENTS

There were too many recipients; no message was sent.

MAPI_E_UNKNOWN_RECIPIENT

A recipient did not appear in the address list; no message was sent.

MAPI_E_USER_ABORT

The user canceled one of the dialog boxes; no message was sent.

SUCCESS_SUCCESS

MAPISendMail successfully sent the message.

Comments

MAPISendMail sends a standard message, with or without any user interaction. The profile must be configured so that MAPISendMail can open the default service providers without requiring user interaction. However, if the flFlags parameter is set to MAPI_NEW_SESSION, disallowing the use of a shared session, and the profile requires a password, MAPI_LOGON_UI must be set or the function will fail. Client applications can avoid this situation by using an explicit profile without a password or by using the default profile without a password.

Client applications can provide a full or partial list of recipient names, subject text, file attachments, or message text. If any information is missing, MAPISendMail can prompt the user for it. If no information is missing, either the message can be sent as is or the user can be prompted to verify the information, changing values if necessary.

A successful return from the MAPISendMail function does not necessarily imply recipient validation. The message may not have been sent to all recipients. Depending on the transport provider, recipient validation may be a lengthy process.

A NULL value for lpMessage->lpszSubject indicates that there is no text for the subject of the message and a NULL value for lpMessage->lpszNoteText indicates that there is no text for the body of the message. Some client applications may truncate subject lines that are too long or contain carriage returns, line feeds, or form feeds.

Each paragraph should be terminated with a CR (0x0d), an LF (0x0a), or a CRLF pair (0x0d0a). The MAPISendMail function wraps lines as appropriate. If the text exceeds system limits, the function returns the MAPI_E_TEXT_TOO_LARGE value.

The lpMessage->lpszMessageType parameter member is used only by non-IPM applications. Applications that handle IPM messages can set it to NULL or have it point to an empty string.

The number of attachments per message may be limited in some messaging systems. If the limit is exceeded, the error MAPI_E_TOO_MANY_FILES is returned. If no files are specified, a pointer value of NULL should be assigned to the lpFiles member of the structure pointed to be lpMessage. File attachments are copied to the message before the function returns; therefore, later changes to the files do not affect the contents of the message. The files must be closed when they are copied. Do not attempt to display attachments outside the range of the message body.

Some messaging systems may limit the number of recipients per message. A pointer value of NULL for lpMessage->lpRecips indicates no recipients. If your application passes a non-NULL value indicating a number of recipients exceeding the system limit, the MAPISendMail function returns MAPI_E_TOO_MANY_RECIPIENTS.

Note that lpMessage->lpRecips can include either an entry identifier, the recipient's name, an address, or a name and address pair. The following table shows how MAPISendMail handles the variety of information that can be specified:

Information	Action
entry identifier	No name resolution; the name and address are ignored.
name	Name resolved using the Simple MAPI resolution rules.
address	No name resolution; address is used for both message delivery and for displaying the recipient name.
name and address	No name resolution; name used only for displaying the recipient name.
Client applications that send messages to custom recipients may want to avoid name resolution. Such clients should set lpMessage->lpRecips-> lpszAddress to the custom address.

The MAPISendMail function does not require an originator-type recipient to send a message.

See Also

MAPILogon function
MAPIMessage data type
MapiRecipDesc structure


 Simple MAPI Structures for C and C++

This section contains a reference entry for each structure.


 MapiFileDesc

[New - Windows 95]

A MapiFileDesc structure holds information about file containing a message attachment stored as a temporary file. That file can contain  a static OLE object, an embedded OLE object, an embedded message, and other types of files..

Syntax

typedef struct {

ULONG ulReserved;

ULONG flFlags;

ULONG nPosition;

LPTSTR lpszPathName;

LPTSTR lpszFileName;

LPVOID lpFileType;

} MapiFileDesc, FAR *lpMapiFileDesc;

Members

ulReserved

Reserved; must be zero.

flFlags

Bitmask of attachment flags. The following flags can be set:

MAPI_OLE

Indicates the attachment is an OLE object. If MAPI_OLE_STATIC is also set, the attachment is a static OLE object. If MAPI_OLE_STATIC is not set, the attachment is an embedded OLE object.

MAPI_OLE_STATIC

Indicates the attachment is a static OLE object.

If neither flag is set, the attachment is treated as a data file.

nPosition

Integer used to indicate where in the message body to render the attachment. Attachments replace the character found at a certain position in the message body. That is, attachments replace character in the MapiMessage structure field lpszNoteText[nPosition]. A value of  − 1 (0xFFFFFFFF) means attachment position is not indicated; the application will have to provide a way for the user to access the attachment.

lpszPathName

Pointer to the fully qualified path of the attached file. This path should include the disk drive letter and directory name.

lpszFileName

Pointer to the attachment filename seen by the recipient, which may differ from the filename in the lpszPathName member if temporary files are being used. If the lpszFileName member is empty or NULL, the filename from lpszPathName is used.

lpFileType

Pointer to the attachment filetype, which can be represented with a MapiFileTagExt structure. A value of NULL indicates an unknown filetype or a filetype determined by the operating system.

Comments

Simple MAPI works with three kinds of embedded attachments:

•	Data file attachments

•	Editable OLE object file attachments

•	Static OLE object file attachments

Data file attachments are simply data files. OLE object file attachments are OLE objects that are displayed in the message body. If the OLE attachment is editable, the recipient can double-click it and its source application will be started to handle the edit session. If the OLE attachment is static, the object cannot be edited. The flag set in the flFlags member of the MapiFileDesc structure determines what kind a particular attachment is. Embedded messages can be identified by a .MSG extension in the lpszFileName member.

OLE (object linking and embedding) object files are file representations of OLE object streams. You can re-create an OLE object from the file by calling the OleLoadFromStream function with an OLESTREAM object that reads the file contents. If an OLE file attachment is included in an outbound message, the OLE object stream should be written directly to the file used as the attachment.

When using the MapiFileDesc member nPosition, your application should not place two attachments in the same location. Applications may not display file attachments at positions beyond the end of the message text.

See Also

MapiFileTagExt structure¤


 MapiFileTagExt

[New - Windows 95]

A MapiFileTagExt structure specifies a message attachment's type at its creation and its current form of encoding so that it can be restored to its original type at its destination.

Syntax

typedef struct {

ULONG ulReserved;

ULONG cbTag;

LPBYTE lpTag;

ULONG cbEncoding;

LPBYTE lpEncoding

} MapiFileTagExt, FAR *lpMapiFileTagExt;

Members

ulReserved

Reserved; must be zero.

cbTag

Size, in bytes, of the value defined by the lpTag member.

lpTag

Pointer to an X.400 object identifier indicating the type of the attachment in its original form, for example "Microsoft Excel worksheet".

cbEncoding

Size, in bytes, of the value defined by the lpEncoding member.

lpEncoding

Pointer to an X.400 object identifier indicating the form in which the attachment is currently encoded, for example MacBinary, UUENCODE, or binary.

Comments

MapiFileTagExt defines the type of an attached file for purposes such as encoding and decoding the file, choosing the correct application to launch when opening it, or any use that requires full information regarding the file type. Client applications can use information in the lpTag and lpEncoding members of this structure to determine what to do with an attachment. For more information on using MAPI with X.400 messaging, see Using MAPI with X.400 Message Systems.

See Also

MapiFileDesc structure¤


 MapiMessage

[New - Windows 95]

A MapiMessage structure holds information about a message.

Syntax

typedef struct {

ULONG ulReserved;

LPTSTR lpszSubject;

LPTSTR lpszNoteText;

LPTSTR lpszMessageType;

LPTSTR lpszDateReceived;

LPTSTR lpszConversationID;

FLAGS flFlags;

lpMapiRecipDesc lpOriginator;

ULONG nRecipCount;

lpMapiRecipDesc lpRecips;

ULONG nFileCount;

lpMapiFileDesc lpFiles;

} MapiMessage, FAR *lpMapiMessage;

Members

ulReserved

Reserved; must be zero.

lpszSubject

Pointer to the text string describing the message subject, typically limited to 256 characters or less. If this member is empty or NULL, the user has not entered subject text.

lpszNoteText

Pointer to a string containing the message text. If this member is empty or NULL, there is no message text.

lpszMessageType

Pointer to a string indicating a non-IPM type of message. Client applications can select message types for their non-IPM messages. Clients that only support IPM messages can ignor the lpszMessageType member when reading messages and set it to empty or NULL when sending messages.

lpszDateReceived

Pointer to a string indicating the date when the message was received. The format is YYYY/MM/DD HH:MM, using a 24-hour clock.

lpszConversationID

Pointer to a string identifying the conversation thread o which the message belongs. Some messaging systems may ignore and not return this member.

flFlags

Bitmask of message status flags. The following flags can be set:

MAPI_RECEIPT_REQUESTED

Indicates a receipt notification is requested. Client applications set this bit when sending a message.

MAPI_SENT

Indicates the message has been sent.

MAPI_UNREAD

Indicates the message has not been read.

lpOriginator

Pointer to a MapiRecipDesc structure holding information about the sender of the message.

nRecipCount

Number of message recipient structures in the array pointed to by the lpRecips member. A value of zero indicates no recipients are included.

lpRecips

Pointer to an array of MapiRecipDesc structures, each holding information about a message recipient.

nFileCount

Number of structures that describe file attachments in the array pointed to by the lpFiles member. A value of zero indicates no file attachments are included.

lpFiles

Pointer to an array of MapiFileDesc structures, each holding information about  a file attachment.

See Also

MapiFileDesc structure, MapiRecipDesc structure¤


 MapiRecipDesc

[New - Windows 95]

A MapiRecipDesc structure holds information about a message sender or recipient.

Syntax

typedef struct {

ULONG ulReserved

ULONG ulRecipClass;

LPTSTR lpszName;

LPTSTR lpszAddress;

ULONG ulEIDSize;

LPVOID lpEntryID;

} MapiRecipDesc, FAR *lpMapiRecipDesc;

Members

ulReserved

Reserved; must be zero.

ulRecipClass

Numeric value that indicates the type of recipient. Possible values for the ulRecipClass member are:

Value	Constant	Meaning
0	MAPI_ORIG	Indicates the original sender of the message.
1	MAPI_TO	Indicates a primary message recipient.
2	MAPI_CC	Indicates a recipient of a message copy.
3	MAPI_BCC	Indicates a recipient of a blind copy.
lpszName

Pointer to the display name of the message recipient or sender.

lpszAddress

Optional pointer to the recipient or sender's address; this address is provider-specific message delivery data. Generally, the messaging system provides such addresses for inbound messages. For outbound messages, the lpszAddress member can point to an address entered by the user for a recipient not in an address book (that is, a custom recipient).

The format of an address pointed to by the lpszAddress member i [address type][e-mail address]. Examples of valid addresses are FAX:206-555-1212 and SMTP:M@X.COM.

ulEIDSize

Size, in bytes, of the entry identifier pointed to by the lpEntryID member.

lpEntryID

Pointer to an opaque entry identifier used by a messaging system service provider to identify the message recipient. Entry identifiers have meaning only for the service provider; client applications will not be able to decipher them. The messaging system uses this member to return valid entry identifiers for all recipients or senders listed in the address book.


 Simple MAPI Functions for Visual Basic

Visual Basic uses a different set of calling and programming conventions than  C and C++ use. Different structure and parameter definitions support the Visual Basic representation of strings and of structures, which in Visual Basic are called types. The following list describes how programming Simple MAPI Visual Basic applications differs from programming Simple MAPI C and C++ applications:

•	Because the concept of a pointer is foreign to Visual Basic, developers use extra function parameters instead of the complex pointer structures used in C and C++.

•	Because the Visual Basic MAPI functions are declared, it is not necessary to explicitly cast passed arguments using ByVal.

•	An empty string in a string variable is equivalent to a NULL value.

•	Arrays must be dynamically declared so that they are redimensioned when the Simple MAPI function is run.

•	Visual Basic manages memory, eliminating the need for calling the MAPIFreeBuffer function.

•	All structures used in the Visual Basic version of Simple MAPI are Visual Basic types rather than C-language structures.

•	All strings used in the Visual Basic version of Simple MAPI are Visual Basic strings rather than C-language strings.

The Simple MAPI functions for Visual Basic work with Visual Basic 3, Visual Basic 4, and Visual Basic for Applications. The following section describes these functions.


 MAPIAddress

[New - Windows 95]

The MAPIAddress function enables users to create or modify a set of recipients. MAPIAddress generates an address-book dialog box that shows the contents of the recipient set and allows the user to select new entries or change existing entries.

Syntax

MAPIAddress(

Session as Long,
UIParam as Long,
Caption as String,
EditFields as Long,
Label as String,
RecipCount as Long,
Recipients() as MapiRecip,
Flags as Long,
Reserved as Long) as Long

Parameters

Session

Input parameter specifying either a session handle that represents a Simple MAPI session or zero. If the Session parameter is zero, MAPI logs on the user and creates a session that exists only for the duration of the call. The temporary session may be an existing shared session or a new one. If necessary, a logon dialog box is displayed.

UIParam

Input parameter specifying either a parent window handle or zero, indicating that if a dialog is displayed, it is application modal. If no dialog box is displayed during the call, the UIParam parameter is ignored.

Caption

Input parameter specifying the caption of the address-list dialog box. If this parameter is an empty string, the default value "Address Book" is used.

EditFields

Input parameter specifying the number of edit controls that should be present in the address list. The values 0 to 4are valid. If nEditFields is 4, each recipient class supported by the underlying messaging system has an edit control.If the nEditFields parameter is set to zero, only address list browsing is allowed. Values of 1, 2, or 3 control the number of edit controls present. If nEditFields is 4, each recipient class supported by the underlying messaging system has an edit control.

However, if the number of recipient classes in the lpRecips array is greater than the value of nEditFields, the number of classes in lpRecips is used to indicate the number of edit controls instead of the value of nEditFields. If the nEditFields parameter is set to 1 and more than one kind of entry exists in lpRecips, then lpszLabels is ignored.

Entries selected for the different controls are differentiated by the ulRecipClass field in the returned recipient structure.

Label

Input parameter specifying an edit control label in the address-list dialog box. This argument is ignored and should be an empty string except when the EditFields parameter is 1. If you want a default control label "To:", the Label parameter should be an empty string.

RecipCount

Input parameter specifying the number of entries in the Recipients parameter. If the RecipCount parameter is zero, the Recipients parameter is ignored.

Recipients

Input parameter specifying the initial array of recipient entries to be used to populate edit controls in the address-list dialog box. Recipient entries need not be grouped by recipient class. If the value of the greatest recipient class present is greater than the EditFields parameter, the EditFields and Label parameters are ignored. This array is redimensioned as necessary to accommodate the entries made by the user in the address-list dialog box.

Flags

Input parameter specifying a bitmask of flags. The following flags can be set:

MAPI_LOGON_UI

Indicates that a dialog box should be displayed to prompt for logon if required. When the MAPI_LOGON_UI flag is not set, the application does not display a logon dialog box and returns an error if the user is not logged on.

MAPI_NEW_SESSION

Indicates an attempt should be made to create a new session rather than acquire the environment's shared session.  If the MAPI_NEW_SESSION flag is not set, the function uses an existing shared session.

Reserved

Reserved for future use;must be zero.

Return Values

The possible return values for the MAPIAddress function and their meanings are as follows:

MAPI_E_FAILURE

One or more unspecified errors occurred while building recipient lists or browsing the address book. No list of recipients was returned.

MAPI_E_INSUFFICIENT_MEMORY

There was insufficient memory to proceed. No list of recipients was returned.

MAPI_E_INVALID_EDITFIELDS

The value of the nEditFields parameterwas outside the range of 0 through 4. No list of recipients was returned.

MAPI_E_INVALID_RECIPIENTS

One or more of the recipients in the address list was not valid or the Recipients parameter was not a valid array. No list of recipients was returned.

MAPI_E_INVALID_SESSION

An invalid session handle was used for the lhSession parameter. No list of recipients was returned.

MAPI_E_LOGIN_FAILURE

There was no default logon, and the user failed to log on successfully when the logon dialog box was displayed. No list of recipients was returned.

MAPI_E_NOT_SUPPORTED

The operation was not supported by the underlying messaging system. A list of recipients may have been returned.

MAPI_E_USER_ABORT

The user canceled one of the dialog boxes. No list of recipients was returned.

SUCCESS_SUCCESS

MAPIAddress successfully returned a list of address entries.

Comments

With the MAPIAddress function, users can create or modify a set of address-list entries using a standard address-list dialog box. The dialog box cannot be suppressed, but function parameters allow the caller to set characteristics of the dialog box.

The call is made with an initial, and possibly empty, set of recipients. The address-list dialog box shows the contents of the recipient set; users can choose new entries to add to the set. The final set of recipients is returned to the caller in the RecipCount and Recipients parameters, destroying their initial values.


 MAPIDeleteMail

[New - Windows 95]

The MAPIDeleteMail function deletes a message.

Syntax

MAPIDeleteMail(

Session as Long,
UIParam as Long,
MessageID as String,
Flags as Long,
Reserved as Long) as Long

Parameters

Session

Input parameter specifying a session handle that represents a valid Simple MAPI session. The value of the Session parameter cannot be zero.

UIParam

Input parameter specifying either a parent window handle or zero, indicating that if a dialog is displayed, it is application modal. If no dialog box is displayed during the call, the UIParam parameter is ignored.

MessageID

Input parameter specifying the identifier for the message to be deleted. This string identifier is messaging system-specific and will be invalid when the MAPIDeleteMail function successfully returns. Both the MAPIFindNext or MAPISaveMail functions return message identifiers.

Flags

Reserved for future use; must be zero.

Reserved

Reserved for future use;must be zero.

Return Values

The possible return values for the MAPIDeleteMail function and their meanings are as follows:

MAPI_E_FAILURE

One or more unspecified errors occurred while deleting the message. No message was deleted.

MAPI_E_INSUFFICIENT_MEMORY

There was insufficient memory to proceed. No message was deleted.

MAPI_E_INVALID_MESSAGE

An invalid message identifier was passed in for the MessageID parameter. No message was deleted.

MAPI_E_INVALID_SESSION

An invalid session handle was passed in for the Session parameter. No message was deleted.

SUCCESS_SUCCESS

The function successfully deleted the message.

Comments

To find the message to be deleted, call the MAPIFindNext function before calling MAPIDeleteMail.


 MAPIDetails

[New - Windows 95]

The MAPIDetails function displays a dialog box containing the details of a selected address-list entry.

Syntax

MAPIDetails(

Session as Long,
UIParam as Long,
Recipient as MapiRecip,
Flags as Long,
Reserved as Long) as Long

Parameters

Session

Input parameter specifying either a session handle that represents a Simple MAPI session or zero. If the Session parameter is zero, MAPI logs on the user and creates a session that exists only for the duration of the call. The temporary session may be an existing shared session or a new one. If necessary, a logon dialog box is displayed.

UIParam

Input parameter specifying either a parent window handle or zero, indicating that if a dialog is displayed, it is application modal. If no dialog box is displayed during the call, the UIParam parameter is ignored.

Recipient

Input parameter specifying a recipient descriptor containing the entry whose details are to be displayed. The MAPIDetails function ignores all fields of the MapiRecip type except EIDSize and EntryID. If the field EIDSize is non-zero, the MAPIDetails function resolves the recipient entry. If EIDSize is zero, the MAPI_E_AMBIGUOUS_RECIPIENT value is returned.

Flags

Input parameter specifying a bitmask of flags. The following flags can be set:

MAPI_AB_NOMODIFY

Indicates the caller is requesting that the dialog be read-only, prohibiting changes. MAPIDetails may or may not honor the request.

MAPI_LOGON_UI

Indicates that a dialog box should be displayed to prompt for logon if required. When the MAPI_LOGON_UI flag is not set, the application does not display a logon dialog box and returns an error if the user is not logged on.

MAPI_NEW_SESSION

Indicates an attempt should be made to create a new session rather than acquire the environment's shared session.  If the MAPI_NEW_SESSION flag is not set, the function uses an existing shared session.

Reserved

Reserved for future use; must be zero.

Return Values

The possible return values for the MAPIDetails function and their meanings are as follows:

MAPI_E_AMBIGUOUS_RECIPIENT

The recipient requested has not or could not be resolved to a unique address list entry.

MAPI_E_FAILURE

One or more unspecified errors occurred. No dialog box was displayed.

MAPI_E_INSUFFICIENT_MEMORY

There was insufficient memory to proceed. No dialog box was displayed.

MAPI_E_INVALID_RECIPS

The recipient specified in Recipient was unknown. No dialog box was displayed.

MAPI_E_LOGIN_FAILURE

There was no default logon, and the user failed to log on successfully when the logon dialog box was displayed. No details dialog box was displayed.

MAPI_E_NOT_SUPPORTED

The operation was not supported by the underlying messaging system.

MAPI_E_USER_ABORT

The user canceled either the logon dialog box or the details dialog box.

SUCCESS_SUCCESS

The function successfully displayed the details dialog box.

Comments

The MAPIDetails function presents a dialog box that shows the details of a particular address list entry. The display name and address are the minimum attributes that are displayed in the dialog box; more information may be shown, depending on the directory to which the entry belongs. The details dialog box cannot be suppressed, but the caller can request that it be read-only or modifiable.

Details can only be shown for resolved address list entries. An entry is resolved if the EIDSize field of the MapiRecip type is nonzero. Entries are resolved when they are returned by the MAPIAddress or MAPIResolveName functions and as the result being recipients of read mail.


 MAPIFindNext

[New - Windows 95]

The MAPIFindNext function retrieves the next (or first) message identifier of a specified type of incoming message.

Syntax

MAPIFindNext(

Session as Long,
UIParam as Long,
MessageType as String,
SeedMessageID as String,
Flags as Long,
Reserved as Long,
MessageID as String) as Long

Parameters

Session

Input parameter specifying a session handle that represents a Simple MAPI session. The value of the Session parameter must represent a valid session; it cannot be zero.

UIParam

Input parameter specifying either a parent window handle or zero, indicating that if a dialog is displayed, it is application modal. If no dialog box is displayed during the call, the UIParam parameter is ignored.

MessageType

Input parameter specifying the type of message to search. To find an interpersonal message (IPM), use an empty string, "".

SeedMessageID

Input parameter specifying the message identifier seed for the request. If the SeedMessageID parameter is an empty string, the MAPIFindNext function retrieves the first message that matches the type specified in the MessageType parameter.

Flags

Input parameter specifying a bitmask of option flags. The following flags can be set:

MAPI_GUARANTEE_FIFO

Indicates the message identifiers returned should be in the order of time received. MAPIFindNext calls may take longer if this flag is set. Some implementations cannot honor this request and return MAPI_E_NO_SUPPORT.

MAPI_NEW_SESSION

Indicates an attempt should be made to create a new session rather than acquire the environment's shared session.  If the MAPI_NEW_SESSION flag is not set, the function uses an existing shared session.

MAPI_UNREAD_ONLY

Indicates that only unread messages of the specified type should be enumerated. When this flag is not set, MAPIFindNext can return any message of the specified type.

Reserved

Reserved for future use;must be zero.

MessageID

Output parameter specifying the returned message identifier. The MessageID parameter is a variable-length string allocated by the caller. To ensure compatibility, allocate 512 characters. A smaller buffer will only be sufficient if the returned message identifier will always be 64 characters or less.

Return Values

The possible return values for the MAPIFindNext function and their meanings are as follows:

MAPI_E_FAILURE

One or more unspecified errors occurred while matching the message type. The call failed before message type matching could take place.

MAPI_E_INSUFFICIENT_MEMORY

There was insufficient memory to proceed. No message was found.

MAPI_E_INVALID_MESSAGE

An invalid message identifier was passed in for SeedMessageID. No message was found.

MAPI_E_INVALID_SESSION

An invalid session handle was passed in for lhSession. No message was found.

MAPI_E_NO_MESSAGES

A matching message could not be found.

SUCCESS_SUCCESS

MAPIFindNext successfully returned the message identifier.

Comments

The MAPIFindNext function allows a client application to enumerate messages of a given type. MAPIFindNext can be called repeatedly to list all messages in the folder. Message identifiers returned from the MAPIFindNext function can be used in other Simple MAPI calls to retrieve message contents and delete messages. MAPIFindNext is for processing incoming messages, not for managing received messages.

When SeedMessageID is NULL or empty, MAPIFindNext returns the message identifier for the first message of the type specified with MessageType. When SeedMessageID contains a valid identifier, MAPIFindNext returns the next matching message of the type specified with MessageType. Repeated calls to MAPIFindNext ultimately result in a return of MAPI_E_NO_MESSAGES, which means the enumeration is complete.

Because message identifiers are messaging system-specific and can be invalidated at any time, message identifiers are valid only for the current session. If the message identifier passed in with SeedMessageID is invalid, MAPIFindNext returns MAPI_E_INVALID_MESSAGE.

Message type matching is done against message class strings. All message types whose names match, up to the length specified in the MessageType parameter are returned.


 MAPILogoff

[New - Windows 95]

The MAPILogoff function ends a session with the messaging system.

Syntax

MAPILogoff(

Session as Long,
UIParam as Long,
Flags as Long,
Reserved as Long) as Long

Parameters

Session

Input parameter specifying a handle for a Simple MAPI session to be terminated. Session handles are returned by MAPILogon and invalidated by MAPILogoff.The value of the Session parameter must represent a valid session; it cannot be zero.

UIParam

Input parameter specifying either a parent window handle or zero, indicating that if a dialog is displayed, it is application modal. If no dialog box is displayed during the call, the UIParam parameter is ignored.

Flags

Reserved for future use;must be zero.

Reserved

Reserved for future use;must be zero.

Return Values

The possible return values for the MAPILogoff function and their meanings are as follows:

MAPI_E_FAILURE

One or more unspecified errors occurred.

MAPI_E_INSUFFICIENT_MEMORY

There was insufficient memory to proceed. The session was not terminated.

MAPI_E_INVALID_SESSION

An invalid session handle was used for the Session parameter. The session was not terminated.

SUCCESS_SUCCESS

MAPILogoff successfully ended the session.


MAPILogon, Simple MAPI Visual Basic function
 MAPILogon

[New - Windows 95]

The MAPILogon function begins a Simple MAPI session, loading the default message store and address book providers.

Syntax

MAPILogon(

UIParam ByVal as Long,
User as String,
Password as String,
Flags as Long,
Reserved as Long,
Session as Long) as Long

Parameters

UIParam

Input parameter specifying either a parent window handle or zero, indicating that if a dialog is displayed, it is application modal. If no dialog box is displayed during the call, the UIParam parameter is ignored.

User

Input parameter specifying a client account-name string, limited to 256 characters or less. This is the name to use when logging on. If the User parameter is empty, and the Flags parameter is set to MAPI_LOGON_UI, the MAPILogon function displays a logon dialog box with an empty name field.

Password

Input parameter specifying a credential string, limited to 256 characters or less. If the messaging system does not require password credentials, or if it requires that the user enter them, Password should be empty. When the user must enter credentials, Flags must be set to MAPI_LOGON_UI to allow a logon dialog box to be displayed.

Flags

Input parameter specifying a bitmask of option flags. The following flags can be set:

MAPI_FORCE_DOWNLOAD

Indicates an attempt should be made to download all of the user's messages before returning. If the MAPI_FORCE_DOWNLOAD flag is not set, messages may be downloaded in the background after the function call returns.

MAPI_LOGON_UI

Indicates that a logon dialog box should be displayed to prompt for logon information. If the user needs to provide information to enable a successful log on, MAPI_LOGON_UI must be set.

MAPI_NEW_SESSION

Indicates an attempt should be made to create a new session rather than acquire the environment's shared session.  If the MAPI_NEW_SESSION flag is not set, the function uses an existing shared session.

Reserved

Reserved for future use; must be zero.

Session

Output parameter specifying a Simple MAPI session handle.

Return Values

The possible return values for the MAPILogon function and their meanings are as follows:

MAPI_E_FAILURE

One or more unspecified errors occurred during sign-on. No session handle was returned.

MAPI_E_INSUFFICIENT_MEMORY

There was insufficient memory to proceed. No session handle was returned.

MAPI_E_LOGIN_FAILURE

There was no default logon, and the user failed to log on successfully when the logon dialog box was displayed. No session handle was returned.

MAPI_E_TOO_MANY_SESSIONS

The user had too many sessions open simultaneously. No session handle was returned.

MAPI_E_USER_ABORT

The user canceled the process. No session handle was returned.

SUCCESS_SUCCESS

A session was successfully established.

Comments

The MAPILogon function begins a session with the messaging system, returning a handle that can be used in subsequent MAPI calls to explicitly provide user credentials to the messaging system. To request the display of a sign-in dialog box if the credentials presented fail to validate the session, set the Flags parameter to MAPI_LOGON_UI.


 MAPIReadMail

[New - Windows 95]

The MAPIReadMail function retrieves a message for reading.

Syntax

MAPIReadMail(

Session as Long,
UIParam as Long,
MessageID as String,
Flags as Long,
Reserved as Long,
Message as MapiMessage,
Originator as MapiRecip,
Recips() as MapiRecip,
Files() as MapiFile) as Long

Parameters

Session

Input parameter specifying a handle to a Simple MAPI session. The value of the Session parameter must represent a valid session; it cannot be zero.

UIParam

Input parameter specifying either a parent window handle or zero, indicating that if a dialog is displayed, it is application modal. If no dialog box is displayed during the call, the UIParam parameter is ignored.

MessageID

Input parameter specifying the message identifier of the message to be read. The MessageID parameter is a variable-length string that be obtained from the MAPIFindNext and MAPISaveMail functions.

Flags

Input parameter specifying a bitmask of flags. The following flags can be set:

MAPI_BODY_AS_FILE

Indicates MAPIReadMail should write the message text to a temporary file and add it as the first attachment in the attachment list.

MAPI_ENVELOPE_ONLY

Indicates MAPIReadMail should read the message header only. File attachments are not copied to temporary files, and neither temporary file names or message text are written. Setting this flag makes MAPIReadMail processing faster.

MAPI_PEEK

Indicates MAPIReadMail does not mark the message as read. Marking a message as read affects its appearance in the user interface and generates a read receipt. If the messaging system does not support this flag, MAPIReadMail always marks the message as read. If MAPIReadMail encounters an error, it leaves the message unread.

MAPI_SUPPRESS_ATTACH

Indicates MAPIReadMail should not copy file attachments, but should write message text into the MapiMessage structure. The function ignores this flag if the calling application has set the MAPI_ENVELOPE_ONLY flag. Setting the MAPI_SUPPRESS_ATTACH flag is a performance enhancement.

Reserved

Reserved for future use;must be zero.

Message

Output parameter specifying a type set by the MAPIReadMail function to a message containing the message contents.

Originator

Output parameter specifying the originator of the message.

Recips

Output parameter specifying an array of recipients. This array is redimensioned as necessary to accommodate the number of recipients chosen by the user.

Files

Output parameter specifying an array of attachment files written when the message is read. When the MAPIReadMail function is called, all message attachments are written to temporary files. It is the caller's responsibility to delete these files when they are no longer needed. When MAPI_ENVELOPE_ONLY or MAPI_SUPPRESS_ATTACH is set, no temporary files are written and no temporary names are filled into the file attachment descriptors. This array is redimensioned as necessary to accommodate the number of files attached by the user.

Return Values

The possible return values for the MAPIReadMail function and their meanings are as follows:

MAPI_E_ATTACHMENT_WRITE_FAILURE

An attachment could not be written to a temporary file. Check directory permissions.

MAPI_E_DISK_FULL

The disk was full.

MAPI_E_FAILURE

One or more unspecified errors occurred while reading the message.

MAPI_E_INSUFFICIENT_MEMORY

There was insufficient memory to read the message.

MAPI_E_INVALID_MESSAGE

An invalid message identifier was passed in for the MessageID parameter.

MAPI_E_INVALID_SESSION

An invalid session handle was passed in for the Session parameter. No message was retrieved.

MAPI_E_TOO_MANY_FILES

There were too many file attachments in the message; the message could not be read.

MAPI_E_TOO_MANY_RECIPIENTS

There were too many recipients of the message; the message could not be read.

SUCCESS_SUCCESS

The message was successfully read.

Comments

The MAPIReadMail function returns one message, breaking the message content into the same parameters and types used in the MAPISendMail function. The MAPIReadMail function fills a block of memory with the MapiMessage type containing message elements. File attachments are saved to temporary files, and the names are returned to the caller in the message type. Recipients, attachments, and contents are copied from the message before the function returns to the caller, so later changes to the files do not affect the contents of the message.

A flag is provided to specify that only envelope informationis to be returned from the call. Another flag, in the MapiMessage type, specifies whether the message is marked as sent or unsent.

All strings are null-terminated and must be specified in the current character set or code page of the application's operating system process. In Microsoft Windows, the character set is ANSI.

The sender, recipients, and file attachments are written into the appropriate parameters of the Visual Basic call. The Recips and Files parameters should be dynamically allocated arrays of their respective types.


 MAPIResolveName

[New - Windows 95]

The MAPIResolveName function transforms a message recipient's name as entered by a user to an unambiguous address list entry.

Syntax

MAPIResolveName(

Session as Long,
UIParam as Long,
UserName as String,
Flags as Long,
Reserved as Long,
Recipient as MapiRecip) as Long

Parameters

Session

Input parameter specifying either a session handle that represents a Simple MAPI session or zero. If the Session parameter is zero, MAPI logs on the user and creates a session that exists only for the duration of the call. The temporary session may be an existing shared session or a new one. If necessary, a logon dialog box is displayed.

UIParam

Input parameter specifying either a parent window handle or zero, indicating that if a dialog is displayed, it is application modal. If no dialog box is displayed during the call, the UIParam parameter is ignored.

UserName

Input parameter specifying the name to be resolved.

Flags

Input parameter specifying a bitmask of option flags. The following flags can be set:

MAPI_AB_NOMODIFY

Indicates the caller is requesting that the dialog be read-only, prohibiting changes. MAPIResolveName ignores this flag if MAPI_DIALOG is not set.

MAPI_DIALOG

Indicates that a dialog box should be displayed for name resolution. If this flag is not set and the name cannot be resolved, the function returns the MAPI_E_AMBIGUOUS_RECIPIENT value.

MAPI_LOGON_UI

Indicates that a dialog box should be displayed to prompt for logon if required. When the MAPI_LOGON_UI flag is not set, the application does not display a logon dialog box and returns an error if the user is not logged on.

MAPI_NEW_SESSION

Indicates an attempt should be made to create a new session rather than acquire the environment's shared session.  If the MAPI_NEW_SESSION flag is not set, the function uses an existing shared session.

Reserved

Reserved for future use;must be zero.

Recipient

Output parameter specifying a recipient-type set returned by the MAPIResolveName function if the resolution results in a single match. The type contains the recipient information of the resolved name. The descriptor can then be used in calls to the MAPISendMail, MAPISaveMail, and MAPIAddress functions.

Return Values

The possible return values for the MAPIResolveName function and their meanings are as follows:

MAPI_E_AMBIGUOUS_RECIPIENT

The recipient requested has not or could not be resolved to a unique address list entry.

MAPI_E_FAILURE

One or more unspecified errors occurred and the name was not resolved.

MAPI_E_INSUFFICIENT_MEMORY

There was insufficient memory to proceed. The name was not resolved.

MAPI_E_LOGIN_FAILURE

There was no default logon, and the user failed to log on successfully when the logon dialog box was displayed. The name was not resolved.

MAPI_E_NOT_SUPPORTED

The operation was not supported by the underlying messaging system.

MAPI_E_USER_ABORT

The user canceled the resolution; the name was not resolved.

SUCCESS_SUCCESS

The name was successfully resolved.

Comments

The MAPIResolveName function resolves a message recipient's name (as entered by a user) to an unambiguous address list entry, optionally prompting the user to choose between possible entries, if necessary. A recipient descriptor containing fully resolved information about the entry is allocated and returned.


 MAPISaveMail

[New - Windows 95]

The MAPISaveMail function saves a message.

Syntax

MAPISaveMail(

Session as Long,
UIParam as Long,
Message as MapiMessage,
Recips as MapiRecip,
Files as MapiFile,
Flags as Long,
Reserved ByVal as Long,
MessageID as String) as Long

Parameters

Session

Input parameter specifying either a session handle that represents a Simple MAPI session or zero. If the Session parameter is zero, MAPI logs on the user and creates a session that exists only for the duration of the call. The temporary session may be an existing shared session or a new one. If necessary, a logon dialog box is displayed.

UIParam

Input parameter specifying either a parent window handle or zero, indicating that if a dialog is displayed, it is application modal. If no dialog box is displayed during the call, the UIParam parameter is ignored.

Message

Input parameter specifying the contents of the message to be saved. Applications can either ignor the Flags member, or, if the message has never been saved, can set the MAPI_SENT and MAPI_UNREAD bits.

Recips

Input parameter specifying the first element in an array of recipients. When the RecipCount field in the MapiMessage type is zero, this parameter is ignored.The recipient string can include either the recipient's name or the recipient's name-address pair. If only a name is specified, the name is resolved to an address using implementation-defined address-book search rules. If an address is also specified, a search for the name is not performed. The address is in an implementation-defined format and is assumed to have been obtained from the implementation some other way. When the address is specified, the name is used for display to the user and the address is used for delivery.When the EntryID field is used, no search is performed and the display-name and address are ignored. (A name and address are associated with the EntryID within the messaging system.)

Files

Input parameter specifying the first element in an array of attachment files written when the message is read. The number of attachments per message may be limited in some systems. If the limit is exceeded, the MAPI_E_TOO_MANY_FILES value is returned. When the FileCount field in the MapiMessage type is zero, this parameter is ignored. Attachment files are read and attached to the message before the call returns. Do not attempt to display attachments outside the range of the message body.

Flags

Input parameter specifying a bitmask of option flags. The following flags can be set:

MAPI_LOGON_UI

Indicates that a dialog box should be displayed to prompt for logon if required. When the MAPI_LOGON_UI flag is not set, the application does not display a logon dialog box and returns an error if the user is not logged on. The MAPISaveMail function ignores this flag if the lpszMessageID parameter is empty.

MAPI_LONG_MSGID

Indicates that the returned message identifier is expected to be 512 characters. If this flag is set, the lpszMessageID parameter must be large enough to accomodate 512 characters.

MAPI_NEW_SESSION

Indicates an attempt should be made to create a new session rather than acquire the environment's shared session.  If the MAPI_NEW_SESSION flag is not set, the function uses an existing shared session.

Reserved

Reserved for future use;must be zero.

MessageID

Input parameter specifying a variable-length, caller-allocated string identifier for the message, returned either by the MAPIFindNext function or a previous call to the MAPISaveMail function, or a null string. If the MessageID parameter contains a valid message identifier, the message is overwritten. If the parameter contains a null string, a new message is created.

Return Values

The possible return values for the MAPISaveMail function and their meanings are as follows:

MAPI_E_FAILURE

One or more unspecified errors occurred while saving the message; no message was saved.

MAPI_E_INSUFFICIENT_MEMORY

There was insufficient memory to save the message; no message was saved.

MAPI_E_INVALID_MESSAGE

An invalid message identifier was passed in for the MessageID parameter; no message was saved.

MAPI_E_INVALID_SESSION

An invalid session handle was passed for the Session parameter; no message was saved.

MAPI_E_LOGIN_FAILURE

There was no default logon, and the user failed to log on successfully when the logon dialog box was displayed. No message was saved.

MAPI_E_NOT_SUPPORTED

The operation was not supported by the underlying messaging system.

MAPI_E_USER_ABORT

The user canceled the process; no message was saved.

SUCCESS_SUCCESS

MAPISaveMail saved the message successfully.

Comments

To replace an existing message, the caller first calls the MAPIFindNext function to locate the message to be replaced and then calls the MAPISaveMail function with the MessageID parameter set with a valid message identifier. The elements of the message identified by the MessageID parameter are replaced by the elements in the MAPIMessage type pointed to by the Message parameter.

To create a new message, the caller passes an empty string for the MessageID parameter. New messages are saved in the folder appropriate for incoming messages of that class. The new message identifier is returned in the MessageID parameter on completion.

The MessageID parameter must be a variable-length string. The elements of the message identified by the MessageID parameter are replaced by the elements in the Message parameter. If the MessageID parameter is empty, a new message is created.

The Visual Basic MAPISaveMail function takes the recipients and file attachments from the Recips and Files parameters, which should each be the first element of dynamically allocated arrays of their respective types. These arrays are not redimensioned.


 MAPISendDocuments

[New - Windows 95]

The MAPISendDocuments function sends a standard message with one or more attached files and a cover note. The cover note is a dialog box that allows the user to enter a list of recipients and an optional message.

Syntax

MAPISendDocuments(

UIParam as Long,
DelimChar as String,
FullPaths as String,
FileNames as String,
Reserved as Long) as Long

Parameters

UIParam

Input parameter specifying either a parent window handle or zero, indicating that if a dialog is displayed, it is application modal. If no dialog box is displayed during the call, the UIParam parameter is ignored.

DelimChar

Input parameter specifying a string containing the character used to delimit the names in the FullPaths and FileNames parameters. This character should not be used in filenames on your operating system.

FullPaths

Input parameter specifying a string containing the list of full paths, including drive letters, for the attached files. The list is formed by concatenating correctly formed filepaths separated by the character specified in the DelimChar parameter. An example of a valid list is:

C:\TMP\TEMP1.DOC;C:\TMP\TEMP2.DOC

The files specified in this parameter are added to the message as file attachments. If this parameter contains an empty string, the Send Note dialog box is displayed with no attached files.

FileNames

Input parameter specifying a string containing the list of the original filenames as they should be displayed in the message. When multiple names are specified, the list is formed by concatenating the filenames separated by the character specified in the DelimChar parameter. An example is:

MEMO.DOC;EXPENSES.DOC

If there is no value for the FileNames parameter or if it is empty, the MAPISendDocuments function sets the filenames set to the filename values indicated by FullPaths.

Reserved

Reserved for future use;must be zero.

Return Values

The possible return values for the MAPISendDocuments function and their meanings are as follows:

MAPI_E_ATTACHMENT_NOT_FOUND

An attachment could not be located at the specified path. Either the drive letter was invalid, the path was not found on that drive, or the file was not found in that path.

MAPI_E_ATTACHMENT_OPEN_FAILURE

One or more files in the FullPaths parameter could not be located. No message was sent.

MAPI_E_ATTACHMENT_WRITE_FAILURE

An attachment could not be written to a temporary file. Check directory permissions.

MAPI_E_FAILURE

One or more unspecified errors occurred while sending the message. It is not known if the message was sent.

MAPI_E_INSUFFICIENT_MEMORY

There was insufficient memory to proceed.

MAPI_E_LOGIN_FAILURE

There was no default logon, and the user failed to log on successfully when the logon dialog box was displayed. No message was sent.

MAPI_E_USER_ABORT

The user canceled the process; no message was sent.

SUCCESS_SUCCESS

MAPISendDocuments sent the message successfully.

Comments

Calling the MAPISendDocuments function displays a Send Note dialog box, which prompts the user to send a message with data file attachments. Attachments can include the active document or all the currently open documents in the Windows-based application that called the MAPISendDocuments function. The function is used primarily for calls from a macro or scripting language, often found in applications such as spreadsheet or word-processing programs.

There is no default identification when this function is called; a standard logon dialog box appears. After the user provides a mailbox name and password, the Send Note dialog box appears.

The user's default messaging options are used as the default dialog box values. The function caller is responsible for deleting temporary files created when using this function.


 MAPISendMail

[New - Windows 95]

The MAPISendMail function sends a standard message.

Syntax

MAPISendMail(

Session as Long,.
UIParam as Long,
Message as MapiMessage,
Recips as MapiRecip,
Files as MapiFile,
Flags as Long,
Reserved as Long) as Long

Parameters

Session

Input parameter specifying either a session handle that represents a Simple MAPI session or zero. If the Session parameter is zero, MAPI logs on the user and creates a session that exists only for the duration of the call. The temporary session may be an existing shared session or a new one. If necessary, a logon dialog box is displayed.

UIParam

The parent window handle for the dialog box. A value of zero specifies that any dialog box displayed is application modal.

Message

Input parameter specifying the message to be sent. An empty string indicates no text. Each paragraph should be terminated with either a carriage return (0x0d), a line feed (0x0a), or a carriage return−line feed pair (0x0d0a). The implementation wraps lines as appropriate. Implementations may place limits on the size of the text. The MAPI_E_TEXT_TOO_LARGE value is returned if this limit is exceeded. Client applications can set MAPI_RECEIPT_REQUESTED in the Flags member to ask for a read report.

Recips

Input parameter specifying the first element of an array of recipients. When the RecipCount field in the Message parameter is zero, this parameter is ignored. The Recips parameter can include either an entry identifier, the recipient's name, an address, or a name and address pair. Depending on the type and amount of information passed, MAPISendMail will perform varied levels of name resolution. If an entry identifier in the EntryID field is specified, the MAPISendMail function performs no lookup and ignores the name and address. If only a name is specified, MAPISendMail resolves the name to a valid address using name resolution rules defined by Simple MAPI. If only an address is specified, MAPISendMail uses this address for both message delivery and for displaying the recipient name; no name resolution occurs. If both a name and address are specified, again the MAPISendMail function does not resolve the name. The specified name is used as the display name and not for resolution.

Files

Input parameter specifying the first element of an array of attachment files written when the message is read. The number of attachments per message might be limited in some systems. If the limit is exceeded, the message MAPI_E_TOO_MANY_FILES is returned. When the FileCount field in the MapiMessage type pointed to by the Message parameter is zero, this parameter is ignored. Attachment files are read and attached to the message before the call returns. Do not attempt to display attachments outside the range of the message body.

Flags

Input parameter specifying a bitmask of option flags. The following flags can be set:

MAPI_DIALOG

Indicates that a dialog box should be displayed to prompt the user for recipients and other sending options. Set the MAPI_LOGON_UI flag if the function should display a dialog box to prompt for log on. When this flag is not set, the function does not display a dialog box and returns a message if the user is not signed in.

MAPI_LOGON_UI

Indicates that a dialog box should be displayed to prompt for logon if required. When the MAPI_LOGON_UI flag is not set, the application does not display a logon dialog box and returns an error if the user is not logged on. MAPISaveMail ignores this flag if the MessageID parameter is empty.

MAPI_NEW_SESSION

Indicates an attempt should be made to create a new session rather than acquire the environment's shared session.  If the MAPI_NEW_SESSION flag is not set, the function uses an existing shared session.

Reserved

Reserved for future use; must be zero.

Return Values

The possible return values for the MAPISendMail function and their meanings are as follows:

MAPI_E_AMBIGUOUS_RECIPIENT

A recipient matched more than one of the recipient descriptor structures and MAPI_DIALOG was not set. No message was sent.

MAPI_E_ATTACHMENT_NOT_FOUND

The specified attachment was not found; no message was sent.

MAPI_E_ATTACHMENT_OPEN_FAILURE

The specified attachment could not be open; no message was sent.

MAPI_E_BAD_RECIPTYPE

The type of a recipient was not MAPI_TO, MAPI_CC, or MAPI_BCC. No message was sent.

MAPI_E_FAILURE

One or more unspecified errors occurred; no message was sent.

MAPI_E_INSUFFICIENT_MEMORY

There was insufficient memory to proceed. No message was sent.

MAPI_E_LOGIN_FAILURE

There was no default logon, and the user failed to log on successfully when the logon dialog box was displayed. No message was sent.

MAPI_E_TEXT_TOO_LARGE

The text in the message was too large to sent; the message was not sent.

MAPI_E_TOO_MANY_FILES

There were too many file attachments; no message was sent.

MAPI_E_TOO_MANY_RECIPIENTS

There were too many recipients; no message was sent.

MAPI_E_UNKNOWN_RECIPIENT

A recipient did not appear in the address list; no message was sent.

MAPI_E_USER_ABORT

The user canceled the process; no message was sent.

SUCCESS_SUCCESS

MAPISendMail successfully sent the message.

Comments

MAPISendMail sends a standard message, with or without any user interaction. If recipient names, file attachments, or message text are provided, the MAPISendMail function can send the files or note without prompting users. If the optional parameters are specified and a dialog box is requested by use of the MAPI_DIALOG flag, the parameters provide the initial values for the dialog box.

File attachments are copied to the message before the function returns; therefore, later changes to the files do not affect the contents of the message. The files must be closed when they are copied.

The Visual Basic MAPISendMail function takes the recipients and file attachments from the Recips and Files parameters, which should each be the first element of dynamically allocated arrays of their respective types. These arrays are not redimensioned.

All strings must be specified in the current character set or code page of your application's operating system process.


 Simple MAPI Data Types for Visual Basic

Visual Basic uses a different set of calling and programming conventions than  C and C++ do. Different structure and parameter definitions support the Visual Basic representation of strings and of structures, which in Visual Basic are called types. The following list describes how programming Simple MAPI Visual Basic applications differs from programming Simple MAPI C and C++ applications:

•	In C and C++, structures can contain pointers to other structures. Because the concept of a pointer is foreign to Visual Basic, extra function parameters are used instead of these complex structures.

•	Because the Visual Basic MAPI functions are declared, it is not necessary to explicitly cast passed arguments using ByVal.

•	An empty string in a string variable is equivalent to a NULLvalue.

•	Arrays must be dynamically declared so that they are redimensioned when the Simple MAPI function is executed.

•	Visual Basic manages memory, eliminating the need for calling the MAPIFreeBuffer function.

•	All structures used in the Visual Basic version of Simple MAPI are Visual Basic types rather than C-language structures.

•	All strings used in the Visual Basic version of Simple MAPI are Visual Basic strings rather than C-language strings.

The following section describes the three Simple MAPI types for Visual Basic.


 MapiFile

[New - Windows 95]

The MapiFile type contains file attachment information.

Syntax

Type MapiFile
Reserved as Long
Flags as Long
Position as Long
PathName as String
FileName as String
FileType as String
End Type

Members

Reserved

Reserved for future use; must be zero.

Flags

A bitmask of flags. The following flags can be set:

MAPI_OLE

Indicates the attachment is an OLE Object file attachment. If MAPI_OLE_STATIC is also set, the object is static. If neither flag is set, the attachment is simply a data file.

MAPI_OLE_STATIC

Indicates a static OLE object file attachment.

Position

An integer describing where the attachment should be placed in the message body. Attachments replace the character found at a certain position in the message body; in other words, attachments replace the MapiMessage member NoteText[Position]. Applications cannot place two attachments in the same location within a message, and attachments cannot be placed beyond the end of the message body.

PathName

The full path name of the attached file. The file should be closed before this call is made.

FileName

The filename seen by the recipient. This name can differ from the filename in PathName if temporary files are being used. If FileName is empty, the filename from PathName is used. If the attachment is an OLE object, FileName contains the class name of the object, such as "Microsoft Excel Worksheet."

FileType

A reserved descriptor that tells the recipient the type of the attached file. An empty string indicates an unknown or operating system−determined file type. With this release, you must use "" for this parameter.

Comments

Simple MAPI for Visual Basic supports the following kinds of attachments:

•	Data files

•	Embedded OLE objects

•	Static OLE objects

The Flags member determines the kind of attachment. OLE (object linking and embedding) object files are file representations of OLE object streams. You can re-create an OLE object from the file by calling the OleLoadFromStream function with an OLESTREAM object that reads the file contents. If an OLE file attachment is included in an outbound message, the OLE object stream should be written directly to the file used as the attachment.


 MapiMessage

[New - Windows 95]

The MAPIMessage type contains message information.

Syntax

Type MapiMessage
Reserved as Long
Subject as String
NoteText as String
MessageType as String
DateReceived as String
ConversiondID as String
Flags as Long
Originator as Long
RecipCount as Long
FileCount as Long
End Type

Members

Reserved

Reserved for future use. This field must be 0.

Subject

The subject text, limited to 256 characters or less. (Messages saved with MAPISaveMail are not limited to 256 characters.) An empty string indicates no subject text.

NoteText

A string containing text in the message. An empty string indicates no text. For inbound messages, each paragraph is terminated with a carriage return−line feed pair (0x0d0a). For outbound messages, paragraphs can be delimited with a carriage return, a line feed, or a carriage return−line feed pair (0x0d, 0x0a, or 0x0d0a).

MessageType

A message type string used by applications other than interpersonal electronic mail. An empty string indicates an interpersonal message (IPM) type.

DateReceived

A string indicating the date a message is received. The format is YYYY/MM/DD HH:MM; hours are measured on a 24-hour clock.

ConversationID

A string indicating the conversation thread ID to which this message belongs.

Flags

A bitmask of flags. The following flags can be set:

MAPI_RECEIPT_REQUESTED

Indicates a receipt notification is requested.

MAPI_SENT

Indicates the message has been sent.

MAPI_UNREAD

Indicates the message has not been read.

Originator

A MapiFile type that describes the sender of the message.

RecipCount

A count of the recipient descriptor types. A value of 0 indicates that no recipients are included.

FileCount

A count of the file attachment descriptor types. A value of 0 indicates that no file attachments are included.


 MapiRecip

[New - Windows 95]

The MAPIRecip type contains recipient information.

Syntax

Type MapiRecip
Reserved as Long
RecipClass as Long
Name as String
Address as String
EIDSize as Long
EntryID as String
End Type

Members

Reserved

Reserved for future use. This member must be zero.

RecipClass

Classifies the recipient of the message. (Messages can be sorted by recipient class.) This field can also contain information about the originator of an inbound message.

Name

The name of the recipient that is displayed by the messaging system.

Address

Provider-specific message delivery data. This can be used by the message system to identify custom recipients who are not in an address list.

EIDSize

The size (in bytes) of the data in EntryID.

EntryID

A string used by the messaging system to uniquely identify the recipient. Unlike the Address field, this data is opaque and is not printable. The messaging system returns valid EntryIDs for recipients or senders included in the address list.


 Essential Extended MAPI Functions

This chapter contains a reference entry for each function.


 ABProviderInit

[New - Windows 95]

Initializes an address book provider for operation.

Syntax

HRESULT ABProviderInit(HINSTANCE hInstance, LPMALLOC lpMalloc, LPALLOCATEBUFFER lpAllocateBuffer, LPALLOCATEMORE lpAllocateMore, LPFREEBUFFER lpFreeBuffer, ULONG ulFlags, ULONG ulMAPIVer, ULONG FAR* lpulProviderVer, LPABPROVIDER FAR* lppABProvider)

Parameters

hInstance

Input parameter containing an instance of the address book provider's dynamic-link library (DLL) that MAPI used when it linked.

lpMalloc

Input parameter pointing to a standard memory allocator.

lpAllocateBuffer

Input parameter pointing to the MAPIAllocateBuffer function, to be used to allocate memory.

lpAllocateMore

Input parameter pointing to the MAPIAllocateMore function, to be used to allocate additional memory where required.

lpFreeBuffer

Input parameter pointing to the MAPIFreeBuffer function, to be used to free memory.

ulFlags

Reserved; do not use.

ulMAPIVer

Input parameter containing the version of the service provider interface that MAPI.DLL uses. For the current version number, see the MAPISPI.H header file.

lpulProviderVer

Input parameter pointing to the version of the service provider interface that the message store uses.

lppABProvider

Output parameter pointing to a variable where the initialized address-book provider object returned is stored

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

To initialize an address book provider, MAPI calls the function named ABProviderInit, based on the ABPROVIDERINIT function prototype defined in MAPISPI.H, from the address book provider's DLL. The address book provider must use its implementation of ABProviderInit to respond to the MAPI initialization call.

The address book provider must also define ABProviderInit using the CDECL calling convention. CDECL definition is required for each service-provider initialization function to ensure the function can work with the current version of the service provider interface, even if the number of function parameters used is not the number set for that function in the current version of the interface. MAPI provides the APPROVIDERINIT prototype to help define ABProviderInit as CDECL. The APPROVIDERINIT prototype has a standard MAPI initialization call type, STDMAPIINITCALLTYPE.

The input parameters lpAllocateBuffer, lpAllocateMore, and lpFreeBuffer point to the MAPIAllocateBuffer, MAPIAllocateMore, and MAPIFreeBuffer functions, respectively, for use by the address-book provider DLL. The provider DLL should not be linked with MAPIX.DLL. Instead, it should use these pointers for memory allocation or deallocation. In particular, the provider must use these pointers when allocating memory for use by client applications in calling object interfaces. For example, two provider interface methods that typically allocate memory are IMAPIProp::GetProps and IMAPITable::QueryRows.

The address book provider should retain information on the allocator pointers passed to it in lpAllocateBuffer, lpAllocateMore, and lpFreeBuffer. If the provider will use a memory allocator later, it should call the IUnknown::AddRef method for the allocation object pointed to by the lpMalloc parameter.

For more information on using ABProviderInit, see the information on using the MSProviderInit, ABProviderInit, and XPProviderInit functions in MAPI Programmer's Guide.

The ABProviderInit function is defined in MAPISPI.H.

See Also

HPProviderInit function, IMAPIProp::GetProps method, IMAPITable::QueryRows method, MAPIAllocateBuffer function, MAPIAllocateMore function, MAPIFreeBuffer function, MSProviderInit function, XPProviderInit function


 BuildDisplayTable

[New - Windows 95]

Creates a display table from the property page data contained in a DTPAGE structure.

Syntax

BuildDisplayTable(LPALLOCATEBUFFER lpAllocateBuffer, LPALLOCATEMORE lpAllocateMore, LPFREEBUFFER lpFreeBuffer, LPVOID lpvReserved, HINSTANCE hInstance, UINT cPages, LPDTPAGE lpPage, ULONG ulFlags, LPMAPITABLE* lppTable, LPTABLEDATA* lppTblData)

Parameters

lpAllocateBuffer

Input parameters pointing to the MAPIAllocateBuffer function, to be used to allocate memory.

lpAllocateMore

Input parameter pointing to the MAPIAllocateMore function, to be used to allocate additional memory where required.

lpFreeBuffer

Input parameter pointing to the MAPIFreeBuffer function, to be used to free memory.

lpvReserved

Reserved, must be zero.

hInstance

Input parameter containing an instance of a MAPI object from which the BuildDisplayTable function retrieves resources.

cPages

Input parameter containing the number of DTPAGE structures pointed to by the lpPage parameter.

lpPage

Input parameter pointing to one or more DTPAGE structures that hold information about the display table to be built.

ulFlags

Input parameter containing a bitmask of flags. The following flag can be set:

MAPI_UNICODE

Indicates the passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

lppTable

Input parameter pointing to the IMAPITable interface for the display table.

lppTblData

Input-output parameter pointing to the ITableData interface for the object that contains table data for the display table. On input, the pointer is NULL to indicate that the existing table data object has been released. On output, the pointer indicates a display table returned by BuildDisplayTable.

Comments

The input parameters lpAllocateBuffer, lpAllocateMore, and lpFreeBuffer point to the MAPIAllocateBuffer, MAPIAllocateMore, and MAPIFreeBuffer functions, respectively. If a client application calls BuildDisplayTable, it passes in these parameters pointers to the functions named as listed. If a service provider calls BuildDisplayTable, it passes the pointers to these functions it received in its initialization call or retrieved by calling the IMAPISupport::GetMemAllocRoutines method.

The BuildDisplayTable function is defined in MAPIUTIL.H.

See Also

DTPAGE structure, IMAPISupport::GetMemAllocRoutines method, IMAPITable : IUnknown interface, ITableData : IUnknown interface, MAPIAllocateBuffer function, MAPIAllocateMore function, MAPIFreeBuffer function


 CheckParameters

[New - Windows 95]

Checks debugging parameters on methods called by MAPI.

Syntax

HRESULT CheckParameters(METHODS eMethod, LPVOID First)

Parameters

eMethod

Specifies the method to validate.

First

Specifies the address of the beginning of the method.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

In contrast to the ValidateParameters function, CheckParameters does not perform a full parameter validation. Parameters passed between MAPI and providers are assumed to be correct; therefore this function performs a debug validation only.

For more information on parameter validation, see MAPI Programmer's Guide.

The CheckParameters function is defined in MAPIVAL.H

See Also

ulValidateParameters function, ValidateParameters function


 CreateIProp

[New - Windows 95]

Creates a property data object (that is, an IPropData object).

Syntax

SCODE CreateIProp(LPCIID lpInterface, ALLOCATEBUFFER FAR* lpAllocateBuffer, ALLOCATEMORE FAR* lpAllocateMore, FREEBUFFER FAR* lpFreeBuffer, LPVOID lpvReserved, LPPROPDATA FAR* lppPropData)

Parameters

lpInterface

Input parameter pointing to an interface identifier (IID) for the property data object.

lpAllocateBuffer

Input parameter pointing to the MAPIAllocateBuffer function, to be used to allocate memory.

lpAllocateMore

Input parameter pointing to the MAPIAllocateMore function, to be used to allocate additional memory where required.

lpFreeBuffer

Input parameter pointing to the MAPIFreeBuffer function, to be used to free memory.

lpvReserved

Reserved, must be zero.

lppPropData

Output parameter pointing to a variable where the returned property data object is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_INTERFACE_NOT_SUPPORTED

The requested interface is not supported for this object.

Comments

The input parameters lpAllocateBuffer, lpAllocateMore, and lpFreeBuffer point to the MAPIAllocateBuffer, MAPIAllocateMore, and MAPIFreeBuffer functions, respectively. If a client application calls CreateIProp, it passes in these parameters pointers to the functions named as listed. If a service provider calls CreateIProp, it passes the pointers to these functions it received in its initialization call or retrieved with a call to the IMAPISupport::GetMemAllocRoutines method.

The CreateIProp function is defined in MAPIUTIL.H.

See Also

Chapter 5, "Extended MAPI Properties," IMAPISupport::GetMemAllocRoutines method, IPropData : IMAPIProp interface, MAPIAllocateBuffer function, MAPIAllocateMore function, MAPIFreeBuffer function


 CreateTable

[New - Windows 95]

Creates a table data object (that is, an ITableData object) that can be used to create table views.

Syntax

SCODE CreateTable(LPCIID lpInterface, ALLOCATEBUFFER FAR* lpAllocateBuffer, ALLOCATEMORE FAR* lpAllocateMore, FREEBUFFER FAR* lpFreeBuffer, LPVOID lpvReserved, ULONG ulTableType, ULONG ulPropTagIndexColumn, LPSPropTagArray lpSPropTagArrayColumns, LPTABLEDATA FAR* lppTableData)

Parameters

lpInterface

Input parameter pointing to an interface identifier (IID) for the table data object. Passing NULL in the lpInterface parameter indicates that the table data object returned in the lppTableData parameter is cast to the standard interface for a table data object; the valid interface identifier is IID_IMAPITableData.

lpAllocateBuffer

Input parameter pointing to the MAPIAllocateBuffer function, to be used to allocate memory.

lpAllocateMore

Input parameter pointing to the MAPIAllocateMore function, to be used to allocate additional memory where required.

lpFreeBuffer

Input parameter pointing to the MAPIFreeBuffer function, to be used to free memory.

lpvReserved

Reserved, must be zero.

ulTableType

Input parameter containing a table type that is available to the client application or service provider as part of the IMAPITable::GetStatus return data on its table views. Possible values are:

TBLTYPE_DYNAMIC

The table's contents are dynamic and can change as the underlying data changes.

TBLTYPE_SNAPSHOT

The table is static and the contents do not change when the underlying data changes.

TBLTYPE_KEYSET

The rows within the table are fixed, but the values within these rows are dynamic and can change as the underlying data changes.

ulPropTagIndexColumn

Input parameter containing the index number of the column for use when changing table data.

lpSPropTagArrayColumns

Input parameter pointing to an SPropTagArray structure containing an array of property tags indicating the properties required in the table for which the object holds data.

lppTableData

Output parameter pointing to a variable where the pointer to the returned table data object is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

The input parameters lpAllocateBuffer, lpAllocateMore, and lpFreeBuffer point to the MAPIAllocateBuffer, MAPIAllocateMore, and MAPIFreeBuffer functions, respectively. If a client application calls the CreateTable function, it passes in these parameters pointers to the functions named as listed. If a service provider calls CreateTable, it passes the pointers to these functions that it received in its initialization call or retrieved with a call to the IMAPISupport::GetMemAllocRoutines method.

The CreateTable function is defined in MAPIUTIL.H.

See Also

IMAPISupport::GetMemAllocRoutines method, IMAPITable::GetStatus method, IMAPITable : IUnknown interface, MAPIAllocateBuffer function, MAPIAllocateMore function, MAPIFreeBuffer function, SPropTagArray structure


 FreePadrlist

[New - Windows 95]

Destroys an ADRLIST structure and frees associated memory, including memory allocated for all member structures.

Syntax

void FreePadrlist(LPADRLIST padrlist)

Parameters

padrlist

Input parameter pointing to the ADRLIST structure to be destroyed.

Comments

Usually, MAPI assigns the MAPIAllocateBuffer function as the function to free memory, but it can designate any other comparable function if necessary.

The FreePadrlist function is defined in MAPIUTIL.H.

See Also

ADRLIST structure, MAPIAllocateBuffer function


 FreeProws

[New - Windows 95]

Destroys an SRowSet structure and frees associated memory, including memory allocated for all member structures.

Syntax

void FreeProws(LPSRowSet prows)

Parameters

prows

Input parameter pointing to the SRowSet structure to be destroyed.

Comments

Usually, MAPI assigns the MAPIAllocateBuffer function as the function to free memory, but it can designate any other comparable function if necessary.

The FreeProws function is defined in MAPIUTIL.H.

See Also

MAPIAllocateBuffer function, SRowSet structure


 GetAttribIMsgOnIStg

[New - Windows 95]

Retrieves the attributes of the properties of a particular object.

Syntax

GetAttribIMsgOnIStg(LPVOID lpObject, LPSPropTagArray lpPropTagArray, LPSPropAttrArray FAR* lppPropAttrArray)

Parameters

lpObject

Input parameter pointing to the object for which property attributes are being retrieved.

lpPropTagArray

Input parameter pointing to an SPropTagArray structure containing an array of property tags indicating the properties for which attributes are being retrieved.

lppPropAttrArray

Output parameter pointing to a variable where the returned SPropAttrArray structure is stored. This SPropAttrArray structure holds the retrieved property attributes.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_W_ERRORS_RETURNED

The call succeeded overall, but one or more properties could not be accessed and were returned with a property type of PT_ERROR.

Comments

MAPI provides this function because there is no method of the IMAPIProp interface that enables the retrieval of attributes.

The GetAttribIMsgOnIStg function is defined in IMESSAGE.H.

See Also

IMAPIProp : IUnknown interface, SetAttribIMsgOnIStg function, SPropAttrArray structure, SPropTagArray structure


 HPProviderInit

[New - Windows 95]

Initializes a message hook provider for operation.

Syntax

HRESULT HpProviderInit(LPMAPISESSION lpSession, HINSTANCE hInstance, LPALLOCATEBUFFER lpAllocateBuffer, LPALLOCATEMORE lpAllocateMore, LPFREEBUFFER lpFreeBuffer, LPMAPIUID lpSectionUID, ULONG ulFlags, LPSPOOLERHOOK FAR* lppSpoolerHook)

Parameters

lpSession

Input parameter pointing to a copy of the object representing the MAPI spooler session. Because the session object is a copy, any component installed as part of the message hook provider must be considered "trusted code." The message hook provider should call the IUnknown::AddRef method for the session object.

hInstance

Input parameter containing an instance of the message hook provider's dynamic-link library (DLL) that MAPI used when it linked.

lpAllocateBuffer

Input parameter pointing to the MAPIAllocateBuffer function, to be used by the message hook provider to allocate memory.

lpAllocateMore

Input parameter pointing to the MAPIAllocateMore function, to be used by the message hook provider to allocate additional memory where required.

lpFreeBuffer

Input parameter pointing to the MAPIFreeBuffer function, to be used by the message hook provider to free memory.

lpSectionUID

Input parameter pointing to the MAPI unique identifier (MAPIUID) of the message hook provider's profile section. The HPProviderInit function can open this identifier using a session-level call to the IMAPISupport::OpenProfileSection method. However, because MAPI and the MAPI spooler control some properties in the session, the provider should use the range of provider-specific property identifiers for storage and retrieval of profile section properties.

ulFlags

Input parameter containing a bitmask of flags used to control whether the message hook provider is called for incoming or outgoing messages. The following flags can be set:

HOOK_INBOUND

Indicates that the message hook provider processes messages inbound to the MAPI spooler.

HOOK_OUTBOUND

Indicates that the message hook provider processes messages outbound from the MAPI spooler.

lppSpoolerHook

Output parameter pointing to a variable where the initialized message-hook provider returned is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

To initialize a message hook provider, MAPI calls the function named HPProviderInit, based on the HPPROVIDERINIT function prototype defined in MAPIHOOK.H, from the message hook provider's DLL. The message hook provider must use its implementation of HPProviderInit to respond to the MAPI initialization call.

The message hook provider must also define HPProviderInit using the CDECL calling convention. CDECL definition is required for each service-provider initialization function to ensure the function can work with the current version of the service provider interface, even if the number of function parameters used is not the number set for that function in the current version of the interface. MAPI provides the HPPROVIDERINIT prototype to help define HPProviderInit as CDECL. The HPPROVIDERINIT prototype has a standard MAPI initialization call type, STDMAPIINITCALLTYPE.

In some respects, a message hook provider resembles a client application extension to the MAPI spooler more closely than it resembles a service provider, because it is an active process. The MAPI spooler, the process that sends and delivers messages through transport providers, is the only process not driven directly by client application actions.

Another difference between the message hook provider and other service providers is that HPProviderInit creates a session object. In contrast, other providers' initialization functions usually create support objects.

The input parameters lpAllocateBuffer, lpAllocateMore, and lpFreeBuffer point to the MAPIAllocateBuffer, MAPIAllocateMore, and MAPIFreeBuffer functions, respectively, for use by the message-hook provider DLL. The provider DLL should not be linked with MAPIX.DLL. Instead, it should use these pointers for memory allocation or deallocation. In particular, the provider must use these pointers when allocating memory for use by client applications in calling object interfaces. For example, two provider interface methods that typically allocate memory are IMAPIProp::GetProps and IMAPITable::QueryRows.

The message hook provider should retain information on the allocator pointers passed to it in lpAllocateBuffer, lpAllocateMore, and lpFreeBuffer. If the message hook provider will use a memory allocator later, it should call the IUnknown::AddRef method for the allocation object pointed to by the lpMalloc parameter.

If the provider needs to use mutex objects or critical sections, it should set them up during initialization using HPProviderInit. A mutex object should be owned by the message-hook provider object created by this function.

For more information on using ABProviderInit, see the information on using the MSProviderInit, ABProviderInit, and XPProviderInit functions in MAPI Programmer's Guide.

The GetAttribIMsgOnIStg function is defined in MAPIHOOK.H.

See Also

ABProviderInit function, IMAPIProp::GetProps method, IMAPISession : IUnknown interface, IMAPISupport::OpenProfileSection method, IMAPITable::QueryRows method, MAPIAllocateBuffer function, MAPIAllocateMore function, MAPIFreeBuffer function, MSProviderInit function, XPProviderInit function


 HrAddColumnsEx

[New - Windows 95]

Adds or moves columns to the beginning of an existing table.

Syntax

HRESULT HrAddColumnsEx(LPMAPITABLE lptbl, LPSPropTagArray lpproptagColumnsNew, LPALLOCATEBUFFER lpAllocateBuffer, LPFREEBUFFER lpFreeBuffer, void (FAR* lpfnFilterColumns) (LPSPropTagArray ptaga)

Parameters

lptbl

Input parameter pointing to the MAPI table affected.

lpproptagColumnsNew

Input parameter holding an SPropTagArray structure containing an array of property tags indicating the properties to be added or moved to the beginning of the table.

lpAllocateBuffer

Input parameter pointing to the MAPIAllocateBuffer function, to be used to allocate memory.

lpFreeBuffer

Input parameter pointing to the MAPIFreeBuffer function, to be used to free memory.

lpfnFilterColumns

Input parameter pointing to a callback function provided by the caller.  If the lpfnFilterColumns parameter is set to NULL, no callback is made.

Return Values

S_OK

The call succeeded and the specified columns were moved or added.

Comments

HrAddColumnsEx differs from HrAddColumns in that it allows the caller to filter the original property tags. For example, the caller might want to use HrAddColumnsEx to convert strings from property type PT_UNICODE to PT_STRING8.

The properties passed to this function using the lpproptagColumnsNew parameter will be the first properties listed on subsequent calls to the IMAPITable::QueryRows method. If any table properties are undefined when QueryRows is called, they will have the property type PT_NULL and the property identifier zero.

The input parameters lpAllocateBuffer and lpFreeBuffer point to the MAPIAllocateBuffer and MAPIFreeBuffer functions, respectively. If a client application calls the HrAddColumnsEx function, it passes in these parameters pointers to the functions named as listed. If a service provider calls HrAddColumnsEx, it passes the pointers to these functions it received in its initialization call or retrieved by calling the IMAPISupport::GetMemAllocRoutines method.

The HrAddColumnsEx function is defined in MAPIUTIL.H.

See Also

IMAPISupport::GetMemAllocRoutines method, IMAPITable::QueryColumns method, IMAPITable::QueryRows method, IMAPITable::SetColumns method, MAPIAllocateBuffer function, MAPIFreeBuffer function, SPropTagArray structure


 HrIStorageFromStream

[New - Windows 95]

Layers an IStorage interface onto an IStream object.

Syntax

HRESULT HrIStorageFromStream(LPUNKNOWN lpUnkIn, PIID lpInterface, ULONG ulFlags, LPSTORAGE FAR* lppStorageOut)

Parameters

lpUnkIn

Input parameter pointing to the IUnknown object for the object that implements the stream object.

lpInterface

Input parameter pointing to the interface identifier for the object in the lpUnkIn parameter. The IID_IStream interface identifier should be used.

ulFlags

Reserved; must be zero.

lppStorageOut

Output parameter pointing to a variable where the pointer to the returned IStorage object is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Store providers support HrIStorageFromStream using the IStorage interface for attachments. Store providers must implement the IStream interface. This function provides the IStorage interface for the IStream object.

HrIStorageFromStream is defined in MAPIUTIL.H.


 HrQueryAllRows

[New - Windows 95]

Retrieves all rows of a table.

Syntax

HrQueryAllRows(LPMAPITABLE ptable, LPSPropTagArray ptaga, LPSRestriction pres, LPSSortOrderSet psos, LONG crowsMax, LPSRowSet FAR* pprows)

Parameters

ptable

Input parameter pointing to the MAPI table from which rows are retrieved.

ptaga

Input parameter pointing to an SPropTagArray structure containing an array of property tags indicating the properties that identify each column in the table. These tags are used to select the table columns to be retrieved. If the ptaga parameter is NULL, the default set of columns for the table is retrieved.

pres

Input parameter pointing to an SRestriction structure containing retrieval restrictions. If the pres parameter is NULL, the calling implementation makes no restrictions.

psos

Input parameter pointing to an SSortOrderSet structure identifying the sort order of the columns to be retrieved. If the psos parameter is NULL, the default sort order for the table is used.

crowsMax

Input parameter containing the maximum number of rows to be retrieved. If this value is zero, no limit on the number of rows retrieved is set.

pprows

Output parameter pointing to the returned SRowSet structure, which contains the retrieved table rows.

Comments

When querying all rows of a table, your client application or service provider should call HrQueryAllRows instead of the IMAPITable::QueryRows method.

The HrQueryAllRows function is defined in MAPIUTIL.H

See Also

IMAPITable : IUnknown interface, IMAPITable::QueryRows method, SPropTagArray structure, SRestriction structure, SRowSet structure, SSortOrderSet structure


 HrThisThreadAdviseSink

[New - Windows 95]

Creates an advise sink that wraps another advise sink.

Syntax

HrThisThreadAdviseSink(LPMAPIADVISESINK lpAdviseSink, LPMAPIADVISESINK FAR* lppAdviseSink)

Parameters

lpAdviseSink

Input parameter pointing to the advise sink to be wrapped.

lppAdviseSink

Output parameter pointing to a new advise sink that wraps the one pointed to by the lpAdviseSink parameter.

Comments

The purpose of the wrapper is to ensure that the original advise sink is called on the same thread that called the HrThisThreadAdviseSink function. It is used to protect notification callbacks that must run on a particular thread when OLE is used. Remoted OLE interfaces must be called on their own threads, and each OLE thread must have a message loop.

Applications should use HrThisThreadAdviseSink to restrict when notifications are generated (that is, when calls are made to the IMAPIAdviseSink::OnNotify method of the advise sink object passed by the client application in a previous Advise call). If notifications can be generated arbitrarily, a notification implementation might make an application multithreaded when multithreading is inappropriate. For example, this result is troublesome when an implementation has been created using a library, such as one of the Microsoft Foundation Class Libraries, that does not support multithreaded calls. In this situation, an application is difficult to thoroughly test and is prone to error.

By implementing HrThisThreadAdviseSink, service providers can ensure that calls to clients' OnNotify methods can avoid causing inappropriate multithreading by occurring at only the following times:

•	During the processing of any call to any MAPI method.

•	When window messages are being processed.

When HrThisThreadAdviseSink is implemented, any calls to the new advise sink's OnNotify method on any thread cause the original notification method to be executed on the thread in which HrThisThreadAdviseSink was called.

For more information on notification and advise sinks, see MAPI Programmer's Guide. For more information on the Advise method, see the reference entries under the IABLogon, IAddrBook, IMAPIForm, IMAPISession, IMAPITable, IMsgStore, and IMSLogon interfaces.

The HrThisThreadAdviseSink function is defined in MAPIUTIL.H.

See Also

IMAPIAdviseSink::OnNotify method


LaunchWizard
 LaunchWizardEntry

[New - Windows 95]

Starts the Profile Wizard application.

Syntax

HRESULT LAUNCHWIZARDENTRY (HWND hParentWnd, ULONG ulFlags, LPCTSTR FAR* lppszServiceNameToAdd, ULONG cbBufferMax,  LPTSTR lpszNewProfileName)

Parameters

hParentWnd

Input parameter specifying a handle to the caller's parent window. If the caller does not have a parent window, hParentWnd should be NULL.

ulFlags

Input parameter containing a bitmask of flags indicating options for the Profile Wizard. The following flags can be set:

MAPI_PW_ADD_SERVICE_ONLY

Indicates that the Profile Wizard is to add a single service to the default profile and not show the page for selecting services.

MAPI_PW_FIRST_PROFILE

Indicates that the profile to be created is the first one for this workstation.

MAPI_PW_HIDE_SERVICES_LIST

Indicates that the Profile Wizard's page for selecting services should be hidden.

MAPI_PW_LAUNCHED_BY_CONFIG

Indicates that the Profile Wizard was launched by the Control Panel configuration application.

MAPI_PW_PROVIDER_UI_ONLY

Indicates that only the provider's configuration dialog boxes should be displayed and the Profile Wizard's pages should not appear. MAPI_PW_PROVIDER_UI_ONLY can only be set if MAPI_PW_ADD_SERVICE_ONLY is set.

lppszServiceNameToAdd

Input parameter specifying a pointer to a string containing the service name to be added, if ulFlags is set to MAPI_PW_ADD_SERVICE_ONLY.

cbBufferMax

Input parameter specifying the size of the buffer pointed to by lpszNewProfileName.

lpszNewProfileName

Output parameter specifying a pointer to a buffer where the LAUNCHSERVICEENTRY function returns the name of the created profile.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_CALL_FAILED

An error of unexpected or unknown origin prevented the operation from completing.

Comments

LaunchWizardEntry is the entry point into the MAPIef Profile Wizard application. MAPI calls this entry point LaunchWizard.

When the ulFlags parameter is set to MAPI_PW_ADD_SERVICE_ONLY, the following rules apply:

•	The flag MAPI_PW_LAUNCHED_BY_CONFIG causes the welcome page to be hidden.

•	The flags MAPI_PW_PROVIDER_UI_ONLY & MAPI_PW_HIDE_SERVICES_LIST are useful only when there is no default profile. When a default profile does not exist, these flags determine the Profile Wizard page to be shown.

•	When the flag MAPI_PW_ADD_SERVICE_ONLY is set and a default profile exists, this indicates that none of the Profile Wizard pages should be shown.

If the caller specifies MAPI_PW_ADD_SERVICE_ONLY, and the service is already in the default profile (and only one such service can be in the profile at a time), the Profile Wizard does not add the provider. An error code is returned indicating that the provider was already in the default profile.

If the provider supports the wizard pages, it must allow programmatic configuration of the profile.

The LaunchWizard function is defined in MAPIWZ.H.

See Also

MSGSERVICEENTRY function  SERVICEWIZARDENTRY function


 MAPIAdminProfiles

[New - Windows 95]

Creates a profile administration object.

Syntax

HRESULT MAPIAdminProfiles(ULONG ulFlags, LPPROFADMIN FAR* lppProfAdmin)

Parameters

ulFlags

Input parameter containing a bitmask of flags indicating options for the service entry function. The following flag can be set:

MAPI_UNICODE

Indicates the passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

lppProfAdmin

Output parameter pointing to a variable where a pointer to the returned new profile administration object is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

The MAPIAdminProfiles function is defined in MAPIX.H.

See Also

IProfAdmin::CreateProfile method


 MAPIAllocateBuffer

[New - Windows 95]

Allocates a memory buffer.

Syntax

SCODE MAPIAllocateBuffer(ULONG cbSize, LPVOID FAR* lppBuffer)

Parameters

cbSize

Input parameter containing the size, in bytes, of the buffer to be allocated.

lppBuffer

Output parameter pointing to a variable where the returned allocated buffer is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

During MAPIAllocateBuffer call processing, the calling implementation acquires a block of memory from the operating system. The memory buffer is allocated on an even-numbered byte address. On platforms where long integer access is more efficient, the operating system allocates the buffer on an address whose size in bytes is a multiple of four.

Calling the MAPIFreeBuffer function releases the memory buffer allocated by MAPIAllocateBuffer, and any buffers linked to it by calling the MAPIAllocateMore function, when the memory is no longer needed.

The MAPIAllocateBuffer function is defined in MAPIX.H

See Also

MAPIAllocateMore function, MAPIFreeBuffer function


 MAPIAllocateMore

[New - Windows 95]

Allocates a memory buffer that is linked to another buffer previously allocated with the MAPIAllocateBuffer function.

Syntax

SCODE MAPIAllocateMore(ULONG cbSize, LPVOID lpObject, LPVOID FAR* lppBuffer)

Parameters

cbSize

Input parameter containing the size, in bytes, of the new buffer to be allocated.

lpObject

Input parameter pointing to an existing MAPI buffer allocated using MAPIAllocateBuffer.

lppBuffer

Output parameter pointing to a variable where the returned, newly allocated buffer is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

During MAPIAllocateMore call processing, the calling implementation acquires a block of memory from the operating system. The memory buffer is allocated on an even-numbered byte address. On platforms where long integer access is more efficient, the operating system allocates the buffer on an address whose size in bytes is a multiple of four.

The only way to release a buffer allocated with MAPIAllocateMore is to pass the buffer pointer specified in the lpObject parameter to the MAPIFreeBuffer function. The link between the memory buffers allocated with MAPIAllocateBuffer and MAPIAllocateMore allows MAPIFreeBuffer to release both buffers on a single call.

The MAPIAllocateMore function is defined in MAPIX.H

See Also

MAPIAllocateBuffer function, MAPIFreeBuffer function


 MAPIFreeBuffer

[New - Windows 95]

Frees a memory buffer allocated with a call to the MAPIAllocateBuffer function or the MAPIAllocateMore function.

Syntax

ULONG MAPIFreeBuffer(LPVOID lpBuffer)

Parameters

lpBuffer

Input parameter pointing to a previously allocated memory buffer. If NULL is passed in the lpBuffer parameter, the MAPIFreeBuffer function does nothing.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Usually, when a client or provider calls MAPIAllocateBuffer or MAPIAllocateMore, the operating system constructs in one contiguous memory buffer one or more complex structures with multiple levels of pointers. When a MAPI function or method creates a buffer with such contents, a client application can later free all the structures contained in the buffer by passing to MAPIFreeBuffer the pointer to the buffer returned by the MAPI function that created the buffer. For a service provider to free a memory buffer using MAPIFreeBuffer, it must pass the pointer to that buffer returned with the provider's support object.

The call to MAPIFreeBuffer to free a particular buffer must be made as soon as a client or provider is finished using the buffer. Simply calling the MAPILogoff function at the end of a MAPI session does not automatically release memory buffers.

A client application or service provider should work on the assumption that the pointer passed in lpBuffer is invalid after a successful return from MAPIFreeBuffer. If the pointer indicates either a memory block not allocated by the messaging system through MAPIAllocateBuffer or MAPIAllocateMore or a free memory block, the behavior of MAPIFreeBuffer is undefined.

Note  Passing a null pointer to MAPIFreeBuffer makes application cleanup code simpler and smaller, because it can initialize pointers to NULL and then free them in the cleanup code without having to test them first.

MAPIFreeBuffer is exported, with a slightly different syntax, by both Simple MAPI and Extended MAPI. For Simple MAPI, it is an entry point function.

The MAPIFreeBuffer function is defined in MAPIX.H

See Also

IMAPISupport::GetMemAllocRoutines method, MAPIAllocateBuffer function, MAPIAllocateMore function, MAPILogoff function


 MAPIGetDefaultMalloc

[New - Windows 95]

Retrieves the address of the default MAPI memory allocation function.

Syntax

LPMALLOC MAPIGetDefaultMalloc( )

Parameters

None.

Comments

MAPIGetDefaultMalloc is defined in MAPIUTIL.H

Return Values

This function returns a pointer to the default MAPI memory allocation function.


 MAPIInitialize

[New - Windows 95]

Increments the reference count and initializes per-instance global data for the Extended MAPI DLL.

Syntax

MAPIInitialize(LPVOID lpMapiInit)

Parameters

lpMapiInit

Input parameter pointing to a MAPIINIT_0 structure. The lpMapiInit parameter can be set to NULL.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

The MAPIInitialize function increments the MAPI reference count for the MAPI DLL, and the MAPIUninitialize function decrements the internal reference count. Thus, the number of calls to one function must equal the number of calls to the other MAPIInitialize returns S_OK if MAPI has not been previously initialized.

Your client application or service provider must call MAPIInitialize before making any other Extended MAPI call. Failure to do so causes client application or service provider calls to return MAPI_E_NOT_INITIALIZED.

MAPIInitialize is similar to the OLE CoInitialize function. One of the main things CoInitialize does is set up the OLE task allocator. Clients and providers that are OLE-aware should call the CoInitialize or OleInitialize function before calling MAPIInitialize to use any OLE task allocator other than the default. For more information on OLE programming, see Inside OLE, Second Edition, by Kraig Brockschmidt, and OLE Programmer's Reference, Volume One and Volume Two.

When calling MAPIInitialize from a multi-threaded application, set lpMapiInit to a MAPIINIT_0 structure that is declared as follows:

MAPIINIT_0 MAPIINIT= { 0, MAPI_MULTITHREAD_NOTIFICATIONS}

and call

MAPIInitialize (&MAPIINIT);

When this structure is declared, MAPI creates a separate thread to handle the notification window, which continues until the initialize reference count falls to zero.

The MAPIInitialize function is defined in MAPIX.H.

See Also

MAPIUninitialize function


 MAPILogonEx

[New - Windows 95]

Logs a client application onto a session with the message system.

Syntax

ULONG MAPILogonEx(ULONG ulUIParam, LPTSTR lpszProfileName, LPTSTR lpszPassword, FLAGS flFlags, ULONG ulReserved, LPLHANDLE lplhSession)

Parameters

ulUIParam

Input parameter containing the handle to the window that the logon dialog box is modal to. If no dialog box is displayed during the call, the ulUIParam parameter is ignored.

lpszProfileName

Input parameter pointing to a string containing the name of the profile to use when logging on. This string is typically limited to 256 characters. If the lpszProfileName parameter is NULL or points to an empty string, and the flFlags parameter is set to the MAPI_LOGON_UI flag, the MAPILogonEx function generates a logon dialog box with an empty field for the profile name.

lpszPassword

Input parameter pointing to a string containing the password of the profile. This string is typically limited to 256 characters. The lpszPassword parameter can be NULL whether or not lpszProfileName is NULL.

flFlags

Input parameter containing a bitmask of flags used to control how logon is performed. The following flags can be set:

MAPI_ALLOW_OTHERS

Indicates that the shared session should be returned, allowing subsequent applications to acquire the session without providing any user credentials.

MAPI_EXPLICIT_PROFILE

Indicates the messaging subsystem should substitute the profile name of the default profile for lpszProfileName. The MAPI_EXPLICIT_PROFILE flag is ignored unless lpszProfileName is NULL or empty.

MAPI_FORCE_DOWNLOAD

Indicates an attempt should be made to download all of the user's messages before returning. If the MAPI_FORCE_DOWNLOAD flag is not set, messages can be downloaded in the background after the call to MAPILogonEx returns.

MAPI_LOGON_UI

Indicates that a dialog box should be displayed to prompt the user for logon information if required. When the MAPI_LOGON_UI flag is not set, the calling client application does not display a logon dialog box and returns an error if the user is not logged on. MAPI_LOGON_UI cannot be set if  the MAPI_PASSWORD_UI flag is set because the calling client can only present one of the two dialog boxes.

MAPI_NEW_SESSION

Indicates an attempt should be made to create a new MAPI session rather than acquire the shared session. If the MAPI_NEW_SESSION flag is not set, the function uses an existing shared session.

MAPI_NO_MAIL

Indicates that MAPI should not inform the MAPI spooler of the session's existence. The result is that no messages can be sent or received within the session. A calling client sets this flag when either configuration work must be done or the client is browsing the available message stores.

MAPI_NT_SERVICE

Indicates that a Windows NT client is logging on, signaling that MAPI should operate within a Windows NT service. This flag is only valid for Windows NT.

MAPI_PASSWORD_UI

Indicates that a dialog box should be displayed to prompt the user for the profile password. MAPI_PASSWORD_UI cannot be set if MAPI_LOGON_UI is set because the calling client can only present one of the two dialog boxes.

MAPI_SERVICE_UI_ALWAYS

Indicates that MAPILogonEx should display a configuration dialog box for each message service in the profile. The dialog box should be displayed after the profile has been chosen, but before any message service is logged on. The MAPI common dialog box for logon contains a check box that sets this flag.

MAPI_USE_DEFAULT

Indicates that the default profile is used for logon.

ulReserved

Reserved; must be zero.

lplhsession

Output parameter pointing to a handle indicating a MAPI session.

Return Values

MAPI_E_FAILONEPROVIDER

The service provider had not previously been configured and attempts to configure the provider failed.

MAPI_E_STRING_TOO_LONG

The string is longer than the maximum allowable length.

MAPI_E_TOO_MANY_SESSIONS

The user had too many sessions open simultaneously. No session handle was returned.

MAPI_E_UNCONFIGURED

A service provider has not been configured, and therefore the operation did not complete.

MAPI_E_USER_CANCEL

The user canceled the operation, typically by choosing the Cancel button in a dialog box.

Comments

Extended MAPI client applications call the MAPILogonEx function to log onto a session with the messaging system. MAPILogonEx does not start any service providers; it is up to the client to perform those calls. All strings passed and returned to and from MAPI calls are null-terminated and must be specified in the current character set or code page of the calling client or provider's operating system process.

The MAPILogonEx function is defined in MAPIX.H.

See Also

IMAPISession::GetMsgStoresTable method, IMAPISession::OpenMsgStore method


 MAPIOpenFormMgr

[New - Windows 95]

Opens an IMAPIFormMgr interface on a form-registry provider object in the context of an existing session.

Syntax

MAPIOpenFormMgr(LPMAPISESSION pSession, LPMAPIFORMMGR FAR* ppmgr)

Parameters

pSession

Input parameter pointing to the session in use by the client application.

ppmgr

Output parameter pointing to the returned IMAPIFormMgr interface.

Comments

After a client application makes a call to the MAPIOpenFormMgr function, most subsequent forms-related interactions take place through the form registry provider or an interface returned by the form registry provider. Among other things, the IMAPIFormMgr interface allows the client to work with message handlers and perform resolutions between message classes and form registries.

The MAPIOpenFormMgr function is defined in MAPIFORM.H.

See Also

IMAPIFormMgr : IUnknown interface


 MAPIOpenLocalFormContainer

[New - Windows 95]

Returns an interface pointer to the local form registry.

Syntax

MAPIOpenLocalFormContainer(LPMAPIFORMCONTAINER FAR* ppfcnt)

Parameters

ppfcnt

Output parameter pointing to a pointer to the local form registry interface.

Comments

The interface to which a pointer is returned can be used by third-party installation programs to install application-specific forms into the registry without the programs' first having to log onto MAPI.

The MAPIOpenLocalFormContainer function is defined in MAPIFORM.H.


MAPIUnintialize
 MAPIUninitialize

[New - Windows 95]

Decrements the reference count, cleans up, and deletes per-instance global data for the Extended MAPI DLL.

Syntax

void MAPIUninitialize(  )

Comments

A client application calls the MAPIUninitialize function to end its interaction with MAPI, begun with a call to the MAPIInitialize function. After MAPIUninitialize is called, no other Extended MAPI calls can be made by the client application.

MAPIUninitialize decrements the reference count, and the corresponding MAPIInitialize function increments the reference count. Thus, the number of calls to one function must equal the number of calls to the other.

The MAPIUninitialize function is defined in MAPIX.H.

See Also

MAPIInitialize function


 MSProviderInit

[New - Windows 95]

Initializes a message store provider for operation..

Syntax

HRESULT MSProviderInit(HINSTANCE hInstance, LPMALLOC lpMalloc, LPALLOCATEBUFFER lpAllocateBuffer, LPALLOCATEMORE lpAllocateMore, LPFREEBUFFER lpFreeBuffer, ULONG ulFlags, ULONG ulMAPIVer, ULONG FAR* lpulProviderVer, LPMSPROVIDER FAR* lppMSProvider)

Parameters

hInstance

Input parameter containing an instance of the message store provider's dynamic-link library (DLL) that MAPI used when it linked.

lpMalloc

Input parameter pointing to a standard memory allocator.

lpAllocateBuffer

Input parameter pointing to the MAPIAllocateBuffer function, to be used to allocate memory.

lpAllocateMore

Input parameter pointing to the MAPIAllocateMore function, to be used to allocate additional memory where required.

ulFlagslpFreeBuffer

Input parameter pointing to the MAPIFreeBuffer function, to be used to free memory.

Reserved; do not use. If any flags are set, the MSProviderInit function fails and returns the value MAPI_E_UNKNOWN_FLAGS.

ulMAPIVer

Input parameter containing the version of the service provider interface that MAPI.DLL uses. For the current version number, see the MAPISPI.H header file.

lpulProviderVer

Input parameter pointing to the version of the service provider interface that the message store uses.

lppMSProvider

Output parameter pointing to a variable where the initialized message-store provider object returned is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

To initialize a message store provider, MAPI calls the function named MSProviderInit, based on the MSPROVIDERINIT function prototype defined in MAPISPI.H from the message store provider's DLL. The message store provider must use its implementation of MSProviderInit to respond to the MAPI initialization call.

The message store provider must also define the MSProviderInit function using the CDECL calling convention. CDECL definition is required for each service provider initialization function to ensure the function can work with the current version of the service provider interface, even if the number of function parameters used is not the number set for that function in the current version of the interface. MAPI provides the MSPROVIDERINIT prototype is to help define MSProviderInit as CDECL. The MSPROVIDERINIT prototype has a standard MAPI initialization call type, STDMAPIINITCALLTYPE.

The input parameters lpAllocateBuffer, lpAllocateMore and lpFreeBuffer specify pointers to the MAPIAllocateBuffer, MAPIAllocateMore, and MAPIFreeBuffer functions, respectively, for use by the message-store provider DLL. The provider DLL should not be linked with MAPIX.DLL. Instead, it should use these pointers for memory allocation or deallocation. In particular, the provider must use these pointers when allocating memory for use by client applications in calling object interfaces. For example, two provider interface methods that typically allocate memory are IMAPIProp::GetProps and IMAPITable::QueryRows.

The message store provider should retain information on the allocator pointers passed to it in lpAllocateBuffer, lpAllocateMore, and lpFreeBuffer. If the provider will use a memory allocator later, it should call the IUnknown::AddRef method for the allocation object pointed to by the lpMalloc parameter.

For more information on using MSProviderInit, see the information on using the MSProviderInit, ABProviderInit, and XPProviderInit functions in MAPI Programmer's Guide.

The MSProviderInit function is defined in MAPISPI.H.

See Also

ABProviderInit function, HPProviderInit function, IMAPIProp::GetProps method, IMAPITable::QueryRows method, MAPIAllocateBuffer function, MAPIAllocateMore function, MAPIFreeBuffer function, XPProviderInit function


 OpenIMsgOnIStg

[New - Windows 95]

Creates internal memory structures and an object handle for creation of a new message object.

Syntax

SCODE OpenIMsgOnIStg(LPMSGSESS lpMsgSess, LPALLOCATEBUFFER lpAllocateBuffer, LPALLOCATEMORE lpAllocateMore, LPFREEBUFFER lpFreeBuffer, LPMALLOC lpmalloc, LPVOID lpMapiSup, LPSTORAGE lpStg, MSGCALLRELEASE FAR* lpfMsgCallRelease, ULONG ulCallerData, ULONG ulFlags, LPMESSAGE FAR* lppMsg)

Parameters

lpMsgSess

Input parameter pointing to a message session object.

lpAllocateBuffer

Input parameter pointing to the MAPIAllocateBuffer function, to be used by the service provider to allocate memory.

lpAllocateMore

Input parameter pointing to the MAPIAllocateMore function, to be used by the provider to allocate additional memory where required.

lpFreeBuffer

Input parameter pointing to the MAPIFreeBuffer function, to be used by the provider to free memory.

lpMalloc

Input parameter pointing to a standard OLE memory allocator, as described in OLE Programmer's Reference, Volume One.

lpMapiSup

Input parameter pointing to an optional MAPI support object used when a service provider calls the OpenIMsgOnIStg function.

lpStg

Input-output parameter pointing to an IStorage object that is open and has read-write access. Because messages do not support write-only access, OpenIMsgOnIStg does not accept a storage object opened with write-only access.

lpfMsgCallRelease

Input parameter pointing to a message-release callback function in the service provider DLL

ulCallerData

Input parameter containing caller data to be written by the callback function indicated by lpfMsgCallRelease.

ulFlags

Input parameter containing a bitmask of flags used to control whether the OLE method IStorage::Commit is called when the client calls the IMessage::SaveChanges method. The following flag can be set:

IMSG_NO_ISTG_COMMIT

Controls whether the OLE method IStorage::Commit is called when the client calls IMessage::SaveChanges.

lppMsg

Output parameter pointing to a variable where the returned message object is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

Warning  The correct process for defining an attachment to a message is to call the IMAPIProp::OpenProperty method with a source interface of IMessage. IMAPIProp::OpenProperty is also supported for message attachments when the source interface is the OLE interface IStorage. IStorage is supported to allow an easy way to put a Microsoft Word for Windows document into an attachment without converting the attachment to or from the OLE IStream interface. However, use of IStorage presents a danger to the predictability of IMessage when the client application or service provider passes a new attachment data pointer to OpenIMsgOnIStg and then releases objects in the wrong order.

Including the lpMsgSess parameter ensures that the new message is created within a session, so that it can be closed when the session is closed. If lpMsgSess is NULL, a message is created independently of any session. If the client application or service provider that created the message does not release the message or does not release open tables within the message, memory is leaked until the external application terminates.

The input parameters lpAllocateBuffer, lpAllocateMore, and lpFreeBuffer point to the MAPIAllocateBuffer, MAPIAllocateMore, and MAPIFreeBuffer functions, respectively, for use by the service provider DLL. The provider DLL should not be linked with MAPIX.DLL. Instead, it should use these pointers for memory allocation or deallocation. In particular, the provider must use these pointers when allocating memory for use by client applications in calling object interfaces. For example, two provider interface methods that typically allocate memory are IMAPIProp::GetProps and IMAPITable::QueryRows. The lpAllocateBuffer, lpAllocateMore, and lpFreeBuffer pointers are optional when the OpenIMsgOnIStg function is called with a valid lpMapiSup parameter.

If a value is supplied for lpMapiSup, IMessage supports the MAPI_DIALOG and ATTACH_DIALOG flags by calling the IMAPISupport::DoProgressDialog method to supply a progress user interface for the IMAPIProp::CopyTo and IMessage::DeleteAttach methods. The IMessage::ModifyRecipients method attempts to convert short-term entry identifiers to long-term entry identifiers by calling the support method IMAPISession::OpenAddressBook and making calls on the resulting address book object. If zero is passed for lpMapiSup, IMessage ignores MAPI_DIALOG and ATTACH_DIALOG and stores short-term entry identifiers without conversion.

MAPI does not define the behavior of multiple open operations performed on a message subobject, such as an attachment, a stream, a message store, or another message. MAPI currently allows a subobject that is already open to be opened once more, but MAPI performs the open operation by incrementing the reference count for the existing open object and returning it to the client or provider that called the IMessage::OpenAttach or IMAPIProp::OpenProperty method. Thus, the access requested for the first open operation on a subobject is the access provided for all subsequent open operations, regardless of the access requested by the operations.

Some clients of IMessage might call the OLE method IStorage::Commit after writing data beyond what IMessage itself writes to the storage object. To aid in this, the IMessage implementation guarantees to name all substorages. Therefore, if the client keeps its names out of that namespace, there will be no accidental collisions.

The callback function mentioned with the lpfMsgCallRelease parameter is optional; if provided, it should be based on the MSGCALLRELEASE function prototype. If the lpfMsgCallRelease parameter is supplied, the IMessage interface calls the callback function when the top-level message receives its last release call. IMSG.DLL will not use the IStorage object pointed to by the lpStg parameter after making this call.

The OpenIMsgOnIStg function is defined in IMESSAGE.H.

See Also

IMessage : IMAPIProp interface, IMessage::ModifyRecipients method, IMessage::OpenAttach method, IMAPIProp::OpenProperty method, MAPIAllocateBuffer function, MAPIAllocateMore function, MAPIFreeBuffer function, MSGCALLRELEASE function prototype, OpenIMsgSession function


OpenIMsgOnIStorage, MSGCALLRELEASE
 OpenIMsgOnIStg, MSGCALLRELEASE

[New - Windows 95]

The MSGCALLRELEASE prototype function represents a callback function that enables a service provider to free the IStorage interface after the final release of a top-level message that was opened with OpenIMsgOnIStg.

Syntax

void (ULONG ulCallerData,  LPMESSAGE lpMessage)

Parameters

ulCallerData

An input parameter that contains calling application information about the IMessage interface.

lpMessage

An input parameter that is a pointer to the top-level message and attachments that have been released.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

The MSGCALLRELEASE function prototype is defined in IMESSAGE.H.

See Also

OpenIMsgOnIStg function


 MSGSERVICEENTRY

[New - Windows 95]

The MSGSERVICEENTRY prototype function represents an optional service provider entry point to support message service configuration. MAPI calls this entry point from the Control Panel application.

Syntax

HRESULT MSGSERVICEENTRY (HINSTANCE hInstance, LPMALLOC lpMalloc, LPMAPISUP lpMAPISup, ULONG ulUIParam, ULONG ulFlags, ULONG ulContext, ULONG cValues, LPSPropValue lpProps, LPPROVIDERADMIN lpProviderAdmin, LPMAPIERROR FAR* lppMapiError)

Parameters

hInstance

Input parameter specifying the handle of the instance of the service provider DLL. The handle is typically used to retrieve resources.

lpMalloc

Input parameter specifying a pointer to a standard OLE memory allocator, as described in the OLE 2 documentation.

lpMAPISup

Input parameter specifying a pointer to an IMAPISupport interface implementation.

ulUIParam

Input parameter specifying an implementation-specific 32-bit value used for passing user interface information to a function or zero. In Microsoft Windows applications, ulUIParam is the parent window handle for the configuration dialog box and is of type HWND (cast to a ULONG). A value of zero indicates that there is no parent window.

ulFlags

Input parameter containing a bitmask of flags indicating options for the service entry function. The following flags can be set:

MAPI_UNICODE

Indicates the passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

MSG_SERVICE_UI_READ_ONLY

Indicates the service's configuration user interface should display the current configuration but not allow the user to change it.

SERVICE_UI_ALLOWED

Permits a configuration dialog box to be displayed if necessary. When SERVICE_UI_ALLOWED is set, the dialog box should be displayed only if the lpProps property value array is empty or does not contain a valid configuration. If SERVICE_UI_ALLOWED is not set, a dialog box might still be displayed if UI_SERVICE_ALWAYS is set.

UI_CURRENT_PROVIDER_FIRST

Requests that the configuration dialog box for the active provider be displayed on top of other dialog boxes.

UI_SERVICE_ALWAYS

Requires the message service display a configuration dialog box. If UI_SERVICE_ALWAYS is not set, a configuration dialog may still be displayed if SERVICE_UI_ALLOWED is set and valid configuration information is not available from the lpProps property value array. Either SERVICE_UI_ALLOWED or UI_SERVICE_ALWAYS must be set to allow a user interface to be displayed.

ulContext

Input parameter specifying the configuration operation that MAPI is currently performing. The ulContext parameter will contain one of the following values:

MSG_SERVICE_CONFIGURE

Indicates that changes to the service's configuration should be made in the profile. If the UI_SERVICE_ALWAYS flag is set, the service should display its configuration dialog box. The dialog box should also be displayed if the SERVICE_UI_ALLOWED flag is set and lpProps is empty or does not contain valid configuration data. If lpProps contains valid data, no dialog box should be displayed and the service should use this data for making the configuration change.

MSG_SERVICE_CREATE

Indicates the service is being added to a profile. If either the UI_SERVICE_ALWAYS or SERVICE_UI_ALLOWED flag is set, the service should display its configuration dialog box. If neither flag is set, the service should fail.

MSG_SERVICE_DELETE

Indicates the service is being removed from a profile. After receiving this event, the service should return S_OK.

MSG_SERVICE_INSTALL

Indicates the service has been installed to the user's workstation from a network, floppy disk, or other external medium. After receiving this event, the service usually returns S_OK.

MSG_SERVICE_PROVIDER_CREATE

Requests that the service create an additional instance of a provider. If the service supports this operation, it should call IProviderAdmin::CreateProvider. If the service does not support this operation, it can return MAPI_E_NO_SUPPORT.

MSG_SERVICE_PROVIDER_DELETE

Requests that the service delete a provider instance. If the service supports this operation, it should call IProviderAdmin::DeleteProvider. If the service does not support this operation, it can return MAPI_E_NO_SUPPORT.

MSG_SERVICE_UNINSTALL

Indicates the service is being removed. After receiving this event, the service can perform any clean up tasks that should be done before the service goes away and then return with a success code. If the user cancels the removal, the service should return MAPI_E_USER_CANCEL.

cValues

Input parameter specifying the number of property values in the array pointed to by lpProps. The cValues parameter is zero if MAPI is passing no property values.

lpProps

Input parameter specifying a pointer to an optional array of SPropValue structures indicating values for provider-supported properties that the function will use in configuring the message service. The function only uses this parameter if ulContext is set to MSG_SERVICE_CONFIGURE. This parameter is commonly used to pass the path to a file for a file-based service, such as a personal address book service.  If the MSG_SERVICE_CONFIGURE flag is not passed in ulFlags, lpProps must be zero.

lpProviderAdmin

Input parameter specifying a pointer to an IProviderAdmin interface that the function can use to locate profile sections for a specific provider in the current message service.

lppMapiError

Output parameter specifying a pointer to a MAPIERROR structure. The structure is allocated with MAPIAllocateBuffer. All members are optional, although most structures will contain a valid error message string in the lpszError member. If the lpszComponent and/or lpszError members of the structure are present, their memory must eventually be freed by a single MAPIFreeBuffer call on the base structure.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_UNCONFIGURED

The service provider has not been configured.

MAPI_E_USER_CANCEL

The user canceled the operation, typically by choosing the cancel button in a dialog box.

Comments

A function defined using the MSGSERVICEENTRY prototype allows message services to configure themselves or to perform other service-specific actions. The function primarily furnishes a dialog box in which the user can change settings specific to the message service. It can also support programmatic configuration by using the property value array passed in lpProps. Programmatic configuration is optional unless the service supports the Profile Wizard. Support for the Profile Wizard requires programmatic configuration.

The MSGSERVICEENTRY function is typically called in response to a user's request either from the client application or the Profile Provider. These two applications call IMsgServiceAdmin::CreateMsgService or IMsgServiceAdmin::ConfigureMsgService and these methods call the service entry function.

MAPI places no restriction on the function name that your message service uses for the MSGSERVICEENTRY prototype, but prefers the name ServiceEntry. There is no restriction on the ordinal for the function, and a single provider DLL can contain more than one function. However, only one of the functions may be named ServiceEntry.

MAPI allows your message service to use Windows 95-style property sheets for its configuration dialog boxes. It can use the BuildDisplayTable function and the IMAPISupport::DoConfigPropsheet method to simplify configuration dialog box  implementation.

It is possible for a user to cancel a MSG_SERVICE_UNINSTALL operation. In this case, the service entry function should check with the user to verify that the service should not be removed and return MAPI_E_USER_CANCEL if the service remains installed.

A function based on the MSGSERVICEENTRY prototype returns one of the HRESULT codes listed.  MAPI forwards this code when responding to a client application call to IMsgServiceAdmin::ConfigureMsgService.

Message services that export a service entry function must include the PR_SERVICE_DLL_NAME and PR_SERVICE_ENTRY_NAME properties in the message service section of MAPISVC.INF.

The MSGSERVICEENTRY function prototype is defined in MAPISPI.H.

See Also

BuildDisplayTable function, IMAPISupport::DoConfigPropsheet method, IMsgServiceAdmin::ConfigureMsgService method, IMalloc


 OpenStreamOnFile

[New - Windows 95]

Allocates and initializes a stream object to hold the contents of a file.

Syntax

HRESULT OpenStreamOnFile(LPALLOCATEBUFFER lpAllocateBuffer, LPFREEBUFFER lpFreeBuffer, ULONG ulFlags, LPTSTR szFileName, LPTSTR szPrefix, LPTSTREAM FAR* lppStream)

Parameters

lpAllocateBuffer

Input parameter pointing to the MAPIAllocateBuffer function, to be used by the service provider to allocate memory.

lpFreeBuffer

Input parameter pointing to the MAPIFreeBuffer function, to be used by the provider to free memory.

ulFlags

Input parameter containing a bitmask of flags used to control the creation of the stream object. All of the flags used with OLE 2.0 IStream::Read and IStream::Write methods, in addition to the following MAPI-defined flag, can be used:

SOF_UNIQUEFILENAME

Creates in a temporary directory a new file that is accessible with the OLE IStream interface. To create a read-only stream interface, do not use this flag.

szFileName

Input parameter containing the filename for the file for which this function opens a stream object.

szPrefix

Input parameter containing the prefix for the filename on which the OpenStreamOnFile function opens a stream object.

lppStream

Output parameter pointing to a variable where the pointer to the returned stream object is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_NO_ACCESS

The object could not be accessed due to insufficient user permissions or because read-only objects cannot be modified.

MAPI_E_NOT_FOUND

The requested object does not exist.

Comments

A client application or service provider calls OpenStreamOnFile to allocate and initialize a stream object to hold the contents of a file. The stream object, and thus the file, is then accessible through the OLE IStream interface. To free the stream object, the application or provider must call the OLE IStream::Release method, which is inherited from the IUnknown interface.

A 32-bit Windows program should call OpenStreamOnFile strictly as defined in the preceding "Syntax" section, using the name provided. However, a 16-bit Windows program can set its own name for this function using the OPENSTREAMONFILE function prototype. The prototype has exactly the same syntax as that provided for the function preceding, except that it designates a return value of HRESULT instead of STDMETHODIMP.

The input parameters lpAllocateBuffer and lpFreeBuffer point to the MAPIAllocateBuffer and MAPIFreeBuffer functions, respectively, for use by the service provider DLL. The provider DLL should not be linked with MAPIX.DLL. Instead, it should use these pointers for memory allocation or deallocation. In particular, the provider must use these pointers when allocating memory for use by client applications in calling object interfaces. For example, two provider interface methods that typically allocate memory are IMAPIProp::GetProps and IMAPITable::QueryRows.

SOF_UNIQUEFILENAME is used to create a temporary filename that is unique to the message system.  If this flag is set, the szFileName parameter specifes the file name and the szPrefix parameter contains a string that is used to designate the directory in which the file should be created. This string is prefixed to the filename. If the value in szFileName is NULL, the unique file will be created in the temporary directory that is returned from the Windows function GetTempDir. If the SOF_UNIQUEFILENAME flag is not set, szPrefix is ignored and szFileName should contain the fully qualified path to the file being opened or created. The file will be opened or created based on the other flags that are set in ulFlags.

The OpenStreamOnFile function is defined in MAPIUTIL.H.

See Also

IMAPIProp::GetProps method, IMAPITable::QueryRows method, MAPIAllocateBuffer function, MAPIFreeBuffer function


 OpenTnefStream

[New - Windows 95]

Called by a transport provider to initiate a MAPI Transport Neutral Encapsulation Format (TNEF) session.

Syntax

HRESULT OpenTnefStream(LPMAPISUP lpMapiSup, LPSTREAM lpStream, LPTSTR lpszStreamName, ULONG ulFlags, LPMESSAGE lpMessage, WORD wKey, LPITNEF FAR* lppTNEF)

Parameters

lpvsup

Passes a support object or passes in NULL. If NULL, lpadrbook should be non NULL.

lpStream

Input parameter specifying a pointer to a storage stream object (OLE IStream interface) providing a source or destination for a TNEF stream message.

lpszStreamName

Input parameter specifying a pointer to the name of the data stream that the TNEF object uses. If the caller has set the TNEF_ENCODE flag (ulFlags parameter) in its call to OpenTnefStream, the lpszName parameter must specify a non-null pointer to a non-null string consisting of any characters considered valid for naming a file. MAPI does not allow string names including the characters "[", "]", or ":", even if the file system permits their use. The size of the string passed for lpszName must not exceed the value of MAX_PATH, the maximum length of a string containing a path name.

ulFlags

Input parameter containing a bitmask of flags used to indicate the mode of the function. The following flags can be set:

TNEF_BEST_DATA

Indicates that all possible properties are mapped into their down-level attributes, but when there is a possible data loss due to the conversion to a down-level attribute, the property is also encoded in the encapsulations. NOTE: this will cause the duplication of information in the TNEF stream. TNEF_BEST_DATA is the default if no other modes are specified.

TNEF_COMPATIBILITY

Ensures backwards compatibility with the MAIL 3.0 client. TNEF streams encoded with this flag will map all possible properties into their corresponding down-level attribute. This mode also causes the defaulting of some properties that are required by down-level clients.

TNEF_DECODE

Indicates the TNEF object on the indicated stream is opened with read-only access. The transport provider must set this flag if it wants the function to initialize the object for subsequent decoding.

TNEF_ENCODE

Indicates the TNEF object on the indicated stream is opened for read/write access. The transport provider must set this flag if it wants the function to initialize the object for subsequent encoding.

TNEF_PURE

Encodes all properties into the MAPI encapsulation blocks. Therefore, a "pure" TNEF file will consist of, at most, attMAPIProps, attAttachment, attRenddata, and attRecipTable. This mode is ideal for use when no backwards compatibility is required.

lpMessage

Input parameter specifying a pointer to a message object as a destination for a decoded message with attachments or a source for an encoded message with attachments. Any properties of a destination message may be overwritten by the properties of an encoded message.

wKey

Input parameter specifying a search key that the TNEF object uses to match attachments to the text tags inserted in the message body. This value should be relatively unique across messages.

lppTNEF

Output parameter pointing to a variable where the new TNEF object is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

A TNEF object created by OpenTnefStream later calls the OLE method IUnknown::AddRef to add references for the support object, the stream object, and the message object. The transport provider can release the references for all three objects with a single call to the OLE method IUnknown::Release on the TNEF object.

This function allocates and initializes a TNEF object (ITnef interface) for the provider to use in encoding a MAPI message (IMessage interface) into a TNEF stream message. Alternatively, the function can set up the object for the provider to use in subsequent calls to ITnef ::ExtractProps to decode a TNEF stream message into a MAPI message. To free the TNEF object and close the session, the transport provider must call the inherited IUnknown::Release method on the object.

A 32-bit Windows program should call OpenTnefStream strictly as defined in the "Syntax" section, using the name provided. However, a 16-bit Windows program can set its own name for this function using the OPENTNEFSTREAM function prototype. The prototype has exactly the same syntax as the formal function, except that it designates a return value of HRESULT instead of STDMETHODIMP.

This function is the original entry-point for TNEF access and has been replaced by OpenTnefStreamEx but is kept around to allow compatibility for those already using TNEF.

The OpenTnefStream function is defined in TNEF.H.

See Also

IMAPISupport : IUnknown interface, ITnef::ExtractProps method, IXPProvider::TransportLogon method OpenTnefStreamEx function


 OpenTnefStreamEx

[New - Windows 95]

Creates a TNEF object that can be used to encode or decode a message object into a TNEF data stream for use by transports or gateways and message stores. This is the entry-point for TNEF access.

Syntax

HRESULT OpenTnefStreamEx(LPVOID lpvSupport, LPSTREAM lpStreamName, LPTSTR lpszStreamName, ULONG ulFlags, LPMESSAGE lpMessage, WORD wKeyVal, LPADRBOOK lpAdressBook, LPITNEF FAR* lppTNEF);

Parameters

lpvsup

Passes a support object or passes in NULL.  If NULL lpadrbook should be non NULL.

lpStream

Input parameter specifying a pointer to a storage stream object (OLE IStream interface) providing a source or destination for a TNEF stream message.

lpszStreamName

Input parameter specifying a pointer to the name of the data stream that the TNEF object uses. If the caller has set the TNEF_ENCODE flag (ulFlags parameter) in its call to OpenTnefStream, the lpszName parameter must specify a non-null pointer to a non-null string consisting of any characters considered valid for naming a file. MAPI does not allow string names including the characters "[", "]", or ":", even if the file system permits their use. The size of the string passed for lpszName must not exceed the value of MAX_PATH, the maximum length of a string containing a path name.

ulFlags

Input parameter containing a bitmask of flags used to indicate the mode of the function. The following flags can be set:

TNEF_BEST_DATA

Indicates that all possible properties are mapped into their down-level attributes, but when there is a possible data loss due to the conversion to a down-level attribute, the property is also encoded in the encapsulations. NOTE: this will cause the duplication of information in the TNEF stream. TNEF_BEST_DATA is the default if no other modes are specified.

TNEF_COMPATIBILITY

Ensures backwards compatibility with the MAIL 3.0 client. TNEF streams encoded with this flag will map all possible properties into their corresponding down-level attribute. This mode also causes the defaulting of some properties that are required by down-level clients.

TNEF_DECODE

Indicates the TNEF object on the indicated stream is opened with read-only access. The transport provider must set this flag if it wants the function to initialize the object for subsequent decoding.

TNEF_ENCODE

Indicates the TNEF object on the indicated stream is opened for read/write access. The transport provider must set this flag if it wants the function to initialize the object for subsequent encoding.

TNEF_PURE

Encodes all properties into the MAPI encapsulation blocks. Therefore, a "pure" TNEF file will consist of, at most, the attributes attMAPIProps, attAttachment, attRenddata, and attRecipTable. This mode is ideal for use when no backwards compatibility is required.

lpMessage

Input parameter specifying a pointer to a message object as a destination for a decoded message with attachments or a source for an encoded message with attachments. Any properties of a destination message may be overwritten by the properties of an encoded message.

wKey

Input parameter specifying a search key that the TNEF object uses to match attachments to the text tags inserted in the message body. This value should be relatively unique across messages.

lpAdressBook

Input parameter pointing to an address book object used to get addressing information for entry identifiers.

lppTNEF

Output parameter pointing to a variable where the new TNEF object is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

A TNEF object created by OpenTnefStream later calls the OLE method IUnknown::AddRef to add references for the support object, the stream object, and the message object. The transport provider can release the references for all three objects with a single call to the OLE method IUnknown::Release on the TNEF object.

This function allocates and initializes a TNEF object for the provider to use in encoding a MAPI message  into a TNEF stream message. Alternatively, the function can set up the object for the provider to use in subsequent calls to ITnef ::ExtractProps to decode a TNEF stream message into a MAPI message. To free the TNEF object and close the session, the transport provider must call the inherited IUnknown::Release method on the object.

A 32-bit Windows program should call OpenTnefStream strictly as defined in the "Syntax" section, using the name provided. However, a 16-bit Windows program can set its own name for this function using the OPENTNEFSTREAM function prototype. The prototype has exactly the same syntax as the formal function, except that it designates a return value of HRESULT instead of STDMETHODIMP.

The OpenTnefStreamEx function is defined in TNEF.H.

See Also

IMAPISupport : IUnknown interface, ITnef::ExtractProps method, IXPProvider::TransportLogon method OpenTnefStream function


 RTFSync

[New - Windows 95]

Ensures that the rich text format (RTF) body of a message matches the plain text body.  It is necessary to call this function before reading the RTF body and after modifying the RTF body.

Syntax

HRESULT RTFSync(LPMESSAGE lpMessage, ULONG ulFlags, BOOL FAR* lpfMessageUpdated)

Parameters

lpMessage

Input parameter specifying a pointer to the message to be updated.

ulFlags

Input parameter containing a bitmask of flags used to indicate the RTF or body of the message has changed. The following flags can be set:

RTF_SYNC_RTF_CHANGED

Indicates the RTF has changed.

RTF_SYNC_BODY_CHANGED

Indicates the plain text body of the message has changed.

lpfMessageUpdated

Output parameter pointing to a variable indicating whether there is an updated message. TRUE if there is an updated message, FALSE otherwise.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

This function should be called with RTF_SYNC_BODY_CHANGED before reading the RTF stream. This function should be called with RTF_SYNC_RTF_CHANGED after modifying the RTF body of a message. If both the RTF body and plain text body are modified, this function should be called with RTF_SYNC_RTF_CHANGED | RTF_SYNC_BODY_CHANGED.

If the value of the lpfMessageUpdated parameter is set to TRUE, then IMAPIProp::SaveChanges should be called for the message. RTFSync does not call SaveChanges as part of its implementation. If SaveChanges is not called the modifications will not be saved in the message.

The RTFSync function is defined in MAPIUTIL.H.

See Also

WrapCompressedRTFStream


 ScDupPropset

[New - Windows 95]

Duplicates a property value array in a single block of MAPI memory. The ScDupPropset function combines the operations of the ScCopyProps and ScCountProps functions.

Syntax

SCODE ScDupPropset(int cprop, LPSPropValue rgprop, LPALLOCATEBUFFER lpAllocateBuffer, LPSPropValue FAR* prgprop)

Parameters

cprop

Input parameter containing the number of property values in the array indicated by the rgprop parameter.

rgprop

Input parameter pointing to an array of SPropValue structures defining the property values to be duplicated.

lpAllocateBuffer

Input parameter pointing to the MAPIAllocateBuffer function, to be used to allocate memory for the duplicated array.

prgprop

Output parameter pointing to the initial position in memory where the returned duplicated array of SPropValue structures is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

The ScDupPropset function is defined in MAPIUTIL.H.

See Also

MAPIAllocateBuffer function, ScCopyProps function, ScCountProps function, SPropValue structure


 SERVICEWIZARDDLGPROC

[New - Windows 95]

The SERVICEWIZARDDLGPROC prototype function represents a callback invoked by the Profile Wizard to allow the provider to react to user events when the provider's property sheets, or pages, are shown.

Syntax

BOOL SERVICEWIZARDDLGPROC (HWND hDlg, UINT wMsgID, WPARAM wParam, LPARAM lParam)

Parameters

hDlg

Input parameter containing a window handle to the Profile Wizard dialog box.

wMsgID

Input parameter indicating the message to be processed. In addition to all the regular Windows messages expected by a modal dialog box, the following messages can be received:

WM_CLOSE

Called when the Profile Wizard has completed. The provider should do any cleanup such as deallocating any dynamically allocated memory.

WM_COMMAND

Called for all of the provider's controls, and in addition, WM_COMMAND is called for the "Next" { ID_NEXT }, and "Prev" { ID_PREV } buttons. When called with ID_NEXT or ID_PREV, the provider is responsible for hiding the old page's controls, and showing the controls for the next or previous page.

WM_INITDIALOG

Called even after the dialog box exists to allow the provider to initialize the controls that the Profile Wizard has added to the dialog box.

WIZ_QUERYNUMPAGES

Called to ask for the number of pages that the provider needs to display. The provider should return the number of pages instead of TRUE or FALSE. For example, use the following return statement to indicate that three pages should to be displayed:

return (BOOL)3;

wParam

Input parameter whose contents depend on the message specified in wMsgID.

lParam

Input parameter whose contents depend on the message specified in wMsgID.

Return Values

The value returned is dependent on the message type sent. The recommended practice is to return TRUE if you process the message and FALSE if you don't process the message.

Comments

When the user selects the Next button, SERVICEWIZARDDLGPROC is called with the WM_COMMAND message and ID_NEXT in the wParam parameter. The following steps describe what occurs between the time when the user chooses Next and when the first provider's configuration pages are rendered.

1.	The Profile Wizard hides any controls that are on the window.

2.	The Profile Wizard adds the provider's controls (hidden) to the page.

3.	The Profile Wizard calls the SERVICEWIZARDDLGPROC function, sending the WM_INITDIALOG message, so that the provider can initialize the controls.

4.	The Profile Wizard calls the SERVICEWIZARDDLGPROC function, sending the WIZ_QUERYNUMPAGES message. The provider returns the number of pages that it will be showing.

5.	The Profile Wizard calls the SERVICEWIZARDDLGPROC function, sending the WM_COMMAND message with the wParam parameter set to either ID_NEXT or ID_PREV. At this point, the provider either returns FALSE {error} or reveals its controls and returns TRUE {success}. If the Profile Wizard passes in ID_NEXT, the provider's first page is displayed. If ID_PREV is passed in, the last page is displayed.

6.	The Profile Wizard calls the provider's SERVICEWIZARDDLGPROC function, sending the WM_COMMAND message with the wParam parameter set to either ID_NEXT or ID_PREV (depending on which button the user pressed). The provider is responsible for showing or hiding its controls and writing its data to the IMAPIProp passed to the profile wizard to step through its sequence of pages. The provider should return TRUE if the next or previous page was successfully shown, and FALSE if the neither the next nor previous page could be shown. The provider needs to be aware of when it is stepping outside of its sequence of pages, and respond appropriately by hiding its controls and writing its data to the profile.

7.	If the user steps outside the provider's range of pages, the Profile Wizard deletes the provider's hidden controls from the dialog box and calls the next provider (or displays its next page if that was the last provider).

The SERVICEWIZARDDLGPROC function prototype is defined in MAPIWIZ.H.


 SERVICEWIZARDENTRY

[New - Windows 95]

The SERVICEWIZARDENTRY prototype function represents a service provider entry point for the Profile Wizard. The Profile Wizard calls this entry point to retrieve enough information to display the provider's configuration property sheets.

Syntax

ULONG SERVICEWIZARDENTRY (HINSTANCE hProviderDLLInstance, LPCSTR FAR* lpcsResourceName, DLGPROC FAR* lpDlgProc, LPMAPIPROP lpMAPIProp)

Parameters

hProviderDLLInstance

Input parameter containing the instance handle of the provider's DLL.

lpcsResourceName

Output parameter pointing to a string containing the full name of the dialog resource that should be displayed by the Profile Wizard during configuration. The maximum size of the string, including the NULL terminator, is 32 characters.

lpDlgProc

Output parameter pointing to a standard Windows dialog box procedure that will be called by the Profile Wizard to notify the provider of various events.

lpMAPIProp

Input parameter pointing to a property interface that provides access to the configuration properties. When the wizard is finished configuring all providers, it writes the properties to the profile by calling IMsgServiceAdmin::ConfigureMsgService.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_CALL_FAILED

An error of unexpected or unknown origin prevented the operation from completing.

Comments

The Profile Wizard calls the SERVICEWIZARDENTRY function when it is ready to display the provider's configuration user interface. The pointer to the property object should be stored by the provider for future reference; this pointer allows the provider access to the profile. At some point during configuration, providers should add their configuration properties to this object. After all providers have been configured, the Profile Wizard adds these properties to the profile.

The name of the SERVICEWIZARDENTRY function must be placed in the PR_SERVICE_WIZARD_ENTRY_NAME property in MAPISVC.INF.

The resource name is the name of the dialog resource that will be rendered in the Profile Wizard's pane. The resource that is passed back needs to contain all the pages (in a single dialog resource) that should be displayed by the Profile Wizard. When the Profile Wizard receives this resource, it ignores the dialog style (but not the control styles), and creates all the controls as children of the Profile Wizard page. All controls are initially hidden. Providers should ensure that the coordinates for their controls are 0, 0 based, and that they don't exceed a maximum width of 200 dialog units and a maximum height of 150 dialog units. Control identifiers below 400 are reserved for the Profile Wizard. The Profile Wizard displays the provider's title in bold text above the provider's user interface.  For more information on this function, see the MAPI Programmer's Guide for more information on this function.

The SERVICEWIZARDENTRY prototype function is defined in MAPIWIZ.H.


 SetAttribIMsgOnIStg

[New - Windows 95]

Sets property attributes for properties of a particular object.

Syntax

SetAttribIMsgOnIStg(LPVOID lpObject, LPSPropTagArray lpPropTags, LPSPropAttrArray lpPropAttrs, LPSPropProblemArray FAR* lppPropProblems)

Parameters

lpObject

Input parameter pointing to the object for which property attributes are being set.

lpPropTags

Input parameter pointing to an SPropTagArray structure containing an array of property tags indicating the properties for which property attributes are being set.

lpPropAttrs

Input parameter pointing to the location to which this function writes an SPropAttrArray defining the property attributes that it has set.

lppPropProblems

Output parameter pointing to a variable where the returned SPropProblemArray structure holding a set of property problems is stored. This structure identifies problems encountered if the SetAttribIMsgOnIStg function has been able to set some properties, but not all. If a pointer to NULL is passed in the lppPropProblems parameter, no property problem array is returned even if some properties were not set.

Comments

A message store provider usually calls SetAttribIMsgOnIStg.

The SetAttribIMsgOnIStg function is defined in IMESSAGE.H.

See Also

GetAttribIMsgOnIStg function, SPropAttrArray structure, SPropProblemArray structure, SPropTagArray structure


 ulValidateParameters

[New - Windows 95]

Checks the parameters MAPI and providers receive from clients.

Syntax

HRESULT ulValidateParameters(METHODS eMethod, LPVOID First)

Parameters

eMethod

Specifies the method to validate.

First

Specifies the address of the beginning of the method.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

MAPI_E_CALL_FAILED

An error of unexpected or unknown origin prevented the operation from completing.

Comments

The ulValidateParameters function is called differently depending on whether the calling code is C or C++. This function is used to validate parameters for the few IUnknown and MAPI methods that return ULONG rather than HRESULT values; ValidateParameters works for all others.

Parameters passed between MAPI and providers are assumed to be correct and are not checked. Providers should check all parameters passed in by clients, but clients should assume that MAPI and provider parameters are correct. Use the HR_FAILED macro to test return values.

For more information on parameter validation, see MAPI Programmer's Guide.

The ulValidateParameters function is defined in MAPIVAL.H.

See Also

CheckParameters function  ValidateParameters function


 ValidateParameters

[New - Windows 95]

Checks the parameters providers receive from clients.

Syntax

HRESULT ValidateParameters(METHODS eMethod, LPVOID First)

Parameters

eMethod

Specifies the method to validate.

First

Specifies the address of the beginning of the method.

Return Values

S_OK

All of the parameters are valid.

MAPI_E_CALL_FAILED

One or more of the parameters are not valid.

Comments

Parameters passed between MAPI and providers are assumed to be correct and are not checked. Providers should check all parameters passed in by clients, but clients should assume that MAPI and provider parameters are correct. Use the HR_FAILED macro to test the return values.

ValidateParameters is called differently depending on whether the calling code is C or C++. C++ passes an implicit parameter known as this to each method call, which becomes explicit in C and is the address of the object. The second parameter is different for C and C++: In C++ it is called First, and it is the first parameter to the method being validated. The second parameter for the C language, ppThis, is the address of the first parameter to the method which is always an object pointer. In both cases, the second parameter gives the address of the beginning of the method's parameter list and, based on eMethod , moves down the stack and validates the parameters.

Providers implementing common interfaces such as IMAPITable and IMAPIProp should always check parameters using the ValidateParameter function in order to ensure consistency across all providers. Additional parameter validation functions have been defined for some complex parameter types to be used instead as appropriate. See the reference entries for the following functions: FBadColumnSet, FBadEntryList, FBadProp, FBadPropTag, FBadRestriction, FBadRglpNameID, FBadRglpszW, FBadRow, FBadRowSet, and FBadSortOrderSet.

Inherited methods use the same parameter validation as the interface from which they inherit. For example, the parameter checking for IMessage and IMAPIProp are the same.

For more information on parameter validation, see MAPI Programmer's Guide.

The ValidateParameters function is defined in MAPIVAL.H.

See Also

CheckParameters  ulValidateParameters


 WrapCompressedRTFStream

[New - Windows 95]

Returns a stream containing the uncompressed RTF body of a message.

Syntax

HRESULT WrapCompressedRTFStream(LPSTREAM lpCompressedRTFStream, ULONG uls, LPSTREAM FAR* lpUncompressedRTFStream)

Parameters

lpCompressedRTFStream

Input parameter specifying a pointer to a stream opened on the PR_RTF_COMPRESSED property of a message.

ulFlags

Input parameter specifying a bitmask of option flags for the function. The following flags can be set:

MAPI_WRITE

Returns a stream for reading the RTF.

MAPI_CREATE

Returns a stream for writing the RTF.

lpUncompressedRTFStream

Output parameter specifying a pointer to the location in which this function returns a stream for the uncompressed RTF.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

The WrapCompressedRTFStream function is defined in MAPIUTIL.H.

See Also

RTFSync function


 WrapStoreEntryID

[New - Windows 95]

Initializes a message-store entry identifier.

Syntax

WrapStoreEntryID(ULONG ulFlags, LPTSTR szDLLName, ULONG cbOrigEntry, LPENTRYID lpOrigEntry, ULONG* lpcbWrappedEntry, LPENTRYID* lppWrappedEntry)

Parameters

ulFlags

Input parameter containing a bitmask of flags. The following flag can be set:

MAPI_UNICODE

Indicates the passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

szDLLName

Input parameter containing the name of the message-store provider DLL.

cbOrigEntry

Input parameter containing the size, in bytes, of the original entry identifier for the message store.

lpOrigEntry

Input parameter pointing to an ENTRYID structure defining the original entry identifier.

lpcbWrappedEntry

Output parameter pointing to the location where the returned size, in bytes, of the new entry identifier is stored.

lppWrappedEntry

Output parameter pointing to a variable where the returned entry identifier is stored.

Comments

If the calling client application or service provider supplies an internal entry identifier, the WrapStoreEntryID function wraps it and forms a new identifier.

The WrapStoreEntryID function is defined in MAPIUTIL.H.

See Also

ENTRYID structure  IMAPISession::OpenEntry interface


 XPProviderInit

[New - Windows 95]

Initializes a transport provider for operation.

Syntax

HRESULT XPProviderInit(HINSTANCE hInstance, LPVOID lpvReserved, LPALLOCATEBUFFER lpAllocateBuffer, LPALLOCATEMORE lpAllocateMore, LPFREEBUFFER lpFreeBuffer, ULONG ulFlags, ULONG ulMAPIVer, ULONG FAR* lpulProviderVer, LPXPPROVIDER FAR* lppXPProvider)

Parameters

hInstance

Input parameter containing an instance of the transport provider's dynamic-link library (DLL) that MAPI used when it linked.

lpvReserved

Reserved, must be zero.

lpAllocateBuffer

Input parameters pointing to the MAPIAllocateBuffer function, to be used to allocate memory.

lpAllocateMore

Input parameters pointing to the MAPIAllocateMore function, to be used to allocate additional memory where required.

lpFreeBuffer

Input parameters pointing to the MAPIFreeBuffer function, to be used to free memory.

ulFlags

Reserved; do not use. If any flags are set, the XPProviderInit function fails and returns the value MAPI_E_UNKNOWN_FLAGS.

ulMAPIVer

Input parameter containing the version of the service provider interface that MAPI.DLL uses. For the current version number, see the MAPISPI.H header file.

lpulProviderVer

Input parameter pointing to the version of the service provider interface that the message store uses.

lppXPProvider

Output parameter pointing a variable where the initialized transport provider object returned is stored.

Return Values

S_OK

The call succeeded and has returned the expected value or values.

Comments

To initialize a transport provider, MAPI calls the function named XPProviderInit, based on the XPPROVIDERINIT function prototype defined in MAPISPI.H, from the transport provider's DLL. The transport provider must use its implementation of XPProviderInit to respond to the MAPI initialization call.

The transport provider must also define the XPProviderInit function using the CDECL calling convention. CDECL definition is required for each service provider initialization function to ensure the function can work with the current version of the service provider interface, even if the number of function parameters used is not the number set for that function in the current version of the interface. MAPI provides the XPPROVIDERINIT prototype to help define XPProviderInit as CDECL. The XPPROVIDERINIT prototype has a standard MAPI initialization call type, STDMAPIINITCALLTYPE.

The input parameters lpAllocateBuffer, lpAllocateMore, and lpFreeBuffer point to the MAPIAllocateBuffer, MAPIAllocateMore, and MAPIFreeBuffer functions, respectively, for use by the transport provider DLL. The provider DLL should not be linked with MAPIX.DLL. Instead, it should use these pointers for memory allocation or deallocation. In particular, the provider must use these pointers when allocating memory for use by client applications in calling object interfaces. For example, two provider interface methods that typically allocate memory are IMAPIProp::GetProps and IMAPITable::QueryRows.

The transport provider should retain information on the allocator pointers passed to it in lpAllocateBuffer, lpAllocateMore, and lpFreeBuffer. If the provider will use a memory allocator later, it should call the IUnknown::AddRef method for the allocation object pointed to by the lpMalloc parameter.

For more information on using XPProviderInit, see the information on using the MSProviderInit, ABProviderInit, and XPProviderInit functions in MAPI Programmer's Guide.

The XPProviderInit function is defined in MAPISPI.H.

See Also

ABProviderInit function, HPProviderInit function, IMAPIProp::GetProps method, IMAPITable::QueryRows method, MAPIAllocateBuffer function, MAPIAllocateMore function, MAPIFreeBuffer function, IXPProvider : IUnknown interface, MSProviderInit function


 Extended MAPI Properties

This chapter provides reference information for MAPI properties. This reference provides information about the property identifier, property type, and the value of the property's data for each property. It also provides comments describing each property's usage and limitations.

For definitions and a general discussion of how MAPI works with properties and a list of the properties available on each object, see the MAPI Programmer's Guide. For information on the property-related macros PROP_ID, PROP_TAG, CHANGE_PROP_TYPE, and PROP_TYPE, see MAPI Programmer's Reference.


 Extended MAPI Property Types

The following table describes property types supported by MAPI 1.0. For a complete description of properties and multivalued properties, see the MAPI Programmer's Guide.

Property type	Multivalued type	Underlying data type
PT_APPTIME	PT_MV_APPTIME	Double.  Time; compatible with the Visual Basic time representation.
PT_BINARY	PT_MV_BINARY	SBinary. Counted byte array.
PT_BOOLEAN	(None)	16-bit Boolean; 0 = False, non-zero = True. Same as OLE type VT_BOOL.
PT_CLSID	PT_MV_CLSID	CLSID structure. Class identifier. VT_CLSID.
PT_CURRENCY	PT_MV_CURRENCY	64-bit integer intepreted as decimal. Compatible with Visual Basic CURRENCY type. Same as OLE type VT_CY.
PT_DOUBLE	PT_MV_DOUBLE	Double; 64-bit floating point, PT_R4.  Same as OLE type VT_R8.
PT_ERROR	(None)	SCODE; 32-bit unsigned integer. Same as OLE type VT_ERROR.
PT_FLOAT	PT_MV_FLOAT	32-bit floating point, PT_R4. Same as OLE type VT_R4.
PT_I2	PT_MV_I2	Signed 16-bit integer, PT_SHORT. Same as OLE type VT_I2.
PT_I4	PT_MV_I4	Signed or unsigned 32-bit integer. Same as OLE type VT_I4.  Same as PT_LONG.
PT_I8	PT_MV_I8	Signed or unsigned 64-bit integer. Same as OLE type VT_I8. Uses the structure LARGE_INTEGER.
PT_LONG	PT_MV_LONG	Signed or unsigned 32-bit integer, PT_I4. Same as OLE type VT_I4.
PT_LONGLONG	PT_MV_LONGLONG	Signed or unsigned 64-bit integer, PT_I8. Same as OLE type VT_I8.
PT_NULL	(None)	Indicates no property value. Same as OLE type VT_NULL. Reserved for interface use.
PT_OBJECT	(None)	A pointer to an object that implements IUnknown. Same as several OLE types, including VT_IUNKNOWN.
PT_R4	PT_MV_R4	4-byte floating-point data. Same as OLE type VT_R4.
PT_R8	PT_MV_R8	8-byte floating-point data. Same as OLE type VT_DOUBLE.
PT_SHORT	PT_MV_SHORT	Signed 16-bit integer, PT_SHORT. Same as OLE type VT_I2.
PT_STRING8	PT_MV_STRING8	Null-terminated 8-bit character string data. Same as OLE type VT_LPSTR.
PT_SYSTIME	PT_MV_SYSTIME	64-bit integer date/time value in the form of a FILETIME structure. Same as OLE type VT_FILETIME.
PT_TSTRING	PT_MV_TSTRING	Set to PT_UNICODE when compiling with the UNICODE symbol; else PT_STRING8. Either the OLE type VT_LPSTR or VT_LPWSTR.
PT_UNICODE	PT_MV_UNICODE	Null-terminated wide string data. Same as OLE type VT_LPWSTR.
PT_UNSPECIFIED	(Not supported)	Indicates that the client application does not supply the property type. Reserved for interface use.
See Also

SBinary structure


 Required Properties

This section describes required properties that must be present in the MAPI table objects. Additional columns may be in the table depending on a provider's implementation.

MAPI Table	Required Properties
AB and DL  Contents Table	PR_ADDRTYPE, PR_DISPLAY_NAME, PR_DISPLAY_TYPE, PR_ENTRYID, PR_INSTANCE_KEY, PR_OBJECT_TYPE
AB Display Table	PR_CONTROL_FLAGS, PR_CONTROL_ID, PR_CONTROL_STRUCTURE, PR_CONTROL_TYPE, PR_DELTAX, PR_DELTAY, PR_XPOS, PR_YPOS
AB Hierarchy Table	PR_AB_PROVIDER_ID, PR_CONTAINER_FLAGS, PR_DEPTH, PR_DISPLAY_NAME, PR_DISPLAY_TYPE, PR_ENTRYID, PR_INSTANCE_KEY, PR_OBJECT_NAME, PR_OBJECT_TYPE
AB One-Off Table	PR_ADDRTYPE, PR_DEPTH, PR_DISPLAY_NAME, PR_DISPLAY_TYPE, PR_ENTRYID, PR_INSTANCE_KEY, PR_SELECTABLE
Attachment Table	PR_ATTACH_NUM, PR_RECORD_KEY, PR_RENDERING_POSITION
Message Store Folder Contents Table	PR_CLIENT_SUBMIT_TIME, PR_DISPLAY_TO, PR_ENTRYID, PR_HASATTACH, PR_LAST_MODIFICATION_TIME, PR_MAPPING_SIGNATURE, PR_MESSAGE_CLASS, PR_MESSAGE_DELIVERY_TIME, PR_MESSAGE_FLAGS, PR_MESSAGE_SIZE, PR_MSG_STATUS, PR_NORMALIZED_SUBJECT, PR_OBJECT_TYPE, PR_PARENT_ENTRYID, PR_PRIORITY, PR_RECORD_KEY, PR_SENDER_NAME, PR_SENSITIVITY, PR_STORE_ENTRYID, PR_STORE_RECORD_KEY, PR_SUBJECT
Message Store Hierarchy Table	PR_COMMENT, PR_DEPTH, PR_DISPLAY_NAME, PR_ENTRYID, PR_FOLDER_TYPE, PR_STATUS, PR_SUBFOLDERS
Message Services Table	PR_DISPLAY_NAME, PR_INSTANCE_KEY, PR_SERVICE_NAME, PR_SERVICE_UID
Message Stores Table	PR_DEFAULT_STORE, PR_DISPLAY_NAME, PR_ENTRYID, PR_INSTANCE_KEY, PR_PROVIDER_DISPLAY, PR_RECORD_KEY, PR_RESOURCE_TYPE
Outgoing Message Queue Table	PR_CLIENT_SUBMIT_TIME, PR_DISPLAY_BCC, PR_DISPLAY_CC, PR_DISPLAY_TO, PR_ENTRYID, PR_MESSAGE_FLAGS, PR_MESSAGE_SIZE, PR_PRIORITY, PR_SENDER_NAME, PR_SUBJECT, PR_SUBMIT_FLAGS
Profile Table	PR_DISPLAY_NAME
Provider Table	PR_DISPLAY_NAME, PR_INSTANCE_KEY, PR_PROVIDER_DISPLAY, PR_PROVIDER_DLL_NAME, PR_PROVIDER_UID, PR_RESOURCE_TYPE, PR_SERVICE_NAME, PR_SERVICE_UID
Receive Folder Table	PR_ENTRYID, PR_MESSAGE_CLASS, PR_RECORD_KEY
Recipients Table	PR_ADDRTYPE, PR_DISPLAY_NAME, PR_ENTRYID, PR_OBJECT_TYPE, PR_RECIPIENT_TYPE, PR_ROWID
Status Table	PR_DISPLAY_NAME, PR_ENTRY_ID, PR_IDENTITY_SEARCH_KEY, PR_INSTANCE_KEY, PR_OBJECT_TYPE, PR_PROVIDER_DISPLAY, PR_PROVIDER_DLL_NAME, PR_RESOURCE_FLAGS, PR_RESOURCE_METHODS, PR_RESOURCE_TYPE, PR_ROWID, PR_STATUS_CODE
You can get pointers to the table objects using Extended MAPI interface methods, as described in the table below:

Table	Table Access Method
AB and DL Contents Table	IMAPIContainer::GetContentsTable
AB Display Table	BuildDisplayTable
AB Hierarchy Table	IMAPIContainer::GetHierarchyTable
AB One-Off Table	IABLogon::GetOneOffTable, IMAPISupport::GetOneOffTable
Attachment Table	IMessage::GetAttachmentTable
Message Store Folder Contents Table	IMAPIFolder::GetContentsTable
Message Store Hierarchy Table	IMAPIFolder::GetHierarchyTable
Message Services Table	IMsgServiceAdmin::GetMsgServiceTable
Message Stores Table	IMAPISession::GetMsgStoresTable
Outgoing Message Queue Table	IMsgStore::GetOutgoingQueue
Profile Table	IProfAdmin::GetProfileTable
Provider Table	IMsgServiceAdmin::GetProviderTable, IProviderAdmin::GetProviderTable
Receive Folder Table	IMsgStore::GetReceiveFolderTable
Recipient Table	IMessage::GetRecipientTable
Status Table	IMAPISession::GetStatusTable


 MAPI Property Identifier Ranges

MAPI property identifiers are grouped into the following ranges. The property identifiers 0x0000 and 0xFFFF are reserved and no object should use these property identifiers.

From	To	Property Category
0x0000	0x0000	Reserved for the special property PROP_ID_NULL
0x0001	0x3FFF	MAPI-defined properties
0x4000	0x57FF	Message envelope properties, defined by transport providers.
0x5800	0x5FFF	Message recipient properties, defined by transport providers.
0x6000	0x65FF	Message properties, defined by client applications.
0x6600	0x67FF	Message properties, defined by service providers.
0x6800	0x7BFF	Message contents properties, defined by the message class.
0x7C00	0x7FFF	Message properties, defined by the message class.
0x8000	0xFFFE	Named properties. Application-defined or provider-defined properties identified only by name through the property name-to-identifier mapping facility of the IMAPIProp interface.
0xFFFF	0xFFFF	Reserved for the special property PROP_ID_INVALID
Developing Portable Property-Related Code

To develop portable code for a client application, use the type PT_TSTRING for all string-related properties and conditionally compile your client application for your target platform.

The PT_TSTRING property type is conditionally compiled to the PT_UNICODE type for a Unicode platform and is conditionally compiled to PT_STRING8 for non-Unicode platforms.

For example, consider the property PR_MESSAGE_CLASS, which has three distinct definitions in the file MAPITAGS.H:

#define PR_MESSAGE_CLASS	   PROP_TAG( PT_TSTRING, 0x001A)

#define PR_MESSAGE_CLASS_W	 PROP_TAG( PT_UNICODE, 0x001A)

#define PR_MESSAGE_CLASS_A	 PROP_TAG( PT_STRING8, 0x001A)

Note that all three properties use the same property identifier, 0x001A. The compiler defines PR_MESSAGE_CLASS as either PR_MESSAGE_CLASS_W or PR_MESSAGE_CLASS_A, depending on your target platform. The Unicode version of a string property (the name ending in "_W") is used when you define the symbolic constant UNICODE and compile your code.

Providers should explicitly handle either the UNICODE string type (the property name that ends in "_W") or the ANSI string type (the property name that ends in "_A"), or both.


 Property Reference

The following section contains a reference entry for each Extended MAPI property.

The values for PT_TSTRING displayed in the property tags in this chapter are the values for PT_STRING8, which has the value 0x001E. To obtain the UNICODE version of the property tag, replace the PT_STRING8 value 0x001E with the PT_UNICODE value 0x001F in the low-order 16 bits of the property tag.

For example, the property tag for the PT_STRING8 version of PR_ADDRTYPE is shown as the PT_STRING8 value, 0x3002001E. 0x3002001F is the property tag for the UNICODE version of PR_ADDRTYPE, obtained by replacing the low-order word value 0x001E with the value 0x001F.


 PR_AB_DEFAULT_DIR

[New - Windows 95]

Reserved for use by MAPI.

Details

Identifier 0x3D06; property type PT_BINARY; property tag 0x3D060102

Comments

Do not use this property. It is reserved for use by MAPI only.

See Also

PR_AB_SEARCH_PATH property


 PR_AB_DEFAULT_PAB

[New - Windows 95]

Reserved for use by MAPI.

Details

Identifier 0x3D07; property type PT_BINARY; property tag 0x3D070102

Comments

Do not use this property. It is used by MAPI only.

See Also

PR_AB_PROVIDER_ID property


 PR_AB_PROVIDER_ID

[New - Windows 95]

Contains a MAPI unique identifier value that identifies the address book provider.

Details

Identifier 0x3615; property type PT_BINARY; property tag 0x36150102

Comments

The uid identifies which provider supplies this particular container in the hierarchy. The value is generated by, and is unique to, each provider.

A provider can provide more than one identifier. For example, a provider that supplies two very different containers can publish unique identifiers for each container. This property represents a documented place where the provider can publish the identifier.

This property is analogous to the PR_MDB_PROVIDER property for stores.

This property appears in the hierarchy tables. Address book containers and hierarchy tables should provide this property. Your application can use it to find related rows in an address book hierarchy table.

See Also

MAPIUID structure, PR_MDB_PROVIDER property


 PR_AB_PROVIDERS

[New - Windows 95]

Reserved for use by MAPI.

Details

Identifier 0x3D01; property type PT_BINARY; property tag 0x3D010102

Comments

Do not use this property. It is reserved for use by MAPI only.

See Also

PR_AB_PROVIDER_ID property


 PR_AB_SEARCH_PATH

[New - Windows 95]

Reserved for use by MAPI.

Details

Identifier 0x3D05; property type PT_MV_BINARY; property tag 0x3D051102

Comments

Do not use this property. It is used by MAPI only.

See Also

PR_AB_DEFAULT_DIR property


 PR_AB_SEARCH_PATH_UPDATE

[New - Windows 95]

Reserved for use by MAPI.

Details

Identifier 0x3D11; property type PT_BINARY; property tag 0x3D110102

Comments

Do not use this property. It is used by MAPI only. Contains an entry identifier for the address book container. Used in conjunction with PR_AB_SEARCH_PATH.

See Also

PR_AB_SEARCH_PATH property


 PR_ACCESS

[New - Windows 95]

Contains a bitmask of flags indicating the level at which the client application can access the open object.

Details

Identifier 0x0FF4, Type:  PT_LONG; property tag 0x0FF40003

Comments

Zero or more of the following flags can be set:

Value	Description
MAPI_ACCESS_CREATE_ASSOCIATED	The client can create the associated contents table.
MAPI_ACCESS_CREATE_CONTENTS	The client can create a contents table.
MAPI_ACCESS_CREATE_HIERARCHY	The client can create a hierarchy table.
MAPI_ACCESS_DELETE	The client can delete the object.
MAPI_ACCESS_MODIFY	The client can write to the object.
MAPI_ACCESS_READ	The client can read the object.
See Also

PR_ACCESS_LEVEL property


 PR_ACCESS_LEVEL

[New - Windows 95]

Contains a bitmask of flags indicating the level at which the client application can access the open object.

Details

Identifier 0x0FF7; property type PT_LONG; property tag 0x0FF70003

Comments

Use PR_ACCESS_LEVEL to determine whether write access was granted. Calls to IMsgStore::OpenEntry can request the best available access. By default, access is read-only, although the access granted is defined by the provider. A generous provider can offer higher access than that requested. For example, the provider may choose to grant read and write access when the client requested read-only access.

The following flag can be set:

Value	Description
MAPI_MODIFY	Write access.
See Also

PR_ACCESS property


 PR_ACCOUNT

[New - Windows 95]

Contains the messaging user's account name.

Details

Identifier 0x3A00; property type PT_TSTRING; property tag 0x3A00001E

Comments

Many properties are available for the messaging user, including several properties that identify the user's  addresses and several telephone numbers.

See Also

PR_EMAIL_ADDRESS property


 PR_ACKNOWLEDGEMENT_MODE

[New - Windows 95]

Contains the identifier of the mode for message acknowledgment.

Details

Identifier 0x0001; property type PT_LONG; property tag 0x00010003

Comments

Corresponds to the interpersonal notification IM_ACKNOWLEDGEMENT_MODE attribute as defined by the X.400 message-handling standard.

X.400 defines the following values:

Value	Description
0	Manual acknowledgment
1	Automatic acknowledgment
See Also

PR_MESSAGE_CLASS property


 PR_ADDRTYPE

[New - Windows 95]

Contains the recipient's e-mail address type, such as "SMTP".

Details

Identifier 0x3002; property type PT_TSTRING; property tag 0x3002001E

Comments

PR_ADDRTYPE specifies whichh messaging service the MAPI system uses to handle a given message. This property also determines the format of the address string. Examples include X400, FAX, MHS, and PROFS.

PR_ADDRTYPE qualifies the PR_EMAIL_ADDRESS property. The string provided by PR_ADDRTYPE can contain only the uppercase alphabetic characters A through Z and the numbers 0 through 9.

Distribution list objects and mail user objects must furnish PR_ADDRTYPE.

See Also

PR_EMAIL_ADDRESS property


 PR_ALTERNATE_RECIPIENT

[New - Windows 95]

Contains an entry identifier defining an alternate recipient chosen by a message sender to receive a message if it cannot be delivered to the original recipient.

Details

Identifier 0x3A01; property type PT_BINARY; property tag 0x3A010102

Comments

For X.400 environments, PR_ALTERNATE_RECIPIENT corresponds to the MH_T_ALTERNATE_RECIPIENT_NAME attribute as defined by the X.400 message-handling standard.

See Also

PR_ALTERNATE_RECIPIENT_ALLOWED property


 PR_ALTERNATE_RECIPIENT_ALLOWED

[New - Windows 95]

Contains TRUE if the messaging system delivers the associated message to an alternate delegated by the original recipient, and FALSE otherwise.

Details

Identifier 0x0002; property type PT_BOOLEAN; property tag 0x0002000B

Comments

For X.400 and EDI environments, PR_ALTERNATE_RECIPIENT_ALLOWED represents the corresponding submission envelope per-message attributes as defined by the X.400 and EDI message-handling standards. For X.400 environments, this MAPI property corresponds to the MH_T_ALTERNATE_RECIP_ALLOWED attribute.

See Also

PR_ALTERNATE_RECIPIENT property


 PR_ANR

[New - Windows 95]

Represents a special property that can be placed in a property restriction to enable special behavior in address book containers.

Details

Identifier 0x360c; property type PT_TSTRING; property tag 0x360C001E

Comments

PR_ANR is not a property of any object. It contains an ambiguous name resolution (ANR) restriction that can be tested against an address book contents table to find corresponding message recipients. It is used exclusively by providers.

See Also

PR_ENTRYID property


 PR_ASSISTANT

[New - Windows 95]

Contains the name of the messaging user's administrative assistant.

Details

Identifier 0x3A30; property type PT_TSTRING; property tag 0x3A30001E

Comments

Another related property, PR_ASSISTANT_TELEPHONE_NUMBER, contains the assistant's phone number.

See Also

PR_ASSISTANT_TELEPHONE_NUMBER property


 PR_ASSISTANT_TELEPHONE_NUMBER

[New - Windows 95]

Contains the phone number of the messaging user's administrative assistant.

Details

Identifier 0x3A2E; property type PT_TSTRING; property tag 0x3A2E001E

Comments

The phone number is for the assistant specified by the property PR_ASSISTANT.

See Also

PR_ENTRYID property


 PR_ASSOC_CONTENT_COUNT

[New - Windows 95]

Contains the count of items in the associated contents folder.

Details

Identifier 0x3617; property type PT_LONG; property tag 0x36170003

Comments

The PR_FOLDER_ASSOCIATED_CONTENTS property indicates the associated contents folder object.

See Also

PR_ACCESS property, PR_FOLDER_ASSOCIATED_CONTENTS property


 PR_ATTACH_DATA_BIN

[New - Windows 95]

Contains binary attachment data typically accessed through an OLE IStream interface.

Details

Identifier 0x3701; property type PT_BINARY; property tag 0x37010102

Comments

For X.400 environments, PR_ATTACH_DATA_BIN corresponds to the IM_EXTERNAL_DATA or IM_BILATERAL_DATA attributes, depending on the object, as defined by the X.400 message-handling standard.

See Also

PR_ATTACH_DATA_OBJ property, PR_ATTACH_METHOD property


 PR_ATTACH_DATA_OBJ

[New - Windows 95]

Contains an object accessible through an OLE interface.

Details

Identifier 0x3701; property type PT_OBJECT; property tag 0x3701000D

Comments

For an embedded dynamic OLE object, PR_ATTACH_DATA_OBJ contains its own rendering information. The PR_ATTACH_RENDERING property is either nonexistent or empty.

If your client application or service provider cannot open an attachment object using PR_ATTACH_DATA_OBJ with PR_ATTACH_METHOD, use PR_ATTACH_DATA_BIN.

For X.400 environments, PR_ATTACH_DATA_OBJ corresponds to the IM_EXTERNAL_DATA attribute as defined by the X.400 message-handling standard.

See Also

PR_ATTACH_DATA_BIN property, PR_ATTACH_METHOD property, PR_ATTACH_RENDERING property


 PR_ATTACH_ENCODING

[New - Windows 95]

Contains an ASN.1 object identifier specifying the encoding for an attachment.

Details

Identifier 0x3702; property type PT_BINARY; property tag 0x37020102

Comments

The syntax and sample object identifiers (OIDs) are defined in the header file MAPIOID.H. For example, the header file includes OIDs for TNEF, MAPI 1.0 OLE 2.0 IStorage, and MacBinary.

For complete information on these types, see the ASN.1 documentation.

See Also

PR_ATTACH_DATA_BIN property, PR_ATTACH_METHOD property


 PR_ATTACH_EXTENSION

[New - Windows 95]

Contains a filename extension (for example, "TXT" or "DOC") that indicates the document type of the attachment.

Details

Identifier 0x3703; property type PT_TSTRING; property tag 0x3703001E

Comments

The message store maintains the attachment data associated with this property and generates an appropriate property tag. The client sets this property.

Your service provider uses PR_ATTACH_EXTENSION when converting message attachments (in-route conversion) or launching applications based on attachments in received messages. If the provider does not implement this property, MAPI generates its own filename extension for an attachment based on the extension provided by the attachment's PR_ATTACH_FILENAME property.

See Also

PR_ATTACH_FILENAME property


 PR_ATTACH_FILENAME

[New - Windows 95]

Provides a message recipient with an attachment's base filename and extension, excluding path.

Details

Identifier 0x3704; property type PT_TSTRING; property tag 0x3704001E

Comments

The filename is restricted to an 8.3 filename: eight characters plus an extension. For long filenames, use the property PR_ATTACH_LONG_FILENAME.

PR_ATTACH_FILENAME pertains to the attachment methods ATTACH_BY_REFERENCE, ATTACH_BY_REF_RESOLVE, and ATTACH_BY_REF_ONLY, as described for the PR_ATTACH_METHOD property.

For X.400 environments, PR_ATTACH_FILENAME corresponds to the IM_EXTERNAL_PARAMETERS attribute as defined by the X.400 message-handling standard.

See Also

PR_ATTACH_LONG_FILENAME property, PR_ATTACH_METHOD property, PR_ATTACH_PATHNAME property


 PR_ATTACH_LONG_FILENAME

[New - Windows 95]

Provides the message recipient with an attachment's long filename, excluding path.

Details

Identifier 0x3707; property type PT_TSTRING; property tag 0x3707001E

Comments

Your application should set this property to a suggested long filename to be used if the host machine receiving a message supports long filenames.

Unlike the filename provided by PR_ATTACH_FILENAME, this name is not restricted to the 8.3 naming convention (up to eight characters and up to three character extension).

See Also

PR_ATTACH_FILENAME property


 PR_ATTACH_METHOD

[New - Windows 95]

Contains a MAPI-defined constant representing the method used to access the contents of an attachment.

Details

Identifier 0x3705; property type PT_LONG; property tag 0x37050003

Comments

On creation, all attachment objects have an initial PR_ATTACH_METHOD value of 0, NO_ATTACHMENT.

The MAPI spooler presents the attachment to the transport as if it were attached by value, so that the actual attachment data is not copied to the message store or the message. The attachment data itself is present in the property PR_ATTACH_DATA_BIN.

Client applications and service providers are only required to support the ATTACH_BY_VALUE method. The other methods are optional.

UNC names are recommended for fully-resolved pathnames.

The message store does not enforce any consistency between the value of PR_ATTACH_METHOD and the values of the other attachment properties.

The PR_ATTACH_METHOD property can have the following values:

Value	Description
0	Value indicating that the attachment has just been created.
ATTACH_BY_VALUE	The PR_ATTACH_DATA_BIN property contains the attachment data.
ATTACH_BY_REFERENCE	The PR_ATTACH_PATHNAME property contains a fully-resolved pathname identifying the attachment to recipients with access to a common file server. If ATTACH_BY_REFERENCE is present, PR_ATTACH_DATA_BIN is empty.  A gateway can turn an ATTACH_BY_REFERENCE attachment into an attachment using ATTACH_BY_VALUE to move the attachment data to the PR_ATTACH_DATA_BIN property.
ATTACH_BY_REF_RESOLVE	The PR_ATTACH_PATHNAME property contains a fully-resolved pathname identifying the attachment. If ATTACH_BY_REF_RESOLVE is present, PR_ATTACH_DATA_BIN is empty.  When the message that contains the ATTACH_BY_REF_RESOLVE attachment is sent, the MAPI spooler resolves the attachment into an ATTACH_BY_VALUE attachment. This resolution process places the attachment data in PR_ATTACH_DATA_BIN.
ATTACH_BY_REF_ONLY	The PR_ATTACH_PATHNAME property contains a fully-resolved pathname identifying the attachment. If ATTACH_BY_REF_ONLY is present, PR_ATTACH_DATA_BIN is empty and the messaging system never resolves the attachment reference. Use this value when you want to send the link but not the data.
ATTACH_EMBEDDED_MSG	The PR_ATTACH_DATA_OBJ property contains an embedded object that supports the IMessage interface.
ATTACH_OLE	The attachment is an embedded OLE object. When the OLE object is in OLE 2.0 IStorage format, the data is accessible via PR_ATTACH_DATA_OBJ. When the OLE object is in OLE 1.0 OleStream format, the data is accessible via PR_ATTACH_DATA_BIN as an IStream. The type of the OLE encoding can be determined by the PR_ATTACH_TAG value.
See Also

PR_ATTACH_TAG property, PR_STORE_SUPPORT_MASK property


 PR_ATTACH_NUM

[New - Windows 95]

Contains a number that uniquely identifies the attachment within its parent message.

Details

Identifier 0x3706; property type PT_LONG; property tag 0x37060003

Comments

The message store object generates and maintains the PR_ATTACH_NUM property. The attachment number is the secondary sort key in the attachment table.

Used when the attachment is opened using the IMessage::OpenAttach method. Within a client application's session, the PR_ATTACH_NUM property of a message attachment remains constant as long as the attachment table is open. MAPI propagates changes to the table using the IMessage::CreateAttach and the IMessage::DeleteAttach methods and generates a table notification on the open attachment tables so that client applications can resynchronize to those changes.

See Also

PR_ATTACH_METHOD property


 PR_ATTACH_PATHNAME

[New - Windows 95]

Contains the fully qualified path and filename for the file that has been attached to a message by reference.

Details

Identifier 0x3708; property type PT_TSTRING; property tag 0x3708001E

Comments

The PR_ATTACH_PATHNAME property indicates that the actual input data resides in the attachment.

Clients should use a UNC file naming convention when the file is shared, and should use an absolute pathname when the file is local. The provider that moves the message from that computer must convert absolute filenames to UNC.

PR_ATTACH_PATHNAME is required when you use any of the PR_ATTACH_METHOD flags that indicate attach by reference: ATTACH_BY_REFERENCE, ATTACH_BY_REF_RESOLVE, or ATTACH_BY_REF_ONLY.

See Also

PR_ATTACH_FILENAME property, PR_ATTACH_METHOD property, ScLocalPathFromUNC function, ScUNCFromLocalPath function


 PR_ATTACH_RENDERING

[New - Windows 95]

Contains rendering information, such as an icon or metafile, that you can use to represent the attachment in a message.

Details

Identifier 0x3709; property type PT_BINARY; property tag 0x37090102

Comments

Your application can use this property when representing an attachment in a message.

For an attached file, the property usually contains the icon for the file.

For an embedded static OLE object, it contains a Microsoft Windows metafile that can be used to draw the attachment representation in a window.

For an embedded dynamic OLE object, the client should use the OLE data to generate the rendering information.

See Also

PR_ATTACH_PATHNAME property


 PR_ATTACH_SIZE

[New - Windows 95]

Contains the sum in bytes of the sizes of all properties in the attachment object.

Details

Identifier 0x0E20; property type PT_LONG; property tag 0x0E200003

Comments

PR_ATTACH_SIZE contains the sum of the sizes of all the properties in the attachment object, including the size of PR_ATTACH_DATA_BIN or PR_ATTACH_DATA_OBJ. Accordingly, PR_ATTACH_SIZE is usually larger than the contents of the attachment alone. For OLE objects, PR_ATTACH_SIZE provides a useful estimate of the size of the attached object.

This property can be used to check the size of the attachment before performing a remote transfer by modem, and to display progress indicators when saving the attachment to disk.

PR_ATTACH_SIZE provides the same information for the attachment object that PR_MESSAGE_SIZE provides for the message.

See Also

PR_ATTACH_NUM property, PR_MESSAGE_SIZE property


 PR_ATTACH_TAG

[New - Windows 95]

Contains further information about the attachment data.

Details

Identifier 0x370A; property type PT_BINARY; property tag 0x370A0102

Comments

For example, when PR_ATTACH_ENCODING indicates the format, PR_ATTACH_TAG contains an ASN.1 attachment object identifier (OID) identifying a document or file type that should be associated with the attachment.

For X.400 environments, PR_ATTACH_TAG corresponds to the IM_EXTERNAL_PARAMETERS attribute as defined by the X.400 message-handling standard.

See Also

PR_ATTACH_ENCODING property


 PR_ATTACH_TRANSPORT_NAME

[New - Windows 95]

Contains the name of an attachment file modified so that it can be correlated with TNEF messages.

Details

Identifier 0x370C; property type PT_TSTRING; property tag 0x370C001E

Comments

TNEF and the transport provider use this property. It is normally not available to a client application.

This property is commonly used by TNEF when your underlying messaging system wouldn't otherwise support the supplied filenames. For example, this property would be used when the user supplies multiple files with the same name, such as five files named CONFIG.SYS. The transport must modify the names to ensure uniqueness. The modified names appear in PR_ATTACH_TRANSPORT_NAME.

See Also

PR_ATTACH_FILENAME property, PR_ATTACH_PATHNAME property


 PR_ATTACHMENT_X400_PARAMETERS

[New - Windows 95]

Contains an ASN.1 object identifier describing an attachment for handling in transit, for example, between platforms.

Details

Identifier 0x3700; property type PT_BINARY; property tag 0x37000102

Comments

In X.400 environments, PR_ATTACHMENT_X400_PARAMETERS corresponds to the IM_EXTERNAL_PARAMETERS attribute as defined by the X.400 message-handling standard. X.400 applications use this property to make the "Parameters" component of a text (body) part of a message.

See Also

PR_ATTACH_ENCODING property


 PR_AUTHORIZING_USERS

[New - Windows 95]

Contains a list of entry identifiers for users who have authorized the sending of a message.

Details

Identifier 0x0003; property type PT_BINARY; property tag 0x00030102

Comments

This MAPI property corresponds to the interpersonal notification IM_AUTHORIZING_USERS attribute as defined by the X.400 message-handling standard. X.400 transport providers use this property for interpersonal messages delivered to client applications.

The message store does not maintain the PR_AUTHORIZING_USERS property.

See Also

PR_ENTRYID property


 PR_AUTO_FORWARD_COMMENT

[New - Windows 95]

Contains a comment added by the autoforwarding agent.

Details

Identifier 0x0004; property type PT_TSTRING; property tag 0x0004001E

Comments

This MAPI property corresponds to the interpersonal notification IM_AUTO_FORWARD_COMMENT attribute as defined by the X.400 message-handling standard.

See Also

PR_AUTO_FORWARDED property


 PR_AUTO_FORWARDED

[New - Windows 95]

Contains TRUE if an automatic agent has forwarded a message, and FALSE otherwise.

Details

Identifier 0x0005; property type PT_BOOLEAN; property tag 0x0005000B

Comments

This MAPI property corresponds to the IM_AUTO_FORWARDED attribute as defined by the X.400 message-handling standard. X.400 transport providers use this property for interpersonal messages delivered to client applications.

See Also

PR_AUTO_FORWARD_COMMENT property


 PR_BEEPER_TELEPHONE_NUMBER

[New - Windows 95]

Contains the telephone number of the messaging user's beeper, or pager.

Details

Identifier 0x32A1; property type PT_TSTRING; property tag 0x32A1001E

Comments

This property is the same as the PR_PAGER_TELEPHONE_NUMBER. property

See Also

PR_PAGER_TELEPHONE_NUMBER property


 PR_BODY

[New - Windows 95]

Contains the text (body) of a message.

Details

Identifier 0x1000; property type PT_TSTRING; property tag 0x1000001E

Comments

The value for PR_BODY must be expressed in the code page of the operating system that MAPI is running on.

The PR_BODY property is only used with interpersonal messaging (IPM).

For X.400 environments, PR_BODY corresponds to the IM_BODY or IM_TEXT attribute as defined by the X.400 message-handling standard.

See Also

PR_RENDERING_POSITION property, PR_RTF_COMPRESSED property, PR_RTF_IN_SYNC property


 PR_BODY_CRC

[New - Windows 95]

Contains a current circular redundancy check (CRC) value computed by a service provider using any CRC algorithm that generates a PT_LONG value.

Details

Identifier 0x0E1C; property type PT_LONG; property tag 0x0E1C0003

Comments

The application only uses PR_BODY_CRC to compare message text (body) strings contained in PR_BODY properties or their variants.

Using this property, your application can quickly and easily detect when the body of a message has changed. It can realize significant performance gains from using PR_BODY_CRC instead of obtaining PR_BODY from the server and comparing it with a local version.

For RTF body values, the RTF_IN_SYNC property.

See Also

PR_BODY property, PR_RTF_IN_SYNC property


 PR_BUSINESS_FAX_NUMBER

[New - Windows 95]

Contains the telephone number of the messaging user's business fax machine.

Details

Identifier 0x3A24; property type PT_TSTRING; property tag 0x3A24001E

Comments

Other messaging user properties include the business telephone number.

See Also

PR_BUSINESS_TELEPHONE_NUMBER property


 PR_BUSINESS_TELEPHONE_NUMBER

[New - Windows 95]

Contains the primary telephone number for the messaging user's place of business.

Details

Identifier 0x3A08; property type PT_TSTRING; property tag 0x3A08001E

Comments

Other messaging user business-related properties include the fax number and secondary business phone number.

See Also

PR_BUSINESS_FAX_NUMBER property


 PR_BUSINESS2_TELEPHONE_NUMBER

[New - Windows 95]

Contains the secondary telephone number for the messaging user's place of business.

Details

Identifier 0x3A1B; property type PT_TSTRING, Property tag: 3a1b001e

Comments

Other messaging user business-related properties include the fax number and primary business phone number.

See Also

PR_BUSINESS_FAX_NUMBER property


 PR_CALLBACK_TELEPHONE_NUMBER

[New - Windows 95]

Contains a telephone number that the message recipient can use to reach the sender.

Details

Identifier 0x3A02; property type PT_TSTRING; property tag 0x3A02001E

Comments

Other messaging user properties include the fax number, primary, and secondary business phone number.

See Also

PR_BUSINESS_FAX_NUMBER property


 PR_CAPABILITIES_TABLE

[New - Windows 95]

This property is not supported in MAPI 1.0.

Details

Identifier 0x3903; property type PT_OBJECT; property tag 0x3903000D

Comments

In previous releases, this property contained an embedded table object that provides a summary of the address book capabilities.


 PR_CAR_TELEPHONE_NUMBER

[New - Windows 95]

Contains the car telephone number of the messaging user.

Details

Identifier 0x3A1E; property type PT_TSTRING; property tag 0x3A1E001E

Comments

Several properties are available for the messaging user, including properties for the fax telephone number, cellular telephone number, and business telephone numbers.

See Also

PR_BUSINESS_TELEPHONE_NUMBER property


 PR_CELLULAR_TELEPHONE_NUMBER

[New - Windows 95]

Contains the cellular telephone number of the messaging user.

Details

Identifier 0x3A1C; property type PT_TSTRING; property tag 0x3A1C001E

Comments

Other messaging user properties include the fax number, primary, and secondary business phone number.

See Also

PR_BUSINESS_TELEPHONE_NUMBER property


 PR_CLIENT_SUBMIT_TIME

[New - Windows 95]

Contains the time computed by a transport provider that indicates when the message sender marked a message for submission.

Details

Identifier 0x0039; property type PT_SYSTIME; property tag 0x00390040

Comments

This MAPI property corresponds to the MH_T_SUBMISSION_TIME attribute as defined by the X.400 message-handling standard. This property is added to a message based on the results of a submission.

See Also

PR_PROVIDER_SUBMIT_TIME property


 PR_COMMENT

[New - Windows 95]

Contains a messaging user-defined comment about the purpose or content of an object.

Details

Identifier 0x3004; property type PT_TSTRING; property tag 0x3004001E

Comments

The content of the string is defined by the specific needs of the messaging user.

See Also

PR_AUTO_FORWARD_COMMENT property


 PR_COMMON_VIEWS_ENTRYID

[New - Windows 95]

Contains the entry identifier of the common views folder.

Details

Identifier 0x35E6; property type PT_BINARY; property tag 0x35E60102

Comments

This folder is not visible in the IPM hierarchy.

See Also

PR_DEFAULT_VIEW_ENTRYID property, PR_VIEWS_ENTRYID property


 PR_COMPANY_NAME

[New - Windows 95]

Contains the company name of the messaging user.

Details

Identifier 0x3A16; property type PT_TSTRING; property tag 0x3A16001E

Comments

Other messaging user properties include the fax number, primary, and secondary business phone number.

See Also

PR_BUSINESS_TELEPHONE_NUMBER property


 PR_CONTAINER_CLASS

[New - Windows 95]

Contains a text string that identifies the folder, as PR_MESSAGE_CLASS identifies the message class.

Details

Identifier 0x3613; property type PT_TSTRING; property tag 0x3613001E

Comments

Your application should set this property for a folder object that it creates. The application should not attempt further accesses to folders that have a PR_CONTAINER_CLASS value that your application does not recognize.

See Also

PR_CONTAINER_CONTENTS property


 PR_CONTAINER_CONTENTS

[New - Windows 95]

Contains an embedded contents table object that describes the characteristics of a container.

Details

Identifier 0x360f; property type PT_OBJECT; property tag 0x360F000D

Comments

PR_CONTAINER_CONTENTS describes the characteristics of a container, similar to the way that PR_STORE_SUPPORT_MASK describes the characteristics of a message store.

To retrieve container or folder contents, your application should call IMAPIContainer::GetContentsTable. The application cannot retrieve PR_CONTAINER_CONTENTS data by calling IMAPIProp::GetPropList or IMAPIProp::GetProps.

See Also

IMAPIContainer::GetContentsTable method, PR_CONTAINER_FLAGS property


 PR_CONTAINER_FLAGS

[New - Windows 95]

Contains a bitmask of flags describing the address book container.

Details

Identifier 0x3600; property type PT_LONG; property tag 0x36000003

Comments

The flags refer to the container itself than to the items within the container. For example, AB_MODIFIABLE indicates that the container allows entries to be added or deleted. The flag does not refer to whether the individual objects themselves can be added or deleted.

Either AB_MODIFIABLE or AB_UNMODIFIABLE must be set. When both flags are cleared, an error occurs. Note that it is valid for both flags to be set. When both are set, you must attempt a call and examine the return code to determine the container's capabilities. Most client applications examine only the AB_MODIFIABLE bit. When it is set, the client makes a call that attempts to modify the container, and check the return value.

Note that both the AB_UNMODIFIABLE and AB_MODIFIABLE bits can be set at the same time, to indicate that the container does not know whether it can be modified or not. One or both must be set.

The following flags can be set for the PR_CONTAINER_FLAGS bitmask:

Value	Description
AB_FIND_ON_OPEN	Display UI to request a restriction before it displays any contents of the container.
AB_MODIFIABLE	You can add and remove entries from the container. Note that this setting does not indicate creation or deletion of the objects, but solely whether they can be placed in the container.
AB_RECIPIENTS	It is possible to modify the contents table, not just the hierarchy table. It is possible for the container to contain recipients. Note that this flag does not indicate whether any recipients are present in the container.
AB_SUBCONTAINERS	Indicates the container holds child containers. This flag must be set for the container to support IMAPIContainer::GetHierarchyTable.
AB_UNMODIFIABLE	The container cannot be modified.
See Also

PR_CONTAINER_CONTENTS property


 PR_CONTAINER_HIERARCHY

[New - Windows 95]

Contains an embedded hierarchy table object that provides information about the child containers. Details

Identifier 0x360e; property type PT_OBJECT; property tag 0x360E000D

Comments

This property is equivalent to the GetHierarchyTable method.

Your application can use the PR_CONTAINER_HIERARCHY property to exclude an item from a copy operation.

To retrieve the data from this property, your application should call IMAPIContainer::GetHierarchyTable. The application cannot retrieve hierarchy data by calling IMAPIProp::GetPropList or IMAPIProp::GetProps.

Several MAPI properties provide access to table objects:

Property	Table
PR_CONTAINER_HIERARCHY	Hierarchy table
PR_FOLDER_ASSOCIATED_CONTENTS	Associated contents table
PR_MESSAGE_ATTACHMENTS	Attachments table
PR_MESSAGE_RECIPIENTS	Recipients table
See Also

IMAPIProp::CopyProps method, IMAPIProp::CopyTo method, PR_CONTAINER_CONTENTS property, PR_MESSAGE_ATTACHMENTS property, PR_MESSAGE_RECIPIENTS property


 PR_CONTAINER_MODIFY_VERSION

[New - Windows 95]

Contains the current modification version for the container.

Details

Identifier 0x3614; property type PT_I8; property tag 0x36140014

Comments

PT_I8 is an eight-byte, or 64-bit integer. The format is described in the reference documentation for the structure LARGE_INTEGER.

See Also

PR_CONTAINER_CLASS property


 PR_CONTENT_CONFIDENTIALITY_ALGORITHM_ID

[New - Windows 95]

Contains an identifier for the algorithm used to confirm message content confidentiality.

Details

Identifier 0x0006; property type PT_BINARY; property tag 0x00060102

Comments

X.400 and EDI transport providers use this property for messages delivered to client applications.

This MAPI property represents the corresponding X.400 and EDI submission envelope per-message attributes as defined by the X.400 and EDI message-handling standards. For X.400 environments, this property corresponds to the MH_T_ALGORITHM_ID or MH_T_CONFIDENTIALITY_ALGORITHM attribute.

See Also

PR_SECURITY property


 PR_CONTENT_CORRELATOR

[New - Windows 95]

Contains a copy of any reports generated by an outbound message to assist the message sender in matching a report with the original message.

Details

Identifier 0x0007; property type PT_BINARY; property tag 0x00070102

Comments

This MAPI property represents the corresponding X.400 and EDI submission envelope per-message attributes as defined by the X.400 and EDI message handling standards. For X.400 environments, PR_CONTENT_CORRELATOR corresponds to the MH_T_CONTENT_CORRELATOR attribute.

X.400 environments use this property in probe messages and to represent report per-message attributes. EDI transport providers use it for messages delivered to client applications.

See Also

PR_CONTENT_IDENTIFIER property


 PR_CONTENT_COUNT

[New - Windows 95]

Contains the number of entries in the container, as computed by the message store.

Details

Identifier 0x3602; property type PT_LONG; property tag 0x36020003

Comments

The number does not include associated entries.

See Also

PR_CONTENT_UNREAD property


 PR_CONTENT_IDENTIFIER

[New - Windows 95]

Contains a key value that enables the recipient of a message to identify its content.

Details

Identifier 0x0008; property type PT_TSTRING; property tag 0x0008001E

Comments

This MAPI property represents the corresponding X.400 and EDI submission envelope per-message attributes as defined by the X.400 and EDI message-handling standards. For X.400 environments, PR_CONTENT_IDENTIFIER corresponds to the MH_T_CONTENT_IDENTIFIER attribute. Both X.400 and EDI transport providers use this property for messages delivered to client applications.X.400 environments also use this property in probe messages.

See Also

PR_CONTENT_LENGTH property


 PR_CONTENT_INTEGRITY_CHECK

[New - Windows 95]

Contains an ASN.1 content integrity check value that allows a message sender to protect message content from disclosure to unauthorized recipients.

Details

Identifier 0x0C00; property type PT_BINARY; property tag 0x0C000102

Comments

Both X.400 and EDI transport providers use this property for messages delivered to client applications.  For X.400 environments, PR_CONTENT_INTEGRITY_CHECK corresponds to the MH_T_INTEGRITY_CHECK attribute.

See Also

PR_CONTENT_IDENTIFIER property


 PR_CONTENT_LENGTH

[New - Windows 95]

Contains a message length (in bytes) passed to a client application or service provider to determine if a message of that length can be delivered.

Details

Identifier 0x0009; property type PT_LONG; property tag 0x00090003

Comments

This MAPI property corresponds to the probe submission per-message MH_T_CONTENT_LENGTH attribute as defined by the X.400 message-handling standard.

See Also

PR_CONTENT_IDENTIFIER property


 PR_CONTENT_RETURN_REQUESTED

[New - Windows 95]

Contains TRUE if a particular message should be returned with a nondelivery report, and FALSE otherwise.

Details

Identifier 0x000A; property type PT_BOOLEAN; property tag 0x000A000B

Comments

This MAPI property represents the corresponding X.400 and EDI submission envelope per-message attributes as defined by the X.400 and EDI message-handling standards. For X.400 environments, PR_CONTENT_RETURN_REQUESTED corresponds to the MH_T_CONTENT_RETURN_REQUESTED attribute.

See Also

PR_CONTENT_LENGTH property


 PR_CONTENT_UNREAD

[New - Windows 95]

Contains a count of the number of unread messages in an address book container or folder contents table.

Details

Identifier 0x3603; property type PT_LONG; property tag 0x36030003

Comments

For a folder, contains the count of the number of messages in the contents table for which the message read flag is not set.

See Also

PR_CONTENT_COUNT property, PR_CONTENT_IDENTIFIER property


 PR_CONTENTS_SORT_ORDER

[New - Windows 95]

Contains a value specifying the sort order for the columns of the container or folder contents table.

Details

Identifier 0x360D; property type PT_MV_LONG; property tag 0x360D1003

Comments

The PR_CONTENTS_SORT_ORDER property can have the following values:

Value	Description
TABLE_SORT_ASCEND	Ascending order
TABLE_SORT_DESCEND	Descending order
TABLE_SORT_COMBINE	Combine to right order.
See Also

PR_CONTENT_IDENTIFIER property, SSortOrder structure


 PR_CONTROL_FLAGS

[New - Windows 95]

Contains a value that controls the behavior associated with the display table.

Details

Identifier 0x3F00; property type PT_LONG; property tag 0x3F000003

Comments

The following flags can be set for the PR_CONTROL_FLAGS bitmask:

Value	Description
DT_ACCEPT_DBCS	Used with edit controls and combo box controls. Allows multiple-byte character sets.
DT_EDITABLE	Indicates that you can edit the control; the value associated with the control can be changed. When this flag is not set, the control is read-only. This value is ignored on label, group box, standard push button, multivalued drop down list box and list box controls.
DT_MULTILINE	Indicates that the edit control can contain multiple lines. This indicates whether you can enter a return character within the control.
DT_PASSWORD_EDIT	Applies to edit controls. Indicates that when you enter a password, the password is not echoed to the control but is displayed using asterisk characters.
DT_REQUIRED	Indicates that if the control allows changes (DT_EDITABLE), the control must have a value before you can call SaveChanges.
DT_SET_IMMEDIATE	Enables immediate setting of a value; as soon as you change a value in the control, MAPI calls the SetProps method for the property associated with that control.  When this flag is not set, the values are set when the control loses focus.
DT_SET_SELECTION	When a selection is made within the listbox, the index column of that listbox is set as a property. Always used with DT_SET_IMMEDIATE.
See Also

DTCTL structure, IMAPIProp::SaveChanges method, PR_CONTROL_ID property


 PR_CONTROL_ID

[New - Windows 95]

Contains the unique identifier for a control used in a dialog box.

Details

Identifier 0x3F07; property type PT_BINARY; property tag 0x3F070102

Comments

PR_CONTROL_ID contains a unique identifier for the control. It is recommended that this be formed from a GUID followed by a LONG, in binary format. Use the same GUID to identify the provider, and use unique LONG values for each control to ensure that the controls do not collide.

The PR_CONTROL_ID value is used in notifications. For example, notifications sent on the display table must have PR_CONTROL_ID to uniquely identify the control to update.

See Also

DTCTL structure, PR_CONTROL_TYPE property


 PR_CONTROL_STRUCTURE

[New - Windows 95]

Contains a pointer to a specific type of dialog box control structure.

Details

Identifier 0x3F01; property type PT_BINARY; property tag 0x3F010102

Comments

This property represents a binary blob that is cast to one of the control structures. The control structures include DTBLBUTTON, DTBLDTBLCHECKBOX, DTBLCOMBOBOX, DTBLDDLBX, DTBLEDIT, DTBLGROUPBOX, DTBLLABEL, DTBLLBX, DTBLMVLBOX, DTMVLISTBOX, DTBLRADIOBUTTON, and DTPAGE.

See Also

DTCTL structure, PR_CONTROL_TYPE property


 PR_CONTROL_TYPE

[New - Windows 95]

Contains a value indicating a control type for a given dialog box.

Details

Identifier 0x3F02; property type PT_LONG; property tag 0x3F020003

Comments

The PR_CONTROL_TYPE property can have the following values:

Value	Description
DTCT_BUTTON	A dialog button control.
DTCT_CHECKBOX	A dialog check box.
DTCT_COMBOBOX	A dialog combo box.
DTCT_DDLBX	A dialog drop-down list box.
DTCT_EDIT	A dialog edit text box.
DTCT_GROUPBOX	A dialog group box.
DTCT_LABEL	A dialog label.
DTCT_LBX	A dialog list box.
DTCT_LISTBOX	A dialog list box.
DTCT_MVDDLBX	A multivalued list box populated by a multivalued property of type string.
DTCT_PAGE	A dialog tabbed page.
DTCT_RADIOBUTTON	A dialog radio button.
See Also

DTCTL structure


 PR_CONVERSATION_INDEX

[New - Windows 95]

Contains an index that indicates the relative position of this message within a conversation thread.

Details

Identifier 0x0071; property type PT_BINARY; property tag 0x00710102

Comments

The conversation index is usually implemented using concatenated time stamp values. A message that represents a reply to another message concatenates a time stamp to the PR_CONVERSATION_INDEX value of the original message. For all messages that have the same value for PR_CONVERSATION_TOPIC, you can then sort by PR_CONVERSATION_INDEX to indicate the hierarchical relationship of the messages.

PR_CONVERSATION_INDEX and PR_CONVERSATION_TOPIC replace the obsolete property PR_CONVERSATION_KEY.

See Also

PR_CONVERSATION_TOPIC property


 PR_CONVERSATION_KEY

[New - Windows 95]

Obsolete. Replaced by the properties PR_CONVERSATION_TOPIC and PR_CONVERSATION_INDEX.

Details

Identifier 0x000B; property type PT_BINARY; property tag 0x000B0102

Comments

This property was part of the original design for organizing conversations. It has been replaced by PR_CONVERSATION_TOPIC and PR_CONVERSATION_INDEX.

See Also

PR_CONVERSATION_INDEX property, PR_CONVERSATION_TOPIC property


 PR_CONVERSATION_TOPIC

[New - Windows 95]

Represents the topic of the first message in a conversation thread. Used with PR_CONVERSATION_INDEX.

Details

Identifier 0x0070; property type PT_TSTRING; property tag 0x0070001E

Comments

A conversation thread represents a series of messages and replies. The PR_CONVERSATION_TOPIC is set for the first message in a thread, usually to the same value as the message subject, with any "RE:" and "FW:" strings removed. Subsequent message in the conversation thread use the same PR_CONVERSATION_TOPIC. The property PR_CONVERSATION_INDEX indicates the relationship between subsequent messages and replies.

PR_CONVERSATION_INDEX and PR_CONVERSATION_TOPIC replace the obsolete property PR_CONVERSATION_KEY.

See Also

PR_CONVERSATION_INDEX property


 PR_CONVERSION_EITS

[New - Windows 95]

Contains the encoded information types (EITs) that are applied to a message in transit to describe conversions.

Details

Identifier 0x000C; property type PT_BINARY; property tag 0x000C0102

Comments

This MAPI property corresponds to the interpersonal notification IM_CONVERSION_EITS attribute as defined by the X.400 message-handling standard.

X.400 environments use the PR_CONVERSION_EITS property for both nondelivery reports and delivery reports.

See Also

PR_CONVERSION_PROHIBITED property


 PR_CONVERSION_PROHIBITED

[New - Windows 95]

Contains TRUE if message conversions are prohibited by default for the associated messaging user, and FALSE otherwise.

Details

Identifier 0x3A03; property type PT_BOOLEAN; property tag 0x3A03000B

Comments

For X.400 environments, PR_CONVERSION_PROHIBITED corresponds to the MH_T_CONVERSION_PROHIBITED attribute as defined by the X.400 message-handling standard.

See Also

PR_CONVERSION_WITH_LOSS_PROHIBITED property


 PR_CONVERSION_WITH_LOSS_PROHIBITED

[New - Windows 95]

Contains TRUE if a message transfer agent (MTA) is prohibited from making message text (body) conversions that lose information, such as "lossy" character set mapping. Contains FALSE otherwise.

Details

Identifier 0x000D; property type PT_BOOLEAN; property tag 0x000D000B

Comments

For X.400 environments, PR_CONVERSION_WITH_LOSS_PROHIBITED corresponds to the MH_T_CONVERSION_LOSS_PROHIBITED attribute.

X.400 and EDI transport providers use this property for messages delivered to client applications. X.400 probe messages also use this property.

See Also

PR_CONVERSION_PROHIBITED property


 PR_CONVERTED_EITS

[New - Windows 95]

Contains an identifier for the types of text (body) parts in a message after conversion.

Details

Identifier 0x000E; property type PT_BINARY; property tag 0x000E0102

Comments

For X.400 environments, PR_CONVERTED_EITS corresponds to the MH_T_CONVERTED_EITS attribute.

X.400 and EDI transport providers use this property for messages delivered to client applications.

See Also

PR_CONVERSION_EITS property


 PR_CORRELATE

[New - Windows 95]

Contains TRUE if the messaging system correlates sent messages with reports, and FALSE otherwise.

Details

Identifier 0x0E0C; property type PT_BOOLEAN; property tag 0x0E0C000B

Comments

The information in the property is provided by the message tracking and report generation facilities of the messaging system.

When your transport provider encounters a submitted message with PR_CORRELATE set to TRUE, it uses the PR_CORRELATE_MTSID property to store the message transport system (MTS) identifier for the message.

See Also

PR_CORRELATE_MTSID property


 PR_CORRELATE_MTSID

[New - Windows 95]

Contains the message transport system (MTS) identifier used with the PR_CORRELATE property in correlating messages with reports.

Details

Identifier 0x0E0D; property type PT_BINARY; property tag 0x0E0D0102

Comments

When your transport provider encounters a submitted message with the PR_CORRELATE property set to TRUE, it uses PR_CORRELATE_MTSID to store the MTS identifier for the message. When information comes in from the message transfer agent (MTA) pertaining to the tracked message, the provider updates PR_CORRELATE_MTSID with the referenced MTS identifier and adds the property to the new report or notification.

Your client application can maintain a search-results folder of all messages having a PR_CORRELATE_MTSID property. When new information comes in about a tracked message, the application can apply restrictions to the search-results folder, find the original version of the tracked message, and correlate the original message information with the new information.

See Also

PR_CORRELATE property


 PR_COUNTRY

[New - Windows 95]

Contains the country of the messaging user.

Details

Identifier 0x3A26; property type PT_TSTRING; property tag 0x3A26001E

Comments

Other messaging user properties include the fax number, primary, and secondary business phone number.

See Also

PR_BUSINESS_TELEPHONE_NUMBER property


 PR_CREATE_TEMPLATES

[New - Windows 95]

Contains an embedded table object that contains dialog box templates.

Details

Identifier 0x3604; property type PT_OBJECT; property tag 0x3604000D

Comments

To learn what you can create inside a container, call IMAPIProp::OpenProperty on PR_CREATE_TEMPLATES. The resulting object is the template ID table that lists the objects you can create inside a container.

To subsequently create the objects, call the container object's CreateEntry method. To create the template table using an IMAPITable interface, your client application passes PR_CREATE_TEMPLATES to the IMAPIProp::OpenProperty method for the address book container or folder.

See Also

IABContainer::CreateEntry method, PR_DEF_CREATE_DL property, PR_DISPLAY_NAME property, PR_DISPLAY_TYPE property


 PR_CREATION_TIME

[New - Windows 95]

Contains the creation time for the object.

Details

Identifier 0x3007; property type PT_SYSTIME; property tag 0x30070040

Comments

A message store sets this property for each message that it creates.

See Also

PR_CREATION_VERSION property


 PR_CREATION_VERSION

[New - Windows 95]

Contains the version number of the message store that was current at the time a given message was created.

Details

Identifier 0x0E19; property type PT_I8; property tag 0x0E190014

Comments

This version number is a copy of the message store version number contained in the  PR_CURRENT_VERSION property.

Your application or service provider uses PR_CREATION_VERSION to support synchronization between message stores.

This property is being evaluated to determine whether it will be supported in future versions of MAPI 1.0.

See Also

PR_CURRENT_VERSION property, PR_MODIFY_VERSION property


 PR_CURRENT_VERSION

[New - Windows 95]

Contains the current version number of a given message store.

Details

Identifier 0x0E00; property type PT_I8; property tag 0x0E000014

Comments

MAPI uses this property to support synchronization between message stores.

See Also

PR_CREATION_VERSION property, PR_MODIFY_VERSION property


 PR_DEF_CREATE_DL

[New - Windows 95]

Contains the entry identifier for the template for a default distribution list object. Used by the client to create a distribution list within the container.

Details

Identifier 0x3611; property type PT_BINARY; property tag 0x36110102

Comments

Specifies the entry that can appear in the PR_CREATE_TEMPLATES property for distribution lists. After you obtain the entry, you use it in the call to CreateEntry. The entry represents the template for the default distribution list.

Your provider's container furnishes this property and furnishes the associated PR_CREATE_TEMPLATES property to the address book container.

See Also

IABLogon::CompareEntryIDs method, PR_CREATE_TEMPLATES property, PR_DEF_CREATE_MAILUSER property


 PR_DEF_CREATE_MAILUSER

[New - Windows 95]

Contains the entry identifier for the template for a default mail user object. Used by the client to create a mail user within the container.

Details

Identifier 0x3612; property type PT_BINARY; property tag 0x36120102

Comments

Specifies the entry that can appear in the PR_CREATE_TEMPLATES property for mail users. After obtaining the entry, the client uses it in the call to CreateEntry. The entry represents the template for the default mail user.

Your provider's container furnishes this property and the associated PR_CREATE_TEMPLATES property to the address book container.

See Also

IABLogon::CompareEntryIDs method, PR_CREATE_TEMPLATES property, PR_DEF_CREATE_DL property


 PR_DEFAULT_PROFILE

[New - Windows 95]

Contains TRUE if a messaging user profile is the MAPI default profile, and FALSE otherwise.

Details

Identifier 0x3D04; property type PT_BOOLEAN; property tag 0x3D04000B

Comments

This property does not appear as a property of any object; it appears as a column in a profiles table.

See Also

PR_DEFAULT_STORE property


 PR_DEFAULT_STORE

[New - Windows 95]

Contains TRUE if a message store is the default message store in the message store table, and FALSE otherwise.

Details

Identifier 0x3400; property type PT_BOOLEAN; property tag 0x3400000B

Comments

This property appears as a column in the message stores table. The value is based on PR_RESOURCE_FLAGS.

See Also

PR_RESOURCE_FLAGS property


 PR_DEFAULT_VIEW_ENTRYID

[New - Windows 95]

Contains the entryid for the default folder view that should be set as the initial view.

Details

Identifier 0x3616; property type PT_BINARY; property tag 0x36160102

Comments

PR_DEFAULT_VIEW_ENTRYID is the entry identifier of the folder view that should be set as the initial view. The property is not set when the "Normal" view is to be used as the initial view.

Because the client obtains this property at the time it opens the folder, the client can achieve significant performance gains. The PR_DEFAULT_VIEW_ENTRYID property can be used as a shortcut to obtain the default view, instead of opening the associated contents table and submitting a restriction.

A provider implementation of IMAPIFolder::CopyFolder can choose to copy this property when it copies folders.

See Also

IMAPIFolder::CopyFolder method, PR_COMMON_VIEWS_ENTRYID property, PR_VIEWS_ENTRYID property


 PR_DEFERRED_DELIVERY_TIME

[New - Windows 95]

Contains the time at which a message sender wants a message delivered.

Details

Identifier 0x000F; property type PT_SYSTIME; property tag 0x000F0040

Comments

For X.400 environments, PR_DEFERRED_DELIVERY_TIME corresponds to the MH_T_DEFERRED_DELIVERY_TIME attribute as defined by the X.400 message-handling standard.

Note that MAPI does not perform the deferred delivery; it is an option of the underlying messaging system to handle deferred delivery.

See Also

PR_MESSAGE_DELIVERY_TIME property


 PR_DELETE_AFTER_SUBMIT

[New - Windows 95]

Contains TRUE if a client application wants MAPI to delete the associated message after submission, and FALSE otherwise.

Details

Identifier 0x0E01; property type PT_BOOLEAN; property tag 0x0E01000B

Comments

The application uses this property with the PR_SENTMAIL_ENTRYID property to control what happens to a message after it is submitted. Either one or the other should be set, but not both.

The IPC message is created in the receive folder for the message class.

See Also

PR_SENTMAIL_ENTRYID property


 PR_DELIVER_TIME

[New - Windows 95]

Appears in reports; contains the time at which the original message was delivered.

Details

Identifier 0x0010; property type PT_SYSTIME; property tag 0x00100040

Comments

This MAPI property represents the corresponding delivered message and report per-recipient (delivery reports only) attributes as described in the X.400 message-handling standard. PR_DELIVER_TIME is a per recipient property on the report that indicates the time the original message was delivered to that user/recipient.

See Also

IMAPISupport::StatusRecips method


 PR_DELTAX

[New - Windows 95]

Contains the width of a control in standard Windows dialog units.

Details

Identifier 0x3F03; property type PT_LONG; property tag 0x3F030003

Comments

The PR_XPOS, PR_YPOS, PR_DELTAX, and PR_DELTAY properties position and size the control.

See Also

PR_CONTROL_TYPE property, PR_DELTAY property, PR_XPOS property, PR_YPOS property


 PR_DELTAY

[New - Windows 95]

Contains the height of a control in standard Windows dialog units.

Details

Identifier 0x3F04; property type PT_LONG; property tag 0x3F040003

Comments

The PR_XPOS, PR_YPOS, PR_DELTAX, and PR_DELTAY properties position and size the control.

See Also

PR_DELTAX property, PR_XPOS property, PR_YPOS property


 PR_DEPARTMENT_NAME

[New - Windows 95]

Contains a name for the department in which a messaging user works.

Details

Identifier 0x3A18; property type PT_TSTRING; property tag 0x3A18001E

Comments

Several properties are provided for information about messaging users, including several telephone numbers and fields of the user's address.

See Also

PR_LOCATION property


 PR_DEPTH

[New - Windows 95]

Represents the relative level of indentation (depth) of an object in a hierarchy table. It also represents the categorization level of a row in a contents table. The depth is zero-based, where zero represents the leftmost category.

Details

Identifier 0x3005; property type PT_LONG; property tag 0x30050003

Comments

PR_DEPTH can also specify the categorization level of a row in a contents table or the hierarchy depth in a hierarchy table. In all cases, the property value represents a relative value rather than an absolute value. In the hierarchy table, for example, the depth value is relative to the container from which you retrieved the hierarchy table. The depth does not represent an absolute depth from the root container.

See Also

PR_OBJECT_TYPE property


 PR_DETAILS_TABLE

[New - Windows 95]

Contains an embedded display table object.

Details

Identifier 0x3605; property type PT_OBJECT; property tag 0x3605000D

Comments

Passing this property to the IMAPIProp::OpenProperty method for the object returns an IMAPITable interface that allows creation of the display table.

See Also

IAddrBook::RecipOptions method, IMAPISession::MessageOptions method, PR_CREATE_TEMPLATES property, PR_SEARCH property


 PR_DISC_VAL

[New - Windows 95]

Contains TRUE if a message has been delivered to a distribution list of recipients but cannot be delivered to an individual messaging user in the list. The property contains FALSE otherwise.

Details

Identifier 0x004A; property type PT_BOOLEAN; property tag 0x004A000B

Comments

Your application can also use PR_DISC_VAL in normal message submission to identify the recipients for which a particular transport driver has accepted messages.

See Also

PR_DL_EXPANSION_HISTORY property


 PR_DISCARD_REASON

[New - Windows 95]

Contains a reason why a message transfer agent (MTA) has discarded a given message.

Details

Identifier 0x0011; property type PT_LONG; property tag 0x00110003

Comments

This reason is used in a nondelivery report (NDR) for the message. This MAPI property corresponds to the interpersonal notification IM_DISCARD_REASON attribute as defined by the X.400 message-handling standard.

See Also

PR_NDR_REASON_CODE property


 PR_DISCLOSE_RECIPIENTS

[New - Windows 95]

Contains TRUE if disclosure of message recipients is allowed, and FALSE otherwise. Disclosure is the default for messages sent to messaging users.

Details

Identifier 0x3A04; property type PT_BOOLEAN; property tag 0x3A04000B

Comments

For X.400 environments, PR_DISCLOSE_RECIPIENTS corresponds to the MH_T_DISCLOSURE_ALLOWED attribute as defined by the X.400 message-handling standard.

See Also

PR_DISCLOSURE_OF_RECIPIENTS property


 PR_DISCLOSURE_OF_RECIPIENTS

[New - Windows 95]

Contains TRUE if disclosure of recipients is allowed, and FALSE otherwise.

Details

Identifier 0x0012; property type PT_BOOLEAN; property tag 0x0012000B

Comments

For X.400 environments, PR_DISCLOSURE_OF_RECIPIENTS corresponds to the MH_T_DISCLOSURE_ALLOWED attribute.

See Also

PR_DISCLOSE_RECIPIENTS property


 PR_DISCRETE_VALUES

[New - Windows 95]

Contains TRUE if the report applies only to discrete members of a group rather than all members of the group. The recipient table contains entries indicating the entry identifier and name values of the recipients that the report applies to.

Details

Identifier 0x0E0E; property type PT_BOOLEAN; property tag 0x0E0E000B

Comments

PR_DISCRETE_VALUES provides the mechanism for generating non-delivery reports for individuals within a group.

This property is not used in MAPI 1.0. This property is being evaluated to determine whether it will be supported in future releases.

For example, consider a message that is sent to a group and one of the users in the group generates a non-delivery report (NDR). The recipient table of the NDR includes the PR_DISCRETE_VALUES property set to TRUE. The value TRUE indicated that the report's values for PR_ORIGINAL_DISPLAY_NAME, PR_ORIGINAL_SEARCH_KEY and PR_ORIGINAL_ENTRYID are significant.

This property is not transmitted so does not exist on the recipient.

See Also

PR_ORIGINAL_SEARCH_KEY property


 PR_DISPLAY_BCC

[New - Windows 95]

Contains an ASCII list of the display names of any blind copy (BCC) message recipients, separated by semicolons (;).

Details

Identifier 0x0E02; property type PT_TSTRING; property tag 0x0E02001E

Comments

The message store computes PR_DISPLAY_BCC using the IMessage::ModifyRecipients method. The store also maintains the property so that it always reflects the last saved state of a message. The value is synchronized at the time of the call to IMAPIProp::SaveChanges.

Note that semicolons cannot be used within recipient names in MAPI messaging.

For X.400 environments, PR_DISPLAY_BCC corresponds to the IM_BLIND_COPY_RECIPIENTS attribute as defined by the X.400 message-handling standard.

See Also

IMessage::ModifyRecipients method, PR_DISPLAY_NAME property


 PR_DISPLAY_CC

[New - Windows 95]

Contains an ASCII list of the names of carbon copy (CC) message recipients, separated by semicolons (;).

Details

Identifier 0x0E03; property type PT_TSTRING; property tag 0x0E03001E

Comments

The message store computes PR_DISPLAY_CC using the IMessage::ModifyRecipients method. The store also maintains the property so that it always reflects the last saved state of a message.

Note that semicolons cannot be used within recipient names in MAPI messaging.

For X.400 environments, PR_DISPLAY_CC corresponds to the IM_COPY_RECIPIENTS attribute as defined by the X.400 message-handling standard.

See Also

IMessage::ModifyRecipients method, PR_DISPLAY_NAME property


 PR_DISPLAY_NAME

[New - Windows 95]

Contains the display name for a given MAPI object.

Details

Identifier 0x3001; property type PT_TSTRING; property tag 0x3001001E

Comments

A status object should furnish PR_DISPLAY_NAME. For this object, the property contains the name of the component that can be displayed by the user interface.

Folders require sibling subfolders to have unique display names. For example, if a folder contains two subfolders, the two subfolders cannot use the same value for their PR_DISPLAY_NAME properties. Note that this restriction does not apply to other containers, such as address books and distribution lists.

Note that semicolons cannot be used within recipient names in MAPI messaging. This is because some properties consist of a list of display names delimited by semicolons.

To distinguish providers of the same type, providers should set the value of PR_DISPLAY_NAME so that it contains both the provider type and configuration information. The additional information helps to distinguish between instances of the providers. Unconfigured providers should use a string that names the provider. Configured providers should have use the same string followed by a distinguishing string in parenthesis. For example, the unconfigured provider sets PR_DISPLAY_NAME to the string, "Personal Information Store", while the configured provider sets PR_DISPLAY_NAME to the string, "Personal Information Store (July '95)".

For recipients in X.400 environments, PR_DISPLAY_NAME corresponds to the IM_FREE_FORM_NAME attribute as defined by the X.400 message-handling standard.

See Also

PR_DISPLAY_BCC property, PR_EMAIL_ADDRESS property, PR_TRANSMITTABLE_DISPLAY_NAME property


 PR_DISPLAY_TO

[New - Windows 95]

Contains an ASCII list of the names of the primary message (To line) recipients, separated by semicolons (;).

Details

Identifier 0x0E04; property type PT_TSTRING; property tag 0x0E04001E

Comments

The message store computes PR_DISPLAY_TO using the IMessage::ModifyRecipients method. The store also maintains the property so that it always reflects the last saved state of a message.

Note that semicolons cannot be used within recipient names in MAPI messaging.

For X.400 environments, PR_DISPLAY_TO corresponds to the IM_PRIMARY_RECIPIENTS attribute as defined by the X.400 message-handling standard.

See Also

PR_DISPLAY_TYPE property


 PR_DISPLAY_TYPE

[New - Windows 95]

Contains a value used to associate an icon with that particular row of the table.

Details

Identifier 0x3900; property type PT_LONG; property tag 0x39000003

Comments

Contains a long integer that is used to associate an icon (or other display elements) with that row of the table.

This property is used on address book and hierarchy table rows.It is not extensible in MAPI 1.0.

Hierarchy table settings include DT_FOLDER and DT_FOLDER_LINK. Address book hierarchy tables and template tables include DT_MODIFIABLE, DT_GLOBAL, DT_LOCAL, and DT_WAN. Address book tables and template tables use the other values listed below.

The PR_DISPLAY_TYPE property can have the following values:

Value	Description
DT_MAILUSER	A typical messaging user.
DT_AGENT	An automated agent, such as Quote-Of-The-Day or a weather chart display.
DT_DISTLIST	A distribution list.
DT_FOLDER	A folder hierarchy table. Display default folder icon adjacent to folder.
DT_FOLDER_LINK	A folder hierarchy table. Display default folder link icon adjacent to folder rather than the default folder icon.
DT_FORUM	A forum, such as a bulletin board service or a public or shared folder.
DT_GLOBAL	A global address book.
DT_LOCAL	A local address book that you share with a small workgroup..
DT_MODIFIABLE	Modifiable; the container should be denoted as modifiable in the UI.
DT_NOTSPECIFIC	Does not match any of the other settings.
DT_ORGANIZATION	A special alias defined for a large group, such as helpdesk, accounting, or blood-drive-coordinator.
DT_PRIVATE_DISTLIST	A private, personally administered distribution list.
DT_REMOTE_MAILUSER	A recipient known to be from a foreign or remote messaging system.
DT_WAN	A wide area network address book.
See Also

PR_DISPLAY_TO property


 PR_DL_EXPANSION_HISTORY

[New - Windows 95]

Contains a history showing how a distribution list has been expanded during message transmission.

Details

Identifier 0x0013; property type PT_BINARY; property tag 0x00130102

Comments

For X.400 environments, PR_DL_EXPANSION_HISTORY corresponds to the MH_T_EXPANSION_HISTORY attribute. X.400 and EDI transport providers use this property for messages delivered to client applications. X.400 probe messages also use this property.

See Also

PR_DL_EXPANSION_PROHIBITED property


 PR_DL_EXPANSION_PROHIBITED

[New - Windows 95]

Contains TRUE if a message transfer agent (MTA) is prohibited from expanding distribution lists.

Details

Identifier 0x0014; property type PT_BOOLEAN; property tag 0x0014000B

Comments

For X.400 environments, PR_DL_EXPANSION_PROHIBITED corresponds to the MH_T_EXPANSION_PROHIBITED attribute as defined by the X.400 message-handling standard.

See Also

PR_DL_EXPANSION_HISTORY property


 PR_EMAIL_ADDRESS

[New - Windows 95]

Contains a null-terminated string that specifies the e-mail address of the message recipient in the format required by the messaging system.

Details

Identifier 0x3003; property type PT_TSTRING; property tag 0x3003001E

Comments

PR_EMAIL_ADDRESS is a null-terminated string whose format has meaning only for the underlying messaging service.

Mail user objects must furnish PR_EMAIL_ADDRESS. This property is optional for distribution list objects.

PR_EMAIL_ADDRESS is used in conjunction with PR_ADDRTYPE and PR_MESSAGE_CLASS in addressing messages. The string format is qualified by the PR_ADDRTYPE property.

Valid PR_EMAIL_ADDRESS examples include:

network/postoffice/user

Bruce@XYZZY.COM

/c=US/a=att/p=Microsoft/o=Finance/ou=Purchasing/s=Furthur/g=Joe

See Also

PR_ADDRTYPE property, PR_MESSAGE_CLASS property, PR_SEARCH_KEY property


 PR_END_DATE

[New - Windows 95]

Contains the ending time of an appointment as managed by a scheduling application.

Details

Identifier 0x0061; property type PT_SYSTIME; property tag 0x00610040

Comments

Several MAPI properties treat appointments: PR_START_DATE, PR_END_DATE, and PR_OWNER_APPT_ID.

See Also

PR_OWNER_APPT_ID property, PR_START_DATE property


 PR_ENTRYID

[New - Windows 95]

Contains a MAPI entry identifier used to open and edit properties of a particular MAPI object.

Details

Identifier 0x0FFF; property type PT_BINARY; property tag 0x0FFF0102

Comments

Mail user, message, distribution list, address book container, folder, and message store objects must furnish PR_ENTRYID. It is an optional property for the status object.

This property can contain either a long-term or a short-term ID. To convert from a short term entry id to a long term entry id, call the object's GetProps method and retrieve PR_ENTRYID.

See Also

ENTRYID structure, NOTIFICATION structure, PR_STORE_ENTRYID property


 PR_EXPIRY_TIME

[New - Windows 95]

Contains the date and time at which the messaging system can invalidate the content of the associated message.

Details

Identifier 0x0015; property type PT_SYSTIME; property tag 0x00150040

Comments

The property is used to direct the messaging system in handling delivered interpersonal messages. For X.400 environments, this MAPI property corresponds to the delivery envelope per-message IM_EXPIRY_TIME attribute as defined by the X.400 message-handling standard.

Transport providers use PR_EXPIRY_TIME for messages delivered to client applications.

See Also

PR_PROVIDER_SUBMIT_TIME property


 PR_EXPLICIT_CONVERSION

[New - Windows 95]

Contains an indication that a message sender specifically requests a message content conversion for a particular recipient.

Details

Identifier 0x0C01; property type PT_LONG; property tag 0x0C010003

Comments

This property represents the X.400 probe submission MH_T_EXPLICIT_CONVERSION attribute as defined in the X.400 message-handling standard.

It also represents the corresponding EDI submission envelope per-recipient attribute as defined by the EDI message-handling standard.

See Also

PR_GENERATION property


 PR_FILTERING_HOOKS

[New - Windows 95]

Not supported in MAPI version 1.0.

Details

Identifier 0x3D08; property type PT_BINARY; property tag 0x3D080102

Comments

This property, which was present in pre-release versions, is not supported in the MAPI 1.0 SDK.


 PR_FINDER_ENTRYID

[New - Windows 95]

Contains the entry identifier for the folder in which search results are typically created.

Details

Identifier 0x35E7; property type PT_BINARY; property tag 0x35E70102

Comments

The entryid has the same format as the MAPI 1.0 ENTRYID structure.

See Also

PR_ENTRYID property


 PR_FOLDER_ASSOCIATED_CONTENTS

[New - Windows 95]

Contains the associated contents table object. This object represents a subfolder that does not appear in the hierarchy.

Details

Identifier 0x3610; property type PT_OBJECT; property tag 0x3610000D

Comments

The associated contents table enumerates associated (hidden) messages in a folder.

Your application can use the PR_FOLDER_ASSOCIATED_CONTENTS property to exclude an item from a copy operation.

Several MAPI properties provide access to tables:

Property	Table
PR_CONTAINER_HIERARCHY	Hierarchy table
PR_FOLDER_ASSOCIATED_CONTENTS	Associated contents table
PR_MESSAGE_ATTACHMENTS	Attachments table
PR_MESSAGE_RECIPIENTS	Recipients table
See Also

PR_ASSOC_CONTENT_COUNT property, PR_CONTAINER_HIERARCHY property


 PR_FOLDER_TYPE

[New - Windows 95]

Contains a constant that indicates the folder type. All folders must furnish this property.

Details

Identifier 0x3601; property type PT_LONG; property tag 0x36010003

Comments

The PR_FOLDER_TYPE property can have the following values:

Value	Description
FOLDER_GENERIC	A normal folder that contains messages and other folders.
FOLDER_ROOT	The root folder of the folder hierarchy table (that is, a folder that has no parent folder). This folder contains messages and other folders. MAPI allows only one root folder per message store. Note that PR_PARENT_ENTRYID does not exist on the root folder.
FOLDER_SEARCH	A search-results folder containing the results of a search, in the form of links to messages that meet search criteria. The information in a search-results folder is mainly stored in its contents table, which contains the same columns as a normal contents table, as well as two extra columns: PR_PARENT_DISPLAY (display name of the folder of the parent) and PR_PARENT_ENTRYID (the parent folder entryid of that message). PR_PARENT_DISPLAY is the display name of the parent of the folder, and is a required column in the search results folder contents table.
See Also

PR_PARENT_ENTRYID property


 PR_FORM_CATEGORY

[New - Windows 95]

Contains the category of a form.

Details

Identifier 0x3309; property type PT_TSTRING; property tag 0x3309001E

Comments

The category name is defined by a client application in a way that is appropriate to the application.

See Also

PR_FORM_CATEGORY_SUB property


 PR_FORM_CATEGORY_SUB

[New - Windows 95]

Contains the subcategory of a form, as defined by a client application.

Details

Identifier 0x3310; property type PT_TSTRING; property tag 0x3310001E

Comments

The PR_FORM_CATEGORY_SUB category is subordinate to the main form category provided in a PR_FORM_CATEGORY property.

See Also

PR_FORM_CATEGORY property


 PR_FORM_CLSID

[New - Windows 95]

Contains the 128-bit OLE globally unique identifier (GUID) of a form.

Details

Identifier 0x3307; property type PT_CLSID; property tag 0x33070048

Comments

The MAPIUID structure contains the definition for the UID.

See Also

MAPIUID structure


 PR_FORM_CONTACT_NAME

[New - Windows 95]

Contains the name of a contact for information concerning a form.

Details

Identifier 0x3308; property type PT_TSTRING; property tag 0x3308001E

Comments

The contact typically contains the name of a person or an alias that is responsible for the form.

See Also

PR_FORM_DESIGNER_NAME property


 PR_FORM_DESIGNER_GUID

[New - Windows 95]

Contains the unique identifier for the object used to design the form.

Details

Identifier 0x3314; property type PT_CLSID; property tag 0x33140048

Comments

Usually contains the GUID of the design program used to create the form. The property may be empty.

The MAPIUID structure contains the definition of the UID.

See Also

PR_FORM_DESIGNER_NAME property


 PR_FORM_DESIGNER_NAME

[New - Windows 95]

Contains the display name for the object used to design the form.

Details

Identifier 0x3313; property type PT_TSTRING; property tag 0x3313001E

Comments

The property PR_FORM_DESIGNER_GUID contains the unique identifier for the form designer object.

See Also

PR_FORM_DESIGNER_GUID property


 PR_FORM_HIDDEN

[New - Windows 95]

Specifies whether the form is to be displayed by compose menus and dialogs.

Details

Identifier 0x3312; property type PT_BOOLEAN; property tag 0x3312000B

Comments

Form-related properties are read-only.

See Also

PR_FORM_CATEGORY property


 PR_FORM_HOST_MAP

[New - Windows 95]

Contains a host map of available forms.

Details

Identifier 0x3311; property type PT_LONG; property tag 0x33110003

Comments

An application should update this property, along with the PR_DISPLAY_NAME property, when changing the underlying structure in the IMAPIFormProp interface.

See Also

PR_DISPLAY_NAME property


 PR_FORM_MESSAGE_BEHAVIOR

[New - Windows 95]

Indicates where the message should be composed.

Details

Identifier 0x3315; property type PT_BOOLEAN; property tag 0x3315000B

Comments

A value of TRUE indicates that the form should be composed in the current folder. A value of FALSE indicates that the message should be composed as any other IPM message.

See Also

PR_FORM_CATEGORY property


 PR_FORM_VERSION

[New - Windows 95]

Contains the version number of the message store that was current at the time the specified form was created.

Details

Identifier 0x3306; property type PT_TSTRING; property tag 0x3306001E

Comments

The form version number is a copy of the message store version number contained in the  PR_CURRENT_VERSION property.

See Also

PR_CURRENT_VERSION property


 PR_GENERATION

[New - Windows 95]

Contains a generational abbreviation (for example, Jr., Sr., III) that follows the full name of the messaging user.

Details

Identifier 0x3A05; property type PT_TSTRING; property tag 0x3A05001E

Comments

For X.400 environments, PR_GENERATION corresponds to the MH_T_GENERATION attribute as defined by the X.400 message-handling standard.

Several properties are available for the messaging user, including several telephone numbers and fields of the user's home address.

See Also

PR_GIVEN_NAME property


 PR_GIVEN_NAME

[New - Windows 95]

Contains the first name of a messaging user.

Details

Identifier 0x3A06; property type PT_TSTRING; property tag 0x3A06001E

Comments

For X.400 environments, PR_GIVEN_NAME corresponds to the MH_T_GIVEN_NAME attribute as defined by the X.400 message-handling standard.

See Also

PR_SURNAME property


 PR_GOVERNMENT_ID_NUMBER

[New - Windows 95]

Contains a government identifier, such as a Social Security number, for a messaging user.

Details

Identifier 0x3A07; property type PT_TSTRING; property tag 0x3A07001E

Comments

Several properties are provided for the messaging user, including telephone numbers and fields of the user's home address.

See Also

PR_ORGANIZATIONAL_ID_NUMBER property


 PR_HASATTACH

[New - Windows 95]

Contains TRUE if a given message contains at least one attachment and FALSE otherwise.

Details

Identifier 0x0E1B; property type PT_BOOLEAN; property tag 0x0E1B000B

Comments

The message store computes the PR_HASATTACH property from the PR_MESSAGE_FLAGS property. Your application can then use PR_HASATTACH to sort on message attachments in a message viewer.

The value of PR_HASATTACH is updated with SaveChanges.

See Also

PR_MESSAGE_FLAGS property


 PR_HEADER_FOLDER_ENTRYID

[New - Windows 95]

Contains the entry identifier that the service provider furnishes for a folder.

Details

Identifier 0x3E0A; property type PT_BINARY; property tag 0x3E0A0102

Comments

This property is specific to remote transports that support remote operations using a folder. The property appears in the status object or in the status table row.

When you call the OpenEntry method for this entryid, you obtain a folder from which you can obtain a contents table. The client application can use this identifier to view the headers of the messages in the folder.

Another way to obtain the contents table is to open the status object and query for the folder object interface. This property was designed for a transport tightly-coupled to a store; the transport could publish the store's folder entryid in this property.

See Also

PR_ENTRYID property


 PR_HOME_FAX_NUMBER

[New - Windows 95]

Contains the phone number for the messaging user's home fax machine.

Details

Identifier 0x3A25; property type PT_TSTRING; property tag 0x3A25001E

Comments

Several properties are available for information about the messaging user, including various phone numbers.

See Also

PR_HOME_TELEPHONE_NUMBER property


 PR_HOME_TELEPHONE_NUMBER

[New - Windows 95]

Contains the home telephone number of a messaging user.

Details

Identifier 0x3A09; property type PT_TSTRING; property tag 0x3A09001E

Comments

Several properties are available for information about the messaging user, including various phone numbers.

See Also

PR_HOME_FAX_NUMBER property, PR_HOME2_TELEPHONE_NUMBER property


 PR_HOME2_TELEPHONE_NUMBER

[New - Windows 95]

Contains a second home telephone number of a messaging user.

Details

Identifier 0x3A2F; property type PT_TSTRING; property tag 0x3A2F001E

Comments

Should contain information only if PR_HOME_TELEPHONE_NUMBER also contains information.

See Also

PR_HOME_TELEPHONE_NUMBER property


 PR_ICON

[New - Windows 95]

Contains a 32 by 32 icon that is used on forms.

Details

Identifier 0x0FFD; property type PT_BINARY; property tag 0x0FFD0102

Comments

The value is the same as the contents of a .ICO file, that is, a bitmap.

See Also

PR_MINI_ICON property


 PR_IDENTITY_DISPLAY

[New - Windows 95]

Contains the display name that corresponds to a messaging user's unique identifier (UID).

Details

Identifier 0x3E00; property type PT_TSTRING; property tag 0x3E00001E

Comments

The PR_IDENTITY_* properties define the user's identity as that provider defines it. These optional properties typically refer to the user's account on the server, but can refer to any representation for that user in the messaging system, as defined by the provider.

This property represents one of three maintained for the user. Opening the entryid to find additional information is a relatively expensive operation, so properties representing the commonly-used display name and search key are defined along with the entryid.

Providers that belong to the same messaging service should expose the same values for the PR_IDENTITY_* properties.

See Also

IMAPISession::QueryIdentity method, PR_IDENTITY_ENTRYID property, PR_IDENTITY_SEARCH_KEY property


 PR_IDENTITY_ENTRYID

[New - Windows 95]

Contains the entry identifier for the user as that provider defines it.

Details

Identifier 0x3E01; property type PT_BINARY; property tag 0x3E010102

Comments

The PR_IDENTITY_* properties define the user's identity as that provider defines it. These optional properties typically refer to the user's account on the server, but can refer to any representation for that user in the messaging system, as defined by the provider.

This property represents one of three maintained for the user. Opening the entryid to find additional information is a relatively expensive operation, so properties representing the commonly-used display name and search key are defined along with the entryid.

Providers that belong to the same messaging service should expose the same values for the PR_IDENTITY_* properties.

See Also

IMAPISession::QueryIdentity method, PR_IDENTITY_DISPLAY property, PR_IDENTITY_SEARCH_KEY property


 PR_IDENTITY_SEARCH_KEY

[New - Windows 95]

Contains the search key for the user.

Details

Identifier 0x3E05; property type PT_BINARY; property tag 0x3E050102

Comments

The PR_IDENTITY_* properties define the user's identity as that provider defines it. These optional properties typically refer to the user's account on the server, but can refer to any representation for that user in the messaging system, as defined by the provider.

This property represents one of three maintained for the user. Opening the entryid to find additional information is a relatively expensive operation, so properties representing the commonly-used display name and search key are defined along with the entryid.

Providers that belong to the same messaging service should expose the same values for the PR_IDENTITY_* properties.

See Also

IMAPISession::QueryIdentity method, PR_IDENTITY_DISPLAY property, PR_IDENTITY_ENTRYID property


 PR_IMPLICIT_CONVERSION_PROHIBITED

[New - Windows 95]

Contains TRUE if a message transfer agent (MTA) is prohibited from implicitly converting message content.

Details

Identifier 0x0016; property type PT_BOOLEAN; property tag 0x0016000B

Comments

For X.400 environments, PR_IMPLICIT_CONVERSION_PROHIBITED corresponds to the MH_T_CONVERSION_PROHIBITED attribute.

X.400 and EDI transport providers use this property for messages delivered to client applications. X.400 probe messages also use this property.

See Also

PR_REPORTING_MTA_CERTIFICATE property


 PR_IMPORTANCE

[New - Windows 95]

Contains a value indicating the message sender's opinion of the importance of a message.

Details

Identifier 0x0017; property type PT_LONG; property tag 0x00170003

Comments

This MAPI property corresponds to the submission envelope per-message IM_IMPORTANCE attribute as defined by the X.400 message-handling standard. X.400 transport providers use this property for messages delivered to client applications.

PR_IMPORTANCE is distinguished from PR_PRIORITY. Importance indicates a value to users, while priority indicates the order or speed at which the message should be sent by the messaging system software. Higher priority usually indicates a higher cost. Higher importance usually is associated with different display by the user interface.

X.400 defines the following values for this property:

Value	Description
IMPORTANCE_LOW	The message has low importance.
IMPORTANCE_HIGH	The message has high importance.
IMPORTANCE_NORMAL	The message has normal importance.
See Also

PR_PRIORITY property


 PR_INCOMPLETE_COPY

[New - Windows 95]

Contains TRUE if a message is an incomplete copy of another message, and FALSE otherwise.

Details

Identifier 0x0035; property type PT_BOOLEAN; property tag 0x0035000B

Comments

This MAPI property corresponds to the IM_INCOMPLETE_COPY attribute as defined by the X.400 message-handling standard.


 PR_INITIAL_DETAILS_PANE

[New - Windows 95]

Indicates which property page in a property sheet to display first.

Details

Identifier 0x3F08; property type PT_LONG; property tag 0x3F080003

Comments

Contains the zero-based index of the initial foreground pane that appears when a client application displays a details table for an object that exposes property sheets. The value indicates which page to display first. This property appears in an object from which you can get back a dsiplay table.

See Also

IMAPISupport::DoConfigPropSheet method


 PR_INITIALS

[New - Windows 95]

Contains the initials for parts of the full name of a messaging user.

Details

Identifier 0x3A0A; property type PT_TSTRING; property tag 0x3A0A001E

Comments

For X.400 environments, PR_INITIALS corresponds to the MH_T_INITIALS attribute as defined by the X.400 message-handling standard.

Several properties are supplied for the messaging user, including several telephone numbers, and parts of the messaging user's address.

See Also

PR_OFFICE_TELEPHONE_NUMBER property


 PR_INSTANCE_KEY

[New - Windows 95]

Represents the unique value that represents a row in a table. These are used in contents and categorization tables, and are not used in display tables.

Details

Identifier 0x0FF6; property type PT_BINARY; property tag 0x0FF60102

Comments

When you explode multivalued properties in a table, you obtain different rows and different instance keys for the properties. Rows added to categorized tables that don't correspond to actual data also get their own unique instance key.

PR_INSTANCE_KEY is also used with notifications. The PR_INSTANCE_KEY property is used as the contents of the TABLE_NOTIFICATION fields propIndex and propPrior. The propIndex field indicates the value of the index property for the row that changed. The propPrior field indicates the value of the index for the row before the changed row (PR_NULL indicates a change to the first row).

This value is not copied as part of the display table.

All instance keys can be compared as binary values.

See Also

TABLE_NOTIFICATION structure


 PR_IPM_ID

[New - Windows 95]

Contains an interpersonal messaging (IPM) identifier that transport providers use for messages delivered to client applications.

Details

Identifier 0x0018; property type PT_BINARY; property tag 0x00180102

Comments

This MAPI property corresponds to the IM_THIS_IPM attribute as defined by the X.400 message-handling standard.

This property is similar to the ENTRYID used by MAPI.

See Also

ENTRYID structure


 PR_IPM_OUTBOX_ENTRYID

[New - Windows 95]

Contains the entry identifier of an interpersonal messaging (IPM) folder in which outbound messages are usually created.

Details

Identifier 0x35E2; property type PT_BINARY; property tag 0x35E20102

Comments

The Outbox folder is the folder in which outbound messages are usually created.

See Also

PR_IPM_OUTBOX_SEARCH_KEY property


 PR_IPM_OUTBOX_SEARCH_KEY

[New - Windows 95]

This property is not supported in MAPI 1.0.

Details

Identifier 0x3411; property type PT_BINARY; property tag 0x34110102

Comments

Although present in pre-release versions, this property is not supported in MAPI 1.0.

In previous releases, this property contained the search key for an interpersonal messaging (IPM) outbound messages (outbox) folder.

See Also

PR_IPM_OUTBOX_ENTRYID property


 PR_IPM_RETURN_REQUESTED

[New - Windows 95]

Contains TRUE if a message should be returned with a report, and FALSE otherwise.

Details

Identifier 0x0C02; property type PT_BOOLEAN; property tag 0x0C02000B

Comments

This MAPI property corresponds to the submission envelope per-recipient IM_IPM_RETURN_REQUESTED attribute as defined by the X.400 message-handling standard.

See Also

PR_IPM_SENTMAIL_ENTRYID property


 PR_IPM_SENTMAIL_ENTRYID

[New - Windows 95]

Contains the entry identifier of an interpersonal messaging (IPM) folder into which the client places sent mail.

Details

Identifier 0x35E4; property type PT_BINARY; property tag 0x35E40102

Comments

The Sent Mail folder is the folder in which sent messages are usually placed.

The client can use this property to set the PR_SENTMAIL_ENTRYID property of a message.

See Also

PR_IPM_SENTMAIL_SEARCH_KEY property, PR_SENTMAIL_ENTRYID property


 PR_IPM_SENTMAIL_SEARCH_KEY

[New - Windows 95]

This property is not supported in MAPI 1.0.

Details

Identifier 0x3413; property type PT_BINARY; property tag 0x34130102

Comments

Although present in pre-release versions, this property is not supported in MAPI 1.0.

In previous releases, this message store object property contained the search key for an interpersonal messaging (IPM) sent-mail folder.

See Also

PR_IPM_SENTMAIL_ENTRYID property


 PR_IPM_SUBTREE_ENTRYID

[New - Windows 95]

Contains the entry identifier of the base of the interpersonal messaging (IPM) folder subtree in the message store's folder tree.

Details

Identifier 0x35E0; property type PT_BINARY; property tag 0x35E00102

Comments

This property represents the base of the IPM hierarchy. IPM clients should not display any folders that are not children of the folder represented by this property.

See Also

PR_IPM_SUBTREE_SEARCH_KEY property


 PR_IPM_SUBTREE_SEARCH_KEY

[New - Windows 95]

This property is not supported in MAPI 1.0.

Details

Identifier 0x3410; property type PT_BINARY; property tag 0x34100102

Comments

Although present in pre-release versions, this property is not supported in MAPI 1.0.

In previous releases, this message store object property contained the search key for the root folder of the interpersonal messaging (IPM) folder subtree in the message store's folder tree.

See Also

PR_IPM_SUBTREE_ENTRYID property


 PR_IPM_WASTEBASKET_ENTRYID

[New - Windows 95]

Contains the entry identifier of an interpersonal messaging (IPM) folder into which deleted messages are usually placed.

Details

Identifier 0x35E3; property type PT_BINARY; property tag 0x35E30102

Comments

A third-party application behaving like a MAPI mail client should move IPM messages to the deleted messages folder indicated by this property. If a message is already in this folder, or if the PR_IPM_WASTEBASKET_ENTRYID property is not supported, your application should delete the message.

See Also

PR_ENTRYID property


 PR_IPM_WASTEBASKET_SEARCH_KEY

[New - Windows 95]

This property is not supported in MAPI 1.0.

Details

Identifier 0x3412; property type PT_BINARY; property tag 0x34120102

Comments

Although present in pre-release versions, this property is not supported in MAPI 1.0.

In previous releases, this message store object property contained the search key for an interpersonal messaging (IPM) deleted messages (wastebasket) folder.

See Also

PR_IPM_WASTEBASKET_ENTRYID property


 PR_ISDN_NUMBER

[New - Windows 95]

Contains the messaging user's ISDN-capable telephone number.

Details

Identifier 0x3A2D; property type PT_STRING; property tag 0x3A2D001E

Comments

Several properties are available for the messaging user, including the office telephone number, fax number, and cellular telephone number.

See Also

PR_OFFICE_TELEPHONE_NUMBER property


 PR_KEYWORD

[New - Windows 95]

Contains a keyword for arbitrary use by the system administrator.

Details

Identifier 0x3A0B; property type PT_TSTRING; property tag 0x3A0B001E

Comments

The contents of the string property are defined based on the needs of the specific  site.

Several properties are available for the messaging user, including the office telephone number, fax number, and cellular telephone number.

See Also

PR_OFFICE_TELEPHONE_NUMBER property


 PR_LANGUAGE

[New - Windows 95]

Contains a value indicating the language in which the messaging user is writing messages.

Details

Identifier 0x3A0C; property type PT_TSTRING; property tag 0x3A0C001E

Comments

The string contains a single 2-character country code.

See Also

PR_LANGUAGES property


 PR_LANGUAGES

[New - Windows 95]

Contains an ASCII list of the languages incorporated in a message. The underlying string is a sequence of 2-character country codes delimited by commas.

Details

Identifier 0x002F; property type PT_TSTRING; property tag 0x002F001E

Comments

For X.400 environments, PR_LANGUAGES corresponds to the IM_LANGUAGES attribute as defined by the X.400 message-handling standard.

See Also

PR_LANGUAGE property


 PR_LAST_MODIFICATION_TIME

[New - Windows 95]

Contains the date and time the mail user object or distribution list object was last modified.

Details

Identifier 0x3008; property type PT_SYSTIME; property tag 0x30080040

Comments

PR_LAST_MODIFICATION_TIME is initially set to the same value as PR_CREATION_TIME. The client can set this property until the first call to SaveChanges.

See Also

PR_CREATION_TIME property


 PR_LATEST_DELIVERY_TIME

[New - Windows 95]

Contains the latest date and time when a message transfer agent (MTA) should deliver a message.

Details

Identifier 0x0019; property type PT_SYSTIME; property tag 0x00190040

Comments

For X.400 environments, PR_LATEST_DELIVERY_TIME corresponds to the MH_T_LATEST_DELIVERY_TIME attribute.

If an MTA cannot deliver a message by the time this property specifies, it cancels the message without delivery.

See Also

PR_DEFERRED_DELIVERY_TIME property


 PR_LOCALITY

[New - Windows 95]

Contains the name of the messaging user's locality, such as the town or city.

Details

Identifier 0x3A27; property type PT_TSTRING; property tag 0x3A27001E

Comments

Several properties are available for the messaging user, including the office telephone number.

See Also

PR_STREET_ADDRESS property


 PR_LOCATION

[New - Windows 95]

Contains the location of the messaging user in a format that is useful to your organization.

Details

Identifier 0x3A0D; property type PT_TSTRING; property tag 0x3A0D001E

Comments

The contents of the string are defined by your particular needs. For example, some users might identify messaging users by specifying the building number and office number.

See Also

PR_BUSINESS_TELEPHONE_NUMBER property


 PR_MAIL_PERMISSION

[New - Windows 95]

Contains TRUE if the messaging user has permissions for a message, and FALSE otherwise.

Details

Identifier 0x3A0E; property type PT_BOOLEAN; property tag 0x3A0E000B

Comments

Several properties are available for the messaging user, including several that represent telephone numbers and parts of the messaging user's address.

See Also

PR_OFFICE_TELEPHONE_NUMBER property


 PR_MAPPING_SIGNATURE

[New - Windows 95]

Contains the mapping signature for named properties of a particular MAPI object. Objects that have the same signature represent the same property.

Details

Identifier 0x0FF8; property type PT_BINARY; property tag 0x0FF80102

Comments

Your application should check the PR_MAPPING_SIGNATURE of both objects when copying named properties from one object to another. Use of this property allows the application to avoid translating between the copied property's name and its identifier.

When two objects have the same PR_MAPPING_SIGNATURE value, you don't have to translate name to identifier and identifier to name. You can simply call SetProps. This is convenient for applications that perform custom copying of named properties, and for providers implementing CopyTo and CopyProps.

See Also

IMAPIProp::SetProps method


 PR_MDB_PROVIDER

[New - Windows 95]

Contains a provider-defined identifier that indicates the type of the message store.

Details

Identifier 0x3414; property type PT_BINARY; property tag 0x34140102

Comments

The uid identifies the type of message store. The value is generated by, and is unique to, each provider. It is typically used for browsing through the message stores table to find a store of the desired type, such as public folders.

This property is analogous to the PR_AB_PROVIDER_ID property for address books.

Address book containers and hierarchy tables should provide this property. Your application can use it to find related rows in an address book hierarchy table.

See Also

PR_AB_PROVIDER_ID property


 PR_MESSAGE_ATTACHMENTS

[New - Windows 95]

Contains a table of restrictions that can be applied to the folder's contents table to find all messages that contain the attachments specified in the restrictions.

Details

Identifier 0x0E13; property type PT_OBJECT; property tag 0x0E13000D

Comments

You can restrict the contents table of the folder to find all messages where the attachment meets the conditions specified in the restriction. The restriction is true if one row remains in the table.

The restrictions are commonly used to exclude attachments from IMessage::CopyTo operations and to include attachments in IMessage::CopyProps operations.

This property can also be used in the IMessage (and IMAPIProp) methods GetPropList, GetProps, and OpenProperty.

Note that using restrictions results in an open operation on every message in the folder. Depending on your application and the number of messages to be searched, it can affect application performance.

PR_MESSAGE_RECIPIENTS is used for recipients as PR_MESSAGE_ATTACHMENTS is used for attachments.

Several MAPI properties provide access to table objects:

Property	Table
PR_CONTAINER_HIERARCHY	Hierarchy table
PR_FOLDER_ASSOCIATED_CONTENTS	Associated contents table
PR_MESSAGE_ATTACHMENTS	Attachments table
PR_MESSAGE_RECIPIENTS	Recipients table
See Also

IMAPIProp::CopyProps method, IMAPIProp::CopyTo method, PR_MESSAGE_RECIPIENTS property


 PR_MESSAGE_CC_ME

[New - Windows 95]

Set to TRUE if the messaging user was specifically named as a carbon copy (Cc) recipient and was not part of a group.

Details

Identifier 0x0058; property type PT_BOOLEAN; property tag 0x0058000B

Comments

PR_MESSAGE_CC_ME is a convenient way to determine whether the user name explicitly appears in the recipient list, without examining all entries in the list. This property also assists automated handling of received messages at the time of receipt. At the transport provider's option, this property either contains FALSE or is not included if the messaging user is not listed directly in the recipient table.

Message delivery resulting from distribution list expansion or a blind carbon copy designation for the message sender does not cause this property to be set.

Unsent messages generally do not include this property. If the property is present in messages the user can access in public message stores, in other users' private stores, in files on disk, or embedded inside other received messages, it generally contains the value to which it was set the last time the transport provider delivered it.

See Also

PR_MESSAGE_RECIP_ME property, PR_MESSAGE_TO_ME property


 PR_MESSAGE_CLASS

[New - Windows 95]

Contains a text string that identifies the sender-defined message class, such as "IPM.FAX". The message class specifies the type of the delivered message.

Details

Identifier 0x001A; property type PT_STRING8; property tag 0x001A001E

Comments

The message class describes the kind of message. It provides information about the set of properties defined for the message, such as the kind of information that the message conveys and how to handle the message.

Each message class can be considered to have its own name space. A range of property values (0x7C00 to 0x7FFF) is reserved for properties that are specific to the message-class. When you create a new message class, you can also specify the meaning of the properties in the reserved range. Within this range, properties for your message class are guaranteed not to collide with properties for other message classes.

To date, the message class has been used for three primary purposes.

1. Receive foldering. A column in the receive folders table of the receive store organizes all incoming mail with this message class prefix. This allows you to specify where to store the incoming messages.

2. Launching forms. All form-aware clients can choose the form associated with a message based on the value of the message class property.

3. Rules. The message class can be used to trigger processing rules.

Any application that creates a message must set the PR_MESSAGE_CLASS property. Message store providers should set its value using the prefix "IPM." For example, MAPI uses the message class, "IPM.Note." PR_MESSAGE_CLASS also appears in recipients of delivery reports (DRs) and non-delivery reports (NDRs).

The message class name must be case-insensitive and must consist of the ASCII characters 32 through 127.

For a report, the value of PR_MESSAGE_CLASS is based on the class of the subject message. The format of the message class for the report is REPORT.X.Y, where REPORT is the report name, X is the class of the subject message, and Y is DR for a delivery report, NDR for a nondelivery report, IPNRN for a read notification report, or IPNNRN for a nonread notification report.

See Also

IMAPIForm : IUnknown interface, IMsgStore::GetReceiveFolderTable method


 PR_MESSAGE_DELIVERY_ID

[New - Windows 95]

Contains a message transport system (MTS) identifier for a message delivered to a client application.

Details

Identifier 0x001B; property type PT_BINARY; property tag 0x001B0102

Comments

For X.400 environments, PR_MESSAGE_DELIVERY_ID corresponds to the MH_T_MTS_IDENTIFIER attribute.

See Also

PR_MESSAGE_SUBMISSION_ID property


 PR_MESSAGE_DELIVERY_TIME

[New - Windows 95]

Contains the date and time that the message was delivered at the server.

Details

Identifier 0x0E06; property type PT_SYSTIME; property tag 0x0E060040

Comments

This property describes delivery time at the server rather than the download time that the transport copied the message from the server to the local store.

For X.400 environments, PR_MESSAGE_DELIVERY_TIME corresponds to the MH_T_DELIVERY_TIME attribute as defined by the X.400 message-handling standard.

See Also

PR_MESSAGE_DOWNLOAD_TIME property


 PR_MESSAGE_DOWNLOAD_TIME

[New - Windows 95]

Contains the time a message was downloaded from a messaging server to a local message store.

Details

Identifier 0x0E18; property type PT_LONG; property tag 0x0E180003

Comments

This property describes the download time that the transport copied the message from the server to the local store rather than the delivery time at the server.

See Also

PR_MESSAGE_DELIVERY_TIME property


 PR_MESSAGE_FLAGS

[New - Windows 95]

Contains a bitmask of flags indicating the current state of a message object. Every message must furnish this property.

Details

Identifier 0x0E07; property type PT_LONG; property tag 0x0E070003

Comments

Your application or provider can read the current state of the message by calling IMAPIProp::GetProps. The application or provider can also use the property in an IMAPIProp::SetProps call to change the current state of the message.

Your client application or message store provider can read any of the flags set in the PR_MESSAGE_FLAGS bitmask. However, the message object will ignore attempts by the application or provider to write to flags with read-only access.

The following flags can be set for the PR_MESSAGE_FLAGS bitmask:

Value	Description
MSGFLAG_ASSOCIATED	Indicates the message is an associated message of a folder. The application or provider has read-only access to this flag.
MSGFLAG_FROMME	Indicates that the messaging user sending was the messaging user receiving the message. The application or provider has read-only access to this flag. This flag is meant to be set by the transport.
MSGFLAG_HASATTACH	Indicates the message has at least one attachment. The application or provider has read-only access to this flag.
MSGFLAG_READ	Indicates the message has been read. The flag is also set when the client creates the message. The application or provider has read-write access to this flag and can call IMessage::SetReadFlag to change it. Some message stores do not honor read-write access to this flag and thus deny access.
MSGFLAG_RESEND	Indicates the message includes a request for a resend operation with a nondelivery report. After the first call to SaveChanges, the application or provider has read-only access to this flag .
MSGFLAG_SUBMIT	Indicates the message is marked for sending as a result of a call to IMessage::SubmitMessage. The application or provider has read-only access to this flag.
MSGFLAG_UNMODIFIED	Indicates the message has not been modified since reception. The application or provider has read-only access to this flag.
MSGFLAG_UNSENT	Indicates the message is still being composed. It is saved, but has not been sent. Typically, this flag is cleared after the message is sent.
See Also

IMAPIProp::GetProps method, IMAPIProp::SaveChanges method, IMAPIProp::SetProps method, IMessage::SetReadFlag method, IMsgStore::AbortSubmit method


 PR_MESSAGE_RECIP_ME

[New - Windows 95]

Set to TRUE if the messaging user was specifically named as the primary (To), carbon copy (CC), or blind carbon copy (BCC) recipient. The property contains FALSE otherwise.

Details

Identifier 0x0059; property type PT_BOOLEAN; property tag 0x0059000B

Comments

PR_MESSAGE_RECIP_ME is a convenient way to determine whether the user name explicitly appears in the recipient list, without examining all entries in the list. The value represents the logical-or operation of the properties PR_MESSAGE_CC_ME, PR_MESSAGE_TO_ME, and the Bcc information (which does not otherwise appear in a property).

This property assists automated handling of received messages at the time of receipt. The transport provider is responsible for setting the PR_MESSAGE_RECIP_ME property. At the transport provider's option, this property either contains FALSE or is not included if the messaging user is not listed directly in the recipient table.

Distribution list expansion does not cause this property to be set. The user must be explicitly named.

Unsent messages generally do not include this property. If the property is present in messages the user can access in public message stores, in other users' private stores, in files on disk, or embedded inside other received messages, it generally contains the value to which it was set the last time the transport provider delivered it.

See Also

PR_MESSAGE_CC_ME property, PR_MESSAGE_TO_ME property


 PR_MESSAGE_RECIPIENTS

[New - Windows 95]

Contains a table of restrictions that can be applied to the folder's contents table to find all messages that contain the recipients specified in the restrictions.

Details

Identifier 0x0E12; property type PT_OBJECT; property tag 0x0E12000D

Comments

You can restrict the contents table of the folder to find all messages where the recipients meet the conditions specified in the restriction. The restriction is true if one row remains in the table.

The restrictions are commonly used to exclude recipients from IMessage::CopyTo operations and to include recipients in IMessage::CopyProps operations.  This property can also be used in the IMAPIProp methods GetPropList, GetProps, OpenProps, and AddProps.

Note that using restrictions results in an open operation on every message in the folder. Depending on your application and the number of messages to be searched, it can affect application performance.

PR_MESSAGE_RECIPIENTS is used for recipients as PR_MESSAGE_ATTACHMENTS is used for attachments.

Several MAPI properties provide access to table objects:

Property	Table
PR_CONTAINER_HIERARCHY	Hierarchy table
PR_FOLDER_ASSOCIATED_CONTENTS	Associated contents table
PR_MESSAGE_ATTACHMENTS	Attachments table
PR_MESSAGE_RECIPIENTS	Recipients table
See Also

IMAPIProp::CopyProps method, IMAPIProp::CopyTo method, PR_MESSAGE_ATTACHMENTS property


 PR_MESSAGE_SECURITY_LABEL

[New - Windows 95]

Contains a security label for a message.

Details

Identifier 0x001E; property type PT_BINARY; property tag 0x001E0102

Comments

For X.400 environments, this property corresponds to the MH_T_SECURITY_LABEL attribute.

X.400 and EDI transport providers use this property for messages delivered to client applications. X.400 environments also use this property to represent the corresponding report per-message attribute as defined in the X.400 message-handling standard.

See Also

PR_MESSAGE_SIZE property


 PR_MESSAGE_SIZE

[New - Windows 95]

Contains the sum in bytes of the sizes of all properties of the message object.

Details

Identifier 0x0E08; property type PT_LONG; property tag 0x0E080003

Comments

The message size indicates the number of bytes transferred when the message is moved from one message store to another.

Most message store providers compute this property for messages that they handle. However, some message store providers do not support the property.

PR_ATTACH_SIZE provides the same information for the attachment that PR_MESSAGE_SIZE provides for the message.

See Also

PR_ATTACH_SIZE property, PR_MESSAGE_SUBMISSION_ID property


 PR_MESSAGE_SUBMISSION_ID

[New - Windows 95]

Contains a message transport system (MTS) identifier for the message transfer agent (MTA).

Details

Identifier 0x0047; property type PT_BINARY; property tag 0x00470102

Comments

For X.400 environments, PR_MESSAGE_SUBMISSION_ID corresponds to the MH_T_MTS_IDENTIFIER attribute.

See Also

PR_MESSAGE_DELIVERY_ID property


 PR_MESSAGE_TO_ME

[New - Windows 95]

Set to TRUE by a transport provider as a message is received into the message store of a messaging user listed directly as a primary (To) recipient in the recipient table.

Details

Identifier 0x0057; property type PT_BOOLEAN; property tag 0x0057000B

Comments

PR_MESSAGE_TO_ME is a convenient way to determine whether the user name explicitly appears in the recipient list, without examining all entries in the list. This property also assists automated handling of received messages at the time of receipt. At the transport provider's option, this property either contains FALSE or is not included if the messaging user is not listed directly in the recipient table.

Message delivery resulting from distribution list expansion or a blind carbon copy designation for the message sender does not cause this property to be set.

Unsent messages generally do not include this property. If the property is present in messages the user can access in public message stores, in other users' private stores, in files on disk, or embedded inside other received messages, it generally contains the value to which it was set the last time the transport provider delivered it.

See Also

PR_MESSAGE_CC_ME property, PR_MESSAGE_RECIP_ME property


 PR_MESSAGE_TOKEN

[New - Windows 95]

Contains an ASN.1 token for a message.

Details

Identifier 0x0C03, property type PT_BINARY; property tag 0x0c030102

Comments

For X.400 environments, PR_MESSAGE_TOKEN corresponds to the MH_T_TOKEN attribute.

X.400 and EDI transport providers use this property for messages delivered to client applications.

See Also

PR_PHYSICAL_RENDITION_ATTRIBUTES property


 PR_MHS_COMMON_NAME

[New - Windows 95]

Contains the common name of a messaging user for use in a message header.

Details

Identifier 0x3A0F, property type PT_TSTRING; property tag 0x3a0f001e

Comments

For X.400 environments, PR_MHS_COMMON_NAME corresponds to the MH_T_COMMON_NAME attribute as defined by the X.400 message-handling standard.

See Also

PR_DISPLAY_NAME property


 PR_MINI_ICON

[New - Windows 95]

Contains a 16 by 16 icon that is used on forms.

Details

Identifier 0x0FFC, property type PT_BINARY; property tag 0x0FFC0102

Comments

The value is the same as the contents of a .ICO file, that is, a bitmap.

See Also

PR_ICON property


 PR_MOBILE_TELEPHONE_NUMBER

[New - Windows 95]

Contains the cellular telephone number for the messaging user.

Details

Identifier 0x3A1C, property type PT_TSTRING; property tag 0x3A1C001E

Comments

This is the same property as PR_CELLULAR_TELEPHONE_NUMBER.

See Also

PR_CELLULAR_TELEPHONE_NUMBER property


 PR_MODIFY_VERSION

[New - Windows 95]

Contains the version number of the message store that was current at the time the specified message was last modified.

Details

Identifier 0x0E1A, property type PT_I8; property tag 0x0e1a0014

Comments

This version number is a copy of the message store version number contained in the PR_CURRENT_VERSION property.

Your application or service provider can use this property to support synchronization between message stores.

See Also

PR_CURRENT_VERSION property


 PR_MSG_STATUS

[New - Windows 95]

Contains a column in a contents table.

Details

Identifier 0x0E17, property type PT_LONG; property tag 0x0e170003

Comments

A message can exist in a contents table and in one or more search contents tables, and each instance of the message can have a different status. PR_MSG_STATUS should not be considered as a property in a message but as a column in a contents table.

Most values for the message status values are user-defined. See Also

IMAPIFolder::GetMessageStatus method, IMAPIFolder::SetMessageStatus method, IMAPITable::QueryRows method


 PR_NDR_DIAG_CODE

[New - Windows 95]

Contains a diagnostic code that forms part of a nondelivery report.

Details

Identifier 0x0C05, property type PT_LONG; property tag 0x0c050003

Comments

This MAPI property corresponds to the MH_T_NON_DELIVERY_DIAGNOSTIC attribute as defined by the X.400 message-handling standard.

The following values are valid for PR_NDR_DIAG_CODE:

Value

MAPI_DIAG_ALPHABETIC_CHARACTER_LOST

MAPI_DIAG_CONTENT_SYNTAX_IN_ERROR

MAPI_DIAG_CONTENT_TOO_LONG

MAPI_DIAG_CONTENT_TYPE_UNSUPPORTED

MAPI_DIAG_CONVERSION_LOSS_PROHIB

MAPI_DIAG_CONVERSION_UNSUBSCRIBED

MAPI_DIAG_CRITICAL_FUNC_UNSUPPORTED

MAPI_DIAG_DOWNGRADING_IMPOSSIBLE

MAPI_DIAG_EITS_UNSUPPORTED

MAPI_DIAG_EXPANSION_FAILED

MAPI_DIAG_EXPANSION_PROHIBITED

MAPI_DIAG_IMPRACTICAL_TO_CONVERT

MAPI_DIAG_LENGTH_CONSTRAINT_VIOLATD

MAPI_DIAG_LINE_TOO_LONG

MAPI_DIAG_LOOP_DETECTED

MAPI_DIAG_MAIL_ADDRESS_INCOMPLETE

MAPI_DIAG_MAIL_ADDRESS_INCORRECT

MAPI_DIAG_MAIL_FORWARDING_PROHIB

MAPI_DIAG_MAIL_FORWARDING_UNWANTED

MAPI_DIAG_MAIL_NEW_ADDRESS_UNKNOWN

MAPI_DIAG_MAIL_OFFICE_INCOR_OR_INVD

MAPI_DIAG_MAIL_ORGANIZATION_EXPIRED

MAPI_DIAG_MAIL_RECIPIENT_DECEASED

MAPI_DIAG_MAIL_RECIPIENT_DEPARTED

MAPI_DIAG_MAIL_RECIPIENT_MOVED

MAPI_DIAG_MAIL_RECIPIENT_TRAVELLING

MAPI_DIAG_MAIL_RECIPIENT_UNKNOWN

MAPI_DIAG_MAIL_REFUSED

MAPI_DIAG_MAIL_UNCLAIMED

MAPI_DIAG_MAXIMUM_TIME_EXPIRED

MAPI_DIAG_MTS_CONGESTED

MAPI_DIAG_MULTIPLE_INFO_LOSSES

MAPI_DIAG_NO_BILATERAL_AGREEMENT

MAPI_DIAG_NO_DIAGNOSTIC

MAPI_DIAG_NUMBER_CONSTRAINT_VIOLATD

MAPI_DIAG_OR_NAME_AMBIGUOUS

MAPI_DIAG_OR_NAME_UNRECOGNIZED

MAPI_DIAG_PAGE_TOO_LONG

MAPI_DIAG_PARAMETERS_INVALID

MAPI_DIAG_PICTORIAL_SYMBOL_LOST

MAPI_DIAG_PROHIBITED_TO_CONVERT

MAPI_DIAG_PUNCTUATION_SYMBOL_LOST

MAPI_DIAG_REASSIGNMENT_PROHIBITED

MAPI_DIAG_RECIPIENT_UNAVAILABLE

MAPI_DIAG_REDIRECTION_LOOP_DETECTED

MAPI_DIAG_RENDITION_UNSUPPORTED

MAPI_DIAG_SECURE_MESSAGING_ERROR

MAPI_DIAG_SUBMISSION_PROHIBITED

MAPI_DIAG_TOO_MANY_RECIPIENTS

See Also

PR_NDR_REASON_CODE property


 PR_NDR_REASON_CODE

[New - Windows 95]

Contains a reason code that forms part of a nondelivery report.

Details

Identifier 0x0C04, property type PT_LONG; property tag 0x0c040003

Comments

This MAPI property corresponds to the MH_T_NON_DELIVERY_REASON attribute as defined by the X.400 message-handling standard.

See Also

PR_NDR_DIAG_CODE property


 PR_NON_RECEIPT_NOTIFICATION_REQUESTED

[New - Windows 95]

Contains TRUE if a message sender wants notification of nondelivery for a specified recipient, and FALSE otherwise.

Details

Identifier 0x0C06, property type PT_BOOLEAN; property tag 0x0c06000b

Comments

If this property contains FALSE and the PR_READ_RECEIPT_REQUESTED property contains TRUE, the service provider can override the PR_NON_RECEIPT_NOTIFICATION_REQUESTED property and generate a nondelivery report.

This MAPI property corresponds to the IM_NOTIFICATION_REQUEST attribute as defined by the X.400 message-handling standard.

See Also

PR_READ_RECEIPT_REQUESTED property


 PR_NON_RECEIPT_REASON

[New - Windows 95]

Contains reasons why a message was not received (for example, the message was discarded) for use in a nondelivery report.

Details

Identifier 0x003E, property type PT_LONG; property tag 0x003e0003

Comments

This MAPI property corresponds to the IM_NON_RECEIPT_REASON attribute as defined by the X.400 message-handling standard.

See Also

PR_NDR_DIAG_CODE property


 PR_NORMALIZED_SUBJECT

[New - Windows 95]

Contains the subject with no prefix or with any prefix except reply and forward.

Details

Identifier 0x0E1D, property type PT_TSTRING; property tag 0x0e1d001e

Comments

A message store computes this property from the PR_SUBJECT and PR_SUBJECT_PREFIX properties. You can set the PR_SUBJECT_PREFIX property to a NULL string. The prefix can be a NULL string or can contain one, two, or three alphanumeric characters, followed by the colon character, ':'. The NULL string is always valid.

For X.400 environments, PR_NORMALIZED_SUBJECT corresponds to the IM_SUBJECT attribute as defined by the X.400 message-handling standard.

See Also

PR_SUBJECT property


 PR_NULL

[New - Windows 95]

Reserved. Represents the property with identifier 0x0000.

Details

Identifier 0x0000, property type PT_NULL; property tag 0x00000001

Comments

PR_NULL is used to reserve space in PropValue arrays. It is used in a PropTag array to tell the method to reserve space in the returned PropValue array. This allows for computed properties to be filled in an inexpensive way.

See Also

Extended MAPI Property Types


 PR_OBJECT_TYPE

[New - Windows 95]

Contains the type for an object. This type corresponds to the primary interface available for the object.

Details

Identifier 0x0FFE, property type PT_LONG; property tag 0x0ffe0003

Comments

The object type is usually obtained by consulting the [out] parameter returned by OpenEntry. When you obtain the interface in other ways, you can call GetProps to obtain the value for PR_OBJECT_TYPE.

All MAPI objects must furnish an object type. Possible types are:

Value	Description
MAPI_ABCONT	Address book container object.
MAPI_ADDRBOOK	Address book object.
MAPI_ATTACH	Message attachment object.
MAPI_DISTLIST	Distribution list object.
MAPI_FOLDER	Folder object.
MAPI_FORMINFO	Form object.
MAPI_MAILUSER	Mail user object.
MAPI_MESSAGE	Message object.
MAPI_PROFSECT	Profile section object.
MAPI_SESSION	Session object.
MAPI_STATUS	Status object.
MAPI_STORE	Message store object.
For more information on object types, see MAPI Programmer's Guide.


 PR_OBSOLETED_IPMS

[New - Windows 95]

Contains the identifiers of messages (PR_SEARCH_KEY) that a specified message supersedes.

Details

Identifier 0x001F, property type PT_BINARY; property tag 0x001f0102

Comments

This MAPI property corresponds to the submission envelope per-message IM_OBSOLETED_IPMS attribute as defined by the X.400 message-handling standard. X.400 transport providers use this property for messages delivered to client applications.

See Also

PR_SEARCH_KEY property


 PR_OFFICE_LOCATION

[New - Windows 95]

Contains the office location of the messaging user.

Details

Identifier 0x3A19, property type PT_TSTRING; property tag 0x3a19001e

Comments

Additional messaging user properties include the telephone number, fax number, and cellular telephone number.

See Also

PR_OFFICE_TELEPHONE_NUMBER property


 PR_OFFICE_TELEPHONE_NUMBER

[New - Windows 95]

Contains the office telephone number of a messaging user.

Details

Identifier 0x3A08, property type PT_TSTRING; property tag 0x3a08001e

Comments

Your application can specify another telephone number by setting the PR_OFFICE2_TELEPHONE_NUMBER property.

See Also

PR_OFFICE2_TELEPHONE_NUMBER property


 PR_OFFICE2_TELEPHONE_NUMBER

[New - Windows 95]

Contains a second office telephone number for a messaging user.

Details

Identifier 0x3A1B, property type PT_TSTRING; property tag 0x3a1b001e

Comments

Your application sets the PR_OFFICE_TELEPHONE_NUMBER property to specify the primary office number.

See Also

PR_OFFICE_TELEPHONE_NUMBER property


 PR_ORGANIZATIONAL_ID_NUMBER

[New - Windows 95]

Contains a number associated with that messaging user by the organization, such as an employee number.

Details

Identifier 0x3A10, property type PT_TSTRING; property tag 0x3a10001e

Comments

Additional messaging user properties include the telephone number, fax number, and cellular telephone number.

See Also

PR_OFFICE_TELEPHONE_NUMBER property


 PR_ORIG_MESSAGE_CLASS

[New - Windows 95]

Contains the class of the original message for use in a message report.

Details

Identifier 0x004B, property type PT_TSTRING; property tag 0x004b001e

Comments

This property contains a copy of the contents of PR_MESSAGE_CLASS.

See Also

PR_MESSAGE_CLASS property


 PR_ORIGINAL_AUTHOR_ADDRTYPE

[New - Windows 95]

Contains the address type of the author of the first version of a message (that is, the message before it is forwarded or replied to).

Details

Identifier 0x0079, property type PT_TSTRING; property tag 0x0079001E

Comments

The PR_ORIGINAL_AUTHOR_* properties allow you to preserve information that is from outside your messaging domain. When you obtain a message from another messaging domain and use it within Microsoft Exchange, such as when you post a message from the Internet to a public folder, these properties provide a way to ensure that information is not lost.

This property represents one of five maintained for the original author. Opening the entry id to find additional information is a relatively expensive operation, so properties representing the commonly-used display name, search key, address type, and email address are also defined with the entryid.

See Also

PR_ADDRTYPE property, PR_ORIGINAL_AUTHOR_EMAIL_ADDRESS property, PR_ORIGINAL_AUTHOR_ENTRYID property, PR_ORIGINAL_AUTHOR_SEARCH_KEY property


 PR_ORIGINAL_AUTHOR_EMAIL_ADDRESS

[New - Windows 95]

Contains the email address of the author of the first version of a message (that is, the message before it is forwarded or replied to).

Details

Identifier 0x007A, property type PT_TSTRING; property tag 0x007A001E

Comments

The PR_ORIGINAL_AUTHOR_* properties allow you to preserve information that is from outside your messaging domain. When you obtain a message from another messaging domain and use it within Microsoft Exchange, such as when you post a message from the Internet to a public folder, these properties provide a way to ensure that information is not lost.

This property represents one of five maintained for the original author. Opening the entry id to find additional information is a relatively expensive operation, so properties representing the commonly-used display name, search key, address type, and email address are also defined with the entryid.

See Also

PR_EMAIL_ADDRESS property, PR_ORIGINAL_AUTHOR_ADDRTYPE property, PR_ORIGINAL_AUTHOR_ENTRYID property, PR_ORIGINAL_AUTHOR_NAME property


 PR_ORIGINAL_AUTHOR_ENTRYID

[New - Windows 95]

Contains the entry identifier of the author of the first version of a message; that is, the message before it is forwarded or replied to.

Details

Identifier 0x004C, property type PT_BINARY; property tag 0x004C0102

Comments

The PR_ORIGINAL_AUTHOR_* properties allow you to preserve information that is from outside your messaging domain. When you obtain a message from another messaging domain and use it within Microsoft Exchange, such as when you post a message from the Internet to a public folder, these properties provide a way to ensure that information is not lost.

At first submission of a message within the same messaging domain, your application should set this optional property to the value of PR_SENDER_ENTRYID. It is never changed when the message is forwarded.

This property represents one of five maintained for the original author. Opening the entry id to find additional information is a relatively expensive operation, so properties representing the commonly-used display name, search key, address type, and email address are also defined with the entryid.

See Also

PR_ORIGINAL_AUTHOR_ADDRTYPE property, PR_ORIGINAL_AUTHOR_EMAIL_ADDRESS property, PR_ORIGINAL_AUTHOR_NAME property, PR_ORIGINAL_AUTHOR_SEARCH_KEY property, PR_SENDER_ENTRYID property


 PR_ORIGINAL_AUTHOR_NAME

[New - Windows 95]

Contains the name of the author of the first version of a message (that is, the message before it is forwarded or replied to).

Details

Identifier 0x004D, property type PT_TSTRING; property tag 0x004D001E

Comments

The PR_ORIGINAL_AUTHOR_* properties allow you to preserve information that is from outside your messaging domain. When you obtain a message from another messaging domain and use it within Microsoft Exchange, such as when you post a message from the Internet to a public folder, these properties provide a way to ensure that information is not lost.

This property represents one of five maintained for the original author. Opening the entry id to find additional information is a relatively expensive operation, so properties representing the commonly-used display name, search key, address type, and email address are also defined with the entryid.

At first submission of a message, your application should set this property to the value of PR_SENDER_NAME. It is never changed when the message is forwarded.

For X.400 environments, PR_ORIGINAL_AUTHOR_NAME corresponds to the MH_T_ORIGINATOR_NAME attribute as defined by the X.400 message-handling standard.

See Also

PR_ORIGINAL_AUTHOR_ADDRTYPE property, PR_ORIGINAL_AUTHOR_EMAIL_ADDRESS property, PR_ORIGINAL_AUTHOR_ENTRYID property, PR_ORIGINAL_AUTHOR_NAME property, PR_SENDER_NAME property


 PR_ORIGINAL_AUTHOR_SEARCH_KEY

[New - Windows 95]

Contains a copy of the original PR_SENDER_SEARCH_KEY data in a conversation thread. This value is copied in subsequent reply or forward operations.

Details

Identifier 0x0056, property type PT_BINARY; property tag 0x00560102

Comments

The PR_ORIGINAL_AUTHOR_* properties allow you to preserve information that is from outside your messaging domain. When you obtain a message from another messaging domain and use it within Microsoft Exchange, such as when you post a message from the Internet to a public folder, these properties provide a way to ensure that information is not lost.

See Also

PR_ORIGINAL_AUTHOR_ADDRTYPE property, PR_ORIGINAL_AUTHOR_EMAIL_ADDRESS property, PR_ORIGINAL_AUTHOR_ENTRYID property, PR_ORIGINAL_AUTHOR_NAME property, PR_SENDER_SEARCH_KEY property


 PR_ORIGINAL_DELIVERY_TIME

[New - Windows 95]

Contains a copy of the original PR_MESSAGE_DELIVERY_TIME data in a thread.

Details

Identifier 0x0055, property type PT_SYSTIME; property tag 0x00550040

Comments

PR_ORIGINAL_DELIVERY_TIME is copied in subsequent reply or forward operations and used in delivery, read, and nonread reports.

See Also

PR_MESSAGE_DELIVERY_TIME property


 PR_ORIGINAL_DISPLAY_BCC

[New - Windows 95]

Contains the original display name of a hidden carbon copy entry.

Details

Identifier 0x0072, property type PT_TSTRING; property tag 0x0072001E

Comments

This property contains the original BCC display name values for a copied entry.

See Also

PR_ORIGINAL_DISPLAY_CC property


 PR_ORIGINAL_DISPLAY_CC

[New - Windows 95]

Contains the original display names of the message CC list.

Details

Identifier 0x0073, property type PT_TSTRING; property tag 0x0073001E

Comments

This property contains the original CC display name values for a copied entry.

See Also

PR_ORIGINAL_DISPLAY_BCC property


 PR_ORIGINAL_DISPLAY_NAME

[New - Windows 95]

Contains the original display name of an entry copied from an address book to a personal address book or another writable address book.

Details

Identifier 0x3A13, property type PT_TSTRING; property tag 0x3A13001E

Comments

This property and the PR_ORIGINAL_ENTRYID property contain the original source of a copied entry.

For a nonread report, PR_ORIGINAL_DISPLAY_NAME contains a copy of the display name of the original message recipient for which the report is generated. When the original recipient is part of a distribution list, the display name of the group is preserved for the report.

Your application can use PR_ORIGINAL_DISPLAY_NAME to prevent alteration or "spoofing" of entries.   An example of spoofing is displaying "John Doe" as "John (What a Guy) Doe."

See Also

PR_TRANSMITTABLE_DISPLAY_NAME property


 PR_ORIGINAL_DISPLAY_TO

[New - Windows 95]

Contains the original display names of the message To: list.

Details

Identifier 0x0074, property type PT_TSTRING; property tag 0x0074001E

Comments

This property contains the original To: display name values for a copied entry.

See Also

PR_ORIGINAL_DISPLAY_CC property


 PR_ORIGINAL_EITS

[New - Windows 95]

Contains a copy of the original embedded information types (EITs) for text (body) parts of a message.

Details

Identifier 0x0021, property type PT_BINARY; property tag 0x00210102

Comments

For X.400 environments, PR_ORIGINAL_EITS corresponds to the MH_T_ORIGINAL_EITS attribute.

X.400 and EDI transport providers use this property for messages delivered to client applications. X.400 environments also use it to represent the corresponding probe submission per-message and report per-message attributes as defined by the X.400 message-handling standard.

See Also

PR_CONVERSION_EITS property, PR_CONVERTED_EITS property


 PR_ORIGINAL_ENTRYID

[New - Windows 95]

Contains the original entry identifier of an entry copied from an address book  to a personal address book or another writeable address book.

Details

Identifier 0x3A12, property type PT_BINARY; property tag 0x3A120102

Comments

This property and the PR_ORIGINAL_DISPLAY_NAME property contain the original source of a copied entry.

For a nonread notification report, PR_ORIGINAL_ENTRYID contains a copy of the entry identifier of the original message recipient for which the report is generated. When the original recipient is part of a distribution list, the entry identifier of the group is preserved for the report.

See Also

PR_ORIGINAL_DISPLAY_NAME property


 PR_ORIGINAL_SEARCH_KEY

[New - Windows 95]

Contains the original search key associated with an entry copied from an address book to a personal address book or another writeable address book.

Details

Identifier 0x3A14, property type PT_BINARY; property tag 0x3A140102

Comments

The PR_ORIGINAL_* properties contain information about the original source of a copied entry.

See Also

PR_ORIGINAL_ENTRYID property


 PR_ORIGINAL_SENDER_ADDRTYPE

[New - Windows 95]

Contains the address type of the sender of the first version of a message (that is, the message before it is forwarded or replied to).

Details

Identifier 0x0066, property type PT_TSTRING; property tag 0x0066001E

Comments

This is set to the same value as PR_SENDER_ADDRTYPE.

This is one of several PR_ORIGINAL_SENDER_* properties that preserve information from the corresponding PR_SENDER_* properties.

See Also

PR_SENDER_ADDRTYPE property


 PR_ORIGINAL_SENDER_EMAIL_ADDRESS

[New - Windows 95]

Contains the email address of the sender of the first version of a message (that is, the message before it is forwarded or replied to).

Details

Identifier 0x0067, property type PT_TSTRING; property tag 0x0067001E

Comments

This is initially set to the same value as PR_SENDER_EMAIL_ADDRESS.

This is one of several PR_ORIGINAL_SENDER_* properties that preserve information from the corresponding PR_SENDER_* properties.

See Also

PR_SENDER_EMAIL_ADDRESS property


 PR_ORIGINAL_SENDER_ENTRYID

[New - Windows 95]

Contains the entry identifier of the sender of the first version of a message (that is, the message before it is forwarded or replied to).

Details

Identifier 0x005B, property type PT_BINARY; property tag 0x005B0102

Comments

This is initially set to the same value as PR_SENDER_ENTRYID.

The PR_ORIGINAL_AUTHOR_* values are usually set to the same values as the PR_ORIGINAL_SENDER_* values.

This is one of several PR_ORIGINAL_SENDER_* properties that preserve information from the corresponding PR_SENDER_* properties.

See Also

PR_ORIGINAL_AUTHOR_ENTRYID property, PR_SENDER_ENTRYID property


 PR_ORIGINAL_SENDER_NAME

[New - Windows 95]

Contains the display name of the sender of the first version of a message (that is, the message before it is forwarded or replied to).

Details

Identifier 0x005A, property type PT_TSTRING; property tag 0x005A001E

Comments

This is initially set to the same value as PR_SENDER_NAME.

The PR_ORIGINAL_AUTHOR_* values are usually set to the same values as the PR_ORIGINAL_SENDER_* values.

For X.400 environments, PR_ORIGINAL_SENDER_NAME corresponds to the MH_T_ORIGINATOR_NAME attribute as defined by the X.400 message-handling standard.

See Also

PR_ORIGINAL_AUTHOR_NAME property, PR_SENDER_NAME property


 PR_ORIGINAL_SENDER_SEARCH_KEY

[New - Windows 95]

Contains the search key for the sender of the first version of a message (that is, the message before it is forwarded or replied to).

Details

Identifier 0x005C, property type PT_BINARY; property tag 0x005C0102

Comments

This is set to the same value as PR_SENDER_SEARCH_KEY.

The PR_ORIGINAL_AUTHOR_* values are usually set to the same values as the PR_ORIGINAL_SENDER_* values.

See Also

PR_ORIGINAL_AUTHOR_SEARCH_KEY property, PR_SENDER_SEARCH_KEY property


 PR_ORIGINAL_SENT_REPRESENTING_ADDRTYPE

[New - Windows 95]

Contains the address type of the messaging user on whose behalf the original message is sent for a conversation thread.

Details

Identifier 0x0068, property type PT_TSTRING; property tag 0x0068001E

Comments

This property applies when the sender is sending the message as the delegated agent of the messaging user.

See Also

PR_ORIGINAL_SENT_REPRESENTING_ENTRYID property


 PR_ORIGINAL_SENT_REPRESENTING_EMAIL_ADDRESS

[New - Windows 95]

Contains the email address of the messaging user on whose behalf the original message is sent for a conversation thread.

Details

Identifier 0x0069, property type PT_TSTRING; property tag 0x0069001E

Comments

This property applies when the sender is sending the message as the delegated agent of the messaging user.

See Also

PR_ORIGINAL_SENT_REPRESENTING_ENTRYID property


 PR_ORIGINAL_SENT_REPRESENTING_ENTRYID

[New - Windows 95]

Contains the entry identifier of the messaging user on whose behalf the original message is sent for a conversation thread (PR_SENT_REPRESENTING_ENTRYID).

Details

Identifier 0x005E, property type PT_BINARY; property tag 0x005E0102

Comments

This property applies when the sender is sending the message as the delegated agent of the messaging user.

See Also

PR_SENT_REPRESENTING_ENTRYID property


 PR_ORIGINAL_SENT_REPRESENTING_NAME

[New - Windows 95]

Contains the display name of the messaging user on whose behalf the original message is sent for a conversation thread.

Details

Identifier 0x005D, property type PT_TSTRING; property tag 0x005D001E

Comments

Like PR_SENT_REPRESENTING_NAME, this property applies when the sender is sending the message as the delegated agent of the messaging user.

See Also

PR_SENT_REPRESENTING_NAME property


 PR_ORIGINAL_SENT_REPRESENTING_SEARCH_KEY

[New - Windows 95]

Contains the search key of the messaging user on whose behalf the original message is sent for a conversation thread.

Details

Identifier 0x005F, property type PT_BINARY; property tag 0x005F0102

Comments

Like PR_SENT_REPRESENTING_SEARCH_KEY, this property applies when the sender is sending the message as the delegated agent of the messaging user.

See Also

PR_SENT_REPRESENTING_SEARCH_KEY property


 PR_ORIGINAL_SUBJECT

[New - Windows 95]

Contains the subject of an original message for use in a report about the message.

Details

Identifier 0x0049, property type PT_TSTRING; property tag 0x0049001E

Comments

Set to the same value as PR_SUBJECT.

For X.400 environments, PR_ORIGINAL_SUBJECT corresponds to the IM_SUBJECT attribute as defined by the X.400 message-handling standard.

See Also

PR_SUBJECT property


 PR_ORIGINAL_SUBMIT_TIME

[New - Windows 95]

Contains the original submission time of the message in the report.

Details

Identifier 0x004E, property type PT_SYSTIME; property tag 0x004E0040

Comments

At first submission of a message, your application should set this property to the value of the PR_CLIENT_SUBMIT_TIME property. It is not changed when the message is forwarded. This is used in reports only.

See Also

PR_CLIENT_SUBMIT_TIME property


 PR_ORIGINALLY_INTENDED_RECIP_ADDRTYPE

[New - Windows 95]

Contains the address type of the originally intended recipient of an autoforwarded message.

Details

Identifier 0x007B, property type PT_TSTRING; property tag 0x007B001E

Comments

This property represents one of several maintained for the intended recipient, including the name, entryid, and email address.

X.400 and EDI transport providers use this property for messages delivered to client applications. X.400 environments also use it to represent the IM_IPM_INTENDED_RECIPIENT attribute as defined by the X.400 message-handling standard.

See Also

PR_ADDRTYPE property, PR_ORIGINALLY_INTENDED_RECIP_EMAIL_ADDRESS property, PR_ORIGINALLY_INTENDED_RECIPIENT_NAME property


 PR_ORIGINALLY_INTENDED_RECIP_EMAIL_ADDRESS

[New - Windows 95]

Contains the email address of the originally intended recipient of an autoforwarded message.

Details

Identifier 0x007C, property type PT_TSTRING; property tag 0x007C001E

Comments

This property represents one of several maintained for the intended recipient, including the name, entryid, and address type.

X.400 and EDI transport providers use this property for messages delivered to client applications. X.400 environments also use it to represent the corresponding report per-recipient attribute as defined by the X.400 message-handling standard.

See Also

PR_EMAIL_ADDRESS property, PR_ORIGINALLY_INTENDED_RECIP_ADDRTYPE property, PR_ORIGINALLY_INTENDED_RECIPIENT_NAME property


 PR_ORIGINALLY_INTENDED_RECIP_ENTRYID

[New - Windows 95]

Contains the entryid of the originally intended recipient of an autoforwarded message.

Details

Identifier 0x1012, property type PT_BINARY; property tag 0x10120102

Comments

This property represents one of several maintained for the intended recipient, including the name, address type, and email address.

X.400 and EDI transport providers use this property for messages delivered to client applications. X.400 environments also use it to represent the corresponding report per-recipient attribute as defined by the X.400 message-handling standard.

See Also

PR_ENTRYID property, PR_ORIGINALLY_INTENDED_RECIP_ADDRTYPE property, PR_ORIGINALLY_INTENDED_RECIPIENT_NAME property


 PR_ORIGINALLY_INTENDED_RECIPIENT_NAME

[New - Windows 95]

Contains the entry identifier of the originally intended recipient of an autoforwarded message.

Details

Identifier 0x0020, property type PT_BINARY; property tag 0x00200102

Comments

For X.400 environments, PR_ORIGINALLY_INTENDED_RECIPIENT_NAME corresponds to the MH_T_ORIGINALLY_INTENDED_RECIP attribute.

X.400 and EDI transport providers use this property for messages delivered to client applications. X.400 environments also use it to represent the corresponding report per-recipient attribute as defined by the X.400 message-handling standard.

See Also

PR_ORIGINALLY_INTENDED_RECIP_ENTRYID property


 PR_ORIGINATING_MTA_CERTIFICATE

[New - Windows 95]

Contains an identifier for the message transfer agent (MTA) that originated the message. Details

Identifier 0x0E25, property type PT_BINARY; property tag 0x0E250102

Comments

This MAPI property represents the corresponding X.400 report per-message attribute as defined by the X.400 message-handling standard.

See Also

PR_REPORTING_MTA_CERTIFICATE property


 PR_ORIGINATOR_AND_DL_EXPANSION_HISTORY

[New - Windows 95]

Contains information about a message originator and a distribution list expansion history for use in report generation.

Details

Identifier 0x1002, property type PT_BINARY; property tag 0x10020102

Comments

This MAPI property corresponds to the report per-message MH_T_ORIG_AND_EXPANSION_HISTORY attribute as defined by the X.400 message-handling standard.

See Also

PR_ORIGINATOR_CERTIFICATE property


 PR_ORIGINATOR_CERTIFICATE

[New - Windows 95]

Contains an authentication certificate for a message originator. An authentication certificate is similar to a digital signature.

Details

Identifier 0x0022, property type PT_BINARY; property tag 0x00220102

Comments

For X.400 environments, PR_ORIGINATOR_CERTIFICATE corresponds to the MH_T_ORIGINATOR_CERTIFICATE attribute.

X.400 and EDI transport providers use this property for messages delivered to client applications. X.400 environments also use it to represent the corresponding probe submission per-message attribute as defined by the X.400 message-handling standard.

See Also

PR_ORIGINATOR_AND_DL_EXPANSION_HISTORY property


 PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED

[New - Windows 95]

Contains TRUE if a message sender requests a delivery report from the messaging system before the message is placed in the message store for a particular recipient. The property contains FALSE otherwise.

Details

Identifier 0x0023, property type PT_BOOLEAN; property tag 0x0023000B

Comments

This property is used to direct the messaging system in handling delivered messages.

For X.400 and EDI environments, the PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED property represents the corresponding submission envelope per-recipient attributes as defined by the X.400 and EDI message-handling standards. For X.400 environments, PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED set to TRUE corresponds to the MH_T_ORIGINATOR_REPORT_REQUEST attribute. In this case, the message must also furnish PR_ORIGINATOR_NON_DELIVERY_REPORT_REQUESTED set to FALSE.

X.400 environments also use PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED to represent the corresponding probe submission per-recipient attribute as defined in the X.400 message-handling standard.

See Also

PR_ORIGINATOR_NON_DELIVERY_REPORT_REQUESTED property


 PR_ORIGINATOR_NON_DELIVERY_REPORT_REQUESTED

[New - Windows 95]

Contains TRUE if a message sender requests a nondelivery report for a particular recipient, and FALSE otherwise.

Details

Identifier 0x0C08, property type PT_BOOLEAN; property tag 0x0C08000B

Comments

For X.400 environments, this property set to TRUE corresponds to the MH_T_ORIGINATOR_REPORT_REQUEST attribute. In this case, the message must also furnish PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED set to FALSE.

See Also

PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED property


 PR_ORIGINATOR_REQUESTED_ALTERNATE_RECIPIENT

[New - Windows 95]

Contains the entry identifier of an alternate recipient chosen by a message sender to receive a message if it cannot be delivered to the original recipient.

Details

Identifier 0x0C09, property type PT_BINARY; property tag 0x0C090102

Comments

For X.400 environments, this property corresponds to the MH_T_ALTERNATE_RECIPIENT_NAME attribute. X.400 environments also use this property to represent the corresponding probe submission per-recipient attribute as defined by the X.400 message-handling standard.

See Also

PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED property


 PR_ORIGINATOR_RETURN_ADDRESS

[New - Windows 95]

Contains the return address of the message originator.

Details

Identifier 0x0024, property type PT_BINARY; property tag 0x00240102

Comments

Represents submission envelope per-recipient attributes as defined by the X.400 and EDI message-handling standards. For X.400 environments, PR_ORIGINATOR_RETURN_ADDRESS corresponds to the MH_T_ORIGINATOR_RETURN_ADDRESS attribute. X.400 and EDI transport providers use this property for messages delivered to client applications.

See Also

PR_ORIGINATOR_CERTIFICATE property


 PR_ORIGIN_CHECK

[New - Windows 95]

Contains the Extended MAPI property corresponding to an X.400 attribute used for authentication checks.

Details

Identifier 0x0027, property type PT_BINARY; property tag 0x00270102

Comments

This property replaces several properties supplied in pre-release versions of Extended MAPI, including PR_MESSAGE_ORIGIN_AUTHENTICATION_CHECK, PR_PROBE_SUBMISSION_AUTHENTICATION_CHECK, and PR_REPORT_ORIGIN_AUTHENTICATION_CHECK.

See Also

PR_ORIGINATOR_CERTIFICATE property


 PR_OTHER_TELEPHONE_NUMBER

[New - Windows 95]

Contains an alternate telephone number (that is, a number other than the home or office number) for a messaging user.

Details

Identifier 0x3A1F, property type PT_TSTRING; property tag 0x3A1F001E

Comments

Additional messaging user properties include the telephone number, fax number, and cellular telephone number.

See Also

PR_OFFICE_TELEPHONE_NUMBER property


 PR_OWN_STORE_ENTRYID

[New - Windows 95]

Contains the entry identifier of the transport's tightly-coupled message store.

Details

Identifier 0x3E06, property type PT_BINARY; property tag 0x3E060102

Comments

Specifies the entry identifier for the tightly-coupled store, if one exists. Appears on the transport status rows or status objects. For example, a transport might specify the private folder store entryid so that the spooler knows how to connect the transport to the store.

See Also

PR_STORE_ENTRYID property


 PR_OWNER_APPT_ID

[New - Windows 95]

Contains an identifier that represents the appointment in the owner's schedule. Used in a meeting request.

Details

Identifier 0x0062, property type PT_LONG; property tag 0x00620003

Comments

Note that this property does not represent an entry identifier, but a long integer that uniquely identifies the appointment within the owner's schedule.

See Also

PR_END_DATE property, PR_ORIGINAL_AUTHOR_SEARCH_KEY property, PR_START_DATE property


 PR_PAGER_TELEPHONE_NUMBER

[New - Windows 95]

Contains the messaging user's pager telephone number.

Details

Identifier 0x3A21, property type PT_TSTRING; property tag 0x3A21001E

Comments

Several properties are available for the messaging user, including the home, office, mobile, and fax telephone numbers.

See Also

PR_OFFICE_TELEPHONE_NUMBER property


 PR_PARENT_DISPLAY

[New - Windows 95]

Contains a copy of the parent folder's display name.

Details

Identifier 0x0E05, property type PT_TSTRING; property tag 0x0E05001E

Comments

Represents a column in a search folder contents table. Note that the search folder contents table differs from the folder contents table.

Message stores compute the PR_PARENT_DISPLAY property for all messages.

All search-results folders must make this property available.

See Also

PR_PARENT_ENTRYID property


 PR_PARENT_ENTRYID

[New - Windows 95]

Contains the entry identifier of the folder in which a message was found during a search. All search-results folders must furnish this property in their contents tables.

Details

Identifier 0x0E09, property type PT_BINARY; property tag 0x0E090102

Comments

Message stores compute the PR_PARENT_ENTRYID property for all messages.

All search-results folders must make this property available. Folder and interpersonal message objects must furnish this property.

For a message store root folder, PR_PARENT_ENTRYID contains the folder's own entry identifier.

See Also

PR_PARENT_DISPLAY property


 PR_PARENT_KEY

[New - Windows 95]

Represents the X.400 property IM_REPLIED_TO_IPM.

Details

Identifier 0x0025, property type PT_BINARY; property tag 0x00250102

Comments

For X.400 environments, PR_PARENT_KEY corresponds to the IM_REPLIED_TO_IPM attribute as defined by the X.400 message-handling standard.

See Also

PR_PARENT_ENTRYID property


 PR_PHYSICAL_DELIVERY_BUREAU_FAX_DELIVERY

[New - Windows 95]

Contains TRUE if the messaging system should use a fax bureau for physical delivery of a specified message.

Details

Identifier 0x0C0A, property type PT_BOOLEAN; property tag 0x0C0A000B

Comments

For X.400 environments, this MAPI property corresponds to the MH_T_BUREAU_FAX_DELIVERY attribute.

X.400 and EDI transport providers use this property for messages delivered to client applications.

See Also

PR_PHYSICAL_DELIVERY_MODE property


 PR_PHYSICAL_DELIVERY_MODE

[New - Windows 95]

Contains a bitmask of flags defining the physical delivery mode (for example, special delivery) for a message designated for a specific recipient.

Details

Identifier 0x0C0B, property type PT_LONG; property tag 0x0C0B0003

Comments

For X.400 environments, this MAPI property corresponds to the MH_T_POSTAL_MODE attribute.

X.400 and EDI transport providers use this property for messages delivered to client applications.

See Also

PR_PHYSICAL_DELIVERY_BUREAU_FAX_DELIVERY property


 PR_PHYSICAL_DELIVERY_REPORT_REQUEST

[New - Windows 95]

Contains the mode of a report to be delivered to a particular message recipient upon completion of physical message delivery or delivery by the message handling system (MHS).

Details

Identifier 0x0C0C, property type PT_LONG; property tag 0x0C0C0003

Comments

For X.400 environments, this MAPI property corresponds to the MH_T_POSTAL_REPORT attribute as defined by the X.400 message-handling standard. X.400 and EDI transport providers use this property for messages delivered to client applications.

See Also

PR_PHYSICAL_DELIVERY_MODE property


 PR_PHYSICAL_FORWARDING_ADDRESS

[New - Windows 95]

Contains the physical forwarding address of a message recipient and is used only with message reports.

Details

Identifier 0x0C0D, property type PT_BINARY; property tag 0x0C0D0102

Comments

This property corresponds to the report per-recipient MH_T_FORWARDING_ADDRESS attribute as defined by the X.400 message-handling standard.

See Also

PR_PHYSICAL_FORWARDING_ADDRESS_REQUESTED property


 PR_PHYSICAL_FORWARDING_ADDRESS_REQUESTED

[New - Windows 95]

Contains TRUE if a message sender requests the message transfer agent (MTA) to attach a physical forwarding address for a message recipient, and FALSE otherwise.

Details

Identifier 0x0C0E, property type PT_BOOLEAN; property tag 0x0C0E000B

Comments

This MAPI property represents the corresponding X.400 and EDI submission envelope per-recipient attributes as defined by the X.400 and EDI message-handling standards.For X.400 environments, this MAPI property corresponds to the MH_T_FORWARDING_ADR_REQUESTED attribute.

X.400 and EDI transport providers use this property for messages delivered to client applications.

See Also

PR_PHYSICAL_FORWARDING_ADDRESS property


 PR_PHYSICAL_FORWARDING_PROHIBITED

[New - Windows 95]

Contains TRUE if a message sender prohibits physical message forwarding for a specific recipient, and FALSE otherwise.

Details

Identifier 0x0C0F, property type PT_BOOLEAN; property tag 0x0C0F000B

Comments

For X.400 environments, this property corresponds to the MH_T_FORWARDING_PROHIBITED attribute.

X.400 and EDI transport providers use this property for messages delivered to client applications.

See Also

PR_PHYSICAL_FORWARDING_ADDRESS_REQUESTED property


 PR_PHYSICAL_RENDITION_ATTRIBUTES

[New - Windows 95]

Contains an ASN.1 object identifier (OID) used for rendering message attachments.

Details

Identifier 0x0C10, property type PT_BINARY; property tag 0x0C100102

Comments

For X.400 environments, this property corresponds to MH_T_RENDITION_ATTRIBUTES.  X.400 and EDI transport providers use this property for messages delivered to client applications. X.400 environments also use the property for probe messages.

See Also

PR_ATTACH_ENCODING property


 PR_POST_OFFICE_BOX

[New - Windows 95]

Contains the messaging user's post office box.

Details

Identifier 0x3A2B, property type PT_TSTRING; property tag 0x3A2B001E

Comments

Several properties are available for the messaging user, including several telephone numbers and fields of the user's home or business mailing address.

See Also

PR_BUSINESS_TELEPHONE_NUMBER property


 PR_POSTAL_ADDRESS

[New - Windows 95]

Contains the postal address of a messaging user.

Details

Identifier 0x3A15, property type PT_TSTRING; property tag 0x3A15001E

Comments

Several properties are available for the messaging user, including several telephone numbers and fields of the user's home or business mailing address.

See Also

PR_BUSINESS_TELEPHONE_NUMBER property


 PR_POSTAL_CODE

[New - Windows 95]

Contains the postal code for the messaging user's address.

Details

Identifier 0x3A2A, property type PT_TSTRING; property tag 0x3A2A001E

Comments

The postal code is specific to the messaging user's country. In the United States of America, this property contains the ZIP code.

See Also

PR_BUSINESS_TELEPHONE_NUMBER property


 PR_PREPROCESS

[New - Windows 95]

Reserved for MAPI.

Details

Identifier 0x0E22, property type PT_BOOLEAN; property tag 0x0E22000B

Comments

This property is for use by MAPI only.  Do not use.

See Also

PR_SUBMIT_FLAGS property


 PR_PRIMARY_CAPABILITY

[New - Windows 95]

Reserved for MAPI.

Details

Identifier 0x3904, property type PT_BINARY; property tag 0x39040102

Comments

This property is reserved for use by MAPI.  Do not use.

See Also

PR_AB_PROVIDER_ID property


 PR_PRIMARY_FAX_NUMBER

[New - Windows 95]

Contains the telephone number for the messaging user's primary fax machine.

Details

Identifier 0x3A23, property type PT_TSTRING; property tag 0x3A23001E

Comments

Several properties are available for the messaging user, including several telephone numbers and fields of the messaging user home mailing address.

See Also

PR_OFFICE_TELEPHONE_NUMBER property


 PR_PRIMARY_TELEPHONE_NUMBER

[New - Windows 95]

Contains the primary telephone number of a messaging user.

Details

Identifier 0x3A1A, property type PT_TSTRING; property tag 0x3A1A001E

Comments

Several properties are available for the messaging user, including several telephone numbers and fields of the messaging user home mailing address.

For X.400 environments, this property corresponds to IM_TELEPHONE_NUMBER as defined by the X.400 messaging standard.

See Also

PR_OFFICE_TELEPHONE_NUMBER property


 PR_PRIORITY

[New - Windows 95]

Contains the relative priority of a message.

Details

Identifier 0x0026, property type PT_LONG; property tag 0x00260003

Comments

PR_PRIORITY is distinguished from PR_IMPORTANCE . Importance indicates a value to users, while priority indicates the order or speed at which the message should be sent by the messaging system software. Higher priority usually indicates a higher cost. Higher importance usually is associated with different display by the user interface.

For X.400 environments, this MAPI property corresponds to MH_T_PRIORITY. X.400 and EDI transport providers use this property for messages delivered to client applications. The PR_PRIORITY property can have the values listed below. Note that the priority of a report message should be the same as the priority of the original message being reported.

Value	Description
PRIO_NONURGENT	The message is not urgent.
PRIO_NORMAL	The message has normal priority.
PRIO_URGENT	The message is urgent.
See Also

PR_IMPORTANCE property


 PR_PROFILE_NAME

[New - Windows 95]

Contains the profile name.

Details

Identifier 0x3D12, property type PT_TSTRING, property tag 0x3D12001E

Comments

PR_PROFILE_NAME is a computed property and is always present on the profile section. A provider's ServiceEntry code can use this property to discover the profile name.

Applications can use this property as a convenient alternative to the other method used to obtain the profile name, which involves examining the PR_DISPLAY_NAME property on the MAPI subsystem's status table row.

See Also

PR_DISPLAY_NAME property


 PR_PROOF_OF_DELIVERY

[New - Windows 95]

Contains an ASN.1 proof of delivery value.

Details

Identifier 0x0C11, property type PT_BINARY; property tag 0x0C110102

Comments

This MAPI property represents the report per-recipient MH_T_PROOF_OF_DELIVERY attribute as defined by the X.400 message-handling standard.

See Also

PR_PROOF_OF_DELIVERY_REQUESTED property


 PR_PROOF_OF_DELIVERY_REQUESTED

[New - Windows 95]

Contains TRUE if a message sender requests proof of delivery for a particular recipient, and FALSE otherwise.

Details

Identifier 0x0C12, property type PT_BOOLEAN; property tag 0x0C12000B

Comments

For X.400 environments, this property corresponds to the MH_T_PROOF_OF_DELIV_REQUESTED attribute. X.400 and EDI transport providers use this property for messages delivered to client applications.

See Also

PR_PROOF_OF_DELIVERY property


 PR_PROOF_OF_SUBMISSION

[New - Windows 95]

Contains an ASN.1 proof of submission value.

Details

Identifier 0x0E26, property type PT_BINARY; property tag 0x0E260102

Comments

This MAPI property represents the corresponding X.400 and EDI submission envelope per-message attributes as defined by the X.400 and EDI message-handling standards. See Also

PR_PROOF_OF_SUBMISSION_REQUESTED property


 PR_PROOF_OF_SUBMISSION_REQUESTED

[New - Windows 95]

Contains TRUE if a message sender requests proof that the message transport system (MTS) has submitted a message for delivery to the originally intended recipient, and FALSE otherwise.

Details

Identifier 0x0028, property type PT_BOOLEAN; property tag 0x0028000B

Comments

This MAPI property represents the corresponding X.400 and EDI submission envelope per-message attributes as defined by the X.400 and EDI message-handling standards. For X.400 environments, this property corresponds to the MH_T_PROOF_OF_SUBMSN_REQUESTED attribute.

See Also

PR_PROOF_OF_SUBMISSION property


 PR_PROVIDER_DISPLAY

[New - Windows 95]

Contains the vendor-defined display name for a service provider.

Details

Identifier 0x3006, property type PT_TSTRING; property tag 0x3006001E

Comments

PR_PROVIDER_DISPLAY and PR_PROVIDER_DLL_NAME are defined only on profile sections belonging to service providers. They must be present in MAPISVC.INF.

See Also

PR_PROVIDER_DLL_NAME property


 PR_PROVIDER_DLL_NAME

[New - Windows 95]

Contains the base filename of the MAPI service provider DLL.

Details

Identifier 0x300A, property type PT_TSTRING; property tag 0x300A001E

Comments

MAPI uses a DLL file naming convention. The base name contains up to six characters that uniquely identify the DLL. MAPI appends the string "32" to the base DLL name to identify the version that runs on 32-bit platforms. For example, when the name "MAPI.DLL" is specified, MAPI constructs the name "MAPI32.DLL" to represent the corresponding 32-bit version of the DLL. The PR_PROVIDER_DLL_NAME property should specify the base name. MAPI appends the string "32" as appropriate.

Including the string "32" as part of the PR_PROVIDER_DLL_NAME property results in an error.

See Also

PR_PROVIDER_DISPLAY property, PR_SERVICE_DLL_NAME property


 PR_PROVIDER_ORDINAL

[New - Windows 95]

Contains the zero-based index of a service provider's position in a provider table created by IMsgServiceAdmin::GetProviderTable.

Details

Identifier 0x300D, property type PT_LONG; property tag 0x300D0003

Comments

Represents a computed property that appears only in the provider table. Sort the provider table by PR_PROVIDER_ORDINAL to display the transport order.

See Also

IMsgServiceAdmin::GetProviderTable method


 PR_PROVIDER_SUBMIT_TIME

[New - Windows 95]

Contains the date and time when a message sender marked a message for submission by a transport provider to its underlying messaging system.

Details

Identifier 0x0048, property type PT_SYSTIME; property tag 0x00480040

Comments

This property is computed by transport providers, which add it to a message based on the results of message submission.

This MAPI property represents the corresponding X.400 and EDI submission envelope per-message attributes as defined by the X.400 and EDI message-handling standards.See Also

PR_CLIENT_SUBMIT_TIME property


 PR_PROVIDER_UID

[New - Windows 95]

Contains the unique identifier (UID) of the service provider that is handling a message.

Details

Identifier 0x300C, property type PT_BINARY; property tag 0x300C0102

Comments

PR_PROVIDER_UID is a unique MAPIUID associated with (and usually hard-coded by) the provider. It is typically used by a client that is interested in only the address book containers supplied by a particular provider.

Appears only in the provider table.

See Also

PR_PROVIDER_DISPLAY property


 PR_RADIO_TELEPHONE_NUMBER

[New - Windows 95]

Contains the radio telephone number of a messaging user.

Details

Identifier 0x3A1D, property type PT_TSTRING; property tag 0x3A1D001E

Comments

Several properties are available for the messaging user, including several telephone numbers and fields of the messaging user home mailing address.

See Also

PR_OFFICE_TELEPHONE_NUMBER property


 PR_RCVD_REPRESENTING_ADDRTYPE

[New - Windows 95]

Contains the address type for the messaging user that is represented by another messaging user.

Details

Identifier 0x0077, property type PT_TSTRING; property tag 0x0077001E

Comments

When user B receives mail for user A, the PR_RECEIVED_BY_* properties are set to user B and the PR_RCVD_REPRESENTING_* properties are set to user A.

The PR_RCVD_REPRESENTING_* properties on a message indicate that one user receives the message on behalf of another messaging user. This property is often set by the transport provider, which is also responsible for authorization or verification of the representative. Note that the PR_RCVD_REPRESENTING_* properties are not required and may not be present for all messages.

Client applications that use this property to categorize messages should set default values for the PR_RCVD_REPRESENTING_* properties when they are not present, such as setting them to the same values as the PR_RECEIVED_BY_* properties.

This property represents one of five maintained for the represented messaging user. Opening the entry id to find additional information is a relatively expensive operation, so properties representing the commonly-used display name, search key, address type, and email address are also defined with the entryid.

See Also

PR_ADDRTYPE property, PR_RCVD_REPRESENTING_ADDRTYPE property, PR_RCVD_REPRESENTING_EMAIL_ADDRESS property, PR_RCVD_REPRESENTING_ENTRYID property, PR_RCVD_REPRESENTING_SEARCH_KEY property


 PR_RCVD_REPRESENTING_EMAIL_ADDRESS

[New - Windows 95]

Contains the email address for the messaging user that is represented by another messaging user.

Details

Identifier 0x0078, property type PT_TSTRING; property tag 0x0078001E

Comments

When user B receives mail for user A, the PR_RECEIVED_BY_* properties are set to user B and the PR_RCVD_REPRESENTING_* properties are set to user A.

The PR_RCVD_REPRESENTING_* properties on a message indicate that one user receives the message on behalf of another messaging user. This property is often set by the transport provider, which is also responsible for authorization or verification of the delegate. Note that the PR_RCVD_REPRESENTING_* properties are not required and may not be present for all messages.

Client applications that use this property to categorize messages should set default values for the PR_RCVD_REPRESENTING_* properties when they are not present, such as setting them to the same values as the PR_RECEIVED_BY_* properties.

This property represents one of five maintained for the represented messaging user. Opening the entry id to find additional information is a relatively expensive operation, so properties representing the commonly-used display name, search key, address type, and email address are also defined with the entryid.

See Also

PR_RCVD_REPRESENTING_ADDRTYPE property, PR_RCVD_REPRESENTING_ENTRYID property, PR_RCVD_REPRESENTING_SEARCH_KEY property, PR_RECEIVED_BY_EMAIL_ADDRESS property, PR_RECEIVED_BY_NAME property


 PR_RCVD_REPRESENTING_ENTRYID

[New - Windows 95]

Contains the entryid for the messaging user that is represented by another messaging user.

Details

Identifier 0x0043, property type PT_BINARY; property tag 0x00430102

Comments

When user B receives mail for user A, the PR_RECEIVED_BY_* properties are set to user B and the PR_RCVD_REPRESENTING_* properties are set to user A.

The PR_RCVD_REPRESENTING_* properties on a message indicate that one user receives the message on behalf of another messaging user. This property is often set by the transport provider, which is also responsible for authorization or verification of the delegate. Note that the PR_RCVD_REPRESENTING_* properties are not required and may not be present for all messages.

Client applications that use this property to categorize messages should set default values for the PR_RCVD_REPRESENTING_* properties when they are not present, such as setting them to the same values as the PR_RECEIVED_BY_* properties.

This property represents one of five maintained for the represented messaging user. Opening the entry id to find additional information is a relatively expensive operation, so properties representing the commonly-used display name, search key, address type, and email address are also defined with the entryid.

See Also

PR_RCVD_REPRESENTING_ADDRTYPE property, PR_RCVD_REPRESENTING_EMAIL_ADDRESS property, PR_RCVD_REPRESENTING_NAME property, PR_RCVD_REPRESENTING_SEARCH_KEY property, PR_RECEIVED_BY_ENTRYID property


 PR_RCVD_REPRESENTING_NAME

[New - Windows 95]

Contains the entryid for the messaging user that is represented by another messaging user.

Details

Identifier 0x0044, property type PT_TSTRING; property tag 0x0044001E

Comments

When user B receives mail for user A, the PR_RECEIVED_BY_* properties are set to user B and the PR_RCVD_REPRESENTING_* properties are set to user A.

The PR_RCVD_REPRESENTING_* properties on a message indicate that one user receives the message on behalf of another messaging user. This property is often set by the transport provider, which is also responsible for authorization or verification of the delegate. Note that the PR_RCVD_REPRESENTING_* properties are not required and may not be present for all messages.

Client applications that use this property to categorize messages should set default values for the PR_RCVD_REPRESENTING_* properties when they are not present, such as setting them to the same values as the PR_RECEIVED_BY_* properties.

This property represents one of five maintained for the represented messaging user. Opening the entry id to find additional information is a relatively expensive operation, so properties representing the commonly-used display name, search key, address type, and email address are also defined with the entryid.

See Also

PR_RCVD_REPRESENTING_ADDRTYPE property, PR_RCVD_REPRESENTING_EMAIL_ADDRESS property, PR_RCVD_REPRESENTING_ENTRYID property, PR_RCVD_REPRESENTING_SEARCH_KEY property, PR_RECEIVED_BY_NAME property


 PR_RCVD_REPRESENTING_SEARCH_KEY

[New - Windows 95]

Contains the entry identifier for the messaging user that is represented by another messaging user.

Details

Identifier 0x0052, property type PT_BINARY; property tag 0x00520102

Comments

When user B receives mail for user A, the PR_RECEIVED_BY_* properties are set to user B and the PR_RCVD_REPRESENTING_* properties are set to user A.

The PR_RCVD_REPRESENTING_* properties on a message indicate that one user receives the message on behalf of another messaging user. This property is often set by the transport provider, which is also responsible for authorization or verification of the delegate. Note that the PR_RCVD_REPRESENTING_* properties are not required and may not be present for all messages.

Client applications that use this property to categorize messages should set default values for the PR_RCVD_REPRESENTING_* properties when they are not present, such as setting them to the same values as the PR_RECEIVED_BY_* properties.

This property represents one of five maintained for the represented messaging user. Opening the entry id to find additional information is a relatively expensive operation, so properties representing the commonly-used display name, search key, address type, and email address are also defined with the entryid.

See Also

PR_RCVD_REPRESENTING_ADDRTYPE property, PR_RCVD_REPRESENTING_EMAIL_ADDRESS property, PR_RCVD_REPRESENTING_ENTRYID property, PR_RCVD_REPRESENTING_NAME property, PR_RECEIVED_BY_SEARCH_KEY property


 PR_READ_RECEIPT_ENTRYID

[New - Windows 95]

Contains an entry identifier computed by a transport provider to indicate the messaging user to whom the messaging system should direct a read report for a message.

Details

Identifier 0x0046, property type PT_BINARY; property tag 0x00460102

Comments

This property is ignored unless PR_READ_RECEIPT_REQUESTED is set to TRUE.

If your client application or service provider wants to receive read receipts for messages, it should set PR_READ_RECEIPT_ENTRYID at message submission time. The transport should set this to the value of the PR_SENDER_ENTRYID property.

This property represents one of three maintained for the read receipt request. Opening the entry id to find additional information is a relatively expensive operation, so properties representing the commonly-used request flag and search key are also defined with the entryid.

See Also

PR_READ_RECEIPT_REQUESTED property, PR_READ_RECEIPT_SEARCH_KEY property, PR_SENDER_ENTRYID property


 PR_READ_RECEIPT_REQUESTED

[New - Windows 95]

Contains TRUE if a message sender wants the messaging system to generate a read report when the recipient has read a message. It contains FALSE otherwise.

Details

Identifier 0x0029, property type PT_BOOLEAN; property tag 0x0029000B

Comments

If a message with this property set is deleted or expires before the messaging system can generate a read report, a nonread report is generated.

For interpersonal messaging in X.400 environments, this MAPI property corresponds to the submission envelope per-recipient IM_NOTIFICATION_REQUEST attribute.

PR_READ_RECEIPT_REQUESTED must be set to TRUE to validate the values in the properties PR_READ_RECEIPT_ENTRYID and PR_READ_RECEIPT_SEARCH_KEY.

This property represents one of three maintained for the read receipt request. Opening the entry id to find additional information is a relatively expensive operation, so properties representing the commonly-used request flag and search key are also defined with the entryid.

See Also

PR_READ_RECEIPT_ENTRYID property, PR_READ_RECEIPT_SEARCH_KEY property


 PR_READ_RECEIPT_SEARCH_KEY

[New - Windows 95]

Contains the search key for a read report.

Details

Identifier 0x0053, property type PT_BINARY; property tag 0x00530102

Comments

This property represents one of three maintained for the read receipt request. Opening the entry id to find additional information is a relatively expensive operation, so properties representing the commonly-used request flag and search key are also defined with the entryid.

See Also

PR_READ_RECEIPT_ENTRYID property, PR_READ_RECEIPT_REQUESTED property


 PR_RECEIPT_TIME

[New - Windows 95]

Contains the date and time of a delivery report.

Details

Identifier 0x002A, property type PT_SYSTIME; property tag 0x002A0040

Comments

This MAPI property corresponds to the interpersonal notification IM_RECEIPT_TIME attribute as defined by the X.400 message-handling standard.

See Also

PR_REPORT_ENTRYID property


 PR_RECEIVED_BY_ADDRTYPE

[New - Windows 95]

Contains the actual recipient's e-mail address type, such as "SMTP".

Details

Identifier 0x3002, property type PT_TSTRING; property tag 0x3002001E

Comments

The address type string can contain only the uppercase alphabetic characters A through Z and the numbers 0 through 9. PR_RECEIVED_BY_ADDRTYPE qualifies the PR_RECEIVED_BY_EMAIL_ADDRESS property.

Five properties are maintained for the message recipient:  the address type, email address, entry id, search key, and display name.

See Also

PR_ADDRTYPE property, PR_RECEIVED_BY_EMAIL_ADDRESS property, PR_RECEIVED_BY_ENTRYID property, PR_RECEIVED_BY_NAME property, PR_RECEIVED_BY_SEARCH_KEY property


 PR_RECEIVE_FOLDER_SETTINGS

[New - Windows 95]

Contains the receive folder settings.

Details

Identifier 0x3415, property type PT_OBJECT; property tag 0x3415000D

Comments

PR_RECEIVE_FOLDER_SETTINGS is a message story property.

See Also

PR_FOLDER_TYPE property


 PR_RECEIVED_BY_EMAIL_ADDRESS

[New - Windows 95]

Contains the actual recipient's e-mail address.

Details

Identifier 0x3003, property type PT_TSTRING; property tag 0x3003001E

Comments

Five properties are maintained for the actual message recipient:  the address type, email address, entry id, search key, and display name.

When the messaging user that receives the message is the same as the intended recipient, the PR_RECEIVED_BY_EMAIL_ADDRESS and PR_EMAIL_ADDRESS properties have the same value.

See Also

PR_EMAIL_ADDRESS property, PR_RECEIVED_BY_ADDRTYPE property, PR_RECEIVED_BY_ENTRYID property, PR_RECEIVED_BY_NAME property, PR_RECEIVED_BY_SEARCH_KEY property


 PR_RECEIVED_BY_ENTRYID

[New - Windows 95]

Contains a message recipient's entry identifier set by the transport provider handling a message.

Details

Identifier 0x003F, property type PT_BINARY; property tag 0x003F0102

Comments

This property, along with the PR_RECEIVED_BY_NAME property, is required for all incoming messages.

This property represents one of five that are maintained for the message recipient. Opening the entry id to find additional information is a relatively expensive operation, so properties representing the commonly-used display name, search key, address type, and email address are also defined. The transport should set all five related PR_RECEIVED_BY_* properties.

For X.400 environments, this MAPI property corresponds to the MH_T_ACTUAL_RECIPIENT_NAME attribute as defined by the X.400 message-handling standard.

See Also

PR_RECEIVED_BY_ADDRTYPE property, PR_RECEIVED_BY_EMAIL_ADDRESS property, PR_RECEIVED_BY_NAME property, PR_RECEIVED_BY_SEARCH_KEY property, PR_SENDER_ENTRYID property


 PR_RECEIVED_BY_NAME

[New - Windows 95]

Contains a message recipient's display name set by the transport provider handling a message.

Details

Identifier 0x0040, property type PT_TSTRING; property tag 0x0040001E

Comments

This property, along with the PR_RECEIVED_BY_ENTRYID property, is required for all incoming messages.

This property represents one of five that are maintained for the message recipient. Opening the entry id to find additional information is a relatively expensive operation, so properties representing the commonly-used display name, search key, address type, and email address are also defined. The transport should set all five related PR_RECEIVED_BY_* properties.

In X.400 and EDI environments, this MAPI property represents the corresponding delivery envelope per-message attributes as defined by the X.400 and EDI message-handling standards. X.400 and EDI transport providers use this property for messages delivered to client applications.

See Also

PR_RECEIVED_BY_ADDRTYPE property, PR_RECEIVED_BY_EMAIL_ADDRESS property, PR_RECEIVED_BY_ENTRYID property, PR_RECEIVED_BY_SEARCH_KEY property, PR_SENDER_NAME property


 PR_RECEIVED_BY_SEARCH_KEY

[New - Windows 95]

Contains the message recipient's search key set by the transport provider handling the message.

Details

Identifier 0x0051, property type PT_BINARY; property tag 0x00510102

Comments

This property represents one of five that are maintained for the message recipient. Opening the entry id to find additional information is a relatively expensive operation, so properties representing the commonly-used display name, search key, address type, and email address are also defined. The transport should set all five related PR_RECEIVED_BY_* properties.

See Also

PR_RECEIVED_BY_ADDRTYPE property, PR_RECEIVED_BY_EMAIL_ADDRESS property, PR_RECEIVED_BY_ENTRYID property, PR_RECEIVED_BY_NAME property, PR_SENDER_NAME property


 PR_RECIPIENT_CERTIFICATE

[New - Windows 95]

Contains a message recipient's ASN.1 certificate for use in a report.

Details

Identifier 0x0C13, property type PT_BINARY; property tag 0x0C130102

Comments

This MAPI property corresponds to the report per-recipient MH_T_RECEIPT_CERTIFICATE attribute as defined by the X.400 message-handling standard.

See Also

PR_RECIPIENT_NUMBER_FOR_ADVICE property


 PR_RECIPIENT_NUMBER_FOR_ADVICE

[New - Windows 95]

Contains a message recipient's telephone number to call to advise of the physical delivery of a message.

Details

Identifier 0x0C14, property type PT_TSTRING; property tag 0x0C14001E

Comments

For X.400 environments, this MAPI property corresponds to the MH_T_RECIP_NUMBER_FOR_ADVICE attribute. X.400 and EDI transport providers use this property for messages delivered to client applications.

See Also

PR_RECIPIENT_REASSIGNMENT_PROHIBITED property


 PR_RECIPIENT_REASSIGNMENT_PROHIBITED

[New - Windows 95]

Contains TRUE if recipient reassignment is prohibited, and FALSE otherwise.

Details

Identifier 0x002B, property type PT_BOOLEAN; property tag 0x002B000B

Comments

For X.400 environments, this MAPI property corresponds to MH_T_REASSIGNMENT_PROHIBITED. X.400 environments use this property for probe messages.

See Also

PR_RECIPIENT_STATUS property


 PR_RECIPIENT_STATUS

[New - Windows 95]

Reserved for use by MAPI only.

Details

Identifier 0x0E15, property type PT_LONG; property tag 0x0E150003

Comments

Do not use this property. PR_RECIPIENT_STATUS is reserved for use by MAPI.

See Also

PR_RECIPIENT_TYPE property


 PR_RECIPIENT_TYPE

[New - Windows 95]

Contains the recipient type for the message.

Details

Identifier 0x0C15, property type PT_LONG; property tag 0x0C150003

Comments

The recipient type must take one of the three values. None, either, or both of the other flags can also be set.

The PR_RECIPIENT_TYPE property can have the following values:

Value	Description
MAPI_TO	The recipient is a primary (To) recipient.
MAPI_CC	The recipient is a carbon copy (CC) recipient.
MAPI_BCC	The recipient is a blind carbon copy (BCC) recipient.
MAPI_P1	The recipient is a P1 resend recipient.
MAPI_SUBMITTED	The recipient is already processed.
See Also

PR_RECIPIENT_STATUS property


 PR_RECORD_KEY

[New - Windows 95]

Contains a unique binary-comparable identifier for an object.

Details

Identifier 0x0FF9, property type PT_BINARY; property tag 0x0FF90102

Comments

This property uniquely identifies the object within a message. This identifier is the only attachment characteristic guaranteed to stay the same after the message is closed and reopened. (It must remain unique across sessions so that it will be guaranteed to stay the same after the message is closed and reopened.)

Mail user, distribution list, address book container, folder, message store (both public and private), attachment, and all message objects must furnish this property.

You can compare PR_RECORD_KEY values using memcmp. This is not possible for entryid values.

For folders, this property contains a key used in the folder hierarchy table. Typically this is the same value as that provided by the PR_ENTRYID property.

For message stores, this property is identical to PR_STORE_RECORD_KEY.

The distinction between PR_RECORD_KEY and PR_SEARCH_KEY is that PR_RECORD_KEY is specific to the object, while PR_SEARCH_KEY can be copied to other objects. For example, two copies of the object could have the same search key, but they must have different record keys.

See Also

PR_ENTRYID property, PR_SEARCH_KEY property, PR_STORE_RECORD_KEY property


 PR_REDIRECTION_HISTORY

[New - Windows 95]

Contains information about the route covered by a delivered message.

Details

Identifier 0x002C, property type PT_BINARY; property tag 0x002C0102

Comments

X.400 and EDI transport providers use this property for messages delivered to client applications.

For X.400 environments, this property corresponds to the MH_T_REDIRECTION_HISTORY attribute.

See Also

PR_AUTO_FORWARDED property


 PR_REGISTERED_MAIL_TYPE

[New - Windows 95]

Contains the type of registration used for physical delivery of a message.

Details

Identifier 0x0C16, property type PT_LONG; property tag 0x0C160003

Comments

For X.400 environments, this MAPI property corresponds to the MH_T_REGISTRATION attribute. X.400 and EDI transport providers use this property for messages delivered to client applications.

See Also

PR_PHYSICAL_FORWARDING_ADDRESS property, PR_X400_CONTENT_TYPE property


 PR_RELATED_IPMS

[New - Windows 95]

Contains a list of message identifiers (as in the PR_SEARCH_KEY property) to which a message is related.

Details

Identifier 0x002D, property type PT_BINARY; property tag 0x002D0102

Comments

This MAPI property corresponds to the submission envelope per-message IM_RELATED_IPMS attribute as defined by the X.400 message-handling standard. X.400 transport providers use this property for messages delivered to client applications.

See Also

PR_SEARCH_KEY property


 PR_REMOTE_PROGRESS

[New - Windows 95]

Contains a numeric code indicating the status of a remote transfer.

Details

Identifier 0x3E0B, property type PT_LONG; property tag 0x3E0B0003

Comments

The text associated with the numeric status code appears in the PR_REMOTE_PROGRESS_TEXT property.

The following flags can be set for the PR_REMOTE_PROGRESS bitmask:

Value	Description
MSGSTATUS_REMOTE_DELETE	Indicates the message transfer is deleted.
MSGSTATUS_REMOTE_DOWNLOAD	Indicates the message transfer is in progress.
See Also

PR_REMOTE_PROGRESS_TEXT property


 PR_REMOTE_PROGRESS_TEXT

[New - Windows 95]

Contains an ASCII string indicating the status of a remote transfer.

Details

Identifier 0x3E0C, property type PT_TSTRING; property tag 0x3E0C001E

Comments

A numeric code associated with this text is passed in the PR_REMOTE_PROGRESS property.

See Also

PR_REMOTE_PROGRESS property


 PR_REMOTE_VALIDATE_OK

[New - Windows 95]

When TRUE, indicates that the remote viewer can make repeated IMAPIStatus::ValidateState calls to the transport. When FALSE, indicates that the remote viewer can not make the calls.

Details

Identifier 0x3E0D, property type PT_BOOLEAN; property tag 0x3E0D000B

Comments

This property appears in the status table and offers some control over transport performance. It can be considered as another way of directing the remote viewer to idle. When it is set to TRUE, the remote viewer can call IMAPIStatus::ValidateState repeatedly. A value of FALSE indicates that the remote viewer can not make these calls.

The transport usually sets this property dynamically, setting the value to FALSE to disable additional calls when the transport has a sufficient amount of processing to perform. When the transport is done, it then sets the value to TRUE to allow the client to make further IMAPIStatus::ValidateState calls.

See Also

IMAPIStatus::ValidateState method, PR_REMOTE_PROGRESS property


 PR_RENDERING_POSITION

[New - Windows 95]

Contains an ordinal offset (in characters) to use in rendering an attachment within the main message text.

Details

Identifier 0x370B, property type PT_LONG; property tag 0x370B0003

Comments

When the supplied offset is -1 (0xFFFFFFFF), the attachment is not rendered using PR_RENDERING_POSITION. All values other than -1 indicate the position within PR_BODY at which the attachment is to be rendered.

Identifies where in the body of the message MAPI should render the attachment. This is not used for RTF messages.

Do not use this property with RTF text. A special RTF tag is defined to indicate the rendering position. All other attachment objects must furnish this property.

See Also

PR_BODY property


 PR_REPLY_RECIPIENT_ENTRIES

[New - Windows 95]

Contains a sized array of entry identifiers for recipients that are to get the reply.

Details

Identifier 0x004F, property type PT_BINARY; property tag 0x004F0102

Comments

When this optional property is not present, the reply message is sent only to PR_SENDER. When PR_REPLY_RECIPIENT_ENTRIES and PR_REPLY_RECIPIENT_NAMES are defined, the reply is sent to all of the recipients identified by these two properties. A transport provider uses these properties to override the normal reply logic.

Note that PR_REPLY_RECIPIENT_ENTRIES contains a FLATENTRYLIST structure and is not a multivalued property.

For X.400 environments, this MAPI property corresponds to the delivery envelope per-message IM_REPLY_RECIPIENTS attribute as defined by the X.400 message-handling standard. X.400 transport providers use this property for messages delivered to client applications.

See Also

FLATENTRYLIST structure, PR_SENDER_ENTRYID property


 PR_REPLY_RECIPIENT_NAMES

[New - Windows 95]

Contains a list of display names of recipients that are to get the reply.

Details

Identifier 0x0050, property type PT_TSTRING; property tag 0x0050001E

Comments

Corresponds to the entryids that appear in PR_REPLY_RECIPIENT_ENTRIES. Contains one string, with the display names separated by semicolons.

See Also

FLATENTRYLIST structure, PR_SENDER_NAME property


 PR_REPLY_REQUESTED

[New - Windows 95]

Contains TRUE if a message sender requests a reply from a recipient, and FALSE otherwise.

Details

Identifier 0x0C17, property type PT_BOOLEAN; property tag 0x0C17000B

Comments

For X.400 environments, this MAPI property corresponds to the submission envelope per-recipient IM_REPLY_REQUESTED attribute as defined by the X.400 message-handling standard.

See Also

PR_REPLY_TIME property


 PR_REPLY_TIME

[New - Windows 95]

Contains the date and time by which a reply is expected for a message.

Details

Identifier 0x0030, property type PT_SYSTIME; property tag 0x00300040

Comments

For X.400 environments, this MAPI property corresponds to the submission envelope per-message IM_REPLY_TIME attribute as defined by the X.400 message-handling standard. X.400 transport providers use this property for messages delivered to client applications.

See Also

PR_REPLY_REQUESTED property


 PR_REPORT_ENTRYID

[New - Windows 95]

Contains the entry identifier for the recipient that should get reports for the message.

Details

Identifier 0x0045, property type PT_BINARY; property tag 0x00450102

Comments

Specifies the recipient for delivery reports (DR) and non-delivery reports (NDR) related to the message.

This property represents one of three maintained for the report recipient. Opening the entry id to find additional information is a relatively expensive operation, so properties representing the commonly-used display name and search key are defined along with the entryid.

Your application should set this property at message submission time. If it is not set, the reports are sent to the recipient specified by PR_SENDER_ENTRYID.

See Also

PR_REPORT_NAME property, PR_REPORT_SEARCH_KEY property, PR_SENDER_ENTRYID property


 PR_REPORT_NAME

[New - Windows 95]

Contains the display name of the recipient that should get reports for the message.

Details

Identifier 0x003A, property type PT_TSTRING; property tag 0x003A001E

Comments

Specifies the display name of the recipient that should get delivery reports (DR) and non-delivery reports (NDR) related to the message. For delivery reports, this is a per-recipient property. On read receipts and non-read receipts, this is a message property.

This property represents one of three maintained for the report recipient. Opening the entry id to find additional information is a relatively expensive operation, so properties representing the commonly-used display name and search key are defined along with the entryid.

Your application should set this property at message submission time. If it is not set, the reports are sent to the recipient specified by the PR_SENDER_ENTRYID and other related PR_SENDER_* properties.

See Also

PR_REPORT_ENTRYID property, PR_SENDER_NAME property


 PR_REPORT_SEARCH_KEY

[New - Windows 95]

Contains the search key for the recipient that should get the report.

Details

Identifier 0x0054, property type PT_BINARY; property tag 0x00540102

Comments

Specifies the search key for the recipient that should get delivery reports (DR) and non-delivery reports (NDR) related to the message.

This property represents one of three maintained for the report recipient. Opening the entry id to find additional information is a relatively expensive operation, so properties representing the commonly-used display name and search key are defined along with the entryid.

See Also

PR_REPORT_ENTRYID property, PR_REPORT_NAME property, PR_SENDER_SEARCH_KEY property


 PR_REPORT_TAG

[New - Windows 95]

Contains a binary tag value that the messaging system should copy to any report generated for the message.

Details

Identifier 0x0031, property type PT_BINARY; property tag 0x00310102

Comments

The PR_REPORT_TAG property is used for correlation between a message and its corresponding report.

See Also

PR_REPORT_NAME property, PR_REPORT_TIME property


 PR_REPORT_TEXT

[New - Windows 95]

Contains optional text for a read report or a nonread report generated by the messaging system.

Details

Identifier 0x1001, property type PT_TSTRING; property tag 0x1001001E

Comments

For X.400 environments, PR_REPORT_TEXT corresponds to the IM_SUPPLEMENTARY_RECEIPT_INFO attribute as defined by the X.400 message-handling standard.

See Also

PR_REPORT_NAME property


 PR_REPORT_TIME

[New - Windows 95]

Contains the date and time when the messaging system generated a read report or a nonread report.

Details

Identifier 0x0032, property type PT_SYSTIME; property tag 0x00320040

Comments

PR_REPORT_TIME represents a per-recipient property in the delivery report and represents a message property on read and non-read reports.

See Also

PR_REPORT_NAME property, PR_REPORT_TAG property


 PR_REPORTING_DL_NAME

[New - Windows 95]

Contains the display name of a distribution list for which the messaging system is delivering a report.

Details

Identifier 0x1003, property type PT_BINARY; property tag 0x10030102

Comments

For X.400 environments, this MAPI property corresponds to the report per-message MH_T_REPORTING_DL_NAME attribute as defined by the X.400 message-handling standard.

See Also

PR_REPORTING_MTA_CERTIFICATE property


 PR_REPORTING_MTA_CERTIFICATE

[New - Windows 95]

Contains an identifier for the message transfer agent (MTA) that generated a report.

Details

Identifier 0x1004, property type PT_BINARY; property tag 0x10040102

Comments

This MAPI property represents the corresponding X.400 report per-message attribute as defined by the X.400 message-handling standard.

See Also

PR_REPORTING_DL_NAME property


 PR_REQUESTED_DELIVERY_METHOD

[New - Windows 95]

Contains a binary array of delivery methods (service providers), in order of a message sender's preference.

Details

Identifier 0x0C18, property type PT_BINARY; property tag 0x0C180102

Comments

For X.400 environments, this property corresponds to the MH_T_PREFERRED_DELIVERY_MODE attribute. X.400 and EDI transport providers use this property for messages delivered to client applications. X.400 environments also use this property for probe messages.

See Also

PR_PROOF_OF_DELIVERY_REQUESTED property


 PR_RESOURCE_FLAGS

[New - Windows 95]

Appears on message services and providers. This property also represents a column in several tables.

Details

Identifier 0x3009, property type PT_LONG; property tag 0x30090003

Comments

All static flags are expected to be set in MAPISVC.INF and never modified. All flags that are not static can be set by an Extended MAPI method.

The following flags can be supplied in PR_RESOURCE_FLAGS for a messaging service, the messaging services table, and a profile.

Value	Description
SERVICE_DEFAULT_STORE	Indicates the messaging service contains the default store. A user interface should be displayed prompting the user for confirmation before deleting or moving this service out of the profile. This flag applies only to messaging services.
SERVICE_NO_PRIMARY_IDENTITY	Indicates that service level flag that should be set to indicate that none of the providers in the service can be used to supply an identity. Either this flag or SERVICE_PRIMARY_IDENTITY should be set, but not both. This flag represents a static value defined in MAPISVC.INF that is not changed by any MAPI method.
SERVICE_PRIMARY_IDENTITY	Indicates that the corresponding service contains the provider used for the primary identity for this session. Use IMAPIMsgServiceAdmin::SetPrimaryIdentity to set this flag. Either this flag or SERVICE_NO_PRIMARY_IDENTITY should be set, but not both.
SERVICE_SINGLE_COPY	Indicates that any attempt to create or copy this service into a profile where the service already exists should fail. To create a single copy service add the PR_RESOURCE_FLAGS property to the service's section in MAPISVC.INF and set this flag. This flag represents a static value defined in MAPISVC.INF that is not changed by any MAPI method.
See Also

IMsgServiceAdmin::MsgServiceTransportOrder method, PR_IDENTITY_ENTRYID property, PR_OWN_STORE_ENTRYID property, PR_SENT_REPRESENTING_NAME property


 PR_RESOURCE_METHODS

[New - Windows 95]

Contains a bitmask of flags indicating the status object methods that are supported.

Details

Identifier 0x3E02, property type PT_LONG; property tag 0x3E020003

Comments

All system resources contain a status table for the IMAPIStatus interface and set flags in this property. If a flag is set in the status table, the corresponding IMAPIStatus method exists and can be called. If that flag is clear in the status table, the method should not be called.

The following flags can be set for the PR_RESOURCE_METHODS bitmask:

Value	Description
STATUS_CHANGE_PASSWORD	Indicates the ChangePassword method is present.
STATUS_FLUSH_QUEUES	Indicates the FlushQueues method is present.
STATUS_SETTINGS_DIALOG	Indicates the SettingsDialog method is present.
STATUS_VALIDATE_STATE	Indicates the ValidateState method is present.
See Also

IMAPIStatus::ChangePassword method, IMAPIStatus::FlushQueues method, IMAPIStatus::SettingsDialog method, IMAPIStatus::ValidateState method


 PR_RESOURCE_PATH

[New - Windows 95]

Contains a path to the service provider's server.

Details

Identifier 0x3E07, property type PT_TSTRING; property tag 0x3E07001E

Comments

This property appears on a status object and or a status table row.

For example, this represents the suggested path where the user would find resources. The definition of the proeprty is provider specific. For example, a scheduling application would use this property to specify the suggested location for its scheduling application files.

The messaging user profile furnishes the property as a convenience so that a client application does not have to prompt the messaging user for a network path or network drive letter.

See Also

PR_RESOURCE_TYPE property


 PR_RESOURCE_TYPE

[New - Windows 95]

Contains a constant indicating the service provider type.

Details

Identifier 0x3E03, property type PT_LONG; property tag 0x3E030003

Comments

The PR_RESOURCE_TYPE property can have one of the following values:

Value	Description
MAPI_AB	Address book
MAPI_AB_PROVIDER	Address book provider
MAPI_HOOK_PROVIDER	Spooler hook provider
MAPI_PROFILE_PROVIDER	Profile provider
MAPI_SPOOLER	Message spooler
MAPI_STORE_PROVIDER	Message store provider
MAPI_SUBSYSTEM	MAPI subsystem
MAPI_TRANSPORT_PROVIDER	Transport provider
See Also

PR_RESOURCE_PATH property


 PR_RESPONSE_REQUESTED

[New - Windows 95]

Contains TRUE if a message sender requests a response, and FALSE otherwise.

Details

Identifier 0x0063, property type PT_BOOLEAN; property tag 0x0063000B

Comments

PR_RESPONSE_REQUESTED is a message envelope property.

See Also

PR_OWNER_APPT_ID property


 PR_RESPONSIBILITY

[New - Windows 95]

Contains TRUE if a transport provider accepts responsibility for sending the message to the specified recipient, and FALSE otherwise.

Details

Identifier 0x0E0F, property type PT_BOOLEAN; property tag 0x0E0F000B

Comments

Indicates that the transport provider is responsible for sending this message to this recipient. The transport sets the value to true when it accepts responsibility and sends the message.

This property exists only on the recipient table.

For X.400 environments, PR_RESPONSIBILITY corresponds to the MH_T_MTA_RESPONSIBILITY attribute as defined by the X.400 message-handling standard.

See Also

PR_DELETE_AFTER_SUBMIT property


 PR_RETURNED_IPM

[New - Windows 95]

Contains TRUE if the original interpersonal message is returned with a nondelivery report, and FALSE otherwise.

Details

Identifier 0x0033, property type PT_BOOLEAN; property tag 0x0033000B

Comments

This property represents the interpersonal notification IM_RETURNED_IPM attribute as defined by the X.400 message-handling standard.

See Also

PR_IPM_ID property, PR_RELATED_IPMS property


 PR_ROW_TYPE

[New - Windows 95]

Contains a value that indicates the type of a row in a table.

Details

Identifier 0x0FF5, property type PT_LONG; property tag 0x0FF50003

Comments

PR_ROW_TYPE appears only on contents tables. A category only exists when it has items.

The PR_ROW_TYPE property can have the following values:

Value	Description
TBL_LEAF_ROW	The row represents actual data, rather than a category row.
TBL_EMPTY_CATEGORY
TBL_EXPANDED_CATEGORY	Indicates that the category is expanded; UI usually displays these with the plus sign '+' next to it.
TBL_COLLAPSED_CATEGORY	Indicates that the category is collapsed; UI usually displays these with the minus sign '-' next to it.
See Also

PR_ROWID property


 PR_ROWID

[New - Windows 95]

Contains a unique identifier for a recipient in a recipient table or status table.

Details

Identifier 0x3000, property type PT_LONG; property tag 0x30000003

Comments

PR_ROWID is an ephemeral value that is valid for the life of the object that owns the table. It appears as a column of the table but is not stored.

See Also

IMessage::GetRecipientTable method, IMessage::ModifyRecipients method


 PR_RTF_COMPRESSED

[New - Windows 95]

Contains the compressed rich text version of the body of the message.

Details

Identifier 0x1009, property type PT_BINARY; property tag 0x10090102

Comments

Contains the same content as PR_BODY, in compressed RTF format. To obtain the contents of the property, call OpenProperty, then call WrapCompressedRTFStream with the setting MAPI_READ.

Note that when opening PR_COMPRESSED_RTF for writing, it is always opened with the MAPI_MODIFY and MAPI_CREATE flags. This ensures that the new data completely replaces any old data and that the stream writes are performed using the minimum number of store updates.

See Also

WrapCompressedRTFStream function


 PR_RTF_IN_SYNC

[New - Windows 95]

Indicates whether PR_RTF_COMPRESSED contains the same content as the message body PR_BODY.

Details

Identifier 0x0E1F, property type PT_BOOLEAN; property tag 0x0E1F000B

Comments

Set the value to FALSE to force synchronization. RTF-aware message stores should perform the synchronization during a SaveChanges call.

See Also

PR_RTF_COMPRESSED property


 PR_RTF_SYNC_BODY_COUNT

[New - Windows 95]

Contains a count of the significant characters of the message body.

Details

Identifier 0x1007, property type PT_LONG; property tag 0x10070003

Comments

The RTFSync routine computes the count of characters in the body using only those that it considers to be significant to the message. For example, some white space and other ignorable characters are omitted from the count.

This property is an RTF auxiliary property. The RTF auxiliary properties are used by the RTFSync function and are not intended to be used directly by client applications.

See Also

PR_RTF_SYNC_BODY_CRC property


 PR_RTF_SYNC_BODY_CRC

[New - Windows 95]

Contains the cyclical redundancy check (CRC) computed for the body text.

Details

Identifier 0x1006, property type PT_LONG; property tag 0x10060003

Comments

The RTFSync routine computes the CRC using only the characters that it considers to be significant to the message. For example, some white space and other ignorable unimportant characters are omitted from the CRC.

This property is an RTF auxiliary property. The RTF auxiliary properties are used by the RTFSync function and are not intended to be used directly by client applications.

See Also

PR_RTF_COMPRESSED property


 PR_RTF_SYNC_BODY_TAG

[New - Windows 95]

Contains significant characters that appear at the beginning of the message body.

Details

Identifier 0x1008, property type PT_TSTRING; property tag 0x1008001E

Comments

The RTFSync routine uses the body tag to indicate the beginning of the body of the message. When the body is modified, the tag is used to find the beginning of the previous body.

This property is an RTF auxiliary property. The RTF auxiliary properties are used by the RTFSync function and are not intended to be used directly by client applications.

See Also

PR_SEND_RICH_INFO property


 PR_RTF_SYNC_PREFIX_COUNT

[New - Windows 95]

Contains the count of the number of ignorable characters that appear before the significant characters.

Details

Identifier 0x1010, property type PT_LONG; property tag 0x10100003

Comments

The count of prefix characters does not include white space.

This property is an RTF auxiliary property. The RTF auxiliary properties are used by the RTFSync function and are not intended to be used directly by client applications.

See Also

PR_SEND_RICH_INFO property


 PR_RTF_SYNC_TRAILING_COUNT

[New - Windows 95]

Contains a count of the ignorable characters that appear after the significant characters of the message.

Details

Identifier 0x1011, property type PT_LONG; property tag 0x10110003

Comments

This property is an RTF auxiliary property. The RTF auxiliary properties are used by the RTFSync function and are not intended to be used directly by client applications.

See Also

PR_SEND_RICH_INFO property


 PR_SEARCH

[New - Windows 95]

Contains an IMAPIContainer object that is used to conduct advanced searches.

Details

Identifier 0x3607, property type PT_OBJECT; property tag 0x3607000D

Comments

If your container does not support advanced search capabilities, you do not have to supply this property.

See Also

IMAPIContainer : IMAPIProp interface


 PR_SEARCH_KEY

[New - Windows 95]

Contains a binary-comparable key that uniquely identifies an object for searches.

Details

Identifier 0x300B, property type PT_BINARY; property tag 0x300B0102

Comments

Message and distribution list objects must furnish this property.

MAPI uses specific rules for constructing search keys for message recipients. The search key is formed by combining the address type (in upper case characters), the colon character ':', the email address in canonical form, and the terminating null character. The canonical form means that case-sensitive addresses appear in the correct case; addresses that are not case-sensitive are converted to uppercase.

For X.400 and EDI environments, this property represents the corresponding submission envelope per-message attributes as defined by the X.400 and EDI message-handling standards. For X.400 environments, this property corresponds to the IM_THIS_IPMS attribute. EDI environments use PR_SEARCH_KEY for messages delivered to client applications.

See Also

PR_RESPONSIBILITY property, PR_STORE_RECORD_KEY property


 PR_SECURITY

[New - Windows 95]

Contains a value that indicates the security level of a message. The underlying messaging system chooses whether to use this value.

Details

Identifier 0x0034, property type PT_LONG; property tag 0x00340003

Comments

The message class can determine whether the underlying messaging system honors the security settings.

The following flags can be set:

Value	Description
SECURITY_SIGNED
SECURITY_ENCRYPTED
See Also

PR_MESSAGE_CLASS property


 PR_SELECTABLE

[New - Windows 95]

Contains TRUE if the entry in the template table or one-off table can be selected, and contains FALSE otherwise.

Details

Identifier 0x3609, property type PT_BOOLEAN; property tag 0x3609000B

Comments

Applies only to the template table or the one-off table. This does not apply to the address book hierarchy table.

This property is used primarily for formatting. For example, you might want to group X.400 templates or all gateway templates in the table by creating an entry that indicates the heading for the group. Setting the PR_SELECTABLE property to FALSE for the heading ensures that the user cannot select this heading entry, and that the user can select only the actual templates.

See Also

PR_FOLDER_TYPE property


 PR_SEND_RICH_INFO

[New - Windows 95]

Indicates whether the recipient can receive all message content, including rich text and OLE objects.

Details

Identifier 0x3A40, property type PT_BOOLEAN; property tag 0x3A40000B

Comments

This property indicates whether the recipient is MAPI-enabled.

When TRUE, the transport or gateway can transmit the full content of the message, including rich text and OLE objects. The transport or gateway should use TNEF.

When FALSE, the transport or gateway is free to discard message content that the native clients of that transport cannot use. For example, when the clients cannot use rich text, the transport may choose to send only plain text.

When the property is not defined, default behavior is determined by the implementation of the transport, MTA, or gateway. Address book providers are not required to support this property. For example, a tighly coupled address book and transport can choose to send TNEF and never use rich text.

By default, MAPI sets the value of this property to TRUE. To set PR_SEND_RICH_INFO to FALSE at the time you call IAddrBook::CreateOneOff or IMAPISupport::CreateOneOff, set the MAPI_SEND_NO_RICH_INFO bit in the ulFlags parameter. One-offs created by UI use the value specified by the creating template.

On calls to IAddrBook::ResolveName when the name is unresolved and can be interpreted as an Internet address, PR_SEND_RICH_INFO is set to FALSE. The display name of the unresolved entry must be in the format x@y.z, such as "pete@pinecone.com".

See Also

IAddrBook::CreateOneOff method, IMAPISupport::CreateOneOff method, PR_ATTACH_DATA_OBJ property, PR_RTF_COMPRESSED property


 PR_SENDER_ADDRTYPE

[New - Windows 95]

Contains a message sender's address type set by the transport provider handling a message.

Details

Identifier 0x0C1E, property type PT_TSTRING; property tag 0x0C1E001E

Comments

This property represents one of several maintained for the sender. Opening the entryid to find additional information is a relatively expensive operation, so properties representing the commonly-used display name, search key, address type, and email address are defined along with the entryid.

When handling a message with sender delegate access, the transport provider must use both the PR_SENDER_* and PR_SENT_REPRESENTING_* properties.

Clients should not set these properties in messages that they send. The transport provider can choose to make sure that the properties exist and can choose to set these properties to the values for the current messaging user. If these properties are not set, MAPI may determine that it cannot send the message.

See Also

PR_ADDRTYPE property, PR_SENT_REPRESENTING_ADDRTYPE property


 PR_SENDER_EMAIL_ADDRESS

[New - Windows 95]

Contains a message sender's email address set by the transport provider handling a message.

Details

Identifier 0x0C1F, property type PT_TSTRING; property tag 0x0C1F001E

Comments

This property represents one of several maintained for the sender. Opening the entryid to find additional information is a relatively expensive operation, so properties representing the commonly-used display name, search key, address type, and email address are defined along with the entryid.

When handling a message with sender delegate access, the transport provider must use both the PR_SENDER_* and PR_SENT_REPRESENTING_* properties.

Clients should not set these properties in messages that they send. The transport provider can choose to make sure that the properties exist and can choose to set these properties to the values for the current messaging user. If these properties are not set, MAPI may determine that it cannot send the message.

See Also

PR_EMAIL_ADDRESS property, PR_SENT_REPRESENTING_EMAIL_ADDRESS property


 PR_SENDER_ENTRYID

[New - Windows 95]

Contains a message sender's entry identifier set by the transport provider handling a message.

Details

Identifier 0x0C19, property type PT_BINARY; property tag 0x0C190102

Comments

This property represents one of several maintained for the sender. Opening the entryid to find additional information is a relatively expensive operation, so properties representing the commonly-used display name, search key, address type, and email address are defined along with the entryid.

When handling a message with sender delegate access, the transport provider must use both the PR_SENDER_* and PR_SENT_REPRESENTING_* properties.

Clients can read these properties in a receive message, but should not set these properties in messages that they send. The transport provider can choose to make sure that the properties exist and can choose to set these properties to the values for the current messaging user. If these properties are not set, MAPI may determine that it cannot send the message.

Transports should ignore any present settings and set the current one. MAPI should use the current values. If they do not exist, MAPI should use default values.

For X.400 environments, PR_SENDER_ENTRYID corresponds to the IM_ORIGINATOR attribute, or is used to generate the IM_FREE_FORM_NAME attribute, depending on the object, as defined by the X.400 message-handling standard.

See Also

PR_SENDER_NAME property, PR_SENDER_SEARCH_KEY property, PR_SENT_REPRESENTING_ENTRYID property, PR_SENT_REPRESENTING_NAME property


 PR_SENDER_NAME

[New - Windows 95]

Contains a message sender's display name set by the transport provider handling a message.

Details

Identifier 0x0C1A, property type PT_TSTRING; property tag 0x0C1A001E

Comments

This property represents one of several maintained for the sender. Opening the entryid to find additional information is a relatively expensive operation, so properties representing the commonly-used display name, search key, address type, and email address are defined along with the entryid.

Clients should not set these properties in messages that they send. The transport provider can choose to make sure that the properties exist and can choose to set these properties to the values for the current messaging user. If these properties are not set, MAPI may determine that it cannot send the message.

When handling a message with sender delegate access, the transport provider must use both the PR_SENDER_* and PR_SENT_REPRESENTING_* properties.

For X.400 environments, PR_SENDER_NAME corresponds to the IM_FREE_FORM_NAME and MH_T_ORIGINATOR_NAME attributes as defined by the X.400 message-handling standard.

See Also

PR_SENDER_ENTRYID property, PR_SENDER_SEARCH_KEY property, PR_SENT_REPRESENTING_ENTRYID property, PR_SENT_REPRESENTING_NAME property


 PR_SENDER_SEARCH_KEY

[New - Windows 95]

Contains the message sender's search key set by the transport provider handling a message.

Details

Identifier 0x0C1D, property type PT_BINARY; property tag 0x0C1D0102

Comments

This property represents one of several maintained for the sender. Opening the entryid to find additional information is a relatively expensive operation, so properties representing the commonly-used display name, search key, address type, and email address are defined along with the entryid.

Clients should not set these properties in messages that they send. The transport provider can choose to make sure that the properties exist and can choose to set these properties to the values for the current messaging user. If these properties are not set, MAPI may determine that it cannot send the message.

When handling a message with sender delegate access, the transport provider must use both the PR_SENDER_* and PR_SENT_REPRESENTING_* properties.

See Also

PR_SENDER_ENTRYID property, PR_SENDER_NAME property, PR_SENT_REPRESENTING_SEARCH_KEY property


 PR_SENSITIVITY

[New - Windows 95]

Contains a value indicating a message sender's opinion about the sensitivity of a message.

Details

Identifier 0x0036, property type PT_LONG; property tag 0x00360003

Comments

This MAPI property represents the submission envelope per-message IM_SENSITIVITY attribute as defined by the X.400 message-handling standard.

X.400 transport providers use this property for messages delivered to client applications.

The PR_SENSITIVITY property can have the following values:

Value	Description
SENSITIVITY_NONE	The message has no sensitivity.
SENSITIVITY_PERSONAL	The message is personal.
SENSITIVITY_PRIVATE	The message is private.
SENSITIVITY_COMPANY_CONFIDENTIAL	The message is designated Company Confidential.
See Also

PR_IMPORTANCE property


 PR_SENT_REPRESENTING_ADDRTYPE

[New - Windows 95]

Contains the address type for the messaging user represented by the sender.

Details

Identifier 0x0068, property type PT_TSTRING; property tag 0x0068001E

Comments

When user B sends mail for user A, the PR_SENDER_* properties are set to user B and the PR_SENT_REPRESENTING_* properties are set to user A.

This property represents one of several maintained for the messaging user that delegates the send operation to another user. Opening the entry id to find additional information is a relatively expensive operation, so properties representing the commonly-used display name, search key, address type, and email address are defined along with the entryid.

When this property is not set, PR_SENDER_ADDRTYPE is used.

See Also

PR_RCVD_REPRESENTING_ADDRTYPE property, PR_SENDER_ADDRTYPE property


 PR_SENT_REPRESENTING_EMAIL_ADDRESS

[New - Windows 95]

Contains the email address for the messaging user represented by the sender.

Details

Identifier 0x0069, property type PT_TSTRING; property tag 0x0069001E

Comments

When user B sends mail for user A, the PR_SENDER_* properties are set to user B and the PR_SENT_REPRESENTING_* properties are set to user A.

This property represents one of several maintained for the messaging user that delegates the send operation to another user. Opening the entry id to find additional information is a relatively expensive operation, so properties representing the commonly-used display name, search key, address type, and email address are defined along with the entryid.

When this property is not set, PR_SENDER_EMAIL_ADDRESS is used.

See Also

PR_RCVD_REPRESENTING_EMAIL_ADDRESS property, PR_SENDER_EMAIL_ADDRESS property


 PR_SENT_REPRESENTING_ENTRYID

[New - Windows 95]

Contains the entry identifier for the messaging user represented by the sender.

Details

Identifier 0x0041, property type PT_BINARY; property tag 0x00410102

Comments

When user B sends mail for user A, the PR_SENDER_* properties are set to user B and the PR_SENT_REPRESENTING_* properties are set to user A.

This property represents one of several maintained for the messaging user that delegates the send operation to another user. Opening the entry id to find additional information is a relatively expensive operation, so properties representing the commonly-used display name, search key, address type, and email address are defined along with the entryid.

When this property is not set, the PR_SENDER_ENTRYID property is used.

To generate a reply message, a client application should copy PR_RCVD_REPRESENTING_ENTRYID from the received message into the PR_SENT_REPRESENTING_ENTRYID property of the reply.

See Also

PR_RCVD_REPRESENTING_ENTRYID property, PR_SENDER_ENTRYID property


 PR_SENT_REPRESENTING_NAME

[New - Windows 95]

Contains the display name for the messaging user represented by the sender.

Details

Identifier 0x0042, property type PT_TSTRING; property tag 0x0042001E

Comments

When user B sends mail for user A, the PR_SENDER_* properties are set to user B and the PR_SENT_REPRESENTING_* properties are set to user A.

This property represents one of several maintained for the messaging user that delegates the send operation to another user. Opening the entry id to find additional information is a relatively expensive operation, so properties representing the commonly-used display name, search key, address type, and email address are defined along with the entryid.

When this property is not set, PR_SENDER_NAME is used.

To generate a reply message, a client application should copy PR_RCVD_REPRESENTING_NAME from the received message into the PR_SENT_REPRESENTING_NAME property of the reply

See Also

PR_RCVD_REPRESENTING_NAME property, PR_SENDER_NAME property, PR_SENT_REPRESENTING_ENTRYID property


 PR_SENT_REPRESENTING_SEARCH_KEY

[New - Windows 95]

Contains the search key for the messaging user represented by the sender.

Details

Identifier 0x003B, property type PT_BINARY; property tag 0x003B0102

Comments

When user B sends mail for user A, the PR_SENDER_* properties are set to user B and the PR_SENT_REPRESENTING_* properties are set to user A.

This property represents one of several maintained for the messaging user that delegates the send operation to another user. Opening the entry id to find additional information is a relatively expensive operation, so properties representing the commonly-used display name, search key, address type, and email address are defined along with the entryid.

When this property is not set, the value of PR_SENDER_SEARCH_KEY is used.

See Also

PR_SENDER_SEARCH_KEY property, PR_SENT_REPRESENTING_ENTRYID property, PR_SENT_REPRESENTING_NAME property


 PR_SENTMAIL_ENTRYID

[New - Windows 95]

Contains the entry identifier of the sent-mail folder where the message should be moved after submission.

Details

Identifier 0x0E0A, property type PT_BINARY; property tag 0x0E0A0102

Comments

Entryid values are also maintained for other important folders, including the wastebasket and out basket.

See Also

PR_IPM_SENTMAIL_ENTRYID property, PR_IPM_WASTEBASKET_ENTRYID property


 PR_SERVICE_DELETE_FILES

[New - Windows 95]

Contains a list of names of files that are to be deleted when the messaging service is uninstalled.

Details

Identifier 0x3D10, property type PT_MV_TSTRING; property tag 0x3D10101E

Comments

Note that these files in the list are deleted from the workstation when using the control panel to uninstall the service. Take care not to include in the list any DLL that supports multiple services, or you may also remove other services.

See Also

PR_SERVICE_SUPPORT_FILES property


 PR_SERVICE_DLL_NAME

[New - Windows 95]

Contains the filename of the DLL containing the messaging service provider entry point function to call for configuration.

Details

Identifier 0x3D0A, property type PT_TSTRING; property tag 0x3D0A001E

Comments

When the entry point function name appears in the property PR_SERVICE_ENTRY_NAME, it indicates that the entry point exists.

MAPI uses a DLL file naming convention, where the base file name contains up to six characters that uniquely identify the DLL. MAPI appends the string "32" to the base DLL name to identify the version that runs on 32-bit platforms. For example, when the name "MAPI.DLL" is specified, MAPI constructs the name "MAPI32.DLL" to represent the corresponding 32-bit version of the DLL.

Including the string "32" as part of the PR_SERVICE_DLL_NAME property results in an error.

See Also

PR_PROVIDER_DLL_NAME property, PR_SERVICE_ENTRY_NAME property


 PR_SERVICE_ENTRY_NAME

[New - Windows 95]

Contains the name of the entry point function for configuration of a messaging service.

Details

Identifier 0x3D0B, property type PT_STRING8; property tag 0x3D0B001E

Comments

Service implementors are strongly recommended to provide a service entry point, but the entry point is not required. You should only supply the entry point if the related configuration properties exist. If these properties do not exist, MAPI assumes that no entry point is provided.

The DLL in which the entry point function appears is named by the property PR_SERVICE_DLL_NAME.

See Also

PR_SERVICE_DLL_NAME property


 PR_SERVICE_EXTRA_UIDS

[New - Windows 95]

Contains a list of MAPI unique identifiers (UIDs) that identify additional profile sections for the messaging service.

Details

Identifier 0x3D0D, property type PT_BINARY; property tag 0x3D0D0102

Comments

New profile sections can be created for each message filter. When the information about the message service is to be copied to another profile, it is important to copy the additional profile sections for the filters as well. A provider that uses additional profile sections can store the UIDs of those profile sections in PR_SERVICE_EXTRA_UIDS, allowing MAPI to copy the additional service information.

See Also

PR_SERVICE_NAME property


 PR_SERVICE_NAME

[New - Windows 95]

Contains the name of a messaging service as set by the user in the MAPISVC.INF file.

Details

Identifier 0x3D09, property type PT_TSTRING; property tag 0x3D09001E

Comments

The name is specific to the messaging service. PR_SERVICE_NAME appears as a column in the service table and can be used to filter services. Because it is used for identify and filter services, the value should not be localized.

See Also

PR_SERVICE_SUPPORT_FILES property


 PR_SERVICE_SUPPORT_FILES

[New - Windows 95]

Contains a list of the files that belong to the messaging service.

Details

Identifier 0x3D0F, property type PT_MV_TSTRING; property tag 0x3D0F101E

Comments

Using a dialog box in the control panel applet, the user can obtain the list of files that belong to the messaging service. For example, the user can obtain the names of all DLLs that belong to the service. The user can then seek additional details about the specified files, such as the names and version numbers of all the DLLs. MAPI uses this property to create a support file list in a dialog box for messaging user selection.

See Also

PR_SERVICE_UID property


 PR_SERVICE_UID

[New - Windows 95]

Contains the MAPI unique identifier (UID) for the messaging service.

Details

Identifier 0x3D0C, property type PT_BINARY; property tag 0x3D0C0102

Comments

PR_SERVICE_UID appears as a column in the provider table, where it is commonly used to group all the providers that belong to the same service. It is supplied as a parameter to most of the IMsgServiceAdmin methods.

See Also

IMsgServiceAdmin::IUnknown method


 PR_SERVICES

[New - Windows 95]

Reserved for use by MAPI.

Details

Identifier 0x3D0E, property type PT_BINARY; property tag 0x3D0E0102

Comments

This property should not be used. Reserved for use by MAPI. See Also

MAPIUID structure


 PR_SPOOLER_STATUS

[New - Windows 95]

Contains the status of the message based on information available to the spooler.

Details

Identifier 0x0E10, property type PT_LONG; property tag 0x0E100003

Comments

The property appears on inbound messages only and is reserved in all other cases. It indicates whether or not a message has been delivered to its final location or whether a hook potentially deleted the message while rerouting it.

You can call IMAPIProp::GetProps on PR_SPOOLER_STATUS to determine the message status. The value S_OK indicates that the message was successfully delivered to the store. The value MAPI_E_OBJECT_DELETED indicates that the message was deleted and was never committed to the store.

Message store providers should support this property on messages, recipient tables, and the outqoing queue table. You should be able to set columns on the outgoing queue table and restrict based on this property.

See Also

PR_TRANSPORT_STATUS property


 PR_START_DATE

[New - Windows 95]

Contains the starting date and time of the appointment.

Details

Identifier 0x0060, property type PT_SYSTIME; property tag 0x00600040

Comments

PR_START_DATE and PR_END_DATE are usually used by scheduling applications.

See Also

PR_END_DATE property


 PR_STATE_OR_PROVINCE

[New - Windows 95]

Contains the messaging user's state or province.

Details

Identifier 0x3A28, property type PT_TSTRING; property tag 0x3A28001E

Comments

Several properties supply information about the messaging user's telephone numbers and fields of the address.

See Also

PR_COUNTRY property


 PR_STATUS

[New - Windows 95]

Contains a 32-bit bitmask of flags defining folder status.

Details

Identifier 0x360b, property type PT_LONG; property tag 0x360B0003

Comments

PR_STATUS provides status about the folder, just as PR_MSG_STATUS provides status information about a message. These flags are provided for the client's information only and do not affect the store. Other clients can choose to use or ignore these settings. The client can also choose to define its own values for the client-definable bits of the PR_STATUS property. PR_STATUS appears in both the folder and the hierarchy table row.

See Also

PR_MSG_STATUS property


 PR_STATUS_CODE

[New - Windows 95]

Contains a bitmask of flags indicating the current status of a service provider.

Details

Identifier 0x3E04, property type PT_LONG; property tag 0x3E040003

Comments

The status code is a required property that must appear in the status table, the profile, and in the MAPISVC.INF file for all providers.

The following enumerated settings are defined for the PR_STATUS_CODE bitmask:

Value	Description
STATUS_AVAILABLE	Indicates the message service is available for use by MAPI and client applications.
STATUS_FAILURE	Indicates the service provider is experiencing severe, unexpected problems and that the provider session may soon end if the problems do not clear up.
STATUS_INBOUND_ACTIVE	Indicates the transport provider is receiving an inbound message.
STATUS_INBOUND_ENABLED	Indicates the transport provider is enabled to receive inbound messages.
STATUS_INBOUND_FLUSH	Indicates the transport provider is flushing its inbound message queue.
STATUS_OFFLINE	Indicates the services available from the service provider are limited to those that use locally available data.
STATUS_OUTBOUND_ACTIVE	Indicates the transport provider is receiving an outbound message.
STATUS_OUTBOUND_ENABLED	Indicates the transport provider is enabled to handle outbound messages.
STATUS_OUTBOUND_FLUSH	Indicates the transport provider is flushing its outbound message queue.
STATUS_REMOTE_ACCESS	Indicates whether the transport provider supports remotely access.
See Also

PR_STATUS_STRING property


 PR_STATUS_STRING

[New - Windows 95]

Contains an ASCII message indicating the current status of a service provider, for example, whether or not it is processing a message.

Details

Identifier 0x3E08, property type PT_TSTRING; property tag 0x3E08001E

Comments

This property gives providers the opportunity to supply specific information about the provider status. PR_STATUS_STRING is optional, based on the value of PR_STATUS_CODE. When the transport does not supply a value, the MAPI spooler supplies a default value.

The string is generated on the same side of the remote procedure call as the spooler; it travels through shared memory rather than being marshalled across a process boundary.

See Also

PR_STATUS_CODE property


 PR_STORE_ENTRYID

[New - Windows 95]

Contains the unique entry identifier of the message store in which an object resides.

Details

Identifier 0x0FFB, property type PT_BINARY; property tag 0x0FFB0102

Comments

PR_STORE_ENTRYID is used to open a message store with OpenMessageStore. It is also used to open any object owned by the store.

Message store, folder, and message objects must furnish this property.

For a message store, this property is identical to the store's own PR_ENTRYID property. Your application can compare the two properties using IMAPISession::CompareEntryIDs.

See Also

PR_ENTRYID property


 PR_STORE_PROVIDERS

[New - Windows 95]

Reserved for use by MAPI.

Details

Identifier 0x3D00, property type PT_BINARY; property tag 0x3D000102

Comments

This property should not be used.See Also

MAPIUID structure


 PR_STORE_RECORD_KEY

[New - Windows 95]

Contains the unique binary-comparable identifier (record key) of the message store in which an object resides.

Details

Identifier 0x0FFA, property type PT_BINARY; property tag 0x0FFA0102

Comments

Message store, folder, and message objects must furnish this property.

For a message store, this property is identical to the store's own PR_RECORD_KEY property.

The relationship between PR_STORE_RECORD_KEY and PR_RECORD_KEY is the same as the relationship between PR_STORE_ENTRYID and PR_ENTRYID.

See Also

PR_RECORD_KEY property, PR_STORE_ENTRYID property


 PR_STORE_STATE

[New - Windows 95]

Contains a flag that describes the state of the store.

Details

Identifier 0x340E, property type PT_LONG; property tag 0x340E0003

Comments

Note that PR_STORE_STATE is dynamic and can change based on user actions, unlike PR_STORE_SUPPORT_MASK.

The following value can be set:

Value	Description
STORE_HAS_SEARCHES	The user has created one or more active searches in the store.
See Also

PR_STORE_ENTRYID property, PR_STORE_SUPPORT_MASK property


 PR_STORE_SUPPORT_MASK

[New - Windows 95]

Contains a bitmask of flags that client applications should query to determine the characteristics of a message store.

Details

Identifier 0x3A0D, property type PT_LONG, Property tag:0x3A0D0003

Comments

The following flags can be set for the PR_STORE_SUPPORT_MASK bitmask:

Value	Description
STORE_ATTACH_OK	Indicates the message store supports attachments (OLE or non-OLE) to messages.
STORE_CATEGORIZE_OK	Indicates the message store supports categorized views of tables.
STORE_CREATE_OK	Indicates the message store supports creation of new messages.
STORE_ENTRYID_UNIQUE	Indicates entry identifiers for the objects in the message store are unique (that is, never reused during the life of the store).
STORE_MODIFY_OK	Indicates the message store supports modification of its existing messages.
STORE_MV_PROPS_OK	Indicates the message store supports multivalued properties, guarantees the stability of value order in a multivalued property throughout a save operation, and supports instantiation of multivalued properties in tables.
STORE_NOTIFY_OK	Indicates the message store supports notifications.
STORE_OLE_OK	Indicates the message store supports OLE attachments. The OLE data is accessible through an IStorage interface, such as that  available via the PR_ATTACH_DATA_OBJ property.
STORE_READONLY	Indicates all interfaces for the message store have a read-only access level.
STORE_RESTRICTION_OK	Indicates the message store supports restrictions.
STORE_RTF_OK	Indicates the message store supports rich text format (RTF) messages.
STORE_SEARCH_OK	Indicates the message store supports search-results folders, and FALSE otherwise.
STORE_SORT_OK	Indicates the message store supports sorting views of tables.
STORE_SUBMIT_OK	Indicates the message store supports marking a message for submission.
See Also

PR_ATTACH_DATA_OBJ property, PR_RTF_COMPRESSED property


 PR_STREET_ADDRESS

[New - Windows 95]

Contains the street address for the messaging user.

Details

Identifier 0x3A29, property type PT_TSTRING; property tag 0x3A29001E

Comments

Several properties are supplied for the messaging user, including several telephone numbers and fields of the messaging user's home and business mailing addresses.

See Also

PR_LOCALITY property


 PR_SUBFOLDERS

[New - Windows 95]

Contains TRUE if a folder contains subfolders, and FALSE otherwise.

Details

Identifier 0x360a, property type PT_BOOLEAN; property tag 0x360A000B

Comments

Message stores compute this property for all folders.

See Also

PR_FOLDER_TYPE property


 PR_SUBJECT

[New - Windows 95]

Contains the subject of a message.

Details

Identifier 0x0037, property type PT_TSTRING; property tag 0x0037001E

Comments

For a report, this property contains the original message's subject preceded by a string indicating what has happened to the message.

A message store uses this property to compute the PR_NORMALIZED_SUBJECT property.

For X.400 environments, PR_SUBJECT corresponds to the IM_SUBJECT property as defined by the X.400 message-handling standard.

See Also

PR_NORMALIZED_SUBJECT property


 PR_SUBJECT_IPM

[New - Windows 95]

Contains message transport system (MTS) identifiers for messages with which a delivery report or nondelivery report is concerned.

Details

Identifier 0x0038, property type PT_BINARY; property tag 0x00380102

Comments

This MAPI property represents the interpersonal notification IM_SUBJECT_IPM attribute as defined by the X.400 message-handling standard.

See Also

PR_SUBJECT property


 PR_SUBJECT_PREFIX

[New - Windows 95]

Contains a subject prefix that indicates a reply or forwarded message, such as "RE:" or "FW:". Details

Identifier 0x003d, property type PT_TSTRING; property tag 0x003D001E

Comments

The subject prefix consists of one, two, or three alphanumeric characters, and the colon character ':'. The property should not contain leading spaces. Client applications prepend the subject prefix to the subject.

See Also

PR_SUBJECT property


 PR_SUBMIT_FLAGS

[New - Windows 95]

Contains a bitmask of flags indicating details about a message submission.

Details

Identifier 0x0E14, property type PT_LONG; property tag 0x0E140003

Comments

This property is part of the outgoing message queue table.

The following flags can be set for the PR_SUBMIT_FLAGS bitmask:

Value	Description
SUBMITFLAG_LOCKED	Indicates the spooler currently has the message locked.
SUBMITFLAG_PREPROCESS	Indicates the message needs preprocessing. When the spooler is done preprocessing this message, it should call the IMessage::SubmitMessage method. The message store provider recognizes that the spooler (rather than the client application) has called SubmitMessage, clears the flag, and continues message submission.
See Also

IMessage::SubmitMessage method, IMsgStore::SetLockState method


 PR_SUPPLEMENTARY_INFO

[New - Windows 95]

Contains arbitrary additional information for use in a delivery report.

Details

Identifier 0x0C1B, property type PT_TSTRING; property tag 0x0C1B001E

Comments

For X.400 environments, this property corresponds to the IM_SUPPLEMENTARY_RECEIPT_INFO attribute.

See Also

PR_REPORT_NAME property


 PR_SURNAME

[New - Windows 95]

Contains the surname of a messaging user.

Details

Identifier 0x3A11, property type PT_TSTRING; property tag 0x3A11001E

Comments

Several properties are supplied for the messaging user's name, phone numbers, and addresses.

See Also

PR_GIVEN_NAME property


 PR_TELEX_NUMBER

[New - Windows 95]

Contains the messaging user's telex number.

Details

Identifier 0x3A2C, property type PT_TSTRING; property tag 0x3A2C001E

Comments

Several properties are supplied for the messaging user's name, phone numbers, and addresses.

See Also

PR_OFFICE_TELEPHONE_NUMBER property


 PR_TEMPLATEID

[New - Windows 95]

Contains an entry identifier that can find the code associated with the provider.

Details

Identifier 0x3902, property type PT_BINARY; property tag 0x39020102

Comments

The entryid can bind the code to the data.

See Also

IABLogon::OpenTemplateID method, IMAPISupport::OpenTemplateID method, PR_PRIMARY_CAPABILITY property


 PR_TITLE

[New - Windows 95]

Contains a messaging user's formal title, such as M.D. or Ph.D.

Details

Identifier 0x3A17, property type PT_TSTRING; property tag 0x3A17001E

Comments

Several properties are supplied for the messaging user's name, phone numbers, and addresses.

See Also

PR_SURNAME property


 PR_TRANSMITTABLE_DISPLAY_NAME

[New - Windows 95]

Contains the messaging user's display name in a secure form that can not be changed.

Details

Identifier 0x3a20, property type PT_TSTRING; property tag 0x3A20001E

Comments

PR_TRANSMITTABLE_DISPLAY_NAME should be provided by all address book providers. The property contains the version of the recipient's display name that is transmitted with the message. This property is used to prevent spoofing. For most providers this property has the same value as PR_DISPLAY_NAME. Providers that do not have a secure display name return PT_ERROR and MAPI changes the display name by adding quote marks around the name.

In previous releases of the MAPI 1.0 SDK, this property was defined using the spelling, "PR_TRANSMITABLE_DISPLAY_NAME." MAPI 1.0 supports both spellings of this property. Both versions use the same property identifier values and property types.

See Also

PR_DISPLAY_NAME property


 PR_TRANSPORT_KEY

[New - Windows 95]

Reserved for MAPI.

Details

Identifier 0x0E16, property type PT_LONG; property tag 0x0E160003

Comments

This property is reserved for MAPI.  Do not use.

See Also

PR_TRANSPORT_PROVIDERS property


 PR_TRANSPORT_MESSAGE_HEADERS

[New - Windows 95]

Contains transport-specific message envelope information.

Details

Identifier 0x007D, property type PT_TSTRING; property tag 0x007D001E

Comments

The transport provider can generate the message header information for inbound messages.

This property offers an alternative to either discarding the transport message header information, or prepending the transport message header information to the message body text. The client can choose whether or not to display the information.

See Also

PR_BODY property


 PR_TRANSPORT_PROVIDERS

[New - Windows 95]

Reserved for use by MAPI.

Details

Identifier 0x3D02, property type PT_BINARY; property tag 0x3D020102

Comments

This property should not be used. It contains a list of MAPI unique identifiers (UIDs), each identifying a transport provider.

See Also

MAPIUID structure


 PR_TRANSPORT_STATUS

[New - Windows 95]

Reserved for MAPI. Do not use.

Details

Identifier 0x0E11, property type PT_LONG; property tag 0x0E110003

Comments

Do not use this property. It is reserved for use by MAPI.

See Also

PR_SPOOLER_STATUS property


 PR_TYPE_OF_MTS_USER

[New - Windows 95]

Contains the type of a message recipient, for use in a report.

Details

Identifier 0x0C1C, property type PT_LONG; property tag 0x0C1C0003

Comments

This MAPI property corresponds to the report per-recipient MH_T_DELIVERY_POINT attribute as defined by the X.400 message-handling standard.

See Also

PR_CORRELATE_MTSID property


 PR_UPDATE_PAB

[New - Windows 95]

This property is not supported in MAPI version 1.0.

Comments

The PR_UPDATE_PAB property, which was present in pre-release versions, is not supported in the MAPI 1.0 SDK.

See Also

PR_AB_DEFAULT_PAB property


 PR_USER_CERTIFICATE

[New - Windows 95]

Contains an authentication certificate for the user. An authentication certificate is similar to a digital signature.

Details

Identifier 0x3A22, property type PT_BINARY; property tag 0x3A220102

Comments

Several MAPI properties supply ASN.1 certificates.

See Also

PR_ORIGINATOR_CERTIFICATE property, PR_RECIPIENT_CERTIFICATE property


 PR_VALID_FOLDER_MASK

[New - Windows 95]

Contains a bitmask of flags set by a message store to indicate the validity of the entry identifiers of the folders in the store.

Details

Identifier 0x35DF, property type PT_LONG; property tag 0x35DF0003

Comments

The following flags can be set for the PR_VALID_FOLDER_MASK bitmask:

Value	Description
FOLDER_COMMON_VIEWS_VALID	Indicates the common views folder has a valid entry identifier (see PR_COMMON_VIEWS_ENTRYID).
FOLDER_FINDER_VALID	Indicates the finder folder has a valid entry identifier (see PR_FINDER_ENTRYID).
FOLDER_INBOX_VALID	Indicates the IPM receive folder has a valid entry identifier. (IPM_INBOX_VALID)
FOLDER_IPM_OUTBOX_VALID	Indicates the IPM outbox folder has a valid entry identifier (see PR_IPM_OUTBOX_ENTRYID).
FOLDER_IPM_SENTMAIL_VALID	Indicates the IPM sent-mail folder has a valid entry identifier (see PR_IPM_SENTMAIL_ENTRYID).
FOLDER_IPM_SUBTREE_VALID	Indicates the interpersonal messaging (IPM) folder subtree has a valid entry identifier (see PR_IPM_SUBTREE_ENTRYID).
FOLDER_IPM_WASTEBASKET_VALID	Indicates the IPM wastebasket folder has a valid entry identifier (see PR_IPM_WASTEBASKET_ENTRYID).
FOLDER_VIEWS_ENTRYID	Indicates the views folder has a valid entry identifier.
See Also

PR_FOLDER_TYPE property


 PR_VIEWS_ENTRYID

[New - Windows 95]

Contains the entry identifier of the user-defined views folder.

Details

Identifier 0x35E5, property type PT_BINARY; property tag 0x35E50102

Comments

The Common Views folder contains a predefined set of views, while the Views folder is defined by the messaging user.

See Also

PR_COMMON_VIEWS_ENTRYID property


 PR_X400_CONTENT_TYPE

[New - Windows 95]

Contains the content type for a submitted message.

Details

Identifier 0x003C, property type PT_BINARY; property tag 0x003C0102

Comments

For X.400 environments, this MAPI property corresponds to the MH_T_CONTENT_TYPE attribute.

See Also

PR_X400_DEFERRED_DELIVERY_CANCEL property


 PR_X400_DEFERRED_DELIVERY_CANCEL

[New - Windows 95]

Contains TRUE if the message transport system (MTS) allows X.400 deferred delivery cancellation, and FALSE otherwise.

Details

Identifier 0x3E09, property type PT_BOOLEAN; property tag 0x3E09000B

Comments

A comprehensive list of MAPI properties and their mappings to X.400 appears in the MAPI Programmer's Guide.

See Also

PR_X400_CONTENT_TYPE property


 PR_XPOS

[New - Windows 95]

Contains the X coordinate of the starting position (the upper left corner) of the control, in standard Windows dialog units.

Details

Identifier 0x3F05, property type PT_LONG; property tag 0x3F050003

Comments

The PR_XPOS, PR_YPOS, PR_DELTAX, and PR_DELTAY properties position and size the control.

See Also

PR_DELTAX property, PR_DELTAY property, PR_YPOS property


 PR_YPOS

[New - Windows 95]

Contains the location of the Y coordinate of the starting position (the upper left corner) of a control, in standard Windows dialog units.

Details

Identifier 0x3F06, property type PT_LONG; property tag 0x3F060003

Comments

The PR_XPOS, PR_YPOS, PR_DELTAX, and PR_DELTAY properties position and size the control.

See Also

PR_DELTAX property, PR_DELTAY property, PR_XPOS property


  Extended MAPI Structures and Simple Data Types

This chapter contains a reference entry for each structure and data type.


  Structures

This section contains a reference entry for each structure.


  ADRENTRY

An ADRENTRY structure holds all properties related to one recipient of a message,  for example, the recipient's display name.

Syntax

typedef struct _ADRENTRY

{

ULONG ulReserved1;

ULONG cValues;

LPSPropValue rgPropVals;

} ADRENTRY, FAR *LPADRENTRY;

Members

ulReserved1

Reserved; must be zero.

cValues

Number of elements in the array pointed to by the rgPropVals member.

rgPropVals

Pointer to an array of SPropValue structures containing values for the properties of the message recipient.

Comments

Each message recipient has a collection of properties contained in an ADRENTRY structure. Among other properties, this structure contains:

•	The display name

•	The messaging system type

•	The messaging system address

•	The entry identifier

ADRENTRY structures typically exist as components of ADRLIST structures. These structures are used to represent message recipients and recipient lists, respectively.

Each instance of an ADRENTRY rgPropVals member in an ADRLIST structure must be allocated separately, using MAPIAllocateBuffer, from the ADRLIST structure. This insures the validity of any pointers to recipients when the ADRLIST structure containing them is reallocated or resized.

The rgPropVals members must be deallocated prior to deallocation of the containing ADRLIST structure so that pointers to allocated SPropValue structures are not lost.

The structure member types and allocation rules for the ADRENTRY structures and SRow structures are identical.

For more information on ADRENTRY allocation and deallocation issues, see the entries for IMessage::ModifyRecipients and IAddrBook::Address.

See Also

IAddrBook::Address method, IMessage::ModifyRecipients method, MAPIAllocateBuffer function, SRow structure


  ADRLIST

An ADRLIST structure holds one ADRENTRY structure for each recipient of a particular message. Therefore, an ADRLIST structure contains all the property information for an address list.

Syntax

typedef struct _ADRLIST

{

ULONG cEntries;

ADRENTRY aEntries[MAPI_DIM];

} ADRLIST, FAR *LPADRLIST;

Members

cEntries

Number of entries in the array specified by the aEntries member.

aEntries

Array of ADRENTRY structures, each typically describing a message recipient.

Comments

An ADRLIST structure has the same form as an SRowSet structure. It can contain both unresolved and resolved entries; an unresolved entry is one that consists only of a message recipient name, whereas a resolved entry contains additional information about the recipient, including an e-mail address type and an entry identifier. Commonly, client applications that enable users to type recipient names create unresolved entries.

If your application deals with a message recipient list that is too large to fit in memory, you can use an ADRLIST structure along with the IMessage::ModifyRecipients method to work with a subset of the list. Your application should not use the address-book common dialog boxes for the user interface in such a situation.

For information about allocation rules for ADRLIST structures, see the entry for ADRENTRY earlier in this chapter.

Use the CbADRLIST macro to return the number of bytes of memory occupied by an existing ADRLIST structure. The syntax for this macro is:

int CbADRLIST (LPADRLIST _lpadrlist)

The _lpadrlist parameter points to an ADRLIST structure. This macro returns the number of bytes occupied by the ADRLIST structure pointed to by _lpadrlist.

Use the CbNewADRLIST macro to determine the memory allocation requirements of an ADRLIST structure containing a specified number of ADRENTRY structures (recipients). The syntax is:

int CbNewADRLIST (int _centries)

The parameter _centries specifies the number of recipients. This macro returns the number of bytes of memory that an ADRLIST structure with _centries recipients would occupy.

Use the SizedADRLIST macro to define a structure with the specified name that contains the specified number of ADRENTRY structures. The syntax is:

SizedADRLIST (int _centries, _name)

The parameter _centries specifies the number of ADRENTRY structures. The structure type is defined with the tag _ADRLIST_ _name and type name _name.

SizedADRLIST provides a means of defining a recipient list with explicit bounds when array length requirements are known.

To use a sized recipient list pointer lpSizedADRList in any function call or structure that expects a LPADRLIST pointer, perform the following cast:

lpADRList = (LPADRLIST) SizedADRList(.

The ADRLIST structure is defined in MAPIDEFS.H.

See Also

ADRENTRY structure, CbNewADRLIST macro , IMessage::ModifyRecipients method, SRowSet structure


  ADRPARM

An ADRPARM structure holds data used for controlling the display and behavior of an address-book common dialog box. This structure is used with the IAddrBook::Address and IMAPISupport::Address methods.

Syntax

typedef struct _ADRPARM

{

ULONG cbABContEntryID;

LPENTRYID lpABContEntryID;

ULONG ulFlags;

LPVOID lpreserved;

ULONG ulHelpContext;

LPTSTR lpszHelpFileName;

LPFNABSDI lpfnABSDI;

LPFNDISMISS lpfnDismiss;

LPVOID lpvDismissContext;

LPTSTR lpszCaption;

LPTSTR lpszNewEntryTitle;

LPTSTR lpszDestWellsTitle;

ULONG cDestFields;

ULONG nDestFieldFocus;

LPTSTR FAR *lppszDestTitles;

ULONG FAR *lpulDestComps;

LPSRestriction lpContRestriction;

LPSRestriction lpHierRestriction;

} ADRPARM, FAR *LPADRPARM;

Members

cbABContEntryID

The list of entries that can be created into the recipient wells.

lpABContEntryID

Pointer to the ENTRYID of a container that will supply the list of one-offs that can be added to the recipient wells of this dialog box.

ulFlags

Bitmask of flags associated with various address-book dialog box options.The following flags can be set:

AB_RESOLVE

Causes all names to be resolved after the address book dialog box is closed. The Resolve Name dialog box will be displayed if there are ambiguous entries in the recipient list.

AB_SELECTONLY

Forces the user to select recipients from the supplied list of resolved names. This flag disables the creation of custom recipient addresses and direct type-in entries for a recipient list. This flag is used only if the dialog box is modal.

ADDRESS_ONE

Indicates that the user of the dialog box is allowed to pick exactly one message recipient, instead of a number of recipients from a recipient list. This flag is valid only when cDestFields is 0. This flag is used only if the dialog box is modal.

DIALOG_MODAL

Causes a modal dialog box to be displayed. Your application must set either this flag or DIALOG_SDI, but not both.

DIALOG_OPTIONS

Causes the "Send Options" button to be displayed on the dialog box. This flag is allowed only if the dialog box is modal.

DIALOG_SDI

Causes a modeless dialog box to be displayed. This call returns immediately and hence does not modify the ADRLIST structure passed in.

This flag causes the lpfnABSDI, lpfnDismiss, and lpvDismissContext members of the ADRPARM structure to be used in the call to the IAddrBook::Address method. Your application must set either this flag or DIALOG_MODAL, but not both.

lpReserved

Reserved, must be zero.

ulHelpContext

Input parameter specifying the context within the Help that will first be shown when the Help button is pressed in the address dialog box.

lpszHelpFileName

Input parameter pointing to the name of a Help file that will be associated with the address dialog box that is a result of this call. Used in conjunction with ulHelpContext to call the Windows function WinHelp.

lpfnABSDI

Output parameter that points to a MAPI function based on the ACCELERATEABSDI prototype that the client application must call in its Windows message loop for a modeless dialog box. This allows for the dialog box to have custom accelerators.

lpfnDismiss

Pointer to a client application dismiss function, a function based on the DISMISSMODELESS prototype. MAPI calls a client application dismiss function when it has dismissed a modeless address-book dialog box. The lpfnDismiss member is used only if the DIALOG_SDI flag is set in ulFlags. The value of lpfnDismiss is NULL if the DIALOG_MODAL constant is set in ulFlags.

lpvDismissContext

Pointer to context information passed in with the IAddrBook::Address call and passed back unchanged. This member contains values that are necessary for the operation of the client application dismiss function. The lpvDismissContext member is used only if the DIALOG_SDI flag is set in ulFlags.

lpszCaption

Pointer to text to be used as a caption for the address-book dialog box.

lpszNewEntryTitle

Pointer to text to be used as a new-entry prompt for an edit box in an address book dialog box.

lpszDestWellsTitle

Pointer to text to be used as a title for for the set of recipient-name edit boxes that appear in the dialog box. This member is used only if the address-book dialog box is modal.

cDestFields

Number of recipient-name edit boxes (that is, destination fields)  in the address-book dialog box. A number from 0 through 3 is typical. If the cDestFields member is zero and the ADDRESS_ONE flag is not set in ulFlags, the address book is open for browsing only.

nDestFieldFocus

Field in the address-book dialog box that should have the initial focus when the dialog box appears. This value must be between 0 and the value of cDestFields minus 1.

lppszDestTitles

Pointer to an array of text titles to be displayed in the recipient-name edit boxes of the address-book dialog box. The size of the array is the value of cDestFields. If the lppszDestTitles member is NULL, IAddrBook::Address chooses default titles.

lpulDestComps

Pointer to an array of recipient types, such as MAPI_TO, MAPI_CC, MAPI_BCC associated with each recipient-name edit box. The size of the array is the value of cDestFields. If the lpulDestComps member is NULL, the IAddrBook::Address interface chooses default recipient types.

lpContRestriction

Pointer to an SRestriction structure of restrictions that the client application sets on any address book container to be viewed. the IAddrBook::Address interface combines using the logical AND operator with any restrictions the user specifies while using the address-book dialog box.

lpHierRestriction

Pointer to an SRestriction structure of restrictions on the hierarchy table used in the address-book dialog box.

Comments

Passing in 0 for the cbABContEntryID member uses the default list of one-off templates of Recipients that can be created for a message. When we create ENTRYIDs into the recipient well MAPI calls CreateEntry.

If the address book is open for browsing only, IAddrBook::Address ignores its lppAdrList parameter. If cDestFields has the value 0xFFFFFFFF, the Address method displays the address-book dialog box in its default configuration, ignoring the lppszDestTitles and lpulDestComps members of ADRPARM.

The lpfnABSDI member must be NULL in order to display the modeless dialog box in IAddrBook::Address and IMAPISupport::Address calls. Also, the lpfnABSDI member is used only if the DIALOG_SDI flag is set in the ulFlags member. IAddrBook::Address fills in the lpfnABSDI member before returning.

Which address book container lpABContEntryID points to determines what is listed in the edit box within the dialog box that holds possible recipient names. Usually, lpABContEntryID is NULL, indicating the use of a custom recipient provider.

The ADRPARM structure is defined in MAPIDEFS.H.

See Also

ACCELERATEABSDI function prototype, DISMISSMODELESS function prototype, ENTRYID structure, IAddrBook::Address method, SRestriction structure


  ADRPARM, ACCELERATEABSDI

The ACCELERATEABSDI prototype function defines a client application callback function that MAPI must call in its Windows message loop during execution of a modeless address book dialog box for IAddrBook::Address. A function with this prototype accelerates the addition of names to the address book.

Syntax

BOOL (STDMETHODCALLTYPE ACCELERATEABSDI)(ULONG ulUIParam, LPVOID lpvmsg)

Parameters

ulUIParam

Input parameter specifying an implementation-specific 32-bit value used for passing user interface information to a function or zero. In Microsoft Windows applications, ulUIParam is the parent window handle for a dialog and is of type HWND, cast to a ULONG. A value of zero indicates there is no parent window.

lpvmsg

Input parameter specifying a pointer to a Windows message.

Return Values

A client application function with the ACCELERATEABSDI prototype returns TRUE if it handles the message.

Comments

A client application's ACCELERATEABSDI prototype-based function is used only if the application has set the DIALOG_SDI flag in the ulFlags member of the ADRPARM structure.

The ACCELERATEABSDI prototype is defined in MAPIDEFS.H.

See Also

ADRPARM structure, IAddrBook::Address method


  ADRPARM, DISMISSMODELESS

The DISMISSMODELESS prototype function represents a client application callback function that MAPI calls when it has dismissed a modeless address book dialog box. This call is necessary so that MAPI will not keep calling the application's accelerator function, ACCELERATEABSDI prototype, when the modeless dialog box is not active.

Syntax

void (STDMETHODCALLTYPE DISMISSMODELESS)(ULONG ulUIParam, LPVOID lpvContext)

Parameters

ulUIParam

Input parameter specifying an implementation-specific 32-bit value normally used for passing user interface information to a function. For example, in Microsoft Windows this parameter is the parent window handle for the dialog box and is of type HWND (cast to a ULONG). A value of zero is always valid.

lpvContext

Input parameter specifying a pointer to an arbitrary value passed to the callback function when MAPI calls it. This value can represent an address of significance to the client application. Typically, for C++ code, lpvContext represents a pointer to the address of a C++ object.

Comments

The DISMISSMODELESS prototype is defined in MAPIDEFS.H.

See Also

ACCELERATEABSDI function prototype, ADRPARM structure


  DTBLBUTTON

A DTBLBUTTON structure holds information about a button control for a display table dialog box.

Syntax

typedef struct _DTBLBUTTON

{

ULONG ulbLpszLabel;

ULONG ulFlags;

ULONG ulPRControl;

} DTBLBUTTON, FAR *LPDTBLBUTTON;

Members

ulbLpszLabel

Offset from the beginning of the structure, in bytes, to text to be displayed on the button.

ulFlags

Bitmask of flags designating the format of the text pointed to by the ulbLpszLabel member. The following flag can be set:

MAPI_UNICODE

Indicates the passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

ulPRControl

A property of type PT_OBJECT on which you can open an IMAPIControl interface using an OpenProperty call.

Comments

A DTBLBUTTON structure does not specify the character length of the label, it only contains an offset to the beginning of the label in memory allocated for the structure.

Use the SizedDtblButton macro to create a structure similar to DTBLBUTTON but contains a label of specified character length. The syntax is:

SizedDtblButton (int n, u)

The parameter n specifies the character length of the button's label. The parameter u specifies the structure type is defined with the tag _DTBLBUTTON_ u and type name u.

A DTBLBUTTON structure does not explicitly give the length of the lpszLabel string, it only provides an offset to the first character of it.

The DTBLBUTTON structure is defined in MAPIDEFS.H.

See Also

DTCTL structure, PR_CONTROL_TYPE property


  DTBLCHECKBOX

A DTBLCHECKBOX structure holds information about a check box to be used in a display table dialog box.

Syntax

typedef struct _DTBLCHECKBOX

{

ULONG ulbLpszLabel;

ULONG ulFlags;

ULONG ulPRPropertyName;

} DTBLCHECKBOX, FAR *LPDTBLCHECKBOX;

Members

ulbLpszLabel

Offset from the beginning of the structure, in bytes, to be the label of the check box.

ulFlags

Bitmask of flags designating the format of the text pointed to by the ulbLpszLabel member. The following flag can be set:

MAPI_UNICODE

Indicates the passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

ulPRPropertyName

A property of type PT_BOOLEAN whose value is maipulated by the user via a check box. GetProps is used to initalize the box. SetProps is used to manipulate this properties value as the user makes changes to the check box.

Comments

A DTBLCHECKBOX structure does not specify the character length of the label, it only contains an offset to the beginning of the label in memory allocated for the structure.

The SizedDtblCheckBox macro defines a structure similar to DTBLCHECKBOX but contains a label of specified character length. The syntax is:

SizedDtblCheckBox (int n, u)

The n parameter specifies the character length of the check box's label. The structure type is defined with the tag _DTBLCHECKBOX_ u and type name u.

SizedDtblCheckBox provides a means of defining a check box when the number of label characters is known. A DTBLCHECKBOX structure does not explicitly give the length of the lpszLabel string, it only provides an offset to the first character of it.

To use a sized display table check box pointer lpSizedDtblCheckBox in any function call or structure that expects a LPDTBLCHECKBOX pointer, perform the following cast:

lpDtblCheckBox = (LPDTBLCHECKBOX) lpSizedDtblCheckBox.

The DTBLCHECKBOX structure is defined in MAPIDEFS.H.

See Also

DTCTL structure, PR_CONTROL_TYPE property


  DTBLCOMBOBOX

A DTBLCOMBOBOX structure holds information about a combo box that is to be part of a dialog box.

Syntax

typedef struct _DTBLCOMBOBOX

{

ULONG ulbLpszCharsAllowed;

ULONG ulFlags;

ULONG ulNumCharsAllowed;

ULONG ulPRPropertyName;

ULONG ulPRTableName;

} DTBLCOMBOBOX, FAR *LPDTBLCOMBOBOX;

Members

ulbLpszCharsAllowed

Offset from the beginning of the structure, in bytes, to a string that lists the characters allowed in the combo box's edit box.

The format of the string is as follows:

*	Any character is allowed (for example, "*")

[]	Defines a set of characters for example, "[0123456789]")

-	Indicates a range of characters. Typically used like "[a-z]".

~	Indicates that these characters are not allowed. (for example, "[~0-9]")

\	Used to quote any of the above symbols. (for example, "[\-\\\[\]]" means -, \, [, and ] characters are allowed)

ulFlags

Bitmask of flags designating the format of the text pointed to by the ulbLpszCharsAllowed member. The following flag can be set:

MAPI_UNICODE

Indicates the passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

ulNumCharsAllowed

Maximum number of characters that the user can type into the combo box's edit box.

ulPRTableName

A property of type PT_OBJECT on which an IMAPITable interface can be opened using an OpenProperty call. The rows of the table are to be used as items in the list box.

ulPRPropertyName

A property name whose values uniquely identify rows in the table (typically of type PT_TSTRING) used to populate the list box. The value of this property identifies the row selected via a choice in the list box. Initially, the ulPRPropertyName member holds the value of a default selection. If the property name is PR_NULL, the list box is not a single selection type.

Comments

A DTBLCOMBOBOX structure does not specify the character length of the allowed character string, it only contains an offset to the beginning of the it in memory allocated for the structure.

Use the SizedDtblComboBox macro to define a structure similar to DTBLCOMBOBOX, but with the added explicit number of characters in the combo box's text edit,or static text, control. SizedDtblComboBox provides a means of defining a combo box when the length of the allowed character string is known. The syntax is:

SizedDtblComboBox (int n, u)

The parameter n specifies the length of the allowed characters string. The allowed character string follows the formatting rules:

*	Any character is allowed (for example, "*")

[]	Defines a set of characters for example, "[0123456789]")

-	Indicates a range of characters. Typically used like "[a-z]".

~	Indicates that these characters are not allowed. (for example, "[~0-9]")

\	Used to quote any of the above symbols. (for example, "[\-\\\[\]]" means -, \, [, and ] characters are allowed)

u

The structure type is defined with the tag _DTBLCOMBOBOX_ u and type name u.

To use a sized display table combo box pointer lpSizedDtblComboBox in any function call or structure that expects a LPDTBLCOMBOBOX pointer, perform the following cast:

lpDtblComboBox = (LPDTBLCOMBOBOX) lpSizedDtblComboBox.

The DTBLCOMBOBOX structure is defined in MAPIDEFS.H.

See Also

DTCTL structure, PR_CONTROL_TYPE property


  DTBLDDLBX

A DTBLDDLBX structure holds information about a drop-down list box to be part of a dialog box.

Syntax

typedef struct _DTBLDDLBX

{

ULONG ulFlags;

ULONG ulPRDisplayProperty;

ULONG ulPRSetProperty;

ULONG ulPRTableName;

} DTBLDDLBX, FAR *LPDTBLDDLBX;

Members

ulFlags

Reserved; must be zero.

ulPRTableName

A property of type PT_OBJECT on which an IMAPITable interface can be opened using an OpenProperty call. The rows of the table are to correspond to items in the list box.

ulPRDisplayProperty

A property name of type PT_TSTRING. The text value of this property in each row is displayed as an item in the list box.

ulPRSetProperty

A property name whose values uniquely identify rows in the table (e.g. PR_ENRTYID). The value of this property identifies the row selected via a choice in the list box. Initially, the ulPRPropertyName member holds the value of a default selection. If the property name is PR_NULL, the list box is not a single selection type.

Comments

The DTBLDDLBX structure is defined in MAPIDEFS.H.

See Also

DTCTL structure


  DTBLEDIT

A DTBLEDIT structure holds information about a edit box to be part of a dialog box.

Syntax

typedef struct _DTBLEDIT

{

ULONG ulbLpszCharsAllowed;

ULONG ulFlags;

ULONG ulNumCharsAllowed;

ULONG ulPropTag;

} DTBLEDIT, FAR *LPDTBLEDIT;

Members

ulbLpszCharsAllowed

Offset from the beginning of the structure, in bytes, to a string that lists the characters allowed in the combo box's edit box.

The format of the string is as follows:

*	Any character is allowed (for example, "*")

[]	Defines a set of characters for example, "[0123456789]")

-	Indicates a range of characters. Typically used like "[a-z]".

~	Indicates that these characters are not allowed. (for example, "[~0-9]")

\	Used to quote any of the above symbols. (for example, "[\-\\\[\]]" means -, \, [, and ] characters are allowed)

ulFlags

Bitmask of flags designating the format of the text pointed to by the ulbLpszCharsAllowed member. The following flag can be set:

MAPI_UNICODE

Indicates the passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

ulNumCharsAllowed

Maximum number of characters that the user can type into the edit box.

ulPropTag

A property name of type PT_TSTRING. The text in this property is displayed and edited in the edit box.

Comments

A DTBLEDIT structure does not specify the character length of the allowed characters string, it only contains an offset to it in memory allocated for the structure.

Use the SizedDtblEdit macro to define a structure similar to DTBLEDIT but with the added explicit number of characters contained in the allowed characters member. The syntax is:

SizedDtblEdit (int n, u)

The parameter n specifies the length of the allowed characters string. The allowed characters string follows the formatting rules:

*	Any character is allowed (for example, "*")

[]	Defines a set of characters for example, "[0123456789]")

-	Indicates a range of characters. Typically used like "[a-z]".

~	Indicates that these characters are not allowed. (for example, "[~0-9]")

\	Used to quote any of the above symbols. (for example, "[\-\\\[\]]" means -, \, [, and ] characters are allowed)

The structure type is defined with the tag _DTBLEDIT_ u and type name u.

SizedDtblEdit provides a means of defining a text edit box when the number of allowed characters is known. A DTBLEDIT structure does not explicitly give the length of the lpszCharsAllowed string, it only provides an offset to the first character of the string.

To use a sized display table edit pointer lpSizedDtblEdit in any function call or structure that expects a LPDTBLEDIT pointer, perform the following cast:

lpDtblEdit = (LPDTBLEDIT) lpSizedDtblEdit.

The DBTLEDIT stucture is defined in MAPIDEFS.H.

See Also

DTCTL structure, IMAPIProp::GetProps method, PR_CONTROL_TYPE property,


  DTBLGROUPBOX

A DTBLGROUPBOX structure holds information about a group box to be part of a dialog box.

Syntax

typedef struct _DTBLGROUPBOX

{

ULONG ulbLpszLabel;

ULONG ulFlags;

} DTBLGROUPBOX, FAR *LPDTBLGROUPBOX;

Members

ulbLpszLabel

Offset from the beginning of the structure, in bytes, to be the label of the group box.

ulFlags

Bitmask of flags designating the format of the text pointed to by the ulbLpszLabel member. The following flag can be set:

MAPI_UNICODE

Indicates the passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

Comments

A DTBLGROUPBOX structure does not specify the character length of the label, it only contains an offset to the beginning of the label in memory allocated for the structure.

Use the SizedDtblGroupBox macro to define a structure similar to DTBLGROUPBOX except that it contains a label of specified character length. The syntax is:

SizedDtblGroupBox (int n, u)

The parameter n specifies the character length of the group box's label. The structure type is defined with the tag _DTBLGROUPBOX_ u and type name u.

SizedDtblGroupBox provides a means of defining a group box when the number of label characters is known. A DTBLGROUPBOX structure does not explicitly give the length of the lpszLabel string, it only provides an offset to the first character of it.

To use a sized display table group box pointer lpSizedDtblGroupBox in any function call or structure that expects a LPDTBLGROUPBOX pointer, perform the following cast:

lpDtblGroupBox = (LPDTBLGROUPBOX) lpSizedDtblGroupBox.

The DTBLGROUPBOX structure is defined in MAPIDEFS.H.

See Also

DTCTL structure


  DTBLINKEDIT

A DTBLINKEDIT structure holds information about an ink-aware edit box to be part of a dialog box used in pen computing.

Syntax

typedef struct _DTBLINKEDIT

{

ULONG ulbLpszCharsAllowed;

ULONG ulFlags;

ULONG ulNumCharsAllowed;

ULONG ulTextPropTag;

ULONG ulInkDataPropTag;

} DTBLINKEDIT, FAR *LPDTBLINKEDIT;

Members

ulbLpszCharsAllowed

Offset from the beginning of the structure, in bytes, to a string that lists the characters allowed in the ink aware edit box.

The format of the string is as follows:

*	Any character is allowed (for example, "*")

[]	Defines a set of characters for example, "[0123456789]")

-	Indicates a range of characters. Typically used like "[a-z]".

~	Indicates that these characters are not allowed. (for example, "[~0-9]")

\	Used to quote any of the above symbols. (for example, "[\-\\\[\]]" means -, \, [, and ] characters are allowed)

ulFlags

Bitmask of flags designating the format of the text pointed to by the ulbLpszCharsAllowed member. The following flag can be set:

MAPI_UNICODE

Indicates the passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

ulNumCharsAllowed

Maximum number of characters that the user can type into the ink-aware edit box.

ulTextPropTag

A property name of type PT_TSTRING. The text in this property is displayed and edited in the edit box.

ulInkDataPropTag

A property name of type PT_BINARY. The property is used to store binary data (that is, graphics input) entered in the ink-aware edit box.

A DTBLINKEDIT structure does not specify the character length of the allowed characters string, it only contains an offset to it in memory allocated for the structure.

Use the SizedDtblInkEdit macro to define a structure similar to DTBLINKEDIT but explicitly specifies the number of character contained in the allowed characters member. The syntax is:

SizedDtblInkEdit (int n, u)

The parameter n is the length of the allowed character string. The allowed character string follows the following formatting rules:

*	Any character is allowed (for example, "*")

[]	Defines a set of characters for example, "[0123456789]")

-	Indicates a range of characters. Typically used like "[a-z]".

~	Indicates that these characters are not allowed. (for example, "[~0-9]")

\	Used to quote any of the above symbols. (for example, "[\-\\\[\]]" means -, \, [, and ] characters are allowed)

The structure type is defined with the tag _DTBLINKEDIT_ u and type name u.

SizedDtblEdit provides a means of defining a ink aware text edit box when the length of the allowed characters string is known. A DTBLINKEDIT structure does not explicitly give the length of the lpszCharsAllowed string, it only provides an offset to the first character of the string.

To use a sized ink aware edit box pointer such as lpSizedDtblInkEdit in any function call or structure that expects a LPDTBLINKEDIT pointer, perform the following cast:

lpDtblInkEdit = (LPDTBLINKEDIT) lpSizedDtblInkEdit.

The DTBLLINKEDIT structure is defined in MAPIDEFS.H.

See Also

DTCTL structure


  DTBLLABEL

A DTBLLABEL structure holds information about a label to be part of a dialog box.

Syntax

typedef struct _DTBLLABEL

{

ULONG ulbLpszLabelName;

ULONG ulFlags;

} DTBLLABEL, FAR *LPDTBLLABEL;

Members

ulbLpszLabelName

Offset from the beginning of the structure, in bytes, to be the label text string.

ulFlags

Bitmask of flags designating the format of the label text string. The following flag can be set:

MAPI_UNICODE

Indicates the passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

Comments

Use the SizedDtblLabel macro to create a structure definition similar to DTBLLABEL but contains a specified character length for the label. The syntax is:

SizedDtblLabel (int n, u)

The parameter n specifies the character length of the label. The structure type is defined with the tag _DTBLLABEL_ u and type name u.

SizedDtblLabel provides a means of defining a display table label when the number of characters in the label is known. A DTBLLABEL structure does not explicitly give the length of the lpszLabelName string, it only provides an offset to the first character of the string.

To use a sized display table label pointer such as lpSizedDtblLabel in any function call or structure that expects a LPDTBLLABEL pointer, perform the following cast:

lpDtblLabel = (LPDtblLabel) lpSizedDtblLabel.

The DTBLLABEL structure is defined in MAPIDEFS.H.

See Also

DTCTL structure


  DTBLLBX

A DTBLLBX structure holds information about a list box to be part of a dialog box.

Syntax

typedef struct _DTBLLBX

{

ULONG ulFlags;

ULONG ulPRSetProperty;

ULONG ulPRTableName;

} DTBLLBX, FAR *LPDTBLLBX

Members

ulFlags

Reserved; must be zero.

ulPRSetProperty

Unique property (such as an entry identifier) that holds a value indicating which entry in the list box was selected by the user. The property name indicates the column in the table whose values fill the list box that is connected with the selected list-box entry. Before the user selects a value in the list box, the ulPRSetProperty member holds the default selection.

ulPRTableName

A property of type PT_OBJECT on which an IMAPITable interface can be opened using an OpenProperty call. The rows of the table are to correspond to items in the list box.

Comments

DTBLLX is defined in MAPIDEFS.H.

See Also

DTCTL structure


  DTBLMVDDLBOX

The DTBLMVDDLBOX structure specifies a multivalued property to be used in a display table drop down list box.

Syntax

typedef struct _DTBLMVDDLBX

{

ULONG ulFlags;

ULONG ulMVPropTag;

} DTBLMVDDLBX, FAR * LPDTBLMVDDLBX;

Members

ulFlags

Reserved; must be zero.

ulMVPropTag

A property name that is a multivalued type (e.g. PT_MV_TSTRING). The different values of this property are displayed as distinct entries in the drop-down list box.

Comments

The list box defined by this structure is browse-only, i.e. no selection can be made by the user.

DTBLMVDDLBOX is defined in MAPIDEFS.H.

See Also

DTCTL structure


  DTBLMVLISTBOX

The DTBLMVLISTBOX structure specifies a multivalued property to be displayed in a list box.

Syntax

typedef struct _DTBLMVLISTBOX

{

ULONG ulFlags;

ULONG ulMVPropTag;

} DTBLMVLISTBOX, FAR * LPDTBLMVLISTBOX;

Members

ulFlags

Reserved; must be zero.

ulMVPropTag

A property name that is a multivalued type (e.g. PT_MV_TSTRING). The different values of this property are displayed as distinct entries in the drop-down list box.

Comments

The list box defined by this structure is browse-only, i.e., no selection can be made by the user.

DTBLMVLISTBOX is defined in MAPIDEFS.H.

See Also

DTCTL structure


  DTBLPAGE

A DTBLPAGE structure holds information about a tabbed page to be part of a dialog box.

Syntax

typedef struct _DTBLPAGE

{

ULONG ulbLpszLabel;

ULONG ulFlags;

ULONG ulbLpszComponent;

ULONG ulContext;

} DTBLPAGE, FAR *LPDTBLPAGE;

Members

ulbLpszLabel

Offset from the beginning of the structure, in bytes, to the label text for the page tab.

ulFlags

Bitmask of flags designating the format of the text pointed to by the ulbLpszLabel member. The following flag can be set:

MAPI_UNICODE

Indicates the passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

ulbLpszComponent

Offset, in number of bytes, to a Help file component string that appears in a MAPISVC.INF entry mapping Help files to user interface items. If this string is not NULL, a user can access extended Help for the tabbed page by clicking the Help button on the property sheet.

ulContext

Unique identifier for the tabbed page within the string defined by the ulbLpszComponent member. If this identifier is 0 and the component string is NULL, there is no Help associated with the page.

Comments

A DTBLPAGE structure does not specify the character length of the label and Help component strings, it only contains offsets to the beginning of these strings in memory allocated for the structure.

Use the SizedDtblPage macro to define a structure similar to DTBLPAGE but whose page label and Help file component string are of specified character lengths. The syntax is:

SizedDtblPage (int n, int n1, u)

The parameter n speciifes the character length of the page's label. The parameter n1 specifies the character length of a Help file component string that appears in a MAPISVC.INF entry mapping Help files to user interface items. If this string is not NULL, a user can access extended Help for the tabbed page by clicking the Help button on the property sheet. The structure type is defined with the tag _DTBLPAGE_ u and type name u.

SizedDtblPage provides a means of defining a display table page when the number of label and component string characters is known. A DTBLPAGE structure does not explicitly give the length of these strings; only offsets to their locations in memory allocated for the structure.

To use a sized display table page pointer lpSizedDtblPage in any function call or structure that expects a LPDTBLPAGE pointer, perform the following cast:

lpDtblPage = (LPDTBLPAGE) lpSizedDtblPage.

The DTBLPAGE stucture is defined in MAPIDEFS.H.

See Also

DTCTL structure


  DTBLRADIOBUTTON

A DTBLRADIOBUTTON structure holds information about one radio button which is to be a part of radio group in a display table dialog.

Syntax

typedef struct _DTBLRADIOBUTTON

{

ULONG ulbLpszLabel;

ULONG ulFlags;

ULONG ulcButtons;

ULONG ulPropTag;

long lReturnValue;

} DTBLRADIOBUTTON, FAR *LPDTBLRADIOBUTTON;

Members

ulbLpszLabel

Offset from the beginning of the structure, in number of bytes, to the label text for the radio button.

ulFlags

Bitmask of flags designating the format of the text pointed to by the ulbLpszLabel member. The following flag can be set:

MAPI_UNICODE

Indicates the passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

ulcButtons

Number of buttons in the radio button group. The actual button structures must appear in successive rows of the display table. Each of these rows should specify the same value for the ulcButtons member.

ulPropTag

The name of the property associated with the group of radio buttons. The property tag must be of type PT_LONG. The initial selection within the radio button group is based on the initial value of this property. Each button in the group must have ulPropTag set to the same property.

lReturnValue

Unique number that represents the radio button within the group when the button is selected at run time. Unless the flag DT_SET_IMMEDIATE is set in the display table, the client application writes the value of lReturnValue to ulPropTag when the dialog is closed. If this flag is set, the client application writes lReturnValue to ulPropTag at the time the radio button is selected.

Comments

A DTBLRADIOBUTTON structure does not specify the character length of the label, it only contains an offset to the beginning of the label in memory allocated for the structure.

The DTBLRADIOBUTTON is defined in MAPIDEFS.H.

See Also

BuildDisplayTable function, DTCTL structure,


  DTCTL

A DTCTL structure holds information about one or more dialog box controls for inclusion in a display table. The BuildDisplayTable function uses this structure for building the display table from control resources.

Syntax

typedef struct {

ULONG	ulCtlType;

ULONG	ulCtlFlags;

LPBYTE	lpbNotif;

ULONG	cbNotif;

LPTSTR	lpszFilter;

ULONG ulItemID;

union {

LPVOID	lpv;

LPDTBLLABEL	lplabel;

LPDTBLEDIT	lpedit;

LPDTBLLBX	lplbx;

LPDTBLCOMBOBOX	lpcombobox;

LPDTBLDDLBX	 	lpddlbx;

LPDTBLCHECKBOX	lpcheckbox;

LPDTBLGROUPBOX	lpgroupbox;

LPDTBLBUTTON	 	lpbutton;

LPDTBLRADIOBUTTON	lpradiobutton;

LPDTBLMVLISTBOX	 lpmvlbx;

LPDTBLMVDDLBX	 lpmvddlbx;

LPDTBLPAGE	lppage;

} ctl;

} DTCTL, FAR *LPDTCTL;

Members

ulCtlType

Value indicating the control represented by the DTCTL structure. The possible values are:

Value	Constant	Meaning
0	DTCT_LABEL	A dialog label.
1	DTCT_EDIT	A dialog edit text box.
2	DTCT_LBX	A dialog list box.
3	DTCT_COMBOBOX	A dialog combo box.
4	DTCT_DDLBX	A dialog drop-down list box.
5	DTCT_CHECKBOX	A dialog check box.
6	DTCT_GROUPBOX	A dialog group box.
7	DTCT_BUTTON	A dialog button control.
8	DTCT_PAGE	A dialog tabbed page.
9	DTCT_RADIOBUTTON	A dialog radio button.
A	DTCT_INKEDIT	A dialog ink-aware edit box.
B	DTCT_MVLISTBOX	A multi-valued list box.
C	DTCT_MVDDLBX	A multi-valued drop down list box.
ulCtlFlags

Bitmask of dialog-box control flags. The following flags can be set:

DT_ACCEPT_DBCS

Indicates ANSI or DBCS format is accepted.

DT_EDITABLE

Indicates the text in the dialog box control can be edited.

DT_MULTILINE

Indicates the dialog box control can contain multiple lines.

DT_PASSWORD_EDIT

Indicates the ability to edit the dialog box control is protected by a password.

DT_REQUIRED

Indicates the dialog box control is required.

DT_SET_IMMEDIATE

Enables immediate output of a value upon selection of a radio button.

lpbNotif

Pointer to notification data.

cbNotif

Size, in bytes, of the notification data.

lpszFilter

Pointer to a character filter for an edit box, (standalone or part of a combo box).

ulItemID

Item identifier validating parallel dialog-box template entries.

lpv

Pointer to a value that the client application should initialize to avoid warnings when calling BuildDisplayTable.

lplabel

Pointer to a DTBLLABEL structure.

lpedit

Pointer to a DTBLEDIT structure.

lplbx

Pointer to a DTBLLBX structure.

pcombobox

Pointer to a DTBLCOMBOBOX structure.

lpddlbx

Pointer to a DTBLDDLBX structure.

lpcheckbox

Pointer to a DTBLCHECKBOX structure.

lpgroupbox

Pointer to a DTBLGROUPBOX structure.

lpbutton

Pointer to a DTBLBUTTON structure.

lpradiobutton

Pointer to a DTBLRADIOBUTTON structure.

lpmvlbx

Pointer to a DTBLMVLISTBOX structure.

lpmvddlbx

Pointer to a DTBLMVDDLBOX structure.

lppage

Pointer to a DTBLPAGE structure.

Comments

The controls available for a dialog box are label, edit box, ink-aware edit box, list box, drop-down list box, combo box, check box, group box, button, radio button, and tabbed page.

DTCTL is defined in MAPIUTIL.H.

See Also

BuildDisplayTable function, DTBLBUTTON structure, DTBLCHECKBOX structure, DTBLCOMBOBOX structure, DTBLDDLBX structure, DTBLEDIT structure, DTBLGROUPBOX structure, DTBLLABEL structure, DTBLLBX structure, DTBLMVDDLBOX structure, DTBLMVLISTBOX structure, DTBLPAGE structure, DTBLRADIOBUTTON structure


  DTPAGE

A DTPAGE structure holds information about a tabbed dialog-box page for inclusion in the associated display table. The BuildDisplayTable function uses this structure for building the display table from control resources.

Syntax

typedef struct {

ULONG cctl;

LPTSTR	lpszResourceName;

LPDTCTL	 lpctl;

} DTPAGE, FAR *LPDTPAGE;

Members

cctl

Contains the count of controls in the lpctl array member of the same DTPAGE structure.

lpszResourceName

Pointer to the name of the tabbed-page resource or to an integer identifier for the resource.

lpctl

Pointer to a DTCTL structure defining the page.

Comments

DTPAGE is defined in MAPIUTIL.H.

See Also

BuildDisplayTable function, DTBLPAGE structure, DTCTL structure


  ENTRYID

An ENTRYID structure holds an entry identifier for a MAPI object. An entry identifier is a unique number that distinguishes one object from all other objects of the same type. For example, a message entry identifier uniquely identifies a message in the message store.

Syntax

typedef struct {

BYTE   abFlags[4];

BYTE	   ab[MAPI_DIM];

} ENTRYID, FAR *LPENTRYID;

Members

abflags

Array of flags that provide information describing the object. The following flags can be set:

MAPI_NOTRECIP

Indicates the entry identifier cannot be used as a recipient on a message.

MAPI_NOTRESERVED

Indicates that other users cannot access the entry identifier.

MAPI_NOW

Indicates the entry identifier cannot be used at other times.

MAPI_SHORTTERM

Indicates the entry identifier is short-term. All other values in this byte must be set unless other uses of the entry identifier are allowed.

MAPI_THISSESSION

Indicates the entry identifier cannot be used on other sessions.

The flags must be clear for permanent entry identifiers and set for short-term entry identifiers, as described in "Comments."

ab

Array of binary data used by service providers. The client application cannot use this array.

Comments

A message store or address book provider fills an entry identifier with information that makes sense for that provider. For a message store, entry identifiers identify folders or messages but not attachments. For an address book, entry identifiers identify address book containers, individual messaging users, and distribution lists. Entry identifiers also identify message store, status, profile, and session objects.

Directly comparing the binary data in two entry identifiers does not provide much information to your application, as MAPI may use different binary values in ENTRYID structures to refer to the same object. To determine if two entry identifiers refer to the same object, your application can use the IMAPISupport::CompareEntryIDs method for the appropriate object. To determine the identity of an object that does not have an entry identifier, your application can compare the two objects' PR_RECORD_KEY properties.

The following rules apply for using the abFlags[0] byte in entry identifiers.

•	Each object, if queried for its entry identifier, generates and provides the most permanent form of its entry identifier. To indicate an entry identifier is the most permanent one available for a given object, clear all the bits in the abFlags array.

•	Entry identifiers found in most MAPI tables can be short-term instead of permanent. The use of short-term entry identifiers is usually restricted. In general, you can use a short-term entry identifier to open an object only in the current MAPI session. You can use the short-term entry identifier with the message store only for the current session and only while the address book remains open. To indicate a short-term entry identifier, set all the values in the abFlags array . The next rule slightly modifies these limitations.

•	In some cases, your short-term entry identifier may be just as good as a permanent entry identifier. In such cases, clear the bits in the abFlags array as described in the first rule preceding.

The CbNewENTRYID macro determines the memory allocation requirements of an ENTRYID structure with an entry identifier of a specifed byte size. The syntax is:

int CbNewENTRYID (int _cb)

The cb parameter specifies the number of bytes used for the entry identifier. This macro returns the size, in bytes, of an ENTRYID that contains a _cb byte entry identifier.

The SizedENTRYID macro creates a structure type definition identical to that of ENTRYID but with an ab member that is a sized array. Use this macro to create an entry identifier array with explicit bounds. The syntax is:

SizedENTRYID (int _cb, _name)

The parameter _cb specifies the number of bytes used for the entry identifier. The structure type is defined with the tag _ENTRYID_ _name and type name _name.

The SizedENTRYID macro provides a means of defining an entry identifier after array length requirements are known.

To use a sized recipient list pointer such as lpSizedENTRYID in any function call or structure that expects a LPENTRYID pointer, perform the following cast:

lpENTRYID = (LPENTRYID) lpSizedENTRYID.

The ENTRYID structure is defined in MAPIDEFS.H.

See Also

IMAPISupport::CompareEntryIDs method, PR_RECORD_KEY property, SizedENTRYID macro


  ENTRYLIST

An ENTRYLIST structure is an SBinaryArray structure that contains a list of MAPI entry identifier structures (that is, ENTRYID structures).

Syntax

typedef SBinaryArray ENTRYLIST, FAR *LPENTRYLIST;

Comments

The ENTRYLIST structure is defined in MAPIDEFS.H.

See Also

ENTRYID structure, SBinaryArray structure


  ERROR_NOTIFICATION

An ERROR_NOTIFICATION structure defines an error notification event that indicates a critical error for an object. MAPI only uses this structure as a member of the NOTIFICATION structure for the advise sink.

Syntax

typedef struct _ERROR_NOTIFICATION

{

ULONG cbEntryID;

LPENTRYID lpEntryID;

SCODE scode;

ULONG ulFlags;

LPMAPIERROR lpMAPIError;

} ERROR_NOTIFICATION;

Members

cbEntryID

Size, in bytes, of the entry identifier of the object causing the error.

lpEntryID

Pointer to the entry identifier of the object causing the error.

scode

Error code for the critical error.

ulFlags

Bitmask of flags designating the format of the text pointed to by the lpszError member. The following flag can be set:

MAPI_UNICODE

Indicates the passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

lpszError

Pointer to a text string describing the error.

Comments

The ERROR_NOTIFICATION is defined in MAPIDEFS.H.

See Also

NOTIFICATION structure


  EXTENDED_NOTIFICATION

An EXTENDED_NOTIFICATION structure holds a notification for a specialized, provider-specific, extended event. MAPI only uses this structure as a member of the NOTIFICATION structure for the advise sink.

Syntax

typedef struct _EXTENDED_NOTIFICATION

{

ULONG ulEvent;

ULONG cb;

LPBYTE pbEventParameters;

} EXTENDED_NOTIFICATION;

Members

ulEvent

Extended event code.

cb

Size, in bytes, of the event-specific parameters defined in the pbEventParameters member.

pbEventParameters

Pointer to event-specific parameters. What type of parameters are used depends on the value of the ulEvent member; these parameters are documented by the provider that issued the event.

Comments

The provider defines and issues the event for which the EXTENDED_NOTIFICATION structure contains information.

The EXTENDED_NOTIFICATION structure is defined in MAPIDEFS.H.

See Also

NOTIFICATION structure


  FILETIME

A FILETIME structure, implemented for 32-bit Windows, holds a 64-bit time value for a file. This value represents the number of 100-nanosecond intervals since January 1, 1601.

Syntax

typedef struct _FILETIME {

DWORD dwLowDateTime;

DWORD dwHighDateTime;

} FILETIME, FAR *LPFILETIME;

Members

dwLowDateTime

Low-order 32 bits of the file time value.

dwHighDateTime

High-order 32 bits of the file time value.

Comments

Each MAPI property includes a FILETIME structure in its definition in an SPropValue structure.

The FILETIME structure is defined in MAPIDEFS.H.

See Also

SPropValue structure


  FLAGLIST

Contains a list of flags.

Syntax

typedef struct {

ULONG cFlags;

ULONG ulFlag[MAPI_DIM];

} FlagList, FAR * LPFlagList;

Members

cFlags

Number of MAPI-defined flags in the list.

ulFlags

First flag in the list.

Comments

See IABContainer::ResolveNames and IDistList::ResolveNames for descriptions of the flags that can be part of this list.

A FLAGLIST structure does not specify the length of the flag list, it only names the first flag in memory allocated for the list.

The FLAGLIST structure is defined in MAPIDEFS.H.

See Also

IABContainer::ResolveNames method


  FLATENTRY

A FLATENTRY structure holds a "flattened" entry identifier. That is, it holds the actual data of an entry identifier, in contrast to an ENTRYID structure, which contains only a pointer to that data..

Syntax

typedef struct {

ULONG cb;

BYTE abEntry[MAPI_DIM];

} FLATENTRY, FAR *LPFLATENTRY;

Members

cb

Size, in bytes, of the data in the abEntry member.

abEntry

Byte array that contains the data of an entry identifier.

Comments

 FLATENTRY is useful because a transport provider can store it in a file or pass it in a stream of bytes. The MAPI SDK sample transport provider contains code that can represent a standard entry identifier in a FLATENTRY structure.

Use the cbFLATENTRY macro to determine the number of bytes of memory occupied by an existing FLATENTRY structure. The syntax is:

int CbFLATENTRY (LPFLATENTRY _lpentry)

The _lpentry parameter points to a FLATENTRY structure. This macro returns the number of bytes occupied by the FLATENTRY structure pointed to by _lpentry.

 Use the CbNewFLATENTRY macro to determine the memory allocation requirements of a FLATENTRY containing an entry identifier of a specified byte size. The syntax is:

int CbNewFLATENTRY (int _cb)

The _cb parameter specifies the entry identifier byte size. This macro returns the number of bytes of memory that a FLATENTRY with a _cb byte entry identifier would occupy.

The FLATENTRY structure is defined in MAPIDEFS.H.

See Also

ENTRYID structure


  FLATENTRYLIST

A FLATENTRYLIST structure contains an array of FLATENTRY structures. A FLATENTRY structure holds a "flattened" entry identifier (that is, the actual data of an entry identifier instead of a pointer to that data).

Syntax

typedef struct {

ULONG	cEntries;

ULONG	cbEntries;

BYTE	abEntries[MAPI_DIM];

} FLATENTRYLIST, FAR *LPFLATENTRYLIST;

Members

cEntries

Number of FLATENTRY structures in the array described by the abEntries member.

cbEntries

Number of bytes occupied by the entire array described by abEntries.

abEntries

Byte array containing the number of FLATENTRY structures designated by the cEntries member, arranged end to end.

Comments

In the abEntries array, each FLATENTRY structure is aligned on a 4-byte boundary. Extra bytes are included as padding to ensure 4-byte alignment between any two FLATENTRY structures. For example, the second FLATENTRY starts at an offset made up of the first FLATENTRY, plus extra bytes as padding to round the space taken up to the next multiple of 4 bytes, plus the offset of the second FLATENTRY.

PR_REPLY_RECIPIENT_ENTRIES is a binary property that contains a FLATENTRYLIST.

The CbFLATENTRYLIST macro determines the number of bytes of memory occupied by an existing FLATENTRYLIST structure. The syntax is:

int CbFLATENTRYLIST (LPFLATENTRYLIST _lplist).

The _lplist parameter points to a FLATENTRYLIST structure. This macro returns the number of bytes occupied by the FLATENTRY structure pointed to by _lplist.

The CbNewFLATENTRYLIST macro determines the memory allocation requirements of a FLATENTRYLIST whose list of FLATENTRYs is of a specified byte size. The syntax is:

int CbNewFLATENTRY (int _cb)

The parameter _cb specifies the byte size of the list of FLATENTRYs. This macro returns the number of bytes in memory that a FLATENTRYLIST with a _cb byte FLATENTRY list would occupy.

The FLATENTRYLIST structure is defined in MAPIDEFS.H.

See Also

FLATENTRY structure, PR_REPLY_RECIPIENT_ENTRIES property


  FLATMTSIDLIST

A FLATMTSIDLIST structure contains an array of MTSID structures, each of which holds an X.400 message transport system (MTS) entry identifier. .

Syntax

typedef struct {

ULONG	cMTSIDs;

ULONG	cbMTSIDs;

BYTE	abMTSIDs[MAPI_DIM];

} FLATMTSIDLIST, FAR *LPFLATMTSIDLIST;

Members

cMTSIDs

Number of MTSID structures in the array described by the abMTSIDs member.

cbMTSIDs

Number of bytes in the array described by abMTSIDs.

abMTSIDs

Byte array of MTSID structures.

Comments

The FLATMTSIDLIST structure's use in X.400 messaging corresponds to the FLATENTRYLIST structure's use in MAPI messaging. MAPI uses FLATMTSIDLIST structures to maintain X.400 properties during message handling. Service providers use FLATMTSIDLIST structures when handling inbound and outbound X.400 messages.

The CbFLATMTSIDLIST macro determines the number of bytes of memory occupied by a FLATMTSIDLIST structure. The syntax is:

int CbFLATMTSIDLIST (LPFLATMTSIDLIST _lplist)

The _lplist parameter is a pointer to a FLATMTSIDLIST structure. This macro returns the number of bytes occupied by the FLATMTSIDLIST structure pointed to by _lpentry.

Use the CbNewFLATMTSIDLIST macro to determine the memory allocation requirements of a FLATMTSIDLIST structure whose list of MTSIDs is of a specified byte size. The syntax is:

int CbNewMTSID (int _cb)

The parameter _cb specifies the byte size of the MTSID list. This macro returns the number of bytes of memory occupied by a FLATMTSIDLIST with a _cb byte MTSID list.

The FLATMTSIDLIST stucture is defined in MAPIDEFS.H.

See Also

CbNewFLATMTSIDLISTmacro  FLATENTRYLIST structure, MTSID structure


  FORMPRINTSETUP

Describes the print setup information for the form object.

Syntax

typedef struct {

ULONG	ulFlags;

HDEVMODE	hDevMode;

HDEVNAMES	hDevNames;

ULONG	ulFirstPageNumber;

ULONG	ulFPrintAttachments;

} FORMPRINTSETUP, FAR * LPFORMPRINTSETUP;

Parameters

ulFlags

Input parameter used to control the type of the strings. The following flag can be used:

MAPI_UNICODE

Indicates the passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

hDevmode

Input parameter specifying the mode of the printer.

hDevnames

Input parameter specifying the pathname of the printer.

ulFirstPageNumber

Input parameter containing the page number of the first page to be printed.

ulFPrintAttachments

Input parameter indicating whether there are attachments to be printed. Comments

FORMPRINTSETUP is used to describe the print setup information for the form object. Implementations of IMAPIViewContext::GetPrintSetup fill in the FORMPRINTSETUP structure and return it in the lppformprintsetup output parameter of GetPrintSetup.

If the MAPI_UNICODE flag is passed in the ulflags parameter of GetPrintSetup, the strings in hDevmode and hDevnames should be in Unicode format. Otherwise, the strings should be ANSI format.

The hDevMode and hDevNames parameters must be allocated using the Win32 function GlobalAlloc and must be freed using Win32 GlobalFree. The FORMPRINTSETUP structure must be freed by the calling form object using the MAPIFreeBuffer function.

The FORMPRINTSETUP structure is defined in MAPIFORM.H.

See Also

IMAPIViewContext::GetPrintSetup  MAPIFreeBuffer


  FORMPROPSPECIALTYPE

A FORMPROPSPECIALTYPE enumeration lists possible special type tags for the nSpecialType member of the SMAPIFormProp structure. SMAPIFormProp holds information about a form property used as part of the definitions of the IMAPIFormInfo interface; nSpecialType holds a tag that applies to the u union that is part of SMAPIFormProp.

Syntax

typedef enum FORMPROPSPECIALTYPE

{

FPST_VANILLA = 0,

FPST_ENUM_PROP = 1

} FORMPROPSPECIALTYPE;

Members

FPST_VANILLA

Indicates no enumeration is used.

FPST_ENUM_PROP

Indicates the enumeration contains a MAPI property.

Comments

The FORMPROPSPECIALTYPE is defined in MAPIFORM.H.

See Also

SMAPIFormProp structure


  GUID

A GUID structure holds a globally unique identifier (GUID), which identifies a particular object class and interface. This identifier is a 128-bit value created with a DEFINE_GUID OLE macro. For more information about GUIDs, see the Remote Procedure Call (RPC) documentation, OLE Programmer's Reference, Volume One, and Inside OLE, Second Edition.

Syntax

typedef struct _GUID

{

    unsigned long  Data1;

    unsigned short  	Data2;

    unsigned short 	 Data3;

    unsigned char 	Data4[8];

} GUID;

Members

Data1

Unsigned long integer data value.

Data2

Unsigned short integer data value.

Data3

Unsigned short integer data value.

Data4

Array of unsigned characters.

Comments

The GUID structure is defined in MAPIGUID.H.


  IID

An IID is a specialized GUID structure containing an interface identifier (IID). For more information about IIDs, see the Remote Procedure Call (RPC) documentation, OLE Programmer's Reference, Volume One, and Inside OLE, Second Edition.

Comments

The IID structure is defined in MAPIGUID.H.

See Also

GUID structure


  LARGE_INTEGER

A LARGE_INTEGER structure, implemented for 32-bit Windows, holds a 64-bit signed integer value.

Syntax

typedef struct _LARGE_INTEGER {

DWORD LowPart;

DWORD HighPart;

} LARGE_INTEGER, FAR *LARGE_INTEGER;

Members

LowPart

Low-order 32 bits of the value.

HighPart

High-order 32 bits of the value.

Comments

A MAPI property includes a LARGE_INTEGER structure in its definition in an SPropValue structure.

The Large_Integer structure is defined in MAPIDEFS.H.

See Also

SPropValue structure


  MAPIERROR

Stores an error code typically generated by the operating system and appropriate help topic information retrieved by GetLastError methods.

Syntax

typedef struct _MAPIERROR

{

ULONG	ulVersion;

LPTSTR	lpszError;

LPTSTR	lpszComponent;

ULONG	ulLowLevelError;

ULONG	ulContext;

} MAPIERROR, FAR * LPMAPIERROR;

Members

ulVersion

Input parameter containing the version number of the component.

lpszError

Input parameter pointing to an error message string.

lpszComponent

Input parameter pointing to a component string that appears in a help file mapping entry in MAPISVC.INF. . Each entry consists of a component string on the lefthand side and a Help file path on the right.  It is recommended that component strings be no longer that 30 characters. For example:

[Help File Mappings]

Microsoft Mail for PC LANs=sfserr.hlp

ulLowLevelError

Input parameter specifying the low-level error code used only when the error to be returned is low-level.

ulContext

Input parameter that uniquely identifies the error within lpszComponent. If there is a Helpfile for this component, ulContext is a Helpfile context identifier; otherwise, it specifies a unique numeric identifier.

Comments

The MAPIERROR structure is used to provide error information to calling processes.  MAPI methods and functions that return error information typcally include an lppMAPIError parameter in which the MAPIERROR structure is placed. To get information on the error, call IMAPIProp::GetLastError.

The MAPIERROR structure is defined in MAPIDEFS.H.

See Also

IMAPIProp::GetLastError


  MapiFile

The MapiFile type contains file attachment information.

Syntax

Type MapiFile
Reserved as Long
Flags as Long
Position as Long
PathName as String
FileName as String
FileType as String
End Type

Members

Reserved

Reserved for future use; must be zero.

Flags

A bitmask of flags. The following flags can be set:

MAPI_OLE

Indicates the attachment is an OLE object file attachment. If MAPI_OLE_STATIC is also set, the object is static. If neither flag is set, the attachment is simply a data file.

MAPI_OLE_STATIC

Indicates a static OLE object file attachment.

Position

An integer describing where the attachment should be placed in the message body. Attachments replace the character found at a certain position in the message body; in other words, attachments replace the MapiMessage member NoteText[Position]. Applications cannot place two attachments in the same location within a message, and attachments cannot be placed beyond the end of the message body. PathName

The full path name of the attached file. The file should be closed before this call is made.

FileName

The filename seen by the recipient. This name can differ from the filename in PathName if temporary files are being used. If FileName is empty, the filename from PathName is used. If the attachment is an OLE object, FileName contains the class name of the object, such as "Microsoft Excel Worksheet."

FileType

A reserved descriptor that tells the recipient the type of the attached file. An empty string indicates an unknown or operating system−determined file type. With this release, you must use "" for this parameter.

Comments

Simple MAPI for Visual Basic supports the following kinds of attachments:

•	Data files

•	Embedded OLE objects

•	Static OLE objects

The Flags member determines the kind of attachment. OLE object files are file representations of OLE object streams. You can recreate an OLE object from the file by calling the OleLoadFromStream function with an OLESTREAM object that reads the file contents. If an OLE file attachment is included in an outbound message, the OLE object stream should be written directly to the file used as the attachment.

With Microsoft Mail version 3.0b, if you send an attachment with Position equal to −1, the attachment is placed at the beginning of the message, with a space character on either side of the attachment.


  MapiFileDesc

A MapiFileDesc structure holds information about a message attachment, which is either an OLE object file or a simple data file.

Syntax

typedef struct {

ULONG ulReserved;

ULONG flFlags;

ULONG nPosition;

LPTSTR lpszPathName;

LPTSTR lpszFileName;

LPVOID lpFileType;

} MapiFileDesc, FAR *lpMapiFileDesc;

Members

ulReserved

Reserved; must be zero.

flFlags

Bitmask of attachment flags. The following flags can be set:

MAPI_OLE

Indicates the attachment is an OLE object file attachment. If MAPI_OLE_STATIC is also set, the object is static. If neither flag is set, the attachment is simply a data file.

MAPI_OLE_STATIC

Set to iIndicates a static OLE object file attachment.

nPosition

Integer used in the MapiMessage structure member lpszNoteText to indicate at which character the attachment should be rendered in the message body. The application renders an attachment within the message text at the character and offset designated by lpszNoteText[nPosition] in MapiMessage. A value of − 1 (0xFFFFFFFF) means attachment position is not indicated in this way.

lpszPathName

Pointer to the fully qualified path of the attachment file. This path should include the disk drive letter and directory name.

lpszFileName

Optional pointer to the attachment filename seen by the recipient, which may differ from the filename in the lpszPathName member if temporary files are being used. If the lpszFileName member is empty or NULL, the filename from lpszPathName is used.

lpFileType

Optional pointer to a descriptor that can be used to indicate to message recipients the type of the attached file; an example is a filename extension such as .DOC. A value of NULL indicates an unknown or operating system−determined file type.

Comments

The flag set in the flFlags member determines what kind a particular attachment is.

OLE object files are file representations of OLE object streams. When a file attachment is being read from an inbound message, your application can direct the OLE object file attachment stream into an object straight from the attachment file. When a user includes a file attachment in an outbound message, your application should write the OLE object stream directly to the attachment file. For more details about OLE object streams, see OLE Programmer's Reference, Volume One, and Inside OLE, Second Edition.

Extended MAPI determines what kind of file an attachment contains in a different fashion. In Extended MAPI, the lpFileType member can be a FAR pointer to an extension structure (that is, the MapiFileTagExt structure) that contains full attachment tag information, as defined in Extended MAPI. For most applications running with Microsoft Windows, the attachment filename extension can be reliably used to identify the file type. For example, the filename extension .DOC means that the file is a Microsoft Word for Windows document.

MapiFileDesc is defined in the MAPI header files as MapiFileDescA for ANSI or DBCS platforms and MapiFileDescW for Unicode platforms. Your application, however, can simply refer to the name MapiFileDesc. Be sure to define the symbolic constant UNICODE and limit the platform where necessary. MAPI will interpret the platform information and internally translate MapiFileDesc to the appropriate alternative.

When using the MapiFileDesc member nPosition, your application should not make two attachments in the same location. Applications may not display file attachments beyond the length of the note text.

The MapiFileDesc structure is defined in MAPI.H.

See Also

MapiFileTagExt structure


  MapiFileTagExt

A MapiFileTagExt structure specifies a message attachment's type at its creation and its current form of encoding so it can be restored to its original type at its destination.

Syntax

typedef struct {

ULONG ulReserved;

ULONG cbTag;

LPBYTE lpTag;

ULONG cbEncoding;

LPBYTE lpEncoding

} MapiFileTagExt, FAR *lpMapiFileTagExt;

Members

ulReserved

Reserved; must be zero.

cbTag

Size, in bytes, of the value defined by the lpTag member.

lpTag

Pointer to an X.400 object identifier indicating the type of the attachment in its original form, for example "Microsoft Excel worksheet."

cbEncoding

Size, in bytes, of the value defined by the lpEncoding member.

lpEncoding

Pointer to an X.400 object identifier indicating the form in which the attachment is currently encoded, for example MacBinary, UUENCODE, or binary.

Comments

MapiFileTagExt defines the type of an attached file for purposes such as filing it, choosing the correct application to launch when opening it, or any use that requires full information regarding the file type. For more information on using MAPI with X.400 messaging, see Chapter 26, "Using MAPI with X.400 Message Systems."

MapiFileTagExt is defined in MAPI.H.

See Also

MapiFileDesc structure


  MAPIINIT_0

A MAPIINIT_0 structure holds the per-instance global data for Extended MAPI.

Syntax

typedef struct {

ULONG ulVersion;

ULONG ulFlags;

} MAPIINIT_0, FAR *LPMAPIINIT_0;

Members

ulVersion

Integer value indicating the MAPIINIT_0 structure version.

ulFlags

Bitmask of flags controlling the format of the data. The following flag can be set:

MAPI_NT_SERVICE

This flag should be passed if the client is a Windows NT service. It is ignored on all platforms other than NT. Value is 0x00010000.

MAPI_MULTITHREAD_NOTIFICATIONS

This flag should be passed if the client wants MAPI notifications to happen on a separate thread, instead of Windows NT and Windows 95. Value is 1.

MAPI_INIT-VERSION

The client application must pass this flag to be sure the correct version of the structure is used.

Comments

MAPIInitialize uses this structure in its processing.

The MAPIINIT_0 structure is defined in MAPIX.H.

See Also

MapiInitialize function


  MapiMessage

A MapiMessage structure holds information about a message.

Syntax

typedef struct {

ULONG ulReserved;

LPTSTR lpszSubject;

LPTSTR lpszNoteText;

LPTSTR lpszMessageType;

LPTSTR lpszDateReceived;

LPTSTR lpszConversationID;

FLAGS flFlags;

lpMapiRecipDesc lpOriginator;

ULONG nRecipCount;

lpMapiRecipDesc lpRecips;

ULONG nFileCount;

lpMapiFileDesc lpFiles;

} MapiMessage, FAR *lpMapiMessage;

Members

ulReserved

Reserved; must be zero.

lpszSubject

Pointer to the text string describing the message subject, typically limited to 256 characters or less. If this member is empty or NULL, there is no subject text.

lpszNoteText

Pointer to a string containing the message text. If this member is empty or NULL, there is no message text.

lpszMessageType

Pointer to a string indicating the message type. The type is for use by non − interpersonal messaging (IPM) applications. Not all messaging systems support non-IPM messages; systems that do not may not provide, and will ignore, the lpszMessageType member. If this member is empty or NULL, the message type is IPM.

lpszDateReceived

Pointer to a string indicating the date when the message was received. The format is YYYY/MM/DD HH:MM, using a 24-hour clock.

lpszConversationID

Pointer to a string identifying the conversation thread to which the message belongs. Some messaging systems may ignore and not return this member.

flFlags

Bitmask of message status flags. Flags must be zero for outbound messages and should be ignored for inbound messages. The following flags can be set:

MAPI_RECEIPT_REQUESTED

Indicates a receipt notification is requested.

MAPI_SENT

Indicates the message has been sent.

MAPI_UNREAD

Indicates the message has not been read.

lpOriginator

Pointer to a MapiRecipDesc structure holding information about the sender of the message.

nRecipCount

Number of structures that describe message recipients in the array pointed to by the lpRecips member. The number of recipient structures in the message envelope is stored in this member. A value of zero indicates no recipients are included.

lpRecips

Pointer to an array of MapiRecipDesc structures, each holding information about a message recipient.

nFileCount

Number of structures that describe file attachments in the array pointed to by the lpFiles member. A value of zero indicates no file attachments are included.

lpFiles

Pointer to an array of MapiFileDesc structures, each holding information about a file attachment.

Comments

MapiMessage is defined in the MAPI header files as MapiMessageA for ANSI or DBCS platforms and MapiMessageW for Unicode platforms. Your application, however, can simply refer to the name MapiMessage. Be sure to define the manifest constant UNICODE and limit the platform where necessary. MAPI will interpret the platform information and internally translate MapiMessage to the appropriate alternative.

The MAPIMessage structure is defined in MAPI.H.

See Also

MapiFileDesc structure, MapiRecipDesc structure


  MAPINAMEID

A MAPINAMEID structure associates a property ID in a foreign source with a GUID structure representing a globally unique identifier and with an object kind made up of an interface identifier and an object name.

Syntax

typedef struct _MAPINAMEID

{

LPGUID lpguid;

ULONG ulKind;

union {

LONG LID;

LPWSTR lpwstrName;

} Kind;

} MAPINAMEID, FAR *LPMAPINAMEID;

Members

lpguid

Pointer to a GUID structure defining a particular property set.

ulKind

Value describing the kind of object described in the Kind union.

LID

Numeric value representing the property name.

lpwstrName

Pointer to a wide character string representing the property name.

Comments

MAPINAMEID is used to make a MAPI compatible name from a name used for another implementation of the messaging system.

The MAPINAMEID structure is defined in MAPIDEFS.H.

See Also

GUID structure, IMAPIProp::GetIDsFromNames interface


  MapiRecipDesc

A MapiRecipDesc structure holds information about a message sender or recipient.

Syntax

typedef struct {

ULONG ulReserved

ULONG ulRecipClass;

LPTSTR lpszName;

LPTSTR lpszAddress;

ULONG ulEIDSize;

LPVOID lpEntryID;

} MapiRecipDesc, FAR *lpMapiRecipDesc;

Members

ulReserved

Reserved; must be zero.

ulRecipClass

Message recipient or sender class. Possible values for the class are:

Value	Constant	Meaning
0	MAPI_ORIG	Indicates the sender of the message.
1	MAPI_TO	Indicates a primary message recipient.
2	MAPI_CC	Indicates a recipient of a message copy.
3	MAPI_BCC	Indicates a recipient of a blind copy.
lpszName

Pointer to the display name of the message recipient or sender.

lpszAddress

Optional pointer to the recipient or sender's address; this address is provider-specific message delivery data. Generally, the messaging system provides such addresses for inbound messages. For outbound messages, the lpszAddress member pointer indicates an address entered by the user for a recipient not in an address book (that is, a custom recipient).

Extended MAPI defines the format of an address pointed to by the lpszAddress member as [address type][e-mail address]. An example of an address is FAX:206-555-1212 or SMTP:M@X.COM.

ulEIDSize

Size, in bytes, of the opaque binary data pointed to by the lpEntryID member.

lpEntryID

Pointer to binary entry-identifier data used by the messaging system to specify the message recipient. Unlike the address indicated by lpszAddress, this data is opaque and may not be printable. The messaging system returns in this member valid entry identifier data for all recipients or senders listed in accessible address books.

Comments

MapiRecipDesc is defined in the MAPI header files as MapiRecipDescA for ANSI or DBCS platforms and MapiRecipDescW for Unicode platforms. Your application, however, can simply refer to the name MapiRecipDesc. Be sure to define the manifest constant UNICODE and limit the platform where necessary. MAPI will interpret the platform information and internally translate MapiRecipDesc to the appropriate alternative.

The MapiRecipDesc structure is defined in MAPI.H.


  MAPIUID

A MAPIUID structure contains a unique identifier (UID) used to identify a particular message conversation or string-to-identifier mapping.

Syntax

typedef struct _MAPIUID

{

BYTE ab[16];

} MAPIUID, FAR *LPMAPIUID;

Members

ab

Array containing a 16-byte UID.

Comments

A MAPI UID is a globally unique identifier (GUID) put into Intel processor byte order. That is, a MAPI UID and a GUID have the same byte order when used on an Intel-processor computer, but on a computer that uses a different byte order (for example, a Motorola-processor computer), the MAPI UID has the same byte order as on the Intel machine and the GUID uses the byte order specific to the computer.

MAPI creates MAPIUID structures in a way that makes it extremely rare for two different items to have the same UID. Your application can store MAPIUID structures as binary object properties or as files, without regard for the byte ordering of the computer storing or accessing the information. When the application transmits across a network, it should use a protocol or transmission format that does not change the byte order of MAPIUID data.

The most common use of a MAPIUID structure by MAPI applications is to define the UID of a profile section. You can define a MAPI UID to identify the profile section your application uses to store configuration information specific to a user's selected profile. The UID can then be formed from the GUID by placing the bytes of the GUID into Intel byte order. For more information on generating a UID, see OLE Programmer's Reference, Volume One.

The IsEqualMAPIUID macro is used inline  by a client application or a service provider to compare two MAPI unique identifiers (UIDs). It evaluates to TRUE if the two UIDs are equal. The syntax is:

BOOL IsEqualMAPIUID(lpuid1, lpuid2)

The input parameters lpuid1 and lpuid2 specify pointers to a MAPIUID structure identifying the first UID and second UID, respectively.

If your application or provider uses this macro, be sure to include MEMORY.H in your code. This macro returns TRUE, if the UIDs are equal, and FALSE otherwise.

The MAPIUID structure is defined in MAPIDEFS.H.

See Also

GUID structure,  IMAPISession::OpenProfileSection method IMAPISupport::NewUID method


  MTSID

An MTSID structure holds the actual data of an X.400 message transport system (MTS) entry identifier. Its format contrasts with that of an ENTRYID structure, which contains only a pointer to entry identifier data.

Syntax

typedef struct {

ULONG	cb;

BYTE	ab[MAPI_DIM];

} MTSID, FAR *LPMTSID;

Members

cb

Size, in bytes, of the data in the abEntry member.

abEntry

Byte array to contain the MTS entry-identifier data.

Comments

The MTSID structure is used only for X.400 mappings of MAPI entry identifiers. It corresponds to MAPI's FLATENTRY structure.

An MTS identifier has the same format as a MAPI entry identifier or a binary property value. MTS identifiers can be particularly useful for canceling deferred messages.

Use the CbMTSID macro to determine the number of bytes of memory occupied by a MTSID structure. The syntax is:

int CbFLATENTRYLIST (LPMTSID _lpentry)

The parameter _lpentry is a pointer to a MTSID structure. This macro returns the number of bytes occupied by the MTSID structure pointed to by _lpentry.

The CbNewMTSID macro determines the memory allocation requirements of an MTSID structure using a specified number of bytes for its message transfer agent identifier. The syntax is:

int CbNewMTSID (int _cb)

The parameter _cb is the byte size of the message transfer agent identifier. This macro returns the number of bytes of memory occupied by an MTSID structure with a _cb byte message transfer agent identifier.

The MTSID structure is defined in MAPIDEFS.H.

See Also

FLATENTRY structure, FLATMTSIDLIST structure


  NEWMAIL_NOTIFICATION

A NEWMAIL_NOTIFICATION structure holds information about a notification event that indicates to an application a new message has arrived. MAPI uses this structure only as a member of the NOTIFICATION structure, which holds information about a notification event for the advise sink.

Syntax

typedef struct _NEWMAIL_NOTIFICATION

{

ULONG cbEntryID;

LPENTRYID lpEntryID;

ULONG cbParentID;

LPENTRYID lpParentID;

ULONG ulFlags;

LPTSTR lpszMessageClass;

ULONG ulMessageFlags;

} NEWMAIL_NOTIFICATION;

Members

cbEntryID

Size, in bytes, of the entry identifier of the arriving message.

lpEntryID

Pointer to the entry identifier of the arriving message.

cbParentID

Size, in bytes, of the data pointed to by the lpParentID member.

lpParentID

Pointer to the entry identifier of the folder where the arriving message was placed.

ulFlags

Bitmask of flags describing the format of the message. The following flag can be set:

MAPI_UNICODE

Indicates the passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

lpszMessageClass

Pointer to the message class of the new message, indicating whether the messaging system is using a Unicode or an ANSI or DBCS platform.

ulMessageFlags

Copy of the PR_MESSAGE_FLAGS property for the message, which contains a bitmask of flags controlling the current state of the message object.

Comments

The NEWMAIL_NOTIFICATION structure is defined in MAPIDEFS.H.

See Also

NOTIFICATION structure, PR_MESSAGE_FLAGS property


  NOTIFICATION

A NOTIFICATION structure holds information about one of several possible notification events for an advise sink.

Syntax

typedef struct {

ULONG	ulEventType;

union {

ERROR_NOTIFICATION  err;

NEWMAIL_NOTIFICATION newmail;

OBJECT_NOTIFICATION obj;

TABLE_NOTIFICATION tab;

EXTENDED_NOTIFICATION ext;

STATUS_OBJECT_NOTIFICATION statobj;

} info;

} NOTIFICATION, FAR *LPNOTIFICATION;

Members

ulEventType

Type of notification event that occurred. Your application uses this value to locate and read the data of the actual notification in the corresponding data structure within a NOTIFICATION structure member. The following table lists the possible types of notification events along with the data structures that hold information for each type of event and the NOTIFICATION members in which these data structures can be found.

Notification event type	Corresponding data structure	In member
fnevCriticalError	ERROR_NOTIFICATION	err
fnevNewMail	NEWMAIL_NOTIFICATION	newmail
fnevObjectCreated	OBJECT_NOTIFICATION	obj
fnevObjectDeleted	OBJECT_NOTIFICATION	obj
fnevObjectModified	OBJECT_NOTIFICATION	obj
fnevObjectCopied	OBJECT_NOTIFICATION	obj
fnevSearchComplete	OBJECT_NOTIFICATION	obj
fnevTableModified	TABLE_NOTIFICATION	tab
fnevStatusObjectModified	STATUS_OBJECT_ NOTIFICATION	statobj
err

ERROR_NOTIFICATION structure containing information about a critical error, if one has occurred.

newmail

NEWMAIL_NOTIFICATION structure containing information about a new message's arrival, if one has arrived.

obj

OBJECT_NOTIFICATION structure containing information about an object's having been created, deleted, modified, copied, or searched, if this has occurred.

tab

TABLE_NOTIFICATION structure containing information about modifications, if any, to a table.

ext

EXTENDED_NOTIFICATION structure containing information for a provider-defined event, if one has occurred.

statobj

STATUS_OBJECT_NOTIFICATION structure containing information about a change in a row of the status table, if a change has occurred.

Comments

One possible use of the NOTIFICATION structure is shown in the following code example. In this example, a test is first performed to determine whether a new mail notification event has occurred. If it has, the message class of the new message is displayed.

if (pNotif -> ulEventType == fnevNewMail)

{

printf("%s\n", pNotif -> newmail.lpszMessageClass)

}

The NOTIFICATION structure is defined in MAPIDEFS.H.

See Also

ERROR_NOTIFICATION structure, EXTENDED_NOTIFICATION structure, NEWMAIL_NOTIFICATION structure, OBJECT_NOTIFICATION structure, STATUS_OBJECT_NOTIFICATION structure, TABLE_NOTIFICATION structure


  NOTIFKEY

A NOTIFKEY structure holds the notification key for the MAPI notification engine; service providers create this key and make it available. MAPI uses this key to identify an object globally so that notifications can reach it. A key works across multiple processes.

Syntax

typedef struct

{

ULONG	cb;

BYTE	ab[MAPI_DIM];

} NOTIFKEY, FAR *LPNOTIFKEY;

Members

cb

Size, in bytes, of the notification key in the ab member.

ab

Byte array containing the notification key.

Comments

The interpretation of a notification key depends on the object that it represents. An object's notification key is frequently its entry identifier. However, the key can be a constant, a name, or another such identifying item. In the sample message store, for example, the notification key for a folder directory is its path.

The NOTIFKEY structure is defined in MAPISPI.H.


  OBJECT_NOTIFICATION

An OBJECT_NOTIFICATION structure holds information about a notification event indicating that an object was created, deleted, modified, copied, or searched. MAPI uses this structure only as a member of the NOTIFICATION structure for the advise sink.

Syntax

typedef struct _OBJECT_NOTIFICATION

{

ULONG cbEntryID;

LPENTRYID lpEntryID;

ULONG ulObjType;

ULONG cbParentID;

LPENTRYID lpParentID;

ULONG cbOldID;

LPENTRYID lpOldID;

ULONG cbOldParentID;

LPENTRYID lpOldParentID;

LPSPropTagArray lpPropTagArray;

} OBJECT_NOTIFICATION;

Members

cbEntryID

Size, in bytes, of the entry identifier of the object that was created or modified.

lpEntryID

Pointer to the entry identifier of the object.

ulObjType

Type of object (for example, message or folder). Possible types are:

Value	Constant	Meaning
1	MAPI_STORE	Message store.
2	MAPI_ADDRBOOK	Address book.
3	MAPI_FOLDER	Folder.
4	MAPI_ABCONT	Address book container.
5	MAPI_MESSAGE	Message.
6	MAPI_MAILUSER	Messaging user.
7	MAPI_ATTACH	Message attachment.
8	MAPI_DISTLIST	Distribution list.
9	MAPI_PROFSECT	Profile section.
A	MAPI_STATUS	Status.
B	MAPI_SESSION	Session.
cbParentID

Size, in bytes, of the data pointed to by the lpParentID member.

lpParentID

Pointer to the entry identifier of the parent of the object.

cbOldID

Size, in bytes, of the entry identifier for the original object.

lpOldID

Pointer to the entry identifier of the original object. This pointer is NULL if the object has not changed.

cbOldParentID

Size, in bytes, of the data pointed to by the lpOldParentID member.

lpOldParentID

Pointer to the entry identifier of the parent of the original object.

lpPropTagArray

Pointer to an SPropTagArray structure containing the tags of object properties affected by the notification event.

Comments

The OBJECT_NOTIFICATION structure is defined in MAPIDEFS.H.

See Also

NOTIFICATION structure, SPropTagArray structure


  OPTIONDATA

An OPTIONDATA structure contains information specific to an e-mail address type supported by the transport service provider. OPTIONDATA address information can apply to a message or to a message recipient.

Syntax

typedef struct _OPTIONDATA

{

ULONG	ulFlags;

LPGUID	lpRecipGUID;

LPTSTR	lpszAdrType;

LPTSTR	lpszDLLName;

ULONG	ulOrdinal;

ULONG	cbOptionsData;

LPBYTE	lpbOptionsData;

ULONG	cOptionsProps;

LPSPropValue	 lpOptionsProps;

} OPTIONDATA, FAR *LPOPTIONDATA;

Members

ulFlags

Bitmask of option data flags. The following flags can be set:

MAPI_MESSAGE

Indicates message-specific options.

MAPI_RECIPIENT

Indicates recipient-specific options.

lpRecipGUID

Pointer to a GUID structure identifying the message recipient, if applicable.

lpszAdrType

Pointer to the e-mail address type that must be NULL.

lpszDLLName

Pointer to the name of the DLL to be loaded.

ulOrdinal

Ordinal the transport provider DLL uses to find the client application's option callback function.

cbOptionsData

Size, in bytes, of the data pointed to by the lpbOptionsData member.

lpbOptionsData

Pointer to transport-provider option data specific to the recipient or message.

cOptionsProps

Number of properties in the array pointed to by the lpOptionsProps member.

lpOptionsProps

Pointer to an array of SPropValue structures, each holding information about a default option property.

Comments

The MAPI spooler logs onto a transport provider with the information that this provider can support a number of options specific to different e-mail address types. An option, for example, might indicate the use of a specific message cover page or direct a phone number be redialed a specific number of times. To register options, the spooler calls the IXPLogon::RegisterOptions method provided by the transport provider.

RegisterOptions writes one or two OPTIONDATA structures for each supported address type, depending on whether the provider is registered for both recipient and message options, recipient options only, or message options only. If a provider is registered for both option types, RegisterOptions writes one structure containing address information for message recipients and one containing address information for messages. For each structure, the ulFlags member indicates whether the options apply to a recipient or a message.

For an example of the use of OPTIONDATA, consider a transport provider that handles recipients for both Microsoft Mail and Microsoft Mail for the Macintosh. If the provider is registered for both recipient and message options, it provides two pairs of OPTIONDATA structures, one pair for each platform. The MAPI spooler can use this information to determine what options are valid for each platform. Once it has this option information, the spooler prompts the user with a dialog box to retrieve the actual settings for the options.

The DLL name in the lpszDLLname parameter should not indicate the operating system platform when OPTIONDATA is passed in the lppOptions parameter of the LXPLogon::Register method.

The OPTIONDATA structure is defined in MAPISPI.H.

See Also

IXPLogon::AddressTypes method, IXPLogon::RegisterOptions method, SPropValue structure


  PFNIDLE

PFNIDLE is a pointer type used to declare a MAPI idle function (that is, a function with the prototype FNIDLE).

Syntax

typedef FNIDLE	*PFNIDLE;

Comments

Functions based on FNIDLE are client application or service provider idle functions that the MAPI idle engine calls periodically according to priority; the specific functionality of such idle functions is defined by the application or provider.

The PFNIDLE type is defined in MAPIUTIL.H.

See Also

FNIDLE function


  SAndRestriction

An SAndRestriction structure holds a group of search restrictions that are combined using a logical AND operation.

Syntax

typedef struct _SAndRestriction

{

ULONG cRes;

LPSRestriction lpRes;

} SAndRestriction;

Members

cRes

Number of search restrictions in the array pointed to by the lpRes member.

lpRes

Pointer to an array of SRestriction structures to be combined with a logical AND operation.

Comments

The SAndRestriction structure is defined in MAPIDEFS.H.

See Also

SRestriction structure


  SAppTimeArray

An SAppTimeArray structure holds a pointer to an array of application time values for use in an SPropValue structure holding information about a property.

Syntax

typedef struct _SAppTimeArray

{

ULONG	cValues;

double	FAR *lpat;

} SAppTimeArray;

Members

cValues

Number of values in the array pointed to by the lpat member.

lpat

Pointer to an array of application time values.

Comments

The SAppTimeArray structure is defined in MAPIDEFS.H.


  SAVEOPTS

A SAVEOPTS enumeration holds a save options enumeration variable for use with the IMAPIForm::Close method.

Syntax

typedef enum tagSAVEOPTS

{

SAVEOPTS_SAVEIFDIRTY = 0,

SAVEOPTS_NOSAVE = 1,

SAVEOPTS_PROMPTSAVE = 2

} SAVEOPTS;

SAVEOPTS_NOSAVE

Indicates form data should not be saved.

SAVEOPTS_PROMPTSAVE

Prompts the user to save data related to the form if the form has changed.

SAVEOPTS_SAVEIFDIRTY

Indicates data related to the form should be saved if the form has changed.

Comments

The SAVEOPTS enumeration is defined in MAPIFORM.H.

See Also

IMAPIForm::ShutdownForm method


  SBinary

An SBinary structure holds a pointer to a property value of type PT_BINARY for use in an SPropValue structure holding information about a property.

Syntax

typedef struct _SBinary

{

ULONG	cb;

LPBYTE	lpb;

} SBinary, FAR *LPSBinary;

Members

cb

Size, in bytes, of the data pointed to by the lpb member.

lpb

Pointer to the PT_BINARY property value.

Comments

The SBinary structure is defined in MAPIDEFS.H.

See Also

SPropValue structure


  SBinaryArray

An SBinaryArray structure holds a property value of type PT_MV_BINARY for use in an SPropValue structure holding information about a multivalued property.

Syntax

typedef struct _SBinaryArray

{

ULONG cValues;

SBinary 	FAR *lpbin;

} SBinaryArray;

Members

cValues

Number of values in the array pointed to by the lpbin member.

lpbin

Pointer to an array of SBinary structures holding the multiple values for the property.

Comments

The SBinaryArray structure is defined in MAPIDEFS.H.

See Also

PT_MV_BINARY property type, SBinary structure, SPropValue structure


  SBitMaskRestriction

An SBitMaskRestriction structure holds a bitmask search restriction for objects such as tables and message stores.

Syntax

typedef struct _SBitMaskRestriction

{

ULONG relBMR;

ULONG ulPropTag;

ULONG ulMask;

} SBitMaskRestriction;

Members

relBMR

Relational operator that applies to all property comparison restrictions. Possible values are:

RELOP_GE

Indicates the comparison is made based on a greater or equal first value.

RELOP_GT

Indicates the comparison is made based on a greater first value.

RELOP_LE

Indicates the comparison is made based on a lesser or equal first value.

RELOP_LT

Indicates the comparison is made based on a lesser first value.

RELOP_NE

Indicates the comparison is based on unequal values.

RELOP_RE

Indicates the comparison is made on LIKE (regular expression) values.

RELOPEQ

Indicates the comparison is made based on equal values.

ulPropTag

Property tag of the property being masked in the search.

ulMask

Bitmask of flags.

Comments

The SBitmaskRestriction structure is defined in MAPIDEFS.H.

See Also

SRestriction structure


  SCommentRestriction

An SCommentRestriction structure holds a comment search restriction for objects such as tables and message stores.

Syntax

typedef struct _SCommentRestriction

{

ULONG cValues;

LPSRestriction lpRes;

LPSPropValue lpProp;

} SCommentRestriction;

Members

cValues

Number of values in the array pointed to by the lpProp member.

lpRes

Pointer to RES_COMMENT in an SRestriction structure.

lpProp

Pointer to an array of SPropValue structures, each holding information about a property. The method using the SCommentRestriction structure ignores the values of the properties when computing the restriction result.

Comments

The SCommentsRestriction structure is defined in MAPIDEFS.H.

See Also

SPropValue structure, SRestriction structure


  SComparePropsRestriction

An SComparePropsRestriction structure holds a search restriction that compares properties  for objects such as tables and message stores.

Syntax

typedef struct _SComparePropsRestriction

{

ULONG relop;

ULONG ulPropTag1;

ULONG ulPropTag2;

} SComparePropsRestriction;

Members

relop

Relational operator to use in the property comparison restriction .  Possible values are:

RELOP_GE

Indicates the comparison is made based on a greater or equal first value.

RELOP_GT

Indicates the comparison is made based on a greater first value.

RELOP_LE

Indicates the comparison is made based on a lesser or equal first value.

RELOP_LT

Indicates the comparison is made based on a lesser first value.

RELOP_NE

Indicates the comparison is based on unequal values.

RELOP_RE

Indicates the comparison is made on LIKE (regular expression) values.

RELOPEQ

Indicates the comparison is made based on equal values.

ulPropTag1

Property tag of the first property to be compared.

ulPropTag2

Property tag of the second property to be compared.

Comments

The comparison order is (property tag 1) (relational operator) (property tag 2). The two properties compared should be of the same type. Attempting to compare properties of different types commonly returns MAPI_E_TOO_COMPLEX.

The SComparePropsRestriction structure is defined in MAPIDEFS.H.

See Also

SBitMaskRestriction structure, SRestriction structure


  SContentRestriction

An SContentRestriction structure holds a search restriction for a search of message contents through messages that are part of objects such as tables and message stores.

Syntax

typedef struct _SContentRestriction

{

ULONG ulFuzzyLevel;

ULONG ulPropTag;

LPSPropValue lpProp;

} SContentRestriction;

Members

ulFuzzyLevel

Fuzzy level defining options for a message contents search. The lower 16 bits contain a code with the following possible values:

FL_FULLSTRING

The comparison deals with property types PT_STRING8 and PT_BINARY. The function checks to see if the property value indicated by lpSPropValueSrc is contained as a full string in the other property.

FL_PREFIX

The comparison deals with property types PT_STRING8 and PT_BINARY. The function compares the values of the two properties only up to the length of the property indicated by lpSPropValueSrc.

FL_SUBSTRING

The comparison deals with property types PT_STRING8 and PT_BINARY. The function checks to see if the property value indicated by lpSPropValueSrc is contained as a substring in the other property.

The upper 16 bits of the fuzzy level make up a bitmask of flags defining different options for comparing character strings within messages. The following flags can be set:

FL_IGNORECASE

The comparison deals only with PT_STRING8 properties. The function makes the comparison in case-insensitive fashion.

FL_IGNORENONSPACE

The comparison deals only with PT_STRING8 properties. The function makes the comparison so as to ignore Unicode-defined "nonspacing characters," for example, diacritical marks.

FL_LOOSE

The comparison deals only with PT_STRING8 properties. The service provider performs as many fuzzy level heuristics of types FL_IGNORECASE and FL_IGNORESPACE as it has been designed to handle.

ulPropTag

Property tag for the property pointed to by the lpProp member. MAPI requires only the property type within this tag and ignores the property identifier portion.

lpProp

Pointer to the SPropValue structure holding information about a property.

Comments

The error value MAPI_E_TOO_COMPLEX is returned if the data type of the property to be checked in the ulPropTag member doesn't match the data type indicated by the lpProp pointer.

The SContentRestriction structure is defined in MAPIDEFS.H.

See Also

SPropValue structure, SRestriction structure


  SCurrencyArray

An SCurrencyArray structure holds a property value of type PT_MV_CURRENCY for use in an SPropValue structure holding information about a multivalued property.

Syntax

typedef struct _SCurrencyArray

{

ULONG cValues;

CURRENCY FAR *lpcur;

} SCurrencyArray;

Members

cValues

Number of values in the array pointed to by the lpcur member.

lpcur

Pointer to an array of CURRENCY structures holding the multiple values for the property.

Comments

The SCurrencyArray structure is defined in MAPIDEFS.H.

See Also

PT_MV_CURRENCY property type, SPropValue structure


  SDateTimeArray

An SDateTimeArray structure holds a property value of type PT_MV_SYSTIME for use in an SPropValue structure holding information about a multivalued property.

Syntax

typedef struct _SDateTimeArray

{

ULONG cValues;

FILETIME FAR *lpft;

} SDateTimeArray;

Members

cValues

Number of values in the array pointed to by the lpft member.

lpft

Pointer to an array of FILETIME structures holding the multiple values for the property.

Comments

The SDateTimeArray structure is defined in MAPIDEFS.H.

See Also

FILETIME structure, PT_MV_SYSTIME property type, SPropValue structure


  SDoubleArray

An SDoubleArray structure holds a property value of type PT_MV_DOUBLE for use in an SPropValue structure holding information about a multivalued property.

Syntax

typedef struct _SDoubleArray

{

ULONG	cValues;

double	FAR *lpdbl;

} SDoubleArray;

Members

cValues

Number of values in the array pointed to by the lpdbl member.

lpdbl

Pointer to the array of double values making up the property.

Comments

The SDoubleArray structure is defined in MAPIDEFS.H.

See Also

PT_MV_DOUBLE property type, SPropValue structure


  SExistRestriction

An SExistRestriction structure holds a search restriction for a search to determine whether a property exists for an object such as a table or message store.

Syntax

typedef struct _SExistRestriction

{

ULONG ulReserved1;

ULONG ulPropTag;

ULONG ulReserved2;

} SExistRestriction;

Members

ulReserved1

Reserved; must be zero.

ulPropTag

Property tag of the property to be tested.

ulReserved2

Reserved; must be zero.

Comments

The SExistRestriction structure is defined in MAPIDEFS.H.

See Also

SRestriction structure


  SGuidArray

An SGuidArray structure holds a property value of type PT_MV_CLSID for use in an SPropValue structure holding information about a multivalued property.

Syntax

typedef struct _SGuidArray

{

ULONG	cValues;

GUID 	FAR *lpguid;

} SGuidArray;

Members

cValues

Number of values in the array pointed to by the lpguid member.

lpguid

Pointer to an array of property values for use in the SPropValue structure.

Comments

The SGUIDArray structure is defined in MAPIDEFS.H.

See Also

GUID structure, PT_MV_CLSID property type, SPropValue structure


  SLargeIntegerArray

An SLargeIntegerArray structure holds a property value of type PT_MV_I8 for use in an SPropValue structure holding information about a multivalued property.

Syntax

typedef struct _SLargeIntegerArray

{

ULONG	cValues;

LARGE_INTEGER 	FAR *lpli;

} SLargeIntegerArray;

Members

cValues

Number of values in the array pointed to by the lpli member.

lpli

Pointer to an array of LARGE_INTEGER structures holding the multiple values for the property.

Comments

The SLargeIntegerArray structure is defined in MAPIDEFS.H.

See Also

LARGE_INTEGER structure, PT_MV_I8 property type, SPropValue structure


  SLongArray

An SLongArray structure holds a property value of type PT_MV_LONG for use in an SPropValue structure holding information about a multivalued property.

Syntax

typedef struct _SLongArray

{

ULONG	cValues;

LONG	 FAR *lpl;

} SLongArray;

Members

cValues

Number of values in the array pointed to by the lpl member.

lpl

Pointer to the array of long values making up the property.

Comments

The SLongArray structure is defined in MAPIDEFS.H.

See Also

PT_MV_LONG property type, SPropValue structure


  SLPSTRArray

An SLPSTRArray structure holds a property value of type PT_MV_STRING8 for use in an SPropValue structure holding information about a multivalued property.

Syntax

typedef struct _SLPSTRArray

{

ULONG cValues;

LPSTR FAR *lppszA;z

} SLPSTRArray;

Members

cValues

Number of values in the array pointed to by the lppszA member.

lppszA

Pointer to the array of null-terminated 8-bit character strings making up the property.

Comments

The SLPSTRArray structure is defined in MAPIDEFS.H.

See Also

PT_MV_STRING8 property type, SPropValue structure


  SMAPIFormInfoArray

Contains a list of pointers to IMAPIFormInfo interfaces.

Syntax

typedef struct

{

ULONG cForms;

LPMAPIFORMINFO aFormInfo[MAPI_DIM];

} SMAPIFormInfoArray, FAR * LPSMAPIFORMINFOARRAY;

Members

cForms

Number of IMAPIFormInfo interface pointers in this structures list.

aFormInfo

Names the first pointer in the list of interface pointers.

Comments

This structure is passed as a parameter in the IMAPIFormMgr methods ResolveMultipleMessageClasses, CalcFormPropSet, SelectMultipleForms and the IMAPIFormContainer method ResolveMultipleMessageClasses.

Use the CbMAPIFormInfoArray macro to determine the minimum number of bytes that are required to hold an SMAPIFormInfoArray containing a specified number of IMAPIFormInfo interface pointers. The syntax is:

int CbMAPIFormInfoArray (int  _c)

The parameter _c specifies the number of IMAPIFormInfo interface pointers. This macro returns the number of bytes of memory needed to hold a SMAPIFormInfoArray containing _c pointers.

The SMAPIFormInfoArray structure is defined in MAPIFORM.H.

See Also

IMAPIFormContainer::ResolveMultipleMessageClasses method, IMAPIFormMgr::CalcFormPropSet method, IMAPIFormMgr::ResolveMultipleMessageClasses method, IMAPIFormMgr::SelectMultipleForms method


  SMAPIFormProp

An SMAPIFormProp structure holds a form property used with form interfaces.

Syntax

typedef struct _SMAPIFormProp

{

ULONG 	ulFlags;

ULONG	nPropType;

MAPINAMEID	nmid;

LPTSTR	pszDisplayName;

FORMPROPSPECIALTYPE	nSpecialType;

union

{

struct

{

MAPINAMEID	nmidIdx;

ULONG	cfpevAvailable;

LPMAPIFormPropEnumVal 	pfpevAvailable;

} s1;

} u;

} SMAPIFormProp;

Members

nPropType

Property type of the form property, with the most significant word equal to zero.

nmid

MAPINAMEID structure containing the property's globally unique identifier (GUID) and a form kind, made up of an interface identifier and the form's name.

pszDisplayName

Pointer to the display name of the property.

nSpecialType

Special type tag defined in the FORMPROPSPECIALTYPE enumeration. This tag applies to the u union.

nmidIdx

MAPINAMEID structure containing the identifier for the interface implementing the property.

cfpevAvailable

Number of SMAPIFormPropEnumVal structures in the array pointed to by the pfpevAvailable member.

pfpevAvailable

Pointer to an array of SMAPIFormPropEnumVal structures, each of which holds a value for a form property.

ulFlags

Undefined.

Comments

The SMAPIFormProp structure is defined in MAPIDEFS.H.

See Also

FORMPROPSPECIALTYPE structure, MAPINAMEID structure, SMAPIFormPropEnumVal structure


  SMAPIFormPropArray

An SMAPIFormPropArray structure contains a list of form properties, i.e., SMAPIFormProp structures.

Syntax

typedef struct

{

ULONG cProps;

ULONG ulPad;

SMAPIFormProp aFormProp[MAPI_DIM];

} SMAPIFormPropArray, FAR * LPMAPIFORMPROPARRAY;

Members

cProps

Number of verbs in the list.

ulPad

An eight byte pad used for alignment of the SMAPIFormPropArray.aFormProp

Names the first form property in the list.

Comments

This structure is passed as a parameter in the methods IMAPIFormInfo::CalcFormPropSet, IMAPIFormMgr::CalcFormPropSet, IMAPIFormContainer::CalcFormPropSet.

Use the CbMAPIFormPropArray macro to determine the memory allocation requirements for an SMAPIFormPropArray containing a specified number of form properties, i.e. a specified number of SMAPIFormProp structures. The syntax is:

int CbMAPIFormPropArray (int  _c)

The parameter _c specifies the number of form properties. This macro returns the number of bytes of memory needed to hold an SMAPIFormPropArray containing _c form properties.

The SMAPIFormPropArray structure is defined in MAPIFORM.H.

See Also

CbMAPIFormPropArray macro, IMAPIFormContainer::CalcFormPropSet method, IMAPIFormInfo::CalcFormPropSet method, IMAPIFormMgr::CalcFormPropSet method, SMAPIFormProp structure


  SMAPIFormPropEnumVal

An SMAPIFormPropEnumVal structure holds a value for a form property for use as part of the SMAPIFormProp structure.

Syntax

typedef struct _SMAPIFormPropEnumVal

{

SPropValue	val;

ULONG nVal;

} SMAPIFormPropEnumVal;

Members

val

SPropValue structure holding information about the form property.

nVal

Enumeration value for the structure in the val member.

Comments

The SMAPIFormProp structure holds form property information used in forms definitions.

The SMAPIFormPropEnumVal structure is defined in MAPIDEFS.H.

See Also

SMAPIFormProp structure, SPropValue structure


  SMAPIVerb

An SMAPIVerb structure contains arrays of MAPI verbs.

Syntax

typedef struct

{

LONG lVerb;

LPTSTR szVerbname;

DWORD fuFlags;

DWORD grfAttribs;

ULONG ulFlags;	/* Either 0 or MAPI_UNICODE */

} SMAPIVerb, FAR * LPMAPIVERB;

Members

ulFlags

Bitmask of flags. If the szVerbname member has Unicode format, the following flag can be set:

MAPI_UNICODE

Indicates the passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in 8-bit format.

Comments

This structure is passed as a parameter in the IMAPIFormMgr and IMAPIFormContainer method ResolveMultipleMessageClasses.

The SMAPIVerb structure is defined in MAPIFORM.H.

See Also

CbMessageClassArray macro, IMAPIFormContainer::ResolveMultipleMessageClasses method, IMAPIFormMgr::ResolveMultipleMessageClasses method


  SMAPIVerbArray

An SMAPIVerbArray structure contains a list of MAPI verbs, i.e. SMAPIVerb structures.

Syntax

typedef struct

{

ULONG cMAPIVerb;

SMAPIVerb aMAPIVerb[MAPI_DIM];

} SMAPIVerbArray, FAR * LPMAPIVERBARRAY;

Members

cForms

Number of verbs in the list.

aFormInfo

Names the first verb in the list.

Comments

This structure is passed as a parameter in the method IMAPIFormInfo::CalcVerbSet.

Use the cbMAPIVerbArray macro to determine the memory allocation requirements of an SMAPIVerbArray containing a specified number of verbs, i.e. a specified number of SMAPIVerb structures. The syntax is:

int CbMAPIVerbArray (int  _c)

The parameter _c specifies the number of verbs. This macro returns the number of bytes of memory needed to hold an SMAPIVerbArray containing _c verbs.

The SMAPIVerbArray is defined in MAPIFORM.H.

See Also

IMAPIFormInfo::CalcVerbSet method, SMAPIVerb structure


  SMessageClassArray

An SMessageClassArray structure contains a list of message class string pointers.

Syntax

typedef struct

{

ULONG cValues;

LPCSTR aMessageClass[MAPI_DIM];

} SMessageClassArray, FAR * LPSMESSAGECLASSARRAY;

Members

cValues

The number of message class string pointers in this structure.

aMessageClass

Names the first pointer in the list of message class string pointers.

Comments

This structure is passed as a parameter in the IMAPIFormMgr and IMAPIFormContainer method ResolveMultipleMessageClasses.

Use the cbMessageClassArray macro to determine the minimum number of bytes that are required to hold an SMessageClassArray containing a specified number of message class string pointers. The syntax is:

int CbMessageClassArray (int  _c)

The parameter _c specifies the number of message class string pointers. This macro returns the number of bytes of memory needed to hold a SMessageClassArray containing _c pointers.

The SMessageClassArray structure is defined in MAPIDEFS.H.

See Also

IMAPIFormContainer::ResolveMultipleMessageClasses method, IMAPIFormMgr::ResolveMultipleMessageClasses method


  SNotRestriction

An SNotRestriction structure holds a group of search restrictions to which a logical NOT operation has been applied.

Syntax

typedef struct _SNotRestriction

{

ULONG ulReserved;

LPSRestriction lpRes;

} SNotRestriction;

Members

ulReserved

Reserved; must be zero.

lpRes

Pointer to an array of SRestriction structures holding the restrictions to be included in the logical NOT operation.

The SNotRestriction structure is defined in MAPIDEFS.H.

See Also

SRestriction structure


  SOrRestriction

An SOrRestriction structure holds a group of search restrictions combined using a logical OR operation.

Syntax

typedef struct _SOrRestriction

{

ULONG cRes;

LPSRestriction lpRes;

} SOrRestriction;

Members

cRes

Number of structures in the array pointed to by the lpRes member.

lpRes

Pointer to an array of SRestriction structures defining the restrictions to be combined using the logical OR operation.

Comments

The SOeRestriction structure is defined in MAPIDEFS.H.

See Also

SRestriction structure


  SPropAttrArray

An SPropAttrArray structure holds a list of attributes for a MAPI property.

Syntax

typedef struct

{

ULONG	cValues;

ULONG	aPropAttr[MAPI_DIM];

} SPropAttrArray, FAR *LPSPropAttrArray;

Members

cValues

Number of property attributes in the array in the aPropAttr member.

aPropAttr

Array of property attributes. Attributes that can be placed in this list are:

PROPATTR_MANDATORY

PROPATTR_READABLE

PROPATTR_WRITEABLE

PROPATTR_NOT_PRESENT

Comments

Use the CbSPropAttrArray macro to determine the number of bytes occupied by an existing SPropAttrArray. The syntax is:

int CbSPropAttrArray (LPSPROPATTRARRAY  _lparray)

The _lparray parameter is a pointer to an SPropAttrArray structure. This macro returns the number of bytes of memory occupied by the SPropAttrArray structure.

Use the CbNewSPropAttrArray macro to determine the memory allocation requirement of an SPropAttrArray structure containing a specified number of property attributes. The syntax is:

int CbNewSPropAttrArray (int  _c)

The parameter _c specifies the number of property attributes. This macro returns the number of bytes of memory needed to hold an SPropAttrArray containing _c property attributes.

The SPropAttrArray structure is defined in IMESSAGE.H.


  SPropertyRestriction

An SPropertyRestriction structure holds a search restriction that compares a property to a constant for a search on an object such as a table or message store.

Syntax

typedef struct _SPropertyRestriction

{

ULONG relop;

ULONG ulPropTag;

LPSPropValue lpProp;

} SPropertyRestriction;

Members

relop

Relational operator to be used in the search. Possible values are:

RELOP_GE

Indicates the comparison is made based on a greater or equal first value.

RELOP_GT

Indicates the comparison is made based on a greater first value.

RELOP_LE

Indicates the comparison is made based on a lesser or equal first value.

RELOP_LT

Indicates the comparison is made based on a lesser first value.

RELOP_NE

Indicates the comparison is based on unequal values.

RELOP_RE

Indicates the comparison is made on LIKE (regular expression) values.

RELOP_EQ

Indicates the comparison is made based on equal values.

ulPropTag

Property tag for the property involved.

lpProp

Pointer to an SPropValue structure holding the property. MAPI requires only the property type within this SPropValue structure and ignores the property identifier portion.

Comments

The comparison order is (property value) (relational operator) (constant value).

The method returns the error value MAPI_E_TOO_COMPLEX when the type of the property to be checked does not match the tag in the ulPropTag member.

The SPropertyRestriction structure is defined in MAPIDEFS.H.

See Also

SPropValue structure, SRestriction structure


  SPropProblem

An SPropProblem structure holds an SCODE error value that is a result of an operation attempting to modify or delete a MAPI property.

Syntax

typedef struct _SPropProblem {

ULONG	ulIndex;

ULONG	ulPropTag;

SCODE	scode;

} SPropProblem, FAR *LPSPropProblem;

Members

ulIndex

Index in an array of property tags of the property for which a problem is indicated.

ulPropTag

Property tag for the property.

scode

Error code indicating the property problem encountered during the update. This code can be any SCODE value.

Comments

The SPropProblem structure is defined in MAPIDEFS.H.

See Also

SCODE data type, SPropProblemArray structure


  SPropProblemArray

An SPropProblemArray structure holds an array of one or more SPropProblem structures, each of which holds an SCODE error value that is a result of an operation attempting to modify or delete a MAPI property.

Syntax

typedef struct _SPropProblemArray {

ULONG cProblem;

SPropProblem aProblem[MAPI_DIM];

} SPropProblemArray, FAR *LPSPropProblemArray;

Members

cProblem

Number of problem structures in the array indicated by the aProblem member.

aProblem

Array of SPropProblem structures, each holding a property error.

Comments

The SPropProblemArray structure is defined in MAPIDEFS.H.

See Also

SCODE data type, SPropProblem structure


  SPropTagArray

An SPropTagArray structure contains an array of property tags.

Syntax

typedef struct _SPropTagArray {

ULONG cValues;

ULONG aulPropTag[MAPI_DIM];

} SPropTagArray, FAR *LPSPropTagArray;

Members

cValues

Number of property tags in the array indicated by the aulPropTag member.

aulPropTag

Array of property tags.

Comments

The CbSPropTagArray macro determines the number of bytes occupied by an existing SPropTagArray. The syntax is:

int CbSPropTagArray (LPSPropTagArray _lparray)

The _lparray specifies a pointer to an SPropTagArray. This macro returns the number of bytes of memory occupied by the SPropTagArray structure pointed to by _lparray.

The CbNewSPropTagArray macro determines the memory allocation requirements of an SPropTagArray containing a specified number of property tags. The syntax is:

int CbNewSPropTagArray (int _ctag)

The _ctag parameter specifies the number of property tags. This macro returns the number of bytes of memory occupied by an SPropTagArray structure that contains _ctag property tags.

The SizedSPropTagArray macro creates a structure definition identical to that of SPropTagArray but with a specified number of property tags. Use the SizedSPropTagArray macro to create property tag arrays with explicit bounds. The syntax is:

SizedSPropTagArray (int _ctag, _name)

The parameter _ctag specifies the number of property tags to be in the property tag array aulPropTag. The structure type is defined with the tag _SPropTagArray_ _name and type name _name.

To use a sized property tag array pointer lpSizedSPropTagArray in any function call or structure that expects a LPSPropTagArray pointer, perform the following cast:

lpSPropTagArray = (LPSPropTagArray) lpSizedSPropTagArray.

The SPropTagArray structure is defined in MAPIDEFS.H.


  SPropValue

An SPropValue structure holds a MAPI property, including its property tag and property value.

Syntax

typedef struct _SPropValue

{

ULONG	ulPropTag;

ULONG	dwAlignPad;

union _PV  Value;

} SPropValue, FAR *LPSPropValue;

Members

ulPropTag

Property tag for the property. This tag consists of a code for the property type in the lower 16 bits and a code for the property identifier in the upper 16 bits.

dwAlignPad

Padding bytes to properly align the information indicated by the Value member.

Value

Property value from the _UPV union.

Comments

A _UPV union, used in the Value member of the SPropValue structure, defines the possible values for a MAPI property. The syntax for the _UPV union is as follows:

typedef union _PV

{

short int	i;

LONG	l;

ULONG	ul;

float	flt;

double	dbl;

unsigned short int	b;

CURRENCY	cur;

double	at;

FILETIME	ft;

LPSTR	lpszA;

SBinary	bin;

LPWSTR	lpszW;

LPGUID	lpguid;

LARGE_INTEGER	li;

SShortArray	 MVi;

SLongArray	 MVl;

SRealArray	 MVflt;

SDoubleArray	MVdbl;

SCurrencyArray	MVcur;

SAppTimeArray	MVat;

SDateTimeArray	MVft;

SBinaryArray	MVbin;

SLPSTRArray	MVszA;

SWStringArray	MVszW;

SGuidArray	MVguid;

SLargeIntegerArray	MVli;

SCODE	err;

LONG	x;

} _UPV;

The members of the _UPV union contain the following information:

i

Property value of the property for which the SPropValue structure holds information if the property's type is PT_I2.

l

Property value if the property's type is PT_LONG and the property value is a LONG integer.

ul

Property value if the property's type is PT_LONG and the property value is an unsigned LONG integer.

flt

Property value if the property's type is PT_R4.

dbl

Property value if the property's type is PT_DOUBLE.

b

Property value if the property's type is PT_BOOLEAN.

cur

Property value if the property's type is PT_CURRENCY.

at

Property value if the property's type is PT_APPTIME.

ft

Property value if the property's type is PT_SYSTIME.

lpszA

Property value if the property's type is PT_STRING8.

bin

Property value if the property's type is PT_BINARY.

lpszW

Property value if the property's type is PT_UNICODE.

lpguid

Property value if the property's type is PT_CLSID.

li

Property value if the property's type is PT_I8.

MVi

Property value if the property's type is PT_MV_I2.

MVl

Property value if the property's type is PT_MV_LONG.

MVflt

Property value if the property's type is PT_MV_R4.

MVdbl

Property value if the property's type is PT_MV_DOUBLE.

MVcur

Property value if the property's type is PT_MV_CURRENCY.

MVat

Property value if the property's type is PT_MV_APPTIME.

MVft

Property value if the property's type is PT_MV_SYSTIME.

MVbin

Property value if the property's type is PT_MV_BINARY.

MVszA

Property value if the property's type is PT_MV_STRING8.

MVszW

Property value if the property's type is PT_MV_UNICODE.

MVguid

Property value if the property's type is PT_MV_CLSID.

MVli

Property value if the property's type is PT_MV_I8.

err

Property value if the property's type is PT_ERROR.

x

Property value if the property's type is PT_NULL or PT_OBJECT.

Five macros to set data types, flags, or to return property or type or property identifier value.

CHANGE_PROP_TYPE

MVI_PROP

PROP_ID

PROP_TAG

PROP_TYPE

Use the CHANGE_PROP_TYPE macro to set the data type of the supplied MAPI property tag without changing the property identifier part of the tag. The syntax is:

ULONG CHANGE_PROP_TYPE (ULONG ulPropTag,ULONG ulPropType)

The ulPropTag parameter specifies the property tag. The ulPropType parameter specifies the value of the property type to set within ulPropTag. This macro returns a property tag with the property ID set to ulPropTag and with the property type set to ulPropType.

Use the MVI_PROP macro to set the MV_FLAG and MV_INSTANCE flags for the supplied property tag. The property identifier and property type are otherwise unchanged. The syntax is:

ULONG  MVI_PROP (ULONG tag)

The parameter  tag is the property tag that will have its MVI_FLAG bits set; this macro returns the property tag with its MVI_FLAG bits set. The MVI_FLAG represents the logical or of the MV_FLAG and the MV_INSTANCE flags.

The MV_FLAG indicates a multi-valued property. The MV_INSTANCE flag is used in table operations to request that a multi-valued property be presented as a single-valued property appearing in multiple rows.

For example, when the input property tag contains the type PT_FLOAT, the returned property tag specifies the type PT_MVI_FLOAT; that is, PT_MV_FLOAT with the MV_INSTANCE bit set. All single-valued types have corresponding multi-valued types.

The PROP_ID macro returns the property ID value from the supplied property tag. The syntax is:

ULONG  PROP_ID (ULONG ulPropTag)

The parameter ulPropTag specifies a property tag for which you want to obtain the property ID. This macro returns the property ID in the low-order word (bits 0-15) and zeroes in the high-order word (bits 16-31). Bits 0-15 of the return value are equal to bits 16-31 of the supplied ulPropTag.

Use the PROP_TAG macro to return a property tag constructed from the supplied property type and the supplied property identifier.

The low-order 16 bits of the returned property tag contains the type and the high-order 16 bits of the returned tag contains the property identifier. The syntax is:

ULONG  PROP_TAG (ulPropType, ulPropID)

The parameter ulPropType specifies the property type to be used in the property tag. The parameter ulPropID specifies the property identifier.  This macro returns a property tag with a data type of ulPropType and identifier ulPropID.

For example, the property tag PR_ENTRYID is formed by using the PROP_TAG macro as follows: PROP_TAG( PT_BINARY, 0x0FFF).

The PROP_TYPE macro returns the property type of the supplied property tag. The syntax is:

ULONG  PROP_TYPE (ULONG ulPropTag)

The parameter ulPropTag specifies a property tag. This macro returns the low-order 16 bits of the property tag, which contain the value that represents the property type. The high-order 16 bits in the return value are set to 0. For example, PROP_TYPE(PR_ENTRYID) returns the value PT_BINARY.

The SPropValue structure is defined in MAPIDEFS.H.

See Also

Extended MAPI Property Types


  SRealArray

An SRealArray structure holds a property value of type PT_FLOAT for use in an SPropValue structure holding information about a multivalued property.

Syntax

typedef struct _SRealArray

{

ULONG	cValues;

float	FAR *lpflt;

} SRealArray;

Members

cValues

Number of values in the array pointed to by the lpflt member.

lpflt

Pointer to an array of float values making up the property.

Comments

The SRealArray structure is defined in MAPIDEFS.H.

See Also

PT_FLOAT property type SPropValue structure


  SRestriction

An SRestriction structure holds a search restriction or a set of search restrictions.

Syntax

typedef struct _SRestriction

{

ULONG	rt;

union {

SComparePropsRestriction resCompareProps;

SAndRestriction resAnd;

SOrRestriction resOr;

SNotRestriction resNot;

SContentRestriction resContent;

SPropertyRestriction resProperty;

SBitMaskRestriction resBitMask;

SSizeRestriction resSize;

SExistRestriction resExist;

SSubRestriction resSub;

SCommentRestriction resComment;

} res;

} SRestriction;

Members

rt

Restriction type. Possible values are:

Value	Level	Meaning
0	RES_AND	A logical AND restriction, defined by an SAndRestriction structure.
1	RES_OR	A logical OR restriction, defined by an SOrRestriction structure.
2	RES_NOT	A logical NOT restriction, defined by an SNotRestriction structure.
3	RES_CONTENT	A message content restriction, defined by an SContentRestriction structure.
4	RES_PROPERTY	A property restriction, defined by an SPropertyRestriction structure.
5	RES_COMPAREPROPS	A property comparison restriction, defined by an SComparePropsRestriction structure.
6	RES_BITMASK	A bitmask restriction, defined by an SBitMaskRestriction structure.
7	RES_SIZE	A size restriction, defined by an SSizeRestriction structure.
8	RES_EXIST	A property existence restriction, defined by an SExistRestriction structure.
9	RES_SUBRESTRICTION	A subrestriction restriction, defined by an SSubRestrictionRestriction structure.
A	RES_COMMENT	A comment restriction, defined by an SCommentRestriction structure.
resCompareProps

An SComparePropsRestriction structure. This structure is the first in the union to accommodate static initializations of three-value restrictions.

resAnd

An SAndRestriction structure.

resOr

An SOrRestriction structure.

resContent

An SContentRestriction structure.

resProperty

An SPropertyRestriction structure.

resBitMask

An SBitMaskRestriction structure.

resSize

An SSizeRestriction structure.

resExist

An SExistRestriction structure.

resSub

An SSubRestriction structure.

resComment

An SCommentRestriction structure.

Comments

A client application uses SRestriction structures in calls to the IMAPITable::Restrict and (for search-results folders) IMAPIContainer::SetSearchCriteria methods. An application can also use SRestriction with the IMAPITable::FindRow method to find table rows with certain attributes.

These three methods use SRestriction structures for locating and selecting an item or items based on the set of criteria incorporated in the SRestriction. During a search or restriction operation, a client application evaluates each object in a table or folder in terms of the SRestriction criteria. Only an object that matches the search restriction is included as a result of the search.

The SRestriction structure is defined in MAPIDEFS.H.

See Also

SAndRestriction structure, SBitMaskRestriction structure, SCommentRestriction structure, SComparePropsRestriction structure, SContentRestriction structure, SExistRestriction structure, SNotRestriction structure, SOrRestriction structure, SPropertyRestriction structure, SSizeRestriction structure, SSubRestriction structure, IMAPIContainer::SetSearchCriteria method, IMAPITable::FindRow method, IMAPITable::Restrict method


  SRow

An SRow structure holds a table row containing selected properties for a specific object.

Syntax

typedef struct _SRow {

ULONG ulAdrEntryPad;

ULONG cValues;

LPSPropValue lpProps;

} SRow, FAR *LPSRow;

Members

ulAdrEntryPad

Padding bytes to properly align the information pointed to by the lpProps member.

cValues

Number of values in the array pointed to by lpProps.

lpProps

Pointer to an array of SPropValue structures. Each SPropValue structure represents column within the SRow.

Comments

SRows typically exist as components of SRowSet structures. These structures are used to represent MAPI table rows and MAPI tables, respectively.

Each instance of an SRow lpProps member in an SRowSet must be allocated (using MAPIAllocateBuffer) separately from the SRowSet. A row's allocated memory can then be preserved and reused outside of the context of the SRowSet.

The lpProps members must be deallocated prior to deallocation of the containing SRowSet so that pointers to allocated SPropValue structures are not lost.

The SRow structure is defined in MAPIDEFS.H.

See Also

ADRLIST structure, SPropValue structure, SRowSet structure


  SRowSet

An SRowSet structure holds a set of table rows; each row in this set of rows contains selected properties for a specific object.

Syntax

typedef struct _SRowSet
{
ULONG cRows;
SRow aRow[MAPI_DIM];
} SRowSet, FAR *LPSRowSet;

Members

cRows

Number of rows in the array indicated by the aRow member.

aRow

Array of SRow structures, one for each table row.

Comments

The MAPI function HrQueryAllRows retrieves MAPI table rows into this structure.

The structure member types and allocation rules for SRows and ADRENTRYs are identical. SRowSet structures can be cast into ADRLISTs to which IMessage::ModifyRecipients and IAddrBook::Address can then be applied.

See SRow for allocation rules for SRowSet structures and their associated SRow structures.

Use the CbSRowSet macro to determine the number of bytes of memory occupied by an existing SRowSet structure. The syntax for this macro is:

int CbSRowSet (LPSRowSet _lpSRowSet)

The parameter _lpSRowSet specifies a pointer to an SRowSet structure. This macro returns the number of bytes occupied by the SRowSet structure pointed to by _lpSRowSet.

Use the cbNewSRowSet macro to determine the memory allocation requirements of an SRowSet structure containing a specified number of rows. The syntax is:

int CbNewSRowSet (int _crow)

The parameter _crow specifies the number of rows, i.e., the number of elements of type SRow in the aRow member. This macro returns the number of bytes of memory that an SRowSet with _crow rows would occupy.

The SizedSRowSet macro creates a structure definition identical to that of SRowSet but with a specified number of rows. The syntax is:

SizedSRowSet (int _crow, _name)

The parameter _crow specifies the number of rows. The structure type is defined with the tag _SRowSet_ _name and type name _name.

To use a sized property tag array pointer lpSizedSRowSet in any function call or structure that expects a LPSRowSet pointer, perform the following cast:

lpSRowSet = (LPSRowSet) lpSizedSRowSet.

The SRowSet structure is defined in MAPIDEFS.H.

See Also

ADRLIST structure, HrQueryAllRows function, SRow structure


  SShortArray

An SShortArray structure holds a property value of type PT_MV_SHORT for use in an SPropValue structure holding information about a multivalued property.

Syntax

typedef struct _SShortArray

{

ULONG	cValues;

short int	FAR *lpi;

} SShortArray;

Members

cValues

Number of values in the array pointed to by the lpi member.

lpi

Pointer to an array of short values making up the property.

Comments

The SRowSet structure is defined in MAPIDEFS.H.

See Also

PT_MV_SHORT property type, SPropValue structure


  SSizeRestriction

An SSizeRestriction structure holds a size search restriction for objects such as tables and message stores.

Syntax

typedef struct _SSizeRestriction

{

ULONG relop;

ULONG ulPropTag;

ULONG cb;

} SSizeRestriction;

Members

relop

Relational operator used in the size comparison.  Possible values are:

RELOP_GE

Indicates the comparison is made based on a greater or equal first value.

RELOP_GT

Indicates the comparison is made based on a greater first value.

RELOP_LE

Indicates the comparison is made based on a lesser or equal first value.

RELOP_LT

Indicates the comparison is made based on a lesser first value.

RELOP_NE

Indicates the comparison is based on unequal values.

RELOP_RE

Indicates the comparison is made on LIKE (regular expression) values.

RELOPEQ

Indicates the comparison is made based on equal values.

ulPropTag

Property tag.

cb

Size, in bytes, of the property value.

Comments

The SSizeRestriction structure is defined in MAPIDEFS.H.

See Also

SRestriction structure


  SSortOrder

A SSortOrder structure defines the sort order of data in a table.

Syntax

typedef struct _SSortOrder

{

ULONG ulPropTag;

ULONG ulOrder;

} SSortOrder, FAR *LPSSortOrder;

Members

ulPropTag

Property tag of the column on which the table is to be sorted.

ulOrder

Order in which the data is to be sorted. Possible values are:

TABLE_SORT_ASCEND

Sorts the table in ascending order.

TABLE_SORT_COMBINE

Indicates that the provider should not show this as a separate category, but should instead combine it with the category to its left. Using this flag reduces the number of category rows which are displayed. This flag can be used on multiple adjacent columns for multiple combinations.

TABLE_SORT_DESCEND

Sorts the table in descending order.

   Comments

The SSortOrder structure is defined in MAPIDEFS.H.

See Also

SSortOrderSet structure


  SSortOrderSet

An SSortOrderSet structure defines a set of sort orders for a table, each order indicating on which column the table is to be sorted.

Syntax

typedef struct _SSortOrderSet

{

ULONG cSorts;

ULONG cCategories;

ULONG cExpanded;

SSortOrder aSort[MAPI_DIM];

} SSortOrderSet, FAR *LPSSortOrderSet;

Members

cSorts

Number of columns on which to sort the table in the array in the aSort member.

cCategories

Number of categories of data to be sorted. Possible values range from zero, which indicates a noncategorized sort, up to the number indicated by the cSorts member.

cExpanded

Number of categories that start in an expanded condition. . Possible values include zero.

aSort

Array of SSortOrder structures, each defining a sort order.

Comments

Use the CbSSortOrderSet macro to determine the number of bytes of memory occupied by an existing SSortOrderSet structure. The syntax is:

int CbSSortOrderSet (LPSSortOrderSet _lpSSortOrderSet)

The parameter lpSSortOrderSet specifies a pointer to an SSortOrderSet structure. This macro returns the number of bytes occupied by the SSortOrderSet structure pointed to by _lpSSortOrderSet.

The CbNewSSortOrderSet macro determines the memory allocation requirements of an SSortOrderSet structure containing a specified number of sort orders. The syntax is:

int CbNewSSortOrderSet (int _csort)

The _csort parameter specifies the number of sort orders, i.e., the number of elements of type SSortOrder in the aSort member. This macro returns the number of bytes of memory that an SSortOrderSet with _csort sort orders would occupy.

The SizedSSortOrderSet macro creates a structure definition identical to that of SSortOrderSet but specifies the number columns to sort on. Use the SizedSSortOrderSet macro to create sort order sets with explicit bounds. The syntax is:

SizedSSortOrderSet (int _csort, _name)

The parameter _crow specifies the number of sort orders. The structure type is defined with the tag _SSortOrderSet_ _name and type name _name.

To use a sized sort order set pointer lpSizedSSortOrderSet in any function call or structure that expects a LPSSortOrderSet pointer, perform the following cast:

lpSSortOrderSet = (LPSSortOrderSet) lpSizedSSortOrderSet.

The SSortOrderSet structure is defined in MAPIDEFS.H.


  SSubRestriction

An SSubRestriction structure holds a search subrestriction for subobjects of table entries.

Syntax

typedef struct _SSubRestriction

{

ULONG ulSubObject;

LPSRestriction lpRes;

} SSubRestriction;

Members

ulSubObject

Subobject identified in the RES_SUBRESTRICTION restriction type supplied for the rt member of the SRestriction structure. Possible values are PR_MESSAGE_RECIPIENTS or PR_MESSAGE_ATTACHMENTS.

lpRes

Pointer to RES_SUBRESTRICTION restriction type.

Comments

The most common objects to support subrestrictions are folder contents tables and search-results folders. These objects may support restricting a search using PR_MESSAGE_ATTACHMENTS or PR_MESSAGE_RECIPIENTS as a restriction to find a message that has an attachment or a recipient that meets the other given restrictions. If an implementation does not support subrestrictions, it returns for a subrestricted search the error value MAPI_E_TOO_COMPLEX.

The SSubRestriction structure is defined in MAPIDEFS.H.

See Also

SRestriction structure


  STATUS_OBJECT_NOTIFICATION

A STATUS_OBJECT_NOTIFICATION structure holds information about a notification event indicating that a row of the status table has changed. MAPI uses this structure only as a member of the NOTIFICATION structure for the advise sink.

Syntax

typedef struct

{

ULONG cbEntryID;

LPENTRYID lpEntryID;

ULONG cValues;

LPSPropValue lpPropVals;

} STATUS_OBJECT_NOTIFICATION;

Members

cbEntryID

Size, in bytes, of the entry identifier of the changed status object.

lpEntryID

Pointer to the entry identifier of the changed status object.

cValues

Number of SPropValue structures in the array pointed to by the lpPropVals member.

lpPropVals

Pointer to an array of SPropValue structures, one for each changed property of the status object.

Comments

The STATUS_OBJECT_NOTIFICATION structure is defined in MAPIDEFS.H.

See Also

NOTIFICATION structure, SPropValue structure


  STnefProblem

An STnefProblem structure holds information about a property or attribute processing problem that occurred during the encoding or decoding of a Transport-Neutral Encapsulation Format (TNEF) stream.

Syntax

typedef struct _STnefProblem

{

ULONG	ulComponent;

ULONG	ulAttribute;

ULONG	ulPropTag;

SCODE	scode;

} STnefProblem;

Members

ulComponent

Type of processing during which the problem occurred. If the problem occurred during message processing, the ulComponent member is set to zero. If the problem occurred during attachment processing, ulComponent is set equal to the corresponding attachment's PR_ATTACHMENT_NUM value.

ulAttribute

Attribute corresponding to the ulPropTag member, except when the TNEF processing problem arises while decoding an encapsulation block. In this case, the ulAttribute member can have the following possible values:

attMAPIProps

Message level

attAttachment

Attachment level

ulPropTag

 Property tag of the property that caused the TNEF processing problem, except when the problem arises while decoding an encapsulation block, in which case ulPropTag is set to zero.

scode

Error code indicating the problem encountered during processing. The error can be any SCODE value as listed in Appendix A, "Return Codes." The error value MAPI_E_UNABLE_TO_COMPLETE is returned when the processing problem occurs in an encapsulation block.

Comments

If an STnefProblem structure is not generated during the processing of an attribute or property, your application can continue under the assumption the processing of that attribute or property succeeded. The only exception occurs when the problem arose during decoding of an encapsulation block. In this case, the decoding of the component corresponding to the block is halted and decoding is continued in another component.

The STnefProblem is defined in TNEF.H.

See Also

STnefProblemArray structure


  STnefProblemArray

An STnefProblemArray structure lists one or more property or attribute processing problems that occurred during the encoding or decoding of a Transport-Neutral Encapsulation Format (TNEF)stream.

Syntax

typedef struct _SPropProblemArray {

ULONG cProblem;

SPropProblem aProblem[MAPI_DIM];

} SPropProblemArray, FAR *LPSPropProblemArray;

Members

cProblem

Number of elements in the array in the aProblem member.

aProblem

Array of STnefProblem structures. Each structure holds information about a property or attribute processing problem.

Comments

If a problem occurs during attribute or property processing, an output parameter in the method ITnef::ExtractProps and in the method ITnef::Finish each receive a pointer to a STnefProblemArray structure and ExtractProps and Finish each return the value MAPI_W_ERRORS_RETURNED. This error value indicates that a problem arose during processing and a STnefProblemArray was generated.

If an STnefProblem structure is not generated during the processing of an attribute or property, your application can continue under the assumption the processing of that attribute or property succeeded. The only exception occurs when the problem arose during decoding of an encapsulation block. In this case, the decoding of the component corresponding to the block is halted and decoding is continued in another component.

The STnefProblemArray structure is defined in TNEF.H.

See Also

ITnef::ExtractProps method, ITnef::Finish method, STnefProblem structure


  SWStringArray

An SWStringArray structure holds a property value of type PT_MV_UNICODE for use in an SPropValue structure holding information about a multivalued property.

Syntax

typedef struct _SWStringArray

{

ULONG	cValues;

LPWSTR	FAR *lppszW;

} SWStringArray;

Members

cValues

Number of values in the array pointed to by the lppszW member.

lppszW

Pointer to the array of null-terminated Unicode string values making up the property.

Comments

The SWStringArray structure is defined in MAPIDEFS.H.

See Also

PT_MV_UNICODE property type, SPropValue structure


  TABLE_NOTIFICATION

The TABLE_NOTIFICATION data structure holds information about a notification event related to a table, such as a table change, error, addition, or deletion. MAPI uses this structure only as a member of the NOTIFICATION structure for the advise sink.

Syntax

typedef struct _TABLE_NOTIFICATION

{

ULONG ulTableEvent;

HRESULT hResult;

SPropValue propIndex;

SPropValue propPrior;

SRow row;

} TABLE_NOTIFICATION;

Members

ulTableEvent

Bitmask of flags representing the table event type. The following flags can be set:

TABLE_CHANGED

Indicates something has changed but the table implementation does not have the details.

In response to this flag, the client application can reread the entire table to get current data.

TABLE_ERROR

Indicates an error has occurred during asynchronous table processing.

TABLE_RELOAD

Indicates a need to re-read the data and start over. When clients receive this event, they should assume that nothing about the table is still valid. All bookmarks, instance keys, status and positioning information are obsolete.

TABLE_RESTRICT_DONE

Indicates a search has completed the table.

TABLE_ROW_ADDED

Indicates the propIndex member identifies the row that the client application has created.

Because client applications handle notifications asynchronously, notification of an addition to a table might arrive after the application is already aware of the change. For example, suppose a notification that a row is added has been generated but not yet sent to the application. The application might read 20 rows, including the added row, before MAPI passes the notification to the application's notification callback function.

Data describing the new position and contents of the row (the propPrior, row.cValues, and row.lpProps members). If the added or modified row is now the first row in the table, the property tag in the propPrior member is zero.

TABLE_ROW_DELETED

Indicates the propIndex member that the client application has deleted.

Because the client application handles notifications asynchronously, notification of deletion of part or all of a table might arrive after the application is already aware of the change.

TABLE_ROW_MODIFIED

Indicates the propIndex member identifies the row that the application has modified.

Because the client application handles notifications asynchronously from regular processing, notification of a table modification might arrive after the application is already aware of the change.

Data describing the new position and contents of the row (the propPrior, row.cValues, and row.lpProps members). If the added or modified row is now the first row in the table, the property tag in the propPrior member is zero.

TABLE_SETCOL_DONE

Indicates the table's columns have been set.

TABLE_SORT_DONE

Indicates the table has been sorted.

hResult

HRESULT value for the TABLE_ERROR event listed for the ulTableEvent member.

propIndex

SPropValue structure giving the index of the table row that has changed, that is, the current row's index.

propPrior

SPropValue structure giving the index of the row preceding the current one.

row

SRow structure containing the data for the added or modified row. This structure is filled for all table notification events, even if an event of the current type doesn't require it. For table notification events that do not pass row data, row.cValues must equal zero and row.lpProps must be NULL. This SRow structure is read-only, so client applications must copy it to work with it.

Comments

TABLE_ERROR can be sent as a result of asynchronous calls to the Sort, IMAPITable::Restrict, or IMAPITable::SetColumns method. This TABLE_ERROR flag can be written for asynchronous Sort, IMAPITable::Restrict, or IMAPITable::SetColumns calls. It can also be written with underlying processing that attempts to update a table with, for example, new or modified rows.

The TABLE_ROW_ADDED flag that indicates the propIndex member identifies the row that the client application has created.

Because client applications handle notifications asynchronously, notification of an addition to a table might arrive after the application is already aware of the change. For example, suppose a notification that a row is added has been generated but not yet sent to the application. The application might read 20 rows, including the added row, before MAPI passes the notification to the application's notification callback function.

Data describing the new position and contents of the row (the propPrior, row.cValues, and row.lpProps members). If the added or modified row is now the first row in the table, the property tag in the propPrior member is zero.

Once a client application receives TABLE_ERROR for a table, the application can no longer rely on the accuracy of the table contents. Notification of changes might be lost. To get additional information about a table for which a TABLE_ERROR event has occurred, your application can call the GetLastError method for the table.

The TABLE_NOTIFICATION structure is defined in MAPIDEFS.H.

See Also

IMAPITable::Restrict method, IMAPITable::SetColumns method, NOTIFICATION structure, SPropValue structure, SRow structure, GetLastErrorSort


  Simple Data Types

This section contains a reference entry for each data type.


  BOOKMARK

BOOKMARK is an unsigned long data type that retains in memory a position in a table. The data stored in a bookmark depends on the client application.

Syntax

typedef ULONG BOOKMARK;

Comments

MAPI defines the bookmarks listed following.

BOOKMARK_BEGINNING

Seeks to the beginning of the table.

BOOKMARK_CURRENT

Seeks to the row in the table where the cursor is located.

BOOKMARK_END

Seeks to the end of the table.

Your application can create additional bookmarks. Created bookmarks are only useful while a table is open. Your application must free any created bookmarks when it closes a table.

The BOOKMARK unsigned long data type is defined in MAPIDEFS.H.

See Also

IMAPITable::CreateBookmark method, IMAPITable::FindRow method, IMAPITable::FreeBookmark method, IMAPITable::SeekRow method


  BYTE

BYTE is an unsigned character data type that is binary data.

Syntax

typedef unsigned char	BYTE;


  HRESULT

HRESULT is a data type that is a 32-bit error or warning code.

Syntax

typedef LONG	HRESULT;

Comments

An HRESULT is made up of a 1-bit severity flag, an 11-bit handle, a 4-bit facility code indicating status code (SCODE) group, and a 16-bit SCODE information code. A value of zero for the severity flag indicates the success of the operation for which the HRESULT was returned.

A HRESULT type returned as an error code for a function can provide the application that called the function information on the error and how to recover from it. To obtain this information, the application uses the handle of the HRESULT. The HRESULT and SCODE types are not equivalent. OLE includes functions and macros to convert between error codes of these two types. To create an HRESULT code from an SCODE code, use ResultFromScode(SCODE). To convert an SCODE code to HRESULT form, use GetScode(HRESULT). For details about ResultFromScode and GetScode and for faster ways of making the conversions just mentioned, see OLE Programmer's Reference, Volume One. . For a description of the OLE implementation of HRESULT, see Inside OLE, Second Edition, by Kraig Brockschmidt.

See Also

SCODE data type


  LHANDLE

LHANDLE is a Simple MAPI data type that is a MAPI session handle.

Syntax

typedef unsigned long LHANDLE, FAR *LPLHANDLE;


  LONG

LONG is a data type that is a 32-bit signed integer.

Syntax

typedef long	LONG;


  SCODE

SCODE is a data type that is a 32-bit status value. MAPI functions and methods return values of the SCODE type.

Syntax

typedef ULONG	SCODE;

Comments

All MAPI functions and methods return SCODE values; some MAPI functions also return warnings, which are non zero HRESULT values.

To obtain an SCODE value from an HRESULT value, your application can use the OLE function GetScode as follows:

SCODE scode;

HRESULT hresult;

hresult = arbitrary function call;

if (hresult)

{

scode = GetScode(hresult);

/* Display error based on scode */

}

When a MAPI function returns an HRESULT value as a warning, an SCODE return value can be identified as a type of success. For example:

hresult = SomeCall(..)

if (hresult !=0)

{

SCODE scode = GetScode(hresult);

if (FAILED(scode))

goto error;

/*Handle the warning here */

if (scode == MAPI_W_warning)

{

}

}

See Also

HRESULT data type


  TCHAR

TCHAR is a data type that is a character string on either a Unicode or an ANSI or DBCS platform. For Unicode platforms, this string is defined as having the WCHAR type. For ANSI and DBCS platforms, the string is defined as having the char type.

Syntax

typedef char	TCHAR;

typedef WCHAR  TCHAR;

Comments

Your application can use TCHAR to represent a string of either the WCHAR or char type. Be sure to define the symbolic constant UNICODE and limit the platform where necessary. MAPI will interpret the platform information and internally translate TCHAR to the appropriate string.


  ULONG

ULONG is a data type that is a 32-bit unsigned integer.

Syntax

typedef unsigned long	ULONG;


  WCHAR

WCHAR is a data type that is a Unicode character string.

Syntax

typedef WORD	WCHAR;


 Additional Extended MAPI Functions

This chapter documents a variety of utility functions for Extended MAPI that are occasionally useful for application development. For a more general discussion of how Extended MAPI functions work, see MAPI Programmer's Guide. For information on required functions, refer to Chapter 4, "Essential Extended MAPI Functions."


 ChangeIdleRoutine

[New - Windows 95]

Changes some or all of the characteristics of an idle function (that is, a function based on the FNIDLE function prototype) included in a client application or service provider.

Syntax

VOID ChangeIdleRoutine(FTG ftg, PFNIDLE pfnIdle, LPVOID pvIdleParam, short priIdle, ULONG csecIdle, USHORT iroIdle, USHORT ircIdle)

Parameters

ftg

Input parameter containing a function tag that identifies the idle function.

pfnIdle

Input parameter pointing to the idle function.

pvIdleParam

Input parameter pointing to a new block of memory that the calling implementation allocates for the idle function.

priIdle

Input parameter containing a new priority for the idle function. priorities for implementation-defined functions are greater than or less than zero, but not zero. The zero priority is reserved for a user event such as a mouse click..

Priorities greater than zero represent background tasks that have a higher priority than user events and are dispatched as part of the standard message pump loop. Priorities less than zero represent idle tasks that only run during message-pump idle time. Examples of priorities are: 1 for foreground submission, −1 for power-edit character insertion, and −3 for downloading new messages.

csecIdle

Input parameter containing a new time, in hundredths of a second, to apply to the idle function. The meaning of the initial time value varies, depending on what is passed in the iroIdle parameter. It can be:

•	The minimum period of user inaction that must elapse before the MAPI idle engine calls the idle function for the first time, if the FIROWAIT flag is set in iroIdle. After this time passes, the idle engine can call the idle function as often as necessary.

•	The minimum interval between calls to the idle function, if the FIROINTERVAL flag is set in iroIdle.

iroIdle

Input parameter containing a bitmask of flags indicating new options for the idle function. The following flags can be set:

FIRODISABLED

Indicates that the idle function is initially disabled when registered. The default is to enable the idle function when the FtgRegisterIdleRoutine function registers it.

FIROINTERVAL

Indicates that the time indicated by csecIdle is the minimum interval between successive calls.

FIROWAIT

Indicates that the time indicated by csecIdle is the minimum user idle time that must elapse before the MAPI idle engine will call the idle function for the first time.

ircIdle

Input parameter containing a bitmask of flags used to indicate changes to be made to the idle function. The following flags can be set:

FIRCCSEC

Indicates a change to the time associated with the idle function (csecIdle).

FIRCIRO

Indicates a change to the options for the idle function (iroIdle).

FIRCPFN

Indicates a change to the idle function pointer (pfnIdle).

FIRCPRI

Indicates a change to the priority of the idle function (priIdle).

FIRCPV

Indicates a change to the memory block of the idle function (pvIdleParam).

Comments

The ChangeIdleRoutine function is defined in MAPIUTIL.H.

See Also

FNIDLE function prototype, FtgRegisterIdleRoutine function


 CloseIMsgSession

[New - Windows 95]

Closes an IMessage session.

Syntax

VOID CloseIMsgSession(LPMSGSESS lpMsgSess)

Parameters

lpMsgSess

Input parameter pointing to the message session object obtained using the OpenIMsgSession function at the start of the message session.

Comments

A client application uses this function along with OpenIMsgSession to wrap the creation of messages inside a message session. When the application closes this session, it also closes all messages created within the session. Using sessions obtained with the IMessage interface is optional.

A message session keeps track of all messages opened during the session, in addition to all the tables and attachments within the messages. When a client calls the CloseIMsgSession function, it closes all these objects.

The CloseIMsgSession function is defined in IMESSAGE.H.

See Also

IMessage : IMAPIProp interface, OpenIMsgSession function


 DeregisterIdleRoutine

[New - Windows 95]

Removes a client application or service provider function based on the FNIDLE function prototype from the idle table.

Syntax

VOID DeregisterIdleRoutine(FTG ftg)

Parameters

ftg

Input parameter containing a function tag that identifies the idle function to be removed.

Comments

A client application or service provider can only remove an idle function (that is, a function based on FNIDLE) from the idle table if the function is not active. MAPI does not verify that the idle function is in a state from which it can be exited.

The application or provider can use the idle function itself to make the call to the DeregisterIdleRoutine function. The idle function is deregistered when the function returns.

After the idle function is deregistered, the idle engine does not call it again. Any implementation that calls DeregisterIdleRoutine must deallocate any memory blocks to which it passed pointers for the idle engine to use in its original call to the FtgRegisterIdleRoutine function.

The DeregisterIdleRoutine function is defined in MAPIUTIL.H.

See Also

FNIDLE function prototype, FtgRegisterIdleRoutine function


 EnableIdleRoutine

[New - Windows 95]

Enables or disables an idle function (that is, a function based on the FNIDLE function prototype).

Syntax

VOID EnableIdleRoutine(FTG ftg, BOOL fEnable)

Parameters

ftg

Input parameter containing a function tag that identifies the idle function to be enabled or disabled.

fEnable

Input parameter containing TRUE if the idle engine should enable the idle function, and FALSE if the idle engine should disable it.

Comments

The EnableIdleRoutine function is defined in MAPIUTIL.H.

See Also

FNIDLE function prototype, FtgRegisterIdleRoutine function


 FBadColumnSet

[New - Windows 95]

Tests the validity of one or more table column sets for use by a service provider in a subsequent call to the IMAPITable::SetColumns method.

Syntax

ULONG FBadColumnSet(LPSPropTagArray lpptaCols)

Parameters

lpptaCols

Input parameter pointing to an array of SPropTagArray structures defining the table column sets to validate.

Return Values

Returns TRUE if the specified column sets are invalid, and FALSE otherwise.

Comments

A service provider calls the FBadColumnSet function. This function treats columns of type PT_ERROR as invalid and columns of type PT_NULL as valid.

The FBadColumnSet function is defined in MAPIVAL.H.

See Also

IMAPITable::SetColumns method, SPropTagArray structure


 FBadEntryList

[New - Windows 95]

Validates a list of MAPI entry identifiers.

Syntax

BOOL FBadEntryList(LPENTRYLIST lpEntryList)

Parameters

lpEntryList

Input parameter pointing to an ENTRYLIST structure defining the list of entry identifiers to be validated.

Comments

This function determines if the entry identifier list has been correctly generated. An example of an invalid entry identifier is an identifier for which memory has been incorrectly allocated or an identifier of an incorrect size.

The FBadEntryList function is defined in MAPIVAL.H.

Return Values

Returns TRUE if any of the listed entry identifiers are invalid, and FALSE otherwise.

See Also

ENTRYLIST structure


 FBadProp

[New - Windows 95]

Validates a specified property.

Syntax

ULONG FBadProp(LPSPropValue lpprop)

Parameters

lpprop

Input parameter containing an SPropValue structure defining the property to be validated.

Return Values

Returns TRUE if the specified property is invalid, and FALSE otherwise.

Comments

A service provider can call this function for several reasons, for example to prepare for a call to the IMAPIProp::SetProps method setting a property. The FBadProp function validates the specified property depending on the property type. For example, if the property is Boolean, FBadProp ensures that its value is either TRUE or FALSE. If the property is binary, FBadProp checks its pointer and size and makes sure that it is allocated correctly.

The FBadProp function is defined in MAPIVAL.H.

See Also

FBadPropTag function, IMAPIProp::SetProps method, SPropValue structure


 FBadPropTag

[New - Windows 95]

Validates a specified property tag.

Syntax

ULONG FBadPropTag(ULONG ulPropTag)

Parameters

ulPropTag

Input parameter containing the property tag to be validated.

Return Values

Returns TRUE if the specified property tag is not a valid MAPI property tag, and FALSE otherwise.

Comments

A service provider calls the FBadPropTag function.

The FBadPropTag function is defined in MAPIVAL.H.

See Also

FBadProp function


 FBadRestriction

[New - Windows 95]

Validates a restriction used to limit a table.

Syntax

ULONG FBadRestriction(LPSRestriction lpres)

Parameters

lpres

Input parameter containing an SRestriction structure defining the restriction to be validated.

Return Values

Returns TRUE if the specified restriction or any of its subrestrictions is invalid, and FALSE otherwise.

Comments

A service provider calls the FBadRestriction function. Once validated, a restriction can be passed in calls to the IMAPITable::Restrict method to restrict a table to certain rows, to the IMAPITable::FindRow method to locate a table row, and to methods of the IMAPIContainer interface to perform a restriction on a container object.

A FBadRestriction function is defined in MAPIVAL.H.

See Also

IMAPIContainer : IMAPIProp interface, IMAPITable::FindRow method, IMAPITable::Restrict method, SRestriction structure


 FBadRglpNameID

[New - Windows 95]

Validates an array of pointers that specify name identifier structures and verifies their allocation.

Syntax

BOOL FBadRglpNameID(LPMAPINAMEID FAR* lppNameId, ULONG cNames)

Parameters

lppNameId

Input parameter pointing to an array of MAPINAMEID structures defining the name identifiers.

cNames

Input parameter containing the number of name identifiers in the array pointed to by the lppNameId parameter.

Return Values

Returns TRUE if any one of the specified name identifiers is invalid, and FALSE otherwise.

Comments

The FBadRglpNameID function is defined in MAPIVAL.H.

See Also

IMAPIProp::GetIDsFromNames method, IMAPIProp::GetNamesFromIDs method, MAPINAMEID structure


 FBadRglpszW

[New - Windows 95]

Validates all strings in an array of Unicode strings.

Syntax

BOOL FBadRglpszW(LPWSTR FAR* lppszW, ULONG cStrings)

Parameters

lppszW

Input parameter pointing to an array of null-terminated Unicode strings.

cStrings

Input parameter containing the number of strings in the array pointed to by the lppszW parameter.

Return Values

Returns TRUE if any of the strings in the specified array are invalid, and FALSE otherwise.

Comments

The FBadRglpszW function is defined in MAPIVAL.H


 FBadRow

[New - Windows 95]

Validates a row in a table.

Syntax

ULONG FBadRow(LPSRow lprow)

Parameters

lprow

Input parameter pointing to an SRow structure identifying the row to be validated.

Return Values

Returns TRUE if the specified row is invalid, and FALSE otherwise.

Comments

A service provider calls the FBadRow function.

The FBadRow function is defined in MAPIVAL.H.

See Also

FBadRowSet function, SRow structure


 FBadRowSet

[New - Windows 95]

Validates all table rows included in a set of table rows.

Syntax

BOOL FBadRowSet(LPSRowSet lpRowSet)

Parameters

lpRowSet

Input parameter pointing to an SRowSet structure identifying the row set to be validated. If the pointer is NULL, the structure is invalid.

Return Values

Returns TRUE if any row of the specified row set is invalid or if the row set itself is invalid, and FALSE otherwise.

Comments

A service provider calls the FBadRowSet function.

The FBadRowSet function is defined in MAPIVAL.H.

See Also

FBadRow function, SRowSet structure


 FBadSortOrderSet

[New - Windows 95]

Validates a sort order set by verifying its memory allocation.

Syntax

ULONG FBadSortOrderSet(LPSSortOrderSet lpsos)

Parameters

lpsos

Input parameter pointing to an SSortOrderSet structure identifying the sort order set to be validated.

Return Values

Returns TRUE if the specified sort order set is invalid, and FALSE otherwise.

Comments

A service provider calls the FBadSortOrderSet function. This function can be used to prepare for a call to a sort method such as the IMAPITable::SortTable method.

The FBadSortOrderSet function is defined in MAPIVAL.H.

See Also

IMAPITable::SortTable method, SSortOrderSet structure


 FBinFromHex

[New - Windows 95]

Converts a string representation of a hexadecimal number to binary data.

Syntax

BOOL FBinFromHex(LPTSTR sz, LPBYTE pb)

Parameters

sz

Input parameter pointing to the null-terminated string to be converted. Valid characters include the hexadecimal characters 0 through 9 and both uppercase and lowercase characters a through f.

pb

Output parameter pointing to a variable where the returned binary number is stored.

Return Values

Returns TRUE if the function successfully converts the string into a binary number, and FALSE if the input string contains invalid ASCII hexadecimal characters.

Comments

The FBinFromHex function is defined in MAPIUTIL.H.

See Also

ScBinFromHexBounded function


 FEqualNames

[New - Windows 95]

Determines whether two MAPI name identifiers are equal.

Syntax

BOOL FEqualNames(LPMAPINAMEID lpName1, LPMAPINAMEID lpName2)

Parameters

lpName1

Input parameter pointing to a MAPINAMEID structure defining the first name to be tested.

lpName2

Input parameter pointing to a MAPINAMEID structure defining the second name to be tested.

Return Values

Returns TRUE if the two name identifiers are equal, and FALSE otherwise.

Comments

This function is useful because name identifiers are represented as structures, which cannot be compared by simple binary methods. The testing process is case-sensitive for strings.

The FEqualNames function is defined in MAPIUTIL.H.

See Also

MAPINAMEID structure


 FPropCompareProp

[New - Windows 95]

Compares two properties using a binary relational operator.

Syntax

BOOL FPropCompareProp(LPSPropValue lpSPropValue1, ULONG ulRelOp, LPSPropValue lpSPropValue2)

Parameters

lpSPropValue1

Input parameter pointing to an SPropValue structure defining the first property for comparison.

ulRelOp

Input parameter containing the relational operator to use in the comparison.

lpSPropValue2

Input parameter pointing to an SPropValue structure defining the second property for comparison.

Return Values

Returns TRUE if it succeeds in comparing the input properties, and FALSE otherwise.

Comments

The order of comparison is lpSPropValue1, ulRelOp, lpSPropValue2. If the property types of the properties do not match, the FPropCompareProp function determines that they are not equal but that they are otherwise incomparable.

The comparison method depends on the property types included with the SPropValue property definitions and a fuzzy level heuristic also provided by the calling implementation. FPropContainsProp can be used to prepare restrictions for generating a table.

The FPropCompareProp function is defined in MAPIUTIL.H.

See Also

SPropValue structure


 FPropContainsProp

[New - Windows 95]

Compares two property values, generally strings or binary arrays, to see if one value contains the other.

Syntax

BOOL FPropContainsProp(LPSPropValue lpSPropValueDst, LPSPropValue lpSPropValueSrc, ULONG ulFuzzyLevel)

Parameters

lpSPropValueDst

Input parameter pointing to an SPropValue structure defining the property value that might contain the property value pointed to by the lpSPropValueSrc parameter.

lpSPropValueSrc

Input parameter pointing to an SPropValue structure defining the property value that the FPropContainsProp function is seeking within the property value pointed to by the lpSPropValueDst parameter.

ulFuzzyLevel

Input parameter containing the fuzzy level to use in the comparison. Possible fuzzy level values are:

FL_FULLSTRING

Works identically to TNEF_PROP_CONTAINED; requires an exact match.

FL_IGNORECASE

Indicates the comparison deals only with properties of type PT_STRING8. When this value is set, FPropContainsProp makes the comparison in case-insensitive fashion.

FL_IGNORENONSPACE

Indicates the comparison deals only with properties of type PT_STRING8. When this value is set, FPropContainsProp makes the comparison so as to ignore Unicode-defined nonspacing characters, for example diacritical marks.

FL_LOOSE

Indicates the comparison deals only with properties of type PT_STRING8. When this value is set, a service provider performs as many fuzzy level heuristics of types FL_IGNORECASE and FL_IGNORESPACE as it has been designed to handle.

FL_PREFIX

Indicates the comparison deals with properties of types PT_STRING8 and PT_BINARY. When this value is set, FPropContainsProp compares the values of the two properties only through the length of the property indicated by the lpSPropValueSrc.

FL_SUBSTRING

The comparison deals with property types PT_STRING8 and PT_BINARY. The function checks to see if the property value indicated by lpSPropValueSrc is contained as a substring in the other property.

Return Values

This function returns TRUE in the following cases:

•	FL_FULLSTRING is set for the fuzzy level and the values of the source and destination properties are equivalent.

•	FL_SUBSTRING is set for the fuzzy level and the property indicated by lpSPropValueSrc is contained as a substring in the property indicated by lpSPropValueDst.

•	For PT_BINARY properties not falling into one of the categories listed for the ulFuzzyLevel parameter, the property indicated by lpSPropValueSrc is contained as a byte sequence in the property indicated by lpSPropValueDst.

The function returns FALSE if the properties being compared are not both of the same type, if one or both of the properties is not of either the PT_STRING8 or PT_BINARY type, or if the input fuzzy level is not one of those listed for ulFuzzyLevel.

Comments

For comparisons of properties of type PT_STRING8 not covered by one of the values for ulFuzzyLevel, FPropContainsProp compares the input property values as fuzzy level 1.

The comparison method this function uses depends on the property types included with the SPropValue property definitions and a fuzzy level heuristic also provided by the calling implementation. FPropContainsProp can be used to prepare restrictions for generating a table.

The FPropContainsProp function is defined in MAPIUTIL.H.

See Also

FPropCompareProp function, SPropValue structure


 FPropExists

[New - Windows 95]

Searches for a given property tag in an IMAPIProp interface or an interface derived from IMAPIProp, such as IMessage or IMAPIFolder.

Syntax

BOOL FPropExists(LPMAPIPROP pobj, ULONG ulPropTag)

Parameters

pobj

Input parameter pointing to the IMAPIProp interface or interface derived from IMAPIProp within which to search for the property tag.

ulPropTag

Input parameter containing the property tag for which to search.

Return Values

Returns TRUE if the function finds a match for the given property tag, and FALSE otherwise.

Comments

If the given property tag has type PT_UNSPECIFIED, the function finds a match only for the property identifier. Otherwise, the match is for the entire property tag, including the type.

The FPropExists function is defined in MAPIUTIL.H.

See Also

IMAPIFolder : IMAPIContainer interface, IMAPIProp : IUnknown interface, IMessage : IMAPIProp interface


 FtAddFt

[New - Windows 95]

Adds one unsigned 64-bit integer to another.

Syntax

FILETIME FtAddFt(FILETIME Addend1, FILETIME Addend2)

Parameters

Addend1

Input parameter containing a FILETIME structure defining the first unsigned 64-bit integer to be added.

Addend2

Input parameter containing a FILETIME structure defining an unsigned 64-bit integer to be added to the value indicated by the Addend1 parameter.

Return Values

Returns a FILETIME structure containing the sum of the two integers.

Comments

The FtAddFt function is defined in MAPIUTIL.H.

See Also

FILETIME structure, FtNegFt function, FtSubFt function


 FtgRegisterIdleRoutine

[New - Windows 95]

Adds a client application or service provider function based on the FNIDLE function prototype to the idle table.

Syntax

FtgRegisterIdleRoutine(PFNIDLE pfnIdle, LPVOID pvIdleParam, short priIdle, ULONG csecIdle, USHORT iroIdle)

Parameters

pfnIdle

Input parameter pointing to the idle function.

pvIdleParam

Input parameter pointing to a block of memory that the idle engine should use when it calls the idle function.

priIdle

Input parameter containing the initial priority that the calling implementation requests for the idle function. Possible priorities for implementation-defined functions are greater than or less than zero, but not zero. The zero priority is reserved for a user event (for example, a mouse click, a WM_PAINT message, and so on).

Priorities greater than zero represent background tasks that have a higher priority than user events and are dispatched as part of the standard message pump loop. Priorities less than zero represent idle tasks that only run during message-pump idle time. Examples of priorities are: 1 for foreground submission, −1 for power-edit character insertion, and −3 for downloading new messages.

csecIdle

Input parameter containing an initial time value, in hundredths of a second, that the calling implementation requests to be used in specifying idle function parameters. The csecIdle parameter represents an input to FtgRegisterIdleRoutine.

The meaning of the initial time value varies, depending on the calling implementation's requirements. It can be:

•	The minimum user idle time that must elapse before the MAPI idle engine will call the idle function (FIROWAIT flag, described following for the iroIdle parameter). After this time, the idle engine can call the function as often as necessary.

•	The minimum interval between calls to the idle function (FIROINTERVAL flag, described following for iroIdle).

iroIdle

Input parameter containing a bitmask of flags used to initial options for the idle function. The following flags can be set:

FIRODISABLED

Indicates that the idle function is initially disabled when registered. The default action is to enable the idle function when the FtgRegisterIdleRoutine function registers it.

FIROINTERVAL

Indicates that the time specified by csecIdle is the minimum interval between successive calls to the idle function.

FIROWAIT

Indicates that the time specified by csecIdle is the minimum period of user inaction that must elapse before the MAPI idle engine calls the idle function for the first time. After this time passes, the idle engine can call the idle function as often as necessary.

Return Values

Returns a function tag identifying the idle function that FtgRegisterIdleRoutine has added to the idle table. If FtgRegisterIdleRoutine cannot register the idle function for the client application or service provider, for example because of memory problems, it returns NULL.

Comments

To later make changes to a registered idle function, a client application or service provider can call the ChangeIdleRoutine function. To remove an idle function from the idle table, your client or provider calls the DeregisterIdleRoutine function.

When all foreground tasks for the platform become idle, the idle engine calls the highest-priority idle function in the idle table that is ready to execute.

The FtgRegisterIdleRoutine function is defined in MAPIUTIL.H.

See Also

ChangeIdleRoutine function, DeregisterIdleRoutine function, FNIDLE function prototype


 FtgRegisterIdleRoutine, FNIDLE

[New - Windows 95]

The FNIDLE prototype function represents a client application or service provider idle function that the MAPI idle engine calls periodically according to priority. The specific functionality of the idle function is defined by the application or provider.

Syntax

BOOL (STDAPICALLTYPE FNIDLE)(LPVOID)

Parameters

LPVOID

Input parameter specifying a pointer to a block of memory. The idle function can use this value as a pointer to a state buffer for length operations.

Return Values

An idle function with the FNIDLE prototype should always return FALSE.

Comments

The client application or service provider must call the idle engine function Idle_InitDLL before it can register its own idle function with a call to FtgRegisterIdleRoutine. Then the application or provider can use these other idle engine functions as needed during idle operations:

•	EnableIdleRoutine

•	ChangeIdleRoutine

•	DeregisterIdleRoutine

•	Idle_DeInitDLL

•	FIsIdleExit

•	FDoNextIdleTask

The FNIDLE function is defined in MAPIUTIL.H.

See Also

ChangeIdleRoutine function, DeregisterIdleRoutine function, EnableIdleRoutine function, FtgRegisterIdleRoutine function


 FtMulDw

[New - Windows 95]

Multiplies an unsigned 64-bit integer indicating a time value by an unsigned 32-bit integer in doubleword format.

Syntax

FILETIME FtMulDw(DWORD Multiplier, FILETIME Multiplicand)

Parameters

Multiplier

Input parameter containing an unsigned 32-bit integer in doubleword format.

Multiplicand

Input parameter containing a FILETIME structure defining a 64-bit integer time value to be multiplied by the value in the Multiplier parameter.

Return Values

Returns a FILETIME structure containing the product of the input values.

Comments

The FtMulDw function is defined in MAPIUTIL.H.

See Also

FILETIME structure, FtAddFt function, FtMulDwDw function, FtNegFt function


 FtMulDwDw

[New - Windows 95]

Multiplies one unsigned 32-bit integer in doubleword format by another.

Syntax

FILETIME FtMulDwDw(DWORD Multiplicand, DWORD Multiplier)

Parameters

Multiplicand

Input parameter containing an unsigned 32-bit integer in doubleword format to be multiplied by the value in the Multiplier parameter.

Multiplier

Input parameter containing an unsigned 32-bit integer in doubleword format.

Return Values

Returns a FILETIME structure containing the product of the input values.

Comments

The FtMulDwDw function is defined in MAPIUTIL.H.

See Also

FILETIME structure, FtMulDw function, FtNegFt function


 FtNegFt

[New - Windows 95]

Computes the two's complement of an unsigned 64-bit integer indicating a time value.

Syntax

FILETIME FtNegFt(FILETIME ft)

Parameters

ft

Input parameter containing a FILETIME structure containing the unsigned 64-bit integer indicating a time value for which to compute the two's complement.

Return Values

Returns a FILETIME structure containing the two's complement of the input value.

Comments

The FtNegFt function is defined in MAPIUTIL.H.

See Also

FILETIME structure, FtAddFt function, FtSubFt function


 FtSubFt

[New - Windows 95]

Subtracts one unsigned 64-bit integer indicating a time value from another.

Syntax

FILETIME FtSubFt(FILETIME Minuend, FILETIME Subtrahend)

Parameters

Minuend

Input parameter containing a FILETIME structure defining the unsigned 64-bit integer from which the value in the Subtrahend parameter is subtracted.

Subtrahend

Input parameter containing a FILETIME structure defining an unsigned 64-bit integer that this function subtracts from the value indicated by the Minuend parameter.

Return Values

Returns a FILETIME structure containing the results of the subtraction.

See Also

FILETIME structure, FtAddFt function, FtNegFt function


 GetInstance

[New - Windows 95]

Copies one value within a multivalued property to a single-valued property of the same type.

Syntax

VOID GetInstance(LPSPropValue pvalMv, LPSPropValue pvalSv, ULONG uliInst)

Parameters

pvalMv

Input parameter pointing to an SPropValue structure defining a multivalued property.

pvalSv

Input parameter pointing to a single-valued property to receive data.

uliInst

Input parameter containing the instance number (that is, the array element) of the value being copied from the structure indicated by the pvalMv parameter.

Comments

If the value copied is too large for the allocated memory, the GetInstance function only copies pointers rather than allocating new memory.

Comments

The GetInstance function is defined in MAPIUTIL.H.

See Also

SPropValue structure


 HexFromBin

[New - Windows 95]

Converts a binary number into a string representation of a hexadecimal number.

Syntax

VOID HexFromBin(LPBYTE pb, int cb, LPTSTR sz)

Parameters

pb

Input parameter pointing to the binary number to be converted.

cb

Input parameter containing the size, in bytes, of the pb parameter.

sz

Output parameter pointing to a variable where the returned null-terminated string representing the binary number is stored.

Return Values

Returns TRUE if the function successfully converts the binary number into a string, and FALSE otherwise.

Comments

This function takes a pointer to a unit of binary data whose size is indicated by the cb parameter. It returns back in the sz string, for which you have allocated memory, a representation of this binary information in hexadecimal numbers. If the byte value was 10, for example, the hexadecimal string would be 0A, so one byte becomes two bytes long in the string.

The HexFromBin function is defined in MAPIUTIL.H.

See Also

ScBinFromHexBounded function


 HrAllocAdviseSink

[New - Windows 95]

Creates an advise sink object, given a context specified by the calling implementation and a callback function to be triggered by an event notification.

Syntax

HrAllocAdviseSink(LPNOTIFCALLBACK lpfnCallback, LPVOID lpvContext, LPMAPIADVISESINK FAR* lppAdviseSink)

Parameters

lpfnCallback

Input parameter pointing to the callback function (that is, the function based on the NOTIFCALLBACK function prototype) defined by a client application or service provider that MAPI is to call when a notification event occurs for the newly created advise sink.

lpvContext

Input parameter pointing to an arbitrary value passed to the callback function when MAPI calls it. This value can represent an address of significance to the client or provider. Typically, for C++ code, the lpvContext parameter represents a pointer to the address of an object.

lppAdviseSink

Output parameter pointing to a variable where the returned advise sink object is stored.

Comments

To use this function, your client or provider creates an object to receive notifications, creates a notification callback function based on the NOTIFCALLBACK function prototype that goes with that object, and passes a pointer to the object in the HrAllocAdviseSink function as the lpvContext value. Doing so performs a notification; and as part of the notification process, MAPI calls the callback function with the object pointer as the context.

MAPI implements its notification engine asynchronously. In C++ , the notification callback can be a method of your object. If the object generating the notification is not present, the application requesting notification must keep a separate reference count for that object for the object's advise sink.

HrAllocAdviseSink should be used sparingly; it is safer for clients to create their own advise sinks.

The HrAllocAdviseSink function is defined in MAPIUTIL.H

See Also

NOTIFCALLBACK function prototype


 HrAllocAdviseSink, NOTIFCALLBACK

[New - Windows 95]

The NOTIFCALLBACK prototype function defines a client application or service provider callback function that the MAPI calls to send an event notification. This callback function can only be used when wrapped in an advise sink object created by calling HrAllocAdviseSink.

Syntax

ULONG (STDAPICALLTYPE NOTIFCALLBACK)
(LPVOID lpvContext, ULONG cNotification,
LPNOTIFICATION lpNotifications)

Parameters

lpvContext

Input parameter specifying a pointer to an arbitrary value passed to the callback function when MAPI calls it. This value can represent an address of significance to the client application or service provider. Typically, for C++ code, lpvContext represents a pointer to the address of a C++ object.

cNotification

Input parameter specifying the number of event notifications in the array indicated by lpNotifications.

lpNotifications

Output parameter specifying a pointer to the location to which this function writes an array of NOTIFICATION structures containing the event notifications.

Return Values

The set of valid return values depends on whether a client or a provider is implementing the NOTIFCALLBACK function. Clients should always return S_OK. Providers should return either S_OK or NOTIFY_CANCELED. If NOTIFY_CANCELED is returned, the caller of IMAPISupport::Notify will receive NOTIFY_CANCELED in the lpUlFlags parameter.

Comments

The NOTIFCALLBACK function prototype is defined in MAPIDEFS.H.

See Also

HrAllocAdviseSink function, IMAPIAdviseSink::OnNotify method, NOTIFICATION structure


 HrComposeEID

[New - Windows 95]

Creates a compound entry identifier for an object, usually a message in a message store.

Syntax

HrComposeEID(LPMAPISESSION psession, ULONG cbStoreRecordKey, LPBYTE pStoreRecordKey, ULONG cbMsgEID, LPENTRYID pMsgEID, ULONG FAR* pcbEID, LPENTRYID FAR* ppEID)

Parameters

psession

Input parameter pointing to the session in use by the client application.

cbStoreRecordKey

Input parameter containing the size, in bytes, of the record key of the message store holding the message or other object. If zero is passed in the cbStoreRecordKey parameter, the ppEID parameter points to a copy of the object's entry identifier.

pStoreRecordKey

Input parameter pointing to the record key of the message store holding the message or other object.

cbMsgEID

Input parameter containing the size, in bytes, of the entry identifier of the message or other object.

pMsgEID

Input parameter pointing to the entry identifier of the object.

pcbEID

Output parameter pointing to a variable where the size, in bytes, of the returned identifier is stored.

ppEID

Output parameter pointing to a variable where the returned data is stored. If the cbStoreRecordKey parameter value is greater than zero, the ppEID parameter points to a pointer to the compound entry identifier that is created. If cbStoreRecordKey is zero, ppEID  points to a pointer to a copy of the object's entry identifier.

Comments

If the message or other object for which the compound entry identifier is being created resides in a message store, the identifier is created from the object's entry identifier and the store's record key. If the object is not in a store (that is, if the byte count for the store record key passed in cbStoreRecordKey is zero), the object's entry identifier is simply copied.

This function, primarily for use with CMC, enables CMC-based applications to work with objects in multiple stores through the use of compound entry identifiers.

The HrComposeEID function is defined in MAPIUTIL.H. See Also

HrComposeMsgID function, HrDecomposeEID function, HrDecomposeMsgID function


 HrComposeMsgID

[New - Windows 95]

Creates an ASCII entry-identifier string for an object, usually a message in a message store.

Syntax

HrComposeMsgID(LPMAPISESSION psession, ULONG cbStoreRecordKey, LPBYTE pStoreRecordKey, ULONG cbMsgEID, LPENTRYID pMsgEID, LPTSTR FAR* pszMsgID)

Parameters

psession

Input parameter pointing to the session in use by the client application.

cbStoreRecordKey

Input parameter containing the size, in bytes, of the record key of the message store holding the message or other object. If zero is passed in the cbStoreRecordKey parameter, the pszMsgID parameter points to a copy of the entry identifier converted to text.

pStoreRecordKey

Input parameter pointing to the record key of the message store holding the message or other object.

cbMsgEID

Input parameter containing the size, in bytes, of the entry identifier of the message or other object.

pMsgEID

Input parameter pointing to the entry identifier of the object.

pszMsgID

Output parameter pointing to a variable where the returned data is stored.. If the cbStoreRecordKey parameter is greater than zero, the pszMsgID parameter points to a compound entry identifier converted to text. If cbStoreRecordKey is zero, it points to noncompound entry identifier converted to text.

Comments

If the message or other object for which the compound entry identifier is being created resides in a message store, the identifier string is created from the object's entry identifier and the store's record key. If the object is not in a store (that is, if the byte count for the store record key passed in cbStoreRecordKey is zero), the object's entry identifier is simply copied and converted into a string.

The HrComposeMsgID function enables applications based on Simple MAPI and OLE to work with objects in multiple stores through the use of compound entry identifiers

. Calling HrComposeMsgID is essentially equivalent to calling the HrComposeEID function and then the HrSzFromEntryID function.

The HrComposeMsgID function is defined in MAPIUTIL.H.

See Also

HrComposeEID function, HrDecomposeEID function, HrDecomposeMsgID function, HrSzFromEntryID function


 HrDecomposeEID

[New - Windows 95]

Takes apart the compound entry identifier of an object, usually a message in a message store, into the entry identifier of that object within the store and that store's entry identifier.

Syntax

HrDecomposeEID(LPMAPISESSION psession, ULONG cbEID, LPENTRYID pEID, ULONG FAR* pcbStoreEID, LPENTRYID FAR* ppStoreEID , ULONG FAR* pcbMsgEID, LPENTRYID FAR* ppMsgEID)

Parameters

psession

Input parameter pointing to the session in use by the client application.

cbEID

Input parameter containing the size, in bytes, of the compound entry identifier to be taken apart..

pEID

Input parameter pointing to the compound entry identifier to be taken apart.

pcbStoreEID

Output parameter pointing to a variable where is stored the returned size, in bytes, of the entry identifier of the message store containing the object. If the pEID parameter points to a noncompound entry identifier, then the pcbStoreEID parameter points to zero.

ppStoreEID

Output parameter pointing to a variable where the returned entry identifier of the message store containing the object is stored. If pEID points to a noncompound entry identifier, NULL is returned in the ppStoreEID parameter.

pcbMsgEID

Output parameter pointing to a variable where the returned size, in bytes, of the entry identifier of the objec is stored. If pEID points to a noncompound entry identifier, then the pcbMsgEID parameter is equal to the value of the cbEID parameter.

ppMsgEID

Output parameter pointing to a variable where the returned  entry identifier of the object is stored. If pEID points to a noncompound entry identifier, memory is copied so that the pointer in pEID is equal to the pointer to the pointer in the ppMsgEID parameter.

Comments

If the identifier identified by pEID is compound, it is split into the entry identifier of the object within its message store and that store's entry identifier. Noncompound entry identifier strings are copied. The compound identifier taken apart is usually one created by the HrComposeEID function.

The memory that holds the pEID pointer is released upon successful completion of this function. The calling implementation is responsible for freeing memory for the output parameters.

The HrDecomposeEID function is defined in MAPIUTIL.H.

See Also

HrComposeEID function, HrComposeMsgID function, HrDecomposeMsgID function


 HrDecomposeMsgID

[New - Windows 95]

Takes apart the compound entry-identifier string of an object, usually a message in a message store, into the entry identifier of that object within the store and that store's entry identifier.

Syntax

HrDecomposeMsgID(LPMAPISESSION psession, LPTSTR szMsgID, ULONG FAR* pcbStoreEID, LPENTRYID FAR* ppStoreEID , ULONG FAR* pcbMsgEID, LPENTRYID FAR* ppMsgEID)

Parameters

psession

Input parameter pointing to the session in use by the client application.

szMsgID

Input parameter containing the entry identifier string of the object.

pcbStoreEID

Output parameter pointing to a variable where is stored the returned size, in bytes, of the entry identifier string of the message store containing the object. If the szMsgID parameter points to a noncompound entry-identifier string, then the pcbStoreEID parameter points to zero.

ppStoreEID

Output parameter pointing a variable where is stored the returned entry identifier of the message store containing the object. If szMsgID points to a noncompound entry identifier, NULL is returned in the ppStoreEID parameter.

pcbMsgEID

Output parameter pointing to a variable storing the returned size, in bytes, of the entry identifier string of the object (within its store). If szMsgID contains a noncompound entry-identifier string, then the pcbMsgEID parameter is equal to the value of the cbEID parameter.

ppMsgEID

Output parameter pointing to a pointer to the entry identifier of the object (within its store). If szMsgID is a noncompound entry identifier string.

Comments

Noncompound entry-identifier strings are accepted. The compound identifier string taken apart is usually one created by the HrComposeMsgID function.

The memory that holds the compound entry-identifier string is released upon successful completion of this function.

The HrDecomposeMsgEID function is defined in MAPIUTIL.H.

See Also

HrComposeEID function, HrComposeMsgID function, HrDecomposeEID function


 HrEntryIDFromSz

[New - Windows 95]

Creates an entry identifier from an ASCII-encoded string, and allocates memory for the entry identifier.

Syntax

HrEntryIDFromSz(LPTSTR sz, ULONG FAR* pcb, LPENTRYID FAR* ppentry)

Parameters

sz

Input parameter pointing to the ASCII-encoded string from which to create an entry identifier.

pcb

Output parameter pointing to a variable storing the size, in bytes, of the entry identifier pointed to by the ppentry parameter.

ppentry

Output parameter pointing to the ENTRYID structure to which this function writes the entry identifier.

Comments

The HrEntryIDFromSz function is defined in MAPIUTIL.H.

See Also

ENTRYID structure, HrSzFromEntryID function


 HrGetOneProp

[New - Windows 95]

Retrieves the value of a single property from an IMAPIProp interface or an interface derived from IMAPIProp.

Syntax

HrGetOneProp(LPMAPIPROP pmp, ULONG ulPropTag, LPSPropValue FAR* ppprop)

Parameters

pmp

Input parameter pointing to the interface from which the property value is retrieved.

ulPropTag

Input parameter containing the property tag of the property to be retrieved.

ppprop

Output parameter pointing a variable where the returned SPropValue structure defining the retrieved property value is stored.

Return Values

MAPI_E_NOT_FOUND

The requested object does not exist.

Comments

Unlike the method IMAPIProp::GetProps, HrGetOneProp does not return a warning. Because it retrieves only one property, it simply either succeeds or fails. To retrieve multiple properties, your client application or service provider should call GetProps.

The HrGetOneProp function is defined in MAPIUTIL.H.

See Also

HrSetOneProp function, IMAPIProp : IUnknown interface, IMAPIProp::GetProps method, SPropValue structure


 HrSetOneProp

[New - Windows 95]

Changes one property of an object.

Syntax

HrSetOneProp(LPMAPIPROP pmp, LPSPropValue pprop)

Parameters

pmp

Input parameter pointing to an IMAPIProp interface or an interface derived from IMAPIProp.

pprop

Input parameter pointing to the SPropValue structure defining the property to be changed.

Comments

Unlike the method IMAPIProp::SetProps, the HrSetOneProp function does not return a warning. Because it sets only one property, it simply either succeeds or fails. To change multiple properties, use the faster SetProps.

The HrSetOneProp function is defined in MAPIUTIL.H.

See Also

HrGetOneProp function, IMAPIProp : IUnknown interface, IMAPIProp::SetProps method, SPropValue structure


 HrSzFromEntryID

[New - Windows 95]

Encodes an entry identifier into an ASCII string, and allocates memory for the string.

Syntax

HrSzFromEntryID(ULONG cb, LPENTRYID pentry, LPTSTR FAR* psz)

Parameters

cb

Input parameter containing the size, in bytes, of the entry identifier pointed to by the pentry parameter.

pentry

Input parameter pointing to an ENTRYID structure defining the entry identifier to be encoded.

psz

Output parameter pointing to a variable where the returned ASCII-encoded string is stored.

Comments

To use Simple MAPI to look at messages in a folder other than the Inbox folder (the only folder recognized by Simple MAPI), your application must use Extended MAPI methods. It calls these methods to enumerate the messages in the folder, looking through the contents table for the folder, which stores entry identifiers. When the application finds the entry identifier for the desired message, it can call the HrSzFromEntryID function to convert the identifier to a Simple MAPI message identifier. Then your application can call the Simple MAPI MAPIReadMail function to retrieve the required information about the message.

The HrSzFromEntryID function is defined in MAPIUTIL.H.

See Also

ENTRYID structure, HrComposeEID function, HrEntryIDFromSz function, MAPIReadMail function


 HrValidateIPMSubtree

[New - Windows 95]

Adds one or more standard interpersonal message (IPM) folders to a message store.

Syntax

HrValidateIPMSubtree(LPMDB lpMDB, ULONG ulFlags,  ULONG FAR* lpcValues, LPSPropValue FAR* lppProps,  LPMAPIERROR FAR* lppMapiError)

Parameters

lpMDB

Input parameter pointing to a message store object.

ulFlags

Input parameter containing a bitmask of flags used to indicate options. The following flags can be set:

MAPI_FORCE_CREATE

Requests that a folder be verified before creation, even if message store properties indicate that they are valid. An application would typically set this flag when an error indicates that the folder structure has been damaged.

MAPI_FULL_IPM_TREE

Requests that the following folders be created in addition to the standard ones: Folder and Common Views, and the Inbox, Outbox and Sent Items folders under the IPM-subtree root folder. MAPI_FULL_IPM_TREE is normally set when the message store is the default store.

lpcValues

Output parameter containing the number of values returned in the lppProps property value array. The value of the lpcValues parameter can be zero if lppProps is NULL.

lppProps

Output parameter pointing to an array of SPropValue structures indicating values for PR_VALID_FOLDER_MASK and related properties. The IPM Inbox's entry identifier is included, with a special property tag equal to PROP_TAG(PT_BINARY, PROP_ID_NULL). The lppProps parameter can be NULL, indicating that the calling implementation is not interested in getting a property value array returned.

lppMapiError

Output parameter pointing to a pointer to the returned MAPIERROR structure containing version, component, and context information for the error. The lppMAPIError parameter can be set to NULL if there is no MAPIERROR structure to return.

Comments

MAPI uses the HrValidateIPMSubtree function internally to construct the standard IPM folder tree in a message store when it is first opened, or when it is made the default store.

HrValidateIPMSubtree always creates the IPM subtree root folder, the Deleted Items folder under the IPM subtree root, and the finders folder in the message store root.

.

HrValidateIPMSubtree sets the property PR_VALID_FOLDER_MASK to indicate whether each folder has a valid entry identifier. The following related entry-identifier properties on the message store are set to the entry identifiers of the corresponding folders and returned in lppProps along with PR_VALID_FOLDER_MASK:

PR_COMMON_VIEWS_ENTRYID
PR_FINDER_ENTRYID
PR_IPM_OUTBOX_ENTRYID
PR_IPM_SENTMAIL_ENTRYID
PR_IPM_SUBTREE_ENTRYID
PR_IPM_WASTEBASKET_ENTRYID
PR_VIEWS_ENTRYID
PROP_TAG(PT_BINARY, PROP_ID_NULL) — placeholder for IPM Inbox

The HrValidateIPMSubtree function is defined in MAPIUTIL.H.

See Also

IMAPISession::OpenMsgStore method, MAPIERROR structure, PR_VALID_FOLDER_MASK property, SPropValue structure


 LPropCompareProp

[New - Windows 95]

Compares two property values to determine if they are equal.

Syntax

LONG LPropCompareProp(LPSPropValue lpSPropValueA, LPSPropValue lpSPropValueB)

Parameters

lpSPropValueA

Input parameter pointing to an SPropValue structure defining the first property value to be compared.

lpSPropValueB

Input parameter pointing to an SPropValue structure defining the second property value to be compared.

Return Values

This function returns one of the following for most property types:

•	 < zero if the value indicated by the lpSPropValueA parameter is less than that indicated by the lpSPropValueB parameter.

•	> zero if the value indicated by lpSPropValueA is greater than that indicated by lpSPropValueB

•	Zero if the value indicated by lpSPropValueA equals the value indicated by lpSPropValueB

For property types that have no intrinsic ordering, such as Boolean or error types, the LPropCompareProp function returns an undefined value if the two property values are not equal. This value is nonzero and consistent across calls.

Comments

Use LPropCompareProp only if the types of two properties are the same.

Before calling LPropCompareProp, your client application or service provider must first retrieve the properties for comparison with a call to the IMAPIProp::GetProps method. When the application or provider calls LPropCompareProp, the function first examines the property tags to ensure that the comparison of property values is valid. The function then compares the property values, returning an appropriate value.

If the values are unequal, this function determines which one is the greater. The properties that LPropCompareProp compares do not have to belong to the same object.

The LPropCompareProp function is defined in MAPIUTIL.H.

See Also

IMAPIProp::GetProps method, SPropValue structure


  MAPIDeInitIdle

[New - Windows 95]

Shuts down the DLL for the idle engine. Your client application or service provider should call this function when it no longer needs the idle engine, for example, when it is about to stop processing.

Syntax

VOID MAPIDeInitIdle(void)

Comments

The MAPIDeInitIdle function is defined in MAPIUTIL.H.

See Also

MAPIInitIdle, FNIDLE


 MAPIInitIdle

[New - Windows 95]

Initializes the DLL for the idle engine. A client application or service provider must call MAPIInitIdle before calling any other idle engine function.

Syntax

LONG MAPIInitIdle(LPVOID lpvReserved)

Parameter

lpvReserved

Reserved, must be zero.

Return Values

MAPIInitIdle returns zero if initialization is successful, and -1 otherwise. When the MAPIInitIdle function is called multiple times, only the first call succeeds.

Comments

The MAPIInitIdle function is defined in MAPIUTIL.H.

See Also

MAPIDeinitIdle, FNIDLE


 MapStorageSCode

[New - Windows 95]

Maps an HRESULT return value from an OLE storage object to a MAPI return value of the SCODE type.

Warning  There is no guarantee that this function will exist in shipped versions of the message dynamic-link library (DLL).

Syntax

SCODE MapStorageSCode(SCODE StgSCode)

Parameters

StgSCode

Input parameter containing the HRESULT return value from an OLE storage object to be mapped to a MAPI SCODE value.

Return Values

This function returns an SCODE value corresponding to the value of the StgSCode parameter. If this function cannot find a matching value, it returns MAPI_E_CALL_FAILED.

Comments

Extended MAPI provides this function for the internal use of MAPI SDK components that base their message implementations on the message DLL. Because these components open OLE storage themselves, they must be able to map error values returned for problems with OLE storage to MAPI SCODE values.

The MapStorageSCode is defined in IMESSAGE.H.


 OpenIMsgSession

[New - Windows 95]

Groups the creation of messages within a session, so that closing the session also closes all messages created within that session.

Syntax

SCODE OpenIMsgSession(LPMALLOC lpMalloc, ULONG ulFlags, LPMSGSESS FAR* lppMsgSess)

Parameters

lpMalloc

Input parameter pointing to a standard OLE memory allocator.

ulFlags

Reserved; must be zero.

lppMsgSess

Output parameter pointing to a variable where the returned message-session object is stored.

Comments

To establish a message session, a client application should call the OpenIMsgSession function to obtain a message session pointer before calling the OpenIMsgOnIStg function for the first time in the session. When finished with the message session, the application should call the CloseIMsgSession function to end it.

This function is used by clients that want to deal with several related message on storage objects. If only a single message is to be open at a time, the application does not need to track multiple messages. Thus it has little cause to create a message session and no reason to call OpenIMsgSession.

The OpenIMsgSession function is defined in IMESSAGE.H.Use of OLE memory allocators is described in Inside OLE, Second Edition, by Kraig Brockschmidt, and OLE Programmer's Reference, Volume One and Volume Two.

See Also

CloseIMsgSession function, IMAPISession : IUnknown interface, OpenIMsgOnIStg function


 PpropFindProp

[New - Windows 95]

Searches for a specified property in a property set.

Syntax

PpropFindProp(LPSPropValue rgprop, ULONG cprop, ULONG ulPropTag)

Parameters

rgprop

Input parameter containing an array of SPropValue structures that define the properties to be searched through.

cprop

Input parameter containing the number of properties in the property set indicated by the rgprop parameter.

ulPropTag

Input parameter containing the property tag for the  property to search for in the property set indicated by rgprop.

Return Values

Returns an SPropValue structure defining the property that matches the input property tag, and NULL if there is no match.

Comments

If the given property tag indicates a property of type PT_UNSPECIFIED, this function finds a match only for the property identifier within the tag. Otherwise, it finds a match for the entire property tag, including the property type, and returns the property so identified.

The PpropFindProp function is defined in MAPIUTIL.H.

See Also

SPropValue structure


 PreprocessMessage

[New - Windows 95]

The PreprocessMessage function prototype, implemented by transport providers, preprocesses message contents or the format of a message.

Syntax

HRESULT PreprocessMessage(LPVOID lpvSession, LPMESSAGE lpMessage, LPADRBOOK lpAdrBook, LPMAPIFOLDER lpFolder, LPALLOCATEBUFFER, AllocateBuffer, LPALLOCATEMORE, AllocateMore, LPFREEBUFFER FreeBuffer, ULONG FAR* lpcOutbound, LPMESSAGE FAR* FAR* lpppMessage, LPADRLIST FAR* lppRecipList)

Parameters

lpvSession

Input parameter pointing to the session to be used.

lpMessage

Input parameter pointing to the message to be preprocessed.

lpAdrBook

Input parameter pointing to the address book from which the user should select recipients for the message.

lpFolder

Input-output parameter pointing to a folder. On input, this parameter points to the folder that contains messages to be preprocessed. On output, this parameter points to the folder where preprocessed messages have been placed.

lpAllocateBuffer

Input parameters pointing to the MAPIAllocateBuffer function, to be used to allocate memory.

lpAllocateMore

Input parameters pointing to the MAPIAllocateMore function, to be used to allocate additional memory where required.

lpFreeBuffer

Input parameters pointing to the MAPIFreeBuffer function, to be used to free memory.

lpcOutbound

Output parameter pointing to the location to which this function writes the number of messages in the array indicated by the lppMessage parameter.

lpppMessage

Output parameter pointing to the location to which this function writes the address of an array of messages to which this function has added the preprocessed message and any other additional messages it has generated.

lppRecipList

Output parameter pointing to an optional ADRLIST structure listing preprocessor-detected recipients for which the message is undeliverable.

Comments

A transport-provider message preprocessor can present a progress user interface. However, it should never use a dialog box requiring user interaction.

Your preprocessor must take care when adding large amounts of data to an outbound message. This type of message might be stored in a server-based message store, causing the preprocessor to have to access the remote store unnecessarily. The preprocessor should have an option that allows it to store data that takes a large amount of space in a local message store and provide a reference to that local store in the message.

Note that your preprocessor should not release any of the objects originally input to PreprocessMessage.

Before the client application can call this function, the transport provider must have registered the function in a call to the IMAPISupport::RegisterPreprocessor method. After calling PreprocessMessage, the client application cannot continue submitting a message until the function returns.

Before returning, PreprocessMessage writes the preprocessed message and any additional messages that it generates to a message array. If the function detects unreachable message recipients during operation, it writes them in a list to the client application.

The PreprocessMessage function is defined in MAPISPI.H.

See Also

ADRLIST structure, IAddrBook : IMAPIProp interface, IMAPIFolder : IMAPIContainer interface, IMAPISupport : IUnknown interface, IMAPISupport::RegisterPreprocessor method


 PropCopyMore

[New - Windows 95]

Copies a single property value from a source location to a destination location.

Syntax

SCODE PropCopyMore(LPSPropValue lpSPropValueDest, LPSPropValue lpSPropValueSrc, ALLOCATEMORE *lpfAllocMore, LPVOID lpvObject)

Parameters

o

lpSPropValueSrc

Input parameter pointing to the SPropValue structure containing the property value to be copied.

lpfAllocMore

Input parameter pointing to the MAPIAllocateMore function to be used to allocate additional memory if the destination location is not large enough to hold the property to be copied.

lpvObject

Input parameter pointing to an object for which MAPIAllocateMore will allocate space if necessary.

Comments

A client application or service provider can use the PropCopyMore function to copy a property out of a table that is about to be freed in order to use it elsewhere.

The function does not need to allocate memory unless the property value copied is of a type, such as STRING8, that does not fit in an SPropValue structure. For these large properties, the function allocates memory using the MAPIAllocateMore indicated on input.

Injudicious use of PropCopyMore fragments memory; consider using the ScCopyProps function instead.

The PropCopyMore function is defined in MAPIUTIL.H.

See Also

MAPIAllocateMore function, ScCopyProps function, SPropValue structure


 RemovePreprocessInfo

[New - Windows 95]

Removes from a message preprocessed information written by a function based on the PreprocessMessage function prototype.

Syntax

HRESULT RemovePreprocessInfo(LPMESSAGE lpMessage)

Parameters

lpMessage

Input parameter pointing to the preprocessed message from which information is to be removed.

Comments

A client application calls the RemovePreprocessInfo function. A transport provider registers RemovePreprocessInfo at the same time it registers the parallel function based on PreprocessMessage in a call to the IMAPISupport::RegisterPreprocessor method.

An image rendering suitable for fax transmission is an example of preprocessed information written by PreprocessMessage. A client usually calls RemovePreprocessInfo after sending a message containing preprocessed information.

The RemovePreprocessInfo function is defined in MAPISPI.H.

See Also

IMAPISupport::RegisterPreprocessor method, PreprocessMessage function prototype


 ScBinFromHexBounded

[New - Windows 95]

Converts the specified portion of a string representation of a hexadecimal number into a binary number.

Syntax

SCODE ScBinFromHexBounded(LPTSTR sz, LPBYTE pb, ULONG cb)

Parameters

sz

Input parameter pointing to the null-terminated string to be converted. Valid characters include the hexadecimal characters 0 through 9 and both uppercase and lowercase characters a through f.

pb

Output parameter pointing to a variable where the returned binary number is stored.

cb

Input parameter containing the size, in bytes, of the pb parameter.

See Also

FBinFromHex function, HexFromBin function


 ScCopyNotifications

[New - Windows 95]

Copies a group of event notifications to a single block of memory.

Syntax

SCODE ScCopyNotifications(int cntf, LPNOTIFICATION rgntf, LPVOID pvDst, ULONG FAR* pcb)

Parameters

cntf

Input parameter containing the number of NOTIFICATION structures in the array indicated by the rgntf parameter.

rgntf

Input parameter pointing to an array of NOTIFICATION structures defining the event notifications to be copied.

pvDst

Output parameter pointing to the location to which this function copies the notifications.

pcb

Output parameter pointing to the size, in bytes, of the array indicated by rgntf.

Comments

If pcb is NULL, nothing happens; if non-null, the ScCopyNotifications function stores the size and bytes of the array. The pvDst parameter must be large enough to accommodate the entire array.

The ScCopyNotifications function is defined in MAPIUTIL.H.

See Also

NOTIFICATION structure, ScCountNotifications function, ScRelocNotifications function


 ScCopyProps

[New - Windows 95]

Copies the properties defined by an array of SPropValue structures to a new destination.

Syntax

SCODE ScCopyProps(int cprop, LPSPropValue rgprop, LPVOID pvDst, ULONG FAR* pcb)

Parameters

cprop

Input parameter containing the number of properties to be copied.

rgprop

Input parameter pointing into an array of SPropValue structures that define the properties to be copied. The rgprop parameter need not point to the beginning of the array, but it must point to the beginning of one of the SPropValue structures in the array.

pvDst

Input parameter pointing to the initial position in memory to which this function copies the properties.

pcb

Output parameter containing the size, in bytes, of the block of memory indicated by the pvDst parameter.

Comments

The new array and its data will reside in a buffer created with a single allocation, and the ScRelocProps function can be used to adjust the pointers in the individual SPropValue structures. Note that prior to this adjustment, the pointers will not be valid.

ScCopyProps maintains the original property order for the copied property array.

The ScCopyProps function is defined in MAPIUTIL.H.

See Also

ScDupPropset function, SPropValue structure, ScRelocProps function


 ScCountNotifications

[New - Windows 95]

Determines the size, in bytes, of an array of event notifications, and validates the memory associated with the array.

Syntax

SCODE ScCountNotifications(int cntf, LPNOTIFICATION rgntf, ULONG FAR* pcb)

Parameters

cntf

Input parameter containing the number of NOTIFICATION structures in the array indicated by the rgntf parameter.

rgntf

Input parameter pointing to the array of NOTIFICATION structures whose size is to be determined.

pcb

Output parameter pointing to a variable where the size, in bytes, is stored of the array pointed to by rgntf.

Comments

If NULL is passed in the pcb parameter, no counting is done; if a non-null value is passed in pcb, the ScCountNotifications function determines the size of the array and stores the result in pcb. The pcb parameter must be large enough to accommodate the entire array.

The ScCountNotifications function is defined in MAPIUTIL.H.

See Also

NOTIFICATION structure, ScCopyNotifications function, ScRelocNotifications function


 ScCountProps

[New - Windows 95]

Determines the size, in bytes, of a property value array, and validates the memory associated with the array.

Syntax

SCODE ScCountProps (int cprop, LPSPropValue rgprop, ULONG FAR* pcb)

Parameters

cprop

Input parameter containing the number of properties in the array indicated by the rgprop parameter.

rgprop

Input parameter pointing to a range in an array of SPropValue structures that defines the properties whose size is to be determined. This range does not necessarily start at the beginning of the array.

pcb

Output parameter pointing to a variable where the size, in bytes, is stored of the property array.

Comments

If any property in the property value array has a property identifier of PROP_ID_NULL or PROP_ID_INVALID, the ScCountProps function returns MAPI_E_INVALID_PARAMETER. ScCountProps also returns this value if the property array contains a multivalued property with no property values.

As it is counting, this function validates the memory associated with the array. ScCountProps only works with properties about which MAPI has information.

The ScCountProps function is defined in MAPIUTIL.H.

See Also

PropCopyMore function, SPropValue structure


 ScLocalPathFromUNC

[New - Windows 95]

Locates a local path counterpart to the given UNC path.

Syntax

SCODE ScLocalPathFromUNC(LPSTR szUNC, LPSTR szLocal, UINT cchLocal)

Parameters

szUNC

Input parameter containing a path in the format \\SERVER\SHARE\PATH of a file or directory.

szLocal

Output parameter containing a path in the format DRIVE:\PATH of the same file or directory as for the szUNC parameter.

cchLocal

Input parameter containing the size of the buffer for the output string.

Comments

The ScLocalPathFromUNC function is defined in MAPIUTIL.H.

See Also

ScUNCFromLocalPath function


 ScRelocNotifications

[New - Windows 95]

Adjusts a pointer within a specified event notification array.

Syntax

SCODE ScRelocNotifications(int cntf, LPNOTIFICATION rgntf, LPVOID pvBaseOld, LPVOID pvBaseNew,ULONG FAR* pcb)

Parameters

cntf

Input parameter containing the number of notifications in the array indicated by the rgntf parameter.

rgntf

Input parameter pointing to an array of NOTIFICATION structures defining event notifications.

pvBaseOld

Input parameter pointing to the original base address of the array indicated by rgntf.

pvBaseNew

Input parameter containing the location to which this function writes the new base address of the array indicated by rgntf.

pcb

Output parameter pointing to the location to which this function writes the number of bytes needed to contain the array indicated by the pvBaseNew parameter.

Comments

The ScRelocNotifications is defined in MAPIUTIL.H.

See Also

NOTIFICATION structure, ScCopyNotifications function, ScCountNotifications function


 ScRelocProps

[New - Windows 95]

Adjusts the pointers in a SPropValue array after the array and its underlying data have been copied or moved to a new location.

Syntax

SCODE ScRelocProps(int cprop, LPSPropValue rgprop, LPVOID pvBaseOld, LPVOID pvBaseNew, ULONG FAR* pcb)

Parameters

cprop

Input parameter containing the number of properties in the array indicated by the rgprop parameter.

rgprop

Input parameter pointing to an array of SPropValue structures for which pointers are to be adjusted.

pvBaseOld

Input parameter pointing to the original base address of the array pointed to by rgprop. For the ScRelocProps function to work properly, the array and its underlying data must initially reside together in memory allocated with a single call to the MAPIAllocateBuffer function.

pvBaseNew

Input parameter pointing to the new base address of the array indicated by rgprop. Note that the array and data must have been moved or copied together into a buffer created with a single MAPIAllocateBuffer call.

pcb

Output parameter pointing to the number of bytes needed to contain the array indicated by pvBaseNewparameter.

Comments

ScRelocProps assumes that the property value array was originally in a single allocation like the one in the ScCopyProps function. If using a property value that is built from disjoint blocks of memory, use ScCopyProps instead.

To maintain the validity of pointers in an SPropValue array when writing it to and reading it from a disk, perform the following:

1.	Before writing the array and data to disk, use ScRelocProps on the array with pvBaseNew pointing to some standard value (zero, for instance).

2.	After reading the array and data from a disk, use ScRelocProps on the array with the pvBaseOld parameter equal to the same standard value used in 1. Note that the array and data must be read into a buffer created with a single allocation.

The ScRelocProps function is defined in MAPIUTIL.H.

See Also

MAPIAllocateBuffer function, ScCopyProps function, ScCountProps function, ScDupPropset function, SPropValue structure


 ScUNCFromLocalPath

[New - Windows 95]

Locates a UNC path counterpart to the given local path.

Syntax

SCODE ScUNCFromLocalPath(LPSTR szLocal, LPSTR szUNC, UINT cchUNC)

Parameters

szLocal

Output parameter containing a DRIVE:PATH name of a file or directory.

szUNC

Input parameter containing a \\SERVER\SHARE\PATH of the same file or directory.

cchUNC

Input parameter containing the size of the buffer for the output string.

Comments

The ScUNCFromLocalPath function is defined in MAPIUTIL.H.

See Also

ScLocalPathFromUNC function


UIAddRef
 UlAddRef

[New - Windows 95]

Provides an alternative way to invoke the method IUnknown::AddRef.

Syntax

ULONG UlAddRef(LPVOID punk)

Parameters

punk

Input parameter pointing to an interface derived from the IUnknown interface, in other words any MAPI interface.

Return Values

Returns the value returned by IUnknown::AddRef, which is the new value of the reference count for the interface. The value is nonzero.

Comments

The UlAddRef function generates less code than the AddRef method and can be used in situations requiring a minimum of code.

The UlAddRef function is defined in MAPIUTIL.H.

See Also

UIRelease function


UIPropSize
 UlPropSize

[New - Windows 95]

Obtains the size of a single property value.

Syntax

ULONG UlPropSize(LPSPropValue lpSPropValue)

Parameters

lpSPropValue

Input parameter pointing to an SPropValue structure defining the property to be measured.

Return Values

Returns the size, in bytes, of the property value for the specified property. It disregards the size of the remainder of the SPropValue structure.

Comments

The UlPropSize function is defined in MAPIUTIL.H.

See Also

SPropValue structure


UIRelease
 UlRelease

[New - Windows 95]

Provides an alternative way to invoke the OLE method IUnknown::Release.

Syntax

ULONG UlRelease(LPVOID punk)

Parameters

punk

Input parameter pointing to an interface derived from the IUnknown interface, in other words any MAPI interface.

Return Values

This function returns the value returned by IUnknown::Release.

Comments

The return value can be equal to the reference count for the object to be released. The reference count is the number of existing pointers to the object.

If the punk parameter specifies NULL, the function returns immediately without calling IUnknown::Release. This feature can save code if your application or provider declares an interface pointer and initializes it to NULL. Code is used in the method indication but saved in not testing for NULL.

The UlRelease function is defined in MAPIUTIL.H.

See Also

UIAddRef function


 MAPISVC.INF File Format and WIN.INI File Format

This chapter contains information about the MAPISVC.INF file format and the WIN.INI file format.


 MAPISVC.INF File Format

The MAPISVC.INF file acts as the central database for MAPI message service configuration information.MAPISVC.INF contains information for MAPI, information for each of the message services installed on a computer, and information for the service providers that belong to each message service. Some of this information is mandatory; without it, without it MAPI cannot load or configure the message service or service provider in question. Message service and service provider implementors must explicitly add the required information as part of their installation process. For example, MAPI cannot load a service provider without information on its name and path. Therefore, MAPISVC.INF must contain an entry for the name and an entry for the full path of each service provider.

Other configuration information is optional; its inclusion in MAPISVC.INF depends on the particular message service or service provider. For example, some service providers require a password to be supplied at logon time. Rather than forcing the user to enter the password with every logon, a service provider might store the password in the profile

When building a new profile or adding to an existing one, information that is required or helpful for configuring each message service and service provider is copied from MAPISVC.INF into the new or changed profile.

MAPISVC.INF is divided into linked hierarchical sections. The top level, divided into three sections called [Services], [Help File Mappings], and [Default Services], contains entries that apply to all profiles. Entries in the [Services] section link to subsequent MAPISVC.INF sections that are specific to individual message services.Entries in the message service sections in turn link to subsequent sections that are specific to individual service providers belonging to the message service.

Figure 8.1, following, illustrates the organization of a typical MAPISVC.INF file. The sections are organized hierarchically, with the [Help File Mappings], [Default Services], and [Services] sections at the top of the hierarchy. The [Help File Mappings] section has one entry for every .HLP file provided by an installed message service. The [Default Services] section has one entry for each message service that should be added to the profile designated as the default. These are the message services that are loaded at session start up if the user has not explicitly selected any others.

The [Services] section contains one entry for every message service installed on the computer workstation. In this example, there are three message services: AB, MsgService, and MS. The name on the right hand side of the equal sign for each message service is the service's display name. Each message service has its own section elsewhere in the file that is linked to one or more service provider sections. There is one service provider section for every service provider that belongs to the message service. The AB and MS message services are single provider services whereas three service providers belong to the MsgService service.

All MAPISVC.INF files will have a similar organization with [Help File Mappings], [Default Services], and [Services] sections and the corresponding message service and service provider sections. Depending on the particular message services included, there may be more or less service provider sections and possibly some special sections. Each of these types of sections in described in more detail below.


 [Help File Mappings] Section

The [Help File Mappings] section contains entries that each map one message service to the file that provides Help for errors generated by the service. Entries in this section use the following format:

[Help File Mappings]

message service name=Help file name

The message service name is the name of the installed message service; the Help file name is the name of the file where the error information resides. The example following shows a typical [Help File Mappings] section that contains entries for three services: MAPI, the MsgService service, and the MS service.

[Help File Mappings]

MAPI=MAPI.HLP

MsgService=MYHELP.HLP

MS=STORE.HLP


 [Services] Section

The [Services] section lists the message services that are installed on a computer. Entries in this section use the following format:

[Services]

message-service section name=message service name

The message-service section name is a string defined by the message service that links this entry to a corresponding section for the service elsewhere in MAPISVC.INF. The message service name is the name of the installed service. The following section shows three message services: the Default Address Book, My Own Service, and the Message Store Service. These services are fictional, for illustration purposes only. Each message service implementor would substitute the appropriate entry for his or her message service in this section.

[Services]

AB=Default Address Book

MsgService=My Own Service

MS=Message Store Service

Each entry in this section has a corresponding section of its own where information for the message service is stored. For example, the corresponding section for the Default Address Book is called [AB].


 [Default Services] Section

The [Default Services] section lists all of the message services that are selected as default message services. These default message services are a subset of the message services listed in the [Services] section. When a profile configuration program creates a default profile, the message services in this section are automatically included.

The entries use the same format as entries in the [Services] section, as shown following:

[Default Services]

message-service section name=message service name

The following entries would be included in the [Default Services] section for the MAPISVC.INF in Figure 8.1:

[Default Services]

AB=Default Address Book

MsgService=My Own Service


 Message Service Sections

MAPISVC.INF includes one message service section for each of the entries listed in the [Services] section. There are two types of entries in these sections: one for setting certain properties and the other for listing names of sections that are related to the message service being configured.

Property Entries

Entries that set properties use this format:

property tag=property value

The property tag can be a standard MAPI property tag, if the configuration data represents one of the properties predefined by MAPI, or a nonstandard tag, if the data does not represent a MAPI property.The nonstandard tag is made by combining the value for a property identifier with a property type. The result is an 8 digit hexadecimal number. The property value can be whatever makes sense for the property tag.

Message service sections can contain a variety of entries depending on the message service being configured. The following MAPI properties are typically included in a message services section in the listed format:

PR_DISPLAY_NAME=string

PR_SERVICE_DLL_NAME=name of DLL file

PR_SERVICE_ENTRY_NAME=name of entry point function

PR_SERVICE_SUPPORT_FILES=list of files

PR_SERVICE_DELETE_FILES=list of files

PR_RESOURCE_FLAGS=bitmask

The PR_DISPLAY_NAME string is the name of the message service that is shown in the user interface, the name that the user associates with the message service. The display name is an optional entry in MAPISVC.INF. Sometimes the display name will be made up of two parts; a part assigned by the message service and a part assigned by the user. If the user is responsible for assigning one of the parts, this is typically handled with a configuration user interface or property sheet under the control of a client application.

The information provided for the PR_SERVICE_DLL_NAME entry is the name of the dynamic-link library (DLL) that contains the message service. The information provided for the PR_SERVICE_ENTRY_POINT entry is the entry point function within that DLL that MAPI calls to configure the message service.

The files listed in the PR_SERVICE_SUPPORT_FILES entry are files that must be installed with the message service. Likewise, the files in the PR_SERVICE_DELETE_FILES entry must be removed when the message service is removed.

The PR_RESOURCE_FLAGS entry is a collection of options defined for the message service. For example, the SERVICE_SINGLE_COPY bit is set when the message service can only appear once in a given profile. The SERVICE_NO_PRIMARY_IDENTITY bit is set if the message service does not provide identity information.

Two examples of nonstandard property entries follow. The first entry specifies the path to the file used by the Default Address Book as the property value; the second entry specifies a numeric property value. Both entries have meaning specific to the AB message service.

6600001e=full path to file

66040003=integer

Section List Entries

There are two types of section list entries: one that service provider sections for each and one that lists miscellaneous message service-specific sections. These two types of entries appear in MAPISVC.INF using the following formats:

Providers=provider section1, provider section2, ...... provider sectionX

Sections=section name1, section name2, ......section nameX

Each section in the Providers entry maps to an individual section providing configuration information for a service provider that belongs to the message service. Each section in the Sections entry maps to a section that contains extra configuration information needed by the message service. Message service implementors define extra sections when they want to include special information that does not fit in the standard sections. Message services that have complicated configurations typically use the Sections entry to add extra information. Every message services section has a Providers entry with at least one section in the list; not all message service sections have a Sections entry.

Two examples of message service sections follow. The first section is for the Default Address Book service from the illustration in Figure 8.1, a straightforward message service with a single service provider. The second section is for the MsgService service, a more complex sample message service with three service providers.

[AB]

PR_DISPLAY_NAME=Default Address Book

Providers=AB Provider

PR_SERVICE_DLL_NAME=AB.DLL

PR_SERVICE_SUPPORT_FILES=AB.DLL

PR_SERVICE_ENTRY_NAME=DABServiceEntry

PR_RESOURCE_FLAGS=SERVICE_NO_PRIMARY_IDENTITY

[MsgService]

PR_DISPLAY_NAME=My Own Service

Providers=MsgService Prov1, MsgService Prov2, MsgService Prov3

Sections=First_Special_Section, Second_Special_Section

PR_SERVICE_DLL_NAME=MYSERV.DLL

PR_SERVICE_SUPPORT_FILES=MYSERV.DLL, MYXXX.DLL, MYZZZ.DLL

PR_SERVICE_ENTRY_NAME=MyServiceEntry

PR_RESOURCE_FLAGS=SERVICE_SINGLE_COPY

66040003=00000000

The Sections entry in the [MsgService] section lists two additional sections, one called [First_Special_Section] and the other called {Second_Special_Section]. The data that might appear in extra sections is meaningful to the specific message service. These sections appear following to illustrate extra sections.

[First_Special_Section]

UID=13DB0C8AA05101A9BB000AA002FC45A

66020003=01000000

66000003=00040000

66010003=06000000

66050003=03000000


 Service Provider Sections

MAPISVC.INF includes one service provider section for each of the entries listed in the Providers entry in the preceding message services section. Service provider sections are similar to message service sections in that both types of sections contains entries in this format:

property tag=property value

However, service provider sections and message service sections differ in that such property entries are the only type of entry included in service provider sections. There can be no additional or linked sections for service providers; all service provider information must be contained within the one section.

Some of the properties set in message service sections are also set in service provider sections because these properties make sense for both.The PR_DISPLAY_NAME property is an example. Both service providers and message services have a name that is used for display in the configuration user interface. Depending on the service provider, that name may or may not be the same. Other properties are specific to service providers. For example, the PR_PROVIDER_DISPLAY property is an optional property that service providers include if they have two different display names.

Typical service provider sections include the following entries, all of which are required except for PR_PROVIDER_DISPLAY:

PR_DISPLAY_NAME=string

PR_PROVIDER_DISPLAY=string

PR_PROVIDER_DLL_NAME=name of DLL file

PR_RESOURCE_TYPE=long

PR_RESOURCE_FLAGS=bitmask

The PR_PROVIDER_DLL_NAME entry is similar to PR_SERVICE_DLL_NAME; it indicates the filename for the DLL that contains the service provider. Message service code may be stored with one of its service providers in the same DLL file or exist as a separate DLL. PR_RESOURCE_TYPE entry represents the type of service provider; service providers set it to the appropriate predefined constant. Valid values include MAPI_STORE_PROVIDER, MAPI_TRANSPORT_PROVIDER, and MAPI_AB_PROVIDER.

Another property entry that applies to both message services and service providers, the PR_RESOURCE_FLAGS entry indicates options. The settings for this property entry can differ depending on the service provider. For example, some message store providers might set PR_RESOURCE_FLAGS to STATUS_NO_DEFAULT_STORE if they can never operate as the default message store.

Three examples of service provider sections follow. The [AB Provider] section is the service provider section for the Default Address Book service. The [MsgService Prov1] and [MsgService Prov2] sections belong to My Own Service; the first is an address-book provider section and the second is a message-store provider section.

[AB Provider]

PR_DISPLAY_NAME=Default Address Book

PR_PROVIDER_DISPLAY=Default Address Book

PR_PROVIDER_DLL_NAME=AB.DLL

PR_RESOURCE_TYPE=MAPI_AB_PROVIDER

6600001e=C:\WINNT35\System32\DEFAB.TXT

[MsgService Prov1]

PR_DISPLAY_NAME=My Own Service

PR_PROVIDER_DISPLAY=My Own Address Book

PR_PROVIDER_DLL_NAME=MYXXX.DLL

PR_RESOURCE_TYPE=MAPI_AB_PROVIDER

[MsgService Prov2]

PR_DISPLAY_NAME=My Folders

PR_PROVIDER_DISPLAY=My Own Message Store

PR_RESOURCE_TYPE=MAPI_STORE_PROVIDER

PR_PROVIDER_DLL_NAME=MYZZZ.DLL

PR_RESOURCE_FLAGS=STATUS_NO_DEFAULT_STORE

66060003=00000000

66030003=00000000

34140102=78b2fa70aff711cd9bc800aa002fc45a

66090003=06000000

660A0003=03000000


 WIN.INI File Format

The Windows initialization file, WIN.INI, contains information about programs installed on a computer and options about their use. MAPI specifies a few entries that might need to be added to WIN.INI by the program that you write for installing your message service, depending on the computer's MAPI installation. These entries indicate the existence of various MAPI components and provide information about their configuration. Because there are default settings for each WIN.INI entry, your setup program can exclude those entries for which the default setting is appropriate.


 [Mail] Section

The entries to be added to this section specify the types of MAPI client application programming interfaces (APIs) that are installed on a computer. These types include Simple MAPI, Extended MAPI, OLE Messaging, and CMC. If CMC is installed, another entry exists to identify the name of the CMC DLL file that should be loaded for your platform.

The entries that identify client API installations are as follows:

[Mail]

MAPI=0 or 1

MAPIX= 0 or 1

OLEMessaging=0 or 1

CMC=0 or 1

Each entry that represents an installed MAPI client API is set to 1. If a particular client API is not installed, its entry either is missing from the WIN.INI file or is set to 0. The MAPI entry identifies a Simple MAPI installation, the MAPIX entry identifies an Extended MAPI installation, and the OLEMessaging and CMC entries indicate the client API of the same name.

Computers with CMC installations can also set the CMCDLLNAME or CMCDLLNAME32 entries to specify the filename of the CMC DLL. CMCDLLNAME identifies the 16-bit version; CMCDLLNAME32 identifies the 32-bit version. If these entries are omitted and a CMC installation exists, MAPI looks for a file named CMC.DLL regardless of whether the installation is for a 16-bit or 32-bit platform. The format of the CMCDLLNAME entries is as follows:

CMCDLLNAME=full path to file

CMCDLLNAME32=full path to file

Simple MAPI, Extended MAPI, and OLE Messaging installations always reside in a standard DLL file. For Extended MAPI, the DLL is called MAPIX.DLL for 16-bit platforms and MAPIX32.DLL for 32-bit platforms. For Simple MAPI, the DLL is called MAPI.DLL for 16-bit platforms and MAPI32.DLL for 32-bit platforms. Both 16-bit and 32-bit Simple MAPI client applications can run in an environment that supports both platforms (Windows 95 and Windows NT operating systems) if there is a Simple MAPI installation available for at least one of the platforms.

If OLE Messaging is installed, the type library resides in MDISP.TLB for 16-bit platforms and MDISP32.TLB for 32-bit platforms. Client applications do not need to know the name of the server executable file; information contained in the OLE registry automatically binds the appropriate file.

For CMC installations, MAPI places the 16-bit CMC DLL into MAPI.DLL and the 32-bit CMC DLL into MAPI32.DLL.

Microsoft supplies an import library for Extended MAPI. Client applications can load the Extended MAPI DLL statically using the import library or load it dynamically using the Windows API functions LoadLibrary and GetProcAddress.

There is no import library for either the Simple MAPI DLLs or the CMC DLLs. These DLLs must always be loaded dynamically by calling the Windows functions LoadLibrary and GetProcAddress. Applications that use these Windows functions to load a CMC, Simple MAPI, or Extended MAPI DLL should always check either the appropriate CMC, MAPI, or MAPIX entry to determine whether the API is installed before attempting to load the DLL.

[Mail]

MAPI=1

CMC=0

MAPIX=1


 [MAPI] Section

MAPI supplies a default profile provider implementation and a set of common dialog boxes. Typically service providers will use what MAPI provides. However, it is possible to replace either the profile provider implementation or the set of common dialog boxes. You can specify your versions of these components in the [MAPI] section of the WIN.INI file. Service providers that use the default components need not include this section.

The following entries can be included in the [MAPI] section:

Profile DLL=full path to file

Dialogs=full path to file

ProfileDirectory16=full path to file

The Profile DLL entry specifies the name of the DLL for the Extended MAPI profile provider. The default setting is MAPIX.DLL for 16-bit platforms and MAPIX32.DLL for 32-bit platforms. The filename included in the path should be the profile provider's base DLL name, that is the DLL name without the suffix.

The Dialogs entry specifies the name of the DLL that contains the implementation for the common dialog boxes. The default setting is WMSUI.DLL for 16-bit platforms and WMSUI32.DLL for 32-bit platforms.

The ProfileDirectory16 entry specifies the path to the directory where the profile files are kept. This entry is supported for 16-bit Windows environments only. The default location is a subdirectory named MAPI under the Windows directory. The ProfileDirectory16 entry can be set either by the user or automatically, for example by a network logon script. Specifying an explicit path for profile files allows you as a service provider to store these files on a server machine rather than locally, allowing them to be accessed from anywhere in the network.


 [MAPI 1.0 Time Zone] Section

The [MAPI 1.0 Time Zone] section stores information that is used by MAPI's 16-bit implementation of the time-zone API functions provided by 32-bit Windows. The entries that appear in this section are as follows:

[MAPI 1.0 Time Zone]

Bias=minutes

StandardName=string

StandardStart=time structure

StandardBias=minutes

DaylightName=string

DaylightStart=time structure

DaylightBias=minutes

The TIME_ZONE_INFORMATION structure is defined as follows in the Win32 SDK documentation.

typedef struct _TIME_ZONE_INFORMATION {

    LONG       Bias;

    WCHAR      StandardName[ 32 ];

    SYSTEMTIME StandardDate;

    LONG       StandardBias;

    WCHAR      DaylightName[ 32 ];

    SYSTEMTIME DaylightDate;

    LONG       DaylightBias;

} TIME_ZONE_INFORMATION;

The TIME_ZONE_INFORMATION structure specifies information specific to the time zone.

Members

Bias

Specifies the current bias, in minutes, for local time translation on this computer. The bias is the difference, in minutes, between Coordinated Universal Time (UTC) and local time. All translations between UTC and local time are based on the following formula:

UTC = local time + bias

This member is required.

StandardName

Specifies a null-terminated string associated with standard time on this operating system. For example, this parameter could contain "EST" to indicate Eastern Standard Time. This string is not used by the operating system, so anything stored there by using the SetTimeZoneInformation function is returned unchanged by the GetTimeZoneInformation function. This string can be empty.

StandardDate

Specifies a SYSTEMTIME structure that contains a date and UTC when the transition from daylight time to standard time occurs on this operating system. If this date is not specified, the wMonth member in the SYSTEMTIME structure must be zero. If this date is specified, the DaylightDate value in the TIME_ZONE_INFORMATION structure must also be specified. Local time translations done during the standard-time range are relative to the supplied StandardBias value.

This member supports two date formats. Absolute format specifies an exact date and time when standard time begins. In this form, the wYear, wMonth, wDay, wHour, wMinute, wSecond, and wMilliseconds members of the SYSTEMTIME structure are used to specify an exact date.

Day-in-month format is specified by setting the wYear member to zero, setting the wDayOfWeek member to an appropriate weekday, and using a wDay value in the range 1 through 5 to select the correct day in the month. Using this notation, the first Sunday in April can be specified, as can the last Thursday in October (5 is equal to "the last").

StandardBias

Specifies a bias value to be used during local time translations that occur during standard time. This member is ignored if a value for the StandardDate member is not supplied.

This value is added to the value of the Bias member to form the bias used during standard time. In most time zones, the value of this member is zero.

DaylightName

Specifies a null-terminated string associated with daylight time on this operating system. For example, this parameter could contain "PDT" to indicate Pacific Daylight Time. This string is not used by the operating system, so anything stored there by using the SetTimeZoneInformation function is returned unchanged by the GetTimeZoneInformation function. This string can be empty.

DaylightDate

Specifies a SYSTEMTIME structure that contains a date and UTC when the transition from standard time to daylight time occurs on this operating system. If this date is not specified, the wMonth member in the SYSTEMTIME structure must be zero. If this date is specified, the StandardDate value in the TIME_ZONE_INFORMATION structure must also be specified. Local time translations during the daylight-time range are relative to the supplied DaylightBias value. This member supports the absolute and day-in-month time formats described for the StandardDate member.

DaylightBias

Specifies a bias value to be used during local time translations that occur during daylight time. This member is ignored if a value for the DaylightDate member is not supplied.

This value is added to the value of the Bias member to form the bias used during daylight time. In most time zones, the value of this member is -60.


 Transport-Neutral Encapsulation Format (TNEF)

TNEF is a serialization of MAPI properties. Here is a summary of the format: The file begins with a 32-bit signature followed by a 16-bit unsigned integer that is used as a key to cross-reference attachments to their location within the tagged message body. The remainder of the file is a sequence of TNEF attributes. Each attribute consists of a class byte, an attribute identifier, the attribute size, the attribute data, and a 16-bit unsigned checksum of the attachment data. Message attributes appear first in the TNEF stream, and attachment attributes follow. Attributes belonging to a particular attachment are grouped together, beginning with the attAttachRenddata attribute.


 TNEF Encoding Example

In the following TNEF encoding, all integers are specified in hexadecimal format. Nonterminal elements are in italics; constants and anything that always appears exactly as shown are in bold. In addition, sequential elements run across, and alternative elements run down.

Stream:
TNEF_SIGNATURE Key Object

Key:
a nonzero 16-bit unsigned integer

Object:
Message_Seq
Message_Seq Attach_Seq
Attach_Seq

Message_Seq:
attTnefVersion
attTnefVersion Msg_Attribute_Seq
attTnefVersion attMessageClass
attTnefVersion attMessageClass Msg_Attribute_Seq
attMessageClass
attMessageClass Msg_Attribute_Seq
Msg_Attribute_Seq

attTnefVersion:
LVL_MESSAGE attTnefVersion sizeof(ULONG) 0x00010000 checksum

attMessageClass:
LVL_MESSAGE attMessagClass msg_class_length msg_class checksum

Msg_Attribute_Seq:
Msg_Attribute
Msg_Attribute Msg_Attribute_Seq

Msg_Attribute:
LVL_MESSAGE attribute-ID attribute-length attribute-data checksum

Attach_Seq:
attRenddata
attRenddata Att_Attribute_Seq

attRenddata:
LVL_ATTACHMENT attRenddata sizeof(RENDDATA) renddata checksum

Att_Attribute_Seq:
Att_Attribute
Att_Attribute Att_Attribute_Seq

Att_Attribute:
LVL_ATTACHMENT attribute-ID attribute-length attribute-data checksum

The key is a nonzero, 16-bit unsigned integer that signifies the initial value of the attachment reference keys. The attachment reference keys are assigned sequentially beginning with the initial value. For example, if the key was 0x01AF, the first attachment reference key would be 0x01AF, the second would be 0x01B0, and so on. The TNEF implementation uses the attachment reference keys to link specific attachments with their position within the tagged message body. The initial key value is passed to the OpenTnefStream function when the stream is encoded. The key value should be random so that two different messages do not use the same key.

The TNEF implementation uses the attribute identifier to map attributes to their corresponding MAPI properties. The attribute identifier is a 32-bit unsigned integer made up of two word values. The high-order byte is an indication of the data type, such as string or binary, and the low-order byte is a relatively unique identifier.

All attribute lengths are unsigned long integers. If the data stored is a string or text attribute, the terminating null character is included in the length.

The checksum is a 16-bit unsigned value that is simply the summation of the individual bytes in the attribute data. The header information is not included in the checksum.

All numbers in the TNEF format are stored in little endian (that is, in Intel format).


 Mapping of TNEF Message Attributes to MAPI Properties

The following table lists all the message attributes possible in a TNEF stream and their mappings to MAPI properties. In some cases, multiple MAPI properties are encoded as a single attribute. In these cases, multiple MAPI properties appear listed for a single TNEF attribute. For further explanation of specific mappings, see "Comments About the Attributes" later in this chapter.

TNEF attribute	MAPI property or properties
attAidOwner	PR_OWNER_APPT_ID
attBody	PR_BODY
attConversationID	PR_CONVERSATION_KEY
attDateEnd	PR_END_DATE
attDateModified	PR_LAST_MODIFICATION_TIME
attDateRecd	PR_MESSAGE_DELIVERY_TIME
attDateSent	PR_CLIENT_SUBMIT_TIME
attDateStart	PR_START_DATE
attFrom	PR_SENDER_ENTRYID and PR_SENDER_NAME
attMAPIProps	For information about this mapping, see "Comments About the Attributes" later in this chapter
attMessageClass	PR_MESSAGE_CLASS
attMessageID	PR_SEARCH_KEY
attMessageStatus	PR_MESSAGE_FLAGS
attOriginalMessageClass	PR_ORIG_MESSAGE_CLASS
attOwner	PR_RCVD_REPRESENTING_ENTRYID and PR_RCVD_REPRESENTING_NAME or PR_SENT_REPRESENTING_ENTRYID and PR_SENT_REPRESENTING_NAME
attParentID	PR_PARENT_KEY
attPriority	PR_PRIORITY
attRecipTable	PR_MESSAGE_RECIPIENTS
attRequestRes	PR_RESPONSE_REQUESTED
attSentFor	PR_SENT_REPRESENTING_ENTRYID
attSubject	PR_SUBJECT
attTnefVersion	For information about this mapping, see "Comments About the Attributes" later in this chapter


 Mapping of TNEF Attachment Attributes to MAPI Properties

Attachment attributes are mapped in the same way message attributes are. The following table lists all the attachment attributes possible in a TNEF stream and their mappings to MAPI properties. For further explanation of specific mappings, see "Comments About the Attributes" later in this chapter.

TNEF attribute	MAPI property or properties
attAttachCreateDate	PR_CREATION_TIME
attAttachData	PR_ATTACH_DATA_BIN or PR_ATTACH_DATA_OBJ
attAttachment	For information about this mapping, see "Comments About the Attributes" later in this chapter
attAttachMetaFile	PR_ATTACH_RENDERING
attAttachModifyDate	PR_LAST_MODIFICATION_TIME
attAttachRenddata	PR_ATTACH_METHOD, PR_RENDERING_POSITION
attAttachTitle	PR_ATTACH_FILENAME
attAttachTransportFilename	PR_ATTACH_TRANSPORT_NAME


 Comments About the Attributes

This section provides additional information about the TNEF attribute to MAPI property mapping for certain attributes. For more information about the MAPI properties that the attributes are mapped to, see the reference entries for the individual properties.


 attMAPIProps

[New - Windows 95]

The attMAPIProps attribute is special in that it can be used to encapsulate any MAPI property that does not have a counterpart in the set of existing TNEF-defined attributes. The attribute data is a counted set of MAPI properties laid end-to-end. The format of attMAPIProps, which allows for any configuration of MAPI properties, is as follows:

Property_Seq:
property-count Property_Values, ...

Property_Values:
proptag Property
proptag Proptag_Name Property

Property:
Value
value-count Value, ...

Value:
value-data
value-size value-data padding
value-size value-IID value-data padding

Proptag_Name:
name-guid name-kind name-id
name-guid name-kind name-string-length name-string padding

The encapsulation of each property varies in the following ways based on the property identifier and the property type:

If the property falls in the named property range, then the property tag is immediately followed by the MAPI property name, consisting of a globally unique identifier (GUID), a kind, and either an identifier or a Unicode string.

If the property is either multivalued or is of variable length, such as the PT_BINARY, PT_STRING8, PT_UNICODE, or PT_OBJECT properties, then the number of values, which are encoded as a 32-bit unsigned long, falls next in the encapsulation followed by the individual values. Each variable-length value is preceded by its size in bytes encoded as a 32-bit unsigned long. Additionally, each individual value is padded out to 4-byte boundaries; the padding is not included in the value size.

If the property is of type PT_OBJECT, the value size is followed by the interface identifier (IID) of the object. The current implementation of TNEF only supports IID_IMessage, IID_IStorage, and IID_IStream. The size of the IID is included in the value size.

If the object is an embedded message,that is, if the object has a property type of PT_OBJECT and an IID of IID_IMessage, the value data is encoded as a TNEF stream. The actual encoding of an embedded message in the MAPI implementation of TNEF is done by opening a second TNEF object for the original stream and processing the stream inline.


 Attributes with the attDate Prefix

[New - Windows 95]

All date properties are stored as DTR structures. A DTR  structure is very similar to the SYSTEMTIME structure defined in the 32-bit Windows header files. The DTR is encoded in TNEF as a sizeof(DTR) bytes starting at &dtr.wYear. The dates and times for attachment attributes are encoded as DTR structures. Any MAPI property that does not map to a down-level attribute is encoded as a MAPI encapsulation in attAttachment.


 attOriginalMessageClass

[New - Windows 95]

A message class is stored as a string. The encoded string usually holds the MAPI-specified name of the message class. The exception is that, to keep compatibility with Microsoft Mail for Windows for Workgroups 3.1, the following MAPI message classes are mapped to down-level message classes:

MAPI message class	Windows for Workgroups Mail 3.x
IPM	IPM.Microsoft Mail.Note
IPM.Note	IPM.Microsoft Mail.Note
IPM.Schedule.Meeting.Canceled	IPM.Microsoft Schedule.MtgCncl
IPM.Schedule.Meeting.Request	IPM.Microsoft Schedule.MtgReq
IPM.Schedule.Meeting.Resp.Neg	IPM.Microsoft Schedule.MtgRespN
IPM.Schedule.Meeting.Resp.Pos	IPM.Microsoft Schedule.MtgRespP
IPM.Schedule.Meeting.Resp.Tent	IPM.Microsoft Schedule.MtgRespA
Report.IPM.Note.NDR	IPM.Microsoft Mail.Non-Delivery
Report.IPM.Note.RN	IPM.Microsoft Mail.Read Receipt


 attConversationID and attParentID

[New - Windows 95]

The Windows for Workgroups 3.1 Mail conversation key is a textual string. The MAPI equivalent is a binary value. TNEF converts the binary data to text and adds a terminating null character.


 attFrom

[New - Windows 95]

The attFrom attribute is encoded as two TRP structures laid end-to-end. The format for attFrom is as follows:

attFrom:
trpidOneOff
(sizeof(TRP) *2) + length display-name + terminator + pad to 2 byte boundary
length address-type:email-address + terminator
display-name terminated and padded
address-type:email-address terminated
zero-fill sizeof(TRP)


 attOwner

[New - Windows 95]

The attOwner attribute is encoded as counted strings laid end-to-end. The format for attOwner is as follows:

attOwner:
16bit-length-display-name (terminator included)
display-name
16bit-length-address-type:email-address (terminator included)
address-type:email-address

The mapping of the attOwner attribute is dependent on the message class of the message being encoded. If the message is either a Microsoft Schedule+ meeting request or cancellation, the attribute maps to one of the PR_SENT_REPRESENTING_X properties. If the message is a Microsoft Schedule+ meeting response of any type, the attribute maps to one of the PR_RCVD_REPRESENTING_X properties.


 attSentFor

[New - Windows 95]

The attSentFor attribute is encoded as counted strings laid end-to-end. The format for attSentFor is as follows:

attSentFor:
16bit-length-display-name (terminator included)
display-name
16bit-length-address-type:email-address (terminator included)
address-type:email-address


 attRecipTable

[New - Windows 95]

When a recipient table is being encoded, each recipients is encoded as a row of MAPI properties. The format is as follows:

Row_Seq:
row-count Property_Seq, ...


 attPriority

[New - Windows 95]

MAPI message priorities are also mapped to TNEF for down-level compatibility. MAPI identifies  − 1, 0, and 1 as low, normal, and high priority respectively. The down-level priorities are 3, 2, and 1.


 attMessageStatus

[New - Windows 95]

MAPI message flags must also be mapped to down-level values. All the flags are grouped together and encoded in a single byte. The mappings are as follows:

MAPI message flags	Down-level message flags
MSGFLAG_READ	fmsRead
MSGFLAG_UNMODIFED	not fmsModified
MSGFLAG_SUBMIT	fmsSubmitted
MSGFLAG_HASATTACH	fmsHasAttach
MSGFLAG_UNSENT	fmsLocal


 attAttachRenddata

[New - Windows 95]

The RENDDATA structure describes how and where the attachment is rendered in the message body.

The rendering data is encoded as sizeof(RENDDATA) bytes beginning at &rd.atyp. If the value of the RENDDATA structure's dwFlags member is set to MAC_BINARY, then the attachment data is stored in MacBinary format; otherwise, the attachment data is encoded as usual.


 OLE Attachments

OLE attachments, when encoded for compatibility, are encoded as OLE 1.0 stream objects. This coding standard means that if the original object is really an OLE 2.0 IStorage object, then the object must be converted to an OLE 1.0 stream. This conversion is performed using OleConvertIStorageToOLESTREAM function, which is supplied by the OLE DLLs; examples of this conversion can be found in OLE Programmer's Reference, Volume One.


 Configuration File Format

A configuration file is formatted file created by form developers to define a form. Because configuration files are used by form managers to load forms, each form must be defined using a configuration file.Configuration files must have the .CFG filename extension. The file follows the general syntax of a Windows initialization file (.INI file): It is divided into named sections, and each section contains a series of entries and values. Values have one of the following types: string, displayed string, platform string, path, integer, or globally unique identifier (GUID). The sections of a configuration file are described in the rest of this chapter.


 The [Description] Section

The [Description] section lists all attributes of the form visible in client application's user interface,plus attributes that are used in locating the form. The MessageClass, Clsid, and DisplayName entries, which identify the name of the form's message class, its GUID, and the message class's display name, respectively, are required entries used to locate the form within the registry. The remaining entries are optional. The format of the [Description] section is shown here.

[Description]

MessageClass = string

Clsid = guid

DisplayName = displayed string

;optional entries

Category = displayed string

Subcategory = displayed string

Comment = displayed string

Owner = displayed string

Number = displayed string

SmallIcon = path

LargeIcon = path

Version = integer

Locale = string

Hidden = integer

DesignerToolName = string

DesignerToolGuid = clsid

DesignerRuntimeGuid = clsid

ComposeInFolder = integer

ComposeCommand = string

The Category and Subcategory entries are used by forms installers to set up the default categorization of forms within client application's user interface. For example a hierarchy could be set up where Help Desk is the category and Software and Hardware were the subcategory. This categorization can then be used by viewer applications to display folder hierarchies. The Comment, Owner, and Number entries are all comment strings that appear in client application's user interface. These are form specific properties that can be used at the discretion of the form developer. For example, the Comment entry can be used to indicate the purpose of the form, the Owner entry used to indicate the person or organization responsible for maintaining the form, and the number used to track variants of the same form version. For the Comment entry, up to ten lines of comments can be included. The first line of comments uses the word "Comment" as the key, the second line of comments uses "Comment 1" as the key, and so on.

The SmallIcon and LargeIcon entries are used to specify the path for the icon resources used to display icons in the client application's user interface, typically this is for table rows that include the PR_ICON or PR_MINI_ICON property columns. Icon file names can be specified as pathnames relative to the directory wherethe configuration file is installed. The Version entry is used to indicate the version number of the form. Locale is the 3-letter language identifier of the destination registry. The Hidden entry indicates whether the form is displayed in registry provider's user interface: 1 indicates that the file is hidden and 0 indicates that the form is visible. An example configuration file is shown following.

[Description]

MessageClass = IPM.Help

Clsid = {00020D31-0000-0000-C000-000000000046}

DisplayName = Help Desk Request Form

;optional entries

Category = Help Desk Requests

Subcategory = New Requests

Comment = Use this form to request network assistance.

Owner = Help Desk

Number = 1

SmallIcon = C:\WINDOWS|EFORMS\HELPDESK\HDSMALL.ICO

LargeIcon = C:\WINDOWS|EFORMS\HELPDESK\HDLARGE.ICO

Version = 1.00

Locale = enu

Hidden = 0

ComposeInFolder = 0

ComposeCommand = Help Desk Request


 The [Extensions] Section

The [Extensions] section lists the extended attributes of the form, typically a named property set, which are any attributes beyond the basic ones listed in the [Description] section of the configuration file. Extended attributes are properties returned from calls to the GetProps method of the IMAPIFormInfo object with the high bit set in the property tag. Client applications can determine a form's extended attributes, if any, by retrieving these tags. To do so, clients call the IMAPIProp::GetIDsFromNames method passing in the names of the form's properties or call the IMAPIProp::GetProps method and requesting all form properties.

Each entry in the [Extensions] section references a subsequent section that has a name with the syntax [Extension.string2].

[Extensions]

Extension.string1 = string2

Each extension property section defines one extension attribute using the MAPI named property syntax. The property type must be either PT_LONG or PT_STRING8. Property sets conntaining named strings are not supported. The format of the [Extension] section is shown here.

[Extensionstring]

Type = integer

NmidPropset = guid

NmidInteger = integer

Value = string | integer

An example of an [Extensions] section and a subsequent related section is shown following.

[Extensions]

Extension.A = 1

[Extension.1]

Type = 30

NmidPropset = {00020D0C-0000-0000-C000-000000000046}

NmidInteger = 1

Value = 11220000


 The [Platforms] Section

The [Platforms] section lists the complete set of platforms supported by this form. Each platform entry consists of the prefix Platform.string, where string is the string code of the platform. Each string corresponds to the CPU entry of an individual [Platforms] sections. Each entry in a [Platforms] section references a subsequent [Platform.platform string] section as shown here.

[Platforms]

Platform.string = platform string

Following is an example of a [Platforms] section.

[Platforms]

Platform.1 = NTx86

Platform.2 = Win95

Each [Platform.platform string] section contains the two required entries CPU and OSVersion. The CPU entry specifies the processor, and the OSVersion entry specifies the operating system. Additionally, either a File entry or a LinkTo entry must be specified. The File entry lists the form server application executable file that the forms registry maintains and loads into a new subdirectory in the disk cache when the form is launched. Instead of a File entry, a platform can have a LinkTo entry. The LinkTo entry contains a single key that names the platform hosting the files.

The Registry entry is used whenever the File entry is used, it identifies the registry key for the registry where the executable file for the form server application is stored. Strings preceded by a backslash ( \ ) are placed at the root of the \\HKEY_CLASSES_ROOT\ registry key. Strings not preceded by a backslash are placed at the root of the HKEY_CLASSES_ROOT\CLSID\GUID\ registry key, where GUID is the GUID of the form. The characters "%d" can be used to indicate the pathname of the directory containing the downloaded form files. Multiple File or Registry entries can be specified by using File or Registry as a prefix followed by any other text. The format for the [Platform.platform string] section is shown here.

[Platform.platform string]

CPU = string

OSVersion = string

File = path

LinkTo = string

Registry = string

Following are shown two example [Platform.platform string] sections, one using the File entry and one using the LinkTo entry.

[Platform.NTx86]

CPU = ix86

OSVersion = WinNT3.5

File = \helpdesk.exe

Registry = Local Server = %d\helpdesk.exe

[Platform.Win95]

CPU = ix86

OSVersion = Win95

LinkTo = NTx86

The [Platform.platform string] section is ignored when adding a form to the local forms registry, when it is assumed that the installer has placed the files constituting the message class handler into accessible local storage, as named in the handler's section in the OLE registry.


 The [Properties] Section

The [Properties] section lists the complete set of properties that the form uses and publishes; that is, the properties it creates in its custom messages that MAPI client applications can use when displaying columns, filtering contents tables, setting up search-results folders, and so on. Each entry in this property list references a subsequent [Property.string] section as shown following.

[Properties]

Property.string = string

Following is an example of a [Properties] section.

[Properties]

Property1 = Fire Hazard

Property2 = Safe

Each [Property.string] section describes a single property. The Type entry specifies the MAPI property type, for example 3(PT_14), of the property. The NmidPropset entry is optional; together with either the NmidString entry or the NmidInteger entry, which are mutually exclusive, the NmidPropset entry gives the name of the property. If set, NmidPropset should contain the name of the property set; if absent, NmidPropset is set to a default based on the following rule: If NmidInteger is present and its value is less than 0x8000, NmidPropset is set to PS_MAPI. If the value of NmidPropset is set to an integer greater than 0x8000, or if it is absent, NmidPropset is set to PS_PUBLIC_STRINGS

The DisplayName entry contains the label for the property. The SpecialType entry, if present and nonzero indicates that this property is a special property. At present, the only special property type defined is SpecialType-== 1, which indicates string enumerated properties. If SpecialType is set to 1, the Enum1 entry references the [Enum1.string] section.

The format of a [Property.string] section is shown here.

[Property.string]

Type = integer

NmidPropset = guid

NmidString = string

NmidInteger = integer

DisplayName = string

Flags = integer

SpecialType = 0|1

Enum1 = string

Following is an example of a [Property.string] section.

[Property.Fire Hazard]

Type = 1

NmidPropSet = {E47F4480-8400-101B-934D-04021C007002]

NmidString = FireHazard

DisplayName = Fire Hazard

SpecialType = 1

Enum1 = HazardEnum

The Enum1 section in the preceeding example references to a subsequent [Enum1.string] section describing an enumeration of a particular type. Such an enumeration associates the first property in the [Property.string] section with an integer property, called the index. Such an enumeration also contains a list of the possible values that the display-index pair can assume. Specifying a property type for the enumeration is unnecessary because by definition an Enum1 entry always has the PT_I4 type. Following is the format for the [Enum1.string] section.

[Enum1.string]

NmidPropset = guid

NmidString = string

NmidInteger = integer

EnumCount = integer

Val.integer.Display = string

Val.integer.Index = integer

Here is an example property definition for an enumerated property named Fire Hazard with possible values of Low, Medium, and High.

[Properties]

Property1 = Fire Hazard

[Enum1.HazardEnum]

IdxNmidPropset={E47F4480-8400-101B-934D-04021C007002]

IdxNmidString=FireHazardEnum

EnumCount = 3

Val.1.Display = Low

Val.1.Index = 1

Val.2.Display = Medium

Val.2.Index = 2

Val.3.Display = High

Val.3.Index = 3

[Enum1.string] sections can be used by applications for two purposes: to speed up the filtering of properties by using the index rather than the string and to sort by a different order than the alphanumeric order of the string values. For example, soprting could be done based on Low-Medium-High order rather than High-Medium-Low order.


 The [Verbs] Section

The [Verbs] section lists the complete set of verbs supported by the form. The format of the [Verbs] section is shown following.

[Verbs]

Verb1 = string

Following is an example of a Verbs section.

[Verbs]

Verb1=1

Verb2=2

Each verb is defined in a separate [Verb.string] section. A [Verb.string] section describes a single verb offered by the form. The DisplayName entry in a [Verb.string] section specifies the command name displayed in the user interface. The Code entry corresponds to the verb number passed in the IMAPIForm::DoVerb method. The syntax for the [Verb.string] section is shown here.

[Verb.string]

DisplayName = displayed string

Code = integer

Flags = integer

Attribs = integer

Following is an example of a [Verb.string] section.

[Verb.1]

DisplayName=Reply

code=1

Flags=0

Attribs=2

[Verb.2]

DisplayName=Delete

Code=2

Flags=0

Attribs=2

Verbs listed in this section are retrieved by a client using the IMAPIFormInfo::CalcVerbSet method and then passed to the IMAPIForm::DoVerb method.


 Extended MAPI Return Values

Throughout the descriptions for Extended MAPI methods and functions in MAPI Programmer's Reference, Volume 1, and MAPI Programmer's Reference, Volume 2, only those return values that client applications and service providers can handle are documented. For example, MAPI_E_NOT_FOUND is documented as the result of a nonexistent profile being named when a session is opened; in this case, error handling can include displaying a dialog box requesting that the user either provide the name of an existing profile or create a new profile.

Extended MAPI methods and functions can also return values representing error conditions that cause method and function calls to fail and that cannot be handled in such a fashion. These values are documented in this appendix. For additional information about the MAPI return value philosophy, see MAPI Programmer's Guide.


 Values Indicating Parameter Validation Errors

Client applications and service providers should use the parameter validation functions provided by MAPI to validate parameters. For more information on how to use the MAPI parameter validation model in your programs, see the MAPI Programmer's Guide. The following error values can be returned by methods and functions using MAPI parameter validation:

 MAPI_E_INVALID_PARAMETER

One or more parameters passed by the calling application were not valid.

 MAPI_E_UNKNOWN_FLAGS

Reserved or unsupported flags were used; therefore, the operation did not complete.


 Values Indicating Resource-Related Errors

The following error values can be returned to indicate the failure of a disk, of memory, or of system resources:

 MAPI_E_DISK_ERROR

A disk error prevented successful completion of the operation.

  MAPI_E_NOT_ENOUGH_DISK

Insufficient disk space was available to complete the operation.

  MAPI_E_NOT_ENOUGH_MEMORY

Insufficient memory was available to complete the operation.

  MAPI_E_NOT_ENOUGH_RESOURCES

Insufficient system resources were available to complete the operation.


 Values Indicating Unicode Errors

The following error value can be returned by all MAPI string methods and functions:

  MAPI_E_BAD_CHARWIDTH

Either the MAPI_UNICODE flag was set and the implementation does not support Unicode, or MAPI_UNICODE was not set and the implementation supports only Unicode.

Unicode implementation is optional when developing programs with MAPI. However, many MAPI methods and functions enable client applications and service providers to specify whether text strings should be in Unicode format; they do so by taking a ulFlags parameter and allowing calling processes to pass MAPI_UNICODE in it to indicate passed-in or returned strings, or both, should be Unicode. Implementations that do not support Unicode, or that only support Unicode, return MAPI_E_BAD_CHARWIDTH when the presence or absence of MAPI_UNICODE does not match the implementation's requirements. For example, message class names cannot be in Unicode format, so passing MAPI_UNICODE to a function that also takes a message class name as a parameter always results in an error.


 Values Indicating Unknown Error Conditions

If an error occurs for which an implementation cannot determine the origin, the following error value can be returned:

MAPI_E_CALL_FAILED

An error of unexpected or unknown origin prevented the operation from completing.


 Extended MAPI Versions of 32-Bit Windows Functions

This appendix documents functions from the Win32 application programming interface (API) useful to in the 16-bit environment used by MAPI client and server developers. Most of the functions documented in this appendix have counterparts published in the Win32 SDK, and some such functions have limitations relative to their Win32 SDK counterparts. Such limitations are noted section for each function. Where possible, if the calling implementation requests unsupported functionality, the function returns a value that indicates failure.

Some of the 32-bit Windows functions documented here have been implemented specifically for MAPI. The MAPIWIN.H header file includes definitions to aid in developing single-source service providers that run on both Win32 and Win16 API platforms.


 Accessing Win32 Information in the MAPIWIN.H Header File

MAPIWIN.H has three sections. The first section defines how to call an available function by different methods in Win16. Functions included in the first section manage per-instance global variables for dynamic-link libraries (DLLs). They work on the assumption that all of a DLL's per-instance global variables exist in a single block of memory.

The second section specifically defines for the Win16 environment functionality that is generally available in the Win32 environment. This section consists largely of Win32 file input-output functions that are not supported under Win16 but are implemented in MAPI.DLL using MS-DOS® calls. Some functions of this type have limitations relative to their Win32 counterparts; the limitations are spelled out in this Appendix. The third section defines conventions that simplify certain common operations.

The following functions have no meaning on Win16, but Microsoft's Extended MAPI implementation defines macros to make it easier to write common code:

CloseMutexHandle

CreateMutex

DeleteCriticalSection

EnterCriticalSection

InitializeCriticalSection

LeaveCriticalSection

ReleaseMutex

WaitforSingleObject


 Syntax and Limitations for Win32 Functions Useful in MAPI Development

The remainder of this appendix lists Win32 functions useful to MAPI developers that have limits, adaptations, or differences when used in the MAPI development environment. Where applicable, these limitations are described. Where there are no limitations specifically defined, only the syntax of a function is included. For detailed descriptions of the Win32 functions, see the Win32 Programmer's Reference.

In general, error codes returned from these functions or from GetLastError come from DOS and may not always match the Win32 counterpart.


 CloseHandle

Syntax

BOOL CloseHandle(HANDLE hObject)

Limitations

This function will close only file handles.


 CompareFileTime

Syntax

LONG CompareFileTime(CONST FILETIME * lpft1, CONST FILETIME * lpft2)


 CompareStringA

int CompareStringA(LCID Locale, DWORD dwCmpFlags, LPCSTR lpString1, int cchCount1, LPCSTR lpString2, int cchCount2)


 CompareStringW

Syntax

int CompareStringW(LCID lcid, DWORD fdwStyle, LPCWSTR lpString1, int cch1, LPCWSTR lpString2, int cch2)

Limitations

Only accurate for less than 128 characters.


 CopyFile

Syntax

BOOL CopyFile(LPCTSTR lpszExistingFile, LPCTSTR lpszNewFile, BOOL fFailIfExists)


 CopyMemory

Syntax

VOID CopyMemory (PVOID Destination, CONST VOID * Source,DWORD Length)


 CreateDirectory

Syntax

BOOL CreateDirectory(LPCTSTR lpszPath, LPSECURITY_ATTRIBUTES lpsa)

Limitations:

LPSECURITY_ATTRIBUTES is not supported; fails if non-null.


 CreateFile

Syntax

HANDLE CreateFile(LPCTSTR lpszName, DWORD fdwAccess, DWORD fdwShareMode, LPSECURITY_ATTRIBUTES lpsa, DWORD fdwCreate, DWORD fdwAttrsAndFlags, HANDLE hTemplateFile)

Limitations

Several differences from ordinary Win32 usage occur when using the MAPI version of the CreateFile function:

•	dwFlagsAndAttributes and dwDesiredAccess are ignored.

•	lpSecurityAttributes is not supported and the function fails if it is not NULL.

•	hTemplateFile is not supported and the function fails if it is nonzero.


 DeleteFile

Syntax

BOOL DeleteFile(LPCTSTR lpszFileName)


 DosDateTimeToFileTime

Syntax

BOOL DosDateTimeToFileTime(WORD wDOSDate, WORD wDOSTime, LPFILETIME lpft)


 FBadReadPtr

Syntax

BOOL FBadReadPtr(CONST VOID * lpvPtr, UINT cbBytes)

Limitations

The FBadReadPtr function behaves as does the IsBadReadPtr function but returns FALSE if the cbBytes parameter is zero regardless of the value of the lpvPtr parameter. This matches the behavior of Win32 IsBadReadPtr, rather than Win16 IsBadReadPtr.


FileTimeoLocalFileTime
 FileTimeToLocalFileTime

Syntax

BOOL FileTimeToLocalFileTime(CONST FILETIME * lpft, LPFILETIME lpftLocal)

Limitations

Depends on time zone information in WIN.INI. The UI is included in the mail and fax control panel applet, and is set by the SetTimeZoneInformation call listed in this Appendix.


 FileTimeToDosDateTime

Syntax

BOOL FileTimeToDosDateTime(CONST FILETIME * lpft, LPWORD lpwDOSDate, LPWORD lpwDOSTime)


 FileTimeToSystemTime

Syntax

BOOL FileTimeToSystemTime(CONST FILETIME * lpft, LPSYSTEMTIME lpst);


 FillMemory

Syntax

VOID FillMemory (PVOID Destination,DWORD Length,BYTE Fill)


 FindClose

Syntax

BOOL FindClose(HANDLE hFindFile)


 FindFirstFile

Syntax

HANDLE FindFirstFile(LPCTSTR lpFileName, LPWIN32_FIND_DATA lpFindFileData)

Limitations

The dwReserved0, dwReserved1 and cAlternateFileName members are not supported in the WIN32_FIND_DATA structure.


 FindNextFile

Syntax

BOOL FindNextFile(HANDLE hFindFile, LPWIN32_FIND_DATA lpFindFileData)

Limitations

The dwReserved0, dwReserved1 and cAlternateFileName members are not supported in the WIN32_FIND_DATA structure.


 GetACP

Syntax

UINT GetACP(VOID)


 GetCurrentProcessID

Syntax

DWORD GetCurrentProcessId(VOID)

Limitations

Returns HTASK.  Value is subject to reuse by the operating system.


 GetFileAttributes

Syntax

DWORD GetFileAttributes(LPCTSTR lpFileName)

Limitations

This function won't work on Novell NetWare without FILESCAN rights.


 GetFileSize

Syntax

DWORD GetFileSize(HANDLE hFile, LPDWORD lpdwFileSizeHigh)


 GetFileTime

Syntax

BOOL GetFileTime(HANDLE hFile, LPFILETIME lpftCreation, LPFILETIME lpftLastAccess, LPFILETIME lpftLastWrite)

Limitations

The time that the file in question was last modified is supported, but not the file creation or access time. The function fails if either of the latter is requested.


 GetFullPathName

Syntax

DWORD GetFullPathName(LPCTSTR lpszFile, DWORD cchPath, LPTSTR lpszPath, LPTSTR *ppszFilePart)

Limitations

This function does not handle ".." path components in lpFileName.


 GetLastError

Syntax

DWORD GetLastError(VOID)

Limitations

This function won't be as reliable as it is on Windows NT. If a function in this module fails because an unsupported feature was requested, no error is returned.


 GetLocalTime

Syntax

VOID GetLocalTime(LPSYSTEMTIME lpst)

Limitations

This function returns the current time as local time.


 GetSystemTime

Syntax

VOID GetSystemTime(LPSYSTEMTIME lpst)

Limitations

This function depends on the time zone and eturns the current time as Greenwich mean time (GMT). Requires that an earlier call to SetTimeZoneInformation has been made to get the local time zone.


 GetTempFileName

UINT GetTempFileName(LPCTSTR lpszPath, LPCTSTR lpszPrefix, UINT uUnique, LPTSTR lpszTempFile)


 GetTempFileName32

UINT WINAPI GetTempFileName32 (LPCSTR lpPathName, LPCSTR lpPrefixString, UINT uUnique, LPSTR lpTempFileName)


 GetTempPath

Syntax

DWORD GetTempPath(DWORD cchBuffer, LPTSTR lpszTempPath)


 GetTimeZoneInformation

Syntax

DWORD GetTimeZoneInformation(LPTIME_ZONE_INFORMATION lptzi)


 GetUserDefaultLCID

Syntax

LCID GetUserDefaultLCID(VOID)


 InterlockedDecrement

Syntax

LONG InterlockedDecrement(LPLONG lplVal)

Limitations

This function relies on cooperative multitasking.


 InterlockedIncrement

Syntax

LONG InterlockedIncrement(LPLONG lplVal)

Limitations

This function relies on cooperative multitasking.


 IsBadBoundedStringPtr

BOOL WINAPI IsBadBoundedStringPtr(const void FAR* lpsz, UINT cchMax)


 IsBadReadPtr

Syntax

BOOL IsBadReadPtr(CONST VOID * lpvPtr,UINT cbBytes)

Limitations

This function has been redefined to work as on the Win32 version of FBadReadPtr.


 IsBadStringPtrW

BOOL IsBadStringPtrW(LPCWSTR lpszStr, UINT cchMax)


 LocalFileTimeToFileTime

Syntax

BOOL LocalFileTimeToFileTime(CONST FILETIME * lpftLocal, LPFILETIME lpft)

Limitations

Requires that an earlier call to SetTimeZoneInformation has been made to get the local time zone.


 lstrlenW

Syntax

int lstrlenW(LPCWSTR lpszString)


 lstrcmpW

int lstrcmpW(LPCWSTR lpszString1, LPCWSTR lpszString2)


 lstrcpyW

LPWSTR lstrcpyW(LPWSTR lpszString1, LPCWSTR lpszString2)


 MoveFile

Syntax

BOOL MoveFile(LPCTSTR lpszExisting, LPCTSTR lpszNew)

Limitations

The MAPI version of the MoveFile function won't move a directory. This function always works across drives, and it always performs a copy operation then deletes the original file, as opposed to truly performing a move operation.


 MoveMemory

Syntax

VOID MoveMemory (PVOID Destination, CONST VOID * Source,DWORD Length)


 MulDiv32

Syntax

int MulDiv(int nMultiplicand, int nMultiplier, int nDivisor)

Limitations

The MulDiv32 function supports the MULDIV macro contained in the MAPIWIN.H header file. It takes 32-bit arguments, unlike the native Win16 MulDiv. The MAPI MulDiv32 does not check for overflow on the nMultiplier parameter.


 MultiByteToWideChar

Syntax

int MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cchMultiByte, LPWSTR lpWideCharStr, int cchWideChar)

Limitations

This function only works for less than 128 characters; does not support Unicode single-byte conversion; only works reliably for ASCII characters.


 ReadFile

Syntax

BOOL ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD NumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped)

Limitations

The count is limited to 64K. The lpOverlapped parameter is not supported and the function fails if lpOverlapped is not NULL.


 RemoveDirectory

Syntax

BOOL RemoveDirectory(LPCTSTR lpszDir)


 SetEndOfFile

Syntax

BOOL SetEndOfFile(HANDLE hFile)


 SetFilePointer

Syntax

DWORD SetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod)

Limitations

Distance is limited to 2 gigabytes (signed 32-bits). The SetFilePointer function fails if the lpDistanceToMoveHigh parameter is present and nonzero, unless the value it holds is the sign extension of a negative distance.


 SetTimeZoneInformation

Syntax

BOOL SetTimeZoneInformation(CONST TIME_ZONE_INFORMATION * lptzi)

Limitations

Depends on time zone information in WIN.INI.  The UI is included in the mail and fax control panel applet.


 Sleep

Syntax

VOID Sleep(DWORD cMilliseconds)

Limitations

This function does not handle the ALT+TAB and ALT+ESC key combinations for task switching.


 SystemTimeToFileTime

Syntax

BOOL SystemTimeToFileTime(CONST SYSTEMTIME * lpst, LPFILETIME lpft)


 WideCharToMultiByte

Syntax

int WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cchMultiByte, LPCSTR lpDefaultChar, LPBOOL lpUsedDefaultChar)

Limitations

This function only works for less than 128 characters; does not support Unicode single-byte conversion; works reliably only for ASCII characters.


 WriteFile

Syntax

BOOL WriteFile(HANDLE hFile, PCVOID lpBuffer, DWORD nNumberOfBytesToWrite, PDWORD lpNumberOfBytesWritten, POVERLAPPED lpOverlapped)

Limitations

The lpOverlapped parameter is not supported, and the function fails if it is not NULL.


 ZeroMemory

Syntax

VOID ZeroMemory (PVOID Destination,DWORD Length)


 Mapping of X.400 P2 Attributes to Extended MAPI Properties

The X/Open CAE Specification API to Electronic Mail (X.400), published by the X/Open Company Limited and X.400 API Association (1991), describes a recommended implementation of the X.400 (1984) and X.400 (1988) Blue Book specifications.

This chapter describes mappings between the recommended implementation's P2 attributes and Extended MAPI properties.

For a description of how to write providers and applications that use these mappings, see the MAPI Programmer's Guide.

The reference information is presented in two different ways in this chapter:

•	X.400 attributes are organized by object.

•	All X.400 attributes are combined into one comprehensive list and presented in alphabetical order.


 X.400 Attributes By Object

The following sections contain tables for each object listing the mappings from X.400 P2 attributes to their corresponding Extended MAPI properties.


 OMP_O_IM_C_BD_PRT

[New - Windows 95]

The class OMP_O_IM_C_BD_PRT does not have any attributes that are unique to the class.


 OMP_O_IM_C_BILAT_DEF_BD_PRT

[New - Windows 95]

The attributes of the class OMP_O_IM_C_BILAT_DEF_BD_PRT map to Extended MAPI properties as follows:

MH ID/Type	MAPI Property
IM_BILATERAL_DATA	PR_ATTACH_DATA_BIN


 OMP_O_IM_C_EXTERN_DEF_BD_PRT

[New - Windows 95]

The attributes of the class OMP_O_IM_C_EXTERN_DEF_BD_PRT map to Extended MAPI properties as follows:

MH ID/Type	MAPI Property
IM_EXTERNAL_DATA	PR_ATTACH_DATA_BIN, PR_ATTACH_FILENAME, PR_ATTACH_TAG
IM_ EXTERNAL_PARAMETERS	PR_ATTACHMENT_X400_PARAMETERS


 OMP_O_IM_C_G3_FAX_BD_PRT

[New - Windows 95]

The attributes of the class OMP_O_IM_C_G3_FAX_BD_PRT are not mapped to Extended MAPI properties.

MH ID/Type	MAPI Property
IM_G3_FAX_NBPS	Not mapped to an Extended MAPI property.
IM_IMAGES	Not mapped to an Extended MAPI property.


 OMP_O_IM_C_G4_CLASS_1_BD_PRT

[New - Windows 95]

The attributes of the class OMP_O_IM_C_G4_CLASS_1_BD_PRT are not mapped to Extended MAPI properties.

MH ID/Type	MAPI Property
IM_G4_CLASS_1_DOCUMENT	Not mapped to an Extended MAPI property.


 OMP_O_IM_C_GENERAL_TEXT_BD_PRT

[New - Windows 95]

The attributes of the class OMP_O_IM_C_GENERAL_TEXT_BD_PRT are not mapped to Extended MAPI properties.

MH ID/Type	MAPI Property
IM_CHAR_SET_REG	Not mapped to an Extended MAPI property.
IM_TEXT	Not mapped to an Extended MAPI property.


 OMP_O_IM_C_IA5_TEXT_BD_PRT

[New - Windows 95]

The attributes of the class OMP_O_IM_C_IA5_TEXT_BD_PRT are mapped to the following Extended MAPI properties:

MH ID/Type	MAPI Property
IM_REPERTOIRE	Not mapped to an Extended MAPI property.
IM_TEXT	PR_BODY


 OMP_O_IM_C_INTERPERSONAL_MSG

[New - Windows 95]

The attributes of the class OMP_O_IM_C_INTERPERSONAL_MSG map to Extended MAPI properties as follows:

MH ID/Type	MAPI Property
IM_AUTHORIZING_USERS	PR_AUTHORIZING_USERS
IM_AUTO_FORWARDED	PR_AUTO_FORWARDED
IM_BLIND_COPY_RECIPIENTS	PR_DISPLAY_BCC
IM_BODY	PR_BODY
IM_COPY_RECIPIENTS	PR_DISPLAY_CC
IM_EXPIRY_TIME	PR_EXPIRY_TIME
IM_IMPORTANCE	PR_IMPORTANCE
IM_INCOMPLETE_COPY	PR_INCOMPLETE_COPY
IM_LANGUAGES	PR_LANGUAGES
IM_OBSOLETED_IPMS	PR_OBSOLETED_IPMS
IM_ORIGINATOR	PR_CALLBACK_TELEPHONE_NUMBER, PR_SENDER_ADDRTYPE, PR_SENDER_EMAIL_ADDRESS, PR_SENDER_ENTRYID, PR_SENDER_NAME, PR_SENDER_SEARCH_KEY (and all PR_SENT_REPRESENTING_* properties)
IM_PRIMARY_RECIPIENTS	PR_DISPLAY_TO
IM_RELATED_IPMS	PR_RELATED_IPMS
IM_REPLIED_TO_IPM	PR_PARENT_KEY
IM_REPLY_RECIPIENTS	PR_REPLY_RECIPIENT_ENTRIES, PR_REPLY_RECIPIENT_NAMES
IM_REPLY_TIME	PR_REPLY_TIME
IM_SENSITIVITY	PR_SENSITIVITY
IM_SUBJECT	PR_NORMALIZED_SUBJECT, PR_SUBJECT, PR_SUBJECT_PREFIX
IM_THIS_IPM	PR_SEARCH_KEY
The following constant values are mapped from IM_IMPORTANCE to PR_IMPORTANCE:

Importance	Extended MAPI Value
IM_HIGH	2
IM_LOW	0
IM_ROUTINE	1
The following constant values are mapped from IM_SENSITIVITY to PR_SENSITIVITY:

IM_SENSITIVITY value	PR_SENSITIVITY value
IM_COMPANY_CONFIDENTIAL	SENSITIVITY_COMPANY_CONFIDENTIAL
IM_NOT_SENSITIVE	SENSITIVITY_NONE
IM_PERSONAL	SENSITIVITY_PERSONAL
IM_PRIVATE	SENSITIVITY_PRIVATE


 OMP_O_IM_C_INTERPERSONAL_NOTIF

[New - Windows 95]

The attributes of the class OMP_O_IM_C_INTERPERSONAL_NOTIF map to Extended MAPI properties as follows:

MH ID/Type	MAPI Property
IM_CONVERSION_EITS	PR_CONVERSION_EITS
IM_IPM_INTENDED_RECIPIENT	PR_ORIGINALLY_INTENDED_RECIPIENT_NAME
IM_IPN_ORIGINATOR	PR_CALLBACK_TELEPHONE_NUMBER, PR_SENDER_ADDRTYPE, PR_SENDER_EMAIL_ADDRESS, PR_SENDER_ENTRYID, PR_SENDER_NAME, PR_SENDER_SEARCH_KEY (and all PR_SENT_REPRESENTING_ * properties)
IM_SUBJECT_IPM	PR_ORIGINAL_SEARCH_KEY


 OMP_O_IM_C_IPM_IDENTIFIER

[New - Windows 95]

The attributes of the class OMP_O_IM_C_IPM_IDENTIFIER map to Extended MAPI properties as follows:

MH ID/Type	MAPI Property
IM_USER, IM_USER_RELATIVE_IDENTIFIER	Construct a GUID from IM_USER_RELATIVE_IDENTIFIER


 OMP_O_IM_C_ISO_6937_TEXT_BD_PRT

[New - Windows 95]

The attributes of the class OMP_O_IM_C_ISO_6937_TEXT_BD_PRT are mapped to the following Extended MAPI properties:

MH ID/Type	MAPI Property
IM_REPERTOIRE	Not mapped to an Extended MAPI property.
IM_TEXT	PR_ATTACH_DATA_BIN


 OMP_O_IM_C_MESSAGE_BD_PRT

[New - Windows 95]

The attributes of the class OMP_O_IM_C_MESSAGE_BD_PRT are mapped as follows:

MH ID/Type	MAPI Property
IM_ENVELOPE	Not mapped to an Extended MAPI property.
IM_IPM	Mapped to an IMessage object embedded in the message.


 OMP_O_IM_C_MIXED_MODE_BD_PRT

[New - Windows 95]

The attributes of the class OMP_O_IM_C_MIXED_MODE_BD_PRT are not mapped to any Extended MAPI properties.

MH ID/Type	MAPI Property
IM_MIXED_MODE_DOCUMENT	Not mapped to an Extended MAPI property.


 OMP_O_IM_C_NATIONAL_DEF_BD_PRT

[New - Windows 95]

The attributes of the class OMP_O_IM_C_NATIONAL_DEF_BD_PRT are not mapped to Extended MAPI properties.

MH ID/Type	MAPI Property
IM_NATIONAL_DATA	Not mapped to an Extended MAPI property.


 OMP_O_IM_C_NON_RECEIPT_NOTIF

[New - Windows 95]

The attributes of the class OMP_O_IM_C_NON_RECEIPT_NOTIF map to Extended MAPI properties (when PR_NON_RECEIPT_NOTIFICATION_REQUESTED = 1 in Recipient table or when the message has PR_READ_RECEIPT_REQUESTED = 1), as follows:

MH ID/Type	MAPI Property
IM_AUTO_FORWARD_COMMENT	PR_AUTO_FORWARD_COMMENT
IM_DISCARD_REASON	PR_DISCARD_REASON
IM_NON_RECEIPT_REASON	PR_NON_RECEIPT_REASON
IM_RETURNED_IPM	(Object; no corresponding property)
The following constant values are mapped from IM_DISCARD_REASON to PR_DISCARD_REASON:

IM_DISCARD_REASON value	PR_DISCARD_REASON value
IM_NO_DISCARD	-1
IM_IPM_EXPIRED	0
IM_IPM_OBSOLETED	1
IM_USER_TERMINATED	2
The following constant values are mapped from IM_NON_RECEIPT_REASON to PR_NON_RECEIPT_REASON:

IM_NON_RECEIPT_REASON value	PR_NON_RECEIPT_REASON value
IM_IPM_AUTO_FORWARDED	1
IM_IPM_DISCARDED	0


 OMP_O_IM_C_ODA_BD_PRT

[New - Windows 95]

The attributes of the class OMP_O_IM_C_ODA_BD_PRT are not mapped to Extended MAPI properties.

MH ID/Type	MAPI Property
IM_APPLICATION_PROFILE	Not mapped to an Extended MAPI property.
IM_ARCHITECTURE_CLASS	Not mapped to an Extended MAPI property.
IM_ODA_DOCUMENT	Not mapped to an Extended MAPI property.


 OMP_O_IM_C_OR_DESCRIPTOR

[New - Windows 95]

The attributes of the class OMP_O_IM_C_OR_DESCRIPTOR map to Extended MAPI properties as follows:

MH ID/Type	MAPI Property
IM_FORMAL_NAME	Extract name using PR_ENTRYID; for X.400 address types, build an OR Address from string address.
IM_FREE_FORM_NAME	PR_SENDER_NAME for originator, PR_DISPLAY_NAME for recipient, or extract the display name using PR_SENDER_ENTRYID
IM_TELEPHONE_NUMBER	PR_CALLBACK_TELEPHONE_NUMBER for originator, PR_PRIMARY_TELEPHONE_NUMBER for recipient


 OMP_O_IM_C_RECEIPT_NOTIF

[New - Windows 95]

The attributes of the class OMP_O_IM_C_RECEIPT_NOTIF map to Extended MAPI properties, as follows:

MH ID/Type	MAPI Property
IM_ACKNOWLEDGEMENT_MODE	PR_ACKNOWLEDGEMENT_MODE
IM_RECEIPT_TIME	PR_RECEIPT_TIME
IM_SUPPLEMENTARY_RECEIPT_INFO	PR_REPORT_TEXT
The following constant values are mapped from IM_ACKNOWLEDGEMENT_MODE to PR_ACKNOWLEDGEMENT_MODE:

IM_ACKNOWLEDGEMENT_ MODE value	PR_ACKNOWLEDGEMENT_ MODE value
IM_AUTOMATIC	1
IM_MANUAL	0


 OMP_O_IM_C_RECIPIENT_SPECIFIER

[New - Windows 95]

The attributes of the class OMP_O_IM_C_OR_DESCRIPTOR map to Extended MAPI properties as follows:

MH ID/Type	MAPI Property
IM_IPM_RETURN_REQUESTED	PR_IPM_RETURN_REQUESTED
IM_NOTIFICATION_REQUEST	PR_NON_RECEIPT_NOTIFICATION_ REQUESTED,  PR_READ_RECEIPT_REQUESTED
IM_RECIPIENT	PR_ADDRTYPE, PR_DISPLAY_NAME, PR_EMAIL_ADDRESS, PR_ENTRYID, PR_OFFICE_LOCATION, PR_PRIMARY_TELEPHONE_NUMBER, PR_SEARCH_KEY
IM_REPLY_REQUESTED	PR_REPLY_REQUESTED
The following constant values are mapped from IM_NOTIFICATION_REQUEST to the corresponding Extended MAPI properties:

IM_NOTIFICATION_REQUEST Value	Extended MAPI Values
IM_ALWAYS	PR_NON_RECEIPT_NOTIFICATION_ REQUESTED = TRUE, PR_READ_RECEIPT_REQUESTED  = TRUE
IM_NEVER	PR_NON_RECEIPT_NOTIFICATION_ REQUESTED = FALSE, PR_READ_RECEIPT_REQUESTED  = FALSE
IM_NON_RECEIPT	PR_NON_RECEIPT_NOTIFICATION_ REQUESTED = TRUE, PR_READ_RECEIPT_REQUESTED  = FALSE


 OMP_O_IM_C_TELETEX_BD_PRT

[New - Windows 95]

The attributes of the class OMP_O_IM_C_TELETEX_BD_PRT are mapped to the following Extended MAPI properties:

MH ID/Type	MAPI Property
IM_TELETEX_COMPATIBLE	Not mapped to an Extended MAPI property.
IM_TELETEX_DOCUMENT	PR_BODY
IM_TELETEX_NBPS	Not mapped to an Extended MAPI property.


 OMP_O_IM_C_UNIDENTIFIED_BD_PRT

[New - Windows 95]

The attributes of the class OMP_O_IM_C_UNIDENTIFIED_BD_PRT are not mapped to Extended MAPI properties.

MH ID/Type	MAPI Property
IM_UNIDENTIFIED_DATA	Not mapped to an Extended MAPI property.
IM_UNIDENTIFIED_TAG	Not mapped to an Extended MAPI property.


 OMP_O_IM_C_USA_NAT_DEF_BD_PRT

[New - Windows 95]

The attributes of the class OMP_O_IM_C_USA_NAT_DEF_BD_PRT are mapped to the following Extended MAPI properties:

MH ID/Type	MAPI Property
IM_BODY_PART_NUMBER	Not mapped to an Extended MAPI property.
IM_USA_DATA	Not mapped to an Extended MAPI property.


 OMP_O_IM_C_VIDEOTEX_BD_PRT

[New - Windows 95]

The attributes of the class OMP_O_IM_C_VIDEOTEX_BD_PRT are not mapped to Extended MAPI properties.

MH ID/Type	MAPI Property
IM_VIDEOTEX_DATA	Not mapped to an Extended MAPI property.
IM_VIDEOTEX_SYNTAX	Not mapped to an Extended MAPI property.


 Comprehensive X.400 Attributes Reference

The following table contains mappings between X.400 P2 attributes and Extended MAPI properties, listed in alphabetical order. The name of the object appears in parentheses.

MH ID/Type	MAPI Property
IM_ACKNOWLEDGEMENT_MODE (OMP_O_IM_C_RECEIPT_NOTIF)	PR_ACKNOWLEDGEMENT_MODE
IM_APPLICATION_PROFILE (OMP_O_IM_C_ODA_BD_PRT)	Not mapped to an Extended MAPI property.
IM_ARCHITECTURE_CLASS (OMP_O_IM_C_ODA_BD_PRT)	Not mapped to an Extended MAPI property.
IM_AUTHORIZING_USERS (OMP_O_IM_C_INTERPERSONAL_MSG)	PR_AUTHORIZING_USERS
IM_AUTO_FORWARD_COMMENT (OMP_O_IM_C_NON_RECEIPT_NOTIF)	PR_AUTO_FORWARD_COMMENT
IM_AUTO_FORWARDED (OMP_O_IM_C_INTERPERSONAL_MSG)	PR_AUTO_FORWARDED
IM_BILATERAL_DATA (OMP_O_IM_C_BILAT_DEF_BD_PRT)	PR_ATTACH_DATA_BIN
IM_BLIND_COPY_RECIPIENTS (OMP_O_IM_C_INTERPERSONAL_MSG)	PR_DISPLAY_BCC
IM_BODY  (OMP_O_IM_C_INTERPERSONAL_MSG)	PR_BODY
IM_BODY_PART_NUMBER (OMP_O_IM_C_USA_NAT_DEF_BD_PRT)	Not mapped to an Extended MAPI property.
IM_CHAR_SET_REG (OMP_O_IM_C_GENERAL_TEXT_BD_PRT)	Not mapped to an Extended MAPI property.
IM_CONVERSION_EITS (OMP_O_IM_C_INTERPERSONAL_NOTIF)	PR_CONVERSION_EITS
IM_COPY_RECIPIENTS (OMP_O_IM_C_INTERPERSONAL_MSG)	PR_DISPLAY_CC
IM_DISCARD_REASON (OMP_O_IM_C_NON_RECEIPT_NOTIF)	PR_DISCARD_REASON
IM_ENVELOPE (OMP_O_IM_C_MESSAGE_BD_PRT)	Not mapped to an Extended MAPI property.
IM_EXPIRY_TIME (OMP_O_IM_C_INTERPERSONAL_MSG)	PR_EXPIRY_TIME
IM_EXTERNAL_DATA (OMP_O_IM_C_EXTERN_DEF_BD_PRT)	PR_ATTACH_DATA_BIN, PR_ATTACH_FILENAME, PR_ATTACH_TAG
IM_EXTERNAL_PARAMETERS (OMP_O_IM_C_EXTERN_DEF_BD_PRT)	PR_ATTACHMENT_X400_PARAMETERS
IM_FORMAL_NAME (OMP_O_IM_C_OR_DESCRIPTOR)	Extract name using PR_ENTRYID; for X.400 address types, build an OR Address from string address.
IM_FREE_FORM_NAME (OMP_O_IM_C_OR_DESCRIPTOR)	PR_SENDER_NAME for originator, PR_DISPLAY_NAME for recipient, or extract the display name using PR_SENDER_ENTRYID
IM_G3_FAX_NBPS (OMP_O_IM_C_G3_FAX_BD_PRT)	Not mapped to an Extended MAPI property.
IM_G4_CLASS_1_DOCUMENT (OMP_O_IM_C_G4_CLASS_1_BD_PRT)	Not mapped to an Extended MAPI property.
IM_IMAGES (OMP_O_IM_C_G3_FAX_BD_PRT)	Not mapped to an Extended MAPI property.
IM_IMPORTANCE (OMP_O_IM_C_INTERPERSONAL_MSG)	PR_IMPORTANCE
IM_INCOMPLETE_COPY (OMP_O_IM_C_INTERPERSONAL_MSG)	PR_INCOMPLETE_COPY
IM_IPM (OMP_O_IM_C_MESSAGE_BD_PRT)	Mapped to an IMessageobject embedded in the message.
IM_IPM_INTENDED_RECIPIENT (OMP_O_IM_C_INTERPERSONAL_NOTIF)	PR_ORIGINALLY_INTENDED_RECIPIENT_NAME
IM_IPM_RETURN_REQUESTED (OMP_O_IM_C_OR_DESCRIPTOR)	PR_IPM_RETURN_REQUESTED
IM_IPN_ORIGINATOR (OMP_O_IM_C_INTERPERSONAL_NOTIF)	PR_CALLBACK_TELEPHONE_NUMBER, PR_SENDER_ADDRTYPE, PR_SENDER_EMAIL_ADDRESS, PR_SENDER_ENTRYID, PR_SENDER_NAME, PR_SENDER_SEARCH_KEY (and all PR_SENT_REPRESENTING_ * properties)
IM_LANGUAGES (OMP_O_IM_C_INTERPERSONAL_MSG)	PR_LANGUAGES
IM_MIXED_MODE_DOCUMENT (OMP_O_IM_C_MIXED_MODE_BD_PRT)	Not mapped to an Extended MAPI property.
IM_NATIONAL_DATA (OMP_O_IM_C_NATIONAL_DEF_BD_PRT)	Not mapped to an Extended MAPI property.
IM_NON_RECEIPT_REASON (OMP_O_IM_C_NON_RECEIPT_NOTIF)	PR_NON_RECEIPT_REASON
IM_NOTIFICATION_REQUEST (OMP_O_IM_C_OR_DESCRIPTOR)	PR_NON_RECEIPT_NOTIFICATION_REQUESTED,  PR_READ_RECEIPT_REQUESTED
IM_OBSOLETED_IPMS (OMP_O_IM_C_INTERPERSONAL_MSG)	PR_OBSOLETED_IPMS
IM_ODA_DOCUMENT (OMP_O_IM_C_ODA_BD_PRT)	Not mapped to an Extended MAPI property.
IM_ORIGINATOR (OMP_O_IM_C_INTERPERSONAL_MSG)	PR_CALLBACK_TELEPHONE_NUMBER, PR_SENDER_ADDRTYPE, PR_SENDER_EMAIL_ADDRESS, PR_SENDER_ENTRYID, PR_SENDER_NAME, PR_SENDER_SEARCH_KEY (and all PR_SENT_REPRESENTING_* properties)
IM_PRIMARY_RECIPIENTS (OMP_O_IM_C_INTERPERSONAL_MSG)	PR_DISPLAY_TO
IM_RECEIPT_TIME (OMP_O_IM_C_RECEIPT_NOTIF)	PR_RECEIPT_TIME
IM_RECIPIENT (OMP_O_IM_C_OR_DESCRIPTOR)	PR_ADDRTYPE, PR_DISPLAY_NAME, PR_EMAIL_ADDRESS, PR_ENTRYID, PR_OFFICE_LOCATION, PR_PRIMARY_TELEPHONE_NUMBER, PR_SEARCH_KEY
IM_RELATED_IPMS (OMP_O_IM_C_INTERPERSONAL_MSG)	PR_RELATED_IPMS
IM_REPERTOIRE (OMP_O_IM_C_IA5_TEXT_BD_PRT)	Not mapped to an Extended MAPI property.
IM_REPERTOIRE (OMP_O_IM_C_ISO_6937_TEXT_BD_PRT)	Not mapped to an Extended MAPI property.
IM_REPLIED_TO_IPM (OMP_O_IM_C_INTERPERSONAL_MSG)	PR_PARENT_KEY
IM_REPLY_RECIPIENTS (OMP_O_IM_C_INTERPERSONAL_MSG)	PR_REPLY_RECIPIENT_ENTRIES, PR_REPLY_RECIPIENT_NAMES
IM_REPLY_REQUESTED (OMP_O_IM_C_OR_DESCRIPTOR)	PR_REPLY_REQUESTED
IM_REPLY_TIME (OMP_O_IM_C_INTERPERSONAL_MSG)	PR_REPLY_TIME
IM_RETURNED_IPM (OMP_O_IM_C_NON_RECEIPT_NOTIF)	(Object; no corresponding property)
IM_SENSITIVITY (OMP_O_IM_C_INTERPERSONAL_MSG)	PR_SENSITIVITY
IM_SUBJECT (OMP_O_IM_C_INTERPERSONAL_MSG)	PR_NORMALIZED_SUBJECT, PR_SUBJECT, PR_SUBJECT_PREFIX
IM_SUBJECT_IPM (OMP_O_IM_C_INTERPERSONAL_NOTIF)	PR_ORIGINAL_SEARCH_KEY
IM_SUPPLEMENTARY_RECEIPT_INFO (OMP_O_IM_C_RECEIPT_NOTIF)	PR_REPORT_TEXT
IM_TELEPHONE_NUMBER (OMP_O_IM_C_OR_DESCRIPTOR)	PR_CALLBACK_TELEPHONE_NUMBER for Originator, PR_PRIMARY_TELEPHONE_NUMBER for Recipient
IM_TELETEX_COMPATIBLE (OMP_O_IM_C_TELETEX_BD_PRT)	Not mapped to an Extended MAPI property.
IM_TELETEX_DOCUMENT (OMP_O_IM_C_TELETEX_BD_PRT)	PR_BODY
IM_TELETEX_NBPS (OMP_O_IM_C_TELETEX_BD_PRT)	Not mapped to an Extended MAPI property.
IM_TEXT (OMP_O_IM_C_GENERAL_TEXT_BD_PRT)	Not mapped to an Extended MAPI property.
IM_TEXT (OMP_O_IM_C_IA5_TEXT_BD_PRT)	PR_BODY
IM_TEXT (OMP_O_IM_C_ISO_6937_TEXT_BD_PRT)	PR_ATTACH_DATA_BIN
IM_THIS_IPM (OMP_O_IM_C_INTERPERSONAL_MSG)	PR_SEARCH_KEY
IM_UNIDENTIFIED_DATA (OMP_O_IM_C_UNIDENTIFIED_BD_PRT)	Not mapped to an Extended MAPI property.
IM_UNIDENTIFIED_TAG (OMP_O_IM_C_UNIDENTIFIED_BD_PRT)	Not mapped to an Extended MAPI property.
IM_USA_DATA (OMP_O_IM_C_USA_NAT_DEF_BD_PRT)	Not mapped to an Extended MAPI property.
IM_USER, IM_USER_RELATIVE_IDENTIFIER (OMP_O_IM_C_IPM_IDENTIFIER)	Construct a GUID from IM_USER_RELATIVE_IDENTIFIER
IM_VIDEOTEX_DATA (OMP_O_IM_C_VIDEOTEX_BD_PRT)	Not mapped to an Extended MAPI property.
IM_VIDEOTEX_SYNTAX (OMP_O_IM_C_VIDEOTEX_BD_PRT)	Not mapped to an Extended MAPI property.


 Glossary


 A

 address book

A collection of one or more recipients. Recipients are messaging users or distribution lists.

address book container

A MAPI address book object that holds recipients, such as distribution lists and messaging users, and implements the IABContainer interface.

address book provider

A service provider that manages one or more address book containers, enabling users to address messages and create recipients.

advise sink

A MAPI object that is told of changes affecting other MAPI objects. Advise sinks register with specific objects to be told of specific types of changes. Advise sinks implement the IMAPIAdviseSink interface.

ambiguous name resolution

See name resolution.

application registry

A MAPI folder object that an application designates to store a form-server executable file, a form configuration file, and all incoming messages for one or more message classes. An application registry implements the IMAPIFormContainer interface and is a form registry that is specific to a particular application. See also form registry, personal registry.

associated information

Hidden data that relates to a standard folder and enables providers to order information in that folder; examples of such data include a view and the definition of a form.

attachment

A MAPI object that contains data appended to a message and that implements the IAttach interface. Most attachments are either files, OLE objects, other messages, or binary data such as sound or images.

attachment table

A MAPI table object that provides access to information about a message's attachments.


 B

bookmark

A marker that identifies a position within a table.


 C

CCITT

The International Telegraph and Telephone Consultative Committee, an international standards committee and division of the United Nations that defines standards, such as the Electronic Document Integration (EDI) data standard. Now called the International Telecommunications Union (ITU). The acronym stands for Comite Consultatif International Telegraphique et Telephonique, the committee's French name. See also Electronic Document Integration, X.435, X.500.

client

See client application.

client application

A program that enables its user to interact with an underlying messaging system by calling functions or interface methods implemented by the MAPI subsystem. These functions and methods are known collectively as the client interface. See also client interface, messaging application.

client extension

A program component that is used with a client application to add to the application's feature set, for example to add a handler for custom commands.

client interface

The set of interfaces and functions that are implemented or used by client applications. MAPI's client interface has three components: Common Messaging Calls (CMC), Simple MAPI, and Extended MAPI.

CMC

See Common Messaging Calls.

common dialog box

A Microsoft Windows dialog box that is provided with the MAPI SDK. Client applications use common dialog boxes to promote an appearance both consistent within the application and consistent with other Windows-based applications.

Common Messaging Calls

(CMC) A set of functions that is based upon the standard developed by the X.400 Application Programming Interface Association (XAPIA) and that is part of the MAPI subsystem's client application interface. CMC is a cross-platform function set that enables client applications to be independent of the actual messaging system, operating system, or hardware used. See also Extended MAPI, Simple MAPI.

Common Messaging Calls data extension

A data structure that is used to add features to Common Messaging Calls (CMC) functions and structures. Data extensions can add members to existing data structures or parameters to existing CMC functions.

compound entry identifier

An identifier that is created by combining the entry identifier of a message store and the entry identifier of a message within the store. Compound entry identifiers are used by Simple MAPI client applications to open messages from a nondefault message store provider. See also entry identifier.

configuration file

A formatted file created by form developers to define a form. Because configuration files are used by form servers to load forms, each form must be defined using a configuration file. Configuration files must have the .CFG filename extension.

connection number

A number that uniquely identifies a notification registration.

container

A MAPI object that holds one or more other MAPI objects and that implements the IMAPIContainer interface. Address books and folders are two types of containers. See also address book container, folder, form container.

contents table

A MAPI table object that provides access to what is contained within another MAPI object. Contents tables are used by message store providers, for example, to display information about messages within a folder.

conversation key

An identifier that, applied to a message, identifies it as one of a series of messages about a particular topic and that enables messages to be sorted by topic. Like other keys, the conversation key is a binary reference or tag that can be compared with other binary references or tags. How messages are sorted using conversation keys is determined by a client application and is not affected by user actions. The message property that holds the conversation key is PR_CONVERSATION_KEY.

conversation thread

A collection of messages that pertain to the same topic.

custom recipient

An address book entry that represents a recipient that is not in the current address book. A custom recipient is created by the user of a client application with a template supplied by the address book provider. Also referred to as a one-off address.

custom recipient table

A MAPI table object that provides access to information about supported custom recipients.


 D

data extension

See Common Messaging Calls data extension.

default profile

Configuration information about a session's set of message services, with which a client application logs on if no other such configuration information is specified. The default profile is stored under the default profile key in the MAPISVC.INF file.

delegate access

The ability of one user to allow another user to send messages as the first user and to access the first user's message store.

Deleted Items folder

A standard folder within the interpersonal message (IPM) subtree that is usually designated to hold items, such as messages, that are marked for deletion. See also IPM subtree.

delivery report

An announcement from the MAPI spooler or a transport provider to a message sender that indicates a recipient has received a message. The recipient might or might not have read the message.

disk instance

A temporary file that contains executable files for a form if those executable files are not yet on the user's local disk.

display name

A character string that represents a MAPI object in the user interface. Service providers assign display names to their objects by setting each object's PR_DISPLAY_NAME property.

display table

A MAPI table object that describes the layout of a dialog box. Each row in the table represents a control in the dialog box; each column in the table has data about one property of the control, such as its location, size, or type.

distribution list

A MAPI address book object that represents a set of individual recipients addressed together as a group and that implements the IDistList interface. Distribution lists can contain other distribution lists and individual recipients. A distribution list is one of the two types of MAPI address book objects that can receive messages; the other is a mail user object. See also mail user object, recipient.

DR

See delivery report.


 E

Electronic Document Integration

(EDI) A standard for integrating data with various native formats into a message, which has been defined by the International Telegraph and Telephone Consultative Committee (CCITT) standards body, now called the International Telecommunications Union (ITU), and is implemented in the X.435 message-handling standard. See also X.435.

entry identifier

A unique piece of data that distinguishes a MAPI object from all other objects of the same type. Entry identifiers allow the MAPI subsystem to determine which service provider should handle a particular object. An object's entry identifier is stored in its PR_ENTRYID property. See also compound entry identifier, long-term entry identifier, short-term entry identifier.

event

A change in an object's state that can generate a notification, such as a critical error occurring or a table object being modified. See also notification.

event mask

A bitmask that is used to indicate one or more types of notifications. Advise sink objects register for specific notifications using the event mask.

Extended MAPI

A set of functions and object-oriented interfaces that forms the foundation for the MAPI subsystem's client and service provider interfaces. Extended MAPI is intended for complex messaging-based applications, such as advanced workgroup programs, and for service providers. See also Common Messaging Calls, Simple MAPI.

extension

See client extension, Common Messaging Calls data extension.


 F

flag

A constant that indicates a particular option for an operation. A flag is used either alone or with other flags to set a bitmask parameter, structure member, or property. When multiple flags must be set, use the logical-OR operator.

folder

A MAPI object in a message store that can contain other objects, such as messages and other folders. Also referred to as a standard folder. See also IPM subtree, receive folder, root folder, search-results folder.

foreign system

An X.400 messaging term indicating a messaging system outside the realm of the local X.400 network.

form

A MAPI object that is used to display a message with a particular message class in a structured format based on MAPI properties. User interaction with the form is controlled with a form server application. MAPI form objects implement the IMAPIForm and IMAPIFormInfo interfaces.

form activation

The process of starting a form server so as to enable a user to work with a particular form within a client application.

form container

A MAPI folder object that an application designates to store a form-server executable file, a form configuration file, and all incoming messages for one or more message classes. A form container implements the IMAPIFormContainer interface. Also referred to as an application registry. See also application registry, form registry.

form registry

A MAPI folder object that contains information about a form, such as the form's executable file, its configuration file, and all incoming messages for one or more message classes. A form registry can be any folder into which a form is installed. See also application registry, personal registry.

form registry provider

A service provider that manages form registries, that implements the IMAPIFormMgr interface, and that like most service providers is a dynamic-link library (DLL).

form resolution

The process of mapping the message classes of particular messages to the class identifiers of the form servers for those messages. Form resolution determines which piece of code should be activated to manage interaction with a particular message.

form server

An application that manages a user's interaction with a form, for example responding to menu commands. See also message class handler.

form viewer

A type of client application that can display a MAPI form.

fuzzy level

A value that describes the degree of exactness or looseness desired when searching for a target word in a text selection. Lower levels of fuzziness indicate more exact matching; higher levels return matches for more varied forms of the target word and usually require more execution time.


 G

gateway

Software that links two or more dissimilar messaging systems (that is, two or more messaging systems that use different protocols). A gateway provides protocol and storage conversion.


 H

hands-off state

A condition in which a form's storage object is unavailable for either read-only or read-write access. Forms are placed in the hands-off state during a save operation to enable the save operation to occur uninterrupted. See also normal state, no-scribble state.

hierarchy table

A MAPI table object that provides hierarchical access to information within a MAPI container. For example, a hierarchy table is used by message store providers to display the folder hierarchy.

hook provider

See message hook provider.


 I

IID

See interface identifier.

Inbox

A standard folder within the interpersonal message (IPM) subtree that is usually designated as the destination for incoming messages. See also IPM subtree, receive folder.

information service

See message service.

information store

The default message store provider for the Microsoft Exchange Server.

input parameter

A structure, pointer, or variable that is allocated, initialized, and freed by a process that calls a public function or interface method. See also input-output parameter, output parameter.

input-output parameter

A structure, pointer, or variable that is initially allocated, initialized, and eventually freed by a process that calls a public function or interface method. Special memory allocation rules apply to input-output parameters. Input-output parameters are typically used to reset a value specified by the calling process. See also input parameter, output parameter.

interface identifier

(IID) A constant that represents a particular interface and is used to request a pointer to the interface in a variety of method calls. For example, the IID for the IAddrBook interface is IID_IADDRBOOK.

International Telecommunications Union

(ITU) See CCITT.

interpersonal message

(IPM) A message that belongs to a message class for which messages are meant to be read by a user rather than by an application or process.

IPM

See interpersonal message.

IPM subtree

(interpersonal message subtree) A set of standard folders that is typically created by MAPI to handle incoming, outgoing, deleted, and sent messages. The default names for these folders are the Inbox, Outbox, Sent Items, and Deleted Items folders.


 K

key

A binary reference or tag that can be compared with another binary reference or tag. See also conversation key, record key.


 L

local message store

A message store provider that keeps its data on the user's local disk.

logon

The process by which a messaging user establishes a session with the MAPI subsystem. Logon involves the verification of the user's name and password and the user's selection of a valid profile.

logoff

The process by which a messaging user ends a session with the MAPI subsystem.

long-term entry identifier

An entry identifier that is stored for later use and that can be used for multiple operations. See also short-term entry identifier.


 M

mail user object

A MAPI address book container object that represents an individual messaging user and that implements the IMailUser interface. A mail user object is one of two types of MAPI address book objects that can receive messages; the other is a distribution list object. See also distribution list, recipient.

MAPI

(Messaging Application Programming Interface) A messaging architecture that enables multiple applications to interact with multiple messaging systems across a variety of hardware platforms. See also Extended MAPI, MAPI subsystem, Simple MAPI.

MAPI interface

A set of related functions that describe the behavior of an object in the MAPI environment. All MAPI interfaces derive from the OLE base interface, IUnknown.

MAPI object

An object that supports the OLE component object model, implementing one or more interfaces derived from the IUnknown interface.

MAPI spooler

A MAPI process that queues messages until ready to send and handles the sending of messages between client applications and messaging systems.

MAPI subsystem

The set of dynamic link libraries (DLLs) provided by MAPI that enable interaction between client applications and service providers. The MAPI subsystem DLLs implement the MAPI spooler, the client interface, the service provider interface, and several support objects.

message

A MAPI message store object that is used for sending data and receiving data by means of a messaging system and that implements the IMessage interface.

message class

A string property that is assigned to each MAPI message, identifying the type of message.

message class handler

A MAPI object that facilitates limited interaction between a form and its form viewer and that can be implemented as either a dynamic link library (DLL) or an executable file. A form server enables more robust form interaction than a message handler does. See also form server.

message hook provider

A service provider that operates on either outbound messages or inbound messages. Outbound hook providers process messages before the MAPI spooler routes them to the transport provider. Inbound hook providers are used to intercept messages and reroute them. For example, a message hook provider might move messages from the default Sent Items folder to an alternate folder. Message hook providers implement the ISpoolerHook interface. Also referred to as a spooler hook or a hook provider. See also message postprocessor, message preprocessor.

message postprocessor

A transport provider component that operates on messages immediately after they have been sent by the MAPI spooler. For example, a message postprocessor might delete the local copy of a message made by a message preprocessor. See also message hook provider, message preprocessor.

message preprocessor

A transport provider component that operates on messages at some time before they are sent. For example, a message preprocessor might make a local copy of every outgoing message. See also message hook provider, message postprocessor.

message service

A group of one or more related service providers. Defining a message service simplifies installation and configuration. Rather than working with individual service providers, client applications work with the message service. The message service has information about each of its service providers.

message service table

A MAPI table object that provides access to information about currently loaded message services, such as a service's name and associated files.

message site

A MAPI object that provides an area for form display and that implements the IMAPIMessageSite interface.

message store

A MAPI object that contains messages and folders organized hierarchically and that implements the IMsgStore interface.

message store provider

A service provider that manages a message store, handling message distribution, organization, and storage.

message stores table

A MAPI table object that provides access to information about currently loaded message stores.

messaging application

A program that uses the MAPI subsystem's client application interface to pass messaging requests, such as requests to send and receive messages, to and from a messaging system. A messaging application is a type of client application. See also client application.

messaging service

See message service.

messaging system

A product that enables electronic communication over a network, such as sending and receiving information.

messaging transport provider

See transport provider.

multivalued property

A property for which the data structure's property type contains the flag MV_FLAG and the property value contains multiple values of the specified property type. See also property value, single-valued property.


 N

name resolution

The process of associating a string with a valid address for a particular messaging system. An unresolved name lacks an entry identifier. The names of all recipients for a message must resolved before the message can be sent. See also resolved recipient, unresolved recipient.

NDR

See nondelivery report.

no-scribble state

A condition in which a form's storage object is accessible only for reading; read-write access is prohibited. See also hands-off state, normal state.

non-IPM message

(noninterpersonal message) A message that is meant to be read by an application rather than by a human user, such as a notification message sent from a workgroup scheduling application.

nondelivery report

An announcement to a message sender that indicates a message could not be delivered to a recipient. Many situations can cause nondelivery reports to be generated, including when the message address is inaccurate, when the message address cannot be reached using the available transport providers, and when the network is not working.

nonread notification

An announcement to a message sender that indicates a message was not read by the recipient (that is, the application did not display the message contents to the recipient) before the recipient deleted the message or before the specified expiration time. Nonread notifications for a message are generated by a message store provider when the provider first processes the message.

nonread report

See nonread notification.

nontransmittable property

An X.400 property that is not sent with the message of which it is a part. Nontransmittable properties are typically those properties that only apply to a message before it has been sent. See also transmittable property.

normal state

A condition in which a form's storage object is accessible for both reading and writing. Form storage is typically in the normal state unless a save operation is occurring. See also hands-off state, no-scribble state.

notification

A pronouncement of change to a MAPI object. The object receiving the notification is referred to as the advise sink. Advise sinks register for a type of notification from a specific object by calling the object's Advise method. See also advise sink.

NRN

See nonread notification.


 O

OLE Messaging

A programming interface, used primarily by Visual Basic and Visual C and C messaging client developers. OLE Messaging provides programmable objects that, like Microsoft Excel objects and Microsoft Access objects, make available properties and methods that can then be managed by Visual Basic and Visual Basic for Applications programs.

OLE Messaging collection

An object that contains zero or more OLE Messaging objects of the same type. OLE Messaging supports two types of collections: large collections and small collections. With large collections, you can use the object's methods to get the first, next, last, and previous items within the collection. With small collections, you can access all items in the collection using an implied index.

OLE Messaging object

An object exposed by OLE Messaging, such as the Session object, Message object, or Folder object.

one-off address

See custom recipient.

Outbox

A standard folder within the interpersonal message (IPM) subtree that is usually designated as the holding place for outgoing messages before they are sent. See also IPM subtree.

output parameter

A structure, pointer, or variable that is allocated, initialized, and freed by a process that is called by a public function or interface method and used to send information back to the calling process. Special memory allocation rules apply to output parameters. See also input parameter, input-output parameter.


 P

PAB

See personal address book.

personal address book

A MAPI container object that holds recipient entries either created by the user or copied from other address book containers. Personal address book objects commonly are contained in files that have the filename extension .PAB.

personal message store

A MAPI message-store object that is created by a user and is stored in a file that has the .PST filename extension.

personal registry

A MAPI folder object that a user designates to store local form server executable and configuration files. A personal registry is a type of form registry. See also application registry, form registry.

primary identity

A string that represents the user of a MAPI session. The primary identity of the user sending a message is placed in that message's PR_RECIPIENT_FROM property when the message is sent.

probe

An X.400 messaging term indicating a message that has a specific message-class identifier but no content. Probes are used by X.400 message senders to determine whether a message has been sent to recipients and, if it has been sent, how.

profile

Configuration information about a session's set of message services. Profiles are created from information stored in the MAPI configuration file, MAPISVC.INF, and can be modified by service providers or by the MAPI configuration application.

profile name

A text string that identifies a particular profile.

profile section

A portion of a profile that is represented by a unique identifier. A profile section can contain information provided or used by MAPI, by a particular message service, or by a particular service provider.

profile table

A MAPI table object that provides access to the names and status of profiles on a particular computer.

property

A MAPI object that describes an attribute of another MAPI object and that implements the IMAPIProp interface. The information that defines a MAPI property is contained in a structure that holds a unique identifier, a data type, and a value. See also property tag, property value.

property identifier

A unique 16-bit number that identifies a particular property. The property identifier is contained in the high-order 16 bits of the property tag. See also property, property tag, property value.

property page

One section of a property sheet. See also property sheet.

property set

A group of user-defined properties.

property sheet

A dialog box that is used to display configuration information to the user and to enable the user to modify that information. A property sheet contains a collection of one or more property pages. See also property page.

property tag

A 32-bit unsigned integer within a property structure that contains the property's unique identifier and data type. The high-order 16 bits contain the unique identifier, and the low-order 16 bits contain the type. See also property, property identifier, property type, property value.

property type

A constant that describes the data type for a property and represents a single value or multiple values. The property type is contained in the low-order 16 bits of the property tag. See also property, property tag, property value.

property value

The actual data of a property, a part of that property's defining structure. Property values can be a single piece of data or multiple pieces of data. See also multivalued property, property, property tag, single-valued property.

provider

See service provider.

provider table

A MAPI table object that provides access to information about currently loaded service providers.

proxy address

An address that is used by directories from different X.400 messaging systems to refer to MAPI objects, such as distribution lists or faxes.

PST

See personal message store.


 R

read flag

A constant, MSGFLAG_READ, that is used to mark a message as having been read. The read flag for a message can be set in a variety of situations; its being set does not necessarily indicate the intended recipient has read the message.

read notification

A announcement to a message sender that indicates the read flag has been set for a message. A read notification can be sent in a variety of situations; its being sent does not necessarily indicate the intended recipient has read the message. Read notifications are generated by a message store provider when a message is first processed.

read receipt

See read notification.

read report

See read notification.

receive folder

A MAPI folder object that is designated as the destination for a particular set of incoming messages. Typically, the receive folder is the Inbox in the interpersonal message (IPM) subtree. See also Inbox, IPM subtree.

recipient

The user who receives a particular message. Recipients are individual messaging users, implemented as MAPI mail user objects, or collections of messaging users, implemented as MAPI distribution list objects. See also custom recipient, distribution list, mail user object.

recipient list

A collection of zero or more individual messaging users, groups of messaging users, or a combination of both types of users that are selected to receive a message.

recipient table

A MAPI table object that provides access to information about a message's recipient list.

recipient box

An editable field in the MAPI common dialog box for addressing into which names of recipients for a message being composed are placed. There must be at least one recipient box in the addressing dialog box for recipients that receive the message directly. There can be one or two other recipient boxes if either carbon copy (CC) or blind carbon-copy (BCC) recipients are supported.

record key

A unique identifier that is a binary reference or tag that can be compared with other binary reference or tags. Objects assign record keys by setting their PR_RECORD_KEY property.

registration

A request on the part of a client application or MAPI to receive notifications about a specific type of event. See also notification.

resolution

See name resolution.

resolved recipient

A messaging user or distribution list that has been assigned an entry identifier and an address for a particular messaging system. See also name resolution, unresolved recipient.

restriction

A test conducted against a table to filter the rows of the table, limiting a user's view of data to only those rows that passed the test.

RN

See read notification.

root folder

The MAPI folder object that appears at the top of the folder hierarchy. Only one root folder can exist in a message store; root folders are invisible to the user because of their inability to be moved, copied, renamed, or deleted. A root folder can contain messages and other folders.

rule

An operation implemented by a message hook provider. See also message hook provider.


 S

search-results folder

A MAPI folder object that contains a list of links to messages that match specified search criteria. A search-results folder is invisible to the user and is valid only for the duration of the current session. It cannot contain other folders or messages, and other folders or messages cannot be created in or moved into it.

section

A portion of either a session profile or a form configuration file. See also configuration file, profile section.

secure property

A property that has a property tag in the range 0x67F0 through 0x67FF and is encrypted and invisible. To view a secure property, it is necessary to ask specifically to view it. Secure properties are typically used for credentials such as passwords.

Sent Items folder

A standard folder within the interpersonal message (IPM) subtree that is usually designated to hold copies of outgoing messages. These copies are saved only if the message store provider supports this functionality and the user of the client application requests it. See also IPM subtree.

service provider

A dynamic-link library (DLL) that links client applications with services supplied by messaging systems. A service provider typically offers address book, form management, message store, message preprocessing, message postprocessing, or transport services. See also address book provider, form registry provider, message hook provider, message postprocessor, message preprocessor, message store provider, transport provider.

service provider interface

(SPI) The set of interfaces and functions that are implemented or used by service providers. The MAPISPI.H header file contains definitions of all the interface methods and functions in the service provider interface.

session

An active connection between a client application and the MAPI subsystem. The session identifies the available messaging operations and the service providers available to handle the operations.

session handle

A handle to a session initiated by a Simple MAPI client application. Session handles are returned by the MAPILogon function at logon time.

session identifier

A pointer to an Extended MAPI session object that implements the IMAPISession interface. Session identifiers are returned by the MAPILogonEx function at logon time.

shared session

A MAPI session that can be used by multiple client applications on a given computer.

short-term entry identifier

An entry identifier that is used for a single operation only and that is not stored for later use. See also long-term entry identifier.

Simple Mail Transfer Protocol

(SMTP) A protocol designed for reliable and efficient electronic mail transfer that is widely used in government and education facilities and on the Internet.

Simple MAPI

A set of functions that is part of the MAPI subsystem's client interface and that enables basic messaging features to be added to client applications. See also Common Messaging Calls, Extended MAPI.

single-valued property

A property for which the data structure contains one property value of the specified property type. See also multivalued property, property value.

SPI

See service provider interface.

spooler

See MAPI spooler.

spooler hook

See message hook provider.

status table

A MAPI table object that provides access to information about each of the service providers in the active profile, describing the state of a MAPI session.

store-and-forward messaging

A messaging model wherein messages are forwarded from a local message store to a component that saves and delivers them if possible. If delivery is not possible with the requested transport provider, this component either forwards messages to another transport provider or holds onto them until the requested transport provider is available. With MAPI, the MAPI spooler performs the store-and-forward function.

subscription

See registration.


 T

table

A MAPI object that provides access to data in row and column format and that supports the IMAPITable interface. MAPI table columns always refer to specific properties of a row. The values of table rows and columns vary depending on the type of table. See also attachment table, contents table, custom recipient table, display table, hierarchy table, message service table, message stores table, profile table, provider table, recipient table, status table.

Telephony Application Programming Interface

(TAPI) A set of functions that allows applications to use telephone lines for transporting data across a network without requiring information on details of how the transport process works.

template

A dialog box that is used for creating custom recipients.

template identifier

An entry identifier for a recipient that is managed by an address book provider that is not part of the current profile.

tightly coupled

Describes a relationship between a message store provider and transport provider that enables messages to be passed directly between the two, bypassing the MAPI spooler.

TNEF

See Transport-Neutral Encapsulation Format.

transmittable property

An X.400 property that is sent with the message of which it is a part. An attachment is an example of a transmittable message properties. See also nontransmittable property.

Transport-Neutral Encapsulation Format

(TNEF) A standard method defined by MAPI of passing message text and binary data. The method involves wrapping unsupported MAPI properties in a binary attachment file that accompanies a message through the transport process and decoding the file on the receiving side to reconstitute the MAPI properties.

transport provider

A service provider that carries messages, resolving MAPI addresses to the format used by the messaging system that delivers the messages.


 U

unresolved recipient

A messaging user or distribution list that has not been assigned an entry identifier and an address for a particular messaging system. See also name resolution, resolved recipient.


 V

view

A MAPI table object that presents a particular way of looking at data in a table, such as a subset of data based on a particular sort order. Some applications enable views to be saved.

view context

A MAPI object implemented by a client application that can act as a form viewer. The view context object is used to handle form commands such as Next, Previous, and Delete.


 W

wastebasket

See Deleted Items folder.

Windows Messaging System

(WMS) The MAPI subsystem that is part of the Microsoft Windows 95 operating system.


 X

X.400

An international message-handling standard for connecting e-mail networks and for connecting users to e-mail networks. X.400 is published by the X.400 Application Programming Interface Association (XAPIA). MAPI applications are fully interoperable with X.400 messaging applications.

X.435

An international message-handling standard that is published by the International Telegraph and Telephone Consultative Committee (CCITT) standards body, now called the International Telecommunications Union (ITU), and that implements the Electronic Document Integration (EDI) standard for integrating data with various native formats into a message.

X.500

An international message-handling standard for directory services, published by the International Telegraph and Telephone Consultative Committee (CCITT) standards body, now called the Internal Telecommunications Union (ITU).

XAPIA

The X.400 Application Programming Interface Association, the standards-setting body for X.400 communications.


 Legal Notice

Information in this document is subject to change without notice. Companies, names, and data used in examples herein are fictitious unless otherwise noted. No part of this document may be reproduced or transmitted in any form or by any means, electronic or mechanical, for any purpose, without the express written permission of Microsoft Corporation.

Microsoft may have patents or pending patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in this document. The furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other intellectual property rights except as expressly provided in any written license agreement from Microsoft.

© 1995 Microsoft Corporation. All rights reserved.

Microsoft, Microsoft Press, Windows, and Win32 are registered trademarks, and Visual C++ and Windows NT are trademarks of Microsoft Corporation.

U.S. Patent No. 4974159

Macintosh is a registered trademark of Apple Computer, Inc.


 About This Book

The Client Extension Programmer's Guide, which accompanies the Microsoft Win32® Software Development Kit (SDK), provides information about adding functionality to the Microsoft Exchange client program.

This book should be used in conjunction with the Messaging Application Programming Interface (MAPI) Programmer's Reference, Volumes 1 and 2 and the MAPI Programmer's Guide to customize the user interface of the Microsoft Exchange client.

The Microsoft Win32 SDK contains the tools and documentation you need to develop 32-bit applications for the Microsoft Windows®, Microsoft Windows for Workgroups, and Microsoft Windows NT™ family of operating systems. The Win32 SDK also includes the Windows NT Device Driver Kit, which contains the tools, documentation, and sample source you need to write a driver for Windows NT.


 Intended Audience

To develop applications for the Microsoft Exchange client environment, your background should include:

•	Familiarity with basic features and capabilities of Microsoft Exchange clients.

•	Proficiency  with C or C++ programming in the Windows environment.

•	Strong familiarity with MAPI. Reviewing the MAPI Programmer's Guide when you begin application development is highly recommended.

•	Familiarity with network environments.


 How This Book Is Organized

This book's contents are organized as follows:

•	Chapter 1, "About Client Extensions," introduces the four major categories of client extensions and gives examples of their use. It also discusses the four corresponding extension objects and the interfaces they implement. Finally, the chapter explains the mechanism Microsoft Exchange uses to activate client extensions on both 16-bit and 32-bit platforms.

•	Chapter 2, "Creating Client Extensions" provides information about creating the various extension types. It also discusses other programming considerations such as error handling, registering extensions, and optimizing performance.

•	Chapter 3, "Interfaces for Extending the Microsoft Exchange Client," consists of an alphabetical listing of all interfaces that developers can implement for creating extensions to the Microsoft Exchange client.


 How Interface Reference Entries Are Structured

The documentation for each interface consists of an introductory section that includes a brief description of the interface's purpose followed by an "At a Glance" table, which contains the following information:

Specified in header file:	The header file where the interface is defined and that must be included when you compile your source code.
Object that supplies this interface:	The object implementing the interface.
Corresponding pointer type:	The pointer type for the object implementing the interface.
Implemented by:	The application or component that must provide an implementation of this interface for other applications to call.
Called by:	The applications that typically call the methods of this interface.
Following the "At a Glance" table is a table that lists all the methods of this interface in vtable order. A vtable is an array of function pointers created by the compiler containing one function pointer for each method of a Microsoft Exchange object. The methods are listed in the same order that they are declared. Methods derived from other interfaces are not shown in the "Vtable Order" table but can be used in the same way as documented in the interface that defines them.

Following the "Vtable Order" table, the interface's methods are then listed in alphabetical order. For each method, the documentation includes a brief purpose statement for the method followed by this information:

Heading	Content
Syntax	The syntax for the method.
Parameters	A description of each parameter of the method.
Return Values	A description of each value that the method can return.
Comments	A description of why and how the method is used.
See Also	Cross-references to other topics in the Client Extension Programmer's Guide that can help you use this method.


 Document Conventions

The following typographical conventions are used throughout this book:

Typographical Convention	Meaning
Bold	Indicates an interface, method, structure, or other keyword in the Client Extension interfaces, MAPI, Microsoft Windows, the OLE application programming interface, C, or C++. For example, OnSubmit is a Client Extension method. Within discussions of syntax, bold type indicates that the text must be entered exactly as shown.
italic	Indicates placeholders, most often method or function parameters; these placeholders stand for information that must be supplied by the implementation or the user. For example, lpeecb is a Client Extension method parameter. In addition, italics are used to highlight the first use of terms and to emphasize meaning.
UPPERCASE	Indicates flags, return values, and properties. For example, EEAC_INCLUDESUBFOLDERS is a flag, S_OK is a return value, and PR_DISPLAY_NAME is a property. In addition, uppercase letters indicate filenames, segment names, registers, and terms used at the operating-system command level.
monospace	Indicates source code, structure syntax, examples, user input, and program output. For example: ptbl->SortTable(pSort, TBL_BATCH);
SMALL CAPITALS	Indicate the names of keys on the keyboard. When you see a plus sign ( + ) between two key names, you should hold down the first key while pressing the second. For example, CTRL + ALT + DEL. The carriage return key, sometimes marked as a bent arrow on the keyboard, is called ENTER.
Note  The interface syntax in this book follows the variable-naming convention known as Hungarian notation, invented by the programmer Charles Simonyi. Variables are prefixed with lowercase letters that indicate their data type. For example, lpszProfileName is a long pointer to a zero-terminated string name ProfileName. For more information about Hungarian notation, see Programming Windows by Charles Petzold.


 For More Information

For information on MAPI, see the MAPI Programmer's Guide and MAPI Programmer's Reference, Volumes 1 and 2, both contained within the MAPI SDK. The MAPI Programmer's Guide provides a conceptual overview of the MAPI architecture and describes a wide range of programming tasks illustrated with extensible and reusable sample code. The MAPI Programmer's Reference, Volume 1 provides a complete reference to the interfaces and methods used with Extended MAPI objects. Volume 2 provides a complete reference to Extended MAPI functions, macros, structures, data types, properties, and return values and to the Simple MAPI and CMC programming models. It also includes a glossary of MAPI terms.

For more information about OLE programming, see Inside OLE, Second Edition, by Kraig Brockschmidt (Redmond, WA: Microsoft Press®, August 1995) and OLE Programmer's Reference, Volume One and Volume Two (Redmond, WA: Microsoft Press, 1995), and the Microsoft Win32 SDK, published on CD-ROM by the Microsoft Developer Network (MSDN) and by Microsoft Visual C++™.

For more information about the Microsoft Windows programming environment, see the Microsoft Windows SDK for Microsoft Windows, Version 3.1. Another good source is Programming Windows by Charles Petzold (Redmond, WA: Microsoft Press, 1990).


About Client Extensions
For more information about Windows 95 programming, see the Microsoft Windows 95 SDK.

For more information about Windows NT programming, see the Microsoft Windows NT SDK.

 About Client Extensions

Using the Client Extension Programmer's Guide, it is possible to develop a wide variety of custom client applications that access Microsoft Exchange services such as the information store. These custom client applications can provide different views of data in the information store, data searching and sorting capabilities, security, custom mail or messaging features, forms, workgroup capabilities, and many other capabilities. This chapter provides an overview of some of the programs it is possible to develop with the Client Extension Programmer's Guide.


 Advantages of Extending Microsoft Exchange

Before developing a completely custom client application, you might want to consider extending the Microsoft Exchange client application. Microsoft Exchange provides a large number of features that enable users to view, search and sort information in the information store. It also provides a development platform for electronic mail, messaging, and workgroup applications that can handle a broad spectrum of information sharing tasks.

Instead of recreating features that are already provided in Microsoft Exchange, you can leverage the existing features and user interface of Microsoft Exchange and add your own custom features (also known as "extensions"). You can even override the default behavior of almost any feature of Microsoft Exchange. This can save a considerable amount of development effort that would otherwise be devoted to creating a custom user interface and custom features.

Additionally, extending the Microsoft Exchange client benefits users by integrating capabilities from many different ISVs into a single user interface, rather than having multiple interfaces through which users accomplish their information sharing tasks.

Microsoft Exchange client extensions can run on any platform that is running the Microsoft Exchange client. This includes Windows 3.1, Windows for Workgroups 3.1, Windows NT, and Windows 95. Since the Microsoft Exchange client is included with Windows 95, any extension you develop can run on any computer running Windows 95—it is not necessary for the user to purchase a separate product to use your extension on Windows 95.


 Extension Possibilities

There are many possible extensions that you can program to work with Microsoft Exchange. These extensions generally fall into four categories, as shown in the following table.

Extension Type	Description
Command extensions	Add new commands to the client's menus and toolbar, or replace the behavior of existing commands and toolbar buttons. For example, you can add commands that are specific to certain folders or selected message types.
Event extensions	Invoke custom behavior to handle events such as the arrival of new messages, reading and writing messages, sending messages, reading and writing attached files and selection changes in a window.
Property sheet extensions	Add custom property sheet pages to an object's properties dialog box, enabling users or administrators to view or edit custom message properties.
Advanced criteria extensions	Implement your own custom advanced criteria dialog boxes to be used when searching for messages in the information store. This is useful when you want to enable users to search for custom message properties.
Each of these extension types is described in greater detail in the following sections.


 Command Extension Examples

Commands that invoke virtually any type of custom behavior can be added to the menus and toolbars of Microsoft Exchange. For example:

•	Integrated proofing tools.  Custom spelling and grammar tools can be added to the Microsoft Exchange menu. If a user has composed a message, choosing a custom Spelling or Grammar command could invoke an ISV-supplied spell-checker or grammar-checker. It is also possible to add a thesaurus, text formatting tools, and other functionality provided by many word processors.

•	Public folder commands.  When a specific public folder has the focus, menu items or toolbar buttons can be enabled that are specific to that folder. For example, if the public folder is associated with an on-line service, you might want to include a Retrieve Latest command that prompts the on-line service to download the most current information into the selected topic area of the public folder.

•	Message class commands.  When messages of a specific class are selected, new application behavior can be added to handle messages of that class in a specific way. For example, you might want to replace the default behavior of the Microsoft Exchange Delete command when a message of a specific class is selected. The new behavior might simply move the message into a certain folder where it is processed at a later time.


 Event Extension Examples

Event extensions enable developers to add or override behavior associated with certain events that occur within Microsoft Exchange. For example:

•	Attachment virus detection.  You can write an extension that transparently scans message attachments for viruses. When a message is received in a user's Inbox, the "message received" event would trigger the virus detection program and the user could be prompted to take action if a virus was found. This is especially useful in environments where users routinely attach executable programs to messages.

•	Message and attachment compression.  You can write an extension that compresses and decompresses messages when certain messaging events are detected. This can be especially useful in an environment where large messages, such as attached documents containing bitmaps, are routinely sent.


 Property Sheet Extension Examples

Property sheet extensions are useful for displaying custom properties for messages of a particular message class or for adding your own Microsoft Exchange options. For Example:

•	Custom form property sheets.  If your application provides a custom form with custom properties, you can display those properties in one or more property sheet pages. For example, the property sheet of a custom routing form might display the name of the person who initiated the routing process or the routing path of the form.

•	Custom document property sheets.  Your application can supply a custom property sheet that is displayed for certain types of documents. For example, if your extension provides a document archiving system, you might want to provide a property sheet that enables users to select archiving options for documents.


 Advanced Criteria Extension Example

Advanced criteria extensions enable you to create your own advanced criteria dialog box that can be used to provide custom search capabilities. For example:

•	Custom property searching.  You can display a custom advanced criteria dialog box that enables users to specify search criteria for custom properties. For example, in a public folder that receives custom messages from an on-line service, there might be custom properties such as "Company" or "Industry" that are defined for each of the messages. With a custom search dialog box, you can supply criteria fields for these custom properties that enable users to perform custom searches. For instance, a user could search for all messages with an Industry property equal to "Biomedical."


 Modal and Modeless Extension Windows

You can create extensions that use modal or modeless windows. When a modal window is displayed, users can only interact with the extension and not with Microsoft Exchange. For example, an extension might display a modal Folder Backup dialog box that enables a user to choose a specific folder to back up.

In contrast, some extensions can run modelessly, displaying windows that allow the user to switch their input back and forth between Microsoft Exchange windows and the extension's windows. For example, a Stock Quote extension could display a modeless window that displays dynamically changing stock data while the user interacts with Microsoft Exchange windows.

For simplicity, an extension that displays only modal windows is referred to as a modal extension while an extension that displays at least one modeless window is referred to as a modeless extension.

Some extensions can involve a combination of modeless and modal windows; that is, modeless extensions might display modal windows at certain times. For example, the Stock Quote extension mentioned previously might display a modal Options dialog box.

When writing modeless extensions, it is important to coordinate the actions of your extension's windows with the windows of Microsoft Exchange. For example, if Microsoft Exchange displays a modal window, modeless extensions should disable their windows. Interfaces that enable this cooperation are implemented by Microsoft Exchange and extensions.


 Extension Interfaces and Contexts

To implement any of the extension types supported by Microsoft Exchange, you create a single dynamic link library (DLL) that contains one or more extension objects. An extension object is an object that complies with the Microsoft Windows Component Object Model and implements a set of Microsoft Exchange extensibility interfaces. Each extension type has more than one interface associated with it, but some of these interfaces are optional, as the following table shows.

Extension Type	Interfaces To Implement
Command extensions	IExchExt (required). IExchExtCommands (required). IExchExtEvents (optional). Implement if your command extension's enablement depends on the current selection or a change in the current object such as a folder, store, or message.
Event extensions	IExchExt (required). IExchExtEvents (optional). Implement if your extension should respond when the object being displayed in a window changes, or when the selection within the window changes. IExchExtSessionEvents (optional). Implement if you want to customize the behavior when new messages are delivered. IExchExtUserEvents (optional). Implement if you want to handle changes to the currently-selected list box item, text, or object. IExchExtMessageEvents (optional). Implement if you want to customize the way Microsoft Exchange manipulates messages. IExchExtAttachedFileEvents (optional). Implement if you want to customize the handling of message file attachments.
Property sheet extensions	IExchExt (required). IExchExtPropertySheets (required).
Advanced criteria extensions	IExchExt (required). IExchExtAdvancedCriteria (required).
If you implement an interface, you must implement all of its methods, even if your extension does not use them. For those methods that your extension doesn't use, a default response can usually be implemented with little effort. All extension objects need to implement the IExchExt : IUnknown interface.

The interaction between Microsoft Exchange and an extension object is bidirectional and involves more than simply calling an extension object's methods. To operate correctly, extension objects must gather information about the version of Microsoft Exchange, the MAPI session, and menu, toolbar and window handles. In most cases, they must also retrieve information from Microsoft Exchange about which objects, such as messages and folders, are currently selected within Microsoft Exchange windows. Retrieving this information is achieved with the IExchExtCallback : IUnknown interface, which is passed to many extension object methods.

Before implementing interfaces within an extension object, it is important to know which contexts the extension object will be associated with. A context is usually associated with a particular window within the Microsoft Exchange client. Most extension objects are designed to operate only within a particular context or set of contexts, but some can operate in all contexts. The following contexts are defined within the Microsoft Exchange client:

Context	Window
EECONTEXT_TASK	The duration of the Microsoft Exchange task, from program start to program exit. This may span several logons. This context does not correspond to a Microsoft Exchange window.
EECONTEXT_SESSION	The duration of a Microsoft Exchange session from logon to logoff. Multiple logons can occur during a single execution of Microsoft Exchange, but they might not overlap. This context does not correspond to a Microsoft Exchange window.
EECONTEXT_VIEWER	The main Viewer window that displays the folder hierarchy in the left pane and folder contents in the right pane.
EECONTEXT_REMOTEVIEWER	The Remote Mail window that is displayed when the user chooses the Remote Mail command.
EECONTEXT_SEARCHVIEWER	The Find window that is displayed when the user chooses the Find command.
EECONTEXT_ADDRBOOK	The Address Book window that is displayed when the user chooses the Address Book command.
EECONTEXT_SENDNOTEMESSAGE	The standard Compose Note window in which messages of class IPM.Note are composed.
EECONTEXT_READNOTEMESSAGE	The standard read note window in which messages of class IPM.Note are read after they are received.
EECONTEXT_READREPORTMESSAGE	The read report message window in which report messages (Read, Delivery, Non-Read, Non-Delivery) are read after they are received.
EECONTEXT_SENDRESENDMESSAGE	The send resend message window that is displayed when the user chooses the Send Again command on the non-delivery report.
EECONTEXT_SENDPOSTMESSAGE	The standard posting window in which existing posting messages are composed.
EECONTEXT_READPOSTMESSAGE	The standard posting window in which existing posting messages are read.
EECONTEXT_PROPERTYSHEETS	A property sheet window.
EECONTEXT_ADVANCEDCRITERIA	The dialog box in which the user specifies advanced search criteria.
Extensions register their "interest" in one or more of these contexts by placing entries in the EXCHNG.INI file on 16-bit versions of Microsoft Windows or in the registry on Windows NT. When an extension registers for a context, it means that events associated with this context will cause the extension to be notified of the event. For example, if an extension registers for the EECONTEXT_VIEWER context, and the user selects an object in the Viewer window, the extension will be called by Microsoft Exchange to notify it of the event.

If an extension does not register interest in specific contexts, it will be loaded and prompted to install itself in all contexts. Since loading extensions may reduce the performance of the Microsoft Exchange client, it is strongly recommended that all extensions specifically include context information as part of their registration.

Note  If the standard compose note or post note form in the Microsoft Exchange Viewer window has been replaced by a custom form, extensions that are normally called from the standard compose note and post note windows will not be called unless the replacement IPM.Note form supports extensibility. This means that the form must do all the same work that the Microsoft Exchange client does when activating a form unless the implementor of this custom form explicitly implements this functionality.


 How Extensions Work

When Microsoft Exchange is started, it reads its .INI file (on 16-bit versions of Windows) or the registry database (on Windows NT) and activates all the extensions that have registered to participate within the EECONTEXT_TASK context. Extensions that participate in other contexts are activated on-demand when those contexts become current.

After Microsoft Exchange and its initial extensions have been loaded into memory, the interaction between Microsoft Exchange and its extensions is determined mostly by the user's interaction with Microsoft Exchange, but it can also be determined by events such as the arrival of a new message. The following steps give an overview of how Microsoft Exchange interacts with its installed extensions:

1.	A context activation occurs.

2.	In the order in which they are listed in the .INI file or registry, Microsoft Exchange invokes the IExchExt::Install method on each extension object that has registered to participate in the new context. One of the parameters passed to each extension through Install is a pointer to a callback object that supports the IExchExtCallback : IUnknown interface.

3.	Each extension that was called in step 2 uses IExchExtCallback to retrieve information about the environment, including the active menu, the active toolbar, the number of objects selected in the current window, and the entry identifier of the selected item. Extensions can also use MAPI and Windows API functions to retrieve information. Extensions use this information to determine if they will participate in the new context.

4.	If an extension determines that it will participate in the context, it will return S_OK from IExchExt::Install. For example, an extension might need to participate in a context only if a certain folder is open. Otherwise, it returns S_FALSE.

5.	In the order in which they are listed in the .INI file or registry, Microsoft Exchange invokes appropriate methods on all extensions that returned S_OK. The methods that are invoked depend on the context. For example, if the context is EECONTEXT_SENDNOTEMESSAGE, Microsoft Exchange first invokes the IExchExtCommands::InstallCommands method on all extensions that are registered to participate in this context and which implement the IExchExtCommands : IUnknown interface. Extensions can then add menu items to an existing menu and enable or disable them using Windows API calls.


 Context Lifetimes

Some contexts last only a short time while others can exist for the entire time that Microsoft Exchange is running. For example, the EECONTEXT_TASK context exists all the time after Microsoft Exchange has logged on because this context refers to the running Microsoft Exchange client application. In contrast, the EECONTEXT_SEARCHVIEWER context exists only while the Find dialog box is displayed.

An extension is loaded into memory the first time a context for which it is registered is created. Once an extension is loaded into memory, it remains in memory for the lifetime of Microsoft Exchange. For example, consider three extensions E1, E2, and E3. If E1 and E2 are both registered for EECONTEXT_SESSION and E3 is registered for EECONTEXT_ADDRBOOK, then E1 and E2 will be loaded when Microsoft Exchange logs on, but E3 will not be loaded until the Address Book is opened. After the Address Book is opened, all three extensions will remain loaded until Microsoft Exchange is closed.

More than one context can exist at the same time. For example, EECONTEXT_VIEWER and EECONTEXT_ADDRBOOK exist simultaneously when the Viewer and the Address Book are active. Additionally, more than one instance of the same context can be active at one time, such as when two Find windows are open or two Compose Note windows are open. In these cases, two instances of the same context are active. When a context is destroyed, all extensions that are instantiated in that context are released but the extension DLLs remain in memory.


 Context Interface Mappings

The following table shows which of the event interfaces can be called in each of the Microsoft Exchange contexts. In addition to these, the required interface IExchExt : IUnknown is called in all contexts.

Context	Interfaces
EECONTEXT_TASK	None. Only IExchExt::Install and IUnknown::Release are called from this context.
EECONTEXT_SESSION	IExchExtSessionEvents
EECONTEXT_VIEWER, EECONTEXT_REMOTEVIEWER, EECONTEXT_SEARCHVIEWER	IExchExtCommands, IExchExtUserEvents, IExchExtPropertySheets
EECONTEXT_ADDRBOOK	IExchExtCommands, IExchExtUserEvents, IExchExtPropertySheets
EECONTEXT_SENDNOTEMESSAGE, EECONTEXT_READNOTEMESSAGE, EECONTEXT_READREPORTMESSAGE, EECONTEXT_SENDRESENDMESSAGE, EECONTEXT_READPOSTMESSAGE, EECONTEXT_SENDPOSTMESSAGE	IExchExtCommands, IExchExtUserEvents, IExchExtMessageEvents, IExchExtAttachedFileEvents, IExchExtPropertySheets
EECONTEXT_PROPERTYSHEETS	IExchExtPropertySheets
EECONTEXT_ADVANCEDCRITERIA	IExchExtAdvancedCriteria


 Creating Client Extensions

As described in the previous chapter, Microsoft Exchange client extensions can be grouped into four categories:

•	Command extensions

•	Event extensions

•	Property sheet extensions

•	Advanced criteria extensions

You can also develop multi-purpose extensions that span two or more of these categories. For example, you can develop an extension that adds menus to the Microsoft Exchange Viewer window and also provides custom property sheets.

This chapter provides detailed information on how Microsoft Exchange interacts with the major categories of extensions shown in the preceding list. Information is also provided on how to write modeless extensions, how to register extensions within the EXCHEXT.INI file or the registry, and how to optimize performance.

Note  For sample code illustrating some of the concepts covered in this chapter, see the Win32 SDK.


 Command Extensions

Command extensions add new commands to the menus or toolbar of the Microsoft Exchange client or replace the behavior of existing menus and toolbar buttons. Consider an extension that adds a new command to the menu bar of the standard send form. To install this new command on the menu bar and handle a user's interaction with it, the extension object implements the IExchExt : IUnknown and IExchExtCommands : IUnknown interfaces.

The sequence of events that should occur when Microsoft Exchange interacts with your extension object to add new commands to the menu bar or new toolbar buttons in the EECONTEXT_SENDNOTEMESSAGE context are as follows:

1.	When the standard send form is activated (but before it is displayed), Microsoft Exchange calls the IExchExt::Install method on all extensions registered to participate in that context and passes each extension a pointer to an IExchExtCallback interface along with the active context, which in this case is EECONTEXT_SENDNOTEMESSAGE.

2.	All extensions that are registered to participate in the EECONTEXT_SENDNOTEMESSAGE context and have determined that they will participate return S_OK to Microsoft Exchange.

3.	After the New Message window is created, Microsoft Exchange invokes the IExchExtCommands::InstallCommands method on all extension objects that returned S_OK to IExchExt::Install. These extension objects then add their menu commands or toolbar buttons to the New Message window using Windows API calls for adding menu commands and toolbar buttons. After the commands and buttons are added, Microsoft Exchange displays the New Message window, and the new commands are available to the user.

4.	As the user interacts with the New Message window, Microsoft Exchange will frequently receive WM_INITMENU messages. Each time this happens, Microsoft Exchange calls the IExchExtCommands::InitMenu method for each extension giving the extension the opportunity to enable, disable, or update its menu items before they are seen by the user. Microsoft Exchange then calls the IExchExtCommands::QueryButtonInfo method for both standard Microsoft Exchange toolbar buttons and any buttons installed by extensions.

5.	When the user chooses a menu command or a toolbar button, the window receives a WM_COMMAND message with the command identifier of the menu item or toolbar button that was selected. Microsoft Exchange sequentially calls the IExchExtCommands::DoCommand method on all extensions that have registered for that context and have implemented the IExchExtCommands : IUnknown interface, passing the command identifier as an argument. Even native Microsoft Exchange commands are passed to the extensions, enabling them to replace or enhance these native commands. When an extension is called, it examines the command identifier and determines if it should handle that command. If an extension isn't programmed to handle the command identifier, it should return S_FALSE, and Microsoft Exchange will pass the command identifier to the next extension. If an extension is programmed to handle the command, it should return S_OK. In most cases, extensions will only handle commands that they added to the menu or toolbar with the IExchExtCommands::InstallCommands method. If no extension handles the command, Microsoft Exchange will handle the command if it recognizes it. If Microsoft Exchange does not recognize a command, it is ignored.

The following table provides a summary of the interaction between a user, Microsoft Exchange and an extension object following a series of user actions performed by a user with a custom command. It also shows which component — Microsoft Exchange or the client extension — performs the step and in the case of the client extension, what method is invoked.

User	Microsoft Exchange	Extension
		InstallCommands returns S_OK
		QueryButtonInfo
Selects menu command
	Receives WM_INITMENU message
		InitMenu
Chooses command
	Receives WM_COMMAND message
		DoCommand returns S_OK
For more information on the IExchExtCommands : IUnknown and IExchExt :IUnknown interfaces, see Chapter 3, "Interfaces for Extending the Microsoft Exchange Client."

You can install commands on the Microsoft Exchange system menu using the same general process as described in the section "Command Extensions," but instead of using the Windows GetMenu function, you'll use GetSystemMenu. Once a custom command is installed, Microsoft Exchange passes the command identifier of the system menu command to the extension when the user chooses that command. Handling system commands enables an extension to override default Microsoft Exchange behavior. For example, you might want your extension to override the system menu's Close command and perform a few "housecleaning" operations before terminating the application.

It is also possible to specify menu accelerators that can be used with menu items. These menu accelerators can be invoked by users in the usual way by pressing Alt plus the access key of the menu or command.

Note  In accordance with standard user interface conventions, the Services and Options commands on the Microsoft Exchange Tools menu should remain at the bottom of the menu. If your extension adds commands to the Tools menu, it should add them above the Microsoft Exchange Services and Options commands.


 Event Extensions

An event extension is an extension that enables you to customize the handling of various events such as new message delivery, reading messages, sending messages, reading and writing attached files, and tracking object selection changes. Extensions that handle events can be installed in the following contexts:

Window	Context
Main Viewer window	EECONTEXT_VIEWER
Remote Mail window	EECONTEXT_REMOTEVIEWER
Find window	EECONTEXT_SEARCHVIEWER
Address Book window	EECONTEXT_ADDRBOOK
Session context	EECONTEXT_SESSION
Additionally, user events (such as an object selection in a container) occur in the various message windows.

Four categories of events are defined. These events, which are described in the following sections, are passed to Microsoft Exchange when they occur.


 User Events

When a Microsoft Exchange user changes the selection within a window or changes which object's contents are being displayed in a window, a user event is sent to Microsoft Exchange extensions. Within the main Viewer window, the selection can be a message store, a folder, or a message. Within the Find window or the Remote Mail window, the selection is always a message. Within the Address Book, it is an address entry.

Extensions that need to be notified whenever a selection or object changes must implement the IExchExtUserEvents : IUnknown interface. This interface includes two methods: IExchExtUserEvents::OnSelectionChange and IExchExtUserEvents::OnObjectChange. Whenever a selection or object changes, Microsoft Exchange calls these methods on all extensions that were installed for that context.

The two IExchExtUserEvents methods do nothing more than pass the extension a pointer to the IExchExtCallBack : IUnknown interface, which provides information about the current selection. Using this information, the extension can then act appropriately. For example, it can enable or disable a toolbar button.


 Session Events

When a new message arrives in a user's mailbox, a session event is sent to Microsoft Exchange. Extensions can be notified when a new message arrives by installing themselves in the EECONTEXT_SESSION context and by implementing the IExchExtSessionEvents : IUnknown interface, which supports only one method: IExchExtSessionEvents::OnDelivery. Whenever a session event occurs, Microsoft Exchange calls this method on all extensions that are registered to handle these events.

OnDelivery passes a pointer to the IExchExtCallBack : IUnknown interface to the extension, which uses the pointer to obtain details about the current context. The extension returns S_OK from OnDelivery if it will handle the event. For example, an extension might use the IExchExtCallBack pointer to determine the class of the newly arrived message. If the message class is of a specific type, the extension might want to perform a custom operation on that message, such as extracting its properties and storing them in a database.

Note  IExchExtSessionEvents::OnDelivery is called after the server has processed the rules attached to the folder. Therefore, OnDelivery cannot be called if it was previously handled. Because this is a server process, rules processing is done regardless of any ordering specified in the EXCHNG.INI file or the registry.


 Message Events

Microsoft Exchange enables extensions to control various details of how a message is handled when certain events occur. This is done with the IExchExtMessageEvents : IUnknown interface, which allows extensions to intercept message events:

•	Immediately before and immediately after a message's properties are read. For example, when an extension displays a message in a form.

•	Immediately before and immediately after a message's properties are written to the message store.

•	Immediately before and immediately after Microsoft Exchange resolves unresolved addresses. For example, when a user chooses the Check Names button.

•	Immediately before and immediately after Microsoft Exchange submits an open message for delivery.

For example, an extension might want to check spelling or validate data before it is written to the properties of the message in the store and sent to another user.

Each one of the events in the preceeding list is associated with a method that is a member of IExchExtMessageEvents. For example, the IExchExtMessageEvents::OnWrite method is invoked whenever Microsoft Exchange is about to save the message properties.


 Attachment Events

Attachment events occur when an attached file is being read, written, or opened. These events enable extensions to control access to attachments and provide custom handling behavior. Attachment extensions are useful for providing virus detection and compression of attached files. These extensions are called from the context of the message containing the attachment.

Note  Not all attachments are files. Attachment events apply only to attached files. Because attachments can themselves be other messages (that is, messages can contain messages), another context corresponding to the attached message might be created when an attached message is opened.

Sending a Note with an Attachment

The following table shows the steps involved in sending a standard message with an attachment. It also shows which component — Microsoft Exchange or the client extension — performs the step and in the case of the client extension, what method is invoked.

User	Microsoft Exchange	Extension
Chooses New Message from the Compose menu
	Receives WM_COMMAND message, calls command extensions, and creates SENDNOTEMESSAGE context
		Install(SENDNOTEMESSAGE) returns S_OK
	Installs command extensions
Types recipient, subject, and body text. Drags file attachment to main body.
		OnReadPattFromSzFile
	Displays attached file in window
Chooses Send from the File menu
	Receives WM_COMMAND message, calls command extensions, and handles command itself
		OnCheckNames
		OnCheckNamesComplete
		OnSubmit
		OnWrite
		OnWriteComplete
		OnSubmitComplete
	Closes send window
		Release on extension objects
	Destroys SENDNOTEMESSAGE context
Reading a Message and Opening its Attachment

The following table shows the steps involved in reading a message and opening its attachment. It also shows which component — Microsoft Exchange or the client extension — performs the step and in the case of the client extension, what method is invoked.

User	Microsoft Exchange	Extension
Chooses Open from the File menu after selecting a message
	Receives WM_COMMAND message, calls command extensions, and creates READNOTEMESSAGE context
		OnRead
		OnReadComplete
	Installs command extensions
	Displays read note
Double clicks on file attachment
		QueryDisallowOpenPatt returns S_OK
		OnWritePattToSzFile
		OpenSzFile
	Opens file
Changes, saves and closes file
Chooses Close from the File menu
	Receives WM_COMMAND message, calls command extensions
Chooses Yes in the Save dialog box
		OnWrite
		OnReadPattFromSzFile
		OnWriteComplete
	Closes read window
		Release on extension objects
	Destroys READNOTEMESSAGE context


 Property Sheet Extensions

Property sheet extensions enable you to add custom property sheet pages for information stores, folders, and messages. These pages can be added to property sheets that are displayed in a variety of contexts. For example, you can add a page to the folder property sheet that is displayed when a user chooses the Properties command from the File menu in the main Viewer window when a folder is selected.

Property sheet extensions are useful for displaying custom properties for messages of a particular message class or for adding your own Microsoft Exchange options. For example, if you wrote an application that created and managed a specific public folder, you could add a property sheet page that would enable users to set various application-specific properties for the folder.

The sequence of events that should occur when Microsoft Exchange interacts with your extension object to install and use custom property sheet pages is as follows:

1.	When the user opens a property sheet, Microsoft Exchange sequentially calls the IExchExt::Install method on all extensions registered to participate in the EECONTEXT_PROPERTYSHEETS context and passes each extension a pointer to an IExchExtCallback interface. These extensions, along with extensions that have registered for the context in which the property sheet is displayed will be called to add property sheet pages. For example, if a property sheet is displayed in the Viewer window, extensions registered for the EECONTEXT_PROPERTYSHEETS or EECONTEXT_VIEWER context will be called.

2.	Microsoft Exchange calls the IExchExtPropertySheets::GetMaxPageCount method on each extension that returned S_OK from Install. This enables Microsoft Exchange to allocate sufficient memory for the property sheet page array.

3.	When Microsoft Exchange is ready to build the property sheet, it calls the IExchExtPropertySheets::GetPages method so that the extension can specify a pointer to the pages it will append. GetPages is called immediately before the property sheet is displayed and enables the extension to fill in the pages it wants appended to the Microsoft Exchange Properties dialog box. The standard Microsoft Exchange pages are added first, followed by pages from each extension in the order the extensions are installed. GetPages uses the IExchExtCallback::GetObject method to retrieve the object for which the information should be displayed and the store which contains that object. The extension must use the standard property sheet structures specified by the Windows API. One of the parameters passed to the extension in GetPages is the type of property sheet being displayed — for example, message, folder, or store property sheet.

4.	When the user closes the property sheet, Microsoft Exchange calls the IExchExtPropertySheets::FreePages method which instructs the extension to free any resources associated with the property sheet pages that were specified in GetPages.

The following table summarizes the interaction between a user, Microsoft Exchange and an extension object when a custom property sheet is being added to the Microsoft Exchange client. It also shows which component — Microsoft Exchange or the client extension — performs the step and in the case of the client extension, what method is invoked. To simplify this table, the installation of command extensions is not included. Command extensions are called in the context of a user choosing the Properties command from the File menu.

User	Microsoft Exchange	Extension
Chooses Properties from the File menu
	Receives WM_COMMAND message, calls command extensions, and creates a PROPERTYSHEETS context
		For extensions registered for the PROPERTYSHEETS context, Install(PROPERTYSHEETS) is called
		GetMaxPageCount returns S_OK
	Allocates property sheet page array
		GetPages returns S_OK
	Displays dialog box
Chooses OK or Cancel button
	Closes dialog box
		FreePages
		Release on extensions which were loaded in the PROPERTYSHEETS context


 Advanced Criteria Extensions

Advanced criteria extensions enable you to create your own advanced criteria window that can be used when searching for messages. This is especially useful when you want to enable users to search for custom message properties.

Although several extensions that supply advanced criteria dialog boxes might be available, only one advanced criteria window at a time can be displayed from a single context. Multiple advanced criteria contexts can be active at the same time; for example, when more than one Find window is open. It is important to remember that extensions are called in the order in which they were installed.

Because multiple advanced criteria extensions might be installed, it is important to ensure that your advanced criteria extension follows a few guidelines. The primary guideline is to be as selective as possible before choosing to install extensions into an advanced criteria context. For instance, a public folder application should only choose to install its advanced criteria interface when its public folder is open or highlighted. Advanced criteria extensions that are more selective should be listed  ahead of more general ones in the EXCHNG.INI file or the registry. Because Microsoft Exchange itself uses very general advanced criteria, most extensions should register themselves before Microsoft Exchange. If two or more such general advanced criteria extensions are present, the first one installed will always be used. The ordering of extensions is determined by their entry order in the EXCHNG.INI file or in the registry. For more information on creating extension entries, see the "Registering Extensions" section later in this chapter.

The sequence of events that should occur when Microsoft Exchange interacts with your extension object to add a custom advanced criteria dialog box to the Microsoft Exchange client is as follows:

1.	When the user chooses the command that displays the Microsoft Exchange Find dialog box, Microsoft Exchange calls the IExchExt::Install method on all extension objects with the EECONTEXT_ADVANCEDCRITERIA bit set in the context map. During the call, it passes each extension a pointer to an IExchExtCallback interface along with the context, which in this case is EECONTEXT_ADVANCEDCRITERIA. The IExchExtCallBack pointer enables the extension to retrieve information about the current context. In this case, the current message store and folder will probably be useful.

2.	Microsoft Exchange calls the IExchExtAdvancedCriteria::InstallAdvancedCriteria method on the first extension to return S_OK from Install. Microsoft Exchange uses InstallAdvancedCriteria to pass information to the extension, including the window handle of the Find dialog box, the current advanced criteria restriction, and an array of folder entry identifiers to which the criteria will be applied. If the extension returns S_OK from InstallAdvancedCriteria, Microsoft Exchange will call the IExchExtAdvancedCriteria::DoDialog method when the user selects the Advanced button in the Find dialog box.

If S_FALSE is returned from InstallAdvancedCriteria, remaining extensions will be given the opportunity to examine the current search restriction and display a custom search dialog box. If no extension returns S_OK, Microsoft Exchange will display a default advanced criteria dialog box.

3.	If the user chooses the New Search button, changes folders, or closes the Find dialog box after Microsoft Exchange calls InstallAdvancedCriteria, Microsoft Exchange calls the IExchExtAdvancedCriteria::Clear, IExchExtAdvancedCriteria::SetFolders, or IExchExtAdvancedCriteria::QueryRestriction methods respectively to inform the extension of the changes.

4.	When the user closes the advanced criteria window, Microsoft Exchange calls the IExchExtAdvancedCriteria::UninstallAdvancedCriteria method, which allows the extension to free any resources associated with the advanced criteria window that it displayed.

The following table summarizes the interaction between a user, Microsoft Exchange and an extension object when using a custom advanced criteria dialog box. It also shows which component — Microsoft Exchange or the client extension — performs the step and in the case of the client extension, what method is invoked.

User	Microsoft Exchange	Extension
Chooses Find from the Tools menu
	Receives WM_COMMAND message, calls command extensions, and creates SEARCHVIEWER and ADVANCEDCRITERIA contexts
		Install(ADVANCEDCRITERIA) returns S_OK
	Installs command extensions
		InstallAdvancedCriteria returns S_OK
	Displays Find window
Chooses Folder in the Find dialog box
	Shows Choose Folder dialog box
Changes the folders to search in and chooses OK
	Closes Choose Folder dialog box
		SetFolders
Chooses New Search in the Find dialog box
		Clear
Chooses Advanced in the Find dialog box
		DoDialog
Specifies criteria and chooses OK
		returning S_OK from DoDialog
Chooses Find Now in the Find dialog box
		QueryRestriction
	Performs search
Closes Find dialog box
		UninstallAdvancedCriteria
	Closes Find window
		Release on extension object
	Destroys SEARCHVIEWER and ADVANCEDCRITERIA contexts


 Task and Session Extensions

In some cases, an extension needs to run when the user starts Microsoft Exchange or right after the user logs on. For example, an extension that integrates with a corporate database may want to establish a connection to the database as part of the logon process.

As shown in the following table, the client extension implements the TASK, SESSION, and VIEWER contexts with only the IExchExt : IUnknown interface using the IExchExt:Install method (and the IUnknown::Release method).

The following table summarizes the interaction between a user, Microsoft Exchange and an extension object when a user launches Microsoft Exchange or logs on to a MAPI session. It also shows which component — Microsoft Exchange or the client extension — performs the step and in the case of the client extension, what method is invoked.

User	Microsoft Exchange	Extension
Launches Microsoft Exchange
	Creates TASK context
		Install(TASK) returns S_OK
Logs on with profile and password
	Creates SESSION context
		Install(SESSION) returns S_OK
	Creates VIEWER context
		Install(VIEWER) returns S_OK
Chooses Exit and Logoff from the File menu
		Release on VIEWER object
	Destroys VIEWER context
		Release on SESSION object
	Destroys SESSION context
		Release on TASK object
	Destroys TASK context
	Shuts down application


 Writing Modeless Extensions

As mentioned previously in this chapter, extension windows can be either modal or modeless. When writing extensions that use modeless windows, it is a good idea to design your code to cooperate with Microsoft Exchange. The most common scenario for this cooperation is enabling or disabling modeless windows when the user switches between Microsoft Exchange windows and the windows of your extension.

Coordination between Microsoft Exchange and modeless extensions is achieved using two interfaces: IExchExtModeless : IUnknown and IExchExtModelessCallback : IUnknown. Microsoft Exchange implements IExchExtModelessCallback and client extensions implement IExchExtModeless.


 Initializing a Modeless Extension

A modeless extension must first indicate to Microsoft Exchange that it will be displaying modeless. This is done by calling the IExchExtCallback::RegisterModeless method. If an extension does not call this method, Microsoft Exchange assumes by default that the extension's window is displayed modally and the extension will not be able to coordinate its actions with those of Microsoft Exchange.

When calling RegisterModeless, the extension must pass to Microsoft Exchange a a modeless object that implements the IExchExtModeless interface. This interface enables Microsoft Exchange to communicate with the extension object about the state of its windows.


 How Modeless Coordination Works

When Microsoft Exchange runs, it creates a modeless callback object with which extensions can communicate. This callback object implements the IExchExtModelessCallback : IUnknown interface.

Before displaying a modal window, Microsoft Exchange invokes the IExchExtModeless::EnableModeless method on all modeless objects. In this case, the fEnable parameter of IExchExtModeless::EnableModeless is set to FALSE, indicating that the extension should disable its modeless windows. When Microsoft Exchange removes its modal window, it calls IExchExtModeless::EnableModeless with the fEnable parameter set to TRUE. The extension can then re-enable its modeless windows.

Similary, if a modeless extension needs to display a modal window, it should call the IExchExtModelessCallback::EnableModeless method with the fEnable parameter set to FALSE. Microsoft Exchange then disables its modeless windows. When the extension removes its modal window, it should call IExchExtModeless::EnableModeless with the fEnable parameter set to TRUE, enabling Microsoft Exchange to re-enable its modeless windows.


 Additional Programming Considerations

When creating extensions for the Microsoft Exchange client, there are a number of programming considerations you will want to keep in mind beyond the basic technique of implementing extension interfaces. These considerations generally fall into the following categories:

•	Performance

•	Error handling

•	Cooperation with other extensions


 Optimizing Performance

Because Microsoft Exchange polls installed extensions every time a context change occurs, Microsoft Exchange can exhibit decreased performance or response time if several extensions are installed. In particular, performance can be affected when displaying menus, sending and receiving messages, or selecting different messages and folders. This performance degradation can be caused by extensions that respond to events that are not applicable to the functionality they provide. It can also be caused by extensions that take a long time to respond when Microsoft Exchange invokes their methods.

When developing an extension, you can reduce the impact on the performance of Microsoft Exchange by keeping the following programming guidelines in mind:

•	Register your extension only for contexts that are applicable to it. This can be done by placing the appropriate values in the context map in the EXCHNG.INI file or the registry. The context map designates contexts in which an extension will participate. Although specifying a context map is optional, it is highly recommended. If you don't specify a context map, an attempt will be made to install your extension in all contexts and it will be loaded at all times. For more information about context maps, see the "Registering Extensions" section later in this chapter.

•	Register your extension only for interfaces that are applicable to it. This can be done by placing the appropriate values in the interface map in the EXCHNG.INI file or the registry. Although specifying an interface map is optional, it is highly recommended. The interface map prevents Microsoft Exchange from making calls to IUnknown::QueryInterface for interfaces that are not supported. This can improve the performance of context creation and application startup.

•	Optimize the efficiency of functions that handle various events received by your extension. For example, event-handling functions should minimize the use of any time-consuming calculations, loops, lookups, and file input and output.

•	Keep the memory footprint of your extensions to a minimum because once loaded, it remains loaded until Microsoft Exchange is closed. To keep your memory footprint small, you might want to split your extension DLL into two separate DLLs. The first DLL should be a handler that handles most of the extension interaction, especially the default responses that ignore unwanted events. The second DLL should be activated when "real" work must be done, such as executing a custom command. This is especially important for large extensions that are infrequently used.


 Handling Errors

Extensions are responsible for handling and displaying their own errors. Microsoft Exchange handles error return values by not continuing with the current operation. Microsoft Exchange does not display error messages because the extension is usually better aware of what caused the error and what steps should be taken to correct it.


 Cooperating with other Extensions

Because extensions that you distribute to customers might be installed alongside extensions developed by other programmers, it is important to design your extensions so they cooperate with other extensions. Cooperation among extensions is important because the order in which extensions are listed in the EXCHNG.INI file or the registry determines the order in which extensions are called to respond to context changes in Microsoft Exchange. Because extensions are called sequentially, extensions that are not designed to operate cooperatively can "block" the execution of other extensions.

For example, suppose a user double clicks on a folder to display its messages. When this happens, Microsoft Exchange will call each extension to determine if it wants to participate in the event. If a "misbehaved" extension handles the event without being selective about the context in which it has been installed, it will block the execution of other extensions that fall after it in the calling sequence. One of these other extensions might be programmed specifically to handle that event, but it will not be given a chance.

To avoid blocking other extensions, your extension should be highly selective in determining when it runs. When Microsoft Exchange passes your extension a pointer to the IExchExtCallback : IUnknown interface, your extension should use the methods of this interface to thoroughly examine the current context. An extension should run only if it determines that the current context is specific to it, for example, if the current selection is a custom message type understood only by your extension.

To avoid collisions, consider the following guidelines:

•	Avoid programming extensions that provide broad or general behavior for features such as the advanced criteria dialog box that can only have one active extension. Most extensions should operate only in contexts that can be considered extension-specific.

•	Extensions that are selective and highly context-specific should be registered at the beginning of the [Extensions] section of the .INI file. Those that exhibit more general behavior should be entered at the end of the [Extensions] section. For example, the standard Microsoft Exchange extension that handles the advanced criteria dialog box always returns S_OK to the IExchExtAdvancedCriteria::InstallAdvancedCriteria method. More selective advanced criteria dialog boxes must come before this entry or they will never be called.


 Registering Extensions

Before an extension can be used within the Microsoft Exchange client, it must be registered. Registering an extension lets Microsoft Exchange know about its existence and provides other information about the extension so that Microsoft Exchange can work with it in an efficient manner.

On 16-bit versions of Windows, extensions are registered by adding entries to the [Extensions] section of the EXCHNG.INI file. These 16-bit clients include Windows 3.1 and Windows for Workgroups 3.x.

On 32-bit versions of Windows, Microsoft Exchange obtains extension-specific information from HKEY_LOCAL_MACHINE\Software\Microsoft\Exchange\Client\Options in the Windows NT or Windows 95 registry.

Information on shared extensions is read from the [Extensions] section of the SHARED.INI file on 16-bit versions of Windows or from the SHARED32.INI file on 32-bit versions of Windows. The location of the SHARED.INI file is specified by the SharedExtsDir entry in the [Exchange] section of the EXCHNG.INI file. The location of the SHARED32.INI file is specified in the SharedExtsDir entry in HKEY_LOCAL_MACHINE\Software\Microsoft\Exchange\Client\Options.

If the directory is on a network drive, the SharedExtsServer entry can contain the name of the server and the SharedExtsPassword entry contains an unencrypted password. If this is the case, a connection to the server is made without redirecting a local device name.

Note that 32-bit clients cannot use 16-bit extensions nor can 16-bit clients use 32-bit extensions.

When registering an extension, you need to conform to a specific syntax when placing your entry in the INI file or registry. This syntax is as follows:

Syntax

Tag=Version;<ExtsDir>DllName;[Ordinal];[ContextMap];[InterfaceMap];[Provider]

Parameters

The following table shows the parameters used in the syntax line.

Parameter	Description
Tag	An extension identifier that uniquely identifies the .INI entry from other .INI entries.
Version	The version number of the syntax; for example '4.0'.
DllName	The path to the DLL containing the extension.
Ordinal	An optional field that specifies the entry point in the DLL to retrieve the extension object. If this field is empty, the default value is 1.
ContextMap	An optional string made up of '0' and '1' characters which indicate the contexts in which the extension should be loaded. Any unspecified values after the end of the string are assumed to be zero. If no context map is provided, the extension will be loaded in all contexts. For more information on context map bit positions, see the table later in this section.
InterfaceMap	An optional string made up of '0' and '1' characters that indicates the interfaces the extension supports. Although supported interfaces can be obtained through IUnknown::QueryInterface, registering which interfaces your extension supports can increase system performance. For more information on interface map bit positions, see the table later in this section.
Provider	An optional string containing the PR_SERVICE_NAME, not the display name, of an ISV-supplied provider that your extension is designed to work with. For example, if your extension is designed to work with a custom address book provider, place the PR_SERVICE_NAME of the address book provider in this parameter. If your extension is not provider-specific, this parameter should be omitted.
Example

MyExtension=4.0;<ExtsDir>MYEXT.DLL;2;010001;1100000

In this example, EECONTEXT_VIEWER=0x00000002 and EECONTEXT_SENDNOTEMESSAGE =0x00000006 so the ContextMap string '010001' indicates that the extension located at MYEXT.DLL;2 should be loaded only for these two contexts. The interface map, specified by the string 1100000, indicates that the extension is registered only for the IExchExtCommands : IUnknown and IExchExtUserEvents : IUnknown interfaces.

Throughout the string, all occurrences of the string '<ExtsDir>' are replaced with the value of the SharedExtsDir entry described below.

The order in which an extension is registered, that is, the order it is listed in the .INI file or registry, might affect the execution of the extension. Given two extensions that are registered within the same context, the first extension that is called to process an event or a command might handle it and not give other extensions a chance to respond.

The following tables indicate which positions in the Context Map and Interface Map correspond to which contexts and interfaces, respectively.

Context Map Bit Positions

Position	Context
1	EECONTEXT_SESSION
2	EECONTEXT_VIEWER
3	EECONTEXT_REMOTEVIEWER
4	EECONTEXT_SEARCHVIEWER
5	EECONTEXT_ADDRBOOK
6	EECONTEXT_SENDNOTEMESSAGE
7	EECONTEXT_READNOTEMESSAGE
8	EECONTEXT_SENDPOSTMESSAGE
9	EECONTEXT_READPOSTMESSAGE
10	EECONTEXT_READREPORTMESSAGE
11	EECONTEXT_SENDRESENDMESSAGE
12	EECONTEXT_PROPERTYSHEETS
13	EECONTEXT_ADVANCEDCRITERIA
14	EECONTEXT_TASK
Interface Map Bit Positions

Position	Interface
1	IExchExtCommands
2	IExchExtUserEvents
3	IExchExtSessionEvents
4	IExchExtMessageEvents
5	IExchExtAttachedFileEvents
6	IExchExtPropertySheets
7	IExchExtAdvancedCriteria


 Provider Parameter

In some cases, your extension might be designed to work only with a custom provider. For example, your extension might only work with a custom address book provider that replaces the default address book provider of Microsoft Exchange. Under these circumstances, your extension should be prevented from loading if its associated provider is not loaded.

This situation is handled by specifying the name of the extension's associated provider in the [Provider] parameter of your extension's registration line. If you specify the provider, your extension will not be loaded unless the provider has been loaded. This can save some programming effort because it might be difficult for your extension to determine whether a specific provider has been loaded.

When Microsoft Exchange starts, it reads the current profile and attempts to start all providers listed there. After attempting to load all providers specified in the profile, it reads the extension registration lines of its .INI file or registry and omits all extensions that specify a provider that was not in the profile or failed to load.


 Interfaces for Extending the Microsoft Exchange Client

The Microsoft Exchange client is an extensible program containing a number of interfaces that independent software vendors can use to extend or enhance its functionality. Two of those interfaces are implemented by Microsoft Exchange and called by extension objects. All the other interfaces for client extensibility are implemented by extension objects and are called by Microsoft Exchange. Both sets of interfaces are described in this chapter.

An extension object is an object that complies with the Microsoft Windows Component Object Model and implements a set of Microsoft Exchange interfaces. Some of the interfaces described in this chapter are optional, but if an extension object implements an interface, it must implement all the functions of that interface.

The IUnknown interface provides object management functions from the OLE 2 component object model. Since all extension objects inherit from this interface, all extension interfaces include the three IUnknown methods in addition to their own methods.


 IExchExt : IUnknown

Microsoft Exchange uses the IExchExt interface to load extension objects in all contexts. Most extension objects are designed to operate only within a particular context or set of contexts, but some can operate in all contexts.

At a Glance

Specified in header file:	EXCHEXT.H
Object that supplies this interface:	Extension object
Corresponding pointer type:	LPEXCHEXT
Implemented by:	Extension objects
Called by:	Microsoft Exchange
Vtable Order

Install	Enables an extension object to determine the context into which it is being loaded, along with information about that context.
Note  Custom form developers are responsible for supporting extension objects in their custom forms. That is, replacement IPM.Note forms and other custom forms supplied by form developers might choose to load extension objects and call them the same way that Microsoft Exchange does with its native forms. In this documentation, all references to forms refer to the standard forms supplied by Microsoft Exchange, such as the standard IPM.Note.


 IExchExt::Install

Enables an extension object to determine the context into which it is being loaded, along with information about that context. The MAPI and user interface information that can be retrieved by the extension includes session, store, viewer, note form, and address book information.

Syntax

HRESULT Install(LPEXCHEXTCALLBACK lpeecb, ULONG eecontext, ULONG ulFlags)

Parameters

lpeecb

Input parameter pointing to an IExchExtCallback interface.

eecontext

Input parameter indicating the currently active Microsoft Exchange context. This parameter can have the following values:

EECONTEXT_TASK

Indicates the context where the Microsoft Exchange client application has started but has not yet logged in. This context begins when the Microsoft Exchange application starts and ends when the Microsoft Exchange application exits. This context does not correspond to a window. This is the first context in which extensions are loaded.

EECONTEXT_SESSION

Indicates the duration of a Microsoft Exchange session. This context and EECONTEXT_TASK are the only contexts that do not correspond to a specific window.

EECONTEXT_VIEWER

Indicates the main Viewer window that displays the folder hierarchy in the left pane and folder contents in the right pane.

EECONTEXT_REMOTEVIEWER

Indicates the remote Viewer window that is displayed when the user chooses the Remote Mail command from the Tools menu in the Microsoft Exchange client.

EECONTEXT_SEARCHVIEWER

Indicates the search Viewer window that is displayed when the user chooses the Find button from the Tools menu in the Microsoft Exchange client.

EECONTEXT_ADDRBOOK

Indicates the Address Book dialog box that is displayed when the user chooses the Address Book button from the Tools menu in the Microsoft Exchange client.

EECONTEXT_SENDNOTEMESSAGE

Indicates the standard send note window in which messages of the IPM.Note class are composed.

EECONTEXT_READNOTEMESSAGE

Indicates the standard read note window in which messages of the IPM.Note class are read after they are received.

EECONTEXT_SENDPOSTMESSAGE

Indicates the standard posting window in which new IPM.Post posting messages are composed.

EECONTEXT_READPOSTMESSAGE

Indicates the standard posting window in which existing posting messages are read.

EECONTEXT_READREPORTMESSAGE

Indicates the read report message window in which the Read, Delivery, Non-Read, and Non-Delivery report messages are read after they are received.

EECONTEXT_SENDRESENDMESSAGE

Indicates the send-resend message window that is displayed when the user chooses the Send Again button from the nondelivery report.

EECONTEXT_PROPERTYSHEETS

Indicates a property sheet window.

EECONTEXT_ADVANCEDCRITERIA

Indicates any window in which the user specifies advanced search criteria. In Microsoft Exchange, this is a window brought up by the Find button from the Tools menu, or the dialog box brought up by the Filter button.

ulFlags

Input parameter containing a bitmask of flags. The following flag can be set:

EE_MODAL

Specifies that the extension is being installed into a context where modal windows are displayed. Extensions that are loaded into modal contexts should only display modal windows.

Return Values

S_OK

The extension object elects to run in this context.

S_FALSE

The extension object does not elect to run in this context and will be released immediately.

Comments

Microsoft Exchange calls the IExchExt::Install method to enable an extension object to determine the context into which it is being loaded, along with information about that context. The context is determined using the callback object returned in the lpeecb parameter. The user interface context is described by the value of the eecontext parameter.

IExchExtCallback::GetVersion is often called during Install to ensure that the version of the Microsoft Exchange client is compatible with your extension object.

IExchExtCallback::GetObject is often called during Install to determine whether the currently selected object in the Microsoft Exchange user interface is the type your extension object supports. When Install is called with the property sheet's context, your extension object should make sure the selected object matches the type of property sheet that is provided to the extension.

HRESULT return values other than S_OK and S_FALSE indicate that the extension object has encountered an error and Microsoft Exchange will not load the extension object.

See Also

IExchExtCallback::GetVersion method, IExchExtCallback::GetObject method


 IExchExtAdvancedCriteria : IUnknown

The IExchExtAdvancedCriteria interface is used to enable extension objects to replace or enhance the functionality of the Advanced dialog box that appears when the user selects the Advanced button from the Find dialog box.

Only one advanced criteria interface is used by a single context, although different extension objects can implement advanced criteria dialog boxes used by different contexts, potentially at the same time. The first extension object to be called with the IExchExtAdvancedCriteria::InstallAdvancedCriteria method is given precedence in determining the situations in which to install its advanced criteria dialog box. This ordering depends on the order in which extensions are listed in the registry database. Advanced criteria implementors can choose whether to take responsibility for advanced criteria based on the selected folder or on the existing restriction.

IExchExtAdvancedCriteria is used by Microsoft Exchange only in the EECONTEXT_VIEWER and EECONTEXT_SEARCHVIEWER contexts.

This interface is optional.

At a Glance

Specified in header file:	EXCHEXT.H
Object that supplies this interface:	Extension object
Corresponding pointer type:	LPEXCHEXTADVANCEDCRITERIA
Implemented by:	Extension objects
Called by:	Microsoft Exchange
Vtable Order

InstallAdvancedCriteria	Enables an extension to install its advanced criteria dialog box.
DoDialog	Displays an extension's advanced criteria dialog box.
Clear	Prompts an extension to clear all of its advanced criteria.
SetFolders	Called when the folders have been changed.
QueryRestriction	Returns a restriction object and a text representation of the restriction.
UninstallAdvancedCriteria	Called when the criteria user interface is closed and enables extensions to release resources.


 IExchExtAdvancedCriteria::Clear

Clears the advanced criteria associated with the extension object. This method is called by Microsoft Exchange when the user chooses the Clear All button in the Advanced dialog box.

Syntax

VOID Clear()


 IExchExtAdvancedCriteria::DoDialog

Displays an extension object's advanced criteria dialog box.

Syntax

HRESULT DoDialog()

Return Values

S_OK

Advanced criteria, including the fNot parameter, were set after the user chose the dialog box's OK button, unless an error occurs.

EXCHEXT_S_NOCHANGE

No change was made to the dialog box, or the user chose the Cancel button.

EXCHEXT_S_NOCRITERIA

No criteria were specified in the dialog box. That is, the user changed the criteria to be empty)

Comments

Microsoft Exchange calls the IExchExtAdvancedCriteria::DoDialog method when the user selects the Advanced button in the Find dialog box. The extension object should display a dialog box that enables the user to specify search criteria. The dialog box should be modal to the window specified in the hwnd parameter of IExchExtAdvancedCriteria::InstallAdvancedCriteria.


 IExchExtAdvancedCriteria::InstallAdvancedCriteria

Enables an extension object to install its advanced criteria dialog box.

Syntax

HRESULT InstallAdvancedCriteria(HWND hwnd, LPSRestriction lpres, BOOL fNot, LPENTRYLIST lpeidl, ULONG ulFlags)

Parameters

hwnd

Input parameter indicating the window handle containing the advanced criteria user interface.

lpres

Input parameter pointing to a MAPI SRestriction structure containing the advanced criteria restriction. NULL if none exists. For more information on SRestriction structures, see the MAPI Programmer's Reference.

fNot

Input parameter indicating TRUE if the user wants only messages that do not meet the criteria specified in the structure pointed to by the lpres parameter.

lpeidl

Input parameter pointing to an array of folder entry identifiers to which the criteria will be applied.

ulFlags

Input parameter containing a bitmask of flags. The following flag can be set:

EEAC_INCLUDESUBFOLDERS

Specifies that subfolders of the lpeidl parameter are to be included in the search.

Return Values

S_OK

The extension object will display its advanced criteria user interface.

S_FALSE

The extension object will not display its advanced criteria user interface.

Comments

Microsoft Exchange calls the IExchExtAdvancedCriteria::InstallAdvancedCriteria method when the user chooses the Advanced button in the Find dialog box. The first extension that returns S_OK is the only IExchExtAdvancedCriteria interface implementation used for the criteria dialog box instance. Implementations of this method should examine the lpres parameter to see if the restriction's format is recognizable. If not, S_FALSE should be returned and other extensions will be given the opportunity to handle the restriction. Extensions should use comment fields in restrictions to identify their particular formats.

Calls to InstallAdvancedCriteria will not be nested within a single context; that is, they will not be prompted to install their advanced criteria dialog box a second time before an existing installation has been uninstalled (with the exception of multiple instances of Microsoft Exchange Find windows and advanced criteria objects). Specifically, separate contexts which use IExchExtAdvancedCriteria can have overlapping lifespans.

To determine whether your extension should participate in the current advanced criteria context, you can obtain information about the context during the last call to the IExchExt::Install method. You might want to save information about the advanced criteria context for later use. You cannot save the pointer to the callback object during the call to Install.

If S_FALSE is returned, remaining extension objects will be given the opportunity to recognize the restriction and display the user interface. If no extension object returns S_OK, the Advanced button will be disabled. Microsoft Exchange will provide default advanced criteria functionality.

See Also

IExchExtCallback::GetObject method


 IExchExtAdvancedCriteria::QueryRestriction

Returns a restriction object and a text version of the restriction. The text version is a user-readable representation of the query that the user composed in the Advanced dialog box. The format of the text version depends on the complexity of the criteria. For example, it could be a description in plain text English or in SQL language.

Syntax

HRESULT QueryRestriction(LPVOID lpvAllocBase, LPSRestriction FAR *lppres, LPSPropTagArray FAR * lppPropTags, LPMAPINAMEID FAR * FAR * lpppPropNames, BOOL * lpfNot, LPTSTR lpszDesc, ULONG cchDesc, ULONG ulFlags)

Parameters

lpvAllocBase

Input parameter pointing to the memory allocation base to be used when allocating memory for the restriction data. For more information on allocating memory, see the MAPI Programmer's Guide.

lppres

Output parameter pointing to where to return a pointer to the advanced criteria restriction.

lppPropTags

Output parameter pointing to where to return a pointer to a MAPI property tag array containing the property tags of any named properties involved in the restriction. This parameter is used by Microsoft Exchange to find property tags which need to be remapped should the restriction be applied to a different store.

lppPropNames

Output parameter pointing to where to return an array of MAPI property NAMEID structures that define the properties whose tags are given in the lppPropTags parameter. This value is used by Microsoft Exchange to obtain the appropriate new property tags should the restriction be applied to a different store.

lpfNot

Output parameter pointing to a variable that returns TRUE if the user only wants messages that do not meet the criteria specified in the structure pointed to by the lpres parameter.

lpszDesc

Output parameter pointing to a buffer which the extension should fill with a string containing a text description of the restriction.

cchDesc

Input parameter indicating the maximum length of the lpszDesc parameter.

ulFlags

Input parameter containing a bitmask of flags.

EXCHEXT_UNICODE

Microsoft Exchange sets the ulFlags parameter to this value if it wants the extension to fill the lpszDesc parameter with a unicode string.

Comments

Microsoft Exchange calls the IExchExtAdvancedCriteria::QueryRestriction method when the criteria which the user has specified must be instantiated as a restriction. For example, when the user closes the Advanced dialog box, Microsoft Exchange prompts the extension object to return the current restriction. The restriction is a MAPI construct specifying a query. Memory for the returned restriction object must be allocated with the MAPIAllocateMore function using the pvAllocBase parameter as the base. QueryRestriction can be called zero, one, or multiple times depending on the context and the user's choices.

The Advanced Criteria restriction returned from this method must start with a Comment restriction that includes lpProp[0].ulPropTag == PR_COMCRIT_COMMENT_ID and lpProp[0].Value.ul == ulComCritCmtAdvanced. The actual restriction is included afterwards.


 IExchExtAdvancedCriteria::SetFolders

Notifies an extension object when the folders to which the search criteria apply have been changed.

Syntax

VOID SetFolders(LPENTRYLIST lpeidl, ULONG ulFlags)

Parameters

lpeidl

Input parameter pointing to an array of folder entry identifiers to which the search criteria will be applied.

ulFlags

Input parameter containing a bitmask of flags. The following flag can be set:

EEAC_INCLUDESUBFOLDERS

Microsoft Exchange sets the ulFlags parameter to this value to specify that subfolders of the lpeidl parameter are to be included in the search.

Comments

Microsoft Exchange calls the IExchExtAdvancedCriteria::SetFolders method when the user changes the folders to which the search criteria will be applied. This enables extensions to take additional actions depending on the newly selected folder.


 IExchExtAdvancedCriteria::UninstallAdvancedCriteria

Notifies an extension object when the search criteria dialog box is closed.

Syntax

VOID UninstallAdvancedCriteria()

Comments

Microsoft Exchange calls the IExchExtAdvancedCriteria::UninstallAdvancedCriteria method when the search criteria dialog box is closed. The effect of this method is similar to what is expected during the IExchExtMessageEvents::OnReadComplete, OnWriteComplete, OnSubmitComplete, and OnCheckNamesComplete methods. When UninstallAdvancedCriteria is invoked, the extension object can release interfaces previously claimed with the AddRef method and release any other resources used while the criteria dialog box was displayed.

The extension object can discard any state information it is maintaining, such as memory allocations and the current state of the dialog box. The extension should not free any memory returned by the IExchExtAdvancedCriteria::QueryRestriction method.


 IExchExtAttachedFileEvents : IUnknown

The IExchExtAttachedFileEvents interface is used to enable extension objects to replace or enhance the default attachment-handling behavior of Microsoft Exchange.

The IExchExtAttachedFileEvents interface is used only in the following contexts: EECONTEXT_SENDNOTEMESSAGE, EECONTEXT_READNOTEMESSAGE, EECONTEXT_SENDPOSTMESSAGE, EECONTEXT_READPOSTMESSAGE, EECONTEXT_READREPORTMESSAGE, EECONTEXT_SENDRESENDMESSAGE.

This interface is optional.

At a Glance

Specified in header file:	EXCHEXT.H
Object that supplies this interface:	Extension object
Corresponding pointer type:	LPEXCHEXTATTACHEDFILEEVENTS
Implemented by:	Extension objects
Called by:	Microsoft Exchange
Vtable Order

OnReadPattFromSzFile	Replaces or enhances the behavior of Microsoft Exchange when adding attachments to a message from a file.
OnWritePattToSzFile	Replaces or enhances the behavior of Microsoft Exchange when writing attachments from a message to a file (such as when responding to the Save command.)
QueryDisallowOpenPatt	Prevents a document file attachment from being opened directly without writing it first to an intermediate file.
OnOpenPatt	Replaces or enhances the behavior of Microsoft Exchange when opening a file attachment directly from the message.
OnOpenSzFile	Replaces or enhances the behavior of Microsoft Exchange when opening an attachment from a temporary file.


 IExchExtAttachedFileEvents::OnReadPattFromSzFile

Replaces or enhances the behavior of Microsoft Exchange when adding attachments to a message from a file.

Syntax

HRESULT OnReadPattFromSzFile(LPATTACH lpAtt, LPTSTR lpszFile, ULONG ulFlags)

Parameters

lpAtt

Input parameter pointing to the MAPI IAttach : IMAPIProp interface on the attachment. For more information on IAttach, see the MAPI Programmer's Reference.

lpszFile

Input parameter pointing to a string containing the name and path of the file being attached.

ulFlags

Input parameter containing a bitmask of flags. The following flag can be set:

EXCHEXT_UNICODE

Specifies that the lpszFile parameter is a unicode string.

Return Values

S_OK

The extension object replaced Microsoft Exchange behavior and handled attaching the file on its own. Microsoft Exchange will consider the task handled.

S_FALSE

The extension object did nothing or added additional behavior. Microsoft Exchange will continue to call extensions or complete the work itself.

Comments

Microsoft Exchange calls the IExchExtAttachedFileEvents::OnReadPattFromSzFile method when it is about to read an attached file's data. This can occur on initial attachment and when the contents of the attachment are being updated from a temporary file. If an error occurs, OnReadPattFromSzFile should display an error message and return an error. Microsoft Exchange will not continue to attach the file, nor will it display an additional error message, but will stop the user action that requested the attachment.


 IExchExtAttachedFileEvents::OnWritePattToSzFile

Replaces or enhances the behavior of Microsoft Exchange when writing attachments from a message to a file.

Syntax

HRESULT OnWritePattToSzFile(LPATTACH lpAtt, LPTSTR lpszFile, ULONG ulFlags)

Parameters

lpAtt

Input parameter pointing to the MAPI IAttach : IMAPIProp interface on the attachment. For more information on IAttach, see the MAPI Programmer's Reference.

lpszFile

Input parameter pointing to a string containing the name and path of the intermediate file being written.

ulFlags

Input parameter containing a bitmask of flags. The following flag can be set:

EXCHEXT_UNICODE

Specifies that the lpszFile parameter is a unicode string.

Return Values

S_OK

The extension object replaced Microsoft Exchange behavior and wrote out the file on its own. Microsoft Exchange will consider the task handled.

S_FALSE

The extension object did nothing or added additional behavior. Microsoft Exchange will continue to call extension objects or complete the work itself.

Comments

Microsoft Exchange calls the IExchExtAttachedFileEvents::OnWritePattToSzFile method when it is about to write an attachment to a file, such as when the user chooses the Save or Open button. If an error occurs, OnWritePattToSzFile should display an error message and return an error. Microsoft Exchange will not continue to try and write out the file, nor will it display an error message, but will stop the user action that requested the file be written.


 IExchExtAttachedFileEvents::OnOpenPatt

Replaces or enhances the behavior of Microsoft Exchange when opening a document file attachment directly from a message.

Syntax

HRESULT OnOpenPatt(LPATTACH lpAtt)

Parameters

lpAtt

Input parameter pointing to the MAPI IAttach : IMAPIProp interface on the attachment. For more information on IAttach, see the MAPI Programmer's Reference.

Return Values

S_OK

The extension object replaced Microsoft Exchange behavior and opened the file on its own. Microsoft Exchange will consider the task handled.

S_FALSE

The extension object did nothing or added additional behavior. Microsoft Exchange will continue to call extensions or complete the work itself.

Comments

Microsoft Exchange calls the IExchExtAttachedFileEvents::OnOpenPatt method when it is about to open an attachment directly from the message. Before writing it to an intermediate file, Microsoft Exchange allows extension objects to open directly from the attachment. File viewers might use this method to display the content of the attachment without writing an intermediate file to the file system.

Microsoft Exchange attempts to find an application that is registered to handle the attached file's class. If no such application can be found, Microsoft Exchange writes the attachment to a temporary file and prompts Microsoft Windows to start the application that is registered to handle files with the given file extension (such as .XLS for Microsoft Excel).

It then calls the IExchExtAttachedFileEvents::OnOpenSzFile method on extension objects instantiated in the context that supports the IExchExtAttachedFileEvents : IUnknown interface. Microsoft Exchange may try to open an attachment from a file after learning from IExchExtAttachedFileEvents::QueryDisallowOpenPatt that it is allowed to do so. At this point, Microsoft Exchange prompts the extension object if it wants to do special handling of the file such as replacing the open-attachment behavior or by doing other work such as detecting viruses.

If an error occurs, OnOpenPatt should display an error message and return an error. Microsoft Exchange will not continue to try and open the attachment, nor will it display an error message, but will stop the user action that requested the attachment be opened.


 IExchExtAttachedFileEvents::OnOpenSzFile

Replaces or enhances the behavior of Microsoft Exchange when opening an attachment from a temporary file.

Syntax

HRESULT OnOpenSzFile(LPTSTR lpszFile, ULONG ulFlags)

Parameters

lpszFile

Input parameter pointing to a string containing the name and path of the temporary file being opened.

ulFlags

Input parameter containing a bitmask of flags. Set this parameter to one of the following values:

EXCHEXT_UNICODE

Indicates that the lpszFile parameter is a unicode string.

EEAFE_OPEN

Indicates that the attachment is being opened.

EEAFE_PRINT

Indicates that the attachment is being printed.

EEAFE_QUICKPREVIEW

Indicates that the attachment is being quickviewed.

Return Values

S_OK

The extension object replaced Microsoft Exchange behavior and opened the file on its own. Microsoft Exchange will consider the task handled.

S_FALSE

The extension object did nothing or added additional behavior. Microsoft Exchange will continue to call extensions or, if necessary, open the file attachment itself.

Comments

Microsoft Exchange calls the IExchExtAttachedFileEvents::OnOpenSzFile method when it is about to open an attachment, but was not able to open it directly from the data in the attachment in the message. When this occurs, the attachment data is written to an intermediate file. Microsoft Exchange attempts to find an application that is registered to handle the attached file's class. If it finds it, the application is started and prompted to open the attachment.

If an error occurs, OnOpenSzFile should display an error message and return an error. Microsoft Exchange will not continue to try and open the attachment, nor will it display an error message, but will stop the user action that requested the attachment be opened.


 IExchExtAttachedFileEvents::QueryDisallowOpenPatt

Prevents a file attachment from being opened directly without writing it first to an intermediate file.

Syntax

HRESULT QueryDisallowOpenPatt(LPATTACH lpAtt)

Parameters

lpAtt

Input parameter pointing to the MAPI IAttach : IMAPIProp interface on the attachment. For more information on IAttach, see the MAPI Programmer's Reference.

Return Values

S_OK

The extension object will prevent other extensions or Microsoft Exchange from opening the attachment directly without writing it to a file first.

S_FALSE

The extension object did nothing. Microsoft Exchange will call other extension objects if opening the attachment directly ought to be disallowed.

Comments

Microsoft Exchange calls the IExchExtAttachedFileEvents::QueryDisallowOpenPatt method when it is about to open the attachment directly without writing it first to an intermediate file. An extension object might elect to disallow opening attachments directly if it has encrypted or modified the attachment and should decrypt or restore it to an intermediate file.

If an error occurs, QueryDisallowOpenPatt should display an error message and return an error. Microsoft Exchange will not continue to try to open the file, nor will it display an error message, but will stop the user action that requested the attachment be opened.


 IExchExtCallback : IUnknown

The IExchExtCallback interface enables extension objects to retrieve information about the current context, including the objects that are currently selected in the Microsoft Exchange window. IExchExtCallback uses the methods of the IUnknown interface for reference management.

IExchExtCallback is implemented by a callback object supplied by Microsoft Exchange. A pointer to this interface is passed as a parameter to many methods of the Microsoft Exchange extensibility API. This interface and any interfaces it might return are valid only for the time of the call to one of its methods and might not be retained when the extension object's method returns. The called method does not need to release the callback object unless it has completed a corresponding call to AddRef.

At a Glance

Specified in header file:	EXCHEXT.H
Object that supplies this interface:	Extension object
Corresponding pointer type:	LPEXCHEXTCALLBACK
Implemented by:	Microsoft Exchange
Called by:	Extension objects
Vtable Order

GetVersion	Returns the version number of the Microsoft Exchange application.
GetWindow	Returns a window handle corresponding to the specified flag.
GetMenu	Returns the Microsoft Exchange menu handle for the current window.
GetToolbar	Returns a toolbar's window handle.
GetSession	Returns an interface to the current open MAPI session and associated address book.
GetObject	Returns an interface and store for a particular object.
GetSelectionCount	Returns the number of objects selected in the window.
GetSelectionItem	Returns the entry identifier of a selected item in a Microsoft Exchange window.
GetMenuPos	Returns the position of a command or set of commands on the Microsoft Exchange menu.
GetSharedExtsDir	Returns the Microsoft Exchange shared-extensions directory.
GetRecipients	Returns a pointer to the recipient list of the currently selected item.
SetRecipients	Sets the recipient list for the currently selected item.
GetNewMessageSite	Returns interface pointers to the message site and view context of the selected message.
RegisterModeless	Enables extension objects that display modeless windows to coordinate with windows displayed by the Microsoft Exchange client.
ChooseFolder	Displays a dialog box that enables users to choose a specific message store and folder.


 IExchExtCallback::ChooseFolder

Displays a dialog box that enables users to choose a specific message store and folder.

Syntax

HRESULT ChooseFolder(LPEXCHEXTCHOOSEFOLDER peecf)

Parameters

peecf

Input parameter pointing to a structure that describes the Choose Folder dialog box. The structure also includes output members that provide information about the selections made by the user when the user chooses the OK button. The structure has the following members:

UINT cbLength

Input member indicating the size of the structure.

HWND hwnd

Input member indicating the parent window of the Choose Folder dialog box.

LPTSTR szCaption

Input member indicating the caption that is displayed in the dialog box's title bar.

LPTSTR szLabel

Input member indicating a label that is displayed at the top of the list box of folders.

LPTSTR szHelpFile

Input member specifying which Help file should be launched when the user chooses the Help button.

ULONG ulHelpID

Input member indicating the topic that should be referenced in the Help file.

HINSTANCE hinst

Input member indicating the instance handle containing the resource of a custom dialog box. Set this value only if you want to supply your own dialog box template.

UINT uiDlgID

Input member indicating the resource identifier of the instance of the custom dialog box template. Set this value only if you set the hinst parameter.

LPEECFHOOKPROC lpeecfhp

Input member indicating a hook proc pointer. Set this value only if you want to do special processing of messages within the dialog box.

DWORD dwHookData

Input member used to cache additional information about events that occur while the dialog box is displayed. Use this member if you are providing a hook process for handling dialog box messages.

ULONG ulFlags

Input member containing a bitwise combination of the following flags:

EECBCF_GETNAME	Determines whether the name of the folder selected by the user is returned. This name must be freed using the MAPIFreeBuffer function. For more information on MAPIFreeBuffer, see the MAPI Programmer's Reference.
EECBCF_HIDENEW	Hides the New button on the Choose Folder dialog box. This button enables  users to create a new folder.
EECBCF_PREVENTROOT	Disables the OK button when the root is the currently selected folder. In most cases, this flag should be specified because the root folder is not a valid container of messages.
LPMDB pmdb

Output member that is an interface pointer to the message store object selected in the Choose Folder dialog box.

LPMAPIFOLDER pfld

Output member that is an interface pointer to the folder object selected in the Choose Folder dialog box.

LPTSTR szName

Output member indicating the name of the folder the user selected. This value enables you to get the name of the folder without using a MAPI GetProps method. This value is only provided if the EECBCF_GETNAME flag is set.

DWORD dwReserved1 - dwReserved3

These three members are reserved for future use and should be set to NULL by extensions.

Return Values

S_OK

No errors occurred.

Comments

Extension objects call the IExchExtCallback::ChooseFolder method to enable users to select a specific message store or folder. For example, if your application provides a backup command, you might want to prompt the user to specify which folder in which message store should be backed up.


 IExchExtCallback::GetMenu

Returns the menu handle for the current Microsoft Exchange window.

Syntax

HRESULT GetMenu(HMENU FAR * lphMenu)

Parameters

lphMenu

Output parameter pointing to the Microsoft Exchange menu handle.

Return Values

S_OK

The lphMenu parameter returned a non-NULL HMENU.

S_FALSE

The lphMenu parameter returned a NULL HMENU.

E_INVALIDARG

The lphMenu parameter is NULL or no HWND is associated with the context where the extension is installed.


 IExchExtCallback::GetMenuPos

Returns the position of a command, menu, or set of commands on the Microsoft Exchange menu for the current context.

Syntax

HRESULT GetMenuPos(UINT cmdid, HMENU FAR * lphmenu, ULONG FAR * lpmposMin, ULONG FAR * lpmposMax, ULONG ulFlags)

Parameters

cmdid

Input parameter indicating the command identifier of interest.

lphMenu

Output parameter pointing to the menu handle where the cmdid parameter can be found.

lpmposMin

Output parameter pointing to the menu position above the command.

lpmposMax

Output parameter pointing to the menu position below the command.

ulFlags

Input parameter containing a bitmask of flags. The following flag can be set:

EECBGMP_RANGE

Specifies that the returned positions should correspond to the separator-delimited range of the menu containing the command.

Return Values

S_OK

No errors occurred.

E_FAIL

Microsoft Exchange cannot find the menu associated with the cmdid parameter.

E_INVALIDARG

The command identifier does not correspond to a menu item or the lphmenu parameter is NULL, or there is no HMENU associated with the context where the extension is installed.


 IExchExtCallback::GetNewMessageSite

Returns interface pointers to the message, message site, and view context for a new message that is being composed. Using these interface pointers, an extension object can display a form for the new message.

Syntax

HRESULT GetNewMessageSite(ULONG fComposeInFolder, LPMAPIFOLDER pfldFocus, LPPERSISTMESSAGE ppermsg, LPMESSAGE FAR * ppmsg, LPMAPIMESSAGESITE FAR * ppmms, LPMAPIVIEWCONTEXT FAR * ppmvc, ULONG ulFlags)

Parameters

fComposeInFolder

Input parameter indicating whether the message is being composed in the same folder from which it was activated. If this flag is TRUE, the message site supports default behavior for posting messages, which means that the message always remains in the same folder in which it was created. If this flag is FALSE, the message site supports default behavior for sending messages, which means that messages are automatically moved to the Outbox or Inbox when the user sends or saves the message.

pfldFocus

Input parameter pointing to the folder in which the message is to be composed.

ppermsg

Input parameter pointing to a variable that points to the IPersistMessage interface on the form for which the new message site is being obtained.

ppmsg

Output parameter pointing to a variable where the pointer to the message being composed is stored.

ppmms

Output parameter pointing to a variable where the pointer to the MAPI message site for the new message is stored.

ppmvc

Output parameter pointing to a variable where the pointer to the MAPI view context for the new message is stored.

ulFlags

Input parameter containing a bitmask of flags. The following flag can be set:

EECBGNMS_MODAL

Indicates that the new form should be modal.

Return Values

S_OK

No error occurred.

E_INVALIDARG

No session is associated with the context where the extension is installed or the ulFlags parameter has EECBGNMS_MODAL set.

Comments

Extension objects call the IExchExtCallback::GetNewMessageSite method to display a form for a new message the user has created. For example, an extension that performs scheduling functions might have a New Meeting menu command which results in the creation of a new message and the display of a custom form that enables users to fill in the fields of the message.


 IExchExtCallback::GetObject

Returns interfaces for a particular object and the object's containing store. The interfaces returned depend on the context of the caller. For a list of possible interfaces returned, see the "Comments" section.

Syntax

HRESULT GetObject(LPMDB FAR * lppmdb, LPMAPIPROP FAR * lppmp)

Parameters

lppmdb

Output parameter pointing to a variable where the pointer to the store object containing the lppmp parameter is stored.

lppmp

Output parameter pointing to a variable where the pointer to a MAPI object is stored.

Return Values

S_OK

Either the lppmdb or lppmp parameter returned non-NULL values.

S_FALSE

Both the lppmdb and lppmp parameters returned NULL values.

E_INVALIDARG

Both the lppmdb and lppmp parameters are NULL.

Comments

The IExchExtCallback::GetObject method is used to return an interface and message store for a particular object. The interface returned depends on the context or the caller. When called by the IExchExtPropertySheets::GetPages method, the object is the object for which information should be displayed, and the store is the store containing that object.

The interfaces must be released before the call which was given the lpeecb parameter returns. The following list describes the interfaces that are returned when GetObject is called from various contexts.

EECONTEXT_SESSION, EECONTEXT_TASK

Both interfaces returned are NULL.

EECONTEXT_VIEWER

The interfaces returned by GetObject are NULL when called from the IExchExt::Install or IExchExtCommands::InstallCommands methods because the Viewer is not necessarily permanently associated with the same store or object.

When called from the IExchExtCommands::InitMenu or IExchExtCommands::DoCommand methods, the object is the open folder being displayed and the store is the store that contains that folder. When the root of a store is displayed, the object is the IPM_SUBTREE folder. Both pointers are NULL when the list of stores is displayed in the content pane.

EECONTEXT_REMOTEVIEWER

Both interfaces are NULL.

EECONTEXT_SEARCHVIEWER

The object is the search folder being displayed, and the store is the store which contains that search folder.

EECONTEXT_ADDRBOOK

The interfaces are generally NULL when called from Install or InstallCommands because the address book is not always necessarily associated with the same container.

When called from InitMenu and DoCommand, the object is the ABContainer being displayed and the store is NULL. GetObject is called in the following contexts:

EECONTEXT_SENDNOTEMESSAGE,

EECONTEXT_READNOTEMESSAGE,

EECONTEXT_SENDPOSTMESSAGE,

EECONTEXT_READPOSTMESSAGE,

EECONTEXT_READREPORTMESSAGE,

EECONTEXT_SENDRESENDMESSAGE,

The object is the message being displayed and the store is the store which contains that message.

The object interface returned in the lppmp parameter supports the IMAPIProp : IUnknown interface as well as the additional interface methods specific to its type.

Object	Interface type
Folder	IMAPIFolder
Message	IMessage
Store	IMsgStore
Address Book	IABContainer
See Also

IExchExt::Install method, IExchExtAdvancedCriteria::InstallAdvancedCriteria method


 IExchExtCallback::GetRecipients

Returns a pointer to the recipient list for the currently open item.

Syntax

HRESULT GetRecipients(LPADRLIST FAR * lppal)

Parameters

lppal

Output parameter pointing to the location where the address list is returned.

Return Values

S_OK

No error occurred.

E_INVALIDARG

The function was called from a context that does not support recipients or there is no recipients list.

Comments

The recipient list is returned in a MAPI ADRLIST structure. For more information on the MAPI ADRLIST structure, see the MAPI Programmer's Reference.

This method is called in the following contexts:

EECONTEXT_SENDNOTEMESSAGE,

EECONTEXT_READNOTEMESSAGE,

EECONTEXT_SENDPOSTMESSAGE,

EECONTEXT_READPOSTMESSAGE,

EECONTEXT_READREPORTMESSAGE,

EECONTEXT_SENDRESENDMESSAGE

See Also

IExchExtCallback::SetRecipients method


 IExchExtCallback::GetSelectionCount

Returns the number of objects selected in the active window. Selections can only be made in windows that display containers.

Syntax

HRESULT GetSelectionCount(ULONG FAR * lpceid)

Parameters

lpceid

Output parameter pointing to a variable containing the number of objects selected in the window.

Return Values

S_OK

The lpceid parameter returned the count of the current selection.

E_INVALIDARG

The lpceid parameter is NULL or GetSelectionCount was called from an invalid context (EECONTEXT_SESSION, EECONTEXT_TASK, EECONTEXT_MESSAGE).

Comments

The IExchExtCallback::GetSelectionCount method is used to return the number of objects selected in the active window. The window is determined by the context in which the extension object is installed.

See Also

IExchExtCommands::InitMenu method


 IExchExtCallback::GetSelectionItem

Returns the entry identifier and other information of the currently selected item in a Microsoft Exchange window.

Syntax

HRESULT GetSelectionItem(ULONG ieid, ULONG FAR * lpcbeid, LPENTRYID FAR * lppeid, ULONG FAR * lpulType, LPTSTR lpszMsgClass, ULONG cbMsgClass, ULONG FAR * lpulMsgFlags, ULONG ulFlags)

Parameters

ieid

Input parameter indicating the index of the entry identifier to be retrieved. Valid values for this parameter are 0 to lpceid -1 where lpceid is returned in the IExchExtCallback::GetSelectionCount method.

lpcbeid

Output parameter pointing to the number of bytes returned in the lppeid parameter.

lppeid

Output parameter pointing to a variable where the pointer to the entry identifier of the selection is stored.

lpulType

Output parameter pointing to the type of entry identifier returned in the lppeid parameter. This parameter can have the following values:

MAPI_STORE = 1, if lppeid refers to a message store.

MAPI_ADDRBOOK = 2, if lppeid refers to an address book.

MAPI_FOLDER = 3, if lppeid refers to a folder.

MAPI_MESSAGE = 5, if lppeid refers to a message.

lpszMsgClass

Input-output parameter pointing to a buffer into which Microsoft Exchange will copy the message class of the selected message.

cbMsgClass

Output parameter indicating the size of the message class.

lpulMsgFlags

Output parameter pointing to the message flags returned. For more information on PR_MESSAGE_FLAGS, see the MAPI Programmer's Reference.

ulFlags

Reserved; must be zero.

Return Values

S_OK

No errors occurred.

S_FAIL

Microsoft Exchange failed to access the selected item.

E_INVALIDARG

The ulFlags parameter is not fMapiUnicode or it is called from an invalid context that does not support the selected item.

Comments

The IExchExtCallback::GetSelectionItem method is used to return the entry identifier of the currently selected item in a Microsoft Exchange Window. For example, if a custom form is installed and the user selects this form, extension objects that implement the IExchExtUserEvents::OnSelectionChange method can use GetSelectionItem to determine the message class of the selected message. If the extension object is programmed to handle messages of this class, it might display or enable menu items specific to the message class.

If you do not use a parameter in this method, pass NULL for that parameter.

See Also

IExchExtCommands::InitMenu method


 IExchExtCallback::GetSession

Returns interfaces to the current open MAPI session and associated address book.

Syntax

HRESULT GetSession(LPMAPISESSION FAR * lppses, LPADRBOOK FAR * lppab)

Parameters

lppses

Output parameter pointing to a variable where the pointer to the current MAPI session object is stored.

lppab

Output parameter pointing to a variable where the pointer to the address book object associated with the lppses parameter is stored.

Return Values

S_OK

Either the lppses or lppab parameter returned a non-NULL value.

S_FALSE

Both the lppses and lppab parameters returned NULL values.

E_INVALIDARG

Both the lppses and lppab parameters are NULL.

Comments

The lppses and lppab parameters might be NULL. Both interfaces must be released before the method which was passed the lpeecb parameter returns a value.


 IExchExtCallback::GetSharedExtsDir

Returns the location of the Microsoft Exchange shared extensions directory.

Syntax

HRESULT GetSharedExtsDir(LPTSTR lpszDir, ULONG cchDir, ULONG ulFlags)

Parameters

lpszDir

Input-output parameter pointing to a buffer to be filled with the location of the shared directory.

cchDir

Input parameter indicating the size of the lpszDir parameter.

ulFlags

Input parameter containing a bitmask of flags. The following flag can be set:

EXCHEXT_UNICODE

Specifies that the lpszDir parameter is a unicode string.

Return Values

S_OK

No error occurred.

S_FALSE

There is no SharedExtsDir.

E_INVALIDARG

The lpszDir parameter is NULL, the cchDir parameter is zero, or the ulFlags parameter is not fMapiUnicode.


 IExchExtCallback::GetToolbar

Returns a toolbar window handle.

Syntax

HRESULT GetToolbar(ULONG tbid, HWND FAR * lphwndTb)

Parameters

tbid

Input parameter indicating the toolbar identifier.

lphwndTb

Output parameter pointing to the Microsoft Exchange toolbar window handle.

Return Values

S_OK

The lphWnd parameter returned a non-NULL HWND.

S_FALSE

The lphWnd parameter returned a NULL HWND.

E_INVALIDARD

The tbid parameter is not EETB_STANDARD or the lphWnd parameter is NULL.

Comments

Currently, only the standard toolbar defined by EETB_STANDARD is supported. It is therefore not possible to add toolbar buttons to other toolbars such as the formatting toolbar.

See Also

IExchExtCommands::ResetToolbar method


 IExchExtCallback::GetVersion

Returns the version number of the Microsoft Exchange client.

Syntax

HRESULT GetVersion(ULONG FAR * lpulVersion, ULONG ulFlags)

Parameters

lpulVersion

Output parameter pointing to the location where the version of Microsoft Exchange is returned. The format of the returned version is determined by the value of the ulFlags parameter.

ulFlags

Input parameter containing a bitmask of flags used to specify the type and format of the version information that is returned. These flags can have the following values:

EECBGV_GETBUILDVERSION

Requests that the major version is returned in the HIWORD and the minor version in the LOWORD. Extension objects should verify that the major version matches the EECBGV_BUILDVERSION_MAJOR with which they were compiled, and that the minor version is at least the minor version with which the extension object was tested.

EECBGV_GETACTUALVERSION

Requests that the version returned corresponds to the actual version of the calling client.

EECBGV_GETVIRTUALVERSION

Requests that the version returned is the version which the client wants the extension to base its decisions on. For example, if an application named Zippypost 5.0 implements Microsoft Exchange extensibility to exactly match that implemented in Microsoft Exchange, the actual version would be Zippypost 5.0 but the virtual version would be Microsoft Exchange.

Return Values

S_OK

No error occurred.

Comments

Extension objects should test against the virtual version and should reserve actual version checking for determination of additional features specific to a particular kind of client or version.

The actual and virtual versions are made up of four bytes, which represent in order from most significant to least the product, the platform, the major version, and the minor version. For example, Microsoft Exchange 4.0 for Windows NT is 0x01030400. Microsoft Exchange for the Macintosh® would be 0x0104052A. Zippypost 3.2 for Windows 3.1 might be 0x13010320.

See Also

IExchExt::Install method


 IExchExtCallback::GetWindow

Returns the window handle for the current Microsoft Exchange window.

Syntax

HRESULT GetWindow(HWND FAR * lphwnd)

Parameters

lphwnd

Output parameter pointing to the Microsoft Exchange window handle.

Return Values

S_OK

The lphwnd parameter returned a non-NULL HWND.

S_FALSE

The lphwnd parameter returned a NULL HWND.

E_INVALIDARG

The lphwnd parameter is NULL.


 IExchExtCallback::RegisterModeless

Ensures coordination between the modeless windows and modal windows displayed by the Microsoft Exchange client.

Syntax

HRESULT RegisterModeless (LPEXCHEXTMODELESS peem, LPEXCHEXTMODELESSCALLBACK FAR * ppeemcb)

Parameters

peem

Input parameter pointing to an IExchExtModeless interface implemented by the extension. This interface should be implemented as another object with separate reference counts from the main extension object.

ppeemcb

Output parameter pointing to an IExchExtModelessCallback interface implemented by Microsoft Exchange.

Return Values

S_OK

No errors occurred.

S_FALSE

It was not possible to register a modeless window for the extension.

E_INVALIDARG

The peemObj or ppeemcb parameter is NULL.

Comments

Extension objects that run in the process space of the Microsoft Exchange client and display modeless windows use the IExchExtCallback::RegisterModeless method primarily to enable and disable Microsoft Exchange windows and extension object windows in a coordinated manner. If an extension object has registered for modeless behavior by calling this method and has called IExchExtModelessCallBack::AddWindow, Microsoft Exchange invokes IExchExtModeless::EnableModeless (with its fEnable parameter set to FALSE) before displaying a modal window. The extension object can then disable its modeless windows. When Microsoft Exchange removes its modal window, it invokes EnableModeless (with its fEnable parameter set to TRUE). The extension object can then re-enable its modeless windows.

Similary, if a modeless extension object needs to display a modal window, it should call IExchExtModelessCallback::EnableModeless (with its fEnable parameter set to FALSE). Microsoft Exchange will then disable its modeless windows. When the extension object removes its modal window, it should invoke IExchExtModeless::EnableModeless (with its fEnable parameter set to TRUE), enabling Microsoft Exchange to re-enable its modeless windows.

When an extension registers itself as modeless, it supplies a modeless object that enables Microsoft Exchange to communicate with the extension object about the state of its windows.

See Also

IExchExtModeless interface


 IExchExtCallback::SetRecipients

Sets the recipient list for the currently selected item.

Syntax

HRESULT SetRecipients(LPADRLIST lpal)

Parameters

lpal

Input parameter pointing to the location of the new address list.

Return Values

S_OK

No error occurred.

E_INVALIDARG

The method was called from a context that does not support recipients.

Comments

Use MAPI functions to fill a MAPI ADRLIST structure with the appropriate information.

This method is called in the following contexts:

EECONTEXT_SENDNOTEMESSAGE,

EECONTEXT_READNOTEMESSAGE,

EECONTEXT_SENDPOSTMESSAGE,

EECONTEXT_READPOSTMESSAGE,

EECONTEXT_READREPORTMESSAGE,

EECONTEXT_SENDRESENDMESSAGE

See Also

IExchExtCallback::GetRecipients


 IExchExtCommands : IUnknown

The IExchExtCommands interface is implemented by extension objects to add and execute custom menu or toolbar command buttons. Extension objects can also replace existing Microsoft Exchange commands or enhance their behavior before Microsoft Exchange carries them out.

Use the operating system's native API to implement the methods given in the following table. For example, when implementing the IExchExtCommands::InstallCommands method for an extension object that will run in the Microsoft Windows 95 environment, the extension object must use  the Win32 structures, messages, and function calls for Windows 95 to manipulate menu or toolbar commands. IExchExtCommands is used in all contexts except EECONTEXT_SESSION, EECONTEXT_TASK, and EECONTEXT_PROPERTYSHEETS.

This interface is optional.

At a Glance

Specified in header file:	EXCHEXT.H
Object that supplies this interface:	Extension object
Corresponding pointer type:	LPEXCHEXTCOMMANDS
Implemented by:	Extension objects
Called by:	Microsoft Exchange
Vtable Order

InstallCommands	Enables an extension to install its menu commands or toolbar buttons.
InitMenu	Enables an extension to update its menu items when the user begins using the menus.
DoCommand	Carries out a menu or toolbar command chosen by the user.
Help	Provides user Help for a command.
QueryHelpText	Provides status bar or tool tip Help text for a command.
QueryButtonInfo	Provides information about the extension's toolbar buttons.
ResetToolbar	Enables an extension to restore its toolbar buttons to their default positions.


 IExchExtCommands::DoCommand

Carries out a menu or toolbar command chosen by the user.

Syntax

HRESULT DoCommand(LPEXCHEXTCALLBACK lpeecb, UINT cmdid)

Parameters

lpeecb

Input parameter pointing to an IExchExtCallback interface.

cmdid

Input parameter indicating the command identifier of the command to be carried out.

Return Values

S_OK

The extension object recognized the cmdid parameter and carried out the command. Microsoft Exchange will consider the task handled.

S_FALSE

The extension object did not recognize the cmdid parameter. Microsoft Exchange will continue prompting extension objects to carry out the command and, if necessary, carry out the command itself. In some cases, an extension object might perform some action but still return S_FALSE to give other extensions the opportunity to handle the command.

Comments

Microsoft Exchange calls the IExchExtCommands::DoCommand method when it receives a WM_COMMAND or WM_SYSCOMMAND message corresponding to a menu command, system menu command, or toolbar button so that the extension object can carry out any commands it implements or supersede the Microsoft Exchange implementation of a command. The command identifier passed to WM_COMMAND is mapped to the published set of Microsoft Exchange commands. It is this published command identifier that is passed to DoCommand in the cmdid parameter. The command identifier in WM_COMMAND maps to, but is different than, the command identifier specified in the cmdid parameter. Extension objects should therefore not rely on this mapping.

If an error occurs, DoCommand should display a message and return an error value. Microsoft Exchange will not continue trying to perform the command nor will it display a message.

The system command identifiers that extensions can override include:

SC_CLOSE
SC_MAXIMIZE
SC_MINIMIZE
SC_MOVE
SC_RESTORE
SC_SIZE
SC_TASKLIST

These commands are standard wparam values for the WM_SYSCOMMAND message.


 IExchExtCommands::Help

Provides user Help for a command.

Syntax

HRESULT Help(LPEXCHEXTCALLBACK lpeecb, UINT cmdid)

Parameters

lpeecb

Input parameter pointing to an IExchExtCallback interface.

cmdid

Input parameter indicating the command identifier selected by the user.

Return Values

S_OK

The extension object recognized the cmdid parameter and provided Help. Microsoft Exchange will consider the task handled.

S_FALSE

The extension object did not recognize the cmdid parameter. Microsoft Exchange will continue prompting extension objects and, if necessary, provide Help itself.

Comments

Microsoft Exchange calls the IExchExtCommands::Help method when the user requests Help on a command. If the extension object has added a menu, the cmdid parameter corresponding to that menu is the cmdid parameter of the first command on the menu minus one.

The extension object can provide Help for any command it implements or supersede Microsoft Exchange Help text for an existing command.


 IExchExtCommands::InitMenu

Enables an extension object to update its menu items when the user begins to use the menu.

Syntax

VOID InitMenu (LPEXCHEXTCALLBACK lpeecb)

Parameters

lpeecb

Input parameter pointing to an IExchExtCallback interface. The lpeech parameter is used to determine information about the selection if this is appropriate to the context.

Comments

Microsoft Exchange calls the IExchExtCommands::InitMenu method when it receives a WM_INITMENU message, allowing the extension object to enable, disable, or update its menu commands before the user sees them.This method is called frequently and should be written in a very efficient manner.

If your command extension needs to be enabled when specific message classes or folders are selected, use the IExchExtCallback::GetSelectionCount method to determine whether there currently is a selection, and use the GetSelectionItem method to traverse the selection. You would traverse the selection to see whether the selected objects are of interest to your command extension.

Microsoft Exchange intercepts the EnableMenuItem message and applies the same enabled or disabled state to the associated toolbar button. These menu items and toolbar buttons do not have to be set independently.

See Also

IExchExtCallback::GetSelectionCount method, IExchExtCallback::GetSelectionItem method


 IExchExtCommands::InstallCommands

Enables an extension object to install its menu commands and toolbar command buttons into a Microsoft Exchange window.

Syntax

HRESULT InstallCommands(LPEXCHEXTCALLBACK lpeecb, HWND hwnd, HMENU hmenu; UINT FAR * lpcmdidBase, LPTBENTRY lptbeArray, UINT ctbe, ULONG ulFlags)

Parameters

lpeecb

Input parameter pointing to an IExchExtCallback interface.

hwnd

Input parameter indicating the handle of the top-level Microsoft Exchange window.

hmenu

Input parameter indicating the Microsoft Exchange menu handle.

lpcmdidBase

Input-output parameter pointing to the first command identifier the extension object can use. This is also the command identifier for a menu item or toolbar button.

lptbeArray

Input parameter pointing to an array of toolbars.

ctbe

Input parameter indicating the number of toolbars in the lptbeArray parameter.

ulFlags

Reserved; must be zero.

The following members are used with the TBENTRY structure, which is defined in the EXCHEXT.H header file:

hwnd

Input member indicating the window handle of the toolbar.

tbid

Input member indicating the toolbar identifier. A toolbar identifier distinguishes between multiple toolbars, such as the standard toolbar and the format toolbar. Currently, only the standard toolbar is defined with the EETB_STANDARD value identifier.

ulFlags

Reserved; must be zero.

itbbBase

Input-output member indicating the index of the extension's first toolbar button in the set of available buttons.

Return Values

S_OK

No error occurred.

Comments

Microsoft Exchange calls the IExchExtCommands::InstallCommands method to enable an extension object to install its menu commands and toolbar command buttons into a Microsoft Exchange window. Microsoft Exchange invokes InstallCommands before a top level Microsoft Exchange window, such as the Viewer, is made visible.

To prevent identifier collisions, the lpcmdidBase parameter points to the first identifier the extension object can use for a command identifier. The extension must update the contents of the lpcmdidBase parameter so that on return it contains the first identifier the next extension can use. The lptbeArray parameter contains a list of toolbars with the number of toolbars in the ctbe parameter.

To prevent identifier collisions, the itbbBase parameter contains the index of the extension's first toolbar button in the set of available buttons. This index is not the same as the position of the extension's first button displayed in the toolbar.

The extension object must use the Windows API to add menus, popup menus, and top-level menus. Windows 95 toolbar messages are used on all platforms to register and add toolbar buttons. If an extension object elects to place its toolbar buttons on the toolbar by default, the extension object must add them to the toolbar's set of available buttons when InstallCommands is called and then position those buttons on the toolbar when the IExchExtCommands::ResetToolbar method is called.

If an error is returned, Microsoft Exchange will not try to install another extension and will fail to create the window associated with the context.


 IExchExtCommands::QueryButtonInfo

Provides information about the extension object's toolbar buttons.

Syntax

HRESULT QueryButtonInfo(ULONG tbid, UINT itbb, LPTBBUTTON ptbb, LPTSTR lpsz, UINT cch, ULONG ulFlags)

Parameters

tbid

Input parameter indicating the toolbar identifier.

itbb

Input parameter indicating an index into the list of available buttons.

ptbb

Input-output parameter pointing to a TBBUTTON toolbar button structure, which can be found in the EXCHEXT.H header file.

lpsz

Input parameter pointing to a buffer in which text describing the button should be returned. This description text appears in the Customize Toolbar dialog box. This parameter can be NULL to indicate that text is not required.

cch

Input parameter indicating the size of the buffer pointed to by the lpsz parameter.

ulFlags

Input parameter containing a bitmask of flags. The following flag can be set:

EXCHEXT_UNICODE

Specifies that the lpsz parameter is a unicode string.

Return Values

S_OK

The extension object recognized the itbb parameter and provided information.

S_FALSE

The extension object did not recognize the itbb parameter. Microsoft Exchange will continue to call extension objects and if necessary provide information itself.

Comments

Microsoft Exchange calls the IExchExtCommands::QueryButtonInfo method when it needs information about a toolbar button. Currently only one toolbar is defined, EETB_STANDARD. For information on manipulating toolbars, see the Microsoft Windows 95 Software Developer's Kit.

If an error is returned, Microsoft Exchange will not call other extensions and will use default or null information.


 IExchExtCommands::QueryHelpText

Provides status bar or tool tip Help text for a command.

Syntax

HRESULT QueryHelpText(UINT cmdid, ULONG ulFlags, LPTSTR lpsz, UINT cch)

Parameters

cmdid

Input parameter indicating the command identifier selected by the user.

ulFlags

Input parameter containing a bitmask of flags. The following flags can be set:

EECQHT_STATUS

Microsoft Exchange requests a string to be displayed in the status bar.

EECQHT_TOOLTIP

Microsoft Exchange requests a string to be displayed in a tool tip.

lpsz

Input-output parameter indicating the buffer to be filled with Help text.

cch

Input parameter indicating the size of the lpsz parameter's buffer.

Return Values

S_OK

The extension object recognized the cmdid parameter and returned text in the lpsz parameter.

S_FALSE

The extension object did not recognize the cmdid parameter. Microsoft Exchange will continue to call extension objects and if necessary provide text itself.

Comments

Microsoft Exchange calls the IExchExtCommands::QueryHelpText method  when the user chooses a menu command or selects and holds the mouse down over a toolbar button. The extension object can provide Help text for any commands it implements or supersede Microsoft Exchange Help text for an existing command.

If an error is returned, Microsoft Exchange will not call other extensions and will use a default or blank string.


 IExchExtCommands::ResetToolbar

Enables an extension to restore its toolbar buttons to their default positions.

Syntax

HRESULT ResetToolbar(UINT tbid, ULONG ulFlags)

Parameters

tbid

Input-output parameter indicating the toolbar identifier. Currently, only the EETB_STANDARD toolbar is defined.

ulFlags

Reserved; must be zero.

Return Values

S_OK

No error occurred.

Comments

Microsoft Exchange calls the IExchExtCommands::ResetToolbar method when the user chooses the Reset button from the Customize Toolbar dialog box, which means that the toolbar has been reset to its default state. The extension object should place its default toolbar buttons into their default locations.

See Also

IExchExtCallback::GetToolbar method


 IExchExtMessageEvents : IUnknown

The IExchExtMessageEvents interface is implemented by extension objects and gives them the ability to replace or enhance the default message-handling behavior of Microsoft Exchange. Microsoft Exchange always calls these methods in pairs. For example, if it calls the IExchExtMessageEvents::OnRead method, it also calls the IExchExtMessageEvents::OnReadComplete method; if it calls the IExchExtMessageEvents::OnWrite method, it also calls the IExchExtMessageEvents::OnWriteComplete method, and so forth. The OnReadComplete, OnWriteComplete, IExchExtMessageEvents::OnSubmitComplete, and IExchExtMessageEvents::OnCheckNamesComplete methods are used to undo operations whenever an error occurs. They are also used to release resources that are allocated during calls to the OnRead, OnWrite, IExchExtMessageEvents::OnSubmit, and IExchExtMessageEvents::OnCheckNames methods. For example, an extension object can allocate buffers to validate text during a call to the OnRead method, and deallocate these buffers during a call to the OnReadComplete method.

There is a specific set of steps followed by Microsoft Exhange to handle errors during a call to these functions. This is best illustrated with a specific example that applies to all other methods in this interface. Suppose Microsoft Exchange calls OnCheckNames to notify extensions that it is about to check names and give extensions an opportunity to resolve names. If no extensions return S_OK, Microsoft Exchange performs the name resolution itself. After the resolution is completed or if it failed, Microsoft Exchange calls the OnCheckNamesComplete method of all the extensions whose OnCheckNames method it called, passing in EEME_FAILED if the operation failed. If any extension returns an error from OnCheckNamesComplete, Microsoft Exchange calls each of those extensions again, passing in EEME_COMPLETE_FAILED as the value for the ulFlags parameter. The same series of steps applies to other methods in this interface.

IExchExtMessageEvents is used only in the following contexts: EECONTEXT_SENDNOTEMESSAGE, EECONTEXT_READNOTEMESSAGE,  EECONTEXT_SENDPOSTMESSAGE, EECONTEXT_READPOSTMESSAGE, EECONTEXT_READREPORTMESSAGE, EECONTEXT_SENDRESENDMESSAGE

This interface is optional.

At a Glance

Specified in header file:	EXCHEXT.H
Object that supplies this interface:	Extension object
Corresponding pointer type:	LPEXCHEXTMESSAGEEVENTS
Implemented by:	Extension objects
Called by:	Microsoft Exchange
Vtable Order

OnRead	Replaces or enhances the behavior of Microsoft Exchange when reading information from a message.
OnReadComplete	Enables extension objects to roll back their implementation of the OnRead method in case of an error or to release resources allocated by OnRead.
OnWrite	Replaces or enhances the behavior of Microsoft Exchange when writing information to a message.
OnWriteComplete	Enables extension objects to roll back their implementation of the OnWrite method in case of an error or to release resources allocated by OnWrite.
OnCheckNames	Replaces or enhances the behavior of Microsoft Exchange when recipient names typed by the user are being resolved to their address book entries.
OnCheckNamesComplete	Enables extension objects to roll back their implementation of the OnCheckNames method in case of an error or to release resources allocated by OnCheckNames.
OnSubmit	Replaces or enhances the behavior of Microsoft Exchange when a message has been submitted.
OnSubmitComplete	Enables extension objects to roll back their implementation of the OnSubmit method in case of an error or to release resources allocated by OnSubmit.


 IExchExtMessageEvents::OnCheckNames

Replaces or enhances the behavior of Microsoft Exchange when recipient names typed by the user are being resolved to their address book entries.

Syntax

HRESULT OnCheckNames(LPEXCHEXTCALLBACK lpeecb)

Parameters

lpeecb

Input parameter pointing to the IExchExtCallback interface. The lpeecb parameter is used to determine information about the message and the window containing the unresolved names.

Return Values

S_OK

The extension object replaced Microsoft Exchange behavior and handled the name resolution on its own. Microsoft Exchange will consider the task handled.

S_FALSE

The extension object did nothing or added additional behavior. See the text provided in the definition of the IExchExtMessageEvents interface in this reference.

Comments

Microsoft Exchange calls the IExchExtMessageEvents::OnCheckNames method when it is about to resolve unresolved names.

If an error occurs, OnCheckNames should display an error message and return an error. Microsoft Exchange will not continue to check names, nor will it display an error message, but will stop the user action that caused the check names operation. This method should call the IExchExtCallback::GetObject method to determine the message identifier of the item being displayed and its container. The container is usually a folder, but it can also be a message or an information store.

See Also

IExchExtCallback::GetObject method, IExchExtMessageEvents : IUnknown interface


 IExchExtMessageEvents::OnCheckNamesComplete

Enables extension objects to roll back their implementation of the IExchExtMessageEvents::OnCheckNames method in case of an error or to release resources allocated by OnCheckNames.

Syntax

HRESULT OnCheckNamesComplete(LPEXCHEXTCALLBACK lpeecb, ULONG ulFlags)

Parameters

lpeecb

Input parameter pointing to the IExchExtCallback interface. The lpeecb parameter is used to determine information about the message and the window containing the unresolved names.

ulFlags

Input parameter containing a bitmask of flags. The following flags can be set:

EEME_FAILED

Indicates that the check names operation could not be completed successfully. See the text provided in the definition of the IExchExtMessageEvents interface in this reference.

EEME_COMPLETE_FAILED

See the text provided in the definition of the IExchExtMessageEvents interface in this reference.

Return Values

S_OK

The extension object handled the event. Microsoft Exchange will consider the task handled.

S_FALSE

The extension object did nothing or added additional behavior. Microsoft Exchange will continue to call extensions or complete the work itself.

Comments

Microsoft Exchange calls the IExchExtMessageEvents::OnCheckNamesComplete method after it has resolved the addresses. This method should call the IExchExtCallback::GetObject method to determine the message identifier of the item being displayed and its container. The container is usually a folder, but it can also be a message or an information store.

See Also

IExchExtCallback::GetObject method, IExchExtMessageEvents : IUnknown interface


 IExchExtMessageEvents::OnRead

Replaces or enhances the behavior of Microsoft Exchange when reading information from a message.

Syntax

HRESULT OnRead(LPEXCHEXTCALLBACK lpeecb)

Parameters

lpeecb

Input parameter pointing to the IExchExtCallback interface. The lpeecb parameter is used to determine information about the message being read and the window whose controls are to be populated.

Return Values

S_OK

The extension object replaced Microsoft Exchange behavior and populated the window used to display the message. Microsoft Exchange will consider the task handled.

S_FALSE

The extension object did nothing or added additional behavior. Microsoft Exchange will continue to call extension objects or complete the work itself.

Comments

Microsoft Exchange calls the IExchExtMessageEvents::OnRead method when it is about to read the properties of a message so that they can be displayed to the user in a standard form. If an error occurs, OnRead should display an error message and return an error. Microsoft Exchange will not continue to read the message, nor will it display an error message, but will stop the user action that caused the read operation to occur.

This method should call the IExchExtCallback::GetObject method to determine the message identifier of the item being read and its container. The container is usually a folder, but it can also be a message or an information store.

See Also

IExchExtCallback::GetObject method, IExchExtMessageEvents : IUnknown interface


 IExchExtMessageEvents::OnReadComplete

Enables extension objects to roll back their implementation of the IExchExtMessageEvents::OnRead method in case of an error or to release resources allocated by the OnRead method.

Syntax

HRESULT OnReadComplete(LPEXCHEXTCALLBACK lpeecb, ULONG ulFlags)

Parameters

lpeecb

Input parameter pointing to the IExchExtCallback interface. The lpeecb parameter is used to determine information about the message being read and the window whose controls are to be populated.

ulFlags

EEME_FAILED

Indicates that the check names operation could not be completed successfully. See the text provided in the definition of the IExchExtMessageEvents interface in this reference.

EEME_COMPLETE_FAILED

See the text provided in the definition of the IExchExtMessageEvents interface in this reference.

Return Values

S_OK

The extension object handled the event. Microsoft Exchange will consider the task handled.

S_FALSE

The extension object did nothing or added additional behavior. Microsoft Exchange will continue to call extensions or complete the work itself.

Comments

Microsoft Exchange calls the IExchExtMessageEvents::OnReadComplete method when it has finished reading the properties of a message for display to the user in a standard form.

If an error occurs, OnReadComplete should display an error message and return an error. Microsoft Exchange will then call each extension object again with OnReadComplete with ulFlags = EEME_FAILED to indicate that the read operation failed. Microsoft Exchange will not continue to read the message, nor will it display an error message, but will stop the user action that caused the read operation.

OnReadComplete should call the IExchExtCallback::GetObject method to determine the message identifier of the item being read and its container. The container is usually a folder, but it can also be a message or an information store.

See Also

IExchExtCallback::GetObject method, IExchExtMessageEvents : IUnknown interface


 IExchExtMessageEvents::OnSubmit

Replaces or enhances the behavior of Microsoft Exchange when a message has been submitted.

Syntax

HRESULT OnSubmit(LPEXCHEXTCALLBACK lpeecb)

Parameters

lpeecb

Input parameter pointing to the IExchExtCallback interface. The lpeecb parameter is used to determine information about the message being submitted and the window whose controls were saved.

Return Values

S_OK

The extension object replaced Microsoft Exchange behavior and handled the submission on its own. Microsoft Exchange will consider the task handled.

S_FALSE

The extension object did nothing or added additional behavior. Microsoft Exchange will continue to call extensions or complete the work itself.

Comments

Microsoft Exchange calls the IExchExtMessageEvents::OnSubmit method when it is about to submit an open message. At this point, the information will have been written to the message.

If an error occurs, OnSubmit should display an error message and return an error. Microsoft Exchange will not submit the message, nor will it display an error message, but will stop the user action that caused the submit.

This method should call the IExchExtCallback::GetObject method to determine the message identifier of the item being submitted and its container. The container is usually a folder, but it can also be a message or an information store.

See Also

IExchExtCallback::GetObject method, IExchExtMessageEvents : IUnknown interface


 IExchExtMessageEvents::OnSubmitComplete

Enables extension objects to roll back their implementation of the IExchExtMessageEvents::OnSubmit method in case of an error or to release resources allocated by OnSubmit.

Syntax

VOID OnSubmitComplete(LPEXCHEXTCALLBACK lpeecb, ULONG ulFlags)

Parameters

lpeecb

Input parameter pointing to the IExchExtCallback interface. The lpeecb parameter is used to determine information about the message and the window containing the displayed information.

ulFlags

EEME_FAILED

Indicates that the check names operation could not be completed successfully. See the text provided in the definition of the IExchExtMessageEvents interface in this reference.

EEME_COMPLETE_FAILED

See the text provided in the definition of the IExchExtMessageEvents interface in this reference.

Comments

The IExchExtMessageEvents::OnSubmitComplete method is used to enable extension objects to roll back the Microsoft Exchange default implementation of the IExchExtMessageEvents::OnSubmit method. OnSubmitComplete should call the IExchExtCallback::GetObject method to determine the message identifier of the item being submitted and its container. The container is usually a folder, but it can also be a message or an information store.

This method returns VOID because at this point the message should have already been submitted, so it is too late to cancel the operation.

See Also

IExchExtCallback::GetObject method, IExchExtMessageEvents : IUnknown interface


 IExchExtMessageEvents::OnWrite

Replaces or enhances the behavior of Microsoft Exchange when writing information to a message.

Syntax

HRESULT OnWrite(LPEXCHEXTCALLBACK lpeecb)

Parameters

lpeecb

Input parameter pointing to the IExchExtCallback interface. The lpeecb parameter is used to determine information about the message being written and the window whose controls are to be saved.

Return Values

S_OK

The extension object replaced Microsoft Exchange behavior and handled writing out the information on its own. Microsoft Exchange will consider the task handled.

S_FALSE

The extension object did nothing or added additional behavior. Microsoft Exchange will continue to call extension objects or complete the work itself.

Comments

Microsoft Exchange calls the IExchExtMessageEvents::OnWrite method when it is about to write the contents of a standard form to the properties of a message. If an error occurs, the extension object should display an error message and return an error. Microsoft Exchange will not continue to write the message, call another extension object's OnWrite method, or display an error message. However, it will stop the user action that caused the write operation.

This method should call the IExchExtCallback::GetObject method to determine the message identifier of the item being written and its container. The container is usually a folder, but it can also be a message or an information store.

See Also

IExchExtCallback::GetObject method, IExchExtMessageEvents : IUnknown interface


 IExchExtMessageEvents::OnWriteComplete

Enables extension objects to roll back the Microsoft Exchange default implementation of the IExchExtMessageEvents::OnWrite method in case of an error or to release resources allocated by OnWrite.

Syntax

HRESULT OnWriteComplete(LPEXCHEXTCALLBACK lpeecb, ULONG ulFlags)

Parameters

lpeecb

Input parameter pointing to the IExchExtCallback interface. The lpeecb parameter is used to determine information about the message that was written and the window whose controls are to be saved.

ulFlags

EEME_FAILED

Indicates that the check names operation could not be completed successfully. See the text provided in the definition of the IExchExtMessageEvents interface in this reference.

EEME_COMPLETE_FAILED

See the text provided in the definition of the IExchExtMessageEvents interface in this reference.

Return Values

S_OK

The extension object successfully rolled back the write operation and freed resources.

S_FALSE

The extension object did nothing or added additional behavior. Microsoft Exchange will continue to call extensions or complete the work itself.

Comments

Microsoft Exchange calls the IExchExtMessageEvents::OnWriteComplete method after it has finished writing the contents of a standard form to the properties of a message. If an error occurs, the extension object should display an error message and return an error. Microsoft Exchange will then call each extension object again with OnWriteComplete with ulFlags = EEME_FAILED to indicate that the write operation failed.

The extension object should free resources used for the write operation.

This method should call the IExchExtCallback::GetObject method to determine the message identifier of the item being written and its container. The container is usually a folder, but it can also be a message or an information store.

See Also

IExchExtCallback::GetObject method, IExchExtMessageEvents : IUnknown interface


 IExchExtModeless : IUnknown

The IExchExtModeless interface enables modeless extensions to coordinate their actions with Microsoft Exchange.

IExchExtModeless should not be implemented by extensions as another interface on their main extension interface, but should instead be implemented on a separate object with its own independent set of reference counts.

This interface is optional.

At a Glance

Specified in header file:	EXCHEXT.H
Object that supplies this interface:	Extension object
Corresponding pointer type:	LPEXCHEXTMODELESS
Implemented by:	Extension objects
Called by:	Microsoft Exchange
Vtable Order

TranslateAccelerator	Enables an extension object to intercept messages before they are processed by the Microsoft Exchange client.
EnableModeless	Notifies an extension object to disable its modeless windows.


 IExchExtModeless::EnableModeless

Enables extension objects to enable or disable their modeless windows.

Syntax

HRESULT EnableModeless(HWND hwnd, BOOL fEnable)

Parameters

hwnd

Input parameter pointing to the handle of the parent window of the modal window being displayed or removed.

fEnable

Input parameter set to TRUE when Microsoft Exchange should enable its modeless windows (that is, when the extension has removed a modal window). Set to FALSE when Microsoft Exchange should disable its modeless windows (that is, when the extension is about to display a modal window).

Return Values

S_OK

No error occurred.

Comments

Microsoft Exchange uses the IExchExtModeless::EnableModeless method to notify extension objects that they should enable or disable their modeless windows. If an extension has registered for modeless behavior using the IExchExtCallback::RegisterModeless method and has called the IExchExtModelessCallBack::AddWindow method, Microsoft Exchange calls the extension's EnableModeless method when it displays or removes a modal window. In the case of creation, the extension object should disable its modeless windows; in the case of removal, the extension object should enable its modeless windows.


 IExchExtModeless::TranslateAccelerator

Enables modeless extensions to intercept and handle messages.

Syntax

HRESULT TranslateAccelerator(LPMSG pmsg)

Parameters

pmsg

An input parameter pointing to the message.

Return Values

S_OK

The message was handled by the extension object.

S_FALSE

The message was not handled by the extension object.

Comments

The IExchExtModeless::TranslateAccelerator method is used to enable modeless extension objects to intercept and handle messages. While running in-process, an extension object might need to intercept and handle various messages that would otherwise be handled by Microsoft Exchange. If the extension object has registered for modeless behavior using the IExchExtCallback::RegisterModeless method and has called the IExchExtModelessCallBack::AddWindow method, the Microsoft Exchange client will call TranslateAccelerator whenever it receives a Windows message. If the extension object handles the message, it should return S_OK to prevent Microsoft Exchange from handling the same message.


 IExchExtModelessCallback : IUnknown

The IExchExtModelessCallback interface is implemented by the Microsoft Exchange client to coordinate with extension objects using a modeless user interface.

At a Glance

Specified in header file:	EXCHEXT.H
Object that supplies this interface:	Extension object
Corresponding pointer type:	LPEXCHEXTMODELESSCALLBACK
Implemented by:	Microsoft Exchange
Called by:	Extension objects
Vtable Order

EnableModeless	Enables the Microsoft Exchange client to enable or disable its modeless windows.
AddWindow	Enables Microsoft Exchange to keep track of modeless windows displayed by extension objects.
ReleaseWindow	Enables the Microsoft Exchange client to keep track of modeless windows displayed by extension objects.


 IExchExtModelessCallback::AddWindow

Enables Microsoft Exchange to keep track of modeless windows that are displayed by extensions.

Syntax

HRESULT AddWindow()

Return Values

S_OK

No error occurred.

Comments

Extension objects should call the IExchExtModelessCallback::AddWindow method when they display a modeless window. This method, along with the IExchExtModelessCallback::ReleaseWindow method, enables Microsoft Exchange to keep track of modeless windows that are displayed by extensions. Microsoft Exchange will not terminate until all extension windows have been closed. It is not necessary to call this method multiple times when multiple modeless windows are displayed.

To enable users to exit Microsoft Exchange with one command, modeless extensions should intercept the Microsoft Exchange Exit and Exit and Logoff commands on the File menu. By doing so, extensions can prompt the user to save any changes that have been made and then close the user's modeless windows, returning S_FALSE to enable other extensions to close their windows as well. In this way, extensions can cooperate with Microsoft Exchange when a user wants to close all windows and exit.

See Also

IExchExtModelessCallback::ReleaseWindow method


 IExchExtModelessCallback::EnableModeless

Extension objects should call this method just before they display or remove a modal dialog box, allowing the Microsoft Exchange client to enable or disable its modeless windows.

Syntax

HRESULT EnableModeless(HWND hwnd, BOOL fEnable)

Parameters

hwnd

Input parameter containing the handle of the parent window of the modal window being displayed or removed.

fEnable

Input parameter. Set to FALSE when your extension is going to display a modal window. Set to TRUE when your extension has removed its modal window.

Return Values

S_OK

No error occurred.

Comments

If an extension object calls the IExchExtModelessCallback::EnableModeless method when it creates or removes a modal window, the Microsoft Exchange client will disable or enable its modeless windows as appropriate.


 IExchExtModelessCallback::ReleaseWindow

Enables the Microsoft Exchange client to be notified when an extension object's modeless windows have been removed.

Syntax

HRESULT ReleaseWindow()

Return Values

S_OK

No error occurred.

Comments

Extension objects should call the IExchExtModelessCallback::ReleaseWindow method when they release all their modeless windows. This method, along with the IExchExtModelessCallback::AddWindow method, enables the Microsoft Exchange client to keep track of modeless windows displayed by extensions. Microsoft Exchange cannot be closed until all extension windows have been closed.

Extensions are expected to make an equal number of calls to AddWindow and ReleaseWindow. For example, if an extension calls AddWindow for every modeless window it displays, it should call ReleaseWindow for each modeless window it closes. Similarly, if an extension calls AddWindow only once for its modeless windows, it should call ReleaseWindow only once when the last of the extension's modeless windows is closed.

To enable users to exit Microsoft Exchange with one command, modeless extensions should intercept the Exit and Exit and Logoff commands on the Microsoft Exchange File menu. By doing so, extensions can prompt the user to save any changes that have been made and then close the user's modeless windows, returning S_FALSE to enable other extensions to close their windows as well. In this way, extensions can cooperate with Microsoft Exchange when a user wants to close all windows and exit.

See Also

IExchExtModelessCallback::AddWindow method


 IExchExtPropertySheets : IUnknown

The IExchExtPropertySheets interface is used to enable extension objects to append pages to Microsoft Exchange property sheets. IExchExtPropertySheets is used only in the EECONTEXT_PROPERTYSHEETS context.

For more information on property sheets, see the Win32 documentation.

This interface is optional.

At a Glance

Specified in header file:	EXCHEXT.H
Object that supplies this interface:	Extension object
Corresponding pointer type:	LPEXCHEXTPROPERTYSHEETS
Implemented by:	Extension objects
Called by:	Microsoft Exchange
Vtable Order

GetMaxPageCount	Returns the maximum number of pages an extension will add to the property sheet.
GetPages	Adds property sheet pages to the current list of pages.
FreePages	Frees any resources allocated by the GetPages method.


 IExchExtPropertySheets::FreePages

Frees all resources allocated by the IExchExtPropertSheets::GetPages method.

Syntax

VOID FreePages(LPPROPSHEETPAGE lppsp, ULONG ulFlags, ULONG cpsp)

Parameters

lppsp

Input parameter pointing to a variable where the pointer to the first page of a list of property sheet pages previously added is stored. The extension object should not free the memory associated with the lppsp parameter because this parameter points to an element of an array allocated by Microsoft Exchange.

cpsp

Input parameter containing the number of property sheet pages added to the lppsp parameter by the extension object.

ulFlags

Input parameter containing a bitmask of flags used to indicate the type of property sheet whose pages are being freed. The following flags can be set:

EEPS_MESSAGE

Indicates a message's property sheet.

EEPS_FOLDER

Indicates a folder's property sheet.

EEPS_STORE

Indicates a store's property sheet.

EEPS_TOOLSOPTIONS

Indicates the Tools.Options property sheet.

Comments

Microsoft Exchange calls the IExchExtPropertySheets::FreePages method when the user closes the properties dialog box and Microsoft Exchange prompts the extension objects to free their pages and other associated resources and interfaces.


 IExchExtPropertySheets::GetMaxPageCount

Returns a value for the maximum number of pages an extension object will add to the property sheet.

Syntax

ULONG GetMaxPageCount(ULONG ulFlags)

Parameters

ulFlags

Input parameter containing a bitmask of flags used to indicate the type of property sheet being displayed. The following flags can be set:

EEPS_MESSAGE

Indicates a message's property sheet.

EEPS_FOLDER

Indicates a folder's property sheet.

EEPS_STORE

Indicates a store's property sheet.

EEPS_TOOLSOPTIONS

Indicates the Tools.Options property sheet.

Comments

Microsoft Exchange calls the IExchExtPropertySheets::GetMaxPageCount method when it is allocating memory for the property sheet page array. The value returned by this method represents the maximum number of pages to be shown at any one time not the sum of all property sheet pages for all objects.


 IExchExtPropertySheets::GetPages

Adds property sheet pages to the current list of pages.

Syntax

HRESULT GetPages(LPEXCHEXTCALLBACK lpeecb, ULONG ulFlags, LPPROPSHEETPAGE lppsp, ULONG FAR * lpcpsp)

Parameters

lpeecb

Input parameter pointing to the IExchExtCallback interface.

ulFlags

Input parameter containing a bitmask of flags used to indicate the type of property sheet being displayed. The following flags can be set:

EEPS_MESSAGE

Indicates a message's property sheet.

EEPS_FOLDER

Indicates a folder's property sheet.

EEPS_STORE

Indicates a store's property sheet.

EEPS_TOOLSOPTIONS

Indicates the Tools.Options property sheet.

lppsp

Output parameter pointing to a variable that stores the pointer to a list of property sheet pages the extension will fill.

lpcpsp

Output parameter pointing to a variable containing the number of property sheet pages actually filled in by the extension object. The number must be less than or equal to the maximum requested by the IExchExtPropertySheets::GetMaxPageCount method.

Return Values

S_OK

No error occurred.

Comments

Microsoft Exchange calls the IExchExtPropertySheets::GetPages method when it is building a property sheet and needs each extension object to fill in any pages that will be appended. Microsoft Exchange, not the extension object, handles the allocation of the page array pointed to by the lppsp parameter. Microsoft Exchange allocates this array after it calls the extension object and gets the value returned by the IExchExtPropertySheets::GetMaxPageCount method. The extension object should not allocate its own pages in the lppsp parameter, nor should it free them when the IExchExtPropertySheets::FreePages method is called. Instead, it should free the additional resources added during the call to GetPages.

The Windows 95 property sheet structures are used to describe the pages.


 IExchExtSessionEvents : IUnknown

The IExchExtSessionEvents interface is used to enable an extension object to respond to the arrival of new messages. This interface can be used to create rules-based inbox processing and other custom handling of new messages. IExchExtSessionEvents is used only in the EECONTEXT_SESSION context.

This interface is optional.

At a Glance

Specified in header file:	EXCHEXT.H
Object that supplies this interface:	Extension object
Corresponding pointer type:	LPEXCHEXTSESSIONEVENTS
Implemented by:	Extension objects
Called by:	Microsoft Exchange
Vtable Order

OnDelivery	Replaces or enhances the behavior of Microsoft Exchange when a new message arrives.


 IExchExtSessionEvents::OnDelivery

Replaces or enhances the behavior of Microsoft Exchange when a new message arrives.

Syntax

HRESULT OnDelivery(LPEXCHEXTCALLBACK lpeecb)

Parameters

lpeecb

Input parameter pointing to the IExchExtCallback interface. The lpeecb parameter is used to determine information about the message or messages which have arrived.

Return Values

S_OK

The extension object replaced Microsoft Exchange default behavior with its own behavior. Microsoft Exchange will consider the task handled.

S_FALSE

The extension object did nothing or added additional behavior. Microsoft Exchange will continue to call extension objects or complete the work itself.

Comments

The IExchExtSessionEvents::OnDelivery method is used to replace or enhance the behavior of Microsoft Exchange when a new message arrives. If an error occurs, OnDelivery should display an error message and return an error value. Microsoft Exchange will not notify the user about the new message, nor will it display an error message or continue to call extension objects in response to the new message.

When a new message arrives, the extension object obtains its message identifier by calling the IExchExtCallback::GetObject method.

See Also

IExchExtCallback::GetObject method


 IExchExtUserEvents : IUnknown

The IExchExtUserEvents interface is used to enable an extension object to handle changes to the currently-selected list box item, text, or object. IExchExtUserEvents is used in all contexts except EECONTEXT_TASK and EECONTEXT_SESSION.

This interface is optional.

At a Glance

Specified in header file:	EXCHEXT.H
Object that supplies this interface:	Extension object
Corresponding pointer type:	LPEXCHEXTUSEREVENTS
Implemented by:	Extension objects
Called by:	Microsoft Exchange
Vtable Order

OnSelectionChange	Enables the extension object to enable, disable, or update visual elements.
OnObjectChange	Enables the extension object to enable, disable, or update visual elements in an object.


 IExchExtUserEvents::OnObjectChange

Enables the extension object to enable, disable, or update visual elements in an object displayed in the window.

Syntax

VOID OnObjectChange (LPEXCHEXTCALLBACK lpeecb)

Parameters

lpeecb

Input parameter pointing to the IExchExtCallback interface. The lpeech parameter is used to determine information about the selection.

Comments

Microsoft Exchange calls the IExchExtUserEvents::OnObjectChange method when the object within the container displayed by the Microsoft Exchange window changes. For example, this method is called when a user changes a folder whose contents are displayed in the Viewer, or when the user moves to the next message in cases where the message's class permits the same window to be used.

OnObjectChange should call the IExchExtCallback::GetObject method to determine the identifier of the changed object and its container. The container is usually a folder, but it can also be a message or an information store.

See Also

IExchExtCallback::GetObject method


 IExchExtUserEvents::OnSelectionChange

Enables the extension object to enable, disable, or update visual elements.

Syntax

VOID OnSelectionChange(LPEXCHEXTCALLBACK lpeecb)

Parameters

lpeecb

Input parameter pointing to an IExchExtCallback interface that is used to determine information about the currently selected item.

Comments

Microsoft Exchange calls the IExchExtUserEvents::OnSelectionChange method when the currently selected message, folder or store changes in a Microsoft Exchange window. This method is also called when a selection in a list box changes or when the current selection of text in a form changes. For example, this method is called when an item is selected in a Viewer list box, or when text is selected in a note form. It is also called when the user changes the currently selected message or folder.

This method might be called very frequently and should therefore be implemented efficiently.

This method should call the IExchExtCallback::GetObject method to determine the identifier of the newly selected object and its container.

See Also

IExchExtCallback::GetObject method


Using Compress and Expand

You can use the Microsoft File Compression Utility (Compress) and Microsoft File Expansion Utility (Expand) to prepare your application files for distribution or as part of the installation process for your application. Compress reduces the size of files so that more files can fit on a disk. Expand restores compressed files to their original size. Both Compress and Expand are run from the operating-system command line.


Compress Utility

You can use the Compress utility (COMPRESS.EXE) to reduce one or more files to 25 to 45 percent of their original size.

To use Compress, use the following syntax:

COMPRESS [/?] [[/r] source destination

Compress provides the following command-line options:

/?

Displays information on using Compress.

/r

Specifies that compressed files should be renamed.

-z

Specifies the MS-ZIP compression used for files distributed by Microsoft.

source

Specifies the source filename. The filename can include a drive letter, a directory path, or both; it can also contain wildcards.

destination

Specifies the destination. This parameter can consist of a directory (with optional drive letter), a filename, or any combination of the two.

If the source parameter contains wildcards and the destination parameter does not specify a directory, the /r option must be used.

If the destination parameter does not contain a filename, the filename specified in the source option will be used when the file is copied to the location specified by the destination option.


Expand Utility

The Expand utility (EXPAND.EXE) restores compressed files to their original size.

To use Expand, use the following syntax:

EXPAND [/?] [[/r] source destination

Expand provides the following command-line options:

/?

Displays information on using Expand.

/r

Specifies that expanded files should be renamed.

Unlike the Compress utility (COMPRESS.EXE), Expand does not have a -z switch. Expand determines the compression type used and automatically decompresses it. You can also use VerInstallFile to expand MS_ZIP files.

source

Specifies the source filename. The filename can include a drive letter, a directory path, or both; it can also contain wildcards.

destination

Specifies the destination. This parameter can consist of a directory (with optional drive letter), a filename, or any combination of the two.

If the source parameter contains wildcards and the destination parameter does not specify a directory, the file must be renamed using the /r option.

If the destination parameter does not contain a filename, the filename specified in the source option will be used when the file is copied to the location specified by the destination parameter.

The following example shows how to expand all of the files on drive A and copy them to a directory on drive C.

expand a:*.* c:\mydir


Creating Help Files

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

This section introduces the tools you can use to develop Windows Help files and to incorporate Help in Windows-hosted applications.


About Windows Help Files

Windows Help files can display information by using the following elements:

•	Text in multiple fonts, sizes, and colors

•	Bitmaps and metafiles with up to 16 colors

•	Segmented-graphics bitmaps with embedded hot spots

•	Cross-reference jumps for links to additional information

•	Pop-up windows to present text and graphics

•	Secondary windows to present information without the full menus and buttons of Windows Help

•	Keywords to help users find the information they need

You create Help files by creating topic and graphics files and a Help project file. A topic file contains the text for the Help topic and contains the Help statements and macros that define the format of the text and the position of graphics in each topic. The graphics files contain the bitmaps and metafiles you want to display in the topics. The project file contains a description of how to build the Help file.

You use the Microsoft Help Compiler to build the final Help file. Combining the topic, graphics, and project files, the compiler creates a single Help file (with the filename extension .HLP) that you can open and view by using Windows Help.


Creating Topic Files

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

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

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


Declaring Character Set, Fonts, and Colors

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

{\rtf1\ansi
    .
    .
    .
}

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

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

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

\deff0

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

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

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


Defining Individual Topics

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

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

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

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

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

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

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

!{\footnote CopyTopic()}

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

The total size of text and graphics data stored in a paragraph must not exceed 64K. (Bitmaps included by using the bmc, bml, and bmr statements do not contribute to this total.)


Setting Font Size and Name

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

\f0\fs20

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


Setting Space Before and After Paragraphs

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

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

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


Setting the Left and Right Indents

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

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

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

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

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


Setting Tab Stops

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

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


Breaking Lines

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

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

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

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

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


Creating Links and Pop-up Topics

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

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

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

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

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

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

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


Creating a Keyword List

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

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

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

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

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


Creating Browse Sequences

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

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

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

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

[CONFIG]
BrowseButtons()

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

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

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


Using Graphics Files

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

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

•	Windows bitmap (.BMP)

•	Placeable Windows metafile (.WMF)

•	Multiple-resolution bitmap (.MRB)

•	Segmented-graphics bitmap (.SHG)

Multiple-resolution bitmaps can be created by using the Microsoft Multiple-Resolution Bitmap Compiler (MRBC). Segmented-graphics bitmaps can be created by using Microsoft Windows Hotspot Editor. Only 16-color and monochrome bitmaps may be used. Windows Help does not support 256-color bitmaps.

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


Inserting a Bitmap in Text

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

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

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

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

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


Wrapping Text Around a Bitmap

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

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

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

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


Using a Bitmap as a Hot Spot

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

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

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

\{bml mydialog.shg\}


Using a Bitmap on Different Displays

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

•	Appear too big or too small on displays having different resolutions

•	Appear stretched or compressed on displays with different aspect ratios

•	Lack colors or use unintended colors on displays with different color capabilities

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

mrbc [/s] filename

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

mrbc mybutton.ega mybutton.vga mybutton.854

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

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

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

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

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

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

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

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

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

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


Creating Help Project Files

This section describes the format and contents of the Help project file (.HPJ) used to build the Help file. The project file contains all the information the Microsoft Help Compiler needs to combine topic files and other elements into a Help file.


Project File Sections

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

Section	Description
[OPTIONS]	Specifies options that control the build process. This section is optional. If this section is used, it should be the first section listed in the project file, so that the options will apply during the entire build process.
[FILES]	Specifies topic files to be included in the build. This section is required.
[BUILDTAGS]	Specifies valid build tags. This section is optional.
[CONFIG]	Specifies Help macros that define nonstandard menus, buttons, and macros used in the Help file. This section is required if the Help file uses any of these features. This section is new for Windows 3.1.
[BITMAPS]	Specifies bitmap files to be included in the build. This section is not required if the project file lists a path for bitmap files by using the BMROOT or ROOT option.
[MAP]	Associates context strings with context numbers. This section is optional.
[ALIAS]	Assigns one or more context strings to the same topic. This section is optional.
[WINDOWS]	Defines the characteristics of the primary Help window and the secondary-window types used in the Help file. This section is required if the Help file uses secondary windows. This section is new for Windows 3.1.
[BAGGAGE]	Lists files that are to be placed within the Help file (which contains its own file system). This section is optional.
Every project file requires a [FILES] section. This section names the topic files. Most project files also have an [OPTIONS] section that specifies how to build the Help file. A very useful option in the [OPTIONS] section is the COMPRESS option, which specifies whether the Help file should be compressed or uncompressed. Compressing a Help file reduces its size considerably and saves valuable disk space.

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

[OPTIONS]
COMPRESS=TRUE

[FILES]
MAIN.RTF
MENUS.RTF


Using Macros in Project Files

You can add macros to the [CONFIG] section of a project file. Since Windows Help executes the macros when it first opens the Help file, macros that create menus, menu items, and buttons are typically placed in this section. If there is more than one macro listed in the [CONFIG] section, Windows Help executes them in the order in which they are listed.

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

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


Sample Project File

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

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

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

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

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


Using Help in a Windows Application

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


Choosing Help from the Help Menu

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

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

    }
    break;

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

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

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

[MAP]
IDM_HELP_KEYBOARD   101

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

#define IDM_HELP_KEYBOARD 101

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

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

[MAP]
#include <myhelp.h>

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


Choosing Help with the Keyboard

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

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

The filter procedure should have the following form:

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

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

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

    return 0;
}

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

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

lpFilterFunc = SetWindowsHook(WH_MSGFILTER, lpProcInstance);

Like all callback functions, the filter procedure must be exported by the application.

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

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

1 ACCELERATORS
BEGIN
    VK_F1, IDM_HELP_CONTENTS, VIRTKEY
END

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

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

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

    if (HIWORD(lParam) == 0)             /* no menu selected    */
        dwCurrentHelpId = ID_NONE;

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

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

    break;

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

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

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

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

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

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

        WinHelp(hWnd, szHelpFileName, HELP_CONTEXT, dwHelp);

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

        DrawMenuBar(hWnd);
    }

    break;

When the application ends, it must remove the filter procedure by using the UnhookWindowsHook function and free the procedure instance for the function by using the FreeProcInstance function.


Choosing Help with the Mouse

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

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

case WM_KEYDOWN:
    if (wParam == VK_F1) {

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

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

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

        else {
            WinHelp(hwnd,"myhelp.hlp",HELP_CONTENTS,0L);
        }
    }

    else if (wParam == VK_ESCAPE && bHelp) {

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

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

    break;

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

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

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

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

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

    return (TRUE);

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

case WM_NCLBUTTONDOWN:
    /*
     * If in Help mode (Shift+F1), display context-sensitive
     * Help for nonclient area.
     */

    if (bHelp) {
        dwHelpContextId =
            (wParam == HTCAPTION) ?(DWORD) HELPID_TITLE_BAR:
            (wParam == HTSIZE) ? (DWORD) HELPID_SIZE_BOX:
            (wParam == HTREDUCE) ? (DWORD) HELPID_MINIMIZE_ICON:
            (wParam == HTZOOM) ? (DWORD) HELPID_MAXIMIZE_ICON:
            (wParam == HTSYSMENU) ?(DWORD) HELPID_SYSTEM_MENU:
            (wParam == HTBOTTOM) ? (DWORD) HELPID_SIZING_BORDER:
            (wParam == HTBOTTOMLEFT) ? (DWORD) HELPID_SIZING_BORDER:
            (wParam == HTBOTTOMRIGHT) ?(DWORD) HELPID_SIZING_BORDER:
            (wParam == HTTOP) ?(DWORD) HELPID_SIZING_BORDER:
            (wParam == HTLEFT) ?(DWORD) HELPID_SIZING_BORDER:
            (wParam == HTRIGHT) ?(DWORD) HELPID_SIZING_BORDER:
            (wParam == HTTOPLEFT) ?(DWORD) HELPID_SIZING_BORDER:
            (wParam == HTTOPRIGHT) ? (DWORD) HELPID_SIZING_BORDER:
            (DWORD) 0L;

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

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

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

case WM_COMMAND:

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

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


Searching for Help with Keywords

An application can enable the user to search for Help topics based on full or partial keywords. This method is similar to employing the Search dialog box in Windows Help to find useful topics. The following example searches for the keyword "Keyboard" and displays the corresponding topic, if found:

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

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

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

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

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

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

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

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

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

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

GlobalUnlock(hglblmkh);
GlobalFree(hglblmkh);

If the keyword is not found, Windows Help displays an error message. If more than one topic has the keyword, Windows Help displays only the first topic. (For a full description of the MULTIKEYHELP structure, see the Microsoft Programmer's Reference.)

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


Displaying Help in a Secondary Window

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

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

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

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

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

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

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

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

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

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

GlobalUnlock(hhwi);
GlobalFree(hhwi);


Canceling Help

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

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

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

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


Windows Help Statements and Macros

This section describes the syntax and purpose of statements and macros used in topic and project files for the Microsoft Windows Help application. The Windows Help statements define the format and placement of text and graphics in the Help file. The Windows Help macros define actions to take while the Help file is being viewed, such as creating custom buttons and carrying out menu commands.


Help Statement Syntax

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

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

left column\tab right column

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

•	A space.

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

•	Any character other than a letter or digit.

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

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

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

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


Help Macro Syntax

Windows Help macros specify actions that Windows Help takes when it loads Help or displays a topic. (Help macros may also be executed when the user selects a hotspot or when the user clicks on a designated segmented-graphic.) A Help macro consists of a macro name and parameters enclosed in parentheses.

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

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

'command "string as parameter"'

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

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

A Help macro and all of its parameters must not exceed 512 characters.

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


Help Project File Reference

This section describes the different sections and options in a Help project file and gives examples of their use. The entries are in alphabetic order.


[ALIAS]

The [ALIAS] section assigns one or more context strings to the same topic alias. This section is optional.

Syntax

context_string = alias
    . . .

Parameters

context_string

Specifies the context string that identifies a particular topic. This context string may be used in a hotspot or in the [MAP] section to refer to a particular topic.

alias

Specifies the alternative string or alias name. This string is used in the \footnote statement. An alias string has the same form and follows the same conventions as the topic context string. That is, it is not case sensitive and may contain the alphabetic characters A through Z, the numeric characters 0 through 9, and the period and underscore characters.

Remarks

Because context strings must be unique for each topic and cannot be used for any other topic in the Help project, the [ALIAS] section provides a way to delete or combine Help topics without recoding your files. For example, if you create a topic that replaces information in three other topics, you could manually search through your files for invalid cross-references to the deleted topics. The easier approach, however, would be to use the [ALIAS] section to assign the name of the new topic to the deleted topics.

The [ALIAS] section can also be used when your application has multiple context identifiers for one Help topic. This situation occurs in context-sensitive Help.

Alias names can be used in a [MAP] section, but only if the [ALIAS] section precedes the [MAP] section.

Example

The following example creates several aliases:

[ALIAS]
sm_key=key_shrtcuts
cc_key=key_shrtcuts
st_key=key_shrtcuts     ; combined into Keyboard Shortcuts topic
clskey=us_dlog_bxs
maakey=us_dlog_bxs      ; covered in Using Dialog Boxes topic.
chk_key=dlogprts
drp_key=dlogprts
lst_key=dlogprts
opt_key=dlogprts
tbx_key=dlogprts        ; combined into Parts of Dialog Box topic.
frmtxt=edittxt
wrptxt=edittxt
seltxt=edittxt          ; covered in Editing Text topic.

See Also

\footnote, [MAP]


[BAGGAGE]

The [BAGGAGE] section lists files (typically multimedia elements) that the Microsoft Help Compiler stores within the Help file's internal file system. Windows Help can access data files stored in the Help file more efficiently than it can access files in the normal file system, since it doesn't have to read the file allocation table from CD-ROM.

Syntax

filename
    . . .

Parameter

filename

Specifies the full path of a file. If a file cannot be found, the compiler reports an error.

Remarks

A maximum of 1000 files can be stored as baggage files.

If a file is listed in the [BAGGAGE] section, you must use or write a dynamic-link library that uses Windows Help to read these files from the Help file.

See Also

ROOT


[BITMAPS]

The [BITMAPS] section specifies the names and locations of the bitmap files specified in the bmc, bml, and bmr statements.

Syntax

filename
    . . .

Parameter

filename

Specifies the full path of a bitmap file. If a file cannot be found, the compiler reports an error.

Remarks

For Windows 3.1, the [BITMAPS] section is not required if the bitmaps are located in the Help project directory or if the path containing the bitmaps is listed in the BMROOT or ROOT option. If the project file does not include either of these options, each bitmap filename must be listed in the [BITMAPS] section of the project file.

Example

The following example specifies three bitmap files:

[BITMAPS]
BMP01.BMP
BMP02.BMP
BMP03.BMP

See Also

bmc, bml, bmr, BMROOT, ROOT


BMROOT

The BMROOT option specifies the directory containing the bitmap files specified in the bmc, bml, and bmr statements.

Syntax

BMROOT = path[, path]

Parameter

path

Specifies a drive and full path.

Remarks

If the project file has a BMROOT option, you do not need to list the bitmap files in the [BITMAPS] section.

If the project file does not have a BMROOT option, the Help compiler looks for bitmaps in the directories specified by the ROOT option. If the project file does not have a ROOT option or if the ROOT option does not specify the directory containing the bitmap files, the filename for each bitmap must be specified in the [BITMAPS] section.

Example

The following example specifies that bitmaps are in the \HELP\BMP directory on drive C and the \GRAPHICS\ART directory on drive D:

[OPTIONS]
BMROOT=C:\HELP\BMP, D:\GRAPHICS\ART

See Also

[BITMAPS], bmc, bml, bmr, [OPTIONS], ROOT


BUILD

The BUILD option specifies which topics containing build tags are included in a build. The BUILD option does not apply to topics that do not contain build tags.

A topic contains a build tag if it contains a build-tag \footnote statement. Topics without build tags are always compiled, regardless of the current build expression.

Syntax

BUILD = expression

Parameter

expression

Specifies the build expression. This parameter consists of a combination of build tags (specified in the [BUILDTAGS] section) and the following operators:

Operator	Description
~	Applies the NOT operator to a single tag. The Help compiler compiles a topic only if the tag is not present. This operator has the highest precedence; the compiler applies it before any other operator.
&	Combines two tags by using the AND operator. The Help compiler compiles a topic only if it contains both tags. The compiler applies this operator only after the ~ operator has been applied.
|	Combines two tags by using the OR operator. The Help compiler compiles a topic if it has at least one tag. This operator has the lowest precedence; the compiler applies it only after all other operators have been applied.
( )	Parentheses may be used to override operator precedence. Expressions enclosed in parentheses are always evaluated first.
Remarks

Only one BUILD option can be given per project file.

The Help compiler evaluates all build expressions from left to right, using the specified precedence rules.

Example

The following examples assume that the [BUILDTAGS] section in the project file defines the build tags DEMO, MASTER, and TEST_BUILD. Although the following examples show several BUILD options on consecutive lines, only one BUILD option per project file is allowed.

BUILD = DEMO            ; compile topics that have the DEMO tag
BUILD = DEMO & MASTER   ; compile topics with both DEMO and MASTER
BUILD = DEMO | MASTER   ; compile topics with either DEMO or MASTER
BUILD = ~DEMO           ; compile topics that do not have DEMO
BUILD = (DEMO | MASTER) & TEST_BUILD
                        ; compile topics that have TEST_BUILD and
                        ; either DEMO or MASTER

See Also

\footnote, [BUILDTAGS], [OPTIONS]


[BUILDTAGS]

The [BUILDTAGS] section defines the build tags for the Help file. The Help compiler uses these tags to determine which topics to include when building the Help file.

This section is used in conjunction with the build-tag \footnote statements. These \footnote statements associate a build tag with a given topic. If the build tag is also defined in the [BUILDTAGS] section, the Help compiler compiles the topic; otherwise, it ignores the topic.

Syntax

tag
    . . .

Parameter

tag

Specifies a build tag consisting of any combination of characters except spaces. The Help compiler strips any space characters from the tag. Also, the compiler treats uppercase and lowercase characters as the same characters (that is, it is case-insensitive).

Remarks

The [BUILDTAGS] section is optional. If given, it can contain up to 30 build tags.

Example

The following example shows the form of the [BUILDTAGS] section in a sample project file:

[BUILDTAGS]
DEMO            ; topics to include in demo build
MASTER          ; topics to include in master help file
DEBUGBUILD      ; topics to include in debugging build
TESTBUILD       ; topics to include in a mini-build for testing

See Also

\footnote, BUILD


CITATION

The CITATION option places a custom citation in the About dialog box of Windows Help. Windows Help displays the citation immediately below the Microsoft copyright notice.

Syntax

CITATION = citation

Parameter

citation

Specifies the citation. The notice can be any combination of characters; its length must be in the range 35 through 75 characters.

See Also

COPYRIGHT, [OPTIONS]


COMPRESS

The COMPRESS option specifies the level of compression to be used when building the Help file. Compression levels indicate either no compression, medium compression (approximately 40%), or high compression (approximately 50%).

Syntax

COMPRESS = compression-level

Parameter

compression-level

Specifies the level of compression. This parameter can be one of the following values:

Value	Meaning
0	No compression
1	High compression
FALSE	No compression
HIGH	High compression
MEDIUM	Medium compression
NO	No compression
TRUE	High compression
YES	High compression
Remarks

Depending on the degree of compression requested, the build uses either block compression or a combination of block and key-phrase compression. Block compression compresses the topic data into predefined units known as blocks. Key-phrase compression combines repeated phrases found within the source file(s). The compiler creates a phrase-table file with the .PH extension if one does not already exist. If the compiler finds a file with the .PH extension, it uses that file for the current compilation. Because the .PH file speeds up the compression process when little text has changed since the last compilation, you might want to keep the phrase file if you compile the same Help file several times with compression. However, you will get maximum compression if you delete the .PH file before starting each build.

See Also

[OPTIONS]


[CONFIG]

The [CONFIG] section contains one or more macros that carry out actions, such as enabling browse buttons and registering dynamic-link library (DLL) functions. Windows Help executes the macros when it opens the Help file.

Syntax

macro
    . . .

Parameter

macro

Specifies a Windows Help macro. For more information about these macros, see the Microsoft Windows Programmer's Reference, Volume 4.

Remarks

The [CONFIG] section may include any number of lines. Each line of the [CONFIG] section may be up to 254 characters long.

Example

The following example registers a DLL, creates a button, enables the browse buttons, and sets the name of the Help file containing information about how to use Help:

[CONFIG]
RegisterRoutine("bmp","HDisplayBmp","USSS")
RegisterRoutine("bmp","CopyBmp", "v=USS")
CreateButton("btn_up", "&Up", "JumpContents('HOME.HLP')")
BrowseButtons()
SetHelpOnFile("APPHELP.HLP")


CONTENTS

The CONTENTS option identifies the context string of the highest-level or Contents topic. This topic is usually a table of contents or index within the Help file. Windows Help displays the Contents topic whenever the user clicks the Contents button.

Syntax

CONTENTS = context-string

Parameter

context-string

Specifies the context string of a topic in the Help file. The string can be any combination of characters, except spaces, and must also be specified in a context-string \footnote statement in some topic in the Help file.

Remarks

If the [OPTIONS] section does not include a CONTENTS option, the compiler assumes that the Contents topic is the first topic encountered in the first listed topic file in the [FILES] section of the project file.

The CONTENTS option is equivalent to the INDEX option that was available in Windows version 3.0.

Example

The following example sets the topic containing the context string "main_contents" as the Contents topic:

CONTENTS=main_contents

See Also

\footnote, [FILES], [OPTIONS]


COPYRIGHT

The COPYRIGHT option places a custom copyright notice in the About dialog box of Windows Help. Windows Help displays the notice immediately below the Microsoft copyright notice.

Syntax

COPYRIGHT = copyright-notice

Parameter

copyright-notice

Specifies the copyright notice. The notice can be any combination of characters; its length must be in the range 35 through 75 characters.

Remarks

The copyright notice is also appended to topics that are copied to the clipboard, unless it is replaced by using the CITATION option.

See Also

CITATION, [OPTIONS]


ERRORLOG

The ERRORLOG option directs the Help compiler to write all error messages to the specified file. The compiler also displays the error messages on the screen.

Syntax

ERRORLOG = error-filename

Parameter

error-filename

Specifies the name of the file to receive the error messages. This parameter can be a full or partial path if the error file should be written to a directory other than the project root directory.

Example

The following example writes all errors during the build to the HLPBUGS.TXT file in the Help project root directory.

ERRORLOG=HLPBUGS.TXT

See Also

[OPTIONS]


[FILES]

The [FILES] section lists all topic files used to build the Help file. Every project file requires a [FILES] section.

Syntax

filename
    . . .

Parameter

filename

Specifies the full or partial path of a topic file. If a partial path is given, the Help compiler uses the directories specified by the ROOT option to construct a full path. If a file cannot be found, the compiler reports an error.

Remarks

The #include directive can also be used in the [FILES] section to specify the topic files indirectly by designating a file that contains a list of the topic files.

Example

The following example specifies four topic files:

[FILES]
rtftxt\COMMANDS.RTF
rtftxt\HOWTO.RTF
rtftxt\KEYS.RTF
rtftxt\GLOSSARY.RTF

The following example uses the #include directive to specify the topic files indirectly. In this case, the file RTFFILES.H must be in the project directory (the Help compiler does not use the INCLUDE environment variable to search for files).

[FILES]
#include <rtffiles.h>

See Also

#include, ROOT


FORCEFONT

The FORCEFONT option forces the specified font to be substituted for all requested fonts. The option is used to create Help files that can be viewed on systems that do not have all fonts available.

Syntax

FORCEFONT = fontname

Parameter

fontname

Specifies the name of an available font. Font names must be spelled the same as they are in the Fonts dialog box in Control Panel. Font names cannot exceed 20 characters. If an invalid font name is given, the Help compiler uses the MS Sans Serif font as the default.

See Also

[OPTIONS]


ICON

The ICON option identifies the icon to display when the user minimizes Windows Help.

Syntax

ICON = icon-file

Parameter

icon-file

Specifies the name of the icon file. This file must have the standard Windows icon-file format.

See Also

[OPTIONS]


LANGUAGE

The LANGUAGE option sets the sorting order for keywords in the Search dialog box.

Syntax

LANGUAGE = language-name

Parameter

language-name

Specifies the language on which to base sorting. This parameter can be scandinavian, which sets the sorting order to the Scandinavian-language order.

Remarks

The default sorting order is the English-language order.

Microsoft Windows Help version 3.1 supports only English and Scandinavian sorting.

See Also

[OPTIONS]


[MAP]

The [MAP] section associates context strings (or aliases) with context numbers for context-sensitive Help. The context number corresponds to a value the parent application passes to Windows Help in order to display a particular topic. This section is optional.

Syntax

context-string context-number
    . . .

Parameter

context-string

Specifies the context string of a topic in the Help file. The string can be any combination of characters, except spaces, and must also be specified in a context-string \footnote statement in some topic in the Help file.

context-number

Specifies the context number to associate with the context string. The number can be in either decimal or standard C hexadecimal format. Only one context number may be assigned to a context string or alias. Assigning the same number to more than one context string generates a compiler error. At least one space must separate the context number from the context string.

Remarks

You can define the context strings listed in the [MAP] section either in a Help topic or in the [ALIAS] section. The compiler generates a warning message if a context string appearing in the [MAP] section is not defined in any of the topic files or in the [ALIAS] section.

If you use an alias name, the [ALIAS] section must precede the [MAP] section in the Help project file.

The [MAP] section supports two additional statements for specifying context strings and their associated context numbers. The first statement has the following form:

#define context-string context-number

The context-string and context-number parameters are as described in the Parameters section.

The second statement has the following form:

#include "filename"

The filename parameter, which can be enclosed in either double quotation marks or angle brackets (<>), specifies the name of a file containing one or more #define statements. The file may contain additional #include statements as well, but files may not be nested in this way more than five deep.

Example

The following example assigns hexadecimal context numbers to the context strings:

[MAP]
Edit_Window     0x0001
Control_Menu    0x0002
Maximize_Icon   0x0003
Minimize_Icon   0x0004
Split_Bar       0x0005
Scroll_Bar      0x0006
Title_Bar       0x0007
Window_Border   0x0008

See Also

#define, #include, [ALIAS]


MAPFONTSIZE

The MAPFONTSIZE option maps font sizes specified in topic files to different sizes when they are displayed in the Help window. This option is especially useful if there is a significant size difference between the authoring display and the intended user display.

Syntax

MAPFONTSIZE = m:p

Parameter

m

Specifies the size of the source font. This parameter is either a single point size or a range of point sizes. A range of point sizes consists of the low and high point sizes separated by a hyphen (-). If a range is specified, all fonts in the range are changed to the size specified by the p parameter.

p

Specifies the size of the font for the Help file.

Remarks

Although the [OPTIONS] section can contain up to five font ranges, only one font size or range is allowed with each MAPFONTSIZE statement. If more than one MAPFONTSIZE statement is included, the source font size or range specified in subsequent statements cannot overlap previous mappings.

Example

The following examples illustrate the use of the MAPFONTSIZE option:

MAPFONTSIZE=8:12      ; display all 8-pt. fonts as 12-pt.
MAPFONTSIZE=12-24:16  ; display fonts from 12 to 24 pts. as 16 pts.

See Also

[OPTIONS]


MULTIKEY

The MULTIKEY option specifies the footnote character to use for an alternative keyword table. This option is intended to be used in conjunction with topic files that contain \footnote statements for alternative keywords.

Syntax

MULTIKEY = footnote-character

Parameter

footnote-character

Specifies the case-sensitive letter to be used for the keyword footnote.

Remarks

Since keyword footnotes are case-sensitive, you should limit your keyword-table footnotes to one case, usually uppercase. If an uppercase letter is specified, the compiler will not include footnotes with the lowercase form of the same letter in the keyword table.

You may use any alphanumeric character for a keyword table except K and k, which are reserved for Help's standard keyword table. There is an absolute limit of five keyword tables, including the standard table. However, depending upon system configuration and the structure of your Help system, a practical limit of only two or three tables may be more realistic. If the compiler cannot create an additional keyword table, the additional table is ignored in the build.

Example

The following example illustrates how to enable the letter L for a keyword-table footnote:

MULTIKEY=L

See Also

\footnote, [OPTIONS]


OLDKEYPHRASE

The OLDKEYPHRASE option specifies whether an existing key-phrase file should be used to build the Help file.

Syntax

OLDKEYPHRASE = onoff

Parameters

onoff

Specifies whether the existing file should be used. This parameter can be one of the following values:

Value	Meaning
0	Recreate the file
1	Use the existing file
FALSE	Recreate the file
NO	Recreate the file
OFF	Recreate the file
ON	Use the existing file
TRUE	Use the existing file
YES	Use the existing file
See Also

[OPTIONS]


OPTCDROM

The OPTCDROM option optimizes a Help file for display on CD-ROM by aligning topic files on predefined block boundaries.

Syntax

OPTCDROM = yesvalue

Parameter

yesvalue

Specifies that the file should be optimized for CD-ROM. This parameter can be any of the values: YES, TRUE, 1, or ON.

See Also

[OPTIONS]


[OPTIONS]

The [OPTIONS] section includes options that control how a Help file is built and what feedback the build process displays. If this section is included in the project file, it should be the first section listed, so that the options will apply during the entire build process.

Syntax

option
    . . .

Parameters

option

Specifies one of the following project-file options:

Option	Description
BMROOT	Specifies the directory containing the bitmap files named in the bmc, bml, and bmr statements in topic files.
BUILD	Specifies which topics to include in the build.
CITATION	Specifies a string that is appended to topics that are copied from Windows Help instead of the COPYRIGHT string.
COMPRESS	Specifies the type of compression to use during the build.
CONTENTS	Specifies the context string of the Contents topic for a Help file.
COPYRIGHT	Adds a unique copyright message for the Help file to the About dialog box.
ERRORLOG	Puts compilation errors in a file during the build.
FORCEFONT	Forces all authored fonts in the topic files to appear in a different font when displayed in the Help window.
ICON	Specifies the icon file to be displayed when the Help window is minimized.
LANGUAGE	Specifies a different sorting order for Help files authored in a Scandinavian language.
MAPFONTSIZE	Maps a font size in the topic file to a different font size in the compiled Help file.
MULTIKEY	Specifies an alternative keyword table to use for mapping topics.
OLDKEYPHRASE	Specifies whether the compiler should use the existing key-phrase table or create a new one during the build.
OPTCDROM	Optimizes the Help file for CD-ROM use.
REPORT	Controls the display of messages during the build process.
ROOT	Specifies the directories containing the topic and data files listed in the project file.
TITLE	Specifies the text displayed in the title bar of the Help window when the file is open.
WARNING	Specifies the level of error-message reporting the compiler is to display during the build.
Remarks

These options can appear in any order within the [OPTIONS] section. The [OPTIONS] section is not required.


REPORT

The REPORT option displays messages on the screen during the build. These messages indicate when the Help compiler is performing the different phases of the build, including compiling the file, resolving jumps, and verifying browse sequences.

Syntax

REPORT = ON

See Also

[OPTIONS], WARNING


ROOT

The ROOT option specifies the directories where the Help compiler looks for files listed in the project file.

Syntax

ROOT = pathname[, pathname]

Parameter

pathname

Specifies either a drive and full path or a relative path from the project directory. If the project file has a ROOT option, all relative paths in the project file refer to one of these paths. If the project file does not have a ROOT option, all paths are relative to the directory containing the project file.

Remarks

If the project file does not have a BMROOT option, the compiler looks in the directories specified in the ROOT option to find bitmaps positioned by using the bmc, bml, and bmr statements. If none of these directories contains these bitmaps, the bitmap filenames must be listed in the [BITMAPS] section of the project file.

Example

The following example specifies that the project root directory is C:\WINHELP\HELPDIR and is found on drive C:

[OPTIONS]
ROOT=C:\WINHELP\HELPDIR

Given this root directory, if the [FILES] section contains the entry TOPICS\FILE.RTF, the full path for the topic file is C:\WINHELP\HELPDIR\TOPICS\FILE.RTF.

See Also

bmc, bml, bmr, [BITMAPS], BMROOT, [OPTIONS], [FILES]


TITLE

The TITLE option sets the title for the Help file. Windows Help displays the title in its title bar whenever it displays the Help file.

Syntax

TITLE = titlename

Parameter

titlename

Specifies the title displayed in the Windows Help title bar. The title must not exceed 50 characters.

Remarks

If no title is specified by using the TITLE option, Windows Help displays the title Windows Help in the title bar.

Example

The following example sets the Help-file title to ABC Help.

[OPTIONS]
TITLE=ABC Help

See Also

[OPTIONS]


WARNING

The WARNING option specifies the amount of debugging information the Help compiler is to report.

Syntax

WARNING = level

Parameter

level

Specifies the warning level. This parameter may be one of the following values:

Value	Meaning
1	Report only the most severe errors.
2	Report an intermediate number of errors.
3	Report all errors and warnings.
Example

The following example specifies an intermediate level of error reporting:

[OPTIONS]
WARNING=2

See Also

[OPTIONS], REPORT


[WINDOWS]

The [WINDOWS] section defines the size, location, and colors for the primary Help window and any secondary-window types used in a Help file.

The secondary windows defined in this section are intended to be used with Windows applications that specify secondary windows when calling the WinHelp function.

Syntax

type = "caption", (x, y, width, height), sizing, (clientRGB), (nonscrollRGB), (fTop)
    . . .

Parameters

type

Specifies the type of window that uses the defined attributes. For the primary Help window, this parameter is main. For a secondary window, this parameter may be any unique name of up to 8 characters. Any jumps that display a topic in a secondary window give this type name as part of the jump.

caption

Specifies the title for a secondary window. Windows Help places the title in the title bar of the window. To set the title for the primary Help window, use the TITLE option in the [OPTIONS] section.

x

Specifies the x-coordinate, in help units, of the window's upper-left corner. Windows Help always assumes the screen is 1024 help units wide, regardless of resolution. For example, if the x-coordinate is 512, the left edge of the Help window is in the middle of the screen.

y

Specifies the y-coordinate, in help units, of the window's upper-left corner. Windows Help always assumes the screen is 1024 help units high, regardless of resolution. For example, if the x-coordinate is 512, the top edge of the Help window is in the middle of the screen.

width

Specifies the default width, in help units, for a secondary window.

height

Specifies the default height, in help units, for a secondary window.

sizing

Specifies the relative size of a secondary window when Windows Help first opens the window. This parameter can be one of the following values:

Value	Meaning
0	Set the window to the size specified by the x, y, width, and height parameters.
1	Maximize the window; ignore the x, y, width, and height parameters.
clientRGB

Specifies the background color of the window. This parameter is an RGB color value consisting of three 8-bit hexadecimal numbers enclosed in parentheses and separated by commas. If this parameter is not given, Windows Help uses the default window color specified by Control Panel.

nonscrollRGB

Specifies the background color of the nonscrolling region (if any) in the Help window. This parameter is an RGB color value consisting of three 8-bit hexadecimal numbers enclosed in parentheses and separated by commas. If this parameter is not given, Windows Help uses the default window color specified by Control Panel.

fTop

Specifies whether the secondary window is displayed on top of all other windows. When this parameter is 1, the window is displayed over all windows that do not also use this attribute. Otherwise, it should be zero. This parameter is optional.

Example

The following example defines two windows, the main window and a secondary window named "picture". The main-window definition sets the background color of nonscrolling regions in the main Help window to (128, 0, 128) but leaves several other values empty (for which Windows Help will supply its own default values). The secondary-window definition sets the caption to "Samples" and sets the width and height of the window to about one-quarter of the width and height of the screen. The background colors for the window and nonscrolling region are (0, 255, 255) and (255, 0, 0), respectively. The sizing parameter for both the main and secondary windows is zero.

[WINDOWS]
main=,,,,, 0,,,, (128, 0, 128)
picture = "Samples", (123,123,256,256), 0, (0,255,255), (255,0,0)

See Also

[OPTIONS], TITLE, WinHelp


Help Macro Reference

This section lists the Microsoft Windows Help macros in alphabetic order.


About

The About macro displays Windows Help's About dialog box.

Syntax

About()

Parameters

This macro does not take any parameters.

Remarks

Use of this macro in secondary windows is not recommended.


AddAccelerator

The AddAccelerator macro assigns a Help macro to an accelerator key (or key combination) so that the macro is carried out when the user presses the accelerator key(s).

Syntax

AddAccelerator(key, shift-state, "macro")

Parameters

key

Specifies the Windows virtual-key value. For a list of virtual-key codes, see the Microsoft Windows Programmer's Reference, Volume 3.

shift-state

Specifies the combination of ALT, SHIFT, and CTRL keys to be used with the accelerator. This parameter may be one of the following values:

Value	Meaning
0	None
1	SHIFT
2	CTRL
3	SHIFT+CTRL
4	ALT
5	ALT+SHIFT
6	ALT+CTRL
7	SHIFT+ALT+CTRL
macro

Specifies the Help macro or macro string executed when the user presses the accelerator key(s). The macro must appear in quotation marks ("). Multiple macros in a string must be separated by semicolons (;).

Remarks

The AddAccelerator macro can be abbreviated as AA.

Example

The following macro executes the Windows Clock program when the user presses ALT+SHIFT+CONTROL+F4:

AddAccelerator(0x73, 7, "ExecProgram('clock.exe', 1)")

See Also

RemoveAccelerator


Annotate

The Annotate macro displays the Annotation dialog box from the Edit menu.

Syntax

Annotate()

Parameters

This macro does not take any parameters.

Remarks

Use of this macro in secondary windows is not recommended.


AppendItem

The AppendItem macro appends a menu item to the end of a Windows Help menu.

Syntax

AppendItem("menu-id", "item-id", "item-name", "macro")

Parameters

menu-id

Specifies the name of a standard Windows Help menu or the name used in the InsertMenu macro used to create the menu. This name must appear in quotation marks. The new item is appended to this menu. For a standard menu, this parameter can be one of the following:

Name	Menu
MNU_FILE	File
MNU_EDIT	Edit
MNU_BOOKMARK	Bookmark menu
MNU_HELP	Help
item-id

Specifies the name that Windows Help uses internally to identify the menu item. This name must appear in quotation marks ("). This name is used by the DisableItem or DeleteItem macros.

item-name

Specifies the name that Windows Help displays on the menu for the item. This name must appear in quotation marks ("). Within the quotation marks, place an ampersand (&) before the character used for the macro's accelerator key.

macro

Specifies one or more macros that are to be executed when the user chooses the menu item. The macro must appear in quotation marks. Multiple macros in a string must be separated by semicolons (;).

Remarks

Windows Help ignores this macro if it is executed in a secondary window.

If the keyboard accelerator conflicts with other menu access keys, Windows Help displays the error message "Unable to add item" and ignores the macro.

Example

The following macro appends a menu item labeled "Tools" to a pop-up menu that has an identifier "IDM_TLS". Choosing the menu item causes a jump to a topic with the context string "tpc1" in the TLS.HLP file:

AppendItem("IDM_BKS", "IDM_TLS", "&Tools", "JI('tls.hlp', 'tpc1')")

See Also

DeleteItem, DisableItem, InsertMenu


Back

The Back macro displays the previous topic in the history list. The history list is a list of the last 40 topics the user has displayed since starting Windows Help.

Syntax

Back()

Parameters

This macro does not take any parameters.

Remarks

Windows Help ignores this macro if it is executed in a secondary window.

If the Back macro is executed when the Back list is empty, Windows Help takes no action.


BookmarkDefine

The BookmarkDefine macro displays the Define dialog from the Bookmark menu.

Syntax

BookmarkDefine()

Parameters

This macro does not take any parameters.

Remarks

Use of this macro in secondary windows is not recommended.

If the BookmarkDefine macro is executed from a pop-up window, the bookmark is attached to the topic that invoked the pop-up window.


BookmarkMore

The BookmarkMore macro displays the More dialog from the Bookmark menu. The More command appears on the Bookmark menu if the menu lists more than nine bookmarks.

Syntax

BookmarkMore()

Parameters

This macro does not take any parameters.

Remarks

Use of the macro in secondary windows is not recommended.


BrowseButtons

The BrowseButtons macro adds browse buttons to the button bar.

Syntax

BrowseButtons()

Parameters

This macro does not take any parameters.

Remarks

Windows Help ignores this macro if it is executed from a secondary window.

If the BrowseButtons macro is used with one or more CreateButton macros in the [CONFIG] section of the project file, the order of the browse buttons on the Windows Help button bar is determined by the order of the BrowseButtons macro in relation to the other macros listed in the [CONFIG] section.

Example

The following macros in the project file cause the Clock button to appear immediately before the two browse buttons on the button bar:

[CONFIG]
CreateButton("&Clock", "ExecProgram('clock', 0)")
BrowseButtons()

See Also

[CONFIG], CreateButton


ChangeButtonBinding

The ChangeButtonBinding macro assigns a Help macro to a Help button.

Syntax

ChangeButtonBinding("button-id", "button-macro")

Parameters

button-id

Specifies the identifier assigned to the button by the CreateButton macro or, for a standard Help button, one of the following predefined button identifiers:

ID	Description
BTN_CONTENTS	Contents
BTN_SEARCH	Search
BTN_BACK	Back
BTN_HISTORY	History
BTN_PREVIOUS	Browse previous
BTN_NEXT	Browse next
The button identifier must be enclosed in quotation marks (").

button-macro

Specifies the Help macro executed when the user selects the button. The macro must be enclosed in quotation marks (").

Remarks

Windows Help ignores this macro if it is executed in a secondary window.

The ChangeButtonBinding macro can be abbreviated as CBB.

Example

In the following macro, "conts" is the context string for the table of contents in the DICT.HLP file:

ChangeButtonBinding("btn_contents", "JumpId('dict.hlp', 'conts')")

See Also

CreateButton


ChangeItemBinding

The ChangeItemBinding macro assigns a Help macro to an item previously added to a Windows Help menu using the AppendItem macro.

Syntax

ChangeItemBinding("item-id", "item-macro")

Parameters

item-id

Identifies the menu item appended by the AppendItem macro. The item identifier must be enclosed in quotation marks (").

item-macro

Specifies the Help macro to execute when the user selects the item. The macro must be enclosed in quotation marks (").

Remarks

Windows Help ignores this macro if it is executed in a secondary window.

The ChangeItemBinding macro can be abbreviated as CIB.

Example

The following macro changes the menu item identified by "time_item" so that it displays the Windows clock:

ChangeItemBinding("time_item", "ExecProgram('clock', 0)")

See Also

AppendItem


CheckItem

The CheckItem macro places a check mark beside a menu item.

Syntax

CheckItem("item-id")

Parameters

item-id

Identifies the menu item to check. The item identifier must be enclosed in quotation marks (").

Remarks

The CheckItem macro can be abbreviated as CI.

See Also

UncheckItem


CloseWindow

The CloseWindow macro closes either a secondary window or the main Help window.

Syntax

CloseWindow("window-name")

Parameters

window-name

Specifies the name of the window to close. The name "main" is reserved for the main Help window. For secondary windows, the window name is defined in the [WINDOWS] section of the project file. This name must be enclosed in quotation marks (").

Example

The following macro closes the secondary window named "keys":

CloseWindow("keys")

See Also

[WINDOWS]


Contents

The Contents macro displays the Contents topic in the current Help file. The Contents topic is defined by the CONTENTS option in the [OPTIONS] section of the project file. If the project file does not have a CONTENTS option, the Contents topic is the first topic of the first topic file specified in the project file.

Syntax

Contents()

See Also

CONTENTS, [OPTIONS]


CopyDialog

The CopyDialog macro displays the Copy dialog from the Edit menu.

Syntax

CopyDialog()

Remarks

Use of this macro in secondary windows is not recommended.


CopyTopic

The CopyTopic macro copies all the text in the currently displayed topic to the Clipboard.

Syntax

CopyTopic()

Remarks

Use of the macro in secondary windows is not recommended.


CreateButton

The CreateButton macro adds a new button to the button bar.

Syntax

CreateButton("button-id", "name", "macro")

Parameters

button-id

Specifies the name that WinHelp uses internally to identify the button. This name must appear in quotation marks ("). Use this name in the DisableButton or DestroyButton macro if you want to remove or disable the button or in the ChangeButtonBinding if you want to change the Help macro that the button executes in certain topics.

name

Specifies the text that appears on the button. To make a letter in this text the mnemonic for the button, place an ampersand (&) before that letter. The button name is case sensitive and can have up to 29 characters in it — any additional characters are ignored.

macro

Specifies the Help macro or macro string executed when the user clicks on the button. Multiple macros in a macro string must be separated by semicolons.

Remarks

Windows Help allows a maximum of 16 custom buttons. It allows a total of 22 buttons, including the standard Browse buttons, on the button bar.

If the BrowseButtons macro is used with one or more CreateButton macros in the project file, the buttons appear in the same order on the button bar as the macros appear in the project file.

Windows Help ignores this macro if it is executed in a secondary window.

The CreateButton macro can be abbreviated as CB.

Example

The following macro creates a new button labeled "Ideas" that jumps to the topic with the context string "dir" in the IDEAS.HLP file when clicked:

CreateButton("btn_ideas", "&Ideas", "JumpId('ideas.hlp', 'dir')")

See Also

BrowseButtons, ChangeButtonBinding, DestroyButton, DisableButton


DeleteItem

The DeleteItem macro removes a menu item that was added by using the AppendItem macro.

Syntax

DeleteItem("item-id")

Parameters

item-id

Specifies the item identifier used in the AppendItem macro. The item identifier must be enclosed in quotation marks (").

Remarks

Windows Help ignores this macro if it is executed in a secondary window.

Example

The following macro removes the menu item "Tools" appended in the example for the AppendItem macro:

DeleteItem("IDM_TOOLS")

See Also

AppendItem


DeleteMark

The DeleteMark macro removes a text marker added with the SaveMark macro.

Syntax

DeleteMark("marker-text")

Parameters

marker-text

Specifies the text marker previously added by the SaveMark macro. The marker text must be enclosed in quotation marks (").

Remarks

If the marker does not exist when the DeleteMark macro is executed, Windows Help displays a "Topic not found" error message.

Example

The following macro removes the marker "Managing Memory" from a Help file:

DeleteMark("Managing Memory")

See Also

SaveMark


DisableButton

The DisableButton macro grays out a button added with the CreateButton macro. This button cannot be used in the topic until an EnableButton macro is executed.

Syntax

DisableButton("button-id")

Parameters

button-id

Specifies the identifier assigned to the button by the CreateButton macro. The button identifier must be enclosed in quotation marks (").

Remarks

Windows Help ignores this macro if it is executed in a secondary window.

The DisableButton macro can be abbreviated as DB.

See Also

CreateButton, EnableButton


DisableItem

The DisableItem macro grays out a menu item added with the AppendItem macro. The menu item cannot be used in the topic until an EnableItem macro is executed.

Syntax

DisableItem("item-id")

Parameters

item-id

Identifies a menu item previously appended with the AppendItem macro. The item identifier must be enclosed in quotation marks (").

Remarks

Windows Help ignores this macro if it is executed in a secondary window.

The DisableItem macro can be abbreviated as DI.

See Also

AppendItem, EnableItem


DestroyButton

The DestroyButton macro removes a button added with the CreateButton macro.

Syntax

DestroyButton("button-id")

Parameters

button-id

Identifies a button previously created by the CreateButton macro. The button identifier must be enclosed in quotation marks (").

Remarks

The button identifier cannot be an identifier for one of the standard Help buttons. For a list of those identifiers, see the ChangeButtonBinding macro.

Windows Help ignores this macro if it is executed in a secondary window.

See Also

CreateButton, ChangeButtonBinding


EnableButton

The EnableButton macro re-enables a button disabled with the DisableButton macro.

Syntax

EnableButton("button-id")

Parameters

button-id

Specifies the identifier assigned to the button by the CreateButton macro. The button identifier must be enclosed in quotation marks (").

Remarks

Windows Help ignores this macro if it is executed in a secondary window.

The EnableButton macro can be abbreviated as EB.

See Also

CreateButton, DisableButton


EnableItem

The EnableItem macro re-enables a menu item disabled with the DisableItem macro.

Syntax

EnableItem("item-id")

Parameters

item-id

Specifies the identifier assigned to the menu item by the AppendItem macro. The item identifier must be enclosed in quotation marks (").

Remarks

Windows Help ignores this macro if it is executed in a secondary window.

The EnableItem macro can be abbreviated as EI.

See Also

AppendItem, DisableItem


ExecProgram

The ExecProgram macro executes a Windows application.

Syntax

ExecProgram("command-line", display-state)

Parameters

command-line

Specifies the command line for the application to be executed. The command line must be enclosed in quotation marks ("). Windows Help searches for this application in the current directory, followed by the Windows directory, the user's path, and the directory of the currently viewed Help file.

display-state

Specifies a value indicating how the application is shown when executed. It may be one of the following values:

Value	Meaning
0	Normal
1	Minimized
2	Maximized
Remarks

The ExecProgram macro can be abbreviated as EP.

The backslash (\) character should not be used to escape double quotation-mark characters in macros. Instead, you can enclose the command line in single quotation marks (') and omit the backslash for the double quotation marks, as shown in the following:

'command "string as parameter"'

Note that the first single quotation mark must be an open quote and the last single quotation mark must be a close quote.

Example

The following example executes the Clock application. The application is minimized when it starts:

ExecProgram('clock.exe', 1)


Exit

The Exit macro exits the Windows Help application. It has the same effect as selecting Exit from the File menu.

Syntax

Exit()

Parameters

This macro does not take any parameters.


FileOpen

The FileOpen macro displays the Open dialog box from the File menu.

Syntax

FileOpen()

Parameters

This macro does not take any parameters.

Remarks

Use of the macro in secondary windows is not recommended.


FocusWindow

The FocusWindow macro changes the focus to the specified window, either the main Help window or a secondary window.

Syntax

FocusWindow("window-name")

Parameters

window-name

Specifies the name of the window to receive the focus. The name "main" is reserved for the main Help window. For secondary windows, the window name is defined in the [WINDOWS] section of the project file. This name must be enclosed in quotation marks (").

Remarks

This macro is ignored if the specified window does not exist.

Example

The following macro changes the focus to the secondary window "keys":

FocusWindow("keys")

See Also

[WINDOWS]


GoToMark

The GoToMark macro jumps to a marker set with the SaveMark macro.

Syntax

GoToMark("marker-text")

Parameters

marker-text

Specifies a text marker previously defined by using the SaveMark macro.

Example

The following macro jumps to the marker "Managing Memory":

GoToMark("Managing Memory")

See Also

SaveMark


HelpOn

The HelpOn macro displays the Help file for the Windows Help application. The macro carries out the same action as choosing the How to Use Help command on the Help menu.

Syntax

HelpOn()

Parameters

This macro does not take any parameters.


HelpOnTop

The HelpOnTop macro toggles the on-top state of Windows Help. It is equivalent to checking or unchecking the Always On Top command in the Help menu.

Syntax

HelpOnTop()

Parameters

This macro does not take any parameters.

Remarks

Windows Help does not provide a macro to check the current state of the Always On Top command. It is up to the user to determine whether the macro should be used to change the state of the command.


History

The History macro displays the history list, which shows the last 40 topics the user has viewed since opening a Help file in Windows Help. It has the same effect as choosing the History button.

Syntax

History()

Parameters

This macro does not take any parameters.

Remarks

Windows Help ignores this macro if it is executed in a secondary window.


IfThen

The IfThen macro executes a Help macro if a given marker exists. It uses the IsMark macro to make the test.

Syntax

IfThen(IsMark("marker-text"), "macro")

Parameters

marker-text

Specifies a text marker previously created by using the SaveMark macro. The marker must be enclosed in quotation marks (").

macro

Specifies a Help macro or macro string to be executed if the marker exists. Multiple macros in a macro string must be separated by semicolons (;).

Example

The following macro jumps to the topic with context string "man_mem" if a marker named "Managing Memory" has been set by the SaveMark macro:

IfThen(IsMark("Managing Memory"), "JI('trb.hlp', 'man_mem')")

See Also

IsMark, SaveMark


IfThenElse

The IfThenElse macro executes one of two Help macros depending on whether or not a marker exists. It uses the IsMark macro to make the test.

Syntax

IfThenElse(IsMark("marker-text"), "macro1", "macro2")

Parameters

marker-text

Specifies a text marker previously created by using the IsMark macro. The marker must be enclosed in quotation marks (").

macro1

Specifies a Help macro or macro string to be executed if the marker exits. Multiple macros in either macro string must be separated by semicolons (;).

macro2

Specifies a Help macro or macro string to be executed if the marker does not exist. Multiple macros in either macro string must be separated by semicolons.

Example

The following macro jumps to the topic with context string "mem" if a marker named "Memory" has been set by the SaveMark macro. If the marker does not exist, it jumps to the next topic in the browse sequence.

IfThenElse(IsMark("Memory"), "JI('trb.hlp', 'mem')", "Next()")

See Also

IsMark, SaveMark


InsertItem

The InsertItem macro inserts a menu item at a given position on an existing menu. The menu can be either one you create with the InsertMenu macro or one of the standard Windows Help menus.

Syntax

InsertItem("menu-id", "item-id", "item-name", "macro", position)

Parameters

menu-id

Identifies either a standard Windows Help menu or a menu previously created by using the InsertMenu macro. For a standard menu, this parameter can be one of the following:

Name	Menu
MNU_FILE	File
MNU_EDIT	Edit
MNU_BOOKMARK	Bookmark menu
MNU_HELP	Help
For other menus, this parameter must be the name used with the InsertMenu macro. In all cases, the menu identifier must be enclosed in quotation marks. The new item is inserted into this menu.

item-id

Specifies the name that Windows Help uses internally to identify the menu item. The item identifier must be enclosed in quotation marks (").

item-name

Specifies the name Windows Help displays in the menu for the item. This name is case-sensitive and must be enclosed in quotation marks. An ampersand (&) before a character in the name identifies it as the item's keyboard access key.

macro

Specifies a Help macro or macro string to be executed when the user chooses the menu item. The macro must be enclosed in quotation marks. Multiple macros in a string must be separated by semicolons (;).

position

Specifies the position of the menu item in the menu. It must be an integer value. Position 0 is the first or topmost position in the menu.

Remarks

The item-id parameter can be used in a subsequent DisableItem or DeleteItem macro to remove or disable the item or to change the operations that the item performs in certain topics.

Windows Help ignores this macro if it is executed in a secondary window.

The specified keyboard access keys must be unique. If a key conflicts with other menu access keys, Windows Help displays the error message "Unable to add item" and ignores the macro.

Example

The following macro inserts a menu item labeled "Tools" as the third item on a menu that has an identifier "MNU_BKS". Selecting the menu item causes a jump to a topic with the context string "tls1" in the TLS.HLP file:

InsertItem("mnu_bks", "m_tls", "&Tools", "JI('tls.hlp', 'tls1')", 3)

See Also

DeleteItem, DisableItem, InsertMenu


InsertMenu

The InsertMenu macro inserts a new menu in the Windows Help menu bar.

Syntax

InsertMenu("menu-id", "menu-name", menu-position)

Parameters

menu-id

Specifies the name that Windows Help uses internally to identify the menu. The menu identifier must be enclosed in quotation marks ("). This identifier can be used in the AppendItem macro to add macros to the menu.

menu-name

Specifies the name that Windows Help displays on the menu bar. This name must be enclosed in quotation marks. An ampersand (&) before a character in the name identifies it as the menu's keyboard access key.

menu-position

Specifies the position on the menu bar of the new menu name. This parameter must be an integer number. Positions are numbered from left to right, with position 0 the left-most menu.

Remarks

Windows Help ignores this macro if it is executed in a secondary window.

Example

The following macro adds a menu named "Utilities" to the Windows Help application. The label "Utilities" appears as the fourth item on the Windows Help menu bar. The user presses ALT+U to open the menu.

InsertMenu("IDM_UTIL", "&Utilities", 3)

See Also

AppendItem


IsMark

The IsMark macro tests whether or not a marker set by the SaveMark macro exists. It is used as a parameter to the conditional macros IfThen and IfThenElse. The IsMark macro returns nonzero if the mark exists or zero if it does not.

Syntax

IsMark("marker-text")

Parameters

marker-text

Specifies a text marker previous created using the SaveMark macro.

Remarks

The Not macro can be used to reverse the results of the IsMark macro.

Example

The following macro jumps to the topic with the context string "man_mem" if a marker named "Managing Memory" has been set by the SaveMark macro:

IfThen(IsMark("Managing Memory"), "JI('trb.hlp', 'man_mem')")

See Also

IfThen, IfThenElse, SaveMark


JumpContents

The JumpContents macro jumps to the Contents topic of a specified file in the Help file. The Contents topic is indicated by the CONTENTS option entry in the [OPTIONS] section of the project file. If the CONTENTS option is not specified, Windows Help jumps to the first topic in the Help file.

Syntax

JumpContents("filename")

Parameters

filename

Specifies the name of the destination file for the jump. The filename must be enclosed in quotation marks ("). If Windows Help cannot find this file, it displays an error message and does not perform the jump.

Remarks

Windows Help ignores this macro if it is executed in a secondary window.

Example

The following macro jumps to the Contents topic of the PROGMAN.HLP file:

JumpContents("PROGMAN.HLP")

See Also

[OPTIONS], CONTENTS


JumpContext

Syntax

JumpContext("filename", context-number)

Parameters

filename

Specifies the name of the destination file for the jump. The filename must be enclosed in quotation marks ("). If Windows Help cannot find this file, it displays an error message and does not perform the jump.

context-number

Specifies the context number of the topic in the destination file. The context number must be defined in the [MAP] section of the project file. If the context number is not valid, Windows Help jumps to the Contents topic or to the first topic in the file instead and displays an error message.

Remarks

The JumpContext macro can be abbreviated as JC.

Example

The following macro jumps to the topic mapped to the context number 801 in the PROGMAN.HLP file:

JumpContext("PROGMAN.HLP", 801)

See Also

[MAP]


JumpHelpOn

The JumpHelpOn macro jumps to the Contents topic of the How to Use Help file. The How To Use Help file is either the default WINHELP.HLP file shipped with Windows 3.1 or the Help file designated by the SetHelpOnFile macro in the [CONFIG] section of the project file.

Syntax

JumpHelpOn()

Parameters

This macro does not take any parameters.

Remarks

If Windows Help cannot find the specified Help file, it displays an error message and does not perform the jump.

Example

The following macro jumps to the Contents topic of the designated How to Use Help file:

JumpHelpOn()

See Also

[CONFIG], SetHelpOnFile


JumpId

The JumpId macro jumps to the topic with the specified context string in the Help file.

Syntax

JumpId("filename", "context-string")

Parameters

filename

Specifies the name of the Help file containing the context string. The filename must be enclosed in quotation marks ("). If Windows Help does not find this file, it displays an error message and does not perform the jump.

context-string

Context string of the topic in the destination file. The context string must be enclosed in quotation marks. If the context string does not exist, Windows Help jumps to the Contents topic for that file instead.

Remarks

The JumpId macro may be abbreviated as JI.

Example

The following macro jumps to a topic with "second_topic" as its context string in the SECOND.HLP file:

JI("second.hlp", "second_topic")


JumpKeyword

The JumpKeyword macro loads the indicated Help file, searches through the K keyword table, and displays the first topic containing the index keyword specified in the macro.

Syntax

JumpKeyword("filename", "keyword")

Parameters

filename

Specifies the name of the Help file containing the desired keyword table. The filename must be enclosed in quotation marks ("). If this file does not exist, Windows Help displays an error message and does not perform the jump.

keyword

Specifies the keyword that the macro searches for. The keyword must be enclosed in quotation marks. If Windows Help finds more than one match, it displays the first matched topic. If it does not find any matches, it displays a "Not a keyword" message and displays the Contents topic of the destination file instead.

Remarks

The JumpKeyword macro can be abbreviated as JK.

Example

The following macro displays the first topic that has "hands" as an index keyword in the CLOCK.HLP file:

JumpKeyword("clock.hlp", "hands")


Next

The Next macro displays the next topic in the browse sequence for the Help file.

Syntax

Next()

Parameters

This macro does not take any parameters.

Remarks

If the currently displayed topic is the last topic of a browse sequence, this macro does nothing.

Windows Help ignores this macro if it is executed in a secondary window.


Not

The Not macro reverses the result (nonzero or zero) returned by the IsMark macro. It is used along with the IsMark macro as a parameter to the conditional macros IfThen and IfThenElse.

Syntax

Not(IsMark("marker-text"))

Parameters

marker-text

Specifies a text marker previously created by using the SaveMark macro. The marker text must be enclosed in quotation marks (").

Example

The following macro jumps to the topic with the context string "mem1" if a marker named "Memory" has not been set by the SaveMark macro:

IfThen(Not(IsMark("Memory")), "JI('trb.hlp', 'mem1')")

See Also

IfThen, IfThenElse, IsMark, SaveMark


PopupContext

The PopupContext macro displays in a pop-up window the topic identified by a specific context number.

Syntax

PopupContext("filename", context-number)

Parameters

filename

Specifies the name of the file that contains the topic to be displayed. The filename must be enclosed in quotation marks ("). If Windows Help cannot find this file, it displays an error message.

context number

Specifies the context number of the topic to be displayed. The context number must be specified in the [MAP] section of the project file. If the context number is not valid, Windows Help displays the Contents topic or the first topic in the file instead.

Remarks

The PopupContext macro can be abbreviated as PC.

Example

The following macro displays in a pop-up window the topic mapped to the context number 801 in the PROGMAN.HLP file:

PopupContext("progman.hlp", 801)

See Also

[MAP]


PopupId

The PopupId macro displays a topic from a specified file in a pop-up window.

Syntax

PopupId("filename", "context-string")

Parameters

filename

Specifies the name of the file containing the pop-up window topic. The filename must be enclosed in quotation marks ("). If this file does not exist, Windows Help displays a warning.

context-string

Specifies the context string of the topic in the destination file. If the requested context string does not exist, Windows Help displays the Contents topic or the first topic in the file.

Remarks

The PopupId macro can be abbreviated as PI.

Example

The following macro displays a pop-up window with context string "second_topic" from the SECOND.HLP file:

PopupId("second.hlp", "second_topic")


PositionWindow

The PositionWindow macro sets the size and position of a window.

Syntax

PositionWindow(x, y, width, height, state, "name")

Parameters

x

Specifies the x-coordinate, in help units, of the upper-left corner of the window. Windows Help always assumes the screen (regardless of resolution) is 1024 help units wide. For example, if the x-coordinate is 512, the left edge of the Help window is in the middle of the screen.

y

Specifies the y-coordinate, in help units, of the upper-left corner of the window. Windows Help always assumes the screen (regardless of resolution) is 1024 help units high. For example, if the y-coordinate is 512, the top edge of the Help window is in the middle of the screen.

width

Specifies the default width, in help units, of the window.

height

Specifies the default height, in help units, of the window.

state

Specifies how the window is sized. This parameter can be one of the following values:

Value	Meaning
0	Normal size
1	Maximized
If the parameter is 1, Windows Help ignores the x, y, width, and height parameters.

name

Specifies the name of the window to position. The name "main" is reserved for the main Help window. For secondary windows, the window name must be defined in the [WINDOWS] section of the project file. This name must be enclosed in quotation marks (").

Remarks

If the window to be positioned does not exist, Windows Help ignores the macro.

The PositionWindow macro can be abbreviated as PW.

Example

The following macro positions the secondary window "Samples" in the upper-left corner (100, 100) with a width and height of 500 (in help units):

PositionWindow(100, 100, 500, 500, 0, "Samples")

See Also

[WINDOWS]


Prev

The Prev macro displays the previous topic in the browse sequence for the Help file. If the currently displayed topic is the first topic of a browse sequence, this macro does nothing.

Syntax

Prev()

Parameters

This macro does not take any parameters.

Remarks

Windows Help ignores this macro if it is executed in a secondary window.


Print

The Print macro sends the currently displayed topic to the printer. It should be used only to print topics in windows other than the main Help window (for example, topics in a secondary window).

Syntax

Print()

Parameters

This macro does not take any parameters.


PrinterSetup

The PrinterSetup macro displays the Printer Setup dialog box from the File menu.

Syntax

PrinterSetup()

Parameters

This macro does not take any parameters.

Remarks

Use of the macro in secondary windows is not recommended.


RegisterRoutine

RegisterRoutine("DLL-name", "function-name", "format-spec")

The RegisterRoutine macro registers a function within a dynamic-link library (DLL). Registered functions can be used in macro footnotes in topic files or in the [CONFIG] section of the project file, the same as standard Help macros.

Syntax

Parameters

DLL-name

Specifies the filename of the DLL. The filename must be enclosed in quotation marks ("). If Windows Help cannot find the library, it displays an error message.

function-name

Specifies the name of the function to execute in the designated DLL.

format-spec

Specifies a string indicating the formats of parameters passed to the function. The format string must be enclosed in quotation marks. Characters in the string represent C parameter types:

Character	Description
u	unsigned short (WORD)
U	unsigned long  (DWORD)
i	short int
I	int
s	near char * (PSTR)
S	far char * (LPSTR)
v	void
If the function is used as a Help macro, Windows Help makes sure the macro parameters match the parameter types given in this macro.

Remarks

The RegisterRoutine macro can be abbreviated as RR.

Example

The following call registers a routine named PlayAudio in a DLL, MMLIB.DLL. PlayAudio takes arguments of the far char *, int, and unsigned long types:

RegisterRoutine("MMLIB", "PlayAudio", "SIU")

See Also

[CONFIG]


RemoveAccelerator

The RemoveAccelerator macro removes the assignment of a Help macro to an accelerator key (or key combination). These assignments are made by using the AddAccelerator macro.

Syntax

RemoveAccelerator(key, shift-state)

Parameters

key

Specifies the Windows virtual-key value. For a list of Virtual-Key Codes, see the Microsoft Windows Programmer's Reference, Volume 3.

shift-state

Specifies the combination of ALT, SHIFT, and CTRL keys that were used with the accelerator. This parameter may be one of the following values:

Value	Meaning
0	None
1	SHIFT
2	CTRL
3	SHIFT+CTRL
4	ALT
5	ALT+SHIFT
6	ALT+CTRL
7	SHIFT+ALT+CTRL
Remarks

The RemoveAccelerator macro can be abbreviated as RA. No error occurs when this macro is used with an accelerator for which a macro was not defined.

Example

The following macro disassociates a macro from the ALT+SHIFT+CONTROL+F4 key combination:

RemoveAccelerator(0x73, 7)

See Also

AddAccelerator


SaveMark

The SaveMark macro saves the location of the currently displayed topic and file and associates a text marker with that location. The GotoMark macro can then be used to jump to this location.

Syntax

SaveMark("marker-text")

Parameters

marker-text

Specifies the text marker to be used to identify the topic location. This text must be enclosed in quotation marks ("), and it must be unique. If the same text is used for more than one marker, the most recently entered marker is used.

Remarks

A text marker can be used with the GotoMark, DeleteMark, IfThen, and IfThenElse macros.

If the user exits Windows Help, all text markers are deleted.

Example

The following macro saves the marker "Managing Memory" in the current topic:

SaveMark("Managing Memory")

See Also

DeleteMark, GotoMark, IfThen, IfThenElse


Search

The Search macro displays the dialog for the Search button, which allows users to search for topics using keywords defined by the K footnote character.

Syntax

Search()

Parameters

This macro does not take any parameters.

Remarks

Windows Help ignores this macro if it is executed in a secondary window.


SetContents

The SetContents macro designates a specific topic as the Contents topic in the specified Help file.

Syntax

SetContents("filename", context-number)

Parameters

filename

Specifies the name of the Help file that contains the Contents topic. The filename must be enclosed in quotation marks ("). If Windows Help cannot find this file, it displays an error message and does not perform the jump.

context number

Specifies the context number of the topic in the specified file. The context number must be defined in the [MAP] section of the project file. If the context number is not valid, Windows Help displays an error message.

Example

The following example sets the topic mapped to the context number 801 in the PROGMAN.HLP file as the Contents topic. After executing this macro, clicking the Contents button will cause a jump to the topic specified by the context-number parameter:

SetContents("PROGMAN.HLP", 801)

See Also

[MAP]


SetHelpOnFile

Syntax

SetHelpOnFile("filename")

Parameters

filename

Specifies the name of the replacement How to Use Help file. The filename must be enclosed in quotation marks ("). If Windows Help cannot find this file, it displays an error message.

Remarks

If this macro appears in a topic in the Help file, the replacement file is set after execution of the macro. If this macro appears in the [CONFIG] section of the project file, the replacement file is set when the Help file is opened.

Example

The following macro sets the Using Help file to MYHELP.HLP:

SetHelpOnFile("myhelp.hlp")

See Also

[CONFIG]


UncheckItem

The UncheckItem macro removes the check mark from a menu item.

Syntax

UncheckItem("item-id")

Parameters

item-id

Identifies the menu item to uncheck. The item identifier must be enclosed in quotation marks.

Remarks

The UncheckItem macro can be abbreviated UI.

See Also

CheckItem


Help Statement Reference

This section lists the RTF keywords recognized by the Help compiler and the special Help statements in alphabetic order. Help-specific commands that are not RTF keywords are marked "Help only." The following table summarizes each RTF keyword and Help statement:

RTF Keyword	Description
\'	Inserts character by value
\ansi	Specifies ANSI character set
\b	Starts bold text
\bin	Specifies picture (bitmap or metafile) data
bmc	Displays picture in text (Help only)
bmcwd	Displays picture in current line of text (Help only)
bml	Displays picture at left margin (Help only)
bmlwd	Displays picture at left margin (Help only)
bmr	Displays picture at right margin (Help only)
bmrwd	Displays picture at right margin (Help only)
\box	Draws box
\brdrb	Draws bottom border
\brdrbar	Draws vertical bar
\brdrdb	Sets double-lined borders
\brdrdot	Sets dotted border
\brdrl	Draws left border
\brdrr	Draws right border
\brdrs	Sets standard borders
\brdrt	Draws top border
\brdrth	Sets thick borders
\cell	Marks end of table cell
\cellx	Sets the position of cell's right edge
\cf	Sets foreground color
\colortbl	Creates color table
\deff	Sets default font
emc	Allows DLL to paint window in text (Help only)
eml	Allows DLL to paint window at left margin (Help only)
emr	Allows DLL to paint window at right margin (Help only)
\fi	Sets first-line indent
\fldrslt	Result of field
\f	Sets font
\fonttbl	Creates font table
\footnote	Defines topic-specific information
\fs	Sets font size
\i	Starts italic text
\intbl	Marks paragraph as in table
\keep	Makes text non-wrapping
\keepn	Creates nonscrolling region
\li	Sets left indent
\line	Breaks current line
\mac	Sets Apple® Macintosh® character set
\page	Ends current topic
\par	Marks end of paragraph
\pard	Restores default paragraph properties
\pc	Sets PC character set
\pichgoal	Specifies desired picture height
\pich	Specifies picture height
\picscalex	Specifies horizontal scaling value
\picscaley	Specifies vertical scaling value
\pict	Creates picture
\picwgoal	Specifies desired picture width
\picw	Specifies picture width
\plain	Restores default character properties
\qc	Centers text
\ql	Aligns text left
\qr	Aligns text right
\ri	Sets right indent
\row	Marks end of table row
\rtf	Specifies RTF version
\sa	Sets spacing after paragraph
\sb	Sets space before
\scaps	Starts small capitals
\sect	Marks end of section and paragraph
\sl	Sets spacing between lines
\strike	Creates hotspot
\tab	Inserts tab character
\tqc	Tabs and centers text
\tqr	Tabs and aligns text right
\trgaph	Sets space between text columns in table
\trleft	Sets left margin for first cell
\trowd	Sets table defaults
\trqc	Sets relative column widths
\trql	Left-aligns table row
\tx	Sets tab stop
\ul	Creates link to a pop-up topic
\uldb	Creates hot spot
\v	Creates link to a topic
\wbitmap	Specifies Windows bitmap and its type
\wbmbitspixel	Specifies number of bits per pixel
\wbmplanes	Specifies number of planes
\wbmwidthbytes	Specifies bitmap width in bytes
\windows	Sets Windows character set
\wmetafile	Specifies Windows metafile


\'

The \' statement converts the specified hexadecimal number into a character value and inserts the value into the Help file. The appearance of the character when displayed depends on the character set specified for the Help file.

Syntax

\'hh

Parameter

hh

Specifies a two-digit hexadecimal value.

Remarks

Since the Microsoft Help Compiler does not accept character values greater than 127, the \' statement is the only way to insert such character values into the Help file.

Example

The following example inserts a trademark in a Help file that uses the \ansi statement to set the character set:

ABC\'99 is a trademark of the ABC Product Corporation.

See Also

\ansi, \mac, \pc


\ansi

The \ansi statement sets the American National Standards Institute (ANSI) character set. The Windows character set is essentially equivalent to the ANSI character set.

See Also

\mac, \pc


\b

The \b statement starts bold text. The statement applies to all subsequent text up to the next \plain or \b0 statement.

Remarks

No \plain or \b0 statement is required if the \b statement and subsequent text are enclosed in braces. Braces limit the scope of a character property statement to just the enclosed text.

The \b0 statement was first supported in the Microsoft Help Compiler version 3.1

Example

The following example sets "Note" to bold:

{\b Note}  Setting the Auto option frees novice users from determining their system configurations.

See Also

\i, \plain, \scaps


\bin

The \bin statement indicates the start of binary picture data. The Help compiler interprets subsequent bytes in the file as binary data. This statement is used in conjunction with the \pict statement.

Syntax

\binn

Parameter

n

Specifies the number of bytes of binary data following the statement.

Remarks

A single space character must separate the \bin statement from subsequent bytes. The Microsoft Help Compiler assumes that all subsequent bytes, including linefeed and carriage return characters, are binary data. These bytes can have any value in the range 0 through 255. For this reason, the \bin statement is typically used in program-generated files only.

If the \bin statement is not given with a \pict statement, the default picture data format is hexadecimal.

See Also

\pict


bmc

The bmc statement displays a specified bitmap or metafile in the current line of text. The statement positions the bitmap or metafile as if it were the next character in the line, aligning it on the base line and applying the current paragraph properties.

Syntax

\{bmc filename\}

Parameter

filename

Specifies the name of a file containing a Windows bitmap, a placeable Windows metafile, a multiresolution bitmap, or a segmented-graphics bitmap.

Remarks

Since the bmc statement is not a standard RTF statement, the Microsoft Help Compiler relies on the opening and closing braces, including the backslashes (\), to distinguish the statement from regular text.

If a file containing a metafile is specified, the file must contain a placeable Windows metafile; the Microsoft Help Compiler will not accept standard Windows metafiles. Furthermore, Windows Help sets the MM_ANISOTROPIC mode prior to displaying the metafile, so the placeable Windows metafile must either set the window origin and extents or set some other mapping mode.

Example

The following example inserts a bitmap representing a keyboard key in a paragraph:

\par
Press the \{bmc escape.bmp\} key to return to the main window.
\par

See Also

bmr, bml, \wbitmap


bmcwd

The bmcwd statement displays a specified bitmap or metafile in the current line of text. The statement positions the bitmap or metafile as if it were the next character in the line, aligning it on the base line and applying the current paragraph properties.

The bmcwd statement is intended to be used for small bitmaps or metafiles that appear only once in a Help file.

Syntax

\{bmcwd filename\}

Parameter

filename

Specifies the name of a file containing a Windows bitmap, a placeable Windows metafile, a multiresolution bitmap, or a segmented-graphics bitmap.

Remarks

Since the bmcwd statement is not a standard RTF statement, the Help compiler relies on the opening and closing braces, including the backslashes (\), to distinguish the statement from regular text or RTF codes.

If a file containing a metafile is specified, the file must contain a placeable Windows metafile; the Help compiler will not accept standard Windows metafiles. Furthermore, Windows Help sets the MM_ANISOTROPIC mode prior to displaying the metafile, so the placeable Windows metafile must either set the window origin and extents or set some other mapping mode.

See Also

bmr, bml, bmc, \wbitmap


bml

The bml statement displays a specified bitmap or metafile at the left margin of the Help window. The first line of subsequent text aligns with the upper-right corner of the image and subsequent lines wrap along the right edge of the image.

Syntax

\{bml filename\}

Parameter

filename

Specifies the name of a file containing a Windows bitmap, a placeable Windows metafile, a multiresolution bitmap, or a segmented-graphics bitmap.

Remarks

Since the bml statement is not a standard RTF statement, the Microsoft Help Compiler relies on the opening and closing braces, including the backslashes (\), to distinguish the statement from regular text or RTF codes.

If a file containing a metafile is specified, the file must contain a placeable Windows metafile; the Microsoft Help Compiler will not accept standard Windows metafiles. Furthermore, Windows Help sets the MM_ANISOTROPIC mode prior to displaying the metafile, so the placeable Windows metafile must either set the window origin and extents or set some other mapping mode.

Example

The following example places a bitmap at the left margin. The subsequent paragraph wraps around the bitmap:

\par
\{bml roadmap.bmp\}
The map at the left shows the easiest route to the school.
Although many people use Highway 125, there are fewer stops
and less traffic if you use Ames Road.

See Also

bmc, bmr, \wbitmap


bmlwd

The bmlwd statement displays a specified bitmap or metafile at the left margin of the Help window. The first line of subsequent text aligns with the upper-right corner of the image and subsequent lines wrap along the right edge of the image.

The bmlwd statement is intended to be used for small bitmaps or metafiles that appear only once in a Help file.

Syntax

\{bmlwd filename\}

Parameter

filename

Specifies the name of a file containing a Windows bitmap, a placeable Windows metafile, a multiresolution bitmap, or a segmented-graphics bitmap.

Remarks

Since the bmlwd statement is not a standard RTF statement, the Windows Help compiler relies on the opening and closing braces, including the backslashes (\), to distinguish the statement from regular text or RTF codes.

If a file containing a metafile is specified, the file must contain a placeable Windows metafile; the Help compiler will not accept standard Windows metafiles. Furthermore, Windows Help sets the MM_ANISOTROPIC mode prior to displaying the metafile, so the placeable Windows metafile must either set the window origin and extents or set some other mapping mode.

See Also

bmc, bml, bmr, \wbitmap


bmr

The bmr statement displays a specified bitmap or metafile at the right margin of the Help window. The first line of subsequent text aligns with the upper-left corner of the image and subsequent lines wrap along the left edge of the image.

Syntax

\{bmr filename\}

Parameter

filename

Specifies the name of a file containing a Windows bitmap, a placeable Windows metafile, a multiresolution bitmap, or a segmented-graphics bitmap.

Remarks

Since the bmr statement is not a standard RTF statement, the Microsoft Help Compiler relies on the opening and closing braces, including the backslashes (\), to distinguish the statement from regular text or RTF codes.

If a file containing a metafile is specified, the file must contain a placeable Windows metafile; the Help compiler will not accept standard Windows metafiles. Furthermore, Windows Help sets the MM_ANISOTROPIC mode prior to displaying the metafile, so the placeable Windows metafile must either set the window origin and extents or set some other mapping mode.

Example

The following example places a bitmap at the right margin. The subsequent paragraph wraps around the bitmap:

\par
\{bmr roadmap.bmp\}
The map at the right shows the easiest route to the school.
Although many people use Highway 125, there are fewer stops
and less traffic if you use Ames Road.

See Also

bmc, bml, \wbitmap


bmrwd

The bmrwd statement displays a specified bitmap or metafile at the right margin of the Help window. The first line of subsequent text aligns with the upper-left corner of the image and subsequent lines wrap along the left edge of the image.

The bmrwd statement is intended to be used for small bitmaps or metafiles that appear only once in a Help file.

Syntax

\{bmrwd filename\}

Parameter

filename

Specifies the name of a file containing a Windows bitmap, a placeable Windows metafile, a multiresolution bitmap, or a segmented-graphics bitmap.

Remarks

Since the bmrwd statement is not a standard RTF statement, the Windows Help compiler relies on the opening and closing braces, including the backslashes (\), to distinguish the statement from regular text or RTF codes.

If a file containing a metafile is specified, the file must contain a placeable Windows metafile; the Help compiler will not accept standard Windows metafiles. Furthermore, Windows Help sets the MM_ANISOTROPIC mode prior to displaying the metafile, so the placeable Windows metafile must either set the window origin and extents or set some other mapping mode.

See Also

bmc, bml, bmr, \wbitmap


\box

The \box statement draws a box around the current paragraph or picture. The statement applies to all subsequent paragraphs or pictures up to the next \pard statement.

Remarks

For paragraphs, Windows Help uses the height of the paragraph, excluding space before or after the paragraph, as the height of the box. For pictures (as defined by \pict statements), Windows Help uses the specified height of the picture as the height of the box. For both paragraphs and pictures, the width of the box is equal to the space between the left and right indents.

Windows Help draws the box using the current border style.

Example

The following example draws a box around the paragraph:

\par \box
{\b Note}  Setting the Auto option frees novice users from
determining their system configurations.
\par \pard

See Also

\brdrb, \brdrl, \brdrr, \brdrt, \pard, \pict


\brdrb

The \brdrb statement draws a border below the current paragraph or picture. The statement applies to all subsequent paragraphs or pictures up to the next \pard statement.

Remarks

Windows Help draws the border using the current border style.

See Also

\box, \brdrbar, \brdrl, \brdrr, \brdrt, \pard


\brdrbar

The \brdrbar statement draws a vertical bar to the left of the current paragraph or picture. The statement applies to all subsequent paragraphs or pictures up to the next \pard statement.

Remarks

Windows Help draws the border using the current border style.

In a print-based document, the \brdrbar statement draws the bar on the right side of paragraphs on odd-numbered pages, but on the left side of paragraphs on even-numbered pages.

See Also

\box, \brdrl, \brdrb, \brdrr, \brdrt, \pard


\brdrdb

The \brdrdb statement selects a double line for drawing borders. The selection applies to all subsequent paragraphs or pictures up to the next \pard statement.

See Also

\brdrdot, \brdrs, \brdrth, \pard


\brdrdot

The Help compiler ignores this statement.

See Also

\brdrs, \brdrth, \brdrdb, \pard


\brdrl

The \brdrl statement draws a border to the left of the current paragraph or picture. The statement applies to all subsequent paragraphs or pictures up to the next \pard statement.

Remarks

Windows Help draws the border using the current border style.

See Also

\box, \brdrb, \brdrbar, \brdrr, \brdrt, \pard


\brdrr

The \brdrr statement draws a border to the right of the current paragraph or picture. The statement applies to all subsequent paragraphs or pictures up to the next \pard statement.

Remarks

Windows Help draws the border using the current border style.

See Also

\box, \brdrb, \brdrbar, \brdrl, \brdrt, \pard


\brdrs

The \brdrs statement selects a standard-width line for drawing borders. The selection applies to all subsequent paragraphs or pictures up to the next \pard statement.

Remarks

The Help compiler ignores this statement.

See Also

\brdrdb, \brdrdot, \brdrth, \pard


\brdrt

The \brdrt statement draws a border above the current paragraph or picture. The statement applies to all subsequent paragraphs or pictures up to the next \pard statement.

Remarks

Windows Help draws the border using the current border style.

See Also

\box, \brdrb, \brdrbar, \brdrl, \brdrr, \pard


\brdrth

The \brdrth statement selects a thick line for drawing borders. The selection applies to all subsequent paragraphs or pictures up to the next \pard statement.

See Also

\brdrdb, \brdrdot, \brdrs, \pard


\cb

The Help compiler ignores this statement.

Syntax

\cbn

Parameter

n

Specifies the color number to set as the background color. The number must be an integer number in the range 1 to the maximum number of colors specified in the color table for the Help file. If an invalid color number is specified, Windows Help uses the default background color.

Remarks

The default background color is the window background color set by Control Panel.

See Also

\cf, \colortbl


\cell

The \cell statement marks the end of a cell in a table. A cell consists of all paragraphs from a preceding \intbl or \cell statement to the ending \cell statement. Windows Help formats and displays these paragraphs using the left and right margins of the cell and any current paragraph properties.

Remarks

This statement was first supported in the Microsoft Help Compiler version 3.1.

Example

The following example creates a two-column table. The second column contains three separate paragraphs, each having different paragraph properties:

\cellx2880\cellx5760
\intbl
Alignment\cell
\ql
Left-aligned
\par
\qc
Centered
\par
\qr
Right-aligned\cell
\row \pard

See Also

\cellx, \intbl, \row, \trgaph, \trleft, \trowd


\cellx

The \cellx statement sets the absolute position of the right edge of a table cell. One \cellx statement must be given for each cell in the table. The first \cellx statement applies to the left-most cell, the last to the right-most cell. For each \cellx statement, the specified position applies to the corresponding cell in each subsequent row of the table up to the next \trowd statement.

Syntax

\cellxn

Parameter

n

Specifies the position of the cell's right edge, in twips. The position is relative to the left edge of the Help window. It is not affected by the current indents.

Remarks

A table consists of a grid of cells in columns and rows. Each cell has an explicitly defined right edge; the position of a cell's left edge is the same as the position of the right edge of the adjacent cell. For the left-most cell in a row, the left edge position is equal to the Help window's left margin position. Each cell has a left and right margin between which Windows Help aligns and wraps text. By default, the margin positions are equal to the left and right edges. The \trgaph and \trleft statements can be used to set different margins for all cells in a row.

This statement was first supported in the Microsoft Help Compiler version 3.1.

Example

The following example creates a three-column table having two rows. The positions of the right edges of the three cells are 2, 4, and 6 inches, respectively:

\cellx2880\cellx5760\cellx8640
\intbl
Row 1 Cell 1\cell
Row 1 Cell 2\cell
Row 1 Cell 3\cell
\row
\intbl
Row 2 Cell 1\cell
Row 2 Cell 2\cell
Row 2 Cell 3\cell
\row \pard

See Also

\cell, \intbl, \row, \trgaph, \trleft, \trowd


\cf

The \cf statement sets the foreground color. The new color applies to all subsequent text up to the next \plain or \cf statement.

Syntax

\cfn

Parameter

n

Specifies the color number to set as foreground. The number must be an integer number in the range 1 to the maximum number of colors specified in the color table for the Help file. If an invalid color number is specified, Windows Help uses the default foreground color.

Remarks

No \plain or \cf statement is required if the \cf statement and subsequent text are enclosed in braces. Braces limit the scope of a character property statement to the enclosed text only.

If the \cf statement is not given, the default foreground color is the text color set by Control Panel.

Example

The following example displays green text:

{\colortbl;\red0\green255\blue0;}
{\cf1 This text is green.}

See Also

\colortbl, \plain


\chftn

The Microsoft Help Compiler ignores this statement.

Syntax

\chftnn

Parameter

n

Specifies the footnote reference character.

See Also

\footnote


\clmgf

The Microsoft Help Compiler ignores this statement.

Remarks

All cells between the \clmgf statement and a subsequent \clmrg statement are combined into a single cell. The left edge of the new cell is the same as that of the leftmost cell to be merged; the right edge is the same as that of the rightmost cell.

See Also

\clmrg


\clmrg

The Microsoft Help Compiler ignores this statement.

Remarks

All cells between the \clmgf statement and a subsequent \clmrg statement are combined into a single cell. The left edge of the new cell is the same as that of the leftmost cell to be merged; the right edge is the same as that of the rightmost cell.

See Also

\clmgf


\colortbl

The \colortbl statement creates a color table for the Help file. The color table consists of one or more color definitions. Each color definition consists of one \red, \green, and \blue statement specifying the amount of primary color to use to generate the final color. Each color definition must end with a semicolon (;).

Syntax

{\colortbl
\redredval\greengreenval\blueblueval;
    . . .
}

Parameters

redval

Specifies the intensity of red in the color. It must be an integer in the range 0 through 255.

greenval

Specifies the intensity of green in the color. It must be an integer in the range 0 through 255.

blueval

Specifies the intensity of blue in the color. It must be an integer in the range 0 through 255.

Remarks

Color definitions are implicitly numbered starting at zero. A color definition's implicit number can be used in the \cf statement to set the foreground color.

The default colors are the window-text and window-background colors set by Control Panel. To override the default colors, both a \colortbl statement and a \cf statement must be given.

Example

The following example creates a color table containing two color definitions. The first color definition is empty (only the semicolon is given), so color number 0 always represents the default color. The second definition specifies green; color number 1 can be used to display green text:

{\colortbl;\red0\green255\blue0;}

See Also

\cf


\deff

The \deff statement sets the default font number. Windows Help uses the number to set the default font whenever a \plain statement is given or an invalid font number is given in a \f statement.

Syntax

\deffn

Parameter

n

Specifies the number of the font to be used as the default font. This parameter must be a valid font number as specified by the \fonttbl statement for the Help file.

Remarks

If the \deff statement is not given, the default font number is zero.

See Also

\f, \fonttbl, \plain


emc

The emc statement allows an external dynamic-link library to paint a window that is embedded in a Help topic. This statement displays the window in the current line of text. The statement positions the window as if it were the next character in the line, aligning it on the base line and applying the current paragraph properties.

Syntax

\{emc module, class, data [, dx, dy]\}

Parameters

module

Specifies the name of the dynamic-link library that paints the embedded window.

class

Specifies the name of the registered window class for the embedded window.

data

Specifies a string that is passed to the embedded window in its WM_CREATE message.

dx

Specifies the suggested width of the embedded window. This parameter is optional.

dy

Specifies the suggested height of the embedded window. This parameter is optional.

Remarks

Since the emc statement is not a standard RTF statement, the Microsoft Help Compiler relies on the opening and closing braces, including the backslashes (\), to distinguish the statement from regular text or RTF codes.

See Also

bmr, bml, bmc, eml, emr, \wbitmap, WM_CREATE


eml

The eml statement allows an external dynamic-link library to paint a window that is embedded at the left margin in a Help topic. The first line of subsequent text aligns with the upper-right corner of the window and subsequent lines wrap along the right edge of the window.

Syntax

\{eml module, class, data [, dx, dy]\}

Parameters

module

Specifies the name of the dynamic-link library that paints the embedded window.

class

Specifies the name of the registered window class for the embedded window.

data

Specifies a string that is passed to the embedded window in its WM_CREATE message.

dx

Specifies the suggested width of the embedded window. This parameter is optional.

dy

Specifies the suggested height of the embedded window. This parameter is optional.

Remarks

Since the eml statement is not a standard RTF statement, the Microsoft Help Compiler relies on the opening and closing braces, including the backslashes (\), to distinguish the statement from regular text or RTF codes.

See Also

bmr, bml, bmc, emc, emr, \wbitmap, WM_CREATE


emr

The emr statement allows an external dynamic-link library to paint a window that is embedded at the right margin in a Help topic. The first line of subsequent text aligns with the upper-left corner of the window and subsequent lines wrap along the left edge of the window.

Syntax

\{emr module, class, data [, dx, dy]\}

Parameters

module

Specifies the name of the dynamic-link library that paints the embedded window.

class

Specifies the name of the registered window class for the embedded window.

data

Specifies a string that is passed to the embedded window in its WM_CREATE message.

dx

Specifies the suggested width of the embedded window. This parameter is optional.

dy

Specifies the suggested height of the embedded window. This parameter is optional.

Remarks

Since the emr statement is not a standard RTF statement, the Microsoft Help Compiler relies on the opening and closing braces, including the backslashes (\), to distinguish the statement from regular text or RTF codes.

See Also

bmr, bml, bmc, emc, eml, \wbitmap, WM_CREATE


\f

The \f statement sets the font. The new font applies to all subsequent text up to the next \plain or \f statement.

Syntax

\fn

Parameter

n

Specifies the font number. This parameter must be one of the integer font numbers defined in the font table for the Help file.

Remarks

The \f statement does not set the point size of the font; use the \fs statement instead.

No \plain or \f statement is required if the \f statement and subsequent text are enclosed in braces. Braces limit the scope of a character property statement to just the enclosed text.

If the \f statement is not given, the default font is defined by the \deff statement (or is zero if no \deff statement is given).

Example

The following example uses the Arial font to display text:

{\fonttbl {\f0\fswiss Arial;}}
{\f0
This text illustrates the Arial font.}
\par

See Also

\deff, \fonttbl, \fs, \plain


\fi

The \fi statement sets the first-line indent for the paragraph. The new indent applies to the first line of each subsequent paragraph up to the next \pard statement or \fi statement. The first-line indent is always relative to the current left indent.

Syntax

\fin

Parameter

n

Specifies the indent, in twips. This parameter can be either a positive or negative number.

Remarks

If the \fi statement is not given, the first-line indent is zero by default.

Example

The following example uses the first-line indent and a tab stop to make a numbered list:

\tx360\li360\fi-360
1
\tab
Insert the disk in drive A.
\par
2
\tab
Type a:setup and press the ENTER key.
\par
3
\tab
Follow the instructions on the screen.
\par \pard

See Also

\li, \pard


\field

The Microsoft Help Compiler ignores this statement and all related field statements except the \fldrslt statement.

See Also

\fldrslt


\fldrslt

The \fldrslt statement specifies the most recently calculated result of a field. The Microsoft Help Compiler interprets the result as text and formats it using the current character and paragraph properties.

Remarks

The Help compiler ignores all field statements except the \fldrslt statement. Any text associated with other field statements is ignored.


\fonttbl

The \fonttbl statement creates a font table for the Help file. The font table consists of one or more font definitions. Each definition consists of a font number, a font family, and a font name.

Syntax

{\fonttbl
    {\fn\family font-name;}
        . . .
}

Parameter

n

Specifies the font number. This parameter must be an integer. This number can be used in subsequent \f statements to set the current font to the specified font. In the font table, font numbers should start at zero and increase by one for each new font definition.

family

Specifies the font family. This parameter must be one of the following:

Value	Meaning
fnil	Unknown or default fonts (default)
froman	Roman, proportionally spaced serif fonts (for example, Times New Roman and Palatino)
fswiss	Swiss, proportionally spaced sans serif fonts (for example, Arial)
fmodern	Fixed-pitch serif and sans serif fonts (for example, Courier and Lucida Sans Typewriter)
fscript	Script fonts (for example, Cursive and Lucida Handwriting)
fdecor	Decorative fonts (for example, Old English and Bodoni Open)
ftech	Technical, symbol, and mathematical fonts (for example, Symbol)
font-name

Specifies the name of the font. This parameter should specify an available Windows font.

Remarks

If a font with the specified name is not available, Windows Help chooses a font from the specified family. If no font from the given family exists, Windows Help chooses a font having the same character set as specified for the Help file.

The \deff statement sets the default font number for the Help file. The default font is set whenever the \pard statement is given.

See Also

\deff, \f, \fs, \pard


\footnote

The \footnote statement defines topic-specific information, such as the topic's build tags, context string, title, browse number, keywords, and execution macros. Every topic must have a context string, at least, to give the user access to the topic through links.

Syntax

{n}{\footnote {n} text}

Parameter

n

Specifies the footnote character. It can be one of the following:

Value	Meaning
*	Specifies a build tag. The Microsoft Help Compiler uses build tags to determine whether it should include the topic in the Help file. The text parameter can be any combination of characters but must not contain spaces. Uppercase and lowercase characters are treated as equivalent characters (case-insensitive). If a topic has build-tag statements, they must be the first statements in the topic. The Microsoft Help Compiler checks a topic for build tags if the project file specifies a build expression using the BUILD option.
#	Specifies a context string. The text parameter can be any combination of letters and digits but must not contain spaces. Uppercase and lowercase characters are treated as equivalent characters (case-insensitive). The context string can be used with the \v statement in other topics to create links to this topic.
$	Specifies a topic title. Windows Help uses the topic title to identify the topic in the Search and History dialog boxes. The text parameter can be any combination of characters including spaces.
+	Specifies the browse-sequence identifier. Windows Help adds topics having an identifier to the browse sequence and allows users to view the topics by using the browse buttons. The text parameter can be a combination of letters and digits. Windows Help determines the order of topics in the browse sequence by sorting the identifier alphabetically. If two topics have the same identifier, Windows Help assumes that the topic that was compiled first is to be displayed first. Windows Help uses the browse sequence identifier only if the browse buttons have been enabled by using the BrowseButtons macro.
K	Specifies a keyword. Windows Help displays all keywords in the Help file in the Search dialog box and allows a user to choose a topic to view by choosing a keyword. The text parameter can be any combination of characters including spaces. If the first character is the letter K, it must be preceded with an extra space or a semicolon. More than one keyword can be given by separating the keywords with semicolons (;). A topic cannot contain keywords unless it also has a topic title.
!	Specifies a Help macro. Windows Help executes the macro when the topic is displayed. The text parameter can be any Help macro.
If n is any letter (other than K), the footnote specifies an alternative keyword. Windows applications can search for topics having alternative keywords by using the HELP_MULTIKEY command with the WinHelp function.

text

Specifies the build tag, context string, topic title, browse-sequence number, keyword, or macro associated with the footnote. This parameter depends on the footnote type as specified by the n parameter.

Remarks

Repetition of the footnote character, n, in the syntax is deliberate.

A topic can have more than one build-tag, context-string, keyword, and Help-macro statement, but must not have more than one topic-title or browse-sequence-number statement.

In print-based documents, the \footnote statement creates a footnote. The footnote is anchored to the character immediately preceding the \footnote statement.

The characters in a context string must be alphanumeric and can include underscore characters (_) and periods (.).

The browse sequence string consists of a major sequence string and a minor sequence string, delimited by a colon:

{+}{\footnote {+} major:minor}

This syntax specifies disjoint sets of ordered browse sequences. The major sequence string determines which browse sequence a topic belongs to, while the minor sequence string determines its position. Minor sequence strings are sorted alphabetically, not numerically; to use numbers, they should be preceded with zeros so that they are all the same length. All topics with browse sequence strings that omit the major sequence string are placed on the same browse sequence.

A topic cannot have more than one build tag footnote. If a topic has a build tag footnote, it must be the first thing in that topic. The title, browse sequence, and macro must be in the first paragraph. Context strings and keywords may appear anywhere; if placed in the middle of a topic, jumps to that context string or keyword will bring you to the middle of that topic.

Example

The following example defines a topic titled Short Topic. The context string topic1 can be used to create links to this topic. The keywords example topic and short topic appear in the Search dialog box and can be used to choose the topic for viewing:

${\footnote Short Topic}
#{\footnote topic1}
K{\footnote example topic;short topic}
This topic has a title, context string, and two keywords.
\par
\page

See Also

\v


\fs

The \fs statement sets the size of the font. The new font size applies to all subsequent text up to the next \plain or \fs statement.

Syntax

\fsn

Parameter

n

Specifies the size of the font, in half points.

Remarks

The \fs statement does not set the font face; use the \f statement instead.

No \plain or \fs statement is required if the \fs statement and subsequent text are enclosed in braces. Braces limit the scope of a character property statement to just the enclosed text.

If the \fs statement is not given, the default font size is 24.

Example

The following example sets the size of the font to 10 points:

{\fs20 This line is in 10 point type.}
\par

See Also

\plain, \f


\i

The \i statement starts italic text. The statement applies to all subsequent text up to the next \plain or \i0 statement.

Remarks

No \plain or \i0 statement is required if the \i statement and subsequent text are enclosed in braces. Braces limit the scope of a character property statement to just the enclosed text.

Example

The following example sets "not" to italic:

You must {\i not} save the file without first setting the
Auto option.

See Also

\b, \plain, \scaps


\intbl

The \intbl statement marks subsequent paragraphs as part of a table. The statement applies to all subsequent paragraphs up to the next \row statement.

Remarks

This statement was first supported in Microsoft Help Compiler version 3.1.

Example

The following example creates a three-column table having two rows:

\cellx1440\cellx2880\cellx4320
\intbl
Row 1 Column 1\cell
Row 1 Column 2\cell
Row 1 Column 3\cell \row
\intbl
Row 2 Column 1\cell
Row 2 Column 2\cell
Row 2 Column 3\cell \row \pard

See Also

\cell, \cellx, \row, \trgaph, \trleft, \trowd


\keep

The \keep statement prevents Windows Help from wrapping text to fit the Help window. The statement applies to all subsequent paragraphs up to the next \pard statement.

Remarks

If the text in a paragraph exceeds the width of the Help window, Help displays a horizontal scroll bar.

In print-based documents, the \keep statement keeps paragraphs intact.

See Also

\keepn, \line


\keepn

The \keepn statement creates a nonscrolling region at the top of the Help window for the given topic. The \keepn statement applies to all subsequent paragraphs up to the next \pard statement. All paragraphs with this paragraph property are placed in the nonscrolling region.

Remarks

If a \keepn statement is used in a topic, it must be applied to the first paragraph in the topic (and subsequent paragraphs as needed). The Help compiler displays an error message and does not create a nonscrolling region if paragraphs are given before the \keepn statement. Only one nonscrolling region per topic is allowed.

Windows Help formats, aligns, and wraps text in the nonscrolling region just as it does in the rest of the topic. It separates the nonscrolling region from the rest of the Help window with a horizontal bar. Windows Help sets the height of the nonscrolling region so that all paragraphs in the region can be viewed if the Help window is large enough. If the window is smaller than the nonscrolling region, the user will be unable to view the rest of the topic. For this reason, the nonscrolling region is typically reserved for a single line of text specifying the name or title of the topic.

In print-based documents, the \keepn statement keeps the subsequent paragraph with the paragraph that follows it.

See Also

\keep, \page


\li

The \li statement sets the left indent for the paragraph. The indent applies to all subsequent paragraphs up to the next \pard or \li statement.

Syntax

\lin

Parameter

n

Specifies the indent, in twips. The value can be either positive or negative.

Remarks

If the \li statement is not given, the left indent is zero by default. Windows Help automatically provides a small left margin so that if no indent is specified the text does not start immediately at the left edge of the Help window.

Specifying a negative left indent moves the starting point for a line of text to the left of the default left margin. If the negative indent is large enough, the start of the text may be clipped by the left edge of the Help window.

Example

The following example uses the left indent and a tab stop to make a bulleted list. In this example, font number 0 is assumed to be the Symbol font:

Use the Auto command to:
\par
\tx360\li360\fi-360
{\f0\'B7}
\tab

Save files automatically
\par
{\f0\'B7}
\tab
Prevent overwriting existing files
\par
{\f0\'B7}
\tab
Create automatic backup files
\par \pard

See Also

\fi, \pard, \ri


\line

The \line statement breaks the current line without ending the paragraph. Subsequent text starts on the next line and is aligned and indented according to the current paragraph properties.

See Also

\par


\mac

The \mac statement sets the Apple Macintosh character set.

See Also

\ansi, \pc


\page

The \page statement marks the end of a topic.

Remarks

In a print-based document, the \page statement creates a page break.

Example

The following example shows a complete topic:

${\footnote Short Topic}
#{\footnote short_topic}
Most topics in a topic file consist of topic-title and
context-string statements followed by the topic text. Every
topic ends with a {\b \\page} statement.

\par
\page

See Also

\par


\par

The \par statement marks the end of a paragraph. The statement ends the current line of text and moves the current position to the left margin and down by the current line-spacing and space-after-paragraph values.

Remarks

The first line of text after a \par, \page, or \sect statement marks the start of a paragraph. When a paragraph starts, the current position is moved down by the current space-before-paragraph value. Subsequent text is formatted using the current text alignment, line spacing, and left, right, and first-line indents.

Example

The following example has three paragraphs:

\ql
This paragraph is left-aligned.
\par \pard
\qc
This paragraph is centered.
\par \pard
\qr
This paragraph is right-aligned.
\par

See Also

\line, \page, \pard, \sect


\pard

The \pard statement restores all paragraph properties to default values.

Remarks

If the \pard statement appears anywhere before the end of a paragraph (that is, before the \par statement), the default properties apply to the entire paragraph.

The default paragraph properties are as follows:

Property	Default
Alignment	Left-aligned
First-line indent	0
Left indent	0
Right indent	0
Space before	0
Space after	0
Line spacing	Tallest character
Tab stops	None
Borders	None
Border style	Single-width
See Also

\par


\pc

The \pc statement sets the OEM character set (also known as code page 437).

See Also

\ansi, \mac


\pca

The Help compiler ignores this statement.

See Also

\ansi, \mac, \pc


\pich

The \pich statement specifies the height of the picture. This statement must be used in conjunction with a \pict statement.

Syntax

\pichn

Parameter

n

Specifies the height of the picture, in twips or pixels, depending on the picture type. If the picture is a metafile, the width is in twips; otherwise, the width is, in pixels.

See Also

\pict, \picw


\pichgoal

The \pichgoal statement specifies the desired height of a picture. If necessary, Windows Help stretches or compresses the picture to match the requested height. This statement must be used in conjunction with a \pict statement.

Syntax

\pichgoaln

Parameter

n

Specifies the desired height, in twips.

Remarks

The \pichgoal statement is not supported for metafiles. Applications should use the \pich statement, instead.

See Also

\pich, \pict, \picwgoal


\picscalex

The \picscalex statement specifies the horizontal scaling value. This statement must be used in conjunction with a \pict statement.

Syntax

\picscalexn

Parameter

n

Specifies the scaling value as a percentage. If this value is greater than 100, the bitmap or metafile is enlarged.

Remarks

If the \picscalex statement is not given, the default scaling value is 100.

See Also

\pict, \picscaley


\picscaley

The \picscaley statement specifies the vertical scaling value. This statement must be used in conjunction with a \pict statement.

Syntax

\picscaleyn

Parameter

n

Specifies the scaling value as a percentage. If this value is greater than 100, the bitmap or metafile is enlarged.

Remarks

If the \picscaley statement is not given, the default scaling value is 100.

See Also

\pict, \picscalex


\pict

The \pict statement creates a picture. A picture consists of hexadecimal or binary data representing a bitmap or metafile.

Syntax

\pict picture-statements picture-data

Parameter

picture-statements

Specifies one or more statements defining the type of picture, the dimensions of the picture, and the format of the picture data. It can be a combination of the following statements:

Statement	Description
\wbitmap	Specifies a Windows bitmap.
\wmetafile	Specifies a Windows metafile.
\picwn	Specifies the picture width.
\pichn	Specifies the picture height.
\picwgoaln	Specifies the desired picture width.
\pichgoaln	Specifies the desired picture height.
\picscalexn	Specifies the horizontal scaling value.
\picscaleyn	Specifies the vertical scaling value.
\wbmbitspixeln	Specifies the number of bits per pixel.
\wbmplanesn	Specifies the number of planes.
\wbmwidthbytesn	Specifies the bitmap width, in bytes.
\binn	Specifies binary picture data and its length in bytes.
picture-data

Specifies hexadecimal or binary data representing the picture. The picture data follows the last picture statement.

Remarks

If a data format is not specified, the default format is hexadecimal.

See Also

\bin, \pich, \pichgoal, \picscalex, \picscaley, \picw, \picwgoal, \wbitmap, \wbmbitspixel, \wbmplanes, \wbmwidthbytes, \wmetafile


\picw

The \picw statement specifies the width of the picture. This statement must be used in conjunction with a \pict statement.

Syntax

\picwn

Parameters

n

Specifies the width of the picture, in twips or pixels, depending on the picture type. If the picture is a metafile, the width is in twips; otherwise, the width is in pixels.

See Also

\pict, \pich


\picwgoal

The \picwgoal statement specifies the desired width of the picture, in twips. If necessary, Windows Help stretches or compresses the picture to match the requested height. This statement must be used in conjunction with a \pict statement.

Syntax

\picwgoaln

Parameter

n

Specifies the desired width, in twips.

Remarks

The \picwgoal statement is not supported for metafiles. Applications should use the \picw statement, instead.

See Also

\pict, \picw, \pichgoal


\plain

The \plain statement restores the character properties to default values.

Remarks

The default character properties are as follows:

Property	Default
Bold	Off
Italic	Off
Small caps	Off
Font	0
Font size	24
See Also

\b, \i, \scaps, \f, \fs


\qc

The \qc statement centers text between the current left and right indents. The statement applies to subsequent paragraphs up to the next \pard statement or text-alignment statement.

Remarks

If a \ql, \qr, or \qc statement is not given, the text is left-aligned by default.

See Also

\pard, \ql, \qr


\qj

The Microsoft Help Compiler ignores this statement.

Remarks

If a \ql, \qr, \qc, or \qj statement is not given, the text is left-aligned by default.

See Also

\qc, \ql, \qr, \pard


\ql

The \ql statement aligns text along the left indent. The statement applies to subsequent paragraphs up to the next \pard statement or text-alignment statement.

Remarks

If a \ql, \qr, or \qc statement is not given, the text is left-aligned by default.

See Also

\pard, \qc, \qr


\qr

The \qr statement aligns text along the right indent. The statement applies to subsequent paragraphs up to the next \pard statement or text-alignment statement.

Remarks

If a \ql, \qr, or \qc statement is not given, the text is left-aligned by default.

See Also

\pard, \qc, \ql


\ri

The \ri statement sets the right indent for the paragraph. The indent applies to all subsequent paragraphs up to the next \pard or \ri statement.

Syntax

\rin

Parameter

n

Specifies the right indent, in twips. It can be a positive or negative value.

Remarks

If the \ri statement is not given, the right indent is zero by default. Windows Help automatically provides a small right margin so that when no right indent is specified, the text does not end abruptly at the right edge of the Help window.

Windows Help never displays less than one word for each line in a paragraph even if the right indent is greater than the width of the window.

Example

In the following example, the right and left indents are set to one inch and the subsequent text is centered between the indents:

\li1440\ri1440\qc
Microsoft Windows Help\line
Sample File\line

See Also

\li, \pard


\row

The \row statement marks the end of a table row. The statement ends the current row and begins a new row by moving down past the end of the longest cell in the row. The next \cell statement specifies the text of the leftmost cell in the next row.

Remarks

This statement was first supported in the Microsoft Help Compiler version 3.1.

Example

The following example creates a table having four rows and two columns:

\cellx2880\cellx5760
\intbl
Row 1, Column 1\cell
Row 1, Column 2\cell \row
\intbl

Row 2, Column 1\cell
Row 2, Column 2\cell \row
\intbl
Row 3, Column 1\cell
Row 3, Column 2\cell \row
\intbl
Row 4, Column 1\cell
Row 4, Column 2\cell \row
\par \pard

See Also

\cell, \cellx, \intbl


\rtf

The \rtf statement identifies the file as a rich-text format (RTF) file and specifies the version of the RTF standard used.

Syntax

\rtfn

Parameter

n

Specifies the version of the RTF standard used. For the Microsoft Help Compiler version 3.1, this parameter must be 1.

Remarks

The \rtf statement must follow the first open brace in the Help file. A statement specifying the character set for the file must also follow the \rtf statement.

See Also

\ansi


\sa

The \sa statement sets the amount of vertical spacing after a paragraph. The vertical space applies to all subsequent paragraphs up to the next \pard or \sa statement.

Syntax

\san

Parameter

n

Specifies the amount of vertical spacing, in twips.

Remarks

If the \sa statement is not given, the vertical spacing after a paragraph is zero by default.

See Also

\sb, \pard


\sb

The \sb statement sets the amount of vertical spacing before the paragraph. The vertical space applies to all subsequent paragraphs up to the next \pard statement or \sb statement.

Syntax

\sbn

Parameter

n

Specifies the amount of vertical spacing, in twips.

Remarks

If the \sb statement is not given, the vertical spacing before the paragraph is zero by default.

See Also

\sa, \pard


\scaps

The \scaps statement starts small-capital text. The statement converts all subsequent lowercase letters to uppercase before displaying the text. This statement applies to all subsequent text up to the next \plain or \scaps0 statement.

Remarks

The \scaps statement does not affect uppercase letters.

No \plain or \scaps0 statement is required if the \scaps statement and subsequent text are enclosed in braces. Braces limit the scope of a character property statement to just the enclosed text.

The \scaps statement does not reduce the point size of the text. To reduce point size, the \fs statement must be used.

Example

The following example displays the key name ENTER in small capitals:

Press the {\scaps enter} key to complete the action.

See Also

\fs, \plain


\sect

The \sect statement marks the end of a section and paragraph.

See Also

\par


\sl

The \sl statement sets the amount of vertical space between lines in a paragraph. The vertical space applies to all subsequent paragraphs up to the next \pard or \sl statement.

Syntax

\sln

Parameter

n

Specifies the amount of vertical spacing, in twips. If this parameter is a positive value, Windows Help uses this value if it is greater than the tallest character. Otherwise, Windows Help uses the height of the tallest character as the line spacing. If this parameter is a negative value, Windows Help uses the absolute value of the number even if the tallest character is taller.

Remarks

If the \sl statement is not given, Windows Help automatically sets the line spacing by using the tallest character in the line.

See Also

\pard


\strike

The \strike statement creates a hot spot. The statement is used in conjunction with a \v statement to create a link to another topic. When the user chooses a hot spot, Windows Help displays the associated topic in the Help window.

The \strike statement applies to all subsequent text up to the next \plain or \strike0 statement.

Remarks

No \plain or \strike0 statement is required if the \strike statement and subsequent text are enclosed in braces. Braces limit the scope of a character property statement to just the enclosed text.

The \strike statement creates the same type of hot spot as the \uldb statement.

In print-based documents, or whenever it is not followed by \v, the \strike statement creates strikeout text.

Example

The following example creates a hot spot for a topic. When displayed, the hot-spot text, "Hot Spot," is green and has a solid line under it:

{\strike Hot Spot}{\v Topic}

See Also

\ul, \uldb, \v


\tab

The \tab statement inserts a tab character (ASCII character code 9).

Remarks

The tab character (ASCII character code 9) has the same effect as the \tab statement.

See Also

\tqc, \tqr, \tx


\tb

The Microsoft Windows Help Compiler ignores this statement.

See Also

\tab, \tqc, \tqr, \tx


\tqc

The \tqc statement is used with the \tx statement to create a tab stop where text is centered. For example, the following statement creates a centered tab stop at 2880 twips:

\tqc\tx2880

See Also

\tab, \tqr, \tx


\tqr

The \tqr statement is used with the \tx statement to create a tab stop where text right-justified. For example, the following statement creates a right-justified tab stop at 2880 twips:

\tqr\tx2880

See Also

\tab, \tqc, \tx


\trgaph

The \trgaph statement specifies the amount of space between text in adjacent cells in a table. For each cell in the table, Windows Help uses the space to calculate the cell's left and right margins. It then uses the margins to align and wrap the text in the cell. Windows Help applies the same margin widths to each cell ensuring that paragraphs in adjacent cells have the specified space between them.

The \trgaph statement applies to cells in all subsequent rows of a table up to the next \trowd statement.

Syntax

\trgaphn

Parameter

n

Specifies the space, in twips, between text in adjacent cells. If this parameter exceeds the actual width of the cell, the left and right margins are assumed to be at the same position in the cell.

Remarks

The width of the left margin in the first cell is always equal to the space specified by this statement. The \trleft statement is typically used to move the left margin to a position similar to the left margins in all other cells.

This statement was first supported in the Microsoft Help Compiler version 3.1.

Example

The following example creates a three-column table with one-quarter inch space between the text in the columns:

\trgaph360 \cellx1440\cellx2880\cellx4320
\intbl
Row 1 Column 1\cell
Row 1 Column 2\cell
Row 1 Column 3\cell \row
\intbl
Row 2 Column 1\cell
Row 2 Column 2\cell
Row 2 Column 3\cell \row \pard

See Also

\cell, \cellx, \intbl, \row, \trleft, \trowd


\trleft

The \trleft statement sets the position of the left margin for the first (leftmost) cell in a row of a table. This statement applies to the first cell in all subsequent rows of the table up to the next \trowd statement.

Syntax

\trleftn

Parameter

n

Specifies the relative position, in twips, of the left margin. This parameter can be a positive or negative number. The final position of the left margin is the sum of the current position and this value.

Remarks

This statement was first supported in the Microsoft Help Compiler version 3.1.

Example

The following example creates a three-column table with one-quarter inch space between the text in the columns. The left margin in the first cell is flush with the left margin of the Help window:

\trgaph360\trleft-360 \cellx1440\cellx2880\cellx4320
\intbl
Row 1 Column 1\cell
Row 1 Column 2\cell
Row 1 Column 3\cell \row
\intbl
Row 2 Column 1\cell
Row 2 Column 2\cell
Row 2 Column 3\cell \row \pard

See Also

\cell, \cellx, \intbl, \row, \trgaph, \trowd


\trowd

The \trowd statement sets default margins and cell positions for subsequent rows in a table.

Remarks

This statement was first supported in the Microsoft Help Compiler version 3.1.

See Also

\cell, \cellx, \intbl, \row, \trgaph, \trleft


\trqc

The \trqc statement directs Windows Help to dynamically adjust the width of table columns to fit in the current window.

Remarks

In a print-based document, the \trqc statement centers a table row with respect to its containing column.

Windows Help will not resize a table to smaller than the widths specified in the \trqc statement. Therefore, the table should be created in the smallest size in which it would ever be displayed. All columns in the table are sized proportionally.

This statement was first supported in the Microsoft Help Compiler version 3.1.

See Also

\trowd, \trql


\trql

The \trql statement aligns the text in each cell of a table row to the left.

Remarks

This statement was first supported in the Microsoft Help Compiler version 3.1.

See Also

\trowd, \trqc


\tx

The \tx statement sets the position of a tab stop. The position is relative to the left margin of the Help window. A tab stop applies to all subsequent paragraphs up the next \pard statement.

Syntax

\txn

Parameter

n

Specifies the tab stop position, in twips.

Remarks

If the \tx statement is not given, tab stops are set at every one-half inch by default.

See Also

\pard, \tab, \tqc, \tqr


\ul

The \ul statement creates a link to a pop-up topic. The statement is used in conjunction with a \v statement to create a link to another topic. When the user chooses the link, Windows Help displays the associated topic in a pop-up window.

The \ul statement applies to all subsequent text up to the next \plain or \ul0 statement.

Remarks

No \plain or \ul0 statement is required if the \ul statement and subsequent text are enclosed in braces. Braces limit the scope of a character property statement to just the enclosed text.

In print-based documents, or whenever it is not followed by \v, the \ul statement creates a continuous underline.

Example

The following example creates a pop-up link for a topic. When displayed, the link text, "Popup Link," is green and has a dotted line under it:

{\ul Popup Link}{\v PopupTopic}

See Also

\plain, \strike, \uldb, \v


\uldb

The \uldb statement creates a hot spot. This statement is used in conjunction with a \v statement to create a link to another topic. When the user chooses a hot spot, Windows Help displays the associated topic in the Help window.

The \uldb statement applies to all subsequent text up to the next \plain or \uldb0 statement.

Remarks

No \plain or \uldb0 statement is required if the \uldb statement and subsequent text are enclosed in braces. Braces limit the scope of a character property statement to just the enclosed text.

The \uldb statement creates the same type of hot spot as the \strike statement.

Example

The following example creates a hot spot for a topic. When displayed, the hot-spot text, "Hot Spot", is green and has a solid line under it:

{\uldb Hot Spot}{\v Topic}

See Also

\plain, \strike, \ul, \v


\v

The \v statement creates a link to the topic having the specified context string. The \v statement is used in conjunction with the \strike, \ul, and \uldb statements to create hot spots and links to topics.

Syntax

{\v context-string}

Parameter

context-string

Specifies the context string of a topic in the Help file. The string can be any combination of characters, except spaces, and must also be specified in a context-string \footnote statement in some topic in the Help file.

Remarks

If the context string is preceded by a percent sign (%), Windows Help displays the associated hot spot or link without applying the standard underline and color. If the context string is preceded by an asterisk (*), Windows Help displays the associated hot spot or link with an underline but without applying the standard color.

In print-based documents, the \v statement creates hidden text.

For links or hot spots, the syntax of the \v statement is as follows:

[%|*] context [>secondary-window] [@filename]

In this syntax, secondary-window is the name of the secondary window to jump to. When the secondary window is not specified, the jump is to the same window as the current Help topic is using. To jump to the main window, specify "main" for this parameter. This parameter may not be used with pop-up windows.

The filename parameter specifies a jump to a topic in a different Help file.

For a macro hotspot, the syntax of the \v statement is as follows:

[%|*] ! macro [;macro][;]

Example

The following example creates a hot spot for the topic having the context string "Topic". Windows Help applies an underline and the color green the text "Hot Spot" when it displays the topic:

{\uldb Hot Spot}{\v Topic}

See Also

\footnote, \strike, \ul, \uldb


\wbitmap

The \wbitmap statement sets the picture type to Windows bitmap. This statement must be used in conjunction with a \pict statement.

Syntax

\wbitmapn

Parameter

n

Specifies the bitmap type. This parameter is zero for a logical bitmap.

Remarks

The \wbitmap statement is optional; if a \wmetafile statement is not specified, the picture is assumed to be a Windows bitmap.

Example

The following example creates a 32-by-8 pixel monochrome bitmap:

{\pict \wbitmap0\wbmbitspixel1\wbmplanes1\wbmwidthbytes4\picw32\pich8
3FFFFFFC
F3FFFFCF
FF3FFCFF
FFF3CFFF
FFFC3FFF
FFCFF3FF
FCFFFF3F
CFFFFFF3
}

See Also

bmc, bml, bmr, \pict, \wmetafile


\wbmbitspixel

The \wbmbitspixel statement specifies the number of consecutive bits in the bitmap data that represent a single pixel. This statement must be used in conjunction with the \pict statement.

Syntax

\wbmbitspixeln

Parameter

n

Specifies the number of bits per pixel.

Remarks

If the \wbmbitspixel statement is not given, the default bits per pixel value is 1.

See Also

\pict, \wbitmap, \wbmplanes


\wbmplanes

The \wbmplanes statement specifies the number of color planes in the bitmap data. This statement must be used in conjunction with a \pict statement.

Syntax

\wbmplanesn

Parameter

n

Specifies the number of bitmap planes.

Remarks

If the \wbmplanes statement is not given, the default number of planes is 1.

See Also

\pict, \wbitmap, \wbmbitspixel


\wbmwidthbytes

The \wbmwidthbytes statement specifies the number of bytes in each scan line of the bitmap data. This statement must be used in conjunction with the \pict statement.

Syntax

\wbmwidthbytesn

Parameter

n

Specifies the width of the bitmap, in bytes.

See Also

\pict, \wbitmap


\windows

The \windows statement sets the Windows character set.

Remarks

If no \windows, \pc, or \pca statement is given in the Help file, the Windows character set is used by default.

See Also

\ansi, \pc, \pca


\wmetafile

The \wmetafile statement sets the picture type to a Windows metafile. This statement must be used in conjunction with the \pict statement.

Syntax

\wmetafilen

Parameter

n

Specifies the metafile type. This parameter must be 8.

Remarks

Windows Help expects the hexadecimal data associated with the picture to represent a valid Windows metafile. By default, Windows Help sets the MM_ANISOTROPIC mapping mode prior to displaying the metafile. To ensure that the picture is displayed correctly, the metafile data must either set the window origin and extents by using the SetWindowOrg and SetWindowExt records or set another mapping mode by using the SetMapMode record.

Example

The following example creates a picture using a metafile:

{{\pict\wmetafile8\picw2880\pich2880
0100090000034f0000000200090000000000
050000000b0200000000050000000c026400
6400090000001d066200ff00640064000000
000008000000fa0200000200000000000000
040000002d01000005000000140200000000
050000001302640064000500000014020000
64000500000013026400000008000000fa02
00000000000000000000040000002d010100
04000000f00100000300000000004e0dff00
870020000050000020000000000000000000}
\par }

See Also

SetMapMode, SetWindowExt, SetWindowOrg, bmc, bml, bmr, \pict, \wbitmap


Help Compiler Error Messages

This section lists the error messages displayed by the Microsoft Help Compiler when it encounters errors in building a Help file. Whenever possible, the compiler displays the name of the file that contains the error, as well as the number used to identify the specific line of the project file or the topic that produced the error. Since topics are not actually numbered, the topic number given with an error message refers to that topic's sequential position in the topic file.


Interpreting Error Messages

The Microsoft Help Compiler displays either warning or fatal-error messages. A warning message indicates a problem during compilation that was not severe enough to prevent the Help file from being created. Microsoft Windows Help should be able to open the file but may encounter problems when displaying some topics. A fatal error indicates a problem that prevents the compiler from creating a Help file. The compiler always reports fatal errors, regardless of the current warning level or reporting option.

While the Microsoft Help Compiler processes the project file, it ignores lines that contain errors and attempts to continue. This means that errors encountered early in the file may result in many more errors being reported as the compiler continues.

When the Microsoft Help Compiler processes topic files, it reports any errors it encounters, and if the errors are not fatal, compilation continues. A single error in a topic file may result in more than one error message being displayed by the compiler. For example, a typographic mistake in a topic's context string will cause an error to be reported every time the compiler encounters a reference to the correct topic identifier.


Error Message Categories

Error-message numbers have four digits; the first one or two of those digits identify the message category. The message-number prefixes and the categories they identify are defined as follows:

Prefix	Error
1	Problems with files used to build the Help file
2	Problems with the project file
30 − 31	Problems with build tags or build-tag expressions
35 − 36	Problems with Help macros
40 − 41	Problems with context strings
42 − 45	Problems with footnotes
46 − 47	Problems with the topic file
5	Other problems


File Errors

The following messages result from problems with files used to build a Help file. A description is given for messages that are not self-explanatory.

Number	File error message
1019	Project file extension cannot be .HLP or .PH.
1030	File name exceeds limit of 259 characters.
	The combined length of the path and filename must not be more than the MS-DOS limit of 259 characters.
1079	Out of file handles.
	The compiler does not have enough available file handles to continue. If possible, increase the FILES setting in the CONFIG.SYS file.
1100	Cannot open file filename: permission denied.
	Requested files must have at least read privilege to be opened.
1150	Cannot overwrite file filename.
	Files with the read-only attribute cannot be overwritten.
1170	File filename is a directory.
	A directory in the project directory has the same name as the requested Help file.
1190	Cannot use reserved DOS file name filename.
	Do not use reserved MS-DOS filenames, such as COM1, LPT2, or PRN, when specifying topic or other data files.
1230	File filename not found.
	The specified file could not be found or is unreadable.
1292	File filename is not a valid bitmap.
	The specified bitmap file could not be found or is not in a recognizable bitmap format.
1319	Disk full.
1513	Bitmap name filename duplicated.
	The [BITMAPS] section contains duplicate bitmap names. The compiler uses the first occurrence of the name.
1536	Not enough memory to compress bitmap filename.
	The specified bitmaps cannot be compressed due to insufficient memory.


Project-File Errors

The following messages result from errors in the Help project file (with the .HPJ filename extension) used to build a Help file. A description is given for messages that are not self-explanatory.

Number	Project-file error message
2010	Include statements nested more than 5 deep.
	The #include statement on the specified line has exceeded the maximum of five include levels.
2030	Comment starting at line linenumber of file filename unclosed at end of file.
	The compiler has unexpectedly come to the end of the project file. There may be an open comment in the project file or in an include file.
2050	Invalid #include syntax.
	The #include statement requires a filename.
2091	Bracket missing from section heading [sectionname].
2111	Section heading missing.
	The section heading on the specified line is not complete. This error is also reported if the first entry in the project file is not a section heading.
2131	Invalid OPTIONS syntax: 'option=value' expected.
2141	Invalid ALIAS syntax: 'context=context' expected.
2151	Incomplete line in [sectionname] section
2171	Unrecognized text.
2191	Section heading [sectionname] unrecognized.
2214	Line in .HPJ file exceeds length limit of 2047 characters.
2273	[OPTIONS] should precede [FILES] and [BITMAPS] for all options to take effect.
	The [OPTIONS] section should be the first section in the project file. Also, if the ERRORLOG option is used, that option should be the first line in the [OPTIONS] section.
2291	Section sectionname previously defined.
	The compiler ignores the lines under the duplicated section and continues from the next valid section heading.
2305	No valid files in [FILES] section.
	The file section is empty or contains only invalid files.
2322	Context string context_name cannot be used as alias string.
	A context string that has been assigned an alias cannot be used later as an alias for another context string. That is, you cannot map a=b and then c=a in the [ALIAS] section. The compiler ignores the attempted reassignment.
2331	Context number already used in [MAP] section.
	The context number on the specified line in the project file was previously mapped to a different context string.
2341	Invalid or missing context string.
	The specified line is missing a context string before an equal sign.
2351	Invalid context identification number.
	The context number on the specified line is empty or contains invalid characters.
2362	Context string context_name already assigned an alias.
	A context string can have only one alias. That is, you cannot map a=b and then a=c in the [ALIAS] section. The specified context string has already been assigned an alias in the [ALIAS] section. The compiler ignores the attempted reassignment.
2372	Alias string aliasname already assigned.
	You cannot alias an alias. That is, an alias string cannot, in turn, be assigned another alias. You cannot map a=b and then b=c in the [ALIAS] section. The compiler ignores the attempted reassignment.
2391	Limit of 6 window definitions exceeded.
	The maximum number of window definitions is one main-window definition and five secondary-window definitions.
2401	Window maximization state must be 0 or 1.
	The sizing parameter in a window definition must be either zero or 1.
2411	Invalid syntax in window color.
	A window color in a window definition consists of three decimal numbers enclosed in parentheses and separated by commas.
2421	Invalid window position.
	The window position in a window definition consists of four decimal numbers enclosed in parentheses and separated by commas.
2431	Missing quote in window caption.
	The window caption in a window definition must be enclosed in quotation marks.
2441	Window name windowname is too long.
	The window name exceeds the maximum length of 8 characters.
2451	Window position value out of range 01023.
	One or more of the window-position coordinates exceed the maximum limit of 1023.
2461	Window name missing.
	A window definition in the project file is missing the window name.
2471	Invalid syntax in [WINDOWS] section.
2481	Secondary-window position required.
	A window definition for a secondary window must specify the four window-position parameters.
2491	Duplicate window name windowname.
	Window names must be unique.
2501	Window caption windowcaption exceeds limit of 50 characters.
2511	Unrecognized option optionname in [OPTIONS] section.
2532	Option optionname previously defined.
	The compiler ignores the attempted redefinition.
2550	Invalid path pathname in optionname option.
	The compiler cannot find the path specified by the ROOT or BMROOT option. The compiler uses the current working directory.
2570	Path in optionname option exceeds number of characters.
	The specified root path exceeds the maximum limit for MS-DOS. The compiler ignores the path and uses the current working directory.
2591	Invalid MAPFONTSIZE option.
	The font range syntax used is invalid. A font range consists of a low and high point size, separated by a hyphen (-).
2612	Maximum of 5 font ranges exceeded.
	The compiler ignores additional ranges.
2632	Current font range overlaps previously defined range.
	The compiler ignores the second mapping.
2651	Font name exceeds limit of 20 characters.
2672	Unrecognized font name fontname in FORCEFONT option.
	The compiler ignores the font name and uses the default Helvetica font.
2691	Invalid MULTIKEY syntax.
	The MULTIKEY option must specify a single capital letter other than the letter K.
2711	Maximum of 5 keyword tables exceeded.
	The compiler ignores the additional tables.
2732	Character already used.
	A character used for indicating the keyword table was previously used. The compiler ignores the line.
2752	Characters 'K' and 'k' cannot be used.
	These characters are reserved for Help's standard keyword table.
2771	REPORT option must be 'ON' or 'OFF'.
2811	OLDKEYPHRASE option must be 'ON' or 'OFF'.
2832	COMPRESS option must be 'OFF', 'MEDIUM' or 'HIGH'.
2842	OPTCDROM option must be 'TRUE' or 'FALSE'.
2852	Invalid TITLE option.
	The TITLE option defines a string that is empty or contains more than 32 characters.
2872	Invalid LANGUAGE option.
	You have specified an ordering that is not supported by the compiler. The compiler uses English sorting order.
2893	Warning option must be 1, 2, or 3.
	The compiler uses full reporting (level 3).
2911	Invalid icon file filename.
	The compiler cannot find the icon file specified in the ICON option, or the file is not a valid icon file.
2932	Copyright string exceeds limit of 50 characters.
	The maximum length of the copyright string in the About box is limited to 50 characters.
3011	Maximum of 32 build tags exceeded.
	The compiler ignores the additional tags.
3031	Build tag length exceeds 32 characters.
	The compiler ignores the build tag.
3051	Build tag tagname contains invalid characters.
	Build tags can contain only alphanumeric characters or the underscore (_) character.
3076	[BUILDTAGS] section missing.
	The BUILD option declared a conditional build, but there is no [BUILDTAGS] section in the project file. The compiler includes all topics in the build.
3096	Build expression too complex.
	The build expression has too many expressions (~, |, or &) or is too deeply nested.
3116	Invalid build expression.
	The syntax used in the build expression on the specified line contains one or more logical or syntax errors.
3133	Duplicate build tag in [BUILDTAGS] section.
3152	Build tag tagname not defined in [BUILDTAGS] section.
	The specified build tag has been assigned to a topic but not declared in the project file. The compiler ignores the tag for the topic.
3178	Build expression missing from project file.
	The topics have build tags, but there is no build expression in the project file. The compiler includes all topics in the build.


Macro Errors

The following messages result from errors in the use of Help macros in footnotes, hot spots, and the [CONFIG] section of the Help project file. A description is given for messages that are not self-explanatory.

Number	Macro error message
3511	Macro macrostring exceeds limit of 254 characters.
3532	Undefined function in macro macroname.
	The specified macro is not on the list of macros supported by the compiler, nor is it specified in the RegisterRoutine macro. The compiler passes the macro to the Help file, however.
3552	Undefined variable in macro macroname.
3571	Wrong number of parameters to function in macro macroname.
3591	Syntax error in macro macroname.
3611	Function parameter type mismatch in macro macroname.
	There is a type mismatch (string or numeric) in the function call.
3631	Bad macro prototype.
	The prototype string passed to the RegisterRoutine macro is invalid.
3652	Empty macro string.
	The ! footnote or a hidden text starting with "!" does not contain a macro.
3672	Macro macroname nested too deeply.
	Macro strings that contain macro strings as parameters may not nest more than three deep.


Context-String Errors

The following messages are caused by problems with context-string footnotes or context strings specified in jumps or in Help project-file options. A description is given for messages that are not self-explanatory.

Number	Context-string error messages
4011	Context string contextname already used.
	The specified context string was previously assigned to another topic. The compiler ignores the latter string and the topic has no identifier.
4031	Invalid context string contextname.
	The context string footnote contains non-alphanumeric characters or is empty. The compiler does not assign the topic an identifier.
4056	Unresolved context string specified in CONTENTS option.
	The Contents topic defined in the project file could not be found. The compiler uses the first topic in the build as the Contents topic.
4072	Context string exceeds limit of 255 characters.
	The compiler ignores the context string.
4098	Context string(s) in [MAP] section not defined in any topic.
	The compiler cannot find a context string listed in the [MAP] section in any of the topics in the build.
4113	Unresolved jump or popup contextname.
	The specified topic contains a context string that identifies a nonexistent topic.
4131	Hash conflict between contextname and contextname.
	The hash algorithm has generated the same hash value for both of the listed context strings. Change one of the context strings and recompile.
4151	Invalid secondary window name windowname.
	The window name for the secondary window is "main" or another disallowed member name.
4171	Cannot use secondary window with popup.
	The hidden text defining the pop-up identifier contains a secondary-window name.
4196	Jumps and lookups not verified.
	Due to low memory conditions, the build continues without verifying the validity of jumps and popups. (The reference to "lookups" in the error message is incorrect.)
4211	Footnote text exceeds limit of 1023 characters.
	Footnote text cannot exceed the limit of 1023 characters. The compiler ignores the footnote.
4231	Footnote text missing.
	The specified topic contains a footnote that has no characters.
4251	Browse sequence not in first paragraph.
	The browse-sequence footnote is not in the first paragraph of the topic. The compiler ignores the browse sequence.
4272	Empty browse sequence string.
	The browse-sequence footnote for the specified topic contains no sequence characters.
4292	Missing sequence number.
	A browse-sequence number ends in a colon (:) for the specified topic. Remove the colon or enter a "minor" sequence number and then recompile.
4312	Browse sequence already defined.
	A browse-sequence footnote already exists for the specified topic. The compiler ignores the latter sequence.
4331	Title not in first paragraph.
	The title footnote ($) is not in the first paragraph of the topic. The topic will not have a topic title string.
4352	Empty title string.
	The title footnote for the specified topic contains no characters. The compiler does not assign the topic a title.
4372	Title defined more than once.
	There is more than one title footnote in the specified topic. The compiler uses the first title string.
4393	Title exceeds limit of 128 characters.
	The compiler ignores the additional characters.
4412	Keyword string exceeds limit of 255 characters.
4433	Empty keyword string.
	There are no characters in the keyword footnote.
4452	Keyword(s) defined without title.
	The topic has a keyword assigned to it, but no title.
4471	Build tag footnote not at beginning of topic.
	The build-tag footnote marker, if used, must be the first character in the topic.
4492	Build tag exceeds limit of 32 characters.
	The compiler ignores the tag for the topic.
4551	Entry macro not in first paragraph.
	The ! footnote (for executing a macro) is not in the first paragraph of the topic. The compiler ignores the macro.


Topic-File Errors

The following messages result from problems in rich-text format (RTF) formatting in one or more topic files. A description is given for messages that are not self-explanatory.

Number	Topic-file error message
4616	File filename is not a valid RTF topic file.
4639	Error in file filename at byte offset 0xoffset.
	The specified file contains unrecognized RTF at that byte offset.
4649	File filename contains more than 32767 topics.
4652	Table formatting too complex.
	The compiler encountered a table with borders, shading, or right justification.
4662	Side by side paragraph formatting not supported.
	The side-by-side paragraph formatting is not supported in Microsoft Windows Help 3.1.
4671	Table contains more than 32 columns.
4680	Font fontname in file filename not in RTF font table.
	The compiler uses the default system font.
4692	Unrecognized graphic format.
	The compiler supports only Windows bitmaps, Windows metafiles, segmented graphics, and multi-resolution graphics. The compiler ignores the graphic.
4733	Hidden page break.
	A page break is a part of the hidden text. A page break formatted as hidden text will not separate two topics.
4753	Hidden paragraph.
	A paragraph marker is part of the hidden text. The compiler ignores the paragraph marker.
4763	Hidden carriage return.
	A carriage return is part of the hidden text. The compiler ignores the carriage return.
4774	Paragraph exceeds limit of 64K.
	A single paragraph has more than 64K of text or 64K of graphics. (This limit does not include graphics stored separately from the data, using the bmc, bml, or bmr statements.)
4792	Non-scrolling region defined after scrolling region.
	A \keepn statement precedes a paragraph that is not the first paragraph in the topic. The compiler ignores the statement; the paragraph is treated as regular text and is part of the regular topic text.
4813	Non-scrolling region crosses page boundary.
	A \pard statement must appear before the \page statement in a topic containing a \keepn statement.


Miscellaneous Errors

The following messages are caused by conditions such as operating-system file errors or out-of-memory conditions. A description is given for messages that are not self-explanatory.

Number	Error message
5035	File filename not created.
	There are no topics to compile or the build expression is false for all topics. The compiler does not create a Help file.
5059	Not enough memory to build Help file.
	To free memory, unload any unneeded applications, device drivers, and memory-resident programs.
5075	Help Compiler corrupted. Please reinstall HC.EXE.
	Virus-checking code has detected a corruption in the compiler. Reinstall the compiler.
5098	Using old key-phrase table.
	Maximum compression can result only by deleting the .PH file before each recompilation of the Help topics or by setting the OLDKEYPHRASE option to "0".
5115	Write failed.
	Write-to-disk operation failed. Contact Microsoft Product Support Services.
5139	Aborted by user.
	Compilation was terminated when the user pressed CTRL+C.


Compiling Resources

The Microsoft Windows Resource Compiler (RC) is a tool for the Microsoft Windows NT operating system. This section describes how to create a resource-definition (script) file, and how to compile your application's resources and add them to the application's executable file.


Including Resources in an Application

To include resources in your 32-bit Windows application, do the following:

1.	Create individual resource files for cursors, icons, bitmaps, dialog boxes, and fonts. To do this, you can use Microsoft Image Editor and Dialog Editor (IMAGEDIT.EXE and DLGEDIT.EXE) and Microsoft Windows Font Editor (FONTEDIT.EXE).

2.	Create a resource-definition file (script) that describes all the resources used by the application.

3.	Compile the script into a resource (.RES) file with RC.

4.	Link the compiled resource files into the application's executable file.

Unlike the 16-bit versions of the Windows development system, you do not use RC to include compiled resources into the executable file or to mark the file as a Windows application. The linker recognizes the compiled resource files and links them to the executable file.


Creating a Resource-Definition File

After creating individual resource files for your application's icon, cursor, font, bitmap, and dialog-box resources, you create a resource-definition file, or script. A script file is a text file with the extension .RC.

The script lists every resource in your application and describes some types of resources in great detail. For a resource that exists in a separate file, such as an icon or cursor, the script names the resource and the file that contains it. For some resources, such as a menu, the entire definition of the resource exists within the script.

A script file can contain the following types of information:

•	Preprocessing directives, which instruct RC to perform actions on the script before compiling it. Directives can also assign values to names.

•	Statements, which name and describe resources.

The following sections describe directives and statements you can use in a script. For detailed descriptions and syntax for each statement, see Resource-Definition Statements.


Preprocessing Directives List

The following directives can be used as needed in the script to instruct RC to perform actions or to assign values to names:

Directive	Description
#define	Defines a specified name by assigning it a given value.
#elif	Marks an optional clause of a conditional-compilation block.
#else	Marks the last optional clause of a conditional-compilation block.
#endif	Marks the end of a conditional-compilation block.
#if	Conditionally compiles the script if a specified expression is true.
#ifdef	Conditionally compiles the script if a specified name is defined.
#ifndef	Conditionally compiles the script if a specified name is not defined.
#include	Copies the contents of a file into the resource-definition file.
#undef	Removes the definition of the specified name.
The syntax and semantics for the RC preprocessor are the same as for a C compiler. For more information on preprocessing in RC, see Preprocessing Reference.


Single-Line Statements

A single-line statement can begin with any of the following keywords:

Keyword	Description
BITMAP	Defines a bitmap by naming it and specifying the name of the file that contains it. (To use a particular bitmap, the application requests it by name.)
CURSOR	Defines a cursor by naming it and specifying the name of the file that contains it. (To use a particular cursor, the application requests it by name.)
FONT	Specifies the name of a file that contains a font.
ICON	Defines an icon by naming it and specifying the name of the file that contains it. (To use a particular icon, the application requests it by name.)
LANGUAGE	Sets the language for all resources up to the next LANGUAGE statement or to the end of the file. When the LANGUAGE statement appears before the BEGIN in an ACCELERATORS, DIALOG, MENU, RCDATA, or STRINGTABLE resource definition, the specified language applies only to that resource.
MESSAGETABLE	Defines a message table by naming it and specifying the name of the file that contains it. The file is a binary resource file generated by the Message Compiler.


Multiline Statements

A multiline statement can begin with any of the following keywords:

Keyword	Description
ACCELERATORS	Defines menu accelerator keys.
DIALOG	Defines a template that an application can use to create dialog boxes.
MENU	Defines the appearance and function of a menu.
RCDATA	Defines data resources. Data resources let you include binary data in the executable file.
STRINGTABLE	Defines string resources. String resources are Unicode strings that can be loaded from the executable file.
Each of these multiline statements allows optional statements before the BEGIN ... END block that defines the resource. You can specify zero or more of the following statements:

Statement	Description
CHARACTERISTICS dword	User-defined information about the resource that can be used by tools that read and write resource files. The value appears in the compiled resource file. However, it is not stored in the executable file and is not used by Windows.
LANGUAGE language, sublanguage	Specifies the language for the resource. The parameters are constants from WINNLS.H.
VERSION dword	User-defined version number for the resource that can be used by tools that read and write resource files. The value appears in the compiled resource file. However, it is not stored in the executable file and is not used by Windows.


Sample Resource-Definition File

The following example shows a script file that defines the resources for an application named Shapes:

#include "SHAPES.H"

ShapesCursor  CURSOR  SHAPES.CUR
ShapesIcon    ICON    SHAPES.ICO

ShapesMenu    MENU
    BEGIN
        POPUP "&Shape"
            BEGIN
                MENUITEM "&Clear", ID_CLEAR
                MENUITEM "&Rectangle", ID_RECT
                MENUITEM "&Triangle", ID_TRIANGLE
                MENUITEM "&Star", ID_STAR
                MENUITEM "&Ellipse", ID_ELLIPSE
            END
    END

The CURSOR statement names the application's cursor resource ShapesCursor and specifies the cursor file SHAPES.CUR, which contains the image for that cursor.

The ICON statement names the application's icon resource ShapesIcon and specifies the icon file SHAPES.ICO, which contains the image for that icon.

The MENU statement defines an application menu named ShapesMenu, a pop-up menu with five menu items.

The menu definition, enclosed by the BEGIN and END keywords, specifies each menu item and the menu identifier that is returned when the user selects that item. For example, the first item on the menu, Clear, returns the menu identifier ID_CLEAR when the user selects it. The menu identifiers are defined in the application header file, SHAPES.H.


Using RC (The RC Command Line)

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

RC [options] script-file

The RC command's options parameter can include one or more of the following options:

/?

Displays a list of RC command-line options.

/d

Defines a symbol for the preprocessor that you can test with the #ifdef directive.

/foresname

Uses resname for the name of the .RES file.

/h

Displays a list of RC command-line options.

/i

Searches the specified directory before searching the directories specified by the INCLUDE environment variable.

/lcodepage

Specifies default language for compilation. For example, -l409 is equivalent to including the following statement at the top of the resource script file:

LANGUAGE LANG_ENGLISH,SUBLANG_ENGLISH_US

/r

Ignored. Provided for compatibility with existing makefiles.

/v

Displays messages that report on the progress of the compiler.

/x

Prevents RC from checking the INCLUDE environment variable when searching for header files or resource files.

Options are not case sensitive, and a hyphen (-) can be used in place of a slash mark (/). You can combine single-letter options if they do not require any additional parameters. For example, the following two commands are equivalent:

RC /V /X SAMPLE.RC

rc -vx sample.rc

The script-file parameter specifies the name of the resource-definition file that contains the names, types, filenames, and descriptions of the resources to be compiled.


Defining Names for the Preprocessor

You can specify conditional compilation in a script, based on whether a name is defined on the RC command line with the /d option, or in the file or an include file with the #define directive.

For example, suppose your application has a pop-up menu, the Debug menu, that should appear only with debugging versions of the application. When you compile the application for normal use, the Debug menu is not included. The following example shows the statements that can be added to the resource-definition file to define the Debug menu:

MainMenu MENU
BEGIN
  . . .
#ifdef DEBUG
        POPUP "&Debug"
        BEGIN
                MENUITEM "&Memory usage", ID_MEMORY
                MENUITEM "&Walk data heap", ID_WALK_HEAP
        END
#endif
END

When compiling resources for a debugging version of the application, you could include the Debug menu by using the following RC command:

rc -d DEBUG myapp.rc

To compile resources for a normal version of the application—one that does not include the Debug menu—you could use the following RC command:

rc myapp.rc


Renaming the Compiled Resource File

By default, when compiling resources, RC names the compiled resource (.RES) file with the base name of the .RC file and places it in the same directory as the .RC file. CVTRES must then be invoked to convert the .RES file to a binary resource (.RBJ) format which can be understood by the linker. The following example compiles MYAPP.RC and creates a compiled resource file named MYAPP.RES in the same directory as MYAPP.RC:

rc myapp.rc

The /fo option gives the resulting .RES file a name that differs from the name of the corresponding .RC file. For example, to name the resulting .RES file NEWFILE.RES, use the following command:

rc -fo newfile.res myapp.rc

The /fo option can also place the .RES file in a different directory. For example, the following command places the compiled resource file MYAPP.RES in the directory C:\SOURCE\RESOURCE:

rc -fo c:\source\resource\myapp.res myapp.rc


Searching for Files

By default, RC searches for header files and resource files (such as icon and cursor files) first in the current directory and then in the directories specified by the INCLUDE environment variable. (The PATH environment variable has no effect on which directories RC searches.)


Adding a Directory to Search

You can use the /i option to add a directory to the list of directories RC searches. The compiler then searches the directories in the following order:

1.	The current directory

2.	The directory or directories you specify by using the /i option, in the order in which they appear on the RC command line

3.	The list of directories specified by the INCLUDE environment variable, in the order in which the variable lists them, unless you specify the /x option

The following example compiles the resource-definition file MYAPP.RC:

rc /i c:\source\stuff /i d:\resources myapp.rc

When compiling the script MYAPP.RC, RC searches for header files and resource files first in the current directory, then in C:\SOURCE\STUFF and D:\RESOURCES, and then in the directories specified by the INCLUDE environment variable.


Suppressing the INCLUDE Environment Variable

You can prevent RC from using the INCLUDE environment variable when determining the directories to search. To do so, use the /x option. The compiler then searches for files only in the current directory and in any directories you specify by using the /i option.

The following example compiles the script file MYAPP.RC:

rc /x /i c:\source\stuff myapp.rc

When compiling the script MYAPP.RC, RC searches for header files and resource files first in the current directory and then in C:\SOURCE\STUFF. It does not search the directories specified by the INCLUDE environment variable.


Displaying Progress Messages

By default, RC compiles quietly. It does not display messages that report on its progress. You can, however, specify that RC is to display these messages. To do so, use the /v option.

The following example causes RC to report on its progress as it compiles the resource-definition file SAMPLE.RC and creates the compiled resource file SAMPLE.RES:

rc /v sample.rc


Resource-Definition Statements

This section describes the statements that define the resources that the Resource Compiler puts in the resource (.RES) file. Once a resource is linked to the executable file, the application can load the resource as it is needed at run time. All resource statements associate an identifying name or number with a given resource.


Common Statement Parameters

This section lists parameters in common among the resource or control statements. Occasionally, a certain statement will use a parameter differently, or may ignore a parameter. The statement-specific variation is described with the statement in the alphabetical reference.


Common Control Parameters

The general syntax for a control definition, and the meaning of each parameter is as follows:

control [text,] id, x, y, width, height [, style [, extended-style]]

Horizontal dialog units are 1/4 of the dialog base width unit. Vertical units are 1/8 of the dialog base height unit. The current dialog base units are computed from the height and width of the current system font. The GetDialogBaseUnits function returns the dialog base units in pixels. The coordinates are relative to the origin of the dialog box.

Parameters

control

Keyword that indicates the type of control being defined, such as PUSHBUTTON or CHECKBOX.

text

Specifies text that is displayed with the control. The text is positioned within the control's specified dimensions or adjacent to the control.

This parameter must contain zero or more characters enclosed in double quotation marks ("). Strings are automatically null-terminated and converted to Unicode in the resulting resource file, except for strings specified in raw-data statements (raw-data can be specified in RCDATA and user-defined resources.) To specify a Unicode string in raw-data, explicitly qualify the string as a wide-character string by using the L prefix.

By default, the characters listed between the double quotation marks are ANSI characters, and escape sequences are interpreted as byte escape sequences. If the string is preceded by the L prefix, the string is a wide-character string and escape sequences are interpreted as 2-byte escape sequences that specify Unicode characters. If a double quotation mark is required in the text, you must include the double quotation mark twice.

An ampersand (&) character in the text indicates that the following character is used as a mnemonic character for the control. When the control is displayed, the ampersand is not shown, but the mnemonic character is underlined. The user can choose the control by pressing the key corresponding to the underlined mnemonic character. To use the ampersand as a character in a string, insert two ampersands (&&).

id

Specifies the control identifier. This value must be a 16-bit unsigned integer in the range 0 through 65,535 or a simple arithmetic expression that evaluates to a value in that range.

x

Specifies the x-coordinate of the left side of the control relative to the left side of the dialog box. This value must be a 16-bit unsigned integer in the range 0 through 65,535. The coordinate is in dialog units and is relative to the origin of the dialog box, window, or control containing the specified control.

y

Specifies the y-coordinate of the top side of the control relative to the top of the dialog box. This value must be a 16-bit unsigned integer in the range 0 through 65,535. The coordinate is in dialog units relative to the origin of the dialog box, window, or control containing the specified control.

width

Specifies the width of the control. This value must be a 16-bit unsigned integer in the range 1 through 65,535. The width is in 1/4-character units.

height

Specifies the height of the control. This value must be a 16-bit unsigned integer in the range 1 through 65,535. The height is in 1/8-character units.

style

Specifies the control styles. Use the bitwise OR (|) operator to combine styles.

extended-style

Specifies extended (WS_EX_xxx) styles. You must specify a style to specify an extended-style. See also EXSTYLE.


Common Resource Attributes

All resource-definition statements include a load-mem option that specifies the loading and memory characteristics of the resource. These attributes are divided into two groups: load attributes and memory attributes. The only attribute that is used by Win32 is the DISCARDABLE attribute. The remaining attribute specifiers are allowed in the script for compatibility with existing scripts, but are ignored.

Load Attributes

The load attributes specify when the resource is to be loaded. The load parameter must be one of the following:

PRELOAD

Ignored. In 16-bit Windows, the resource is loaded with the executable file.

LOADONCALL

Ignored. In 16-bit Windows, the resource is loaded when called.

Memory Attributes

The memory attributes specify whether the resource is fixed or movable, whether it is discardable, and whether it is pure. The memory parameter can be one or more of the following:

FIXED

Ignored. In 16-bit Windows, the resource remains at a fixed memory location.

MOVEABLE

Ignored. In 16-bit Windows, the resource can be moved if necessary in order to compact memory.

DISCARDABLE

Resource can be discarded if no longer needed.

PURE

Ignored. Accepted for compatibility with existing resource scripts.

IMPURE

Ignored. Accepted for compatibility with existing resource scripts.

The default is DISCARDABLE for cursor, icon, and font resources.


Statement Reference

This section lists the resource and control statements in alphabetic order. For information on the preprocessing directives, see Preprocessing Reference.


ACCELERATORS Resource

The ACCELERATORS statement defines one or more accelerators for an application. An accelerator is a keystroke defined by the application to give the user a quick way to perform a task. The TranslateAccelerator function is used to translate accelerator messages from the application queue into WM_COMMAND or WM_SYSCOMMAND messages.

Syntax

acctablename ACCELERATORS
[optional-statements]
BEGIN
    event, idvalue, [type] [options]
    . . .
END

Parameters

acctablename

Specifies either a unique name or a 16-bit unsigned integer value that identifies the resource.

optional-statements

Zero or more of the following statements:

Statement	Description
CHARACTERISTICS dword	User-defined information about a resource that can be used by tools that read and write resource files.
LANGUAGE language, sublanguage	Specifies the language for the resource. The parameters are constants from WINNLS.H.
VERSION dword	User-defined version number for the resource that can be used by tools that read and write resource files.
event

Specifies the keystroke to be used as an accelerator. It can be any one of the following character types:

"char"

A single character enclosed in double quotation marks ("). The character can be preceded by a caret (^), meaning that the character is a control character.

character

An integer value representing a character. The type parameter must be ASCII.

virtual-key character

An integer value representing a virtual key. The virtual key for alphanumeric keys can be specified by placing the uppercase letter or number in double quotation marks (for example, "9" or "C"). The type parameter must be VIRTKEY.

idvalue

Specifies a 16-bit unsigned integer value that identifies the accelerator.

type

Required only when the event parameter is a character or a virtual-key character. The type parameter specifies either ASCII or VIRTKEY; the integer value of event is interpreted accordingly. When VIRTKEY is specified and event contains a string, event must be uppercase.

options

Specifies the options that define the accelerator. This parameter can be one or more of the following values:

NOINVERT

Specifies that no top-level menu item is highlighted when the accelerator is used. This is useful when defining accelerators for actions such as scrolling that do not correspond to a menu item. If NOINVERT is omitted, a top-level menu item will be highlighted (if possible) when the accelerator is used.

ALT

Causes the accelerator to be activated only if the ALT key is down.

SHIFT

Causes the accelerator to be activated only if the SHIFT key is down.

CONTROL

Defines the character as a control character (the accelerator is only activated if the CONTROL key is down). This has the same effect as using a caret (^) before the accelerator character in the event parameter.

The ALT, SHIFT, and CONTROL options apply only to virtual keys.

Example

The following example demonstrates the use of accelerator keys:

1 ACCELERATORS
BEGIN
  "^C",  IDDCLEAR         ; control C
  "K",   IDDCLEAR         ; shift K
  "k",   IDDELLIPSE, ALT  ; alt k
  98,    IDDRECT, ASCII   ; b
  66,    IDDSTAR, ASCII   ; B (shift b)
  "g",   IDDRECT          ; g
  "G",   IDDSTAR          ; G (shift G)
  VK_F1, IDDCLEAR, VIRTKEY                ; F1
  VK_F1, IDDSTAR, CONTROL, VIRTKEY        ; control F1
  VK_F1, IDDELLIPSE, SHIFT, VIRTKEY       ; shift F1
  VK_F1, IDDRECT, ALT, VIRTKEY            ; alt F1
  VK_F2, IDDCLEAR, ALT, SHIFT, VIRTKEY    ; alt shift F2
  VK_F2, IDDSTAR, CONTROL, SHIFT, VIRTKEY ; ctrl shift F2
  VK_F2, IDDRECT, ALT, CONTROL, VIRTKEY   ; alt control F2
END

See Also

TranslateAccelerator
Multiline Statements
CHARACTERISTICS, DIALOG, LANGUAGE, MENU, RCDATA, STRINGTABLE, VERSION


AUTO3STATE Control

The AUTO3STATE statement creates an automatic 3-state check box. The control is an open box with the given text positioned to the right of the box. When chosen, the box automatically advances between three states: checked, unchecked, and disabled (grayed). The control sends a message to its parent whenever the user chooses the control.

Syntax

AUTO3STATE text, id, x, y, width, height [, style [, extended-style]]

Parameters

style

Specifies styles for the control, which can be a combination of the BS_AUTO3STATE style and the following styles: WS_TABSTOP, WS_DISABLED, and WS_GROUP.

The default style for this control is BS_AUTO3STATE and WS_TABSTOP.

For more information on the text, id, x, y, width, height, style, and extended-style parameters, see Common Statement Parameters.

See Also

AUTOCHECKBOX, CHECKBOX, CONTROL, STATE3


AUTOCHECKBOX Control

The AUTOCHECKBOX statement creates an automatic check box control. The control is a small rectangle (check box) that has the specified text displayed next to it (typically, to the right). When the user chooses the control, the control highlights the rectangle and sends a message to its parent window. The AUTOCHECKBOX statement, which can only be used in the body of a DIALOG statement, defines the text, identifier, dimensions, and attributes of the control.

Syntax

AUTOCHECKBOX text, id, x, y, width, height [, style [, extended-style]]

Parameters

style

Specifies the styles of the control. This value can be a combination of the button class style BS_AUTOCHECKBOX and the WS_TABSTOP and WS_GROUP styles.

If you do not specify a style, the default style is BS_AUTOCHECKBOX and WS_TABSTOP.

For more information on the text, id, x, y, width, height, style, and extended-style parameters, see Common Statement Parameters.

See Also

AUTO3STATE, CHECKBOX, CONTROL, STATE3


AUTORADIOBUTTON Control

The AUTORADIOBUTTON control statement specifies an automatic radio button control. This control automatically performs mutual exclusion with the other AUTORADIOBUTTON controls in the same group. When the button is chosen, the application is notified with BN_CLICKED.

Syntax

AUTORADIOBUTTON text, id, x, y, width, height [, style [, extended-style]]

Parameters

text

The specified text appears next to the radio button.

style

Specifies styles for the automatic radio button, which can be a combination of BUTTON-class styles and the following styles: WS_TABSTOP, WS_DISABLED, and WS_GROUP.

The default style for AUTORADIOBUTTON is BS_AUTORADIOBUTTON and WS_TABSTOP.

For more information on the text, id, x, y, width, height, style, and extended-style parameters, see Common Statement Parameters.

See Also

CONTROL, RADIOBUTTON


BITMAP Resource

The BITMAP resource-definition statement specifies a bitmap that an application uses in its screen display or as an item in a menu or control.

Syntax

nameID BITMAP [load-mem] filename

Parameter

nameID

Specifies either a unique name or a 16-bit unsigned integer value identifying the resource.

load-mem

Specifies loading and memory attributes for the resource. For more information, see Common Resource Attributes.

filename

Specifies the name of the file that contains the resource. The name must be a valid filename; it must be a full path if the file is not in the current working directory. The path can either be a quoted or nonquoted string.

Example

The following example specifies two bitmap resources:

disk1   BITMAP disk.bmp
12      BITMAP PRELOAD diskette.bmp

See Also

LoadBitmap


CAPTION Statement

The CAPTION statement defines the title for a dialog box. The title appears in the box's caption bar (if it has one).

The default caption is empty.

Syntax

CAPTION "captiontext"

Parameter

captiontext

Specifies a character string enclosed in double quotation marks (").

Example

The following example demonstrates the use of the CAPTION statement:

CAPTION "Error!"


CHARACTERISTICS Statement

The CHARACTERISTICS statement allows the developer to specify information about a resource that can be used by tools that read and write resource-definition files. The specified dword value appears with the resource in the compiled .RES file. However, the value is not stored in the executable file and has no significance to Windows.

The CHARACTERISTICS statement appears before the BEGIN in an ACCELERATORS, DIALOG, MENU, RCDATA, or STRINGTABLE resource definition. The specified value applies only to that resource.

Syntax

CHARACTERISTICS dword

Parameter

dword

A user-defined doubleword value.

See Also

Multiline Statements, ACCELERATORS, DIALOG, LANGUAGE, MENU, RCDATA, STRINGTABLE


CHECKBOX Control

The CHECKBOX statement creates a check box control. The control is a small rectangle (check box) that has the specified text displayed next to it (typically, to the right). When the user selects the control, the control highlights the rectangle and sends a message to its parent window. The CHECKBOX statement, which can only be used in a DIALOG statement, defines the text, identifier, dimensions, and attributes of the control.

Syntax

CHECKBOX text, id, x, y, width, height [, style [, extended-style]]

Parameters

text

Specifies text that is displayed to the right of the control.

style

Specifies the control styles. This value can be a combination of the button class style BS_CHECKBOX and the WS_TABSTOP and WS_GROUP styles.

If you do not specify a style, the default style is BS_CHECKBOX and WS_TABSTOP.

For more information on the text, id, x, y, width, height, style, and extended-style parameters, see Common Statement Parameters.

Example

This example creates a check-box control that is labeled "Italic":

CHECKBOX "Italic", 3, 10, 10, 40, 10

See Also

AUTOCHECKBOX, AUTO3STATE, GetDialogBaseUnits, STATE3


CLASS Statement

The CLASS statement defines the class of the dialog box. The CLASS statement appears in the optional section before a DIALOG statement's BEGIN keyword. If no class is given, the Windows standard dialog class is used.

Syntax

CLASS class

Parameters

class

Specifies a 16-bit unsigned integer or a string, enclosed in double quotation marks ("), that identifies the class of the dialog box. If the window procedure for the class does not process a message sent to it, it must call the DefDlgProc function to ensure that all messages are handled properly for the dialog box. A private class can use DefDlgProc as the default window procedure. The class must be registered with the cbWndExtra member of the WNDCLASS structure set to DLGWINDOWEXTRA.

Remarks

The CLASS statement should only be used with special cases, because it overrides the normal processing of a dialog box. The CLASS statement converts a dialog box to a window of the specified class; depending on the class, this could give undesirable results. Do not use the redefined control-class names with this statement.

Example

The following example demonstrates the use of the CLASS statement:

CLASS "myclass"

See Also

DefDlgProc, DIALOG


COMBOBOX Control

The COMBOBOX statement creates a combination box control (a combo box). A combo box consists of either a static text box or an edit box combined with a list box. The list box can be displayed at all times or pulled down by the user. If the combo box contains a static text box, the text box always displays the selection (if any) in the list box portion of the combo box. If it uses an edit box, the user can type in the desired selection; the list box highlights the first item (if any) that matches what the user has entered in the edit box. The user can then select the item highlighted in the list box to complete the choice. In addition, the combo box can be owner-drawn and of fixed or variable height.

Syntax

COMBOBOX text, id, x, y, width, height [, style [, extended-style]]

Parameters

style

Specifies the control styles. This value can be a combination of the COMBOBOX class styles and any of the following styles: WS_TABSTOP, WS_GROUP, WS_VSCROLL, and WS_DISABLED.

If you do not specify a style, the default style is CBS_SIMPLE and WS_TABSTOP.

For more information on the text, id, x, y, width, height, style, and extended-style parameters, see Common Statement Parameters.

Example

This example creates a combo-box control with a vertical scroll bar:

COMBOBOX 777, 10, 10, 50, 54, CBS_SIMPLE | WS_VSCROLL | WS_TABSTOP


CONTROL: General Control

This statement defines a user-defined control window.

Syntax

CONTROL text, id, class, style, x, y, width, height [, extended-style]

Parameters

class

Specifies a redefined name, character string, or a 16-bit unsigned integer value that defines the class. This can be any one of the control classes; for a list of the control classes, see the first list following this description. If the value is a redefined name supplied by the application, it must be a string enclosed in double quotation marks (").

style

Specifies a redefined name or integer value that specifies the style of the given control. The exact meaning of style depends on the class value. The sections following this description show the control classes and corresponding styles.

For more information on the text, id, x, y, width, height, style, and extended-style parameters, see Common Statement Parameters.

The six possible control classes are described in the following sections.


The Button Control Class

A button control is a small rectangular child window that represents a "button" that the user can turn on or off by clicking it with the mouse. Button controls can be used alone or in groups, and can either be labeled or appear without text. Button controls typically change appearance when the user clicks them.

A button can have only one of the following styles, with the exception of BS_LEFTTEXT, which can be combined with check boxes and radio buttons:

BS_3STATE

Creates a button that is the same as a check box, except that the box can be grayed (dimmed) as well as checked. The grayed state is used to show that the state of the check box is not determined.

BS_AUTO3STATE

Creates a button that is the same as a three-state check box, except that the box changes its state when the user selects it. The state cycles through checked, grayed, and normal.

BS_AUTOCHECKBOX

Creates a button that is the same as a check box, except that an X appears in the check box when the user selects the box; the X disappears (is cleared) the next time the user selects the box.

BS_AUTORADIOBUTTON

Creates a button that is the same as a radio button, except that when the user selects it, the button automatically highlights itself and clears (removes the selection from) any other buttons in the same group.

BS_CHECKBOX

Creates a small square that has text displayed to its right (unless this style is combined with the BS_LEFTTEXT style).

BS_DEFPUSHBUTTON

Creates a button that has a heavy black border. The user can select this button by pressing the ENTER key. This style is useful for enabling the user to quickly select the most likely option (the default option).

BS_GROUPBOX

Creates a rectangle in which other controls can be grouped. Any text associated with this style is displayed in the rectangle's upper-left corner.

BS_LEFTTEXT

Places text on the left side of the radio button or check box when combined with a radio button or check box style.

BS_OWNERDRAW

Creates an owner-drawn button. The owner window receives a WM_MEASUREITEM message when the button is created, and it receives a WM_DRAWITEM message when a visual aspect of the button has changed. The BS_OWNERDRAW style cannot be combined with any other button styles.

BS_PUSHBUTTON

Creates a push button that posts a WM_COMMAND message to the owner window when the user selects the button.

BS_RADIOBUTTON

Creates a small circle that has text displayed to its right (unless this style is combined with the BS_LEFTTEXT style). Radio buttons are usually used in groups of related but mutually exclusive choices.


The Combobox Control Class

Combo-box controls consist of a selection field similar to an edit control plus a list box. The list box may be displayed at all times or may be dropped down when the user selects a "pop box" next to the selection field.

Depending on the style of the combo box, the user can or cannot edit the contents of the selection field. If the list box is visible, typing characters into the selection box will cause the first list-box entry that matches the characters typed to be highlighted. Conversely, selecting an item in the list box displays the selected text in the selection field. Combo-box control styles are described below.

CBS_SIMPLE

Displays the list box at all times. The current selection in the list box is displayed in the edit control.

CBS_DROPDOWN

Similar to CBS_SIMPLE except that the list box is not displayed unless the user selects an icon next to the selection field.

CBS_DROPDOWNLIST

Similar to CBS_DROPDOWN except that the edit control is replaced by a static text item which displays the current selection in the list box.

CBS_OWNERDRAWFIXED

Specifies a fixed-height owner-draw combo box. The owner of the list box is responsible for drawing its contents; the items in the list box are all the same height.

CBS_OWNERDRAWVARIABLE

Specifies a variable-height owner-draw combo box. The owner of the list box is responsible for drawing its contents; the items in the list box can have different heights.

CBS_AUTOHSCROLL

Scrolls the text in the edit control to the right when the user types a character at the end of the line. If this style is not set, only text that fits within the rectangular boundary is allowed.

CBS_SORT

Sorts strings entered into the list box.

CBS_HASSTRINGS

Specifies an owner-draw combo box that contains items consisting of strings. The combo box maintains the memory and pointers for the strings so that the application can use the LB_GETTEXT message to retrieve the text for a particular item.

CBS_OEMCONVERT

Converts text entered in the combo box edit control from the ANSI character set to the OEM character set and then back to ANSI. This ensures proper character conversion when the application calls the CharToOem function to convert an ANSI string in the combo box to OEM characters. This style is most useful for combo boxes that contain filenames and applies only to combo boxes created with the CBS_SIMPLE or CBS_DROPDOWN styles.


The Edit Control Class

An edit control is a rectangular child window in which the user can enter text from the keyboard. The user selects the control, and gives it the input focus, by clicking the mouse inside it or pressing the TAB key. The user can enter text when the control displays a flashing insertion point. The mouse can be used to move the cursor and select characters to be replaced, or to position the cursor for inserting characters. The BACKSPACE key can be used to delete characters.

Edit controls use the fixed-pitch font and display Unicode characters. They expand tab characters into as many space characters as are required to move the cursor to the next tab stop. Tab stops are assumed to be at every eighth character position. Edit control styles are described below.

ES_LEFT

Justifies the text to the left.

ES_CENTER

Centers the text. This style is valid in multiline edit controls only.

ES_RIGHT

Justifies the text to the right. This style is valid in multiline edit controls only.

ES_LOWERCASE

Converts all characters to lowercase as they are typed into the edit control.

ES_UPPERCASE

Converts all characters to uppercase as they are typed into the edit control.

ES_PASSWORD

Displays all characters as an asterisk (*) as they are typed into the edit control. An application can use the EM_SETPASSWORDCHAR message to change the character that is displayed.

ES_MULTILINE

Multiple-line edit control. (The default is single-line.) Shows as many lines of text as possible. The following four styles specify options for horizontal and vertical scrolling.

ES_AUTOVSCROLL specified

Shows as many lines as possible and scrolls vertically when the user presses ENTER. (This is actually the carriage-return character, which the edit control expands to a carriage-return − linefeed combination.)

ES_AUTOVSCROLL not specified

Shows as many lines as possible and beeps if the user presses ENTER when no more lines can be displayed.

ES_AUTOHSCROLL specified

Scrolls horizontally when the insertion point goes past the right edge of the control. To start a new line, press ENTER.

ES_AUTOHSCROLL not specified

Wraps words to the beginning of the next line when necessary. A new line is also started if the user presses ENTER. If the window size changes, the word-wrap position changes, and the text is redisplayed.

Multiple-line edit controls can have scroll bars. An edit control with scroll bars processes its own scroll-bar messages. Edit controls without scroll bars scroll as described above and process any scroll messages sent by the parent window.

ES_AUTOVSCROLL

Scrolls text automatically up one page when the user presses ENTER on the last line.

ES_AUTOHSCROLL

Scrolls text automatically to the right by 10 characters when the user types a character at the end of the line. When the user presses ENTER, the control scrolls all text back to position 0.

ES_NOHIDESEL

Overrides the default action, in which an edit control hides the selection when the control loses the input focus. Inverts the selection instead.

ES_OEMCONVERT

Converts text entered in the edit control from the ANSI character set to the OEM character set and then back to ANSI. This ensures proper character conversion when the application calls the CharToOem function to convert an ANSI string in the edit control to OEM characters. This style is most useful for edit controls that contain filenames.


The Listbox Control Class

Listbox controls consist of a list of character strings. The control is used whenever an application needs to present a list of names, such as filenames, that the user can view and select. The user can select a string by pointing to the string with the mouse and clicking a mouse button. When a string is selected, it is highlighted and a notification message is passed to the parent window. A scroll bar can be used with a listbox control to scroll lists that are too long or too wide for the control window. Listbox control styles are described below.

LBS_STANDARD

Strings in the list box are sorted alphabetically and the parent window receives an input message whenever the user clicks or double-clicks a string. The list box contains borders on all sides.

LBS_DISABLENOSCROLL

Shows a disabled vertical scroll bar for the list box when the box does not contain enough items to scroll. If this style is not specified, the scroll bar is hidden when the list box does not contain enough items.

LBS_EXTENDEDSEL

The user can select multiple items using the mouse with the SHIFT and/or the CONTROL key or special key combinations.

LBS_HASSTRINGS

An owner-draw list box contains items consisting of strings. The list box maintains the memory and pointers for the strings so the application can use the LB_GETTEXT message to retrieve the text for a particular item.

LBS_NOTIFY

The parent receives an input message whenever the user clicks or double-clicks a string.

LBS_MULTIPLESEL

The string selection is toggled each time the user clicks or double-clicks the string. Any number of strings can be selected.

LBS_MULTICOLUMN

The list box contains multiple columns. The list box can be scrolled horizontally. The LB_SETCOLUMNWIDTH message sets the width of the columns.

LBS_NOINTEGRALHEIGHT

The size of the list box is exactly the size specified by the application when it created the list box. Normally, Windows sizes a list box so that the list box does not display partial items.

LBS_SORT

The strings in the list box are sorted alphabetically.

LBS_NOREDRAW

The list-box display is not updated when changes are made. This style can be changed at any time by sending a WM_SETREDRAW message.

LBS_OWNERDRAWFIXED

The owner of the list box is responsible for drawing its contents; the items in the list box are all the same height.

LBS_OWNERDRAWVARIABLE

The owner of the list box is responsible for drawing its contents; the items in the list box are variable in height.

LBS_USETABSTOPS

The list box is able to recognize and expand tab characters when drawing its strings. The default tab positions are set at every 32 dialog units. (A dialog unit is a horizontal or vertical distance. One horizontal dialog unit is equal to 1/4 of the current dialog base width unit. The dialog base units are computed from the height and width of the current system font. The GetDialogBaseUnits function returns the size of the dialog base units in pixels.)

LBS_WANTKEYBOARDINPUT

The owner of the list box receives WM_VKEYTOITEM or WM_CHARTOITEM messages whenever the user presses a key while the list box has input focus. This allows an application to perform special processing on the keyboard input.


The Scroll-Bar Control Class

A scroll-bar control is a rectangle that contains a scroll thumb and has direction arrows at both ends. The scroll bar sends a notification message to its parent whenever the user clicks the mouse in the control. The parent is responsible for updating the thumb position, if necessary. Scroll-bar controls have the same appearance and function as the scroll bars used in ordinary windows. But unlike scroll bars, scroll-bar controls can be positioned anywhere within a window and used whenever needed to provide scrolling input for a window. Scroll-bar control styles are described below.

SBS_VERT

Vertical scroll bar. If neither SBS_RIGHTALIGN nor SBS_LEFTALIGN is specified, the scroll bar has the height, width, and position given in the CreateWindow function.

SBS_RIGHTALIGN

Used with SBS_VERT. The right edge of the scroll bar is aligned with the right edge of the rectangle specified by the x, y, width, and height values given in the CreateWindow function. The scroll bar has the default width for system scroll bars.

SBS_LEFTALIGN

Used with SBS_VERT. The left edge of the scroll bar is aligned with the left edge of the rectangle specified by the x, y, width, and height values given in the CreateWindow function. The scroll bar has the default width for system scroll bars.

SBS_HORZ

Horizontal scroll bar. If neither SBS_BOTTOMALIGN nor SBS_TOPALIGN is specified, the scroll bar has the height, width, and position given in the CreateWindow function.

SBS_TOPALIGN

Used with SBS_HORZ. The top edge of the scroll bar is aligned with the top edge of the rectangle specified by the x, y, width, and height values given in the CreateWindow function. The scroll bar has the default height for system scroll bars.

SBS_BOTTOMALIGN

Used with SBS_HORZ. The bottom edge of the scroll bar is aligned with the bottom edge of the rectangle specified by the x, y, width, and height values given in the CreateWindow function. The scroll bar has the default height for system scroll bars.

SBS_SIZEBOX

Size box. If neither SBS_SIZEBOXBOTTOMRIGHTALIGN nor SBS_SIZEBOXTOPLEFTALIGN is specified, the size box has the height, width, and position given in the CreateWindow function.

SBS_SIZEBOXTOPLEFTALIGN

Used with SBS_SIZEBOX. The top-left corner of the size box is aligned with the top-left corner of the rectangle specified by the x, y, width, and height values given in the CreateWindow function. The size box has the default size for system size boxes.

SBS_SIZEBOXBOTTOMRIGHTALIGN

Used with SBS_SIZEBOX. The bottom-right corner of the size box is aligned with the bottom-right corner of the rectangle specified by the x, y, width, and height values given in the CreateWindow function. The size box has the default size for system size boxes.


The Static Control Class

Static controls are simple text fields, boxes, and rectangles that can be used to label, box, or separate other controls. Static controls take no input and provide no output. Static control styles are described below.

SS_LEFT

A simple rectangle displaying the given text flush left. The text is formatted before it is displayed. Words that would extend past the end of a line are automatically wrapped to the beginning of the next line.

SS_CENTER

A simple rectangle displaying the given text centered. The text is formatted before it is displayed. Words that would extend past the end of a line are automatically wrapped to the beginning of the next line.

SS_RIGHT

A simple rectangle displaying the given text flush right. The text is formatted before it is displayed. Words that would extend past the end of a line are automatically wrapped to the beginning of the next line.

SS_LEFTNOWORDWRAP

A simple rectangle displaying the given text flush left. Tabs are expanded, but words are not wrapped. Text that extends past the end of a line is clipped.

SS_SIMPLE

A simple rectangle with a single line of text flush left. The line of text cannot be shortened or altered in any way. (The control's parent window or dialog box must not process the WM_CTLCOLOR message.)

SS_NOPREFIX

Removes any ampersand (&) characters and underlines the next character in the string. Unless this style is specified, Windows will interpret any ampersand characters in the control's text to be accelerator prefix characters. If a static control is to contain text where this feature is not wanted, SS_NOPREFIX may be added. This static-control style may be included with any of the defined static controls.

You can combine SS_NOPREFIX with other styles by using the bitwise OR (|) operator. This is most often used when filenames or other strings that may contain an ampersand need to be displayed in a static control in a dialog box.

SS_ICON

An icon displayed in the dialog box. The given text is the name of an icon (not a filename) defined elsewhere in the resource file. For the ICON statement, the width and height parameters in the CreateWindow function are ignored; the icon automatically sizes itself.

SS_BLACKRECT

A rectangle filled with the color used to draw window frames. This color is black in the default Windows color scheme.

SS_GRAYRECT

A rectangle filled with the color used to fill the screen background. This color is gray in the default Windows color scheme.

SS_WHITERECT

A rectangle filled with the color used to fill window backgrounds. This color is white in the default Windows color scheme.

SS_BLACKFRAME

Box with a frame drawn with the same color as window frames. This color is black in the default Windows color scheme.

SS_GRAYFRAME

Box with a frame drawn with the same color as the screen background (desktop). This color is gray in the default Windows color scheme.

SS_WHITEFRAME

Box with a frame drawn with the same color as window backgrounds. This color is white in the default Windows color scheme.

SS_USERITEM

User-defined item.


CTEXT Control

The CTEXT statement creates a centered-text control. The control is a simple rectangle displaying the given text centered in the rectangle. The text is formatted before it is displayed. Words that would extend past the end of a line are automatically wrapped to the beginning of the next line. The CTEXT statement, which you can use only in a DIALOG statement, defines the text, identifier, dimensions, and attributes of the control.

Syntax

CTEXT text, id, x, y, width, height [, style [, extended-style]]

Parameters

text

Specifies text that is centered in the rectangular area of the control.

style

Specifies the control styles. This value can be any combination of the following styles: SS_CENTER, WS_TABSTOP, and WS_GROUP.

If you do not specify a style, the default style is SS_CENTER and WS_GROUP.

For more information on the text, id, x, y, width, height, style, and extended-style parameters, see Common Statement Parameters.

Example

This example creates a centered-text control that is labeled "filename":

CTEXT "filename", 101, 10, 10, 100, 100

See Also

CONTROL, DIALOG, LTEXT, RTEXT


CURSOR Resource

The CURSOR statement specifies a bitmap that defines the shape of the cursor on the display screen.

Syntax

nameID CURSOR [load-mem] filename

Parameters

nameID

Specifies either a unique name or a 16-bit unsigned integer identifying the resource.

load-mem

Specifies loading and memory attributes for the resource. For more information, see Common Resource Attributes.

filename

Specifies the name of the file that contains the resource. The name must be a valid filename; it must be a full path if the file is not in the current working directory. The path can either be a quoted or nonquoted string.

Remarks

Icon and cursor resources can contain more than one image. If the resource is marked with the PRELOAD option, Windows loads all images in the resource when the application executes.

Example

The following example specifies two cursor resources; one by name (cursor1) and the other by number (2):

cursor1 CURSOR bullseye.cur
2       CURSOR "d:\\cursor\\arrow.cur"


DEFPUSHBUTTON Control

The DEFPUSHBUTTON statement creates a default push-button control. The control is a small rectangle with a bold outline that represents the default response for the user. The given text is displayed inside the button. The control highlights the button in the usual way when the user clicks the mouse in it and sends a message to its parent window.

Syntax

DEFPUSHBUTTON text, id, x, y, width, height [, style [, extended-style]]

Parameters

text

Specifies text that is centered in the rectangular area of the control.

style

Specifies the control styles. This value can be a combination of the following styles: BS_DEFPUSHBUTTON, WS_TABSTOP, WS_GROUP, and WS_DISABLED.

If you do not specify a style, the default style is BS_DEFPUSHBUTTON and WS_TABSTOP.

For more information on the text, id, x, y, width, height, style, and extended-style parameters, see Common Statement Parameters.

Example

This example creates a default push-button control that is labeled "Cancel":

DEFPUSHBUTTON "Cancel", 101, 10, 10, 24, 50

See Also

PUSHBUTTON, RADIOBUTTON


DIALOG Resource

The DIALOG statement defines a window that an application can use to create dialog boxes. The statement defines the position and dimensions of the dialog box on the screen as well as the dialog box style.

Syntax

nameID DIALOG [ load-mem] x, y, width, height
[optional-statements]
BEGIN
    control-statement
    . . .
END

Parameters

nameID

Identifies the dialog box. This is either a unique name or a unique 16-bit unsigned integer value in the range 1 to 65,535.

load-mem

Specifies loading and memory attributes for the resource. For more information, see Common Resource Attributes.

option-statements

Specifies options for the dialog box. This can be zero or more of the following statements:

CAPTION "text"

Specifies the caption of the dialog box if it has a title bar. See CAPTION for more information.

CHARACTERISTICS dword

Specifies a user-defined double-word value for use by resource tools. This value is not used by Windows. For more information, see CHARACTERISTICS.

CLASS class

Specifies a 16-bit unsigned integer or a string, enclosed in double quotation marks ("), that identifies the class of the dialog box. See CLASS for more information.

LANGUAGE language,sublanguage

Specifies the language of the dialog box. See LANGUAGE for more information.

STYLE styles

Specifies the styles of the dialog box. See STYLE for more information.

EXSTYLE=extended-styles

Specifies the extended styles of the dialog box. See EXSTYLE for more information.

VERSION dword

Specifies a user-defined doubleword value. This statement is intended for use by additional resource tools and is not used by Windows. For more information, see VERSION.

For more information on the x, y, width, and height parameters, see Common Statement Parameters.

Remarks

The GetDialogBaseUnits function returns the dialog base units in pixels. The exact meaning of the coordinates depends on the style defined by the STYLE option statement. For child-style dialog boxes, the coordinates are relative to the origin of the parent window, unless the dialog box has the style DS_ABSALIGN; in that case, the coordinates are relative to the origin of the display screen.

Do not use the WS_CHILD style with a modal dialog box. The DialogBox function always disables the parent/owner of the newly created dialog box. When a parent window is disabled, its child windows are implicitly disabled. Since the parent window of the child-style dialog box is disabled, the child-style dialog box is too.

If a dialog box has the DS_ABSALIGN style, the dialog coordinates for its upper-left corner are relative to the screen origin instead of to the upper-left corner of the parent window. You would typically use this style when you wanted the dialog box to start in a specific part of the display no matter where the parent window may be on the screen.

The name DIALOG can also be used as the class-name parameter to the CreateWindow function to create a window with dialog box attributes.

Example

The following demonstrates the usage of the DIALOG statement:

#include <windows.h>

ErrorDialog DIALOG  10, 10, 300, 110
STYLE WS_POPUP|WS_BORDER
CAPTION "Error!"

BEGIN
    CTEXT "Select One:", 1, 10, 10, 280, 12
    PUSHBUTTON "&Retry", 2, 75, 30, 60, 12
    PUSHBUTTON "&Abort", 3, 75, 50, 60, 12
    PUSHBUTTON "&Ignore", 4, 75, 80, 60, 12
END

See Also

CONTROL, CreateDialog, CreateWindow, DialogBox, DIALOGEX, GetDialogBaseUnits, Multiline Statements, ACCELERATORS, CHARACTERISTICS, LANGUAGE, MENU, RCDATA, STRINGTABLE, VERSION


DIALOGEX Resource

The DIALOGEX resource is an extension of the DIALOG resource. In addition to the functionality offered by DIALOG, DIALOGEX allows for the following:

•	Help IDs on the dialog itself as well as on controls within the dialog.

•	Use of the EXSTYLE statement for the dialog itself as well as on controls within the dialog.

•	Font weight and italic settings for the font to be used in the dialog.

•	Control-specific data for controls within the dialog.

•	Use of the BEDIT, IEDIT, and HEDIT predefined system class names.

Syntax

nameID DIALOGEX [ load-mem] x, y, width, height [ , helpID]
[ optional-statements]
BEGIN
     control-statement
     . . .
END

Parameters

nameID

Identifies the dialog box. This is either a unique name or a unique 16-bit unsigned integer value in the range 1 to 65,535.

load-mem

Specifies loading and memory attributes for the resource. For more information, see Common Resource Attributes.

x

Specifies the location on the screen of the left side of the dialog, in dialog units.

y

Specifies the location on the screen of the top of the dialog, in dialog units.

width

Specifies the width of the dialog, in dialog units.

height

Specifies the height of the dialog, in dialog units.

helpID

Specifies a numeric expression indicating the ID used to identify the dialog during WM_HELP processing.

optional-statements

Specifies options for the dialog box. This can be zero or more of the following statements:

CAPTION "text"

Specifies the caption of the dialog box if it has a title bar. See CAPTION for more information.

CHARACTERISTICS DWORD

Specifies a user-defined DWORD value for use by resource tools. This value is not used by Windows. For more information see CHARACTERISTICS.

CLASS class

Specifies a 16-bit unsigned integer or a string, enclosed in double quotation marks ("), that identifies the class of the dialog box. See CLASS for more information.

EXSTYLE=extended-styles

Specifies the extended styles of the dialog box. See EXSTYLE for more information.

FONT pointsize, typeface, weight, italic

pointsize

Specifies the size, in points, of the font.

typeface

Specifies the name of the typeface. This name must be identical to the name defined in the [FONTS] section of WIN.INI. This parameter must be enclosed in double quotation marks (").

weight

Specifies a numeric expression for the font weight (explicit FW_* values defined in WINGDI.H can be used by adding an include to the RC file: #include "WINGDI.H")

italic

Indicates whether the font should be italic or not. Specify either TRUE or FALSE for the italic value.

LANGUAGE language, sublanguage

Specifies the language of the dialog box. See LANGUAGE for more information.

MENU menuname

Specifies the menu to use. This value is either the name of the menu or the integer identifier.

STYLE styles

Specifies the styles of the dialog box. See STYLE for more information.

VERSION DWORD

Specifies a user-defined DWORD value. This statement is intended for use by additional resource tools and is not used by Windows. For more information, see VERSION.

The DIALOGEX body is marked with a BEGIN statement at the beginning of the body and an END statement at the end of the body. The body is made up of any number of control statements. There are four families of control statements: generic, static, button, and edit. While each of these families uses a different syntax for defining specific features of its controls, they all share a common syntax for defining the position, size, extended styles, help identification number, and control-specific data. That common syntax is:

(controlType), x, y, cx, cy [, [exStyle] [, helpID]
    [BEGIN
        data-element-1 [,
        data-element-2 [,
        ... ]]
    END]

(controlType)

Family-specific definition — described below.

x

Specifies the location in the dialog of the left side of the control, in dialog units.

y

Specifies the location in the dialog of the top of the control, in dialog units.

cx

Specifies the width of the control, in dialog units.

cy

Specifies the height of the control, in dialog units.

exStyle

Specifies any number of extended window styles (explicit WS_EX_* style values defined in winuser.h can be used by adding an include to the RC file: #include "winuser.h")

helpID

Specifies a numeric expression indicating the ID used to identify the control during WM_HELP processing.

controlData

Marked by a nested BEGIN and END, specifies the control-specific data for the control. When a dialog is created, and a control in that dialog which has control-specific data is created, a pointer to that data is passed into the control's window procedure via the lParam to the WM_CREATE message for that control.

Following is the family-specific syntax of the (controlType):

Generic control:

CONTROL controlText, id, className, style

controlText

Specifies the window text for the control. For more information, see Common Statement Parameters.

id

Specifies the control identifier. For more information, see Common Statement Parameters.

className

Specifies the name of the class. This may be either a string enclosed in double quotation marks (") or one of the following predefined system classes: BUTTON, STATIC, EDIT, LISTBOX, SCROLLBAR, or COMBOBOX.

style

Specifies the window styles (explicit WS_*, BS_*, SS_*, ES_*, LBS_*, SBS_*, and CBS_* style values defined in WINUSER.H can be used by adding an include to the RC file: #include "WINUSER.H")

Static control:

staticClass controlText, id

staticClass {LTEXT | RTEXT | CTEXT}

controlText

Specifies the window text for the control. For more information, see "Common Statement Parameters".

id

Specifies the control identifier. For more information, see "Common Statement Parameters".

Button control:

buttonClass controlText, id

buttonClass {AUTO3STATE | AUTOCHECKBOX | AUTORADIOBUTTON | CHECKBOX | PUSHBOX | PUSHBUTTON | RADIOBUTTON | STATE3 | USERBUTTON}

controlText

Specifies the window text for the control. For more information, see "Common Statement Parameters".

id

Specifies the control identifier. For more information, see "Common Statement Parameters".

Edit control:

editClass id

editClass {EDITTEXT | BEDIT | HEDIT | IEDIT}

id

Specifies the control identifier. For more information, see "Common Statement Parameters".

Arithmetic and Boolean Operations

Valid operations that may be contained in any of the numeric expressions in the statements of DIALOGEX are:

•	Add ('+')

•	Subtract ('-')

•	Unary minus ('-')

•	Unary NOT ('~')

•	AND ('&')

•	OR ('|')

See Also

CONTROL, CreateDialog, CreateWindow, DialogBox, DIALOGEX, GetDialogBaseUnits, Multiline Statements, ACCELERATORS, CHARACTERISTICS, LANGUAGE, MENU, RCDATA, STRINGTABLE, VERSION


EDITTEXT Control

The EDITTEXT statement defines an EDIT control belonging to the EDIT class. It creates a rectangular region in which the user can type and edit text. The control displays a cursor when the user clicks the mouse in it. The user can then use the keyboard to enter text or edit the existing text. Editing keys include the BACKSPACE and DELETE keys. The user can also use the mouse to select characters to be deleted or to select the place to insert new characters.

Syntax

EDITTEXT text, id, x, y, width, height [, style [, extended-style]]

Parameters

style

Specifies the control styles. This value can be a combination of the edit class styles and the following styles: WS_TABSTOP, WS_GROUP, WS_VSCROLL, WS_HSCROLL, and WS_DISABLED.

If you do not specify a style, the default style is ES_LEFT, WS_BORDER, and WS_TABSTOP.

For more information on the text, id, x, y, width, height, style, and extended-style parameters, see Common Statement Parameters.

Example

The following example demonstrates the use of the EDITTEXT statement:

EDITTEXT  3, 10, 10, 100, 10


EXSTYLE Statement

The EXSTYLE command allows you to designate a dialog box with the WS_EX_style styles. In a resource definition, the EXSTYLE statement is placed with the optional statements before the BEGIN keyword.

Syntax

EXSTYLE extended-style

Parameter

extended-style

The WS_EX_style style for the dialog box or control.

Remarks

It can also be placed with the load-mem parameters in a DIALOG statement as follows:

name DIALOG [load-mem] EXSTYLE=extended-style x, y, ...

For controls, extended styles are specified after the style option in any control definition, as follows:

control text, id, x, y, width, height, [style[, extended-style]]

See also

ACCELERATORS, CONTROL, DIALOG, MENU, POPUP, RCDATA, STRINGTABLE, User-Defined Resource


FONT Resource

The FONT resource-definition statement specifies a file that contains a font.

For a font resource, nameID must be a number; it cannot be a name.

Syntax

nameID FONT [load-mem] filename

Parameters

nameID

Specifies either a unique name or a 16-bit unsigned integer value identifying the resource.

load-mem

Specifies loading and memory attributes for the resource. For more information, see Common Resource Attributes.

filename

Specifies the name of the file that contains the resource. The name must be a valid filename; it must be a full path if the file is not in the current working directory. The path can either be a quoted or nonquoted string.

Example

The following example specifies a single font resource:

5 FONT  CMROMAN.FNT


FONT Statement

The FONT statement defines the font with which Windows will draw text in the dialog box. The font must have been previously loaded, either from the WIN.INI file or by calling the LoadResource function.

Syntax

FONT pointsize, typeface

Parameters

pointsize

Specifies the size, in points, of the font.

typeface

Specifies the name of the typeface. This name must be identical to the name defined in the [FONTS] section of WIN.INI. This parameter must be enclosed in double quotes (").

Example

The following example demonstrates the use of the FONT statement:

FONT 12, "MS Sans Serif"

See Also

DIALOG, LoadResource


GROUPBOX Control

The GROUPBOX statement creates a group box control. The control is a rectangle that groups other controls together. The controls are grouped by drawing a border around them and displaying the given text in the upper-left corner. The GROUPBOX statement, which you can use only in a DIALOG statement, defines the text, identifier, dimensions, and attributes of a control window.

When the style contains WS_TABSTOP or the text specifies an accelerator, tabbing or pressing the accelerator key moves the focus to the first control within the group.

Syntax

GROUPBOX text, id, x, y, width, height [, style [, extended-style]]

Parameters

style

Specifies the control styles. This value can be a combination of the button class style BS_GROUPBOX and the WS_TABSTOP and WS_DISABLED styles.

If you do not specify a style, the default style is BS_GROUPBOX.

For more information on the text, id, x, y, width, height, style, and extended-style parameters, see Common Statement Parameters.

Example

This example creates a group-box control that is labeled "Options":

GROUPBOX "Options", 101, 10, 10, 100, 100

See Also

DIALOG


ICON Resource

The ICON resource-definition statement specifies a bitmap that defines the shape of the icon to be used for a given application.

Syntax

nameID ICON [load-mem] filename

Parameters

nameID

Specifies either a unique name or a 16-bit unsigned integer value identifying the resource.

load-mem

Specifies loading and memory attributes for the resource. For more information, see Common Resource Attributes.

filename

Specifies the name of the file that contains the resource. The name must be a valid filename; it must be a full path if the file is not in the current working directory. The path can either be a quoted or nonquoted string.

Remarks

Icon and cursor resources can contain more than one image. If the resource is marked as PRELOAD, Windows loads all images in the resource when the application executes.

Example

The following example specifies two icon resources:

desk1   ICON desk.ico
11      ICON DISCARDABLE custom.ico


ICON Control

The ICON statement creates an icon control. This control is an icon displayed in a dialog box. The ICON control statement, which you can use only in a DIALOG statement, defines the icon-resource identifier, icon-control identifier, position, and attributes of a control.

Syntax

ICON text, id, x, y, [width, height, style [, extended-style]]

Parameters

text

Specifies the name of an icon (not a filename) defined elsewhere in the resource file.

width

This value is ignored and should be set to zero.

height

This value is ignored and should be set to zero.

style

Specifies the control style. This parameter is optional. The only value that can be specified is the SS_ICON style. This is the default style whether this parameter is specified or not.

For more information on the text, id, x, y, width, height, style, and extended-style parameters, see Common Statement Parameters.

Example

This example creates an icon control whose icon identifier is 901 and whose name is "myicon":

ICON "myicon" 901, 30, 30

See Also

DIALOG, ICON


LANGUAGE Statement

The LANGUAGE statement sets the language for all resources up to the next LANGUAGE statement or to the end of the file. When the LANGUAGE statement appears before the BEGIN in an ACCELERATORS, DIALOG, MENU, RCDATA, or STRINGTABLE resource definition, the specified language applies only to that resource.

Syntax

LANGUAGE language, sublanguage

Parameters

language

Language identifier. Must be one of the constants from WINNLS.H

sublanguage

Sublanguage identifier. Must be one of the constants from WINNLS.H

See Also

Multiline Statements, ACCELERATORS, CHARACTERISTICS, DIALOG, MENU, RCDATA, STRINGTABLE, VERSION


LISTBOX Control

The LISTBOX statement creates commonly used controls for a dialog box or window. The control is a rectangle containing a list of strings (such as filenames) from which the user can select. The LISTBOX statement, which can only be used in a DIALOG or WINDOW statement, defines the identifier, dimensions, and attributes of a control window.

Syntax

LISTBOX text, id, x, y, width, height [, style [, extended-style]]

Parameters

style

Specifies the control styles. This value can be a combination of the list-box class styles and any of the following styles: WS_BORDER and WS_VSCROLL.

If you do not specify a style, the default style is LBS_NOTIFY and WS_BORDER.

For more information on the text, id, x, y, width, height, style, and extended-style parameters, see Common Statement Parameters.

Example

This example creates a list-box control whose identifier is 101:

LISTBOX 101, 10, 10, 100, 100

See Also

COMBOBOX, DIALOG


LTEXT Control

The LTEXT statement creates a left-aligned text control. The control is a simple rectangle displaying the given text left-aligned in the rectangle. The text is formatted before it is displayed. Words that would extend past the end of a line are automatically wrapped to the beginning of the next line. The LTEXT statement, which can be used only in a DIALOG statement, defines the text, identifier, dimensions, and attributes of the control.

Syntax

LTEXT text, id, x, y, width, height [, style [, extended-style]]

Parameters

style

Specifies the control styles. This value can be any combination of the BS_RADIOBUTTON style and the following styles: SS_LEFT, WS_TABSTOP, and WS_GROUP.

If you do not specify a style, the default style is SS_LEFT and WS_GROUP.

For more information on the text, id, x, y, width, height, style, and extended-style parameters, see Common Statement Parameters.

Example

This example creates a left-aligned text control that is labeled "Filename":

LTEXT "Filename", 101, 10, 10, 100, 100

See Also

CONTROL, CTEXT, DIALOG, RTEXT


MENU Resource

The MENU statement defines the contents of a menu resource. A menu resource is a collection of information that defines the appearance and function of an application menu. A menu is a special input tool that lets a user select commands from a list of command names.

Syntax

menuID MENU [load-mem]
[optional-statements]
BEGIN
    item-definitions
    . . .
END

Parameters

menuID

Identifies the menu. This value is either a unique string or a unique 16-bit unsigned integer value in the range of 1 to 65,535.

load-mem

Specifies loading and memory attributes for the resource. For more information, see Common Resource Attributes.

optional-statements

Zero or more of the following statements:

Statement	Description
CHARACTERISTICS dword	User-defined information about a resource that can be used by tools that read and write resource files.
LANGUAGE language, sublanguage	Specifies the language for the resource. The parameters are constants from WINNLS.H.
VERSION dword	User-defined version number for the resource that can be used by tools that read and write resource files.
Example

Following is an example of a complete MENU statement:

sample MENU
BEGIN
     MENUITEM "&Soup", 100
     MENUITEM "S&alad", 101
     POPUP "&Entree"
     BEGIN
          MENUITEM "&Fish", 200
          MENUITEM "&Chicken", 201, CHECKED
          POPUP "&Beef"
          BEGIN
               MENUITEM "&Steak", 301
               MENUITEM "&Prime Rib", 302
          END
     END
     MENUITEM "&Dessert", 103
END

See Also

MENUEX, MENUITEM, POPUP, Multiline Statements, ACCELERATORS, CHARACTERISTICS, DIALOG, LANGUAGE, RCDATA, STRINGTABLE, VERSION


MENU Statement

The MENU statement defines the dialog box's menu. If no statement is given, the dialog box has no menu.

Syntax

MENU menuname

Parameter

menuname

Specifies the menu to use. This value is either the name of the menu or the integer identifier of the menu.

Example

The following example demonstrates the use of the MENU dialog statement:

MENU errmenu


MENUEX Resource

The MENUEX resource is an extension of the MENU resource. In addition to the functionality offered by MENU, MENUEX allows for the following:

•	Help IDs on popup menus.

•	IDs on popup menus.

•	Use of the menu type and state flags created for Windows 95 (MFT_* type flags and MFS_* state flags).

Syntax

menuID MENUEX
BEGIN
    [{[MENUITEM itemText [, [id] [, [type] [, state]]]] |
    [POPUP    itemText [, [id] [, [type] [, [state] [, helpID]]]]
    BEGIN
        popupBody
    END]} ...]
END

Parameters

MENUITEM statement

Defines a normal menu item

itemText

Specifies the string containing the text for the menu item. For more information, see MENUITEM.

id

Specifies a numeric expression indicating the ID of the menu item.

type

Specifies a numeric expression indicating the type of the menu item (explicit MFT_* type values defined in WINUSER.H can be used by adding an include to the RC file: #include "WINUSER.H")

state

Specifies a numeric expression indicating the state of the menu item (explicit MFS_* state values defined in WINUSER.H can be used by adding an include to the RC file: #include "WINUSER.H")

POPUP statement

Defines a menu item which has another menu (a submenu) associated with it.

itemText

Specifies a string containing the text for the menu item.

id

Specifies a numeric expression indicating the ID of the menu item.

type

Specifies a numeric expression indicating the type of the menu item (explicit MFT_* type values defined in WINUSER.H can be used by adding an include to the RC file: #include "WINUSER.H").

state

Specifies a numeric expression indicating the state of the menu item (explicit MFS_* state values defined in WINUSER.H can be used by adding an include to the RC file: #include "WINUSER.H").

helpID

Specifies a numeric expression indicating the ID used to identify the menu during WM_HELP processing.

popupBody

Contain any combination of the MENUITEM and POPUP statements described above.

Remarks

Valid arithmetic and Boolean operations that may be contained in any of the numeric expressions in the statements of MENUEX are:

•	Add ('+')

•	Subtract ('-')

•	Unary minus ('-')

•	Unary NOT ('~')

•	AND ('&')

•	OR ('|')

See Also

MENU, MENUITEM, POPUP, Multiline Statements, ACCELERATORS, CHARACTERISTICS, DIALOG, LANGUAGE, RCDATA, STRINGTABLE, VERSION


MENUITEM Statement

The MENUITEM statement defines a menu item.

Syntax

MENUITEM text, result, [optionlist]
MENUITEM SEPARATOR

Parameters

text

Specifies the name of the menu item.

The string can contain the escape characters \t and \a. The \t character inserts a tab in the string and is used to align text in columns. Tab characters should be used only in pop-up menus, not in menu bars. (For information on pop-up menus, see the POPUP statement.) The \a character aligns all text that follows it flush right to the menu bar or pop-up menu.

result

Specifies the result generated when the user selects the menu item. This parameter takes an integer value. Menu-item results are always integers; when the user clicks the menu-item name, the result is sent to the window that owns the menu.

optionlist

Specifies the appearance of the menu item. This optional parameter takes one or more redefined menu options, separated by commas or spaces. The menu options are as follows:

CHECKED

Item has a check mark next to it.

GRAYED

Item name is initially inactive and appears on the menu in gray or a lightened shade of the menu-text color.

HELP

Identifies a help item.

INACTIVE

Item name is displayed but it cannot be selected.

MENUBARBREAK

Same as MF_MENUBREAK except that for pop-up menus, it separates the new column from the old column with a vertical line.

MENUBREAK

Places the menu item on a new line for static menu-bar items. For pop-up menus, it places the menu item in a new column with no dividing line between the columns.

The INACTIVE and GRAYED options cannot be used together.

SEPARATOR

The MENUITEM SEPARATOR form of the MENUITEM statement creates an inactive menu item that serves as a dividing bar between two active menu items in a pop-up menu.

Example

The following example demonstrates the use of the MENUITEM and MENUITEM SEPARATOR statements:

MENUITEM "&Roman", 206, CHECKED, GRAYED
MENUITEM SEPARATOR
MENUITEM "&Blackletter", 301

See Also

MENU, POPUP


MESSAGETABLE Resource

The MESSAGETABLE resource-definition statement defines the ID and file of an application's message table resource. Message tables are special string resources used in event logging and with the FormatMessage function. The file contains a binary message table generated by the Message Compiler. The Message Compiler also generates a resource script file that contains the MESSAGETABLE statements you need to include the message table resources in the compiled resource file. Use the #include directive to include this resource script into your main resource script.

Syntax

nameID MESSAGETABLE filename

Parameters

nameID

Specifies either a unique name or a 16-bit unsigned integer value identifying the resource.

filename

Specifies the name of the file that contains the resource. The name must be a valid filename; it must be a full path if the file is not in the current working directory. The path can either be a quoted or nonquoted string.

See Also

Compiling Messages, STRINGTABLE


POPUP Resource

The POPUP statement marks the beginning of the definition of a pop-up menu. A pop-up menu (which is also known as a drop-down menu) is a special menu item that displays a sublist of menu items when it is selected.

Syntax

POPUP text, [optionlist]

BEGIN
    item-definitions
    .
    .
    .
END

Parameters

text

Specifies the name of the pop-up menu. This string must be enclosed in double quotation marks (").

optionlist

Specifies one or more redefined menu options that specify the appearance of the menu item. The menu options follow:

CHECKED

Item has a check mark next to it. This option is not valid for a top-level pop-up menu.

GRAYED

Item name is initially inactive and appears on the menu in gray or a lightened shade of the menu-text color.

INACTIVE

Item name is displayed but it cannot be selected.

MENUBARBREAK

Same as MF_MENUBREAK except that for pop-up menus, it separates the new column from the old column with a vertical line.

MENUBREAK

Places the menu item on a new line for static menu-bar items. For pop-up menus, it places the menu item in a new column with no dividing line between the columns.

The INACTIVE and GRAYED options cannot be used together.

Example

The following example demonstrates the use of the POPUP statement:

chem MENU
BEGIN
    POPUP "&Elements"
    BEGIN
         MENUITEM "&Oxygen", 200
         MENUITEM "&Carbon", 201, CHECKED
         MENUITEM "&Hydrogen", 202
         MENUITEM SEPARATOR
         MENUITEM "&Sulfur", 203
         MENUITEM "Ch&lorine", 204
    END

    POPUP "&Compounds"
    BEGIN
         POPUP "&Sugars"
         BEGIN
            MENUITEM "&Glucose", 301
            MENUITEM "&Sucrose", 302, CHECKED
            MENUITEM "&Lactose", 303, MENUBREAK
            MENUITEM "&Fructose", 304
         END
         POPUP "&Acids"
         BEGIN
              "&Hydrochloric", 401
              "&Sulfuric", 402
         END
    END
END

See Also

MENU, MENUITEM


PUSHBOX Control

The PUSHBOX statement creates a push-box control, which is identical to a PUSHBUTTON, except that it does not display a button face or frame; only the text appears.

Syntax

PUSHBOX text, id, x, y, width, height [, style [, extended-style]]

Parameters

style

Specifies styles for the pushbox, which can be a combination of the BS_PUSHBOX style and the following styles: WS_TABSTOP, WS_DISABLED, and WS_GROUP.

The default style is BS_PUSHBOX and WS_TABSTOP.

For more information on the text, id, x, y, width, height, style, and extended-style parameters, see Common Statement Parameters.

See Also

PUSHBUTTON


PUSHBUTTON Control

The PUSHBUTTON statement creates a push-button control. The control is a round-cornered rectangle containing the given text. The text is centered in the control. The control sends a message to its parent whenever the user chooses the control.

Syntax

PUSHBUTTON text, id, x, y, width, height [, style [, extended-style]]

Parameters

style

Specifies styles for the pushbutton, which can be a combination of the BS_PUSHBUTTON style and the following styles: WS_TABSTOP, WS_DISABLED, and WS_GROUP.

The default style is BS_PUSHBUTTON and WS_TABSTOP.

For more information on the text, id, x, y, width, height, style, and extended-style parameters, see Common Statement Parameters.

Example

The following example demonstrates the use of the PUSHBUTTON statement:

PUSHBUTTON "ON", 7, 10, 10, 20, 10

See Also

GetDialogBaseUnits


RADIOBUTTON Control

The RADIOBUTTON statement creates a radio-button control. The control is a small circle that has the given text displayed next to it, typically to its right. The control highlights the circle and sends a message to its parent window when the user selects the button. The control removes the highlight and sends a message when the button is next selected.

Syntax

RADIOBUTTON text, id, x, y, width, height [, style [, extended-style]]

Parameters

style

Specifies styles for the radio button, which can be a combination of BUTTON-class styles and the following styles: WS_TABSTOP, WS_DISABLED, and WS_GROUP.

The default style for RADIOBUTTON is BS_RADIOBUTTON and WS_TABSTOP.

For more information on the text, id, x, y, width, height, style, and extended-style parameters, see Common Statement Parameters.

Example

The following example demonstrates the use of the RADIOBUTTON statement:

RADIOBUTTON "Italic", 100, 10, 10, 40, 10

See Also

GetDialogBaseUnits


RCDATA Resource

The RCDATA statement defines a raw data resource for an application. Raw data resources permit the inclusion of binary data directly in the executable file.

Syntax

nameID RCDATA [load-mem]
[optional-statements]
BEGIN
    raw-data
    . . .
END

Parameters

nameID

Specifies either a unique name or a 16-bit unsigned integer value that identifies the resource.

load-mem

Specifies loading and memory attributes for the resource. For more information, see Common Resource Attributes.

optional-statements

Zero or more of the following statements:

Statement	Description
CHARACTERISTICS dword	User-defined information about a resource that can be used by tools that read and write resource files.
LANGUAGE language, sublanguage	Specifies the language for the resource. The parameters are constants from WINNLS.H.
VERSION dword	User-defined version number for the resource that can be used by tools that read and write resource files.
raw-data

Specifies raw data consisting of one or more integers or strings of characters. Integers can be specified in decimal, octal, or hexadecimal format. RC does not automatically append a terminating null character to a string. The string is a sequence of the specified ANSI (byte) characters unless explicitly qualified as a wide-character string with the L prefix. Strings in all resources other than RCDATA and user-defined resources are Unicode strings.

The block of data begins on a DWORD boundary and RC performs no padding or alignment of data within the raw-data block. It is the programmer's responsibility to ensure the proper alignment of data within the block.

Example

The following example demonstrates the use of the RCDATA statement:

resname RCDATA
BEGIN
   L"Here is a Unicode string\0", /* A Unicode string. Note: explicitly
                                 null-terminated */
   1024,                  /* int        */
   0x029a,                /* hex int    */
   0o733,                 /* octal int  */
   "\07"                  /* octal byte */
END

See Also

Multiline Statements, ACCELERATORS, CHARACTERISTICS, DIALOG, LANGUAGE, MENU, STRINGTABLE, VERSION


RTEXT Control

The RTEXT statement creates a right-aligned text control. The control is a simple rectangle displaying the given text right-aligned in the rectangle. The text is formatted before it is displayed. Words that would extend past the end of a line are automatically wrapped to the beginning of the next line.

Syntax

RTEXT text, id, x, y, width, height [, style [, extended-style]]

Parameters

style

Specifies styles for the text control, which can be any combination of the following: WS_TABSTOP and WS_GROUP.

The default style for RTEXT is SS_RIGHT and WS_GROUP.

For more information on the text, id, x, y, width, height, style, and extended-style parameters, see Common Statement Parameters.

Example

The following example demonstrates the use of the RTEXT statement:

RTEXT "Number of Messages", 4, 30, 50, 100, 10

See Also

CONTROL, CTEXT, DIALOG, LTEXT


SCROLLBAR Control

The SCROLLBAR statement creates a scroll-bar control. The control is a rectangle that contains a scroll box and has direction arrows at both ends. The scroll-bar control sends a notification message to its parent whenever the user clicks the mouse in the control. The parent is responsible for updating the scroll-box position. Scroll-bar controls can be positioned anywhere in a window and used whenever needed to provide scrolling input.

Syntax

SCROLLBAR text, id, x, y, width, height [, style [, extended-style]]

Parameters

style

Specifies a combination (or none) of the following styles: WS_TABSTOP, WS_GROUP, and WS_DISABLED.

In addition to these styles, the style parameter may contain a combination (or none) of the SCROLLBAR-class styles. The default style for SCROLLBAR is SBS_HORZ.

For more information on the text, id, x, y, width, height, style, and extended-style parameters, see Common Statement Parameters.

Example

The following example demonstrates the use of the SCROLLBAR statement:

SCROLLBAR 999, 25, 30, 10, 100


STATE3 Control

The STATE3 statement defines a three-state check box control. The control is identical to a CHECKBOX, except that it has three states: checked, unchecked, and disabled (grayed).

Syntax

STATE3 text, id, x, y, width, height [, style [, extended-style]]

Parameters

text

Specifies text that is displayed to the right of the control.

style

Specifies the control styles. This value can be a combination of the button class style BS_3STATE and the WS_TABSTOP and WS_GROUP styles.

If you do not specify a style, the default style is BS_3STATE and WS_TABSTOP.

For more information on the text, id, x, y, width, height, style, and extended-style parameters, see Common Statement Parameters.

See Also

AUTOCHECKBOX, CHECKBOX, CONTROL


STRINGTABLE Resource

The STRINGTABLE statement defines one or more string resources for an application. String resources are simply null-terminated Unicode strings that can be loaded when needed from the executable file, using the LoadString function.

Syntax

STRINGTABLE [load-mem]
[optional-statements]
BEGIN
    stringID string
    . . .
END

Parameter

load-mem

Specifies loading and memory attributes for the resource. For more information, see Common Resource Attributes.

optional-statements

Zero or more of the following statements:

Statement	Description
CHARACTERISTICS dword	User-defined information about a resource that can be used by tools that read and write resource files.
LANGUAGE language, sublanguage	Specifies the language for the resource. The parameters are constants from WINNLS.H.
VERSION dword	User-defined version number for the resource that can be used by tools that read and write resource files.
stringID

Specifies an unsigned 16-bit integer that identifies the resource.

string

Specifies one or more strings, enclosed in double quotation marks. The string must be no longer than 255 characters and must occupy a single line in the source file. To add a carriage return to the string, use this character sequence: \012. For example, "Line one\012Line two" would define a string that would be displayed as follows:

Line one
Line two

Remarks

Grouping strings in separate sections allows all related strings to be read in at one time and discarded together. When possible, an application should make the table movable and discardable. RC allocates 16 strings per section and uses the identifier value to determine which section is to contain the string. Strings with the same upper-12 bits in their identifiers are placed in the same section.

Example

The following example demonstrates the use of the STRINGTABLE statement:

#define IDS_HELLO    1
#define IDS_GOODBYE  2

STRINGTABLE
BEGIN
    IDS_HELLO,   "Hello"
    IDS_GOODBYE, "Goodbye"
END

See Also

LoadString, Multiline Statements, ACCELERATORS, CHARACTERISTICS, DIALOG, LANGUAGE, MENU, RCDATA, VERSION


STYLE Statement

The STYLE statement defines the window style of the dialog box. The window style specifies whether the box is a pop-up or a child window. The default style has the following attributes: WS_POPUP, WS_BORDER, and WS_SYSMENU.

Syntax

STYLE style

Parameter

style

Specifies the window style. This parameter takes an integer value or redefined name. The following lists the redefined styles:

DS_LOCALEDIT

Specifies that edit controls in the dialog box will use memory in the application's data section. By default, all edit controls in dialog boxes use memory outside the application's data section. This feature can be suppressed by adding the DS_LOCALEDIT flag to the STYLE command for the dialog box. If this flag is not used, EM_GETHANDLE and EM_SETHANDLE messages must not be used since the storage for the control is not in the application's data section. This feature does not affect edit controls created outside of dialog boxes.

DS_MODALFRAME

Creates a dialog box with a modal dialog box frame that can be combined with a title bar and System menu by specifying the WS_CAPTION and WS_SYSMENU styles.

DS_NOIDLEMSG

Suppresses WM_ENTERIDLE messages that Windows would otherwise send to the owner of the dialog box while the dialog box is displayed.

DS_SYSMODAL

Creates a system-modal dialog box.

WS_BORDER

Creates a window that has a border.

WS_CAPTION

Creates a window that has a title bar (implies the WS_BORDER style).

WS_CHILD

Creates a child window. It cannot be used with the WS_POPUP style.

WS_CHILDWINDOW

Creates a child window that has the WS_CHILD style.

WS_CLIPCHILDREN

Excludes the area occupied by child windows when drawing within the parent window. Used when creating the parent window.

WS_CLIPSIBLINGS

Clips child windows relative to each other; that is, when a particular child window receives a WM_PAINT message, this style clips all other top-level child windows out of the region of the child window to be updated. (If the WS_CLIPSIBLINGS style is not given and child windows overlap, it is possible, when drawing in the client area of a child window, to draw in the client area of a neighboring child window.) For use with the WS_CHILD style only.

WS_DISABLED

Creates a window that is initially disabled.

WS_DLGFRAME

Creates a window with a modal dialog box frame but no title.

WS_GROUP

Specifies the first control of a group of controls in which the user can move from one control to the next by using the arrow keys. All controls defined with the WS_GROUP style after the first control belong to the same group. The next control with the WS_GROUP style ends the style group and starts the next group (that is, one group ends where the next begins). This style is valid only for controls.

WS_HSCROLL

Creates a window that has a horizontal scroll bar.

WS_ICONIC

Creates a window that is initially iconic. For use with the WS_OVERLAPPED style only.

WS_MAXIMIZE

Creates a window of maximum size.

WS_MAXIMIZEBOX

Creates a window that has a Maximize box.

WS_MINIMIZE

Creates a window of minimum size.

WS_MINIMIZEBOX

Creates a window that has a Minimize box.

WS_OVERLAPPED

Creates an overlapped window. An overlapped window has a caption and a border.

WS_OVERLAPPEDWINDOW

Creates an overlapped window having the WS_OVERLAPPED, WS_CAPTION, WS_SYSMENU, WS_THICKFRAME, WS_MINIMIZEBOX, and WS_MAXIMIZEBOX styles.

WS_POPUP

Creates a pop-up window. It cannot be used with the WS_CHILD style.

WS_POPUPWINDOW

Creates a pop-up window that has the WS_POPUP, WS_BORDER, and WS_SYSMENU styles. The WS_CAPTION style must be combined with the WS_POPUPWINDOW style to make the System menu visible.

WS_SIZEBOX

Creates a window that has a size box. Used only for windows with a title bar or with vertical and horizontal scroll bars.

WS_SYSMENU

Creates a window that has a System-menu box in its title bar. Used only for windows with title bars. If used with a child window, this style creates a Close box instead of a System-menu box.

WS_TABSTOP

Specifies one of any number of controls through which the user can move by using the TAB key. The TAB key moves the user to the next control specified by the WS_TABSTOP style. This style is valid only for controls.

WS_THICKFRAME

Creates a window with a thick frame that can be used to size the window.

WS_VISIBLE

Creates a window that is initially visible. This applies to overlapping and pop-up windows. For overlapping windows, the y parameter is used as a parameter for the ShowWindow function.

WS_VSCROLL

Creates a window that has a vertical scroll bar.

Remarks

If the redefined names are used, you must include WINDOWS.H.


User-Defined Resource

A user-defined resource statement specifies a resource that contains application-specific data. The data can have any format and can be defined either as the content of a given file (if the filename parameter is given) or as a series of numbers and strings (if the raw-data block is given).

Syntax

nameID typeID [load-mem] filename

The filename specifies the name of a file containing the binary data of the resource. The contents of the file are included as the resource. RC does not interpret the binary data in any way. It is the programmer's responsibility to ensure that the data is properly aligned for the target computer architecture.

A user-defined resource can also be defined completely in the resource script using the syntax:

nameID typeID [load-mem]
BEGIN
    raw-data
END

Parameters

nameID

Specifies either a unique name or a 16-bit unsigned integer that identifies the resource.

typeID

Specifies either a unique name or a 16-bit unsigned integer that identifies the resource type. If a number is given, it must be greater than 255. The numbers 1 through 255 are reserved for existing and future redefined resource types.

load-mem

Specifies loading and memory attributes for the resource. For more information, see Common Resource Attributes.

filename

Specifies the name of the file that contains the resource data. The parameter must be a valid filename; it must be a full path if the file is not in the current working directory.

raw-data

Specifies raw data consisting of one or more integers or strings of characters. Integers can be specified in decimal, octal, or hexadecimal format. RC does not automatically append a terminating null character to a string. The string is a sequence of the specified ANSI (byte) characters unless explicitly qualified as a wide-character string with the L prefix. Strings in all resources other than RCDATA and user-defined resources are Unicode strings.

The block of data begins on a DWORD boundary, and RC performs no padding or alignment of data within the raw-data block. It is the programmer's responsibility to ensure the proper alignment of data within the block.

Example

The following example shows several user-defined statements:

array   MYRES   data.res
14      300     custom.res
18 MYRES2
BEGIN
  "Here is a data string\0", /* A string. Note: explicitly
                                null-terminated */
   1024,                     /* int        */
   0x029a,                   /* hex int    */
   0o733,                    /* octal int  */
   "\07"                     /* octal byte */
END


VERSION Statement

The VERSION statement allows the developer to specify version information about a resource that can be used by tools that read and write resource files. The specified dword value appears with the resource in the compiled .RES file. However, the value is not stored in the executable file and has no significance to Windows.

The VERSION statement appears before the BEGIN in an ACCELERATORS, DIALOG, MENU, RCDATA, or STRINGTABLE resource definition. The specified value applies only to that resource.

Syntax

VERSION dword

Parameter

dword

A user-defined doubleword value.

See Also

Multiline Statements, ACCELERATORS, CHARACTERISTICS, DIALOG, LANGUAGE, MENU, RCDATA, STRINGTABLE


VERSIONINFO Resource

The VERSIONINFO statement creates a version-information resource. The resource contains such information about the file as its version number, its intended operating system, and its original filename. The resource is intended to be used with the File Installation library functions.

Syntax

versionID VERSIONINFO fixed-info
BEGIN
    block-statement
    . . .
END

Parameters

versionID

Specifies the version-information resource identifier. This value must be 1.

fixed-info

Specifies the version information, such as the file version and the intended operating system. This parameter consists of the following statements:

FILEVERSION version

Specifies the binary version number for the file. The version consists of two 32-bit integers, defined by four 16-bit integers. For example, "FILEVERSION 3,10,0,61" is translated into two doublewords: 0x0003000a and 0x0000003d, in that order. Therefore, if version is defined by the doublewords dw1 and dw2, they need to appear in the FILEVERSION statement as follows: HIWORD(dw1), LOWORD(dw1), HIWORD(dw2), LOWORD(dw2).

PRODUCTVERSION version

Specifies the binary version number for the product with which the file is distributed. The version parameter is two 32-bit integers, defined by four 16-bit integers. For more information about version, see the FILEVERSION description.

FILEFLAGSMASK fileflagsmask

Specifies which bits in the FILEFLAGS statement are valid. If a bit is set, the corresponding bit in FILEFLAGS is valid.

FILEFLAGS fileflags

Specifies the Boolean attributes of the file. The fileflags parameter must be the combination of all the file flags that are valid at compile time. For Windows 3.1, this value is 0x3f.

FILEOS fileos

Specifies the operating system for which this file was designed. The fileos parameter can be one of the operating system values given in the Comments section.

FILETYPE filetype

Specifies the general type of file. The filetype parameter can be one of the file type values listed in the Comments section.

FILESUBTYPE subtype

Specifies the function of the file. The subtype parameter is zero unless the type parameter in the FILETYPE statement is VFT_DRV, VFT_FONT, or VFT_VXD. For a list of file subtype values, see the Comments section.

block-statement

Specifies one or more version-information blocks. A block can contain string information or variable information.

Remarks

To use the constants specified with the VERSIONINFO statement, the WINVER.H file (included in WINDOWS.H) must be included in the resource-definition file.

The following list describes the parameters used in the VERSIONINFO statement:

fileflags

Specifies a combination of the following values:

VS_FF_DEBUG

File contains debugging information or is compiled with debugging features enabled.

VS_FF_INFOINFERRED

File contains a dynamically created version-information resource. Some of the blocks for the resource may be empty or incorrect. This value is not intended to be used in version-information resources created by using the VERSIONINFO statement.

VS_FF_PATCHED

File has been modified and is not identical to the original shipping file of the same version number.

VS_FF_PRERELEASE

File is a development version, not a commercially released product.

VS_FF_PRIVATEBUILD

File was not built using standard release procedures. If this value is given, the StringFileInfo block must contain a PrivateBuild string.

VS_FF_SPECIALBUILD

File was built by the original company using standard release procedures but is a variation of the standard file of the same version number. If this value is given, the StringFileInfo block must contain a SpecialBuild string.

fileos

Specifies one of the following values:

Value	Description
VOS_UNKNOWN	Operating system for which the file was designed is unknown to Windows.
VOS_DOS	File was designed for MS-DOS.
VOS_NT	File was designed for Windows NT.
VOS_WINDOWS16	File was designed for Windows version 3.0 or later.
VOS_WINDOWS32	File was designed for 32-bit Windows.
VOS_DOS_WINDOWS16	File was designed for Windows version 3.0 or later running with MS-DOS.
VOS_DOS_WINDOWS32	File was designed for 32-bit Windows running with MS-DOS.
VOS_NT_WINDOWS32	File was designed for 32-bit Windows running with Windows NT.
The values 0x00002L, 0x00003L, 0x20000L and 0x30000L are reserved.

filetype

Specifies one of the following values:

Value	Description
VFT_UNKNOWN	File type is unknown to Windows.
VFT_APP	File contains an application.
VFT_DLL	File contains a dynamic-link library (DLL).
VFT_DRV	File contains a device driver. If the dwFileType member is VFT_DRV, the dwFileSubtype member contains a more specific description of the driver.
VFT_FONT	File contains a font. If the dwFileType member is VFT_FONT, the dwFileSubtype member contains a more specific description of the font.
VFT_VXD	File contains a virtual device.
VFT_STATIC_LIB	File contains a static-link library.
All other values are reserved for use by Microsoft.

subtype

Specifies additional information about the file type.

If the FILETYPE statement specifies VFT_DRV, this parameter can be one of the following values:

Value	Description
VFT2_UNKNOWN	Driver type is unknown to Windows.
VFT2_DRV_COMM	File contains a communications driver.
VFT2_DRV_PRINTER	File contains a printer driver.
VFT2_DRV_KEYBOARD	File contains a keyboard driver.
VFT2_DRV_LANGUAGE	File contains a language driver.
VFT2_DRV_DISPLAY	File contains a display driver.
VFT2_DRV_MOUSE	File contains a mouse driver.
VFT2_DRV_NETWORK	File contains a network driver.
VFT2_DRV_SYSTEM	File contains a system driver.
VFT2_DRV_INSTALLABLE	File contains an installable driver.
VFT2_DRV_SOUND	File contains a sound driver.
If the FILETYPE statement specifies VFT_FONT, this parameter can be one of the following values:

Value	Description
VFT2_UNKNOWN	Font type is unknown to Windows.
VFT2_FONT_RASTER	File contains a raster font.
VFT2_FONT_VECTOR	File contains a vector font.
VFT2_FONT_TRUETYPE	File contains a TrueType font.
If the FILETYPE statement specifies VFT_VXD, this parameter must be the virtual-device identifier included in the virtual-device control block.

All subtype values not listed here are reserved for use by Microsoft.

langID

Specifies one of the following language codes:

Code	Language	Code	Language
0x0401	Arabic	0x0415	Polish
0x0402	Bulgarian	0x0416	Brazilian Portuguese
0x0403	Catalan	0x0417	Rhaeto-Romanic
0x0404	Traditional Chinese	0x0418	Romanian
0x0405	Czech	0x0419	Russian
0x0406	Danish	0x041A	Croato-Serbian (Latin)
0x0407	German	0x041B	Slovak
0x0408	Greek	0x041C	Albanian
0x0409	U.S. English	0x041D	Swedish
0x040A	Castilian Spanish	0x041E	Thai
0x040B	Finnish	0x041F	Turkish
0x040C	French	0x0420	Urdu
0x040D	Hebrew	0x0421	Bahasa
0x040E	Hungarian	0x0804	Simplified Chinese
0x040F	Icelandic	0x0807	Swiss German
0x0410	Italian	0x0809	U.K. English
0x0411	Japanese	0x080A	Mexican Spanish
0x0412	Korean	0x080C	Belgian French
0x0413	Dutch	0x0C0C	Canadian French
0x0414	Norwegian − Bokml	0x100C	Swiss French
0x0810	Swiss Italian	0x0816	Portuguese
0x0813	Belgian Dutch	0x081A	Serbo-Croatian (Cyrillic)
0x0814	Norwegian − Nynorsk
charsetID

Specifies one of the following character-set identifiers:

Identifier	Character Set
0	7-bit ASCII
932	Windows, Japan (Shift − JIS X-0208)
949	Windows, Korea (Shift − KSC 5601)
950	Windows, Taiwan (GB5)
1200	Unicode
1250	Windows, Latin-2 (Eastern European)
1251	Windows, Cyrillic
1252	Windows, Multilingual
1253	Windows, Greek
1254	Windows, Turkish
1255	Windows, Hebrew
1256	Windows, Arabic
string-name

Specifies one of the following redefined names:

Comments

Specifies additional information that should be displayed for diagnostic purposes.

CompanyName

Specifies the company that produced the file—for example, "Microsoft Corporation" or "Standard Microsystems Corporation, Inc." This string is required.

FileDescription

Specifies a file description to be presented to users. This string may be displayed in a list box when the user is choosing files to install—for example, "Keyboard Driver for AT-Style Keyboards" or "Microsoft Word for Windows". This string is required.

FileVersion

Specifies the version number of the file—for example, "3.10" or "5.00.RC2". This string is required.

InternalName

Specifies the internal name of the file, if one exists—for example, a module name if the file is a dynamic-link library. If the file has no internal name, this string should be the original filename, without extension. This string is required.

LegalCopyright

Specifies all copyright notices that apply to the file. This should include the full text of all notices, legal symbols, copyright dates, and so on—for example, "Copyright© Microsoft Corporation 1990−1992". This string is optional.

LegalTrademarks

Specifies all trademarks and registered trademarks that apply to the file. This should include the full text of all notices, legal symbols, trademark numbers, and so on—for example, "Windows™ is a trademark of Microsoft® Corporation". This string is optional.

OriginalFilename

Specifies the original name of the file, not including a path. This information enables an application to determine whether a file has been renamed by a user. The format of the name depends on the file system for which the file was created. This string is required.

PrivateBuild

Specifies information about a private version of the file—for example, "Built by TESTER1 on \TESTBED". This string should be present only if the VS_FF_PRIVATEBUILD flag is set in the dwFileFlags member of the VS_FIXEDFILEINFO structure of the root block.

ProductName

Specifies the name of the product with which the file is distributed—for example, "Microsoft Windows". This string is required.

ProductVersion

Specifies the version of the product with which the file is distributed—for example, "3.10" or "5.00.RC2". This string is required.

SpecialBuild

Specifies how this version of the file differs from the standard version—for example, "Private build for TESTER1 solving mouse problems on M250 and M250E computers". This string should be present only if the VS_FF_SPECIALBUILD flag is set in the dwFileFlags member of the VS_FIXEDFILEINFO structure in the root block.

A string information block has the following form:

BLOCK "StringFileInfo"
BEGIN
    BLOCK "lang-charset"
    BEGIN
        VALUE "string-name", "value"
            . . .
    END
END

Following are the parameters in the StringFileInfo block:

lang-charset

Specifies a language and character-set identifier pair. It is a hexadecimal string consisting of the concatenation of the language and character-set identifiers listed earlier in this section.

string-name

Specifies the name of a value in the block and can be one of the redefined names listed earlier in this section.

value

Specifies, as a character string, the value of the corresponding string name. More than one VALUE statement can be given.

A variable information block has the following form:

BLOCK "VarFileInfo"
BEGIN
    VALUE "Translation",
        langID, charsetID
            . . .
END

Following are the parameters in the variable information block:

langID

Specifies one of the language identifiers listed earlier in this section.

charsetID

Specifies one of the character-set identifiers listed earlier in this section. More than one identifier pair can be given, but each pair must be separated from the preceding pair with a comma.


Preprocessing Reference

The syntax and semantics for the RC preprocessor are the same as for the preprocessor in a C compiler. Single-line comments begin with two forward slashes (//) and run to the end of the line. Block comments begin with an opening delimiter (/*) and run to a closing delimiter (*/). Comments do not nest.

You use the #define directive to define symbols for your resource identifiers in a header file. You include this header both in the resource script and your application source code. Similarly, the values for attributes and styles are defined by including the C header files for Windows.

You can also define macros. The standard C preprocessing operators (#, ##) can be used in a macro definition. For detailed information on preprocessing and defining macros, see your C compiler documentation.

The rest of this section describes each of the preprocessing directives in alphabetical order.


#define

The #define directive assigns the given value to the specified name. All subsequent occurrences of the name are replaced by the value.

Syntax

#define name value

Parameters

name

Specifies the name to be defined. This value is any combination of letters, digits, and punctuation.

value

Specifies any integer, character string, or line of text.

Example

This example assigns values to the names "NONZERO" and "USERCLASS":

#define     NONZERO     1
#define     USERCLASS   "MyControlClass"

See Also

#ifdef, #ifndef, #undef


#elif

The #elif directive marks an optional clause of a conditional-compilation block defined by a #ifdef, #ifndef, or #if directive. The directive controls conditional compilation of the resource file by checking the specified constant expression. If the constant expression is nonzero, #elif directs the compiler to continue processing statements up to the next #endif, #else, or #elif directive and then skip to the statement after #endif. If the constant expression is zero, #elif directs the compiler to skip to the next #endif, #else, or #elif directive. You can use any number of #elif directives in a conditional block.

Syntax

#elif constant-expression

Parameter

constant-expression

Specifies the expression to be checked. This value is a defined name, an integer constant, or an expression consisting of names, integers, and arithmetic and relational operators.

Example

In this example, #elif directs the compiler to process the second BITMAP statement only if the value assigned to the name "Version" is less than 7. The #elif directive itself is processed only if Version is greater than or equal to 3.

#if Version < 3
BITMAP 1 errbox.bmp
#elif Version < 7
BITMAP 1 userbox.bmp
#endif

See Also

#else, #endif, #if, #ifdef, #ifndef


#else

The #else directive marks an optional clause of a conditional-compilation block defined by a #ifdef, #ifndef, or #if directive. The #else directive must be the last directive before the #endif directive.

This directive has no arguments.

Syntax

#else

Example

This example compiles the second BITMAP statement only if the name "DEBUG" is not defined:

#ifdef DEBUG
    BITMAP 1 errbox.bmp
#else
    BITMAP 1 userbox.bmp
#endif

See Also

#elif, #endif, #if, #ifdef, #ifndef


#endif

The #endif directive marks the end of a conditional-compilation block defined by a #ifdef directive. One #endif is required for each #if, #ifdef, or #ifndef directive.

Syntax

#endif

This directive has no arguments.

See Also

#elif, #else, #if, #ifdef, #ifndef


#if

The #if directive controls conditional compilation of the resource file by checking the specified constant expression. If the constant expression is nonzero, #if directs the compiler to continue processing statements up to the next #endif, #else, or #elif directive and then skip to the statement after the #endif directive. If the constant expression is zero, #if directs the compiler to skip to the next #endif, #else, or #elif directive.

Syntax

#if constant-expression

Parameter

constant-expression

Specifies the expression to be checked. This value is a defined name, an integer constant, or an expression consisting of names, integers, and arithmetic and relational operators.

Example

This example compiles the BITMAP statement only if the value assigned to the name "Version" is less than 3:

#if Version < 3
BITMAP 1 errbox.bmp
#endif

See Also

#elif, #else, #endif, #ifdef, #ifndef


#ifdef

The #ifdef directive controls conditional compilation of the resource file by checking the specified name. If the name has been defined by using a #define directive or by using the /d command-line option with the Resource Compiler, #ifdef directs the compiler to continue with the statement immediately after the #ifdef directive. If the name has not been defined, #ifdef directs the compiler to skip all statements up to the next #endif directive.

Syntax

#ifdef name

Parameter

name

Specifies the name to be checked by the directive.

Example

This example compiles the BITMAP statement only if the name "Debug" is defined:

#ifdef Debug
BITMAP 1 errbox.bmp
#endif

See Also

#define, #endif, #if, #ifndef, #undef


#ifndef

The #ifndef directive controls conditional compilation of the resource file by checking the specified name. If the name has not been defined or if its definition has been removed by using the #undef directive, #ifndef directs the compiler to continue processing statements up to the next #endif, #else, or #elif directive and then skip to the statement after the #endif directive. If the name is defined, #ifndef directs the compiler to skip to the next #endif, #else, or #elif directive.

Syntax

#ifndef name

Parameter

name

Specifies the name to be checked by the directive.

Example

This example compiles the BITMAP statement only if the name "Optimize" is not defined:

#ifndef Optimize
BITMAP 1 errbox.bmp
#endif

See Also

#elif, #else, #endif, #if, #ifdef, #undef


#include

The #include directive causes Resource Compiler to process the file specified in the filename parameter. This file should be a header file that defines the constants used in the resource-definition file.

Syntax

#include filename

Parameter

filename

Specifies the name of the file to be included. If the file is in the current directory, the string must be enclosed in double quotation marks; if the file is in the directory specified by the INCLUDE environment variable, the string must be enclosed in less-than and greater-than characters (<>). You must give a full path enclosed in double quotation marks (") if the file is not in the current directory or in the directory specified by the INCLUDE environment variable.

Example

This example processes the header files WINDOWS.H and HEADERS\MYDEFS.H while compiling the resource-definition file:

#include <windows.h>
#include "headers\mydefs.h"

See Also

#define


#undef

The #undef directive removes the current definition of the specified name. All subsequent occurrences of the name are processed without replacement.

Syntax

#undef name

Parameter

name

Specifies the name to be removed. This value is any combination of letters, digits, and punctuation.

Example

This example removes the definitions for the names "nonzero" and "USERCLASS":

#undef     nonzero
#undef     USERCLASS

See Also

#define


RC Diagnostic Messages

This section contains descriptions of diagnostic messages produced by the Microsoft Resource Compiler (RC) for Windows NT. Many of these messages appear when RC is not able to compile resources properly. The descriptions clarify the cause of each message. The messages are listed in alphabetic order.

A capital V in parentheses (V) at the beginning of a message description indicates that the message is displayed only if RC is run with the /v (verbose) option. These messages are generally informative and do not necessarily indicate errors.


A

Accelerator Type required (ASCII or VIRTKEY)

The type parameter in the ACCELERATORS statement must contain either the ASCII or VIRTKEY value.


B

BEGIN expected in Accelerator Table

An ACCELERATORS statement was not followed by the BEGIN keyword.

BEGIN expected in Dialog

A DIALOG statement was not followed by the BEGIN keyword.

BEGIN expected in menu

A MENU statement was not followed by the BEGIN keyword.

BEGIN expected in RCData

An RCDATA statement was not followed by the BEGIN keyword.

BEGIN expected in String Table

A STRINGTABLE statement was not followed by the BEGIN keyword.

BEGIN expected in VERSIONINFO resource

A VERSIONINFO statement was not followed by the BEGIN keyword.

Bitmap file resource-file is not in version-number format.

Use Microsoft Image Editor (IMAGEDIT.EXE) to convert old resource files to the current format.


C

Cannot Re-use String Constants

You are using the same value twice in a STRINGTABLE statement. Make sure that you have not mixed overlapping decimal and hexadecimal values.

Control Character out of range [A − Z]

A control character in the ACCELERATORS statement is invalid. The character following the caret (^) must be in the range A through Z.

Could not find RCPP.EXE

The preprocessor (RCPP.EXE) must be in the current directory or in a directory specified in the PATH environment variable.

Could not open in-file-name

Microsoft Windows Resource Compiler (RC) could not open the specified file. Make sure that the file exists and that you typed the filename correctly.

Couldn't open resource-name

Microsoft Windows Resource Compiler (RC) could not open the specified file. Make sure that the file exists and that you typed the filename correctly.

Creating resource-name

(V) Microsoft Windows Resource Compiler (RC) is creating a new binary resource (.RES) file.


E

Empty menus not allowed

An END keyword appears before any menu items are defined in the MENU statement. Empty menus are not permitted by Microsoft Windows Resource Compiler (RC). Make sure that you do not have any opening quotation marks within the MENU statement.

END expected in Dialog

The END keyword must appear at the end of a DIALOG statement. Make sure that there are no opening quotation marks left from the preceding statement.

END expected in menu

The END keyword must appear at the end of a MENU statement. Make sure that there are no mismatched BEGIN and END statements.

Error Creating resource-name

Microsoft Windows Resource Compiler (RC) could not create the specified binary resource (.RES) file. Make sure that it is not being created on a read-only drive. Use the /v option to find out whether the file is being created.

Expected Comma in Accelerator Table

Microsoft Windows Resource Compiler (RC) requires a comma between the event and idvalue parameters in the ACCELERATORS statement.

Expected control class name

The class parameter of a CONTROL statement in the DIALOG statement must be one of the following control types: BUTTON, COMBOBOX, EDIT, LISTBOX, SCROLLBAR, STATIC, or user-defined. Make sure that the class is spelled correctly.

Expected font face name

The typeface parameter of the FONT statement in the DIALOG statement must be a character string enclosed in double quotation marks ("). This parameter specifies the name of a font.

Expected ID value for Menuitem

The MENU statement must contain a MENUITEM statement, which has either an integer or a symbolic constant in the MenuID parameter.

Expected Menu String

Each MENUITEM and POPUP statement must contain a text parameter. This parameter is a string enclosed in double quotation marks (") that specifies the name of the menu item or pop-up menu. A MENUITEM SEPARATOR statement requires no quoted string.

Expected numeric command value

Microsoft Windows Resource Compiler (RC) was expecting a numeric idvalue parameter in the ACCELERATORS statement. Make sure that you have used a #define constant to specify the value and that the constant used is spelled correctly.

Expected numeric constant in string table

A numeric constant, defined in a #define statement, must immediately follow the BEGIN keyword in a STRINGTABLE statement.

Expected numeric point size

The pointsize parameter of the FONT statement in the DIALOG statement must be an integer point-size value.

Expected Numerical Dialog constant

A DIALOG statement requires integer values for the x, y, width, and height parameters. Make sure that these values, which are included after the DIALOG keyword, are not negative.

Expected String in STRINGTABLE

A string is expected after each numeric stringid parameter in a STRINGTABLE statement.

Expected String or Constant Accelerator command

Microsoft Windows Resource Compiler (RC) was not able to determine which key was being set up for the accelerator. The event parameter in the ACCELERATORS statement might be invalid.

Expected VALUE, BLOCK, or END keyword.

The VERSIONINFO structure requires a VALUE, BLOCK, or END keyword.

Expecting number for ID

A number is expected for the id parameter of a CONTROL statement in the DIALOG statement. Make sure that you have a number or a #define statement for the control identifier.

Expecting quoted string for key

The key string following the BLOCK or VALUE keyword should be enclosed in double quotation marks.

Expecting quoted string in dialog class

The class parameter of the CLASS statement in the DIALOG statement must be an integer or a string enclosed in double quotation marks (").

Expecting quoted string in dialog title

The captiontext parameter of the CAPTION statement in the DIALOG statement must be a character string, enclosed in double quotation marks (").


F

File not found: filename

The file specified in the rc command was not found. Make sure that the file has not been moved to another directory and that the filename or path is typed correctly.

Font names must be ordinals

The pointsize parameter in the FONT statement must be an integer, not a string.


I

Insufficient memory to spawn RCPP.EXE

There wasn't enough memory to run the preprocessor (RCPP.EXE).

Invalid Accelerator

An event parameter in the ACCELERATORS statement was not recognized or was more than two characters long.

Invalid Accelerator Type (ASCII or VIRTKEY)

The type parameter in the ACCELERATORS statement must contain either the ASCII or VIRTKEY value.

Invalid control character

A control character in the ACCELERATORS statement is invalid. A valid control character consists of a caret (^) followed by a single letter.

Invalid Control type

The CONTROL statement in a DIALOG statement must be one of the following: AUTO3STATE, AUTOCHECKBOX, AUTORADIOBUTTON, CHECKBOX, COMBOBOX, CONTROL, CTEXT, DEFPUSHBUTTON, EDITTEXT, GROUPBOX, ICON, LISTBOX, LTEXT, PUSHBOX, PUSHBUTTON, RADIOBUTTON, RTEXT, SCROLLBAR, STATE3.

Invalid directive in preprocessed RC file

The specified filename has an embedded newline character.

Invalid .EXE file

The executable (.EXE) file is invalid. Make sure that the linker created it correctly and that the file exists.

Invalid switch, option

An option used was invalid. For a list of the command-line options, use the rc /? command.

Invalid switch, too many -D switches

Too many -d options were specified. To define a large number of symbols, use the #include directive to include a file of definitions.

Invalid type

The resource type was not among the types defined in the include file.

Invalid usage. Use RC -? for Help

Make sure that you have at least one filename to work with. For a list of the command-line options, use the rc -? command.

I/O error reading file

Read failed. Since this is a generic routine, no specific filename is supplied.

I/O error seeking in file

Seeking in file failed. Since this is a generic routine, no specific filename is supplied.

I/O error writing file

Write failed. Since this is a generic routine, no specific filename is supplied.


N

No resource binary filename specified.

The /fo option was used, but no binary resource (.RES) file was specified.


O

Old DIB in resource-name. Pass it through IMAGEDIT.

The resource file specified is not compatible with Win32. Make sure you have read and saved this file using the latest version of Microsoft Image Editor (IMAGEDIT.EXE).

Out of heap memory

There was not enough memory.

Out of memory, needed n bytes

Microsoft Windows Resource Compiler (RC) was not able to allocate the specified amount of memory.


R

Redefinition of Button Type

The specified button styles conflict with or modify the style specified by the control keyword. This is a warning only and may be ignored.

The following common method of declaring an automatic radio button generates this warning:

RADIOBUTTON "&Italic", MYRB_ITALIC, 10, 10, 30, 12, BS_AUTORADIOBUTTON

To avoid the warning, use the control statement appropriate for the type of button that you want to define. In this example, the corrected statement is:

AUTORADIOBUTTON "&Italic", MYRB_ITALIC, 10, 10, 30, 12

RC: Invalid switch: option

An option used was invalid. For a list of the command-line options, use the rc /? command.

RC: RCPP.ERR not found

The RCPP.ERR file must be in the current directory or in a directory specified in the PATH environment variable.

RC terminated by user

A CTRL+C key combination was pressed, exiting Microsoft Windows Resource Compiler (RC).

RC terminating after preprocessor errors

For information about preprocessor errors, see the documentation for the preprocessor.

RCPP.EXE is not a valid executable

The preprocessor (RCPP.EXE) may have been altered. Try copying the file again from the Microsoft Windows Software Development Kit (SDK) disks.

Resource file resource-name is not in version-number format.

Make sure your icons and cursors have been read and saved using the latest version of Microsoft Image Editor (IMAGEDIT.EXE).


T

Text string or ordinal expected in Control

The text parameter of a CONTROL statement in the DIALOG statement must be either a text string or an ordinal reference to the type of control that is expected. If using an ordinal, make sure that you have a #define statement for the control.


U

Unable to create destination

Microsoft Windows Resource Compiler (RC) was not able to create the destination file. Make sure that there is enough disk space.

Unbalanced Parentheses

Make sure that you have closed every opening parenthesis in the DIALOG statement.

Unexpected value in RCData

The values for the raw-data parameter in the RCDATA statement must be integers or strings, separated by commas. Make sure that you did not leave out a comma or a quotation mark around a string.

Unexpected value in value data

A statement contained information with a format or size different from the expected value for that parameter.

Unknown DIB header format

The device-independent bitmap (DIB) header is not a BITMAPCOREHEADER or BITMAPINFOHEADER structure.

Unknown error spawning RCPP.EXE

For an unknown reason, the preprocessor (RCPP.EXE) has not started. Try copying the file again from the distribution disks.

Unknown Menu SubType

The item-definitions parameter of the MENU statement can contain only MENUITEM and POPUP statements.

Unrecognized VERSIONINFO field; BEGIN or comma expected

The format of the information following a VERSIONINFO statement is incorrect.


V

Version WORDs separated by commas expected

Values in an information block for a VERSIONINFO statement should be separated by commas.


W

Warning: ASCII character not equivalent to virtual key code

An invalid virtual-key code exists in the ACCELERATORS statement. The ASCII values for some characters such as *, ^, or & are not equivalent to the virtual-key codes for the corresponding keys. In the case of the asterisk (*), the virtual-key code is equivalent to the ASCII value for 8, the numeric character on the same key. Therefore, the statement VIRTKEY '*' is invalid.

Warning: SHIFT or CONTROL used without VIRTKEY

The ALT, SHIFT, and CONTROL options apply only to virtual keys in the ACCELERATORS statement. Make sure that the VIRTKEY option is used with one of these other options.

Writing resource type image lang:language size:size

(V) Microsoft Windows Resource Compiler (RC) is writing the specified resource. The type is the resource type. It may be a number or a string. The image can be a number or a string. The language is the national language of the resource. The size is the decimal size of the resource in bytes.


Compiling Messages

The Microsoft Windows Message Compiler (MC) is a tool for the Microsoft Windows NT operating system. This section describes how to create a message text file, and how to compile it for inclusion in a resource script.


 About the Message Compiler

The Message Compiler (MC.EXE) converts message text files into binary files suitable for inclusion in a resource script (.RC file). The Resource Compiler is then used to place the messages into a resource for inclusion in an application or DLL.

Applications that perform event logging typically use an independent resource-only DLL that contains the messages, rather than carry the messages in the application image.


 Using the Message Compiler

The Message Compiler utility has the following command-line syntax:

Syntax

MC [-v] [-w] [-s] [-d] [-h dir] [-e extension] [-r dir] filename[.MC]...

Parameters

-v

Generates verbose output to stderr.

-w

Generates a warning message whenever an insert escape sequence is seen that is a superset of the type supported by the OS/2 MKMSGF utility. These are any escape sequences other than %0 and %n. This option is useful for converting MKMSGF message files to MC format.

-s

Adds an extra line to the beginning of each message that is the symbolic name associated with the message identifier.

-d

Ouputs Severity and Facility constants in decimal. Sets the initial output radix for messages to decimal.

-h dirs

Specifies the target directory of the generated include file. The include-file name is the base name of the .MC file with a .H extension.

-e extension

Specifies the extension for the header file, which can be from one to three characters. The default is .H.

-r dir

Specifies the target directory of the generated Resource Compiler script (.RC file). The script file name is the base name of the .MC file with a .RC extension.

filename[.MC]

Specifies one or more input message files that is compiled into one or more binary resource files, one for each language specified in the Message Compiler source files.

The Message Compiler reads the source file and generates a C/C++ include file containing definitions for the symbolic names. For each LanguageId statement, MC generates a binary file containing a message table resource. It also generates a single RC script file that contains the appropriate Resource Compiler statements to include each binary output file as a resource with the appropriate symbolic name and language type.


Message Compiler Source Files

Message Compiler source files (default extension .MC) are converted into binary resource files by the Message Compiler (MC.EXE). The binary resources are then passed to the Resource Compiler which puts them in the resource table for an application or DLL. For applications performing event logging, the messages are typically placed in a DLL that contains nothing but the message table. This DLL is registered by the application as the source of message text for the events that it logs. The application then uses the event logging functions or the FormatMessage function to retrieve and use the message text.

Messages are defined using ASCII text in a text file. The Message Compiler source-format supports multiple versions of the same message text, one for each national language supported by your application. The Message Compiler automatically assigns numbers to each message, and generates a C/C++ include file for use by the application to access a message using a symbolic constant. The purpose of the message text file is to define all of the messages needed by an application, in a format that makes it easy to support multiple languages with the same image file.


Message Source File General Syntax

The general syntax for lines in the message source file is:

keyword=value

Spaces around the equal sign are ignored, and the value is delimited by white space (including line breaks) from the next keyword=value pair. Case is ignored when comparing against keyword names. The value portion can be a numeric integer constant using C/C++ syntax; a symbol name that follows the rules for C/C++ identifiers; or a file name that follows the rules for the base name of a file with the FAT file system (eight characters or less, with no periods).


Message Source File Comments

Comment lines are allowed in the source file. A semicolon (;) begins a comment that ends at the end of the line. A comment by itself on a line is copied to the generated include file with the semicolon converted to the C++ line-comment delimiter (//).


 Header Section

The overall structure of a message text file consists of a header which defines names and language identifiers for use by the message definitions in the body of the file. The header contains zero or more of the following statements:

MessageIdTypedef = [type]
SeverityNames = (name=number[:name])
FacilityNames = (name=number[:name])
LanguageNames = (name=number:filename)
OutputBase = {number}

These keywords have the following meaning:

MessageIdTypedef = type

Gives a typedef name that is used in a type cast for each message code in the generated include file. Each message code appears in the include file with the format:

#define name ((type) 0xnnnnnnnn)

The default value for type is empty, and no type cast is generated. It is the programmer's responsibility to specify a typedef statement in the application source code to define the type. The type used in the typedef must be large enough to accommodate the entire 32-bit message code.

SeverityNames = (name=number[:name])

Defines the set of names that are allowed as the value of the Severity keyword in the message definition. The set is delimited by left and right parentheses. Associated with each severity name is a number that, when shifted left by 30, gives the bit pattern to logical-OR with the Facility value and MessageId value to form the full 32-bit message code.

The default value of this keyword is:

SeverityNames=(
    Success=0x0
    Informational=0x1
    Warning=0x2
    Error=0x3
    )

Severity values occupy the high two bits of a 32-bit message code. Any severity value that does not fit in two bits is an error. The severity codes can be given symbolic names by following each value with :name

FacilityNames = (name=number[:name])

Defines the set of names that are allowed as the value of the Facility keyword in the message definition. The set is delimited by left and right parentheses. Associated with each facility name is a number that, when shifted left by 16 bits, gives the bit pattern to logical-OR with the Severity value and MessageId value to form the full 32-bit message code.

The default value of this keyword is:

FacilityNames=(
    System=0x0FF
    Application=0xFFF
    )

Facility codes occupy the low-order 12 bits of the high-order 16 bits of a 32-bit message code. Any facility code that does not fit in 12 bits is an error. This allows for 4096 facility codes. The first 256 codes are reserved for use by the system software. The facility codes can be given symbolic names by following each value with :name

LanguageNames = (name=number:filename)

Defines the set of names that are allowed as the value of the Language keyword in the message definition. The set is delimited by left and right parentheses. Associated with each language name are a number and a file name that are used to name the generated resource file that contains the messages for that language. The number corresponds to the language identifier to use in the resource table. The number is separated from the file name by a colon.

The initial value of LanguageNames is:

LanguageNames=(English=1:MSG00001)

Any new names in the source file which don't override the built-in names are added to the list of valid languages. This allows an application to support private languages with descriptive names.

OutputBase = {number}

Sets the output radix for the message constants output to the C/C++ include file. It does not set the radix for the Severity and Facility constants; these default to HEX, but can be output in decimal by using the -d switch. If present, OutputBase overrides the -d switch for message constants in the include file.

The legal values for number are 10 and 16.

You can use OutputBase in both the header section and the message definition section of the input file. You can change OutputBase as often as you like.


Message Definitions

Following the header section is the body of the Message Compiler source file. The body consists of zero or more message definitions. Each message definition begins with one or more of the following statements.

MessageId = [number|+number]
Severity = severity_name
Facility = facility_name
SymbolicName = name
OutputBase = {number}

The MessageId statement marks the beginning of the message definition. A MessageID statement is required for each message, although the value is optional. If no value is specified, the value used is the previous value for the facility plus one. If the value is specified as +number then the value used is the previous value for the facility, plus the number after the plus sign. Otherwise, if a numeric value is given, that value is used. Any MessageId value that does not fit in 16 bits is an error.

The Severity and Facility statements are optional. These statements specify additional bits to OR into the final 32-bit message code. If not specified they default to the value last specified for a message definition. The initial values prior to processing the first message definition are:

Severity=Success
Facility=Application

The value associated with Severity and Facility must match one of the names given in the FacilityNames and SeverityNames statements in the header section.

The SymbolicName statement allows you to associate a C/C++ symbolic constant with the final 32-bit message code.

The constant definition in the generated include file has the format:

//
// message text
//

#define name ((type) 0xnnnnnnnn)

The comment before the definition is a copy of the message text for the first language specified in the message definition. The name is the value given in the SymbolicName statement. The type is the type name specified in the MessageIdTypedef statement. If no type was specified, the cast is not generated.

The following comment appears in each header file to explain the bit fields in the 32-bit message:

//  Values are 32 bit values laid out as follows:
//
//   3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
//   1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
//  +---+-+-+-----------------------+-------------------------------+
//  |Sev|C|R|     Facility          |               Code            |
//  +---+-+-+-----------------------+-------------------------------+
//

The meanings of the fields in the message code are:

Sev

The severity code:

Bits	Meaning
00	Success
01	Informational
10	Warning
11	Error
C

The Customer code flag.

R

A reserved bit.

Facility

The facility code.

Code

The status code for the facility.

The OutputBase statement lets you set the output radix for the message constants output to the C/C++ include file. It does not set the radix for the Severity and Facility constants; these default to HEX, but can be output in decimal by using the -d switch. If present, OutputBase overrides the -d switch for message constants in the include file.

The legal values for number are 10 and 16

You can use OutputBase in both the header section and the message definition section of the input file. You can change OutputBase as often as you like.


Language-Specific Message Text Definitions

After the message definition statements, you specify one or more message text definitions.

Syntax

Language=language_name
messagetext
.

Each message begins with a Language statement that identifies the binary output file for this message. The first line of the message text begins with the next line. The message text is terminated by a line containing a single period at the beginning of the line, immediately followed by a new line. No spaces are allowed around the terminating period. Within the message, blank lines and white space are preserved as part of the message.

You can specify several escape sequences for formatting the message when the message text is used by the application or an event viewer. The percent sign character (%) begins all escape sequences.

%0

Terminates a message text line without a trailing newline. This can be used to build up long lines or to terminate the message without a trailing newline, which is useful for prompt messages.

%n[!printf-format-specifier!]

Identifies an insert. Each insert refers to a parameter used in a call to the FormatMessage function. FormatMessage returns an error if the message text specifies an insert that was not passed to FormatMessage.

The value of n can be between 1 and 99. The printf format specifier must be enclosed in exclamation marks. It is optional and defaults to !s! if not specified.

The printf format specifier can contain the * specifier for either the precision or width components. When specified, they consume inserts numbered n+1 and n+2 for their values at run time. MC prints a warning message if these inserts are specified elsewhere in the message text.

Any character following a percent sign other than a digit is formatted in the output message without the percent sign.

You can specify the following additional escape sequences:

%%

Generates a single percent sign in the formatted message text.

%\

Generates a hard line break when it occurs at the end of a line. Useful when FormatMessage is supplying normal line breaks so the message fits in a certain width.

%r

Generates a hard carriage return, without a trailing newline character.

%b

Generates a space character in the formatted message text. This can be used to ensure there are the appropriate number of trailing spaces in a message text line.

%.

Generates a single period in the formatted message text. This can be used to get a period at the beginning of a line without terminating the message definition.

%!

Generates a single exclamation point in the formatted message text. This can be used to specify an exclamation point immediately after an insert.


Creating Dialog Boxes

The Dialog Editor automates the process of creating dialog boxes. You can see your dialogs as you design them without writing and compiling your own resource scripts.

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

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

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


Using the Dialog Editor

The following topics describe how to design, test, and include dialogs in your application.

Note  The Dialog Editor requires a mouse or equivalent pointing device.


Creating a New Dialog

To create your application's dialog

1.	Start the Dialog Editor from its group icon in the Program Manager.

2.	From the File menu, choose New.

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

•	Dlg. Sym., for your symbolic dialog name

•	Caption, for your dialog title

•	A dialog ID field

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

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

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

To design dialogs using your application as a backdrop

1.	Start your application.

2.	Start the Dialog Editor.

3.	Move the dialog you are designing outside the Dialog Editor window.

4.	Reduce the Dialog Editor window in size and move it to a corner of the display.

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


Adding a Control

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

To add a control to the dialog

1.	In the Toolbox, click one of the control icons.

2.	Click in the dialog.

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

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

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


Symbolic Names and ID Numbers

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

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

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

To enter a zero-terminated string as a dialog designator

1.	Type the string in the Dlg. Sym. edit field.

2.	Immediately tab to the field on the right (the Dialog ID edit field).

3.	Delete the integer ID.

4.	Press ENTER.

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

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


The IDOK, IDCANCEL, and UNUSED Symbols

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

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

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

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

You can use the Symbols command on the Edit menu to display and edit the current symbols. The Symbols dialog box displays a list box of symbols and corresponding IDs. You can add, change, and delete symbols in the Symbols dialog box.

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

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

To assign other text to the button

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

2.	Press ENTER.

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

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

•	Check box

•	Push button

•	Radio button

•	Text

•	Custom controls written to support this feature

To size a control to its text

1.	Select the control.

2.	From the Edit menu choose the Size to Text command, or press F7.

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


Adding More Controls

Dialog boxes often include more than one control — push buttons, list boxes, and check boxes are common. This section shows you how to add controls and how to edit and organize these controls.


Duplicating a Control

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

To add another push button

1.	Hold down the CTRL key.

2.	Drag the existing push button to a new location and drop it.

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

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


Adding a List Box

Now add a list box to the dialog, clicking its icon in the Toolbox (fourth row, second column) and dropping it into the dialog box. A list box is a box of text strings with a scrollbar on its right side.

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


Adding Custom Controls

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

The code that defines a custom control resides in either a DLL or, occasionally, in the .EXE file that calls the dialog box. For information about creating custom controls, see the Microsoft Windows 3 Developer's Workshop, by Richard Wilton.

The Dialog Editor supports custom-control DLLs and temporary custom controls, as described in the following table:

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

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

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

To add a new temporary custom control

1.	From the File menu, choose New Custom. The New Temporary Custom Control dialog box appears.

2.	Type a name for the custom control in the Class Name edit field.

3.	Optionally, change the other Control Defaults.

4.	Choose OK.

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

To add a custom control

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

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

2.	From the Available Controls list box, select the custom control you want to add to the dialog box.

3.	Choose OK.

4.	Move the cursor into the dialog. A rectangle with the "move" icon inside replaces the cursor.

5.	Press and hold the mouse button to see an outline of the control. The coordinates for the location of the control are displayed in the Properties Bar.

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

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


Editing Groups of Controls

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

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

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


The Anchor Control

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


Sizing and Aligning a Group

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

1.	From the Arrange menu, choose the Same Size command.

2.	Click the top option to make the buttons the same width.

3.	Choose the Same Size command again.

4.	Click the bottom option to make the buttons the same height.

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

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


Ordering Controls

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

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


Changing Control Tabbing Order

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

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

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

1.	Select the list box control from the list in the Order/Group dialog box by clicking its title once with the mouse.

2.	Move the mouse pointer to the start of the list. The mouse pointer changes shape at a valid insertion point.

3.	Click to reposition the list box.


Making Groups

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

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

To make and order a group of controls

1.	From the Arrange menu, choose Order/Group. This brings up the Order/Group dialog box.

2.	In the control list box, click the first control you want in a particular group.

3.	Drag the mouse up or down to select the other controls in the group.

4.	Choose Make Group.

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

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


Changing Control Size and Placement

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

•	Align controls along an edge (Align command)

•	Distribute controls evenly with respect to an anchor control (Even Spacing command)

•	Set controls to the same size (Same Size command)

•	Distribute push buttons evenly along the bottom or side of the dialog (Push Buttons command)

•	Change grid and spacing values for editing controls (Settings command)

You might want to experiment with these commands in the dialog you have just created. Click the Arranging icon in Help for more information about these commands.


Testing Your Dialog

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

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

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

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


Dialog and Control Styles

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

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

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


Designing Multiple Dialogs for an Application

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

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

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

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

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

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


Including Dialogs in an Application

When you save a dialog or dialogs, the editor normally creates three files:
·
The .RES (resource) file, a resource file dedicated to the Dialog Editor. This .RES file is read only by the Dialog Editor and is not the same as the .RES file that is produced by the Resource Compiler and linked into your application.
·
The .DLG (dialog) script, a text file containing
DIALOG
 and
CONTROL
 statements that the Resource Compiler interprets.
·
The .H (include) file, a text file containing
#define
 statements associated with the symbolic names of controls in dialogs. (If you haven't defined any symbolic names in your dialogs, the editor won't create an .H file.)
The .DLG and .H files are used to integrate the current dialogs into your application.
By default, the editor uses the same base name for all three files. Thus, if you use the editor's suggested default name of DIALOGS, the editor writes DIALOGS.RES, DIALOGS.DLG, and DIALOGS.H.
To include dialogs in your application
1.
Use
#include
 statements to include DIALOGS.H and DIALOGS.DLG in your application's resource script (.RC) file. Place the DIALOGS.H statement before the DIALOGS.DLG statement.
#include "dialogs.h"
#include "dialogs.dlg"
2.
Include DIALOGS.H in your source code.
3.
Write a dialog procedure for each dialog to initialize controls and process their messages. Place each dialog procedure name in the module definition file.
4.
Compile your source code.
5.
Use the Resource Compiler to compile the .RC file into the application's .RES file.
6.
Link the .RES file into your application's .EXE file.


The DIALOGS.RES File
The DIALOGS.RES and DIALOGS.H files are created by the Dialog Editor. Together they are an archive of all the dialog information. The .RES file contains all the dialog information except the symbolic names you've defined, which are in the .H file.
Don't confuse the .RES file written by the Dialog Editor with the .RES file produced by the Resource Compiler that is linked into your application. The .RES file that the Dialog Editor writes is just an archive for the Dialog Editor's use.
Note
  You must avoid name conflicts between the two .RES files. Failing to avoid name conflicts will cause unpredictable results.


The DIALOGS.DLG File
When you save a dialog, one of the files the Dialog Editor writes is the .DLG file. This text file contains the information in the .RES file expressed as resource script statements. Each dialog is described in a sequence of statements called a "template."
When you create a dialog in the editor, it has a unique ID number, which becomes a handle to the template. When you want to create an instance of the dialog in your application, you pass this handle to Windows in a call to the
DialogBox
 function. Windows does the rest. Here's a typical .DLG script file containing two simple dialogs:
100 DIALOG 6, 16, 148, 84
STYLE DS_MODALFRAME | WS_VISIBLE | WS_CAPTION | NOT WS_BORDER | WS_POPUP
CAPTION "Invert"
BEGIN
    PUSHBUTTON      "Push This", 101, 54, 30, 40, 14,
END
200 DIALOG 6, 16, 148, 84
STYLE DS_MODALFRAME | WS_VISIBLE | WS_CAPTION | NOT WS_BORDER | WS_POPUP
CAPTION "Reverse"
BEGIN
    PUSHBUTTON      "Push That", 101, 43, 30, 40, 14,
END
The handles to the two dialogs are 100 and 200. You can also define a corresponding symbolic name for a dialog in the editor. It's easier to use a name than a number in your code.
The Dialog Editor cannot read the DIALOGS.DLG file. The data is saved and read from the .RES file.


The DIALOGS.H File
If you define symbolic names in your dialogs, the Dialog Editor writes them to a .H file.
When you create a dialog control, it gets an ID number. You can also assign a symbolic name to the control, and can refer to the control by name or number in your code. The .H file associates symbolic names with corresponding ID numbers.
A typical .H file looks like this:
#define MYOPTION1  101
#define MYOPTION2  102
You can then refer to controls in this way:
BOOL FAR PASCAL FirstDlgProc(hDlg, wMessage, wParam, lParam)
 .
 .
 .
case WM_COMMAND:
switch (LOWORD(wParam))
{
   case IDOK :
      /* Respond to Ok button here */
           break;
   case IDCANCEL :
      /* Respond to Cancel button here */
           break;
   case MYOPTION1:
      /* Respond to MyOption1 button here */
           break;
   case MYOPTION2:
      /* Respond to MyOption2 button here */
           break;
 .
 .
 .
Remember that IDOK and IDCANCEL are defined by Windows and should be used for the OK and Cancel buttons in your dialog box.


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


Using the Editor for Existing Projects
If you begin using the Dialog Editor in an existing project, you may initially find the structure of the project awkward. The project's dialogs may have been written by hand, and the resulting resource script statements may be in an .RC file along with all the other resources for the application. The project's dialog symbols may be in an .H file along with numerous other of the application's symbols. If you don't restructure the project, you'll have to merge files by hand each time you create a dialog.
The easiest way to proceed is to read the application's .RES file with the Dialog Editor by loading it into the editor and at the same time retrieve the dialog symbols by opening the appropriate .H file. You can then save all the dialog information in the Dialog Editor's own dedicated .RES, .DLG, and .H files.
If you save the dialogs under the name DIALOGS, you can then use DIALOGS.DLG as a guide for removing the appropriate resource script statements from the .RC file and substituting a DIALOGS.DLG include statement. In the same way, remove the dialog symbols from the original .H file and include DIALOGS.H in your application and .RC file.
You could continue to let the dialog symbols reside in the original .H file by using the Set Include command on the File menu to associate that file with the dialogs. However, it will be easier for you if you take the time to put the dialog symbols in their own file. Then if you later want to archive the dialogs, examine the dialog files, or move the dialogs to another environment, all the information will be readily available to you.


Using Symbolic Debuggers
The Microsoft Windows NT Software Development Kit (SDK) includes three symbolic debuggers:
·
NTSD, the NT Symbolic Debugger with which you can debug user-mode programs.
·
KD, the Kernel Debugger with which you can debug kernel-mode device drivers. KD provides assembly language debugging and is intended for system developers and device driver authors. NTSD and KD share much of their syntax and support many identical commands.
·
WinDbg, the Windows-based source-level debugger with which you can debug both user-mode programs and kernel-mode drivers.
In most cases, you can use WinDbg to debug application programs, user-mode drivers, and kernel-mode drivers. You may have to use NTSD and KD to debug drivers that initialize before you can run WinDbg or that interfere with WinDbg itself. KD is a kernel-mode remote debugger that runs on a separate host computer. KD provides assembly language debugging and is intended for system developers and device driver authors. NTSD and KD share much of their syntax and support many identical commands. This section explains how to use NTSD and KD.
Introducing WinDbg
 explains how to use WinDbg.
NTSD supports multiple-thread and multiprocess debugging of user-mode applications and DLLs. NTSD is extensible, and can read and write both paged and nonpaged memory.
Using NTSD, you can display and execute program code, set breakpoints, and examine and change values in memory. Because NTSD can access memory locations through addresses, global symbols, or line numbers, you can refer to data and instructions by name rather than by address, making it easy to locate and debug specific sections of code. You can debug C programs at source-file level as well as at machine level. You can display source statements, disassembled machine code, or a combination of both.
KD supports debugging of kernel-mode code. It also supports multiprocessor debugging. Because it is deficient in setting breakpoints in user-mode code and cannot be used to examine or deposit paged-out memory, KD is not well suited to debugging user-mode programs. KD does not provide support for threads.
KD runs on a host computer and communicates through a null-modem serial cable with the target computer running NT. The host computer must be running Windows NT.


The NT Symbolic Debugger (NTSD)
This section describes operation of the NT Symbolic Debugger. Summaries of NTSD commands are included.
The following topics are covered:
·
TOOLS.INI
·
NTSD Command Line
·
Using NTSD
For a complete reference of NTSD commands, see
NTSD and KD Reference
.


TOOLS.INI
On startup, NTSD searches for an [NTSD] header in the TOOLS.INI file and extracts initialization information from the entries under the header. The environment variable INIT must point to the directory containing the TOOLS.INI file.
NTSD also attempts on startup to take commands from the file NTSD.INI in the current directory or in the path specified in the
TOOLS.INI
 file.
The TOOLS.INI entries for the [NTSD] section are as follows:
$u0-$u9
Assign values to user-defined pseudo registers.
DebugChildren
True or false. If true, NTSD debugs the specified application as well as any children that it may spawn.
DebugOutput
True or false. If true, NTSD sends output and receives input through a terminal.
IniFile
Specifies the name of the script file NTSD takes commands from at startup.
LazyLoad
True or false. If true, NTSD performs lazy symbol loading; that is, symbols are not loaded until needed and NTSD starts faster.
StopFirst
True or false. If true, NTSD stops on the first breakpoint it encounters.
StopOnProcessExit
True or false. If true, NTSD stops when it receives a process termination notification.
sxd, sxe
Set exception handling for the following events:
Code
Description
3c
Child App Termination (break on GUI application exit)
av
Access Violation
cc
CTRL+C
ct
Create Thread
et
Exit Thread
ep
Exit Process
ld
Load DLL
The
sxe
 command enables the break status for an exception; the
sxd
 command disables the break status for an exception.
VerboseOutput
True or false. If true, NTSD will display detailed information on symbol handling, event notification, and other run-time occurrences.
An example
TOOLS
.
INI
 file follows:
[ntsd]
sxe: 3c
sxe: cc
$u0: VeryLongName
VerboseOutput:true


NTSD Command Line
The NTSD command line uses the following syntax:
NTSD
 [
options
]
imagefile
where
imagefile
 is the name of the image to be debugged and
options
 is one of the following:
Option
Description
-2
Opens a new window for debugging character mode applications.
-d
Redirects output to the debugging terminal.
-g
Causes execution past the first breakpoint automatically.
-G
Causes NTSD to exit immediately when the child terminates.
-o
Enables debugging of multiple processes. The default is for one process directly spawned by the debugger.
-p
process-id
Specifies debugging of the process identified by
process-id
.
-v
Produces verbose output.


Using NTSD
Before using NTSD, follow these steps:
1.
On
x
86 platforms, compile your program using the CL386 option
/Zd
. This generates debugger symbol information for your .EXE file.
2.
On
x
86 platforms, generate your object file using CVTOMF with the
-g
 option.
3.
Link your program using LINK with the
/
DEBUG
:full
 option.
Note
  The
MSTOOLS
directory includes examples of these options.


Starting NTSD
To start debugging your program with NTSD, enter the following:
ntsd yourexename.exe
This starts NTSD in the current console window and loads the application specified by
yourexename.exe
.
 From the NTSD prompt, set any initial breakpoints with the bp command, and type
g
 (
go
) to start the application. The
g
command directs NTSD to pass control to the program. Execution begins at the current code address.
Note
  NTSD cannot access symbols if the
.EXE
or
.DLL
 being debugged is on drive C and the system was restarted from a drive other than drive C.
If the application hits a breakpoint or has an access violation, you will be returned to the NTSD prompt. It is often handy to run NTSD on the kernel debugging computer. This allows you to continue to watch the NTSD screen while the application is running; you can break into NTSD with
CTRL+C
. To start NTSD with its display redirected to KD, enter
ntsd -d appname
To break into NTSD, use the minus key (below
PRINT SCREEN
) on an 84-key keyboard; on a 101/102-key keyboard, use
F12
.
On invocation of NTSD, you can use the
-g
 option to go past the first breakpoint automatically. For example, the command line
ntsd -g ls
causes NTSD to pass control to
LS
, which executes until it terminates or until an exception causes NTSD to take control.


Using Basic NTSD Commands
These are the most important commands for getting started debugging your application.
NTSD and KD Reference
 contains the complete list of NTSD commands.
Command
Meaning
?
Display command summary
bp
Set breakpoint, for example "bp main"
g
Go
¾
continue execution
ln
List near symbols
p
Single step
r
Display register contents, set register
s+
Set source display mode
u
"Unassemble" (disassemble)
v
View source lines


Canceling NTSD Commands
To cancel the current command, use
SYS RQ
on the target keyboard (
ALT-SYS RQ
 on enhanced keyboards) for MIPS platforms; for
x
86 platforms, use
CTRL+C
. This action is most useful for halting commands that generate long output listings on the display.
If NTSD is running, program execution is stopped. Entering
CTRL+C
 will not affect commands that pass execution control to the application being debugged.


Quitting NTSD
You can terminate NTSD at any time by using the
q
 command to return to the operating system prompt.


Basic Debugging
Follow this sample procedure to get started debugging your application:
1.
Type "ntsd
yourappname
" to start NTSD.
2.
Set source display mode using the
s+
 command.
3.
Set a breakpoint at "main" or "winmain" using the
bp
 command.
4.
Go to this breakpoint using the
g
 command.
5.
Unassemble code from this point using the
u
 command.
6.
Type "v .23 l10" to view 16 (10 hex) source lines starting at line 23.
7.
Set more breakpoints as necessary. If the virtual address corresponding to the next line number you want to stop at is 41000a, type "bp 41000a".
8.
Use the
p
 command to single step or the
g
 command to run until the next breakpoint is encountered.


The Kernel Debugger (KD)
This section describes basic procedures for using KD, the kernel debugger. The following topics are included:
·
Setting Up KD
·
Using KD
·
Quitting KD


Setting Up KD


Preparing a Cable
To use KD to debug kernel-mode executables from a remote location, you must connect a null-modem serial cable to the serial ports of the host computer running KD and the NT computer running the executables. The following two tables list these connections:
KD Serial Cable Connections
KD Serial port
Connected to
NT Serial port
Transmit
Receive
Receive
Transmit
Ground
Ground
KD 9-pin and 25-pin D-subminiature Cable Connections
Pin
Connected to
Pin
2
3
3
2
7
7


Connecting KD
First connect the Windows NT computer and KD computer with a standard null-modem serial cable. On the Windows NT (target) computer, connect the cable to the highest-numbered serial port. For example, on a computer with two serial ports, connect it to COM2. On the debugger (host) computer, connect it to COM1. See the instructions below if you need to use a different port on the debugger computer.
To connect KD
1.
Install a debug version of Windows NT on the debugger computer.
2.
For
x
86 platforms: copy
\NT\MSTOOLS\BIN\I386KD.EXE
 from the development computer to
\NT\BIN
 on the debugger computer; alternatively, copy
\DEBUG\MSTOOLS\BIN\I386\I386KD.EXE
 from the CD-ROM to
\NT\BIN
 on the debugger computer.
For MIPS platforms: copy
\NT\MSTOOLS\BIN\MIPSKD.EXE
 from the development computer to
\NT\BIN
 on the debugger computer; alternatively, copy
\DEBUG\MSTOOLS\BIN\MIPS\MIPSKD.EXE
 from the CD-ROM to
 \NT\BIN
 on the debugger computer.
3.
Create a batch file beginning with these two lines:
SET
 _NT_DEBUG_PORT=COM1
SET
 _NT_DEBUG_LOG_FILE_APPEND=
C:\DEBUG.LOG
T
he last line in this batch file is platform dependent. For
x
86 platforms add
i386kd
and for MIPS platforms add
mipskd
4.
Run the batch file to execute KD. The KD debugging session is logged in the file specified by the
_NT_DEBUG_LOG_FILE_APPEND
 variable. To connect the debugging cable to a port other than COM1 (on the debugging computer), use the
_NT_DEBUG_PORT
 variable to set the desired
COM
 port.


Setting Environment Variables
Set environment variables on the debugger (host) computer as follows:
Variable
Meaning
_nt_debug_port=
portname
Name of the debugger computer port through which the debugger computer and the target computer are connected (for example,
_NT_DEBUG_PORT=COM1
).
_nt_symbol_path=
pathname
Name of the root of a directory tree containing image files containing symbols (for example, if you set
_NT_SYMBOL_PATH=C:\TESTROOT
 on the host, and you run
\NT\BINARY\TEST1.EXE
 on the target computer, KD will try to read symbols from
C:\TESTROOT\NT\BINARY\TEST1.EXE
 on the host computer.). If this variable is not provided, X: is the default path.
_nt_debug_log_file_append=
filename
Name of the log file to which KD appends output.
_nt_debug_log_file_open=
filename
Name of the log file to which KD sends output.


Starting KD
Note
  Remember to start KD before starting the Windows NT computer.
To start KD on
x
86 platforms, enter the following command line at the command prompt:
i386kd
 [
-?
|
-h
|
-H
] [
-b
[
-n
] [
-v
]
exename
where
exename
 is the pathname of the host computer's kernel image file for loading symbols.
To start KD on MIPS platforms, enter the following command line at the command prompt:
mipskd
 [
-?
] [
-h
] [
-l
image-file
] [
-n
] [
-t
] [
-v
]
To start KD on PowerPC platforms, enter the following command line at the command prompt:
ppckd
A list of options and their meanings follows:
Option
Meaning
-?
Displays help
-b
Causes initial break in the kernel
¾
x
86 only
-h
Displays help
¾
x
86 only
-l
image-file
Load symbols from
image-file
 immediately
¾
MIPS only
-n
No lazy symbol loading
-t
Time out between serial port character I/O
¾
MIPS only
-v
Generates verbose messages for loads, deferred loads, and unloads
If your debugger computer is running NT, entering "i386kd -?" (on an
x
86 platform), "mipskd -?" (on a MIPS platform), or "ppckd -?" (on a PowerPC platform) at the command prompt gives information on environment variables and control keys. At the debugger prompt, typing "?" gives help for built-in commands, Entering "!?" gives help for extension commands, which start with a "!".


Using KD
The following list gives suggestions for effective use of KD and summarizes the most common commands:
Command
Description
ENTER
Repeats the last command.
bp
Sets a breakpoint. Breakpoints cannot be set in user space (addresses below 80000000). Breakpoints in user space transfer control to NTSD if it is debugging the thread that encountered the breakpoint. Breakpoints in system space transfer control to KD.
CTRL+R
Synchronizes with the target computer. Use this command if the debugger computer isn't responding.
CTRL+D
Dumps the MIPSKD state.
CTRL+C
Interrupts commands that generate long output listings on the display (for
x
86 platforms only).
Note
  KD cannot dump floating-point registers, but it can dump floating-point variables.


Canceling Commands
To cancel KD commands use the following commands:
·
SYS RQ
on the target keyboard (
ALT-SYS RQ
 on enhanced keyboards)
·
SYS RQ
on the debugger (host) keyboard (
ALT-SYS RQ
 on enhanced keyboards)
·
CTRL+C
 on the target keyboard (for x86 platforms only)
·
CTRL+C
 on the debugger (host) keyboard


Quitting KD
Use the
q
 command to save your log file and quit KD.
Try
CTRL+R
 followed by
ENTER
 on the debugger keyboard if the q command fails to work, and then try using the q command again (to save your log file and quit). Otherwise, press
CTRL+B
 followed by
ENTER
 to locally abort the current session and return to the local command prompt. The log file is not saved when using
CTRL+B
to quit
 KD
. Press
CTRL+B
to quit if both the host and target computers are hung.


NTSD and KD Debugging Topics
This section discusses selected aspects of using NTSD and KD.


DLL Load Notification
Symbols are loaded from the DLL itself (if allowed) and are at the location specified by the pathname for the DLL.


Setting Breakpoints with Symbols
You can use the
bp
 (breakpoint set) command and symbols to set breakpoints in your application code. The
bp
 command uses symbolic names to compute the breakpoint address. For example, for a character mode application, the command
bp main
sets a breakpoint at the application's
main
 function. For a Windows-based application, the command
bp winmain
sets a breakpoint at the application's
winmain
 function.
On MIPS platforms, the breakpoint is automatically set after the prolog.
The "KB" stack trace uses the stack frame to determine which function is executing. Since the stack frame is set up by the first two instructions, you should step a minimum of two assembly-language instructions into a procedure to get an accurate stack trace.
A stack trace after an access violation in a window procedure may be uninformative, since the window procedure is called via a function pointer. If you place a breakpoint in the offending function, you will get a better stack trace.
KD supports virtual breakpoints. If an application has not been loaded, KD sets a virtual breakpoint. A virtual breakpoint has no effect on execution until the application is actually loaded. Once an application is loaded, KD computes the actual coded addresses of all virtual breakpoints and enables them.


Debugging Multiple Processors
KD supports multiple processor computer debugging. Processors are numbered 0 through
n
.
If the current processor is processor 0 (that is, if it is processor 0 that currently causes KD to be active), you can look at the other noncurrent processors (processors 1 through
n
). However, you cannot change anything in the noncurrent processors; you can only look at their state. For example, you can run
k
 and
r
 commands on other processors, using "1r" to dump the registers of processor 1, and "2k" to do a stack trace on processor 2, etc. But running "1r eax=8080808" gives a syntax error because changing the state of noncurrent processors is not allowed.
The KD commands
BA
 (data breakpoint, not implemented on MIPS or PowerPC) and
BP
 (breakpoint) apply to all processors of a multiple processor computer. For example, if the current processor is 63 and you type
bp SomeAddress
to put a breakpoint at
SomeAddress
,
 any processor (not just processor 63) executing at that address will cause a breakpoint trap.


Displaying Variables
Use the
d
 command to display an application's global variables. These commands can use a variable's symbol as an argument and compute the variable's address.
For example, the
d
 command to dump a word
dw hwInstance
causes NTSD or KD to display the contents of the variable
hwInstance
, which might be:
00000235 0000 0000 0000 0000 0000 0000
To display an application's local variables on
x
86 platforms, first compile the application with the
/Zi
 compiler option. Use the "dot" command (
.
) to display the contents of local variables.


Using Pseudoregisters
NTSD supports the use and definition of pseudoregisters. Four of these are automatically set to specific debug information:
·
$ea is set to the last effective address displayed
·
$exp is set to the last expression evaluated
·
$ra is set to the return address currently on the stack
·
$p is set to the value printed by the last
dd
,
dw
, or
db
 command
The pseudoregisters $u0 through $u9 are user-defined and can be used as macros. Pseudoregisters can be used to eliminate typing of long or complex symbol names:
0:000> r $u0=usersrv!NameTooLongToWantToType
0:000> dw $u0+8
Here is another example using a pseudoregister to simplify typing of commands:
0:000> r $u5='dd esp 14;g'
0:000> bp Api1 $u5; bp Api2 $u5
The preceding expands to
bp Api1 'dd esp 14;g'
Note
  Recursive definitions such as the following are not supported:
0:000> r $u0=abc + $u1
0:000> r $u1=def + $u0
You can predefine pseudoregisters in your TOOLS.INI file by adding
$u
 fields to your [NTSD] entry:
[NTSD]
$u0:_ntdll!_RtlRaiseException
$u1:"dd esp 14;g"
$u9:$u0 + $u7


Extending NTSD
A debugger extension is an entry point in a DLL called by NTSD. Debugger extensions are called when NTSD sees the following command:
!
[
module-name
.
]
extension-name
 [
extension-arguments
]
If the module name is specified, it is loaded into NTSD using a call to
LoadLibrary(module-name)
. Otherwise, the default extension module is loaded using
LoadLibrary(
"
ntsdexts
"
)
.
After NTSD has loaded the extension library, NTSD calls
GetProcAddress
 to locate the extension name in the extension module. The extension name is case sensitive and must be entered exactly as it appears in the extension module's .DEF file. If the extension address is found, the extension is called.
The header file NTSDEXTS.H specifies the extension protocol.


NTSD and KD Reference
This section includes arguments and expressions used with NTSD and KD commands, as well as predefined names used as register and register-flag names. Following these descriptions is an alphabetic list of all NTSD and KD commands.
Note
  Several commands and command options listed in
Commands and Command Arguments
 and in
Command Reference
 are unique to either NTSD or KD. NTSD does not support multiple processor debugging. KD does not support threads or multiprocess debugging.


Commands and Command Arguments
Any combination of uppercase and lowercase letters may be used in commands and arguments. If a command uses two or more parameters, separate them with a single comma (
,
) or one or more spaces.
Command arguments can be numbers, symbols, line numbers, or expressions. The arguments specify addresses or values used by commands. The arguments and their meanings are listed below:
address
The relative or symbolic address of a variable or function. Flat addresses are prefixed with a percent sign (
%
), when necessary, to distinguish them from addresses in other modes.
byte
A value argument representing a byte value. It must be within the range 0 to 255.
command-string
One or more commands. Multiple commands must be separated by a semicolon (
;
).
expression
A combination of arguments and operators representing a single value or address.
filename
The name of a file or a device. The filename must follow MS-DOS filename conventions.
id
A decimal number representing a breakpoint. The number must be within the range 0 to 31.
d-list
One or more unique decimal numbers representing a list of breakpoint identifiers. The numbers must be within the range 0 to 31. Multiple numbers must be separated by spaces. The wildcard character (
*
) can be used to specify all breakpoints.
list
One or more value arguments. The values must be within the range 0 to 2
 (32 )
-
 1. Multiple values must be separated by spaces. A list can also be specified as a list of ASCII values. The list can contain any combination of characters and must be enclosed in either single (
'
) or double quotation marks (
"
). If the enclosing mark appears within the list, it must be given twice.
range
A range of addresses. Address ranges have two forms: a starting- and ending-address pair and a start address and object count. The first form is two address arguments, the first specifying the starting address and the second specifying the ending address. The second form consists of an address argument, the letter L, and a value argument. The address specifies the starting address; the value specifies the number of objects to be examined or displayed. The size of an object depends on the command. If a command requires a range but only a start address is given in the command, the command assumes the range to have a default object count as follows:
Size
Object count
ASCII
384
byte
128
word
64
double
32
This default count does not apply to commands that require a range followed immediately by a value or an address argument.
register
The name of a CPU register or a floating point register. The register set is processor dependent. All registers of interest to the application programmer are displayed. A name preceded by an at sign (
@
) always indicates a register name. If no at sign is present, a name is tested to be first a variable, then a hex number, and finally a register name.
symbol
The address of a variable, function, or segment. A symbol consists of one or more characters, but always begins with a letter, underscore (
_
), question mark (
?
), at sign (
@
), or dollar sign (
$
). Any combination of uppercase and lowercase letters can be used; NTSD and KD symbols are not case sensitive. For some commands, the wildcard character (
*
) can be used as part of a symbol to match any combination of characters; you can use a question mark (
?
) to match any single character.
process-id
A process identifier. A vertical bar (
|
) precedes the process identifier, which is one of the following:
Process identifier
Description
.
Current process
*
All processes
ddd
Decimal number of process ordinal
Processes are assigned ordinals as they are created.
Process specifiers appear as command prefixes. The current process is the process that caused the debug exception. It defines the memory space and the set of threads used. That process remains the current process until a new process is specified by a
|s
 command.
Commands that are process-id specific are prefixed by a vertical bar (
|
) and can be followed by a process number or special name as follows:
Process option
Description
.
Current process
#
Process causing present exception
ddd
Decimal number of process ordinal
prefix
!
symbol
A symbol name may be prefixed by a DLL name. An exclamation mark (
!
) separates the DLL name from the symbol.
threadspec
A thread specifier. A tilde (
~
) precedes the thread specifier, which is one of the following:
Thread specifier
Description
.
Current thread
#
Thread causing present exception
*
All threads in the process
ddd
Decimal number of the thread ordinal
Thread specifiers appear as command prefixes. Note that not all wildcards are available in all commands using thread specifiers.
value
Specifies an integer number in octal, decimal, or hexadecimal format.


Symbol Name Resolution
NTSD and KD attempt to match a symbol name in the following order:
1.
E
xact case match (
sym
)
2.
E
xact case match with leading underscore (
_sym
)
3.
M
ixed-case match (
Sym
 or
SYM
)
4.
Mixed-case match with leading underscore (
_Sym
 or
_SYM
)
See also the rules for resolving register, hex, and DLL names listed in the preceding section.


Address Modes and Segment Support
On
x
86 platforms, NTSD and KD support two addressing modes. These modes are distinguished by their prefixes:
Prefix
Name
Mode prompt
Address types
%
flat
(also 16:32)
KD>
32-bit addresses (also 16-bit selectors pointing to 32-bit segments
¾
x
86 only)
&
virtual 86
VMKD>
Real-mode addresses
¾
x
86 only.
If you access memory through an addressing mode that is not the current default, you can use the address mode prefixes to override the current address mode.
NTSD and KD support only the flat addressing mode on MIPS platforms.


Address Arguments
Address arguments specify the location of variables and functions.
The following table explains the syntax and meaning of the various addresses used in NTSD and KD.
Syntax
Meaning
offset
Absolute 32-bit address in virtual memory space.
&[[ segment:]]  offset
Real address
¾
x
86 only.
%segment:[[ offset]]
Flat 32-bit address
¾
x
86 only.
%[[ offset]]
Flat 32-bit address.
name[[ +|
-
 ]]  offset
Flat 32-bit address;
name
 can be any symbol. The
offset
 specifies the offset in bytes. The address can be specified as a positive (+) or negative (
-
) offset.


Line-Number Arguments
If source line information exists in the .EXE or .DLL file, the debugger can display a specified source line. Line number syntax is:
[
module
!
[
filename
[
.
expr
] ] ]
Symbols are as follows:
Symbol
Meaning
module
The name of an executable .EXE or .DLL file. The special name
nt
 indicates the kernel. If
module
 is not given, the module executing as the current process is the default.
filename
The name of a source file, with no path or extension. If
filename
 is not given, the default source file (if available) is that of the module currently executing.
expr
A value in the range from 1 to the highest source-line number in the specified source file. The default radix is 10 regardless of the radix given in the n command.
Line number arguments are translated to the code address designated by the first source line in what may be a multiline source statement. If a line number does not correspond to a source statement, an error occurs. The
 v
command is an exception to this rule: it causes the debugger to display the specified source line, which may be a non-executable line such as a comment or blank line.


Expressions
An expression is a combination of arguments and operators that evaluates to an 8-, 16-, or 32-bit value. Expressions can be used as values in any command.
An expression can combine any symbol, number, or address with any of the unary and binary operators in the tables in
Unary Operators
 and
Binary Operators
. All unary operators have the highest precedence; the precedence of binary operators is indicated by their position in the table.


Unary Operators
Unary address operators assume DS as the default segment for addresses. Expressions are evaluated in order of operator precedence. If adjacent operators have equal precedence, the expression is evaluated from left to right. Use parentheses to override this order.
For symbols with the same character sequence as reserved words (for example, register names and operators), prefix the symbol name with an at sign (
@
) to force symbol access.
The unary operators are listed below:
Operator
Meaning
+
Unary plus
-
Unary minus
not
one's complement
hi
High 16-bits
low
Low 16-bits
by
Low-order byte from given address
wo
Low-order word from given address
dw
Double-word from given address
poi
Pointer from given address (same as
dw
)


Binary Operators
The binary operators are listed in the following table in their order of precedence. Operators with higher precedence appear first.
Operator
Meaning
*
Multiplication
/
Integer division
mod (%)
Modulus
+
Addition
-
Subtraction
and
Bitwise Boolean AND
xor
Bitwise Boolean exclusive OR
or
Bitwise Boolean OR


Command Reference
This section describes the NTSD commands. The commands are summarized in
NTSD and KD Debugging Quick Reference
.


Enter (Repeat Last Command)
Syntax
ENTER
Repeats the last command typed.


| (Process Status)
Syntax
|
[
.
 |
#
 |
*
 |
process-id
]
Prints the status of all processes in the system. If a process is specified, then status for the given process only is printed.


~ (Thread Status)
Syntax
~
[
.
 |
#
 |
*
 | ddd]
Prints status for threads in the current process. If a thread is specified then status is printed for the given thread only.


# (Search for Disassembly Pattern)
Syntax
#
pattern address-expression
Displays the first line of assembly that contains the specified pattern after address.
For example,
# strlen main
causes the debugger to look for the first reference to the function strlen after the entry point to main.


? (Display Help)
Syntax
?
Displays a list of all NTSD or KD commands and operators.


? (Display Expression)
Syntax
?
expression
Displays the value of
expression
. The display includes a full address, a 16-bit hexadecimal value, a full 32-bit hexadecimal value, a decimal value (enclosed in parentheses), and a string value (enclosed in double quotation marks). The expression parameter can include any combination of numbers, symbols, addresses, and operators.


$< (Redirect Input)
Syntax
$<
filename
Redirects input to the specified file until the end of file is reached. When end of file is reached, input is reset to the console.


. (Display Local Variables)
Syntax
.
Displays local variables for the current function. This command is not implemented on MIPS or PowerPC.


a (Assemble)
Syntax
a
[
address
]
Assembles instruction mnemonics and places the resulting instruction codes into memory at
address
. If no address is given, the assembly starts at the address given by the current value of the instruction pointer. To assemble a new instruction, type the desired mnemonic and press
ENTER
. To terminate assembly, press
ENTER
 only.


ba, ~ba (Breakpoint Address)
Syntax
~[[
threadspec
]
ba
[
io
]
option
size
address
 [
value
] [
cmd-string
]
Sets an address breakpoint at a given address. If
threadspec
 is given, the breakpoints are set for the specified threads. If your program accesses memory at this address, the debugger stops execution and displays the current values of all registers and flags.
The
option
 parameter specifies the type of breakpoint:
Option
Action
E (executable)
Breakpoint trap when the CPU fetches an instruction from the given
address
.
R (read only)
Breakpoint trap when the CPU reads or writes a byte, word, or double-word at the given address.
W (read/write)
Breakpoint trap when the CPU writes a byte, word, or double-word at the given address.
The
io
 parameter is an optional value in the range 0
-
31.
The
address
 parameter can specify any valid address. Offsets only are supported.
The
size
 parameter is the size in bytes. It can be 1, 2, or 4.
The optional
value
 parameter specifies the number of times the breakpoint is to be ignored before being taken. It can be any 16-bit value.
The
cmd-string
 parameter specifies an optional list of commands to be executed each time the breakpoint is taken. Each command in the list can include parameters and is separated from the next command by a semicolon (
;
).
The
bc
,
bd
,
be
, and
bl
 commands can all be used on these breakpoints.
This command is not implemented on MIPS or PowerPC.


bc (Breakpoint Clear)
Syntax
bc
 [
id-list
]
Permanently removes one or more breakpoints. If
id-list
 is given, the command removes the breakpoints named in the list. The
id-list
can be any combination of integer values from 0 to 31. If the
id-list
is a wildcard character (
*
), the command removes all breakpoints.


bd (Breakpoint Disable)
Syntax
bd
 [
id-list
]
Disables, but does not delete, one or more breakpoints. If
id-list
is given, the command disables the breakpoints named in the list. The
id-list
can be any combination of integer values from 0 to 31. If the
id-list
is a wildcard character (*), the command disables all breakpoints.


be (Breakpoint Enable)
Syntax
be
 [
id-list
]
Restores one or more breakpoints that were temporarily disabled by a
bd
 command. If
id-list
 is given, the command enables the breakpoints named in the list. The
id-list
can be any combination of integer values from 0 to 9. If the
id-list
is a wildcard character (
*
), the command enables all breakpoints.


bl (Breakpoint List)
Syntax
bl
Lists current information about all breakpoints. The command displays the breakpoint number, the enabled status, the address of the breakpoint, the number of passes remaining, and the initial number of passes (in parentheses). The enabled status can be enabled (e) or disabled (d).


bp (Breakpoint Set)
Syntax
~
 [
.
 |
#
| ddd |
*
] [
threadspec
]
bp
 [
id
]
address
 [
value
] [
command-string
]
Creates a "sticky" breakpoint at the given address. Sticky breakpoints stop execution and display the current values of all registers and flags. Sticky breakpoints remain in the program until they are removed by the
bc
 command or temporarily disabled by the
bd
 command.
If
threadspec
 is given, breakpoints are set on the specified threads. For example, the
~*bp
 command sets breakpoints on all threads;
~#bp
 sets a breakpoint on the thread causing the current exception; and
~123bp
 sets a breakpoint on thread 123. The
~bp
 and
~.bp
 commands both set a breakpoint on the current thread.
The debugger supports up to 32 breakpoints, which are numbered 0 through 31. The optional
id
 parameter specifies the number of the breakpoint to be created. If
id
 is not given, the first available breakpoint number is used.
The
address
 parameter can be any valid instruction address (it must be the first byte of an instruction).
The optional
value
 parameter specifies the number of times the breakpoint is to be ignored before being taken. It can be any 16-bit value.
The optional
command-string
 parameter specifies a list of commands to be executed each time the breakpoint is taken. This command-string is executed only if the breakpoint is from a g command (and not from a
t
 or
p
 command). Debugger commands in the list can include parameters; the commands are separated by semicolons (
;
).


c (Compare)
Syntax
c
 [
range
]
address
Compares the bytes in the memory locations specified by
range
 with the corresponding bytes in the memory locations beginning at
address
. If all corresponding bytes match, the debugger displays its prompt and waits for the next command. If one or more pairs of corresponding bytes do not match, the debugger displays each pair of mismatched bytes.


d (Dump)
Syntax
d
 [
range
]
Displays the contents of memory in
range
. The command displays data in the same format as the most recent dump command (
d
,
da
,
db
,
dd
,
dg
,
dh
,
dl
,
dq
,
dt
, or
dw
).
If no range is given and no previous dump command has been used, the debugger displays bytes starting at the current instruction pointer.


da (Dump ASCII)
Syntax
da
 [
range
]
Displays the ASCII characters in the given
range
. Each line displays up to 48 characters. The display continues until the first null byte or until all characters in
range
 have been displayed. Nonprintable characters, such as carriage returns and line feeds, are displayed as periods (
.
).


db (Dump Bytes)
Syntax
db
 [
range
]
Displays the hexadecimal and ASCII values of the bytes in the given
range
. Each display line shows the address of the first byte in the line, followed by up to 16 hexadecimal byte values. The byte values are immediately followed by the corresponding ASCII values. The eighth and ninth hexadecimal values are separated by a hyphen (
-
). Nonprintable ASCII values are displayed as periods (
.
).


dd (Dump Double-Words)
Syntax
dd
 [
range
]
Displays the hexadecimal values of the double-words (4-byte values) in the given
range
. Each display line shows the address of the first double-word in the line and up to four hexadecimal double-word values.


dw (Dump Words)
Syntax
dw
 [
range
]
Displays the hexadecimal values of the words (2-byte values) in the given
range
. Each display line shows the address of the first word in the line and up to eight hexadecimal word values.


e (Enter)
Syntax
e
address
 [
list
]
Enters one or more values into memory. The size of the value entered depends on the most recently used
Enter
 command (
e
,
ea
,
eb
,
ed
,
el
,
es
,
et
, or
ew
). The default is
eb
 (bytes). If no list is given, the command displays the value at
address
 and prompts for a new value. If
list
 is given, the debugger replaces the value at
address
 and at each subsequent address until all values in the list have been used.


ea (Enter ASCII)
Syntax
ea
address
 [
list
]
Enters an ASCII string into memory. If
list
 is not given, the debugger displays the byte at
address
 and prompts for a replacement. If
list
 is given, the debugger replaces the bytes at
address
, then displays the next byte and prompts for a replacement.


eb (Enter Bytes)
Syntax
eb
address
 [
list
]
Enters one or more byte values into memory. If
list
 is given, the debugger replaces the byte at
address
 and at each subsequent address until all values in the list have been used. If
list
 is not given, the debugger displays the byte at
address
 and prompts for a new value. To skip to the next byte, enter a new value or press
SPACE
. To move back to the previous byte, type a hyphen (
-
). To exit from the command, press
ENTER
.


ed (Enter Double-Words)
Syntax
ed
address
 [
list
]
Enters a double-word value into memory. If
list
 is not given, the debugger displays the double-word at
address
 and prompts for a replacement. If
list
 is given, the debugger replaces the double-word at
address
, then displays the next double-word and prompts for a replacement. Double-words must be entered as two words separated by a colon (
:
).


ew (Enter Words)
Syntax
ew
address
 [
list
]
Enters a word value into memory. If
list
 is not given, the debugger displays the word at
address
 and prompts for a replacement. If
list
 is given, the debugger replaces the word at
address
, then displays the next word and prompts for a replacement.


f (Fill)
Syntax
f
range
list
Fills the addresses in
range
 with the values in
list
. If
range
 specifies more bytes than the number of values in the list, the list is repeated until all bytes in the range are filled. If
list
 has more values than the number of bytes in the range, the debugger ignores the extra values.


~f (Freeze Thread)
Syntax
~
 [
.
 |
#
 |
*
 | ddd]
f
Freezes the current thread. The
~*f
 command freezes all threads;
~#f
 freezes the thread causing the current exception; and
~123f
, for example, freezes thread 123.


g (Go)
Syntax
[
threadspec
 ]
g
 [
=
startaddress
] [
breakaddress
]
...
Passes execution control to the program at
startaddress
. Execution continues to the end of the program or until
breakaddress
 is encountered. The program also stops at any breakpoints set using the bp command.
If
startaddress
 is not given, the debugger passes execution to the address specified by the current value of the instruction pointer. If
breakaddress
 is given, it must specify an instruction address (that is, the address must contain the first byte of an instruction). Up to 10 break addresses, in any order, can be given at one time.
If
~g
 is given then the go command is executed with the specified thread unfrozen, and all others frozen. For example, if the command
~123g
,
~#g
, or
~*g
 is given, the specified threads are unfrozen and all others are frozen.


gh, gn (Go for Exceptions)
Syntax
~
[
threadspec
]
gh
 [
=
startaddress
] [
breakaddress
]
...
~
[
threadspec
]
gn
 [
=
startaddress
] [
breakaddress
]
...
Control exception handling. These commands can be used after the first break to an exception. The
gh
 command treats the exception as handled;
gn
 treats the exception as not handled. See the
sx
 command for more details.


ib, iw, id (Input from Port)
Syntax
i
 [
b
 |
w
 |
d
]
address
Inputs and displays a byte, word, or double word (
b
,
w
, or
d
) from the port at the location given by
address
 (KD only).


.inputfile (Read from Command File)
Syntax
.inputfile
filename
Reads commands from
filename
 until the end of file is reached or another .inputfile command is executed. Input files are not recursive and cannot be nested: a .inputfile command in a log file causes an immediate jump to the new log file with no return.


j (Conditional Execution)
Syntax
j
expression
 [
'
]
command1
[
'
]
;
[
'
]
command2
[
'
]
Allows conditional execution of commands. If
expression
 evaluates to a nonzero value, the string
command1
 is executed, else the string
command2
 is executed. The optional single quotes are used to group multiple commands (separated by semicolons) into a single command string. This command can be combined with the bp command to create conditional breakpoints:
bp _foo "j (eax>0x1) 'dd app!bar;g;'u;|' "


~k (Backtrace Stack)
Syntax
~
 [
threadspec
]
k
 [
value
]
[
processor-num
]
k
 [
value
]
Displays the current stack frame. Each line shows the name of a procedure, its arguments, and the address of the statement that called it. If
value
 is given, the command displays that many stack frames.
Using the
k
 command at the beginning of a function (before the function prolog has been executed) will give incorrect results. The debugger uses the frame register to compute the current backtrace, and this register is not correctly set for a function until its prolog has been executed.
If a thread specifier is given, a backtrace for the given thread is printed.
With the kernel debugger, the process number can be specified to indicate the stack frame for a given process. Default is 1.


ln (List Near)
Syntax
ln
address
Lists the nearest symbols before and after
address
.


.logappend (Append to Log File)
Syntax
.logappend
 [
file
]
Appends history information to the current log file. The default filenames are NTSD.LOG and KD.LOG, for NTSD.EXE and SDK.EXE, respectively.


.logclose (Close Log File)
Syntax
.logclose
Closes the current log file.


.logopen (Open Log File)
Syntax
.logopen
 [
file
]
Opens the log file and deletes any existing file. The default filenames are NTSD.LOG and KD.LOG for NTSD.EXE and SDK.EXE, respectively.
Any current log file is closed.


m (Move)
Syntax
m
range
address
Moves the block of memory specified by
range
 to the location starting at
address
. All moves are guaranteed to be performed without data loss.


ob, ow, od (Output to Port)
Syntax
o
 [
b
 |
w
 |
d
]
address value
Outputs a byte, word, or double word (b, w, or d)
value
 to the port at
address
 (KD only).


p (Program Step)
Syntax
p
 [
r
] [
=
startaddress
] [
repeat
]
Executes an instruction, then displays the current values of all registers and flags.
The
r
 flag toggles display of register values.
If
startaddress
 is given, the debugger starts execution at the given address. Otherwise, the debugger starts execution at the instruction pointed to by the instruction pointer.
If
repeat
 is given, the debugger executes
repeat
 number of instructions before stopping. The debugger automatically executes and returns from any call instructions or software interrupts it encounters, leaving execution control at the next instruction after the call or interrupt.
With
s
-
  and
s&
, the
p
 command steps one machine instruction; with
s+
, the
p
 command steps one source line.


~p (Program Thread Step)
Syntax
~
[
.
 |
#
 |
*
 | ddd]
p
 [
r
] [
=
startaddress
] [
repeat
]
Steps execution with indicated threads thawed; all others are frozen. For example,
~*p
 steps with all threads thawed;
~#p
 steps with only the current exception thread unfrozen; and
~123p
, steps with thread 123 thawed and all others frozen. The
~p
 and
~.p
commands both step execution with the current thread unfrozen.


q (Quit)
Syntax
q
Terminates NTSD execution and returns control to the operating system.


r, rf (Register Display)
Syntax
~
 [
.
 |
#
 | ddd |
*
]
r
 [
register
] [= [
value
] ]
~
 [
.
 |
#
 | ddd |
*
]
rf
 [
floatregister
] [= [
value
] ]
Display the contents of CPU registers and allow their contents to be changed to new values.
If
register
 is not specified, the debugger displays all registers, all flags, and the instruction at the address pointed to by the instruction pointer. If
register
 is specified, the debugger displays the current value of the register and prompts for a new value. If both
register
 and
value
 are specified, the debugger changes the register contents to the specified value.
With the kernel debugger, a processor number can be specified to indicate the registers for a given processor. The default is 0.
With the user-mode debugger, a thread specifier can be specified to display registers for a given thread.
The
rf
 command displays floating-point registers. Note that floating-point registers may be operated on in the same way as other CPU registers.


rt (Register Display Toggle)
Syntax
[
threadspec
]
rt
Toggles the register display (KD only). The default is off.
With the kernel debugger, a processor number can be specified to indicate the registers for a given processor. The default is 0.


.reboot (Restart Target Computer)
Syntax
.reboot
Restarts the target computer (KD only, not implemented on MIPS or PowerPC). This command exits the debugger, so that open symbol files are closed.


!reload
Syntax
!reload
Loads symbols for all drivers that have been loaded on the target system. This command is useful in the event of a system crash which may result in the loss of symbols for the target computer being debugged. To load the correct symbols, invoke KD with an explicit path to the kernel, for example:
i386kd c:\nt\oskrnl.exe
Then you can type
!reload
and the debugger will load the symbols for the drivers that the target system has already loaded.


s (Search)
Syntax
s
range list
Searches the given
range
 of memory locations for the byte values given in
list
. The debugger displays the address of each byte found.


ss (Set Suffix)
Syntax
ss
 [
n
| a
| w
]
Outputs the current state of the suffix value. Suffix values may be:
Suffix
Meaning
n
No suffix
a
ASCII
w
Wide characters
For the a and w suffix values, any symbol that is undefined will have the suffix value appended to its name, and the resulting symbol is searched for in the symbol table.


sx, sxe, sxd (Set Exceptions)
Syntax
sx
 [
e
 |
d
] [
eventcode
 |
exceptnum
]
Control the behavior of the debugger when exceptions occur (NTSD only).
The
sx
 command causes the debugger to display its break status for all events, including exceptions.
Followed by one of the two-letter event codes listed below or by an exception number, the
sx
 command causes the debugger to print its break status for the given event. Non-exception events are identified by a two-letter combination:
Event code
Meaning
av
Access Violation
cc
CTRL+C
ct
Create Thread
et
Exit Thread
ep
Exit Process
ld
Load DLL
The
sx
 command also can be used to set the debugger's behavior on an event. The
sxe
 command enables the break status for an exception; the
sxd
 command disables the break status of an exception.
On a break on an event, only the
g
 command (not
t
 or
p
) is allowed to continue execution.
On a first-time break to an exception, special versions of the
go
 command can be used:
gh
 treats the exception as handled, and
gu
 treats the exception as unhandled. A normal
g
 command uses the default disposition.
Second time exceptions always break into the debugger.


s+, s&, s
-
 (Set Source Display Mode)
Syntax
s+
s&
s
-
Set the display mode for commands that display instruction code:
Command
Action
s
-
Disassemble and display the instruction code in memory
s&
Display the source line and the disassembled code
s+
Display the source line corresponding to the instruction to be displayed
Source lines are identified by
module.lineno
, where
module
 is the source filename (without a path or extension) and
lineno
 is the line number in the source file.


|s (Set Process)
Syntax
| [
.
 |
#
 |
process-id
]
s
Sets the current process number. If
process-id
 is not given, information for the current process is printed.


~s (Set Thread)
Syntax
~
 [
.
|
#
|
 ddd] s
Sets the current thread number. If no thread number is given, information for the current thread is printed.


t (Trace)
Syntax
t
 [
r
] [
=
startaddress
] [
repeat
]
Executes an instruction, then displays the current values of all registers and flags.
The
r
 flag toggles display of register values.
If
startaddress
 is given, the debugger starts execution at the given address. Otherwise, it starts execution at the instruction pointed to by the instruction pointer.
If
repeat
 is given, the debugger continues to execute
repeat
 instructions before stopping.
In source-only mode (
s+
),
t
 operates directly on source lines. The
t
 command can be used to trace instructions in ROM.
The
t
 command with a repetition count outputs instructions for all repetitions.


~t (Trace Thread)
Syntax
~
 [
.
 |
#
 |
*
 | ddd]
p
 [
t
] [
=
startaddress
] [
repeat
]
Traces with indicated threads thawed; all others are frozen. For example,
~*t
 traces with all threads thawed;
~#t
traces with only the current exception thread thawed; and
~123t
, traces with thread 123 thawed, and all others frozen. The
~t
 and
~.t
commands both trace with the current thread thawed.


u (Unassemble)
Syntax
u
 [
range
]
Displays the instructions and/or statements of the program being debugged. The
s+
,
s
-
 , and
s&
 commands set the display format.
If
range
 is given, the debugger displays instructions generated from code within the given range. Otherwise, the debugger displays the instructions generated from the first eight lines of code at the current address.
The 80286 protected-mode mnemonics cannot be displayed.


~u (Unfreeze)
~
[
.
 |
#
 |
*
 | ddd]
u
Unfreezes the current thread. The
~*u
 command unfreezes all threads;
~#u
 unfreezes the thread causing the current exception; and
~123u
, for example, unfreezes thread 123.


v (View Source Lines)
Syntax
v
range
Displays source lines beginning at the specified
range
. The symbol file must contain line-number information.


x (Examine Symbols)
Syntax
x
symbol
Displays all symbols matching
symbol
. The pattern match is case sensitive. The ? character matches any character and the
*
 character matches zero or more characters.
The
x *
 form of the command displays module information. The
x *!*
 command displays module and line number information, when available, for all modules. The first asterisk is a wildcard for module names and the second is a wildcard for line number expressions.


NTSD and KD Debugging Quick Reference
The following table lists the command syntax for NTSD and KD debugging commands:
NTSD and KD Debugging Commands
Syntax
Meaning
ENTER
Repeat last command
| [. | # | * |
process-id
]
Process status
~ [. | # | * | ddd]
Thread status
#
pattern address=expression
Search for dissassembly pattern
?
Display debugger help
?
expression
Compute and display
expression
$<
filename
Redirect input from
filename
.
Display local variables
¾
not implemented on MIPS or PowerPC
a
 [
address
]
Assemble instruction mnemonics
~
[
threadspec
]
ba
[
io
]
option
size
address
 [
value
] [
cmd-string
]
Set address breakpoint (KD only
¾
not implemented on MIPS or PowerPC)
bc
[
id-list
]
Clear breakpoint(s)
bd
[
id-list
]
Disable breakpoint(s)
be
[
id-list
]
Enable breakpoint(s)
bl
List breakpoint(s)
~
[. | # | ddd | *] [
threadspec
]
bp
[
id
]
address
 [
value
] [
command-string
]
Set breakpoints
c
[
range
]
address
Compare
d
[
range
]
Dump memory using previous type
da
[
range
]
Dump memory ASCII
db
[
range
]
Dump memory bytes
dd
[
range
]
Dump memory double-words
dw
[
range
]
Dump memory words
e
address
 [
list
]
Enter using previous type
ea
address
 [
list
]
Enter ASCII
eb
address
 [
list
]
Enter bytes
ed
address
 [
list
]
Enter double-words
ew
address
 [
list
]
Enter words
f
range list
Fill range
~
[. | # | * | ddd] f
Freeze thread
g
,
gh
, and
gn
Go commands
i
[b | w | d]
address
Input from port at
address
 (KD only)
.inputfile
filename
Read from command file
j
expression
 [']
command1
[']
;
[']
command2
[']
Conditional execution
~
[
threadspec
]
k
[
value
]
Backtrace stack
ln
address
Lists first symbols before and after address
.logappend
[
file
]
Append to the current log file
.logclose
Close the current log file
.logopen
[
file
]
Open a log file
m
range address
Move
o
[b | w | d]
address value
Output
 value
 to port at
address
 (KD only)
[
.
 |
#
 |
*
 | ddd]
p
[r] [
=
startaddress
] [
repeat
]
Execute an instruction, then display registers and flags
~ [
threadspec
]
p
 [=
startaddress
] [
value
]
Trace program instruction or call
q
Quit
[
threadspec
]
r
[t] [
register
] [= [
value
] ]
Register set (
rt
 toggles full register display
¾
KD only)
[
threadspec
]
rf
 [
floatregister
] [= [
value
] ]
Register set command for floating-point values
.reboot
Restart target computer (KD only
¾
not implemented on MIPS or PowerPC)
!reload
Load symbols for all the drivers that have been loaded on the target system.
s
range
list
Search
range
 for bytes in
list
ss
[n | a | w]
Set suffix to n for none, a for ASCII, or w for wide. With no argument, prints current suffix setting.
sx
[e | d] [
eventcode
 |
exceptnum
]
Set exceptions (NTSD only)
s+
Set source display only
s&
Set mixed assembler and source display mode
s
-
Set assembler display only
| [. | # |
process-id
] s
Set process
~
[. | # | ddd] s
Set thread
t
[r] [=
startaddress
] [
repeat
]
Trace program instruction
~
[. | # | * | ddd]
p
[t] [=
startaddress
] [
repeat
]
Trace thread
u
[
range
]
Display unassembled instructions
~
[. | # | * | ddd]
u
Unfreeze thread
v
range
View source lines
x
symbol
Examine symbol(s)


Monitoring Messages and Data
Microsoft Windows NT Spy (SPY.EXE) and DDESpy (DDESPY.EXE) are monitoring tools for the Microsoft Windows NT operating system. Spy makes it possible for you to monitor messages sent to one or more windows and to examine the values of message parameters. DDESpy lets you monitor dynamic data exchange (DDE) activity in the Microsoft Windows NT operating system. This section describes the use of both Spy and DDESpy.


Spy
This section describes how to use the Spy, Edit, Options, and Start!/Stop! menus to specify how Spy is to operate.


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


The Edit Menu
You can use the Edit menu to Cut, Copy, and Clear information from the Spy window to the clipboard.
Command
Description
Cut
Cuts the selected text to the clipboard.
Copy
Copies the selected text to the clipboard.
Clear
Clears the selected text from the Spy window.


The Options Menu
The Options menu displays a dialog box in which you make selections about the following:
·
Which message types Spy is to monitor
·
Which font Spy should use
·
Which output device Spy is to send messages to
You make your selections from items displayed under Messages, Font, and Output.


Selecting Message Types
Under Messages, you can select any of the following message types you want Spy to monitor:
Message
Description
DDE
Dynamic data exchange (DDE) messages, such as
WM_DDE_REQUEST
Clipboard
Clipboard messages, such as
WM_RENDERFORMAT
Mouse
Mouse messages, such as
WM_MOUSEMOVE
 and
WM_SETCURSOR
Non Client
Windows nonclient messages, such as
WM_NCDESTROY
 and
WM_NCHITTEST
Keyboard
Keyboard messages, such as
WM_KEYDOWN
 and
WM_ACTIVATE
Button Control
Button control messages, such as
BN_CLICKED
 and
BM_GETCHECK
Combo Box Control
Combo Box control messages, such as
CB_ADDSTRING
 and
CB_LIMITTEXT
Editfield Control
Editfield control messages, such as
EM_GETSEL
 and
EM_UNDO
Listbox Control
Listbox control messages, such as
LB_GETSEL
 and
LB_GETCARETINDEX
Static Control
Static control messages, such as
STM_GETICON
 and
WM_CTLCOLORSTATIC
WM_USER
Application-defined WM_USER messages
Unknown
Messages other than those explicitly listed
By default, Spy monitors all messages.


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


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


The Start!/Stop! Menu
After using the Options and Spy menus to make your selections, start Spy by clicking the Start! menu.
To stop monitoring messages, click the Stop! menu.


DDESpy
This section describes how to use DDESpy. For more information about dynamic data exchange, see the
Microsoft Windows 32-Bit API Programmer's Reference
.
DDESpy is a typical DDE monitoring application. Because DDE is a cooperative activity, DDE monitoring applications must follow certain guidelines for your Windows system to operate properly while they are in use. In particular, DDE monitoring applications should not perform DDE server or client communications
¾
 problems may arise when the monitoring application intercepts its own communications.


The Output Menu
DDESpy can display DDE information in a window or on your debugging terminal or can save the displayed information in a file for later use.
You use the Output menu to select where DDESpy is to send output. If you choose the File command, you must specify the name of an output file. After you have chosen the File command once, DDESpy prompts you for an output filename every time you restart the application.
From the Output menu, you can choose to send your output to either a debug terminal or to the DDESpy window. You can also choose the Clear Screen command to clear the display window. Use the Mark command to add text to the display as a marker
¾
 for example, before a DDE event to make it easier to find the event in the output file.


The Monitor Menu
You use the Monitor menu to specify one or more types of DDE information that DDESpy is to display. The following information can be displayed:
·
String handle data
·
Posted DDE messages
·
Callbacks
·
Errors
·
Filters
The Dynamic Data Exchange protocol passes information by using shared memory. The contents of the shared memory depend on the type of DDE transaction. Several structures have been defined to allow applications using DDE to access the information in shared memory. DDESpy displays the contents of the appropriate structure for the DDE activity being monitored.
You can use the Filters option to choose the type of DDE messages and types of DDE callbacks to monitor.


Monitoring String-Handle Data
The DDE protocol uses the
MONHSZSTRUCT
 structure to pass string-handle data. DDESpy displays the following information from this structure:
·
Task (application instance)
·
Time, in milliseconds, since you started Windows
·
Activity type (create, destroy, or increment)
·
String handle
·
String contents
The following example shows a typical DDESpy display of string-handle data:
Task:0x94f, Time:519700, String Handle Created: c4a4(this is a test)
Task:0x94f, Time:526126, String Handle Created: c4aa(another test)


Monitoring Posted DDE Messages
The DDE protocol uses the
MONMSGSTRUCT
 structure to post DDE messages. DDESpy displays the following information from this structure:
·
Task
·
Time
·
Handle of receiving window
·
Transaction type (sent or posted)
·
Message type
·
Handle of sending application
·
Other message-specific information
The following example shows a typical DDESpy display of DDE message activity:
Task:0x8df Time:642402 hwndTo=0x38dc Message(Sent)=Initiate:
       hwndFrom=9224, App=0xc35d("Server")
       Topic=*
Task:0x94f Time:642457 hwndTo=0x2408 Message(Sent)=Ack:
       hwndFrom=9396, App=0xc35d("Server")status=c35d(fAck fBusy )
       Topic=Item=0xc361("System")


Monitoring Callbacks
The DDE protocol uses the
MONCBSTRUCT
 structure to pass information to application callback functions. DDESpy displays the following information from this structure:
·
Task
·
Time
·
Transaction type
·
Exchanged-data format, if any
·
Conversation handle
·
String handles and their referenced strings
·
Transaction-specific data
The following example shows a typical DDESpy display of callback activity:
Task:0x8df Time:2882628 Callback:
       Type=Advstart, fmt=0x1("CF_TEXT"), hConv=0xc24b4,
       hsz1=0xc361("System") hsz2=0xc4df("xxcall"), hData=0x0,
       lData1=0x83f0000, lData2=0x0
       return=0x0


Monitoring Errors
When an error occurs during a DDE transaction, the DDE protocol places the error value and associated information in a
MONERRSTRUCT
 structure. DDESpy uses this structure to display the following information about the error:
·
Task (the handle of the application that caused the error)
·
Time
·
Error value and name


Tracking Options
DDESpy can also display information about aspects of DDE communication in your Windows system:
·
String handles
·
Conversations
·
Links
·
Services
You can use the Track menu to specify which DDE activity DDESpy is to track. When you choose a command from the Track menu, DDESpy creates a separate window for the display of information in conjunction with the DDE functions. For each window created, DDESpy updates the displayed information as DDE activity occurs. Events that occurred prior to creation of the tracking window are not displayed in the tracking window.
DDESpy can sort the displayed information in the tracking window. If you select the heading for a particular column in the tracking window, DDESpy will sort the displayed information based on the column you selected. This can be useful if you are searching for a particular event or handle.


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


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


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


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


The About Menu
Provides information about the version of DDESpy you are using.


Using PView
The PView process viewer lets you examine and modify many characteristics of processes and threads running on your system.
PView can help you answer questions like these:
·
How much memory does the program allocate at various points in its execution, and how much memory is being paged out?
·
Which processes and threads are using the most CPU time?
·
How does the program run at different system priorities?
·
What happens if a thread or process stops responding to DDE, OLE, or pipe I/O?
·
What percentage of time is being spent running API calls?
Warning
  PView lets you modify the status of processes running on your system. As a result, by using PView, you can stop processes and potentially halt the entire system. Make sure that you have saved edited files before running PView.


PView Main Dialog
The main PView dialog box consists of several boxes containing information on active processes and threads, and controls to change their behavior (see the following figure).
The following buttons control PView actions:
Exit
Closes PView.
Memory Details
Opens the Memory Details dialog box. See
Memory Details Dialog
 for more information.
Kill Process
Removes the highlighted process from the system. This is different from choosing Close from the system menu, because the process is not informed of the shutdown (with WM_DESTROY) before it is stopped.
Refresh
Updates information in the main PView dialog box and the Memory Details dialog box.
Connect
View information about the computer specified in the Computer text box. The Computer box should contain the network name of the computer that you wish to view. Your ability to connect to a remote system may be affected by security on the target computer.


Process Selection
The Process Selection list box displays information on the accessible processes running on the system. From this list, you can select a process to use for future actions. All other information and control areas in PView reflect the process chosen in this box.
Note
  Since Windows NT is a secure operating system, you may not be able to view or alter attributes of some programs running on the system. See your NT
User's Guide
 for more information on NT security.
The fields in the Process Selection box are as follows:
Process
Name of the process on this line. Usually an .EXE filename.
CPU Time
Amount of CPU time that this process has used.
Privileged
Percentage of the CPU time that was spent executing privileged code (code in the NT Executive).
User
Percentage of the CPU time that was spent executing user code. This time includes time running protected subsystem code.


Process Memory Used
The Process Memory Used box displays information on the memory usage of the process selected in the Process Selection box:
Working Set
The average amount of physical memory used by the process. The longer a process has been running, the more accurate this value is.
Heap Usage
The current total heap being used by the process. Heap space is taken by dynamically allocated data, including memory reserved by
malloc
,
new
,
LocalAlloc
,
HeapAlloc
,
VirtualAlloc
, and
GlobalAlloc
.


Priority
The Priority buttons let you change the base priority of the process highlighted in the Process Selection box. This priority determines the activity of all threads of the selected process:
Very High
Maximum priority. CPU time is split between this and other Very High priority processes. Lower priority processes will execute only when all Very High priority processes are blocked.
Normal
The standard-priority group, also known as "foreground." Most applications run with normal priority.
Idle
The lowest-priority group, also known as "background." Processes with this priority will execute only when the system has no higher-priority processes that need CPU time. Screen savers run at this priority.


Thread Selection
The Thread Selection list box displays statistics for threads of the process selected in the Process Selection box and lets you select a thread for further operations:
Threads
The thread ID number. This is the handle returned by
CreateThread
.
CPU Time
The amount of time that this instance of the thread has been running.
% Privileged
The percentage of the CPU time that was spent executing privileged code (code in the NT Executive).
% User
The percentage of the CPU time that was spent executing user code. This time includes time running protected subsystem code.


Thread Information
The Thread Selection box displays execution information about the thread selected in the Thread Selection box:
User PC Value
The value of the instruction pointer for this thread.
Start Address
The address of the entry point of this thread. This information is useful for debugging.
Context Switches
Number of times that this thread has received CPU attention.
Dynamic Priority
The current dynamic thread priority. This number is determined by many factors, including user activity.


Thread Priority
The Thread Priority box shows you the base priority of the thread selected in the Thread Selection box. This is not an absolute priority, but is a range of priorities that can be selected by the operating system for the selected thread:
Highest
The highest priority level allowed by the process priority.
Above Normal
Slightly elevated priority.
Normal
The standard priority level for the given process priority.
Below Normal
Reduced priority.
Idle
No CPU time will be spent on this thread unless all other threads are blocked.


Memory Details Dialog
The Memory Details dialog box (see the following figure) gives information on the process selected by the Process Selection box in the main PView dialog box. To update the information contained in this dialog box, return to the main dialog box and click on the Refresh button.
This dialog box consists of the following buttons:
OK
Returns to the main PView dialog box.
Process
The name and process ID of the process selected in the Process Selection box of the main dialog.
User Address Space for
Displays the statistics for specific .EXE or .DLL files or "Total Image Commit," which displays statistics for all components of the currently selected process. These statistics are the following:
Inaccessible
Address space that cannot be accessed. This includes memory reserved by
VirtualAlloc
.
Read Only
Read-only data and code.
Writeable
Total data address space that can be written to.
Writeable (Not Written)
Data address space that can be written to, but has not been.
Executable
Code in selected EXEs and DLLs.
Virtual Memory Counts
Displays the following statistics on Virtual Memory usage:
Working Set
Average amount of virtual memory used by the process. The longer a process has been running, the more accurate this value is.
Peak Working Set
Maximum value attained by the Working Set described above.
Private Pages
Number of pages marked as private.
Virtual Size
Current size of virtual memory for this process.
Peak Virtual Size
Maximum size of virtual memory for this process.
Fault Count
Number of page faults. Each page fault represents an attempt to access memory at an address that was not in physical memory.
Paged
Number of pages currently in the swap file.
Peak Paged
Maximum number of pages currently in the swap file.
Non-Paged
Number of pages that have not been moved to the swap file.


Introducing WinDbg
The WinDbg debugger is a powerful, graphically based tool that allows you to debug programs and edit source code under Windows NT. Its user interface is similar to Microsoft QuickC for Windows 1.0, but the debugger has been significantly enhanced to allow more flexible debugging and to provide full support for the NT operating system.
You can use WinDbg to debug kernel-mode drivers.
This introduction explains how to install WinDbg and briefly introduces the WinDbg debugger. It describes starting and quitting WinDbg, using WinDbg windows, and customizing WinDbg.


Installing WinDbg
The WinDbg files are copied with other development files from the NT SDK CD-ROM. By default, the files are held in the MSTOOLS\BIN directory. You can use the SDK SETUP program to install WinDbg.


Starting and Quitting WinDbg
After you have installed WinDbg, start it by double-clicking its icon on the Program Manager. You can also start WinDbg from the Windows NT command line by typing
windbg
 [-a] [-g] [-h] [-i] [-k[
platform
port
speed
]] [-l[
text
]] [-m] [-p
id
 [-e
event
]] [-s[
pipe
]] [-v] [-w
name
 ] [-y
path
] [-z
crashfile
] [
filename
[.
ext
] [
arguments
]]
The following table describes the command-line options.
WinDbg Command-Line Options
Option
Description
-a
Ignore all bad symbols (but still print warning message).
-g
Go now; start executing the process.
-h
Causes child processes to inherit access to WinDbg's handles.
-i
Ignore workspace; like running without any registry data.
-k
 [
platform port speed
]
Run as a kernel debugger with the specified options:
platform
 is the target computer type (i386, mips, alpha)
port
 is the com port (com1 ... com
n
)
speed
 is the com port speed (9600, 19200, 57600, ...)
-l
 [
text
]
Sets the window title for WinDbg.
-m
Start WinDbg minimized.
-p
id
Attach to the process with the given id.
-e
event
Signal an event after process is attached. Used only for post-mortem debugging (AeDebug).
-s
 [
pipe
]
Start a remote.EXE server, using the named pipe.
-v
Verbose option; WinDbg prints module load and unload messages.
-w
name
Load the named workspace.
-y
path
Search for symbols along the specified path. You can specify multiple paths by separating them with semicolons.
-z
crashfile
Debug the specified crash dump file.
filename
[.
ext
]
Program to debug or file to edit. If no extension is specified, WinDbg assumes an .EXE extension. If the file is not an .EXE or .COM file, WinDbg will try to load it as a text file.
arguments
Arguments to program being debugged.
To quit WinDbg, choose Exit from the File menu. This returns you to the Windows NT Program Manager.


WinDbg Windows
WinDbg uses windows to present and enter information. These windows are like standard windows in other applications for Windows.


The Toolbar
The Toolbar appears beneath the menu bar (see the figure below). It provides shortcuts for menu selections.
You can hide or display the Toolbar with the Toolbar command on the View menu. When this command is checked, the Toolbar appears. When it is turned off (unchecked), the Toolbar is hidden. You turn the command on or off by selecting it.
To issue debug commands, click one of the icons on the Toolbar:
Icon
Action
Starts or continues execution. Execution proceeds until the program reaches a breakpoint or the program ends. All threads and processes are unfrozen. Equivalent to the Go command from the Run menu.
Stops the program and its threads, allowing you to regain control of the debugger. Equivalent to the Halt command from the Run menu.
Sets a breakpoint at the current line.
Displays the Quickwatch debugging dialog box. Equivalent to the Quickwatch command from the Debug menu.
Steps into a function when it is called and steps through all of the instructions in the function. Equivalent to the Trace Into command from the Run menu.
Single-steps through instructions in the program. If this command is used when you reach a function call, the function is executed without stepping through the function instructions. Equivalent to the Step Over command from the Run menu.
Switches between source and assembly mode. Equivalent to switching modes with the Toggle Source/Asm Mode command from the Run menu.
Switches between source and assembly mode. Equivalent to switching modes with the Toggle Source/Asm Mode command from the Run menu.
Opens the Options dialog, if any, for the current window.
When a button cannot be used (for example, a trace command while the debuggee is running), the button is grayed.
Font selection is not available from the toolbar. You can change the typeface of the current source file by choosing Font from the Options menu.


The Status Bar
A status bar (see the figure below) appears at the bottom of the main WinDbg window. The status bar provides information about WinDbg and the active source window, such as line and column position and editor mode. When debugging, the status bar will also give the WinDbg process ID (PID) and thread ID (TID) of the code being debugged.
The status bar displays the following information:
Contents
Description
Message box
Displays messages from the environment.
SRC/ASM
Indicates whether WinDbg is in source or assembly mode.
pid
Shows the ID number of the process being debugged.
tid
Shows the ID number of the thread being debugged.
^Q
Indicates a WordStar keystroke sequence.
OVR
Indicates overtype mode.
READ
Indicates read-only status.
CAPS
Indicates that CAPS LOCK is on.
NUM
Indicates that NUM LOCK is on.
Line
Displays the line number at the insertion point in the current window.
Column
Displays the column number at the insertion point in the current window.
You can hide or display the status bar with the Status Bar command on the View menu. When this command is checked, the status bar appears. When it is turned off (unchecked), the status bar is hidden. Turn the command on or off by selecting it.


Customizing WinDbg
Many parts of WinDbg can be customized to suit your programming needs. This section discusses how you can modify the appearance and functionality of WinDbg.


Using the Program Registry
To start debugging a program from within WinDbg, you must first add it to the program registry (or use the
.ATTACH
 command). The WinDbg program registry is a list of programs that WinDbg can debug. Each program in the registry has one or more workspaces associated with it. A workspace is a set of WinDbg defaults that can be associated with a program.
To add a program to the registry
1.
Choose Open from the Program menu.
The Program Open dialog will appear with a list of all of the programs in the registry.
2.
Choose New.
The common Open dialog will appear.
3.
Open the executable file that you want to debug, and choose OK.
The dialog boxes will close. WinDbg is now ready to begin debugging.
To load a program already in the registry
1.
Choose Open from the Program menu.
The Program Open dialog will appear with a list of all of the programs in the registry.
2.
Select the program to debug from the Programs list.
3.
Select the workspace to use from the Workspaces list.
For more information on workspaces, see the following section, "Using Workspaces."
4.
Choose OK.
To delete a program
1.
Choose Delete from the Program menu.
2.
In the Program box, select the program that you want to delete.
3.
Choose Delete. The selected program will disappear.
4.
Choose OK.


Using Workspaces
With workspaces, you can save and restore the state of WinDbg between debugging sessions and customize WinDbg for different debugging situations. Workspaces are saved in the Windows NT registry for each user.
When you debug a program for the first time or start WinDbg without loading a debuggee, you start with the Common Workspace. The Common Workspace is different from other workspaces because it is not associated with a particular program, but is available at all times. You can use the Common Workspace as a starting point for custom workspaces that are saved with each program.
You can change the Common Workspace to reflect your preferences for WinDbg.
To change the Common Workspace
1.
Configure WinDbg windows and options.
2.
Choose Save Common from the Program menu.
Note
  Since the Common Workspace does not correspond to a specific program, breakpoints, watch expressions, and other program-specific information are not saved.
To create a new workspace
1.
Load a debuggee using Open from the Program menu.
2.
Configure WinDbg windows, breakpoints, and options.
3.
Choose Save As from the Program menu.
4.
Enter a name for the workspace.
If you check the Make Default box, the workspace will be saved with the given name, and it will be made the default workspace for the program when the Program Open Dialog box is next used.
5.
Choose OK.
To delete a workspace
1.
Choose Delete from the Program menu.
2.
In the Program box, select the program that has the workspace that you want to delete.
3.
In the Workspace box, select the workspaces that you want to delete.
4.
Choose Delete. The selected workspaces will disappear.
5.
Choose OK.


Changing Display Colors
Using different colors for various language elements such as functions and variables gives you immediate visual cues about the structure of your source code. You can change the default colors of these elements as well as the color of other text in WinDbg, such as reserved words, breakpoints, and information windows.
To change the colors in the source window
1.
From the Options menu, choose Color. The Color dialog box appears.
2.
From the Items list select the item you want to change. For this example, select Source Window.
3.
Select the color square from the palette to represent the foreground color. Press Set Foreground. The new color combination is shown in the Items box.
4.
Select the color square to represent the background color from the palette shown. Press Set Background. The new color combination is shown in the Items box.
5.
Choose OK to apply the change to the source window. You can change several items in the list before choosing OK.
To change the source window back to its original colors
1.
From the Options menu, choose Color.
2.
From the Items list, select Source Window.
3.
Choose Set Default.
4.
Choose OK.
To change all windows back to their default colors
1.
From the Options menu, choose Color.
2.
Choose Select All.
3.
Choose Set Default.
4.
Choose OK.


Setting Font Type and Size
You can specify which font type and size appear in WinDbg source windows. You can choose any font type and size found within the Windows NT system.
To set the font type and size
1.
From the Options menu, choose Font. The Font dialog box appears.
2.
Select the font, font style, and size from the combo boxes. The words "sample text" will change to the font you selected.
3.
Choose OK.
The Make Default box in the Font dialog box sets the selected font and size as the default.
Text within the source window can be only one font and size. Multiple fonts cannot be displayed in the same source window.


Debugging Programs
The WinDbg debugger lets you analyze the internal workings of your program by using the debugger to set breakpoints and examine variables. In this section, you use the GENERIC program to learn debugging strategies and techniques within WinDbg.
WinDbg supports debugging of EXEs and DLLs for Windows NT. This section describes how to debug an .EXE project. If you want to debug a .DLL project, you must create an appropriate .EXE shell program to call the DLL. Load the calling program from the command line or with the Open command from the Program Menu, then run the EXE with the Go command.


Using Debugging Information Windows
WinDbg displays information in a series of windows that you can view as you debug a program. You activate these windows with commands from the Window menu.
These are the windows and information they show:
Window
Information
Watch
Monitor expressions set with the Watch Expression command.
Locals
Values of local variables within the function currently being stepped through.
Registers
Current contents of the CPU registers.
Disassembly
Assembly-language instructions being debugged.
Command
Allows you to enter debugger commands with the keyboard. These commands are described in
Command Window Interface
.
Floating-Point Registers
Current contents of floating-point registers and stack.
Memory
Current contents of memory. Display format controlled by Memory Options dialog box.
Calls
Displays the current call stack and lets you jump to any stack frame displayed.
You can size and minimize these windows during debugging so that you can see various types of information at one time.


Using the WinDbg Debugger
WinDbg lets you set breakpoints in the source code; view variables, memory, and registers; and control program execution.


Preparing a Debug Version of a Program
Before a program can be debugged, you must include debugging information with the project.
To build the GENERIC project for debugging
1.
Open a command-line session with the Windows NT Program Manager.
2.
Move to the directory containing the GENERIC example program.
3.
Build the executable by typing
NMAKE /A
4.
Load the executable into WinDbg by typing
WINDBG GENERIC.EXE
Note
If there are errors during the build, make sure that the build tools are in your path and that the INCLUDE and LIB environment variables point to the directories containing the system .H and .LIB files respectively.


Setting and Removing Breakpoints
Breakpoints are useful when you have a general idea of where a bug occurs in a program. WinDbg runs until it reaches a breakpoint, then stops. You can then step to the next line of code or trace through a function until you find the problem.
To set a breakpoint in the GENERIC program
1.
Move the insertion point to the first line of the
About
 function in the source code.
2.
From the Debug menu, choose Breakpoints. The Breakpoints dialog box appears. (See the figure below.)
3.
From the Break list, select at Location.
4.
Choose Add.
5.
Choose OK.
6.
Choose Go from the Run menu. The GENERIC program begins to run.
7.
While the program is running, choose About Generic from its Help menu. The program stops and the breakpoint line is highlighted in the source window.
To remove a breakpoint
1.
From the Debug menu, choose Breakpoints. The Breakpoints dialog box appears. (See the figure above.)
2.
Select the breakpoint to remove from the Breakpoints list.
3.
Choose Delete.
4.
Choose OK.
The Breakpoints dialog box offers a variety of options for setting breakpoints. You can set breakpoints based on Windows messages, memory location, and the values in an expression. See the WinDbg online help for details.


Controlling Program Execution
Once a breakpoint is reached and the program stops, you can control execution with commands on the Run menu. The following list shows the commands and their actions.
Command
Action
Restart
Resets execution to the first line of the program. It reloads the program into memory and discards the current values of all variables.
Stop Debugging
Terminates the debugging session and returns to a normal editing session.
Go
Executes code from the current statement until a breakpoint or the end of the program is reached.
Continue to Cursor
Executes the program as far as the line that currently has the cursor. This is equivalent to setting a temporary breakpoint at the cursor location.
Trace Into
Steps into a function when it is called and steps through all of the instructions in the function.
Step Over
Single-steps through instructions in the program. If this command is used when you reach a function call, the function is executed without stepping through the function instructions.
Set Thread
Selects thread to monitor with the debugger. This determines which thread receives debugger commands and is viewed by the display windows. Also freezes and thaws individual threads.
Set Process
Selects process to monitor with the debugger. This determines which process receives debugger commands and is viewed by the display windows.
Source/Asm Mode
Toggles between source and assembly modes.


Using Watch Expressions
The Watch Expressions command shows a variable's name and value in the Watch window. It updates the window whenever the variable's value changes. This feature is useful during debugging to check the value of a variable. You can enter expressions as well as variables.
To add a watch variable
1.
In the GENERIC program, select the
message
variable in the
 About
 function.
2.
From the Debug menu, choose Watch Expression. The selected
message
variable appears in the Watch Expression text box.
3.
Choose Add.
4.
Choose OK. The Watch window opens, and it includes the
message
variable.
5.
Resize the Watch window so it is visible with the source window displayed.
6.
With the breakpoint in the GENERIC program still in place, choose Go from the Run menu. The
message
variable is updated to show its new value.
To remove the
message
variable from the Watch Expression list
1.
From the Debug menu, choose Watch Expression.
2.
Select
Message
from the Watch Expression list.
3.
Choose Delete.
4.
Choose Close.


Using Quickwatch
Quickwatch gives you a fast way to view variables and expressions. Unlike Watch Expressions, which are stored in the Watch window, the values of Quickwatch variables and expressions appear only in the Quickwatch dialog box (see the figure below.) This is useful in exploratory debugging where you are checking a number of variables that are suspect.
To use Quickwatch
1.
With the breakpoint in the
About
procedure, run the GENERIC program, open the Help menu of the Generic Sample Application, and select the About Generic command.
2.
Move the insertion point in the source file to the
message
variable in the
About
function.
3.
From the Debug menu, choose Quickwatch. You can also use the Quickwatch button on the Toolbar.
4.
Choose Cancel to close the Quickwatch dialog box.
The Quickwatch dialog box also lists commands that you can use to evaluate expressions, add variables and expressions to the Watch Expression list, contract and expand structures, and modify values.


Using the Command Window
With the Command window, you can use the keyboard instead of the mouse to operate the debugger using CodeView-style commands.
See the WinDbg online help or
Command Window Interface
 for a detailed list of the commands available in the Command window.
To debug a program from the Command Window
1.
Open the Command window by choosing Command from the Window menu.
2.
Reset the program counter by choosing Restart from the Run Menu.
3.
Type
bl
 in the command window to list breakpoints. You should see the breakpoint in the
About
procedure.
4.
Type
g
 to start program execution. After the program begins, open the Help menu of the Generic Sample Application, and select the About Generic command.
5.
Type
dc
 to display the assembly language instructions following the breakpoint.


Postmortem Debugging with WinDbg
When a program crashes (for example, after a general-protection fault), Windows NT automatically invokes a debugger that is specified in the registry. To make WinDbg be that debugger, use REGEDT32.EXE to edit the following registry key:
HKEY_LOCAL_MACHINE
SOFTWARE
Microsoft
Windows NT
CurrentVersion
AeDebug
Add or edit the Debugger value entry (REG_SZ). Give it the following string value:
windbg -p %ld -e %ld
You can also use the Attach command from the Run menu to attach the debugger to a process that is already running.


Remote Debugging
Remote debugging lets you debug a program from another computer. You run WinDbg on one computer (the
host
) and install the program you are debugging on another (the
target
). You run a remote monitor program (WinDbgRm) on the target computer to control the program you are debugging. WinDbgRm communicates with WinDbg across a serial cable or across the network.
Remote debugging isolates WinDbg from the program being debugged so that errors in the program do not affect the debugger, and the debugger does not affect the target system. If the program crashes the remote system, your development system continues to run.
The remote monitor demands fewer system resources, and after starting and loading the program to be debugged, it does not use the file system. Therefore, the monitor has no effect on the resources that can change your program's behavior.
You can debug large programs or programs that destabilize the operating system. You can also debug programs on smaller systems that cannot support the full debugger. Some bugs that you cannot reproduce while running under the full debugger can appear under the remote monitor. Remote debugging also allows the debugging of Win32 programs on Win32s
™
, since WinDbg will not run on Win32s.
The process of debugging a program on a remote computer is almost the same as for local debugging. The only difference is in how you start the session. The following sections describe the hardware and files required for remote debugging and how to configure the debugger components on the host and target computers.


Requirements
Remote debugging requires two computers, the host running Microsoft Windows NT and the target running under Windows NT or Win32s. Serial debugging requires a serial port connecting the host and target computers (this is the only connection allowed when debugging Win32s applications). Debugging through a named pipe requires that both computers be connected to a common network that is supported by Windows NT. Network debugging is faster and does not require a special cable between the two systems.
To remotely debug using the serial ports, connect the host and target computers with a null-modem cable plugged into the serial ports on the two computers. A null modem is a serial cable that connects the transmitting line at each end to the receiving line at the opposite end. You cannot use an extension cable with "straight-through" connections.
Most computer stores stock or can assemble a null-modem cable for you with the correct wiring and the appropriate connectors for your host and target computers.


Starting a Remote Debugging Session
After the WinDbg components are in their locations and properly configured, you can begin a remote debugging session.
To start a remote debugging session
1.
If you are debugging across a serial cable, connect the cable to both the target and host.
2.
On the target computer:
·
Install your program and its DLLs. You do not need to have the source files on the target.
·
Start WinDbgRm.
·
WinDbgRm starts minimized as an icon. Its default is to communicate with WinDbg across the network, using the named pipe "windbg". If you want to change how the host and target communicate, double-click on the WinDbgRm icon and select the Transport DLL command from the Options menu. Choose the appropriate transport layer in the Known Transport Layers list box.
3.
On the host computer:
·
Start WinDbg from the Windows NT command prompt:
start windbg
yourprog
.exe
·
Use the Debugger DLLs command from the Options menu to change the transport layer to match the one used by WinDbgRm on the target. If you are using named pipes, use the Change button to modify the transport layer parameters so that the first parameter is the name of the target computer.
·
Select the Execution Model and Expression Evaluator to reflect the target computer.
·
Use the User DLLs command from the Options menu to specify the symbol search path to your program's symbols; use the Debug command from the Options menu to specify the source search path to your source files.
·
Select Go from the Run menu.
If you can start your program on the target before attaching the debugger to it, then you can change step 3 as follows:
On the host computer:
·
Start WinDbg.
·
Use the Debugger DLLs command from the Options menu to change the transport layer to match the one used by WinDbgRm on the target. If you are using named pipes, use the Change button to modify the transport layer parameters so that the first parameter is the name of the target computer.
·
Select the Execution Model and Expression Evaluator to reflect the target computer.
·
Use the User DLLs command from the Options menu to specify the symbol search path to your program's symbols; use the Debug command from the Options menu to specify the source search path to your source files.
·
Select the Attach command from the Run menu.
·
Select your program from the task list that the Attach command displays.
To connect to a computer with an IPC password, use the Windows NT NET USE command to manually connect to the remote IPC$ share.
Use the .disconnect command to disconnect the host from the target. Use the .attach command to reestablish the connection. Another computer can run WinDbg and use .attach to connect to the target and debug your program. If you are still connected and another computer tries to connect to the target, you will receive a popup notifying you of that fact. You have 20 seconds to cancel the pop-up, then you will be disconnected and the other computer will be connected as the host of the remote debugging session.
If problems occur, check connections and make sure that WinDbg and WinDbgRm are using the same communications methods. If your system has trouble maintaining the communications link between the host and target computers, when communicating through a serial port, reduce the transmission baud rate.


Using the Editor
Use the WinDbg integrated text editor to edit source files. Writing text with the WinDbg editor is similar to using most other editors. For example, to start a new line, press
ENTER
; to leave a blank line between lines, press
ENTER
 twice; If you make a mistake while typing, press
BACKSPACE
 to delete the error.
This section provides information on how to edit source files. Most of the procedures, such as file and text handling and moving around in a file, follow basic Windows editing conventions.


Managing Source Files
This section explains how to create, save, open, and close a file. To familiarize yourself with the steps, you can use the sample program below. You can also use this program to try the other editing features described in this section.
/* first sample program */
#include <stdio.h>
main()
{
     printf("Windows NT console I/O is easy!\n");
}


Opening and Closing Source Files
To create a new source file
1.
Choose New from the File menu.
2.
Type your program into the new window.
New files are labeled "UNTITLED
n
" until they are saved.
Note
  Before you can save or close a window it must be active. To make a window active, either click on the window or select the window name or number from the Window menu.
To open an existing source file
1.
From the File menu, choose Open.
2.
If the file is on a network share, click the Network button to select the share.
3.
Choose a drive from the Drives list box. The default drive is the current drive.
4.
From the Directories list box, double-click a directory where the file is stored (or down a directory path to the directory where the file is stored.)
5.
Choose a file type in the List Files of Type box. Only files with the chosen extension(s) are displayed in the File Name box.
6.
Double-click a filename, or click a filename and choose OK.
The names of the four most recently opened files are displayed at the end of the File menu. To open one of these files, choose its name from the menu.
Because the editor works with any ASCII file, you can open and edit text files created with other editors.
When a source file is opened, its name is added to the Window menu. If you want to see more than one view of your source file, use the New Window command on the Window menu to open another view. A file can be opened only once; if you try to open a file that is already open, the file's window will activate, but the file will not be reloaded. You can, however, open multiple windows showing the same source file, so that you can, for instance, compare two different sections of the file. If more than one copy of the file is displayed, the window is titled
filename
:
x
, where
x
 is a unique window number.
To save a source file
1.
Activate the source window.
2.
From the File menu, choose Save.
3.
If your file is unnamed, WinDbg displays the Save As dialog box. Enter the file's name. If you are using the sample program, name the file FIRST.C.
4.
Select the drive and the directory to save the file to by choosing items from the Drives and Directories list boxes.
5.
Choose OK.
If the file has already been named, the Save command saves any changes without displaying the Save As dialog box.
The title bar will display an asterisk (
*
) when the source file has been modified.
To save a source file under a different name
1.
Activate the source window.
2.
From the File menu, choose Save As.
3.
Type a new name for the file.
4.
Choose OK.
This is useful for maintaining revised copies of a source file while keeping the original unchanged. You can also use the Save As command to name and save a newly created file.
To save all open source files that are new or have been changed
·
Choose Save All from the File menu.
To close a source file
1.
Activate the source window.
2.
From the File menu, choose Close.
If you are using the sample program, use one of these techniques to close the FIRST.C source window.
If you create a new source file or modify an existing file and try to close it before saving, a message appears asking if you want to save the changes before closing.
To activate a source window
·
Click the title bar.
-
 Or
-
·
Select it from the Window menu.
-
 Or
-
·
Use the shortcut key listed on the title bar (
ALT
+ #
 for windows 0
-
 9,
ALT
+
CTRL
+ #
 for windows 10
-
 19).
-
 Or
-
·
Use
CTRL
+
F6
 to cycle through all active windows.
To close a source window
1.
Activate the source window.
2.
Double-click the document Control-menu box.
-
 or
-
Press
CTRL
+
F4
.


Merging Source Files
The Merge command inserts another file at the insertion point. You can also use the command to replace selected text within the active source window with the contents of another file.
To merge source files
1.
Move the insertion point where you want to merge text, or select the text you want to replace.
2.
From the File menu, choose Merge. The Merge dialog box appears.
3.
Select the drive and directory where the source file to be inserted is stored. The default is the current drive and directory.
4.
Select the type of file to display.
5.
Type a filename or select the name from the list of files.
6.
Choose OK to merge the specified file at the insertion point.
As an alternative you can open a file with the editor and copy and paste text to another file.


Moving Around Source Files
This section discusses some special techniques for moving around source files in WinDbg.
To move to a specific line within the source window
1.
From the View menu, choose Goto Line. The Line dialog box appears.
2.
Enter the line number you wish to move to.
3.
Choose OK.
To set a tag in the source window
1.
Move the insertion point to the line where you want to set a tag.
2.
From the View menu, choose Toggle Tag. The tagged line is highlighted.
You can tag frequently accessed lines in your source file and use menu commands to move quickly to them. Tags can be cleared when you no longer need them.
To clear a tag
1.
Move the insertion point to the tagged line.
2.
From the View menu, choose Toggle Tag. The tag and the highlight are removed.
To remove all tags in a window, choose Clear All Tags from the View menu.
To move to the next tag after the insertion point
·
From the View menu, choose Next Tag, or press
F2
.
To move to the previous tag before the insertion point
·
From the View menu, choose Previous Tag, or press
SHIFT
+
F2
.


Using the Keyboard Commands
The editor includes a number of special keystrokes for editing and moving around in a source file. These are in addition to the familiar
ARROW
 keys,
SPACEBAR
, and
ENTER
.
To move to
Press
Word to left
CTRL+LEFT ARROW
Word to right
CTRL+RIGHT ARROW
Beginning of current line
HOME
End of current line
END
Beginning of file
CTRL+HOME
End of file
CTRL+END
See online Help for the complete set of WinDbg keyboard commands.


Controlling the Source Window
The editor features a number of options that affect the source window. These include the ability to set tabs, highlight language syntax within the window, and make the file read-only.


Setting Tabs
You can set tab stops in a source file and save them as tabs or spaces when you save the file.
To set tabs
1.
Choose Environment from the Options menu. The Environment dialog box appears.
2.
Enter the number of spaces to be used as a tab stop in the Tab Stops text box.
3.
Choose the Keep Tabs option to treat tabs as a single tab character when the source file is saved.
-
 or
-
Choose Insert Spaces to convert tabs to the number of spaces shown in the Tab Stops box.
4.
Choose OK.


Highlighting Language Syntax
WinDbg highlights language keywords, identifiers, comments, and strings in different colors. This feature is useful when learning a language or when viewing lengthy and complex source files. For example, if you are editing a file with a .C extension, all C keywords are highlighted.


Making a File Read-Only
The Read Only command makes the active source window read-only. When you choose this command, the window cannot be altered.
This command is useful when you are viewing a program and don't want to accidentally make any changes to the window.
To make a source window read-only
1.
Activate the window.
2.
From the Edit menu, choose Read Only.
To deactivate the command, choose it again.
A check mark next to the Read Only menu item and the word READ in the status bar at the bottom of the screen indicate that the source file is read-only.


Finding and Replacing
The WinDbg editor offers advanced find and replace capabilities. You can search for literal text or use regular expressions to find words or characters in the source window.
The Find command searches for specified text. The Replace command finds the text and replaces it with other text.


Finding Text
To find a character, word, or group of characters in the active source window
1.
Position the insertion point where you want to start the search.
2.
From the Edit menu, choose Find. The Find dialog box appears.
3.
In the Find What box, type the text you want to find, or choose from the 16 previous instances of text searched for, which are listed in the drop-down box.
4.
Choose any of the Find options, as described below.
5.
Choose OK.
When you choose the Find command, the editor uses the location of the insertion point to select a default search string. If the insertion point is inside a word, that word is displayed as the search text in the Find What box.
If the insertion point is between words, the word to the right is displayed. If there is no word to the right, the word to the left is displayed. If that is not possible, nothing is displayed.
The Find dialog box has these choices for locating text:
Command
Description
Match Whole Word Only
Searches for complete occurrences of the text. A word contains only the characters a
-
 z and A
-
 Z, the numbers 0
-
 9, and the # or _ (underscore) characters. If you don't select this option, the editor finds embedded occurrences; for example, "main" in "remainder".
Match Case
Searches for text that matches the capitalization of the search text.
Regular Expression
Finds text using patterns. See the WinDbg help file for details on regular expressions.
Direction
The Up option searches from the insertion point to the beginning of the file. The Down option searches from the insertion point to the end of the file.
Tag All
Searches for text and marks each line that contains the text. Use the Tag commands from the View menu to move to each marked line.
If the text is located, the source window scrolls to the text and highlights it. Choose Find Next from the abbreviated Find dialog box to move to the next occurrence of the text.


Replacing Text
To find and replace text
1.
From the Edit menu, choose Replace. The Replace dialog box appears.
2.
In the Find What box, type the search text or regular expression, or choose from the 16 previous instances of text searched for, which are listed in the drop-down box.
3.
In the Replace With box, type the replacement text, or choose from the 16 previous instances of text searched for, which are listed in the drop-down box.
4.
Set any change options you need. These options are the same as those in the Find dialog box (see the previous section, "Finding Text").
5.
Choose OK.
For information on default search strings, see the previous section, "Finding Text."
To repeat the last search or search and replace
·
Choose Find Next in the abbreviated Find or Replace dialog box. The abbreviated dialog box remains active until the search reaches the starting location (after wrapping) or until you choose Cancel.


Command Window Interface
This section describes the commands that you can run in the Command window. It describes the commands that apply to debugging user-mode applications, as well as those that apply to debugging kernel-mode drivers.
You can use standard editing keys when you enter a command. Use the
UP ARROW
 and
DOWN ARROW
 keys to retrieve previous commands. Edit the current command line with the
BACKSPACE
,
DELETE
,
INSERT
, and
LEFT ARROW
 and
RIGHT ARROW
 keys. Press the
ESC
 key to clear the current line.
To copy text from a previous line in the Command window, highlight the text by holding down the left mouse button and dragging the mouse pointer. Click the right mouse button to copy the highlighted text to the Clipboard. Click the right button again to paste the text into the current command line. You can use the same technique to copy text from other windows to the Command window. You can also press
CTRL
+
INS
 to copy highlighted text to the Clipboard and press
SHIFT
+
INS
 to paste text from the Clipboard to the insertion point.


Command Conventions
Many commands in this section use a specific range syntax or process and thread syntax.


Range Syntax
You can specify a range as either of the following:
·
startaddress endaddress
·
startaddress
L
length
With the first method, you specify the start and end addresses of the range. With the second method, you specify the start address, the letter "L," and the number of data items in the range.
Note
  With the
DC
 (Display Memory) and the
U
 (Unassemble) commands, you can also use the following to dump
line
 instructions starting at
startaddress
:
startaddress
I
line


Process and Thread Syntax
You can specify a process in the following ways:
Symbol
Description
|.
The current process.
|number
The process number.
|*
All processes.
You can specify a thread in the following ways:
Symbol
Description
~.
The current thread.
~number
The thread ID.
~*
All threads.
If you do not specify a process or thread with a command, the command will act on the current process or thread. To set the current process or thread, enter a process or thread specifier alone on a command line.
To display the state of the processes or threads, type pipeline (|) or tilde (~) alone on the command line.
In kernel debugging, threads represent the physical processors of the target computer: a two-processor computer would have two threads, one for each processor. The single process represents the target computer itself.


Command List
The following table lists the commands that you can run in the Command window:
Command
Definition
*
Comment
;
Command Separator
?
Evaluate Expression
!
User Extension DLL
|
Display Process State
~
Display Thread State
#
Search for Disassembly Pattern
%
Change Context
.attach
Attach to Process
.cache
Cache Size
.list
Display Source/Assembly Listing
.logappend
Append Log File
.logclose
Close Log File
.logopen
Open Log File
.reboot
Reboot Target Machine
.reload
Reload Symbols
BC
Breakpoint Clear
BD
Breakpoint Disable
BE
Breakpoint Enable
BL
Breakpoint List
BP
Set Breakpoint
C
Compare Memory
DA, DB, DC, DD, DI, DS, DT, DU, DW
Display Memory
EA, EB, ED, EI, ES, ET, EU, EW
Enter Values
F
Freeze Thread
FIA, FIB, FID, FII, FIS, FIT, FIU, FIW
Fill Memory
FR
Floating-Point Registers
G
Go
GH
Go-- Exception Handled
GN
Go-- Exception not Handled
K, KB, KN, KS, KV
Display Stack Backtrace
L
Restart Debuggee
LM
List Loaded Modules
LN
List Nearest Symbols
M
Move Memory
N
Set Number Base
P
Program Step
Q
Quit WinDbg
R
Registers
REMOTE
Start Remote Server
RT
Register Display Toggle
S+, S-
Set Source/Assembly Mode
SA, SB, SD, SI, SS, ST, SU, SW
Search Memory
SEB, SEW
Set Error Break, Set Error Warning
SX, SXD, SXE, SXN
Set Exceptions
T
Trace
U
Unassemble
X
Examine Symbols
Z
Unfreeze Thread


* (Comment)
Syntax
*
Description
If this character is at the start of a line, then the rest of the line is treated as a comment.


; (Command Separator)
Syntax
;
Description
Use this character to separate multiple commands on a single line. Commands are executed sequentially from left to right. All commands on a single line refer to the current thread, unless otherwise specified. If a command causes the thread to execute, the remaining commands on the line will be deferred until that thread stops on a debug event.


? (Evaluate Expression)
Syntax
?
expression
[
,
format
]
Parameters
expression
Expression to be evaluated with the expression evaluator.
format
C-style format characters. For example, to display a long int, use
LI
 as the
format
 specifier. Do not use percent signs (
%
).
Description
Evaluates and displays the value of the expression or symbol in the context of the current thread and process.
Note
  The C++ expression evaluator cannot calculate expressions that use the conditional operator (
?:
).


! (User Extension DLL)
Syntax
!
 [
filename
.
]
function
 [
string
]
Parameters
filename
Name of the DLL to call (without the .DLL extension), followed by a period (.). The default filename is NTSDEXTS.DLL.
In kernel debugging, the default extension DLL depends upon the target platform:
Target platform
Default extension DLL
x86
KDEXTX86.DLL
MIPS
KDEXTMIP.DLL
ALPHA
KDEXTALP.DLL
function
Name of the DLL function to call.
string
String to pass to the DLL function.
Description
Calls a DLL function from WinDbg. Use this command to call special routines while debugging. For a complete list of the built-in extension commands, enter
!?
at the WinDbg prompt.


# (Search for Disassembly Pattern)
Syntax
#
 [pattern] [address]
Parameters
pattern
The pattern to search for in the Disassembly window.
address
The address after which to search.
Description
Displays the first line of assembly code after
address
 that contains the specified pattern.


% (Change Context)
Syntax
%
[
frame
]
Parameters
frame
The number of the frame on the call stack to change context to. The current procedure is number 0 on the stack.
Description
Changes the context to the specified frame. Updates the Locals window with the variables of the new frame.
Use the
KN
 command to list the call stack with the frame numbers.


.
ATTACH
 (Attach to Process)
Syntax
.ATTACH
process
Parameter
process
Process ID of task to debug.
Description
Starts debugging the process specified by
process
. You can use PView to find process IDs of running programs or use the
Attach
 command from the Run menu to select a task.
This command is similar to the
/P
 command-line option.


.CACHE (Cache Size)
Syntax
.CACHE
 [
cachesize
]
Parameter
cachesize
The size of the kernel debugging cache, in MB. If you do not specify
cachesize
, the command displays the status of the cache. If you issue
.cache 0
, the cache is disabled.
Description
Sets the size of the cache for WinDbg KD to use for memory values. Normal operations, such as single-stepping or the
G
 command, invalidate the cache. If WinDbg KD has frozen the target computer, but hardware on the target can change memory (for example, through shared memory or DMA), you must disable the cache to see the memory changes.


.LIST (Display Source/Assembly Listing)
Syntax
.LIST
 [
address
]
Parameter
address
The address at which to start displaying the listing.
Description
Displays source-code lines and their corresponding assembly code, starting at
address
. If you do not specify
address
, the display starts from the current address.


.
LOGAPPEND
 (Append Log file)
Syntax
.
LOGAPPEND
 [
filename
]
Parameter
filename
Filename of the log file. The default filename is WINDBG.LOG.
Description
Sends a copy of the events and commands from the Command window to the given log file. If you are already logging, that log file will be closed. If
filename
 already exists, new information will be appended to it.


.LOGCLOSE
Syntax
.
LOGCLOSE
Description
Closes any currently open log file.


.LOGOPEN (Open Log File)
Syntax
.
LOGOPEN
 [
filename
]
Parameter
filename
Filename of the log file. The default filename is WINDBG.LOG.
Description
Sends a copy of the events and commands from the Command window to the given log file. If you are already logging, the current log file will be closed. If
filename
 already exists, its contents will be overwritten.


.REBOOT (Reboot Target Machine)
Syntax
.REBOOT
Description
Reboots the target computer (WinDbg KD only).


.RELOAD (Reload Symbols)
Syntax
.RELOAD
 [
modulename
]
Parameter
modulename
The name of the module whose symbols you want to reload.
Description
Loads symbols for the specified module on the target system. If you do not specify
modulename
, the symbols for all loaded modules will be reloaded. This command is useful in the event of a system crash, which can result in the loss of symbols for the target computer.


BC (Breakpoint Clear)
Syntax
BC
 {
breakpoint
 [
breakpoint
...] |
*
}
Parameter
breakpoint
The number of the breakpoint to be cleared. Use the Breakpoint List (
BL
) command to display currently set breakpoints and their numbers. Specify ranges of breakpoints with a hyphen. Separate multiple breakpoints with spaces or commas.
Description
Removes one or more previously set breakpoints from the system.
BC*
 clears all breakpoints.


BD (Breakpoint Disable)
Syntax
BD
 {
breakpoint
 [
breakpoint
...] |
*
}
Parameter
breakpoint
The number of the breakpoint to be disabled. Use the Breakpoint List (
BL
) command to display currently set breakpoints and their numbers. Specify ranges of breakpoints with a hyphen. Separate multiple breakpoints with spaces or commas.
Description
Disables, but does not delete, one or more breakpoints.
BD*
 disables all breakpoints. While a breakpoint is disabled, the system does not check to see if the conditions specified in the breakpoint are valid.
Use the Breakpoint Enable (
BE
) command to reenable a disabled breakpoint.


BE
(
Breakpoint Enable)
Syntax
BE
 {
breakpoint
 [
breakpoint
...] |
*
}
Parameter
breakpoint
The number of the breakpoint to be enabled. Use the Breakpoint List (
BL
) command to display currently set breakpoints and their numbers. Specify ranges of breakpoints with a hyphen. Separate multiple breakpoints with spaces or commas.
Description
Restores one or more breakpoints that were temporarily disabled by the Breakpoint Disable (
BD
)
command.
BE*
 enables all breakpoints.


BL (Breakpoint List)
Syntax
BL
Description
Lists all breakpoints. For each breakpoint, the command displays the following:
·
The breakpoint number
·
The breakpoint status, where "E" is for enabled, "D" is for disabled, "V" is for virtual, and "U" is for unknown address. A virtual breakpoint is a breakpoint for code that is not currently loaded.
·
The conditional information specifying the breakpoint, such as the address, expression, and length. If a breakpoint has a pass count, the remaining number of times that the breakpoint will be ignored is listed in parentheses.
BL
 also displays commands to execute, message/message classes (in the case of message breakpoints), thread and process number.


BP (Set Breakpoint)
Syntax
[
thread
]
BP
[
breakpoint
] [
location
] [
condition
] [
option
...]
Parameters
thread
The thread that the breakpoint will apply to. See
Process and Thread Syntax
 for more information on the
thread
 syntax.
breakpoint
The breakpoint number to be set. If the given breakpoint number already exists, the new breakpoint will replace the old.
location
The memory location of the breakpoint, in the format given in the table below.
condition
One of the breakpoint conditions given in the table below. You can specify multiple conditions for a breakpoint.
option
One of the breakpoint options given in the table below. Separate multiple options with spaces.
Description
Sets a breakpoint. You can combine locations, conditions, and options to set different kinds of breakpoints. If you do not specify a thread, the breakpoint will apply to all threads.
If you want to put a breakpoint on a C++ public, enclose the expression in parentheses. For example, "BP (??MyPublic)" or "BP (operator new)".
On x86 computers, WinDbg will use debug registers to implement watchpoints if:
·
There is a debug register available
·
Memory size is 1
·
Memory size is 2 and address is
WORD
 aligned
·
Memory size is 4 and address is
DWORD
 aligned
You can use the following options when setting a breakpoint:
Location
Description
[
{
[
procedure
], [
module
], [
exe
]
}
]
address
The address for the breakpoint.
[
{
[
procedure
], [
module
],
[
exe
]
}
]
@
line
The line number for the breakpoint.
Condition
Description
?
expression
Break if
expression
 is true.
=
address
 [/R
count
]
Break if memory at
address
 has changed. Use the
/R
 option to specify the number of bytes to check (default is 1).
Option
Description
/P
count
Ignore the breakpoint
count
 times.
/C
cmdlist
Execute
cmdlist
 when the breakpoint is hit. The
cmdlist
 parameter is a semicolon-separated list of one or more debugger commands. If
cmdlist
 includes multiple commands, enclose it in quotes (
"
).
/M
messagename
/M
messageclass
Break only if the given message name or message class has been received.
/Q
Suppress the unresolved-breakpoint dialog box for this breakpoint.
/H
process
Specify the process number to attach the breakpoint to. Defaults to all threads in
process
if
/T
 is not used.
If
/H
 is not specified and no debuggee is running, the default is process 0.
/T
thread
Specify the thread number to attach the breakpoint to. Defaults to current process if
/H
 is not used.


C (Compare Memory)
Syntax
C
range
address
Parameters
range
The first memory area to compare. See
Range Syntax
 for information on the
range
 syntax.
address
The starting address of the second memory area.
Description
Compares the values held in two memory areas. Specify the first area with the
range
 parameter. Specify the starting address of the second area with
address
. The second area is the same length as the first. If the two areas are not identical, WinDbg will display all memory addresses in
range
 where they do not agree.


DA, DB, DC, DD, DI, DS, DT, DU, DW (Display Memory)
Syntax
D
{
A
 |
B
 |
C
 |
D
 |
I
 |
S
 |
T
 |
U
 |
W
} [
range
]
Parameters
range
The memory area to display. See
Range Syntax
 for information on the
range
 syntax.
Description
Displays the contents of memory in the given range. Each line shows the address of the first byte in the line, followed by the contents of memory at that and following locations.
If you omit
range
, the command will display memory starting at the ending location of the last Display command. This allows you to continuously scan through memory.
When WinDbg is displaying ANSI or Unicode characters, it will stop displaying characters at the first null byte. When displaying ANSI characters, all characters, including non-printable characters, are displayed using the current code page character set. With Unicode, all nonprintable and nonmappable characters are displayed as dots.
Command
Definition
Displays
DA
Display ANSI
ANSI (extended ASCII) characters
DB
Display Bytes (
char
)
Byte values and ANSI characters
DC
Display Code
Assembly-language instructions (disassembly)
DD
Display Doublewords
(
long
)
Doubleword (4-byte) values and ANSI characters
DI
Display 8-Byte Reals (
double
)
8-byte hexadecimal values and floating-point representations
DS
Display 4-Byte Reals
(
float
)
4-byte hexadecimal values and floating-point representations
DT
Display 10-Byte Reals
(
long double
)
10-byte hexadecimal values and floating-point representations
DU
Display Unicode
Unicode characters
DW
Display Words (
short
)
Word values and Unicode characters
Note
  With the
DC
 (Dump Code) command, you can use the standard
range
 syntax or
startaddress
I
line
 to dump
line
 instructions starting at
startaddress
.


EA, EB, ED, EI, ES, ET, EU, EW (Enter Values)
Syntax
E
{
A
 |
B
 |
D
 |
I
 |
S
 |
T
 |
U
 |
W
}
address
 [
values
]
Parameters
address
The starting address to enter values.
values
One or more values to enter into memory. Separate multiple numeric values with spaces.
Description
Enters the values that you specify into memory. If you do not specify any values, the current address and the value at that address will be displayed. You can then enter a new value, preserve the current value in memory by pressing the space bar, or stop entering data by pressing
ENTER
 alone.
When entering numeric values, you can use C-style radix prefixes to override the default radix. Prefix octal constants with a "0o" (for example 0o1776), hexadecimal constants with "0x" (for example 0xF000), and decimal constants with "0t" (for example 0t199).
When entering ANSI or Unicode values, you can include space (
"
"
) characters by enclosing the character string in quotation marks (
"
 or
'
). If you enclose the string in double quotation marks, WinDbg will automatically null-terminate the string. Single quotation marks (
'
) will not add a null character. You can enter standard C escape characters, such as \
t
, \
007
, and \
"
.
Command
Definition
Enter
EA
Enter ANSI
ANSI (extended ASCII) characters
EB
Enter Bytes (
char
)
Byte values
ED
Enter Doublewords (
long
)
Doubleword (4-byte) values
EI
Enter 8-Byte Reals (
double
)
Floating-point numbers
ES
Enter 4-Byte Reals (
float
)
Floating-point numbers
ET
Enter 10-Byte Reals (
long double
)
Floating-point numbers
EU
Enter Unicode
Unicode characters
EW
Enter Words (
short
)
Word values


F (Freeze Thread)
Syntax
[
thread
]
F
Parameter
thread
The thread to be frozen. See
Process and Thread Syntax
 for information on the
thread
 syntax.
Description
Freezes the given thread, causing it to wait until it is unfrozen. Other threads will continue to execute. If no thread is specified, the current thread is frozen.
Use the
Z
 (Unfreeze) command to reenable the thread.


FIA, FIB, FID, FII, FIS, FIT, FIU, FIW (Fill Memory)
Syntax
FI
{
A
 |
B
 |
D
 |
I
 |
S
 |
T
 |
U
 |
W
}
range
pattern
Parameters
range
The memory area to fill. See
Range Syntax
 for information on the
range
 syntax.
pattern
One or more values to fill memory with. Separate multiple numeric values with spaces.
Description
Fills the memory area specified by
range
 with the user-specified
pattern
. The entire
range
 will be filled by repeatedly storing
pattern
 into memory.
When entering numeric values, you can use C-style radix prefixes to override the default radix. Prefix octal constants with a "0o" (for example 0o1776), hexadecimal constants with "0x" (for example 0xF000), and decimal constants with "0t" (for example 0t199).
When entering ANSI or Unicode values, you can include space (
" "
) characters by enclosing the character string in quotation marks (
"
 or
'
). If you enclose the string in double quotation marks, WinDbg will automatically null-terminate the string. Single quotation marks (
'
) will not add a null character. Standard C escape characters (such as
\t
,
\007
, and
\"
) are also allowed.
Command
Definition
Fill
FIA
Fill ANSI
ANSI (extended ASCII) characters
FIB
Fill Bytes (
char
)
Byte values
FID
Fill Doublewords (
long
)
Doubleword (4-byte) values
FII
Fill 8-Byte Reals (
double
)
Floating-point numbers
FIS
Fill 4-Byte Reals (
float
)
Floating-point numbers
FIT
Fill 10-Byte Reals (
long double
)
Floating-point numbers
FIU
Fill Unicode
Unicode characters
FIW
Fill Words (
short
)
Word values


FR (Floating-Point Registers)
Syntax
[
thread
]
FR
 [
register
 [
=
value
] ]
Parameters
thread
The thread from which the floating-point registers are to be read. See
Process and Thread Syntax
 for information on the
thread
 syntax.
register
The floating-point register to display or modify.
value
The floating-point value to assign to
register
.
Description
Displays or modifies floating-point registers. If no thread is specified, the current thread is used.
If you do not specify a register, all of the floating-point registers are displayed. If you specify a register, the command displays the current value of the register and prompts for a new value. If you specify both a register and a value, the command changes the register to contain the value.
Use the
R
 command to view and modify standard registers.


G (Go)
Syntax
[
process
|
thread
]
G
 [
breakaddress
]
Parameters
process
The process to execute. See
Process and Thread Syntax
 for information on the
process
 syntax.
thread
The thread to execute. See
Process and Thread Syntax
 for information on the
thread
 syntax.
breakaddress
The address for an unconditional breakpoint.
Description
Starts executing the given process or thread. Execution will halt at the end of the program, when
breakaddress
 is hit, or when another event causes the debugger to stop.
Note
  The breakpoint associated with
breakaddress
 will only be hit by the current thread. Other threads that execute the code at that location will not be stopped.


GH (Go
Exception Handled)
Syntax
[
thread
]
GH
Parameter
thread
The thread to execute. This thread must have been stopped by an exception. See
Process and Thread Syntax
 for information on the
thread
 syntax.
Description
Marks the given thread's exception as being handled and allows the thread to continue execution at the instruction that caused the exception. This allows the debuggee to handle the exception. Use the
GN
 (Go Exception Not Handled) command to continue execution without marking the exception as handled.


GN (Go
Exception Not Handled)
Syntax
[
thread
]
GN
Parameter
thread
The thread to execute. This thread must have been stopped by an exception. See
Process and Thread Syntax
 for information on the
thread
 syntax.
Description
Continues execution of the given thread without marking the exception as having been handled. This allows the debuggee's exception handler to handle the exception. Use the
GH
 (Go Exception Handled) command to continue execution after marking the exception as having been handled.


K, KB, KN, KS, KV (Display Stack Backtrace)
Syntax
[
thread
]
K
[
BNSV
] [
framecount
]
Parameters
thread
The thread whose stack is to be displayed. See
Process and Thread Syntax
 for information on the
thread
 syntax.
framecount
Number of stack frames to display.
Description
Displays the stack frame of the given thread. Each display line shows the name or address of the procedure called, the arguments used on the call, and the address of the statement that called it. You can use any or all of the options in a single command; for example,
K
,
KB
, and
KBNSV
 are valid commands. The following table describes the effect of the options:
Option
Effect
none
The
K
 command without any options displays the basic call stack based on debugging information in the executable. It displays the frame pointer, return address, and function names.
B
The
B
option causes the
K
 command to additionally display the first three parameters to the functions.
N
The
N
 option causes the
K
 command to additionally display the frame numbers for the calls.
S
The
S
 option causes the
K
 command to additionally display source module and line number information for the calls.
V
The
V
 option causes the
K
 command to additionally display runtime function information.


L (Restart Debuggee)
Syntax
L
 [
parameters
]
Parameter
parameters
Command-line options for the debuggee.
Description
Restarts the debuggee with optional
parameters
 supplied as command-line options.


LM (List Loaded Modules)
Syntax
LM
  [/s  [/o]  [/f ]  [
modulename
]
Parameter
parameters
/s
  List segmented modules.
/f
   List flat modules.
/o
  Sorts segmented modules by selector.
modulename
    Module to list
Description
This command lists the specified loaded modules. If you do not specify a modulename,
LM
 will list all loaded modules. If
/f
 and
/s
 are both absent from the command line,
LM
 will assume both; the following two commands are equivalent:
> LM
> LM  /f  /s
Segmented modules are sorted by module name, then selector, unless you specified
/o
. Flat modules are sorted by base address.


LN (List Nearest symbols)
Syntax
LN
 address
Parameter
address
The address to search for symbols.
Description
Displays the symbols at or near the given
address
. You can use this command to help determine what a pointer is pointing to. It also can be useful when looking at a corrupted stack to determine what procedure made a call.


M (Move Memory)
Syntax
M
range address
Parameters
range
The memory area to copy. See
Range Syntax
 for information on the
range
 syntax.
address
The starting address of the destination memory area.
Description
Copies the contents of memory from one location to another. It is legal for
address
 to be part of
range
. Overlapping moves are handled correctly.


N (Set Number Base)
Syntax
N
radix
Parameter
radix
The default number base used for numeric display and entry. Legal values are 8 (octal), 10 (decimal), and 16 (hexadecimal).
Description
Sets the default number base to
radix
. You can use C-style radix prefixes to override the default radix.
WinDbg's default is base 16.


P (Program Step)
Syntax
[
thread
]
P
 [
count
]
Parameters
thread
The thread to step through. See
Process and Thread Syntax
 for information on the
thread
 syntax.
count
The number of instructions or source lines to step through before stopping.
Description
Executes the instruction (in ASM mode) or source line (in SRC mode) at the instruction pointer. If WinDbg encounters a CALL instruction or interrupt while stepping, the called subroutine will execute before control returns to the debugger.
Use the
T
 (Trace) command to have WinDbg step through subroutine calls and interrupt-handling routines.


Q (Quit WinDbg)
Syntax
Q
Description
Exits WinDbg. This command is identical to choosing Exit from the File menu.


R (Registers)
Syntax
[
thread
]
R
 [
register
 [=
value
] ]
Parameters
thread
The thread from which the registers are to be read. See
Process and Thread Syntax
 for information on the
thread
 syntax.
register
The register to display or modify.
value
The value to assign to
register
.
Description
Displays or modifies registers. If you do not specify a thread, the current thread is used.
If you do not specify a register, all of the registers are displayed. If you specify a register, the command displays the current value of the register. If you specify both a register and a value, the command changes the register to contain the value.
Use the
FR
 (Floating-Point Registers) command to view and modify floating-point registers.


REMOTE (Start Remote Server)
Syntax
REMOTE
 [
pipename
 | STOP]
Parameters
pipename
The name that you want to use for the remote server pipe.
STOP
Ends a currently active remote server.
Description
Starts a remote server, which lets you get access to the Command window from another computer on the network. You can then enter Command window commands on the other computer to debug the application remotely.
If you do not specify any parameters to REMOTE, the command displays its connection status and the name of the client.
To connect from another computer, run the following in a cmd shell (the Windows NT command prompt):
remote /c
hostname
pipename
where
hostname
 is the computer name of the computer that is running WinDbg and
pipename
 is the same as above.
You now have access from the remote computer to the WinDbg Command window.


RT (Register Display Toggle)
Syntax
[
thread
]
RT
Parameters
thread
The thread from which the registers are to be read. See
Process and Thread Syntax
 for information on the
thread
 syntax.
Description
Toggles the register display (WinDbg KD only). The default is off.


S+, S
-
 (Set Source/Assembly Mode)
Syntax
S+
S
-
Description
Use these commands to switch between source mode (where the debugger steps line-by-line through the source code) and assembly-language mode (where the debugger steps instruction-by-instruction). The
S+
 command switches to Source mode, and
S
-
  switches to assembly-language mode. The status bar displays whether the current mode is SRC or ASM.


SA, SB, SD, SI, SS, ST, SU, SW (Search Memory)
Syntax
S
{
A
 |
B
 |
D
 |
I
 |
S
 |
T
 |
U
 |
W
}
range
pattern
Parameters
range
The memory area to search through. See
Range Syntax
 for information on the
range
 syntax.
pattern
One or more byte values or ANSI or Unicode characters to search for. Separate multiple values with spaces.
Description
Searches through memory to find a specific byte pattern. If the pattern is found, WinDbg will display the first memory address in
range
 where it was found.
When entering numeric values to search for, you can use C-style radix prefixes to override the default radix. Prefix octal constants with a "0o" (for example 0o1776), hexadecimal constants with "0x" (for example 0xF000), and decimal constants with "0t" (for example 0t199).
When entering Unicode values to search for, you can include space (
" "
) characters by enclosing the character string in quotation marks (
"
 or
'
). If you enclose the string in double quotation marks, WinDbg will automatically null-terminate the string. Single quotation marks (
'
) will not add a null character. Standard C escape characters (such as
\t
,
\007
, and
\"
) are also allowed.
Command
Definition
Fill
SA
Search ANSI
ANSI (extended ASCII) characters
SB
Search Bytes (
char
)
Byte values
SD
Search Doublewords (
long
)
Doubleword (4-byte) values
SI
Search 8-Byte Reals (
double
)
Floating-point numbers
SS
Search 4-Byte Reals (
float
)
Floating-point numbers
ST
Search 10-Byte Reals (
long double
)
Floating-point numbers
SU
Search Unicode
Unicode characters
SW
Search Words (
short
)
Word values


SEB, SEW (Set Error Break, Set Error Warning)
Syntax
SEB
 [
level
]
SEW
 [
level
]
Parameters
level
The error level required to break into the debugger (
SEB
) or display a message (
SEW
). One of the following:
Level
Triggered by
0
Nothing. Disables breaks or warnings.
1
Severe errors only.
2
All errors.
3
All warnings and errors.
Description
The
SEB
 command causes the debugger to break after the debuggee causes a system error or warning of the appropriate
level
. The
SEW
 command causes the debugger to display a message under these conditions. If you do not specify a level, the commands will default to level 1.
The
SEB
 command implies an
SEW
level
equal to or greater than its own level. For example,
SEB 3
causes the debugger to give warnings at levels 1
-
 3.
These errors are triggered by the Windows subsystem. They are known as RIPs from Win16 where they usually signal a fatal program error. They are often caused by passing a bad value to an API function.


SX (Set Exceptions)
Syntax
SX
 [
exception
]
SXE
exception
[
message
] [
/C
cmdlist1
]
[
/C2
cmdlist2
]
SX
{
D
 |
N
}
exception
[
message
] [
/C2
cmdlist2
]
Parameters
exception
The exception number that the command acts upon, in the current radix. If you do not specify an exception, the
SX
 command will display information on all exceptions.
message
Message to display in the Command window when the exception is trapped.
cmdlist1
Semicolon-separated list of WinDbg commands to execute when an exception first occurs. The
/C
 option is permitted only with the
SXE
 command. Enclose in quotes if
cmdlist1
 includes spaces or semicolons.
cmdlist2
Semicolon-separated list of WinDbg commands to execute after an exception has not been handled. Enclose in quotes if
cmdlist2
 includes spaces or semicolons.
Description
Controls the behavior of the debugger when trapping exceptions before executing exception-handling code. The debugger always halts before execution returns from the exception handler.
Command
Action
SX
Displays the events that the debugger will halt for.
SXD
Causes the debugger to ignore the specified exception and issue an automatic
GN
 command.
SXE
Causes the debugger to halt at the specified exception.
SXN
Causes the debugger to display a message before the exception is passed to the debuggee, and causes the debugger to issue a
GN
 command after the message is displayed.
The
/C
 option (allowed only with
SXE
) tells WinDbg to execute the specified debugger commands on the first chance (before the exception is passed to the debuggee). The
/C2
 option tells WinDbg to execute the specified debugger commands on the second chance (if the exception is not handled by WinDbg or the application). See your documentation on structured exception handling for more information.
When the debugger stops due to an exception, only the
GN
 (Go Exception Not Handled) and
GH
 (Go Exception Handled) commands can be used to continue execution. The
SXD
 and
SXN
 commands automatically call
GN
.


T (Trace)
Syntax
[
thread
]
T
 [
count
]
Parameters
thread
The thread to trace through. See
Process and Thread Syntax
 for information on the
thread
 syntax.
count
The number of instructions or source lines (depending on the Source/Assembly mode) to step through before stopping.
Description
Executes the instruction or source line at the instruction pointer and displays the resulting values of all registers and flags.
Use the
P
 (Program Step) command to have WinDbg execute subroutine calls or interrupts without returning control to the debugger.


U (Unassemble)
Syntax
U  [[
range
]
Parameters
range
The memory area that contains the instructions to unassemble. See
Range Syntax
. You can use the standard range syntax or
startaddress
I
line
 to dump
line
 instructions starting at
startaddress
.
Description
Displays the instructions of the program being debugged. If you do not specify
range
, the debugger displays the instructions generated from the first eight lines of code at the current address.
The 80286 protected-mode mnemonics cannot be displayed.


X (Examine Symbols)
Syntax
X
[
options
] [ { [
procedure
]
,
[
module
]
,
[
executable
] } ] [
pattern
]
Parameters
options
Specifies the scope of the symbol search. These options cannot be separated by spaces and must immediately follow the
X
 (for example,
XEM
). Use the following letters to specify scope:
Option
Description
C
Search current class.
E
Search entire executable or DLL, except for current module.
F
Search current function.
G
Search all global symbols.
L
Search current code block (lexical scope).
M
Search current module.
P
Search all public symbols.
procedure, module, executable
The area to search. For example,
{Function1, srcfile.c, target.dll}
will search Function1 from SCRFILE.C in TARGET.DLL. This is identical to the breakpoint context operator.
pattern
A pattern to search for. The
?
 and
*
 wildcards are supported.
Description
Displays the symbols in all contexts that match
pattern
. If you do not specify any options, all except public symbols are searched. If you do not specify a pattern, all symbols will be displayed. The search will be case-sensitive if the Ignore Case option is not checked in the Debug command from the Options menu.


Z (Unfreeze Thread)
Syntax
[
thread
]
Z
Parameters
thread
The thread or threads to be unfrozen. See
Process and Thread Syntax
 for information on the
thread
 syntax.
Description
Unfreezes the specified thread. If you do not specify the thread, this command unfreezes the thread that caused the most recent exception, if any. You can freeze threads with the
F
 (Freeze) command.


Creating a Setup Program
When you install a Microsoft software program on your computer, you may be using Setup and its supporting functions to decompress and copy the program files onto your hard disk. Setup is a tool that you can use to create programs that will install your application on a user's computer. Microsoft is providing the Setup toolkit as part of the SDK so that you can take advantage of its many automated procedures when you create an installation program for your own product.


The Basic Components of Setup
The Setup toolkit includes the following basic components:
·
Sample dialog box templates and procedures (DIALOGS.DLG, DIALOGS.RES, and DIALOGS.C), which you modify using the Windows Dialog Editor to create the dialog and message boxes you need for your installation.
·
Five .DLL files that contain useful routines for detecting the hardware and software environment, managing dialog and message boxes, copying files, modifying .INI files, and performing other program management functions. These procedures are described in
Setup Procedures
. you will use them to create your Setup program.
·
Disk Layout Utilities, DISKLAYT.EXE and DISKLAYT2.EXE, which you use to create the installation disks you will ship with your product.
Use these components as described in the next section to create your own Setup program. Using Setup for your product installations will ensure that the process is safe and efficient, and that the installation meets Windows programming standards.


Steps for Creating a Setup Program
Use the following procedure to create a Setup program for your product. The remainder of this section discusses each step in more detail.
To create a Setup installation program
1.
Identify the files that will be installed for your product.
2.
Design the directory structure for those files.
3.
Identify all user-defined parameters.
4.
Design the dialog boxes you will need for the installation.
5.
Create the code that will install your product's files.
6.
Create the images for the installation disks using the Disk Layout Utilities.
7.
Test your installation.


Step 1: Identify the Files That Will Be Installed for Your Product
Before you start modifying sample code and dialog box templates, it's a good idea to make a list of the files you will need to install. For each file that you will install, answer the following questions:
1.
Is this file unique for your product, is it a shared resource, or is it a system resource? For example, a shared resource could be a language dictionary used by more than one product for your company. A system resource could be a TrueType font. If the file is a shared file or a system file, you will want your code to check to see if it already exists and whether it is currently in use before copying it onto the user's hard disk.
2.
Can the user decide whether to install this file? For example, is the installation of tutorial files optional? If so, you'll need to design a dialog box that asks the user to choose the files to install.
3.
If an older version of the file already exists, should you overwrite it or rename it? Or, if you want to delete it, is the older version of the file under a different filename? If so, you will want your code to remove it, as well as install its newer version.
Beside each filename on your list, make notations indicating the answers to these questions. These notations will help you later when you design dialog boxes or set the properties for each file with the Disk Layout Utilities.


Step 2: Design the Directory Structure for the Installable Files
Take the time now to sketch out the directory structure for your product by organizing the installable files into categories that make sense. For example, you might put all computer-based training files in one subdirectory and all font files in another. You may need to place some files in the Windows directory or in one of its subdirectories. On the other hand, one directory (with no subdirectories) may suffice for a product that has only a few files.


Step 3: Identify All User-Defined Parameters
Identify the dialog and message boxes you will need for your Setup program. What input does the user provide during installation? For example, will you store the user's name, the company name, and the product serial number in a file? Can the user decide which directory to use for installation? Can the user decide not to install some of the product files? You should also note whether you will allow network installations and, if so, how the installation process will differ when installing to a network drive.
Are there any issues that you need to communicate to the user? For example, do you need a message box to notify the user that you will be updating or deleting existing files? If so, note these as well.


Step 4: Design Dialog Boxes
Make a rough sketch of each dialog box and identify the controls (buttons, check boxes, and list boxes) that will be needed. This will help you choose the most appropriate template to modify. Then use the Windows Dialog Editor to customize the templates. You may also need to modify the dialog box procedures (in DIALOGS.C) to process the user's responses. For more information about this process, see
Designing Dialog Boxes
.


Step 5: Create Your Installation Program
Starting from the sample program provided in the toolkit, you will create your own Setup program.  For more information, see
Building a Setup Program
. For descriptions of the functions used in these files, see
Setup Procedures
.


Step 6: Create the Images for the Installation Disks
Gather all of your product files and installation program files into the directory structure that you sketched out earlier. Then use the Disk Layout Utilities to define each file's properties (such as whether it can be put on a writable disk) and to create the images for the installation disks. The Disk Layout Utilities automatically create the .INF file as part of this process.
You can use the Disk Layout Utilities throughout your software development project, until you create your master disks. Each time you release another version of your product, use the Disk Layout Utilities to update the .INF file and disk images.
For more information about the Disk Layout Utilities, see
Using the Disk Layout Utilities
.


Step 7: Test Your Installation Program
Once you've created your own Setup installation program, test it thoroughly. Test your code under a variety of situations and computer configurations. Check the results by verifying that the files were copied to their appropriate directories and that system files were updated correctly. When you are satisfied that the installation is correct, create your master disks by copying the disk images onto media that you've chosen to deliver your product.


Designing Dialog Boxes
The Setup toolkit includes dialog box templates that you can customize to meet your installation's specific needs. You can use the Microsoft Windows Dialog Editor (DLGEDIT.EXE) to edit the templates.
The Dialog Editor is a tool that lets you design and test a dialog box on the display screen instead of defining dialog statements in a resource script. Using the Dialog Editor, you can add, modify, and delete controls in a dialog box. The Dialog Editor saves the changes you make as resource script statements. You then compile these statements into a binary resource file that is linked to your Setup application's executable file of dialog procedures.
The Setup toolkit provides the following files that contain sample dialog box templates and procedures:
·
DIALOGS.DLG, which contains dialog box templates and is used to create MSCUISTF.DLL. See the table below for descriptions of these templates. DIALOGS.DLG is updated automatically when you use the Dialog Editor to read the companion file that the editor creates, DIALOGS.RES.
·
DIALOGS.RC, which contains the resource statements for the bitmaps and the icons that are used in the DIALOGS.DLG and DIALOGS.H sample files.
·
DLGPROCS.C, which contains the C code for sample dialog box procedures associated with each template and is used to create MSCUISTF.DLL. You modify this file to update the procedures for the dialog box templates that you edited using the Dialog Editor. You can also add new dialog procedures to this file.
·
DIALOGS.H, which contains the dialog control identification number definitions and is used to create MSCUISTF.DLL. This file is updated automatically when you use the Dialog Editor.
·
CUI.H, which is the header file for the Setup toolkit dialog box C functions.
·
MAKEFILE, which you can use to compile the preceding files.
Use these files with the Dialog Editor, the C compiler, and the linker to create your own dialog boxes.
To customize the dialog box templates for your installation program, follow these steps
1.
Use the Dialog Editor to modify DIALOGS.RES. For each dialog box that you need, choose a template that closely resembles the design of the dialog box and modify it as necessary.
2.
When you save your changes, the Dialog Editor updates the script statements in DIALOGS.DLG and the constants in DIALOGS.H.
3.
If necessary, edit DLGPROCS.C to update the dialog box procedures for the templates that you modified.
The Setup toolkit provides a set of functions that you can use in the dialog procedures in addition to the standard Windows functions. These Setup functions are written in C and are described in detail in the following section.
Note
DLGPROCS.C uses the Symbol Table, a temporary storage area in memory, to transfer information between dialog box procedures and Setup. The comments embedded in the code for each dialog box procedure identify the symbols the procedure uses. For more information about the Symbol Table, see
Building a Setup Program
.
Note
Two constants are defined in CUI.H that can directly affect dialog box procedures: STF_REINITDIALOG and STF_ACTIVATEAPP. If your dialog box procedure has called the
UIStartDlg
 function for a dialog box that is already on top of the dialog box stack (that is, to update the contents of the dialog box), Windows returns the STF_REINITDIALOG constant to let you know. If the user has switched to another application during your installation, Windows returns the STF_ACTIVATEAPP constant to let you know that control has returned to your Setup program.
3.
Compile the dialog box procedures with MAKEFILE to create the .DLL file with your changes.
MAKEFILE compiles the dialog procedures and dialog resources into MSCUISTF.DLL. You then use the name of the .DLL file, the resource identification numbers of the dialog boxes, the help description resource identification numbers, and the names of the associated dialog box procedures as parameters for the
UIStartDlg
 procedure, which is called from the installation program.
Note
  All dialog boxes must have a style of WS_CHILD in order to run properly.
The following table provides a quick guide to the dialog box procedures provided in DLGPROCS.C and their associated templates provided in DLGPROCS.DLG. Each procedure in DIALOGS.C is preceded with comments indicating what the procedure does and what symbols it uses. You can also preview each template using the Dialog Editor to open DIALOGS.RES.
Dialog Box Procedures
Procedure name
Used for
Associated template(s)
FCheckDlgProc
Dialog boxes with one to ten check boxes.
CHECK
FCustInstDlgProc
Dialog boxes with one to ten check boxes. Each check box can have an associated push button. This procedure also supports a push button that displays the current installation path and allows the user to change it.
CUSTINST
FEditDlgProc
Dialog boxes that contain one edit control.
DESTPATH
FHelpDlgProc
Dialog boxes that contain help messages.
APPHELP
FInfoDlgProc
Dialog boxes that present information to the user. The user must respond.
WELCOME
FInfo0DlgProc
This procedure is the same as FInfoDlgProc but does not support an Exit button.
BADPATH EXITFAILURE EXITQUIT EXITSUCCESS TOOBIG
FListDlgProc
Dialog boxes that contain one single-selection list box.
SINGLELIST
FModelessDlgProc
Dialog boxes that present information to the user during lengthy operations. The user does not have to respond.
MODELESS
FMultiDlgProc
Dialog boxes with one multiple-selection list box.
EXTENDEDLIST MULTILIST
FQuitDlgProc
Dialog boxes that let the user either quit or resume the installation process.
ASKQUIT
FRadioDlgProc
Dialog boxes with a single group of one to ten radio buttons.
OPTIONS
For information about the
UIStartDlg
 procedure, see
Setup Procedures
. For information about using the Dialog Editor, refer to "Designing Dialog Boxes: The Dialog Editor" in
Microsoft Windows Programming Utilities.


Dialog Box Functions


AsciiToInt
int AsciiToInt(LPSTR
 sz
);
The
AsciiToInt
 function converts an ASCII string representing a positive value into an integer.
Argument
sz
A non-null zero-terminated string to convert.
Return Value
Returns the integer that is represented by
sz
.
Comments
The integer to convert must be both positive and less than 100.
See Also
IntToAscii


AssertSzUs
void AssertSzUs(LPSTR, unsigned
fValue
);
The
AssertSzUs
 function asserts whether a boolean expression is true when the DEBUG compiler flag is defined. When DEBUG is not defined, the function is ignored.
Argument
fValue
Specifies the Boolean value that you want to assert.
Return Value
This function has no return value.
Comments
If the asserted value is true, the
Assert
 function simply returns. If the asserted value is false, the program displays a message box containing the source filename and the line number of the failed assertion. You must click OK to continue.


CbGetListItem
int
CbGetListItem(LPSTR
szListSymbol
, unsigned
 n
, LPSTR
szListItem
, unsigned
cbMax
);
The
CbGetListItem
 function copies the specified list item into the provided buffer as a zero-terminated string.
Arguments
szListSymbol
Specifies the name of the symbol whose associated value is the list you want.
n
Specifies the index number (one-based) for the list item you want to copy into the buffer.
szListItem
Specifies the buffer for the copy of the list item.
cbMax
Specifies the size of the buffer.
Return Value
If the function is successful, the return value is the length (in bytes) of the full string of the specified list item. If
szListSymbol
 or
n
 doesn't exist, the return value is zero and the empty string is placed in the buffer.
Comments
If you specify a buffer that is smaller than the length of the symbol value, the
CbGetListItem
 function will copy in as many characters as will fit (including a trailing zero). However, the return value will be the full length of the string.
See Also
UsGetListLength
,
FAddListItem
,
FReplaceListItem
.
For information about setting symbol values in the Symbol Table, see
FSetSymbolValue
.


CbGetSymbolValue
int
CbGetSymbolValue(LPSTR
szSymbol
, LPSTR
szValue
, unsigned
Length
);
The
CbGetSymbolValue
 function copies the specified value from the symbol-value pair in the Symbol Table into a buffer.
Arguments
szSymbol
Specifies the name of the symbol whose value you want to copy into the buffer.
szValue
Specifies a buffer for the value associated with the symbol.
Length
Specifies the length, in bytes, of the buffer.
Return Value
If the function is successful in copying the value into the buffer, the return value is the length of the value string (excluding the terminating zero). If the symbol does not exist or is an empty string, the return value is zero.
Comments
If you specify a buffer length that is smaller than the length of the value, the function will copy in as many characters as will fit (including a trailing zero). However, the return value will be the full length of the specified value.
See Also
FSetSymbolValue
,
FRemoveSymbol


DoMsgBox
int
DoMsgBox
(
LPSTR
lpText
,
LPSTR
lpCaption
,
unsigned
wType
);
The
DoMsgBox
 function launches a Windows message box of the style specified by
wType
. The return value is the identification for the user's response, such as IDOK.
Arguments
lpText
Specifies the text you want to appear in the message box.
lpCaption
Specifies the caption for the message box.
wType
Specifies the contents of the message box.
wType
 can be a combination of values.
Return Value
The return value is the value of the button control that the user selected (such as IDOK). If there is not enough memory to create the message box, the return value is zero.
Comments
This function is similar to the Windows
MessageBox
 function. The valid message box values and control values are the same as for the
MessageBox
 function.
See Also
For more information on the
 MessageBox
 function, see the Microsoft Windows Programmer
¢
s Reference.


FAddListItem
BOOL FAddListItem(LPSTR
szListSymbol
, LPSTR
szListItem
);
The
FAddListItem
 function adds the specified item to the end of the list of items associated with the symbol in the Symbol Table.
Arguments
szListSymbol
Points to a zero-terminated string that identifies the symbol.
szListItem
Points to a zero-terminated string that identifies the item you want to add to the list associated with
szSym
.
Return Value
If the function is successful in adding the item, the return value is
fTrue
 (one). Otherwise, the return value is
fFalse
 (zero).
Comments
You can initialize an empty list by setting its associated symbol value to "" with the
FSetSymbolValue
 function. You can then add values to the list using
FAddListItem
.
See Also
FReplaceListItem
,
CbGetListItem
,
UsGetListLength


FCloseHelp
BOOL FCloseHelp();
The
FCloseHelp
 function closes the currently open help dialog box, if one exists.
Return Value
The return value is
fTrue
 (one) if the help dialog box is successfully closed. Otherwise, it is
fFalse
 (zero).
See Also
HdlgShowHelp


FHandleOOM
BOOL FHandleOOM();
The
FHandleOOM
 function displays a message box when an "Out Of Memory" error occurs and waits for a user response. This function lets the user switch out of the current application and free up some memory by closing other applications.
Return Value
If the user presses the RETRY button, the return value is
fTrue
 (one). If the user presses the ABORT button, the return value is
fFalse
 (zero).


FRemoveSymbol
BOOL
FRemoveSymbol(LPSTR
szSym
);
The
FRemoveSymbol
 function removes a symbol and its associated value from the Symbol Table.
Argument
szSym
Specifies the name of the symbol you want to remove.
Return Value
If the function is successful, the return value is
fTrue
 (one). Otherwise, the return value is
fFalse
 (zero).
See Also
FSetSymbolValue


FReplaceListItem
BOOL
FReplaceListItem(LPSTR
szListSymbol
, unsigned
n
, LPSTR
szListItem
);
The
FReplaceListItem
 function replaces the specified item in the list of items associated with the symbol in the Symbol Table.
Arguments
szListSymbol
Specifies the name of the symbol.
szSym
 must be a zero-terminated string.
n
Specifies the index number (one-based) of the item you want to replace.
szListItem
Identifies the item you want to use to replace the existing item.
szItem
 must be a zero-terminated string.
Return Value
If the function successfully replaces the item, the return value is
fTrue
 (one). If the index is invalid or the application is out of memory, the return value is
fFalse
 (zero).
See Also
FAddListItem
,
CbGetListItem
,
UsGetListLength


FSetSymbolValue
int FSetSymbolValue(LPSTR
szSymbol
,
LPSTR
szValue
);
The
FSetSymbolValue
 function inserts a new symbol-value pair into the Symbol Table. If the symbol already exists, the function replaces the symbol's associated value.
Arguments
szSymbol
Specifies the name of the symbol you want to create or whose associated value you want to replace.
szValue
Specifies the value you want to add or replace. If
szValue
 is NULL, an empty string is added or used to replace the existing value.
Return Value
If the function is successful, the return value is
fTrue
 (one). If the application is out of memory, the return value is
fFalse
 (zero).
See Also
CbGetSymbolValue
,
FRemoveSymbol


HdlgShowHelp
HWND HdlgShowHelp();
The
HdlgShowHelp
 function displays the help dialog box for the dialog box that is currently on the top of the dialog box stack.
Return Value
The return value is the handle to the help dialog. If the help dialog does not exist and cannot be created, the return value is NULL.
See Also
FCloseHelp


IntToAscii
int
IntToAscii(int
i,
LPSTR
 sz
);
The
IntToAscii
 function converts a positive integer (< 100) into a string that represents its value.
Arguments
i
The integer to convert.
sz
The buffer to hold the converted string (at least 3 bytes).
Return Value
Returns the ASCII value of the provided integer (
sz
).
Comments
The integer to convert must be both positive and less than 100.
See Also
AsciiToInt


ReactivateSetupScript
void ReactivateSetupScript();
The
ReactivateSetupScript
 function returns control to the Setup program.
Return Value
This function has no return value.
Comments
This function is the vehicle for returning from a dialog box procedure to the Setup program.


SzDlgEvent
LPSTR
SzDlgEvent(WORD
wParam
);
The
SzDlgEvent
 function gets the string values for the following WM_COMMAND events:
IDC_B, IDC_C, IDC_X, and IDCANCEL.
Argument
wParam
Event parameter value.
Return Value
Returns a pointer to string value constant.  If the event is unknown,
SzDlgEvent
 returns NULL.
See Also
SzLastChar


SzLastChar
LPSTR
SzLastChar(LPSTR
sz
);
The
SzLastChar
 function finds the last character in a string.
Argument
sz
Specifies the non-null zero-terminated string to search.
Return Value
Returns NULL for an empty string.  If the string is not empty,
SzLastChar
 returns a non-Null string pointer to the last valid character in
sz
.
See Also
SzDlgEvent


UsGetListLength
int
UsGetListLength(LPSTR
szSymbol
);
The
UsGetListLength
 function determines the number of items in the list associated with the specified symbol.
Argument
szSymbol
Specifies the name of the symbol.
szSym
 must be a zero-terminated string.
Return Value
The return value is the number of items in the list associated with the symbol.
See Also
CbGetListItem
,
FReplaceListItem


Building a Setup Program
Once you've identified the list of files you need to install and used the Windows Dialog Editor to design dialog boxes and message boxes, you're ready to create an C program that contains the commands and procedure calls that Setup uses to install your product on the user's system.
Start by reviewing the files that make up the Setup toolkit. The following table lists the name and purpose of each file in the toolkit.
Setup Toolkit Files
Filename
Description
SETUP.EXE
    (required)
The program that you write to copy your files to the user's hard disk.
Setup .DLL files:
    (required)
    MSCOMSTF.DLL
    MSDETSTF.DLL
    MSINSSTF.DLL
    MSUILSTF.DLL
    MSSHLSTF.DLL
These .DLL files contain the code for the Setup procedures that you call from your installation program. You should list them in the SETUP.LST file and include them on the first installation disk.
The common library, which contains supporting routines for the other .DLL files.
The detection library, which contains procedures that return information about the user's system, such as the version of Windows.
The install library, which contains procedures that install files on the user's hard disk.
The user interface library, which contains procedures that manipulate the user interface, such as displaying a dialog box or deleting a dialog box from the dialog stack.
The shell library, which contains the routines that manage the frame window.
README.TXT
A text file that contains information about Setup that could not be included in this documentation. You should read this file before creating an installation program. Do not include this file on your installation disks.
The rest of this section explains the process of creating an installation program and defining which files you need to include on the first installation disk.


Modifying the Sample Installation Program
At this point, you have defined the list of files you will be installing and designed the dialog boxes you will need. Your focus has been on identifying the choices you will ask the user to make
¾
for example, determining the directory in which you will install your product.
To create the installation program, your focus must now shift slightly. When you create the code that handles the dialog boxes and installs the product files, you must pay attention to designing a safe and efficient installation process. Therefore, before you start modifying the Setup sample program, answer these questions:
·
How much disk space w
n
ill the installation use? Is it a significant amount? If so, you will need to ensure that the user's hard disk has enough disk space available. Also, if your product includes optional files that the user has chosen, you may want to inform the user how much disk space each optional file will use.
·
Does your product have minimum hardware and system software requirements? If so, you may want to check the version of your operating system, or check for the existence of, for example, a math coprocessor. If the user's system falls below your minimum requirements, you will want to display a warning message.
·
Will you be installing shareable files? For example, does your product require a spelling dictionary that the user already may have installed with another product? If so, you will need to take some special steps to handle these files.
·
Will you be installing any system files? If so, you may need to use special Setup functions to exit Windows and update files that would be in use while Windows is running.
·
What other parts of your installation have associated risks? Do you need to post warnings of any kind for the user? Do you need to check the validity of paths and filenames the user enters?
The answers to these questions provide the information you need to design your installation code. You should design the installation program just as you would any other program: Identify the types of routines you will need, determine the logical order in which those routines should occur, and then draw a flowchart of the installation process.


Using the Symbol Table
Whether your installation is simple or complex, you will probably use the Symbol Table to store values. The Symbol Table is a temporary storage area in memory that contains a table of text symbols and their associated text values. Setup uses the Symbol Table to store information such as directory names and data that is passed between the installation program and the .DLL files.
Setup automatically creates and sets three symbols that you can use:
·
STF_SRCDIR, which is the source directory
·
STF_CWDDIR, which is the current working directory or the temporary directory for Setup
·
STF_SRCINFPATH, which is the path for the .INF file (usually empty, unless you or the user supplied it as part of the SETUP.EXE command line)
The procedures in MSCUISTF.DLL (the customized dialog box routines) also use the Symbol Table to store the user's responses.You'll see other uses of the Symbol Table interspersed throughout the sample code. Use the Symbol Table to pass data between your installation program and the .DLL files.
Note
  To conserve memory, clear all Symbol Table strings after you use them.


Installing Shared Files or System Files
If you are planning to install shared files or system files, you must handle that part of the installation with extra care. This section describes some of the issues involved with installing shared files or system files and how Setup handles them.
Shared Files
A shared file is a file that may be used by more than one application on the user's system. For example, your company may have two products that use the same spelling dictionary. If the user has already installed one of the products, that dictionary file may already be installed. Furthermore, if the user has that product running during the installation process, the dictionary file may be in use, in which case it can't be updated.
To handle this problem, the
CopyFilesInCopyList
 procedure checks each file listed in your .INF file with the SHARED attribute to see if the file is in use. If so, Setup displays an error message. The user can fix the problem by:
·
Switching out of Setup, closing the other application, switching back into Setup, and then choosing the Retry button.
·
Exiting Setup and rerunning the installation after closing the other application.
·
Ignoring the message. If the file is marked as vital, Setup will display another error message. If the file is not vital, Setup skips it but continues to copy other files in the list.
System Files
A system file is a file that may be in use by Windows when Windows is running. The
CopyFilesInCopyList
 procedure checks each file listed in your .INF file with the SYSTEM attribute to see if the file is in use. If so, the procedure copies the file to a temporary location (the restart directory) and adds a command to the _MSSETUP.BAT file.
Toward the end of the installation, your program should call the
RestartListEmpty
 function. If the function returns zero, there are system files that must be updated. You should inform the user about this and then use the
ExitExecRestart
 function to shut down Windows, update the files, and restart Windows.
For more information, see
CopyFilesInCopyList
,
RestartListEmpty
, and
ExitExecRestart
, and
Setup Procedures
.


Using the Disk Layout Utilities
The Disk Layout Utilities automate tedious, error-prone tasks by taking your project files and creating efficiently organized disk images for your product installation. As part of this process, the Disk Layout Utilities also creates the .INF file.
Typically, you will use the Disk Layout Utilities in the following manner:
·
As soon as you have a distributable product release, even if it is planned for internal release within your company, use the Disk Layout Utilities to create the .INF file and the disk images.
·
For each subsequent release, run the Disk Layout Utilities to update the directory of disk images for any files you may have added or changed.
After the first time you use the Disk Layout Utilities to create a software release, the program remembers which files have already been included and tells you if you have added any new files. The Disk Layout Utilities also update disk images and compressed files only when they change.
This chapter describes the disk layout process and explains the use of the Dsklayt and Dsklayt2 programs to create a layout file, disk images, and the .INF file.


Understanding the Disk Layout Process
The Disk Layout Utilities consist of two parts:
·
A Windows-based program (Dsklayt) that you use to specify the properties for all files that will go into your product release
·
An Win32-based program (Dsklayt2) that creates the disk images and the .INF file for the installation
You use Dsklayt to create a layout file containing file specifications. Dsklayt2 then uses the directives in the layout file to create the disk images and the .INF file. You can use Dsklayt2 as part of your product build process.
To run Dsklayt
1.
In File Manager, choose Run from the File menu.
2.
In the Command Line box, type \MSTOOLS\MSSETUP\DISKLAY\DSKLAYT, and then click OK.
The main window for Dsklayt appears with an open dialog box.
3.
In the Microsoft Disk Layout Utilities dialog box, click either Open
Layout to open an existing layout file or New
Layout to create a new layout file.
4.
If you are opening an existing layout file, specify the name of the file and click OK. If you are creating a new layout file, specify the directory where your product files are stored and click OK.
The files from the source directory appear in the list box on the left side of the main window. You can then select one or more files from the list box and specify their properties.


Using the Disk Layout Utilities Commands
Dsklayt has a main window and three menus
¾
File, Options, and Help. This section describes the contents of the main window and each of the commands on the menus.


Dsklayt Main Window
You can use the options in the main window to set most of the file specifications for your installation. To set specifications for one file or for a group of files, you simply select the file(s) you want to affect from the list box and specify the options you want the file(s) to have.
The Dsklayt main window options are divided roughly into two types:
layout time
 options, which affect how the files are stored on the installation disks, and
install time
 options, which affect how the files are copied onto the user's hard disk. Each option is described below.
Source Directory
Displays the name of the top-level directory for your product files.
List box
Displays all the files in the source directory and its subdirectories. Choose files from this list to set their attributes. You can choose:
·
A single file, by clicking on it.
·
A contiguous range of files, by clicking on the first file, holding down the
SHIFT
 key, and then clicking on the last file.
·
A discontiguous range of files, by holding down the
CTRL
 key and clicking on each file.
Just Show New
Checking this box displays only the files that are new or have been updated since you last created the layout file. Use this option when you are doing successive product releases and only need to add specifications for the new or changed source files.
Layout Time Options:
File Destination
Determines the type of disk on which the selected file can be placed. Choose one of five options:
1.
Any Diskette:
 Indicates that the selected file can go on any diskette in the installation set. This option is the default.
2.
Writable Diskette:
Indicates that the selected file must go on a disk that Setup can write to.
3.
Read-Only Diskette:
 Indicates that the selected file must go on a write-protected disk. For example, you may want to store uncompressed binary files (.EXE files) that might be targets of viruses on a read-only diskette.
4.
Setup Diskette (#1):
 Indicates that the selected file must go on the first disk in the installation disk set. For example, you would choose this option for your Setup program.
5.
Do Not Lay Out File:
 Indicates that the selected file should not be placed on an installation disk. Use this option for files that reside in your project directories but are not part of the product installation, such as source code management files.
File Attributes
Marks a file in the layout file as having one or more attributes. Check one or more of the following:
·
System File:
 The file is a system file, such as WINHELP.EXE or GDI.EXE.
·
Shared File:
 The selected file may be shared by one or more applications, such as a common code library that ships with all of your company products.
·
Vital File:
 The installation will fail unless the selected file is installed successfully. This option is the default.
Set File Date
Specifies the date stamp used for the file when it is copied into a disk image directory by Dsklayt2 and when Setup copies the file onto the user's hard disk. Choose one of the following options:
·
Source Date:
 Uses the date of the installable file.
·
Other:
 Uses the date you specify in the adjacent text box (in the format YYYY-MM-DD). Use this option when you want the date on all installed files to be a significant date, such as the product release date.
Compress
Determines whether the selected file should be compressed by Dsklayt2.
Check For Version
Tells Dsklayt2 to check the source file for the existence of a version resource. If the version resource exists, Dsklayt2 puts this information into the .INF file. Otherwise, Dsklayt2 issues a warning and leaves this portion of the file description blank in the .INF file.
Reference Key
Specifies a unique reference for the selected file. Use this option when you want the Setup program to determine whether to install the selected file based on information available at the time of the installation. For example, the type of monitor on the user's system could affect the files you install for your product. You can also use this option when you want to display reference keys rather than filenames in the dialog boxes displayed by the installation, because the keys are more descriptive than the filenames.
Put In Section
Specifies a unique .INF section name for the selected file. Use this field when you want installation files organized by categories rather than all listed in the default "Files" section of the .INF file.
Install-Time Options:
Overwrite
Specifies what should happen if the selected file already exists on the user's hard disk. Choose one of the following options:
·
Always:
 The installed file will always overwrite any existing version of the file.
·
Never:
 The installed file will never overwrite an existing version of the file.
·
Older:
 The installed file will overwrite an existing version of the file only if the existing version is older. Setup will look for version information; if none exists, it will use the file dates to determine which file is older.
·
Unprotected:
 The installed file will overwrite an existing version of the file only if the existing version has a file attribute of "Write."
Decompress
Indicates that Setup should check to see if the source file is compressed and, if so, decompress it before copying it onto the user's hard disk. You should leave this option checked in most cases, even if the source file is not compressed.
Mark as Read Only
Indicates that you want the file to have a file attribute of "Read Only" when it is copied onto the user's hard disk.
Rename Copied File
Indicates that you want to rename the file to the filename you supply in the adjacent text box when it is copied onto the user's hard disk.
Backup Existing File
Indicates that you want to back up an existing version of the file to the filename you supply in the adjacent text box before copying the source file. If you type an asterisk (*), Setup will back up the file to the same name with a .BAK extension.


File menu
New
Creates a new, untitled layout file.
Open
Displays a dialog box that you can use to open an existing layout file so that you can update it. Dsklayt checks for new product files and notifies you if there are any.
Save
Saves any changes you have made to the currently open layout file.
Save As
Displays a dialog box that you can use to save the current layout file under a name you specify.
Exit
Exits Dsklayt and returns you to the most recently active window. If you have made changes but did not save them, Dsklayt prompts you to save.


Options menu
Disk Labels
Displays a dialog box that lets you add, delete, or modify the disk labels for your installation disks.
To insert a new label, select the label in the list box that you want to follow the new label, type the new label name in the text box, and then click Add. To delete a label, select it from the list box and then click Delete. To modify a label, select it from the list box, click Delete, type the correct text in the text box, and then click Add.
You can use generic labels, such as "Disk 1," until you see how the files are organized on the disks. You can then rename the labels to reflect the content of the disks.
You can specify which disk label goes on the writable disk by selecting the label in the drop-down list box at the bottom of the dialog box.
Note
  The order in which you add disk labels is the order in which Dsklayt2 will apply them to the disk images.
Remove Files List
Displays a dialog box in which you can create one or more lists of files that you want Setup to remove from the user's hard disk during product installation. Use this list to remove obsolete files or older versions of files whose names differ from the newer versions.
To add a file to a removal list, type its filename in the Filename box, type the name of the .INF section in the .INF Section box (if necessary), and then click Add. If you don't type a section name in the .INF Section box, Dsklayt2 adds the name of the file to the "Files" section in the .INF file.
To delete a file from a removal list, select it from the list box and click Delete. To modify a filename in a removal list, select it from the list box, click Delete, type the correct filename in the Filename box, and then click Add.


Help menu
About
Displays a dialog box that provides copyright and version information for Dsklayt.


Using the MS-DOS-Based Dsklayt2 Program
Using the Dsklayt2 Program
After saving your specifications in a layout file, use the Dsklayt2 program to generate disk images and the .INF file for your product installation. Dsklayt2 reads the directives in the layout file and creates a directory of disk images that you can copy onto disks using the Diskcopy command.
The Dsklayt2 program has the following command line syntax:
Dsklayt2
[drive:][path]layout_filename [[drive:][path]INF_filename]
[options]
Parameter
Description
drive:path for layout_filename
The drive letter and path of the layout file.
layout_filename
The name of the layout file that Dsklayt2 should read to create the disk images. This argument is required.
drive:path for .INF_filename
The drive letter and path of the .INF file.
INF_filename
The name of the .INF file that you want Dsklayt2 to create. If you do not specify a filename, Dsklayt2 uses SETUP.INF.
Options:
  /k{
n
}
Specifies the type of disk Dsklayt2 should target when creating the disk images. For
n,
 you can specify:
·
 A standard size ("360," "720," "12," or "144"), "N" for Network
·
 O
n/m
 for Other, where
n/m
 is the bytes per cluster and the cluster per disk, respectively.
The default is 1.2 MB.
  /f
Specifies that Dsklayt2 should overwrite the existing .INF file, if necessary.
  /w{
n
}
Specifies the writable disk. For
n,
specify a disk number. This field overrides the specification in the layout file. If you omit this option, Dsklayt2 makes the last disk in the installation the writable disk. If you specify the option without a disk number, Dsklayt2 assumes that all disks are read-only.
  /d
{destdir}
Specifies the destination directory for the disk images. Dsklayt2 creates a directory for each disk image, named DISK 1, DISK 2, and so on. If your product will be installed from a network drive (that is, if the /k option specifies a network device), all files are placed at the top-level destination directory. If you omit this option, Dsklayt2 will not create any files in the destination directory.
  /c
{compdir}
Specifies the directory where Dsklayt2 can put compressed versions of the files. If you specify the same directory each time you run Dsklayt2, the program adds or updates only those files that are new or have changed. If you omit this option, Dsklayt2 creates a COMP subdirectory in the parent of the source directory. If the source directory is the root directory, Dsklayt2 displays an error message and aborts.
  /z
{compcmd}
Specifies a compression utility that Dsklayt2 can use to compress files. For
compcmd,
specify the operating system command that will execute the compression utility. Dsklayt2 will call this command with two arguments: the source directory and the destination directory. If this option is not specified, Dsklayt2 looks for COMPRESS.EXE in the path.  (To specify internal compression only use
lzi
.)


Setup Procedures
This chapter describes the functions and subroutines that you can call in your installation program. They are listed in alphabetical order.
Note
  All functions and subroutines are declared in the Setup .C files. The descriptions in this chapter show the calling syntax for each procedure.
To:
Use these procedures:
Manipulate what the user sees
on the screen
DoMsgBox
InitSetupToolkit
RestoreCursor
SetBeepingMode
SetBitmap
SetCopyGaugePosition
SetSilentMode
SetTitle
ShowWaitCursor
UIPop
UIPopAll
UIStartDlg
Manipulate a list associated with a
symbol in the Symbol Table
AddListItem
GetListItem
GetListLength
GetSymbolValue
MakeListFromSectionKeys
RemoveSymbol
ReplaceListItem
SetSymbolValue
Modify the contents of the global list of installable files (the copy list)
AddSectionFilesToCopyList
AddSectionKeyFileToCopyList
AddSpecialFileToCopyList
ClearCopyList
CopyFilesInCopyList
DumpCopyList
GetCopyListCost
Control aspects of the copy list
installation
SetCopyMode
SetDecompMode
Manipulate billboard dialog boxes
and the global billboard list
AddBlankToBillboardList
AddToBillboardList
ClearBillboardList
Manipulate a file on the user's system
BackupFile
CopyAFile
DoesFileExist
FindFileInTree
FindFileUsingFileOpen
FindTargetOnEnvVar
GetDateOfFile
GetSizeOfFile
GetVersionNthField
GetVersionOfFile
HandleSharedFile
InStr
IsFileWritable
PrependToPath
RemoveFile
RenameFile
RightTrim
StampResource
SzCatStr
SzCat2Str
SzCat3Str
Manipulate a directory on the
user's system
CreateDir
RemoveDir
DoesDirExist
GetWindowsDir
IsDirWritable
Update an .INI file
CreateIniKeyValue
CreateSysIniKeyValue
DoesIniKeyExist
DoesIniSectionExist
FValidIniFile
GetIniKeyString
GetNthFieldFromIniString
RemoveIniKey
RemoveIniSection
Create a Program Manager group
and item for your product
CreateProgmanGroup
CreateProgmanItem
ShowProgmanGroup
Add information to or get information
from the Registration Database
CreateRegKey
CreateRegKeyValue
DeleteRegKey
DeleteAllSubkeys
DoesRegKeyExist
GetRegKeyValue
SetRegKeyValue
Install system resources (that may be
in use while Windows is running)
ExitExecRestart
RestartListEmpty
SearchForLocationForSharedFile
SetRestartDir
Create a record of what occurred during
an installation
CloseLogFile
OpenLogFile
SetAbout
WriteToLogFile
Query the user's environment
FValidDrive
GetConfigLastDrive
GetConfigNumBuffers
GetConfigNumFiles
GetConfigRamdriveSize
GetConfigSmartdrvSize
GetDOSMajorVersion
GetDOSMinorVersion
GetEnvVariableValue
GetFreeSpaceForDrive
GetLocalHardDrivesList
GetNetworkDrivesList
GetNumWinApps
GetParallelPortsList
GetProcessorType
GetRemovableDrivesList
GetScreenHeight
GetScreenWidth
GetSerialPortsList
GetTotalSpaceForDrive
GetTypeFaceNameFromTTF
GetValidDrivesList
GetWindowsMajorVersion
GetWindowsMinorVersion
GetWindowsMode
GetWindowsSysDir
Has87MathChip
HasMonochromeDisplay
HasMouseInstalled
IsDriveLocalHard
IsDriveNetwork
IsDriveRemovable
IsDriverInConfig
IsDriveValid
IsWindowsShared
Parse a date field
GetDayFromDate
GetHourFromDate
GetMinuteFromDate
GetMonthFromDate
GetSecondFromDate
GetYearFromDate
Retrieve information about the topmost frame window
HinstFrame
HwndFrame
Read or manipulate information from the .INF file
FValidInfSect
GetSectionKeyDate
GetSectionKeyFilename
GetSectionKeySize
GetSectionKeyVersion
MakeListFromSectionDate
MakelistFromSectionFilename
MakeListFromSectionKeys
MakeListFromSectionSize
MakeListFromSectionVersion
ReadInfFile
RemoveSymbol
ReplaceListItem
Set and remove environment variable values.
SetEnvVariable
RemoveEnvVariable
Uninstall an installation.
FStoreUninstallData
FUninstall


AddBlankToBillboardList
VOID AddBlankToBillboardList(LONG
lTicks
);
AddBlankToBillboardList
 adds a hidden dialog box to the global billboard list. The hidden dialog box destroys the previous billboard dialog box and delays the display of the next billboard dialog box.
Argument
lTicks
Defines the amount of time you want to delay the display of the next billboard dialog box. The unit is arbitrary, relative to a total number of units.
Comments
Use
AddBlankToBillboardList
 prior to calling
CopyFilesInCopyList
.


AddListItem
int AddListItem(LPSTR
szListSymbol
,
LPSTR
szListItem
);
AddListItem
 adds a new item to the end of the list associated with the specified symbol name.
Arguments
szListSymbol
Specifies the name of the symbol in the Symbol Table to which the list is associated.
szListItem
Specifies the item that you want to add to the list.
Comments
If
szListSymbol
 is previously undefined, a new list with the specified item is created and associated with the symbol name. You can create a new, empty list by using
SetSymbolValue
 and specifying the value as " ".


AddSectionFilesToCopyList
VOID AddSectionFilesToCopyList(LPSTR
szSect
, LPSTR
szSrc
, LPSTR
szDest
)
;
AddSectionFilesToCopyList
 adds all file descriptions from the specified section of the .INF file to the global list of installable files (the copy list).
Arguments
szSect
Specifies the name of the section in the .INF file that contains the files you want to add to the copy list.
szSrc
Specifies the full path of the directory where the files currently reside. Typically, you use the value associated with the symbol STF_SRCDIR for
szSrc.
szDest
Specifies the full path of the directory to which the files will be copied.
Comments
You must call
ReadInfFile
 before using
AddSectionFilesToCopyList
.


AddSectionKeyFileToCopyList
VOID AddSectionKeyFileToCopyList(LPSTR
szSect
, LPSTR
szKey
, LPSTR
szSrc
, LPSTR
szDest
);
AddSectionKeyFileToCopyList
 adds a file description identified by the reference key from the .INF file to the global list of installable files (the copy list).
Arguments
szSect
Specifies the name of the section in the .INF file that contains the file you want to add to the copy list.
szKey
Specifies the reference key for the file you want to add to the copy list.
szSrc
Specifies the full path of the directory where the file currently resides. Typically, you use the value associated with the symbol STF_SRCDIR for
szSrc$
.
szDest
Specifies the full path of the directory to which the file will be copied.
Comments
You must call
ReadInfFile
 before using
AddSectionKeyFileToCopyList
.


AddSpecialFileToCopyList
VOID AddSpecialFileToCopyList(LPSTR
szSect
, LPSTR
szKey
, LPSTR
szSrc
, LPSTR
szDest
);
AddSpecialFileToCopyList
 adds the file description of a special file, such as a shared resource, from the .INF file to the global list of installable files (the copy list).
Arguments
szSect
Specifies the name of the section in the .INF file that contains the file you want to add to the copy list.
szKey
Specifies the reference key for the file you want to add to the copy list.
szSrc
Specifies the full path of the directory where the file currently resides. Typically, you use the symbol STF_SRCDIR for
szSrc$
.
szDest
Specifies the full path of the file to be copied.
Comments
You must call
ReadInfFile
 before using
AddSpecialFileToCopyList
.


AddToBillboardList
VOID AddToBillboardList(LPSTR
szDll
, INT
idDlg
, LPSTR
szProc
, LONG
lTicks
);
AddToBillboardList
 adds a billboard dialog box to the end of the global billboard list. The dialog box will be displayed during the next
CopyFilesInCopyList
 call.
Arguments
szDll
Specifies the name of the .DLL file that contains the dialog box resource and procedure.
idDlg
Specifies the dialog box resource identification number.
szProc
Specifies the name of the dialog box procedure.
lTicks
Defines the amount of time you want the billboard dialog box to display. The unit is arbitrary, relative to the total number of units specified at the time the files are copied onto the user's hard disk or network drive.


BackupFile
VOID BackupFile(LPSTR
szFullPath
, LPSTR
szBackup
);
BackupFile
 backs up the specified file by renaming it.
Arguments
szFullPath
Specifies the full path and name of the file you want to create a copy of.
szBackup
Specifies the filename of the copy.
Comments
The copy is placed in the same directory as the original file(as specified by
szFullPath
).
BackupFile
 is identical to
RenameFile
.


ClearBillboardList
VOID ClearBillboardList(VOID);
ClearBillboardList
 deletes all dialog boxes from the global billboard list.


ClearCopyList
VOID ClearCopyList(VOID);
ClearCopyList
 removes all file entries from the global list of installable files (or copy list).


CloseLogFile
VOID CloseLogFile(VOID);
CloseLogFile
 closes the currently open log file.


CopyAFile
VOID CopyAFile(LPSTR
szFullPathSrc
, LPSTR
szFullPathDst
, INT
cmo
, INT
fAppend
);
CopyAFile
 copies the specified file from its source directory to its destination directory.
Arguments
szFullPathSrc
Specifies the full path of the file you want to copy.
szFullPathDst
Specifies the full path of the destination directory for the file.
cmo
Specifies one or more command option flags. You can use one or more of the following for
cmo
(by adding them together):
cmoDecompress, cmoTimeStamp, cmoReadOnly, cmoOverwrite, cmoNone,
or
cmoAll .
fAppend
Specifies whether you want any existing file to be appended to. A value of one indicates that you want to append to an existing file; zero indicates that you want to remove the existing file before copying the new file.


CopyFilesInCopyList
VOID CopyFilesInCopyList(VOID);
CopyFilesInCopyList
 sorts the file descriptions in the global list of installable files (the copy list) and then copies them from their source directory to their destination directory.
Comments
The files are sorted by their source disk identification number to minimize the number of times the user has to insert disks during the installation. The source and destination directories are specified in the functions that add the files to the copy list.


CreateDir
VOID CreateDir(LPSTR
szDir
, INT
cmo
);
CreateDir
 creates a directory with the specified path and name.
Arguments
szDir
Specifies the complete path and name of the directory you want to create (starting with the disk drive letter and backslash).
cmo
Specifies a command option flag. You can use
cmoVital
 or
cmoNone
. If the directory already exists, the subroutine does nothing.


CreateIniKeyValue
VOID CreateIniKeyValue(LPSTR
szFile
, LPSTR
szSect
, LPSTR
szKey
, LPSTR
szValue
, INT
cmo
);
CreateIniKeyValue
 creates a symbol and an associated value in the designated section of the .INI file.
Arguments
szFile
Specifies the name of the .INI file in which you want to create the symbol and value. If the file you specify is WIN.INI, you do not have to provide the full path. If the file you specify does not exist, it is created.
szSect
Specifies the section name in which you want to create the symbol and value.
szSect
 must be a non-empty string.
szKey
Defines the name of the symbol you want to create. If
szKey
 already exists,
CreateIniKeyValue
 will fail unless you specify
cmoOverwrite
 for the command option flag.
szValue
Defines the value that will be associated with the symbol.
cmo
Specifies the command option flag. You can use
cmoVital
,
cmoNone
,
cmoAll
, or
cmoOverwrite
.


CreateProgmanGroup
VOID CreateProgmanGroup(LPSTR
szGroup
, LPSTR
szPath
, INT
cmo
);
CreateProgmanGroup
 creates a new Program Manager group with the specified name.
Arguments
szGroup
Specifies the name of the Program Manager group you want to create. This name will be displayed in the group window title bar (or below the icon when the group window is minimized).
szPath
Specifies the name and path for the Program goup that you want to create. If you provide an empty string for
szPath
(the suggested method), a default file is created.
cmo
Specifies the command option flag. You can use
cmoVital
or
 cmoNone
.
Comments
Typically, you should use an empty string for
szPath.


CreateProgmanItem
VOID CreateProgmanItem(LPSTR
szGroup
, LPSTR
szItem
, LPSTR
szCmd
, LPSTR
szOther
, INT
cmo
);
CreateProgmanItem
 creates a new item in the specified Program Manager group.
Arguments
szGroup
Specifies the name of the Program Manager group in which you want to create the item. If
szGroup
 does not exist,
CreateProgmanItem
 does nothing.
szItem
Specifies the description that will be displayed below the item.
szCmd
Specifies the path and executable filename for the new item.
szOther
Specifies an optional icon file, icon resource index,
x
 and
y
 icon positions for the new item, and the working directory, separated by commas. If you provide an empty string for
szOther
, defaults are used. However, if you need to specify one of the latter options in the string, you must specify the preceding ones.
cmo
Specifies the command option flag. You can use
cmoVital
 or
cmoOverwrite
. If you use
cmoOverwrite
and the user is running Windows version 3.1, Setup will replace an existing Program Manager item.
See Also
Command Option Flags
,
Guide to Programming.


CreateRegKey
void CreateRegKey(LPSTR
szKey
);
CreateRegKey
 creates a Registration Database key that is a subkey of HKEY_CLASSES_ROOT.
Argument
szKey
Specifies the name of the key you want to create. This key will have no associated value.


CreateRegKeyValue
void CreateRegKeyValue(LPSTR
szKey
, LPSTR
szValue
);
CreateRegKeyValue
 creates a Registration Database key that is a subkey of HKEY_CLASSES_ROOT and associates a value with the key.
Arguments
szKey
Specifies the name of the key you want to create.
szValue
Specifies the value you want to associate with the key.


CreateSysIniKeyValue
VOID CreateSysIniKeyValue(LPSTR
szFile
, LPSTR
szSect
, LPSTR
szKey
, LPSTR
szValue
, INT
cmo
);
CreateSysIniKeyValue
 adds the specified symbol and its associated value to the .INI file.
Arguments
szFile
Specifies the full path of the .INI file.
CreateSysIniKeyValue
 should not be used to modify WIN.INI.
szSect
Specifies the name of the section in which you want to add the symbol-value pair.
szSect$
 must be a non-empty string.
szKey
Specifies the name of the symbol you want to add. This string does not have to be unique.
szValue
Defines the value you want to associate with the symbol.
cmo
Specifies the command option flag. You can use
cmoVital
 or
cmoNone
.
Comments
Use
CreateSysIniKeyValue
, rather than
CreateIniKeyValue
, to add symbol-value pairs with non-unique keys to the .INI file. For example, you could add a line such as
DEV = *.VGA
where DEV = is likely to occur several times in the file.


DeleteAllSubKeys
BOOL DeleteAllSubKeys(HKEY
hKey
, LPCTSTR
szKey
);
DeleteAllSubkeys
 deletes a subkey and all of its subkeys.
Argument
hKey
Specifies the handle of an open key.
szKey
Address of the name of the subkey to delete.


DeleteRegKey
void DeleteRegKey(LPSTR
szKey
);
DeleteRegKey
 removes the specified Registration Database key, its associated values, and subkeys.
Argument
szKey
Specifies the name of the key you want to remove.


DoesDirExist
BOOL DoesDirExist(LPSTR
szDir
);
DoesDirExist
 determines if the specified directory exists.
Argument
szDir
Specifies the name of the directory.
Return Value
If the directory exists, the return value is one. Otherwise, the return value is zero.


DoesFileExist
BOOL DoesFileExist(LPSTR
szFile
, int
mode
);
DoesFileExist
 determines if the specified file exists, can be read from, can be written to, or all of these states.
Arguments
szFile
Specifies the name of the file you want to inquire about.
mode
Specifies the file exist mode (femExists, femRead, femWrite, femReadWrite) you want to inquire about.
Return Value
If the answer is yes, the return value is one. Otherwise, the return value is zero.


DoesIniKeyExist
BOOL DoesIniKeyExist(LPSTR
szFile
, LPSTR
szSect
, LPSTR
szKey
);
DoesIniKeyExist
 determines if the specified key exists in the specified section of the .INI file.
Arguments
szFile
Specifies the name of the .INI file. If you specify WIN.INI, you do not have to provide the full path.
szSect
Specifies the section of the file.
szSect
 must be a non-empty string.
szKey
Specifies the key (or symbol) you are looking for.
Return Value
If the key exists, the return value is one. Otherwise, the return value is zero.


DoesIniSectionExist
BOOL DoesIniSectionExist(LPSTR
szFile
, LPSTR
szSect
);
DoesIniSectionExist
 determines if the specified section exists in the .INI file.
Arguments
szFile
Specifies the name of the .INI file. If you specify WIN.INI, you do not have to provide the full path.
szSect
Specifies the section of the file.
 szSect
 must be a non-empty string.
Return Value
If the section exists, the return value is one. Otherwise, the return value is zero.


DoesRegKeyExist
int DoesRegKeyExist(LPSTR
szKey
);
DoesRegKeyExist
 checks for the existence of the specified key in the Registration Database.
Argument
szKey
Specifies the name of the key. This key is assumed to be a subkey of HKEYS_CLASSES_ROOT.
Return Value
If the key exists, the return value is one. Otherwise, the return value is zero.


DoesSharedFileNeedCopying
BOOL DoesSharedFileNeedCopying(VOID);


DoMsgBox
int DoMsgBox(LPSTR
lpText
, LPSTR
szCaption
, INT
wType
);
DoMsgBox
 launches a Windows message box containing the specified caption and text.
Arguments
szText
Specifies the text you want to appear in the message box.
szCaption
Specifies the caption for the message box.
wType
Specifies the contents of the message box.
wType
 can be a combination of values.
Return Value
The return value is the value of the button control that the user selected (such as IDOK). If there is not enough memory to create the message box, the return value is zero.
Comments
DoMsgBox
 is similar to the Windows
MessageBox
 function. The valid message box values and control values are the same as for
MessageBox
.
See Also
For more information on
MessageBox
, message box values, and control values, see the
Programmer's Reference.


DumpCopyList
VOID DumpCopyList(LPSTR
szFile
);
DumpCopyList
 prints the contents of the global list of installable files (the copy list) to the specified file.
Argument
szFile
Specifies the path and name of the file to which you want the list to be copied.
Comments
Use
DumpCopyList
 when debugging your installation files.


EndSetupToolkit
VOID EndSetupToolkit(VOID);


ExitExecRestart
int ExitExecRestart(VOID);
ExitExecRestart
 installs system resources that may be in use by Windows (and therefore can't be overwritten).
Return Value
If the function succeeds, it doesn't return. The return value is true (one) if the restart list is empty or the user is running Windows version 3.0 (see comments below). The return value is false (zero) if there are write errors, the restart fails, Windows can't exit, or the function can't find _MSSETUP.EXE.
Comments
This function returns a value but can fail for one of three reasons: if the restart list is empty, if the user is running Windows version 3.0 (which does not support the function), or if an error occurs (such as Windows not exiting because of open MS-DOS boxes or applications). Therefore, you should use the
RestartListEmpty
 function to determine the contents of the restart list before calling this function. You should also check the current version of Windows. If the user is running Windows version 3.0, you will need to provide a message box explaining that the user must exit Windows and run the batch file to update the shared resources. In addition, you should warn the user to close all MS-DOS boxes and applications.
ExitExecRestart
 exits Windows and executes _MSSETUP.EXE to read any commands that have been placed in _MSSETUP.BAT. (Commands are placed in _MSSETUP.BAT when a file in the copy list is specified as a system resource, Setup determines that it is a newer version, and it is currently in use.)
ExitExecRestart
 will then delete _MSSETUP.EXE and _MSSETUP.BAT before restarting Windows. You must call
SetRestartDir
 before using
ExitExecRestart
.


FindFileInTree
LPSTR FindFileInTree(LPSTR
szFile
, LPSTR
szDir
, LPSTR
szBuf
, int
cbBuf
);
FindFileInTree
 searches for the specified file in a directory and its subdirectories.
Arguments
szFile
Specifies the name of the file you are trying to locate.
szDir
Specifies the top-level directory of the tree structure you want to search.
szBuf
Points to the destination buffer that will receive the path string.
cbBuf
Length, in bytes, of the destination buffer.
Return Value
The return value is the full path of the first instance of the file. If the file isn't found, the return value is an empty string.


FindFileUsingFileOpen
LPSTR FindFileUsingFileOpen(LPSTR
szFile
, LPSTR
szBuf
, INT
cbBuf
);
FindFileUsingFileOpen
 locates a file by using the Windows
FileOpen
 function.
Arguments
szFile
Specifies the name of the file you want to find.
szBuf
Points to the destination buffer that will receive the path string.
cbBuf
Length, in bytes, of the destination buffer.
Return Value
The return value is the full path of the file. If the file isn't found, the return value is an empty string.


FindTargetOnEnvVar
LPSTR FindTargetOnEnvVar(LPSTR
szFile
, LPSTR
szEnvVar
, LPSTR
szBuf
, int
cbBuf
);
FindTargetOnEnvVar
 searches for the specified file in directories based on the designated environment variable (such as PATH).
Arguments
szFile
Specifies the name or partial path of the file you are trying to locate.
szEnvVar
Specifies the environment variable for the search.
szBuf
Points to the destination buffer that will receive the string.
cbBuf
Length, in bytes, of the destination buffer.
Return Value
The return value is the full path of the specified file. If the file isn't found, the return value is an empty string.


FStoreUninstallData
BOOL FStoreUninstallData(LPSTR
szUninstallDataFile
);
FStoreUninstallData
 stores information on the current installation. It stores the files, directories, environment variables, and Program Manager items and groups that were installed. This information is required for a subsequent call to
FUninstall
.
Argument
szUninstallDataFile
Specifies the name of the file in which to store the installation information.
Return Value
If the function succeeds, it returns
fTrue
.
If the function fails, it returns
fFalse
.
See Also
FUninstall


FUninstall
BOOL FUninstall(LPSTR
szUninstallDataFile
,
 LPSTR
 szNewPath
);
FUninstall
 removes the files, directories, environment variables. and Program Manager items and groups created during installation.
Arguments
szUninstallDataFile
Specifies the name of the file that contains the installation data. This file was previously created by
FStoreUninstallData
, which should be run at the end of the initial setup.
szNewPath
Specifies a directory to place files that were found in the installation directory structure, but which were not part of the installation. If
szNewPath
 is NULL, then these files will be left in the installation directory.
Return Value
If the function succeeds, it returns
fTrue
.
If the function fails, it returns
fFalse
.
See Also
FStoreUninstallData


FValidDrive
int FValidDrive(LPSTR
szDrive
);
FValidDrive
 determines whether or not a specified pathname begins with a valid drive letter. For example, if the the first character is between a and z and the next character is either a NULL or a colon (:), the pathname is valid.
Arguments
szDrive
The specified pathname.


FValidInfSect
int FValidInfSect(LPSTR
szSect
);
FValidInfSect
 determines if the specified .INF section name is valid.
Arguments
szSect
Specifies the .INF section name.
Return Value
Returns a 0 if the section name is invalid and a 1 if the section name is valid.


FValidIniFile
int FValidIniFile(LPSTR
szFile
);
int FValidIniFile
 determines if the path to an .INI file is valid.
Arguments
szFile
Specifies the full path to the .INI file.
Return Value
Returns TRUE if the path is either valid or
szfile
 equals WIN.INI.


GetConfigLastDrive
LPSTR GetConfigLastDrive(LPSTR
szBuf
, int
cbBuf
);
GetConfigLastDrive
 determines the LASTDRIVE set in the CONFIG.SYS file.
Arguments
szBuf
Points to the destination buffer that will receive the string.
cbBuf
Length, in bytes, of the destination buffer.
Return Value
The return value is the string for LASTDRIVE.


GetConfigNumBuffers
int GetConfigNumBuffers(VOID);
GetConfigNumBuffers
 determines the number of BUFFERS set in the CONFIG.SYS file.
Return Value
The return value is the number of BUFFERS.


GetConfigNumFiles
int GetConfigNumFiles(VOID);
GetConfigNumFiles
 determines the number of FILES set in the CONFIG.SYS file.
Return Value
The return value is the number of FILES.


GetCopyListCost
LONG GetCopyListCost(LPSTR
szExtraList
, LPSTR
szCostList
, LPSTR
szNeedList
);
GetCopyListCost
 examines the files listed in the global list of installable files (the copy list) and determines the amount of disk space needed to copy, back up, and overwrite files. The values retrieved are associated with symbols in the Symbol Table.
Arguments
szExtraList
Symbol whose associated value identifies the extra, or incidental, disk space needed on each disk drive to update files such as .INI files. The symbol value is a list of as many as 26 integers. Missing values are assumed to be zero.
szCostList
Symbol whose associated value is set to a list of 26 numbers, each of which identifies the cost per disk drive to copy and update files. A positive number is the amount of free space that will be used by new or larger files. A negative number is the amount of space that will be freed by removing files or replacing existing files with smaller versions.
szNeedList
Symbol whose associated value is set to a list of 26 numbers, each of which identifies the additional space needed per disk drive. Each entry in
szCostList
 that is not zero has a corresponding entry in this list that is the value in
szCostList
 minus the current free space on that disk drive. A positive number indicates that the new files will not fit (and by how much). A negative number indicates how much free space will be left after the new files are copied.
Return Value
The return value is the total additional free disk space needed. This value is the sum of the positive numbers in
szNeedList.
 If there is enough free disk space on the appropriate disk drives for
CopyFilesInCopyList
 to succeed, the return value is zero.


GetDateOfFile
LPSTR GetDateOfFile(LPSTR
szFile
, LPSTR
szBuf
, int
cbBuf
);
GetDateOfFile
 determines the file date of the specified file.
Arguments
szFile
Specifies the full path of the file.
szBuf
Points to the destination buffer that will receive the date string.
cbBuf
Length, in bytes, of the destination buffer.
Return Value
The return value is the date in YYYY-MM-DD-HH-MM-SS format. If
szFile
 does not exist, or if it has an invalid date, the return value will be 1980-01-01-00-00-00.


GetDayFromDate
int GetDayFromDate(LPSTR
szDate
);
GetDayFromDate
 retrieves the day field from the return value for
GetDateOfFile
.
Argument
szDate
Specifies the date in YYYY-MM-DD-HH-MM-SS format. This value is obtained from the
GetDateOfFile
 function.
Return Value
The return value is an integer with a valid range from 1 through 31.


GetDOSMajorVersion
int GetDOSMajorVersion(void);
GetDOSMajorVersion
 determines the major version number of the currently installed MS-DOS.
Return Value
The return value is the major version number of MS-DOS.


GetDOSMinorVersion
int GetDOSMinorVersion(void);
GetDOSMinorVersion
 determines the minor version number of the currently installed MS-DOS.
Return Value
The return value is the minor version number of MS-DOS.


GetEnvVariableValue
LPSTR GetEnvVariableValue(LPSTR
szEnvVar
,
LPSTR
szBuf
,
int
cbBuf
);
GetEnvVariableValue
 determines the associated value for the specified environment variable.
Arguments
szEnvVar
Specifies the environment variable name.
szBuf
Points to the destination buffer that will receive the string.
cbBuf
Length, in bytes, of the destination buffer.
Return Value
The return value is the string associated with the environment variable. If there is no associated value, the string is empty.


GetFreeSpaceForDrive
LONG GetFreeSpaceForDrive(LPSTR
szDrive
);
GetFreeSpaceForDrive
 determines the amount of free space available on the specified disk drive.
Argument
szDrive
Specifies a string identifying the disk drive letter (A through Z).
Return Value
The return value is the amount of free disk space. If
szDrive
 is not a valid disk drive, the return value is zero.


GetHourFromDate
int GetHourFromDate(LPSTR
szDate
);
GetHourFromDate
 retrieves the hour field from the return value for
GetDateOfFile
 .
Argument
szDate
Specifies the date in YYYY-MM-DD-HH-MM-SS format. This value is obtained from
GetDateOfFile
.
Return Value
The return value is an integer with a valid range from 0 through 23.


GetIniKeyString
LPSTR GetIniKeyString(LPSTR
szFile
, LPSTR
szSect
, LPSTR
szKey
, LPSTR
szBuf
, int
cbBuf
);
GetIniKeyString
 searches the .INI file for the specified key string.
Arguments
szFile
Specifies the .INI file that you want to search. If you specify WIN.INI, you do not have to provide the full path.
szSect
Specifies the section of the file to be searched.
 szSect
 must be a non-empty string.
szKey
Specifies the key or symbol you want to search for.
szBuf
Points to the destination buffer that will receive the string.
cbBuf
Length, in bytes, of the destination buffer.
Return Value
If the key is found, the return value is the full string associated with the key. Otherwise, the return value is an empty string.


GetListItem
LPSTR GetListItem(LPSTR
szSymbol
, INT
n
, LPSTR
szBuf
, INT
cbBuf
);
GetListItem
 retrieves a single item from the list associated with the specified symbol name.
Arguments
szSymbol
Specifies the name of the symbol in the Symbol Table with which the list is associated.
n
Specifies the index (one-based) of the item you want to retrieve.
szBuf
Points to the destination buffer that will receive the string.
cbBuf
Length, in bytes, of the destination buffer.
Return Value
The return value is the item from the list.
Comments
If the string is empty, the symbol or item does not exist.


GetListLength
int GetListLength(LPSTR
szSymbol
);
GetListLength
 determines the number of items in the list associated with the specified symbol name.
Argument
szSymbol
Specifies the name of the symbol in the Symbol Table with which the list is associated.
Return Value
The return value is the number of items in the list.


GetLocalHardDrivesList
void GetLocalHardDrivesList(LPSTR
szSymbol
);
GetLocalHardDrivesList
 sets the specified symbol to a list of all local hard drives (that is, "A", "B", and so on).
Argument
szSymbol
Specifies the name of the symbol to associate with the list.


GetMinuteFromDate
int GetMinuteFromDate(LPSTR
szDate
);
GetMinuteFromDate
 retrieves the minute field from the return value for
GetDateOfFile
.
Argument
szDate
Specifies the date in YYYY-MM-DD-HH-MM-SS format. This value is obtained from the
GetDateOfFile
 function.
Return Value
The return value is an integer with a valid range from 0 through 59.


GetMonthFromDate
int GetMonthFromDate(LPSTR
szDate
);
GetMonthFromDate
 retrieves the month field from the return value for
GetDateOfFile
.
Argument
szDate
Specifies the date in YYYY-MM-DD-HH-MM-SS format. This value is obtained from
GetDateOfFile
.
Return Value
The return value is an integer with a valid range from 1 through 12.


GetNetworkDrivesList
void GetNetworkDrivesList(LPSTR
szSymbol
);
GetNetworkDrivesList
 sets the specified symbol to a list of all network drives (that is, "A", "B", and so on).
Argument
szSymbol
Specifies the name of the symbol to associate with the list.


GetNthFieldFromIniString
LPSTR GetNthFieldFromIniString(LPSTR
szLine
, INT
iField
, LPSTR
szBuf
, INT
cbBuf
);
GetNthFieldFromIniString
 extracts the specified comma-separated field from the specified string.
Arguments
szLine
Specifies the string from which you want to extract the field.
iField
Specifies the index (one-based) of the field that you want to extract.
szBuf
Points to the destination buffer that will receive the string.
cbBuf
Length, in bytes, of the destination buffer.
Return Value
The return value is the field. If the requested field doesn't exist or is invalid, the return value is an empty string.


GetNumWinApps
int GetNumWinApps(void);
GetNumWinApps
 determines the number of unique instances of Windows applications currently running in the system.
Return Value
The return value is the number of applications.


GetParallelPortsList
void GetParallelPortsList(LPSTR
szSymbol
);
GetParallelPortsList
 sets the specified symbol to a list of all parallel ports (that is, "LPT1","LPT2",_).
Argument
szSymbol
Specifies the name of the symbol to associate with the list.


GetProcessorType
int GetProcessorType(void);
GetProcessorType
 determines the type of processor being run on the user's system.
Return Value
The return value is either zero (for 8086), one (for 80186), two (for 80286), three (for 80386), or four (for 80486).


GetRegKeyValue
LPSTR GetRegKeyValue(LPSTR
szKey
, LPSTR
szBuf
, int
cbBuf
);
GetRegKeyValue
 determines the value associated with the specified Registration Database key.
Argument
szKey
Specifies the name of the key whose value you want to retrieve. Because all keys are assumed to be subkeys of HKEYS_CLASSES_ROOT, you only have to specify the name of the key.
szBuf
Points to the destination buffer that will receive the string.
cbBuf
Length, in bytes, of the destination buffer.
Return Value
The return value is the value associated with
szKey
 in the Registration Database.


GetRemovableDrivesList
void GetRemovableDrivesList(LPSTR
szSymbol
);
GetRemovableDrivesList
 sets the specified symbol to a list of all removable drives (that is, "A", "B", and so on).
Argument
szSymbol
Specifies the name of the symbol to associate with the list.


GetScreenHeight
int GetScreenHeight(void);
GetScreenHeight
 determines the height of the screen.
Return Value
The return value is the height of the screen (in pixels).


GetScreenWidth
int GetScreenWidth(void);
GetScreenWidth
 determines the width of the screen.
Return Value
The return value is the width of the screen (in pixels).


GetSecondFromDate
int GetSecondFromDate(LPSTR
szDate
);
GetSecondFromDate
 retrieves the seconds field from the return value for
GetDateOfFile
.
Argument
szDate
Specifies the date in YYYY-MM-DD-HH-MM-SS format. This value is obtained from the
GetDateOfFile
 function.
Return Value
The return value is an integer with a valid range from 0 through 59.


GetSectionKeyDate
LPSTR GetSectionKeyDate(LPSTR
szSect
, LPSTR
szKey
, LPSTR
szBuf
, INT
cbBuf
);
GetSectionKeyDate
 retrieves the date from a file description in the .INF file.
Arguments
szSect
Specifies the name of the section where the file description resides.
szKey
Specifies the name of the key associated with the file description.
szBuf
Points to the destination buffer that will receive the string.
cbBuf
Length, in bytes, of the destination buffer.
Return Value
The return value is the date. This string can be parsed by
GetDayFromDate
,
GetMonthFromDate
,
 and
GetYearFromDate
.


GetSectionKeyFilename
LPSTR GetSectionKeyFilename(LPSTR
szSect
, LPSTR
szKey
, LPSTR
szBuf
, INT
cbBuf
);
GetSectionKeyFilename
 retrieves the filename from a file description in the .INF file.
Arguments
szSect
Specifies the name of the section where the file description resides.
szKey
Specifies the name of the key associated with the file description.
szBuf
Points to the destination buffer that will receive the string.
cbBuf
Length, in bytes, of the destination buffer.
Return Value
The return value is the filename.


GetSectionKeySize
LONG GetSectionKeySize(LPSTR
szSect
, LPSTR
szKey
);
GetSectionKeySize
 retrieves the file size from a file description in the .INF file.
Arguments
szSect
Specifies the name of the section where the file description resides.
szKey
Specifies the name of the key associated with the file description.
Return Value
The return value is the file size in bytes.


GetSectionKeyVersion
LPSTR GetSectionKeyVersion(LPSTR
szSect
, LPSTR
szKey
, LPSTR
szBuf
, INT
cbBuf
);
GetSectionKeyVersion
 retrieves the version number from a file description in the .INF file.
Arguments
szSect
Specifies the name of the section where the file description resides.
szKey
Specifies the name of the key associated with the file description.
szBuf
Points to the destination buffer that will receive the string.
cbBuf
Length, in bytes, of the destination buffer.
Return Value
The return value is the version number. This string can be parsed by
GetVersionNthField
.


GetSerialPortsList
void GetSerialPortsList(LPSTR
szSymbol
);
GetSerialPortsList
 sets the specified symbol to a list of all serial ports (that is, "COM1","COM2", and so on).
Argument
szSymbol
Specifies the name of the symbol to associate with the list.


GetSizeOfFile
LONG GetSizeOfFile(LPSTR
szFile
);
GetSizeOfFile
 determines the size of the specified file.
Argument
szFile
Specifies the path and name of the file.
Return Value
The return value is the size of the file in bytes. If
szFile
 is invalid or does not exist, the return value is zero.


GetSymbolValue
LPSTR GetSymbolValue(LPSTR
szSymbol
, LPSTR
szBuf
, INT
cbBuf
);
GetSymbolValue
 finds the value associated with a symbol in the Symbol Table.
Arguments
szSymbol
Specifies the name of the symbol to be found in the Symbol Table.
szBuf
Points to the destination buffer that will receive the string.
cbBuf
Length, in bytes, of the destination buffer.
Return Value
The return value is the value associated with
szSymbol
 in the Symbol Table. If there is no value associated with
szSymbol
, the return value is an empty string.
Comments
Use this function to retrieve information stored in the Symbol Table by other .DLL file procedures.


GetTotalSpaceForDrive
LONG GetTotalSpaceForDrive(LPSTR
szDrive
);
GetTotalSpaceForDrive
 determines the total amount of disk space for the specified disk drive.
Argument
szDrive
Specifies a string identifying the disk drive letter (A through Z).
Return Value
The return value is the total capacity in bytes of the disk drive. If
szDrive
 is not a valid disk drive, the return value is zero.


GetTypeFaceNameFromTTF
int GetTypeFaceNameFromTTF(LPSTR
szFile
, LPSTR
szBuf
, int
cbBuf
);
GetTypeFaceNameFromTTF
 extracts the typeface name from a TrueType font file.
Arguments
szFile
Specifies the name of the TrueType font file.
szBuff
Specifies the buffer you are providing for the storage of the typeface name.
cbBuff
Specifies the size of the buffer you are providing.
Return Value
If the file you specified is not a TrueType font file, the return value is zero. Otherwise, the return value is the actual length of the typeface name.
Comments
Check to ensure that the return value is not greater than the size of
szBuff.
 If the return value is greater, the typeface name has been truncated.


GetValidDrivesList
void GetValidDrivesList(LPSTR
szSymbol
);
GetValidDrivesList
 sets the specified symbol to a list of all valid disk drives (that is, "A", "B", and so on).
Argument
szSymbol
Specifies the name of the symbol to associate with the list.


GetVersionNthField
LONG GetVersionNthField(LPSTR
szVersion
, int
nField
);
GetVersionNthField
 extracts the specified field from the return value for
GetVersionOfFile
.
Arguments
szVersion
Specifies the string returned from
GetVersionOfFile
.
nField
Specifies the number of the field you want to extract (1 through 4 from the version string).
Return Value
The return value is the integer extracted from
szVersion
.


GetVersionOfFile
LPSTR GetVersionOfFile(LPSTR
szFile
, LPSTR
szBuf
, int
cbBuf
);
GetVersionOfFile
 determines the version of the specified file.
Argument
szFile
Specifies the path and name of the file.
szBuff
Specifies the buffer you are providing for the storage of the typeface name.
cbBuff
Specifies the size of the buffer you are providing.
Return Value
The return value is a string in the format
N.N.N.N
, where each
N
 is an integer.


GetWindowsDir
LPSTR GetWindowsDir(LPSTR
szBuf
, INT
cbBuf
);
GetWindowsDir
 determines the name and path of the Windows directory.
Arguments
szBuff
Specifies the buffer you are providing for the storage of the typeface name.
cbBuff
Specifies the size of the buffer you are providing.
Return Value
The return value is the path name terminated with a backslash; for example, "C:\WINDOWS\".


GetWindowsMajorVersion
int GetWindowsMajorVersion(void):
GetWindowsMajorVersion
 determines the major version number for the currently installed Windows software.
Return Value
The return value is the Windows major version number.


GetWindowsMinorVersion
int GetWindowsMinorVersion(void);
GetWindowsMinorVersion
 determines the minor version number for the currently installed Windows software.
Return Value
The return value is the Windows minor version number.


GetWindowsMode
int GetWindowsMode(void);
GetWindowsMode
 determines the current mode of Windows.
Return Value
The return value is zero for Real mode, one for Standard mode, or two for Enhanced mode.


GetWindowsSysDir
LPSTR GetWindowsSysDir(LPSTR
szBuf
, INT
cbBuf
);
GetWindowsSysDir
 determines the name and path of the Windows system directory.
Arguments
szBuff
Specifies the buffer you are providing for the storage of the typeface name.
cbBuff
Specifies the size of the buffer you are providing.
Return Value
The return value is the path which ends with a backslash.


GetYearFromDate
int GetYearFromDate(LPSTR
szDate
);
GetYearFromDate
 retrieves the year field from the return value for
GetDateOfFile
.
Argument
szDate
Specifies the date in YYYY-MM-DD-HH-MM-SS format. This value is obtained from
GetDateOfFile
.
Return Value
The return value is an integer with a valid range from 1980 through 2099.


HandleSharedFile
LPSTR HandleSharedFile(LPSTR
szInfSection
, LPSTR
szInfKey
, LPSTR
szSubDir
, LPSTR
szRegDbKey
,
 LPSTR
szWinIniSect
,
 LPSTR
szWinIniKey
, int
iWinIniField
, LPSTR
szBuf
, int
cbBuf
);
HandleSharedFile
 checks a shared file already exists, based on
szWinIniKey
. If the file does not exist, it is added to WIN.INI.
Arguments
szInfSection
Specifies the .INF Section that contains the shared application description line.
szInfKey
Specifies the .INF reference key for the shared application description line.
szSubDir
Specifies the shared application WIN.INI key (such as PROOF, TEXTCONV, or MSDRAW).
szRegDbKey
Specifies the Registration Database key that might contain the full path of an existing copy of the shared application.
szWinIniSect
Specifies the WIN.INI section that might contain the full path of an existing copy of the shared application (such as "MS Proofing Tools").
szWinIniKey
Specifies the WIN.INI key which might reference the full path of an existing copy of the shared application (such as "Spelling 1033,0").
iWinIniField
An index of the path in
szWinIniKey
 (such as "1" for speller, "2" for dictionary).
szBuf
Specifies the destination buffer for the full path of the shared application.
cbBuf
The size of
szBuf
.


Has87MathChip
BOOL Has87MathChip(void);
Has87MathChip
 checks for an 87 math coprocessor on the user's system.
Return Value
If an 87 math coprocessor exists, the return value is one. Otherwise, the return value is zero.


HasMonochromeDisplay
BOOL HasMonochromeDisplay(void);
HasMonochromeDisplay
 checks for a monochrome display on the user's system.
Return Value
If the monochrome display exists, the return value is one. Otherwise, the return value is zero.


HasMouseInstalled
BOOL HasMouseInstalled(void);
HasMouseInstalled
 determines if a mouse is installed on the user's system.
Return Value
If a mouse exists, the return value is one. Otherwise, the return value is zero.


HinstFrame
handle HinstFrame(void);
HinstFrame
 retrieves the instance handle for the Setup program.
Return Value
The return value is the instance handle.


HwndFrame
int HwndFrame(void);
HwndFrame
 provides the handle for the Setup application frame window (the main window).
Return Value
The return value is the handle of the frame window (the main window).
Comments
Use the return value from this function for the
hwnd
 argument in procedures that require it.


InitSetupToolkit
int InitSetupToolkit(LPSTR
szCmdLine
);
InitSetupToolkit
creates the Setup Toolkit window.
Argument
szCmdLine
Specifies the command line passed in to Setup, which must be called at the beginning of every Setup application.


InStr
int InStr(INT
cch
, LPSTR
sz1
, LPSTR
sz2
);
InStr
 determines if
sz2
 is contained in
sz1
, starting at the character
cch
.
cch
Position to compare from, must be 1 or greater.
sz1
Source string.
sz2
String to search for in
sz1
.


IsDirWritable
int IsDirWritable(LPSTR
szDir
);
IsDirWritable
 determines if the specified directory is writable (so that Setup can create a file in it).
Argument
szDir
Specifies the name of the directory.
Return Value
If the directory is writable, the return value is one. Otherwise, the return value is zero.


IsDriveLocalHard
BOOL IsDriveLocalHard(LPSTR
szDrive
);
IsDriveLocalHard
 determines whether the specified disk drive is a local hard disk.
Argument
szDrive
Specifies a string identifying the disk drive letter (A through Z).
Return Value
If the disk drive is a local hard disk, the return value is one. Otherwise, the return value is zero.


IsDriveNetwork
BOOL IsDriveNetwork(LPSTR
szDrive
);
IsDriveNetwork
 determines if the specified disk drive is a network drive.
Argument
szDrive
Specifies a string identifying the disk drive letter (A through Z).
Return Value
If the disk drive is a network drive, the return value is one. Otherwise, the return value is zero.


IsDriveRemovable
BOOL IsDriveRemovable(LPSTR
szDrive
);
IsDriveRemovable
 determines if the specified disk drive is a removable disk drive.
Argument
szDrive
Specifies a string identifying the disk drive letter (A through Z).
Return Value
If the disk drive is removable, the return value is one. Otherwise, the return value is zero.


IsDriverInConfig
BOOL IsDriverInConfig(LPSTR
szDrv
);
IsDriverInConfig
 determines if the specified device driver is in the CONFIG.SYS file.
Argument
szDrv
Specifies the name of the device driver you want to find.
Return Value
If the device driver statement is found, the return value is one. Otherwise, the return value is zero.


IsDriveValid
BOOL IsDriveValid(LPSTR
szDrive
);
IsDriveValid
 determines if the specified disk drive exists.
Argument
szDrive
Specifies a string identifying the disk drive letter (A through Z).
Return Value
If the specified disk drive is valid, the return value is one. Otherwise, the return value is zero.


IsFileWritable
bool IsFileWritable(LPSTR
szFile
);
IsFileWritable
 determines whether the specified file is writable.
Argument
szFile
Specifies the full path and name of the file you want to write to.
Return Value
If the file is writable, the return value is one. Otherwise, the return value is zero.


IsWindowsShared
bool IsWindowsShared(void);
IsWindowsShared
 determines if Windows is shared by comparing the Windows and system directories.
Return Value
If Windows is shared, the return value is one. Otherwise, the return value is zero.


MakeListFromSectionDate
VOID MakeListFromSectionDate(LPSTR
szSym
, LPSTR
szSect
);
MakeListFromSectionDate
 creates a string with all of the dates from the specified .INF section.
Arguments
szSym
Specifies the buffer to receive the list of dates.
szSect
Specifies the section name.


MakeListFromSectionFilename
VOID MakeListFromSectionFilename(LPSTR
szSym
, LPSTR
szSect
);
MakeListFromSectionFilename
 creates a string with all of the filenames from the specified .INF section.
Arguments
szSym
Specifies the buffer to receive the list of filenames.
szSect
Specifies the section name.


MakeListFromSectionKeys
VOID MakeListFromSectionKeys(LPSTR
szSymbol
, LPSTR
szSect
);
MakeListFromSectionKeys
 creates a list of the reference key values found in a section of the currently open .INF file and associates the list with the specified symbol name.
Arguments
szSymbol
Specifies the symbol name of the list in the Symbol Table.
szSect
Specifies the name for the section in the .INF file that contains the reference key values.
Comments
Use this function to create a list that can be used in dialog list boxes.


MakeListFromSectionSize
VOID MakeListFromSectionSize(LPSTR
szSym
, LPSTR
szSect
);
MakeListFromSectionSize
 creates a string with all of the sizes from the specified .INF section.
Arguments
szSym
Specifies the buffer to receive the list of sizes.
szSect
Specifies the section name.


MakeListFromSectionVersion
VOID MakeListFromSectionVersion(LPSTR
szSym
, LPSTR
szSect
);
MakeListFromSectionVersion
 creates a string with all of the version numbers from the specified .INF section.
Arguments
szSym
Specifies the buffer to receive the list of versions.
szSect
Specifies the section name.


OpenLogFile
VOID OpenLogFile(LPSTR
szFile
, INT
fAppend
);
OpenLogFile
 opens a log file that the Setup program or your script can use for writing status information.
Argument
szFile
Specifies the path and name of the log file. If this file does not exist, it is created.
fAppend
Specifies whether to add information to the log file or overwrite the existing contents of the file. Specify one to add information and zero to overwrite information.


PrependToPath
VOID PrependToPath(LPSTR
szSrc
, LPSTR
szDst
, LPSTR
szDir
, INT
cmo
);
PrependToPath
 modifies the specified AUTOEXEC.BAT to add a specified directory to the head of the PATH environment variable.
Arguments
szSrc
Specifies the full path to file to modify.  If NULL or empty (" "), just create a new, one line
szDst
 file.
szDst
Specifies the valid full path for the resulting modified file.
szDir
Specifies the valid path to add.
cmo
Specifies the command option flag.  You can use : cmoOverwrite, which overwrites any existing
szDst
 file, or cmoVital, which calls the Vital command handler if an error occurs.
Comments
The directory is added to the head of the first PATH statement of the file and to every following PATH statement that doesn't contain a %PATH% reference.
PrependToPath
 does not check for resulting file line length or duplicate directory nodes in the path and dynamically allocates a buffer for the whole file.
Returns
Returns
fTrue
 if the function is successful and
fFalse
 if an error occurs.


ReadInfFile
VOID ReadInfFile(LPSTR
szFile
);
ReadInfFile
 opens and reads the contents of the specified .INF file.
Arguments
szFile
Specifies the path and name of the .INF file.
Comments
The Setup program should call
ReadInfFile
 to read an .INF file before attempting to call any of the procedures that access .INF file information.


RemoveDir
VOID RemoveDir(LPSTR
szDir
, INT
cmo
);
RemoveDir
 deletes the specified directory.
Arguments
szDir
Specifies the path and the name of the directory to be deleted.
cmo
Specifies the command option flag. You can use either
cmoVital
 or
cmoNone
 for the command option flag.


RemoveEnvVariable
BOOL RemoveEnvVariable(LPSTR
szName
,
 LPSTR
szValue
);
RemoveEnvVariable
 removes the specified value from the specified environment variable. Under Windows NT, the environment variables affected are the ones specified in the registry. Under Windows 95, autoexec.bat is modified to remove the values.
Arguments
szName
Specifies the name of the environment variable.
szValue
Specifies the value that you want to remove from the environment variable.
Return Value
If the function succeeds, it returns
fTrue
.
If the function fails, it returns
fFalse
.
See Also
SetEnvVariable


RemoveFile
VOID RemoveFile(LPSTR
szFullPathSrc
, INT
cmo
);
RemoveFile
 deletes the specified file.
Arguments
szFullPathSrc
Specifies the full path of the file you want to delete.
cmo
Specifies the command option flag. You can use
cmoVital, cmoForce,
or
cmoNone
.


RemoveIniKey
VOID RemoveIniKey(LPSTR
szFile
, LPSTR
szSect
, LPSTR
szKey
, INT
cmo
);
RemoveIniKey
 deletes a symbol from the specified .INI file.
Arguments
szFile
Specifies the name of the .INI file. If the .INI file is WIN.INI, you do not have to provide the full path.
szSect
Specifies the name of the section where the symbol to be deleted exists.
 szSect$
 must be a non-empty string.
szKey
Specifies the name of the symbol you want to delete.
cmo
Specifies the command option flag. You can use
cmoVital
 or
cmoNone
.


RemoveIniSection
VOID RemoveIniSection(LPSTR
szFile
, LPSTR
szSect
, INT
cmo
);
RemoveIniSection
 deletes the specified section from the designated .INI file.
Arguments
szFile
Specifies the name of the .INI file. If the .INI file is WIN.INI, you do not have to provide the full path.
szSect
Specifies the name of the section you want to delete.
 szSect$
 must be a non-empty string.
cmo
Specifies the command option flag. You can use
cmoVital
 or
cmoNone.


RemoveSymbol
VOID RemoveSymbol(LPSTR
szSym
);
RemoveSymbol
 deletes a symbol from the Symbol Table.
Argument
szSym
Specifies the name of the symbol in the Symbol Table.
Comments
Use
RemoveSymbol
 to free up space occupied by unused symbols and their associated values in the Symbol Table.


RenameFile
VOID RenameFile(LPSTR
szFullPath
, LPSTR
szBackup
);
The
RenameFile
 renames the specified file.
Arguments
szFullPath
Specifies the full path and name of the file you want to rename.
szBackup
Specifies the new name for the file.
Comments
The renamed file is placed in the same directory as the original file (as specified by
szFullPath
).
RenameFile
 is the same as
BackupFile
.


ReplaceListItem
VOID ReplaceListItem(LPSTR
szSymbol
, INT
n
, LPSTR
szItem
);
ReplaceListItem
 replaces an item in the list associated with the specified symbol.
Arguments
szSymbol
Specifies the name of the symbol whose associated value is the list.
n
Specifies the index (one-based) of the item to be replaced.
szItem
Specifies the new item.


RestartListEmpty
bool RestartListEmpty(void);
RestartListEmpty
 determines if any files have been added to _MSSETUP.BAT that need to be copied or deleted by
ExitExecRestart
 when Windows is restarted.
Return Value
If the restart list is empty, the return value is one. Otherwise, the return value is zero.
Comments
Setup adds files to _MSSETUP.BAT as a result of reading the .INF file and finding files identified as a system resource (that is, the file description contains a SYSTEM flag). If the file is newer than the file on the user's system, Setup adds its name to _MSSETUP.BAT.


RestoreCursor
VOID RestoreCursor(int
hPrev
);
The
RestoreCursor
 restores the previous cursor state.
Argument
hPrev
Specifies the identification number of the previous cursor state. Use the return value from
ShowWaitCursor
 for this parameter.


RightTrim
VOID RightTrim(LPSTR
sz
);
RightTrim
 removes any trailing spaces from a string.
Argument
sz
Specifies the string to be trimmed.


SearchForLocationForSharedFile
LPSTR SearchForLocationForSharedFile (LPSTR
szRegDbKey
,
LPSTR
szWinIniSect
,
LPSTR
szWinIniKey
,
LPSTR
iWinIniField
,
LPSTR
szDefault
,
LPSTR
szVersion
,
LPSTR
 szBuf
,
int
 cbBuf
);
SearchForLocationForSharedFile
 uses information from the Registration Database and WIN.INI to determine where the specified shared file should be installed and whether the file will actually be copied.
Arguments
szRegDbKey
Specifies the Registration Database key that might have an associated value that is the path of an existing copy of the file. You can tell the function to ignore the Registration Database in its search by specifying an empty string for this argument.
szWinIniSect
Specifies the section in the WIN.INI file that might have an entry that is the path of an existing copy of the file. You can tell the function to ignore WIN.INI in its search by specifying an empty string for this argument.
szWinIniKey
Specifies the key for the WIN.INI file that will contain a path to an existing copy of this shared file.
iWinIniField
Specifies the index (one-based) of the field in the WIN.INI line entry that contains a path to an existing copy of this shared file.
szDefault
Specifies the default path of the file if no existing copy can be found.
szVersion
Specifies the version for the new copy of the file as a string of 1 to 4 integers separated by periods; for example, 3.1.0.16.
szBuf
Specifies the source buffer.
cbBuf
Size of the source buffer.
Return Value
The return value is the full path for installing the shared file. This function also sets the global variable
SharedFileNeedsCopying
 to one (if the file should be copied) or zero (if the file shouldn't be copied).
Comments
To determine a location for the shared file, the function first uses the Registration Database path. If this file doesn't exist, the function will retrieve only the filename from the Registration Database and perform a
FileOpen
 function to try to determine the path. If either of these methods works and the file found is writable or newer, the function returns that path. If these methods fail, the function uses the path from the WIN.INI field. If that file doesn't exist in the WIN.INI field, the function uses the path from WIN.INI and searches by using a
FileOpen
 function. If these two methods don't succeed,
szDefault
 is used.
After determining where the file should be installed, the function then determines if the file will be copied later when
CopyFilesInCopyList
 is called.
SearchForLocationForSharedFile
 then sets the value of the global variable
SharedFileNeedsCopying
 accordingly.


SetAbout
VOID SetAbout(LPSTR
szAbout1
, LPSTR
szAbout2
);
SetAbout
 adds the specified strings to Setup's About dialog box.
Arguments
szAbout1
Specifies the first string you want to add to the dialog box, typically the product name.
szAbout2
Specifies the second string you want to add to the dialog box, typically the product version, the date, or the copyright notice.


SetBeepingMode
int SetBeepingMode(int
mode
);
SetBeepingMode
 allows the Setup script to specify whether error messages, requests for diskettes, and similar messages will be accompanied by a beep.
Argument
mode
Specifies the beeping mode value. If
mode
 is one, beeping mode is on and the message will generate beeps. If
mode
 is zero, beeping mode is off.
Return Value
The return value is the value of the previous beeping mode.


SetBitmap
VOID SetBitmap(LPSTR
szDll
, int
Bitmap
);
SetBitmap
 defines the logo bitmap used in the background of the frame (or main) window.
Arguments
szDll
Specifies the name of the .DLL file that contains the bitmap resource.
Bitmap
Specifies the identification number of the bitmap resource.
Comments
It is best to use a plain white bitmap.
SetBitmap
 automatically adds a shadow down the right side to give the impression that the bitmap is above the plane of the background.


SetCopyGaugePosition
VOID SetCopyGaugePosition(int
x
, int
y
);
SetCopyGaugePosition
 specifies the display position of the Copy Gauge dialog box during subsequent
CopyFilesInCopyList
 calls.
Arguments
x
Specifies the
x
 coordinate in dialog units relative to the upper-left corner of the client window frame. A value of 1 precisely centers the dialog box horizontally.
y
Specifies the
y
 coordinate in dialog units relative to the upper-left corner of the client window frame. A value of 1 centers the dialog box vertically one-third of the distance from the top margin.
Comments
By default, the Copy Gauge dialog box is centered over the client window frame. However, the default position can interfere with the display of billboard dialog boxes, depending on how the user has resized the window, the size of the monitor, and so on. Use
SetCopyGaugePosition
 to control the position of the Copy Gauge dialog box.


SetCopyMode
int SetCopyMode(int
fMode
);
SetCopyMode
 specifies whether the files from the copy list will actually be copied.
Argument
fMode
Specifies whether copy mode is on (one) or off (zero). If the copy mode is off, the files will not be copied when the script calls
CopyFilesInCopyList
.
Return Value
The return value is the prior value for the copy mode.
Comments
Use this function to streamline testing of your Setup program.


SetEnvVariable
BOOL SetEnvVariable(LPSTR
szName
,
 LPSTR
szValue
,
 CMO
cmo
);
SetEnvVariable
 sets the specified environment variable to a certain value. The environment variable can also be elongated by specifying the command option flag
fAppend
 or
fPrepend
. Under Windows NT, the environment variables affected are the ones specified in the registry. Under Windows 95, autoexec.bat is modified to set the values.
Arguments
szName
Specifies the name of the environment variable.
szValue
Specifies the new value that you want to associate with the environment variable.
cmo
Specifies the command option flag. You can use
fOverwrite
,
fAppend
, or
fPrepend
.
Return Value
If the function succeeds, it returns
fTrue
.
If the function fails, it returns
fFalse
.
See Also
RemoveEnvVariable


SetDecompMode
int SetDecompMode(int
fMode
);
SetDecompMode
 specifies whether compressed files will be decompressed when they are copied.
Argument
fMode
Specifies whether decompression is on (one) or off (zero). When decompression is off,
CopyFilesInCopyList
 copies compressed files byte for byte without decompressing them.
Return Value
The return value is the prior value for decompression.
Comments
You can use
SetDecompMode
 to install compressed files on a network drive.


SetRegKeyValue
void SetRegKeyValue(LPSTR
szKey
, LPSTR
szValue
);
SetRegKeyValue
 replaces the value associated with the specified Registration Database key with the specified value.
Arguments
szKey
Specifies the name of the key. All keys are assumed to be subkeys of HKEY_CLASSES_ROOT; therefore, you only have to specify the name of the key.
szValue
Specifies the new value you want to associate with the key.


SetRestartDir
VOID SetRestartDir(LPSTR
szDir
);
SetRestartDir
 establishes the restart directory where _MSSETUP.EXE and _MSSETUP.BAT (used to restart the system) will be located.
Argument
szDir
Specifies the name of the directory. If
szDir
 does not exist, it is created.


SetSilentMode
int SetSilentMode(INT
mode
);
SetSilentMode
 allows the Setup script to determine whether or not the copy gauge, error messages, billboards, and so on will be displayed.
Argument
mode
Specifies the silent mode value. If
mode
 is one, silent mode is on and the Setup procedures cannot display message-related dialog boxes. If
mode
 is zero, silent mode is off.
Return Value
The return value is the value of the previous silent mode.


SetSymbolValue
VOID SetSymbolValue(LPSTR
szSymbol
, LPSTR
szValue
);
SetSymbolValue
 associates a value with a symbol in the Symbol Table.
Arguments
szSymbol
Specifies the name of the symbol in the Symbol Table.
szValue
Specifies the value you want to associate with the symbol.
Comments
Use
SetSymbolValue
 to store information that can be shared among .DLLs and the Symbol Table.


SetTitle
VOID SetTitle(LPSTR
sz
);
SetTitle
 defines the title used in the frame (or main) window.
Argument
sz
Defines the title used in the frame window.


ShowProgmanGroup
VOID ShowProgmanGroup(LPSTR
szGroup
, INT
Cmd
, INT
cmo
);
ShowProgmanGroup
 minimizes, maximizes, or restores the window of the specified Program Manager group.
Arguments
szGroup
Specifies the name of the Program Manager group.
Cmd
Specifies the operation you want to perform on the group window. To activate and display the group window, use one; to activate and display the group window icon, use two; and to activate and display the group window maximized, use three.
cmo
Specifies the command option flag. You can use
cmoVital
 or
cmoNone
.
Comments
Creating a new item in a Program Manager group causes the Program Manager to become active and its window to come to the front. You can use
ShowProgmanGroup
 to determine what state the group window will be in when it comes to the front.


ShowWaitCursor
int ShowWaitCursor(void);
ShowWaitCursor
 loads and displays the wait cursor.
Return Value
The return value is the previous cursor state.
Comments
Use the return value of this function for the
hPrev
 parameter in
RestoreCursor
.


StampResource
VOID StampResource(LPSTR
szSect
, LPSTR
szKey
, LPSTR
szDst
, int
wResType
, int
wResId
, LPSTR
szData
, int
cbData
);
StampResource
 modifies the first
cbData
bytes of a file resource with the specified data.
Arguments
szSect
Specifies the section of the .INF file that contains the description line of the file to be modified.
szKey
Specifies the reference key to the description line of the file to be modified.
szDst
Specifies the destination directory where the file to be modified resides.
wResType
Specifies the resource identification type.
wResId
Specifies the resource identification number.
szData
Defines the data that will be used to modify the resource.
cbData
Specifies how many bytes of data will be replaced with
szData.


SzCatStr
LPSTR SzCatStr(LPSTR
sz1
, LPSTR
sz2
);
SzCatStr
 appends sz2 to sz1 and returns the concatenated string.
Argument
sz1
Specifies the string to which sz2 is added.
sz2
Specifies the string to append to
sz1
.
Return Value
SzCatStr
 returns the concatenated string.


SzCat2Str
LPSTR SzCat2Str(LPSTR
sz1
, LPSTR
sz2
, LPSTR
sz3
);
SzCat2Str
 appends
sz2
 and
sz3
 to
sz1
 so that
sz1
 becomes
sz1
+
sz2
+
sz3
.
Arguments
sz1
Specifies the original string to which the others are appended.
sz2
Specifies the first string to be appended to
sz1
.
sz3
Specifies the string to be appended to
sz1
+
sz2
.
Return Value
SzCat2Str
 returns the concatenated string
sz1
+
sz2
+
sz3
.


SzCat3Str
LPSTR SzCat3Str(LPSTR
sz1
, LPSTR
sz2
, LPSTR
sz3
, LPSTR
sz4
);
SzCat3Str
 appends
sz2
,
sz3
, and
sz4
 to
sz1
 so that
sz1
 becomes
sz1
+
sz2
+
sz3+sz4
.
Arguments
sz1
Specifies the original string to which the others are appended.
sz2
Specifies the first string to be appended to
sz1
.
sz3
Specifies the string to be appended to
sz1
+
sz2
.
sz4
Specifies the string to be appended to
sz1
+
sz2+sz3
.
Return Value
SzCat2Str
 returns the concatenated string
sz1
+
sz2
+
sz3+sz4
.


UIPop
void UIPop(int
n
);
UIPop
 destroys dialog boxes and removes them from the top of the dialog stack in memory.
Argument
n
Identifies the number of dialog boxes you want to destroy and remove from the dialog stack.
Comments
If
n
 is greater than the number of dialog boxes in the dialog stack, the subroutine will destroy all the dialog boxes in the dialog stack.


UIPopAll
VOID UIPopAll(void);
UIPopAll
 destroys all dialog boxes and removes them from the dialog box stack in memory.


UIStartDlg
LPSTR UIStartDlg(LPSTR
szDll
, int
Dlg
, LPSTR
szDlgProc
, int
HelpDlg
, LPSTR
szHelpProc
, LPSTR
szBuf
, int
cbBuf
);
UIStartDlg
 launches a dialog box and adds it to the top of the dialog stack in memory.
Arguments
szDll
Specifies the name of the .DLL file that contains the dialog box template resources and procedures.
Dlg
Specifies the identification number of the dialog box template resource in the .DLL file.
szDlgProc
Specifies the name of the dialog box procedure exported in the .DLL file.
HelpDlg
Specifies the identification number of the associated help dialog box template resource in the .DLL file.
szHelpProc
Specifies the name of the associated help dialog box procedure exported in the .DLL file.
szBuf
Points to the destination buffer that will receive the string.
cbBuf
Length, in bytes, of the destination buffer.
Return Value
UIStartDlg
 returns a string that is the value associated with the DLGEVENT symbol at the time the dialog ends
.
Comments
If the dialog box is modeless,
UIStartDlg
 returns immediately; if the dialog box is modal, it returns after a user action.


WriteToLogFile
VOID WriteToLogFile(LPSTR
szStr
);
WriteToLogFile
 writes the specified string to the log file.
Argument
szStr
Defines the information you want to write to the log file. The string is written and terminated with a new-line character.
Comments
If the log file is not open,
WriteToLogFile
 does nothing.


INF File Format
This appendix provides information about the format of the .INF file. You do not need to create the .INF file yourself; the Disk Layout Tools will do it for you. Refer to the information below when you are using the Disk Layout Tools to define the properties of installable files.
The Setup toolkit contains a single sample .INF file: SAMPLE.INF. Look at this file as an example of a typical .INF file.
An .INF file will have at least three sections:
·
Source Media Descriptions, which describes each of the disks in the installation set
·
Files, which lists each of the files that will be installed by Setup
·
Default File Settings, which describes the defaults Setup uses to install a file
The Files section can be split into as many sections as you want; you specify these section names using the Disk Layout Tools. You can also specify one or more sections for files that you want to remove during the installation. Throughout the .INF file, you will see lines that begin with a semicolon at the left margin. These are comment lines.


Source Media Descriptions
This section of the .INF file contains one line for each of the disks you use to install your product. Source Media Description lines must be indented and contain four quoted strings, separated by commas:
·
The disk identification number, which is a unique integer between 1 and 999
·
The disk label, which you create using the Disk Layout Tools
·
The tag filename, which is the name of a file that resides on the diskette
·
The relative path for SETUP.EXE. This fourth string exists only if the installable files reside on a network disk drive
The following is the Source Media Descriptions line for the first installation disk. Its tag file is SETUP.EXE:
"1","My Disk Label 1","SETUP.EXE,""


Files
Each line in this section of the .INF file has one of two formats:
1.
The first format begins at the left margin with the identification number for the disk on which the file resides, followed by the filename and a list of nineteen file properties, separated by commas (see the table below). These entries are not enclosed in quotation marks. The following line, from SAMPLE1.INF, is a typical example of this format:
1, bldcui\dialogs.res,,,,1992-01 30,,,,,,,ROOT,,,
13839,,6,,,
2.
The second format begins at the left margin with a reference key enclosed in quotation marks, followed by an equal sign and an unquoted disk identification number. (A disk with that identification number must have a description line in the Source Media Descriptions section.) The reference key and disk identification number are followed by the filename and the list of file properties. The following line, from SAMPLE3.INF, describes a shared file with the reference key CustDict (for customer dictionary) :
"CustDict" = 1, custom.dic, ,,,1992-01-13,,,
OLDER,,,,,, SHARED, 69632, ,,, 0.2.0.2,
The following table lists the file properties that can be included in a file description line:
File Properties
Property
Possible values
Meaning
Append
<empty>
valid filename
Don't append to an existing file, overwrite it instead.
Append to the specified file.
Note
: You cannot append the installable file to an existing file if you have specified Rename, Root, or Backup.
Backup
<empty>
*
valid filename
Use the default setting.
Back up the file to the same filename with a .BAK extension.
The filename you want to use for the backup copy.
Copy
COPY
!COPY
Copy the file onto the user's hard disk or network server.
Don't copy the file.
Date
<empty>
YYYY-MM-DD
Use the default setting.
Specify a date with a range from 1980-01-01 through 2099-12-31.
Decompress
<empty>
DECOMPRESS
!DECOMPRESS
Use the default setting.
Decompress the file.
Don't decompress the file.
Destination
<empty>
full path of a valid directory
Use the destination directory specified in the script (for example, in the AddSectionFilesToCopyList subroutine).
Override the specified destination directory with this one.
Overwrite
<empty>
ALWAYS
NEVER
OLDER UNPROTECTED
Use the default setting.
For information about these values, see Using the Disk Layout Utilities.
ReadOnly
<empty>
READONLY
!READONLY
Use the default setting.
Set read-only attributes on the file after it has been installed.
Don't set read-only attributes.
Remove
<empty>
REMOVE
!REMOVE
Copy the file using other properties.
Remove the file from the user's hard disk or network server.
Copy the file using other properties.
Rename
<empty>
valid filename
Use the source filename when the file is copied.
Use the specified filename when the file is copied.
Note
: You cannot specify a filename for this property if you have also specified Root or Append.
Root
<empty>
ROOT
!ROOT
Use the default setting.
Strip any subdirectories from the filename when the file is copied.
Don't strip subdirectories from the filename when the file is copied.
Note
:
 You cannot specify Root or Append if you have specified that the file be renamed when it is copied.
SetTimeStamp
<empty>
SETTIME
!SETTIME
Use the default setting.
Use the DATE property.
Use the current system time.
Shared
SHARED
<empty> or !SHARED
Treat the file as if it is a shared file that is, an existing version of it may be in use during installation.
Do not treat the file as if it is a shared file.
Size
integer
Size of the file in bytes (uncompressed).
System
SYSTEM
<empty> or !SYSTEM
This is a system file; therefore, it will be replaced during system restart.
Treat the file as if it is not a system file.
TimeToCopy
<empty>
integer
Use the default setting.
Increment the progress indicator by integers. This is an arbitrary number of time units relative to the other file description lines.
Reserved
<empty>
This is a reserved field and must be empty.
Version
<empty>
1 to 4 integers separated by periods
There is no version resource in source file.
The version of the file. For information about this format, see the Microsoft Windows SDK documentation.
Vital
<empty>
VITAL
!VITAL
Use the default setting.
The installation will fail if this file cannot be successfully installed.
The installation will not fail if this file cannot be successfully installed.


Default File Settings
This section contains default values that Setup uses if a file description line in the .INF file has no entry for the field. These lines always begin at the left margin with a quoted symbol name, followed by an equal sign and another quoted string that is the value associated with the symbol. The value is required but may be an empty string.
The following line is an example of a default setting from SAMPLE1.INF:
"STF_COPY" = "YES"
The following table lists the default settings.
Default File Settings
Attribute/Symbol
Possible values or format
Default
STF_BACKUP
"*" = create a .BAK file or
 " " = don't create one
" "
STF_COPY
"YES" = copy or
 " " = don't copy
"YES"
STF_DECOMPRESS
"YES" = decompress or
" " = don't decompress
" "
STF_OVERWRITE
"ALWAYS" = always overwrite an existing version of the file, "NEVER" = never overwrite an existing version of the file, "OLDER" = overwrite the existing version of the file if it is older, or
"UNPROTECTED" = overwrite the existing version of the file if it is not write-protected
"ALWAYS"
STF_READONLY
"YES" = when the file is copied, set the read-only file attribute or
 " " = do not set the read-only file attribute
" "
STF_ROOT
"YES" = when copying the file, strip any subdirectories from the path of the file in the .INF file description or
" " = use the entire path for the file in the .INF file decription
" "
STF_SETTIME
"YES" = use the contents of the Date file property in the .INF file description to set the creation date of the copied file or
" " = leave the creation date as is (the time at which the file was copied onto the user's hard disk)
"YES"
STF_TIME
non-negative integer = use this number to calculate the display of the copy gauge or
"" = use the value entered for the Size file property in the .INF file decription
value of Size
STF_VITAL
"YES" = this is a vital file that must be successfuly copied to the user's hard disk or the installation will fail; or
" " = the file is not vital to the success of the installation
"YES


Command Option Flags
This appendix provides a list of the command option flags that you can specify as parameters for many of the Setup script procedures. Use the list below to determine which command option flag to use for a function or subroutine. You can use combinations of command option flags with logical operators (such as AND or OR). For more information about Setup procedures and which ones use command option flags, see
Setup Procedures
.
Command Option Flags
Name
Meaning
cmoVital
This function must be successfully completed or the installation will fail and Setup will be terminated.
cmoDecompress
The file should be decompressed as it is copied. If this option is not specified, the file will be copied byte by byte, whether or not it is compressed.
cmoTimeStamp
Set the timestamp on the file after it has been copied.
cmoReadOnly
Set a read-only attribute on the file after it has been copied.
cmoBackup
Back up any existing version of the file (using the same filename with a .BAK extension) before the source file is copied onto the user's hard disk or network server.
cmoForce
Force the removal of a file from the user's hard disk or network server, even if it has a file attribute of read-only.
cmoOverwrite
Overwrite any existing version of the file on the user's hard disk or network server. Or, overwrite the entry in the .INI file.
cmoAppend
Append the file to the existing file on the user's hard disk or network server rather than replacing the existing file. Or, append the value to the existing value in the .INI file.
cmoPrepend
Prepend the value to the existing .INI value rather than replacing the value.
cmoNone
No command option flag is specified.
cmoAll
All command option flags are specified.


Introduction to Microsoft Win32s
Microsoft
®
 Win32s
®
 version 1.25 is an operating system extension that allows Win32
®
 applications for Microsoft
®
 Windows NT
™
 and Microsoft
®
 Windows
®
 95 to run on Microsoft
®
 Windows
®
 version 3.1
x
 and Microsoft
®
 Windows
®
 for Workgroups.
Win32s offers software developers:
·
A 32-bit programming model for Windows 3.1 that shares binary compatibility with Windows NT and Windows 95.
·
Full OLE support, including 16-bit/32-bit interoperability.
·
Performance advantages of 32-bit mode.
·
Win32 semantics for the application programming interface (API).
·
A rich subset of the full Win32 API found on Windows NT and Windows 95.
·
An established market of Windows 3.1
x
 systems and the new Windows NT and Windows 95 market to sell Win32-based applications.
·
The ability to ship a single Win32 product for Windows NT, Windows 95, and Windows 3.1
x.
Win32s consists of a virtual device driver (VxD) and a set of dynamic-link libraries (DLLs) that extend Windows 3.1
x
 to support Win32-based applications. The Win32s files must be shipped with the Win32-based application and installed on the Windows 3.1
x
 system.
The Microsoft Win32 Software Development Kit (SDK) provides the following Win32s components:
·
Win32s binaries and Setup program to install Win32s on a Windows 3.1
x
 system
·
Development files as part of the Win32 SDK to create, debug, test, and ship your Win32-based application and Win32s files.
The Win32 SDK relies on Windows NT
-
 or Windows 95
-
 hosted development tools, such as the compiler and debugger, to build and test your Win32-based application.
Win32s is a licensed technology and a number of compiler vendors provide Win32 development solutions on MS-DOS
®
, Windows 3.1
x
, Windows NT, and Windows 95 platforms.
This section provides Win32s installation instructions using a setup program provided on the Win32 SDK CD-ROM. The rest of this documentation covers issues developers should consider when writing Win32-based applications targeted for both Windows NT and Windows 3.1
x
.


New Features
In Win32s version 1.25, the 128K stack limitation of previous releases of Win32s has been removed. Support has been improved for Stacker
®
 and Novell
®
 Netware
®
.


Win32s System Requirements
To install Win32s and run Win32-based applications, you need:
·
A system running Microsoft Windows for Workgroups or Windows 3.1
x
 in enhanced mode with paging enabled (default installation).
·
A 386, 486 or Pentium
™
 processor (386sx and 486sx processors are supported).
·
6MB memory requirement (4MB for Win32 core and 2MB for OLE).
·
2.2MB of hard disk space for Win32s and another 2MB for OLE (for a total of 4.2MB).


Installing Win32s
The Win32s system files can be installed from the Win32 SDK CD-ROM, from a shared CD-ROM drive over the network, or from a 3.5-inch or 5.25-inch high density floppy disk to which you've copied the system files from the Win32 SDK CD-ROM (there is no guarantee that the 5.25-inch floppy disks will match). In all cases, the same setup program is used to install and enable Win32s on a Windows 3.1
x
 system. Please note that installing Win32s requires write access to the Windows system directory, which may require special permissions on a networked installation.


Making a Floppy-Disk Version of Win32s
The Win32s files are located on the Win32 SDK CD-ROM in the directory \MSTOOLS\WIN32S\DISKS. Making a floppy-disk version of Win32s requires either an MS-DOS or Windows NT system that can access a CD-ROM drive directly or over a network, and two or three floppy disks (two floppies for the Win32 core and three floppies for the Win32 core plus OLE).
1.
Place a blank, formatted disk (3.5-inch) in your floppy drive.
2.
Copy all files in
\MSTOOLS\WIN32S\DISKS\RETAIL\OLE32S\DISK1
 into the root directory of the floppy disk.
If you are installing the Win32s core only, use this path:
\MSTOOLS\WIN32S\DISKS\RETAIL\WIN32S
 (which requires two floppies only).
3.
Place another blank, formatted disk (3.5-inch) in your floppy drive.
4.
Copy all files in
\MSTOOLS\WIN32S\DISKS\RETAIL\OLE32S\DISK2
 into the root directory of the floppy disk.
5.
Place another blank, formatted disk (3.5-inch) in your floppy drive.
6.
Copy all files in
\MSTOOLS\WIN32S\DISKS\RETAIL\OLE32S\DISK3
 into the root directory of the floppy disk.


Installing Win32s from a Floppy Disk
1.
Start your computer, then start Windows (type
win
 at the MS-DOS prompt).
2.
Place the Win32s Setup Disk1 in your floppy drive.
3.
In File Manager, display the files on the floppy, then double-click on SETUP.EXE to run the Setup program.
4.
Follow the setup instructions to complete the installation.


Installing Win32s from CD-ROM or a Network
1.
Start MS-DOS with appropriate software for accessing a local CD-ROM drive or a remote CD-ROM drive over the network.
2.
Start Windows (by typing
win
 at the MS-DOS prompt).
3.
Use File Manager to access the Win32 SDK CD-ROM.
4.
In File Manager, display the files in the
\MSTOOLS\WIN32S\DISKS\OLE32S\DISK1
directory, then double-click SETUP.EXE to run the Setup program.
If you are installing the Win32s core only, use this path:
\MSTOOLS\WIN32S\DISKS\RETAIL\WIN32S
5.
Follow the setup instructions to complete the installation.


Verifying Win32s Installation
In addition to installing the Win32s system components, the Win32s Setup program gives you the option to install the Win32 card game FreeCell, the same program that ships as part of Windows NT. After installing Win32s, you can run FreeCell to verify that Win32s is installed correctly. FreeCell is located in the Program Manager group Win32-based applications, which the Win32s Setup program creates.
A common source of problems with Win32s is a bad display driver. Older versions of the S3 display drivers are incompatible with Win32s, and when a Win32 application (such as FreeCell) is run, errors ranging from display corruption to system hangs are reported. Other video cards that do not use S3 accelerator chips have been reported to have similar problems. To obtain newer drivers, contact your display card manufacturer. Until you get drivers that work you can switch to the VGA or SuperVGA drivers included with Windows.
Note
  If you are installing Win32s on Windows 3.1
x
, you must run either the MS-DOS Share or VSHARE.386 utility before starting Windows. Either add SHARE.EXE to your AUTOEXEC.BAT file or install VSHARE.386 in SYSTEM.INI by adding the line "device=VSHARE.386" to the [386Enh] section. Windows for Workgroups installs VSHARE.386 by default, and does not need SHARE.EXE.


Disabling Win32s
You shouldn't need to disable Win32s. The Win32s DLLs will be loaded only when a Win32-based application is executed. The Win32s VxD is loaded when Windows starts, but has little memory overhead. If you must disable Win32s or wish to reinstall Win32s, take the following actions:
·
Remove the Win32s VxD line from Windows SYSTEM.INI file in the [Enh386] section:
device=<SYSTEM>win32s\w32s.386
·
Modify the following line from the [BOOT] section in the SYSTEM.INI file:
drivers=mmsystem.dll winmm16.dll
to the following (remove WINMM16.DLL, leaving any other DLLs on the line):
drivers=mmsystem.dll
·
Delete the WIN32S.INI, W32SYS.DLL, WIN32S16.DLL, and WINMM16.DLL files from the <SYSTEM> directory and all files in the <SYSTEM>\WIN32S
subdirectory.
<WINDOWS
>
 is the Windows installation directory, such as C:\WINDOWS. <SYSTEM> is the Windows System directory, which may be on a networked drive and not a subdirectory of the <WINDOWS> directory. If you are removing only Win32s from your computer, you do not need to remove the shared files (in <SYSTEM> and <SYSTEM>\WIN32S). Before removing these files from the network share, make sure that all users of Win32s have removed the references to Win32s from the SYSTEM.INI file.
·
Restart Windows.


Technical Overview
This section provides architectural details and high-level functionality information on features supported by Win32s.


Features
The Win32s system extension allows Win32-based applications to make 32-bit calls to Windows 3.1
x
, which is then responsible for all graphics and windowing operations. The Windows API in Windows 3.1
x
 and the Win32 API in Windows NT and Windows 95 have many common features.
The following list highlights Windows 3.1
x
 features available through Win32s:
·
Complete windowing interfaces (User)
·
All graphics functions (GDI)
·
OLE
·
DDE/DDEML (dynamic data exchange and DDE Management Library)
·
TrueType fonts
·
Common dialogs
·
Network support (NetBios and Windows Sockets 1.1
 (*)
 APIs)
·
Multimedia support (sound APIs)
In addition to supporting Windows 3.1
x
 functionality, the following Win32 features are also supported through Win32s on Windows 3.1
x
:
·
Structured exception handling (SEH)
·
Sparse memory (Virtual memory API)
·
Memory-mapped files (backed by disk image)
·
Growable heaps (Heap API)
·
International Support (localized versions of Win32s and Code Page/Unicode
™
 translation APIs)
The following new features have been added in Win32s 1.2:
·
OLE support
·
New National Language Support (NLS) functions
·
Memory-saving compressed code page files
·
Combined libraries that require less memory
Win32s provides a 32-bit Windows Socket translation layer and requires that your system already have 16-bit Windows Sockets 1.1 installed. A number of third-party vendors ship TCP/IP and Windows Sockets products for MS-DOS and Windows. Windows Sockets support for Windows for Workgroups is freely available.
Win32s offers a 32-bit solution for Windows 3.1
x
 supporting binary compatibility with Windows 95 and Windows NT running on 386/486 hardware and source compatibility to RISC platforms such as the MIPS R4x00, DEC
™
 Alpha AXP
™
, and Motorola PowerPC architectures.


Architecture
The following figure illustrates the key pieces of Win32s. The dark gray boxes represent Win32s components; the light gray boxes depict Windows 3.1
x
 components. The 32-bit application dynamically binds to W32SCOMB.DLL, which is the combined Win32s version of the Win32 system DLLs KERNEL32.DLL, GDI32.DLL, USER32.DLL, and others. A large percentage of the API calls are then handled by the general 32/16 thunking DLL, WIN32S16.DLL, which is responsible for repacking the stack, truncating or expanding parameters, mapping message parameters (due to Win16/Win32 differences), etc. The VxD is trusted ring 0 kernel code that handles low-level system services such as exception handling, floating-point trap emulation, and low-level memory management.
Because Windows 3.1
x
 does not recognize and cannot load Win32 executables, Win32s provides Win32 loader code. Loader services are handled by W32SKRNL.DLL.
The W32SCOMB component contains the Windows 3.1
x
 window manager, graphics engine, and kernel services DLLs. Figure 1 shows the general flow of control when a Win32-based application makes a Win32 call. Most calls are passed to Windows 3.1
x
, which actually implements the call.


Coordination Between Windows 3.1
x
 and Win32s
Win32s and Windows 3.1
x
 system-code are tightly coupled. Win32s is a true system extension to the Windows 3.1
x
 operating system code.
The first level of coordination occurs in the Windows 3.1
x
 loader. The Windows 3.1
x
 loader was designed to recognize the presence of a Win32s loader. When Windows 3.1
x
 attempts to load an executable and cannot identify the image header, the Win32s loader (if present) is called to determine whether the image is a Win32 executable, known as "PE," for Portable Executable. If the image is not a PE image, Windows 3.1
x
 reports that file cannot be executed. If the image is a PE image, the Win32s loader loads the image table (fix-up tables, etc.) and then demand-loads the rest of the image as the program executes.
Win32s also hooks the Windows 3.1
x
 resource loader, so that application icons appear correctly in the Program Manager, or other resource-viewing utilities. When Windows 3.1
x
 attempts to read a resource from a PE image (something that it cannot do), Win32s fabricates the resource (such as the icon) as a 16-bit resource. In this way, Win32-based applications can be added to the Program Manager and still have properly displayed icons for selection. This support is transparent to both the programmer and the user.
Win32s uses a similar method to support version resources. Versioning APIs are new to Windows 3.1
x
 and allow version-marked executables to be checked by utilities such as setup tools. Win32s hooks Windows 3.1
x
 so that version calls return valid information when a 16-bit Windows application version-checks a Win32-based application.
Messaging between applications is generally handled in a straightforward manner by the Win32s thunk layer. However, special cooperation between Win32s and Windows 3.1
x
 also allows Windows hook APIs and message subclassing to be supported. A Win32-based application can install a hook to monitor all Windows applications (16- and 32-bit). Win32s ensures that the Win32 hook sees a 32-bit format of all messages regardless of the message source or destination.
Windows 3.1
x
 and Win32s also require cooperative memory management between the Win32s VxD and Win386. Win32s also manages the task of translating pointers passed via the Windows API between the Win32-based application and 16-bit Windows system code.


Handling Messages
Message handling in a Win32-based application is generally identical to message handling in an equivalent 16-bit Windows application. A Win32-based application receives messages in the same order as a Win16 application because Win32s relies on Windows 3.1
x
 to deliver messages. Message order is also the same on Windows NT and Windows 95.


Memory
Windows 3.1
x
 implements a shared memory design, in which all Windows processes reside in one global memory heap. Windows NT, however, isolates processes into their own, private address space. Win32-based applications running on Windows 3.1
x
 coexist in the same shared global memory heap as other Win32- and Win16-based applications.
Win32s supports the following features for Win32 executables or DLLs:
·
Multiple Win32 executables and DLLs can be loaded simultaneously.
·
Multiple Win32 executables can reference the same Win32 DLL.
·
Win32 DLLs referenced by multiple Win32-based applications share a single copy of the DLL code and data (just like 16-bit Windows DLLs).
·
Win32s DLLs and VxD are shared by all Win32-based applications.
·
Win32s supports executing data as code, such as dynamic code generation (
FlushInstructionCache
 should be used where appropriate).
·
Win32-based applications see a flat 32-bit address space (CS, DS, SS, and ES map a single address space).
·
Win32s supports demand-paging of executables for efficient loading of executables, DLLs and data.
·
Win32s allocates a growable stack for each Win32 process. Stack size is specified at link time (linker switch); Win32s will create a stack that is at least 64K.
Because Win32 executables share a global heap and cannot use selectors for dereferencing addresses (as do Win16 applications), multiple instances of Win32 executables do not share code. The loader must fix up all 32-bit linear addresses to code and data when an executable is loaded. Win32-based applications do not move in memory nor are segment registers available to switch context to a second instance while still sharing the same code. Therefore, each instance of a Win32 executable must be loaded into memory and code cannot be shared.
Note
  Win32-based applications should not be designed to assume that all Win32-based applications run in the same address space. Such applications will not run on Windows NT or Windows 95.


Processes and Tasking
Win16- and Win32-based applications coexist seamlessly on the same desktop (display). Win32s assures that Win16-based applications "see" Win32-based applications as other Win16-based applications, and that Win32-based applications see Win16-based applications as other Win32-based applications. A Win32-based application can enumerate windows in the system and will receive 32-bit window handles for both Win32- and Win16-based applications. This means that Win32-based applications can send messages to other windows or can use DDE or OLE to communicate with other processes without regard to the 16- or 32-bit nature of the other application.
The Windows 3.1
x
 non-preemptive, message-driven scheduler is responsible for scheduling both Win16- and Win32-based applications. Win32-based applications operate under the same constraints as Win16-based applications. To keep the user interface responsive, Win32-based applications must check their message queue regularly. On Windows NT, a Win32-based application that does not check its message queue and handle messages in a timely manner only affects its own user interface and the user may switch away and work on other applications. Windows 3.1
x
, however, uses messages to schedule processes. Therefore, applications (16- or 32-bit) must handle messages in a timely manner in order to keep Windows 3.1
x
 responsive.


Win32 Dynamic-Link Libraries
Windows NT and Windows 95 support new features for 32-bit DLLs not available to 16-bit DLLs. Win32s supports Win32 DLL features such as:
·
Win32 DLLs in Windows 3.1
x
 receive the same notifications as on Windows NT and Windows 95 when each process loads or links to the DLL and when each process frees the DLL or terminates. This includes abnormal termination.
·
DLLs are initialized in the same order as on Windows NT. This applies to applications with multiple DLLs.
·
The Win32s loader searches for Win32 DLLs first in the Win32s directory and then uses the same search algorithm as Windows NT.
·
Thread local allocations (
TlsAlloc
) are made system-wide rather than on a per-process basis providing an instance data solution for DLLs on Win32s.
Another instance data solution is to use
_declspec(
thread
)
. While this method may be more convenient, all of the DLLs that contain the instance data must be loaded implicitly during load time. It is still possible to use
LoadLibrary
 to load libraries that don't have static instance data (static data that was declared using
_declspec(
thread
)
). Memory allocation for all of the
_declspec(
thread
)
 variables is a 4KB quantum.


File Input and Output (I/O)
The Win32 API provides all functions for manipulating files such as open, seek, move, and rename. The Win32 API is required since calling MS-DOS functions using Interrupt 21H is not supported. Many applications rely on the C run-time library, which in turn relies on Win32 API functions for file I/O. For this reason, the C run-time library is portable and calls Win32s for file I/O.


Floating-Point Emulation
Win32s provides a floating-point trap emulator to support Win32-based applications with in-line math coprocessor instructions. This support allows these applications to function even if they are run on systems without coprocessor hardware. If a coprocessor is present, the trap emulator is not involved.
The same floating-point emulator is used on both Windows NT and Win32s, ensuring compatible results between a Win32-based application running with Windows 3.1
x
 and with Windows NT.
Win32-based applications can use structured exception handling (SEH) to handle exceptions generated by the coprocessor. SEH allows the Win32-based application to handle the exception itself and continue or allow the system to handle the exception, generally resulting in termination of the application.
Note
  Under Win32s, floating-point exceptions are reported as soon as the exception is detected by the processor. On Windows NT, the exception is reported on the following floating-point instruction.


OLE Support
Win32s 1.2 and later provides full support for Microsoft OLE. 32-bit applications that use OLE run without any changes under Win32s.
The OLE2THK library provides the thunking by which 16-bit OLE applications can interoperate with 32-bit OLE applications under Win32s.
Note
  A 32-bit process cannot call a 16-bit DLL, and vice versa, as mixed-bitness within a process is not supported under Win32 or on Windows 3.1
x
.
Under Win32s, memory that is marshalled between processes must be allocated with
GlobalAlloc
(GMEM_MOVEABLE). Memory allocated as GMEM_FIXED will not be marshalled correctly.
See
Shipping Win32s with Win32 Applications
 for information regarding the OLE files you must ship with your Win32 OLE application for it to run under Win32s.


Printing
Win32 and Win32s support existing printing code. Win32s relies on the existing Windows 3.1
x
 printer drivers for output and does not support loading 32-bit Windows NT printer drivers.
Win32s supports all Windows 3.1
x
 escapes except those marked as obsolete in the Windows 3.1
x
 SDK. Windows NT implements a small set of fundamental escapes for ease in portability, but uses named API functions rather than device-specific escapes to support advanced hard copy output. Therefore, it is critical to query for the support of an escape rather than assume the escape will always be present. If you find that a particular escape is not supported, use an alternate method to accomplish the same task.
Windows 3.1
x
 applications can use printer-specific escapes, if available, and should use general-purpose code for doing the same thing if the escape is not supported. This approach should also work in Windows NT. Or, you can call the new Win32 printing API functions that replace the driver-specific escapes when the application runs with Windows NT.


Win32s Programming Details
This section provides detailed programming information that you should be aware of in using the Win32 API and C run-time library in applications that will run on Windows NT, Windows 95, and Windows 3.1. Programming solutions and recommendations are provided to create portable applications and avoid architecture dependencies.


Preemptive Multitasking
Windows NT and Windows 95 are pre-emptive multitasking operating systems; Windows 3.1 relies on message-driven multitasking. This difference can cause compatibility problems when Win32-based applications are run on the different systems unless properly designed and tested.
Data manipulations in DLLs must be guarded by synchronization objects. Windows 3.1 DLL operations are atomic. For example, when an application receives a message, it will be scheduled to handle that message and be given control of the CPU. The application will own the CPU until it checks its message queue. When the application checks its queue, Windows 3.1 may opt to schedule another application. When an application owns the CPU, no other Windows application is scheduled. Therefore, the application handling a message can call a DLL, update data managed in the DLL, and be assured that no other applications call the DLL at the same time.
This is not true of Win32-based applications running on Windows NT or Windows 95. For example, a Win32-based application may call a DLL which begins to update DLL-managed data; the pre-emptive scheduler may pass control of the processor to another process, which could call the same DLL. If the second process also updates data in the DLL, the data will be corrupted. To protect DLL data, the Win32 API provides a set of synchronization objects. These objects are supported in Win32s. Functions like
EnterCriticalSection
 are implemented as a NOP and return success even though they are unnecessary in Windows 3.1.
By supporting synchronization calls in Win32s, applications can execute a common code path and simplify programming and testing.
Note
  It is critical to test an application in both Windows 3.1 and Windows NT to ensure correct operation.


Message Handling
Win32- and Win16-based applications coexist in the system and can pass messages without knowing whether the other application is a 16- or 32-bit application. Win32s maps messages transparently, offering Win32-based applications and 16-bit Windows messages with Win32 semantics.
For private messages (messages defined by an application, not by the Win32 API), Win32s cannot determine the contents of
 wParam
and
 lParam
 message parameters. Therefore, the following effects will occur when passing private messages between Windows applications:
·
Private message from Win16 to Win32:
wParam
 is 0 extended.
·
Private message from Win32 to Win16: high-order word of
wParam
 is lost.
·
Private message from Win32 to Win32: high-order word of
wParam
 is lost.
·
Private message from Win16 to Win32 or Win32 to Win32:
lParam
 is unaffected.
This behavior has the following impact: Passing a pointer using a private message in
lParam
 is safe between two cooperative Win32-based applications; passing a linear 32-bit pointer in
lParam
 using a private message to a Win16-based application will result in an invalid pointer when the Win16-based application uses it because Win32s cannot translate this pointer. Because Windows 3.1 is used to deliver messages, the high word of
wParam
 is lost even when private messages are being passed only between Win32-based applications. Again, this is a limitation of private messages, not public messages such as
WM_COMMAND
.
Win32s supports message hooks. Since hooks can be used to intercept messages between applications, Win32s assures that hooks installed by Win16-based applications can intercept messages destined for Win32-based applications; and similarly Win32 hooks can intercept messages destined for Win16-based applications. In each case the 16- or 32-bit message hook will intercept messages for Win16- and Win32-based applications, but translated into the appropriate 16- or 32-bit message form.


Dynamic Data Exchange
Win32s supports Dynamic Data Exchange (DDE). However, while it is possible to use DDE on Windows NT or Windows 95 without using the DDE message-packing functions, using DDE under Win32s requires that these functions are used. The message-packing functions are
PackDDElParam
,
UnpackDDElParam
,
ReuseDDElParam
, and
FreeDDElParam
.


Memory Management
Windows 3.1 uses a single address space in which all Windows (16- and 32-bit) applications run. Therefore, DLL data segments are shared among all processes that call the DLL. Windows NT has separate address spaces with 2GB of virtual memory available for each process. The default DLL behavior is to have private DLL data, also known as instance data. Windows NT DLLs can be built to have shared DLL data for compatibility with Windows applications that require this feature.
In order to specify that DLL data should be shared, add the following lines to your Win32 DLL's DEF file:
SECTION
.bss READ-WRITE-SHARED    ; Share uninitialized global variables
.data READ-WRITE-SHARED   ; Share initialized global variables
Note:
  If your port of a 16-bit Windows-based application to Win32 relies on shared DLL data, you should build the DLL indicating shared data. The default linker behavior is to create instance data DLLs resulting in shared DLL data on Windows 3.1 and instance data on Windows NT.
Note:
  The Win32s loader loads the DLL data section as SHARED, regardless of the section attribute.
To facilitate communication and passing of data between Win32-based applications and other Win16-based applications (and Windows 3.1 itself), Win32s supports the various memory allocation functions differently than on Windows NT or Windows 95.
On Windows NT and Windows 95:
·
VirtualAlloc
 supports sparse memory allocation.
·
GlobalAlloc
 maps to
HeapAlloc
 (always commits memory).
·
LocalAlloc
 maps to
HeapAlloc
.
·
HeapAlloc
 implements suballocation from large memory block allocated using
VirtualAlloc
.
·
C run-time
malloc
 maps to
HeapAlloc
.
On Win32s:
·
VirtualAlloc
 supports sparse memory allocation.
·
GlobalAlloc
 relies on Windows 3.1
GlobalAlloc
 and always allocates committed and fixed memory.
·
LocalAlloc
 maps to
HeapAlloc
.
·
HeapAlloc
 implements suballocation from large memory blocks allocated using
VirtualAlloc
.
·
C run-time
malloc
 maps to
HeapAlloc
.
The primary difference is the behavior of
GlobalAlloc
. Win32s relies on Windows 3.1 for global allocation. This allows a 32-bit application to simply pass the handle to global memory to Windows (such as the clipboard) or to another 16-bit application. The memory can then be locked, unlocked, resized or freed; the 16-bit side (system or application) is never aware that the memory was allocated by a 32-bit process. This is not true for the other memory allocation functions. In these cases Win32s has to create and manage handles dynamically using a private handle cache.
The
VirtualAlloc
 and
HeapAlloc
 functions are better memory allocation methods for application-manipulated data. The
GlobalAlloc
 function is more efficient for data that will be passed back and forth between the Win32-based application and system or other applications.
Allocating global memory with the GMEM_FIXED flag locks the pages. In most cases, this is undesirable and affects the overall performance of the system. It is recommended that you allocate memory as moveable and obtain a pointer to the memory using
GlobalLock
.
Thread Local Storage is supported on Win32s even though threads are not. TLS is useful in Win32 DLLs on Win32s to create DLL instance data. By default, all global variables in a DLL on Windows 3.1
x
 are shared by all processes that call the DLL. This can be inconvenient when the DLL must maintain global information that applies only to a particular process calling the DLL. The TLS implementation in Win32s creates a system-wide index such that a unique TLS index is available for each process that links to a DLL.
In the following DLL initialization code fragment, the DLL will allocate a TLS index for each process that attaches to the DLL on Windows NT and Windows 95. On Win32s, a TLS index is only allocated when the first process attaches to the DLL. Each Win32 process can use
dwIndex
 in calls to
TlsSetValue
 and
TlsGetValue
 to store per-process data (such as a pointer to allocated data unique to each process).
Another way to look at TLS support on Win32s is that each process in Windows 3.1 uses the TLS index like a thread does on Windows NT or Windows 95.
The following DLL initialization code fragment illustrates how to initialize TLS in a DLL that will work on Windows NT, Windows 95, and Win32s:
BOOL APIENTRY DllEntryPoint(HINSTANCE hinstDll, DWORD fdwReason,
        LPVOID lpvReserved)
{
    static BOOL fFirstProcess = TRUE;
    DWORD  dwVer = GetVersion();
    BOOL   fWin32s = (dwVer & 0x80000000) &&
                      (LOBYTE(dwVer)<4);
   static DWORD  dwIndex;
    if (dwReason == DLL_PROCESS_ATTACH) {
        if (fFirstProcess || !fWin32s) {
            dwIndex = TlsAlloc();
         }
         fFirstProcess = FALSE;
    }
    .
    .
    .
}
There should be a matching platform test in the DLL
TlsFree
 cleanup code.


C Run-time Support
Win32-based applications that rely on C run-time routines may be linked statically to the application or dynamically to CRTDLL.DLL, a C run-time DLL. CRTDLL.DLL is part of the Win32s system and should be redistributed. Therefore, an application can rely on the existence of the C run-time DLL on Windows NT, Windows 95, and Win32s.
Using CRTDLL.DLL is useful for applications that have an executable and multiple DLLs that all make C run-time calls. The CRTDLL.DLL is also useful for applications that consist of multiple executables that share a single or set of application DLLs which all rely on C run-time calls.
Because of the shared system memory of Windows 3.1, some aspects of CRTDLL.DLL cannot be supported. Multiple applications can link and use CRTDLL.DLL simultaneously, but global variables such as
__argc_dll
 and
__argv_dll
 are not exported by the Win32s version of CRTDLL.DLL. The portable method for determining the command-line parameters would be to call
GetCommandLine
. There are several other similarly affected global variables, such as _
environ
.
The portable method for getting environment variables when using CRTDLL.DLL is by calling Win32 APIs
GetEnvironmentStrings
 or
GetEnvironmentVariable
 instead of _
environ
.
It is not recommended to statically link to a CRT library. Win32s applications should link to CRTDLL.DLL or the CRT library provided by your compiler vendor--for example, MSVCRT20.DLL.
Note that your C compiler vendor may have its own form of C run-time in a redistributable DLL.


File Input and Output
In network environments especially, or on a single system with multiple applications opening a single file, applications should indicate how they would like to share, or not share, files explicitly. The flag semantics for Win32s and Windows NT are the same for
OpenFile
. For
CreateFile
, however, there are differences. If
fdwShareMode
 is a zero, Win32s interprets it as compatibility mode (OF_SHARE_COMPAT), while Windows NT interprets it as deny all (OF_SHARE_DENY_ALL). Under Win32s,
CreateFile
 and
fopen
 do not support OF_SHARE_DENY_ALL. Windows NT does not support compatibility mode (OF_SHARE_COMPAT). For further information, see the
OpenFile
 reference topic.
It is very important to enable file-sharing and locking. When running on Windows 3.1
x
, be sure that SHARE.EXE has been loaded before starting Windows. Windows for Workgroups provides file-sharing and locking support by default, so you should not load SHARE.EXE.


International Support
Win32-based applications that are designed for international markets will find localized versions of Win32s and code page support for manipulating resources.


Localized Versions of Win32s
Since Win32s consists primarily of a mapping layer, it is language independent. Therefore, Win32s can be installed on localized versions of Windows 3.1 or Windows for Workgroups. Win32s does have several low-level error messages that are displayed when memory is low, the Win32s loader encounters a corrupt binary, and so on. These error message strings are isolated to the VxD and one 16-bit DLL, W32S.386 and W32SYS.DLL, respectively. Additionally, system messages are provided by NTMSG.DLL.
To ship a localized version of a Win32-based application with Win32s, you must replace the English versions of W32S.386, W32SYS.DLL, and NTMSG.DLL with the appropriate language version of these files from the \
MSTOOLS\WIN32S\NLS
 directory according to the following table:
w32s.deu, w32sys.deu:    German
w32s.esp, w32sys.esp:    Spanish
w32s.fra, w32sys.fra:    French
w32s.ita, w32sys.ita:    Italian
w32s.sve, w32sys.sve:    Swedish
Localized versions of NTMSG.DLL are generated with
mkntsmg,
which can be found in \MSTOOLS\WIN32S\BIN. The syntax for
mkntsmg
is:
mkntmsg
 [
-v
] [
-h
] [
-o
outfile
]
infile
-v
(Verbose)  Displays the message groups.
-h
Displays the usage message.
-o
outfile
Specifes the output file name.
infile
Should be KERNEL32.DLL taken from a localized version of Windows NT.
This current set of languages matches those supported in the first release of Windows NT. If your application requires additional language support, contact Microsoft Product Support Services, which are most easily reached on CompuServe. For CompuServe information, see the
Win32 SDK Getting Started
 documentation.


Code Page and Unicode Translation Support
Windows 3.1 does not support Unicode, so Win32s 1.25 has been implemented without Unicode support. Win32 application resources, however, such as dialog boxes, menus, and message tables consist of Unicode strings. Win32s translates these resources automatically using the Windows 3.1 code page. However, some applications may wish to control string translation using other code pages.
Win32s version 1.25 supports Code Page/Unicode translation using the following functions:
MultiByteToWideChar
WideCharToMultiByte
IsValidCodePage
GetCPInfo
IsDBCSLeadByte
These functions can be useful when creating dialog boxes dynamically within an application. Dialog box templates require Unicode, not ANSI, character strings.
Win32s 1.25 installs the following OEM and ANSI code pages by default:
CTYPE.NLS
P_850.NLS
LOCALE.NLS
P_852.NLS
L_INTL.NLS
P_855.NLS
P_037.NLS
P_857.NLS
P_10000.NLS
P_860.NLS
P_10001.NLS
P_861.NLS
P_10006.NLS
P_863.NLS
P_10007.NLS
P_865.NLS
P_10029.NLS
P_866.NLS
P_10081.NLS
P_869.NLS
P_1026.NLS
P_875.NLS
P_1250.NLS
P_932.NLS
P_1251.NLS
P_936.NLS
P_1252.NLS
P_949.NLS
P_1253.NLS
P_950.NLS
P_1254.NLS
SORTKEY.NLS
P_437.NLS
SORTTBLS.NLS
P_500.NLS
UNICODE.NLS
P_737.NLS
The table below lists the code pages supported by these .NLS files:
The following table shows various Code Pages and the support associated with each code page. It also lists whether or not a code page is a valid ACP or OEMCP.
CP ID
¾
 the Code Page ID
Name
¾
 the canonical name of the character set
ACP
¾
eligibility for ACP
OEMCP
¾
 eligibility for OEMCP
Code Page Identification Numbers
CP ID
Name
ACP
OEMCP
Windows NT 3.1
Windows 95
Windows NT 3.5
"Cairo"
1200
Unicode (BMP of ISO 10646)
x
x
x
1250
Windows 3.1 Eastern European
x
x
x
x
x
1251
Windows 3.1 Cyrillic
x
x
x
x
x
1252
Windows 3.1 US (ANSI)
x
x
x
x
x
1253
Windows 3.1 Greek
x
x
x
x
x
1254
Windows 3.1Turkish
x
x
x
x
x
1255
Hebrew
x
x
x
x
1256
Arabic
x
x
x
x
1257
Baltic
x
x
x
x
437
MS-DOS United States
x
x
x
x
x
708
Arabic (ASMO 708)
x
x
x
x
709
Arabic (ASMO 449+, BCON V4)
x
x
x
x
710
Arabic (Transparent Arabic)
x
x
x
x
720
Arabic (Transparent ASMO)
x
x
x
x
737
Greek (formerly 437G)
x
x
x
x
x
775
Baltic
x
x
x
x
850
MS-DOS Multilingual (Latin I)
x
x
x
x
x
852
MS-DOS Slavic (Latin II)
x
x
x
x
x
855
IBM Cyrillic
x
x
x
x
x
857
IBM Turkish
x
x
x
x
x
860
MS-DOS Portuguese
x
x
x
x
x
861
MS-DOS Icelandic
x
x
x
x
x
862
Hebrew
x
x
x
x
863
MS-DOS Canadian-French
x
x
x
x
x
864
Arabic
x
x
x
x
865
MS-DOS Nordic
x
x
x
x
x
866
MS-DOS Russian (USSR)
x
x
x
x
x
869
IBM Modern Greek
x
x
x
x
x
874
Thai
x
x
x
x
x
932
Japan
x
x
x
x
x
936
Chinese (PRC, Singapore)
x
x
x
x
x
949
Korean
x
x
x
x
x
950
Chinese (Taiwan, Hong Kong)
x
x
x
x
x
874
Thai
x
x
x
x
1361
Korean (Johab)
10000
Macintosh Roman
x
x
x
x
10001
Macintosh Japanese
x
x
x
10006
Macintosh Greek I
x
x
x
x
10007
Macintosh Cyrillic
x
x
x
x
10029
Macintosh Latin 2
x
x
x
x
10079
Macintosh Icelandic
x
x
x
10081
Macintosh Turkish
x
x
x
x
037
EBCDIC
x
x
x
500
EBCDIC "500V1"
x
x
x
1026
EBCDIC
x
x
x
875
EBCDIC
x
x
x
Win32s 1.25 installs all of these OEM code pages by default.
Note
  Use of code pages other than UNICODE.NLS and P_1252.NLS requires several file handles and 150K
-
 220K of virtual memory. This extra resource will only be consumed when one of the five code page APIs listed above is called.
The code pages installed by default enable multi-locale systems. These code pages are provided in \MSTOOLS\WIN32S.
The OEM code page that is installed should match the code page used by MS-DOS. This has ID 437 in the U.S. and, generally, ID 850 for Western Europe. Win32s 1.2 installs both of these code pages by default. Your Setup program will need to install other OEM code pages to match MS-DOS code pages for other languages.
See
Shipping Win32s with Win32 Applications
 for installation instructions.


Performance Considerations
Calls to the Win32 API are translated before they are passed to Windows. This involves translating pointers and repacking parameters on the stack, among other operations. Therefore, there is an overhead associated with calling the Windows API. For functions that require a large amount of processor time to complete (such as
BitBlt
), the thunking overhead as a percentage of total API execution time is less than one percent. Other functions
¾
for example, functions that simply query status
¾
have a relatively high thunking overhead. Test scenarios that call a broad selection of Win32 functions take approximately ten percent longer due to the thunking layer.
Therefore, an application that calls only Win32 functions will experience a 10 percent degradation. However, real applications have a mix of system calls and time spent in the 32-bit routines of the application, and generally will see a performance increase.
Win32s is a perfect candidate for applications that are data- and memory-intensive or calculation-intensive, such as CAD packages, desktop publishing packages, image manipulation tools, spreadsheet programs, and simulation software. Manipulating data and performing calculations in 32-bit mode improves the performance of these applications significantly. Win32-based applications should see performance improvements despite the slight overhead resulting from 32-bit to 16-bit translation (thunking) that occurs during Windows API calls.
Several Win32-based applications have been used to do performance analysis of Win32s by comparing performance between 16- and 32-bit versions of the same applications. For GDI-intensive operations used in these applications, the performance was found to be roughly the same. For numeric computation and for traversing data, the Win32s versions of the applications were up to 2 times faster.
The overall effect is that most Win32-based applications using Win32s will see a performance gain over their 16-bit Windows counterparts, with the added benefit that these new applications are native 32-bit applications on Windows NT.
Using the following techniques can significantly improve the performance of your Win32-based application on both Windows 3.1 and Windows NT:
·
Use the Working Set Tuner provided with the Win32 SDK.
·
Use the
PolyLine
 function rather than
MoveTo
/
LineTo
 operations.
·
Use
PolyPolygon
 instead of multiple calls to
Polygon
.
·
Use a reference between the Win32-based application and the system to pass local variables (stack variables).
Using
PolyLine
 saves time in Win32s by minimizing the number of thunks that must pass through from the Win32-based application to Windows 3.1
x
 system code. This is beneficial on both Win32s and Windows NT.
Pointer translation from 32 bits to 16 bits can be a time-consuming operation for Win32s. Different types of memory (
GlobalAlloc
,
LocalAlloc
,
VirtualAlloc
, global data, local data) take different amounts of time to translate pointers. In general, pointers to local variables will always be translated fastest since they are on the application's stack, and Win32s has optimized translation of the stack pointer.


Advanced Features
Because the entire Win32 API is exported by Win32s, any Win32-based application can be loaded into Windows 3.1
x
. All functions will be fixed-up correctly by the loader. Applications that call Win32 functions that cannot be implemented in Windows 3.1, such as paths, threads, transformations, or asynchronous file I/O, will find that these functions fail and return errors.
Unsupported APIs return error codes appropriate for the function called. Win32s will set the last-error code to ERROR_CALL_NOT_IMPLEMENTED, which can be retrieved by
GetLastError
. However, Win32-based applications do not need to rely exclusively on error return codes, but can determine which Windows platform they are running on (Windows 3.1 or Windows NT) by calling the
GetVersion
 function. The high-order bit of the
DWORD
 return value is
zero
 when the Win32-based application is running on Windows NT and is
one
 if the application is running on Windows 3.1 or Windows 95.
An application can selectively, and as a run-time feature, implement different functionality when the application is run with Windows 3.1 using Win32s or when it is run with Windows NT. For example, a graphics application could offer Bezier-curve drawing tools when the paint program is run on Windows NT. The same tool could emulate this functionality itself or not offer the feature with Windows 3.1
x
. The application can use the error return from these unsupported Win32 functions in Win32s to determine the proper plan of action.
When running on Windows NT, an application can spawn background threads to complete tasks, something it cannot do when running on Windows 3.1
x
, where it runs only as a single-threaded application. But, consider that all Win32-based applications automatically benefit from the scheduler on Windows NT even if they do not use multiple threads. Win32-based applications execute with an asynchronous messaging model on Windows NT, which allows users to switch away from applications that are tied up in long calculations. Taking advantage of threads on Windows NT is not required, and most applications will rely on the asynchronous messaging model advantage.


Mixing 16-bit and 32-bit Code
Windows NT does not support mixing 16- and 32-bit code. Such support is contrary to the portable design of Windows NT running on
x
86 (CISC) and R4000 (RISC) systems. The Win32 SDK tools generate only 32-bit code, and the Windows NT linker and loader have no support for fixing up 16-bit segmented addresses.
Therefore, for binary compatibility of a Win32-based application running on Win32s and Windows NT, mixing is not supported by Win32s. Mixing is not limited to embedding 16-bit routines in a Win32-based application, such as static library code. There is no support for Win32-based applications directly loading 16-bit DLLs or vice versa.
Applications that rely on 16-bit DLLs, such as licensed DLLs with difficult-to-obtain 32-bit versions, have several choices:
·
Use a client/server architecture where all 16-bit DLLs are bound to a small, custom 16-bit server application. This custom 16-bit server can communicate with the Win32-based application using DDE, shared memory, or other IPC mechanism. The client/server solution will work in Win32s and Windows NT.
·
A unique solution provided by Win32s allows Win32-based applications to use existing 16-bit DLLs and device drivers. The Universal Thunk, discussed later in this document, is not supported on Windows NT but is available as a stepping stone for moving applications to 32-bit on Windows 3.1
x
.


Device Drivers
Windows NT runs applications in user mode, but only kernel-mode device drivers running in privileged mode can access devices. Because of fundamental differences in architecture between Windows 3.1 and Windows NT, Win32s does not support the Windows NT device-driver model. For binary compatibility with Windows NT, Win32-based applications should not access hardware directly within the application.
This poses a problem similar to mixing 16-bit and 32-bit code. The general solution is to build your Win32-based application such that the main application has a standard interface to a Win32 DLL (service provider). The Win32 DLL uses a client/server design to request/transfer data to a 16-bit server responsible for hardware access on Windows 3.1
x
.
To support this application in Windows NT, the DLL should be replaced by a Windows NT-specific DLL that uses IOCTLs to communicate directly with the kernel-mode driver, or uses Win32 APIs for supported devices. This solution isolates the platform-specific code to a DLL, which can be correctly installed during setup.
This mixing restriction creates an interesting scenario for printing. The 16-bit Windows applications load and call printer drivers directly, by using calls such as
LoadLibrary
,
GetProcAddress
, and
ExtDeviceMode
. Win32s handles these printer drivers specifically by creating a mapping thunk dynamically. The address returned to the Win32-based application by
GetProcAddress
 is actually the address to the thunk that makes the 32/16 transition and calls the printer driver. This Win32s solution for printing has been generalized for Win32-based applications with the
universal thunk
 solution.


Universal Thunk
Binary compatibility and the requirement to provide natural migration to Windows NT and Windows 95 creates a portability problem for developers who have Windows applications that require device drivers. Windows NT does not support mixing 16- and 32-bit code in a Win32 process. The mixing restriction also prevents Win32-based applications from calling 16-bit DLLs.
A number of IPC mechanisms, such as DDE, allow data to be passed between Win32 and 16-bit Windows processes, but the bandwidth is not sufficiently high for some types of applications. The universal thunk (UT) allows a Win32-based application to call a routine in a 16-bit DLL. There is also support for a 16-bit routine to call back to a 32-bit function. The simple Win32s thunk used to implement this design also translates a data pointer to shared memory, from flat to segmented form, allowing large amounts of memory to be transferred between drivers and Win32-based applications.
This design allows a Win32-based application to isolate driver-specific routines in a 16-bit DLL. The Win32-based application remains portable across Windows 3.1
x
, Windows 95, and Windows NT; in Windows NT, the 16-bit DLL is replaced with a 32-bit DLL that communicates to devices by using the Windows NT model. A similar DLL would be written for Windows 95.


Universal Thunk Design
The following figure illustrates a Win32-based application using a Win32 service DLL on Windows NT or Windows 95.
The next figure illustrates how the same Win32-based application running on Windows 3.1
x
uses the UT mechanism to access services provided by a Win16 DLL. The figure illustrates thunking from 32-bit to 16-bit; thunking in the reverse direction works in a similar way.
The same version of the 32-bit application runs on Windows 3.1
x,
 Windows 95,
and Windows NT. For the service provider, different modules are required. They all provide the very same services, one using Win32 DLL on Windows NT, and another using 16-bit DLL by way of UT on Win32s.
UTRegister
 registers a UT with Win32s that can be used to access 16-bit code from a 32-bit application running on Win32s.
UTRegister
 will automatically load the 16-bit DLL specified by name as a parameter to this function. The 16-bit DLL exports two functions: an initialization function
InitFunc
and function
UTFunc. InitFunc
 is called once when
UTRegister
 is called and is optional.
UTFunc
is called indirectly using a 32-bit callable stub from the Win32-based application.
The thunk can be destroyed by calling
UTUnRegister
.
Registering the UT enables two options for communicating between 32-bit and 16-bit routines. The first option is to allow a Win32-based application to call a 16-bit routine, passing data using global memory. This is a Win32 application-initiated data transfer mechanism. The second option is to register a callback routine by which 16-bit code can callback into a 32-bit routine in a Win32 DLL. Again, global memory is used to transfer data.
UTRegister
 will result in Win32s loading the specified DLL (using
LoadLibrary
) with normal Windows 3.1
x
DLL initialization occurring. Win32s will then call the
InitFunc
routine (indirectly using the UT), passing this function a 16:16 alias of the 32-bit callback function. The
InitFunc
routine can return data in a global memory buffer.
UTRegister
 will also create a 32-bit callable stub for
UTFunc
 and return its address to the 32-bit DLL. Also, a 16-bit callable stub might be created to reflect the 32-bit callback and will be passed to the 16-bit DLL using its
InitFunc.
The UT will translate the 32-bit linear pointer to shared memory to a 16:16 segmented pointer for the 16-bit
UTFunc
routine. The application must define the format and packing of the data in the global memory. Care should be taken when passing information in structures using global memory since some data types, such as
int
, are 32-bits in Win32 and 16-bits in Windows 3.1
x
.
The UT stub and the callback thunk are associated with the 32-bit module whose module handle is passed to
UTRegister
. Only one UT can be registered per 32-bit DLL at any given time.
UTUnRegister
 allows the dynamically created UT to be destroyed and the 16-bit DLL freed. Win32s will clean up these resources automatically when the Win32 process terminates, either normally or abnormally.
1.
Win32s will destroy the UT and call
FreeLibrary
 for the 16-bit DLL when:
·
UTUnRegister
 is called.
·
The module that created the UT is unloaded, either normally or abnormally.
2.
The shared memory accessed using the thunked data pointer will be freed as part of normal process cleanup if the process itself does not free the memory.
3.
The 32-bit callback function should not be used by 16-bit interrupt handlers. The Win32 API does not support locking memory pages; therefore, an interrupt service routine that calls back into 32-bit code cannot guarantee that the code is currently paged into memory.


Translation List
One of the parameters passed to the callable stub (either 32-bit or 16-bit) is a translation list. If you want to pass a reference to a structure containing pointers, you should use a translation list (see the following figure), which indirectly points to all the pointers to be translated during the thunking process.
Upon a call to UT callable stub:
(*pfnMyDispatch)(lpPerson, SERVICE_ID, pTranslationList);
the thunking process will translate the
lpPerson
 pointer, scan the
lpTranslationList
 and translate in place all the pointers, change the stack, and call the relevant function.


Universal Thunk Implementation Notes
The following information discusses implementation issues that affect application performance. The UT functions, parameters, and structures are defined in the
Win32s API Reference
. The UT headers are located in the \MSTOOLS\WIN32S\UT directory.
1.
Include the file W32SUT.H when using UT services. On the 32-bit side, define W32SUT_32 before including the file. On the 16-bit side, define W32SUT_16.
2.
Link a 32-bit DLL using UT services with the library W32SUT32.LIB. A 16-bit DLL should be linked with the library W32SUT16.LIB.
3.
UTRegister
and
UTUnRegister
 can be loaded by calling
GetProcAddress
 on KERNEL32.DLL, or by linking to W32SUT.LIB.
UTLinearToSelectorOffset
 and
UTSelectorOffsetToLinear
 are exported by WIN32S16.DLL
4.
Only one UT may exist for each Win32 DLL. Additional calls to
UTRegister
 will fail until
UTUnRegister
 is called for that DLL.
5.
Win32s will destroy the UT and call
FreeLibrary
 for the 16-bit DLL when:
·
UTUnRegister
 is called
·
The Win32 DLL is freed, either normally or abnormally
6.
Memory allocated by 16-bit routines using
GlobalAlloc
 should be fixed using
GlobalFix
. It must be translated to flat address before it can be used by 32-bit code. Translation will be performed by Win32s if passed as
lpBuff
 or by using the translation list. It can also be translated explicitly using
UTSelectorOffsetToLinear
.
7.
The 32-bit callback function should not be used by 16-bit interrupt handlers. The Win32 API does not support locking memory pages, therefore an interrupt service routine that calls back into 32-bit code cannot guarantee that the code is currently paged into memory.
8.
Exception handling can be done in 32-bit code only. Exceptions in 16-bit code will be handled by the last 32-bit exception frame.
9.
While it is possible to call into 32-bit code from a 16-bit task using Universal Thunks, that 16-bit task will not have a proper 32-bit context, and many things (such as TLS indices) will not work.
Two samples are provided on the Win32 SDK CD-ROM that illustrate how to use and build a UT application:
·
\MSTOOLS\WIN32S\UT\SAMPLES\UT_DEF illustrates the fundamental pieces required to use the UT.
·
\MSTOOLS\WIN32S\UT\SAMPLES\UTSAMPLE is a buildable UT sample which calls several 16-bit functions and returns data to the Win32-based application.
Note
  The UT has been tailored to Windows 3.1
x
,
which provides a single address space for all processes. Applications that use the UT may have dependencies to Windows 3.1. The UT should be considered a stepping stone to full 32-bit applications. It is very important to isolate UT code in separate DLLs. These DLLs can be more easily replaced to run on Windows NT or Windows 95. The DLL can be replaced with platform-specific versions, isolating the application.


Win32s Development with the Win32 SDK
The Win32 SDK combined with a Win32 compiler provides all the tools necessary for creating a Win32-based application on Windows NT or Windows 95.
After a Win32-based application has been debugged and fully tested on Windows NT and Windows 95, you are ready to install Win32s and your Win32-based application on Windows 3.1
x
for final testing and verification. The Win32 SDK provides floppy-disk images containing a redistributable version of Win32s with a Setup program and FreeCell, a card game test application. You can choose to bundle these disks with your product or use the Win32s Setup Toolkit development files to customize your own application and Win32s installation program. For further details on Win32s redistributable files, refer to the Win32 SDK License Agreement.


Installing Win32s Development Files
The Win32s system files, Setup Toolkit for Win32s, and the development files are provided on the Win32 SDK CD-ROM in the \MSTOOLS\WIN32S directory. These files are intended for use on a Windows 3.1
x
 system. Two versions of Win32s are provided to aid debugging:
·
A debug version with additional Win32s asserts and diagnostic messages.
·
The nondebug (end-user) version of Win32s.
Symbol files for both debug and nondebug systems are provided to obtain symbolic information in stack dumps and when using the kernel debugger.
Also included are the sources to the Setup program used in the Win32s Setup program. These files should be used in conjunction with the 16-bit Microsoft Setup Toolkit to create and customize your own setup program.
To install the Win32s development files onto a Windows 3.1
x
 system, first install Win32s by using the Win32s Setup program described in the
Introduction to Microsoft Win32s
, then follow these steps:
1.
Start MS-DOS with appropriate software for accessing a local CD-ROM drive or a remote CD-ROM drive over the network.
2.
Access the Win32 SDK CD-ROM.
Type the drive letter and press enter. (For example
¾
x
:, where x: is the CD-ROM drive or network drive containing the Win32 SDK CD-ROM).
3.
Change directories to the Win32s files by typing
cd
 \
mstools\win32s
.
4.
Type
install
 and press
ENTER
.
5.
The INSTALL batch script will provide usage information on how to specify the destination directory for the Win32s files.


Porting Tool
Win32s allows applications to call any Win32 function. Win32 functions that cannot be supported in Windows 3.1
x
 generally return errors. A spreadsheet listing all Win32 APIs and whether the API is supported on Win32s, Windows 95, or Windows NT is located on the Win32 SDK CD-ROM in
\MSTOOLS\LIB\I386\WIN32API.CSV
, a comma-separated file.
To help programmers determine whether they have inadvertently referenced unsupported Win32 functions, the Win32 SDK provides a porting tool and a data file, WIN32S.DAT, that lists all unsupported Win32 functions on Win32s. Read WIN32S.DAT into the porting tool, load your application source code, and let the porting tool scan your sources.
To read the file into the porting tool:
1.
First install the Win32 SDK.
2.
Rename PORT.INI in
\MSTOOLS\BIN
 to PORT.DAT.
3.
Rename WIN32S.DAT in
\MSTOOLS\BIN
 to PORT.INI.
4.
Start Porting Tool (from the Win32 SDK Program Group).
5.
Load a source file to be analyzed.
6.
Select Interactive or Background port to have unsupported Win32 functions found and highlighted.
Note
  For more information on using the porting tool, run PORTTOOL and bring up Help.


Debugging and Testing
The Win32 SDK tools running on Windows NT or Windows 95 provide the primary development and debugging environment for creating Win32-based applications. A Win32-based application should be fully functional and debugged using WinDbg (or equivalent debugger) on Windows NT and Windows 95 before running the application on Win32s. There are several debugging solutions available to help test and debug Win32-based applications running on Windows 3.1
x
: remote WinDbg, debugging DLLs, profiling DLLs, and the Windows 3.1
x
 kernel debugger. Other debugging tools are available from tools vendors such as Borland, NuMega, Symantec, Microsoft, and others.


Remote WinDbg
The remote WinDbg solution makes it possible to debug your Win32-based application running on Windows 3.1
x
 (a second system) from your Windows NT or Windows 95 development machine (primary system). The Windows NT (or Windows 95) system is the development system with full sources for the application, where WinDbg debugs the Win32 binary running on the secondary Windows 3.1
x
 system. Since primary development and debugging should already be complete on Windows NT or Windows 95, this remote debugging technique should only be necessary to debug unique problems that occur when the Win32-based application runs on Windows 3.1
x
.
Binary debugging data is passed between the Windows 3.1
x
 and Windows NT or Windows 95 systems, so a cable that supports hardware handshaking (HW) is recommended. XON/XOFF flow control is also supported if a minimally wired NULL modem cable is used, but transfer is somewhat slower since data must be translated for transfer. The preceding figure illustrates standard cable wiring that should be used with the remote debugger.
Note
  The cable layouts in the preceding figure are for standard DB-9 serial connectors. Be sure to refer to your serial card manufacturer's manual for complete cabling information.
When setting up the remote debugger transport, be sure to specify XON/XOFF or HW (hardware handshaking) to match the cable that you are using. Also, make sure that you match the handshaking of the WinDbg and Remote WinDbg transports; both should be XON/XOFF or both should be set up for HW.
Remote WinDbg has better response with high communication baud rates and using HW rather than XON/XOFF control. Typically, you should use a baud rate of 19.2K. Test your connections before attempting to debug by using the Terminal program that ships with both Windows 3.1
x
 and Windows NT or Windows 95.
Install Win32s and your application on the Windows 3.1
x
 system. The following remote debug components should also be installed on the Windows 3.1
x
 system into a directory that is referenced by the PATH environment variable:
·
WDBG32S.EXE
·
DM32S.DLL
·
TLSER32S.DLL
Note
  WinDbgRm from Windows NT 3.5 no longer runs on Win32s. Use WDBG32S instead.
These files are located on the Win32 SDK CD-ROM in the
\MSTOOLS\BIN\I386
 directory. The following figures illustrate how to setup the WinDbg and WDBG32S transports to use COM1 at 19,200 baud with XON/XOFF control.
WinDbg minimizes the amount of information transmitted across the serial line by accessing symbols out of the local version of the application binaries located on the development system. WinDbg is designed to access the source code on the development system, saving enormous communication overhead that would be required if symbols and source code information were transferred over the serial line.
The remote debugging environment requires that binaries be located on the same drive/directory on both the development and target systems. For example, if
WIN32APP.EXE
 is built from sources in a
C:\DEV\WIN32APP
 directory, the binary should be located in this path on both systems. If you build your source files by specifying fully qualified paths for the compiler, the compiler will place this information with the debug records which will allow WinDbg to automatically locate the appropriate source files.
WinDbg expects the sources to be in the same directory where the binary is built, but WinDbg allows browsing for them if the sources are not found in the default location.
The Win32 SDK allows applications to be built with CodeView
Ô
, COFF debugging symbols, or both. The makefiles provided with the Win32 SDK samples illustrate the compiler and linker switches required to build CodeView symbols for WinDbg. For compiling, use
 -Od
 and
-Zi
 to turn off optimization and specify CodeView symbols, respectively. Specify
-debug:full
 and
-debugtype:cv
 when linking with LINK32. Makefile macros (such as cdebug and ldebug) in WIN32.MAK can be used to make this easier.


Debugging Session Example
To initiate a debugging session, begin with the host (Windows NT or Windows 95) system:
·
windbg
C:\DEV\WIN32APP\WIN32APP.EXE
(where
WIN32APP.EXE
 is the name of your binary and
C:\DEV\WIN32APP
 is the location of the binary on both systems).
·
Select the WinDbg menu Options/Debugger DLLs and set the Transport to SERIAL192. Set the serial port communication parameters.
On the Windows 3.1
x
 system:
·
Run
WDBG32S.EXE.
·
Select the WDBG32S menu Options\TransportDLLs and set the Transport to SERIAL192. Adjust the serial port parameters to match the WinDbg parameters on the Windows NT system.
·
Choose Connect.
Now return to the host system:
·
Step into the application. This will establish the communication connection.
·
Once a connection is established, WDBG32S will disappear. When the debugging session ends or the connection is broken, WDBG32S will reappear to allow you to reconnect or exit.
At this point you can now debug the application just as you would if you were debugging locally on the host system; you can set breakpoints, single step, display locals, structures, and so on.
Note
  WinDbg is designed for 32-bit and 16-bit debugging on Windows NT, but only 32-bit debugging on Win32s. Therefore, do not use WinDbg to trace into universal thunks or attempt to set breakpoints in 16-bit code. Using both the kernel debugger (WDEB386) and WinDbg simultaneously is not recommended.


Win32s Debugging DLLs
The Windows 3.1
x
 SDK provides two environments for debugging or testing your Windows applications: a debugging version of the retail Windows product and a nondebugging version. The same is true for Win32s shipped with the Win32 SDK; there are debug and nondebug versions of Win32s.
The debugging version of Windows 3.1
x
 consists of a set of DLLs that replace the Windows system DLLs of the retail product. The debugging DLLs provide error checking and diagnostics messages that help you debug a Windows application. Along with the DLLs, symbol files are also provided to help trace calls into Windows and Win32s.
During application development, you should use the debugging version of Windows. Switch to the nondebug versions for final application testing. To simplify switching between debug and nondebug Win32s binaries, use the SWITCH.BAT file located in the \MSTOOLS\WIN32S\BIN directory. Usage information is provided by invoking this batch file with no parameters.
Note
  Do not ship the debugging version of the Win32s files with your application. Not only would the debug versions undermine your application's performance, the license agreement on Win32s Redistributables only covers the nondebug files.
The Win32 SDK provides debugging versions of the Win32s DLLs. It is necessary to obtain a Windows 3.1
x
 SDK for the Windows 3.1
x
 debugging DLLs. The Windows 3.1
x
 SDK also provides additional details on how to use the debug DLLs.


Automated Testing Using Microsoft Test
Microsoft Test is an automated testing tool that facilitates building test scripts for regression testing, profiling, and quality assurance.
The same scripts built with 32-bit Microsoft Test on Windows NT or Windows 95 can be used with the 16-bit version of Microsoft Test for Windows 3.1
x
 to test Win32-based applications using Win32s. This will help verify and guarantee that your Win32-based application functionality is identical on Windows NT, Windows 95, and Windows 3.1
x
.
The Microsoft Test product is available separately from Microsoft and is not part of the Win32 SDK that ships 32-bit tools.


Application Profiling
The Win32 SDK provides tools for profiling Win32-based applications on Windows NT. One such tool allows calls to the Win32 API to be profiled to help determine how applications are calling the system and what calls are taking the longest.
The API profiling tool modifies the application's .EXE and .DLLs (if any) so that it dynamically links to a set of profiling DLLs. This is separate from the compile and link process. The API profiling tool, APF32CVT.EXE, is provided with the Win32 SDK and should be used on Windows NT to modify the Win32 binary.
In the \MSTOOLS\WIN32S\PROFILE directory you will find several profiling DLLs: ZERNEL32.DLL, ZSER32.DLL and ZDI32.DLL. These profiling DLLs should be used on Windows 3.1
x
 for Win32s profiling. The profiling DLLs can be placed in the same directory as the Win32-based application being profiled.
Once you have verified that profiling is working on Windows NT, you can use the same modified Win32-based application for API profiling on Windows 3.1
x
 using the Win32s versions of the profiling DLLs.


Kernel Debugger
The Windows 3.1
x
 kernel debugger is fully documented in the Windows 3.1
x
 SDK. An updated copy of the debugger (WDEB386.EXE) is provided on the Win32 SDK CD-ROM. The following kernel debugger notes should be sufficient regardless of whether or not you have the Windows 3.1
x
 SDK.
Windows NT executables (PE format) support COFF and CV4 debug and symbol information. The Windows 3.1
x
 kernel debugger supports a third, older format, SYM. The utility MAPSYMPE.EXE provided in the Win32 SDK creates a separate SYM file from COFF symbol information (which is embedded in the PE file). You can run MAPSYMPE.EXE on Windows NT as the final stage of your build process.
Since WinDbg uses CV4 debug information and MAPSYMPE.EXE uses COFF debug information, it is important to link your application correctly to get the proper debug data for debugging. When creating a debug version of your Win32-based application that will be used with the kernel debugger, specify:
-debug:full -debugtype:coff.
Specifying
-debugtype:both
 creates both CV4 and COFF symbols, but no COFF line numbers are generated; therefore this option is not useful for kernel debugging.
Debugging notes:
1.
Link your Win32-based application with
-debugtype:coff
 for kernel debugging (WinDbg requires
-debugtype:cv
).
2.
Use
MAPSYMPE.EXE
 to generate a
.SYM
 file.
mapsympe -o win32app.sym win32app.exe
Add a
-n
 if
mapsympe
 complains about too many line numbers.
3.
Invoke the Windows kernel debugger:
wdeb386 /c:n /x /s:win32app.sym [/s:win32s.sym ...] \windows\win.com
An alternative is to use an input file, as follows:
Create the file
WIN32S.DBG
 with these contents:
/c:1
/x
/s:win32app.sym
/s:win32s.sym
...
\windows\win.com
Invoke the debugger:
wdeb386 /f:win32s.dbg
4.
The debug version of Win32s provides basic facilities to monitor application execution. These features are triggered by setting bits in a debug flag, and are intended to help in Win32s system development. Some may be helpful for application development, as well.
Add a line to
<WINDOWS-DIRECTORY>\SYSTEM.INI
 in the [386Enh] section:
Win32sDebug=xxxxxxxx
where
xxxxxxxx
 is a hex value combined with the following flags:
·
00000001
¾
Verbose. Print messages including notification on application loading and termination, and exceptions.
·
00000002
¾
Stop on fatal exceptions. Causes the debugger to stop on abnormal exceptions such as divide by zero, general protection fault, invalid instruction, etc. These exceptions are not necessarily fatal. A general protection fault may occur while Windows checks whether a given hWnd is valid. Even if the exception is abnormal, such as divide by zero, it may be handled "gracefully" by Win32 SEH mechanism (try/except structure). The "Go" command will resume execution.
·
00000004
¾
Stop at 16-bit and 32-bit initialization code, and just before DLL initialization. Allows setting break points in application and DLL initialization routines.
·
00000008
¾
Print message for Win16 APIs that are called. This includes most USER and GDI calls and many KERNEL APIs.
·
00000010
¾
Stop on SetError
·
00000020
¾
Verbose loader
·
00000040
¾
Message return codes displayed before and after thunking
·
00000080
¾
NE resource table information
·
00000100
¾
SEH information
·
00000200
¾
Paging information
·
00000400
¾
Unimplemented/unrecognized message warnings
·
00001000
¾
Trap NULL pointer usage in 32-bit code (similar to 0x2) but for page faults only.
·
00002000
¾
Stop after loading completed. See 0x4.
·
00004000
¾
Trace Virtual Memory Manager in VxD
·
00010000
¾
Pass all int 1 to ring 3 (for debugging hi-level debugger while wdeb386 present)
·
80000000
¾
Pre-load all modules (disable demand paging of modules). With demand paging you may not be able to set a breakpoint if the page is currently not present. It is possible to use 386 debug registers ("br e address") for up to four breakpoints. This debug flag causes all modules to be pre-loaded so code can be disassembled and breakpoints set.
To assist setting the debug flags, the WIN32SDB.EXE utility (located in the
\MSTOOLS\WIN32S\BIN
 directory) can be used to set/check the state of the debug flags:
WIN32SDB.EXE Utility
Setting the following flags makes the following change in SYSTEM.INI:
[386Enh]
Win32sDebug=00000022
5.
All Win32 functions are defined in Win32s, so every Win32-based application can be loaded. Yet, many functions are not supported on Win32s, like security services. Calling these functions will return error values, which depend on the function; the last error is set to ERROR_CALL_NOT_IMPLEMENTED. In debug versions of Win32s, a message with the name of the unsupported function is printed on the debug terminal.
6.
Win32s debugging requires a large amount of contiguous virtual memory. You should have at least 4MB of physical memory. You can increase the amount of virtual memory by using the 386 Enhanced applet in the Windows Control Panel. From 386 Enhanced, click the Virtual Memory button and then click the Change button.
7.
You can switch between the debug version of Win32s and the end-user (nondebug) version by using the SWITCH.BAT file, which is installed onto the Windows 3.1
x
 system using INSTALL.BAT. Run SWITCH for usage information. This script lets you test using the additional debug support provided by the debug version and verifying the application on the end-user version (nondebug). Note: Be sure to run SWITCH.BAT from the directory where this file resides (\WIN32S\BIN).


Shipping Win32s with Win32 Applications
Win32s is not built into Windows 3.1, so software vendors must ship and install Win32s along with the Win32-based application in order to work on Windows 3.1
x
. The key feature of Win32s is that it allows software developers to ship Win32-based applications today for Windows 3.1
x
 and Windows NT that will continue to install and work well on future Windows operating systems. Setup programs created today must properly handle various setup issues when installing on current and future operating systems.
The Win32s Setup program provided with the Win32 SDK addresses all the issues raised in this guide. A 16-bit Setup program is required to install Win32s onto Windows 3.1
x
. The sources for the Win32s Setup program are provided. This will allow you to create a custom graphical setup program which addresses the system setup issues correctly, and to save time by re-using an existing solution. The Win32s Setup program is built using the Setup Toolkit shipped with the Microsoft Windows 3.1
x
 Software Development Kit, also available separately from Microsoft.


Win32s Installation Rules
For a single Win32-based application that installs correctly on Windows 3.1
x
 and Windows NT, a setup program should do the following:
·
Install Win32s files on Windows 3.1
x
 systems running in Enhanced Mode with paging enabled (paging is enabled by default in a Windows 3.1
x
 installation).
·
Not install Win32s files if Win32s is already installed (do a version check).
·
Install only Win32-based applications on Windows NT and Windows 95 (do not install Win32s files).
These minimum installation requirements ensure that Win32s files are only installed on systems that require them (Windows 3.1
x
) and not on Windows 95 or Windows NT since Windows NT and Windows 95 are capable of running Win32-based applications as they are.
A Win32s setup program should also meet the following criteria:
·
Detect Windows 3.0 or lower, provide an informative error message, and not install Win32s.
·
Detect Windows 3.1
x
 running in standard mode, give an informative error message, and not install Win32s.
·
Be prepared for possible future releases of Windows. Win32s should not be installed on any Windows version later than 3.11, since such versions will be able to run Win32-based applications directly.
·
Detect the presence of Windows NT and Windows 95 and install only the Win32-based application, not Win32s, since Windows NT and Windows 95 runs Win32 binaries directly.
·
If setup detects that Windows NT is running, test whether this is a RISC-based system. If RISC-based, setup should fail with appropriate message (or install R4000 or DEC Alpha version of the Win32-based application).
·
Setup should check for the presence of Win32s and only install a later version of Win32s (call
GetWin32sInfo
, exported by W32SYS.DLL and documented in Appendix C). Any future updates to Win32s will have higher version numbers, so that new versions can overwrite earlier releases.
·
For OLE applications, install the 16-bit OLE libraries in compliance with the OLE Programmer's Reference. This implies that each 16-bit DLL is overwritten only by newer 16-bit DLLs. Install the 32-bit OLE libraries in the same manner.
While the list of setup issues above seems long, a simple set of tests can detect these conditions. It is necessary to use a 16-bit installation program to install Win32s since Win32s isn't necessarily running yet. It is recommended that you use a Win16 program (rather than MS-DOS) and preferably based on the Win32s Setup program that ships with the Win32 SDK. Several functions can be called from a Win16 program to determine the version of the system, version of Win32s and the platform:
·
GetVersion
: Determine version number of Windows (for MS-DOS), Windows NT, and past and future versions of Windows.
·
GetWinFlags
: Flag indicates whether the Win16-based application is running on Windows NT. Test for 0x00004000: if set, then running on Windows NT.
·
_environ
: Use this C run-time function to determine if on a RISC-based system. Windows NT runs Win16-based applications using an emulator on RISC systems. Therefore, Setup should first determine if the system is Windows NT using
GetWinFlags
 (as discussed above), then check to ensure that the environment variable PROCESSOR_ARCHITECTURE is equal to INTEL before installing an
x
86-based Win32 application (or install the appropriate RISC binary).
Win32s 1.1 added an exported function from W32SYS.DLL to make it easy to determine the version number of Win32s that is installed. W32SYS.DLL is a 16-bit DLL, and this function should be called from a 16-bit Windows Setup program.
Before shipping a Win32-based application, it is critical to test your application fully on Windows 3.1
x
, Windows for Workgroups, Windows 95, and Windows NT.


Win32s File Installation and Configuration
This section lists all Win32s files and the directories in which the files must reside. The complete set of files must be installed. Partial installation will affect other Win32-based applications that rely on Win32s to run. All Win32s files contain version information. Your setup program must version-check every file and only install the most recent version on a file-by-file basis.
Note
  Win32s setup programs must implement version checking. There are previously released versions of Win32s. Only the most recent version of Win32s should be installed. Earlier versions of Win32s, such as Win32s 1.0, must not be installed over a Win32s 1.25 installation.
The following set of Win32s files must be installed in the
<SYSTEM>
directory (where
<SYSTEM>
 is the drive and directory returned from
GetSystemDirectory
. Note that this may not be on the same drive as the Windows directory.)
OLECLI.DLL
W32SYS.DLL
WIN32S.INI*
WIN32S16.DLL
WINMM16.DLL
The WIN32S.INI file is not shipped as part of Win32s but should be created during setup as discussed in the next section.
Note
  The WINMM16.DLL file and the driver for After Dark
™
 (ADWRAP.DRV) do not coexist. After installing Win32s, look at WIN32S.INI and make certain that the ADWRAP.DRV is listed in the device= line
after
 WINMM16.DLL and MMSYSTEM.DLL. Otherwise problems may result.
The following set of Win32s files must be installed in the
<SYSTEM>\WIN32S
 directory:
.EXE file:
WIN32S.EXE
.DLL files:
COMDLG32.DLL
COMCTL32.DLL
CRTDLL.DLL
LZ32.DLL
NETAPI32.DLL
NTMSG.DLL
OLECLI32.DLL
OLESVR32.DLL
SCK16THK.DLL
SHELL32.DLL
VERSION.DLL
W32SCOMB.DLL
W32SKRNL.DLL
WINMM.DLL
WSOCK32.DLL
Configuration files and drivers:
W32S.386
WINSPOOL.DRV
.NLS files:
You must also install National Language Support (.NLS) files that correspond to the market of the Win32s application. For a Win32s application that has an international market, you must install all of the .NLS files found in \MSTOOLS\WIN32S\NLS. For example, a Win32s application that is released only in the United States must install P_437.NLS, P_850.NLS, and P_1252.NLS.
The following files must be removed from the <SYSTEM>\WIN32S directory if an earlier version of Win32s is present:
ADVAPI32.DLL
C_*.NLS
EM87.DLL
GDI32.DLL
KERNEL32.DLL
MPR.DLL
NTDLL.DLL
USER32.DLL
See
Installing OLE Applications
 for OLE installations.
Once the files are installed, enable Win32s by loading the Win32s VxD. As with any VxD, do this by adding a
device=
 reference in the [Enh386] section of the Windows SYSTEM.INI file:
[Enh386]
device=c:\windows\system\win32s\w32s.386
Enable multimedia wave callbacks by having the WINMM16.DLL loaded when Windows boots. Do this by using the [Boot] section of SYSTEM.INI file. Add WINMM16.DLL to the
device
= line as below:
[Boot]
device=mmsytem.dll winmm16.dll
Please refer to the License Agreement concerning Win32s Redistributable Files.


Installing OLE Applications
This guide discusses issues related to the distribution of your OLE application. It continues with a description of the files that must be included on your distribution disk(s), discusses special considerations for OLE application distribution, and concludes with a discussion of special considerations for distribution of OLE server applications.


Disk Contents
You must distribute the files listed following if your application is OLE-enabled. When installing your application on the end user's system your install/setup program
must
 correctly install all of the following files to the user's <SYSTEM> directory:
COMPOBJ.DLL
OLE2.DLL
OLE2PROX.DLL
OLE2DISP.DLL
OLE2NLS.DLL
OLE2CONV.DLL
OLE2.REG
STDOLE.TLB
STORAGE.DLL
TYPELIB.DLL
You must also correctly install all of the following files to the user's <SYSTEM>\WIN32S directory:
OLE32.DLL
OLEAUT32.DLL
OLE2THK.DLL
STDOLE32.TLB
Note
  The installation of 32-bit OLE components must occur if the 16-bit OLE components are not installed. The 16-bit OLE files may already be present on the user's system.
Since OLE requires all of these files in order to run correctly, your setup/installation program must install
all of them
 regardless of whether or not the application itself uses the files.


Where to Install
Use the
GetSystemDirectory
 function to get the name of the user's <SYSTEM> directory. The install/setup program
must
 check the user's <SYSTEM> subdirectory to verify if copies of the OLE files are already present. If the files are already present in the user's system, the version information of
each
 file
must
 be checked to make sure that newer versions of the OLE files will not be overwritten by older versions.
You can use the File Installation Library, VER.DLL, supplied with Microsoft Windows Version 3.1
x
, to extract a version string from the application. For more information on VER.DLL, see the
Microsoft Windows Programmer's Reference, Volume 1: Overview
 in Version 3.1
x
 of the Microsoft Windows Software Development Kit.
Additionally, the application should copy its registration entry file
YYYY
.REG (
YYYY
 is determined by the object application) into the directory where the application installs its executable (.EXE file). This will allow the user to double-click on the
YYYY
.REG file and re-register the application in case the registration database (REG.DAT) gets corrupted. For the content and creation of the registration files, see
Registering OLE Libraries
.


TEMP Entry
Checking the TEMP Entry
The setup of an application should detect if the user's TEMP= entry points to a removable media and prompt the user to change it to point to a local hard drive. (If the application is doing AUTOEXEC.BAT modification, it should make the modification for the TEMP= entry also.)


SHARE.EXE
Checking the SHARE.EXE
In order to function, the OLE Compound File implementation requires that file range-locking be enabled. If range-locking is not already installed on the machine, then you must add the MS-DOS command
SHARE.EXE
to AUTOEXEC.BAT. SHARE.EXE is the common way that range-locking is supported on Microsoft Windows 3.1. On Microsoft Windows for Workgroups, range-locking is part of the system (through VSHARE.386) and SHARE.EXE should not be installed.
Caution
  The SHARE.EXE entry should follow the PATH statement in AUTOEXEC.BAT, but precede any statement that starts Windows or otherwise prevents SHARE.EXE from being executed.
To determine if range-locking is installed, open a local file and attempt to acquire a range lock on it. If an error is returned, then range-locking is not supported (see MS-DOS Int 21h Function 5Ch for further details). AUTOEXEC.BAT is a suggested local file to use for this purpose.
If range-locking is not supported, add SHARE.EXE to AUTOEXEC.BAT. If range-locking is in fact currently supported, you may still need to modify AUTOEXEC.BAT. Scan AUTOEXEC.BAT for SHARE.EXE. If it is not found, do nothing; if it is found, then ensure that its /L and /F options are at least as large as outlined below.
The
/L
option on the MS-DOS SHARE command indicates the number of locks that can be placed on files. The
/F
 parameter allocates file space (in bytes) for the MS-DOS storage area used to record file-sharing information. The default setting for the
/L
 option is 20 locks; the default setting for the
 /F
 option is 2048. Each open OLE Compound File requires for its own use four (or fewer) dedicated locks. The Compound File implementation requires a small number (fewer than five) of additional locks, independent of how many files are open. Each lock reserved by
/L
 requires 18 bytes.
It is recommended that an
/L
 setting of at least
/L:500
 and an
/F
 setting of at least
/F:5100
 be used:
SHARE /L:500 /F:5100
If the
/L
 or the
/F
 setting to SHARE has a larger value than listed here, installation programs should leave the setting as it is rather than reducing it.
Note
  Be sure to add the necessary copyright notice to the copyright notice(s) for your application. See the SDK documentation for information on copyright notices.


Registering OLE 2 Libraries
Registering OLE Libraries
The OLE libraries require that many internal interfaces be registered in the registration database. Therefore, if your installation program installs any of the OLE libraries on a machine that does not have them already, it should register OLE specific information by running
REGEDIT.EXE /S OLE2.REG
to register the OLE internal interfaces in the REG.DAT file.
Also, if your installation/setup program has overwritten older versions of the application on the user's hard drive, run the
REGEDIT.EXE /S OLE2.REG
 entry mentioned above.
If your installation program does not install OLE libraries because it found more recent libraries on the user's drive, it should not register the OLE interface information.
Note
  When checking the version stamp (using VER.DLL) on existing OLE libraries to determine whether to replace them on the user's hard drive, do so on a file-by-file basis.
If OLE2.REG is registered, copy the file to the user's <SYSTEM> directory.


Win32s Setup Sample
As part of the Win32s development files, a sample setup project is provided that will recreate the Win32s Setup floppy-disk image, which is also provided on the Win32 SDK CD-ROM. After installing Win32s, you will find a \WIN32S\SETUP directory containing Microsoft Setup Toolkit binaries, floppy disk layout files, and sources to Setup extensions that are used to install Win32s. You are encouraged to use these Setup files to build your own Win32-based application and Win32s installation program. Use the
Setup Toolkit for Windows
 manual as a reference.
You will find the following Win32s Setup Sample files:
·
\WIN32S\SETUP contains the layout files and required Setup Toolkit binaries.
·
\WIN32S\SETUP\BLDCUI contains the sources and dialog templates for Win32s Setup screens.
·
\WIN32S\SETUP\INIUPD contains the Setup extension DLL that:
1.
Determines if Win32s is already installed.
2.
Calls
GetWin32sInfo
 exported by W32SYS.DLL to determine the version of Win32s already on the user's computer, if any.
3.
Adds the VxD entry to SYSTEM.INI.
·
\WIN32S\SETUP\BUILD.BAT is used build the floppy-disk image in \WIN32S\DISKS\RETAIL\FLOPPY.
The FreeCell sample consists of three files: FREECELL.EXE, FREECELL.HLP, and CARDS.DLL. To ship your own application, modify the following setup sample files and change the FreeCell references as appropriate for your application:
·
For the Win32s core, W32S.LYT contains the names of the files to install, destination directories, and whether the files are compressed or not. This is the input file for the DSKLAYT2 utility, which creates the setup disk layout. For Win32s plus OLE, use OW32S.LYT.
·
32INST.MST is an MS-Test script that controls the setup process events. This file contains strings to add a Program Group to the Window Program Manager.
·
DIALOGS.DLG in the BLDCUI directory contains the dialog definitions and text for the Setup screens.
The Win32s Setup program creates/updates a WIN32S.INI file in the \WINDOWS\SYSTEM directory with the following information:
[Win32s]
Setup=1
Version=1.2.0.0
[Nls]
AnsiCP=1252
[FreeCell]
Setup=1
Version=1.2.0.0
The [Win32s] section indicates whether Win32s is fully installed (Setup=1 when Win32s is correctly installed.) This section should list the current version of Win32s that is installed. The [Nls] section tells Win32s which code page should be used for translation. If the [Nls] section is not present, code page 1252 is used by default. See
International Support
 for more information.
When OLE is installed a corresponding [ole] section appears in WIN32S.INI.
The WIN32S.INI file can also be used by Win32-based applications to indicate what Win32-based applications have been installed, and what version of Win32s was installed at the time the application was installed. FreeCell is listed above as an example of a Win32-based application entry. The example indicates that Win32s version 1.25 was installed.
The Win32s Setup program requires the 16-bit Microsoft Setup Toolkit, which is a separate product available from Microsoft that was previously bundled with the Microsoft
®
 Windows 3.1 SDK.
Note
  The disk layout utility that ships with the Microsoft Setup Toolkit uses COMPRESS.EXE for file compression. Several versions of this utility are shipped with other products. Be sure that the version shipped with the Microsoft Setup Toolkit is first in the PATH statement when building the Win32s Setup sources.


Unsupported Features
The following features are planned for Win32s version 1.3:
·
Windows 95/Windows NT 3.51 Common Controls
·
Windows 95/Windows NT 3.51 Common Dialogs
·
WinHelp 4.0
·
OLEDLG (OLE Dialogs)
Win32s 1.3 is planned to be the last release of Win32s as Windows 95 replaces Windows 3.1 as the volume platform.
The following Win32 features are not currently planned for Win32s:
·
MAPI
·
RPC
·
Console APIs
·
Unicode APIs (Win32s does support Code Page/Unicode translation APIs)
·
Security APIs
·
Comm APIs
·
Asynchronous File I/O
·
Threads
·
Paths (graphics object)
·
Enhanced Metafiles
·
Bezier curves
While it is impossible to include all of the features listed above in a future Win32s release, your feedback on desired features is very important. Please post your suggestions on the CompuServe
®
 MSWIN32 forum in the
API-Win32s
 section.


System Limits
This guide lists Windows 3.1
x
 and Windows NT differences that programmers should be aware of when designing Win32-based applications to run on both platforms. Reviewing these differences can save time developing and debugging applications.


Window Manager (User)
Win32s relies on Windows 3.1
x
 to provide standard dialog controls such as list boxes, combo boxes, and edit controls. Win32s translates messages between the controls and the Win32-based application.
Controls have size limitations that do not exist on Windows NT. An edit control, for example, is limited to somewhat less than 64K of text; list boxes store data in one 64K heap. Therefore, a Win32-based application can create a large file by way of an edit control in Windows NT and not be able to read the file back into the same edit control when the Win32-based application is run with Windows 3.1
x
 or Windows 95.
Controls support specifying limits on the amount of information they will hold, such as
EM_SETLIMITTEXT
 for edit controls. One solution is to specify a lowest common denominator for controls to ensure compatibility across platforms. Other solutions are application specific.
Win32s does not support
EM_SETHANDLE
 and
EM_GETHANDLE
. These messages allow the sharing of local memory handles between an application and the system. In Win32s an application's local heap is 32 bits and allocated from the global heap, so Windows 3.1
x
 cannot interpret a local handle. Text for multiline edit controls is stored in the 16-bit local heap. This means that the amount of edit control text is limited to somewhat less than 64K. To read and write multiline edit control text, an application should use the
WM_GETTEXT
 and
WM_SETTEXT
 messages.
Any private application message must be defined above WM_USER + 0x100. This will ensure that there is no collision between private messages and dialog control messages on Windows 3.1
x
.
When calling the
PeekMessage
 function, a Win32-based application should not filter any messages for Windows 3.1
x
 private window classes (button, edit, scroll bar, and so on). The messages for these controls are mapped to different values in Win32, and checking for the necessity of mapping is a time-consuming operation.
Win32s child window identifiers must be sign-extended 16-bit values. This precludes using 32-bit pointer values as child window identifiers.
Windows NT dynamically grows the message queue size. Windows 3.1
x
 has a default message queue size of 8, which can be changed by calling
SetMessageQueue
. This call is supported in Win32s and is a no-operation instruction on Windows NT.
The
SetClipboardData
 function must be called with global handles to ensure that the data can be accessed by other applications.
Applications specify the return value for the
DialogBox
 function by way of the
nResult
 parameter to the
EndDialog
function. This parameter is of type
int
, which is 32-bits for Win32-based applications. However, this value is thunked by Win32s to the Windows 3.1
x
 EndDialog
 function, which will truncate it to 16 bits. Win32s sign-extends the return code from
DialogBox
.
The
TranslateMessage
 function is better supported on Windows NT than on Windows 3.1
x
. Win32s provides the Windows 3.1
x
 functionality that is to return TRUE when any key or number is typed (which generates a KEYDOWN/KEYUP sequence). On Windows NT, function and arrow keys will also result in
TranslateMessage
 returning TRUE. Few applications test the return value from
TranslateMessage
.
Resource IDs (identifiers in resource files) must be 16-bit values.
The resource table size is limited to 32K (not including the resource data).


Graphics (GDI)
Windows 3.1
x
 has a limit of five cached device contexts (DCs). The
GetDC
call obtains a cached DC in Windows 3.1
x
; therefore, it is important to call
ReleaseDC
 before checking the message queue. Otherwise, another application may be scheduled and there will be one less cached DC for all applications in the system. Windows NT does not have a cached DC limit but applications should not waste DCs. It is important to follow the
GetDC/ReleaseDC
 model for compatibility on both platforms and good memory management.
Windows 3.1
x
 allows drawing objects (pens and brushes) to be deleted while still selected in a DC. However, the memory allocated for the drawing object remains allocated until the process terminates. In Windows NT, the
DeleteObject
 call fails. Don't delete selected objects, for this may slowly use up system resources while the application is running on Windows 3.1
x
.
The
SetDIBitsToDevice
 function is not supported for bitmaps in memory DCs, and is limited to bitmaps of up to 3.75MB when using block-transfers (BLTs) to update the display. This limit was chosen to support a 1280x1024x24 bitmap. Since the limit is one of size and not resolution, larger bitmaps with a lower color depth are supported (for example, 1600x1200x16).
Process cleanup assures that all objects allocated by an application exiting the system are destroyed and the memory freed for reuse by the system or other applications. Windows 3.1
x
 added additional robustness and process cleanup compared to Windows 3.0, but is not as complete as Windows NT. Win32-based applications running on Windows 3.1
x
 must abide by the same rules as 16-bit Windows applications and properly free objects allocated while running, especially pens, brushes and other graphics objects.
Windows 3.1
x
 has a 16-bit world coordinate system (as does Windows 95). Windows NT supports a 32-bit world coordinate system. You must use the Windows 3.1
x
 limit in developing a Win32-based graphics application that will run on Windows 3.1
x
, Windows 95, and Windows NT.
Windows NT allows Win32-based applications to call
SetCursor
 and specify an icon handle. Windows NT supports color icons and color cursors; Windows 3.1
x
 only supports color icons and monochrome cursors. Therefore, you cannot pass an icon handle to
SetCursor
 on Win32s.
In Win32s,
GetIconInfo
 sets to TRUE the
fIcon
 member of the
ICONINFO
 structure pointed to by
pIconInfo
. In Windows NT and Windows 95,
GetIconInfo
 sets
fIcon
 to FALSE for a cursor and TRUE for an icon.
For an application's icon in Program Manager, Windows NT uses the first icon specified in the RC file; Windows 3.1 uses the lowest-numbered icon. To use the same icon in Windows NT and Windows 3.1, the first icon in the RC file should be the lowest-numbered icon.


System Services (Kernel)
Win32s processes that are started by Win16-based applications should be launched using
WinExec
.
The Win16 version of
LoadModule
 will not start a Win32s process. If you are using the Win32 version of
LoadModule
, note the following difference in specifying the
lpCmdLine
 in the
LOADPARAMS32
 structure passed to this function:
·
On Windows NT,
lpCmdLine
 points to a Pascal-style string that contains a correctly-formed command line. The first byte of the string contains the number of bytes in the string. The remainder of the string contains the command line arguments, excluding the name of the child process. If there are no command line arguments, this parameter must point to a zero length string; it cannot be NULL.
·
On Win32s,
lpCmdLine
 points to a null-terminated string that contains a correctly-formed command line. The string must not exceed 120 bytes in length.
The
VirtualAlloc
 function provides a feature on Windows NT allowing the process to request the memory allocation at a specified virtual address. This is supported on Win32s, but applications should not be designed to depend on available address range. Windows NT allocates memory in the low 2GB address space, Win32s allocates memory in the high 2GB address space. Applications can query the address space using
GetSystemInfo
.
Do not specify GMEM_FIXED when using
GlobalAlloc
 (use GMEM_MOVEABLE instead). On Win32s, this will result in locked pages in memory. Therefore, allocations will be limited to physically available memory rather than virtual limits (pageable memory allocations).
The implementation of the Win32
Sleep
 function differs in Win32s and Windows NT. On Win32s, this function calls
Yield
, which will return immediately if a) no other applications have messages in their message queues awaiting processing or b) the application calling
Yield
 still has messages in its queue. It is not possible to block for the specified delay time (as occurs on Windows NT) since Windows 3.1
x
 is a cooperative multitasking system, not a pre-emptive multitasking system. Time delays should be implemented in
PeekMessage
 loops with calls to
GetSystemTime
 to control delay time.
On Windows NT you cannot call
DeleteFile
 and delete an open file (for normal I/O or as a memory mapped file). On MS-DOS (and therefore Win32s) you can, even if SHARE.EXE is loaded. Deleting such a file may result in loss of data and application failure. Be very careful when using
DeleteFile
 to ensure that the file is not in use.
When a file is created or modified, the precision of the recorded time is
±
2 seconds (this is an MS-DOS limitation from the FAT file system). Also, file times returned in Win32s are always in local time, not UTC.
The
GetPrivateProfileSection
 and
GetProfileSection
 functions work only on initialization files that have unique keys. For example, in the following private initialization file:
[TestSection]
Entry1=123
Entry1=456
Entry1=789
Entry2=ABC
The
 GetPrivateProfileSection
 function will return three copies of the string: Entry1=123.
Windows 3.1
x
 supports a single value (string) per key in its registration database. Windows NT supports a multivalue per key registration database and new APIs to manipulate the database. Win32s supports the subset of Win32 registry APIs that map to Windows 3.1
x
 functionality.
Win32-based applications and DLLs should be linked with 4K alignment. This is the default for the LINK32 linker that ships with the Win32 SDK. 64K alignment is supported, but 4K is more efficient for the memory manager in the shared 2GB address space of Windows 3.1
x
.
Calling
LoadLibrary
 on a 16-bit DLL will succeed and return a valid
hModule
, but
GetLastError
 will return ERROR_BAD_EXE_FORMAT. This was done to support the
LoadLibrary
/
GetProcAddress
 method of printing, and for some resource APIs. The
hModule
 returned cannot be used for other methods. Make sure that
FreeLibrary
 is called for this
hModule
 when you are finished with the handle.


Networking
The WinSocket API supports blocking and non-blocking calls. The WinSocket specification indicates that blocking calls should be avoided on systems (such as Windows 3.1
x
) that are non-pre-emptive. A portable Win32 WinSocket application should use non-blocking calls in order to run well on Win32s, Windows 95, and Windows NT.
Windows NT supports certain
NetBios
 features that are not supported on Win32s due to the non-pre-emptive shared memory design of Windows 3.1
x
. The
ncb_event
 member of the
NCB
 structure is ignored since Win32s does not implement Win32 events. Also, Windows NT maintains a per-process name table; Win32s maintains one system-wide name table. Before calling
Netbios
 with NCBRESET, there should be no outstanding asynchronous messages
¾
 all such messages should be received or canceled.


Multimedia
Win32s supports all multimedia sound APIs provided on Windows NT except for MIDI callbacks, so the CALL_FUNCTION flag of
midiOutOpen
 and
midiInOpen
 is not supported. Also, Multimedia event callbacks (
timeSetEvent
 and
timeKillEvent
) are not supported.
Win32s does not support the SND_ALIAS, SND_FILENAME, and SND_NOWAIT flags for
PlaySound
. These flags are supported in Windows NT and Windows 95.


Win32s API Reference
The functions listed in this guide are supported by Win32s and define interfaces for Setup programs and the Universal Thunk.


GetWin32sInfo
WORD GetWin32sInfo(
    LPWIN32SINFO
lpInfo
   );
Parameters
lpInfo
Points to a WIN32SINFO structure, defined as follows:
typedef struct {
    BYTE bMajor;
    BYTE bMinor;
    WORD wBuildNumber;
    BOOL fDebug;
} WIN32SINFO, far * LPWIN32SINFO;
Return Value
The return value is zero if the function is successful. Otherwise, the possible values are:
1
Win32s VxD not present.
2
Win32s VxD not loaded because paging system not enabled.
3
Win32s VxD not loaded because Windows is running in standard mode.
Remarks
Function is exported by W32SYS.DLL in Win32s version 1.1 and later. The function fills the specified structure with the information from Win32s VxD. A 16-bit Windows Setup program should use this function to determine if Win32s is already installed version and only install a later Win32s release. The Setup program must use
LoadLibrary
 and
GetProcAddress
 to call the function since the function did not exist in Win32s 1.0.
Example
// Indicates whether Win32s is installed and version number
// if Win32s is loaded and VxD is functional.
BOOL FAR PASCAL IsWin32sLoaded(LPSTR szVersion)
{
    BOOL              fWin32sLoaded = FALSE;
    FARPROC           pfnInfo;
    HANDLE            hWin32sys;
    WIN32SINFO        Info;
    hWin32sys = LoadLibrary("W32SYS.DLL");
    if (hWin32sys > HINSTANCE_ERROR) {
        pfnInfo = GetProcAddress(hWin32sys, "GETWIN32SINFO");
        if (pfnInfo) {
            // Win32s version 1.1 (or later) is installed
            if (!(*pfnInfo)((LPWIN32SINFO) &Info)) {
                fWin32sLoaded = TRUE;
                wsprintf(szVersion, "%d.%d.%d.0",
                         Info.bMajor, Info.bMinor, Info.wBuildNumber);
            } else
                fWin32sLoaded = FALSE;    // Win32s VxD not loaded.
        } else {
            // Win32s version 1.0 is installed.
            fWin32sLoaded = TRUE;
            lstrcpy( szVersion, "1.0.0.0" );
        }
        FreeLibrary( hWin32sys );
    } else                                // Win32s not installed.
        fWin32sLoaded = FALSE;
    return fWin32sLoaded;
}


Universal Thunk API
The universal thunk (UT) allows a Win32-based application to call a routine in a 16-bit DLL. It also allows a 16-bit routine to call back to a 32-bit function. This API represents the means by which these calls and associated operations can be completed.


UTRegister
BOOL
UTRegister(
    HANDLE
hModule
,
    LPCTSTR
lpsz16BITDLL
,
    LPCTSTR
lpszInitName
,
    LPCTSTR
lpszProcName
,
    UT32PROC
 *
ppfn32Thunk
,
    FARPROC
pfnUT32CallBack
,
    LPVOID
lpBuff
,
   );
This routine registers a universal thunk (UT) that can be used to access 16-bit code from a Win32 application running via Win32s on Windows 3.1. Only one UT can be created per Win32 DLL. The thunk can be destroyed by calling
UTUnRegister
. UTRegister
will automatically load the 16-bit DLL specified. After loading the 16-bit DLL, Win32s calls the initialization routine. Win32s creates a 32-bit thunk that is used to call the 16-bit procedure in the 16-bit DLL.
Parameters
hModule
Handle of 32-bit DLL. The UT provides a mechanism to "extend" a Win32 DLL into Windows 3.1. The thunk is owned by the DLL and every DLL is limited to one thunk.
lpsz16BITDLL
Points to a null-terminated string that names the library file to be loaded. If the string does not contain a path, Win32s searches for the library using the same search mechanism as
LoadLibrary
 on Windows 3.1.
lpszInitName
Points to a null-terminated string containing the function name, or specifies the ordinal value of the initialization function. If it is an ordinal value, the value must be in the low word and the high word must be zero. This parameter can be NULL if no initialization or callback is required.
lpszProcName
Points to a null-terminated string containing the function name, or specifies the ordinal value of the 16-bit function. If it is an ordinal value, the value must be in the low word and the high word must be zero.
ppfn32Thunk
Return value is a 32-bit function pointer (thunk to 16-bit routine) if
UTRegister
 is successful. This function can be used to call the 16-bit routine indirectly.
pfnUT32CallBack
Address of the 32-bit callback routine. Win32s creates a 16-bit callable thunk to the 32-bit function and provides it to the initialization routine. The 32-bit routine does not need to be specified as an EXPORT function in the DEF file. No callback thunk is created if either this parameter or
lpszInitName
 is NULL.
lpBuff
Pointer to globally allocated shared memory. Pointer is translated into 16:16 alias by UT and is passed to the initialization routine. This parameter is optional and ignored if NULL.
Return Value
Function returns TRUE if the DLL is loaded and
UT16Init
 routine was successfully called or FALSE if an error occurred. To obtain extended error information, call
GetLastError
. Typical errors are:
ERROR_NOT_ENOUGH_MEMORY
ERROR_FILE_NOT_FOUND
ERROR_PATH_NOT_FOUND
ERROR_BAD_FORMAT
ERROR_INVALID_FUNCTION
ERROR_SERVICE_EXISTS (when the UT is already registered).
Remarks
Registering the UT enables two capabilities for communicating between 32-bit and 16-bit routines. The first capability is to allow a Win32 application to call a 16-bit routine passing data using globally shared memory. This is a Win32 application initiated data transfer mechanism. The second capability is to register a callback routine by which 16-bit code can callback into a 32-bit routine in a Win32 DLL. Again, shared global memory is used to transfer data.
UTRegister
 will result in Win32s loading the specified DLL with normal Windows 3.1 DLL initialization occurring. Win32s will then call the initialization routine passing this function a 16:16 thunk to the 32-bit callback function. The initialization routine can return data in a global shared memory buffer. The initialization routine must return a nonzero value to indicate successful initialization.
The initialization routine must return a nonzero value to indicate successful initialization. If it fails no thunk is created.
UTRegister
 returns a 32-bit thunk to the 16-bit
UT16Proc
. This pointer can be used in Win32 code to call the 16-bit routine:
dwUserDefinedReturn = (*pfnUT16Proc)(pSharedMemory, dwUserDefinedSend,
        lpTranslationList);
The UT will translate the 32-bit linear address of the shared memory to a 16:16 segmented pointer, along with all the addresses listed by
lpTranslationList
 before passing it to the 16-bit
UT16Proc
 routine.
The 16-bit code can call Win32 code using the callback mechanism:
dwUserDefinedReturn = (*pfnUT32CallBack)(pSharedMemory,
        dwUserDefinedSend, lpTranslationList);
The 32-bit callback routine should be defined as follows (but does not need to be exported in the DEF file):
DWORD WINAPI UT32CBPROC(LPVOID lpBuff, DWORD dwUserDefined);
See Also
UT16Proc
,
UTUnRegister
,
LoadLibrary
(16-bit version),
GetProcAddress
(16-bit version)


UTUnRegister
VOID UTUnRegister(
    HANDLE
hModule
   );
Requests Win32s to call
FreeLibrary
 for the 16-bit DLL loaded by
UTRegister
. Also, destroys the dynamically created universal thunk (UT).
Parameters
hModule
Handle of 32-bit DLL which previously registered the UT.
Return Value
No return value.
Remarks
This call allows the single dynamically created UT to be destroyed and the 16-bit DLL dereferenced. Win32s will clean up these resources automatically when the Win32 DLL is freed (normally or abnormally).
See Also
UTRegister
,
FreeLibrary
 (16-bit version)


UT16INIT
DWORD
FAR PASCAL UT16INIT(
    UT16CBPROC
pfnUT16CallBack
,
    LPVOID
lpBuff
   );
UT16INIT name is a placeholder for the application-defined function name. The actual name must be exported by including it in the EXPORTS statement in the DLL's DEF file. This function will be called only once upon calling
UTRegister
 by the 32-bit DLL.
Parameters
pfnUT16CallBack
16-bit thunk to 32-bit callback routine, as specified at registration.
lpBuff
Pointer to general purpose memory buffer that was passed by the 32-bit code.
Return Value
1
Upon success.
0
Upon failure. If the initialization function fails, no stub will be created and
UTRegister
 will return 0.
See Also
UTRegister


UT16CBPROC
typedef DWORD FAR PASCAL(
    LPVOID
lpBuff
,
    DWORD
dwUserDefined
,
    LPVOID
*lpTranslationList
,
   );
Prototype of the 16-bit callable stub that is called by the 16-bit DLL. The stub will translate the
lpBuff
 pointer to a 32-bit pointer, scan the translation list and translate all its pointers to 32-bit pointers, arrange the stack as a 32-bit stack, and then call the 32-bit procedure in the 32-bit DLL.
Parameters
lpBuff
Pointer to general-purpose memory buffer. This segmented pointer is translated to flat address and passed to the 32-bit callback procedure. This parameter is optional. If not used, should be NULL.
dwUserDefined
Available for application use.
lpTranslationList
A far (16:16) pointer to an array of far (16:16) pointers that should be translated to flat form. The list is terminated by a null pointer. No validity check is performed on the address except for null check. The translation list is used internally and not passed to the 32-bit callback procedure. This parameter is optional.
Return Value
User defined
See Also
UTRegister


UT32CBPROC
DWORD WINAPI UT32CBPROC(
    LPVOID
lpBuff
,
    DWORD
dwUserDefined
   );
UT32CBPROC name is a placeholder for the application-defined function name. It does not have to be exported. That callback function will be called indirectly by the 16-bit side.
Parameters
lpBuff
Pointer to general purpose memory buffer as passed to 16-bit callback thunk.
dwUserDefined
Available for application use.
Return Value
User defined.
Remarks
Memory allocated by 16-bit code and passed to 32-bit must first be fixed in memory.
See Also
UTRegister


UT16PROC
DWORD FAR PASCAL UT16PROC(
    LPVOID
lpBuff
,
    DWORD
dwUserDefined
   );
UT16PROC name is a placeholder for the application-defined function name. The actual name must be exported by including it in the EXPORTS statement in the DLL's DEF file.
Parameters
lpBuff
Pointer to general purpose memory buffer that is passed by the 32-bit code.
dwUserDefined
Available for application use.
Return Value
User defined.
See Also
UTRegister


UT32PROC
typedef DWORD (
    LPVOID
lpBuff
,
    DWORD
dwUserDefined
,
    LPVOID
 *
lpTranslationList
   );
Prototype of the 32-bit callable stub that is called by the 32-bit DLL. The stub will translate the
lpBuff
 pointer to a 16:16 pointer, scan the translation list and translate all its pointers to 16:16 pointers, arrange the stack as a 16-bit stack, and then call the 16-bit procedure in the 16-bit DLL.
Parameters
lpBuff
Pointer to general purpose memory buffer. This 32-bit pointer is translated to 16:16 form and passed to the 16-bit procedure. The segmented address provides addressibility for objects up to 32K. This parameter is optional.
dwUserDefined
Available for application use.
lpTranslationList
Pointer to an array of pointers that should be translated to segmented form. The list is terminated by a null pointer. No validity check is performed on the address except for null check. The translation list is used internally and not passed to the 16-bit procedure. This parameter is optional and if not used should be NULL.
Return Value
User defined.
See Also
UTRegister


Universal Thunk Auxiliary Services
The following are address translation services available for 16-bit code only.
UTSelectorOffsetToLinear
UTLinearToSelectorOffset


UTLinearToSelectorOffset
LPVOID UTLinearToSelectorOffset(
    DWORD
lpByte
,
   );
Translate a flat address to a segmented form.
Parameters
lpByte
Translate a flat address to segmented form.
Return Value
Equivalent segmented address (16:16 far pointer).
Remarks
The returned address guarantees addressibility for objects up to 32K.
See Also
UTSelectorOffsetToLinear
,
GlobalFix


UTSelectorOffsetToLinear
DWORD UTSelectorOffsetToLinear(
    LPVOID
lpByte
;
   );
Parameters
lpByte
Translate a segmented address to flat form.
Return Value
Equivalent flat address.
Remarks
The base of the flat selectors used by Win32s process is not zero. If the memory is allocated by 16-bit API it must be fixed before its address can be converted to flat form.
See Also
UTLinearToSelectorOffset


Legal Notice
Information in this document is subject to change without notice. Companies, names, and data used in examples herein are fictitious unless otherwise noted. No part of this document may be reproduced or transmitted in any form or by any means, electronic or mechanical, for any purpose, without the express written permission of Microsoft Corporation.
Microsoft may have patents or pending patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in this document. The furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other intellectual property rights except as expressly provided in any written license agreement from Microsoft.
©
1995 Microsoft Corporation. All rights reserved.
Portions
©
 Silicon Graphics, Inc. from the
OpenGL Programming Guide
 and the
OpenGL Reference Manual
. Reprinted with permission of Silicon Graphics, Inc.
Microsoft, MS, MS-DOS, Windows, Win32, and Win32s are registered trademarks, and Windows NT is a trademark of Microsoft Corporation. OS/2 is a registered trademark licensed to Microsoft Corporation.
U.S. Patent No. 4974159
Macintosh and TrueType are registered trademarks of Apple Computer, Inc.
Alpha AXP and DEC are trademarks of Digital Equipment Corporation.
Hewlett-Packard, HP, LaserJet, and PCL are registered trademarks of Hewlett-Packard Company.
AT, IBM, Micro Channel, OS/2, and XGA are registered trademarks, and PC/XT and RISC System/6000 are trademarks of International Business Machines Corporation.
Intel and Pentium are registered trademarks, and i386 and i486 are trademarks of Intel Corporation.
Intergraph is a registered trademark of Intergraph Corporation.
Arial, Monotype, and Times New Roman are registered trademarks of The Monotype Corporation.
NCR is a registered trademark of NCR Corporation.
OpenGL and Silicon Graphics are registered trademarks, and IRIS GL is a trademark of Silicon Graphics, Inc.
PostScript is a registered trademark of Adobe Systems, Inc.
Unicode is a registered trademark in the United States and other countries, licensed exclusively through X/Open Company, Ltd.
UNIX is a registered trademark of UNIX Systems Laboratories.
X Window System is a trademark of the Massachusetts Institute of Technology.


Introduction to OpenGL
As a software interface for graphics hardware, OpenGL's main purpose is to render two- and three-dimensional objects into a frame buffer. These objects are described as sequences of vertexes (which define geometric objects) or pixels (which define images). OpenGL performs several processing steps on this data to convert it to pixels to form the final desired image in the frame buffer.
The following topics
present
 a global view of how OpenGL works
:
·
OpenGL Fundamentals
 briefly explains basic OpenGL concepts, such as what a graphic primitive is and how OpenGL implements a client-server execution model.
·
Basic OpenGL
Operation
 gives a high-level description of how OpenGL processes data and produces a corresponding image in the frame buffer.


OpenGL Fundamentals
The following topics
 explain some of the concepts inherent in OpenGL.
Primitives and Commands
OpenGL draws primitives
¾
points, line segments, or polygons
¾
subject to several selectable modes. You can control modes independently of one another; that is, setting one mode doesn't affect whether other modes are set (although many modes may interact to determine what eventually ends up in the frame buffer). Primitives are specified, modes are set, and other OpenGL operations are described by issuing commands in the form of function calls.
Primitives are defined by a group of one or more vertexes. A vertex defines a point, an endpoint of a line, or a corner of a polygon where two edges meet. Data (consisting of vertex coordinates, colors, normals, texture coordinates, and edge flags) is associated with a vertex, and each vertex and its associated data are processed independently, in order, and in the same way. The only exception to this rule is if the group of vertexes must be clipped so that a particular primitive fits within a specified region. In this case, vertex data may be modified and new vertexes created. The type of clipping depends on which primitive the group of vertexes represents.
Commands are always processed in the order in which they are received, although there may be an indeterminate delay before a command takes effect. This means that each primitive is drawn completely before any subsequent command takes effect. It also means that state-querying commands return data that is consistent with complete execution of all previously issued OpenGL commands.


Procedural versus Descriptive
OpenGL provides you with fairly direct control over the fundamental operations of two- and three-dimensional graphics. This includes specification of such parameters as transformation matrices, lighting equation coefficients, antialiasing methods, and pixel update operators. However, it doesn't provide you with a means for describing or modeling complex geometric objects. Thus, the OpenGL commands you issue specify how a certain result should be produced (what procedure should be followed) rather than what exactly that result should look like. That is, OpenGL is fundamentally procedural rather than descriptive. Because of this procedural nature, it helps to know how OpenGL works
¾
the order in which it carries out its operations, for example
¾
to fully understand how to use it.


Execution Model
The model for interpretation of OpenGL commands is client-server. An application (the client) issues commands, which are interpreted and processed by OpenGL (the server). The server may or may not operate on the same computer as the client. In this sense, OpenGL is network-transparent. A server can maintain several GL contexts, each of which is an encapsulated GL state. A client can connect to any one of these contexts. The required network protocol can be implemented by augmenting an already existing protocol or by using an independent protocol. No OpenGL commands are provided for obtaining user input.
The effects of OpenGL commands on the frame buffer are ultimately controlled by the window system that allocates frame buffer resources. The window system determines which portions of the frame buffer OpenGL may access at any given time and communicates to OpenGL how those portions are structured. Therefore, there are no OpenGL commands to configure the frame buffer or initialize OpenGL. Frame buffer configuration is done outside of OpenGL in conjunction with the window system; OpenGL initialization takes place when the window system allocates a window for OpenGL rendering.


Basic OpenGL Operation
The figure shown below gives an abstract, high-level block diagram of how OpenGL processes data. In the diagram, commands enter from the left and proceed through what can be thought of as a processing pipeline. Some commands specify geometric objects to be drawn, and others control how the objects are handled during the various processing stages.
As shown in the diagram's first block, rather than having all commands proceed immediately through the pipeline, you can choose to accumulate some of them in a display list for processing later.
The evaluator stage of processing provides an efficient means for approximating curve and surface geometry by evaluating polynomial commands of input values. During the next stage, per-vertex operations and primitive assembly, OpenGL processes geometric primitives
¾
points, line segments, and polygons, all of which are described by vertexes. Vertexes are transformed and lit, and primitives are clipped to the viewport in preparation for the next stage.
Rasterization produces a series of frame buffer addresses and associated values using a two-dimensional description of a point, line segment, or polygon. Each fragment so produced is fed into the last stage, per-fragment operations, which performs the final operations on the data before it's stored as pixels in the frame buffer. These operations include conditional updates to the frame buffer based on incoming and previously stored z-values (for z-buffering) and blending of incoming pixel colors with stored colors, as well as masking and other logical operations on pixel values.
Input data can be in the form of pixels rather than vertexes. Such data, which might describe an image for use in texture mapping, skips the first stage of processing described above and instead is processed as pixels, in the pixel operations stage. The result of this stage is either stored as texture memory, for use in the rasterization stage, or rasterized and the resulting fragments merged into the frame buffer just as if they were generated from geometric data.
All elements of OpenGL state, including the contents of the texture memory and even of the frame buffer, can be obtained by an OpenGL application.


Overview of Commands and Routines
Many OpenGL commands pertain specifically to drawing objects such as points, lines, polygons, and bitmaps. Other commands control the way that some of this drawing occurs (such as those that enable antialiasing or texturing). Still other commands are specifically concerned with frame buffer manipulation. This section describes how all the OpenGL commands work together to create the OpenGL processing pipeline. Brief overviews are also given of the routines comprising the OpenGL Utility Library (GLU).
·
OpenGL Processing Pipeline
 expands on the discussion in
Introduction to OpenGL
 by explaining how specific OpenGL commands control the processing of data.
·
Additional OpenGL Commands
 discusses several sets of OpenGL commands not covered in the previous section.
·
OpenGL Utility Library
 describes the GLU routines that are available.


OpenGL Processing Pipeline
This section takes a closer look at the stages in which data is actually processed, and ties these stages to OpenGL commands. Scroll to the end of this topic to see a more detailed block diagram of the OpenGL processing pipeline.
For most of the pipeline, you can see three vertical arrows between the major stages. These arrows represent vertices and the two primary types of data that can be associated with vertices: color values and texture coordinates. Also note that vertices are assembled into primitives, then to fragments, and finally to pixels in the frame buffer. This progression is discussed in more detail in
Vertices
,
Primitives
,
Fragments
, and
Pixels
.
As you continue reading, be aware that we've taken some liberties with command names. Many OpenGL commands are simple variations of each other, differing mostly in the data type of arguments. Some commands differ in the number of related arguments and whether those arguments can be specified as a vector or whether they must be specified separately in a list. For example, if you use the
glVertex2f
 command, you need to supply
x
 and
y
 coordinates as 32-bit floating-point numbers; with
glVertex3sv
, you must supply an array of three short (16-bit) integer values for
x
,
y
, and
z
. For simplicity, only the base name of the command is used in the topics that follow, and an asterisk is included to indicate that there may be more to the actual command name than is shown. For example,
glVertex
 stands for all variations of the command you use to specify vertices.
Also keep in mind that the effect of an OpenGL command may vary depending on whether certain modes are enabled. For example, you need to enable lighting if the lighting-related commands are to produce a properly lit object. To enable a particular mode, use the
glEnable
 command and supply the appropriate constant to identify the mode (for example, GL_LIGHTING). Refer to
glEnable
 for a complete list of the modes that can be enabled. Modes are disabled with
glDisable
.


Vertices
This topic relates the OpenGL commands that perform per-vertex operations to the processing stages shown in
OpenGL Processing Pipeline
.
Input Data
You must provide several types of input data to the OpenGL pipeline:
·
Vertices
¾
Vertices describe the shape of the desired geometric object. To specify vertices, use
glVertex
 commands in conjunction with
glBegin
 and
glEnd
 to create a point, line, or polygon. You can also use
glRect
 to describe an entire rectangle at once.
·
Edge flag
¾
By default, all edges of polygons are boundary edges. Use the
glEdgeFlag
 command to explicitly set the edge flag.
·
Current raster position
¾
Specified with
glRasterPos
, the current raster position is used to determine raster coordinates for pixel and bitmap drawing operations.
·
Current normal
¾
A normal vector associated with a particular vertex determines how a surface at that vertex is oriented in three-dimensional space; this in turn affects how much light that particular vertex receives. Use
glNormal
 to specify a normal vector.
·
Current color
¾
The color of a vertex, together with the lighting conditions, determine the final, lit color. Color is specified with
glColor
 if in RGBA mode or with
glIndex
 if in color index mode.
·
Current texture coordinates
¾
Specified with
glTexCoord
, texture coordinates determine the location in a texture map that should be associated with a vertex of an object.
·
When
glVertex
 is called, the resulting vertex inherits the current edge flag, normal, color, and texture coordinates. Therefore,
glEdgeFlag
,
glNormal
,
glColor
, and
glTexCoord
 must be called before
glVertex
 if they are to affect the resulting vertex.


Matrix Transformations
Vertices and normals are transformed by the modelview and projection matrices before they're used to produce an image in the frame buffer. You can use commands such as
glMatrixMode
,
glMultMatrix
,
glRotate
,
glTranslate
, and
glScale
 to compose the desired transformations, or you can directly specify matrices with
glLoadMatrix
 and
glLoadIdentity
. Use
glPushMatrix
 and
glPopMatrix
 to save and restore modelview and projection matrices on their respective stacks.


Lighting and Coloring
In addition to specifying colors and normal vectors, you may define the desired lighting conditions with
glLight
 and
glLightModel
, and the desired material properties with
glMaterial
. Related commands for controlling how lighting calculations are performed include
glShadeModel
,
glFrontFace
, and
glColorMaterial
.


Generating Texture Coordinates
Rather than explicitly supplying texture coordinates, you can have OpenGL generate them as a function of other vertex data. This is what the
glTexGen
 command does. After the texture coordinates have been specified or generated, they are transformed by the texture matrix. This matrix is controlled with the same commands for matrix transformations.


Primitive Assembly
Once all necessary calculations have been performed, vertices are assembled into
primitives
¾
points, line segments, or polygons
¾
together with the relevant edge flag, color, and texture information for each vertex.


Primitives
Primitives are converted to pixel fragments in several steps: primitives are clipped appropriately, whatever corresponding adjustments are necessary are made to the color and texture data, and the relevant coordinates are transformed to window coordinates. Finally, rasterization converts the clipped primitives to pixel fragments.


Clipping
Points, line segments, and polygons are handled slightly differently during clipping. Points are either retained in their original state (if they're inside the clip volume) or discarded (if they're outside). If portions of line segments or polygons are outside the clip volume, new vertices are generated at the clip points. For polygons, an entire edge may need to be constructed between such new vertices. For both line segments and polygons that are clipped, the edge flag, color, and texture information is assigned to all new vertices.
Clipping actually happens in two steps:
1.
Application-specific clipping
¾
Immediately after primitives are assembled, they're clipped in eye coordinates as necessary for any arbitrary clipping planes you've defined for your application with
glClipPlane
. (OpenGL requires support for at least six such application-specific clipping planes.)
2.
View volume clipping
¾
Next, primitives are transformed by the projection matrix (into clip coordinates) and clipped by the corresponding viewing volume. This matrix can be controlled by the previously mentioned matrix transformation commands but is most typically specified by
glFrustum
 or
glOrtho
.


Transforming to Window Coordinates
Before clip coordinates can be converted to window coordinates, they are normalized by dividing by the value of
w
 to yield normalized device coordinates. After that, the viewport transformation applied to these normalized coordinates produces window coordinates. You control the viewport, which determines the area of the on-screen window that displays an image, with
glDepthRange
 and
glViewport
.


Rasterization
Rasterization is the process by which a primitive is converted to a two-dimensional image. Each point of this image contains such information as color, depth, and texture data. Together, a point and its associated information are called a fragment. The current raster position (as specified with
glRasterPos
) is used in various ways during this stage for pixel drawing and bitmaps. As discussed below, different issues arise when rasterizing the three different types of primitives. In addition, pixel rectangles and bitmaps need to be rasterized.
Primitives. Control how primitives are rasterized with commands that allow you to choose dimensions and stipple patterns:
glPointSize
,
glLineWidth
,
glLineStipple
, and
glPolygonStipple
. In addition, you can control how the front and back faces of polygons are rasterized with
glCullFace
,
glFrontFace
, and
glPolygonMode
.
Pixels. Several commands control pixel storage and transfer modes. The command
glPixelStore
 controls the encoding of pixels in client memory, and
glPixelTransfer
 and
glPixelMap
 control how pixels are processed before being placed in the frame buffer. A pixel rectangle is specified with
glDrawPixels
; its rasterization is controlled with
glPixelZoom
.
Bitmaps. Bitmaps are rectangles of zeros and ones specifying a particular pattern of fragments to be produced. Each of these fragments has the same associated data. A bitmap is specified using
glBitmap
.
Texture Memory. Texturing maps a portion of a specified texture image onto each primitive when texturing is enabled. This mapping is accomplished by using the color of the texture image at the location indicated by a fragment's texture coordinates to modify the fragment's RGBA color. A texture image is specified using
glTexImage2D
 or
glTexImage1D
. The commands
glTexParameter
 and
glTexEnv
 control how texture values are interpreted and applied to a fragment.
Fog. You can have OpenGL blend a fog color with a rasterized fragment's post-texturing color using a blending factor that depends on the distance between the eyepoint and the fragment. Use
glFog
 to specify the fog color and blending factor.


Fragments
OpenGL allows a fragment produced by rasterization to modify the corresponding pixel in the frame buffer only if it passes a series of tests. If it does pass, the fragment's data can be used directly to replace the existing frame buffer values, or it can be combined with existing data in the frame buffer, depending on the state of certain modes.


Pixel Ownership Test
The first test is to determine whether the pixel in the frame buffer corresponding to a particular fragment is owned by the current OpenGL context. If so, the fragment proceeds to the next test. If not, the window system determines whether the fragment is discarded or whether any further fragment operations will be performed with that fragment. This test allows the window system to control OpenGL's behavior when, for example, an OpenGL window is obscured.


Scissor Test
With the
glScissor
 command, you can specify an arbitrary screen-aligned rectangle outside of which fragments will be discarded.


Alpha Test
The alpha test (which is performed only in RGBA mode) discards a fragment depending on the outcome of a comparison between the fragment's alpha value and a constant reference value. The comparison command and reference value are specified with
glAlphaFunc
.


Stencil Test
The stencil test conditionally discards a fragment based on the outcome of a comparison between the value in the stencil buffer and a reference value. The command
glStencilFunc
 specifies the comparison command and the reference value. Whether the fragment passes or fails the stencil test, the value in the stencil buffer is modified according to the instructions specified with
glStencilOp
.


Depth Buffer Test
The depth buffer test discards a fragment if a depth comparison fails;
glDepthFunc
 specifies the comparison command. The result of the depth comparison also affects the stencil buffer update value if stenciling is enabled.


Blending
Blending combines a fragment's R, G, B, and A values with those stored in the frame buffer at the corresponding location. The blending, which is performed only in RGBA mode, depends on the alpha value of the fragment and that of the corresponding currently stored pixel; it might also depend on the RGB values. You control blending with
glBlendFunc
, which allows you to indicate the source and destination blending factors.


Dithering
If dithering is enabled, a dithering algorithm is applied to the fragment's color or color index value. This algorithm depends only on the fragment's value and its
x
 and
y
 window coordinates.


Logical Operations
Finally, a logical operation can be applied between the fragment and the value stored at the corresponding location in the frame buffer; the result replaces the current frame buffer value. You choose the desired logical operation with
glLogicOp
. Logical operations are performed only on color indices, never on RGBA values.


Pixels
During the previous stage of the OpenGL pipeline, fragments are converted to pixels in the frame buffer. The frame buffer is actually organized into a set of logical buffers
¾
the color, depth, stencil, and accumulation buffers. The color buffer itself consists of a front left, front right, back left, back right, and some number of auxiliary buffers. You can issue commands to control these buffers, and you can directly read or copy pixels from them. (Note that the particular OpenGL context you're using may not provide all of these buffers.)


Frame Buffer Operations
You can select into which buffer color values are written with
glDrawBuffer
. In addition, four different commands are used to mask the writing of bits to each of the logical frame buffers after all per-fragment operations have been performed:
glIndexMask
,
glColorMask
,
glDepthMask
, and
glStencilMask
. The operation of the accumulation buffer is controlled with
glAccum
. Finally,
glClear
 sets every pixel in a specified subset of the buffers to the value specified with
glClearColor
,
glClearIndex
,
glClearDepth
,
glClearStencil
, or
glClearAccum
.


Reading or Copying Pixels
You can read pixels from the frame buffer into memory, encode them in various ways, and store the encoded result in memory with
glReadPixels
. In addition, you can copy a rectangle of pixel values from one region of the frame buffer to another with
glCopyPixels
. The command
glReadBuffer
 controls from which color buffer the pixels are read or copied.


Additional OpenGL Commands
The following topics briefly describe special groups of commands that weren't explicitly shown as part of OpenGL's processing pipeline. These commands accomplish such diverse tasks as evaluating polynomials, using display lists, and obtaining the values of OpenGL state variables.
Using Evaluators
Performing Selection and Feedback
Using Display Lists
Managing Modes and Execution
Obtaining State Information


Using Evaluators
OpenGL's evaluator commands allow you to use a polynomial mapping to produce vertices, normals, texture coordinates, and colors. These calculated values are then passed on to the pipeline as if they had been directly specified. The evaluator facility is also the basis for the NURBS (Non-Uniform Rational B-Spline) commands, which allow you to define curves and surfaces, as described in
OpenGL Utility Library
.
The first step involved in using evaluators is to define the appropriate one- or two-dimensional polynomial mapping using
glMap
. The domain values for this map can then be specified and evaluated in one of two ways:
·
By defining a series of evenly spaced domain values to be mapped using
glMapGrid
 and then evaluating a rectangular subset of that grid with
glEvalMesh
. A single point of the grid can be evaluated using
glEvalPoint
.
·
By explicitly specifying a desired domain value as an argument to
glEvalCoord
, which evaluates the maps at that value.


Performing Selection and Feedback
Selection, feedback, and rendering are mutually exclusive modes of operation. Rendering is the normal, default mode during which fragments are produced by rasterization; in selection and feedback modes, no fragments are produced and therefore no frame buffer modification occurs. In selection mode, you can determine which primitives would be drawn into some region of a window; in feedback mode, information about primitives that would be rasterized is fed back to the application. You select among these three modes with
glRenderMode
.


Selection
Selection works by returning the current contents of the name stack, which is an array of integer-valued names. You assign the names and build the name stack within the modeling code that specifies the geometry of objects you want to draw. Then, in selection mode, whenever a primitive intersects the clip volume, a selection hit occurs. The hit record, which is written into the selection array you've supplied with
glSelectBuffer
, contains information about the contents of the name stack at the time of the hit. (Note that
glSelectBuffer
 needs to be called before OpenGL is put into selection mode with
glRenderMode
. Also, the entire contents of the name stack isn't guaranteed to be returned until
glRenderMode
 is called to take OpenGL out of selection mode.) You manipulate the name stack with
glInitNames
,
glLoadName
,
glPushName
, and
glPopName
. In addition, you might want to use an OpenGL Utility Library routine for selection,
gluPickMatrix
, which is described in
OpenGL Utility Library
.


Feedback
In feedback mode, each primitive that would be rasterized generates a block of values that is copied into the feedback array. You supply this array with
glFeedbackBuffer
, which must be called before OpenGL is put into feedback mode. Each block of values begins with a code indicating the primitive type, followed by values that describe the primitive's vertices and associated data. Entries are also written for bitmaps and pixel rectangles. Values are not guaranteed to be written into the feedback array until
glRenderMode
 is called to take OpenGL out of feedback mode. You can use
glPassThrough
 to supply a marker that's returned in feedback mode as if it were a primitive.


Using Display Lists
A display list is simply a group of OpenGL commands that has been stored for subsequent execution. The
glNewList
 command begins the creation of a display list, and
glEndList
 ends it. With few exceptions, OpenGL commands called between
glNewList
 and
glEndList
 are appended to the display list, and optionally executed as well. (
glNewList
 lists the commands that can't be stored and executed from within a display list.) To trigger the execution of a list or set of lists, use
glCallList
 or
glCallLists
 and supply the identifying number of a particular list or lists. You can manage the indices used to identify display lists with
glGenLists
,
glListBase
, and
glIsList
. Finally, you can delete a set of display lists with
glDeleteLists
.


Managing Modes and Execution
The effect of many OpenGL commands depends on whether a particular mode is in effect. You use
glEnable
 and
glDisable
 to set such modes and
glIsEnabled
 to determine whether a particular mode is set.
You can control the execution of previously issued OpenGL commands with
glFinish
, which forces all such commands to complete, or
glFlush
, which ensures that all such commands will be completed in a finite time.
A particular implementation of OpenGL may allow certain behaviors to be controlled with hints, by using the
glHint
 command. Possible behaviors are the quality of color and texture coordinate interpolation, the accuracy of fog calculations, and the sampling quality of antialiased points, lines, or polygons.


Obtaining State Information
OpenGL maintains many state variables that affect the behavior of many commands. Some of these variables have specialized query commands:
glGetLight
glGetTexEnv
glGetTexParameter
glGetMaterial
glGetTexGen
glGetMap
glGetClipPlane
glGetTexImage
glGetPixelMap
glGetPolygonStipple
glGetTexLevelParameter
The value of other state variables can be obtained with
glGetBooleanv
,
glGetDoublev
,
glGetFloatv
, or
glGetIntegerv
, as appropriate. See
glGet
 for information about how to use these commands. Other query commands you might want to use are
glGetError
,
glGetString
, and
glIsEnabled
. (See
Handling Errors
 for more information about routines related to error handling.) Finally, you can save and restore sets of state variables with
glPushAttrib
 and
glPopAttrib
.


OpenGL Utility Library
The OpenGL Utility Library (GLU) contains several groups of commands that complement the core OpenGL interface by providing support for auxiliary features. These utility routines make use of core OpenGL commands, so any OpenGL implementation is guaranteed to support the utility routines. Note that the prefix for Utility Library routines is "glu" rather than "gl."


Manipulating Images for Use in Texturing
The OpenGL Utility Library (GLU) provides image scaling and automatic mipmapping routines to simplify the specification of texture images. The routine
gluScaleImage
 scales a specified image to an accepted texture size; the resulting image can then be passed to OpenGL as a texture. The automatic mipmapping routines
gluBuild1DMipmaps
 and
gluBuild2DMipmaps
 create mipmapped texture images from a specified image and pass them to
glTexImage1D
 and
glTexImage2D
, respectively.


Transforming Coordinates
The OpenGL Utility Library (GLU) provides several commonly used matrix transformation routines. You can set up a two-dimensional orthographic viewing region with
gluOrtho2D
, a perspective viewing volume using
gluPerspective
, or a viewing volume that is centered on a specified eyepoint with
gluLookAt
. Each of these routines creates the desired matrix and applies it to the current matrix using
glMultMatrix
.
The
gluPickMatrix
 routine simplifies selection by creating a matrix that restricts drawing to a small region of the viewport. If you rerender the scene in selection mode after this matrix has been applied, all objects that would be drawn near the cursor will be selected, and information about them will be stored in the selection buffer. See
Performing Selection and Feedback
 for more information about selection mode.
To determine where in the window an object is being drawn, use the
gluProject
 function, which converts specified coordinates from object coordinates to window coordinates. The
gluUnProject
 function performs the inverse conversion.


Polygon Tessellation
The polygon tessellation routines triangulate a concave polygon with one or more contours. To use this GLU feature, first create a tessellation object with
gluNewTess
, and define callback routines that will be used to process the triangles generated by the tessellator (with
gluTessCallBack
). Then use
gluBeginPolygon
,
gluTessVertex
,
gluNextContour
, and
gluEndPolygon
 to specify the concave polygon to be tessellated. Unneeded tessellation objects can be destroyed with
gluDeleteTess
.


Rendering Simple Surfaces
You can render spheres, cylinders, and disks using the GLU quadric routines. To do this, create a quadric object with
gluNewQuadric
. (To destroy this object when you're finished with it, use
gluDeleteQuadric
.) Then specify the desired rendering style, as listed below, with the appropriate routine (unless you're satisfied with the default values):
·
Whether surface normals should be generated, and if so, whether there should be one normal per vertex or one normal per face:
gluQuadricNormals
·
Whether texture coodinates should be generated:
gluQuadricTexture
·
Which side of the quadric should be considered the outside and which the inside:
gluQuadricOrientation
·
Whether the quadric should be drawn as a set of polygons, lines, or points:
gluQuadricDrawStyle
After you've specified the rendering style, simply invoke the rendering routine for the desired type of quadric object:
gluSphere
,
gluCylinder
,
gluDisk
, or
gluPartialDisk
. If an error occurs during rendering, the error-handling routine you've specified with
gluQuadricCallBack
 is invoked.


NURBS Curves and Surfaces
Non-Uniform Rational B-Spline (NURBS) curves and surfaces are converted to OpenGL evaluators by the routines described in this section. You can create and delete a NURBS object with
gluNewNurbsRenderer
 and
gluDeleteNurbsRenderer
, and establish an error-handling routine with
gluNurbsCallback
.
You specify the desired curves and surfaces with different sets of routines
¾
gluBeginCurve
,
gluNurbsCurve
, and
gluEndCurve
 for curves or
gluBeginSurface
,
gluNurbsSurface
, and
gluEndSurface
 for surfaces. You can also specify a trimming region, which defines a subset of the NURBS surface domain to be evaluated, thereby allowing you to create surfaces that have smooth boundaries or that contain holes. The trimming routines are
gluBeginTrim
,
gluPwlCurve
,
gluNurbsCurve
, and
gluEndTrim
.
As with quadric objects, you can control how NURBS curves and surfaces are rendered:
·
Whether a curve or surface should be discarded if its control polyhedron lies outside the current viewport
·
What the maximum length should be (in pixels) of edges of polygons used to render curves and surfaces
·
Whether the projection matrix, modelview matrix, and viewport should be taken from the OpenGL server or whether you'll supply them explictly with
gluLoadSamplingMatrices
.
Use
gluNurbsProperty
 to set these properties, or use the default values. You can query a NURBS object about its rendering style with
gluGetNurbsProperty
.


Handling Errors
The routine
gluErrorString
 is provided for retrieving an error string that corresponds to an OpenGL or GLU error code. The currently defined OpenGL error codes are described in
glGetError
. The GLU error codes are listed in
gluErrorString
,
gluTessCallback
,
gluQuadricCallback
, and
gluNurbsCallback
.


OpenGL on Windows NT
The Microsoft
®
 implementation of OpenGL
™
 in Windows NT
™
 is an implementation of the industry-standard OpenGL three-dimensional (3D) graphics software interface that lets programmers create high-quality still and animated 3D color images. This overview describes the Windows NT implementation of OpenGL.


About OpenGL
OpenGL, originally developed by Silicon Graphics Incorporated (SGI) for their graphics workstations, lets applications create high-quality color images independent of windowing systems, operating systems, and hardware.
The OpenGL Architecture Review Board (ARB), an industry consortium, is currently responsible for defining OpenGL. Members of the ARB include Silicon Graphics Incorporated, Microsoft Corporation, Intel, IBM, and Digital Equipment Corporation.
The official reference document for OpenGL, version 1, is the
OpenGL Reference Manual
, by the OpenGL Architecture Review Board (ISBN 0-201-63276-4). The official guide to learning OpenGL, version 1, is the
OpenGL Programming Guide
, by Jackie Neider, Tom Davis, and Mason Woo (ISBN 0-201-63274-8). Both books are published by Addison-Wesley.


OpenGL in Windows NT
With Microsoft's implementation of OpenGL in Windows NT, application developers can use OpenGL in Windows NT applications, and existing applications that use OpenGL can be ported to Windows NT.


Components
Microsoft's implementation of OpenGL in Windows NT includes the following components:
·
the full set of current OpenGL commands
The core of OpenGL, this library contains 115 distinct functions for 3D graphics operations. These basic functions deal with such things as object shape description, matrix transformation, lighting, coloring, texture, clipping, bitmaps, fog, and anti-aliasing. The names for these core functions have a "gl" prefix.
Many of the 115 distinct OpenGL commands have several variants. The variants differ in the number and type of their parameters. Counting all the variants, there are more than 300 OpenGL commands.
·
the OpenGL Utility (GLU) library
This is a library of 43 auxiliary functions that complement the core OpenGL functions. The commands deal with texture support, coordinate transformation, polygon tessellation, rendering spheres, cylinders and disks, NURBS (Non-Uniform Rational B-Spline) curves and surfaces, and error handling.
·
the OpenGL Programming Guide Auxiliary Library
This is a simple, platform-independent library of 31 functions for managing windows, handling input events, drawing classic 3D objects, managing a background process, and running a program. The window management and input routines provide a base level of functionality that let you quickly get started programming in OpenGL, but they should not be used in a production application. Here are some reasons for this warning:
·
The message loop is in the library code.
·
There is no way to add handlers for additional WM* messages.
·
There is very little support for logical palettes.
The library is described and used in the
OpenGL Programming Guide
.
·
the WGL APIs
This is a set of nine functions that connects OpenGL to the Windows NT windowing system. The functions manage rendering contexts, display lists, extension functions, and font bitmaps. The WGL functions are analogous to the GLX extensions that connect OpenGL to the X-Windows windowing system. The names for these functions have a "wgl" prefix.
·
new Win32 APIs for pixel formats and double buffering
This is a set of five functions that support per-window pixel formats and double buffering (for smooth image changes) of windows. These new functions apply only to OpenGL graphics windows.


Generic Implementation and Hardware Implementations
This overview discusses the current generic implementation of OpenGL in Windows NT. The generic implementation is the Microsoft Windows NT software implementation of OpenGL. Hardware manufacturers may enhance parts of OpenGL in their drivers, and may support some features not supported by the generic implementation.


Limitations
The generic implementation has some limitations:
·
Printing.
An application cannot print an OpenGL image directly to a monochrome printer. There is, however, a workaround for this situation: see
Printing an OpenGL Image
. An application can print an OpenGL image directly to a color printer that offers four or more bits of color information per pixel.
·
OpenGL and GDI graphics cannot be mixed in a double-buffered window.
An application can draw both OpenGL graphics and GDI graphics directly into a single-buffered window, but not into a double-buffered window.
·
There are no per-window hardware color palettes.
Windows NT has a single system hardware color palette, which applies to the whole screen. An OpenGL window cannot have its own hardware palette. It can have its own logical palette. To do so, it must become a palette-aware application. For more information, see
OpenGL Color Modes and Windows Palette Management
.
·
There is no direct support for the Clipboard, DDE, metafiles, or OLE.
A window with OpenGL graphics does not directly support these Windows NT capabilities. There are workarounds, however, for working with the Clipboard; see
Copying an OpenGL Image to the Clipboard
.
·
The Inventor 2.0 C++ class library is not included.
The Inventor class library, built on top of OpenGL, provides higher-level constructs for programming 3D graphics. It is not included in the current version of Microsoft's implementation of OpenGL for Windows NT.
·
There is no support for several pixel format features: overlay and underlay layers, stereoscopic images, alpha bitplanes, and auxiliary buffers.
There is, however, support for several ancillary buffers: stencil buffer, accumulation buffer, back buffer (double buffering), and depth (z-axis) buffer.


Guide To Documentation
There are five elements in the documentation set for OpenGL in Windows NT.
The first two elements are the official OpenGL books previously mentioned: the
OpenGL Reference Manual
 and the
OpenGL Programming Guide
. Due to the dominant colors of their covers, these books are known respectively as "the Blue book" and "the Red book."
Note
OpenGL Reference Manual
 and the
OpenGL Programming Guide
 are not included with the Win32 SDK.
The
OpenGL Reference Manual
, the Blue book, includes an overview of how OpenGL works and a set of detailed reference pages. The reference pages cover all of the 115 distinct OpenGL functions, as well as the 43 functions in the OpenGL Utility (GLU) library.
The
OpenGL Programming Guide
, the Red book, explains how to create graphics programs using OpenGL. It includes discussions of the following major topics:
·
drawing geometric shapes
·
pixels, bitmaps, fonts, and images
·
viewing and matrix transformations
·
texture mapping
·
display lists
·
advanced composite techniques
·
color
·
evaluators and NURBS
·
lighting
·
selection and feedback
·
blending, anti-aliasing, and fog
·
advanced techniques
In addition, the
OpenGL Programming Guide
 contains appendixes that discuss the OpenGL Utility Library and the OpenGL Programming Guide Auxiliary Library.
The third documentation element is this overview chapter. It describes the Windows NT implementation of OpenGL and provides an overview of its components. It discusses several important concepts: rendering contexts, pixel formats, and buffers. It discusses the six new WGL APIs that connect OpenGL to the Windows NT windowing system, and the five new Win32 APIs that support per-window pixel formats and double buffering of windows for OpenGL graphics windows. The six WGL APIs and the five new Win32 APIs are specific to the Windows NT implementation of OpenGL.
The fourth documentation element is the set of reference pages for the six WGL APIs, the five new Win32 APIs just mentioned, and the
PIXELFORMATDESCRIPTOR
 data structure.
The fifth documentation element is
Porting to OpenGL
. It discusses moving existing OpenGL code from other environments into Windows NT.


Rendering Contexts
An
OpenGL rendering context
 is a port through which all OpenGL commands pass. Every thread that makes OpenGL calls needs to have a current rendering context. Rendering contexts link OpenGL to the Windows NT windowing system.
An application specifies a Windows device context when it creates a rendering context. The rendering context created is suitable for drawing on the device that the specified device context references. In particular, the rendering context has the same pixel format as the device context. For more information, see
Rendering Context Functions
. Despite this relationship, a rendering context is not the same as a device context. A device context contains information pertinent to the graphics component of Windows, GDI. A rendering context contains information pertinent to OpenGL. A device context must be explicitly specified in a GDI call. A rendering context is implicit in an OpenGL call. An application should set a device context's pixel format before creating a rendering context.
A thread that makes OpenGL calls must have a current rendering context. If an application makes OpenGL calls from a thread that lacks a current rendering context, nothing happens; the call has no effect. An application commonly creates a rendering context, sets it as a thread's current rendering context, then calls OpenGL functions. When it finishes calling OpenGL functions, the application uncouples the rendering context from the thread, and then deletes the rendering context. An application can use multiple rendering contexts drawing to the same window, but a thread can have one current, active rendering context.
A current rendering context has an associated device context. That device context need not be the same device context as that used when the rendering context was created, but it must reference the same device and have the same pixel format.
A thread can have only one current rendering context. A rendering context can be current to only one thread.


Rendering Context Functions
Five WGL functions manage rendering contexts:
WGL Function
Description
wglCreateContext
Creates a new rendering context.
wglMakeCurrent
Sets a thread's current rendering context.
wglGetCurrentContext
Obtains a handle to a thread's current rendering context.
wglGetCurrentDC
Obtains a handle to the device context associated with a thread's current rendering context.
wglDeleteContext
Deletes a rendering context.
An application creates a rendering context by calling
wglCreateContext
. The
wglCreateContext
 function takes a device context handle as its parameter and returns a rendering context handle. The created rendering context is suitable for drawing on the device referenced by the device context handle. In particular, its pixel format is the same as the device context's pixel format. After the rendering context is created, an application can release or dispose of the device context. See the
Device Contexts
 overview for more details on creating, obtaining, releasing, and disposing of a device context. One important note: the device context sent to
wglCreateContext
must be a display device context, a memory device context, or a color printer device context that uses four or more bits per pixel. The device context cannot be a monochrome printer device context.
An application gives a thread a current rendering context by calling
wglMakeCurrent
. The
wglMakeCurrent
 function takes a rendering context handle and a device context handle as parameters. All subsequent OpenGL calls made by the thread are made through that rendering context, and are drawn on the device referenced by that device context. The device context does not have to be the same one passed to
wglCreateContext
 when the rendering context was created, but it must be on the same device and have the same pixel format. The call to
wglMakeCurrent
 creates an association between the supplied rendering context and device context. An application cannot release or dispose of the device context associated with a current rendering context until the rendering context is made not current.
Once a thread has a current rendering context, it can make OpenGL graphics calls. All calls must pass through a rendering context. Nothing happens if an application makes OpenGL graphics calls from a thread that lacks a current rendering context.
An application obtains a handle to a thread's current rendering context by calling
wglGetCurrentContext
. The
wglGetCurrentContext
 function takes no parameters, and returns a handle to the calling thread's current rendering context. If the thread has no current rendering context, the return value is NULL.
An application obtains a handle to the device context associated with a thread's current rendering context by calling
wglGetCurrentDC
. As noted above, such associations are created when a rendering context is made current.
There are two ways for an application to break the association between a current rendering context and a thread: calling
wglMakeCurrent
 with a null rendering context handle, and calling
wglMakeCurrent
 with a handle other than the one originally called.
After calling
wglMakeCurrent
 with the rendering context handle parameter set to NULL, the calling thread has no current rendering context. The rendering context is released from its connection to the thread, and the rendering context's association to a device context ends. OpenGL flushes all drawing commands, and may release some resources. No OpenGL drawing will be done until the next call to
wglMakeCurrent
, since the thread can make no OpenGL graphics calls until it regains a current rendering context.
The second way an application can break the association between a rendering context and a thread is to call
wglMakeCurrent
 with a different rendering context. After such a call, the calling thread has a new current rendering context, the former current rendering context is released from its connection to the thread, and the former current rendering context's association to a device context ends.
An application deletes a rendering context by calling
wglDeleteContext
. The
wglDeleteContext
 function takes a single parameter, the handle to the rendering context to be deleted. Before calling
wglDeleteContext
an application should make the rendering context not current by calling
wglMakeCurrent
, and delete or release the associated device context by calling
DeleteDC
or
ReleaseDC
as appropriate.
It is an error for a thread to delete a rendering context that is another thread's current rendering context. However, if a rendering context is the calling thread's current rendering context,
wglDeleteContext
 will flush all OpenGL drawing commands and make the rendering context not current before deleting it. In this case, relying on
wglDeleteContext
 to make a rendering context not current, it is the programmer's responsibility to delete or release the associated device context.


Pixel Formats
A
pixel format
 specifies several properties of an OpenGL drawing surface. Some of the properties specified by a pixel format are:
·
whether the pixel buffer is single- or double-buffered
·
whether the pixel data is in RGBA or color-indexed form
·
the number of bits used to store color data
·
the number of bits used for the depth (z-axis) buffer
·
the number of bits used for the stencil buffer
·
various visibility masks
Microsoft's implementation of OpenGL for Windows NT uses the
PIXELFORMATDESCRIPTOR
 data structure to convey pixel format data. The structure's members specify the preceding properties and several others.
A given device context can support several pixel formats. Windows NT identifies the pixel formats that a device context supports with consecutive one-based index values (1, 2, 3, 4, and so on). A device context can have just one current pixel format, chosen from the set of pixel formats it supports.
Each window has its own current pixel format in OpenGL in WIndows NT. This means, for example, that an application can simultaneously display RGBA and color-indexed OpenGL windows, or single- and double-buffer OpenGL windows. This per-window pixel format capability is limited to OpenGL windows.
An application typically obtains a device context, sets the device context's pixel format, and then creates an OpenGL rendering context suitable for that device. Notice that the pixel format is set before creating a rendering context. The rendering context inherits the device context's pixel format.


Pixel Format Functions
Four new Win32 functions manage pixel formats:
Win32 Function
Description
ChoosePixelFormat
Obtains a device context's pixel format that is the closest match to a specified pixel format.
SetPixelFormat
Sets a device context's current pixel format to the pixel format specified by a pixel format index.
GetPixelFormat
Obtains the pixel format index of a device context's current pixel format.
DescribePixelFormat
Given a device context and a pixel format index, fills in a PIXELFORMATDESCRIPTOR data structure with the pixel format's properties.
An application calls the
ChoosePixelFormat
 function to obtain a device context's best match to a specified pixel format. The
ChoosePixelFormat
 function returns a one-based pixel format index that identifies the best match from the device context's supported pixel formats.
An application sets a specified device context's current pixel format by calling the
SetPixelFormat
 function. The
SetPixelFormat
 function identifies the desired format using a one-based pixel format index. Typically, an application calls
ChoosePixelFormat
 to find a best-match pixel format, then calls
SetPixelFormat
 with the result of
ChoosePixelFormat
.
If
SetPixelFormat
is called for a device context that references a window, the function also changes the pixel format of the window. Setting the pixel format of a window more than once can lead to significant complications for the window manager and for multi-threaded applications, so it is not allowed. An application can set the pixel format of a window only one time. Once a window's pixel format is set, it cannot be changed.
An application obtains a device context's current pixel format by calling the
GetPixelFormat
 function. The
GetPixelFormat
function returns a one-based pixel format index.
An application obtains pixel format data by calling the
DescribePixelFormat
 function. The
DescribePixelFormat
 function takes a handle to a device context, a pixel format index, and a pointer to a
PIXELFORMATDESCRIPTOR
 data structure as parameters, and returns with the members of
PIXELFORMATDESCRIPTOR
 appropriately set.


Front, Back, and Other Buffers
OpenGL stores and manipulates pixel data in a frame buffer. The frame buffer consists of a set of logical buffers: color, depth, accumulation, and stencil buffers. The color buffer itself consists of a set of logical buffers; this set can include a front left, a front right, a back left, a back right, and some number of auxiliary buffers. A particular pixel format or OpenGL implementation may not supply all of these buffers. For example, the current version of Microsoft's implementation of OpenGL in Windows NT does not support stereoscopic images, and so a pixel format cannot have left and right color buffers. In addition, the current version does not support auxiliary buffers. Refer to the Red and Blue books for further details on OpenGL buffers and the OpenGL functions that operate on them.
Microsoft's implementation of OpenGL in Windows NT supports double buffering of images. This is a technique in which an application draws pixels to an off-screen buffer, and then, when that image is ready for display, the application copies the contents of the off-screen buffer to an on-screen buffer. Double buffering enables smooth image changes, which are especially important for animated images.
Two color buffers are available to applications that use double buffering: a front buffer and a back buffer. By default, drawing commands are directed to the back buffer, while the front buffer is displayed on the screen. When the off-screen buffer is ready for display, an application calls
SwapBuffers
, and Windows NT copies the contents of the off-screen buffer to the on-screen buffer.
The generic implementation uses a device-independent bitmap (DIB) as a back buffer and the screen display as a front buffer. Hardware devices and their drivers may use different approaches.
Double buffering is a pixel format property. An application requests double buffering for a pixel format by setting the PFD_DOUBLEBUFFER flag in the
PIXELFORMATDESCRIPTOR
 data structure in a call to
ChoosePixelFormat
.
The OpenGL core function
glDrawBuffer
 selects buffers for writing and clearing.


Buffer Functions
One new Win32 function manages buffers:
Win32 Function
Description
SwapBuffers
Copies the contents of the off-screen buffer to the on-screen buffer if the current pixel format for the specified device context includes a back buffer. By default, the back buffer is off-screen, and the front buffer is on-screen. After the operation, the contents of the off-screen buffer are undefined.
An application copies the contents of an off-screen buffer to an on-screen buffer by  calling the
SwapBuffers
 function. The
SwapBuffers
 function takes a handle to a device context. The current pixel format for the specified device context must include a back buffer.
Notice carefully that the
SwapBuffers
 function does not really swap the contents of the two buffers, but rather copies the contents of one buffer to another. The contents of the off-screen buffer are undefined after calling this function. Thus, the result of two consecutive calls to
SwapBuffers
is undefined. The following illustrates this situation:
Several OpenGL core functions also deal with buffers. The
glDrawBuffer
 function previously mentioned is the one most relevant to double buffering; it specifies the frame buffer(s) that OpenGL draws into. In addition, there are these functions:
glReadBuffer
,
glReadPixels
,
glCopyPixels
,
glAccum
,
glColorMask
,
glDepthMask
,
glIndexMask
,
glStencilMask
, and
glClearAccum
,
glClearColor
,
glClearDepth
,
glClearIndex
,
 and
glClearStencil
.


Fonts and Text
Microsoft's implementation of OpenGL in Windows NT supports GDI graphics in a single-buffered OpenGL window. It does not support GDI graphics in a double-buffered OpenGL window. Thus, an application can call only the standard GDI font and text functions to draw text in a single-buffered OpenGL window; it cannot call those functions to draw text in a double-buffered OpenGL window.
There is a workaround for this restriction on text in double-buffered windows. An application can build OpenGL display lists for bitmap images of characters, and then execute those display lists to draw characters. There are three main steps in this process:
·
Select a font for a device context, setting the font's properties as desired.
·
Create a set of bitmap display lists based on the glyphs in the device context's font, one display list for each glyph that the application will draw.
·
Draw each glyph in a string, using those bitmap display lists.
An application calls the
wglUseFontBitmaps
and
wglUseFontOutlines
 functions to create the display lists, and uses
glCallLists
 to draw characters in a string using those display lists. .
To create applications that are easy to localize and that use resources sparingly, a programmer must carefully manage the creation and storage of these glyph image display lists. Many languages, unlike English, have alphabets whose character codes range over a relatively large set of values.


Font and Text Functions
Two WGL functions deal with fonts and text:
Win32 Function
Description
wglUseFontBitmaps
Creates a set of character bitmap display lists. Characters come from a specified device context's current font. Characters are specified as a consecutive run within the font's glyph set.
wglUseFontOutlines
Creates a set of display lists based on the glyphs of the currently selected outline font of a device context for use with the current rendering context. The display lists are used to draw 3D characters of TrueType fonts.
An application creates a set of character bitmap display lists by calling the
wglUseFontBitmaps
function or the
wglUseFontOutlines
 function. These functions take a handle to a device context, and use that device context's current font as a source for the bitmaps. Thus, an application should set the device context's font and the font's properties before calling
wglUseFontBitmaps
 or
wglUseFontOutlines
.
The
wglUseFontBitmaps
 and
wglUseFontOutlines
functions also take a parameter that turns the first glyph in the font into a bitmap display list, and a parameter that specifies how many glyphs to turn into display lists. The function then creates display lists for the specified consecutive run of glyphs. For example:
·
An application can set these two parameters to 32 and 224, respectively, to create a set of 224 bitmap display lists for all of the Windows character set glyphs.
·
An application can set these two parameters to 0 and 256, respectively, to create a set of 256 bitmap display lists for all of the OEM character set glyphs.
·
An application can set the second of these parameters to 1 to create a single bitmap display list for any single character set glyph.
The
wglUseFontBitmaps
 and
wglUseFontOutlines
functions represent a null glyph in a font with an empty display list.
The display lists created by a call to
wglUseFontBitmaps
 or
wglUseFontOutlines
are automatically numbered consecutively.
After calling
wglUseFontBitmaps
 or
wglUseFontOutlines
, an application calls the
glCallLists
 function to draw a string of characters. See
Drawing Text in a Double-Buffered OpenGL Window
 for some sample code. In this context, the
glCallLists
 function uses each character in a string as an index into the array of consecutively numbered display lists created by calling
wglUseFontBitmaps
 or
wglUseFontOutlines
.
When an application finishes drawing text, it calls
glDeleteLists
 to release the contiguous set of display lists created by
wglUseFontBitmaps
 and
wglUseFontOutlines
.


OpenGL Color Modes and Windows Palette Management
Microsoft's implementation of OpenGL in Windows NT supports two color pixel data modes: RGBA and color-indexed mode. Windows and Windows NT provide two analogous ways of handling color: true color and palette management.
True-color devices, able to accept 16, 24, or more bits of color information per pixel, can display tens of thousands, tens of millions, or more colors simultaneously. Complexities arise, however, when an application has to deal with RGBA or color-indexed mode on a palette-type device. Palette-type devices, such as a 256-color VGA display, are limited in the number of colors they can display simultaneously. Applications must handle a number of tricky details to successfully use palette-type devices. Because color-index mode programs don't use a hardware palette, they are more difficult to use with true-color devices than programs using the RGBA mode.
If you are unfamiliar with using true-color devices or the Palette Manager, refer to the articles "Palette Awareness," "The Palette Manager: How and Why," and "Using True-color devices" on the Microsoft Development Library CDs for an introduction to the essentials of Windows color management.


Palettes and the Palette Manager
The Windows NT Palette Manager, which is part of the GDI, specifically targets 8-bit display adapters with a
hardware palette
 of 256 color entries. Pixels on the screen are stored as an 8-bit index into the hardware palette. Each entry in the hardware palette usually defines a 24-bit color (eight each of red, green, and blue).
The Palette Manager maintains a
system palette
 that is a copy of the hardware palette. The system palette is divided into two sections: 20 reserved colors and the remaining 236 colors, which you can set using the Palette Manager
A default 20-color logical palette is selected and realized into a device context. You can create and use a new logical palette. By selecting and realizing that palette you can change the system palette.
You'll probably create a
logical palette
 to specify the colors you want display in your OpenGL application. Using certain GDI calls, your application can temporarily replace most of the system palette with a logical palette. Using a logical palette you can define pixel colors for the GDI using either the RGBA or the color-index mode. The maximum size of a logical palette is 256 colors for 8-bit devices and 4,096 colors on a true-color device (16, 24, and 32 bits).
For more information on the RGBA and color-index modes, see RGBA Mode and Palette Management and Color Modes and Windows Palette Management.


Palette Awareness
Your application must respond to the WM_PALETTECHANGED, WM_QUERYNEWPALETTE, and WM_ACTIVATE messages to be aware of and use palettes. Design your application to select and realize palettes in response to these messages.
For more information on palettes and palette awareness, refer to the articles "Palette Awareness," and "The Palette Manager: How and Why" on the Microsoft Development Library CDs.


Reading Color Values from the Frame Buffer
When using functions that read back color values from the frame buffer, be aware of the differences between reading RGBA values and color-index values on true-color devices and on palette-based devices:
·
On a true-color device:
·
RGBA values are limited to the channel in the device.
·
Color-index values are stored a RGBA values in the frame buffer. When using these values, you must perform an inverse translation from RGBA to the logical palette index. If two logical indexes have the same RGB value, the wrong index can be returned.
·
On a palette-based device:
·
RGBA values are read from an index in the system palette. The logical index is obtained from an inverse table and the RGBA components are extracted.
·
Color-index values are read from an index into the system palette and an inverse table is used to get the logical palette index.


Choosing Between RGBA and Color-Index Mode
In general, use the RGBA mode for your OpenGL applications; it provides more flexibility than the color-index mode for effects such as shading, lighting, color mapping, fog, anti-aliasing, and blending. Consider using the color-index mode in the following cases:
·
If you have a limited number of bitplanes available, the color-index mode can produce less coarse shading than the RGBA mode.
·
If you are not concerned about using "real" colors; for example, using several colors in a topographic map to designate relative elevations.
·
When you're porting an existing application that uses color-index mode extensively.
·
When you want to use colormap animation and effects in your application. (This is not possible on true-color devices.)


RGBA Mode and Windows Palette Management
RGBA Mode and Palette Management
While most GDI applications tend to use color-indexing with logical palettes, for OpenGL applications you'll usually choose the RGBA mode. It works better than color mapping for several effects, such as shading, lighting, fog, and texture mapping.
The RGBA mode uses red, green, and blue (R, G, and B) color values that together specify the color of each pixel in the display. The R, G, and B values specify the intensity of each color (red, green, or blue); the values range from 0.0 (least intense) to 1.0 (most intense). The number of bits for each component varies depending on the hardware used (2, 3, 5, 6, and 8 bits are possible).The color displayed is a result of the sum of the three color values. If all three values are 0.0, the result is black. If they are all 1.0, the result is white. Other colors are a result of a combination of values of R, G, and B that fall between 0 and 1.0. The A (alpha) bit isn't used to specify color.
The standard super-VGA display uses palettes with eight color-bits per pixel. The eight bits are read from the from buffer and used as an index in the system palette to get the R, G, and B values. When an RGB palette is selected and realized in a device context, OpenGL can render using the RGBA mode.
Because there are eight color-bits per pixel, OpenGL emphasizes the use of a three-three-two RGB palette. The three-three-two refers to how the color-bit data is handled by the hardware or physical palette. Red (R) and green (G) are each specified by three bits while blue (B) is specified by two bits. Red is the least-significant bit and blue is the most-significant bit.
You determine the colors of your application's logical palette with
PALETTEENTRY
 structures. Typically you create an array of PALETTEENTRY structures to specify entire palette entry table of the logical palette.
RGBA Mode Palette Sample
The following code fragment shows how you can create a three-three-two RGBA palette.
/*
 * win8map.c - program to create an 8-bit RGB color map for
 * use with OpenGL
 *
 * For OpenGL RGB rendering you need to know red, green, & blue
 * component bit sizes and positions. On 8 bit palette devices you need
 * to create a logical palette that has the correct RGB values for all
 * 256 possible entries. This program creates an 8 bit RGB color cube
 * with a default gamma of 1.4.
 *
 * Unfortunately, because the standard 20 colors in the system palette
 * cannot be changed,if you select this palette into an 8-bit display
 * DC, you will not realize all of the logical palette. The program
 * changes some of the entries in the logical palette to match enties in
 * the system palette using a least-squares calculation to find which
 * entries to replace.
  *
 * Note: Three bits for red & green and two bits for blue; red is the
 * least-significant bit and blue is the most-significant bit.
 */
#include <stdio.h>
#include <math.h>
#define DEFAULT_GAMMA 1.4F
#define MAX_PAL_ERROR (3*256*256L)
struct colorentry {
    unsigned char red;
    unsigned char green;
    unsigned char blue;
};
struct rampentry {
    struct colorentry color;
    long defaultindex;
    unsigned char flags;
};
struct defaultentry {
    struct colorentry color;
    long rampindex;
    unsigned char flags;
};
/* values for flags */
#define EXACTMATCH      0x01
#define CHANGED         0x02        /* one of the default entries is close */
/*
 * These arrays hold bit arrays with a gamma of 1.0
 * used to convert n bit values to 8 bit values
 */
unsigned char threeto8[8] = {
    0, 0111>>1, 0222>>1, 0333>>1, 0444>>1, 0555>>1, 0666>>1, 0377
};
unsigned char twoto8[4] = {
    0, 0x55, 0xaa, 0xff
};
unsigned char oneto8[2] = {
    0, 255
};
struct defaultentry defaultpal[20] = {
    { 0,   0,   0 },
    { 0x80,0,   0 },
    { 0,   0x80,0 },
    { 0x80,0x80,0 },
    { 0,   0,   0x80 },
    { 0x80,0,   0x80 },
    { 0,   0x80,0x80 },
    { 0xC0,0xC0,0xC0 },
    { 192, 220, 192 },
    { 166, 202, 240 },
    { 255, 251, 240 },
    { 160, 160, 164 },
    { 0x80,0x80,0x80 },
    { 0xFF,0,   0 },
    { 0,   0xFF,0 },
    { 0xFF,0xFF,0 },
    { 0,   0,   0xFF },
    { 0xFF,0,   0xFF },
    { 0,   0xFF,0xFF },
    { 0xFF,0xFF,0xFF }
};
struct rampentry rampmap[256];
void
gammacorrect(double gamma)
{
    int i;
    unsigned char v, nv;
    double dv;
    for (i=0; i<8; i++) {
        v = threeto8[i];
        dv = (255.0 * pow(v/255.0, 1.0/gamma)) + 0.5;
    nv = (unsigned char)dv;
    printf("Gamma correct %d to %d (gamma %.2f)\n", v, nv, gamma);
        threeto8[i] = nv;
    }
    for (i=0; i<4; i++) {
        v = twoto8[i];
        dv = (255.0 * pow(v/255.0, 1.0/gamma)) + 0.5;
    nv = (unsigned char)dv;
    printf("Gamma correct %d to %d (gamma %.2f)\n", v, nv, gamma);
        twoto8[i] = nv;
    }
    printf("\n");
}
main(int argc, char *argv[])
{
    long i, j, error, min_error;
    long error_index, delta;
    double gamma;
    struct colorentry *pc;
    if (argc == 2)
        gamma = atof(argv[1]);
    else
        gamma = DEFAULT_GAMMA;
    gammacorrect(gamma);
    /* First create a 256 entry RGB color cube */
    for (i = 0; i < 256; i++) {
        /* BGR: 2:3:3 */
        rampmap[i].color.red = threeto8[(i&7)];
        rampmap[i].color.green = threeto8[((i>>3)&7)];
        rampmap[i].color.blue = twoto8[(i>>6)&3];
    }
    /* Go through the default palette and find exact matches */
    for (i=0; i<20; i++) {
        for(j=0; j<256; j++) {
            if ( (defaultpal[i].color.red == rampmap[j].color.red) &&
                 (defaultpal[i].color.green == rampmap[j].color.green) &&
                 (defaultpal[i].color.blue == rampmap[j].color.blue)) {
                rampmap[j].flags = EXACTMATCH;
                rampmap[j].defaultindex = i;
                defaultpal[i].rampindex = j;
                defaultpal[i].flags = EXACTMATCH;
                break;
            }
        }
    }
    /* Now find close matches */
    for (i=0; i<20; i++) {
        if (defaultpal[i].flags == EXACTMATCH)
            continue;         /* skip entries w/ exact matches */
        min_error = MAX_PAL_ERROR;
        /* Loop through RGB ramp and calculate least square error */
        /* if an entry has already been used, skip it */
        for(j=0; j<256; j++) {
            if (rampmap[j].flags != 0)      /* Already used */
                continue;
            delta = defaultpal[i].color.red - rampmap[j].color.red;
            error = (delta * delta);
            delta = defaultpal[i].color.green - rampmap[j].color.green;
            error += (delta * delta);
            delta = defaultpal[i].color.blue - rampmap[j].color.blue;
            error += (delta * delta);
            if (error < min_error) {        /* New minimum? */
                error_index = j;
                min_error = error;
            }
        }
        defaultpal[i].rampindex = error_index;
        rampmap[error_index].flags = CHANGED;
        rampmap[error_index].defaultindex = i;
    }
    /* First print out the color cube */
    printf("Standard 8 bit RGB color cube with gamma %.2f:\n", gamma);
    for (i=0; i<256; i++) {
        pc = &rampmap[i].color;
        printf("%3ld: (%3d, %3d, %3d)\n", i, pc->red,
                pc->green, pc->blue);
    }
    printf("\n");
    /* Now print out the default entries that have an exact match */
    for (i=0; i<20; i++) {
        if (defaultpal[i].flags == EXACTMATCH) {
            pc = &defaultpal[i].color;
            printf("Default entry %2ld exactly matched RGB ramp entry
                      %3ld", i, defaultpal[i].rampindex);
            printf(" (%3d, %3d, %3d)\n", pc->red, pc->green, pc->blue);
        }
    }
    printf("\n");
    /* Now print out the closet entries for rest of
     * the default entries */
    for (i=0; i<20; i++) {
        if (defaultpal[i].flags != EXACTMATCH) {
            pc = &defaultpal[i].color;
            printf("Default entry %2ld (%3d, %3d, %3d) is close to ",
                i, pc->red, pc->green, pc->blue);
            pc = &rampmap[defaultpal[i].rampindex].color;
            printf("RGB ramp entry %3ld (%3d, %3d, %3d)\n",
                defaultpal[i].rampindex, pc->red, pc->green, pc->blue);
        }
    }
    printf("\n");
    /* Print out code to initialize a logical palette
     * that will not overflow */
    printf("Here is code you can use to create a logical palette\n");
    printf("static struct {\n");
    printf("    WORD        palVersion;\n");
    printf("    WORD        palNumEntries;\n");
    printf("    PALETTEENTRY palPalEntries[256];\n");
    printf("} rgb8palette = {\n");
    printf("    0x300,\n");
    printf("    256,\n");
    for (i=0; i<256; i++) {
        if (rampmap[i].flags == 0)
            pc = &rampmap[i].color;
        else
            pc = &defaultpal[rampmap[i].defaultindex].color;
        printf("    %3d, %3d, %3d,   0,    /* %ld",
                pc->red, pc->green, pc->blue, i);
        if (rampmap[i].flags == EXACTMATCH)
            printf(" - Exact match with default %d",
                       rampmap[i].defaultindex);
        if (rampmap[i].flags == CHANGED)
            printf(" - Changed to match default %d",
                       rampmap[i].defaultindex);
        printf(" */\n");
    }
    printf("};\n");
    printf("\n    * * *\n\n");
    printf("    hpal = CreatePalette((LOGPALETTE *)&rgb8palette);\n");
    return 0;
}


Color-Indexed Mode and Windows Palette Management
Color-Indexed Mode and Palette Management
The color-index mode specifies colors in a logical palette with an index to a specific logical-palette entry. Most GDI programs use color-index palettes, but the RGBA mode works better for OpenGL for several effects, such as shading, lighting, fog, and texture mapping. If having the truest color isn't critical for your OpenGL application, you might choose to use the color-index mode (for example, a topographic map that uses "false color" to emphasize the elevation gradient).
Color-Index Mode Palette Sample
The following code sets up a
PIXELFORMATDESCRIPTOR
 that sets the flag of the
iPixelType
 field to PFD_TYPE_COLORINDEX. This specifies that the application use a color-index palette.
BOOL bSetupPixelFormat(HDC hdc)
{
    PIXELFORMATDESCRIPTOR pfd, *ppfd;
    int pixelformat;
    ppfd = &pfd;
    ppfd->nSize = sizeof(PIXELFORMATDESCRIPTOR);
    ppfd->nVersion = 1;
    ppfd->dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL |
PFD_DOUBLEBUFFER;
    ppfd->dwLayerMask = PFD_MAIN_PLANE;
/* Set to color-index mode and use the default color palette. */
    ppfd->iPixelType = PFD_TYPE_COLORINDEX;
    ppfd->cColorBits = 8;
    ppfd->cDepthBits = 16;
    ppfd->cAccumBits = 0;
    ppfd->cStencilBits = 0;
    pixelformat = ChoosePixelFormat(hdc, ppfd);
    if ( (pixelformat = ChoosePixelFormat(hdc, ppfd)) == 0 )
    {
        MessageBox(NULL, "ChoosePixelFormat failed", "Error", MB_OK);
        return FALSE;
    }
    if (SetPixelFormat(hdc, pixelformat, ppfd) == FALSE)
    {
        MessageBox(NULL, "SetPixelFormat failed", "Error", MB_OK);
        return FALSE;
    }
    return TRUE;
}


Overlay, Underlay, and Main Planes
In other environments OpenGL may support drawing in several layers of planes. In Microsoft's implementation of OpenGL in Windows NT, all drawing occurs on one layer: the main plane. There is no support for overlay or underlay planes.


Sharing Display Lists
When you create a rendering context, it has its own display-list space. The
wglShareLists
 function enables a rendering context to share the display-list space of another rendering context. Any number of rendering contexts can share a single display-list space.


Extending OpenGL Functions
The OpenGL library supports multiple implementations of its functions. Extension functions supported in one rendering context aren't necessarily available in a different rendering context. For a given rendering context in an application using extension functions, use the function addresses returned by
wglGetProcAddress
 only.


GLX and WGL/Win32
Some of the WGL functions, new Win32 functions, and other Win32 functions are more or less analogous to GLX X-windows functions. The following list shows some of the relationships.
GLX Functions
WGL/Win32 Functions
glXChooseVisual
ChoosePixelFormat
glXCopyContext
---
glXCreateContext
wglCreateContext
glXCreateGLXPixmap
CreateDIBitmap
/
CreateDIBSection
glXDestroyContext
wglDeleteContext
glXDestroyGLXPixmap
DeleteObject
glXGetConfig
DescribePixelFormat
glXGetCurrentContext
wglGetCurrentContext
glXGetCurrentDrawable
wglGetCurrentDC
glXIsDirect
---
glXMakeCurrent
wglMakeCurrent
glXQueryExtension
GetVersion
glXQueryVersion
GetVersion
glXSwapBuffers
SwapBuffers
glXUseXFont
wglUseFontBitmaps
/
wglUseFontOutlines
glXWaitGL
---
glXWaitX
---
XGetVisualInfo
GetPixelFormat
XCreateWindow
CreateWindow
/
CreateWindowEx
and
GetDC
/
BeginPaint
XSync
GdiFlush
---
SetPixelFormat
---
wglGetProcAddress
---
wglShareLists
For further details, refer to the
 Porting Guide
.


Using OpenGL on Windows NT
The following topics explain how to use several Windows NT
-
 specific features of Microsoft's implementation of OpenGL in Windows NT.


Header Files
Applications that use the core OpenGL functions must include the header file <GL\GL.H>.
Applications that use the OpenGL utility library must include the header file <GL\GLU.H>.
Applications that use the OpenGL Programming Guide Auxiliary Library must include the header file <GL\GLAUX.H>.
Applications that use the WGL functions must include the header file WINDOWS.H.
Applications that use the new Win32 functions that support Microsoft's implementation of OpenGL in Windows NT must include the header file WINDOWS.H.


Some Pixel Format Tasks
Before an application creates an OpenGL rendering context, it must set a device context pixel format.


Choosing and Setting a Best-Match Pixel Format
An application can obtain a device context's best match to a pixel format by specifying the desired pixel format in a
PIXELFORMATDESCRIPTOR
 data structure, then calling the
ChoosePixelFormat
function. That function returns a pixel format index; which an application can then pass to
SetPixelFormat
 to set the best match as the device context's current pixel format. The following is a sample code fragment:
PIXELFORMATDESCRIPTOR pfd = {
sizeof(PIXELFORMATDESCRIPTOR),
// size of this pfd
1,
// version number
PFD_DRAW_TO_WINDOW |
// support window
PFD_SUPPORT_OPENGL |
// support OpenGL
PFD_DOUBLEBUFFER,
// double buffered
PFD_TYPE_RGBA,
// RGBA type
24,
// 24-bit color depth
0, 0, 0, 0, 0, 0,
// color bits ignored
0,
// no alpha buffer
0,
// shift bit ignored
0,
// no accumulation buffer
0, 0, 0, 0,
// accum bits ignored
32,
// 32-bit z-buffer
0,
// no stencil buffer
0,
// no auxiliary buffer
PFD_MAIN_PLANE,
// main layer
0,
// reserved
0, 0, 0
// layer masks ignored
};
HDC  hdc;
int  iPixelFormat;
// get the device context's best-available-match pixel format
iPixelFormat = ChoosePixelFormat(hdc, &pfd);
// make that the device context's current pixel format
SetPixelFormat(hdc, iPixelFormat, &pfd);


Examining A Device Context's Current Pixel Format
An application uses the
GetPixelFormat
 and
DescribePixelFormat
functions to examine a device context's current pixel format. Here is a code fragment:
PIXELFORMATDESCRIPTOR  pfd;
HDC
hdc;
int
iPixelFormat;
// if the DC has a current pixel format ...
if (iPixelFormat = GetPixelFormat(hdc)) {
// obtain a detailed description of that pixel format
DescribePixelFormat(hdc, iPixelFormat,
  sizeof(PIXELFORMATDESCRIPTOR), &pfd);
}


Examining A Device's Supported Pixel Formats
The
DescribePixelFormat
function obtains device context pixel format data. It also returns an integer that is the device context's maximum pixel format index. The following code fragment shows how an application can use that result to step through and examine the pixel formats supported by a device.
// local variables
int
iMax ;
PIXELFORMATDESCRIPTOR
pfd;
int
iPixelFormat ;
// initialize a pixel format index variable
iPixelFormat = 1;
// keep obtaining and examining pixel format data ...
do {
// try to obtain some pixel format data
iMax = DescribePixelFormat(hdc, iPixelFormat, sizeof(pfd), &pfd);
// if there was some problem with that...
if (iMax == 0)
// return indicating failure
return(FALSE);
// we have successfully obtained pixel format data
// let's examine the pixel format data...
myPixelFormatExaminer (&pfd);
}
// ...until we've looked at all the device context's pixel formats
while (++iPixelFormat <= iMax);


Some Rendering Context Tasks
All calls pass through a rendering context. After an application sets a device context's pixel format, it can create a rendering context.


Creating a Rendering Context and Making It Current
The following code fragment shows how an application might create an OpenGL rendering context in response to a WM_CREATE message. Notice that the pixel format is set up (details not included in this code fragment) before creating the rendering context. Also note that in this scenario the device context is not released locally; the application will release it when the window is closed, after the rendering context is made not current. See
Deleting a Rendering Context
. Finally, notice that an application can use local variables for the device context and rendering context handles, since
wglGetCurrentContext
 and
wglGetCurrentDC
 let an application obtain handles to those contexts as needed.
// a window has been created, but is not yet visible
case WM_CREATE:
{
// local variables
HDC
hdc ;
HGLRC
hglrc ;
// obtain a device context for the window
hdc = GetDC(hWnd);
// set an appropriate pixel format
myPixelFormatSetupFunction(hdc);
// if we can create a rendering context ...
if (hglrc = wglCreateContext( hdc ) ) {
// try to make it the thread's current rendering context
bHaveCurrentRC = wglMakeCurrent(hdc, hglrc) ;
}
// perform miscellaneous other WM_CREATE chores ....
}
break ;


Making a Rendering Context Not Current
An application detaches a rendering context from a thread by making it not current. You can do this by calling
wglMakeCurrent
 with the parameters set to NULL. The following is a sample of this simple task:
// detach the current rendering context from the thread
wglMakeCurrent(NULL, NULL);


Deleting a Rendering Context
The following code fragment shows how an application might delete an OpenGL rendering context when an OpenGL window is closed. It is a continuation of the scenario used in
Creating a Rendering Context and Making It Current
:
// a window is about to cease its glorious OpenGL existence
case WM_DESTROY:
{
// local variables
HGLRC
hglrc;
HDC
hdc ;
// if the thread has a current rendering context ....
if(hglrc = wglGetCurrentContext()) {
// obtain its associated device context
hdc = wglGetCurrentDC() ;
// make the rendering context not current
wglMakeCurrent(NULL, NULL) ;
// release the device context
ReleaseDC (hwnd, hdc) ;
// nuke the rendering context
    wglDeleteContext(hglrc);
}


Drawing with Double Buffers
An application uses double buffers to smooth the transition between images. Swapping buffers typically comes at the end of a sequence of drawing commands. By default, Microsoft's implementation of OpenGL in Windows NT draws to the off-screen buffer; when drawing is complete, an application can copy the off-screen buffer to the on-screen buffer by calling the
SwapBuffers
 function. In the following code fragment, an application prepares to draw, calls a drawing function, and then copies the completed image on-screen if it is using double buffering:
void myRedraw(void)
{
// set up for drawing commands
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45, 1.0, 0.1, 100.0);
// draw our objects
myDrawAllObjects(GL_FALSE);
// if we're double-buffering ...
if (bDoubleBuffering)
// ...copy the image on-screen
SwapBuffers(hdc);
}
Here is another example. An application obtains a window device context, renders a scene, copies the image on-screen (to show the rendering), and then releases the device context:
  hdc = GetDC(hwnd);
  mySceneRenderingFunction();
  SwapBuffers(hdc);
  ReleaseDC(hWnd, hdc);


Drawing Text in a Double-Buffered OpenGL Window
As previously mentioned, an application draws text in a double-buffered OpenGL window by creating display lists for selected characters in a font, then executing the appropriate display list for each character it wishes to draw. In the following sample fragment, an application creates a rendering context, draws a red triangle, and then labels it with text. The sample assumes that the application has obtained a device context and set up a font and pixel format for it.
// we enter with a device context, font, and pixel format
// create an OpenGL rendering context
hglrc = wglCreateContext(hdc);
// make it this thread's current rendering context
wglMakeCurrent(hdc, hglrc);
// we'll be clearing to a lovely and quiescent deep blue hue
glClearColor(0.0F, 0.0F, 0.4F, 1.0F);
// we want smooth shading
glShadeModel(GL_SMOOTH);
// clear the color buffers
glClear(GL_COLOR_BUFFER_BIT);
// specify a red triangle
glBegin(GL_TRIANGLES);
    glColor3f(1.0F, 0.0F, 0.0F);
    glVertex2f(10.0F, 10.0F);
    glVertex2f(250.0F, 50.0F);
    glVertex2f(105.0F, 280.0F);
glEnd();
// create bitmaps for the device context's font's first 256 glyphs
wglUseFontBitmaps(hdc, 0, 256, 1000);
// move bottom left, southwest of the red triangle
glRasterPos2f(30.0F, 300.0F);
// set up for a string-drawing display list call
glListBase(1000);
// draw a string using font display lists
glCallLists(12, GL_UNSIGNED_BYTE, "Red Triangle");
// get all those commands to execute
glFlush();
// delete our 256 glyphic display lists
glDeleteLists(1000, 256) ;
// make the rendering context not current
wglMakeCurrent (NULL, NULL) ;
// release the device context
ReleaseDC(hdc) ;
// delete the rendering context
wglDeleteContext(hglrc);


Printing an OpenGL Image
The current version of Microsoft's implementation of OpenGL in Windows NT provides direct support for printing on color printers that provide four or more bits of color information per pixel. To print on such a device, an application calls
wglCreateContext
with a printer device context to create a printing rendering context.
The current version of Microsoft's implementation of OpenGL in Windows NT does not provide direct support for printing on monochrome printers. More specifically: an application cannot call
wglCreateContext
 with a monochrome printer device context. There is a workaround for this situation, as illustrated in
Printing on a Monochrome Printer
.


Printing on a Monochrome Printer
There is an indirect way to print an image on a monochrome printer. The main points of the algorithm are as follows:
1.
Create a printer device context.
2.
Create a memory device context compatible with that printer device context.
3.
Create a rendering context, passing the
wglCreateContext
function the handle to the memory device context.
4.
Make that rendering context a thread's current rendering context.
5.
Make OpenGL calls, which will draw into that rendering context.
6.
Disconnect and delete the rendering context.
7.
Bitblt from the memory device context's bitmap to the printer device context's bitmap, banding to conserve memory.
8.
Delete the memory device context.
9.
Delete the printer device context.


Copying an OpenGL Image to the Clipboard
Although the current version of Microsoft's implementation of OpenGL in Windows NT does not directly support the Clipboard, an application can copy a Windows OpenGL image to the Clipboard by following these steps:
1.
Draw the image to a memory bitmap.
2.
Copy that bitmap to the Clipboard.


Multi-Threaded OpenGL Drawing Strategies
The GDI does not support multiple threads. Your OpenGL application must use a distinct device context and a distinct rendering context (RC) for each thread. This tends to limit the performance advantages of using multiple threads with single-processor systems running OpenGL applications. However, there are ways to use threads with a single processor system to greatly increase performance. For example, your application can use a separate thread to pass OpenGL rendering calls to dedicated 3D hardware.
Symmetric multi-processing (SMP) systems can greatly benefit from using multiple threads. An obvious strategy is to use a separate thread for each processor to handle OpenGL rendering in separate windows. For example, in a flight simulation application you could use a separate processor and thread to render the front, back, and side views.
A thread can have one current, active rendering context only. When your application uses multiple threads and multiple rendering contexts, you must be careful to synchronize their use. For example, use one thread only to call
SwapBuffers
 after all threads complete drawing.


Using the Auxiliary Library
Using OpenGL, SGI created the Auxiliary Library to write simple sample programs for the "OpenGL Programming Guide" (the "red book"). The source code for the auxiliary library is supplied with the SDK along with the OpenGL samples. You can examine the source code to help you understand how the Auxiliary Library was developed from OpenGL functions and routines, and you can use auxiliary library functions in your own programs. For a description of the Auxiliary Library, refer to the "OpenGL Programming Guide."


Lists of Functions and Structures
WGL Functions
wglCreateContext
wglDeleteContext
wglGetCurrentContext
wglGetCurrentDC
wglGetProcAddress
wglMakeCurrent
wglShareLists
wglUseFontBitmaps
wglUseFontOutlines
Win32 Functions
ChoosePixelFormat
DescribePixelFormat
GetPixelFormat
SetPixelFormat
SwapBuffers
Structures
GLYPHMETRICSFLOAT
PIXELFORMATDESCRIPTOR
POINTFLOAT


ChoosePixelFormat
The
ChoosePixelFormat
 function attempts to find the pixel format supported by a device context that is the best match to a given pixel format specification.
int ChoosePixelFormat(
    HDC
hdc
,
//Device context to search for a best pixel format match
    CONST PIXELFORMATDESCRIPTOR *
ppfd
//Pixel format for which a best match is sought
   );
Parameters
hdc
Specifies the device context that the function shall examine for a pixel format that best matches the pixel format descriptor pointed to by
ppfd
.
ppfd
Pointer to a
PIXELFORMATDESCRIPTOR
 structure that specifies the requested pixel format. In this particular context, the members of the pointed-to
PIXELFORMATDESCRIPTOR
structure are used as follows:
nSize
Specifies the size of the
PIXELFORMATDESCRIPTOR
 data structure. Set this member to
sizeof
(
PIXELFORMATDESCRIPTOR
).
nVersion
Specifies the version number of the
PIXELFORMATDESCRIPTOR
 data structure. Set this member to 1.
dwFlags
A set of bit flags that specify properties of the pixel buffer. An application can combine the following bit flag constants by bitwise-ORing.
If any of the following flags is set, the function attempts to choose a pixel format that also has that flag set. Otherwise, it ignores that flag in the pixel formats:
PFD_DRAW_TO_WINDOW
PFD_DRAW_TO_BITMAP
PFD_SUPPORT_GDI
PFD_SUPPORT_OPENGL
If any of the following flags are set, the function attempts to match pixel formats with that flag set. Otherwise, it attempts to match pixel formats without that flag set:
PFD_DOUBLEBUFFER
PFD_STEREO
If the following flag is set, the function ignores the PFD_DOUBLEBUFFER flag in the pixel formats:
PFD_DOUBLEBUFFER_DONTCARE
If the following flag is set, the function ignores the PFD_STEREO flag in the pixel formats:
PFD_STEREO_DONTCARE
iPixelType
The function only considers pixel formats of the specified type. It is one of the following types:
PFD_TYPE_RGBA
PFD_TYPE_COLORINDEX
cColorBits
0 or greater.
cRedBits
Not used.
cRedShift
Not used.
cGreenBits
Not used.
cGreenShift
Not used.
cBlueBits
Not used.
cBlueShift
Not used.
cAlphaBits
0 or greater.
cAlphaShift
Not used.
cAccumBits
0 or greater.
cAccumRedBits
Not used.
cAccumGreenBits
Not used.
cAccumBlueBits
Not used.
cAccumAlphaBits
Not used.
cDepthBits
0 or greater.
cStencilBits
0 or greater.
cAuxBuffers
0 or greater.
iLayerType
One of the following values:
PFD_MAIN_PLANE
PFD_OVERLAY_PLANE
PFD_UNDERLAY_PLANE
bReserved
Not used.
dwLayerMask
Not used.
dwVisibleMask
Not used.
dwDamageMask
Not used.
Return Value
If the function succeeds, the return value is a pixel format index (one-based) that is the closest match to the specification of the pixel format descriptor.
If the function fails, the return value is zero. Call
GetLastError
 for extended error information.
Remarks
It is an application's responsibility to ensure that the pixel format selected by the
ChoosePixelFormat
function satisfies its requirements. For example, if an application requests a pixel format with a 24-bit RGB color buffer, but the device context offers only 8-bit RGB color buffers, then the function returns a pixel format with an 8-bit RGB color buffer.
Here is a code fragment sample:
PIXELFORMATDESCRIPTOR pfd = {
sizeof(PIXELFORMATDESCRIPTOR),  // size of this pfd
1,                     // version number
PFD_DRAW_TO_WINDOW |   // support window
PFD_SUPPORT_OPENGL |   // support OpenGL
PFD_DOUBLEBUFFER,      // double buffered
PFD_TYPE_RGBA,         // RGBA type
24,                    // 24-bit color depth
0, 0, 0, 0, 0, 0,      // color bits ignored
0,                     // no alpha buffer
0,                     // shift bit ignored
0,                     // no accumulation buffer
0, 0, 0, 0,            // accum bits ignored
32,                    // 32-bit z-buffer
0,                     // no stencil buffer
0,                     // no auxiliary buffer
PFD_MAIN_PLANE,        // main layer
0,                     // reserved
0, 0, 0                // layer masks ignored
};
HDC  hdc;
int  iPixelFormat;
iPixelFormat = ChoosePixelFormat(hdc, &pfd);
See Also
DescribePixelFormat
,
GetPixelFormat
,
SetPixelFormat


DescribePixelFormat
The
DescribePixelFormat
 function obtains information about the pixel format identified by
iPixelFormat
 of the device associated with
hdc
. The function sets the members of the
PIXELFORMATDESCRIPTOR
 structure pointed to by
ppfd
 with that pixel format information.
int DescribePixelFormat(
    HDC
hdc
,
//Device context of interest
    int
iPixelFormat
,
//Pixel format selector
    UINT
nBytes
,
//Size of buffer pointed to by
ppfd
    LPPIXELFORMATDESCRIPTOR
ppfd
//Pointer to structure to receive pixel format data
   );
Parameters
hdc
Specifies the device context of interest.
iPixelFormat
Index that specifies the pixel format of interest. The pixel formats that a device context supports are identified by positive one-based integer indices.
nBytes
Specifies the size, in bytes, of the structure pointed to by
ppfd
. The function stores data to that structure; it stores no more than
nBytes
 bytes. Set this value to
sizeof
(
PIXELFORMATDESCRIPTOR
).
ppfd
Pointer to a
PIXELFORMATDESCRIPTOR
 structure whose members the function sets with pixel format data. The function stores the number of bytes copied to the structure in the structure's
nSize
 field. If, upon entry,
ppfd
 is NULL, the function writes no data to the structure. This is useful when an application only wants to obtain a device context's maximum pixel format index.
Return Value
If the function succeeds, the return value is the device context's maximum pixel format index. In addition, the function sets the members of the
PIXELFORMATDESCRIPTOR
 structure pointed to by
ppfd
 according to the specified pixel format.
If the function fails, the return value is zero. Call
GetLastError
 for extended error information.
Remarks
Here's a skeletal example of
DescribePixelFormat
 usage:
PIXELFORMATDESCRIPTOR  pfd;
HDC  hdc;
int  iPixelFormat;
iPixelFormat = 1;
// obtain detailed information about
// the device context's 1st pixel format
DescribePixelFormat(hdc, iPixelFormat,
        sizeof(PIXELFORMATDESCRIPTOR), &pfd);
See Also
ChoosePixelFormat
,
GetPixelFormat
,
SetPixelFormat


GetPixelFormat
The
GetPixelFormat
 function obtains the index of the specified device context's currently selected pixel format.
int GetPixelFormat(
    HDC
hdc
//Device context whose currently selected pixel format index is sought
   );
Parameter
hdc
Specifies the device context whose currently selected pixel format index the function returns.
Return Value
If the function succeeds, the return value is the specified device context's currently selected pixel format index. This is a positive, one-based index value.
If the function fails, the return value is zero. Call
GetLastError
 for extended error information.
Remarks
Here is a skeletal example of
GetPixelFormat
 usage:
PIXELFORMATDESCRIPTOR  pfd;
HDC  hdc;
int  iPixelFormat;
// get the current pixel format index
iPixelFormat = GetPixelFormat(hdc);
// obtain a detailed description of that pixel format
DescribePixelFormat(hdc, iPixelFormat,
        sizeof(PIXELFORMATDESCRIPTOR), &pfd);
See Also
ChoosePixelFormat
,
DescribePixelFormat
,
SetPixelFormat


PIXELFORMATDESCRIPTOR
typedef struct tagPIXELFORMATDESCRIPTOR { // pfd
    WORD  nSize;
    WORD  nVersion;
    DWORD dwFlags;
    BYTE  iPixelType;
    BYTE  cColorBits;
    BYTE  cRedBits;
    BYTE  cRedShift;
    BYTE  cGreenBits;
    BYTE  cGreenShift;
    BYTE  cBlueBits;
    BYTE  cBlueShift;
    BYTE  cAlphaBits;
    BYTE  cAlphaShift;
    BYTE  cAccumBits;
    BYTE  cAccumRedBits;
    BYTE  cAccumGreenBits;
    BYTE  cAccumBlueBits;
    BYTE  cAccumAlphaBits;
    BYTE  cDepthBits;
    BYTE  cStencilBits;
    BYTE  cAuxBuffers;
    BYTE  iLayerType;
    BYTE  bReserved;
    DWORD dwLayerMask;
    DWORD dwVisibleMask;
    DWORD dwDamageMask;
} PIXELFORMATDESCRIPTOR;
The
PIXELFORMATDESCRIPTOR
 structure describes the pixel format of a drawing surface.
Members
nSize
Specifies the size of this data structure. This value should be set to
sizeof
(
PIXELFORMATDESCRIPTOR
).
nVersion
Specifies the version of this data structure. This value should be set to 1.
dwFlags
A set of bit flags that specify properties of the pixel buffer. The properties are generally not mutually exclusive; an application can set any combination of bit flags, with the exceptions noted. The following bit flag constants are defined:
Value
Meaning
PFD_DRAW_TO_WINDOW
The buffer can draw to a window or device surface.
PFD_DRAW_TO_BITMAP
The buffer can draw to a memory bitmap.
PFD_SUPPORT_GDI
The buffer supports GDI drawing. This flag and PFD_DOUBLEBUFFER are mutually exclusive in the current generic implementation.
PFD_SUPPORT_OPENGL
The buffer supports OpenGL drawing.
PFD_GENERIC_FORMAT
The pixel format is supported by the GDI software implementation. That implementation is also known as the generic implementation. If this bit is clear, the pixel format is supported by a device driver or hardware.
PFD_NEED_PALETTE
The buffer uses RGBA pixels on a palette-managed device. A logical palette is required to achieve the best results for this pixel type. Colors in the palette should be specified according to the values of the
cRedBits
,
cRedShift
,
cGreenBits
,
cGreenShift
,
cBluebits
, and
cBlueShift
 members. The palette should be created and realized in the device context (DC) before calling
wglMakeCurrent
.
PFD_NEED_SYSTEM_PALETTE
Used with systems with OpenGL hardware that supports one hardware palette only. For such systems to use hardware acceleration, the hardare palette must be in a fixed order (for example, 3-3-2) when in RGBA mode or must match the logical palette when in color-index mode.
When you set this flag, you should call
SetSystemPaletteUse
 in your program to force a one-to-one mapping of the logical palette and the system palette. If your OpenGL harware supports multiple hardware palettes and the device driver can allocate spare hardware palettes for OpenGL, you don't need to set PFD_NEED_SYSTEM_PALETTE.
This flag is not set in the generic pixel formats.
PFD_DOUBLEBUFFER
The buffer is double-buffered. This flag and PFD_SUPPORT_GDI are mutually exclusive in the current generic implementation.
PFD_STEREO
The buffer is stereoscopic. This flag is not supported in the current generic implementation.
In addition, the following bit flags can be specified when calling
ChoosePixelFormat
:
Value
Meaning
PFD_DOUBLE_BUFFER_DONTCARE
The requested pixel format can be either single- or double-buffered.
PFD_STEREO_DONTCARE
The requested pixel format can be either monoscopic or stereoscopic.
With the
glAddSwapHintRectWIN
 extension function two new flags are included for the
PIXELFORMATDESCRIPTOR
 pixel format structure:
Value
Meaning
PFD_SWAP_COPY
Specifies the content of the back buffer in the double-buffered main color plane following a buffer swap. Swapping the color buffers causes the back-buffer content to be copied to the front buffer. The content of the back buffer is not affected by the swap.
PFD_SWAP_COPY
 is a hint only and might not be provided by a driver.
PFD_SWAP_EXCHANGE
Specifies the content of the back buffer in the double-buffered main color plane following a buffer swap. Swapping the color buffers causes the exchange of back-buffer content with the front-buffer content. Following the swap, the back-buffer content contains the front-buffer content before the swap.
PFD_SWAP_EXCHANGE
 is a hint only and might not be provided by a driver.
iPixelType
Specifies the type of pixel data. The following types are defined:
Value
Meaning
PFD_TYPE_RGBA
RGBA pixels. Each pixel has four components: red, green, blue, and alpha.
PFD_TYPE_COLORINDEX
Color index pixels. Each pixel uses a color index value
cColorBits
Specifies the number of color bitplanes in each color buffer. For RGBA pixel types, it is the size of the color buffer excluding the alpha bitplanes. For color index pixels, it is the size of the color index buffer.
cRedBits
Specifies the number of red bitplanes in each RGBA color buffer.
cRedShift
Specifies the shift count for red bitplanes in each RGBA color buffer.
cGreenBits
Specifies the number of green bitplanes in each RGBA color buffer.
cGreenShift
Specifies the shift count for green bitplanes in each RGBA color buffer.
cBlueBits
Specifies the number of blue bitplanes in each RGBA color buffer.
cBlueShift
Specifies the shift count for blue bitplanes in each RGBA color buffer.
cAlphaBits
Specifies the number of alpha bitplanes in each RGBA color buffer. Alpha bitplanes are not supported.
cAlphaShift
Specifies the shift count for alpha bitplanes in each RGBA color buffer. Alpha bitplanes are not supported.
cAccumBits
Specifies the total number of bitplanes in the accumulation buffer.
cAccumRedBits
Specifies the number of red bitplanes in the accumulation buffer.
cAccumGreenBits
Specifies the number of green bitplanes in the accumulation buffer.
cAccumBlueBits
Specifies the number of blue bitplanes in the accumulation buffer.
cAccumAlphaBits
Specifies the number of alpha bitplanes in the accumulation buffer.
cDepthBits
Specifies the depth of the depth (z-axis) buffer.
cStencilBits
Specifies the depth of the stencil buffer.
cAuxBuffers
Specifies the number of auxiliary buffers. Auxiliary buffers are not supported.
iLayerType
Specifies the type of layer. Although the following values are defined, the current version supports only the main plane (there is no support for overlay or underlay planes):
Value
Meaning
PFD_MAIN_PLANE
The layer is the main plane.
PFD_OVERLAY_PLANE
The layer is the overlay plane.
PFD_UNDERLAY_PLANE
The layer is the underlay plane.
bReserved
Not used. Must be zero.
dwLayerMask
Specifies the layer mask. The layer mask is used in conjunction with the visible mask to determine if one layer overlays another.
dwVisibleMask
Specifies the visible mask. The visible mask is used in conjunction with the layer mask to determine if one layer overlays another. If the result of the bitwise-AND of the visible mask of a layer and the layer mask of a second layer is nonzero, then the first layer overlays the second layer, and a transparent pixel value exists between the two layers.  If the visible mask is 0, the layer is opaque.
dwDamageMask
Specifies whether more than one pixel format shares the same frame buffer. If the result of the bitwise-AND of the damage masks between two pixel formats is non-zero, then they share the same buffers.
Remarks
Please notice carefully, as documented above, that certain pixel format properties are not supported in the current generic implementation. The generic implementation is the Microsoft GDI software implementation of OpenGL. Hardware manufacturers may enhance parts of OpenGL, and may support some pixel format properties not supported by the generic implementation.
See Also
ChoosePixelFormat
,
DescribePixelFormat
,
GetPixelFormat
,
SetPixelFormat


SetPixelFormat
The
SetPixelFormat
 function sets the specified device context's pixel format to the format specified by the
iPixelFormat
 index.
BOOL SetPixelFormat(
    HDC
hdc
,
//Device context whose pixel format the function attempts to set
    int
iPixelFormat
,
//Pixel format index (one-based)
    CONST PIXELFORMATDESCRIPTOR *
ppfd
//Pointer to logical pixel format specification
   );
Parameters
hdc
Specifies the device context whose pixel format the function attempts to set.
iPixelFormat
Index that identifies the pixel format to set.  The various pixel formats supported by a device context are identified by one-based indices.
ppfd
Pointer to a
PIXELFORMATDESCRIPTOR
 structure that contains the logical pixel format specification. The system's metafile component uses this structure to record the logical pixel format specification. The structure has no other effect upon the behavior of the
SetPixelFormat
 function.
Return Value
If the function succeeds, the return value is TRUE.
If the function fails, the return value is FALSE. Call
GetLastError
for extended error information.
Remarks
If
hdc
 references a window, calling the
SetPixelFormat
 function also changes the pixel format of the window. Setting the pixel format of a window more than once can lead to significant complications for the window manager and for multithreaded applications, so it is not allowed. An application may only set the pixel format of a window one time. Once a window's pixel format is set, it cannot be changed.
An application should select a pixel format in the device context before calling the
wglCreateContext
 function. The
wglCreateContext
 function creates a rendering context for drawing on the device in the device context's selected pixel format.
An OpenGL window has its own pixel format. Because of this, only device contexts retrieved for the client area of an OpenGL window are allowed to draw into the window. As a result, an OpenGL window should be created with the WS_CLIPCHILDREN and WS_CLIPSIBLINGS styles. Additionally, the window class attribute should not include the CS_PARENTDC style.
Here is a skeletal example of
SetPixelFormat
 usage:
PIXELFORMATDESCRIPTOR pfd = {
sizeof(PIXELFORMATDESCRIPTOR),   // size of this pfd
1,                     // version number
PFD_DRAW_TO_WINDOW |   // support window
PFD_SUPPORT_OPENGL |   // support OpenGL
PFD_DOUBLEBUFFER,      // double buffered
PFD_TYPE_RGBA,         // RGBA type
24,                    // 24-bit color depth
0, 0, 0, 0, 0, 0,      // color bits ignored
0,                     // no alpha buffer
0,                     // shift bit ignored
0,                     // no accumulation buffer
0, 0, 0, 0,            // accum bits ignored
32,                    // 32-bit z-buffer
0,                     // no stencil buffer
0,                     // no auxiliary buffer
PFD_MAIN_PLANE,        // main layer
0,                     // reserved
0, 0, 0                // layer masks ignored
};
HDC  hdc;
int  iPixelFormat;
// get the device context's best-available-match pixel format
iPixelFormat = ChoosePixelFormat(hdc, &pfd);
// make that the device context's current pixel format
SetPixelFormat(hdc, iPixelFormat, &pfd);
See Also
ChoosePixelFormat
,
DescribePixelFormat
,
GetPixelFormat


SwapBuffers
The
SwapBuffers
 function exchanges the front and back buffers if the current pixel format for the window referenced by the specified device context includes a back buffer.
BOOL SwapBuffers
(
    HDC
hdc
//Device context whose buffers get swapped
   );
Parameter
hdc
Specifies a device context. If the current pixel format for the window referenced by this device context includes a back buffer, the function exchanges the front and back buffers.
Return Value
If the function succeeds, the return value is TRUE.
If the function fails, the return value is FALSE. Call
GetLastError
for extended error information.
Remarks
If the current pixel format for the window referenced by the device context does not include a back buffer, then this call has no effect. The content of the back buffer is undefined when the function returns.
A multithreaded application should flush the drawing commands in any other threads drawing to the same window before calling the
SwapBuffers
 function.


wglCreateContext
The
wglCreateContext
function creates a new OpenGL rendering context. The rendering context is suitable for drawing on the device referenced by
hdc
. The rendering context has the same pixel format as the device context.
HGLRC wglCreateContext(
    HDC
hdc
//Device context of device that the rendering context will be suitable for
   );
Parameter
hdc
Handle to a device context. The function creates an OpenGL rendering context suitable for the device the device context references.
Return Value
If the function succeeds, the return value is a valid handle to an OpenGL rendering context.
If the function fails, the return value is NULL. Call
GetLastError
 for extended error information.
Remarks
A rendering context, or GLRC, is a port through which all OpenGL commands pass. Every thread that makes OpenGL calls needs to have a current OpenGL rendering context.
A rendering context is not the same as a device context. A device context contains information pertinent to GDI, and a rendering context contains information pertinent to OpenGL.
An application should set the device context's pixel format before creating a rendering context. See the
SetPixelFormat
 function.
To use OpenGL, an application creates a rendering context, selects it as a thread's current rendering context, then calls OpenGL functions. When the application is finished with the rendering context, it disposes of it by calling
wglDeleteContext
. Here's a code example:
// The barest of OpenGL skeletons
HDC  hdc;
HGLRC  hglrc;
// create a rendering context
hglrc = wglCreateContext (hdc);
// make it the calling thread's current rendering context
wglMakeCurrent (hdc, hglrc);
// call OpenGL APIs as desired ...
.
.
.
// when the rendering context is no longer needed ...
// make the rendering context not current
wglMakeCurrent (NULL, NULL) ;
// delete the rendering context
wglDeleteContext (hglrc);
See Also
SetPixelFormat
,
wglDeleteContext
,
wglGetCurrentContext
,
wglGetCurrentDC
,
wglMakeCurrent


wglDeleteContext
The
wglDeleteContext
function deletes a specified OpenGL rendering context.
BOOL wglDeleteContext(
    HGLRC
hglrc
//Handle to the OpenGL rendering context to delete
   );
Parameter
hglrc
Handle to an OpenGL rendering context that the function is to delete.
Return Value
If the function succeeds, the return value is TRUE.
If the function fails, the return value is FALSE. Call
GetLastError
 for extended error information.
Remarks
It is an error to delete an OpenGL rendering context that is another thread's current context. However, if a rendering context is the calling thread's current context, the function makes the rendering context not current before deleting it.
The
wglDeleteContext
 function does not delete the device context associated with the OpenGL rendering context via the
wglMakeCurrent
 function. After calling
wglDeleteContext
, an application should call
DeleteDC
to delete the associated device context.
See Also
wglCreateContext
,
wglGetCurrentContext
,
wglGetCurrentDC
,
wglMakeCurrent


wglGetCurrentContext
The
wglGetCurrentContext
function obtains a handle to the calling thread's current OpenGL rendering context.
HGLRC wglGetCurrentContext(
VOID
);
Parameter
This function has no parameters.
Return Value
If the calling thread has a current OpenGL rendering context, the function returns a handle to that rendering context. Otherwise, the function return value is NULL.
Remarks
A thread's current OpenGL rendering context is associated with a device context via the
wglMakeCurrent
 function. An application can use the
wglGetCurrentDC
 function to obtain a handle to the device context associated with the current OpenGL rendering context.
See Also
wglCreateContext
,
wglDeleteContext
,
wglGetCurrentDC
,
wglMakeCurrent


wglGetCurrentDC
The
wglGetCurrentDC
function obtains a handle to the device context that is associated with the calling thread's current OpenGL rendering context.
HDC wglGetCurrentDC(
VOID
);
Parameter
This function has no parameters.
Return Value
If the calling thread has a current OpenGL rendering context, the function returns a handle to the device context associated with that rendering context via the
wglMakeCurrent
 function. Otherwise, the function return value is NULL.
Remarks
An application associates a device context with an OpenGL rendering context when it calls the
wglMakeCurrent
function.  An application can use the
wglGetCurrentContext
 function to obtain a handle to calling thread's current OpenGL rendering context.
See Also
wglCreateContext
,
wglDeleteContext
,
wglGetCurrentContext
,
wglMakeCurrent


wglGetProcAddress
The
wglGetProcAddress
function returns the address of an OpenGL extension function for use with the current OpenGL rendering context.
PROC wglGetProcAddress(
    LPCSTR
lpszProc
//Name of the extension function
   );
Parameter
lpszProc
Points to a null-terminated string that is the name of the extension function. The name of the extension function must be identical to a corresponding function implemented by OpenGL.
Return Value
When the function succeeds, the return value is the address of the extension function. When no current rendering context exists or the function fails, the return value is NULL. Call
GetLastError
 for extended error information.
Remarks
The OpenGL library supports multiple implementations of its functions. Extension functions supported in one rendering context are not necessarily available in a separate rendering context. Thus for a given rendering context in an application use the function addresses returned by
wglGetProcAddress
 only.
The spelling and the case of the extension function pointed to by
lpszProc
 must be identical to that of a function supported and implemented by OpenGL. Because extension functions are not exported by the OpenGL library, you must use
wglGetProcAddress
 to get the addresses of vendor-specific extension functions.
The extension function addresses are unique for each pixel format. All rendering contexts of a given pixel format share the same extension function addresses.
See Also
glGetString
,
wglMakeCurrent


wglMakeCurrent
The
wglMakeCurrent
function makes a specified OpenGL rendering context the calling thread's current rendering context. All subsequent OpenGL calls made by the thread are drawn on the device identified by
hdc
. The function can also be used to make the calling thread's current rendering context not current.
BOOL wglMakeCurrent(
    HDC
hdc
,
//Device context of device that OpenGL calls are to be drawn on
    HGLRC
hglrc
//OpenGL rendering context to be made calling thread's current rendering context
   );
Parameters
hdc
Handle to a device context. Subsequent OpenGL calls made by the calling thread are drawn on the device identified by
hdc
.
hglrc
Handle to an OpenGL rendering context that the function sets as the calling thread's rendering context.
If
hglrc
 is NULL, the function makes the calling thread's current rendering context not current, and releases the device context that is used by the rendering context. In this situation,
hdc
 is ignored.
Return Value
If the function succeeds, the return value is TRUE.
If the function fails, the return value is FALSE. Call
GetLastError
 for extended error information.
Remarks
The
hdc
 parameter must refer to a drawing surface supported by OpenGL.  It need not be the same
hdc
 that was passed to
wglCreateContext
when
hglrc
 was created, but it must be on the same device and it must have the same pixel format. GDI transformation and clipping in
hdc
 are not supported by the rendering context. The current rendering context uses the
hdc
 device context until the rendering context is made not current.
Before switching to the new rendering context, OpenGL flushes any previous rendering context that was current to the calling thread.
A thread can have one current rendering context. A process can have multiple rendering contexts via multi-threading. A thread must set a current rendering context before calling any OpenGL functions. Otherwise, all OpenGL calls are ignored.
A rendering context can be current to only one thread at a time. It is an error to make a rendering context current to multiple threads.
An application can perform multi-threaded drawing by making different rendering contexts current to different threads, supplying each thread with its own rendering context and device context.
If an error occurs, the
wglMakeCurrent
 function makes the thread's current rendering context, if any, not current before returning.
See Also
wglCreateContext
,
wglDeleteContext
,
wglGetCurrentContext
,
wglGetCurrentDC


wglShareLists
The
wglShareLists
function enables multiple OpenGL rendering context to share a single display-list space.
BOOL wlgMakeShareLists(
    HGLRC
hglrc1
,
//OpenGL rendering context with which to share display lists
    HGLRC
hglrc2
//OpenGL rendering context to share display lists
   );
Parameters
hglrc1
Specifies the OpenGL rendering context with which to share display lists.
hglrc2
Specifies the OpenGL rendering context to share display lists with
hglrc1
.
hglrc2
 should not contain any existing display lists when
wglShareLists
 is called.
Return Value
When the function succeeds, the return value is TRUE.
When the function fails, the return value is FALSE and the display lists are not shared. Call
GetLastError
 for extended error information.
Remarks
When you create an OpenGL rendering context, it has its own display-list space.
wlgShareLists
 enables a rendering context to share the display-list space of another rendering context and any number of rendering contexts can share a single display-list space. Once a rendering context shares a display-list space, the rendering context always uses the display-list space until the rendering context is deleted. When the last rendering context of a shared display-list space is deleted, the shared display-list spaced is deleted. All the indexes and definitions of display lists in a shared display-list space are shared.
You can only share display lists with rendering contexts within the same process. However, not all rendering contexts in  a process can share display lists. Rendering contexts can share display lists if they use the same implementation of OpenGL functions only. All client rendering contexts of a given pixel format can always share display lists.
Note
wlgShareLists
 is available with OpenGL version 1.01 or later only. To determine the version number of the implementation of OpenGL, call
glGetString
.
See Also
glGetString


wglUseFontBitmaps
The
wglUseFontBitmaps
function creates a set of bitmap display lists based on the glyphs in a device context's currently selected font for use in the current OpenGL rendering context. These bitmaps can then be used to draw characters in an OpenGL image.
The
wglUseFontBitmaps
 function creates
count
 display lists, one for each of a run of
count
 glyphs that begins with
hdc
's selected font's
first
 glyph.
BOOL wglUseFontBitmaps(
    HDC
hdc
,
//Device context whose font will be used
    DWORD
first
,
//Glyph that is the first of a run of glyphs to be turned into bitmap display lists
    DWORD
count
,
//Number of glyphs to turn into bitmap display lists
    DWORD
listBase
//Specifies starting display list
   );
Parameters
hdc
Specifies the device context whose currently selected font will be used to form the glyph bitmap display lists in the current OpenGL rendering context.
first
Specifies the glyph of the font that is the first element of a run of glyphs that will be used to form glyph bitmap display lists.
count
Specifies the number of glyphs in the run of glyphs that will be used to form glyph bitmap display lists. The function creates
count
 display lists, one for each glyph in the run.
listBase
Specifies a starting display list.
Return Value
If the function succeeds, the return value is TRUE.
If the function fails, the return value is FALSE. Call
GetLastError
 for extended error information.
Remarks
The
wglUseFontBitmaps
 function defines
count
 display lists in the current OpenGL rendering context. Each display list has an identifying number, starting at
listBase
. Each display list consists of a single call to
glBitmap
. The definition of bitmap
listBase
+
i
 is taken from the glyph
first
+
i
 of the font currently selected in the device context specified by
hdc
. If a glyph is not defined, then the function defines an empty display list for it.
The function creates bitmap text in the plane of the screen. It enables the labeling of objects in OpenGL.
The current version of Microsoft's implementation of OpenGL in Windows NT does not allow GDI calls to be made to a device context whose pixel format is double-buffered. That precludes an application from using the GDI fonts and text functions with such device contexts. The
wglUseFontBitmaps
 function lets an application circumvent this limitation and draw text in a double-buffered device context.
The function determines the parameters of each call to
glBitmap
 as follows:
glBitmap parameter
Determination
width
The width of the glyph's bitmap, as returned in the
gmBlackBoxX
 field of the glyph's
GLYPHMETRICS
 structure.
height
The height of the glyph's bitmap, as returned in the
gmBlackBoxY
 field of the glyph's
GLYPHMETRICS
 structure.
xorig
The x offset of the glyph's origin, as returned in the
gmptGlyphOrigin.x
 field of the glyph's
GLYPHMETRICS
 structure.
yorig
The y offset of the glyph's origin, as returned in the
gmptGlyphOrigin.y
 field of the glyph's
GLYPHMETRICS
 structure.
xmove
The horizontal distance to the origin of the next character cell, as returned in the
gmCellIncX
 field of the glyph's
GLYPHMETRICS
 structure.
ymove
The vertical distance to the origin of the next character cell as returned in the
gmCellIncY
 field of the glyph's
GLYPHMETRICS
 structure.
bitmap
The bitmap for the glyph, as returned by
GetGlyphOutline
 with
uFormat
 equal to 1.
Here's a skeletal example that shows how to draw some text:
HDC    hdc;
HGLRC    hglrc;
// create a rendering context
hglrc = wglCreateContext (hdc);
// make it the calling thread's current rendering context
wglMakeCurrent (hdc, hglrc);
// now we can call OpenGL API
// make the system font the device context's selected font
SelectObject (hdc, GetStockObject (SYSTEM_FONT));
// create the bitmap display lists
// we're making images of glyphs 0 thru 255
// the display list numbering starts at 1000, an arbitrary choice
wglUseFontBitmaps (hdc, 0, 255, 1000);
// display a string:
// indicate start of glyph display lists
glListBase (1000);
// now draw the characters in a string
glCallLists (24, GL_UNSIGNED_BYTE, "Hello Win32 OpenGL World");
See Also
glListBase
,
glCallLists
,
wglUseFontOutlines


wglUseFontOutlines
The
wglUseFontOutlines
function creates a set of display lists based on the glyphs of the currently selected outline font of a device context for use with the current rendering context. The display lists are used to draw 3D characters of True Type fonts.
wglUseFontOutlines
 creates
count
 display lists, one for each glyph of a run of
count
 glyphs The run of glyphs begins with the
first
 glyph of the font of the specified device context,
hdc
. Each display list describes a glyph outline in floating point coordinates. The em square size of the font, the notional grid size of the original font outline from which the font is fitted, is mapped to 1.0 in the
x
 and
y
 directions in the display lists. The extrusion parameter sets how much depth the font has in the
z
 direction.
The parameter
lpgmf
 returns a
GLYPHMETRICSFLOAT
 structure that contains information about the placement and orientation of each glyph in a character cell.
BOOL wglUseFontOutlines(
    HDC
hdc
,
//Device context of the outline font
    DWORD
first
,
//First glyph to be turned into a display list
    DWORD
count
,
//Number of glyphs to be turned into display lists
    DWORD
listBase
,
//Specifies the starting display list
    FLOAT
deviation
,
//Specifies the maximum chordal deviation from the true outlines
    FLOAT
extrusion
,
//Extrusion value in the negative
z
 direction
    int
format
,
//Specifies line segments or polygons in display lists
    LPGLYPHMETRICSFLOAT
lpgmf
//Address of buffer to receive glyphs metric data
   );
Parameters
hdc
Specifies the device context with the desired outline font. The outline font of
hdc
 is used to create the display lists in the current rendering context.
first
Specifies the glyph of the font that is the first element of the set of glyphs that form the font outline display lists.
count
Specifies the number of glyphs in the set of glyphs used to form the font outline display lists.
wglUseFontOutlines
 creates
count
 display lists, one display list for each glyph in a set of glyphs.
listBase
Specifies a starting display list.
deviation
Specifies the maximum chordal deviation from the original outlines. When deviation is 0, the chordal deviation is equivalent to one design unit of the original font. The value of
deviation
 must be equal to or greater than 0
extrusion
Specifies the amount a font is extruded in the negative
z
 direction. The value must be equal to or greater than 0. When
extrusion
 is 0, the display lists are not extruded.
format
Specifies the format, either WGL_FONT_LINES or WGL_FONT_POLYGONS, to use in the display lists. When
format
 is WGL_FONT_LINES,
wglUseFontOutlines
 creates fonts with line segments and when
format
 is WGL_FONT_POLYGONS,
wglUseFontOutlines
 creates fonts with polygons.
lpgmf
Points to an array of
count
GLYPHMETRICSFLOAT
 structures that is to receive the metrics of the glyphs. When
lpgmf
 is NULL, no glyph metrics are returned.
Return Value
When the function succeeds, the return value is TRUE.
When the function fails, the return value is FALSE and no display lists are generated. Call
GetLastError
 for extended error information.
Remarks
The
 wglUseFontOutlines
 function defines the glyphs of an outline font with display lists in the current rendering context. The outline font of the currently selected device context,
hdc
, is the model
wglUseFontOutlines
 uses to define glyphs.
wglUseFontOutlines
 works with True Type fonts only; stroke and raster fonts are not supported.
The parameter
count
 specifies the total number of glyphs generated, each with its own display list. Each display list consists of either line segments or polygons;
format
 specifies which method is used. Each display list has a unique identifying number starting with the number
listBase
. The first glyph in the set of glyphs is specified with the
first
 parameter.
wglUseFontOutlines
 approximates glyph outlines by subdividing the quadratic B-spline curves of the outline into line segments until the distance between the outline and the interpolated midpoint is within the value specified by
deviation
. This is the final format used when
format
 is WGL_FONT_LINES. When you specify
format
 as WGL_FONT_POLYGONS the outlines are further tessellated into separate triangles, triangle fans, triangle strips, or quadrilateral strips to create the surface of each glyph.
A GLYPHMETRICSFLOAT structure contains information about the placement and orientation of each glyph in a character cell. The parameter
lpgmf
 is an array of GLYPHMETRICSFLOAT structures holding the entire set of glyphs for a font. Each display list ends with a translation specified with the
gmfCellIncX
 and
gmfCellIncY
 fields of the corresponding GLYPHMETRICSFLOAT structure. The translation enables the drawing of successive characters in their natural direction with a single call to
glCallLists
.
Note
  The current release of OpenGL for Windows NT does not permit you to make GDI calls to a device context when a pixel format is double-buffered. You can get around this limitation using
wglUseFontOutlines
 and
wglUseFontBitmaps
, when using double-buffered device contexts.
The following sample code shows how to draw text using
wglUseFontOutlines
:
HDC  hdc;  // A TrueType font has already been selected.
HGLRC  hglrc;
GLYPHMETRICSFLOAT agmf[256];
// Make hglrc the calling thread's current rendering context.
wglMakeCurrent(hdc, hglrc);
//create display lists for glyphs 0 through 255 with 0.1 extrusion
// and default deviation. The display list numbering starts at 1000
// (it could be any number).
wglUseFontOutlines(hdc, 0, 255, 1000, 0.0f, 0.1f,
            WGL_FONT_POLYGONS, &agmf);
// Set up transformation to draw the string.
glLoadIdentity();
glTranslate(0.0f, 0.0f, -5.0f)
glScalef(2.0f, 2.0f, 2.0f);
// Display a string:
glListBase(1000); // indicate the start of display lists for the glyphs.
// Draw the characters in a string.
glCallLists(24, GL_UNSIGNED_BYTE, "Hello Win32 OpenGL World.");
See Also
GLYPHMETRICSFLOAT
,
wglUseFontBitmaps
,
glListBase
,
glCallLists
,
glTexGen


GLYPHMETRICSFLOAT
typedef struct _GLYPHMETRICSFLOAT { // gmf
    FLOAT      gmfBlackBoxX;
    FLOAT      gmfBlackBoxY;
    POINTFLOAT gmfptGlyphOrigin;
    FLOAT      gmfCellIncX;
    FLOAT      gmfCellIncY;
} GLYPHMETRICSFLOAT;
The
GLYPHMETRICSFLOAT
 structure contains information about the placement and orientation of a glyph in a character cell.
Members
gmfBlackBoxX
Specifies the width of the smallest rectangle (its black box) that completely encloses the glyph.
gmfBlackBox
Specifies the height of the smallest rectangle (its black box) that completely encloses the glyph.
gmfptGlyphOrigin
Specifies the x and y coordinates of the upper left corner of the smallest rectangle that completely encloses the glyph..
gmfCellIncX
Specifies the horizontal distance from the origin of the current character cell to the origin of the next character cell.
gmfCellIncY
Specifies the vertical distance from the origin of the current character cell to the origin of the next character cell.:
Remarks
The values of
GLYPHMETRICSFLOAT
 are specified as notional units.
See Also
wglUseFontOutlines
,
POINTFLOAT


POINTFLOAT
typedef struct _POINTFLOAT { // ptf
    FLOAT      x;
    FLOAT      y;
} POINTFLOAT;
The
POINTFLOAT
 structure contains the x and y coordinates of a point.
Members
x
Specifies the horizontal (x) coordinate of a point.
y
Specifies the vertical (y) coordinate of a point.
See Also
GLYPHMETRICSFLOAT


The OpenGL Utility Library
OpenGL provides a small but powerful set of drawing operations, and all higher-level drawing requires their use. To help simplify some of your programming tasks, the OpenGL Utility Library (GLU) includes several routines that encapsulate OpenGL commands. Consult the
OpenGL Reference Manual
 for more detailed descriptions of these routines. This section groups them functionally as follows:
·
Initialization
·
Manipulating Images for Use in Texturing
·
Transforming Coordinates
·
Tessellation
·
Rendering Spheres, Cylinders, and Disks
·
NURBS Curves and Surfaces
·
Describing Errors
Initialization
With GLU version 1.1 or later you can use a routine that returns the version number of GLU library or that returns the version number and any vendor-specific GLU extension calls (
gluGetString
).
const GLubyte *
gluGetString
(GLenum
name
);


Manipulating Images for Use in Texturing
As you set up texture mapping in your application, you'll probably want to take advantage of mipmapping, which requires a series of reduced images (or texture maps). To support mipmapping, the GLU includes a general routine that scales images (
gluScaleImage
) and routines that generate a complete set of mipmaps given an original image in one or two dimensions (
gluBuild1DMipmaps
 and
gluBuild2DMipmaps
).
GLint
gluScaleImage(
GLenum
format
,
 GLint
widthin
,
 GLint
heightin
,
GLenum
typein
,
 const void
*
datain
,
GLint
widthout
,
 GLint
heightout
,
GLenum
typeout
,
 void
*
dataout
);
GLint
gluBuild1DMipmaps(
GLenum
target
,
 GLint
components
,
GLint
width
,
 GLenum
format
,
 GLenum
type
,
void
*
data
);
GLint
gluBuild2DMipmaps(
GLenum
target
,
 GLint
components
,
GLint
width
,
 GLint
height
,
 GLenum
format
,
GLenum
type
,
 void
*
data
);


Transforming Coordinates
The GLU includes routines that create matrices for standard perspective and orthographic viewing (
gluPerspective
 and
gluOrtho2D
). In addition, a viewing routine allows you to position your eye at any point in space and look at any other point (
gluLookAt
). In addition, the GLU includes a routine to help you create a picking matrix (
gluPickMatrix
). The prototypes for these four routines are listed here.
void
gluPerspective(
GLdouble
fovy
,
 GLdouble
aspect
,
 GLdouble
zNear
,
GLdouble
zFar
);
void
gluOrtho2D(
GLdouble
left
,
 GLdouble
right
,
 GLdouble
bottom
,
GLdouble
top
);
void
gluLookAt(
GLdouble
eyex
,
 GLdouble
eyey
,
 GLdouble
eyez
,
GLdouble
centerx
,
 GLdouble
centery
,
GLdouble
centerz
,
 GLdouble
upx
,
 GLdouble
upy
,
GLdouble
upz
);
void
gluPickMatrix(
GLdouble
x
,
 GLdouble
y
,
 GLdouble
width
,
GLdouble
height
,
 GLint
viewport
[4]);
In addition, GLU provides two routines that convert between object coordinates and screen coordinates,
gluProject
 and
gluUnProject
.
GLint
gluProject(
GLdouble
objx
,
 GLdouble
objy
,
 GLdouble
objz
,
const GLdouble
modelMatrix
[16]
,
const GLdouble
projMatrix
[16]
,
const GLint
viewport
[4]
,
 GLdouble
*
winx
,
GLdouble
*
winy
,
 GLdouble
*
winz
);
Transforms the specified object coordinates
objx
,
objy
, and
objz
into window coordinates using
modelMatrix
,
projMatrix
, and
viewport
. The result is stored in
winx
,
winy
, and
winz
. A return value of GL_TRUE indicates success, and GL_FALSE indicates failure.
GLint
gluUnProject(
GLdouble
winx
,
 GLdouble
winy
,
 GLdouble
winz
,
const GLdouble
modelMatrix
[16]
,
const GLdouble
projMatrix
[16]
,
const GLint
viewport
[4]
,
 GLdouble
*
objx
,
GLdouble
*
objy
,
 GLdouble
*
objz
);
Transforms the specified window coordinates
winx
,
winy
, and
winz
into object coordinates using
modelMatrix
,
projMatrix
, and
viewport
. The result is stored in
objx
,
objy
, and
objz
. A return value of GL_TRUE indicates success, and GL_FALSE indicates failure.


Tessellation
OpenGL can directly display only simple convex polygons. A polygon is simple if the edges intersect only at vertices, there are no duplicate vertices, and exactly two edges meet at any vertex. If your application requires the display of simple nonconvex polygons or of simple polygons containing holes, those polygons must first be subdivided into convex polygons before they can be displayed. Such subdivision is called
tessellation
. GLU provides a collection of routines that perform tessellation. Note that the GLU tessellation routines can't handle nonsimple polygons; there's no standard OpenGL method to handle such polygons.
Because tessellation is often required and can be rather tricky, this section describes the GLU tessellation routines in detail. These routines take as input arbitrary simple polygons that might include holes, and they return some combination of triangles, triangle meshes, and triangle fans. You can insist on triangles only if you don't want to have to deal with meshes or fans. If you care about performance, however, you should probably take advantage of any available mesh or fan information.


The Callback Mechanism
To tessellate a polygon using the GLU, first create a tessellation object, then provide a series of callback routines to be called at appropriate times during the tessellation. After specifying the callbacks, describe the polygon and any holes using GLU routines, which are similar to the OpenGL polygon routines. When the polygon description is complete, the tessellation facility invokes your callback routines as necessary.
The callback routines typically save the data for the triangles, triangle meshes, and triangle fans in user-defined data structures, or in OpenGL display lists. To render the polygons, other code traverses the data structures or calls the display lists. Although the callback routines could call OpenGL commands to display them directly, this is usually not done, as tessellation can be computationally expensive. It's a good idea to save the data if there is any chance that you want to display it again. The GLU tessellation routines are guaranteed never to return any new vertices, so interpolation of vertices, texture coordinates, or colors is never required.


The Tessellation Object
As a complex polygon is being described and tessellated, it has associated data, such as the vertices, edges, and callback functions. All this data is tied to a single tessellation object. To tessellate, your program must first create a tessellation object using the routine
gluNewTess
.
GLUtriangulatorObj
* gluNewTess(
void
);
Creates a new tessellation object and returns a pointer to it. A null pointer is returned if the creation fails.
If you no longer need a tessellation object, you can delete it and free all associated memory with
gluDeleteTess
.
void
gluDeleteTess(
GLUtriangulatorObj
*
tessobj
);
Deletes the specified tessellation object,
tessobj
, and frees all associated memory.
A single tessellation object can be reused for all your tessellations. This object is required only because library routines might be required to do their own tessellations, and they should be able to do so without interfering with any tessellation that your program is doing. It might also be useful to have multiple tessellation objects if you want to use different sets of callbacks for different tessellations. A typical program, however, allocates a single tessellation object and uses it for all its tessellations. There's no real need to free it because it uses a small amount of memory. On the other hand, if you're writing a library routine that uses the GLU tessellation, you'll want to be careful to free any tessellation objects you create.


Specifying Callbacks
You can specify up to five callback functions for a tessellation. Any functions that are omitted are simply not called during the tessellation, and any information they might have returned to your program is lost. All are specified by the single routine
gluTessCallback
.
void
gluTessCallback(
GLUtriangulatorObj
*
tessobj
,
 GLenum
type
,
void
(*
fn
)(
));
Associates the callback function fn with the tessellation object
tessobj
. The type of the callback is determined by the parameter
type
, which can be GLU_BEGIN, GLU_EDGE_FLAG, GLU_VERTEX, GLU_END, or GLU_ERROR. The five possible callback functions have the following prototypes:
GLU_BEGIN
void
begin(
GLenum
type
);
GLU_EDGE_FLAG
void
edgeFlag(
GLboolean
flag
);
GLU_VERTEX
void
vertex(
void
*
data
);
GLU_END
void
end(
void
);
GLU_ERROR
void
error(
GLenum
errno
);
To change a callback routine, simply call
gluTessCallback
 with the new routine. To eliminate a callback routine without replacing it with a new one, pass
gluTessCallback
 a null pointer for the appropriate function.
As tessellation proceeds, these routines are called in a manner similar to the way you would use the OpenGL commands
glBegin
,
glEdgeFlag
,
glVertex
, and
glEnd
. The error callback is invoked during the tessellation only if something goes wrong.
The GLU_BEGIN callback is invoked with one of three possible parameters: GL_TRIANGLE_FAN, GL_TRIANGLE_STRIP, or GL_TRIANGLES. After this routine is called, and before the callback associated with GLU_END is called, some combination of the GLU_EDGE_FLAG and GLU_VERTEX callbacks is invoked. The associated vertices and edge flags are interpreted exactly as they are in OpenGL between
glBegin(GL_TRIANGLE_FAN)
,
glBegin(GL_TRIANGLE_STRIP)
, or
glBegin(GL_TRIANGLES)
 and the matching
glEnd
. Since edge flags make no sense in a triangle fan or triangle strip, if there is a callback associated with GLU_EDGE_FLAG, the GLU_BEGIN callback is called only with GL_TRIANGLES. The GLU_EDGE_FLAG callback works exactly analogously to the OpenGL
glEdgeFlag
 call.
The error callback is passed a GLU error number. A character string describing the error can be obtained using the routine
gluErrorString
.


Describing the Polygon to Be Tessellated
The polygon to be tessellated, possibly containing holes, is specified using the following four routines:
gluBeginPolygon
,
gluTessVertex
,
gluNextContour
, and
gluEndPolygon
. For polygons without holes, the specification is exactly as in OpenGL: start with
gluBeginPolygon
, call
gluTessVertex
 for each vertex in the boundary, and end the polygon with a call to
gluEndPolygon
. If a polygon consists of multiple contours, including holes and holes within holes, the contours are specified one after the other, each preceded by
gluNextContour
. When
gluEndPolygon
 is called, it signals the end of the final contour and starts the tessellation. You can omit the call to
gluNextContour
 before the first contour. The detailed descriptions of these functions follow.
void
gluBeginPolygon(
GLUtriangulatorObj
*
tessobj
);
Begins the specification of a polygon to be tessellated and associates a tessellation object,
tessobj
, with it. The callback functions to be used are those that were bound to the tessellation object using the routine
gluTessCallback
.
void
gluTessVertex
(
GLUtriangulatorObj
*
tessobj
,
GLdouble
v
[3]
,
 void
*
data
);
Specifies a vertex in the polygon to be tessellated. Call this routine for each vertex in the polygon to be tessellated.
tessobj
 is the tessellation object to use,
v
contains the three-dimensional vertex coordinates, and
data
is an arbitrary pointer that is sent to the callback associated with GLU_VERTEX. Typically, it contains vertex data, texture coordinates, color information, or whatever else the application may require.
void
gluNextContour(
GLUtriangulatorObj
*
tessobj
,
 GLenum
type
);
Marks the beginning of the next contour when multiple contours make up the boundary of the polygon to be tessellated.
type
 can be GLU_EXTERIOR, GLU_INTERIOR, GLU_CCW, GLU_CW, or GLU_UNKNOWN. These serve only as hints to the tessellation. If you get them right, the tessellation might go faster. If you get them wrong, they're ignored, and the tessellation still works. For a polygon with holes, one contour is the exterior contour and the others interior.
gluNextContour
 can be called immediately after
gluBeginPolygon
, but if it isn't, the first contour is assumed to be of type GLU_EXTERIOR. GLU_CW and GLU_CCW indicate clockwise- and counterclockwise- oriented polygons. Choosing which are clockwise and which are counterclockwise is arbitrary in three dimensions, but in any plane, there are two different orientations, and the GLU_CW and GLU_CCW types should be used consistently. Use GLU_UNKNOWN if you don't know which to use.
void
gluEndPolygon(
GLUtriangulatorObj
*
tessobj
);
Indicates the end of the polygon specification and that the tessellation can begin using the tessellation object
tessobj
.


Rendering Spheres, Cylinders, and Disks
The GLU includes a set of routines for drawing various simple surfaces (spheres, cylinders, disks, and parts of disks) in a variety of styles and orientations. These routines are described in detail in the
OpenGL Reference Manual
; their use is discussed briefly in the following paragraphs, and their prototypes are also listed.
To create a quadric object, use
gluNewQuadric
. (To destroy this object when you're finished with it, use
gluDeleteQuadric
.) Then specify the desired rendering style, as follows, with the appropriate routine (unless you're satisfied with the default values):
·
Whether surface normals should be generated, and if so, whether there should be one normal per vertex or one normal per face:
gluQuadricNormals
.
·
Whether texture coodinates should be generated:
gluQuadricTexture
.
·
Which side of the quadric should be considered the outside and which the inside:
gluQuadricOrientation
.
·
Whether the quadric should be drawn as a set of polygons, lines, or points:
gluQuadricDrawStyle
.
After you've specified the rendering style, simply invoke the rendering routine for the desired type of quadric object:
gluSphere
,
gluCylinder
,
gluDisk
, or
gluPartialDisk
. If an error occurs during rendering, the error-handling routine you've specified with
gluQuadricCallBack
 is invoked.
It's better to use the
*
Radius
,
height
, and similar arguments to scale the quadrics rather than the
glScale
 command, so that unit-length normals that are generated don't have to be renormalized. Set the
loops
and
stacks
arguments to values other than 1 to force lighting calculations at a finer granularity, especially if the material specularity is high.
The prototypes are listed in three categories.
Manage quadric objects:
GLUquadricObj
*
gluNewQuadric
(void);
void
gluDeleteQuadric (
GLUquadricObj
*
state
);
void
gluQuadricCallback (
GLUquadricObj
*
qobj
,
 GLenum
which
,
void
(*
fn
)( ));
Control the rendering:
void
gluQuadricNormals (
GLUquadricObj
*
quadObject
,
GLenum
normals
);
void
gluQuadricTexture (
GLUquadricObj
*
quadObject
,
GLboolean
textureCoords
);
void
gluQuadricOrientation (
GLUquadricObj
*
quadObject
,
GLenum
orientation
);
void
gluQuadricDrawStyle (
GLUquadricObj
*
quadObject
,
GLenum
drawStyle
);
Specify a quadric primitive:
void
gluCylinder (
GLUquadricObj
*
qobj
,
 GLdouble
baseRadius
,
GLdouble
topRadius
,
 GLdouble
height
,
 GLint
slices
,
GLint
stacks
);
void
gluDisk (
GLUquadricObj
*
qobj
,
 GLdouble
innerRadius
,
GLdouble
outerRadius
,
GLint
slices
,
 GLint
loops
);
void
gluPartialDisk (
GLUquadricObj
*
qobj
,
 GLdouble
innerRadius
,
GLdouble
outerRadius
,
 GLint
slices
,
 GLint
loops
,
GLdouble
startAngle
,
 GLdouble
sweepAngle
);
void
gluSphere (
GLUquadricObj
*
qobj
,
 GLdouble
radius
,
 GLint
slices
,
GLint
stacks
);


NURBS Curves and Surfaces
NURBS routines provide general and powerful descriptions of curves and surfaces in two and three dimensions. They're used to represent geometry in many computer-aided mechanical design systems. The GLU NURBS routines can render such curves and surfaces in a variety of styles, and they can automatically handle adaptive subdivision that tessellates the domain into smaller triangles in regions of high curvature and near silhouette edges.
Manage a NURBS object:
GLUnurbsObj
* gluNewNurbsRenderer (
void
);
void
gluDeleteNurbsRenderer (
GLUnurbsObj
*
nobj
);
void
gluNurbsCallback (
GLUnurbsObj
*
nobj
,
 GLenum
which
,
void
(*
fn
)(
));
Create a NURBS curve:
void
gluBeginCurve (
GLUnurbsObj
*
nobj
);
void
gluEndCurve (
GLUnurbsObj
*
nobj
);
void
gluNurbsCurve (
GLUnurbsObj
*
nobj
,
 GLint
nknots
,
 GLfloat
*
knot
,
GLint
stride
,
 GLfloat
*
ctlarray
,
GLint
order
,
 GLenum
type
);
Create a NURBS surface:
void
gluBeginSurface (
GLUnurbsObj
*
nobj
);
void
gluEndSurface (
GLUnurbsObj
*
nobj
);
void
gluNurbsSurface (
GLUnurbsObj
*
nobj
,
 GLint
uknot_count
,
GLfloat
*
uknot
,
 GLint
vknot_count
,
 GLfloat
*
vknot
,
GLint
u_stride
,
 GLint
v_stride
,
 GLfloat
*
ctlarray
,
GLint
uorder
,
 GLint
vorder
,
 GLenum
type
);
Define a trimming region:
void
gluBeginTrim (
GLUnurbsObj
*
nobj
);
void
gluEndTrim (
GLUnurbsObj
*
nobj
);
void
gluPwlCurve (
GLUnurbsObj
*
nobj
,
 GLint
count
,
 GLfloat
*
array
,
GLint
stride
,
 GLenum
type
);
Control NURBS rendering:
void
gluLoadSamplingMatrices (
GLUnurbsObj
*
nobj
,
const GLfloat
modelMatrix
[16]
,
const GLfloat
projMatrix
[16]
,
const GLint
viewport
[4]
);
void
gluNurbsProperty (
GLUnurbsObj
*
nobj
,
 GLenum
property
,
GLfloat
value
);
void
gluGetNurbsProperty (
GLUnurbsObj
*
nobj
,
 GLenum
property
,
GLfloat
*
value
);


Describing Errors
The GLU provides a routine for obtaining a descriptive string for an error code.
const GLubyte
*
gluErrorString
(
GLenum
errorCode
);
Returns a pointer to a descriptive string that corresponds to the OpenGL, GLU, or GLX error number passed in
errorCode
. The defined error codes are described in the
OpenGL Reference Manual
along with the command or routine that can generate them.


Programming Tips
This section lists some tips and guidelines that you might find useful. Keep in mind that these tips are based on the intentions of the designers of the OpenGL, not on any experience with actual applications and implementations! This section has the following major topics:
·
OpenGL Correctness Tips
·
OpenGL Performance Tips


OpenGL Correctness Tips
·
Do not count on the error behavior of an OpenGL implementation
¾
it might change in a future release of OpenGL. For example, OpenGL 1.0 ignores matrix operations invoked between
glBegin
 and
glEnd
 commands, but OpenGL 1.1 might not. OpenGL error semantics may change between upward-compatible revisions.
·
Use the projection matrix to collapse all geometry to a single plane. If the modelview matrix is used, OpenGL features that operate in eye coordinates (such as lighting and application-defined clipping planes) might fail.
·
Do not make extensive changes to a single matrix. For example, do not animate a rotation by continually calling
glRotate
 with an incremental angle. Rather, use
glLoadIdentity
 to initialize the given matrix for each frame, then call
glRotate
 with the desired complete angle for that frame.
·
Count on multiple passes through a rendering database to generate the same pixel fragments only if this behavior is guaranteed by the invariance rules established for a compliant OpenGL implementation. Otherwise, a different set of fragments might be generated.
·
Do not expect errors to be reported while a display list is being defined. The commands within a display list generate errors only when the list is executed.
·
Place the near frustum plane as far from the viewpoint as possible to optimize the operation of the depth buffer.
·
Call
glFlush
 to force all previous OpenGL commands to be executed. Do not count on
glGet
 or
glIs
 to flush the rendering stream. Query commands flush as much of the stream as is required to return valid data but don't guarantee to complete all pending rendering commands.
·
Turn dithering off when rendering predithered images (for example, when
glCopyPixels
 is called).
·
Make use of the full range of the accumulation buffer. For example, if accumulating four images, scale each by one-quarter as it's accumulated.
·
If exact two-dimensional rasterization is desired, you must carefully specify both the orthographic projection and the vertices of primitives that are to be rasterized. The orthographic projection should be specified with integer coordinates, as shown in the following example:
gluOrtho2D(0, width, 0, height);
where
width
 and
height
are the dimensions of the viewport. Given this projection matrix, polygon vertices and pixel image positions should be placed at integer coordinates to rasterize predictably. For example,
glRecti(0, 0, 1, 1)
 reliably fills the lower-left pixel of the viewport, and
glRasterPos2i(0, 0)
 reliably positions an unzoomed image at the lower left of the viewport. Point vertices, line vertices, and bitmap positions should be placed at half-integer locations, however. For example, a line drawn from (
x
 (1)
, 0.5) to (
x
 (2)
, 0.5) will be reliably rendered along the bottom row of pixels int the viewport, and a point drawn at (0.5, 0.5) will reliably fill the same pixel as
glRecti(0, 0, 1, 1)
.
An optimum compromise that allows all primitives to be specified at integer positions, while still ensuring predictable rasterization, is to translate
x
and
y
by 0.375, as shown in the following code fragment. Such a translation keeps polygon and pixel image edges safely away from the centers of pixels, while moving line vertices close enough to the pixel centers.
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity( );
gluOrtho2D(0, width, 0, height);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity( );
glTranslatef(0.375, 0.375, 0.0);
/* render all primitives at integer positions */
·
Avoid using negative
w
 vertex coordinates and negative
q
 texture coordinates. OpenGL might not clip such coordinates correctly and might make interpolation errors when shading primitives defined by such coordinates.


OpenGL Performance Tips
·
Use
glColorMaterial
 when only a single material property is being varied rapidly (at each vertex, for example). Use
glMaterial
 for infrequent changes, or when more than a single material property is being varied rapidly.
·
Use
glLoadIdentity
 to initialize a matrix, rather than loading your own copy of the identity matrix.
·
Use specific matrix calls such as
glRotate
,
glTranslate
, and
glScale
, rather than composing your own rotation, translation, and scale matrices and calling
glMultMatrix
.
·
Use
glPushAttrib
 and
glPopAttrib
 to save and restore state values. Use query functions only when your application requires the state values for its own computations.
·
Use display lists to encapsulate potentially expensive state changes. For example, place all the
glTexImage
 calls required to completely specify a texture, and perhaps the associated
glTexParameter
,
glPixelStore
, and
glPixelTransfer
 calls as well, into a single display list. Call this display list to select the texture.
·
Use display lists to encapsulate the rendering calls of rigid objects that will be drawn repeatedly.
·
Use evaluators even for simple surface tessellations to minimize network bandwidth in client-server environments.
·
Provide unit-length normals if possible, and avoid the overhead of GL_NORMALIZE. Avoid using
glScale
 when doing lighting because it almost always requies that GL_NORMALIZE be enabled.
·
Set
glShadeModel
 to GL_FLAT if smooth shading isn't required.
·
Use a single
glClear
 call per frame if possible. Do not use
glClear
 to clear small subregions of the buffers; use it only for complete or near-complete clears.
·
Use a single call to
glBegin
(GL_TRIANGLES)
 to draw multiple independent triangles, rather than calling
glBegin(GL_TRIANGLES)
 multiple times, or calling
glBegin(GL_POLYGON)
. Even if only a single triangle is to be drawn, use GL_TRIANGLES rather than GL_POLYGON. Use a single call to
glBegin(GL_QUADS)
 in the same manner, rather than calling
glBegin(GL_POLYGON)
 repeatedly. Likewise, use a single call to
glBegin(GL_LINES)
 to draw multiple independent line segments, rather than calling
glBegin(GL_LINES)
 multiple times.
·
In general, use the vector forms of commands to pass precomputed data, and use the scalar forms of commands to pass values that are computed near call time.
·
Avoid making redundant mode changes, such as setting the color to the same value between each vertex of a flat-shaded polygon.
·
Be sure to disable expensive rasterization and per-fragment operations when drawing or copying images. OpenGL will apply textures to pixel images if asked to do so.


The Query Commands
There are four commands for obtaining simple state variables, and one for determining whether a particular state is enabled or disabled.
void
glGetBooleanv
(GLenum
pname
, GLboolean *
params
);
void
glGetIntegerv
(GLenum
pname
, GLint *
params
);
void
glGetFloatv
(GLenum
pname
, GLfloat *
params
);
void
glGetDoublev
(GLenum
pname
, GLdouble *
params
);
Obtains Boolean, integer, floating-point, or double-precision state variables. The
pname
 argument is a symbolic constant indicating the state variable to return, and
params
 is a pointer to an array of the indicated type in which to place the returned data. The possible values for
pname
 are listed in
OpenGL State Variables
. A type conversion is performed if necessary to return the desired variable as the requested data type.
GLboolean
glIsEnabled
(GLenum
cap
);
Returns GL_TRUE if the mode specified by
cap
 is enabled; otherwise, returns GL_FALSE. The possible values for
cap
 are listed in
OpenGL State Variables
.
Other specialized commands return specific state variables. The prototypes for these commands are listed here. To find out when to use these commands, see
OpenGL State Variables
. Also see the
OpenGL Reference Manual
. OpenGL's error handling facility and the
glGetError
 command are described in more detail in
Error Handling
.
void
glGetClipPlane
(GLenum
plane
,GLdouble *
equation
);
GLenum
glGetError
(void);
void
glGetLight
{if}
v
(GLenum
light
,GLenum
pname
,
TYPE
 *
params
);
void
glGetMap
{ifd}
v
(GLenum
target
,GLenum
query
TYPE
 *
v
);
void
glGetMaterial
{if}
v
(GLenum
face
,GLenum
pname
,
TYPE
 *
params
);
void
glGetPixelMap
{if ui us}
v
(GLenum
map
,
TYPE
 *
values
);
void
glGetPolygonStipple
(GLubyte *
mask
);
void
glGetPolygonStipple
(GLubyte *
mask
);
const GLubyte *
glGetString
(GLenum
 name
);
void
glGetTexEnv
{if}
v
(GLenum
target
, GLenum
pname
,
TYPE
 *
params
);
void
glGetTexGen
{ifd}
v
(GLenum
coord,
GLenum
pname
,
TYPE
 *
params
);
void
glGetTexImage
(GLenum
target
, GLint
level
, GLenum
format,
 GLenum
type,
 GLvoid *
pixels
);
void
glGetTexLevelParameter
{if}
v
(GLenum
target
, GLint
level
, GLenum
pname
,
TYPE
 *
params
);
void
glGetTexParameter
{if}
v
(GLenum
target
,GLenum
pname
,
TYPE
 *
params
);


Error Handling
When OpenGL detects an error, it records a current error code. The command that caused the error is ignored, so it has no effect on OpenGL state or on the frame-buffer contents. (If the error recorded was GL_OUT_OF_MEMORY, however, the results of the command are undefined.) Once recorded, the current error code isn't cleared until you call the query command
glGetError
, which returns the current error code.
Distributed implementations of OpenGL may return multiple current error codes, each of which remains set until queried. The
glGetError
 function returns GL_NO_ERROR once you've queried all the current error codes, or if there's no error, so if you obtain an error code, it's a good practice to call
glGetError
 until GL_NO_ERROR is returned to be sure you've discovered all the errors. See
OpenGL error codes
.
You can use the GLU routine
gluErrorString
 to obtain a descriptive string corresponding to the error code passed in. This routine is described in more detail in
Describing Errors
. Notice that GLU routines often return error values if an error is detected. Also, the GLU defines the error codes GLU_INVALID_ENUM, GLU_INVALID_VALUE, and GLU_OUT_OF_MEMORY, which have the same meaning as the related OpenGL codes.


OpenGL Error Codes
Error Code
Description
GL_INVALID_ENUM
GLenum argument out of range
GL_INVALID_VALUE
Numeric argument out of range
GL_INVALID_OPERATION
Operation illegal in current state
GL_STACK_OVERFLOW
Command would cause a stack overflow
GL_STACK_UNDERFLOW
Command would cause a stack underflow
GL_OUT_OF_MEMORY
Not enough memory left to execute command


Saving and Restoring Sets of State Variables
You can save and restore the values of a collection of state variables on an attribute stack with the commands
glPushAttrib
 and
glPopAttrib
. The attribute stack has a depth of at least 16, and the actual depth can be obtained using GL_MAX_ATTRIB_STACK_DEPTH with
glGetIntegerv
. Pushing a full stack or popping an empty one generates an error.
In general, it's faster to use
glPushAttrib
 and
glPopAttrib
 than to get and restore the values yourself. Some values might be pushed and popped in the hardware, and saving and restoring them might be expensive. Also, if you're operating on a remote client, all the attribute data must be transferred across the network connection and back as it's saved and restored. However, your OpenGL implementation keeps the attribute stack on the server, avoiding unnecessary network delays.
void
glPushAttrib
(GLbitfield
mask
);
Saves all the attributes indicated by bits in
mask
 by pushing them onto the attribute stack. The following Attribute Groups table lists the possible mask bits than can be logically ORed together to save any combination of attributes. Each bit corresponds to a collection of individual state variables. For example, GL_LIGHTING_BIT refers to all the state variables related to lighting, which include the current material color, the ambient, diffuse, specular, and emitted light, a list of the lights that are enabled, and the directions of the spotlights. When
glPopAttrib
 is called, all those variables are restored. To find out exactly which attributes are saved for particular mask values, see
OpenGL State Variables
.


Attribute Groups
Mask bit
Attribute group
GL_ACCUM_BUFFER_BIT
accum-buffer
GL_ALL_ATTRIB_BITS
¾
GL_COLOR_BUFFER_BIT
color-buffer
GL_CURRENT_BIT
current
GL_DEPTH_BUFFER_BIT
depth-buffer
GL_ENABLE_BIT
enable
GL_EVAL_BIT
eval
GL_FOG_BIT
fog
GL_HINT_BIT
hint
GL_LIGHTING_BIT
lighting
GL_LINE_BIT
line
GL_LIST_BIT
list
GL_PIXEL_MODE_BIT
pixel
GL_POINT_BIT
point
GL_POLYGON_BIT
polygon
GL_POLYGON_STIPPLE_BIT
polygon-stipple
GL_SCISSOR_BIT
scissor
GL_STENCIL_BUFFER_BIT
stencil-buffer
GL_TEXTURE_BIT
texture
GL_TRANSFORM_BIT
transform
GL_VIEWPORT_BIT
viewport
void
glPopAttrib
(void);
Restores the values of those state variables that were saved with the last
glPushAttrib
.


OpenGL State Variables
The following topics list the names of queryable state variables:
State Variables for Current Values and Associated Data
Transformation State Variables
Coloring State Variables
Lighting State Variables
Rasterization State Variables
Texturing State Variables
Pixel Operations
Framebuffer Control State Variables
Pixel State Variables
Evaluator State Variables
Hint State Variables
Implementation-Dependent State Variables
Implementation-Dependent Pixel-Depth State Variables
Miscellaneous State Variables
For each variable, the topic lists a description, attribute group, initial or minimum value, and the suggested
glGet
*
 command to use for obtaining it. State variables that can be obtained using
glGetBooleanv
,
glGetIntegerv
,
glGetFloatv
, or
glGetDoublev
 are listed with just one of these commands
¾
 the one that's most appropriate give the type of data to be returned. These state variables can't be obtained using
glIsEnabled
. However, state variables for which
glIsEnabled
 is listed as the query command can also be obtained using
glGetBooleanv( )
,
glGetIntegerv
,
glGetFloatv
, and
glGetDoublev
. State variables for which any other command is listed as the query command can be obtained only by using that command. If no attribute group is listed, the variable doesn't belong to any group. All queryable state variables except the implementation-dependent ones have initial values. If no initial value is listed, consult the topic where that variable is discussed.


State Variables for Current Values and Associated Data
GL_CURRENT_COLOR
Description:
Current color
Attribute Group:
current
Initial Value:
1,1,1,1
Get Command:
glGetIntegerv
glGetFloatv
GL_CURRENT_INDEX
Description:
Current color index
Attribute Group:
current
Initial Value:
1
Get Command:
glGetIntegerv
glGetFloatv
GL_CURRENT_TEXTURE_COORDS
Description:
Current texture coordinates
Attribute Group:
current
Initial Value:
0,0,0,1
Get Command:
glGetFloatv
GL_CURRENT_NORMAL
Description:
Current normal
Attribute Group:
current
Initial Value:
0,0,1
Get Command:
glGetFloatv
GL_CURRENT_RASTER POSITION
Description:
Current raster position
Attribute Group:
current
Initial Value:
0,0,0,1
Get Command:
glGetFloatv
GL_CURRENT_RASTER_DISTANCE
Description:
Current raster distance
Attribute Group:
current
Initial Value:
0
Get Command:
glGetFloatv
GL_CURRENT_RASTER_COLOR
Description:
Color associated with raster position
Attribute Group:
current
Initial Value:
1,1,1,1
Get Command:
glGetIntegerv
glGetFloatv
GL_CURRENT_RASTER_INDEX
Description:
Color index associated with raster position
Attribute Group:
current
Initial Value:
1
Get Command:
glGetIntegerv
glGetFloatv
GL_CURRENT_RASTER_TEXTURE_COORDS
Description:
Texture coordinates associated with raster position
Attribute Group:
current
Initial Value:
0,0,0,1
Get Command:
glGetFloatv
GL_CURRENT_RASTER_POSITION_VALID
Description:
Raster position valid bit
Attribute Group:
current
Initial Value:
GL_TRUE
Get Command:
glGetBoolean
GL_EDGE_FLAG
Description:
Edge flag
Attribute Group:
current
Initial Value:
GL_TRUE
Get Command:
glGetBoolean


Transformation State Variables
GL_MODELVIEW_MATRIX
Description:
Modelview matrix stack
Attribute Group:
¾
Initial Value:
Identity
Get Command:
glGetFloatv
GL_PROJECTION_MATRIX
Description:
Projection matrix stack
Attribute Group:
¾
Initial Value:
Identity
Get Command:
glGetFloatv
GL_TEXTURE_MATRIX
Description:
Texture matrix stack
Attribute Group:
¾
Initial Value:
Identity
Get Command:
glGetFloatv
GL_VIEWPORT
Description:
Viewport origin and extent
Attribute Group:
viewport
Initial Value:
¾
Get Command:
glGetIntegerv
GL_DEPTH_RANGE
Description:
Depth range near and far
Attribute Group:
viewport
Initial Value:
0,1
Get Command:
glGetFloatv
GL_MODELVIEW_STACK_DEPTH
Description:
Modelview matrix stack pointer
Attribute Group:
¾
Initial Value:
1
Get Command:
glGetIntegerv
GL_PROJECTION_STACK_DEPTH
Description:
Projection matrix stack pointer
Attribute Group:
¾
Initial Value:
1
Get Command:
glGetIntegerv
GL_TEXTURE_STACK_DEPTH
Description:
Texture matrix stack pointer
Attribute Group:
¾
Initial Value:
1
Get Command:
glGetIntegerv
GL_MATRIX_MODE
Description:
Current matrix mode
Attribute Group:
transform
Initial Value:
GL_MODELVIEW
Get Command:
glGetIntegerv
GL_NORMALIZE
Description:
Current normal normalization on/off
Attribute Group:
transform/enable
Initial Value:
GL_FALSE
Get Command:
glIsEnabled
GL_CLIP_PLANE
i
Description:
User clipping plane coefficients
Attribute Group:
transform
Initial Value:
0,0,0,0
Get Command:
glGetClipPlane
GL_CLIP_PLANE
i
Description:
i
th user clipping plane enabled
Attribute Group:
transform/enable
Initial Value:
GL_FALSE
Get Command:
glIsEnabled


Coloring State Variables
GL_FOG_COLOR
Description:
Fog color
Attribute Group:
fog
Initial Value:
0,0,0,0
Get Command:
glGetFloatv
GL_FOG_INDEX
Description:
Fog index
Attribute Group:
fog
Initial Value:
0
Get Command:
glGetFloatv
GL_FOG_DENSITY
Description:
Exponential fog density
Attribute Group:
fog
Initial Value:
1.0
Get Command:
glGetFloatv
GL_FOG_START
Description:
Linear fog start
Attribute Group:
fog
Initial Value:
0.0
Get Command:
glGetFloatv
GL_FOG_END
Description:
Linear fog end
Attribute Group:
fog
Initial Value:
1.0
Get Command:
glGetFloatv
GL_FOG_MODE
Description:
Fog mode
Attribute Group:
fog
Initial Value:
GL_EXP
Get Command:
glGetIntegerv
GL_FOG
Description:
True if fog enabled
Attribute Group:
fog/enable
Initial Value:
GL_FALSE
Get Command:
glIsEnabled
GL_SHADE_MODEL
Description:
glShadeModel setting
Attribute Group:
lighting
Initial Value:
GL_SMOOTH
Get Command:
glGetIntegerv


Lighting State Variables
GL_LIGHTING
Description:
True if lighting is enabled
Attribute Group:
lighting/enable
Initial Value:
GL_FALSE
Get Command:
glIsEnabled
GL_COLOR_MATERIAL
Description:
True if color tracking is enabled
Attribute Group:
lighting
Initial Value:
GL_FALSE
Get Command:
glIsEnabled
GL_COLOR_MATERIAL_PARAMETER
Description:
Material properties tracking current color
Attribute Group:
lighting
Initial Value:
GL_AMBIENT_AND_DIFFUSE
Get Command:
glGetIntegerv
GL_COLOR_MATERIAL_FACE
Description:
Face(s) affected by color tracking
Attribute Group:
lighting
Initial Value:
GL_FRONT_AND_BACK
Get Command:
glGetIntegerv
GL_AMBIENT
Description:
Ambient material color
Attribute Group:
lighting
Initial Value:
(0.2, 0.2, 0.2, 1.0)
Get Command:
glGetMaterialfv
GL_DIFFUSE
Description:
Diffuse material color
Attribute Group:
lighting
Initial Value:
(0.8, 0.8, 0.8, 1.0)
Get Command:
glGetMaterialfv
GL_SPECULAR
Description:
Specular material color
Attribute Group:
lighting
Initial Value:
(0.0, 0.0, 0.0, 1.0)
Get Command:
glGetMaterialfv
GL_EMISSION
Description:
Emissive material color
Attribute Group:
lighting
Initial Value:
(0.0, 0.0, 0.0, 1.0)
Get Command:
glGet
GL_SHININESS
Description:
Specular exponent of material
Attribute Group:
lighting
Initial Value:
0.0
Get Command:
glGetMaterialfv
GL_LIGHT_MODEL_AMBIENT
Description:
Ambient scene color
Attribute Group:
lighting
Initial Value:
(0.2, 0.2, 0.2, 0.1)
Get Command:
glGetFloatv
GL_LIGHT_MODEL_LOCAL_VIEWER
Description:
Viewer is local
Attribute Group:
lighting
Initial Value:
GL_FALSE
Get Command:
glGetBoolean
GL_LIGHT_MODEL_TWO_SIDE
Description:
Use two-sided lighting
Attribute Group:
lighting
Initial Value:
GL_FALSE
Get Command:
glGetBooleanv
GL_AMBIENT
Description:
Ambient intensity of light
i
Attribute Group:
lighting
Initial Value:
(0.0, 0.0, 0.0, 1.0)
Get Command:
glGetLightfv
GL_DIFFUSE
Description:
Diffuse intensity of light
i
Attribute Group:
lighting
Initial Value:
¾
Get Command:
glGetLightfv
GL_SPECULAR
Description:
Specular intensity of light
i
Attribute Group:
lighting
Initial Value:
¾
Get Command:
glGetLightfv
GL_POSITION
Description:
Position of light
i
Attribute Group:
lighting
Initial Value:
(0.0, 0.0, 1.0, 0.0)
Get Command:
glGetLightfv
GL_CONSTANT_ATTENUATION
Description:
Constant attenuation factor
Attribute Group:
lighting
Initial Value:
1.0
Get Command:
glGetLightfv
GL_LINEAR_ATTENUATION
Description:
Linear attenuation factor
Attribute Group:
lighting
Initial Value:
0.0
Get Command:
glGetLightfv
GL_QUADRATIC_ATTENUATION
Description:
Quadratic attenuation factor
Attribute Group:
lighting
Initial Value:
0.0
Get Command:
glGetLightfv
GL_SPOT_DIRECTION
Description:
Spotlight direction of light
i
Attribute Group:
lighting
Initial Value:
(0.0, 0.0,
-
1.0)
Get Command:
glGetLightfv
GL_SPOT_EXPONENT
Description:
Spotlight exponent of light
i
Attribute Group:
lighting
Initial Value:
0.0
Get Command:
glGetLightfv
GL_SPOT_CUTOFF
Description:
Spotlight angle of light
i
Attribute Group:
lighting
Initial Value:
180.0
Get Command:
glGetLightfv
GL_LIGHT
i
Description:
True if light
i
 enabled
Attribute Group:
lighting/enable
Initial Value:
GL_FALSE
Get Command:
glIsEnabled
GL_COLOR_INDEXES
Description:
C
 (a)
,
C
 (d)
, and
C
 (s)
for color-index lighting
Attribute Group:
lighting/enable
Initial Value:
0, 1, 1
Get Command:
glGetFloatv


Rasterization State Variables
GL_POINT_SIZE
Description:
Point size
Attribute Group:
point
Initial Value:
1.0
Get Command:
glGetFloatv
GL_POINT_SMOOTH
Description:
Point aliasing on
Attribute Group:
point/enable
Initial Value:
GL_FALSE
Get Command:
glIsEnabled
GL_LINE_WIDTH
Description:
Line width
Attribute Group:
line
Initial Value:
1.0
Get Command:
glGetFloatv
GL_LINE_SMOOTH
Description:
Line antialiasing on
Attribute Group:
line/enable
Initial Value:
GL_FALSE
Get Command:
glIsEnabled
GL_LINE_STIPPLE_PATTERN
Description:
Line stipple
Attribute Group:
line
Initial Value:
1's
Get Command:
glGetIntegerv
GL_LINE_STIPPLE_REPEAT
Description:
Line stipple repeat
Attribute Group:
line
Initial Value:
1
Get Command:
glGetIntegerv
GL_LINE_STIPPLE
Description:
Line stipple enable
Attribute Group:
line/enable
Initial Value:
GL_FALSE
Get Command:
glIsEnabled
GL_CULL_FACE
Description:
Polygon culling enabled
Attribute Group:
polygon/enable
Initial Value:
GL_FALSE
Get Command:
glIsEnabled
GL_CULL_FACE_MODE
Description:
Cull front-/back-facing polygons
Attribute Group:
polygon
Initial Value:
GL_BACK
Get Command:
glGetIntegerv
GL_FRONT_FACE
Description:
Polygon front-face CW/CCW indicator
Attribute Group:
polygon
Initial Value:
GL_CCW
Get Command:
glGetIntegerv
GL_POLYGON_SMOOTH
Description:
Polygon antialiasing on
Attribute Group:
polygon/enable
Initial Value:
GL_FALSE
Get Command:
glIsEnabled
GL_POLYGON_MODE
Description:
Polygon rasterization mode (front and back)
Attribute Group:
polygon
Initial Value:
GL_FILL
Get Command:
glGetIntegerv
GL_POLYGON_STIPPLE
Description:
Polygon stipple enable
Attribute Group:
polygon/enable
Initial Value:
GL_FALSE
Get Command:
glIsEnabled
¾
Description:
Polygon stipple pattern
Attribute Group:
polygon-stipple
Initial Value:
1's
Get Command:
glGetPolygon-Stipple


Texturing State Variables
GL_TEXTURE_
x
Description:
True if
x
-D texturing enabled (
x
 is 1D or 2D)
Attribute Group:
texture/enable
Initial Value:
GL_FALSE
Get Command:
glIsEnabled
GL_TEXTURE
Description:
x
-D texture image at level of detail
i
Attribute Group:
¾
Initial Value:
¾
Get Command:
glGetTexImage
GL_TEXTURE_WIDTH
Description:
x
-D texture image
i
's width
Attribute Group:
¾
Initial Value:
0
Get Command:
glGetTexLevelParameter
GL_TEXTURE_HEIGHT
Description:
x
-D texture image
i
's height
Attribute Group:
¾
Initial Value:
0
Get Command:
glGetTexLevelParameter
GL_TEXTURE_BORDER
Description:
x
-D texture image
i
's border
Attribute Group:
¾
Initial Value:
0
Get Command:
glGetTexLevelParameter
GL_TEXTURE_COMPONENTS
Description:
Texture image components
Attribute Group:
¾
Initial Value:
1
Get Command:
glGetTexLevelParameter
GL_TEXTURE_BORDER_COLOR
Description:
Texture border color
Attribute Group:
texture
Initial Value:
0,0,0,0
Get Command:
glGetTexParameter
GL_TEXTURE_MIN_FILTER
Description:
Texture minification function
Attribute Group:
texture
Initial Value:
GL_NEAREST_MIPMAP_LINEAR
Get Command:
glGetGetTexParameter
GL_TEXTURE_MAG_FILTER
Description:
Texture magnification function
Attribute Group:
texture
Initial Value:
GL_LINEAR
Get Command:
glGetTexParameter
GL_TEXTURE_WRAP_
x
Description:
Texture wrap mode (
x
 is S or T)
Attribute Group:
texture
Initial Value:
GL_REPEAT
Get Command:
glGetTexParameter
GL_TEXTURE_ENV_MODE
Description:
Texture application function
Attribute Group:
texture
Initial Value:
GL_MODULATE
Get Command:
glGetTexEnviv
GL_TEXTURE_ENV_COLOR
Description:
Texture environment color
Attribute Group:
texture
Initial Value:
0,0,0,0
Get Command:
glGetTexEnvfv
GL_TEXTURE_GEN_
x
Description:
Texgen is enabled (
x
 is S, T, R, or Q)
Attribute Group:
texture/enable
Initial Value:
GL_FALSE
Get Command:
glIsEnabled
GL_EYE_LINEAR
Description:
Texgen plane equation coefficients
Attribute Group:
texture
Initial Value:
¾
Get Command:
glGetTexGenfv
GL_OBJECT_LINEAR
Description:
Texgen object linear coefficients
Attribute Group:
texture
Initial Value:
¾
Get Command:
glGetTexGenfv
GL_TEXTURE_GEN_MODE
Description:
Function used for texgen
Attribute Group:
texture
Initial Value:
GL_EYTE_LINEAR
Get Command:
glGetTexGeniv


Pixel Operations
GL_SCISSOR_TEST
Description:
Scissoring enabled
Attribute Group:
scissor/enable
Initial Value:
GL_FALSE
Get Command:
glIsEnabled
GL_SCISSOR_BOX
Description:
Scissor box
Attribute Group:
scissor
Initial Value:
¾
Get Command:
glGetGetIntegerv
GL_STENCIL_TEST
Description:
Stenciling enabled
Attribute Group:
stencil-buffer/enable
Initial Value:
GL_FALSE
Get Command:
glIsEnabled
GL_STENCIL_FUNC
Description:
Stencil function
Attribute Group:
stencil-buffer
Initial Value:
GL_ALWAYS
Get Command:
glGetIntegerv
GL_STENCIL_VALUE_MASK
Description:
Stencil mask
Attribute Group:
stencil-buffer
Initial Value:
1's
Get Command:
glGetIntegerv
GL_STENCIL_REF
Description:
Stencil reference value
Attribute Group:
stencil-buffer
Initial Value:
0
Get Command:
glGetIntegerv
GL_STENCIL_FAIL
Description:
Stencil fail action
Attribute Group:
stencil-buffer
Initial Value:
GL_KEEP
Get Command:
glGetIntegerv
GL_STENCIL_PASS_DEPTH_FAIL
Description:
Stencil depth buffer fail action
Attribute Group:
stencil-buffer
Initial Value:
GL_KEEP
Get Command:
glGetIntegerv
GL_STENCIL_PASS_DEPTH_PASS
Description:
Stencil depth buffer pass action
Attribute Group:
stencil-buffer
Initial Value:
GL_KEEP
Get Command:
glGetIntegerv
GL_ALPHA_TEST
Description:
Alpha test enabled
Attribute Group:
color-buffer/enable
Initial Value:
GL_FALSE
Get Command:
glIsEnabled
GL_ALPHA_TEST_FUNC
Description:
Alpha test function
Attribute Group:
color-buffer
Initial Value:
GL_ALWAYS
Get Command:
glGetIntegerv
GL_ALPHA_TEST_REF
Description:
Alpha test reference value
Attribute Group:
color-buffer
Initial Value:
0
Get Command:
glGetIntegerv
GL_DEPTH_TEST
Description:
Depth buffer enabled
Attribute Group:
depth-buffer/enable
Initial Value:
GL_FALSE
Get Command:
glIsEnabled
GL_DEPTH_FUNC
Description:
Depth buffer test function
Attribute Group:
depth-buffer
Initial Value:
GL_LESS
Get Command:
glGetIntegerv
GL_BLEND
Description:
Blending enabled
Attribute Group:
color-buffer/enable
Initial Value:
GL_FALSE
Get Command:
glIsEnabled
GL_BLENC_SRC
Description:
Blending source function
Attribute Group:
color-buffer
Initial Value:
GL_ONE
Get Command:
glGetIntegerv
GL_BLEND_DST
Description:
Blending destination function
Attribute Group:
color-buffer
Initial Value:
GL_ZERO
Get Command:
glGetIntegerv
GL_LOGIC_OP
Description:
Logical operation enabled
Attribute Group:
color-buffer/enable
Initial Value:
GL_FALSE
Get Command:
glIsEnabled
GL_LOGIC_OP_MODE
Description:
Logical operation function
Attribute Group:
color-buffer
Initial Value:
GL_COPY
Get Command:
glGetIntegerv
GL_DITHER
Description:
Dithering enabled
Attribute Group:
color-buffer/enable
Initial Value:
GL_TRUE
Get Command:
glIsEnabled


Framebuffer Control State Variables
GL_DRAW_BUFFER
Description:
Buffers selected for drawing
Attribute Group:
color-buffer
Initial Value:
¾
Get Command:
glGetIntegerv
GL_INDEX_WRITEMASK
Description:
Color-index writemask
Attribute Group:
color-buffer
Initial Value:
1's
Get Command:
glGetIntegerv
GL_COLOR_WRITEMASK
Description:
Color write enables; R, G, B, or A
Attribute Group:
color-buffer
Initial Value:
GL_TRUE
Get Command:
glGetBooleanv
GL_DEPTH_WRITEMASK
Description:
Depth buffer enabled for writing
Attribute Group:
depth-buffer
Initial Value:
GL_TRUE
Get Command:
glGetBooleanv
GL_STENCIL_WRITEMASK
Description:
Stencil-buffer writemask
Attribute Group:
stencil-buffer
Initial Value:
1's
Get Command:
glGetIntegerv
GL_COLOR_CLEAR_VALUE
Description:
Color-buffer clear value (RGBA mode)
Attribute Group:
color-buffer
Initial Value:
0, 0, 0, 0
Get Command:
glGetFloatv
GL_INDEX_CLEAR_VALUE
Description:
Color-buffer clear value (color-index mode)
Attribute Group:
color-buffer
Initial Value:
0
Get Command:
glGetFloatv
GL_DEPTH_CLEAR_VALUE
Description:
Depth-buffer clear value
Attribute Group:
depth-buffer
Initial Value:
1
Get Command:
glGetIntegerv
GL_STENCIL_CLEAR_VALUE
Description:
Stencil-buffer clear value
Attribute Group:
stencil-buffer
Initial Value:
0
Get Command:
glGetIntegerv
GL_ACCUM_CLEAR_VALUE
Description:
Accumulation-buffer clear value
Attribute Group:
accum-buffer
Initial Value:
0
Get Command:
glGetFloatv


Pixel State Variables
GL_UNPACK_SWAP_BYTES
Description:
Value of GL_UNPACK_SWAP_BYTES
Attribute Group:
¾
Initial Value:
GL_FALSE
Get Command:
glGetBooleanv
GL_UNPACK_LSB_FIRST
Description:
Value of GL_UNPACK_LSB_FIRST
Attribute Group:
¾
Initial Value:
GL_FALSE
Get Command:
glGetBooleanv
GL_UNPACK_ROW_LENGTH
Description:
Value of GL_UNPACK_ROW_LENGTH
Attribute Group:
¾
Initial Value:
0
Get Command:
glGetIntegerv
GL_UNPACK_SKIP_ROWS
Description:
Value of GL_UNPACK_SKIP_ROWS
Attribute Group:
¾
Initial Value:
0
Get Command:
glGetIntegerv
GL_UNPACK_SKIP_PIXELS
Description:
Value of GL_UNPACK_SKIP_PIXELS
Attribute Group:
¾
Initial Value:
0
Get Command:
glGetIntegerv
GL_UNPACK_ALIGNMENT
Description:
Value of GL_UNPACK_ALIGNMENT
Attribute Group:
¾
Initial Value:
4
Get Command:
glGetIntegerv
GL_PACK_SWAP_BYTES
Description:
Value of GL_PACK_SWAP_BYTES
Attribute Group:
¾
Initial Value:
GL_FALSE
Get Command:
glGetBooleanv
GL_PACK_LSB_FIRST
Description:
Value of GL_PACK_LSB_FIRST
Attribute Group:
¾
Initial Value:
GL_FALSE
Get Command:
glGetBooleanv
GL_PACK_ROW_LENGTH
Description:
Value of GL_PACK_ROW_LENGTH
Attribute Group:
¾
Initial Value:
0
Get Command:
glGetIntegerv
GL_PACK_SKIP_ROWS
Description:
Value of GL_PACK_SKIP_ROWS
Attribute Group:
¾
Initial Value:
0
Get Command:
glGetIntegerv
GL_PACK_SKIP_PIXELS
Description:
Value of GL_PACK_SKIP_PIXELS
Attribute Group:
¾
Initial Value:
0
Get Command:
glGetIntegerv
GL_PACK_ALIGNMENT
Description:
Value of GL_PACK_ALIGNMENT
Attribute Group:
¾
Initial Value:
4
Get Command:
glGetIntegerv
GL_MAP_COLOR
Description:
True if colors are mapped
Attribute Group:
pixel
Initial Value:
GL_FALSE
Get Command:
glGetBooleanv
GL_MAP_STENCIL
Description:
True if stencil values are mapped
Attribute Group:
pixel
Initial Value:
GL_FALSE
Get Command:
glGetBooleanv
GL_INDEX_SHIFT
Description:
Value of GL_INDEX_SHIFT
Attribute Group:
pixel
Initial Value:
0
Get Command:
glGetIntegerv
GL_INDEX_OFFSET
Description:
Value of GL_INDEX_OFFSET
Attribute Group:
pixel
Initial Value:
0
Get Command:
glGetIntegerv
GL_
x
_SCALE
Description:
Value of GL_
x
_SCALE;
x
 IS GL_RED GL_BLUE, GL_ALPHA, or GL_DEPTH
Attribute Group:
pixel
Initial Value:
1
Get Command:
glGetFloatv
GL_
x
_BIAS
Description:
Value of GL_
x
_BIAS;
x
 IS GL_RED GL_BLUE, GL_ALPHA, or GL_DEPTH
Attribute Group:
pixel
Initial Value:
0
Get Command:
glGetFloatv
GL_ZOOM_X
Description:
x
 zoom factor
Attribute Group:
pixel
Initial Value:
1.0
Get Command:
glGetFloat
GL_ZOOM_Y
Description:
y
 zoom factor
Attribute Group:
pixel
Initial Value:
1.0
Get Command:
glGetFloatv
GL_
x
Description:
glPixelMap translation tables
Attribute Group:
pixel
Initial Value:
0's
Get Command:
glGetPixelMap
GL_
x
_SIZE
Description:
Size of table
x
Attribute Group:
pixel
Initial Value:
1
Get Command:
glGetIntegerv
GL_READ_BUFFER
Description:
Read source buffer
Attribute Group:
pixel
Initial Value:
¾
Get Command:
glGetIntegerv


Evaluator State Variables
GL_ORDER
Description:
1D map order
Attribute Group:
¾
Initial Value:
1
Get Command:
glGetMapiv
GL_ORDER
Description:
2D map orders
Attribute Group:
¾
Initial Value:
1, 1
Get Command:
glGetMapiv
GL_COEFF
Description:
1D control points
Attribute Group:
¾
Initial Value:
¾
Get Command:
glGetMapfv
GL_COEFF
Description:
2D control points
Attribute Group:
¾
Initial Value:
¾
Get Command:
glGetMapfv
GL_DOMAIN
Description:
1D domain endpoints
Attribute Group:
¾
Initial Value:
¾
Get Command:
glGetMapfv
GL_DOMAIN
Description:
2D domain endpoints
Attribute Group:
¾
Initial Value:
¾
Get Command:
glGetMapfv
GL_MAP1_x
Description:
1D map enables:
x
 is map type
Attribute Group:
eval/enable
Initial Value:
GL_FALSE
Get Command:
glIsEnabled
GL_MAP2_x
Description:
2D map enables:
x
 is map type
Attribute Group:
eval/enable
Initial Value:
GL_FALSE
Get Command:
glIsEnabled
GL_MAP1_GRID_DOMAIN
Description:
1D grid endpoints
Attribute Group:
eval
Initial Value:
0, 1
Get Command:
glGetFloatv
GL_MAP2_GRID_DOMAIN
Description:
2D grid endpoints
Attribute Group:
eval
Initial Value:
0, 1; 0, 1
Get Command:
glGetFloatv
GL_MAP1_GRID_SEGMENTS
Description:
1D grid divisions
Attribute Group:
eval
Initial Value:
1
Get Command:
glGetFloatv
GL_MAP1_GRID_SEGMENTS
Description:
2D grid segments
Attribute Group:
eval
Initial Value:
1, 1
Get Command:
glGetFloatv
GL_AUTO_NORMAL
Description:
True if automatic normal generation enabled
Attribute Group:
eval
Initial Value:
GL_FALSE
Get Command:
glIsEnabled


Hint State Variables
GL_PERSPECTIVE_CORRECTION_HINT
Description:
Perspective correction hint
Attribute Group:
hint
Initial Value:
GL_DON'T CARE
Get Command:
glGetIntegerv
GL_POINT_SMOOTH_HINT
Description:
Point smooth hint
Attribute Group:
hint
Initial Value:
GL_DON'T CARE
Get Command:
glGetIntegerv
GL_LINE_SMOOTH_HINT
Description:
Line smooth hint
Attribute Group:
hint
Initial Value:
GL_DON'T CARE
Get Command:
glGetIntegerv
GL_POLYGON_SMOOTH_HINT
Description:
Polygon smooth hint
Attribute Group:
hint
Initial Value:
GL_DON'T CARE
Get Command:
glGetIntegerv
GL_FOG_HINT
Description:
Fog hint
Attribute Group:
hint
Initial Value:
GL_DON'T CARE
Get Command:
glGetIntegerv


Implementation-Dependent State Variables
GL_MAX_LIGHTS
Description:
Maximum number of lights
Attribute Group:
¾
Initial Value:
8
Get Command:
glGetIntegerv
GL_MAX_CLIP_PLANES
Description:
Maximum number of user clipping planes
Attribute Group:
¾
Initial Value:
6
Get Command:
glGetIntegerv
GL_MAX_MODELVIEW_STACK_DEPTH
Description:
Maximum modelview-matrix stack depth
Attribute Group:
¾
Initial Value:
32
Get Command:
glGetIntegerv
GL_MAX_PROJECTION_STACK_DEPTH
Description:
Maximum projection-matrix stack depth
Attribute Group:
¾
Initial Value:
2
Get Command:
glGetIntegerv
GL_MAX_MAX_TEXTURE_STACK_DEPTH
Description:
Maximum depth of texture matrix stack
Attribute Group:
¾
Initial Value:
2
Get Command:
glGetIntegerv
GL_SUBPIXEL_BITS
Description:
Number of bits of subpixel precision in
x
 and
y
Attribute Group:
¾
Initial Value:
4
Get Command:
glGetIntegerv
GL_MAX_TEXTURE_SIZE
Description:
Maximum height or width of a texture image (w/o borders)
Attribute Group:
¾
Initial Value:
64
Get Command:
glGetIntegerv
GL_MAX_PIXEL_MAP_TABLE
Description:
Maximum size of a glPixelMap translation table
Attribute Group:
¾
Initial Value:
32
Get Command:
glGetIntegerv
GL_MAX_NAME_STACK_DEPTH
Description:
Maximum selection-name stack depth
Attribute Group:
¾
Initial Value:
64
Get Command:
glGetIntegerv
GL_MAX_LIST_NESTING
Description:
Maximum display-list call nesting
Attribute Group:
¾
Initial Value:
64
Get Command:
glGetIntegerv
GL_MAX_EVAL_ORDER
Description:
Maximum evaluator polynomial order
Attribute Group:
¾
Initial Value:
8
Get Command:
glGetIntegerv
GL_MAX_VIEWPORT_DIMS
Description:
Maximum viewport dimensions
Attribute Group:
¾
Initial Value:
¾
Get Command:
glGetIntegerv
GL_MAX_ATTRIB_STACK_DEPTH
Description:
Maximum depth of the attribute stack
Attribute Group:
¾
Initial Value:
16
Get Command:
glGetIntegerv
GL_AUX_BUFFERS
Description:
Number of auxiliary buffers
Attribute Group:
¾
Initial Value:
0
Get Command:
glGetBooleanv
GL_RGBA_MODE
Description:
True if color buffers store RGBA
Attribute Group:
¾
Initial Value:
¾
Get Command:
glGetBooleanv
GL_INDEX_MODE
Description:
True if color buffers store indices
Attribute Group:
¾
Initial Value:
¾
Get Command:
glGetBooleanv
GL_DOUBLEBUFFER
Description:
True if front and back buffers exist
Attribute Group:
¾
Initial Value:
¾
Get Command:
glGetBooleanv
GL_STEREO
Description:
True if left and right buffers exist
Attribute Group:
¾
Initial Value:
¾
Get Command:
glGetFloatv
GL_POINT_SIZE_RANGE
Description:
Range (low to hight) of antialiased point sizes
Attribute Group:
¾
Initial Value:
1, 1
Get Command:
glGetFloatv
GL_POINT_SIZE_GRANULARITY
Description:
Antialiased point size granularity
Attribute Group:
¾
Initial Value:
¾
Get Command:
glGetFloatv
GL_LINE_WIDTH_RANGE
Description:
Range (low to high) of antialiased line widths
Attribute Group:
¾
Initial Value:
1, 1
Get Command:
glGetFloatv
GL_LINE_WIDTH_GRANULARITY
Description:
Antialiased line-width granularity
Attribute Group:
¾
Initial Value:
¾
Get Command:
glGetFloatv


Implementation-Dependent Pixel-Depth State Variables
GL_RED_BITS
Description:
Number of bits per red component in color buffers
Attribute Group:
¾
Initial Value:
¾
Get Command:
glGetIntegerv
GL_GREEN_BITS
Description:
Number of bits per green component in color buffers
Attribute Group:
¾
Get Command:
glGetIntegerv
Initial Value:
¾
GL_BLUE_BITS
Description:
Number of bits per blue component in color buffers
Attribute Group:
¾
Initial Value:
¾
Get Command:
glGetIntegerv
GL_ALPHA_BITS
Description:
Number of bits per alpha component in color buffers
Attribute Group:
¾
Initial Value:
¾
Get Command:
glGetIntegerv
GL_INDEX_BITS
Description:
Number of bits per index in color buffers
Attribute Group:
¾
Initial Value:
¾
Get Command:
glGetIntegerv
GL_DEPTH_BITS
Description:
Number of depth-buffer bitplanes
Attribute Group:
¾
Initial Value:
¾
Get Command:
glGetIntegerv
GL_STENCIL_BITS
Description:
Number of stencil bitplanes
Attribute Group:
¾
Initial Value:
¾
Get Command:
glGetIntegerv
GL_ACCUM_RED_BITS
Description:
Number of bits per red component in the accumulation buffer
Attribute Group:
¾
Initial Value:
¾
Get Command:
glGetIntegerv
GL_ACCUM_GREEN_BITS
Description:
Number of bits per green component in the accumulation buffer
Attribute Group:
¾
Initial Value:
¾
Get Command:
glGetIntegerv
GL_ACCUM_BLUE_BITS
Description:
Number of bits per blue component in the accumulation buffer
Attribute Group:
¾
Initial Value:
¾
Get Command:
glGetIntegerv
GL_ACCUM_ALPHA_BITS
Description:
Number of bits per alpha component in the accumulation buffer
Attribute Group:
¾
Initial Value:
¾
Get Command:
glGetIntegerv


Miscellaneous State Variables
GL_LIST_BASE
Description:
Setting of glListBase
Attribute Group:
list
Initial Value:
0
Get Command:
glGetIntegerv
GL_LIST_INDEX
Description:
Number of display list under construction; 0 if none
Attribute Group:
¾
Initial Value:
0
Get Command:
glGetIntegerv
GL_LIST_MODE
Description:
Mode of display list under construction; undefined if none
Attribute Group:
¾
Initial Value:
0
Get Command:
glGetIntegerv
GL_ATTRIB_STACK_DEPTH
Description:
Attribute stack pointer
Attribute Group:
¾
Initial Value:
0
Get Command:
glGetIntegerv
GL_NAME_STACK_DEPTH
Description:
Name stack depth
Attribute Group:
¾
Initial Value:
0
Get Command:
glGetIntegerv
GL_RENDER_MODE
Description:
glRenderMode setting
Attribute Group:
¾
Initial Value:
GL_RENDER
Get Command:
glGetIntegerv
¾
Description:
Current error code(s)
Attribute Group:
¾
Initial Value:
0
Get Command:
glGetError


glAccum
The
glAccum
 function operates on the accumulation buffer.
void glAccum
(
GLenum
op
,
GLfloat
value
);
Parameters
op
Specifies the accumulation buffer operation. Symbolic constants
GL_ACCUM
,
GL_LOAD
,
GL_ADD
,
GL_MULT
, and
GL_RETURN
 are accepted.
value
Specifies a floating-point value used in the accumulation buffer operation.
op
 determines how
value
 is used.
Remarks
The accumulation buffer is an extended-range color buffer. Images are not rendered into it. Rather, images rendered into one of the color buffers are added to the contents of the accumulation buffer after rendering. Effects such as antialiasing (of points, lines, and polygons), motion blur, and depth of field can be created by accumulating images generated with different transformation matrices.
Each pixel in the accumulation buffer consists of red, green, blue, and alpha values. The number of bits per component in the accumulation buffer depends on the implementation. You can examine this number by calling
glGetIntegerv
 four times, with arguments
GL_ACCUM_RED_BITS
,
GL_ACCUM_GREEN_BITS
,
GL_ACCUM_BLUE_BITS
, and
GL_ACCUM_ALPHA_BITS
, respectively. Regardless of the number of bits per component, however, the range of values stored by each component is
[
-
 1, 1]. The accumulation buffer pixels are mapped one-to-one with frame buffer pixels.
The
 glAccum
 function operates on the accumulation buffer. The first argument,
op
, is a symbolic constant that selects an accumulation buffer operation. The second argument,
value
, is a floating-point value to be used in that operation. Five operations are specified:
GL_ACCUM, GL_LOAD, GL_ADD,GL_MULT,
and
 GL_RETURN.
All accumulation buffer operations are limited to the area of the current scissor box and are applied identically to the red, green, blue, and alpha components of each pixel. The contents of an accumulation buffer pixel component are undefined if the
glAccum
 operation results in a value outside the range [
-
 1,1]. The operations are as follows:
GL_ACCUM
Obtains R, G, B, and A values from the buffer currently selected for reading (see
glReadBuffer
). Each component value is divided by 2
n
-
 1, where
n
 is the number of bits allocated to each color component in the currently selected buffer. The result is a floating-point value in the range [0,1], which is multiplied by
value
 and added to the corresponding pixel component in the accumulation buffer, thereby updating the accumulation buffer.
GL_LOAD
Similar to
GL_ACCUM
, except that the current value in the accumulation buffer is not used in the calculation of the new value. That is, the R, G, B, and A values from the currently selected buffer are divided by  2
n
-
 1, multiplied by
value
, and then stored in the corresponding accumulation buffer cell, overwriting the current value.
GL_ADD
Adds
value
 to each R, G, B, and A in the accumulation buffer.
GL_MULT
Multiplies each R, G, B, and A in the accumulation buffer by
value
 and returns the scaled component to its corresponding accumulation buffer location.
GL_RETURN
Transfers accumulation buffer values to the color buffer or buffers currently selected for writing. Each R, G, B, and A component is multiplied by
value
, then multiplied by  2
n
-
 1, clamped to the range [0, 2
n
-
 1 ], and stored in the corresponding display buffer cell. The only fragment operations that are applied to this transfer are pixel ownership, scissor, dithering, and color writemasks.
The accumulation buffer is cleared by specifying R, G, B, and A values to set it to with the
glClearAccum
 directive, and issuing a
glClear
 command with the accumulation buffer enabled.
Only those pixels within the current scissor box are updated by any
glAccum
 operation.
The following functions retrieve information related to the
glAccum
 function:
glGet
 with argument
GL_ACCUM_RED_BITS
glGet
 with argument
GL_ACCUM_GREEN_BITS
glGet
 with argument
GL_ACCUM_BLUE_BITS
glGet
 with argument
GL_ACCUM_ALPHA_BITS
Errors
GL_INVALID_ENUM
 is generated if
op
 is not an accepted value.
GL_INVALID_OPERATION
 is generated if there is no accumulation buffer.
GL_INVALID_OPERATION
 is generated if
glAccum
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glBlendFunc
,
glClear
,
glClearAccum
,
glCopyPixels
,
glGet
,
glLogicOp
,
glPixelStore
,
glPixelTransfer
,
glReadPixels
,
glReadBuffer
,
glScissor
,
glStencilOp


glAddSwapHintRectWIN
The
glAddSwapHintRectWIN
 function specifies a set of rectangles that are to be copied by
SwapBuffers
.
void glAddSwapHintRectWIN
(
GLint
x
,
GLint
y
,
GLsizei
width
,
GLsizei
height
);
Parameters
x
Specifies the x coordinate (in window coordinates) of lower-left hand corner of the hint region rectangle.
y
Specifies the y coordinate (in window coordinates) of lower-left hand corner of the hint region rectangle.
width
Specifies the width of the hint region rectangle.
height
Specifies the height of the hint region rectangle.
Remarks
The
 glAddSwapHintRectWIN
 function enables your application to speed up animation by reducing the amount of repainting between frames. With
glAddSwapHintRectWIN
 you specify a set of rectangular areas that you want copied when you call the
SwapBuffers
 function. When no rectangles are specified with
glAddSwapHintRectWIN
 before calling
SwapBuffers
, the entire frame buffer is swapped. Using
glAddSwapHintRectWIN
 to copy only parts of the buffer that changed can increase the performance of
SwapBuffers
 significantly, especially when
SwapBuffers
 is implemented in software.
The
glAddSwapHintRectWIN
 function adds a rectangle to the hint region. When the
PFD_SWAP_COPY
 flag of the
PIXELFORMATDESCRIPTOR
 pixel format structure is set,
 SwapBuffers
uses this region to clip the copying of the back buffer to the front buffer. You don't specify
PFD_SWAP_COPY
, it is set by capable hardware. The hint region is cleared after each call to
SwapBuffers
. With some hardware configurations,
SwapBuffers
 can ignore the hint region and exchange the entire buffer.
SwapBuffers
 is implemented by the system, not by the application.
OpenGL maintains a separate hint region for each window. When you call
glAddSwapHintRectWIN
 on any rendering contexts associated with a window, the hint rectangles are combined into a single region.
Call
glAddSwapHintRectWIN
 with a bounding rectangle for each object drawn for a frame and for each rectangle cleared to erase previous frame objects.
Note
Note
  The
 glAddSwapHintRectWIN
 function is an extension function that is not part of the standard OpenGL library but is part of the GL_WIN_swap_hint extension. To check whether your implementation of OpenGL supports
glAddSwapHintRectWIN
, call
glGetString
(
GL_EXTENSIONS
). If it returns GL_WIN_swap_hint,
glAddSwapHintRectWIN
 is supported. To obtain the address of an extension function, call
wglGetProcAddress
.
See Also
PIXELFORMATDESCRIPTOR
,
SwapBuffers
,
glGetString


glAlphaFunc
The
glAlphaFunc
 function specifies the alpha test function.
void glAlphaFunc
(
GLenum
func
,
GLclampf
ref
);
Parameters
func
Specifies the alpha comparison function. Symbolic constants
GL_NEVER
,
GL_LESS
,
GL_EQUAL
,
GL_LEQUAL
,
GL_GREATER
,
GL_NOTEQUAL
,
GL_GEQUAL
, and
GL_ALWAYS
 are accepted. The default function is
GL_ALWAYS
.
ref
Specifies the reference value that incoming alpha values are compared to. This value is clamped to the range 0 through 1, where 0 represents the lowest possible alpha value and 1 the highest possible value. The default reference is 0.
Remarks
The alpha test discards fragments depending on the outcome of a comparison between the incoming fragments alpha value and a constant reference value. The
glAlphaFunc
 function specifies the reference and comparison function. The comparison is performed only if alpha testing is enabled. (See
glEnable
 of
GL_ALPHA_TEST
.)
The
 func
 and
ref
 parameters specify the conditions under which the pixel is drawn. The incoming alpha value is compared to
ref
 using the function specified by
func
. If the comparison passes, the incoming fragment is drawn, conditional on subsequent stencil and depth buffer tests. If the comparison fails, no change is made to the frame buffer at that pixel location.
The comparison functions are as follows:
GL_NEVER
Never passes.
GL_LESS
Passes if the incoming alpha value is less than the reference value.
GL_EQUAL
Passes if the incoming alpha value is equal to the reference value.
GL_LEQUAL
Passes if the incoming alpha value is less than or equal to the reference value.
GL_GREATER
Passes if the incoming alpha value is greater than the reference value.
GL_NOTEQUAL
Passes if the incoming alpha value is not equal to the reference value.
GL_GEQUAL
Passes if the incoming alpha value is greater than or equal to the reference value.
GL_ALWAYS
Always passes.
The
 glAlphaFunc
 function operates on all pixel writes, including those resulting from the scan conversion of points, lines, polygons, and bitmaps, and from pixel draw and copy operations.
glAlphaFunc
 does not affect screen clear operations.
Alpha testing is done only in RGBA mode.
The following functions retrieve information related to the
glAlphaFunc
 function:
glGet
 with argument
GL_ALPHA_TEST_FUNC
glGet
 with argument
GL_ALPHA_TEST_REF
glIsEnabled
 with argument
GL_ALPHA_TEST
Errors
GL_INVALID_ENUM
 is generated if
func
 is not an accepted value.
GL_INVALID_OPERATION
 is generated if
glAlphaFunc
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glBlendFunc
,
glClear
,
glDepthFunc
,
glEnable
,
glStencilFunc


glArrayElementEXT
The
glArrayElementEXT
 function specifies the array elements used to render a vertex.
void glArrayElementEXT
(
GLint
index
);
Parameters
index
Specifies an index in the enabled arrays.
Remarks
Use the
glArrayElementEXT
 function within
glBegin
 and
glEnd
 pairs to specify vertex and attribute data for point, line and polygon primitives. The
glArrayElementEXT
 function specifies the data for a single vertex using vertex and attribute data located at the
index
 of the enabled vertex arrays.
You can use
glArrayElementEXT
 to construct primitives by indexing vertex data, rather than by streaming through arrays of data in first-to-last order. Because
glArrayElementEXT
 specifies a single vertex only, you can explicitly specify attributes for individual primitives. For example, you can set a single normal for each individual triangle.
When you include calls to
glArrayElementEXT
 in display lists, the necessary array data, determined by the array pointers and enable values, is entered in the display list also. Array pointer and enable values are determined when display lists are created, not when display lists are executed.
The implementation can read and cache static array data at any time with
glArrayElementEXT
. When you modify the elements of a static array without specifying the array again, the results of any subsequent calls to
glArrayElementEXT
 are undefined.
Note
  The
 glArrayElementEXT
 function is an extension function that is not part of the standard OpenGL library but is part of the GL_EXT_vertex_array extension. To check whether your implementation of OpenGL supports
glArrayElementEXT
, call
glGetString
(
GL_EXTENSIONS
). If it returns GL_EXT_vertex_array,
glArrayElementEXT
 is supported.
To obtain the address of an extension function, call
wglGetProcAddress
.
When you call
glArrayElementEXT
 without first calling
glEnable
(
GL_VERTEX_ARRAY_EXT
), no drawing occurs but the attributes corresponding to enabled arrays are modified. Although no error is generated when you specify an array within
glBegin
 and
glEnd
 pairs, the results are undefined.
See Also
glColorPointerEXT
,
glDrawArraysEXT
,
glEdgeFlagPointerEXT
,
glGetPointervEXT
,
glIndexPointerEXT
,
glNormalPointerEXT
,
glTexCoordPointerEXT
,
glVertexPointerEXT
,
glGetString
,
wglGetProcAddress


glBegin
glBegin, glEnd
The
glBegin
 and
glEnd
 functions delimit the vertexes of a primitive or a group of like primitives.
void glBegin
(
GLenum
mode
);
Parameters
mode
Specifies the primitive or primitives that will be created from vertexes presented between
glBegin
 and the subsequent
glEnd
. Ten symbolic constants are accepted:
GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_LINE_LOOP, GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_QUADS, GL_QUAD_STRIP,
and
GL_POLYGON
.
void glEnd
(
void
);
Remarks
The
glBegin
 and
glEnd
 functions delimit the vertexes that define a primitive or a group of like primitives. The
glBegin
 function accepts a single argument that specifies which of ten ways the vertexes are interpreted. Taking
n
 as an integer count starting at one, and
N
as the total number of vertexes specified, the interpretations are as follows:
GL_POINTS
Treats each vertex as a single point. Vertex
n
 defines point
n
.
N
 points are drawn.
GL_LINES
Treats each pair of vertexes as an independent line segment. Vertexes
2n
-
1
 and
2n
 define line
n. N/2
 lines are drawn.
GL_LINE_STRIP
Draws a connected group of line segments from the first vertex to the last. Vertexes
n
 and
n+1
 define line
n. N
-
1
 lines are drawn.
GL_LINE_LOOP
Draws a connected group of line segments from the first vertex to the last, then back to the first. Vertexes
n
 and
n+1
 define line
n
.
The last line, however, is defined by vertexes
N
 and
1. N
 lines are drawn.
GL_TRIANGLES
Treats each triplet of vertexes as an independent triangle. Vertexes
3n
-
2
,
3n-1
, and
3n
 define triangle
n
.
N/3
 triangles are drawn.
GL_TRIANGLE_STRIP
Draws a connected group of triangles. One triangle is defined for each vertex presented after the first two vertexes. For odd
n
, vertexes
n
,
n+1
, and
n+2
 define triangle
n
. For even
n
, vertexes
n+1
,
n
, and
n+2
 define triangle
n
.
N
-
2
 triangles are drawn.
GL_TRIANGLE_FAN
Draws a connected group of triangles. One triangle is defined for each vertex presented after the first two vertexes. Vertexes
1
,
n+1
, and
n+2
 define triangle
n
.
N
-
2
 triangles are drawn.
GL_QUADS
Treats each group of four vertexes as an independent quadrilateral. Vertexes
4n
-
3
,
4n
-
2
,
4n
-
1
, and
4n
 define quadrilateral
n
.
N/4
 quadrilaterals are drawn.
GL_QUAD_STRIP
Draws a connected group of quadrilaterals. One quadrilateral is defined for each pair of vertexes presented after the first pair. Vertexes
2n
-
1
,
2n
,
2n+2
, and
2n+1
 define quadrilateral
n
.
N
 quadrilaterals are drawn. Note that the order in which vertexes are used to construct a quadrilateral from strip data is different from that used with independent data.
GL_POLYGON
Draws a single, convex polygon. Vertexes
1
 through
N
 define this polygon.
Only a subset of GL commands can be used between
glBegin
 and
glEnd
. The commands are
glVertex
,
glColor
,
glIndex
,
glNormal
,
glTexCoord
,
glEvalCoord
,
glEvalPoint
,
glMaterial
, and
glEdgeFlag
. Also, it is acceptable to use
glCallList
 or
glCallLists
 to execute display lists that include only the preceding commands. If any other GL command is called between
glBegin
 and
glEnd
, the error flag is set and the command is ignored.
Regardless of the value chosen for
mode
, there is no limit to the number of vertexes that can be defined between
glBegin
 and
glEnd
. Lines, triangles, quadrilaterals, and polygons that are incompletely specified are not drawn. Incomplete specification results when either too few vertexes are provided to specify even a single primitive or when an incorrect multiple of vertexes is specified. The incomplete primitive is ignored; the rest are drawn.
The minimum specification of vertexes for each primitive is as follows: 1 for a point,
2 for a line, 3 for a triangle, 4 for a quadrilateral, and 3 for a polygon. Modes that require a certain multiple of vertexes are
GL_LINES (2), GL_TRIANGLES (3)
,
GL_QUADS (4),
and
GL_QUAD_STRIP (2)
.
Errors
GL_INVALID_ENUM
 is generated if
mode
 is set to an unaccepted value.
GL_INVALID_OPERATION
 is generated if a command other than
glVertex, glColor, glIndex, glNormal, glTexCoord, glEvalCoord, glEvalPoint, glMaterial, glEdgeFlag, glCallList,
 or
glCallLists
 is called between
glBegin
 and the corresponding
glEnd
.
GL_INVALID_OPERATION
 is generated if
glEnd
 is called before the corresponding
glBegin
 is called, or if
glBegin
 is called within a
glBegin
/
glEnd
 sequence.
See Also
glCallList
,
glCallLists
,
glColor
,
glEdgeFlag
,
glEvalCoord
,
glEvalPoint
,
glIndex
,
glMaterial
,
glNormal
,
glTexCoord
,
glVertex


glBitmap
The
glBitmap
 function draws a bitmap.
void
glBitmap
(
GLsizei
width
,
GLsizei
height
,
GLfloat
xorig
,
GLfloat
yorig
,
GLfloat
xmove
,
GLfloat
ymove
,
const GLubyte
*bitmap
);
Parameters
width, height
Specify the pixel width and height of the bitmap image.
xorig, yorig
Specify the location of the origin in the bitmap image. The origin is measured from the lower left corner of the bitmap, with right and up being the positive axes.
xmove, ymove
Specify the
x
 and
y
 offsets to be added to the current raster position after the bitmap is drawn.
bitmap
Specifies the address of the bitmap image.
Remarks
A bitmap is a binary image. When drawn, the bitmap is positioned relative to the current raster position, and frame buffer pixels corresponding to ones in the bitmap are written using the current raster color or index. Frame buffer pixels corresponding to zeros in the bitmap are not modified.
The
glBitmap
 function takes seven arguments. The first pair specify the width and height of the bitmap image. The second pair specify the location of the bitmap origin relative to the lower left corner of the bitmap image. The third pair of arguments specify
x
 and
y
 offsets to be added to the current raster position after the bitmap has been drawn. The final argument is a pointer to the bitmap image itself.
The bitmap image is interpreted like image data for the
glDrawPixels
 command, with
width
 and
height
 corresponding to the width and height arguments of that command, and with
type
 set to
GL_BITMAP
 and
format
 set to
GL_COLOR_INDEX
. Modes specified using
glPixelStore
 affect the interpretation of bitmap image data; modes specified using
glPixelTransfer
 do not.
If the current raster position is invalid,
glBitmap
 is ignored. Otherwise, the lower left corner of the bitmap image is positioned at the window coordinates
x
 (w)
 =
ë
 x
 (r)
-
 x
 (o)
û
y
 (w)
 =
ë
y
 (r)
-
y
 (o)
û
where (
xr, yr)
 is the raster position and (
xo, yo
) is the bitmap origin. Fragments are then generated for each pixel corresponding to a one in the bitmap image. These fragments are generated using the current raster
z
 coordinate, color or color index, and current raster texture coordinates. They are then treated just as if they had been generated by a point, line, or polygon, including texture mapping, fogging, and all per-fragment operations such as alpha and depth testing.
After the bitmap has been drawn, the
x
 and
y
 coordinates of the current raster position are offset by
xmove
 and
ymove
. No change is made to the
z
 coordinate of the current raster position, or to the current raster color, index, or texture coordinates.
The following functions retrieve information related to the
glBitmap
 function:
glGet
 with argument
GL_CURRENT_RASTER_POSITION
glGet
 with argument
 GL_CURRENT_RASTER_COLOR
glGet
 with argument
 GL_CURRENT_RASTER_INDEX
glGet
 with argument
 GL_CURRENT_RASTER_TEXTURE_COORDS
glGet
 with argument
 GL_CURRENT_RASTER_POSITION_VALID
Errors
GL_INVALID_VALUE
 is generated if
width
 or
height
 is negative.
GL_INVALID_OPERATION
 is generated if
glBitmap
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glBegin
,
glDrawPixels
,
glRasterPos
,
glPixelStore
,
glPixelTransfer


glBlendFunc
The
glBlendFunc
 function specifies pixel arithmetic.
void glBlendFunc
(
GLenum
sfactor
,
GLenum
dfactor
,
);
Parameters
sfactor
Specifies how the red, green, blue, and alpha source-blending factors are computed. Nine symbolic constants are accepted:
 GL_ZERO, GL_ONE, GL_DST_COLOR, GL_ONE_MINUS_DST_COLOR, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA,
and
 GL_SRC_ALPHA_SATURATE
.
dfactor
Specifies how the red, green, blue, and alpha destination blending factors are computed. Eight symbolic constants are accepted:
 GL_ZERO, GL_ONE, GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_DST_ALPHA,
and
 GL_ONE_MINUS_DST_ALPHA.
Remarks
In RGB mode, pixels can be drawn using a function that blends the incoming (source) RGBA values with the RGBA values that are already in the frame buffer (the destination values). By default, blending is disabled. Use
glEnable
 and
glDisable
 with argument
GL_BLEND
 to enable and disable blending.
The
glBlendFunc
 function defines the operation of blending when it is enabled. The
sfactor
parameter specifies which of nine methods is used to scale the source color components. The
dfactor
 parameter specifies which of eight methods is used to scale the destination color components. The eleven possible methods are described in the table below. Each method defines four scale factors, one each for red, green, blue, and alpha.
In the table and in subsequent equations, source and destination color components are referred to as (
R
 (s)
,G
 (s)
,B
 (s)
,A
 (s)
) and (
R
 (d)
,G
 (d)
,B
 (d)
,A
 (d)
). They are understood to have integer values between zero and (
k
 (R)
,k
 (G)
,k
 (B)
,k
 (A)
), where
k
 (c)
 = 2^
m
 (c)
-
 1
and (
m
 (R)
,m
 (G)
,m
 (B)
,m
 (A)
) is the number of red, green, blue, and alpha bitplanes.
Source and destination scale factors are referred to as (
s
 (R)
,s
 (G)
,s
 (B)
,s
 (A)
) and (
d
 (R)
,d
 (G)
,d
 (B)
,d
 (A)
). The scale factors described in the table, denoted (
f
 (R)
,f
 (G)
,f
 (B)
,f
 (A)
), represent either source or destination factors. All scale factors have range [0,1].
Parameter
(f
 (R)
,f
 (G)
,f
 (B)
,f
 (A)
)
GL_ZERO
(0,0,0,0)
GL_ONE
(1,1,1,1)
GL_SRC_COLOR
(
R
 (s)
/k
 (R)
,G
 (s)
/k
 (G)
,B
 (s)
/
k
 (B)
,A
 (s)
/k
 (A)
)
GL_ONE_MINUS_SRC_COLOR
(1,1,1,1).
(
R
 (s)
/k
 (R)
,G
 (s)
/k
 (G)
,B
 (s)
/k
 (B)
,A
 (s)
/k
 (A)
)
GL_DST_COLOR
(
R
 (d)
/k
 (R)
,G
 (d)
/k
 (G)
,B
 (d)
/k
 (B)
,A
 (d)
/k
 (A)
)
GL_ONE_MINUS_DST_COLOR
(1,1,1,1)
GL_SRC_ALPHA
(
R
 (d)
/k
 (R)
,G
 (d)
/k
 (G)
,B
 (d)
/k
 (B)
,A
 (d)
/k
 (A)
)
(
A
 (s)
/k
 (A)
,A
 (s)
/k
 (A)
,A
 (s)
/k
 (A)
,A
 (s)
/k
 (A)
)
GL_ONE_MINUS_SRC_ALPHA
(1,1,1,1)
(
A
 (s)
/k
 (A)
,A
 (s)
/k
 (A)
,A
 (s)
/k
 (A)
,A
 (s)
/k
 (A)
)
GL_DST_ALPHA
(
A
 (d)
/k
 (A)
,A
 (d)
/k
 (A)
,A
 (d)
/k
 (A)
,A
 (d)
/k
 (A)
)
GL_ONE_MINUS_DST_ALPHA
(1,1,1,1)
(
A
 (d)
/k
 (A)
,A
 (d)
/k
 (A)
,A
 (d)
/k
 (A)
,A
 (d)
/k
 (A)
)
GL_SRC_ALPHA_SATURATE
(
i,i,i,
1)
In the table,
i
 = min (
A
 (s)
,k
 (A)
-
A
 (d)
) /
kA
To determine the blended RGBA values of a pixel when drawing in RGB mode, the system uses the following equations:
R
 (d)
 = min(
kR,RssR+RddR)
G
 (d)
 = min(
kG,GssG+GddG
)
B
 (d)
 = min(
kB,BssB+BddB)
A
 (d)
 = min(
kA,AssA+AddA
)
Despite the apparent precision of the above equations, blending arithmetic is not exactly specified, because blending operates with imprecise integer color values. However, a blend factor that should be equal to one is guaranteed not to modify its multiplicand, and a blend factor equal to zero reduces its multiplicand to zero. Thus, for example, when
sfactor
 is
GL_SRC_ALPHA
,
 dfactor
 is
GL_ONE_MINUS_SRC_ALPHA
, and
A
 (s)
 is equal to
 k
 (A)
, the equations reduce to simple replacement:
R
 (d)
 = R
 (s)
G
 (d)
 =  G
 (s)
B
 (d)
 =  B
 (s)
A
 (d)
 = A
 (s
)
Examples
Transparency is best implemented using blend function (
GL_SRC_ALPHA
,
GL_ONE_MINUS_SRC_ALPHA
) with primitives sorted from farthest to nearest. Note that this transparency calculation does not require the presence of alpha bitplanes in the frame buffer.
Blend function (
GL_SRC_ALPHA
,
GL_ONE_MINUS_SRC_ALPHA
) is also useful for rendering antialiased points and lines in arbitrary order.
Polygon antialiasing is optimized using blend function (
GL_SRC_ALPHA_SATURATE
,
GL_ONE
) with polygons sorted from nearest to farthest. (See
glEnable
 and the
GL_POLYGON_SMOOTH
 argument for information on polygon antialiasing.) Destination alpha bitplanes, which must be present for this blend function to operate correctly, store the accumulated coverage.
Incoming (source) alpha is correctly thought of as a material opacity, ranging from 1.0 (
K
 (A)
), representing complete opacity, to 0.0 (0), representing complete transparency.
When more than one color buffer is enabled for drawing, blending is done separately for each enabled buffer, using for destination color the contents of that buffer. (See
glDrawBuffer
.)
Blending affects only RGB rendering. It is ignored by color index renderers.
The following functions retrieve information related to the
glBlendFunc
 function:
glGet
 with argument
GL_BLEND_SRC
glGet
 with argument
GL_BLEND_DST
glIsEnabled
 with argument
GL_BLEND
Errors
GL_INVALID_ENUM
 is generated if either
sfactor
 or
dfactor
 is not an accepted value.
GL_INVALID_OPERATION
 is generated if
glBlendFunc
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glAlphaFunc
,
glBegin
,
glClear
,
glDrawBuffer
,
glEnable
,
glLogicOp
,
glStencilFunc


glCallList
The
glCallList
 function executes a display list.
void glCallList
(
GLuint
list
);
Parameters
list
Specifies the integer name of the display list to be executed.
Remarks
The
glCallList
 function causes the named display list to be executed. The commands saved in the display list are executed in order, just as if they were called without using a display list. If
list
 has not been defined as a display list,
glCallList
 is ignored.
The
glCallList
 function can appear inside a display list. To avoid the possibility of infinite recursion resulting from display lists calling one another, a limit is placed on the nesting level of display lists during display-list execution. This limit is at least 64, and it depends on the implementation.
GL state is not saved and restored across a call to
glCallList
. Thus, changes made to GL state during the execution of a display list remain after execution of the display list is completed. Use
glPushAttrib
,
glPopAttrib
,
glPushMatrix
, and
glPopMatrix
 to preserve GL state across
glCallList
 calls.
Display lists can be executed between a call to
glBegin
 and the corresponding call to
glEnd
, as long as the display list includes only commands that are allowed in this interval.
The following functions retrieve information related to the
glCallList
 function:
glGet
 with argument
GL_MAX_LIST_NESTING
glIsList
See Also
glBegin
,
glCallLists
,
glDeleteLists
,
glGenLists
,
glNewList
,
glPushAttrib
,
glPushMatrix


glCallLists
The
glCallLists
 function executes a list of display lists.
void glCallLis0s
(
GLsizei
n
,
GLenum
type
,
const GLvoid
*lists
);
Parameters
n
Specifies the number of display lists to be executed.
type
Specifies the type of values in
lists
. Symbolic constants
GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_INT, GL_UNSIGNED_INT,
GL_FLOAT
,
GL_2_BYTES
,
GL_3_BYTES
, and
GL_4_BYTES
 are accepted.
lists
Specifies the address of an array of name offsets in the display list. The pointer type is void because the offsets can be bytes, shorts, ints, or floats, depending on the value of
type
.
Remarks
The
glCallLists
 function causes each display list in the list of names passed as
lists
 to be executed. As a result, the commands saved in each display list are executed in order, just as if they were called without using a display list. Names of display lists that have not been defined are ignored.
The
glCallLists
 function provides an efficient means for executing display lists.The
n
 parameter allows lists with various name formats to be accepted. The formats are as follows:
GL_BYTE
The
 lists
 parameter is treated as an array of signed bytes, each in the range
-
 128 through 127.
GL_UNSIGNED_BYTE
The
 lists
 parameter is treated as an array of unsigned bytes, each in the range 0 through 255.
GL_SHORT
The
 lists
 parameter is treated as an array of signed two-byte integers, each in the range
-
 32768 through 32767.
GL_UNSIGNED_SHORT
The
 lists
 parameter is treated as an array of unsigned two-byte integers, each in the range 0 through 65535.
GL_INT
The
 lists
 parameter is treated as an array of signed four-byte integers.
GL_UNSIGNED_INT
The
 lists
 parameter is treated as an array of unsigned four-byte integers.
GL_FLOAT
The
 lists
 parameter is treated as an array of four-byte floating-point values.
GL_2_BYTES
The
 lists
 parameter is treated as an array of unsigned bytes. Each pair of bytes specifies a single display-list name. The value of the pair is computed as 256 times the unsigned value of the first byte plus the unsigned value of the second byte.
GL_3_BYTES
The
 lists
 parameter is treated as an array of unsigned bytes. Each triplet of bytes specifies a single display-list name. The value of the triplet is computed as 65536 times the unsigned value of the first byte, plus 256 times the unsigned value of the second byte, plus the unsigned value of the third byte.
GL_4_BYTES
The
 lists
 parameter is treated as an array of unsigned bytes. Each quadruplet of bytes specifies a single display-list name. The value of the quadruplet is computed as 16777216 times the unsigned value of the first byte, plus 65536 times the unsigned value of the second byte, plus 256 times the unsigned value of the third byte, plus the unsigned value of the fourth byte.
The list of display list names is not null-terminated. Rather,
n
 specifies how many names are to be taken from
lists
.
An additional level of indirection is made available with the
glListBase
 command, which specifies an unsigned offset that is added to each display-list name specified in
lists
 before that display list is executed.
The
glCallLists
 function can appear inside a display list. To avoid the possibility of infinite recursion resulting from display lists calling one another, a limit is placed on the nesting level of display lists during display-list execution. This limit must be at least 64, and it depends on the implementation.
GL state is not saved and restored across a call to
glCallLists
. Thus, changes made to GL state during the execution of the display lists remain after execution is completed. Use
glPushAttrib
,
glPopAttrib
,
glPushMatrix
, and
glPopMatrix
 to preserve GL state across
glCallLists
 calls.
Display lists can be executed between a call to
glBegin
 and the corresponding call to
glEnd
, as long as the display list includes only commands that are allowed in this interval.
The following functions retrieve information related to the
glCallLists
 function:
glGet
with argument
GL_LIST_BASE
glGet
with argument
GL_MAX_LIST_NESTING
glIsList
See Also
glCallList
,
glDeleteLists
,
glGenLists
,
glListBase
,
glNewList
,
glPushAttrib
,
glPushMatrix


glClear
The
glClear
 function clears buffers within the viewport.
void glClear
(
GLbitfield
mask
);
Parameters
mask
Bitwise OR of masks that indicate the buffers to be cleared. The four masks are
GL_COLOR_BUFFER_BIT
,
GL_DEPTH_BUFFER_BIT
,
GL_ACCUM_BUFFER_BIT
, and
GL_STENCIL_BUFFER_BIT
.
Remarks
The
glClear
 function sets the bitplane area of the window to values previously selected by
glClearColor
,
glClearIndex
,
glClearDepth
,
glClearStencil
, and
glClearAccum
. Multiple color buffers can be cleared simultaneously by selecting more than one buffer at a time using
glDrawBuffer
.
The pixel ownership test, the scissor test, dithering, and the buffer writemasks affect the operation of
glClear
. The scissor box bounds the cleared region. Alpha function, blend function, logical operation, stenciling, texture mapping, and
z
-buffering are ignored by
glClear
.
The
glClear
 function takes a single argument that is the bitwise OR of several values indicating which buffer is to be cleared.
The values are as follows:
GL_COLOR_BUFFER_BIT
Indicates the buffers currently enabled for color writing.
GL_DEPTH_BUFFER_BIT
Indicates the depth buffer.
GL_ACCUM_BUFFER_BIT
Indicates the accumulation buffer.
GL_STENCIL_BUFFER_BIT
Indicates the stencil buffer.
The value to which each buffer is cleared depends on the setting of the clear value for that buffer.
If a buffer is not present, then a
glClear
 call directed at that buffer has no effect.
The following functions retrieve information related to the
glClear
 function:
glGet
with argument
GL_ACCUM_CLEAR_VALUE
glGet
with argument
GL_DEPTH_CLEAR_VALUE
glGet
with argument
GL_INDEX_CLEAR_VALUE
glGet
with argument
GL_COLOR_CLEAR_VALUE
glGet
 with argument
GL_STENCIL_CLEAR_VALUE
Errors
GL_INVALID_VALUE
 is generated if any bit other than the four defined bits is set in
mask
.
GL_INVALID_OPERATION
 is generated if
glClear
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glClearAccum
,
glClearColor
,
glClearDepth
,
glClearIndex
,
glClearStencil
,
glDrawBuffer
,
glScissor


glClearAccum
The
glClearAccum
 function clears values for the accumulation buffer.
void glClearAccum
(
GLfloat
red
,
GLfloat
green
,
GLfloat
blue
,
GLfloat
alpha
);
Parameters
red, green, blue, alpha
Specify the red, green, blue, and alpha values used when the accumulation buffer is cleared. The default values are all zero.
Remarks
The
glClearAccum
 function specifies the red, green, blue, and alpha values used by
glClear
 to clear the accumulation buffer.
Values specified by
glClearAccum
 are clamped to the range [
-
 1,1].
The following function retrieves information related to the
glClearAccum
 function:
glGet
 with argument
GL_ACCUM_CLEAR_VALUE
Errors
GL_INVALID_OPERATION
 is generated if
glClearAccum
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glClear


glClearColor
The
glClearColor
 function specifies clear values for the color buffers.
void glClearColor
(
GLclampf
red
,
GLclampf
green
,
GLclampf
blue
,
GLclampf
alpha
);
Parameters
red, green, blue, alpha
Specify the red, green, blue, and alpha values used when the color buffers are cleared. The default values are all zero.
Remarks
The
glClearColor
 function specifies the red, green, blue, and alpha values used by
glClear
 to clear the color buffers. Values specified by
glClearColor
 are clamped to the range [0,1].
The following functions retrieve information related to the
glClearColor
 function:
glGet
 with argument
GL_ACCUM_CLEAR_VALUE
glGet
 with argument
GL_COLOR_CLEAR_VALUE
Errors
GL_INVALID_OPERATION
 is generated if
glClearColor
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glClear


glClearDepth
The
glClearDepth
 function specifies the clear value for the depth buffer.
void glClearDepth
(
GLclampd
depth
);
Parameters
depth
Specifies the depth value used when the depth buffer is cleared.
Remarks
The
glClearDepth
 function specifies the depth value used by
glClear
 to clear the depth buffer. Values specified by
glClearDepth
 are clamped to the range [0,1].
The following function retrieves information related to the
glClearDepth
 function:
glGet
 with argument
GL_DEPTH_CLEAR_VALUE
Errors
GL_INVALID_OPERATION
 is generated if
glClearDepth
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glClear


glClearIndex
The
glClearIndex
function specifies the clear value for the color index buffers.
void glClearIndex
(
GLfloat
c
);
Parameters
c
Specifies the index used when the color index buffers are cleared. The default value is zero.
Remarks
The
glClearIndex
function specifies the index used by
glClear
 to clear the color index buffers.
c
 is not clamped. Rather,
c
 is converted to a fixed-point value with unspecified precision to the right of the binary point. The integer part of this value is then masked with 2^
m
-
 1, where
m
 is the number of bits in a color index stored in the frame buffer.
The following functions retrieve information related to the
glClearIndex
 function:
glGet
 with argument
GL_INDEX_CLEAR_VALUE
glGet
 with argument
GL_INDEX_BITS
Errors
GL_INVALID_OPERATION
 is generated if
glClearIndex
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glClear


glClearStencil
The
glClearStencil
 function specifies the clear value for the stencil buffer.
void glClearStencil
(
GLint
s
);
Parameters
s
Specifies the index used when the stencil buffer is cleared. The default value is zero.
Remarks
The
glClearStencil
 function specifies the index used by
glClear
 to clear the stencil buffer. The
s
 parameter is masked with 2^
m
-
 1, where
m
 is the number of bits in the stencil buffer.
The following functions retrieve information related to the
glCearStencil
 function:
glGet
 with argument
GL_STENCIL_CLEAR_VALUE
glGet
 with argument
GL_STENCIL_BITS
Errors
GL_INVALID_OPERATION
 is generated if
glClearStencil
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glClear


glClipPlane
The
glClipPlane
function specifies a plane against which all geometry is clipped.
void glClipPlane
(
GLenum
plane
,
const GLdouble
*equation
);
Parameters
plane
Specifies which clipping plane is being positioned. Symbolic names of the form
GL_CLIP_PLANE
i
, where
i
 is an integer between 0 and
GL_MAX_CLIP_PLANES
-
 1, are accepted.
equation
Specifies the address of an array of four double-precision floating-point values. These values are interpreted as a plane equation.
Remarks
Geometry is always clipped against the boundaries of a six-plane frustum in
x
,
y
, and
z
.
glClipPlane
 allows the specification of additional planes, not necessarily perpendicular to the
x
,
y
, or
z
 axis, against which all geometry is clipped. Up to
GL_MAX_CLIP_PLANES
 planes can be specified, where
GL_MAX_CLIP_PLANES
 is at least six in all implementations. Because the resulting clipping region is the intersection of the defined half-spaces, it is always convex.
The
glClipPlane
function specifies a half-space using a four-component plane equation. When
glClipPlane
 is called,
equation
 is transformed by the inverse of the modelview matrix and stored in the resulting eye coordinates. Subsequent changes to the modelview matrix have no effect on the stored plane-equation components. If the dot product of the eye coordinates of a vertex with the stored plane equation components is positive or zero, the vertex is
 in
with respect to that clipping plane. Otherwise, it is
out
.
Clipping planes are enabled and disabled with
glEnable
 and
glDisable
, and called with the argument
GL_CLIP_PLANE
i
, where
i
 is the plane number.
By default, all clipping planes are defined as (0,0,0,0) in eye coordinates and are disabled.
It is always the case that
GL_CLIP_PLANE
i
 =
GL_CLIP_PLANE0
 +
i
.
The following functions retrieve information related to the
glClipPlane
 function:
glGetClipPlane
glIsEnabled
 with argument
GL_CLIP_PLANE
i
Errors
GL_INVALID_ENUM
 is generated if
plane
 is not an accepted value.
GL_INVALID_OPERATION
 is generated if
glClipPlane
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glEnable


glColor
glColor3b, glColor3d, glColor3f, glColor3i, glColor3s, glColor3ub, glColor3ui, glColor3us, glColor4b, glColor4d, glColor4f, glColor4i, glColor4s, glColor4ub, glColor4ui, glColor4us, glColor3bv, glColor3dv, glColor3fv, glColor3iv, glColor3sv, glColor3ubv, glColor3uiv, glColor3usv, glColor4bv, glColor4dv, glColor4fv, glColor4iv, glColor4sv, glColor4ubv, glColor4uiv, glColor4usv
These functions set the current color.
void glColor3b
(
GLbyte
red
,
GLbyte
green
,
GLbyte
blue
);
void glColor3d
(
GLdouble
red
,
GLdouble
green
,
GLdouble
blue
);
void glColor3f
(
GLfloat
red
,
GLfloat
green
,
GLfloat
blue
);
void
glColor3i
(
GLint
red
,
GLint
green
,
GLint
blue
);
void glColor3s
(
GLshort
red
,
GLshort
green
,
GLshort
blue
);
void
glColor3ub
(
GLubyte
red
,
GLubyte
green
,
GLubyte
blue
);
void
glColor3ui
(
GLuint
red
,
GLuint
green
,
GLuint
blue
);
void glColor3us
(
GLushort
red
,
GLushort
green
,
GLushort
blue
);
void glColor4b
(
GLbyte
red
,
GLbyte
green
,
GLbyte
blue
,
GLbyte
alpha
);
void glColor4d
(
GLdouble
red
,
GLdouble
green
,
GLdouble
blue
,
GLdouble
alpha
);
void glColor4f
(
GLfloat
red
,
GLfloat
green
,
GLfloat
blue
,
GLfloat
alpha
);
void glColor4i
(
GLint
red
,
GLint
green
,
GLint
blue
,
GLint
alpha
);
void glColor4s
(
GLshort
red
,
GLshort
green
,
GLshort
blue
,
GLshort
alpha
);
void glColor4ub
(
GLubyte
red
,
GLubyte
green
,
GLubyte
blue
,
GLubyte
alpha
);
void glColor4ui
(
GLuint
red
,
GLuint
green
,
GLuint
blue
,
GLuint
alpha
);
void glColor4us
(
GLushort
red
,
GLushort
green
,
GLushort
blue
,
GLushort
alpha
);
Parameters
red, green, blue
Specify new red, green, and blue values for the current color.
alpha
Specifies a new alpha value for the current color. Included only in the four-argument
glColor4
 command.
void
glColor3bv
(
const GLbyte
*v
);
void glColor3dv
(
const GLdouble
*v
);
void
glColor3fv
(
const GLfloat
*v
);
void
glColor3iv
(
const GLint
*v
);
void glColor3sv
(
const GLshort
*v
);
void glColor3ubv
(
const GLubyte
*v
);
void glColor3uiv
(
const GLuint
*v
);
void
glColor3usv
(
const GLushort
*v
);
void
glColor4bv
(
const GLbyte
*v
);
void
glColor4dv
(
const GLdouble
*v
);
void
glColor4fv
(
const GLfloat
*v
);
void glColor4iv
(
const GLint
*v
);
void glColor4sv
(
const GLshort
*v
);
void glColor4ubv
(
const GLubyte
*v
);
void glColor4uiv
(
const GLuint
*v
);
void glColor4usv
(
const GLushort
*v
);
Parameters
v
Specifies a pointer to an array that contains red, green, blue, and (sometimes) alpha values.
Remarks
The GL stores both a current single-valued color index and a current four-valued RGBA color.
glColor
 sets a new four-valued RGBA color.
glColor
 has two major variants:
glColor3 and glColor4. glColor3
 variants specify new red, green, and blue values explicitly, and set the current alpha value to 1.0 implicitly.
glColor4
 variants specify all four color components explicitly.
The
glColor3b
,
glColor4b
,
glColor3s
,
glColor4s
,
glColor3i
, and
glColor4i
 functions take three or four signed byte, short, or long integers as arguments. When
v
 is appended to the name, the color commands can take a pointer to an array of such values.
Current color values are stored in floating-point format, with unspecified mantissa and exponent sizes. Unsigned integer color components, when specified, are linearly mapped to floating-point values such that the largest representable value maps to 1.0 (full intensity), and zero maps to 0.0 (zero intensity). Signed integer color components, when specified, are linearly mapped to floating-point values such that the most positive representable value maps to 1.0, and the most negative representable value maps to
-
 1.0. Floating-point values are mapped directly.
Neither floating-point nor signed integer values are clamped to the range [0,1] before updating the current color. However, color components are clamped to this range before they are interpolated or written into a color buffer.
The current color can be updated at any time. In particular,
glColor
 can be called between a call to
glBegin
 and the corresponding call to
glEnd
.
The following functions retrieve information related to the
glColor
 functions:
glGet
 with argument
GL_CURRENT_COLOR
glGet
 with argument
GL_RGBA_MODE
See Also
glIndex


glColorMask
The
glColorMask
 function enables and disables writing of frame buffer color components.
void glColorMask
(
GLboolean
red
,
GLboolean
green
,
GLboolean
blue
,
GLboolean
alpha
);
Parameters
red, green, blue, alpha
Specify whether red, green, blue, and alpha can or cannot be written into the frame buffer. The default values are all
GL_TRUE
, indicating that the color components can be written.
Remarks
The
glColorMask
 function specifies whether the individual color components in the frame buffer can or cannot be written. If
red
 is
GL_FALSE
, for example, no change is made to the red component of any pixel in any of the color buffers, regardless of the drawing operation attempted.
Changes to individual bits of components cannot be controlled. Rather, changes are either enabled or disabled for entire color components.
The following functions retrieve information related to the
glColorMask
 function:
glGet
with argument
GL_COLOR_WRITEMASK
glGet
 with argument
GL_RGBA_MODE
Errors
GL_INVALID_OPERATION
 is generated if
glColorMask
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glColor
,
glIndex
,
glIndexMask
,
glDepthMask
,
glStencilMask


glColorMaterial
The
glColorMaterial
 function causes a material color to track the current color.
void glColorMaterial
(
GLenum
face
,
GLenum
mode
);
Parameters
face
Specifies whether front, back, or both front and back material parameters should track the current color. Accepted values are
GL_FRONT
,
GL_BACK
, and
GL_FRONT_AND_BACK
. The default value is
GL_FRONT_AND_BACK
.
mode
Specifies which of several material parameters track the current color. Accepted values are
GL_EMISSION
,
GL_AMBIENT
,
GL_DIFFUSE
,
GL_SPECULAR
, and
GL_AMBIENT_AND_DIFFUSE
. The default value is
GL_AMBIENT_AND_DIFFUSE
.
Remarks
The
glColorMaterial
 function specifies which material parameters track the current color. When
GL_COLOR_MATERIAL
 is enabled, the material parameter or parameters specified by
mode
, of the material or materials specified by
face
, track the current color at all times.
GL_COLOR_MATERIAL
 is enabled and disabled using the commands
glEnable
 and
glDisable
, called with
GL_COLOR_MATERIAL
 as their argument. By default, it is disabled.
The
glColorMaterial
 function allows a subset of material parameters to be changed for each vertex using only the
glColor
 command, without calling
glMaterial
. If only such a subset of parameters is to be specified for each vertex,
glColorMaterial
 is preferred over calling
glMaterial
.
The following functions retrieve information related to the
glColorMaterial
function:
glGet
 with argument
GL_COLOR_MATERIAL_PARAMETER
glGet
 with argument
GL_COLOR_MATERIAL_FACE
glIsEnabled
 with argument
GL_COLOR_MATERIAL
Errors
GL_INVALID_ENUM
 is generated if
face
 or
mode
 is not an accepted value.
GL_INVALID_OPERATION
 is generated if
glColorMaterial
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glColor
,
glEnable
,
glLight
,
glLightModel
,
glMaterial


glColorPointerEXT
The
glColorPointerEXT
 function defines an array of colors.
void glColorPointerEXT(
GLint
size
,
GLenum
type
,
GLsizei
stride
,
GLsizei
count
,
const GLvoid
 *
pointer
);
Parameters
size
Specifies the number of components per color. The value must be either 3 or 4.
type
Specifies the data type of each color component in a color array. Acceptable data types are specified with the following constants:
GL_BYTE
,
GL_UNSIGNED_BYTE
,
GL_SHORT
,
GL
_
UNSIGNED_SHORT
,
GL_INT
,
GL_UNSIGNED_INT
,
GL_FLOAT
, or
GL_DOUBLE_EXT
.
stride
Specifies the byte offset between consecutive colors. When
stride
 is zero, the colors are tightly packed in the array.
count
Specifies the number of static colors, counting from the first color.
pointer
Specifies a pointer to the first component of the first color element in a color array.
Remarks
The
 glColorPointerEXT
 function specifies the location and data format of an array of color components to use when rendering. The
stride
 parameter determines the byte offset from one color to the next, enabling the packing of vertex atributes in a single array or storage in separate arrays. In some implementations storing vertex attributes in a single array can be more efficient than the use of separate arrays. Starting from the first color array element,
count
indicates the total number of static elements. Your application can modify static elements, but once the elements are modified, the application must explicitly specify the array again before using the array for any rendering. Non-static color array elements are not accessed until you call
glDrawArraysEXT
 or
glArrayElementEXT
.
The color array is enabled when you specify the
 GL_COLOR_ARRAY_EXT
constant with
glEnable
. When enabled in this way, the color array is used when you call
glDrawArraysEXT
 or
glArrayElementEXT
. By default, the color array is disabled.
glColorPointerEXT
 calls are not entered in display lists.
When you specify a color array using
glColorPointerEXT
, the values of all the function's color array parameters are saved in a client-side state and static array elements can be cached. Because the color array parameters are client-side state, their values are not saved or restored by
glPushAttrib
 and
glPopAttrib
.
Although no error is generated when you specify the color array within
glBegin
 and
glEnd
 pairs, the results are undefined.
Note
Note
  The
 glColorPointerEXT
 function is an extension function that is not part of the standard OpenGL library but is part of the GL_EXT_vertex_array extension. To check whether your implementation of OpenGL supports
glColorPointerEXT
, call
glGetString
(
GL_EXTENSIONS
). If it returns GL_EXT_vertex_array,
glColorPointerEXT
 is supported. To obtain the function address of an extension function, call
wglGetProcAddress
.
The following functions retrieve information related to the
glColorPointerEXT
 function:
glIsEnabled
 with argument
GL_COLOR_ARRAY_EXT
glGet
 with argument
GL_COLOR_ARRAY_SIZE_EXT
glGet
 with argument
GL_COLOR_ARRAY_TYPE_EXT
glGet
 with argument
GL_COLOR_ARRAY_STRIDE_EXT
glGet
 with argument
GL_COLOR_ARRAY_COUNT_EXT
glGetPointervEXT
 with argument
GL_COLOR_ARRAY_POINTER_EXT
Errors
GL_INVALID_VALUE
 is generated if
size
 is not 3 or 4.
GL_INVALID_ENUM
 is generated if
type
 is not an accepted value.
GL_INVALID_VALUE
 is generated if
stride
 or
count
 is negative.
See Also
glArrayElementEXT
,
glDrawArraysEXT
,
glEdgeFlagPointerEXT
,
glIndexPointerEXT
,
glNormalPointerEXT
,
glTexCoordPointerEXT
,
glVertexPointerEXT
,
glGetString
wglGetProcAddress


glCopyPixels
The
glCopyPixels
 function copies pixels in the frame buffer.
void glCopyPixels
(
GLint
x
,
GLint
y
,
GLsizei
width
,
GLsizei
height
,
GLenum
type
);
Parameters
x, y
Specify the window coordinates of the lower left corner of the rectangular region of pixels to be copied.
width, height
Specify the dimensions of the rectangular region of pixels to be copied. Both must be nonnegative.
type
Specifies whether color values, depth values, or stencil values are to be copied. Symbolic constants
GL_COLOR
,
GL_DEPTH
 and
GL_STENCIL
 are accepted.
Remarks
The
glCopyPixels
 function copies a screen-aligned rectangle of pixels from the specified frame buffer location to a region relative to the current raster position. Its operation is well defined only if the entire pixel source region is within the exposed portion of the window. Results of copies from outside the window, or from regions of the window that are not exposed, are hardware dependent and undefined.
The
 x
 and
y
 parameters specify the window coordinates of the lower left corner of the rectangular region to be copied.
width
 and
height
 specify the dimensions of the rectangular region to be copied. Both
width
 and
height
 must not be negative.
Several parameters control the processing of the pixel data while it is being copied. These parameters are set with three commands:
glPixelTransfer
,
glPixelMap
, and
glPixelZoom
.
 This topic describes the effects on
glCopyPixels
 of most, but not all, of the parameters specified by these three commands.
The
glCopyPixels
 function copies values from each pixel with the lower left-hand corner at (
x
+ i,
y
+
j
) for 0
£
i
<
width
 and 0
£
j
<
height
. This pixel is said to be the
i
th pixel in the
 j
th row. Pixels are copied in row order from the lowest to the highest row, left to right in each row.
The
 type
 parameter specifies whether color, depth, or stencil data is to be copied. The details of the transfer for each data type are as follows:
GL_COLOR
Indices or RGBA colors are read from the buffer currently specified as the read source buffer (see
glReadBuffer
). If the GL is in color index mode, each index that is read from this buffer is converted to a fixed-point format with an unspecified number of bits to the right of the binary point. Each index is then shifted left by
GL_INDEX_SHIFT
 bits, and added to
GL_INDEX_OFFSET
. If
GL_INDEX_SHIFT
 is negative, the shift is to the right. In either case, zero bits fill otherwise unspecified bit locations in the result. If
GL_MAP_COLOR
 is true, the index is replaced with the value that it references in lookup table
GL_PIXEL_MAP_I_TO_I.
Whether the lookup replacement of the index is done or not, the integer part of the index is then ANDed with 2^
b
-
 1, where
b
 is the number of bits in a color index buffer.
If the GL is in RGBA mode, the red, green, blue, and alpha components of each pixel that is read are converted to an internal floating-point format with unspecified precision. The conversion maps the largest representable component value to 1.0, and component value zero to 0.0. The resulting floating-point color values are then multiplied by
GL_c_SCALE
 and added to
GL_c_BIAS
, where
c
 is
RED
,
GREEN
,
BLUE
, and
ALPHA
  for the respective color components. The results are clamped to the range [0,1]. If
GL_MAP_COLOR
 is true, each color component is scaled by the size of lookup table
GL_PIXEL_MAP_c_TO_c
, then replaced by the value that it references in that table.
c
 is
R
,
G
,
B
, or
A
, respectively.
The resulting indices or RGBA colors are then converted to fragments by attaching the current raster position
z
 coordinate and texture coordinates to each pixel, then assigning window coordinates (
x
 (r)
 +
i
,
y
 (r)
 + j
), where (
x
 (r)
  y
 (r)
) is the current raster position, and the pixel was the ith pixel in the jth row. These pixel fragments are then treated just like the fragments generated by rasterizing points, lines, or polygons. Texture mapping, fog, and all the fragment operations are applied before the fragments are written to the frame buffer.
GL_DEPTH
Depth values are read from the depth buffer and converted directly to an internal floating-point format with unspecified precision. The resulting floating-point depth value is then multiplied by
GL_DEPTH_SCALE
 and added to
GL_DEPTH_BIAS
. The result is clamped to the range [0,1].
The resulting depth components are then converted to fragments by attaching the current raster position color or color index and texture coordinates to each pixel, then assigning window coordinates (
x
 (r)
 +
i
,
y
 (r)
 + j
), where (x
 (r)
, y
 (r)
) is the current raster position, and the pixel was the ith pixel in the jth row. These pixel fragments are then treated just like the fragments generated by rasterizing points, lines, or polygons. Texture mapping, fog, and all the fragment operations are applied before the fragments are written to the frame buffer.
GL_STENCIL
Stencil indices are read from the stencil buffer and converted to an internal fixed-point format with an unspecified number of bits to the right of the binary point. Each fixed-point index is then shifted left by
GL_INDEX_SHIFT
 bits, and added to
GL_INDEX_OFFSET
. If
GL_INDEX_SHIFT
 is negative, the shift is to the right. In either case, zero bits fill otherwise unspecified bit locations in the result. If
GL_MAP_STENCIL
 is true, the index is replaced with the value that it references in lookup table
GL_PIXEL_MAP_S_TO_S
. Whether the lookup replacement of the index is done or not, the integer part of the index is then ANDed with 2^
b
-
 1, where
b
 is the number of bits in the stencil buffer. The resulting stencil indices are then written to the stencil buffer such that the index read from the
 i
th location of the
 j
th row is written to location (
x
 (r)
 + i, y
 (r)
 + j
), where (
x
 (r)
,
 y
 (r)
) is the current raster position. Only the pixel ownership test, the scissor test, and the stencil writemask affect these writes.
The rasterization described thus far assumes pixel zoom factors of 1.0. If
glPixelZoom
 is used to change the
x
 and
y
 pixel zoom factors, pixels are converted to fragments as follows. If (
x
 (r)
, y
 (r)
) is the current raster position, and a given pixel is in the
i
th location in the
j
th row of the source pixel rectangle, then fragments are generated for pixels whose centers are in the rectangle with corners at
(
x
 (r)
 + zoom
 (x)
 i, y
 (r)
 + zoom
 (y)
 j
)
and
(
x
 (r)
 + zoom
 (x)
(
i + 1
)
, y
 (r)
 + zoom
 (y)
 (
j + 1
))
where
zoom
 (x)
 is the value of
GL_ZOOM_X
 and
zoom
 (y)
 is the value of
GL_ZOOM_Y
.
Modes specified by
glPixelStore
 have no effect on the operation of
glCopyPixels
.
The following functions retrieve information related to the
glCopyPixels
function:
glGet
 with argument
GL_CURRENT_RASTER_POSITION
glGet
 with argument
GL_CURRENT_RASTER_POSITION_VALID
To copy the color pixel in the lower left corner of the window to the current raster position, use
glCopyPixels
(0, 0, 1, 1,
GL_COLOR
);
Errors
GL_INVALID_ENUM
 is generated if
type
 is not an accepted value.
GL_INVALID_VALUE
 is generated if either
width
 or
height
 is negative.
GL_INVALID_OPERATION
 is generated if
type
 is
GL_DEPTH
 and there is no depth buffer.
GL_INVALID_OPERATION
 is generated if
type
 is
GL_STENCIL
 and there is no stencil buffer.
GL_INVALID_OPERATION
 is generated if
glCopyPixels
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glDepthFunc
,
glDrawBuffer
,
glDrawPixels
,
glPixelMap
,
glPixelTransfer
,
glPixelZoom
,
glRasterPos
,
glReadBuffer
,
glReadPixels
,
glStencilFunc


glCullFace
The
glCullFace
 function specifies whether front- or back-facing facets can be culled.
void glCullFace
(
GLenum
mode
);
Parameters
mode
Specifies whether front- or back-facing facets are candidates for culling. Symbolic constants
GL_FRONT
 and
GL_BACK
 are accepted. The default value is
GL_BACK
.
Remarks
The
glCullFace
 function specifies whether front- or back-facing facets are culled (as specified by
mode
) when facet culling is enabled. Facet culling is enabled and disabled using the
glEnable
 and
glDisable
 commands with the argument
GL_CULL_FACE
. Facets include triangles, quadrilaterals, polygons, and rectangles.
The
glFrontFace
 function specifies which of the clockwise and counterclockwise facets are front-facing and back-facing.
The following functions retrieve information related to the
glCullFace
 function:
glGet
 with argument
GL_CULL_FACE_MODE
glIsEnabled
 with argument
GL_CULL_FACE
Errors
GL_INVALID_ENUM
 is generated if
mode
 is not an accepted value.
GL_INVALID_OPERATION
 is generated if
glCullFace
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glEnable
,
glFrontFace


glDeleteLists
The
glDeleteLists
 function deletes a contiguous group of display lists.
void glDeleteLists
(
GLuint
list
,
GLsizei
range
);
Parameters
list
Specifies the integer name of the first display list to delete.
range
Specifies the number of display lists to delete.
Remarks
The
glDeleteLists
 function causes a contiguous group of display lists to be deleted. The
list
 parameter is the name of the first display list to be deleted, and
range
 is the number of display lists to delete. All display lists
d
 with
list
£
d
£
list
 +
range
-
 1 are deleted.
All storage locations allocated to the specified display lists are freed, and the names are available for reuse at a later time. Names within the range that do not have an associated display list are ignored. If
range
 is zero, nothing happens.
Errors
GL_INVALID_VALUE
 is generated if
range
 is negative.
GL_INVALID_OPERATION
 is generated if
glDeleteLists
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glCallList
,
glCallLists
,
glGenLists
,
glIsList
,
glNewList


glDepthFunc
The
glDepthFunc
 function specifies the value used for depth buffer comparisons.
void glDepthFunc
(
GLenum
func
);
Parameters
func
Specifies the depth comparison function. Symbolic constants
GL_NEVER
,
GL_LESS
,
GL_EQUAL
,
GL_LEQUAL
,
GL_GREATER
,
GL_NOTEQUAL
,
GL_GEQUAL
, and
GL_ALWAYS
 are accepted. The default value is
GL_LESS
.
Remarks
The
glDepthFunc
 function specifies the function used to compare each incoming pixel
z
 value with the
z
 value present in the depth buffer. The comparison is performed only if depth testing is enabled. (See
glEnable
 of
GL_DEPTH_TEST
.)
The
 func
 parameter specifies the conditions under which the pixel will be drawn. The comparison functions are as follows:
GL_NEVER
Never passes.
GL_LESS
Passes if the incoming
z
 value is less than the stored
z
 value.
GL_EQUAL
Passes if the incoming
z
 value is equal to the stored
z
 value.
GL_LEQUAL
Passes if the incoming
z
 value is less than or equal to the stored
z
 value.
GL_GREATER
Passes if the incoming
z
 value is greater than the stored
z
 value.
GL_NOTEQUAL
Passes if the incoming
z
 value is not equal to the stored
z
 value.
GL_GEQUAL
Passes if the incoming
z
 value is greater than or equal to the stored
z
 value.
GL_ALWAYS
Always passes.
The default value of
func
 is
GL_LESS
. Initially, depth testing is disabled.
The following functions retrieve information related to the
glDepthFunc
 function:
glGet
 with argument
GL_DEPTH_FUNC
glIsEnabled
 with argument
GL_DEPTH_TEST
Errors
GL_INVALID_ENUM
 is generated if
func
 is not an accepted value.
GL_INVALID_OPERATION
 is generated if
glDepthFunc
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glDepthRange
,
glEnable


glDepthMask
The
glDepthMask
function enables or disables writing into the depth buffer.
void glDepthMask
(
GLboolean
flag
);
Parameters
flag
Specifies whether the depth buffer is enabled for writing. If
flag
 is zero, depth buffer writing is disabled. Otherwise, it is enabled. Initially, depth buffer writing is enabled.
Remarks
The
glDepthMask
function specifies whether the depth buffer is enabled for writing. If
flag
 is zero, depth buffer writing is disabled. Otherwise, it is enabled. Initially, depth buffer writing is enabled.
The following function retrieves information related to the
glDepthMask
function:
glGet
 with argument
GL_DEPTH_WRITEMASK
Errors
GL_INVALID_OPERATION
 is generated if
glDepthMask
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glColorMask
,
glDepthFunc
,
glDepthRange
,
glIndexMask
,
glStencilMask


glDepthRange
The
glDepthRange
function specifies the mapping of
z
values from normalized device coordinates to window coordinates.
void glDepthRange
(
GLclampd
near
,
GLclampd
far
);
Parameters
near
Specifies the mapping of the near clipping plane to window coordinates. The default value is 0.
far
Specifies the mapping of the far clipping plane to window coordinates. The default value is 1.
Remarks
After clipping and division by
w
,
z
 coordinates range from
-
1.0 to 1.0, corresponding to the near and far clipping planes. The
glDepthRange
function specifies a linear mapping of the normalized
z
 coordinates in this range to window
z
 coordinates. Regardless of the actual depth buffer implementation, window coordinate depth values are treated as though they range from 0.0 through 1.0 (like color components). Thus, the values accepted by
glDepthRange
 are both clamped to this range before they are accepted.
The default mapping of 0,1 maps the near plane to 0 and the far plane to 1. With this mapping, the depth buffer range is fully utilized.
It is not necessary that
near
 be less than
far
. Reverse mappings such as 1,0 are acceptable.
The following function retrieves information related to the
glDepthRange
 function:
glGet
 with argument
GL_DEPTH_RANGE
Errors
GL_INVALID_OPERATION
 is generated if
glDepthRange
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glDepthFunc
,
glViewport


glDrawArraysEXT
The
glDrawArraysEXT
 function specifies multiple primitives to render.
void glDrawArraysEXT
(
GLenum
mode
,
GLint
first
,
GLsizei
count
);
Parameters
mode
Specifies the kind of primitives to render. Acceptable types of primitives are specified with the following constants:
GL_POINTS
,
GL_LINE_STRIP
,
GL_LINE_LOOP
,
GL
_
LINES
,
GL_TRIANGLE_STRIP
,
GL_TRIANGLE_FAN
,
GL_TRIANGLES
,
GL_QUAD_STRIP
,
GL_QUADS
, or
GL_POLYGON
.
first
Specifies the starting index in the enabled arrays.
count
Specifies the number of indexes to render.
Remarks
The
 glDrawArraysEXT
 function enables you to specify multiple geometric primitives to render. Instead of calling separate OpenGL functions to pass each individual vertex, normal, or color, you can specify separate arrays of vertexes, normals, and colors to define a sequence of primitives (all the same kind) with a single call to
glDrawArraysEXT
.
When you call
glDrawArraysEXT
,
count
 sequential elements from each enabled array are used to construct a sequence of geometric primitives, beginning with the
first
 element. The
mode
 parameter specifies what kind of primitive to construct and how to use the array elements to construct the primitives.
After
glDrawArraysEXT
 returns, the values of vertex attributes that are modified by
glDrawArraysEXT
 are undefined. For example, if
GL_COLOR_ARRAY_EXT
 is enabled, the value of the current color is undefined after
glDrawArraysEXT
 returns. Attributes not modified by
glDrawArraysEXT
 remain defined. When
GL_VERTEX_ARRAY_EXT
 is not enabled, no geometric primitives are generated but the attributes corresponding to enabled arrays are modified.
You can include
glDrawArraysEXT
 in display lists. When you include
glDrawArraysEXT
 in a display list, the necessary array data, determined by the array pointers and the enables, are generated and entered in the display list. The values of array pointers and enables are determined during the creation of display lists.
Static array data can be read at any time. If any static array elements are modified and the array is not specified again, the results of any subsequent calls to
glDrawArraysEXT
 are undefined.
Although no error is generated when you specify an array more than once within
glBegin
 and
glEnd
 pairs, the results are undefined.
Note
Note
  The
 glDrawArraysEXT
 function is an extension function that is not part of the standard OpenGL library but is part of the GL_EXT_vertex_array extension. To check whether your implementation of OpenGL supports
glDrawArraysEXT
, call
glGetString
(
GL_EXTENSIONS
). If it returns GL_EXT_vertex_array,
glDrawArraysEXT
 is supported.
To obtain the address of an extension function, call
wglGetProcAddress
.
Errors
GL_INVALID_VALUE
 is generated if
count
 is negative.
GL_INVALID_ENUM
 is generated if
mode
 is not an accepted value.
GL_INVALID_OPERATION
 is generated if
glDrawArraysEXT
 is called between
glBegin
 and
glEnd
 pairs.
See Also
glArrayElementEXT
,
glColorPointerEXT
,
glEdgeFlagPointerEXT
,
glGetPointervEXT
,
glIndexPointerEXT
,
glNormalPointerEXT
,
glTexCoordPointerEXT
,
glVertexPointerEXT
,
glGetString
,
wglGetProcAddress


glDrawBuffer
The
glDrawBuffer
 function specifies which color buffers are to be drawn into.
void glDrawBuffer
(
GLenum
mode
);
Parameters
mode
Specifies up to four color buffers to be drawn into. Symbolic constants
GL_NONE, GL_FRONT_LEFT, GL_FRONT_RIGHT, GL_BACK_LEFT, GL_BACK_RIGHT, GL_FRONT, GL_BACK, GL_LEFT, GL_RIGHT, GL_FRONT_AND_BACK
, and
GL_AUX
i
, where
i
 is between 0 and
GL_AUX_BUFFERS
-
1, are accepted. (
GL_AUX_BUFFERS
 is not the upper limit; use
glGet
 to query the number of available aux buffers.) The default value is
GL_FRONT
 for single-buffered contexts, and
GL_BACK
 for double-buffered contexts.
Remarks
When colors are written to the frame buffer, they are written into the color buffers specified by
glDrawBuffer
. The specifications are as follows:
GL_NONE
No color buffers are written.
GL_FRONT_LEFT
Only the front left color buffer is written.
GL_FRONT_RIGHT
Only the front right color buffer is written.
GL_BACK_LEFT
Only the back left color buffer is written.
GL_BACK_RIGHT
Only the back right color buffer is written.
GL_FRONT
Only the front left and front right color buffers are written. If there is no front right color buffer, only the front left color buffer is written.
GL_BACK
Only the back left and back right color buffers are written. If there is no back right color buffer, only the back left color buffer is written.
GL_LEFT
Only the front left and back left color buffers are written. If there is no back left color buffer, only the front left color buffer is written.
GL_RIGHT
Only the front right and back right color buffers are written. If there is no back right color buffer, only the front right color buffer is written.
GL_FRONT_AND_BACK
All the front and back color buffers (front left, front right, back left, back right) are written. If there are no back color buffers, only the front left and front right color buffers are written. If there are no right color buffers, only the front left and back left color buffers are written. If there are no right or back color buffers, only the front left color buffer is written.
GL_AUX
i
Only auxiliary color buffer
i
 is written.
If more than one color buffer is selected for drawing, then blending or logical operations are computed and applied independently for each color buffer and can produce different results in each buffer.
Monoscopic contexts include only
left
 buffers, and stereoscopic contexts include both
left
 and
right
 buffers. Likewise, single-buffered contexts include only
front
 buffers, and double-buffered contexts include both
front
 and
back
buffers. The context is selected at GL initialization.
It is always the case that
GL_AUX
i
 =
GL_AUX0
 +
i
.
The following functions retrieve information related to the
glDrawBuffer
 function:
glGet
 with argument
GL_DRAW_BUFFER
glGet
 with argument
GL_AUX_BUFFERS
Errors
GL_INVALID_ENUM
 is generated if
mode
 is not an accepted value.
GL_INVALID_OPERATION
 is generated if none of the buffers indicated by
mode
 exists.
GL_INVALID_OPERATION
 is generated if
glDrawBuffer
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glBlendFunc
,
glColorMask
,
glIndexMask
,
glLogicOp
,
glReadBuffer


glDrawPixels
The
glDrawPixels
 function writes a block of pixels to the frame buffer.
void glDrawPixels
(
GLsizei
width
,
GLsizei
height
,
GLenum
format
,
GLenum
type
,
const GLvoid
*pixels
);
Parameters
width, height
Specify the dimensions of the pixel rectangle that will be written into the frame buffer.
format
Specifies the format of the pixel data. Symbolic constants
GL_COLOR_INDEX, GL_STENCIL_INDEX, GL_DEPTH_COMPONENT, GL_RGBA, GL_RED, GL_GREEN, GL_BLUE,
GL_ALPHA
,
GL_RGB
,
GL_LUMINANCE
, and
GL_LUMINANCE_ALPHA
 are accepted.
type
Specifies the data type for
pixels
. Symbolic constants
GL_UNSIGNED_BYTE, GL_BYTE, GL_BITMAP, GL_UNSIGNED_SHORT, GL_SHORT,
GL_UNSIGNED_INT
,
GL_INT
, and
GL_FLOAT
 are accepted.
pixels
Specifies a pointer to the pixel data.
Remarks
The
glDrawPixels
 function reads pixel data from memory and writes it into the frame buffer relative to the current raster position. Use
glRasterPos
 to set the current raster position, and use
glGet
 with argument
GL_CURRENT_RASTER_POSITION
 to query the raster position.
Several parameters define the encoding of pixel data in memory and control the processing of the pixel data before it is placed in the frame buffer. These parameters are set with four commands:
glPixelStore
,
glPixelTransfer
,
glPixelMap
, and
glPixelZoom
. This topic describes the effects on
glDrawPixels
 of many, but not all, of the parameters specified by these four commands.
Data is read from
pixels
 as a sequence of signed or unsigned bytes, signed or unsigned shorts, signed or unsigned integers, or single-precision floating-point values, depending on
type
. Each of these bytes, shorts, integers, or floating-point values is interpreted as one color or depth component, or one index, depending on
format
. Indices are always treated individually. Color components are treated as groups of one, two, three, or four values, again based on
format
. Both individual indices and groups of components are referred to as pixels. If
type
 is
GL_BITMAP
, the data must be unsigned bytes, and
format
 must be either
GL_COLOR_INDEX
 or
GL_STENCIL_INDEX
. Each unsigned byte is treated as eight 1-bit pixels, with bit ordering determined by
GL_UNPACK_LSB_FIRST
 (see
glPixelStore
).
The
 width
x
height
 pixels are read from memory, starting at location
pixels
. By default, these pixels are taken from adjacent memory locations, except that after all
width
 pixels are read, the read pointer is advanced to the next four-byte boundary. The four-byte row alignment is specified by
glPixelStore
 with argument
GL_UNPACK_ALIGNMENT
, and it can be set to one, two, four, or eight bytes. Other pixel store parameters specify different read pointer advancements, both before the first pixel is read, and after all
width
 pixels are read.
The
width
x
height
 pixels that are read from memory are each operated on in the same way, based on the values of several parameters specified by
glPixelTransfer
 and
glPixelMap
. The details of these operations, as well as the target buffer into which the pixels are drawn, are specific to the format of the pixels, as specified by
format
.
format
 can assume one of eleven symbolic values:
GL_COLOR_INDEX
Each pixel is a single value, a color index. It is converted to fixed-point format, with an unspecified number of bits to the right of the binary point, regardless of the memory data type. Floating-point values convert to true fixed-point values. Signed and unsigned integer data is converted with all fraction bits set to zero. Bitmap data convert to either 0.0 or 1.0.
Each fixed-point index is then shifted left by
GL_INDEX_SHIFT
 bits and added to
GL_INDEX_OFFSET
. If
GL_INDEX_SHIFT
 is negative, the shift is to the right. In either case, zero bits fill otherwise unspecified bit locations in the result.
If the GL is in RGBA mode, the resulting index is converted to an RGBA pixel  using the
GL_PIXEL_MAP_I_TO_R
,
GL_PIXEL_MAP_I_TO_G
,
GL_PIXEL_MAP_I_TO_B
, and
GL_PIXEL_MAP_I_TO_A
 tables. If the GL is in color index mode, and if
GL_MAP_COLOR
 is true, the index is replaced with the value that it references in lookup table
GL_PIXEL_MAP_I_TO_I
. Whether the lookup replacement of the index is done or not, the integer part of the index is then ANDed with 2
b
-
1, where
b
 is the number of bits in a color index buffer.
The resulting indices or RGBA colors are then converted to fragments by attaching the current raster position
z
 coordinate and texture coordinates to each pixel, then assigning x and y window coordinates to the
n
th fragment such that
x
 (n)
 = x
 (r)
 + n
mod
width
y
 (n)
 = y
 (r)
+
ë
n
/
width
û
where (
x
 (r)
 , y
 (r)
) is the current raster position. These pixel fragments are then treated just like the fragments generated by rasterizing points, lines, or polygons. Texture mapping, fog, and all the fragment operations are applied before the fragments are written to the frame buffer.
GL_STENCIL_INDEX
Each pixel is a single value, a stencil index. It is converted to fixed-point format, with an unspecified number of bits to the right of the binary point, regardless of the memory data type. Floating-point values convert to true fixed-point values. Signed and unsigned integer data is converted with all fraction bits set to zero. Bitmap data convert to either 0.0 or 1.0.
Each fixed-point index is then shifted left by
GL_INDEX_SHIFT
 bits, and added to
GL_INDEX_OFFSET
. If
GL_INDEX_SHIFT
 is negative, the shift is to the right. In either case, zero bits fill otherwise unspecified bit locations in the result. If
GL_MAP_STENCIL
 is true, the index is replaced with the value that it references in lookup table
GL_PIXEL_MAP_S_TO_S
. Whether the lookup replacement of the index is done or not, the integer part of the index is then ANDed with 2
b
-
 1, where
b
 is the number of bits in the stencil buffer. The resulting stencil indices are then written to the stencil buffer such that the
n
th index is written to location
x
 (n)
 = x
 (r)
 + n
 mod
width
y
 (n)
 =
y
 (r)
 +
ë
n
 /
width
û
where (
x
 (r)
 , y
 (r)
) is the current raster position. Only the pixel ownership test, the scissor test, and the stencil writemask affect these writes.
GL_DEPTH_COMPONENT
Each pixel is a single-depth component. Floating-point data is converted directly to an internal floating-point format with unspecified precision. Signed integer data is mapped linearly to the internal floating-point format such that the most positive representable integer value maps to 1.0, and the most negative representable value maps to -1.0. Unsigned integer data is mapped similarly: the largest integer value maps to 1.0
,
and zero maps to 0.0. The resulting floating-point depth value is then multiplied by
GL_DEPTH_SCALE
 and added to
GL_DEPTH_BIAS
. The result is clamped to the range [0,1].
The resulting depth components are then converted to fragments by attaching the current raster position color or color index and texture coordinates to each pixel, then assigning x and y window coordinates to the nth fragment such that
x
 (n)
 = x
 (r)
 + n
 mod
width
y
 (n)
 = y
 (r)
 +
ë
n
 /
width
û
where (
x
 (r)
 , y
 (r)
) is the current raster position. These pixel fragments are then treated just like the fragments generated by rasterizing points, lines, or polygons. Texture mapping, fog, and all the fragment operations are applied before the fragments are written to the frame buffer.
GL_RGBA
Each pixel is a four-component group: red first, followed by green, followed by blue, followed by alpha.
Floating-point values are converted directly to an internal floating-point format with unspecified precision. Signed integer values are mapped linearly to the internal floating-point format such that the most positive representable integer value maps to 1.0, and the most negative representable value maps to
-
 1.0. Unsigned integer data is mapped similarly: the largest integer value maps to 1.0, and zero maps to 0.0. The resulting floating-point color values are then multiplied by
GL_c_SCALE
 and added to
GL_c_BIAS
, where
c
 is
RED
,
GREEN
,
BLUE
, and
ALPHA
  for the respective color components. The results are clamped to the range [0,1].
If
GL_MAP_COLOR
 is true, each color component is scaled by the size of lookup table
GL_PIXEL_MAP_c_TO_c
, then replaced by the value that it references in that table.
c
 is
R
,
G
,
B
, or
A
, respectively.
The resulting RGBA colors are then converted to fragments by attaching the current raster position
z
 coordinate and texture coordinates to each pixel, then assigning x and y window coordinates to the nth fragment such that
x
 (n)
 = x
 (r)
 + n
 mod
width
y
 (n)
 = y
 (r)
 +
ë
n
/
width
û
where (
x
 (r)
 , y
 (r)
) is the current raster position. These pixel fragments are then treated just like the fragments generated by rasterizing points, lines, or polygons. Texture mapping, fog, and all the fragment operations are applied before the fragments are written to the frame buffer.
GL_RED
Each pixel is a single red component. This component is converted to the internal floating-point format in the same way as the red component of an RGBA pixel is, then it is converted to an RGBA pixel with green and blue set to 0.0, and alpha set to 1.0. After this conversion, the pixel is treated just as if it had been read as an RGBA pixel.
GL_GREEN
Each pixel is a single green component. This component is converted to the internal floating-point format in the same way as the green component of an RGBA pixel is, then it is converted to an RGBA pixel with red and blue set to 0.0, and alpha set to 1.0. After this conversion, the pixel is treated just as if it had been read as an RGBA pixel.
GL_BLUE
Each pixel is a single blue component. This component is converted to the internal floating-point format in the same way as the blue component of an RGBA pixel is, then it is converted to an RGBA pixel with red and green set to 0.0, and alpha set to 1.0. After this conversion, the pixel is treated just as if it had been read as an RGBA pixel.
GL_ALPHA
Each pixel is a single alpha component. This component is converted to the internal floating-point format in the same way as the alpha component of an RGBA pixel is, then it is converted to an RGBA pixel with red, green, and blue set to 0.0. After this conversion, the pixel is treated just as if it had been read as an RGBA pixel.
GL_RGB
Each pixel is a three-component group: red first, followed by green, followed by blue. Each component is converted to the internal floating-point format in the same way as the red, green, and blue components of an RGBA pixel are. The color triple is converted to an RGBA pixel with alpha set to 1.0. After this conversion, the pixel is treated just as if it had been read as an RGBA pixel.
GL_LUMINANCE
Each pixel is a single luminance component. This component is converted to the internal floating-point format in the same way as the red component of an RGBA pixel is, then it is converted to an RGBA pixel with red, green, and blue set to the converted luminance value, and alpha set to 1.0. After this conversion, the pixel is treated just as if it had been read as an RGBA pixel.
GL_LUMINANCE_ALPHA
Each pixel is a two-component group: luminance first, followed by alpha. The two components are converted to the internal floating-point format in the same way as the red component of an RGBA pixel is, then they are converted to an RGBA pixel with red, green, and blue set to the converted luminance value, and alpha set to the converted alpha value. After this conversion, the pixel is treated just as if it had been read as an RGBA pixel.
The following table summarizes the meaning of the valid constants for the
type
parameter:
Type
Corresponding Type
GL_UNSIGNED_BYTE
unsigned 8-bit integer
GL_BYTE
signed 8-bit integer
GL_BITMAP
single bits in unsigned 8-bit integers
GL_UNSIGNED_SHORT
unsigned 16-bit integer
GL_SHORT
signed 16-bit integer
GL_UNSIGNED_INT
unsigned 32-bit integer
GL_INT
32-bit integer
GL_FLOAT
single-precision floating-point
The rasterization described thus far assumes pixel zoom factors of 1.0. If
glPixelZoom
 is used to change the x and y pixel zoom factors, pixels are converted to fragments as follows. If (
x
 (r)
, y
 (r)
) is the current raster position, and a given pixel is in the
n
th column and mth row of the pixel rectangle, then fragments are generated for pixels whose centers are in the rectangle with corners at
 (
x
 (r)
 + zoom
 (x)
 n, y
 (r)
 + zoom
 (y)
 m
)
 (
x
 (r)
 + zoom
 (x)
 (
n
 + 1),
y
 (r)
 + zoom
 (y)
 (
m
 + 1))
where
zoom
 (x)
 is the value of
GL_ZOOM_X
 and
zoom
 (y)
 is the value of
GL_ZOOM_Y
.
The following functions retrieve information related to the
glDrawPixels
 function:
glGet
 with argument
GL_CURRENT_RASTER_POSITION
glGet
 with argument
GL_CURRENT_RASTER_POSITION_VALID
Errors
GL_INVALID_VALUE
 is generated if either
width
 or
height
 is negative.
GL_INVALID_ENUM
 is generated if
format
 or
type
 is not one of the accepted values.
GL_INVALID_OPERATION
 is generated if
format
 is
GL_RED
,
GL_GREEN
,
GL_BLUE
,
GL_ALPHA
,
GL_RGB
,
GL_RGBA
,
GL_LUMINANCE
, or
GL_LUMINANCE_ALPHA
, and the GL is in color index mode.
GL_INVALID_ENUM
 is generated if
type
 is
GL_BITMAP
 and
format
 is not either
GL_COLOR_INDEX
 or
GL_STENCIL_INDEX
.
GL_INVALID_OPERATION
 is generated if
format
 is
GL_STENCIL_INDEX
 and there is no stencil buffer.
GL_INVALID_OPERATION
 is generated if
glDrawPixels
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glAlphaFunc
,
glBlendFunc
,
glCopyPixels
,
glDepthFunc
,
glLogicOp
,
glPixelMap
,
glPixelStore
,
glPixelTransfer
,
glPixelZoom
,
glRasterPos
,
glReadPixels
,
glScissor
,
glStencilFunc


glEdgeFlag
glEdgeFlag, glEdgeFlagv
The
glEdgeFlag
 and
glEdgeFlagv
 functions flag edges as either boundary or nonboundary.
void glEdgeFlag
(
GLboolean
flag
);
Parameters
flag
Specifies the current edge flag value, either true or false.
void glEdgeFlagv
(
const GLboolean
*flag
);
Parameters
flag
Specifies a pointer to an array that contains a single Boolean element, which replaces the current edge flag value.
Remarks
Each vertex of a polygon, separate triangle, or separate quadrilateral specified between a
glBegin
/
glEnd
 pair is marked as the start of either a boundary or nonboundary edge. If the current edge flag is true when the vertex is specified, the vertex is marked as the start of a boundary edge. Otherwise, the vertex is marked as the start of a nonboundary edge. The
glEdgeFlag
 function sets the edge flag to true if
flag
 is nonzero, false otherwise.
The vertexes of connected triangles and connected quadrilaterals are always marked as boundary, regardless of the value of the edge flag.
Boundary and nonboundary edge flags on vertexes are significant only if
GL_POLYGON_MODE
 is set to
GL_POINT
 or
GL_LINE
. See
glPolygonMode
.
Initially, the edge flag bit is true.
The current edge flag can be updated at any time. In particular,
glEdgeFlag
 can be called between a call to
glBegin
 and the corresponding call to
glEnd
.
The following function retrieves information related to the
glEdgeFlag
 function:
glGet
 with argument
GL_EDGE_FLAG
See Also
glBegin
,
glPolygonMode


glEdgeFlagPointerEXT
The
glEdgeFlagPointerEXT
 function defines an array of edge flags.
void glEdgeFlagPointerEXT
(
GLsizei
stride
,
GLsizei
count
,
const GLboolean
 *
pointer
);
Parameters
stride
Specifies the byte offset between consecutive edge flags. When
stride
 is zero, the edge flags are tightly packed in the array.
count
Specifies the number of edge flags, counting from the first, that are static.
pointer
Specifies a pointer to the first edge flag in the array.
Remarks
The
 glEdgeFlagPointerEXT
 function specifies the location and data of an array of Boolean edge flags to use when rendering. The
stride
 parameter determines the byte offset from one edge flag to the next, which enables the packing of vertexes and attributes in a single array or storage in separate arrays. In some implementations storing the vertexes and attributes in a single array can be more efficient than using separate arrays. Starting from the first edge-flag array element,
count
 indicates the total number of static elements. Your application can modify static elements, but once the elements are modified, the application must explicitly specify the array again before using the array for any rendering. Non-static array elements are not accessed until you call
glDrawArraysEXT
 or
glArrayElementEXT
.
Static array data can be read at any time. If any static array elements are modified and the array is not specified again, the results of any subsequent calls to
glEdgeFlagPointerEXT
 are undefined.
An edge-flag array is enabled when you specify the
 GL_EDGE_FLAG_ARRAY_EXT
constant with
glEnable
. When enabled,
glDrawArraysEXT
 and
glArrayElementEXT
 use the edge-flag array. By default the edge-flag array is disabled.
You cannot include
glEdgeFlagPointerEXT
 in display lists.
When you specify an edge-flag array using
glEdgeFlagPointerEXT
, the values of all the function's edge-flag array parameters are saved in a client-side state and static array elements can be cached. Because the edge-flag array parameters are client-side state, their values are not saved or restored by
glPushAttrib
 and
glPopAttrib
.
Although no error is generated when you call
glEdgeFlagPointerEXT
 within
glBegin
 and
glEnd
 pairs, the results are undefined.
Note
Note
  The
 glEdgeFlagPointerEXT
 function is an extension function that is not part of the standard OpenGL library but is part of the
GL_EXT_vertex_array
 extension. To check whether your implementation of OpenGL supports
glEdgeFlagPointerEXT
, call
glGetString
(
GL_EXTENSIONS
). If it returns GL_EXT_vertex_array,
glEdgeFlagPointerEXT
 is supported.
To obtain the address of an extension function, call
wglGetProcAddress
.
The following functions retrieve information related to the
glEdgeFlagPointerEXT
 function:
glIsEnabled
 with argument
GL_EDGE_FLAG_ARRAY_EXT
glGet
 with argument
GL_EDGE_FLAG_ARRAY_STRIDE_EXT
glGet
 with argument
GL_EDGE_FLAG_ARRAY_COUNT_EXT
glGetPointervEXT
 with argument
GL_EDGE_FLAG_ARRAY_POINTER_EXT
Errors
GL_INVALID_ENUM
 is generated if
stride
 or
count
 is negative.
See Also
glArrayElementEXT
,
glColorPointerEXT
,
glDrawArraysEXT
,
glGetPointervEXT
,
glIndexPointerEXT
,
glNormalPointerEXT
,
glTexCoordPointerEXT
,
glVertexPointerEXT
,
glGetString
,
wglGetProcAddress


glEnable
glEnable, glDisable
The
glEnable
 and
glDisable
 functions enable or disable GL capabilities.
void
glEnable
(
GLenum
cap
);
Parameters
cap
Specifies a symbolic constant indicating a GL capability.
void glDisable
(
GLenum
cap
);
Parameters
cap
Specifies a symbolic constant indicating a GL capability.
Remarks
The
glEnable
 and
glDisable
 functions enable and disable various capabilities. Use
glIsEnabled
 or
glGet
 to determine the current setting of any capability.
Both the
glEnable
 and
glDisable
 functions take a single argument,
cap
, which can assume one of the following values:
GL_ALPHA_TEST
If enabled, do alpha testing. See
glAlphaFunc
.
GL_AUTO_NORMAL
If enabled, compute surface normal vectors analytically when either
GL_MAP2_VERTEX_3
 or
GL_MAP2_VERTEX_4
 is used to generate vertexes. See
glMap2
.
GL_BLEND
If enabled, blend the incoming RGBA color values with the values in the color buffers. See
glBlendFunc
.
GL_CLIP_PLANE
i
If enabled, clip geometry against user-defined clipping plane
i
. See
glClipPlane
.
GL_COLOR_MATERIAL
If enabled, have one or more material parameters track the current color. See
glColorMaterial
.
GL_CULL_FACE
If enabled, cull polygons based on their winding in window coordinates. See
glCullFace
.
GL_DEPTH_TEST
If enabled, do depth comparisons and update the depth buffer. See
glDepthFunc
 and
glDepthRange
.
GL_DITHER
If enabled, dither color components or indices before they are written to the color buffer.
GL_FOG
If enabled, blend a fog color into the posttexturing color. See
glFog
.
GL_LIGHT
i
If enabled, include light
i
 in the evaluation of the lighting equation. See
glLightModel
 and
glLight
.
GL_LIGHTING
If enabled, use the current lighting parameters to compute the vertex color or index. Otherwise, simply associate the current color or index with each vertex. See
glMaterial
,
glLightModel
, and
glLight
.
GL_LINE_SMOOTH
If enabled, draw lines with correct filtering. Otherwise, draw aliased lines. See
glLineWidth
.
GL_LINE_STIPPLE
If enabled, use the current line stipple pattern when drawing lines. See
glLineStipple
.
GL_LOGIC_OP
If enabled, apply the currently selected logical operation to the incoming and color buffer indices. See
glLogicOp
.
GL_MAP1_COLOR_4
If enabled, calls to
glEvalCoord1
,
glEvalMesh1
, and
glEvalPoint1
 will generate RGBA values.
See
glMap1
.
GL_MAP1_INDEX
If enabled, calls to
glEvalCoord1, glEvalMesh1
, and
glEvalPoint1
will generate color indices. See
glMap1
.
GL_MAP1_NORMAL
If enabled, calls to
glEvalCoord1
,
glEvalMesh1
, and
glEvalPoint1
 will generate normals.
See
glMap1
.
GL_MAP1_TEXTURE_COORD_1
If enabled, calls to
glEvalCoord1, glEvalMesh1
, and
glEvalPoint1
 will generate
s
 texture coordinates. See
glMap1
.
GL_MAP1_TEXTURE_COORD_2
If enabled, calls to
glEvalCoord1
,
glEvalMesh1
, and
glEvalPoint1
 will generate
s
 and
t
 texture coordinates. See
glMap1
.
GL_MAP1_TEXTURE_COORD_3
If enabled, calls to
glEvalCoord1, glEvalMesh1
, and
glEvalPoint1
 will generate
s
,
t
, and
r
 texture coordinates. See
glMap1
.
GL_MAP1_TEXTURE_COORD_4
If enabled, calls to
glEvalCoord1
,
glEvalMesh1
, and
glEvalPoint1
 will generate
s
,
t
,
r
, and
q
 texture coordinates.
glMap1
.
GL_MAP1_VERTEX_3
If enabled, calls to
glEvalCoord1, glEvalMesh1
, and
glEvalPoint1
will generate
x
,
y
, and
z
 vertex coordinates. See
glMap1
.
GL_MAP1_VERTEX_4
If enabled, calls to
glEvalCoord1
,
glEvalMesh1
, and
glEvalPoint1
 will generate
homogeneous
x
,
y
,
z
, and
w
 vertex coordinates. See
glMap1
.
GL_MAP2_COLOR_4
If enabled, calls to
glEvalCoord2, glEvalMesh2
, and
glEvalPoint2
will generate RGBA values.
See
glMap2
.
GL_MAP2_INDEX
If enabled, calls to
glEvalCoord2
,
glEvalMesh2
, and
glEvalPoint2
will generate color indices. See
glMap2
.
GL_MAP2_NORMAL
If enabled, calls to
glEvalCoord2
,
glEvalMesh2
, and
glEvalPoint2
 will generate normals. See
glMap2
.
GL_MAP2_TEXTURE_COORD_1
If enabled, calls to
glEvalCoord2
,
glEvalMesh2
, and
glEvalPoint2
 will generate
s
texture coordinates. See
glMap2
.
GL_MAP2_TEXTURE_COORD_2
If enabled, calls to
glEvalCoord2
,
glEvalMesh2
, and
glEvalPoint2
 will generate
s
 and
t
 texture coordinates. See
glMap2
.
GL_MAP2_TEXTURE_COORD_3
If enabled, calls to
glEvalCoord2
,
glEvalMesh2
, and
glEvalPoint2
 will generate
s
,
t
, and
r
 texture coordinates. See
glMap2
.
GL_MAP2_TEXTURE_COORD_4
If enabled, calls to
glEvalCoord2
,
glEvalMesh2
, and
glEvalPoint2
 will generate
s
,
t
,
r
, and
q
 texture coordinates. See
glMap2
.
GL_MAP2_VERTEX_3
If enabled, calls to
glEvalCoord2
,
glEvalMesh2
, and
glEvalPoint2
 will generate
x
,
y
, and
z
 vertex coordinates. See
glMap2
.
GL_MAP2_VERTEX_4
If enabled, calls to
glEvalCoord2
,
glEvalMesh2
, and
glEvalPoint2
 will generate
homogeneous
x
,
y
,
z
, and
w
 vertex coordinates. See
glMap2
.
GL_NORMALIZE
If enabled, normal vectors specified with
glNormal
 are scaled to unit length after transformation. See
glNormal
.
GL_POINT_SMOOTH
If enabled, draw points with proper filtering. Otherwise, draw aliased points. See
glPointSize
.
GL_POLYGON_SMOOTH
If enabled, draw polygons with proper filtering. Otherwise, draw aliased polygons. See
glPolygonMode
.
GL_POLYGON_STIPPLE
If enabled, use the current polygon stipple pattern when rendering polygons. See
glPolygonStipple
.
GL_SCISSOR_TEST
If enabled, discard fragments that are outside the scissor rectangle. See
glScissor
.
GL_STENCIL_TEST
If enabled, do stencil testing and update the stencil buffer. See
glStencilFunc
 and
glStencilOp
.
GL_TEXTURE_1D
If enabled, one-dimensional texturing is performed (unless two-dimensional texturing is also enabled). See
glTexImage1D
.
GL_TEXTURE_2D
If enabled, two-dimensional texturing is performed. See
glTexImage2D
.
GL_TEXTURE_GEN_Q
If enabled, the
q
 texture coordinate is computed using the texture generation function defined with
glTexGen
. Otherwise, the current
q
 texture coordinate is used.
GL_TEXTURE_GEN_R
If enabled, the
r
 texture coordinate is computed using the texture generation function defined with
glTexGen
. Otherwise, the current
r
 texture coordinate is used.
GL_TEXTURE_GEN_S
If enabled, the
s
 texture coordinate is computed using the texture generation function defined with
glTexGen
. Otherwise, the current
s
 texture coordinate is used.
GL_TEXTURE_GEN_T
If enabled, the
t
 texture coordinate is computed using the texture generation function defined with
glTexGen
. Otherwise, the current
t
 texture coordinate is used.
Errors
GL_INVALID_ENUM
 is generated if
cap
 is not one of the values listed above.
GL_INVALID_OPERATION
 is generated if
glEnable
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glAlphaFunc
,
glBlendFunc
,
glClipPlane
,
glColorMaterial
,
glCullFace
,
glDepthFunc
,
glDepthRange
,
glFog
,
glGet
,
glIsEnabled
,
glLight
,
glLightModel
,
glLineWidth
,
glLineStipple
,
glLogicOp
,
glMap1
,
glMap2
,
glMaterial
,
glNormal
,
glPointSize
,
glPolygonMode
,
glPolygonStipple
,
glScissor
,
glStencilFunc
,
glStencilOp
,
glTexGen
,
glTexImage1D
,
glTexImage2D


glEvalCoord
glEvalCoord1d, glEvalCoord1f, glEvalCoord2d, glEvalCoord2f, glEvalCoord1dv, glEvalCoord1fv, glEvalCoord2dv, glEvalCoord2fv
These functions evaluate enabled one- and two-dimensional maps.
void glEvalCoord1d
(
GLdouble
u
);
void glEvalCoord1f
(
GLfloat
u
);
void glEvalCoord2d
(
GLdouble
u
,
GLdouble
v
);
void glEvalCoord2f
(
GLfloat
u
,
GLfloat
v
);
Parameters
u
Specifies a value that is the domain coordinate
u
 to the basis function defined in a previous
glMap1
 or
glMap2
 command.
v
Specifies a value that is the domain coordinate
v
 to the basis function defined in a previous
glMap2
 command. This argument is not present in an
glEvalCoord1
 command.
void glEvalCoord1dv
(
const GLdouble
*u
);
void glEvalCoord1fv(
const GLfloat
*u
);
void glEvalCoord2dv(
const GLdouble
*u
);
void glEvalCoord2fv(
const GLfloat
*u
);
Parameters
u
Specifies a pointer to an array containing either one or two domain coordinates. The first coordinate is
u
. The second coordinate is
v
, which is present only in
glEvalCoord2
 versions.
Remarks
The
 glEvalCoord1
 function evaluates enabled one-dimensional maps at argument
u
.
glEvalCoord2
 does the same for two-dimensional maps using two domain values,
u
 and
v
. Maps are defined with
glMap1
 and
glMap2
 and enabled and disabled with
glEnable
 and
glDisable
.
When one of the
glEvalCoord
 commands is issued, all currently enabled maps of the indicated dimension are evaluated. Then, for each enabled map, it is as if the corresponding GL command was issued with the computed value. That is, if
GL_MAP1_INDEX
 or
GL_MAP2_INDEX
 is enabled, a
glIndex
 command is simulated. If
GL_MAP1_COLOR_4
 or
GL_MAP2_COLOR_4
 is enabled, a
glColor
 command is simulated. If
GL_MAP1_NORMAL
 or
GL_MAP2_NORMAL
 is enabled, a normal vector is produced, and if any of
GL_MAP1_TEXTURE_COORD_1
,
GL_MAP1_TEXTURE_COORD_2
,
GL_MAP1_TEXTURE_COORD_3
,
GL_MAP1_TEXTURE_COORD_4
,
GL_MAP2_TEXTURE_COORD_1
,
GL_MAP2_TEXTURE_COORD_2
,
GL_MAP2_TEXTURE_COORD_3
, or
GL_MAP2_TEXTURE_COORD_4
 is enabled, then an appropriate
glTexCoord
 command is simulated.
The GL uses evaluated values instead of current values for those evaluations that are enabled, and current values otherwise, for color, color index, normal, and texture coordinates. However, the evaluated values do not update the current values. Thus, if
glVertex
 commands are interspersed with
glEvalCoord
 commands, the color, normal, and texture coordinates associated with the
glVertex
 commands are not affected by the values generated by the
glEvalCoord
 commands, but rather only by the most recent
glColor
,
glIndex
,
glNormal
, and
glTexCoord
 commands.
No commands are issued for maps that are not enabled. If more than one texture evaluation is enabled for a particular dimension (for example,
GL_MAP2_TEXTURE_COORD_1
 and
GL_MAP2_TEXTURE_COORD_2
), then only the evaluation of the map that produces the larger number of coordinates (in this case,
GL_MAP2_TEXTURE_COORD_2
) is carried out.
GL_MAP1_VERTEX_4
 overrides
GL_MAP1_VERTEX_3
, and
GL_MAP2_VERTEX_4
 overrides
GL_MAP2_VERTEX_3
, in the same manner. If neither a three- nor four-component vertex map is enabled for the specified dimension, the
glEvalCoord
 command is ignored.
If automatic normal generation is enabled, by calling
glEnable
 with argument
GL_AUTO_NORMAL
,
glEvalCoord2
 generates surface normals analytically, regardless of the contents or enabling of the
GL_MAP2_NORMAL
 map. Let
Then the generated normal
 n
 is
If automatic normal generation is disabled, the corresponding normal map
GL_MAP2_NORMAL
, if enabled, is used to produce a normal. If neither automatic normal generation nor a normal map is enabled, no normal is generated for
glEvalCoord2
 commands.
The following functions retrieve information related to the
glEvalCoord
 functions:
glIsEnabled
 with argument
GL_MAP1_VERTEX_3
glIsEnabled
 with argument
 GL_MAP1_VERTEX_4
glIsEnabled
 with argument
 GL_MAP1_INDEX
glIsEnabled
 with argument
 GL_MAP1_COLOR_4
glIsEnabled
 with argument
 GL_MAP1_NORMAL
glIsEnabled
 with argument
 GL_MAP1_TEXTURE_COORD_1
glIsEnabled
 with argument
 GL_MAP1_TEXTURE_COORD_2
glIsEnabled
 with argument
 GL_MAP1_TEXTURE_COORD_3
glIsEnabled
 with argument
 GL_MAP1_TEXTURE_COORD_4
glIsEnabled
 with argument
 GL_MAP2_VERTEX_3
glIsEnabled
 with argument
 GL_MAP2_VERTEX_4
glIsEnabled
 with argument
 GL_MAP2_INDEX
glIsEnabled
 with argument
 GL_MAP2_COLOR_4
glIsEnabled
 with argument
 GL_MAP2_NORMAL
glIsEnabled
 with argument
 GL_MAP2_TEXTURE_COORD_1
glIsEnabled
 with argument
 GL_MAP2_TEXTURE_COORD_2
glIsEnabled
 with argument
 GL_MAP2_TEXTURE_COORD_3
glIsEnabled
 with argument
 GL_MAP2_TEXTURE_COORD_4
glIsEnabled
 with argument
 GL_AUTO_NORMAL
glGetMap
See Also
glBegin
,
glColor
,
glEnable
,
glEvalMesh
,
glEvalPoint
,
glIndex
,
glMap1
,
glMap2
,
glMapGrid
,
glNormal
,
glTexCoord
,
glVertex


glEvalMesh
glEvalMesh1, glEvalMesh2
The
glEvalMesh1
 and
glEvalMesh2
 functions compute a one- or two-dimensional grid of points or lines.
void glEvalMesh1
(
GLenum
mode
,
GLint
i1
,
GLint
i2
);
Parameters
mode
In
glEvalMesh1
, specifies whether to compute a one-dimensional mesh of points or lines. Symbolic constants
GL_POINT
 and
GL_LINE
 are accepted.
i1, i2
Specify the first and last integer values for grid domain variable
 i
.
void glEvalMesh2
(
GLenum
mode
,
GLint
i1
,
GLint
i2
,
GLint
j1
,
GLint
j2
);
Parameters
mode
In
glEvalMesh2
, specifies whether to compute a two-dimensional mesh of points, lines, or polygons. Symbolic constants
GL_POINT
,
GL_LINE
, and
GL_FILL
 are accepted.
i1, i2
Specify the first and last integer values for grid domain variable
 i
.
j1, j2
Specify the first and last integer values for grid domain variable
j
.
Remarks
The
glMapGrid
 and
glEvalMesh
 functions are used in tandem to efficiently generate and evaluate a series of evenly spaced map domain values.
glEvalMesh
 steps through the integer domain of a one- or two-dimensional grid, whose range is the domain of the evaluation maps specified by
glMap1
 and
glMap2
.
mode
 determines whether the resulting vertexes are connected as points, lines, or filled polygons.
In the one-dimensional case,
glEvalMesh1
, the mesh is generated as if the following code fragment were executed:
glBegin
(
type
) ;
for (
i
 =
i1
;
 i
<=
i2
;
 i
 += 1)
glEvalCoord1
(
i
·
D
u
+
u
 (1)
)
 (
)
glEnd
( );
where
D
u  =  (
u
 (2)
-
 u
 (1)
) /
 n
and
n
,
 u
 (1)
, and
u
 (2)
 are the arguments to the most recent
glMapGrid1
 command.
type
 is
GL_POINTS
 if
mode
 is
GL_POINT
, or
GL_LINES
 if
mode
 is
GL_LINE
. The one absolute numeric requirement is that if
i
 =
n
, then the value computed from
i
·
D
u
 +
u
 (1)
 is exactly
u
 (2)
.
In the two-dimensional case,
glEvalMesh2
, let
D
u
 = (
u
 (2)
-
u
 (1)
)/
n
D
v
 = (
v
 (2)
-
v
 (1)
)/m,
where
n
,
u
 (1)
,
u
 (2)
,
m
,
v
 (1)
, and
v
 (2)
 are the arguments to the most recent
 glMapGrid2
command. Then, if
mode
is
 GL_FILL,
the
glEvalMesh2
 command is equivalent to:
for (
j
 =
j1
;
j
 <
j2
;
j
 += 1) {
glBegin
 (
GL_QUAD_STRIP
);
    for (
i
 =
i1
;
i
 <=
i2
;
i
 += 1)
{
glEvalCoord2
(
i
·
D
u
 +
u
 (1,)
j
·
D
v
 +
v
 (1)
);
glEvalCoord2
(
i
·
D
u
 +
u
 (1,)
 (
j
+1)
·
D
v
 +
v
 (1)
);
    }
glEnd
( );
}
If
mode
 is
GL_LINE
, then a call to
 glEvalMesh2
 is equivalent to:
for (
j
 =
j1
;
j
 <=
j2
;
j
 += 1) {
glBegin
 (
GL_LINE_STRIP
);
    for (
i
 =
i1
;
i
 <=
i2
;
i
 += 1)
glEvalCoord2
(
i
·
D
u
 +
u
 (1)
,
 j
·
D
v
 +
v
 (1);)
glEnd
( );
}
    for (
i
 =
i1
;
i
 <=
i2
;
i
 += 1) {
glBegin
 (
GL_LINE_STRIP
);
    for (
j
 =
j1
;
j
 <=
j1
;
j
 += 1)
glEvalCoord2
(
i
·
D
u
 +
u
 (1)
,
 j
·
D
v
 +
v
 (1)
);
glEnd
( );
}
And finally, if
mode
is
 GL_POINT,
then a call to
glEvalMesh2
 is equivalent to:
glBegin
 (
GL_POINTS
);
for (
j
 =
j1
;
j
 <=
j2
;
j
 += 1) {
    for (
i
 =
i1
;
i
 <=
i2
;
i
 += 1) {
glEvalCoord2
(
i
·
D
u
  +
u
 (1)
,
j
·
D
v
 +
v
 (1)
);
    }
}
glEnd
( );
In all three cases, the only absolute numeric requirements are that if
i
 =
n
, then the value computed from
i
·
D
u
 +
u
 (1)
 is exactly
u
 (2)
, and if
j
 =
m
, then the value computed from
j
·
D
v
 +
v
 (1)
 is exactly
v
 (2)
.
The following functions retrieve information relating to the
glEvalMesh
 function:
glGet
 with argument
GL_MAP1_GRID_DOMAIN
glGet
 with argument
GL_MAP2_GRID_DOMAIN
glGet
 with argument
GL_MAP1_GRID_SEGMENTS
glGet
 with argument
GL_MAP2_GRID_SEGMENTS
Errors
GL_INVALID_ENUM
 is generated if
mode
 is not an accepted value.
GL_INVALID_OPERATION
 is generated if
glEvalMesh
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glBegin
,
glEvalCoord
,
glEvalPoint
,
glMap1
,
glMap2
,
glMapGrid


glEvalPoint
glEvalPoint1, glEvalPoint2
The
glEvalPoint1
 and
glEvalPoint2
 functions generate and evaluate a single point in a mesh.
void glEvalPoint1
(
GLint
i
);
void glEvalPoint2
(
GLint
i
,
GLint
j
);
Parameters
i
Specifies the integer value for grid domain variable
i
.
j
Specifies the integer value for grid domain variable
j
 (
glEvalPoint2
 only).
Remarks
The
glMapGrid
 and
glEvalMesh
 functions are used in tandem to efficiently generate and evaluate a series of evenly spaced map domain values. The
glEvalPoint
 function can be used to evaluate a single grid point in the same gridspace that is traversed by
glEvalMesh
. Calling
glEvalPoint1
 is equivalent to calling
glEvalCoord1
(i
·
D
u
 +
u
 (1)
);
where
D
u
 = (
u
 (2)
-
u
 (1)
) /
n
and
n
,
u
 (1)
, and
u
 (2)
 are the arguments to the most recent
glMapGrid1
 command. The one absolute numeric requirement is that if
i
 =
 n
, then the value computed from i
·
D
u
 +
u
 (1)
 is exactly
 u
 (2)
.
In the two-dimensional case,
glEvalPoint2
, let.
D
u
 = (
u
 (2)
-
u
 (1)
)/
n
D
v
 = (
v
 (2)
-
v
 (1)
)/
m
where
n
,
u
 (1)
,
u
 (2)
,
m
,
v
 (1)
, and
v
 (2)
 are the arguments to the most recent
glMapGrid2
 command. Then the
glEvalPoint2
 command is equivalent to calling
glEvalCoord2
(i
·
D
u
 +
u
 (1)
,
 j
·
D
v
 +
v
 (1)
);
The only absolute numeric requirements are that if
i
 =
n
, then the value computed from
i
·
D
u
 +
u
 (1)
 is exactly
u
 (2)
, and if
j
 =
m
, then the value computed from
 j
·
D
v
 +
v
1 is exactly
v
 (2)
.
The following functions retrieve information relating to the
glEvalPoint1
 and
glEvalPoint2
 functions:
glGet
 with argument
GL_MAP1_GRID_DOMAIN
glGet
 with argument
GL_MAP2_GRID_DOMAIN
glGet
 with argument
GL_MAP1_GRID_SEGMENTS
glGet
 with argument
GL_MAP2_GRID_SEGMENTS
See Also
glEvalCoord
,
glEvalMesh
,
glMap1
,
glMap2
,
glMapGrid


glFeedbackBuffer
The
glFeedbackBuffer
 function controls feedback mode.
void
glFeedbackBuffer
(
GLsizei
size
,
GLenum
type
,
GLfloat
*buffer
);
Parameters
size
Specifies the maximum number of values that can be written into
buffer
.
type
Specifies a symbolic constant that describes the information that will be returned for each vertex.
GL_2D
,
GL_3D
,
GL_3D_COLOR
,
GL_3D_COLOR_TEXTURE
, and
GL_4D_COLOR_TEXTURE
 are accepted.
buffer
Returns the feedback data.
Remarks
The
glFeedbackBuffer
 function controls feedback. Feedback, like selection, is a GL mode. The mode is selected by calling
glRenderMode
 with
GL_FEEDBACK
. When the GL is in feedback mode, no pixels are produced by rasterization. Instead, information about primitives that would have been rasterized is fed back to the application using the GL.
The
glFeedbackBuffer
 function has three arguments:
buffer
is a pointer to an array of floating-point values
into which feedback information is placed.
size
 indicates the size of the array.
type
 is a symbolic constant describing the information that is fed back for each vertex. The
glFeedbackBuffer
 function must be issued before feedback mode is enabled (by calling
glRenderMode
 with argument
GL_FEEDBACK
). Setting
GL_FEEDBACK
 without establishing the feedback buffer, or calling
glFeedbackBuffer
 while the GL is in feedback mode, is an error.
The GL is taken out of feedback mode by calling
glRenderMode
 with a parameter value other than
GL_FEEDBACK
. When this is done while the GL is in feedback mode,
glRenderMode
 returns the number of entries placed in the feedback array. The returned value never exceeds
size
. If the feedback data required more room than was available in
buffer
,
glRenderMode
 returns a negative value.
While in feedback mode, each primitive that would be rasterized generates a block of values that get copied into the feedback array. If doing so would cause the number of entries to exceed the maximum, the block is partially written so as to fill the array (if there is any room left at all), and an overflow flag is set. Each block begins with a code indicating the primitive type, followed by values that describe the primitives vertexes and associated data. Entries are also written for bitmaps and pixel rectangles. Feedback occurs after polygon culling and
glPolyMode
 interpretation of polygons has taken place, so polygons that are culled are not returned in the feedback buffer. It can also occur after polygons with more than three edges are broken up into triangles, if the GL implementation renders polygons by performing this decomposition.
The
glPassThrough
 command can be used to insert a marker into the feedback buffer.
Following is the grammar for the blocks of values written into the feedback buffer. Each primitive is indicated with a unique identifying value followed by some number of vertexes. Polygon entries include an integer value indicating how many vertexes follow. A vertex is fed back as some number of floating-point values, as determined by
type
. Colors are fed back as four values in RGBA mode and one value in color index mode.
feedbackList
¬
 feedbackItem feedbackList | feedbackItem
feedbackItem
¬
 point | lineSegment | polygon | bitmap | pixelRectangle | passThru
point
¬
GL_POINT_TOKEN
 vertex
lineSegment
¬
GL_LINE_TOKEN
 vertex vertex |
GL_LINE_RESET_TOKEN
 vertex vertex
polygon
¬
GL_POLYGON_TOKEN
 n polySpec
polySpec
¬
 polySpec vertex | vertex vertex vertex
bitmap
¬
GL_BITMAP_TOKEN
 vertex
pixelRectangle
¬
GL_DRAW_PIXEL_TOKEN
 vertex |
GL_COPY_PIXEL_TOKEN
 vertex
passThru
¬
GL_PASS_THROUGH_TOKEN
 value
vertex
¬
 2d | 3d | 3dColor | 3dColorTexture | 4dColorTexture
2d
¬
 value value
3d
¬
 value value value
3dColor
¬
 value value value color
3dColorTexture
¬
 value value value color tex
4dColorTexture
¬
 value value value value color tex
color
¬
 rgba | index
rgba
¬
 value value value value
index
¬
 value
tex
¬
 value value value value
The
 value
 parameter is a floating-point number, and
 n
is a floating-point integer giving the number of vertexes in the polygon.
GL_POINT_TOKEN
,
GL_LINE_TOKEN
,
GL_LINE_RESET_TOKEN
,
GL_POLYGON_TOKEN
,
GL_BITMAP_TOKEN
,
GL_DRAW_PIXEL_TOKEN
,
GL_COPY_PIXEL_TOKEN
 and
GL_PASS_THROUGH_TOKEN
 are symbolic floating-point constants.
GL_LINE_RESET_TOKEN
 is returned whenever the line stipple pattern is reset. The data returned as a vertex depends on the feedback
type
.
The following table gives the correspondence between
type
 and the number of values per vertex.
k
 is 1 in color index mode and 4 in RGBA mode.
Type
Coordinates
Color
Texture
Total Number of Values
GL_2D
x
,
y
2
GL_3D
x
,
y
,
z
3
GL_3D_COLOR
x
,
y
,
z
k
3 + k
GL_3D_COLOR_TEXTURE
x
,
y
,
z
,
k
4
7 + k
GL_4D_COLOR_TEXTURE
x
,
y
,
z
,
w
k
4
8 + k
Feedback vertex coordinates are in window coordinates, except
w
, which is in clip coordinates. Feedback colors are lighted, if lighting is enabled. Feedback texture coordinates are generated, if texture coordinate generation is enabled. They are always transformed by the texture matrix.
The
glFeedbackBuffer
 function, when used in a display list, is not compiled into the display list but rather is executed immediately.
The following function retrieves information related to the
glFeedbackBuffer
function:
glGet
 with argument
GL_RENDER_MODE
Errors
GL_INVALID_ENUM
 is generated if
type
 is not an accepted value.
GL_INVALID_VALUE
 is generated if
size
 is negative.
GL_INVALID_OPERATION
 is generated if
glFeedbackBuffer
 is called while the render mode is
GL_FEEDBACK
, or if
glRenderMode
 is called with argument
GL_FEEDBACK
 before
glFeedbackBuffer
 is called at least once.
GL_INVALID_OPERATION
 is generated if
glFeedbackBuffer
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glBegin
,
glLineStipple
,
glPassThrough
,
glPolygonMode
,
glRenderMode
,
glSelectBuffer


glFinish
The
glFinish
 function blocks until all GL execution is complete.
void glFinish
(
void
);
Remarks
The
glFinish
 function does not return until the effects of all previously called GL commands are complete. Such effects include all changes to GL state, all changes to connection state, and all changes to the frame buffer contents.
The
glFinish
 function requires a round trip to the server.
Errors
GL_INVALID_OPERATION
 is generated if
glFinish
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glFlush


glFlush
The
glFlush
 function forces execution of GL commands in finite time.
void
glFlush
(
void
);
Remarks
Different GL implementations buffer commands in several different locations, including network buffers and the graphics accelerator itself. The
glFlush
 function empties all of these buffers, causing all issued commands to be executed as quickly as they are accepted by the actual rendering engine. Though this execution may not be completed in any particular time period, it does complete in finite time.
Because any GL program might be executed over a network, or on an accelerator that buffers commands, all programs should call
glFlush
 whenever they count on having all of their previously issued commands completed. For example, call
glFlush
 before waiting for user input that depends on the generated image.
The
glFlush
 function can return at any time. It does not wait until the execution of all previously issued OpenGL commands is complete.
Errors
GL_INVALID_OPERATION
 is generated if
glFlush
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glFinish


glFog
glFogf, glFogi, glFogfv, glFogiv
These functions specify fog parameters.
void glFogf
(
GLenum
pname
,
GLfloat
param
);
void glFogi(
GLenum
pname
,
GLint
param
);
Parameters
pname
Specifies a single-valued fog parameter.
GL_FOG_MODE, GL_FOG_DENSITY, GL_FOG_START, GL_FOG_END,
 and
GL_FOG_INDEX
 are accepted.
param
Specifies the value that
pname
 will be set to.
void glFogfv
(
GLenum
pname
,
const GLfloat
*params
);
void glFogiv
(
GLenum
pname
,
const GLint
*params
);
Parameters
pname
Specifies a fog parameter.
GL_FOG_MODE, GL_FOG_DENSITY, GL_FOG_START, GL_FOG_END
,
GL_FOG_INDEX
, and
GL_FOG_COLOR
 are accepted.
params
Specifies the value or values to be assigned to
pname
.
GL_FOG_COLOR
 requires an array of four values. All other parameters accept an array containing only a single value.
Remarks
Fog is enabled and disabled with
glEnable
 and
glDisable
 using the argument
GL_FOG
. While enabled, fog affects rasterized geometry, bitmaps, and pixel blocks, but not buffer clear operations.
The
 glFog
 function assigns the value or values in
params
 to the fog parameter specified by
pname
. The accepted values for
pname
 are as follows:
GL_FOG_MODE
The
params
 parameter is a single integer or floating-point value that specifies the equation to be used to compute the fog blend factor,
f
. Three symbolic constants are accepted:
GL_LINEAR, GL_EXP
, and
GL_EXP2
. The equations corresponding to these symbolic constants are defined below. The default fog mode is
GL_EXP
.
GL_FOG_DENSITY
The
params
 parameter is a single integer or floating-point value that specifies
density
, the fog density used in both exponential fog equations. Only nonnegative densities are accepted. The default fog density is 1.0.
GL_FOG_START
The
params
 parameter is a single integer or floating-point value that specifies
start
, the near distance used in the linear fog equation. The default near distance is 0.0.
GL_FOG_END
The
params
 parameter is a single integer or floating-point value that specifies
end
, the far distance used in the linear fog equation. The default far distance is 1.0.
GL_FOG_INDEX
The
params
 parameter is a single integer or floating-point value that specifies
i
 (f)
, the fog color index. The default fog index is 0.0.
GL_FOG_COLOR
The
params
 parameter contains four integer or floating-point values that specify
C
 (f)
, the fog color. Integer values are mapped linearly such that the most positive representable value maps to 1.0, and the most negative representable value maps to
-
1.0. Floating-point values are mapped directly. After conversion, all color components are clamped to the range [0,1]. The default fog color is (0,0,0,0).
Fog blends a fog color with each rasterized pixel fragments posttexturing color using a blending factor
f
. Factor
f
 is computed in one of three ways, depending on the fog mode. Let
z
 be the distance in eye coordinates from the origin to the fragment being fogged. The equation for
GL_LINEAR
 fog is
The equation for
GL_EXP
 fog is
The equation for
GL_EXP2
 fog is
Regardless of the fog mode,
f
 is clamped to the range [0,1] after it is computed. Then, if the GL is in RGBA color mode, the fragments color
C
 (r)
 is replaced by
In color index mode, the fragments color index
i
 (r)
 is replaced by
The following functions retrieve information related to the
glFog
 functions:
glGet
 with argument
GL_FOG_COLOR
glGet
with argument
GL_FOG_INDEX
glGet
with argument
GL_FOG_DENSITY
glGet
with argument
GL_FOG_START
glGet
with argument
GL_FOG_END
glGet
with argument
GL_FOG_MODE
glIsEnabled
 with argument
GL_FOG
Errors
GL_INVALID_ENUM
 is generated if pname is not an accepted value.
GL_INVALID_OPERATION
 is generated if
glFog
 is called between a call to glBegin and the corresponding call to glEnd.


glFrontFace
The
glFrontFace
 function defines front- and back-facing polygons.
void glFrontFace
(
GLenum
mode
);
Parameters
mode
Specifies the orientation of front-facing polygons.
GL_CW
 and
GL_CCW
 are accepted. The default value is
GL_CCW
.
Remarks
In a scene composed entirely of opaque closed surfaces, back-facing polygons are never visible. Eliminating these invisible polygons has the obvious benefit of speeding up the rendering of the image. Elimination of back-facing polygons is enabled and disabled with
glEnable
 and
glDisable
 using argument
GL_CULL_FACE
.
The projection of a polygon to window coordinates is said to have clockwise winding if an imaginary object following the path from its first vertex, its second vertex, and so on, to its last vertex, and finally back to its first vertex, moves in a clockwise direction about the interior of the polygon. The polygons winding is said to be counterclockwise if the imaginary object following the same path moves in a counterclockwise direction about the interior of the polygon. The
glFrontFace
 function specifies whether polygons with clockwise winding in window coordinates, or counterclockwise winding in window coordinates, are taken to be front-facing. Passing
GL_CCW
 to
mode
 selects counterclockwise polygons as front-facing;
GL_CW
 selects clockwise polygons as front-facing. By default, counterclockwise polygons are taken to be front-facing.
The following function retrieves information about the
glFrontface
 function:
glGet
 with argument GL_FRONT_FACE
Errors
GL_INVALID_ENUM
 is generated if
mode
 is not an accepted value.
GL_INVALID_OPERATION
 is generated if
glFrontFace
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glCullFace
,
glLightModel


glFrustum
The
glFrustum
 function multiplies the current matrix by a perspective matrix.
void glFrustum
(
GLdouble
left
,
GLdouble
right
,
GLdouble
bottom
,
GLdouble
top
,
GLdouble
near
,
GLdouble
far
);
Parameters
left, right
Specify the coordinates for the left and right vertical clipping planes.
bottom, top
Specify the coordinates for the bottom and top horizontal clipping planes.
near, far
Specify the distances to the near and far depth clipping planes. Both distances must be positive.
Remarks
The
glFrustum
 function describes a perspective matrix that produces a perspective projection. (
left
,
bottom
,
near
) and (
right
,
top
,
near
) specify the points on the near clipping plane that are mapped to the lower left and upper right corners of the window, respectively, assuming that the eye is located at (0, 0, 0).
far
 specifies the location of the far clipping plane. Both
near
 and
far
 must be positive. The corresponding matrix is
The current matrix is multiplied by this matrix with the result replacing the current matrix. That is, if M is the current matrix and F is the frustum perspective matrix, then M is replaced with M
·
 F.
Use
glPushMatrix
 and
glPopMatrix
 to save and restore the current matrix stack.
Depth buffer precision is affected by the values specified for
near
 and
far
. The greater the ratio of
far
 to
near
 is, the less effective the depth buffer will be at distinguishing between surfaces that are near each other. If
roughly log
 (2)
 r
 bits of depth buffer precision are lost. Because
r
 approaches infinity as
near
 approaches zero,
near
 must never be set to zero.
The following functions retrieve information about the
glFrustum
 function:
glGet
 with argument
GL_MATRIX_MODE
glGet
 with argument
GL_MODELVIEW_MATRIX
glGet
 with argument
GL_PROJECTION_MATRIX
glGet
 with argument
GL_TEXTURE_MATRIX
Errors
GL_INVALID_VALUE
 is generated if
near
 or
far
 is not positive.
GL_INVALID_OPERATION
 is generated if
glFrustum
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glOrtho
,
glMatrixMode
,
glMultMatrix
,
glPushMatrix
,
glViewport


glGenLists
The
glGenLists
 function generates a contiguous set of empty display lists.
GLuint glGenLists
(
GLsizei
range
);
Parameters
range
Specifies the number of contiguous empty display lists to be generated.
Remarks
The
glGenLists
 function has one argument,
range
. It returns an integer
n
 such that
range
 contiguous empty display lists, named
n
,
n
+1, . . .,
n
+
range
-
 1, are created. If
range
 is zero, if there is no group of
range
 contiguous names available, or if any error is generated, no display lists are generated, and zero is returned.
The following function retrieves information related to the
glGenLists
 function:
glIsList
Errors
GL_INVALID_VALUE
 is generated if
range
 is negative.
GL_INVALID_OPERATION
 is generated if
glGenLists
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glCallList
,
glCallLists
,
glDeleteLists
,
glNewList


glGet
glGetBooleanv, glGetDoublev, glGetFloatv, glGetIntegerv
These functions return the value or values of a selected parameter.
void glGetBooleanv
(
GLenum
pname
,
GLboolean
*params
);
void
glGetDoublev
(
GLenum
pname
,
GLdouble
*params
);
void
glGetFloatv
(
GLenum
pname
,
GLfloat
*params
);
void glGetIntegerv
(
GLenum
pname
,
GLint
*params
);
Parameters
pname
Specifies the parameter value to be returned. The symbolic constants in the list below are accepted.
params
Returns the value or values of the specified parameter.
Remarks
These four commands return values for simple state variables in GL.
pname
 is a symbolic constant indicating the state variable to be returned, and
params
 is a pointer to an array of the indicated type in which to place the returned data.
Type conversion is performed if
params
 has a different type than the state variable value being requested. If
glGetBooleanv
 is called, a floating-point or integer value is converted to
GL_FALSE
 if and only if it is zero. Otherwise, it is converted to
GL_TRUE
. If
glGetIntegerv
 is called, Boolean values are returned as
GL_TRUE
 or
GL_FALSE
, and most floating-point values are rounded to the nearest integer value. Floating-point colors and normals, however, are returned with a linear mapping that maps 1.0 to the most positive representable integer value, and
-
1.0 to the most negative representable integer value. If
glGetFloatv
 or
glGetDoublev
 is called, Boolean values are returned as
GL_TRUE
 or
GL_FALSE
, and integer values are converted to floating-point values.
The following symbolic constants are accepted by
pname
:
GL_ACCUM_ALPHA_BITS
The
 params
 parameter returns one value, the number of alpha bitplanes in the accumulation buffer.
GL_ACCUM_BLUE_BITS
The
 params
 parameter returns one value, the number of blue bitplanes in the accumulation buffer.
GL_ACCUM_CLEAR_VALUE
The
 params
 parameter returns four values: the red, green, blue, and alpha values used to clear the accumulation buffer. Integer values, if requested, are linearly mapped from the internal floating-point representation such that 1.0 returns the most positive representable integer value, and
-
1.0 returns the most negative representable integer value. See
glClearAccum
.
GL_ACCUM_GREEN_BITS
The
 params
 parameter returns one value, the number of green bitplanes in the accumulation buffer.
GL_ACCUM_RED_BITS
The
 params
 parameter returns one value, the number of red bitplanes in the accumulation buffer.
GL_ALPHA_BIAS
The
 params
 parameter returns one value, the alpha bias factor used during pixel transfers. See
glPixelTransfer
.
GL_ALPHA_BITS
The
 params
 parameter returns one value, the number of alpha bitplanes in each color buffer.
GL_ALPHA_SCALE
The
 params
 parameter returns one value, the alpha scale factor used during pixel transfers. See
glPixelTransfer
.
GL_ALPHA_TEST
The
 params
 parameter returns a single Boolean value indicating whether alpha testing of fragments is enabled. See
glAlphaFunc
.
GL_ALPHA_TEST_FUNC
The
 params
 parameter returns one value, the symbolic name of the alpha test function. See
glAlphaFunc
.
GL_ALPHA_TEST_REF
The
 params
 parameter returns one value, the reference value for the alpha test. See
glAlphaFunc
. An integer value, if requested, is linearly mapped from the internal floating-point representation such that 1.0 returns the most positive representable integer value, and
-
1.0 returns the most negative representable integer value.
GL_ATTRIB_STACK_DEPTH
The
 params
 parameter returns one value, the depth of the attribute stack. If the stack is empty, zero is returned. See
glPushAttrib
.
GL_AUTO_NORMAL
The
 params
 parameter returns a single Boolean value indicating whether 2-D map evaluation automatically generates surface normals. See
glMap2
.
GL_AUX_BUFFERS
The
 params
 parameter returns one value, the number of auxiliary color buffers.
GL_BLEND
The
 params
 parameter returns a single Boolean value indicating whether blending is enabled. See
glBlendFunc
.
GL_BLEND_DST
The
 params
 parameter returns one value, the symbolic constant identifying the destination blend function. See
glBlendFunc
.
GL_BLEND_SRC
The
 params
 parameter returns one value, the symbolic constant identifying the source blend function. See
glBlendFunc
.
GL_BLUE_BIAS
The
 params
 parameter returns one value, the blue bias factor used during pixel transfers. See
glPixelTransfer
.
GL_BLUE_BITS
The
 params
 parameter returns one value, the number of blue bitplanes in each color buffer.
GL_BLUE_SCALE
The
 params
 parameter returns one value, the blue scale factor used during pixel transfers. See
glPixelTransfer
.
GL_CLIP_PLANE
i
The
 params
 parameter returns a single Boolean value indicating whether the specified clipping plane is enabled. See
glClipPlane
.
GL_COLOR_CLEAR_VALUE
The
 params
 parameter returns four values: the red, green, blue, and alpha values used to clear the color buffers.
Integer values, if requested, are linearly mapped from the internal floating-point representation such that 1.0 returns the most positive representable integer value, and
-
1.0 returns the most negative representable integer value. See
glClearColor
.
GL_COLOR_MATERIAL
The
 params
 parameter returns a single Boolean value indicating whether one or more material parameters are tracking the current color. See
glColorMaterial
.
GL_COLOR_MATERIAL_FACE
The
 params
 parameter returns one value, a symbolic constant indicating which materials have a parameter that is tracking the current color. See
glColorMaterial
.
GL_COLOR_MATERIAL_PARAMETER
The
 params
 parameter returns one value, a symbolic constant indicating which material parameters are tracking the current color. See
glColorMaterial
.
GL_COLOR_WRITEMASK
The
 params
 parameter returns four Boolean values: the red, green, blue, and alpha write enables for the color buffers.
See
glColorMask
.
GL_CULL_FACE
The
 params
 parameter returns a single Boolean value indicating whether polygon culling is enabled. See
glCullFace
.
GL_CULL_FACE_MODE
The
 params
 parameter returns one value, a symbolic constant indicating which polygon faces are to be culled. See
glCullFace
.
GL_CURRENT_COLOR
The
 params
 parameter returns four values: the red, green, blue, and alpha values of the current color.
Integer values, if requested, are linearly mapped from the internal floating-point representation such that 1.0 returns the most positive representable integer value, and
-
1.0 returns the most negative representable integer value. See
glColor
.
GL_CURRENT_INDEX
The
 params
 parameter returns one value, the current color index. See
glIndex
.
GL_CURRENT_NORMAL
The
 params
 parameter returns three values: the
x
,
y
,
and
z
values of the current normal. Integer values, if requested, are linearly mapped from the internal floating-point representation such that 1.0 returns the most positive representable integer value, and
-
1.0 returns the most negative representable integer value. See
glNormal
.
GL_CURRENT_RASTER_COLOR
The
 params
 parameter returns four values: the red, green, blue, and alpha values of the current raster position.
Integer values, if requested, are linearly mapped from the internal floating-point representation such that 1.0 returns the most positive representable integer value, and
-
1.0 returns the most negative representable integer value. See
glRasterPos
.
GL_CURRENT_RASTER_DISTANCE
The
 params
 parameter returns one value, the distance from the eye to the current raster position. See
glRasterPos
.
GL_CURRENT_RASTER_INDEX
The
 params
 parameter returns one value, the color index of the current raster position. See
glRasterPos
.
GL_CURRENT_RASTER_POSITION
The
 params
 parameter returns four values: the
x
,
y
,
z
,
and
w
components of the current raster position.
x
,
y
, and
z
 are in window coordinates, and
w
 is in clip coordinates. See
glRasterPos
.
GL_CURRENT_RASTER_TEXTURE_COORDS
The
 params
 parameter returns four values: the
s
,
t
,
r
,
 and
q
current raster texture coordinates. See
glRasterPos
 and
glTexCoord
.
GL_CURRENT_RASTER_POSITION_VALID
The
 params
 parameter returns a single Boolean value indicating whether the current raster position is valid. See
glRasterPos
.
GL_CURRENT_TEXTURE_COORDS
The
 params
 parameter returns four values: the
s
,
t
,
r
,
and
q
current texture coordinates. See
glTexCoord
.
GL_DEPTH_BIAS
The
 params
 parameter returns one value, the depth bias factor used during pixel transfers. See
glPixelTransfer
.
GL_DEPTH_BITS
The
 params
 parameter returns one value, the number of bitplanes in the depth buffer.
GL_DEPTH_CLEAR_VALUE
The
 params
 parameter returns one value, the value that is used to clear the depth buffer. Integer values, if requested, are linearly mapped from the internal floating-point representation such that 1.0 returns the most positive representable integer value, and
-
 1.0 returns the most negative representable integer value. See
glClearDepth
.
GL_DEPTH_FUNC
The
 params
 parameter returns one value, the symbolic constant that indicates the depth comparison function. See
glDepthFunc
.
GL_DEPTH_RANGE
The
 params
 parameter returns two values: the near and far mapping limits for the depth buffer. Integer values, if requested, are linearly mapped from the internal floating-point representation such that 1.0 returns the most positive representable integer value, and
-
1.0 returns the most negative representable integer value. See
glDepthRange
.
GL_DEPTH_SCALE
The
 params
 parameter returns one value, the depth scale factor used during pixel transfers. See
glPixelTransfer
.
GL_DEPTH_TEST
The
 params
 parameter returns a single Boolean value indicating whether depth testing of fragments is enabled. See
glDepthFunc
 and
glDepthRange
.
GL_DEPTH_WRITEMASK
The
 params
 parameter returns a single Boolean value indicating if the depth buffer is enabled for writing. See
glDepthMask
.
GL_DITHER
The
 params
 parameter returns a single Boolean value indicating whether dithering of fragment colors and indices is enabled.
GL_DOUBLEBUFFER
The
 params
 parameter returns a single Boolean value indicating whether double buffering is supported.
GL_DRAW_BUFFER
The
 params
 parameter returns one value, a symbolic constant indicating which buffers are being drawn to. See
glDrawBuffer
.
GL_EDGE_FLAG
The
 params
 parameter returns a single Boolean value indication whether the current edge flag is true or false. See
glEdgeFlag
.
GL_FOG
The
 params
 parameter returns a single Boolean value indicating whether fogging is enabled. See
glFog
.
GL_FOG_COLOR
The
 params
 parameter returns four values: the red, green, blue, and alpha components of the fog color.
Integer values, if requested, are linearly mapped from the internal floating-point representation such that 1.0 returns the most positive representable integer value, and
-
1.0 returns the most negative representable integer value. See
glFog
.
GL_FOG_DENSITY
The
 params
 parameter returns one value, the fog density parameter. See
glFog
.
GL_FOG_END
The
 params
 parameter returns one value, the end factor for the linear fog equation. See
glFog
.
GL_FOG_HINT
The
 params
parameter returns one value, a symbolic constant indicating the mode of the fog hint. See
glHint
.
GL_FOG_INDEX
The
 params
parameter returns one value, the fog color index. See
glFog
.
GL_FOG_MODE
The
 params
parameter returns one value, a symbolic constant indicating which fog equation is selected. See
glFog
.
GL_FOG_START
The
 params
parameter returns one value, the start factor for the linear fog equation. See
glFog
.
GL_FRONT_FACE
The
 params
parameter returns one value, a symbolic constant indicating whether clockwise or counterclockwise polygon winding is treated as front-facing. See
glFrontFace
.
GL_GREEN_BIAS
The
 params
parameter returns one value, the green bias factor used during pixel transfers.
GL_GREEN_BITS
The
 params
parameter returns one value, the number of green bitplanes in each color buffer.
GL_GREEN_SCALE
The
 params
parameter returns one value, the green scale factor used during pixel transfers. See
glPixelTransfer
.
GL_INDEX_BITS
The
 params
parameter returns one value, the number of bitplanes in each color index buffer.
GL_INDEX_CLEAR_VALUE
The
 params
parameter returns one value, the color index used to clear the color index buffers. See
glClearIndex
.
GL_INDEX_MODE
The
 params
parameter returns a single Boolean value indicating whether the GL is in color index mode (true) or RGBA mode (false).
GL_INDEX_OFFSET
The
 params
parameter returns one value, the offset added to color and stencil indices during pixel transfers. See
glPixelTransfer
.
GL_INDEX_SHIFT
The
 params
parameter returns one value, the amount that color and stencil indices are shifted during pixel transfers. See
glPixelTransfer
.
GL_INDEX_WRITEMASK
The
 params
parameter returns one value, a mask indicating which bitplanes of each color index buffer can be written. See
glIndexMask
.
GL_LIGHT
i
The
 params
parameter returns a single Boolean value indicating whether the specified light is enabled. See
glLight
 and
glLightModel
.
GL_LIGHTING
The
 params
parameter returns a single Boolean value indicating whether lighting is enabled. See
glLightModel
.
GL_LIGHT_MODEL_AMBIENT
The
 params
parameter returns four values: the red, green, blue, and alpha components of the ambient intensity of the entire scene. Integer values, if requested, are linearly mapped from the internal floating-point representation such that 1.0 returns the most positive representable integer value, and
-
1.0 returns the most negative representable integer value. See
glLightModel
.
GL_LIGHT_MODEL_LOCAL_VIEWER
The
 params
parameter returns a single Boolean value indicating whether specular reflection calculations treat the viewer as being local to the scene. See
glLightModel
.
GL_LIGHT_MODEL_TWO_SIDE
The
 params
parameter returns a single Boolean value indicating whether separate materials are used to compute lighting for front- and back-facing polygons. See
glLightModel
.
GL_LINE_SMOOTH
The
 params
parameter returns a single Boolean value indicating whether antialiasing of lines is enabled. See
glLineWidth
.
GL_LINE_SMOOTH_HINT
The
 params
parameter returns one value, a symbolic constant indicating the mode of the line antialiasing hint. See
glHint
.
GL_LINE_STIPPLE
The
 params
parameter returns a single Boolean value indicating whether stippling of lines is enabled. See
glLineStipple
.
GL_LINE_STIPPLE_PATTERN
The
 params
parameter returns one value, the 16-bit line stipple pattern. See
glLineStipple
.
GL_LINE_STIPPLE_REPEAT
The
 params
parameter returns one value, the line stipple repeat factor. See
glLineStipple
.
GL_LINE_WIDTH
The
 params
parameter returns one value, the line width as specified with
glLineWidth
.
GL_LINE_WIDTH_GRANULARITY
The
 params
parameter returns one value, the width difference between adjacent supported widths for antialiased lines. See
glLineWidth
.
GL_LINE_WIDTH_RANGE
The
 params
parameter returns two values: the smallest and largest supported widths for antialiased lines. See
glLineWidth
.
GL_LIST_BASE
The
 params
parameter returns one value, the base offset added to all names in arrays presented to
glCallLists
. See
glListBase
.
GL_LIST_INDEX
The
 params
parameter returns one value, the name of the display list currently under construction. Zero is returned if no display list is currently under construction. See
glNewList
.
GL_LIST_MODE
The
 params
parameter returns one value, a symbolic constant indicating the construction mode of the display list currently being constructed. See
glNewList
.
GL_LOGIC_OP
The
 params
parameter returns a single Boolean value indicating whether fragment indexes are merged into the framebuffer using a logical operation. See
glLogicOp
.
GL_LOGIC_OP_MODE
The
 params
parameter returns one value, a symbolic constant indicating the selected logic operational mode. See
glLogicOp
.
GL_MAP1_COLOR_4
The
 params
parameter returns a single Boolean value indicating whether 1D evaluation generates colors. See
glMap1
.
GL_MAP1_GRID_DOMAIN
The
 params
parameter returns two values: the endpoints of the 1-D maps grid domain. See
glMapGrid
.
GL_MAP1_GRID_SEGMENTS
The
 params
parameter returns one value, the number of partitions in the 1-D maps grid domain. See
glMapGrid
.
GL_MAP1_INDEX
The
 params
parameter returns a single Boolean value indicating whether 1D evaluation generates color indices. See
glMap1
.
GL_MAP1_NORMAL
The
 params
parameter returns a single Boolean value indicating whether 1D evaluation generates normals. See
glMap1
.
GL_MAP1_TEXTURE_COORD_1
The
 params
parameter returns a single Boolean value indicating whether 1D evaluation generates 1D texture coordinates. See
glMap1
.
GL_MAP1_TEXTURE_COORD_2
The
 params
parameter returns a single Boolean value indicating whether 1D evaluation generates 2D texture coordinates. See
glMap1
.
GL_MAP1_TEXTURE_COORD_3
The
 params
parameter returns a single Boolean value indicating whether 1D evaluation generates 3D texture coordinates. See
glMap1
.
GL_MAP1_TEXTURE_COORD_4
The
 params
parameter returns a single Boolean value indicating whether 1D evaluation generates 4D texture coordinates. See
glMap1
.
GL_MAP1_VERTEX_3
The
 params
parameter returns a single Boolean value indicating whether 1D evaluation generates 3D vertex coordinates. See
glMap1
.
GL_MAP1_VERTEX_4
The
 params
parameter returns a single Boolean value indicating whether 1D evaluation generates 4D vertex coordinates. See
glMap1
.
GL_MAP2_COLOR_4
The
 params
parameter returns a single Boolean value indicating whether 2D evaluation generates colors. See
glMap2
.
GL_MAP2_GRID_DOMAIN
The
 params
parameter returns four values: the endpoints of the 2-D maps
i
 and
j
 grid domains. See
glMapGrid
.
GL_MAP2_GRID_SEGMENTS
The
 params
parameter returns two values: the number of partitions in the 2-D maps
i
and
 j
 grid domains.
See
glMapGrid
.
GL_MAP2_INDEX
The
 params
parameter returns a single Boolean value indicating whether 2D evaluation generates color indices. See
glMap2
.
GL_MAP2_NORMAL
The
 params
parameter returns a single Boolean value indicating whether 2D evaluation generates normals. See
glMap2
.
GL_MAP2_TEXTURE_COORD_1
The
 params
parameter returns a single Boolean value indicating whether 2D evaluation generates 1D texture coordinates. See
glMap2
.
GL_MAP2_TEXTURE_COORD_2
The
 params
parameter returns a single Boolean value indicating whether 2D evaluation generates 2D texture coordinates. See
glMap2
.
GL_MAP2_TEXTURE_COORD_3
The
 params
parameter returns a single Boolean value indicating whether 2D evaluation generates 3D texture coordinates. See
glMap2
.
GL_MAP2_TEXTURE_COORD_4
The
 params
parameter returns a single Boolean value indicating whether 2D evaluation generates 4D texture coordinates. See
glMap2
.
GL_MAP2_VERTEX_3
The
 params
parameter returns a single Boolean value indicating whether 2D evaluation generates 3D vertex coordinates. See
glMap2
.
GL_MAP2_VERTEX_4
The
 params
parameter returns a single Boolean value indicating whether 2D evaluation generates 4D vertex coordinates. See
glMap2
.
GL_MAP_COLOR
The
 params
parameter returns a single Boolean value indicating if colors and color indices are to be replaced by table lookup during pixel transfers. See
glPixelTransfer
.
GL_MAP_STENCIL
The
 params
parameter returns a single Boolean value indicating if stencil indices are to be replaced by table lookup during pixel transfers. See
glPixelTransfer
.
GL_MATRIX_MODE
The
 params
parameter returns one value, a symbolic constant indicating which matrix stack is currently the target of all matrix operations. See
glMatrixMode
.
GL_MAX_ATTRIB_STACK_DEPTH
The
 params
parameter returns one value, the maximum supported depth of the attribute stack. See
glPushAttrib
.
GL_MAX_CLIP_PLANES
The
 params
parameter returns one value, the maximum number of application-defined clipping planes. See
glClipPlane
.
GL_MAX_EVAL_ORDER
The
 params
parameter returns one value, the maximum equation order supported by 1-D and 2-D evaluators. See
glMap1
 and
glMap2
.
GL_MAX_LIGHTS
The
 params
parameter returns one value, the maximum number of lights. See
glLight
.
GL_MAX_LIST_NESTING
The
 params
parameter returns one value, the maximum recursion depth allowed during display-list traversal. See
glCallList
.
GL_MAX_MODELVIEW_STACK_DEPTH
The
 params
parameter returns one value, the maximum supported depth of the modelview matrix stack. See
glPushMatrix
.
GL_MAX_NAME_STACK_DEPTH
The
 params
parameter returns one value, the maximum supported depth of the selection name stack. See
glPushName
.
GL_MAX_PIXEL_MAP_TABLE
The
 params
parameter returns one value, the maximum supported size of a
glPixelMap
 lookup table. See
glPixelMap
.
GL_MAX_PROJECTION_STACK_DEPTH
The
 params
parameter returns one value, the maximum supported depth of the projection matrix stack. See
glPushMatrix
.
GL_MAX_TEXTURE_SIZE
The
 params
parameter returns one value, the maximum width or height of any texture image (without borders). See
glTexImage1D
 and
glTexImage2D
GL_MAX_TEXTURE_STACK_DEPTH
The
 params
parameter returns one value, the maximum supported depth of the texture matrix stack. See
glPushMatrix
.
GL_MAX_VIEWPORT_DIMS
The
 params
parameter returns two values: the maximum supported width and height of the viewport. See
glViewport
.
GL_MODELVIEW_MATRIX
The
 params
parameter returns sixteen values: the modelview matrix on the top of the modelview matrix stack. See
glPushMatrix
.
GL_MODELVIEW_STACK_DEPTH
The
 params
parameter returns one value, the number of matrices on the modelview matrix stack. See
glPushMatrix
.
GL_NAME_STACK_DEPTH
The
 params
parameter returns one value, the number of names on the selection name stack. See
glPushMatrix
.
GL_NORMALIZE
The
 params
parameter returns a single Boolean value indicating whether normals are automatically scaled to unit length after they have been transformed to eye coordinates. See
glNormal
.
GL_PACK_ALIGNMENT
The
 params
parameter returns one value, the byte alignment used for writing pixel data to memory. See
glPixelStore
.
GL_PACK_LSB_FIRST
The
 params
parameter returns a single Boolean value indicating whether single-bit pixels being written to memory are written first to the least significant bit of each unsigned byte. See
glPixelStore
.
GL_PACK_ROW_LENGTH
The
 params
parameter returns one value, the row length used for writing pixel data to memory. See
glPixelStore
.
GL_PACK_SKIP_PIXELS
The
 params
parameter returns one value, the number of pixel locations skipped before the first pixel is written into memory. See
glPixelStore
.
GL_PACK_SKIP_ROWS
The
 params
parameter returns one value, the number of rows of pixel locations skipped before the first pixel is written into memory. See
glPixelStore
.
GL_PACK_SWAP_BYTES
The
 params
parameter returns a single Boolean value indicating whether the bytes of two-byte and four-byte pixel indices and components are swapped before being written to memory. See
glPixelStore
.
GL_PERSPECTIVE_CORRECTION_HINT
The
 params
parameter returns one value, a symbolic constant indicating the mode of the perspective correction hint. See
glHint
.
GL_PIXEL_MAP_A_TO_A_SIZE
The
 params
parameter returns one value, the size of the alpha-to-alpha pixel translation table. See
glPixelMap
.
GL_PIXEL_MAP_B_TO_B_SIZE
The
 params
parameter returns one value, the size of the blue-to-blue pixel translation table. See
glPixelMap
.
GL_PIXEL_MAP_G_TO_G_SIZE
The
 params
parameter returns one value, the size of the green-to-green pixel translation table. See
glPixelMap
.
GL_PIXEL_MAP_I_TO_A_SIZE
The
 params
parameter returns one value, the size of the index-to-alpha pixel translation table. See
glPixelMap
.
GL_PIXEL_MAP_I_TO_B_SIZE
The
 params
parameter returns one value, the size of the index-to-blue pixel translation table. See
glPixelMap
.
GL_PIXEL_MAP_I_TO_G_SIZE
The
 params
parameter returns one value, the size of the index-to-green pixel translation table. See
glPixelMap
.
GL_PIXEL_MAP_I_TO_I_SIZE
The
 params
parameter returns one value, the size of the index-to-index pixel translation table. See
glPixelMap
.
GL_PIXEL_MAP_I_TO_R_SIZE
The
 params
parameter returns one value, the size of the index-to-red pixel translation table. See
glPixelMap
.
GL_PIXEL_MAP_R_TO_R_SIZE
The
 params
parameter returns one value, the size of the red-to-red pixel translation table. See
glPixelMap
.
GL_PIXEL_MAP_S_TO_S_SIZE
The
 params
parameter returns one value, the size of the stencil-to-stencil pixel translation table. See
glPixelMap
.
GL_POINT_SIZE
The
 params
parameter returns one value, the point size as specified by
glPointSize
.
GL_POINT_SIZE_GRANULARITY
The
 params
parameter returns one value, the size difference between adjacent supported sizes for antialiased points. See
glPointSize
.
GL_POINT_SIZE_RANGE
The
 params
parameter returns two values: the smallest and largest supported sizes for antialiased points. See
glPointSize
.
GL_POINT_SMOOTH
The
 params
parameter returns a single Boolean value indicating whether antialiasing of points is enabled. See
glPointSize
.
GL_POINT_SMOOTH_HINT
The
 params
parameter returns one value, a symbolic constant indicating the mode of the point antialiasing hint. See
glHint
.
GL_POLYGON_MODE
The
 params
parameter returns two values: symbolic constants indicating whether front-facing and back-facing polygons are rasterized as points, lines, or filled polygons. See
glPolygonMode
.
GL_POLYGON_SMOOTH
The
 params
parameter returns a single Boolean value indicating whether antialiasing of polygons is enabled. See
glPolygonMode
.
GL_POLYGON_SMOOTH_HINT
The
 params
parameter returns one value, a symbolic constant indicating the mode of the polygon antialiasing hint. See
glHint
.
GL_POLYGON_STIPPLE
The
 params
parameter returns a single Boolean value indicating whether stippling of polygons is enabled. See
glPolygonStipple
.
GL_PROJECTION_MATRIX
The
 params
parameter returns sixteen values: the projection matrix on the top of the projection matrix stack. See
glPushMatrix
.
GL_PROJECTION_STACK_DEPTH
The
 params
parameter returns one value, the number of matrices on the projection matrix stack. See
glPushMatrix
.
GL_READ_BUFFER
The
 params
parameter returns one value, a symbolic constant indicating which color buffer is selected for reading. See
glReadPixels
 and
glAccum
.
GL_RED_BIAS
The
 params
parameter returns one value, the red bias factor used during pixel transfers.
GL_RED_BITS
The
 params
parameter returns one value, the number of red bitplanes in each color buffer.
GL_RED_SCALE
The
 params
parameter returns one value, the red scale factor used during pixel transfers. See
glPixelTransfer
.
GL_RENDER_MODE
The
 params
parameter returns one value, a symbolic constant indicating whether the GL is in render, select, or feedback mode. See
glRenderMode
.
GL_RGBA_MODE
The
 params
parameter returns a single Boolean value indicating whether the GL is in RGBA mode (true) or color index mode (false). See
glColor
.
GL_SCISSOR_BOX
The
 params
parameter returns four values: the
x
 and
y
 window coordinates of the scissor box, followed by its width and height. See
glScissor
.
GL_SCISSOR_TEST
The
 params
parameter returns a single Boolean value indicating whether scissoring is enabled. See
glScissor
.
GL_SHADE_MODEL
The
 params
parameter returns one value, a symbolic constant indicating whether the shading mode is flat or smooth. See
glShadeModel
.
GL_STENCIL_BITS
The
 params
parameter returns one value, the number of bitplanes in the stencil buffer.
GL_STENCIL_CLEAR_VALUE
The
 params
parameter returns one value, the index to which the stencil bitplanes are cleared. See
glClearStencil
.
GL_STENCIL_FAIL
The
 params
parameter returns one value, a symbolic constant indicating what action is taken when the stencil test fails. See
glStencilOp
.
GL_STENCIL_FUNC
The
 params
parameter returns one value, a symbolic constant indicating what function is used to compare the stencil reference value with the stencil buffer value. See
glStencilFunc
.
GL_STENCIL_PASS_DEPTH_FAIL
The
 params
parameter returns one value, a symbolic constant indicating what action is taken when the stencil test passes, but the depth test fails. See
glStencilOp
.
GL_STENCIL_PASS_DEPTH_PASS
The
 params
parameter returns one value, a symbolic constant indicating what action is taken when the stencil test passes and the depth test passes. See
glStencilOp
.
GL_STENCIL_REF
The
 params
parameter returns one value, the reference value that is compared with the contents of the stencil buffer. See
glStencilFunc
.
GL_STENCIL_TEST
The
 params
parameter returns a single Boolean value indicating whether stencil testing of fragments is enabled. See
glStencilFunc
 and
glStencilOp
.
GL_STENCIL_VALUE_MASK
The
 params
parameter returns one value, the mask that is used to mask both the stencil reference value and the stencil buffer value before they are compared. See
glStencilFunc
.
GL_STENCIL_WRITEMASK
The
 params
parameter returns one value, the mask that controls writing of the stencil bitplanes. See
glStencilMask
.
GL_STEREO
The
 params
parameter returns a single Boolean value indicating whether stereo buffers (left and right) are supported.
GL_SUBPIXEL_BITS
The
 params
parameter returns one value, an estimate of the number of bits of subpixel resolution that are used to position rasterized geometry in window coordinates.
GL_TEXTURE_1D
The
 params
parameter returns a single Boolean value indicating whether 1D texture mapping is enabled. See
glTexImage1D
.
GL_TEXTURE_2D
The
 params
parameter returns a single Boolean value indicating whether 2D texture mapping is enabled. See
glTexImage2D
.
GL_TEXTURE_ENV_COLOR
The
 params
parameter returns four values: the red, green, blue, and alpha values of the texture environment color. Integer values, if requested, are linearly mapped from the internal floating-point representation such that 1.0 returns the most positive representable integer value, and
-
1.0 returns the most negative representable integer value. See
glTexEnv
.
GL_TEXTURE_ENV_MODE
The
 params
parameter returns one value, a symbolic constant indicating what texture environment function is currently selected. See
glTexEnv
.
GL_TEXTURE_GEN_S
The
 params
parameter returns a single Boolean value indicating whether automatic generation of the S texture coordinate is enabled. See
glTexGen
.
GL_TEXTURE_GEN_T
The
 params
parameter returns a single Boolean value indicating whether automatic generation of the T texture coordinate is enabled. See
glTexGen
.
GL_TEXTURE_GEN_R
The
 params
parameter returns a single Boolean value indicating whether automatic generation of the R texture coordinate is enabled. See
glTexGen
.
GL_TEXTURE_GEN_Q
The
 params
parameter returns a single Boolean value indicating whether automatic generation of the Q texture coordinate is enabled. See
glTexGen
.
GL_TEXTURE_MATRIX
The
 params
parameter returns sixteen values: the texture matrix on the top of the texture matrix stack. See
glPushMatrix
.
GL_TEXTURE_STACK_DEPTH
The
 params
parameter returns one value, the number of matrices on the texture matrix stack. See
glPushMatrix
.
GL_UNPACK_ALIGNMENT
The
 params
parameter returns one value, the byte alignment used for reading pixel data from memory. See
glPixelStore
.
GL_UNPACK_LSB_FIRST
The
 params
parameter returns a single Boolean value indicating whether single-bit pixels being read from memory are read first from the least significant bit of each unsigned byte. See
glPixelStore
.
GL_UNPACK_ROW_LENGTH
The
 params
parameter returns one value, the row length used for reading pixel data from memory. See
glPixelStore
.
GL_UNPACK_SKIP_PIXELS
The
 params
parameter returns one value, the number of pixel locations skipped before the first pixel is read from memory. See
glPixelStore
.
GL_UNPACK_SKIP_ROWS
The
 params
parameter returns one value, the number of rows of pixel locations skipped before the first pixel is read from memory. See
glPixelStore
.
GL_UNPACK_SWAP_BYTES
The
 params
parameter returns a single Boolean value indicating whether the bytes of two-byte and four-byte pixel indices and components are swapped after being read from memory. See
glPixelStore
.
GL_VIEWPORT
The
 params
parameter returns four values: the
x
 and
y
 window coordinates of the viewport, followed by its width and height. See
glViewport
.
GL_ZOOM_X
The
 params
parameter returns one value, the
x
 pixel zoom factor. See
glPixelZoom
.
GL_ZOOM_Y
The
 params
parameter returns one value, the
y
 pixel zoom factor. See
glPixelZoom
.
Many of the Boolean parameters can also be queried more easily using
glIsEnabled
.
Errors
GL_INVALID_ENUM
 is generated if
pname
 is not an accepted value.
GL_INVALID_OPERATION
 is generated if
glGet
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glGetClipPlane
,
glGetError
,
glGetLight
,
glGetMap
,
glGetMaterial
,
glGetPixelMap
,
glGetPolygonStipple
,
glGetString
,
glGetTexEnv
,
glGetTexGen
,
glGetTexImage
,
glGetTexLevelParameter
,
glGetTexParameter
,
glIsEnabled


glGetClipPlane
The
glGetClipPlane
 function returns the coefficients of the specified clipping plane.
void glGetClipPlane
(
GLenum
plane
,
GLdouble
*equation
);
Parameters
plane
Specifies a clipping plane. The number of clipping planes depends on the implementation, but at least six clipping planes are supported. They are identified by symbolic names of the form
GL_CLIP_PLANE
i where 0
£
i
 <
GL_MAX_CLIP_PLANES
.
equation
Returns four double-precision values that are the coefficients of the plane equation of
plane
 in eye coordinates.
Remarks
The
glGetClipPlane
 function returns in
equation
 the four coefficients of the plane equation for
plane
.
It is always the case that
GL_CLIP_PLANE
i
 =
GL_CLIP_PLANE0
 +
i
.
If an error is generated, no change is made to the contents of
equation
.
Errors
GL_INVALID_ENUM
 is generated if
plane
 is not an accepted value.
GL_INVALID_OPERATION
 is generated if
glGetClipPlane
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glClipPlane


glGetError
The
glGetError
 function returns error information.
GLenum glGetError
(
void
);
Remarks
The
glGetError
 function returns the value of the error flag. Each detectable error is assigned a numeric code and symbolic name. When an error occurs, the error flag is set to the appropriate error code value. No other errors are recorded until
glGetError
 is called, the error code is returned, and the flag is reset to
GL_NO_ERROR
. If a call to
glGetError
 returns
GL_NO_ERROR
, there has been no detectable error since the last call to
glGetError
, or since the GL was initialized.
To allow for distributed implementations, there may be several error flags. If any single error flag has recorded an error, the value of that flag is returned and that flag is reset to
GL_NO_ERROR
 when
glGetError
 is called. If more than one flag has recorded an error,
glGetError
 returns and clears an arbitrary error flag value. Thus,
glGetError
 should always be called in a loop, until it returns
GL_NO_ERROR
, if all error flags are to be reset.
Initially, all error flags are set to
GL_NO_ERROR
.
The currently defined errors are as follows:
GL_NO_ERROR
No error has been recorded. The value of this symbolic constant is guaranteed to be zero.
GL_INVALID_ENUM
An unacceptable value is specified for an enumerated argument. The offending command is ignored, having no side effect other than to set the error flag.
GL_INVALID_VALUE
A numeric argument is out of range. The offending command is ignored, having no side effect other than to set the error flag.
GL_INVALID_OPERATION
The specified operation is not allowed in the current state. The offending command is ignored, having no side effect other than to set the error flag.
GL_STACK_OVERFLOW
This command would cause a stack overflow. The offending command is ignored, having no side effect other than to set the error flag.
GL_STACK_UNDERFLOW
This command would cause a stack underflow. The offending command is ignored, having no side effect other than to set the error flag.
GL_OUT_OF_MEMORY
There is not enough memory left to execute the command. The state of the GL is undefined, except for the state of the error flags, after this error is recorded.
When an error flag is set, results of a GL operation are undefined only if
GL_OUT_OF_MEMORY
 has occurred. In all other cases, the command generating the error is ignored and has no effect on the GL state or frame buffer contents.
Errors
GL_INVALID_OPERATION
 is generated if
glGetError
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.


glGetLight
glGetLightfv, glGetLightiv
The
glGetLightfv
 and
glGetLightiv
 functions return light source parameter values.
void glGetLightfv
(
GLenum
light
,
GLenum
pname
,
GLfloat
*params
);
void glGetLightiv
(
GLenum
light
,
GLenum
pname
,
GLint
*params
);
Parameters
light
Specifies a light source. The number of possible lights depends on the implementation, but at least eight lights are supported. They are identified by symbolic names of the form
GL_LIGHT
i
 where 0
£
i
 <  <
GL_MAX_LIGHTS
.
pname
Specifies a light source parameter for
light
. Accepted symbolic names are
GL_AMBIENT, GL_DIFFUSE, GL_SPECULAR, GL_POSITION, GL_SPOT_DIRECTION, GL_SPOT_EXPONENT, GL_SPOT_CUTOFF, GL_CONSTANT_ATTENUATION
,
GL_LINEAR_ATTENUATION
, and
GL_QUADRATIC_ATTENUATION
.
params
Returns the requested data.
Remarks
The
 glGetLight
 function returns in
params
 the value or values of a light source parameter.
light
 names the light and is a symbolic name of the form
GL_LIGHT
i
 for 0
£
i
<
GL_MAX_LIGHTS
, where
GL_MAX_LIGHTS
 is an implementation dependent constant that is greater than or equal to eight.
pname
 specifies one of ten light source parameters, again by symbolic name.
The parameters are as follows:
GL_AMBIENT
The
 params
 parameter returns four integer or floating-point values representing the ambient intensity of the light source. Integer values, when requested, are linearly mapped from the internal floating-point representation such that 1.0 maps to the most positive representable integer value, and
-
1.0 maps to the most negative representable integer value. If the internal value is outside the range [
-
1,1], the corresponding integer return value is undefined.
GL_DIFFUSE
The
 params
 parameter returns four integer or floating-point values representing the diffuse intensity of the light source. Integer values, when requested, are linearly mapped from the internal floating-point representation such that 1.0 maps to the most positive representable integer value, and
-
1.0 maps to the most negative representable integer value. If the internal value is outside the range [
-
1,1], the corresponding integer return value is undefined.
GL_SPECULAR
The
 params
 parameter returns four integer or floating-point values representing the specular intensity of the light source. Integer values, when requested, are linearly mapped from the internal floating-point representation such that 1.0 maps to the most positive representable integer value, and
-
1.0 maps to the most negative representable integer value. If the internal value is outside the range [
-
1,1], the corresponding integer return value is undefined.
GL_POSITION
The
 params
 parameter returns four integer or floating-point values representing the position of the light source. Integer values, when requested, are computed by rounding the internal floating-point values to the nearest integer value. The returned values are those maintained in eye coordinates. They will not be equal to the values specified using
glLight
, unless the modelview matrix was identity at the time
glLight
 was called.
GL_SPOT_DIRECTION
The
 params
 parameter returns three integer or floating-point values representing the direction of the light source. Integer values, when requested, are computed by rounding the internal floating-point values to the nearest integer value. The returned values are those maintained in eye coordinates. They will not be equal to the values specified using
glLight
, unless the modelview matrix was identity at the time
glLight
 was called. Although spot direction is normalized before being used in the lighting equation, the returned values are the transformed versions of the specified values prior to normalization.
GL_SPOT_EXPONENT
The
 params
 parameter returns a single integer or floating-point value representing the spot exponent of the light. An integer value, when requested, is computed by rounding the internal floating-point representation to the nearest integer.
GL_SPOT_CUTOFF
The
 params
 parameter returns a single integer or floating-point value representing the spot cutoff angle of the light. An integer value, when requested, is computed by rounding the internal floating-point representation to the nearest integer.
GL_CONSTANT_ATTENUATION
The
 params
 parameter returns a single integer or floating-point value representing the constant (not distance related) attenuation of the light. An integer value, when requested, is computed by rounding the internal floating-point representation to the nearest integer.
GL_LINEAR_ATTENUATION
The
 params
 parameter returns a single integer or floating-point value representing the linear attenuation of the light. An integer value, when requested, is computed by rounding the internal floating-point representation to the nearest integer.
GL_QUADRATIC_ATTENUATION
The
 params
 parameter returns a single integer or floating-point value representing the quadratic attenuation of the light. An integer value, when requested, is computed by rounding the internal floating-point representation to the nearest integer.
It is always the case that
GL_LIGHT
i
=
GL_LIGHT0
 +
i
.
If an error is generated, no change is made to the contents of
params
.
Errors
GL_INVALID_ENUM
 is generated if
light
 or
pname
 is not an accepted value.
GL_INVALID_OPERATION
 is generated if
glGetLight
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glLight


glGetMap
glGetMapdv, glGetMapfv, glGetMapiv
These functions return evaluator parameters.
void
glGetMapdv
(
GLenum
target
,
GLenum
query
,
GLdouble
*v
);
void glGetMapfv
(
GLenum
target
,
GLenum
query
,
GLfloat
*v
);
void glGetMapiv
(
GLenum
target
,
GLenum
query
,
GLint
*v
);
Parameters
target
Specifies the symbolic name of a map. Accepted values are
GL_MAP1_COLOR_4, GL_MAP1_INDEX, GL_MAP1_NORMAL, GL_MAP1_TEXTURE_COORD_1, GL_MAP1_TEXTURE_COORD_2, GL_MAP1_TEXTURE_COORD_3
,
GL_MAP1_TEXTURE_COORD_4
,
GL_MAP1_VERTEX_3
,
GL_MAP1_VERTEX_4
,
GL_MAP2_COLOR_4
,
GL_MAP2_INDEX
,
GL_MAP2_NORMAL
,
GL_MAP2_TEXTURE_COORD_1
,
GL_MAP2_TEXTURE_COORD_2
,
GL_MAP2_TEXTURE_COORD_3
,
GL_MAP2_TEXTURE_COORD_4
,
GL_MAP2_VERTEX_3
, and
GL_MAP2_VERTEX_4
.
query
Specifies which parameter to return. Symbolic names
GL_COEFF
,
GL_ORDER
, and
GL_DOMAIN
 are accepted.
v
Returns the requested data.
Remarks
The
glGetMap
 function returns evaluator parameters. (The
 glMap1
 and
glMap2
 functions define evaluators.)
target
 chooses a map,
query
 selects a specific parameter, and
v
 points to storage where the values will be returned.
The acceptable values for the
target
 parameter are described in
glMap1
 and
glMap2
The
 query
 parameter can assume the following values:
GL_COEFF
The
 v
 parameter returns the control points for the evaluator function. One-dimensional evaluators return
order
 control points, and two-dimensional evaluators return
uorder
x
vorder
 control points. Each control point consists of one, two, three, or four integer, single-precision floating-point, or double-precision floating-point values, depending on the type of the evaluator. Two-dimensional control points are returned in row-major order, incrementing the
uorder
 index quickly, and the
vorder
 index after each row. Integer values, when requested, are computed by rounding the internal floating-point values to the nearest integer values.
GL_ORDER
v
 returns the order of the evaluator function. One-dimensional evaluators return a single value,
order
. Two-dimensional evaluators return two values,
uorder
 and
vorder
.
GL_DOMAIN
v
 returns the linear u and v mapping parameters. One-dimensional evaluators return two values,
u
1 and
u
2, as specified by
glMap1
. Two-dimensional evaluators return four values (
u
1,
u
2,
v
1, and
v
2) as specified by
glMap2
. Integer values, when requested, are computed by rounding the internal floating-point values to the nearest integer values.
If an error is generated, no change is made to the contents of
v
.
Errors
GL_INVALID_ENUM
 is generated if either
target
 or
query
 is not an accepted value.
GL_INVALID_OPERATION
 is generated if
glGetMap
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glEvalCoord
,
glMap1
,
glMap2


glGetMaterial
glGetMaterialfv, glGetMaterialiv
The
glGetMaterialfv
 and
glGetMaterialiv
 functions return material parameters.
void glGetMaterialfv
(
GLenum
face
,
GLenum
pname
,
GLfloat
*params
);
void glGetMaterialiv
(
GLenum
face
,
GLenum
pname
,
GLint
*params
);
Parameters
face
Specifies which of the two materials is being queried.
GL_FRONT
 or
GL_BACK
 are accepted, representing the front and back materials, respectively.
pname
Specifies the material parameter to return.
GL_AMBIENT, GL_DIFFUSE, GL_SPECULAR, GL_EMISSION, GL_SHININESS,
 and
GL_COLOR_INDEXES
 are accepted.
params
Returns the requested data.
Remarks
The
 glGetMaterial
 function returns in
params
 the value or values of parameter
pname
 of material
face
. Six parameters are defined:
GL_AMBIENT
The
 params
 parameter returns four integer or floating-point values representing the ambient reflectance of the material. Integer values, when requested, are linearly mapped from the internal floating-point representation such that 1.0 maps to the most positive representable integer value, and
-
1.0 maps to the most negative representable integer value. If the internal value is outside the range [
-
1,1], the corresponding integer return value is undefined.
GL_DIFFUSE
The
 params
 parameter returns four integer or floating-point values representing the diffuse reflectance of the material. Integer values, when requested, are linearly mapped from the internal floating-point representation such that 1.0 maps to the most positive representable integer value, and
-
1.0 maps to the most negative representable integer value. If the internal value is outside the range [
-
1,1], the corresponding integer return value is undefined.
GL_SPECULAR
The
 params
 parameter returns four integer or floating-point values representing the specular reflectance of the material. Integer values, when requested, are linearly mapped from the internal floating-point representation such that 1.0 maps to the most positive representable integer value, and
-
1.0 maps to the most negative representable integer value. If the internal value is outside the range [
-
1,1], the corresponding integer return value is undefined.
GL_EMISSION
The
 params
 parameter returns four integer or floating-point values representing the emitted light intensity of the material. Integer values, when requested, are linearly mapped from the internal floating-point representation such that 1.0 maps to the most positive representable integer value, and
-
1.0 maps to the most negative representable integer value. If the internal value is outside the range [
-
1,1], the corresponding integer return value is undefined.
GL_SHININESS
The
 params
 parameter returns one integer or floating-point value representing the specular exponent of the material. Integer values, when requested, are computed by rounding the internal floating-point value to the nearest integer value.
GL_COLOR_INDEXES
The
 params
 parameter returns three integer or floating-point values representing the ambient, diffuse, and specular indices of the material. These indices are used only for color index lighting. (The other parameters are all used only for RGBA lighting.) Integer values, when requested, are computed by rounding the internal floating-point values to the nearest integer values.
If an error is generated, no change is made to the contents of
params
.
Errors
GL_INVALID_ENUM
 is generated if
face
 or
pname
 is not an accepted value.
GL_INVALID_OPERATION
 is generated if
glGetMaterial
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glMaterial


glGetPixelMap
glGetPixelMapfv, glGetPixelMapuiv, glGetPixelMapusv
These functions return the specified pixel map.
void glGetPixelMapfv
(
GLenum
map
,
GLfloat
*values
);
void glGetPixelMapuiv
(
GLenum
map
,
GLuint
*values
);
void glGetPixelMapusv
(
GLenum
map
,
GLushort
*values
);
Parameters
map
Specifies the name of the pixel map to return. Accepted values are
GL_PIXEL_MAP_I_TO_I
,
GL_PIXEL_MAP_S_TO_S
,
 GL_PIXEL_MAP_I_TO_R
,
GL_PIXEL_MAP_I_TO_G
,
GL_PIXEL_MAP_I_TO_B
,
GL_PIXEL_MAP_I_TO_A
,
GL_PIXEL_MAP_R_TO_R
,
GL_PIXEL_MAP_G_TO_G
,
GL_PIXEL_MAP_B_TO_B
, and
GL_PIXEL_MAP_A_TO_A
values
Returns the pixel map contents.
Remarks
See
glPixelMap
 for a description of the acceptable values for the
map
 parameter. The
glGetPixelMap
 function returns in
values
 the contents of the pixel map specified in
map
. Pixel maps are used during the execution of
glReadPixels
,
glDrawPixels
,
glCopyPixels
,
glTexImage1D
, and
glTexImage2D
 to map color indices, stencil indices, color components, and depth components to other values.
Unsigned integer values, if requested, are linearly mapped from the internal fixed or floating-point representation such that 1.0 maps to the largest representable integer value, and 0.0 maps to zero. Return unsigned integer values are undefined if the map value was not in the range [0,1].
To determine the required size of
map
, call
glGet
 with the appropriate symbolic constant.
If an error is generated, no change is made to the contents of
values
.
The following functions retrieve information related to the
glGetPixelMap
 function:
glGet
 with argument
GL_PIXEL_MAP_I_TO_I_SIZE
glGet
 with argument
GL_PIXEL_MAP_S_TO_S_SIZE
glGet
 with argument
GL_PIXEL_MAP_I_TO_R_SIZE
glGet
 with argument
GL_PIXEL_MAP_I_TO_G_SIZE
glGet
 with argument
GL_PIXEL_MAP_I_TO_B_SIZE
glGet
 with argument
GL_PIXEL_MAP_I_TO_A_SIZE
glGet
 with argument
GL_PIXEL_MAP_R_TO_R_SIZE
glGet
 with argument
GL_PIXEL_MAP_G_TO_G_SIZE
glGet
 with argument
GL_PIXEL_MAP_B_TO_B_SIZE
glGet
 with argument
GL_PIXEL_MAP_A_TO_A_SIZE
glGet
 with argument
GL_MAX_PIXEL_MAP_TABLE
Errors
GL_INVALID_ENUM
 is generated if
map
 is not an accepted value.
GL_INVALID_OPERATION
 is generated if
glGetPixelMap
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glCopyPixels
,
glDrawPixels
,
glPixelMap
,
glPixelTransfer
,
glReadPixels
,
glTexImage1D
,
glTexImage2D


glGetPointervEXT
The
glGetPointervEXT
 function returns the address of a vertex data array.
void glGetPointervEXT
(
GLenum
pname
,
GLvoid
*params
);
Parameters
pname
Specifies the type of array pointer to return from the following list symbolic constants:
GL_VERTEX_ARRAY_POINTER_EXT
,
GL_NORMAL_ARRAY_POINTER_EXT
,
 GL_COLOR_ARRAY_POINTER_EXT
,
 GL_INDEX_ARRAY_POINTER_EXT
,
 GL_TEXTURE_COORD_ARRAY_POINTER_EXT
,
 GL_EDGE_FLAG_ARRAY_POINTER_EXT
params
Returns the value of the array pointer specified by
pname
.
Remarks
The
 glGetPointervEXT
 function returns array pointer information. The
pname
 parameter is a symbolic constant specifying the kind of array pointer to return and
params
 is a pointer to a location to place the returned data.
Note
  The
 glGetPointervEXT
 function is an extension function that is not part of the standard OpenGL library but is part of the
GL_EXT_vertex_array
 extension. To check whether your implementation of OpenGL supports
glGetPointervEXT
, call
glGetString
(
GL_EXTENSIONS
). If it returns GL_EXT_vertex_array,
glGetPointervEXT
 is supported.
To obtain the address of an extension function, call
wglGetProcAddress
.
Errors
GL_INVALID_ENUM
 is generated if
pname
 is not an accepted value.
See Also
glArrayElementEXT
,
glColorPointerEXT
,
glDrawArraysEXT
,
glEdgeFlagPointerEXT
,
glIndexPointerEXT
,
glNormalPointerEXT
,
glTexCoordPointerEXT
,
glVertexPointerEXT
,
glGetString
,
wglGetProcAddress


glGetPolygonStipple
The
glGetPolygonStipple
 function returns the polygon stipple pattern.
void glGetPolygonStipple
(
GLubyte
*mask
);
Parameters
mask
Returns the stipple pattern.
Remarks
The
glGetPolygonStipple
 function returns to
mask
 a 32x32 polygon stipple pattern. The pattern is packed into memory as if
glReadPixels
 with both
height
 and
width
 of 32,
type
 of
GL_BITMAP
, and
format
 of
GL_COLOR_INDEX
 were called, and the stipple pattern were stored in an internal 32x32 color index buffer. Unlike
glReadPixels
, however, pixel transfer operations (shift, offset, pixel map) are not applied to the returned stipple image.
If an error is generated, no change is made to the contents of
mask
.
Errors
GL_INVALID_OPERATION
 is generated if
glGetPolygonStipple
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glPixelStore
,
glPixelTransfer
,
glPolygonStipple
,
glReadPixels


glGetString
The
glGetString
 function returns a string describing the current GL connection.
const GLubyte
 *
glGetString
(
GLenum
name
);
Parameters
name
Specifies a symbolic constant, one of
GL_VENDOR
,
GL_RENDERER
,
GL_VERSION
, or
GL_EXTENSIONS
.
Remarks
The
glGetString
 function returns a pointer to a static string describing some aspect of the current GL connection. The
name
 parameter can be one of the following:
GL_VENDOR
Returns the company responsible for this GL implementation. This name does not change from release to release.
GL_RENDERER
Returns the name of the renderer. This name is typically specific to a particular configuration of a hardware platform. It does not change from release to release.
GL_VERSION
Returns a version or release number.
GL_EXTENSIONS
Returns a space-separated list of supported extensions to GL.
Because GL does not include queries for the performance characteristics of an implementation, it is expected that some applications will be written to recognize known platforms and will modify their GL usage based on known performance characteristics of these platforms. Strings
GL_VENDOR
 and
GL_RENDERER
 together uniquely specify a platform, and will not change from release to release. They should be used by such platform recognition algorithms.
The format and contents of the string that
glGetString
 returns depend on the implementation, except that extension names will not include space characters and will be separated by space characters in the
GL_EXTENSIONS
 string, and that all strings are null-terminated.
If an error is generated,
glGetString
 returns zero.
Errors
GL_INVALID_ENUM
 is generated if
name
 is not an accepted value.
GL_INVALID_OPERATION
 is generated if
glGetString
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.


glGetTexEnv
glGetTexEnvfv, glGetTexEnviv
The
glGetTexEnvfv
 and
glGetTexEnviv
 functions return texture environment parameters.
void glGetTexEnvfv
(
GLenum
target
,
GLenum
pname
,
GLfloat
*params
);
void glGetTexEnviv
(
GLenum
target
,
GLenum
pname
,
GLint
*params
);
Parameters
target
Specifies a texture environment. Must be
GL_TEXTURE_ENV
.
pname
Specifies the symbolic name of a texture environment parameter. Accepted values are
GL_TEXTURE_ENV_MODE
 and
GL_TEXTURE_ENV_COLOR
.
params
Returns the requested data.
Remarks
The
 glGetTexEnv
 function returns in
params
 selected values of a texture environment that was specified with
glTexEnv
.
target
 specifies a texture environment. Currently, only one texture environment is defined and supported:
GL_TEXTURE_ENV
.
The
 pname
 parameter names a specific texture environment parameter. The two parameters are as follows:
GL_TEXTURE_ENV_MODE
The
 params
 parameter returns the single-valued texture environment mode, a symbolic constant.
GL_TEXTURE_ENV_COLOR
The
 params
 parameter returns four integer or floating-point values that are the texture environment color. Integer values, when requested, are linearly mapped from the internal floating-point representation such that 1.0 maps to the most positive representable integer, and
-
1.0 maps to the most negative representable integer.
If an error is generated, no change is made to the contents of
params
.
Errors
GL_INVALID_ENUM
 is generated if
target
 or
pname
 is not an accepted value.
GL_INVALID_OPERATION
 is generated if
glGetTexEnv
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glTexEnv


glGetTexGen
glGetTexGendv, glGetTexGenfv, glGetTexGeniv
These functions return texture coordinate generation parameters.
void glGetTexGendv
(
GLenum
coord
,
GLenum
pname
,
GLdouble
*params
);
void glGetTexGenfv
(
GLenum
coord
,
GLenum
pname
,
GLfloat
*params
);
void glGetTexGeniv
(
GLenum
coord
,
GLenum
pname
,
GLint
*params
);
Parameters
coord
Specifies a texture coordinate. Must be
GL_S
,
GL_T
,
GL_R
, or
GL_Q
.
pname
Specifies the symbolic name of the value(s) to be returned. Must be either
GL_TEXTURE_GEN_MODE
 or the name of one of the texture generation plane equations:
GL_OBJECT_PLANE
 or
GL_EYE_PLANE
.
params
Returns the requested data.
Remarks
The
 glGetTexGen
 funtion returns in
params
 selected parameters of a texture coordinate generation function that was specified using
glTexGen
.
coord
 names one of the (
s
,
t
,
r
,
q
) texture coordinates, using the symbolic constant
GL_S
,
GL_T
,
GL_R
, or
GL_Q
.
The
pname
 parameter specifies one of three symbolic names:
GL_TEXTURE_GEN_MODE
params
 returns the single-valued texture generation function, a symbolic constant.
GL_OBJECT_PLANE
The
 params
 parameter returns the four plane equation coefficients that specify object linear-coordinate generation. Integer values, when requested, are mapped directly from the internal floating-point representation.
GL_EYE_PLANE
The
 params
 parameter returns the four plane equation coefficients that specify eye linear-coordinate generation. Integer values, when requested, are mapped directly from the internal floating-point representation. The returned values are those maintained in eye coordinates. They are not equal to the values specified using
glTexGen
, unless the modelview matrix was identified at the time
glTexGen
 was called.
If an error is generated, no change is made to the contents of
params
.
Errors
GL_INVALID_ENUM
 is generated if
coord
 or
pname
 is not an accepted value.
GL_INVALID_OPERATION
 is generated if
glGetTexGen
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glTexGen


glGetTexImage
The
glGetTexImage
 function returns a texture image.
void
glGetTexImage
(
GLenum
target
,
GLint
level
,
GLenum
format
,
GLenum
type
,
GLvoid
*pixels
);
Parameters
target
Specifies which texture is to be obtained.
GL_TEXTURE_1D
 and
GL_TEXTURE_2D
 are accepted.
level
Specifies the level-of-detail number of the desired image. Level 0 is the base image level. Level
n
 is the
n
th mipmap reduction image.
format
Specifies a pixel format for the returned data. The supported formats are
GL_RED
,
GL_GREEN
,
GL_BLUE
,
GL_ALPHA
,
GL_RGB
,
GL_RGBA
,
GL_LUMINANCE
, and
GL_LUMINANCE_ALPHA
.
type
Specifies a pixel type for the returned data. The supported types are
GL_UNSIGNED_BYTE
,
GL_BYTE
,
GL_UNSIGNED_SHORT
,
GL_SHORT
,
GL_UNSIGNED_INT
,
GL_INT
, and
GL_FLOAT
.
pixels
Returns the texture image. Should be a pointer to an array of the type specified by
type
.
Remarks
The
glGetTexImage
 function returns a texture image into
pixels
.
target
 specifies whether the desired texture image is one specified by
glTexImage1D
 (
GL_TEXTURE_1D
) or by
glTexImage2D
 (
GL_TEXTURE_2D
).
level
 specifies the level-of-detail number of the desired image.
format
 and
type
 specify the format and type of the desired image array. Please see
glTexImage1D
 and
glDrawPixels
 for a description of the acceptable values for the
format
 and
type
 parameters, respectively.
Operation of
glGetTexImage
 is best understood by considering the selected internal four-component texture image to be an RGBA color buffer the size of the image. The semantics of
glGetTexImage
 are then identical to those of
glReadPixels
 called with the same
format
 and
type
, with
x
 and
y
 set to zero,
width
 set to the width of the texture image (including border if one was specified), and
height
 set to one for 1-D images, or to the height of the texture image (including border if one was specified) for 2-D images.
Because the internal texture image is an RGBA image, pixel formats
GL_COLOR_INDEX
,
GL_STENCIL_INDEX
, and
GL_DEPTH_COMPONENT
 are not accepted, and pixel type
GL_BITMAP
 is not accepted.
If the selected texture image does not contain four components, the following mappings are applied. Single-component textures are treated as RGBA buffers with red set to the single-component value, and green, blue, and alpha set to zero. Two-component textures are treated as RGBA buffers with red set to the value of component zero, alpha set to the value of component one, and green and blue set to zero. Finally, three-component textures are treated as RGBA buffers with red set to component zero, green set to component one, blue set to component two, and alpha set to zero.
To determine the required size of
pixels
, use
glGetTexLevelParameter
 to ascertain the dimensions of the internal texture image, then scale the required number of pixels by the storage required for each pixel, based on
format
 and
type
. Be sure to take the pixel storage parameters into account, especially
GL_PACK_ALIGNMENT
.
If an error is generated, no change is made to the contents of
pixels
.
The following functions retrieve information related to the
glGetTexImage
function:
glGetTexLevelParameter
 with argument
GL_TEXTURE_WIDTH
glGetTexLevelParameter
 with argument
GL_TEXTURE_HEIGHT
glGetTexLevelParameter
 with argument
GL_TEXTURE_BORDER
glGetTexLevelParameter
 with argument
GL_TEXTURE_COMPONENTS
glGet
 with arguments
GL_PACK_ALIGNMENT
 and others
Errors
GL_INVALID_ENUM
 is generated if
target
,
format
, or
type
 is not an accepted value.
GL_INVALID_VALUE
 is generated if
level
 is less than zero or greater than log
 (2)
 max, where max is the returned value of
GL_MAX_TEXTURE_SIZE
.
GL_INVALID_OPERATION
 is generated if
glGetTexImage
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glDrawPixels
,
glReadPixels
,
glTexImage1D
,
glTexImage2D


glGetTexLevelParameter
glGetTexLevelParameterfv, glGetTexLevelParameteriv
The
glGetTexLevelParameterfv
 and
glGetTexLevelParameteriv
 functions return texture parameter values for a specific level of detail.
void glGetTexLevelParameterfv
(
GLenum
target
,
GLint
level
,
GLenum
pname
,
GLfloat
*params
);
void glGetTexLevelParameteriv
(
GLenum
target
,
GLint
level
,
GLenum
pname
,
GLint
*params
);
Parameters
target
Specifies the symbolic name of the target texture, either
GL_TEXTURE_1D
 or
GL_TEXTURE_2D
.
level
Specifies the level-of-detail number of the desired image. Level 0 is the base image level. Level
n
 is the
n
th mipmap reduction image.
pname
Specifies the symbolic name of a texture parameter.
GL_TEXTURE_WIDTH
,
GL_TEXTURE_HEIGHT
,
GL_TEXTURE_COMPONENTS
, and
GL_TEXTURE_BORDER
 are accepted.
params
Returns the requested data.
Remarks
The
 glGetTexLevelParameter
 function returns in
params
 texture parameter values for a specific level-of-detail value, specified as
level
.
target
 defines the target texture, either
GL_TEXTURE_1D
 or
GL_TEXTURE_2D
, to specify one- or two-dimensional texturing.
pname
 specifies the texture parameter whose value or values will be returned.
The accepted parameter names are as follows:
GL_TEXTURE_WIDTH
The
 params
 parameter returns a single value, the width of the texture image. This value includes the border of the texture image.
GL_TEXTURE_HEIGHT
The
 params
 parameter returns a single value, the height of the texture image. This value includes the border of the texture image.
GL_TEXTURE_COMPONENTS
The
 params
 parameter returns a single value, the number of components in the texture image.
GL_TEXTURE_BORDER
The
 params
 parameter returns a single value, the width in pixels of the border of the texture image.
If an error is generated, no change is made to the contents of
params
.
Errors
GL_INVALID_ENUM
 is generated if
target
 or
pname
 is not an accepted value.
GL_INVALID_VALUE
 is generated if
level
 is less than zero or greater than log
 (2)
 max, where max is the returned value of
GL_MAX_TEXTURE_SIZE
.
GL_INVALID_OPERATION
 is generated if
glGetTexLevelParameter
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glGetTexParameter
,
glTexImage1D
,
glTexImage2D
,
glTexParameter


glGetTexParameter
glGetTexParameterfv, glGetTexParameteriv
The
glGetTexParameterfv
 and
glGetTexParameteriv
 functions return texture parameter values.
void glGetTexParameterfv
(
GLenum
target
,
GLenum
pname
,
GLfloat
*params
);
void glGetTexParameteriv
(
GLenum
target
,
GLenum
pname
,
GLint
*params
);
Parameters
target
Specifies the symbolic name of the target texture.
GL_TEXTURE_1D
 and
GL_TEXTURE_2D
 are accepted.
pname
Specifies the symbolic name of a texture parameter.
GL_TEXTURE_MAG_FILTER, GL_TEXTURE_MIN_FILTER, GL_TEXTURE_WRAP_S
,
GL_TEXTURE_WRAP_T
, and
GL_TEXTURE_BORDER_COLOR
 are accepted.
params
Returns the texture parameters.
Remarks
The
 glGetTexParameter
 function returns in
params
 the value or values of the texture parameter specified as
pname
. The
target
 parameter defines the target texture, either
GL_TEXTURE_1D
 or
GL_TEXTURE_2D
, to specify one- or two-dimensional texturing. The
pname
 parameter accepts the same symbols as
glTexParameter
, with the same interpretations:
GL_TEXTURE_MAG_FILTER
Returns the single-valued texture magnification filter, a symbolic constant.
GL_TEXTURE_MIN_FILTER
Returns the single-valued texture minification filter, a symbolic constant.
GL_TEXTURE_WRAP_S
Returns the single-valued wrapping function for texture coordinate
 s
, a symbolic constant.
GL_TEXTURE_WRAP_T
Returns the single-valued wrapping function for texture coordinate
t
, a symbolic constant.
GL_TEXTURE_BORDER_COLOR
Returns four integer or floating-point numbers that comprise the RGBA color of the texture border. Floating-point values are returned in the range [0,1]. Integer values are returned as a linear mapping of the internal floating-point  representation such that 1.0 maps to the most positive representable integer and
-
1.0 maps to the most negative representable integer.
If an error is generated, no change is made to the contents of
params
.
Errors
GL_INVALID_ENUM
 is generated if
target
 or
pname
 is not an accepted value.
GL_INVALID_OPERATION
 is generated if
glGetTexParameter
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glTexParameter


glHint
The
glHint
 function specifies implementation-specific hints.
void
glHint
(
GLenum
target
,
GLenum
mode
);
Parameters
target
Specifies a symbolic constant indicating the behavior to be controlled.
GL_FOG_HINT, GL_LINE_SMOOTH_HINT, GL_PERSPECTIVE_CORRECTION_HINT, GL_POINT_SMOOTH_HINT,
and
GL_POLYGON_SMOOTH_HINT
are accepted.
mode
Specifies a symbolic constant indicating the desired behavior.
GL_FASTEST
,
GL_NICEST
, and
GL_DONT_CARE
 are accepted.
Remarks
Certain aspects of GL behavior, when there is room for interpretation, can be controlled with hints. A hint is specified with two arguments.
target
 is a symbolic constant indicating the behavior to be controlled, and
mode
 is another symbolic constant indicating the desired behavior.
mode
 can be one of the following:
GL_FASTEST
The most efficient option should be chosen.
GL_NICEST
The most correct, or highest quality, option should be chosen.
GL_DONT_CARE
The client doesn't have a preference.
Though the implementation aspects that can be hinted are well defined, the interpretation of the hints depends on the implementation. The hint aspects that can be specified with
target
, along with suggested semantics, are as follows:
GL_FOG_HINT
Indicates the accuracy of fog calculation. If per-pixel fog calculation is not efficiently supported by the GL implementation, hinting
GL_DONT_CARE
 or
GL_FASTEST
 can result in per-vertex calculation of fog effects.
GL_LINE_SMOOTH_HINT
Indicates the sampling quality of antialiased lines. Hinting
GL_NICEST
 can result in more pixel fragments being generated during rasterization, if a larger filter function is applied.
GL_PERSPECTIVE_CORRECTION_HINT
Indicates the quality of color and texture coordinate interpolation. If perspective-corrected parameter interpolation is not efficiently supported by the GL implementation, hinting
GL_DONT_CARE
 or
GL_FASTEST
 can result in simple linear interpolation of colors and/or texture coordinates.
GL_POINT_SMOOTH_HINT
Indicates the sampling quality of antialiased points. Hinting
GL_NICEST
 can result in more pixel fragments being generated during rasterization, if a larger filter function is applied.
GL_POLYGON_SMOOTH_HINT
Indicates the sampling quality of antialiased polygons. Hinting
GL_NICEST
 can result in more pixel fragments being generated during rasterization, if a larger filter function is applied.
The interpretation of hints depends on the implementation.
glHint
 can be ignored.
Errors
GL_INVALID_ENUM
 is generated if either
target
 or
mode
 is not an accepted value.
GL_INVALID_OPERATION
 is generated if
glHint
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.


glIndex
glIndexd, glIndexf, glIndexi, glIndexs, glIndexdv, glIndexfv, glIndexiv, glIndexsv
These functions set the current color index.
void glIndexd
(
GLdouble
c
);
void
glIndexf
(
GLfloat
c
);
void
glIndexi
(
GLint
c
);
void glIndexs
(
GLshort
c
);
Parameters
c
Specifies the new value for the current color index.
void glIndexdv
(
const GLdouble
*c
);
void glIndexfv
(
const GLfloat
*c
);
void glIndexiv
(
const GLint
*c
);
void glIndexsv
(
const GLshort
*c
);
Parameters
c
Specifies a pointer to a one-element array that contains the new value for the current color index.
Remarks
The
 glIndex
 function updates the current (single-valued) color index. It takes one argument: the new value for the current color index.
The current index is stored as a floating-point value. Integer values are converted directly to floating-point values, with no special mapping.
Index values outside the representable range of the color index buffer are not clamped. However, before an index is dithered (if enabled) and written to the frame buffer, it is converted to fixed-point format. Any bits in the integer portion of the resulting fixed-point value that do not correspond to bits in the frame buffer are masked out.
The current index can be updated at any time. In particular,
glIndex
 can be called between a call to
glBegin
 and the corresponding call to
glEnd
.
The following function retrieves information related to the
glIndex
 function:
glGet
 with argument
GL_CURRENT_INDEX
See Also
glColor


glIndexMask
The
glIndexMask
 function controls the writing of individual bits in the color index buffers.
void glIndexMask
(
GLuint
mask
);
Parameters
mask
Specifies a bit mask to enable and disable the writing of individual bits in the color index buffers. Initially, the mask is all ones.
Remarks
The
glIndexMask
 function controls the writing of individual bits in the color index buffers. The least significant
n
 bits of
mask
, where
n
 is the number of bits in a color index buffer, specify a mask. Wherever a one appears in the mask, the corresponding bit in the color index buffer (or buffers) is made writable. Where a zero appears, the bit is write-protected.
This mask is used only in color index mode, and it affects only the buffers currently selected for writing (see
glDrawBuffer
). Initially, all bits are enabled for writing.
The following function retrieves information related to the
glIndexMask
 function.
glGet
 with argument
GL_INDEX_WRITEMASK
Errors
GL_INVALID_OPERATION
 is generated if
glIndexMask
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glDepthMask
,
glDrawBuffer
,
glIndex
,
glStencilMask


glIndexPointerEXT
The
glIndexPointerEXT
 function defines an array of color indexes.
void glIndexPointerEXT
(
GLenum
type
,
GLsizei
stride
,
GLsizei
count
,
const GLvoid
 *
pointer
);
Parameters
type
Specifies the datatype of each color index in the array using the following symbolic constants:
GL_SHORT
,
GL_INT
,
GL_FLOAT
,
GL_DOUBLE_EXT
stride
Specifies the byte offset between consecutive color indexes. When
stride
 is zero, the color indexes are tightly packed in the array.
count
Specifies the number of color indexes, counting from the first, that are static.
pointer
Specifies a pointer to the first color index in the array.
Remarks
The
 glIndexPointerEXT
 function specifies the location and data of an array of color indexes to use when rendering. The
type
 parameter specifies the datatype of each color index and
stride
 determines the byte offset from one color index to the next, enabling the packing of vertexes and attributes in a single array or storage in separate arrays. In some implementations storing the vertexes and attributes in a single array can be more efficient than using separate arrays. Starting from the first color index element,
count
 indicates the total number of static elements. Your application can modify static elements, but once the elements are modified, the application must explicitly specify the array again before using the array for any rendering. Non-static array elements are not accessed until you call
glDrawArraysEXT
 or
glArrayElementEXT
.
A color-index array is enabled when you specify the
 GL_INDEX_ARRAY_EXT
constant with
glEnable
. When enabled,
glDrawArraysEXT
 and
glArrayElementEXT
 use the color index array. By default the color-index array is disabled.
You cannot include
glIndexPointerEXT
 in display lists.
When you specify a color-index array using
glIndexPointerEXT
, the values of all the function's color-index array parameters are saved in a client-side state and static array elements can be cached. Because the color-index array parameters are client-side state, their values are not saved or restored by
glPushAttrib
 and
glPopAttrib
.
Although no error is generated when you call
glIndexPointerEXT
 within
glBegin
 and
glEnd
 pairs, the results are undefined.
Note
  The
 glIndexPointerEXT
 function is an extension function that is not part of the standard OpenGL library but is part of the
GL_EXT_vertex_array
 extension. To check whether your implementation of OpenGL supports
glIndexPointerEXT
, call
glGetString
(
GL_EXTENSIONS
). If it returns GL_EXT_vertex_array,
glIndexPointerEXT
 is supported.
To obtain the address of an extension function, call
wglGetProcAddress
.
The following functions retrieve information related to the
glIndexPointerEXT
 function:
glIsEnabled
 with argument
GL_INDEX_ARRAY_EXT
glGet
 with argument
GL_INDEX_ARRAY_STRIDE_EXT
glGet
 with argument
GL_INDEX_ARRAY_COUNT_EXT
glGet
 with argument
GL_INDEX_ARRAY_TYPE_EXT
glGet
 with argument
GL_INDEX_ARRAY_SIZE_EXT
glGetPointervEXT
 with argument
GL_INDEX_ARRAY_POINTER_EXT
Errors
GL_INVALID_ENUM
 is generated if
type
 is not an accepted value.
GL_INVALID_VALUE
 is generated if
stride
 or
count
 is negative.
See Also
glArrayElementEXT
,
glColorPointerEXT
,
glDrawArraysEXT
,
glEdgeFlagPointerEXT
,
glGetPointervEXT
,
glNormalPointerEXT
,
glTexCoordPointerEXT
,
glVertexPointerEXT
,
glGetString
,
wglGetProcAddress


glInitNames
The
glInitNames
 function initializes the name stack.
void glInitNames
(
void
);
Remarks
The name stack is used during selection mode to allow sets of rendering commands to be uniquely identified. It consists of an ordered set of unsigned integers. The
glInitNames
 function causes the name stack to be initialized to its default empty state.
The name stack is always empty while the render mode is not
GL_SELECT
. Calls to
glInitNames
 while the render mode is not
GL_SELECT
 are ignored.
The following functions retrieve information related to the
glInitNames
 function:
glGet
 with argument
GL_NAME_STACK_DEPTH
glGet
 with argument
GL_MAX_NAME_STACK_DEPTH
Errors
GL_INVALID_OPERATION
 is generated if
glInitNames
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glLoadName
,
glPushName
,
glRenderMode
,
glSelectBuffer


glIsEnabled
The
gllsEnabled
 function tests whether a capability is enabled.
GLboolean
glIsEnabled
(
GLenum
cap
);
Parameters
cap
Specifies a symbolic constant indicating a GL capability.
Remarks
The
gllsEnabled
 function returns
GL_TRUE
 if
cap
 is an enabled capability and returns
GL_FALSE
 otherwise. The following capabilities are accepted for
cap
:
GL_ALPHA_TEST
See
glAlphaFunc
GL_AUTO_NORMAL
See
glEvalCoord
GL_BLEND
See
glBlendFunc
GL_CLIP_PLANE
i
See
glClipPlane
GL_COLOR_MATERIAL
See
glColorMaterial
GL_CULL_FACE
See
glCullFace
GL_DEPTH_TEST
See
glDepthFunc
and
glDepthRange
GL_DITHER
See
glEnable
GL_FOG
See
glFog
GL_LIGHT
i
See
glLightModel
and
glLight
GL_LIGHTING
See
glMaterial
glLightModel
and
glLight
GL_LINE_SMOOTH
See
glLineWidth
GL_LINE_STIPPLE
See
glLineStipple
GL_LOGIC_OP
See
glLogicOp
GL_MAP1_COLOR_4
See
glMap1
GL_MAP1_INDEX
See
glMap1
GL_MAP1_NORMAL
See
glMap1
GL_MAP1_TEXTURE_COORD_1
See
glMap1
GL_MAP1_TEXTURE_COORD_2
See
glMap1
GL_MAP1_TEXTURE_COORD_3
See
glMap1
GL_MAP1_TEXTURE_COORD_4
See
glMap1
GL_MAP1_VERTEX_3
See
glMap1
GL_MAP1_VERTEX_4
See
glMap1
GL_MAP2_COLOR_4
See
glMap2
GL_MAP2_INDEX
See
glMap2
GL_MAP2_NORMAL
See
glMap2
GL_MAP2_TEXTURE_COORD_1
See
glMap2
GL_MAP2_TEXTURE_COORD_2
See
glMap2
GL_MAP2_TEXTURE_COORD_3
See
glMap2
GL_MAP2_TEXTURE_COORD_4
See
glMap2
GL_MAP2_VERTEX_3
See
glMap2
GL_MAP2_VERTEX_4
See
glMap2
GL_NORMALIZE
See
glNormal
GL_POINT_SMOOTH
See
glPointSize
GL_POLYGON_SMOOTH
See
glPolygonMode
GL_POLYGON_STIPPLE
See
glPolygonStipple
GL_SCISSOR_TEST
See
glScissor
GL_STENCIL_TEST
See
glStencilFunc
and
glStencilOp
GL_TEXTURE_1D
See
glTexImage1D
GL_TEXTURE_2D
See
glTexImage2D
GL_TEXTURE_GEN_Q
See
glTexGen
GL_TEXTURE_GEN_R
See
glTexGen
GL_TEXTURE_GEN_S
See
glTexGen
GL_TEXTURE_GEN_T
See
glTexGen
If an error is generated,
glIsEnabled
 returns zero.
Errors
GL_INVALID_ENUM
 is generated if
cap
 is not an accepted value.
GL_INVALID_OPERATION
 is generated if
glIsEnabled
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glEnable


glIsList
The
gllsList
 function tests for display-list existence.
GLboolean
glIsList
(
GLuint
list
);
Parameters
list
Specifies a potential display-list name.
Remarks
The
gllsList
 function returns
GL_TRUE
 if
list
 is the name of a display list and returns
GL_FALSE
 otherwise.
Errors
GL_INVALID_OPERATION
 is generated if
glIsList
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glCallList
,
glCallLists
,
glDeleteLists
,
glGenLists
,
glNewList


glLight
glLightf, glLighti, glLightfv, glLightiv
These functions set light source parameters.
void
glLightf
(
GLenum
light
,
GLenum
pname
,
GLfloat
param
);
void glLighti
(
GLenum
light
,
GLenum
pname
,
GLint
param
);
Parameters
light
Specifies a light. The number of lights depends on the implementation, but at least eight lights are supported. They are identified by symbolic names of the form
GL_LIGHT
i where 0
£
i
 <
GL_MAX_LIGHTS
.
pname
Specifies a single-valued light source parameter for
light
.
GL_SPOT_EXPONENT, GL_SPOT_CUTOFF, GL_CONSTANT_ATTENUATION, GL_LINEAR_ATTENUATION
, and
GL_QUADRATIC_ATTENUATION
 are accepted.
param
Specifies the value to which parameter
pname
 of light source
light
 will be set.
void glLightfv
(
GLenum
light
,
GLenum
pname
,
const GLfloat
*params
);
void
glLightiv
(
GLenum
light
,
GLenum
pname
,
const GLint
*params
);
Parameters
light
Specifies a light. The number of lights depends on the implementation, but at least eight lights are supported. They are identified by symbolic names of the form
GL_LIGHT
i
 where 0
£
i
 <
GL_MAX_LIGHTS
.
pname
Specifies a light source parameter for
light
.
GL_AMBIENT, GL_DIFFUSE, GL_SPECULAR, GL_POSITION, GL_SPOT_DIRECTION
,
GL_SPOT_EXPONENT
,
GL_SPOT_CUTOFF
,
GL_CONSTANT_ATTENUATION
,
GL_LINEAR_ATTENUATION
, and
GL_QUADRATIC_ATTENUATION
 are accepted.
params
Specifies a pointer to the value or values to which parameter
pname
 of light source
light
 will be set.
Remarks
The
 glLight
 function sets the values of individual light source parameters.
light
 names the light and is a symbolic name of the form
GL_LIGHT
i
, where 0
£
i
 <
GL_MAX_LIGHTS
.
The
 pname
 parameter specifies one of ten light source parameters, again by symbolic name. The
params
 parameter is either a single value or a pointer to an array that contains the new values.
Lighting calculation is enabled and disabled using
glEnable
 and
glDisable
 with argument
GL_LIGHTING
. When lighting is enabled, light sources that are enabled contribute to the lighting calculation. Light source
i
 is enabled and disabled using
glEnable
 and
glDisable
 with argument
GL_LIGHT
i
.
The ten light parameters are as follows:
GL_AMBIENT
The
params
 parameter contains four integer or floating-point values that specify the ambient RGBA intensity of the light. Integer values are mapped linearly such that the most positive representable value maps to 1.0, and the most negative representable value maps to
-
1.0. Floating-point values are mapped directly. Neither integer nor floating-point values are clamped. The default ambient light intensity is (0.0, 0.0, 0.0, 1.0).
GL_DIFFUSE
The
params
 parameter contains four integer or floating-point values that specify the diffuse RGBA intensity of the light. Integer values are mapped linearly such that the most positive representable value maps to 1.0, and the most negative representable value maps to
-
1.0. Floating-point values are mapped directly. Neither integer nor floating-point values are clamped. The default diffuse intensity is (0.0, 0.0, 0.0, 1.0) for all lights other than light zero. The default diffuse intensity of light zero is (1.0, 1.0, 1.0, 1.0).
GL_SPECULAR
The
params
 parameter contains four integer or floating-point values that specify the specular RGBA intensity of the light. Integer values are mapped linearly such that the most positive representable value maps to 1.0, and the most negative representable value maps to
-
1.0. Floating-point values are mapped directly. Neither integer nor floating-point values are clamped. The default specular intensity is (0.0, 0.0, 0.0, 1.0) for all lights other than light zero. The default specular intensity of light zero is (1.0, 1.0, 1.0, 1.0).
GL_POSITION
The
params
 parameter contains four integer or floating-point values that specify the position of the light in homogeneous object coordinates. Both integer and floating-point values are mapped directly. Neither integer nor floating-point values are clamped.
The position is transformed by the modelview matrix when
glLight
 is called (just as if it were a point), and it is stored in eye coordinates. If the
w
component of the position is 0.0, the light is treated as a directional source. Diffuse and specular lighting calculations take the lights direction, but not its actual position, into account, and attenuation is disabled. Otherwise, diffuse and specular lighting calculations are based on the actual location of the light in eye coordinates, and attenuation is enabled. The default position is (0,0,1,0); thus, the default light source is directional, parallel to, and in the direction of the -
z
 axis.
GL_SPOT_DIRECTION
The
params
 parameter contains three integer or floating-point values that specify the direction of the light in homogeneous object coordinates. Both integer and floating-point values are mapped directly. Neither integer nor floating-point values are clamped.
The spot direction is transformed by the inverse of the modelview matrix when
glLight
 is called (just as it it were a normal), and it is stored in eye coordinates. It is significant only when
GL_SPOT_CUTOFF
 is not 180, which it is by default. The default direction is (0,0,
-
1).
GL_SPOT_EXPONENT
The
params
 parameter is a single integer or floating-point value that specifies the intensity distribution of the light. Integer and floating-point values are mapped directly. Only values in the range [0,128] are accepted.
Effective light intensity is attenuated by the cosine of the angle between the direction of the light and the direction from the light to the vertex being lighted, raised to the power of the spot exponent. Thus, higher spot exponents result in a more focused light source, regardless of the spot cutoff angle (see the following paragraph). The default spot exponent is 0, resulting in uniform light distribution.
GL_SPOT_CUTOFF
The
params
 parameter is a single integer or floating-point value that specifies the maximum spread angle of a light source. Integer and floating-point values are mapped directly. Only values in the range [0,90], and the special value 180, are accepted. If the angle between the direction of the light and the direction from the light to the vertex being lighted is greater than the spot cutoff angle, the light is completely masked. Otherwise, its intensity is controlled by the spot exponent and the attenuation factors. The default spot cutoff is 180, resulting in uniform light distribution.
GL_CONSTANT_ATTENUATION
GL_LINEAR_ATTENUATION
GL_QUADRATIC_ATTENUATION
The
params
 parameter is a single integer or floating-point value that specifies one of the three light attenuation factors. Integer and floating-point values are mapped directly. Only nonnegative values are accepted. If the light is positional, rather than directional, its intensity is attenuated by the reciprocal of the sum of: the constant factor, the linear factor times the distance between the light and the vertex being lighted, and the  quadratic factor times the square of the same distance. The default attenuation factors are (1,0,0), resulting in no attenuation.
It is always the case that
GL_LIGHT
i
 =
GL_LIGHT0
 +
i
.
The following functions retrieve information related to the
glLight
function:
glGetLight
glIsEnabled
 with argument
GL_LIGHTING
Errors
GL_INVALID_ENUM
 is generated if either
light
 or
pname
 is not an accepted value.
GL_INVALID_VALUE
 is generated if a spot exponent value is specified outside the range [0,128], or if spot cutoff is specified outside the range [0,90] (except for the special value 180), or if a negative attenuation factor is specified.
GL_INVALID_OPERATION
 is generated if
glLight
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glColorMaterial
,
glLightModel
,
glMaterial


glLightModel
glLightModelf, glLightModeli, glLightModelfv, glLightModeliv
These functions set the lighting model parameters.
void
glLightModelf
(
GLenum
pname
,
GLfloat
param
);
void glLightModeli
(
GLenum
pname
,
GLint
param
);
Parameters
pname
Specifies a single-valued lighting model parameter.
GL_LIGHT_MODEL_LOCAL_VIEWER
 and
GL_LIGHT_MODEL_TWO_SIDE
 are accepted.
param
Specifies the value to which
param
 will be set.
void glLightModelfv
(
GLenum
pname
,
const GLfloat
*params
);
void glLightModeliv
(
GLenum
pname
,
const GLint
*params
);
Parameters
pname
Specifies a lighting model parameter.
GL_LIGHT_MODEL_AMBIENT, GL_LIGHT_MODEL_LOCAL_VIEWER,
 and
GL_LIGHT_MODEL_TWO_SIDE
 are accepted.
params
Specifies a pointer to the value or values to which
params
 will be set.
Remarks
The
glLightModel
 function sets the lighting model parameter.
pname
 names a parameter and
params
 gives the new value. There are three lighting model parameters:
GL_LIGHT_MODEL_AMBIENT
The
params
 parameter contains four integer or floating-point values that specify the ambient RGBA intensity of the entire scene. Integer values are mapped linearly such that the most positive representable value maps to 1.0, and the most negative representable value maps to
-
1.0. Floating-point values are mapped directly. Neither integer nor floating-point values are clamped. The default ambient scene intensity is (0.2, 0.2, 0.2, 1.0).
GL_LIGHT_MODEL_LOCAL_VIEWER
The
params
 parameter is a single integer or floating-point value that specifies how specular reflection angles are computed. If
params
 is 0 (or 0.0), specular reflection angles take the view direction to be parallel to and in the direction of the
-
z axis, regardless of the location of the vertex in eye coordinates. Otherwise specular reflections are computed from the origin of the eye coordinate system. The default is 0.
GL_LIGHT_MODEL_TWO_SIDE
The
params
 parameter is a single integer or floating-point value that specifies whether one- or two-sided lighting calculations are done for polygons. It has no effect on the lighting calculations for points, lines, or bitmaps. If
params
 is 0 (or 0.0), one-sided lighting is specified, and only the
front
 material parameters are used in the lighting equation. Otherwise, two-sided lighting is specified. In this case, vertexes of back-facing polygons are lighted using the
back
 material parameters, and have their normals reversed before the lighting equation is evaluated. Vertexes of front-facing polygons are always lighted using the
front
 material parameters, with no change to their normals. The default is 0.
In RGBA mode, the lighted color of a vertex is the sum of the material emission intensity, the product of the material ambient reflectance and the lighting model full-scene  ambient intensity, and the contribution of each enabled light source. Each light source contributes the sum of three terms: ambient, diffuse, and specular. The ambient light source contribution is the product of the material ambient reflectance and the lights ambient intensity. The diffuse light source contribution is the product of the material diffuse reflectance, the lights diffuse intensity, and the dot product of the vertex's normal with the normalized vector from the vertex to the light source. The specular light source contribution is the product of the material specular reflectance, the lights specular intensity, and the dot product of the normalized vertex-to-eye and vertex-to-light vectors, raised to the power of the shininess of the material. All three light source contributions are attenuated equally based on the distance from the vertex to the light source and on light source direction, spread exponent, and spread cutoff angle. All dot products are replaced with zero if they evaluate to a negative value.
The alpha component of the resulting lighted color is set to the alpha value of the material diffuse reflectance.
In color index mode, the value of the lighted index of a vertex ranges from the ambient to the specular values passed to
glMaterial
 using
GL_COLOR_INDEXES
. Diffuse and specular coefficients, computed with a (.30, .59, .11) weighting of the lights colors, the shininess of the material, and the same reflection and attenuation equations as in the RGBA case, determine how much above ambient the resulting index is.
The following functions retrieve information related to the
glLightModel
function:
glGet
 with argument
GL_LIGHT_MODEL_AMBIENT
glGet
 with argument
GL_LIGHT_MODEL_LOCAL_VIEWER
glGet
 with argument
GL_LIGHT_MODEL_TWO_SIDE
glIsEnabled
 with argument
GL_LIGHTING
Errors
GL_INVALID_ENUM
 is generated if
pname
 is not an accepted value.
GL_INVALID_OPERATION
 is generated if
glLightModel
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glLight
,
glMaterial


glLineStipple
The
glLineStipple
 function specifies the line stipple pattern.
void glLineStipple
(
GLint
factor
,
GLushor
t
pattern
);
Parameters
factor
Specifies a multiplier for each bit in the line stipple pattern. If
factor
 is 3, for example, each bit in the pattern will be used three times before the next bit in the pattern is used.
factor
is clamped to the range [1, 256] and defaults to one.
pattern
Specifies a 16-bit integer whose bit pattern determines which fragments of a line will be drawn when the line is rasterized. Bit zero is used first, and the default pattern is all ones.
Remarks
Line stippling masks out certain fragments produced by rasterization; those fragments will not be drawn. The masking is achieved by using three parameters: the 16-bit line stipple pattern
pattern
,
the repeat count
factor
, and an integer stipple counter
s
.
Counter
s
 is reset to zero whenever
glBegin
 is called, and before each line segment of a
glBegin
(
GL_LINES
)/
glEnd
 sequence is generated. It is incremented after each fragment of a unit width aliased line segment is generated, or after each
i
 fragments of an
i
 width line segment are generated. The
i
 fragments associated with count
s
 are masked out if
pattern
 bit (
s factor
) mod 16 is zero, otherwise these fragments are sent to the frame buffer. Bit zero of
pattern
 is the least significant bit.
Antialiased lines are treated as a sequence of 1x
width
 rectangles for purposes of stippling. Rectangle
s
is rasterized or not based on the fragment rule described for aliased lines, counting rectangles rather than groups of fragments.
Line stippling is enabled or disabled using
glEnable
 and
glDisable
 with argument
GL_LINE_STIPPLE
. When enabled, the line stipple pattern is applied as described above. When disabled, it is as if the pattern were all ones. Initially, line stippling is disabled.
The following functions retrieve information related to the
glLineStipple
 function:
glGet
 with argument
GL_LINE_STIPPLE_PATTERN
glGet
 with argument
GL_LINE_STIPPLE_REPEAT
glIsEnabled
 with argument
GL_LINE_STIPPLE
Errors
GL_INVALID_OPERATION
 is generated if
glLineStipple
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glLineWidth
,
glPolygonStipple


glLineWidth
The
glLineWidth
 function specifies the width of rasterized lines.
void glLineWidth
(
GLfloat
width
);
Parameters
width
Specifies the width of rasterized lines. The default is 1.0.
Remarks
The
glLineWidth
 function specifies the rasterized width of both aliased and antialiased lines. Using a line width other than 1.0 has different effects, depending on whether line antialiasing is enabled. Line antialiasing is controlled by calling
glEnable
 and
glDisable
 with argument
GL_LINE_SMOOTH
.
If line antialiasing is disabled, the actual width is determined by rounding the supplied width to the nearest integer. (If the rounding results in the value 0, it is as if the line width were 1.) If |
D
 x |
³
 |
D
 y |,
i
 pixels are filled in each column that is rasterized, where
i
 is the rounded value of
width
. Otherwise,
i
 pixels are filled in each row that is rasterized.
If antialiasing is enabled, line rasterization produces a fragment for each pixel square that intersects the region lying within the rectangle having width equal to the current line width, length equal to the actual length of the line, and centered on the mathematical line segment. The coverage value for each fragment is the window coordinate area of the intersection of the rectangular region with the corresponding pixel square. This value is saved and used in the final rasterization step.
Not all widths can be supported when line antialiasing is enabled. If an unsupported width is requested, the nearest supported width is used. Only width 1.0 is guaranteed to be supported; others depend on the implementation. The range of supported widths and the size difference between supported widths within the range can be queried by calling
glGet
 with arguments
GL_LINE_WIDTH_RANGE
 and
GL_LINE_WIDTH_GRANULARITY
.
The line width specified by
glLineWidth
 is always returned when
GL_LINE_WIDTH
 is queried. Clamping and rounding for aliased and antialiased lines have no effect on the specified value.
Non-antialiased line width may be clamped to an implementation-dependent maximum. Although this maximum cannot be queried, it must be no less than the maximum value for antialiased lines, rounded to the nearest integer value.
The following functions retrieve information related to the
glLineWidth
 function:
glGet
 with argument
GL_LINE_WIDTH
glGet
 with argument
GL_LINE_WIDTH_RANGE
glGet
 with argument
GL_LINE_WIDTH_GRANULARITY
glIsEnabled
 with argument
GL_LINE_SMOOTH
Errors
GL_INVALID_VALUE
 is generated if
width
 is less than or equal to zero.
GL_INVALID_OPERATION
 is generated if
glLineWidth
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glEnable


glListBase
The
glListBase
 function sets the display-list base for
glCallLists.
void
glListBase
(
GLuint
base
);
Parameters
base
Specifies an integer offset that will be added to
glCallLists
 offsets to generate display-list names. Initial value is zero.
Remarks
The
glListBase
 function specifies an array of offsets. Display-list names are generated by adding
base
 to each offset. Names that reference valid display lists are executed; the others are ignored.
The following function retrieves information related to the
glListBase
 function:
glGet
 with argument
GL_LIST_BASE
Errors
GL_INVALID_OPERATION
 is generated if
glListBase
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glCallLists


glLoadIdentity
The
glLoadIdentity
 function replaces the current matrix with the identity matrix.
void
glLoadIdentity
(
void
);
Remarks
The
glLoadIdentity
 function replaces the current matrix with the identity matrix. It is semantically equivalent to calling
glLoadMatrix
 with the identity matrix
but in some cases it is more efficient.
The following functions retrieve information related to the
glLoadIdentity
 function:
glGet
 with argument
GL_MATRIX_MODE
glGet
 with argument
GL_MODELVIEW_MATRIX
glGet
 with argument
GL_PROJECTION_MATRIX
glGet
 with argument
GL_TEXTURE_MATRIX
Errors
GL_INVALID_OPERATION
 is generated if
glLoadIdentity
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glLoadMatrix
,
glMatrixMode
,
glMultMatrix
,
glPushMatrix


glLoadMatrix
glLoadMatrixd, glLoadMatrixf
The
glLoadMatrixd
and
glLoadMatrixf
 functions replace the current matrix with an arbitrary matrix.
void glLoadMatrixd
(
const GLdouble
*m
);
void glLoadMatrixf
(
const GLfloat
*m
);
Parameters
m
Specifies a pointer to a 4 times 4 matrix stored in column-major order as sixteen consecutive values.
Remarks
The
 glLoadMatrix
 function replaces the current matrix with the one specified in
m
. The current matrix is the projection matrix, modelview matrix, or texture matrix, determined by the current matrix mode (see
glMatrixMode
).
The
 m
parameter
points to a 4x4 matrix of single- or double-precision floating-point values stored in column-major order. That is, the matrix is stored as follows:
The following functions retrieve information related to the
glLoadMatrix
 function:
glGet
 with argument
GL_MATRIX_MODE
glGet
 with argument
 GL_MODELVIEW_MATRIX
glGet
 with argument
 GL_PROJECTION_MATRIX
glGet
 with argument
GL_TEXTURE_MATRIX
Errors
GL_INVALID_OPERATION
 is generated if
glLoadMatrix
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glLoadIdentity
,
glMatrixMode
,
glMultMatrix
,
glPushMatrix


glLoadName
The
glLoadName
 function loads a name onto the name stack.
void
glLoadName
(
GLuint
name
);
Parameters
name
Specifies a name that will replace the top value on the name stack.
Remarks
The name stack is used during selection mode to allow sets of rendering commands to be uniquely identified. It consists of an ordered set of unsigned integers. The
glLoadName
 function causes
name
 to replace the value on the top of the name stack, which is initially empty.
The name stack is always empty while the render mode is not
GL_SELECT
. Calls to
glLoadName
 while the render mode is not
GL_SELECT
 are ignored.
The following functions retrieve information related to the
glLoadName
 function:
glGet
 with argument
GL_NAME_STACK_DEPTH
glGet
 with argument
GL_MAX_NAME_STACK_DEPTH
Errors
GL_INVALID_OPERATION
 is generated if
glLoadName
 is called while the name stack is empty.
GL_INVALID_OPERATION
 is generated if
glLoadName
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glInitNames
,
glPushName
,
glRenderMode
,
glSelectBuffer


glLogicOp
The
glLogicOp
 function specifies a logical pixel operation for color index rendering.
void glLogicOp
(
GLenum
opcode
);
Parameters
opcode
Specifies a symbolic constant that selects a logical operation. The following symbols are accepted:
GL_CLEAR, GL_SET, GL_COPY, GL_COPY_INVERTED, GL_NOOP, GL_INVERT, GL_AND, GL_NAND, GL_OR, GL_NOR, GL_XOR, GL_EQUIV, GL_AND_REVERSE, GL_AND_INVERTED, GL_OR_REVERSE,
 and
GL_OR_INVERTED
.
Remarks
The
glLogicOp
 function specifies a logical operation that, when enabled, is applied between the incoming color index and the color index at the corresponding location in the frame buffer. The logical operation is enabled or disabled with
glEnable
 and
glDisable
 using the symbolic constant
GL_LOGIC_OP
.
The
 opcode
 parameter is a symbolic constant chosen from the list below. In the explanation of the logical operations,
s
 represents the incoming color index and
d
 represents the index in the frame buffer. Standard C-language operators are used. As these bitwise operators suggest, the logical operation is applied independently to each bit pair of the source and destination indices.
Opcode
Resulting Value
GL_CLEAR
0
GL_SET
1
GL_COPY
s
GL_COPY_INVERTED
!s
GL_NOOP
d
GL_INVERT
!d
GL_AND
s & d
GL_NAND
!(s & d)
GL_OR
s | d
GL_NOR
!(s | d)
GL_XOR
s ^ d
GL_EQUIV
!(s ^ d)
GL_AND_REVERSE
s & !d
GL_AND_INVERTED
!s & d
GL_OR_REVERSE
s | !d
GL_OR_INVERTED
!s | d
Logical pixel operations are not applied to RGBA color buffers.
When more than one color index buffer is enabled for drawing, logical operations are done separately for each enabled buffer, using for the destination index the contents of that buffer (see
glDrawBuffer
).
The
 opcode
 parameter must be one of the sixteen accepted values. Other values result in an error.
The following functions retrieve information related to the
glLogicOp
 function:
glGet
 with argument
GL_LOGIC_OP_MODE
glIsEnabled
 with argument
GL_LOGIC_OP
Errors
GL_INVALID_ENUM
 is generated if
opcode
 is not an accepted value.
GL_INVALID_OPERATION
 is generated if
glLogicOp
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glAlphaFunc
,
glBlendFunc
,
glDrawBuffer
,
glEnable
,
glStencilOp


glMap1
glMap1d, glMap1f
The
glMap1d
 and
glMap1f
functions define a one-dimensional evaluator.
void
glMap1d
(
GLenum
target
,
GLdouble
u1
,
GLdouble
u2
,
GLint
stride
,
GLint
order
,
const GLdouble
*points
);
void
glMap1f
(
GLenum
target
,
GLfloat
u1
,
GLfloat
u2
,
GLint
stride
,
GLint
order
,
const GLfloat
*points
);
Parameters
target
Specifies the kind of values that are generated by the evaluator. Symbolic constants
GL_MAP1_VERTEX_3, GL_MAP1_VERTEX_4, GL_MAP1_INDEX, GL_MAP1_COLOR_4, GL_MAP1_NORMAL, GL_MAP1_TEXTURE_COORD_1,
GL_MAP1_TEXTURE_COORD_2
,
GL_MAP1_TEXTURE_COORD_3
, and
GL_MAP1_TEXTURE_COORD_4
 are accepted.
u1, u2
Specify a linear mapping of u, as presented to
glEvalCoord1
, to
û
, the variable that is evaluated by the equations specified by this command.
stride
Specifies the number of floats or doubles between the beginning of one control point and the beginning of the next one in the data structure referenced in
points
. This allows control points to be embedded in arbitrary data structures. The only constraint is that the values for a particular control point must occupy contiguous memory locations.
order
Specifies the number of control points. Must be positive.
points
Specifies a pointer to the array of control points.
Remarks
Evaluators provide a way to use polynomial or rational polynomial mapping to produce vertexes, normals, texture coordinates, and colors. The values produced by an evaluator are sent to further stages of GL processing just as if they had been presented using
glVertex
,
glNormal
,
glTexCoord
, and
glColor
 commands, except that the generated values do not update the current normal, texture coordinates, or color.
All polynomial or rational polynomial splines of any degree (up to the maximum degree supported by the GL implementation) can be described using evaluators. These include almost all splines used in computer graphics, including B-splines, Bezier curves, Hermite splines, and so on.
Evaluators define curves based on Bernstein polynomials. Define
p
(
û
)  as
where
R
 (i)
 is a control point and
(
û
) is the
i
th Bernstein polynomial of degree
n
 (
order
 =
n
 + 1):
Recall that
The
 glMap1
 function is used to define the basis and to specify what kind of values are produced. Once defined, a map can be enabled and disabled by calling
glEnable
 and
glDisable
 with the map name, one of the nine predefined values for
target
 described below.
glEvalCoord1
 evaluates the one-dimensional maps that are enabled. When
glEvalCoord1
 presents a value
u
, the Bernstein functions are evaluated using
û
, where
The
 target
 parameter is a symbolic constant that indicates what kind of control points are provided in
points
, and what output is generated when the map is evaluated. It can assume one of nine predefined values:
GL_MAP1_VERTEX_3
Each control point is three floating-point values representing
x, y,
 and
z
. Internal
glVertex3
 commands are generated when the map is evaluated.
GL_MAP1_VERTEX_4
Each control point is four floating-point values representing
 x, y, z,
 and
w
. Internal
glVertex4
 commands are generated when the map is evaluated.
GL_MAP1_INDEX
Each control point is a single floating-point value representing a color index. Internal
glIndex
 commands are generated when the map is evaluated. The current index is not updated with the value of these
glIndex
 commands, however.
GL_MAP1_COLOR_4
Each control point is four floating-point values representing red, green, blue, and alpha. Internal
glColor4
 commands are generated when the map is evaluated. The current color is not updated with the value of these
glColor4
 commands, however.
GL_MAP1_NORMAL
Each control point is three floating-point values representing the
x, y,
 and
z
 components of a normal vector. Internal
glNormal
 commands are generated when the map is evaluated. The current normal is not updated with the value of these
glNormal
 commands, however.
GL_MAP1_TEXTURE_COORD_1
Each control point is a single floating-point value representing the
s
 texture coordinate. Internal
glTexCoord1
 commands are generated when the map is evaluated. The current texture coordinates are not updated with the value of these
glTexCoord
 commands, however.
GL_MAP1_TEXTURE_COORD_2
Each control point is two floating-point values representing the
s
 and
t
 texture coordinates. Internal
glTexCoord2
 commands are generated when the map is evaluated. The current texture coordinates are not updated with the value of these
glTexCoord
 commands, however.
GL_MAP1_TEXTURE_COORD_3
Each control point is three floating-point values representing the
s, t,
 and
r
 texture coordinates. Internal
glTexCoord3
 commands are generated when the map is evaluated. The current texture coordinates are not updated with the value of these
glTexCoord
 commands, however.
GL_MAP1_TEXTURE_COORD_4
Each control point is four floating-point values representing the
s, t, r,
and
q
 texture coordinates. Internal
glTexCoord4
 commands are generated when the map is evaluated. The current texture coordinates are not updated with the value of these
glTexCoord
 commands, however.
The
stride
,
order
, and
points
 parameters define the array addressing for accessing the control points.
points
 is the location of the first control point, which occupies one, two, three, or four contiguous memory locations, depending on which map is being defined.
order
 is the number of control points in the array.
stride
 tells how many float or double locations to advance the internal memory pointer to reach the next control point.
As is the case with all GL commands that accept pointers to data, it is as if the contents of
points
 were copied by
glMap1
 before it returned. Changes to the contents of
points
 have no effect after
glMap1
 is called.
The following functions retrieve information related to the
glMap1
 function:
glGetMap
glGet
 with argument
GL_MAX_EVAL_ORDER
glIsEnabled
 with argument
GL_MAP1_VERTEX_3
glIsEnabled
 with argument
GL_MAP1_VERTEX_4
glIsEnabled
 with argument
GL_MAP1_INDEX
glIsEnabled
 with argument
GL_MAP1_COLOR_4
glIsEnabled
 with argument
GL_MAP1_NORMAL
glIsEnabled
 with argument
GL_MAP1_TEXTURE_COORD_1
glIsEnabled
 with argument
GL_MAP1_TEXTURE_COORD_2
glIsEnabled
 with argument
GL_MAP1_TEXTURE_COORD_3
glIsEnabled
 with argument
GL_MAP1_TEXTURE_COORD_4
Errors
GL_INVALID_ENUM
 is generated if
target
 is not an accepted value.
GL_INVALID_VALUE
 is generated if
u1
 is equal to
u2
.
GL_INVALID_VALUE
 is generated if
stride
 is less than the number of values in a control point.
GL_INVALID_VALUE
 is generated if
order
 is less than one or greater than
GL_MAX_EVAL_ORDER
.
GL_INVALID_OPERATION
 is generated if
glMap1
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glBegin
,
glColor
,
glEnable
,
glEvalCoord
,
glEvalMesh
,
glEvalPoint
,
glMap2
,
glMapGrid
,
glNormal
,
glTexCoord
,
glVertex


glMap2
glMap2d, glMap2f
The
glMap2d
 and
glMap2f
 functions define a two-dimensional evaluator.
void glMap2d
(
GLenum
target
,
GLdouble
u1
,
GLdouble
u2
,
GLint
ustride
,
GLint
uorder
,
GLdouble
v1
,
GLdouble
v2
,
GLint
vstride
,
GLint
vorder
,
const GLdouble
*points
);
void glMap2f
(
GLenum
target
,
GLfloat
u1
,
GLfloat
u2
,
GLint
ustride
,
GLint
uorder
,
GLfloat
v1
,
GLfloat
v2
,
GLint
vstride
,
GLint
vorder
,
const GLfloat
*points
);
Parameters
target
Specifies the kind of values that are generated by the evaluator. Symbolic constants
GL_MAP2_VERTEX_3, GL_MAP2_VERTEX_4, GL_MAP2_INDEX, GL_MAP2_COLOR_4, GL_MAP2_NORMAL, GL_MAP2_TEXTURE_COORD_1,
GL_MAP2_TEXTURE_COORD_2
,
GL_MAP2_TEXTURE_COORD_3
, and
GL_MAP2_TEXTURE_COORD_4
 are accepted.
u1, u2
Specify a linear mapping of
u
, as presented to
glEvalCoord2
, to
û
, one of the two variables that is evaluated by the equations specified by this command.
ustride
Specifies the number of floats or doubles between the beginning of control point
R
 (ij)
 and the beginning of control point
R
(
i
+1)
j
, where
i
 and
 j
 are the
u
 and
v
 control point indices, respectively. This allows control points to be embedded in arbitrary data structures. The only constraint is that the values for a particular control point must occupy contiguous memory locations.
uorder
Specifies the dimension of the control point array in the
u
 axis. Must be positive.
v1, v2
Specify a linear mapping of
v
, as presented to
glEvalCoord2
, to
, one of the two variables that is evaluated by the equations specified by this command.
vstride
Specifies the number of floats or doubles between the beginning of control point
R
 (ij)
 and the beginning of control point
R
 (i
(
j
+1)
)
, where
i
 and
j
 are the
u
 and
v
 control point indices, respectively. This allows control points to be embedded in arbitrary data structures. The only constraint is that the values for a particular control point must occupy contiguous memory locations.
vorder
Specifies the dimension of the control point array in the
v
 axis. Must be positive.
points
Specifies a pointer to the array of control points.
Remarks
Evaluators provide a way to use polynomial or rational polynomial mapping to produce vertexes, normals, texture coordinates, and colors. The values produced by an evaluator are sent on to further stages of GL processing just as if they had been presented using
glVertex
,
glNormal
,
glTexCoord
, and
glColor
 commands, except that the generated values do not update the current normal, texture coordinates, or color.
All polynomial or rational polynomial splines of any degree (up to the maximum degree supported by the GL implementation) can be described using evaluators. These include almost all surfaces used in computer graphics, including B-spline surfaces, NURBS surfaces, Bezier surfaces, and so on.
Evaluators define surfaces based on bivariate Bernstein polynomials. Define
p
(
û,
) as
where
R
 (ij)
 is a control point,
 (
û
) is the
i
th Bernstein polynomial of degree
n
 (
uorder
 =
n
 + 1)
and (
) is the
 j
th Bernstein polynomial of degree
m
 (
vorder
 =
m
 + 1)
Recall that
The
 glMap2
 function is used to define the basis and to specify what kind of values are produced. Once defined, a map can be enabled and disabled by calling
glEnable
 and
glDisable
 with the map name, one of the nine predefined values for
target
, described below. When
glEvalCoord2
 presents values
u
 and
v
, the bivariate Bernstein polynomials are evaluated using
û
 and
, where
The
 target
 parameter is a symbolic constant that indicates what kind of control points are provided in
points
, and what output is generated when the map is evaluated. It can assume one of nine predefined values:
GL_MAP2_VERTEX_3
Each control point is three floating-point values representing
x, y,
and
z
. Internal
glVertex3
 commands are generated when the map is evaluated.
GL_MAP2_VERTEX_4
Each control point is four floating-point values representing
x, y, z,
 and
w
. Internal
glVertex4
 commands are generated when the map is evaluated.
GL_MAP2_INDEX
Each control point is a single floating-point value representing a color index. Internal
glIndex
 commands are generated when the map is evaluated. The current index is not updated with the value of these
glIndex
 commands, however.
GL_MAP2_COLOR_4
Each control point is four floating-point values representing red, green, blue, and alpha. Internal
glColor4
 commands are generated when the map is evaluated. The current color is not updated with the value of these
glColor4
 commands, however.
GL_MAP2_NORMAL
Each control point is three floating-point values representing the
x, y,
 and
z
 components of a normal vector. Internal
glNormal
 commands are generated when the map is evaluated. The current normal is not updated with the value of these
glNormal
 commands, however.
GL_MAP2_TEXTURE_COORD_1
Each control point is a single floating-point value representing the
s
 texture coordinate. Internal
glTexCoord1
 commands are generated when the map is evaluated. The current texture coordinates are not updated with the value of these
glTexCoord
 commands, however.
GL_MAP2_TEXTURE_COORD_2
Each control point is two floating-point values representing the
s
 and
t
 texture coordinates. Internal
glTexCoord2
 commands are generated when the map is evaluated. The current texture coordinates are not updated with the value of these
glTexCoord
 commands, however.
GL_MAP2_TEXTURE_COORD_3
Each control point is three floating-point values representing the
s, t,
 and
r
texture coordinates. Internal
glTexCoord3
 commands are generated when the map is evaluated. The current texture coordinates are not updated with the value of these
glTexCoord
 commands, however.
GL_MAP2_TEXTURE_COORD_4
Each control point is four floating-point values representing the
s, t, r,
 and
q
 texture coordinates. Internal
glTexCoord4
 commands are generated when the map is evaluated. The current texture coordinates are not updated with the value of these
glTexCoord
 commands, however.
The
 ustride
,
uorder
,
vstride
,
vorder
, and
points
 parameters define the array addressing for accessing the control points.
points
 is the location of the first control point, which occupies one, two, three, or four contiguous memory locations, depending on which map is being defined. There are
uorder
x
vorder
 control points in the array.
ustride
 tells how many float or double locations are skipped to advance the internal memory pointer from control point
R
 ((i j))
 to control point
R
 ((
i
+1)
j
)
 .
vstride
 tells how many float or double locations are skipped to advance the internal memory pointer from control point
R
 ((i j))
 to control point
R
 ((
i
(
j
+1))
.
As is the case with all GL commands that accept pointers to data, it is as if the contents of
points
 were copied by
glMap2
 before it returned. Changes to the contents of
points
 have no effect after
glMap2
 is called.
The following functions retrieve information related to the
glMap2
 function:
glGetMap
glGet
 with argument
GL_MAX_EVAL_ORDER
glIsEnabled
 with argument
GL_MAP2_VERTEX_3
glIsEnabled
 with argument
GL_MAP2_VERTEX_4
glIsEnabled
 with argument
GL_MAP2_INDEX
glIsEnabled
 with argument
GL_MAP2_COLOR_4
glIsEnabled
 with argument
GL_MAP2_NORMAL
glIsEnabled
 with argument
GL_MAP2_TEXTURE_COORD_1
glIsEnabled
 with argument
GL_MAP2_TEXTURE_COORD_2
glIsEnabled
 with argument
GL_MAP2_TEXTURE_COORD_3
glIsEnabled
 with argument
GL_MAP2_TEXTURE_COORD_4
Errors
GL_INVALID_ENUM
 is generated if
target
 is not an accepted value.
GL_INVALID_VALUE
 is generated if
u1
 is equal to
u2
, or if
v1
 is equal to
v2
.
GL_INVALID_VALUE
 is generated if either
ustride
 or
vstride
 is less than the number of values in a control point.
GL_INVALID_VALUE
 is generated if either
uorder
 or
vorder
 is less than one or greater than
GL_MAX_EVAL_ORDER
.
GL_INVALID_OPERATION
 is generated if
glMap2
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glBegin
,
glColor
,
glEnable
,
glEvalCoord
,
glEvalMesh
,
glEvalPoint
,
glMap1
,
glMapGrid
,
glNormal
,
glTexCoord
,
glVertex


glMapGrid
glMapGrid1d, glMapGrid1f, glMapGrid2d, glMapGrid2f
These functions define a one- or two-dimensional mesh.
void
glMapGrid1d
(
GLint
un
,
GLdouble
u1
,
GLdouble
u2
);
void glMapGrid1f
(
GLint
un
,
GLfloat
u1
,
GLfloat
u2
);
void glMapGrid2d
(
GLint
un
,
GLdouble
u1
,
GLdouble
u2
,
GLint
vn
,
GLdouble
v1
,
GLdouble
v2
);
void glMapGrid2f
(
GLint
un
,
GLfloat
u1
,
GLfloat
u2
,
GLint
vn
,
GLfloat
v1
,
GLfloat
v2
);
Parameters
un
Specifies the number of partitions in the grid range interval [
u1
,
u2
]. Must be positive.
u1, u2
Specify the mappings for integer grid domain values
i
= 0 and
i
=
un
.
vn
Specifies the number of partitions in the grid range interval [
v1
,
v2
] (
glMapGrid2
 only).
v1, v2
Specify the mappings for integer grid domain values
j
 = 0 and
 j
 =
vn
 (
glMapGrid2
 only).
Remarks
The
glMapGrid
 and
glEvalMesh
 functions are used in tandem to efficiently generate and evaluate a series of evenly spaced map domain values.
glEvalMesh
 steps through the integer domain of a one- or two-dimensional grid, whose range is the domain of the evaluation maps specified by
glMap1
 and
glMap2
.
The
glMapGrid1
 and
glMapGrid2
 functions specify the linear grid mappings between the
i
 (or
i
 and
j
) integer grid coordinates, to the
u
 (or
u
 and
v
) floating-point evaluation map coordinates. See
glMap1
 and
glMap2
 for details of how
u
 and
v
 coordinates are evaluated.
The
glMapGrid1
 function specifies a single linear mapping such that integer grid coordinate 0 maps exactly to
u1
, and integer grid coordinate
un
 maps exactly to
u2
. All other integer grid coordinates i are mapped such that
u =
i
(
u
2
-
u
1)/
un
 +
u1
The
 glMapGrid2
 function specifies two such linear mappings. One maps integer grid coordinate
i
= 0 exactly to
u1
, and integer grid coordinate
i
=
un
 exactly to
u2
. The other maps integer grid coordinate
j
= 0 exactly to
v1
, and integer grid coordinate
j
=
vn
 exactly to
v2
. Other integer grid coordinates
i
 and
j
 are mapped such that
u
 =
i
(
u
2
-
u
1)/
un
 +
u
1
v
 =
j
 (
v
2
-
v
1)/
vn
 +
v
1
The mappings specified by
glMapGrid
 are used identically by
glEvalMesh
 and
glEvalPoint
.
The following functions retrieve information related to the
glMapGrid
 function:
glGet
 with argument
GL_MAP1_GRID_DOMAIN
glGet
 with argument
GL_MAP2_GRID_DOMAIN
glGet
 with argument
GL_MAP1_GRID_SEGMENTS
glGet
 with argument
GL_MAP2_GRID_SEGMENTS
Errors
GL_INVALID_VALUE
 is generated if either
un
 or
vn
 is not positive.
GL_INVALID_OPERATION
 is generated if
glMapGrid
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glEvalCoord
,
glEvalMesh
,
glEvalPoint
,
glMap1
,
glMap2


glMaterial
glMaterialf, glMateriali, glMaterialfv, glMaterialiv
These functions specify material parameters for the lighting model.
void
glMaterialf
(
GLenum
face
,
GLenum
pname
,
GLfloat
param
);
void glMateriali
(
GLenum
face
,
GLenum
pname
,
GLint
param
);
Parameters
face
Specifies which face or faces are being updated. Must be one of
GL_FRONT
,
GL_BACK
, or
GL_FRONT_AND_BACK
.
pname
Specifies the single-valued material parameter of the face or faces that is being updated. Must be
GL_SHININESS
.
param
Specifies the value that parameter
GL_SHININESS
 will be set to.
void glMaterialfv
(
GLenum
face
,
GLenum
pname
,
const GLfloat
*params
);
void glMaterialiv
(
GLenum
face
,
GLenum
pname
,
const GLint
*params
);
Parameters
face
Specifies which face or faces are being updated. Must be one of
GL_FRONT
,
GL_BACK
, or
GL_FRONT_AND_BACK
.
pname
Specifies the material parameter of the face or faces that is being updated. Must be one of
GL_AMBIENT
,
GL_DIFFUSE
,
GL_SPECULAR
,
GL_EMISSION
,
GL_SHININESS
,
GL_AMBIENT_AND_DIFFUSE
, or
GL_COLOR_INDEXES
.
params
Specifies a pointer to the value or values to which
pname
 will be set.
Remarks
The
glMaterial
 function assigns values to material parameters. There are two matched sets of material parameters. One, the
front-facing
 set, is used to shade points, lines, bitmaps, and all polygons (when two-sided lighting is disabled), or just front-facing polygons (when two-sided lighting is enabled). The other set,
back-facing
, is used to shade back-facing polygons only when two-sided lighting is enabled. Refer to the
glLightModel
 reference page for details concerning one- and two-sided lighting calculations.
The
glMaterial
 function takes three arguments. The first,
face
, specifies whether the
GL_FRONT
 materials, the
GL_BACK
 materials, or both
GL_FRONT_AND_BACK
 materials will be modified. The second,
pname
, specifies which of several parameters in one or both sets will be modified. The third,
params
, specifies what value or values will be assigned to the specified parameter.
Material parameters are used in the lighting equation that is optionally applied to each vertex. The equation is discussed in
glLightModel
. The parameters that can be specified using
glMaterial
, and their interpretations by the lighting equation, are as follows:
GL_AMBIENT
The
 params
 parameter contains four integer or floating-point values that specify the ambient RGBA reflectance of the material. Integer values are mapped linearly such that the most positive representable value maps to 1.0, and the most negative representable value maps to
-
1.0. Floating-point values are mapped directly. Neither integer nor floating-point values are clamped. The default ambient reflectance for both front- and back-facing materials is (0.2, 0.2, 0.2, 1.0).
GL_DIFFUSE
The
 params
 parameter contains four integer or floating-point values that specify the diffuse RGBA reflectance of the material. Integer values are mapped linearly such that the most positive representable value maps to 1.0, and the most negative representable value maps to
-
1.0. Floating-point values are mapped directly. Neither integer nor floating-point values are clamped. The default diffuse reflectance for both front- and back-facing materials is (0.8, 0.8, 0.8, 1.0).
GL_SPECULAR
The
 params
 parameter contains four integer or floating-point values that specify the specular RGBA reflectance of the material. Integer values are mapped linearly such that the most positive representable value maps to 1.0, and the most negative representable value maps to
-
1.0. Floating-point values are mapped directly. Neither integer nor floating-point values are clamped. The default specular reflectance for both front- and back-facing materials is (0.0, 0.0, 0.0, 1.0).
GL_EMISSION
The
 params
 parameter contains four integer or floating-point values that specify the RGBA emitted light intensity of the material. Integer values are mapped linearly such that the most positive representable value maps to 1.0, and the most negative representable value maps to
-
1.0. Floating-point values are mapped directly. Neither integer nor floating-point values are clamped. The default emission intensity for both front- and back-facing materials is (0.0, 0.0, 0.0, 1.0).
GL_SHININESS
The
 params
 parameter is a single integer or floating-point value that specifies the RGBA specular exponent of the material. Integer and floating-point values are mapped directly. Only values in the range [0,128] are accepted. The default specular exponent for both front- and back-facing materials is 0.
GL_AMBIENT_AND_DIFFUSE
Equivalent to calling
glMaterial
 twice with the same parameter values, once with
GL_AMBIENT
 and once with
GL_DIFFUSE
.
GL_COLOR_INDEXES
The
 params
 parameter contains three integer or floating-point values specifying the color indices for ambient, diffuse, and specular lighting. These three values, and
GL_SHININESS
, are the only material values used by the color index mode lighting equation. Refer to
glLightModel
 for a discussion of color index lighting.
The material parameters can be updated at any time. In particular,
glMaterial
 can be called between a call to
glBegin
 and the corresponding call to
glEnd
. If only a single material parameter is to be changed per vertex, however,
glColorMaterial
 is preferred over
glMaterial
.
The following function retrieves information related to the
glMaterial
 function:
glGetMaterial
Errors
GL_INVALID_ENUM
 is generated if either
face
 or
pname
 is not an accepted value.
GL_INVALID_VALUE
 is generated if a specular exponent outside the range [0,128] is specified.
See Also
glColorMaterial
,
glLight
,
glLightModel


glMatrixMode
The
glMatixMode
 function specifies which matrix is the current matrix.
void glMatrixMode
(
GLenum
mode
);
Parameters
mode
Specifies which matrix stack is the target for subsequent matrix operations. Three values are accepted:
GL_MODELVIEW
,
GL_PROJECTION
, and
GL_TEXTURE
.
Remarks
The
glMatixMode
 function sets the current matrix mode. The
mode
 parameter can assume one of three values:
GL_MODELVIEW
Applies subsequent matrix operations to the modelview matrix stack.
GL_PROJECTION
Applies subsequent matrix operations to the projection matrix stack.
GL_TEXTURE
Applies subsequent matrix operations to the texture matrix stack.
The following function retrieves information related to the
glMatrixMode
 function:
glGet
 with argument
GL_MATRIX_MODE
Errors
GL_INVALID_ENUM
 is generated if
mode
 is not an accepted value.
GL_INVALID_OPERATION
 is generated if
glMatrixMode
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glLoadMatrix
,
glPushMatrix


glMultMatrix
glMultMatrixd, glMultMatrixf
The
glMultMatrixd
 and
glMultMatrixf
 functions multiply the current matrix by an arbitrary matrix.
void glMultMatrixd
(
const GLdouble
*m
);
void glMultMatrixf
(
const GLfloat
*m
);
Parameters
m
Specifies a pointer a to 4x4 matrix stored in column-major order as sixteen consecutive values.
Remarks
The
glMultMatrix
 function multiplies the current matrix with the one specified in
m
. That is, if M is the current matrix and T is the matrix passed to
glMultMatrix
, then M is replaced with M
·
 T.
The current matrix is the projection matrix, modelview matrix, or texture matrix, determined by the current matrix mode (see
glMatrixMode
).
The
 m
 parameter points to a 4x4 matrix of single- or double-precision floating-point values stored in column-major order. That is, the matrix is stored as
The following functions retrieve information related to the
glMultMatrix
function:
glGet
 with argument
GL_MATRIX_MODE
glGet
 with argument
GL_MODELVIEW_MATRIX
glGet
 with argument
GL_PROJECTION_MATRIX
glGet
 with argument
GL_TEXTURE_MATRIX
Errors
GL_INVALID_OPERATION
 is generated if
glMultMatrix
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glMatrixMode
,
glLoadIdentity
,
glLoadMatrix
,
glPushMatrix


glNewList
glNewList, glEndList
The
glNewList
 and
glEndList
 functions create or replace a display list.
void
glNewList
(
GLuint
list
,
GLenum
mode
);
void
glEndList
(
void
);
Parameters
list
Specifies the display list name.
mode
Specifies the compilation mode, which can be
GL_COMPILE
 or
GL_COMPILE_AND_EXECUTE
.
Remarks
Display lists are groups of GL commands that have been stored for subsequent execution. The display lists are created with
glNewList
. All subsequent commands are placed in the display list, in the order issued, until
glEndList
 is called.
The
glNewList
 function has two arguments. The first argument,
list
, is a positive integer that becomes the unique name for the display list. Names can be created and reserved with
glGenLists
 and tested for uniqueness with
glIsList
. The second argument,
mode
, is a symbolic constant that can assume one of two values:
GL_COMPILE
 Commands are merely compiled.
GL_COMPILE_AND_EXECUTE
 Commands are executed as they are compiled into the display list.
Certain commands are not compiled into the display list, but are executed immediately, regardless of the display-list mode. These commands are
glIsList
,
glGenLists
,
glDeleteLists
,
glFeedbackBuffer
,
glSelectBuffer
,
glRenderMode
,
glReadPixels
,
glPixelStore
,
glFlush
,
glFinish
,
glIsEnabled
, and all of the
glGet
 routines.
When the
glNewList
 function is encountered, the display-list definition is completed by associating the list with the unique name
list
 (specified in the
glNewList
 command). If a display list with name
list
 already exists, it is replaced only when
glEndList
 is called.
glCallList
 and
glCallLists
 can be entered into display lists. The commands in the display list or lists executed by
glCallList
 or
glCallLists
 are not included in the display list being created, even if the list creation mode is
GL_COMPILE_AND_EXECUTE
.
The following function retrieves information related to the
glNewList
 function:
glGet
 with argument
GL_MATRIX_MODE
Errors
GL_INVALID_VALUE
 is generated if
list
 is zero.
GL_INVALID_ENUM
 is generated if
mode
 is not an accepted value.
GL_INVALID_OPERATION
 is generated if
glEndList
 is called without a preceding
glNewList
, or if
glNewList
 is called while a display list is being defined.
GL_INVALID_OPERATION
 is generated if
glNewList
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glCallList
,
glCallLists
,
glDeleteLists
,
glGenLists
,
glIsList


glNormal
glNormal3b, glNormal3d, glNormal3f, glNormal3i, glNormal3s, glNormal3bv, glNormal3dv, glNormal3fv, glNormal3iv, glNormal3sv
These functions set the current normal vector.
void glNormal3b
(
GLbyte
nx
,
GLbyte
ny
,
GLbyte
nz
);
void glNormal3d
(
GLdouble
nx
,
GLdouble
ny
,
GLdouble
nz
);
void glNormal3f
(
GLfloat
nx
,
GLfloat
ny
,
GLfloat
nz
);
void glNormal3i
(
GLint
nx
,
GLint
ny
,
GLint
nz
);
void glNormal3s
(
GLshort
nx
,
GLshort
ny
,
GLshort
nz
);
Parameters
nx, ny, nz
Specify the
x, y,
 and
z
 coordinates of the new current normal. The initial value of the current normal is (0,0,1).
void glNormal3bv
(
const GLbyte
*v
);
void glNormal3dv
(
const GLdouble
*v
);
void glNormal3fv
(
const GLfloat
*v
);
void
glNormal3iv
(
const GLint
*v
);
void
glNormal3sv
(
const GLshort
*v
);
Parameters
v
Specifies a pointer to an array of three elements:
the
x, y,
 and
z
 coordinates of the new current normal.
Remarks
The current normal is set to the given coordinates whenever
glNormal
 is issued. Byte, short, or integer arguments are converted to floating-point format with a linear mapping that maps the most positive representable integer value to 1.0, and the most negative representable integer value to
-
1.0.
Normals specified with
glNormal
 need not have unit length. If normalization is enabled, then normals specified with
glNormal
 are normalized after transformation. Normalization is controlled using
glEnable
 and
glDisable
 with the argument
GL_NORMALIZE
. By default, normalization is disabled.
The current normal can be updated at any time. In particular,
glNormal
 can be called between a call to
glBegin
 and the corresponding call to
glEnd
.
The following functions retrieve information related to the
glNormal
 function:
glGet
 with argument
GL_CURRENT_NORMAL
glIsEnable
 with argument
GL_NORMALIZE
See Also
glBegin
,
glColor
,
glIndex
,
glTexCoord
,
glVertex


glNormalPointerEXT
The
glNormalPointerEXT
 function defines an array of normals.
void glNormalPointerEXT
(
GLenum
type
,
GLsizei
stride
,
GLsizei
count
,
const GLvoid
*
pointer
);
Parameters
type
Specifies the datatype of each coordinate in the array using the following symbolic constants:
GL_BYTE
,
GL_SHORT
,
GL_INT
,
GL_FLOAT
, and
GL_DOUBLE_EXT
.
stride
Specifies the byte offset between consecutive normals. When
stride
 is zero, the normals are tightly packed in the array.
count
Specifies the number of normals, counting from the first, that are static.
pointer
Specifies a pointer to the first normal in the array.
Remarks
The
 glNormalPointerEXT
 function specifies the location and data of an array of normals to use when rendering. The
type
 parameter specifies the datatype of each normal coordinate and
stride
 determines the byte offset from one normal to the next, enabling the packing of vertexes and attributes in a single array or storage in separate arrays. In some implementations storing the vertexes and attributes in a single array can be more efficient than using separate arrays. Starting from the first normal element,
count
 indicates the total number of static elements. Your application can modify static elements, but once the elements are modified, the application must explicitly specify the array again before using the array for any rendering. Non-static array elements are not accessed until you call
glDrawArraysEXT
 or
glArrayElementEXT
.
A normal arrays is enabled when you specify the
 GL_NORMAL_ARRAY_EXT
constant with
glEnable
. When enabled,
glDrawArraysEXT
 and
glArrayElementEXT
 use the normal array. By default the normal array is disabled.
You cannot include
glNormalPointerEXT
 in display lists.
When you specify a normal array using
glNormalPointerEXT
, the values of all the function's normal array parameters are saved in a client-side state and static array elements can be cached. Because the normal array parameters are client-side state, their values are not saved or restored by
glPushAttrib
 and
glPopAttrib
.
Although no error is generated when you call
glNormalPointerEXT
 within
glBegin
 and
glEnd
 pairs, the results are undefined.
Note
Note
  The
 glNormalPointerEXT
 function is an extension function that is not part of the standard OpenGL library but is part of the
GL_EXT_vertex_array
 extension. To check whether your implementation of OpenGL supports
glNormalPointerEXT
, call
glGetString
(
GL_EXTENSIONS
). If it returns
GL_EXT_vertex_array
,
glNormalPointerEXT
 is supported.
To obtain the address of an extension function, call
wglGetProcAddress
.
The following functions are associated with the
glNormalPointerEXT
 function:
glIsEnabled
 with argument
GL_NORMAL_ARRAY_EXT
glGet
 with argument
GL_NORMAL_ARRAY_STRIDE_EXT
glGet
 with argument
GL_NORMAL_ARRAY_COUNT_EXT
glGet
 with argument
GL_NORMAL_ARRAY_TYPE_EXT
glGetPointervEXT
 with argument
GL_NORMAL_ARRAY_POINTER_EXT
Errors
GL_INVALID_ENUM
 is generated if
type
 is not an accepted value.
GL_INVALID_VALUE
 is generated if
stride
 or
count
 is negative.
See Also
glArrayElementEXT
,
glColorPointerEXT
,
glDrawArraysEXT
,
glEdgeFlagPointerEXT
,
glGetPointervEXT
,
glIndexPointerEXT
,
glTexCoordPointerEXT
,
glVertexPointerEXT
,
glGetString
,
wglGetProcAddress


glOrtho
The
glOrtho
 function multiplies the current matrix by an orthographic matrix.
void glOrtho
(
GLdouble
left
,
GLdouble
right
,
GLdouble
bottom
,
GLdouble
top
,
GLdouble
near
,
GLdouble
far
);
Parameters
left, right
Specify the coordinates for the left and right vertical clipping planes.
bottom, top
Specify the coordinates for the bottom and top horizontal clipping planes.
near, far
Specify the distances to the nearer and farther depth clipping planes. These distances are negative if the plane is to be behind the viewer.
Remarks
The
glOrtho
 function describes a perspective matrix that produces a parallel projection. (
left
,
bottom
,
-
near
) and (
right
,
top
,
-
near
) specify the points on the near clipping plane that are mapped to the lower left and upper right corners of the window, respectively, assuming that the eye is located at (0, 0, 0).
-
far
 specifies the location of the far clipping plane. Both
near
 and
far
 can be either positive or negative. The corresponding matrix is
where
The current matrix is multiplied by this matrix with the result replacing the current matrix. That is, if M is the current matrix and O is the ortho matrix, then M is replaced with M
·
 O.
Use
glPushMatrix
 and
glPopMatrix
 to save and restore the current matrix stack.
The following functions retrieve information related to the
glOrtho
 function:
glGet
 with argument
GL_MATRIX_MODE
glGet
 with argument
GL_MODELVIEW_MATRIX
glGet
 with argument
GL_PROJECTION_MATRIX
glGet
 with argument
GL_TEXTURE_MATRIX
Errors
GL_INVALID_OPERATION
 is generated if
glOrtho
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glFrustum
,
glMatrixMode
,
glMultMatrix
,
glPushMatrix
,
glViewport


glPassThrough
The
glPassThrough
 function places a marker in the feedback buffer.
void glPassThrough
(
GLfloat
token
);
Parameters
token
Specifies a marker value to be placed in the feedback buffer following a
GL_PASS_THROUGH_TOKEN
.
Remarks
Feedback is a GL render mode. The mode is selected by calling
glRenderMode
 with
GL_FEEDBACK
. When the GL is in feedback mode, no pixels are produced by rasterization. Instead, information about primitives that would have been rasterized is fed back to the application using the GL. See
glFeedbackBuffer
 for a description of the feedback buffer and the values in it.
The
glPassThrough
 function inserts a user-defined marker in the feedback buffer when it is executed in feedback mode.
token
 is returned as if it were a primitive; it is indicated with its own unique identifying value:
GL_PASS_THROUGH_TOKEN
. The order of
glPassThrough
 commands with respect to the specification of graphics primitives is maintained.
The
glPassThrough
 function is ignored if the GL is not in feedback mode.
The following function retrieves information related to the
glPassThrough
 function:
glGet
 with argument
GL_RENDER_MODE
Errors
GL_INVALID_OPERATION
 is generated if
glPassThrough
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glFeedbackBuffer
,
glRenderMode


glPixelMap
glPixelMapfv, glPixelMapuiv, glPixelMapusv
These functions set up pixel transfer maps.
void glPixelMapfv
(
GLenum
map
,
GLint
mapsize
,
const GLfloat
*values
);
void glPixelMapuiv
(
GLenum
map
,
GLint
mapsize
,
const GLuint
*values
);
void glPixelMapusv
(
GLenum
map
,
GLint
mapsize
,
const GLushort
*values
);
Parameters
map
Specifies a symbolic map name. Must be one of the following:
GL_PIXEL_MAP_I_TO_I, GL_PIXEL_MAP_S_TO_S, GL_PIXEL_MAP_I_TO_R, GL_PIXEL_MAP_I_TO_G, GL_PIXEL_MAP_I_TO_B, GL_PIXEL_MAP_I_TO_A, GL_PIXEL_MAP_R_TO_R, GL_PIXEL_MAP_G_TO_G, GL_PIXEL_MAP_B_TO_B,
 or
GL_PIXEL_MAP_A_TO_A.
mapsize
Specifies the size of the map being defined.
values
Specifies an array of
mapsize
 values.
Remarks
The
 glPixelMap
 function sets up translation tables, or
maps
, used by
glDrawPixels
,
glReadPixels
,
glCopyPixels
,
glTexImage1D
, and
glTexImage2D
. Use of these maps is described completely in the
glPixelTransfer
 reference page, and partly in the reference pages for the pixel and texture image commands. Only the specification of the maps is described in this topic.
The
 map
 parameter is a symbolic map name, indicating one of ten maps to set.
mapsize
 specifies the number of entries in the map, and
values
 is a pointer to an array of
mapsize
 map values.
The ten maps are as follows:
GL_PIXEL_MAP_I_TO_I
Maps color indices to color indices.
GL_PIXEL_MAP_S_TO_S
Maps stencil indices to stencil indices.
GL_PIXEL_MAP_I_TO_R
Maps color indices to red components.
GL_PIXEL_MAP_I_TO_G
Maps color indices to green components.
GL_PIXEL_MAP_I_TO_B
Maps color indices to blue components.
GL_PIXEL_MAP_I_TO_A
Maps color indices to alpha components.
GL_PIXEL_MAP_R_TO_R
Maps red components to red components.
GL_PIXEL_MAP_G_TO_G
Maps green components to green components.
GL_PIXEL_MAP_B_TO_B
Maps blue components to blue components.
GL_PIXEL_MAP_A_TO_A
Maps alpha components to alpha components.
The entries in a map can be specified as single-precision floating-point numbers, unsigned short integers, or unsigned long integers. Maps that store color component values (all but
GL_PIXEL_MAP_I_TO_I
 and
GL_PIXEL_MAP_S_TO_S
) retain their values in floating-point format, with unspecified mantissa and exponent sizes. Floating-point values specified by
glPixelMapfv
 are converted directly to the internal floating-point format of these maps, then clamped to the range [0,1]. Unsigned integer values specified by
glPixelMapusv
 and
glPixelMapuiv
 are converted linearly such that the largest representable integer maps to 1.0, and zero maps to 0.0.
Maps that store indices,
GL_PIXEL_MAP_I_TO_I
 and
GL_PIXEL_MAP_S_TO_S
, retain their values in fixed-point format, with an unspecified number of bits to the right of the binary point. Floating-point values specified by
glPixelMapfv
 are converted directly to the internal fixed-point format of these maps. Unsigned integer values specified by
glPixelMapusv
 and
glPixelMapuiv
 specify integer values, with all zeros to the right of the binary point.
The table below shows the initial sizes and values for each of the maps. Maps that are indexed by either color or stencil indices must have
mapsize
 = 2^
n
for some
n
 or results are undefined. The maximum allowable size for each map depends on the implementation and can be determined by calling
glGet
 with argument
GL_MAX_PIXEL_MAP_TABLE
. The single maximum applies to all maps, and it is at least 32.
GL_PIXEL_MAP_I_TO_I
Lookup Index:
color index
Lookup Value:
color index
Initial Size:
1
Initial Value:
0.0
GL_PIXEL_MAP_S_TO_S
Lookup Index:
stencil index
Lookup Value:
stencil index
Initial Size:
1
Initial Value:
0.0
GL_PIXEL_MAP_I_TO_R
Lookup Index:
color index
Lookup Value:
R
Initial Size:
1
Initial Value:
0.0
GL_PIXEL_MAP_I_TO_G
Lookup Index:
color index
Lookup Value:
G
Initial Size:
1
Initial Value:
0.0
GL_PIXEL_MAP_I_TO_B
Lookup Index:
color index
Lookup Value:
B
Initial Size:
1
Initial Value:
0.0
GL_PIXEL_MAP_I_TO_A
Lookup Index:
color index
Lookup Value:
A
Initial Size:
1
Initial Value:
0.0
GL_PIXEL_MAP_R_TO_R
Lookup Index:
R
Lookup Value:
R
Initial Size:
1
Initial Value:
0.0
GL_PIXEL_MAP_G_TO_G
Lookup Index:
G
Lookup Value:
G
Initial Size:
1
Initial Value:
0.0
GL_PIXEL_MAP_B_TO_B
Lookup Index:
B
Lookup Value:
B
Initial Size:
1
Initial Value:
0.0
GL_PIXEL_MAP_A_TO_A
Lookup Index:
A
Lookup Value:
A
Initial Size:
1
Initial Value:
0.0
The following functions retrieve information related to the
glPixelMap
 function:
glGet
 with argument
GL_PIXEL_MAP_I_TO_I_SIZE
glGet
 with argument
GL_PIXEL_MAP_S_TO_S_SIZE
glGet
 with argument
GL_PIXEL_MAP_I_TO_R_SIZE
glGet
 with argument
GL_PIXEL_MAP_I_TO_G_SIZE
glGet
 with argument
GL_PIXEL_MAP_I_TO_B_SIZE
glGet
 with argument
GL_PIXEL_MAP_I_TO_A_SIZE
glGet
 with argument
GL_PIXEL_MAP_R_TO_R_SIZE
glGet
 with argument
GL_PIXEL_MAP_G_TO_G_SIZE
glGet
 with argument
GL_PIXEL_MAP_B_TO_B_SIZE
glGet
 with argument
GL_PIXEL_MAP_A_TO_A_SIZE
glGet
 with argument
GL_MAX_PIXEL_MAP_TABLE
Errors
GL_INVALID_ENUM
 is generated if
map
 is not an accepted value.
GL_INVALID_VALUE
 is generated if
mapsize
 is negative or larger than
GL_MAX_PIXEL_MAP_TABLE
.
GL_INVALID_VALUE
 is generated if
map
 is
GL_PIXEL_MAP_I_TO_I
,
GL_PIXEL_MAP_S_TO_S
,
GL_PIXEL_MAP_I_TO_R
,
GL_PIXEL_MAP_I_TO_G
,
GL_PIXEL_MAP_I_TO_B
, or
GL_PIXEL_MAP_I_TO_A
, and
mapsize
 is not a power of two.
GL_INVALID_OPERATION
 is generated if
glPixelMap
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glCopyPixels
,
glDrawPixels
,
glPixelStore
,
glPixelTransfer
,
glReadPixels
,
glTexImage1D
,
glTexImage2D


glPixelStore
glPixelStoref, glPixelStorei
The
glPixelStoref
 and
glPixelStorei
functions set pixel storage modes.
void glPixelStoref
(
GLenum
pname
,
GLfloat
param
);
void glPixelStorei
(
GLenum
pname
,
GLint
param
);
Parameters
pname
Specifies the symbolic name of the parameter to be set. Six values affect the packing of pixel data into memory:
GL_PACK_SWAP_BYTES, GL_PACK_LSB_FIRST, GL_PACK_ROW_LENGTH, GL_PACK_SKIP_PIXELS, GL_PACK_SKIP_ROWS
, and
GL_PACK_ALIGNMENT
. Six more affect the unpacking of pixel data
from
 memory:
GL_UNPACK_SWAP_BYTES, GL_UNPACK_LSB_FIRST, GL_UNPACK_ROW_LENGTH, GL_UNPACK_SKIP_PIXELS, GL_UNPACK_SKIP_ROWS,
 and
GL_UNPACK_ALIGNMENT
.
param
Specifies the value that
pname
 is set to.
Remarks
The
 glPixelStore
 function sets pixel storage modes that affect the operation of subsequent
glDrawPixels
 and
glReadPixels
 as well as the unpacking of polygon stipple patterns (see
glPolygonStipple
), bitmaps (see
glBitmap
), and texture patterns (see
glTexImage1D
 and
glTexImage2D
).
The
 pname
 parameter is a symbolic constant indicating the parameter to be set, and
param
 is the new value. Six of the twelve storage parameters affect how pixel data is returned to client memory, and are therefore significant only for
glReadPixels
 commands. They are as follows:
GL_PACK_SWAP_BYTES
If true, byte ordering for multibyte color components, depth components, color indices, or stencil indices is reversed. That is, if a four-byte component is made up of bytes
b
 (0)
,
b
 (1)
,
b
 (2)
,
b
 (3)
, it is stored in memory as
b
 (3)
,
b
 (2)
,
b
 (1)
,
b
 (0)
 if
GL_PACK_SWAP_BYTES
 is true.
GL_PACK_SWAP_BYTES
has no effect on the memory order of components within a pixel, only on the order of bytes within components or indices. For example, the three components of a
GL_RGB
 format pixel are always stored with red first, green second, and blue third, regardless of the value of
GL_PACK_SWAP_BYTES
.
GL_PACK_LSB_FIRST
If true, bits are ordered within a byte from least significant to most significant; otherwise, the first bit in each byte is the most significant one. This parameter is significant for bitmap data only.
GL_PACK_ROW_LENGTH
If greater than zero,
GL_PACK_ROW_LENGTH
 defines the number of pixels in a row. If the first pixel of a row is placed at location
p
 in memory, then the location of the first pixel of the next row is obtained by skipping
components or indices, where
n
 is the number of components or indices in a pixel,
 l
 is the number of pixels in a row (
GL_PACK_ROW_LENGTH
 if it is greater than zero, the width argument to the pixel routine otherwise),
a
 is the value of
GL_PACK_ALIGNMENT
, and
s
 is the size, in bytes, of a single component (if
a
 <
s
, then it is as if
a
 =
s
). In the case of 1-bit values, the location of the next row is obtained by skipping
components or indices.
The word
component
 in this description refers to the nonindex values red, green, blue, alpha, and depth. Storage format
GL_RGB
, for example, has three components per pixel: first red, then green, and finally blue.
GL_PACK_SKIP_PIXELS
 and
GL_PACK_SKIP_ROWS
These values are provided as a convenience to the programmer; they provide no functionality that cannot be duplicated simply by incrementing the pointer passed to
glReadPixels
. Setting
GL_PACK_SKIP_PIXELS
 to
i
 is equivalent to incrementing the pointer by
i
n
 components or indices, where
n
 is the number of components or indices in each pixel. Setting
GL_PACK_SKIP_ROWS
 to
j
is equivalent to incrementing the pointer by
j
k
 components or indices, where
k
 is the number of components or indices per row, as computed above in the
GL_PACK_ROW_LENGTH
 section.
GL_PACK_ALIGNMENT
Specifies the alignment requirements for the start of each pixel row in memory. The allowable values are 1 (byte-alignment), 2 (rows aligned to even-numbered bytes), 4 (word alignment), and 8 (rows start on double-word boundaries).
The other six of the twelve storage parameters affect how pixel data is read from client memory. These values are significant for
glDrawPixels
,
glTexImage1D
,
glTexImage2D
,
glBitmap
, and
glPolygonStipple
. They are as follows:
GL_UNPACK_SWAP_BYTES
If true, byte ordering for multibyte color components, depth components, color indices, or stencil indices is reversed. That is, if a four-byte component is made up of bytes
b
 (0)
,
b
 (1)
,
b
 (2)
,
b
 (3)
, it is taken from memory as
b
 (3)
,
b
 (2)
,
b
 (1)
,
b
 (0)
 if
GL_UNPACK_SWAP_BYTES
 is true.
GL_UNPACK_SWAP_BYTES
has no effect on the memory order of components within a pixel, only on the order of bytes within components or indices. For example, the three components of a
GL_RGB
 format pixel are always stored with red first, green second, and blue third, regardless of the value of
GL_UNPACK_SWAP_BYTES
.
GL_UNPACK_LSB_FIRST
If true, bits are ordered within a byte from least significant to most significant; otherwise, the first bit in each byte is the most significant one. This is significant for bitmap data only.
GL_UNPACK_ROW_LENGTH
If greater than zero,
GL_UNPACK_ROW_LENGTH
 defines the number of pixels in a row. If the first pixel of a row is placed at location
p
 in memory, then the location of the first pixel of the next row is obtained by skipping
components or indices, where n is the number of components or indices in a pixel,
l
 is the number of pixels in a row (
GL_UNPACK_ROW_LENGTH
 if it is greater than zero, the width argument to the pixel routine otherwise),
a
 is the value of
GL_UNPACK_ALIGNMENT
, and
s
 is the size, in bytes, of a single component (if
a
 <
s
, then it is as if
a
 =
s
). In the case of 1-bit values, the location of the next row is obtained by skipping
components or indices.
The word
component
 in this description refers to the nonindex values red, green, blue, alpha, and depth. Storage format
GL_RGB
, for example, has three components per pixel: first red,
then green, and finally blue.
GL_UNPACK_SKIP_PIXELS
 and
GL_UNPACK_SKIP_ROWS
These values are provided as a convenience to the programmer; they provide no functionality that cannot be duplicated simply by incrementing the pointer passed to
glDrawPixels
,
glTexImage1D
,
glTexImage2D
,
glBitmap
, or
glPolygonStipple
. Setting
GL_UNPACK_SKIP_PIXELS
 to
i
 is equivalent to incrementing the pointer by
i n
 components or indices, where
n
 is the number of components or indices in each pixel. Setting
GL_UNPACK_SKIP_ROWS
 to
j
 is equivalent to incrementing the pointer by
j k
 components or indices, where
k
 is the number of components or indices per row, as computed above in the
GL_UNPACK_ROW_LENGTH
 section.
GL_UNPACK_ALIGNMENT
Specifies the alignment requirements for the start of each pixel row in memory. The allowable values are 1 (byte-alignment), 2 (rows aligned to even-numbered bytes), 4 (word alignment), and 8 (rows start on double-word boundaries).
The following table gives the type, initial value, and range of valid values for each of the storage parameters that can be set with
glPixelStore
.
Pname
Type
Initial Value
Valid Range
GL_PACK_SWAP_BYTES
Boolean
false
true or false
GL_PACK_SWAP_BYTES
Boolean
false
true or false
GL_PACK_ROW_LENGTH
integer
0
[0,
oo
)
GL_PACK_SKIP_ROWS
integer
0
[0,
oo
)
GL_PACK_SKIP_PIXELS
integer
0
[0,
oo
)
GL_PACK_ALIGNMENT
integer
4
1, 2, 4, or 8 _
GL_UNPACK_SWAP_BYTES
Boolean
false
true or false
GL_UNPACK_LSB_FIRST
Boolean
false
true or false
GL_UNPACK_ROW_LENGTH
integer
0
[0,
oo
)
GL_UNPACK_SKIP_ROWS
integer
0
[0,
oo
)
GL_UNPACK_SKIP_PIXELS
integer
0
[0,
oo
)
GL_UNPACK_ALIGNMENT
integer
4
1, 2, 4, or 8
The
 glPixelStoref
 function can be used to set any pixel store parameter. If the parameter type is Boolean, and if
param
 is 0.0, the parameter is false; otherwise it is set to true. If
pname
 is an integer type parameter,
param
 is rounded to the nearest integer.
Likewise, the
glPixelStorei
 function can also be used to set any of the pixel store parameters. Boolean parameters are set to false if
param
 is 0 and true otherwise.
param
 is converted to floating point before being assigned to real-valued parameters.
The pixel storage modes in effect when
glDrawPixels
,
glReadPixels
,
glTexImage1D
,
glTexImage2D
,
glBitmap
, or
glPolygonStipple
 is placed in a display list control the interpretation of memory data. The pixel storage modes in effect when a display list is executed are not significant.
The following functions retrieve information related to the
glPixelStore
 function:
glGet
 with argument
GL_PACK_SWAP_BYTES
glGet
 with argument
GL_PACK_LSB_FIRST
glGet
 with argument
GL_PACK_ROW_LENGTH
glGet
 with argument
GL_PACK_SKIP_ROWS
glGet
 with argument
GL_PACK_SKIP_PIXELS
glGet
 with argument
GL_PACK_ALIGNMENT
glGet
 with argument
GL_UNPACK_SWAP_BYTES
glGet
 with argument
GL_UNPACK_LSB_FIRST
glGet
 with argument
GL_UNPACK_ROW_LENGTH
glGet
 with argument
GL_UNPACK_SKIP_ROWS
glGet
 with argument
GL_UNPACK_SKIP_PIXELS
glGet
 with argument
GL_UNPACK_ALIGNMENT
Errors
GL_INVALID_ENUM
 is generated if
pname
 is not an accepted value.
GL_INVALID_VALUE
 is generated if a negative row length, pixel skip, or row skip value is specified, or if alignment is specified as other than 1, 2, 4, or 8.
GL_INVALID_OPERATION
 is generated if
glPixelStore
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glBitmap
,
glDrawPixels
,
glPixelMap
,
glPixelTransfer
,
glPixelZoom
,
glPolygonStipple
,
glReadPixels
,
glTexImage1D
,
glTexImage2D


glPixelTransfer
glPixelTransferf, glPixelTransferi
The
glPixelTransferf
 and
glPixelTransferi
 functions set pixel transfer modes.
void glPixelTransferf
(
GLenum
pname
,
GLfloat
param
);
void glPixelTransferi
(
GLenum
pname
,
GLint
param
);
Parameters
pname
Specifies the symbolic name of the pixel transfer parameter to be set. Must be one of the following:
 GL_MAP_COLOR, GL_MAP_STENCIL, GL_INDEX_SHIFT, GL_INDEX_OFFSET, GL_RED_SCALE, GL_RED_BIAS, GL_GREEN_SCALE, GL_GREEN_BIAS, GL_BLUE_SCALE, GL_BLUE_BIAS, GL_ALPHA_SCALE, GL_ALPHA_BIAS, GL_DEPTH_SCALE,
or
GL_DEPTH_BIAS
.
param
Specifies the value that
pname
 is set to.
Remarks
The
glPixelTransfer
 function sets pixel transfer modes that affect the operation of subsequent
glDrawPixels
,
glReadPixels
,
glCopyPixels
,
glTexImage1D
, and
glTexImage2D
 commands. The algorithms that are specified by pixel transfer modes operate on pixels after they are read from the frame buffer (
glReadPixels
 and
glCopyPixels
) or unpacked from client memory (
glDrawPixels
,
glTexImage1D
, and
glTexImage2D
). Pixel transfer operations happen in the same order, and in the same manner, regardless of the command that resulted in the pixel operation. Pixel storage modes (
glPixelStore
) control the unpacking of pixels being read from client memory, and the packing of pixels being written back into client memory.
Pixel transfer operations handle four fundamental pixel types:
color, color index, depth
, and
stencil
.
Color
 pixels are made up of four floating-point values with unspecified mantissa and exponent sizes, scaled such that 0.0 represents zero intensity and 1.0 represents full intensity.
Color indices
 comprise a single fixed-point value, with unspecified precision to the right of the binary point.
Depth
 pixels comprise a single floating-point value, with unspecified mantissa and exponent sizes, scaled such that 0.0 represents the minimum depth buffer value, and 1.0 represents the maximum depth buffer value. Finally,
stencil
 pixels comprise a single fixed-point value, with unspecified precision to the right of the binary point.
The pixel transfer operations performed on the four basic pixel types are as follows:
Color
Each of the four color components is multiplied by a scale factor, then added to a bias factor. That is, the red component is multiplied by
GL_RED_SCALE
, then added to
GL_RED_BIAS
; the green component is multiplied by
GL_GREEN_SCALE
, then added to
GL_GREEN_BIAS
; the blue component is multiplied by
GL_BLUE_SCALE
, then added to
GL_BLUE_BIAS
; and the alpha component is multiplied by
GL_ALPHA_SCALE
, then added to
GL_ALPHA_BIAS
. After all four color components are scaled and biased, each is clamped to the range [0,1]. All color scale and bias values are specified with
glPixelTransfer
.
If
GL_MAP_COLOR
 is true, each color component is scaled by the size of the corresponding color-to-color map, then replaced by the contents of that map indexed by the scaled component. That is, the red component is scaled by
GL_PIXEL_MAP_R_TO_R_SIZE
, then replaced by the contents of
GL_PIXEL_MAP_R_TO_R
 indexed by itself. The green component is scaled by
GL_PIXEL_MAP_G_TO_G_SIZE
, then replaced by the contents of
GL_PIXEL_MAP_G_TO_G
 indexed by itself. The blue component is scaled by
GL_PIXEL_MAP_B_TO_B_SIZE
, then replaced by the contents of
GL_PIXEL_MAP_B_TO_B
 indexed by itself. And the alpha component is scaled by
GL_PIXEL_MAP_A_TO_A_SIZE
, then replaced by the contents of
GL_PIXEL_MAP_A_TO_A
 indexed by itself. All components taken from the maps are then clamped to the range [0,1].
GL_MAP_COLOR
 is specified with
glPixelTransfer
. The contents of the various maps are specified with
glPixelMap
.
Color index
Each color index is shifted left by
GL_INDEX_SHIFT
 bits, filling with zeros any bits beyond the number of fraction bits carried by the fixed-point index. If
GL_INDEX_SHIFT
 is negative, the shift is to the right, again zero filled. Then
GL_INDEX_OFFSET
 is added to the index.
GL_INDEX_SHIFT
 and
GL_INDEX_OFFSET
 are specified with
glPixelTransfer
.
From this point, operation diverges depending on the required format of the resulting pixels. If the resulting pixels are to be written to a color index buffer, or if they are being read back to client memory in
GL_COLOR_INDEX
 format, the pixels continue to be treated as indices. If
GL_MAP_COLOR
 is true, each index is masked by 2^
n
-
 1, where
n
 is
GL_PIXEL_MAP_I_TO_I_SIZE
, then replaced by the contents of
GL_PIXEL_MAP_I_TO_I
 indexed by the masked value.
GL_MAP_COLOR
 is specified with
glPixelTransfer
. The contents of the index map are specified with
glPixelMap
.
If the resulting pixels are to be written to an RGBA color buffer, or if they are being read back to client memory in a format other than
GL_COLOR_INDEX
, the pixels are converted from indices to colors by referencing the four maps
GL_PIXEL_MAP_I_TO_R
,
GL_PIXEL_MAP_I_TO_G
,
GL_PIXEL_MAP_I_TO_B
, and
GL_PIXEL_MAP_I_TO_A
. Before being dereferenced, the index is masked by 2
n
-
 1, where
n
 is
GL_PIXEL_MAP_I_TO_R_SIZE
 for the red map,
GL_PIXEL_MAP_I_TO_G_SIZE
 for the green map,
GL_PIXEL_MAP_I_TO_B_SIZE
 for the blue map, and
GL_PIXEL_MAP_I_TO_A_SIZE
 for the alpha map. All components taken from the maps are then clamped to the range [0,1]. The contents of the four maps are specified with
glPixelMap
.
Depth
Each depth value is multiplied by
GL_DEPTH_SCALE
, added to
GL_DEPTH_BIAS
, then clamped to the range [0,1].
Stencil
Each index is shifted
GL_INDEX_SHIFT
 bits just as a color index is, then added to
GL_INDEX_OFFSET
. If
GL_MAP_STENCIL
 is true, each index is masked by 2^
n
-
 1, where
n
 is
GL_PIXEL_MAP_S_TO_S_SIZE
, then replaced by the contents of
GL_PIXEL_MAP_S_TO_S
 indexed by the masked value.
The following table gives the type, initial value, and range of valid values for each of the pixel transfer parameters that are set with
glPixelTransfer
.
Pname
Type
Initial Value
Valid Range
GL_MAP_COLOR
Boolean
false
true/false
GL_MAP_STENCIL
Boolean
false
true/false
GL_INDEX_SHIFT
integer
0
(
-
oo
,
oo
)
GL_INDEX_OFFSET
integer
0
(
-
oo
,
oo
)
GL_RED_SCALE
float
1.0
(
-
oo
,
oo
)
GL_GREEN_SCALE
float
1.0
(
-
oo
,
oo
)
GL_BLUE_SCALE
float
1.0
(
-
oo
,
oo
)
GL_ALPHA_SCALE
float
1.0
(
-
oo
,
oo
)
GL_DEPTH_SCALE
float
1.0
(
-
oo
,
oo
)
GL_RED_BIAS
float
0.0
(
-
oo
,
oo
)
GL_GREEN_BIAS
float
0.0
(
-
oo
,
oo
)
GL_BLUE_BIAS
float
0.0
(
-
oo
,
oo
)
GL_ALPHA_BIAS
float
0.0
(
-
oo
,
oo
)
GL_DEPTH_BIAS
float
0.0
(
-
oo
,
oo
)
The
 glPixelTransferf
 function can be used to set any pixel transfer parameter. If the parameter type is Boolean, 0.0 implies false and any other value implies true. If
pname
 is an integer parameter,
param
 is rounded to the nearest integer.
Likewise,
glPixelTransferi
 can also be used to set any of the pixel transfer parameters. Boolean parameters are set to false if
param
 is 0 and true otherwise.
param
 is converted to floating point before being assigned to real-valued parameters.
If a
glDrawPixels
,
glReadPixels
,
glCopyPixels
,
glTexImage1D
, or
glTexImage2D
 command is placed in a display list (see
glNewList
 and
glCallList
), the pixel transfer mode settings in effect when the display list is
 executed
 are the ones that are used. They may be different from the settings when the command was compiled into the display list.
The following functions retrieve information related to the
glPixelTransfer
 function:
glGet
 with argument
GL_MAP_COLOR
glGet
 with argument
GL_MAP_STENCIL
glGet
 with argument
GL_INDEX_SHIFT
glGet
 with argument
GL_INDEX_OFFSET
glGet
 with argument
GL_RED_SCALE
glGet
 with argument
GL_RED_BIAS
glGet
 with argument
GL_GREEN_SCALE
glGet
 with argument
GL_GREEN_BIAS
glGet
 with argument
GL_BLUE_SCALE
glGet
 with argument
GL_BLUE_BIAS
glGet
 with argument
GL_ALPHA_SCALE
glGet
 with argument
GL_ALPHA_BIAS
glGet
 with argument
GL_DEPTH_SCALE
glGet
 with argument
GL_DEPTH_BIAS
Errors
GL_INVALID_ENUM
 is generated if
pname
 is not an accepted value.
GL_INVALID_OPERATION
 is generated if
glPixelTransfer
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glCallList
,
glCopyPixels
,
glDrawPixels
,
glNewList
,
glPixelMap
,
glPixelStore
,
glPixelZoom
,
glReadPixels
,
glTexImage1D
,
glTexImage2D


glPixelZoom
The
glPixelZoom
 function specifies the pixel zoom factors.
void glPixelZoom
(
GLfloat
xfactor
,
GLfloat
yfactor
);
Parameters
xfactor, yfactor
Specify the
x
 and
y
 zoom factors for pixel write operations.
Remarks
The
glPixelZoom
 function specifies values for the
x
 and
y
 zoom factors. During the execution of
glDrawPixels
 or
glCopyPixels
, if (
x
 (r)
,
y
 (r)
) is the current raster position, and a given element is in the
n
th row and mth column of the pixel rectangle, then pixels whose centers are in the rectangle with corners at
are candidates for replacement. Any pixel whose center lies on the bottom or left edge of this rectangular region is also modified.
Pixel zoom factors are not limited to positive values. Negative zoom factors reflect the resulting image about the current raster position.
The following functions retrieve information related to the
glPixelZoom
function:
glGet
 with argument
 GL_ZOOM_X
glGet
 with argument
GL_ZOOM_Y
Errors
GL_INVALID_OPERATION
 is generated if
glPixelZoom
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glCopyPixels
,
glDrawPixels


glPointSize
The
glPointSize
 function specifies the diameter of rasterized points.
void
glPointSize
(
GLfloat
size
);
Parameters
size
Specifies the diameter of rasterized points. The default is 1.0.
Remarks
The
glPointSize
 function specifies the rasterized diameter of both aliased and antialiased points. Using a point size other than 1.0 has different effects, depending on whether point antialiasing is enabled. Point antialiasing is controlled by calling
glEnable
 and
glDisable
 with argument
GL_POINT_SMOOTH
.
If point antialiasing is disabled, the actual size is determined by rounding the supplied size to the nearest integer. (If the rounding results in the value 0, it is as if the point size were 1.) If the rounded size is odd, then the center point (
x, y
) of the pixel fragment that represents the point is computed as
 (
ë
x
 (w)
û
 + .5 ,
ë
y
 (w)
û
 + .5)
where
w
 subscripts indicate window coordinates. All pixels that lie within the square grid of the rounded size centered at (
x , y
) make up the fragment. If the size is even, the center point is
 (
ë
x
 (w)
 + .5
û
,
ë
y
 (w)
 + .5
û
 )
and the rasterized fragments centers are the half-integer window coordinates within the square of the rounded size centered at  (
x, y
). All pixel fragments produced in rasterizing a nonantialiased point are assigned the same associated data; that of the vertex corresponding to the point.
If antialiasing is enabled, then point rasterization produces a fragment for each pixel square that intersects the region lying within the circle having diameter equal to the current point size and centered at the points (
x
 (w)
, y
 (w)
). The coverage value for each fragment is the window coordinate area of the intersection of the circular region with the corresponding pixel square. This value is saved and used in the final rasterization step.  The data associated with each fragment is the data associated with the point being rasterized.
Not all sizes are supported when point antialiasing is enabled. If an unsupported size is requested, the nearest supported size is used. Only size 1.0 is guaranteed to be supported; others depend on the implementation. The range of supported sizes and the size difference between supported sizes within the range can be queried by calling
glGet
 with arguments
GL_POINT_SIZE_RANGE
 and
GL_POINT_SIZE_GRANULARITY
.
The point size specified by
glPointSize
 is always returned when
GL_POINT_SIZE
 is queried. Clamping and rounding for aliased and antialiased points have no effect on the specified value.
Non-antialiased point size may be clamped to an implementation-dependent maximum. Although this maximum cannot be queried, it must be no less than the maximum value for antialiased points, rounded to the nearest integer value.
The following functions retrieve information related to the
glPointSize
function:
glGet
 with argument
GL_POINT_SIZE
glGet
 with argument
GL_POINT_SIZE_RANGE
glGet
 with argument
GL_POINT_SIZE_GRANULARITY
glIsEnabled
 with argument
GL_POINT_SMOOTH
Errors
GL_INVALID_VALUE
 is generated if
size
 is less than or equal to zero.
GL_INVALID_OPERATION
 is generated if
glPointSize
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glEnable


glPolygonMode
The
glPolygonMode
function selects a polygon rasterization mode.
void glPolygonMode
(
GLenum
face
,
GLenum
mode
);
Parameters
face
Specifies the polygons that
mode
 applies to. Must be
GL_FRONT
 for front-facing polygons,
GL_BACK
 for back-facing polygons, or
GL_FRONT_AND_BACK
 for front- and back-facing polygons.
mode
Specifies the way polygons will be rasterized. Accepted values are
GL_POINT
,
GL_LINE
, and
GL_FILL
. The default is
GL_FILL
 for both front- and back-facing polygons.
Remarks
The
glPolygonMode
function controls the interpretation of polygons for rasterization.
face
 describes which polygons
mode
 applies to: front-facing polygons
 (GL_FRONT),
back-facing polygons (
GL_BACK
), or both (
GL_FRONT_AND_BACK
). The polygon mode affects only the final rasterization of polygons. In particular, a polygon's vertexes are lit and the polygon is clipped and possibly culled before these modes are applied.
Three modes are defined and can be specified in
mode
:
GL_POINT
Polygon vertexes that are marked as the start of a boundary edge are drawn as points. Point attributes such as
GL_POINT_SIZE
 and
GL_POINT_SMOOTH
 control the rasterization of the points. Polygon rasterization attributes other than
GL_POLYGON_MODE
 have no effect.
GL_LINE
Boundary edges of the polygon are drawn as line segments. They are treated as connected line segments for line stippling; the line stipple counter and pattern are not reset between segments (see
glLineStipple
). Line attributes such as
GL_LINE_WIDTH
and
 GL_LINE_SMOOTH
 control the rasterization of the lines. Polygon rasterization attributes other than
GL_POLYGON_MODE
 have no effect.
GL_FILL
The interior of the polygon is filled. Polygon attributes such as
GL_POLYGON_STIPPLE
 and
GL_POLYGON_SMOOTH
 control the rasterization of the polygon.
To draw a surface with filled back-facing polygons and outlined front-facing polygons, call
glPolygonMode
(
GL_FRONT
,
GL_LINE
);
Vertexes are marked as boundary or nonboundary with an edge flag. Edge flags are generated internally by the GL when it decomposes polygons, and they can be set explicitly using
glEdgeFlag
.
The following function retrieves information related to the
glPolygonMode
function:
glGet
 with argument
GL_POLYGON_MODE
Errors
GL_INVALID_ENUM
 is generated if either
face
 or
mode
 is not an accepted value.
GL_INVALID_OPERATION
 is generated if
glPolygonMode
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glBegin
,
glEdgeFlag
,
glLineStipple
,
glLineWidth
,
glPointSize
,
glPolygonStipple


glPolygonStipple
The
glPolygonStipple
 function sets the polygon stippling pattern.
void
glPolygonStipple
(
const GLubyte
*mask
);
Parameters
mask
Specifies a pointer to a 32x32 stipple pattern that will be unpacked from memory in the same way that
glDrawPixels
 unpacks pixels.
Remarks
Polygon stippling, like line stippling (see
glLineStipple
), masks out certain fragments produced by rasterization, creating a pattern. Stippling is independent of polygon antialiasing.
The
 mask
 parameter is a pointer to a 32x32 stipple pattern that is stored in memory just like the pixel data supplied to a
glDrawPixels
 with
height
and
 width
 both equal to 32, a pixel
 format
of
GL_COLOR_INDEX
, and data
 type
of
GL_BITMAP
. That is, the stipple pattern is represented as a 32x32 array of 1-bit color indices packed in unsigned bytes.
glPixelStore
 parameters like
GL_UNPACK_SWAP_BYTES
 and
GL_UNPACK_LSB_FIRST
 affect the assembling of the bits into a stipple pattern. Pixel transfer operations (shift, offset, pixel map) are not applied to the stipple image, however.
Polygon stippling is enabled and disabled with
glEnable
 and
glDisable
, using argument
GL_POLYGON_STIPPLE
. If enabled, a rasterized polygon fragment with window coordinates
x
 (w)
 and
y
 (w)
 is sent to the next stage of the GL if and only if the (
x
 (w)
 mod 32)th bit in the (
y
 (w)
 mod 32)th row of the stipple pattern is one. When polygon stippling is disabled, it is as if the stipple pattern were all ones.
The following functions retrieve information related to the
glPolygonStipple
function:
glGetPolygonStipple
glIsEnabled
 with argument
GL_POLYGON_STIPPLE
Errors
GL_INVALID_OPERATION
 is generated if
glPolygonStipple
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glDrawPixels
,
glLineStipple
,
glPixelStore
,
glPixelTransfer


glPushAttrib
glPushAttrib, glPopAttrib
The
glPushAttrib
 and
glPopAttrib
 functions push and pop the attribute stack.
void glPushAttrib
(
GLbitfield
mask
);
Parameters
mask
Specifies a mask that indicates which attributes to save. Values for
mask
are listed below.
void glPopAttrib
(
void
);
Remarks
The
 glPushAttrib
 function takes one argument, a mask that indicates which groups of state variables to save on the attribute stack. Symbolic constants are used to set bits in the mask.
mask
 is typically constructed by ORing several of these constants together. The special mask
GL_ALL_ATTRIB_BITS
 can be used to save all stackable states.
The symbolic mask constants and their associated GL state are as follows (the indented paragraphs list which attributes are saved):
GL_ACCUM_BUFFER_BIT
Accumulation buffer clear value
GL_COLOR_BUFFER_BIT
GL_ALPHA_TEST
 enable bit
Alpha test function and reference value
GL_BLEND
 enable bit
Blending source and destination
functions
GL_DITHER
 enable bit
GL_DRAW_BUFFER
 setting
GL_LOGIC_OP
 enable bit
Logic op function
Color mode and index mode
clear values
Color mode and index mode writemasks
GL_CURRENT_BIT
Current RGBA color
Current color index
Current normal vector
Current texture coordinates
Current raster position
GL_CURRENT_RASTER_POSITION_VALID
 flag
RGBA color associated with current raster position
Color index associated with current raster position
Texture coordinates associated with current raster position
GL_EDGE_FLAG flag
GL_DEPTH_BUFFER_BIT
GL_DEPTH_TEST
 enable bit
Depth buffer test function
Depth buffer clear value
GL_DEPTH_WRITEMASK
 enable bit
GL_ENABLE_BIT
GL_ALPHA_TEST
 flag
GL_AUTO_NORMAL
 flag
GL_BLEND
 flag
Enable bits for the user-definable clipping planes
GL_COLOR_MATERIAL
GL_CULL_FACE
 flag
GL_DEPTH_TEST
 flag
GL_DITHER
 flag
GL_FOG
 flag
GL_LIGHT
i
 where 0<=
i
<
GL_MAX_LIGHTS
GL_LIGHTING
 flag
GL_LINE_SMOOTH
 flag
GL_LINE_STIPPLE
 flag
GL_LOGIC_OP
 flag
GL_MAP1_
x
 where
x
 is a map type
GL_MAP2_
x
 where
x
 is a map type
GL_NORMALIZE
 flag
GL_POINT_SMOOTH
flag
GL_POLYGON_SMOOTH
 flag
GL_POLYGON_STIPPLE
 flag
GL_SCISSOR_TEST
 flag
GL_SENCIL_TESTT
 flag
GL_TEXTURE_1D
 flag
GL_TEXTURE_2D
 flag
Flags
GL_TEXTURE_GEN_
x
 where
x
 is
S
,
T
,
R
, or
Q
GL_EVAL_BIT
GL_MAP1_
x
 enable bits, where
x
 is a map type
GL_MAP2_
x
 enable bits, where
x
 is a map type
1-D grid endpoints and divisions
2-D grid endpoints and divisions
GL_AUTO_NORMAL
 enable bit
GL_FOG_BIT
GL_FOG
 enable flag
Fog color
Fog density
Linear fog start
Linear fog end
Fog index
GL_FOG_MODE
 value
GL_HINT_BIT
GL_PERSPECTIVE_CORRECTION_HINT
 setting
GL_POINT_SMOOTH_HINT
setting
GL_LINE_SMOOTH_HINT
setting
GL_POLYGON_SMOOTH_HINT
 setting
GL_FOG_HINT
 setting
GL_LIGHTING_BIT
GL_COLOR_MATERIAL
 enable bit
GL_COLOR_MATERIAL_FACE value
Color material parameters that are tracking the current color
Ambient scene color
GL_LIGHT_MODEL_LOCAL_VIEWER
value
GL_LIGHT_MODEL_TWO_SIDE
setting
GL_LIGHTING
enable bit
Enable bit for each light
Ambient, diffuse, and specular intensity for each light
Direction, position, exponent, and cutoff angle for each light
Constant, linear, and quadratic attenuation factors for each light
Ambient, diffuse, specular, and emissive color for each material
Ambient, diffuse, and specular color indices for each material
Specular exponent for each material
GL_SHADE_MODEL
 setting
GL_LINE_BIT
GL_LINE_SMOOTH
 flag
GL_LINE_STIPPLE
enable bit
Line stipple pattern and repeat counter
Line width
GL_LIST_BIT
GL_LIST_BASE
 setting
GL_PIXEL_MODE_BIT
GL_RED_BIAS
 and
GL_RED_SCALE
 settings
GL_GREEN_BIAS
and
 GL_GREEN_SCALE
values
GL_BLUE_BIAS
 and
 GL_BLUE_SCALE
GL_ALPHA_BIAS
and
 GL_ALPHA_SCALE
GL_DEPTH_BIAS
 and
GL_DEPTH_SCALE
GL_INDEX_OFFSET
 and
 GL_INDEX_SHIFT
 values
GL_MAP_COLOR
and
 GL_MAP_STENCIL
 flags
GL_ZOOM_X
and
GL_ZOOM_Y
 factors
GL_READ_BUFFER
 setting
GL_POINT_BIT
GL_POINT_SMOOTH
 flag
Point size
GL_POLYGON_BIT
GL_CULL_FACE
 enable bit
GL_CULL_FACE_MODE
 value
GL_FRONT_FACE
 indicator
GL_POLYGON_MODE
 setting
GL_POLYGON_SMOOTH
 flag
GL_POLYGON_STIPPLE
 enable bit
GL_POLYGON_STIPPLE_BIT
Polygon stipple image
GL_SCISSOR_BIT
GL_SCISSOR_TEST
 flag
Scissor box
GL_STENCIL_BUFFER_BIT
GL_STENCIL_TEST
enable bit
Stencil function and reference value
Stencil value mask
Stencil fail, pass, and depth buffer pass actions
Stencil buffer clear value
Stencil buffer writemask
GL_TEXTURE_BIT
Enable bits for the four texture coordinates
Border color for each texture image
Minification function for each texture image
Magnification function for each texture image
Texture coordinates and wrap mode for each texture image
Color and mode for each texture environment
Enable bits
GL_TEXTURE_GEN_
x
,
x
 is
S
,
T
,
R
, and
Q
GL_TEXTURE_GEN_MODE
 setting for
S
,
T
,
R
, and
Q
glTexGen plane
 equations for
S
,
T
,
R
, and
Q
GL_TRANSFORM_BIT
Coefficients of the six clipping planes
Enable bits for the user-definable clipping planes
GL_MATRIX_MODE
 value
GL_NORMALIZE
 flag
GL_VIEWPORT_BIT
Depth range (near and far)
Viewport origin and extent
The
 glPopAttrib
 function restores the values of the state variables saved with the last
glPushAttrib
 command. Those not saved are left unchanged.
It is an error to push attributes onto a full stack, or to pop attributes off an empty stack. In either case, the error flag is set and no other change is made to GL state.
Initially, the attribute stack is empty.
Not all values for GL state can be saved on the attribute stack. For example, pixel pack and unpack state, render mode state, and select and feedback state cannot be saved.
The depth of the attribute stack depends on the implementation, but it must be at least 16.
The following functions retrieve information related to the
glPushAttrib
 and
glPopAttrib
 functions:
glGet
 with argument
GL_ATTRIB_STACK_DEPTH
.
glGet
 with argument
GL_MAX_ATTRIB_STACK_DEPTH
.
Errors
GL_STACK_OVERFLOW
 is generated if
glPushAttrib
 is called while the attribute stack is full.
GL_STACK_UNDERFLOW
 is generated if
glPopAttrib
 is called while the attribute stack is empty.
GL_INVALID_OPERATION
 is generated if
glPushAttrib
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glGet
,
glGetClipPlane
,
glGetError
,
glGetLight
,
glGetMap
,
glGetMaterial
,
glGetPixelMap
,
glGetPolygonStipple
,
glGetString
,
glGetTexEnv
,
glGetTexGen
,
glGetTexImage
,
glGetTexLevelParameter
,
glGetTexParameter
,
glIsEnabled


glPushMatrix
glPushMatrix, glPopMatrix
The
glPushMatrix
 and
glPopMatrix
 functions push and pop the current matrix stack.
void glPushMatrix
(
void
);
void glPopMatrix
(
void
);
Remarks
There is a stack of matrices for each of the matrix modes. In
GL_MODELVIEW
 mode, the stack depth is at least 32. In the other two modes,
GL_PROJECTION
 and
GL_TEXTURE
, the depth is at least 2. The current matrix in any mode is the matrix on the top of the stack for that mode.
The
 glPushMatrix
 function pushes the current matrix stack down by one, duplicating the current matrix. That is, after a
glPushMatrix
 call, the matrix on the top of the stack is identical to the one below it. The
 glPushMatrix
 function pops the current matrix stack, replacing the current matrix with the one below it on the stack. Initially, each of the stacks contains one matrix, an identity matrix.
It is an error to push a full matrix stack, or to pop a matrix stack that contains only a single matrix. In either case, the error flag is set and no other change is made to GL state.
The following functions retrieve information related to the
glPushMatrix
 and
glPopMatrix
 functions:
glGet
with argument
GL_MATRIX_MODE
glGet
with argument
GL_MODELVIEW_MATRIX
glGet
with argument
GL_PROJECTION_MATRIX
glGet
with argument
GL_TEXTURE_MATRIX
glGet
with argument
GL_MODELVIEW_STACK_DEPTH
glGet
with argument
GL_PROJECTION_STACK_DEPTH
glGet
with argument
GL_TEXTURE_STACK_DEPTH
glGet
with argument
GL_MAX_MODELVIEW_STACK_DEPTH
glGet
with argument
GL_MAX_PROJECTION_STACK_DEPTH
glGet
with argument
GL_MAX_TEXTURE_STACK_DEPTH
Errors
GL_STACK_OVERFLOW
 is generated if
glPushMatrix
 is called while the current matrix stack is full.
GL_STACK_UNDERFLOW
 is generated if
glPopMatrix
 is called while the current matrix stack contains only a single matrix.
GL_INVALID_OPERATION
 is generated if
glPushMatrix
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glFrustum
,
glLoadIdentity
,
glLoadMatrix
,
glMatrixMode
,
glMultMatrix
,
glOrtho
,
glRotate
,
glScale
,
glTranslate
,
glViewport


glPushName
glPushName, glPopName
The
glPushName
 and
glPopName
 functions push and pop the name stack.
void glPushName
(
GLuint
name
);
Parameters
name
Specifies a name that will be pushed onto the name stack.
void
glPopName
(
void
);
Remarks
The name stack is used during selection mode to allow sets of rendering commands to be uniquely identified. It consists of an ordered set of unsigned integers. The
glPushName
 function causes
name
 to be pushed onto the name stack, which is initially empty.
glPopName
 pops one name off the top of the stack.
It is an error to push a name onto a full stack, or to pop a name off an empty stack. It is also an error to manipulate the name stack between a call to
glBegin
 and the corresponding call to
glEnd
. In any of these cases, the error flag is set and no other change is made to GL state.
The name stack is always empty while the render mode is not
GL_SELECT
. Calls to
glPushName
 or
glPopName
 while the render mode is not
GL_SELECT
 are ignored.
The following functions retrieve information related to the
glPushName
 and
glPopName
 functions:
glGet
 with argument
GL_NAME_STACK_DEPTH
glGet
 with argument
GL_MAX_NAME_STACK_DEPTH
Errors
GL_STACK_OVERFLOW
 is generated if
glPushName
 is called while the name stack is full.
GL_STACK_UNDERFLOW
 is generated if
glPopName
 is called while the name stack is empty.
GL_INVALID_OPERATION
 is generated if
glPushName
 or
glPopName
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glInitNames
,
glLoadName
,
glRenderMode
,
glSelectBuffer


glRasterPos
glRasterPos2d, glRasterPos2f, glRasterPos2i, glRasterPos2s, glRasterPos3d, glRasterPos3f, glRasterPos3i, glRasterPos3s, glRasterPos4d, glRasterPos4f, glRasterPos4i, glRasterPos4s, glRasterPos2dv, glRasterPos2fv, glRasterPos2iv, glRasterPos2sv, glRastePos3dv, glRasterPos3fv, glRasterPos3iv, glRasterPos3sv, glRasterPos4dv, glRasterPos4fv, glRasterPos4iv, glRasterPos4sv
These functions specify the raster position for pixel operations.
void
glRasterPos2d
(
GLdouble
x
,
GLdouble
y
);
void glRasterPos2f
(
GLfloat
x
,
GLfloat
y
);
void glRasterPos2i
(
GLint
x
,
GLint
y
);
void glRasterPos2s
(
GLshort
x
,
GLshort
y
);
void glRasterPos3d
(
GLdouble
x
,
GLdouble
y
,
GLdouble
z
);
void glRasterPos3f
(
GLfloat
x
,
GLfloat
y
,
GLfloat
z
);
void glRasterPos3i
(
GLint
x
,
GLint
y
,
GLint
z
);
void glRasterPos3s
(
GLshort
x
,
GLshort
y
,
GLshort
z
);
void glRasterPos4d
(
GLdouble
x
,
GLdouble
y
,
GLdouble
z
,
GLdouble
w
);
void glRasterPos4f
(
GLfloat
x
,
GLfloat
y
,
GLfloat
z
,
GLfloat
w
);
void glRasterPos4i
(
GLint
x
,
GLint
y
,
GLint
z
,
GLint
w
);
void glRasterPos4s
(
GLshort
x
,
GLshort
y
,
GLshort
z
,
GLshort
w
);
Parameters
x, y, z, w
Specify the x, y, z, and w object coordinates (if present) for the raster position.
void
glRasterPos2dv
(
const GLdouble
*v
);
void
glRasterPos2fv
(
const GLfloat
*v
);
void
glRasterPos2iv
(
const GLint
*v
);
void
glRasterPos2sv
(
const GLshort
*v
);
void
glRasterPos3dv
(
const GLdouble
*v
);
void glRasterPos3fv
(
const GLfloat
*v
);
void glRasterPos3iv
(
const GLint
*v
);
void glRasterPos3sv
(
const GLshort
*v
);
void glRasterPos4dv
(
const GLdouble
*v
);
void glRasterPos4fv
(
const GLfloat
*v
);
void glRasterPos4iv
(
const GLint
*v
);
void glRasterPos4sv
(
const GLshort
*v
);
Parameters
v
Specifies a pointer to an array of two, three, or four elements, specifying
x, y, z,
and
w
 coordinates, respectively.
Remarks
The GL maintains a 3-D position in window coordinates. This position, called the raster position, is maintained with subpixel accuracy. It is used to position pixel and bitmap write operations. See
glBitmap
,
glDrawPixels
, and
glCopyPixels
.
The current raster position consists of three window coordinates (
x, y, z
), a clip coordinate
w
 value, an eye coordinate distance, a valid bit, and associated color data and texture coordinates. The
w
 coordinate is a clip coordinate, because
w
 is not projected to window coordinates.
glRasterPos4
 specifies object coordinates
x, y, z,
 and
w
 explicitly.
glRasterPos3
 specifies object coordinate
x, y,
 and
z
explicitly, while
w
 is implicitly set to one.
glRasterPos2
 uses the argument values for
x
 and
y
 while implicitly setting
z
 and
w
 to zero and one.
The object coordinates presented by
glRasterPos
 are treated just like those of a
glVertex
 command: They are transformed by the current modelview and projection matrices
and passed to the clipping stage. If the vertex is not culled, then it is projected and scaled to window coordinates, which become the new current raster position, and the
GL_CURRENT_RASTER_POSITION_VALID
 flag is set. If the vertex is culled, then the valid bit is cleared and the current raster position and associated color and texture coordinates are undefined.
The current raster position also includes some associated color data and texture coordinates. If lighting is enabled, then
GL_CURRENT_RASTER_COLOR
, in RGBA mode, or the
GL_CURRENT_RASTER_INDEX
, in color index mode, is set to the color produced by the lighting calculation (see
glLight
,
glLightModel
, and
glShadeModel
). If lighting is disabled, current color (in RGBA mode, state variable
GL_CURRENT_COLOR
) or color index (in color index mode, state variable
GL_CURRENT_INDEX
) is used to update the current raster color.
Likewise,
GL_CURRENT_RASTER_TEXTURE_COORDS
 is updated as a function of
GL_CURRENT_TEXTURE_COORDS
, based on the texture matrix and the texture generation functions (see
glTexGen
). Finally, the distance from the origin of the eye coordinate system to the vertex, as transformed by only the modelview matrix, replaces
GL_CURRENT_RASTER_DISTANCE
.
Initially, the current raster position is (0,0,0,1), the current raster distance is 0, the valid bit is set, the associated RGBA color is (1,1,1,1), the associated color index is 1, and the associated texture coordinates are (0, 0, 0, 1). In RGBA mode,
GL_CURRENT_RASTER_INDEX
 is always 1; in color index mode, the current raster RGBA color always maintains its initial value.
Notes
The raster position is modified both by
glRasterPos
 and by
glBitmap
.
When the raster position coordinates are invalid, drawing commands that are based on the raster position are ignored (that is, they do not result in changes to GL state).
The following functions retrieve information related to the
glRasterPos
 function:
glGet
 with argument
GL_CURRENT_RASTER_POSITION
glGet
 with argument
GL_CURRENT_RASTER_POSITION_VALID
glGet
 with argument
GL_CURRENT_RASTER_DISTANCE
glGet
 with argument
GL_CURRENT_RASTER_COLOR
glGet
 with argument
GL_CURRENT_RASTER_INDEX
glGet
 with argument
GL_CURRENT_RASTER_TEXTURE_COORDS
Errors
GL_INVALID_OPERATION
 is generated if
glRasterPos
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glBitmap
,
glCopyPixels
,
glDrawPixels
,
glLight
,
glLightModel
,
glShadeModel
,
glTexCoord
,
glTexGen
,
glVertex


glReadBuffer
The
glReadBuffer
 function selects a color buffer source for pixels.
void glReadBuffer
(
GLenum
mode
);
Parameters
mode
Specifies a color buffer. Accepted values are
GL_FRONT_LEFT, GL_FRONT_RIGHT, GL_BACK_LEFT, GL_BACK_RIGHT, GL_FRONT, GL_BACK
,
GL_LEFT
,
GL_RIGHT
, and
GL_AUX
i
, where
i
 is between 0 and
GL_AUX_BUFFERS
-
1.
Remarks
The
glReadBuffer
 function specifies a color buffer as the source for subsequent
glReadPixels
 and
glCopyPixels
 commands.
mode
 accepts one of twelve or more predefined values. (
GL_AUX0
 through
GL_AUX3
 are always defined.) In a fully configured system,
GL_FRONT
,
GL_LEFT
, and
GL_FRONT_LEFT
 all name the front left buffer,
GL_FRONT_RIGHT
 and
GL_RIGHT
 name the front right buffer, and
GL_BACK_LEFT
 and
GL_BACK
 name the back left buffer.
Nonstereo double-buffered configurations have only a front left and a back left buffer. Single-buffered configurations have a front left and a front right buffer if stereo, and only a front left buffer if nonstereo. It is an error to specify a nonexistent buffer to
glReadBuffer
.
By default,
mode
 is
GL_FRONT
 in single-buffered configurations, and
GL_BACK
 in double-buffered configurations.
The following function retrieves information related to the
glReadBuffer
 function:
glGet
 with argument
GL_READ_BUFFER
Errors
GL_INVALID_ENUM
 is generated if
mode
 is not one of the twelve (or more) accepted values.
GL_INVALID_OPERATION
 is generated if
mode
 specifies a buffer that does not exist.
GL_INVALID_OPERATION
 is generated if
glReadBuffer
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glCopyPixels
,
glDrawBuffer
,
glReadPixels


glReadPixels
The
glReadPixels
 function reads a block of pixels from the frame buffer.
void glReadPixels
(
GLint
x
,
GLint
y
,
GLsizei
width
,
GLsizei
height
,
GLenum
format
,
GLenum
type
,
GLvoid
*pixels
);
Parameters
x, y
Specify the window coordinates of the first pixel that is read from the frame buffer. This location is the lower left corner of a rectangular block of pixels.
width, height
Specify the dimensions of the pixel rectangle. The
width
 and
height
 parameters of one correspond to a single pixel.
format
Specifies the format of the pixel data. The following symbolic values are accepted:
 GL_COLOR_INDEX, GL_STENCIL_INDEX, GL_DEPTH_COMPONENT, GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA, GL_RGB, GL_RGBA, GL_LUMINANCE,
and
GL_LUMINANCE_ALPHA
.
type
Specifies the data type of the pixel data. Must be one of
GL_UNSIGNED_BYTE, GL_BYTE, GL_BITMAP, GL_UNSIGNED_SHORT, GL_SHORT, GL_UNSIGNED_INT, GL_INT,
 or
GL_FLOAT
.
pixels
Returns the pixel data.
Remarks
The
glReadPixels
 function returns pixel data from the frame buffer, starting with the pixel whose lower left corner is at location (
x
,
y
), into client memory starting at location
pixels
. Several parameters control the processing of the pixel data before it is placed into client memory. These parameters are set with three commands:
glPixelStore
,
glPixelTransfer
, and
glPixelMap
. This topic describes the effects on
glReadPixels
 of most, but not all of the parameters specified by these three commands.
The
glReadPixels
 function returns values from each pixel with lower left-hand corner at (
x
 + i,
y
+ j) for 0
£
i<
width
 and 0
£
j<
height
. This pixel is said to be the
i
th pixel in the
j
th row. Pixels are returned in row order from the lowest to the highest row, left to right in each row.
The
 format
 parameter specifies the format for the returned pixel values. Accepted values for
format
 are as follows:
GL_COLOR_INDEX
Color indices are read from the color buffer selected by
glReadBuffer
. Each index is converted to fixed point, shifted left or right depending on the value and sign of
GL_INDEX_SHIFT
, and added to
GL_INDEX_OFFSET
. If
GL_MAP_COLOR
 is
GL_TRUE
, indices are replaced by their mappings in the table
GL_PIXEL_MAP_I_TO_I
.
GL_STENCIL_INDEX
Stencil values are read from the stencil buffer. Each index is converted to fixed point, shifted left or right depending on the value and sign of
GL_INDEX_SHIFT
, and added to
GL_INDEX_OFFSET
. If
GL_MAP_STENCIL
 is
GL_TRUE
, indices are replaced by their mappings in the table
GL_PIXEL_MAP_S_TO_S
.
GL_DEPTH_COMPONENT
Depth values are read from the depth buffer. Each component is converted to floating point such that the minimum depth value maps to 0.0 and the maximum value maps to 1.0. Each component is then multiplied by
GL_DEPTH_SCALE
, added to
GL_DEPTH_BIAS
, and finally clamped to the range [0,1].
GL_RED
GL_GREEN
GL_BLUE
GL_ALPHA
GL_RGB
GL_RGBA
GL_LUMINANCE
GL_LUMINANCE_ALPHA
Processing differs depending on whether color buffers store color indices or RGBA color components. If color indices are stored, they are read from the color buffer selected by
glReadBuffer
. Each index is converted to fixed point, shifted left or right depending on the value and sign of
GL_INDEX_SHIFT
, and added to
GL_INDEX_OFFSET
.  Indices are then replaced by the red, green, blue, and alpha values obtained by indexing the
GL_PIXEL_MAP_I_TO_R, GL_PIXEL_MAP_I_TO_G
,
GL_PIXEL_MAP_I_TO_B,
and
 GL_PIXEL_MAP_I_TO_A
 tables.
If RGBA color components are stored in the color buffers, they are read from the color buffer selected by
glReadBuffer
. Each color component is converted to floating point such that zero intensity maps to 0.0 and full intensity maps to 1.0. Each component is then multiplied by
GL_c_SCALE
 and added to
GL_c_BIAS
, where
c
 is
GL_RED
,
GL_GREEN
,
GL_BLUE
, and
GL_ALPHA
. Each component is clamped to the range [0,1]. Finally, if
GL_MAP_COLOR
 is
GL_TRUE
, each color component
c
 is replaced by its mapping in the table
GL_PIXEL_MAP_c_TO_c
, where
c
 again is
GL_RED
,
GL_GREEN
,
GL_BLUE
, and
GL_ALPHA
. Each component is scaled to the size of its corresponding table before the lookup is performed.
Finally, unneeded data is discarded. For example,
GL_RED
 discards the green, blue, and alpha components, while
GL_RGB
 discards only the alpha component.
GL_LUMINANCE
 computes a single component value as the sum of the red, green, and blue components, and
GL_LUMINANCE_ALPHA
 does the same, while keeping alpha as a second value.
The shift, scale, bias, and lookup factors described above are all specified by
glPixelTransfer
. The lookup table contents themselves are specified by
glPixelMap
.
The final step involves converting the indices or components to the proper format, as specified by
type
. If
format
 is
GL_COLOR_INDEX
 or
GL_STENCIL_INDEX
 and
type
 is not
GL_FLOAT
, each index is masked with the mask value given in the following table. If
type
 is
GL_FLOAT
, then each integer index is converted to single-precision floating-point format.
If
format
 is
GL_RED
,
GL_GREEN
,
GL_BLUE
,
GL_ALPHA
,
GL_RGB
,
GL_RGBA
,
GL_LUMINANCE
, or
GL_LUMINANCE_ALPHA
 and
type
 is not
GL_FLOAT
, each component is multiplied by the multiplier shown in the following table. If type is
GL_FLOAT
, then each component is passed as is (or converted to the clients single-precision floating-point format if it is different from the one used by the GL).
Type
Index Mask
Component Conversion
GL_UNSIGNED_BYTE
2^
8
-
1
(2^
8
-
1)
c
GL_BYTE
2^
7
-
1
[2^
7
-
1]
c
-1]/2
GL_BITMAP
1
1
GL_UNSIGNED_SHORT
2^
1
6
-
1
(2^
16
-
1)
c
GL_SHORT
2^
15
-
1
[(2^
15
-
1)
c
-
1] / 2
GL_UNSIGNED_INT
2^
32
-
1
(2^
32
-
1)
c
GL_INT
2^
31
-
1
[(2^
3
1
-
1)
c
-
1] / 2
GL_FLOAT
none
c
Return values are placed in memory as follows. If
format
 is
GL_COLOR_INDEX
,
GL_STENCIL_INDEX
,
GL_DEPTH_COMPONENT
,
GL_RED
,
GL_GREEN
,
GL_BLUE
,
GL_ALPHA
, or
GL_LUMINANCE
, a single value is returned and the data for the ith pixel in the jth row is placed in location (
j
)
width
 +
i
.
GL_RGB
 returns three values,
GL_RGBA
 returns four values, and
GL_LUMINANCE_ALPHA
 returns two values for each pixel, with all values corresponding to a single pixel occupying contiguous space in
pixels
. Storage parameters set by
glPixelStore
, such as
GL_PACK_SWAP_BYTES
 and
GL_PACK_LSB_FIRST
, affect the way that data is written into memory. See
glPixelStore
 for a description.
Values for pixels that lie outside the window connected to the current GL context are undefined.
If an error is generated, no change is made to the contents of
pixels
.
The following function retrieves information related to the
glReadPixels
 function:
glGet
 with argument
GL_INDEX_MODE
Errors
GL_INVALID_ENUM
 is generated if
format
 or
type
 is not an accepted value.
GL_INVALID_VALUE
 is generated if either
width
 or
height
 is negative.
GL_INVALID_OPERATION
 is generated if
format
 is
GL_COLOR_INDEX
 and the color buffers store RGBA color components.
GL_INVALID_OPERATION
 is generated if
format
 is
GL_STENCIL_INDEX
 and there is no stencil buffer.
GL_INVALID_OPERATION
 is generated if
format
 is
GL_DEPTH_COMPONENT
 and there is no depth buffer.
GL_INVALID_OPERATION
 is generated if
glReadPixels
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glCopyPixels
,
glDrawPixels
,
glPixelMap
,
glPixelStore
,
glPixelTransfer
,
glReadBuffer


glRect
glRectd, glRectf, glRecti, glRects, glRectdv, glRectfv, glRectiv, glRectsv
These functions draw a rectangle.
void glRectd
(
GLdouble
x1
,
GLdouble
y1
,
GLdouble
x2
,
GLdouble
y2
);
void glRectf
(
GLfloat
x1
,
GLfloat
y1
,
GLfloat
x2
,
GLfloat
y2
);
void glRecti
(
GLint
x1
,
GLint
y1
,
GLint
x2
,
GLint
y2
);
void glRects
(
GLshort
x1
,
GLshort
y1
,
GLshort
x2
,
GLshort
y2
);
Parameters
x1, y1
Specify one vertex of a rectangle.
x2, y2
Specify the opposite vertex of the rectangle.
void glRectdv
(
const GLdouble
*v1
,
const GLdouble
*v2
);
void glRectfv
(
const GLfloat
*v1
,
const GLfloat
*v2
);
void glRectiv
(
const GLint
*v1
,
const GLint
*v2
);
void glRectsv
(
const GLshort
*v1
,
const GLshort
*v2
);
Parameters
v1
Specifies a pointer to one vertex of a rectangle.
v2
Specifies a pointer to the opposite vertex of the rectangle.
Remarks
The
 glRect
 function supports efficient specification of rectangles as two corner points. Each rectangle command takes four arguments, organized either as two consecutive pairs of (
x
,
y
) coordinates, or as two pointers to arrays, each containing an (
x
,
y
) pair. The resulting rectangle is defined in the
z
= 0 plane.
The
 glRect
(
x1
,
y1
,
x2
,
y2
) function is exactly equivalent to the following sequence:
glBegin
(
GL_POLYGON
);
glVertex2
(
x1
,
y1
);
glVertex2
(
x2
,
y1
);
glVertex2
(
x2
,
y2
);
glVertex2
(
x1
,
y2
);
glEnd
( );
Notice that if the second vertex is above and to the right of the first vertex, the rectangle is constructed with a counterclockwise winding.
Errors
GL_INVALID_OPERATION
 is generated if
glRect
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glBegin
,
glVertex


glRenderMode
The
glRenderMode
 function sets the rasterization mode.
GLint
glRenderMode
(
GLenum
mode
);
Parameters
mode
Specifies the rasterization mode. Three values are accepted:
GL_RENDER, GL_SELECT,
 and
GL_FEEDBACK
.
The default value is
GL_RENDER
.
Remarks
The
glRenderMode
 function takes one argument,
mode
, which can assume one of three predefined values:
GL_RENDER
Render mode. Primitives are rasterized, producing pixel fragments, which are written into the frame buffer. This is the normal mode and also the default mode.
GL_SELECT
Selection mode. No pixel fragments are produced, and no change to the frame buffer contents is made. Instead, a record of the names of primitives that would have been drawn if the render mode was
GL_RENDER
 is returned in a select buffer, which must be created (see
glSelectBuffer
) before selection mode is entered.
GL_FEEDBACK
Feedback mode. No pixel fragments are produced, and no change to the frame buffer contents is made. Instead, the coordinates and attributes of vertexes that would have been drawn had the render mode been
GL_RENDER
 are returned in a feedback buffer, which must be created (see
glFeedbackBuffer
) before feedback mode is entered.
The return value of the
glRenderMode
 function is determined by the render mode at the time
glRenderMode
 is called, rather than by
mode
. The values returned for the three render modes are as follows:
GL_RENDER
Zero.
GL_SELECT
The number of hit records transferred to the select buffer.
GL_FEEDBACK
The number of values (not vertexes) transferred to the feedback buffer.
Refer to
glSelectBuffer
 and
glFeedbackBuffer
 for more details concerning selection and feedback operation.
If an error is generated, the
glRenderMode
 function returns zero regardless of the current render mode.
The following function retrieves information related to the
glRenderMode
 function:
glGet
 with argument
GL_RENDER_MODE
Errors
GL_INVALID_ENUM
 is generated if
mode
 is not one of the three accepted values.
GL_INVALID_OPERATION
 is generated if
glSelectBuffer
 is called while the render mode is
GL_SELECT
, or if
glRenderMode
 is called with argument
GL_SELECT
 before
glSelectBuffer
 is called at least once.
GL_INVALID_OPERATION
 is generated if
glFeedbackBuffer
 is called while the render mode is
GL_FEEDBACK
, or if
glRenderMode
 is called with argument
GL_FEEDBACK
 before
glFeedbackBuffer
 is called at least once.
GL_INVALID_OPERATION
 is generated if
glRenderMode
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glFeedbackBuffer
,
glInitNames
,
glLoadName
,
glPassThrough
,
glPushName
,
glSelectBuffer


glRotate
glRotated, glRotatef
The
glRotated
 and
glRotatef
 functions multiply the current matrix by a rotation matrix.
void glRotated
(
GLdouble
angle
,
GLdouble
x
,
GLdouble
y
,
GLdouble
z
)
void glRotatef
(
GLfloat
angle
,
GLfloat
x
,
GLfloat
y
,
GLfloat
z
)
Parameters
angle
Specifies the angle of rotation, in degrees.
x, y, z
Specify the
x
,
y
, and
z
 coordinates of a vector, respectively.
Remarks
The
 glRotate
 function computes a matrix that performs a counterclockwise rotation of
angle
 degrees about the vector from the origin through the point (
x
,
y
,
z
).
The current matrix (see
glMatrixMode
) is multiplied by this rotation matrix, with the product replacing the current matrix. That is, if M is the current matrix and R is the translation matrix, then M is replaced with M
·
R.
If the matrix mode is either
GL_MODELVIEW
 or
GL_PROJECTION
, all objects drawn after
glRotate
 is called are rotated. Use
glPushMatrix
 and
glPopMatrix
 to save and restore the unrotated coordinate system.
The following functions retrieve information related to the
glRotate
 function:
glGet
 with argument
GL_RENDER_MODE
glGet
 with argument
GL_MATRIX_MODE
glGet
 with argument
GL_MODELVIEW_MATRIX
glGet
 with argument
GL_PROJECTION_MATRIX
glGet
 with argument
GL_TEXTURE_MATRIX
Errors
GL_INVALID_OPERATION
 is generated if
glRotate
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glMatrixMode
,
glMultMatrix
,
glPushMatrix
,
glScale
,
glTranslate


glScale
glScaled, glScalef
The
glScaled
 and
glScalef
 functions multiply the current matrix by a general scaling matrix.
void
glScaled
(
GLdouble
x
,
GLdouble
y
,
GLdouble
z
);
void glScalef
(
GLfloat
x
,
GLfloat
y
,
GLfloat
z
);
Parameters
x, y, z
Specify scale factors along the
x
,
y
, and
z
 axes, respectively.
Remarks
The
glScale
 function produces a general scaling along the
x
,
y
, and
z
 axes. The three arguments indicate the desired scale factors along each of the three axes. The resulting matrix is
The current matrix (see
glMatrixMode
) is multiplied by this scale matrix, with the product replacing the current matrix. That is, if M is the current matrix and S is the scale matrix, then M is replaced with M
·
S.
If the matrix mode is either
GL_MODELVIEW
 or
GL_PROJECTION
, all objects drawn after
glScale
 is called are scaled. Use
glPushMatrix
 and
glPopMatrix
 to save and restore the unscaled coordinate system.
If scale factors other than 1.0 are applied to the modelview matrix and lighting is enabled, automatic normalization of normals should probably also be enabled (
glEnable
 and
glDisable
 with argument
GL_NORMALIZE
).
The following functions retrieve information related to the
glScale
 function:
glGet
 with argument
GL_MATRIX_MODE
glGet
 with argument
GL_MODELVIEW_MATRIX
glGet
 with argument
GL_PROJECTION_MATRIX
glGet
 with argument
GL_TEXTURE_MATRIX
Errors
GL_INVALID_OPERATION
 is generated if
glScale
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glMatrixMode
,
glMultMatrix
,
glPushMatrix
,
glRotate
,
glTranslate


glScissor
The
glScissor
 function defines the scissor box.
void glScissor
(
GLint
x
,
GLint
y
,
GLsizei
width
,
GLsizei
height
);
Parameters
x, y
Specify the lower left corner of the scissor box. Initially (0,0).
width, height
Specify the width and height of the scissor box. When a GL context is
first
 attached to a window,
width
 and
height
 are set to the dimensions of that window.
Remarks
The
glScissor
 function defines a rectangle, called the scissor box, in window coordinates. The first two arguments,
x
 and
y
, specify the lower-left corner of the box.
width
 and
height
 specify the width and height of the box.
The scissor test is enabled and disabled using
glEnable
 and
glDisable
 with argument
GL_SCISSOR_TEST
. While the scissor test is enabled, only pixels that lie within the scissor box can be modified by drawing commands. Window coordinates have integer values at the shared corners of frame buffer pixels, so
glScissor
(0,0,1,1) allows only the lower-left pixel in the window to be modified, and
glScissor
(0,0,0,0) disallows modification to all pixels in the window.
When the scissor test is disabled, it is as though the scissor box includes the entire window.
The following functions retrieve information related to the
glScissor
 function:
glGet
 with argument
GL_SCISSOR_BOX
glIsEnabled
 with argument
GL_SCISSOR_TEST
Errors
GL_INVALID_VALUE
 is generated if either
width
 or
height
 is negative.
GL_INVALID_OPERATION
 is generated if
glScissor
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glEnable
,
glViewport


glSelectBuffer
The
glSelectBuffer
 function establishes a buffer for selection mode values.
void
glSelectBuffer
(
GLsizei
size
,
GLuint
*buffer
);
Parameters
size
Specifies the size of
buffer
.
buffer
Returns the selection data.
Remarks
The
glSelectBuffer
 function has two arguments:
buffer
is a pointer to an array of unsigned integers,
and
size
 indicates the size of the array.
buffer
 returns values from the name stack (see
glInitNames
,
glLoadName
,
glPushName
) when the rendering mode is
GL_SELECT
 (see
glRenderMode
). The
glSelectBuffer
 function must be issued before selection mode is enabled, and it must not be issued while the rendering mode is
GL_SELECT
.
Selection is used by a programmer to determine which primitives are drawn into some region of a window. The region is defined by the current modelview and perspective matrices.
In selection mode, no pixel fragments are produced from rasterization. Instead, if a primitive intersects the clipping volume defined by the viewing frustum and the user-defined clipping planes, this primitive causes a selection hit. (With polygons, no hit occurs if the polygon is culled.) When a change is made to the name stack, or when
glRenderMode
 is called, a hit record is copied to
buffer
 if any hits have occurred since the last such event (name stack change or
glRenderMode
 call). The hit record consists of the number of names in the name stack at the time of the event, followed by the minimum and maximum depth values of all vertexes that hit since the previous event, followed by the name stack contents, bottom name first.
Returned depth values are mapped such that the largest unsigned integer value corresponds to window coordinate depth 1.0, and zero corresponds to window coordinate depth 0.0.
An internal index into
buffer
 is reset to zero whenever selection mode is entered. Each time a hit record is copied into
buffer
, the index is incremented to point to the cell just past the end of the block of names
-
  that is, to the next available cell. If the hit record is larger than the number of remaining locations in
buffer
, as much data as can fit is copied, and the overflow flag is set. If the name stack is empty when a hit record is copied, that record consists of zero followed by the minimum and maximum depth values.
Selection mode is exited by calling
glRenderMode
 with an argument other than
GL_SELECT
. Whenever
glRenderMode
 is called while the render mode is
GL_SELECT
, it returns the number of hit records copied to
buffer
, resets the overflow flag and the selection buffer pointer, and initializes the name stack to be empty. If the overflow bit was set when
glRenderMode
 was called, a negative hit record count is returned.
The contents of
buffer
 are undefined until
glRenderMode
 is called with an argument other than
GL_SELECT
.
The
glBegin
/
glEnd
 primitives and calls to
glRasterPos
 can result in hits.
The following function retrieves information related to the
glSelectBuffer
 function:
glGet
 with argument
GL_NAME_STACK_DEPTH
Errors
GL_INVALID_VALUE
 is generated if
size
 is negative.
GL_INVALID_OPERATION
 is generated if
glSelectBuffer
 is called while the render mode is
GL_SELECT
, or if
glRenderMode
 is called with argument
GL_SELECT
 before
glSelectBuffer
 is called at least once.
GL_INVALID_OPERATION
 is generated if
glSelectBuffer
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glFeedbackBuffer
,
glInitNames
,
glLoadName
,
glPushName
,
glRenderMode


glShadeModel
The
glShadeModel
 function selects flat or smooth shading.
void
glShadeModel
(
GLenum
mode
);
Parameters
mode
Specifies a symbolic value representing a shading technique. Accepted values are
GL_FLAT
 and
GL_SMOOTH
. The default is
GL_SMOOTH
.
Remarks
GL primitives can have either flat or smooth shading. Smooth shading, the default, causes the computed colors of vertexes to be interpolated as the primitive is rasterized, typically assigning different colors to each resulting pixel fragment. Flat shading selects the computed color of just one vertex and assigns it to all the pixel fragments generated by rasterizing a single primitive. In either case, the computed color of a vertex is the result of lighting, if lighting is enabled, or it is the current color at the time the vertex was specified, if lighting is disabled.
Flat and smooth shading are indistinguishable for points. Counting vertexes and primitives from one starting when
glBegin
 is issued, each flat-shaded line segment i is given the computed color of vertex
 i
 + 1, its second vertex. Counting similarly from one, each flat-shaded polygon is given the computed color of the vertex listed in the following table. This is the last vertex to specify the polygon in all cases except single polygons, where the first vertex specifies the flat-shaded color.
Primitive Type of Polygon i
Vertex
Single polygon (
i
º
1)
1
Triangle strip
i
 + 2
Triangle fan
i
 + 2
Independent triangle
 3
i
Quad strip
2
i
 + 2
Independent quad
 4
i
Flat and smooth shading are specified by
glShadeModel
 with
mode
 set to
GL_FLAT
 and
GL_SMOOTH
, respectively.
The following function retrieves information related to the
glShadeModel
 function:
glGet
 with argument
GL_SHADE_MODEL
Errors
GL_INVALID_ENUM
 is generated if
mode
 is any value other than
GL_FLAT
 or
GL_SMOOTH
.
GL_INVALID_OPERATION
 is generated if
glShadeModel
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glColor
,
glLight
,
glLightModel


glStencilFunc
The
glStencilFunc
 function sets the function and reference value for stencil testing.
void
glStencilFunc
(
GLenum
func
,
GLint
ref
,
GLuint
mask
);
Parameters
func
Specifies the test function. Eight tokens are valid:
 GL_NEVER, GL_LESS, GL_LEQUAL, GL_GREATER, GL_GEQUAL, GL_EQUAL, GL_NOTEQUAL,
 and
GL_ALWAYS
.
ref
Specifies the reference value for the stencil test.
ref
is clamped to the range
[0,2^n
-
1],
where
n
 is the number of bitplanes in the stencil buffer.
mask
Specifies a mask that is ANDed with both the reference value and the stored stencil value when the test is done.
Remarks
Stenciling, like
z
-buffering, enables and disables drawing on a per-pixel basis. You draw into the stencil planes using GL drawing primitives, then render geometry and images, using the stencil planes to mask out portions of the screen. Stenciling is typically used in multipass rendering algorithms to achieve special effects, such as decals, outlining, and constructive solid geometry rendering.
The stencil test conditionally eliminates a pixel based on the outcome of a comparison between the reference value and the value in the stencil buffer. The test is enabled by
glEnable
 and
glDisable
 with argument
GL_STENCIL
. Actions taken based on the outcome of the stencil test are specified with
glStencilOp
.
The
 func
 parameter is a symbolic constant that determines the stencil comparison function. It accepts one of eight values, shown below.
ref
 is an integer reference value that is used in the stencil comparison. It is clamped to the range [0,2^
n
-
 1], where n is the number of bitplanes in the stencil buffer.
mask
 is bitwise ANDed with both the reference value and the stored stencil value, with the ANDed values participating in the comparison.
If
stencil
 represents the value stored in the corresponding stencil buffer location, the following list shows the effect of each comparison function that can be specified by
func
. Only if the comparison succeeds is the pixel passed through to the next stage in the rasterization process (see
glStencilOp
). All tests treat
stencil
 values as unsigned integers in the range [0,2^
n
-
 1], where
n
 is the number of bitplanes in the stencil buffer.
Here are the values accepted by
func
:
GL_NEVER
Always fails.
GL_LESS
Passes if (
ref
 &
mask
) < (
stencil
 &
mask
).
GL_LEQUAL
Passes if (
ref
 &
mask
)
£
 (
stencil
 &
mask
).
GL_GREATER
Passes if (
ref
 &
mask
) > (
stencil
 &
mask
).
GL_GEQUAL
Passes if (
ref
 &
mask
)
³
 (
stencil
 &
mask
).
GL_EQUAL
Passes if (
ref
 &
mask
) = (
stencil
 &
mask
).
GL_NOTEQUAL
Passes if (
ref
 &
mask
)
¹
  (
stencil
 &
mask
).
GL_ALWAYS
Always passes.
Initially, the stencil test is disabled. If there is no stencil buffer, no stencil modification can occur and it is as if the stencil test always passes.
The following functions retrieve information related to the
glStencilFunc
 function:
glGet
 with argument
GL_STENCIL_FUNC
glGet
 with argument
GL_STENCIL_VALUE_MASK
glGet
 with argument
GL_STENCIL_REF
glGet
 with argument
GL_STENCIL_BITS
glIsEnabled
 with argument
GL_STENCIL_TEST
Errors
GL_INVALID_ENUM
 is generated if
func
 is not one of the eight accepted values.
GL_INVALID_OPERATION
 is generated if
glStencilFunc
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glAlphaFunc
,
glBlendFunc
,
glDepthFunc
,
glEnable
,
glIsEnabled
,
glLogicOp
,
glStencilOp


glStencilMask
The
glStencilMask
function controls the writing of individual bits in the stencil planes.
void glStencilMask
(
GLuint
mask
);
Parameters
mask
Specifies a bit mask to enable and disable writing of individual bits in the stencil planes. Initially, the mask is all ones.
Remarks
The
glStencilMask
function controls the writing of individual bits in the stencil planes. The least significant
n
 bits of
mask
, where
n
 is the number of bits in the stencil buffer, specify a mask. Wherever a one appears in the mask, the corresponding bit in the stencil buffer is made writable. Where a zero appears, the bit is write-protected. Initially, all bits are enabled for writing.
The following functions retrieve information related to the
glStencilMask
 function:
glGet
 with argument
GL_STENCIL_WRITEMASK
glGet
 with argument
GL_STENCIL_BITS
Errors
GL_INVALID_OPERATION
 is generated if
glStencilMask
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glColorMask
,
glDepthMask
,
glIndexMask
,
glStencilFunc
,
glStencilOp


glStencilOp
The
glStencilOp
 function sets the stencil test actions.
void glStencilOp
(
GLenum
fail
,
GLenum
zfail
,
GLenum
zpass
);
Parameters
fail
Specifies the action to take when the stencil test fails. Six symbolic constants are accepted:
GL_KEEP, GL_ZERO, GL_REPLACE, GL_INCR, GL_DECR,
 and
GL_INVERT
.
zfail
Specifies stencil action when the stencil test passes, but the depth test fails. Accepts the same symbolic constants as
fail.
zpass
Specifies stencil action when both the stencil test and the depth test pass, or when the stencil test passes and either there is no depth buffer or depth testing is not enabled. Accepts the same symbolic constants as
 fail
.
Remarks
Stenciling, like
z
-buffering, enables and disables drawing on a per-pixel basis. You draw into the stencil planes using GL drawing primitives, then render geometry and images, using the stencil planes to mask out portions of the screen. Stenciling is typically used in multipass rendering algorithms to achieve special effects, such as decals, outlining, and constructive solid geometry rendering.
The stencil test conditionally eliminates a pixel based on the outcome of a comparison between the value in the stencil buffer and a reference value. The test is enabled with
glEnable
 and
glDisable
 calls with argument
GL_STENCIL
, and controlled with
glStencilFunc
.
The
glStencilOp
 function takes three arguments that indicate what happens to the stored stencil value while stenciling is enabled. If the stencil test fails, no change is made to the pixels color or depth buffers, and
fail
 specifies what happens to the stencil buffer contents. The six possible actions are as follows:
GL_KEEP
Keeps the current value.
GL_ZERO
Sets the stencil buffer value to zero.
GL_REPLACE
Sets the stencil buffer value to
ref
, as specified by
glStencilFunc
.
GL_INCR
Increments the current stencil buffer value. Clamps to the maximum representable unsigned value.
GL_DECR
Decrements the current stencil buffer value. Clamps to zero.
GL_INVERT
Bitwise inverts the current stencil buffer value.
Stencil buffer values are treated as unsigned integers. When incremented and decremented, values are clamped to 0 and 2^
n
 - 1, where
n
 is the value returned by querying
GL_STENCIL_BITS
.
The other two arguments to
glStencilOp
 specify stencil buffer actions should subsequent depth buffer tests succeed (
zpass
) or fail (
zfail
). (See
glDepthFunc
.) They are specified using the same six symbolic constants as
fail
. Note that
zfail
 is ignored when there is no depth buffer, or when the depth buffer is not enabled. In these cases,
fail
 and
zpass
 specify stencil action when the stencil test fails and passes, respectively.
Initially the stencil test is disabled. If there is no stencil buffer, no stencil modification can occur and it is as if the stencil tests always pass, regardless of any call to
glStencilOp
.
The following functions retrieve information related to the
glStencilOp
 function:
glGet
 with argument
GL_STENCIL_FAIL
glGet
 with argument
GL_STENCIL_PASS_DEPTH_PASS
glGet
 with argument
GL_STENCIL_PASS_DEPTH_FAIL
glGet
 with argument
GL_STENCIL_BITS
glIsEnabled
 with argument
GL_STENCIL_TEST
Errors
GL_INVALID_ENUM
 is generated if
fail
,
zfail
, or
zpass
 is any value other than the six defined constant values.
GL_INVALID_OPERATION
 is generated if
glStencilOp
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glAlphaFunc
,
glBlendFunc
,
glDepthFunc
,
glEnable
,
glLogicOp
,
glStencilFunc


glTexCoord
glTexCoord1d, glTexCoord1f, glTexCoord1i, glTexCoord1s, glTexCoord2d, glTexCoord2f, glTexCoord2i, glTexCoord2s, glTexCoord3d, glTexCoord3f, glTexCoord3i, glTexCoord3s, glTexCoord4d, glTexCoord4f, glTexCoord4i, glTexCoord4s, glTexCoord1dv, glTexCoord1fv, glTexCoord1iv, glTexCoord1sv, glTexCoord2dv, glTexCoord2fv, glTexCoord2iv, glTexCoord2sv, glTexCoord3dv, glTexCoord3fv, glTexCoord3iv, glTexCoord3sv, glTexCoord4dv, glTexCoord4fv, glTexCoord4iv, glTexCoord4sv
These functions set the current texture coordinates.
void glTexCoord1d
(
GLdouble
s
);
void
glTexCoord1f
(
GLfloat
s
);
void
glTexCoord1i
(
GLint
s
);
void
glTexCoord1s
(
GLshort
s
);
void
glTexCoord2d
(
GLdouble
s
,
GLdouble
t
);
void glTexCoord2f
(
GLfloat
s
,
GLfloat
t
);
void glTexCoord2i
(
GLint
s
,
GLint
t
);
void
glTexCoord2s
(
GLshort
s
,
GLshort
t
);
void glTexCoord3d
(
GLdouble
s
,
GLdouble
t
,
GLdouble
r
);
void
glTexCoord3f
(
GLfloat
s
,
GLfloat
t
,
GLfloat
r
);
void
glTexCoord3i
(
GLint
s
,
GLint
t
,
GLint
r
);
void
glTexCoord3s
(
GLshort
s
,
GLshort
t
,
GLshort
r
);
void
glTexCoord4d
(
GLdouble
s
,
GLdouble
t
,
GLdouble
r
,
GLdouble
q
);
void
glTexCoord4f
(
GLfloat
s
,
GLfloat
t
,
GLfloat
r
,
GLfloat
q
);
void
glTexCoord4i
(
GLint
s
,
GLint
t
,
GLint
r
,
GLint
q
);
void
glTexCoord4s
(
GLshort
s
,
GLshort
t
,
GLshort
r
,
GLshort
q
);
Parameters
s, t, r, q
Specify
s
,
t
,
r
, and
q
 texture coordinates. Not all parameters are present in all forms of the command.
void glTexCoord1dv
(
const GLdouble
*v
);
void glTexCoord1fv
(
const GLfloat
*v
);
void glTexCoord1iv
(
const GLint
*v
);
void glTexCoord1sv
(
const GLshort
*v
);
void glTexCoord2dv
(
const GLdouble
*v
);
void glTexCoord2fv
(
const GLfloat
*v
);
void glTexCoord2iv
(
const GLint
*v
);
void glTexCoord2sv
(
const GLshort
*v
);
void glTexCoord3dv
(
const GLdouble
*v
);
void glTexCoord3fv
(
const GLfloat
*v
);
void glTexCoord3iv
(
const GLint
*v
);
void glTexCoord3sv
(
const GLshort
*v
);
void glTexCoord4dv
(
const GLdouble
*v
);
void glTexCoord4fv
(
const GLfloat
*v
);
void glTexCoord4iv
(
const GLint
*v
);
void glTexCoord4sv
(
const GLshort
*v
)
Parameters
v
Specifies a pointer to an array of one, two, three, or four elements, which in turn specify the
s, t
,
r,
 and
q
 texture coordinates.
Remarks
The current texture coordinates are part of the data that is associated with polygon vertexes. They are set with
glTexCoord
.
The
 glTexCoord
 function specifies texture coordinates in one, two, three, or four dimensions.
glTexCoord1
 sets the current texture coordinates to (
s
, 0, 0, 1); a call to
glTexCoord2
 sets them to (
s
,
t
, 0, 1). Similarly,
glTexCoord3
 specifies the texture coordinates as (
s
,
t
,
r
, 1), and
glTexCoord4
 defines all four components explicitly as (
s
,
t
,
r
,
q
).
The current texture coordinates can be updated at any time. In particular,
glTexCoord
 can be called between a call to
glBegin
 and the corresponding call to
glEnd
.
The following function retrieves information related to the
glTexCoord
 function:
glGet
 with argument
GL_CURRENT_TEXTURE_COORDS
See Also
glVertex


glTexCoordPointerEXT
The
glTexCoordPointerEXT
 function defines an array of texture coordinates.
void
glTexCoordPointerEXT
(
GLint
size
,
GLenum
type
,
GLsizei
stride
,
GLsizei
count
,
const GLvoid
 *
pointer
);
Parameters
size
Specifies the number of coordinates per array element. The value of
size
 must be 1, 2, 3, or 4.
type
Specifies the datatype of each texture coordinate in the array using the following symbolic constants:
GL_SHORT
,
GL_INT
,
GL_FLOAT
, and
GL_DOUBLE_EXT
.
stride
Specifies the byte offset between consecutive array elements. When
stride
 is zero, the array elements are tightly packed in the array.
count
Specifies the number of array elements, counting from the first, that are static.
pointer
Specifies a pointer to the first coordinate of the first element in the array.
Remarks
The
 glTexCoordPointerEXT
 function specifies the location and data of an array of texture coordinates to use when rendering.The
size
 parameter specifies the number of coordinates used for each element of the array.The
type
 parameter specifies the datatype of each texture coordinate and the
stride
 parameter determines the byte offset from one array element to the next, enabling the packing of vertexes and attributes in a single array or storage in separate arrays. In some implementations storing the vertexes and attributes in a single array can be more efficient than using separate arrays. Starting from the first array element,
count
 indicates the total number of static elements. Your application can modify static elements, but once the elements are modified, the application must explicitly specify the array again before using the array for any rendering. Non-static array elements are not accessed until you call
glDrawArraysEXT
 or
glArrayElementEXT
.
A texture coordinate array is enabled when you specify the
 GL_TEXTURE_COORD_ARRAY_EXT
 constant with
glEnable
. When enabled,
glDrawArraysEXT
 and
glArrayElementEXT
 use the texture coordinate array. By default the texture coordinate array is disabled.
You cannot include
glTexCoordPointerEXT
 in display lists.
When you specify a texture coordinate array using
glTexCoordPointerEXT
, the values of all the function's texture coordinate array parameters are saved in a client-side state, and static array elements can be cached. Because the texture coordinate array parameters are client-side state, their values are not saved or restored by
glPushAttrib
 and
glPopAttrib
.
Although no error is generated when you call
glTexCoordPointerEXT
 within
glBegin
 and
glEnd
 pairs, the results are undefined.
Note
Note
  The
 glTexCoordPointerEXT
 function is an extension function that is not part of the standard OpenGL library but is part of the
GL_EXT_vertex_array
 extension. To check whether your implementation of OpenGL supports
glTexCoordPointerEXT
, call
glGetString
(
GL_EXTENSIONS
). If it returns
GL_EXT_vertex_array
,
glTexCoordPointerEXT
 is supported.
To obtain the address of an extension function, call
wglGetProcAddress
.
The following functions retrieve information related to the
glTexCoordPointerEXT
 function:
glIsEnabled
 with argument
GL_TEXTURE_COORD_ARRAY_EXT
glGet
 with argument
GL_TEXTURE_COORD_ARRAY_SIZE_EXT
glGet
 with argument
GL_TEXTURE_COORD_ARRAY_STRIDE_EXT
glGet
 with argument
GL_TEXTURE_COORD_ARRAY_COUNT_EXT
glGet
 with argument
GL_TEXTURE_COORD_ARRAY_TYPE_EXT
glGetPointervEXT
 with argument
GL_TEXTURE_COORD_ARRAY_POINTER_EXT
Errors
GL_INVALID_VALUE
 is generated if
size
 is not 1, 2, 3, or 4.
GL_INVALID_ENUM
 is generated if
type
 is not an accepted value.
GL_INVALID_VALUE
 is generated if
stride
 or
count
 is negative.
See Also
glArrayElementEXT
,
glColorPointerEXT
,
glDrawArraysEXT
,
glEdgeFlagPointerEXT
,
glGetPointervEXT
,
glIndexPointerEXT
,
glNormalPointerEXT
,
glVertexPointerEXT
,
glGetString
,
wglGetProcAddress


glTexEnv
glTexEnvf, glTexEnvi, glTexEnvfv, glTexEnviv
These functions set texture environment parameters.
void glTexEnvf
(
GLenum
target
,
GLenum
pname
,
GLfloat
param
);
void glTexEnvi
(
GLenum
target
,
GLenum
pname
,
GLint
param
);
Parameters
target
Specifies a texture environment. Must be
GL_TEXTURE_ENV
.
pname
Specifies the symbolic name of a single-valued texture environment parameter. Must be
GL_TEXTURE_ENV_MODE
.
param
Specifies a single symbolic constant, one of
GL_MODULATE
,
GL_DECAL
, or
GL_BLEND
.
void glTexEnvfv
(
GLenum
target
,
GLenum
pname
,
const GLfloat
*params
);
void glTexEnviv
(
GLenum
target
,
GLenum
pname
,
const GLint
*params
);
Parameters
target
Specifies a texture environment. Must be
GL_TEXTURE_ENV
.
pname
Specifies the symbolic name of a texture environment parameter. Accepted values are
GL_TEXTURE_ENV_MODE
 and
GL_TEXTURE_ENV_COLOR
.
params
Specifies a pointer to an array of parameters: either a single symbolic constant or an RGBA color.
Remarks
A texture environment specifies how texture values are interpreted when a fragment is textured.
target
 must be
GL_TEXTURE_ENV
.
pname
 can be either
GL_TEXTURE_ENV_MODE
 or
GL_TEXTURE_ENV_COLOR
.
If
pname
 is
GL_TEXTURE_ENV_MODE
, then
params
 is (or points to) the symbolic name of a texture function. Three texture functions are defined:
GL_MODULATE
,
 GL_DECAL
, and
GL_BLEND
.
A texture function acts on the fragment to be textured using the texture image value that applies to the fragment (see
glTexParameter
) and produces an RGBA color for that fragment. The following table shows how the RGBA color is produced for each of the three texture functions that can be chosen.
C
 is a triple of color values (RGB) and
A
 is the associated alpha value. RGBA values extracted from a texture image are in the range [0,1]. The subscript
f
 refers to the incoming fragment, the subscript
t
 to the texture image, the subscript
c
 to the texture environment color, and subscript
v
 indicates a value produced by the texture function.
A texture image can have up to four components per texture element (see
glTexImage1D
 and
glTexImage2D
). In a one-component image,
L
 (t)
indicates that single component. A two-component image uses
 L
 (t)
 and
A
 (t)
. A three-component image has only a color value,
C
 (t)
. A four-component image has both a color value
C
 (t)
 and an alpha value
A
 (t)
.
If
pname
 is
GL_TEXTURE_ENV_COLOR
,
params
 is a pointer to an array that holds an RGBA color consisting of four values. Integer color components are interpreted linearly such that the most positive integer maps to 1.0, and the most negative integer maps to
-
1.0. The values are clamped to the range [0,1] when they are specified.
C
 (c)
 takes these four values.
GL_TEXTURE_ENV_MODE
 defaults to
GL_MODULATE
 and
GL_TEXTURE_ENV_COLOR
 defaults to (0,0,0,0).
The following function retrieves information related to the
glTexEnv
 function:
glGetTexEnv
Errors
GL_INVALID_ENUM
 is generated when
target
 or
pname
 is not one of the accepted defined values, or when
params
 should have a defined constant value (based on the value of
pname
) and does not.
GL_INVALID_OPERATION
 is generated if
glTexEnv
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glTexImage1D
,
glTexImage2D
,
glTexParameter


glTexGen
glTexGend, glTexGenf, glTexGeni, glTexGendv, glTexGenfv, glTexGeniv
These functions control the generation of texture coordinates.
void glTexGend
(
GLenum
coord
,
GLenum
pname
,
GLdouble
param
);
void glTexGenf
(
GLenum
coord
,
GLenum
pname
,
GLfloat
param
);
void glTexGeni
(
GLenum
coord
,
GLenum
pname
,
GLint
param
);
Parameters
coord
Specifies a texture coordinate. Must be one of the following:
GL_S, GL_T, GL_R,
or
GL_Q
.
pname
Specifies the symbolic name of the texture-coordinate generation function. Must be
GL_TEXTURE_GEN_MODE
.
param
Specifies a single-valued texture generation parameter, one of
GL_OBJECT_LINEAR
,
GL_EYE_LINEAR
, or
GL_SPHERE_MAP
.
void glTexGendv
(
GLenum
coord
,
GLenum
pname
,
const GLdouble
*params
);
void glTexGenfv
(
GLenum
coord
,
GLenum
pname
,
const GLfloat
*params
);
void glTexGeniv
(
GLenum
coord
,
GLenum
pname
,
const GLint
*params
);
Parameters
coord
Specifies a texture coordinate. Must be one of the following:
GL_S, GL_T, GL_R,
 or
GL_Q
.
pname
Specifies the symbolic name of the texture-coordinate generation function or function parameters. Must be
GL_TEXTURE_GEN_MODE, GL_OBJECT_PLANE,
 or
GL_EYE_PLANE
.
params
Specifies a pointer to an array of texture generation parameters. If
pname
 is
GL_TEXTURE_GEN_MODE
, then the array must contain a single symbolic constant, one of
GL_OBJECT_LINEAR
,
GL_EYE_LINEAR
, or
GL_SPHERE_MAP
. Otherwise, params holds the coefficients for the texture-coordinate generation function specified by
pname
.
Remarks
The
 glTexGen
 function selects a texture-coordinate generation function or supplies coefficients for one of the functions.
coord
 names one of the (
s
,
t
,
r
,
q
) texture coordinates, and it must be one of these symbols:
GL_S, GL_T
,
GL_R,
 or
GL_Q
.
pname
 must be one of three symbolic constants:
GL_TEXTURE_GEN_MODE, GL_OBJECT_PLANE
, or
GL_EYE_PLANE.
If
pname
 is
GL_TEXTURE_GEN_MODE
, then
params
 chooses a mode, one of
GL_OBJECT_LINEAR, GL_EYE_LINEAR
, or
GL_SPHERE_MAP.
If
pname
 is either
GL_OBJECT_PLANE
 or
GL_EYE_PLANE
,
params
 contains coefficients for the corresponding texture generation function.
If the texture generation function is
GL_OBJECT_LINEAR
, the function
is used, where
g
 is the value computed for the coordinate named in
coord
,
p
 (1)
,
p
 (2)
,
p
 (3)
, and
p
 (4)
 are the four values supplied in
params
, and
x
 (o)
,
y
 (o)
,
z
 (o)
, and
w
 (o)
 are the object coordinates of the vertex. This function can be used to texture-map terrain using sea level as a reference plane (defined by
p
 (1)
,
p
 (2)
,
p
 (3)
, and
p
 (4)
). The altitude of a terrain vertex is computed by the
GL_OBJECT_LINEAR
 coordinate generation function as its distance from sea level; that altitude is used to index the texture image to map white snow onto peaks and green grass onto foothills, for example.
If the texture generation function is
GL_EYE_LINEAR
, the function
is used, where
and
x
 (e)
, y
 (e)
, z
 (e)
,
 and
w
 (e)
 are the eye coordinates of the vertex,
p
 (1)
,
p
 (2)
,
p
 (3)
, and
p
 (4)
 are the values supplied in
params
, and
M
 is the modelview matrix when
glTexGen
 is invoked. If
M
 is poorly conditioned or singular, texture coordinates generated by the resulting function may be inaccurate or undefined.
Note that the values in
params
 define a reference plane in eye coordinates. The modelview matrix that is applied to them may not be the same one in effect when the polygon vertexes are transformed. This function establishes a field of texture coordinates that can produce dynamic contour lines on moving objects.
If
pname
 is
GL_SPHERE_MAP
 and
coord
 is either
GL_S
 or
GL_T
,
s
 and
t
 texture coordinates are generated as follows. Let
u
 be the unit vector pointing from the origin to the polygon vertex (in eye coordinates).  Let
n
¢
 be the current normal, after transformation to eye coordinates. Let
f
 = (
f
 (x )
f
 (y )
f
 (z)
)
T
 be the reflection vector such that
Finally, let
Then the values assigned to the
i
 and
t
 texture coordinates are
A texture-coordinate generation function is enabled or disabled using
glEnable
 or
glDisable
 with one of the symbolic texture-coordinate names (
GL_TEXTURE_GEN_S
,
GL_TEXTURE_GEN_T
,
GL_TEXTURE_GEN_R
, or
GL_TEXTURE_GEN_Q
) as the argument. When enabled, the specified texture coordinate is computed according to the generating function associated with that coordinate. When disabled, subsequent vertexes take the specified texture coordinate from the current set of texture coordinates. Initially, all texture generation functions are set to
GL_EYE_LINEAR
 and are disabled. Both
s
 plane equations are (1,0,0,0), both
t
 plane equations are (0,1,0,0), and all
r
 and
q
 plane equations are (0,0,0,0).
The following functions retrieve information related to the
glTexGen
 function:
glGetTexGen
glIsEnabled
 with argument
GL_TEXTURE_GEN_S
glIsEnabled
 with argument
GL_TEXTURE_GEN_T
glIsEnabled
 with argument
GL_TEXTURE_GEN_R
glIsEnabled
 with argument
GL_TEXTURE_GEN_Q
Errors
GL_INVALID_ENUM
 is generated when
coord
 or
pname
 is not an accepted defined value, or when
pname
 is
GL_TEXTURE_GEN_MODE
 and
params
 is not an accepted defined value.
GL_INVALID_ENUM
 is generated when
pname
 is
GL_TEXTURE_GEN_MODE
,
params
 is
GL_SPHERE_MAP
, and
coord
 is either
GL_R
 or
GL_Q
.
GL_INVALID_OPERATION
 is generated if
glTexGen
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glTexEnv
,
glTexImage1D
,
glTexImage2D
,
glTexParameter


glTexImage1D
The
glTexImage1D
 function specifies a one-dimensional texture image.
void
glTexImage1D
(
GLenum
target
,
GLint
level
,
GLint
components
,
GLsizei
width
,
GLint
border
,
GLenum
format
,
GLenum
type
,
const GLvoid
*pixels
);
Parameters
target
Specifies the target texture. Must be
GL_TEXTURE_1D
.
level
Specifies the level-of-detail number. Level 0 is the base image level. Level
n
 is the
n
th mipmap reduction image.
components
Specifies the number of color components in the texture. Must be 1, 2, 3, or 4.
width
Specifies the width of the texture image. Must be 2^
n
 + 2(
border
) for some integer
n
. The height of the texture image is 1.
border
Specifies the width of the border. Must be either 0 or 1.
format
Specifies the format of the pixel data. The following symbolic values are accepted:
GL_COLOR_INDEX, GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA, GL_RGB, GL_RGBA, GL_LUMINANCE,
 and
GL_LUMINANCE_ALPHA
.
type
Specifies the data type of the pixel data. The following symbolic values are accepted:
GL_UNSIGNED_BYTE, GL_BYTE, GL_BITMAP, GL_UNSIGNED_SHORT, GL_SHORT, GL_UNSIGNED_INT, GL_INT,
and
GL_FLOAT
.
pixels
Specifies a pointer to the image data in memory.
Remarks
Texturing maps a portion of a specified
texture image
 onto each graphical primitive for which texturing is enabled. One-dimensional texturing is enabled and disabled using
glEnable
 and
glDisable
 with argument
GL_TEXTURE_1D
.
Texture images are defined with
glTexImage1D
. The arguments describe the parameters of the texture image, such as width, width of the border, level-of-detail number (see
glTexParameter
), and number of color components provided. The last three arguments describe the way the image is represented in memory, and they are identical to the pixel formats used for
glDrawPixels
.
Data is read from
pixels
 as a sequence of signed or unsigned bytes, shorts, or longs, or single-precision floating-point values, depending on
type
. These values are grouped into sets of one, two, three, or four values, depending on
format
, to form elements. If
type
 is
GL_BITMAP
, the data is considered as a string of unsigned bytes (and
format
 must be
GL_COLOR_INDEX
). Each data byte is treated as eight 1-bit elements, with bit ordering determined by
GL_UNPACK_LSB_FIRST
 (see
glPixelStore
).
The
 format
 parameter determines the composition of each element in
pixels
. It can assume one of nine symbolic values:
GL_COLOR_INDEX
Each element is a single value, a color index. It is converted to fixed point (with an unspecified number of zero bits to the right of the binary point), shifted left or right depending on the value and sign of
GL_INDEX_SHIFT
, and added to
GL_INDEX_OFFSET
 (see
glPixelTransfer
).  The resulting index is converted to a set of color components using the
GL_PIXEL_MAP_I_TO_R, GL_PIXEL_MAP_I_TO_G,
GL_PIXEL_MAP_I_TO_B,
 and
GL_PIXEL_MAP_I_TO_A
 tables, and clamped to the range [0,1].
GL_RED
Each element is a single red component. It is converted to floating point and assembled into an RGBA element by attaching 0.0 for green and blue, and 1.0 for alpha. Each component is then multiplied by the signed scale factor
GL_c_SCALE
, added to the signed bias
GL_c_BIAS
, and clamped to the range [0,1] (see
glPixelTransfer
).
GL_GREEN
Each element is a single green component. It is converted to floating point and assembled into an RGBA element by attaching 0.0 for red and blue, and 1.0 for alpha. Each component is then multiplied by the signed scale factor
GL_c_SCALE
, added to the signed bias
GL_c_BIAS
, and clamped to the range [0,1] (see
glPixelTransfer
).
GL_BLUE
Each element is a single blue component. It is converted to floating point and assembled into an RGBA element by attaching 0.0 for red and green, and 1.0 for alpha.  Each component is then multiplied by the signed scale factor
GL_c_SCALE
, added to the signed bias
GL_c_BIAS
, and clamped to the range [0,1] (see
glPixelTransfer
).
GL_ALPHA
Each element is a single red component. It is converted to floating point and assembled into an RGBA element by attaching 0.0 for red, green, and blue. Each component is then multiplied by the signed scale factor
GL_c_SCALE
, added to the signed bias
GL_c_BIAS
, and clamped to the range [0,1] (see
glPixelTransfer
).
GL_RGB
Each element is an RGB triple. It is converted to floating point and assembled into an RGBA element by attaching 1.0 for alpha. Each component is then multiplied by the signed scale factor
GL_c_SCALE
, added to the signed bias
GL_c_BIAS
, and clamped to the range [0,1] (see
glPixelTransfer
).
GL_RGBA
Each element is a complete RGBA element. It is converted to floating point. Each component is then multiplied by the signed scale factor
GL_c_SCALE
, added to the signed bias
GL_c_BIAS
, and clamped to the range [0,1] (see
glPixelTransfer
).
GL_LUMINANCE
Each element is a single luminance value. It is converted to floating point, then assembled into an RGBA element by replicating the luminance value three times for red, green, and blue and attaching 1.0 for alpha. Each component is then multiplied by the signed scale factor
GL_c_SCALE
, added to the signed bias
GL_c_BIAS
, and clamped to the range [0,1] (see
glPixelTransfer
).
GL_LUMINANCE_ALPHA
Each element is a luminance/alpha pair. It is converted to floating point, then assembled into an RGBA element by replicating the luminance value three times for red, green, and blue. Each component is then multiplied by the signed scale factor
GL_c_SCALE
, added to the signed bias
GL_c_BIAS
, and clamped to the range [0,1] (see
glPixelTransfer
).
A texture image can have up to four components per texture element, depending on
components
. A one-component texture image uses only the red component of the RGBA color extracted from
pixels
.  A two-component image uses the R and A values. A three-component image uses the R, G, and B values. A four-component image uses all of the RGBA components.
Texturing has no effect in color index mode.
The texture image can be represented by the same data formats as the pixels in a
glDrawPixels
 command, except that
GL_STENCIL_INDEX
 and
GL_DEPTH_COMPONENT
 cannot be used.
glPixelStore
 and
glPixelTransfer
 modes affect texture images in exactly the way they affect
glDrawPixels
.
A texture image with zero width indicates the null texture. If the null texture is specified for level-of-detail 0, it is as if texturing were disabled.
The following functions retrieve information related to the
glTexImageID
 function:
glGetTexImage
glIsEnabled
 with argument
GL_TEXTURE_1D
Errors
GL_INVALID_ENUM
 is generated when
target
 is not
GL_TEXTURE_1D
.
GL_INVALID_ENUM
 is generated when
format
 is not an accepted
format
 constant. Format constants other than
GL_STENCIL_INDEX
 and
GL_DEPTH_COMPONENT
 are accepted.
GL_INVALID_ENUM
 is generated when
type
 is not a
type
 constant.
GL_INVALID_ENUM
 is generated if
type
 is
GL_BITMAP
 and
format
 is not
GL_COLOR_INDEX
.
GL_INVALID_VALUE
 is generated if
level
 is less than zero or greater than log
 (2)
max
, where
max
 is the returned value of
GL_MAX_TEXTURE_SIZE
.
GL_INVALID_VALUE
 is generated if
components
 is not 1, 2, 3, or 4.
GL_INVALID_VALUE
 is generated if
width
 is less than zero or greater than  2 +
GL_MAX_TEXTURE_SIZE
, or if it cannot be represented as 2^
n
 + 2(
border
) for some integer value of
n
.
GL_INVALID_VALUE
 is generated if
border
 is not 0 or 1.
GL_INVALID_OPERATION
 is generated if
glTexImage1D
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glDrawPixels
,
glFog
,
glPixelStore
,
glPixelTransfer
,
glTexEnv
,
glTexGen
,
glTexImage2D
,
glTexParameter


glTexImage2D
The
glTexImage2D
 function specifies a two-dimensional texture image.
void glTexImage2D
(
GLenum
target
,
GLint
level
,
GLint
components
,
GLsizei
width
,
GLsizei
height
,
GLint
border
,
GLenum
format
,
GLenum
type
,
const GLvoid
*pixels
);
Parameters
target
Specifies the target texture. Must be
GL_TEXTURE_2D
.
level
Specifies the level-of-detail number. Level 0 is the base image level. Level
n
 is the
n
th mipmap reduction image.
components
Specifies the number of color components in the texture. Must be 1, 2, 3, or 4.
width
Specifies the width of the texture image. Must be 2^
n
 + 2(
border
) for some integer
n
.
height
Specifies the height of the texture image. Must be 2^
m
 + 2(
border
) for some integer
m
.
border
Specifies the width of the border. Must be either 0 or 1.
format
Specifies the format of the pixel data. The following symbolic values are accepted:
GL_COLOR_INDEX, GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA, GL_RGB, GL_RGBA, GL_LUMINANCE,
 and
GL_LUMINANCE_ALPHA.
type
Specifies the data type of the pixel data. The following symbolic values are accepted:
GL_UNSIGNED_BYTE, GL_BYTE, GL_BITMAP, GL_UNSIGNED_SHORT, GL_SHORT, GL_UNSIGNED_INT, GL_INT,
and
GL_FLOAT
.
pixels
Specifies a pointer to the image data in memory.
Remarks
Texturing maps a portion of a specified
texture image
 onto each graphical primitive for which texturing is enabled. Two-dimensional texturing is enabled and disabled using
glEnable
 and
glDisable
 with argument
GL_TEXTURE_2D
.
Texture images are defined with
glTexImage2D
. The arguments describe the parameters of the texture image, such as height, width, width of the border, level-of-detail number (see
glTexParameter
), and number of color components provided. The last three arguments describe the way the image is represented in memory, and they are identical to the pixel formats used for
glDrawPixels
.
Data is read from
pixels
 as a sequence of signed or unsigned bytes, shorts, or longs, or single-precision floating-point values, depending on
type
. These values are grouped into sets of one, two, three, or four values, depending on
format
, to form elements. If
type
 is
GL_BITMAP
, the data is considered as a string of unsigned bytes (and
format
 must be
GL_COLOR_INDEX
). Each data byte is treated as eight 1-bit elements, with bit ordering determined by
GL_UNPACK_LSB_FIRST
 (see
glPixelStore
).
The
 format
 parameter determines the composition of each element in
pixels
. It can assume one of nine symbolic values:
GL_COLOR_INDEX
Each element is a single value, a color index. It is converted to fixed point (with an unspecified number of zero bits to the right of the binary point), shifted left or right depending on the value and sign of
GL_INDEX_SHIFT
, and added to
GL_INDEX_OFFSET
 (see
glPixelTransfer
). The resulting index is converted to a set of color components using the
GL_PIXEL_MAP_I_TO_R, GL_PIXEL_MAP_I_TO_G, GL_PIXEL_MAP_I_TO_B
, and
 GL_PIXEL_MAP_I_TO_A
tables, and clamped to the range [0,1].
GL_RED
Each element is a single red component. It is converted to floating point and assembled into an RGBA element by attaching 0.0 for green and blue, and 1.0 for alpha. Each component is then multiplied by the signed scale factor
GL_c_SCALE
, added to the signed bias
GL_c_BIAS
, and clamped to the range [0,1] (see
glPixelTransfer
).
GL_GREEN
Each element is a single green component. It is converted to floating point and assembled into an RGBA element by attaching 0.0 for red and blue, and 1.0 for alpha.  Each component is then multiplied by the signed scale factor
GL_c_SCALE
, added to the signed bias
GL_c_BIAS
, and clamped to the range [0,1] (see
glPixelTransfer
).
GL_BLUE
Each element is a single blue component. It is converted to floating point and assembled into an RGBA element by attaching 0.0 for red and green, and 1.0 for alpha. Each component is then multiplied by the signed scale factor
GL_c_SCALE
, added to the signed bias
GL_c_BIAS
, and clamped to the range [0,1] (see
glPixelTransfer
).
GL_ALPHA
Each element is a single red component. It is converted to floating point and assembled into an RGBA element by attaching 0.0 for red, green, and blue. Each component is then multiplied by the signed scale factor
GL_c_SCALE
, added to the signed bias
GL_c_BIAS
, and clamped to the range [0,1] (see
glPixelTransfer
).
GL_RGB
Each element is an RGB triple. It is converted to floating point and assembled into an RGBA element by attaching 1.0 for alpha. Each component is then multiplied by the signed scale factor
GL_c_SCALE
, added to the signed bias
GL_c_BIAS
, and clamped to the range [0,1] (see
glPixelTransfer
).
GL_RGBA
Each element is a complete RGBA element. It is converted to floating point. Each component is then multiplied by the signed scale factor
GL_c_SCALE
, added to the signed bias
GL_c_BIAS
, and clamped to the range [0,1] (see
glPixelTransfer
).
GL_LUMINANCE
Each element is a single luminance value. It is converted to floating point, then assembled into an RGBA element by replicating the luminance value three times for red, green, and blue and attaching 1.0 for alpha.  Each component is then multiplied by the signed scale factor
GL_c_SCALE
, added to the signed bias
GL_c_BIAS
, and clamped to the range [0,1] (see
glPixelTransfer
).
GL_LUMINANCE_ALPHA
Each element is a luminance/alpha pair. It is converted to floating point, then assembled into an RGBA element by replicating the luminance value three times for red, green, and blue. Each component is then multiplied by the signed scale factor
GL_c_SCALE
, added to the signed bias
GL_c_BIAS
, and clamped to the range [0,1] (see
glPixelTransfer
).
Please see
glDrawPixels
 for a description of the acceptable values for the
type
 parameter. A texture image can have up to four components per texture element, depending on
components
. A one-component texture image uses only the red component of the RGBA color extracted from
pixels
. A two-component image uses the R and A values. A three-component image uses the R, G, and B values. A four-component image uses all of the RGBA components.
Texturing has no effect in color index mode.
The texture image can be represented by the same data formats as the pixels in a
glDrawPixels
 command, except that
GL_STENCIL_INDEX
 and
GL_DEPTH_COMPONENT
 cannot be used.
glPixelStore
 and
glPixelTransfer
 modes affect texture images in exactly the way they affect
glDrawPixels
.
A texture image with zero height or width indicates the null texture. If the null texture is specified for level-of-detail 0, it is as if texturing were disabled.
The following functions retrieve information related to the
glTexImage2D
 function:
glGetTexImage
glIsEnabled
 with argument
GL_TEXTURE_2D
Errors
GL_INVALID_ENUM
 is generated when
target
 is not
GL_TEXTURE_2D
.
GL_INVALID_ENUM
 is generated when
format
 is not an accepted
format
 constant. Format constants other than
GL_STENCIL_INDEX
 and
GL_DEPTH_COMPONENT
 are accepted.
GL_INVALID_ENUM
 is generated when
type
 is not a
type
 constant.
GL_INVALID_ENUM
 is generated if
type
 is
GL_BITMAP
 and
format
 is not
GL_COLOR_INDEX
.
GL_INVALID_VALUE
 is generated if
level
 is less than zero or greater than log
 (2)
 max, where
max
 is the returned value of
GL_MAX_TEXTURE_SIZE
.
GL_INVALID_VALUE
 is generated if
components
 is not 1, 2, 3, or 4.
GL_INVALID_VALUE
 is generated if
width
 or
height
 is less than zero or greater than 2 +
GL_MAX_TEXTURE_SIZE
, or if either cannot be represented as 2^
k
 + 2(
border
) for some integer value of
k
.
GL_INVALID_VALUE
 is generated if
border
 is not 0 or 1.
GL_INVALID_OPERATION
 is generated if
glTexImage2D
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glDrawPixels
,
glFog
,
glPixelStore
,
glPixelTransfer
,
glTexEnv
,
glTexGen
,
glTexImage1D
,
glTexParameter


glTexParameter
glTexParameterf, glTexParameteri, glTexParameterfv, glTexParameteriv
These functions set texture parameters.
void
glTexParameterf
(
GLenum
target
,
GLenum
pname
,
GLfloat
param
);
void glTexParameteri
(
GLenum
target
,
GLenum
pname
,
GLint
param
);
Parameters
target
Specifies the target texture, which must be either
GL_TEXTURE_1D
 or
GL_TEXTURE_2D
.
pname
Specifies the symbolic name of a single-valued texture parameter.
pname
can be one of the following:
GL_TEXTURE_MIN_FILTER, GL_TEXTURE_MAG_FILTER, GL_TEXTURE_WRAP_S,
 or
GL_TEXTURE_WRAP_T
.
param
Specifies the value of
pname
.
void glTexParameterfv
(
GLenum
target
,
GLenum
pname
,
const GLfloat
*params
);
void glTexParameteriv
(
GLenum
target
,
GLenum
pname
,
const GLint
*params
);
Parameters
target
Specifies the target texture, which must be either
GL_TEXTURE_1D
 or
GL_TEXTURE_2D
.
pname
Specifies the symbolic name of a texture parameter.The
pname
parameter can be one of the following:
GL_TEXTURE_MIN_FILTER, GL_TEXTURE_MAG_FILTER,
GL_TEXTURE_WRAP_S, GL_TEXTURE_WRAP_T,
 or
GL_TEXTURE_BORDER_COLOR.
params
Specifies a pointer to an array where the value or values of
pname
 are stored.
Remarks
Texture mapping is a technique that applies an image onto an object's surface as if the image were a decal or cellophane shrink-wrap. The image is created in texture space, with an (
s, t
) coordinate system. A texture is a one- or two-dimensional image and a set of parameters that determine how samples are derived from the image.
The
 glTexParameter
 function assigns the value or values in
params
 to the texture parameter specified as
pname
.
target
 defines the target texture, either
GL_TEXTURE_1D
 or
GL_TEXTURE_2D
. The following symbols are accepted in
pname
:
GL_TEXTURE_MIN_FILTER
The texture minifying function is used whenever the pixel being textured maps to an area greater than one texture element. There are six defined minifying functions. Two of them use the nearest one or nearest four texture elements to compute the texture value. The other four use mipmaps.
A mipmap is an ordered set of arrays representing the same image at progressively lower resolutions. If the texture has dimensions 2^
n
x2^
m
 there are
max
(
n
,
m
) + 1 mipmaps. The first mipmap is the original texture, with dimensions 2^
n
x2^
m
. Each subsequent mipmap has dimensions 2^
k
 (
-
1)
x2^
l
 (
-
1)
 where 2^
k
x2^
l
 are the dimensions of the previous mipmap, until either
k
 = 0 or
l
 = 0. At that point, subsequent mipmaps have dimension 1x2^
l
-
1
 or 2^
k
-
1
x1 until the final mipmap, which has dimension 1x1. Mipmaps are defined using
glTexImage1D
 or
glTexImage2D
 with the level-of-detail argument indicating the order of the mipmaps. Level 0 is the original texture; level bold max(
n, m
) is the final 1x1 mipmap.
The
 params
 parameter supplies a function for minifying the texture as one of the following:
GL_NEAREST
Returns the value of the texture element that is nearest (in Manhattan distance) to the center of the pixel being textured.
GL_LINEAR
Returns the weighted average of the four texture elements that are closest to the center of the pixel being textured. These can include border texture elements, depending on the values of
GL_TEXTURE_WRAP_S
 and
GL_TEXTURE_WRAP_T
, and on the exact mapping.
GL_NEAREST_MIPMAP_NEAREST
Chooses the mipmap that most closely matches the size of the pixel being textured and uses the
GL_NEAREST
 criterion (the texture element nearest to the center of the pixel) to produce a texture value.
GL_LINEAR_MIPMAP_NEAREST
Chooses the mipmap that most closely matches the size of the pixel being textured and uses the
GL_LINEAR
 criterion (a weighted average of the four texture elements that are closest to the center of the pixel) to produce a texture value.
GL_NEAREST_MIPMAP_LINEAR
Chooses the two mipmaps that most closely match the size of the pixel being textured and uses the
GL_NEAREST
 criterion (the texture element nearest to the center of the pixel) to produce a texture value from each mipmap.  The final texture value is a weighted average of those two values.
GL_LINEAR_MIPMAP_LINEAR
Chooses the two mipmaps that most closely match the size of the pixel being textured and uses the
GL_LINEAR
 criterion (a weighted average of the four texture elements that are closest to the center of the pixel) to produce a texture value from each mipmap. The final texture value is a weighted average of those two values.
As more texture elements are sampled in the minification process, fewer aliasing artifacts will be apparent. While the
GL_NEAREST
 and
GL_LINEAR
 minification functions can be faster than the other four, they sample only one or four texture elements to determine the texture value of the pixel being rendered and can produce moire patterns or ragged transitions. The default value of
GL_TEXTURE_MIN_FILTER
 is
GL_NEAREST_MIPMAP_LINEAR
.
GL_TEXTURE_MAG_FILTER
The texture magnification function is used when the pixel being textured maps to an area less than or equal to one texture element. It sets the texture magnification function to either of the following:
GL_NEAREST
Returns the value of the texture element that is nearest (in Manhattan distance) to the center of the pixel being textured.
GL_LINEAR
Returns the weighted average of the four texture elements that are closest to the center of the pixel being textured. These can include border texture elements, depending on the values of
GL_TEXTURE_WRAP_S
 and
GL_TEXTURE_WRAP_T
, and on the exact mapping.
GL_NEAREST
 is generally faster than
GL_LINEAR
, but it can produce textured images with sharper edges because the transition between texture elements is not as smooth.  The default value of
GL_TEXTURE_MAG_FILTER
 is
GL_LINEAR
.
GL_TEXTURE_WRAP_S
Sets the wrap parameter for texture coordinate
s
 to either
GL_CLAMP
 or
GL_REPEAT
.
GL_CLAMP
 causes
s
 coordinates to be clamped to the range [0,1] and is useful for preventing wrapping artifacts when mapping a single image onto an object.
GL_REPEAT
 causes the integer part of the
s
 coordinate to be ignored; the GL uses only the fractional part, thereby creating a repeating pattern. Border texture elements are accessed only if wrapping is set to
GL_CLAMP
. Initially,
GL_TEXTURE_WRAP_S
 is set to
GL_REPEAT
.
GL_TEXTURE_WRAP_T
Sets the wrap parameter for texture coordinate
t
 to either
GL_CLAMP
 or
GL_REPEAT
. See the discussion under
GL_TEXTURE_WRAP_S
.  Initially,
GL_TEXTURE_WRAP_T
 is set to
GL_REPEAT
.
GL_TEXTURE_BORDER_COLOR
Sets a border color. The
params
 parameter contains four values that comprise the RGBA color of the texture border. Integer color components are interpreted linearly such that the most positive integer maps to 1.0, and the most negative integer maps to
-
1.0. The values are clamped to the range [0,1] when they are specified. Initially, the border color is (0, 0, 0, 0).
Suppose texturing is enabled (by calling
glEnable
 with argument
GL_TEXTURE_1D
 or
GL_TEXTURE_2D
) and
GL_TEXTURE_MIN_FILTER
 is set to one of the functions that requires a mipmap. If either the dimensions of the texture images currently defined (with previous calls to
glTexImage1D
 or
glTexImage2D
) do not follow the proper sequence for mipmaps, or there are fewer texture images defined than are needed, or the set of texture images have differing numbers of texture components, then it is as if texture mapping were disabled.
Linear filtering accesses the four nearest texture elements only in 2-D textures. In 1-D textures, linear filtering accesses the two nearest texture elements.
The following functions retrieve information related to the
glTexParameterf, glTexParameteri, glTexParameterfv,
 and
glTexParameteriv
 functions:
glGet
TexParameter
glGetTexLevelParameter
Errors
GL_INVALID_ENUM
 is generated when
target
 or
pname
 is not one of the accepted defined values, or when
params
 should have a defined constant value (based on the value of
pname
) and does not.
GL_INVALID_OPERATION
 is generated if
glTexParameter
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glTexEnv
,
glTexImage1D
,
glTexImage2D
,
glTexGen


glTranslate
glTranslated, glTranslatef
The
glTranslated
 and
glTranslatef
 functions multiply the current matrix by a translation matrix.
void glTranslated
(
GLdouble
x
,
GLdouble
y
,
GLdouble
z
);
void glTranslatef
(
GLfloat
x
,
GLfloat
y
,
GLfloat
z
);
Parameters
x, y, z
Specify the
x
,
y
, and
z
 coordinates of a translation vector.
Remarks
The
 glTranslate
 function moves the coordinate system origin to the point specified by (
x
,
y
,
z
). The translation vector is used to compute a 4x4 translation matrix:
The current matrix (see
glMatrixMode
) is multiplied by this translation matrix, with the product replacing the current matrix. That is, if M is the current matrix and T is the translation matrix, then M is replaced with M
·
T.
If the matrix mode is either
GL_MODELVIEW
 or
GL_PROJECTION
, all objects drawn after
glTranslate
 is called are translated. Use
glPushMatrix
 and
glPopMatrix
 to save and restore the untranslated coordinate system.
The following functions retrieve information related to the
glTranslated
 and
glTranslatef
 functions:
glGet
 with argument
GL_MATRIX_MODE
glGet
 with argument
GL_MODELVIEW_MATRIX
glGet
 with argument
GL_PROJECTION_MATRIX
glGet
 with argument
GL_TEXTURE_MATRIX
Errors
GL_INVALID_OPERATION
 is generated if
glTranslate
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glMatrixMode
,
glMultMatrix
,
glPushMatrix
,
glRotate
,
glScale


glVertex
glVertex2d, glVertex2f, glVertex2i, glVertex2s, glVertex3d, glVertex3f, glVertex3i, glVertex3s, glVertex4d, glVertex4f, glVertex4i, glVertex4s, glVertex2dv, glVertex2fv, glVertex2iv, glVertex2sv, glVertex3dv, glVertex3fv, glVertex3iv, glVertex3sv, glVertex4dv, glVertex4fv, glVertex4iv, glVertex4sv
These functions specify a vertex.
void glVertex2d
(
GLdouble
x
,
GLdouble
y
);
void glVertex2f
(
GLfloat
x
,
GLfloat
y
);
void glVertex2i
(
GLint
x
,
GLint
y
);
void glVertex2s
(
GLshort
x
,
GLshort
y
);
void glVertex3d
(
GLdouble
x
,
GLdouble
y
,
GLdouble
z
);
void
glVertex3f
(
GLfloat
x
,
GLfloat
y
,
GLfloat
z
);
void
glVertex3i
(
GLint
x
,
GLint
y
,
GLint
z
);
void glVertex3s
(
GLshort
x
,
GLshort
y
,
GLshort
z
);
void glVertex4d
(
GLdouble
x
,
GLdouble
y
,
GLdouble
z
,
GLdouble
w
);
void
glVertex4f
(
GLfloat
x
,
GLfloat
y
,
GLfloat
z
,
GLfloat
w
);
void glVertex4i
(
GLint
x
,
GLint
y
,
GLint
z
,
GLint
w
);
void glVertex4s
(
GLshort
x
,
GLshort
y
,
GLshort
z
,
GLshort
w
);
Parameters
x, y, z, w
Specify
x
,
y
,
z
, and
w
 coordinates of a vertex. Not all parameters are present in all forms of the command.
void
glVertex2dv
(
const GLdouble
*v
);
void glVertex2fv
(
const GLfloat
*v
);
void glVertex2iv
(
const GLint
*v
);
void
glVertex2sv
(
const GLshort
*v
);
void
glVertex3dv
(
const GLdouble
*v
);
void
glVertex3fv
(
const GLfloat
*v
);
void
glVertex3iv
(
const GLint
*v
);
void
glVertex3sv
(
const GLshort
*v
);
void
glVertex4dv
(
const GLdouble
*v
);
void
glVertex4fv
(
const GLfloat
*v
);
void glVertex4iv
(
const GLint
*v
);
void
glVertex4sv
(
const GLshort
*v
);
Parameters
v
Specifies a pointer to an array of two, three, or four elements. The elements of a two-element array are
x
 and
y
; of a three-element array,
x
,
y
, and
z
; and of a four-element array,
x
,
y
,
z
, and
w
.
Remarks
The
 glVertex
 function commands are used within
glBegin
/
glEnd
 pairs to specify point, line, and polygon vertexes. The current color, normal, and texture coordinates are associated with the vertex when
glVertex
 is called.
When only
x
 and
y
 are specified,
z
 defaults to 0.0 and
w
 defaults to 1.0. When
x, y,
 and
z
 are specified,
w
 defaults to 1.0.
Invoking
glVertex
 outside of a
glBegin
/
glEnd
 pair results in undefined behavior.
See Also
glBegin
,
glCallList
,
glColor
,
glEdgeFlag
,
glEvalCoord
,
glIndex
,
glMaterial
,
glNormal
,
glRect
,
glTexCoord


glVertexPointerEXT
The
glVertexPointerEXT
function defines an array of vertex data.
void glVertexPointerEXT
(
GLint
size
,
GLenum
type
,
GLsizei
stride
,
GLsizei
count
,
const GLvoid
 *
pointer
);
Parameters
size
Specifies the number of coordinates per vertex. The value of
size
 must be 2, 3, or 4.
type
Specifies the datatype of each coordinate in the array using the following symbolic constants:
GL_SHORT
,
GL_INT
,
GL_FLOAT
, and
GL_DOUBLE_EXT
.
stride
Specifies the byte offset between consecutive vertexes. When
stride
 is zero, the vertexes are tightly packed in the array.
count
Specifies the number of vertexes, counting from the first, that are static.
pointer
Specifies a pointer to the first coordinate of the first vertex in the array.
Remarks
The
 glVertexPointerEXT
 function specifies the location and data of an array of vertex coordinates to use when rendering. The
size
 parameter specifies the number of coordinates per vertex. The
type
 parameter specifies the datatype of each vertex coordinate and the
stride
 parameter determines the byte offset from one vertex to the next, enabling the packing of vertexes and attributes in a single array or storage in separate arrays. In some implementations storing the vertexes and attributes in a single array can be more efficient than using separate arrays. Starting from the first vertex element, the
count
 parameter indicates the total number of static elements. Your application can modify static elements, but once the elements are modified, the application must explicitly specify the array again before using the array for any rendering. Non-static array elements are not accessed until you call
glDrawArraysEXT
 or
glArrayElementEXT
.
A vertex array is enabled when you specify the
 GL_VERTEX_ARRAY_EXT
constant with
glEnable
. When enabled,
glDrawArraysEXT
 and
glArrayElementEXT
 use the vertex array. By default, the vertex array is disabled.
You cannot include
glVertexPointerEXT
 in display lists.
When you specify a vertex array using
glVertexPointerEXT
, the values of all the function's vertex array parameters are saved in a client-side state and static array elements can be cached. Because the vertex array parameters are client-side state, their values are not saved or restored by
glPushAttrib
 and
glPopAttrib
.
Although no error is generated when you call
glVertexPointerEXT
 within
glBegin
 and
glEnd
 pairs, the results are undefined.
Note
Note
glVertexPointerEXT
 is an extension function that is not part of the standard OpenGL library but is part of the
GL_EXT_vertex_array
 extension. To check whether your implementation of OpenGL supports
glVertexPointerEXT
, call
glGetString
(
GL_EXTENSIONS
). If it returns
GL_EXT_vertex_array
,
glVertexPointerEXT
 is supported.
To obtain the address of an extension function, call
wglGetProcAddress
.
The following functions retrieve information related to the
glVertexPointerEXT
 function:
glIsEnabled
 with argument
GL_VERTEX_ARRAY_EXT
glGet
 with argument
GL_VERTEX_ARRAY_SIZE_EXT
glGet
 with argument
GL_VERTEX_ARRAY_STRIDE_EXT
glGet
 with argument
GL_VERTEX_ARRAY_COUNT_EXT
glGet
 with argument
GL_VERTEX_ARRAY_TYPE_EXT
glGetPointervEXT
 with argument
GL_VERTEX_ARRAY_POINTER_EXT
Errors
GL_INVALID_VALUE
 is generated if
size
 is not 2, 3, or 4.
GL_INVALID_ENUM
 is generated if
type
 is not an accepted value.
GL_INVALID_VALUE
 is generated if
stride
 or
count
 is negative.
See Also
glArrayElementEXT
,
glColorPointerEXT
,
glDrawArraysEXT
,
glEdgeFlagPointerEXT
,
glGetPointervEXT
,
glIndexPointerEXT
,
glNormalPointerEXT
,
glTexCoordPointerEXT
,
glGetString
,
wglGetProcAddress


glViewport
The
glViewport
 function sets the viewport.
void
glViewport
(
GLint
x
,
GLint
y
,
GLsizei
width
,
GLsizei
height
);
Parameters
x, y
Specify the lower-left corner of the viewport rectangle, in pixels. The default is (0,0).
width, height
Specify the width and height, respectively, of the viewport. When a GL context is
first
 attached to a window,
width
and
height
 are set to the dimensions of that window.
Remarks
The
glViewport
 function specifies the affine transformation of x and y from normalized device coordinates to window coordinates. Let (
x
 (nd)
,
y
 (nd)
) be normalized device coordinates. Then the window coordinates (
x
 (w)
, y
 (w)
) are computed as follows:
Viewport width and height are silently clamped to a range that depends on the implementation. This range is queried by calling
glGet
 with argument
GL_MAX_VIEWPORT_DIMS
.
The following functions retrieve information related to the
glViewport
 function:
glGet
 with argument
GL_VIEWPORT
glGet
 with argument
GL_MAX_VIEWPORT_DIMS
Errors
GL_INVALID_VALUE
 is generated if either
width
 or
height
 is negative.
GL_INVALID_OPERATION
 is generated if
glViewport
 is called between a call to
glBegin
 and the corresponding call to
glEnd
.
See Also
glDepthRange


gluBeginCurve, gluEndCurve
The
gluBeginCurve
 and
gluEndCurve
 functions delimit a NURBS curve definition.
void gluBeginCurve
(
GLUnurbsObj
*nobj
);
void gluEndCurve
(
GLUnurbsObj
*nobj
);
Parameters
nobj
Specifies the NURBS object (created with
gluNewNurbsRenderer
).
Remarks
Use the
gluBeginCurve
 function to mark the beginning of a NURBS curve definition. After calling
gluBeginCurve
, make one or more calls to
gluNurbsCurve
 to define the attributes of the curve. Exactly one of the calls to
gluNurbsCurve
 must have a curve type of
GL_MAP1_VERTEX_3
 or
GL_MAP1_VERTEX_4
. To mark the end of the NURBS curve definition, call
gluEndCurve
.
OpenGL evaluators are used to render the NURBS curve as a series of line segments. Evaluator state is preserved during rendering with
glPushAttrib
(
GL_EVAL_BIT
) and
glPopAttrib
( ). See
glPushAttrib
 for details on exactly what state these calls preserve.
Example
The following commands render a textured NURBS curve with normals; texture coordinates and normals are also specified as NURBS curves:
gluBeginCurve(nobj);
gluNurbsCurve(nobj, . . ., GL_MAP1_TEXTURE_COORD_2);
gluNurbsCurve(nobj, . . ., GL_MAP1_NORMAL);
gluNurbsCurve(nobj, . . ., GL_MAP1_VERTEX_4);
gluEndCurve(nobj);
See Also
gluBeginSurface
,
gluBeginTrim
,
gluNewNurbsRenderer
,
gluNurbsCurve
,
glPopAttrib
,
glPushAttrib


gluBeginPolygon, gluEndPolygon
The
gluBeginPolygon
 and
gluEndPolygon
 functions delimit a polygon description.
void
gluBeginPolygon
(
GLUtesselator
*tess
);
void gluEndPolygon
(
GLUtesselator
*tess
);
Parameters
tess
Specifies the tessellation object (created with
gluNewTess
).
Remarks
Use the
gluBeginPolygon
 and
gluEndPolygon
 functions to delimit the definition of a nonconvex polygon. To define such a polygon, first call
gluBeginPolygon
. Then define the contours of the polygon by calling
gluTessVertex
 for each vertex and
gluNextContour
 to start each new contour. Finally, call
gluEndPolygon
 to signal the end of the definition. See
gluTessVertex
 and
gluNextContour
 for more details.
Once
gluEndPolygon
 is called, the polygon is tessellated, and the resulting triangles are described through callbacks. See
gluTessCallback
 for descriptions of the callback functions.
Note
  The
gluBeginPolygon
 and
gluEndPolygon
 functions are obsolete and are provided for backward compatibility only.
gluBeginPolygon
 is mapped to
gluTessBeginPolygon
 followed by
gluTessBeginContour
;
gluEndPolygon
 is mapped to
gluTessEndPolygon
 followed by
gluTessEndContour
.
Example
A quadrilateral with a triangular hole in it can be described like this:
gluBeginPolygon(tess);
gluTessVertex(tess, v1, v1);
gluTessVertex(tess, v2, v2);
gluTessVertex(tess, v3, v3);
gluTessVertex(tess, v4, v4);
gluNextContour(tess, GLU_INTERIOR);
gluTessVertex(tess, v5, v5);
gluTessVertex(tess, v6, v6);
gluTessVertex(tess, v7, v7);
gluEndPolygon(tess);
See Also
gluNewTess
,
gluNextContour
,
gluTessCallback
,
gluTessVertex
,
gluTessBeginPolygon
,
gluTessBeginContour


gluBeginSurface, gluEndSurface
The
gluBeginSurface
 and
gluEndSurface
 functions delimit a NURBS surface definition.
void
gluBeginSurface
(
GLUnurbsObj
*nobj
);
void gluEndSurface
(
GLUnurbsObj
*nobj
);
Parameters
nobj
Specifies the NURBS object (created with
gluNewNurbsRenderer
).
Remarks
Use the
gluBeginSurface
 function to mark the beginning of a NURBS surface definition. After calling
gluBeginSurface
, make one or more calls to
gluNurbsSurface
 to define the attributes of the surface. Exactly one of these calls to
gluNurbsSurface
 must have a surface type of
GL_MAP2_VERTEX_3
 or
GL_MAP2_VERTEX_4
. To mark the end of the NURBS surface definition, call
gluEndSurface
.
Trimming of NURBS surfaces is supported with
gluBeginTrim
,
gluPwlCurve
,
gluNurbsCurve
, and
gluEndTrim
. See
gluBeginTrim
 for details.
OpenGL evaluators are used to render the NURBS surface as a set of polygons. Evaluator state is preserved during rendering with
glPushAttrib
(
GL_EVAL_BIT
) and
glPopAttrib
( ). See
glPushAttrib
 for details on exactly what state these calls preserve.
Example
The following commands render a textured NURBS surface with normals; the texture coordinates and normals are also described as NURBS surfaces:
gluBeginSurface(nobj);
    gluNurbsSurface(nobj, . . ., GL_MAP2_TEXTURE_COORD_2);
    gluNurbsSurface(nobj, . . ., GL_MAP2_NORMAL);
    gluNurbsSurface(nobj, . . ., GL_MAP2_VERTEX_4);
gluEndSurface(nobj);
See Also
gluBeginCurve
,
gluBeginTrim
,
gluNewNurbsRenderer
,
gluNurbsCurve
,
gluNurbsSurface
,
gluPwlCurve


gluBeginTrim, gluEndTrim
The
gluBeginTrim
 and
gluEndTrim
 functions delimit a NURBS trimming loop definition.
void gluBeginTrim
(
GLUnurbsObj
*nobj
);
void gluEndTrim
(
GLUnurbsObj
*nobj
);
Parameters
nobj
Specifies the NURBS object (created with
gluNewNurbsRenderer
).
Remarks
Use the
gluBeginTrim
 function to mark the beginning of a trimming loop, and the
gluEndTrim
 function to mark the end of a trimming loop. A trimming loop is a set of oriented curve segments (forming a closed curve) that define boundaries of a NURBS surface. You include these trimming loops in the definition of a NURBS surface, between calls to
gluBeginSurface
 and
gluEndSurface
.
The definition for a NURBS surface can contain many trimming loops. For example, if you wrote a definition for a NURBS surface that resembled a rectangle with a hole punched out, the definition would contain two trimming loops. One loop would define the outer edge of the rectangle; the other would define the hole punched out of the rectangle. The definitions of each of these trimming loops would be bracketed by a
gluBeginTrim
/
gluEndTrim
 pair.
The definition of a single closed trimming loop can consist of multiple curve segments, each described as a piecewise linear curve (see
gluPwlCurve
) or as a single NURBS curve (see
gluNurbsCurve
), or as a combination of both in any order. The only library calls that can appear in a trimming loop definition (between the calls to
gluBeginTrim
 and
gluEndTrim
) are
gluPwlCurve
 and
gluNurbsCurve
.
The area of the NURBS surface that is displayed is the region in the domain to the left of the trimming curve as the curve parameter increases. Thus, the retained region of the NURBS surface is inside a counterclockwise trimming loop and outside a clockwise trimming loop. For the rectangle mentioned earlier, the trimming loop for the outer edge of the rectangle runs counterclockwise, while the trimming loop for the punched-out hole runs clockwise.
If you use more than one curve to define a single trimming loop, the curve segments must form a closed loop (that is, the endpoint of each curve must be the starting point of the next curve, and the endpoint of the final curve must be the starting point of the first curve). If the endpoints of the curve are sufficiently close together but not exactly coincident, they will be coerced to match. If the endpoints are not sufficiently close, an error results (see
gluNurbsCallback
).
If a trimming loop definition contains multiple curves, the direction of the curves must be consistent (that is, the inside must be to the left of all of the curves). Nested trimming loops are legal as long as the curve orientations alternate correctly. Trimming curves cannot be self-intersecting, nor can they intersect one another (or an error results).
If no trimming information is given for a NURBS surface, the entire surface is drawn.
Example
This code fragment defines a trimming loop that consists of one piecewise linear curve, and two NURBS curves:
gluBeginTrim(nobj);
    gluPwlCurve(. . ., GLU_MAP1_TRIM_2);
    gluNurbsCurve(. . ., GLU_MAP1_TRIM_2);
    gluNurbsCurve(. . ., GLU_MAP1_TRIM_3);
gluEndTrim(nobj);
See Also
gluBeginSurface
,
gluNewNurbsRenderer
,
gluNurbsCallback
,
gluNurbsCurve
,
gluPwlCurve


gluBuild1DMipmaps
The
gluBuild1DMipmaps
 function creates 1-D mipmaps.
int gluBuild1DMipmaps(
GLenum
target
,
GLint
components
,
GLint
width
,
GLenum
format
,
GLenum
type
,
const void
*
data
);
Parameters
target
Specifies the target texture. Must be
GL_TEXTURE_1D
.
components
Specifies the number of color components in the texture. Must be 1, 2, 3, or 4.
width
Specifies the width of the texture image.
format
Specifies the format of the pixel data. Must be one of
GL_COLOR_INDEX, GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA, GL_RGB, GL_RGBA, GL_LUMINANCE,
 and
GL_LUMINANCE_ALPHA.
type
Specifies the data type for
data
. Must be one of
GL_UNSIGNED_BYTE, GL_BYTE, GL_BITMAP, GL_UNSIGNED_SHORT, GL_SHORT
,
GL_UNSIGNED_INT
,
GL_INT
, or
GL_FLOAT
.
data
Specifies a pointer to the image data in memory.
Remarks
The
gluBuild1DMipmaps
 function obtains the input image and generates all mipmap images (using
gluScaleImage
) so that the input image can be used as a mipmapped texture image.
glTexImage1D
 is then called to load each of the images. If the width of the input image is not a power of two, then the image is scaled to the nearest power of two before the mipmaps are generated.
A return value of zero indicates success. Otherwise, a GLU error code is returned (see
gluErrorString
).
See
glTexImage1D
 for a description of the acceptable values for the
format
 parameter. See
glDrawPixels
 for a description of the acceptable values for the
type
 parameter.
See Also
glTexImage1D
,
gluBuild2DMipmaps
,
gluErrorString
,
gluScaleImage


gluBuild2DMipmaps
The
gluBuild2DMipmaps
function creates 2-D mipmaps.
int gluBuild2DMipmaps
(
GLenum
target
,
GLint
components
,
GLint
width
,
GLint
height
,
GLenum
format
,
GLenum
type
,
const void
*data
);
Parameters
target
Specifies the target texture. Must be
GL_TEXTURE_2D
.
components
Specifies the number of color components in the texture. Must be 1, 2, 3, or 4.
width, height
Specifies the width and height, respectively, of the texture image.
format
Specifies the format of the pixel data. Must be one of:
GL_COLOR_INDEX, GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA, GL_RGB, GL_RGBA, GL_LUMINANCE,
 and
GL_LUMINANCE_ALPHA.
type
Specifies the data type for
data
. Must be one of:
GL_UNSIGNED_BYTE, GL_BYTE, GL_BITMAP, GL_UNSIGNED_SHORT, GL_SHORT,  GL_UNSIGNED_INT, GL_INT,
 or
GL_FLOAT.
data
Specifies a pointer to the image data in memory.
Remarks
The
 gluBuild2DMipmaps
 function obtains the input image and generates all mipmap images (using
gluScaleImage
) so that the input image can be used as a mipmapped texture image. The
glTexImage2D
 function is then called to load each of the images. If the dimensions of the input image are not powers of two, then the image is scaled so that both the width and height are powers of two before the mipmaps are generated.
A return value of 0 indicates success. Otherwise, a GLU error code is returned (see
gluErrorString
).
See
glTexImage1D
 for a description of the acceptable values for the
format
 parameter. See
glDrawPixels
 for a description of the acceptable values for the
type
 parameter.
See Also
glDrawPixels
,
glTexImage1D
,
glTexImage2D
,
gluBuild1DMipmaps
,
gluErrorString
,
gluScaleImage


gluCylinder
The
gluCylinder
 function draws a cylinder.
void gluCylinder
(
GLUquadricObj
*qobj
,
GLdouble
baseRadius
,
GLdouble
topRadius
,
GLdouble
height
,
GLint
slices
,
GLint
stacks
);
Parameters
qobj
Specifies the quadrics object (created with
gluNewQuadric
).
baseRadius
Specifies the radius of the cylinder at
z
 = 0.
topRadius
Specifies the radius of the cylinder at
z
 =
height
.
height
Specifies the height of the cylinder.
slices
Specifies the number of subdivisions around the
z
 axis.
stacks
Specifies the number of subdivisions along the
z
 axis.
Remarks
The
 gluCylinder
 function draws a cylinder oriented along the
z
 axis. The base of the cylinder is placed at
z
 = 0, and the top at z =
height
. Like a sphere, a cylinder is subdivided around the
z
 axis into slices, and along the
z
 axis into stacks.
Notice that if
topRadius
 is set to zero, then this routine will generate a cone.
If the orientation is set to
GLU_OUTSIDE
 (with
gluQuadricOrientation
), then any generated normals point away from the
z
 axis. Otherwise, they point toward the
z
 axis.
If texturing is turned on (with
gluQuadricTexture
), then texture coordinates are generated so that
t
 ranges linearly from 0.0 at
z
 = 0 to 1.0 at
z
 =
height
, and
s
 ranges from 0.0 at the +
y
 axis, to 0.25 at the +
x
 axis, to 0.5 at the -
y
 axis, to 0.75 at the
x
 axis, and back to 1.0 at the +
y
 axis.
See Also
gluDisk
,
gluNewQuadric
,
gluPartialDisk
,
gluQuadricTexture
,
gluSphere


gluDeleteNurbsRenderer
The
gluDeleteNurbsRenderer
 function destroys a NURBS object.
void gluDeleteNurbsRenderer
(
GLUnurbsObj
*nobj
);
Parameters
nobj
Specifies the NURBS object to be destroyed (created with
gluNewNurbsRenderer
).
Remarks
The
 gluDeleteNurbsRenderer
 function destroys the NURBS object and frees any memory used by it. Once
gluDeleteNurbsRenderer
 has been called,
nobj
cannot be used again.
See Also
gluNewNurbsRenderer


gluDeleteQuadric
The
gluDeleteQuadric
 function destroys a quadrics object.
void gluDeleteQuadric
(
GLUquadricObj
*state
);
Parameters
state
Specifies the quadrics object to be destroyed (created with
gluNewQuadric
).
Remarks
The
gluDeleteQuadric
 function destroys the quadrics object and frees any memory used by it. Once
gluDeleteQuadric
 has been called,
state
 cannot be used again.
See Also
gluNewQuadric


gluDeleteTess
The
gluDeleteTess
 function destroys a tessellation object.
void gluDeleteTess
(
GLUtesselator
*tess
);
Parameters
tess
Specifies the tessellation object to destroy (created with
gluNewTess
).
Remarks
The
 gluDeleteTess
 function destroys the indicated tessellation object and frees any memory that it used.
See Also
gluTessBeginPolygon
,
gluNewTess
,
gluTessCallback


gluDisk
The
gluDisk
function draws a disk.
void gluDisk
(
GLUquadricObj
*qobj
,
GLdouble
innerRadius
,
GLdouble
outerRadius
,
GLint
slices
,
GLint
loops
);
Parameters
qobj
Specifies the quadrics object (created with
gluNewQuadric
).
innerRadius
Specifies the inner radius of the disk (may be 0).
outerRadius
Specifies the outer radius of the disk.
slices
Specifies the number of subdivisions around the
z
 axis.
loops
Specifies the number of concentric rings about the origin into which the disk is subdivided.
Remarks
The
gluDisk
 function renders a disk on the
z
 = 0 plane. The disk has a radius of
outerRadius
, and contains a concentric circular hole with a radius of
innerRadius
. If
innerRadius
 is 0, then no hole is generated. The disk is subdivided around the
z
 axis into slices (like pizza slices), and also about the
z
 axis into rings (as specified by
slices
 and
loops
, respectively).
With respect to orientation, the +
z
 side of the disk is considered to be
outside
 (see
gluQuadricOrientation
). This means that if the orientation is set to
GLU_OUTSIDE
, then any normals generated point along the +
z
 axis. Otherwise, they point along the
z
 axis.
If texturing is turned on (with
gluQuadricTexture
), texture coordinates are generated linearly such that where r =
outerRadius
 , the value at (
r
, 0, 0) is (1, 0.5), at (0,
r
, 0) it is (0.5, 1), at (
r
, 0, 0) it is (0, 0.5), and at (0,
r
, 0) it is (0.5, 0).
See Also
gluCylinder
,
gluNewQuadric
,
gluPartialDisk
,
gluQuadricOrientation
,
gluQuadricTexture
,
gluSphere


gluErrorString
The
gluErrorString
 function produces an error string from an OpenGL or GLU error code. The error string is ANSI only.
const GLubyte
*
gluErrorString
(
GLenum
errorCode
);
Parameters
errorCode
Specifies an OpenGL or GLU error code.
Remarks
The
gluErrorString
 function produces an error string from an OpenGL or GLU error code. The string is in an ISO Latin 1 format. For example,
gluErrorString
(
GL_OUT_OF_MEMORY
) returns the string
out of memory
.
The standard GLU error codes are
GLU_INVALID_ENUM
,
GLU_INVALID_VALUE
, and
GLU_OUT_OF_MEMORY
. Certain other GLU functions can return specialized error codes through callbacks. See
glGetError
 for the list of OpenGL error codes.
The
gluErrorString
function produces error strings in ANSI only. Whenever possible you should use
gluErrorStringWIN
, which allows ANSI or Unicode error strings. This makes it easier to internationalize your program.
See Also
glGetError
,
gluNurbsCallback
,
gluQuadricCallback
,
gluTessCallback


gluGetNurbsProperty
The
gluGetNurbsProperty
 function gets a NURBS property.
void gluGetNurbsProperty
(
GLUnurbsObj
*nobj
,
GLenum
property
,
GLfloat
*value
);
Parameters
nobj
Specifies the NURBS object (created with
gluNewNurbsRenderer
).
property
Specifies the property whose value is to be fetched. Valid values are
GLU_SAMPLING_TOLERANCE, GLU_DISPLAY_MODE, GLU_CULLING,
GLU_AUTO_LOAD_MATRIX
,
GLU_PARAMETRIC_TOLERANCE
,
GLU_SAMPLING_METHOD
,
GLU_U_STEP
, and
GLU_V_STEP
.
value
Specifies a pointer to the location into which the value of the named property is written.
Remarks
The
gluGetNurbsProperty
 function is used to retrieve properties stored in a NURBS object. These properties affect the way that NURBS curves and surfaces are rendered. See
gluNurbsProperty
  for information about what the properties are and what they do.
See Also
gluNewNurbsRenderer
,
gluNurbsProperty


gluGetString
The
gluGetString
 function gets a string that describes the GLU version number or supported GLU extension calls.
const GLubyte
 *
gluGetString
(
GLenum
name
);
Parameters
name
Specifies either the version number of GLU,
GL_VERSION
, or available vendor-specific extension calls,
GL_EXTENSIONS
.
Remarks
The
gluGetString
 function returns a pointer to a static, null-terminated string. When
name
 is
GL_VERSION
, the returned string is a value that represents the version number of GLU. The format of the version number is as follows:
<version number><space><vendor-specific information>
(for example, "1.2.11 Microsoft Windows NT")
The version number has the form "major_number.minor_number" or "major_number.minor_number.release_number". The vendor-specific information is optional and the format and contents depend on the implementation.
When
name
 is
GL_EXTENSIONS
, the returned string contains a list of names of supported GLU extensions that are separated by spaces. The format of the returned list of strings is as follows:
<extension_name><space><extension_ name><space> . . .
(for example, "GLU_NURBS GL_TESSELATION")
The extension names cannot contain any spaces.
The
gluGetString
 function is valid for GLU version 1.1 or later.


gluGetTessProperty
The
gluGetTessProperty
 function gets a tessellation object property.
void
gluTessProperty
(
GLUtesselator
 *
tess
,
GLenum
which
,
GLdouble
 *
value
);
Parameters
tess
Specifies the tessellation object (created with
gluNewTess
).
which
Specifies the property whose value is to be retrieved. Valid values are
GLU_TESS_WINDING_RULE
,
GLU_TESS_BOUNDARY_ONLY
, and
GLU_TESS_TOLERANCE
.
value
Specifies a pointer to the location of where the value of the named property is written.
Remarks
Use
gluGetTessProperty
 to retrieve properties stored in a tessellation object. These properties affect the way that tessellation objects are interpreted and rendered. For information about what the properties are and what they do, see
gluTessProperty
.
See Also
gluNewTess


gluLoadSamplingMatrices
The
gluLoadSamplingMatices
function loads NURBS sampling and culling matrices.
void
gluLoadSamplingMatrices
(
GLUnurbsObj
*nobj
,
const GLfloat
modelMatrix[16]
,
const GLfloat
projMatrix[16]
,
const GLint
viewport[4]
);
Parameters
nobj
Specifies the NURBS object (created with
gluNewNurbsRenderer
).
modelMatrix
Specifies a modelview matrix (as from a
glGetFloatv
 call).
projMatrix
Specifies a projection matrix (as from a
glGetFloatv
 call).
viewport
Specifies a viewport (as from a
glGetIntegerv
 call).
Remarks
The
gluLoadSamplingMatrices
 function uses
modelMatrix
,
projMatrix
, and
viewport;
 to recompute the sampling and culling matrices stored in
nobj
. The sampling matrix determines how finely a NURBS curve or surface must be tessellated to satisfy the sampling tolerance (as determined by the
GLU_SAMPLING_TOLERANCE
 property). The culling matrix is used in deciding if a NURBS curve or surface should be culled before rendering (when the
GLU_CULLING
 property is turned on).
The
gluLoadSamplingMatrices
 function is necessary only if the
GLU_AUTO_LOAD_MATRIX
 property is turned off (see
gluNurbsProperty
). Although it can be convenient to leave the
GLU_AUTO_LOAD_MATRIX
 property turned on, there can be a performance penalty for doing so. (A round trip to the OpenGL server is needed to fetch the current values of the modelview matrix, projection matrix, and viewport.)
See Also
gluGetNurbsProperty
,
gluNewNurbsRenderer
,
gluNurbsProperty


gluLookAt
The
gluLookAt
 function defines a viewing transformation.
void gluLookAt
(
GLdouble
eyex
,
GLdouble
eyey
,
GLdouble
eyez
,
GLdouble
centerx
,
GLdouble
centery
,
GLdouble
centerz
,
GLdouble
upx
,
GLdouble
upy
,
GLdouble
upz
);
Parameters
eyex, eyey, eyez
Specifies the position of the eye point.
centerx, centery, centerz
Specifies the position of the reference point.
upx, upy, upz
Specifies the direction of the up vector.
Remarks
The
gluLookAt
 function creates a viewing matrix derived from an eye point, a reference point indicating the center of the scene, and an up vector. The matrix maps the reference point to the negative
z
 axis and the eye point to the origin, so that, when a typical projection matrix is used, the center of the scene maps to the center of the viewport. Similarly, the direction described by the up vector projected onto the viewing plane is mapped to the positive
y
 axis so that it points upward in the viewport. The up vector must not be parallel to the line of sight from the eye to the reference point.
The matrix generated by
gluLookAt
 postmultiplies the current matrix.
See Also
glFrustum
,
gluPerspective


gluNewNurbsRenderer
The
gluNewNurbsRenderer
 function creates a NURBS object.
GLUnurbsObj* gluNewNurbsRenderer
(
void
);
Remarks
The
gluNewNurbsRenderer
 function creates and returns a pointer to a new NURBS object. This object must be referred to when calling NURBS rendering and control functions. A return value of zero means that there is not enough memory to allocate the object.
See Also
gluBeginCurve
,
gluBeginSurface
,
gluBeginTrim
,
gluDeleteNurbsRenderer
,
gluNurbsCallback
,
gluNurbsProperty


gluNewQuadric
The
gluNewQuadric
 function creates a quadrics object.
GLUquadricObj* gluNewQuadric
(
void
);
Remarks
The
gluNewQuadric
 function creates and returns a pointer to a new quadrics object. This object must be referred to when calling quadrics rendering and control functions. A return value of zero means that there is not enough memory to allocate the object.
See Also
gluCylinder
,
gluDeleteQuadric
,
gluDisk
,
gluPartialDisk
,
gluQuadricCallback
,
gluQuadricDrawStyle
,
gluQuadricNormals
,
gluQuadricOrientation
,
gluQuadricTexture
,
gluSphere


gluNewTess
The
 gluNewTess
 function creates a tessellation object.
GLUtesselator* gluNewTess
(
void
);
Remarks
The
 gluNewTess
 function creates and returns a pointer to a new tessellation object. This object must be referred to when calling tessellation functions. A return value of zero means that there is not enough memory to allocate the object.
See Also
gluTessBeginPolygon
,
gluDeleteTess
,
gluTessCallback


gluNextContour
The
gluNextContour
 function marks the beginning of another contour.
void gluNextContour(
GLUtesselator
*tess
,
GLenum
type
);
Parameters
tess
Specifies the tessellation object (created with
gluNewTess
).
type
Specifies the type of the contour being defined. Valid values are
GLU_EXTERIOR
,
GLU_INTERIOR
,
GLU_UNKNOWN
,
GLU_CCW
, and
GLU_CW
.
Remarks
The
gluNextContour
 function is used in describing polygons with multiple contours. After the first contour has been described through a series of
gluTessVertex
 calls, a
gluNextContour
 call indicates that the previous contour is complete and that the next contour is about to begin. Another series of
gluTessVertex
 calls is then used to describe the new contour. This process can be repeated until all contours have been described.
The
 type
 parameter defines what type of contour follows. The legal contour types are as follows:
GLU_EXTERIOR
An exterior contour defines an exterior boundary of the polygon.
GLU_INTERIOR
An interior contour defines an interior boundary of the polygon (such as a hole).
GLU_UNKNOWN
An unknown contour is analyzed by the library to determine if it is interior or exterior.
GLU_CCW, GLU_CW
The first
GLU_CCW
 or
GLU_CW
 contour defined is considered to be exterior. All other contours are considered to be exterior if they are oriented in the same direction (clockwise or counterclockwise) as the first contour, and interior if they are not.
If one contour is of type
GLU_CCW
 or
GLU_CW
, then all contours must be of the same type (if they are not, then all
GLU_CCW
 and
GLU_CW
 contours will be changed to
GLU_UNKNOWN
). Note that there is no real difference between the
GLU_CCW
 and
GLU_CW
contour types
.
The
gluNextContour
 function can be called before the first contour is described to define the type of the first contour. If
gluNextContour
 is not called before the first contour, then the first contour is marked
GLU_EXTERIOR
.
Note
  The
 gluNextContour
 function is obsolete and is provided for backwards compatibility only. The
gluNextContour
 function is mapped to
gluTessEndContour
 followed by
gluTessBeginContour
.
Example
A quadrilateral with a triangular hole in it can be described as follows:
gluBeginPolygon(tess);
    gluTessVertex(tess, v1, v1);
    gluTessVertex(tess, v2, v2);
    gluTessVertex(tess, v3, v3);
    gluTessVertex(tess, v4, v4);
gluNextContour(tess, GLU_INTERIOR);
    gluTessVertex(tess, v5, v5);
    gluTessVertex(tess, v6, v6);
    gluTessVertex(tess, v7, v7);
gluEndPolygon(tess);
See Also
gluTessBeginPolygon
,
gluNewTess
,
gluTessCallback
,
gluTessVertex
,
gluTessBeginContour


gluNurbsCallback
The
gluNurbsCallback
 function defines a callback for a NURBS object.
void gluNurbsCallback
(
GLUnurbsObj
*nobj
,
GLenum
which
,
void
(
*fn
)( )
);
Parameters
nobj
Specifies the NURBS object (created with
gluNewNurbsRenderer
).
which
Specifies the callback being defined. The only valid value is
GLU_ERROR
.
fn
Specifies the function that the callback calls.
Remarks
The
gluNurbsCallback
 function is used to define a callback to be used by a NURBS object. If the specified callback is already defined, then it is replaced. If
fn
 is NULL, then any existing callback is erased.
The one legal callback is
GLU_ERROR
:
GLU_ERROR
The error function is called when an error is encountered. Its single argument is of type GLenum, and it indicates the specific error that occurred. There are 37 errors unique to NURBS named
GLU_NURBS_ERROR1
 through
GLU_NURBS_ERROR37.
Character strings describing these errors can be retrieved with
gluErrorString.
See Also
gluErrorString
,
gluNewNurbsRenderer


gluNurbsCurve
The
gluNurbsCurve
 function defines the shape of a NURBS curve.
void gluNurbsCurve
(
GLUnurbsObj
*nobj
,
GLint
nknots
,
GLfloat
*knot
,
GLint
stride
,
GLfloat
*ctlarray
,
GLint
order
,
GLenum
type
);
Parameters
nobj
Specifies the NURBS object (created with
gluNewNurbsRenderer
).
nknots
Specifies the number of knots in
knot
.
 nknots
 equals the number of control points plus the order.
knot
Specifies an array of
nknots
 nondecreasing knot values.
stride
Specifies the offset (as a number of single-precision floating-point values) between successive curve control points.
ctlarray
Specifies a pointer to an array of control points. The coordinates must agree with
type
, specified below.
order
Specifies the order of the NURBS curve.
order
 equals degree + 1, hence a cubic curve has an order of 4.
type
Specifies the type of the curve. If this curve is defined within a
gluBeginCurve
/
gluEndCurve
 pair, then the type can be any of the valid one-dimensional evaluator types (such as
GL_MAP1_VERTEX_3
 or
GL_MAP1_COLOR_4
). Between a
gluBeginTrim
/
gluEndTrim
 pair, the only valid types are
GLU_MAP1_TRIM_2
 and
GLU_MAP1_TRIM_3
.
Remarks
Use the
gluNurbsCurve
 function to describe a NURBS curve.
When
gluNurbsCurve
 appears between a
gluBeginCurve
/
gluEndCurve
 pair, it is used to describe a curve to be rendered. Positional, texture, and color coordinates are associated by presenting each as a separate
gluNurbsCurve
 between a
gluBeginCurve
/
gluEndCurve
 pair. No more than one call to
gluNurbsCurve
 for each of color, position, and texture data can be made within a single
gluBeginCurve
/
gluEndCurve
 pair. Exactly one call must be made to describe the position of the curve (a
type
 of
GL_MAP1_VERTEX_3
 or
GL_MAP1_VERTEX_4
).
When
gluNurbsCurve
 appears between a
gluBeginTrim
/
gluEndTrim
 pair, it is used to describe a trimming curve on a NURBS surface. If
type
 is
GLU_MAP1_TRIM_2
, then it describes a curve in two-dimensional (
u
 and
v
) parameter space. If it is
GLU_MAP1_TRIM_3
, then it describes a curve in two-dimensional homogeneous (
u
,
v
, and
w
) parameter space. See
gluBeginTrim
 for more discussion about trimming curves.
Example
The following commands render a textured NURBS curve with normals:
gluBeginCurve(nobj);
    gluNurbsCurve(nobj, ..., GL_MAP1_TEXTURE_COORD_2);
    gluNurbsCurve(nobj, ..., GL_MAP1_NORMAL);
    gluNurbsCurve(nobj, ..., GL_MAP1_VERTEX_4);
gluEndCurve(nobj);
See Also
gluBeginCurve
,
gluBeginTrim
,
gluNewNurbsRenderer
,
gluPwlCurve


gluNurbsProperty
The
gluNurbsProperty
 function sets a NURBS property.
void gluNurbsProperty
(
GLUnurbsObj
*nobj
,
GLenum
property
,
GLfloat
value
);
Parameters
nobj
Specifies the NURBS object (created with
gluNewNurbsRenderer
).
property
Specifies the property to be set. Valid values are
GLU_SAMPLING_TOLERANCE, GLU_DISPLAY_MODE, GLU_CULLING,
GLU_AUTO_LOAD_MATRIX
,
GLU_PARAMETRIC_TOLERANCE
,
GLU_SAMPLING_METHOD
,
GLU_U_STEP
, and
GLU_V_STEP
.
value
Specifies the value to which to set the indicated property.
value
 can be a numeric value or one of three values
GLU_PATH_LENGTH, GLU_PARAMETRIC_ERROR,
or
GLU_DOMAIN_DISTANCE
.
Remarks
The
gluNurbsProperty
 function is used to control properties stored in a NURBS object. These properties affect the way that a NURBS curve is rendered. The legal values for
property
 are as follows:
GLU_SAMPLING_TOLERANCE
Specifies the maximum length, in pixels, to use when the sampling method is set to the
GLU_PATH_LENGTH
 sampling method. The default value is 50.0 pixels.
GLU_DISPLAY_MODE
The
 value
 parameter defines how a NURBS surface should be rendered.
value
 can be set to
GLU_FILL, GLU_OUTLINE_POLYGON,
 or
GLU_OUTLINE_PATCH
. When set to
GLU_FILL
, the surface is rendered as a set of polygons.
GLU_OUTLINE_POLYGON
 instructs the NURBS library to draw only the outlines of the polygons created by tessellation.
GLU_OUTLINE_PATCH
 causes just the outlines of patches and trim curves defined by the user to be drawn. The default value is
GLU_FILL
.
GLU_CULLING
The
 value
 parameter is a Boolean value that, when set to
GL_TRUE
, indicates that a NURBS curve should be discarded prior to tessellation if its control points lie outside the current viewport. The default is
GL_FALSE
 (because a NURBS curve cannot fall entirely within the convex hull of its control points).
GLU_PARAMETRIC_TOLERANCE
Specifies the maximum distance, in pixels, to use when the sampling method is set to
GLU_PARAMETRIC_ERROR
. The default value is 0.5.
GLU_SAMPLING_METHOD
Specifies how to tessallate a NURBS surface.
GLU_SAMPLING_METHOD
 can have one of three values:
GLU_PATH_LENGTH
Specifies that surfaces rendered with the maximum length, in pixels, of the edges of the tessallation polygons are no greater than the value specified by
GLU_SAMPLING_TOLERANCE
.
GLU_PARAMETRIC_ERROR
Specifies that the surface is rendered with the value of
GLU_PARAMETRIC_TOLERANCE
 specifying the maximum distance, in pixels, between the tessellation polygons and the surfaces they approximate.
GLU_DOMAIN_DISTANCE
Specifies, in parametric coordinates, how many sample points per unit length to take in the u and v dimensions.
The default value is
GLU_PATH_LENGTH
.
GLU_U_STEP
Specifies the number of sample points per unit length taken along the u dimension in parametric coordinates. The value of
GLU_U_STEP
 is used when
GLU_SAMPLING_METHOD
 is set to
GLU_DOMAIN_DISTANCE
. The default value is 100.
GLU_V_STEP
Specifies the number of sample points per unit length taken along the v dimension in parametric coordinates. The value of
GLU_V_STEP
 is used when
GLU_SAMPLING_METHOD
 is set to
GLU_DOMAIN_DISTANCE
. The default value is 100.
GLU_AUTO_LOAD_MATRIX
The
 value
 parameter is a Boolean value. When set to
GL_TRUE
, the NURBS code downloads the projection matrix, the modelview matrix, and the viewport from the OpenGL server to compute sampling and culling matrices for each NURBS curve that is rendered. Sampling and culling matrices are required to determine the tessellation of a NURBS surface into line segments or polygons and to cull a NURBS surface if it lies outside of the viewport. If this mode is set to
GL_FALSE
, then the user needs to provide a projection matrix, a modelview matrix, and a viewport for the NURBS renderer to use to construct sampling and culling matrices. This can be done with the
gluLoadSamplingMatrices
 function. The default for this mode is
GL_TRUE
. Changing this mode from
GL_TRUE
 to
GL_FALSE
 does not affect the sampling and culling matrices until
gluLoadSamplingMatrices
 is called.
Note
Note
  The following
property
 parameters are supported GLU version 1.1 or later and are not valid for GLU version 1.0:
GLU_PARAMETRIC_TOLERANCE
,
GLU_SAMPLING_METHOD
,
GLU_U_STEP
, and
GLU_V_STEP
The following
value
 parameters are supported GLU version 1.1 or later and are not valid for GLU version 1.0:
GLU_PATH_LENGTH
,
GLU_PARAMETRIC_ERROR
,
GLU_DOMAIN_DISTANCE
See Also
gluGetNurbsProperty
,
gluGetString
,
gluLoadSamplingMatrices
,
gluNewNurbsRenderer


gluNurbsSurface
The
gluNurbsSurface
 defines the shape of a NURBS surface.
void gluNurbsSurface
(
GLUnurbsObj
*nobj
,
GLint
uknot_count
,
GLfloat
*uknot
,
GLint
vknot_count
,
GLfloat
*vknot
,
GLint
u_stride
,
GLint
v_stride
,
GLfloat
*ctlarray
,
GLint
uorder
,
GLint
vorder
,
GLenum
type
);
Parameters
nobj
Specifies the NURBS object (created with
gluNewNurbsRenderer
).
uknot_count
Specifies the number of knots in the parametric
u
 direction.
uknot
Specifies an array of
uknot_count
 nondecreasing knot values in the parametric
u
direction
.
vknot_count
Specifies the number of knots in the parametric
v
 direction.
vknot
Specifies an array of
vknot_count
 nondecreasing knot values in the parametric
v
direction
.
u_stride
Specifies the offset (as a number of single-precision floating point values) between successive control points in the parametric
u
 direction in
ctlarray
.
v_stride
Specifies the offset (in single-precision floating-point values) between successive control points in the parametric
v
 direction in
ctlarray
.
ctlarray
Specifies an array containing control points for the NURBS surface. The offsets between successive control points in the parametric
u
 and
v
 directions are given by
u_stride
 and
v_stride
.
uorder
Specifies the order of the NURBS surface in the parametric
u
 direction. The order is one more than the degree, hence a surface that is cubic in
u
 has a
u
 order of 4.
vorder
Specifies the order of the NURBS surface in the parametric
v
 direction. The order is one more than the degree, hence a surface that is cubic in
v
 has a
v
 order of 4.
type
Specifies type of the surface.
type
 can be any of the valid two-dimensional evaluator types (such as
GL_MAP2_VERTEX_3
 or
GL_MAP2_COLOR_4
).
Remarks
Use
gluNurbsSurface
 within a NURBS (Non-Uniform Rational B-Spline) surface definition to describe the shape of a NURBS surface (before any trimming). To mark the beginning of a NURBS surface definition, use the
gluBeginSurface
 command. To mark the end of a NURBS surface definition, use the
gluEndSurface
 command. Call
gluNurbsSurface
 within a NURBS surface definition only.
Positional, texture, and color coordinates are associated with a surface by presenting each as a separate
gluNurbsSurface
 between a
gluBeginSurface
/
gluEndSurface
 pair. No more than one call to
gluNurbsSurface
 for each of color, position, and texture data can be made within a single
gluBeginSurface
/
gluEndSurface
 pair. Exactly one call must be made to describe the position of the surface (a
type
 of
GL_MAP2_VERTEX_3
 or
GL_MAP2_VERTEX_4
).
A NURBS surface can be trimmed by using the commands
gluNurbsCurve
 and
gluPwlCurve
 between calls to
gluBeginTrim
 and
gluEndTrim
.
Notice that a
gluNurbsSurface
 with
uknot_count
 knots in the u direction and
vknot_count
 knots in the
v
 direction with orders
uorder
 and
vorder
 must have (
uknot_count
 -
uorder
) times (
vknot_count
 -
vorder
) control points.
Example
The following commands render a textured NURBS surface with normals; the texture coordinates and normals are also NURBS surfaces:
gluBeginSurface(nobj);
    gluNurbsSurface(nobj, . . ., GL_MAP2_TEXTURE_COORD_2);
    gluNurbsSurface(nobj, . . ., GL_MAP2_NORMAL);
    gluNurbsSurface(nobj, . . ., GL_MAP2_VERTEX_4);
gluEndSurface(nobj);
See Also
gluBeginSurface
,
gluBeginTrim
,
gluNewNurbsRenderer
,
gluNurbsCurve
,
gluPwlCurve


gluOrtho2D
The
gluOrtho2D
 function defines a 2-D orthographic projection matrix.
void gluOrtho2D
(
GLdouble
left
,
GLdouble
right
,
GLdouble
bottom
,
GLdouble
top
);
Parameters
left, right
Specify the coordinates for the left and right vertical clipping planes.
bottom, top
Specify the coordinates for the bottom and top horizontal clipping planes.
Remarks
The
gluOrtho2D
 function sets up a two-dimensional orthographic viewing region. This is equivalent to calling
glOrtho
 with near =
-
1 . and far = 1.
See Also
glOrtho
,
gluPerspective


gluPartialDisk
The
gluPartialDisk
 function draws an arc of a disk.
void gluPartialDisk
(
GLUquadricObj
*qobj
,
GLdouble
innerRadius
,
GLdouble
outerRadius
,
GLint
slices
,
GLint
loops
,
GLdouble
startAngle
,
GLdouble
sweepAngle
);
Parameters
qobj
Specifies a quadrics object (created with
gluNewQuadric
).
innerRadius
Specifies the inner radius of the partial disk (can be zero).
outerRadius
Specifies the outer radius of the partial disk.
slices
Specfies the number of subdivisions around the
z
 axis.
loops
Specifies the number of concentric rings about the origin into which the partial disk is subdivided.
startAngle
Specifies the starting angle, in degrees, of the disk portion.
sweepAngle
Specifies the sweep angle, in degrees, of the disk portion.
Remarks
The
gluPartialDisk
 function renders a partial disk on the z = 0 plane. A partial disk is similar to a full disk, except that only the subset of the disk from
startAngle
 through
startAngle
 +
sweepAngle
 is included (where 0 degrees is along the +
y
axis, 90 degrees along the +
x
 axis, 180 along the
-
y
axis, and 270 along the
-
x
 . axis).
The partial disk has a radius of
outerRadius
, and contains a concentric circular hole with a radius of
innerRadius
. If
innerRadius
 is zero, then no hole is generated. The partial disk is subdivided around the
z
 axis into slices (like pizza slices), and also about the
z
. axis into rings (as specified by
slices
 and
loops
, respectively).
With respect to orientation, the +
z
 side of the partial disk is considered to be outside (see
gluQuadricOrientation
). This means that if the orientation is set to
GLU_OUTSIDE
, then any normals generated point along the +
z
 axis. Otherwise, they point along the
z
 axis.
If texturing is turned on (with
gluQuadricTexture
), texture coordinates are generated linearly such that where
r
 =
outerRadius
, the value at (
r
, 0, 0) is (1, 0.5), at (0,
r
, 0) it is (0.5, 1), at (
r
, 0, 0) it is (0, 0.5), and at (0,
r
, 0) it is (0.5, 0).
See Also
gluCylinder
,
gluDisk
,
gluNewQuadric
,
gluQuadricOrientation
,
gluQuadricTexture
,
gluSphere


gluPerspective
The
gluPerspective
 function sets up a perspective projection matrix.
void gluPerspective
(
GLdouble
fovy
,
GLdouble
aspect
,
GLdouble
zNear
,
GLdouble
zFar
);
Parameters
fovy
Specifies the field of view angle, in degrees, in the
y
 direction.
aspect
Specifies the aspect ratio that determines the field of view in the
x
 direction. The aspect ratio is the ratio of
x
 (width) to
y
 (height).
zNear
Specifies the distance from the viewer to the near clipping plane (always positive).
zFar
Specifies the distance from the viewer to the far clipping plane (always positive).
Remarks
The
gluPerspective
 function specifies a viewing frustum into the world coordinate system. In general, the aspect ratio in
gluPerspective
 should match the aspect ratio of the associated viewport. For example,
aspect
 = 2.0 means the viewers angle of view is twice as wide in
x
 as it is in
y
. If the viewport is twice as wide as it is tall, it displays the image without distortion.
The matrix generated by
gluPerspective
 is multipled by the current matrix, just as if
glMultMatrix
 were called with the generated matrix. To load the perspective matrix onto the current matrix stack instead, precede the call to
gluPerspective
 with a call to
glLoadIdentity
.
See Also
glFrustum
,
glLoadIdentity
,
glMultMatrix
,
gluOrtho2D


gluPickMatrix
The
gluPickMatrix
 function defines a picking region.
void gluPickMatrix
(
GLdouble
x
,
GLdouble
y
,
GLdouble
width
,
GLdouble
height
,
GLint
viewport[4]
);
Parameters
x, y
Specify the center of a picking region in window coordinates.
width, height
Specify the width and height, respectively, of the picking region in window coordinates.
viewport
Specifies the current viewport (as from a
glGetIntegerv
 call).
Remarks
The
gluPickMatrix
 function creates a projection matrix that can be used to restrict drawing to a small region of the viewport. This is typically useful to determine what objects are being drawn near the cursor. Use
gluPickMatrix
 to restrict drawing to a small region around the cursor. Then, enter selection mode (with
glRenderMode
 and rerender the scene. All primitives that would have been drawn near the cursor are identified and stored in the selection buffer.
The matrix created by
gluPickMatrix
 is multiplied by the current matrix just as if
glMultMatrix
 is called with the generated matrix. To effectively use the generated pick matrix for picking, first call
glLoadIdentity
 to load an identity matrix onto the perspective matrix stack. Then call
gluPickMatrix
, and finally, call a command (such as
gluPerspective
) to multiply the perspective matrix by the pick matrix.
When using
gluPickMatrix
 to pick NURBS, be careful to turn off the NURBS property
GLU_AUTO_LOAD_MATRIX
. If
GLU_AUTO_LOAD_MATRIX
 is not turned off, then any NURBS surface rendered is subdivided differently with the pick matrix than the way it was subdivided without the pick matrix.
Example
When rendering a scene as follows:
glMatrixMode(GL_PROJECTION);
glLoadIdentity( );
gluPerspective(. . .);
glMatrixMode(GL_MODELVIEW);
/* Draw the scene */
a portion of the viewport can be selected as a pick region like this:
glMatrixMode(GL_PROJECTION);
glLoadIdentity( );
gluPickMatrix(x, y, width, height, viewport);
gluPerspective(. . .);
glMatrixMode(GL_MODELVIEW);
/* Draw the scene */
See Also
glGet
,
glLoadIdentity
,
glMultMatrix
,
glRenderMode
,
gluPerspective


gluProject
The
gluProject
 function maps object coordinates to window coordinates.
int
gluProject
(
GLdouble
objx
,
GLdouble
objy
,
GLdouble
objz
,
const GLdouble
modelMatrix[16]
,
const GLdouble
projMatrix[16]
,
const GLint
viewport[4]
,
GLdouble
*winx
,
GLdouble
*winy
,
GLdouble
*winz
);
Parameters
objx, objy, objz
Specify the object coordinates.
modelMatrix
Specifies the current modelview matrix (as from a
glGetDoublev
 call).
projMatrix
Specifies the current projection matrix (as from a
glGetDoublev
 call).
viewport
Specifies the current viewport (as from a
glGetIntegerv
 call).
winx, winy, winz
Return the computed window coordinates.
Remarks
The
gluProject
 function transforms the specified object coordinates into window coordinates using
modelMatrix
,
projMatrix
, and
viewport
. The result is stored in
winx
,
winy
, and
winz
. A return value of
GL_TRUE
 indicates success, and
GL_FALSE
 indicates failure.
See Also
glGet
,
gluUnProject


gluPwlCurve
The
gluPwlCurve
 function describes a piecewise linear NURBS trimming curve.
void gluPwlCurve(
GLUnurbsObj
*nobj
,
GLint
count
,
GLfloat
*array
,
GLint
stride
,
GLenum
type
);
Parameters
nobj
Specifies the NURBS object (created with
gluNewNurbsRenderer
).
count
Specifies the number of points on the curve.
array
Specifies an array containing the curve points.
stride
Specifies the offset (a number of single-precision floating-point values) between points on the curve.
type
Specifies the type of curve. Must be either
GLU_MAP1_TRIM_2
 or
GLU_MAP1_TRIM_3
.
Remarks
The
gluPwlCurve
 function describes a piecewise linear trimming curve for a NURBS surface. A piecewise linear curve consists of a list of coordinates of points in the parameter space for the NURBS surface to be trimmed. These points are connected with line segments to form a curve. If the curve is an approximation to a real curve, the points should be close enough that the resulting path appears curved at the resolution used in the application.
If
type
 is
GLU_MAP1_TRIM_2
, then it describes a curve in two-dimensional (
u
 and
v
) parameter space. If it is
GLU_MAP1_TRIM_3
, then it describes a curve in two-dimensional homogeneous (
u
,
v
, and
w
) parameter space. See
gluBeginTrim
 for more information about trimming curves.
See Also
gluBeginCurve
,
gluBeginTrim
,
gluNewNurbsRenderer
,
gluNurbsCurve


gluQuadricCallback
The
gluQuadricCallback
function defines a callback for a quadrics object.
void
gluQuadricCallback
(
GLUquadricObj
*qobj
,
GLenum
which
,
void
(*fn)(
)
);
Parameters
qobj
Specifies the quadrics object (created with
gluNewQuadric
).
which
Specifies the callback being defined. The only valid value is
GLU_ERROR
.
fn
Specifies the function to be called.
Remarks
The
gluQuadricCallback
 function is used to define a new callback to be used by a quadrics object. If the specified callback is already defined, then it is replaced. If
fn
 is NULL, then any existing callback is erased.
The one legal callback is
GLU_ERROR
:
GLU_ERROR
The function is called when an error is encountered. Its single argument is of type GLenum, and it indicates the specific error that occurred. Character strings describing these errors can be retrieved with the
gluErrorString call.
See Also
gluErrorString
,
gluNewQuadric


gluQuadricDrawStyle
The
gluQuadricDrawStyle
 function specifies the draw style desired for quadrics.
void gluQuadricDrawStyle
(
GLUquadricObj
*qobj
,
GLenum
drawStyle
);
Parameters
qobj
Specifies the quadrics object (created with
gluNewQuadric
).
drawStyle
Specifies the desired draw style. Valid values are
GLU_FILL
,
GLU_LINE
,
GLU_SILHOUETTE
, and
GLU_POINT
.
Remarks
The
gluQuadricDrawStyle
 function specifies the draw style for quadrics rendered with
 qobj.
 The legal values are as follows:
GLU_FILL
Quadrics are rendered with polygon primitives. The polygons are drawn in a counterclockwise fashion with respect to their normals (as defined with
gluQuadricOrientation
).
GLU_LINE
Quadrics are rendered as a set of lines.
GLU_SILHOUETTE
Quadrics are rendered as a set of lines, except that edges separating coplanar faces will not be drawn.
GLU_POINT
Quadrics are rendered as a set of points.
See Also
gluNewQuadric
,
gluQuadricNormals
,
gluQuadricOrientation
,
gluQuadricTexture


gluQuadricNormals
The
gluQuadricNormals
 function specifies what kind of normals are desired for quadrics.
void gluQuadricNormals
(
GLUquadricObj
*qobj
,
GLenum
normals
);
Parameters
qobj
Specifes the quadrics object (created with
gluNewQuadric
).
normals
Specifies the desired type of normals. Valid values are
GLU_NONE
,
GLU_FLAT
, and
GLU_SMOOTH
.
Remarks
The
gluQuadricNormals
 function specifies what kind of normals are desired for quadrics rendered with
qobj
. The legal values are as follows:
GLU_NONE
No normals are generated.
GLU_FLAT
One normal is generated for every facet of a quadric.
GLU_SMOOTH
One normal is generated for every vertex of a quadric. This is the default.
See Also
gluNewQuadric
,
gluQuadricDrawStyle
,
gluQuadricOrientation
,
gluQuadricTexture


gluQuadricOrientation
The
gluQuadricOrientation
 function specifies inside/outside orientation for quadrics.
void gluQuadricOrientation
(
GLUquadricObj
*qobj
,
GLenum
orientation
);
Parameters
qobj
Specifies the quadrics object (created with
gluNewQuadric
).
orientation
Specifies the desired orientation. Valid values are
GLU_OUTSIDE
 and
GLU_INSIDE
.
Remarks
The
 gluQuadricOrientation
 function specifies what kind of orientation is desired for quadrics rendered with
qobj
. The
orientation
 values are as follows:
GLU_OUTSIDE
Quadrics are drawn with normals pointing outward.
GLU_INSIDE
Normals point inward. The default is
GLU_OUTSIDE
.
Notice that the interpretation of
outward
 and
inward
 depends on the quadric being drawn.
See Also
gluNewQuadric
,
gluQuadricDrawStyle
,
gluQuadricNormals
,
gluQuadricTexture


gluQuadricTexture
The
gluQuadricTexture
 function specifies if texturing is desired for quadrics.
void gluQuadricTexture
(
GLUquadricObj
*qobj
,
GLboolean
textureCoords
);
Parameters
qobj
Specifies the quadrics object (created with
gluNewQuadric
).
textureCoords
Specifies a flag indicating if texture coordinates should be generated.
Remarks
The
gluQuadricTexture
 function specifies if texture coordinates should be generated for quadrics rendered with
qobj
. If the value of
textureCoords
 is
GL_TRUE
, then texture coordinates are generated, and if
textureCoords
 is
GL_FALSE
, they are not. The default is
GL_FALSE
.
The manner in which texture coordinates are generated depends upon the specific quadric rendered.
See Also
gluNewQuadric
,
gluQuadricDrawStyle
,
gluQuadricNormals
,


gluScaleImage
The
gluScaleImage
 function scales an image to an arbitrary size.
int gluScaleImage
(
GLenum
format
,
GLint
widthin
,
GLint
heightin
,
GLenum
typein
,
const void
*datain
,
GLint
widthout
,
GLint
heightout
,
GLenum
typeout
,
void
*dataout
);
Parameters
format
Specifies the format of the pixel data. The following symbolic values are valid:
GL_COLOR_INDEX, GL_STENCIL_INDEX, GL_DEPTH_COMPONENT, GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA, GL_RGB, GL_RGBA, GL_LUMINANCE,
 and
GL_LUMINANCE_ALPHA
.
widthin, heightin
Specify the width and height, respectively, of the source image that is scaled.
typein
Specifies the data type for
datain
. Must be one of
GL_UNSIGNED_BYTE, GL_BYTE, GL_BITMAP, GL_UNSIGNED_SHORT, GL_SHORT, GL_UNSIGNED_INT, GL_INT,
or
GL_FLOAT
.
datain
Specifies a pointer to the source image.
widthout, heightout
Specify the width and height, respectively, of the destination image.
typeout
Specifies the data type for
dataout
. Must be one of
GL_UNSIGNED_BYTE, GL_BYTE, GL_BITMAP, GL_UNSIGNED_SHORT, GL_SHORT, GL_UNSIGNED_INT, GL_INT,
 or
GL_FLOAT
.
dataout
Specifies a pointer to the destination image.
Remarks
The
gluScaleImage
 function scales a pixel image using the appropriate pixel store modes to unpack data from the source image and pack data into the destination image.
When shrinking an image,
gluScaleImage
 uses a box filter to sample the source image and create pixels for the destination image. When magnifying an image, the pixels from the source image are linearly interpolated to create the destination image.
A return value of zero indicates success, otherwise a GLU error code is returned indicating what the problem was (see
gluErrorString
).
See
glReadPixels
 for a description of the acceptable values for the
format
,
typein
, and
typeout
 parameters.
See Also
glDrawPixels
,
glReadPixels
,
gluBuild1DMipmaps
,
gluBuild2DMipmaps
,
gluErrorString


gluSphere
The
gluSphere
 function draws a sphere.
void gluSphere
(
GLUquadricObj
*qobj
,
GLdouble
radius
,
GLint
slices
,
GLint
stacks
);
Parameters
qobj
Specifies the quadrics object (created with
gluNewQuadric
).
radius
Specifies the radius of the sphere.
slices
Specifies the number of subdivisions around the
z
 axis  (similar to lines of longitude).
stacks
Specifies the number of subdivisions along the
z
 axis (similar to lines of latitude).
Remarks
The
gluSphere
 function draws a sphere of the given radius centered around the origin. The sphere is subdivided around the
z
 axis into slices and along the
z
 axis into stacks (similar to lines of longitude and latitude).
If the orientation is set to
GLU_OUTSIDE
 (with
gluQuadricOrientation
), then any normals generated point away from the center of the sphere. Otherwise, they point toward the center of the sphere.
If texturing is turned on (with
gluQuadricTexture
), then texture coordinates are generated so that
t
 ranges from 0.0 at
z
 =
-
radius
 to 1.0 at
z
 =
radius
 (
t
 increases linearly along longitudinal lines), and
s
 ranges from 0.0 at the +
y
 axis, to 0.25 at the +
x
 axis, to 0.5 at the
y
 axis, to 0.75 at the
x
 axis, and back to 1.0 at the +
y
 axis.
See Also
gluCylinder
,
gluDisk
,
gluNewQuadric
,
gluPartialDisk
,
gluQuadricOrientation
,
gluQuadricTexture


gluTessBeginContour, gluTessEndContour
The
gluTessBeginContour
 and
gluTessEndContour
 functions delimit a contour description.
void
gluTessBeginContour
(
GLUtesselator
*tess
);
void gluTessEndContour
(
GLUtesselator
*tess
);
Parameters
tess
Specifies the tessellation object (created with
gluNewTess
).
Remarks
The
 gluTessBeginContour
 and
gluTessEndContour
 functions delimit the definition of a polygon contour. Within each
gluTessBeginContour/gluTessEndContour
 pair, there can be zero or more calls to
gluTessVertex
. The vertexes specify a closed contour (the last vertex of each contour is automatically linked to the first). You can call
gluTessBeginContour
 between
gluTessBeginPolygon
 and
gluTessEndPolygon
 only.
See Also
gluNewTess
,
gluTessBeginPolygon
,
gluTessVertex
,
gluTessCallback
,
gluTessProperty
,
gluTessNormal
,
gluTessEndPolygon


gluTessBeginPolygon
,
gluTessEndPolygon
The
gluTessBeginPolygon
 and
gluTessEndPolygon
 functions delimit a polygon description.
void gluTessBeginPolygon
(
GLUtesselator
 *
tess
,
void
 *
polygon_data
);
void gluTessEndPolygon
(
GLUtesselator
 *
tess
);
Parameters
tess
Specifies the tessellation object (created with
gluNewTess
).
polygon_data
Specifies a pointer to user-defined polygon data.
Remarks
The
 gluTessBeginPolygon
 and
gluTessEndPolygon
 functions delimit the definition of a non-convex polygon. Within each
gluTessBeginPolygon
/
gluTessEndPolygon
 pair, you must include one or more calls to
gluTessBeginContour
/
gluTessEndContour
. Within each contour, there are zero or more calls to
gluTessVertex
. The vertexes specify a closed contour (the last vertex of each contour is automatically linked to the first).
The
polygon_data
 parameter is a pointer to a user-defined data structure. If the appropriate callback(s) are specified (see
gluTessCallback
), this pointer is returned to the callback function(s), making it a convenient way to store per-polygon information.
When you call
gluTessEndPolygon
, the polygon is tessellated, and the resulting triangles are described through callbacks. For descriptions of the callback functions, see
gluTessCallback
.
Example
A quadrilateral with a triangular hole in it can be described as follows:
gluTessBeginPolygon(tobj, NULL);
  gluTessBeginContour(tobj);
    gluTessVertex(tobj, v1, v1);
    gluTessVertex(tobj, v2, v2);
    gluTessVertex(tobj, v3, v3);
    gluTessVertex(tobj, v4, v4);
  gluTessEndContour(tobj);
  gluTessBeginContour(tobj);
    gluTessVertex(tobj, v5, v5);
    gluTessVertex(tobj, v6, v6);
    gluTessVertex(tobj, v7, v7);
  gluTessEndContour(tobj);
gluTessEndPolygon(tobj);
See Also
gluNewTess
,
gluTessBeginContour
,
gluTessVertex
,
gluTessCallback
,
gluTessProperty
,
gluTessNormal


gluTessCallback
The
gluTessCallback
 function defines a callback for a tessellation object.
void
gluTessCallback
(
GLUtesselator
*tess
,
GLenum
which
,
void
 (
*fn
)( )
);
Parameters
tess
Specifies the tessellation object (created with
gluNewTess
).
which
Specifies the callback being defined. The following values are valid:
GLU_TESS_BEGIN
,
 GLU_TESS_BEGIN_DATA
,
 GLU_TESS_EDGE_FLAG
,
 GLU_TESS_EDGE_FLAG_DATA
,
 GLU_TESS_VERTEX
,
 GLU_TESS_VERTEX_DATA
,
 GLU_TESS_END
,
 GLU_TESS_END_DATA
,
 GLU_TESS_COMBINE
,
 GLU_TESS_COMBINE_DATA
,
 GLU_TESS_ERROR
,
and
 GLU_TESS_ERROR_DATA
.
fn
Specifies the function to be called.
Remarks
Use
gluTessCallback
 to specify a callback to be used by a tessellation object. If the specified callback is already defined, then it is replaced. If
fn
 is NULL, then the existing callback becomes undefined.
The tessallation object uses these callbacks to describe how a polygon you specify is broken into triangles. Note that there are two versions of each callback: one with polygon data that you can define and one without. If both versions of a particular callback are specified then the callback with the polygon data you specify will be used. The
polygon_data
 parameter of
gluTessBeginPolygon
 is a copy of the pointer that was specified when
gluTessBeginPolygon
 was called.
The legal callbacks are as follows:
GLU_TESS_BEGIN
The
GLU_TESS_BEGIN
 callback is invoked like
glBegin
 to indicate the start of a (triangle) primitive. The function takes a single argument of type GLenum.  If the
GLU_TESS_BOUNDARY_ONLY
 property is set to
GL_FALSE
 then the argument is set to either
 GL_TRIANGLE_FAN
,
GL_TRIANGLE_STRIP
,
or
GL_TRIANGLES
. If the
 GLU_TESS_BOUNDARY_ONLY
 property is set to
GL_TRUE
then the argument will be set to
GL_LINE_LOOP
. The function prototype for this callback is as follows:
void begin ( GLenum type );
GLU_TESS_BEGIN_DATA
The
GLU_TESS_BEGIN_DATA
 is same as the
GLU_TESS_BEGIN
callback except that it takes an additional pointer argument. This pointer is identical to the opaque pointer provided when you call
gluTessBeginPolygon
. The function prototype for this callback is as follows:
void beginData ( GLenum type, void *polygon_data );
GLU_TESS_EDGE_FLAG
The
GLU_TESS_EDGE_FLAG
 callback is similar to
glEdgeFlag
. The function takes a single Boolean flag that indicates which edges lie on the polygon boundary. If the flag is
GL_TRUE
, then each vertex that follows begins an edge that lies on the polygon boundary; that is, an edge which separates an interior region from an exterior one. If the flag is
GL_FALSE
, then each vertex that follows begins an edge that lies in the polygon interior. The
GLU_TESS_EDGE_FLAG
 callback (if defined) is invoked before the first vertex callback is made.
Because triangle fans and triangle strips do not support edge flags, the begin callback is not called with
GL_TRIANGLE_FAN
 or
GL_TRIANGLE_STRIP
 if an edge flag callback is provided. Instead, the fans and strips are converted to independent triangles. The function prototype for this callback is as follows:
void edgeFlag ( GLboolean flag );
GLU_TESS_EDGE_FLAG_DATA
The
GLU_TESS_EDGE_FLAG_DATA
 callback is the same as the
GLU_TESS_EDGE_FLAG
 callback except that it takes an additional pointer argument. This pointer is identical to the opaque pointer provided when you call
gluTessBeginPolygon
. The function prototype for this callback is as follows:
void edgeFlagData ( GLboolean flag, void *polygon_data );
GLU_TESS_VERTEX
The
GLU_TESS_VERTEX
 callback is invoked between the begin and end callbacks. It is similar to
glVertex
, and it defines the vertexes of the triangles created by the tessellation process. The function takes a pointer as its only argument. This pointer is identical to the opaque pointer that you provided when you defined the vertex (see
gluTessVertex
). The function prototype for this callback is as follows:
void vertex ( void *vertex_data );
GLU_TESS_VERTEX_DATA
The
GLU_TESS_VERTEX_DATA
 is the same as the
GLU_TESS_VERTEX
 callback except that it takes an additional pointer argument. This pointer is identical to the opaque pointer provided when you call
gluTessBeginPolygon
. The function prototype for this callback is as follows:
void vertexData ( void *vertex_data, void *polygon_data );
GLU_TESS_END
The
GLU_TESS_END
 callback serves the same purpose as
glEnd
. It indicates the end of a primitive and it takes no arguments. The function prototype for this callback is as follows:
void end ( void );
GLU_TESS_END_DATA
The
GLU_TESS_END_DATA
 callback is the same as the
GLU_TESS_END
 callback except that it takes an additional pointer argument. This pointer is identical to the opaque pointer provided when you call
gluTessBeginPolygon
.The function prototype for this callback is as follows:
void endData ( void *polygon_data);
GLU_TESS_COMBINE
The
GLU_TESS_COMBINE
 callback is called to create a new vertex when the tessellation detects an intersection, or to merge features. The function takes four arguments: an array of three elements each of type GLdouble, an array of four pointers, an array of four elements each of type GLfloat, and a pointer to a pointer. The prototype is as follows:
void combine( GLdouble coords[3], void *vertex_data[4],
                       GLfloat weight[4], void **outData );
The vertex is defined as a linear combination of up to 4 existing vertexes, stored in
vertex_data
. The coefficients of the linear combination are given by
weight
; these weights always sum to 1.0.  All vertex pointers are valid even when some of the weights are zero.
coords
 gives the location of the new vertex.
You must allocate another vertex, interpolate parameters using
vertex_data
 and weight, and return the new vertex pointer in
outData
. This handle is supplied during rendering callbacks. You are responsible for freeing the memory sometime after calling
gluTessEndPolygon
.
For example, if the polygon lies in an arbitrary plane in 3-space, and you associate a color with each vertex, the
GLU_TESS_COMBINE
 callback might look like the following:
void myCombine( GLdouble coords[3], VERTEX *d[4],
                         GLfloat w[4], VERTEX **dataOut )
{
VERTEX *new = new_vertex();
new->x = coords[0];
new->y = coords[1];
new->z = coords[2];
new->r = w[0]*d[0]->r + w[1]*d[1]->r + w[2]*d[2]->r +
w[3]*d[3]->r;
new->g = w[0]*d[0]->g + w[1]*d[1]->g + w[2]*d[2]->g +
w[3]*d[3]->g;
new->b = w[0]*d[0]->b + w[1]*d[1]->b + w[2]*d[2]->b +
w[3]*d[3]->b;
new->a = w[0]*d[0]->a + w[1]*d[1]->a + w[2]*d[2]->a +
w[3]*d[3]->a;
*dataOut = new;
}
When the tessellation detects an intersection, the
GLU_TESS_COMBINE
 or
GLU_TESS_COMBINE_DATA
 callback (see below) must be defined, and it must write a non-NULL pointer into
dataOut
. Otherwise the
GLU_TESS_NEED_COMBINE_CALLBACK
 error occurs, and no output is generated. (This is the only error that can occur during tessellation and rendering.)
GLU_TESS_COMBINE_DATA
The
GLU_TESS_COMBINE_DATA
 callback is the same as the
GLU_TESS_COMBINE
 callback except that it takes an additional pointer argument. This pointer is identical to the opaque pointer provided when you call
gluTessBeginPolygon
. The function prototype for this callback is as follows:
void combineData ( GLdouble coords[3], void *vertex_data[4],
GLfloat weight[4], void **outData,
void *polygon_data );
GLU_TESS_ERROR
The
GLU_TESS_ERROR
 callback is called when an error is encountered. The one argument is of type GLenum; it indicates the specific error that occurred and will be set to one of
GLU_TESS_MISSING_BEGIN_POLYGON, GLU_TESS_MISSING_END_POLYGON, GLU_TESS_MISSING_BEGIN_CONTOUR, GLU_TESS_MISSING_END_CONTOUR, GLU_TESS_COORD_TOO_LARGE, GLU_TESS_NEED_COMBINE_CALLBACK
. You can call
gluErrorString
 to retrieve character strings describing these errors.The function prototype for this callback is as follows:
void error ( GLenum errno );
The GLU library recovers from the first four errors by inserting the missing call(s).
GLU_TESS_COORD_TOO_LARGE
 indicates that some vertex coordinate exceeded the predefined constant
GLU_TESS_MAX_COORD
 in absolute value, and that the value has been clamped. (Coordinate values must be small enough so that two can be multiplied together without overflow.)
GLU_TESS_NEED_COMBINE_CALLBACK
 indicates that the tessellation detected an intersection between two edges in the input data, and the
GLU_TESS_COMBINE
 or
GLU_TESS_COMBINE_DATA
 callback was not provided. No output will be generated.
GLU_TESS_ERROR_DATA
The
GLU_TESS_ERROR_DATA
 callback is the same as the
GLU_TESS_ERROR
 callback except that it takes an additional pointer argument. This pointer is identical to the opaque pointer provided when you call
gluTessBeginPolygon
. The function prototype for this callback is as follows:
void errorData ( GLenum errno, void *polygon_data );
Example
You can render tessallated polygons directly as follows:
gluTessCallback(tess, GLU_TESS_BEGIN, glBegin);
gluTessCallback(tess, GLU_TESS_VERTEX, glVertex3dv);
gluTessCallback(tess, GLU_TESS_END, glEnd);
gluTessBeginPolygon(tess, NULL);
gluTessBeginContour(tess);
gluTessVertex(tess, v, v);
. . .
gluTessEndContour(tess);
gluTessEndPolygon(tess);
Typically, you should store the tessellated polygon in a display list so that it does not need to be tessellated every time it is rendered.
See Also
glBegin
,
glEdgeFlag
,
glVertex
,
gluDeleteTess
,
gluErrorString
,
gluNewTess
,
gluTessVertex


gluTessNormal
The
gluTessNormal
 function specifies a normal for a polygon.
void gluTessNormal
(
GLUtesselator
 *
tess
,
GLdouble
x
,
GLdouble
y
,
GLdouble
z
);
Parameters
tess
Specifies the tessellation object (created with
gluNewTess
).
x
Specifies the x-coordinate component of a normal.
y
Specifies the y-coordinate component of a normal.
z
Specifies the z-coordinate component of a normal.
Remarks
The
 gluTessNormal
 function describes a normal for a polygon that you define. All input data is projected onto a plane perpendicular to one of the three coordinate axes before tessellation, and all output triangles are oriented counterclockwise with respect to the normal. (You can obtain clockwise orientation by reversing the sign of the supplied normal). For example, if you know that all polygons lie in the x-y plane, call
gluTessNormal
(tess, 0.0, 0.0, 1.0) before rendering any polygons.
If the supplied normal is (0,0,0) (the default value), the normal is determined as follows. The direction of the normal, up to its sign, is found by fitting a plane to the vertexes, without regard to how the vertexes are connected. It is expected that the input data lies approximately in the plane; otherwise projection perpendicular to one of the three coordinate axes can change the geometry substantially. The sign of the normal is chosen so that the sum of the signed areas of all input contours is non-negative (where a counter-clock-wise contour has positive area).
The supplied normal persists until it is changed by another call to
gluTessNormal
.
See Also
gluTessBeginPolygon
,
gluTessEndPolygon


gluTessProperty
The
gluTessProperty
 function sets the property of a tessellation object.
void
gluTessProperty
(
GLUtesselator
*tess
,
GLenum
which
,
GLdouble
value
);
Parameters
tess
Specifies the tessellation object (created with
gluNewTess
).
which
Specifies the property value to set. Valid values are
GLU_TESS_WINDING_RULE
,
GLU_TESS_BOUNDARY_ONLY
, and
GLU_TESS_TOLERANCE
.
value
Specifies the value of the indicated property.
Remarks
The
gluTessProperty
 function controls properties stored in a tessellation object. These properties affect the way that the polygons are interpreted and rendered. The legal values are as follows:
GLU_TESS_WINDING_RULE
Determines which parts of the polygon are on the "interior." The
value
 parameter may be set to one of
GLU_TESS_WINDING_ODD
,
GLU_TESS_WINDING_NONZERO
,
GLU_TESS_WINDING_POSITIVE
, or
GLU_TESS_WINDING_NEGATIVE
, or
GLU_TESS_WINDING_ABS_GEQ_TWO
.
To understand how the winding rule works, first consider that the input contours partition the plane into regions. The winding rule determines which of these regions are inside the polygon.
For a single contour C, the winding number of a point
x
 is simply the signed number of revolutions we make around
x
 as we travel once around C (where counterclockwise is positive). When there are several contours, the individual winding numbers are summed. This procedure associates a signed integer value with each point
x
 in the plane. Note that the winding number is the same for all points in a single region.
The winding rule classifies a region as "inside" if its winding number belongs to the chosen category (odd, non-zero, positive, negative, or absolute value of at least two). The previous GLU tessellator (prior to GLU 1.2) used the "odd" rule. The "non-zero" rule is another common way to define the interior. The other three rules are useful for polygon CSG operations.
GLU_TESS_BOUNDARY_ONLY
Specifies a Boolean value (
value
 should be set to
GL_TRUE
 or
GL_FALSE
). When set to
GL_TRUE
, a set of closed contours separating the polygon interior and exterior are returned instead of a tessellation. Exterior contours are oriented counterclockwise with respect to the normal, interior contours are oriented clockwise. The
GLU_TESS_BEGIN
 and
GLU_TESS_BEGIN_DATA
 callbacks use the type
GL_LINE_LOOP
 for each contour.
GLU_TESS_TOLERANCE
Specifies a tolerance for merging features to reduce the size of the output. For example, two vertexes that are very close to each other might be replaced by a single vertex. The tolerance is multiplied by the largest coordinate magnitude of any input vertex; this specifies the maximum distance that any feature can move as the result of a single merge operation. If a single feature takes part in several merge operations, the total distance moved can be larger.
Feature merging is completely optional; the tolerance is only a hint. The implementation is free to merge in some cases and not in others, or to never merge features at all. The default tolerance is zero.
The current implementation merges vertexes only if they are exactly coincident, regardless of the current tolerance. A vertex is spliced into an edge only if the implementation is unable to distinguish which side of the edge the vertex lies on. Two edges are merged only when both endpoints are identical.
See Also
gluGetTessProperty


gluTessVertex
The
gluTessVertex
function specifies a vertex on a polygon.
void gluTessVertex
(
GLUtesselator
*tess
,
GLdouble
v[3]
,
void
*data
);
Parameters
tess
Specifies the tessellation object (created with
gluNewTess
).
v
Specifies the location of the vertex.
data
Specifies an opaque pointer passed back to the user with the vertex callback (as specified by
gluTessCallback
).
Remarks
The
gluTessVertex
function describes a vertex on a polygon that the user is defining. Successive
gluTessVertex
 calls describe a closed contour. For example, if the user wants to describe a quadrilateral, then
gluTessVertex
 should be called four times. The
gluTessVertex
function can only be called between
gluTessBeginContour
 and
gluTessEndContour
.
The
data
 parameter normally points to a structure containing the vertex location, as well as other per-vertex attributes such as color and normal. This pointer is passed back to the user through the
GLU_VERTEX
 callback after tessellation (see
gluTessCallback
).
Example
A quadrilateral with a triangular hole in it can be described as follows:
gluTessBeginPolygon(tess, NULL);
gluTessBeginContour(tess);
gluTessVertex(tess, v1, v1);
gluTessVertex(tess, v2, v2);
gluTessVertex(tess, v3, v3);
gluTessVertex(tess, v4, v4);
gluTessEndContour(tess);
gluNextContour(tess, GLU_INTERIOR);
gluTessBeginContour(tess);
gluTessVertex(tess, v5, v5);
gluTessVertex(tess, v6, v6);
gluTessVertex(tess, v7, v7);
gluTessEndContour(tess);
gluTessEndPolygon(tess);
See Also
gluTessBeginPolygon
,
gluNewTess
,
gluTessCallback
,
gluTessBeginContour
,
gluTessProperty
,
gluTessNormal


gluUnProject
The
gluUnProject
 function maps window coordinates to object coordinates.
int gluUnProject
(
GLdouble
winx
,
GLdouble
winy
,
GLdouble
winz
,
const GLdouble
modelMatrix[16]
,
const GLdouble
projMatrix[16]
,
const GLint
viewport[4]
,
GLdouble
*objx
,
GLdouble
*objy
,
GLdouble
*objz
);
Parameters
winx, winy, winz
Specify the window coordinates to be mapped.
modelMatrix
Specifies the modelview matrix (as from a
glGetDoublev
 call).
projMatrix
Specifies the projection matrix (as from a
glGetDoublev
 call).
viewport
Specifies the viewport (as from a
glGetIntegerv
 call).
objx, objy, objz
Returns the computed object coordinates.
Remarks
The
gluUnProject
 function maps the specified window coordinates into object coordinates using
modelMatrix
,
projMatrix
, and
viewport
. The result is stored in
objx
,
objy
, and
objz
. A return value of
GL_TRUE
 indicates success, and
GL_FALSE
 indicates failure.
See Also
glGet
,
gluProject


Introduction to Porting to OpenGL for Windows NT
OpenGL is designed for compatibility across hardware and operating systems. This design makes it easier for programmers to port OpenGL programs from one system to another. While each operating system has unique requirements, much of the OpenGL code in your current programs can be used as is. To port your OpenGL application to Windows NT you'll have to modify your programs to work with the Windows NT windowing system.
In general applications are ported to OpenGL for Windows NT from one of two platforms:
·
OpenGL applications developed for the X Window System and the X library (Xlib).
·
IRIS GL applications.
The following topics describe how to port your applications from each of these platforms. The topics discuss porting OpenGL and window management code only; there is no discussion of other operating system port issues such as reading files, messaging, thread creation, and so on. This porting guide focuses on specific porting issues and assumes that you have an understanding of OpenGL and Windows NT programming.


Porting X Window System Applications
Like Windows NT, the X Window System is an event-handling, message-based system that uses windows controls and menus. The OpenGL code in your X Window System application probably is located in areas that roughly correspond to where it will appear when you port it to Windows NT. Most of your OpenGL code will not change, but you must rewrite any code that is specific to the X Window System. For more information on Win 32 User and GDI calls, refer to the
Win32 Programmer's Reference
. For more information on the X Window System and UNIX, refer to your X Window System and UNIX operating system documentation.
In general, you'll use the following procedure to port your X Window System OpenGL programs to Windows NT.
1.
Rewrite the X Window System specific code using equivalent Win32 code. Locate window-creation and event-handling code. The X Window System and Windows NT are both event-handling, message-based windowing systems, which makes it easier to determine where to make the appropriate changes. (However, especially for large applications, rewriting an application from one operating system to another can be a complex and difficult undertaking.)
2.
Locate any code that uses GLX functions. These are the functions you'll translate to their corresponding Win32 functions.
3.
Translate GLX pixel format functions and Visual/Drawable functions to appropriate Win32/OpenGL pixel format and device context functions.
4.
Translate GLX rendering context functions to Win32/OpenGL rendering context functions.
5.
Translate GLX Pixmap functions to corresponding Win32 functions.
6.
Translate GLX framebuffer and other GLX functions to the appropriate Win32 functions.


Translating the GLX Library
OpenGL X Window System programs use the OpenGL Extension with the X Windows System (GLX) library. The library is a set of functions and routines that initialize the pixel format, control rendering, and do other OpenGL specific tasks. It connects the OpenGL library to the X Window System by managing window handles and rendering contexts. You must translate these functions to their corresponding Windows NT functions. The following table lists the X Window System GLX functions and their corresponding Win32 functions.
GLX/Xlib Functions
Win32 Functions
glXChooseVisual
ChoosePixelFormat
glXCopyContext
---
glXCreateContext
wglCreateContext
glXCreateGLXPixmap
CreateDIBitmap
/
CreateDIBSection
glXDestroyContext
wglDeleteContext
glXDestroyGLXPixmap
DeleteObject
glXGetConfig
DescribePixelFormat
glXGetCurrentContext
wglGetCurrentContext
glXGetCurrentDrawable
wglGetCurrentDC
glXIsDirect
---
glXMakeCurrent
wglMakeCurrent
glXQueryExtension
GetVersion
glXQueryVersion
GetVersion
glXSwapBuffers
SwapBuffers
glXUseXFont
wglUseFontBitmaps
XGetVisualInfo
GetPixelFormat
XCreateWindow
CreateWindow
/
CreateWindowEx
and
GetDC
/
BeginPaint
XSync
GdiFlush
---
SetPixelFormat
Some GLX functions don't have a corresponding Win32 function. To port these functions to Win32, rewrite your code to achieve the same functionality. For example,
glXWaitGL
 has no corresponding Win32 function but you can achieve the same result, executing any pending OpenGL commands, by calling
glFinish
.
The following topics describe how to port GLX functions that set the pixel format, manage rendering contexts, and manage pixmaps and bitmaps.


Porting Device Contexts and Pixel Formats
Each window in Microsoft's implementation of OpenGL for Windows NT has its own current pixel format. A pixel format is defined by a
PIXELFORMATDESCRIPTOR
 data structure. Because each window has its own pixel format, you obtain a device context, set the pixel format of the device context, and then create an OpenGL rendering context for the device context. The rendering context automatically uses the pixel format of its device context.
The X Window System also uses a data structure,
XVisualInfo
, to specify the properties of pixels in a window. XVisualInfo structures contain a
Visual
 data structure that describes how color resources are used in a specific screen.
In the X Window System,
XVisualInfo
 is used to create windows by setting it to the pixel format you want. The returned structure is used to create the window and a rendering context. In Windows NT, you first create a window and get a handle to a device context (HDC) of the window. The HDC is then used to set the pixel format for the window. The rendering context uses the pixel format of the window.
The following table compares the X Window System and GLX visual functions with their corresponding Win32 pixel format functions.
X Window/GLX Visual Functions
Win32 Pixel Format Functions
XVisualInfo*
glXChooseVisual
(Display
*dpy
,
int
screen
,
int
*attribList
)
int
ChoosePixelFormat
(HDC
hdc
,
PIXELFORMATDESCRIPTOR
*ppfd
)
int
glXGetConfig
(Display
*dpy
,
XVisualInfo
*vis
,
int
*attribList
,
int
*value
)
int
DescribePixelFormat
(HDC
hdc
,
int
iPixelFormat
,
UINT
nBytes
,
LPPIXELFORMATDESCRIPTOR
ppfd
)
XVisualInfo*
XGetVisualInfo
(Display
*dpy
,
long
vinfo_mask
,
XVisualInfo
*vinfo_templ
,
int
*nitems
)
int
GetPixelFormat
(HDC
hdc
)
The
visual
 returned by
glxChooseVisual
 is used when a window is created.
BOOL
SetPixelFormat
(HDC
hdc
,
int
iPixelFormat
,
PIXELFORMATDESCRIPTOR
*ppfd
)
The following sections give examples of pixel format code fragments for an X Window System program, and the same code after it has been ported to Windows NT.
For more information on pixel formats, see
Pixel Formats
.


GLX Pixel Format Code Sample
The code fragment below shows how an X Windows System OpenGL program uses GLX visual/pixel formatting functions.
/* X globals, defines, and prototypes */
Display *dpy;
Window glwin;
static int attributes[] = {GLX_DEPTH_SIZE, 16, GLX_DOUBLEBUFFER, None};
.
.
.
    /* find an OpenGL-capable Color Index visual with depth buffer */
    vi = glXChooseVisual(dpy, DefaultScreen(dpy), attributes);
    if (vi == NULL) {
        fprintf(stderr, "could not get visual\n");
        exit(1);
    }
The Visual can be used to create a window and a rendering context.


Win32 Pixel Format Code Sample
The following code fragment shows a function that sets the pixel format using Win32 functions.
BOOL bSetupPixelFormat(HDC hdc)
{
    PIXELFORMATDESCRIPTOR pfd, *ppfd;
    int pixelformat;
    ppfd = &pfd;
    ppfd->nSize = sizeof(PIXELFORMATDESCRIPTOR);
    ppfd->nVersion = 1;
    ppfd->dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL |
PFD_DOUBLEBUFFER;
    ppfd->dwLayerMask = PFD_MAIN_PLANE;
    ppfd->iPixelType = PFD_TYPE_COLORINDEX;
    ppfd->cColorBits = 8;
    ppfd->cDepthBits = 16;
    ppfd->cAccumBits = 0;
    ppfd->cStencilBits = 0;
    pixelformat = ChoosePixelFormat(hdc, ppfd);
    if ( (pixelformat = ChoosePixelFormat(hdc, ppfd)) == 0 )
    {
        MessageBox(NULL, "ChoosePixelFormat failed", "Error", MB_OK);
        return FALSE;
    }
    if (SetPixelFormat(hdc, pixelformat, ppfd) == FALSE)
    {
        MessageBox(NULL, "SetPixelFormat failed", "Error", MB_OK);
        return FALSE;
    }
    return TRUE;
}


Porting Rendering Contexts
Both the X Window System and Windows NT render through rendering contexts. Six GLX functions manage rendering contexts and five of them have a corresponding Win32 function.
The following table lists the GLX rendering functions and their corresponding Win32 functions.
GLX Rendering Context Functions
Win32 Rendering Context Functions
GLXContext
glXCopyContext
(Display
*dpy
,
GLXContext
src
,
GLXContext
dst
,
GLuint
mask
)
No corresponding Win32 function.
GLXContext
glXCreateContext
(Display
*dpy
,
XVisualInfo
*vis
,
GLXContext
shareList
,
Bool
direct
)
HGLRC
wglCreateContext
(HDC
hdc
)
void
glXDeleteContext
(Display
*dpy
,
GLXContext
ctx
)
BOOL
wglDeleteContext
(HGLRC
hglrc
)
GLXContext
glXGetCurrentContext
(
void
)
HGLRC
wglGetCurrentContext
(
VOID
)
GLXDrawable
glXGetCurrentDrawable
(
void
)
HDC
wglGetCurrentDC
(
VOID
)
Bool
glXMakeCurrent
(Display
*dpy
,
GLXDrawable
draw
,
GLXContext
ctx
)
BOOL
wglMakeCurrent
(HDC
hdc
,
HGLRC
 hglrc
)
The X Window System and Windows NT use different names for return types and other types. You can search for occurrences of GLXContext to help find parts of your code that need to be ported.
The following sections compare rendering context code fragment samples in an X Window System program and the same code after it has been ported to Windows NT.
For more information on rendering contexts, see
Rendering Contexts
.


GLX Rendering Context Code Sample
The code fragment below shows how an X Windows System OpenGL program uses GLX rendering context functions.
Display *dpy;
/* display variable */
XVisualInfo *vi;
/* visual variable */
Window win;
/* window variable */
GLXDrawable drawable;
/* drawable variable */
GLXContext cx, cxTemp;
/* rendering context variables */
/* Code to open a display and get a visual. */
.
.
.
/* Create a GLX context. */
cx = glXCreateContext(dpy, vi, 0, GL_FALSE);
if (!cx) {
fprintf(stderr, "Cannot create context.\n");
exit(-1);
}
.
.
.
/* Connect the context to the window. */
glXMakeCurrent(dpy, win, cx);
.
.
.
/* When it's time to destroy the rendering context. . . */
cx = glXGetCurrentContext;
glXDestroyContext(dpy, cx);


Win32 Rendering Context Code Sample
The following code fragment shows how the GLX rendering context code in the previous section looks when it has been ported to Windows NT using Win32 functions.
HGLRC hRC;
// rendering context variable
/* Create and initialize a window */
.
.
.
/* Window message switch in a window procedure */
case WM_CREATE:
// Message when window is created.
{
HDC hDC, hDCTemp;
// device context handles
/* Get the handle of the windows device context. */
hDC = GetDC(hWnd);
/* Create a rendering context and make it the current context*/
hRC = wglCreateContext(hDC);
if (!hRC)
{
MessageBox(NULL, "Cannot create context.", "Error", MB_OK);
return FALSE;
}
wglMakeCurrent(hDC, hRC);
}
break;
.
.
.
case WM_DESTROYED:
// Message when window is destroyed.
{
HGLRC hRC
// rendering context handle
HDC hDC;
// device context handle
/* Release and free the device context and rendering context. */
hDC = wglGetCurrentDC;
hRC = wglGetCurrentContext;
wglMakeCurrent(NULL, NULL);
if (hRC)
wglDeleteContext(hRC);
if (hDC)
ReleaseDC(hWnd, hDC);
PostQuitMessage (0);
}
break;


Porting GLX Pixmap and Font Code
Porting GLX Pixmap Code
The X Window System uses
pixmaps
, which are off-screen virtual drawing surfaces in the form of a three-dimensional array of bits. You can think of a pixmap as a stack of bitmaps: a two-dimensional array of pixels with each pixel having a value from 0 to 2
 (N)
-1 where N is the depth of the pixmap.
For OpenGL programs you use the GLX functions
glXCreateGLXPixmap
 and
glXDestroyGLXPixmap
 to create and destroy GLX pixmaps used for off-screen rendering.
Windows NT uses device-independent bitmaps that serve the same function as X Window System pixmaps. Use the standard Win32 bitmap functions to create and destroy bitmaps.
The following table lists the GLX pixmap functions and their corresponding Win32 bitmap functions.
GLX Pixmap and Font Functions
Win32 Bitmap and Font Functions
GLXPixmap
glXCreateGLXPixmap
(Display
*dpy
,
XVisualInfo
*vis
,
Pixmap
pixmap
)
HBITMAP
CreateDIBitmap
(HDC
hdc
,
LPBITMAPINFOHEADER
lpbmih
,
DWORD
fdwInit
,
CONST BYTE
*lpbIni
t,
LPBITMAPINFO
lpbmi
,
UINT
fuUsage
)
HBITMAP
CreateDIBSection
(HDC
hdc
,
LPBITMAPINFO
lpbmi
,
DWORD
fInit
,
DWORD
iUsage
)
void
glXDestroyGLXPixmap
(Display
*dpy
,
GLXPixmap
pix
)
BOOL
DeleteObject
(HGDIOBJ
hObject
)


Porting Other GLX Code
In addition to the Xlib and GLX functions described in the preceding sections, your program probably contains some of the other GLX or Xlib functions listed in
Translating the GLX Library
. Rewrite your X Window System code to Windows NT code substituting the appropriate functions.


A Porting Sample
It's easier to understand how to modify your X Window System OpenGL program for a Windows NT program if you can compare before and after samples, and you can better see how the translated code is used in the proper context. This section presents an example of an X Windows System OpenGL program and then shows how the program looks after it has been ported to Windows NT. Note that the OpenGL code is the same in both programs.


An X Windows System OpenGL Program
The following program is an X Windows System OpenGL program with the same OpenGL code used in the AUXEDEMO.C sample program supplied with the Win32 SDK. Compare this program with the Win32 OpenGL program in the next section.
/*
 * Example of an X Windows System OpenGL program.
 * OpenGL code is taken from auxdemo.c in the Win32 SDK.
 */
#include <GL/glx.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <X11/keysym.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <stdio.h>
/* X globals, defines, and prototypes */
Display *dpy;
Window glwin;
static int attributes[] = {GLX_DEPTH_SIZE, 16, GLX_DOUBLEBUFFER, None};
#define SWAPBUFFERS glXSwapBuffers(dpy, glwin)
#define BLACK_INDEX     0
#define RED_INDEX       1
#define GREEN_INDEX     2
#define BLUE_INDEX      4
#define WIDTH           300
#define HEIGHT          200
/* OpenGL globals, defines, and prototypes */
GLfloat latitude, longitude, latinc, longinc;
GLdouble radius;
#define GLOBE    1
#define CYLINDER 2
#define CONE     3
GLvoid resize(GLsizei, GLsizei);
GLvoid initializeGL(GLsizei, GLsizei);
GLvoid drawScene(GLvoid);
void polarView( GLdouble, GLdouble, GLdouble, GLdouble);
static Bool WaitForMapNotify(Display *d, XEvent *e, char *arg)
{
    if ((e->type == MapNotify) && (e->xmap.window == (Window)arg)) {
return GL_TRUE;
    }
    return GL_FALSE;
}
void
main(int argc, char **argv)
{
    XVisualInfo    *vi;
    Colormap        cmap;
    XSetWindowAttributes swa;
    GLXContext      cx;
    XEvent          event;
    GLboolean       needRedraw = GL_FALSE, recalcModelView = GL_TRUE;
    int
    dummy;
    dpy = XOpenDisplay(NULL);
    if (dpy == NULL){
        fprintf(stderr, "could not open display\n");
        exit(1);
    }
    if(!glXQueryExtension(dpy, &dummy, &dummy)){
        fprintf(stderr, "could not open display");
        exit(1);
    }
    /* find an OpenGL-capable Color Index visual with depth buffer */
    vi = glXChooseVisual(dpy, DefaultScreen(dpy), attributes);
    if (vi == NULL) {
        fprintf(stderr, "could not get visual\n");
        exit(1);
    }
    /* create an OpenGL rendering context */
    cx = glXCreateContext(dpy, vi,  None, GL_TRUE);
    if (cx == NULL) {
        fprintf(stderr, "could not create rendering context\n");
        exit(1);
    }
    /* create an X colormap since probably not using default visual */
    cmap = XCreateColormap(dpy, RootWindow(dpy, vi->screen),
vi->visual, AllocNone);
    swa.colormap = cmap;
    swa.border_pixel = 0;
    swa.event_mask = ExposureMask | KeyPressMask | StructureNotifyMask;
    glwin = XCreateWindow(dpy, RootWindow(dpy, vi->screen), 0, 0, WIDTH,
HEIGHT, 0, vi->depth, InputOutput, vi->visual,
CWBorderPixel | CWColormap | CWEventMask, &swa);
    XSetStandardProperties(dpy, glwin, "xogl", "xogl", None, argv,
argc, NULL);
    glXMakeCurrent(dpy, glwin, cx);
    XMapWindow(dpy, glwin);
    XIfEvent(dpy,  &event,  WaitForMapNotify,  (char *)glwin);
    initializeGL(WIDTH, HEIGHT);
    resize(WIDTH, HEIGHT);
    /* Animation loop */
    while (1) {
    KeySym key;
while (XPending(dpy)) {
    XNextEvent(dpy, &event);
    switch (event.type) {
    case KeyPress:
                XLookupString((XKeyEvent *)&event, NULL, 0, &key, NULL);
switch (key) {
case XK_Left:
    longinc += 0.5;
    break;
case XK_Right:
    longinc -= 0.5;
    break;
case XK_Up:
    latinc += 0.5;
    break;
case XK_Down:
    latinc -= 0.5;
    break;
}
break;
    case ConfigureNotify:
resize(event.xconfigure.width, event.xconfigure.height);
break;
    }
}
drawScene();
    }
}
/* OpenGL code */
GLvoid resize( GLsizei width, GLsizei height )
{
    GLfloat aspect;
    glViewport( 0, 0, width, height );
    aspect = (GLfloat) width / height;
    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();
    gluPerspective( 45.0, aspect, 3.0, 7.0 );
    glMatrixMode( GL_MODELVIEW );
}
GLvoid createObjects()
{
    GLUquadricObj *quadObj;
    glNewList(GLOBE, GL_COMPILE);
        quadObj = gluNewQuadric ();
        gluQuadricDrawStyle (quadObj, GLU_LINE);
        gluSphere (quadObj, 1.5, 16, 16);
    glEndList();
    glNewList(CONE, GL_COMPILE);
        quadObj = gluNewQuadric ();
        gluQuadricDrawStyle (quadObj, GLU_FILL);
        gluQuadricNormals (quadObj, GLU_SMOOTH);
        gluCylinder(quadObj, 0.3, 0.0, 0.6, 15, 10);
    glEndList();
    glNewList(CYLINDER, GL_COMPILE);
        glPushMatrix ();
        glRotatef ((GLfloat)90.0, (GLfloat)1.0, (GLfloat)0.0, (GLfloat)0.0);
        glTranslatef ((GLfloat)0.0, (GLfloat)0.0, (GLfloat)-1.0);
        quadObj = gluNewQuadric ();
        gluQuadricDrawStyle (quadObj, GLU_FILL);
        gluQuadricNormals (quadObj, GLU_SMOOTH);
        gluCylinder (quadObj, 0.3, 0.3, 0.6, 12, 2);
        glPopMatrix ();
    glEndList();
}
GLvoid initializeGL(GLsizei width, GLsizei height)
{
    GLfloat
maxObjectSize, aspect;
    GLdouble
near_plane, far_plane;
    glClearIndex( (GLfloat)BLACK_INDEX);
    glClearDepth( 1.0 );
    glEnable(GL_DEPTH_TEST);
    glMatrixMode( GL_PROJECTION );
    aspect = (GLfloat) width / height;
    gluPerspective( 45.0, aspect, 3.0, 7.0 );
    glMatrixMode( GL_MODELVIEW );
    near_plane = 3.0;
    far_plane = 7.0;
    maxObjectSize = 3.0F;
    radius = near_plane + maxObjectSize/2.0;
    latitude = 0.0F;
    longitude = 0.0F;
    latinc = 6.0F;
    longinc = 2.5F;
    createObjects();
}
void polarView(GLdouble radius, GLdouble twist, GLdouble latitude,
       GLdouble longitude)
{
    glTranslated(0.0, 0.0, -radius);
    glRotated(-twist, 0.0, 0.0, 1.0);
    glRotated(-latitude, 1.0, 0.0, 0.0);
    glRotated(longitude, 0.0, 0.0, 1.0);
}
GLvoid drawScene(GLvoid)
{
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
    glPushMatrix();
latitude += latinc;
longitude += longinc;
polarView( radius, 0, latitude, longitude );
        glIndexi(RED_INDEX);
        glCallList(CONE);
        glIndexi(BLUE_INDEX);
        glCallList(GLOBE);
glIndexi(GREEN_INDEX);
glPushMatrix();
            glTranslatef(0.8F, -0.65F, 0.0F);
            glRotatef(30.0F, 1.0F, 0.5F, 1.0F);
            glCallList(CYLINDER);
        glPopMatrix();
    glPopMatrix();
    SWAPBUFFERS;
}


The Program Ported to Win32
The following program is a Win32 OpenGL program with the same OpenGL code used in the AUXDEMO.C sample program supplied with the Win32 SDK. Compare this program with the X Windows System OpenGL program in the above  section.
/*
 * Example of a Win32 OpenGL program.
 * The OpenGL code is the same as that used in
 * the X Windows System sample.
 */
#include <windows.h>
#include <GL/gl.h>
#include <GL/glu.h>
/* Windows globals, defines, and prototypes */
CHAR szAppName[]="Win OpenGL";
HWND  ghWnd;
HDC   ghDC;
HGLRC ghRC;
#define SWAPBUFFERS SwapBuffers(ghDC)
#define BLACK_INDEX     0
#define RED_INDEX       13
#define GREEN_INDEX     14
#define BLUE_INDEX      16
#define WIDTH           300
#define HEIGHT          200
LONG WINAPI MainWndProc (HWND, UINT, WPARAM, LPARAM);
BOOL bSetupPixelFormat(HDC);
/* OpenGL globals, defines, and prototypes */
GLfloat latitude, longitude, latinc, longinc;
GLdouble radius;
#define GLOBE    1
#define CYLINDER 2
#define CONE     3
GLvoid resize(GLsizei, GLsizei);
GLvoid initializeGL(GLsizei, GLsizei);
GLvoid drawScene(GLvoid);
void polarView( GLdouble, GLdouble, GLdouble, GLdouble);
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    MSG        msg;
    WNDCLASS   wndclass;
    /* Register the frame class */
    wndclass.style         = 0;
    wndclass.lpfnWndProc   = (WNDPROC)MainWndProc;
    wndclass.cbClsExtra    = 0;
    wndclass.cbWndExtra    = 0;
    wndclass.hInstance     = hInstance;
    wndclass.hIcon         = LoadIcon (hInstance, szAppName);
    wndclass.hCursor       = LoadCursor (NULL,IDC_ARROW);
    wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    wndclass.lpszMenuName  = szAppName;
    wndclass.lpszClassName = szAppName;
    if (!RegisterClass (&wndclass) )
        return FALSE;
    /* Create the frame */
    ghWnd = CreateWindow (szAppName,
             "Generic OpenGL Sample",
     WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
             CW_USEDEFAULT,
             CW_USEDEFAULT,
             WIDTH,
             HEIGHT,
             NULL,
             NULL,
             hInstance,
             NULL);
    /* make sure window was created */
    if (!ghWnd)
        return FALSE;
    /* show and update main window */
    ShowWindow (ghWnd, nCmdShow);
    UpdateWindow (ghWnd);
    /* animation loop */
    while (1) {
        /*
         *  Process all pending messages
         */
        while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) == TRUE)
        {
            if (GetMessage(&msg, NULL, 0, 0) )
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            } else {
                return TRUE;
            }
        }
        drawScene();
    }
}
/* main window procedure */
LONG WINAPI MainWndProc (
    HWND    hWnd,
    UINT    uMsg,
    WPARAM  wParam,
    LPARAM  lParam)
{
    LONG    lRet = 1;
    PAINTSTRUCT    ps;
    RECT rect;
    switch (uMsg) {
    case WM_CREATE:
        ghDC = GetDC(hWnd);
        if (!bSetupPixelFormat(ghDC))
            PostQuitMessage (0);
        ghRC = wglCreateContext(ghDC);
        wglMakeCurrent(ghDC, ghRC);
        GetClientRect(hWnd, &rect);
        initializeGL(rect.right, rect.bottom);
        break;
    case WM_PAINT:
        BeginPaint(hWnd, &ps);
        EndPaint(hWnd, &ps);
        break;
    case WM_SIZE:
        GetClientRect(hWnd, &rect);
        resize(rect.right, rect.bottom);
        break;
    case WM_CLOSE:
        if (ghRC)
            wglDeleteContext(ghRC);
        if (ghDC)
            ReleaseDC(hWnd, ghDC);
        ghRC = 0;
        ghDC = 0;
        DestroyWindow (hWnd);
        break;
    case WM_DESTROY:
        if (ghRC)
            wglDeleteContext(ghRC);
        if (ghDC)
            ReleaseDC(hWnd, ghDC);
        PostQuitMessage (0);
        break;
    case WM_KEYDOWN:
        switch (wParam) {
        case VK_LEFT:
            longinc += 0.5F;
            break;
        case VK_RIGHT:
            longinc -= 0.5F;
            break;
        case VK_UP:
            latinc += 0.5F;
            break;
        case VK_DOWN:
            latinc -= 0.5F;
            break;
        }
    default:
        lRet = DefWindowProc (hWnd, uMsg, wParam, lParam);
        break;
    }
    return lRet;
}
BOOL bSetupPixelFormat(HDC hdc)
{
    PIXELFORMATDESCRIPTOR pfd, *ppfd;
    int pixelformat;
    ppfd = &pfd;
    ppfd->nSize = sizeof(PIXELFORMATDESCRIPTOR);
    ppfd->nVersion = 1;
    ppfd->dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL |
PFD_DOUBLEBUFFER;
    ppfd->dwLayerMask = PFD_MAIN_PLANE;
    ppfd->iPixelType = PFD_TYPE_COLORINDEX;
    ppfd->cColorBits = 8;
    ppfd->cDepthBits = 16;
    ppfd->cAccumBits = 0;
    ppfd->cStencilBits = 0;
    pixelformat = ChoosePixelFormat(hdc, ppfd);
    if ( (pixelformat = ChoosePixelFormat(hdc, ppfd)) == 0 )
    {
        MessageBox(NULL, "ChoosePixelFormat failed", "Error", MB_OK);
        return FALSE;
    }
    if (SetPixelFormat(hdc, pixelformat, ppfd) == FALSE)
    {
        MessageBox(NULL, "SetPixelFormat failed", "Error", MB_OK);
        return FALSE;
    }
    return TRUE;
}
/* OpenGL code */
GLvoid resize( GLsizei width, GLsizei height )
{
    GLfloat aspect;
    glViewport( 0, 0, width, height );
    aspect = (GLfloat) width / height;
    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();
    gluPerspective( 45.0, aspect, 3.0, 7.0 );
    glMatrixMode( GL_MODELVIEW );
}
GLvoid createObjects()
{
    GLUquadricObj *quadObj;
    glNewList(GLOBE, GL_COMPILE);
        quadObj = gluNewQuadric ();
        gluQuadricDrawStyle (quadObj, GLU_LINE);
        gluSphere (quadObj, 1.5, 16, 16);
    glEndList();
    glNewList(CONE, GL_COMPILE);
        quadObj = gluNewQuadric ();
        gluQuadricDrawStyle (quadObj, GLU_FILL);
        gluQuadricNormals (quadObj, GLU_SMOOTH);
        gluCylinder(quadObj, 0.3, 0.0, 0.6, 15, 10);
    glEndList();
    glNewList(CYLINDER, GL_COMPILE);
        glPushMatrix ();
        glRotatef ((GLfloat)90.0, (GLfloat)1.0, (GLfloat)0.0, (GLfloat)0.0);
        glTranslatef ((GLfloat)0.0, (GLfloat)0.0, (GLfloat)-1.0);
        quadObj = gluNewQuadric ();
        gluQuadricDrawStyle (quadObj, GLU_FILL);
        gluQuadricNormals (quadObj, GLU_SMOOTH);
        gluCylinder (quadObj, 0.3, 0.3, 0.6, 12, 2);
        glPopMatrix ();
    glEndList();
}
GLvoid initializeGL(GLsizei width, GLsizei height)
{
GLfloat
maxObjectSize, aspect;
GLdouble
near_plane, far_plane;
    glClearIndex( (GLfloat)BLACK_INDEX);
    glClearDepth( 1.0 );
    glEnable(GL_DEPTH_TEST);
    glMatrixMode( GL_PROJECTION );
    aspect = (GLfloat) width / height;
    gluPerspective( 45.0, aspect, 3.0, 7.0 );
    glMatrixMode( GL_MODELVIEW );
    near_plane = 3.0;
    far_plane = 7.0;
    maxObjectSize = 3.0F;
    radius = near_plane + maxObjectSize/2.0;
    latitude = 0.0F;
    longitude = 0.0F;
    latinc = 6.0F;
    longinc = 2.5F;
    createObjects();
}
void polarView(GLdouble radius, GLdouble twist, GLdouble latitude,
       GLdouble longitude)
{
    glTranslated(0.0, 0.0, -radius);
    glRotated(-twist, 0.0, 0.0, 1.0);
    glRotated(-latitude, 1.0, 0.0, 0.0);
    glRotated(longitude, 0.0, 0.0, 1.0);
}
GLvoid drawScene(GLvoid)
{
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
    glPushMatrix();
latitude += latinc;
longitude += longinc;
polarView( radius, 0, latitude, longitude );
        glIndexi(RED_INDEX);
        glCallList(CONE);
        glIndexi(BLUE_INDEX);
        glCallList(GLOBE);
glIndexi(GREEN_INDEX);
glPushMatrix();
            glTranslatef(0.8F, -0.65F, 0.0F);
            glRotatef(30.0F, 1.0F, 0.5F, 1.0F);
            glCallList(CYLINDER);
        glPopMatrix();
    glPopMatrix();
    SWAPBUFFERS;
}


Porting Applications from IRIS GL
This chapter lists important differences between IRIS GL and OpenGL and describes the basic steps for porting code from IRIS GL to OpenGL. For a complete list of the differences between IRIS GL and Open GL, see
IRIS GL and OpenGL Differences
.
Porting IRIS GL programs to OpenGL for Windows NT requires considerably more work than converting OpenGL programs from the X Window System. While IRIS GL programs are designed to run with specific hardware and software, OpenGL was designed for portability among various systems.
Here are some of the key differences between IRIS GL and OpenGL programs:
OpenGL code
IRIS GL code
Operating system independent; contains no functions for windowing, event handling, buffer allocation/management, and so on.
Dependent on operating system; windowing-system functions are mixed with rendering functions.  There is no windows manager in IRIS GL.
Uses a standard, common naming  convention. OpenGL functions and defined types begin with a "gl" prefix to prevent conflicts with other libraries.
Does not use a common naming convention for functions and defined types.
Manages state variables (such as color, fog, texture, lighting, and so on) directly and consistently. Does not use tables to load state-variable values.
Uses tables to manage state variables and must bind variables to table values.
Display lists cannot be edited.
Display lists can be edited.
Does not provide a file format for fonts.
Provides functions to handle fonts and text strings and a file format for fonts.
Includes a GL Utility Library (GLU) that contains additional functions and routines (such as NURBS and quadratic rendering routines).
Does not support the GLU library.
Use the following general procedure to port your IRIS GL programs to OpenGL:
1.
Rewrite any code that makes calls to a window manager, window configuration, device, or event, or where you load a color map to equivalent Win32 code. Rewriting an application from one operating system to another can be a complex and difficult undertaking. This subject is beyond the scope of this chapter.
2.
Locate any code that uses IRIS GL functions and routines. You'll translate these functions to their corresponding OpenGL functions. For a complete listing of IRIS GL functions and routines and their equivalent OpenGL counterparts, see "IRIS GL Commands and Their OpenGL Equivalents."
3.
Change IRIS GL code as described in "Special IRIS GL Porting Issues."


Special IRIS GL Porting Issues
The following sections describe techniques for porting specific parts of your IRIS GL code to OpenGL code.


Porting greset
OpenGL replaces the IRIS GL function
greset
 with the functions
glPushAttrib
 and
glPopAttrib
. Use these functions to save and restore groups of state variables. For example,
void glPushAttrib( GLbitfield mask );
This example takes a bitwise OR of symbolic constants, indicating which groups of state variables to push onto an attribute stack. Each constant refers to a group of state variables. The following table shows the attribute groups with their corresponding symbolic constant names. For a complete list of the OpenGL state variables associated with each constant, see
glPushAttrib
.
Attribute
Constant
accumulation buffer clear value
GL_ACCUM_BUFFER_BIT
color buffer
GL_COLOR_BUFFER_BIT
current
GL_CURRENT_BIT
depth buffer
GL_DEPTH_BUFFER_BIT
enable
GL_ENABLE_BIT
evaluators
EGL_VAL_BIT
fog
GL_FOG_BIT
GL_LIST_BASE setting
GL_LIST_BIT
hint variables
GL_HINT_BIT
lighting variables
GL_LIGHTING_BIT
line drawing mode
GL_LINE_BIT
pixel mode variables
GL_PIXEL_MODE_BIT
point variables
GL_POINT_BIT
polygon
GL_POLYGON_BIT
polygon stipple
GL_POLYGON_STIPPLE_BIT
scissor
GL_SCISSOR_BIT
stencil buffer
GL_STENCIL_BUFFER_BIT
texture
GL_TEXTURE_BIT
transform
GL_TRANSFORM_BIT
viewport
GL_VIEWPORT_BIT
¾
GL_ALL_ATTRIB_BITS
To restore the values of the state variables to those saved with the last
glPushAttrib
, simply call
glPopAttrib
. The variables you didn't save will remain unchanged. The attribute stack has a finite depth of at least 16.


Porting IRIS GL `Get' Functions
Porting IRIS GL 'Get' Functions
IRIS GL "get" functions take the following form:
int getthing();
and
int getthings( int *a, int *b);
Your IRIS GL code probably includes get function calls that look something like:
thing = getthing();
if (getthing() == THING) { /* some stuff here */ }
getthings (&a, &b);
In OpenGL you use one of the following four types of
glGet
 functions in place of corresponding IRIS GL get functions:
·
glGetBooleanv
·
glGetIntegerv
·
glGetFloatv
·
glGetDoublev
The functions have the following syntax:
glGet<Datatype>v( value, *data );
where
value
 is of type
GLenum
 and data is of type
GLdatatype
. When you call
glGet
 and it returns a type different from the type expected, the type is converted appropriately. For a complete list of
glGet
 parameters, see
glGet
.


Porting Code that Requires a Current Graphics Position
OpenGL does not maintain a current graphics position. IRIS GL functions that depend on the current graphics position, such as
move
,
draw
, and
rmv
, have no equivalents in OpenGL.
Older versions of IRIS GL included drawing commands that relied upon the current graphics position, though their use has been discouraged. You will need to rewrite your code if you relied on the current graphics position in any way, or used any of the following routines:
·
draw
 and
move
·
pmv
,
pdr
, and
pclos
·
rdr
,
rmv
,
rpdr
, and
rpmv
·
getgpos
OpenGL has a concept of raster position that corresponds to IRIS GL's current character position. For more information on raster positioning, see
Porting Pixel Operations
.


Porting Screen and Buffer Clearing Commands
OpenGL replaces a variety of IRIS GL
clear
 functions (such as
zclear
,
aclear
,
sclear
, and so on) with a single function
glClear
. Specify exactly what you want to clear by passing masks to
glClear
.
Keep the following points in mind when porting screen and buffer commands:
·
OpenGL maintains clearing colors separately from drawing colors, with calls like
glClearColor
 and
glClearIndex
. Be sure to set the clear color for each buffer before doing a clear.
·
Instead of using one of several differently named clear calls, you now clear several buffers with one call,
glClear
, by OR-ing together buffer masks. For example,
czclear
 is replaced by:
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT )
·
IRIS GL references the polygon stipple and the color write mask. OpenGL ignores the polygon stipple but references the write mask. (
czclear
 ignores both the polygon stipple and the write mask.)
The table below lists the various IRIS GL clear calls with their OpenGL equivalents.
IRIS GL Call
OpenGL Call
Meaning
acbuf(AC_CLEAR)
glClear(GL_ACCUM_BUFFER_BIT)
Clear the accumulation buffer.
¾
glClearColor
Set the RGBA clear color.
¾
glClearIndex
Set the clear-color index.
clear
glClear(GL_COLOR_BUFFER_BIT)
Clear the color buffer.
¾
glClearDepth
Specify the clear value for the depth buffer.
zclear
glClear(GL_DEPTH_BUFFER_BIT)
Clear the depth buffer.
czclear
glClear(GL_COLOR_BUFFER_BIT |
 GL_DEPTH_BUFFER_BIT)
Clear the color buffer and the depth buffer.
¾
glClearAccum
Specify clear values for the accumulation buffer.
¾
glClearStencil
Specify the clear value for the stencil buffer.
sclear
glClear(GL_STENCIL_BUFFER_BIT )
Clear the stencil buffer.
When your IRIS GL code uses both
gclear
 and
sclear
, you can combine them into a single
glClear
 call
¾
this can improve your program's performance.


Porting Matrix and Transformation Functions
IRIS GL and OpenGL handle matrixes and transformations in a similar manner. But there are several differences to keep in mind when porting code from IRIS GL:
·
In OpenGL you are always in double-matrix mode; there is no single-matrix mode.
·
Angles are measured in degrees, instead of tenths of degrees.
·
Projection matrix calls, like
glFrustum
 and
glOrtho
, now multiply onto the current matrix, instead of being loaded onto the current matrix.
·
The OpenGL function
glRotate
 is very different from
rotate
. You can rotate around any arbitrary axis, instead of being confined to the x, y, and z axes. For example, you can translate:
rotate(200*(i+1), 'z');
to:
glRotate(.1*(200*(i+1), 0.0, 0.0, 1.0);
When translating from
rotate
 to
glRotate
 you switch to degrees from tenths of degrees and replace 'z' with a vector for the z-axis.
·
OpenGL has no equivalent to the
polarview
 function. You can replace it easily with a translation and three rotations. For example, you can translate:
polarview(distance, azimuth, incidence, twist);
to:
glTranslatef( 0.0, 0.0, -distance);
glRotatef( -twist * 10.0, 0.0, 0.0, 1.0);
glRotatef( -incidence * 10.0, 1.0, 0.0, 0.0);
glRotatef( -azimuth * 10.0, 0.0, 0.0, 1.0);
The following table lists the OpenGL matrix functions and their IRIS GL equivalents.
IRIS GL Function
OpenGL Function
Meaning
mmode
glMatrixMode
Set current matrix mode.
¾
glLoadIdentity
Replace current matrix with the identity matrix.
loadmatrix
glLoadMatrixf
,
glLoadMatrixd
Replace current matrix with the specified matrix.
multmatrix
glMultMatrixf
,
glMultMatrixd
Post-multiply current matrix with the specified matrix (note that
multmatrix
 pre-multiplied).
mapw, mapw2
gluUnProject
Project world-space coordinates to object space (see also
gluProject
).
ortho
glOrtho
Multiply current matrix by an orthographic projection matrix.
ortho2
gluOrtho2D
Define a two-dimensional orthographic projection matrix.
perspective
gluPerspective
Define a perspective projection matrix.
picksize
gluPickMatrix
Define a picking region.
popmatrix
glPopMatrix
Pop current matrix stack, replacing the current matrix with the one below it.
pushmatrix
glPushMatrix
Push current matrix stack down by one, duplicating the current matrix.
rotate,
rot
glRotated
,
glRotatef
Rotate current coordinate system by the given angle about the vector from the origin through the given point. Note that
rotate
 rotated only about the x, y, and z axes.
scale
glScaled
,
glScalef
Multiply current matrix by a scaling matrix.
translate
glTranslatef
,
glTranslated
Move coordinate-system origin to the point specified, by multiplying the current matrix by a translation matrix.
window
glFrustum
Given coordinates for clipping planes, multiply the current matrix by a perspective matrix.
OpenGL has three matrix modes, which are set with
glMatrixMode
. The following table lists the modes available as parameters for
glMatrixMode
.
IRIS GL Matrix Mode
OpenGL Mode
Meaning
Min Stack Depth
MTEXTURE
GL_TEXTURE
Operate on the texture matrix stack.
2
MVIEWING
GL_MODELVIEW
Operate on the model view matrix stack.
32
MPROJECTION
GL_PROJECTION
Operate on the projection matrix stack.
2


Porting MSINGLE Mode Code
OpenGL has no equivalent for MSINGLE, single-matrix mode. Though use of this mode has been discouraged, it is the default for IRIS GL. If your IRIS GL program uses the single-matrix mode, you need to rewrite it to use double-matrix mode only. OpenGL is always in double-matrix mode, and is initially in GL_MODELVIEW mode.
Most IRIS GL code in MSINGLE mode looks like this:
projectionmatrix();
where
projectionmatrix
 is one of:
ortho
,
ortho2
,
perspective
, or
window
. To port to OpenGL, replace the MSINGLE-mode
projectionmatrix
 function with:
glMatrixMode( GL_PROJECTION );
glLoadMatrix( identity matrix );
/* call one of these functions here: */
/* glFrustrum(), glOrtho(), glOrtho2(), gluPerspective()};
 */
glMatrixMode( GL_MODELVIEW );
glLoadMatrix( identity matrix );


Porting Functions that Get Matrixes and Transformations
The following table lists the IRIS GL functions that get the state of matrixes and transformations and their OpenGL equivalents.
IRIS GL Matrix Query
OpenGL glGet Matrix Query
Meaning
getmmode
GL_MATRIX_MODE
Return the current matrix mode.
getmatrix in MVIEWING mode
GL_MODELVIEW_MATRIX
Return a copy of the current model-view matrix.
getmatrix in MPROJECTION mode
GL_PROJECTION_MATRIX
Return a copy of the current projection matrix.
getmatrix in MTEXTURE mode
GL_TEXTURE_MATRIX
Return a copy of the current texture matrix.
Not applicable.
GL_MAX_MODELVIEW_
STACK_DEPTH
Return maximum supported depth of the model-view matrix stack.
Not applicable.
GL_MAX_PROJECTION_
STACK_DEPTH
Return maximum supported depth of the projection matrix stack.
Not applicable.
GL_MAX_TEXTURE_
STACK_DEPTH
Return maximum supported depth of the texture matrix stack.
Not applicable.
GL_MODELVIEW_
STACK_DEPTH
Returns number of matrices on the model view stack.
Not applicable.
GL_PROJECTION_
STACK_DEPTH
Returns number of matrices on the projection stack.
Not applicable.
GL_TEXTURE_STACK_
DEPTH
Returns number of matrices on the texture stack.


Porting Viewports, Screenmasks, and Scrboxes
The following IRIS GL viewport functions have no OpenGL equivalent:
·
reshapeviewport
·
scrbox
·
getscrbox
With the IRIS GL
viewport
 function, you specify the x coordinates (in pixels) for the left and right of a viewport rectangle and the y coordinates for the top and bottom. With the OpenGL
glViewport
 function, however, you specify the x and y coordinates (in pixels) of the lower-left corner of the viewport rectangle along with its width and height.
The following table lists IRIS GL viewport functions and their equivalent OpenGL functions.
IRIS GL Call
OpenGL Call
Meaning
viewport(left, right,
bottom, top)
glViewport
(x, y, width, height)
Set the viewport.
popviewport
pushviewport
glPopAttrib
glPushAttrib
(GL_VIEWPORT_BIT)
Push and pop the stack.
getviewport
glGet
(GL_VIEWPORT)
Returns viewport dimensions.


Porting Clipping Planes
OpenGL implements clipping planes similarly to IRIS GL. In addition, in OpenGL you can query clipping planes. The following table lists the OpenGL equivalents to IRIS GL functions.
IRIS GL Call
OpenGL Call
Meaning
clipplane(i, CP_ON, params)
glEnable
(GL_CLIP_PLANEi)
Enable clipping on plane i.
clipplane(i, CP_DEFINE, plane)
glClipPlane
(GL_CLIP_PLANEi, plane)
Define clipping plane.
¾
glGetClipPlane
Returns clipping plane equation.
¾
glIsEnabled
(GL_CLIP_PLANEi)
Returns true if clip plane i is enabled.
scrmask
glScissor
Defines the scissor box.
getscrmask
glGet
(GL_SCISSOR_BOX)
Return the current scissor box.
To turn on the scissor test, call
glEnable
 using GL_SCISSOR_BOX as the parameter.


Porting Drawing Functions
The following sections discuss how to port IRIS GL drawing primitives.


The IRIS GL Sphere Library
OpenGL doesn't support the IRIS GL sphere library. You can replace your sphere library calls with quadrics routines from the GLU library. For more information about the GLU library, see the
Open GL Programming Guide
 and GLU.
The following table lists the OpenGL quadrics functions.
OpenGL Call
Meaning
gluNewQuadric
Create a new quadric object.
gluDeleteQuadric
Delete a quadric object.
gluQuadricCallback
Associate a callback with a quadric object, for error handling.
gluQuadricNormals
Specify normals: no normals, one per face, or one per vertex.
gluQuadricOrientation
Specify direction of normals: outward or inward.
gluQuadricTexture
Turn texture-coordinate generation on or off.
gluQuadricDrawstyle
Specify drawing style: polygons, lines, points, and so on.
gluSphere
Draw a sphere.
gluCylinder
Draw a cylinder or cone.
gluPartialDisk
Draw an arc.
gluDisk
Draw a circle or disk.
You can use one quadric object for all quadrics you want to render in similar ways. The following code fragment uses two quadric objects to draw four quadrics, two of them textured.
GLUquadricObj    *texturedQuad, *plainQuad;
texturedQuad = gluNewQuadric(void);
gluQuadricTexture(texturedQuad, GL_TRUE);
gluQuadricOrientation(texturedQuad, GLU_OUTSIDE);
gluQuadricDrawStyle(texturedQuad, GLU_FILL);
plainQuad = gluNewQuadric(void);
gluQuadricDrawStyle(plainQuad, GLU_LINE);
glColor3f (1.0, 1.0, 1.0);
gluSphere(texturedQuad, 5.0, 20, 20);
glTranslatef(10.0, 10.0, 0.0);
gluCylinder(texturedQuad, 2.5, 5, 5, 10, 10);
glTranslatef(10.0, 10.0, 0.0);
gluDisk(plainQuad, 2.0, 5.0, 10, 10);
glTranslatef(10.0, 10.0, 0.0);
gluSphere(plainQuad, 5.0, 20, 20);


Porting v Functions
In IRIS GL, you use variations on the
v
 function to specify vertices. The equivalent OpenGL function is
glVertex
: Below are examples of
glVertex
.
glVertex2[d|f|i|s][v]( x, y );
glVertex3[d|f|i|s][v]( x, y, z);
glVertex4[d|f|i|s][v]( x, y, z, w);
glVertex
 takes suffixes the same way other OpenGL calls do. The vector versions of the call take arrays of the proper size as arguments. In the 2D version, z=0 and w=1. In the 3D version, w=1.


Porting bgn/end Commands
IRIS GL uses the begin/end paradigm but has a different function for each graphics primitive. For example, you probably use
bgnpolygon
 and
endpolygon
 to draw polygons, and
bgnline
 and
endline
 to draw lines. In OpenGL, you use the
glBegin
/
glEnd
 structure for both. In OpenGL you draw most geometric objects by enclosing a series of functions that specify vertices, normals, textures, and colors between pairs of
glBegin
 and
glEnd
 calls. For example:
void glBegin( GLenum mode) ;
   /* vertex list, colors, normals, textures, materials */
void glEnd( void );
glBegin
 takes a single parameter that specifies the drawing mode, and thus the primitive. Here's an OpenGL code fragment that draws a polygon and then a line:
glBegin( GL_POLYGON ) ;
   glVertex2f(20.0, 10.0);
   glVertex2f(10.0, 30.0);
   glVertex2f(20.0, 50.0);
   glVertex2f(40.0, 50.0);
   glVertex2f(50.0, 30.0);
   glVertex2f(40.0, 10.0);
glEnd();
glBegin( GL_LINES ) ;
   glVertex2i(100,100);
   glVertex2i(500,500);
glEnd();
With OpenGL, you draw different geometric objects by specifying different parameters for
glBegin
. The following table lists the OpenGL
glBegin
 parameters that correspond to equivalent IRIS GL functions.
IRIS GL Call
Value of glBegin Mode
Meaning
bgnpoint
GL_POINTS
Individual points.
bgnline
GL_LINE_STRIP
Series of connected line segments.
bgnclosedline
GL_LINE_LOOP
Series of connected line segments, with a segment added between first and last vertices.
¾
GL_LINES
Pairs of vertices interpreted as individual line segments.
bgnpolygon
GL_POLYGON
Boundary of a simple convex polygon.
¾
GL_TRIANGLES
Triples of vertices interpreted as triangles.
bgntmesh
GL_TRIANGLE_STRIP
Linked strips of triangles.
¾
GL_TRIANGLE_FAN
Linked fans of triangles.
¾
GL_QUADS
Quadruples of vertices interpreted as quadrilaterals.
bgnqstrip
GL_QUAD_STRIP
Linked strips of quadrilaterals.
For a detailed discussion of the differences between triangle meshes, strips, and fans, see "Triangles."
There is no limit to the number of vertices you can specify between a
glBegin
/
glEnd
 pair.
In addition to specifying vertices inside a
glBegin
/
glEnd
 pair, you can specify a current normal, current texture coordinates, and a current color. The following table lists the commands valid inside a
glBegin
/
glEnd
 pair.
IRIS GL Function
OpenGL Equivalent
Meaning
v2, v3, v4
glVertex
Set vertex coordinates.
RGBcolor, cpack
glColor
Set current color.
color
glIndex
Set current color index.
n3f
glNormal
Set normal vector coordinates.
¾
glEvalCoord
Evaluate enabled one- and two-dimensional maps.
callobj
glCallList
,
glCallLists
Execute display list(s).
t2
glTexCoord
Set texture coordinates.
¾
glEdgeFlag
Control drawing edges.
lmbind
glMaterial
Set material properties.
If you use any OpenGL function other than those listed in the preceding table inside a
glBegin
/
glEnd
 pair, you'll get unpredictable results, or possibly an error.


Porting Points
OpenGL has no command to draw a single point. Otherwise, porting point functions is straightforward. The following table lists functions for drawing points.
IRIS GL Call
OpenGL Equivalent
Meaning
pnt
¾
Draw a single point.
bgnpoint,
endpoint
glBegin
(GL_POINTS),
glEnd
Interpret vertices as points.
pntsize
glPointSize
Set point size in pixels.
pntsmooth
glEnable
(GL_POINT_SMOOTH)
Turn on point antialiasing. (For more information on point antialiasing, see "Porting Antialiasing Calls.")
For information about related get functions, see
glPointSize
.


Porting Lines
Porting IRIS GL code that draws lines is fairly straightforward, though you should note the differences in the way OpenGL stipples. The following table lists functions for drawing lines.
IRIS GL Function
OpenGL Function
Meaning
bgnclosedline,
endclosedline
glBegin
(GL_LINE_LOOP)
glEnd
Draw a closed line.
bgnline
glBegin(GL_LINE_STRIP)
Draw line segments.
linewidth
glLineWidth
Set line width.
getlwidth
glGet
(GL_LINE_WIDTH)
Return current line width.
deflinestyle,
setlinestyle
glLineStipple
(factor, pattern)
Specify a line stipple pattern.
lsrepeat
factor argument of glLineStipple
Set a repeat factor for the line style.
getlstyle
glGet(GL_LINE_STIPPLE_PATTERN)
Return line stipple pattern.
getlsrepeat
glGet
(GL_LINE_STIPPLE_REPEAT)
Return repeat factor.
linesmooth, smoothline
glEnable
(GL_LINE_SMOOTH)
Turn on line antialiasing (For more information on antialiasing, see "Porting Antialiasing Calls.")
OpenGL doesn't use tables for line stipples; it maintains only one line-stipple pattern. You can use
glPushAttrib
 and
glPopAttrib
 to switch between different stipple patterns.
Older IRIS GL line style functions (such as
draw
,
lsbackup
,
getlsbackup
, and so on) are not supported by OpenGL.
For information on drawing antialiased lines, see "Porting Antialiasing Calls."


Porting Polygons and Quadrilaterals
·
Keep the following points in mind when porting polygons and quadrilaterals:
·
There is no direct equivalent for
concave(TRUE)
. Instead you can use the tessellation routines in the GLU, described in "
Polygon Tessellation
."
·
Polygon modes are set differently.
·
These polygon drawing functions have no direct equivalents in OpenGL:
·
The
poly
 family of routines
·
The
polf
 family of routines
·
pmv
,
pdr
, and
pclos
·
rpmv
 and
rpdr
·
splf
·
spclos
If your IRIS GL code uses these functions, you'll have to rewrite the code using
glBegin
(GL_POLYGON)
.
The following table lists the OpenGL equivalents to IRIS GL polygon drawing calls.
IRIS GL Function
OpenGL Equivalent
Meaning
bgnpolygon
endpolygon
glBegin
(GL_POLYGON)
glEnd
Vertices define boundary of a simple convex polygon.
¾
glBegin(GL_QUADS)
glEnd
Interpret quadruples of vertices as quadrilaterals.
bgnqstrip
endqstrip
glBegin
(GL_QUAD_STRIP)
glEnd
Interpret vertices as linked strips of quadrilaterals.
¾
glEdgeFlag
polymode
glPolygonMode
Set polygon drawing mode.
rect
rectf
glRect
Draw a rectangle.
sbox
sboxf
¾
Draw a screen-aligned rectangle.
Porting Polygon Modes
The OpenGL function
glPolygonMode
 lets you specify which side of a polygon (the back or the front) that the mode applies to. Its syntax is:
void glPolygonMode( GLenum face, GLenum mode );
where face is one of:
GL_FRONT
mode which applies to front-facing polygons
GL_BACK
mode which applies to back-facing polygons
GL_FRONT_AND_BACK
mode which applies to both front- and back-facing polygons
The GL_FRONT_AND_BACK mode is equivalent to the IRIS GL
polymode
 function. The following table lists IRIS GL polygon modes and the corresponding OpenGL modes.
IRIS GL Mode
OpenGL Mode
Meaning
PYM_POINT
GL_POINT
Draw vertices as points.
PYM_LINE
GL_LINE
Draw boundary edges as line segments.
PYM_FILL
GL_FILL
Draw polygon interior filled.
PYM_HOLLOW
¾
Fill only interior pixels at the boundaries.
Porting Polygon Stipples
When porting IRIS GL polygon stipples, keep the following point in mind:
·
OpenGL doesn't use tables for polygon stipples; only one stipple pattern is kept. You can use display lists to store different stipple patterns.
·
The OpenGL polygon stipple bitmap size is always a 32x32 bit pattern.
·
Stipple encoding is affected by
glPixelStore
.
For more information on porting polygon stipples, see
Porting Pixel Operations
.
The following table lists IRIS GL polygon stipple functions and their OpenGL equivalents.
IRIS GL Function
OpenGL Function
Meaning
defpattern
glPolygonStipple
Set the stipple pattern.
setpattern
¾
OpenGL keeps only one polygon stipple pattern.
getpattern
glGetPolygonStipple
Return the stipple bitmap (used to return an index).
In OpenGL, you enable and disable polygon stippling by passing GL_POLYGON_STIPPLE as a parameter for
glEnable
 and
glDisable
.
Here's an example OpenGL code fragment that demonstrates polygon stippling:
void display(void)
{
    GLubyte fly[] = {
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x03, 0x80, 0x01, 0xC0, 0x06, 0xC0, 0x03, 0x60,
      0x04, 0x60, 0x06, 0x20, 0x04, 0x30, 0x0C, 0x20,
      0x04, 0x18, 0x18, 0x20, 0x04, 0x0C, 0x30, 0x20,
      0x04, 0x06, 0x60, 0x20, 0x44, 0x03, 0xC0, 0x22,
      0x44, 0x01, 0x80, 0x22, 0x44, 0x01, 0x80, 0x22,
      0x44, 0x01, 0x80, 0x22, 0x44, 0x01, 0x80, 0x22,
      0x44, 0x01, 0x80, 0x22, 0x44, 0x01, 0x80, 0x22,
      0x66, 0x01, 0x80, 0x66, 0x33, 0x01, 0x80, 0xCC,
      0x19, 0x81, 0x81, 0x98, 0x0C, 0xC1, 0x83, 0x30,
      0x07, 0xe1, 0x87, 0xe0, 0x03, 0x3f, 0xfc, 0xc0,
      0x03, 0x31, 0x8c, 0xc0, 0x03, 0x33, 0xcc, 0xc0,
      0x06, 0x64, 0x26, 0x60, 0x0c, 0xcc, 0x33, 0x30,
      0x18, 0xcc, 0x33, 0x18, 0x10, 0xc4, 0x23, 0x08,
      0x10, 0x63, 0xC6, 0x08, 0x10, 0x30, 0x0c, 0x08,
      0x10, 0x18, 0x18, 0x08, 0x10, 0x00, 0x00, 0x08
    };
    GLubyte halftone[] = {
      0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
      0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
      0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
      0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
      0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
      0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
      0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
      0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
      0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
      0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
      0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
      0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
      0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
      0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
      0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
      0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55
    };
    glClear (GL_COLOR_BUFFER_BIT);
/*  draw all polygons in white*/
    glColor3f (1.0, 1.0, 1.0);
/*  draw one solid, unstippled rectangle,*/
/*  then two stippled rectangles*/
    glRectf (25.0, 25.0, 125.0, 125.0);
    glEnable (GL_POLYGON_STIPPLE);
    glPolygonStipple (fly);
    glRectf (125.0, 25.0, 225.0, 125.0);
    glPolygonStipple (halftone);
    glRectf (225.0, 25.0, 325.0, 125.0);
    glDisable (GL_POLYGON_STIPPLE);
    glFlush ();
}
Porting Tessellated Polygons
In IRIS GL, you use
concave(TRUE)
 and then
bgnpolygon
 to draw concave polygons. The OpenGL GLU includes functions you can use to draw concave polygons.
To draw a concave polygon with OpenGL, follow these steps
1.
Create a tessellation object.
2.
Define callbacks that will be used to process the triangles generated by the tessellator.
3.
Specify the concave polygon to be tessellated.
The following table lists the OpenGL functions for drawing tessellated polygons.
OpenGL GLU Function
Meaning
g
luNewTess
Create a new tessellation object.
gluDeleteTess
Delete a tessellation object.
gluTessCallback
¾
gluBeginPolygon
Begin the polygon specification.
gluTessVertex
Specify a polygon vertex in a contours.
gluNextContour
Indicate that the next series of vertices describe a new contour.
gluEndPolygon
End the polygon specification.


Porting Triangles
You can draw three types of triangles in OpenGL: separate triangles, triangle strips, and triangle fans.
OpenGL has no equivalent for the IRIS GL
swaptmesh
 function. You can achieve the same effect using a combination of triangles, triangle strips, and triangle fans.
The following table lists the IRIS GL functions for drawing triangles and their OpenGL equivalents.
IRIS GL Function
Equivalent glBegin Parameter
Meaning
¾
GL_TRIANGLES
Triples of vertices interpreted as triangles.
bgntmesh
endtmesh
GL_TRIANGLE_STRIP
Linked strips of triangles.
¾
GL_TRIANGLE_FAN
Linked fans of triangles.


Porting Arcs and Circles
With OpenGL, filled arcs and circles are drawn with the same calls as unfilled arcs and circles. The following table lists the IRIS GL arc and circle functions and their corresponding OpenGL (GLU) functions.
IRIS GL Function
OpenGL Function
Meaning
arc
arcf
gluPartialDisk
Draw an arc.
circ
circf
gluDisk
Draw a circle or disk.
You can do some things with OpenGL arcs and circles that you can't do with IRIS GL. OpenGL calls arcs and circles, disks and partial disks respectively.
When porting arcs and circles, keep the following points about OpenGL in mind:
·
Angles are measured in degrees not in tenths of degrees.
·
The start angle is measured from the positive y-axis, and not from the x-axis.
·
The sweep angle is now clockwise instead of counterclockwise.


Porting Spheres
When porting spheres to OpenGL, keep the following point in mind:
·
You cannot control the type of primitives used to draw the sphere. You can control drawing precision in another way: use the slices and stacks parameters. Slices are longitudinal; stacks are latitudinal.
·
Spheres are drawn centered at the origin. Instead of specifying the location, as you do in
sphdraw
, precede a call to
gluSphere
 with a translation.
·
The sphere library is not yet available for OpenGL.
The following table lists the IRIS GL functions for drawing spheres and their corresponding GLU calls where available.
IRIS GL Function
GLU Function
Meaning
sphobj
gluNewQuadric
Create a new sphere object.
sphfree
gluDeleteQuadric
Delete sphere object and free memory used.
sphdraw
gluSphere
Draw a sphere.
sphmode
¾
Set sphere attributes.
sphrotmatrix
¾
Control sphere orientation.
sphgnpolys
¾
Return number of polygons in current sphere.


Porting Color, Shading, and Writemask Code
When porting color, shading, and writemask code to OpenGL keep the following points in mind:
·
Though you can set color-map indices with the OpenGL
glIndex
 function, OpenGL does not have a function for loading color-map indices.
·
Color values are normalized to their data type. (For information about color values, see
glColor
).
·
There is no simple equivalent for
cpack
.
·
You may have to translate code that includes the
c
 or
color
 functions to
glClearColor
 or
glClearIndex
 instead of
glColor
 or
glIndex
.
·
The RGBA writemask applies to each component but not for each bit.
·
IRIS GL provides defined color constants: BLACK, BLUE, RED, GREEN, MAGENTA, CYAN, YELLOW, and WHITE. OpenGL does not provide these constants.


Porting Color Calls
The following table lists IRIS GL color functions and their OpenGL equivalents.
IRIS GL Call
OpenGL Call
Meaning
c
glColor
Sets RGB color.
color
glIndex
Sets the color index.
getcolor
glGet
(GL_CURRENT_INDEX)
Returns the current color index.
getmcolor
¾
Gets a copy of the RGB values for a color map entry.
gRGBcolor
glGet(GL_CURRENT_COLOR)
Gets the current RGB color values.
mapcolor
¾
RGBcolor
glColor
Sets RGB color.
writemask
glIndexMask
Sets the color-index mode color mask.
wmpack
RGBwritemask
glColorMask
Sets the RGB color mode mask.
getwritemask
glGet
(GL_COLOR_WRITEMASK)
glGet
(GL_INDEX_WRITEMASK)
Gets the color mask.
gRGBmask
glGet
(GL_COLOR_WRITEMASK)
Gets the color mask.
zwritemask
glDepthMask
¾
Note
  Be careful when replacing
zwritemask
 with
glDepthMask
;
glDepthMask
 takes a Boolean argument, whereas
zwritemask
 takes a bit field.
If you want to use multiple color maps, you need to use the appropriate Win32 colormap functions. Therefore,
multimap
,
onemap
,
getcmmode
,
setmap
, and
getmap
 have no OpenGL equivalents.


Porting Shading Models
Like IRIS GL, OpenGL lets you switch between smooth (Gouraud) shading and flat shading. The following table lists the IRIS GL shading and dithering functions and their OpenGL equivalents.
IRIS GL Call
OpenGL Call
Meaning
shademodel(FLAT)
glShadeModel
(GL_FLAT)
Do flat shading.
shademodel(GOURAUD)
glShadeModel(GL_SMOOTH)
Do smooth shading.
getsm
glGet
(GL_SHADE_MODEL)
Return current shade model.
dither(DT_ON)
dither(DT_OFF)
glEnable
(GL_DITHER)
glDisable
(GL_DITHER)
Turn dithering on/off.


Porting Pixel Operations
When porting code that involves pixel operations, keep the following points in mind:
·
Logical pixel operations are not applied to RGBA color buffers. For more information, see
glLogicOp
.
·
In general, IRIS GL uses the format ABGR for pixels, whereas OpenGL uses RGBA. You can change the format with
glPixelStore
.
·
When porting
lrectwrite
 functions, be careful to note where
lrectwrite
 is writing (for instance, it could be writing to the depth buffer).
OpenGL gives you some additional flexibility in pixel operations. The following table lists IRIS GL functions for pixel operations and their OpenGL equivalents.
IRIS GL Call
OpenGL Call
Meaning
lrectread, rectread,
readRGB
glReadPixels
Read a block of pixels from the frame buffer.
lrectwrite, rectwrite
glDrawPixels
Write a block of pixels to the frame buffer.
rectcopy
glCopyPixels
Copy pixels in the frame buffer.
rectzoom
glPixelZoom
Specify pixel zoom factors for glDrawPixels and glCopyPixels.
cmov
glRasterPos
Specify raster position for pixel operations.
readsource
glReadBuffer
Select a color buffer source for pixels.
pixmode
glPixelStore
Set pixel storage modes.
pixmode
glPixelTransfer
Set pixel transfer modes.
logicop
glLogicOp
Specify a logical operation for pixel writes.
¾
glEnable
(GL_LOGIC_OP)
Turn on pixel logic operations.
For a complete list of possible logical operations, see
glLogicOp
.
This IRIS GL code fragment shows a typical pixel write:
unsigned long *packedRaster;
...
packedRaster[k] = 0x00000000;
...
lrectwrite(0, 0, xSize, ySize, packedRaster);
The preceding code looks like this when translated to OpenGL:
glRasterPos2i( 0, 0);
glDrawPixels( xSize + 1, ySize + 1, GL_RGBA, GL_UNSIGNED_BYTE,
              packedRaster);


Porting Depth Cueing and Fog Commands
When porting depth-cueing and fog code, keep the following points in mind:
·
The IRIS GL call
fogvertex
 sets a mode and parameters affecting that mode. In OpenGL, you call
glFog
 once to set the mode, then again twice or more to set various parameters.
·
In OpenGL, depth cueing is not a separate feature. Use linear fog instead of depth cueing. (This section gives an example of how to do this.) The following IRIS GL functions have no direct OpenGL equivalent:
·
depthcue
·
lRGBrange
·
lshaderange
·
getdcm
·
To adjust fog quality, use
glHint
(GL_FOG_HINT)
.
The following table lists the IRIS GL functions for managing fog and their corresponding OpenGL calls.
IRIS GL Call
OpenGL Call
Meaning
fogvertex
glFog
Set various fog parameters.
fogvertex(FG_ON)
glEnable
(GL_FOG)
Turn fog on.
fogvertex(FG_OFF)
glDisable
(GL_FOG)
Turn fog off.
depthcue
glFog
(GL_FOG_MOD, GL_LINEAR)
Use linear fog for depth cueing.
The following table lists the arguments you can pass to
glFog
.
Fog Parameter
Meaning
Default
GL_FOG_DENSITY
Fog density.
1.0
GL_FOG_START
Near distance for linear fog.
0.0
GL_FOG_END
Far distance for linear fog.
1.0
GL_FOG_INDEX
Fog color index.
0.0
GL_FOG_COLOR
Fog RGBA color.
(0, 0, 0, 0)
GL_FOG_MODE
Fog mode.
See the table below.
The fog-density parameter of OpenGL differs from the one in IRIS GL.  They are related as follows:
·
if  fogMode = EXP2
openGLfogDensity = (irisGLfogDensity)  (sqrt( - log( 1 / 255 ) ))
·
if fogMode =  EXP
openGLfogDensity = (irisGLfogDensity)  (- log( 1 / 255 ) )
where
sqrt
 is the square root operation,
log
 is the natural logarithm,
irisGLfogDensity
 is the IRIS GL fog density, and
openGLfogDensity
 is the OpenGL fog density.
To switch between calculating fog in per-pixel mode and per-vertex mode, use
glHint
(GL_FOG_HINT, hintMode)
. Two hint modes are available:
·
GL_NICEST
per-pixel fog calculation
·
GL_FASTEST
per-vertex fog calculation
The following table lists the IRIS GL fog modes and their OpenGL equivalents.
IRIS GL Fog Mode
OpenGL Fog Mode
Hint Mode
Meaning
FG_VTX_EXP,
FG_PIX_EXP
GL_EXP
GL_FASTEST,
GL_NICEST
Heavy fog mode (default).
FG_VTX_EXP2,
FG_PIX_EXP2
GL_EXP2
GL_FASTEST,
GL_NICEST
Haze mode.
FG_VTX_LIN,
FG_PIX_LIN
GL_LINEAR
GL_FASTEST,
GL_NICEST
Linear fog mode. (Use for depth cueing).
Here's an example that demonstrates depth cueing in OpenGL:
/*
 *  depthcue.c
 *  This program draws a wire frame model, which uses
 *  intensity (brightness) to give clues to distance.
 *  Fog is used to achieve this effect.
 */
#include <GL/gl.h>
#include <GL/glu.h>
#include "aux.h"
/*  Initialize linear fog for depth cueing.
 */
void myinit(void)
{
    GLfloat fogColor[4] = {0.0, 0.0, 0.0, 1.0};
    glEnable(GL_FOG);
    glFogi (GL_FOG_MODE, GL_LINEAR);
    glHint (GL_FOG_HINT, GL_NICEST);  /*  per pixel   */
    glFogf (GL_FOG_START, 3.0);
    glFogf (GL_FOG_END, 5.0);
    glFogfv (GL_FOG_COLOR, fogColor);
    glClearColor(0.0, 0.0, 0.0, 1.0);
    glDepthFunc(GL_LEQUAL);
    glEnable(GL_DEPTH_TEST);
    glShadeModel(GL_FLAT);
}
/*  display() draws an icosahedron.
 */
void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glColor3f (1.0, 1.0, 1.0);
    auxWireIcosahedron(1.0);
    glFlush();
}
void myReshape(GLsizei w, GLsizei h)
{
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective (45.0, (GLfloat) w/(GLfloat) h, 3.0, 5.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity ();
    glTranslatef (0.0, 0.0, -4.0); /*move object into view*/
}
/*  Main Loop
 */
int main(int argc, char** argv)
{
    auxInitDisplayMode (AUX_SINGLE | AUX_RGBA | AUX_DEPTH);
    auxInitPosition (0, 0, 400, 400);
    auxInitWindow (argv[0]);
    myinit();
    auxReshapeFunc (myReshape);
    auxMainLoop(display);
}


Porting Curve and Surface Functions
OpenGL doesn't support equivalents to the IRIS GL curves and surface patches. You'll need to rewrite your code if it includes any of the following calls:
·
defbasis
·
curvebasis
,
curveprecision
,
crv
, c
rvn
,
rcrv
,
rcrvn
, and
curveit
·
patchbasis
,
patchcurves
,
patchprecision
,
patch
, and
rpatch


Porting NURBS Objects
OpenGL treats NURBS as objects, similar to the way it treats quadrics: you create a NURBS object and then specify how it should be rendered. The following table lists the OpenGL GLU functions for managing NURBS objects.
OpenGL Call
Meaning
gluNewNurbsRenderer
Create a new NURBS object.
gluDeleteNurbsRenderer
Delete a NURBS object.
gluNurbsCallback
Associate a callback with a NURBS object, for error handling.
When porting IRIS GL NURBS code to OpenGL, keep the following points in mind:
·
NURBS control points are floats, not doubles.
·
The stride parameter is counted in floats, not bytes.
·
If you're using lighting and you're not specifying normals, call
glEnable
 with GL_AUTO_NORMAL as the parameter to generate normals automatically.


Porting NURBS Curves
The OpenGL calls for drawing NURBS are very similar to the IRIS GL calls. You specify knot sequences and control points using a
gluNurbsCurve
 call, which must be contained within a
gluBeginCurve
/
gluEndCurve
 pair.
The following table lists the IRIS GL functions for drawing NURBS curves and their OpenGL equivalents.
IRIS GL Function
OpenGL Function
Meaning
bgncurve
gluBeginCurve
Begin a curve definition.
nurbscurve
gluNurbsCurve
Specify curve attributes.
endcurve
gluEndCurve
End a curve definition.
Associate position, texture, and color coordinates by presenting each as a separate
gluNurbsCurve
 inside the begin/end pair. You can make no more than one call to
gluNurbsCurve
 for each piece of color, position, and texture data within a single
gluBeginCurve
/gluEndCurve
 pair. You must make exactly one call to describe the position of the curve (a GL_MAP1_VERTEX_3 or GL_MAP1_VERTEX_4 description). When you call
gluEndCurve
, the curve is tessellated into line segments and then rendered.
The following table lists IRIS GL and OpenGL NURBS curve types.
IRIS GL Type
OpenGL Type
Meaning
N_V3D
GL_MAP1_VERTEX_3
Polynomial curve.
N_V3DR
GL_MAP1_VERTEX_4
Rational curve.
¾
GL_MAP1_TEXTURE_COORD_*
Control points are texture coordinates.
¾
GL_MAP1_NORMAL
Control points are normals.
For more information on available evaluator types, see
glMap1
.


Porting Trimming Curves
OpenGL trimming curves are very similar to IRIS GL trimming curves. The following table lists the IRIS GL functions for defining trimming curves and their OpenGL equivalents.
IRIS GL Function
OpenGL Function
Meaning
bgntrim
gluBeginTrim
Begin trimming-curve definition.
pwlcurve
gluPwlCurve
Define a piecewise linear curve.
nurbscurve
gluNurbsCurve
Specify trimming-curve attributes.
endtrim
gluEndTrim
End trimming-curve definition.


Porting NURBS Surfaces
The following table lists the IRIS GL functions for drawing NURBS surfaces and their OpenGL equivalents.
IRIS GL Function
OpenGL Function
Meaning
bgnsurface
gluBeginSurface
Begin a surface definition.
nurbssurface
gluNurbsSurface
Specify surface attributes.
endsurface
gluEndSurface
End a surface definition.
The following table lists IRIS GL parameters for surface types and their OpenGL equivalents.
IRIS GL Type
OpenGL Type
Meaning
N_V3D
GL_MAP2_VERTEX_3
Polynomial curve.
N_V3DR
GL_MAP2_VERTEX_4
Rational curve.
N_C4D
GL_MAP2_COLOR_4
Control points define color surface in (R,G,B,A) form.
N_C4DR
¾
¾
N_T2D
GL_MAP2_TEXTURE_COORD_2
Control points are texture coordinates.
N_T2DR
GL_MAP2_TEXTURE_COORD_3
Control points are texture coordinates.
¾
GL_MAP2_NORMAL
Control points are normals.
For more information on available evaluator types, see
glMap2
.
This sample program draws a trimmed NURBS surface:
/*
 *  trim.c
 *  This program draws a NURBS surface in the shape of a
 *  symmetrical hill, using both a NURBS curve and pwl
 *  (piecewise linear) curve to trim part of the surface.
 */
#include <GL/gl.h>
#include <GL/glu.h>
#include "aux.h"
GLfloat ctlpoints[4][4][3];
GLUnurbsObj *theNurb;
/*
 *  Initializes the control points of the surface to
 *  a small hill. The control points range from -3 to
 *  +3 in x, y, and z
 */
void init_surface(void)
{
    int u, v;
    for (u = 0; u < 4; u++) {
        for (v = 0; v < 4; v++) {
            ctlpoints[u][v][0] = 2.0*((GLfloat)u - 1.5);
            ctlpoints[u][v][1] = 2.0*((GLfloat)v - 1.5);
            if ( (u == 1 || u == 2) && (v == 1 || v == 2))
                ctlpoints[u][v][2] = 3.0;
            else
                ctlpoints[u][v][2] = -3.0;
        }
    }
}
/*  Initialize material property and depth buffer.
 */
void myinit(void)
{
    GLfloat mat_diffuse[] = { 0.6, 0.6, 0.6, 1.0 };
    GLfloat mat_specular[] = { 0.9, 0.9, 0.9, 1.0 };
    GLfloat mat_shininess[] = { 128.0 };
    glClearColor (0.0, 0.0, 0.0, 1.0);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
    glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glDepthFunc(GL_LEQUAL);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_AUTO_NORMAL);
    glEnable(GL_NORMALIZE);
    init_surface();
    theNurb = gluNewNurbsRenderer();
    gluNurbsProperty(theNurb, GLU_SAMPLING_TOLERANCE, 50.0);
    gluNurbsProperty(theNurb, GLU_DISPLAY_MODE, GLU_FILL);
}
void display(void)
{
    GLfloat knots[8] = {0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0};
    GLfloat edgePt[5][2] = /* counter clockwise */
    {{0.0, 0.0}, {1.0, 0.0}, {1.0, 1.0}, {0.0, 1.0},
     {0.0, 0.0}};
    GLfloat curvePt[4][2] = /* clockwise */
    {{0.25, 0.5}, {0.25, 0.75}, {0.75, 0.75}, {0.75, 0.5}};
    GLfloat curveKnots[8] =
        {0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0};
    GLfloat pwlPt[4][2] = /* clockwise */
        {{0.75, 0.5}, {0.5, 0.25}, {0.25, 0.5}};
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glPushMatrix();
    glRotatef(330.0, 1.,0.,0.);
    glScalef (0.5, 0.5, 0.5);
    gluBeginSurface(theNurb);
    gluNurbsSurface(theNurb,
            8, knots,
            8, knots,
            4 * 3,
            3,
            &ctlpoints[0][0][0],
            4, 4,
            GL_MAP2_VERTEX_3);
    gluBeginTrim (theNurb);
        gluPwlCurve (theNurb, 5, &edgePt[0][0], 2,
                     GLU_MAP1_TRIM_2);
    gluEndTrim (theNurb);
    gluBeginTrim (theNurb);
        gluNurbsCurve (theNurb, 8, curveKnots, 2,
                &curvePt[0][0], 4, GLU_MAP1_TRIM_2);
        gluPwlCurve (theNurb, 3, &pwlPt[0][0], 2,
                     GLU_MAP1_TRIM_2);
    gluEndTrim (theNurb);
    gluEndSurface(theNurb);
    glPopMatrix();
    glFlush();
}
void myReshape(GLsizei w, GLsizei h)
{
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective (45.0, (GLdouble)w/(GLdouble)h, 3.0, 8.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glTranslatef (0.0, 0.0, -5.0);
}
/*  Main Loop
 */
int main(int argc, char** argv)
{
    auxInitDisplayMode (AUX_SINGLE | AUX_RGBA | AUX_DEPTH);
    auxInitPosition (0, 0, 500, 500);
    auxInitWindow (argv[0]);
    myinit();
    auxReshapeFunc (myReshape);
    auxMainLoop(display);
}


Porting Antialiasing Calls
In OpenGL the subpixel mode is always on, consequently the IRIS GL call
subpixel (TRUE)
 is not necessary and has no OpenGL equivalent. The following sections describe aspects of porting IRIS GL antialiasing code.


Porting Blending Code
In IRIS GL, when drawing to both front and back buffers, blending is done by reading one of the buffers, blending with that color, and then writing the result to both buffers. In OpenGL, however, each buffer is read in turn, blended, and then written.
The following table lists IRIS GL blending functions and their OpenGL equivalents.
IRIS GL Function
OpenGL Function
Meaning
¾
glEnable
(GL_BLEND)
Turn on blending.
blendfunction
glBlendFunc
Specify a blend function.
The OpenGL
glBlendFunc
 function and the IRIS GL
 blendfunction
 function are almost identical. The following table lists the OpenGL equivalents to the IRIS GL blend factors.
IRIS GL
OpenGL
Notes
BF_ZERO
GL_ZERO
BF_ONE
GL_ONE
BF_SA
GL_SRC_ALPHA
BF_MSA
GL_ONE_MINUS_SRC_ALPHA
BF_DA
GL_DST_ALPHA
BF_MDA
GL_ONE_MINUS_DST_ALPHA
BF_SC
GL_SRC_COLOR
BF_MSC
GL_ONE_MINUS_SRC_COLOR
Destination only.
BF_DC
GL_DST_COLOR
Source only.
BF_MDC
GL_ONE_MINUS_DST_COLOR
Source only.
BF_MIN_SA_MDA
GL_SRC_ALPHA_SATURATE


Porting afunction Test Functions
The following table lists the available IRIS GL alpha test functions and their OpenGL equivalents.
afunction
glAlphaFunc
AF_NOTEQUAL
GL_NOTEQUAL
AF_ALWAYS
GL_ALWAYS
AF_NEVER
GL_NEVER
AF_LESS
GL_LESS
AF_EQUAL
GL_EQUAL
AF_LEQUAL
GL_LEQUAL
AF_GREATER
GL_GREATER
AF_GEQUAL
GL_GEQUAL


Antialiasing
OpenGL has direct equivalents to IRIS GL's antialiasing calls; the following table lists them.
IRIS GL Call
OpenGL Call
Meaning
pntsmooth
glEnable
(GL_POINT_SMOOTH)
Enable antialiasing of points.
linesmooth
glEnable(GL_LINE_SMOOTH)
Enable antialiasing of lines.
polysmooth
glEnable
(GL_POLYGON_SMOOTH)
Enable antialiasing of polygons.
Use the corresponding
glDisable
 calls to turn off antialiasing.
In IRIS GL, you can control the quality of the antialiasing by calling:
linesmooth(SML_ON + SML_SMOOTHER);
OpenGL provides similar control
¾
use
glHint
:
glHint(GL_POINT_SMOOTH_HINT, hintMode);
glHint(GL_LINE_SMOOTH_HINT, hintMode);
glHint(GL_POLYGON_SMOOTH_HINT, hintMode);
where
hintMode
 is one of the following:
·
GL_NICEST
(Use the highest quality smoothing.)
·
GL_FASTEST
(Use the most efficient smoothing.)
·
GL_DONT_CARE
IRIS GL also permits end-correction by calling:
linesmooth(SML_ON +  SML_END_CORRECT);
OpenGL has no equivalent for this function.


Porting Accumulation Buffer Calls
You must allocate your accumulation buffer by requesting the appropriate pixel format with
auxInitDisplayMode
 or
ChoosePixelFormat
. The following table lists IRIS GL functions that affect the accumulation buffer and their OpenGL equivalents.
IRIS GL Function
OpenGL Function
Meaning
acsize
auxInitDisplayMode
 or
ChoosePixelFormat
Specify number of bitplanes per color component in the accumulation buffer.
acbuf
glAccum
Operate on the accumulation buffer.
¾
glClearAccum
Set clear values for accumulation buffer.
acbuf(AC_CLEAR)
glClear
(GL_ACCUM_BUFFER_BIT)
Clear the accumulation buffer.
The following table lists IRIS GL's
acbuf
 parameters along with the corresponding parameters to OpenGL's
glAccum
.
IRIS GL Parameter
OpenGL Parameter
AC_ACCUMULATE
GL_ACCUM
AC_CLEAR_ACCUMULATE
GL_LOAD
AC_RETURN
GL_RETURN
AC_MULT
GL_MULT
AC_ADD
GL_ADD


Porting Stencil Plane Calls
In OpenGL, you allocate stencil planes by requesting the appropriate pixel format with
auxInitDisplayMode
 or
ChoosePixelFormat
. The following table lists IRIS GL functions that affect the stencil planes and their OpenGL equivalents.
IRIS GL Function
OpenGL Function
Meaning
stensize
ChoosePixelFormat
¾
stencil(TRUE, ...)
glEnable
(GL_STENCIL_TEST)
Enable stencil tests.
stencil
glStencilOp
Set stencil test actions.
stencil(... func, ...)
glStencilFunc
Set function and reference value for stencil testing.
swritemask
glStencilMask
Specify which stencil bits can be written.
¾
glClearStencil
Specify the clear value for the stencil buffer.
sclear
glClear
(GL_STENCIL_BUFFER_BIT)
¾
Stencil-comparison functions and stencil pass/fail operations are nearly equivalent in OpenGL and IRIS GL. The IRIS GL stencil-function flags are prefaced with SF, the OpenGL flags with GL. IRIS GL pass/fail operation flags are prefaced with ST, the OpenGL flags with GL.


Porting Display Lists
The OpenGL implementation of display lists is similar to the IRIS GL implementation, with two exceptions: in OpenGL you can't edit display lists once you've created them and you can't call functions from within display lists.
Because you can't edit or call functions from within display lists, these IRIS GL functions have no equivalent in OpenGL:
·
editobj
·
objdelete
,
objinsert
, and
objreplace
·
maketag
,
gentag
,
istag
, and
deltag
·
callfunc
In IRIS GL, you use the
makeobj
 and
closeobj
 functions to create display lists. In OpenGL, you use
glNewList
 and
glEndList
.
The following table lists the IRIS GL display list commands with the corresponding OpenGL commands.
IRIS GL Function
OpenGL Function
Meaning
makeobj
glNewList
Create a new display list.
closeobj
glEndList
Signal end of display list.
callobj
glCallList
,
glCallLists
Execute display list(s).
isobj
glIsList
Test for display list existence.
delobj
glDeleteLists
Delete contiguous group of display lists.
genobj
glGenLists
Generate the given number of contiguous empty display lists.


Porting the bbox2 Function
There is no OpenGL equivalent for the IRIS GL
bbox2
 function.
To port code that contains bbox2 functions
1.
Create a new (OpenGL) display list that contains everything in the corresponding IRIS GL display list except the call to
bbox2
.
2.
Use appropriate Win32 code to draw a rectangle the same size as the IRIS GL bbox.


Porting Edited Display Lists
Although you can't edit OpenGL display lists, you can get similar results by nesting display lists and then destroying and creating new versions of the sublists. For example:
glNewList (1, GL_COMPILE);
glIndexi(MY_RED);
glEndlist();
glNewList(2, GL_COMPILE);
glScalef(1.2, 1.2, 1.0);
glEndList();
glNewList(3, GL_COMPILE);
glCallList(1);
glCallList(2);
glEndList();
.
.
.
glDeleteLists(1, 2);
glNewList(1, GL_COMPILE);
glIndexi(MY_CYAN);
glEndList();
glNewList(2, GL_COPILE);
glScalef(0.5, 0.5, 1.0);
glEndList;


A Sample Port of a Display Lists
This topic gives an IRIS GL sample of code that defines three display lists; one of the display lists refers to the others in its definition. Following the IRIS GL sample is a sample of what the code looks like when translated to OpenGL.
IRIS GL Sample Display List Code
makeobj(10);  // 10 object.
cpack(0x0000FF);
recti(164, 33, 364, 600);  // Hollow rectangle.
closeobj();
makeobj(20);  // 20 object.
cpack(0xFFFF00);
circle(0, 0, 25); // Unfilled circle.
recti(100, 100, 200, 200);  // Filled rectangle.
closeobj();
makeobj(30); // 30 object.
callobj(10);
cpack(0xFFFFFF);
recti(400, 100, 500, 300); // Draw filled rectangle.
callobj(20);
closeobj();
// Now draw by calling the lists.
call(30);
OpenGL Sample Display List Code
Here is the preceding IRIS GL code translated to OpenGL:
glNewList(10, GL_COMPILE);
// List #10.
glColor3f(1, 0, 0);
glRecti(164, 33, 364, 600);
glEndList();
glNewList(20, GL_COMPILE);
//List #20.
glColor3f(1, 1, 0);
// Set color to YELLOW.
glPolygonMode(GL_BOTH, GL_LINE);  // Unfilled mode.
glBegin(GL_POLYGON);  // Use polygon to approximate a circle.
for(i=0; i<100; i++) {
cosine = 25 * cos(i * 2 * PI/100.0);
sine =   25 * sin(i * 2 * PI/100.0);
glVertex2f(cosine, sine);
}
glEnd();
glBegin(GL_QUADS);
glColorf(0, 1, 1);  // Set color ro CYAN.
glVertex2i(100, 100);
glVertex2i(100, 200);
glVertex2i(200, 200);
glVertex2i(100, 200);
glEnd();
glEndList();
glNewList(30, GL_COMPILE);  // List #30.
glCallList(10);
glColorf(1, 1, 1);
// Set color to WHITE.
glRecti(400, 100, 500, 300);
glCallList(20);
glEndList();
// Execute the display lists.
glCallList(30);


Porting Defs, Binds, and Sets
OpenGL doesn't have tables of stored definitions; you can't define lighting models, material, textures, line styles, or patterns as separate objects as you can in IRIS GL. Thus OpenGL has no direct equivalents to the following IRIS GL functions:
·
Imdef
 and
Imbind
·
tevdef
and
 tevbind
·
textdef
and
 textbind
·
definestyle
and
 setstyle
·
defpattern
and
 setpattern
You can use OpenGL display lists to mimic the IRIS GL def/bind mechanism. For example, here is a material definition in IRIS GL:
float mat() = {
AMBIENT, .1, .1, .1,
DIFFUSE, 0, .369, .165,
SPECULAR, .5, .5, .5,
SHININESS, 10,
LMNULL
};
lmdef(DEFMATERIAL, 1, 0, mat);
lmbind(MATERIAL, 1);
The following OpenGL code fragment defines the same material in a display list that is referred to by the list number defined by MYMATERIAL.
#define MYMATERIAL 10
GLfloat
mat_amb[] = {.1, .1, .1, 1.0};
GLfloat
mat_dif[] = {0, .369, .165, 1.0};
GLfloat
mat_spec[] = {.5, .5, .5, 1.0};
glNewList(MYMATERIAL, GL_COMPILE);
glMaterialfv(GL_FRONT, GL_AMBIENT, mat_amb);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_dif);
glMaterialfv(GL_FRONT, GL_SHININESS, 10);
glEndList();
glCallList( MYMATERIAL );


Porting Lighting and Materials Functions
OpenGL functions for lighting and materials differ substantially from the IRIS GL functions. Unlike IRIS GL, OpenGL has separate functions for setting lights, light models and materials.
Keep the following points in mind when porting lighting and materials functions:
·
OpenGL has no table of stored definitions. You can use display lists to mimic the IRIS GL def/bind mechanism. For more information on defs and binds, see "Porting Defs, Binds, and Sets."
·
With OpenGL attenuation is associated with each light source, rather than the overall lighting model.
·
Diffuse and specular components are separated in OpenGL light sources.
·
OpenGL light sources have an alpha component. When porting your IRIS GL code set this alpha component to 1.0, indicating 100% opaque. The alpha values are then determined by the alpha component of your materials only, so the objects in your scene will look the same as they did in IRIS GL.
The following table lists IRIS GL lighting and materials functions and their OpenGL equivalents.
IRIS GL Function
OpenGL Function
Meaning
Imdef(DEFLIGHT, ...)
glLight
Define a light source.
Imdef(DEFMODEL, ...)
glLightModel
Define a lighting model.
Imbind
glEnable
(GL_LIGHT
i
)
Enable light
i
.
Imbind
glEnable
(GL_LIGHTING)
Enable lighting.
Imdef(DEFMATERIAL, ...)
glMaterial
Define a material.
Imcolor
glColorMaterial
Change the effect of color commands while lighting is active.
--
glGetMaterial
Get material parameters.
The following table lists various IRIS GL material parameters and their OpenGL equivalents.
Imdef index
glMaterial parameter
Default
Meaning
ALPHA
GL_DIFFUSE
--
The fourth value in the GL_DIFFUSE parameter specifies the alpha value.
AMBIENT
GL_AMBIENT
(0.2, 0.2, 0.2, 1.0)
Ambient color
DIFFUSE
GL_DIFFUSE
(0.8, 0.8, 0.8, 1.0)
Diffuse color
SPECULAR
GL_SPECULAR
(0.0, 0.0, 0.0, 1.0)
Emissive color
SHININESS
GL_SHININESS
GL_AMBIENT_
AND_DIFFUSE
0.0
Specular exponent
Equivalent to calling glMaterial twice with the same  values.
COLORINDEXES
GL_COLOR_
INDEXES
--
Color indices for ambient, diffuse, and specular lighting.
When the first parameter of
Imdef
 is DEFLMODEL, the equivalent OpenGL translation is the function
glLightModel
. The exception is when the parameter following DEFMODEL is ATTENUATION: then the equivalent OpenGL function is
glLight
.
The following table lists the equivalent lighting model parameters for IRIS GL and OpenGL.
Imdef Index
glLightModel parameter
Default
Meaning
AMBIENT
GL_LIGHT_
MODEL_AMBIENT
(0.2, 0.2, 0.2, 1.0)
Ambient color of scene.
ATTENUATION
See
glLight
.
LOCALVIEWER
GL_LIGHT_MODEL_
LOCAL_VIEWER
GL_FALSE
Viewer local (TRUE) or infinite (FALSE).
TWOSIDE
GL_LIGHTMODEL_
TWO_SIDE
GL_FALSE
Use two-sided lighting when TRUE.
When the first parameter of
Imdef
 is DEFLIGHT, the equivalent OpenGL translation is the function
glLight
.
The following table lists the equivalent light parameters for IRIS GL and OpenGL.
Imdef Index
glLight Parameter
Default
Meaning
AMBIENT
GL_AMBIENT
GL_DIFFUSE
GL_SPECULAR
(0.0, 0.0, 0.0, 1.0)
(1.0, 1.0, 1.0, 1.0)
(1.0, 1.0, 1.0, 1.0)
Ambient intensity.
Diffuse intensity.
Specular intensity.
LCOLOR
No equivalent.
--
--
POSITION
GL_POSITION
(0.0, 0.0, 1.0, 0.0)
Position of light.
SPOTDIRECTION
GL_SPOT_
DIRECTION
(0, 0, -1)
Direction of spotlight.
SPOTLIGHT
GL_SPOT_EXPONENT
GL_SPOT_CUTOFF
0
180
Intensity distribution.
Maximum spread angle of light source.
DEFLMODE, ATTENUATION
GL_CONSTANT_
ATTENUATION
GL_LINEAR_
ATTENUATION
GL_QUADRATIC_
ATTENUATION
(1, 0, 0)
Attenuation factors.


Porting Texture Functions
When porting IRIS GL texture functions to OpenGL, keep the following points in mind:
·
OpenGL doesn't maintain tables of textures; it uses either 1D texture and 2D texture only. To reuse the textures from your IRIS GL code, put them in a display list.
·
OpenGL doesn't automatically generate mipmaps. If you're using mipmaps, you must first call
gluBuild2DMipmaps
.
·
In OpenGL, you use
glEnable
 and
glDisable
 to turn texturing capabilities on and off.
·
In OpenGL, texture size is more strictly regulated than with IRIS GL. The size of an OpenGL texture must be:
2
 (n)
+2
b
where
 (n)
 is an integer and
b
 is:
·
0, if the texture has no border
·
1, if the texture has a border pixel (OpenGL textures can have 1-pixel borders.)
The following table lists IRIS GL texture functions and their general OpenGL equivalents.
IRIS GL Function
OpenGL Function
Meaning
textdef2d
glTexImage2D
glTexParameter
gluBuild2DMipmaps
Specify a 2D texture image.
textbind
glTexImage2D
glTexParameter
gluBuild2DMipmaps
Select a texture function.
tevdef
glTexEnv
Define a texture-mapping environment.
tevbind
glTexEnv
glTexImage1D
Select a texture environment.
t2
glTexCoord
Set the current texture coordinates.
texgen
glTexGen
glGetTexParameter
gluBuild1DMipmaps
gluBuild2DMipmaps
gluScaleImage
Control generation of texture coordinates.
Scale an image to an arbitrary size.
For more information on texturing, see the
OpenGL Programming Guide
.


Translating tevdef
Here is an example of an IRIS GL texture-environment definition that specifies the TV_DECAL texture-environment option:
float tevprops[] = {TV_DECAL, TV_NULL};
tevdef(1, 0, tevprops);
and the same code translated to OpenGL:
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
The following table lists the IRIS GL texture-environment options and their OpenGL equivalents.
IRIS GL Option
OpenGL Option
TV_MODULATE
GL_MODULATE
TV_DECAL
GL_DECAL
TV_BLEND
GL_BLEND
TV_COLOR
GL_TEXTURE_ENV_COLOR
TV_ALPHA
No direct OpenGL equivalent.
TV_COMPONENT_SELECT
No direct OpenGL equivalent.
For more information about texture-environment options, see
glTexEnv
.


Translating texdef
Here is an example of an IRIS GL texture definition:
float texprops[] = {
TX_MINFILTER, TX_POINT,
TX_MAGFILTER, TX_POINT,
TX_WRAP_S, TX_REPEAT,
TX_WRAP_T, TX_REPEAT,
TX_NULL };
textdef2d(1, 1, 6, 6, ganite_texture, 7, texprops);
In the example above,
texdef
 specifies the TX_POINT filter as both the magnification and the minimizing filter, and TX_REPEAT as the wrapping mechanism. It also specifies the texture image:
granite_texture
.
In OpenGL,
glTexImage
 specifies the image and
glTexParameter
 sets the property. To translate IRIS GL texture definitions, replace the
textdef
 function with
glTexImage
 and one or more calls to
glTexParameter
.
The preceding IRIS GL code looks like this when translated to OpenGL:
GLfloat nearest[] = {GL_NEAREST};
GLfloat repeat = {GL_REPEAT};
glTexParameterfv( GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, nearest);
glTexParameterfv( GL_TEXTURE_1D, GL_TEXTURE_MAGILTER, nearest);
glTexParameterfv( GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, repeat);
glTexParameterfv( GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, nearest);
glTexImage1D( GL_TEXTURE_1D, 0, 1, 6, 0, GL_RGB,
GL_UNSIGNED_SHORT, granite_tex);
The following table lists the IRIS GL texture parameters and their OpenGL equivalents.
texdef(..., np, ...) Option
glTexParameter Parameter
TX_MINFILTER
GL_TEXTURE_MIN_FILTER
TX_MAGFILTER
GL_TEXTURE_MAG_FILTER
TX_WRAP, TX_WRAP_S
GL_TEXTURE_WRAP_S
TX_WRAP, TX_WRAP_T
GL_TEXTURE_WRAP_T
GL_TEXTURE_BORDER_COLOR
The following table lists the possible values of the IRIS GL texture parameters and their OpenGL equivalents.
IRIS GL Texture Parameter
OpenGL Texture Parameter
TX_POINT
GL_NEAREST
TX_BILINEAR
GL_LINEAR
TX_MIPMAP_POINT
GL_NEAREST_MIPMAP_NEAREST
TX_MIPMAP_BILINEAR
GL_LINEAR_MIPMAP_NEAREST
TX_MIPMAP_LINEAR
GL_NEAREST_MIPMAP_LINEAR
TX_TRILINEAR
GL_LINEAR_MIPMAP_LINEAR


Translating texgen
The IRIS GL function
texgen
 is translated to
glTexGen
 for OpenGL.
With IRIS GL, you call
texgen
 twice: once to set the mode and plane equation simultaneously, and once to enable texture-coordinate generation. For example:
texgen(TX_S, TG_LINEAR, planeParams);
texgen(TX_S, TG_ON, NULL);
With OpenGL, you make three calls: two to
glTexGen
 (once to set the mode and once to set the plane equation), and one to
glEnable
. For example, the OpenGL equivalent to the IRIS GL code above is:
glTexGen(GL_S, GLTEXTURE_GEN_MODE, modeName);
glTextGen(GL_S, GL_OBJECT_PLANE, planeParameters);
glEnable(GL_TEXTURE_GEN_S);
The following table lists the IRIS GL texture-coordinate names and their OpenGL equivalents.
 IRIS GL Texture Coordinate
OpenGL Texture Coordinate
glEnable Argument
TX_S
GL_S
GL_TEXTURE_GEN_S
TX_T
GL_T
GL_TEXTURE_GEN_T
TX_R
GL_R
GL_TEXTURE_GEN_R
TX_Q
GL_Q
GL_TEXTURE_GEN_Q
The following table lists the IRIS GL texture-generation mode and plane names and their OpenGL equivalents.
IRIS GL Texture Mode
OpenGL Texture Mode
OpenGL Plane Name
TG_LINEAR
GL_OBJECT_LINEAR
GL_OBJECT_PLANE
TG_CONTOUR
GL_EYE_LINEAR
GL_EYE_PLANE
TG_SPHEREMAP
GL_SPHERE_MAP


Porting Picking Functions
All IRIS GL picking functions have OpenGL equivalents, with the exception of
clearhitcode
. The following table lists the IRIS GL picking functions and their OpenGL counterparts.
IRIS GL Function
OpenGL Function
Meaning
clearhitcode
Not supported.
Clears global variable and hitcode.
pick,
select
glRenderMode
(GL_SELECT)
Switch to selection or picking mode.
endpick
endselect
glRenderMode
(GL_RENDER)
Switch to rendering mode.
picksize
gluPickMatrix
glSelectBuffer
Set the return array.
initnames
glInitNames
pushname
popname
glPushName
glPopName
loadname
glLoadName
For more information on picking, see
gluPickMatrix
.


Porting Feedback Functions
With IRIS GL, the way that feedback is handled differs depending on the computer running IRIS GL. OpenGL standardizes feedback functions so you can rely on consistent feedback among various hardware platforms. The following table lists the IRIS GL feedback functions and their OpenGL equivalents.
IRIS GL Function
OpenGL Function
Meaning
feedback
glRenderMode
(GL_FEEDBACK)
Switch to feedback mode.
endfeedback
glRenderMode
(GL_RENDER)
glFeedbackBuffer
Switch to rendering mode.
passthrough
glPassThrough
Place a token marker in the feedback buffer.


OpenGL Commands and Their IRIS GL Equivalents
This appendix lists IRIS GL functions and their equivalent OpenGL functions. The first column is an alphabetical list of IRIS GL functions, the second column contains the corresponding functions to use in OpenGL.
Note
  In many cases the OpenGL commands listed will function somewhat differently from the IRIS GL commands, and the parameters may be different as well. For more information on the differences between IRIS GL and OpenGL, see "IRIS GL and OpenGL Differences."
IRIS GL Call
OpenGL/GLU/Win32 Equivalent
acbuf
glAccum
acsize
ChoosePixelFormat
addtopup
Use Win32 for menus.
afunction
glAlphaFunc
arc
gluPartialDisk
backbuffer
glDrawBuffer(GL_BACK)
backface
glCullFace(GL_BACK)
bbox2
Not supported.
bgnclosedline
glBegin(GL_LINE_LOOP)
bgncurve
gluBeginCurve
bgnline
glBegin(GL_LINE_STRIP)
bgnpoint
glBegin(GL_POINTS)
bgnpolygon
glBegin(GL_POLYGON)
bgnqstrip
glBegin(GL_QUAD_STRIP)
bgnsurface
gluBeginSurface
bgntmesh
glBegin( GL_TRIANGLE_STRIP)
bgntrim
gluBeginTrim
blankscreen
Use Win32 for windowing.
blanktime
Use Win32 for windowing.
blendfunction
glBlendFunc
blink
Use Win32 for color maps.
blkqread
Use Win32 for event handling.
c
glColor
callfunc
Not supported.
callobj
glCallList
charstr
glCallLists
chunksize
Not needed.
circ
gluDisk
clear
glClear( GL_COLOR_BUFFER_BIT)
clearhitcode
Not supported.
clipplane
glClipPlane
clkon
Use Win32 for keyboard management.
clkoff
Use Win32 for keyboard management.
closeobj
glEndList
cmode
ChoosePixelFormat
cmov
cmov2
glRasterPos3
glRasterPos2
color
glIndex
compactify
Not needed.
concave
gluBeginPolygon
cpack
glColor
crv
Not supported.
crvn
Not supported.
curorigin
Use Win32 for cursors.
cursoff
Use Win32 for cursors.
curson
Use Win32 for cursors.
curstype
Use Win32 for cursors.
curvebasis
glMap1
curveit
glEvalMesh1
curveprecision
Not supported.
cyclemap
Use Win32 for color maps.
czclear
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
dbtext
Not supported.
defbasis
glMap1
defcursor
Use Win32 for cursors.
deflinestyle
glLineStipple
defpattern
glPolygonStipple
defpup
Use Win32 for menus.
defrasterfont
wglUseFontBitmaps
delobj
glDeleteLists
deltag
Not supported.
depthcue
glFog
dglclose
Not needed. (OpenGL is network transparent.)
dglopen
Not needed. (OpenGL is network transparent.)
dither
glEnable(GL_DITHER)
dopup
Use Win32 for menus.
doublebuffer
ChoosePixelFormat
draw
glBegin(GL_LINES)
drawmode
wglMakeCurrent
editobj
Not supported.
endclosedline
glEnd
endcurve
gluEndCurve
endfeedback
glRenderMode(GL_RENDER)
endfullscreen
Not supported.
endline
glEnd
endpick
glRenderMode(GL_RENDER)
endpoint
glEnd
endpolygon
glEnd
endpupmode
Use Win32 for menus.
endqstrip
glEnd
endselect
glRenderMode(GL_RENDER)
endsurface
gluEndSurface
endtmesh
glEnd
endtrim
gluEndTrim
feedback
glFeedbackBuffer
finish
glFinish
fogvertex
glFog
font
See glListBase.
foreground
Use Win32 for windowing.
freepup
Use Win32 for menus.
frontbuffer
glDrawBuffer(GL_FRONT)
frontface
See glCullFace.
fudge
Use Win32 for windowing.
fullscrn
Not supported.
gammaramp
Use Win32 for color maps.
gbegin
Use Win32 for windowing.
gconfig
No equivalent. (Not needed.)
genobj
glGenLists
gentag
Not supported.
getbackface
glGet
getbuffer
glGet
getbutton
Use Win32 for windowing.
getcmmode
wglGetCurrentContext
getcolor
glGet
getcpos
glGet
getcursor
Not supported.
getdcm
glIsEnabled
getdepth
glGet
getdescender
Use Win32 for fonts.
getdev
Not supported.
getdisplaymode
glGet
wglGetCurrentContext
getdrawmode
wglGetCurrentContext
getfont
Use Win32 for fonts.
getgdesc
glGet
DescribePixelFormat
wglGetCurrentContext
wglGetCurrentDC
getgpos
Not supported.
getheight
Use Win32 for fonts.
gethitcode
Not supported.
getlsbackup
Not supported.
getlsrepeat
glGet
getlstyle
glGet
getlwidth
glGet
getmap(void)
Not supported.
getmatrix
glGet(GL_MODELVIEW_MATRIX)
glGet(GL_PROJECTION_MATRIX)
getmcolor
Not supported.
getmmode
glGet(GL_MATRIX_MODE)
getmonitor
Not supported.
getnurbsproperty
gluGetNurbsProperty
getopenobj
Not supported.
getorigin
Use Win32 for windowing.
getpattern
glGetPolygonStipple
getplanes
glGet(GL_RED_BITS)
glGet(GL_GREEN_BITS)
glGet(GL_BLUE_BITS)
getport
Use Win32 for windowing.
getresetls
Not supported.
getscrbox
Not supported.
getscrmask
glGet(GL_SCISSOR_BOX)
getshade
glGet( GL_CURRENT_INDEX)
getsize
Use Win32 for windowing.
getsm
glGet(GL_SHADE_MODEL)
getvaluator
Use Win32 for event handling
getvideo
Not supported.
getviewport
glGet(GL_VIEWPORT)
getwritemask
glGet( GL_INDEX_WRITEMASK)
getwscrn
Use Win32 for windowing.
getzbuffer
glIsEnabled( GL_DEPTH_TEST)
gexit
Use Win32 for windowing.
gflush
glFlush
ginit
Use Win32 for windowing.
glcompat
Not supported.
greset
Not supported.
gRGBcolor
glGet(GL_CURRENT_RASTER_COLOR)
gRGBcursor
Use Win32 for cursors.
gRGBmask
glGet( GL_COLOR_WRITEMASK)
gselect
glSelectBuffer
gsync
Use Win32 for windowing.
gversion
glGetString( GL_RENDERER)
iconsize
Use Win32.
icontitle
Use Win32.
imakebackground
Use Win32 for event handling.
initnames
glInitNames
ismex
Not supported.
isobj
glIsList
isqueued
Use Win32 for event handling.
istag
Not supported.
keepaspect
Use Win32 for windowing.
lampoff
Not supported.
lampon
Not supported.
linesmooth
glEnable( GL_LINE_SMOOTH)
linewidth
glLineWidth
linewidthf
glLineWidth
lmbind
glEnable(GL_LIGHTING)
glEnable(GL_LIGHT)
lmcolor
glColorMaterial
lmdef
glMaterial
glLight
glLightModel
loadmatrix
glLoadMatrix
loadname
glLoadName
logicop
glLogicOp
lookat
gluLookAt
lrectread
glReadPixels
lrectwrite(])
glDrawPixels
lRGBrange
Not supported. (See glFog)
lsbackup
Not supported.
lsetdepth
glDepthRange
lshaderange
Not supported. (See glFog)
lsrepeat
glLineStipple
makeobj
glNewList
maketag
Not supported.
mapcolor
Use Win32 for color maps.
mapw
gluProject
maxsize
Use Win32 for windowing.
minsize
Use Win32 for windowing.
mmode
glMatrixMode
move
Not supported.
mswapbuffers
Use Win32 for windowing.
multimap
Use Win32 for color maps.
multmatrix
glMultMatrix
n3f
glNormal3fv
newpup
Use Win32 for Menus.
newtag
Not supported.
nmode
glEnable(GL_NORMALIZE)
noborder
Use Win32 for windowing.
noise
Use Win32 for event handling.
noport
Use Win32 for windowing.
normal
glNormal3fv
nurbscurve
gluNurbsCurve
nurbssurface
gluNurbsSurface
objdelete
Not supported.
objinsert
Not supported.
objreplace
Not supported.
onemap
Use Win32 for color maps.
ortho
glOrtho
ortho2
gluOrtho2D
overlay
Use Win32.
pagecolor
Not supported.
passthrough
glPassThrough
patch
glEvalMesh2
patchbasis
glMap2
patchcurves
glMap2
patchprecision
Not supported.
pclos
Not supported. (See glEnd)
pdr
Not supported. (See glVertex)
perspective
gluPerspective
pick
gluPickMatrix
glRenderMode(GL_SELECT)
picksize
gluPickMatrix
pixmode
glPixelTransfer and glPixelStore
pmv
Not supported. (See glBegin and glVertex)
pnt
glBegin(GL_POINTS)
pntsize
glPointSize
pntsizef
glPointSize
pntsmooth
glEnable( GL_POINT_SMOOTH)
polarview
Not supported. (See glRotate and glTranslate)
polf
Not supported.
poly
Not supported.
polymode
glPolygonMode
polysmooth
glEnable( GL_POLYGON_SMOOTH)
popattributes
glPopAttrib
popmatrix
glPopMatrix
popname
glPopName
popviewport
glPopAttrib
prefposition
Use Win32 for windowing.
prefsize
Use Win32 for windowing.
pupmode
Use Win32 for windowing.
pushattributes
glPushAttrib
pushmatrix
glPushMatrix
pushname
glPushName
pushviewport
glPushAttrib(GL_VIEWPORT)
pwlcurve
gluPWLCurve
qcontrol
Use Win32 for event handling.
qdevice
Use Win32 for event handling.
qenter
Use Win32 for event handling.
qgetfd
Use Win32 for event handling.
qread
Use Win32 for event handling.
qreset
Use Win32 for event handling.
qtest
Use Win32 for event handling.
rcrv
Not supported.
rcrvn
Not supported.
rdr
Not supported.
readdisplay
Not supported.
readRGB
Not supported.
readsource
glReadBuffer
rect
See glRect and glPolygonMode
rectf
glRect
rectcopy
glCopyPixels
rectread
glReadPixels
rectwrite
glDrawPixels
rectzoom
glPixelZoom
resetls
Not supported.
reshapeviewport
Not supported.
RGBcolor
glColor
RGBcursor
Use Win32 for cursors.
RGBmode
Use Win32 for windowing.
RGBrange
Not supported.
RGBwritemask
glColorMask
ringbell
Not supported.
rmv
Not supported.
rot
glRotate
rotate
glRotate
rpatch
Not supported.
rpdr
Not supported.
rpmv
Not supported.
sbox
glRect
scale
glScale
sclear
glClear( GL_STENCIL_BUFFER_BIT)
scrbox
Not supported.
screenspace
Not supported.
scrmask
glScissor
scrnattach
Use Win32 for windowing.
scrnselect
Use Win32 for windowing.
scrsubdivide
Not supported.
select
glRenderMode
setbell
Not supported.
setcursor
Use Win32 for cursors.
setdblights
Not supported.
setdepth
glDepthRangea
setlinestyle
glLineStipple
setmap
Use Win32 for color maps.
setmonitor
Not supported.
setnurbsproperty
gluNurbsProperty
setpattern
glPolygonStipple
setpup
Use Win32 for menus.
setvaluator
Use Win32 for devices.
setvideo
Not supported.
shademodel
glShadeModel
shaderange
glFog
singlebuffer
Use Win32 for windowing.
smoothline
glEnable( GL_LINE_SMOOTH)
spclos
Not supported.
splf
Not supported. (See glBegin)
stencil
glStencilFunc
glStencilOp
stensize
glStencilMask
stepunit
Use Win32 for windowing.
strwidth
Use Win32 for fonts and strings.
subpixel
Not needed.
swapbuffers
SwapBuffers
swapinterval
Use Win32 for windowing.
swaptmesh
Not supported.
(See glBegin(GL_TRIANGLE_FAN))
swinopen
Use Win32 for windowing.
swritemask
glStencilMask
t2
glTexCoord2
tevbind
glTexEnv
tevdef
glTexEnv
texbind
glTexImage2D
glTexParameter
gluBuild2DMipmaps,
texdef2d
glTexImage2D
glTexParameter
gluBuild2DMipmaps
texgen
glTexGen
textcolor
Not supported.
textinit
Not supported.
textport
Not supported.
tie
Use Win32 for event handling.
tpoff
Not supported.
tpon
Not supported.
translate
glTranslate
underlay
ChoosePixelFormat
unqdevice
Use Win32 for event handling.
v
glVertex
videocmd
Not supported.
viewport
glViewport
winattach
Use Win32 for windowing.
winclose
wglDeleteContext
CloseWindow
winconstraints
Use Win32 for windowing.
windepth
Use Win32 for windowing.
window
glFrustum
winget
wglGetCurrentContext
winmove
Use Win32 for windowing.
winopen
Use Win32 for windowing.
winpop
Use Win32 for windowing.
winposition
Use Win32 for windowing.
winpush
Use Win32 for windowing.
winset
Use Win32 for windowing.
wintitle
Use Win32 for windowing.
wmpack
glColorMask
writemask
glIndexMask
writepixels
glDrawPixels
writeRGB
glDrawPixels
xfpt
Not supported.
zbuffer
glEnable(GL_DEPTH_TEST)
zclear
glClear( GL_DEPTH_BUFFER_BIT)
zdraw
Not supported.
zfunction
glDepthFunc
zsource
Not supported.
zwritemask
glDepthMask


IRIS GL and OpenGL Differences
This appendix lists the differences between OpenGL and IRIS GL. A term for each difference is given, followed by a description.
accumulation wrapping
The OpenGL accumulation buffer operation is not defined when component values exceed 1.0 or drop below
-
 1.0.
antialiased lines
OpenGL stipples antialiased lines. IRIS GL does not.
arc
OpenGL supports arcs in its utility library.
attribute lists
The attributes pushed by IRIS GL
pushattributes
 differ from any of the attribute sets pushed by OpenGL
glPushAttrib
. Because all OpenGL states can be read back, however, you can implement any desired push/pop semantics using OpenGL.
automatic texture scaling
The OpenGL texture interface does not support automatic scaling of images to power-of-two dimensions. However, the GLU supports image scaling.
bbox
OpenGL doesn't support conditional execution of display lists.
callfunc
OpenGL doesn't support callback from display lists. Note that IRIS GL doesn't support this functionality either, when client and server are on different platforms.
circle
OpenGL supports circles with the GLU. In OpenGL both circles and arcs (disks and partial disks) can have holes. Also, you can change subdivision of the primitives in OpenGL, and the primitives' surface normals are available for lighting.
clear options
OpenGL actually clears buffers. It doesn't apply currently specified pixel operations, such as blending and logicop, regardless of their modes. To clear using such features, you must render a window-size polygon.
closed lines
OpenGL renders all single-width aliased lines such that abutting lines share no pixels. This means that the "last" pixel of an independent line is not drawn.
color/normal flag
OpenGL lighting is explicitly enabled or disabled. When enabled, it is effective regardless of the order in which colors and normals are specified.
You cannot enable or disable lighting between OpenGL
glBegin
 and
glEnd
 commands. To disable lighting between
glBegin
 and
glEnd
, specify zero ambient, diffuse, and specular material reflectance and then set the material emission to the desired color.
concave polygons
The core OpenGL API doesn't handle concave polygons, but the GLU support decomposing concave, non-self-intersecting contours into triangles. These triangles can either be drawn immediately or returned.
current computed color
OpenGL has no equivalent to a current computed color. If you're using OpenGL as a lighting engine, you can use feedback to obtain colors generated by lighting calculations.
current graphics position
OpenGL doesn't maintain a current graphics position. IRIS GL commands that depends on current graphics position, such as relative lines and polygons, are not included in OpenGL.
curves
OpenGL does not support IRIS GL curves. Use of NURBS curves is recommended.
defs/binds
OpenGL doesn't have the concept of material, light, or texture objects, only of material, light, and texture properties. You can use display lists to create their own objects, however.
depthcue
OpenGL provides no direct support for depth cueing, but its fog support is a more general capability that you can easily use to emulate the IRIS GL
depthcue
 function.
display list editing
OpenGL display lists can't be edited, only created and destroyed. Because you specify display list names, however, you can redefine individual display lists in a hierarchy.
OpenGL display lists are designed for data caching, not for database management. They are guaranteed to be stored on the server in client/server environments, so they are not limited by network bandwidth during execution.
OpenGL display lists can be called between
glBegin
 and
glEnd
 commands, so the display list hierarchy can be made fine enough that it can, in effect, be edited.
error checking
OpenGL checks for errors more carefully than IRIS GL. For example, all OpenGL functions that are not accepted between
glBegin
 and
glEnd
 are detected as errors, and have no other effect.
error return values
When an OpenGL command that returns a value detects an error, it always returns zero. OpenGL commands that return data through passed pointers make no change to the array contents if an error is detected.
error side effects
When an OpenGL command results in an error, its only side effect is to update the error flag to the appropriate value. No other state changes are made. (An exception is the OUT_OF_MEMORY error, which is fatal.)
feedback
Feedback is standardized in OpenGL so it doesn't change from machine to machine.
fonts and strings
OpenGL requires character glyphs to be manipulated as individual display lists. It provides a display list calling function that accepts a list of display list names, each name represented as 1, 2, or 4 bytes.
glCallLists
 adds a separately specified offset to each display list name before the call, allowing lists of display list names to be treated as strings.
This mechanism provides all the functionality of IRIS GL fonts, and considerably more. For example, characters comprised of triangles can be easily manipulated.
frontbuffer
IRIS GL has complex rules for rendering to the front buffer in single buffer mode. OpenGL handles rendering to the front buffer in a straightforward way.
hollow polygons
You can use the OpenGL stencil capacity to render hollow polygons. OpenGL doesn't support other means for creating hollow polygons.
index clamping
Where possible, OpenGL treats color and stencil indexes as bit fields rather than numbers. Thus indexes are masked, rather than clamped, to the supported range of the framebuffer.
integer colors
Signed integer color components (red, green, blue, or alpha) are mapped linearly to floating point such that the most negative integer maps to -1.0 and the most positive integer maps to 1.0. This mapping occurs when you specify the color, before OpenGL replaces the current color.
Unsigned integer color components are mapped linearly to floating points such that 0 maps to 0.0 and the largest integer maps to 1.0. This mapping occurs when you specify the color, before OpenGL replaces the current color.
integer normals
Integer normal components are mapped just like signed color components. The most negative integer maps to -1.0, and the most positive integer maps to 1.0. pixel fragments.
Pixels drawn by
glDrawPixels
 or
glCopyPixels
 are always rasterized and converted to fragments. The resulting fragments are textured, fogged, depth buffered, blended, and so on, just as if they were generated from geometric points. Fragment data that isn't provided by the source pixels is augmented from the current raster position. For example, RGBA pixels take the raster position Z and texture coordinates. Depth pixels take the raster position color and texture coordinates.
invariance
OpenGL guarantees certain consistency that IRIS GL doesn't. For example, OpenGL guarantees that identical code sequences sent to the same system, differing only in the specified blending function, will generate the same pixel fragments. (The fragments differ, however, if blending is enabled and then disabled.)
lighting equation
The OpenGL lighting equation differs slightly from the IRIS GL equation. OpenGL supports separate attenuation for each light source, rather than a single attenuation for all the light sources like IRIS GL. OpenGL adjusts the equation so that ambient, diffuse, and specular lighting contributions are all attenuated. Also, OpenGL allows you to specify separate colors for the ambient, diffuse, and specular intensities of light sources, as well as for the ambient, diffuse, and specular reflectance of materials. All OpenGL light and material colors include alpha.
Setting the specular exponent to zero does not defeat specular lighting in OpenGL.
mapw
OpenGL utilities support mapping between object and window coordinates.
matrix mode
Where the IRIS GL
ortho
,
ortho2
,
perspective
, and
window
 functions operate on a particular matrix, all OpenGL matrix operations work on the current matrix. All OpenGL matrix operations except
glLoadIdentity
 and
glLoadMatrix
 multiply the current matrix rather than replacing it (as do
ortho
,
ortho2
,
perspective
, and
window
 in the IRIS GL).
mipmaps, automatic generation
The OpenGL texture interface does not support automatic generation of mipmap images. However, the GLU supports the automatic generation of mipmap images for both 1D and 2D textures.
move/draw/pmove/pdraw/pclos
OpenGL supports only Begin/End style graphics, because it does not maintain a current graphics position. The scalar parameter specification of the old move/draw commands is accepted by OpenGL for all vertex related commands, however.
mprojection mode
IRIS GL doesn't transform geometry by the ModelView matrix while in Projection matrix mode. OpenGL always transforms by both the ModelView and the Projection matrix, regardless of matrix mode.
multi-buffer drawing
OpenGL renders to each color buffer individually, rather than computing a single new color value based on the contents of one color buffer and writing it to all the enabled color buffers, as IRIS GL does.
NURBS
OpenGL supports NURBS with a combination of core capability (evaluators) and GLU support. All IRIS GL NURBS capabilities are supported.
old polygon mode
Aliased OpenGL polygons are always point-sampled. IRIS GL's polygon compatibility mode, where pixels outside the polygon perimeter are included in its rasterization, is not supported. If your code uses this polygon mode, it's probably for rectangles. Old polygon mode rectangles appear one pixel wider and higher.
packed color formats
OpenGL accepts colors as 8-bit components, but these components are treated as an array of bytes rather than as bytes packed into larger words. By encouraging array indexing rather than shifting, OpenGL promotes endian-invariant programming.
Just as IRIS GL accepts packed colors both for geometric and pixel rendering, OpenGL accepts arrays of color components for geometric and pixel rendering.
patches
OpenGL doesn't support IRIS GL patches.
per-bit color writemask
OpenGL writemasks for color components enable or disable changes to the entire component (red, green, blue, or alpha), not to individual bits of components. Note that per-bit writemasks are supported for both color indexes and stencil indexes, however.
per-bit depth writemask
OpenGL writemasks for depth components enable or disable changes to the entire component, not to individual bits of the depth component.
pick
The OpenGL utility library includes support for generating a pick matrix.
pixel coordinates
In both OpenGL and IRIS GL, the origin of a window's coordinate system is at its lower left corner. OpenGL places the origin at the lower left corner of this pixel, however, while IRIS GL places it at the center of the lower left pixel.
pixel zoom
OpenGL negative zoom factors reflect about the current graphics position. IRIS GL doesn't define the operation of negative zoom factors, and instead provides RIGHT_TO_LEFT and TOP_TO_BOTTOM reflection pixmodes. These reflection modes reflect in place, rather than about the current raster position. OpenGL doesn't define reflection modes.
pixmode
OpenGL pixel transfers operate on individual color components, rather than on packed groups of four 8-bit components as does IRIS GL. While OpenGL provides substantially more pixel capability than IRIS GL, it doesn't support packed color constructs, and it doesn't enable color components to be reassigned (red to green, red to blue, etc.) during pixel copy operations.
polf/poly
OpenGL provides no direct support for vertex lists other than display lists. Functions like
polf
 and
poly
 can be implemented easily using the OpenGL API, however.
polygon provoking vertex
Flat shaded IRIS GL polygons take the color of the last vertex specified, while OpenGL polygons take the color of the first vertex specified.
polygon stipple
With IRIS GL the polygon stipple pattern is relative to the screen. With OpenGL it is relative to a window.
polygon vertex count
There is no limit to the number of vertexes between
glBegin
 and
glEnd
 with OpenGL, even for
glBegin(POLYGON)
. With IRIS GL polygons are limited to no more than 255 vertexes.
readdisplay
Reading pixels outside window boundaries is properly a window system capability, rather than a rendering capability. Use Win32 functions to replace the IRIS GL readdisplay command.
relative move/draw/pmove/pdraw/pclos
OpenGL doesn't maintain a current graphics position, and therefore doesn't support relative vertex operations.
RGBA logicop()
OpenGL does not support logical operations on RGBA buffers.
sbox()
sbox
 is an IRIS GL rectangle primitive that is well-defined only if transformed without rotation. It is designed to be rendered faster than standard rectangles. While OpenGL doesn't support such a primitive, it can be tuned to render rectangles very quickly when the matrixes and other modes are in states that simplify calculations.
scalar arguments
All OpenGL commands that are accepted between
glBegin
 and
glEnd
 have entry points that accept scalar arguments. For example,
glColor4f(red,green,blue,alpha)
.
scissor
OpenGL
glScissor
 doesn't track the viewport. The IRIS GL
viewport
 command automatically updates the
scrmask
.
scrbox()
OpenGL doesn't support bounding box computation.
scrsubdivide()
OpenGL doesn't support screen subdivision.
single matrix mode
OpenGL always maintains two matrixes: ModelView and Projection. While an OpenGL implementation can consolidate these into a single matrix for performance reasons, it must always present the 2-matrix model to the programmer.
subpixel mode
All OpenGL rendering is subpixel positioned
¾
subpixel mode is always on.
swaptmesh()
OpenGL doesn't support the
swaptmesh
 capability. It does offer two types of triangle meshes, however: one that corresponds to the default "strip" behavior of the IRIS GL, and another that corresponds to calling
swaptmesh
 prior to the third and all subsequent vertexes when using IRIS GL.
vector arguments
All OpenGL commands that are accepted between
glBegin
 and
glEnd
 have entry points that accept vector arguments. For example,
glColor4fv(v)
.
window management
OpenGL includes no window system commands. It is always supported as an extension to a window or operating system that includes capability for device and window control. Each extension provides a system-specific mechanism for creating, destroying, and manipulating OpenGL rendering contexts. For example, the OpenGL extension to the X window system (GLX) includes roughly 10 commands for this purpose.
IRIS GL commands such as
gconfig
 and
drawmode
 are not implemented by OpenGL.
window offset
IRIS GL returns viewport and character positions in screen, rather than window, coordinates. OpenGL always uses window coordinates.
z rendering
OpenGL doesn't support rendering colors to the depth buffer. It does allow for additional color buffers, which can be implemented using the same memory that is used for depth buffers in other window configurations. But these additional color buffers cannot share memory with the depth buffer in any single configuration.


OpenGL Glossary
A
aliasing
A rendering technique that assigns to pixels the color of the primitive being rendered, regardless of whether that primitive covers all of the pixel's area or only a portion of the pixel's area. This results in jagged edges, or
jaggies
alpha
A fourth color component typically used to control color blending. The alpha component is never displayed directly. By convention, OpenGL alpha corresponds to opacity rather than transparency, meaning an alpha value of 1.0 implies complete opacity, and an alpha value of 0.0 implies complete transparency.
animation
Generating repeated renderings of a scene, with smoothly changing viewpoint and/or object positions, quickly enough that the illusion of motion is achieved. OpenGL animation almost always is done using double-buffering.
antialiasing
A rendering technique that assigns pixel colors based on the fraction of the pixel's area that's covered by the primitive being rendered. Antialiased rendering reduces or eliminates the jaggies that result from aliased rendering.
application-specific clipping
Clipping of primitives against planes in eye coordinates. The planes are specified by the application using
glClipPlane( )
.
B
back face
See
face
bit
Binary digit. A state variable that has only two possible values: 0 or 1. Binary numbers are constructions of one or more bits.
bitmap
A rectangular array of bits. Also, the primitive rendered by the
glBitmap( )
 command, which uses its
bitmap
 parameter as a mask.
bitplane
A rectangular array of bits mapped one-to-one with pixels. The frame buffer is a stack of bitplanes.
blending
Reduction of two color components to one component, usually as a linear interpolation between the two components.
buffer
A group of bitplanes that store a single component (such as depth or green) or a single index (such as the color index or the stencil index). Sometimes the red, green, blue, and alpha buffers together are referred to as the color buffer, rather than the color buffers.
C
client
The computer from which OpenGL commands are issued. The computer that issues OpenGL commands can be connected through a network to a different computer that executes the commands, or commands can be issued and executed on the same computer. See also
server
client memory
The main memory (where program variables are stored) of the client computer.
clip coordinates
The coordinate system that follows transformation by the projection matrix and that precedes perspective division. View-volume clipping is done in clip coordinates, but application-specific clipping is not.
clipping
Elimination of the portion of a geometric primitive that's outside the half-space defined by a clipping plane. Points are simply rejected if outside. The portion of a line or of a polygon that's outside the half-space is eliminated, and additional vertices are generated as necessary to complete the primitive within the clipping half-space. Geometric primitives and the current raster position (when specified) are always clipped against the six half-spaces defined by the left, right, bottom, top, near, and far planes of the view volume. Applications can specify optional application-specific clipping planes to be applied in eye coordinates.
color index
A single value that represents a color by name, rather than by value. OpenGL color indexes are treated as continuous values (for example, floating-point numbers) while operations such as interpolation and dithering are performed on them. Color indexes stored in the frame buffer are always integer values, however. Floating-point indexes are converted to integers by rounding to the nearest integer value.
color-index mode
An OpenGL context is in color index mode if its color buffers store color indexes, rather than red, green, blue, and alpha color components.
color map
A table of index-to-RGB mappings that's accessed by the display hardware. Each color index is read from the color buffer, converted to an RGB triple by lookup in the color map, and sent to the monitor.
component
A single, continuous (for example, floating-point) value that represents an intensity or quantity. Usually, a component value of zero represents the minimum value or intensity, and a component value of one represents the maximum value or intensity, though other normalizations are sometimes used. Because component values are interpreted in a normalized range, they are specified independent of actual resolution. For example, the RGB triple (1, 1, 1) is white, regardless of whether the color buffers store 4, 8, or 12 bits each.
Out-of-range components are typically clamped to the normalized range, not truncated or otherwise interpreted. For example, the RGB triple (1.4, 1.5, 0.9) is clamped to (1.0, 1.0, 0.9) before it's used to update the color buffer. Red, green, blue, alpha, and depth are always treated as components, never as indexes.
context
A complete set of OpenGL state variables. Note that frame buffer contents are not part of the OpenGL state, but that the configuration of the frame buffer is.
convex
A polygon is convex if no straight line in the plane of the polygon intersects the polygon more than twice.
convex hull
The smallest convex region enclosing a specified group of points. In two dimensions, the convex hull is found conceptually by stretching a rubber band around the points so that all of the points lie within the band.
coordinate system
In n-dimensional space, a set of n linearly independent vectors anchored to a point (called the origin). A group of coordinates specifies a point in space (or a vector from the origin) by indicating how far to travel along each vector to reach the point (or tip of the vector).
culling
The process of eliminating a front face or back face of a polygon so that it isn't drawn.
current matrix
A matrix that transforms coordinates in one coordinate system to coordinates of another system. There are three current matrices in OpenGL: the modelview matrix transforms object coordinates (coordinates specified by the programmer) to eye coordinates; the perspective matrix transforms eye coordinates to clip coordinates; the texture matrix transforms specified or generated texture coordinates as described by the matrix. Each current matrix is the top element on a stack of matrices. Each of the three stacks can be manipulated with OpenGL matrix-manipulation commands.
current raster position
A window coordinate position that specifies the placement of an image primitive when it's rasterized. The current raster position, and other current raster parameters, are updated when
glRasterpos( )
 is called.
D
depth
Generally refers to the
z
 window coordinate.
depth-cueing
A rendering technique that assigns color based on distance from the viewpoint.
display list
A named list of OpenGL commands. Display lists are always stored on the server, so display lists can be used to reduce the network traffic in client-server environments. The contents of a display list may be preprocessed, and might therefore execute more efficiently than the same set of OpenGL commands executed in immediate mode. Such preprocessing is especially important for computing intensive commands such as
glTexImage( )
.
dithering
A technique for increasing the perceived range of colors in an image at the cost of spatial resolution. Adjacent pixels are assigned differing color values. When viewed from a distance, these colors seem to blend into a single intermediate color. The technique is similar to the half-toning used in black-and-white publications to achieve shades of gray.
double-buffering
OpenGL contexts with both front and back color buffers are double-buffered. Smooth animation is accomplished by rendering into only the back buffer (which isn't displayed), then causing the front and back buffers to be swapped.
E
element
A single component or index.
evaluation
The OpenGL process of generating object-coordinate vertices and parameters from previously specified B
é
zier equations.
execute
An OpenGL command is executed when it's called in immediate mode or when the display list that it's a part of is called.
eye coordinates
The coordinate system that follows transformation by the modelview matrix and that precedes transformation by the projection matrix. Lighting and application-specific clipping are done in eye coordinates.
F
face
One side of a polygon. Each polygon has two faces: a front face and a back face. Only one face or the other is ever visible in the window. Whether the back or front face is visible is effectively determined after the polygon is projected onto the window. After this projection, if the polygon's edges are directed clockwise, one of the faces is visible; if directed counterclockwise, the other face is visible. Whether clockwise corresponds to front or back (and counterclockwise corresponds to back or front) is determined by the OpenGL programmer.
flat shading
Refers to coloring a primitive with a single, constant color across its extent, rather than smoothly interpolating colors across the primitive. See
Gouraud shading
fog
A rendering technique that can be used to simulate atmospheric effects such as haze, fog, and smog by fading object colors to a background color based on distance from the viewer. Fog also aids in the perception of distance from the viewer, giving a
depth cue
font
A group of graphical character representations usually used to display strings of text. The characters may be roman letters, mathematical symbols, Asian ideograms, Egyptian hieroglyphs, and so on.
fragment
Fragments are generated by the rasterization of primitives. Each fragment corresponds to a single pixel and includes color, depth, and sometimes texture-coordinate values.
frame buffer
All the buffers of a given window or context. Sometimes includes all the pixel memory of the graphics hardware accelerator.
front face
See
face
frustum
The view volume warped by perspective division.
G
gamma correction
A function applied to colors stored in the frame buffer to correct for the nonlinear response of the eye (and sometimes of the monitor) to linear changes in color-intensity values.
geometric model
The object-coordinate vertices and parameters that describe an object. Note that OpenGL doesn't define a syntax for geometric models, but rather a syntax and semantics for the rendering of geometric models.
geometric object
Geometric model.
geometric primitive
A point, a line, or a polygon.
Gouraud shading
Smooth interpolation of colors across a polygon or line segment. Colors are assigned at vertices and linearly interpolated across the primitive to produce a relatively smooth variation in color. Also called
smooth shading
.
group
Each pixel of an image in client memory is represented by a group of one, two, three, or four elements. Thus, in the context of a client memory image, a group and a pixel are the same thing.
H
half-space
A plane divides space into two half-spaces.
homogenous coordinates
A set of
n
+1 coordinates used to represent points in
n
-dimensional projective space. Points in projective space can be thought of as points in Euclidean space together with some points at infinity. The coordinates are homogenous because a scaling of each of the coordinates by the same non-zero constant doesn't alter the point to which the coordinates refer. Homogeneous coordinates are useful in the calculations of projective geometry, and thus in computer graphics, where scenes must be projected onto a window.
I
image
A rectangular array of pixels, either in client memory or in the frame buffer.
image primitive
A bitmap or an image.
immediate mode
Execution of OpenGL commands when they're called, rather than from a display list. No immediate-mode bit exists; the
mode
 in immediate mode refers to usage of OpenGL, rather than to a specific bit of OpenGL state.
index
A single value that's interpreted as an absolute value, rather than as a normalized value in a specified range (as is a component). Color indexes are the names of colors, which are dereferenced by the display hardware using the color map. Indexes are typically masked, rather than clamped, when out of range. For example, the index 0xf7 is masked to 0x7 when written to a 4-bit buffer (color or stencil). Color indexes and stencil indexes are always treated as indexes, never as components.
IRIS GL
Silicon Graphics' proprietary graphics library, developed from 1982 through 1992. OpenGL was designed with IRIS GL as a starting point.
JK
jaggies
Artifacts of aliased rendering. The edges of primitives that are rendered with aliasing are jagged rather than smooth. A near-horizontal aliased line, for example, is rendered as a set of horizontal lines on adjacent pixel rows, rather than as a smooth, continuous line.
L
lighting
The process of computing the color of a vertex based on current lights, material properties, and lighting-model modes.
line
A straight region of finite width between two vertices. (Unlike mathematical lines, OpenGL lines have finite width and length.) Each segment of a strip of lines is itself a line.
luminance
The perceived brightness of a surface. Often refers to a weighted average of red, green, and blue color values that gives the perceived brightness of the combination.
M
matrices
Plural of
matrix
.
matrix
A two-dimensional array of values. OpenGL matrices are all 4x4, though when they are stored in client memory they're treated as 1x16 single-dimension arrays.
modelview matrix
The 4x4 matrix that transforms points, lines, polygons, and raster positions from object coordinates to eye coordinates.
monitor
The device that displays the image in the frame buffer.
motion blurring
A technique that simulates what you get on a piece of film when you take a picture of a moving object, or when you move the camera when you take a picture of a stationary object. In animations without motion blur, moving objects can appear jerky.
N
network
A connection between two or more computers that allows each to transfer data to and from the others.
nonconvex
A polygon is nonconvex if there exists a line in the plane of the polygon that intersects the polygon more than twice.
normal
A three-component plane equation that defines the angular orientation, but not position, of a plane or surface.
normalize
Divide each of the components of a normal by the square root of the sum of their squares. Then, if the normal is thought of as a vector from the origin to the point (nx
¢
, ny
¢
, nx
¢
), this vector has unit length
nx
¢
 =
nx/factor
ny
¢
 =
ny/factor
nz
¢
 =
nz/factor
normal vector
Same as
normal
.
NURBS
Non-Uniform Rational B-Spline. A common way to specify parametric curves and surfaces.
O
object
An object-coordinate model that's rendered as a collection of primitives.
object coordinates
Coordinate system prior to any OpenGL transformation.
orthographic
Nonperspective projection, as in some engineering drawings, with no foreshortening.
P
parameter
A value passed as an argument to an OpenGL command. Sometimes one of the values passed by reference to an OpenGL command.
perspective division
The division of
x
,
y
, and
z
 by
w
, carried out in clip coordinates.
pixel
Picture element. The bits at location (
x
,
y
) of all the bitplanes in the frame buffer constitute the single pixel (
x
,
y
). In an image in client memory, a pixel is one group of elements. In OpenGL window coordinates, each pixel corresponds to a 1.0x1.0 screen area. The coordinates of the lower left corner of the pixel names
x
,
y
 are (
x
,
y
), and the upper right corner are (
x
+1,
y
+1).
point
An exact location in space, which is rendered as a finite-diameter dot.
polygon
A near-planar surface bounded by edges specified by vertices. Each triangle of a triangle mesh is a polygon, as is each quadrilateral of a quadrilateral mesh. The rectangle specified by
glRect*( )
 is also a polygon.
primitive
A shape (such as a point, line, polygon, bitmap or image) that can be drawn, stored, and manipulated as a discrete entity; elements from which large graphic designs are created.
projection matrix
The 4x4 matrix that transforms points, lines, polygons, and raster positions from eye coordinates to clip coordinates.
Q
quadrilateral
A polygon with four edges.
R
rasterize
Convert a projected point, line, or polygon, or the pixels of a bitmap or image, to fragments, each corresponding to a pixel in the frame buffer. Note that all primitives are rasterized, not just points, lines, and polygons.
rectangle
A quadrilateral whose alternate edges are parallel to each other in object coordinates. Polygons specified with
glRect*( )
 are always rectangles; other quadrilaterals might be rectangles.
rendering
Conversion of primitives specified in object coordinates to an image in the frame buffer. Rendering is the primary operation of OpenGL.
RGBA
Red, Green, Blue, Alpha
RGBA mode
An OpenGL context is in RGBA mode if its color buffers store red, green, blue, and alpha color components, rather than color indexes.
S
server
The computer on which OpenGL commands are executed. This might differ from the computer from which commands are issued. See
client
shading
The process of interpolating color within the interior of a polygon, or between the vertices of a line, during rasterization.
single-buffering
OpenGL contexts that don't have back color buffers are single-buffered.
stipple
A one- or two-dimensional binary pattern that defeats the generation of fragments where its value is zero. Line stipples are one-dimensional and are applied relative to the start of a line. Polygon stipples are two-dimensional and are applied with a fixed orientation to the window.
T
tessellation
Reduction of a portion of an analytic surface to a mesh of polygons, or of a portion of an analytic curve to a sequence of lines.
texel
A texture element. A texel is obtained from texture memory and represents the color of the texture to be applied to a corresponding fragment.
texture
A one- or two-dimensional image used to modify the color of fragments produced by rasterization.
texture mapping
The process of applying an image (the texture) to a primitive. Texture mapping is often used to add realism to a scene. For example, you could apply a picture of a building facade to a polygon representing a wall.
texture matrix
The 4x4 matrix that transforms texture coordinates from the coordinates that they're specified in to the coordinates that are used for interpolation and texture lookup.
transformation
A warping of space. In OpenGL, transformations are limited to projective transformations that include anything that can be represented by a 4x4 matrix. Such transformations include rotations, translations, (nonuniform) scalings along the coordinate axes, perspective transformations, and combinations of these.
triangle
A polygon with three edges. Triangles are always convex.
U V
vertex
A point in three-dimensional space.
vertices
Preferred plural of vertex.
viewpoint
The origin of either the eye- or the clip-coordinate system, depending on context. (For example, when discussing lighting, the viewpoint is the origin of the eye-coordinate system. When discussing projection, the viewpoint is the origin of the clip-coordinate system.) With a typical projection matrix, the eye-coordinate and clip-coordinate origins are at the same location.
view volume
The volume in clip coordinates whose coordinates satisfy the three conditions
-
w
£
x
£
w
-
w
£
y
£
w
-
w
£
z
£
w
W
window
A subregion of the frame buffer, usually rectangular, whose pixels all have the same buffer configuration. An OpenGL context renders to a single window at a time.
window-aligned
When referring to line segments or polygon edges, implies that these are parallel to the window boundaries. (In OpenGL, the window is rectangular, with horizontal and vertical edges). When referring to a polygon pattern, implies that the pattern is fixed relative to the window origin.
window coordinates
The coordinate system of a window. It's important to distinguish between the names of pixels, which are discrete, and the window-coordinate system, which is continuous. For example, the pixel at the lower-left corner of a window is a pixel (0, 0); the window coordinates of the center of this pixel are (0.5, 0.5,
z
). Note that window coordinates include a depth, or
z
, component, and that this component is continuous as well.
wireframe
A representation of an object that contains line segments only. Typically, the line segments indicate polygon edges.
X Y Z
X Window System
A window system used by many of the machines on which OpenGL is implemented.


BOOK
The following sample is taken from the
OpenGL Programming Guide.


MAKEFILE  (BOOK Sample)
# Nmake macros for building Windows 32-Bit apps for OpenGL
!include <ntwin32.mak>
opengllibs
    = opengl32.lib glu32.lib glaux.lib
EXES
= accanti.exe  \
          accnot.exe   \
          accpersp.exe \
          accum.exe    \
          aim.exe      \
          alpha.exe    \
          alpha3d.exe  \
          anti.exe     \
          antindx.exe  \
          antipndx.exe \
          antipnt.exe  \
          antipoly.exe \
          bezcurve.exe \
          bezmesh.exe  \
          bezsurf.exe  \
          checker.exe  \
          checker2.exe \
          chess.exe    \
          clip.exe     \
          colormat.exe \
          cone.exe     \
          cube.exe     \
          curve.exe    \
          depthcue.exe \
          disk.exe     \
          dof.exe      \
          dofnot.exe   \
          double.exe   \
          drawf.exe    \
          feedback.exe \
          fog.exe      \
          fogindex.exe \
          font.exe     \
          light.exe    \
          linelist.exe \
          lines.exe    \
          list.exe     \
          list2.exe    \
          maplight.exe \
          material.exe \
          mipmap.exe   \
          model.exe    \
          movelght.exe \
          nurbs.exe    \
          pickdpth.exe \
          pickline.exe \
          picksqr.exe  \
          plane.exe    \
          planet.exe   \
          planetup.exe \
          polys.exe    \
          robot.exe    \
          scclrlt.exe  \
          scene.exe    \
          scenebmb.exe \
          sceneflt.exe \
          select.exe   \
          simple.exe   \
          smooth.exe   \
          sphere.exe   \
          stencil.exe  \
          stroke.exe   \
          surface.exe  \
          tea.exe      \
          teaamb.exe   \
          teapots.exe  \
          texgen.exe   \
          texsurf.exe  \
          trim.exe
all: $(EXES)
.c.exe:
    $(cc) $(cflags) $(cdebug) -DSILENT_WARN $(cvars) $<
    $(link) $(linkdebug) $(guiflags) -subsystem:windows -entry:mainCRTStartup -out:$*.exe $*.obj $(opengllibs) $(guilibs)


ACCANTI.C  (BOOK Sample)
/*
 * (c) Copyright 1993, Silicon Graphics, Inc.
 *               1993, 1994 Microsoft Corporation
 *
 * ALL RIGHTS RESERVED
 *
 * Please refer to OpenGL/readme.txt for additional information
 *
 */
/*  accanti.c
 */
#include "glos.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>
#include "jitter.h"
void myinit(void);
void CALLBACK myReshape(GLsizei w, GLsizei h);
void CALLBACK display(void);
/*  Initialize lighting and other values.
 */
void myinit(void)
{
    GLfloat mat_ambient[] = { 1.0, 1.0, 1.0, 1.0 };
    GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
    GLfloat light_position[] = { 0.0, 0.0, 10.0, 1.0 };
    GLfloat lm_ambient[] = { 0.2, 0.2, 0.2, 1.0 };
    glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
    glMaterialf(GL_FRONT, GL_SHININESS, 50.0);
    glLightfv(GL_LIGHT0, GL_POSITION, light_position);
    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lm_ambient);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glDepthFunc(GL_LESS);
    glEnable(GL_DEPTH_TEST);
    glShadeModel (GL_FLAT);
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glClearAccum(0.0, 0.0, 0.0, 0.0);
}
void displayObjects(void)
{
    GLfloat torus_diffuse[] = { 0.7, 0.7, 0.0, 1.0 };
    GLfloat cube_diffuse[] = { 0.0, 0.7, 0.7, 1.0 };
    GLfloat sphere_diffuse[] = { 0.7, 0.0, 0.7, 1.0 };
    GLfloat octa_diffuse[] = { 0.7, 0.4, 0.4, 1.0 };
    glPushMatrix ();
    glRotatef (30.0, 1.0, 0.0, 0.0);
    glPushMatrix ();
    glTranslatef (-0.80, 0.35, 0.0);
    glRotatef (100.0, 1.0, 0.0, 0.0);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, torus_diffuse);
    auxSolidTorus (0.275, 0.85);
    glPopMatrix ();
    glPushMatrix ();
    glTranslatef (-0.75, -0.50, 0.0);
    glRotatef (45.0, 0.0, 0.0, 1.0);
    glRotatef (45.0, 1.0, 0.0, 0.0);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, cube_diffuse);
    auxSolidCube (1.5);
    glPopMatrix ();
    glPushMatrix ();
    glTranslatef (0.75, 0.60, 0.0);
    glRotatef (30.0, 1.0, 0.0, 0.0);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, sphere_diffuse);
    auxSolidSphere (1.0);
    glPopMatrix ();
    glPushMatrix ();
    glTranslatef (0.70, -0.90, 0.25);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, octa_diffuse);
    auxSolidOctahedron (1.0);
    glPopMatrix ();
    glPopMatrix ();
}
#define ACSIZE  8
void CALLBACK display(void)
{
    GLint viewport[4];
    int jitter;
    glGetIntegerv (GL_VIEWPORT, viewport);
    glClear(GL_ACCUM_BUFFER_BIT);
    for (jitter = 0; jitter < ACSIZE; jitter++) {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glPushMatrix ();
/*  Note that 4.5 is the distance in world space between
 *  left and right and bottom and top.
 *  This formula converts fractional pixel movement to
 *  world coordinates.
 */
        glTranslatef (j8[jitter].x*4.5/viewport[2],
            j8[jitter].y*4.5/viewport[3], 0.0);
        displayObjects ();
        glPopMatrix ();
        glAccum(GL_ACCUM, 1.0/ACSIZE);
    }
    glAccum (GL_RETURN, 1.0);
    glFlush();
}
void CALLBACK myReshape(GLsizei w, GLsizei h)
{
    h = (h == 0) ? 1 : h;
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    if (w <= h)
    glOrtho (-2.25, 2.25, -2.25*h/w, 2.25*h/w, -10.0, 10.0);
    else
    glOrtho (-2.25*w/h, 2.25*w/h, -2.25, 2.25, -10.0, 10.0);
    glMatrixMode(GL_MODELVIEW);
}
/*  Main Loop
 *  Open window with initial window size, title bar,
 *  RGBA display mode, and handle input events.
 */
int main(int argc, char** argv)
{
    auxInitDisplayMode (AUX_SINGLE | AUX_RGB
            | AUX_ACCUM | AUX_DEPTH16);
    auxInitPosition (0, 0, 250, 250);
    auxInitWindow ("Jittering - Orthographic");
    myinit();
    auxReshapeFunc (myReshape);
    auxMainLoop(display);
    return(0);
}


ACCNOT.C  (BOOK Sample)
/*
 * (c) Copyright 1993, Silicon Graphics, Inc.
 *               1993, 1994 Microsoft Corporation
 *
 * ALL RIGHTS RESERVED
 *
 * Please refer to OpenGL/readme.txt for additional information
 *
 */
/*  accnot.c
 */
#include "glos.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>
void myinit(void);
void CALLBACK myReshape(GLsizei w, GLsizei h);
void CALLBACK display(void);
/*  Initialize lighting and other values.
 */
void myinit(void)
{
    GLfloat mat_ambient[] = { 1.0, 1.0, 1.0, 1.0 };
    GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
    GLfloat light_position[] = { 0.0, 0.0, 10.0, 1.0 };
    GLfloat lm_ambient[] = { 0.2, 0.2, 0.2, 1.0 };
    glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
    glMaterialf(GL_FRONT, GL_SHININESS, 50.0);
    glLightfv(GL_LIGHT0, GL_POSITION, light_position);
    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lm_ambient);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glDepthFunc(GL_LESS);
    glEnable(GL_DEPTH_TEST);
}
void CALLBACK display(void)
{
    GLfloat torus_diffuse[] = { 0.7, 0.7, 0.0, 1.0 };
    GLfloat cube_diffuse[] = { 0.0, 0.7, 0.7, 1.0 };
    GLfloat sphere_diffuse[] = { 0.7, 0.0, 0.7, 1.0 };
    GLfloat octa_diffuse[] = { 0.7, 0.4, 0.4, 1.0 };
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glShadeModel (GL_FLAT);
    glPushMatrix ();
    glRotatef (30.0, 1.0, 0.0, 0.0);
    glPushMatrix ();
    glTranslatef (-0.80, 0.35, 0.0);
    glRotatef (100.0, 1.0, 0.0, 0.0);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, torus_diffuse);
    auxSolidTorus (0.275, 0.85);
    glPopMatrix ();
    glPushMatrix ();
    glTranslatef (-0.75, -0.50, 0.0);
    glRotatef (45.0, 0.0, 0.0, 1.0);
    glRotatef (45.0, 1.0, 0.0, 0.0);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, cube_diffuse);
    auxSolidCube (1.5);
    glPopMatrix ();
    glPushMatrix ();
    glTranslatef (0.75, 0.60, 0.0);
    glRotatef (30.0, 1.0, 0.0, 0.0);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, sphere_diffuse);
    auxSolidSphere (1.0);
    glPopMatrix ();
    glPushMatrix ();
    glTranslatef (0.70, -0.90, 0.25);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, octa_diffuse);
    auxSolidOctahedron (1.0);
    glPopMatrix ();
    glPopMatrix ();
    glFlush();
}
void CALLBACK myReshape(GLsizei w, GLsizei h)
{
    h = (h == 0) ? 1 : h;
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    if (w <= h)
        glOrtho (-2.25, 2.25, -2.25*h/w, 2.25*h/w, -10.0, 10.0);
    else
        glOrtho (-2.25*w/h, 2.25*w/h, -2.25, 2.25, -10.0, 10.0);
    glMatrixMode(GL_MODELVIEW);
}
/*  Main Loop
 *  Open window with initial window size, title bar,
 *  RGBA display mode, and handle input events.
 */
int main(int argc, char** argv)
{
    auxInitDisplayMode (AUX_SINGLE | AUX_RGB
            | AUX_ACCUM | AUX_DEPTH16);
    auxInitPosition (0, 0, 250, 250);
    auxInitWindow ("Auxillary 3-D Models");
    myinit();
    auxReshapeFunc (myReshape);
    auxMainLoop(display);
    return(0);
}


ACCPERSP.C  (BOOK Sample)
/*
 * (c) Copyright 1993, Silicon Graphics, Inc.
 *               1993, 1994 Microsoft Corporation
 *
 * ALL RIGHTS RESERVED
 *
 * Please refer to OpenGL/readme.txt for additional information
 *
 */
/*  accpersp.c
 */
#include "glos.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <math.h>
#include <GL/glaux.h>
#include "jitter.h"
void myinit(void);
void accFrustum(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top,
    GLdouble znear, GLdouble zfar, GLdouble pixdx, GLdouble pixdy,
    GLdouble eyedx, GLdouble eyedy, GLdouble focus);
void accPerspective(GLdouble fovy, GLdouble aspect,
    GLdouble znear, GLdouble zfar, GLdouble pixdx, GLdouble pixdy,
    GLdouble eyedx, GLdouble eyedy, GLdouble focus);
void displayObjects(void);
void CALLBACK myReshape(GLsizei w, GLsizei h);
void CALLBACK display(void);
#define PI_ 3.14159265358979323846
/*  accFrustum()
 *  The first 6 arguments are identical to the glFrustum() call.
 *
 *  pixdx and pixdy are anti-alias jitter in pixels.
 *  Set both equal to 0.0 for no anti-alias jitter.
 *  eyedx and eyedy are depth-of field jitter in pixels.
 *  Set both equal to 0.0 for no depth of field effects.
 *
 *  focus is distance from eye to plane in focus.
 *  focus must be greater than, but not equal to 0.0.
 *
 *  Note that accFrustum() calls glTranslatef().  You will
 *  probably want to insure that your ModelView matrix has been
 *  initialized to identity before calling accFrustum().
 */
void accFrustum(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top,
    GLdouble znear, GLdouble zfar, GLdouble pixdx, GLdouble pixdy,
    GLdouble eyedx, GLdouble eyedy, GLdouble focus)
{
    GLdouble xwsize, ywsize;
    GLdouble dx, dy;
    GLint viewport[4];
    glGetIntegerv (GL_VIEWPORT, viewport);
    xwsize = right - left;
    ywsize = top - bottom;
    dx = -(pixdx*xwsize/(GLdouble) viewport[2] + eyedx*znear/focus);
    dy = -(pixdy*ywsize/(GLdouble) viewport[3] + eyedy*znear/focus);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glFrustum (left + dx, right + dx, bottom + dy, top + dy, znear, zfar);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glTranslatef (-eyedx, -eyedy, 0.0);
}
/*  accPerspective()
 *
 *  The first 4 arguments are identical to the gluPerspective() call.
 *  pixdx and pixdy are anti-alias jitter in pixels.
 *  Set both equal to 0.0 for no anti-alias jitter.
 *  eyedx and eyedy are depth-of field jitter in pixels.
 *  Set both equal to 0.0 for no depth of field effects.
 *
 *  focus is distance from eye to plane in focus.
 *  focus must be greater than, but not equal to 0.0.
 *
 *  Note that accPerspective() calls accFrustum().
 */
void accPerspective(GLdouble fovy, GLdouble aspect,
    GLdouble znear, GLdouble zfar, GLdouble pixdx, GLdouble pixdy,
    GLdouble eyedx, GLdouble eyedy, GLdouble focus)
{
    GLdouble fov2,left,right,bottom,top;
    fov2 = ((fovy*PI_) / 180.0) / 2.0;
    top = znear / (cos(fov2) / sin(fov2));
    bottom = -top;
    right = top * aspect;
    left = -right;
    accFrustum (left, right, bottom, top, znear, zfar,
    pixdx, pixdy, eyedx, eyedy, focus);
}
/*  Initialize lighting and other values.
 */
void myinit(void)
{
    GLfloat mat_ambient[] = { 1.0, 1.0, 1.0, 1.0 };
    GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
    GLfloat light_position[] = { 0.0, 0.0, 10.0, 1.0 };
    GLfloat lm_ambient[] = { 0.2, 0.2, 0.2, 1.0 };
    glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
    glMaterialf(GL_FRONT, GL_SHININESS, 50.0);
    glLightfv(GL_LIGHT0, GL_POSITION, light_position);
    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lm_ambient);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glDepthFunc(GL_LESS);
    glEnable(GL_DEPTH_TEST);
    glShadeModel (GL_FLAT);
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glClearAccum(0.0, 0.0, 0.0, 0.0);
}
void displayObjects(void)
{
    GLfloat torus_diffuse[] = { 0.7, 0.7, 0.0, 1.0 };
    GLfloat cube_diffuse[] = { 0.0, 0.7, 0.7, 1.0 };
    GLfloat sphere_diffuse[] = { 0.7, 0.0, 0.7, 1.0 };
    GLfloat octa_diffuse[] = { 0.7, 0.4, 0.4, 1.0 };
    glPushMatrix ();
    glTranslatef (0.0, 0.0, -5.0);
    glRotatef (30.0, 1.0, 0.0, 0.0);
    glPushMatrix ();
    glTranslatef (-0.80, 0.35, 0.0);
    glRotatef (100.0, 1.0, 0.0, 0.0);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, torus_diffuse);
    auxSolidTorus (0.275, 0.85);
    glPopMatrix ();
    glPushMatrix ();
    glTranslatef (-0.75, -0.50, 0.0);
    glRotatef (45.0, 0.0, 0.0, 1.0);
    glRotatef (45.0, 1.0, 0.0, 0.0);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, cube_diffuse);
    auxSolidCube (1.5);
    glPopMatrix ();
    glPushMatrix ();
    glTranslatef (0.75, 0.60, 0.0);
    glRotatef (30.0, 1.0, 0.0, 0.0);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, sphere_diffuse);
    auxSolidSphere (1.0);
    glPopMatrix ();
    glPushMatrix ();
    glTranslatef (0.70, -0.90, 0.25);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, octa_diffuse);
    auxSolidOctahedron (1.0);
    glPopMatrix ();
    glPopMatrix ();
}
#define ACSIZE  8
void CALLBACK display(void)
{
    GLint viewport[4];
    int jitter;
    glGetIntegerv (GL_VIEWPORT, viewport);
    glClear(GL_ACCUM_BUFFER_BIT);
    for (jitter = 0; jitter < ACSIZE; jitter++) {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        accPerspective (50.0,
            (GLdouble) viewport[2]/(GLdouble) viewport[3],
            1.0, 15.0, j8[jitter].x, j8[jitter].y,
            0.0, 0.0, 1.0);
        displayObjects ();
        glAccum(GL_ACCUM, 1.0/ACSIZE);
    }
    glAccum (GL_RETURN, 1.0);
    glFlush();
}
void CALLBACK myReshape(GLsizei w, GLsizei h)
{
    h = (h == 0) ? 1 : h;
    glViewport(0, 0, w, h);
}
/*  Main Loop
 *  Open window with initial window size, title bar,
 *  RGBA display mode, and handle input events.
 */
int main(int argc, char** argv)
{
    auxInitDisplayMode (AUX_SINGLE | AUX_RGB
            | AUX_ACCUM | AUX_DEPTH16);
    auxInitPosition (0, 0, 250, 250);
    auxInitWindow ("Scene Antialiasing");
    myinit();
    auxReshapeFunc (myReshape);
    auxMainLoop(display);
    return(0);
}


ACCUM.C  (BOOK Sample)
/*
 * (c) Copyright 1993, Silicon Graphics, Inc.
 *               1993, 1994 Microsoft Corporation
 *
 * ALL RIGHTS RESERVED
 *
 * Please refer to OpenGL/readme.txt for additional information
 *
 */
/*  accum.c
 */
#include "glos.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>
#include <stdio.h>
void myinit(void);
void loaddxdy(void);
void CALLBACK display(void);
void CALLBACK myReshape(GLsizei w, GLsizei h);
GLsizei width, height;
void myinit(void)
{
    GLfloat ambient[] = { 0.4, 0.4, 0.4, 1.0 };
    GLfloat diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
    GLfloat specular[] = { 1.0, 1.0, 1.0, 1.0 };
    GLfloat position[] = { 0.0, 2.0, 2.0, 0.0 };
    GLfloat mat_ambient[] = { 0.2, 0.2, 0.2, 1.0 };
    GLfloat mat_diffuse[] = { 0.7, 0.7, 0.7, 1.0 };
    GLfloat mat_specular[] = { 0.9, 0.9, 0.9, 1.0 };
    GLfloat mat_shininess[] = { 50.0 };
    GLfloat lmodel_ambient[] = { 0.2, 0.2, 0.2, 1.0 };
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);
    glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
    glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
    glLightfv(GL_LIGHT0, GL_POSITION, position);
    glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
    glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glEnable(GL_AUTO_NORMAL);
    glEnable(GL_NORMALIZE);
    glEnable(GL_CULL_FACE);
    glCullFace(GL_FRONT);
    glClearAccum(0.0, 0.0, 0.0, 0.0);
}
#define ACSIZE 16
GLfloat dx[ACSIZE], dy[ACSIZE];
GLfloat jitter3[3][2] = {
    {0.5, 0.5},
    {1.35899e-05, 0.230369},
    {0.000189185, 0.766878},
};
GLfloat jitter11[11][2] = {
    {0.5, 0.5}, {0.406537, 0.135858},
    {0.860325, 0.968558}, {0.680141, 0.232877},
    {0.775694, 0.584871}, {0.963354, 0.309056},
    {0.593493, 0.864072}, {0.224334, 0.415055},
    {0.0366643, 0.690884}, {0.139685, 0.0313988},
    {0.319861, 0.767097},
};
GLfloat jitter16[16][2] = {
    {0.4375, 0.4375}, {0.1875, 0.5625},
    {0.9375, 1.1875}, {0.4375, 0.9375-1},
    {0.6875, 0.5625}, {0.1875, 0.0625},
    {0.6875, 0.3125}, {0.1875, 0.3125},
    {0.4375, 0.1875}, {0.9375-1, 0.4375},
    {0.6875, 0.8125}, {0.4375, 0.6875},
    {0.6875, 0.0625}, {0.9375, 0.9375},
    {1.1875, 0.8125}, {0.9375, 0.6875},
};
GLfloat jitter29[29][2] = {
    {0.5, 0.5}, {0.498126, 0.141363},
    {0.217276, 0.651732}, {0.439503, 0.954859},
    {0.734171, 0.836294}, {0.912454, 0.79952},
    {0.406153, 0.671156}, {0.0163892, 0.631994},
    {0.298064, 0.843476}, {0.312025, 0.0990405},
    {0.98135, 0.965697}, {0.841999, 0.272378},
    {0.559348, 0.32727}, {0.809331, 0.638901},
    {0.632583, 0.994471}, {0.00588314, 0.146344},
    {0.713365, 0.437896}, {0.185173, 0.246584},
    {0.901735, 0.474544}, {0.366423, 0.296698},
    {0.687032, 0.188184}, {0.313256, 0.472999},
    {0.543195, 0.800044}, {0.629329, 0.631599},
    {0.818263, 0.0439354}, {0.163978, 0.00621497},
    {0.109533, 0.812811}, {0.131325, 0.471624},
    {0.0196755, 0.331813},
};
GLfloat jitter90[90][2] = {
    {0.5, 0.5}, {0.784289, 0.417355},
    {0.608691, 0.678948}, {0.546538, 0.976002},
    {0.972245, 0.270498}, {0.765121, 0.189392},
    {0.513193, 0.743827}, {0.123709, 0.874866},
    {0.991334, 0.745136}, {0.56342, 0.0925047},
    {0.662226, 0.143317}, {0.444563, 0.928535},
    {0.248017, 0.981655}, {0.100115, 0.771923},
    {0.593937, 0.559383}, {0.392095, 0.225932},
    {0.428776, 0.812094}, {0.510615, 0.633584},
    {0.836431, 0.00343328}, {0.494037, 0.391771},
    {0.617448, 0.792324}, {0.688599, 0.48914},
    {0.530421, 0.859206}, {0.0742278, 0.665344},
    {0.979388, 0.626835}, {0.183806, 0.479216},
    {0.151222, 0.0803998}, {0.476489, 0.157863},
    {0.792675, 0.653531}, {0.0990416, 0.267284},
    {0.776667, 0.303894}, {0.312904, 0.296018},
    {0.288777, 0.691008}, {0.460097, 0.0436075},
    {0.594323, 0.440751}, {0.876296, 0.472043},
    {0.0442623, 0.0693901}, {0.355476, 0.00442787},
    {0.391763, 0.361327}, {0.406994, 0.696053},
    {0.708393, 0.724992}, {0.925807, 0.933103},
    {0.850618, 0.11774}, {0.867486, 0.233677},
    {0.208805, 0.285484}, {0.572129, 0.211505},
    {0.172931, 0.180455}, {0.327574, 0.598031},
    {0.685187, 0.372379}, {0.23375, 0.878555},
    {0.960657, 0.409561}, {0.371005, 0.113866},
    {0.29471, 0.496941}, {0.748611, 0.0735321},
    {0.878643, 0.34504}, {0.210987, 0.778228},
    {0.692961, 0.606194}, {0.82152, 0.8893},
    {0.0982095, 0.563104}, {0.214514, 0.581197},
    {0.734262, 0.956545}, {0.881377, 0.583548},
    {0.0560485, 0.174277}, {0.0729515, 0.458003},
    {0.719604, 0.840564}, {0.325388, 0.7883},
    {0.26136, 0.0848927}, {0.393754, 0.467505},
    {0.425361, 0.577672}, {0.648594, 0.0248658},
    {0.983843, 0.521048}, {0.272936, 0.395127},
    {0.177695, 0.675733}, {0.89175, 0.700901},
    {0.632301, 0.908259}, {0.782859, 0.53611},
    {0.0141421, 0.855548}, {0.0437116, 0.351866},
    {0.939604, 0.0450863}, {0.0320883, 0.962943},
    {0.341155, 0.895317}, {0.952087, 0.158387},
    {0.908415, 0.820054}, {0.481435, 0.281195},
    {0.675525, 0.25699}, {0.585273, 0.324454},
    {0.156488, 0.376783}, {0.140434, 0.977416},
    {0.808155, 0.77305}, {0.282973, 0.188937},
};
void loaddxdy(void)
{
    long i;
    for (i = 0; i < ACSIZE; i++) {
        dx[i] = jitter16[i][0]*10/width;
        dy[i] = jitter16[i][1]*10/height;
    }
}
void CALLBACK display(void)
{
    int i;
    glClear(GL_ACCUM_BUFFER_BIT);
    loaddxdy();
    for (i = 0; i < (ACSIZE); i++) {
        //printf("Pass %d\n", i);
        glPushMatrix();
        glTranslatef(dx[i], dy[i], 0.0);
        glRotatef(45.0, 1.0, 1.0, 1.0);
        glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
        auxSolidTeapot(1.0);
        glPopMatrix();
        glAccum(GL_ACCUM, 1.0/(ACSIZE));
    }
    //printf("final job\n");
    glAccum(GL_RETURN, 1.0);
    //printf("done\n");
    glFlush();
}
void CALLBACK myReshape(GLsizei w, GLsizei h)
{
    h = (h == 0) ? 1 : h;
    width = w; height = h;
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    if (w <= h)
        glOrtho(-3.0, 3.0, -3.0*(GLfloat) h/(GLfloat) w,
                3.0*(GLfloat) h/(GLfloat) w, -15.0, 15.0);
    else
        glOrtho(-3.0*(GLfloat) w/(GLfloat) h,
                3.0*(GLfloat) w/(GLfloat) h, -3.0, 3.0, -15.0, 15.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}
int main(int argc, char** argv)
{
    auxInitDisplayMode (AUX_SINGLE | AUX_RGB
            | AUX_ACCUM | AUX_DEPTH16);
    auxInitPosition (0, 0, 300, 300);
    auxInitWindow ("Accumulation Buffer");
    myinit();
    auxReshapeFunc (myReshape);
    auxMainLoop(display);
    return(0);
}


AIM.C  (BOOK Sample)
/*
 * (c) Copyright 1993, Silicon Graphics, Inc.
 *               1993, 1994 Microsoft Corporation
 *
 * ALL RIGHTS RESERVED
 *
 * Please refer to OpenGL/readme.txt for additional information
 *
 */
/*
 *  aim.c
 *  This program calculates the fovy (field of view angle
 *  in the y direction), by using trigonometry, given the
 *  size of an object and its size.
 */
#include "glos.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <math.h>
#include <GL/glaux.h>
#include <stdio.h>
void myinit(void);
GLdouble calculateAngle (double size, double distance);
void CALLBACK display(void);
void CALLBACK myReshape(GLsizei w, GLsizei h);
void myinit (void) {
    glShadeModel (GL_FLAT);
}
/*  Clear the screen.  Set the current color to white.
 *  Draw the wire frame cube and sphere.
 */
void CALLBACK display (void)
{
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3f (1.0, 1.0, 1.0);
    glLoadIdentity ();
/*  glTranslatef() as viewing transformation    */
    glTranslatef (0.0, 0.0, -5.0);
    auxWireCube(2.0);
    auxWireSphere(1.0);
    glFlush();
}
#define PI  3.1415926535
/*  atan2 () is a system math routine which calculates
 *  the arctangent of an angle, given length of the
 *  opposite and adjacent sides of a right triangle.
 *  atan2 () is not an OpenGL routine.
 */
GLdouble calculateAngle (double size, double distance)
{
    GLdouble radtheta, degtheta;
    radtheta = 2.0 * atan2 (size/2.0, distance);
    degtheta = (180.0 * radtheta) / PI;
    //printf ("degtheta is %lf\n", degtheta);
    return ((GLdouble) degtheta);
}
/*  Called when the window is first opened and whenever
 *  the window is reconfigured (moved or resized).
 */
void CALLBACK myReshape(GLsizei w, GLsizei h)
{
    GLdouble theta;
    h = (h == 0) ? 1 : h;
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    theta = calculateAngle (2.0, 5.0);
    gluPerspective(theta, (GLfloat) w/(GLfloat) h, 1.0, 20.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}
/*  Main Loop
 *  Open window with initial window size, title bar,
 *  RGBA display mode, and handle input events.
 */
int main(int argc, char** argv)
{
    auxInitDisplayMode (AUX_SINGLE | AUX_RGB);
    auxInitPosition (0, 0, 500, 500);
    auxInitWindow ("Field of View Angle");
    myinit ();
    auxReshapeFunc (myReshape);
    auxMainLoop(display);
    return(0);
}


ALPHA.C  (BOOK Sample)
/*
 * (c) Copyright 1993, Silicon Graphics, Inc.
 *               1993, 1994 Microsoft Corporation
 *
 * ALL RIGHTS RESERVED
 *
 * Please refer to OpenGL/readme.txt for additional information
 *
 */
/*
 *  alpha.c
 *  This program draws several overlapping filled polygons
 *  to demonstrate the effect order has on alpha blending results.
 */
#include "glos.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>
void myinit(void);
void CALLBACK myReshape(GLsizei w, GLsizei h);
void CALLBACK display(void);
/*  Initialize alpha blending function.
 */
void myinit(void)
{
    glEnable (GL_BLEND);
    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glShadeModel (GL_FLAT);
    glClearColor (0.0, 0.0, 0.0, 0.0);
}
void CALLBACK display(void)
{
    glClear(GL_COLOR_BUFFER_BIT);
    glColor4f (1.0, 1.0, 0.0, 0.75);
    glRectf (0.0, 0.0, 0.5, 1.0);
    glColor4f (0.0, 1.0, 1.0, 0.75);
    glRectf (0.0, 0.0, 1.0, 0.5);
/*  draw colored polygons in reverse order in upper right  */
    glColor4f (0.0, 1.0, 1.0, 0.75);
    glRectf (0.5, 0.5, 1.0, 1.0);
    glColor4f (1.0, 1.0, 0.0, 0.75);
    glRectf (0.5, 0.5, 1.0, 1.0);
    glFlush();
}
void CALLBACK myReshape(GLsizei w, GLsizei h)
{
    h = (h == 0) ? 1 : h;
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    if (w <= h)
    gluOrtho2D (0.0, 1.0, 0.0, 1.0*(GLfloat)h/(GLfloat)w);
    else
    gluOrtho2D (0.0, 1.0*(GLfloat)w/(GLfloat)h, 0.0, 1.0);
    glMatrixMode(GL_MODELVIEW);
}
/*  Main Loop
 *  Open window with initial window size, title bar,
 *  RGBA display mode, and handle input events.
 */
int main(int argc, char** argv)
{
    auxInitDisplayMode (AUX_SINGLE | AUX_RGB);
    auxInitPosition (0, 0, 500, 500);
    auxInitWindow ("Alpha Blending");
    myinit();
    auxReshapeFunc (myReshape);
    auxMainLoop(display);
    return(0);
}


ALPHA3D.C  (BOOK Sample)
/*
 * (c) Copyright 1993, Silicon Graphics, Inc.
 *               1993, 1994 Microsoft Corporation
 *
 * ALL RIGHTS RESERVED
 *
 * Please refer to OpenGL/readme.txt for additional information
 *
 */
/*
 *  alpha3D.c
 *  This program demonstrates how to intermix opaque and
 *  alpha blended polygons in the same scene, by using glDepthMask.
 *  Pressing the left mouse button toggles the eye position.
 */
#include "glos.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>
void myinit(void);
void CALLBACK toggleEye (AUX_EVENTREC *event);
void CALLBACK myReshape(GLsizei w, GLsizei h);
void CALLBACK display(void);
void myinit(void)
{
    GLfloat mat_ambient[] = { 0.0, 0.0, 0.0, 0.15 };
    GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 0.15 };
    GLfloat mat_shininess[] = { 15.0 };
    glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
    glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
    glEnable (GL_LIGHTING);
    glEnable (GL_LIGHT0);
    glDepthFunc(GL_LESS);
    glEnable(GL_DEPTH_TEST);
}
GLboolean eyePosition = GL_FALSE;
void CALLBACK toggleEye (AUX_EVENTREC *event)
{
    if (eyePosition)
    eyePosition = GL_FALSE;
    else
    eyePosition = GL_TRUE;
}
void CALLBACK display(void)
{
    GLfloat position[] = { 0.0, 0.0, 1.0, 1.0 };
    GLfloat mat_torus[] = { 0.75, 0.75, 0.0, 1.0 };
    GLfloat mat_cylinder[] = { 0.0, 0.75, 0.75, 0.15 };
    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLightfv (GL_LIGHT0, GL_POSITION, position);
    glPushMatrix ();
    if (eyePosition)
        gluLookAt (0.0, 0.0, 9.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
    else
        gluLookAt (0.0, 0.0, -9.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
    glPushMatrix ();
    glTranslatef (0.0, 0.0, 1.0);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_torus);
    auxSolidTorus (0.275, 0.85);
    glPopMatrix ();
    glEnable (GL_BLEND);
    glDepthMask (GL_FALSE);
    glBlendFunc (GL_SRC_ALPHA, GL_ONE);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_cylinder);
    glTranslatef (0.0, 0.0, -1.0);
    auxSolidCylinder (1.0, 2.0);
    glDepthMask (GL_TRUE);
    glDisable (GL_BLEND);
    glPopMatrix ();
    glFlush ();
}
void CALLBACK myReshape(GLsizei w, GLsizei h)
{
    h = (h == 0) ? 1 : h;
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(30.0, (GLfloat) w/(GLfloat) h, 1.0, 20.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}
/*  Main Loop
 *  Open window with initial window size, title bar,
 *  RGBA display mode, and handle input events.
 */
int main(int argc, char** argv)
{
    auxInitDisplayMode (AUX_SINGLE | AUX_RGB | AUX_DEPTH16);
    auxInitPosition (0, 0, 500, 500);
    auxInitWindow ("Intermixing Opaque and Alpha Blending");
    auxMouseFunc (AUX_LEFTBUTTON, AUX_MOUSEDOWN, toggleEye);
    myinit();
    auxReshapeFunc (myReshape);
    auxMainLoop(display);
    return(0);
}


ANTI.C  (BOOK Sample)
/*
 * (c) Copyright 1993, Silicon Graphics, Inc.
 *               1993, 1994 Microsoft Corporation
 *
 * ALL RIGHTS RESERVED
 *
 * Please refer to OpenGL/readme.txt for additional information
 *
 */
/*
 *  anti.c
 *  This program draws antialiased lines in RGBA mode.
 */
#include "glos.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>
#include <stdio.h>
void myinit(void);
void CALLBACK myReshape(GLsizei w, GLsizei h);
void CALLBACK display(void);
/*  Initialize antialiasing for RGBA mode, including alpha
 *  blending, hint, and line width.  Print out implementation
 *  specific info on line width granularity and width.
 */
void myinit(void)
{
    GLfloat values[2];
    glGetFloatv (GL_LINE_WIDTH_GRANULARITY, values);
    //printf ("GL_LINE_WIDTH_GRANULARITY value is %3.1f\n", values[0]);
    glGetFloatv (GL_LINE_WIDTH_RANGE, values);
    //printf ("GL_LINE_WIDTH_RANGE values are %3.1f %3.1f\n",
    //values[0], values[1]);
    glEnable (GL_LINE_SMOOTH);
    glEnable (GL_BLEND);
    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glHint (GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
    glLineWidth (1.5);
    glShadeModel(GL_FLAT);
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glDepthFunc(GL_LESS);
    glEnable(GL_DEPTH_TEST);
}
/*  display() draws an icosahedron with a large alpha value, 1.0.
 */
void CALLBACK display(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glColor4f (1.0, 1.0, 1.0, 1.0);
    auxWireIcosahedron(1.0);
    glFlush();
}
void CALLBACK myReshape(GLsizei w, GLsizei h)
{
    h = (h == 0) ? 1 : h;
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective (45.0, (GLfloat) w/(GLfloat) h, 3.0, 5.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity ();
    glTranslatef (0.0, 0.0, -4.0);  /*  move object into view   */
}
/*  Main Loop
 *  Open window with initial window size, title bar,
 *  RGBA display mode, and handle input events.
 */
int main(int argc, char** argv)
{
    auxInitDisplayMode (AUX_SINGLE | AUX_RGB | AUX_DEPTH16);
    auxInitPosition (0, 0, 400, 400);
    auxInitWindow ("Antialiased Lines Using RGBA");
    myinit();
    auxReshapeFunc (myReshape);
    auxMainLoop(display);
    return(0);
}


ANTINDX.C  (BOOK Sample)
/*
 * (c) Copyright 1993, Silicon Graphics, Inc.
 *               1993, 1994 Microsoft Corporation
 *
 * ALL RIGHTS RESERVED
 *
 * Please refer to OpenGL/readme.txt for additional information
 *
 */
/*
 *  antiindex.c
 *  The program draws a wireframe icosahedron with
 *  antialiased lines, in color index mode.
 */
#include "glos.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>
void myinit(void);
void CALLBACK myReshape(GLsizei w, GLsizei h);
void CALLBACK display(void);
#define RAMPSIZE 16
#define RAMPSTART 32
/*  Initialize antialiasing for color index mode,
 *  including loading a grey color ramp starting
 *  at RAMPSTART, which must be a multiple of 16.
 */
void myinit(void)
{
    int i;
    for (i = 0; i < RAMPSIZE; i++) {
    GLfloat shade;
    shade = (GLfloat) i/(GLfloat) RAMPSIZE;
    auxSetOneColor(RAMPSTART+(GLint)i, shade, shade, shade);
    }
    glEnable (GL_LINE_SMOOTH);
    glHint (GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
    glLineWidth (1.5);
    glClearIndex ((GLfloat) RAMPSTART);
    glShadeModel(GL_FLAT);
    glDepthFunc(GL_LESS);
    glEnable(GL_DEPTH_TEST);
}
/*  display() draws an icosahedron.
 */
void CALLBACK display(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glIndexi(RAMPSTART);
    auxWireIcosahedron(1.0);
    glFlush();
}
void CALLBACK myReshape(GLsizei w, GLsizei h)
{
    h = (h == 0) ? 1 : h;
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective (45.0, (GLfloat) w/(GLfloat) h, 3.0, 5.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity ();
    glTranslatef (0.0, 0.0, -4.0);  /*  move object into view   */
}
/*  Main Loop
 *  Open window with initial window size, title bar,
 *  color index display mode, depth buffer,
 *  and handle input events.
 */
int main(int argc, char** argv)
{
    auxInitDisplayMode (AUX_SINGLE | AUX_INDEX | AUX_DEPTH16);
    auxInitPosition (0, 0, 400, 400);
    auxInitWindow ("Antialiased Lines Using Color Index");
    myinit();
    auxReshapeFunc (myReshape);
    auxMainLoop(display);
    return(0);
}


ANTIPNDX.C  (BOOK Sample)
/*
 * (c) Copyright 1993, Silicon Graphics, Inc.
 *               1993, 1994 Microsoft Corporation
 *
 * ALL RIGHTS RESERVED
 *
 * Please refer to OpenGL/readme.txt for additional information
 *
 */
/*
 *  antipindex.c
 *  The program draws antialiased points,
 *  in color index mode.
 */
#include "glos.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>
void myinit(void);
void CALLBACK myReshape(GLsizei w, GLsizei h);
void CALLBACK display(void);
#define RAMPSIZE 16
#define RAMPSTART 32
/*  Initialize point antialiasing for color index mode,
 *  including loading a grey color ramp starting at
 *  RAMPSTART, which must be a multiple of 16.
 */
void myinit(void)
{
    int i;
    for (i = 0; i < RAMPSIZE; i++) {
    GLfloat shade;
    shade = (GLfloat) i/(GLfloat) RAMPSIZE;
    auxSetOneColor (RAMPSTART+(GLint)i, shade, shade, shade);
    }
    glEnable (GL_POINT_SMOOTH);
    glHint (GL_POINT_SMOOTH_HINT, GL_FASTEST);
    glPointSize (3.0);
    glClearIndex ((GLfloat) RAMPSTART);
}
/*  display() draws several points.  */
void CALLBACK display(void)
{
    int i;
    glClear(GL_COLOR_BUFFER_BIT);
    glIndexi (RAMPSTART);
    glBegin (GL_POINTS);
    for (i = 1; i < 10; i++) {
        glVertex2f ((GLfloat) i * 10.0, (GLfloat) i * 10.0);
    }
    glEnd ();
    glFlush();
}
void CALLBACK myReshape(GLsizei w, GLsizei h)
{
    h = (h == 0) ? 1 : h;
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    if (w < h)
    glOrtho (0.0, 100.0, 0.0,
        100.0*(GLfloat) h/(GLfloat) w, -1.0, 1.0);
    else
    glOrtho (0.0, 100.0*(GLfloat) w/(GLfloat) h,
        0.0, 100.0, -1.0, 1.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity ();
}
/*  Main Loop
 *  Open window with initial window size, title bar,
 *  color index display mode, and handle input events.
 */
int main(int argc, char** argv)
{
    auxInitDisplayMode (AUX_SINGLE | AUX_INDEX);
    auxInitPosition (0, 0, 100, 100);
    auxInitWindow ("Points");
    myinit();
    auxReshapeFunc (myReshape);
    auxMainLoop(display);
    return(0);
}


ANTIPNT.C  (BOOK Sample)
/*
 * (c) Copyright 1993, Silicon Graphics, Inc.
 *               1993, 1994 Microsoft Corporation
 *
 * ALL RIGHTS RESERVED
 *
 * Please refer to OpenGL/readme.txt for additional information
 *
 */
/*
 *  antipoint.c
 *  The program draws antialiased points, in RGBA mode.
 */
#include "glos.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>
void myinit(void);
void CALLBACK myReshape(GLsizei w, GLsizei h);
void CALLBACK display(void);
/*  Initialize point anti-aliasing for RGBA mode, including alpha
 *  blending, hint, and point size.  These points are 3.0 pixels big.
 */
void myinit(void)
{
    glEnable (GL_POINT_SMOOTH);
    glEnable (GL_BLEND);
    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glHint (GL_POINT_SMOOTH_HINT, GL_DONT_CARE);
    glPointSize (3.0);
    glClearColor(0.0, 0.0, 0.0, 0.0);
}
/*  display() draws several points.
 */
void CALLBACK display(void)
{
    int i;
    glClear (GL_COLOR_BUFFER_BIT);
    glColor4f (1.0, 1.0, 1.0, 1.0);
    glBegin (GL_POINTS);
    for (i = 1; i < 10; i++) {
        glVertex2f ((GLfloat) i * 10.0, (GLfloat) i * 10.0);
    }
    glEnd ();
    glFlush();
}
void CALLBACK myReshape(GLsizei w, GLsizei h)
{
    h = (h == 0) ? 1 : h;
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    if (w < h)
    glOrtho (0.0, 100.0,
        0.0, 100.0*(GLfloat) h/(GLfloat) w, -1.0, 1.0);
    else
    glOrtho (0.0, 100.0*(GLfloat) w/(GLfloat) h,
        0.0, 100.0, -1.0, 1.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity ();
}
/*  Main Loop
 *  Open window with initial window size, title bar,
 *  RGBA display mode, and handle input events.
 */
int main(int argc, char** argv)
{
    auxInitDisplayMode (AUX_SINGLE | AUX_RGB);
    auxInitPosition (0, 0, 100, 100);
    auxInitWindow ("Points");
    myinit();
    auxReshapeFunc (myReshape);
    auxMainLoop(display);
    return(0);
}


ANTIPOLY.C  (BOOK Sample)
/*
 * (c) Copyright 1993, Silicon Graphics, Inc.
 *               1993, 1994 Microsoft Corporation
 *
 * ALL RIGHTS RESERVED
 *
 * Please refer to OpenGL/readme.txt for additional information
 *
 */
/*
 *  antipoly.c
 *  This program draws filled polygons with antialiased
 *  edges.  The special GL_SRC_ALPHA_SATURATE blending
 *  function is used.
 *  Pressing the left mouse button turns the antialiasing
 *  on and off.
 */
#include "glos.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>
void myinit(void);
void CALLBACK toggleSmooth (AUX_EVENTREC *event);
void CALLBACK myReshape(GLsizei w, GLsizei h);
void CALLBACK display(void);
GLboolean polySmooth;
void myinit(void)
{
    GLfloat mat_ambient[] = { 0.0, 0.0, 0.0, 1.00 };
    GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.00 };
    GLfloat mat_shininess[] = { 15.0 };
    glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
    glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
    glEnable (GL_LIGHTING);
    glEnable (GL_LIGHT0);
    glEnable (GL_BLEND);
    glCullFace (GL_BACK);
    glEnable (GL_CULL_FACE);
    glEnable (GL_POLYGON_SMOOTH);
    polySmooth = GL_TRUE;
    glClearColor (0.0, 0.0, 0.0, 0.0);
}
void CALLBACK toggleSmooth (AUX_EVENTREC *event)
{
    if (polySmooth) {
    polySmooth = GL_FALSE;
    glDisable (GL_BLEND);
    glDisable (GL_POLYGON_SMOOTH);
    glEnable (GL_DEPTH_TEST);
    }
    else {
    polySmooth = GL_TRUE;
    glEnable (GL_BLEND);
    glEnable (GL_POLYGON_SMOOTH);
    glDisable (GL_DEPTH_TEST);
    }
}
/*  Note:  polygons must be drawn from back to front
 *  for proper blending.
 */
void CALLBACK display(void)
{
    GLfloat position[] = { 0.0, 0.0, 1.0, 0.0 };
    GLfloat mat_cube1[] = { 0.75, 0.75, 0.0, 1.0 };
    GLfloat mat_cube2[] = { 0.0, 0.75, 0.75, 1.0 };
    if (polySmooth)
    glClear (GL_COLOR_BUFFER_BIT);
    else
    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glPushMatrix ();
    glTranslatef (0.0, 0.0, -8.0);
    glLightfv (GL_LIGHT0, GL_POSITION, position);
    glBlendFunc (GL_SRC_ALPHA_SATURATE, GL_ONE);
    glPushMatrix ();
    glRotatef (30.0, 1.0, 0.0, 0.0);
    glRotatef (60.0, 0.0, 1.0, 0.0);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_cube1);
    auxSolidCube (1.0);
    glPopMatrix ();
    glTranslatef (0.0, 0.0, -2.0);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_cube2);
    glRotatef (30.0, 0.0, 1.0, 0.0);
    glRotatef (60.0, 1.0, 0.0, 0.0);
    auxSolidCube (1.0);
    glPopMatrix ();
    glFlush ();
}
void CALLBACK myReshape(GLsizei w, GLsizei h)
{
    h = (h == 0) ? 1 : h;
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(30.0, (GLfloat) w/(GLfloat) h, 1.0, 20.0);
    glMatrixMode(GL_MODELVIEW);
}
/*  Main Loop
 */
int main(int argc, char** argv)
{
    auxInitDisplayMode (AUX_SINGLE | AUX_RGB | AUX_ALPHA | AUX_DEPTH16);
    auxInitPosition (0, 0, 200, 200);
    auxInitWindow ("Antialiased Edges");
    auxMouseFunc (AUX_LEFTBUTTON, AUX_MOUSEDOWN, toggleSmooth);
    myinit();
    auxReshapeFunc (myReshape);
    auxMainLoop(display);
    return(0);
}


BEZCURVE.C  (BOOK Sample)
/*
 * (c) Copyright 1993, Silicon Graphics, Inc.
 *               1993, 1994 Microsoft Corporation
 *
 * ALL RIGHTS RESERVED
 *
 * Please refer to OpenGL/readme.txt for additional information
 *
 */
/*  bezcurve.c
 *  This program uses evaluators to draw a Bezier curve.
 */
#include "glos.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>
void myinit(void);
void CALLBACK myReshape(GLsizei w, GLsizei h);
void CALLBACK display(void);
GLfloat ctrlpoints[4][3] = {
    { -4.0, -4.0, 0.0}, { -2.0, 4.0, 0.0},
    {2.0, -4.0, 0.0}, {4.0, 4.0, 0.0}};
void myinit(void)
{
    glClearColor(0.0, 0.0, 0.0, 1.0);
    glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, &ctrlpoints[0][0]);
    glEnable(GL_MAP1_VERTEX_3);
    glShadeModel(GL_FLAT);
}
void CALLBACK display(void)
{
    int i;
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3f(1.0, 1.0, 1.0);
    glBegin(GL_LINE_STRIP);
    for (i = 0; i <= 30; i++)
        glEvalCoord1f((GLfloat) i/30.0);
    glEnd();
    /* The following code displays the control points as dots. */
    glPointSize(5.0);
    glColor3f(1.0, 1.0, 0.0);
    glBegin(GL_POINTS);
    for (i = 0; i < 4; i++)
        glVertex3fv(&ctrlpoints[i][0]);
    glEnd();
    glFlush();
}
void CALLBACK myReshape(GLsizei w, GLsizei h)
{
    h = (h == 0) ? 1 : h;
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    if (w <= h)
    glOrtho(-5.0, 5.0, -5.0*(GLfloat)h/(GLfloat)w,
        5.0*(GLfloat)h/(GLfloat)w, -5.0, 5.0);
    else
    glOrtho(-5.0*(GLfloat)w/(GLfloat)h,
        5.0*(GLfloat)w/(GLfloat)h, -5.0, 5.0, -5.0, 5.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}
int main(int argc, char** argv)
{
    auxInitDisplayMode (AUX_SINGLE | AUX_RGB);
    auxInitPosition (0, 0, 500, 500);
    auxInitWindow ("Bezier Curves Using Evaluators");
    myinit();
    auxReshapeFunc (myReshape);
    auxMainLoop(display);
    return(0);
}


BEZMESH.C  (BOOK Sample)
/*
 * (c) Copyright 1993, Silicon Graphics, Inc.
 *               1993, 1994 Microsoft Corporation
 *
 * ALL RIGHTS RESERVED
 *
 * Please refer to OpenGL/readme.txt for additional information
 *
 */
/*  bezsurf.c
 *  This program renders a lighted, filled Bezier surface,
 *  using two-dimensional evaluators.
 */
#include "glos.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>
void myinit(void);
void initlights(void);
void CALLBACK myReshape(GLsizei w, GLsizei h);
void CALLBACK display(void);
GLfloat ctrlpoints[4][4][3] = {
    {{-1.5, -1.5, 4.0}, {-0.5, -1.5, 2.0},
    {0.5, -1.5, -1.0}, {1.5, -1.5, 2.0}},
    {{-1.5, -0.5, 1.0}, {-0.5, -0.5, 3.0},
    {0.5, -0.5, 0.0}, {1.5, -0.5, -1.0}},
    {{-1.5, 0.5, 4.0}, {-0.5, 0.5, 0.0},
    {0.5, 0.5, 3.0}, {1.5, 0.5, 4.0}},
    {{-1.5, 1.5, -2.0}, {-0.5, 1.5, -2.0},
    {0.5, 1.5, 0.0}, {1.5, 1.5, -1.0}}
};
void initlights(void)
{
    GLfloat ambient[] = { 0.2, 0.2, 0.2, 1.0 };
    GLfloat position[] = { 0.0, 0.0, 2.0, 1.0 };
    GLfloat mat_diffuse[] = { 0.6, 0.6, 0.6, 1.0 };
    GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
    GLfloat mat_shininess[] = { 50.0 };
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
    glLightfv(GL_LIGHT0, GL_POSITION, position);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
    glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
}
void CALLBACK display(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glPushMatrix();
    glRotatef(85.0, 1.0, 1.0, 1.0);
    glEvalMesh2(GL_FILL, 0, 20, 0, 20);
    glPopMatrix();
    glFlush();
}
void myinit(void)
{
    glClearColor (0.0, 0.0, 0.0, 1.0);
    glEnable (GL_DEPTH_TEST);
    glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4,
        0, 1, 12, 4, &ctrlpoints[0][0][0]);
    glEnable(GL_MAP2_VERTEX_3);
    glEnable(GL_AUTO_NORMAL);
    glEnable(GL_NORMALIZE);
    glMapGrid2f(20, 0.0, 1.0, 20, 0.0, 1.0);
    initlights();   /* for lighted version only */
}
void CALLBACK myReshape(GLsizei w, GLsizei h)
{
    h = (h == 0) ? 1 : h;
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    if (w <= h)
    glOrtho(-4.0, 4.0, -4.0*(GLfloat)h/(GLfloat)w,
        4.0*(GLfloat)h/(GLfloat)w, -4.0, 4.0);
    else
    glOrtho(-4.0*(GLfloat)w/(GLfloat)h,
        4.0*(GLfloat)w/(GLfloat)h, -4.0, 4.0, -4.0, 4.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}
int main(int argc, char** argv)
{
    auxInitDisplayMode (AUX_SINGLE | AUX_RGB | AUX_DEPTH16);
    auxInitPosition (0, 0, 500, 500);
    auxInitWindow ("Lighted and Filled Bezier Surface");
    myinit();
    auxReshapeFunc (myReshape);
    auxMainLoop(display);
    return(0);
}


BEZSURF.C  (BOOK Sample)
/*
 * (c) Copyright 1993, Silicon Graphics, Inc.
 *               1993, 1994 Microsoft Corporation
 *
 * ALL RIGHTS RESERVED
 *
 * Please refer to OpenGL/readme.txt for additional information
 *
 */
/*  bezmesh.c
 *  This program renders a wireframe Bezier surface,
 *  using two-dimensional evaluators.
 */
#include "glos.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>
void myinit(void);
void CALLBACK myReshape(GLsizei w, GLsizei h);
void CALLBACK display(void);
GLfloat ctrlpoints[4][4][3] = {
    {{-1.5, -1.5, 4.0}, {-0.5, -1.5, 2.0},
{0.5, -1.5, -1.0}, {1.5, -1.5, 2.0}},
    {{-1.5, -0.5, 1.0}, {-0.5, -0.5, 3.0},
{0.5, -0.5, 0.0}, {1.5, -0.5, -1.0}},
    {{-1.5, 0.5, 4.0}, {-0.5, 0.5, 0.0},
{0.5, 0.5, 3.0}, {1.5, 0.5, 4.0}},
    {{-1.5, 1.5, -2.0}, {-0.5, 1.5, -2.0},
{0.5, 1.5, 0.0}, {1.5, 1.5, -1.0}}
};
void CALLBACK display(void)
{
    int i, j;
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glColor3f(1.0, 1.0, 1.0);
    glPushMatrix ();
    glRotatef(85.0, 1.0, 1.0, 1.0);
    for (j = 0; j <= 8; j++) {
glBegin(GL_LINE_STRIP);
        for (i = 0; i <= 30; i++)
    glEvalCoord2f((GLfloat)i/30.0, (GLfloat)j/8.0);
glEnd();
glBegin(GL_LINE_STRIP);
        for (i = 0; i <= 30; i++)
    glEvalCoord2f((GLfloat)j/8.0, (GLfloat)i/30.0);
glEnd();
    }
    glPopMatrix ();
    glFlush();
}
void myinit(void)
{
    glClearColor (0.0, 0.0, 0.0, 1.0);
    glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4,
    0, 1, 12, 4, &ctrlpoints[0][0][0]);
    glEnable(GL_MAP2_VERTEX_3);
    glMapGrid2f(20, 0.0, 1.0, 20, 0.0, 1.0);
    glEnable(GL_DEPTH_TEST);
    glShadeModel(GL_FLAT);
}
void CALLBACK myReshape(GLsizei w, GLsizei h)
{
    h = (h == 0) ? 1 : h;
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    if (w <= h)
glOrtho(-4.0, 4.0, -4.0*(GLfloat)h/(GLfloat)w,
    4.0*(GLfloat)h/(GLfloat)w, -4.0, 4.0);
    else
glOrtho(-4.0*(GLfloat)w/(GLfloat)h,
    4.0*(GLfloat)w/(GLfloat)h, -4.0, 4.0, -4.0, 4.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}
int main(int argc, char** argv)
{
    auxInitDisplayMode (AUX_SINGLE | AUX_RGB | AUX_DEPTH16);
    auxInitPosition (0, 0, 500, 500);
    auxInitWindow ("Wireframe Bezier Surface");
    myinit();
    auxReshapeFunc (myReshape);
    auxMainLoop(display);
    return(0);
}


CHECKER.C  (BOOK Sample)
/*
 * (c) Copyright 1993, Silicon Graphics, Inc.
 *               1993, 1994 Microsoft Corporation
 *
 * ALL RIGHTS RESERVED
 *
 * Please refer to OpenGL/readme.txt for additional information
 *
 */
/*  checker.c
 *  This program texture maps a checkerboard image onto
 *  two rectangles.  This program clamps the texture, if
 *  the texture coordinates fall outside 0.0 and 1.0.
 */
#include "glos.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>
void myinit(void);
void makeCheckImage(void);
void CALLBACK myReshape(GLsizei w, GLsizei h);
void CALLBACK display(void);
/*  Create checkerboard texture */
#define checkImageWidth 64
#define checkImageHeight 64
GLubyte checkImage[checkImageWidth][checkImageHeight][3];
void makeCheckImage(void)
{
    int i, j, c;
    for (i = 0; i < checkImageWidth; i++) {
    for (j = 0; j < checkImageHeight; j++) {
        c = ((((i&0x8)==0)^((j&0x8))==0))*255;
        checkImage[i][j][0] = (GLubyte) c;
        checkImage[i][j][1] = (GLubyte) c;
        checkImage[i][j][2] = (GLubyte) c;
    }
    }
}
void myinit(void)
{
    glClearColor (0.0, 0.0, 0.0, 0.0);
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);
    makeCheckImage();
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glTexImage2D(GL_TEXTURE_2D, 0, 3, checkImageWidth,
    checkImageHeight, 0, GL_RGB, GL_UNSIGNED_BYTE,
    &checkImage[0][0][0]);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
    glEnable(GL_TEXTURE_2D);
    glShadeModel(GL_FLAT);
}
void CALLBACK display(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glBegin(GL_QUADS);
    glTexCoord2f(0.0, 0.0); glVertex3f(-2.0, -1.0, 0.0);
    glTexCoord2f(0.0, 1.0); glVertex3f(-2.0, 1.0, 0.0);
    glTexCoord2f(1.0, 1.0); glVertex3f(0.0, 1.0, 0.0);
    glTexCoord2f(1.0, 0.0); glVertex3f(0.0, -1.0, 0.0);
    glTexCoord2f(0.0, 0.0); glVertex3f(1.0, -1.0, 0.0);
    glTexCoord2f(0.0, 1.0); glVertex3f(1.0, 1.0, 0.0);
    glTexCoord2f(1.0, 1.0); glVertex3f(2.41421, 1.0, -1.41421);
    glTexCoord2f(1.0, 0.0); glVertex3f(2.41421, -1.0, -1.41421);
    glEnd();
    glFlush();
}
void CALLBACK myReshape(GLsizei w, GLsizei h)
{
    h = (h == 0) ? 1 : h;
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(60.0, 1.0*(GLfloat)w/(GLfloat)h, 1.0, 30.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glTranslatef(0.0, 0.0, -3.6);
}
int main(int argc, char** argv)
{
    auxInitDisplayMode (AUX_SINGLE | AUX_RGB | AUX_DEPTH16);
    auxInitPosition (0, 0, 500, 500);
    auxInitWindow ("Texture Map");
    myinit();
    auxReshapeFunc (myReshape);
    auxMainLoop(display);
    return(0);
}


CHECKER2.C  (BOOK Sample)
/*
 * (c) Copyright 1993, Silicon Graphics, Inc.
 *               1993, 1994 Microsoft Corporation
 *
 * ALL RIGHTS RESERVED
 *
 * Please refer to OpenGL/readme.txt for additional information
 *
 */
/*  checker2.c
 *  This program texture maps a checkerboard image onto
 *  two rectangles.  This program repeats the texture, if
 *  the texture coordinates fall outside 0.0 and 1.0.
 */
#include "glos.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>
void myinit(void);
void makeCheckImage(void);
void CALLBACK myReshape(GLsizei w, GLsizei h);
void CALLBACK display(void);
/*  Create checkerboard texture */
#define checkImageWidth 64
#define checkImageHeight 64
GLubyte checkImage[checkImageWidth][checkImageHeight][3];
void makeCheckImage(void)
{
    int i, j, c;
    for (i = 0; i < checkImageWidth; i++) {
    for (j = 0; j < checkImageHeight; j++) {
        c = ((((i&0x8)==0)^((j&0x8))==0))*255;
        checkImage[i][j][0] = (GLubyte) c;
        checkImage[i][j][1] = (GLubyte) c;
        checkImage[i][j][2] = (GLubyte) c;
    }
    }
}
void myinit(void)
{
    glClearColor (0.0, 0.0, 0.0, 0.0);
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);
    makeCheckImage();
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glTexImage2D(GL_TEXTURE_2D, 0, 3, checkImageWidth,
    checkImageHeight, 0, GL_RGB, GL_UNSIGNED_BYTE,
    &checkImage[0][0][0]);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
    glEnable(GL_TEXTURE_2D);
    glShadeModel(GL_FLAT);
}
void CALLBACK display(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glBegin(GL_QUADS);
    glTexCoord2f(0.0, 0.0); glVertex3f(-2.0, -1.0, 0.0);
    glTexCoord2f(0.0, 3.0); glVertex3f(-2.0, 1.0, 0.0);
    glTexCoord2f(3.0, 3.0); glVertex3f(0.0, 1.0, 0.0);
    glTexCoord2f(3.0, 0.0); glVertex3f(0.0, -1.0, 0.0);
    glTexCoord2f(0.0, 0.0); glVertex3f(1.0, -1.0, 0.0);
    glTexCoord2f(0.0, 3.0); glVertex3f(1.0, 1.0, 0.0);
    glTexCoord2f(3.0, 3.0); glVertex3f(2.41421, 1.0, -1.41421);
    glTexCoord2f(3.0, 0.0); glVertex3f(2.41421, -1.0, -1.41421);
    glEnd();
    glFlush();
}
void CALLBACK myReshape(GLsizei w, GLsizei h)
{
    h = (h == 0) ? 1 : h;
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(60.0, 1.0*(GLfloat)w/(GLfloat)h, 1.0, 30.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glTranslatef(0.0, 0.0, -3.6);
}
int main(int argc, char** argv)
{
    auxInitDisplayMode (AUX_SINGLE | AUX_RGB | AUX_DEPTH16);
    auxInitPosition (0, 0, 500, 500);
    auxInitWindow ("Texture Map");
    myinit();
    auxReshapeFunc (myReshape);
    auxMainLoop(display);
    return(0);
}


CHESS.C  (BOOK Sample)
/*
 * (c) Copyright 1993, Silicon Graphics, Inc.
 *               1993, 1994 Microsoft Corporation
 *
 * ALL RIGHTS RESERVED
 *
 * Please refer to OpenGL/readme.txt for additional information
 *
 */
/*  chess.c
 *  This program texture maps a checkerboard image onto
 *  two rectangles.  The texture coordinates for the
 *  rectangles are 0.0 to 3.0.
 */
#include "glos.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>
#include <math.h>
void myinit(void);
void makeCheckImage(void);
void CALLBACK myReshape(GLsizei w, GLsizei h);
void CALLBACK display(void);
#define checkImageWidth 64
#define checkImageHeight 64
GLubyte checkImage[checkImageWidth][checkImageHeight][3];
void makecheckimage(void)
{
    int i, j, c;
    for (i = 0; i < checkImageWidth; i++) {
    for (j = 0; j < checkImageHeight; j++) {
        c = ((((i&0x8)==0)^((j&0x8))==0))*255;
        checkImage[i][j][0] = (GLubyte) c;
        checkImage[i][j][1] = (GLubyte) c;
        checkImage[i][j][2] = (GLubyte) c;
    }
    }
}
void myinit(void)
{
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);
    makecheckimage();
    glTexImage2D(GL_TEXTURE_2D, 0, 3,
    checkImageWidth, checkImageHeight, 0,
    GL_RGB, GL_UNSIGNED_BYTE, &checkImage[0][0][0]);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
    glEnable(GL_TEXTURE_2D);
    glShadeModel(GL_FLAT);
}
void CALLBACK display(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glBegin(GL_QUADS);
    glTexCoord2f(0.0, 0.0); glVertex3f(-2.0, -1.0, 0.0);
    glTexCoord2f(0.0, 3.0); glVertex3f(-2.0, 1.0, 0.0);
    glTexCoord2f(3.0, 3.0); glVertex3f(0.0, 1.0, 0.0);
    glTexCoord2f(3.0, 0.0); glVertex3f(0.0, -1.0, 0.0);
    glTexCoord2f(0.0, 0.0); glVertex3f(1.0, -1.0, 0.0);
    glTexCoord2f(0.0, 3.0); glVertex3f(1.0, 1.0, 0.0);
    glTexCoord2f(3.0, 3.0); glVertex3f(2.41421, 1.0, -1.41421);
    glTexCoord2f(3.0, 0.0); glVertex3f(2.41421, -1.0, -1.41421);
    glEnd();
    glFlush();
}
void CALLBACK myReshape(GLsizei w, GLsizei h)
{
    h = (h == 0) ? 1 : h;
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(60.0, 1.0*(GLfloat)w/(GLfloat)h, 1.0, 30.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glTranslatef(0.0, 0.0, -3.6);
}
int main(int argc, char** argv)
{
    auxInitDisplayMode (AUX_SINGLE | AUX_RGB | AUX_DEPTH16);
    auxInitPosition (0, 0, 500, 500);
    auxInitWindow ("Texture Map");
    myinit();
    auxReshapeFunc (myReshape);
    auxMainLoop(display);
    return(0);
}


CLIP.C  (BOOK Sample)
/*
 * (c) Copyright 1993, Silicon Graphics, Inc.
 *               1993, 1994 Microsoft Corporation
 *
 * ALL RIGHTS RESERVED
 *
 * Please refer to OpenGL/readme.txt for additional information
 *
 */
/*
 *  clip.c
 *  This program demonstrates arbitrary clipping planes.
 */
#include "glos.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>
void myinit(void);
void CALLBACK myReshape(GLsizei w, GLsizei h);
void CALLBACK display(void);
void CALLBACK display(void)
{
    GLdouble eqn[4] = {0.0, 1.0, 0.0, 0.0};
    GLdouble eqn2[4] = {1.0, 0.0, 0.0, 0.0};
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3f (1.0, 1.0, 1.0);
    glPushMatrix();
    glTranslatef (0.0, 0.0, -5.0);
/*    clip lower half -- y < 0      */
    glClipPlane (GL_CLIP_PLANE0, eqn);
    glEnable (GL_CLIP_PLANE0);
/*    clip left half -- x < 0       */
    glClipPlane (GL_CLIP_PLANE1, eqn2);
    glEnable (GL_CLIP_PLANE1);
    glRotatef (90.0, 1.0, 0.0, 0.0);
    auxWireSphere(1.0);
    glPopMatrix();
    glFlush();
}
void myinit (void) {
    glShadeModel (GL_FLAT);
}
void CALLBACK myReshape(GLsizei w, GLsizei h)
{
    h = (h == 0) ? 1 : h;
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(60.0, (GLfloat) w/(GLfloat) h, 1.0, 20.0);
    glMatrixMode(GL_MODELVIEW);
}
/*  Main Loop
 *  Open window with initial window size, title bar,
 *  RGBA display mode, and handle input events.
 */
int main(int argc, char** argv)
{
    auxInitDisplayMode (AUX_SINGLE | AUX_RGB);
    auxInitPosition (0, 0, 500, 500);
    auxInitWindow ("Arbitrary Clipping Planes");
    myinit ();
    auxReshapeFunc (myReshape);
    auxMainLoop(display);
    return(0);
}


COLORMAT.C  (BOOK Sample)
/*
 * (c) Copyright 1993, Silicon Graphics, Inc.
 *               1993, 1994 Microsoft Corporation
 *
 * ALL RIGHTS RESERVED
 *
 * Please refer to OpenGL/readme.txt for additional information
 *
 */
/*
 *  colormat.c
 *  After initialization, the program will be in
 *  ColorMaterial mode.  Pressing the mouse buttons
 *  will change the color of the diffuse reflection.
 */
#include "glos.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>
void myinit(void);
void CALLBACK changeRedDiffuse (void);
void CALLBACK changeGreenDiffuse (void);
void CALLBACK changeBlueDiffuse (void);
void CALLBACK myReshape(GLsizei w, GLsizei h);
void CALLBACK display(void);
GLfloat diffuseMaterial[4] = { 0.5, 0.5, 0.5, 1.0 };
/*  Initialize values for material property, light source,
 *  lighting model, and depth buffer.
 */
void myinit(void)
{
    GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
    GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 };
    glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuseMaterial);
    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
    glMaterialf(GL_FRONT, GL_SHININESS, 25.0);
    glLightfv(GL_LIGHT0, GL_POSITION, light_position);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glDepthFunc(GL_LESS);
    glEnable(GL_DEPTH_TEST);
    glColorMaterial(GL_FRONT, GL_DIFFUSE);
    glEnable(GL_COLOR_MATERIAL);
}
void CALLBACK changeRedDiffuse (void)
{
    diffuseMaterial[0] += 0.1;
    if (diffuseMaterial[0] > 1.0)
    diffuseMaterial[0] = 0.0;
    glColor4fv(diffuseMaterial);
}
void CALLBACK changeGreenDiffuse (void)
{
    diffuseMaterial[1] += 0.1;
    if (diffuseMaterial[1] > 1.0)
    diffuseMaterial[1] = 0.0;
    glColor4fv(diffuseMaterial);
}
void CALLBACK changeBlueDiffuse (void)
{
    diffuseMaterial[2] += 0.1;
    if (diffuseMaterial[2] > 1.0)
    diffuseMaterial[2] = 0.0;
    glColor4fv(diffuseMaterial);
}
void CALLBACK display(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    auxSolidSphere(1.0);
    glFlush();
}
void CALLBACK myReshape(GLsizei w, GLsizei h)
{
    h = (h == 0) ? 1 : h;
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    if (w <= h)
    glOrtho (-1.5, 1.5, -1.5*(GLfloat)h/(GLfloat)w,
        1.5*(GLfloat)h/(GLfloat)w, -10.0, 10.0);
    else
    glOrtho (-1.5*(GLfloat)w/(GLfloat)h,
        1.5*(GLfloat)w/(GLfloat)h, -1.5, 1.5, -10.0, 10.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}
int main(int argc, char** argv)
{
    auxInitDisplayMode (AUX_SINGLE | AUX_RGB | AUX_DEPTH16);
    auxInitPosition (0, 0, 500, 500);
    auxInitWindow ("ColorMaterial Mode");
    myinit();
    auxKeyFunc(AUX_R, changeRedDiffuse);
    auxKeyFunc(AUX_r, changeRedDiffuse);
    auxKeyFunc(AUX_G, changeGreenDiffuse);
    auxKeyFunc(AUX_g, changeGreenDiffuse);
    auxKeyFunc(AUX_B, changeBlueDiffuse);
    auxKeyFunc(AUX_b, changeBlueDiffuse);
    auxReshapeFunc (myReshape);
    auxMainLoop(display);
    return(0);
}


CONE.C  (BOOK Sample)
/*
 * (c) Copyright 1993, Silicon Graphics, Inc.
 *               1993, 1994 Microsoft Corporation
 *
 * ALL RIGHTS RESERVED
 *
 * Please refer to OpenGL/readme.txt for additional information
 *
 */
/*
 * cone.c
 * This program demonstrates the use of the GL lighting model.
 * A sphere is drawn using a grey material characteristic.
 * A single light source illuminates the object.
 */
#include "glos.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>
void myinit(void);
void CALLBACK myReshape(GLsizei w, GLsizei h);
void CALLBACK display(void);
/*  Initialize material property, light source, and lighting model.
 */
void myinit(void)
{
    GLfloat mat_ambient[] = { 0.2, 0.2, 0.2, 1.0 };
    GLfloat mat_diffuse[] = { 0.8, 0.8, 0.8, 1.0 };
/*  mat_specular and mat_shininess are NOT default values   */
    GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
    GLfloat mat_shininess[] = { 50.0 };
    GLfloat light_ambient[] = { 0.0, 0.0, 0.0, 1.0 };
    GLfloat light_diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
    GLfloat light_specular[] = { 1.0, 1.0, 1.0, 1.0 };
/*  light_position is NOT default value */
    GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 };
    GLfloat lmodel_ambient[] = { 0.2, 0.2, 0.2, 1.0 };
    glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
    glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
    glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
    glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
    glLightfv(GL_LIGHT0, GL_POSITION, light_position);
    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glDepthFunc(GL_LESS);
    glEnable(GL_DEPTH_TEST);
}
void CALLBACK display(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glPushMatrix();
    glTranslatef (0.0, -1.0, 0.0);
    glRotatef (250.0, 1.0, 0.0, 0.0);
    auxSolidCone(1.0, 2.0);
    glPopMatrix();
    glFlush();
}
void CALLBACK myReshape(GLsizei w, GLsizei h)
{
    h = (h == 0) ? 1 : h;
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    if (w <= h)
        glOrtho (-1.5, 1.5, -1.5*(GLfloat)h/(GLfloat)w,
                1.5*(GLfloat)h/(GLfloat)w, -10.0, 10.0);
    else
        glOrtho (-1.5*(GLfloat)w/(GLfloat)h,
                1.5*(GLfloat)w/(GLfloat)h, -1.5, 1.5, -10.0, 10.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}
/*  Main Loop
 *  Open window with initial window size, title bar,
 *  RGBA display mode, and handle input events.
 */
int main(int argc, char** argv)
{
    auxInitDisplayMode (AUX_SINGLE | AUX_RGB | AUX_DEPTH16);
    auxInitPosition (0, 0, 500, 500);
    auxInitWindow ("Lighting");
    myinit();
    auxReshapeFunc (myReshape);
    auxMainLoop(display);
    return(0);
}


CUBE.C  (BOOK Sample)
/*
 * (c) Copyright 1993, Silicon Graphics, Inc.
 *               1993, 1994 Microsoft Corporation
 *
 * ALL RIGHTS RESERVED
 *
 * Please refer to OpenGL/readme.txt for additional information
 *
 */
/*
 *  cube.c
 *  Draws a 3-D cube, viewed with perspective, stretched
 *  along the y-axis.
 */
#include "glos.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>
void myinit(void);
void CALLBACK myReshape(GLsizei w, GLsizei h);
void CALLBACK display(void);
/*  Clear the screen.  Set the current color to white.
 *  Draw the wire frame cube.
 */
void CALLBACK display (void)
{
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3f (1.0, 1.0, 1.0);
    glLoadIdentity ();  /*  clear the matrix    */
    glTranslatef (0.0, 0.0, -5.0);  /*  viewing transformation  */
    glScalef (1.0, 2.0, 1.0);   /*  modeling transformation */
    auxWireCube(1.0);   /*  draw the cube   */
    glFlush();
}
void myinit (void) {
    glShadeModel (GL_FLAT);
}
/*  Called when the window is first opened and whenever
 *  the window is reconfigured (moved or resized).
 */
void CALLBACK myReshape(GLsizei w, GLsizei h)
{
    glMatrixMode (GL_PROJECTION);   /*  prepare for and then  */
    glLoadIdentity ();  /*  define the projection  */
    glFrustum (-1.0, 1.0, -1.0, 1.0, 1.5, 20.0);    /*  transformation  */
    glMatrixMode (GL_MODELVIEW);    /*  back to modelview matrix    */
    glViewport (0, 0, w, h);    /*  define the viewport */
}
/*  Main Loop
 *  Open window with initial window size, title bar,
 *  RGBA display mode, and handle input events.
 */
int main(int argc, char** argv)
{
    auxInitDisplayMode (AUX_SINGLE | AUX_RGB);
    auxInitPosition (0, 0, 500, 500);
    auxInitWindow ("Perspective 3-D Cube");
    myinit ();
    auxReshapeFunc (myReshape);
    auxMainLoop(display);
    return(0);
}


CURVE.C  (BOOK Sample)
/*
 * (c) Copyright 1993, Silicon Graphics, Inc.
 *               1993, 1994 Microsoft Corporation
 *
 * ALL RIGHTS RESERVED
 *
 * Please refer to OpenGL/readme.txt for additional information
 *
 */
/*
 *  curve.c
 *  This program uses the Utility Library NURBS routines to
 *  draw a one-dimensional NURBS curve.
 */
#include "glos.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>
void myinit(void);
void CALLBACK myReshape(GLsizei w, GLsizei h);
void CALLBACK display(void);
GLUnurbsObj *theNurb;
void myinit(void)
{
    glShadeModel (GL_FLAT);
    theNurb = gluNewNurbsRenderer();
    gluNurbsProperty (theNurb, GLU_SAMPLING_TOLERANCE, 10.0);
}
/*  This routine draws a B-spline curve.  Try a different
 *  knot sequence for a Bezier curve.  For example,
    GLfloat knots[8] = {0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0};
 */
void CALLBACK display(void)
{
    GLfloat ctlpoints[4][3] = {{-.75, -.75, 0.0},
    {-.5, .75, 0.0}, {.5, .75, 0.0}, {.75, -.75, 0.0}};
    GLfloat knots[8] = {0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0};
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3f (1.0, 1.0, 1.0);
    gluBeginCurve(theNurb);
    gluNurbsCurve(theNurb,
        8, knots,
        3,
        &ctlpoints[0][0],
        4,
        GL_MAP1_VERTEX_3);
    gluEndCurve(theNurb);
    glFlush();
}
void CALLBACK myReshape(GLsizei w, GLsizei h)
{
    h = (h == 0) ? 1 : h;
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    if (w <= h)
    gluOrtho2D (-1.0, 1.0, -1.0 * (GLfloat) h/(GLfloat) w,
        1.0 * (GLfloat) h/(GLfloat) w);
    else
    gluOrtho2D (-1.0 * (GLfloat) w/(GLfloat) h,
        1.0 * (GLfloat) w/(GLfloat) h, -1.0, 1.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}
/*  Main Loop
 */
int main(int argc, char** argv)
{
    auxInitDisplayMode (AUX_SINGLE | AUX_RGB);
    auxInitPosition (0, 0, 500, 500);
    auxInitWindow ("NURBS Curve");
    myinit();
    auxReshapeFunc (myReshape);
    auxMainLoop(display);
    return(0);
}


DEPTHCUE.C  (BOOK Sample)
/*
 * (c) Copyright 1993, Silicon Graphics, Inc.
 *               1993, 1994 Microsoft Corporation
 *
 * ALL RIGHTS RESERVED
 *
 * Please refer to OpenGL/readme.txt for additional information
 *
 */
/*
 *  depthcue.c
 *  This program draws a wireframe model, which uses
 *  intensity (brightness) to give clues to distance.
 *  Fog is used to achieve this effect.
 */
#include "glos.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>
void myinit(void);
void CALLBACK myReshape(GLsizei w, GLsizei h);
void CALLBACK display(void);
/*  Initialize linear fog for depth cueing.
 */
void myinit(void)
{
    GLfloat fogColor[4] = {0.0, 0.0, 0.0, 1.0};
    glEnable(GL_FOG);
    glFogi (GL_FOG_MODE, GL_LINEAR);
    glHint (GL_FOG_HINT, GL_NICEST);  /*  per pixel   */
    glFogf (GL_FOG_START, 3.0);
    glFogf (GL_FOG_END, 5.0);
    glFogfv (GL_FOG_COLOR, fogColor);
    glClearColor(0.0, 0.0, 0.0, 1.0);
    glDepthFunc(GL_LESS);
    glEnable(GL_DEPTH_TEST);
    glShadeModel(GL_FLAT);
}
/*  display() draws an icosahedron.
 */
void CALLBACK display(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glColor3f (1.0, 1.0, 1.0);
    auxWireIcosahedron(1.0);
    glFlush();
}
void CALLBACK myReshape(GLsizei w, GLsizei h)
{
    h = (h == 0) ? 1 : h;
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective (45.0, (GLfloat) w/(GLfloat) h, 3.0, 5.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity ();
    glTranslatef (0.0, 0.0, -4.0);  /*  move object into view   */
}
/*  Main Loop
 */
int main(int argc, char** argv)
{
    auxInitDisplayMode (AUX_SINGLE | AUX_RGB | AUX_DEPTH16);
    auxInitPosition (0, 0, 400, 400);
    auxInitWindow ("Distance Using Fog");
    myinit();
    auxReshapeFunc (myReshape);
    auxMainLoop(display);
    return(0);
}


DISK.C  (BOOK Sample)
/*
 * (c) Copyright 1993, Silicon Graphics, Inc.
 *               1993, 1994 Microsoft Corporation
 *
 * ALL RIGHTS RESERVED
 *
 * Please refer to OpenGL/readme.txt for additional information
 *
 */
/*
 *  disk.c
 *  This program demonstrates the use of the quadrics
 *  Utility Library routines to draw circles and arcs.
 */
#include "glos.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>
void myinit(void);
void CALLBACK myReshape(GLsizei w, GLsizei h);
void CALLBACK display(void);
GLUquadricObj * quadObj;
/*  Clear the screen.  For each triangle, set the current
 *  color and modify the modelview matrix.
 */
void CALLBACK display(void)
{
    glClearColor (0.0, 0.0, 0.0, 1.0);
    glClear (GL_COLOR_BUFFER_BIT);
    glPushMatrix();
    gluQuadricDrawStyle (quadObj, GLU_FILL);
    glColor3f (1.0, 1.0, 1.0);
    glTranslatef (10.0, 10.0, 0.0);
    gluDisk (quadObj, 0.0, 5.0, 10, 2);
    glPopMatrix();
    glPushMatrix();
    glColor3f (1.0, 1.0, 0.0);
    glTranslatef (20.0, 20.0, 0.0);
    gluPartialDisk (quadObj, 0.0, 5.0, 10, 3, 30.0, 120.0);
    glPopMatrix();
    glPushMatrix();
    gluQuadricDrawStyle (quadObj, GLU_SILHOUETTE);
    glColor3f (0.0, 1.0, 1.0);
    glTranslatef (30.0, 30.0, 0.0);
    gluPartialDisk (quadObj, 0.0, 5.0, 10, 3, 135.0, 270.0);
    glPopMatrix();
    glPushMatrix();
    gluQuadricDrawStyle (quadObj, GLU_LINE);
    glColor3f (1.0, 0.0, 1.0);
    glTranslatef (40.0, 40.0, 0.0);
    gluDisk (quadObj, 2.0, 5.0, 10, 10);
    glPopMatrix();
    glFlush();
}
void myinit (void) {
    quadObj = gluNewQuadric ();
    glShadeModel(GL_FLAT);
}
void CALLBACK myReshape(GLsizei w, GLsizei h)
{
    h = (h == 0) ? 1 : h;
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    if (w <= h)
    glOrtho (0.0, 50.0,
        0.0, 50.0*(GLfloat)h/(GLfloat)w, -1.0, 1.0);
    else
    glOrtho (0.0, 50.0*(GLfloat)w/(GLfloat)h,
        0.0, 50.0, -1.0, 1.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity ();
}
/*  Main Loop
 *  Open window with initial window size, title bar,
 *  RGBA display mode, and handle input events.
 */
int main(int argc, char** argv)
{
    auxInitDisplayMode (AUX_SINGLE | AUX_RGB);
    auxInitPosition (0, 0, 500, 500);
    auxInitWindow ("Quadrics");
    myinit ();
    auxReshapeFunc (myReshape);
    auxMainLoop(display);
    return(0);
}


DOF.C  (BOOK Sample)
/*
 * (c) Copyright 1993, Silicon Graphics, Inc.
 *               1993, 1994 Microsoft Corporation
 *
 * ALL RIGHTS RESERVED
 *
 * Please refer to OpenGL/readme.txt for additional information
 *
 */
/*
 *  dof.c
 *  This program demonstrates use of the accumulation buffer to
 *  create an out-of-focus depth-of-field effect.  The teapots
 *  are drawn several times into the accumulation buffer.  The
 *  viewing volume is jittered, except at the focal point, where
 *  the viewing volume is at the same position, each time.  In
 *  this case, the gold teapot remains in focus.
 */
#include "glos.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <math.h>
#include <GL/glaux.h>
#include "jitter.h"
void myinit(void);
void accFrustum(GLdouble left, GLdouble right, GLdouble bottom,
    GLdouble top, GLdouble znear, GLdouble zfar, GLdouble pixdx,
    GLdouble pixdy, GLdouble eyedx, GLdouble eyedy, GLdouble focus);
void accPerspective(GLdouble fovy, GLdouble aspect,
    GLdouble znear, GLdouble zfar, GLdouble pixdx, GLdouble pixdy,
    GLdouble eyedx, GLdouble eyedy, GLdouble focus);
void renderTeapot (GLfloat x, GLfloat y, GLfloat z,
    GLfloat ambr, GLfloat ambg, GLfloat ambb,
    GLfloat difr, GLfloat difg, GLfloat difb,
    GLfloat specr, GLfloat specg, GLfloat specb, GLfloat shine);
void CALLBACK myReshape(GLsizei w, GLsizei h);
void CALLBACK display(void);
#define PI_ 3.14159265358979323846
/*  accFrustum()
 *  The first 6 arguments are identical to the glFrustum() call.
 *
 *  pixdx and pixdy are anti-alias jitter in pixels.
 *  Set both equal to 0.0 for no anti-alias jitter.
 *  eyedx and eyedy are depth-of field jitter in pixels.
 *  Set both equal to 0.0 for no depth of field effects.
 *
 *  focus is distance from eye to plane in focus.
 *  focus must be greater than, but not equal to 0.0.
 *
 *  Note that accFrustum() calls glTranslatef().  You will
 *  probably want to insure that your ModelView matrix has been
 *  initialized to identity before calling accFrustum().
 */
void accFrustum(GLdouble left, GLdouble right, GLdouble bottom,
    GLdouble top, GLdouble znear, GLdouble zfar, GLdouble pixdx,
    GLdouble pixdy, GLdouble eyedx, GLdouble eyedy, GLdouble focus)
{
    GLdouble xwsize, ywsize;
    GLdouble dx, dy;
    GLint viewport[4];
    glGetIntegerv (GL_VIEWPORT, viewport);
    xwsize = right - left;
    ywsize = top - bottom;
    dx = -(pixdx*xwsize/(GLdouble) viewport[2] + eyedx*znear/focus);
    dy = -(pixdy*ywsize/(GLdouble) viewport[3] + eyedy*znear/focus);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glFrustum (left + dx, right + dx, bottom + dy, top + dy, znear, zfar);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glTranslatef (-eyedx, -eyedy, 0.0);
}
/*  accPerspective()
 *
 *  The first 4 arguments are identical to the gluPerspective() call.
 *  pixdx and pixdy are anti-alias jitter in pixels.
 *  Set both equal to 0.0 for no anti-alias jitter.
 *  eyedx and eyedy are depth-of field jitter in pixels.
 *  Set both equal to 0.0 for no depth of field effects.
 *
 *  focus is distance from eye to plane in focus.
 *  focus must be greater than, but not equal to 0.0.
 *
 *  Note that accPerspective() calls accFrustum().
 */
void accPerspective(GLdouble fovy, GLdouble aspect,
    GLdouble znear, GLdouble zfar, GLdouble pixdx, GLdouble pixdy,
    GLdouble eyedx, GLdouble eyedy, GLdouble focus)
{
    GLdouble fov2,left,right,bottom,top;
    fov2 = ((fovy*PI_) / 180.0) / 2.0;
    top = znear / (cos(fov2) / sin(fov2));
    bottom = -top;
    right = top * aspect;
    left = -right;
    accFrustum (left, right, bottom, top, znear, zfar,
    pixdx, pixdy, eyedx, eyedy, focus);
}
void myinit(void)
{
    GLfloat ambient[] = { 0.0, 0.0, 0.0, 1.0 };
    GLfloat diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
    GLfloat specular[] = { 1.0, 1.0, 1.0, 1.0 };
    GLfloat position[] = { 0.0, 3.0, 3.0, 0.0 };
    GLfloat lmodel_ambient[] = { 0.2, 0.2, 0.2, 1.0 };
    GLfloat local_view[] = { 0.0 };
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);
    glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
    glLightfv(GL_LIGHT0, GL_POSITION, position);
    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
    glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, local_view);
    glFrontFace (GL_CW);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glEnable(GL_AUTO_NORMAL);
    glEnable(GL_NORMALIZE);
    glMatrixMode (GL_MODELVIEW);
    glLoadIdentity ();
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glClearAccum(0.0, 0.0, 0.0, 0.0);
}
void renderTeapot (GLfloat x, GLfloat y, GLfloat z,
    GLfloat ambr, GLfloat ambg, GLfloat ambb,
    GLfloat difr, GLfloat difg, GLfloat difb,
    GLfloat specr, GLfloat specg, GLfloat specb, GLfloat shine)
{
    float mat[3];
    glPushMatrix();
    glTranslatef (x, y, z);
    mat[0] = ambr; mat[1] = ambg; mat[2] = ambb;
    glMaterialfv (GL_FRONT, GL_AMBIENT, mat);
    mat[0] = difr; mat[1] = difg; mat[2] = difb;
    glMaterialfv (GL_FRONT, GL_DIFFUSE, mat);
    mat[0] = specr; mat[1] = specg; mat[2] = specb;
    glMaterialfv (GL_FRONT, GL_SPECULAR, mat);
    glMaterialf (GL_FRONT, GL_SHININESS, shine*128.0);
    auxSolidTeapot(0.5);
    glPopMatrix();
}
/*  display() draws 5 teapots into the accumulation buffer
 *  several times; each time with a jittered perspective.
 *  The focal point is at z = 5.0, so the gold teapot will
 *  stay in focus.  The amount of jitter is adjusted by the
 *  magnitude of the accPerspective() jitter; in this example, 0.33.
 *  In this example, the teapots are drawn 8 times.  See jitter.h
 */
void CALLBACK display(void)
{
    int jitter;
    GLint viewport[4];
    glGetIntegerv (GL_VIEWPORT, viewport);
    glClear(GL_ACCUM_BUFFER_BIT);
    for (jitter = 0; jitter < 8; jitter++) {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    accPerspective (45.0,
        (GLdouble) viewport[2]/(GLdouble) viewport[3],
        1.0, 15.0, 0.0, 0.0,
        0.33*j8[jitter].x, 0.33*j8[jitter].y, 5.0);
/*  ruby, gold, silver, emerald, and cyan teapots   */
    renderTeapot (-1.1, -0.5, -4.5, 0.1745, 0.01175, 0.01175,
        0.61424, 0.04136, 0.04136, 0.727811, 0.626959, 0.626959, 0.6);
    renderTeapot (-0.5, -0.5, -5.0, 0.24725, 0.1995, 0.0745,
        0.75164, 0.60648, 0.22648, 0.628281, 0.555802, 0.366065, 0.4);
    renderTeapot (0.2, -0.5, -5.5, 0.19225, 0.19225, 0.19225,
        0.50754, 0.50754, 0.50754, 0.508273, 0.508273, 0.508273, 0.4);
    renderTeapot (1.0, -0.5, -6.0, 0.0215, 0.1745, 0.0215,
        0.07568, 0.61424, 0.07568, 0.633, 0.727811, 0.633, 0.6);
    renderTeapot (1.8, -0.5, -6.5, 0.0, 0.1, 0.06, 0.0, 0.50980392,
        0.50980392, 0.50196078, 0.50196078, 0.50196078, .25);
    glAccum (GL_ACCUM, 0.125);
    }
    glAccum (GL_RETURN, 1.0);
    glFlush();
}
void CALLBACK myReshape(GLsizei w, GLsizei h)
{
    h = (h == 0) ? 1 : h;
    glViewport(0, 0, w, h);
}
/*  Main Loop
 *  Open window with initial window size, title bar,
 *  RGBA display mode, depth buffer, and handle input events.
 */
int main(int argc, char** argv)
{
    auxInitDisplayMode (AUX_SINGLE | AUX_RGB
            | AUX_ACCUM | AUX_DEPTH16);
    auxInitPosition (0, 0, 400, 400);
    auxInitWindow ("Depth-of-Field");
    myinit();
    auxReshapeFunc (myReshape);
    auxMainLoop(display);
    return(0);
}


DOFNOT.C  (BOOK Sample)
/*
 * (c) Copyright 1993, Silicon Graphics, Inc.
 *               1993, 1994 Microsoft Corporation
 *
 * ALL RIGHTS RESERVED
 *
 * Please refer to OpenGL/readme.txt for additional information
 *
 */
/*
 *  dofnot.c
 *  This program demonstrates the same scene as dof.c, but
 *  without use of the accumulation buffer, so everything
 *  is in focus.
 */
#include "glos.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <math.h>
#include <GL/glaux.h>
void myinit(void);
void renderTeapot (GLfloat x, GLfloat y, GLfloat z,
    GLfloat ambr, GLfloat ambg, GLfloat ambb,
    GLfloat difr, GLfloat difg, GLfloat difb,
    GLfloat specr, GLfloat specg, GLfloat specb, GLfloat shine);
void CALLBACK myReshape(GLsizei w, GLsizei h);
void CALLBACK display(void);
void myinit(void)
{
    GLfloat ambient[] = { 0.0, 0.0, 0.0, 1.0 };
    GLfloat diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
    GLfloat specular[] = { 1.0, 1.0, 1.0, 1.0 };
    GLfloat position[] = { 0.0, 3.0, 3.0, 0.0 };
    GLfloat lmodel_ambient[] = { 0.2, 0.2, 0.2, 1.0 };
    GLfloat local_view[] = { 0.0 };
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);
    glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
    glLightfv(GL_LIGHT0, GL_POSITION, position);
    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
    glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, local_view);
    glFrontFace (GL_CW);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glEnable(GL_AUTO_NORMAL);
    glEnable(GL_NORMALIZE);
    glClearColor(0.0, 0.0, 0.0, 0.0);
}
void renderTeapot (GLfloat x, GLfloat y, GLfloat z,
    GLfloat ambr, GLfloat ambg, GLfloat ambb,
    GLfloat difr, GLfloat difg, GLfloat difb,
    GLfloat specr, GLfloat specg, GLfloat specb, GLfloat shine)
{
    float mat[3];
    glPushMatrix();
    glTranslatef (x, y, z);
    mat[0] = ambr; mat[1] = ambg; mat[2] = ambb;
    glMaterialfv (GL_FRONT, GL_AMBIENT, mat);
    mat[0] = difr; mat[1] = difg; mat[2] = difb;
    glMaterialfv (GL_FRONT, GL_DIFFUSE, mat);
    mat[0] = specr; mat[1] = specg; mat[2] = specb;
    glMaterialfv (GL_FRONT, GL_SPECULAR, mat);
    glMaterialf (GL_FRONT, GL_SHININESS, shine*128.0);
    auxSolidTeapot(0.5);
    glPopMatrix();
}
/*  display() draws 5 teapots into the accumulation buffer
 *  several times; each time with a jittered perspective.
 *  The focal point is at z = 5.0, so the gold teapot will
 *  stay in focus.  The amount of jitter is adjusted by the
 *  magnitude of the accPerspective() jitter; in this example, 0.33.
 *  In this example, the teapots are drawn 8 times.  See jitter.h
 */
void CALLBACK display(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glPushMatrix ();
/*  ruby, gold, silver, emerald, and cyan teapots   */
    renderTeapot (-1.1, -0.5, -4.5, 0.1745, 0.01175, 0.01175,
        0.61424, 0.04136, 0.04136, 0.727811, 0.626959, 0.626959, 0.6);
    renderTeapot (-0.5, -0.5, -5.0, 0.24725, 0.1995, 0.0745,
        0.75164, 0.60648, 0.22648, 0.628281, 0.555802, 0.366065, 0.4);
    renderTeapot (0.2, -0.5, -5.5, 0.19225, 0.19225, 0.19225,
        0.50754, 0.50754, 0.50754, 0.508273, 0.508273, 0.508273, 0.4);
    renderTeapot (1.0, -0.5, -6.0, 0.0215, 0.1745, 0.0215,
        0.07568, 0.61424, 0.07568, 0.633, 0.727811, 0.633, 0.6);
    renderTeapot (1.8, -0.5, -6.5, 0.0, 0.1, 0.06, 0.0, 0.50980392,
        0.50980392, 0.50196078, 0.50196078, 0.50196078, .25);
    glPopMatrix ();
    glFlush();
}
void CALLBACK myReshape(GLsizei w, GLsizei h)
{
    h = (h == 0) ? 1 : h;
    glViewport(0, 0, w, h);
    glMatrixMode (GL_PROJECTION);
    glLoadIdentity ();
    gluPerspective (45.0, (GLfloat) w/(GLfloat) h,
        1.0, 15.0);
    glMatrixMode (GL_MODELVIEW);
    glLoadIdentity ();
}
/*  Main Loop
 *  Open window with initial window size, title bar,
 *  RGBA display mode, depth buffer, and handle input events.
 */
int main(int argc, char** argv)
{
    auxInitDisplayMode (AUX_SINGLE | AUX_RGB | AUX_DEPTH16);
    auxInitPosition (0, 0, 400, 400);
    auxInitWindow ("Depth-of-Field");
    myinit();
    auxReshapeFunc (myReshape);
    auxMainLoop(display);
    return(0);
}


DOUBLE.C  (BOOK Sample)
/*
 * (c) Copyright 1993, Silicon Graphics, Inc.
 *               1993, 1994 Microsoft Corporation
 *
 * ALL RIGHTS RESERVED
 *
 * Please refer to OpenGL/readme.txt for additional information
 *
 */
/*
 *  double.c
 *  This program demonstrates double buffering for
 *  flicker-free animation.  The left and middle mouse
 *  buttons start and stop the spinning motion of the square.
 */
#include "glos.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>
void myinit(void);
void CALLBACK spinDisplay (void);
void CALLBACK startIdleFunc (AUX_EVENTREC *event);
void CALLBACK stopIdleFunc (AUX_EVENTREC *event);
void CALLBACK myReshape(GLsizei w, GLsizei h);
void CALLBACK display(void);
static GLfloat spin = 0.0;
void CALLBACK display(void)
{
    glClear (GL_COLOR_BUFFER_BIT);
    glPushMatrix ();
    glRotatef (spin, 0.0, 0.0, 1.0);
    glRectf (-25.0, -25.0, 25.0, 25.0);
    glPopMatrix ();
    glFlush();
    auxSwapBuffers();
}
void CALLBACK spinDisplay (void)
{
    spin = spin + 2.0;
    if (spin > 360.0)
    spin = spin - 360.0;
    display();
}
void CALLBACK startIdleFunc (AUX_EVENTREC *event)
{
    auxIdleFunc(spinDisplay);
}
void CALLBACK stopIdleFunc (AUX_EVENTREC *event)
{
    auxIdleFunc(0);
}
void myinit (void)
{
    glClearColor (0.0, 0.0, 0.0, 1.0);
    glColor3f (1.0, 1.0, 1.0);
    glShadeModel (GL_FLAT);
}
void CALLBACK myReshape(GLsizei w, GLsizei h)
{
    h = (h == 0) ? 1 : h;
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    if (w <= h)
    glOrtho (-50.0, 50.0, -50.0*(GLfloat)h/(GLfloat)w,
        50.0*(GLfloat)h/(GLfloat)w, -1.0, 1.0);
    else
    glOrtho (-50.0*(GLfloat)w/(GLfloat)h,
        50.0*(GLfloat)w/(GLfloat)h, -50.0, 50.0, -1.0, 1.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity ();
}
/*  Main Loop
 *  Open window with initial window size, title bar,
 *  RGBA display mode, and handle input events.
 */
int main(int argc, char** argv)
{
    auxInitDisplayMode (AUX_DOUBLE | AUX_RGB);
    auxInitPosition (0, 0, 500, 500);
    auxInitWindow ("Double Buffering");
    myinit ();
    auxReshapeFunc (myReshape);
    auxIdleFunc (spinDisplay);
    auxMouseFunc (AUX_LEFTBUTTON, AUX_MOUSEDOWN, startIdleFunc);
    auxMouseFunc (AUX_RIGHTBUTTON, AUX_MOUSEDOWN, stopIdleFunc);
    auxMainLoop(display);
    return(0);
}


DRAWF.C  (BOOK Sample)
/*
 * (c) Copyright 1993, Silicon Graphics, Inc.
 *               1993, 1994 Microsoft Corporation
 *
 * ALL RIGHTS RESERVED
 *
 * Please refer to OpenGL/readme.txt for additional information
 *
 */
/*
 *  drawf.c
 *  Draws the bitmapped letter F on the screen (several times).
 *  This demonstrates use of the glBitmap() call.
 */
#include "glos.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>
void myinit(void);
void CALLBACK myReshape(GLsizei w, GLsizei h);
void CALLBACK display(void);
GLubyte rasters[24] = {
    0xc0, 0x00, 0xc0, 0x00, 0xc0, 0x00, 0xc0, 0x00, 0xc0, 0x00,
    0xff, 0x00, 0xff, 0x00, 0xc0, 0x00, 0xc0, 0x00, 0xc0, 0x00,
    0xff, 0xc0, 0xff, 0xc0};
void myinit(void)
{
    glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
    glClearColor (0.0, 0.0, 0.0, 0.0);
}
void CALLBACK display(void)
{
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3f (1.0, 1.0, 1.0);
    glRasterPos2i (20.5, 20.5);
    glBitmap (10, 12, 0.0, 0.0, 12.0, 0.0, rasters);
    glBitmap (10, 12, 0.0, 0.0, 12.0, 0.0, rasters);
    glBitmap (10, 12, 0.0, 0.0, 12.0, 0.0, rasters);
    glFlush();
}
void CALLBACK myReshape(GLsizei w, GLsizei h)
{
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho (0, w, 0, h, -1.0, 1.0);
    glMatrixMode(GL_MODELVIEW);
}
/*  Main Loop
 *  Open window with initial window size, title bar,
 *  RGBA display mode, and handle input events.
 */
int main(int argc, char** argv)
{
    auxInitDisplayMode (AUX_SINGLE | AUX_RGB);
    auxInitPosition (0, 0, 500, 500);
    auxInitWindow ("Bitmap");
    myinit();
    auxReshapeFunc (myReshape);
    auxMainLoop(display);
    return(0);
}


FEEDBACK.C  (BOOK Sample)
/*
 * (c) Copyright 1993, Silicon Graphics, Inc.
 *               1993, 1994 Microsoft Corporation
 *
 * ALL RIGHTS RESERVED
 *
 * Please refer to OpenGL/readme.txt for additional information
 *
 */
/*
 *  feedback.c
 *  This program demonstrates use of OpenGL feedback.  First,
 *  a lighting environment is set up and a few lines are drawn.
 *  Then feedback mode is entered, and the same lines are
 *  drawn.  The results in the feedback buffer are printed.
 */
#include "glos.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>
#include <stdio.h>
void myinit(void);
void drawGeometry (GLenum mode);
void print3DcolorVertex (GLint size, GLint *count, GLfloat *buffer);
void printBuffer(GLint size, GLfloat *buffer);
void CALLBACK myReshape(GLsizei w, GLsizei h);
void CALLBACK display(void);
/*  Initialize lighting.
 */
void myinit(void)
{
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
}
/*  Draw a few lines and two points, one of which will
 *  be clipped.  If in feedback mode, a passthrough token
 *  is issued between the each primitive.
 */
void drawGeometry (GLenum mode)
{
    glBegin (GL_LINE_STRIP);
    glNormal3f (0.0, 0.0, 1.0);
    glVertex3f (30.0, 30.0, 0.0);
    glVertex3f (50.0, 60.0, 0.0);
    glVertex3f (70.0, 40.0, 0.0);
    glEnd ();
    if (mode == GL_FEEDBACK)
    glPassThrough (1.0);
    glBegin (GL_POINTS);
    glVertex3f (-100.0, -100.0, -100.0);    /*  will be clipped  */
    glEnd ();
    if (mode == GL_FEEDBACK)
    glPassThrough (2.0);
    glBegin (GL_POINTS);
    glNormal3f (0.0, 0.0, 1.0);
    glVertex3f (50.0, 50.0, 0.0);
    glEnd ();
}
/*  Write contents of one vertex to stdout. */
void print3DcolorVertex (GLint size,
    GLint *count, GLfloat *buffer)
{
    int i;
    //printf ("  ");
    for (i = 0; i < 7; i++) {
    //printf ("%4.2f ", buffer[size-(*count)]);
    *count = *count - 1;
    }
    //printf ("\n");
}
/*  Write contents of entire buffer.  (Parse tokens!)   */
void printBuffer(GLint size, GLfloat *buffer)
{
    GLint count;
    GLfloat token;
    count = size;
    while (count) {
    token = buffer[size-count]; count--;
    if (token == GL_PASS_THROUGH_TOKEN) {
        //printf ("GL_PASS_THROUGH_TOKEN\n");
        //printf ("  %4.2f\n", buffer[size-count]);
        count--;
    }
    else if (token == GL_POINT_TOKEN) {
        //printf ("GL_POINT_TOKEN\n");
        print3DcolorVertex (size, &count, buffer);
    }
    else if (token == GL_LINE_TOKEN) {
        //printf ("GL_LINE_TOKEN\n");
        print3DcolorVertex (size, &count, buffer);
        print3DcolorVertex (size, &count, buffer);
    }
    else if (token == GL_LINE_RESET_TOKEN) {
        //printf ("GL_LINE_RESET_TOKEN\n");
        print3DcolorVertex (size, &count, buffer);
        print3DcolorVertex (size, &count, buffer);
    }
    }
}
void CALLBACK display(void)
{
    GLfloat feedBuffer[1024];
    GLint size;
    glMatrixMode (GL_PROJECTION);
    glLoadIdentity ();
    glOrtho (0.0, 100.0, 0.0, 100.0, 0.0, 1.0);
    glClearColor (0.0, 0.0, 0.0, 0.0);
    glClear(GL_COLOR_BUFFER_BIT);
    drawGeometry (GL_RENDER);
    glFeedbackBuffer (1024, GL_3D_COLOR, feedBuffer);
    (void) glRenderMode (GL_FEEDBACK);
    drawGeometry (GL_FEEDBACK);
    size = glRenderMode (GL_RENDER);
    printBuffer (size, feedBuffer);
}
/*  Main Loop
 *  Open window with initial window size, title bar,
 *  RGBA display mode, and handle input events.
 */
int main(int argc, char** argv)
{
    auxInitDisplayMode (AUX_SINGLE | AUX_RGB);
    auxInitPosition (0, 0, 100, 100);
    auxInitWindow ("Feedback");
    myinit ();
    auxMainLoop(display);
    return(0);
}


FOG.C  (BOOK Sample)
/*
 * (c) Copyright 1993, Silicon Graphics, Inc.
 *               1993, 1994 Microsoft Corporation
 *
 * ALL RIGHTS RESERVED
 *
 * Please refer to OpenGL/readme.txt for additional information
 *
 */
/*
 *  fog.c
 *  This program draws 5 red teapots, each at a different
 *  z distance from the eye, in different types of fog.
 *  Pressing the left mouse button chooses between 3 types of
 *  fog:  exponential, exponential squared, and linear.
 *  In this program, there is a fixed density value, as well
 *  as fixed start and end values for the linear fog.
 */
#include "glos.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <math.h>
#include <GL/glaux.h>
#include <stdio.h>
void myinit(void);
void renderRedTeapot (GLfloat x, GLfloat y, GLfloat z);
void CALLBACK cycleFog (AUX_EVENTREC *event);
void CALLBACK myReshape(GLsizei w, GLsizei h);
void CALLBACK display(void);
GLint fogMode;
void CALLBACK cycleFog (AUX_EVENTREC *event)
{
    if (fogMode == GL_EXP) {
    fogMode = GL_EXP2;
    //printf ("Fog mode is GL_EXP2\n");
    }
    else if (fogMode == GL_EXP2) {
    fogMode = GL_LINEAR;
    //printf ("Fog mode is GL_LINEAR\n");
    glFogf (GL_FOG_START, 1.0);
    glFogf (GL_FOG_END, 5.0);
    }
    else if (fogMode == GL_LINEAR) {
    fogMode = GL_EXP;
    //printf ("Fog mode is GL_EXP\n");
    }
    glFogi (GL_FOG_MODE, fogMode);
}
/*  Initialize z-buffer, projection matrix, light source,
 *  and lighting model.  Do not specify a material property here.
 */
void myinit(void)
{
    GLfloat position[] = { 0.0, 3.0, 3.0, 0.0 };
    GLfloat local_view[] = { 0.0 };
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);
    glLightfv(GL_LIGHT0, GL_POSITION, position);
    glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, local_view);
    glFrontFace (GL_CW);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glEnable(GL_AUTO_NORMAL);
    glEnable(GL_NORMALIZE);
    glEnable(GL_FOG);
    {
    GLfloat fogColor[4] = {0.5, 0.5, 0.5, 1.0};
    fogMode = GL_EXP;
    glFogi (GL_FOG_MODE, fogMode);
    glFogfv (GL_FOG_COLOR, fogColor);
    glFogf (GL_FOG_DENSITY, 0.35);
    glHint (GL_FOG_HINT, GL_DONT_CARE);
    glClearColor(0.5, 0.5, 0.5, 1.0);
    }
}
void renderRedTeapot (GLfloat x, GLfloat y, GLfloat z)
{
    float mat[3];
    glPushMatrix();
    glTranslatef (x, y, z);
    mat[0] = 0.1745; mat[1] = 0.01175; mat[2] = 0.01175;
    glMaterialfv (GL_FRONT, GL_AMBIENT, mat);
    mat[0] = 0.61424; mat[1] = 0.04136; mat[2] = 0.04136;
    glMaterialfv (GL_FRONT, GL_DIFFUSE, mat);
    mat[0] = 0.727811; mat[1] = 0.626959; mat[2] = 0.626959;
    glMaterialfv (GL_FRONT, GL_SPECULAR, mat);
    glMaterialf (GL_FRONT, GL_SHININESS, 0.6*128.0);
    auxSolidTeapot(1.0);
    glPopMatrix();
}
/*  display() draws 5 teapots at different z positions.
 */
void CALLBACK display(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    renderRedTeapot (-4.0, -0.5, -1.0);
    renderRedTeapot (-2.0, -0.5, -2.0);
    renderRedTeapot (0.0, -0.5, -3.0);
    renderRedTeapot (2.0, -0.5, -4.0);
    renderRedTeapot (4.0, -0.5, -5.0);
    glFlush();
}
void CALLBACK myReshape(GLsizei w, GLsizei h)
{
    h = (h == 0) ? 1 : h;
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    if (w <= (h*3))
    glOrtho (-6.0, 6.0, -2.0*((GLfloat) h*3)/(GLfloat) w,
        2.0*((GLfloat) h*3)/(GLfloat) w, 0.0, 10.0);
    else
    glOrtho (-6.0*(GLfloat) w/((GLfloat) h*3),
        6.0*(GLfloat) w/((GLfloat) h*3), -2.0, 2.0, 0.0, 10.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity ();
}
/*  Main Loop
 *  Open window with initial window size, title bar,
 *  RGBA display mode, depth buffer, and handle input events.
 */
int main(int argc, char** argv)
{
    auxInitDisplayMode (AUX_SINGLE | AUX_RGB | AUX_DEPTH16);
    auxInitPosition (0, 0, 450, 150);
    auxInitWindow ("Fog");
    auxMouseFunc (AUX_LEFTBUTTON, AUX_MOUSEDOWN, cycleFog);
    myinit();
    auxReshapeFunc (myReshape);
    auxMainLoop(display);
    return(0);
}


FOGINDEX.C  (BOOK Sample)
/*
 * (c) Copyright 1993, Silicon Graphics, Inc.
 *               1993, 1994 Microsoft Corporation
 *
 * ALL RIGHTS RESERVED
 *
 * Please refer to OpenGL/readme.txt for additional information
 *
 */
/*
 *  fogindex.c
 *  This program demonstrates fog in color index mode.
 *  Three cones are drawn at different z values in a linear
 *  fog.  32 contiguous colors (from 16 to 47) are loaded
 *  with a color ramp.
 */
#include "glos.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>
void myinit(void);
void CALLBACK myReshape(GLsizei w, GLsizei h);
void CALLBACK display(void);
/*  Initialize color map and fog.  Set screen clear color
 *  to end of color ramp.
 */
#define NMCOLORS 32
#define RAMPSTART 16
void myinit(void)
{
    int i;
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);
    for (i = 0; i < NMCOLORS; i++) {
    GLfloat shade;
    shade = (GLfloat) (NMCOLORS-i)/(GLfloat) NMCOLORS;
    auxSetOneColor (16 + i, shade, shade, shade);
    }
    glEnable(GL_FOG);
    glFogi (GL_FOG_MODE, GL_LINEAR);
    glFogi (GL_FOG_INDEX, NMCOLORS);
    glFogf (GL_FOG_START, 0.0);
    glFogf (GL_FOG_END, 4.0);
    glHint (GL_FOG_HINT, GL_NICEST);
    glClearIndex((GLfloat) (NMCOLORS+RAMPSTART-1));
}
/*  display() renders 3 cones at different z positions.
 */
void CALLBACK display(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glPushMatrix ();
    glTranslatef (-1.0, -1.0, -1.0);
    glRotatef (-90.0, 1.0, 0.0, 0.0);
    glIndexi (RAMPSTART);
    auxSolidCone(1.0, 2.0);
    glPopMatrix ();
    glPushMatrix ();
    glTranslatef (0.0, -1.0, -2.25);
    glRotatef (-90.0, 1.0, 0.0, 0.0);
    glIndexi (RAMPSTART);
    auxSolidCone(1.0, 2.0);
    glPopMatrix ();
    glPushMatrix ();
    glTranslatef (1.0, -1.0, -3.5);
    glRotatef (-90.0, 1.0, 0.0, 0.0);
    glIndexi (RAMPSTART);
    auxSolidCone(1.0, 2.0);
    glPopMatrix ();
    glFlush();
}
void CALLBACK myReshape(GLsizei w, GLsizei h)
{
    h = (h == 0) ? 1 : h;
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    if (w <= h)
    glOrtho (-2.0, 2.0, -2.0*(GLfloat)h/(GLfloat)w,
        2.0*(GLfloat)h/(GLfloat)w, 0.0, 10.0);
    else
    glOrtho (-2.0*(GLfloat)w/(GLfloat)h,
        2.0*(GLfloat)w/(GLfloat)h, -2.0, 2.0, 0.0, 10.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity ();
}
/*  Main Loop
 *  Open window with initial window size, title bar,
 *  RGBA display mode, depth buffer, and handle input events.
 */
int main(int argc, char** argv)
{
    auxInitDisplayMode (AUX_SINGLE | AUX_INDEX | AUX_DEPTH16);
    auxInitPosition (0, 0, 200, 200);
    auxInitWindow ("Fog Using Color Index");
    myinit();
    auxReshapeFunc (myReshape);
    auxMainLoop(display);
    return(0);
}


FONT.C  (BOOK Sample)
/*
 * (c) Copyright 1993, Silicon Graphics, Inc.
 *               1993, 1994 Microsoft Corporation
 *
 * ALL RIGHTS RESERVED
 *
 * Please refer to OpenGL/readme.txt for additional information
 *
 */
/*
 *  font.c
 *
 *  Draws some text in a bitmapped font.  Uses glBitmap()
 *  and other pixel routines.  Also demonstrates use of
 *  display lists.
 */
#include "glos.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>
void myinit(void);
void makeRasterFont(void);
void printString(char *s);
void CALLBACK myReshape(GLsizei w, GLsizei h);
void CALLBACK display(void);
GLubyte rasters[][13] = {
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36},
{0x00, 0x00, 0x00, 0x66, 0x66, 0xff, 0x66, 0x66, 0xff, 0x66, 0x66, 0x00, 0x00},
{0x00, 0x00, 0x18, 0x7e, 0xff, 0x1b, 0x1f, 0x7e, 0xf8, 0xd8, 0xff, 0x7e, 0x18},
{0x00, 0x00, 0x0e, 0x1b, 0xdb, 0x6e, 0x30, 0x18, 0x0c, 0x76, 0xdb, 0xd8, 0x70},
{0x00, 0x00, 0x7f, 0xc6, 0xcf, 0xd8, 0x70, 0x70, 0xd8, 0xcc, 0xcc, 0x6c, 0x38},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x1c, 0x0c, 0x0e},
{0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c},
{0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30},
{0x00, 0x00, 0x00, 0x00, 0x99, 0x5a, 0x3c, 0xff, 0x3c, 0x5a, 0x99, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0xff, 0xff, 0x18, 0x18, 0x18, 0x00, 0x00},
{0x00, 0x00, 0x30, 0x18, 0x1c, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x60, 0x60, 0x30, 0x30, 0x18, 0x18, 0x0c, 0x0c, 0x06, 0x06, 0x03, 0x03},
{0x00, 0x00, 0x3c, 0x66, 0xc3, 0xe3, 0xf3, 0xdb, 0xcf, 0xc7, 0xc3, 0x66, 0x3c},
{0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x38, 0x18},
{0x00, 0x00, 0xff, 0xc0, 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0xe7, 0x7e},
{0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0x7e, 0x07, 0x03, 0x03, 0xe7, 0x7e},
{0x00, 0x00, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xff, 0xcc, 0x6c, 0x3c, 0x1c, 0x0c},
{0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0xff},
{0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc7, 0xfe, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e},
{0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x03, 0x03, 0xff},
{0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e},
{0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x03, 0x7f, 0xe7, 0xc3, 0xc3, 0xe7, 0x7e},
{0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x30, 0x18, 0x1c, 0x1c, 0x00, 0x00, 0x1c, 0x1c, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06},
{0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60},
{0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x18, 0x0c, 0x06, 0x03, 0xc3, 0xc3, 0x7e},
{0x00, 0x00, 0x3f, 0x60, 0xcf, 0xdb, 0xd3, 0xdd, 0xc3, 0x7e, 0x00, 0x00, 0x00},
{0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xff, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18},
{0x00, 0x00, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe},
{0x00, 0x00, 0x7e, 0xe7, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e},
{0x00, 0x00, 0xfc, 0xce, 0xc7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc7, 0xce, 0xfc},
{0x00, 0x00, 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xc0, 0xff},
{0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xff},
{0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xcf, 0xc0, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e},
{0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xff, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3},
{0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e},
{0x00, 0x00, 0x7c, 0xee, 0xc6, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06},
{0x00, 0x00, 0xc3, 0xc6, 0xcc, 0xd8, 0xf0, 0xe0, 0xf0, 0xd8, 0xcc, 0xc6, 0xc3},
{0x00, 0x00, 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0},
{0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xff, 0xff, 0xe7, 0xc3},
{0x00, 0x00, 0xc7, 0xc7, 0xcf, 0xcf, 0xdf, 0xdb, 0xfb, 0xf3, 0xf3, 0xe3, 0xe3},
{0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xe7, 0x7e},
{0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe},
{0x00, 0x00, 0x3f, 0x6e, 0xdf, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c},
{0x00, 0x00, 0xc3, 0xc6, 0xcc, 0xd8, 0xf0, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe},
{0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0x7e, 0xe0, 0xc0, 0xc0, 0xe7, 0x7e},
{0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff},
{0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3},
{0x00, 0x00, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3},
{0x00, 0x00, 0xc3, 0xe7, 0xff, 0xff, 0xdb, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3},
{0x00, 0x00, 0xc3, 0x66, 0x66, 0x3c, 0x3c, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3},
{0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3},
{0x00, 0x00, 0xff, 0xc0, 0xc0, 0x60, 0x30, 0x7e, 0x0c, 0x06, 0x03, 0x03, 0xff},
{0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c},
{0x00, 0x03, 0x03, 0x06, 0x06, 0x0c, 0x0c, 0x18, 0x18, 0x30, 0x30, 0x60, 0x60},
{0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18},
{0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x30, 0x70},
{0x00, 0x00, 0x7f, 0xc3, 0xc3, 0x7f, 0x03, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0xfe, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0},
{0x00, 0x00, 0x7e, 0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x7f, 0xc3, 0xc3, 0xc3, 0xc3, 0x7f, 0x03, 0x03, 0x03, 0x03, 0x03},
{0x00, 0x00, 0x7f, 0xc0, 0xc0, 0xfe, 0xc3, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x33, 0x1e},
{0x7e, 0xc3, 0x03, 0x03, 0x7f, 0xc3, 0xc3, 0xc3, 0x7e, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0},
{0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x18, 0x00},
{0x38, 0x6c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x00, 0x00, 0x0c, 0x00},
{0x00, 0x00, 0xc6, 0xcc, 0xf8, 0xf0, 0xd8, 0xcc, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0},
{0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78},
{0x00, 0x00, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xfe, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xfc, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00},
{0xc0, 0xc0, 0xc0, 0xfe, 0xc3, 0xc3, 0xc3, 0xc3, 0xfe, 0x00, 0x00, 0x00, 0x00},
{0x03, 0x03, 0x03, 0x7f, 0xc3, 0xc3, 0xc3, 0xc3, 0x7f, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, 0xfe, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0xfe, 0x03, 0x03, 0x7e, 0xc0, 0xc0, 0x7f, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x1c, 0x36, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x00},
{0x00, 0x00, 0x7e, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0xc3, 0xe7, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00},
{0xc0, 0x60, 0x60, 0x30, 0x18, 0x3c, 0x66, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0xff, 0x60, 0x30, 0x18, 0x0c, 0x06, 0xff, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x0f, 0x18, 0x18, 0x18, 0x38, 0xf0, 0x38, 0x18, 0x18, 0x18, 0x0f},
{0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18},
{0x00, 0x00, 0xf0, 0x18, 0x18, 0x18, 0x1c, 0x0f, 0x1c, 0x18, 0x18, 0x18, 0xf0},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x8f, 0xf1, 0x60, 0x00, 0x00, 0x00}
};
GLuint fontOffset;
void makeRasterFont(void)
{
    GLuint i;
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    fontOffset = glGenLists (128);
    for (i = 32; i < 127; i++) {
    glNewList(i+fontOffset, GL_COMPILE);
    glBitmap(8, 13, 0.0, 2.0, 10.0, 0.0, rasters[i-32]);
    glEndList();
    }
}
void myinit(void)
{
    glShadeModel (GL_FLAT);
    makeRasterFont();
}
void printString(char *s)
{
    glPushAttrib (GL_LIST_BIT);
    glListBase(fontOffset);
    glCallLists(strlen(s), GL_UNSIGNED_BYTE, (GLubyte *) s);
    glPopAttrib ();
}
/* Everything above this line could be in a library that defines a font.
 * To make it work, you've got to call makeRasterFont() before you start
 * making calls to printString().
 */
void CALLBACK display(void)
{
    GLfloat white[3] = { 1.0, 1.0, 1.0 };
    int i, j;
    char teststring[33];
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3fv(white);
    for (i = 32; i < 127; i += 32) {
    glRasterPos2i(20, 200 - 18*i/32);
    for (j = 0; j < 32; j++)
        teststring[j] = (char) (i+j);
    teststring[32] = 0;
    printString(teststring);
    }
    glRasterPos2i(20, 100);
    printString("The quick brown fox jumps");
    glRasterPos2i(20, 82);
    printString("over a lazy dog.");
    glFlush ();
}
void CALLBACK myReshape(GLsizei w, GLsizei h)
{
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho (0.0, w, 0.0, h, -1.0, 1.0);
    glMatrixMode(GL_MODELVIEW);
}
/*  Main Loop
 *  Open window with initial window size, title bar,
 *  RGBA display mode, and handle input events.
 */
int main(int argc, char** argv)
{
    auxInitDisplayMode (AUX_SINGLE | AUX_RGB);
    auxInitPosition (0, 0, 500, 500);
    auxInitWindow ("Display Lists");
    myinit();
    auxReshapeFunc (myReshape);
    auxMainLoop(display);
    return(0);
}


GLOS.H  (BOOK Sample)
// GLOS.H
//
// This is an OS specific header file
#include <windows.h>
// disable data conversion warnings
#pragma warning(disable : 4244)     // MIPS
#pragma warning(disable : 4136)     // X86
#pragma warning(disable : 4051)     // ALPHA


JITTER.H  (BOOK Sample)
/*
jitter.h
This file contains jitter point arrays for 2,3,4,8,15,24 and 66 jitters.
The arrays are named j2, j3, etc. Each element in the array has the form,
for example, j8[0].x and j8[0].y
Values are floating point in the range -.5 < x < .5, -.5 < y < .5, and
have a gaussian distribution around the origin.
Use these to do model jittering for scene anti-aliasing and view volume
jittering for depth of field effects. Use in conjunction with the
accwindow() routine.
*/
typedef struct
{
GLfloat x, y;
} jitter_point;
#define MAX_SAMPLES  66
/* 2 jitter points */
jitter_point j2[] =
{
{ 0.246490,  0.249999},
{-0.246490, -0.249999}
};
/* 3 jitter points */
jitter_point j3[] =
{
{-0.373411, -0.250550},
{ 0.256263,  0.368119},
{ 0.117148, -0.117570}
};
/* 4 jitter points */
jitter_point j4[] =
{
{-0.208147,  0.353730},
{ 0.203849, -0.353780},
{-0.292626, -0.149945},
{ 0.296924,  0.149994}
};
/* 8 jitter points */
jitter_point j8[] =
{
{-0.334818,  0.435331},
{ 0.286438, -0.393495},
{ 0.459462,  0.141540},
{-0.414498, -0.192829},
{-0.183790,  0.082102},
{-0.079263, -0.317383},
{ 0.102254,  0.299133},
{ 0.164216, -0.054399}
};
/* 15 jitter points */
jitter_point j15[] =
{
{ 0.285561,  0.188437},
{ 0.360176, -0.065688},
{-0.111751,  0.275019},
{-0.055918, -0.215197},
{-0.080231, -0.470965},
{ 0.138721,  0.409168},
{ 0.384120,  0.458500},
{-0.454968,  0.134088},
{ 0.179271, -0.331196},
{-0.307049, -0.364927},
{ 0.105354, -0.010099},
{-0.154180,  0.021794},
{-0.370135, -0.116425},
{ 0.451636, -0.300013},
{-0.370610,  0.387504}
};
/* 24 jitter points */
jitter_point j24[] =
{
{ 0.030245,  0.136384},
{ 0.018865, -0.348867},
{-0.350114, -0.472309},
{ 0.222181,  0.149524},
{-0.393670, -0.266873},
{ 0.404568,  0.230436},
{ 0.098381,  0.465337},
{ 0.462671,  0.442116},
{ 0.400373, -0.212720},
{-0.409988,  0.263345},
{-0.115878, -0.001981},
{ 0.348425, -0.009237},
{-0.464016,  0.066467},
{-0.138674, -0.468006},
{ 0.144932, -0.022780},
{-0.250195,  0.150161},
{-0.181400, -0.264219},
{ 0.196097, -0.234139},
{-0.311082, -0.078815},
{ 0.268379,  0.366778},
{-0.040601,  0.327109},
{-0.234392,  0.354659},
{-0.003102, -0.154402},
{ 0.297997, -0.417965}
};
/* 66 jitter points */
jitter_point j66[] =
{
{ 0.266377, -0.218171},
{-0.170919, -0.429368},
{ 0.047356, -0.387135},
{-0.430063,  0.363413},
{-0.221638, -0.313768},
{ 0.124758, -0.197109},
{-0.400021,  0.482195},
{ 0.247882,  0.152010},
{-0.286709, -0.470214},
{-0.426790,  0.004977},
{-0.361249, -0.104549},
{-0.040643,  0.123453},
{-0.189296,  0.438963},
{-0.453521, -0.299889},
{ 0.408216, -0.457699},
{ 0.328973, -0.101914},
{-0.055540, -0.477952},
{ 0.194421,  0.453510},
{ 0.404051,  0.224974},
{ 0.310136,  0.419700},
{-0.021743,  0.403898},
{-0.466210,  0.248839},
{ 0.341369,  0.081490},
{ 0.124156, -0.016859},
{-0.461321, -0.176661},
{ 0.013210,  0.234401},
{ 0.174258, -0.311854},
{ 0.294061,  0.263364},
{-0.114836,  0.328189},
{ 0.041206, -0.106205},
{ 0.079227,  0.345021},
{-0.109319, -0.242380},
{ 0.425005, -0.332397},
{ 0.009146,  0.015098},
{-0.339084, -0.355707},
{-0.224596, -0.189548},
{ 0.083475,  0.117028},
{ 0.295962, -0.334699},
{ 0.452998,  0.025397},
{ 0.206511, -0.104668},
{ 0.447544, -0.096004},
{-0.108006, -0.002471},
{-0.380810,  0.130036},
{-0.242440,  0.186934},
{-0.200363,  0.070863},
{-0.344844, -0.230814},
{ 0.408660,  0.345826},
{-0.233016,  0.305203},
{ 0.158475, -0.430762},
{ 0.486972,  0.139163},
{-0.301610,  0.009319},
{ 0.282245, -0.458671},
{ 0.482046,  0.443890},
{-0.121527,  0.210223},
{-0.477606, -0.424878},
{-0.083941, -0.121440},
{-0.345773,  0.253779},
{ 0.234646,  0.034549},
{ 0.394102, -0.210901},
{-0.312571,  0.397656},
{ 0.200906,  0.333293},
{ 0.018703, -0.261792},
{-0.209349, -0.065383},
{ 0.076248,  0.478538},
{-0.073036, -0.355064},
{ 0.145087,  0.221726}
};


LIGHT.C  (BOOK Sample)
/*
 * (c) Copyright 1993, Silicon Graphics, Inc.
 *               1993, 1994 Microsoft Corporation
 *
 * ALL RIGHTS RESERVED
 *
 * Please refer to OpenGL/readme.txt for additional information
 *
 */
/*
 *  light.c
 *  This program demonstrates the use of the OpenGL lighting
 *  model.  A sphere is drawn using a grey material characteristic.
 *  A single light source illuminates the object.
 */
#include "glos.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>
void myinit(void);
void CALLBACK myReshape(GLsizei w, GLsizei h);
void CALLBACK display(void);
/*  Initialize material property, light source, lighting model,
 *  and depth buffer.
 */
void myinit(void)
{
    GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
    GLfloat mat_shininess[] = { 50.0 };
    GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 };
    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
    glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
    glLightfv(GL_LIGHT0, GL_POSITION, light_position);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glDepthFunc(GL_LESS);
    glEnable(GL_DEPTH_TEST);
}
void CALLBACK display(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    auxSolidSphere(1.0);
    glFlush();
}
void CALLBACK myReshape(GLsizei w, GLsizei h)
{
    h = (h == 0) ? 1 : h;
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    if (w <= h)
    glOrtho (-1.5, 1.5, -1.5*(GLfloat)h/(GLfloat)w,
        1.5*(GLfloat)h/(GLfloat)w, -10.0, 10.0);
    else
    glOrtho (-1.5*(GLfloat)w/(GLfloat)h,
        1.5*(GLfloat)w/(GLfloat)h, -1.5, 1.5, -10.0, 10.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}
/*  Main Loop
 *  Open window with initial window size, title bar,
 *  RGBA display mode, and handle input events.
 */
int main(int argc, char** argv)
{
    auxInitDisplayMode (AUX_SINGLE | AUX_RGB | AUX_DEPTH16);
    auxInitPosition (0, 0, 500, 500);
    auxInitWindow ("Lighting");
    myinit();
    auxReshapeFunc (myReshape);
    auxMainLoop(display);
    return(0);
}


LINELIST.C  (BOOK Sample)
/*
 * (c) Copyright 1993, Silicon Graphics, Inc.
 *               1993, 1994 Microsoft Corporation
 *
 * ALL RIGHTS RESERVED
 *
 * Please refer to OpenGL/readme.txt for additional information
 *
 */
/*
 *  linelist.c
 *  This program demonstrates using display lists to call
 *  different line stipples.
 */
#include "glos.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>
void myinit(void);
void CALLBACK display(void);
#define drawOneLine(x1,y1,x2,y2) glBegin(GL_LINES); \
    glVertex2f ((x1),(y1)); glVertex2f ((x2),(y2)); glEnd();
GLuint offset;
void myinit (void)
{
/*  background to be cleared to black   */
    glClearColor (0.0, 0.0, 0.0, 0.0);
    glShadeModel (GL_FLAT);
    offset = glGenLists (3);
    glNewList (offset, GL_COMPILE);
    glDisable (GL_LINE_STIPPLE);
    glEndList ();
    glNewList (offset+1, GL_COMPILE);
    glEnable (GL_LINE_STIPPLE);
    glLineStipple (1, 0x0F0F);
    glEndList ();
    glNewList (offset+2, GL_COMPILE);
    glEnable (GL_LINE_STIPPLE);
    glLineStipple (1, 0x1111);
    glEndList ();
}
void CALLBACK display(void)
{
    glClear (GL_COLOR_BUFFER_BIT);
/*  draw all lines in white */
    glColor3f (1.0, 1.0, 1.0);
    glCallList (offset);
    drawOneLine (50.0, 125.0, 350.0, 125.0);
    glCallList (offset+1);
    drawOneLine (50.0, 100.0, 350.0, 100.0);
    glCallList (offset+2);
    drawOneLine (50.0, 75.0, 350.0, 75.0);
    glCallList (offset+1);
    drawOneLine (50.0, 50.0, 350.0, 50.0);
    glCallList (offset);
    drawOneLine (50.0, 25.0, 350.0, 25.0);
    glFlush ();
}
/*  Main Loop
 *  Open window with initial window size, title bar,
 *  RGBA display mode, and handle input events.
 */
int main(int argc, char** argv)
{
    auxInitDisplayMode (AUX_SINGLE | AUX_RGB);
    auxInitPosition (0, 0, 400, 150);
    auxInitWindow ("Display Lists");
    myinit ();
    auxMainLoop(display);
    return(0);
}


LINES.C  (BOOK Sample)
/*
 * (c) Copyright 1993, Silicon Graphics, Inc.
 *               1993, 1994 Microsoft Corporation
 *
 * ALL RIGHTS RESERVED
 *
 * Please refer to OpenGL/readme.txt for additional information
 *
 */
/*
 *  lines.c
 *  This program demonstrates different line stipples and widths.
 */
#include "glos.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>
void myinit(void);
void CALLBACK display(void);
#define drawOneLine(x1,y1,x2,y2) glBegin(GL_LINES); \
    glVertex2f ((x1),(y1)); glVertex2f ((x2),(y2)); glEnd();
void myinit (void) {
    /*  background to be cleared to black   */
    glClearColor (0.0, 0.0, 0.0, 0.0);
    glShadeModel (GL_FLAT);
}
void CALLBACK display(void)
{
    int i;
    glClear (GL_COLOR_BUFFER_BIT);
/*  draw all lines in white */
    glColor3f (1.0, 1.0, 1.0);
/*  in 1st row, 3 lines drawn, each with a different stipple    */
    glEnable (GL_LINE_STIPPLE);
    glLineStipple (1, 0x0101);  /*  dotted  */
    drawOneLine (50.0, 125.0, 150.0, 125.0);
    glLineStipple (1, 0x00FF);  /*  dashed  */
    drawOneLine (150.0, 125.0, 250.0, 125.0);
    glLineStipple (1, 0x1C47);  /*  dash/dot/dash   */
    drawOneLine (250.0, 125.0, 350.0, 125.0);
/*  in 2nd row, 3 wide lines drawn, each with different stipple */
    glLineWidth (5.0);
    glLineStipple (1, 0x0101);
    drawOneLine (50.0, 100.0, 150.0, 100.0);
    glLineStipple (1, 0x00FF);
    drawOneLine (150.0, 100.0, 250.0, 100.0);
    glLineStipple (1, 0x1C47);
    drawOneLine (250.0, 100.0, 350.0, 100.0);
    glLineWidth (1.0);
/*  in 3rd row, 6 lines drawn, with dash/dot/dash stipple,  */
/*  as part of a single connect line strip          */
    glLineStipple (1, 0x1C47);
    glBegin (GL_LINE_STRIP);
    for (i = 0; i < 7; i++)
    glVertex2f (50.0 + ((GLfloat) i * 50.0), 75.0);
    glEnd ();
/*  in 4th row, 6 independent lines drawn,  */
/*  with dash/dot/dash stipple          */
    for (i = 0; i < 6; i++) {
    drawOneLine (50.0 + ((GLfloat) i * 50.0),
        50.0, 50.0 + ((GLfloat)(i+1) * 50.0), 50.0);
    }
/*  in 5th row, 1 line drawn, with dash/dot/dash stipple    */
/*  and repeat factor of 5          */
    glLineStipple (5, 0x1C47);
    drawOneLine (50.0, 25.0, 350.0, 25.0);
    glFlush ();
}
/*  Main Loop
 *  Open window with initial window size, title bar,
 *  RGBA display mode, and handle input events.
 */
int main(int argc, char** argv)
{
    auxInitDisplayMode (AUX_SINGLE | AUX_RGB);
    auxInitPosition (0, 0, 400, 150);
    auxInitWindow ("Lines");
    myinit ();
    auxMainLoop(display);
    return(0);
}


LIST.C  (BOOK Sample)
/*
 * (c) Copyright 1993, Silicon Graphics, Inc.
 *               1993, 1994 Microsoft Corporation
 *
 * ALL RIGHTS RESERVED
 *
 * Please refer to OpenGL/readme.txt for additional information
 *
 */
/*
 *  list.c
 *  This program demonstrates how to make and execute a
 *  display list.  Note that attributes, such as current
 *  color and matrix, are changed.
 */
#include "glos.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>
void myinit(void);
void drawLine (void);
void CALLBACK display(void);
void CALLBACK myReshape(GLsizei w, GLsizei h);
GLuint listName = 1;
void myinit (void)
{
    glNewList (listName, GL_COMPILE);
    glColor3f (1.0, 0.0, 0.0);
    glBegin (GL_TRIANGLES);
    glVertex2f (0.0, 0.0);
    glVertex2f (1.0, 0.0);
    glVertex2f (0.0, 1.0);
    glEnd ();
    glTranslatef (1.5, 0.0, 0.0);
    glEndList ();
    glShadeModel (GL_FLAT);
}
void drawLine (void)
{
    glBegin (GL_LINES);
    glVertex2f (0.0, 0.5);
    glVertex2f (15.0, 0.5);
    glEnd ();
}
void CALLBACK display(void)
{
    GLuint i;
    glClear (GL_COLOR_BUFFER_BIT);
    glColor3f (0.0, 1.0, 0.0);
    glPushMatrix();
    for (i = 0; i < 10; i++)
        glCallList (listName);
    drawLine ();
    glPopMatrix();
    glFlush ();
}
void CALLBACK myReshape(GLsizei w, GLsizei h)
{
    h = (h == 0) ? 1 : h;
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    if (w <= h)
        gluOrtho2D (0.0, 2.0, -0.5 * (GLfloat) h/(GLfloat) w,
                1.5 * (GLfloat) h/(GLfloat) w);
    else
        gluOrtho2D (0.0, 2.0 * (GLfloat) w/(GLfloat) h, -0.5, 1.5);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}
/*  Main Loop
 *  Open window with initial window size, title bar,
 *  RGBA display mode, and handle input events.
 */
int main(int argc, char** argv)
{
    auxInitDisplayMode (AUX_SINGLE | AUX_RGB);
    auxInitPosition (0, 0, 400, 50);
    auxInitWindow ("Display List");
    myinit ();
    auxReshapeFunc (myReshape);
    auxMainLoop(display);
    return(0);
}


LIST2.C  (BOOK Sample)
/*
 * (c) Copyright 1993, Silicon Graphics, Inc.
 *               1993, 1994 Microsoft Corporation
 *
 * ALL RIGHTS RESERVED
 *
 * Please refer to OpenGL/readme.txt for additional information
 *
 */
/*
 *  list2.c
 *  This program demonstrates glGenList() and glPushAttrib().
 *  The matrix and color are restored, before the line is drawn.
 */
#include "glos.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>
void myinit(void);
void drawLine (void);
void CALLBACK display(void);
void CALLBACK myReshape(GLsizei w, GLsizei h);
GLuint listName;
void myinit (void)
{
    GLfloat color_vector[3] = {1.0, 0.0, 0.0};
    listName = glGenLists (1);
    glNewList (listName, GL_COMPILE);
    glPushAttrib (GL_CURRENT_BIT);
    glColor3fv (color_vector);
    glBegin (GL_TRIANGLES);
    glVertex2f (0.0, 0.0);
    glVertex2f (1.0, 0.0);
    glVertex2f (0.0, 1.0);
    glEnd ();
    glTranslatef (1.5, 0.0, 0.0);
    glPopAttrib ();
    glEndList ();
    glShadeModel (GL_FLAT);
}
void drawLine (void)
{
    glBegin (GL_LINES);
    glVertex2f (0.0, 0.5);
    glVertex2f (15.0, 0.5);
    glEnd ();
}
void CALLBACK display(void)
{
    GLuint i;
    GLfloat new_color[3] = {0.0, 1.0, 0.0};
    glClear (GL_COLOR_BUFFER_BIT);
    glColor3fv (new_color);
    glPushMatrix ();
    for (i = 0; i < 10; i++)
    glCallList (listName);
    glPopMatrix ();
    drawLine ();
    glFlush ();
}
void CALLBACK myReshape(GLsizei w, GLsizei h)
{
    h = (h == 0) ? 1 : h;
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    if (w <= h)
    gluOrtho2D (0.0, 2.0, -0.5 * (GLfloat) h/(GLfloat) w,
        1.5 * (GLfloat) h/(GLfloat) w);
    else
    gluOrtho2D (0.0, 2.0 * (GLfloat) w/(GLfloat) h, -0.5, 1.5);
    glMatrixMode(GL_MODELVIEW);
}
/*  Main Loop
 *  Open window with initial window size, title bar,
 *  RGBA display mode, and handle input events.
 */
int main(int argc, char** argv)
{
    auxInitDisplayMode (AUX_SINGLE | AUX_RGB);
    auxInitPosition (0, 0, 400, 50);
    auxInitWindow ("Display List");
    myinit();
    auxReshapeFunc (myReshape);
    auxMainLoop(display);
    return(0);
}


MAPLIGHT.C  (BOOK Sample)
/*
 * (c) Copyright 1993, Silicon Graphics, Inc.
 *               1993, 1994 Microsoft Corporation
 *
 * ALL RIGHTS RESERVED
 *
 * Please refer to OpenGL/readme.txt for additional information
 *
 */
/*
 *  maplight.c
 *  This program demonstrates the use of the GL lighting model.
 *  A sphere is drawn using a magenta diffuse reflective and
 *  white specular material property.
 *  A single light source illuminates the object.  This program
 *  illustrates lighting in color map mode.
 */
#include "glos.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>
void myinit(void);
void CALLBACK display(void);
void CALLBACK myReshape(GLsizei w, GLsizei h);
/*  Initialize material property, light source, and lighting model.
 */
void myinit(void)
{
    GLint i;
    GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 };
    GLfloat mat_colormap[] = { 16.0, 48.0, 79.0 };
    GLfloat mat_shininess[] = { 10.0 };
    glMaterialfv(GL_FRONT, GL_COLOR_INDEXES, mat_colormap);
    glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
    glLightfv(GL_LIGHT0, GL_POSITION, light_position);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glDepthFunc(GL_LESS);
    glEnable(GL_DEPTH_TEST);
    for (i = 0; i < 32; i++) {
    auxSetOneColor (16 + i, 1.0 * (i/32.0), 0.0, 1.0 * (i/32.0));
    auxSetOneColor (48 + i, 1.0, 1.0 * (i/32.0), 1.0);
    }
    glClearIndex(0);
}
void CALLBACK display(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    auxSolidSphere(1.0);
    glFlush();
}
void CALLBACK myReshape(GLsizei w, GLsizei h)
{
    h = (h == 0) ? 1 : h;
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    if (w <= h)
    glOrtho (-1.5, 1.5, -1.5*(GLfloat)h/(GLfloat)w,
        1.5*(GLfloat)h/(GLfloat)w, -10.0, 10.0);
    else
    glOrtho (-1.5*(GLfloat)w/(GLfloat)h,
        1.5*(GLfloat)w/(GLfloat)h, -1.5, 1.5, -10.0, 10.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}
/*  Main Loop
 *  Open window with initial window size, title bar, color
 *  index display mode, and handle input events.
 */
int main(int argc, char** argv)
{
    auxInitDisplayMode (AUX_SINGLE | AUX_INDEX | AUX_DEPTH16);
    auxInitPosition (0, 0, 500, 500);
    auxInitWindow ("Lighting in Color Map Mode");
    myinit();
    auxReshapeFunc (myReshape);
    auxMainLoop(display);
    return(0);
}


MATERIAL.C  (BOOK Sample)
/*
 * (c) Copyright 1993, Silicon Graphics, Inc.
 *               1993, 1994 Microsoft Corporation
 *
 * ALL RIGHTS RESERVED
 *
 * Please refer to OpenGL/readme.txt for additional information
 *
 */
/*
 * material.c
 * This program demonstrates the use of the GL lighting model.
 * Several objects are drawn using different material characteristics.
 * A single light source illuminates the objects.
 */
#include "glos.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>
void myinit(void);
void CALLBACK display(void);
void CALLBACK myReshape(GLsizei w, GLsizei h);
/*  Initialize z-buffer, projection matrix, light source,
 *  and lighting model.  Do not specify a material property here.
 */
void myinit(void)
{
    GLfloat ambient[] = { 0.0, 0.0, 0.0, 1.0 };
    GLfloat diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
    GLfloat specular[] = { 1.0, 1.0, 1.0, 1.0 };
    GLfloat position[] = { 0.0, 3.0, 2.0, 0.0 };
    GLfloat lmodel_ambient[] = { 0.4, 0.4, 0.4, 1.0 };
    GLfloat local_view[] = { 0.0 };
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);
    glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
    glLightfv(GL_LIGHT0, GL_POSITION, position);
    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
    glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, local_view);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glClearColor(0.0, 0.1, 0.1, 0.0);
}
/*  Draw twelve spheres in 3 rows with 4 columns.
 *  The spheres in the first row have materials with no ambient reflection.
 *  The second row has materials with significant ambient reflection.
 *  The third row has materials with colored ambient reflection.
 *
 *  The first column has materials with blue, diffuse reflection only.
 *  The second column has blue diffuse reflection, as well as specular
 *  reflection with a low shininess exponent.
 *  The third column has blue diffuse reflection, as well as specular
 *  reflection with a high shininess exponent (a more concentrated highlight).
 *  The fourth column has materials which also include an emissive component.
 *
 *  glTranslatef() is used to move spheres to their appropriate locations.
 */
void CALLBACK display(void)
{
    GLfloat no_mat[] = { 0.0, 0.0, 0.0, 1.0 };
    GLfloat mat_ambient[] = { 0.7, 0.7, 0.7, 1.0 };
    GLfloat mat_ambient_color[] = { 0.8, 0.8, 0.2, 1.0 };
    GLfloat mat_diffuse[] = { 0.1, 0.5, 0.8, 1.0 };
    GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
    GLfloat no_shininess[] = { 0.0 };
    GLfloat low_shininess[] = { 5.0 };
    GLfloat high_shininess[] = { 100.0 };
    GLfloat mat_emission[] = {0.3, 0.2, 0.2, 0.0};
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
/*  draw sphere in first row, first column
 *  diffuse reflection only; no ambient or specular
 */
    glPushMatrix();
    glTranslatef (-3.75, 3.0, 0.0);
    glMaterialfv(GL_FRONT, GL_AMBIENT, no_mat);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR, no_mat);
    glMaterialfv(GL_FRONT, GL_SHININESS, no_shininess);
    glMaterialfv(GL_FRONT, GL_EMISSION, no_mat);
    auxSolidSphere(1.0);
    glPopMatrix();
/*  draw sphere in first row, second column
 *  diffuse and specular reflection; low shininess; no ambient
 */
    glPushMatrix();
    glTranslatef (-1.25, 3.0, 0.0);
    glMaterialfv(GL_FRONT, GL_AMBIENT, no_mat);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
    glMaterialfv(GL_FRONT, GL_SHININESS, low_shininess);
    glMaterialfv(GL_FRONT, GL_EMISSION, no_mat);
    auxSolidSphere(1.0);
    glPopMatrix();
/*  draw sphere in first row, third column
 *  diffuse and specular reflection; high shininess; no ambient
 */
    glPushMatrix();
    glTranslatef (1.25, 3.0, 0.0);
    glMaterialfv(GL_FRONT, GL_AMBIENT, no_mat);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
    glMaterialfv(GL_FRONT, GL_SHININESS, high_shininess);
    glMaterialfv(GL_FRONT, GL_EMISSION, no_mat);
    auxSolidSphere(1.0);
    glPopMatrix();
/*  draw sphere in first row, fourth column
 *  diffuse reflection; emission; no ambient or specular reflection
 */
    glPushMatrix();
    glTranslatef (3.75, 3.0, 0.0);
    glMaterialfv(GL_FRONT, GL_AMBIENT, no_mat);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR, no_mat);
    glMaterialfv(GL_FRONT, GL_SHININESS, no_shininess);
    glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission);
    auxSolidSphere(1.0);
    glPopMatrix();
/*  draw sphere in second row, first column
 *  ambient and diffuse reflection; no specular
 */
    glPushMatrix();
    glTranslatef (-3.75, 0.0, 0.0);
    glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR, no_mat);
    glMaterialfv(GL_FRONT, GL_SHININESS, no_shininess);
    glMaterialfv(GL_FRONT, GL_EMISSION, no_mat);
    auxSolidSphere(1.0);
    glPopMatrix();
/*  draw sphere in second row, second column
 *  ambient, diffuse and specular reflection; low shininess
 */
    glPushMatrix();
    glTranslatef (-1.25, 0.0, 0.0);
    glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
    glMaterialfv(GL_FRONT, GL_SHININESS, low_shininess);
    glMaterialfv(GL_FRONT, GL_EMISSION, no_mat);
    auxSolidSphere(1.0);
    glPopMatrix();
/*  draw sphere in second row, third column
 *  ambient, diffuse and specular reflection; high shininess
 */
    glPushMatrix();
    glTranslatef (1.25, 0.0, 0.0);
    glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
    glMaterialfv(GL_FRONT, GL_SHININESS, high_shininess);
    glMaterialfv(GL_FRONT, GL_EMISSION, no_mat);
    auxSolidSphere(1.0);
    glPopMatrix();
/*  draw sphere in second row, fourth column
 *  ambient and diffuse reflection; emission; no specular
 */
    glPushMatrix();
    glTranslatef (3.75, 0.0, 0.0);
    glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR, no_mat);
    glMaterialfv(GL_FRONT, GL_SHININESS, no_shininess);
    glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission);
    auxSolidSphere(1.0);
    glPopMatrix();
/*  draw sphere in third row, first column
 *  colored ambient and diffuse reflection; no specular
 */
    glPushMatrix();
    glTranslatef (-3.75, -3.0, 0.0);
    glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient_color);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR, no_mat);
    glMaterialfv(GL_FRONT, GL_SHININESS, no_shininess);
    glMaterialfv(GL_FRONT, GL_EMISSION, no_mat);
    auxSolidSphere(1.0);
    glPopMatrix();
/*  draw sphere in third row, second column
 *  colored ambient, diffuse and specular reflection; low shininess
 */
    glPushMatrix();
    glTranslatef (-1.25, -3.0, 0.0);
    glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient_color);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
    glMaterialfv(GL_FRONT, GL_SHININESS, low_shininess);
    glMaterialfv(GL_FRONT, GL_EMISSION, no_mat);
    auxSolidSphere(1.0);
    glPopMatrix();
/*  draw sphere in third row, third column
 *  colored ambient, diffuse and specular reflection; high shininess
 */
    glPushMatrix();
    glTranslatef (1.25, -3.0, 0.0);
    glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient_color);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
    glMaterialfv(GL_FRONT, GL_SHININESS, high_shininess);
    glMaterialfv(GL_FRONT, GL_EMISSION, no_mat);
    auxSolidSphere(1.0);
    glPopMatrix();
/*  draw sphere in third row, fourth column
 *  colored ambient and diffuse reflection; emission; no specular
 */
    glPushMatrix();
    glTranslatef (3.75, -3.0, 0.0);
    glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient_color);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR, no_mat);
    glMaterialfv(GL_FRONT, GL_SHININESS, no_shininess);
    glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission);
    auxSolidSphere(1.0);
    glPopMatrix();
    glFlush();
}
void CALLBACK myReshape(GLsizei w, GLsizei h)
{
    h = (h == 0) ? 1 : h;
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    if (w <= (h * 2))
    glOrtho (-6.0, 6.0, -3.0*((GLfloat)h*2)/(GLfloat)w,
        3.0*((GLfloat)h*2)/(GLfloat)w, -10.0, 10.0);
    else
    glOrtho (-6.0*(GLfloat)w/((GLfloat)h*2),
        6.0*(GLfloat)w/((GLfloat)h*2), -3.0, 3.0, -10.0, 10.0);
    glMatrixMode(GL_MODELVIEW);
}
/*  Main Loop
 *  Open window with initial window size, title bar,
 *  RGBA display mode, and handle input events.
 */
int main(int argc, char** argv)
{
    auxInitDisplayMode (AUX_SINGLE | AUX_RGB | AUX_DEPTH16);
    auxInitPosition (0, 0, 600, 450);
    auxInitWindow ("Lighting");
    myinit();
    auxReshapeFunc (myReshape);
    auxMainLoop(display);
    return(0);
}


PIPES
The following sample is for the Pipes screensaver included with Windows
®
 NT
ä
.


MAKEFILE  (PIPES Sample)
!include <ntwin32.mak>
all: sspipes.scr
.c.obj:
    $(cc) $(cdebug) $(cflags) $(cvars) $(scall) $*.c
sspipes.res: sspipes.rc sspipes.h
    $(rc) -r sspipes.rc
sspipes.scr: sspipes.res \
                material.obj    \
                objects.obj     \
                pipes.obj       \
                texture.obj     \
                util.obj        \
                sspipes.obj
  $(link) $(linkdebug) $(lflags) -subsystem:windows -entry:mainCRTStartup -machine:$(CPU) -out:$*.scr $** $(guilibs) opengl32.lib glu32.lib glaux.lib scrnsave.lib comdlg32.lib


MATERIAL.H  (PIPES Sample)
/******************************Module*Header*******************************\
* Module Name: material.h
*
* Externals from material.c
*
* Copyright (c) 1994 Microsoft Corporation
*
\**************************************************************************/
// 24 materials (from teapots)
enum {
    EMERALD = 0,
    JADE,
    OBSIDIAN,
    PEARL,
    RUBY,
    TURQUOISE,
    BRASS,
    BRONZE,
    CHROME,
    COPPER,
    GOLD,
    SILVER,
    BLACK_PLASTIC,
    CYAN_PLASTIC,
    GREEN_PLASTIC,
    RED_PLASTIC,
    WHITE_PLASTIC,
    YELLOW_PLASTIC,
    BLACK_RUBBER,
    CYAN_RUBBER,
    GREEN_RUBBER,
    RED_RUBBER,
    WHITE_RUBBER,
    YELLOW_RUBBER
};
// other materials
enum {
    BRIGHT_WHITE = 0,
    LESS_BRIGHT_WHITE,
    WARM_WHITE,
    COOL_WHITE
};
extern void ChooseMaterial();
extern void SpecifyMaterial( unsigned int mIndex );


MATERIAL.C  (PIPES Sample)
/******************************Module*Header*******************************\
* Module Name: material.c
*
* Material selection functions.
*
* Copyright (c) 1994 Microsoft Corporation
*
\**************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <sys/types.h>
#include <time.h>
#include <windows.h>
#include <GL/gl.h>
#include "pipes.h"
#include "objects.h"
#include "util.h"
#include "material.h"
#define NUM_MATERIALS 24
#define NUM_GOOD_MATS 16  // good ones among the 24
#define NUM_TEX_MATS 4  // materials for texture
int goodMaterials[NUM_GOOD_MATS] = {
        EMERALD, JADE, PEARL, RUBY, TURQUOISE, BRASS, BRONZE,
        COPPER, GOLD, SILVER, CYAN_PLASTIC, WHITE_PLASTIC, YELLOW_PLASTIC,
        CYAN_RUBBER, GREEN_RUBBER, WHITE_RUBBER };
/*  materials:  emerald, jade, obsidian, pearl, ruby, turquoise
 *              brass, bronze, chrome, copper, gold, silver
 *              black, cyan, green, red, white, yellow plastic
 *              black, cyan, green, red, white, yellow rubber
    description: ambient(RGB), diffuse(RGB), specular(RGB), shininess
 *
 */
// 'tea' materials, from aux teapots program
static GLfloat teaMaterial[NUM_MATERIALS][10] = {
     0.0215f, 0.1745f, 0.0215f,
        0.07568f, 0.61424f, 0.07568f, 0.633f, 0.727811f, 0.633f, 0.6f,
     0.135f, 0.2225f, 0.1575f,
        0.54f, 0.89f, 0.63f, 0.316228f, 0.316228f, 0.316228f, 0.1f,
     0.05375f, 0.05f, 0.06625f, // XX
        0.18275f, 0.17f, 0.22525f, 0.332741f, 0.328634f, 0.346435f, 0.3f,
     0.25f, 0.20725f, 0.20725f,
        1.0f, 0.829f, 0.829f, 0.296648f, 0.296648f, 0.296648f, 0.088f,
     0.1745f, 0.01175f, 0.01175f,
        0.61424f, 0.04136f, 0.04136f, 0.727811f, 0.626959f, 0.626959f, 0.6f,
     0.1f, 0.18725f, 0.1745f,
        0.396f, 0.74151f, 0.69102f, 0.297254f, 0.30829f, 0.306678f, 0.1f,
     0.329412f, 0.223529f, 0.027451f,
        0.780392f, 0.568627f, 0.113725f, 0.992157f, 0.941176f, 0.807843f,
        0.21794872f,
     0.2125f, 0.1275f, 0.054f,
        0.714f, 0.4284f, 0.18144f, 0.393548f, 0.271906f, 0.166721f, 0.2f,
     0.25f, 0.25f, 0.25f,  // XX
        0.4f, 0.4f, 0.4f, 0.774597f, 0.774597f, 0.774597f, 0.6f,
     0.19125f, 0.0735f, 0.0225f,
        0.7038f, 0.27048f, 0.0828f, 0.256777f, 0.137622f, 0.086014f, 0.1f,
     0.24725f, 0.1995f, 0.0745f,
        0.75164f, 0.60648f, 0.22648f, 0.628281f, 0.555802f, 0.366065f, 0.4f,
     0.19225f, 0.19225f, 0.19225f,
        0.50754f, 0.50754f, 0.50754f, 0.508273f, 0.508273f, 0.508273f, 0.4f,
     0.0f, 0.0f, 0.0f, 0.01f, 0.01f, 0.01f,
        0.50f, 0.50f, 0.50f, .25f,
     0.0f, 0.1f, 0.06f, 0.0f, 0.50980392f, 0.50980392f,
        0.50196078f, 0.50196078f, 0.50196078f, .25f,
     0.0f, 0.0f, 0.0f,
        0.1f, 0.35f, 0.1f, 0.45f, 0.55f, 0.45f, .25f,
     0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, // XX
        0.7f, 0.6f, 0.6f, .25f,
     0.0f, 0.0f, 0.0f, 0.55f, 0.55f, 0.55f,
        0.70f, 0.70f, 0.70f, .25f,
     0.0f, 0.0f, 0.0f, 0.5f, 0.5f, 0.0f,
        0.60f, 0.60f, 0.50f, .25f,
     0.02f, 0.02f, 0.02f, 0.01f, 0.01f, 0.01f, // XX
        0.4f, 0.4f, 0.4f, .078125f,
     0.0f, 0.05f, 0.05f, 0.4f, 0.5f, 0.5f,
        0.04f, 0.7f, 0.7f, .078125f,
     0.0f, 0.05f, 0.0f, 0.4f, 0.5f, 0.4f,
        0.04f, 0.7f, 0.04f, .078125f,
     0.05f, 0.0f, 0.0f, 0.5f, 0.4f, 0.4f,
        0.7f, 0.04f, 0.04f, .078125f,
     0.05f, 0.05f, 0.05f, 0.5f, 0.5f, 0.5f,
        0.7f, 0.7f, 0.7f, .078125f,
     0.05f, 0.05f, 0.0f, 0.5f, 0.5f, 0.4f,
        0.7f, 0.7f, 0.04f, .078125f };
// generally white materials for texturing
static GLfloat texMaterial[NUM_TEX_MATS][10] = {
// bright white
     0.2f, 0.2f, 0.2f,
        1.0f, 1.0f, 1.0f, 0.8f, 0.8f, 0.8f, 0.4f,
// less bright white
     0.2f, 0.2f, 0.2f,
        0.8f, 0.8f, 0.8f, 0.5f, 0.5f, 0.5f, 0.35f,
// warmish white
     0.3f, 0.2f, 0.2f,
        1.0f, 0.9f, 0.8f, 0.4f, 0.2f, 0.2f, 0.35f,
// coolish white
     0.2f, 0.2f, 0.3f,
        0.8f, 0.9f, 1.0f, 0.2f, 0.2f, 0.4f, 0.35f
};
static void SetMaterial( GLfloat *pMat )
{
    glMaterialfv (GL_FRONT, GL_AMBIENT, pMat);
    glMaterialfv (GL_BACK, GL_AMBIENT, pMat);
    pMat += 3;
    glMaterialfv (GL_FRONT, GL_DIFFUSE, pMat);
    glMaterialfv (GL_BACK, GL_DIFFUSE, pMat);
    pMat += 3;
    glMaterialfv (GL_FRONT, GL_SPECULAR, pMat);
    glMaterialfv (GL_BACK, GL_SPECULAR, pMat);
    pMat++;
    glMaterialf (GL_FRONT, GL_SHININESS, *pMat*128.0f);
    glMaterialf (GL_BACK, GL_SHININESS, *pMat*128.0f);
}
void SpecifyMaterial( unsigned int mIndex )
{
    if( mIndex >= NUM_MATERIALS )
mIndex = NUM_MATERIALS - 1;
    SetMaterial( &teaMaterial[mIndex][0] );
}
void ChooseMaterial()
{
    static int numMat = NUM_GOOD_MATS;
    if( bTexture ) // choose a white material
SetMaterial( &texMaterial[mfRand(NUM_TEX_MATS)][0] );
    else {
        // randomnly pick new material
        SetMaterial( &teaMaterial[ goodMaterials[mfRand(numMat)] ][0] );
    }
}


OBJECTS.H  (PIPES Sample)
/******************************Module*Header*******************************\
* Module Name: objects.h
*
* Externals from objects.c
*
* Copyright (c) 1994 Microsoft Corporation
*
\**************************************************************************/
extern GLint ball;
extern GLint elbows[4], balls[4];
extern GLint shortPipe, longPipe;
extern void BuildLists(void);


OBJECTS.C  (PIPES Sample)
/******************************Module*Header*******************************\
* Module Name: object.c
*
* Creates command lists for pipe primitives
*
* Copyright (c) 1994 Microsoft Corporation
*
\**************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <windows.h>
#include <GL/gl.h>
#include "objects.h"
#include "pipes.h"
#include "texture.h"
#define PI 3.14159265358979323846f
#define ROOT_TWO 1.414213562373f
GLint ball;
GLint shortPipe, longPipe;
GLint elbows[4];
GLint balls[4];
GLint Slices;
typedef struct strpoint3d {
    GLfloat x;
    GLfloat y;
    GLfloat z;
} POINT3D;
typedef struct _MATRIX {
    GLfloat M[4][4];
} MATRIX;
#define ZERO_EPS    0.00000001
// most of these transform routines from 'flying objects' screen saver
void xformPoint(POINT3D *ptOut, POINT3D *ptIn, MATRIX *mat)
{
    double x, y, z;
    x = (ptIn->x * mat->M[0][0]) + (ptIn->y * mat->M[0][1]) +
        (ptIn->z * mat->M[0][2]) + mat->M[0][3];
    y = (ptIn->x * mat->M[1][0]) + (ptIn->y * mat->M[1][1]) +
        (ptIn->z * mat->M[1][2]) + mat->M[1][3];
    z = (ptIn->x * mat->M[2][0]) + (ptIn->y * mat->M[2][1]) +
        (ptIn->z * mat->M[2][2]) + mat->M[2][3];
    ptOut->x = (float) x;
    ptOut->y = (float) y;
    ptOut->z = (float) z;
}
static void zeroMatrix( MATRIX *m )
{
    GLint i, j;
    for( j = 0; j < 4; j ++ ) {
for( i = 0; i < 4; i ++ ) {
    m->M[i][j] = 0.0f;
}
    }
}
static void matrixMult( MATRIX *m1, MATRIX *m2, MATRIX *m3 )
{
    GLint i, j;
    for( j = 0; j < 4; j ++ ) {
for( i = 0; i < 4; i ++ ) {
    m1->M[j][i] = m2->M[j][0] * m3->M[0][i] +
  m2->M[j][1] * m3->M[1][i] +
  m2->M[j][2] * m3->M[2][i] +
  m2->M[j][3] * m3->M[3][i];
}
    }
}
void matrixIdent(MATRIX *mat)
{
    mat->M[0][0] = 1.0f; mat->M[0][1] = 0.0f;
    mat->M[0][2] = 0.0f; mat->M[0][3] = 0.0f;
    mat->M[1][0] = 0.0f; mat->M[1][1] = 1.0f;
    mat->M[1][2] = 0.0f; mat->M[1][3] = 0.0f;
    mat->M[2][0] = 0.0f; mat->M[2][1] = 0.0f;
    mat->M[2][2] = 1.0f; mat->M[2][3] = 0.0f;
    mat->M[3][0] = 0.0f; mat->M[3][1] = 0.0f;
    mat->M[3][2] = 0.0f; mat->M[3][3] = 1.0f;
}
void matrixTranslate(MATRIX *m, float xTrans, float yTrans,
                     float zTrans)
{
    m->M[0][3] = (float) xTrans;
    m->M[1][3] = (float) yTrans;
    m->M[2][3] = (float) zTrans;
}
void matrixRotate(MATRIX *m, double xTheta, double yTheta, double zTheta)
{
    float xScale, yScale, zScale;
    float sinX, cosX;
    float sinY, cosY;
    float sinZ, cosZ;
    xScale = m->M[0][0];
    yScale = m->M[1][1];
    zScale = m->M[2][2];
    sinX = (float) sin(xTheta);
    cosX = (float) cos(xTheta);
    sinY = (float) sin(yTheta);
    cosY = (float) cos(yTheta);
    sinZ = (float) sin(zTheta);
    cosZ = (float) cos(zTheta);
    m->M[0][0] = (float) ((cosZ * cosY) * xScale);
    m->M[0][1] = (float) ((cosZ * -sinY * -sinX + sinZ * cosX) * yScale);
    m->M[0][2] = (float) ((cosZ * -sinY * cosX + sinZ * sinX) * zScale);
    m->M[1][0] = (float) (-sinZ * cosY * xScale);
    m->M[1][1] = (float) ((-sinZ * -sinY * -sinX + cosZ * cosX) * yScale);
    m->M[1][2] = (float) ((-sinZ * -sinY * cosX + cosZ * sinX) * zScale);
    m->M[2][0] = (float) (sinY * xScale);
    m->M[2][1] = (float) (cosY * -sinX * yScale);
    m->M[2][2] = (float) (cosY * cosX * zScale);
}
// rotate circle around x-axis, with edge attached to anchor
static void TransformCircle(
    float angle,
    POINT3D *inPoint,
    POINT3D *outPoint,
    GLint num,
    POINT3D *anchor )
{
    MATRIX matrix1, matrix2, matrix3;
    int i;
    // translate anchor point to origin
    matrixIdent( &matrix1 );
    matrixTranslate( &matrix1, -anchor->x, -anchor->y, -anchor->z );
    // rotate by angle, cw around x-axis
    matrixIdent( &matrix2 );
    matrixRotate( &matrix2, (double) -angle, 0.0, 0.0 );
    // concat these 2
    matrixMult( &matrix3, &matrix2, &matrix1 );
    // translate back
    matrixIdent( &matrix2 );
    matrixTranslate( &matrix2,  anchor->x,  anchor->y,  anchor->z );
    // concat these 2
    matrixMult( &matrix1, &matrix2, &matrix3 );
    // transform all the points, + center
    for( i = 0; i < num; i ++, outPoint++, inPoint++ ) {
xformPoint( outPoint, inPoint, &matrix1 );
    }
}
static void normalize( POINT3D *n )
{
    float len;
    len = (n->x * n->x) + (n->y * n->y) + (n->z * n->z);
    if (len > ZERO_EPS)
        len = (float) (1.0 / sqrt(len));
    else
        len = 1.0f;
    n->x *= len;
    n->y *= len;
    n->z *= len;
}
static void CalcNormals( POINT3D *p, POINT3D *n, POINT3D *center,
 int num )
{
    int i;
    for( i = 0; i < num; i ++, n++, p++ ) {
n->x = p->x - center->x;
n->y = p->y - center->y;
n->z = p->z - center->z;
normalize( n );
    }
}
/*----------------------------------------------------------------------\
|    MakeQuadStrip()
|
|
- builds quadstrip between 2 rows of points. pA points to one
|
|
  row of points, and pB to the next rotated row.  Because
|
|
  the rotation has previously been defined CCW around the
|
|
  x-axis, using an A-B sequence will result in CCW quads
|
|
|
\----------------------------------------------------------------------*/
static void MakeQuadStrip
(
    POINT3D *pA,
    POINT3D *pB,
    POINT3D *nA,
    POINT3D *nB,
    GLfloat *tex_s,
    GLfloat *tex_t,
    GLint slices
)
{
    GLint i;
    glBegin( GL_QUAD_STRIP );
    for( i = 0; i < slices; i ++ ) {
glNormal3fv( (GLfloat *) nA++ );
if( bTextureCoords )
    glTexCoord2f( tex_s[0], *tex_t );
glVertex3fv( (GLfloat *) pA++ );
glNormal3fv( (GLfloat *) nB++ );
if( bTextureCoords )
    glTexCoord2f( tex_s[1], *tex_t++ );
glVertex3fv( (GLfloat *) pB++ );
    }
    glEnd();
}
#define CACHE_SIZE
100
/*----------------------------------------------------------------------\
|    BuildElbows()
|
|
- builds elbows, by rotating a circle in the y=r plane
|
|
  centered at (0,r,-r), CW around the x-axis at anchor pt.
|
|
  (r = radius of the circle)
|
|
- rotation is 90.0 degrees, ending at circle in z=0 plane,
|
|
  centered at origin.
|
|
- in order to 'mate' texture coords with the cylinders
|
|
  generated with glu, we generate 4 elbows, each corresponding
|
|
  to the 4 possible CW 90 degree orientations of the start point|
|
  for each circle.
|
|
- We call this start point the 'notch'.  If we characterize
|
|
  each notch by the axis it points down in the starting and
|
|
  ending circles of the elbow, then we get the following axis
|
|
  pairs for our 4 notches:
|
|
- +z,+y
|
|
- +x,+x
|
|
- -z,-y
|
|
- -x,-x
|
|
  Since the start of the elbow always points down +y, the 4
|
|
  start notches give all possible 90.0 degree orientations
|
|
  around y-axis.
|
|
- We can keep track of the current 'notch' vector to provide
|
|
  proper mating between primitives.
|
|
- Each circle of points is described CW from the start point,
|
|
  assuming looking down the +y axis(+y direction).
|
|
- texture 's' starts at 0.0, and goes to 2.0*r/divSize at
|
|
  end of the elbow.  (Then a short pipe would start with this
|
|
  's', and run it to 1.0).
|
|
|
\----------------------------------------------------------------------*/
static void BuildElbows(void)
{
    GLfloat radius = vc.radius;
    GLfloat angle, startAng;
    GLint slices = Slices;
    GLint stacks = Slices / 2;
    GLint numPoints;
    GLfloat start_s, end_s, delta_s;
    POINT3D pi[CACHE_SIZE]; // initial row of points + center
    POINT3D p0[CACHE_SIZE]; // 2 rows of points
    POINT3D p1[CACHE_SIZE];
    POINT3D n0[CACHE_SIZE]; // 2 rows of normals
    POINT3D n1[CACHE_SIZE];
    GLfloat tex_t[CACHE_SIZE];// 't' texture coords
    GLfloat tex_s[2];  // 's' texture coords
    POINT3D center;  // center of circle
    POINT3D anchor;  // where circle is anchored
    POINT3D *pA, *pB, *nA, *nB;
    int i, j;
    // 's' texture range
    start_s = 0.0f;
    end_s = texRep.x * 2.0f * vc.radius / vc.divSize;
    delta_s = end_s;
    // calculate 't' texture coords
    for( i = 0; i <= slices; i ++ ) {
tex_t[i] = (GLfloat) i * texRep.y / slices;
    }
    numPoints = slices + 1;
    for( j = 0; j < 4; j ++ ) {
// starting angle increment 90.0 degrees each time
startAng = j * PI / 2;
        // calc initial circle of points for circle centered at 0,r,-r
        // points start at (0,r,0), and rotate circle CCW
        for( i = 0; i <= slices; i ++ ) {
    angle = startAng + (2 * PI * i / slices);
    pi[i].x = radius * (float) sin(angle);
    pi[i].y = radius;
    // translate z by -r, cuz these cos calcs are for circle at origin
    pi[i].z = radius * (float) cos(angle) - radius;
        }
// center point, tacked onto end of circle of points
pi[i].x =  0.0f;
pi[i].y =  radius;
pi[i].z = -radius;
center = pi[i];
// anchor point
anchor.x = anchor.z = 0.0f;
anchor.y = radius;
// calculate initial normals
CalcNormals( pi, n0, &center, numPoints );
// initial 's' texture coordinate
tex_s[0] = start_s;
// setup pointers
pA = pi;
pB = p0;
nA = n0;
nB = n1;
// now iterate throught the stacks
glNewList(elbows[j], GL_COMPILE);
        for( i = 1; i <= stacks; i ++ ) {
    // ! this angle must be negative, for correct vertex orientation !
    angle = - 0.5f * PI * i / stacks;
    // transform to get next circle of points + center
    TransformCircle( angle, pi, pB, numPoints+1, &anchor );
    // calculate normals
    center = pB[numPoints];
    CalcNormals( pB, nB, &center, numPoints );
    // calculate next 's' texture coord
    tex_s[1] = (GLfloat) start_s + delta_s * i / stacks;
    // now we've got points and normals, ready to be quadstrip'd
    MakeQuadStrip( pA, pB, nA, nB, tex_s, tex_t, numPoints );
    // reset pointers
    pA = pB;
    nA = nB;
    pB = (pB == p0) ? p1 : p0;
    nB = (nB == n0) ? n1 : n0;
    tex_s[0] = tex_s[1];
        }
        glEndList();
    }
}
/*----------------------------------------------------------------------\
|    BuildBallJoints()
|
|
- These are very similar to the elbows, in that
the starting
|
|
  and ending positions are almost identical.   The difference
|
|
  here is that the circles in the sweep describe a sphere as
|
|
  they are rotated.
|
|
- The starting circle has the same diameter as a pipe, but
|
|
  instead of starting at a distance of 1.0*r from the node
|
|
  centre, as in the elbow, it starts at the circle that
|
|
  is the intersection of the standard Ball object and the
|
|
  pipe.  The Ball's size was chosen to have a radius such
|
|
  that it would encompass all intersection points between 2
|
|
  pipes at right angles, so that there wouldn't be 'any sharp
|
|
  stuff sticking out of the Ball'.  But we'll try using a
|
|
  starting and ending circle coincident with the ends of the
|
|
  pipes, since this will make life easier.  If it doesn't work,
|
|
  we can then increase the sphere radius and futz around with
|
|
  the starting and ending texture coords (which is why we're
|
|
  going to all this trouble in the first place)
|
|
  same as the standard Ball radius.  Therefore we use sphere
|
|
  radius of (2)**0.5 * r.
|
|
|
\----------------------------------------------------------------------*/
static void BuildBallJoints(void)
{
    GLfloat ballRadius;
    GLfloat angle, delta_a, startAng, theta;
    GLint slices = Slices;
    GLint stacks = Slices; // same # as standard Ball
    GLint numPoints;
    GLfloat start_s, end_s, delta_s;
    POINT3D pi0[CACHE_SIZE]; // 2 circles of untransformed points
    POINT3D pi1[CACHE_SIZE];
    POINT3D p0[CACHE_SIZE]; // 2 rows of transformed points
    POINT3D p1[CACHE_SIZE];
    POINT3D n0[CACHE_SIZE]; // 2 rows of normals
    POINT3D n1[CACHE_SIZE];
    float   r[CACHE_SIZE];  // radii of the circles
    GLfloat tex_t[CACHE_SIZE];// 't' texture coords
    GLfloat tex_s[2];  // 's' texture coords
    POINT3D center;  // center of circle
    POINT3D anchor;  // where circle is anchored
    POINT3D *pA, *pB, *nA, *nB;
    int i, j, k;
    // calculate the radii for each circle in the sweep, where
    // r[i] = y = sin(angle)/r
    angle = PI / 4;  // first radius always at 45.0 degrees
    delta_a = (PI / 2.0f) / stacks;
    ballRadius = ROOT_TWO * vc.radius;
    for( i = 0; i <= stacks; i ++, angle += delta_a ) {
r[i] = (float) sin(angle) * ballRadius;
    }
    // calculate 't' texture coords
    for( i = 0; i <= slices; i ++ ) {
tex_t[i] = (GLfloat) i * texRep.y / slices;
    }
    // 's' texture range
    start_s = 0.0f;
    end_s = texRep.x * 2.0f * vc.radius / vc.divSize;
    delta_s = end_s;
    numPoints = slices + 1;
    // unlike the elbow, the center for the ball joint is constant
    center.x = center.y = 0.0f;
    center.z = -vc.radius;
    for( j = 0; j < 4; j ++ ) {
// starting angle along circle, increment 90.0 degrees each time
startAng = j * PI / 2;
        // calc initial circle of points for circle centered at 0,r,-r
        // points start at (0,r,0), and rotate circle CCW
delta_a = 2 * PI / slices;
        for( i = 0, theta = startAng; i <= slices; i ++, theta += delta_a ) {
    pi0[i].x = r[0] * (float) sin(theta);
    pi0[i].y = vc.radius;
    // translate z by -r, cuz these cos calcs are for circle at origin
    pi0[i].z = r[0] * (float) cos(theta) - r[0];
        }
// anchor point
anchor.x = anchor.z = 0.0f;
anchor.y = vc.radius;
// calculate initial normals
CalcNormals( pi0, n0, &center, numPoints );
// initial 's' texture coordinate
tex_s[0] = start_s;
// setup pointers
pA = pi0; // circles of transformed points
pB = p0;
nA = n0; // circles of transformed normals
nB = n1;
// now iterate throught the stacks
glNewList(balls[j], GL_COMPILE);
        for( i = 1; i <= stacks; i ++ ) {
    // ! this angle must be negative, for correct vertex orientation !
    angle = - 0.5f * PI * i / stacks;
            // calc the next circle of untransformed points into pi1[]
            for( k = 0, theta = startAng; k <= slices; k ++, theta+=delta_a ) {
        pi1[k].x = r[i] * (float) sin(theta);
        pi1[k].y = vc.radius;
        // translate z by -r, cuz calcs are for circle at origin
        pi1[k].z = r[i] * (float) cos(theta) - r[i];
            }
    // rotate cirle of points to next position
    TransformCircle( angle, pi1, pB, numPoints, &anchor );
    // calculate normals
    CalcNormals( pB, nB, &center, numPoints );
    // calculate next 's' texture coord
    tex_s[1] = (GLfloat) start_s + delta_s * i / stacks;
    // now we've got points and normals, ready to be quadstrip'd
    MakeQuadStrip( pA, pB, nA, nB, tex_s, tex_t, numPoints );
    // reset pointers
    pA = pB;
    nA = nB;
    pB = (pB == p0) ? p1 : p0;
    nB = (nB == n0) ? n1 : n0;
    tex_s[0] = tex_s[1];
        }
        glEndList();
    }
}
// 'glu' routines
#ifdef _EXTENSIONS_
#define COS cosf
#define SIN sinf
#define SQRT sqrtf
#else
#define COS cos
#define SIN sin
#define SQRT sqrt
#endif
/*----------------------------------------------------------------------\
|    pipeCylinder()
|
|
|
\----------------------------------------------------------------------*/
static void pipeCylinder( GLfloat radius, GLfloat height, GLint slices,
GLint stacks, GLfloat start_s, GLfloat end_s )
{
    GLint i,j;
    GLfloat sinCache[CACHE_SIZE];
    GLfloat cosCache[CACHE_SIZE];
    GLfloat sinCache2[CACHE_SIZE];
    GLfloat cosCache2[CACHE_SIZE];
    GLfloat angle;
    GLfloat zLow, zHigh;
    GLfloat zNormal;
    GLfloat delta_s;
    if (slices >= CACHE_SIZE) slices = CACHE_SIZE-1;
    zNormal = 0.0f;
    delta_s = end_s - start_s;
    for (i = 0; i < slices; i++) {
angle = 2 * PI * i / slices;
sinCache2[i] = (float) SIN(angle);
cosCache2[i] = (float) COS(angle);
sinCache[i] = (float) SIN(angle);
cosCache[i] = (float) COS(angle);
    }
    sinCache[slices] = sinCache[0];
    cosCache[slices] = cosCache[0];
    sinCache2[slices] = sinCache2[0];
    cosCache2[slices] = cosCache2[0];
for (j = 0; j < stacks; j++) {
    zLow = j * height / stacks;
    zHigh = (j + 1) * height / stacks;
    glBegin(GL_QUAD_STRIP);
    for (i = 0; i <= slices; i++) {
    glNormal3f(sinCache2[i], cosCache2[i], zNormal);
    if (bTextureCoords) {
glTexCoord2f( (float) start_s + delta_s * j / stacks,
      (float) i * texRep.y / slices );
    }
    glVertex3f(radius * sinCache[i],
    radius * cosCache[i], zLow);
    if (bTextureCoords) {
glTexCoord2f( (float) start_s + delta_s*(j+1) / stacks,
      (float) i * texRep.y / slices );
    }
    glVertex3f(radius * sinCache[i],
    radius * cosCache[i], zHigh);
    }
    glEnd();
}
}
/*----------------------------------------------------------------------\
|    pipeSphere()
|
|
|
\----------------------------------------------------------------------*/
void pipeSphere(GLfloat radius, GLint slices, GLint stacks,
GLfloat start_s, GLfloat end_s)
{
    GLint i,j;
    GLfloat sinCache1a[CACHE_SIZE];
    GLfloat cosCache1a[CACHE_SIZE];
    GLfloat sinCache2a[CACHE_SIZE];
    GLfloat cosCache2a[CACHE_SIZE];
    GLfloat sinCache1b[CACHE_SIZE];
    GLfloat cosCache1b[CACHE_SIZE];
    GLfloat sinCache2b[CACHE_SIZE];
    GLfloat cosCache2b[CACHE_SIZE];
    GLfloat angle;
    GLfloat zLow, zHigh;
    GLfloat sintemp1, sintemp2, sintemp3, sintemp4;
    GLfloat costemp3, costemp4;
    GLfloat delta_s;
    GLint start, finish;
    if (slices >= CACHE_SIZE) slices = CACHE_SIZE-1;
    if (stacks >= CACHE_SIZE) stacks = CACHE_SIZE-1;
    // invert sense of s - it seems the glu sphere is not built similarly
    // to the glu cylinder
    // (this probably means stacks don't grow along +z - check it out)
    delta_s = start_s;
    start_s = end_s;
    end_s = delta_s;
    delta_s = end_s - start_s;
    /* Cache is the vertex locations cache */
    /* Cache2 is the various normals at the vertices themselves */
    for (i = 0; i < slices; i++) {
angle = 2 * PI * i / slices;
sinCache1a[i] = (float) SIN(angle);
cosCache1a[i] = (float) COS(angle);
    sinCache2a[i] = sinCache1a[i];
    cosCache2a[i] = cosCache1a[i];
    }
    for (j = 0; j <= stacks; j++) {
angle = PI * j / stacks;
sinCache2b[j] = (float) SIN(angle);
cosCache2b[j] = (float) COS(angle);
sinCache1b[j] = radius * (float) SIN(angle);
cosCache1b[j] = radius * (float) COS(angle);
    }
    /* Make sure it comes to a point */
    sinCache1b[0] = 0.0f;
    sinCache1b[stacks] = 0.0f;
    sinCache1a[slices] = sinCache1a[0];
    cosCache1a[slices] = cosCache1a[0];
sinCache2a[slices] = sinCache2a[0];
cosCache2a[slices] = cosCache2a[0];
/* Do ends of sphere as TRIANGLE_FAN's (if not bTextureCoords)
** We don't do it when bTextureCoords because we need to respecify the
** texture coordinates of the apex for every adjacent vertex (because
** it isn't a constant for that point)
*/
if (!bTextureCoords) {
    start = 1;
    finish = stacks - 1;
    /* Low end first (j == 0 iteration) */
    sintemp2 = sinCache1b[1];
    zHigh = cosCache1b[1];
sintemp3 = sinCache2b[1];
costemp3 = cosCache2b[1];
glNormal3f(sinCache2a[0] * sinCache2b[0],
cosCache2a[0] * sinCache2b[0],
cosCache2b[0]);
    glBegin(GL_TRIANGLE_FAN);
    glVertex3f(0.0f, 0.0f, radius);
for (i = slices; i >= 0; i--) {
glNormal3f(sinCache2a[i] * sintemp3,
cosCache2a[i] * sintemp3,
costemp3);
    glVertex3f(sintemp2 * sinCache1a[i],
    sintemp2 * cosCache1a[i], zHigh);
}
    glEnd();
    /* High end next (j == stacks-1 iteration) */
    sintemp2 = sinCache1b[stacks-1];
    zHigh = cosCache1b[stacks-1];
sintemp3 = sinCache2b[stacks-1];
costemp3 = cosCache2b[stacks-1];
glNormal3f(sinCache2a[stacks] * sinCache2b[stacks],
cosCache2a[stacks] * sinCache2b[stacks],
cosCache2b[stacks]);
    glBegin(GL_TRIANGLE_FAN);
    glVertex3f(0.0f, 0.0f, -radius);
for (i = 0; i <= slices; i++) {
glNormal3f(sinCache2a[i] * sintemp3,
cosCache2a[i] * sintemp3,
costemp3);
    glVertex3f(sintemp2 * sinCache1a[i],
    sintemp2 * cosCache1a[i], zHigh);
}
    glEnd();
} else {
    start = 0;
    finish = stacks;
}
for (j = start; j < finish; j++) {
    zLow = cosCache1b[j];
    zHigh = cosCache1b[j+1];
    sintemp1 = sinCache1b[j];
    sintemp2 = sinCache1b[j+1];
    sintemp3 = sinCache2b[j+1];
    costemp3 = cosCache2b[j+1];
    sintemp4 = sinCache2b[j];
    costemp4 = cosCache2b[j];
    glBegin(GL_QUAD_STRIP);
    for (i = 0; i <= slices; i++) {
    glNormal3f(sinCache2a[i] * sintemp3,
    cosCache2a[i] * sintemp3,
    costemp3);
    if (bTextureCoords) {
glTexCoord2f( (float) start_s + delta_s*(j+1) / stacks,
      (float) i * texRep.y / slices );
    }
    glVertex3f(sintemp2 * sinCache1a[i],
    sintemp2 * cosCache1a[i], zHigh);
    glNormal3f(sinCache2a[i] * sintemp4,
    cosCache2a[i] * sintemp4,
    costemp4);
    if (bTextureCoords) {
glTexCoord2f( (float) start_s + delta_s * j / stacks,
      (float) i * texRep.y / slices );
    }
    glVertex3f(sintemp1 * sinCache1a[i],
    sintemp1 * cosCache1a[i], zLow);
    }
    glEnd();
}
}
/*----------------------------------------------------------------------\
|    BuildBall()
|
|
- builds sphere along the +z axis, by calling pipesSphere()
|
|
- What is calculated here is the starting and ending 's' values
|
|
  for texturing.  This primitive will only be used for start
|
|
  and end caps when texturing.  As such, the intersection points|
|
  where the sphere meets the pipe must be calculated to provide
|
|
  a smooth texturing transition.  Therefore, at the initial
|
|
  intersection point, we want s=0.0, and at the final point
|
|
  we want s= texRep.x * 2.0f * vc.radius / vc.divSize;
|
|
  But, since this will result in a negative start_s, we have
|
|
  to adjust these values to be positive - therefore add
|
|
  a value to each 's' to compensate for this.
|
|
|
\----------------------------------------------------------------------*/
static void BuildBall(void)
{
    GLfloat radius = ROOT_TWO*vc.radius;
    GLint stacks = Slices;
    GLfloat start_s;
    GLfloat comp_s;
    GLfloat end_s;
    if( bTextureCoords ) {
start_s = - texRep.x * (ROOT_TWO - 1.0f) * vc.radius / vc.divSize;
end_s = texRep.x * (2.0f + (ROOT_TWO - 1.0f)) * vc.radius / vc.divSize;
comp_s = (int) ( - start_s ) + 1.0f;
start_s += comp_s;
end_s += comp_s;
    }
    glNewList(ball, GL_COMPILE);
        pipeSphere( radius, Slices, stacks, start_s, end_s );
    glEndList();
}
/*----------------------------------------------------------------------\
|    BuildShortPipe()
|
|
- builds a long cylinder along the +z axis, from the origin
|
|
- a quad stack starts at point along +y axis, and rotate CW
|
|
- texture coord 't' is 1.0 at starting point, reducing to 0.0
|
|
  after full rotation.
|
|
- texture 's' is 0.0 at start of cylinder, to 1.0 at end
|
|
|
\----------------------------------------------------------------------*/
static void BuildShortPipe(void)
{
    GLfloat radius = vc.radius;
    GLfloat height = vc.divSize - 2*vc.radius;
    GLint stacks = Slices;
    GLfloat start_s;
    float end_s = (float) texRep.y;
    //start_s = 1.0f - height / vc.divSize;
    start_s = texRep.x * (1.0f - height / vc.divSize);
    glNewList(shortPipe, GL_COMPILE);
    pipeCylinder( radius, height, Slices, stacks, start_s, end_s );
    glEndList();
}
static void BuildLongPipe(void)
{
    GLfloat radius = vc.radius;
    GLfloat height = vc.divSize;
    GLint stacks = Slices;
    float end_s = (float) texRep.y;
    glNewList(longPipe, GL_COMPILE);
    pipeCylinder( radius, height, Slices, stacks, 0.0f, end_s );
    glEndList();
}
void BuildLists(void)
{
    GLint i;
    Slices = (tessLevel+2) * 4;
    ball = glGenLists(1);
    shortPipe = glGenLists(1);
    longPipe = glGenLists(1);
    for( i = 0; i < 4; i ++ )
elbows[i] = glGenLists(1);
    if( bTextureCoords ) {
        for( i = 0; i < 4; i ++ )
    balls[i] = glGenLists(1);
        BuildBallJoints();
    }
    BuildElbows();
    BuildBall();
    BuildShortPipe();
    BuildLongPipe();
}


PIPES.H  (PIPES Sample)
/******************************Module*Header*******************************\
* Module Name: pipes.h
*
* Include file for accessing pipelib functionality
*
* Copyright (c) 1994 Microsoft Corporation
*
\**************************************************************************/
typedef struct {
   float x,y,z;
} mfPoint3df;
typedef struct {
   int x,y,z;
} mfPoint3di;
typedef struct {
   float width, height, depth;
} mfSize3df;
typedef struct {
   int width, height, depth;
} mfSize3di;
typedef struct {
   float x,y;
} mfPoint2df;
typedef struct {
   int x,y;
} mfPoint2di;
typedef struct {
   float width, height;
} mfSize2df;
typedef struct {
   int width, height;
} mfSize2di;
enum {
    MF_MANUAL = 0,
    MF_STEP,
    MF_AUTO
};
// These are absolute directions, with origin in center of screen,
// looking down -z
#define NUM_DIRS 6
enum {
    PLUS_X = 0,
    MINUS_X,
    PLUS_Y,
    MINUS_Y,
    PLUS_Z,
    MINUS_Z
};
#define RANDOM_DIR
-1
// styles for pipe joints
enum {
    ELBOWS = 0,
    BALLS,
    EITHER
};
#define NUM_JOINT_STYLES
3
typedef struct {
    GLboolean   empty;
} Node;
#define MAX_TESS 3
// texture quality level
enum {
    TEX_LOW = 0,
    TEX_MID,
    TEX_HIGH
};
// viewing context stuff
typedef struct {
    float viewAngle;
// field of view angle for height
    float aspectRatio;
// width/height
    float zNear;
// near z clip value
    float zFar;
// far z clip value
} Perspective;  // perspective view description
typedef struct {
    float
zTrans;
// z translation
    float
viewDist;
// viewing distance, usually -zTrans
    int
numDiv;
// # grid divisions in x,y,z
    float
divSize;
// distance between divisions
    mfSize2di
winSize;        // window size in pixels
    mfPoint3di
numNodes;       // number of nodes in x,y,z
    mfPoint3df
world;          // view area in world space
    Perspective persp;
// perspective view description
    float
radius;
// pipe radius
    mfPoint3di
curPos;         // current x,y stray in cylinder units
    Node
*curNode;       // ptr to current node
    int
numPipes;
// number of pipes/frame
    float
yRot;
// current yRotation
} VC;  // viewing context
extern VC vc;
extern GLenum polyMode;
extern GLenum dithering;
extern GLenum shade;
extern GLenum doStipple;
extern GLenum projMode;
extern int drawMode;
extern int jointStyle;
extern int bCycleJointStyles;
extern int tessLevel;
extern int textureQuality;
extern int bTexture;
extern int bTextureCoords;
extern GLubyte stipple[];
int (*drawNext)( int );
extern void ChooseMaterial();
extern void InitPipes(int mode);
//extern void ResetPipes();
extern void SetProjMatrix();
extern void ReshapePipes(int width, int height);
extern void DrawPipes(void);
extern int InitBMPTexture( char *, int );


PIPES.C  (PIPES Sample)
/******************************Module*Header*******************************\
* Module Name: pipes.c
*
* Core pipes code
*
* Copyright (c) 1994 Microsoft Corporation
*
\**************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <sys/types.h>
#include <time.h>
#include <windows.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include "gl/glaux.h"
#include "pipes.h"
#include "objects.h"
#include "material.h"
#include "util.h"
GLenum polyMode;
GLenum dithering;
GLenum shade;
GLenum projMode;
int drawMode;
int bTexture;
int bTextureCoords;
enum {
    ELBOW_JOINT = 0,
    BALL_JOINT
};
#define TEAPOT 66
// these attributes correspond to screen-saver dialog items
int jointStyle;
int bCycleJointStyles;
int tessLevel;
int textureQuality;
// initial viewing context
#define NUM_DIV 16              // divisions in window in longest dimension
#define NUM_NODE (NUM_DIV - 1)  // num nodes in longest dimension
VC vc;
VC *vp;
// for now, static array
static Node node[NUM_NODE][NUM_NODE][NUM_NODE];
static int lastDir;  // last direction taken by pipe
static int notchVec; // current pipe notch vector
// forward decl'ns
void ResetPipes(void);
void DrawPipes(void);
int (*drawNext)( int );
/*-----------------------------------------------------------------------
|                                                                       |
|    InitPipes( int mode ):                                             |
|       - One time init stuff                                           |
|                                                                       |
-----------------------------------------------------------------------*/
void InitPipes( int mode )
{
    static float ambient[] = {0.1f, 0.1f, 0.1f, 1.0f};
    static float diffuse[] = {1.0f, 1.0f, 1.0f, 1.0f};
    static float position[] = {90.0f, 90.0f, 150.0f, 0.0f};
    static float lmodel_ambient[] = {1.0f, 1.0f, 1.0f, 1.0f};
    time_t timer;
    time( &timer );
    srand( timer );
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glFrontFace(GL_CCW);
    glDepthFunc(GL_LEQUAL);
    glEnable(GL_DEPTH_TEST);
    glEnable( GL_AUTO_NORMAL ); // needed for GL_MAP2_VERTEX (tea)
    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
    glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
    glLightfv(GL_LIGHT0, GL_POSITION, position);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    ChooseMaterial();
    glCullFace(GL_BACK);
    glEnable(GL_CULL_FACE);
    dithering = GL_TRUE;
    shade = GL_TRUE;
    polyMode = GL_BACK;
    projMode = GL_TRUE;
    drawMode = mode;
    vp = &vc;
    // set some initial viewing and size params
    vc.zTrans = -75.0f;
    vc.viewDist = -vc.zTrans;
    vc.numDiv = NUM_DIV;
    vc.radius = 1.0f;
    vc.divSize = 7.0f;
    vc.persp.viewAngle = 90.0f;
    vc.persp.zNear = 1.0f;
    vc.yRot = 0.0f;
    if( bTexture )
vc.numPipes = 3;
    else
vc.numPipes = 5;
    // Build objects
    BuildLists();
}
/*-----------------------------------------------------------------------
|                                                                       |
|    SetProjMatrix();                                                   |
|       - sets ortho or perspective viewing dimensions                  |
|                                                                       |
-----------------------------------------------------------------------*/
void SetProjMatrix()
{
    mfPoint3df *world = &vc.world;
    Perspective *persp = &vc.persp;
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    persp->aspectRatio = world->x / world->y;
    persp->zFar = vc.viewDist + world->z*2;
    if( projMode ) {
        gluPerspective( persp->viewAngle,
persp->aspectRatio,
persp->zNear, persp->zFar );
    }
    else {
        glOrtho( -world->x/2, world->x/2, -world->y/2, world->y/2,
                          -world->z, world->z );
    }
    glMatrixMode(GL_MODELVIEW);
    // reset drawing state
    ResetPipes();
}
/*-----------------------------------------------------------------------
|                                                                       |
|    ReshapePipes( width, height ):                                     |
|       - called on resize, expose                                      |
|       - always called on app startup                                  |
|       - use it to reset projection matrix, model dimensions, etc.     |
|                                                                       |
-----------------------------------------------------------------------*/
void ReshapePipes(int width, int height)
{
    float ratio;
    glViewport(0, 0, (GLint)width, (GLint)height);
    vc.winSize.width = width;
    vc.winSize.height = height;
    // adjust world dimensions to fit viewport, and adjust node counts
    if( width >= height ) {
        ratio = (float)height/width;
        vc.world.x = vc.numDiv * vc.divSize;
        vc.world.y = ratio * vc.world.x;
        vc.world.z = vc.world.x;
        vc.numNodes.x = vc.numDiv - 1;
        vc.numNodes.y = (int) (ratio * vc.numNodes.x);
        vc.numNodes.z = vc.numNodes.x;
    }
    else {
        ratio = (float)width/height;
        vc.world.y = vc.numDiv * vc.divSize;
        vc.world.x = ratio * vc.world.y;
        vc.world.z = vc.world.y;
        vc.numNodes.y = vc.numDiv - 1;
        vc.numNodes.x = (int) (ratio * vc.numNodes.y);
        vc.numNodes.z = vc.numNodes.y;
    }
    // reset stuff not done on PipeReset()
    vc.yRot = 0.0f;
    // set view matrix (resets pipe drawing as well)
    SetProjMatrix();
}
/*-----------------------------------------------------------------------
|                                                                       |
|    getNeighbourNodes( pos ):                                          |
|       - get addresses of the neigbour nodes,                          |
|         and put them in supplied matrix                               |
|       - boundary hits are returned as NULL                            |
|                                                                       |
-----------------------------------------------------------------------*/
static void getNeighbourNodes( mfPoint3di *pos, Node **nNode )
{
    Node *theNode = &node[pos->z][pos->y][pos->x];
    if( pos->x == 0 )
        nNode[MINUS_X] = (Node *) NULL;
    else
        nNode[MINUS_X] = theNode - 1;
    if( pos->x == (vc.numNodes.x - 1) )
        nNode[PLUS_X] = (Node *) NULL;
    else
        nNode[PLUS_X] = theNode + 1;
    if( pos->y == 0 )
        nNode[MINUS_Y] = (Node *) NULL;
    else
        nNode[MINUS_Y] = theNode - NUM_NODE;
    if( pos->y == (vc.numNodes.y - 1) )
        nNode[PLUS_Y] = (Node *) NULL;
    else
        nNode[PLUS_Y] = theNode + NUM_NODE;
    if( pos->z == 0 )
        nNode[MINUS_Z] = (Node *) NULL;
    else
        nNode[MINUS_Z] = theNode - NUM_NODE*NUM_NODE;
    if( pos->z == (vc.numNodes.z - 1) )
        nNode[PLUS_Z] = (Node *) NULL;
    else
        nNode[PLUS_Z] = theNode + NUM_NODE*NUM_NODE;
}
/*-----------------------------------------------------------------------
|                                                                       |
|    getEmptyNeighbourNodes()                                           |
|       - get list of direction indices of empty node neighbours,       |
|         and put them in supplied matrix                               |
|       - return number of empty node neighbours                        |
|
- currently, if we find a node that is empty in the current
|
|
  direction, we duplicate it in the empty set, thereby making
|
|
  it a bit more likely to go straight.
|
|                                                                       |
-----------------------------------------------------------------------*/
static int getEmptyNeighbours( Node **nNode, int *nEmpty )
{
    int i, count = 0;
    for( i = 0; i < NUM_DIRS; i ++ ) {
        if( nNode[i] && nNode[i]->empty )
// weight straight
{
            nEmpty[count++] = i;
    if( i == lastDir )
nEmpty[count++] = i;
}
    }
    return count;
}
/*-----------------------------------------------------------------------
|                                                                       |
|    updateCurrentPosition( newDir ):                                           |
|                                                                       |
-----------------------------------------------------------------------*/
static void updateCurrentPosition( int newDir )
{
    switch( newDir ) {
        case PLUS_X:
            vc.curPos.x += 1;
            break;
        case MINUS_X:
            vc.curPos.x -= 1;
            break;
        case PLUS_Y:
            vc.curPos.y += 1;
            break;
        case MINUS_Y:
            vc.curPos.y -= 1;
            break;
        case PLUS_Z:
            vc.curPos.z += 1;
            break;
        case MINUS_Z:
            vc.curPos.z -= 1;
            break;
    }
}
/*-----------------------------------------------------------------------
|                                                                       |
|    align_plusz( int newDir )
|
|       - Aligns the z axis along specified direction
|
|                                                                       |
-----------------------------------------------------------------------*/
static void align_plusz( int newDir )
{
    // align +z along new direction
    switch( newDir ) {
        case PLUS_X:
            glRotatef( 90.0f, 0.0f, 1.0f, 0.0f);
            break;
        case MINUS_X:
            glRotatef( -90.0f, 0.0f, 1.0f, 0.0f);
            break;
        case PLUS_Y:
            glRotatef( -90.0f, 1.0f, 0.0f, 0.0f);
            break;
        case MINUS_Y:
            glRotatef( 90.0f, 1.0f, 0.0f, 0.0f);
            break;
        case PLUS_Z:
            glRotatef( 0.0f, 0.0f, 1.0f, 0.0f);
            break;
        case MINUS_Z:
            glRotatef( 180.0f, 0.0f, 1.0f, 0.0f);
            break;
    }
}
static float RotZ[NUM_DIRS][NUM_DIRS] = {
  0.0f,
  0.0f,
 90.0f,  90.0f,
 90.0f,
-90.0f,
  0.0f,
  0.0f,
-90.0f,
-90.0f,
-90.0f,
 90.0f,
180.0f,
180.0f,   0.0f,
  0.0f, 180.0f,
180.0f,
  0.0f,
  0.0f,
  0.0f,
  0.0f,   0.0f,
  0.0f,
-90.0f,  90.0f,
  0.0f,
180.0f,   0.0f,   0.0f,
 90.0f, -90.0f, 180.0f,   0.0f,   0.0f,   0.0f };
/*-----------------------------------------------------------------------
|                                                                       |
|    align_plusy( int lastDir, int newDir )
|
|       - Assuming +z axis is already aligned with newDir, align
|
|
  +y axis BACK along lastDir
|
|                                                                       |
-----------------------------------------------------------------------*/
static void align_plusy( int oldDir, int newDir )
{
    GLfloat rotz;
    rotz = RotZ[oldDir][newDir];
    glRotatef( rotz, 0.0f, 0.0f, 1.0f );
}
// defCylNotch shows where the notch for the default cylinder will be,
//  in absolute coords, once we do an align_plusz
static GLint defCylNotch[NUM_DIRS] =
{ PLUS_Y, PLUS_Y, MINUS_Z, PLUS_Z, PLUS_Y, PLUS_Y };
// given a dir, determine how much to rotate cylinder around z to match notches
// format is [newDir][notchVec]
#define fXX 1.0f
// float don't care value
#define iXX -1
// int don't care value
static GLfloat alignNotchRot[NUM_DIRS][NUM_DIRS] = {
fXX,
fXX,
0.0f,
180.0f,
 90.0f,
-90.0f,
fXX,
fXX,
0.0f,
180.0f,
 -90.0f, 90.0f,
-90.0f,
90.0f,
fXX,
fXX,
180.0f,
0.0f,
-90.0f,
90.0f,
fXX,
fXX,
0.0f,
180.0f,
-90.0f,
90.0f,
0.0f,
180.0f,
fXX,
fXX,
90.0f,
-90.0f,
0.0f,
180.0f,
fXX,
fXX
};
/*-----------------------------------------------------------------------
|                                                                       |
|    align_notch( int newDir )
|
|
- a cylinder is notched, and we have to line this up
|
|
  with the previous primitive's notch which is maintained as
|
|
  notchVec.
|
|
- this adds a rotation around z to achieve this
|
|                                                                       |
-----------------------------------------------------------------------*/
static void align_notch( int newDir, int notch )
{
    GLfloat rotz;
    GLint curNotch;
    // figure out where notch is presently after +z alignment
    curNotch = defCylNotch[newDir];
    // (don't need this now we have lut)
    // look up rotation value in table
    rotz = alignNotchRot[newDir][notch];
    if( rotz != 0.0f )
        glRotatef( rotz, 0.0f, 0.0f, 1.0f );
}
/*-----------------------------------------------------------------------
|                                                                       |
|    ChooseJointType
|
|       - Decides which type of joint to draw
|
|                                                                       |
-----------------------------------------------------------------------*/
#define BLUE_MOON 153
static int ChooseJointType()
{
    switch( jointStyle ) {
case ELBOWS:
    return ELBOW_JOINT;
case BALLS:
    return BALL_JOINT;
case EITHER:
    // draw a teapot once in a blue moon
    if( mfRand(1000) == BLUE_MOON )
return( TEAPOT );
    // otherwise an elbow or a ball
    return( mfRand( 2 ) );
    }
}
// this array supplies the sequence of elbow notch vectors, given
//  oldDir and newDir  (0's are don't cares's)
// it is also used to determine the ending notch of an elbow
static GLint notchElbDir[NUM_DIRS][NUM_DIRS][4] = {
// oldDir = +x
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
PLUS_Y,
MINUS_Z,
MINUS_Y,
PLUS_Z,
MINUS_Y,
PLUS_Z,
PLUS_Y,
MINUS_Z,
PLUS_Z,
PLUS_Y,
MINUS_Z,
MINUS_Y,
MINUS_Z,
MINUS_Y,
PLUS_Z,
PLUS_Y,
// oldDir = -x
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
PLUS_Y,
PLUS_Z,
MINUS_Y,
MINUS_Z,
MINUS_Y,
MINUS_Z,
PLUS_Y,
PLUS_Z,
PLUS_Z,
MINUS_Y,
MINUS_Z,
PLUS_Y,
MINUS_Z,
PLUS_Y,
PLUS_Z,
MINUS_Y,
// oldDir = +y
PLUS_X,
PLUS_Z,
MINUS_X,
MINUS_Z,
MINUS_X,
MINUS_Z,
PLUS_X,
PLUS_Z,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
PLUS_Z,
MINUS_X,
MINUS_Z,
PLUS_X,
MINUS_Z,
PLUS_X,
PLUS_Z,
MINUS_X,
// oldDir = -y
PLUS_X,
MINUS_Z,
MINUS_X,
PLUS_Z,
MINUS_X,
PLUS_Z,
PLUS_X,
MINUS_Z,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
PLUS_Z,
PLUS_X,
MINUS_Z,
MINUS_X,
MINUS_Z,
MINUS_X,
PLUS_Z,
PLUS_X,
// oldDir = +z
PLUS_X,
MINUS_Y,
MINUS_X,
PLUS_Y,
MINUS_X,
PLUS_Y,
PLUS_X,
MINUS_Y,
PLUS_Y,
PLUS_X,
MINUS_Y,
MINUS_X,
MINUS_Y,
MINUS_X,
PLUS_Y,
PLUS_X,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
// oldDir = -z
PLUS_X,
PLUS_Y,
MINUS_X,
MINUS_Y,
MINUS_X,
MINUS_Y,
PLUS_X,
PLUS_Y,
PLUS_Y,
MINUS_X,
MINUS_Y,
PLUS_X,
MINUS_Y,
PLUS_X,
PLUS_Y,
MINUS_X,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX
};
// this array tells you which way the notch will be once you make
// a turn
// format: notchTurn[oldDir][newDir][notchVec]
static GLint notchTurn[NUM_DIRS][NUM_DIRS][NUM_DIRS] = {
// oldDir = +x
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
MINUS_X,PLUS_X, PLUS_Z, MINUS_Z,
iXX,
iXX,
PLUS_X, MINUS_X,PLUS_Z, MINUS_Z,
iXX,
iXX,
PLUS_Y, MINUS_Y,MINUS_X,PLUS_X,
iXX,
iXX,
PLUS_Y, MINUS_Y,PLUS_X, MINUS_X,
// oldDir = -x
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
PLUS_X, MINUS_X,PLUS_Z, MINUS_Z,
iXX,
iXX,
MINUS_X,PLUS_X, PLUS_Z, MINUS_Z,
iXX,
iXX,
PLUS_Y, MINUS_Y,PLUS_X, MINUS_X,
iXX,
iXX,
PLUS_Y, MINUS_Y,MINUS_X,PLUS_X,
// oldDir = +y
MINUS_Y,PLUS_Y, iXX,
iXX,
PLUS_Z, MINUS_Z,
PLUS_Y, MINUS_Y,iXX,
iXX,
PLUS_Z, MINUS_Z,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
PLUS_X, MINUS_X,iXX,
iXX,
MINUS_Y,PLUS_Y,
PLUS_X, MINUS_X,iXX,
iXX,
PLUS_Y, MINUS_Y,
// oldDir = -y
PLUS_Y, MINUS_Y,iXX,
iXX,
PLUS_Z, MINUS_Z,
MINUS_Y,PLUS_Y, iXX,
iXX,
PLUS_Z, MINUS_Z,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
PLUS_X, MINUS_X,iXX,
iXX,
PLUS_Y, MINUS_Y,
PLUS_X, MINUS_X,iXX,
iXX,
MINUS_Y,PLUS_Y,
// oldDir = +z
MINUS_Z,PLUS_Z, PLUS_Y, MINUS_Y,iXX,
iXX,
PLUS_Z, MINUS_Z,PLUS_Y, MINUS_Y,iXX,
iXX,
PLUS_X, MINUS_X,MINUS_Z,PLUS_Z, iXX,
iXX,
PLUS_X, MINUS_X,PLUS_Z, MINUS_Z,iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
// oldDir = -z
PLUS_Z, MINUS_Z,PLUS_Y, MINUS_Y,iXX,
iXX,
MINUS_Z,PLUS_Z, PLUS_Y, MINUS_Y,iXX,
iXX,
PLUS_X, MINUS_X,PLUS_Z, MINUS_Z,iXX,
iXX,
PLUS_X, MINUS_X,MINUS_Z,PLUS_Z, iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX,
iXX
};
static GLint oppositeDir[NUM_DIRS] =
    { MINUS_X, PLUS_X, MINUS_Y, PLUS_Y, MINUS_Z, PLUS_Z };
/*-----------------------------------------------------------------------
|                                                                       |
|    ChooseElbow( int newDir, int oldDir )
|
|       - Decides which elbow to draw
|
|
- The beginning of each elbow is aligned along +y, and we have
|
|
  to choose the one with the notch in correct position
|
|
- The 'primary' start notch (elbow[0]) is in same direction as  |
|
  newDir,
|
|
  and successive elbows rotate this notch CCW around +y
|
|                                                                       |
-----------------------------------------------------------------------*/
static GLint ChooseElbow( int oldDir, int newDir )
{
    int i;
    // precomputed table supplies correct elbow orientation
    for( i = 0; i < 4; i ++ ) {
if( notchElbDir[oldDir][newDir][i] == notchVec )
    return i;
    }
    // we shouldn't arrive here
    return -1;
}
/*----------------------------------------------------------------------\
|                                                                       |
| drawPipeSection(int dir)                                              |
|                                                                       |
|
- Draws a continuous pipe section
|
|       - if turning, draws a joint and a short cylinder, otherwise     |
|         draws a long cylinder.                                        |
|       - int dir: new absolute direction, or RANDOM_DIR                |
|       - the 'current node' is set as the one we draw thru the NEXT    |
|         time around.                                                  |
|       - return: 0 if couldn't do it                                   |
|                 1 if successful                                       |
|                                                                       |
|                                                                       |
\----------------------------------------------------------------------*/
static int drawPipeSection( int dir )
{
    static Node *nNode[NUM_DIRS];
    // weight going straight a little more
    static int nEmpty[NUM_DIRS+1];
    int numEmpty, newDir;
    int jointType;
    int iElbow;
    VC *vp = &vc;
    // find out who the neighbours are: this returns addresses of the  6
    // neighbours, or NULL, if they're out of bounds
    getNeighbourNodes( &vc.curPos, nNode );
    // determine new direction to go in
    if( dir != RANDOM_DIR ) {  // choose absolute direction
        if( (nNode[dir] != NULL) && nNode[dir]->empty ) {
            newDir = dir;
        }
        else {  // can't go in that direction
            return 0;
        }
    }
    else {  // randomnly choose one of the empty nodes
        // who's empty ?: returns the number of empty nodes, and fills the
        // nEmpty matrix with the direction indices of the empty nodes
        numEmpty = getEmptyNeighbours( nNode, nEmpty );
        if( numEmpty == 0 ) {  // no empty nodes - nowhere to go
            return 0;
        }
        // randomnly choose an empty node: by direction index
        newDir = nEmpty[mfRand( numEmpty )];
    }
    // push matrix that has initial zTrans and rotation
    glPushMatrix();
    // translate to current position
    glTranslatef( (vc.curPos.x - (vc.numNodes.x - 1)/2.0f )*vc.divSize,
                  (vc.curPos.y - (vc.numNodes.y - 1)/2.0f )*vc.divSize,
                  (vc.curPos.z - (vc.numNodes.z - 1)/2.0f )*vc.divSize );
    // draw joint if necessary, and pipe
    if( newDir != lastDir ) { // turning! - we have to draw joint
jointType = ChooseJointType();
switch( jointType ) {
  case BALL_JOINT:
    if( bTexture ) {
// use special texture-friendly balls
        align_plusz( newDir );
        glPushMatrix();
        align_plusy( lastDir, newDir );
        // translate forward 1.0*r along +z to get set for drawing elbow
        glTranslatef( 0.0f, 0.0f, vc.radius );
        // decide which elbow orientation to use
        iElbow = ChooseElbow( lastDir, newDir );
        glCallList( balls[iElbow] );
        glPopMatrix();
    }
    else {
// draw ball in default orientation
        glCallList( ball );
        align_plusz( newDir );
    }
    // move ahead 1.0*r to draw pipe
    glTranslatef( 0.0f, 0.0f, vc.radius );
    break;
  case ELBOW_JOINT:
    align_plusz( newDir );
    // the align_plusy() here will screw up our notch calcs, so
    //  we push-pop
    glPushMatrix();
    align_plusy( lastDir, newDir );
    // translate forward 1.0*r along +z to get set for drawing elbow
    glTranslatef( 0.0f, 0.0f, vc.radius );
    // decide which elbow orientation to use
    iElbow = ChooseElbow( lastDir, newDir );
    if( iElbow == -1 ) {
iElbow = 0; // recover
    }
    glCallList( elbows[iElbow] );
    glPopMatrix();
    glTranslatef( 0.0f, 0.0f, vc.radius );
    break;
  default:
            // Horrors! It's the teapot!
    glFrontFace( GL_CW );
    glEnable( GL_NORMALIZE );
    auxSolidTeapot(2.5 * vc.radius);
    glDisable( GL_NORMALIZE );
    glFrontFace( GL_CCW );
    align_plusz( newDir );
    // move ahead 1.0*r to draw pipe
    glTranslatef( 0.0f, 0.0f, vc.radius );
}
// update the current notch vector
notchVec = notchTurn[lastDir][newDir][notchVec];
        // draw short pipe
align_notch( newDir, notchVec );
glCallList( shortPipe );
    }
    else {  // no turn
        // draw long pipe, from point 1.0*r back
align_plusz( newDir );
align_notch( newDir, notchVec );
glTranslatef( 0.0f, 0.0f, -vc.radius );
glCallList( longPipe );
    }
    glPopMatrix();
    // mark new node as non-empty
    nNode[newDir]->empty = GL_FALSE;
    vc.curNode = nNode[newDir];
    updateCurrentPosition( newDir );
    lastDir = newDir;
    return 1;
}
/*----------------------------------------------------------------------\
|                                                                       |
| drawFirstPipeSection(int dir)                                         |
|                                                                       |
|
- Draws a starting cap and a short pipe section
|
|       - int dir: new absolute direction, or RANDOM_DIR                |
|       - the 'current node' is set as the one we draw thru the NEXT    |
|         time around.                                                  |
|       - return: 0 if couldn't do it                                   |
|                 1 if successful                                       |
|                                                                       |
|                                                                       |
\----------------------------------------------------------------------*/
static int drawFirstPipeSection( int dir )
{
    static Node *nNode[NUM_DIRS];
    // weight going straight a little more
    static int nEmpty[NUM_DIRS+1];
    int numEmpty, newDir;
    VC *vp = &vc;
    // find out who the neighbours are: this returns addresses of the  6
    // neighbours, or NULL, if they're out of bounds
    getNeighbourNodes( &vc.curPos, nNode );
    // determine new direction to go in
    if( dir != RANDOM_DIR ) {  // choose absolute direction
        if( (nNode[dir] != NULL) && nNode[dir]->empty ) {
            newDir = dir;
        }
        else {  // can't go in that direction
            return 0;
        }
    }
    else {  // randomnly choose one of the empty nodes
        numEmpty = getEmptyNeighbours( nNode, nEmpty );
        if( numEmpty == 0 ) {  // no empty nodes - nowhere to go
            return 0;
        }
        // randomnly choose an empty node: by direction index
        newDir = nEmpty[mfRand( numEmpty )];
    }
    // push matrix that has initial zTrans and rotation
    glPushMatrix();
    // translate to current position
    glTranslatef( (vc.curPos.x - (vc.numNodes.x - 1)/2.0f )*vc.divSize,
                  (vc.curPos.y - (vc.numNodes.y - 1)/2.0f )*vc.divSize,
                  (vc.curPos.z - (vc.numNodes.z - 1)/2.0f )*vc.divSize );
    // draw ball
    if( bTexture ) {
align_plusz( newDir );
glCallList( ball );
    }
    else {
// draw ball in default orientation
glCallList( ball );
align_plusz( newDir );
    }
    // set initial notch vector
    notchVec = defCylNotch[newDir];
    // move ahead 1.0*r to draw pipe
    glTranslatef( 0.0f, 0.0f, vc.radius );
    // draw short pipe
    align_notch( newDir, notchVec );
    glCallList( shortPipe );
    glPopMatrix();
    // mark new node as non-empty
    nNode[newDir]->empty = GL_FALSE;
    vc.curNode = nNode[newDir];
    updateCurrentPosition( newDir );
    lastDir = newDir;
    // set normal drawing mode
    drawNext = drawPipeSection;
    return 1;
}
/*-----------------------------------------------------------------------
|                                                                       |
|    DrawEndCap():                                                      |
|       - Draws a ball, used to cap end of a pipe
|
|                                                                       |
-----------------------------------------------------------------------*/
void DrawEndCap()
{
    glPushMatrix();
    // translate to current position
    glTranslatef( (vc.curPos.x - (vc.numNodes.x - 1)/2.0f )*vc.divSize,
                  (vc.curPos.y - (vc.numNodes.y - 1)/2.0f )*vc.divSize,
                  (vc.curPos.z - (vc.numNodes.z - 1)/2.0f )*vc.divSize );
    if( bTexture ) {
glPushMatrix();
align_plusz( lastDir );
align_notch( lastDir, notchVec );
        glCallList( ball );
glPopMatrix();
    }
    else
        glCallList( ball );
    glPopMatrix();
}
/*-----------------------------------------------------------------------
|                                                                       |
|    ResetPipes():                                                      |
|       - Resets drawing parameters                                     |
|                                                                       |
-----------------------------------------------------------------------*/
void ResetPipes(void)
{
    int i;
    Node *pNode;
    // ! flush gl cmds before calling gdi !
    glFlush();
    RectWipeClear( vc.winSize.width, vc.winSize.height );
    glClear(GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
    glTranslatef(0.0f, 0.0f, vc.zTrans);
    // Rotate Scene
    glRotatef( vc.yRot, 0.0f, 1.0f, 0.0f );
    vc.yRot += 9.73156f;
    vc.viewDist = -vc.zTrans;
    vc.curPos.x = vc.numNodes.x / 2;
    vc.curPos.y = vc.numNodes.y / 2;
    vc.curPos.z = vc.numNodes.z / 2;
    vc.curNode = (Node *) &node[vc.curPos.z][vc.curPos.y][vc.curPos.x];
    // Reset the node states
    pNode = &node[0][0][0];
    for( i = 0; i < (NUM_NODE)*(NUM_NODE)*(NUM_NODE); i++, pNode++ )
        pNode->empty = GL_TRUE;
    // Mark starting node as taken
    node[vc.curPos.z][vc.curPos.y][vc.curPos.x].empty = GL_FALSE;
    // Set the joint style
    if( bCycleJointStyles ) {
        if( ++jointStyle >= NUM_JOINT_STYLES )
    jointStyle = 0;
    }
    drawNext = drawFirstPipeSection;
}
/*-----------------------------------------------------------------------
|                                                                       |
|    DrawPipes(void):                                                   |
|       - Draws next section in random orientation                      |
|                                                                       |
-----------------------------------------------------------------------*/
// If random search takes longer than twice the total number
// of nodes, give up the random search.  There may not be any
// empty nodes.
#define INFINITE_LOOP   (2 * NUM_NODE * NUM_NODE * NUM_NODE)
void DrawPipes(void)
{
    static int pipeCount = 0;
    int infLoopDetect = 0;
    int count = 0;
    int x,y,z;
    BOOL bFoundNode = FALSE;
    if( drawMode != MF_MANUAL ) {
        if( !drawNext(RANDOM_DIR) ) {  // deadlock -- nowhere for current pipe to go.
            // Cap off last pipe.
            DrawEndCap();
            ChooseMaterial();
            // If number pipes exceeds max, then reset the pipes and exit.
            // Otherwise, start a new pipe.
            if( pipeCount++ >= vc.numPipes ) {
                pipeCount = 0;
                ResetPipes();
                return;
            }
            else {
                // Find empty node
                while( !bFoundNode ) {
                    // Pick a random node.
                    x = mfRand( vc.numNodes.x );
                    y = mfRand( vc.numNodes.y );
                    z = mfRand( vc.numNodes.z );
                    // If its empty, we're done.
                    if( node[z][y][x].empty )
                        bFoundNode = TRUE;
                    else {
                        // Watch out for infinite loops!  After trying for
                        // awhile, give up on the random search and look
                        // for the first empty node.
                        if ( infLoopDetect++ > INFINITE_LOOP ) {
                            // Search for first empty node.
                            for ( x = 0; !bFoundNode && (x < vc.numNodes.x); x++ )
                                for ( y = 0; !bFoundNode && (y < vc.numNodes.y); y++ )
                                    for ( z = 0; !bFoundNode && (z < vc.numNodes.z); z++ )
                                        if ( node[z][y][x].empty )
                                            bFoundNode = TRUE;
                            // If nothing found, there are no more empty nodes.
                            // Reset the pipes and exit.
                            if ( !bFoundNode ) {
                                pipeCount = 0;
                                ResetPipes();
                                return;
                            }
                        }
                    }
                }
                // start drawing at new node next time we come thru
                vc.curPos.x = x;
                vc.curPos.y = y;
                vc.curPos.z = z;
                node[z][y][x].empty = GL_FALSE;
                vc.curNode =
                    (Node *) &node[vc.curPos.z][vc.curPos.y][vc.curPos.x];
drawNext = drawFirstPipeSection;
                return;
            }
        }
    }
    glFlush();
}


RESOURCE.H  (PIPES Sample)
/******************************Module*Header*******************************\
* Module Name: resource.h
*
* AppStudio generated header used by sspipes.rc.
*
* Copyright (c) 1994 Microsoft Corporation
*
\**************************************************************************/
//{{NO_DEPENDENCIES}}
// App Studio generated include file.
// Used by sspipes.rc
//
#define IDI_ICON1                       103
#define IDC_STATIC                      -1
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE        104
#define _APS_NEXT_COMMAND_VALUE         101
#define _APS_NEXT_CONTROL_VALUE         1011
#define _APS_NEXT_SYMED_VALUE           101
#endif
#endif


SSPIPES.H  (PIPES Sample)
/******************************Module*Header*******************************\
* Module Name: sspipes.h
*
* Global header for 3D Pipes screen saver.
*
* Copyright (c) 1994 Microsoft Corporation
*
\**************************************************************************/
extern float fTesselFact;
extern ULONG ulJointType;
extern ULONG ulSurfStyle;
extern WCHAR awchTexPathname[];
extern int nTexFileOffset;
// Resource constants
#define IDS_COPYRIGHT           1001
#define IDS_SAVERNAME           1002
#define IDS_GENNAME             1003
#define IDS_INIFILE             1004
#define IDS_TESSELATION         1005
#define IDS_TEXTURE             1006
#define IDS_TEXTURE_FILE_OFFSET 1007
#define IDS_JOINT               1008
#define IDS_SURF                1009
#define IDS_TEXQUAL             1010
#define IDS_WARNING             1011
#define IDS_BITMAP_SIZE         1012
#define IDS_BITMAP_INVALID      1013
#define IDS_RUN_CONTROL_PANEL   1014
#define IDS_TEXTUREFILTER       1015
#define IDS_TEXTUREDIALOGTITLE  1016
#define IDS_BMP                 1017
#define IDS_DOTBMP              1018
#define IDS_STARDOTBMP          1019
#define DLG_SETUP_TESSEL        2001
#define DLG_SETUP_TEXTURE       2002
#define IDC_STATIC_TESS         2003
#define IDC_STATIC_TESS_MIN     2004
#define IDC_STATIC_TESS_MAX     2005
#define IDC_STATIC_TESS_GRP     2006
#define IDC_STATIC_TEXQUAL_GRP  2007
// In order for the IDC_TO_JOINT conversion macro to work, the radio buttons
// for joint types must be kept contiguous.
#define IDC_RADIO_ELBOW         2101
#define IDC_RADIO_BALL          2102
#define IDC_RADIO_MIXED         2103
#define IDC_RADIO_ALT           2104
#define JOINT_ELBOW             0
#define JOINT_BALL              1
#define JOINT_MIXED             2
#define JOINT_ALT               3
#define IDC_TO_JOINT(n)         ( (n) - IDC_RADIO_ELBOW )
// In order for the IDC_TO_SURF conversion macro to work, the radio buttons
// for surface styles must be kept contiguous.
#define IDC_RADIO_SOLID         2111
#define IDC_RADIO_TEX           2112
#define SURF_SOLID              0
#define SURF_TEX                1
#define IDC_TO_SURF(n)          ( (n) - IDC_RADIO_SOLID )
// In order for the IDC_TO_TEXQUAL conversion macro to work, the radio buttons
// for texture quality must be kept contiguous.
#define IDC_RADIO_TEXQUAL_LOW   2121
#define IDC_RADIO_TEXQUAL_HIGH  2122
#define TEXQUAL_LOW             0
#define TEXQUAL_HIGH            1
#define IDC_TO_TEXQUAL(n)       ( (n) - IDC_RADIO_TEXQUAL_LOW )


SSPIPES.RC  (PIPES Sample)
/******************************Module*Header*******************************\
* Module Name: sspipes.rc
*
* Resource file for OpenGL-based 3D Pipes screen saver.
*
* Copyright (c) 1994 Microsoft Corporation
*
\**************************************************************************/
//Microsoft App Studio generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#define APSTUDIO_HIDDEN_SYMBOLS
#include "windows.h"
#undef APSTUDIO_HIDDEN_SYMBOLS
#include "scrnsave.h"
#include "sspipes.h"
/////////////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
//////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
DLG_SCRNSAVECONFIGURE DIALOG DISCARDABLE  28, 25, 297, 113
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "3D Pipes Setup"
FONT 8, "MS Sans Serif"
BEGIN
    DEFPUSHBUTTON   "OK",1,240,5,50,14,WS_GROUP
    PUSHBUTTON      "Cancel",2,240,25,50,14,WS_GROUP
    GROUPBOX        "Joint Style",IDC_STATIC,5,0,110,50,WS_GROUP
    CONTROL         "&Elbow",IDC_RADIO_ELBOW,"Button",BS_AUTORADIOBUTTON |
                    WS_GROUP | WS_TABSTOP,15,15,35,13
    CONTROL         "&Ball",IDC_RADIO_BALL,"Button",BS_AUTORADIOBUTTON |
                    WS_GROUP | WS_TABSTOP,15,30,30,13
    CONTROL         "&Mixed",IDC_RADIO_MIXED,"Button",BS_AUTORADIOBUTTON |
                    WS_GROUP | WS_TABSTOP,55,15,38,13
    CONTROL         "&Cycle styles",IDC_RADIO_ALT,"Button",
                    BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,55,30,50,13
    GROUPBOX        "Surface Style",IDC_STATIC,120,0,110,50,WS_GROUP
    CONTROL         "&Solid",IDC_RADIO_SOLID,"Button",BS_AUTORADIOBUTTON |
                    WS_GROUP | WS_TABSTOP,132,15,35,13
    CONTROL         "B&itmap texture",IDC_RADIO_TEX,"Button",
                    BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,132,30,60,14
    PUSHBUTTON      "Te&xture...",DLG_SETUP_TEXTURE,240,45,50,14
    GROUPBOX        "Texture Quality",IDC_STATIC_TEXQUAL_GRP,5,55,110,50
    CONTROL         "&Default quality",IDC_RADIO_TEXQUAL_LOW,"Button",
                    BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,15,70,65,15
    CONTROL         "&High quality",IDC_RADIO_TEXQUAL_HIGH,"Button",
                    BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,15,85,65,15
    GROUPBOX        "&Resolution",IDC_STATIC_TESS_GRP,120,55,111,50
    LTEXT           "Min",IDC_STATIC_TESS_MIN,135,70,30,7
    SCROLLBAR       DLG_SETUP_TESSEL,135,80,80,11,WS_GROUP | WS_TABSTOP
    RTEXT           "Max",IDC_STATIC_TESS_MAX,185,70,30,7
END
#ifdef APSTUDIO_INVOKED
//////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE DISCARDABLE
BEGIN
    "resource.h\0"
END
2 TEXTINCLUDE DISCARDABLE
BEGIN
    "#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
    "#include ""windows.h""\r\n"
    "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
    "#include ""scrnsave.h""\r\n"
    "#include ""sspipes.h""\r\n"
    "\0"
END
3 TEXTINCLUDE DISCARDABLE
BEGIN
    "\r\n"
    "\0"
END
/////////////////////////////////////////////////////////////////////////////////////
#endif    // APSTUDIO_INVOKED
//////////////////////////////////////////////////////////////////////////////
//
// String Table
//
STRINGTABLE PRELOAD DISCARDABLE
BEGIN
    IDS_DESCRIPTION         "3D Pipes (OpenGL)"
END
STRINGTABLE PRELOAD DISCARDABLE
BEGIN
    IDS_TEXTUREFILTER       "Bitmap files"
    IDS_TEXTUREDIALOGTITLE  "Choose Texture Bitmap"
    IDS_BMP                 "BMP"
    IDS_DOTBMP              ".BMP"
    IDS_STARDOTBMP          "*.BMP"
END
STRINGTABLE PRELOAD DISCARDABLE
BEGIN
    IDS_COPYRIGHT           "Copyright (c) 1994 Microsoft Corporation"
    IDS_SAVERNAME           "Screen Saver.3DPipes"
    IDS_GENNAME             "ScreenSaver"
    IDS_INIFILE             "control.ini"
    IDS_TESSELATION         "Tesselation"
    IDS_TEXTURE             "Texture"
    IDS_TEXTURE_FILE_OFFSET "TextureFileOffset"
END
// This string table is used for registry keys -- localization not required
STRINGTABLE PRELOAD DISCARDABLE
BEGIN
    IDS_JOINT               "JointType"
    IDS_SURF                "SurfStyle"
    IDS_TEXQUAL             "TextureQuality"
END
STRINGTABLE PRELOAD DISCARDABLE
BEGIN
    IDS_WARNING             "Warning"
    IDS_BITMAP_SIZE         "The bitmap must not be larger than %ld by %ld pixels."
    IDS_BITMAP_INVALID      "The bitmap you selected is not a valid texture."
    IDS_RUN_CONTROL_PANEL   "Please run the Control Panel Desktop Applet and select another bitmap.  %ws is not a valid bitmap texture for this screen saver."
END
#ifndef APSTUDIO_INVOKED
////////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////////////
#endif    // not APSTUDIO_INVOKED


SSPIPES.C  (PIPES Sample)
/******************************Module*Header*******************************\
* Module Name: sspipes.c
*
* Message loop and dialog box for the OpenGL-based 3D Pipes screen saver.
*
* Copyright (c) 1994 Microsoft Corporation
*
\**************************************************************************/
#include <windows.h>
#include <commdlg.h>
#include <scrnsave.h>
#include <GL\gl.h>
#include <math.h>
#include <memory.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <sys\timeb.h>
#include <time.h>
#include "sspipes.h"
#include "pipes.h"
#include "gl\glaux.h"
extern void tkErrorPopups(GLboolean);
// Global strings.
#define GEN_STRING_SIZE 64
WCHAR wszTextureDialogTitle[GEN_STRING_SIZE];
WCHAR wszTextureFilter[2*GEN_STRING_SIZE];
WCHAR wszBmp[GEN_STRING_SIZE];
WCHAR wszDotBmp[GEN_STRING_SIZE];
HWND hWnd;
HANDLE hInst;
HGLRC gHrc = (HGLRC) 0;
HDC ghdcMem = 0;
HPALETTE ghpalOld, ghPalette = (HPALETTE) 0;
UINT guiOldStaticUse = SYSPAL_STATIC;
BOOL gbUseStatic = FALSE;
// Global string buffers for message box.
WCHAR gawch[2 * MAX_PATH];      // May contain a pathname
WCHAR gawchFormat[MAX_PATH];
WCHAR gawchTitle[MAX_PATH];
ULONG totalMem = 0;
// ulJointType controls the style of the elbows.
ULONG ulJointType = JOINT_ELBOW;
// ulSurfStyle determines whether the pipe surfaces are textured.
ULONG ulSurfStyle = SURF_SOLID;
// ulTexQuality control the texture quality.
ULONG ulTexQuality = TEXQUAL_LOW;
// fTesselFact controls the how finely the surface is tesselated.  It
// varies from very course (0.0) to very fine (2.0).
float fTesselFact = 1.0f;
static float fTesselSave = 1.0f;
// If ulSurfStyle indicates a textured surface, awchTexPathname specifies
// the bitmap chosen as the texture.
WCHAR awchTexPathname[MAX_PATH];
int nTexFileOffset;
// If 0, awchTexPathname is not full pathname.
#define TEX_WIDTH_MAX   1280
#define TEX_HEIGHT_MAX  1024
extern HPALETTE Hpal;
static int xSize;
static int ySize;
static int wxSize;
static int wySize;
static int updates = 0;
BOOL bVerifyDIB(WCHAR *fileName, ULONG *pWidth, ULONG *pHeight);
void TimerProc(HWND);
char *IDString(int id)
{
    static char strings[2][128];
    static int count = 0;
    char *str;
    str = strings[count];
    LoadString(hMainInstance, id, str, 128);
    count++;
    count &= 1;
    return str;
}
/******************************Public*Routine******************************\
* getIniSettings
*
* Get the screen saver configuration options from .INI file/registry.
*
\**************************************************************************/
static void getIniSettings()
{
    WCHAR  sectName[30];
    WCHAR  itemName[30];
    WCHAR  fname[30];
    HKEY   hkey;
    WCHAR  awchDefaultBitmap[MAX_PATH];
    LONG   cjDefaultBitmap = MAX_PATH;
    int    tessel;
    LPWSTR pwsz;
    LoadString(hMainInstance, IDS_GENNAME, szScreenSaver, sizeof(szScreenSaver) / sizeof(TCHAR));
    LoadStringW(hMainInstance, IDS_TEXTUREDIALOGTITLE, wszTextureDialogTitle, GEN_STRING_SIZE);
    LoadStringW(hMainInstance, IDS_BMP, wszBmp, GEN_STRING_SIZE);
    LoadStringW(hMainInstance, IDS_DOTBMP, wszDotBmp, GEN_STRING_SIZE);
// wszTextureFilter requires a little more work.  We need to assemble the file
// name filter string, which is composed of two strings separated by a NULL
// and terminated with a double NULL.
    LoadStringW(hMainInstance, IDS_TEXTUREFILTER, wszTextureFilter, GEN_STRING_SIZE);
    pwsz = &wszTextureFilter[lstrlenW(wszTextureFilter)+1];
    LoadStringW(hMainInstance, IDS_STARDOTBMP, pwsz, GEN_STRING_SIZE);
    pwsz[lstrlenW(pwsz)+1] = L'\0';
    if (LoadStringW(hMainInstance, IDS_SAVERNAME, sectName, 30) &&
        LoadStringW(hMainInstance, IDS_INIFILE, fname, 30))
    {
        if (LoadStringW(hMainInstance, IDS_JOINT, itemName, 30))
            ulJointType = GetPrivateProfileIntW(sectName, itemName,
                                                JOINT_ELBOW, fname);
        if (LoadStringW(hMainInstance, IDS_SURF, itemName, 30))
            ulSurfStyle = GetPrivateProfileIntW(sectName, itemName,
                                                SURF_SOLID, fname);
        if (LoadStringW(hMainInstance, IDS_TEXQUAL, itemName, 30))
            ulTexQuality = GetPrivateProfileIntW(sectName, itemName,
                                                 TEXQUAL_LOW, fname);
        if (LoadStringW(hMainInstance, IDS_TESSELATION, itemName, 30))
            tessel = GetPrivateProfileIntW(sectName, itemName,
  0, fname);
        fTesselFact  = (float)tessel / 100.0f;
    // Startup bitmap name not in the registry (yet).  We have to
    // synthesis the name from the ProductType registry entry.
        if ( RegOpenKeyExW(HKEY_LOCAL_MACHINE,
                           (PCWSTR) L"System\\CurrentControlSet\\Control\\ProductOptions",
                           0,
                           KEY_QUERY_VALUE,
                           &hkey) == ERROR_SUCCESS )
        {
            if ( RegQueryValueExW(hkey,
                                  L"ProductType",
                                  (LPDWORD) NULL,
                                  (LPDWORD) NULL,
                                  (LPBYTE) awchDefaultBitmap,
                                  (LPDWORD) &cjDefaultBitmap) == ERROR_SUCCESS
                 && (cjDefaultBitmap / sizeof(WCHAR) + 4) <= MAX_PATH )
                lstrcatW(awchDefaultBitmap, wszDotBmp);
            else
                lstrcpyW(awchDefaultBitmap, L"winnt.bmp");
            RegCloseKey(hkey);
        }
        else
            lstrcpyW(awchDefaultBitmap, L"winnt.bmp");
        if (LoadStringW(hMainInstance, IDS_TEXTURE, itemName, 30))
            GetPrivateProfileStringW(sectName, itemName, awchDefaultBitmap,
                                     awchTexPathname, MAX_PATH, fname);
        if (LoadStringW(hMainInstance, IDS_TEXTURE_FILE_OFFSET, itemName, 30))
            nTexFileOffset = GetPrivateProfileIntW(sectName, itemName,
                                                   0, fname);
    }
}
/******************************Public*Routine******************************\
* saveIniSettings
*
* Save the screen saver configuration option to the .INI file/registry.
*
\**************************************************************************/
static void saveIniSettings(HWND hDlg)
{
    WCHAR sectName[30];
    WCHAR itemName[30];
    WCHAR fname[30];
    WCHAR tmp[30];
    int pos;
    pos = GetScrollPos(GetDlgItem(hDlg,DLG_SETUP_TESSEL),SB_CTL);
    fTesselFact  = (float)pos / 100.0f;
    if (LoadStringW(hMainInstance, IDS_SAVERNAME, sectName, 30) &&
        LoadStringW(hMainInstance, IDS_INIFILE, fname, 30)) {
        if (LoadStringW(hMainInstance, IDS_JOINT, itemName, 30)) {
            wsprintfW(tmp, L"%ld", ulJointType);
            WritePrivateProfileStringW(sectName, itemName,
                                      tmp, fname);
        }
        if (LoadStringW(hMainInstance, IDS_SURF, itemName, 30)) {
            wsprintfW(tmp, L"%ld", ulSurfStyle);
            WritePrivateProfileStringW(sectName, itemName,
                                       tmp, fname);
        }
        if (LoadStringW(hMainInstance, IDS_TEXQUAL, itemName, 30)) {
            wsprintfW(tmp, L"%ld", ulTexQuality);
            WritePrivateProfileStringW(sectName, itemName,
                                       tmp, fname);
        }
        if (LoadStringW(hMainInstance, IDS_TESSELATION, itemName, 30)) {
            wsprintfW(tmp, L"%d", pos);
            WritePrivateProfileStringW(sectName, itemName,
                                       tmp, fname);
        }
        if (LoadStringW(hMainInstance, IDS_TEXTURE, itemName, 30)) {
            WritePrivateProfileStringW(sectName, itemName,
                                      awchTexPathname, fname);
        }
        if (LoadStringW(hMainInstance, IDS_TEXTURE_FILE_OFFSET, itemName, 30)) {
            wsprintfW(tmp, L"%ld", nTexFileOffset);
            WritePrivateProfileStringW(sectName, itemName,
                                      tmp, fname);
        }
    }
}
/******************************Public*Routine******************************\
* setupDialogControls
*
* Setup the dialog controls based on the current global state.
*
\**************************************************************************/
static void setupDialogControls(HWND hDlg)
{
    int pos;
    CheckDlgButton(hDlg, IDC_RADIO_ELBOW, ulJointType == JOINT_ELBOW);
    CheckDlgButton(hDlg, IDC_RADIO_BALL , ulJointType == JOINT_BALL );
    CheckDlgButton(hDlg, IDC_RADIO_MIXED, ulJointType == JOINT_MIXED);
    CheckDlgButton(hDlg, IDC_RADIO_ALT  , ulJointType == JOINT_ALT  );
    CheckDlgButton(hDlg, IDC_RADIO_SOLID, ulSurfStyle == SURF_SOLID );
    CheckDlgButton(hDlg, IDC_RADIO_TEX  , ulSurfStyle == SURF_TEX   );
    CheckDlgButton(hDlg, IDC_RADIO_TEXQUAL_LOW ,
                   ulSurfStyle == SURF_TEX && ulTexQuality == TEXQUAL_LOW);
    CheckDlgButton(hDlg, IDC_RADIO_TEXQUAL_HIGH,
                   ulSurfStyle == SURF_TEX && ulTexQuality == TEXQUAL_HIGH);
    EnableWindow(GetDlgItem(hDlg, DLG_SETUP_TEXTURE),
                 ulSurfStyle == SURF_TEX);
    EnableWindow(GetDlgItem(hDlg, IDC_RADIO_TEXQUAL_LOW),
                 ulSurfStyle == SURF_TEX);
    EnableWindow(GetDlgItem(hDlg, IDC_RADIO_TEXQUAL_HIGH),
                 ulSurfStyle == SURF_TEX);
    EnableWindow(GetDlgItem(hDlg, IDC_STATIC_TEXQUAL_GRP),
                 ulSurfStyle == SURF_TEX);
    EnableWindow(GetDlgItem(hDlg, DLG_SETUP_TESSEL), TRUE);
    EnableWindow(GetDlgItem(hDlg, IDC_STATIC_TESS_MIN), TRUE);
    EnableWindow(GetDlgItem(hDlg, IDC_STATIC_TESS_MAX), TRUE);
    EnableWindow(GetDlgItem(hDlg, IDC_STATIC_TESS_GRP), TRUE);
    SetScrollRange(GetDlgItem(hDlg, DLG_SETUP_TESSEL), SB_CTL, 0, 200, FALSE);
    pos = (int)(fTesselFact * 100.0f);
    SetScrollPos(GetDlgItem(hDlg, DLG_SETUP_TESSEL), SB_CTL, pos, TRUE);
}
/******************************Public*Routine******************************\
* getTextureBitmap
*
* Use the common dialog GetOpenFileName to get the name of a bitmap file
* for use as a texture.  This function will not return until the user
* either selects a valid bitmap or cancels.  If a valid bitmap is selected
* by the user, the global array awchTexPathname will have the full path
* to the bitmap file and the global value nTexFileOffset will have the
* offset from the beginning of awchTexPathname to the pathless file name.
*
* If the user cancels, awchTexPathname and nTexFileOffset will remain
* unchanged.
*
\**************************************************************************/
void getTextureBitmap(HWND hDlg)
{
    OPENFILENAMEW ofn;
    WCHAR dirName[MAX_PATH];
    WCHAR fileName[MAX_PATH];
    PWSTR pwsz;
    BOOL bTryAgain;
// Make dialog look nice by parsing out the initial path and
// file name from the full pathname.  If this isn't done, then
// dialog has a long ugly name in the file combo box and
// directory will end up with the default current directory.
    if (nTexFileOffset) {
    // Separate the directory and file names.
        lstrcpyW(dirName, awchTexPathname);
        dirName[nTexFileOffset-1] = L'\0';
        lstrcpyW(fileName, &awchTexPathname[nTexFileOffset]);
    }
    else {
    // If nTexFileOffset is zero, then awchTexPathname is not a full path.
    // Attempt to make it a full path by calling SearchPathW.
        if ( SearchPathW(NULL, awchTexPathname, NULL, MAX_PATH,
                         dirName, &pwsz) )
        {
        // Successful.  Go ahead a change awchTexPathname to the full path
        // and compute the filename offset.
            lstrcpyW(awchTexPathname, dirName);
            nTexFileOffset = pwsz - dirName;
        // Break the filename and directory paths apart.
            dirName[nTexFileOffset-1] = L'\0';
            lstrcpyW(fileName, pwsz);
        }
    // Give up and use the Windows system directory.
        else
        {
            GetWindowsDirectoryW(dirName, MAX_PATH);
            lstrcpyW(fileName, awchTexPathname);
        }
    }
    ofn.lStructSize = sizeof(OPENFILENAMEW);
    ofn.hwndOwner = hDlg;
    ofn.hInstance = NULL;
    ofn.lpstrFilter = wszTextureFilter;
    ofn.lpstrCustomFilter = (LPWSTR) NULL;
    ofn.nMaxCustFilter = 0;
    ofn.nFilterIndex = 1;
    ofn.lpstrFile = fileName;
    ofn.nMaxFile = MAX_PATH;
    ofn.lpstrFileTitle = (LPWSTR) NULL;
    ofn.nMaxFileTitle = 0;
    ofn.lpstrInitialDir = dirName;
    ofn.lpstrTitle = wszTextureDialogTitle;
    ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
    ofn.nFileOffset = 0;
    ofn.nFileExtension = 0;
    ofn.lpstrDefExt = wszBmp;
    ofn.lCustData = 0;
    ofn.lpfnHook = (LPOFNHOOKPROC) NULL;
    ofn.lpTemplateName = (LPWSTR) NULL;
    do {
    // Invoke the common file dialog.  If it succeeds, then validate
    // the bitmap file.  If not valid, make user try again until either
    // they pick a good one or cancel the dialog.
        bTryAgain = FALSE;
        if ( GetOpenFileNameW(&ofn) ) {
            ULONG w, h;
            if (bVerifyDIB(fileName, &w, &h)) {
                if ( w <= TEX_WIDTH_MAX && h <= TEX_HEIGHT_MAX )
                {
                    lstrcpyW(awchTexPathname, fileName);
                    nTexFileOffset = ofn.nFileOffset;
                }
                else {
                    if ( LoadStringW(hMainInstance, IDS_WARNING, gawchTitle, MAX_PATH) &&
                         LoadStringW(hMainInstance, IDS_BITMAP_SIZE, gawchFormat, MAX_PATH) )
                    {
                        wsprintfW(gawch, gawchFormat, TEX_WIDTH_MAX, TEX_HEIGHT_MAX);
                        MessageBoxW(NULL, gawch, gawchTitle, MB_OK);
                    }
                    bTryAgain = TRUE;
                }
            }
            else {
                if ( LoadStringW(hMainInstance, IDS_WARNING, gawchTitle, MAX_PATH) &&
                     LoadStringW(hMainInstance, IDS_BITMAP_INVALID, gawchFormat, MAX_PATH) )
                {
                    MessageBoxW(NULL, gawchFormat, gawchTitle, MB_OK);
                }
                bTryAgain = TRUE;
            }
        }
    // If need to try again, recompute dir and file name so dialog
    // still looks nice.
        if (bTryAgain && ofn.nFileOffset) {
            lstrcpyW(dirName, fileName);
            dirName[ofn.nFileOffset-1] = L'\0';
            lstrcpyW(fileName, &fileName[ofn.nFileOffset]);
        }
    } while (bTryAgain);
}
BOOL WINAPI RegisterDialogClasses(HANDLE hinst)
{
    return TRUE;
}
/******************************Public*Routine******************************\
* ScreenSaverConfigureDialog
*
* Screen saver setup dialog box procedure.
\**************************************************************************/
BOOL ScreenSaverConfigureDialog(HWND hDlg, UINT message,
                                WPARAM wParam, LPARAM lParam)
{
    int wTmp;
    int optMask = 1;
    switch (message)
    {
        case WM_INITDIALOG:
            getIniSettings();
            setupDialogControls(hDlg);
            return TRUE;
        case WM_HSCROLL:
            if (lParam == (LPARAM) GetDlgItem(hDlg,DLG_SETUP_TESSEL)) {
                wTmp = GetScrollPos(GetDlgItem(hDlg,DLG_SETUP_TESSEL),SB_CTL);
                switch(LOWORD(wParam))
                {
                    case SB_PAGEDOWN:
                        wTmp += 10;
                    case SB_LINEDOWN:
                        wTmp += 1;
                        wTmp = min(200, wTmp);
                        break;
                    case SB_PAGEUP:
                        wTmp -= 10;
                    case SB_LINEUP:
                        wTmp -= 1;
                        wTmp = max(0, (int)wTmp);
                        break;
                    case SB_THUMBPOSITION:
                        wTmp = HIWORD(wParam);
                        break;
                    default:
                        break;
                }
                SetScrollPos(GetDlgItem(hDlg, DLG_SETUP_TESSEL), SB_CTL, wTmp,
                             TRUE);
                fTesselFact  = (float)wTmp / 100.0f;
            }
            break;
        case WM_COMMAND:
            switch (LOWORD(wParam))
            {
                case IDC_RADIO_ELBOW:
                case IDC_RADIO_BALL:
                case IDC_RADIO_MIXED:
                case IDC_RADIO_ALT:
                    ulJointType = IDC_TO_JOINT(LOWORD(wParam));
                    setupDialogControls(hDlg);
                    break;
                case IDC_RADIO_SOLID:
case IDC_RADIO_TEX:
                    ulSurfStyle = IDC_TO_SURF(LOWORD(wParam));
                    setupDialogControls(hDlg);
                    break;
                case IDC_RADIO_TEXQUAL_LOW:
                case IDC_RADIO_TEXQUAL_HIGH:
                    ulTexQuality = IDC_TO_TEXQUAL(LOWORD(wParam));
                    setupDialogControls(hDlg);
                    break;
                case DLG_SETUP_TEXTURE:
    getTextureBitmap(hDlg);
    setupDialogControls(hDlg);
                    break;
                case IDOK:
                    saveIniSettings(hDlg);
                    EndDialog(hDlg, TRUE);
                    break;
                case IDCANCEL:
                    EndDialog(hDlg, FALSE);
                    break;
                default:
                    break;
            }
            return TRUE;
        default:
            return 0;
    }
    return 0;
}
// These are in GLAUX.LIB
extern unsigned char threeto8[];
extern unsigned char twoto8[];
extern unsigned char oneto8[];
unsigned char
jComponentFromIndex(i, nbits, shift)
{
    unsigned char val;
    val = i >> shift;
    switch (nbits) {
    case 1:
        val &= 0x1;
        return oneto8[val];
    case 2:
        val &= 0x3;
        return twoto8[val];
    case 3:
        val &= 0x7;
        return threeto8[val];
    default:
        return 0;
    }
}
void
vCreateRGBPalette(HDC hdc)
{
    PIXELFORMATDESCRIPTOR pfd, *ppfd;
    LOGPALETTE *pPal;
    int n, i;
    ppfd = &pfd;
    n = GetPixelFormat(hdc);
    DescribePixelFormat(hdc, n, sizeof(PIXELFORMATDESCRIPTOR), ppfd);
    if (ppfd->dwFlags & PFD_NEED_PALETTE) {
        n = 1 << ppfd->cColorBits;
        pPal = (PLOGPALETTE)LocalAlloc(LMEM_FIXED, sizeof(LOGPALETTE) +
                n * sizeof(PALETTEENTRY));
        pPal->palVersion = 0x300;
        pPal->palNumEntries = n;
        for (i=0; i < n; i++) {
            pPal->palPalEntry[i].peRed =
                    jComponentFromIndex(i, ppfd->cRedBits, ppfd->cRedShift);
            pPal->palPalEntry[i].peGreen =
                    jComponentFromIndex(i, ppfd->cGreenBits, ppfd->cGreenShift);
            pPal->palPalEntry[i].peBlue =
                    jComponentFromIndex(i, ppfd->cBlueBits, ppfd->cBlueShift);
            pPal->palPalEntry[i].peFlags = ((n == 256) && (i == 0 || i == 255))
                                           ? 0 : PC_NOCOLLAPSE;
        }
        ghPalette = CreatePalette(pPal);
        LocalFree(pPal);
        if ( n == 256 )
        {
            gbUseStatic = TRUE;
            guiOldStaticUse = SetSystemPaletteUse(hdc, SYSPAL_NOSTATIC);
        }
        ghpalOld = SelectPalette(hdc, ghPalette, FALSE);
        n = RealizePalette(hdc);
    }
}
BOOL bSetupPixelFormat(HDC hdc)
{
    PIXELFORMATDESCRIPTOR pfd, *ppfd;
    int pixelformat;
    ppfd = &pfd;
    ppfd->nSize = sizeof(PIXELFORMATDESCRIPTOR);
    ppfd->nVersion = 1;
    ppfd->dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
    ppfd->iLayerType = PFD_MAIN_PLANE;
    ppfd->cAlphaBits = 0;
    ppfd->cAuxBuffers = 0;
    ppfd->bReserved = 0;
    ppfd->iPixelType = PFD_TYPE_RGBA;
    ppfd->cColorBits = 24;
    ppfd->cDepthBits = 16;
    ppfd->cAccumBits = 0;
    ppfd->cStencilBits = 0;
    if ( (pixelformat = ChoosePixelFormat(hdc, ppfd)) == 0 ||
         SetPixelFormat(hdc, pixelformat, ppfd) == FALSE )
        return FALSE;
    return TRUE;
}
HGLRC hrcInitGL(HWND hwnd, HDC hdc)
{
    HGLRC hrc;
    RECT rect;
    GetClientRect(hwnd, &rect);
    wxSize = rect.right - rect.left;
    wySize = rect.bottom - rect.top;
    // communicate window size to pipelib:
    vc.winSize.width = wxSize;
    vc.winSize.height= wySize;
    bSetupPixelFormat(hdc);
    vCreateRGBPalette(hdc);
    hrc = wglCreateContext(hdc);
    if (!hrc || !wglMakeCurrent(hdc, hrc))
        return NULL;
    glViewport(0, 0, wxSize, wySize);
    return hrc;
}
void
vCleanupGL(HGLRC hrc, HWND hwnd)
{
    HDC hdc = wglGetCurrentDC();
    if (ghPalette)
    {
        if ( gbUseStatic )
        {
            SetSystemPaletteUse(hdc, guiOldStaticUse);
            PostMessage(HWND_BROADCAST, WM_SYSCOLORCHANGE, 0, 0);
        }
        DeleteObject(SelectPalette(hdc, ghpalOld, FALSE));
    }
    /*  Destroy our context and release the DC */
    ReleaseDC(hwnd, hdc);
    wglDeleteContext(hrc);
}
/******************************Public*Routine******************************\
* PipesGetHWND()
*
* Get HWND for drawing.
*
* Note: done here so that pipes.lib is tk-independent.
*
\**************************************************************************/
HWND PipesGetHWND()
{
    return( hMainWindow );
}
/******************************Public*Routine******************************\
* TimerProc
*
* Procedure called on each screen saver timer tick to draw the next section
* of pipe.
*
\**************************************************************************/
void TimerProc(HWND hwnd)
{
    static int busy = FALSE;
    if (busy)
        return;
    busy = TRUE;
    updates++;
// Put stuff to be done on each update here:
    DrawPipes();
    busy = FALSE;
}
/******************************Public*Routine******************************\
* InitPipeSettings
*
* - translates variables set from the dialog boxes, into
*   variables used in pipelib.
*
\**************************************************************************/
void InitPipeSettings()
{
    // tesselation from fTesselFact(0.0-2.0) to tessLevel(0-MAX_TESS)
    tessLevel = (int) (fTesselFact * (MAX_TESS+1) / 2.0001f);
    // texturing state
    switch( ulTexQuality ) {
case TEXQUAL_LOW:
    textureQuality = TEX_LOW;
    break;
case TEXQUAL_HIGH:
default:
    textureQuality = TEX_MID;
    break;
    }
    if( ulSurfStyle == SURF_TEX ) {
// try to load the bmp file
// if nTexFileOffset is 0, then awchTexPathname is not a valid
// pathname and we should not call to load texture (InitBMPTexture
// calls glaux.lib which may try and put a MessageBox without focus
// -- this causes a problem and the screen saver will have to be
// killed).
if( nTexFileOffset &&
    InitBMPTexture( (char *) awchTexPathname, 1 ) ) {
    bTextureCoords = 1;
    bTexture = 1;
}
else {  // couldn't open .bmp file
    bTextureCoords = 0;
    bTexture = 0;
}
    }
    // joint types
    bCycleJointStyles = 0;
    switch( ulJointType ) {
case JOINT_ELBOW:
    jointStyle = ELBOWS;
    break;
case JOINT_BALL:
            jointStyle = BALLS;
    break;
case JOINT_MIXED:
    jointStyle = EITHER;
    break;
case JOINT_ALT:
    bCycleJointStyles = 1;
    jointStyle = EITHER;
    break;
default:
    break;
    }
}
/******************************Public*Routine******************************\
* ScreenSaverProc
*
* Screen saver window procedure.
*
\**************************************************************************/
LONG ScreenSaverProc(HWND hwnd, UINT message, WPARAM wParam,
                     LPARAM lParam)
{
    HDC hdc;
    PAINTSTRUCT ps;
    static POINT point;
    static WORD wTimer = 0;
    static BOOL bInited = FALSE;
    switch (message) {
    case WM_CREATE:
getIniSettings();
    // Make sure the selected texture file is OK.
if ( ulSurfStyle == SURF_TEX )
{
    ULONG w, h;
    WCHAR fileName[MAX_PATH];
    PWSTR pwsz;
    lstrcpyW(fileName, awchTexPathname);
    if ( SearchPathW(NULL, fileName, NULL, MAX_PATH,
     awchTexPathname, &pwsz)
 && bVerifyDIB(awchTexPathname, &w, &h)
                 && w <= TEX_WIDTH_MAX && h <= TEX_HEIGHT_MAX
       )
    {
nTexFileOffset = pwsz - awchTexPathname;
    }
    else
    {
                lstrcpyW(awchTexPathname, fileName);    // restore
nTexFileOffset = 0; // A valid pathname will never have this 0
    // so this is a good error indicator.
                if ( LoadStringW(hMainInstance, IDS_WARNING, gawchTitle, MAX_PATH) &&
                     LoadStringW(hMainInstance, IDS_RUN_CONTROL_PANEL, gawchFormat, MAX_PATH) )
                {
                    wsprintfW(gawch, gawchFormat, awchTexPathname);
                    MessageBoxW(NULL, gawch, gawchTitle, MB_OK);
                }
    }
}
        break;
    case WM_DESTROY:
        if (wTimer) {
            KillTimer(hwnd, wTimer);
        }
        // Put stuff to be done on app close here:
        if (gHrc)
            vCleanupGL(gHrc, hwnd);
        break;
    case WM_PAINT:
        hdc = BeginPaint(hwnd, &ps);
        EndPaint(hwnd, &ps);
    // Normally do this in WM_CREATE, but in this case if we do, you see
    // the system colors get changed.  By doing it here, we delay the
    // initialization until after the screen has already been cleared.
        if (!bInited)
        {
        // Put initial setup stuff here:
            bInited = TRUE;
            /* do not release the dc until we quit */
            if (hdc = GetDC(hwnd)) {
                if ( gHrc = hrcInitGL(hwnd, hdc) ) {
                    tkErrorPopups(FALSE);   // disable message boxes in GLAUX
                    InitPipeSettings();
                    InitPipes( MF_AUTO );
                    ReshapePipes( wxSize, wySize );
                    wTimer = SetTimer( hwnd, 1, 16, NULL );
                }
                else {
                    ReleaseDC(hwnd, hdc);
                }
            }
        }
        break;
    case WM_TIMER:
        TimerProc(hwnd);
        break;
    }
    return DefScreenSaverProc(hwnd, message, wParam, lParam);
}
#define BFT_BITMAP  0x4d42  // 'BM' -- indicates structure is BITMAPFILEHEADER
// struct BITMAPFILEHEADER {
//      WORD  bfType
//      DWORD bfSize
//      WORD  bfReserved1
//      WORD  bfReserved2
//      DWORD bfOffBits
// }
#define OFFSET_bfType       0
#define OFFSET_bfSize       2
#define OFFSET_bfReserved1  6
#define OFFSET_bfReserved2  8
#define OFFSET_bfOffBits    10
#define SIZEOF_BITMAPFILEHEADER 14
// Read a WORD-aligned DWORD.  Needed because BITMAPFILEHEADER has
// WORD-alignment.
#define READDWORD(pv)   ( (DWORD)((PWORD)(pv))[0]               \
                          | ((DWORD)((PWORD)(pv))[1] << 16) )   \
// Computes the number of BYTES needed to contain n number of bits.
#define BITS2BYTES(n)   ( ((n) + 7) >> 3 )
/******************************Public*Routine******************************\
* bVerifyDIB
*
* Stripped down version of tkDIBImageLoadAW that verifies that a bitmap
* file is valid and, if so, returns the bitmap dimensions.
*
* Returns:
*   TRUE if valid bitmap file; otherwise, FALSE.
*
\**************************************************************************/
BOOL bVerifyDIB(WCHAR *fileName, ULONG *pWidth, ULONG *pHeight)
{
    BOOL bRet = FALSE;
    BITMAPFILEHEADER *pbmf;         // Ptr to file header
    BITMAPINFOHEADER *pbmihFile;    // Ptr to file's info header (if it exists)
    BITMAPCOREHEADER *pbmchFile;    // Ptr to file's core header (if it exists)
    // These need to be cleaned up when we exit:
    HANDLE     hFile = INVALID_HANDLE_VALUE;        // File handle
    HANDLE     hMap = (HANDLE) NULL;                // Mapping object handle
    PVOID      pvFile = (PVOID) NULL;               // Ptr to mapped file
// Map the DIB file into memory.
    hFile = CreateFileW((LPWSTR) fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
    if (hFile == INVALID_HANDLE_VALUE)
        goto bVerifyDIB_cleanup;
    hMap = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
    if (!hMap)
        goto bVerifyDIB_cleanup;
    pvFile = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
    if (!pvFile)
        goto bVerifyDIB_cleanup;
// Check the file header.  If the BFT_BITMAP magic number is there,
// then the file format is a BITMAPFILEHEADER followed immediately
// by either a BITMAPINFOHEADER or a BITMAPCOREHEADER.  The bitmap
// bits, in this case, are located at the offset bfOffBits from the
// BITMAPFILEHEADER.
//
// Otherwise, this may be a raw BITMAPINFOHEADER or BITMAPCOREHEADER
// followed immediately with the color table and the bitmap bits.
    pbmf = (BITMAPFILEHEADER *) pvFile;
    if ( pbmf->bfType == BFT_BITMAP )
        pbmihFile = (BITMAPINFOHEADER *) ((PBYTE) pbmf + SIZEOF_BITMAPFILEHEADER);
    else
        pbmihFile = (BITMAPINFOHEADER *) pvFile;
// Get the width and height from whatever header we have.
//
// We distinguish between BITMAPINFO and BITMAPCORE cases based upon
// BITMAPINFOHEADER.biSize.
    // Note: need to use safe READDWORD macro because pbmihFile may
    // have only WORD alignment if it follows a BITMAPFILEHEADER.
    switch (READDWORD(&pbmihFile->biSize))
    {
    case sizeof(BITMAPINFOHEADER):
        *pWidth  = READDWORD(&pbmihFile->biWidth);
        *pHeight = READDWORD(&pbmihFile->biHeight);
        bRet = TRUE;
        break;
    case sizeof(BITMAPCOREHEADER):
        pbmchFile = (BITMAPCOREHEADER *) pbmihFile;
    // Convert BITMAPCOREHEADER to BITMAPINFOHEADER.
        *pWidth  = (DWORD) pbmchFile->bcWidth;
        *pHeight = (DWORD) pbmchFile->bcHeight;
        bRet = TRUE;
        break;
    default:
        break;
    }
bVerifyDIB_cleanup:
    if (pvFile)
        UnmapViewOfFile(pvFile);
    if (hMap)
        CloseHandle(hMap);
    if (hFile != INVALID_HANDLE_VALUE)
        CloseHandle(hFile);
    return bRet;
}


TEXTURE.H  (PIPES Sample)
/******************************Module*Header*******************************\
* Module Name: texture.h
*
* Externals from texture.c
*
* Copyright (c) 1994 Microsoft Corporation
*
\**************************************************************************/
extern mfPoint2di texRep;  // texture repetition


TEXTURE.C  (PIPES Sample)
/******************************Module*Header*******************************\
* Module Name: texture.c
*
* Handles texture initialization
*
* Copyright (c) 1994 Microsoft Corporation
*
\**************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <sys/types.h>
#include <time.h>
#include <windows.h>
#include <GL/gl.h>
#include <GL/glaux.h>
#include "pipes.h"
#include "texture.h"
mfPoint2di texRep; // texture repetition factors
// creates a texture from a BMP file
int InitBMPTexture( char *bmpfile, int wflag )
{
    AUX_RGBImageRec *image = (AUX_RGBImageRec *) NULL;
    double xPow2, yPow2;
    int ixPow2, iyPow2;
    int xSize2, ySize2;
    BYTE *pData;
    float fxFact, fyFact;
    GLint glMaxTexDim;
    // load the bmp file
    if( wflag )
image = auxDIBImageLoadW( (LPCWSTR) bmpfile);
    else
image = auxDIBImageLoadA( bmpfile );
    if( !image )
return 0; // failure
    glEnable(GL_TEXTURE_2D);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
    switch( textureQuality ) {
case TEX_HIGH:
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
    GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
    GL_LINEAR_MIPMAP_NEAREST);
    break;
case TEX_MID:
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    break;
case TEX_LOW:
default:
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    break;
    }
    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &glMaxTexDim);
    glMaxTexDim = min(256, glMaxTexDim);
    if (image->sizeX <= glMaxTexDim)
        xPow2 = log((double)image->sizeX) / log((double)2.0);
    else
        xPow2 = log((double)glMaxTexDim) / log((double)2.0);
    if (image->sizeY <= glMaxTexDim)
        yPow2 = log((double)image->sizeY) / log((double)2.0);
    else
        yPow2 = log((double)glMaxTexDim) / log((double)2.0);
    ixPow2 = (int)xPow2;
    iyPow2 = (int)yPow2;
    if (xPow2 != (double)ixPow2)
        ixPow2++;
    if (yPow2 != (double)iyPow2)
        iyPow2++;
    xSize2 = 1 << ixPow2;
    ySize2 = 1 << iyPow2;
    pData = LocalAlloc(LMEM_FIXED, xSize2 * ySize2 * 3 * sizeof(BYTE));
    if (!pData)
        return 0;
    gluScaleImage(GL_RGB, image->sizeX, image->sizeY,
                  GL_UNSIGNED_BYTE, image->data,
                  xSize2, ySize2, GL_UNSIGNED_BYTE,
                  pData);
    if( textureQuality == TEX_HIGH ) {
        gluBuild2DMipmaps(GL_TEXTURE_2D, 3, image->sizeX, image->sizeY,
  GL_RGB, GL_UNSIGNED_BYTE, image->data);
    }
    else {
           glTexImage2D(GL_TEXTURE_2D, 0, 3, xSize2, ySize2,
                         0, GL_RGB, GL_UNSIGNED_BYTE, pData);
    }
    // Figure out repetition factor of texture, based on bitmap size and
    // screen size.
    //
    // We arbitrarily decide to repeat textures that are smaller than
    // 1/8th of screen width or height.
    texRep.x = texRep.y = 1;
    if( (fxFact = vc.winSize.width / xSize2 / 8.0f) >= 1.0f)
texRep.x = (int) (fxFact+0.5f);
    if( (fyFact = vc.winSize.height / ySize2 / 8.0f) >= 1.0f)
texRep.y = (int) (fyFact+0.5f);
    LocalFree(image->data);
    image->data = pData;
    return 1; // success
}


UTIL.H  (PIPES Sample)
/******************************Module*Header*******************************\
* Module Name: util.h
*
* Externals from util.c
*
* Copyright (c) 1994 Microsoft Corporation
*
\**************************************************************************/
extern int  mfRand( int );
extern void RectWipeClear( int width, int height );


UTIL.C  (PIPES Sample)
/******************************Module*Header*******************************\
* Module Name: util.c
*
* Misc. utility functions
*
* Copyright (c) 1994 Microsoft Corporation
*
\**************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <windows.h>
#include <GL/gl.h>
extern HWND PipesGetHWND();
/*-----------------------------------------------------------------------
|
|
|    mfRand(numVal):
|
|        Generates random number 0..(numVal-1)
|
|
|
-----------------------------------------------------------------------*/
int mfRand( int numVal )
{
    int num;
    num = (int) ( numVal * ( ((float)rand()) / ((float)(RAND_MAX+1)) ) );
    return num;
}
/*-----------------------------------------------------------------------
|
|
|    RectWipeClear(width, height):                                      |
|       - Does a rectangular wipe (or clear) by drawing in a sequence   |
|         of rectangles using Gdi                                       |
|
MOD: add calibrator capability to adjust speed for different
|
|
     architectures
|
|
|
-----------------------------------------------------------------------*/
void RectWipeClear( int width, int height )
{
    HWND hwnd;
    HDC hdc;
    HBRUSH hbr;
    RECT rect;
    int i, j, xinc, yinc, numDivs = 500;
    int xmin, xmax, ymin, ymax;
    int repCount = 3;
    xinc = 1;
    yinc = 1;
    numDivs = height;
    xmin = ymin = 0;
    xmax = width;
    ymax = height;
    hwnd = PipesGetHWND();
    hdc = GetDC( hwnd );
    hbr = CreateSolidBrush( RGB( 0, 0, 0 ) );
    for( i = 0; i < (numDivs/2 - 1); i ++ ) {
      for( j = 0; j < repCount; j ++ ) {
rect.left = xmin; rect.top = ymin;
rect.right = xmax; rect.bottom = ymin + yinc;
FillRect( hdc, &rect, hbr );
rect.top = ymax - yinc;
rect.bottom = ymax;
FillRect( hdc, &rect, hbr );
rect.top = ymin + yinc;
rect.right = xmin + xinc; rect.bottom = ymax - yinc;
FillRect( hdc, &rect, hbr );
rect.left = xmax - xinc; rect.top = ymin + yinc;
rect.right = xmax; rect.bottom = ymax - yinc;
FillRect( hdc, &rect, hbr );
      }
xmin += xinc;
xmax -= xinc;
ymin += yinc;
ymax -= yinc;
    }
    // clear last square in middle
    rect.left = xmin; rect.top = ymin;
    rect.right = xmax; rect.bottom = ymax;
    FillRect( hdc, &rect, hbr );
    ReleaseDC( hwnd, hdc );
    GdiFlush();
}


AbortProc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user-defined
Header File
wingdi.h
Unicode
No
Platform Notes
None


acmDriverEnumCallback
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user-defined
Header File
msacm.h
Unicode
No
Platform Notes
None


acmDriverProc
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user-defined
Header File
msacm.h
Unicode
No
Platform Notes
None


acmFilterChooseHookProc
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user-defined
Header File
msacm.h
Unicode
WinNT
Platform Notes
None


acmFilterEnumCallback
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user-defined
Header File
msacm.h
Unicode
WinNT
Platform Notes
None


acmFilterTagEnumCallback
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user-defined
Header File
msacm.h
Unicode
WinNT
Platform Notes
None


acmFormatChooseHookProc
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user-defined
Header File
msacm.h
Unicode
WinNT
Platform Notes
None


acmFormatEnumCallback
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user-defined
Header File
msacm.h
Unicode
WinNT
Platform Notes
None


acmFormatTagEnumCallback
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user-defined
Header File
msacm.h
Unicode
WinNT
Platform Notes
None


acmStreamConvertCallback
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user-defined
Header File
Unicode
Platform Notes
None


AddPropSheetPageProc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user-defined
Header File
prsht.h
Unicode
Platform Notes
None


BrowseCallbackProc
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


CallWndProc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user-defined
Header File
winuser.h
Unicode
No
Platform Notes
None


CallWndRetProc
Windows NT
No
Win95
Yes
Win32s
No
Import Library
user-defined
Header File
winuser.h
Unicode
Platform Notes
None


CBTProc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user-defined
Header File
winuser.h
Unicode
No
Platform Notes
None


CplApplet
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user-defined
Header File
cpl.h
Unicode
No
Platform Notes
None


DdeCallback
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user-defined
Header File
ddeml.h
Unicode
No
Platform Notes
None


DebugProc
Windows NT
Yes
Win95
No
Win32s
No
Import Library
user-defined
Header File
winuser.h
Unicode
Platform Notes
None


DialogProc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user-defined
Header File
winuser.h
Unicode
No
Platform Notes
None


DrawStateProc
Windows NT
No
Win95
Yes
Win32s
No
Import Library
user-defined
Header File
winuser.h
Unicode
Platform Notes
None


DriverProc
Windows NT
No
Win95
Yes
Win32s
No
Import Library
user-defined
Header File
mmsystem.h
Unicode
Platform Notes
None


EditWordBreakProc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user-defined
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


EditWordBreakProcEx
Windows NT
No
Win95
Yes
Win32s
No
Import Library
user-defined
Header File
richedit.h
Unicode
Platform Notes
None


EnhMetaFileProc
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user-defined
Header File
wingdi.h
Unicode
No
Platform Notes
None


EnumCalendarInfoProc
Windows NT
New
Win95
No
Win32s
New
Import Library
user-defined
Header File
winnls.h
Unicode
WinNT
Platform Notes
None


EnumChildProc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user-defined
Header File
winuser.h
Unicode
No
Platform Notes
None


EnumCodePagesProc
Windows NT
New
Win95
No
Win32s
New
Import Library
user-defined
Header File
winnls.h
Unicode
WinNT
Platform Notes
None


EnumDateFormatsProc
Windows NT
New
Win95
No
Win32s
New
Import Library
user-defined
Header File
winnls.h
Unicode
WinNT
Platform Notes
None


EnumDesktopProc
Windows NT
Yes
Win95
No
Win32s
No
Import Library
user-defined
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


EnumFontFamExProc
Windows NT
No
Win95
Yes
Win32s
No
Import Library
user-defined
Header File
wingdi.h
Unicode
Platform Notes
None


EnumFontFamProc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user-defined
Header File
wingdi.h
Unicode
No
Platform Notes
None


EnumFontsProc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user-defined
Header File
wingdi.h
Unicode
No
Platform Notes
None


EnumICMProfilesProc
Windows NT
No
Win95
Yes
Win32s
No
Import Library
user-defined
Header File
wingdi.h
Unicode
WinNT
Platform Notes
None


EnumLocalesProc
Windows NT
New
Win95
No
Win32s
New
Import Library
user-defined
Header File
winnls.h
Unicode
WinNT
Platform Notes
None


EnumMetaFileProc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user-defined
Header File
wingdi.h
Unicode
No
Platform Notes
None


EnumObjectsProc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user-defined
Header File
wingdi.h
Unicode
No
Platform Notes
None


EnumRegisterWordProc
Windows NT
No
Win95
Yes
Win32s
No
Import Library
user-defined
Header File
imm.h
Unicode
No
Platform Notes
None


EnumResLangProc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user-defined
Header File
winbase.h
Unicode
No
Platform Notes
None


EnumResNameProc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user-defined
Header File
winbase.h
Unicode
No
Platform Notes
None


EnumResTypeProc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user-defined
Header File
winbase.h
Unicode
No
Platform Notes
None


EnumThreadWndProc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user-defined
Header File
winuser.h
Unicode
No
Platform Notes
None


EnumTimeFormatsProc
Windows NT
New
Win95
No
Win32s
New
Import Library
user-defined
Header File
winnls.h
Unicode
WinNT
Platform Notes
None


EnumWindowsProc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user-defined
Header File
winuser.h
Unicode
No
Platform Notes
None


EnumWindowStationProc
Windows NT
New
Win95
No
Win32s
No
Import Library
user-defined
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


ExtensionPropSheetPageProc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user-defined
Header File
prsht.h
Unicode
No
Platform Notes
None


FileIOCompletionRoutine
Windows NT
Yes
Win95
No
Win32s
No
Import Library
user-defined
Header File
winbase.h
Unicode
Platform Notes
None


FMExtensionProc
Windows NT
Yes
Win95
No
Win32s
No
Import Library
user-defined
Header File
wfext.h
Unicode
WinNT
Platform Notes
Windows 95: Only supports 16-bit FileManager


ForegroundIdleProc
Windows NT
Yes
Win95
No
Win32s
No
Import Library
user-defined
Header File
winuser.h
Unicode
No
Platform Notes
None


GetMsgProc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user-defined
Header File
winuser.h
Unicode
No
Platform Notes
None


IOProc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user-defined
Header File
mmsystem.h
Unicode
No
Platform Notes
None


JournalPlaybackProc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user-defined
Header File
winuser.h
Unicode
No
Platform Notes
None


JournalRecordProc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user-defined
Header File
winuser.h
Unicode
No
Platform Notes
None


KeyboardProc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user-defined
Header File
winuser.h
Unicode
No
Platform Notes
None


LineDDAProc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user-defined
Header File
wingdi.h
Unicode
No
Platform Notes
None


MessageProc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user-defined
Header File
winuser.h
Unicode
No
Platform Notes
None


MidiInProc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user-defined
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MidiOutProc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user-defined
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MidiProc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user-defined
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MMIOProc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user-defined
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MouseProc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user-defined
Header File
winuser.h
Unicode
No
Platform Notes
None


MyStatusProc
Windows NT
Win95
Yes
Win32s
Import Library
user-defined
Header File
vfw.h
Unicode
Platform Notes
None


OutputProc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user-defined
Header File
winuser.h
Unicode
No
Platform Notes
None


PropEnumProc
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user-defined
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


PropEnumProcEx
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user-defined
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


PropSheetPageProc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user-defined
Header File
prsht.h
Unicode
WinNT
Platform Notes
None


PropSheetProc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user-defined
Header File
prsht.h
Unicode
No
Platform Notes
None


RasDialFunc
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user-defined
Header File
ras.h
Unicode
No
Platform Notes
None


RasDialFunc1
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user-defined
Header File
ras.h
Unicode
No
Platform Notes
None


SendAsyncProc
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user-defined
Header File
winuser.h
Unicode
No
Platform Notes
None


ShellProc
Windows NT
Yes
Win95
Yes
Win32s
Import Library
user-defined
Header File
winuser.h
Unicode
No
Platform Notes
None


SoundSentryProc
Windows NT
Yes
Win95
Yes
Win32s
Import Library
user-defined
Header File
Unicode
Platform Notes
None


SysMsgProc
Windows NT
Yes
Win95
Yes
Win32s
Import Library
user-defined
Header File
winuser.h
Unicode
Platform Notes
None


TimeProc
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user-defined
Header File
mmsystem.h
Unicode
Platform Notes
None


TimerProc
Windows NT
Yes
Win95
No
Win32s
No
Import Library
user-defined
Header File
winuser.h
Unicode
No
Platform Notes
None


UndeleteFile
Windows NT
Win95
Win32s
Import Library
user-defined
Header File
wfext.h
Unicode
No
Platform Notes
None


waveInProc
Windows NT
Yes
Win95
Yes
Win32s
Import Library
user-defined
Header File
mmsystem.h
Unicode
Platform Notes
None


waveOutProc
Windows NT
Yes
Win95
Yes
Win32s
Import Library
user-defined
Header File
mmsystem.h
Unicode
Platform Notes
None


WaveProc
Windows NT
Yes
Win95
Yes
Win32s
Import Library
user-defined
Header File
mmsystem.h
Unicode
Platform Notes
None


WindowProc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user-defined
Header File
winuser.h
Unicode
Platform Notes
None


BS_3STATE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


BS_AUTO3STATE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


BS_AUTOCHECKBOX
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


BS_AUTORADIOBUTTON
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


BS_BITMAP
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


BS_BOTTOM
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


BS_CENTER
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


BS_CHECKBOX
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


BS_DEFPUSHBUTTON
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


BS_DIBPATTERN
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: Only supports 8x8 brushes


BS_DIBPATTERN8X8
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
wingdi.h
Unicode
No
Platform Notes
None


BS_DIBPATTERNPT
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
wingdi.h
Unicode
No
Platform Notes
None


BS_GROUPBOX
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


BS_HATCHED
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
wingdi.h
Unicode
No
Platform Notes
None


BS_HOLLOW
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
wingdi.h
Unicode
No
Platform Notes
None


BS_ICON
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


BS_INDEXED
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
wingdi.h
Unicode
No
Platform Notes
None


BS_LEFT
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


BS_MULTILINE
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


BS_NOTIFY
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


BS_NULL
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
wingdi.h
Unicode
No
Platform Notes
None


BS_OWNERDRAW
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


BS_PATTERN
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
wingdi.h
Unicode
No
Platform Notes
None


BS_PATTERN8X8
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
wingdi.h
Unicode
No
Platform Notes
None


BS_PUSHBUTTON
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


BS_PUSHLIKE
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


BS_RADIOBUTTON
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


BS_RIGHT
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


BS_RIGHTBUTTON
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


BS_SOLID
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
wingdi.h
Unicode
No
Platform Notes
None


BS_TEXT
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


BS_TOP
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


BS_VCENTER
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CBS_AUTOHSCROLL
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CBS_DISABLENOSCROLL
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CBS_DROPDOWN
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CBS_DROPDOWNLIST
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CBS_HASSTRINGS
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CBS_LOWERCASE
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CBS_NOINTEGRALHEIGHT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CBS_OEMCONVERT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CBS_OWNERDRAWFIXED
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CBS_OWNERDRAWVARIABLE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CBS_SIMPLE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CBS_SORT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CBS_UPPERCASE
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


LBS_DISABLENOSCROLL
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


LBS_EXTENDEDSEL
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


LBS_HASSTRINGS
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


LBS_MULTICOLUMN
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


LBS_MULTIPLESEL
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


LBS_NODATA
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


LBS_NOINTEGRALHEIGHT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


LBS_NOREDRAW
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


LBS_NOTIFY
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


LBS_OWNERDRAWFIXED
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


LBS_OWNERDRAWVARIABLE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


LBS_SORT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


LBS_STANDARD
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


LBS_USETABSTOPS
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


LBS_WANTKEYBOARDINPUT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


PS_ALTERNATE
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
wingdi.h
Unicode
No
Platform Notes
None


PS_COSMETIC
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
wingdi.h
Unicode
No
Platform Notes
None


PS_DASH
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: Doesn't support this in a wideline


PS_DASHDOT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: Doesn't support this in a wideline


PS_DASHDOTDOT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: Doesn't support this in a wideline


PS_DOT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: Doesn't support this in a wideline


PS_ENDCAP_FLAT
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: Supported only in a path


PS_ENDCAP_ROUND
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: Supported only in a path


PS_ENDCAP_SQUARE
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: Supported only in a path


PS_GEOMETRIC
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
wingdi.h
Unicode
No
Platform Notes
None


PS_INSIDEFRAME
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
wingdi.h
Unicode
No
Platform Notes
None


PS_JOIN_BEVEL
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: Supported only in a path


PS_JOIN_MITER
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: Supported only in a path


PS_JOIN_ROUND
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: Supported only in a path


PS_NULL
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
wingdi.h
Unicode
No
Platform Notes
None


PS_SOLID
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
wingdi.h
Unicode
No
Platform Notes
None


PS_USERSTYLE
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
wingdi.h
Unicode
No
Platform Notes
None


WM_DDE_FIRST
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
dde.h
Unicode
No
Platform Notes
None


WM_DDE_LAST
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
dde.h
Unicode
No
Platform Notes
None


WM_MOUSEFIRST
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
Platform Notes
None


WM_MOUSELAST
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
Platform Notes
None


WM_PENWINFIRST
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_PENWINLAST
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WS_EX_ACCEPTFILES
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WS_EX_DLGMODALFRAME
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WS_EX_NOPARENTNOTIFY
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WS_EX_TOPMOST
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WS_EX_TRANSPARENT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


XTYP_ADVDATA
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
ddeml.h
Unicode
Platform Notes
None


XTYP_ADVREQ
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
ddeml.h
Unicode
Platform Notes
None


XTYP_ADVSTART
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
ddeml.h
Unicode
Platform Notes
None


XTYP_ADVSTOP
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
ddeml.h
Unicode
Platform Notes
None


XTYP_CONNECT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
ddeml.h
Unicode
Platform Notes
None


XTYP_CONNECT_CONFIRM
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
ddeml.h
Unicode
Platform Notes
None


XTYP_DISCONNECT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
ddeml.h
Unicode
Platform Notes
None


XTYP_ERROR
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
ddeml.h
Unicode
Platform Notes
None


XTYP_EXECUTE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
ddeml.h
Unicode
Platform Notes
None


XTYP_MONITOR
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
ddeml.h
Unicode
Platform Notes
None


XTYP_POKE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
ddeml.h
Unicode
Platform Notes
None


XTYP_REGISTER
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
ddeml.h
Unicode
Platform Notes
None


XTYP_REQUEST
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
ddeml.h
Unicode
Platform Notes
None


XTYP_UNREGISTER
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
ddeml.h
Unicode
Platform Notes
None


XTYP_WILDCONNECT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
ddeml.h
Unicode
Platform Notes
None


XTYP_XACT_COMPLETE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
ddeml.h
Unicode
Platform Notes
None


FSCTL_DISMOUNT_VOLUME
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
winioctl.h
Unicode
No
Platform Notes
None


FSCTL_GET_COMPRESSION
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
winioctl.h
Unicode
No
Platform Notes
None


FSCTL_LOCK_VOLUME
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
winioctl.h
Unicode
No
Platform Notes
None


FSCTL_SET_COMPRESSION
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
winioctl.h
Unicode
No
Platform Notes
None


FSCTL_UNLOCK_VOLUME
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
winioctl.h
Unicode
No
Platform Notes
None


IOCTL_DISK_CHECK_VERIFY
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
winioctl.h
Unicode
No
Platform Notes
None


IOCTL_DISK_EJECT_MEDIA
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
winioctl.h
Unicode
No
Platform Notes
None


IOCTL_DISK_FORMAT_TRACKS
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
winioctl.h
Unicode
No
Platform Notes
None


IOCTL_DISK_GET_DRIVE_GEOMETRY
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
winioctl.h
Unicode
No
Platform Notes
None


IOCTL_DISK_GET_DRIVE_LAYOUT
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
winioctl.h
Unicode
No
Platform Notes
None


IOCTL_DISK_GET_MEDIA_TYPES
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
winioctl.h
Unicode
No
Platform Notes
None


IO
CTL_DISK_GET_PARTITION_INFO
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
winioctl.h
Unicode
No
Platform Notes
None


IOCTL_DISK_LOAD_MEDIA
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
winioctl.h
Unicode
No
Platform Notes
None


IOCTL_DISK_MEDIA_REMOVAL
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
winioctl.h
Unicode
No
Platform Notes
None


IOCTL_DISK_PERFORMANCE
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
winioctl.h
Unicode
No
Platform Notes
None


IOCTL_DISK_REASSIGN_BLOCKS
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
winioctl.h
Unicode
No
Platform Notes
None


IOCTL_DISK_SET_DRIVE_LAYOUT
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
winioctl.h
Unicode
No
Platform Notes
None


IO
CTL_DISK_SET_PARTITION_INFO
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
winioctl.h
Unicode
No
Platform Notes
None


IOCTL_DISK_VERIFY
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
winioctl.h
Unicode
No
Platform Notes
None


IOCTL_SERIAL_LSRMST_INSERT
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
winioctl.h
Unicode
No
Platform Notes
None


ACL_INFORMATION_CLASS
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
winnt.h
Unicode
Platform Notes
None


FD_FLAGS
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


MEDIA_TYPE
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
winioctl.h
Unicode
Platform Notes
None


RASCONNSTATE
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
ras.h
Unicode
Platform Notes
None


RASPROJECTION
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
ras.h
Unicode
Platform Notes
None


SECURITY_IMPERSONATION_LEVEL
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
winnt.h
Unicode
Platform Notes
None


SID_NAME_USE
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
winnt.h
Unicode
Platform Notes
None


TOKEN_INFORMATION_CLASS
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
winnt.h
Unicode
Platform Notes
None


TOKEN_TYPE
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
winnt.h
Unicode
Platform Notes
None


__WSAFDIsSet
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


_hread
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


_hwrite
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


_lclose
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


_lcreat
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


_llseek
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


_lopen
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


_lread
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


_lwrite
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


AbnormalTermination
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
rpc.h
Unicode
No
Platform Notes
None


AbortDoc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


AbortPath
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


AbortPrinter
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
winspool.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


AbortSystemShutdown
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winreg.h
Unicode
WinNT
Platform Notes
None


accept
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


AccessCheck
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


AccessCheckAndAuditAlarm
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


acmDriverAdd
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
msacm32.lib
Header File
msacm.h
Unicode
WinNT
Platform Notes
None


acmDriverClose
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
msacm32.lib
Header File
msacm.h
Unicode
No
Platform Notes
None


acmDriverDetails
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
msacm32.lib
Header File
msacm.h
Unicode
WinNT
Platform Notes
None


acmDriverEnum
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
msacm32.lib
Header File
msacm.h
Unicode
No
Platform Notes
None


acmDriverID
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
msacm32.lib
Header File
msacm.h
Unicode
No
Platform Notes
None


acmDriverMessage
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
msacm32.lib
Header File
msacm.h
Unicode
No
Platform Notes
None


acmDriverOpen
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
msacm32.lib
Header File
msacm.h
Unicode
No
Platform Notes
None


acmDriverPriority
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
msacm32.lib
Header File
msacm.h
Unicode
No
Platform Notes
None


acmDriverRemove
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
msacm32.lib
Header File
msacm.h
Unicode
No
Platform Notes
None


acmFilterChoose
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
msacm32.lib
Header File
msacm.h
Unicode
WinNT
Platform Notes
None


acmFilterDetails
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
msacm32.lib
Header File
msacm.h
Unicode
WinNT
Platform Notes
None


acmFilterEnum
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
msacm32.lib
Header File
msacm.h
Unicode
WinNT
Platform Notes
None


acmFilterTagDetails
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
msacm32.lib
Header File
msacm.h
Unicode
WinNT
Platform Notes
None


acmFilterTagEnum
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
msacm32.lib
Header File
msacm.h
Unicode
WinNT
Platform Notes
None


acmFormatChoose
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
msacm32.lib
Header File
msacm.h
Unicode
WinNT
Platform Notes
None


acmFormatDetails
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
msacm32.lib
Header File
msacm.h
Unicode
WinNT
Platform Notes
None


acmFormatEnum
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
msacm32.lib
Header File
msacm.h
Unicode
WinNT
Platform Notes
None


acmFormatSuggest
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
msacm32.lib
Header File
msacm.h
Unicode
No
Platform Notes
None


acmFormatTagDetails
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
msacm32.lib
Header File
msacm.h
Unicode
WinNT
Platform Notes
None


acmFormatTagEnum
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
msacm32.lib
Header File
msacm.h
Unicode
WinNT
Platform Notes
None


acmGetVersion
Windows NT
New
Win95
Yes
Win32s
No
Import Library
msacm32.lib
Header File
msacm.h
Unicode
No
Platform Notes
None


acmMetrics
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
msacm32.lib
Header File
msacm.h
Unicode
No
Platform Notes
None


acmStreamClose
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
msacm32.lib
Header File
msacm.h
Unicode
No
Platform Notes
None


acmStreamConvert
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
msacm32.lib
Header File
msacm.h
Unicode
No
Platform Notes
None


acmStreamOpen
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
msacm32.lib
Header File
msacm.h
Unicode
No
Platform Notes
None


acmStreamPrepareHeader
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
msacm32.lib
Header File
msacm.h
Unicode
No
Platform Notes
None


acmStreamReset
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
msacm32.lib
Header File
msacm.h
Unicode
No
Platform Notes
None


acmStreamSize
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
msacm32.lib
Header File
msacm.h
Unicode
No
Platform Notes
None


acmStreamUnprepareHeader
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
msacm32.lib
Header File
msacm.h
Unicode
No
Platform Notes
None


AcsLan
Windows NT
Yes
Win95
No
Win32s
No
Import Library
dlcapi.lib
Header File
dlcapi.h
Unicode
No
Platform Notes
None


ActivateKeyboardLayout
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


AddAccessAllowedAce
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


AddAccessDeniedAce
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


AddAce
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


AddAtom
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


AddAuditAccessAce
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


AddFontResource
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
WinNT
Platform Notes
Windows 95: int == 16 bits


AddForm
Windows NT
Yes
Win95
No
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
WinNT
Platform Notes
None


AddJob
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
WinNT
Platform Notes
None


AddMonitor
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
WinNT
Platform Notes
None


AddPort
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
WinNT
Platform Notes
None


AddPrinter
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
WinNT
Platform Notes
None


AddPrinterDriver
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
WinNT
Platform Notes
None


AddPrintProcessor
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
WinNT
Platform Notes
None


AddPrintProvidor
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
WinNT
Platform Notes
None


AdjustTokenGroups
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


AdjustTokenPrivileges
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


AdjustWindowRect
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


AdjustWindowRectEx
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


AdvancedDocumentProperties
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
WinNT
Platform Notes
None


AllocateAndInitializeSid
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


AllocateLocallyUniqueId
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


AllocConsole
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
wincon.h
Unicode
No
Platform Notes
None


AngleArc
Windows NT
Yes
Win95
No
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


AnimatePalette
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


AnsiLower
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


AnsiLowerBuff
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


AnsiNext
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


AnsiPrev
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


AnsiToOem
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


AnsiToOemBuff
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


AnsiUpper
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


AnsiUpperBuff
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


AnyPopup
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


AppendMenu
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


Arc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


ArcTo
Windows NT
Yes
Win95
No
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


AreAllAccessesGranted
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


AreAnyAccessesGranted
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


AreFileApisANSI
Windows NT
New
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
On Win32s the file APIs are always ANSI


ArrangeIconicWindows
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


AttachThreadInput
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


auxGetDevCaps
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
WinNT
Platform Notes
None


auxGetNumDevs
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


auxGetVolume
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


auxOutMessage
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


auxSetVolume
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


AVIBuildFilter
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
WinNT
Platform Notes
None


AVIClearClipboard
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


AVIFileAddRef
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


AVIFileCreateStream
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


AVIFileEndRecord
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


AVIFileExit
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


AVIFileGetStream
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


AVIFileInfo
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
WinNT
Platform Notes
None


AVIFileInit
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


AVIFileOpen
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
WinNT
Platform Notes
None


AVIFileReadData
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


AVIFileRelease
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


AVIFileWriteData
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


AVIGetFromClipboard
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


AVIMakeCompressedStream
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


AVIMakeFileFromStreams
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


AVIMakeStreamFromClipboard
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


AVIPutFileOnClipboard
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


AVISave
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
WinNT
Platform Notes
None


AVISaveOptions
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


AVISaveOptionsFree
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


AVISaveV
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
WinNT
Platform Notes
None


AVIStreamAddRef
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


AVIStreamBeginStreaming
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


AVIStreamCreate
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


AVIStreamEndStreaming
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


AVIStreamFindSample
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


AVIStreamGetFrame
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


AVIStreamGetFrameClose
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


AVIStreamGetFrameOpen
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


AVIStreamInfo
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
WinNT
Platform Notes
None


AVIStreamLength
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


AVIStreamOpenFromFile
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
WinNT
Platform Notes
None


AVIStreamRead
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


AVIStreamReadData
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


AVIStreamReadFormat
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


AVIStreamRelease
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


AVIStreamSampleToTime
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


AVIStreamSetFormat
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


AVIStreamStart
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


AVIStreamTimeToSample
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


AVIStreamWrite
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


AVIStreamWriteData
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


BackupEventLog
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


BackupRead
Windows NT
Yes
Win95
No
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


BackupSeek
Windows NT
Yes
Win95
No
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


BackupWrite
Windows NT
Yes
Win95
No
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


Beep
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


BeginDeferWindowPos
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


BeginPaint
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


BeginPath
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


BeginUpdateResource
Windows NT
Yes
Win95
No
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


bind
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


BindMoniker
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


BitBlt
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


BringWindowToTop
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


BroadcastSystemMessage
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


BuildCommDCB
Windows NT
New
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


BuildCommDCBAndTimeouts
Windows NT
New
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


CallMsgFilter
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


CallNamedPipe
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


CallNextHookEx
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


CallProc32W
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


CallProcEx32W
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


CallWindowProc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


CancelDC
Windows NT
Yes
Win95
No
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


capCreateCaptureWindow
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
WinNT
Platform Notes
None


capGetDriverDescription
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
WinNT
Platform Notes
None


CascadeWindows
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


ChangeClipboardChain
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


ChangeDisplaySettings
Windows NT
Yes
Win95
Yes
Win32s
Import Library
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


ChangeMenu
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


ChangeServiceConfig
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winsvc.h
Unicode
WinNT
Platform Notes
None


char_array_from_ndr
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcndr.h
Unicode
Platform Notes
None


char_from_ndr
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcndr.h
Unicode
Platform Notes
None


CharLower
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


CharLowerBuff
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


CharNext
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


CharNextExA
Windows NT
No
Win95
Yes
Win32s
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


CharPrev
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


CharPrevExA
Windows NT
No
Win95
Yes
Win32s
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


CharToOem
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


CharToOemBuff
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


CharUpper
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


CharUpperBuff
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


CheckColorsInGamut
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


CheckDlgButton
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


CheckMenuItem
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


CheckMenuRadioItem
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


CheckRadioButton
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


ChildWindowFromPoint
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


ChildWindowFromPointEx
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


ChooseColor
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
comdlg32.lib
Header File
commdlg.h
Unicode
WinNT
Platform Notes
None


ChooseFont
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
comdlg32.lib
Header File
commdlg.h
Unicode
WinNT
Platform Notes
None


ChoosePixelFormat
Windows NT
Yes
Win95
No
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


Chord
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


ClearCommBreak
Windows NT
New
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


ClearCommError
Windows NT
New
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


ClearEventLog
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


ClientToScreen
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


ClipCursor
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


CloseClipboard
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


CloseDesktop
Windows NT
Yes
Win95
No
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


CloseEnhMetaFile
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


CloseEventLog
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


CloseFigure
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


CloseHandle
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


CloseMetaFile
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


ClosePrinter
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
No
Platform Notes
None


CloseServiceHandle
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winsvc.h
Unicode
No
Platform Notes
None


closesocket
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


CloseWindow
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


CloseWindowStation
Windows NT
Yes
Win95
No
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


CLSIDFromProgID
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


CLSIDFromString
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


CoBuildVersion
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


CoCreateGuid
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


CoCreateInstance
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


CoDisconnectObject
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


CoDosDateTimeToFileTime
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


CoFileTimeNow
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


CoFileTimeToDosDateTime
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


CoFreeAllLibraries
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


CoFreeLibrary
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


CoFreeUnusedLibraries
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


CoGetClassObject
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


CoGetCurrentProcess
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


CoGetMalloc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


CoGetMarshalSizeMax
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


CoGetStandardMarshal
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


CoGetState
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


CoGetTreatAsClass
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


CoInitialize
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


CoIsHandlerConnected
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


CoIsOle1Class
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


CoLoadLibrary
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


CoLockObjectExternal
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


ColorMatchToTarget
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


CoMarshalHresult
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


CoMarshalInterface
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


CombineRgn
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


CombineTransform
Windows NT
Yes
Win95
No
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


CommandLineToArgvW
Windows NT
New
Win95
No
Win32s
New
Import Library
shell32.lib
Header File
shellapi.h
Unicode
No
Platform Notes
None


CommConfigDialog
Windows NT
New
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


CommDlgExtendedError
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
comdlg32.lib
Header File
commdlg.h
Unicode
No
Platform Notes
None


CompareFileTime
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


CompareString
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winnls.h
Unicode
WinNT
Platform Notes
None


ConfigurePort
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
WinNT
Platform Notes
None


connect
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


ConnectNamedPipe
Windows NT
Yes
Win95
No
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


ConnectToPrinterDlg
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
No
Platform Notes
None


ContinueDebugEvent
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


ControlService
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winsvc.h
Unicode
No
Platform Notes
None


ConvertDefaultLocale
Windows NT
New
Win95
New
Win32s
New
Import Library
kernel32.lib
Header File
winnls.h
Unicode
No
Platform Notes
None


CopyAcceleratorTable
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


CopyCursor
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CopyEnhMetaFile
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
WinNT
Platform Notes
None


CopyFile
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


CopyIcon
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


CopyImage
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


CopyLZFile
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
lz32.lib
Header File
lzexpand.h
Unicode
No
Platform Notes
None


CopyMemory
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winbase.h
Unicode
No
Platform Notes
None


CopyMetaFile
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
WinNT
Platform Notes
Windows 95: int == 16 bits


CopyRect
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


CopySid
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


CoRegisterClassObject
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


CoRegisterMessageFilter
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


CoReleaseMarshalData
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


CoRevokeClassObject
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


CoTaskMemAlloc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


CoTaskMemFree
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


CoTaskMemRealloc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


CoTreatAsClass
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


CoUninitialize
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


CoUnmarshalHresult
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


CoUnmarshalInterface
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


CountClipboardFormats
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


CreateAcceleratorTable
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


CreateAntiMoniker
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


CreateBindCtx
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


CreateBitmap
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


CreateBitmapIndirect
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


CreateBrushIndirect
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


CreateCaret
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


CreateColorSpace
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
WinNT
Platform Notes
None


CreateCompatibleBitmap
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


CreateCompatibleDC
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


CreateConsoleScreenBuffer
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
wincon.h
Unicode
No
Platform Notes
None


CreateCursor
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


CreateDataAdviseHolder
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


CreateDataCache
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


CreateDC
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
WinNT
Platform Notes
Windows 95: int == 16 bits


CreateDesktop
Windows NT
Yes
Win95
No
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


CreateDialog
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CreateDialogIndirect
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CreateDialogIndirectParam
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


CreateDialogParam
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


CreateDIBitmap
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


CreateDIBPatternBrush
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


CreateDIBPatternBrushPt
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


CreateDIBSection
Windows NT
New
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


CreateDirectory
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


CreateDirectoryEx
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


CreateDiscardableBitmap
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


CreateDispTypeInfo
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


CreateEditableStream
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


CreateEllipticRgn
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


CreateEllipticRgnIndirect
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


CreateEnhMetaFile
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
WinNT
Platform Notes
None


CreateErrorInfo
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


CreateEvent
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


CreateFile
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


CreateFileMapping
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


CreateFileMoniker
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


CreateFont
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
WinNT
Platform Notes
Windows 95: int == 16 bits


CreateFontIndirect
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
WinNT
Platform Notes
Windows 95: int == 16 bits


CreateGenericComposite
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


CreateHalftonePalette
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


CreateHatchBrush
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


CreateIC
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
WinNT
Platform Notes
Windows 95: int == 16 bits


CreateIcon
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


CreateIconFromResource
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


CreateIconFromResourceEx
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


CreateIconIndirect
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


CreateILockBytesOnHGlobal
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


CreateIoCompletionPort
Windows NT
New
Win95
No
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


CreateItemMoniker
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


CreateMailslot
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


CreateMappedBitmap
Windows NT
Yes
Win95
Yes
Win32s
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


CreateMDIWindow
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


CreateMenu
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


CreateMetaFile
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
WinNT
Platform Notes
Windows 95: int == 16 bits


CreateMutex
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


CreateNamedPipe
Windows NT
Yes
Win95
No
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


CreateOleAdviseHolder
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


CreatePalette
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


CreatePatternBrush
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


CreatePen
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


CreatePenIndirect
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


CreatePipe
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


CreatePointerMoniker
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


CreatePolygonRgn
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


CreatePolyPolygonRgn
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


CreatePopupMenu
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


CreatePrivateObjectSecurity
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


CreateProcess
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


CreateProcessAsUser
Windows NT
New
Win95
No
Win32s
No
Import Library
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


CreatePropertySheetPage
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
prsht.h
Unicode
WinNT
Platform Notes
None


CreateRectRgn
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


CreateRectRgnIndirect
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


CreateRemoteThread
Windows NT
Yes
Win95
No
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


CreateRoundRectRgn
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


CreateScalableFontResource
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
WinNT
Platform Notes
Windows 95: int == 16 bits


CreateSemaphore
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


CreateService
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winsvc.h
Unicode
WinNT
Platform Notes
None


CreateSolidBrush
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


CreateStatusWindow
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
commctrl.h
Unicode
WinNT
Platform Notes
None


CreateStdDispatch
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


CreateStreamOnHGlobal
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


CreateTapePartition
Windows NT
Yes
Win95
No
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


CreateThread
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


CreateToolbarEx
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


CreateTypeLib
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


CreateUpDownControl
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


CreateWindow
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CreateWindowEx
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
hMenu limited to WORD on Win32s


CreateWindowStation
Windows NT
Yes
Win95
No
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


data_from_ndr
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcndr.h
Unicode
Platform Notes
None


data_into_ndr
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcndr.h
Unicode
Platform Notes
None


data_size_ndr
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcndr.h
Unicode
Platform Notes
None


DceErrorInqText
Windows NT
New
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
WinNT
Platform Notes
None


DdeAbandonTransaction
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
ddeml.h
Unicode
No
Platform Notes
None


DdeAccessData
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
ddeml.h
Unicode
No
Platform Notes
None


DdeAddData
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
ddeml.h
Unicode
No
Platform Notes
None


DdeClientTransaction
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
ddeml.h
Unicode
No
Platform Notes
None


DdeCmpStringHandles
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
ddeml.h
Unicode
No
Platform Notes
None


DdeConnect
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
ddeml.h
Unicode
No
Platform Notes
None


DdeConnectList
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
ddeml.h
Unicode
No
Platform Notes
None


DdeCreateDataHandle
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
ddeml.h
Unicode
No
Platform Notes
None


DdeCreateStringHandle
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
ddeml.h
Unicode
WinNT
Platform Notes
None


DdeDisconnect
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
ddeml.h
Unicode
No
Platform Notes
None


DdeDisconnectList
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
ddeml.h
Unicode
No
Platform Notes
None


DdeEnableCallback
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
ddeml.h
Unicode
No
Platform Notes
None


DdeFreeDataHandle
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
ddeml.h
Unicode
No
Platform Notes
None


DdeFreeStringHandle
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
ddeml.h
Unicode
No
Platform Notes
None


DdeGetData
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
ddeml.h
Unicode
No
Platform Notes
None


DdeGetLastError
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
ddeml.h
Unicode
No
Platform Notes
None


DdeImpersonateClient
Windows NT
Yes
Win95
No
Win32s
No
Import Library
user32.lib
Header File
ddeml.h
Unicode
No
Platform Notes
None


DdeInitialize
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
ddeml.h
Unicode
WinNT
Platform Notes
None


DdeKeepStringHandle
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
ddeml.h
Unicode
No
Platform Notes
None


DdeNameService
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
ddeml.h
Unicode
No
Platform Notes
None


DdePostAdvise
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
ddeml.h
Unicode
No
Platform Notes
None


DdeQueryConvInfo
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
ddeml.h
Unicode
No
Platform Notes
None


DdeQueryNextServer
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
ddeml.h
Unicode
No
Platform Notes
None


DdeQueryString
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
ddeml.h
Unicode
WinNT
Platform Notes
None


DdeReconnect
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
ddeml.h
Unicode
No
Platform Notes
None


DdeSetQualityOfService
Windows NT
Yes
Win95
No
Win32s
No
Import Library
user32.lib
Header File
dde.h
Unicode
No
Platform Notes
None


DdeSetUserHandle
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
ddeml.h
Unicode
No
Platform Notes
None


DdeUnaccessData
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
ddeml.h
Unicode
No
Platform Notes
None


DdeUninitialize
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
ddeml.h
Unicode
No
Platform Notes
None


DebugActiveProcess
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


DebugBreak
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


DefDlgProc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


DefDriverProc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


DeferWindowPos
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


DefFrameProc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


DefHookProc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


DefineDosDevice
Windows NT
Yes
Win95
No
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


DefineHandleTable
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winbase.h
Unicode
No
Platform Notes
None


DefMDIChildProc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


DefScreenSaverProc
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
scrnsave.lib
Header File
scrnsave.h
Unicode
No
Platform Notes
None


DefWindowProc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


DeleteAce
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


DeleteAtom
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


DeleteColorSpace
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


DeleteCriticalSection
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


DeleteDC
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


DeleteEnhMetaFile
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


DeleteFile
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


DeleteForm
Windows NT
Yes
Win95
No
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
WinNT
Platform Notes
None


DeleteMenu
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


DeleteMetaFile
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


DeleteMonitor
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
WinNT
Platform Notes
None


DeleteObject
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


DeletePort
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
WinNT
Platform Notes
None


DeletePrinter
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
No
Platform Notes
None


DeletePrinterDriver
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
WinNT
Platform Notes
None


DeletePrintProcessor
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
WinNT
Platform Notes
None


DeletePrintProvidor
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
WinNT
Platform Notes
None


DeleteService
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winsvc.h
Unicode
No
Platform Notes
None


DeregisterEventSource
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


DescribePixelFormat
Windows NT
Yes
Win95
No
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


DestroyAcceleratorTable
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


DestroyCaret
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


DestroyCursor
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


DestroyIcon
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


DestroyMenu
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


DestroyPrivateObjectSecurity
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


DestroyPropertySheetPage
Windows NT
Yes
Win95
Yes
Win32s
Import Library
Header File
prsht.h
Unicode
No
Platform Notes
None


DestroyWindow
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


DeviceCapabilitiesEx
Windows NT
No
Win95
No
Win32s
No
Import Library
gdi32.lib
Header File
Unicode
No
Platform Notes
None


DeviceIoControl
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


DialogBox
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


DialogBoxIndirect
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


DialogBoxIndirectParam
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


DialogBoxParam
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


DisableThreadLibraryCalls
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


DisconnectNamedPipe
Windows NT
Yes
Win95
No
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


DispatchMessage
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


DispGetIDsOfNames
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


DispGetParam
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


DispInvoke
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


DlgDirList
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


DlgDirListComboBox
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


DlgDirSelectComboBoxEx
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


DlgDirSelectEx
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


DllEntryPoint
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
Unicode
No
Platform Notes
None


DllGetClassObject
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
objbase.h
Unicode
Platform Notes
None


DocumentProperties
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
WinNT
Platform Notes
None


DoDragDrop
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


DosDateTimeToFileTime
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


DosDateTimeToVariantTime
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


double_array_from_ndr
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcndr.h
Unicode
Platform Notes
None


double_from_ndr
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcndr.h
Unicode
Platform Notes
None


DPtoLP
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


DragAcceptFiles
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
shell32.lib
Header File
shellapi.h
Unicode
No
Platform Notes
None


DragDetect
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


DragFinish
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
shell32.lib
Header File
shellapi.h
Unicode
No
Platform Notes
None


DragObject
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


DragQueryFile
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
shell32.lib
Header File
shellapi.h
Unicode
WinNT
Platform Notes
None


DragQueryPoint
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
shell32.lib
Header File
shellapi.h
Unicode
No
Platform Notes
None


DrawAnimatedRects
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


DrawCaption
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


DrawDibBegin
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


DrawDibChangePalette
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


DrawDibClose
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


DrawDibDraw
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


DrawDibEnd
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


DrawDibGetBuffer
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


DrawDibGetPalette
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


DrawDibOpen
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


DrawDibProfileDisplay
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


DrawDibRealize
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


DrawDibSetPalette
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


DrawDibStart
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


DrawDibStop
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


DrawDibTime
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


DrawEdge
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


DrawEscape
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


DrawFocusRect
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


DrawFrameControl
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


DrawIcon
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


DrawIconEx
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


DrawInsert
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


DrawMenuBar
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


DrawState
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


DrawStatusText
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
commctrl.h
Unicode
WinNT
Platform Notes
None


DrawText
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


DrawTextEx
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


DriverCallback
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
digitalv.h
Unicode
No
Platform Notes
None


DrvGetModuleHandle
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


DrvSendMessage
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


DuplicateHandle
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


DuplicateIcon
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
shell32.lib
Header File
shellapi.h
Unicode
No
Platform Notes
None


DuplicateToken
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


EditStreamClone
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


EditStreamCopy
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


EditStreamCut
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


EditStreamPaste
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


EditStreamSetInfo
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
WinNT
Platform Notes
None


EditStreamSetName
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
WinNT
Platform Notes
None


Ellipse
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


EmptyClipboard
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


EnableMenuItem
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


EnableScrollBar
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


EnableWindow
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


EndDeferWindowPos
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


EndDialog
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


EndDoc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


EndDocPrinter
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
No
Platform Notes
None


EndPage
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


EndPagePrinter
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
No
Platform Notes
None


EndPaint
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


EndPath
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


EndUpdateResource
Windows NT
Yes
Win95
No
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


EnterCriticalSection
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


enum_from_ndr
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcndr.h
Unicode
Platform Notes
None


EnumCalendarInfo
Windows NT
New
Win95
New
Win32s
New
Import Library
kernel32.lib
Header File
winnls.h
Unicode
WinNT
Platform Notes
None


EnumChildWindows
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


EnumClipboardFormats
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


EnumDateFormats
Windows NT
New
Win95
New
Win32s
New
Import Library
kernel32.lib
Header File
winnls.h
Unicode
WinNT
Platform Notes
None


EnumDependentServices
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winsvc.h
Unicode
WinNT
Platform Notes
None


EnumDesktops
Windows NT
Yes
Win95
No
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


EnumDesktopWindows
Windows NT
Yes
Win95
No
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


EnumDisplaySettings
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


EnumEnhMetaFile
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


EnumFontFamilies
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
WinNT
Platform Notes
Windows 95: int == 16 bits


EnumFontFamiliesEx
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
Unicode
Platform Notes
None


EnumFonts
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
WinNT
Platform Notes
Windows 95: int == 16 bits


EnumForms
Windows NT
Yes
Win95
No
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
WinNT
Platform Notes
None


EnumICMProfiles
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
WinNT
Platform Notes
None


EnumJobs
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
WinNT
Platform Notes
None


EnumMetaFile
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


EnumMonitors
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
WinNT
Platform Notes
None


EnumObjects
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


EnumPorts
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
WinNT
Platform Notes
None


EnumPrinterDrivers
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
WinNT
Platform Notes
None


EnumPrinters
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
WinNT
Platform Notes
None


EnumPrintProcessorDatatypes
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
WinNT
Platform Notes
None


EnumPrintProcessors
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
WinNT
Platform Notes
None


EnumProps
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


EnumPropsEx
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


EnumProtocols
Windows NT
Yes
Win95
No
Win32s
No
Import Library
wsock32.lib
Header File
nspapi.h
Unicode
WinNT
Platform Notes
None


EnumResourceLanguages
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT; Win95
Platform Notes
None


EnumResourceNames
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT; Win95
Platform Notes
None


EnumResourceTypes
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT; Win95
Platform Notes
None


EnumServicesStatus
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winsvc.h
Unicode
WinNT
Platform Notes
None


EnumSystemCodePages
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winnls.h
Unicode
WinNT
Platform Notes
None


EnumSystemLocales
Windows NT
New
Win95
New
Win32s
New
Import Library
kernel32.lib
Header File
winnls.h
Unicode
WinNT
Platform Notes
None


EnumTaskWindows
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


EnumThreadWindows
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


EnumTimeFormats
Windows NT
New
Win95
New
Win32s
New
Import Library
kernel32.lib
Header File
winnls.h
Unicode
WinNT
Platform Notes
None


EnumWindows
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


EnumWindowStations
Windows NT
Yes
Win95
No
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


EqualPrefixSid
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


EqualRect
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


EqualRgn
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


EqualSid
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


EraseTape
Windows NT
Yes
Win95
No
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


Escape
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


EscapeCommFunction
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


ExcludeClipRect
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


ExcludeUpdateRgn
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


ExitProcess
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


ExitThread
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


ExitWindows
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


ExitWindowsEx
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


ExpandEnvironmentStrings
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


ExtCreatePen
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
New
Platform Notes
Windows 95: Only supports solid colors (e.g.


ExtCreateRegion
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: Fails if the transform involves a shearing or rotation; int == 16 bits


ExtEscape
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


ExtFloodFill
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


ExtractAssociatedIcon
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
shell32.lib
Header File
shellapi.h
Unicode
WinNT
Platform Notes
None


ExtractIcon
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
shell32.lib
Header File
shellapi.h
Unicode
WinNT
Platform Notes
None


ExtractIconEx
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
Header File
shellapi.h
Unicode
Platform Notes
None


ExtSelectClipRgn
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


ExtTextOut
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
WinNT; Win95
Platform Notes
Windows 95: 16-bit coordinates only


FatalAppExit
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


FatalExit
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


FileTimeToDosDateTime
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


FileTimeToLocalFileTime
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
Win32s always uses LocalTime never UTC


FileTimeToSystemTime
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


FillConsoleOutputAttribute
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
wincon.h
Unicode
No
Platform Notes
None


FillConsoleOutputCharacter
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
wincon.h
Unicode
WinNT
Platform Notes
None


FillMemory
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winbase.h
Unicode
No
Platform Notes
None


FillPath
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


FillRect
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


FillRgn
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


FindAtom
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


FindClose
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


FindCloseChangeNotification
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


FindClosePrinterChangeNotification
Windows NT
New
Win95
No
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
No
Platform Notes
None


FindExecutable
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
shell32.lib
Header File
shellapi.h
Unicode
WinNT
Platform Notes
None


FindFirstChangeNotification
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


FindFirstFile
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
Win32s returns times in LocalTime


FindFirstFreeAce
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


FindFirstPrinterChangeNotification
Windows NT
New
Win95
No
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
No
Platform Notes
None


FindNextChangeNotification
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


FindNextFile
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
Win32s returns times in LocalTime


FindNextPrinterChangeNotification
Windows NT
New
Win95
No
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
No
Platform Notes
None


FindResource
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT; Win95
Platform Notes
None


FindResourceEx
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT; Win95
Platform Notes
None


FindText
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
comdlg32.lib
Header File
commdlg.h
Unicode
WinNT
Platform Notes
None


FindWindow
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


FindWindowEx
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


FixBrushOrgEx
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


FlashWindow
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


FlattenPath
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


float_array_from_ndr
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcndr.h
Unicode
Platform Notes
None


float_from_ndr
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcndr.h
Unicode
Platform Notes
None


FloodFill
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


FlushConsoleInputBuffer
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
wincon.h
Unicode
No
Platform Notes
None


FlushFileBuffers
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


FlushInstructionCache
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
This is valid on SMP platforms only; Windows 95 returns a constant


FlushViewOfFile
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


FoldString
Windows NT
Yes
Win95
No
Win32s
Yes
Import Library
kernel32.lib
Header File
winnls.h
Unicode
WinNT
Platform Notes
None


FormatMessage
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


FrameRect
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


FrameRgn
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


FreeConsole
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
wincon.h
Unicode
No
Platform Notes
None


FreeDDElParam
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
dde.h
Unicode
No
Platform Notes
None


FreeEnvironmentStrings
Windows NT
New
Win95
New
Win32s
New
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


FreeImageColorMatcher
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


FreeLibrary
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


FreeLibraryAndExitThread
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


FreeModule
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winbase.h
Unicode
No
Platform Notes
None


FreeProcInstance
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winbase.h
Unicode
No
Platform Notes
None


FreeResource
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


FreeSid
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GdiComment
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


GdiFlush
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


GdiGetBatchLimit
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


GdiSetBatchLimit
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


GenerateConsoleCtrlEvent
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
wincon.h
Unicode
No
Platform Notes
None


GetAce
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetAclInformation
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetACP
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winnls.h
Unicode
No
Platform Notes
None


GetActiveObject
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


GetActiveWindow
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetAddressByName
Windows NT
Yes
Win95
No
Win32s
No
Import Library
wsock32.lib
Header File
nspapi.h
Unicode
WinNT
Platform Notes
None


GetArcDirection
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


GetAspectRatioFilterEx
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


GetAsyncKeyState
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetAtomName
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


GetBinaryType
Windows NT
New
Win95
No
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


GetBitmapBits
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


GetBitmapDimensionEx
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


GetBkColor
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


GetBkMode
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


GetBoundsRect
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


GetBrushOrgEx
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


GetCapture
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetCaretBlinkTime
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetCaretPos
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetCharABCWidths
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
WinNT
Platform Notes
Windows 95: int == 16 bits


GetCharABCWidthsFloat
Windows NT
Yes
Win95
No
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
WinNT
Platform Notes
None


GetCharacterPlacement
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
WinNT
Platform Notes
None


GetCharWidth
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
WinNT; Win95
Platform Notes
Windows 95: int == 16 bits


GetCharWidth32
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
WinNT
Platform Notes
Windows 95: int == 16 bits


GetCharWidthFloat
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
WinNT
Platform Notes
Windows 95: int == 16 bits


GetClassFile
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


GetClassInfo
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


GetClassInfoEx
Windows NT
Stub
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


GetClassLong
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


GetClassName
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


GetClassWord
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetClientRect
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetClipboardData
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetClipboardFormatName
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


GetClipboardOwner
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetClipboardViewer
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetClipBox
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


GetClipCursor
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetClipRgn
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


GetColorAdjustment
Windows NT
Yes
Win95
No
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


GetColorSpace
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


GetCommandLine
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT; Win95
Platform Notes
None


GetCommConfig
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetCommMask
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetCommModemStatus
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetCommProperties
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetCommState
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetCommTimeouts
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetCompressedFileSize
Windows NT
New
Win95
No
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


GetComputerName
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


GetConsoleCP
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
wincon.h
Unicode
No
Platform Notes
Windows 95 limitations


GetConsoleCursorInfo
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
wincon.h
Unicode
No
Platform Notes
None


GetConsoleMode
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
wincon.h
Unicode
No
Platform Notes
None


GetConsoleOutputCP
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
wincon.h
Unicode
No
Platform Notes
Windows 95 limitations


GetConsoleScreenBufferInfo
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
wincon.h
Unicode
No
Platform Notes
None


GetConsoleTitle
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
wincon.h
Unicode
WinNT
Platform Notes
None


GetConvertStg
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


GetCPInfo
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winnls.h
Unicode
No
Platform Notes
None


GetCurrencyFormat
Windows NT
New
Win95
New
Win32s
New
Import Library
kernel32.lib
Header File
winnls.h
Unicode
WinNT
Platform Notes
None


GetCurrentDirectory
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


GetCurrentObject
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


GetCurrentPositionEx
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


GetCurrentProcess
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetCurrentProcessId
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetCurrentThread
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetCurrentThreadId
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetCurrentTime
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winbase.h
Unicode
No
Platform Notes
None


GetCursor
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetCursorPos
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetDateFormat
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winnls.h
Unicode
WinNT
Platform Notes
None


GetDC
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetDCEx
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetDCOrgEx
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


GetDefaultCommConfig
Windows NT
No
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


GetDesktopWindow
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetDeviceCaps
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


GetDeviceGammaRamp
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


GetDialogBaseUnits
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetDIBColorTable
Windows NT
New
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


GetDIBits
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


GetDiskFreeSpace
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


GetDlgCtrlID
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetDlgItem
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetDlgItemInt
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetDlgItemText
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


GetDoubleClickTime
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetDriverModuleHandle
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


GetDriveType
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


GetEffectiveClientRect
Windows NT
Yes
Win95
Yes
Win32s
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


GetEnhMetaFile
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
WinNT
Platform Notes
None


GetEnhMetaFileBits
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


GetEnhMetaFileDescription
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
WinNT
Platform Notes
None


GetEnhMetaFileHeader
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


GetEnhMetaFilePaletteEntries
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


GetEnvironmentStrings
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetEnvironmentVariable
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


GetErrorInfo
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


GetExceptionCode
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
Unicode
Platform Notes
None


GetExceptionInformation
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
Unicode
Platform Notes
None


GetExitCodeProcess
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetExitCodeThread
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetExpandedName
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
lz32.lib
Header File
lzexpand.h
Unicode
WinNT
Platform Notes
None


GetFileAttributes
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


GetFileInformationByHandle
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetFileSecurity
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


GetFileSize
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetFileTime
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetFileTitle
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
comdlg32.lib
Header File
commdlg.h
Unicode
WinNT
Platform Notes
None


GetFileType
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetFileVersionInfo
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
version.lib
Header File
winver.h
Unicode
WinNT
Platform Notes
None


GetFileVersionInfoSize
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
version.lib
Header File
winver.h
Unicode
WinNT
Platform Notes
None


GetFocus
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetFontData
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


GetFontLanguageInfo
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


GetForegroundWindow
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetForm
Windows NT
Yes
Win95
No
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
WinNT
Platform Notes
None


GetFreeSpace
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winbase.h
Unicode
No
Platform Notes
None


GetFullPathName
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


GetGlyphOutline
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


GetGraphicsMode
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: Only GM_COMPATIBLE is supported


GetHandleInformation
Windows NT
Yes
Win95
No
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetHGlobalFromILockBytes
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


GetHGlobalFromStream
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


gethostbyaddr
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


gethostbyname
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


gethostname
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


GetICMProfile
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
WinNT
Platform Notes
None


GetIconInfo
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetInputState
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetJob
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
WinNT
Platform Notes
None


GetKBCodePage
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetKernelObjectSecurity
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetKerningPairs
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


GetKeyboardLayout
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetKeyboardLayoutList
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetKeyboardLayoutName
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


GetKeyboardState
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetKeyboardType
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetKeyNameText
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


GetKeyState
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetLargestConsoleWindowSize
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
wincon.h
Unicode
No
Platform Notes
None


GetLastActivePopup
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetLastError
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetLengthSid
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetLocaleInfo
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winnls.h
Unicode
WinNT
Platform Notes
None


GetLocalTime
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetLogColorSpace
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
WinNT
Platform Notes
None


GetLogicalDrives
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetLogicalDriveStrings
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


GetMailslotInfo
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetMapMode
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


GetMenu
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetMenuCheckMarkDimensions
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetMenuContextHelpId
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetMenuDefaultItem
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetMenuItemCount
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetMenuItemID
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetMenuItemInfo
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


GetMenuItemRect
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetMenuState
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetMenuString
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


GetMessage
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


GetMessageExtraInfo
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetMessagePos
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetMessageTime
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetMetaFile
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
WinNT
Platform Notes
Windows 95: int == 16 bits


GetMetaFileBitsEx
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


GetMetaRgn
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


GetMiterLimit
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


GetModuleFileName
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


GetModuleHandle
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


GetNameByType
Windows NT
Yes
Win95
No
Win32s
No
Import Library
wsock32.lib
Header File
nspapi.h
Unicode
WinNT
Platform Notes
None


GetNamedPipeHandleState
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


GetNamedPipeInfo
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetNearestColor
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


GetNearestPaletteIndex
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


GetNextDlgGroupItem
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetNextDlgTabItem
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetNextWindow
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


GetNumberFormat
Windows NT
New
Win95
New
Win32s
New
Import Library
kernel32.lib
Header File
winnls.h
Unicode
WinNT
Platform Notes
None


GetNumberOfConsoleInputEvents
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
wincon.h
Unicode
No
Platform Notes
None


GetNumberOfConsoleMouseButtons
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
wincon.h
Unicode
No
Platform Notes
None


GetNumberOfEventLogRecords
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetObject
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
WinNT
Platform Notes
Windows 95: int == 16 bits


GetObjectType
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


GetOEMCP
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winnls.h
Unicode
No
Platform Notes
None


GetOldestEventLogRecord
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetOpenClipboardWindow
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetOpenFileName
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
comdlg32.lib
Header File
commdlg.h
Unicode
WinNT
Platform Notes
None


GetOpenFileNamePreview
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
WinNT
Platform Notes
None


GetOutlineTextMetrics
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
WinNT
Platform Notes
Windows 95: int == 16 bits


GetOverlappedResult
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
Windows 95: Only on serial and IOCTL devices


GetPaletteEntries
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


GetParent
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetPath
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


getpeername
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


GetPixel
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


GetPixelFormat
Windows NT
Yes
Win95
No
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


GetPolyFillMode
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


GetPrinter
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
WinNT
Platform Notes
None


GetPrinterData
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
WinNT
Platform Notes
None


GetPrinterDriver
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
WinNT
Platform Notes
None


GetPrinterDriverDirectory
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
WinNT
Platform Notes
None


GetPrintProcessorDirectory
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
WinNT
Platform Notes
None


GetPriorityClass
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetPriorityClipboardFormat
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetPrivateObjectSecurity
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetPrivateProfileInt
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


GetPrivateProfileSection
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


GetPrivateProfileSectionNames
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


GetPrivateProfileString
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


GetPrivateProfileStruct
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


GetProcAddress
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetProcessAffinityMask
Windows NT
New
Win95
New
Win32s
New
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
This is valid on SMP platforms only; Windows 95 returns a constant


GetProcessHeap
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetProcessHeaps
Windows NT
New
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetProcessShutdownParameters
Windows NT
Yes
Win95
No
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetProcessTimes
Windows NT
Yes
Win95
No
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetProcessVersion
Windows NT
New
Win95
New
Win32s
No
Import Library
Header File
winbase.h
Unicode
No
Platform Notes
None


GetProcessWindowStation
Windows NT
Yes
Win95
No
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetProcessWorkingSetSize
Windows NT
New
Win95
No
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetProfileInt
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


GetProfileSection
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


GetProfileSectionNames
Windows NT
No
Win95
No
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


GetProfileString
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


GetProp
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


getprotobyname
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


getprotobynumber
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


GetQueuedCompletionStatus
Windows NT
New
Win95
No
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetQueueStatus
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetRasterizerCaps
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


GetRegionData
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


GetResourceID
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


GetRgnBox
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


GetROP2
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


GetRunningObjectTable
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


GetSaveFileName
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
comdlg32.lib
Header File
commdlg.h
Unicode
WinNT
Platform Notes
None


GetSaveFileNamePreview
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
WinNT
Platform Notes
None


GetScrollInfo
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetScrollPos
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetScrollRange
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetSecurityDescriptorControl
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetSecurityDescriptorDacl
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetSecurityDescriptorGroup
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetSecurityDescriptorLength
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetSecurityDescriptorOwner
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetSecurityDescriptorSacl
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


getservbyname
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


getservbyport
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


GetService
Windows NT
Yes
Win95
No
Win32s
No
Import Library
wsock32.lib
Header File
nspapi.h
Unicode
WinNT
Platform Notes
None


GetServiceDisplayName
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winsvc.h
Unicode
WinNT
Platform Notes
None


GetServiceKeyName
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winsvc.h
Unicode
WinNT
Platform Notes
None


GetShortPathName
Windows NT
New
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


GetSidIdentifierAuthority
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetSidLengthRequired
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetSidSubAuthority
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetSidSubAuthorityCount
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


getsockname
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


getsockopt
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


GetStartupInfo
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


GetStdHandle
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetStockObject
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


GetStretchBltMode
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


GetStringTypeA
Windows NT
New
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winnls.h
Unicode
Unicode
Platform Notes
None


GetStringTypeEx
Windows NT
New
Win95
New
Win32s
New
Import Library
kernel32.lib
Header File
winnls.h
Unicode
No
Platform Notes
None


GetStringTypeW
Windows NT
Yes
Win95
No
Win32s
No
Import Library
kernel32.lib
Header File
winnls.h
Unicode
Unicode
Platform Notes
None


GetSubMenu
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetSysColor
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetSysColorBrush
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetSysModalWindow
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


GetSystemDefaultLangID
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winnls.h
Unicode
No
Platform Notes
None


GetSystemDefaultLCID
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winnls.h
Unicode
No
Platform Notes
None


GetSystemDirectory
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


GetSystemInfo
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetSystemMenu
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetSystemMetrics
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetSystemPaletteEntries
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


GetSystemPaletteUse
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


GetSystemPowerStatus
Windows NT
No
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetSystemTime
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetSystemTimeAdjustment
Windows NT
New
Win95
No
Win32s
New
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetSystemTimeAsFileTime
Windows NT
New
Win95
Yes
Win32s
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetTabbedTextExtent
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


GetTapeParameters
Windows NT
Yes
Win95
No
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetTapePosition
Windows NT
Yes
Win95
No
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetTapeStatus
Windows NT
Yes
Win95
No
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetTempFileName
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


GetTempPath
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


GetTextAlign
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


GetTextCharacterExtra
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


GetTextCharset
Windows NT
No
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


GetTextCharsetInfo
Windows NT
No
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


GetTextColor
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


GetTextExtentExPoint
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
WinNT; Win95
Platform Notes
Windows 95: int == 16 bits


GetTextExtentPoint
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
WinNT; Win95
Platform Notes
Windows 95: int == 16 bits


GetTextExtentPoint32
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
WinNT; Win95
Platform Notes
Windows 95: int == 16 bits


GetTextFace
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
WinNT
Platform Notes
Windows 95: int == 16 bits


GetTextMetrics
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
WinNT
Platform Notes
Windows 95: int == 16 bits


GetThreadContext
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetThreadDesktop
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
Windows 95: NOP; only one desktop


GetThreadLocale
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winnls.h
Unicode
No
Platform Notes
Windows 95: Locales are static & can change only at system boot


GetThreadPriority
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetThreadSelectorEntry
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetThreadTimes
Windows NT
Yes
Win95
No
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetTickCount
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetTimeFormat
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winnls.h
Unicode
WinNT
Platform Notes
None


GetTimeZoneInformation
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetTokenInformation
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetTopWindow
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetTypeByName
Windows NT
Yes
Win95
No
Win32s
No
Import Library
wsock32.lib
Header File
nspapi.h
Unicode
WinNT
Platform Notes
None


GetUpdateRect
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetUpdateRgn
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetUserDefaultLangID
Windows NT
Yes
Win95
Yes
Win32s
New
Import Library
kernel32.lib
Header File
winnls.h
Unicode
No
Platform Notes
None


GetUserDefaultLCID
Windows NT
Yes
Win95
Yes
Win32s
New
Import Library
kernel32.lib
Header File
winnls.h
Unicode
No
Platform Notes
None


GetUserName
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


GetUserObjectInformation
Windows NT
Yes
Win95
No
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


GetUserObjectSecurity
Windows NT
Yes
Win95
No
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetVersion
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetVersionEx
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GetViewportExtEx
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


GetViewportOrgEx
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


GetVolumeInformation
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


GetWindow
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetWindowContextHelpId
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetWindowDC
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetWindowExtEx
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


GetWindowLong
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


GetWindowOrgEx
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


GetWindowPlacement
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetWindowRect
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetWindowRgn
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetWindowsDirectory
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


GetWindowTask
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


GetWindowText
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


GetWindowTextLength
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


GetWindowThreadProcessId
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetWindowWord
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


GetWinMetaFileBits
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


GetWorldTransform
Windows NT
Yes
Win95
No
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


glAccum
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glAddSwapHintRectWIN
Windows NT
New
Win95
No
Win32s
No
Import Library
Header File
gl.h
Unicode
Platform Notes
None


glAlphaFunc
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glArrayElementEXT
Windows NT
New
Win95
No
Win32s
No
Import Library
Header File
gl.h
Unicode
Platform Notes
None


glBegin
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glBitmap
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glBlendFunc
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glCallList
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glCallLists
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glClear
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glClearAccum
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glClearColor
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glClearDepth
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glClearIndex
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glClearStencil
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glClipPlane
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glColor3b
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glColor3bv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glColor3d
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glColor3dv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glColor3f
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glColor3fv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glColor3i
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glColor3iv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glColor3s
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glColor3sv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glColor3ub
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glColor3ubv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glColor3ui
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glColor3uiv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glColor3us
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glColor3usv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glColor4b
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glColor4bv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glColor4d
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glColor4dv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glColor4f
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glColor4fv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glColor4i
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glColor4iv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glColor4s
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glColor4sv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glColor4ub
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glColor4ubv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glColor4ui
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glColor4uiv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glColor4us
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glColor4usv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glColorMask
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glColorMaterial
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glColorPointerEXT
Windows NT
New
Win95
No
Win32s
No
Import Library
Header File
gl.h
Unicode
Platform Notes
None


glCopyPixels
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glCullFace
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glDeleteLists
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glDepthFunc
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glDepthMask
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glDepthRange
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glDisable
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glDrawArraysEXT
Windows NT
New
Win95
No
Win32s
No
Import Library
Header File
gl.h
Unicode
Platform Notes
None


glDrawBuffer
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glDrawPixels
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glEdgeFlag
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glEdgeFlagPointerEXT
Windows NT
New
Win95
No
Win32s
No
Import Library
Header File
gl.h
Unicode
Platform Notes
None


glEdgeFlagv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glEnable
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glEnd
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glEndList
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glEvalCoord1d
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glEvalCoord1dv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glEvalCoord1f
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glEvalCoord1fv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glEvalCoord2d
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glEvalCoord2dv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glEvalCoord2f
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glEvalCoord2fv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glEvalMesh1
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glEvalMesh2
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glEvalPoint1
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glEvalPoint2
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glFeedbackBuffer
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glFinish
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glFlush
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glFogf
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glFogfv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glFogi
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glFogiv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glFrontFace
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glFrustum
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glGenLists
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glGetBooleanv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glGetClipPlane
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glGetDoublev
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glGetError
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glGetFloatv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glGetIntegerv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glGetLightfv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glGetLightiv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glGetMapdv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glGetMapfv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glGetMapiv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glGetMaterialfv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glGetMaterialiv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glGetPixelMapfv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glGetPixelMapuiv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glGetPixelMapusv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glGetPointervEXT
Windows NT
New
Win95
No
Win32s
No
Import Library
Header File
gl.h
Unicode
Platform Notes
None


glGetPolygonStipple
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glGetString
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glGetTexEnvfv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glGetTexEnviv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glGetTexGendv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glGetTexGenfv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glGetTexGeniv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glGetTexImage
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glGetTexLevelParameterfv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glGetTexLevelParameteriv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glGetTexParameterfv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glGetTexParameteriv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glHint
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glIndexd
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glIndexdv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glIndexf
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glIndexfv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glIndexi
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glIndexiv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glIndexMask
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glIndexPointEXT
Windows NT
New
Win95
No
Win32s
No
Import Library
Header File
gl.h
Unicode
Platform Notes
None


glIndexs
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glIndexsv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glInitNames
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glIsEnabled
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glIsList
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glLightf
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glLightfv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glLighti
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glLightiv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glLightModelf
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glLightModelfv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glLightModeli
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glLightModeliv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glLineStipple
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glLineWidth
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glListBase
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glLoadIdentity
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glLoadMatrixd
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glLoadMatrixf
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glLoadName
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glLogicOp
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glMap1d
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glMap1f
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glMap2d
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glMap2f
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glMapGrid1d
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glMapGrid1f
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glMapGrid2d
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glMapGrid2f
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glMaterialf
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glMaterialfv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glMateriali
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glMaterialiv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glMatrixMode
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glMultMatrixd
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glMultMatrixf
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glNewList
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glNormal3b
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glNormal3bv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glNormal3d
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glNormal3dv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glNormal3f
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glNormal3fv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glNormal3i
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glNormal3iv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glNormal3s
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glNormal3sv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glNormalPointerEXT
Windows NT
New
Win95
No
Win32s
No
Import Library
Header File
gl.h
Unicode
Platform Notes
None


GlobalAddAtom
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


GlobalAlloc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
GMEM_FIXED is expensive (locks pages) on Win32s - use GMEM_MOVEABLE


GlobalCompact
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GlobalDeleteAtom
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GlobalDiscard
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winbase.h
Unicode
No
Platform Notes
None


GlobalFindAtom
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


GlobalFlags
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GlobalFree
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GlobalGetAtomName
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


GlobalHandle
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GlobalLock
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GlobalLRUNewest
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winbase.h
Unicode
No
Platform Notes
None


GlobalLRUOldest
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winbase.h
Unicode
No
Platform Notes
None


GlobalMemoryStatus
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GlobalReAlloc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GlobalSize
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


GlobalUnlock
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


glOrtho
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glPassThrough
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glPixelMapfv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glPixelMapuiv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glPixelMapusv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glPixelStoref
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glPixelStorei
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glPixelTransferf
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glPixelTransferi
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glPixelZoom
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glPointSize
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glPolygonMode
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glPolygonStipple
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glPopAttrib
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glPopMatrix
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glPopName
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glPushAttrib
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glPushMatrix
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glPushName
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glRasterPos2d
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glRasterPos2dv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glRasterPos2f
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glRasterPos2fv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glRasterPos2i
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glRasterPos2iv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glRasterPos2s
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glRasterPos2sv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glRasterPos3d
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glRasterPos3dv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glRasterPos3f
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glRasterPos3fv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glRasterPos3i
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glRasterPos3iv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glRasterPos3s
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glRasterPos3sv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glRasterPos4d
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glRasterPos4dv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glRasterPos4f
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glRasterPos4fv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glRasterPos4i
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glRasterPos4iv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glRasterPos4s
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glRasterPos4sv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glReadBuffer
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glReadPixels
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glRectd
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glRectdv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glRectf
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glRectfv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glRecti
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glRectiv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glRects
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glRectsv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glRenderMode
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glRotated
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glRotatef
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glScaled
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glScalef
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glScissor
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glSelectBuffer
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glShadeModel
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glStencilFunc
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glStencilMask
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glStencilOp
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTexCoord1d
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTexCoord1dv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTexCoord1f
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTexCoord1fv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTexCoord1i
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTexCoord1iv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTexCoord1s
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTexCoord1sv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTexCoord2d
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTexCoord2dv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTexCoord2f
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTexCoord2fv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTexCoord2i
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTexCoord2iv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTexCoord2s
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTexCoord2sv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTexCoord3d
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTexCoord3dv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTexCoord3f
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTexCoord3fv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTexCoord3i
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTexCoord3iv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTexCoord3s
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTexCoord3sv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTexCoord4d
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTexCoord4dv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTexCoord4f
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTexCoord4fv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTexCoord4i
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTexCoord4iv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTexCoord4s
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTexCoord4sv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTexCoordPointerEXT
Windows NT
New
Win95
No
Win32s
No
Import Library
Header File
gl.h
Unicode
Platform Notes
None


glTexEnvf
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTexEnvfv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTexEnvi
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTexEnviv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTexGend
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTexGendv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTexGenf
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTexGenfv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTexGeni
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTexGeniv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTexImage1D
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTexImage2D
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTexParameterf
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTexParameterfv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTexParameteri
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTexParameteriv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTranslated
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glTranslatef
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


gluBeginCurve
Windows NT
Yes
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluBeginPolygon
Windows NT
Yes
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluBeginSurface
Windows NT
Yes
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluBeginTrim
Windows NT
Yes
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluBuild1DMipmaps
Windows NT
Yes
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluBuild2DMipmaps
Windows NT
Yes
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluCylinder
Windows NT
Yes
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluDeleteNurbsRenderer
Windows NT
Yes
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluDeleteQuadric
Windows NT
Yes
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluDeleteTess
Windows NT
Yes
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluDisk
Windows NT
Yes
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluEndCurve
Windows NT
Yes
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluEndPolygon
Windows NT
Yes
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluEndSurface
Windows NT
Yes
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluEndTrim
Windows NT
Yes
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluErrorString
Windows NT
Yes
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluErrorUnicodeStringEXT
Windows NT
Yes
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
WinNT
Platform Notes
None


gluGetNurbsProperty
Windows NT
Yes
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluGetString
Windows NT
New
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluGetTessProperty
Windows NT
New
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluLoadSamplingMatrices
Windows NT
Yes
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluLookAt
Windows NT
Yes
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluNewNurbsRenderer
Windows NT
Yes
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluNewQuadric
Windows NT
Yes
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluNewTess
Windows NT
Yes
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluNextContour
Windows NT
Yes
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluNurbsCallback
Windows NT
Yes
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluNurbsCurve
Windows NT
Yes
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluNurbsProperty
Windows NT
Yes
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluNurbsSurface
Windows NT
Yes
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluOrtho2D
Windows NT
Yes
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluPartialDisk
Windows NT
Yes
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluPerspective
Windows NT
Yes
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluPickMatrix
Windows NT
Yes
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluProject
Windows NT
Yes
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluPwlCurve
Windows NT
Yes
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluQuadricCallback
Windows NT
Yes
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluQuadricDrawStyle
Windows NT
Yes
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluQuadricNormals
Windows NT
Yes
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluQuadricOrientation
Windows NT
Yes
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluQuadricTexture
Windows NT
Yes
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluScaleImage
Windows NT
Yes
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluSphere
Windows NT
Yes
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluTessBeginContour
Windows NT
New
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluTessBeginPolygon
Windows NT
New
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluTessCallback
Windows NT
Yes
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluTessEndContour
Windows NT
New
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluTessEndPolygon
Windows NT
New
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluTessNormal
Windows NT
New
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluTessProperty
Windows NT
New
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluTessVertex
Windows NT
Yes
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


gluUnProject
Windows NT
Yes
Win95
No
Win32s
No
Import Library
glu32.lib
Header File
glu.h
Unicode
No
Platform Notes
None


glVertex2d
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glVertex2dv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glVertex2f
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glVertex2fv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glVertex2i
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glVertex2iv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glVertex2s
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glVertex2sv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glVertex3d
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glVertex3dv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glVertex3f
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glVertex3fv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glVertex3i
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glVertex3iv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glVertex3s
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glVertex3sv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glVertex4d
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glVertex4dv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glVertex4f
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glVertex4fv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glVertex4i
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glVertex4iv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glVertex4s
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glVertex4sv
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


glVertexPointerEXT
Windows NT
New
Win95
No
Win32s
No
Import Library
Header File
gl.h
Unicode
Platform Notes
None


glViewport
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
gl.h
Unicode
No
Platform Notes
None


GrayString
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


Handler
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
Unicode
No
Platform Notes
None


HandlerRoutine
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
Unicode
No
Platform Notes
None


HeapAlloc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


HeapCompact
Windows NT
New
Win95
No
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


HeapCreate
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


HeapDestroy
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


HeapFree
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


HeapLock
Windows NT
New
Win95
No
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


HeapReAlloc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


HeapSize
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


HeapUnlock
Windows NT
New
Win95
No
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


HeapValidate
Windows NT
New
Win95
No
Win32s
in debug version only
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


HeapWalk
Windows NT
New
Win95
No
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


HideCaret
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


HiliteMenuItem
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


htonl
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


htons
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


I_BrowserDebugTrace
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmbrowsr.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


I_BrowserQueryOtherDomains
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmbrowsr.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


I_BrowserQueryStatistics
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmbrowsr.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


I_BrowserResetNetlogonState
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmbrowsr.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


I_BrowserResetStatistics
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmbrowsr.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


I_BrowserServerEnum
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmbrowsr.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


I_NetLogonControl
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmaccess.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


I_NetLogonControl2
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmaccess.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


I_RpcAllocate
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdcep.h
Unicode
Platform Notes
None


I_RpcBindingCopy
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdcep.h
Unicode
Platform Notes
None


I_RpcBindingInqDynamicEndpoint
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdcep.h
Unicode
Platform Notes
None


I_RpcBindingInqTransportType
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdcep.h
Unicode
No
Platform Notes
None


I_RpcBindingIsClientLocal
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdcep.h
Unicode
Platform Notes
None


I_RpcClearMutex
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdcep.h
Unicode
Platform Notes
None


I_RpcDeleteMutex
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdcep.h
Unicode
Platform Notes
None


I_RpcFree
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdcep.h
Unicode
Platform Notes
None


I_RpcFreeBuffer
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdcep.h
Unicode
Platform Notes
None


I_RpcGetAssociationContext
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdcep.h
Unicode
Platform Notes
None


I_RpcGetBuffer
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdcep.h
Unicode
Platform Notes
None


I_RpcGetCurrentCallHandle
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdcep.h
Unicode
Platform Notes
None


I_RpcIfInqTransferSyntaxes
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdcep.h
Unicode
Platform Notes
None


I_RpcMapWin32Status
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpc.h
Unicode
Platform Notes
None


I_RpcMonitorAssociation
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdcep.h
Unicode
Platform Notes
None


I_RpcNsBindingSetEntryName
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdcep.h
Unicode
Platform Notes
None


I_RpcNsGetBuffer
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcns4.lib
Header File
rpcnsip.h
Unicode
Platform Notes
None


I_RpcNsRaiseException
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcns4.lib
Header File
rpcnsip.h
Unicode
Platform Notes
None


I_RpcNsSendReceive
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcns4.lib
Header File
rpcnsip.h
Unicode
Platform Notes
None


I_RpcPauseExecution
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdcep.h
Unicode
Platform Notes
None


I_RpcReBindBuffer
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcns4.lib
Header File
rpcdcep.h
Unicode
Platform Notes
None


I_RpcRequestMutex
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdcep.h
Unicode
Platform Notes
None


I_RpcSendReceive
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdcep.h
Unicode
Platform Notes
None


I_RpcServerRegisterForwardFunction
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdcep.h
Unicode
No
Platform Notes
None


I_RpcSetAssociationContext
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdcep.h
Unicode
Platform Notes
None


I_RpcSsDontSerializeContext
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdcep.h
Unicode
No
Platform Notes
None


I_RpcStopMonitorAssociation
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdcep.h
Unicode
Platform Notes
None


I_UuidCreate
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdcep.h
Unicode
Platform Notes
None


ICClose
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
WinNT
Platform Notes
None


ICCompress
Windows NT
New
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


ICCompressorChoose
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


ICCompressorFree
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


ICDecompress
Windows NT
New
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


ICDecompressEx
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h
Unicode
No
Platform Notes
None


ICDecompressExBegin
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h
Unicode
No
Platform Notes
None


ICDecompressExQuery
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h
Unicode
No
Platform Notes
None


ICDraw
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


ICDrawBegin
Windows NT
New
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


ICDrawSuggestFormat
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h
Unicode
No
Platform Notes
None


ICGetDisplayFormat
Windows NT
New
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


ICGetInfo
Windows NT
New
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


ICImageCompress
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


ICImageDecompress
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


ICInfo
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


ICInstall
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


ICLocate
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


ICOpen
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


ICOpenFunction
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


ICRemove
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


ICSendMessage
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


ICSeqCompressFrame
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


ICSeqCompressFrameEnd
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


ICSeqCompressFrameStart
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


ICSetState
Windows NT
New
Win95
Yes
Win32s
No
Import Library
Header File
vfw.h
Unicode
No
Platform Notes
None


ICSetStatusProc
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h
Unicode
Platform Notes
None


IIDFromString
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


ImageList_Add
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


ImageList_AddMasked
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


ImageList_BeginDrag
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


ImageList_Create
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


ImageList_Destroy
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


ImageList_DragEnter
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


ImageList_DragLeave
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


ImageList_DragMove
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


ImageList_DragShowNolock
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


ImageList_Draw
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


ImageList_DrawEx
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


ImageList_EndDrag
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


ImageList_ExtractIcon
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


ImageList_GetBkColor
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


ImageList_GetDragImage
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


ImageList_GetIcon
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


ImageList_GetIconSize
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


ImageList_GetImageCount
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


ImageList_GetImageInfo
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


ImageList_LoadBitmap
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


ImageList_LoadImage
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
commctrl.h
Unicode
WinNT
Platform Notes
None


ImageList_Merge
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


ImageList_Read
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


ImageList_Remove
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


ImageList_Replace
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


ImageList_ReplaceIcon
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


ImageList_SetBkColor
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


ImageList_SetDragCursorImage
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


ImageList_SetIconSize
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


ImageList_SetOverlayImage
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


ImageList_Write
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


ImmAssociateContext
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


ImmConfigureIME
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


ImmCreateContext
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


ImmDestroyContext
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


ImmEnumRegisterWord
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


ImmEscape
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


ImmGetCandidateList
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


ImmGetCandidateListCount
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


ImmGetCandidateWindow
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


ImmGetCompositionFont
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


ImmGetCompositionString
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


ImmGetCompositionWindow
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


ImmGetContext
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


ImmGetConversionList
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


ImmGetConversionStatus
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


ImmGetDefaultIMEWnd
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


ImmGetDescription
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


ImmGetGuideLine
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


ImmGetIMEFileName
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


ImmGetOpenStatus
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


ImmGetProperty
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


ImmGetRegisterWordStyle
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


ImmGetStatusWindowPos
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


ImmGetVirtualKey
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


ImmInstallIME
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


ImmIsIME
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


ImmIsUIMessage
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


ImmNotifyIME
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


ImmRegisterWord
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


ImmReleaseContext
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


ImmSetCandidateWindow
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


ImmSetCompositionFont
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


ImmSetCompositionString
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


ImmSetCompositionWindow
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


ImmSetConversionStatus
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


ImmSetOpenStatus
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


ImmSetStatusWindowPos
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


ImmSimulateHotKey
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


ImmUnregisterWord
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


ImpersonateDdeClientWindow
Windows NT
Yes
Win95
No
Win32s
No
Import Library
user32.lib
Header File
dde.h
Unicode
No
Platform Notes
None


ImpersonateLoggedOnUser
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
winbase.h
Unicode
No
Platform Notes
None


ImpersonateNamedPipeClient
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


ImpersonateSelf
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


inet_addr
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


inet_ntoa
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


InflateRect
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


InitAtomTable
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


InitCommonControls
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


InitializeAcl
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


InitializeCriticalSection
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


InitializeSecurityDescriptor
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


InitializeSid
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


InitiateSystemShutdown
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winreg.h
Unicode
WinNT
Platform Notes
None


InSendMessage
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


InsertMenu
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


InsertMenuItem
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


Int32x32To64
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
winnt.h
Unicode
No
Platform Notes
None


Int64ShllMod32
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
winnt.h
Unicode
No
Platform Notes
None


Int64ShraMod32
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
winnt.h
Unicode
No
Platform Notes
None


Int64ShrlMod32
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
winnt.h
Unicode
No
Platform Notes
None


InterlockedDecrement
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


InterlockedExchange
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


InterlockedIncrement
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


IntersectClipRect
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


IntersectRect
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


InvalidateRect
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


InvalidateRgn
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


InvertRect
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


InvertRgn
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


ioctlsocket
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


IsAccelerator
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


IsBadCodePtr
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


IsBadHugeReadPtr
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


IsBadHugeWritePtr
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


IsBadReadPtr
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


IsBadStringPtr
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


IsBadWritePtr
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


IsCharAlpha
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


IsCharAlphaNumeric
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


IsCharLower
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


IsCharUpper
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


IsChild
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


IsClipboardFormatAvailable
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


IsDBCSLeadByte
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winnls.h
Unicode
No
Platform Notes
None


IsDBCSLeadByteEx
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winnls.h
Unicode
No
Platform Notes
None


IsDialogMessage
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


IsDlgButtonChecked
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


IsEqualGUID
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


IsIconic
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


IsMenu
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


IsRectEmpty
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


IsTextUnicode
Windows NT
New
Win95
No
Win32s
New
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


IsValidAcl
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


IsValidCodePage
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winnls.h
Unicode
No
Platform Notes
None


IsValidLocale
Windows NT
New
Win95
New
Win32s
New
Import Library
kernel32.lib
Header File
winnls.h
Unicode
No
Platform Notes
None


IsValidPtrOut
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


IsValidSecurityDescriptor
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


IsValidSid
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


IsWindow
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


IsWindowEnabled
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


IsWindowUnicode
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


IsWindowVisible
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


IsZoomed
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


joyGetDevCaps
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
WinNT
Platform Notes
None


joyGetNumDevs
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


joyGetPos
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


joyGetThreshold
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


joyReleaseCapture
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


joySetCapture
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


joySetThreshold
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


keybd_event
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


KillTimer
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


LBItemFromPt
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


LCMapString
Windows NT
New
Win95
Yes
Win32s
New
Import Library
kernel32.lib
Header File
winnls.h
Unicode
WinNT
Platform Notes
None


LeaveCriticalSection
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


LHashValOfNameSys
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


LineDDA
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


LineTo
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


listen
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


LoadAccelerators
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


LoadBitmap
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


LoadCursor
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


LoadCursorFromFile
Windows NT
New
Win95
New
Win32s
New
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


LoadIcon
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


LoadImage
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


LoadImageColorMatcher
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
WinNT
Platform Notes
None


LoadKeyboardLayout
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
Windows 95: Only 1 keybrd loaded at once


LoadLibrary
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


LoadLibraryEx
Windows NT
Yes
Win95
Yes
Win32s
New
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
Windows 95 limitations


LoadMenu
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


LoadMenuIndirect
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


LoadModule
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


LoadRegTypeLib
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


LoadResource
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


LoadString
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


LoadTypeLib
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


LocalAlloc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


LocalCompact
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


LocalDiscard
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winbase.h
Unicode
No
Platform Notes
None


LocalFileTimeToFileTime
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


LocalFlags
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


LocalFree
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


LocalHandle
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


LocalLock
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


LocalReAlloc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


LocalShrink
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


LocalSize
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


LocalUnlock
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


LockFile
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


LockFileEx
Windows NT
Yes
Win95
No
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


LockResource
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


LockSegment
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winbase.h
Unicode
No
Platform Notes
None


LockServiceDatabase
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winsvc.h
Unicode
No
Platform Notes
None


LockWindowUpdate
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


LogonUser
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


long_array_from_ndr
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcndr.h
Unicode
Platform Notes
None


long_from_ndr
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcndr.h
Unicode
Platform Notes
None


long_from_ndr_temp
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcndr.h
Unicode
Platform Notes
None


LookupAccountName
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


LookupAccountSid
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


LookupIconIdFromDirectory
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


LookupIconIdFromDirectoryEx
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


LookupPrivilegeDisplayName
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


LookupPrivilegeName
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


LookupPrivilegeValue
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


LPtoDP
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


lstrcat
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


lstrcmp
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


lstrcmpi
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


lstrcpy
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


lstrcpyn
Windows NT
New
Win95
Yes
Win32s
New
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


lstrlen
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT; Win95
Platform Notes
None


LZClose
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
lz32.lib
Header File
lzexpand.h
Unicode
No
Platform Notes
None


LZCopy
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
lz32.lib
Header File
lzexpand.h
Unicode
No
Platform Notes
None


LZDone
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
lz32.lib
Header File
lzexpand.h
Unicode
No
Platform Notes
None


LZInit
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
lz32.lib
Header File
lzexpand.h
Unicode
No
Platform Notes
None


LZOpenFile
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
lz32.lib
Header File
lzexpand.h
Unicode
WinNT
Platform Notes
None


LZRead
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
lz32.lib
Header File
lzexpand.h
Unicode
No
Platform Notes
None


LZSeek
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
lz32.lib
Header File
lzexpand.h
Unicode
No
Platform Notes
None


LZStart
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
lz32.lib
Header File
lzexpand.h
Unicode
No
Platform Notes
None


MakeAbsoluteSD
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


MakeDragList
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


MakeProcInstance
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winbase.h
Unicode
No
Platform Notes
None


MakeSelfRelativeSD
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


MapDialogRect
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


MapGenericMask
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


MapViewOfFile
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
Windows 95: Memory mapped files appear in the same address space in all processes


MapViewOfFileEx
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
Windows 95: Memory mapped files appear in the same address space in all processes


MapVirtualKey
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


MapVirtualKeyEx
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


MapWindowPoints
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


MaskBlt
Windows NT
Yes
Win95
No
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


mciGetCreatorTask
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


mciGetDeviceID
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
WinNT
Platform Notes
None


mciGetDeviceIDFromElementID
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
WinNT
Platform Notes
None


mciGetErrorString
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
WinNT
Platform Notes
None


mciGetYieldProc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


mciSendCommand
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
WinNT
Platform Notes
None


mciSendString
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
WinNT
Platform Notes
None


mciSetYieldProc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MCIWndCreate
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
WinNT
Platform Notes
None


MCIWndRegisterClass
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


MenuHelp
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


MenuItemFromPoint
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


MesBufferHandleReset
Windows NT
New
Win95
Win32s
No
Import Library
rpcrt4.lib
Header File
midles.h
Unicode
No
Platform Notes
None


MesDecodeBufferHandleCreate
Windows NT
New
Win95
Win32s
No
Import Library
rpcrt4.lib
Header File
midles.h
Unicode
No
Platform Notes
None


MesDecodeIncrementalHandleCreate
Windows NT
New
Win95
Win32s
No
Import Library
rpcrt4.lib
Header File
midles.h
Unicode
No
Platform Notes
None


MesEncodeDynBufferHandleCreate
Windows NT
New
Win95
Win32s
No
Import Library
rpcrt4.lib
Header File
midles.h
Unicode
No
Platform Notes
None


MesEncodeFixedBufferHandleCreate
Windows NT
New
Win95
Win32s
No
Import Library
rpcrt4.lib
Header File
midles.h
Unicode
No
Platform Notes
None


MesEncodeIncrementalHandleCreate
Windows NT
New
Win95
Win32s
No
Import Library
rpcrt4.lib
Header File
midles.h
Unicode
No
Platform Notes
None


MesHandleFree
Windows NT
New
Win95
Win32s
No
Import Library
rpcrt4.lib
Header File
midles.h
Unicode
No
Platform Notes
None


MesIncrementalHandleReset
Windows NT
New
Win95
Win32s
No
Import Library
rpcrt4.lib
Header File
midles.h
Unicode
No
Platform Notes
None


MesInqProcEncodingId
Windows NT
New
Win95
Win32s
No
Import Library
rpcrt4.lib
Header File
midles.h
Unicode
No
Platform Notes
None


MessageBeep
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


MessageBox
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT; Win95
Platform Notes
None


MessageBoxEx
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT; Win95
Platform Notes
None


MessageBoxIndirect
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


midiConnect
Windows NT
Stub
Win95
Yes
Win32s
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


midiDisconnect
Windows NT
Stub
Win95
Yes
Win32s
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


midiInAddBuffer
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


midiInClose
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


midiInGetDevCaps
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
WinNT
Platform Notes
None


midiInGetErrorText
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
WinNT
Platform Notes
None


midiInGetID
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


midiInGetNumDevs
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


midiInMessage
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


midiInOpen
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


midiInPrepareHeader
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


midiInReset
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


midiInStart
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


midiInStop
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


midiInUnprepareHeader
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


midiOutCacheDrumPatches
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


midiOutCachePatches
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


midiOutClose
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


midiOutGetDevCaps
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
WinNT
Platform Notes
None


midiOutGetErrorText
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
WinNT
Platform Notes
None


midiOutGetID
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


midiOutGetNumDevs
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


midiOutGetVolume
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


midiOutLongMsg
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


midiOutMessage
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


midiOutOpen
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


midiOutPrepareHeader
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


midiOutReset
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


midiOutSetVolume
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


midiOutShortMsg
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


midiOutUnprepareHeader
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


midiStreamClose
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


midiStreamOpen
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


midiStreamOut
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


midiStreamPause
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


midiStreamPosition
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


midiStreamProperty
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


midiStreamRestart
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


midiStreamStop
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


midl_allocate
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
rpcndr.h
Unicode
Platform Notes
None


MIDL_user_allocate
Windows NT
Yes
Win95
No
Win32s
No
Import Library
user defined
Header File
rpcndr.h
Unicode
Platform Notes
None


MIDL_wchar_strcpy
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcndr.h
Unicode
Platform Notes
None


MIDL_wchar_strlen
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcndr.h
Unicode
Platform Notes
None


mixerClose
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


mixerGetControlDetails
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
WinNT
Platform Notes
None


mixerGetDevCaps
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
WinNT
Platform Notes
None


mixerGetID
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


mixerGetLineControls
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
WinNT
Platform Notes
None


mixerGetLineInfo
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
WinNT
Platform Notes
None


mixerGetNumDevs
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


mixerMessage
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


mixerOpen
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


mixerSetControlDetails
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MkParseDisplayName
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


mmioAdvance
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


mmioAscend
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


mmioClose
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


mmioCreateChunk
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


mmioDescend
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


mmioFlush
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


mmioGetInfo
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


mmioInstallIOProc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
WinNT
Platform Notes
None


mmioOpen
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
WinNT
Platform Notes
None


mmioRead
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


mmioRename
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
WinNT
Platform Notes
None


mmioSeek
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


mmioSendMessage
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


mmioSetBuffer
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


mmioSetInfo
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


mmioStringToFOURCC
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
WinNT
Platform Notes
None


mmioWrite
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


mmsystemGetVersion
Windows NT
No
Win95
No
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


ModifyMenu
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


ModifyWorldTransform
Windows NT
Yes
Win95
No
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


MonikerCommonPrefixWith
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


MonikerRelativePathTo
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


mouse_event
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


MoveFile
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


MoveFileEx
Windows NT
Yes
Win95
No
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


MoveMemory
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winbase.h
Unicode
No
Platform Notes
None


MoveToEx
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


MoveWindow
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


MsgWaitForMultipleObjects
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


MulDiv
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


MultiByteToWideChar
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winnls.h
Unicode
No
Platform Notes
None


NDdeGetErrorString
Windows NT
Yes
Win95
No
Win32s
No
Import Library
nddeapi.lib
Header File
nddeapi.h
Unicode
WinNT
Platform Notes
None


NDdeGetShareSecurity
Windows NT
Yes
Win95
No
Win32s
No
Import Library
nddeapi.lib
Header File
nddeapi.h
Unicode
WinNT
Platform Notes
None


NDdeGetTrustedShare
Windows NT
Yes
Win95
No
Win32s
No
Import Library
nddeapi.lib
Header File
nddeapi.h
Unicode
WinNT
Platform Notes
None


NDdeIsValidAppTopicList
Windows NT
Yes
Win95
No
Win32s
No
Import Library
nddeapi.lib
Header File
nddeapi.h
Unicode
WinNT
Platform Notes
None


NDdeIsValidShareName
Windows NT
Yes
Win95
No
Win32s
No
Import Library
nddeapi.lib
Header File
nddeapi.h
Unicode
WinNT
Platform Notes
None


NDdeSetShareSecurity
Windows NT
Yes
Win95
No
Win32s
No
Import Library
nddeapi.lib
Header File
nddeapi.h
Unicode
WinNT
Platform Notes
None


NDdeSetTrustedShare
Windows NT
Yes
Win95
No
Win32s
No
Import Library
nddeapi.lib
Header File
nddeapi.h
Unicode
WinNT
Platform Notes
None


NDdeShareAdd
Windows NT
Yes
Win95
No
Win32s
No
Import Library
nddeapi.lib
Header File
nddeapi.h
Unicode
WinNT
Platform Notes
None


NDdeShareDel
Windows NT
Yes
Win95
No
Win32s
No
Import Library
nddeapi.lib
Header File
nddeapi.h
Unicode
WinNT
Platform Notes
None


NDdeShareEnum
Windows NT
Yes
Win95
No
Win32s
No
Import Library
nddeapi.lib
Header File
nddeapi.h
Unicode
WinNT
Platform Notes
None


NDdeShareGetInfo
Windows NT
Yes
Win95
No
Win32s
No
Import Library
nddeapi.lib
Header File
nddeapi.h
Unicode
WinNT
Platform Notes
None


NDdeShareSetInfo
Windows NT
Yes
Win95
No
Win32s
No
Import Library
nddeapi.lib
Header File
nddeapi.h
Unicode
WinNT
Platform Notes
None


NDdeTrustedShareEnum
Windows NT
Yes
Win95
No
Win32s
Yes
Import Library
nddeapi.lib
Header File
nddeapi.h
Unicode
WinNT
Platform Notes
None


NDRCContextBinding
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcndr.h
Unicode
Platform Notes
None


NDRCContextMarshall
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcndr.h
Unicode
Platform Notes
None


NDRCContextUnmarshall
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcndr.h
Unicode
Platform Notes
None


NDRcopy
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcndr.h
Unicode
Platform Notes
None


NDRSContextMarshall
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcndr.h
Unicode
Platform Notes
None


NDRSContextUnmarshall
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcndr.h
Unicode
Platform Notes
None


NetAccessAdd
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
lmaccess.h
Unicode
WinNT
Platform Notes
None


NetAccessCheck
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
Unicode
WinNT
Platform Notes
None


NetAccessDel
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
lmaccess.h
Unicode
WinNT
Platform Notes
None


NetAccessEnum
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
lmaccess.h
Unicode
WinNT
Platform Notes
None


NetAccessGetInfo
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
lmaccess.h
Unicode
WinNT
Platform Notes
None


NetAccessGetUserPerms
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
lmaccess.h
Unicode
WinNT
Platform Notes
None


NetAccessSetInfo
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
lmaccess.h
Unicode
WinNT
Platform Notes
None


NetAlertRaise
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmalert.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetAlertRaiseEx
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmalert.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetApiBufferAllocate
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmapibuf.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetApiBufferFree
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmapibuf.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetApiBufferReallocate
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmapibuf.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetApiBufferSize
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmapibuf.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetapipBufferAllocate
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmapibuf.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetAuditClear
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmapibuf.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetAuditRead
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmapibuf.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetAuditWrite
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmaudit.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


Netbios
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
netapi32.lib
Header File
nb30.h
Unicode
No
Platform Notes
None


NetConfigGet
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmconfig.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetConfigGetAll
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmconfig.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetConfigSet
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmconfig.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetConnectionEnum
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
netapi32.lib
Header File
lmshare.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetErrorLogClear
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmerrlog.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetErrorLogRead
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmerrlog.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetErrorLogWrite
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmerrlog.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetFileClose
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
netapi32.lib
Header File
lmshare.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetFileEnum
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
netapi32.lib
Header File
lmshare.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetFileGetInfo
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmaccess.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetGetAnyDCName
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmaccess.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetGetDCName
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmaccess.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetGroupAdd
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmaccess.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetGroupAddUser
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmaccess.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetGroupDel
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmaccess.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetGroupDelUser
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmaccess.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetGroupEnum
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmaccess.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetGroupGetInfo
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmaccess.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetGroupGetUsers
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmaccess.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetGroupSetInfo
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmaccess.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetGroupSetUsers
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmaccess.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetLocalGroupAdd
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmaccess.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetLocalGroupAddMember
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmaccess.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetLocalGroupDel
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmaccess.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetLocalGroupDelMember
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmaccess.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetLocalGroupEnum
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmaccess.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetLocalGroupGetInfo
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmaccess.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetLocalGroupGetMembers
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmaccess.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetLocalGroupSetInfo
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmaccess.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetLocalGroupSetMembers
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmaccess.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetMessageBufferSend
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmmsg.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetMessageNameAdd
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmmsg.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetMessageNameDel
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmmsg.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetMessageNameEnum
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmmsg.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetMessageNameGetInfo
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmmsg.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetRemoteComputerSupports
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmremutl.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetRemoteTOD
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmremutl.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetReplExportDirAdd
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmrepl.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetReplExportDirDel
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmrepl.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetReplExportDirEnum
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmrepl.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetReplExportDirGetInfo
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmrepl.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetReplExportDirLock
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmrepl.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetReplExportDirSetInfo
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmrepl.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetReplExportDirUnlock
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmrepl.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetReplGetInfo
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmrepl.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetReplImportDirAdd
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmrepl.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetReplImportDirDel
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmrepl.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetReplImportDirEnum
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmrepl.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetReplImportDirGetInfo
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmrepl.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetReplImportDirLock
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmrepl.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetReplImportDirUnlock
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmrepl.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetReplSetInfo
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmrepl.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetScheduleJobAdd
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmat.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetScheduleJobDel
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmat.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetScheduleJobEnum
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmat.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetScheduleJobGetInfo
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmat.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetServerDiskEnum
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmserver.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetServerEnum
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmserver.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetServerGetInfo
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
netapi32.lib
Header File
lmserver.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetServerSetInfo
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
netapi32.lib
Header File
lmserver.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetServerTransportAdd
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmserver.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetServerTransportDel
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmserver.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetServerTransportEnum
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmserver.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetServiceControl
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmsvc.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetServiceEnum
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmsvc.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetServiceGetInfo
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmsvc.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetServiceInstall
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmsvc.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetSessionDel
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
netapi32.lib
Header File
lmshare.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetSessionEnum
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmshare.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetSessionGetInfo
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmshare.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetShareAdd
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmshare.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetShareCheck
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmshare.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetShareDel
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmshare.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetShareDelSticky
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmshare.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetShareEnum
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
netapi32.lib
Header File
lmshare.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetShareEnumSticky
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmshare.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetShareGetInfo
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
netapi32.lib
Header File
lmshare.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetShareSetInfo
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
netapi32.lib
Header File
lmshare.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetStatisticsGet
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmstats.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetUseAdd
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmuse.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetUseDel
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmuse.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetUseEnum
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmuse.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetUseGetInfo
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmuse.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetUserAdd
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmaccess.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetUserChangePassword
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
lmaccess.h
Unicode
WinNT
Platform Notes
None


NetUserDel
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmaccess.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetUserEnum
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmaccess.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetUserGetGroups
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmaccess.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetUserGetInfo
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmaccess.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetUserGetLocalGroups
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmaccess.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetUserModalsGet
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmaccess.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetUserModalsSet
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmaccess.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetUserSetGroups
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmaccess.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetUserSetInfo
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmaccess.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetWkstaGetInfo
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmwksta.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetWkstaSetInfo
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmwksta.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetWkstaTransportAdd
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmwksta.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetWkstaTransportDel
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmwksta.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetWkstaTransportEnum
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmwksta.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetWkstaUserEnum
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmwksta.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetWkstaUserGetInfo
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmwksta.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NetWkstaUserSetInfo
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmwksta.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


NotifyBootConfigStatus
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winsvc.h
Unicode
No
Platform Notes
None


NotifyChangeEventLog
Windows NT
New
Win95
No
Win32s
New
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


ntohl
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


ntohs
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


OaBuildVersion
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


ObjectCloseAuditAlarm
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


ObjectOpenAuditAlarm
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


ObjectPrivilegeAuditAlarm
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


OemKeyScan
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


OemToAnsi
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


OemToAnsiBuff
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


OemToChar
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


OemToCharBuff
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


OffsetClipRgn
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


OffsetRect
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


OffsetRgn
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


OffsetViewportOrgEx
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


OffsetWindowOrgEx
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


OleBuildVersion
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


OleConvertIStorageToOLESTREAM
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


Ol
eConvertIStorageToOLESTREAMEx
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


OleConvertOLESTREAMToIStorage
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


Ol
eConvertOLESTREAMToIStorageEx
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


OleCreate
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


OleCreateDefaultHandler
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


OleCreateEmbeddingHelper
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


OleCreateFromData
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


OleCreateFromFile
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


OleCreateLink
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


OleCreateLinkFromData
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


OleCreateLinkToFile
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


OleCreateMenuDescriptor
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


OleCreateStaticFromData
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


OleDestroyMenuDescriptor
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


OleDoAutoConvert
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


OleDraw
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


OleDuplicateData
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


OleFlushClipboard
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


OleGetAutoConvert
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


OleGetClipboard
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


OleGetIconOfClass
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


OleGetIconOfFile
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


OleInitialize
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


OleIsCurrentClipboard
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


OleIsRunning
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


OleLoad
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


OleLoadFromStream
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


OleLockRunning
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


OleMetafilePictFromIconAndLabel
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


OleNoteObjectVisible
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


OleQueryCreateFromData
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


OleQueryLinkFromData
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


OleRegEnumFormatEtc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


OleRegEnumVerbs
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


OleRegGetMiscStatus
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


OleRegGetUserType
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


OleRun
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


OleSave
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


OleSaveToStream
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


OleSetAutoConvert
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


OleSetClipboard
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


OleSetContainedObject
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


OleSetMenuDescriptor
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


OleTranslateAccelerator
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


OleUninitialize
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


OpenBackupEventLog
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


OpenClipboard
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


OpenDesktop
Windows NT
Yes
Win95
No
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


OpenEvent
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


OpenEventLog
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


OpenFile
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


OpenFileMapping
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


OpenIcon
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


OpenInputDesktop
Windows NT
Yes
Win95
No
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


OpenMutex
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


OpenPrinter
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
WinNT
Platform Notes
None


OpenProcess
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
On Win32s fdwAccess and fInherit ignored (set to PROCESS_ALL_ACCCESS and TRUE)


OpenProcessToken
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


OpenSCManager
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winsvc.h
Unicode
WinNT
Platform Notes
None


OpenSemaphore
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


OpenService
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winsvc.h
Unicode
WinNT
Platform Notes
None


OpenThreadToken
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


OpenWindowStation
Windows NT
Yes
Win95
No
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


OutputDebugString
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


PackDDElParam
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
dde.h
Unicode
No
Platform Notes
None


PaintDesktop
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


PaintRgn
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


PatBlt
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


PathToRegion
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


PeekConsoleInput
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
wincon.h
Unicode
WinNT
Platform Notes
None


PeekMessage
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


PeekNamedPipe
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


Pie
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


PlayEnhMetaFile
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
 no dashed widelines
Platform Notes
Windows 95: Skips records which couldn't be processed under Windows 95's GDI: greater than 16-bit coordinates


PlayEnhMetaFileRecord
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
 no dashed widelines
Platform Notes
Windows 95: Skips records which couldn't be processed under Windows 95's GDI: greater than 16-bit coordinates


PlayMetaFile
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


PlayMetaFileRecord
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


PlaySound
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
WinNT
Platform Notes
None


PlgBlt
Windows NT
Yes
Win95
No
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


PolyBezier
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


PolyBezierTo
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


PolyDraw
Windows NT
Yes
Win95
No
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


Polygon
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


Polyline
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


PolylineTo
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


PolyPolygon
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


PolyPolyline
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


PolyTextOut
Windows NT
Yes
Win95
No
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
WinNT
Platform Notes
None


PostAppMessage
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


PostMessage
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


PostQueuedCompletionStatus
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
winbase.h
Unicode
No
Platform Notes
None


PostQuitMessage
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


PostThreadMessage
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


PrepareTape
Windows NT
Yes
Win95
No
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


PrintDlg
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
comdlg32.lib
Header File
commdlg.h
Unicode
WinNT
Platform Notes
None


PrinterMessageBox
Windows NT
Yes
Win95
No
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
WinNT
Platform Notes
None


PrinterProperties
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
No
Platform Notes
None


PrivilegeCheck
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


PrivilegedServiceAuditAlarm
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


PtInRect
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


PtInRegion
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


PtVisible
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


PulseEvent
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


PurgeComm
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


QueryDosDevice
Windows NT
Yes
Win95
No
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


QueryPathOfRegTypeLib
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


QueryPerformanceCounter
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


QueryPerformanceFrequency
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


QueryServiceConfig
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winsvc.h
Unicode
WinNT
Platform Notes
None


QueryServiceLockStatus
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winsvc.h
Unicode
WinNT
Platform Notes
None


QueryServiceObjectSecurity
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winsvc.h
Unicode
No
Platform Notes
None


QueryServiceStatus
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winsvc.h
Unicode
No
Platform Notes
None


RaiseException
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


RasDial
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rasapi32.lib
Header File
ras.h
Unicode
WinNT
Platform Notes
None


RasEnumConnections
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rasapi32.lib
Header File
ras.h
Unicode
WinNT
Platform Notes
None


RasEnumEntries
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rasapi32.lib
Header File
ras.h
Unicode
WinNT
Platform Notes
None


RasGetConnectStatus
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rasapi32.lib
Header File
ras.h
Unicode
WinNT
Platform Notes
None


RasGetErrorString
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rasapi32.lib
Header File
ras.h
Unicode
WinNT
Platform Notes
None


RasGetProjectionInfo
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rasapi32.lib
Header File
ras.h
Unicode
WinNT
Platform Notes
None


RasHangUp
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rasapi32.lib
Header File
ras.h
Unicode
WinNT
Platform Notes
None


ReadClassStg
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


ReadClassStm
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


ReadConsole
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
wincon.h
Unicode
WinNT
Platform Notes
None


ReadConsoleInput
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
wincon.h
Unicode
WinNT
Platform Notes
None


ReadConsoleOutput
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
wincon.h
Unicode
WinNT
Platform Notes
None


ReadConsoleOutputAttribute
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
wincon.h
Unicode
No
Platform Notes
None


ReadConsoleOutputCharacter
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
wincon.h
Unicode
WinNT
Platform Notes
None


ReadEventLog
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


ReadFile
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
New
Platform Notes
Windows 95: No overlapped regions


ReadFileEx
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
Windows 95 limitations


ReadFmtUserTypeStg
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


ReadPrinter
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
No
Platform Notes
None


ReadProcessMemory
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


RealizePalette
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


Rectangle
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


RectInRegion
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


RectVisible
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


recv
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


recvfrom
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


RedrawWindow
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


RegCloseKey
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
advapi32.lib
Header File
winreg.h
Unicode
No
Platform Notes
None


RegConnectRegistry
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
advapi32.lib
Header File
winreg.h
Unicode
WinNT
Platform Notes
None


RegCreateKey
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
advapi32.lib
Header File
winreg.h
Unicode
WinNT
Platform Notes
None


RegCreateKeyEx
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
advapi32.lib
Header File
winreg.h
Unicode
WinNT
Platform Notes
None


RegDeleteKey
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
advapi32.lib
Header File
winreg.h
Unicode
WinNT
Platform Notes
None


RegDeleteValue
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
advapi32.lib
Header File
winreg.h
Unicode
WinNT
Platform Notes
None


RegEnumKey
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
advapi32.lib
Header File
winreg.h
Unicode
WinNT
Platform Notes
None


RegEnumKeyEx
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
advapi32.lib
Header File
winreg.h
Unicode
WinNT
Platform Notes
None


RegEnumValue
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
advapi32.lib
Header File
winreg.h
Unicode
WinNT
Platform Notes
None


RegFlushKey
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
advapi32.lib
Header File
winreg.h
Unicode
No
Platform Notes
None


RegGetKeySecurity
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winreg.h
Unicode
No
Platform Notes
None


RegisterActiveObject
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


RegisterClass
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


RegisterClassEx
Windows NT
Stub
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


RegisterClipboardFormat
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


RegisterDialogClasses
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
scrnsave.lib
Header File
scrnsave.h
Unicode
No
Platform Notes
None


RegisterDragDrop
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


RegisterEventSource
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


RegisterHotKey
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


RegisterServiceCtrlHandler
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winsvc.h
Unicode
WinNT
Platform Notes
None


RegisterTypeLib
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


RegisterWindowMessage
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


RegLoadKey
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
advapi32.lib
Header File
winreg.h
Unicode
WinNT
Platform Notes
None


RegNotifyChangeKeyValue
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winreg.h
Unicode
No
Platform Notes
None


RegOpenKey
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
advapi32.lib
Header File
winreg.h
Unicode
WinNT
Platform Notes
None


RegOpenKeyEx
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
advapi32.lib
Header File
winreg.h
Unicode
WinNT
Platform Notes
None


RegQueryInfoKey
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
advapi32.lib
Header File
winreg.h
Unicode
WinNT
Platform Notes
None


RegQueryMultipleValues
Windows NT
No
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
Platform Notes
None


RegQueryValue
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
advapi32.lib
Header File
winreg.h
Unicode
WinNT
Platform Notes
None


RegQueryValueEx
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
advapi32.lib
Header File
winreg.h
Unicode
WinNT
Platform Notes
None


RegReplaceKey
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
advapi32.lib
Header File
winreg.h
Unicode
WinNT
Platform Notes
None


RegRestoreKey
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winreg.h
Unicode
WinNT
Platform Notes
None


RegSaveKey
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
advapi32.lib
Header File
winreg.h
Unicode
WinNT
Platform Notes
None


RegSetKeySecurity
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winreg.h
Unicode
No
Platform Notes
None


RegSetValue
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
advapi32.lib
Header File
winreg.h
Unicode
WinNT
Platform Notes
None


RegSetValueEx
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
advapi32.lib
Header File
winreg.h
Unicode
WinNT
Platform Notes
None


RegUnLoadKey
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
advapi32.lib
Header File
winreg.h
Unicode
WinNT
Platform Notes
None


ReleaseCapture
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


ReleaseDC
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


ReleaseMutex
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


ReleaseSemaphore
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


ReleaseStgMedium
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


RemoveDirectory
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


RemoveFontResource
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
WinNT
Platform Notes
Windows 95: int == 16 bits


RemoveMenu
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


RemoveProp
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


ReplaceText
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
comdlg32.lib
Header File
commdlg.h
Unicode
WinNT
Platform Notes
None


ReplyMessage
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


ReportEvent
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


ResetDC
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
WinNT
Platform Notes
Windows 95: int == 16 bits


ResetDisplay
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


ResetEvent
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


ResetPrinter
Windows NT
Yes
Win95
No
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
WinNT
Platform Notes
None


ResizePalette
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


RestoreDC
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


ResumeThread
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


ReuseDDElParam
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
dde.h
Unicode
No
Platform Notes
None


RevertToSelf
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


RevokeActiveObject
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


RevokeDragDrop
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


RoundRect
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


RpcAbnormalTermination
Windows NT
New
Win95
Yes
Win32s
No
Import Library
Header File
rpc.h
Unicode
No
Platform Notes
None


RpcBindingCopy
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
No
Platform Notes
None


RpcBindingFree
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
No
Platform Notes
None


RpcBindingFromStringBinding
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
WinNT
Platform Notes
None


RpcBindingInqAuthClient
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
Platform Notes
None


RpcBindingInqAuthInfo
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
WinNT
Platform Notes
None


RpcBindingInqObject
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
No
Platform Notes
None


RpcBindingReset
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
No
Platform Notes
None


RpcBindingServerFromClient
Windows NT
Yes
Win95
Yes
Win32s
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
No
Platform Notes
None


RpcBindingSetAuthInfo
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
Platform Notes
None


RpcBindingSetObject
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
No
Platform Notes
None


RpcBindingToStringBinding
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
WinNT
Platform Notes
None


RpcBindingVectorFree
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
No
Platform Notes
None


RpcCancelThread
Windows NT
New
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
No
Platform Notes
None


RpcEndExcept
Windows NT
New
Win95
Yes
Win32s
No
Import Library
Header File
rpc.h
Unicode
No
Platform Notes
None


RpcEndFinally
Windows NT
New
Win95
Yes
Win32s
No
Import Library
Header File
rpc.h
Unicode
No
Platform Notes
None


RpcEpRegister
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
WinNT
Platform Notes
None


RpcEpRegisterNoReplace
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
WinNT
Platform Notes
None


RpcEpResolveBinding
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
No
Platform Notes
None


RpcEpUnregister
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
No
Platform Notes
None


RpcExcept
Windows NT
New
Win95
Yes
Win32s
No
Import Library
Header File
rpc.h
Unicode
No
Platform Notes
None


RpcExceptionCode
Windows NT
New
Win95
Yes
Win32s
No
Import Library
Header File
rpc.h
Unicode
No
Platform Notes
None


RpcFinally
Windows NT
New
Win95
Yes
Win32s
No
Import Library
Header File
rpc.h
Unicode
No
Platform Notes
None


RpcIfIdVectorFree
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
No
Platform Notes
None


RpcIfInqId
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
No
Platform Notes
None


RpcImpersonateClient
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpc.h
Unicode
Platform Notes
None


RpcMgmtEnableIdleCleanup
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
No
Platform Notes
None


RpcMgmtEpEltInqBegin
Windows NT
New
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
No
Platform Notes
None


RpcMgmtEpEltInqDone
Windows NT
New
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
No
Platform Notes
None


RpcMgmtEpEltInqNext
Windows NT
New
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
WinNT
Platform Notes
None


RpcMgmtEpUnregister
Windows NT
New
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
No
Platform Notes
None


RpcMgmtInqComTimeout
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
No
Platform Notes
None


RpcMgmtInqDefaultProtectLevel
Windows NT
Yes
Win95
Yes
Win32s
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
No
Platform Notes
None


RpcMgmtInqIfIds
Windows NT
Yes
Win95
Yes
Win32s
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
No
Platform Notes
None


RpcMgmtInqServerPrincName
Windows NT
New
Win95
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
WinNT
Platform Notes
None


RpcMgmtInqStats
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
No
Platform Notes
None


RpcMgmtIsServerListening
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
No
Platform Notes
None


RpcMgmtSetAuthorizationFn
Windows NT
New
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
No
Platform Notes
None


RpcMgmtSetCancelTimeout
Windows NT
New
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
No
Platform Notes
None


RpcMgmtSetComTimeout
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
No
Platform Notes
None


RpcMgmtSetServerStackSize
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
No
Platform Notes
None


RpcMgmtStatsVectorFree
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
No
Platform Notes
None


RpcMgmtStopServerListening
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
No
Platform Notes
None


RpcMgmtWaitServerListen
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
No
Platform Notes
None


RpcNetworkInqProtseqs
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
WinNT
Platform Notes
None


RpcNetworkIsProtseqValid
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
WinNT
Platform Notes
None


RpcNsBindingExport
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcns4.lib
Header File
rpcnsi.h
Unicode
WinNT
Platform Notes
None


RpcNsBindingImportBegin
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcns4.lib
Header File
rpcnsi.h
Unicode
WinNT
Platform Notes
None


RpcNsBindingImportDone
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcns4.lib
Header File
rpcnsi.h
Unicode
No
Platform Notes
None


RpcNsBindingImportNext
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcns4.lib
Header File
rpcnsi.h
Unicode
No
Platform Notes
None


RpcNsBindingInqEntryName
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
WinNT
Platform Notes
None


RpcNsBindingLookupBegin
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcns4.lib
Header File
rpcnsi.h
Unicode
WinNT
Platform Notes
None


RpcNsBindingLookupDone
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcns4.lib
Header File
rpcnsi.h
Unicode
No
Platform Notes
None


RpcNsBindingLookupNext
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcns4.lib
Header File
rpcnsi.h
Unicode
No
Platform Notes
None


RpcNsBindingSelect
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcns4.lib
Header File
rpcnsi.h
Unicode
No
Platform Notes
None


RpcNsBindingUnexport
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcns4.lib
Header File
rpcnsi.h
Unicode
WinNT
Platform Notes
None


RpcNsEntryExpandName
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcns4.lib
Header File
rpcnsi.h
Unicode
WinNT
Platform Notes
None


RpcNsEntryObjectInqBegin
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcns4.lib
Header File
rpcnsi.h
Unicode
WinNT
Platform Notes
None


RpcNsEntryObjectInqDone
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcns4.lib
Header File
rpcnsi.h
Unicode
No
Platform Notes
None


RpcNsEntryObjectInqNext
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcns4.lib
Header File
rpcnsi.h
Unicode
No
Platform Notes
None


RpcNsGroupDelete
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcns4.lib
Header File
rpcnsi.h
Unicode
WinNT
Platform Notes
None


RpcNsGroupMbrAdd
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcns4.lib
Header File
rpcnsi.h
Unicode
WinNT
Platform Notes
None


RpcNsGroupMbrInqBegin
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcns4.lib
Header File
rpcnsi.h
Unicode
WinNT
Platform Notes
None


RpcNsGroupMbrInqDone
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcns4.lib
Header File
rpcnsi.h
Unicode
No
Platform Notes
None


RpcNsGroupMbrInqNext
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcns4.lib
Header File
rpcnsi.h
Unicode
WinNT
Platform Notes
None


RpcNsGroupMbrRemove
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcns4.lib
Header File
rpcnsi.h
Unicode
WinNT
Platform Notes
None


RpcNsMgmtBindingUnexport
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcns4.lib
Header File
rpcnsi.h
Unicode
WinNT
Platform Notes
None


RpcNsMgmtEntryCreate
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcns4.lib
Header File
rpcnsi.h
Unicode
WinNT
Platform Notes
None


RpcNsMgmtEntryDelete
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcns4.lib
Header File
rpcnsi.h
Unicode
WinNT
Platform Notes
None


RpcNsMgmtEntryInqIfIds
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcns4.lib
Header File
rpcnsi.h
Unicode
WinNT
Platform Notes
None


RpcNsMgmtHandleSetExpAge
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcns4.lib
Header File
rpcnsi.h
Unicode
No
Platform Notes
None


RpcNsMgmtInqExpAge
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcns4.lib
Header File
rpcnsi.h
Unicode
No
Platform Notes
None


RpcNsMgmtSetExpAge
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcns4.lib
Header File
rpcnsi.h
Unicode
No
Platform Notes
None


RpcNsProfileDelete
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcns4.lib
Header File
rpcnsi.h
Unicode
WinNT
Platform Notes
None


RpcNsProfileEltAdd
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcns4.lib
Header File
rpcnsi.h
Unicode
WinNT
Platform Notes
None


RpcNsProfileEltInqBegin
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcns4.lib
Header File
rpcnsi.h
Unicode
WinNT
Platform Notes
None


RpcNsProfileEltInqDone
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcns4.lib
Header File
rpcnsi.h
Unicode
No
Platform Notes
None


RpcNsProfileEltInqNext
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcns4.lib
Header File
rpcnsi.h
Unicode
WinNT
Platform Notes
None


RpcNsProfileEltRemove
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcns4.lib
Header File
rpcnsi.h
Unicode
WinNT
Platform Notes
None


RpcObjectInqType
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
No
Platform Notes
None


RpcObjectSetInqFn
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
No
Platform Notes
None


RpcObjectSetType
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
No
Platform Notes
None


RpcProtseqVectorFree
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
Platform Notes
None


RpcRaiseException
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
Platform Notes
None


RpcRevertToSelf
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpc.h
Unicode
Platform Notes
None


RpcServerInqBindings
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
Platform Notes
None


RpcServerInqIf
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
Platform Notes
None


RpcServerListen
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
Platform Notes
None


RpcServerRegisterAuthInfo
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
Platform Notes
None


RpcServerRegisterIf
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
Platform Notes
None


RpcServerUnregisterIf
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
Platform Notes
None


RpcServerUseAllProtseqs
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
Platform Notes
None


RpcServerUseAllProtseqsIf
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
Platform Notes
None


RpcServerUseProtseq
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
Platform Notes
None


RpcServerUseProtseqEp
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
Platform Notes
None


RpcServerUseProtseqIf
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
Platform Notes
None


RpcSmAllocate
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
rpcrt4.lib
Header File
rpcndr.h
Unicode
No
Platform Notes
None


RpcSmClientFree
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
rpcrt4.lib
Header File
rpcndr.h
Unicode
No
Platform Notes
None


RpcSmDestroyClientContext
Windows NT
New
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcndr.h
Unicode
No
Platform Notes
None


RpcSmDisableAllocate
Windows NT
New
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcndr.h
Unicode
No
Platform Notes
None


RpcSmEnableAllocate
Windows NT
New
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcndr.h
Unicode
No
Platform Notes
None


RpcSmFree
Windows NT
New
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcndr.h
Unicode
No
Platform Notes
None


RpcSmGetThreadHandle
Windows NT
Yes
Win95
Yes
Win32s
Import Library
rpcrt4.lib
Header File
rpcndr.h
Unicode
No
Platform Notes
None


RpcSmSetClientAllocFree
Windows NT
New
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcndr.h
Unicode
No
Platform Notes
None


RpcSmSetThreadHandle
Windows NT
Yes
Win95
Yes
Win32s
Import Library
rpcrt4.lib
Header File
rpcndr.h
Unicode
No
Platform Notes
None


RpcSmSwapClientAllocFree
Windows NT
New
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcndr.h
Unicode
No
Platform Notes
None


RpcSsAllocate
Windows NT
Yes
Win95
Yes
Win32s
Import Library
rpcrt4.lib
Header File
rpcndr.h
Unicode
No
Platform Notes
None


RpcSsDestroyClientContext
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcndr.h
Unicode
No
Platform Notes
None


RpcSsDisableAllocate
Windows NT
Yes
Win95
Yes
Win32s
Import Library
rpcrt4.lib
Header File
rpcndr.h
Unicode
No
Platform Notes
None


RpcSsEnableAllocate
Windows NT
Yes
Win95
Yes
Win32s
Import Library
rpcrt4.lib
Header File
rpcndr.h
Unicode
No
Platform Notes
None


RpcSsFree
Windows NT
Yes
Win95
Yes
Win32s
Import Library
rpcrt4.lib
Header File
rpcndr.h
Unicode
No
Platform Notes
None


RpcSsGetThreadHandle
Windows NT
Yes
Win95
Yes
Win32s
Import Library
rpcrt4.lib
Header File
rpcndr.h
Unicode
No
Platform Notes
None


RpcSsSetClientAllocFree
Windows NT
New
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcndr.h
Unicode
No
Platform Notes
None


RpcSsSetThreadHandle
Windows NT
Yes
Win95
Yes
Win32s
Import Library
rpcrt4.lib
Header File
rpcndr.h
Unicode
No
Platform Notes
None


RpcSsSwapClientAllocFree
Windows NT
New
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcndr.h
Unicode
No
Platform Notes
None


RpcStringBindingCompose
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
WinNT
Platform Notes
None


RpcStringBindingParse
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
WinNT
Platform Notes
None


RpcStringFree
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
WinNT
Platform Notes
None


RpcTestCancel
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
WinNT
Platform Notes
None


RpcTryExcept
Windows NT
New
Win95
Yes
Win32s
No
Import Library
Header File
rpc.h
Unicode
No
Platform Notes
None


RpcTryFinally
Windows NT
New
Win95
Yes
Win32s
No
Import Library
Header File
rpc.h
Unicode
No
Platform Notes
None


RxNetAccessAdd
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmaccess.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


RxNetAccessDel
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmaccess.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


RxNetAccessEnum
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmaccess.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


RxNetAccessGetInfo
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmaccess.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


RxNetAccessGetUserPerms
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmaccess.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


RxNetAccessSetInfo
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmaccess.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


RxRemoteApi
Windows NT
Yes
Win95
No
Win32s
No
Import Library
netapi32.lib
Header File
lmremutl.h
Unicode
WinNT
Platform Notes
All LanMan APIs are UNICODE only


SafeArrayAccessData
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


SafeArrayAllocData
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


SafeArrayAllocDescriptor
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


SafeArrayCopy
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


SafeArrayCreate
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


SafeArrayDestroy
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


SafeArrayDestroyData
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


SafeArrayDestroyDescriptor
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


SafeArrayGetDim
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


SafeArrayGetElement
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


SafeArrayGetElemsize
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


SafeArrayGetLBound
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


SafeArrayGetUBound
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


SafeArrayLock
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


SafeArrayPtrOfIndex
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


SafeArrayPutElement
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


SafeArrayRedim
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


SafeArrayUnaccessData
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


SafeArrayUnlock
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


SaveDC
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


ScaleViewportExtEx
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


ScaleWindowExtEx
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


ScheduleJob
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
No
Platform Notes
None


ScreenSaverConfigureDialog
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
scrnsave.lib
Header File
scrnsave.h
Unicode
No
Platform Notes
None


ScreenSaverProc
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
scrnsave.lib
Header File
scrnsave.h
Unicode
No
Platform Notes
None


ScreenToClient
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


ScrollConsoleScreenBuffer
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
wincon.h
Unicode
WinNT
Platform Notes
None


ScrollDC
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


ScrollWindow
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


ScrollWindowEx
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


SearchPath
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


select
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


SelectClipPath
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


SelectClipRgn
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


SelectObject
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes


SelectPalette
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


send
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


SendDlgItemMessage
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


SendMessage
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


SendMessageCallback
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


SendMessageTimeout
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


SendNotifyMessage
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


sendto
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


ServiceMain
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
Unicode
No
Platform Notes
None


SetAbortProc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


SetAclInformation
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


SetActiveWindow
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


SetArcDirection
Windows NT
Yes
Win95
No
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


SetBitmapBits
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


SetBitmapDimensionEx
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


SetBkColor
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


SetBkMode
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


SetBoundsRect
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


SetBrushOrgEx
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


SetCapture
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


SetCaretBlinkTime
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


SetCaretPos
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


SetClassLong
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


SetClassWord
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


SetClipboardData
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


SetClipboardViewer
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


SetColorAdjustment
Windows NT
Yes
Win95
No
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


SetColorSpace
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


SetCommBreak
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


SetCommConfig
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


SetCommMask
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


SetCommState
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


SetCommTimeouts
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


SetComputerName
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


SetConsoleActiveScreenBuffer
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
wincon.h
Unicode
No
Platform Notes
None


SetConsoleCP
Windows NT
Yes
Win95
No
Win32s
No
Import Library
kernel32.lib
Header File
wincon.h
Unicode
No
Platform Notes
None


SetConsoleCtrlHandler
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
wincon.h
Unicode
No
Platform Notes
None


SetConsoleCursorInfo
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
wincon.h
Unicode
No
Platform Notes
None


SetConsoleCursorPosition
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
wincon.h
Unicode
No
Platform Notes
None


SetConsoleMode
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
wincon.h
Unicode
No
Platform Notes
None


SetConsoleOutputCP
Windows NT
Yes
Win95
No
Win32s
No
Import Library
kernel32.lib
Header File
wincon.h
Unicode
No
Platform Notes
None


SetConsoleScreenBufferSize
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
wincon.h
Unicode
No
Platform Notes
None


SetConsoleTextAttribute
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
wincon.h
Unicode
No
Platform Notes
None


SetConsoleTitle
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
wincon.h
Unicode
WinNT
Platform Notes
None


SetConsoleWindowInfo
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
wincon.h
Unicode
No
Platform Notes
None


SetConvertStg
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


SetCurrentDirectory
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


SetCursor
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


SetCursorPos
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


SetDebugErrorLevel
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


SetDefaultCommConfig
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


SetDeviceGammaRamp
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


SetDIBColorTable
Windows NT
New
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


SetDIBits
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


SetDIBitsToDevice
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


SetDlgItemInt
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


SetDlgItemText
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


SetDoubleClickTime
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


SetEndOfFile
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


SetEnhMetaFileBits
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


SetEnvironmentVariable
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


SetErrorInfo
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


SetErrorMode
Windows NT
New
Win95
Yes
Win32s
New
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
This is used for RISC platforms only. x86 platforms and Windows 95 return a constant


SetEvent
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


SetFileApisToANSI
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
On Win32s all file APIs are ANSI


SetFileApisToOEM
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
On Win32s the file APIs are always OEM


SetFileAttributes
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


SetFilePointer
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


SetFileSecurity
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


SetFileTime
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


SetFocus
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


SetForegroundWindow
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


SetForm
Windows NT
Yes
Win95
No
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
WinNT
Platform Notes
None


SetGraphicsMode
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: Only GM_COMPATIBLE is supported


SetHandleCount
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


SetHandleInformation
Windows NT
Yes
Win95
No
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


SetICMMode
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


SetICMProfile
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
WinNT
Platform Notes
None


SetJob
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
WinNT
Platform Notes
None


SetKernelObjectSecurity
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


SetKeyboardState
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


SetLastError
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


SetLastErrorEx
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


SetLocaleInfo
Windows NT
New
Win95
New
Win32s
New
Import Library
kernel32.lib
Header File
winnls.h
Unicode
WinNT
Platform Notes
None


SetLocalTime
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


SetMailslotInfo
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


SetMapMode
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


SetMapperFlags
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


SetMenu
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


SetMenuContextHelpId
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


SetMenuDefaultItem
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


SetMenuItemBitmaps
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


SetMenuItemInfo
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


SetMessageExtraInfo
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


SetMessageQueue
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


SetMetaFileBitsEx
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


SetMetaRgn
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


SetMiterLimit
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


SetNamedPipeHandleState
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


SetPaletteEntries
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


SetParent
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


SetPixel
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


SetPixelFormat
Windows NT
Yes
Win95
No
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


SetPixelV
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


SetPolyFillMode
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


SetPrinter
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
WinNT
Platform Notes
None


SetPrinterData
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
WinNT
Platform Notes
None


SetPriorityClass
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


SetPrivateObjectSecurity
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


SetProcessShutdownParameters
Windows NT
Yes
Win95
No
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


SetProcessWindowStation
Windows NT
Yes
Win95
No
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


SetProcessWorkingSetSize
Windows NT
Yes
Win95
No
Win32s
New
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


SetProp
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


SetRect
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


SetRectEmpty
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


SetRectRgn
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


SetROP2
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


SetScrollInfo
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


SetScrollPos
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


SetScrollRange
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


SetSecurityDescriptorDacl
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


SetSecurityDescriptorGroup
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


SetSecurityDescriptorOwner
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


SetSecurityDescriptorSacl
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


SetService
Windows NT
Yes
Win95
No
Win32s
No
Import Library
wsock32.lib
Header File
nspapi.h
Unicode
WinNT
Platform Notes
None


SetServiceBits
Windows NT
New
Win95
No
Win32s
New
Import Library
advapi32.lib
Header File
lmserver.h
Unicode
No
Platform Notes
None


SetServiceObjectSecurity
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winsvc.h
Unicode
No
Platform Notes
None


SetServiceStatus
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winsvc.h
Unicode
No
Platform Notes
None


setsockopt
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


SetStdHandle
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


SetStretchBltMode
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


SetSwapAreaSize
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winbase.h
Unicode
No
Platform Notes
None


SetSysColors
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


SetSysModalWindow
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


SetSystemCursor
Windows NT
New
Win95
Yes
Win32s
New
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


SetSystemPaletteUse
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


SetSystemPowerState
Windows NT
No
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


SetSystemTime
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


SetSystemTimeAdjustment
Windows NT
New
Win95
No
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


SetTapeParameters
Windows NT
Yes
Win95
No
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


SetTapePosition
Windows NT
Yes
Win95
No
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


SetTextAlign
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


SetTextCharacterExtra
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


SetTextColor
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


SetTextJustification
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


SetThreadAffinityMask
Windows NT
New
Win95
New
Win32s
New
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
This is valid on SMP platforms only; Windows 95 returns a constant


SetThreadContext
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


SetThreadDesktop
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
Windows 95: NOP; only one desktop


SetThreadLocale
Windows NT
Yes
Win95
No
Win32s
No
Import Library
kernel32.lib
Header File
winnls.h
Unicode
No
Platform Notes
Windows 95: Locales are static & can change only at system boot


SetThreadPriority
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


SetThreadToken
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


SetTimer
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


SetTimeZoneInformation
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


SetTokenInformation
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


SetUnhandledExceptionFilter
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


SetupComm
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


SetUserObjectInformation
Windows NT
Yes
Win95
No
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


SetUserObjectSecurity
Windows NT
Yes
Win95
No
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


SetViewportExtEx
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


SetViewportOrgEx
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


SetVolumeLabel
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


SetWindowContextHelpId
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


SetWindowExtEx
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


SetWindowLong
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


SetWindowOrgEx
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


SetWindowPlacement
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


SetWindowPos
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


SetWindowRgn
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


SetWindowsHook
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


SetWindowsHookEx
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


SetWindowText
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


SetWindowWord
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


SetWinMetaFileBits
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


SetWorldTransform
Windows NT
Yes
Win95
No
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


SHAddToRecentDocs
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


SHAppBarMessage
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shellapi.h
Unicode
Platform Notes
None


SHBrowseForFolder
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


SHChangeNotify
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


Shell_NotifyIcon
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shellapi.h
Unicode
Platform Notes
None


ShellAbout
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
shell32.lib
Header File
shellapi.h
Unicode
WinNT
Platform Notes
None


ShellExecute
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
shell32.lib
Header File
shellapi.h
Unicode
WinNT
Platform Notes
None


ShellExecuteEx
Windows NT
Win95
Yes
Win32s
Import Library
Header File
shellapi.h
Unicode
Platform Notes
None


SHFileOperation
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


SHFreeNameMappings
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


SHGetDesktopFolder
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


SHGetFileInfo
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


SHGetInstanceExplorer
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


SHGetMalloc
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


SHGetPathFromIDList
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


SHGetSpecialFolderLocation
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


SHLoadInProc
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


short_array_from_ndr
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcndr.h
Unicode
Platform Notes
None


short_from_ndr
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcndr.h
Unicode
Platform Notes
None


short_from_ndr_temp
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcndr.h
Unicode
Platform Notes
None


ShowCaret
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


ShowCursor
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


ShowHideMenuCtl
Windows NT
Yes
Win95
Yes
Win32s
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


ShowOwnedPopups
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


ShowScrollBar
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


ShowWindow
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


ShowWindowAsync
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


shutdown
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


SizeofResource
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


Sleep
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


SleepEx
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


sndPlaySound
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
WinNT
Platform Notes
None


socket
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


StartDoc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
WinNT
Platform Notes
Windows 95: int == 16 bits


StartDocPrinter
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
WinNT
Platform Notes
None


StartPage
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


StartPagePrinter
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
No
Platform Notes
None


StartService
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winsvc.h
Unicode
WinNT
Platform Notes
None


StartServiceCtrlDispatcher
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winsvc.h
Unicode
WinNT
Platform Notes
None


StgCreateDocfile
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


StgCreateDocfileOnILockBytes
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


StgIsStorageFile
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


StgIsStorageILockBytes
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


StgOpenStorage
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


StgOpenStorageOnILockBytes
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
No
Platform Notes
None


StgSetTimes
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


StretchBlt
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


StretchDIBits
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


StringFromCLSID
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


StringFromGUID2
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


StringFromIID
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
objbase.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


StrokeAndFillPath
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


StrokePath
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


SubtractRect
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


SuspendThread
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


SwapBuffers
Windows NT
Yes
Win95
No
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


SwapMouseButton
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


SwitchDesktop
Windows NT
Yes
Win95
No
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


SysAllocString
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


SysAllocStringByteLen
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


SysAllocStringLen
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


SysFreeString
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


SysReAllocString
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


SysReAllocStringLen
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


SysStringByteLen
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


SysStringLen
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


SystemParametersInfo
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


SystemTimeToFileTime
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


SystemTimeToTzSpecificLocalTime
Windows NT
New
Win95
No
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


TabbedTextOut
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


TerminateProcess
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


TerminateThread
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


TextOut
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
WinNT; Win95
Platform Notes
Windows 95: 16-bit coordinates only


TileWindows
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


timeBeginPeriod
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


timeEndPeriod
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


timeGetDevCaps
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


timeGetSystemTime
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


timeGetTime
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


timeKillEvent
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


timeSetEvent
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


TlsAlloc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


TlsFree
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


TlsGetValue
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


TlsSetValue
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


ToAscii
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


ToAsciiEx
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


ToUnicode
Windows NT
Yes
Win95
No
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


TrackPopupMenu
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


TrackPopupMenuEx
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


TransactNamedPipe
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


TranslateAccelerator
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


TranslateCharsetInfo
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
wingdi.h
Unicode
No
Platform Notes
None


TranslateMDISysAccel
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


TranslateMessage
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


TransmitCommChar
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


TransmitFile
Windows NT
Yes
Win95
No
Win32s
No
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


tree_into_ndr
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcndr.h
Unicode
Platform Notes
None


tree_peek_ndr
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcndr.h
Unicode
Platform Notes
None


tree_size_ndr
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcndr.h
Unicode
Platform Notes
None


UInt32x32To64
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
winnt.h
Unicode
No
Platform Notes
None


UnhandledExceptionFilter
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


UnhookWindowsHook
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


UnhookWindowsHookEx
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


UnionRect
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


UnloadKeyboardLayout
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


UnlockFile
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


UnlockFileEx
Windows NT
Yes
Win95
No
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


UnlockResource
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winbase.h
Unicode
No
Platform Notes
None


UnlockSegment
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winbase.h
Unicode
No
Platform Notes
None


UnlockServiceDatabase
Windows NT
Yes
Win95
No
Win32s
No
Import Library
advapi32.lib
Header File
winsvc.h
Unicode
No
Platform Notes
None


UnmapViewOfFile
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


UnpackDDElParam
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
dde.h
Unicode
No
Platform Notes
None


UnrealizeObject
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


UnregisterClass
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


UnregisterHotKey
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


UpdateColors
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: int == 16 bits


UpdateResource
Windows NT
Yes
Win95
No
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


UpdateWindow
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


UuidCompare
Windows NT
New
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
No
Platform Notes
None


UuidCreate
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
No
Platform Notes
None


UuidCreateNil
Windows NT
New
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
No
Platform Notes
None


UuidEqual
Windows NT
New
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
No
Platform Notes
None


UuidFromString
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
WinNT
Platform Notes
None


UuidHash
Windows NT
New
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
No
Platform Notes
None


UuidIsNil
Windows NT
New
Win95
Yes
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
No
Platform Notes
None


UuidToString
Windows NT
Yes
Win95
No
Win32s
No
Import Library
rpcrt4.lib
Header File
rpcdce.h
Unicode
WinNT
Platform Notes
None


ValidateRect
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


ValidateRgn
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


VarBoolFromCy
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarBoolFromDate
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarBoolFromDisp
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarBoolFromI2
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarBoolFromI4
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarBoolFromR4
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarBoolFromR8
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarBoolFromStr
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


VarBoolFromUI1
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarBstrFromBool
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


VarBstrFromCy
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


VarBstrFromDate
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


VarBstrFromDisp
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


VarBstrFromI2
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


VarBstrFromI4
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


VarBstrFromR4
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


VarBstrFromR8
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


VarBstrFromUI1
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


VarCyFromBool
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarCyFromDate
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarCyFromDisp
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarCyFromI2
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarCyFromI4
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarCyFromR4
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarCyFromR8
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarCyFromStr
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


VarCyFromUI1
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarDateFromBool
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarDateFromCy
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarDateFromDisp
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarDateFromI2
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarDateFromI4
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarDateFromR4
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarDateFromR8
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarDateFromStr
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


VarDateFromUI1
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarI2FromBool
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarI2FromCy
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarI2FromDate
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarI2FromDisp
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarI2FromI4
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarI2FromR4
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarI2FromR8
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarI2FromStr
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


VarI2FromUI1
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarI4FromBool
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarI4FromCy
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarI4FromDate
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarI4FromDisp
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarI4FromI2
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarI4FromR4
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarI4FromR8
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarI4FromStr
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


VarI4FromUI1
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VariantChangeType
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VariantChangeTypeEx
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VariantClear
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VariantCopy
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VariantCopyInd
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VariantInit
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VariantTimeToDosDateTime
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarR4FromBool
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarR4FromCy
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarR4FromDate
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarR4FromDisp
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarR4FromI2
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarR4FromI4
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarR4FromR8
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarR4FromStr
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


VarR4FromUI1
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarR8FromBool
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarR8FromCy
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarR8FromDate
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarR8FromDisp
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarR8FromI2
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarR8FromI4
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarR8FromR4
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarR8FromStr
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarR8FromUI1
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarUI1FromBool
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarUI1FromCy
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarUI1FromDate
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarUI1FromDisp
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarUI1FromI2
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarUI1FromI4
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarUI1FromR4
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarUI1FromR8
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
No
Platform Notes
None


VarUI1FromStr
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
oleaut32.lib
Header File
oleauto.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


VerFindFile
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
version.lib
Header File
winver.h
Unicode
WinNT
Platform Notes
None


VerInstallFile
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
version.lib
Header File
winver.h
Unicode
WinNT
Platform Notes
None


VerLanguageName
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winver.h
Unicode
WinNT
Platform Notes
None


VerQueryValue
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
version.lib
Header File
winver.h
Unicode
WinNT
Platform Notes
None


VideoForWindowsVersion
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
vfw32.lib
Header File
vfw.h
Unicode
No
Platform Notes
None


VirtualAlloc
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


VirtualFree
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


VirtualLock
Windows NT
Yes
Win95
Stub
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


VirtualProtect
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


VirtualProtectEx
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


VirtualQuery
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


VirtualQueryEx
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


VirtualUnlock
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


VkKeyScan
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


VkKeyScanEx
Windows NT
Stub
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


WaitCommEvent
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


WaitForDebugEvent
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


WaitForInputIdle
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


WaitForMultipleObjects
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


WaitForMultipleObjectsEx
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


WaitForPrinterChange
Windows NT
Yes
Win95
No
Win32s
No
Import Library
winspool.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


WaitForSingleObject
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


WaitForSingleObjectEx
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


WaitMessage
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


WaitNamedPipe
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


waveInAddBuffer
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


waveInClose
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


waveInGetDevCaps
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
WinNT
Platform Notes
None


waveInGetErrorText
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
WinNT
Platform Notes
None


waveInGetID
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


waveInGetNumDevs
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


waveInGetPosition
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


waveInMessage
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


waveInOpen
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


waveInPrepareHeader
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


waveInReset
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


waveInStart
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


waveInStop
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


waveInUnprepareHeader
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


waveOutBreakLoop
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


waveOutClose
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


waveOutGetDevCaps
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
WinNT
Platform Notes
None


waveOutGetErrorText
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
WinNT
Platform Notes
None


waveOutGetID
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


waveOutGetNumDevs
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


waveOutGetPitch
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


waveOutGetPlaybackRate
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


waveOutGetPosition
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


waveOutGetVolume
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


waveOutMessage
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


waveOutOpen
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


waveOutPause
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


waveOutPrepareHeader
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


waveOutReset
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


waveOutRestart
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


waveOutSetPitch
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


waveOutSetPlaybackRate
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


waveOutSetVolume
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


waveOutUnprepareHeader
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


waveOutWrite
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
winmm.lib
Header File
mmsystem.h
Unicode
No
Platform Notes
None


wglCreateContext
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


wglDeleteContext
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


wglGetCurrentContext
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


wglGetCurrentDC
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


wglGetProcAddress
Windows NT
New
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


wglMakeCurrent
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
None


wglShareLists
Windows NT
New
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
wingdi.h
Unicode
Platform Notes
None


wglUseFontBitmaps
Windows NT
Yes
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
wingdi.h
Unicode
WinNT
Platform Notes
None


wglUseFontOutlines
Windows NT
New
Win95
No
Win32s
No
Import Library
opengl32.lib
Header File
wingdi.h
Unicode
WinNT
Platform Notes
None


WideCharToMultiByte
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winnls.h
Unicode
No
Platform Notes
None


WidenPath
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
gdi32.lib
Header File
wingdi.h
Unicode
No
Platform Notes
Windows 95: 16-bit coordinates only


WindowFromDC
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


WindowFromPoint
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
No
Platform Notes
None


WinExec
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


WinHelp
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


WinMain
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winbase.h
Unicode
No
Platform Notes
None


WNetAddConnection
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
mpr.lib
Header File
winnetwk.h
Unicode
WinNT
Platform Notes
None


WNetAddConnection2
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
mpr.lib
Header File
winnetwk.h
Unicode
WinNT
Platform Notes
None


WNetAddConnection3
Windows NT
Yes
Win95
Win32s
No
Import Library
mpr.lib
Header File
winnetwk.h
Unicode
WinNT
Platform Notes
None


WNetCancelConnection
Windows NT
Yes
Win95
Yes
Win32s
1.30 only
Import Library
mpr.lib
Header File
winnetwk.h
Unicode
WinNT
Platform Notes
None


WNetCancelConnection2
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
mpr.lib
Header File
winnetwk.h
Unicode
WinNT
Platform Notes
None


WNetCloseEnum
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
mpr.lib
Header File
winnetwk.h
Unicode
No
Platform Notes
None


WNetConnectionDialog
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
mpr.lib
Header File
winnetwk.h
Unicode
No
Platform Notes
None


WNetDisconnectDialog
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
mpr.lib
Header File
winnetwk.h
Unicode
No
Platform Notes
None


WNetEnumResource
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
mpr.lib
Header File
winnetwk.h
Unicode
WinNT
Platform Notes
None


WNetGetConnection
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
mpr.lib
Header File
winnetwk.h
Unicode
WinNT
Platform Notes
None


WNetGetLastError
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
mpr.lib
Header File
winnetwk.h
Unicode
WinNT
Platform Notes
None


WNetGetUniversalName
Windows NT
Yes
Win95
Win32s
No
Import Library
mpr.lib
Header File
winnetwk.h
Unicode
WinNT
Platform Notes
None


WNetGetUser
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
mpr.lib
Header File
winnetwk.h
Unicode
WinNT
Platform Notes
None


WNetOpenEnum
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
mpr.lib
Header File
winnetwk.h
Unicode
WinNT
Platform Notes
None


WriteClassStg
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


WriteClassStm
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
No
Platform Notes
None


WriteConsole
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
wincon.h
Unicode
WinNT
Platform Notes
None


WriteConsoleInput
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
wincon.h
Unicode
WinNT
Platform Notes
None


WriteConsoleOutput
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
wincon.h
Unicode
WinNT
Platform Notes
None


WriteConsoleOutputAttribute
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
wincon.h
Unicode
No
Platform Notes
None


WriteConsoleOutputCharacter
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
wincon.h
Unicode
WinNT
Platform Notes
None


WriteFile
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
New
Platform Notes
Windows 95: No overlapped regions


WriteFileEx
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
Windows 95 limitations


WriteFmtUserTypeStg
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
ole32.lib
Header File
ole2.h
Unicode
WinNT; Win95; Win32s
Platform Notes
All 32-bit OLE Apis are UNICODE only


WritePrinter
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
winspool.lib
Header File
winspool.h
Unicode
No
Platform Notes
None


WritePrivateProfileSection
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


WritePrivateProfileString
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


WritePrivateProfileStruct
Windows NT
Yes
Win95
Yes
Win32s
Import Library
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


WriteProcessMemory
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


WriteProfileSection
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


WriteProfileString
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
kernel32.lib
Header File
winbase.h
Unicode
WinNT
Platform Notes
None


WriteTapemark
Windows NT
Yes
Win95
No
Win32s
No
Import Library
kernel32.lib
Header File
winbase.h
Unicode
No
Platform Notes
None


WSAAsyncGetHostByAddr
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


WSAAsyncGetHostByName
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


WSAAsyncGetProtoByName
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


WSAAsyncGetProtoByNumber
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


WSAAsyncGetServByName
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


WSAAsyncGetServByPort
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


WSAAsyncSelect
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


WSACancelAsyncRequest
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


WSACancelBlockingCall
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


WSACleanup
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


WSAGetLastError
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


WSAIsBlocking
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


WSARecvEx
Windows NT
Yes
Win95
Win32s
No
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


WSASetBlockingHook
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


WSASetLastError
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


WSAStartup
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


WSAUnhookBlockingHook
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
wsock32.lib
Header File
winsock.h
Unicode
No
Platform Notes
None


wsprintf
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


wvsprintf
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
user32.lib
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


ZeroMemory
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winbase.h
Unicode
No
Platform Notes
None


IAVIEditStream::Clone
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h; aviiface.h
Unicode
Platform Notes
None


IAVIEditStream::Copy
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h; aviiface.h
Unicode
Platform Notes
None


IAVIEditStream::Cut
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h; aviiface.h
Unicode
Platform Notes
None


IAVIEditStream::Paste
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h; aviiface.h
Unicode
Platform Notes
None


IAVIEditStream::SetInfo
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h; aviiface.h
Unicode
Platform Notes
None


IAVIFile::CreateStream
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h; aviiface.h
Unicode
Platform Notes
None


IAVIFile::EndRecord
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h; aviiface.h
Unicode
Platform Notes
None


IAVIFile::GetStream
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h; aviiface.h
Unicode
Platform Notes
None


IAVIFile::Info
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h; aviiface.h
Unicode
Platform Notes
None


IAVIFile::Open
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h; aviiface.h
Unicode
Platform Notes
None


IAVIFile::ReadData
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h; aviiface.h
Unicode
Platform Notes
None


IAVIFile::WriteData
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h; aviiface.h
Unicode
Platform Notes
None


IAVIStream::Create
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h; aviiface.h
Unicode
Platform Notes
None


IAVIStream::Delete
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h; aviiface.h
Unicode
Platform Notes
None


IAVIStream::FindSample
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h; aviiface.h
Unicode
Platform Notes
None


IAVIStream::Info
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h; aviiface.h
Unicode
Platform Notes
None


IAVIStream::Read
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h; aviiface.h
Unicode
Platform Notes
None


IAVIStream::ReadData
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h; aviiface.h
Unicode
Platform Notes
None


IAVIStream::ReadFormat
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h; aviiface.h
Unicode
Platform Notes
None


IAVIStream::SetFormat
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h; aviiface.h
Unicode
Platform Notes
None


IAVIStream::Write
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h; aviiface.h
Unicode
Platform Notes
None


IAVIStream::WriteData
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h; aviiface.h
Unicode
Platform Notes
None


IAVIStreaming::Begin
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h; aviiface.h
Unicode
Platform Notes
None


IAVIStreaming::End
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h; aviiface.h
Unicode
Platform Notes
None


IContextMenu::GetCommandString
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


IContextMenu::InvokeCommand
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


IContextMenu::QueryContextMenu
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


ICopyHook::CopyCallback
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


IEnumIDList::Clone
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


IEnumIDList::Next
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


IEnumIDList::Reset
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


IEnumIDList::Skip
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


IExtractIcon::Extract
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


IExtractIcon::GetIconLocation
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


IFileViewer::PrintTo
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


IFileViewer::Show
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


IFileViewer::ShowInitialize
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


IFileViewerSite::GetPinnedWindow
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


IFileViewerSite::SetPinnedWindow
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


IGetFrame::Begin
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h
Unicode
Platform Notes
None


IGetFrame::End
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h
Unicode
Platform Notes
None


IGetFrame::GetFrame
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h
Unicode
Platform Notes
None


IGetFrame::SetFormat
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h
Unicode
Platform Notes
None


IShellExtInit::Initialize
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


IShellFolder::BindToObject
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


IShellFolder::BindToStorage
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


IShellFolder::CompareIDs
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


IShellFolder::CreateViewObject
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


IShellFolder::EnumObjects
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


IShellFolder::GetAttributesOf
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


IShellFolder::GetDisplayNameOf
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


IShellFolder::GetUIObjectOf
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


IShellFolder::ParseDisplayName
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


IShellFolder::SetNameOf
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


IShellLink::GetArguments
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


IShellLink::GetDescription
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


IShellLink::GetHotkey
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


IShellLink::GetIconLocation
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


IShellLink::GetIDList
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


IShellLink::GetPath
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


IShellLink::GetShowCmd
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


IShellLink::GetWorkingDirectory
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


IShellLink::Resolve
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


IShellLink::SetArguments
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


IShellLink::SetDescription
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


IShellLink::SetHotkey
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


IShellLink::SetIconLocation
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


IShellLink::SetIDList
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


IShellLink::SetPath
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


IShellLink::SetRelativePath
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


IShellLink::SetShowCmd
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


IShellLink::SetWorkingDirectory
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


IShellPropSheetExt::AddPages
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


IShellPropSheetExt::ReplacePage
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


Animate_Close
Windows NT
Yes
Win95
Yes
Win32s
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


Animate_Create
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


Animate_Open
Windows NT
Yes
Win95
Yes
Win32s
Import Library
Header File
commctrl.h
Unicode
WinNT
Platform Notes
None


Animate_Play
Windows NT
Yes
Win95
Yes
Win32s
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


Animate_Seek
Windows NT
Yes
Win95
Yes
Win32s
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


Animate_Stop
Windows NT
Yes
Win95
Yes
Win32s
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


AVIStreamDataSize
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h
Unicode
Platform Notes
None


AVIStreamEnd
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h
Unicode
Platform Notes
None


AVIStreamEndTime
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h
Unicode
Platform Notes
None


AVIStreamFormatSize
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h
Unicode
Platform Notes
None


AVIStreamIsKeyFrame
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h
Unicode
Platform Notes
None


AVIStreamLengthTime
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h
Unicode
Platform Notes
None


AVIStreamNearestKeyFrame
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h
Unicode
Platform Notes
None


AVIStreamNearestKeyFrameTime
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h
Unicode
Platform Notes
None


AVIStreamNearestSample
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h
Unicode
Platform Notes
None


AVIStreamNearestSampleTime
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h
Unicode
Platform Notes
None


AVIStreamNextKeyFrame
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h
Unicode
Platform Notes
None


AVIStreamNextKeyFrameTime
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h
Unicode
Platform Notes
None


AVIStreamNextSample
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h
Unicode
Platform Notes
None


AVIStreamNextSampleTime
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h
Unicode
Platform Notes
None


AVIStreamPrevKeyFrame
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h
Unicode
Platform Notes
None


AVIStreamPrevKeyFrameTime
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h
Unicode
Platform Notes
None


AVIStreamPrevSample
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h
Unicode
Platform Notes
None


AVIStreamPrevSampleTime
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h
Unicode
Platform Notes
None


AVIStreamSampleSize
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h
Unicode
Platform Notes
None


AVIStreamSampleToSample
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h
Unicode
Platform Notes
None


AVIStreamStartTime
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h
Unicode
Platform Notes
None


CMYK
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
wingdi.h
Unicode
No
Platform Notes
None


DrawDibUpdate
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
vfw.h
Unicode
No
Platform Notes
None


FORWARD_WM_NOTIFY
Windows NT
Yes
Win95
Yes
Win32s
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


GetBValue
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
wingdi.h
Unicode
No
Platform Notes
None


GetCValue
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
wingdi.h
Unicode
No
Platform Notes
None


GetGValue
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
wingdi.h
Unicode
No
Platform Notes
None


GetKValue
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
wingdi.h
Unicode
No
Platform Notes
None


GetMValue
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
wingdi.h
Unicode
No
Platform Notes
None


GetRValue
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
wingdi.h
Unicode
No
Platform Notes
None


GetYValue
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
wingdi.h
Unicode
No
Platform Notes
None


HANDLE_WM_NOTIFY
Windows NT
Yes
Win95
Yes
Win32s
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


HIBYTE
Windows NT
Yes
Win95
Yes
Win32s
Import Library
Header File
windef.h
Unicode
No
Platform Notes
None


HIWORD
Windows NT
Yes
Win95
Yes
Win32s
Import Library
Header File
windef.h
Unicode
No
Platform Notes
None


ICAbout
Windows NT
New
Win95
Yes
Win32s
No
Import Library
Header File
vfw.h
Unicode
No
Platform Notes
None


ICCompressBegin
Windows NT
New
Win95
Yes
Win32s
No
Import Library
Header File
vfw.h
Unicode
No
Platform Notes
None


ICCompressEnd
Windows NT
New
Win95
Yes
Win32s
No
Import Library
Header File
vfw.h
Unicode
No
Platform Notes
None


ICCompressGetFormat
Windows NT
New
Win95
Yes
Win32s
No
Import Library
Header File
vfw.h
Unicode
No
Platform Notes
None


ICCompressGetFormatSize
Windows NT
New
Win95
Yes
Win32s
No
Import Library
Header File
vfw.h
Unicode
No
Platform Notes
None


ICCompressGetSize
Windows NT
New
Win95
Yes
Win32s
No
Import Library
Header File
vfw.h
Unicode
No
Platform Notes
None


ICCompressQuery
Windows NT
New
Win95
Yes
Win32s
No
Import Library
Header File
vfw.h
Unicode
No
Platform Notes
None


ICConfigure
Windows NT
New
Win95
Yes
Win32s
No
Import Library
Header File
vfw.h
Unicode
No
Platform Notes
None


ICDecompressBegin
Windows NT
New
Win95
Yes
Win32s
No
Import Library
Header File
vfw.h
Unicode
No
Platform Notes
None


ICDecompressEnd
Windows NT
New
Win95
Yes
Win32s
No
Import Library
Header File
vfw.h
Unicode
No
Platform Notes
None


ICDecompressGetFormat
Windows NT
New
Win95
Yes
Win32s
No
Import Library
Header File
vfw.h
Unicode
No
Platform Notes
None


ICDecompressGetFormatSize
Windows NT
New
Win95
Yes
Win32s
No
Import Library
Header File
vfw.h
Unicode
No
Platform Notes
None


ICDecompressGetPalette
Windows NT
New
Win95
Yes
Win32s
No
Import Library
Header File
vfw.h
Unicode
No
Platform Notes
None


ICDecompressOpen
Windows NT
New
Win95
Yes
Win32s
No
Import Library
Header File
vfw.h
Unicode
No
Platform Notes
None


ICDecompressQuery
Windows NT
New
Win95
Yes
Win32s
No
Import Library
Header File
vfw.h
Unicode
No
Platform Notes
None


ICDrawEnd
Windows NT
New
Win95
Yes
Win32s
No
Import Library
Header File
vfw.h
Unicode
No
Platform Notes
None


ICDrawFlush
Windows NT
New
Win95
Yes
Win32s
No
Import Library
Header File
vfw.h
Unicode
No
Platform Notes
None


ICDrawGetTime
Windows NT
New
Win95
Yes
Win32s
No
Import Library
Header File
vfw.h
Unicode
No
Platform Notes
None


ICDrawOpen
Windows NT
New
Win95
Yes
Win32s
No
Import Library
Header File
vfw.h
Unicode
No
Platform Notes
None


ICDrawQuery
Windows NT
New
Win95
Yes
Win32s
No
Import Library
Header File
vfw.h
Unicode
No
Platform Notes
None


ICDrawRealize
Windows NT
New
Win95
Yes
Win32s
No
Import Library
Header File
vfw.h
Unicode
No
Platform Notes
None


ICDrawSetTime
Windows NT
New
Win95
Yes
Win32s
No
Import Library
Header File
vfw.h
Unicode
No
Platform Notes
None


ICDrawStart
Windows NT
New
Win95
Yes
Win32s
No
Import Library
Header File
vfw.h
Unicode
No
Platform Notes
None


ICDrawStartPlay
Windows NT
New
Win95
Yes
Win32s
No
Import Library
Header File
vfw.h
Unicode
No
Platform Notes
None


ICDrawStop
Windows NT
New
Win95
Yes
Win32s
No
Import Library
Header File
vfw.h
Unicode
No
Platform Notes
None


ICDrawStopPlay
Windows NT
New
Win95
Yes
Win32s
No
Import Library
Header File
vfw.h
Unicode
No
Platform Notes
None


ICDrawWindow
Windows NT
New
Win95
Yes
Win32s
No
Import Library
Header File
vfw.h
Unicode
No
Platform Notes
None


ICGetBuffersWanted
Windows NT
New
Win95
Yes
Win32s
No
Import Library
Header File
vfw.h
Unicode
No
Platform Notes
None


ICGetDefaultKeyFrameRate
Windows NT
New
Win95
Yes
Win32s
No
Import Library
Header File
vfw.h
Unicode
No
Platform Notes
None


ICGetDefaultQuality
Windows NT
New
Win95
Yes
Win32s
No
Import Library
Header File
vfw.h
Unicode
No
Platform Notes
None


ICGetState
Windows NT
New
Win95
Yes
Win32s
No
Import Library
Header File
vfw.h
Unicode
No
Platform Notes
None


ICGetStateSize
Windows NT
New
Win95
Yes
Win32s
No
Import Library
Header File
vfw.h
Unicode
No
Platform Notes
None


ICQueryAbout
Windows NT
New
Win95
Yes
Win32s
No
Import Library
Header File
vfw.h
Unicode
No
Platform Notes
None


ICQueryConfigure
Windows NT
New
Win95
Yes
Win32s
No
Import Library
Header File
vfw.h
Unicode
No
Platform Notes
None


ImageList_AddIcon
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


INDEXTOOVERLAYMASK
Windows NT
New
Win95
Yes
Win32s
No
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


INDEXTOSTATEIMAGEMASK
Windows NT
New
Win95
Yes
Win32s
No
Import Library
Header File
commctrl.h
Unicode
No
Platform Notes
None


LANGIDFROMLCID
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winnt.h
Unicode
No
Platform Notes
None


LOBYTE
Windows NT
Yes
Win95
Yes
Win32s
Import Library
Header File
windef.h
Unicode
No
Platform Notes
None


LOWORD
Windows NT
Yes
Win95
Yes
Win32s
Import Library
Header File
windef.h
Unicode
No
Platform Notes
None


MAKEINTATOM
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winbase.h
Unicode
No
Platform Notes
None


MAKEINTRESOURCE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
WinNT
Platform Notes
None


MAKELANGID
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winnt.h
Unicode
No
Platform Notes
None


MAKELCID
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winnt.h
Unicode
No
Platform Notes
None


MAKELONG
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
windef.h
Unicode
No
Platform Notes
None


MAKELPARAM
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


MAKELRESULT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


MAKEPOINTS
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
wingdi.h
Unicode
No
Platform Notes
None


MAKEROP4
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
wingdi.h
Unicode
No
Platform Notes
None


MAKEWORD
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
windef.h
Unicode
No
Platform Notes
None


MAKEWPARAM
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


max
Windows NT
Yes
Win95
Yes
Win32s
Import Library
Header File
windef.h
Unicode
No
Platform Notes
None


MCI_HMS_HOUR
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MCI_HMS_MINUTE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MCI_HMS_SECOND
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MCI_MAKE_HMS
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MCI_MAKE_MSF
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MCI_MAKE_TMSF
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MCI_MSF_FRAME
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MCI_MSF_MINUTE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MCI_MSF_SECOND
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MCI_TMSF_FRAME
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MCI_TMSF_MINUTE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MCI_TMSF_SECOND
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MCI_TMSF_TRACK
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MCIWndCanConfig
Windows NT
Win95
Yes
Win32s
Import Library
Header File
vfw.h
Unicode
Platform Notes
None


MCIWndCanEject
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndCanPlay
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndCanRecord
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndCanSave
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndCanWindow
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndChangeStyles
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndClose
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndDestroy
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndEject
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndEnd
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndGetActiveTimer
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndGetAlias
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndGetDest
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndGetDevice
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndGetDeviceID
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndGetEnd
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndGetError
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndGetFileName
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndGetInactiveTimer
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndGetLength
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndGetMode
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndGetPalette
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndGetPosition
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndGetPositionString
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndGetRepeat
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndGetSource
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndGetSpeed
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndGetStart
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndGetStyles
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndGetTimeFormat
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndGetVolume
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndGetZoom
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndHome
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndNew
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndOpen
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndOpenDialog
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndOpenInterface
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndPause
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndPlay
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndPlayFrom
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndPlayFromTo
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndPlayReverse
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndPlayTo
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndPutDest
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndPutSource
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndRealize
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndRecord
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndResume
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndReturnString
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndSave
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndSaveDialog
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndSeek
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndSendString
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndSetActiveTimer
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndSetInactiveTimer
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndSetOwner
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndSetPalette
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndSetRepeat
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndSetSpeed
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndSetTimeFormat
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndSetTimers
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndSetVolume
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndSetZoom
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndStep
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndStop
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndUseFrames
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndUseTime
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWndValidateMedia
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MEVT_EVENTPARM
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
Unicode
Platform Notes
None


MEVT_EVENTTYPE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
Unicode
Platform Notes
None


min
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
Unicode
Platform Notes
None


mmioFOURCC
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


PALETTEINDEX
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
wingdi.h
Unicode
No
Platform Notes
None


PALETTERGB
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
wingdi.h
Unicode
No
Platform Notes
None


POINTSTOPOINT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


POINTTOPOINTS
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


PRIMARYLANGID
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winnt.h
Unicode
No
Platform Notes
None


RGB
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
wingdi.h
Unicode
No
Platform Notes
None


SHGetNameMappingCount
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


SHGetNameMappingPtr
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


SORTIDFROMLCID
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winnt.h
Unicode
No
Platform Notes
None


SUBLANGID
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winnt.h
Unicode
No
Platform Notes
None


TEXT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
Unicode
Platform Notes
None


ABM_ACTIVATE
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shellapi.h
Unicode
Platform Notes
None


ABM_GETAUTOHIDEBAR
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shellapi.h
Unicode
Platform Notes
None


ABM_GETSTATE
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shellapi.h
Unicode
Platform Notes
None


ABM_GETTASKBARPOS
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shellapi.h
Unicode
Platform Notes
None


ABM_NEW
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shellapi.h
Unicode
Platform Notes
None


ABM_QUERYPOS
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shellapi.h
Unicode
Platform Notes
None


ABM_REMOVE
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shellapi.h
Unicode
Platform Notes
None


ABM_SETAUTOHIDEBAR
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shellapi.h
Unicode
Platform Notes
None


ABM_SETPOS
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shellapi.h
Unicode
Platform Notes
None


ABM_WINDOWPOSCHANGED
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shellapi.h
Unicode
Platform Notes
None


ABN_FULLSCREENAPP
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shellapi.h
Unicode
Platform Notes
None


ABN_POSCHANGED
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shellapi.h
Unicode
Platform Notes
None


ABN_STATECHANGE
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shellapi.h
Unicode
Platform Notes
None


ABN_WINDOWARRANGE
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shellapi.h
Unicode
Platform Notes
None


ACM_OPEN
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ACM_PLAY
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ACM_STOP
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ACN_START
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ACN_STOP
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


BM_CLICK
Windows NT
Yes
Win95
Yes
Win32s
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


BM_GETCHECK
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


BM_GETSTATE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


BM_SETCHECK
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


BM_SETSTATE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


BM_SETSTYLE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


BN_CLICKED
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


BN_DBLCLK
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


BN_DISABLE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


BN_DOUBLECLICKED
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


BN_HILITE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


BN_KILLFOCUS
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


BN_PAINT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


BN_PUSHED
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


BN_SETFOCUS
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


BN_UNHILITE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


BN_UNPUSHED
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CB_ADDSTRING
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CB_DELETESTRING
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CB_DIR
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CB_FINDSTRING
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CB_FINDSTRINGEXACT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CB_GETCOUNT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CB_GETCURSEL
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CB_GETDROPPEDCONTROLRECT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CB_GETDROPPEDSTATE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CB_GETDROPPEDWIDTH
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CB_GETEDITSEL
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CB_GETEXTENDEDUI
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CB_GETHORIZONTALEXTENT
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CB_GETITEMDATA
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CB_GETITEMHEIGHT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CB_GETLBTEXT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CB_GETLBTEXTLEN
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CB_GETLOCALE
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CB_GETTOPINDEX
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CB_INITSTORAGE
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CB_INSERTSTRING
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CB_LIMITTEXT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CB_MSGMAX
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CB_RESETCONTENT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CB_SELECTSTRING
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CB_SETCURSEL
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CB_SETDROPPEDWIDTH
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CB_SETEDITSEL
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CB_SETEXTENDEDUI
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CB_SETHORIZONTALEXTENT
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CB_SETITEMDATA
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CB_SETITEMHEIGHT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CB_SETLOCALE
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CB_SETTOPINDEX
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CB_SHOWDROPDOWN
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CBN_CLOSEUP
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CBN_DBLCLK
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CBN_DROPDOWN
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CBN_EDITCHANGE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CBN_EDITUPDATE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CBN_ERRSPACE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CBN_KILLFOCUS
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CBN_SELCHANGE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CBN_SELENDCANCEL
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CBN_SELENDOK
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CBN_SETFOCUS
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


CPL_DBLCLK
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
cpl.h
Unicode
No
Platform Notes
None


CPL_EXIT
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
cpl.h
Unicode
No
Platform Notes
None


CPL_GETCOUNT
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
cpl.h
Unicode
No
Platform Notes
None


CPL_INIT
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
cpl.h
Unicode
No
Platform Notes
None


CPL_INQUIRE
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
cpl.h
Unicode
No
Platform Notes
None


CPL_NEWINQUIRE
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
cpl.h
Unicode
No
Platform Notes
None


CPL_SELECT
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
cpl.h
Unicode
No
Platform Notes
None


CPL_STOP
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
cpl.h
Unicode
No
Platform Notes
None


DBT_APPYBEGIN
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
dbt.h
Unicode
Platform Notes
None


DBT_APPYEND
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
dbt.h
Unicode
Platform Notes
None


DBT_CONFIGCHANGECANCELED
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
dbt.h
Unicode
Platform Notes
None


DBT_CONFIGCHANGED
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
dbt.h
Unicode
Platform Notes
None


DBT_CONFIGMGAPI32
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
dbt.h
Unicode
Platform Notes
None


DBT_CONFIGMGPRIVATE
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
dbt.h
Unicode
Platform Notes
None


DBT_DEVICEARRIVAL
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
dbt.h
Unicode
Platform Notes
None


DBT_DEVICEQUERYREMOVE
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
dbt.h
Unicode
Platform Notes
None


DBT_DEVICEQUERYREMOVEFAILED
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
dbt.h
Unicode
Platform Notes
None


DBT_DEVICEREMOVECOMPLETE
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
dbt.h
Unicode
Platform Notes
None


DBT_DEVICEREMOVEPENDING
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
dbt.h
Unicode
Platform Notes
None


DBT_DEVICETYPESPECIFIC
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
dbt.h
Unicode
Platform Notes
None


DBT_DEVNODES_CHANGED
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
dbt.h
Unicode
Platform Notes
None


DBT_DEVTYP_OEM
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
dbt.h
Unicode
Platform Notes
None


DBT_DEVTYP_PORT
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
dbt.h
Unicode
Platform Notes
None


DBT_DEVTYP_VOLUME
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
dbt.h
Unicode
Platform Notes
None


DBT_MONITORCHANGE
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
dbt.h
Unicode
Platform Notes
None


DBT_NO_DISK_SPACE
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
dbt.h
Unicode
Platform Notes
None


DBT_QUERYCHANGECONFIG
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
dbt.h
Unicode
Platform Notes
None


DBT_SHELLLOGGEDON
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
dbt.h
Unicode
Platform Notes
None


DBT_USERDEFINED
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
dbt.h
Unicode
Platform Notes
None


DBT_VOLLOCKLOCKFAILED
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
dbt.h
Unicode
Platform Notes
None


DBT_VOLLOCKLOCKRELEASED
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
dbt.h
Unicode
Platform Notes
None


DBT_VOLLOCKLOCKTAKEN
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
dbt.h
Unicode
Platform Notes
None


DBT_VOLLOCKQUERYLOCK
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
dbt.h
Unicode
Platform Notes
None


DBT_VOLLOCKQUERYUNLOCK
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
dbt.h
Unicode
Platform Notes
None


DBT_VOLLOCKUNLOCKFAILED
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
dbt.h
Unicode
Platform Notes
None


DL_BEGINDRAG
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
commctrl.h
Unicode
Platform Notes
None


DL_CANCELDRAG
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
commctrl.h
Unicode
Platform Notes
None


DL_COPYCURSOR
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
commctrl.h
Unicode
Platform Notes
None


DL_CURSORSET
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
commctrl.h
Unicode
Platform Notes
None


DL_DRAGGING
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
commctrl.h
Unicode
Platform Notes
None


DL_DROPPED
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
commctrl.h
Unicode
Platform Notes
None


DL_MOVECURSOR
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
commctrl.h
Unicode
Platform Notes
None


DL_STOPCURSOR
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
commctrl.h
Unicode
Platform Notes
None


DM_GETDEFID
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


DM_REPOSITION
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


DM_SETDEFID
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


DRV_CLOSE
Windows NT
Win95
Win32s
Import Library
Header File
mmsystem.h
Unicode
Platform Notes
None


DRV_CONFIGURE
Windows NT
Win95
Win32s
Import Library
Header File
mmsystem.h
Unicode
Platform Notes
None


DRV_DISABLE
Windows NT
Win95
Win32s
Import Library
Header File
mmsystem.h
Unicode
Platform Notes
None


DRV_ENABLE
Windows NT
Win95
Win32s
Import Library
Header File
mmsystem.h
Unicode
Platform Notes
None


DRV_EXITSESSION
Windows NT
Win95
Win32s
Import Library
Header File
mmsystem.h
Unicode
Platform Notes
None


DRV_FREE
Windows NT
Win95
Win32s
Import Library
Header File
mmsystem.h
Unicode
Platform Notes
None


DRV_INSTALL
Windows NT
Win95
Win32s
Import Library
Header File
mmsystem.h
Unicode
Platform Notes
None


DRV_LOAD
Windows NT
Win95
Win32s
Import Library
Header File
mmsystem.h
Unicode
Platform Notes
None


DRV_OPEN
Windows NT
Win95
Win32s
Import Library
Header File
mmsystem.h
Unicode
Platform Notes
None


DRV_POWER
Windows NT
Win95
Win32s
Import Library
Header File
mmsystem.h
Unicode
Platform Notes
None


DRV_QUERYCONFIGURE
Windows NT
Win95
Win32s
Import Library
Header File
mmsystem.h
Unicode
Platform Notes
None


DRV_REMOVE
Windows NT
Win95
Win32s
Import Library
Header File
mmsystem.h
Unicode
Platform Notes
None


EM_CANPASTE
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EM_CANUNDO
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


EM_CHARFROMPOS
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


EM_DISPLAYBAND
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EM_EMPTYUNDOBUFFER
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


EM_EXGETSEL
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EM_EXLIMITTEXT
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EM_EXLINEFROMCHAR
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EM_EXSETSEL
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EM_FINDTEXT
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EM_FINDTEXT_EX
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EM_FINDWORDBREAK
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EM_FMTLINES
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


EM_FORMATRANGE
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EM_GETCHARFORMAT
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EM_GETEVENTMASK
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EM_GETFIRSTVISIBLELINE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
For Single Line Edit controls Win32s returns 0


EM_GETHANDLE
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


EM_GETIMECOLOR
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EM_GETIMEOPTIONS
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EM_GETLIMITTEXT
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


EM_GETLINE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


EM_GETLINECOUNT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


EM_GETMARGINS
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


EM_GETMODIFY
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


EM_GETOLEINTERFACE
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EM_GETOPTIONS
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EM_GETOPTIONS
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EM_GETPARAFORMAT
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EM_GETPASSWORDCHAR
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


EM_GETPUNCTUATION
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EM_GETRECT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


EM_GETSEL
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


EM_GETSELTEXT
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EM_GETTEXTRANGE
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EM_GETTHUMB
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


EM_GETWORDBREAKPROC
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


EM_GETWORDBREAKPROCEX
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
No
Platform Notes
None


EM_GETWORDWRAPMODE
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EM_HIDESELECTION
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EM_LIMITTEXT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


EM_LINEFROMCHAR
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


EM_LINEINDEX
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


EM_LINELENGTH
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


EM_LINESCROLL
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


EM_PASTESPECIAL
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EM_POSFROMCHAR
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


EM_REPLACESEL
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


EM_REQUESTRESIZE
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EM_SCROLL
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


EM_SCROLLCARET
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


EM_SELECTIONTYPE
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EM_SETBKGNDCOLOR
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EM_SETCHARFORMAT
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EM_SETEVENTMASK
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EM_SETHANDLE
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


EM_SETIMECOLOR
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EM_SETIMEOPTIONS
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EM_SETLIMITTEXT
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


EM_SETMARGINS
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


EM_SETMODIFY
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


EM_SETOLECALLBACK
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EM_SETOLECALLBACK
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EM_SETOPTIONS
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EM_SETOPTIONS
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EM_SETPARAFORMAT
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EM_SETPASSWORDCHAR
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


EM_SETPUNCTUATION
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EM_SETREADONLY
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


EM_SETRECT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


EM_SETRECTNP
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


EM_SETSEL
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


EM_SETTABSTOPS
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


EM_SETTARGETDEVICE
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EM_SETWORDBREAK
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


EM_SETWORDBREAKPROC
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


EM_SETWORDBREAKPROCEX
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
No
Platform Notes
None


EM_SETWORDWRAPMODE
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EM_STREAMIN
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EM_STREAMOUT
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EM_UNDO
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


EN_CHANGE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


EN_DROPFILES
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EN_ERRSPACE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


EN_HSCROLL
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


EN_KILLFOCUS
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


EN_MAXTEXT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


EN_MSGFILTER
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EN_OLEOPFAILED
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EN_PROTECTED
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EN_REQUESTRESIZE
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EN_SAVECLIPBOARD
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EN_SELCHANGE
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EN_SETFOCUS
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


EN_STOPNOUNDO
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


EN_UPDATE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


EN_VSCROLL
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


FM_GETDRIVEINFO
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
wfext.h
Unicode
WinNT
Platform Notes
Windows 95: Only supports 16-bit FileManager


FM_GETFILESEL
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
wfext.h
Unicode
WinNT
Platform Notes
Windows 95: Only supports 16-bit FileManager


FM_GETFILESELLFN
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
wfext.h
Unicode
WinNT
Platform Notes
Windows 95: Only supports 16-bit FileManager


FM_GETFOCUS
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
wfext.h
Unicode
No
Platform Notes
Windows 95: Only supports 16-bit FileManager


FM_GETSELCOUNT
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
wfext.h
Unicode
No
Platform Notes
Windows 95: Only supports 16-bit FileManager


FM_GETSELCOUNTLFN
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
wfext.h
Unicode
No
Platform Notes
Windows 95: Only supports 16-bit FileManager


FM_REFRESH_WINDOWS
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
wfext.h
Unicode
No
Platform Notes
Windows 95: Only supports 16-bit FileManager


FM_RELOAD_EXTENSIONS
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
wfext.h
Unicode
No
Platform Notes
Windows 95: Only supports 16-bit FileManager


FMEVENT_HELPMENUITEM
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
wfext.h
Unicode
No
Platform Notes
Windows 95: Only supports 16-bit FileManager


FMEVENT_HELPSTRING
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
wfext.h
Unicode
No
Platform Notes
Windows 95: Only supports 16-bit FileManager


FMEVENT_INITMENU
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
wfext.h
Unicode
No
Platform Notes
Windows 95: Only supports 16-bit FileManager


FMEVENT_LOAD
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
wfext.h
Unicode
No
Platform Notes
Windows 95: Only supports 16-bit FileManager


FMEVENT_SELCHANGE
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
wfext.h
Unicode
No
Platform Notes
Windows 95: Only supports 16-bit FileManager


FMEVENT_TOOLBARLOAD
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
wfext.h
Unicode
No
Platform Notes
Windows 95: Only supports 16-bit FileManager


FMEVENT_UNLOAD
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
wfext.h
Unicode
No
Platform Notes
Windows 95: Only supports 16-bit FileManager


FMEVENT_USER_REFRESH
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
wfext.h
Unicode
No
Platform Notes
Windows 95: Only supports 16-bit FileManager


HDM_DELETEITEM
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


HDM_GETITEM
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


HDM_GETITEMCOUNT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


HDM_HITTEST
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


HDM_INSERTITEM
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


HDM_LAYOUT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


HDM_SETITEM
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


HDN_BEGINTRACK
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


HDN_DIVIDERDBLCLICK
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


HDN_ENDTRACK
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


HDN_ITEMCHANGED
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


HDN_ITEMCHANGING
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


HDN_ITEMCLICK
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


HDN_ITEMDBLCLICK
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


HDN_TRACK
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


HKM_GETHOTKEY
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


HKM_SETHOTKEY
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


HKM_SETRULES
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICM_ABOUT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICM_COMPRESS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICM_COMPRESS_BEGIN
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICM_COMPRESS_END
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICM_COMPRESS_FRAMES_INFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICM_COMPRESS_GET_FORMAT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICM_COMPRESS_GET_SIZE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICM_COMPRESS_QUERY
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICM_CONFIGURE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICM_DECOMPRESS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICM_DECOMPRESS_BEGIN
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICM_DECOMPRESS_END
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


IC
M_DECOMPRESS_GET_FORMAT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


IC
M_DECOMPRESS_GET_PALETTE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICM_DECOMPRESS_QUERY
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


IC
M_DECOMPRESS_SET_PALETTE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICM_DECOMPRESSEX
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICM_DECOMPRESSEX_BEGIN
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICM_DECOMPRESSEX_END
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICM_DECOMPRESSEX_QUERY
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICM_DRAW
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICM_DRAW_BEGIN
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICM_DRAW_CHANGEPALETTE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICM_DRAW_END
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICM_DRAW_FLUSH
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICM_DRAW_GET_PALETTE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICM_DRAW_GETTIME
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICM_DRAW_QUERY
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICM_DRAW_REALIZE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICM_DRAW_RENDERBUFFER
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICM_DRAW_SETTIME
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICM_DRAW_START
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICM_DRAW_START_PLAY
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICM_DRAW_STOP
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICM_DRAW_STOP_PLAY
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICM_DRAW_SUGGESTFORMAT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICM_DRAW_WINDOW
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICM_GET
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICM_GETBUFFERSWANTED
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


IC
M_GETDEFAULTKEYFRAMERATE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICM_GETDEFAULTQUALITY
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICM_GETINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICM_GETQUALITY
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICM_GETSTATE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICM_SET_STATUS_PROC
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICM_SETQUALITY
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICM_SETSTATE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


IMC_GETCANDIDATEPOS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


IMC_GETCOMPOSITIONFONT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


IMC_GETCOMPOSITIONWINDOW
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


IMC_GETCONVERSIONMODE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


IMC_GETOPENSTATUS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


IMC_GETSENTENCEMODE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


IMC_GETSTATUSWINDOWPOS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


IMC_SETCANDIDATEPOS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


IMC_SETCOMPOSITIONFONT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


IMC_SETCOMPOSITIONWINDOW
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


IMC_SETCONVERSIONMODE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


IMC_SETOPENSTATUS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


IMC_SETSENTENCEMODE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


IMC_SETSTATUSWINDOWPOS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


IMN_CHANGECANDIDATE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


IMN_CLOSECANDIDATE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


IMN_CLOSESTSTATUSWINDOW
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


IMN_GUIDELINE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


IMN_OPENCANDIDATE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


IMN_OPENSTATUSWINDOW
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


IMN_SETCANDIDATEPOS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


IMN_SETCOMPOSITIONFONT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


IMN_SETCOMPOSITIONWINDOW
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


IMN_SETCONVERSIONMODE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


IMN_SETOPENSTATUS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


IMN_SETSENTENCEMODE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


IMN_SETSTATUSWINDOWPOS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LB_ADDFILE
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


LB_ADDSTRING
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


LB_DELETESTRING
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
Windows 95: wParam is 16-bits


LB_DIR
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


LB_FINDSTRING
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
Windows 95: wParam is 16-bits


LB_FINDSTRINGEXACT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
Windows 95: wParam is 16-bits


LB_GETANCHORINDEX
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


LB_GETCARETINDEX
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


LB_GETCOUNT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


LB_GETCURSEL
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


LB_GETHORIZONTALEXTENT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


LB_GETITEMDATA
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
Windows 95: wParam is 16-bits


LB_GETITEMHEIGHT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
Windows 95: wParam is 16-bits


LB_GETITEMRECT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
Windows 95: wParam is 16-bits


LB_GETLOCALE
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


LB_GETSEL
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
Windows 95: wParam is 16-bits


LB_GETSELCOUNT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


LB_GETSELITEMS
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
Windows 95: wParam is 16-bits


LB_GETTEXT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
Windows 95: wParam is 16-bits


LB_GETTEXTLEN
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
Windows 95: wParam is 16-bits


LB_GETTOPINDEX
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


LB_INITSTORAGE
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


LB_INSERTSTRING
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
Windows 95: wParam is 16-bits


LB_ITEMFROMPOINT
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


LB_RESETCONTENT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


LB_SELECTSTRING
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
Windows 95: wParam is 16-bits


LB_SELITEMRANGE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
Windows 95: wParam is 16-bits


LB_SELITEMRANGEEX
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


LB_SETANCHORINDEX
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


LB_SETCARETINDEX
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
Windows 95: wParam is 16-bits


LB_SETCOLUMNWIDTH
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


LB_SETCOUNT
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


LB_SETCURSEL
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
Windows 95: wParam is 16-bits


LB_SETHORIZONTALEXTENT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


LB_SETITEMDATA
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
Windows 95: wParam is 16-bits


LB_SETITEMHEIGHT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
Windows 95: wParam is 16-bits


LB_SETLOCALE
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


LB_SETSEL
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
Windows 95: wParam is 16-bits


LB_SETTABSTOPS
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


LB_SETTOPINDEX
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
Windows 95: wParam is 16-bits


LBN_DBLCLK
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


LBN_ERRSPACE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


LBN_KILLFOCUS
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


LBN_SELCANCEL
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


LBN_SELCHANGE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


LBN_SETFOCUS
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


LVM_ARRANGE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_CREATEDRAGIMAGE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_DELETEALLITEMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_DELETECOLUMN
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_DELETEITEM
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_EDITLABEL
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_ENSUREVISIBLE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_FINDITEM
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_GETBKCOLOR
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_GETCALLBACKMASK
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_GETCOLUMN
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_GETCOLUMNWIDTH
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_GETCOUNTPERPAGE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_GETEDITCONTROL
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_GETIMAGELIST
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_GETITEM
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_GETITEMCOUNT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_GETITEMPOSITION
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_GETITEMRECT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_GETITEMSPACING
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_GETITEMSTATE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_GETITEMTEXT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_GETNEXTITEM
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_GETORIGIN
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_GETSELECTEDCOUNT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_GETSTRINGWIDTH
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_GETTEXTBKCOLOR
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_GETTEXTCOLOR
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_GETTOPINDEX
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_GETVIEWRECT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_HITTEST
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_INSERTCOLUMN
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_INSERTITEM
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_REDRAWITEMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_SCROLL
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_SETBKCOLOR
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_SETCALLBACKMASK
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_SETCOLUMN
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_SETCOLUMNWIDTH
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_SETIMAGELIST
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_SETITEM
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_SETITEMCOUNT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_SETITEMPOSITION
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_SETITEMPOSITION32
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_SETITEMSTATE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_SETITEMTEXT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_SETTEXTBKCOLOR
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_SETTEXTCOLOR
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_SORTITEMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVM_UPDATE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVN_BEGINDRAG
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVN_BEGINLABELEDIT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVN_BEGINRDRAG
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVN_COLUMNCLICK
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVN_DELETEALLITEMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVN_DELETEITEM
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVN_ENDLABELEDIT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVN_GETDISPINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVN_INSERTITEM
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVN_ITEMCHANGED
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVN_ITEMCHANGING
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVN_KEYDOWN
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVN_PEN
Windows NT
No
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LVN_SETDISPINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_BREAK
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MCI_CAPTURE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_CLOSE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MCI_CONFIGURE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_COPY
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MCI_CUE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MCI_CUT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MCI_DELETE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MCI_ESCAPE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MCI_FREEZE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MCI_GETDEVCAPS
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MCI_INDEX
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_INFO
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MCI_LIST
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_LOAD
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MCI_MARK
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_MONITOR
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_OPEN
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MCI_PASTE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MCI_PAUSE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MCI_PLAY
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MCI_PUT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MCI_QUALITY
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_REALIZE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MCI_RECORD
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MCI_RESERVE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_RESTORE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_RESUME
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MCI_SAVE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MCI_SEEK
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MCI_SET
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MCI_SETAUDIO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_SETTIMECODE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_SETTUNER
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_SETVIDEO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_SIGNAL
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_SPIN
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MCI_STATUS
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MCI_STEP
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MCI_STOP
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MCI_SYSINFO
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MCI_UNDO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_UNFREEZE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MCI_UPDATE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MCI_WHERE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MCI_WINDOW
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MCIWNDM_NOTIFYERROR
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWNDM_NOTIFYMEDIA
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWNDM_NOTIFYMODE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWNDM_NOTIFYPOS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCIWNDM_NOTIFYSIZE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MIM_CLOSE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MIM_DATA
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MIM_ERROR
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MIM_LONGDATA
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MIM_LONGERROR
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MIM_MOREDATA
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MIM_OPEN
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MM_ACM_FILTERCHOOSE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MM_ACM_FORMATCHOOSE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MM_JOY1BUTTONDOWN
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MM_JOY1BUTTONUP
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MM_JOY1MOVE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MM_JOY1ZMOVE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MM_JOY2BUTTONDOWN
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MM_JOY2BUTTONUP
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MM_JOY2MOVE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MM_JOY2ZMOVE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MM_MCINOTIFY
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MM_MCISIGNAL
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MM_MIM_CLOSE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MM_MIM_DATA
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MM_MIM_ERROR
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MM_MIM_LONGDATA
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MM_MIM_LONGERROR
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MM_MIM_MOREDATA
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MM_MIM_OPEN
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MM_MIXM_CONTROL_CHANGE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MM_MIXM_LINE_CHANGE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MM_MOM_CLOSE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MM_MOM_DONE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MM_MOM_OPEN
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MM_MOM_POSITIONCB
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MM_WIM_CLOSE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MM_WIM_DATA
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MM_WIM_OPEN
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MM_WOM_CLOSE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MM_WOM_DONE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MM_WOM_OPEN
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MMIOM_CLOSE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MMIOM_OPEN
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MMIOM_READ
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MMIOM_RENAME
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MMIOM_SEEK
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MMIOM_WRITE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MMIOM_WRITEFLUSH
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MOM_CLOSE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MOM_DONE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MOM_OPEN
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


MOM_POSITIONCB
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
mmsystem.h
Unicode
No
Platform Notes
None


NIM_ADD
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shellapi.h
Unicode
Platform Notes
None


NIM_DELETE
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shellapi.h
Unicode
Platform Notes
None


NIM_MODIFY
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shellapi.h
Unicode
Platform Notes
None


NM_CLICK
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


NM_DBLCLK
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


NM_ENDWAIT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


NM_KILLFOCUS
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


NM_OUTOFMEMORY
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


NM_RCLICK
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


NM_RDBLCLK
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


NM_RETURN
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


NM_SETFOCUS
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


NM_STARTWAIT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PBM_DELTAPOS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PBM_SETPOS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PBM_SETRANGE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PBM_SETSTEP
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PBM_STEPIT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PBT_APMBATTERYLOW
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
pbt.h
Unicode
Platform Notes
None


PBT_APMOEMEVENT
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
pbt.h
Unicode
Platform Notes
None


PBT_APMPOWERSTATUSCHANGE
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
pbt.h
Unicode
Platform Notes
None


PBT_APMQUERYSTANDBY
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
pbt.h
Unicode
Platform Notes
None


PBT_APMQUERYSTANDBYFAILED
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
pbt.h
Unicode
Platform Notes
None


PBT_APMQUERYSUSPEND
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
pbt.h
Unicode
Platform Notes
None


PBT_APMQUERYSUSPENDFAILED
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
pbt.h
Unicode
Platform Notes
None


PBT_APMRESUMECRITICAL
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
pbt.h
Unicode
Platform Notes
None


PBT_APMRESUMEFROMFAILURE
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
pbt.h
Unicode
Platform Notes
None


PBT_APMRESUMESTANDBY
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
pbt.h
Unicode
Platform Notes
None


PBT_APMRESUMESUSPEND
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
pbt.h
Unicode
Platform Notes
None


PBT_APMSTANDBY
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
pbt.h
Unicode
Platform Notes
None


PBT_APMSUSPEND
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
pbt.h
Unicode
Platform Notes
None


PSM_ADDPAGE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PSM_APPLY
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PSM_CANCELTOCLOSE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PSM_CHANGED
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PSM_GETTABCONTROL
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PSM_PRESSBUTTON
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PSM_QUERYSIBLINGS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PSM_REBOOTSYSTEM
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PSM_REMOVEPAGE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PSM_RESTARTWINDOWS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PSM_SETCURSEL
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PSM_SETCURSELID
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PSM_SETFINISHTEXT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PSM_SETTITLE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PSM_SETWIZBUTTONS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PSM_UNCHANGED
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PSN_APPLY
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PSN_HASHELP
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PSN_HELP
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PSN_KILLACTIVE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PSN_QUERYCANCEL
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PSN_RESET
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PSN_SETACTIVE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PSN_WIZBACK
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PSN_WIZFINISH
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PSN_WIZNEXT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


SB_GETBORDERS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


SB_GETPARTS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


SB_GETRECT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


SB_GETTEXT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


SB_GETTEXTLENGTH
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


SB_SETMINHEIGHT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


SB_SETPARTS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


SB_SETTEXT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


SB_SIMPLE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


SBM_ENABLE_ARROWS
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


SBM_GETPOS
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


SBM_GETRANGE
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


SBM_GETSCROLLINFO
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


SBM_SETPOS
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


SBM_SETRANGE
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


SBM_SETRANGEREDRAW
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


SBM_SETSCROLLINFO
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


STM_GETICON
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


STM_GETIMAGE
Windows NT
Yes
Win95
Yes
Win32s
Import Library
Header File
winuser.h
Unicode
Platform Notes
None


STM_SETICON
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


STM_SETIMAGE
Windows NT
Yes
Win95
Yes
Win32s
Import Library
Header File
winuser.h
Unicode
Platform Notes
None


STN_CLICKED
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


STN_DBLCLK
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


STN_DISABLE
Windows NT
No
Win95
Yes
Win32s
Import Library
Header File
winuser.h
Unicode
Platform Notes
None


STN_ENABLE
Windows NT
No
Win95
Yes
Win32s
Import Library
Header File
winuser.h
Unicode
Platform Notes
None


TB_ADDBITMAP
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TB_ADDBUTTONS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TB_ADDSTRING
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TB_AUTOSIZE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TB_BUTTONCOUNT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TB_BUTTONSTRUCTSIZE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TB_CHANGEBITMAP
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TB_CHECKBUTTON
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TB_COMMANDTOINDEX
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TB_CUSTOMIZE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TB_DELETEBUTTON
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TB_ENABLEBUTTON
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TB_GETBITMAP
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TB_GETBITMAPFLAGS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TB_GETBUTTON
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TB_GETBUTTONTEXT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TB_GETITEMRECT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TB_GETROWS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TB_GETSTATE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TB_GETTOOLTIPS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TB_HIDEBUTTON
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TB_INDETERMINATE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TB_INSERTBUTTON
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TB_ISBUTTONCHECKED
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TB_ISBUTTONENABLED
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TB_ISBUTTONHIDDEN
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TB_ISBUTTONINDETERMINATE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TB_ISBUTTONPRESSED
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TB_PRESSBUTTON
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TB_SAVERESTORE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TB_SETBITMAPSIZE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TB_SETBUTTONSIZE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TB_SETCMDID
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TB_SETPARENT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TB_SETROWS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TB_SETSTATE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TB_SETTOOLTIPS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TBM_CLEARSEL
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TBM_CLEARTICS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TBM_GETCHANNELRECT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TBM_GETLINESIZE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TBM_GETNUMTICS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TBM_GETPAGESIZE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TBM_GETPOS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TBM_GETPTICS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TBM_GETRANGEMAX
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TBM_GETRANGEMIN
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TBM_GETSELEND
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TBM_GETSELSTART
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TBM_GETTHUMBLENGTH
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TBM_GETTHUMBRECT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TBM_GETTIC
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TBM_GETTICPOS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TBM_SETLINESIZE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TBM_SETPAGESIZE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TBM_SETPOS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TBM_SETRANGE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TBM_SETRANGEMAX
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TBM_SETRANGEMIN
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TBM_SETSEL
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TBM_SETSELEND
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TBM_SETSELSTART
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TBM_SETTHUMBLENGTH
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TBM_SETTIC
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TBM_SETTICFREQ
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TBN_BEGINADJUST
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TBN_BEGINDRAG
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TBN_CUSTHELP
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TBN_ENDADJUST
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TBN_ENDDRAG
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TBN_GETBUTTONINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TBN_QUERYDELETE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TBN_QUERYINSERT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TBN_RESET
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TBN_TOOLBARCHANGE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TCM_ADJUSTRECT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TCM_DELETEALLITEMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TCM_DELETEITEM
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TCM_GETBKCOLOR
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TCM_GETCURFOCUS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TCM_GETCURSEL
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TCM_GETIMAGELIST
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TCM_GETITEM
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TCM_GETITEMCOUNT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TCM_GETITEMRECT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TCM_GETROWCOUNT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TCM_GETTOOLTIPS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TCM_HITTEST
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TCM_INSERTITEM
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TCM_REMOVEIMAGE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TCM_SETBKCOLOR
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TCM_SETCURSEL
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TCM_SETIMAGELIST
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TCM_SETITEM
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TCM_SETITEMEXTRA
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TCM_SETITEMSIZE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TCM_SETPADDING
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TCM_SETTOOLTIPS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TCN_KEYDOWN
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TCN_SELCHANGE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TCN_SELCHANGING
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TTM_ACTIVATE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TTM_ADDTOOL
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TTM_DELTOOL
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TTM_ENUMTOOLS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TTM_GETCURRENTTOOL
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TTM_GETTEXT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TTM_GETTOOLCOUNT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TTM_GETTOOLINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TTM_HITTEST
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TTM_NEWTOOLRECT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TTM_RELAYEVENT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TTM_SETDELAYTIME
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TTM_SETTOOLINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TTM_UPDATETIPTEXT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TTM_WINDOWFROMPOINT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TTN_NEEDTEXT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TTN_POP
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TTN_SHOW
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TVM_CREATEDRAGIMAGE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TVM_DELETEITEM
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TVM_EDITLABEL
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TVM_ENDEDITLABELNOW
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TVM_ENSUREVISIBLE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TVM_EXPAND
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TVM_GETCOUNT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TVM_GETEDITCONTROL
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TVM_GETIMAGELIST
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TVM_GETINDENT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TVM_GETISEARCHSTRING
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TVM_GETITEM
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TVM_GETITEMRECT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TVM_GETNEXTITEM
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TVM_GETVISIBLECOUNT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TVM_HITTEST
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TVM_INSERTITEM
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TVM_SELECTITEM
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TVM_SETIMAGELIST
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TVM_SETINDENT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TVM_SETITEM
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TVM_SORTCHILDREN
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TVM_SORTCHILDRENCB
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TVN_BEGINDRAG
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TVN_BEGINLABELEDIT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TVN_BEGINRDRAG
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TVN_DELETEITEM
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TVN_ENDLABELEDIT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TVN_GETDISPINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TVN_ITEMEXPANDED
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TVN_ITEMEXPANDING
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TVN_KEYDOWN
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TVN_SELCHANGED
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TVN_SELCHANGING
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TVN_SETDISPINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


UDM_DELTAPOS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


UDM_GETACCEL
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


UDM_GETBASE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


UDM_GETBUDDY
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


UDM_GETPOS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


UDM_GETRANGE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


UDM_SETACCEL
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


UDM_SETBASE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


UDM_SETBUDDY
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


UDM_SETPOS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


UDM_SETRANGE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WIM_CLOSE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WIM_DATA
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WIM_OPEN
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_ACTIVATE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_ACTIVATEAPP
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_APP
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_ASKCBFORMATNAME
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_CANCELJOURNAL
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_CANCELMODE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_CAP_ABORT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_CAP_DLG_VIDEOCOMPRESSION
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_CAP_DLG_VIDEODISPLAY
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_CAP_DLG_VIDEOFORMAT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_CAP_DLG_VIDEOSOURCE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_CAP_DRIVER_CONNECT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_CAP_DRIVER_DISCONNECT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_CAP_DRIVER_GET_CAPS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_CAP_DRIVER_GET_NAME
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_CAP_DRIVER_GET_VERSION
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_CAP_EDIT_COPY
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_CAP_FILE_ALLOCATE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_CAP_FILE_GET_CAPTURE_FILE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_CAP_FILE_SAVEAS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_CAP_FILE_SAVEDIB
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM
_CAP_FILE_SET_CAPTURE_FILE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_CAP_FILE_SET_INFOCHUNK
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_CAP_GET_AUDIOFORMAT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_CAP_GET_MCI_DEVICE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM
_CAP_GET_SEQUENCE_SETUP
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_CAP_GET_STATUS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_CAP_GET_USER_DATA
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_CAP_GET_VIDEOFORMAT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_CAP_GRAB_FRAME
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_CAP_GRAB_FRAME_NOSTOP
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_CAP_PAL_AUTOCREATE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_CAP_PAL_MANUALCREATE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_CAP_PAL_OPEN
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_CAP_PAL_PASTE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_CAP_PAL_SAVE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_CAP_SEQUENCE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_CAP_SEQUENCE_NOFILE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_CAP_SET_AUDIOFORMAT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_CAP_SET_CALLBACK_CAPCONTR
OL
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM
_CAP_SET_CALLBACK_ERROR
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_CAP_SET_CALLBACK_FRAME
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM
_CAP_SET_CALLBACK_STATUS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_CAP_SET_CALLBACK_VIDEOSTR
EAM
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_CAP_SET_CALLBACK_WAVESTRE
AM
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_CAP_SET_CALLBACK_YIELD
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_CAP_SET_MCI_DEVICE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_CAP_SET_OVERLAY
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_CAP_SET_PREVIEW
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_CAP_SET_PREVIEWRATE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_CAP_SET_SCALE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_CAP_SET_SCROLL
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM
_CAP_SET_SEQUENCE_SETUP
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_CAP_SET_USER_DATA
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_CAP_SET_VIDEOFORMAT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_CAP_SINGLE_FRAME
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_CAP_SINGLE_FRAME_CLOSE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_CAP_SINGLE_FRAME_OPEN
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_CAP_STOP
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WM_CAPTURECHANGED
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_CHANGECBCHAIN
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_CHAR
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_CHARTOITEM
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_CHILDACTIVATE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM
_CHOOSEFONT_GETLOGFONT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
commdlg.h
Unicode
No
Platform Notes
None


WM_CLEAR
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_CLOSE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_COMMAND
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_COMMNOTIFY
Windows NT
No
Win95
No
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_COMPACTING
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_COMPAREITEM
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_CONTEXTMENU
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_CONVERTREQUESTEX
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


WM_COPY
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_COPYDATA
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_CPL_LAUNCH
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
cpl.h
Unicode
No
Platform Notes
None


WM_CPL_LAUNCHED
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
cpl.h
Unicode
No
Platform Notes
None


WM_CREATE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_CTLCOLORBTN
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_CTLCOLORDLG
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_CTLCOLOREDIT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_CTLCOLORLISTBOX
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_CTLCOLORMSGBOX
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_CTLCOLORSCROLLBAR
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_CTLCOLORSTATIC
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_CUT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_DDE_ACK
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
dde.h
Unicode
No
Platform Notes
None


WM_DDE_ADVISE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
dde.h
Unicode
No
Platform Notes
None


WM_DDE_DATA
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
dde.h
Unicode
No
Platform Notes
None


WM_DDE_EXECUTE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
dde.h
Unicode
No
Platform Notes
None


WM_DDE_INITIATE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
dde.h
Unicode
No
Platform Notes
None


WM_DDE_POKE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
dde.h
Unicode
No
Platform Notes
None


WM_DDE_REQUEST
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
dde.h
Unicode
No
Platform Notes
None


WM_DDE_TERMINATE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
dde.h
Unicode
No
Platform Notes
None


WM_DDE_UNADVISE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
dde.h
Unicode
No
Platform Notes
None


WM_DEADCHAR
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_DELETEITEM
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_DESTROY
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_DESTROYCLIPBOARD
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_DEVICECHANGE
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
Platform Notes
None


WM_DEVMODECHANGE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_DISPLAYCHANGE
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_DRAWCLIPBOARD
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_DRAWITEM
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_DROPFILES
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_ENABLE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_ENDSESSION
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_ENTERIDLE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_ENTERMENULOOP
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_ENTERSIZEMOVE
Windows NT
Yes
Win95
Yes
Win32s
Import Library
Header File
winuser.h
Unicode
Platform Notes
None


WM_ERASEBKGND
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_EXITMENULOOP
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_EXITSIZEMOVE
Windows NT
Yes
Win95
Yes
Win32s
Import Library
Header File
winuser.h
Unicode
Platform Notes
None


WM_FONTCHANGE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_GETDLGCODE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_GETFONT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_GETHOTKEY
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_GETICON
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_GETMINMAXINFO
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_GETTEXT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_GETTEXTLENGTH
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_HELP
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_HOTKEY
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_HSCROLL
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_HSCROLLCLIPBOARD
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_ICONERASEBKGND
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_IME_CHAR
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


WM_IME_COMPOSITION
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


WM_IME_COMPOSITIONFULL
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


WM_IME_CONTROL
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


WM_IME_ENDCOMPOSITION
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


WM_IME_KEYDOWN
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


WM_IME_KEYLAST
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


WM_IME_KEYUP
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


WM_IME_NOTIFY
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


WM_IME_SELECT
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


WM_IME_SETCONTEXT
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


WM_IME_STARTCOMPOSITION
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
imm.h
Unicode
Platform Notes
None


WM_INITDIALOG
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_INITMENU
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_INITMENUPOPUP
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_KEYDOWN
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_KEYFIRST
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_KEYLAST
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_KEYUP
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_KILLFOCUS
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_LBUTTONDBLCLK
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_LBUTTONDOWN
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_LBUTTONUP
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_MBUTTONDBLCLK
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_MBUTTONDOWN
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_MBUTTONUP
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_MDIACTIVATE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_MDICASCADE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_MDICREATE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_MDIDESTROY
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_MDIGETACTIVE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_MDIICONARRANGE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_MDIMAXIMIZE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_MDINEXT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_MDIREFRESHMENU
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_MDIRESTORE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_MDISETMENU
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_MDITILE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_MEASUREITEM
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_MENUCHAR
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_MENUSELECT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_MOUSEACTIVATE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_MOUSEMOVE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_MOVE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_MOVING
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_NCACTIVATE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_NCCALCSIZE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_NCCREATE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_NCDESTROY
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_NCHITTEST
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_NCLBUTTONDBLCLK
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_NCLBUTTONDOWN
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_NCLBUTTONUP
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_NCMBUTTONDBLCLK
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_NCMBUTTONDOWN
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_NCMBUTTONUP
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_NCMOUSEMOVE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_NCPAINT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_NCRBUTTONDBLCLK
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_NCRBUTTONDOWN
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_NCRBUTTONUP
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_NEXTDLGCTL
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_NOTIFY
Windows NT
Yes
Win95
Yes
Win32s
Import Library
Header File
winuser.h
Unicode
Platform Notes
None


WM_NOTIFYFORMAT
Windows NT
Yes
Win95
Yes
Win32s
Import Library
Header File
winuser.h
Unicode
Platform Notes
None


WM_NULL
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_PAINT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_PAINTCLIPBOARD
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_PAINTICON
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_PALETTECHANGED
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_PALETTEISCHANGING
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_PARENTNOTIFY
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_PASTE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_POWER
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_POWERBROADCAST
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_PRINT
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_PRINTCLIENT
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_QUERYDRAGICON
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_QUERYENDSESSION
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_QUERYNEWPALETTE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_QUERYOPEN
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_QUEUESYNC
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_QUIT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_RASDIALEVENT
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
ras.h
Unicode
No
Platform Notes
None


WM_RBUTTONDBLCLK
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_RBUTTONDOWN
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_RBUTTONUP
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_RENDERALLFORMATS
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_RENDERFORMAT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_SETCURSOR
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_SETFOCUS
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_SETFONT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_SETHOTKEY
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_SETICON
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_SETREDRAW
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_SETTEXT
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_SETTINGCHANGE
Windows NT
No
Win95
Yes
Win32s
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_SHOWWINDOW
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_SIZE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_SIZECLIPBOARD
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_SIZING
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_SPOOLERSTATUS
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_STYLECHANGED
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_STYLECHANGING
Windows NT
Yes
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_SYSCHAR
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_SYSCOLORCHANGE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_SYSCOMMAND
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_SYSDEADCHAR
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_SYSKEYDOWN
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_SYSKEYUP
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_TCARD
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
Platform Notes
None


WM_TIMECHANGE
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_TIMER
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_UNDO
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_USER
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_USERCHANGED
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
Platform Notes
None


WM_VKEYTOITEM
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_VSCROLL
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_VSCROLLCLIPBOARD
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_WINDOWPOSCHANGED
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_WINDOWPOSCHANGING
Windows NT
Yes
Win95
Yes
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WM_WININICHANGE
Windows NT
Yes
Win95
No
Win32s
Yes
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WOM_CLOSE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WOM_DONE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WOM_OPEN
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WS_EX_CLIENTEDGE
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WS_EX_MDICHILD
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


WS_EX_WINDOWEDGE
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winuser.h
Unicode
No
Platform Notes
None


_DEV_BROADCAST_USER_DEFINED
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ABC
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ABCFLOAT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ACCEL
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ACCESS_ALLOWED_ACE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ACCESS_DENIED_ACE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ACCESS_MASK
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ACCESSTIMEOUT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ACE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ACE_HEADER
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ACL
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ACL_REVISION_INFORMATION
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ACL_SIZE_INFORMATION
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ACMDRIVERDETAILS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ACMFILTERCHOOSE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ACMFILTERDETAILS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ACMFILTERTAGDETAILS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ACMFORMATCHOOSE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ACMFORMATDETAILS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ACMFORMATTAGDETAILS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ACMSTREAMHEADER
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ACTION_HEADER
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ADAPTER_STATUS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ADDJOB_INFO_1
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ANIMATIONINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


APPBARDATA
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shellapi.h
Unicode
Platform Notes
None


AUXCAPS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


AVICOMPRESSOPTIONS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


AVIFILEINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


AVISTREAMINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


BITMAP
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


BITMAPCOREHEADER
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


BITMAPCOREINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


BITMAPFILEHEADER
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


BITMAPINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


BITMAPINFOHEADER
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


BITMAPV4HEADER
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


BLOB
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


BROWSEINFO
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


BY_HANDLE_FILE_INFORMATION
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


CANDIDATEFORM
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


CANDIDATELIST
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


CAPDRIVERCAPS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


CAPINFOCHUNK
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


CAPSTATUS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


CAPTUREPARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


CBT_CREATEWND
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


CBTACTIVATESTRUCT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


CHAR_INFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


CHARFORMAT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


CHARRANGE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


CHARSET
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


CHARSETINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


CHOOSECOLOR
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


CHOOSEFONT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


CIDA
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


CIEXYZ
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


CIEXYZTRIPLE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


CLIENTCREATESTRUCT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


CMINVOKECOMMANDINFO
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


COLORADJUSTMENT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


COLORMAP
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


COLORREF
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


COMMCONFIG
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


COMMPROP
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


COMMTIMEOUTS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


COMPAREITEMSTRUCT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


COMPCOLOR
Windows NT
Win95
Win32s
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


COMPOSITIONFORM
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


COMPVARS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


COMSTAT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


CONSOLE_CURSOR_INFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


CO
NSOLE_SCREEN_BUFFER_INFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


CONTEXT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


CONVCONTEXT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


CONVINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


COORD
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


COPYDATASTRUCT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


CPINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


CPLINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


CREATE_PROCESS_DEBUG_INFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


CREATE_THREAD_DEBUG_INFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


CREATESTRUCT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


CSADDR_INFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


CURRENCYFMT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


CURSORSHAPE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


CWPRETSTRUCT
Windows NT
No
Win95
Yes
Win32s
Import Library
Header File
winuser.h
Unicode
Platform Notes
None


CWPSTRUCT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


DATATYPES_INFO_1
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


DCB
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


DDEACK
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


DDEADVISE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


DDEDATA
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


DDELN
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


DDEML_MSG_HOOK_DATA
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


DDEPOKE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


DDEUP
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


DEBUG_EVENT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


DEBUGHOOKINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


DELETEITEMSTRUCT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


DEV_BROADCAST_DEVNODE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


DEV_BROADCAST_HDR
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


DEV_BROADCAST_NET
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


DEV_BROADCAST_OEM
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


DEV_BROADCAST_PORT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


DEV_BROADCAST_VOLUME
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


DEVMODE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


DEVNAMES
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


DIBSECTION
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


DISK_GEOMETRY
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


DISK_PERFORMANCE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


DLGITEMTEMPLATE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


DLGTEMPLATE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


DOC_INFO_1
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


DOC_INFO_2
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


DOCINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


DRAGLISTINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


DRAWDIBTIME
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


DRAWITEMSTRUCT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


DRAWTEXTPARAMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


DRIVE_LAYOUT_INFORMATION
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


DRIVER_INFO_1
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


DRIVER_INFO_2
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


DRIVER_INFO_3
Windows NT
No
Win95
Yes
Win32s
Import Library
Header File
winspool.h
Unicode
Platform Notes
None


DROPFILES
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


DRVCONFIGINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EDITSTREAM
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMR
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMRANGLEARC
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMRARC
Windows NT
 EMRARCTO
Win95
 EMRCHORD
Win32s
 EMRPIE
Import Library
Header File
Unicode
Platform Notes
None


EMRBITBLT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMRCREATEBRUSHINDIRECT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMRCREATECOLORSPACE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EM
RCREATEDIBPATTERNBRUSHPT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMRCREATEMONOBRUSH
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMRCREATEPALETTE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMRCREATEPEN
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMRELLIPSE
Windows NT
 EMRRECTANGLE
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMREOF
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMREXCLUDECLIPRECT
Windows NT
 EMRINTERSECTCLIPRECT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMREXTCREATEFONTINDIRECTW
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMREXTCREATEPEN
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMREXTFLOODFILL
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMREXTSELECTCLIPRGN
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMREXTTEXTOUTA
Windows NT
 EMREXTTEXTOUTW
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMRFILLPATH
Windows NT
 EMRSTROKEANDFILLPATH
Win95
 EMRSTROKEPATH
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMRFILLRGN
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMRFORMAT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMRFRAMERGN
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMRGDICOMMENT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMRINVERTRGN
Windows NT
 EMRPAINTRGN
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMRLINETO
Windows NT
 EMRMOVETOEX
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMRMASKBLT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMRMODIFYWORLDTRANSFORM
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMROFFSETCLIPRGN
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMRPLGBLT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMRPOLYDRAW
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMRPOLYDRAW16
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMRPOLYLINE
Windows NT
 EMRPOLYBEZIER
Win95
 EMRPOLYGON
Win32s
 EMRPOLYBEZIERTO
Import Library
Header File
Unicode
Platform Notes
None


EMRPOLYLINE16
Windows NT
 EMRPOLYBEZIER16
Win95
 EMRPOLYGON16
Win32s
 EMRPOLYBEZIERTO16
Import Library
Header File
Unicode
Platform Notes
None


EMRPOLYPOLYLINE
Windows NT
 EMRPOLYPOLYGON
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMRPOLYPOLYLINE16
Windows NT
 EMRPOLYPOLYGON16
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMRPOLYTEXTOUTA
Windows NT
 EMRPOLYTEXTOUTW
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMRRESIZEPALETTE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMRRESTOREDC
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMRROUNDRECT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMRSCALEVIEWPORTEXTEX
Windows NT
 EMRSCALEWINDOWEXTEX
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMRSELECTCOLORSPACE
Windows NT
 EMRDELETECOLORSPACE
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMRSELECTOBJECT
Windows NT
 EMRDELETEOBJECT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMRSELECTPALETTE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMRSETARCDIRECTION
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMRSETBKCOLOR
Windows NT
 EMRSETTEXTCOLOR
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMRSETCOLORADJUSTMENT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMRSETDIBITSTODEVICE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMRSETMAPPERFLAGS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMRSETMITERLIMIT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMRSETPALETTEENTRIES
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMRSETPIXELV
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMRSETVIEWPORTEXTEX
Windows NT
 EMRSETWINDOWEXTEX
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMRSETVIEWPORTORGEX
Windows NT
 EMRSETWINDOWORGEX
Win95
 EMRSETBRUSHORGEX
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMRSETWORLDTRANSFORM
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMRSTRETCHBLT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMRSTRETCHDIBITS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EMRTEXT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ENCORRECTTEXT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ENDROPFILES
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ENHMETAHEADER
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ENHMETARECORD
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ENOLEOPFAILED
Windows NT
Win95
Win32s
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


ENPROTECTED
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ENSAVECLIPBOARD
Windows NT
Win95
Win32s
Import Library
Header File
richedit.h
Unicode
Platform Notes
None


ENUM_SERVICE_STATUS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ENUMLOGFONT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ENUMLOGFONTEX
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EVENTLOGRECORD
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EVENTMSG
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EXCEPTION_DEBUG_INFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EXCEPTION_POINTERS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EXCEPTION_RECORD
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EXIT_PROCESS_DEBUG_INFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EXIT_THREAD_DEBUG_INFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EXT_BUTTON
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EXTLOGFONT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


EXTLOGPEN
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


FILEDESCRIPTOR
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
Unicode
Platform Notes
None


FILEGROUPDESCRIPTOR
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
Unicode
Platform Notes
None


FILETIME
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


FILTERKEYS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


FIND_NAME_BUFFER
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


FIND_NAME_HEADER
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


FINDREPLACE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


FINDTEXT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


FINDTEXTEX
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


FIXED
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


FMS_GETDRIVEINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


FMS_GETFILESEL
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


FMS_LOAD
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


FMS_TOOLBARLOAD
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


FOCUS_EVENT_RECORD
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


FONTSIGNATURE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


FORM_INFO_1
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


FORMAT_PARAMETERS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


FORMATRANGE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


FVSHOWINFO
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


GCP_RESULTS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


GENERIC_MAPPING
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


GLYPHMETRICS
Windows NT
Yes
Win95
No
Win32s
No
Import Library
Header File
wingdi.h
Unicode
Platform Notes
None


GLYPHMETRICSFLOAT
Windows NT
New
Win95
No
Win32s
No
Import Library
Header File
wingdi.h
Unicode
Platform Notes
None


HANDLETABLE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


HD_HITTESTINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


HD_ITEM
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


HD_LAYOUT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


HD_NOTIFY
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


HELPINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


HELPWININFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


HIGHCONTRAST
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


HSZPAIR
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICCOMPRESS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICCOMPRESSFRAMES
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICDECOMPRESS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICDECOMPRESSEX
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICDRAW
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICDRAWBEGIN
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICDRAWSUGGEST
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICONINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICONMETRICS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICOPEN
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ICSETSTATUSPROC
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


IMAGEINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


INPUT_RECORD
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ITEMIDLIST
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


JOB_INFO_1
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


JOB_INFO_2
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


JOYCAPS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


JOYCAPS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


JOYINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


JOYINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


KERNINGPAIR
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


KEY_EVENT_RECORD
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


KEYARRAY
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LANA_ENUM
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LARGE_INTEGER
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LDT_ENTRY
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LIST_ENTRY
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LOAD_DLL_DEBUG_INFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LOCALESIGNATURE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LOCALGROUP_MEMBERS_INFO_0
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LOCALGROUP_MEMBERS_INFO_3
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LOGBRUSH
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LOGCOLORSPACE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LOGFONT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LOGPALETTE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LOGPEN
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LUID
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LUID_AND_ATTRIBUTES
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LV_COLUMN
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LV_DISPINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LV_FINDINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LV_HITTESTINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LV_ITEM
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


LV_KEYDOWN
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MAT2
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_ANIM_OPEN_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_ANIM_PLAY_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_ANIM_RECT_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_ANIM_STEP_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_ANIM_UPDATE_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_ANIM_WINDOW_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_BREAK_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_DGV_CAPTURE_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_DGV_COPY_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_DGV_CUE_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_DGV_CUT_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_DGV_DELETE_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_DGV_FREEZE_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_DGV_INFO_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_DGV_LIST_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_DGV_LOAD_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_DGV_MONITOR_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_DGV_OPEN_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_DGV_PASTE_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_DGV_PAUSE_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_DGV_PLAY_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_DGV_PUT_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_DGV_QUALITY_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_DGV_RECORD_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_DGV_RECT_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_DGV_RESERVE_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_DGV_RESTORE_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_DGV_RESUME_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_DGV_SAVE_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_DGV_SET_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_DGV_SETAUDIO_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_DGV_SETVIDEO_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_DGV_SIGNAL_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_DGV_STATUS_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_DGV_STEP_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_DGV_STOP_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_DGV_UPDATE_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_DGV_WINDOW_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_GENERIC_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_GENERIC_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_GETDEVCAPS_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_GETDEVCAPS_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_INFO_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_INFO_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_LOAD_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_LOAD_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_OPEN_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_OPEN_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_OVLY_LOAD_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_OVLY_LOAD_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_OVLY_OPEN_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_OVLY_OPEN_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_OVLY_RECT_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_OVLY_RECT_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_OVLY_SAVE_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_OVLY_SAVE_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_OVLY_WINDOW_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_OVLY_WINDOW_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_PLAY_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_PLAY_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_RECORD_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_RECORD_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_SAVE_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_SAVE_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_SEEK_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_SEEK_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_SEQ_SET_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_SEQ_SET_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_SET_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_SET_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_STATUS_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_STATUS_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_SYSINFO_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_SYSINFO_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_VCR_CUE_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_VCR_LIST_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_VCR_PLAY_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_VCR_RECORD_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_VCR_SEEK_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_VCR_SET_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_VCR_SETAUDIO_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_VCR_SETTUNER_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_VCR_SETVIDEO_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_VCR_STATUS_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_VCR_STEP_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_VD_ESCAPE_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_VD_ESCAPE_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_VD_PLAY_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_VD_PLAY_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_VD_STEP_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_VD_STEP_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_WAVE_DELETE_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_WAVE_DELETE_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_WAVE_OPEN_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_WAVE_OPEN_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_WAVE_SET_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MCI_WAVE_SET_PARMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MDICREATESTRUCT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MEASUREITEMSTRUCT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MEMORY_BASIC_INFORMATION
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MEMORYSTATUS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MENU_EVENT_RECORD
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MENUEX_TEMPLATE_HEADER
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MENUEX_TEMPLATE_ITEM
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MENUITEMINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MENUITEMTEMPLATE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MENUITEMTEMPLATEHEADER
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


METAFILEPICT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


METAHEADER
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


METARECORD
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MIDIEVENT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MIDIHDR
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MIDIHDR
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MIDIINCAPS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MIDIINCAPS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MIDIOUTCAPS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MIDIOUTCAPS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MIDIPROPTEMPO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MIDIPROPTIMEDIV
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MIDISTRMBUFFVER
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MINIMIZEDMETRICS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MINMAXINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MIXERCAPS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MIXERCONTROL
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MIXERCONTROLDETAILS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MI
XERCONTROLDETAILS_BOOLEAN
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MI
XERCONTROLDETAILS_LISTTEXT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MIXERCONTROLDETAILS_SIGNED
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MIXERCONTROLDETAILS_UNSIGNED
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MIXERLINE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MIXERLINECONTROLS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MMCKINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MMCKINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MMIOINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MMIOINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MMTIME
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MMTIME
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MODEMDEVCAPS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MODEMSETTINGS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MONCBSTRUCT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MONCONVSTRUCT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MONERRSTRUCT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MONHSZSTRUCT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MONITOR_INFO_1
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MONITOR_INFO_2
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MONLINKSTRUCT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MONMSGSTRUCT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MOUSE_EVENT_RECORD
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MOUSEHOOKSTRUCT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MOUSEKEYS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MSG
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MSGBOXPARAMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MSGFILTER
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MULTIKEYHELP
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


MULTIKEYHELP
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


NAME_BUFFER
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


NCB
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


NCCALCSIZE_PARAMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


NDDESHAREINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


NETRESOURCE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


NEWCPLINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


NEWTEXTMETRIC
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


NEWTEXTMETRICEX
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


NM_LISTVIEW
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


NM_LISTVIEW
Windows NT
Win95
Win32s
Import Library
Header File
commctrl.h
Unicode
Platform Notes
None


NM_TREEVIEW
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


NM_UPDOWN
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


NMHDR
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


NONCLIENTMETRICS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


NOTIFYICONDATA
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shellapi.h
Unicode
Platform Notes
None


NRESARRAY
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


NS_SERVICE_INFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


NUMBERFMT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


OFSTRUCT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


OPENFILENAME
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


OSVERSIONINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


OUTLINETEXTMETRIC
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


OUTPUT_DEBUG_STRING_INFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


OVERLAPPED
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PAINTSTRUCT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PALETTEENTRY
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PANOSE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PARAFORMAT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PARTITION_INFORMATION
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PATCHARRAY
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PCMWAVEFORMAT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PCMWAVEFORMAT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PERF_COUNTER_BLOCK
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PERF_COUNTER_DEFINITION
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PERF_DATA_BLOCK
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PERF_INSTANCE_DEFINITION
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PERF_OBJECT_TYPE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


POINT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


POINTFLOAT
Windows NT
New
Win95
No
Win32s
No
Import Library
Header File
wingdi.h
Unicode
Platform Notes
None


POINTFX
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


POINTL
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


POINTS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


POLYTEXT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PORT_INFO_1
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PORT_INFO_2
Windows NT
No
Win95
Yes
Win32s
Import Library
Header File
winspool.h
Unicode
Platform Notes
None


PREVENT_MEDIA_REMOVAL
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PRINTDLG
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PRINTER_DEFAULTS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PRINTER_INFO_1
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PRINTER_INFO_2
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PRINTER_INFO_3
Windows NT
Yes
Win95
No
Win32s
Import Library
Header File
winspool.h
Unicode
Platform Notes
None


PRINTER_INFO_4
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PRINTER_INFO_5
Windows NT
No
Win95
Yes
Win32s
Import Library
Header File
winspool.h
Unicode
Platform Notes
None


PRINTER_NOTIFY_INFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PRINTER_NOTIFY_INFO_DATA
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PRINTER_NOTIFY_OPTIONS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PR
INTER_NOTIFY_OPTIONS_TYPE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PRINTPROCESSOR_INFO_1
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PRIVILEGE_SET
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PROCESS_HEAP_ENTRY
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PROCESS_INFORMATION
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PROPSHEETHEADER
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PROPSHEETPAGE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PROTOCOL_INFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PROVIDOR_INFO_1
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PSHNOTIFY
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


PUNCTUATION
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


QUERY_SERVICE_CONFIG
Windows NT
Yes
Win95
No
Win32s
Import Library
Header File
winsvc.h
Unicode
Platform Notes
None


QUERY_SERVICE_LOCK_STATUS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


RASAMB
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


RASCONN
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


RASCONNSTATUS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


RASDIALEXTENSIONS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


RASDIALPARAMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


RASENTRYNAME
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


RASPPPIP
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


RASPPPIPX
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


RASPPPNBF
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


RASTERIZER_STATUS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


REASSIGN_BLOCKS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


RECT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


RECTL
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


REGISTERWORD
Windows NT
Win95
Win32s
Import Library
Header File
imm.h
Unicode
Platform Notes
None


REMOTE_NAME_INFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


REOBJECT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


REPASTESPECIAL
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


REQRESIZE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


RGBQUAD
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


RGBTRIPLE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


RGNDATA
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


RGNDATAHEADER
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


RIP_INFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


SCROLLINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


SECURITY_ATTRIBUTES
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


SECURITY_DESCRIPTOR
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


SE
CURITY_DESCRIPTOR_CONTROL
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


SECURITY_INFORMATION
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


SE
CURITY_QUALITY_OF_SERVICE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


SELCHANGE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


SERIALKEYS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


SERVICE_ADDRESS
Windows NT
Yes
Win95
No
Win32s
Import Library
Header File
nspapi.h
Unicode
Platform Notes
None


SERVICE_ADDRESSES
Windows NT
Yes
Win95
No
Win32s
Import Library
Header File
nspapi.h
Unicode
Platform Notes
None


SERVICE_INFO
Windows NT
Yes
Win95
No
Win32s
Import Library
Header File
nspapi.h
Unicode
Platform Notes
None


SERVICE_STATUS
Windows NT
Yes
Win95
No
Win32s
Import Library
Header File
winsvc.h
Unicode
Platform Notes
None


SERVICE_TABLE_ENTRY
Windows NT
Yes
Win95
No
Win32s
Import Library
Header File
winsvc.h
Unicode
Platform Notes
None


SERVICE_TYPE_INFO_ABS
Windows NT
Yes
Win95
No
Win32s
Import Library
Header File
nspapi.h
Unicode
Platform Notes
None


SERVICE_TYPE_VALUE_ABS
Windows NT
Yes
Win95
No
Win32s
Import Library
Header File
nspapi.h
Unicode
Platform Notes
None


SESSION_BUFFER
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


SESSION_HEADER
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


SET_PARTITION_INFORMATION
Windows NT
Yes
Win95
No
Win32s
Import Library
Header File
winioctl.h
Unicode
Platform Notes
None


SHCONTF
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


SHFILEINFO
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


SHFILEOPSTRUCT
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


SHGNO
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


SHITEMID
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


SHNAMEMAPPING
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


SID
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


SID_AND_ATTRIBUTES
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


SID_IDENTIFIER_AUTHORITY
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


SINGLE_LIST_ENTRY
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


SIZE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


SMALL_RECT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


SOUNDSENTRY
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


STARTUPINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


STICKYKEYS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


String
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


StringFileInfo
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


StringTable
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


STRRET
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
shlobj.h
Unicode
Platform Notes
None


STYLEBUF
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


STYLESTRUCT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


SYSTEM_ALARM_ACE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


SYSTEM_AUDIT_ACE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


SYSTEM_INFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


SYSTEM_POWER_STATUS
Windows NT
No
Win95
Yes
Win32s
No
Import Library
Header File
winbase.h
Unicode
Platform Notes
None


SYSTEMTIME
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TAPE_ERASE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TAPE_GET_DRIVE_PARAMETERS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TAPE_GET_MEDIA_PARAMETERS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TAPE_GET_POSITION
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TAPE_PREPARE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TAPE_SET_DRIVE_PARAMETERS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TAPE_SET_MEDIA_PARAMETERS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TAPE_SET_POSITION
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TAPE_WRITE_MARKS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TBADDBITMAP
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TBBUTTON
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TBNOTIFY
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TBSAVEPARAMS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TC_HITTESTINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TC_ITEM
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TC_ITEMHEADER
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TC_KEYDOWN
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TEXTMETRIC
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TEXTRANGE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TIME_ZONE_INFORMATION
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TIMECAPS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TOGGLEKEYS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TOKEN_CONTROL
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TOKEN_DEFAULT_DACL
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TOKEN_GROUPS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TOKEN_OWNER
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TOKEN_PRIMARY_GROUP
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TOKEN_PRIVILEGES
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TOKEN_SOURCE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TOKEN_STATISTICS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TOKEN_USER
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TOOLINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TOOLTIPTEXT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TPMPARAMS
Windows NT
No
Win95
Yes
Win32s
Import Library
Header File
winuser.h
Unicode
Platform Notes
None


TRANSMIT_FILE_BUFFERS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TTHITTESTINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TTPOLYCURVE
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TTPOLYGONHEADER
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TV_DISPINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TV_HITTESTINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TV_INSERTSTRUCT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TV_ITEM
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TV_KEYDOWN
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


TV_SORTCB
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


UDACCEL
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


ULARGE_INTEGER
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


UNIVERSAL_NAME_INFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


UNLOAD_DLL_DEBUG_INFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


USEROBJECTFLAGS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


VALENT
Windows NT
Win95
Yes
Win32s
Import Library
Header File
Unicode
Platform Notes
None


Var
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


VarFileInfo
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


VERIFY_INFORMATION
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


VS_FIXEDFILEINFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


VS_VERSION_INFO
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WAVEFILTER
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WAVEFORMAT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WAVEFORMAT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WAVEFORMATEX
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WAVEHDR
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WAVEHDR
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WAVEINCAPS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WAVEINCAPS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WAVEOUTCAPS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WAVEOUTCAPS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WIN32_FIND_DATA
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WIN32_STREAM_ID
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WINDOW_BUFFER_SIZE_RECORD
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WINDOWPLACEMENT
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WINDOWPOS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WNDCLASS
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


WNDCLASSEX
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None


XFORM
Windows NT
Win95
Win32s
Import Library
Header File
Unicode
Platform Notes
None